summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--.gitlab-ci.yml2
-rw-r--r--.gitlab/CODEOWNERS16
-rw-r--r--.gitlab/ci/dast.gitlab-ci.yml2
-rw-r--r--.gitlab/ci/dev-fixtures.gitlab-ci.yml13
-rw-r--r--.gitlab/ci/docs.gitlab-ci.yml4
-rw-r--r--.gitlab/ci/frontend.gitlab-ci.yml38
-rw-r--r--.gitlab/ci/global.gitlab-ci.yml21
-rw-r--r--.gitlab/ci/notify.gitlab-ci.yml17
-rw-r--r--.gitlab/ci/rails.gitlab-ci.yml91
-rw-r--r--.gitlab/ci/reports.gitlab-ci.yml17
-rw-r--r--.gitlab/ci/review.gitlab-ci.yml29
-rw-r--r--.gitlab/ci/rules.gitlab-ci.yml35
-rw-r--r--.gitlab/ci/test-metadata.gitlab-ci.yml4
-rw-r--r--.gitlab/issue_templates/Feature Flag Roll Out.md8
-rw-r--r--.gitlab/issue_templates/Feature proposal.md18
-rw-r--r--.gitlab/issue_templates/Implementation.md62
-rw-r--r--.gitlab/issue_templates/Migrations.md4
-rw-r--r--.gitlab/issue_templates/Security Release Tracking Issue.md2
-rw-r--r--.gitlab/issue_templates/Snowplow event tracking.md42
-rw-r--r--.gitlab/issue_templates/actionable_insight.md6
-rw-r--r--.gitlab/merge_request_templates/Change Documentation Location.md10
-rw-r--r--.gitlab/merge_request_templates/Documentation.md5
-rw-r--r--.gitlab/merge_request_templates/New Static Analysis Check.md2
-rw-r--r--.gitlab/merge_request_templates/Security Release.md2
-rw-r--r--.gitpod.yml89
-rw-r--r--.haml-lint_todo.yml733
-rw-r--r--.rubocop.yml33
-rw-r--r--.rubocop_todo.yml284
-rw-r--r--.test_license_encryption_key.pub9
-rw-r--r--.theia/settings.json11
-rw-r--r--CHANGELOG.md56
-rw-r--r--GITALY_SERVER_VERSION2
-rw-r--r--GITLAB_KAS_VERSION2
-rw-r--r--GITLAB_PAGES_VERSION2
-rw-r--r--GITLAB_SHELL_VERSION2
-rw-r--r--GITLAB_WORKHORSE_VERSION2
-rw-r--r--Gemfile46
-rw-r--r--Gemfile.lock230
-rw-r--r--PROCESS.md6
-rw-r--r--app/assets/javascripts/admin/cohorts/components/usage_ping_disabled.vue6
-rw-r--r--app/assets/javascripts/admin/dev_ops_report/components/usage_ping_disabled.vue8
-rw-r--r--app/assets/javascripts/alert_handler.js22
-rw-r--r--app/assets/javascripts/alert_management/components/alert_details.vue137
-rw-r--r--app/assets/javascripts/alert_management/components/alert_management_empty_state.vue31
-rw-r--r--app/assets/javascripts/alert_management/components/alert_management_list_wrapper.vue63
-rw-r--r--app/assets/javascripts/alert_management/components/alert_management_table.vue456
-rw-r--r--app/assets/javascripts/alert_management/components/alert_metrics.vue2
-rw-r--r--app/assets/javascripts/alert_management/components/alert_sidebar.vue1
-rw-r--r--app/assets/javascripts/alert_management/components/alert_status.vue38
-rw-r--r--app/assets/javascripts/alert_management/components/alert_summary_row.vue18
-rw-r--r--app/assets/javascripts/alert_management/components/sidebar/sidebar_assignee.vue8
-rw-r--r--app/assets/javascripts/alert_management/components/sidebar/sidebar_assignees.vue60
-rw-r--r--app/assets/javascripts/alert_management/components/system_notes/system_note.vue27
-rw-r--r--app/assets/javascripts/alert_management/constants.js2
-rw-r--r--app/assets/javascripts/alert_management/details.js6
-rw-r--r--app/assets/javascripts/alert_management/graphql/fragments/detail_item.fragment.graphql5
-rw-r--r--app/assets/javascripts/alert_management/graphql/queries/get_alerts.query.graphql4
-rw-r--r--app/assets/javascripts/alert_management/graphql/queries/get_count_by_status.query.graphql4
-rw-r--r--app/assets/javascripts/alert_management/list.js35
-rw-r--r--app/assets/javascripts/alerts_service_settings/components/alerts_service_form.vue8
-rw-r--r--app/assets/javascripts/alerts_settings/components/alerts_integrations_list.vue109
-rw-r--r--app/assets/javascripts/alerts_settings/components/alerts_settings_form.vue179
-rw-r--r--app/assets/javascripts/alerts_settings/constants.js24
-rw-r--r--app/assets/javascripts/analytics/instance_statistics/components/app.vue30
-rw-r--r--app/assets/javascripts/analytics/instance_statistics/components/instance_counts.vue64
-rw-r--r--app/assets/javascripts/analytics/instance_statistics/components/pipelines_chart.vue215
-rw-r--r--app/assets/javascripts/analytics/instance_statistics/components/users_chart.vue143
-rw-r--r--app/assets/javascripts/analytics/instance_statistics/constants.js5
-rw-r--r--app/assets/javascripts/analytics/instance_statistics/graphql/fragments/count.fragment.graphql4
-rw-r--r--app/assets/javascripts/analytics/instance_statistics/graphql/queries/count.fragment.graphql4
-rw-r--r--app/assets/javascripts/analytics/instance_statistics/graphql/queries/instance_statistics_count.query.graphql34
-rw-r--r--app/assets/javascripts/analytics/instance_statistics/graphql/queries/pipeline_stats.query.graphql76
-rw-r--r--app/assets/javascripts/analytics/instance_statistics/graphql/queries/users.query.graphql13
-rw-r--r--app/assets/javascripts/analytics/instance_statistics/index.js24
-rw-r--r--app/assets/javascripts/analytics/instance_statistics/utils.js69
-rw-r--r--app/assets/javascripts/analytics/shared/components/metric_card.vue80
-rw-r--r--app/assets/javascripts/api.js99
-rw-r--r--app/assets/javascripts/awards_handler.js2
-rw-r--r--app/assets/javascripts/badges/components/badge_form.vue4
-rw-r--r--app/assets/javascripts/badges/components/badge_list_row.vue36
-rw-r--r--app/assets/javascripts/badges/components/badge_settings.vue30
-rw-r--r--app/assets/javascripts/batch_comments/components/draft_note.vue5
-rw-r--r--app/assets/javascripts/batch_comments/components/preview_dropdown.vue111
-rw-r--r--app/assets/javascripts/batch_comments/components/preview_item.vue17
-rw-r--r--app/assets/javascripts/batch_comments/components/publish_button.vue20
-rw-r--r--app/assets/javascripts/batch_comments/components/review_bar.vue47
-rw-r--r--app/assets/javascripts/batch_comments/stores/modules/batch_comments/actions.js22
-rw-r--r--app/assets/javascripts/batch_comments/stores/modules/batch_comments/mutation_types.js7
-rw-r--r--app/assets/javascripts/batch_comments/stores/modules/batch_comments/mutations.js16
-rw-r--r--app/assets/javascripts/batch_comments/stores/modules/batch_comments/state.js2
-rw-r--r--app/assets/javascripts/behaviors/autosize.js2
-rw-r--r--app/assets/javascripts/behaviors/collapse_sidebar_on_window_resize.js21
-rw-r--r--app/assets/javascripts/behaviors/copy_to_clipboard.js25
-rw-r--r--app/assets/javascripts/behaviors/gl_emoji.js4
-rw-r--r--app/assets/javascripts/behaviors/index.js3
-rw-r--r--app/assets/javascripts/behaviors/load_startup_css.js15
-rw-r--r--app/assets/javascripts/behaviors/markdown/gfm_auto_complete.js1
-rw-r--r--app/assets/javascripts/behaviors/shortcuts/keybindings.js96
-rw-r--r--app/assets/javascripts/behaviors/shortcuts/shortcuts.js7
-rw-r--r--app/assets/javascripts/blob/components/blob_edit_content.vue17
-rw-r--r--app/assets/javascripts/blob/components/blob_header_filepath.vue1
-rw-r--r--app/assets/javascripts/blob/components/eventhub.js3
-rw-r--r--app/assets/javascripts/blob/pipeline_tour_success_modal.vue48
-rw-r--r--app/assets/javascripts/blob/suggest_web_ide_ci/components/web_ide_alert.vue50
-rw-r--r--app/assets/javascripts/blob/suggest_web_ide_ci/index.js20
-rw-r--r--app/assets/javascripts/blob/viewer/index.js7
-rw-r--r--app/assets/javascripts/blob_edit/blob_bundle.js27
-rw-r--r--app/assets/javascripts/blob_edit/edit_blob.js109
-rw-r--r--app/assets/javascripts/boards/boards_util.js41
-rw-r--r--app/assets/javascripts/boards/components/board_blank_state.vue104
-rw-r--r--app/assets/javascripts/boards/components/board_column.vue18
-rw-r--r--app/assets/javascripts/boards/components/board_configuration_options.vue65
-rw-r--r--app/assets/javascripts/boards/components/board_content.vue7
-rw-r--r--app/assets/javascripts/boards/components/board_delete.js30
-rw-r--r--app/assets/javascripts/boards/components/board_extra_actions.vue57
-rw-r--r--app/assets/javascripts/boards/components/board_form.vue25
-rw-r--r--app/assets/javascripts/boards/components/board_list.vue14
-rw-r--r--app/assets/javascripts/boards/components/board_list_header.vue49
-rw-r--r--app/assets/javascripts/boards/components/board_list_new.vue166
-rw-r--r--app/assets/javascripts/boards/components/board_new_issue.vue6
-rw-r--r--app/assets/javascripts/boards/components/board_settings_sidebar.vue33
-rw-r--r--app/assets/javascripts/boards/components/issue_card_inner.vue9
-rw-r--r--app/assets/javascripts/boards/components/modal/tabs.vue34
-rw-r--r--app/assets/javascripts/boards/components/new_list_dropdown.js32
-rw-r--r--app/assets/javascripts/boards/components/project_select.vue6
-rw-r--r--app/assets/javascripts/boards/components/sidebar/board_editable_item.vue8
-rw-r--r--app/assets/javascripts/boards/components/sidebar/board_sidebar_labels_select.vue120
-rw-r--r--app/assets/javascripts/boards/ee_functions.js2
-rw-r--r--app/assets/javascripts/boards/filtered_search_boards.js3
-rw-r--r--app/assets/javascripts/boards/icons/fullscreen_collapse.svg1
-rw-r--r--app/assets/javascripts/boards/icons/fullscreen_expand.svg1
-rw-r--r--app/assets/javascripts/boards/index.js108
-rw-r--r--app/assets/javascripts/boards/mixins/is_wip_limits.js7
-rw-r--r--app/assets/javascripts/boards/models/list.js3
-rw-r--r--app/assets/javascripts/boards/queries/board.mutation.graphql11
-rw-r--r--app/assets/javascripts/boards/queries/board_list_create.mutation.graphql20
-rw-r--r--app/assets/javascripts/boards/queries/board_lists.query.graphql28
-rw-r--r--app/assets/javascripts/boards/queries/group_board.query.graphql13
-rw-r--r--app/assets/javascripts/boards/queries/issue_set_labels.mutation.graphql15
-rw-r--r--app/assets/javascripts/boards/queries/lists_issues.query.graphql28
-rw-r--r--app/assets/javascripts/boards/queries/project_board.query.graphql13
-rw-r--r--app/assets/javascripts/boards/stores/actions.js159
-rw-r--r--app/assets/javascripts/boards/stores/boards_store.js63
-rw-r--r--app/assets/javascripts/boards/stores/getters.js15
-rw-r--r--app/assets/javascripts/boards/stores/mutation_types.js6
-rw-r--r--app/assets/javascripts/boards/stores/mutations.js89
-rw-r--r--app/assets/javascripts/boards/stores/state.js5
-rw-r--r--app/assets/javascripts/boards/toggle_focus.js13
-rw-r--r--app/assets/javascripts/breadcrumb.js9
-rw-r--r--app/assets/javascripts/build_artifacts.js18
-rw-r--r--app/assets/javascripts/ci_lint/components/ci_lint.vue112
-rw-r--r--app/assets/javascripts/ci_lint/components/ci_lint_results.vue115
-rw-r--r--app/assets/javascripts/ci_lint/components/ci_lint_results_param.vue26
-rw-r--r--app/assets/javascripts/ci_lint/components/ci_lint_results_value.vue81
-rw-r--r--app/assets/javascripts/ci_lint/components/ci_lint_warnings.vue69
-rw-r--r--app/assets/javascripts/ci_lint/graphql/mutations/lint_ci.mutation.graphql22
-rw-r--r--app/assets/javascripts/ci_lint/index.js47
-rw-r--r--app/assets/javascripts/ci_settings_pipeline_triggers/components/triggers_list.vue143
-rw-r--r--app/assets/javascripts/ci_settings_pipeline_triggers/index.js36
-rw-r--r--app/assets/javascripts/ci_variable_list/components/ci_environments_dropdown.vue42
-rw-r--r--app/assets/javascripts/ci_variable_list/components/ci_variable_modal.vue16
-rw-r--r--app/assets/javascripts/ci_variable_list/components/ci_variable_table.vue5
-rw-r--r--app/assets/javascripts/clusters/components/applications.vue4
-rw-r--r--app/assets/javascripts/clusters/components/crossplane_provider_stack.vue18
-rw-r--r--app/assets/javascripts/clusters/components/fluentd_output_settings.vue35
-rw-r--r--app/assets/javascripts/clusters/components/ingress_modsecurity_settings.vue42
-rw-r--r--app/assets/javascripts/clusters/components/knative_domain_editor.vue27
-rw-r--r--app/assets/javascripts/clusters/components/uninstall_application_confirmation_modal.vue8
-rw-r--r--app/assets/javascripts/clusters/forms/components/integration_form.vue4
-rw-r--r--app/assets/javascripts/clusters_list/components/clusters.vue33
-rw-r--r--app/assets/javascripts/clusters_list/components/node_error_help_text.vue53
-rw-r--r--app/assets/javascripts/clusters_list/constants.js43
-rw-r--r--app/assets/javascripts/clusters_list/index.js18
-rw-r--r--app/assets/javascripts/clusters_list/load_clusters.js18
-rw-r--r--app/assets/javascripts/clusters_list/store/actions.js2
-rw-r--r--app/assets/javascripts/code_navigation/index.js10
-rw-r--r--app/assets/javascripts/code_navigation/store/index.js11
-rw-r--r--app/assets/javascripts/commit/pipelines/pipelines_bundle.js7
-rw-r--r--app/assets/javascripts/commit/pipelines/pipelines_table.vue126
-rw-r--r--app/assets/javascripts/commons/index.js1
-rw-r--r--app/assets/javascripts/commons/jquery.js4
-rw-r--r--app/assets/javascripts/confidential_merge_request/components/dropdown.vue31
-rw-r--r--app/assets/javascripts/confirm_danger_modal.js10
-rw-r--r--app/assets/javascripts/confirm_modal.js12
-rw-r--r--app/assets/javascripts/create_cluster/eks_cluster/components/create_eks_cluster.vue5
-rw-r--r--app/assets/javascripts/create_cluster/eks_cluster/components/eks_cluster_configuration_form.vue299
-rw-r--r--app/assets/javascripts/create_cluster/eks_cluster/index.js2
-rw-r--r--app/assets/javascripts/create_cluster/eks_cluster/store/actions.js5
-rw-r--r--app/assets/javascripts/create_cluster/eks_cluster/store/mutation_types.js1
-rw-r--r--app/assets/javascripts/create_cluster/eks_cluster/store/mutations.js3
-rw-r--r--app/assets/javascripts/create_cluster/eks_cluster/store/state.js1
-rw-r--r--app/assets/javascripts/custom_metrics/components/delete_custom_metric_modal.vue8
-rw-r--r--app/assets/javascripts/cycle_analytics/components/limit_warning_component.vue23
-rw-r--r--app/assets/javascripts/cycle_analytics/components/stage_staging_component.vue16
-rw-r--r--app/assets/javascripts/cycle_analytics/components/stage_test_component.vue19
-rw-r--r--app/assets/javascripts/cycle_analytics/cycle_analytics_bundle.js6
-rw-r--r--app/assets/javascripts/cycle_analytics/svg/icon_branch.svg1
-rw-r--r--app/assets/javascripts/cycle_analytics/svg/icon_build_status.svg1
-rw-r--r--app/assets/javascripts/cycle_analytics/svg/icon_commit.svg1
-rw-r--r--app/assets/javascripts/deploy_freeze/components/deploy_freeze_table.vue18
-rw-r--r--app/assets/javascripts/design_management/components/delete_button.vue2
-rw-r--r--app/assets/javascripts/design_management/components/design_note_pin.vue14
-rw-r--r--app/assets/javascripts/design_management/components/design_overlay.vue4
-rw-r--r--app/assets/javascripts/design_management/components/design_presentation.vue4
-rw-r--r--app/assets/javascripts/design_management/components/design_scaler.vue2
-rw-r--r--app/assets/javascripts/design_management/components/design_sidebar.vue13
-rw-r--r--app/assets/javascripts/design_management/components/image.vue4
-rw-r--r--app/assets/javascripts/design_management/components/list/item.vue9
-rw-r--r--app/assets/javascripts/design_management/components/toolbar/design_navigation.vue4
-rw-r--r--app/assets/javascripts/design_management/components/toolbar/index.vue8
-rw-r--r--app/assets/javascripts/design_management/components/upload/design_dropzone.vue10
-rw-r--r--app/assets/javascripts/design_management/graphql/queries/get_design_list.query.graphql1
-rw-r--r--app/assets/javascripts/design_management/mixins/all_designs.js26
-rw-r--r--app/assets/javascripts/design_management/pages/design/index.vue23
-rw-r--r--app/assets/javascripts/design_management/pages/index.vue53
-rw-r--r--app/assets/javascripts/design_management/utils/cache_update.js14
-rw-r--r--app/assets/javascripts/design_management/utils/design_management_utils.js4
-rw-r--r--app/assets/javascripts/design_management/utils/tracking.js28
-rw-r--r--app/assets/javascripts/diff_notes/components/comment_resolve_btn.js65
-rw-r--r--app/assets/javascripts/diff_notes/components/diff_note_avatars.js189
-rw-r--r--app/assets/javascripts/diff_notes/components/jump_to_discussion.js210
-rw-r--r--app/assets/javascripts/diff_notes/components/new_issue_for_discussion.js28
-rw-r--r--app/assets/javascripts/diff_notes/components/resolve_btn.js145
-rw-r--r--app/assets/javascripts/diff_notes/components/resolve_count.js28
-rw-r--r--app/assets/javascripts/diff_notes/diff_notes_bundle.js72
-rw-r--r--app/assets/javascripts/diff_notes/icons/collapse_icon.svg1
-rw-r--r--app/assets/javascripts/diff_notes/mixins/discussion.js37
-rw-r--r--app/assets/javascripts/diff_notes/models/discussion.js99
-rw-r--r--app/assets/javascripts/diff_notes/models/note.js14
-rw-r--r--app/assets/javascripts/diff_notes/services/resolve.js86
-rw-r--r--app/assets/javascripts/diff_notes/stores/comments.js56
-rw-r--r--app/assets/javascripts/diffs/components/app.vue4
-rw-r--r--app/assets/javascripts/diffs/components/collapsed_files_warning.vue2
-rw-r--r--app/assets/javascripts/diffs/components/commit_item.vue129
-rw-r--r--app/assets/javascripts/diffs/components/commit_widget.vue13
-rw-r--r--app/assets/javascripts/diffs/components/compare_dropdown_layout.vue2
-rw-r--r--app/assets/javascripts/diffs/components/compare_versions.vue1
-rw-r--r--app/assets/javascripts/diffs/components/diff_content.vue8
-rw-r--r--app/assets/javascripts/diffs/components/diff_file.vue8
-rw-r--r--app/assets/javascripts/diffs/components/diff_file_header.vue222
-rw-r--r--app/assets/javascripts/diffs/components/diff_row_utils.js85
-rw-r--r--app/assets/javascripts/diffs/components/diff_stats.vue2
-rw-r--r--app/assets/javascripts/diffs/components/diff_table_cell.vue206
-rw-r--r--app/assets/javascripts/diffs/components/edit_button.vue64
-rw-r--r--app/assets/javascripts/diffs/components/inline_diff_table_row.vue91
-rw-r--r--app/assets/javascripts/diffs/components/parallel_diff_comment_row.vue8
-rw-r--r--app/assets/javascripts/diffs/components/parallel_diff_table_row.vue178
-rw-r--r--app/assets/javascripts/diffs/diff_file.js12
-rw-r--r--app/assets/javascripts/diffs/i18n.js5
-rw-r--r--app/assets/javascripts/diffs/store/actions.js9
-rw-r--r--app/assets/javascripts/diffs/store/getters.js50
-rw-r--r--app/assets/javascripts/diffs/store/mutations.js4
-rw-r--r--app/assets/javascripts/editor/constants.js1
-rw-r--r--app/assets/javascripts/editor/editor_lite.js37
-rw-r--r--app/assets/javascripts/emoji/index.js239
-rw-r--r--app/assets/javascripts/emoji/support/index.js8
-rw-r--r--app/assets/javascripts/environments/components/enable_review_app_button.vue109
-rw-r--r--app/assets/javascripts/environments/components/enable_review_app_modal.vue98
-rw-r--r--app/assets/javascripts/environments/components/environment_actions.vue8
-rw-r--r--app/assets/javascripts/environments/components/environment_delete.vue8
-rw-r--r--app/assets/javascripts/environments/components/environment_item.vue8
-rw-r--r--app/assets/javascripts/environments/components/environment_stop.vue6
-rw-r--r--app/assets/javascripts/environments/components/environment_terminal_button.vue2
-rw-r--r--app/assets/javascripts/environments/components/environments_app.vue144
-rw-r--r--app/assets/javascripts/environments/components/environments_table.vue1
-rw-r--r--app/assets/javascripts/environments/components/stop_environment_modal.vue49
-rw-r--r--app/assets/javascripts/environments/folder/environments_folder_view.vue26
-rw-r--r--app/assets/javascripts/error_tracking/components/stacktrace_entry.vue4
-rw-r--r--app/assets/javascripts/error_tracking_settings/components/app.vue18
-rw-r--r--app/assets/javascripts/error_tracking_settings/components/error_tracking_form.vue15
-rw-r--r--app/assets/javascripts/feature_flags/components/configure_feature_flags_modal.vue258
-rw-r--r--app/assets/javascripts/feature_flags/components/edit_feature_flag.vue144
-rw-r--r--app/assets/javascripts/feature_flags/components/environments_dropdown.vue181
-rw-r--r--app/assets/javascripts/feature_flags/components/feature_flags.vue326
-rw-r--r--app/assets/javascripts/feature_flags/components/feature_flags_tab.vue108
-rw-r--r--app/assets/javascripts/feature_flags/components/feature_flags_table.vue271
-rw-r--r--app/assets/javascripts/feature_flags/components/form.vue606
-rw-r--r--app/assets/javascripts/feature_flags/components/new_environments_dropdown.vue100
-rw-r--r--app/assets/javascripts/feature_flags/components/new_feature_flag.vue101
-rw-r--r--app/assets/javascripts/feature_flags/components/strategies/default.vue10
-rw-r--r--app/assets/javascripts/feature_flags/components/strategies/flexible_rollout.vue121
-rw-r--r--app/assets/javascripts/feature_flags/components/strategies/gitlab_user_list.vue63
-rw-r--r--app/assets/javascripts/feature_flags/components/strategies/parameter_form_group.vue22
-rw-r--r--app/assets/javascripts/feature_flags/components/strategies/percent_rollout.vue69
-rw-r--r--app/assets/javascripts/feature_flags/components/strategies/users_with_id.vue47
-rw-r--r--app/assets/javascripts/feature_flags/components/strategy.vue206
-rw-r--r--app/assets/javascripts/feature_flags/components/strategy_parameters.vue54
-rw-r--r--app/assets/javascripts/feature_flags/components/user_lists_table.vue122
-rw-r--r--app/assets/javascripts/feature_flags/constants.js54
-rw-r--r--app/assets/javascripts/feature_flags/edit.js41
-rw-r--r--app/assets/javascripts/feature_flags/index.js49
-rw-r--r--app/assets/javascripts/feature_flags/new.js39
-rw-r--r--app/assets/javascripts/feature_flags/store/edit/actions.js61
-rw-r--r--app/assets/javascripts/feature_flags/store/edit/index.js11
-rw-r--r--app/assets/javascripts/feature_flags/store/edit/mutation_types.js9
-rw-r--r--app/assets/javascripts/feature_flags/store/edit/mutations.js39
-rw-r--r--app/assets/javascripts/feature_flags/store/edit/state.js18
-rw-r--r--app/assets/javascripts/feature_flags/store/helpers.js213
-rw-r--r--app/assets/javascripts/feature_flags/store/index/actions.js97
-rw-r--r--app/assets/javascripts/feature_flags/store/index/index.js11
-rw-r--r--app/assets/javascripts/feature_flags/store/index/mutation_types.js22
-rw-r--r--app/assets/javascripts/feature_flags/store/index/mutations.js113
-rw-r--r--app/assets/javascripts/feature_flags/store/index/state.js18
-rw-r--r--app/assets/javascripts/feature_flags/store/new/actions.js37
-rw-r--r--app/assets/javascripts/feature_flags/store/new/index.js11
-rw-r--r--app/assets/javascripts/feature_flags/store/new/mutation_types.js3
-rw-r--r--app/assets/javascripts/feature_flags/store/new/mutations.js15
-rw-r--r--app/assets/javascripts/feature_flags/store/new/state.js6
-rw-r--r--app/assets/javascripts/feature_flags/utils.js66
-rw-r--r--app/assets/javascripts/filtered_search/add_extra_tokens_for_merge_requests.js107
-rw-r--r--app/assets/javascripts/filtered_search/available_dropdown_mappings.js21
-rw-r--r--app/assets/javascripts/filtered_search/constants.js2
-rw-r--r--app/assets/javascripts/filtered_search/filtered_search_dropdown_manager.js2
-rw-r--r--app/assets/javascripts/filtered_search/filtered_search_manager.js2
-rw-r--r--app/assets/javascripts/flash.js2
-rw-r--r--app/assets/javascripts/frequent_items/index.js82
-rw-r--r--app/assets/javascripts/frequent_items/utils.js2
-rw-r--r--app/assets/javascripts/gfm_auto_complete.js108
-rw-r--r--app/assets/javascripts/gl_form.js15
-rw-r--r--app/assets/javascripts/grafana_integration/components/grafana_integration.vue8
-rw-r--r--app/assets/javascripts/group_label_subscription.js9
-rw-r--r--app/assets/javascripts/group_settings/components/shared_runners_form.vue139
-rw-r--r--app/assets/javascripts/group_settings/constants.js11
-rw-r--r--app/assets/javascripts/group_settings/mount_shared_runners.js15
-rw-r--r--app/assets/javascripts/groups/components/group_folder.vue6
-rw-r--r--app/assets/javascripts/groups/components/item_actions.vue2
-rw-r--r--app/assets/javascripts/groups/components/item_stats_value.vue10
-rw-r--r--app/assets/javascripts/groups/members/components/app.vue33
-rw-r--r--app/assets/javascripts/groups/members/constants.js5
-rw-r--r--app/assets/javascripts/groups/members/index.js13
-rw-r--r--app/assets/javascripts/groups/members/utils.js44
-rw-r--r--app/assets/javascripts/ide/components/activity_bar.vue18
-rw-r--r--app/assets/javascripts/ide/components/commit_sidebar/actions.vue25
-rw-r--r--app/assets/javascripts/ide/components/commit_sidebar/editor_header.vue12
-rw-r--r--app/assets/javascripts/ide/components/commit_sidebar/form.vue15
-rw-r--r--app/assets/javascripts/ide/components/commit_sidebar/message_field.vue19
-rw-r--r--app/assets/javascripts/ide/components/editor_mode_dropdown.vue6
-rw-r--r--app/assets/javascripts/ide/components/file_templates/bar.vue6
-rw-r--r--app/assets/javascripts/ide/components/file_templates/dropdown.vue5
-rw-r--r--app/assets/javascripts/ide/components/ide.vue30
-rw-r--r--app/assets/javascripts/ide/components/ide_review.vue30
-rw-r--r--app/assets/javascripts/ide/components/ide_side_bar.vue18
-rw-r--r--app/assets/javascripts/ide/components/ide_status_bar.vue11
-rw-r--r--app/assets/javascripts/ide/components/ide_tree.vue32
-rw-r--r--app/assets/javascripts/ide/components/ide_tree_list.vue28
-rw-r--r--app/assets/javascripts/ide/components/jobs/detail.vue9
-rw-r--r--app/assets/javascripts/ide/components/jobs/detail/scroll_button.vue7
-rw-r--r--app/assets/javascripts/ide/components/jobs/stage.vue7
-rw-r--r--app/assets/javascripts/ide/components/new_dropdown/modal.vue1
-rw-r--r--app/assets/javascripts/ide/components/new_dropdown/upload.vue4
-rw-r--r--app/assets/javascripts/ide/components/repo_commit_section.vue44
-rw-r--r--app/assets/javascripts/ide/components/repo_editor.vue19
-rw-r--r--app/assets/javascripts/ide/constants.js6
-rw-r--r--app/assets/javascripts/ide/index.js12
-rw-r--r--app/assets/javascripts/ide/lib/editor.js6
-rw-r--r--app/assets/javascripts/ide/lib/errors.js38
-rw-r--r--app/assets/javascripts/ide/lib/languages/README.md4
-rw-r--r--app/assets/javascripts/ide/lib/languages/hcl.js192
-rw-r--r--app/assets/javascripts/ide/lib/languages/index.js3
-rw-r--r--app/assets/javascripts/ide/stores/actions/file.js4
-rw-r--r--app/assets/javascripts/ide/stores/getters.js6
-rw-r--r--app/assets/javascripts/ide/stores/modules/commit/actions.js18
-rw-r--r--app/assets/javascripts/ide/stores/modules/commit/mutations.js4
-rw-r--r--app/assets/javascripts/ide/stores/mutations/file.js15
-rw-r--r--app/assets/javascripts/ide/stores/utils.js23
-rw-r--r--app/assets/javascripts/ide/utils.js54
-rw-r--r--app/assets/javascripts/incidents/components/incidents_list.vue463
-rw-r--r--app/assets/javascripts/incidents/constants.js34
-rw-r--r--app/assets/javascripts/incidents/graphql/queries/get_count_by_status.query.graphql15
-rw-r--r--app/assets/javascripts/incidents/graphql/queries/get_incidents.query.graphql6
-rw-r--r--app/assets/javascripts/incidents/list.js11
-rw-r--r--app/assets/javascripts/incidents_settings/components/alerts_form.vue22
-rw-r--r--app/assets/javascripts/incidents_settings/components/incidents_settings_tabs.vue3
-rw-r--r--app/assets/javascripts/incidents_settings/components/pagerduty_form.vue41
-rw-r--r--app/assets/javascripts/incidents_settings/index.js8
-rw-r--r--app/assets/javascripts/init_issuable_sidebar.js8
-rw-r--r--app/assets/javascripts/integrations/edit/components/confirmation_modal.vue60
-rw-r--r--app/assets/javascripts/integrations/edit/components/integration_form.vue26
-rw-r--r--app/assets/javascripts/invite_member/components/invite_member_modal.vue64
-rw-r--r--app/assets/javascripts/invite_member/components/invite_member_trigger.vue37
-rw-r--r--app/assets/javascripts/invite_member/constants.js2
-rw-r--r--app/assets/javascripts/invite_member/event_hub.js3
-rw-r--r--app/assets/javascripts/invite_member/init_invite_member_modal.js21
-rw-r--r--app/assets/javascripts/invite_member/init_invite_member_trigger.js16
-rw-r--r--app/assets/javascripts/invite_members/components/invite_members_modal.vue224
-rw-r--r--app/assets/javascripts/invite_members/components/invite_members_trigger.vue38
-rw-r--r--app/assets/javascripts/invite_members/event_hub.js3
-rw-r--r--app/assets/javascripts/invite_members/init_invite_members_modal.js25
-rw-r--r--app/assets/javascripts/invite_members/init_invite_members_trigger.js20
-rw-r--r--app/assets/javascripts/issuable_context.js1
-rw-r--r--app/assets/javascripts/issuable_create/components/issuable_form.vue1
-rw-r--r--app/assets/javascripts/issuable_show/components/issuable_body.vue103
-rw-r--r--app/assets/javascripts/issuable_show/components/issuable_description.vue31
-rw-r--r--app/assets/javascripts/issuable_show/components/issuable_edit_form.vue135
-rw-r--r--app/assets/javascripts/issuable_show/components/issuable_header.vue120
-rw-r--r--app/assets/javascripts/issuable_show/components/issuable_show_root.vue98
-rw-r--r--app/assets/javascripts/issuable_show/components/issuable_title.vue96
-rw-r--r--app/assets/javascripts/issuable_show/constants.js5
-rw-r--r--app/assets/javascripts/issuable_show/event_hub.js3
-rw-r--r--app/assets/javascripts/issuable_sidebar/components/issuable_sidebar_root.vue88
-rw-r--r--app/assets/javascripts/issuable_sidebar/components/sidebar_app.vue23
-rw-r--r--app/assets/javascripts/issuable_sidebar/sidebar_bundle.js27
-rw-r--r--app/assets/javascripts/issue_show/components/fields/description_template.vue11
-rw-r--r--app/assets/javascripts/issue_show/components/incidents/graphql/queries/get_alert.graphql1
-rw-r--r--app/assets/javascripts/issue_show/components/incidents/highlight_bar.vue35
-rw-r--r--app/assets/javascripts/issue_show/components/incidents/incident_tabs.vue20
-rw-r--r--app/assets/javascripts/issue_show/incident.js4
-rw-r--r--app/assets/javascripts/issue_show/stores/index.js2
-rw-r--r--app/assets/javascripts/issue_show/utils/parse_data.js10
-rw-r--r--app/assets/javascripts/issues_list/components/issuable.vue2
-rw-r--r--app/assets/javascripts/jira_connect.js7
-rw-r--r--app/assets/javascripts/jira_import/components/jira_import_form.vue2
-rw-r--r--app/assets/javascripts/jira_import/index.js2
-rw-r--r--app/assets/javascripts/jira_import/queries/initiate_jira_import.mutation.graphql1
-rw-r--r--app/assets/javascripts/jira_import/utils/cache_update.js21
-rw-r--r--app/assets/javascripts/jobs/components/commit_block.vue33
-rw-r--r--app/assets/javascripts/jobs/components/job_container_item.vue8
-rw-r--r--app/assets/javascripts/jobs/components/log/line.vue32
-rw-r--r--app/assets/javascripts/jobs/components/sidebar.vue15
-rw-r--r--app/assets/javascripts/jobs/components/trigger_block.vue11
-rw-r--r--app/assets/javascripts/jobs/store/utils.js4
-rw-r--r--app/assets/javascripts/label_manager.js5
-rw-r--r--app/assets/javascripts/labels_select.js22
-rw-r--r--app/assets/javascripts/layout_nav.js9
-rw-r--r--app/assets/javascripts/lib/dompurify.js53
-rw-r--r--app/assets/javascripts/lib/graphql.js1
-rw-r--r--app/assets/javascripts/lib/utils/axios_startup_calls.js2
-rw-r--r--app/assets/javascripts/lib/utils/common_utils.js1
-rw-r--r--app/assets/javascripts/lib/utils/constants.js1
-rw-r--r--app/assets/javascripts/lib/utils/csrf.js8
-rw-r--r--app/assets/javascripts/lib/utils/css_utils.js19
-rw-r--r--app/assets/javascripts/lib/utils/datetime_utility.js49
-rw-r--r--app/assets/javascripts/lib/utils/experimentation.js3
-rw-r--r--app/assets/javascripts/lib/utils/highlight.js2
-rw-r--r--app/assets/javascripts/lib/utils/number_utils.js14
-rw-r--r--app/assets/javascripts/lib/utils/rails_ujs.js20
-rw-r--r--app/assets/javascripts/lib/utils/text_markdown.js27
-rw-r--r--app/assets/javascripts/lib/utils/unit_format/index.js20
-rw-r--r--app/assets/javascripts/lib/utils/url_utility.js42
-rw-r--r--app/assets/javascripts/logs/components/environment_logs.vue62
-rw-r--r--app/assets/javascripts/logs/components/log_simple_filters.vue42
-rw-r--r--app/assets/javascripts/main.js13
-rw-r--r--app/assets/javascripts/members.js38
-rw-r--r--app/assets/javascripts/merge_request.js74
-rw-r--r--app/assets/javascripts/merge_request_tabs.js18
-rw-r--r--app/assets/javascripts/milestone.js11
-rw-r--r--app/assets/javascripts/milestones/project_milestone_combobox.vue1
-rw-r--r--app/assets/javascripts/milestones/stores/actions.js58
-rw-r--r--app/assets/javascripts/milestones/stores/getters.js2
-rw-r--r--app/assets/javascripts/milestones/stores/index.js16
-rw-r--r--app/assets/javascripts/milestones/stores/mutation_types.js13
-rw-r--r--app/assets/javascripts/milestones/stores/mutations.js44
-rw-r--r--app/assets/javascripts/milestones/stores/state.js14
-rw-r--r--app/assets/javascripts/mirrors/mirror_repos.js3
-rw-r--r--app/assets/javascripts/monitoring/components/alert_widget_form.vue19
-rw-r--r--app/assets/javascripts/monitoring/components/dashboard_header.vue2
-rw-r--r--app/assets/javascripts/monitoring/components/dashboards_dropdown.vue6
-rw-r--r--app/assets/javascripts/monitoring/components/group_empty_state.vue8
-rw-r--r--app/assets/javascripts/monitoring/stores/actions.js2
-rw-r--r--app/assets/javascripts/namespaces/leave_by_url.js3
-rw-r--r--app/assets/javascripts/notebook/cells/markdown.vue2
-rw-r--r--app/assets/javascripts/notebook/cells/output/html.vue2
-rw-r--r--app/assets/javascripts/notes.js45
-rw-r--r--app/assets/javascripts/notes/components/comment_form.vue15
-rw-r--r--app/assets/javascripts/notes/components/diff_discussion_header.vue7
-rw-r--r--app/assets/javascripts/notes/components/diff_with_note.vue2
-rw-r--r--app/assets/javascripts/notes/components/discussion_counter.vue105
-rw-r--r--app/assets/javascripts/notes/components/discussion_filter.vue81
-rw-r--r--app/assets/javascripts/notes/components/note_actions.vue5
-rw-r--r--app/assets/javascripts/notes/components/note_body.vue3
-rw-r--r--app/assets/javascripts/notes/components/note_form.vue13
-rw-r--r--app/assets/javascripts/notes/components/notes_app.vue5
-rw-r--r--app/assets/javascripts/notes/components/sort_discussion.vue53
-rw-r--r--app/assets/javascripts/notes/components/timeline_toggle.vue60
-rw-r--r--app/assets/javascripts/notes/components/toggle_replies_widget.vue10
-rw-r--r--app/assets/javascripts/notes/constants.js3
-rw-r--r--app/assets/javascripts/notes/index.js12
-rw-r--r--app/assets/javascripts/notes/stores/actions.js8
-rw-r--r--app/assets/javascripts/notes/stores/getters.js24
-rw-r--r--app/assets/javascripts/notes/stores/modules/index.js2
-rw-r--r--app/assets/javascripts/notes/stores/mutation_types.js1
-rw-r--r--app/assets/javascripts/notes/stores/mutations.js9
-rw-r--r--app/assets/javascripts/notes/timeline.js16
-rw-r--r--app/assets/javascripts/notes/utils.js12
-rw-r--r--app/assets/javascripts/notifications_dropdown.js7
-rw-r--r--app/assets/javascripts/operation_settings/components/metrics_settings.vue8
-rw-r--r--app/assets/javascripts/packages/details/components/additional_metadata.vue6
-rw-r--r--app/assets/javascripts/packages/details/components/composer_installation.vue8
-rw-r--r--app/assets/javascripts/packages/details/components/package_title.vue10
-rw-r--r--app/assets/javascripts/packages/details/store/getters.js24
-rw-r--r--app/assets/javascripts/packages/details/utils.js13
-rw-r--r--app/assets/javascripts/packages/list/coming_soon/helpers.js55
-rw-r--r--app/assets/javascripts/packages/list/coming_soon/packages_coming_soon.vue172
-rw-r--r--app/assets/javascripts/packages/list/coming_soon/queries/issues.graphql20
-rw-r--r--app/assets/javascripts/packages/list/components/package_title.vue47
-rw-r--r--app/assets/javascripts/packages/list/components/packages_list_app.vue73
-rw-r--r--app/assets/javascripts/packages/list/components/packages_sort.vue2
-rw-r--r--app/assets/javascripts/packages/list/constants.js36
-rw-r--r--app/assets/javascripts/packages/list/stores/mutations.js9
-rw-r--r--app/assets/javascripts/packages/list/utils.js5
-rw-r--r--app/assets/javascripts/packages/shared/components/package_list_row.vue16
-rw-r--r--app/assets/javascripts/packages/shared/components/package_path.vue71
-rw-r--r--app/assets/javascripts/packages/shared/components/publish_method.vue3
-rw-r--r--app/assets/javascripts/packages/shared/constants.js3
-rw-r--r--app/assets/javascripts/packages/shared/utils.js2
-rw-r--r--app/assets/javascripts/pages/admin/credentials/index.js3
-rw-r--r--app/assets/javascripts/pages/admin/instance_statistics/index.js3
-rw-r--r--app/assets/javascripts/pages/admin/keys/index.js5
-rw-r--r--app/assets/javascripts/pages/admin/users/keys/index.js5
-rw-r--r--app/assets/javascripts/pages/dashboard/merge_requests/index.js2
-rw-r--r--app/assets/javascripts/pages/groups/group_members/index.js29
-rw-r--r--app/assets/javascripts/pages/groups/issues/index.js22
-rw-r--r--app/assets/javascripts/pages/groups/registry/repositories/index.js12
-rw-r--r--app/assets/javascripts/pages/groups/security/credentials/index.js3
-rw-r--r--app/assets/javascripts/pages/groups/settings/ci_cd/show/index.js3
-rw-r--r--app/assets/javascripts/pages/milestones/shared/components/delete_milestone_modal.vue31
-rw-r--r--app/assets/javascripts/pages/milestones/shared/delete_milestone_modal_init.js54
-rw-r--r--app/assets/javascripts/pages/profiles/keys/index.js3
-rw-r--r--app/assets/javascripts/pages/projects/blob/show/index.js47
-rw-r--r--app/assets/javascripts/pages/projects/ci/lints/ci_lint_editor.js42
-rw-r--r--app/assets/javascripts/pages/projects/ci/lints/new/index.js16
-rw-r--r--app/assets/javascripts/pages/projects/ci/lints/show/index.js18
-rw-r--r--app/assets/javascripts/pages/projects/clusters/index/index.js2
-rw-r--r--app/assets/javascripts/pages/projects/commit/pipelines/index.js12
-rw-r--r--app/assets/javascripts/pages/projects/commit/show/index.js12
-rw-r--r--app/assets/javascripts/pages/projects/environments/index/index.js4
-rw-r--r--app/assets/javascripts/pages/projects/feature_flags/edit/index.js3
-rw-r--r--app/assets/javascripts/pages/projects/feature_flags/index/index.js3
-rw-r--r--app/assets/javascripts/pages/projects/feature_flags/new/index.js3
-rw-r--r--app/assets/javascripts/pages/projects/feature_flags_user_lists/edit/index.js19
-rw-r--r--app/assets/javascripts/pages/projects/feature_flags_user_lists/new/index.js22
-rw-r--r--app/assets/javascripts/pages/projects/feature_flags_user_lists/show/index.js18
-rw-r--r--app/assets/javascripts/pages/projects/graphs/charts/index.js4
-rw-r--r--app/assets/javascripts/pages/projects/graphs/components/code_coverage.vue34
-rw-r--r--app/assets/javascripts/pages/projects/incidents/show/index.js11
-rw-r--r--app/assets/javascripts/pages/projects/index.js6
-rw-r--r--app/assets/javascripts/pages/projects/issues/index/index.js26
-rw-r--r--app/assets/javascripts/pages/projects/issues/new/index.js2
-rw-r--r--app/assets/javascripts/pages/projects/issues/service_desk/index.js22
-rw-r--r--app/assets/javascripts/pages/projects/issues/show.js32
-rw-r--r--app/assets/javascripts/pages/projects/issues/show/index.js12
-rw-r--r--app/assets/javascripts/pages/projects/merge_requests/index/index.js19
-rw-r--r--app/assets/javascripts/pages/projects/merge_requests/init_merge_request_show.js11
-rw-r--r--app/assets/javascripts/pages/projects/merge_requests/show/index.js16
-rw-r--r--app/assets/javascripts/pages/projects/new/index.js3
-rw-r--r--app/assets/javascripts/pages/projects/packages/packages/index/index.js6
-rw-r--r--app/assets/javascripts/pages/projects/packages/packages/show/index.js2
-rw-r--r--app/assets/javascripts/pages/projects/pipeline_schedules/shared/components/pipeline_schedules_callout.vue11
-rw-r--r--app/assets/javascripts/pages/projects/pipeline_schedules/shared/icons/intro_illustration.svg1
-rw-r--r--app/assets/javascripts/pages/projects/registry/repositories/index.js12
-rw-r--r--app/assets/javascripts/pages/projects/settings/ci_cd/show/index.js3
-rw-r--r--app/assets/javascripts/pages/projects/shared/permissions/components/project_feature_setting.vue20
-rw-r--r--app/assets/javascripts/pages/projects/shared/permissions/components/settings_panel.vue38
-rw-r--r--app/assets/javascripts/pages/projects/shared/web_ide_link/index.js31
-rw-r--r--app/assets/javascripts/pages/projects/show/index.js60
-rw-r--r--app/assets/javascripts/pages/projects/tags/index/index.js12
-rw-r--r--app/assets/javascripts/pages/projects/tags/remove_tag.js16
-rw-r--r--app/assets/javascripts/pages/projects/tags/show/index.js10
-rw-r--r--app/assets/javascripts/pages/projects/tree/show/index.js10
-rw-r--r--app/assets/javascripts/pages/search/show/index.js4
-rw-r--r--app/assets/javascripts/pages/search/show/search.js16
-rw-r--r--app/assets/javascripts/pages/shared/wikis/wikis.js2
-rw-r--r--app/assets/javascripts/performance_bar/components/performance_bar_app.vue2
-rw-r--r--app/assets/javascripts/performance_bar/performance_bar_log.js25
-rw-r--r--app/assets/javascripts/performance_constants.js23
-rw-r--r--app/assets/javascripts/performance_utils.js10
-rw-r--r--app/assets/javascripts/pipeline_new/components/pipeline_new_form.vue234
-rw-r--r--app/assets/javascripts/pipeline_new/index.js2
-rw-r--r--app/assets/javascripts/pipelines/components/dag/constants.js6
-rw-r--r--app/assets/javascripts/pipelines/components/dag/dag.vue13
-rw-r--r--app/assets/javascripts/pipelines/components/dag/dag_graph.vue12
-rw-r--r--app/assets/javascripts/pipelines/components/graph/action_component.vue2
-rw-r--r--app/assets/javascripts/pipelines/components/graph/graph_component.vue40
-rw-r--r--app/assets/javascripts/pipelines/components/graph/job_group_dropdown.vue25
-rw-r--r--app/assets/javascripts/pipelines/components/graph/job_item.vue4
-rw-r--r--app/assets/javascripts/pipelines/components/graph/job_name_component.vue2
-rw-r--r--app/assets/javascripts/pipelines/components/graph/stage_column_component.vue2
-rw-r--r--app/assets/javascripts/pipelines/components/header_component.vue166
-rw-r--r--app/assets/javascripts/pipelines/components/legacy_header_component.vue132
-rw-r--r--app/assets/javascripts/pipelines/components/parsing_utils.js (renamed from app/assets/javascripts/pipelines/components/dag/parsing_utils.js)0
-rw-r--r--app/assets/javascripts/pipelines/components/pipeline_graph/drawing_utils.js96
-rw-r--r--app/assets/javascripts/pipelines/components/pipeline_graph/job_pill.vue46
-rw-r--r--app/assets/javascripts/pipelines/components/pipeline_graph/pipeline_graph.vue177
-rw-r--r--app/assets/javascripts/pipelines/components/pipelines_list/empty_state.vue1
-rw-r--r--app/assets/javascripts/pipelines/components/pipelines_list/nav_controls.vue5
-rw-r--r--app/assets/javascripts/pipelines/components/pipelines_list/pipeline_stop_modal.vue28
-rw-r--r--app/assets/javascripts/pipelines/components/pipelines_list/pipeline_triggerer.vue2
-rw-r--r--app/assets/javascripts/pipelines/components/pipelines_list/pipeline_url.vue11
-rw-r--r--app/assets/javascripts/pipelines/components/pipelines_list/pipelines_table.vue4
-rw-r--r--app/assets/javascripts/pipelines/components/pipelines_list/pipelines_table_row.vue28
-rw-r--r--app/assets/javascripts/pipelines/components/pipelines_list/time_ago.vue11
-rw-r--r--app/assets/javascripts/pipelines/components/pipelines_list/tokens/pipeline_trigger_author_token.vue6
-rw-r--r--app/assets/javascripts/pipelines/components/test_reports/test_suite_table.vue30
-rw-r--r--app/assets/javascripts/pipelines/constants.js11
-rw-r--r--app/assets/javascripts/pipelines/graphql/queries/get_pipeline_header_data.query.graphql30
-rw-r--r--app/assets/javascripts/pipelines/mixins/graph_component_mixin.js54
-rw-r--r--app/assets/javascripts/pipelines/pipeline_details_bundle.js16
-rw-r--r--app/assets/javascripts/pipelines/pipeline_details_header.js41
-rw-r--r--app/assets/javascripts/pipelines/stores/test_reports/utils.js12
-rw-r--r--app/assets/javascripts/pipelines/utils.js51
-rw-r--r--app/assets/javascripts/profile/account/components/update_username.vue10
-rw-r--r--app/assets/javascripts/profile/gl_crop.js4
-rw-r--r--app/assets/javascripts/profile/profile.js11
-rw-r--r--app/assets/javascripts/project_find_file.js8
-rw-r--r--app/assets/javascripts/project_label_subscription.js4
-rw-r--r--app/assets/javascripts/projects/commit_box/info/index.js18
-rw-r--r--app/assets/javascripts/projects/commit_box/info/load_branches.js20
-rw-r--r--app/assets/javascripts/projects/commits/components/author_select.vue1
-rw-r--r--app/assets/javascripts/projects/commits/store/actions.js2
-rw-r--r--app/assets/javascripts/projects/default_project_templates.js4
-rw-r--r--app/assets/javascripts/projects/default_sample_data_templates.js12
-rw-r--r--app/assets/javascripts/projects/project_new.js4
-rw-r--r--app/assets/javascripts/projects/settings/access_dropdown.js138
-rw-r--r--app/assets/javascripts/projects/settings/constants.js7
-rw-r--r--app/assets/javascripts/projects/settings_service_desk/components/service_desk_root.vue12
-rw-r--r--app/assets/javascripts/projects/settings_service_desk/components/service_desk_setting.vue46
-rw-r--r--app/assets/javascripts/projects/tree/components/commit_pipeline_status_component.vue7
-rw-r--r--app/assets/javascripts/protected_branches/constants.js2
-rw-r--r--app/assets/javascripts/protected_branches/protected_branch_create.js4
-rw-r--r--app/assets/javascripts/ref/components/ref_selector.vue1
-rw-r--r--app/assets/javascripts/registry/explorer/components/details_page/partial_cleanup_alert.vue38
-rw-r--r--app/assets/javascripts/registry/explorer/components/details_page/tags_list_row.vue14
-rw-r--r--app/assets/javascripts/registry/explorer/components/list_page/image_list_row.vue18
-rw-r--r--app/assets/javascripts/registry/explorer/components/list_page/registry_header.vue79
-rw-r--r--app/assets/javascripts/registry/explorer/constants/expiration_policies.js7
-rw-r--r--app/assets/javascripts/registry/explorer/pages/details.vue20
-rw-r--r--app/assets/javascripts/registry/settings/components/registry_settings_app.vue50
-rw-r--r--app/assets/javascripts/registry/settings/components/settings_form.vue145
-rw-r--r--app/assets/javascripts/registry/settings/graphql/fragments/container_expiration_policy.fragment.graphql8
-rw-r--r--app/assets/javascripts/registry/settings/graphql/index.js14
-rw-r--r--app/assets/javascripts/registry/settings/graphql/mutations/update_container_expiration_policy.graphql10
-rw-r--r--app/assets/javascripts/registry/settings/graphql/queries/get_expiration_policy.graphql9
-rw-r--r--app/assets/javascripts/registry/settings/graphql/utils/cache_update.js22
-rw-r--r--app/assets/javascripts/registry/settings/registry_settings_bundle.js13
-rw-r--r--app/assets/javascripts/registry/settings/store/actions.js30
-rw-r--r--app/assets/javascripts/registry/settings/store/getters.js26
-rw-r--r--app/assets/javascripts/registry/settings/store/index.js18
-rw-r--r--app/assets/javascripts/registry/settings/store/mutation_types.js5
-rw-r--r--app/assets/javascripts/registry/settings/store/mutations.js29
-rw-r--r--app/assets/javascripts/registry/settings/store/state.js42
-rw-r--r--app/assets/javascripts/registry/shared/components/expiration_policy_fields.vue32
-rw-r--r--app/assets/javascripts/registry/shared/constants.js24
-rw-r--r--app/assets/javascripts/registry/shared/utils.js27
-rw-r--r--app/assets/javascripts/related_issues/components/add_issuable_form.vue3
-rw-r--r--app/assets/javascripts/related_issues/components/issue_token.vue2
-rw-r--r--app/assets/javascripts/related_issues/components/related_issuable_input.vue3
-rw-r--r--app/assets/javascripts/releases/components/app_edit_new.vue42
-rw-r--r--app/assets/javascripts/releases/components/app_index.vue49
-rw-r--r--app/assets/javascripts/releases/components/app_show.vue6
-rw-r--r--app/assets/javascripts/releases/components/asset_links_form.vue3
-rw-r--r--app/assets/javascripts/releases/components/evidence_block.vue6
-rw-r--r--app/assets/javascripts/releases/components/release_block.vue17
-rw-r--r--app/assets/javascripts/releases/components/release_block_assets.vue137
-rw-r--r--app/assets/javascripts/releases/components/release_block_author.vue42
-rw-r--r--app/assets/javascripts/releases/components/release_block_header.vue8
-rw-r--r--app/assets/javascripts/releases/components/release_block_metadata.vue90
-rw-r--r--app/assets/javascripts/releases/components/release_block_milestones.vue50
-rw-r--r--app/assets/javascripts/releases/components/release_skeleton_loader.vue51
-rw-r--r--app/assets/javascripts/releases/components/releases_pagination_graphql.vue6
-rw-r--r--app/assets/javascripts/releases/components/releases_pagination_rest.vue8
-rw-r--r--app/assets/javascripts/releases/constants.js2
-rw-r--r--app/assets/javascripts/releases/mount_edit.js3
-rw-r--r--app/assets/javascripts/releases/mount_new.js3
-rw-r--r--app/assets/javascripts/releases/mount_show.js3
-rw-r--r--app/assets/javascripts/releases/queries/all_releases.query.graphql74
-rw-r--r--app/assets/javascripts/releases/queries/one_release.query.graphql9
-rw-r--r--app/assets/javascripts/releases/queries/release.fragment.graphql62
-rw-r--r--app/assets/javascripts/releases/stores/getters.js11
-rw-r--r--app/assets/javascripts/releases/stores/index.js2
-rw-r--r--app/assets/javascripts/releases/stores/modules/detail/actions.js37
-rw-r--r--app/assets/javascripts/releases/stores/modules/detail/mutation_types.js1
-rw-r--r--app/assets/javascripts/releases/stores/modules/detail/mutations.js5
-rw-r--r--app/assets/javascripts/releases/stores/modules/detail/state.js2
-rw-r--r--app/assets/javascripts/releases/stores/modules/list/actions.js111
-rw-r--r--app/assets/javascripts/releases/stores/modules/list/mutations.js7
-rw-r--r--app/assets/javascripts/releases/stores/modules/list/state.js3
-rw-r--r--app/assets/javascripts/releases/util.js54
-rw-r--r--app/assets/javascripts/repository/components/breadcrumbs.vue26
-rw-r--r--app/assets/javascripts/repository/components/last_commit.vue32
-rw-r--r--app/assets/javascripts/repository/components/preview/index.vue5
-rw-r--r--app/assets/javascripts/repository/components/tree_content.vue5
-rw-r--r--app/assets/javascripts/repository/index.js86
-rw-r--r--app/assets/javascripts/repository/log_tree.js22
-rw-r--r--app/assets/javascripts/repository/queries/path_last_commit.query.graphql38
-rw-r--r--app/assets/javascripts/repository/utils/icon.js98
-rw-r--r--app/assets/javascripts/right_sidebar.js19
-rw-r--r--app/assets/javascripts/search/dropdown_filter/components/dropdown_filter.vue100
-rw-r--r--app/assets/javascripts/search/dropdown_filter/constants/confidential_filter_data.js36
-rw-r--r--app/assets/javascripts/search/dropdown_filter/constants/state_filter_data.js42
-rw-r--r--app/assets/javascripts/search/dropdown_filter/index.js38
-rw-r--r--app/assets/javascripts/search/index.js9
-rw-r--r--app/assets/javascripts/search/state_filter/components/state_filter.vue94
-rw-r--r--app/assets/javascripts/search/state_filter/constants.js39
-rw-r--r--app/assets/javascripts/search/state_filter/index.js34
-rw-r--r--app/assets/javascripts/search/store/index.js12
-rw-r--r--app/assets/javascripts/search/store/state.js4
-rw-r--r--app/assets/javascripts/self_monitor/components/self_monitor_form.vue7
-rw-r--r--app/assets/javascripts/sentry/sentry_config.js2
-rw-r--r--app/assets/javascripts/sentry/wrapper.js26
-rw-r--r--app/assets/javascripts/serverless/components/functions.vue12
-rw-r--r--app/assets/javascripts/serverless/components/missing_prometheus.vue8
-rw-r--r--app/assets/javascripts/serverless/components/url.vue4
-rw-r--r--app/assets/javascripts/shared/milestones/form.js1
-rw-r--r--app/assets/javascripts/sidebar/components/assignees/assignee_title.vue17
-rw-r--r--app/assets/javascripts/sidebar/components/assignees/sidebar_assignees.vue8
-rw-r--r--app/assets/javascripts/sidebar/components/confidential/edit_form_buttons.vue20
-rw-r--r--app/assets/javascripts/sidebar/components/labels/sidebar_labels.vue50
-rw-r--r--app/assets/javascripts/sidebar/components/lock/edit_form_buttons.vue18
-rw-r--r--app/assets/javascripts/sidebar/components/lock/issuable_lock_form.vue11
-rw-r--r--app/assets/javascripts/sidebar/components/participants/participants.vue10
-rw-r--r--app/assets/javascripts/sidebar/components/reviewers/collapsed_reviewer.vue24
-rw-r--r--app/assets/javascripts/sidebar/components/reviewers/collapsed_reviewer_list.vue107
-rw-r--r--app/assets/javascripts/sidebar/components/reviewers/reviewer_avatar.vue43
-rw-r--r--app/assets/javascripts/sidebar/components/reviewers/reviewer_avatar_link.vue84
-rw-r--r--app/assets/javascripts/sidebar/components/reviewers/reviewer_title.vue65
-rw-r--r--app/assets/javascripts/sidebar/components/reviewers/reviewers.vue72
-rw-r--r--app/assets/javascripts/sidebar/components/reviewers/sidebar_reviewers.vue112
-rw-r--r--app/assets/javascripts/sidebar/components/reviewers/uncollapsed_reviewer_list.vue103
-rw-r--r--app/assets/javascripts/sidebar/components/time_tracking/collapsed_state.vue14
-rw-r--r--app/assets/javascripts/sidebar/components/time_tracking/comparison_pane.vue7
-rw-r--r--app/assets/javascripts/sidebar/components/time_tracking/sidebar_time_tracking.vue7
-rw-r--r--app/assets/javascripts/sidebar/mount_sidebar.js141
-rw-r--r--app/assets/javascripts/sidebar/sidebar_mediator.js12
-rw-r--r--app/assets/javascripts/sidebar/stores/sidebar_store.js51
-rw-r--r--app/assets/javascripts/single_file_diff.js10
-rw-r--r--app/assets/javascripts/snippet/snippet_bundle.js30
-rw-r--r--app/assets/javascripts/snippet/snippet_edit.js35
-rw-r--r--app/assets/javascripts/snippet/snippet_embed.js37
-rw-r--r--app/assets/javascripts/snippet/snippet_show.js28
-rw-r--r--app/assets/javascripts/snippets/components/edit.vue23
-rw-r--r--app/assets/javascripts/snippets/components/embed_dropdown.vue2
-rw-r--r--app/assets/javascripts/snippets/components/show.vue13
-rw-r--r--app/assets/javascripts/snippets/components/snippet_blob_actions_edit.vue15
-rw-r--r--app/assets/javascripts/snippets/components/snippet_blob_edit.vue10
-rw-r--r--app/assets/javascripts/snippets/components/snippet_blob_view.vue7
-rw-r--r--app/assets/javascripts/snippets/components/snippet_description_edit.vue1
-rw-r--r--app/assets/javascripts/snippets/components/snippet_header.vue2
-rw-r--r--app/assets/javascripts/snippets/fragments/snippetBase.fragment.graphql26
-rw-r--r--app/assets/javascripts/snippets/index.js14
-rw-r--r--app/assets/javascripts/snippets/mixins/snippets.js11
-rw-r--r--app/assets/javascripts/snippets/queries/snippet.blob.content.query.graphql10
-rw-r--r--app/assets/javascripts/snippets/queries/snippet.query.graphql12
-rw-r--r--app/assets/javascripts/snippets/utils/blob.js15
-rw-r--r--app/assets/javascripts/static_site_editor/components/edit_meta_controls.vue104
-rw-r--r--app/assets/javascripts/static_site_editor/components/edit_meta_modal.vue85
-rw-r--r--app/assets/javascripts/static_site_editor/components/publish_toolbar.vue4
-rw-r--r--app/assets/javascripts/static_site_editor/graphql/index.js3
-rw-r--r--app/assets/javascripts/static_site_editor/graphql/mutations/has_submitted_changes.mutation.graphql5
-rw-r--r--app/assets/javascripts/static_site_editor/graphql/queries/app_data.query.graphql1
-rw-r--r--app/assets/javascripts/static_site_editor/graphql/resolvers/has_submitted_changes.js25
-rw-r--r--app/assets/javascripts/static_site_editor/graphql/resolvers/submit_content_changes.js36
-rw-r--r--app/assets/javascripts/static_site_editor/graphql/typedefs.graphql6
-rw-r--r--app/assets/javascripts/static_site_editor/index.js12
-rw-r--r--app/assets/javascripts/static_site_editor/pages/home.vue52
-rw-r--r--app/assets/javascripts/static_site_editor/pages/success.vue81
-rw-r--r--app/assets/javascripts/static_site_editor/services/front_matterify.js73
-rw-r--r--app/assets/javascripts/static_site_editor/services/parse_source_file.js17
-rw-r--r--app/assets/javascripts/static_site_editor/services/submit_content_changes.js18
-rw-r--r--app/assets/javascripts/static_site_editor/services/templater.js2
-rw-r--r--app/assets/javascripts/task_list.js9
-rw-r--r--app/assets/javascripts/test_utils/simulate_drag.js2
-rw-r--r--app/assets/javascripts/tooltips/index.js10
-rw-r--r--app/assets/javascripts/tracking.js2
-rw-r--r--app/assets/javascripts/user_lists/components/add_user_modal.vue72
-rw-r--r--app/assets/javascripts/user_lists/components/edit_user_list.vue74
-rw-r--r--app/assets/javascripts/user_lists/components/new_user_list.vue50
-rw-r--r--app/assets/javascripts/user_lists/components/user_list.vue142
-rw-r--r--app/assets/javascripts/user_lists/components/user_list_form.vue97
-rw-r--r--app/assets/javascripts/user_lists/constants/edit.js6
-rw-r--r--app/assets/javascripts/user_lists/constants/show.js8
-rw-r--r--app/assets/javascripts/user_lists/store/edit/actions.js22
-rw-r--r--app/assets/javascripts/user_lists/store/edit/index.js11
-rw-r--r--app/assets/javascripts/user_lists/store/edit/mutation_types.js5
-rw-r--r--app/assets/javascripts/user_lists/store/edit/mutations.js19
-rw-r--r--app/assets/javascripts/user_lists/store/edit/state.js9
-rw-r--r--app/assets/javascripts/user_lists/store/new/actions.js15
-rw-r--r--app/assets/javascripts/user_lists/store/new/index.js11
-rw-r--r--app/assets/javascripts/user_lists/store/new/mutation_types.js3
-rw-r--r--app/assets/javascripts/user_lists/store/new/mutations.js10
-rw-r--r--app/assets/javascripts/user_lists/store/new/state.js5
-rw-r--r--app/assets/javascripts/user_lists/store/show/actions.js32
-rw-r--r--app/assets/javascripts/user_lists/store/show/index.js11
-rw-r--r--app/assets/javascripts/user_lists/store/show/mutation_types.js8
-rw-r--r--app/assets/javascripts/user_lists/store/show/mutations.js29
-rw-r--r--app/assets/javascripts/user_lists/store/show/state.js9
-rw-r--r--app/assets/javascripts/user_lists/store/utils.js5
-rw-r--r--app/assets/javascripts/user_popovers.js3
-rw-r--r--app/assets/javascripts/users_select/index.js38
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/deployment/deployment_actions.vue7
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/deployment/deployment_view_button.vue7
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_author_time.vue7
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_header.vue3
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/source_branch_removal_status.vue7
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_archived.vue6
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_failed.vue14
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merged.vue17
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_missing_branch.vue7
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_rebase.vue24
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue34
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/squash_before_merge.vue31
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/work_in_progress.vue8
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/i18n.js7
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue20
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js1
-rw-r--r--app/assets/javascripts/vue_shared/components/actions_button.vue23
-rw-r--r--app/assets/javascripts/vue_shared/components/alert_details_table.vue49
-rw-r--r--app/assets/javascripts/vue_shared/components/awards_list.vue8
-rw-r--r--app/assets/javascripts/vue_shared/components/blob_viewers/mixins.js16
-rw-r--r--app/assets/javascripts/vue_shared/components/ci_badge_link.vue16
-rw-r--r--app/assets/javascripts/vue_shared/components/clipboard_button.vue27
-rw-r--r--app/assets/javascripts/vue_shared/components/commit.vue2
-rw-r--r--app/assets/javascripts/vue_shared/components/confirm_modal.vue11
-rw-r--r--app/assets/javascripts/vue_shared/components/content_viewer/content_viewer.vue37
-rw-r--r--app/assets/javascripts/vue_shared/components/content_viewer/viewers/download_viewer.vue13
-rw-r--r--app/assets/javascripts/vue_shared/components/deprecated_modal_2.vue33
-rw-r--r--app/assets/javascripts/vue_shared/components/dismissible_feedback_alert.vue14
-rw-r--r--app/assets/javascripts/vue_shared/components/dropdown/dropdown_search_input.vue6
-rw-r--r--app/assets/javascripts/vue_shared/components/droplab_dropdown_button.vue92
-rw-r--r--app/assets/javascripts/vue_shared/components/editor_lite.vue99
-rw-r--r--app/assets/javascripts/vue_shared/components/file_finder/index.vue11
-rw-r--r--app/assets/javascripts/vue_shared/components/file_icon/file_icon_map.js6
-rw-r--r--app/assets/javascripts/vue_shared/components/filtered_search_bar/store/modules/filters/actions.js121
-rw-r--r--app/assets/javascripts/vue_shared/components/filtered_search_bar/store/modules/filters/index.js10
-rw-r--r--app/assets/javascripts/vue_shared/components/filtered_search_bar/store/modules/filters/mutation_types.js26
-rw-r--r--app/assets/javascripts/vue_shared/components/filtered_search_bar/store/modules/filters/mutations.js109
-rw-r--r--app/assets/javascripts/vue_shared/components/filtered_search_bar/store/modules/filters/state.js47
-rw-r--r--app/assets/javascripts/vue_shared/components/gl_mentions.vue55
-rw-r--r--app/assets/javascripts/vue_shared/components/header_ci_component.vue62
-rw-r--r--app/assets/javascripts/vue_shared/components/local_storage_sync.vue48
-rw-r--r--app/assets/javascripts/vue_shared/components/markdown/field.vue59
-rw-r--r--app/assets/javascripts/vue_shared/components/markdown/suggestion_diff.vue6
-rw-r--r--app/assets/javascripts/vue_shared/components/markdown/suggestion_diff_header.vue7
-rw-r--r--app/assets/javascripts/vue_shared/components/markdown/suggestions.vue9
-rw-r--r--app/assets/javascripts/vue_shared/components/members/action_buttons/access_request_action_buttons.vue59
-rw-r--r--app/assets/javascripts/vue_shared/components/members/action_buttons/action_button_group.vue11
-rw-r--r--app/assets/javascripts/vue_shared/components/members/action_buttons/approve_access_request_button.vue42
-rw-r--r--app/assets/javascripts/vue_shared/components/members/action_buttons/group_action_buttons.vue27
-rw-r--r--app/assets/javascripts/vue_shared/components/members/action_buttons/invite_action_buttons.vue48
-rw-r--r--app/assets/javascripts/vue_shared/components/members/action_buttons/leave_button.vue40
-rw-r--r--app/assets/javascripts/vue_shared/components/members/action_buttons/remove_group_link_button.vue36
-rw-r--r--app/assets/javascripts/vue_shared/components/members/action_buttons/remove_member_button.vue57
-rw-r--r--app/assets/javascripts/vue_shared/components/members/action_buttons/resend_invite_button.vue41
-rw-r--r--app/assets/javascripts/vue_shared/components/members/action_buttons/user_action_buttons.vue61
-rw-r--r--app/assets/javascripts/vue_shared/components/members/avatars/group_avatar.vue34
-rw-r--r--app/assets/javascripts/vue_shared/components/members/avatars/invite_avatar.vue32
-rw-r--r--app/assets/javascripts/vue_shared/components/members/avatars/user_avatar.vue91
-rw-r--r--app/assets/javascripts/vue_shared/components/members/constants.js70
-rw-r--r--app/assets/javascripts/vue_shared/components/members/modals/leave_modal.vue70
-rw-r--r--app/assets/javascripts/vue_shared/components/members/modals/remove_group_link_modal.vue69
-rw-r--r--app/assets/javascripts/vue_shared/components/members/table/created_at.vue40
-rw-r--r--app/assets/javascripts/vue_shared/components/members/table/expires_at.vue66
-rw-r--r--app/assets/javascripts/vue_shared/components/members/table/member_action_buttons.vue57
-rw-r--r--app/assets/javascripts/vue_shared/components/members/table/member_avatar.vue35
-rw-r--r--app/assets/javascripts/vue_shared/components/members/table/member_source.vue27
-rw-r--r--app/assets/javascripts/vue_shared/components/members/table/members_table.vue110
-rw-r--r--app/assets/javascripts/vue_shared/components/members/table/members_table_cell.vue64
-rw-r--r--app/assets/javascripts/vue_shared/components/members/table/role_dropdown.vue70
-rw-r--r--app/assets/javascripts/vue_shared/components/members/utils.js19
-rw-r--r--app/assets/javascripts/vue_shared/components/modal_copy_button.vue21
-rw-r--r--app/assets/javascripts/vue_shared/components/navigation_tabs.vue7
-rw-r--r--app/assets/javascripts/vue_shared/components/notes/skeleton_note.vue2
-rw-r--r--app/assets/javascripts/vue_shared/components/paginated_table_with_search_and_tabs/constants.js21
-rw-r--r--app/assets/javascripts/vue_shared/components/paginated_table_with_search_and_tabs/paginated_table_with_search_and_tabs.vue313
-rw-r--r--app/assets/javascripts/vue_shared/components/paginated_table_with_search_and_tabs/utils.js11
-rw-r--r--app/assets/javascripts/vue_shared/components/registry/list_item.vue2
-rw-r--r--app/assets/javascripts/vue_shared/components/registry/title_area.vue78
-rw-r--r--app/assets/javascripts/vue_shared/components/rich_content_editor/constants.js15
-rw-r--r--app/assets/javascripts/vue_shared/components/rich_content_editor/modals/add_image/add_image_modal.vue4
-rw-r--r--app/assets/javascripts/vue_shared/components/rich_content_editor/modals/insert_video_modal.vue91
-rw-r--r--app/assets/javascripts/vue_shared/components/rich_content_editor/rich_content_editor.vue28
-rw-r--r--app/assets/javascripts/vue_shared/components/rich_content_editor/services/editor_service.js31
-rw-r--r--app/assets/javascripts/vue_shared/components/rich_content_editor/services/renderers/render_html_block.js18
-rw-r--r--app/assets/javascripts/vue_shared/components/rich_content_editor/services/sanitize_html.js22
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/collapsed_calendar_icon.vue16
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/dropdown_contents.vue1
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/dropdown_contents_labels_view.vue14
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/dropdown_value.vue19
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/labels_select_root.vue11
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/store/actions.js3
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/store/mutation_types.js1
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/store/mutations.js4
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/store/state.js1
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/toggle_sidebar.vue41
-rw-r--r--app/assets/javascripts/vue_shared/components/split_button.vue30
-rw-r--r--app/assets/javascripts/vue_shared/components/stacked_progress_bar.vue10
-rw-r--r--app/assets/javascripts/vue_shared/components/timezone_dropdown.vue35
-rw-r--r--app/assets/javascripts/vue_shared/components/todo_button.vue2
-rw-r--r--app/assets/javascripts/vue_shared/components/toggle_button.vue2
-rw-r--r--app/assets/javascripts/vue_shared/components/user_popover/user_popover.vue28
-rw-r--r--app/assets/javascripts/vue_shared/components/web_ide_link.vue92
-rw-r--r--app/assets/javascripts/vue_shared/directives/tooltip.js5
-rw-r--r--app/assets/javascripts/vue_shared/mixins/ci_pagination_api_mixin.js4
-rw-r--r--app/assets/javascripts/vue_shared/mixins/related_issuable_mixin.js2
-rw-r--r--app/assets/javascripts/vue_shared/security_reports/security_reports_app.vue107
-rw-r--r--app/assets/javascripts/vuex_shared/modules/members/actions.js25
-rw-r--r--app/assets/javascripts/vuex_shared/modules/members/index.js6
-rw-r--r--app/assets/javascripts/vuex_shared/modules/members/mutation_types.js7
-rw-r--r--app/assets/javascripts/vuex_shared/modules/members/mutations.js33
-rw-r--r--app/assets/javascripts/vuex_shared/modules/members/state.js16
-rw-r--r--app/assets/javascripts/vuex_shared/modules/members/utils.js1
-rw-r--r--app/assets/javascripts/whats_new/components/app.vue100
-rw-r--r--app/assets/javascripts/whats_new/components/skeleton_loader.vue25
-rw-r--r--app/assets/javascripts/whats_new/index.js2
-rw-r--r--app/assets/javascripts/whats_new/store/actions.js12
-rw-r--r--app/assets/javascripts/whats_new/store/mutation_types.js1
-rw-r--r--app/assets/javascripts/whats_new/store/mutations.js3
-rw-r--r--app/assets/javascripts/whats_new/store/state.js1
-rw-r--r--app/assets/stylesheets/_page_specific_files.scss19
-rw-r--r--app/assets/stylesheets/application.scss19
-rw-r--r--app/assets/stylesheets/application_utilities.scss12
-rw-r--r--app/assets/stylesheets/application_utilities_dark.scss3
-rw-r--r--app/assets/stylesheets/components/design_management/design.scss74
-rw-r--r--app/assets/stylesheets/components/rich_content_editor.scss8
-rw-r--r--app/assets/stylesheets/components/whats_new.scss25
-rw-r--r--app/assets/stylesheets/fontawesome_custom.scss65
-rw-r--r--app/assets/stylesheets/framework.scss1
-rw-r--r--app/assets/stylesheets/framework/animations.scss3
-rw-r--r--app/assets/stylesheets/framework/buttons.scss6
-rw-r--r--app/assets/stylesheets/framework/common.scss8
-rw-r--r--app/assets/stylesheets/framework/contextual_sidebar.scss27
-rw-r--r--app/assets/stylesheets/framework/diffs.scss1129
-rw-r--r--app/assets/stylesheets/framework/dropdowns.scss109
-rw-r--r--app/assets/stylesheets/framework/editor-lite.scss6
-rw-r--r--app/assets/stylesheets/framework/files.scss4
-rw-r--r--app/assets/stylesheets/framework/filters.scss29
-rw-r--r--app/assets/stylesheets/framework/header.scss12
-rw-r--r--app/assets/stylesheets/framework/icons.scss1
-rw-r--r--app/assets/stylesheets/framework/mixins.scss2
-rw-r--r--app/assets/stylesheets/framework/secondary_navigation_elements.scss30
-rw-r--r--app/assets/stylesheets/framework/snippets.scss27
-rw-r--r--app/assets/stylesheets/framework/tables.scss21
-rw-r--r--app/assets/stylesheets/framework/typography.scss4
-rw-r--r--app/assets/stylesheets/framework/variables.scss5
-rw-r--r--app/assets/stylesheets/framework/wells.scss6
-rw-r--r--app/assets/stylesheets/lazy_bundles/cropper.css378
-rw-r--r--app/assets/stylesheets/mailer.scss13
-rw-r--r--app/assets/stylesheets/page_bundles/_ide_theme_overrides.scss95
-rw-r--r--app/assets/stylesheets/page_bundles/_pipeline_mixins.scss233
-rw-r--r--app/assets/stylesheets/page_bundles/boards.scss613
-rw-r--r--app/assets/stylesheets/page_bundles/cycle_analytics.scss355
-rw-r--r--app/assets/stylesheets/page_bundles/dev_ops_report.scss261
-rw-r--r--app/assets/stylesheets/page_bundles/environments.scss131
-rw-r--r--app/assets/stylesheets/page_bundles/error_tracking_details.scss51
-rw-r--r--app/assets/stylesheets/page_bundles/error_tracking_index.scss40
-rw-r--r--app/assets/stylesheets/page_bundles/experimental_separate_sign_up.scss96
-rw-r--r--app/assets/stylesheets/page_bundles/ide_themes/_dark.scss12
-rw-r--r--app/assets/stylesheets/page_bundles/ide_themes/_solarized-dark.scss14
-rw-r--r--app/assets/stylesheets/page_bundles/issues_list.scss45
-rw-r--r--app/assets/stylesheets/page_bundles/jira_connect.scss77
-rw-r--r--app/assets/stylesheets/page_bundles/jira_connect_users.scss13
-rw-r--r--app/assets/stylesheets/page_bundles/merge_conflicts.scss316
-rw-r--r--app/assets/stylesheets/page_bundles/merge_requests.scss96
-rw-r--r--app/assets/stylesheets/page_bundles/milestone.scss254
-rw-r--r--app/assets/stylesheets/page_bundles/pipeline.scss484
-rw-r--r--app/assets/stylesheets/page_bundles/pipelines.scss195
-rw-r--r--app/assets/stylesheets/page_bundles/reports.scss94
-rw-r--r--app/assets/stylesheets/page_bundles/terminal.scss3
-rw-r--r--app/assets/stylesheets/page_bundles/wiki.scss159
-rw-r--r--app/assets/stylesheets/pages/alert_management/details.scss2
-rw-r--r--app/assets/stylesheets/pages/boards.scss613
-rw-r--r--app/assets/stylesheets/pages/builds.scss11
-rw-r--r--app/assets/stylesheets/pages/commits.scss1
-rw-r--r--app/assets/stylesheets/pages/cycle_analytics.scss353
-rw-r--r--app/assets/stylesheets/pages/dev_ops_report.scss259
-rw-r--r--app/assets/stylesheets/pages/diff.scss1193
-rw-r--r--app/assets/stylesheets/pages/environments.scss140
-rw-r--r--app/assets/stylesheets/pages/error_details.scss49
-rw-r--r--app/assets/stylesheets/pages/error_list.scss34
-rw-r--r--app/assets/stylesheets/pages/error_tracking_list.scss5
-rw-r--r--app/assets/stylesheets/pages/experience_level.scss29
-rw-r--r--app/assets/stylesheets/pages/experimental_separate_sign_up.scss60
-rw-r--r--app/assets/stylesheets/pages/graph.scss74
-rw-r--r--app/assets/stylesheets/pages/groups.scss72
-rw-r--r--app/assets/stylesheets/pages/incident_management_list.scss20
-rw-r--r--app/assets/stylesheets/pages/issuable.scss13
-rw-r--r--app/assets/stylesheets/pages/issues.scss45
-rw-r--r--app/assets/stylesheets/pages/issues/issues_list.scss5
-rw-r--r--app/assets/stylesheets/pages/labels.scss91
-rw-r--r--app/assets/stylesheets/pages/members.scss21
-rw-r--r--app/assets/stylesheets/pages/merge_conflicts.scss307
-rw-r--r--app/assets/stylesheets/pages/merge_requests.scss31
-rw-r--r--app/assets/stylesheets/pages/milestone.scss252
-rw-r--r--app/assets/stylesheets/pages/notes.scss50
-rw-r--r--app/assets/stylesheets/pages/pipelines.scss1005
-rw-r--r--app/assets/stylesheets/pages/profile.scss21
-rw-r--r--app/assets/stylesheets/pages/projects.scss102
-rw-r--r--app/assets/stylesheets/pages/reports.scss132
-rw-r--r--app/assets/stylesheets/pages/search.scss22
-rw-r--r--app/assets/stylesheets/pages/serverless.scss3
-rw-r--r--app/assets/stylesheets/pages/settings_ci_cd.scss4
-rw-r--r--app/assets/stylesheets/pages/tags.scss3
-rw-r--r--app/assets/stylesheets/pages/ui_dev_kit.scss17
-rw-r--r--app/assets/stylesheets/pages/wiki.scss157
-rw-r--r--app/assets/stylesheets/themes/_dark.scss3
-rw-r--r--app/assets/stylesheets/utilities.scss48
-rw-r--r--app/channels/application_cable/connection.rb6
-rw-r--r--app/controllers/abuse_reports_controller.rb2
-rw-r--r--app/controllers/admin/abuse_reports_controller.rb2
-rw-r--r--app/controllers/admin/appearances_controller.rb2
-rw-r--r--app/controllers/admin/application_settings_controller.rb21
-rw-r--r--app/controllers/admin/applications_controller.rb2
-rw-r--r--app/controllers/admin/background_jobs_controller.rb1
-rw-r--r--app/controllers/admin/broadcast_messages_controller.rb2
-rw-r--r--app/controllers/admin/ci/variables_controller.rb2
-rw-r--r--app/controllers/admin/cohorts_controller.rb2
-rw-r--r--app/controllers/admin/concerns/authenticates_2fa_for_admin_mode.rb110
-rw-r--r--app/controllers/admin/dashboard_controller.rb2
-rw-r--r--app/controllers/admin/deploy_keys_controller.rb2
-rw-r--r--app/controllers/admin/dev_ops_report_controller.rb2
-rw-r--r--app/controllers/admin/gitaly_servers_controller.rb2
-rw-r--r--app/controllers/admin/groups_controller.rb2
-rw-r--r--app/controllers/admin/health_check_controller.rb2
-rw-r--r--app/controllers/admin/hook_logs_controller.rb2
-rw-r--r--app/controllers/admin/hooks_controller.rb4
-rw-r--r--app/controllers/admin/identities_controller.rb2
-rw-r--r--app/controllers/admin/impersonation_tokens_controller.rb2
-rw-r--r--app/controllers/admin/impersonations_controller.rb2
-rw-r--r--app/controllers/admin/instance_review_controller.rb39
-rw-r--r--app/controllers/admin/instance_statistics_controller.rb2
-rw-r--r--app/controllers/admin/integrations_controller.rb5
-rw-r--r--app/controllers/admin/jobs_controller.rb2
-rw-r--r--app/controllers/admin/keys_controller.rb2
-rw-r--r--app/controllers/admin/labels_controller.rb2
-rw-r--r--app/controllers/admin/plan_limits_controller.rb2
-rw-r--r--app/controllers/admin/projects_controller.rb3
-rw-r--r--app/controllers/admin/requests_profiles_controller.rb2
-rw-r--r--app/controllers/admin/runner_projects_controller.rb2
-rw-r--r--app/controllers/admin/runners_controller.rb10
-rw-r--r--app/controllers/admin/serverless/domains_controller.rb2
-rw-r--r--app/controllers/admin/services_controller.rb2
-rw-r--r--app/controllers/admin/sessions_controller.rb9
-rw-r--r--app/controllers/admin/spam_logs_controller.rb2
-rw-r--r--app/controllers/admin/system_info_controller.rb2
-rw-r--r--app/controllers/admin/users_controller.rb23
-rw-r--r--app/controllers/application_controller.rb12
-rw-r--r--app/controllers/autocomplete_controller.rb6
-rw-r--r--app/controllers/boards/issues_controller.rb2
-rw-r--r--app/controllers/boards/lists_controller.rb4
-rw-r--r--app/controllers/clusters/base_controller.rb2
-rw-r--r--app/controllers/clusters/clusters_controller.rb29
-rw-r--r--app/controllers/concerns/authenticates_with_two_factor.rb21
-rw-r--r--app/controllers/concerns/authenticates_with_two_factor_for_admin_mode.rb107
-rw-r--r--app/controllers/concerns/boards_actions.rb4
-rw-r--r--app/controllers/concerns/controller_with_feature_category.rb29
-rw-r--r--app/controllers/concerns/controller_with_feature_category/config.rb38
-rw-r--r--app/controllers/concerns/hooks_execution.rb15
-rw-r--r--app/controllers/concerns/integrations_actions.rb2
-rw-r--r--app/controllers/concerns/issuable_collections.rb10
-rw-r--r--app/controllers/concerns/issuable_collections_action.rb5
-rw-r--r--app/controllers/concerns/membership_actions.rb18
-rw-r--r--app/controllers/concerns/milestone_actions.rb14
-rw-r--r--app/controllers/concerns/multiple_boards_actions.rb6
-rw-r--r--app/controllers/concerns/redis_tracking.rb14
-rw-r--r--app/controllers/concerns/runner_setup_scripts.rb25
-rw-r--r--app/controllers/concerns/show_inherited_labels_checker.rb11
-rw-r--r--app/controllers/concerns/snippets_actions.rb40
-rw-r--r--app/controllers/concerns/wiki_actions.rb8
-rw-r--r--app/controllers/confirmations_controller.rb2
-rw-r--r--app/controllers/dashboard/groups_controller.rb2
-rw-r--r--app/controllers/dashboard/labels_controller.rb6
-rw-r--r--app/controllers/dashboard/milestones_controller.rb2
-rw-r--r--app/controllers/dashboard/projects_controller.rb2
-rw-r--r--app/controllers/dashboard/snippets_controller.rb2
-rw-r--r--app/controllers/dashboard/todos_controller.rb2
-rw-r--r--app/controllers/dashboard_controller.rb4
-rw-r--r--app/controllers/explore/groups_controller.rb2
-rw-r--r--app/controllers/explore/projects_controller.rb2
-rw-r--r--app/controllers/explore/snippets_controller.rb2
-rw-r--r--app/controllers/google_api/authorizations_controller.rb2
-rw-r--r--app/controllers/graphql_controller.rb16
-rw-r--r--app/controllers/groups/avatars_controller.rb2
-rw-r--r--app/controllers/groups/boards_controller.rb2
-rw-r--r--app/controllers/groups/children_controller.rb2
-rw-r--r--app/controllers/groups/deploy_tokens_controller.rb2
-rw-r--r--app/controllers/groups/group_links_controller.rb11
-rw-r--r--app/controllers/groups/group_members_controller.rb6
-rw-r--r--app/controllers/groups/imports_controller.rb2
-rw-r--r--app/controllers/groups/labels_controller.rb30
-rw-r--r--app/controllers/groups/milestones_controller.rb4
-rw-r--r--app/controllers/groups/packages_controller.rb2
-rw-r--r--app/controllers/groups/registry/repositories_controller.rb6
-rw-r--r--app/controllers/groups/releases_controller.rb2
-rw-r--r--app/controllers/groups/runners_controller.rb2
-rw-r--r--app/controllers/groups/settings/ci_cd_controller.rb8
-rw-r--r--app/controllers/groups/settings/integrations_controller.rb2
-rw-r--r--app/controllers/groups/settings/repository_controller.rb2
-rw-r--r--app/controllers/groups/shared_projects_controller.rb2
-rw-r--r--app/controllers/groups/uploads_controller.rb2
-rw-r--r--app/controllers/groups/variables_controller.rb2
-rw-r--r--app/controllers/groups_controller.rb26
-rw-r--r--app/controllers/help_controller.rb57
-rw-r--r--app/controllers/ide_controller.rb2
-rw-r--r--app/controllers/import/available_namespaces_controller.rb2
-rw-r--r--app/controllers/import/base_controller.rb1
-rw-r--r--app/controllers/import/bulk_imports_controller.rb109
-rw-r--r--app/controllers/import/fogbugz_controller.rb2
-rw-r--r--app/controllers/import/github_controller.rb2
-rw-r--r--app/controllers/import/gitlab_groups_controller.rb2
-rw-r--r--app/controllers/import/manifest_controller.rb11
-rw-r--r--app/controllers/invites_controller.rb59
-rw-r--r--app/controllers/jira_connect/application_controller.rb2
-rw-r--r--app/controllers/jira_connect/events_controller.rb4
-rw-r--r--app/controllers/jira_connect/users_controller.rb11
-rw-r--r--app/controllers/jwt_controller.rb2
-rw-r--r--app/controllers/notification_settings_controller.rb2
-rw-r--r--app/controllers/oauth/jira/authorizations_controller.rb2
-rw-r--r--app/controllers/omniauth_callbacks_controller.rb5
-rw-r--r--app/controllers/passwords_controller.rb2
-rw-r--r--app/controllers/profiles/accounts_controller.rb2
-rw-r--r--app/controllers/profiles/active_sessions_controller.rb2
-rw-r--r--app/controllers/profiles/avatars_controller.rb2
-rw-r--r--app/controllers/profiles/chat_names_controller.rb2
-rw-r--r--app/controllers/profiles/emails_controller.rb2
-rw-r--r--app/controllers/profiles/gpg_keys_controller.rb2
-rw-r--r--app/controllers/profiles/groups_controller.rb2
-rw-r--r--app/controllers/profiles/keys_controller.rb2
-rw-r--r--app/controllers/profiles/notifications_controller.rb2
-rw-r--r--app/controllers/profiles/passwords_controller.rb2
-rw-r--r--app/controllers/profiles/personal_access_tokens_controller.rb2
-rw-r--r--app/controllers/profiles/preferences_controller.rb2
-rw-r--r--app/controllers/profiles/two_factor_auths_controller.rb7
-rw-r--r--app/controllers/profiles/u2f_registrations_controller.rb2
-rw-r--r--app/controllers/profiles/webauthn_registrations_controller.rb2
-rw-r--r--app/controllers/profiles_controller.rb5
-rw-r--r--app/controllers/projects/alert_management_controller.rb3
-rw-r--r--app/controllers/projects/alerting/notifications_controller.rb2
-rw-r--r--app/controllers/projects/artifacts_controller.rb2
-rw-r--r--app/controllers/projects/autocomplete_sources_controller.rb5
-rw-r--r--app/controllers/projects/avatars_controller.rb2
-rw-r--r--app/controllers/projects/badges_controller.rb2
-rw-r--r--app/controllers/projects/blame_controller.rb2
-rw-r--r--app/controllers/projects/blob_controller.rb5
-rw-r--r--app/controllers/projects/boards_controller.rb2
-rw-r--r--app/controllers/projects/branches_controller.rb2
-rw-r--r--app/controllers/projects/build_artifacts_controller.rb2
-rw-r--r--app/controllers/projects/builds_controller.rb2
-rw-r--r--app/controllers/projects/ci/daily_build_group_report_results_controller.rb9
-rw-r--r--app/controllers/projects/ci/lints_controller.rb2
-rw-r--r--app/controllers/projects/commit_controller.rb2
-rw-r--r--app/controllers/projects/commits_controller.rb2
-rw-r--r--app/controllers/projects/compare_controller.rb2
-rw-r--r--app/controllers/projects/confluences_controller.rb2
-rw-r--r--app/controllers/projects/cycle_analytics/events_controller.rb2
-rw-r--r--app/controllers/projects/cycle_analytics_controller.rb2
-rw-r--r--app/controllers/projects/deploy_keys_controller.rb2
-rw-r--r--app/controllers/projects/deploy_tokens_controller.rb2
-rw-r--r--app/controllers/projects/deployments_controller.rb2
-rw-r--r--app/controllers/projects/design_management/designs_controller.rb2
-rw-r--r--app/controllers/projects/discussions_controller.rb2
-rw-r--r--app/controllers/projects/environments/prometheus_api_controller.rb2
-rw-r--r--app/controllers/projects/environments/sample_metrics_controller.rb2
-rw-r--r--app/controllers/projects/environments_controller.rb2
-rw-r--r--app/controllers/projects/error_tracking/base_controller.rb2
-rw-r--r--app/controllers/projects/error_tracking/projects_controller.rb2
-rw-r--r--app/controllers/projects/feature_flags_clients_controller.rb29
-rw-r--r--app/controllers/projects/feature_flags_controller.rb174
-rw-r--r--app/controllers/projects/feature_flags_user_lists_controller.rb23
-rw-r--r--app/controllers/projects/find_file_controller.rb2
-rw-r--r--app/controllers/projects/forks_controller.rb2
-rw-r--r--app/controllers/projects/grafana_api_controller.rb2
-rw-r--r--app/controllers/projects/graphs_controller.rb3
-rw-r--r--app/controllers/projects/group_links_controller.rb15
-rw-r--r--app/controllers/projects/hook_logs_controller.rb2
-rw-r--r--app/controllers/projects/hooks_controller.rb4
-rw-r--r--app/controllers/projects/import/jira_controller.rb2
-rw-r--r--app/controllers/projects/imports_controller.rb2
-rw-r--r--app/controllers/projects/incident_management/pager_duty_incidents_controller.rb2
-rw-r--r--app/controllers/projects/incidents_controller.rb39
-rw-r--r--app/controllers/projects/issue_links_controller.rb2
-rw-r--r--app/controllers/projects/issues_controller.rb24
-rw-r--r--app/controllers/projects/jobs_controller.rb55
-rw-r--r--app/controllers/projects/labels_controller.rb5
-rw-r--r--app/controllers/projects/logs_controller.rb2
-rw-r--r--app/controllers/projects/mattermosts_controller.rb2
-rw-r--r--app/controllers/projects/merge_requests/application_controller.rb3
-rw-r--r--app/controllers/projects/merge_requests/diffs_controller.rb3
-rw-r--r--app/controllers/projects/merge_requests/drafts_controller.rb2
-rw-r--r--app/controllers/projects/merge_requests_controller.rb29
-rw-r--r--app/controllers/projects/metrics/dashboards/builder_controller.rb2
-rw-r--r--app/controllers/projects/metrics_dashboard_controller.rb2
-rw-r--r--app/controllers/projects/milestones_controller.rb6
-rw-r--r--app/controllers/projects/mirrors_controller.rb2
-rw-r--r--app/controllers/projects/network_controller.rb2
-rw-r--r--app/controllers/projects/notes_controller.rb2
-rw-r--r--app/controllers/projects/packages/package_files_controller.rb2
-rw-r--r--app/controllers/projects/packages/packages_controller.rb9
-rw-r--r--app/controllers/projects/pages_controller.rb2
-rw-r--r--app/controllers/projects/pages_domains_controller.rb2
-rw-r--r--app/controllers/projects/performance_monitoring/dashboards_controller.rb2
-rw-r--r--app/controllers/projects/pipeline_schedules_controller.rb2
-rw-r--r--app/controllers/projects/pipelines/application_controller.rb2
-rw-r--r--app/controllers/projects/pipelines_controller.rb18
-rw-r--r--app/controllers/projects/pipelines_settings_controller.rb2
-rw-r--r--app/controllers/projects/product_analytics_controller.rb2
-rw-r--r--app/controllers/projects/project_members_controller.rb6
-rw-r--r--app/controllers/projects/prometheus/alerts_controller.rb2
-rw-r--r--app/controllers/projects/prometheus/metrics_controller.rb2
-rw-r--r--app/controllers/projects/protected_refs_controller.rb4
-rw-r--r--app/controllers/projects/raw_controller.rb2
-rw-r--r--app/controllers/projects/refs_controller.rb2
-rw-r--r--app/controllers/projects/registry/application_controller.rb2
-rw-r--r--app/controllers/projects/registry/repositories_controller.rb6
-rw-r--r--app/controllers/projects/registry/tags_controller.rb9
-rw-r--r--app/controllers/projects/releases/evidences_controller.rb2
-rw-r--r--app/controllers/projects/releases_controller.rb14
-rw-r--r--app/controllers/projects/repositories_controller.rb2
-rw-r--r--app/controllers/projects/runner_projects_controller.rb2
-rw-r--r--app/controllers/projects/runners_controller.rb6
-rw-r--r--app/controllers/projects/serverless/functions_controller.rb2
-rw-r--r--app/controllers/projects/service_desk_controller.rb2
-rw-r--r--app/controllers/projects/services_controller.rb4
-rw-r--r--app/controllers/projects/settings/access_tokens_controller.rb2
-rw-r--r--app/controllers/projects/settings/ci_cd_controller.rb25
-rw-r--r--app/controllers/projects/settings/integrations_controller.rb2
-rw-r--r--app/controllers/projects/settings/operations_controller.rb37
-rw-r--r--app/controllers/projects/settings/repository_controller.rb5
-rw-r--r--app/controllers/projects/snippets/application_controller.rb2
-rw-r--r--app/controllers/projects/snippets_controller.rb25
-rw-r--r--app/controllers/projects/starrers_controller.rb2
-rw-r--r--app/controllers/projects/static_site_editor_controller.rb24
-rw-r--r--app/controllers/projects/tags/releases_controller.rb2
-rw-r--r--app/controllers/projects/tags_controller.rb26
-rw-r--r--app/controllers/projects/templates_controller.rb2
-rw-r--r--app/controllers/projects/todos_controller.rb2
-rw-r--r--app/controllers/projects/tracings_controller.rb28
-rw-r--r--app/controllers/projects/tree_controller.rb2
-rw-r--r--app/controllers/projects/triggers_controller.rb2
-rw-r--r--app/controllers/projects/uploads_controller.rb2
-rw-r--r--app/controllers/projects/usage_ping_controller.rb2
-rw-r--r--app/controllers/projects/variables_controller.rb2
-rw-r--r--app/controllers/projects/web_ide_schemas_controller.rb2
-rw-r--r--app/controllers/projects/web_ide_terminals_controller.rb2
-rw-r--r--app/controllers/projects/wikis_controller.rb2
-rw-r--r--app/controllers/projects_controller.rb23
-rw-r--r--app/controllers/registrations/experience_levels_controller.rb10
-rw-r--r--app/controllers/registrations_controller.rb52
-rw-r--r--app/controllers/repositories/git_http_client_controller.rb2
-rw-r--r--app/controllers/runner_setup_controller.rb9
-rw-r--r--app/controllers/search_controller.rb8
-rw-r--r--app/controllers/sent_notifications_controller.rb2
-rw-r--r--app/controllers/sessions_controller.rb9
-rw-r--r--app/controllers/snippets/application_controller.rb2
-rw-r--r--app/controllers/snippets/notes_controller.rb2
-rw-r--r--app/controllers/snippets_controller.rb27
-rw-r--r--app/controllers/uploads_controller.rb2
-rw-r--r--app/controllers/user_callouts_controller.rb2
-rw-r--r--app/controllers/users/terms_controller.rb2
-rw-r--r--app/controllers/users_controller.rb4
-rw-r--r--app/controllers/whats_new_controller.rb25
-rw-r--r--app/finders/README.md11
-rw-r--r--app/finders/alert_management/alerts_finder.rb14
-rw-r--r--app/finders/ci/jobs_finder.rb4
-rw-r--r--app/finders/concerns/time_frame_filter.rb7
-rw-r--r--app/finders/environment_names_finder.rb47
-rw-r--r--app/finders/group_labels_finder.rb29
-rw-r--r--app/finders/group_members_finder.rb28
-rw-r--r--app/finders/groups_finder.rb12
-rw-r--r--app/finders/issuable_finder.rb18
-rw-r--r--app/finders/keys_finder.rb2
-rw-r--r--app/finders/merge_requests/by_approvals_finder.rb93
-rw-r--r--app/finders/merge_requests_finder.rb63
-rw-r--r--app/finders/milestones_finder.rb3
-rw-r--r--app/finders/packages/generic/package_finder.rb22
-rw-r--r--app/finders/projects_finder.rb13
-rw-r--r--app/finders/releases_finder.rb10
-rw-r--r--app/graphql/batch_loaders/merge_request_diff_summary_batch_loader.rb29
-rw-r--r--app/graphql/mutations/award_emojis/base.rb7
-rw-r--r--app/graphql/mutations/base_mutation.rb1
-rw-r--r--app/graphql/mutations/boards/create.rb78
-rw-r--r--app/graphql/mutations/boards/lists/destroy.rb41
-rw-r--r--app/graphql/mutations/ci/base.rb7
-rw-r--r--app/graphql/mutations/concerns/mutations/spammable_mutation_fields.rb24
-rw-r--r--app/graphql/mutations/design_management/move.rb11
-rw-r--r--app/graphql/mutations/discussions/toggle_resolve.rb7
-rw-r--r--app/graphql/mutations/issues/common_mutation_arguments.rb28
-rw-r--r--app/graphql/mutations/issues/create.rb109
-rw-r--r--app/graphql/mutations/issues/move.rb33
-rw-r--r--app/graphql/mutations/issues/update.rb43
-rw-r--r--app/graphql/mutations/merge_requests/set_milestone.rb2
-rw-r--r--app/graphql/mutations/metrics/dashboard/annotations/create.rb19
-rw-r--r--app/graphql/mutations/notes/base.rb19
-rw-r--r--app/graphql/mutations/notes/create/base.rb11
-rw-r--r--app/graphql/mutations/notes/create/note.rb8
-rw-r--r--app/graphql/mutations/notes/destroy.rb8
-rw-r--r--app/graphql/mutations/notes/update/base.rb2
-rw-r--r--app/graphql/mutations/notes/update/image_diff_note.rb4
-rw-r--r--app/graphql/mutations/notes/update/note.rb4
-rw-r--r--app/graphql/mutations/snippets/create.rb29
-rw-r--r--app/graphql/mutations/snippets/update.rb22
-rw-r--r--app/graphql/mutations/todos/base.rb7
-rw-r--r--app/graphql/mutations/todos/mark_done.rb2
-rw-r--r--app/graphql/mutations/todos/restore.rb2
-rw-r--r--app/graphql/mutations/todos/restore_many.rb18
-rw-r--r--app/graphql/queries/repository/path_last_commit.query.graphql47
-rw-r--r--app/graphql/resolvers/alert_management/alert_resolver.rb4
-rw-r--r--app/graphql/resolvers/alert_management/alert_status_counts_resolver.rb4
-rw-r--r--app/graphql/resolvers/assigned_merge_requests_resolver.rb2
-rw-r--r--app/graphql/resolvers/authored_merge_requests_resolver.rb2
-rw-r--r--app/graphql/resolvers/base_resolver.rb3
-rw-r--r--app/graphql/resolvers/board_list_issues_resolver.rb2
-rw-r--r--app/graphql/resolvers/board_lists_resolver.rb10
-rw-r--r--app/graphql/resolvers/board_resolver.rb27
-rw-r--r--app/graphql/resolvers/boards_resolver.rb2
-rw-r--r--app/graphql/resolvers/ci/runner_platforms_resolver.rb30
-rw-r--r--app/graphql/resolvers/concerns/group_issuable_resolver.rb14
-rw-r--r--app/graphql/resolvers/concerns/issue_resolver_arguments.rb6
-rw-r--r--app/graphql/resolvers/concerns/looks_ahead.rb4
-rw-r--r--app/graphql/resolvers/concerns/resolves_merge_requests.rb9
-rw-r--r--app/graphql/resolvers/concerns/time_frame_arguments.rb20
-rw-r--r--app/graphql/resolvers/group_issues_resolver.rb7
-rw-r--r--app/graphql/resolvers/group_merge_requests_resolver.rb25
-rw-r--r--app/graphql/resolvers/merge_requests_resolver.rb12
-rw-r--r--app/graphql/resolvers/milestones_resolver.rb27
-rw-r--r--app/graphql/resolvers/project_merge_requests_resolver.rb8
-rw-r--r--app/graphql/resolvers/projects/jira_projects_resolver.rb2
-rw-r--r--app/graphql/resolvers/projects_resolver.rb16
-rw-r--r--app/graphql/resolvers/snippets/blobs_resolver.rb40
-rw-r--r--app/graphql/resolvers/terraform/states_resolver.rb23
-rw-r--r--app/graphql/types/admin/analytics/instance_statistics/measurement_identifier_enum.rb16
-rw-r--r--app/graphql/types/alert_management/alert_status_counts_type.rb4
-rw-r--r--app/graphql/types/alert_management/alert_type.rb8
-rw-r--r--app/graphql/types/alert_management/status_enum.rb4
-rw-r--r--app/graphql/types/base_argument.rb14
-rw-r--r--app/graphql/types/base_field.rb2
-rw-r--r--app/graphql/types/board_list_type.rb7
-rw-r--r--app/graphql/types/ci/detailed_status_type.rb47
-rw-r--r--app/graphql/types/ci/group_type.rb3
-rw-r--r--app/graphql/types/ci/job_type.rb5
-rw-r--r--app/graphql/types/ci/runner_architecture_type.rb15
-rw-r--r--app/graphql/types/ci/runner_platform_type.rb17
-rw-r--r--app/graphql/types/ci/stage_type.rb3
-rw-r--r--app/graphql/types/ci/status_action_type.rb25
-rw-r--r--app/graphql/types/date_type.rb22
-rw-r--r--app/graphql/types/design_management/design_collection_copy_state_enum.rb27
-rw-r--r--app/graphql/types/design_management/design_collection_type.rb4
-rw-r--r--app/graphql/types/design_management/design_type.rb2
-rw-r--r--app/graphql/types/environment_type.rb8
-rw-r--r--app/graphql/types/global_id_type.rb16
-rw-r--r--app/graphql/types/group_type.rb10
-rw-r--r--app/graphql/types/issue_sort_enum.rb2
-rw-r--r--app/graphql/types/issue_state_event_enum.rb11
-rw-r--r--app/graphql/types/issue_type.rb21
-rw-r--r--app/graphql/types/label_type.rb2
-rw-r--r--app/graphql/types/merge_request_type.rb30
-rw-r--r--app/graphql/types/mutation_type.rb5
-rw-r--r--app/graphql/types/notes/noteable_type.rb32
-rw-r--r--app/graphql/types/package_type_enum.rb8
-rw-r--r--app/graphql/types/project_member_type.rb7
-rw-r--r--app/graphql/types/project_type.rb8
-rw-r--r--app/graphql/types/query_type.rb19
-rw-r--r--app/graphql/types/range_input_type.rb29
-rw-r--r--app/graphql/types/root_storage_statistics_type.rb1
-rw-r--r--app/graphql/types/snippet_type.rb19
-rw-r--r--app/graphql/types/sort_enum.rb15
-rw-r--r--app/graphql/types/terraform/state_type.rb37
-rw-r--r--app/graphql/types/timeframe_input_type.rb10
-rw-r--r--app/helpers/analytics/navbar_helper.rb2
-rw-r--r--app/helpers/analytics/unique_visits_helper.rb3
-rw-r--r--app/helpers/application_helper.rb24
-rw-r--r--app/helpers/application_settings_helper.rb14
-rw-r--r--app/helpers/avatars_helper.rb2
-rw-r--r--app/helpers/blob_helper.rb26
-rw-r--r--app/helpers/boards_helper.rb22
-rw-r--r--app/helpers/ci/runners_helper.rb8
-rw-r--r--app/helpers/clusters_helper.rb20
-rw-r--r--app/helpers/container_expiration_policies_helper.rb5
-rw-r--r--app/helpers/dropdowns_helper.rb2
-rw-r--r--app/helpers/emails_helper.rb20
-rw-r--r--app/helpers/events_helper.rb16
-rw-r--r--app/helpers/external_link_helper.rb2
-rw-r--r--app/helpers/feature_flags_helper.rb19
-rw-r--r--app/helpers/form_helper.rb26
-rw-r--r--app/helpers/gitlab_routing_helper.rb12
-rw-r--r--app/helpers/gitpod_helper.rb10
-rw-r--r--app/helpers/groups/group_members_helper.rb42
-rw-r--r--app/helpers/icons_helper.rb20
-rw-r--r--app/helpers/invite_members_helper.rb21
-rw-r--r--app/helpers/issuables_helper.rb58
-rw-r--r--app/helpers/issues_helper.rb15
-rw-r--r--app/helpers/labels_helper.rb31
-rw-r--r--app/helpers/merge_requests_helper.rb4
-rw-r--r--app/helpers/mirror_helper.rb6
-rw-r--r--app/helpers/namespaces_helper.rb2
-rw-r--r--app/helpers/nav_helper.rb3
-rw-r--r--app/helpers/operations_helper.rb2
-rw-r--r--app/helpers/packages_helper.rb22
-rw-r--r--app/helpers/page_layout_helper.rb8
-rw-r--r--app/helpers/pagination_helper.rb10
-rw-r--r--app/helpers/preferences_helper.rb4
-rw-r--r--app/helpers/projects/alert_management_helper.rb4
-rw-r--r--app/helpers/projects/incidents_helper.rb7
-rw-r--r--app/helpers/projects_helper.rb32
-rw-r--r--app/helpers/releases_helper.rb9
-rw-r--r--app/helpers/reminder_emails_helper.rb76
-rw-r--r--app/helpers/search_helper.rb51
-rw-r--r--app/helpers/services_helper.rb6
-rw-r--r--app/helpers/snippets_helper.rb25
-rw-r--r--app/helpers/ssh_keys_helper.rb18
-rw-r--r--app/helpers/startupjs_helper.rb17
-rw-r--r--app/helpers/suggest_pipeline_helper.rb2
-rw-r--r--app/helpers/system_note_helper.rb6
-rw-r--r--app/helpers/tags_helper.rb9
-rw-r--r--app/helpers/timeboxes_helper.rb4
-rw-r--r--app/helpers/todos_helper.rb9
-rw-r--r--app/helpers/tree_helper.rb45
-rw-r--r--app/helpers/user_callouts_helper.rb6
-rw-r--r--app/helpers/users_helper.rb13
-rw-r--r--app/helpers/visibility_level_helper.rb17
-rw-r--r--app/helpers/web_ide_button_helper.rb61
-rw-r--r--app/helpers/webpack_helper.rb14
-rw-r--r--app/helpers/whats_new_helper.rb27
-rw-r--r--app/helpers/wiki_helper.rb3
-rw-r--r--app/mailers/abuse_report_mailer.rb4
-rw-r--r--app/mailers/emails/issues.rb2
-rw-r--r--app/mailers/emails/members.rb32
-rw-r--r--app/mailers/emails/merge_requests.rb25
-rw-r--r--app/mailers/emails/projects.rb10
-rw-r--r--app/mailers/notify.rb2
-rw-r--r--app/models/alert_management/alert.rb80
-rw-r--r--app/models/alert_management/http_integration.rb41
-rw-r--r--app/models/analytics/instance_statistics/measurement.rb22
-rw-r--r--app/models/application_record.rb14
-rw-r--r--app/models/application_setting.rb16
-rw-r--r--app/models/application_setting/term.rb2
-rw-r--r--app/models/application_setting_implementation.rb2
-rw-r--r--app/models/audit_event.rb18
-rw-r--r--app/models/authentication_event.rb10
-rw-r--r--app/models/blob_viewer/balsamiq.rb2
-rw-r--r--app/models/blob_viewer/markup.rb10
-rw-r--r--app/models/blob_viewer/pdf.rb2
-rw-r--r--app/models/blob_viewer/sketch.rb2
-rw-r--r--app/models/bulk_import.rb16
-rw-r--r--app/models/bulk_imports/configuration.rb20
-rw-r--r--app/models/bulk_imports/entity.rb43
-rw-r--r--app/models/ci/bridge.rb30
-rw-r--r--app/models/ci/build.rb45
-rw-r--r--app/models/ci/build_pending_state.rb6
-rw-r--r--app/models/ci/build_trace_chunk.rb104
-rw-r--r--app/models/ci/build_trace_chunks/database.rb2
-rw-r--r--app/models/ci/deleted_object.rb37
-rw-r--r--app/models/ci/job_artifact.rb32
-rw-r--r--app/models/ci/pipeline.rb46
-rw-r--r--app/models/ci_platform_metric.rb2
-rw-r--r--app/models/clusters/agent.rb1
-rw-r--r--app/models/clusters/applications/fluentd.rb6
-rw-r--r--app/models/clusters/applications/ingress.rb7
-rw-r--r--app/models/clusters/applications/prometheus.rb8
-rw-r--r--app/models/clusters/applications/runner.rb2
-rw-r--r--app/models/clusters/platforms/kubernetes.rb3
-rw-r--r--app/models/commit.rb32
-rw-r--r--app/models/commit_status.rb10
-rw-r--r--app/models/concerns/approvable_base.rb24
-rw-r--r--app/models/concerns/avatarable.rb15
-rw-r--r--app/models/concerns/checksummable.rb8
-rw-r--r--app/models/concerns/counter_attribute.rb29
-rw-r--r--app/models/concerns/has_repository.rb10
-rw-r--r--app/models/concerns/has_user_type.rb6
-rw-r--r--app/models/concerns/integration.rb4
-rw-r--r--app/models/concerns/issuable.rb11
-rw-r--r--app/models/concerns/issue_available_features.rb23
-rw-r--r--app/models/concerns/mentionable.rb16
-rw-r--r--app/models/concerns/presentable.rb4
-rw-r--r--app/models/concerns/reactive_caching.rb5
-rw-r--r--app/models/concerns/reactive_service.rb1
-rw-r--r--app/models/concerns/referable.rb2
-rw-r--r--app/models/concerns/relative_positioning.rb43
-rw-r--r--app/models/concerns/shardable.rb4
-rw-r--r--app/models/concerns/timebox.rb26
-rw-r--r--app/models/concerns/update_project_statistics.rb5
-rw-r--r--app/models/container_expiration_policy.rb11
-rw-r--r--app/models/container_repository.rb8
-rw-r--r--app/models/data_list.rb10
-rw-r--r--app/models/deploy_token.rb14
-rw-r--r--app/models/deployment.rb34
-rw-r--r--app/models/deployment_merge_request.rb21
-rw-r--r--app/models/design_management/design.rb10
-rw-r--r--app/models/design_management/design_at_version.rb4
-rw-r--r--app/models/design_management/design_collection.rb1
-rw-r--r--app/models/diff_viewer/rich.rb2
-rw-r--r--app/models/environment.rb11
-rw-r--r--app/models/environment_status.rb8
-rw-r--r--app/models/event.rb14
-rw-r--r--app/models/global_label.rb32
-rw-r--r--app/models/group.rb120
-rw-r--r--app/models/group_import_state.rb3
-rw-r--r--app/models/incident_management/project_incident_management_setting.rb2
-rw-r--r--app/models/issuable_severity.rb7
-rw-r--r--app/models/issue.rb18
-rw-r--r--app/models/issue_assignee.rb1
-rw-r--r--app/models/issue_email_participant.rb13
-rw-r--r--app/models/iteration.rb16
-rw-r--r--app/models/member.rb13
-rw-r--r--app/models/merge_request.rb36
-rw-r--r--app/models/merge_request_context_commit.rb4
-rw-r--r--app/models/merge_request_diff.rb25
-rw-r--r--app/models/milestone.rb4
-rw-r--r--app/models/milestone_release.rb4
-rw-r--r--app/models/namespace.rb57
-rw-r--r--app/models/namespace_setting.rb19
-rw-r--r--app/models/note.rb2
-rw-r--r--app/models/notification_reason.rb2
-rw-r--r--app/models/notification_recipient.rb2
-rw-r--r--app/models/notification_setting.rb1
-rw-r--r--app/models/operations/feature_flags/strategy.rb33
-rw-r--r--app/models/packages/event.rb25
-rw-r--r--app/models/packages/package.rb14
-rw-r--r--app/models/pages_deployment.rb14
-rw-r--r--app/models/postgresql/replication_slot.rb4
-rw-r--r--app/models/preloaders/merge_request_diff_preloader.rb27
-rw-r--r--app/models/project.rb57
-rw-r--r--app/models/project_pages_metadatum.rb1
-rw-r--r--app/models/project_repository_storage_move.rb10
-rw-r--r--app/models/project_services/chat_message/deployment_message.rb10
-rw-r--r--app/models/project_services/chat_message/issue_message.rb10
-rw-r--r--app/models/project_services/confluence_service.rb2
-rw-r--r--app/models/project_services/drone_ci_service.rb4
-rw-r--r--app/models/project_services/packagist_service.rb2
-rw-r--r--app/models/project_statistics.rb31
-rw-r--r--app/models/project_tracing_setting.rb15
-rw-r--r--app/models/project_wiki.rb3
-rw-r--r--app/models/prometheus_alert.rb2
-rw-r--r--app/models/prometheus_metric.rb2
-rw-r--r--app/models/release.rb17
-rw-r--r--app/models/repository.rb24
-rw-r--r--app/models/resource_label_event.rb11
-rw-r--r--app/models/resource_state_event.rb25
-rw-r--r--app/models/resource_timebox_event.rb15
-rw-r--r--app/models/resource_weight_event.rb7
-rw-r--r--app/models/service.rb29
-rw-r--r--app/models/service_list.rb12
-rw-r--r--app/models/snippet.rb8
-rw-r--r--app/models/snippet_input_action_collection.rb6
-rw-r--r--app/models/snippet_repository.rb2
-rw-r--r--app/models/snippet_statistics.rb2
-rw-r--r--app/models/system_note_metadata.rb4
-rw-r--r--app/models/terraform/state.rb68
-rw-r--r--app/models/terraform/state_version.rb6
-rw-r--r--app/models/todo.rb2
-rw-r--r--app/models/u2f_registration.rb22
-rw-r--r--app/models/user.rb50
-rw-r--r--app/models/user_callout.rb2
-rw-r--r--app/models/user_interacted_project.rb2
-rw-r--r--app/models/user_preference.rb3
-rw-r--r--app/models/vulnerability.rb10
-rw-r--r--app/models/wiki.rb46
-rw-r--r--app/models/wiki_directory.rb39
-rw-r--r--app/models/wiki_page.rb23
-rw-r--r--app/policies/base_policy.rb5
-rw-r--r--app/policies/ci/bridge_policy.rb12
-rw-r--r--app/policies/ci/build_policy.rb2
-rw-r--r--app/policies/global_policy.rb1
-rw-r--r--app/policies/group_policy.rb37
-rw-r--r--app/policies/issue_policy.rb9
-rw-r--r--app/policies/project_policy.rb12
-rw-r--r--app/policies/releases/evidence_policy.rb1
-rw-r--r--app/policies/terraform/state_policy.rb9
-rw-r--r--app/policies/wiki_policy.rb6
-rw-r--r--app/presenters/alert_management/alert_presenter.rb33
-rw-r--r--app/presenters/clusterable_presenter.rb2
-rw-r--r--app/presenters/environment_presenter.rb13
-rw-r--r--app/presenters/event_presenter.rb22
-rw-r--r--app/presenters/instance_clusterable_presenter.rb2
-rw-r--r--app/presenters/issue_presenter.rb2
-rw-r--r--app/presenters/label_presenter.rb5
-rw-r--r--app/presenters/merge_request_presenter.rb2
-rw-r--r--app/presenters/packages/detail/package_presenter.rb6
-rw-r--r--app/presenters/packages/pypi/package_presenter.rb4
-rw-r--r--app/presenters/project_presenter.rb52
-rw-r--r--app/presenters/projects/prometheus/alert_presenter.rb179
-rw-r--r--app/presenters/release_presenter.rb2
-rw-r--r--app/presenters/sentry_error_presenter.rb2
-rw-r--r--app/presenters/snippet_blob_presenter.rb8
-rw-r--r--app/presenters/snippet_presenter.rb10
-rw-r--r--app/serializers/README.md4
-rw-r--r--app/serializers/build_details_entity.rb4
-rw-r--r--app/serializers/ci/trigger_entity.rb42
-rw-r--r--app/serializers/ci/trigger_serializer.rb7
-rw-r--r--app/serializers/cluster_entity.rb2
-rw-r--r--app/serializers/cluster_serializer.rb1
-rw-r--r--app/serializers/container_repository_entity.rb1
-rw-r--r--app/serializers/deployment_entity.rb1
-rw-r--r--app/serializers/diff_file_base_entity.rb14
-rw-r--r--app/serializers/diffs_entity.rb4
-rw-r--r--app/serializers/discussion_entity.rb5
-rw-r--r--app/serializers/feature_flag_entity.rb48
-rw-r--r--app/serializers/feature_flag_scope_entity.rb12
-rw-r--r--app/serializers/feature_flag_serializer.rb10
-rw-r--r--app/serializers/feature_flag_summary_entity.rb19
-rw-r--r--app/serializers/feature_flag_summary_serializer.rb5
-rw-r--r--app/serializers/feature_flags/scope_entity.rb8
-rw-r--r--app/serializers/feature_flags/strategy_entity.rb11
-rw-r--r--app/serializers/feature_flags/user_list_entity.rb10
-rw-r--r--app/serializers/feature_flags_client_entity.rb7
-rw-r--r--app/serializers/feature_flags_client_serializer.rb9
-rw-r--r--app/serializers/group_group_link_entity.rb24
-rw-r--r--app/serializers/import/bulk_import_entity.rb15
-rw-r--r--app/serializers/label_entity.rb2
-rw-r--r--app/serializers/label_serializer.rb2
-rw-r--r--app/serializers/merge_request_basic_entity.rb1
-rw-r--r--app/serializers/merge_request_poll_cached_widget_entity.rb12
-rw-r--r--app/serializers/merge_request_poll_widget_entity.rb16
-rw-r--r--app/serializers/merge_request_widget_entity.rb26
-rw-r--r--app/serializers/paginated_diff_entity.rb2
-rw-r--r--app/serializers/pipeline_entity.rb4
-rw-r--r--app/serializers/pipeline_serializer.rb10
-rw-r--r--app/serializers/test_case_entity.rb1
-rw-r--r--app/services/admin/propagate_integration_service.rb67
-rw-r--r--app/services/admin/propagate_service_template.rb6
-rw-r--r--app/services/alert_management/alerts/update_service.rb22
-rw-r--r--app/services/alert_management/process_prometheus_alert_service.rb2
-rw-r--r--app/services/audit_event_service.rb21
-rw-r--r--app/services/boards/create_service.rb18
-rw-r--r--app/services/boards/issues/list_service.rb5
-rw-r--r--app/services/boards/lists/destroy_service.rb8
-rw-r--r--app/services/bulk_create_integration_service.rb59
-rw-r--r--app/services/bulk_update_integration_service.rb32
-rw-r--r--app/services/ci/archive_trace_service.rb2
-rw-r--r--app/services/ci/build_report_result_service.rb29
-rw-r--r--app/services/ci/create_downstream_pipeline_service.rb15
-rw-r--r--app/services/ci/create_job_artifacts_service.rb9
-rw-r--r--app/services/ci/create_pipeline_service.rb5
-rw-r--r--app/services/ci/daily_build_group_report_result_service.rb2
-rw-r--r--app/services/ci/delete_objects_service.rb62
-rw-r--r--app/services/ci/destroy_expired_job_artifacts_service.rb7
-rw-r--r--app/services/ci/expire_pipeline_cache_service.rb13
-rw-r--r--app/services/ci/list_config_variables_service.rb13
-rw-r--r--app/services/ci/pipelines/create_artifact_service.rb1
-rw-r--r--app/services/ci/play_bridge_service.rb14
-rw-r--r--app/services/ci/play_build_service.rb4
-rw-r--r--app/services/ci/play_manual_stage_service.rb8
-rw-r--r--app/services/ci/process_pipeline_service.rb4
-rw-r--r--app/services/ci/retry_build_service.rb2
-rw-r--r--app/services/ci/update_build_queue_service.rb4
-rw-r--r--app/services/ci/update_build_state_service.rb142
-rw-r--r--app/services/clusters/kubernetes/create_or_update_service_account_service.rb4
-rw-r--r--app/services/concerns/admin/propagate_service.rb51
-rw-r--r--app/services/deployments/after_create_service.rb67
-rw-r--r--app/services/deployments/update_environment_service.rb67
-rw-r--r--app/services/design_management/copy_design_collection.rb6
-rw-r--r--app/services/design_management/copy_design_collection/copy_service.rb309
-rw-r--r--app/services/design_management/copy_design_collection/queue_service.rb42
-rw-r--r--app/services/design_management/delete_designs_service.rb1
-rw-r--r--app/services/design_management/design_service.rb1
-rw-r--r--app/services/design_management/generate_image_versions_service.rb3
-rw-r--r--app/services/design_management/runs_design_actions.rb11
-rw-r--r--app/services/design_management/save_designs_service.rb21
-rw-r--r--app/services/feature_flags/base_service.rb55
-rw-r--r--app/services/feature_flags/create_service.rb52
-rw-r--r--app/services/feature_flags/destroy_service.rb33
-rw-r--r--app/services/feature_flags/disable_service.rb46
-rw-r--r--app/services/feature_flags/enable_service.rb93
-rw-r--r--app/services/feature_flags/update_service.rb87
-rw-r--r--app/services/git/branch_hooks_service.rb8
-rw-r--r--app/services/git/wiki_push_service.rb4
-rw-r--r--app/services/groups/create_service.rb19
-rw-r--r--app/services/groups/import_export/import_service.rb2
-rw-r--r--app/services/groups/transfer_service.rb35
-rw-r--r--app/services/groups/update_service.rb58
-rw-r--r--app/services/groups/update_shared_runners_service.rb32
-rw-r--r--app/services/incident_management/incidents/create_service.rb6
-rw-r--r--app/services/incident_management/incidents/update_severity_service.rb38
-rw-r--r--app/services/incident_management/pager_duty/process_webhook_service.rb2
-rw-r--r--app/services/issuable/clone/attributes_rewriter.rb13
-rw-r--r--app/services/issuable_base_service.rb3
-rw-r--r--app/services/issues/base_service.rb12
-rw-r--r--app/services/issues/build_service.rb20
-rw-r--r--app/services/issues/move_service.rb23
-rw-r--r--app/services/issues/reopen_service.rb8
-rw-r--r--app/services/jira/requests/base.rb7
-rw-r--r--app/services/lfs/push_service.rb16
-rw-r--r--app/services/members/create_service.rb2
-rw-r--r--app/services/members/invitation_reminder_email_service.rb54
-rw-r--r--app/services/merge_requests/base_service.rb9
-rw-r--r--app/services/merge_requests/cleanup_refs_service.rb2
-rw-r--r--app/services/merge_requests/export_csv_service.rb55
-rw-r--r--app/services/merge_requests/ff_merge_service.rb2
-rw-r--r--app/services/merge_requests/merge_service.rb2
-rw-r--r--app/services/merge_requests/merge_to_ref_service.rb9
-rw-r--r--app/services/merge_requests/mergeability_check_service.rb17
-rw-r--r--app/services/merge_requests/refresh_service.rb17
-rw-r--r--app/services/merge_requests/update_service.rb2
-rw-r--r--app/services/metrics/dashboard/custom_dashboard_service.rb6
-rw-r--r--app/services/metrics/dashboard/dynamic_embed_service.rb2
-rw-r--r--app/services/namespace_settings/update_service.rb25
-rw-r--r--app/services/notes/create_service.rb2
-rw-r--r--app/services/notification_recipients/build_service.rb8
-rw-r--r--app/services/notification_recipients/builder/default.rb3
-rw-r--r--app/services/notification_service.rb31
-rw-r--r--app/services/packages/composer/composer_json_service.rb6
-rw-r--r--app/services/packages/create_event_service.rb37
-rw-r--r--app/services/packages/create_package_service.rb1
-rw-r--r--app/services/packages/generic/create_package_file_service.rb38
-rw-r--r--app/services/packages/generic/find_or_create_package_service.rb15
-rw-r--r--app/services/personal_access_tokens/revoke_service.rb7
-rw-r--r--app/services/pod_logs/base_service.rb2
-rw-r--r--app/services/pod_logs/elasticsearch_service.rb1
-rw-r--r--app/services/pod_logs/kubernetes_service.rb1
-rw-r--r--app/services/projects/alerting/notify_service.rb75
-rw-r--r--app/services/projects/container_repository/cleanup_tags_service.rb5
-rw-r--r--app/services/projects/container_repository/delete_tags_service.rb4
-rw-r--r--app/services/projects/create_from_template_service.rb18
-rw-r--r--app/services/projects/create_service.rb22
-rw-r--r--app/services/projects/gitlab_projects_import_service.rb1
-rw-r--r--app/services/projects/operations/update_service.rb10
-rw-r--r--app/services/projects/overwrite_project_service.rb12
-rw-r--r--app/services/projects/prometheus/alerts/notify_service.rb14
-rw-r--r--app/services/projects/transfer_service.rb4
-rw-r--r--app/services/projects/update_pages_service.rb16
-rw-r--r--app/services/projects/update_remote_mirror_service.rb11
-rw-r--r--app/services/quick_actions/target_service.rb4
-rw-r--r--app/services/releases/base_service.rb89
-rw-r--r--app/services/releases/concerns.rb77
-rw-r--r--app/services/releases/create_evidence_service.rb2
-rw-r--r--app/services/releases/create_service.rb4
-rw-r--r--app/services/releases/destroy_service.rb4
-rw-r--r--app/services/releases/update_service.rb20
-rw-r--r--app/services/repository_archive_clean_up_service.rb24
-rw-r--r--app/services/resource_access_tokens/create_service.rb18
-rw-r--r--app/services/resource_access_tokens/revoke_service.rb27
-rw-r--r--app/services/search/global_service.rb10
-rw-r--r--app/services/search/group_service.rb3
-rw-r--r--app/services/search/project_service.rb19
-rw-r--r--app/services/search_service.rb4
-rw-r--r--app/services/snippets/base_service.rb18
-rw-r--r--app/services/snippets/create_service.rb9
-rw-r--r--app/services/snippets/repository_validation_service.rb2
-rw-r--r--app/services/snippets/update_service.rb39
-rw-r--r--app/services/spam/spam_action_service.rb2
-rw-r--r--app/services/static_site_editor/config_service.rb66
-rw-r--r--app/services/system_note_service.rb8
-rw-r--r--app/services/system_notes/incident_service.rb29
-rw-r--r--app/services/system_notes/issuables_service.rb82
-rw-r--r--app/services/system_notes/time_tracking_service.rb12
-rw-r--r--app/services/todos/destroy/entity_leave_service.rb74
-rw-r--r--app/services/users/approve_service.rb37
-rw-r--r--app/services/users/block_service.rb2
-rw-r--r--app/services/users/build_service.rb3
-rw-r--r--app/services/users/destroy_service.rb2
-rw-r--r--app/services/users/validate_otp_service.rb25
-rw-r--r--app/services/web_hooks/destroy_service.rb78
-rw-r--r--app/services/webauthn/authenticate_service.rb12
-rw-r--r--app/uploaders/deleted_object_uploader.rb11
-rw-r--r--app/uploaders/pages/deployment_uploader.rb51
-rw-r--r--app/uploaders/terraform/versioned_state_uploader.rb14
-rw-r--r--app/validators/addressable_url_validator.rb2
-rw-r--r--app/validators/ip_address_validator.rb39
-rw-r--r--app/validators/json_schemas/security_ci_configuration_schemas/sast_ui_schema.json6
-rw-r--r--app/views/admin/abuse_reports/_abuse_report.html.haml13
-rw-r--r--app/views/admin/abuse_reports/index.html.haml2
-rw-r--r--app/views/admin/application_settings/_abuse.html.haml6
-rw-r--r--app/views/admin/application_settings/_account_and_limit.html.haml3
-rw-r--r--app/views/admin/application_settings/_ci_cd.html.haml2
-rw-r--r--app/views/admin/application_settings/_diff_limits.html.haml3
-rw-r--r--app/views/admin/application_settings/_eks.html.haml2
-rw-r--r--app/views/admin/application_settings/_email.html.haml2
-rw-r--r--app/views/admin/application_settings/_external_authorization_service_form.html.haml3
-rw-r--r--app/views/admin/application_settings/_gitaly.html.haml2
-rw-r--r--app/views/admin/application_settings/_gitpod.html.haml5
-rw-r--r--app/views/admin/application_settings/_grafana.html.haml2
-rw-r--r--app/views/admin/application_settings/_help_page.html.haml7
-rw-r--r--app/views/admin/application_settings/_import_export_limits.html.haml2
-rw-r--r--app/views/admin/application_settings/_initial_branch_name.html.haml3
-rw-r--r--app/views/admin/application_settings/_ip_limits.html.haml2
-rw-r--r--app/views/admin/application_settings/_issue_limits.html.haml2
-rw-r--r--app/views/admin/application_settings/_localization.html.haml2
-rw-r--r--app/views/admin/application_settings/_outbound.html.haml2
-rw-r--r--app/views/admin/application_settings/_pages.html.haml2
-rw-r--r--app/views/admin/application_settings/_performance.html.haml2
-rw-r--r--app/views/admin/application_settings/_performance_bar.html.haml2
-rw-r--r--app/views/admin/application_settings/_plantuml.html.haml2
-rw-r--r--app/views/admin/application_settings/_prometheus.html.haml2
-rw-r--r--app/views/admin/application_settings/_protected_paths.html.haml2
-rw-r--r--app/views/admin/application_settings/_realtime.html.haml2
-rw-r--r--app/views/admin/application_settings/_registry.html.haml2
-rw-r--r--app/views/admin/application_settings/_repository_check.html.haml6
-rw-r--r--app/views/admin/application_settings/_repository_mirrors_form.html.haml3
-rw-r--r--app/views/admin/application_settings/_repository_static_objects.html.haml3
-rw-r--r--app/views/admin/application_settings/_repository_storage.html.haml3
-rw-r--r--app/views/admin/application_settings/_signin.html.haml3
-rw-r--r--app/views/admin/application_settings/_signup.html.haml11
-rw-r--r--app/views/admin/application_settings/_snowplow.html.haml2
-rw-r--r--app/views/admin/application_settings/_sourcegraph.html.haml2
-rw-r--r--app/views/admin/application_settings/_spam.html.haml2
-rw-r--r--app/views/admin/application_settings/_terminal.html.haml3
-rw-r--r--app/views/admin/application_settings/_terms.html.haml3
-rw-r--r--app/views/admin/application_settings/_third_party_offers.html.haml2
-rw-r--r--app/views/admin/application_settings/_usage.html.haml4
-rw-r--r--app/views/admin/application_settings/_visibility_and_access.html.haml3
-rw-r--r--app/views/admin/application_settings/general.html.haml3
-rw-r--r--app/views/admin/applications/_delete_form.html.haml2
-rw-r--r--app/views/admin/applications/_form.html.haml4
-rw-r--r--app/views/admin/applications/index.html.haml4
-rw-r--r--app/views/admin/applications/show.html.haml6
-rw-r--r--app/views/admin/broadcast_messages/_form.html.haml6
-rw-r--r--app/views/admin/dashboard/_billable_users_text.html.haml1
-rw-r--r--app/views/admin/dashboard/index.html.haml10
-rw-r--r--app/views/admin/dashboard/stats.html.haml2
-rw-r--r--app/views/admin/deploy_keys/edit.html.haml4
-rw-r--r--app/views/admin/deploy_keys/index.html.haml6
-rw-r--r--app/views/admin/deploy_keys/new.html.haml4
-rw-r--r--app/views/admin/dev_ops_report/show.html.haml5
-rw-r--r--app/views/admin/groups/_form.html.haml10
-rw-r--r--app/views/admin/groups/_group.html.haml2
-rw-r--r--app/views/admin/groups/index.html.haml4
-rw-r--r--app/views/admin/groups/show.html.haml4
-rw-r--r--app/views/admin/health_check/show.html.haml2
-rw-r--r--app/views/admin/hook_logs/show.html.haml2
-rw-r--r--app/views/admin/hooks/edit.html.haml4
-rw-r--r--app/views/admin/hooks/index.html.haml2
-rw-r--r--app/views/admin/identities/_form.html.haml2
-rw-r--r--app/views/admin/identities/_identity.html.haml4
-rw-r--r--app/views/admin/identities/index.html.haml2
-rw-r--r--app/views/admin/jobs/index.html.haml2
-rw-r--r--app/views/admin/labels/_form.html.haml4
-rw-r--r--app/views/admin/labels/_label.html.haml4
-rw-r--r--app/views/admin/labels/index.html.haml2
-rw-r--r--app/views/admin/projects/index.html.haml4
-rw-r--r--app/views/admin/projects/show.html.haml9
-rw-r--r--app/views/admin/runners/_runner.html.haml8
-rw-r--r--app/views/admin/runners/index.html.haml10
-rw-r--r--app/views/admin/runners/show.html.haml4
-rw-r--r--app/views/admin/serverless/domains/_form.html.haml12
-rw-r--r--app/views/admin/sessions/_new_base.html.haml2
-rw-r--r--app/views/admin/sessions/_two_factor_otp.html.haml2
-rw-r--r--app/views/admin/spam_logs/_spam_log.html.haml8
-rw-r--r--app/views/admin/users/_approve_user.html.haml7
-rw-r--r--app/views/admin/users/_block_user.html.haml11
-rw-r--r--app/views/admin/users/_form.html.haml2
-rw-r--r--app/views/admin/users/_head.html.haml17
-rw-r--r--app/views/admin/users/_modals.html.haml2
-rw-r--r--app/views/admin/users/_user.html.haml24
-rw-r--r--app/views/admin/users/_user_approve_effects.html.haml11
-rw-r--r--app/views/admin/users/_user_detail.html.haml2
-rw-r--r--app/views/admin/users/index.html.haml10
-rw-r--r--app/views/admin/users/show.html.haml84
-rw-r--r--app/views/ci/status/_dropdown_graph_badge.html.haml4
-rw-r--r--app/views/ci/variables/_index.html.haml2
-rw-r--r--app/views/clusters/clusters/_advanced_settings.html.haml21
-rw-r--r--app/views/clusters/clusters/_buttons.html.haml6
-rw-r--r--app/views/clusters/clusters/_cluster.html.haml19
-rw-r--r--app/views/clusters/clusters/_cluster_list.html.haml12
-rw-r--r--app/views/clusters/clusters/_empty_state.html.haml8
-rw-r--r--app/views/clusters/clusters/_gcp_signup_offer_banner.html.haml18
-rw-r--r--app/views/clusters/clusters/_provider_details_form.html.haml12
-rw-r--r--app/views/clusters/clusters/aws/_new.html.haml1
-rw-r--r--app/views/clusters/clusters/gcp/_form.html.haml8
-rw-r--r--app/views/clusters/clusters/index.html.haml46
-rw-r--r--app/views/clusters/clusters/user/_form.html.haml8
-rw-r--r--app/views/dashboard/merge_requests.html.haml2
-rw-r--r--app/views/dashboard/milestones/index.html.haml1
-rw-r--r--app/views/dashboard/todos/_todo.html.haml10
-rw-r--r--app/views/dashboard/todos/index.html.haml4
-rw-r--r--app/views/devise/mailer/confirmation_instructions.text.erb2
-rw-r--r--app/views/devise/shared/_experimental_separate_sign_up_flow_box.html.haml15
-rw-r--r--app/views/devise/shared/_signup_box.html.haml20
-rw-r--r--app/views/devise/shared/_terms_of_service_notice.html.haml5
-rw-r--r--app/views/discussions/_diff_with_notes.html.haml2
-rw-r--r--app/views/discussions/_jump_to_next.html.haml9
-rw-r--r--app/views/discussions/_new_issue_for_all_discussions.html.haml8
-rw-r--r--app/views/discussions/_new_issue_for_discussion.html.haml10
-rw-r--r--app/views/discussions/_notes.html.haml22
-rw-r--r--app/views/doorkeeper/applications/_delete_form.html.haml2
-rw-r--r--app/views/doorkeeper/authorized_applications/_delete_form.html.haml2
-rw-r--r--app/views/events/event/_common.html.haml2
-rw-r--r--app/views/groups/_invite_members_modal.html.haml6
-rw-r--r--app/views/groups/_invite_members_side_nav_link.html.haml3
-rw-r--r--app/views/groups/group_members/index.html.haml9
-rw-r--r--app/views/groups/issues.html.haml6
-rw-r--r--app/views/groups/labels/destroy.js.haml2
-rw-r--r--app/views/groups/labels/index.html.haml4
-rw-r--r--app/views/groups/milestones/index.html.haml1
-rw-r--r--app/views/groups/milestones/show.html.haml1
-rw-r--r--app/views/groups/projects.html.haml2
-rw-r--r--app/views/groups/registry/repositories/index.html.haml2
-rw-r--r--app/views/groups/runners/_index.html.haml2
-rw-r--r--app/views/groups/runners/_shared_runners.html.haml3
-rw-r--r--app/views/groups/settings/_advanced.html.haml8
-rw-r--r--app/views/groups/settings/_export.html.haml5
-rw-r--r--app/views/groups/settings/_general.html.haml3
-rw-r--r--app/views/groups/settings/_permanent_deletion.html.haml3
-rw-r--r--app/views/groups/settings/_permissions.html.haml5
-rw-r--r--app/views/groups/settings/_two_factor_auth.html.haml9
-rw-r--r--app/views/groups/show.html.haml2
-rw-r--r--app/views/ide/_show.html.haml3
-rw-r--r--app/views/import/bitbucket/status.html.haml5
-rw-r--r--app/views/import/bitbucket_server/new.html.haml6
-rw-r--r--app/views/import/bitbucket_server/status.html.haml5
-rw-r--r--app/views/import/bulk_imports/status.html.haml1
-rw-r--r--app/views/import/github/new.html.haml4
-rw-r--r--app/views/import/github/status.html.haml6
-rw-r--r--app/views/import/google_code/new.html.haml5
-rw-r--r--app/views/import/google_code/new_user_map.html.haml5
-rw-r--r--app/views/import/google_code/status.html.haml5
-rw-r--r--app/views/import/shared/_errors.html.haml8
-rw-r--r--app/views/invites/decline.html.haml8
-rw-r--r--app/views/invites/show.html.haml4
-rw-r--r--app/views/jira_connect/subscriptions/index.html.haml85
-rw-r--r--app/views/jira_connect/users/show.html.haml12
-rw-r--r--app/views/layouts/_head.html.haml25
-rw-r--r--app/views/layouts/_loading_hints.html.haml1
-rw-r--r--app/views/layouts/_page.html.haml1
-rw-r--r--app/views/layouts/_startup_css.haml2
-rw-r--r--app/views/layouts/_startup_css_activation.haml1
-rw-r--r--app/views/layouts/_startup_js.html.haml22
-rw-r--r--app/views/layouts/devise.html.haml5
-rw-r--r--app/views/layouts/devise_experimental_onboarding_issues.html.haml1
-rw-r--r--app/views/layouts/devise_experimental_separate_sign_up_flow.html.haml1
-rw-r--r--app/views/layouts/group.html.haml4
-rw-r--r--app/views/layouts/header/_current_user_dropdown.html.haml2
-rw-r--r--app/views/layouts/header/_default.html.haml10
-rw-r--r--app/views/layouts/header/_help_dropdown.html.haml2
-rw-r--r--app/views/layouts/header/_new_dropdown.haml2
-rw-r--r--app/views/layouts/jira_connect.html.haml1
-rw-r--r--app/views/layouts/nav/_classification_level_banner.html.haml2
-rw-r--r--app/views/layouts/nav/_dashboard.html.haml10
-rw-r--r--app/views/layouts/nav/sidebar/_admin.html.haml9
-rw-r--r--app/views/layouts/nav/sidebar/_group.html.haml2
-rw-r--r--app/views/layouts/nav/sidebar/_project.html.haml59
-rw-r--r--app/views/layouts/nav/sidebar/_tracing_link.html.haml7
-rw-r--r--app/views/layouts/project.html.haml4
-rw-r--r--app/views/notify/_failed_builds.html.haml2
-rw-r--r--app/views/notify/_issuable_csv_export.html.haml6
-rw-r--r--app/views/notify/autodevops_disabled_email.html.haml2
-rw-r--r--app/views/notify/autodevops_disabled_email.text.erb2
-rw-r--r--app/views/notify/changed_reviewer_of_merge_request_email.html.haml2
-rw-r--r--app/views/notify/changed_reviewer_of_merge_request_email.text.erb1
-rw-r--r--app/views/notify/issue_status_changed_email.text.erb1
-rw-r--r--app/views/notify/issues_csv_email.html.haml7
-rw-r--r--app/views/notify/member_invited_reminder_email.html.haml9
-rw-r--r--app/views/notify/member_invited_reminder_email.text.erb6
-rw-r--r--app/views/notify/merge_requests_csv_email.html.haml1
-rw-r--r--app/views/notify/merge_requests_csv_email.text.erb5
-rw-r--r--app/views/notify/pipeline_failed_email.html.haml2
-rw-r--r--app/views/notify/pipeline_failed_email.text.erb2
-rw-r--r--app/views/notify/prometheus_alert_fired_email.html.haml7
-rw-r--r--app/views/notify/prometheus_alert_fired_email.text.erb6
-rw-r--r--app/views/profiles/accounts/show.html.haml10
-rw-r--r--app/views/profiles/active_sessions/_active_session.html.haml2
-rw-r--r--app/views/profiles/chat_names/_chat_name.html.haml2
-rw-r--r--app/views/profiles/chat_names/new.html.haml4
-rw-r--r--app/views/profiles/emails/index.html.haml6
-rw-r--r--app/views/profiles/gpg_keys/_form.html.haml2
-rw-r--r--app/views/profiles/gpg_keys/_key.html.haml4
-rw-r--r--app/views/profiles/keys/_form.html.haml8
-rw-r--r--app/views/profiles/keys/_key.html.haml11
-rw-r--r--app/views/profiles/keys/_key_details.html.haml2
-rw-r--r--app/views/profiles/notifications/show.html.haml2
-rw-r--r--app/views/profiles/passwords/edit.html.haml2
-rw-r--r--app/views/profiles/passwords/new.html.haml2
-rw-r--r--app/views/profiles/preferences/_gitpod.html.haml4
-rw-r--r--app/views/profiles/preferences/show.html.haml4
-rw-r--r--app/views/profiles/show.html.haml14
-rw-r--r--app/views/profiles/two_factor_auths/_codes.html.haml4
-rw-r--r--app/views/profiles/two_factor_auths/show.html.haml19
-rw-r--r--app/views/projects/_export.html.haml5
-rw-r--r--app/views/projects/_files.html.haml2
-rw-r--r--app/views/projects/_home_panel.html.haml12
-rw-r--r--app/views/projects/_import_project_pane.html.haml17
-rw-r--r--app/views/projects/_project_templates.html.haml18
-rw-r--r--app/views/projects/_stat_anchor_list.html.haml3
-rw-r--r--app/views/projects/_visibility_modal.html.haml2
-rw-r--r--app/views/projects/artifacts/_artifact.html.haml8
-rw-r--r--app/views/projects/blob/_content.html.haml4
-rw-r--r--app/views/projects/blob/_editor.html.haml5
-rw-r--r--app/views/projects/blob/_header.html.haml7
-rw-r--r--app/views/projects/blob/_new_dir.html.haml4
-rw-r--r--app/views/projects/blob/_remove.html.haml4
-rw-r--r--app/views/projects/blob/_upload.html.haml6
-rw-r--r--app/views/projects/blob/_viewer_switcher.html.haml4
-rw-r--r--app/views/projects/blob/edit.html.haml3
-rw-r--r--app/views/projects/blob/new.html.haml3
-rw-r--r--app/views/projects/blob/viewers/_markup.html.haml3
-rw-r--r--app/views/projects/branches/_branch.html.haml8
-rw-r--r--app/views/projects/branches/index.html.haml2
-rw-r--r--app/views/projects/buttons/_fork.html.haml4
-rw-r--r--app/views/projects/buttons/_remove_tag.html.haml6
-rw-r--r--app/views/projects/buttons/_star.html.haml6
-rw-r--r--app/views/projects/ci/builds/_build.html.haml22
-rw-r--r--app/views/projects/ci/lints/show.html.haml14
-rw-r--r--app/views/projects/cleanup/_show.html.haml3
-rw-r--r--app/views/projects/commit/_commit_box.html.haml12
-rw-r--r--app/views/projects/commit/pipelines.html.haml1
-rw-r--r--app/views/projects/commit/show.html.haml1
-rw-r--r--app/views/projects/commits/_commits.html.haml3
-rw-r--r--app/views/projects/commits/show.html.haml6
-rw-r--r--app/views/projects/compare/_form.html.haml8
-rw-r--r--app/views/projects/confluences/show.html.haml1
-rw-r--r--app/views/projects/cycle_analytics/show.html.haml1
-rw-r--r--app/views/projects/default_branch/_show.html.haml3
-rw-r--r--app/views/projects/deployments/_actions.haml2
-rw-r--r--app/views/projects/deployments/_commit.html.haml2
-rw-r--r--app/views/projects/deployments/_confirm_rollback_modal.html.haml4
-rw-r--r--app/views/projects/deployments/_rollback.haml2
-rw-r--r--app/views/projects/diffs/_diffs.html.haml2
-rw-r--r--app/views/projects/diffs/_file_header.html.haml2
-rw-r--r--app/views/projects/diffs/_line.html.haml3
-rw-r--r--app/views/projects/diffs/_parallel_view.html.haml6
-rw-r--r--app/views/projects/diffs/_stats.html.haml4
-rw-r--r--app/views/projects/diffs/_text_file.html.haml2
-rw-r--r--app/views/projects/diffs/_warning.html.haml23
-rw-r--r--app/views/projects/edit.html.haml23
-rw-r--r--app/views/projects/empty.html.haml10
-rw-r--r--app/views/projects/environments/edit.html.haml1
-rw-r--r--app/views/projects/environments/folder.html.haml1
-rw-r--r--app/views/projects/environments/index.html.haml1
-rw-r--r--app/views/projects/environments/new.html.haml1
-rw-r--r--app/views/projects/environments/show.html.haml7
-rw-r--r--app/views/projects/environments/terminal.html.haml4
-rw-r--r--app/views/projects/error_tracking/details.html.haml1
-rw-r--r--app/views/projects/error_tracking/index.html.haml1
-rw-r--r--app/views/projects/feature_flags/_errors.html.haml4
-rw-r--r--app/views/projects/feature_flags/edit.html.haml4
-rw-r--r--app/views/projects/feature_flags/index.html.haml2
-rw-r--r--app/views/projects/feature_flags/new.html.haml2
-rw-r--r--app/views/projects/forks/_fork_button.html.haml4
-rw-r--r--app/views/projects/forks/index.html.haml4
-rw-r--r--app/views/projects/generic_commit_statuses/_generic_commit_status.html.haml2
-rw-r--r--app/views/projects/group_links/update.js.haml4
-rw-r--r--app/views/projects/hook_logs/show.html.haml2
-rw-r--r--app/views/projects/hooks/edit.html.haml4
-rw-r--r--app/views/projects/hooks/index.html.haml3
-rw-r--r--app/views/projects/incidents/_new_branch.html.haml1
-rw-r--r--app/views/projects/incidents/index.html.haml2
-rw-r--r--app/views/projects/incidents/show.html.haml1
-rw-r--r--app/views/projects/issues/_discussion.html.haml1
-rw-r--r--app/views/projects/issues/_issue.html.haml4
-rw-r--r--app/views/projects/issues/_issues.html.haml8
-rw-r--r--app/views/projects/issues/_new_branch.html.haml2
-rw-r--r--app/views/projects/issues/export_csv/_button.html.haml2
-rw-r--r--app/views/projects/issues/export_csv/_modal.html.haml13
-rw-r--r--app/views/projects/issues/index.html.haml1
-rw-r--r--app/views/projects/issues/service_desk.html.haml2
-rw-r--r--app/views/projects/issues/show.html.haml14
-rw-r--r--app/views/projects/jobs/show.html.haml4
-rw-r--r--app/views/projects/jobs/terminal.html.haml5
-rw-r--r--app/views/projects/labels/index.html.haml4
-rw-r--r--app/views/projects/merge_requests/_description.html.haml3
-rw-r--r--app/views/projects/merge_requests/_discussion.html.haml11
-rw-r--r--app/views/projects/merge_requests/_merge_request.html.haml5
-rw-r--r--app/views/projects/merge_requests/_merge_requests.html.haml2
-rw-r--r--app/views/projects/merge_requests/_mr_title.html.haml9
-rw-r--r--app/views/projects/merge_requests/conflicts/show.html.haml1
-rw-r--r--app/views/projects/merge_requests/creations/new.html.haml1
-rw-r--r--app/views/projects/merge_requests/diffs/_commit_widget.html.haml11
-rw-r--r--app/views/projects/merge_requests/diffs/_different_base.html.haml11
-rw-r--r--app/views/projects/merge_requests/diffs/_diffs.html.haml21
-rw-r--r--app/views/projects/merge_requests/diffs/_not_all_comments_displayed.html.haml17
-rw-r--r--app/views/projects/merge_requests/diffs/_version_controls.html.haml73
-rw-r--r--app/views/projects/merge_requests/invalid.html.haml15
-rw-r--r--app/views/projects/merge_requests/show.html.haml8
-rw-r--r--app/views/projects/milestones/index.html.haml3
-rw-r--r--app/views/projects/milestones/show.html.haml15
-rw-r--r--app/views/projects/milestones/update.js.haml2
-rw-r--r--app/views/projects/mirrors/_mirror_repos.html.haml6
-rw-r--r--app/views/projects/mirrors/_regenerate_public_ssh_key_confirm_modal.html.haml4
-rw-r--r--app/views/projects/mirrors/_ssh_host_keys.html.haml4
-rw-r--r--app/views/projects/network/show.html.haml8
-rw-r--r--app/views/projects/no_repo.html.haml2
-rw-r--r--app/views/projects/notes/_actions.html.haml2
-rw-r--r--app/views/projects/packages/packages/show.html.haml3
-rw-r--r--app/views/projects/pages/_destroy.haml2
-rw-r--r--app/views/projects/pages/_list.html.haml4
-rw-r--r--app/views/projects/pages/_pages_settings.html.haml7
-rw-r--r--app/views/projects/pages/show.html.haml2
-rw-r--r--app/views/projects/pages_domains/_certificate.html.haml2
-rw-r--r--app/views/projects/pages_domains/_form.html.haml3
-rw-r--r--app/views/projects/pipeline_schedules/_pipeline_schedule.html.haml2
-rw-r--r--app/views/projects/pipeline_schedules/index.html.haml2
-rw-r--r--app/views/projects/pipelines/_info.html.haml6
-rw-r--r--app/views/projects/pipelines/_with_tabs.html.haml2
-rw-r--r--app/views/projects/pipelines/index.html.haml1
-rw-r--r--app/views/projects/pipelines/new.html.haml12
-rw-r--r--app/views/projects/pipelines/show.html.haml5
-rw-r--r--app/views/projects/project_members/_team.html.haml2
-rw-r--r--app/views/projects/project_members/import.html.haml4
-rw-r--r--app/views/projects/project_templates/_built_in_templates.html.haml17
-rw-r--r--app/views/projects/project_templates/_template.html.haml16
-rw-r--r--app/views/projects/protected_branches/_create_protected_branch.html.haml4
-rw-r--r--app/views/projects/protected_tags/shared/_create_protected_tag.html.haml2
-rw-r--r--app/views/projects/registry/repositories/index.html.haml3
-rw-r--r--app/views/projects/registry/settings/_index.haml3
-rw-r--r--app/views/projects/releases/show.html.haml3
-rw-r--r--app/views/projects/runners/_shared_runners.html.haml25
-rw-r--r--app/views/projects/services/mattermost_slash_commands/_installation_info.html.haml2
-rw-r--r--app/views/projects/services/prometheus/_configuration_banner.html.haml4
-rw-r--r--app/views/projects/services/prometheus/_custom_metrics.html.haml2
-rw-r--r--app/views/projects/settings/_archive.html.haml7
-rw-r--r--app/views/projects/settings/_general.html.haml3
-rw-r--r--app/views/projects/settings/ci_cd/_badge.html.haml6
-rw-r--r--app/views/projects/settings/ci_cd/_form.html.haml13
-rw-r--r--app/views/projects/settings/operations/_alert_management.html.haml2
-rw-r--r--app/views/projects/settings/operations/_tracing.html.haml33
-rw-r--r--app/views/projects/settings/operations/show.html.haml2
-rw-r--r--app/views/projects/snippets/_actions.html.haml36
-rw-r--r--app/views/projects/snippets/show.html.haml8
-rw-r--r--app/views/projects/starrers/index.html.haml2
-rw-r--r--app/views/projects/tags/_tag.html.haml8
-rw-r--r--app/views/projects/tags/destroy.js.haml4
-rw-r--r--app/views/projects/tags/show.html.haml3
-rw-r--r--app/views/projects/tracings/_tracing_button.html.haml2
-rw-r--r--app/views/projects/tracings/show.html.haml33
-rw-r--r--app/views/projects/tree/_tree_header.html.haml12
-rw-r--r--app/views/projects/tree/show.html.haml2
-rw-r--r--app/views/projects/triggers/_index.html.haml35
-rw-r--r--app/views/projects/triggers/_trigger.html.haml4
-rw-r--r--app/views/projects/wikis/git_access.html.haml1
-rw-r--r--app/views/registrations/welcome.html.haml2
-rw-r--r--app/views/search/_category.html.haml1
-rw-r--r--app/views/search/_filter.html.haml24
-rw-r--r--app/views/search/_form.html.haml4
-rw-r--r--app/views/search/_results.html.haml10
-rw-r--r--app/views/search/results/_blob.html.haml2
-rw-r--r--app/views/search/results/_blob_data.html.haml2
-rw-r--r--app/views/search/results/_empty.html.haml2
-rw-r--r--app/views/search/results/_filters.html.haml7
-rw-r--r--app/views/search/results/_issue.html.haml5
-rw-r--r--app/views/search/show.html.haml7
-rw-r--r--app/views/shared/_auto_devops_implicitly_enabled_banner.html.haml18
-rw-r--r--app/views/shared/_confirm_fork_modal.html.haml2
-rw-r--r--app/views/shared/_confirm_modal.html.haml2
-rw-r--r--app/views/shared/_delete_label_modal.html.haml2
-rw-r--r--app/views/shared/_issuable_meta_data.html.haml14
-rw-r--r--app/views/shared/_label.html.haml3
-rw-r--r--app/views/shared/_label_full_path.html.haml4
-rw-r--r--app/views/shared/_label_row.html.haml31
-rw-r--r--app/views/shared/_new_project_item_select.html.haml8
-rw-r--r--app/views/shared/_user_dropdown_instance_review.html.haml6
-rw-r--r--app/views/shared/_web_ide_button.html.haml10
-rw-r--r--app/views/shared/boards/_show.html.haml3
-rw-r--r--app/views/shared/deploy_keys/_project_group_form.html.haml2
-rw-r--r--app/views/shared/deploy_tokens/_form.html.haml2
-rw-r--r--app/views/shared/icons/_next_discussion.svg1
-rw-r--r--app/views/shared/issuable/_approved_by_dropdown.html.haml16
-rw-r--r--app/views/shared/issuable/_assignees.html.haml5
-rw-r--r--app/views/shared/issuable/_close_reopen_button.html.haml13
-rw-r--r--app/views/shared/issuable/_close_reopen_draft_report_toggle.html.haml37
-rw-r--r--app/views/shared/issuable/_close_reopen_report_toggle.html.haml2
-rw-r--r--app/views/shared/issuable/_reviewers.html.haml11
-rw-r--r--app/views/shared/issuable/_search_bar.html.haml11
-rw-r--r--app/views/shared/issuable/_sidebar.html.haml349
-rw-r--r--app/views/shared/issuable/_sidebar_assignees.html.haml19
-rw-r--r--app/views/shared/issuable/_sidebar_reviewers.html.haml55
-rw-r--r--app/views/shared/issuable/form/_type_selector.html.haml6
-rw-r--r--app/views/shared/labels/_form.html.haml6
-rw-r--r--app/views/shared/labels/_nav.html.haml8
-rw-r--r--app/views/shared/members/_access_request_links.html.haml6
-rw-r--r--app/views/shared/members/_group.html.haml13
-rw-r--r--app/views/shared/members/_member.html.haml11
-rw-r--r--app/views/shared/members/update.js.haml6
-rw-r--r--app/views/shared/milestones/_delete_button.html.haml6
-rw-r--r--app/views/shared/milestones/_issuable.html.haml2
-rw-r--r--app/views/shared/milestones/_issuables.html.haml2
-rw-r--r--app/views/shared/milestones/_issues_tab.html.haml3
-rw-r--r--app/views/shared/milestones/_merge_requests_tab.haml3
-rw-r--r--app/views/shared/milestones/_milestone.html.haml4
-rw-r--r--app/views/shared/milestones/_sidebar.html.haml3
-rw-r--r--app/views/shared/milestones/_tabs.html.haml17
-rw-r--r--app/views/shared/milestones/_top.html.haml2
-rw-r--r--app/views/shared/notes/_edit.html.haml2
-rw-r--r--app/views/shared/notes/_notes_with_form.html.haml2
-rw-r--r--app/views/shared/notifications/_button.html.haml2
-rw-r--r--app/views/shared/projects/_search_form.html.haml2
-rw-r--r--app/views/shared/runners/_shared_runners_description.html.haml11
-rw-r--r--app/views/shared/snippets/_blob.html.haml13
-rw-r--r--app/views/shared/snippets/_form.html.haml58
-rw-r--r--app/views/shared/snippets/_header.html.haml47
-rw-r--r--app/views/shared/snippets/_snippet.html.haml2
-rw-r--r--app/views/shared/web_hooks/_form.html.haml2
-rw-r--r--app/views/shared/wikis/_form.html.haml26
-rw-r--r--app/views/shared/wikis/_main_links.html.haml9
-rw-r--r--app/views/shared/wikis/_pages_wiki_page.html.haml2
-rw-r--r--app/views/shared/wikis/_sidebar.html.haml11
-rw-r--r--app/views/shared/wikis/_wiki_directory.html.haml4
-rw-r--r--app/views/shared/wikis/diff.html.haml3
-rw-r--r--app/views/shared/wikis/edit.html.haml3
-rw-r--r--app/views/shared/wikis/empty.html.haml1
-rw-r--r--app/views/shared/wikis/history.html.haml1
-rw-r--r--app/views/shared/wikis/pages.html.haml5
-rw-r--r--app/views/shared/wikis/show.html.haml11
-rw-r--r--app/views/sherlock/file_samples/show.html.haml4
-rw-r--r--app/views/snippets/_actions.html.haml35
-rw-r--r--app/views/snippets/show.html.haml8
-rw-r--r--app/views/users/_overview.html.haml31
-rw-r--r--app/views/users/show.html.haml91
-rw-r--r--app/workers/all_queues.yml167
-rw-r--r--app/workers/analytics/instance_statistics/count_job_trigger_worker.rb5
-rw-r--r--app/workers/archive_trace_worker.rb2
-rw-r--r--app/workers/authorized_project_update/periodic_recalculate_worker.rb4
-rw-r--r--app/workers/authorized_project_update/user_refresh_over_user_range_worker.rb4
-rw-r--r--app/workers/background_migration_worker.rb4
-rw-r--r--app/workers/build_coverage_worker.rb2
-rw-r--r--app/workers/build_finished_worker.rb17
-rw-r--r--app/workers/build_trace_sections_worker.rb2
-rw-r--r--app/workers/chat_notification_worker.rb1
-rw-r--r--app/workers/ci/build_report_result_worker.rb2
-rw-r--r--app/workers/ci/build_trace_chunk_flush_worker.rb4
-rw-r--r--app/workers/ci/delete_objects_worker.rb38
-rw-r--r--app/workers/ci/schedule_delete_objects_cron_worker.rb18
-rw-r--r--app/workers/cleanup_container_repository_worker.rb12
-rw-r--r--app/workers/concerns/limited_capacity/job_tracker.rb74
-rw-r--r--app/workers/concerns/limited_capacity/worker.rb164
-rw-r--r--app/workers/container_expiration_policy_worker.rb16
-rw-r--r--app/workers/deployments/drop_older_deployments_worker.rb14
-rw-r--r--app/workers/deployments/execute_hooks_worker.rb17
-rw-r--r--app/workers/deployments/finished_worker.rb2
-rw-r--r--app/workers/deployments/forward_deployment_worker.rb2
-rw-r--r--app/workers/deployments/link_merge_request_worker.rb18
-rw-r--r--app/workers/deployments/success_worker.rb4
-rw-r--r--app/workers/deployments/update_environment_worker.rb20
-rw-r--r--app/workers/design_management/copy_design_collection_worker.rb26
-rw-r--r--app/workers/design_management/new_version_worker.rb4
-rw-r--r--app/workers/disallow_two_factor_for_group_worker.rb19
-rw-r--r--app/workers/disallow_two_factor_for_subgroups_worker.rb30
-rw-r--r--app/workers/expire_build_instance_artifacts_worker.rb1
-rw-r--r--app/workers/export_csv_worker.rb4
-rw-r--r--app/workers/git_garbage_collect_worker.rb6
-rw-r--r--app/workers/group_destroy_worker.rb1
-rw-r--r--app/workers/group_export_worker.rb2
-rw-r--r--app/workers/group_import_worker.rb4
-rw-r--r--app/workers/incident_management/add_severity_system_note_worker.rb22
-rw-r--r--app/workers/issuable_export_csv_worker.rb53
-rw-r--r--app/workers/issue_placement_worker.rb8
-rw-r--r--app/workers/issue_rebalancing_worker.rb3
-rw-r--r--app/workers/member_invitation_reminder_emails_worker.rb19
-rw-r--r--app/workers/metrics/dashboard/sync_dashboards_worker.rb22
-rw-r--r--app/workers/pages_domain_ssl_renewal_worker.rb1
-rw-r--r--app/workers/pages_domain_verification_worker.rb1
-rw-r--r--app/workers/pages_worker.rb1
-rw-r--r--app/workers/post_receive.rb2
-rw-r--r--app/workers/project_destroy_worker.rb1
-rw-r--r--app/workers/project_export_worker.rb2
-rw-r--r--app/workers/propagate_integration_group_worker.rb25
-rw-r--r--app/workers/propagate_integration_inherit_worker.rb19
-rw-r--r--app/workers/propagate_integration_project_worker.rb22
-rw-r--r--app/workers/propagate_integration_worker.rb3
-rw-r--r--app/workers/repository_import_worker.rb3
-rw-r--r--app/workers/stuck_ci_jobs_worker.rb2
-rw-r--r--app/workers/web_hooks/destroy_worker.rb27
-rwxr-xr-xbin/feature-flag19
-rw-r--r--changelogs/unreleased/-231183-invites.yml5
-rw-r--r--changelogs/unreleased/-231185-admin-jobs.yml5
-rw-r--r--changelogs/unreleased/-231191-projects-services-mattermost_slash_commands.yml5
-rw-r--r--changelogs/unreleased/-231200-projects-issues-export_csv.yml5
-rw-r--r--changelogs/unreleased/-231206-projects-commits.yml5
-rw-r--r--changelogs/unreleased/-231207-projects-compare.yml5
-rw-r--r--changelogs/unreleased/-231208-sherlock-file_samples.yml5
-rw-r--r--changelogs/unreleased/-231217-shared-wikis.yml5
-rw-r--r--changelogs/unreleased/-231225-projects-deployments.yml5
-rw-r--r--changelogs/unreleased/10io-return-empty-string-for-md5-maven-upload-requests.yml5
-rw-r--r--changelogs/unreleased/119032-add-filename-to-unit-test-report.yml5
-rw-r--r--changelogs/unreleased/13426-bugfix-copyState-and-padding.yml5
-rw-r--r--changelogs/unreleased/13426-copy-designs.yml5
-rw-r--r--changelogs/unreleased/13426-graphql-fe.yml5
-rw-r--r--changelogs/unreleased/13426-graphql.yml5
-rw-r--r--changelogs/unreleased/13426-remove-feature-flag.yml5
-rw-r--r--changelogs/unreleased/17673-wiki-pages-tree-structure.yml5
-rw-r--r--changelogs/unreleased/18324-add-links-to-urls-in-job-logs.yml5
-rw-r--r--changelogs/unreleased/18969-allow-optional-caching-in-failed-builds.yml5
-rw-r--r--changelogs/unreleased/197227-load-milestone-issues-tab-async.yml5
-rw-r--r--changelogs/unreleased/198-add-automation-friendly-migration-rake-tasks.yml5
-rw-r--r--changelogs/unreleased/198413-CI-Pre-Collapsed-Sections.yml5
-rw-r--r--changelogs/unreleased/198612-monaco-ci-default.yml5
-rw-r--r--changelogs/unreleased/202264-migrate-fa-spinner-to-spinner-for-app-assets-javascripts-vue_share.yml5
-rw-r--r--changelogs/unreleased/205157-cannot-include-downstream-pipeline-with-include-file.yml5
-rw-r--r--changelogs/unreleased/207347-terraform-versions-api.yml5
-rw-r--r--changelogs/unreleased/208193-add-expiration-started-at-to-container-repositories.yml5
-rw-r--r--changelogs/unreleased/208260-fix-mr-task-lists-starting-with-new-line.yml5
-rw-r--r--changelogs/unreleased/209831-propagate-integrations-using-batching-and-queues.yml5
-rw-r--r--changelogs/unreleased/212373-249588-enable-ci_new_artifact_file_reader.yml5
-rw-r--r--changelogs/unreleased/215669-create-auto-fix-bot.yml5
-rw-r--r--changelogs/unreleased/215697-allow-groups-to-disable-2fa-requirement-for-subgroups-migration.yml6
-rw-r--r--changelogs/unreleased/215697-allow-groups-to-disable-2fa-requirement-for-subgroups-ui.yml5
-rw-r--r--changelogs/unreleased/216438-add-lsif-to-go-auto-devops-gitlab-ci-yml.yml5
-rw-r--r--changelogs/unreleased/21654-ide-button-in-mr-diff-files.yml5
-rw-r--r--changelogs/unreleased/216571-terraform-states-graphql-endpoint.yml5
-rw-r--r--changelogs/unreleased/216642-display-youtube-iframes.yml5
-rw-r--r--changelogs/unreleased/216642-embed-youtube-video.yml5
-rw-r--r--changelogs/unreleased/216861-autosave.yml5
-rw-r--r--changelogs/unreleased/216861-ui-for-mr-title-description.yml5
-rw-r--r--changelogs/unreleased/216881-add-close-button-to-sidebar-labels-to-remove.yml5
-rw-r--r--changelogs/unreleased/216881-remove-vue_sidebar_labels-feature-flag.yml5
-rw-r--r--changelogs/unreleased/217115-assign-epic-to-a-group-when-creating-within-another-epic.yml5
-rw-r--r--changelogs/unreleased/217157-nuget-version-regex.yml5
-rw-r--r--changelogs/unreleased/217722-fj-add-spam-mechanism-to-snippet-mutations.yml5
-rw-r--r--changelogs/unreleased/217809-fj-remove-snippet-multiple-files-ff.yml5
-rw-r--r--changelogs/unreleased/217882-allow-designs-to-be-added-to-moved-issues.yml5
-rw-r--r--changelogs/unreleased/219915-cleanup-policy-not-working.yml5
-rw-r--r--changelogs/unreleased/219951-improve-styling-of-design-pins.yml5
-rw-r--r--changelogs/unreleased/220182-remove-feature-flag.yml5
-rw-r--r--changelogs/unreleased/220203-gitlab-com-sso-create-no-access-role-fe-changes.yml5
-rw-r--r--changelogs/unreleased/220388-project-access-tokens-bot-not-deleted-when-token-expires.yml5
-rw-r--r--changelogs/unreleased/220420-migration-validate-designs-filename-text-limit.yml5
-rw-r--r--changelogs/unreleased/220503_bug_add_branches_to_be_notified_to_hangouts_service_api.yml5
-rw-r--r--changelogs/unreleased/220561-fix-invalid-project-path-response-in-go-middleware.yml5
-rw-r--r--changelogs/unreleased/220795-remove-snippets-vue-feature-flag.yml5
-rw-r--r--changelogs/unreleased/222511-missing-tooltip-for-redeploy.yml5
-rw-r--r--changelogs/unreleased/222699-wiki-find-page-empty-title.yml5
-rw-r--r--changelogs/unreleased/223101-follow-up-from-replace-double-angle-icons-with-chevron.yml5
-rw-r--r--changelogs/unreleased/223236_update_middleman_logo.yml5
-rw-r--r--changelogs/unreleased/224143-suggestion-button-not-work-for-numbers.yml5
-rw-r--r--changelogs/unreleased/224527-replace-fa-search-with-gitlab-svg-search-icon.yml5
-rw-r--r--changelogs/unreleased/225164-add-a-title-section-to-the-package-registry-ui.yml5
-rw-r--r--changelogs/unreleased/225175-change-the-default-order-for-packages-in-the-package-registry-list.yml5
-rw-r--r--changelogs/unreleased/225293-emaill-participants.yml5
-rw-r--r--changelogs/unreleased/225644-package-registry-in-the-group-registry-view-make-the-project-ui-mo.yml5
-rw-r--r--changelogs/unreleased/225655-alert-new-page.yml5
-rw-r--r--changelogs/unreleased/225930-replace-fa-file-icons-with-gitlab-svg-document-icon.yml5
-rw-r--r--changelogs/unreleased/225941-replace-fa-file-text-o-icons-with-gitlab-svg-doc-text-icon.yml5
-rw-r--r--changelogs/unreleased/225952-replace-fa-calendar-icons-with-gitlab-svg-calendar-icon.yml5
-rw-r--r--changelogs/unreleased/227668-boards_resolver_id_required.yml5
-rw-r--r--changelogs/unreleased/227836-incidents-comments-timeline-view.yml5
-rw-r--r--changelogs/unreleased/228674-no-dependencies-on-deploy-ecs.yml5
-rw-r--r--changelogs/unreleased/229023-migrate-sidebar-epic-tooltip.yml5
-rw-r--r--changelogs/unreleased/229038-delete-environment-tooltip.yml5
-rw-r--r--changelogs/unreleased/229039-environment-stop-tooltip.yml5
-rw-r--r--changelogs/unreleased/229040-activity-bar-tooltip.yml5
-rw-r--r--changelogs/unreleased/229114-jira-connect-install-webhook-for-updates.yml5
-rw-r--r--changelogs/unreleased/229223-store-jira-server-type-post-migration.yml5
-rw-r--r--changelogs/unreleased/229284-migrate-bootstrap-button-to-gitlab-ui-glbutton-in-app-assets-javas.yml5
-rw-r--r--changelogs/unreleased/229303-migrate-bootstrap-button-to-gitlab-ui-glbutton-in-app-assets-javas.yml6
-rw-r--r--changelogs/unreleased/229327-migrate-bootstrap-button-to-gitlab-ui-glbutton-in-ee-app-assets-ja.yml5
-rw-r--r--changelogs/unreleased/229330-update-discard-changes-button.yml5
-rw-r--r--changelogs/unreleased/229343-update-lock-form-buttons.yml5
-rw-r--r--changelogs/unreleased/229344-update-confidential-form-buttons.yml5
-rw-r--r--changelogs/unreleased/229404-filter-capabilities.yml5
-rw-r--r--changelogs/unreleased/229534-incident-sorting-backend.yml5
-rw-r--r--changelogs/unreleased/229534-incidents-sorting.yml5
-rw-r--r--changelogs/unreleased/229672-update-badge-list-row-modal.yml5
-rw-r--r--changelogs/unreleased/229727-drop-type-on-audit-events.yml5
-rw-r--r--changelogs/unreleased/229834-destroy-board-list-graphql.yml5
-rw-r--r--changelogs/unreleased/229838-create-issue-graphql.yml5
-rw-r--r--changelogs/unreleased/229918-issue_data_designs.yml5
-rw-r--r--changelogs/unreleased/229918-issue_data_epics.yml5
-rw-r--r--changelogs/unreleased/229918-track-additional-issue-change-events.yml5
-rw-r--r--changelogs/unreleased/229918-track-time-tracking-events.yml5
-rw-r--r--changelogs/unreleased/230438-usage-data-optimize-usage_activity_by_stage-counters.yml5
-rw-r--r--changelogs/unreleased/230719-tabs-vue-migrate-app-assets-javascripts-environments-components-en.yml5
-rw-r--r--changelogs/unreleased/230720-tabs-vue-migrate-app-assets-javascripts-environments-folder-enviro.yml5
-rw-r--r--changelogs/unreleased/230725-update-boards-modal-tabs.yml5
-rw-r--r--changelogs/unreleased/230827-fix-epics-filter.yml5
-rw-r--r--changelogs/unreleased/230841-update-alert-gfm-like-reference.yml5
-rw-r--r--changelogs/unreleased/231072-project-members-import-button.yml5
-rw-r--r--changelogs/unreleased/231180-ui-button-proj-hook_logs.yml5
-rw-r--r--changelogs/unreleased/231209-labels-buttons.yml5
-rw-r--r--changelogs/unreleased/231214-admin-deploy-key-buttons.yml5
-rw-r--r--changelogs/unreleased/231306-approve-activity-in-core.yml5
-rw-r--r--changelogs/unreleased/231467-reduce-cached-query-jobscontroller-show.yml5
-rw-r--r--changelogs/unreleased/232503-editor-lite-extensions-on-instance.yml5
-rw-r--r--changelogs/unreleased/232503-editor-lite-to-snippet.yml5
-rw-r--r--changelogs/unreleased/232503-editor-lite-vue-component.yml5
-rw-r--r--changelogs/unreleased/232670-webauthn-background-migration.yml5
-rw-r--r--changelogs/unreleased/232798-alrt-graphql.yml5
-rw-r--r--changelogs/unreleased/233016_fix_jira_dvcs_user_avatars.yml5
-rw-r--r--changelogs/unreleased/233430-design-repo-in-backup.yml5
-rw-r--r--changelogs/unreleased/233433-create-board-graphql.yml5
-rw-r--r--changelogs/unreleased/233626-fj-add-snippets-to-backups.yml5
-rw-r--r--changelogs/unreleased/233627-fj-restore-snippets-in-backups.yml5
-rw-r--r--changelogs/unreleased/233647-replace-bootstrap-alerts-to-gitlab-ui.yml5
-rw-r--r--changelogs/unreleased/233660-remove-bootstrap-alert-gcp.yml5
-rw-r--r--changelogs/unreleased/233664-bootstrap-alert-auto-devops.yml5
-rw-r--r--changelogs/unreleased/233674-remove-bootstrap-usage-invalid.yml5
-rw-r--r--changelogs/unreleased/233680-replace-bootstrap-alerts-in-app-views-profiles-accounts-show-html-.yml5
-rw-r--r--changelogs/unreleased/233681-replace-bootstrap-alerts-in-app-views-projects-milestones-show-htm.yml5
-rw-r--r--changelogs/unreleased/233686-replace-bootstrap-alerts-in-app-views-admin-projects-show-html-ham.yml5
-rw-r--r--changelogs/unreleased/233693-remove-bootstrap-pages.yml5
-rw-r--r--changelogs/unreleased/233694-replace-bootstrap-alerts-in-app-views-projects-diffs-_warning-html.yml5
-rw-r--r--changelogs/unreleased/233703-replace-bootstrap-alerts-in-app-views-import-shared-_errors-html-h.yml5
-rw-r--r--changelogs/unreleased/233719-project-creating-incidents-usage-ping.yml5
-rw-r--r--changelogs/unreleased/233722-snowplow-incidents-list-details-views.yml5
-rw-r--r--changelogs/unreleased/233785-track-audit-event-searches.yml5
-rw-r--r--changelogs/unreleased/233940-product-analytics-for-group-level-integrations.yml5
-rw-r--r--changelogs/unreleased/233994_sse_usage_ping.yml5
-rw-r--r--changelogs/unreleased/235108-migrate-terraform-states-to-versioniong.yml5
-rw-r--r--changelogs/unreleased/235676-prioritize-exact-matches.yml5
-rw-r--r--changelogs/unreleased/235765-enable-project-access-tokens-gitlab-com.yml5
-rw-r--r--changelogs/unreleased/235822-group-package-permissions.yml5
-rw-r--r--changelogs/unreleased/235822-maven-group-token.yml6
-rw-r--r--changelogs/unreleased/235857-sentryerrortype-project_id-returns-a-project-global-id.yml5
-rw-r--r--changelogs/unreleased/235888-gitlab-for-jira-app-should-display-who-is-logged-in.yml5
-rw-r--r--changelogs/unreleased/235945-replace-the-delete-ssh-confirmation-dialog-with-a-pajamas-modal.yml5
-rw-r--r--changelogs/unreleased/237923-error-when-quickly-reordering-designs.yml5
-rw-r--r--changelogs/unreleased/238570-hide-instance-level-integrations-on-gitlab-com.yml5
-rw-r--r--changelogs/unreleased/238605-optimise-lfs-cleanup.yml5
-rw-r--r--changelogs/unreleased/238605-remove-cleanup-lfs-during-gc-feature-flag.yml5
-rw-r--r--changelogs/unreleased/238628-design-specs-for-confirmation-modal.yml5
-rw-r--r--changelogs/unreleased/238931-improve-responsive-state-of-board-filtering-bar-when-group-by-drop.yml5
-rw-r--r--changelogs/unreleased/239090-fix-throughput-chart.yml6
-rw-r--r--changelogs/unreleased/239130-conan-recipe-display-be.yml5
-rw-r--r--changelogs/unreleased/239130-package-presenter-conan.yml5
-rw-r--r--changelogs/unreleased/239327-fj-fix-snippet-update-edge-case.yml5
-rw-r--r--changelogs/unreleased/239852-move-merge-conflicts-to-page-bundle.yml5
-rw-r--r--changelogs/unreleased/239861-pipeline-light-text-normal.yml5
-rw-r--r--changelogs/unreleased/241165-sse-config-image-upload-path.yml5
-rw-r--r--changelogs/unreleased/241166-sse-config-mounts.yml5
-rw-r--r--changelogs/unreleased/241663-incident-sla-cron-job.yml5
-rw-r--r--changelogs/unreleased/241663-incident-sla-logic.yml5
-rw-r--r--changelogs/unreleased/241678-python-name-normalization.yml6
-rw-r--r--changelogs/unreleased/241831-null-bytes.yml5
-rw-r--r--changelogs/unreleased/241990-default-show_inherited_labels-feature-flag-to-true.yml5
-rw-r--r--changelogs/unreleased/241990-show-all-inherited-labels-in-subgroups.yml5
-rw-r--r--changelogs/unreleased/241990-show-full-path-where-labels-come-from.yml5
-rw-r--r--changelogs/unreleased/242016-fj-add-instance-gitpod-enabled-to-usage-data.yml5
-rw-r--r--changelogs/unreleased/242016-fj-add-user-preferences-gitpod-enabled-to-usage-data.yml5
-rw-r--r--changelogs/unreleased/242285-approve-graphql-ce.yml5
-rw-r--r--changelogs/unreleased/243563-move-approval-code-to-ce.yml5
-rw-r--r--changelogs/unreleased/243750-display-messages-and-warning-for-partially-executed-cleanup-polici.yml5
-rw-r--r--changelogs/unreleased/243776-reorder-nav-item.yml5
-rw-r--r--changelogs/unreleased/244050-feature-flag-to-allow-old-projects-to-have-a-cleanup-policy.yml5
-rw-r--r--changelogs/unreleased/244355-add-javascript-example-on-how-we-could-track-ui-events-using-usage.yml5
-rw-r--r--changelogs/unreleased/244427-bold-search-term-issues.yml5
-rw-r--r--changelogs/unreleased/244484-remove-redundant-cluster-agents-index.yml5
-rw-r--r--changelogs/unreleased/244828-drop-iglu-registry-url-column.yml5
-rw-r--r--changelogs/unreleased/244873-perceived-ux-success-screen.yml5
-rw-r--r--changelogs/unreleased/245304-reference-pages_deployments-in-pages_metadata.yml5
-rw-r--r--changelogs/unreleased/245325-refactor-the-invites-controller-member-method.yml5
-rw-r--r--changelogs/unreleased/245331-alert-integrations-list.yml5
-rw-r--r--changelogs/unreleased/245337-integrations-list-icons.yml5
-rw-r--r--changelogs/unreleased/246619-add-package-events.yml5
-rw-r--r--changelogs/unreleased/246739-use-gitlab-svg-icons-in-file_type_icon_class-helper.yml5
-rw-r--r--changelogs/unreleased/246783-setting-button-position.yml5
-rw-r--r--changelogs/unreleased/246793-mr-coverage-only-latest-build.yml5
-rw-r--r--changelogs/unreleased/246847-store-pipeline-counts-by-status.yml5
-rw-r--r--changelogs/unreleased/247449_auto-purchased-storage-allocation.yml5
-rw-r--r--changelogs/unreleased/247476-standardise-usage-of-angle-brackets.yml5
-rw-r--r--changelogs/unreleased/247489-update-create-column-from-to-also-copy-constraints-take-2.yml5
-rw-r--r--changelogs/unreleased/247496-add-rollback-migration-helpers-for-change-column-type-concurrently.yml5
-rw-r--r--changelogs/unreleased/247634-add-healthcheck-to-ce.yml6
-rw-r--r--changelogs/unreleased/247895-search-results-filters-should-have-a-clear-behavior.yml5
-rw-r--r--changelogs/unreleased/248564-remove-web-ide-suggestion-banner-on-blob-edit.yml5
-rw-r--r--changelogs/unreleased/249180-add-time-limit-on-counts.yml5
-rw-r--r--changelogs/unreleased/249368-unit-test-report-test-cases-with-errored-status-show-skipped-icon.yml5
-rw-r--r--changelogs/unreleased/249550-remove-feature-flag-for-core-mr-widget.yml5
-rw-r--r--changelogs/unreleased/249561-update-workhorse.yml5
-rw-r--r--changelogs/unreleased/249590-project-count-admin-view.yml5
-rw-r--r--changelogs/unreleased/249811-remove-coverage-report-view-feature-flag.yml5
-rw-r--r--changelogs/unreleased/249819-ide-improve-errors.yml5
-rw-r--r--changelogs/unreleased/250041-does-not-refresh-project-snippet-statistics-on-a-read-only-instanc.yml5
-rw-r--r--changelogs/unreleased/250355-iterations-overlap-validation-bug.yml5
-rw-r--r--changelogs/unreleased/250571-jumping-button-on-the-environments-page.yml5
-rw-r--r--changelogs/unreleased/250580-fix-graphql-api-token-authentication.yml5
-rw-r--r--changelogs/unreleased/250654-get-lfs-push-mirror-working-for-github.yml5
-rw-r--r--changelogs/unreleased/250671-don-t-init-http-metrics-in-sidekiq.yml5
-rw-r--r--changelogs/unreleased/250685-fix-carets.yml5
-rw-r--r--changelogs/unreleased/250727-use-fuzzaldrinplus-search-for-labels.yml5
-rw-r--r--changelogs/unreleased/251048-modify-time-period-for-batch-counting-performance-of-the-last-port.yml5
-rw-r--r--changelogs/unreleased/251113-create_framework_model.yml5
-rw-r--r--changelogs/unreleased/251179-spike-investigate-value-of-sentry-vs-performance-implications.yml5
-rw-r--r--changelogs/unreleased/251214-remove-release-evidence-collection-feature-flag.yml5
-rw-r--r--changelogs/unreleased/251935-add-default_branch_name-column-to-namespace_settings-table.yml5
-rw-r--r--changelogs/unreleased/251963-respect-group-s-default-branch-name-when-present.yml5
-rw-r--r--changelogs/unreleased/254197-merge-request-diff-has-an-extra-spacing-on-mobile.yml5
-rw-r--r--changelogs/unreleased/254224-notification-icons-missing-icon-for-custom.yml5
-rw-r--r--changelogs/unreleased/254250-add-time-tracking-to-incidents.yml5
-rw-r--r--changelogs/unreleased/254281-add-user-agent-to-git-lfs-client.yml5
-rw-r--r--changelogs/unreleased/254281-lfs-push-mirror-prefers-server-authorization-header.yml5
-rw-r--r--changelogs/unreleased/254281-remove-push-mirror-syncs-lfs-feature-flag.yml5
-rw-r--r--changelogs/unreleased/254673-replace-cycle_analytics-icon_branch-svg-with-commit-svg-in-gitlab-.yml5
-rw-r--r--changelogs/unreleased/254706-fix-commit-item-layout-on-mrs.yml5
-rw-r--r--changelogs/unreleased/254721-enable-store_ci_pipeline_counts_by_status-ff-by-default.yml5
-rw-r--r--changelogs/unreleased/254823-automatically-expand-file-on-merge-request-with-changes-to-single-.yml5
-rw-r--r--changelogs/unreleased/254903-add-multiple-assignee-filter-graphql.yml5
-rw-r--r--changelogs/unreleased/254932-fix-search-results-blob-link-to-branch.yml5
-rw-r--r--changelogs/unreleased/254946-add-missing-fa-icons-for-file_type_icon_class.yml5
-rw-r--r--changelogs/unreleased/255322-search-sort-issues-and-mrs.yml5
-rw-r--r--changelogs/unreleased/255347-add-a-project-configured-with-gitpod-to-project-templates.yml5
-rw-r--r--changelogs/unreleased/255938-delete-user-dialog-text-contains-formatting-strings.yml5
-rw-r--r--changelogs/unreleased/255985-snowplow-count-timeline-toggle.yml5
-rw-r--r--changelogs/unreleased/256094-fix-copy-indexes-migration-helper-opclass-replication.yml6
-rw-r--r--changelogs/unreleased/256121-add-schema-to-migration-helpers-that-query-the-pg-catalog.yml5
-rw-r--r--changelogs/unreleased/257198-align-recognized-markdown-extensions-with-file-icon.yml5
-rw-r--r--changelogs/unreleased/257762-boards-page-broken-on-dark-mode.yml5
-rw-r--r--changelogs/unreleased/257764-milestones-page-broken-on-dark-mode.yml5
-rw-r--r--changelogs/unreleased/257842-issue-incident-feature-flag-removal.yml5
-rw-r--r--changelogs/unreleased/257881-migration-user-admin-approval-toggle.yml6
-rw-r--r--changelogs/unreleased/258203-add-api-fuzzing-plan-limits-db.yml5
-rw-r--r--changelogs/unreleased/258206-enable-gitpod-flag-by-default.yml5
-rw-r--r--changelogs/unreleased/258668-update-icons-in-nav.yml5
-rw-r--r--changelogs/unreleased/258677-center-toggle-focus-mode-icon.yml5
-rw-r--r--changelogs/unreleased/258964-update-node-sass-from-4-12-to-4-14.yml5
-rw-r--r--changelogs/unreleased/258980-enable-feature-flag-by-default-of-admin-approval-for-new-user-sign.yml5
-rw-r--r--changelogs/unreleased/259005-add-cached-queries-to-performance-bar.yml5
-rw-r--r--changelogs/unreleased/259060-align-badge-in-mr-list.yml5
-rw-r--r--changelogs/unreleased/260323-handle-malformed-composer-json.yml5
-rw-r--r--changelogs/unreleased/262051-design-thumbnail-image-is-not-updated-after-uploading-an-image-wit.yml5
-rw-r--r--changelogs/unreleased/262073-fix-merge-conflict-button-text-none.yml5
-rw-r--r--changelogs/unreleased/262633-integrations-form-cleanup.yml5
-rw-r--r--changelogs/unreleased/262686-track-unique-wiki-page-views.yml5
-rw-r--r--changelogs/unreleased/262730-fix-incident-table-hover.yml5
-rw-r--r--changelogs/unreleased/262851-minimal-access-role-resending-member-invite-causes-404.yml5
-rw-r--r--changelogs/unreleased/263102-bugfix-use-project-owner-to-perform-git-actions-during-design-copy.yml6
-rw-r--r--changelogs/unreleased/263110-improve-cleanup-policies-selection-during-their-execution.yml5
-rw-r--r--changelogs/unreleased/263221-clone-button-misaligned-on-empty-repository.yml5
-rw-r--r--changelogs/unreleased/263237-replace-font-awesome-icons-in-user-profile.yml5
-rw-r--r--changelogs/unreleased/263402-enable-review-app-button-opens-twice-the-popup.yml5
-rw-r--r--changelogs/unreleased/263406-enable-cached-markdown-blob-default.yml5
-rw-r--r--changelogs/unreleased/263412-enable-ci_manual_bridges-by-default.yml5
-rw-r--r--changelogs/unreleased/263484-integration-descriptions-should-be-less-project-level-specific.yml5
-rw-r--r--changelogs/unreleased/263509_add_cross_site_cookies_browser_limitaion_message.yml5
-rw-r--r--changelogs/unreleased/264790-bs4-optimization-admin-abuse-reports.yml5
-rw-r--r--changelogs/unreleased/264790-bs4-optimization-admin-devops-report.yml5
-rw-r--r--changelogs/unreleased/264790-bs4-optimization-commit-2.yml5
-rw-r--r--changelogs/unreleased/264790-bs4-optimization-commit.yml5
-rw-r--r--changelogs/unreleased/264790-bs4-optimization-diff.yml5
-rw-r--r--changelogs/unreleased/264790-bs4-optimization-environments.yml5
-rw-r--r--changelogs/unreleased/264790-bs4-optimization-issuable-header.yml5
-rw-r--r--changelogs/unreleased/264790-bs4-optimization-pipelines.yml5
-rw-r--r--changelogs/unreleased/267000-create-from-template-inherit-integrations.yml5
-rw-r--r--changelogs/unreleased/267011-accept-alternative-names-for-production-env.yml5
-rw-r--r--changelogs/unreleased/267114-enable-usage_data_api-by-default-feature.yml5
-rw-r--r--changelogs/unreleased/267498-failed-test-qa-specs-features-browser_ui-1_manage-login-register_s.yml5
-rw-r--r--changelogs/unreleased/267505-mobile-empty-screen-svg-overlap.yml5
-rw-r--r--changelogs/unreleased/267583-fix-storing-of-issue-json-for-redirect.yml5
-rw-r--r--changelogs/unreleased/267973-replace-fa-angle-double-left-with-gitlab-svg-chevron-double-lg-lef.yml5
-rw-r--r--changelogs/unreleased/268042-graphql-use-new-global_id-for-discussion-mutations.yml5
-rw-r--r--changelogs/unreleased/268144-mr-widget-copy-branch-name-button-tooltip-occasionally-shows-undef.yml5
-rw-r--r--changelogs/unreleased/270054-fix-no-method-error.yml5
-rw-r--r--changelogs/unreleased/27535-new-project-ide.yml5
-rw-r--r--changelogs/unreleased/32328_add_help_page_documentation_url_column.yml5
-rw-r--r--changelogs/unreleased/32328_use_documentation_url_to_configure_path_to_help_pages.yml5
-rw-r--r--changelogs/unreleased/35223-drop-unused-user-id-column-on-cluster-providers-aws.yml5
-rw-r--r--changelogs/unreleased/40174-snowflake-npm-forward.yml5
-rw-r--r--changelogs/unreleased/42426-migrate-slack-button.yml5
-rw-r--r--changelogs/unreleased/42782-move-beforescript-into-script.yml5
-rw-r--r--changelogs/unreleased/42916-pypi-install-command.yml5
-rw-r--r--changelogs/unreleased/42917_golang_vendor_templates.yml5
-rw-r--r--changelogs/unreleased/42989-update-deactivation-threshold-to-90-days.yml5
-rw-r--r--changelogs/unreleased/43009-update-docs-link-packages.yml5
-rw-r--r--changelogs/unreleased/43499-update-commit-message-popover.yml5
-rw-r--r--changelogs/unreleased/44949-update-copy-insert-modal.yml5
-rw-r--r--changelogs/unreleased/Add-Issue-Link-to-Open-Message.yml5
-rw-r--r--changelogs/unreleased/Migrate-deprecated-delete-milestone-modal-ab.yml5
-rw-r--r--changelogs/unreleased/Replace-GIDeprecatedDropdown-in-app-assets-javascripts-alert_management.yml5
-rw-r--r--changelogs/unreleased/Replace-GlDeprecatedDropdown-with-GlDropdown-in-app-assets-javascripts-ci.yml5
-rw-r--r--changelogs/unreleased/Replace-GlDeprecatedDropdown-with-GlDropdown-in-app-assets-javascripts-cl.yml5
-rw-r--r--changelogs/unreleased/Replace-GlDeprecatedDropdown-with-GlDropdown-in-app-assets-javascripts-co.yml5
-rw-r--r--changelogs/unreleased/Replace-GlDeprecatedDropdown-with-GlDropdown-in-app-assets-javascripts-lo.yml5
-rw-r--r--changelogs/unreleased/Replace-GlDeprecatedDropdown-with-GlDropdown-in-app-assets-javascripts-pa.yml5
-rw-r--r--changelogs/unreleased/Replace-GlDeprecatedDropdown-with-GlDropdown-in-app-assets-javascripts-pi.yml5
-rw-r--r--changelogs/unreleased/Replace-GlDeprecatedDropdown-with-GlDropdown-in-app-assets-javascripts-re.yml5
-rw-r--r--changelogs/unreleased/Replace-GlDeprecatedDropdown-with-GlDropdown-in-app-assets-javascripts-vu.yml5
-rw-r--r--changelogs/unreleased/Replace-GlDeprecatedDropdown-with-GlDropdown-in-ee-app-assets-javascripts.yml5
-rw-r--r--changelogs/unreleased/Replace-GlDeprecatedDropdown-with-GlDropdown-timezone-dropdown.yml5
-rw-r--r--changelogs/unreleased/Replace-calendar-icon-tooltip-sidebar-ab.yml5
-rw-r--r--changelogs/unreleased/ab-reindexing-actiontracking.yml5
-rw-r--r--changelogs/unreleased/ab-reindexing-index-model.yml5
-rw-r--r--changelogs/unreleased/ab-reindexing-limit-schema.yml5
-rw-r--r--changelogs/unreleased/add-abuse-notification-email.yml5
-rw-r--r--changelogs/unreleased/add-ci-deleted-objects-table.yml5
-rw-r--r--changelogs/unreleased/add-dast-site-validation-worker-245209.yml5
-rw-r--r--changelogs/unreleased/add-golang-to-packages.yml5
-rw-r--r--changelogs/unreleased/add-notification-setting-for-merge-request-reviewers.yml5
-rw-r--r--changelogs/unreleased/add-sorting-to-releases.yml5
-rw-r--r--changelogs/unreleased/add-sse-config-file-3.yml6
-rw-r--r--changelogs/unreleased/add-vuex-store-for-milestone-combobox.yml5
-rw-r--r--changelogs/unreleased/add_index_for_sha_to_deployments.yml5
-rw-r--r--changelogs/unreleased/add_options_to_dast_scanner_profile_254626.yml6
-rw-r--r--changelogs/unreleased/adding-hcl.yml5
-rw-r--r--changelogs/unreleased/ajk-219380-fix-design-type-formatting-in-activity-streams.yml5
-rw-r--r--changelogs/unreleased/ajk-graphql-group-mrs.yml5
-rw-r--r--changelogs/unreleased/ajk-graphql-milestone-filters.yml5
-rw-r--r--changelogs/unreleased/ajk-issue-reposition-take.yml5
-rw-r--r--changelogs/unreleased/ajk-remove-design_management_reference_filter_gfm_pipeline-ff.yml5
-rw-r--r--changelogs/unreleased/ajk-remove-graphql_lookahead_support.yml5
-rw-r--r--changelogs/unreleased/ajk-remove-wiki_events_on_git_push-ff.yml5
-rw-r--r--changelogs/unreleased/alipniagov-update-wh-to-8-49.yml5
-rw-r--r--changelogs/unreleased/alipniagov-update-wh-version.yml5
-rw-r--r--changelogs/unreleased/alipniagov-update-workhorse-to-8-51.yml5
-rw-r--r--changelogs/unreleased/always-show-clear-cluster-cache-button.yml5
-rw-r--r--changelogs/unreleased/api-expose-gpg.yml5
-rw-r--r--changelogs/unreleased/automatic_move_storage.yml5
-rw-r--r--changelogs/unreleased/batch-load-user-notes-count.yml5
-rw-r--r--changelogs/unreleased/bjk-rack_metric_methods.yml5
-rw-r--r--changelogs/unreleased/bugfix_coverage_fuzzing_linux_arch.yml5
-rw-r--r--changelogs/unreleased/bump-deploy-image-for-fixing-scale-bug.yml5
-rw-r--r--changelogs/unreleased/bvl-remove-ff-commits-count.yml5
-rw-r--r--changelogs/unreleased/bw-delete-jira-tracker-data-jobs.yml5
-rw-r--r--changelogs/unreleased/bw_update_global_id_checks.yml5
-rw-r--r--changelogs/unreleased/change-transfer-update-create-services.yml5
-rw-r--r--changelogs/unreleased/cngo-clear-label-select-on-enter.yml5
-rw-r--r--changelogs/unreleased/cngo-fix-scoped-label-markdown-padding.yml5
-rw-r--r--changelogs/unreleased/copy-project-homepage-default-view-for-anonoymous-users.yml5
-rw-r--r--changelogs/unreleased/cycle-analytics-to-value-stream-analytics-in-university.yml5
-rw-r--r--changelogs/unreleased/dblessing-auth-events-usage-ping.yml5
-rw-r--r--changelogs/unreleased/dblessing-ip-address-validator.yml5
-rw-r--r--changelogs/unreleased/dblessing_user_created_by_id.yml5
-rw-r--r--changelogs/unreleased/debian_packages.yml5
-rw-r--r--changelogs/unreleased/debian_regexp.yml5
-rw-r--r--changelogs/unreleased/design-tracking-create-update.yml5
-rw-r--r--changelogs/unreleased/disable-shared-runners-ui.yml5
-rw-r--r--changelogs/unreleased/disabled-scoped-issue-board-assigns-labels.yml5
-rw-r--r--changelogs/unreleased/display-contributor-and-author-badges-on-notes.yml5
-rw-r--r--changelogs/unreleased/docs-test-hardcoded-docs-links.yml5
-rw-r--r--changelogs/unreleased/drop-an-element.yml5
-rw-r--r--changelogs/unreleased/drop-instance-statistics-visibility-private-column.yml5
-rw-r--r--changelogs/unreleased/dz-scope-profile-routes.yml5
-rw-r--r--changelogs/unreleased/eb-limit-test-cases-parsed.yml5
-rw-r--r--changelogs/unreleased/eb-unit-tests-parsed-usage-ping.yml5
-rw-r--r--changelogs/unreleased/enable-track-unique-visits-ff-by-default.yml5
-rw-r--r--changelogs/unreleased/eread-migrate-badge-list-row-buttons-to-new-buttons.yml5
-rw-r--r--changelogs/unreleased/eread-migrate-tooltip-time-track-collapsed.yml5
-rw-r--r--changelogs/unreleased/expose-clusters-namespace-per-environment-flag.yml6
-rw-r--r--changelogs/unreleased/expose-created-at.yml5
-rw-r--r--changelogs/unreleased/expose-junit-spec-file-path.yml5
-rw-r--r--changelogs/unreleased/feat-jcunha-adds-terraform-ci-latest-template.yml6
-rw-r--r--changelogs/unreleased/feature-flag-limits-ux.yml5
-rw-r--r--changelogs/unreleased/feature-flags-flexible-rollout-ux.yml5
-rw-r--r--changelogs/unreleased/feature-gb-validate-build-traces.yml5
-rw-r--r--changelogs/unreleased/fix-backward-keyset-pagination-for-merged-at.yml5
-rw-r--r--changelogs/unreleased/fix-design-zoom.yml5
-rw-r--r--changelogs/unreleased/fix-encoding-for-nil-diff-files.yml5
-rw-r--r--changelogs/unreleased/fix-gb-fix-chunks-migration-race.yml5
-rw-r--r--changelogs/unreleased/fix-gl-emoji-race-condition.yml5
-rw-r--r--changelogs/unreleased/fix-pipeline-stage-action-alignment.yml5
-rw-r--r--changelogs/unreleased/fix-retry-job-button-422.yml5
-rw-r--r--changelogs/unreleased/fix-spelling-of-pypi.yml5
-rw-r--r--changelogs/unreleased/fix-theme-switcher.yml5
-rw-r--r--changelogs/unreleased/fix-unresolved-value-error-in-instance-statistics-graphql-api.yml5
-rw-r--r--changelogs/unreleased/fix-wrong-scope-in-approved-by.yml5
-rw-r--r--changelogs/unreleased/forward_deployment_enabled-api.yml5
-rw-r--r--changelogs/unreleased/gaga5lala-227175-carrierwave-error-handle.yml5
-rw-r--r--changelogs/unreleased/generic-packages-enable-by-default.yml5
-rw-r--r--changelogs/unreleased/georgekoltsov-add-group-import-usage-ping.yml5
-rw-r--r--changelogs/unreleased/gitlab_buttons_ci_builds.yml5
-rw-r--r--changelogs/unreleased/gitlab_buttons_projects_blob.yml5
-rw-r--r--changelogs/unreleased/gitlab_buttons_projects_forks.yml5
-rw-r--r--changelogs/unreleased/gy-add-demo-templates.yml5
-rw-r--r--changelogs/unreleased/himkp-webide-binary-regression.yml5
-rw-r--r--changelogs/unreleased/id-add-approval-rules-approvers-usage-ping.yml5
-rw-r--r--changelogs/unreleased/id-fix-squash-messages.yml5
-rw-r--r--changelogs/unreleased/id-required-sections.yml5
-rw-r--r--changelogs/unreleased/id-update-mini-magick.yml5
-rw-r--r--changelogs/unreleased/improve-emoji-support.yml5
-rw-r--r--changelogs/unreleased/improve-gfm-ac-emoji.yml5
-rw-r--r--changelogs/unreleased/incident-settings-sla.yml5
-rw-r--r--changelogs/unreleased/isolate-mentions-migration.yml5
-rw-r--r--changelogs/unreleased/issuable-award-fuzzy-search.yml5
-rw-r--r--changelogs/unreleased/issue-233479-Allow_move_issues_on_graphql.yml5
-rw-r--r--changelogs/unreleased/issue_205151.yml4
-rw-r--r--changelogs/unreleased/issue_233479-allow-graphql-to-update-issue-state.yml5
-rw-r--r--changelogs/unreleased/issue_237977-2.yml5
-rw-r--r--changelogs/unreleased/issue_237977.yml5
-rw-r--r--changelogs/unreleased/jdb-refactor-diff-rows-utils.yml5
-rw-r--r--changelogs/unreleased/jh-store_temp_import_data.yml5
-rw-r--r--changelogs/unreleased/jivanvl-runner-guided-install-backend.yml5
-rw-r--r--changelogs/unreleased/jl-update-signin-page.yml5
-rw-r--r--changelogs/unreleased/john_long-update_project_pages_settings.yml5
-rw-r--r--changelogs/unreleased/jv-cleanup-job-waiter.yml5
-rw-r--r--changelogs/unreleased/jv-job-waiter-key-leak.yml5
-rw-r--r--changelogs/unreleased/jyavorska-master-patch-96769.yml5
-rw-r--r--changelogs/unreleased/kassio-do-not-add-missing-not-if-importer-user-is-mapped.yml5
-rw-r--r--changelogs/unreleased/kassio-fix-missing-author-notes-on-importers.yml5
-rw-r--r--changelogs/unreleased/khanchi-designs-patch.yml5
-rw-r--r--changelogs/unreleased/kubeclient_491.yml6
-rw-r--r--changelogs/unreleased/latest-successful-build-including-child-pipelines.yml5
-rw-r--r--changelogs/unreleased/ld-graphql-use-new-global_id-for-note-mutations.yml5
-rw-r--r--changelogs/unreleased/list_issue_filters.yml5
-rw-r--r--changelogs/unreleased/lm-add-action-to-detailed-status.yml5
-rw-r--r--changelogs/unreleased/lm-add-scheduled-jobs.yml5
-rw-r--r--changelogs/unreleased/lm-add-status-graphql.yml5
-rw-r--r--changelogs/unreleased/lm-enable-one-d-matrix-by-default.yml5
-rw-r--r--changelogs/unreleased/lm-improve-n-1-pl-serializer.yml5
-rw-r--r--changelogs/unreleased/lm-update-status-null-fields.yml5
-rw-r--r--changelogs/unreleased/mb-rails-save-bang-rubcop.yml5
-rw-r--r--changelogs/unreleased/mb_rails_save_bang_fix2.yml5
-rw-r--r--changelogs/unreleased/mb_rails_save_bang_fix3.yml5
-rw-r--r--changelogs/unreleased/mb_rails_save_bang_fix4.yml5
-rw-r--r--changelogs/unreleased/mc-feature-ci-config-render-api-endpoint.yml5
-rw-r--r--changelogs/unreleased/mc-feature-fix-keep-path-artifact-locking.yml5
-rw-r--r--changelogs/unreleased/mc-feature-project-ci-lint-api.yml5
-rw-r--r--changelogs/unreleased/mgill-user-gpg.yml5
-rw-r--r--changelogs/unreleased/migrate-recover-hidden-stage.yml5
-rw-r--r--changelogs/unreleased/migrate_blocked_by.yml5
-rw-r--r--changelogs/unreleased/mk-add-missing-avatar-size.yml5
-rw-r--r--changelogs/unreleased/mk-enforce-not-null-file-store-on-package-files.yml6
-rw-r--r--changelogs/unreleased/mk-stackprof-object-support.yml5
-rw-r--r--changelogs/unreleased/mo-pipeline-artifacts-size-graphql.yml5
-rw-r--r--changelogs/unreleased/move-ff-menu-doc-to-core.yml5
-rw-r--r--changelogs/unreleased/move-referrer-policy-to-header.yml5
-rw-r--r--changelogs/unreleased/mr-state-index.yml5
-rw-r--r--changelogs/unreleased/mw-description-template-replace-fa-icons.yml5
-rw-r--r--changelogs/unreleased/mw-feature-flags-replace-chevron-fa-icon.yml5
-rw-r--r--changelogs/unreleased/mw-project-settings-icon-replacements.yml5
-rw-r--r--changelogs/unreleased/mw-replace-external-link-icon-group-folder.yml5
-rw-r--r--changelogs/unreleased/mw-replace-fa-bitbucket-icons.yml5
-rw-r--r--changelogs/unreleased/mw-replace-fa-github-icons.yml5
-rw-r--r--changelogs/unreleased/mw-replace-fa-google-icons.yml5
-rw-r--r--changelogs/unreleased/mw-replace-fa-icon-in-repo-preview.yml5
-rw-r--r--changelogs/unreleased/mw-replace-fa-refresh.yml5
-rw-r--r--changelogs/unreleased/mw-replace-fa-search-icons.yml5
-rw-r--r--changelogs/unreleased/mw-replace-fa-warning-in-limit-warning-component.yml5
-rw-r--r--changelogs/unreleased/mw-replace-switcher-icons.yml5
-rw-r--r--changelogs/unreleased/mw-vsa-limit-warnings-icon-refactor.yml5
-rw-r--r--changelogs/unreleased/mwaw-230438-log-usage-data-failed-queries.yml5
-rw-r--r--changelogs/unreleased/nfriend-add-release-og-description.yml5
-rw-r--r--changelogs/unreleased/nfriend-fix-markdown-preview-on-new-release-page.yml5
-rw-r--r--changelogs/unreleased/nfriend-fix-release-asset-link-length.yml5
-rw-r--r--changelogs/unreleased/nfriend-fix-release-edit-button-size.yml5
-rw-r--r--changelogs/unreleased/nfriend-strip-markdown-from-og-description.yml5
-rw-r--r--changelogs/unreleased/nfriend-update-releases-page-skeleton-loader-shape.yml5
-rw-r--r--changelogs/unreleased/nicolasdular-remove-tos-checkobx.yml5
-rw-r--r--changelogs/unreleased/nicolasdular-respect-dnt.yml5
-rw-r--r--changelogs/unreleased/nicolasdular-split-first-last-name.yml5
-rw-r--r--changelogs/unreleased/nix-comment.yml5
-rw-r--r--changelogs/unreleased/notificaion-button-class.yml5
-rw-r--r--changelogs/unreleased/ntepluhina-fix-incorrect-parameter.yml5
-rw-r--r--changelogs/unreleased/ntepluhina-refactor-toolbar-to-gitlab-ui.yml5
-rw-r--r--changelogs/unreleased/okr-alert-widget-form.yml5
-rw-r--r--changelogs/unreleased/okr-fluentd-output-settings.yml5
-rw-r--r--changelogs/unreleased/okr-ingress-modsecurity-settings.yml5
-rw-r--r--changelogs/unreleased/okr-modal-copy-button.yml5
-rw-r--r--changelogs/unreleased/pages-1-26-0.yml5
-rw-r--r--changelogs/unreleased/pages-1-27-0.yml5
-rw-r--r--changelogs/unreleased/pat-bot-terms.yml5
-rw-r--r--changelogs/unreleased/ph-199725-diffHeaderActionDropdown.yml5
-rw-r--r--changelogs/unreleased/ph-207481-targetBranchFilterDashboard.yml5
-rw-r--r--changelogs/unreleased/ph-212334-fixTwoButtonReviewSubmit.yml5
-rw-r--r--changelogs/unreleased/ph-218300-fixedSystemHeaderOnDiffs.yml5
-rw-r--r--changelogs/unreleased/ph-224141-hideBatchSuggestionsWithOnlyOneSuggestion.yml5
-rw-r--r--changelogs/unreleased/ph-227421-changeMROptionsDropdownToIncludeDraft.yml5
-rw-r--r--changelogs/unreleased/pl-tracing-core-2-usage-data.yml5
-rw-r--r--changelogs/unreleased/pl-tracing-core-5-settings-haml.yml5
-rw-r--r--changelogs/unreleased/preload-merge-request-diffs-for-throughtput-table.yml5
-rw-r--r--changelogs/unreleased/ps-fix-attach-a-file.yml5
-rw-r--r--changelogs/unreleased/psi-board-remove-list-to-sidebar.yml5
-rw-r--r--changelogs/unreleased/psi-do-not-extend-2.yml5
-rw-r--r--changelogs/unreleased/put_extra_graphql_logs.yml5
-rw-r--r--changelogs/unreleased/rails-save-bang-33.yml5
-rw-r--r--changelogs/unreleased/rails-save-bang-34.yml5
-rw-r--r--changelogs/unreleased/rails-save-bang-35.yml5
-rw-r--r--changelogs/unreleased/rails-save-bang-36.yml5
-rw-r--r--changelogs/unreleased/rails-save-bang-37.yml5
-rw-r--r--changelogs/unreleased/rate-limit-docs.yml5
-rw-r--r--changelogs/unreleased/reminder-emails-invitation-declined-screen.yml5
-rw-r--r--changelogs/unreleased/remove-add_severity_system_note-feature-flag.yml5
-rw-r--r--changelogs/unreleased/remove-index-on-issues-relative-position.yml5
-rw-r--r--changelogs/unreleased/remove-project-id-and-id-index-on-vulnerabilities-table.yml5
-rw-r--r--changelogs/unreleased/remove-tmp-index.yml5
-rw-r--r--changelogs/unreleased/remove-unused-index-for-cs-reports.yml5
-rw-r--r--changelogs/unreleased/remove-wiki-history-button-editing-view.yml5
-rw-r--r--changelogs/unreleased/remove_store_instance_statistics_measurements_ff.yml5
-rw-r--r--changelogs/unreleased/replace-alert-milestones.yml5
-rw-r--r--changelogs/unreleased/revert-42465-and-42343.yml5
-rw-r--r--changelogs/unreleased/revert-a6875e5f.yml5
-rw-r--r--changelogs/unreleased/revert-aa19ce96.yml5
-rw-r--r--changelogs/unreleased/revise-tooltip-text-of-note-role-badge.yml5
-rw-r--r--changelogs/unreleased/revoke-token-delete-project-bot.yml5
-rw-r--r--changelogs/unreleased/sarnold-deprecate-lowercase-enums.yml5
-rw-r--r--changelogs/unreleased/scoped-label-dashboard.yml5
-rw-r--r--changelogs/unreleased/security-update-runner-version.yml5
-rw-r--r--changelogs/unreleased/send-chat-notification-when-deployment-starts.yml5
-rw-r--r--changelogs/unreleased/set-performance-bar-cookie-expiry.yml5
-rw-r--r--changelogs/unreleased/sh-active-include-lfs-in-archives.yml5
-rw-r--r--changelogs/unreleased/sh-destroy-hook-logs-in-batches.yml5
-rw-r--r--changelogs/unreleased/sh-fix-pipeline-notification-email-warning.yml5
-rw-r--r--changelogs/unreleased/sh-improve-merge-error-display.yml5
-rw-r--r--changelogs/unreleased/sh-lfs-smudge-api.yml5
-rw-r--r--changelogs/unreleased/sh-update-gitlab-shell-13-10.yml5
-rw-r--r--changelogs/unreleased/sh-update-puma-memory-limits.yml5
-rw-r--r--changelogs/unreleased/sh-update-rack-2-1-4.yml5
-rw-r--r--changelogs/unreleased/sh-upgrade-gitlab-shell-13-8.yml5
-rw-r--r--changelogs/unreleased/sh-usage-data-pg-system-id.yml5
-rw-r--r--changelogs/unreleased/sk-250667-fix-block-user-api.yml5
-rw-r--r--changelogs/unreleased/sk-250679-fix-deactivate-user-api.yml5
-rw-r--r--changelogs/unreleased/spec_job_token.yml5
-rw-r--r--changelogs/unreleased/ss-add-apply-to-assignees.yml5
-rw-r--r--changelogs/unreleased/sy-alert-integrations-table.yml5
-rw-r--r--changelogs/unreleased/sy-allow-guests-to-view-incidents.yml5
-rw-r--r--changelogs/unreleased/sy-improve-generic-alert-system-note.yml5
-rw-r--r--changelogs/unreleased/sy-truncate-alert-fields.yml5
-rw-r--r--changelogs/unreleased/tr-add-detail-fields-to-table.yml5
-rw-r--r--changelogs/unreleased/tr-filter-internal-strings.yml5
-rw-r--r--changelogs/unreleased/tz-lazy-load-cropper.yml5
-rw-r--r--changelogs/unreleased/tz-preload-iconfont.yml5
-rw-r--r--changelogs/unreleased/unleash-api-with-private-repo.yml5
-rw-r--r--changelogs/unreleased/update-clipboard-button.yml5
-rw-r--r--changelogs/unreleased/update-cluster-applications-34.yml5
-rw-r--r--changelogs/unreleased/update-gitlab-runner-helm-chart-to-0-21-0.yml5
-rw-r--r--changelogs/unreleased/update-members-api-for-multiple-user_ids.yml5
-rw-r--r--changelogs/unreleased/upgrade-rouge-to-3-24.yml5
-rw-r--r--changelogs/unreleased/upgrate-gitlab-pages-to-1-28-0.yml5
-rw-r--r--changelogs/unreleased/use_mirror_of_helm_stable_repo.yml5
-rw-r--r--changelogs/unreleased/vij-public-project-snippets.yml5
-rw-r--r--changelogs/unreleased/vij-public-snippet-access.yml5
-rw-r--r--changelogs/unreleased/wiki-editor-ux-debt-1.yml5
-rw-r--r--changelogs/unreleased/wiki-editor-ux-debt-2.yml5
-rw-r--r--changelogs/unreleased/zj-bump-shell.yml5
-rw-r--r--changelogs/unreleased/zj-update-lang-colors.yml5
-rw-r--r--config/application.rb96
-rw-r--r--config/database.yml.postgresql4
-rw-r--r--config/dependency_decisions.yml46
-rw-r--r--config/environments/production.rb2
-rw-r--r--config/feature_categories.yml11
-rw-r--r--config/feature_flags/development/additional_snowplow_tracking.yml7
-rw-r--r--config/feature_flags/development/admin_approval_for_new_user_signups.yml7
-rw-r--r--config/feature_flags/development/ajax_new_deploy_token.yml4
-rw-r--r--config/feature_flags/development/allow_group_deploy_token.yml4
-rw-r--r--config/feature_flags/development/allow_possible_spam.yml6
-rw-r--r--config/feature_flags/development/allow_unsafe_ruby_regexp.yml4
-rw-r--r--config/feature_flags/development/api_kaminari_count_with_limit.yml7
-rw-r--r--config/feature_flags/development/artifacts_management_page.yml6
-rw-r--r--config/feature_flags/development/auto_create_cluster_management_project.yml4
-rw-r--r--config/feature_flags/development/backfill_partitioned_audit_events.yml7
-rw-r--r--config/feature_flags/development/boards_with_swimlanes.yml6
-rw-r--r--config/feature_flags/development/branch_push_merge_commit_analyze.yml7
-rw-r--r--config/feature_flags/development/broadcast_issue_updates.yml6
-rw-r--r--config/feature_flags/development/build_service_proxy.yml6
-rw-r--r--config/feature_flags/development/bulk_import.yml7
-rw-r--r--config/feature_flags/development/bulk_update_health_status.yml6
-rw-r--r--config/feature_flags/development/burnup_charts.yml6
-rw-r--r--config/feature_flags/development/cached_markdown_blob.yml7
-rw-r--r--config/feature_flags/development/canary_ingress_weight_control.yml7
-rw-r--r--config/feature_flags/development/ci_always_refresh_merge_requests_from_beginning.yml7
-rw-r--r--config/feature_flags/development/ci_artifacts_exclude.yml6
-rw-r--r--config/feature_flags/development/ci_bridge_pipeline_details.yml7
-rw-r--r--config/feature_flags/development/ci_build_metadata_config.yml6
-rw-r--r--config/feature_flags/development/ci_bulk_insert_on_create.yml7
-rw-r--r--config/feature_flags/development/ci_child_of_child_pipeline.yml7
-rw-r--r--config/feature_flags/development/ci_daily_code_coverage.yml7
-rw-r--r--config/feature_flags/development/ci_delete_objects_high_concurrency.yml7
-rw-r--r--config/feature_flags/development/ci_delete_objects_low_concurrency.yml7
-rw-r--r--config/feature_flags/development/ci_delete_objects_medium_concurrency.yml7
-rw-r--r--config/feature_flags/development/ci_disable_validates_dependencies.yml6
-rw-r--r--config/feature_flags/development/ci_download_daily_code_coverage.yml7
-rw-r--r--config/feature_flags/development/ci_dynamic_child_pipeline.yml6
-rw-r--r--config/feature_flags/development/ci_enable_live_trace.yml6
-rw-r--r--config/feature_flags/development/ci_instance_variables_ui.yml6
-rw-r--r--config/feature_flags/development/ci_job_heartbeats_runner.yml7
-rw-r--r--config/feature_flags/development/ci_job_jwt.yml4
-rw-r--r--config/feature_flags/development/ci_jobs_finder_refactor.yml2
-rw-r--r--config/feature_flags/development/ci_key_autocomplete.yml7
-rw-r--r--config/feature_flags/development/ci_lint_creates_pipeline_with_dry_run.yml6
-rw-r--r--config/feature_flags/development/ci_lint_vue.yml2
-rw-r--r--config/feature_flags/development/ci_manual_bridges.yml7
-rw-r--r--config/feature_flags/development/ci_new_artifact_file_reader.yml7
-rw-r--r--config/feature_flags/development/ci_pipeline_latest.yml6
-rw-r--r--config/feature_flags/development/ci_pipeline_rewind_iid.yml7
-rw-r--r--config/feature_flags/development/ci_pipeline_status_omit_commit_sha_in_cache_key.yml4
-rw-r--r--config/feature_flags/development/ci_pipeline_triggers_settings_vue_ui.yml7
-rw-r--r--config/feature_flags/development/ci_raise_job_rules_without_workflow_rules_warning.yml6
-rw-r--r--config/feature_flags/development/ci_send_deployment_hook_when_start.yml7
-rw-r--r--config/feature_flags/development/ci_skip_persistent_ref_existence_check.yml4
-rw-r--r--config/feature_flags/development/ci_store_pipeline_messages.yml6
-rw-r--r--config/feature_flags/development/ci_synchronous_artifact_parsing.yml4
-rw-r--r--config/feature_flags/development/ci_update_queues_for_online_runners.yml7
-rw-r--r--config/feature_flags/development/ci_yaml_limit_size.yml6
-rw-r--r--config/feature_flags/development/cleanup_lfs_during_gc.yml7
-rw-r--r--config/feature_flags/development/cluster_agent_list.yml7
-rw-r--r--config/feature_flags/development/cluster_management_project.yml4
-rw-r--r--config/feature_flags/development/clusters_list_redesign.yml7
-rw-r--r--config/feature_flags/development/consolidated_edit_button.yml7
-rw-r--r--config/feature_flags/development/container_expiration_policies_historic_entry.yml7
-rw-r--r--config/feature_flags/development/container_registry_api.yml7
-rw-r--r--config/feature_flags/development/container_registry_cleanup.yml7
-rw-r--r--config/feature_flags/development/container_registry_fast_tag_delete.yml7
-rw-r--r--config/feature_flags/development/core_security_mr_widget.yml7
-rw-r--r--config/feature_flags/development/create_cloud_run_clusters.yml6
-rw-r--r--config/feature_flags/development/dag_pipeline_tab.yml7
-rw-r--r--config/feature_flags/development/dashboard_pipeline_status.yml6
-rw-r--r--config/feature_flags/development/debian_packages.yml7
-rw-r--r--config/feature_flags/development/default_merge_ref_for_diffs.yml7
-rw-r--r--config/feature_flags/development/deploy_boards_dedupe_instances.yml7
-rw-r--r--config/feature_flags/development/deploy_from_footer.yml7
-rw-r--r--config/feature_flags/development/deploy_keys_on_protected_branches.yml7
-rw-r--r--config/feature_flags/development/deploy_tokens_api.yml6
-rw-r--r--config/feature_flags/development/deployment_filters.yml7
-rw-r--r--config/feature_flags/development/design_management_allow_dangerous_images.yml6
-rw-r--r--config/feature_flags/development/design_management_reference_filter_gfm_pipeline.yml7
-rw-r--r--config/feature_flags/development/design_management_todo_button.yml7
-rw-r--r--config/feature_flags/development/disable_metric_dashboard_refresh_rate.yml6
-rw-r--r--config/feature_flags/development/disable_shared_runners_on_group.yml7
-rw-r--r--config/feature_flags/development/display_merge_conflicts_in_diff.yml7
-rw-r--r--config/feature_flags/development/drop_license_management_artifact.yml6
-rw-r--r--config/feature_flags/development/efficient_counter_attribute.yml6
-rw-r--r--config/feature_flags/development/export_lfs_objects_projects.yml7
-rw-r--r--config/feature_flags/development/export_reduce_relation_batch_size.yml6
-rw-r--r--config/feature_flags/development/expose_environment_path_in_alert_details.yml7
-rw-r--r--config/feature_flags/development/feature_flag_api.yml7
-rw-r--r--config/feature_flags/development/feature_flag_permissions.yml7
-rw-r--r--config/feature_flags/development/feature_flags_legacy_read_only.yml7
-rw-r--r--config/feature_flags/development/feature_flags_legacy_read_only_override.yml7
-rw-r--r--config/feature_flags/development/feature_flags_new_version.yml7
-rw-r--r--config/feature_flags/development/forti_authenticator.yml7
-rw-r--r--config/feature_flags/development/forward_deployment_enabled.yml4
-rw-r--r--config/feature_flags/development/g_compliance_dashboard_feature.yml7
-rw-r--r--config/feature_flags/development/generic_packages.yml2
-rw-r--r--config/feature_flags/development/git_push_create_all_pipelines.yml6
-rw-r--r--config/feature_flags/development/gitpod.yml4
-rw-r--r--config/feature_flags/development/global_default_branch_name.yml6
-rw-r--r--config/feature_flags/development/go_proxy.yml6
-rw-r--r--config/feature_flags/development/go_proxy_disable_gomod_validation.yml6
-rw-r--r--config/feature_flags/development/graphql_board_lists.yml6
-rw-r--r--config/feature_flags/development/graphql_individual_release_page.yml7
-rw-r--r--config/feature_flags/development/graphql_lookahead_support.yml7
-rw-r--r--config/feature_flags/development/graphql_milestone_stats.yml6
-rw-r--r--config/feature_flags/development/graphql_pipeline_header.yml7
-rw-r--r--config/feature_flags/development/graphql_release_data.yml6
-rw-r--r--config/feature_flags/development/graphql_releases_page.yml7
-rw-r--r--config/feature_flags/development/group_export_ndjson.yml6
-rw-r--r--config/feature_flags/development/group_import_export.yml6
-rw-r--r--config/feature_flags/development/group_import_ndjson.yml6
-rw-r--r--config/feature_flags/development/group_level_integrations.yml2
-rw-r--r--config/feature_flags/development/help_page_documentation_redirect.yml7
-rw-r--r--config/feature_flags/development/improved_mr_merged_at_queries.yml7
-rw-r--r--config/feature_flags/development/inactive_policy_condition.yml7
-rw-r--r--config/feature_flags/development/include_lfs_blobs_in_archive.yml7
-rw-r--r--config/feature_flags/development/increased_diff_limits.yml7
-rw-r--r--config/feature_flags/development/ingress_modsecurity.yml6
-rw-r--r--config/feature_flags/development/invisible_captcha.yml6
-rw-r--r--config/feature_flags/development/invite_email_experiment.yml6
-rw-r--r--config/feature_flags/development/invite_members_group_modal.yml7
-rw-r--r--config/feature_flags/development/json_limited_encoder.yml6
-rw-r--r--config/feature_flags/development/junit_pipeline_screenshots_view.yml6
-rw-r--r--config/feature_flags/development/kubernetes_cluster_namespace_role_admin.yml7
-rw-r--r--config/feature_flags/development/limit_projects_in_groups_api.yml6
-rw-r--r--config/feature_flags/development/log_import_export_relation_creation.yml6
-rw-r--r--config/feature_flags/development/maintenance_mode.yml6
-rw-r--r--config/feature_flags/development/marginalia.yml7
-rw-r--r--config/feature_flags/development/merge_base_pipelines.yml7
-rw-r--r--config/feature_flags/development/merge_orchestration_service.yml4
-rw-r--r--config/feature_flags/development/merge_request_cached_pipeline_serializer.yml7
-rw-r--r--config/feature_flags/development/merge_request_draft_filter.yml6
-rw-r--r--config/feature_flags/development/merge_request_short_pipeline_serializer.yml7
-rw-r--r--config/feature_flags/development/merge_request_widget_graphql.yml6
-rw-r--r--config/feature_flags/development/metrics_dashboard.yml6
-rw-r--r--config/feature_flags/development/migrate_bio_to_user_details.yml7
-rw-r--r--config/feature_flags/development/migrate_user_mentions.yml4
-rw-r--r--config/feature_flags/development/modifed_path_ci_variables.yml7
-rw-r--r--config/feature_flags/development/monaco_blobs.yml7
-rw-r--r--config/feature_flags/development/monaco_ci.yml7
-rw-r--r--config/feature_flags/development/mr_commit_neighbor_nav.yml6
-rw-r--r--config/feature_flags/development/multi_select_board.yml6
-rw-r--r--config/feature_flags/development/multiline_comments.yml6
-rw-r--r--config/feature_flags/development/new_pipeline_form.yml6
-rw-r--r--config/feature_flags/development/new_pipeline_form_prefilled_vars.yml7
-rw-r--r--config/feature_flags/development/new_release_page.yml6
-rw-r--r--config/feature_flags/development/new_variables_ui.yml6
-rw-r--r--config/feature_flags/development/not_issuable_queries.yml6
-rw-r--r--config/feature_flags/development/one_dimensional_matrix.yml7
-rw-r--r--config/feature_flags/development/packages_coming_soon.yml7
-rw-r--r--config/feature_flags/development/paginated_notes.yml6
-rw-r--r--config/feature_flags/development/periodic_project_authorization_recalculation.yml7
-rw-r--r--config/feature_flags/development/phabricator_import.yml6
-rw-r--r--config/feature_flags/development/pipelines_security_report_summary.yml6
-rw-r--r--config/feature_flags/development/product_analytics.yml6
-rw-r--r--config/feature_flags/development/project_export_as_ndjson.yml6
-rw-r--r--config/feature_flags/development/project_finder_similarity_sort.yml7
-rw-r--r--config/feature_flags/development/project_import_ndjson.yml6
-rw-r--r--config/feature_flags/development/project_transactionless_destroy.yml6
-rw-r--r--config/feature_flags/development/prometheus_computed_alerts.yml6
-rw-r--r--config/feature_flags/development/push_mirror_syncs_lfs.yml7
-rw-r--r--config/feature_flags/development/reactive_caching_limit_environment.yml6
-rw-r--r--config/feature_flags/development/real_time_issue_sidebar.yml6
-rw-r--r--config/feature_flags/development/rebalance_issues.yml2
-rw-r--r--config/feature_flags/development/recursive_approach_for_all_projects.yml7
-rw-r--r--config/feature_flags/development/release_asset_link_editing.yml7
-rw-r--r--config/feature_flags/development/release_asset_link_type.yml7
-rw-r--r--config/feature_flags/development/release_evidence.yml4
-rw-r--r--config/feature_flags/development/release_evidence_collection.yml7
-rw-r--r--config/feature_flags/development/release_issue_summary.yml7
-rw-r--r--config/feature_flags/development/release_mr_issue_urls.yml6
-rw-r--r--config/feature_flags/development/release_show_page.yml7
-rw-r--r--config/feature_flags/development/remove_legacy_github_client.yml6
-rw-r--r--config/feature_flags/development/repack_after_shard_migration.yml6
-rw-r--r--config/feature_flags/development/resource_access_token.yml7
-rw-r--r--config/feature_flags/development/safezip_use_rubyzip.yml7
-rw-r--r--config/feature_flags/development/save_raw_usage_data.yml6
-rw-r--r--config/feature_flags/development/schema_linting.yml6
-rw-r--r--config/feature_flags/development/search_filter_by_confidential.yml7
-rw-r--r--config/feature_flags/development/security_auto_fix.yml7
-rw-r--r--config/feature_flags/development/serverless_domain.yml4
-rw-r--r--config/feature_flags/development/service_desk_custom_address.yml2
-rw-r--r--config/feature_flags/development/settings_operations_prometheus_service.yml6
-rw-r--r--config/feature_flags/development/show_contributor_on_note.yml7
-rw-r--r--config/feature_flags/development/show_inherited_labels.yml7
-rw-r--r--config/feature_flags/development/similarity_search.yml6
-rw-r--r--config/feature_flags/development/snippet_multiple_files.yml7
-rw-r--r--config/feature_flags/development/snippet_spam.yml7
-rw-r--r--config/feature_flags/development/snippets_binary_blob.yml6
-rw-r--r--config/feature_flags/development/snippets_edit_vue.yml7
-rw-r--r--config/feature_flags/development/snippets_vue.yml7
-rw-r--r--config/feature_flags/development/soft_email_confirmation.yml6
-rw-r--r--config/feature_flags/development/soft_fail_count_by_state.yml7
-rw-r--r--config/feature_flags/development/specialized_project_authorization_project_share_worker.yml6
-rw-r--r--config/feature_flags/development/specialized_project_authorization_workers.yml6
-rw-r--r--config/feature_flags/development/sql-set-operators.yml7
-rw-r--r--config/feature_flags/development/sql_set_operators.yml6
-rw-r--r--config/feature_flags/development/store_ci_pipeline_counts_by_status.yml7
-rw-r--r--config/feature_flags/development/store_instance_statistics_measurements.yml7
-rw-r--r--config/feature_flags/development/store_mentioned_users_to_db.yml7
-rw-r--r--config/feature_flags/development/suggest_pipeline.yml7
-rw-r--r--config/feature_flags/development/sync_metrics_dashboards.yml7
-rw-r--r--config/feature_flags/development/track_issue_activity_actions.yml4
-rw-r--r--config/feature_flags/development/track_resource_state_change_events.yml7
-rw-r--r--config/feature_flags/development/track_unique_test_cases_parsed.yml7
-rw-r--r--config/feature_flags/development/track_unique_visits.yml6
-rw-r--r--config/feature_flags/development/track_unique_wiki_page_views.yml7
-rw-r--r--config/feature_flags/development/tribute_autocomplete.yml6
-rw-r--r--config/feature_flags/development/two_factor_for_cli.yml7
-rw-r--r--config/feature_flags/development/unified_diff_lines.yml2
-rw-r--r--config/feature_flags/development/upload_middleware_jwt_params_handler.yml2
-rw-r--r--config/feature_flags/development/usage_data_a_compliance_audit_events_api.yml7
-rw-r--r--config/feature_flags/development/usage_data_api.yml6
-rw-r--r--config/feature_flags/development/usage_data_g_compliance_dashboard.yml6
-rw-r--r--config/feature_flags/development/usage_data_i_source_code_code_intelligence.yml7
-rw-r--r--config/feature_flags/development/usage_data_i_testing_test_case_parsed.yml7
-rw-r--r--config/feature_flags/development/usage_data_incident_management_alert_assigned.yml6
-rw-r--r--config/feature_flags/development/usage_data_incident_management_alert_status_changed.yml6
-rw-r--r--config/feature_flags/development/usage_data_incident_management_alert_todo.yml6
-rw-r--r--config/feature_flags/development/usage_data_incident_management_incident_assigned.yml6
-rw-r--r--config/feature_flags/development/usage_data_incident_management_incident_change_confidential.yml6
-rw-r--r--config/feature_flags/development/usage_data_incident_management_incident_closed.yml6
-rw-r--r--config/feature_flags/development/usage_data_incident_management_incident_comment.yml6
-rw-r--r--config/feature_flags/development/usage_data_incident_management_incident_created.yml6
-rw-r--r--config/feature_flags/development/usage_data_incident_management_incident_relate.yml6
-rw-r--r--config/feature_flags/development/usage_data_incident_management_incident_reopened.yml6
-rw-r--r--config/feature_flags/development/usage_data_incident_management_incident_todo.yml6
-rw-r--r--config/feature_flags/development/usage_data_incident_management_incident_unrelate.yml6
-rw-r--r--config/feature_flags/development/usage_data_incident_management_incident_zoom_meeting.yml6
-rw-r--r--config/feature_flags/development/users_search.yml7
-rw-r--r--config/feature_flags/development/validate_import_decompressed_archive_size.yml6
-rw-r--r--config/feature_flags/development/view_diffs_file_by_file.yml6
-rw-r--r--config/feature_flags/development/vue_issuable_sidebar.yml6
-rw-r--r--config/feature_flags/development/vue_issuables_list.yml6
-rw-r--r--config/feature_flags/development/web_ide_primary_edit.yml4
-rw-r--r--config/feature_flags/development/webperf_experiment.yml6
-rw-r--r--config/feature_flags/development/whats_new_drawer.yml6
-rw-r--r--config/feature_flags/development/widget_visibility_polling.yml6
-rw-r--r--config/feature_flags/development/wiki_events_on_git_push.yml7
-rw-r--r--config/feature_flags/development/zip_pages_deployments.yml7
-rw-r--r--config/feature_flags/licensed/incident_sla.yml7
-rw-r--r--config/feature_flags/licensed/minimal_access_role.yml7
-rw-r--r--config/feature_flags/licensed/resource_access_token.yml7
-rw-r--r--config/feature_flags/ops/api_kaminari_count_with_limit.yml7
-rw-r--r--config/feature_flags/ops/ci_accept_trace.yml4
-rw-r--r--config/feature_flags/ops/ci_trace_log_invalid_chunks.yml7
-rw-r--r--config/feature_flags/ops/database_reindexing.yml7
-rw-r--r--config/feature_flags/ops/gitlab_sidekiq_enable_semi_reliable_fetcher.yml7
-rw-r--r--config/feature_flags/ops/gitlab_sidekiq_reliable_fetcher.yml7
-rw-r--r--config/feature_flags/ops/marginalia.yml7
-rw-r--r--config/gitlab.yml.example40
-rw-r--r--config/initializers/0_license.rb3
-rw-r--r--config/initializers/0_marginalia.rb2
-rw-r--r--config/initializers/1_settings.rb29
-rw-r--r--config/initializers/7_prometheus_metrics.rb4
-rw-r--r--config/initializers/database_config.rb19
-rw-r--r--config/initializers/forbid_sidekiq_in_transactions.rb2
-rw-r--r--config/initializers/lograge.rb54
-rw-r--r--config/initializers/rails_host_authorization_gitpod.rb6
-rw-r--r--config/initializers/sidekiq.rb4
-rw-r--r--config/initializers/sprockets.rb1
-rw-r--r--config/initializers/stackprof.rb65
-rw-r--r--config/initializers/static_files.rb36
-rw-r--r--config/initializers/webauthn.rb2
-rw-r--r--config/initializers_before_autoloader/000_inflections.rb4
-rw-r--r--config/locales/devise.en.yml4
-rw-r--r--config/locales/en.yml2
-rw-r--r--config/object_store_settings.rb20
-rw-r--r--config/redis.cache.yml.example2
-rw-r--r--config/redis.queues.yml.example2
-rw-r--r--config/redis.shared_state.yml.example2
-rw-r--r--config/resque.yml.example2
-rw-r--r--config/routes.rb17
-rw-r--r--config/routes/admin.rb6
-rw-r--r--config/routes/group.rb5
-rw-r--r--config/routes/import.rb5
-rw-r--r--config/routes/jira_connect.rb1
-rw-r--r--config/routes/pipelines.rb1
-rw-r--r--config/routes/project.rb16
-rw-r--r--config/routes/snippets.rb2
-rw-r--r--config/sidekiq_queues.yml24
-rw-r--r--config/webpack.config.js13
-rw-r--r--danger/ci_templates/Dangerfile30
-rw-r--r--danger/documentation/Dangerfile3
-rw-r--r--danger/metadata/Dangerfile7
-rw-r--r--danger/pajamas/Dangerfile65
-rw-r--r--danger/product_analytics/Dangerfile48
-rw-r--r--danger/specialization_labels/Dangerfile3
-rw-r--r--danger/telemetry/Dangerfile38
-rw-r--r--data/whats_new/202008180001_12_10.yml4
-rw-r--r--data/whats_new/202009300001_13_04.yml61
-rw-r--r--db/fixtures/development/29_instance_statistics.rb26
-rw-r--r--db/migrate/20200123090839_remove_analytics_repository_table_fks_on_projects.rb26
-rw-r--r--db/migrate/20200123091422_remove_analytics_repository_files_fk_on_other_analytics_tables.rb19
-rw-r--r--db/migrate/20200226100624_requirements_add_project_fk.rb2
-rw-r--r--db/migrate/20200226100634_requirements_add_author_fk.rb2
-rw-r--r--db/migrate/20200304121828_add_ci_sources_project_pipeline_foreign_key.rb2
-rw-r--r--db/migrate/20200304121844_add_ci_sources_project_source_project_foreign_key.rb2
-rw-r--r--db/migrate/20200316173312_add_vulnerability_export_project_foreign_key.rb2
-rw-r--r--db/migrate/20200317142110_add_vulnerability_export_user_foreign_key.rb2
-rw-r--r--db/migrate/20200326124443_add_projects_fk_to_jira_imports_table.rb2
-rw-r--r--db/migrate/20200326134443_add_users_fk_to_jira_imports_table.rb2
-rw-r--r--db/migrate/20200326144443_add_labels_fk_to_jira_imports_table.rb2
-rw-r--r--db/migrate/20200416120354_add_locked_by_user_id_foreign_key_to_terraform_state.rb2
-rw-r--r--db/migrate/20200423075720_add_user_id_foreign_key_to_resource_state_events.rb2
-rw-r--r--db/migrate/20200423080334_add_issue_id_foreign_key_to_resource_state_events.rb2
-rw-r--r--db/migrate/20200423080607_add_merge_request_id_foreign_key_to_resource_state_events.rb2
-rw-r--r--db/migrate/20200429015603_add_fk_to_project_repository_storage_moves.rb2
-rw-r--r--db/migrate/20200510183128_add_foreign_key_from_webauthn_registrations_to_users.rb2
-rw-r--r--db/migrate/20200511092505_add_foreign_key_to_epic_id_on_resource_state_events.rb2
-rw-r--r--db/migrate/20200511121549_add_group_wiki_repositories_shard_id_foreign_key.rb2
-rw-r--r--db/migrate/20200511121610_add_group_wiki_repositories_group_id_foreign_key.rb2
-rw-r--r--db/migrate/20200511191027_add_author_foreign_key_to_test_reports.rb2
-rw-r--r--db/migrate/20200511208012_add_pipeline_foreign_key_to_test_reports.rb2
-rw-r--r--db/migrate/20200521225337_add_foreign_key_to_user_id_on_alert_management_alert_assignees.rb2
-rw-r--r--db/migrate/20200521225346_add_foreign_key_to_alert_id_on_alert_mangagement_alert_assignees.rb2
-rw-r--r--db/migrate/20200526164947_add_foreign_key_to_ops_feature_flags_issues.rb2
-rw-r--r--db/migrate/20200527135313_add_requirements_build_reference.rb2
-rw-r--r--db/migrate/20200527152116_add_foreign_key_to_build_id_on_build_report_results.rb2
-rw-r--r--db/migrate/20200527152657_add_foreign_key_to_project_id_on_build_report_results.rb2
-rw-r--r--db/migrate/20200604174544_add_users_foreign_key_to_board_user_preferences.rb2
-rw-r--r--db/migrate/20200604174558_add_boards_foreign_key_to_board_user_preferences.rb2
-rw-r--r--db/migrate/20200605003204_add_foreign_key_to_alert_management_alert_user_mentions.rb2
-rw-r--r--db/migrate/20200623073431_add_source_merge_request_id_to_resource_state_events.rb2
-rw-r--r--db/migrate/20200722132040_add_users_fk_to_resource_iteration_events_table.rb2
-rw-r--r--db/migrate/20200722132540_add_issues_fk_to_resource_iteration_events_table.rb2
-rw-r--r--db/migrate/20200722133040_add_merge_requests_fk_to_resource_iteration_events_table.rb2
-rw-r--r--db/migrate/20200722133540_add_iterations_fk_to_resource_iteration_events_table.rb2
-rw-r--r--db/migrate/20200731201408_add_foreign_key_to_experiment_on_experiment_users.rb2
-rw-r--r--db/migrate/20200731201834_add_foreign_key_to_user_on_experiment_users.rb2
-rw-r--r--db/migrate/20200805151001_add_foreign_key_to_pipeline_id_on_pipeline_artifact.rb2
-rw-r--r--db/migrate/20200805151726_add_foreign_key_to_project_id_on_pipeline_artifact.rb2
-rw-r--r--db/migrate/20200813135558_create_ci_deleted_objects.rb29
-rw-r--r--db/migrate/20200817195628_add_modified_to_approval_merge_request_rule.rb9
-rw-r--r--db/migrate/20200825081035_boards_epic_user_preferences_fk_board.rb2
-rw-r--r--db/migrate/20200825081045_boards_epic_user_preferences_fk_user.rb2
-rw-r--r--db/migrate/20200825081055_boards_epic_user_preferences_fk_epic.rb2
-rw-r--r--db/migrate/20200827060911_add_merge_request_foreign_key_to_merge_request_reviewers.rb2
-rw-r--r--db/migrate/20200827060932_add_user_foreign_key_to_merge_request_reviewers.rb2
-rw-r--r--db/migrate/20200828155134_add_foreign_key_on_scan_id_to_security_scans.rb2
-rw-r--r--db/migrate/20200828155205_add_foreign_key_on_scanner_id_to_vulnerability_scanners.rb2
-rw-r--r--db/migrate/20200905013247_add_golang_package_max_file_size_to_plan_limits.rb9
-rw-r--r--db/migrate/20200907092610_add_user_id_to_group_import_states.rb26
-rw-r--r--db/migrate/20200908094810_add_new_setting_to_namespace_setting.rb19
-rw-r--r--db/migrate/20200909040555_create_package_events.rb19
-rw-r--r--db/migrate/20200909083339_add_change_reviewer_merge_request_to_notification_settings.rb9
-rw-r--r--db/migrate/20200911121027_add_pages_deployment_project_foreign_key.rb2
-rw-r--r--db/migrate/20200911121048_add_pages_deployment_ci_build_foreign_key.rb2
-rw-r--r--db/migrate/20200912152943_rename_admin_notification_email_application_setting.rb17
-rw-r--r--db/migrate/20200912193210_add_scheduling_issues_temp_indexes.rb21
-rw-r--r--db/migrate/20200914070140_add_expiration_policy_started_at_to_container_repositories.rb13
-rw-r--r--db/migrate/20200915134004_add_indices_to_approval_project_rules.rb25
-rw-r--r--db/migrate/20200916135044_add_state_id_index_to_merge_requests.rb17
-rw-r--r--db/migrate/20200916151442_add_result_index_to_authentication_events.rb18
-rw-r--r--db/migrate/20200916165232_add_debian_max_file_size_to_plan_limits.rb9
-rw-r--r--db/migrate/20200917121650_add_help_page_documentation_url_to_application_settings.rb12
-rw-r--r--db/migrate/20200919200318_add_default_branch_name_to_namespace_settings.rb15
-rw-r--r--db/migrate/20200919204155_add_text_limit_to_namespace_settings_default_branch_name.rb19
-rw-r--r--db/migrate/20200921093826_add_index_to_user_preferences.rb17
-rw-r--r--db/migrate/20200921113722_add_text_limit_to_help_page_documentation_url.rb16
-rw-r--r--db/migrate/20200921130028_add_pages_deployment_id_to_pages_metadata.rb9
-rw-r--r--db/migrate/20200921131313_add_foreign_key_to_pages_deployment_id_in_project_pages_metadata.rb20
-rw-r--r--db/migrate/20200921203231_remove_duplicate_cluster_agents_index.rb18
-rw-r--r--db/migrate/20200922052316_create_issue_email_participants.rb32
-rw-r--r--db/migrate/20200922075244_add_compliance_framework_model.rb32
-rw-r--r--db/migrate/20200922093004_add_postgres_index_view.rb33
-rw-r--r--db/migrate/20200922133949_create_bulk_import.rb26
-rw-r--r--db/migrate/20200923071622_add_description_to_requirements.rb15
-rw-r--r--db/migrate/20200923071644_add_text_limit_to_requirements_description.rb17
-rw-r--r--db/migrate/20200923102312_update_programming_language_colors.rb21
-rw-r--r--db/migrate/20200923130057_remove_tmp_container_scanning_index.rb20
-rw-r--r--db/migrate/20200923140404_add_postgres_reindex_actions_table.rb26
-rw-r--r--db/migrate/20200924035825_add_options_to_dast_scanner_profile.rb13
-rw-r--r--db/migrate/20200925112104_create_bulk_import_configurations.rb27
-rw-r--r--db/migrate/20200925114522_create_bulk_import_entities.rb38
-rw-r--r--db/migrate/20200925125321_add_u2f_id_to_webauthn_registration.rb11
-rw-r--r--db/migrate/20200925153423_add_bulk_import_foreign_key_to_bulk_import_entities.rb17
-rw-r--r--db/migrate/20200925193815_add_parent_foreign_key_to_bulk_import_entities.rb17
-rw-r--r--db/migrate/20200925193906_add_namespace_foreign_key_to_bulk_import_entities.rb19
-rw-r--r--db/migrate/20200925194006_add_project_foreign_key_to_bulk_import_entities.rb19
-rw-r--r--db/migrate/20200927224750_add_incident_issue_type_index_to_issues.rb20
-rw-r--r--db/migrate/20200928095732_add_state_to_dast_site_validation.rb12
-rw-r--r--db/migrate/20200928100408_add_text_limit_to_dast_site_validation_state.rb17
-rw-r--r--db/migrate/20200928125258_add_foreign_key_to_u2f_reg_id_in_webauthn_regs.rb20
-rw-r--r--db/migrate/20200928131934_create_required_code_owners_sections.rb26
-rw-r--r--db/migrate/20200928164807_add_index_on_vulnerabilities_state_case.rb21
-rw-r--r--db/migrate/20200928203531_create_alert_management_http_integrations.rb37
-rw-r--r--db/migrate/20200928210524_add_http_integrations_project_foreign_key.rb19
-rw-r--r--db/migrate/20200928233632_remove_terraform_state_verification_indexes.rb21
-rw-r--r--db/migrate/20200929032729_add_sla_minutes_to_project_incident_management_settings.rb10
-rw-r--r--db/migrate/20200929063159_add_require_admin_approval_after_user_signup_to_application_settings.rb9
-rw-r--r--db/migrate/20200930094812_update_postgres_indexes_view.rb54
-rw-r--r--db/migrate/20200930131343_add_index_on_project_id_and_sha_to_deployments.rb20
-rw-r--r--db/migrate/20200930132319_add_api_fuzzing_to_plan_limits.rb9
-rw-r--r--db/migrate/20201002012659_add_issuable_sla_table.rb12
-rw-r--r--db/migrate/20201004163918_remove_project_id_and_id_index_from_vulnerabilities_table.rb17
-rw-r--r--db/migrate/20201005092703_add_namespace_column_to_frameworks.rb26
-rw-r--r--db/migrate/20201005092709_remove_compliance_frameworks_group_id_fk.rb39
-rw-r--r--db/migrate/20201005092753_add_framework_id_to_project_framework_settings.rb34
-rw-r--r--db/migrate/20201006014605_add_automatic_purchased_storage_allocation_to_application_settings.rb9
-rw-r--r--db/migrate/20201007115209_add_lock_version_to_ci_build_trace_chunk.rb9
-rw-r--r--db/migrate/20201009090954_add_index_with_project_id_to_container_expiration_policies.rb19
-rw-r--r--db/migrate/20201012194936_create_saml_group_links.rb30
-rw-r--r--db/migrate/20201014205300_drop_backfill_jira_tracker_deployment_type_jobs.rb25
-rw-r--r--db/post_migrate/20190926180443_schedule_epic_issues_after_epics_move.rb2
-rw-r--r--db/post_migrate/20200511083541_cleanup_projects_with_missing_namespace.rb2
-rw-r--r--db/post_migrate/20200810191256_remove_pipeline_id_from_test_reports.rb2
-rw-r--r--db/post_migrate/20200901170135_backfill_modified_column_for_approval_merge_request_rules.rb17
-rw-r--r--db/post_migrate/20200907092715_add_not_null_constraint_to_user_on_group_import_states.rb17
-rw-r--r--db/post_migrate/20200908064229_add_partial_index_to_ci_builds_table_on_user_id_name.rb37
-rw-r--r--db/post_migrate/20200909161624_cleanup_group_import_states_with_null_user_id.rb80
-rw-r--r--db/post_migrate/20200910155617_backfill_jira_tracker_deployment_type.rb19
-rw-r--r--db/post_migrate/20200912153218_cleanup_admin_notification_email_application_setting_rename.rb17
-rw-r--r--db/post_migrate/20200915185707_ensure_filled_file_store_on_package_files.rb33
-rw-r--r--db/post_migrate/20200915191156_validate_not_null_file_store_on_package_files.rb21
-rw-r--r--db/post_migrate/20200917135802_remove_duplicated_cs_findings_without_vulnerability_id.rb30
-rw-r--r--db/post_migrate/20200917165525_update_index_on_namespaces_for_type_and_id.rb23
-rw-r--r--db/post_migrate/20200922054642_drop_snowplow_iglu_registry_url_from_application_settings.rb9
-rw-r--r--db/post_migrate/20200922095954_remove_instance_statistics_visibility_private_from_application_settings.rb13
-rw-r--r--db/post_migrate/20200922170907_change_index_on_pipeline_status.rb21
-rw-r--r--db/post_migrate/20200922231755_remove_created_by_user_id_from_cluster_providers_aws.rb26
-rw-r--r--db/post_migrate/20200929052138_create_initial_versions_for_pre_versioning_terraform_states.rb18
-rw-r--r--db/post_migrate/20200929113254_remove_type_from_audit_events.rb125
-rw-r--r--db/post_migrate/20200929114107_schedule_migrate_u2f_webauthn.rb31
-rw-r--r--db/post_migrate/20200930144340_set_job_waiter_ttl.rb31
-rw-r--r--db/post_migrate/20201001022100_validate_designs_filename_text_limit.rb16
-rw-r--r--db/post_migrate/20201001101136_remove_index_on_issues_relative_position.rb18
-rw-r--r--db/post_migrate/20201002094617_remove_container_scanning_report_type_index.rb24
-rw-r--r--db/post_migrate/20201002175953_add_index_for_merged_merge_requests.rb21
-rw-r--r--db/post_migrate/20201005094331_migrate_compliance_framework_enum_to_database_framework_record.rb104
-rw-r--r--db/post_migrate/20201005153955_add_not_null_constraint_to_compliance_project_settings.rb21
-rw-r--r--db/post_migrate/20201014142521_schedule_sync_blocking_issues_count.rb46
-rw-r--r--db/post_migrate/20201015073808_schedule_blocked_by_links_replacement.rb30
-rw-r--r--db/post_migrate/20201015154527_add_index_on_services_for_usage_data.rb18
-rw-r--r--db/schema_migrations/202008131355581
-rw-r--r--db/schema_migrations/202008171956281
-rw-r--r--db/schema_migrations/202009011701351
-rw-r--r--db/schema_migrations/202009050132471
-rw-r--r--db/schema_migrations/202009070926101
-rw-r--r--db/schema_migrations/202009070927151
-rw-r--r--db/schema_migrations/202009080642291
-rw-r--r--db/schema_migrations/202009080948101
-rw-r--r--db/schema_migrations/202009090405551
-rw-r--r--db/schema_migrations/202009090833391
-rw-r--r--db/schema_migrations/202009091616241
-rw-r--r--db/schema_migrations/202009101556171
-rw-r--r--db/schema_migrations/202009121529431
-rw-r--r--db/schema_migrations/202009121532181
-rw-r--r--db/schema_migrations/202009121932101
-rw-r--r--db/schema_migrations/202009140701401
-rw-r--r--db/schema_migrations/202009151340041
-rw-r--r--db/schema_migrations/202009151857071
-rw-r--r--db/schema_migrations/202009151911561
-rw-r--r--db/schema_migrations/202009161350441
-rw-r--r--db/schema_migrations/202009161514421
-rw-r--r--db/schema_migrations/202009161652321
-rw-r--r--db/schema_migrations/202009171216501
-rw-r--r--db/schema_migrations/202009171358021
-rw-r--r--db/schema_migrations/202009171655251
-rw-r--r--db/schema_migrations/202009192003181
-rw-r--r--db/schema_migrations/202009192041551
-rw-r--r--db/schema_migrations/202009210938261
-rw-r--r--db/schema_migrations/202009211137221
-rw-r--r--db/schema_migrations/202009211300281
-rw-r--r--db/schema_migrations/202009211313131
-rw-r--r--db/schema_migrations/202009212032311
-rw-r--r--db/schema_migrations/202009220523161
-rw-r--r--db/schema_migrations/202009220546421
-rw-r--r--db/schema_migrations/202009220752441
-rw-r--r--db/schema_migrations/202009220930041
-rw-r--r--db/schema_migrations/202009220959541
-rw-r--r--db/schema_migrations/202009221339491
-rw-r--r--db/schema_migrations/202009221709071
-rw-r--r--db/schema_migrations/202009222317551
-rw-r--r--db/schema_migrations/202009230716221
-rw-r--r--db/schema_migrations/202009230716441
-rw-r--r--db/schema_migrations/202009231023121
-rw-r--r--db/schema_migrations/202009231300571
-rw-r--r--db/schema_migrations/202009231404041
-rw-r--r--db/schema_migrations/202009240358251
-rw-r--r--db/schema_migrations/202009251121041
-rw-r--r--db/schema_migrations/202009251145221
-rw-r--r--db/schema_migrations/202009251253211
-rw-r--r--db/schema_migrations/202009251534231
-rw-r--r--db/schema_migrations/202009251938151
-rw-r--r--db/schema_migrations/202009251939061
-rw-r--r--db/schema_migrations/202009251940061
-rw-r--r--db/schema_migrations/202009272247501
-rw-r--r--db/schema_migrations/202009280957321
-rw-r--r--db/schema_migrations/202009281004081
-rw-r--r--db/schema_migrations/202009281252581
-rw-r--r--db/schema_migrations/202009281319341
-rw-r--r--db/schema_migrations/202009281648071
-rw-r--r--db/schema_migrations/202009282035311
-rw-r--r--db/schema_migrations/202009282105241
-rw-r--r--db/schema_migrations/202009282336321
-rw-r--r--db/schema_migrations/202009290327291
-rw-r--r--db/schema_migrations/202009290521381
-rw-r--r--db/schema_migrations/202009290631591
-rw-r--r--db/schema_migrations/202009291132541
-rw-r--r--db/schema_migrations/202009291141071
-rw-r--r--db/schema_migrations/202009300948121
-rw-r--r--db/schema_migrations/202009301313431
-rw-r--r--db/schema_migrations/202009301323191
-rw-r--r--db/schema_migrations/202009301443401
-rw-r--r--db/schema_migrations/202010010221001
-rw-r--r--db/schema_migrations/202010011011361
-rw-r--r--db/schema_migrations/202010020126591
-rw-r--r--db/schema_migrations/202010020946171
-rw-r--r--db/schema_migrations/202010021759531
-rw-r--r--db/schema_migrations/202010041639181
-rw-r--r--db/schema_migrations/202010050927031
-rw-r--r--db/schema_migrations/202010050927091
-rw-r--r--db/schema_migrations/202010050927531
-rw-r--r--db/schema_migrations/202010050943311
-rw-r--r--db/schema_migrations/202010051539551
-rw-r--r--db/schema_migrations/202010060146051
-rw-r--r--db/schema_migrations/202010071152091
-rw-r--r--db/schema_migrations/202010090909541
-rw-r--r--db/schema_migrations/202010121949361
-rw-r--r--db/schema_migrations/202010141425211
-rw-r--r--db/schema_migrations/202010142053001
-rw-r--r--db/schema_migrations/202010150738081
-rw-r--r--db/schema_migrations/202010151545271
-rw-r--r--db/structure.sql527
-rw-r--r--doc/.vale/gitlab/Acronyms.yml2
-rw-r--r--doc/.vale/gitlab/Admin.yml13
-rw-r--r--doc/.vale/gitlab/InclusionAbleism.yml14
-rw-r--r--doc/.vale/gitlab/InclusionCultural.yml16
-rw-r--r--doc/.vale/gitlab/InclusionGender.yml18
-rw-r--r--doc/.vale/gitlab/OutdatedVersions.yml2
-rw-r--r--doc/.vale/gitlab/SubstitutionWarning.yml3
-rw-r--r--doc/.vale/gitlab/Substitutions.yml1
-rw-r--r--doc/.vale/gitlab/spelling-exceptions.txt24
-rw-r--r--doc/README.md14
-rw-r--r--doc/administration/audit_events.md9
-rw-r--r--doc/administration/auditor_users.md79
-rw-r--r--doc/administration/auth/README.md2
-rw-r--r--doc/administration/auth/ldap/index.md42
-rw-r--r--doc/administration/auth/ldap/ldap-troubleshooting.md2
-rw-r--r--doc/administration/auth/smartcard.md3
-rw-r--r--doc/administration/compliance.md6
-rw-r--r--doc/administration/consul.md3
-rw-r--r--doc/administration/database_load_balancing.md10
-rw-r--r--doc/administration/environment_variables.md92
-rw-r--r--doc/administration/feature_flags.md20
-rw-r--r--doc/administration/geo/disaster_recovery/index.md35
-rw-r--r--doc/administration/geo/disaster_recovery/planned_failover.md2
-rw-r--r--doc/administration/geo/disaster_recovery/promotion_runbook.md268
-rw-r--r--doc/administration/geo/disaster_recovery/runbooks/planned_failover_multi_node.md274
-rw-r--r--doc/administration/geo/disaster_recovery/runbooks/planned_failover_single_node.md269
-rw-r--r--doc/administration/geo/index.md14
-rw-r--r--doc/administration/geo/replication/datatypes.md119
-rw-r--r--doc/administration/geo/replication/disable_geo.md2
-rw-r--r--doc/administration/geo/replication/faq.md4
-rw-r--r--doc/administration/geo/replication/geo_validation_tests.md17
-rw-r--r--doc/administration/geo/replication/img/geo-ha-diagram.png (renamed from doc/administration/high_availability/img/geo-ha-diagram.png)bin43826 -> 43826 bytes
-rw-r--r--doc/administration/geo/replication/multiple_servers.md5
-rw-r--r--doc/administration/geo/replication/troubleshooting.md57
-rw-r--r--doc/administration/geo/replication/updating_the_geo_nodes.md7
-rw-r--r--doc/administration/geo/replication/version_specific_updates.md12
-rw-r--r--doc/administration/geo/setup/database.md12
-rw-r--r--doc/administration/gitaly/index.md71
-rw-r--r--doc/administration/gitaly/praefect.md25
-rw-r--r--doc/administration/gitaly/reference.md4
-rw-r--r--doc/administration/high_availability/README.md7
-rw-r--r--doc/administration/high_availability/alpha_database.md5
-rw-r--r--doc/administration/high_availability/consul.md5
-rw-r--r--doc/administration/high_availability/database.md5
-rw-r--r--doc/administration/high_availability/gitaly.md5
-rw-r--r--doc/administration/high_availability/gitlab.md5
-rw-r--r--doc/administration/high_availability/img/fully-distributed.pngbin46691 -> 0 bytes
-rw-r--r--doc/administration/high_availability/img/horizontal.pngbin18179 -> 0 bytes
-rw-r--r--doc/administration/high_availability/img/hybrid.pngbin20693 -> 0 bytes
-rw-r--r--doc/administration/high_availability/load_balancer.md5
-rw-r--r--doc/administration/high_availability/monitoring_node.md5
-rw-r--r--doc/administration/high_availability/nfs.md5
-rw-r--r--doc/administration/high_availability/nfs_host_client_setup.md5
-rw-r--r--doc/administration/high_availability/object_storage.md5
-rw-r--r--doc/administration/high_availability/pgbouncer.md5
-rw-r--r--doc/administration/high_availability/redis.md5
-rw-r--r--doc/administration/high_availability/redis_source.md5
-rw-r--r--doc/administration/high_availability/sidekiq.md5
-rw-r--r--doc/administration/housekeeping.md9
-rw-r--r--doc/administration/img/export_audit_log_v13_4.pngbin127518 -> 46643 bytes
-rw-r--r--doc/administration/incoming_email.md10
-rw-r--r--doc/administration/index.md30
-rw-r--r--doc/administration/instance_limits.md38
-rw-r--r--doc/administration/instance_review.md22
-rw-r--r--doc/administration/integration/plantuml.md2
-rw-r--r--doc/administration/integration/terminal.md6
-rw-r--r--doc/administration/job_artifacts.md31
-rw-r--r--doc/administration/job_logs.md9
-rw-r--r--doc/administration/lfs/index.md10
-rw-r--r--doc/administration/libravatar.md14
-rw-r--r--doc/administration/load_balancer.md3
-rw-r--r--doc/administration/logs.md40
-rw-r--r--doc/administration/merge_request_diffs.md45
-rw-r--r--doc/administration/monitoring/github_imports.md2
-rw-r--r--doc/administration/monitoring/gitlab_self_monitoring_project/index.md26
-rw-r--r--doc/administration/monitoring/index.md2
-rw-r--r--doc/administration/monitoring/ip_whitelist.md2
-rw-r--r--doc/administration/monitoring/performance/gitlab_configuration.md2
-rw-r--r--doc/administration/monitoring/performance/grafana_configuration.md4
-rw-r--r--doc/administration/monitoring/performance/img/performance_bar.pngbin21503 -> 9926 bytes
-rw-r--r--doc/administration/monitoring/performance/img/performance_bar_sql_queries.pngbin143074 -> 139550 bytes
-rw-r--r--doc/administration/monitoring/performance/index.md4
-rw-r--r--doc/administration/monitoring/performance/performance_bar.md4
-rw-r--r--doc/administration/monitoring/performance/request_profiling.md3
-rw-r--r--doc/administration/monitoring/prometheus/gitlab_exporter.md2
-rw-r--r--doc/administration/monitoring/prometheus/gitlab_metrics.md25
-rw-r--r--doc/administration/monitoring/prometheus/index.md13
-rw-r--r--doc/administration/monitoring/prometheus/node_exporter.md4
-rw-r--r--doc/administration/monitoring/prometheus/pgbouncer_exporter.md4
-rw-r--r--doc/administration/monitoring/prometheus/postgres_exporter.md5
-rw-r--r--doc/administration/monitoring/prometheus/redis_exporter.md4
-rw-r--r--doc/administration/monitoring/prometheus/registry_exporter.md2
-rw-r--r--doc/administration/nfs.md44
-rw-r--r--doc/administration/object_storage.md21
-rw-r--r--doc/administration/operations/cleaning_up_redis_sessions.md6
-rw-r--r--doc/administration/operations/extra_sidekiq_processes.md6
-rw-r--r--doc/administration/operations/fast_ssh_key_lookup.md7
-rw-r--r--doc/administration/operations/filesystem_benchmarking.md6
-rw-r--r--doc/administration/operations/index.md6
-rw-r--r--doc/administration/operations/moving_repositories.md6
-rw-r--r--doc/administration/operations/puma.md6
-rw-r--r--doc/administration/operations/rails_console.md144
-rw-r--r--doc/administration/operations/sidekiq_memory_killer.md8
-rw-r--r--doc/administration/operations/ssh_certificates.md6
-rw-r--r--doc/administration/operations/unicorn.md6
-rw-r--r--doc/administration/packages/container_registry.md194
-rw-r--r--doc/administration/packages/dependency_proxy.md36
-rw-r--r--doc/administration/packages/index.md53
-rw-r--r--doc/administration/pages/index.md41
-rw-r--r--doc/administration/pages/source.md4
-rw-r--r--doc/administration/postgresql/external.md6
-rw-r--r--doc/administration/postgresql/index.md5
-rw-r--r--doc/administration/postgresql/pgbouncer.md32
-rw-r--r--doc/administration/postgresql/replication_and_failover.md117
-rw-r--r--doc/administration/postgresql/standalone.md14
-rw-r--r--doc/administration/raketasks/check.md31
-rw-r--r--doc/administration/raketasks/doctor.md5
-rw-r--r--doc/administration/raketasks/github_import.md5
-rw-r--r--doc/administration/raketasks/uploads/sanitize.md2
-rw-r--r--doc/administration/read_only_gitlab.md125
-rw-r--r--doc/administration/redis/replication_and_failover.md6
-rw-r--r--doc/administration/redis/replication_and_failover_external.md14
-rw-r--r--doc/administration/redis/troubleshooting.md6
-rw-r--r--doc/administration/reference_architectures/10k_users.md560
-rw-r--r--doc/administration/reference_architectures/1k_users.md28
-rw-r--r--doc/administration/reference_architectures/25k_users.md560
-rw-r--r--doc/administration/reference_architectures/2k_users.md217
-rw-r--r--doc/administration/reference_architectures/3k_users.md437
-rw-r--r--doc/administration/reference_architectures/50k_users.md560
-rw-r--r--doc/administration/reference_architectures/5k_users.md433
-rw-r--r--doc/administration/reference_architectures/index.md2
-rw-r--r--doc/administration/reply_by_email_postfix_setup.md10
-rw-r--r--doc/administration/repository_storage_types.md4
-rw-r--r--doc/administration/server_hooks.md16
-rw-r--r--doc/administration/smime_signing_email.md4
-rw-r--r--doc/administration/snippets/index.md4
-rw-r--r--doc/administration/terraform_state.md6
-rw-r--r--doc/administration/troubleshooting/debug.md24
-rw-r--r--doc/administration/troubleshooting/elasticsearch.md8
-rw-r--r--doc/administration/troubleshooting/gitlab_rails_cheat_sheet.md74
-rw-r--r--doc/administration/troubleshooting/kubernetes_cheat_sheet.md7
-rw-r--r--doc/administration/troubleshooting/log_parsing.md4
-rw-r--r--doc/administration/troubleshooting/navigating_gitlab_via_rails_console.md18
-rw-r--r--doc/administration/troubleshooting/sidekiq.md2
-rw-r--r--doc/administration/troubleshooting/ssl.md4
-rw-r--r--doc/administration/troubleshooting/tracing_correlation_id.md4
-rw-r--r--doc/administration/uploads.md37
-rw-r--r--doc/api/README.md96
-rw-r--r--doc/api/admin_sidekiq_queues.md1
-rw-r--r--doc/api/api_resources.md7
-rw-r--r--doc/api/commits.md2
-rw-r--r--doc/api/container_registry.md49
-rw-r--r--doc/api/epics.md8
-rw-r--r--doc/api/experiments.md40
-rw-r--r--doc/api/feature_flag_user_lists.md5
-rw-r--r--doc/api/feature_flags.md8
-rw-r--r--doc/api/feature_flags_legacy.md6
-rw-r--r--doc/api/geo_nodes.md16
-rw-r--r--doc/api/graphql/reference/gitlab_schema.graphql2616
-rw-r--r--doc/api/graphql/reference/gitlab_schema.json6549
-rw-r--r--doc/api/graphql/reference/index.md397
-rw-r--r--doc/api/group_clusters.md3
-rw-r--r--doc/api/group_iterations.md55
-rw-r--r--doc/api/group_milestones.md2
-rw-r--r--doc/api/group_wikis.md4
-rw-r--r--doc/api/groups.md97
-rw-r--r--doc/api/import.md4
-rw-r--r--doc/api/instance_level_ci_variables.md6
-rw-r--r--doc/api/issue_links.md22
-rw-r--r--doc/api/issues.md161
-rw-r--r--doc/api/iterations.md57
-rw-r--r--doc/api/job_artifacts.md10
-rw-r--r--doc/api/license.md4
-rw-r--r--doc/api/lint.md190
-rw-r--r--doc/api/members.md58
-rw-r--r--doc/api/merge_request_approvals.md2
-rw-r--r--doc/api/merge_requests.md12
-rw-r--r--doc/api/metrics_dashboard_annotations.md7
-rw-r--r--doc/api/metrics_user_starred_dashboards.md2
-rw-r--r--doc/api/namespaces.md26
-rw-r--r--doc/api/openapi/openapi.yaml4
-rw-r--r--doc/api/packages.md17
-rw-r--r--doc/api/personal_access_tokens.md4
-rw-r--r--doc/api/project_badges.md2
-rw-r--r--doc/api/project_clusters.md3
-rw-r--r--doc/api/project_repository_storage_moves.md2
-rw-r--r--doc/api/project_snippets.md61
-rw-r--r--doc/api/projects.md115
-rw-r--r--doc/api/protected_branches.md61
-rw-r--r--doc/api/releases/index.md17
-rw-r--r--doc/api/repositories.md3
-rw-r--r--doc/api/resource_iteration_events.md29
-rw-r--r--doc/api/runners.md47
-rw-r--r--doc/api/search.md75
-rw-r--r--doc/api/services.md4
-rw-r--r--doc/api/settings.md42
-rw-r--r--doc/api/snippets.md105
-rw-r--r--doc/api/templates/gitlab_ci_ymls.md2
-rw-r--r--doc/api/todos.md22
-rw-r--r--doc/api/users.md12
-rw-r--r--doc/api/v3_to_v4.md2
-rw-r--r--doc/api/vulnerabilities.md50
-rw-r--r--doc/api/vulnerability_exports.md22
-rw-r--r--doc/api/wikis.md2
-rw-r--r--doc/architecture/blueprints/cloud_native_build_logs/index.md141
-rw-r--r--doc/architecture/blueprints/cloud_native_gitlab_pages/index.md135
-rw-r--r--doc/architecture/blueprints/feature_flags_development/index.md140
-rw-r--r--doc/architecture/index.md9
-rw-r--r--doc/articles/artifactory_and_gitlab/index.md5
-rw-r--r--doc/articles/how_to_configure_ldap_gitlab_ce/index.md5
-rw-r--r--doc/articles/how_to_configure_ldap_gitlab_ee/index.md5
-rw-r--r--doc/articles/how_to_install_git/index.md5
-rw-r--r--doc/articles/index.md5
-rw-r--r--doc/articles/laravel_with_gitlab_and_envoy/index.md5
-rw-r--r--doc/articles/numerous_undo_possibilities_in_git/index.md5
-rw-r--r--doc/articles/openshift_and_gitlab/index.md3
-rw-r--r--doc/articles/runner_autoscale_aws/index.md5
-rw-r--r--doc/ci/README.md9
-rw-r--r--doc/ci/caching/index.md6
-rw-r--r--doc/ci/ci_cd_for_external_repos/bitbucket_integration.md2
-rw-r--r--doc/ci/ci_cd_for_external_repos/github_integration.md2
-rw-r--r--doc/ci/ci_cd_for_external_repos/index.md1
-rw-r--r--doc/ci/cloud_deployment/index.md83
-rw-r--r--doc/ci/docker/using_docker_build.md24
-rw-r--r--doc/ci/docker/using_docker_images.md38
-rw-r--r--doc/ci/docker/using_kaniko.md6
-rw-r--r--doc/ci/enable_or_disable_ci.md1
-rw-r--r--doc/ci/environments/index.md111
-rw-r--r--doc/ci/environments/protected_environments.md2
-rw-r--r--doc/ci/examples/artifactory_and_gitlab/index.md15
-rw-r--r--doc/ci/examples/authenticating-with-hashicorp-vault/index.md17
-rw-r--r--doc/ci/examples/end_to_end_testing_webdriverio/index.md9
-rw-r--r--doc/ci/examples/laravel_with_gitlab_and_envoy/index.md15
-rw-r--r--doc/ci/examples/php.md23
-rw-r--r--doc/ci/examples/test-and-deploy-ruby-application-to-heroku.md2
-rw-r--r--doc/ci/examples/test_phoenix_app_with_gitlab_ci_cd/index.md2
-rw-r--r--doc/ci/img/cf_ec2_diagram_v13_5.pngbin0 -> 43247 bytes
-rw-r--r--doc/ci/img/ci_lint.pngbin37745 -> 11525 bytes
-rw-r--r--doc/ci/img/ci_lint_dry_run.pngbin18688 -> 6811 bytes
-rw-r--r--doc/ci/img/gitlab_vault_workflow_v13_4.pngbin0 -> 47541 bytes
-rw-r--r--doc/ci/introduction/index.md4
-rw-r--r--doc/ci/merge_request_pipelines/index.md6
-rw-r--r--doc/ci/merge_request_pipelines/pipelines_for_merged_results/index.md4
-rw-r--r--doc/ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/index.md1
-rw-r--r--doc/ci/metrics_reports.md2
-rw-r--r--doc/ci/migration/jenkins.md4
-rw-r--r--doc/ci/multi_project_pipelines.md53
-rw-r--r--doc/ci/parent_child_pipelines.md44
-rw-r--r--doc/ci/pipelines/img/ci_efficiency_pipeline_dag_critical_path.pngbin124100 -> 35397 bytes
-rw-r--r--doc/ci/pipelines/img/ci_efficiency_pipeline_health_grafana_dashboard.pngbin241128 -> 55200 bytes
-rw-r--r--doc/ci/pipelines/index.md31
-rw-r--r--doc/ci/pipelines/job_artifacts.md27
-rw-r--r--doc/ci/pipelines/pipeline_artifacts.md18
-rw-r--r--doc/ci/pipelines/schedules.md5
-rw-r--r--doc/ci/pipelines/settings.md65
-rw-r--r--doc/ci/quick_start/README.md13
-rw-r--r--doc/ci/review_apps/img/toolbar_feeback_form.pngbin24599 -> 0 bytes
-rw-r--r--doc/ci/review_apps/img/toolbar_feedback_form_v13_5.pngbin0 -> 13176 bytes
-rw-r--r--doc/ci/review_apps/index.md92
-rw-r--r--doc/ci/runners/README.md30
-rw-r--r--doc/ci/secrets/index.md27
-rw-r--r--doc/ci/services/postgres.md45
-rw-r--r--doc/ci/ssh_keys/README.md6
-rw-r--r--doc/ci/triggers/README.md35
-rw-r--r--doc/ci/unit_test_reports.md15
-rw-r--r--doc/ci/variables/README.md93
-rw-r--r--doc/ci/variables/deprecated_variables.md1
-rw-r--r--doc/ci/variables/predefined_variables.md5
-rw-r--r--doc/ci/variables/where_variables_can_be_used.md12
-rw-r--r--doc/ci/yaml/README.md974
-rw-r--r--doc/ci/yaml/img/ci_config_visualization_hover_v13_5.pngbin0 -> 30986 bytes
-rw-r--r--doc/ci/yaml/img/ci_config_visualization_v13_5.pngbin0 -> 30319 bytes
-rw-r--r--doc/ci/yaml/includes.md9
-rw-r--r--doc/ci/yaml/visualization.md46
-rw-r--r--doc/container_registry/README.md5
-rw-r--r--doc/container_registry/troubleshooting.md5
-rw-r--r--doc/customization/welcome_message.md4
-rw-r--r--doc/development/README.md10
-rw-r--r--doc/development/adding_database_indexes.md6
-rw-r--r--doc/development/adding_service_component.md2
-rw-r--r--doc/development/api_graphql_styleguide.md95
-rw-r--r--doc/development/api_styleguide.md2
-rw-r--r--doc/development/architecture.md214
-rw-r--r--doc/development/background_migrations.md23
-rw-r--r--doc/development/changelog.md11
-rw-r--r--doc/development/chatops_on_gitlabcom.md4
-rw-r--r--doc/development/cicd/templates.md21
-rw-r--r--doc/development/code_review.md5
-rw-r--r--doc/development/contributing/community_roles.md6
-rw-r--r--doc/development/contributing/design.md7
-rw-r--r--doc/development/contributing/index.md7
-rw-r--r--doc/development/contributing/issue_workflow.md12
-rw-r--r--doc/development/contributing/merge_request_workflow.md9
-rw-r--r--doc/development/contributing/style_guides.md7
-rw-r--r--doc/development/database/add_foreign_key_to_existing_column.md8
-rw-r--r--doc/development/database/client_side_connection_pool.md63
-rw-r--r--doc/development/database/database_reviewer_guidelines.md6
-rw-r--r--doc/development/database/index.md9
-rw-r--r--doc/development/database/not_null_constraints.md8
-rw-r--r--doc/development/database/setting_multiple_values.md103
-rw-r--r--doc/development/database/strings_and_the_text_data_type.md6
-rw-r--r--doc/development/database/table_partitioning.md259
-rw-r--r--doc/development/database_debugging.md8
-rw-r--r--doc/development/database_query_comments.md6
-rw-r--r--doc/development/database_review.md12
-rw-r--r--doc/development/db_dump.md6
-rw-r--r--doc/development/distributed_tracing.md7
-rw-r--r--doc/development/documentation/feature_flags.md4
-rw-r--r--doc/development/documentation/graphql_styleguide.md92
-rw-r--r--doc/development/documentation/index.md80
-rw-r--r--doc/development/documentation/restful_api_styleguide.md180
-rw-r--r--doc/development/documentation/site_architecture/global_nav.md5
-rw-r--r--doc/development/documentation/site_architecture/release_process.md5
-rw-r--r--doc/development/documentation/styleguide.md390
-rw-r--r--doc/development/elasticsearch.md2
-rw-r--r--doc/development/emails.md2
-rw-r--r--doc/development/event_tracking/backend.md4
-rw-r--r--doc/development/event_tracking/frontend.md4
-rw-r--r--doc/development/event_tracking/index.md4
-rw-r--r--doc/development/experiment_guide/index.md141
-rw-r--r--doc/development/fe_guide/architecture.md4
-rw-r--r--doc/development/fe_guide/dependencies.md6
-rw-r--r--doc/development/fe_guide/event_tracking.md4
-rw-r--r--doc/development/fe_guide/graphql.md8
-rw-r--r--doc/development/fe_guide/icons.md28
-rw-r--r--doc/development/fe_guide/index.md4
-rw-r--r--doc/development/fe_guide/keyboard_shortcuts.md98
-rw-r--r--doc/development/fe_guide/tooling.md5
-rw-r--r--doc/development/fe_guide/vuex.md5
-rw-r--r--doc/development/feature_categorization/index.md40
-rw-r--r--doc/development/feature_flags/controls.md39
-rw-r--r--doc/development/feature_flags/development.md32
-rw-r--r--doc/development/frontend.md7
-rw-r--r--doc/development/geo.md8
-rw-r--r--doc/development/geo/framework.md52
-rw-r--r--doc/development/go_guide/index.md6
-rw-r--r--doc/development/gotchas.md15
-rw-r--r--doc/development/graphql_guide/index.md2
-rw-r--r--doc/development/i18n/externalization.md4
-rw-r--r--doc/development/i18n/index.md6
-rw-r--r--doc/development/img/architecture_simplified.pngbin21239 -> 106339 bytes
-rw-r--r--doc/development/instrumentation.md4
-rw-r--r--doc/development/integrations/secure.md9
-rw-r--r--doc/development/integrations/secure_partner_integration.md8
-rw-r--r--doc/development/internal_api.md3
-rw-r--r--doc/development/kubernetes.md51
-rw-r--r--doc/development/logging.md3
-rw-r--r--doc/development/migration_style_guide.md35
-rw-r--r--doc/development/multi_version_compatibility.md2
-rw-r--r--doc/development/new_fe_guide/development/accessibility.md2
-rw-r--r--doc/development/new_fe_guide/development/index.md2
-rw-r--r--doc/development/packages.md21
-rw-r--r--doc/development/performance.md8
-rw-r--r--doc/development/pipelines.md2
-rw-r--r--doc/development/policies.md10
-rw-r--r--doc/development/product_analytics/event_dictionary.md32
-rw-r--r--doc/development/product_analytics/index.md182
-rw-r--r--doc/development/product_analytics/snowplow.md429
-rw-r--r--doc/development/product_analytics/usage_ping.md937
-rw-r--r--doc/development/profiling.md3
-rw-r--r--doc/development/prometheus.md12
-rw-r--r--doc/development/prometheus_metrics.md11
-rw-r--r--doc/development/reactive_caching.md6
-rw-r--r--doc/development/redis.md12
-rw-r--r--doc/development/reference_processing.md16
-rw-r--r--doc/development/secure_coding_guidelines.md43
-rw-r--r--doc/development/shell_scripting_guide/index.md4
-rw-r--r--doc/development/sidekiq_style_guide.md81
-rw-r--r--doc/development/sql.md2
-rw-r--r--doc/development/swapping_tables.md6
-rw-r--r--doc/development/telemetry/event_dictionary.md31
-rw-r--r--doc/development/telemetry/index.md181
-rw-r--r--doc/development/telemetry/snowplow.md409
-rw-r--r--doc/development/telemetry/usage_ping.md886
-rw-r--r--doc/development/testing_guide/best_practices.md37
-rw-r--r--doc/development/testing_guide/ci.md3
-rw-r--r--doc/development/testing_guide/end_to_end/beginners_guide.md4
-rw-r--r--doc/development/testing_guide/end_to_end/best_practices.md59
-rw-r--r--doc/development/testing_guide/end_to_end/environment_selection.md27
-rw-r--r--doc/development/testing_guide/end_to_end/feature_flags.md57
-rw-r--r--doc/development/testing_guide/end_to_end/rspec_metadata_tests.md2
-rw-r--r--doc/development/testing_guide/end_to_end/running_tests_that_require_special_setup.md4
-rw-r--r--doc/development/testing_guide/end_to_end/style_guide.md4
-rw-r--r--doc/development/testing_guide/frontend_testing.md2
-rw-r--r--doc/development/what_requires_downtime.md4
-rw-r--r--doc/development/wikis.md94
-rw-r--r--doc/getting-started/subscription.md3
-rw-r--r--doc/git_hooks/git_hooks.md5
-rw-r--r--doc/gitlab-basics/README.md2
-rw-r--r--doc/gitlab-basics/add-file.md15
-rw-r--r--doc/gitlab-basics/create-branch.md6
-rw-r--r--doc/gitlab-basics/create-project.md30
-rw-r--r--doc/gitlab-basics/start-using-git.md21
-rw-r--r--doc/gitlab-geo/README.md5
-rw-r--r--doc/gitlab-geo/after_setup.md5
-rw-r--r--doc/gitlab-geo/bring-primary-back.md5
-rw-r--r--doc/gitlab-geo/configuration.md5
-rw-r--r--doc/gitlab-geo/configuration_source.md5
-rw-r--r--doc/gitlab-geo/database.md5
-rw-r--r--doc/gitlab-geo/database_source.md5
-rw-r--r--doc/gitlab-geo/disaster-recovery.md5
-rw-r--r--doc/gitlab-geo/docker_registry.md5
-rw-r--r--doc/gitlab-geo/faq.md5
-rw-r--r--doc/gitlab-geo/ha.md5
-rw-r--r--doc/gitlab-geo/object_storage.md5
-rw-r--r--doc/gitlab-geo/planned-failover.md5
-rw-r--r--doc/gitlab-geo/security-review.md5
-rw-r--r--doc/gitlab-geo/ssh.md5
-rw-r--r--doc/gitlab-geo/troubleshooting.md5
-rw-r--r--doc/gitlab-geo/tuning.md5
-rw-r--r--doc/gitlab-geo/updating_the_geo_nodes.md5
-rw-r--r--doc/gitlab-geo/using_a_geo_server.md5
-rw-r--r--doc/hooks/custom_hooks.md7
-rw-r--r--doc/incoming_email/README.md5
-rw-r--r--doc/incoming_email/postfix.md5
-rw-r--r--doc/install/README.md102
-rw-r--r--doc/install/aws/index.md5
-rw-r--r--doc/install/azure/index.md2
-rw-r--r--doc/install/docker.md3
-rw-r--r--doc/install/google_cloud_platform/index.md3
-rw-r--r--doc/install/installation.md76
-rw-r--r--doc/install/openshift_and_gitlab/index.md6
-rw-r--r--doc/install/relative_url.md3
-rw-r--r--doc/install/requirements.md3
-rw-r--r--doc/install/structure.md2
-rw-r--r--doc/integration/README.md15
-rw-r--r--doc/integration/cas.md8
-rw-r--r--doc/integration/elasticsearch.md260
-rw-r--r--doc/integration/external-issue-tracker.md19
-rw-r--r--doc/integration/facebook.md2
-rw-r--r--doc/integration/github.md26
-rw-r--r--doc/integration/gitlab.md7
-rw-r--r--doc/integration/gitpod.md19
-rw-r--r--doc/integration/google.md7
-rw-r--r--doc/integration/jira_development_panel.md25
-rw-r--r--doc/integration/kerberos.md51
-rw-r--r--doc/integration/omniauth.md28
-rw-r--r--doc/integration/salesforce.md2
-rw-r--r--doc/integration/saml.md116
-rw-r--r--doc/integration/sourcegraph.md2
-rw-r--r--doc/integration/twitter.md3
-rw-r--r--doc/intro/README.md2
-rw-r--r--doc/logs/logs.md5
-rw-r--r--doc/operations/error_tracking.md12
-rw-r--r--doc/operations/feature_flags.md87
-rw-r--r--doc/operations/incident_management/alert_details.md199
-rw-r--r--doc/operations/incident_management/alert_integrations.md163
-rw-r--r--doc/operations/incident_management/alert_notifications.md36
-rw-r--r--doc/operations/incident_management/alerts.md300
-rw-r--r--doc/operations/incident_management/generic_alerts.md125
-rw-r--r--doc/operations/incident_management/img/alert_detail_activity_feed_v13_5.pngbin0 -> 37418 bytes
-rw-r--r--doc/operations/incident_management/img/incident_highlight_bar_v13_5.pngbin0 -> 36177 bytes
-rw-r--r--doc/operations/incident_management/img/incident_list_v13_4.pngbin16735 -> 0 bytes
-rw-r--r--doc/operations/incident_management/img/incident_list_v13_5.pngbin0 -> 43685 bytes
-rw-r--r--doc/operations/incident_management/img/incident_sla_settings_v13_5.pngbin0 -> 21480 bytes
-rw-r--r--doc/operations/incident_management/img/integrations_list_v13_5.pngbin0 -> 9916 bytes
-rw-r--r--doc/operations/incident_management/img/link_runbooks_to_alerts_v13_5.pngbin0 -> 77748 bytes
-rw-r--r--doc/operations/incident_management/img/timeline_view_toggle_v13_5.pngbin0 -> 5651 bytes
-rw-r--r--doc/operations/incident_management/incidents.md240
-rw-r--r--doc/operations/incident_management/index.md79
-rw-r--r--doc/operations/incident_management/integrations.md16
-rw-r--r--doc/operations/incident_management/status_page.md16
-rw-r--r--doc/operations/index.md4
-rw-r--r--doc/operations/metrics/alerts.md8
-rw-r--r--doc/operations/metrics/dashboards/default.md3
-rw-r--r--doc/operations/metrics/dashboards/develop.md2
-rw-r--r--doc/operations/metrics/dashboards/img/metrics_dashboard_panel_preview_v13_3.pngbin67972 -> 45857 bytes
-rw-r--r--doc/operations/metrics/dashboards/index.md21
-rw-r--r--doc/operations/metrics/dashboards/panel_types.md72
-rw-r--r--doc/operations/metrics/dashboards/settings.md2
-rw-r--r--doc/operations/metrics/dashboards/templating_variables.md2
-rw-r--r--doc/operations/metrics/dashboards/variables.md10
-rw-r--r--doc/operations/metrics/dashboards/yaml.md16
-rw-r--r--doc/operations/metrics/dashboards/yaml_number_format.md2
-rw-r--r--doc/operations/metrics/embed.md5
-rw-r--r--doc/operations/metrics/embed_grafana.md11
-rw-r--r--doc/operations/metrics/index.md2
-rw-r--r--doc/operations/product_analytics.md4
-rw-r--r--doc/operations/tracing.md7
-rw-r--r--doc/pages/README.md5
-rw-r--r--doc/pages/administration.md5
-rw-r--r--doc/pages/getting_started_part_one.md5
-rw-r--r--doc/pages/getting_started_part_three.md5
-rw-r--r--doc/pages/getting_started_part_two.md5
-rw-r--r--doc/policy/maintenance.md6
-rw-r--r--doc/profile/README.md5
-rw-r--r--doc/profile/preferences.md5
-rw-r--r--doc/profile/two_factor_authentication.md5
-rw-r--r--doc/project_services/bamboo.md5
-rw-r--r--doc/project_services/bugzilla.md5
-rw-r--r--doc/project_services/emails_on_push.md5
-rw-r--r--doc/project_services/hipchat.md5
-rw-r--r--doc/project_services/irker.md5
-rw-r--r--doc/project_services/jira.md5
-rw-r--r--doc/project_services/kubernetes.md5
-rw-r--r--doc/project_services/mattermost.md5
-rw-r--r--doc/project_services/mattermost_slash_commands.md5
-rw-r--r--doc/project_services/project_services.md5
-rw-r--r--doc/project_services/redmine.md5
-rw-r--r--doc/project_services/services_templates.md5
-rw-r--r--doc/project_services/slack.md5
-rw-r--r--doc/project_services/slack_slash_commands.md5
-rw-r--r--doc/push_rules/push_rules.md40
-rw-r--r--doc/raketasks/README.md2
-rw-r--r--doc/raketasks/backup_restore.md647
-rw-r--r--doc/raketasks/cleanup.md4
-rw-r--r--doc/raketasks/import.md4
-rw-r--r--doc/security/asset_proxy.md2
-rw-r--r--doc/security/passwords_for_integrated_authentication_methods.md2
-rw-r--r--doc/security/project_import_decompressed_archive_size_limits.md2
-rw-r--r--doc/security/rack_attack.md2
-rw-r--r--doc/security/rate_limits.md19
-rw-r--r--doc/security/two_factor_authentication.md13
-rw-r--r--doc/ssh/README.md6
-rw-r--r--doc/subscriptions/gitlab_com/index.md48
-rw-r--r--doc/subscriptions/self_managed/index.md33
-rw-r--r--doc/system_hooks/system_hooks.md19
-rw-r--r--doc/telemetry/index.md4
-rw-r--r--doc/telemetry/snowplow.md4
-rw-r--r--doc/topics/autodevops/customize.md4
-rw-r--r--doc/topics/autodevops/index.md66
-rw-r--r--doc/topics/autodevops/stages.md27
-rw-r--r--doc/topics/autodevops/upgrading_auto_deploy_dependencies.md262
-rw-r--r--doc/topics/autodevops/upgrading_chart.md75
-rw-r--r--doc/topics/autodevops/upgrading_postgresql.md7
-rw-r--r--doc/topics/cron/index.md2
-rw-r--r--doc/topics/git/git_rebase.md272
-rw-r--r--doc/topics/git/img/git_rebase_v13_5.pngbin0 -> 49048 bytes
-rw-r--r--doc/topics/git/index.md1
-rw-r--r--doc/university/README.md8
-rw-r--r--doc/university/training/index.md2
-rw-r--r--doc/update/10.0-ce-to-ee.md5
-rw-r--r--doc/update/10.0-to-10.1.md5
-rw-r--r--doc/update/10.1-ce-to-ee.md5
-rw-r--r--doc/update/10.1-to-10.2.md5
-rw-r--r--doc/update/10.2-ce-to-ee.md5
-rw-r--r--doc/update/10.2-to-10.3.md5
-rw-r--r--doc/update/10.3-ce-to-ee.md5
-rw-r--r--doc/update/10.3-to-10.4.md5
-rw-r--r--doc/update/10.4-ce-to-ee.md5
-rw-r--r--doc/update/10.4-to-10.5.md5
-rw-r--r--doc/update/10.5-ce-to-ee.md5
-rw-r--r--doc/update/10.5-to-10.6.md5
-rw-r--r--doc/update/10.6-ce-to-ee.md5
-rw-r--r--doc/update/10.6-to-10.7.md5
-rw-r--r--doc/update/10.7-ce-to-ee.md5
-rw-r--r--doc/update/10.7-to-10.8.md5
-rw-r--r--doc/update/10.8-ce-to-ee.md5
-rw-r--r--doc/update/10.8-to-11.0.md5
-rw-r--r--doc/update/11.0-ce-to-ee.md5
-rw-r--r--doc/update/11.0-to-11.1.md5
-rw-r--r--doc/update/11.1-ce-to-ee.md5
-rw-r--r--doc/update/11.1-to-11.2.md5
-rw-r--r--doc/update/11.2-ce-to-ee.md5
-rw-r--r--doc/update/11.2-to-11.3.md5
-rw-r--r--doc/update/11.3-ce-to-ee.md5
-rw-r--r--doc/update/11.3-to-11.4.md5
-rw-r--r--doc/update/11.4-ce-to-ee.md5
-rw-r--r--doc/update/11.4-to-11.5.md5
-rw-r--r--doc/update/11.5-ce-to-ee.md5
-rw-r--r--doc/update/11.5-to-11.6.md5
-rw-r--r--doc/update/11.6-ce-to-ee.md5
-rw-r--r--doc/update/11.6-to-11.7.md5
-rw-r--r--doc/update/11.7-ce-to-ee.md5
-rw-r--r--doc/update/11.7-to-11.8.md5
-rw-r--r--doc/update/11.8-ce-to-ee.md5
-rw-r--r--doc/update/2.6-to-3.0.md5
-rw-r--r--doc/update/2.9-to-3.0.md5
-rw-r--r--doc/update/3.0-to-3.1.md5
-rw-r--r--doc/update/3.1-to-4.0.md5
-rw-r--r--doc/update/4.0-to-4.1.md5
-rw-r--r--doc/update/4.1-to-4.2.md5
-rw-r--r--doc/update/4.2-to-5.0.md5
-rw-r--r--doc/update/5.0-to-5.1.md5
-rw-r--r--doc/update/5.1-to-5.2.md5
-rw-r--r--doc/update/5.1-to-5.4.md5
-rw-r--r--doc/update/5.1-to-6.0.md5
-rw-r--r--doc/update/5.2-to-5.3.md5
-rw-r--r--doc/update/5.3-to-5.4.md5
-rw-r--r--doc/update/5.4-to-6.0.md5
-rw-r--r--doc/update/6.0-ce-to-ee.md5
-rw-r--r--doc/update/6.0-to-6.1.md5
-rw-r--r--doc/update/6.1-ce-to-ee.md5
-rw-r--r--doc/update/6.1-to-6.2.md5
-rw-r--r--doc/update/6.2-ce-to-ee.md5
-rw-r--r--doc/update/6.2-to-6.3.md5
-rw-r--r--doc/update/6.3-ce-to-ee.md5
-rw-r--r--doc/update/6.3-to-6.4.md5
-rw-r--r--doc/update/6.4-ce-to-ee.md5
-rw-r--r--doc/update/6.4-to-6.5.md5
-rw-r--r--doc/update/6.5-ce-to-ee.md5
-rw-r--r--doc/update/6.5-to-6.6.md5
-rw-r--r--doc/update/6.6-ce-to-ee.md5
-rw-r--r--doc/update/6.6-to-6.7.md5
-rw-r--r--doc/update/6.7-ce-to-ee.md5
-rw-r--r--doc/update/6.7-to-6.8.md5
-rw-r--r--doc/update/6.8-ce-to-ee.md5
-rw-r--r--doc/update/6.8-to-6.9.md5
-rw-r--r--doc/update/6.9-ce-to-ee.md5
-rw-r--r--doc/update/6.9-to-7.0.md5
-rw-r--r--doc/update/6.x-or-7.x-to-7.14.md5
-rw-r--r--doc/update/7.0-ce-to-ee.md5
-rw-r--r--doc/update/7.0-to-7.1.md5
-rw-r--r--doc/update/7.1-ce-to-ee.md5
-rw-r--r--doc/update/7.1-to-7.2.md5
-rw-r--r--doc/update/7.10-ce-to-ee.md5
-rw-r--r--doc/update/7.10-to-7.11.md5
-rw-r--r--doc/update/7.11-ce-to-ee.md5
-rw-r--r--doc/update/7.11-to-7.12.md5
-rw-r--r--doc/update/7.12-ce-to-ee.md5
-rw-r--r--doc/update/7.12-to-7.13.md5
-rw-r--r--doc/update/7.13-ce-to-ee.md5
-rw-r--r--doc/update/7.13-to-7.14.md5
-rw-r--r--doc/update/7.14-ce-to-ee.md5
-rw-r--r--doc/update/7.14-to-8.0.md5
-rw-r--r--doc/update/7.2-to-7.3.md5
-rw-r--r--doc/update/7.3-ce-to-ee.md5
-rw-r--r--doc/update/7.3-to-7.4.md5
-rw-r--r--doc/update/7.4-ce-to-ee.md5
-rw-r--r--doc/update/7.4-to-7.5.md5
-rw-r--r--doc/update/7.5-ce-to-ee.md5
-rw-r--r--doc/update/7.5-to-7.6.md5
-rw-r--r--doc/update/7.6-ce-to-ee.md5
-rw-r--r--doc/update/7.6-to-7.7.md5
-rw-r--r--doc/update/7.7-ce-to-ee.md5
-rw-r--r--doc/update/7.7-to-7.8.md5
-rw-r--r--doc/update/7.8-ce-to-ee.md5
-rw-r--r--doc/update/7.8-to-7.9.md5
-rw-r--r--doc/update/7.9-ce-to-ee.md5
-rw-r--r--doc/update/7.9-to-7.10.md5
-rw-r--r--doc/update/8.0-ce-to-ee.md5
-rw-r--r--doc/update/8.0-to-8.1.md5
-rw-r--r--doc/update/8.1-ce-to-ee.md5
-rw-r--r--doc/update/8.1-to-8.2.md5
-rw-r--r--doc/update/8.10-ce-to-ee.md5
-rw-r--r--doc/update/8.10-to-8.11.md5
-rw-r--r--doc/update/8.11-ce-to-ee.md5
-rw-r--r--doc/update/8.11-to-8.12.md5
-rw-r--r--doc/update/8.12-ce-to-ee.md5
-rw-r--r--doc/update/8.12-to-8.13.md5
-rw-r--r--doc/update/8.13-ce-to-ee.md5
-rw-r--r--doc/update/8.13-to-8.14.md5
-rw-r--r--doc/update/8.14-ce-to-ee.md5
-rw-r--r--doc/update/8.14-to-8.15.md5
-rw-r--r--doc/update/8.15-ce-to-ee.md5
-rw-r--r--doc/update/8.15-to-8.16.md5
-rw-r--r--doc/update/8.16-ce-to-ee.md5
-rw-r--r--doc/update/8.16-to-8.17.md5
-rw-r--r--doc/update/8.17-ce-to-ee.md5
-rw-r--r--doc/update/8.17-to-9.0.md5
-rw-r--r--doc/update/8.2-ce-to-ee.md5
-rw-r--r--doc/update/8.2-to-8.3.md5
-rw-r--r--doc/update/8.3-ce-to-ee.md5
-rw-r--r--doc/update/8.3-to-8.4.md5
-rw-r--r--doc/update/8.4-ce-to-ee.md5
-rw-r--r--doc/update/8.4-to-8.5.md5
-rw-r--r--doc/update/8.5-ce-to-ee.md5
-rw-r--r--doc/update/8.5-to-8.6.md5
-rw-r--r--doc/update/8.6-ce-to-ee.md5
-rw-r--r--doc/update/8.6-to-8.7.md5
-rw-r--r--doc/update/8.7-ce-to-ee.md5
-rw-r--r--doc/update/8.7-to-8.8.md5
-rw-r--r--doc/update/8.8-ce-to-ee.md5
-rw-r--r--doc/update/8.8-to-8.9.md5
-rw-r--r--doc/update/8.9-ce-to-ee.md5
-rw-r--r--doc/update/8.9-to-8.10.md5
-rw-r--r--doc/update/9.0-ce-to-ee.md5
-rw-r--r--doc/update/9.0-to-9.1.md5
-rw-r--r--doc/update/9.1-ce-to-ee.md5
-rw-r--r--doc/update/9.1-to-9.2.md5
-rw-r--r--doc/update/9.2-ce-to-ee.md5
-rw-r--r--doc/update/9.2-to-9.3.md5
-rw-r--r--doc/update/9.3-ce-to-ee.md5
-rw-r--r--doc/update/9.3-to-9.4.md5
-rw-r--r--doc/update/9.4-ce-to-ee.md5
-rw-r--r--doc/update/9.4-to-9.5.md5
-rw-r--r--doc/update/9.5-ce-to-ee.md5
-rw-r--r--doc/update/9.5-to-10.0.md5
-rw-r--r--doc/update/README.md4
-rw-r--r--doc/user/admin_area/abuse_reports.md18
-rw-r--r--doc/user/admin_area/activating_deactivating_users.md2
-rw-r--r--doc/user/admin_area/analytics/img/cohorts_v13_4.pngbin92729 -> 31518 bytes
-rw-r--r--doc/user/admin_area/analytics/img/dev_ops_report_v13_4.pngbin167541 -> 51758 bytes
-rw-r--r--doc/user/admin_area/analytics/index.md3
-rw-r--r--doc/user/admin_area/analytics/instance_statistics.md18
-rw-r--r--doc/user/admin_area/approving_users.md36
-rw-r--r--doc/user/admin_area/credentials_inventory.md22
-rw-r--r--doc/user/admin_area/img/admin_wrench.pngbin3314 -> 0 bytes
-rw-r--r--doc/user/admin_area/img/credentials_inventory_ssh_keys_v13_5.pngbin0 -> 26813 bytes
-rw-r--r--doc/user/admin_area/index.md11
-rw-r--r--doc/user/admin_area/license.md112
-rw-r--r--doc/user/admin_area/settings/gitaly_timeouts.md40
-rw-r--r--doc/user/admin_area/settings/img/email_confirmation_v12_7.pngbin9837 -> 0 bytes
-rw-r--r--doc/user/admin_area/settings/img/gitaly_timeouts.pngbin24654 -> 0 bytes
-rw-r--r--doc/user/admin_area/settings/img/sign_up_restrictions_v13_5.pngbin0 -> 39902 bytes
-rw-r--r--doc/user/admin_area/settings/index.md8
-rw-r--r--doc/user/admin_area/settings/instance_template_repository.md2
-rw-r--r--doc/user/admin_area/settings/project_integration_management.md45
-rw-r--r--doc/user/admin_area/settings/sign_up_restrictions.md11
-rw-r--r--doc/user/admin_area/settings/usage_statistics.md2
-rw-r--r--doc/user/analytics/img/mr_throughput_chart_v13_3.pngbin62510 -> 17870 bytes
-rw-r--r--doc/user/analytics/img/mr_throughput_table_v13_3.pngbin55637 -> 20273 bytes
-rw-r--r--doc/user/analytics/img/new_value_stream_v13_3.pngbin82797 -> 31215 bytes
-rw-r--r--doc/user/analytics/img/vsa_filter_bar_v13.3.pngbin117834 -> 33694 bytes
-rw-r--r--doc/user/analytics/index.md11
-rw-r--r--doc/user/analytics/merge_request_analytics.md15
-rw-r--r--doc/user/analytics/productivity_analytics.md28
-rw-r--r--doc/user/analytics/value_stream_analytics.md50
-rw-r--r--doc/user/application_security/api_fuzzing/index.md8
-rw-r--r--doc/user/application_security/configuration/index.md10
-rw-r--r--doc/user/application_security/container_scanning/index.md26
-rw-r--r--doc/user/application_security/coverage_fuzzing/index.md46
-rw-r--r--doc/user/application_security/dast/img/dast_v13_2.pngbin6763 -> 0 bytes
-rw-r--r--doc/user/application_security/dast/img/dast_v13_4.pngbin0 -> 6558 bytes
-rw-r--r--doc/user/application_security/dast/index.md98
-rw-r--r--doc/user/application_security/dependency_scanning/index.md131
-rw-r--r--doc/user/application_security/img/cve_request_communication.pngbin45402 -> 17386 bytes
-rw-r--r--doc/user/application_security/img/cve_request_communication_publication.pngbin66617 -> 24126 bytes
-rw-r--r--doc/user/application_security/img/new_cve_request_issue.pngbin96795 -> 36847 bytes
-rw-r--r--doc/user/application_security/img/unconfigured_security_approval_rules_and_enabled_jobs_v13_4.pngbin99883 -> 35553 bytes
-rw-r--r--doc/user/application_security/img/unconfigured_security_approval_rules_and_jobs_v13_4.pngbin82526 -> 29773 bytes
-rw-r--r--doc/user/application_security/img/vulnerability-check_v13_4.pngbin75105 -> 25832 bytes
-rw-r--r--doc/user/application_security/img/vulnerability_solution.pngbin3419 -> 9750 bytes
-rw-r--r--doc/user/application_security/index.md29
-rw-r--r--doc/user/application_security/sast/analyzers.md43
-rw-r--r--doc/user/application_security/sast/index.md206
-rw-r--r--doc/user/application_security/secret_detection/index.md130
-rw-r--r--doc/user/application_security/security_dashboard/img/group_vulnerability_report_v13_4.pngbin42099 -> 50648 bytes
-rw-r--r--doc/user/application_security/security_dashboard/img/instance_security_center_settings_v13_4.pngbin0 -> 30034 bytes
-rw-r--r--doc/user/application_security/security_dashboard/img/instance_security_dashboard_empty_v13_4.pngbin38731 -> 13264 bytes
-rw-r--r--doc/user/application_security/security_dashboard/img/instance_security_dashboard_v13_4.pngbin62615 -> 29797 bytes
-rw-r--r--doc/user/application_security/security_dashboard/img/project_security_dashboard_dismissal_v13_4.pngbin0 -> 53541 bytes
-rw-r--r--doc/user/application_security/security_dashboard/img/project_security_dashboard_v13_0.pngbin66337 -> 0 bytes
-rw-r--r--doc/user/application_security/security_dashboard/img/project_security_dashboard_v13_2.pngbin78549 -> 0 bytes
-rw-r--r--doc/user/application_security/security_dashboard/img/project_security_dashboard_v13_3.pngbin168847 -> 0 bytes
-rw-r--r--doc/user/application_security/security_dashboard/img/project_security_dashboard_v13_5.pngbin0 -> 69166 bytes
-rw-r--r--doc/user/application_security/security_dashboard/img/vulnerability_list_table_v13_4.pngbin79904 -> 61329 bytes
-rw-r--r--doc/user/application_security/security_dashboard/index.md142
-rw-r--r--doc/user/application_security/terminology/index.md1
-rw-r--r--doc/user/application_security/threat_monitoring/index.md24
-rw-r--r--doc/user/application_security/vulnerabilities/index.md11
-rw-r--r--doc/user/clusters/agent/index.md231
-rw-r--r--doc/user/clusters/applications.md753
-rw-r--r--doc/user/clusters/cost_management.md74
-rw-r--r--doc/user/clusters/crossplane.md1
-rw-r--r--doc/user/clusters/environments.md5
-rw-r--r--doc/user/clusters/img/kubecost_v13_5.pngbin0 -> 34791 bytes
-rw-r--r--doc/user/compliance/compliance_dashboard/img/compliance_dashboard_v13_3_1.pngbin298542 -> 71374 bytes
-rw-r--r--doc/user/compliance/license_compliance/img/license-check_v13_4.pngbin74407 -> 25590 bytes
-rw-r--r--doc/user/compliance/license_compliance/index.md11
-rw-r--r--doc/user/gitlab_com/index.md24
-rw-r--r--doc/user/group/clusters/index.md6
-rw-r--r--doc/user/group/contribution_analytics/index.md2
-rw-r--r--doc/user/group/epics/index.md46
-rw-r--r--doc/user/group/index.md49
-rw-r--r--doc/user/group/iterations/index.md9
-rw-r--r--doc/user/group/repositories_analytics/index.md27
-rw-r--r--doc/user/group/saml_sso/index.md54
-rw-r--r--doc/user/group/saml_sso/scim_setup.md36
-rw-r--r--doc/user/img/feature_flags_history_note_info_v13_2.pngbin67034 -> 21794 bytes
-rw-r--r--doc/user/img/gitlab_snippet_v13_5.pngbin0 -> 20563 bytes
-rw-r--r--doc/user/img/version_history_notes_collapsed_v13_2.pngbin27528 -> 7770 bytes
-rw-r--r--doc/user/index.md6
-rw-r--r--doc/user/infrastructure/index.md42
-rw-r--r--doc/user/instance/clusters/index.md4
-rw-r--r--doc/user/markdown.md92
-rw-r--r--doc/user/packages/composer_repository/img/project_id_v13_5.pngbin0 -> 9264 bytes
-rw-r--r--doc/user/packages/composer_repository/index.md315
-rw-r--r--doc/user/packages/conan_repository/img/conan_package_view.pngbin46391 -> 0 bytes
-rw-r--r--doc/user/packages/conan_repository/index.md382
-rw-r--r--doc/user/packages/container_registry/img/container_registry_group_repositories_v13_1.pngbin45865 -> 0 bytes
-rw-r--r--doc/user/packages/container_registry/img/container_registry_hover_path_13_4.pngbin0 -> 13597 bytes
-rw-r--r--doc/user/packages/container_registry/img/container_registry_repositories_v13_1.pngbin46734 -> 0 bytes
-rw-r--r--doc/user/packages/container_registry/img/container_registry_repositories_with_quickstart_v13_1.pngbin51791 -> 0 bytes
-rw-r--r--doc/user/packages/container_registry/img/container_registry_repository_details_v13.0.pngbin32673 -> 0 bytes
-rw-r--r--doc/user/packages/container_registry/index.md342
-rw-r--r--doc/user/packages/dependency_proxy/img/group_dependency_proxy.pngbin29334 -> 0 bytes
-rw-r--r--doc/user/packages/dependency_proxy/index.md92
-rw-r--r--doc/user/packages/generic_packages/index.md139
-rw-r--r--doc/user/packages/go_proxy/index.md2
-rw-r--r--doc/user/packages/index.md1
-rw-r--r--doc/user/packages/maven_repository/img/maven_package_view_v12_6.pngbin83954 -> 0 bytes
-rw-r--r--doc/user/packages/maven_repository/index.md98
-rw-r--r--doc/user/packages/npm_registry/index.md26
-rw-r--r--doc/user/packages/nuget_repository/index.md38
-rw-r--r--doc/user/packages/package_registry/index.md12
-rw-r--r--doc/user/packages/pypi_repository/index.md35
-rw-r--r--doc/user/packages/workflows/monorepo.md28
-rw-r--r--doc/user/packages/workflows/project_registry.md18
-rw-r--r--doc/user/permissions.md75
-rw-r--r--doc/user/profile/account/create_accounts.md6
-rw-r--r--doc/user/profile/index.md9
-rw-r--r--doc/user/profile/personal_access_tokens.md6
-rw-r--r--doc/user/profile/preferences.md10
-rw-r--r--doc/user/project/autocomplete_characters.md4
-rw-r--r--doc/user/project/badges.md2
-rw-r--r--doc/user/project/clusters/add_eks_clusters.md44
-rw-r--r--doc/user/project/clusters/add_remove_clusters.md87
-rw-r--r--doc/user/project/clusters/index.md82
-rw-r--r--doc/user/project/clusters/kubernetes_pod_logs.md3
-rw-r--r--doc/user/project/clusters/runbooks/index.md4
-rw-r--r--doc/user/project/clusters/securing.md2
-rw-r--r--doc/user/project/clusters/serverless/aws.md16
-rw-r--r--doc/user/project/clusters/serverless/index.md51
-rw-r--r--doc/user/project/code_intelligence.md6
-rw-r--r--doc/user/project/code_owners.md7
-rw-r--r--doc/user/project/deploy_boards.md4
-rw-r--r--doc/user/project/deploy_keys/index.md2
-rw-r--r--doc/user/project/description_templates.md7
-rw-r--r--doc/user/project/file_lock.md6
-rw-r--r--doc/user/project/img/issue_board_default_lists_v13_4.pngbin0 -> 14866 bytes
-rw-r--r--doc/user/project/img/issue_board_welcome_message.pngbin13519 -> 0 bytes
-rw-r--r--doc/user/project/img/labels_key_value_v12_1.pngbin55495 -> 0 bytes
-rw-r--r--doc/user/project/img/labels_key_value_v13_5.pngbin0 -> 24731 bytes
-rw-r--r--doc/user/project/img/labels_prioritized_v12_1.pngbin51751 -> 0 bytes
-rw-r--r--doc/user/project/img/labels_prioritized_v13_5.pngbin0 -> 26117 bytes
-rw-r--r--doc/user/project/img/labels_subscriptions_v12_1.pngbin48037 -> 0 bytes
-rw-r--r--doc/user/project/img/labels_subscriptions_v13_5.pngbin0 -> 11375 bytes
-rw-r--r--doc/user/project/import/bitbucket.md3
-rw-r--r--doc/user/project/import/bitbucket_server.md46
-rw-r--r--doc/user/project/import/gemnasium.md2
-rw-r--r--doc/user/project/import/github.md39
-rw-r--r--doc/user/project/import/img/manifest_status_v13_3.pngbin90811 -> 31313 bytes
-rw-r--r--doc/user/project/import/index.md4
-rw-r--r--doc/user/project/import/manifest.md2
-rw-r--r--doc/user/project/import/perforce.md2
-rw-r--r--doc/user/project/import/repo_by_url.md4
-rw-r--r--doc/user/project/index.md6
-rw-r--r--doc/user/project/integrations/irker.md8
-rw-r--r--doc/user/project/integrations/jira.md4
-rw-r--r--doc/user/project/integrations/overview.md2
-rw-r--r--doc/user/project/integrations/prometheus.md44
-rw-r--r--doc/user/project/integrations/prometheus_library/cloudwatch.md2
-rw-r--r--doc/user/project/integrations/prometheus_library/haproxy.md2
-rw-r--r--doc/user/project/integrations/prometheus_library/index.md2
-rw-r--r--doc/user/project/integrations/prometheus_library/kubernetes.md4
-rw-r--r--doc/user/project/integrations/prometheus_library/nginx.md2
-rw-r--r--doc/user/project/integrations/prometheus_library/nginx_ingress.md6
-rw-r--r--doc/user/project/integrations/prometheus_library/nginx_ingress_vts.md2
-rw-r--r--doc/user/project/integrations/services_templates.md44
-rw-r--r--doc/user/project/integrations/slack.md2
-rw-r--r--doc/user/project/integrations/webhooks.md7
-rw-r--r--doc/user/project/issue_board.md97
-rw-r--r--doc/user/project/issues/crosslinking_issues.md2
-rw-r--r--doc/user/project/issues/design_management.md71
-rw-r--r--doc/user/project/issues/due_dates.md2
-rw-r--r--doc/user/project/issues/img/design_todo_button_v13_4.pngbin166635 -> 0 bytes
-rw-r--r--doc/user/project/issues/img/design_todo_button_v13_5.pngbin0 -> 79978 bytes
-rw-r--r--doc/user/project/issues/img/designs_reordering_v13_3.gifbin7068938 -> 0 bytes
-rw-r--r--doc/user/project/issues/index.md5
-rw-r--r--doc/user/project/issues/issue_data_and_actions.md10
-rw-r--r--doc/user/project/issues/managing_issues.md1
-rw-r--r--doc/user/project/issues/multiple_assignees_for_issues.md2
-rw-r--r--doc/user/project/issues/related_issues.md23
-rw-r--r--doc/user/project/labels.md68
-rw-r--r--doc/user/project/merge_requests/accessibility_testing.md2
-rw-r--r--doc/user/project/merge_requests/allow_collaboration.md5
-rw-r--r--doc/user/project/merge_requests/getting_started.md42
-rw-r--r--doc/user/project/merge_requests/img/commit_nav_v13_4.pngbin0 -> 21170 bytes
-rw-r--r--doc/user/project/merge_requests/load_performance_testing.md4
-rw-r--r--doc/user/project/merge_requests/merge_request_approvals.md27
-rw-r--r--doc/user/project/merge_requests/revert_changes.md2
-rw-r--r--doc/user/project/merge_requests/reviewing_and_managing_merge_requests.md4
-rw-r--r--doc/user/project/merge_requests/squash_and_merge.md4
-rw-r--r--doc/user/project/merge_requests/test_coverage_visualization.md101
-rw-r--r--doc/user/project/merge_requests/work_in_progress_merge_requests.md13
-rw-r--r--doc/user/project/milestones/burndown_and_burnup_charts.md142
-rw-r--r--doc/user/project/milestones/burndown_charts.md88
-rw-r--r--doc/user/project/milestones/img/burndown_and_burnup_charts_v13_5.pngbin0 -> 55865 bytes
-rw-r--r--doc/user/project/milestones/img/burndown_chart_fixed_v13_5.pngbin0 -> 32250 bytes
-rw-r--r--doc/user/project/milestones/img/burndown_chart_legacy_v13_5.pngbin0 -> 28180 bytes
-rw-r--r--doc/user/project/milestones/img/burndown_chart_v13_5.png (renamed from doc/user/project/milestones/img/burndown_chart.png)bin48403 -> 48403 bytes
-rw-r--r--doc/user/project/milestones/img/burnup_chart_v13_5.pngbin0 -> 29283 bytes
-rw-r--r--doc/user/project/milestones/index.md4
-rw-r--r--doc/user/project/new_ci_build_permissions_model.md5
-rw-r--r--doc/user/project/pages/custom_domains_ssl_tls_certification/dns_concepts.md4
-rw-r--r--doc/user/project/pages/custom_domains_ssl_tls_certification/index.md10
-rw-r--r--doc/user/project/pages/custom_domains_ssl_tls_certification/lets_encrypt_integration.md3
-rw-r--r--doc/user/project/pages/getting_started/new_or_existing_website.md2
-rw-r--r--doc/user/project/pages/getting_started/pages_forked_sample_project.md2
-rw-r--r--doc/user/project/pages/getting_started_part_one.md9
-rw-r--r--doc/user/project/pages/getting_started_part_three.md4
-rw-r--r--doc/user/project/pages/index.md21
-rw-r--r--doc/user/project/pages/introduction.md11
-rw-r--r--doc/user/project/pages/lets_encrypt_for_gitlab_pages.md5
-rw-r--r--doc/user/project/pages/pages_access_control.md17
-rw-r--r--doc/user/project/pages/redirects.md36
-rw-r--r--doc/user/project/protected_branches.md4
-rw-r--r--doc/user/project/quick_actions.md15
-rw-r--r--doc/user/project/releases/index.md38
-rw-r--r--doc/user/project/repository/forking_workflow.md2
-rw-r--r--doc/user/project/repository/img/repository_mirroring_push_settings.pngbin23955 -> 92335 bytes
-rw-r--r--doc/user/project/repository/index.md4
-rw-r--r--doc/user/project/repository/reducing_the_repo_size_using_git.md14
-rw-r--r--doc/user/project/repository/repository_mirroring.md5
-rw-r--r--doc/user/project/repository/x509_signed_commits/index.md2
-rw-r--r--doc/user/project/requirements/img/requirement_create_v13_5.pngbin0 -> 89654 bytes
-rw-r--r--doc/user/project/requirements/img/requirement_view_v13_5.pngbin0 -> 90238 bytes
-rw-r--r--doc/user/project/requirements/img/requirements_list_v13_1.pngbin68346 -> 0 bytes
-rw-r--r--doc/user/project/requirements/img/requirements_list_v13_5.pngbin0 -> 81211 bytes
-rw-r--r--doc/user/project/requirements/index.md41
-rw-r--r--doc/user/project/service_desk.md4
-rw-r--r--doc/user/project/settings/index.md20
-rw-r--r--doc/user/project/settings/project_access_tokens.md55
-rw-r--r--doc/user/project/static_site_editor/img/front_matter_ui_v13_4.pngbin0 -> 36431 bytes
-rw-r--r--doc/user/project/static_site_editor/index.md169
-rw-r--r--doc/user/project/web_ide/index.md63
-rw-r--r--doc/user/project/wiki/img/wiki_sidebar.pngbin3178 -> 0 bytes
-rw-r--r--doc/user/project/wiki/img/wiki_sidebar_v13_5.pngbin0 -> 16039 bytes
-rw-r--r--doc/user/project/wiki/index.md46
-rw-r--r--doc/user/search/advanced_global_search.md4
-rw-r--r--doc/user/search/advanced_search_syntax.md9
-rw-r--r--doc/user/search/img/basic_search.pngbin0 -> 88486 bytes
-rw-r--r--doc/user/search/img/basic_search_results.pngbin0 -> 19901 bytes
-rw-r--r--doc/user/search/index.md83
-rw-r--r--doc/user/snippets.md46
-rw-r--r--doc/user/todos.md79
-rw-r--r--doc/user/upgrade_email_bypass.md4
-rw-r--r--doc/web_hooks/web_hooks.md5
-rw-r--r--doc/workflow/README.md5
-rw-r--r--doc/workflow/add-user/add-user.md5
-rw-r--r--doc/workflow/authorization_for_merge_requests.md5
-rw-r--r--doc/workflow/award_emoji.md5
-rw-r--r--doc/workflow/cherry_pick_changes.md5
-rw-r--r--doc/workflow/ff_merge.md5
-rw-r--r--doc/workflow/file_finder.md5
-rw-r--r--doc/workflow/forking_workflow.md5
-rw-r--r--doc/workflow/git_annex.md5
-rw-r--r--doc/workflow/git_lfs.md5
-rw-r--r--doc/workflow/gitlab_flow.md5
-rw-r--r--doc/workflow/groups.md5
-rw-r--r--doc/workflow/importing/README.md5
-rw-r--r--doc/workflow/importing/import_projects_from_bitbucket.md5
-rw-r--r--doc/workflow/importing/import_projects_from_fogbugz.md5
-rw-r--r--doc/workflow/importing/import_projects_from_gitea.md5
-rw-r--r--doc/workflow/importing/import_projects_from_github.md5
-rw-r--r--doc/workflow/importing/import_projects_from_gitlab_com.md5
-rw-r--r--doc/workflow/importing/migrating_from_svn.md5
-rw-r--r--doc/workflow/issue_weight.md5
-rw-r--r--doc/workflow/labels.md7
-rw-r--r--doc/workflow/lfs/lfs_administration.md5
-rw-r--r--doc/workflow/lfs/manage_large_binaries_with_git_lfs.md5
-rw-r--r--doc/workflow/lfs/migrate_from_git_annex_to_git_lfs.md5
-rw-r--r--doc/workflow/merge_request_approvals.md5
-rw-r--r--doc/workflow/merge_requests.md5
-rw-r--r--doc/workflow/merge_when_build_succeeds.md5
-rw-r--r--doc/workflow/milestones.md5
-rw-r--r--doc/workflow/notifications.md5
-rw-r--r--doc/workflow/project_features.md5
-rw-r--r--doc/workflow/protected_branches.md5
-rw-r--r--doc/workflow/rebase_before_merge.md5
-rw-r--r--doc/workflow/releases.md5
-rw-r--r--doc/workflow/repository_mirroring.md5
-rw-r--r--doc/workflow/revert_changes.md5
-rw-r--r--doc/workflow/share_projects_with_other_groups.md5
-rw-r--r--doc/workflow/share_with_group.md5
-rw-r--r--doc/workflow/shortcuts.md5
-rw-r--r--doc/workflow/time_tracking.md5
-rw-r--r--doc/workflow/timezone.md5
-rw-r--r--doc/workflow/todos.md5
-rw-r--r--doc/workflow/web_editor.md5
-rw-r--r--doc/workflow/wip_merge_requests.md5
-rw-r--r--doc/workflow/workflow.md5
-rw-r--r--docker/README.md2
-rw-r--r--geo_architecture.pngbin0 -> 226694 bytes
-rw-r--r--haml_lint/linter/documentation_links.rb2
-rw-r--r--jest.config.base.js4
-rw-r--r--lib/api/access_requests.rb2
-rw-r--r--lib/api/admin/ci/variables.rb2
-rw-r--r--lib/api/admin/instance_clusters.rb4
-rw-r--r--lib/api/admin/sidekiq.rb2
-rw-r--r--lib/api/api.rb10
-rw-r--r--lib/api/api_guard.rb39
-rw-r--r--lib/api/appearance.rb2
-rw-r--r--lib/api/applications.rb2
-rw-r--r--lib/api/avatar.rb2
-rw-r--r--lib/api/award_emoji.rb2
-rw-r--r--lib/api/badges.rb2
-rw-r--r--lib/api/base.rb6
-rw-r--r--lib/api/boards.rb2
-rw-r--r--lib/api/boards_responses.rb2
-rw-r--r--lib/api/branches.rb2
-rw-r--r--lib/api/broadcast_messages.rb2
-rw-r--r--lib/api/ci/pipeline_schedules.rb2
-rw-r--r--lib/api/ci/pipelines.rb6
-rw-r--r--lib/api/ci/runner.rb6
-rw-r--r--lib/api/ci/runners.rb2
-rw-r--r--lib/api/commit_statuses.rb2
-rw-r--r--lib/api/commits.rb18
-rw-r--r--lib/api/composer_packages.rb8
-rw-r--r--lib/api/conan_instance_packages.rb2
-rw-r--r--lib/api/conan_package_endpoints.rb2
-rw-r--r--lib/api/conan_project_packages.rb2
-rw-r--r--lib/api/container_registry_event.rb2
-rw-r--r--lib/api/debian_group_packages.rb21
-rw-r--r--lib/api/debian_package_endpoints.rb124
-rw-r--r--lib/api/debian_project_packages.rb56
-rw-r--r--lib/api/deploy_keys.rb2
-rw-r--r--lib/api/deploy_tokens.rb2
-rw-r--r--lib/api/deployments.rb2
-rw-r--r--lib/api/discussions.rb2
-rw-r--r--lib/api/entities/ci/lint/result.rb16
-rw-r--r--lib/api/entities/cluster.rb2
-rw-r--r--lib/api/entities/container_registry.rb1
-rw-r--r--lib/api/entities/feature_flag.rb16
-rw-r--r--lib/api/entities/feature_flag/detailed_legacy_scope.rb11
-rw-r--r--lib/api/entities/feature_flag/legacy_scope.rb16
-rw-r--r--lib/api/entities/feature_flag/scope.rb12
-rw-r--r--lib/api/entities/feature_flag/strategy.rb14
-rw-r--r--lib/api/entities/feature_flag/user_list.rb27
-rw-r--r--lib/api/entities/job_request/cache.rb2
-rw-r--r--lib/api/entities/member.rb1
-rw-r--r--lib/api/entities/package.rb14
-rw-r--r--lib/api/entities/project.rb1
-rw-r--r--lib/api/entities/snippet.rb6
-rw-r--r--lib/api/entities/unleash_feature.rb32
-rw-r--r--lib/api/entities/unleash_gitlab_user_list_strategy.rb14
-rw-r--r--lib/api/entities/unleash_legacy_strategy.rb14
-rw-r--r--lib/api/entities/unleash_strategy.rb10
-rw-r--r--lib/api/entities/user_with_admin.rb2
-rw-r--r--lib/api/environments.rb2
-rw-r--r--lib/api/error_tracking.rb2
-rw-r--r--lib/api/events.rb2
-rw-r--r--lib/api/feature_flag_scopes.rb158
-rw-r--r--lib/api/feature_flags.rb266
-rw-r--r--lib/api/feature_flags_user_lists.rb100
-rw-r--r--lib/api/features.rb2
-rw-r--r--lib/api/files.rb2
-rw-r--r--lib/api/freeze_periods.rb2
-rw-r--r--lib/api/generic_packages.rb90
-rw-r--r--lib/api/github/entities.rb4
-rwxr-xr-xlib/api/go_proxy.rb2
-rw-r--r--lib/api/group_boards.rb2
-rw-r--r--lib/api/group_clusters.rb4
-rw-r--r--lib/api/group_container_repositories.rb6
-rw-r--r--lib/api/group_export.rb2
-rw-r--r--lib/api/group_import.rb2
-rw-r--r--lib/api/group_labels.rb2
-rw-r--r--lib/api/group_milestones.rb2
-rw-r--r--lib/api/group_packages.rb2
-rw-r--r--lib/api/group_variables.rb2
-rw-r--r--lib/api/groups.rb22
-rw-r--r--lib/api/helpers.rb3
-rw-r--r--lib/api/helpers/groups_helpers.rb1
-rw-r--r--lib/api/helpers/merge_requests_helpers.rb7
-rw-r--r--lib/api/helpers/packages/conan/api_helpers.rb4
-rw-r--r--lib/api/helpers/packages/dependency_proxy_helpers.rb1
-rw-r--r--lib/api/helpers/packages_helpers.rb5
-rw-r--r--lib/api/helpers/pagination.rb4
-rw-r--r--lib/api/helpers/presentable.rb2
-rw-r--r--lib/api/helpers/projects_helpers.rb10
-rw-r--r--lib/api/helpers/runner.rb4
-rw-r--r--lib/api/helpers/services_helpers.rb6
-rw-r--r--lib/api/helpers/settings_helpers.rb1
-rw-r--r--lib/api/helpers/snippets_helpers.rb2
-rw-r--r--lib/api/import_bitbucket_server.rb2
-rw-r--r--lib/api/import_github.rb2
-rw-r--r--lib/api/internal/base.rb92
-rw-r--r--lib/api/internal/kubernetes.rb2
-rw-r--r--lib/api/internal/lfs.rb54
-rw-r--r--lib/api/internal/pages.rb2
-rw-r--r--lib/api/issue_links.rb2
-rw-r--r--lib/api/issues.rb7
-rw-r--r--lib/api/job_artifacts.rb2
-rw-r--r--lib/api/jobs.rb2
-rw-r--r--lib/api/keys.rb2
-rw-r--r--lib/api/labels.rb2
-rw-r--r--lib/api/lint.rb38
-rw-r--r--lib/api/markdown.rb2
-rw-r--r--lib/api/maven_packages.rb18
-rw-r--r--lib/api/members.rb32
-rw-r--r--lib/api/merge_request_approvals.rb2
-rw-r--r--lib/api/merge_request_diffs.rb2
-rw-r--r--lib/api/merge_requests.rb2
-rw-r--r--lib/api/metrics/dashboard/annotations.rb2
-rw-r--r--lib/api/metrics/user_starred_dashboards.rb2
-rw-r--r--lib/api/namespaces.rb6
-rw-r--r--lib/api/notes.rb2
-rw-r--r--lib/api/notification_settings.rb2
-rw-r--r--lib/api/npm_packages.rb6
-rw-r--r--lib/api/nuget_packages.rb12
-rw-r--r--lib/api/package_files.rb2
-rw-r--r--lib/api/pages.rb2
-rw-r--r--lib/api/pages_domains.rb2
-rw-r--r--lib/api/project_clusters.rb4
-rw-r--r--lib/api/project_container_repositories.rb14
-rw-r--r--lib/api/project_events.rb2
-rw-r--r--lib/api/project_export.rb4
-rw-r--r--lib/api/project_hooks.rb6
-rw-r--r--lib/api/project_import.rb4
-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.rb4
-rw-r--r--lib/api/project_snapshots.rb2
-rw-r--r--lib/api/project_snippets.rb14
-rw-r--r--lib/api/project_statistics.rb2
-rw-r--r--lib/api/project_templates.rb2
-rw-r--r--lib/api/projects.rb4
-rw-r--r--lib/api/protected_branches.rb2
-rw-r--r--lib/api/protected_tags.rb2
-rw-r--r--lib/api/pypi_packages.rb10
-rw-r--r--lib/api/release/links.rb2
-rw-r--r--lib/api/releases.rb16
-rw-r--r--lib/api/remote_mirrors.rb2
-rw-r--r--lib/api/repositories.rb2
-rw-r--r--lib/api/resource_label_events.rb2
-rw-r--r--lib/api/resource_milestone_events.rb2
-rw-r--r--lib/api/resource_state_events.rb2
-rw-r--r--lib/api/search.rb16
-rw-r--r--lib/api/services.rb2
-rw-r--r--lib/api/settings.rb11
-rw-r--r--lib/api/sidekiq_metrics.rb2
-rw-r--r--lib/api/snippets.rb16
-rw-r--r--lib/api/statistics.rb2
-rw-r--r--lib/api/submodules.rb2
-rw-r--r--lib/api/subscriptions.rb2
-rw-r--r--lib/api/suggestions.rb2
-rw-r--r--lib/api/system_hooks.rb6
-rw-r--r--lib/api/tags.rb2
-rw-r--r--lib/api/templates.rb2
-rw-r--r--lib/api/terraform/state.rb2
-rw-r--r--lib/api/terraform/state_version.rb68
-rw-r--r--lib/api/todos.rb2
-rw-r--r--lib/api/triggers.rb2
-rw-r--r--lib/api/unleash.rb77
-rw-r--r--lib/api/usage_data.rb4
-rw-r--r--lib/api/user_counts.rb2
-rw-r--r--lib/api/users.rb33
-rw-r--r--lib/api/v3/github.rb4
-rw-r--r--lib/api/variables.rb2
-rw-r--r--lib/api/version.rb2
-rw-r--r--lib/api/wikis.rb2
-rw-r--r--lib/backup/artifacts.rb4
-rw-r--r--lib/backup/builds.rb4
-rw-r--r--lib/backup/lfs.rb4
-rw-r--r--lib/backup/pages.rb4
-rw-r--r--lib/backup/registry.rb4
-rw-r--r--lib/backup/repositories.rb310
-rw-r--r--lib/backup/repository.rb265
-rw-r--r--lib/backup/uploads.rb4
-rw-r--r--lib/banzai/filter/design_reference_filter.rb14
-rw-r--r--lib/banzai/reference_parser.rb4
-rw-r--r--lib/banzai/reference_parser/mentioned_group_parser.rb2
-rw-r--r--lib/banzai/reference_redactor.rb1
-rw-r--r--lib/feature.rb2
-rw-r--r--lib/feature/definition.rb33
-rw-r--r--lib/feature/shared.rb12
-rw-r--r--lib/gitlab/alert_management/alert_params.rb46
-rw-r--r--lib/gitlab/alert_management/alert_status_counts.rb10
-rw-r--r--lib/gitlab/alert_management/payload/base.rb22
-rw-r--r--lib/gitlab/alert_management/payload/generic.rb4
-rw-r--r--lib/gitlab/alerting/alert.rb215
-rw-r--r--lib/gitlab/alerting/alert_annotation.rb11
-rw-r--r--lib/gitlab/alerting/notification_payload_parser.rb107
-rw-r--r--lib/gitlab/application_context.rb4
-rw-r--r--lib/gitlab/auth.rb2
-rw-r--r--lib/gitlab/auth/auth_finders.rb2
-rw-r--r--lib/gitlab/auth/otp/strategies/base.rb32
-rw-r--r--lib/gitlab/auth/otp/strategies/devise.rb15
-rw-r--r--lib/gitlab/auth/otp/strategies/forti_authenticator.rb41
-rw-r--r--lib/gitlab/auth/user_access_denied_reason.rb4
-rw-r--r--lib/gitlab/background_migration/add_modified_to_approval_merge_request_rule.rb73
-rw-r--r--lib/gitlab/background_migration/backfill_snippet_repositories.rb2
-rw-r--r--lib/gitlab/background_migration/migrate_u2f_webauthn.rb46
-rw-r--r--lib/gitlab/background_migration/migrate_users_bio_to_user_details.rb2
-rw-r--r--lib/gitlab/background_migration/remove_duplicated_cs_findings_without_vulnerability_id.rb13
-rw-r--r--lib/gitlab/background_migration/replace_blocked_by_links.rb29
-rw-r--r--lib/gitlab/background_migration/sync_blocking_issues_count.rb13
-rw-r--r--lib/gitlab/background_migration/user_mentions/lib/banzai/reference_parser.rb25
-rw-r--r--lib/gitlab/background_migration/user_mentions/lib/banzai/reference_parser/isolated_mentioned_group_parser.rb25
-rw-r--r--lib/gitlab/background_migration/user_mentions/lib/gitlab/isolated_reference_extractor.rb30
-rw-r--r--lib/gitlab/background_migration/user_mentions/models/concerns/isolated_mentionable.rb5
-rw-r--r--lib/gitlab/background_migration/user_mentions/models/concerns/namespace/recursive_traversal.rb74
-rw-r--r--lib/gitlab/background_migration/user_mentions/models/group.rb91
-rw-r--r--lib/gitlab/background_migration/user_mentions/models/namespace.rb33
-rw-r--r--lib/gitlab/bulk_import/client.rb72
-rw-r--r--lib/gitlab/checks/matching_merge_request.rb2
-rw-r--r--lib/gitlab/checks/post_push_message.rb6
-rw-r--r--lib/gitlab/ci/ansi2json/converter.rb23
-rw-r--r--lib/gitlab/ci/ansi2json/line.rb7
-rw-r--r--lib/gitlab/ci/ansi2json/state.rb3
-rw-r--r--lib/gitlab/ci/artifact_file_reader.rb27
-rw-r--r--lib/gitlab/ci/config.rb4
-rw-r--r--lib/gitlab/ci/config/entry/bridge.rb19
-rw-r--r--lib/gitlab/ci/config/entry/cache.rb24
-rw-r--r--lib/gitlab/ci/config/entry/include.rb6
-rw-r--r--lib/gitlab/ci/config/entry/jobs.rb29
-rw-r--r--lib/gitlab/ci/config/entry/needs.rb23
-rw-r--r--lib/gitlab/ci/config/entry/ports.rb26
-rw-r--r--lib/gitlab/ci/config/entry/product/matrix.rb2
-rw-r--r--lib/gitlab/ci/config/entry/product/variables.rb6
-rw-r--r--lib/gitlab/ci/config/entry/reports.rb3
-rw-r--r--lib/gitlab/ci/config/entry/rules.rb21
-rw-r--r--lib/gitlab/ci/config/entry/services.rb26
-rw-r--r--lib/gitlab/ci/config/entry/variables.rb22
-rw-r--r--lib/gitlab/ci/features.rb30
-rw-r--r--lib/gitlab/ci/lint.rb7
-rw-r--r--lib/gitlab/ci/parsers/test/junit.rb34
-rw-r--r--lib/gitlab/ci/pipeline/chain/command.rb2
-rw-r--r--lib/gitlab/ci/pipeline/chain/config/process.rb2
-rw-r--r--lib/gitlab/ci/pipeline/chain/create.rb2
-rw-r--r--lib/gitlab/ci/pipeline/seed/build/cache.rb4
-rw-r--r--lib/gitlab/ci/reports/test_case.rb9
-rw-r--r--lib/gitlab/ci/reports/test_suite.rb16
-rw-r--r--lib/gitlab/ci/runner/backoff.rb75
-rw-r--r--lib/gitlab/ci/status/bridge/action.rb12
-rw-r--r--lib/gitlab/ci/status/bridge/common.rb1
-rw-r--r--lib/gitlab/ci/status/bridge/factory.rb5
-rw-r--r--lib/gitlab/ci/status/bridge/manual.rb12
-rw-r--r--lib/gitlab/ci/status/bridge/play.rb19
-rw-r--r--lib/gitlab/ci/status/canceled.rb4
-rw-r--r--lib/gitlab/ci/status/created.rb4
-rw-r--r--lib/gitlab/ci/status/failed.rb4
-rw-r--r--lib/gitlab/ci/status/manual.rb4
-rw-r--r--lib/gitlab/ci/status/pending.rb4
-rw-r--r--lib/gitlab/ci/status/preparing.rb4
-rw-r--r--lib/gitlab/ci/status/running.rb4
-rw-r--r--lib/gitlab/ci/status/scheduled.rb4
-rw-r--r--lib/gitlab/ci/status/skipped.rb4
-rw-r--r--lib/gitlab/ci/status/success.rb4
-rw-r--r--lib/gitlab/ci/status/waiting_for_resource.rb4
-rw-r--r--lib/gitlab/ci/templates/AWS/CF-Provision-and-Deploy-EC2.gitlab-ci.yml11
-rw-r--r--lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml2
-rw-r--r--lib/gitlab/ci/templates/Bash.gitlab-ci.yml2
-rw-r--r--lib/gitlab/ci/templates/Clojure.gitlab-ci.yml2
-rw-r--r--lib/gitlab/ci/templates/Crystal.gitlab-ci.yml2
-rw-r--r--lib/gitlab/ci/templates/Django.gitlab-ci.yml4
-rw-r--r--lib/gitlab/ci/templates/Elixir.gitlab-ci.yml2
-rw-r--r--lib/gitlab/ci/templates/Jobs/CF-Provision.gitlab-ci.yml14
-rw-r--r--lib/gitlab/ci/templates/Jobs/Code-Intelligence.gitlab-ci.yml16
-rw-r--r--lib/gitlab/ci/templates/Jobs/Code-Quality.gitlab-ci.yml3
-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.yml9
-rw-r--r--lib/gitlab/ci/templates/Jobs/Deploy/EC2.gitlab-ci.yml39
-rw-r--r--lib/gitlab/ci/templates/Jobs/Deploy/ECS.gitlab-ci.yml1
-rw-r--r--lib/gitlab/ci/templates/Laravel.gitlab-ci.yml4
-rw-r--r--lib/gitlab/ci/templates/Managed-Cluster-Applications.gitlab-ci.yml2
-rw-r--r--lib/gitlab/ci/templates/Nodejs.gitlab-ci.yml4
-rw-r--r--lib/gitlab/ci/templates/PHP.gitlab-ci.yml2
-rw-r--r--lib/gitlab/ci/templates/Pages/Gatsby.gitlab-ci.yml2
-rw-r--r--lib/gitlab/ci/templates/Pages/Jekyll.gitlab-ci.yml2
-rw-r--r--lib/gitlab/ci/templates/Ruby.gitlab-ci.yml2
-rw-r--r--lib/gitlab/ci/templates/Rust.gitlab-ci.yml2
-rw-r--r--lib/gitlab/ci/templates/Security/Coverage-Fuzzing.gitlab-ci.yml1
-rw-r--r--lib/gitlab/ci/templates/Security/License-Scanning.gitlab-ci.yml2
-rw-r--r--lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml43
-rw-r--r--lib/gitlab/ci/templates/Security/Secret-Detection.gitlab-ci.yml4
-rw-r--r--lib/gitlab/ci/templates/Terraform.latest.gitlab-ci.yml22
-rw-r--r--lib/gitlab/ci/templates/Terraform/Base.latest.gitlab-ci.yml53
-rw-r--r--lib/gitlab/ci/trace.rb13
-rw-r--r--lib/gitlab/ci/trace/checksum.rb83
-rw-r--r--lib/gitlab/ci/trace/metrics.rb33
-rw-r--r--lib/gitlab/ci/variables/collection/item.rb4
-rw-r--r--lib/gitlab/ci/yaml_processor/result.rb8
-rw-r--r--lib/gitlab/cleanup/orphan_lfs_file_references.rb5
-rw-r--r--lib/gitlab/cluster/puma_worker_killer_initializer.rb4
-rw-r--r--lib/gitlab/code_navigation_path.rb1
-rw-r--r--lib/gitlab/config/entry/composable_array.rb58
-rw-r--r--lib/gitlab/config/entry/composable_hash.rb47
-rw-r--r--lib/gitlab/config/entry/factory.rb2
-rw-r--r--lib/gitlab/config/entry/legacy_validation_helpers.rb14
-rw-r--r--lib/gitlab/config/entry/simplifiable.rb2
-rw-r--r--lib/gitlab/config/entry/validators.rb8
-rw-r--r--lib/gitlab/conflict/file_collection.rb8
-rw-r--r--lib/gitlab/danger/commit_linter.rb4
-rw-r--r--lib/gitlab/danger/helper.rb11
-rw-r--r--lib/gitlab/danger/roulette.rb15
-rw-r--r--lib/gitlab/danger/teammate.rb7
-rw-r--r--lib/gitlab/data_builder/deployment.rb4
-rw-r--r--lib/gitlab/database.rb40
-rw-r--r--lib/gitlab/database/batch_count.rb48
-rw-r--r--lib/gitlab/database/bulk_update.rb168
-rw-r--r--lib/gitlab/database/concurrent_reindex.rb143
-rw-r--r--lib/gitlab/database/count/reltuples_count_strategy.rb3
-rw-r--r--lib/gitlab/database/migration_helpers.rb196
-rw-r--r--lib/gitlab/database/partitioning/partition_creator.rb4
-rw-r--r--lib/gitlab/database/partitioning_migration_helpers/backfill_partitioned_table.rb2
-rw-r--r--lib/gitlab/database/postgres_index.rb31
-rw-r--r--lib/gitlab/database/reindexing.rb18
-rw-r--r--lib/gitlab/database/reindexing/concurrent_reindex.rb127
-rw-r--r--lib/gitlab/database/reindexing/coordinator.rb41
-rw-r--r--lib/gitlab/database/reindexing/reindex_action.rb35
-rw-r--r--lib/gitlab/database/schema_helpers.rb17
-rw-r--r--lib/gitlab/database/similarity_score.rb11
-rw-r--r--lib/gitlab/database/with_lock_retries.rb8
-rw-r--r--lib/gitlab/design_management/copy_design_collection_model_attributes.yml43
-rw-r--r--lib/gitlab/diff/file_collection/merge_request_diff_base.rb9
-rw-r--r--lib/gitlab/diff/highlight_cache.rb47
-rw-r--r--lib/gitlab/exclusive_lease_helpers.rb2
-rw-r--r--lib/gitlab/experimentation.rb46
-rw-r--r--lib/gitlab/git/diff.rb12
-rw-r--r--lib/gitlab/git/diff_collection.rb34
-rw-r--r--lib/gitlab/git/diff_stats_collection.rb4
-rw-r--r--lib/gitlab/git/repository.rb19
-rw-r--r--lib/gitlab/git/wiki.rb10
-rw-r--r--lib/gitlab/git_access.rb36
-rw-r--r--lib/gitlab/git_access_result/custom_action.rb2
-rw-r--r--lib/gitlab/git_access_snippet.rb25
-rw-r--r--lib/gitlab/git_access_wiki.rb10
-rw-r--r--lib/gitlab/gitaly_client/diff_stitcher.rb10
-rw-r--r--lib/gitlab/gitaly_client/operation_service.rb5
-rw-r--r--lib/gitlab/gitpod.rb8
-rw-r--r--lib/gitlab/gl_repository.rb10
-rw-r--r--lib/gitlab/gl_repository/identifier.rb13
-rw-r--r--lib/gitlab/gl_repository/repo_type.rb6
-rw-r--r--lib/gitlab/gon_helper.rb10
-rw-r--r--lib/gitlab/graphql/authorize/authorize_resource.rb4
-rw-r--r--lib/gitlab/graphql/global_id_compatibility.rb20
-rw-r--r--lib/gitlab/graphql/markdown_field.rb8
-rw-r--r--lib/gitlab/graphql/markdown_field/resolver.rb22
-rw-r--r--lib/gitlab/graphql/pagination/keyset/connection.rb3
-rw-r--r--lib/gitlab/graphql/pagination/keyset/last_items.rb57
-rw-r--r--lib/gitlab/graphql/pagination/keyset/order_info.rb16
-rw-r--r--lib/gitlab/graphql/query_analyzers/logger_analyzer.rb11
-rw-r--r--lib/gitlab/group_search_results.rb6
-rw-r--r--lib/gitlab/health_checks/unicorn_check.rb2
-rw-r--r--lib/gitlab/import_export/attribute_cleaner.rb4
-rw-r--r--lib/gitlab/import_export/base/relation_factory.rb30
-rw-r--r--lib/gitlab/import_export/file_importer.rb4
-rw-r--r--lib/gitlab/import_export/json/ndjson_reader.rb6
-rw-r--r--lib/gitlab/import_export/lfs_saver.rb8
-rw-r--r--lib/gitlab/import_export/members_mapper.rb6
-rw-r--r--lib/gitlab/import_export/project/import_export.yml6
-rw-r--r--lib/gitlab/import_export/project/sample/date_calculator.rb37
-rw-r--r--lib/gitlab/import_export/project/sample/sample_data_relation_tree_restorer.rb51
-rw-r--r--lib/gitlab/import_export/project/tree_restorer.rb10
-rw-r--r--lib/gitlab/import_export/project/tree_saver.rb2
-rw-r--r--lib/gitlab/import_export/repo_restorer.rb14
-rw-r--r--lib/gitlab/import_export/saver.rb4
-rw-r--r--lib/gitlab/import_export/uploads_manager.rb2
-rw-r--r--lib/gitlab/import_export/version_checker.rb4
-rw-r--r--lib/gitlab/instrumentation/redis.rb2
-rw-r--r--lib/gitlab/issuables_count_for_state.rb57
-rw-r--r--lib/gitlab/job_waiter.rb17
-rw-r--r--lib/gitlab/kubernetes/kube_client.rb15
-rw-r--r--lib/gitlab/kubernetes/pod.rb36
-rw-r--r--lib/gitlab/lfs/client.rb44
-rw-r--r--lib/gitlab/manifest_import/metadata.rb49
-rw-r--r--lib/gitlab/marginalia.rb10
-rw-r--r--lib/gitlab/marginalia/active_record_instrumentation.rb2
-rw-r--r--lib/gitlab/markdown_cache.rb2
-rw-r--r--lib/gitlab/metrics/dashboard/importers/prometheus_metrics.rb49
-rw-r--r--lib/gitlab/metrics/dashboard/stages/custom_dashboard_metrics_inserter.rb24
-rw-r--r--lib/gitlab/metrics/dashboard/stages/url_validator.rb2
-rw-r--r--lib/gitlab/metrics/dashboard/transformers/errors.rb6
-rw-r--r--lib/gitlab/metrics/requests_rack_middleware.rb43
-rw-r--r--lib/gitlab/metrics/samplers/unicorn_sampler.rb2
-rw-r--r--lib/gitlab/metrics/subscribers/active_record.rb2
-rw-r--r--lib/gitlab/middleware/go.rb9
-rw-r--r--lib/gitlab/middleware/handle_null_bytes.rb61
-rw-r--r--lib/gitlab/middleware/multipart.rb3
-rw-r--r--lib/gitlab/pagination/offset_pagination.rb10
-rw-r--r--lib/gitlab/project_search_results.rb4
-rw-r--r--lib/gitlab/project_template.rb58
-rw-r--r--lib/gitlab/quick_actions/issuable_actions.rb12
-rw-r--r--lib/gitlab/quick_actions/merge_request_actions.rb14
-rw-r--r--lib/gitlab/redis/hll.rb20
-rw-r--r--lib/gitlab/regex.rb90
-rw-r--r--lib/gitlab/relative_positioning/item_context.rb4
-rw-r--r--lib/gitlab/repo_path.rb15
-rw-r--r--lib/gitlab/repository_size_checker.rb11
-rw-r--r--lib/gitlab/sample_data_template.rb22
-rw-r--r--lib/gitlab/search/recent_items.rb21
-rw-r--r--lib/gitlab/search_results.rb67
-rw-r--r--lib/gitlab/seeder.rb11
-rw-r--r--lib/gitlab/sidekiq_daemon/memory_killer.rb2
-rw-r--r--lib/gitlab/sidekiq_middleware/worker_context/server.rb6
-rw-r--r--lib/gitlab/slash_commands/presenters/help.rb2
-rw-r--r--lib/gitlab/static_site_editor/config/file_config.rb35
-rw-r--r--lib/gitlab/static_site_editor/config/file_config/entry/global.rb39
-rw-r--r--lib/gitlab/static_site_editor/config/file_config/entry/image_upload_path.rb26
-rw-r--r--lib/gitlab/static_site_editor/config/file_config/entry/mount.rb39
-rw-r--r--lib/gitlab/static_site_editor/config/file_config/entry/mounts.rb33
-rw-r--r--lib/gitlab/static_site_editor/config/file_config/entry/static_site_generator.rb26
-rw-r--r--lib/gitlab/static_site_editor/config/generated_config.rb12
-rw-r--r--lib/gitlab/subscription_portal.rb11
-rw-r--r--lib/gitlab/template/gitlab_ci_yml_template.rb2
-rw-r--r--lib/gitlab/themes.rb24
-rw-r--r--lib/gitlab/usage_data.rb104
-rw-r--r--lib/gitlab/usage_data_counters/hll_redis_counter.rb3
-rw-r--r--lib/gitlab/usage_data_counters/issue_activity_unique_counter.rb124
-rw-r--r--lib/gitlab/usage_data_counters/known_events.yml97
-rw-r--r--lib/gitlab/usage_data_counters/static_site_editor_counter.rb16
-rw-r--r--lib/gitlab/usage_data_queries.rb2
-rw-r--r--lib/gitlab/utils/usage_data.rb5
-rw-r--r--lib/gitlab/view/presenter/factory.rb2
-rw-r--r--lib/gitlab/visibility_level_checker.rb2
-rw-r--r--lib/gitlab/webpack/dev_server_middleware.rb9
-rw-r--r--lib/gitlab/webpack/manifest.rb108
-rw-r--r--lib/gitlab/whats_new.rb28
-rw-r--r--lib/gitlab/workhorse.rb3
-rw-r--r--lib/gitlab_danger.rb3
-rw-r--r--lib/google_api/cloud_platform/client.rb2
-rw-r--r--lib/grafana/client.rb4
-rw-r--r--lib/pager_duty/validator/schemas/message.json47
-rw-r--r--lib/pager_duty/webhook_payload_parser.rb12
-rw-r--r--lib/peek/views/active_record.rb25
-rw-r--r--lib/peek/views/detailed_view.rb2
-rw-r--r--lib/safe_zip/extract.rb22
-rw-r--r--lib/sentry/client/issue.rb4
-rw-r--r--lib/system_check/app/redis_version_check.rb2
-rw-r--r--lib/tasks/gettext.rake2
-rw-r--r--lib/tasks/gitlab/assets.rake2
-rw-r--r--lib/tasks/gitlab/backup.rake4
-rw-r--r--lib/tasks/gitlab/db.rake34
-rw-r--r--lib/tasks/gitlab/web_hook.rake5
-rw-r--r--lib/uploaded_file.rb7
-rw-r--r--locale/am_ET/gitlab.po1719
-rw-r--r--locale/ar_SA/gitlab.po1785
-rw-r--r--locale/as_IN/gitlab.po1717
-rw-r--r--locale/az_AZ/gitlab.po1717
-rw-r--r--locale/ba_RU/gitlab.po1700
-rw-r--r--locale/bg/gitlab.po1717
-rw-r--r--locale/bn_BD/gitlab.po1717
-rw-r--r--locale/bn_IN/gitlab.po1717
-rw-r--r--locale/bs_BA/gitlab.po1738
-rw-r--r--locale/ca_ES/gitlab.po1721
-rw-r--r--locale/cs_CZ/gitlab.po1823
-rw-r--r--locale/cy_GB/gitlab.po1785
-rw-r--r--locale/da_DK/gitlab.po1717
-rw-r--r--locale/de/gitlab.po1745
-rw-r--r--locale/el_GR/gitlab.po1717
-rw-r--r--locale/eo/gitlab.po1717
-rw-r--r--locale/es/gitlab.po1835
-rw-r--r--locale/et_EE/gitlab.po1717
-rw-r--r--locale/fa_IR/gitlab.po1717
-rw-r--r--locale/fi_FI/gitlab.po1717
-rw-r--r--locale/fil_PH/gitlab.po1717
-rw-r--r--locale/fr/gitlab.po1741
-rw-r--r--locale/gitlab.pot1921
-rw-r--r--locale/gl_ES/gitlab.po1735
-rw-r--r--locale/he_IL/gitlab.po1751
-rw-r--r--locale/hi_IN/gitlab.po1717
-rw-r--r--locale/hr_HR/gitlab.po1734
-rw-r--r--locale/hu_HU/gitlab.po1717
-rw-r--r--locale/id_ID/gitlab.po1700
-rw-r--r--locale/ig_NG/gitlab.po1700
-rw-r--r--locale/is_IS/gitlab.po1717
-rw-r--r--locale/it/gitlab.po1719
-rw-r--r--locale/ja/gitlab.po1942
-rw-r--r--locale/ka_GE/gitlab.po1717
-rw-r--r--locale/kab/gitlab.po1717
-rw-r--r--locale/ko/gitlab.po1726
-rw-r--r--locale/ku_TR/gitlab.po1717
-rw-r--r--locale/ky_KG/gitlab.po1717
-rw-r--r--locale/lt_LT/gitlab.po1751
-rw-r--r--locale/mn_MN/gitlab.po1717
-rw-r--r--locale/nb_NO/gitlab.po14217
-rw-r--r--locale/nl_NL/gitlab.po1717
-rw-r--r--locale/pa_IN/gitlab.po1717
-rw-r--r--locale/pl_PL/gitlab.po1753
-rw-r--r--locale/pt_BR/gitlab.po1765
-rw-r--r--locale/pt_PT/gitlab.po1739
-rw-r--r--locale/ro_RO/gitlab.po1734
-rw-r--r--locale/ru/gitlab.po2211
-rw-r--r--locale/si_LK/gitlab.po1717
-rw-r--r--locale/sk_SK/gitlab.po1751
-rw-r--r--locale/sl_SI/gitlab.po1751
-rw-r--r--locale/sq_AL/gitlab.po1717
-rw-r--r--locale/sr_CS/gitlab.po1734
-rw-r--r--locale/sr_SP/gitlab.po1734
-rw-r--r--locale/sv_SE/gitlab.po1717
-rw-r--r--locale/sw_KE/gitlab.po1717
-rw-r--r--locale/tr_TR/gitlab.po2209
-rw-r--r--locale/uk/gitlab.po3113
-rw-r--r--locale/unfound_translations.rb1
-rw-r--r--locale/ur_PK/gitlab.po1717
-rw-r--r--locale/uz_UZ/gitlab.po1717
-rw-r--r--locale/vi_VN/gitlab.po1700
-rw-r--r--locale/zh_CN/gitlab.po1908
-rw-r--r--locale/zh_HK/gitlab.po1702
-rw-r--r--locale/zh_TW/gitlab.po1712
-rw-r--r--package.json42
-rw-r--r--qa/Gemfile2
-rw-r--r--qa/Gemfile.lock14
-rw-r--r--qa/README.md2
-rw-r--r--qa/Rakefile6
-rw-r--r--qa/qa.rb7
-rw-r--r--qa/qa/fixtures/designs/banana_sample.gif (renamed from qa/spec/fixtures/banana_sample.gif)bin71759 -> 71759 bytes
-rw-r--r--qa/qa/fixtures/designs/tanuki.jpgbin0 -> 84616 bytes
-rw-r--r--qa/qa/fixtures/designs/update/tanuki.jpgbin0 -> 83907 bytes
-rw-r--r--qa/qa/fixtures/designs/values.pngbin0 -> 122101 bytes
-rw-r--r--qa/qa/flow/login.rb1
-rw-r--r--qa/qa/flow/merge_request.rb15
-rw-r--r--qa/qa/git/repository.rb138
-rw-r--r--qa/qa/page/component/design_management.rb43
-rw-r--r--qa/qa/page/component/issuable/sidebar.rb33
-rw-r--r--qa/qa/page/component/new_snippet.rb39
-rw-r--r--qa/qa/page/component/note.rb66
-rw-r--r--qa/qa/page/component/select2.rb2
-rw-r--r--qa/qa/page/component/snippet.rb38
-rw-r--r--qa/qa/page/dashboard/snippet/edit.rb9
-rw-r--r--qa/qa/page/dashboard/todos.rb33
-rw-r--r--qa/qa/page/main/sign_up.rb9
-rw-r--r--qa/qa/page/merge_request/show.rb80
-rw-r--r--qa/qa/page/profile/accounts/show.rb5
-rw-r--r--qa/qa/page/profile/ssh_keys.rb15
-rw-r--r--qa/qa/page/project/issue/show.rb12
-rw-r--r--qa/qa/page/project/job/show.rb6
-rw-r--r--qa/qa/page/project/new.rb6
-rw-r--r--qa/qa/page/project/operations/kubernetes/index.rb4
-rw-r--r--qa/qa/page/project/packages/index.rb2
-rw-r--r--qa/qa/page/project/pipeline/index.rb14
-rw-r--r--qa/qa/page/project/pipeline/new.rb19
-rw-r--r--qa/qa/page/project/pipeline/show.rb19
-rw-r--r--qa/qa/page/project/settings/ci_variables.rb4
-rw-r--r--qa/qa/page/project/show.rb2
-rw-r--r--qa/qa/page/project/snippet/index.rb29
-rw-r--r--qa/qa/page/project/web_ide/edit.rb14
-rw-r--r--qa/qa/page/project/wiki/show.rb2
-rw-r--r--qa/qa/resource/api_fabricator.rb35
-rw-r--r--qa/qa/resource/design.rb34
-rw-r--r--qa/qa/resource/events/base.rb7
-rw-r--r--qa/qa/resource/events/project.rb7
-rw-r--r--qa/qa/resource/file.rb13
-rw-r--r--qa/qa/resource/merge_request.rb46
-rw-r--r--qa/qa/resource/project.rb16
-rw-r--r--qa/qa/resource/project_snippet.rb7
-rw-r--r--qa/qa/resource/repository/push.rb5
-rw-r--r--qa/qa/resource/snippet.rb11
-rw-r--r--qa/qa/resource/ssh_key.rb9
-rw-r--r--qa/qa/resource/user.rb10
-rw-r--r--qa/qa/runtime/api/request.rb6
-rw-r--r--qa/qa/runtime/env.rb49
-rw-r--r--qa/qa/runtime/feature.rb169
-rw-r--r--qa/qa/service/praefect_manager.rb2
-rw-r--r--qa/qa/specs/features/api/3_create/gitaly/automatic_failover_and_recovery_spec.rb2
-rw-r--r--qa/qa/specs/features/api/3_create/gitaly/backend_node_recovery_spec.rb4
-rw-r--r--qa/qa/specs/features/api/3_create/gitaly/changing_repository_storage_spec.rb11
-rw-r--r--qa/qa/specs/features/api/3_create/gitaly/distributed_reads_spec.rb4
-rw-r--r--qa/qa/specs/features/api/3_create/merge_request/push_options_labels_spec.rb64
-rw-r--r--qa/qa/specs/features/api/3_create/merge_request/push_options_mwps_spec.rb124
-rw-r--r--qa/qa/specs/features/api/3_create/merge_request/push_options_remove_source_branch_spec.rb45
-rw-r--r--qa/qa/specs/features/api/3_create/merge_request/push_options_target_branch_spec.rb53
-rw-r--r--qa/qa/specs/features/api/3_create/merge_request/push_options_title_description_spec.rb49
-rw-r--r--qa/qa/specs/features/api/3_create/repository/default_branch_name_setting_spec.rb4
-rw-r--r--qa/qa/specs/features/api/3_create/repository/project_archive_compare_spec.rb7
-rw-r--r--qa/qa/specs/features/browser_ui/1_manage/login/2fa_ssh_recovery_spec.rb65
-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/2_plan/issue/create_issue_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/3_create/design_management/add_design_content_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/design_management/archive_design_content_spec.rb51
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/design_management/modify_design_content_spec.rb30
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/merge_request/view_merge_request_merge_ref_diff_spec.rb80
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/repository/create_edit_delete_file_via_web_spec.rb1
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/repository/protocol_v2_push_http_spec.rb6
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/repository/push_mirroring_lfs_over_http_spec.rb7
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/repository/push_over_http_file_size_spec.rb2
-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_protected_branch_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/snippet/clone_push_pull_personal_snippet_spec.rb6
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/snippet/clone_push_pull_project_snippet_spec.rb6
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/snippet/create_personal_snippet_with_multiple_files_spec.rb40
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/snippet/create_project_snippet_spec.rb4
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/snippet/create_project_snippet_with_multiple_files_spec.rb50
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/web_ide/create_first_file_in_web_ide_spec.rb7
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/wiki/project_based_directory_management_spec.rb6
-rw-r--r--qa/qa/specs/features/browser_ui/4_verify/ci_variable/add_remove_ci_variable_spec.rb31
-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/run_pipeline_via_web_only_spec.rb65
-rw-r--r--qa/qa/specs/features/browser_ui/4_verify/pipeline/trigger_child_pipeline_with_manual_spec.rb109
-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/view_code_coverage_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/5_package/maven_repository_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/5_package/npm_registry_spec.rb6
-rw-r--r--qa/qa/specs/features/browser_ui/6_release/deploy_key/clone_using_deploy_key_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/6_release/pipeline/parent_child_pipelines_dependent_relationship_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/6_release/pipeline/parent_child_pipelines_independent_relationship_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/sanity/framework_spec.rb2
-rw-r--r--qa/qa/specs/helpers/quarantine.rb4
-rw-r--r--qa/qa/support/api.rb2
-rw-r--r--qa/qa/support/json_formatter.rb3
-rw-r--r--qa/qa/support/otp.rb5
-rw-r--r--qa/qa/support/retrier.rb17
-rw-r--r--qa/qa/support/run.rb43
-rw-r--r--qa/qa/support/ssh.rb62
-rw-r--r--qa/qa/support/wait_for_requests.rb12
-rw-r--r--qa/qa/tools/initialize_gitlab_auth.rb30
-rw-r--r--qa/spec/factory/resource/user_spec.rb2
-rw-r--r--qa/spec/git/location_spec.rb2
-rw-r--r--qa/spec/git/repository_spec.rb84
-rw-r--r--qa/spec/page/base_spec.rb2
-rw-r--r--qa/spec/page/element_spec.rb2
-rw-r--r--qa/spec/page/logging_spec.rb2
-rw-r--r--qa/spec/page/validator_spec.rb2
-rw-r--r--qa/spec/page/view_spec.rb2
-rw-r--r--qa/spec/resource/api_fabricator_spec.rb2
-rw-r--r--qa/spec/resource/base_spec.rb2
-rw-r--r--qa/spec/resource/events/base_spec.rb2
-rw-r--r--qa/spec/resource/events/project_spec.rb2
-rw-r--r--qa/spec/resource/repository/push_spec.rb2
-rw-r--r--qa/spec/resource/ssh_key_spec.rb2
-rw-r--r--qa/spec/resource/user_spec.rb2
-rw-r--r--qa/spec/runtime/api/client_spec.rb2
-rw-r--r--qa/spec/runtime/api/request_spec.rb2
-rw-r--r--qa/spec/runtime/application_settings_spec.rb2
-rw-r--r--qa/spec/runtime/env_spec.rb20
-rw-r--r--qa/spec/runtime/feature_spec.rb252
-rw-r--r--qa/spec/runtime/key/ecdsa_spec.rb2
-rw-r--r--qa/spec/runtime/key/ed25519_spec.rb2
-rw-r--r--qa/spec/runtime/key/rsa_spec.rb2
-rw-r--r--qa/spec/runtime/logger_spec.rb2
-rw-r--r--qa/spec/runtime/namespace_spec.rb2
-rw-r--r--qa/spec/runtime/release_spec.rb2
-rw-r--r--qa/spec/runtime/scenario_spec.rb2
-rw-r--r--qa/spec/scenario/actable_spec.rb2
-rw-r--r--qa/spec/scenario/bootable_spec.rb2
-rw-r--r--qa/spec/scenario/template_spec.rb2
-rw-r--r--qa/spec/scenario/test/instance/airgapped_spec.rb2
-rw-r--r--qa/spec/scenario/test/instance/all_spec.rb2
-rw-r--r--qa/spec/scenario/test/instance/smoke_spec.rb2
-rw-r--r--qa/spec/scenario/test/integration/github_spec.rb2
-rw-r--r--qa/spec/scenario/test/integration/instance_saml_spec.rb2
-rw-r--r--qa/spec/scenario/test/integration/kubernetes_spec.rb2
-rw-r--r--qa/spec/scenario/test/integration/ldap_spec.rb6
-rw-r--r--qa/spec/scenario/test/integration/mattermost_spec.rb2
-rw-r--r--qa/spec/scenario/test/integration/object_storage_spec.rb2
-rw-r--r--qa/spec/scenario/test/sanity/framework_spec.rb2
-rw-r--r--qa/spec/scenario/test/sanity/selectors_spec.rb2
-rw-r--r--qa/spec/specs/helpers/quarantine_spec.rb71
-rw-r--r--qa/spec/specs/parallel_runner_spec.rb2
-rw-r--r--qa/spec/specs/runner_spec.rb2
-rw-r--r--qa/spec/support/repeater_spec.rb2
-rw-r--r--qa/spec/support/retrier_spec.rb2
-rw-r--r--qa/spec/support/run_spec.rb27
-rw-r--r--qa/spec/support/ssh_spec.rb114
-rw-r--r--qa/spec/support/wait_for_requests_spec.rb3
-rw-r--r--qa/spec/support/waiter_spec.rb2
-rw-r--r--rubocop/cop/api/base.rb53
-rw-r--r--rubocop/cop/api/grape_api_instance.rb42
-rw-r--r--rubocop/cop/code_reuse/active_record.rb35
-rw-r--r--rubocop/cop/graphql/gid_expected_type.rb21
-rw-r--r--rubocop/cop/graphql/id_type.rb29
-rw-r--r--rubocop/cop/migration/add_concurrent_foreign_key.rb20
-rw-r--r--rubocop/cop/migration/add_limit_to_text_columns.rb10
-rw-r--r--rubocop/cop/migration/create_table_with_foreign_keys.rb2
-rw-r--r--rubocop/cop/migration/with_lock_retries_disallowed_method.rb18
-rw-r--r--rubocop/cop/rspec/expect_gitlab_tracking.rb66
-rw-r--r--rubocop/cop/rspec/factory_bot/inline_association.rb109
-rw-r--r--rubocop/cop/rspec/timecop_travel.rb41
-rw-r--r--rubocop/migration_helpers.rb2
-rw-r--r--rubocop/rubocop-migrations.yml3
-rw-r--r--rubocop/rubocop-usage-data.yml2
-rwxr-xr-xscripts/docs_screenshots.rb2
-rwxr-xr-xscripts/lint-doc.sh6
-rw-r--r--scripts/prepare_build.sh6
-rwxr-xr-xscripts/review_apps/review-apps.sh12
-rwxr-xr-xscripts/slack10
-rwxr-xr-xscripts/used-feature-flags94
-rw-r--r--spec/bin/feature_flag_spec.rb13
-rw-r--r--spec/channels/application_cable/connection_spec.rb52
-rw-r--r--spec/config/object_store_settings_spec.rb15
-rw-r--r--spec/controllers/admin/application_settings_controller_spec.rb38
-rw-r--r--spec/controllers/admin/clusters_controller_spec.rb5
-rw-r--r--spec/controllers/admin/hooks_controller_spec.rb8
-rw-r--r--spec/controllers/admin/instance_review_controller_spec.rb68
-rw-r--r--spec/controllers/admin/integrations_controller_spec.rb14
-rw-r--r--spec/controllers/admin/runners_controller_spec.rb17
-rw-r--r--spec/controllers/admin/sessions_controller_spec.rb2
-rw-r--r--spec/controllers/admin/users_controller_spec.rb90
-rw-r--r--spec/controllers/application_controller_spec.rb12
-rw-r--r--spec/controllers/boards/lists_controller_spec.rb11
-rw-r--r--spec/controllers/concerns/controller_with_feature_category/config_spec.rb53
-rw-r--r--spec/controllers/concerns/controller_with_feature_category_spec.rb38
-rw-r--r--spec/controllers/concerns/issuable_collections_spec.rb34
-rw-r--r--spec/controllers/concerns/redis_tracking_spec.rb99
-rw-r--r--spec/controllers/dashboard/labels_controller_spec.rb23
-rw-r--r--spec/controllers/dashboard_controller_spec.rb10
-rw-r--r--spec/controllers/every_controller_spec.rb20
-rw-r--r--spec/controllers/graphql_controller_spec.rb10
-rw-r--r--spec/controllers/groups/clusters_controller_spec.rb5
-rw-r--r--spec/controllers/groups/group_links_controller_spec.rb54
-rw-r--r--spec/controllers/groups/group_members_controller_spec.rb38
-rw-r--r--spec/controllers/groups/labels_controller_spec.rb79
-rw-r--r--spec/controllers/groups/milestones_controller_spec.rb7
-rw-r--r--spec/controllers/groups/registry/repositories_controller_spec.rb2
-rw-r--r--spec/controllers/groups/settings/ci_cd_controller_spec.rb21
-rw-r--r--spec/controllers/groups_controller_spec.rb98
-rw-r--r--spec/controllers/help_controller_spec.rb63
-rw-r--r--spec/controllers/import/bulk_imports_controller_spec.rb179
-rw-r--r--spec/controllers/import/manifest_controller_spec.rb99
-rw-r--r--spec/controllers/invites_controller_spec.rb89
-rw-r--r--spec/controllers/jira_connect/events_controller_spec.rb37
-rw-r--r--spec/controllers/profiles_controller_spec.rb13
-rw-r--r--spec/controllers/projects/alert_management_controller_spec.rb2
-rw-r--r--spec/controllers/projects/blob_controller_spec.rb4
-rw-r--r--spec/controllers/projects/clusters_controller_spec.rb6
-rw-r--r--spec/controllers/projects/feature_flags_clients_controller_spec.rb57
-rw-r--r--spec/controllers/projects/feature_flags_controller_spec.rb1604
-rw-r--r--spec/controllers/projects/feature_flags_user_lists_controller_spec.rb113
-rw-r--r--spec/controllers/projects/group_links_controller_spec.rb51
-rw-r--r--spec/controllers/projects/hooks_controller_spec.rb8
-rw-r--r--spec/controllers/projects/import/jira_controller_spec.rb2
-rw-r--r--spec/controllers/projects/incidents_controller_spec.rb103
-rw-r--r--spec/controllers/projects/issues_controller_spec.rb18
-rw-r--r--spec/controllers/projects/jobs_controller_spec.rb94
-rw-r--r--spec/controllers/projects/labels_controller_spec.rb95
-rw-r--r--spec/controllers/projects/merge_requests/conflicts_controller_spec.rb2
-rw-r--r--spec/controllers/projects/milestones_controller_spec.rb4
-rw-r--r--spec/controllers/projects/pipelines/stages_controller_spec.rb11
-rw-r--r--spec/controllers/projects/pipelines_controller_spec.rb80
-rw-r--r--spec/controllers/projects/project_members_controller_spec.rb52
-rw-r--r--spec/controllers/projects/registry/tags_controller_spec.rb2
-rw-r--r--spec/controllers/projects/releases/evidences_controller_spec.rb32
-rw-r--r--spec/controllers/projects/releases_controller_spec.rb8
-rw-r--r--spec/controllers/projects/runners_controller_spec.rb41
-rw-r--r--spec/controllers/projects/serverless/functions_controller_spec.rb16
-rw-r--r--spec/controllers/projects/settings/access_tokens_controller_spec.rb171
-rw-r--r--spec/controllers/projects/settings/ci_cd_controller_spec.rb32
-rw-r--r--spec/controllers/projects/settings/operations_controller_spec.rb115
-rw-r--r--spec/controllers/projects/snippets_controller_spec.rb283
-rw-r--r--spec/controllers/projects/static_site_editor_controller_spec.rb92
-rw-r--r--spec/controllers/projects/tags_controller_spec.rb21
-rw-r--r--spec/controllers/projects/tracings_controller_spec.rb62
-rw-r--r--spec/controllers/projects/web_ide_terminals_controller_spec.rb23
-rw-r--r--spec/controllers/projects_controller_spec.rb4
-rw-r--r--spec/controllers/registrations/experience_levels_controller_spec.rb49
-rw-r--r--spec/controllers/registrations_controller_spec.rb282
-rw-r--r--spec/controllers/runner_setup_controller_spec.rb21
-rw-r--r--spec/controllers/search_controller_spec.rb2
-rw-r--r--spec/controllers/sessions_controller_spec.rb33
-rw-r--r--spec/controllers/snippets_controller_spec.rb338
-rw-r--r--spec/db/schema_spec.rb39
-rw-r--r--spec/factories/alert_management/alerts.rb22
-rw-r--r--spec/factories/alert_management/http_integrations.rb14
-rw-r--r--spec/factories/alerting/alert.rb25
-rw-r--r--spec/factories/authentication_event.rb11
-rw-r--r--spec/factories/bulk_import.rb8
-rw-r--r--spec/factories/bulk_import/entities.rb21
-rw-r--r--spec/factories/ci/bridge.rb13
-rw-r--r--spec/factories/ci/build_pending_states.rb2
-rw-r--r--spec/factories/ci/build_trace_chunks.rb13
-rw-r--r--spec/factories/ci/builds.rb3
-rw-r--r--spec/factories/ci/deleted_object.rb9
-rw-r--r--spec/factories/ci/pipelines.rb18
-rw-r--r--spec/factories/ci/test_case.rb2
-rw-r--r--spec/factories/design_management/designs.rb2
-rw-r--r--spec/factories/events.rb11
-rw-r--r--spec/factories/group_import_states.rb1
-rw-r--r--spec/factories/groups.rb4
-rw-r--r--spec/factories/instance_statistics/measurement.rb8
-rw-r--r--spec/factories/issue_email_participants.rb8
-rw-r--r--spec/factories/merge_request_diffs.rb8
-rw-r--r--spec/factories/merge_requests.rb6
-rw-r--r--spec/factories/namespaces.rb8
-rw-r--r--spec/factories/packages.rb164
-rw-r--r--spec/factories/packages/package_file.rb165
-rw-r--r--spec/factories/pages_deployments.rb9
-rw-r--r--spec/factories/project_repository_storage_moves.rb1
-rw-r--r--spec/factories/project_tracing_settings.rb8
-rw-r--r--spec/factories/projects.rb8
-rw-r--r--spec/factories/prometheus_alert.rb4
-rw-r--r--spec/factories/prometheus_metrics.rb1
-rw-r--r--spec/factories/resource_weight_events.rb8
-rw-r--r--spec/factories/services.rb6
-rw-r--r--spec/factories/terraform/state.rb10
-rw-r--r--spec/factories/terraform/state_version.rb8
-rw-r--r--spec/factories/todos.rb4
-rw-r--r--spec/factories/usage_data.rb23
-rw-r--r--spec/factories/users.rb8
-rw-r--r--spec/factories/wiki_pages.rb3
-rw-r--r--spec/factories/wikis.rb6
-rw-r--r--spec/factories_spec.rb30
-rw-r--r--spec/features/admin/admin_groups_spec.rb2
-rw-r--r--spec/features/admin/admin_mode/login_spec.rb10
-rw-r--r--spec/features/admin/admin_settings_spec.rb37
-rw-r--r--spec/features/admin/admin_users_spec.rb97
-rw-r--r--spec/features/admin/admin_uses_repository_checks_spec.rb2
-rw-r--r--spec/features/admin/clusters/eks_spec.rb2
-rw-r--r--spec/features/admin/dashboard_spec.rb6
-rw-r--r--spec/features/alert_management/alert_details_spec.rb86
-rw-r--r--spec/features/alert_management/alert_management_list_spec.rb58
-rw-r--r--spec/features/alert_management/user_filters_alerts_by_status_spec.rb56
-rw-r--r--spec/features/alert_management/user_searches_alerts_spec.rb31
-rw-r--r--spec/features/alert_management/user_updates_alert_status_spec.rb36
-rw-r--r--spec/features/alert_management_spec.rb62
-rw-r--r--spec/features/boards/add_issues_modal_spec.rb12
-rw-r--r--spec/features/boards/boards_spec.rb40
-rw-r--r--spec/features/boards/sidebar_spec.rb2
-rw-r--r--spec/features/calendar_spec.rb2
-rw-r--r--spec/features/clusters/cluster_detail_page_spec.rb12
-rw-r--r--spec/features/commits_spec.rb1
-rw-r--r--spec/features/dashboard/issuables_counter_spec.rb4
-rw-r--r--spec/features/dashboard/merge_requests_spec.rb6
-rw-r--r--spec/features/dashboard/todos/todos_filtering_spec.rb8
-rw-r--r--spec/features/dashboard/todos/todos_spec.rb19
-rw-r--r--spec/features/discussion_comments/snippets_spec.rb1
-rw-r--r--spec/features/expand_collapse_diffs_spec.rb1
-rw-r--r--spec/features/file_uploads/maven_package_spec.rb26
-rw-r--r--spec/features/groups/clusters/eks_spec.rb2
-rw-r--r--spec/features/groups/clusters/user_spec.rb8
-rw-r--r--spec/features/groups/members/leave_group_spec.rb2
-rw-r--r--spec/features/groups/members/manage_groups_spec.rb113
-rw-r--r--spec/features/groups/members/master_adds_member_with_expiration_date_spec.rb75
-rw-r--r--spec/features/groups/navbar_spec.rb8
-rw-r--r--spec/features/groups/packages_spec.rb2
-rw-r--r--spec/features/groups/show_spec.rb13
-rw-r--r--spec/features/incidents/incident_details_spec.rb52
-rw-r--r--spec/features/incidents/incidents_list_spec.rb38
-rw-r--r--spec/features/incidents/user_creates_new_incident_spec.rb55
-rw-r--r--spec/features/incidents/user_filters_incidents_by_status_spec.rb59
-rw-r--r--spec/features/incidents/user_searches_incidents_spec.rb30
-rw-r--r--spec/features/invites_spec.rb48
-rw-r--r--spec/features/issuables/close_reopen_report_toggle_spec.rb12
-rw-r--r--spec/features/issuables/issuable_list_spec.rb8
-rw-r--r--spec/features/issuables/markdown_references/internal_references_spec.rb8
-rw-r--r--spec/features/issuables/merge_request_discussion_lock_spec.rb79
-rw-r--r--spec/features/issues/csv_spec.rb4
-rw-r--r--spec/features/issues/gfm_autocomplete_spec.rb24
-rw-r--r--spec/features/issues/issue_sidebar_spec.rb136
-rw-r--r--spec/features/issues/todo_spec.rb4
-rw-r--r--spec/features/issues/user_edits_issue_spec.rb436
-rw-r--r--spec/features/issues/user_sees_live_update_spec.rb2
-rw-r--r--spec/features/issues/user_views_issue_spec.rb4
-rw-r--r--spec/features/labels_hierarchy_spec.rb1
-rw-r--r--spec/features/merge_request/batch_comments_spec.rb15
-rw-r--r--spec/features/merge_request/maintainer_edits_fork_spec.rb7
-rw-r--r--spec/features/merge_request/user_comments_on_diff_spec.rb9
-rw-r--r--spec/features/merge_request/user_edits_assignees_sidebar_spec.rb47
-rw-r--r--spec/features/merge_request/user_edits_mr_spec.rb18
-rw-r--r--spec/features/merge_request/user_expands_diff_spec.rb1
-rw-r--r--spec/features/merge_request/user_marks_merge_request_as_draft_spec.rb29
-rw-r--r--spec/features/merge_request/user_merges_when_pipeline_succeeds_spec.rb2
-rw-r--r--spec/features/merge_request/user_reopens_merge_request_spec.rb6
-rw-r--r--spec/features/merge_request/user_resolves_wip_mr_spec.rb4
-rw-r--r--spec/features/merge_request/user_sees_diff_spec.rb3
-rw-r--r--spec/features/merge_request/user_sees_page_metadata_spec.rb17
-rw-r--r--spec/features/merge_request/user_sees_pipelines_spec.rb4
-rw-r--r--spec/features/merge_request/user_sees_suggest_pipeline_spec.rb35
-rw-r--r--spec/features/merge_request/user_suggests_changes_on_diff_spec.rb7
-rw-r--r--spec/features/merge_request/user_views_open_merge_request_spec.rb19
-rw-r--r--spec/features/merge_requests/user_filters_by_approvals_spec.rb82
-rw-r--r--spec/features/merge_requests/user_filters_by_deployments_spec.rb93
-rw-r--r--spec/features/merge_requests/user_lists_merge_requests_spec.rb37
-rw-r--r--spec/features/milestone_spec.rb4
-rw-r--r--spec/features/milestones/user_views_milestone_spec.rb76
-rw-r--r--spec/features/milestones/user_views_milestones_spec.rb3
-rw-r--r--spec/features/operations_sidebar_link_spec.rb81
-rw-r--r--spec/features/profiles/keys_spec.rb36
-rw-r--r--spec/features/projects/activity/user_sees_design_comment_spec.rb2
-rw-r--r--spec/features/projects/badges/list_spec.rb8
-rw-r--r--spec/features/projects/blobs/edit_spec.rb16
-rw-r--r--spec/features/projects/blobs/user_creates_new_blob_in_new_project_spec.rb17
-rw-r--r--spec/features/projects/blobs/user_follows_pipeline_suggest_nudge_spec.rb2
-rw-r--r--spec/features/projects/branches/user_deletes_branch_spec.rb2
-rw-r--r--spec/features/projects/branches_spec.rb8
-rw-r--r--spec/features/projects/ci/lint_spec.rb137
-rw-r--r--spec/features/projects/clusters/eks_spec.rb2
-rw-r--r--spec/features/projects/clusters/gcp_spec.rb12
-rw-r--r--spec/features/projects/clusters/user_spec.rb8
-rw-r--r--spec/features/projects/clusters_spec.rb16
-rw-r--r--spec/features/projects/commit/builds_spec.rb2
-rw-r--r--spec/features/projects/commit/user_comments_on_commit_spec.rb48
-rw-r--r--spec/features/projects/compare_spec.rb2
-rw-r--r--spec/features/projects/environments/environment_spec.rb2
-rw-r--r--spec/features/projects/environments/environments_spec.rb4
-rw-r--r--spec/features/projects/feature_flag_user_lists/user_deletes_feature_flag_user_list_spec.rb63
-rw-r--r--spec/features/projects/feature_flag_user_lists/user_edits_feature_flag_user_list_spec.rb21
-rw-r--r--spec/features/projects/feature_flag_user_lists/user_sees_feature_flag_user_list_details_spec.rb21
-rw-r--r--spec/features/projects/feature_flags/user_creates_feature_flag_spec.rb200
-rw-r--r--spec/features/projects/feature_flags/user_deletes_feature_flag_spec.rb31
-rw-r--r--spec/features/projects/feature_flags/user_sees_feature_flag_list_spec.rb147
-rw-r--r--spec/features/projects/feature_flags/user_updates_feature_flag_spec.rb195
-rw-r--r--spec/features/projects/features_visibility_spec.rb2
-rw-r--r--spec/features/projects/files/project_owner_sees_link_to_create_license_file_in_empty_project_spec.rb41
-rw-r--r--spec/features/projects/files/user_browses_lfs_files_spec.rb24
-rw-r--r--spec/features/projects/files/user_creates_files_spec.rb6
-rw-r--r--spec/features/projects/files/user_edits_files_spec.rb173
-rw-r--r--spec/features/projects/issues/design_management/user_links_to_designs_in_issue_spec.rb29
-rw-r--r--spec/features/projects/issues/viewing_relocated_issues_spec.rb40
-rw-r--r--spec/features/projects/jobs/user_browses_job_spec.rb4
-rw-r--r--spec/features/projects/members/groups_with_access_list_spec.rb43
-rw-r--r--spec/features/projects/members/list_spec.rb2
-rw-r--r--spec/features/projects/members/master_adds_member_with_expiration_date_spec.rb75
-rw-r--r--spec/features/projects/navbar_spec.rb10
-rw-r--r--spec/features/projects/pages_spec.rb2
-rw-r--r--spec/features/projects/pipelines/pipeline_spec.rb17
-rw-r--r--spec/features/projects/pipelines/pipelines_spec.rb4
-rw-r--r--spec/features/projects/releases/user_creates_release_spec.rb31
-rw-r--r--spec/features/projects/releases/user_views_edit_release_spec.rb49
-rw-r--r--spec/features/projects/releases/user_views_release_spec.rb55
-rw-r--r--spec/features/projects/releases/user_views_releases_spec.rb68
-rw-r--r--spec/features/projects/settings/pipelines_settings_spec.rb4
-rw-r--r--spec/features/projects/settings/registry_settings_spec.rb70
-rw-r--r--spec/features/projects/show/user_manages_notifications_spec.rb8
-rw-r--r--spec/features/projects/show/user_sees_setup_shortcut_buttons_spec.rb22
-rw-r--r--spec/features/projects/snippets/create_snippet_spec.rb134
-rw-r--r--spec/features/projects/snippets/show_spec.rb10
-rw-r--r--spec/features/projects/snippets/user_comments_on_snippet_spec.rb1
-rw-r--r--spec/features/projects/snippets/user_deletes_snippet_spec.rb11
-rw-r--r--spec/features/projects/snippets/user_updates_snippet_spec.rb70
-rw-r--r--spec/features/projects/tracings_spec.rb63
-rw-r--r--spec/features/projects/tree/tree_show_spec.rb2
-rw-r--r--spec/features/projects/user_sees_sidebar_spec.rb61
-rw-r--r--spec/features/projects/wiki/markdown_preview_spec.rb168
-rw-r--r--spec/features/projects/wiki/shortcuts_spec.rb20
-rw-r--r--spec/features/projects/wiki/user_creates_wiki_page_spec.rb360
-rw-r--r--spec/features/projects/wiki/user_deletes_wiki_page_spec.rb22
-rw-r--r--spec/features/projects/wiki/user_updates_wiki_page_spec.rb263
-rw-r--r--spec/features/projects/wiki/user_views_wiki_empty_spec.rb138
-rw-r--r--spec/features/projects/wiki/user_views_wiki_page_spec.rb276
-rw-r--r--spec/features/projects/wiki/user_views_wiki_pages_spec.rb91
-rw-r--r--spec/features/projects/wiki/users_views_asciidoc_page_with_includes_spec.rb79
-rw-r--r--spec/features/projects/wikis_spec.rb20
-rw-r--r--spec/features/projects_spec.rb37
-rw-r--r--spec/features/protected_branches_spec.rb16
-rw-r--r--spec/features/reportable_note/snippets_spec.rb1
-rw-r--r--spec/features/runners_spec.rb4
-rw-r--r--spec/features/search/user_searches_for_code_spec.rb1
-rw-r--r--spec/features/search/user_uses_header_search_field_spec.rb26
-rw-r--r--spec/features/search/user_uses_search_filters_spec.rb38
-rw-r--r--spec/features/sentry_js_spec.rb2
-rw-r--r--spec/features/snippets/internal_snippet_spec.rb11
-rw-r--r--spec/features/snippets/notes_on_personal_snippets_spec.rb1
-rw-r--r--spec/features/snippets/private_snippets_spec.rb7
-rw-r--r--spec/features/snippets/public_snippets_spec.rb19
-rw-r--r--spec/features/snippets/show_spec.rb12
-rw-r--r--spec/features/snippets/spam_snippets_spec.rb25
-rw-r--r--spec/features/snippets/user_creates_snippet_spec.rb196
-rw-r--r--spec/features/snippets/user_deletes_snippet_spec.rb12
-rw-r--r--spec/features/snippets/user_edits_snippet_spec.rb128
-rw-r--r--spec/features/snippets_spec.rb12
-rw-r--r--spec/features/static_site_editor_spec.rb67
-rw-r--r--spec/features/tags/developer_deletes_tag_spec.rb27
-rw-r--r--spec/features/tags/developer_views_tags_spec.rb13
-rw-r--r--spec/features/task_lists_spec.rb115
-rw-r--r--spec/features/triggers_spec.rb186
-rw-r--r--spec/features/users/overview_spec.rb70
-rw-r--r--spec/features/users/show_spec.rb52
-rw-r--r--spec/features/users/signup_spec.rb214
-rw-r--r--spec/features/users/terms_spec.rb15
-rw-r--r--spec/finders/alert_management/alerts_finder_spec.rb115
-rw-r--r--spec/finders/ci/pipelines_for_merge_request_finder_spec.rb2
-rw-r--r--spec/finders/environment_names_finder_spec.rb63
-rw-r--r--spec/finders/group_labels_finder_spec.rb42
-rw-r--r--spec/finders/groups_finder_spec.rb56
-rw-r--r--spec/finders/issues_finder_spec.rb10
-rw-r--r--spec/finders/labels_finder_spec.rb36
-rw-r--r--spec/finders/merge_requests/by_approvals_finder_spec.rb82
-rw-r--r--spec/finders/merge_requests_finder_spec.rb87
-rw-r--r--spec/finders/packages/generic/package_finder_spec.rb31
-rw-r--r--spec/finders/projects_finder_spec.rb32
-rw-r--r--spec/finders/releases_finder_spec.rb28
-rw-r--r--spec/fixtures/api/schemas/entities/group_group_link.json13
-rw-r--r--spec/fixtures/api/schemas/entities/merge_request_basic.json1
-rw-r--r--spec/fixtures/api/schemas/entities/test_case.json1
-rw-r--r--spec/fixtures/api/schemas/entities/trigger.json39
-rw-r--r--spec/fixtures/api/schemas/environment.json7
-rw-r--r--spec/fixtures/api/schemas/feature_flag.json23
-rw-r--r--spec/fixtures/api/schemas/feature_flag_scope.json18
-rw-r--r--spec/fixtures/api/schemas/feature_flag_strategy.json13
-rw-r--r--spec/fixtures/api/schemas/feature_flags.json13
-rw-r--r--spec/fixtures/api/schemas/feature_flags_client_token.json10
-rw-r--r--spec/fixtures/api/schemas/group_member.json19
-rw-r--r--spec/fixtures/api/schemas/public_api/v4/feature_flag.json15
-rw-r--r--spec/fixtures/api/schemas/public_api/v4/feature_flag_detailed_scopes.json22
-rw-r--r--spec/fixtures/api/schemas/public_api/v4/feature_flag_scope.json17
-rw-r--r--spec/fixtures/api/schemas/public_api/v4/feature_flag_scopes.json9
-rw-r--r--spec/fixtures/api/schemas/public_api/v4/feature_flag_strategy.json13
-rw-r--r--spec/fixtures/api/schemas/public_api/v4/feature_flags.json9
-rw-r--r--spec/fixtures/api/schemas/public_api/v4/operations/scope.json9
-rw-r--r--spec/fixtures/api/schemas/public_api/v4/operations/strategy.json14
-rw-r--r--spec/fixtures/api/schemas/public_api/v4/packages/package.json3
-rw-r--r--spec/fixtures/api/schemas/registry/repository.json3
-rw-r--r--spec/fixtures/api/schemas/unleash/unleash.json20
-rw-r--r--spec/fixtures/api/schemas/unleash/unleash_feature.json27
-rw-r--r--spec/fixtures/api/schemas/unleash/unleash_strategy.json24
-rw-r--r--spec/fixtures/invalid_manifest.xml4
-rw-r--r--spec/fixtures/lib/backup/design_repo.bundlebin0 -> 490 bytes
-rw-r--r--spec/fixtures/lib/backup/personal_snippet_repo.bundlebin0 -> 686 bytes
-rw-r--r--spec/fixtures/lib/backup/project_repo.bundlebin0 -> 387 bytes
-rw-r--r--spec/fixtures/lib/backup/project_snippet_repo.bundlebin0 -> 696 bytes
-rw-r--r--spec/fixtures/lib/backup/wiki_repo.bundlebin0 -> 365 bytes
-rw-r--r--spec/fixtures/lib/gitlab/import_export/sample_data/tree/project.json1
-rw-r--r--spec/fixtures/lib/gitlab/import_export/sample_data/tree/project/issues.ndjson10
-rw-r--r--spec/fixtures/lib/gitlab/import_export/sample_data/tree/project/labels.ndjson2
-rw-r--r--spec/fixtures/lib/gitlab/import_export/sample_data/tree/project/milestones.ndjson3
-rw-r--r--spec/fixtures/packages/debian/libsample0_1.2.3~alpha2-1_amd64.deb1
-rw-r--r--spec/fixtures/packages/generic/myfile.tar.gzbin0 -> 1149 bytes
-rw-r--r--spec/frontend/alert_handler_spec.js65
-rw-r--r--spec/frontend/alert_management/components/alert_details_spec.js140
-rw-r--r--spec/frontend/alert_management/components/alert_management_empty_state_spec.js20
-rw-r--r--spec/frontend/alert_management/components/alert_management_list_wrapper_spec.js50
-rw-r--r--spec/frontend/alert_management/components/alert_management_table_spec.js370
-rw-r--r--spec/frontend/alert_management/components/alert_status_spec.js151
-rw-r--r--spec/frontend/alert_management/components/alert_summary_row_spec.js40
-rw-r--r--spec/frontend/alert_management/components/sidebar/alert_managment_sidebar_assignees_spec.js4
-rw-r--r--spec/frontend/alert_management/components/sidebar/alert_sidebar_status_spec.js17
-rw-r--r--spec/frontend/alert_management/components/system_notes/alert_management_system_note_spec.js6
-rw-r--r--spec/frontend/alert_management/mocks/alerts_provide_config.json13
-rw-r--r--spec/frontend/alert_settings/__snapshots__/alert_settings_form_spec.js.snap48
-rw-r--r--spec/frontend/alert_settings/alert_settings_form_spec.js51
-rw-r--r--spec/frontend/alert_settings/alerts_integrations_list_spec.js89
-rw-r--r--spec/frontend/analytics/instance_statistics/apollo_mock_data.js30
-rw-r--r--spec/frontend/analytics/instance_statistics/components/__snapshots__/pipelines_chart_spec.js.snap161
-rw-r--r--spec/frontend/analytics/instance_statistics/components/app_spec.js34
-rw-r--r--spec/frontend/analytics/instance_statistics/components/instance_counts_spec.js54
-rw-r--r--spec/frontend/analytics/instance_statistics/components/pipelines_chart_spec.js189
-rw-r--r--spec/frontend/analytics/instance_statistics/components/users_chart_spec.js200
-rw-r--r--spec/frontend/analytics/instance_statistics/mock_data.js42
-rw-r--r--spec/frontend/analytics/instance_statistics/utils_spec.js84
-rw-r--r--spec/frontend/analytics/shared/components/metric_card_spec.js129
-rw-r--r--spec/frontend/api_spec.js80
-rw-r--r--spec/frontend/awards_handler_spec.js24
-rw-r--r--spec/frontend/badges/components/badge_settings_spec.js120
-rw-r--r--spec/frontend/batch_comments/components/preview_item_spec.js16
-rw-r--r--spec/frontend/batch_comments/components/publish_button_spec.js11
-rw-r--r--spec/frontend/batch_comments/components/publish_dropdown_spec.js87
-rw-r--r--spec/frontend/batch_comments/stores/modules/batch_comments/actions_spec.js90
-rw-r--r--spec/frontend/batch_comments/stores/modules/batch_comments/mutations_spec.js52
-rw-r--r--spec/frontend/behaviors/load_startup_css_spec.js44
-rw-r--r--spec/frontend/behaviors/shortcuts/keybindings_spec.js66
-rw-r--r--spec/frontend/blob/components/__snapshots__/blob_header_filepath_spec.js.snap2
-rw-r--r--spec/frontend/blob/pipeline_tour_success_modal_spec.js5
-rw-r--r--spec/frontend/blob/sketch/index_spec.js7
-rw-r--r--spec/frontend/blob/suggest_web_ide_ci/web_ide_alert_spec.js67
-rw-r--r--spec/frontend/blob/viewer/index_spec.js55
-rw-r--r--spec/frontend/blob_edit/blob_bundle_spec.js15
-rw-r--r--spec/frontend/blob_edit/edit_blob_spec.js33
-rw-r--r--spec/frontend/boards/board_blank_state_spec.js95
-rw-r--r--spec/frontend/boards/board_list_new_spec.js234
-rw-r--r--spec/frontend/boards/board_list_spec.js3
-rw-r--r--spec/frontend/boards/boards_store_spec.js19
-rw-r--r--spec/frontend/boards/components/board_configuration_options_spec.js59
-rw-r--r--spec/frontend/boards/components/board_content_spec.js3
-rw-r--r--spec/frontend/boards/components/sidebar/board_editable_item_spec.js26
-rw-r--r--spec/frontend/boards/components/sidebar/board_sidebar_labels_select_spec.js143
-rw-r--r--spec/frontend/boards/mock_data.js8
-rw-r--r--spec/frontend/boards/stores/actions_spec.js236
-rw-r--r--spec/frontend/boards/stores/getters_spec.js30
-rw-r--r--spec/frontend/boards/stores/mutations_spec.js135
-rw-r--r--spec/frontend/ci_lint/components/ci_lint_results_spec.js114
-rw-r--r--spec/frontend/ci_lint/components/ci_lint_spec.js77
-rw-r--r--spec/frontend/ci_lint/components/ci_lint_warnings_spec.js54
-rw-r--r--spec/frontend/ci_lint/mock_data.js49
-rw-r--r--spec/frontend/ci_settings_pipeline_triggers/components/triggers_list_spec.js102
-rw-r--r--spec/frontend/ci_settings_pipeline_triggers/mock_data.js30
-rw-r--r--spec/frontend/ci_variable_list/components/ci_enviroments_dropdown_spec.js103
-rw-r--r--spec/frontend/ci_variable_list/components/ci_environments_dropdown_spec.js107
-rw-r--r--spec/frontend/ci_variable_list/components/ci_variable_modal_spec.js24
-rw-r--r--spec/frontend/ci_variable_list/store/getters_spec.js2
-rw-r--r--spec/frontend/ci_variable_list/store/mutations_spec.js2
-rw-r--r--spec/frontend/clusters/components/__snapshots__/applications_spec.js.snap2
-rw-r--r--spec/frontend/clusters/components/__snapshots__/remove_cluster_confirmation_spec.js.snap90
-rw-r--r--spec/frontend/clusters/components/fluentd_output_settings_spec.js4
-rw-r--r--spec/frontend/clusters/components/ingress_modsecurity_settings_spec.js10
-rw-r--r--spec/frontend/clusters/components/knative_domain_editor_spec.js4
-rw-r--r--spec/frontend/clusters/services/crossplane_provider_stack_spec.js4
-rw-r--r--spec/frontend/clusters_list/components/clusters_spec.js20
-rw-r--r--spec/frontend/clusters_list/components/node_error_help_text_spec.js33
-rw-r--r--spec/frontend/clusters_list/mock_data.js10
-rw-r--r--spec/frontend/clusters_list/store/actions_spec.js2
-rw-r--r--spec/frontend/code_navigation/components/__snapshots__/popover_spec.js.snap1
-rw-r--r--spec/frontend/collapsed_sidebar_todo_spec.js6
-rw-r--r--spec/frontend/commit/commit_pipeline_status_component_spec.js4
-rw-r--r--spec/frontend/commit/pipelines/pipelines_spec.js82
-rw-r--r--spec/frontend/confidential_merge_request/components/dropdown_spec.js31
-rw-r--r--spec/frontend/create_cluster/eks_cluster/components/create_eks_cluster_spec.js8
-rw-r--r--spec/frontend/create_cluster/eks_cluster/components/eks_cluster_configuration_form_spec.js1
-rw-r--r--spec/frontend/create_cluster/eks_cluster/store/actions_spec.js32
-rw-r--r--spec/frontend/cycle_analytics/stage_nav_item_spec.js4
-rw-r--r--spec/frontend/deploy_freeze/components/timezone_dropdown_spec.js6
-rw-r--r--spec/frontend/design_management/components/__snapshots__/design_note_pin_spec.js.snap18
-rw-r--r--spec/frontend/design_management/components/__snapshots__/design_presentation_spec.js.snap20
-rw-r--r--spec/frontend/design_management/components/__snapshots__/design_scaler_spec.js.snap6
-rw-r--r--spec/frontend/design_management/components/__snapshots__/image_spec.js.snap10
-rw-r--r--spec/frontend/design_management/components/design_note_pin_spec.js17
-rw-r--r--spec/frontend/design_management/components/design_overlay_spec.js6
-rw-r--r--spec/frontend/design_management/components/design_sidebar_spec.js30
-rw-r--r--spec/frontend/design_management/components/design_todo_button_spec.js2
-rw-r--r--spec/frontend/design_management/components/list/__snapshots__/item_spec.js.snap2
-rw-r--r--spec/frontend/design_management/components/toolbar/__snapshots__/design_navigation_spec.js.snap6
-rw-r--r--spec/frontend/design_management/components/toolbar/__snapshots__/index_spec.js.snap9
-rw-r--r--spec/frontend/design_management/components/toolbar/design_navigation_spec.js4
-rw-r--r--spec/frontend/design_management/components/upload/__snapshots__/button_spec.js.snap3
-rw-r--r--spec/frontend/design_management/components/upload/__snapshots__/design_dropzone_spec.js.snap68
-rw-r--r--spec/frontend/design_management/mock_data/apollo_mock.js29
-rw-r--r--spec/frontend/design_management/pages/__snapshots__/index_spec.js.snap23
-rw-r--r--spec/frontend/design_management/pages/design/__snapshots__/index_spec.js.snap47
-rw-r--r--spec/frontend/design_management/pages/index_spec.js94
-rw-r--r--spec/frontend/design_management/router_spec.js2
-rw-r--r--spec/frontend/design_management/utils/design_management_utils_spec.js4
-rw-r--r--spec/frontend/diff_comments_store_spec.js136
-rw-r--r--spec/frontend/diffs/components/app_spec.js4
-rw-r--r--spec/frontend/diffs/components/collapsed_files_warning_spec.js2
-rw-r--r--spec/frontend/diffs/components/commit_item_spec.js6
-rw-r--r--spec/frontend/diffs/components/diff_file_header_spec.js55
-rw-r--r--spec/frontend/diffs/components/diff_file_spec.js10
-rw-r--r--spec/frontend/diffs/components/diff_row_utils_spec.js203
-rw-r--r--spec/frontend/diffs/components/diff_table_cell_spec.js279
-rw-r--r--spec/frontend/diffs/components/edit_button_spec.js75
-rw-r--r--spec/frontend/diffs/components/inline_diff_table_row_spec.js33
-rw-r--r--spec/frontend/diffs/components/parallel_diff_table_row_spec.js26
-rw-r--r--spec/frontend/diffs/mock_data/diff_discussions.js3
-rw-r--r--spec/frontend/diffs/mock_data/diff_file.js5
-rw-r--r--spec/frontend/diffs/mock_data/diff_file_unreadable.js5
-rw-r--r--spec/frontend/diffs/store/actions_spec.js8
-rw-r--r--spec/frontend/diffs/store/getters_spec.js90
-rw-r--r--spec/frontend/diffs/store/mutations_spec.js8
-rw-r--r--spec/frontend/editor/editor_lite_spec.js147
-rw-r--r--spec/frontend/emoji/emoji_spec.js157
-rw-r--r--spec/frontend/environment.js12
-rw-r--r--spec/frontend/environments/enable_review_app_button_spec.js31
-rw-r--r--spec/frontend/environments/enable_review_app_modal_spec.js25
-rw-r--r--spec/frontend/environments/environment_actions_spec.js15
-rw-r--r--spec/frontend/environments/environments_app_spec.js99
-rw-r--r--spec/frontend/environments/folder/environments_folder_view_spec.js17
-rw-r--r--spec/frontend/error_tracking_settings/components/error_tracking_form_spec.js12
-rw-r--r--spec/frontend/feature_flags/components/configure_feature_flags_modal_spec.js159
-rw-r--r--spec/frontend/feature_flags/components/edit_feature_flag_spec.js183
-rw-r--r--spec/frontend/feature_flags/components/environments_dropdown_spec.js147
-rw-r--r--spec/frontend/feature_flags/components/feature_flags_spec.js371
-rw-r--r--spec/frontend/feature_flags/components/feature_flags_tab_spec.js168
-rw-r--r--spec/frontend/feature_flags/components/feature_flags_table_spec.js266
-rw-r--r--spec/frontend/feature_flags/components/form_spec.js493
-rw-r--r--spec/frontend/feature_flags/components/new_environments_dropdown_spec.js105
-rw-r--r--spec/frontend/feature_flags/components/new_feature_flag_spec.js136
-rw-r--r--spec/frontend/feature_flags/components/strategies/default_spec.js10
-rw-r--r--spec/frontend/feature_flags/components/strategies/flexible_rollout_spec.js116
-rw-r--r--spec/frontend/feature_flags/components/strategies/gitlab_user_list_spec.js51
-rw-r--r--spec/frontend/feature_flags/components/strategies/parameter_form_group_spec.js50
-rw-r--r--spec/frontend/feature_flags/components/strategies/percent_rollout_spec.js78
-rw-r--r--spec/frontend/feature_flags/components/strategies/users_with_id_spec.js38
-rw-r--r--spec/frontend/feature_flags/components/strategy_parameters_spec.js83
-rw-r--r--spec/frontend/feature_flags/components/strategy_spec.js264
-rw-r--r--spec/frontend/feature_flags/components/user_lists_table_spec.js98
-rw-r--r--spec/frontend/feature_flags/mock_data.js155
-rw-r--r--spec/frontend/feature_flags/store/edit/actions_spec.js303
-rw-r--r--spec/frontend/feature_flags/store/edit/mutations_spec.js134
-rw-r--r--spec/frontend/feature_flags/store/helpers_spec.js514
-rw-r--r--spec/frontend/feature_flags/store/index/actions_spec.js563
-rw-r--r--spec/frontend/feature_flags/store/index/mutations_spec.js307
-rw-r--r--spec/frontend/feature_flags/store/new/actions_spec.js192
-rw-r--r--spec/frontend/feature_flags/store/new/mutations_spec.js49
-rw-r--r--spec/frontend/fixtures/blob.rb10
-rw-r--r--spec/frontend/fixtures/releases.rb146
-rw-r--r--spec/frontend/fixtures/snippet.rb1
-rw-r--r--spec/frontend/fixtures/static/issue_sidebar_label.html26
-rw-r--r--spec/frontend/fixtures/static/pipeline_graph.html2
-rw-r--r--spec/frontend/gfm_auto_complete_spec.js117
-rw-r--r--spec/frontend/grafana_integration/components/__snapshots__/grafana_integration_spec.js.snap22
-rw-r--r--spec/frontend/group_settings/components/shared_runners_form_spec.js169
-rw-r--r--spec/frontend/groups/components/group_item_spec.js2
-rw-r--r--spec/frontend/groups/components/item_actions_spec.js125
-rw-r--r--spec/frontend/groups/components/item_caret_spec.js58
-rw-r--r--spec/frontend/groups/components/item_stats_spec.js131
-rw-r--r--spec/frontend/groups/components/item_stats_value_spec.js111
-rw-r--r--spec/frontend/groups/components/item_type_icon_spec.js80
-rw-r--r--spec/frontend/groups/members/components/app_spec.js89
-rw-r--r--spec/frontend/groups/members/index_spec.js26
-rw-r--r--spec/frontend/groups/members/utils_spec.js51
-rw-r--r--spec/frontend/helpers/dom_shims/create_object_url.js3
-rw-r--r--spec/frontend/helpers/dom_shims/index.js1
-rw-r--r--spec/frontend/helpers/emoji.js88
-rw-r--r--spec/frontend/helpers/experimentation_helper.js14
-rw-r--r--spec/frontend/helpers/keep_alive_component_helper.js29
-rw-r--r--spec/frontend/helpers/keep_alive_component_helper_spec.js32
-rw-r--r--spec/frontend/helpers/local_storage_helper.js2
-rw-r--r--spec/frontend/helpers/local_storage_helper_spec.js4
-rw-r--r--spec/frontend/helpers/startup_css_helper_spec.js2
-rw-r--r--spec/frontend/helpers/vue_test_utils_helper.js7
-rw-r--r--spec/frontend/helpers/wait_for_text.js3
-rw-r--r--spec/frontend/ide/components/commit_sidebar/actions_spec.js4
-rw-r--r--spec/frontend/ide/components/commit_sidebar/form_spec.js37
-rw-r--r--spec/frontend/ide/components/ide_review_spec.js78
-rw-r--r--spec/frontend/ide/components/ide_side_bar_spec.js81
-rw-r--r--spec/frontend/ide/components/ide_tree_list_spec.js8
-rw-r--r--spec/frontend/ide/components/ide_tree_spec.js41
-rw-r--r--spec/frontend/ide/components/jobs/__snapshots__/stage_spec.js.snap2
-rw-r--r--spec/frontend/ide/components/jobs/detail/scroll_button_spec.js2
-rw-r--r--spec/frontend/ide/components/new_dropdown/upload_spec.js17
-rw-r--r--spec/frontend/ide/components/repo_commit_section_spec.js21
-rw-r--r--spec/frontend/ide/lib/errors_spec.js46
-rw-r--r--spec/frontend/ide/lib/languages/hcl_spec.js290
-rw-r--r--spec/frontend/ide/stores/actions/file_spec.js14
-rw-r--r--spec/frontend/ide/stores/getters_spec.js10
-rw-r--r--spec/frontend/ide/stores/modules/commit/actions_spec.js82
-rw-r--r--spec/frontend/ide/stores/mutations/file_spec.js26
-rw-r--r--spec/frontend/ide/stores/utils_spec.js10
-rw-r--r--spec/frontend/ide/utils_spec.js40
-rw-r--r--spec/frontend/incidents/components/incidents_list_spec.js302
-rw-r--r--spec/frontend/incidents/mocks/incidents.json6
-rw-r--r--spec/frontend/incidents_settings/components/__snapshots__/alerts_form_spec.js.snap27
-rw-r--r--spec/frontend/incidents_settings/components/__snapshots__/incidents_settings_tabs_spec.js.snap3
-rw-r--r--spec/frontend/incidents_settings/components/__snapshots__/pagerduty_form_spec.js.snap55
-rw-r--r--spec/frontend/incidents_settings/components/incidents_settings_tabs_spec.js7
-rw-r--r--spec/frontend/integrations/edit/components/confirmation_modal_spec.js51
-rw-r--r--spec/frontend/integrations/edit/components/integration_form_spec.js23
-rw-r--r--spec/frontend/integrations/edit/mock_data.js1
-rw-r--r--spec/frontend/invite_member/components/invite_member_modal_spec.js63
-rw-r--r--spec/frontend/invite_member/components/invite_member_trigger_mock_data.js7
-rw-r--r--spec/frontend/invite_member/components/invite_member_trigger_spec.js48
-rw-r--r--spec/frontend/invite_members/components/invite_members_modal_spec.js115
-rw-r--r--spec/frontend/invite_members/components/invite_members_trigger_spec.js58
-rw-r--r--spec/frontend/issuable/related_issues/components/add_issuable_form_spec.js5
-rw-r--r--spec/frontend/issuable/related_issues/components/issue_token_spec.js257
-rw-r--r--spec/frontend/issuable/related_issues/components/related_issues_block_spec.js5
-rw-r--r--spec/frontend/issuable/related_issues/components/related_issues_list_spec.js5
-rw-r--r--spec/frontend/issuable_create/components/issuable_form_spec.js1
-rw-r--r--spec/frontend/issuable_list/mock_data.js12
-rw-r--r--spec/frontend/issuable_show/components/issuable_body_spec.js140
-rw-r--r--spec/frontend/issuable_show/components/issuable_description_spec.js41
-rw-r--r--spec/frontend/issuable_show/components/issuable_edit_form_spec.js122
-rw-r--r--spec/frontend/issuable_show/components/issuable_header_spec.js132
-rw-r--r--spec/frontend/issuable_show/components/issuable_show_root_spec.js123
-rw-r--r--spec/frontend/issuable_show/components/issuable_title_spec.js100
-rw-r--r--spec/frontend/issuable_show/mock_data.js34
-rw-r--r--spec/frontend/issuable_sidebar/components/issuable_sidebar_root_spec.js199
-rw-r--r--spec/frontend/issue_show/components/incidents/highlight_bar_spec.js74
-rw-r--r--spec/frontend/issue_show/components/incidents/incident_tabs_spec.js17
-rw-r--r--spec/frontend/issue_show/issue_spec.js8
-rw-r--r--spec/frontend/jira_import/components/__snapshots__/jira_import_form_spec.js.snap8
-rw-r--r--spec/frontend/jobs/components/job_container_item_spec.js2
-rw-r--r--spec/frontend/jobs/components/log/line_spec.js65
-rw-r--r--spec/frontend/jobs/store/utils_spec.js8
-rw-r--r--spec/frontend/labels_issue_sidebar_spec.js98
-rw-r--r--spec/frontend/lib/dompurify_spec.js98
-rw-r--r--spec/frontend/lib/utils/axios_startup_calls_spec.js49
-rw-r--r--spec/frontend/lib/utils/datetime_utility_spec.js65
-rw-r--r--spec/frontend/lib/utils/experimentation_spec.js20
-rw-r--r--spec/frontend/lib/utils/number_utility_spec.js11
-rw-r--r--spec/frontend/lib/utils/text_markdown_spec.js99
-rw-r--r--spec/frontend/lib/utils/url_utility_spec.js71
-rw-r--r--spec/frontend/logs/components/environment_logs_spec.js16
-rw-r--r--spec/frontend/logs/components/log_simple_filters_spec.js8
-rw-r--r--spec/frontend/merge_request_spec.js63
-rw-r--r--spec/frontend/milestones/stores/actions_spec.js140
-rw-r--r--spec/frontend/milestones/stores/getter_spec.js15
-rw-r--r--spec/frontend/milestones/stores/mutations_spec.js159
-rw-r--r--spec/frontend/mini_pipeline_graph_dropdown_spec.js2
-rw-r--r--spec/frontend/monitoring/components/__snapshots__/dashboard_template_spec.js.snap1
-rw-r--r--spec/frontend/monitoring/components/__snapshots__/group_empty_state_spec.js.snap181
-rw-r--r--spec/frontend/monitoring/components/dashboard_panel_spec.js4
-rw-r--r--spec/frontend/monitoring/components/group_empty_state_spec.js33
-rw-r--r--spec/frontend/monitoring/router_spec.js3
-rw-r--r--spec/frontend/notes/components/discussion_counter_spec.js28
-rw-r--r--spec/frontend/notes/components/discussion_filter_spec.js38
-rw-r--r--spec/frontend/notes/components/notes_app_spec.js17
-rw-r--r--spec/frontend/notes/components/sort_discussion_spec.js22
-rw-r--r--spec/frontend/notes/components/timeline_toggle_spec.js117
-rw-r--r--spec/frontend/notes/stores/actions_spec.js9
-rw-r--r--spec/frontend/notes/stores/getters_spec.js13
-rw-r--r--spec/frontend/notes/stores/mutation_spec.js3
-rw-r--r--spec/frontend/packages/details/components/__snapshots__/package_title_spec.js.snap214
-rw-r--r--spec/frontend/packages/details/components/composer_installation_spec.js56
-rw-r--r--spec/frontend/packages/details/store/getters_spec.js34
-rw-r--r--spec/frontend/packages/details/utils_spec.js24
-rw-r--r--spec/frontend/packages/list/coming_soon/helpers_spec.js36
-rw-r--r--spec/frontend/packages/list/coming_soon/mock_data.js90
-rw-r--r--spec/frontend/packages/list/coming_soon/packages_coming_soon_spec.js138
-rw-r--r--spec/frontend/packages/list/components/__snapshots__/packages_list_app_spec.js.snap756
-rw-r--r--spec/frontend/packages/list/components/packages_list_app_spec.js1
-rw-r--r--spec/frontend/packages/list/components/packages_title_spec.js71
-rw-r--r--spec/frontend/packages/list/stores/mutations_spec.js1
-rw-r--r--spec/frontend/packages/mock_data.js4
-rw-r--r--spec/frontend/packages/shared/components/__snapshots__/package_list_row_spec.js.snap26
-rw-r--r--spec/frontend/packages/shared/components/__snapshots__/publish_method_spec.js.snap3
-rw-r--r--spec/frontend/packages/shared/components/package_list_row_spec.js8
-rw-r--r--spec/frontend/packages/shared/components/package_path_spec.js86
-rw-r--r--spec/frontend/packages/shared/utils_spec.js2
-rw-r--r--spec/frontend/pages/admin/users/components/__snapshots__/delete_user_modal_spec.js.snap3
-rw-r--r--spec/frontend/pages/projects/graphs/__snapshots__/code_coverage_spec.js.snap91
-rw-r--r--spec/frontend/pages/projects/graphs/code_coverage_spec.js18
-rw-r--r--spec/frontend/pages/projects/pipeline_schedules/shared/components/pipeline_schedule_callout_spec.js21
-rw-r--r--spec/frontend/performance_bar/index_spec.js1
-rw-r--r--spec/frontend/pipeline_new/components/pipeline_new_form_spec.js165
-rw-r--r--spec/frontend/pipeline_new/mock_data.js6
-rw-r--r--spec/frontend/pipelines/components/dag/dag_graph_spec.js2
-rw-r--r--spec/frontend/pipelines/components/dag/dag_spec.js9
-rw-r--r--spec/frontend/pipelines/components/dag/drawing_utils_spec.js2
-rw-r--r--spec/frontend/pipelines/components/dag/parsing_utils_spec.js2
-rw-r--r--spec/frontend/pipelines/graph/graph_component_spec.js102
-rw-r--r--spec/frontend/pipelines/graph/job_item_spec.js5
-rw-r--r--spec/frontend/pipelines/graph/job_name_component_spec.js7
-rw-r--r--spec/frontend/pipelines/header_component_spec.js177
-rw-r--r--spec/frontend/pipelines/legacy_header_component_spec.js116
-rw-r--r--spec/frontend/pipelines/mock_data.js78
-rw-r--r--spec/frontend/pipelines/pipeline_graph/mock_data.js21
-rw-r--r--spec/frontend/pipelines/pipeline_graph/utils_spec.js307
-rw-r--r--spec/frontend/pipelines/pipelines_spec.js383
-rw-r--r--spec/frontend/pipelines/pipelines_table_row_spec.js2
-rw-r--r--spec/frontend/pipelines/test_reports/mock_data.js19
-rw-r--r--spec/frontend/pipelines/test_reports/test_suite_table_spec.js30
-rw-r--r--spec/frontend/project_find_file_spec.js5
-rw-r--r--spec/frontend/projects/commit_box/info/load_branches_spec.js68
-rw-r--r--spec/frontend/projects/components/__snapshots__/project_delete_button_spec.js.snap1
-rw-r--r--spec/frontend/projects/components/shared/__snapshots__/delete_button_spec.js.snap3
-rw-r--r--spec/frontend/projects/settings/access_dropdown_spec.js21
-rw-r--r--spec/frontend/projects/settings_service_desk/components/service_desk_root_spec.js4
-rw-r--r--spec/frontend/ref/components/ref_selector_spec.js6
-rw-r--r--spec/frontend/registry/explorer/components/details_page/partial_cleanup_alert_spec.js71
-rw-r--r--spec/frontend/registry/explorer/components/list_page/image_list_row_spec.js23
-rw-r--r--spec/frontend/registry/explorer/components/list_page/registry_header_spec.js90
-rw-r--r--spec/frontend/registry/explorer/pages/details_spec.js65
-rw-r--r--spec/frontend/registry/settings/components/__snapshots__/registry_settings_app_spec.js.snap7
-rw-r--r--spec/frontend/registry/settings/components/registry_settings_app_spec.js107
-rw-r--r--spec/frontend/registry/settings/components/settings_form_spec.js302
-rw-r--r--spec/frontend/registry/settings/graphql/cache_updated_spec.js56
-rw-r--r--spec/frontend/registry/settings/mock_data.js40
-rw-r--r--spec/frontend/registry/settings/store/actions_spec.js90
-rw-r--r--spec/frontend/registry/settings/store/getters_spec.js72
-rw-r--r--spec/frontend/registry/settings/store/mutations_spec.js80
-rw-r--r--spec/frontend/registry/shared/__snapshots__/utils_spec.js.snap101
-rw-r--r--spec/frontend/registry/shared/components/expiration_policy_fields_spec.js20
-rw-r--r--spec/frontend/registry/shared/stubs.js11
-rw-r--r--spec/frontend/registry/shared/utils_spec.js37
-rw-r--r--spec/frontend/related_merge_requests/components/related_merge_requests_spec.js5
-rw-r--r--spec/frontend/releases/__snapshots__/util_spec.js.snap230
-rw-r--r--spec/frontend/releases/components/app_edit_new_spec.js59
-rw-r--r--spec/frontend/releases/components/app_index_spec.js63
-rw-r--r--spec/frontend/releases/components/app_show_spec.js8
-rw-r--r--spec/frontend/releases/components/asset_links_form_spec.js23
-rw-r--r--spec/frontend/releases/components/evidence_block_spec.js8
-rw-r--r--spec/frontend/releases/components/release_block_assets_spec.js13
-rw-r--r--spec/frontend/releases/components/release_block_footer_spec.js4
-rw-r--r--spec/frontend/releases/components/release_block_header_spec.js6
-rw-r--r--spec/frontend/releases/components/release_block_metadata_spec.js67
-rw-r--r--spec/frontend/releases/components/release_block_milestone_info_spec.js26
-rw-r--r--spec/frontend/releases/components/release_block_spec.js111
-rw-r--r--spec/frontend/releases/components/release_skeleton_loader_spec.js15
-rw-r--r--spec/frontend/releases/components/releases_pagination_graphql_spec.js10
-rw-r--r--spec/frontend/releases/components/releases_pagination_rest_spec.js8
-rw-r--r--spec/frontend/releases/mock_data.js335
-rw-r--r--spec/frontend/releases/stores/getters_spec.js22
-rw-r--r--spec/frontend/releases/stores/modules/detail/actions_spec.js50
-rw-r--r--spec/frontend/releases/stores/modules/detail/mutations_spec.js25
-rw-r--r--spec/frontend/releases/stores/modules/list/actions_spec.js336
-rw-r--r--spec/frontend/releases/stores/modules/list/mutations_spec.js44
-rw-r--r--spec/frontend/releases/util_spec.js68
-rw-r--r--spec/frontend/repository/components/__snapshots__/last_commit_spec.js.snap58
-rw-r--r--spec/frontend/repository/components/breadcrumbs_spec.js6
-rw-r--r--spec/frontend/repository/components/last_commit_spec.js2
-rw-r--r--spec/frontend/repository/components/preview/__snapshots__/index_spec.js.snap5
-rw-r--r--spec/frontend/repository/log_tree_spec.js8
-rw-r--r--spec/frontend/repository/utils/icon_spec.js23
-rw-r--r--spec/frontend/right_sidebar_spec.js13
-rw-r--r--spec/frontend/search/components/state_filter_spec.js104
-rw-r--r--spec/frontend/search/dropdown_filter/components/dropdown_filter_spec.js196
-rw-r--r--spec/frontend/search/dropdown_filter/mock_data.js5
-rw-r--r--spec/frontend/self_monitor/components/__snapshots__/self_monitor_form_spec.js.snap12
-rw-r--r--spec/frontend/self_monitor/components/self_monitor_form_spec.js4
-rw-r--r--spec/frontend/sentry/sentry_config_spec.js2
-rw-r--r--spec/frontend/serverless/components/__snapshots__/empty_state_spec.js.snap2
-rw-r--r--spec/frontend/serverless/components/missing_prometheus_spec.js4
-rw-r--r--spec/frontend/serverless/components/url_spec.js2
-rw-r--r--spec/frontend/sidebar/assignee_title_spec.js17
-rw-r--r--spec/frontend/sidebar/components/time_tracking/time_tracker_spec.js3
-rw-r--r--spec/frontend/sidebar/confidential/edit_form_buttons_spec.js15
-rw-r--r--spec/frontend/sidebar/lock/edit_form_buttons_spec.js14
-rw-r--r--spec/frontend/sidebar/lock/issuable_lock_form_spec.js13
-rw-r--r--spec/frontend/sidebar/reviewer_title_spec.js116
-rw-r--r--spec/frontend/sidebar/reviewers_spec.js169
-rw-r--r--spec/frontend/sidebar/sidebar_assignees_spec.js1
-rw-r--r--spec/frontend/sidebar/sidebar_labels_spec.js35
-rw-r--r--spec/frontend/sidebar/sidebar_store_spec.js37
-rw-r--r--spec/frontend/snippet/snippet_bundle_spec.js87
-rw-r--r--spec/frontend/snippet/snippet_edit_spec.js44
-rw-r--r--spec/frontend/snippets/components/__snapshots__/snippet_blob_edit_spec.js.snap5
-rw-r--r--spec/frontend/snippets/components/__snapshots__/snippet_description_edit_spec.js.snap2
-rw-r--r--spec/frontend/snippets/components/edit_spec.js8
-rw-r--r--spec/frontend/snippets/components/snippet_blob_actions_edit_spec.js25
-rw-r--r--spec/frontend/snippets/components/snippet_blob_edit_spec.js18
-rw-r--r--spec/frontend/snippets/components/snippet_blob_view_spec.js6
-rw-r--r--spec/frontend/snippets_spec.js70
-rw-r--r--spec/frontend/static_site_editor/components/edit_meta_controls_spec.js99
-rw-r--r--spec/frontend/static_site_editor/components/edit_meta_modal_spec.js80
-rw-r--r--spec/frontend/static_site_editor/components/front_matter_controls_spec.js11
-rw-r--r--spec/frontend/static_site_editor/graphql/resolvers/has_submitted_changes_spec.js27
-rw-r--r--spec/frontend/static_site_editor/mock_data.js11
-rw-r--r--spec/frontend/static_site_editor/pages/home_spec.js99
-rw-r--r--spec/frontend/static_site_editor/pages/success_spec.js110
-rw-r--r--spec/frontend/static_site_editor/services/front_matterify_spec.js47
-rw-r--r--spec/frontend/static_site_editor/services/submit_content_changes_spec.js53
-rw-r--r--spec/frontend/static_site_editor/services/templater_spec.js8
-rw-r--r--spec/frontend/test_setup.js3
-rw-r--r--spec/frontend/tracking_spec.js2
-rw-r--r--spec/frontend/user_lists/components/add_user_modal_spec.js50
-rw-r--r--spec/frontend/user_lists/components/edit_user_list_spec.js150
-rw-r--r--spec/frontend/user_lists/components/new_user_list_spec.js93
-rw-r--r--spec/frontend/user_lists/components/user_list_form_spec.js40
-rw-r--r--spec/frontend/user_lists/components/user_list_spec.js196
-rw-r--r--spec/frontend/user_lists/store/edit/actions_spec.js121
-rw-r--r--spec/frontend/user_lists/store/edit/mutations_spec.js61
-rw-r--r--spec/frontend/user_lists/store/new/actions_spec.js69
-rw-r--r--spec/frontend/user_lists/store/new/mutations_spec.js38
-rw-r--r--spec/frontend/user_lists/store/show/actions_spec.js117
-rw-r--r--spec/frontend/user_lists/store/show/mutations_spec.js86
-rw-r--r--spec/frontend/user_lists/store/utils_spec.js23
-rw-r--r--spec/frontend/vue_mr_widget/components/mr_widget_author_time_spec.js4
-rw-r--r--spec/frontend/vue_mr_widget/components/mr_widget_header_spec.js2
-rw-r--r--spec/frontend/vue_mr_widget/components/mr_widget_rebase_spec.js22
-rw-r--r--spec/frontend/vue_mr_widget/components/states/mr_widget_auto_merge_failed_spec.js14
-rw-r--r--spec/frontend/vue_mr_widget/components/states/mr_widget_merged_spec.js4
-rw-r--r--spec/frontend/vue_mr_widget/components/states/mr_widget_ready_to_merge_spec.js15
-rw-r--r--spec/frontend/vue_mr_widget/components/states/mr_widget_squash_before_merge_spec.js5
-rw-r--r--spec/frontend/vue_mr_widget/deployment/deployment_actions_spec.js5
-rw-r--r--spec/frontend/vue_mr_widget/deployment/deployment_spec.js5
-rw-r--r--spec/frontend/vue_mr_widget/mock_data.js1
-rw-r--r--spec/frontend/vue_mr_widget/mr_widget_options_spec.js102
-rw-r--r--spec/frontend/vue_mr_widget/stores/mr_widget_store_spec.js14
-rw-r--r--spec/frontend/vue_shared/components/__snapshots__/awards_list_spec.js.snap8
-rw-r--r--spec/frontend/vue_shared/components/__snapshots__/clone_dropdown_spec.js.snap2
-rw-r--r--spec/frontend/vue_shared/components/__snapshots__/editor_lite_spec.js.snap14
-rw-r--r--spec/frontend/vue_shared/components/__snapshots__/expand_button_spec.js.snap8
-rw-r--r--spec/frontend/vue_shared/components/__snapshots__/split_button_spec.js.snap37
-rw-r--r--spec/frontend/vue_shared/components/actions_button_spec.js28
-rw-r--r--spec/frontend/vue_shared/components/alert_detail_table_spec.js74
-rw-r--r--spec/frontend/vue_shared/components/alert_details_table_spec.js139
-rw-r--r--spec/frontend/vue_shared/components/clipboard_button_spec.js5
-rw-r--r--spec/frontend/vue_shared/components/confirm_modal_spec.js16
-rw-r--r--spec/frontend/vue_shared/components/deprecated_modal_2_spec.js2
-rw-r--r--spec/frontend/vue_shared/components/dropdown/dropdown_search_input_spec.js2
-rw-r--r--spec/frontend/vue_shared/components/editor_lite_spec.js144
-rw-r--r--spec/frontend/vue_shared/components/filtered_search_bar/store/modules/filters/actions_spec.js448
-rw-r--r--spec/frontend/vue_shared/components/filtered_search_bar/store/modules/filters/mock_data.js50
-rw-r--r--spec/frontend/vue_shared/components/filtered_search_bar/store/modules/filters/mutations_spec.js116
-rw-r--r--spec/frontend/vue_shared/components/filtered_search_bar/store/modules/filters/test_helper.js11
-rw-r--r--spec/frontend/vue_shared/components/local_storage_sync_spec.js150
-rw-r--r--spec/frontend/vue_shared/components/markdown/__snapshots__/suggestion_diff_spec.js.snap1
-rw-r--r--spec/frontend/vue_shared/components/markdown/field_spec.js213
-rw-r--r--spec/frontend/vue_shared/components/markdown/suggestion_diff_header_spec.js8
-rw-r--r--spec/frontend/vue_shared/components/members/action_buttons/access_request_action_buttons_spec.js108
-rw-r--r--spec/frontend/vue_shared/components/members/action_buttons/approve_access_request_button_spec.js74
-rw-r--r--spec/frontend/vue_shared/components/members/action_buttons/invite_action_buttons_spec.js85
-rw-r--r--spec/frontend/vue_shared/components/members/action_buttons/leave_button_spec.js59
-rw-r--r--spec/frontend/vue_shared/components/members/action_buttons/remove_group_link_button_spec.js64
-rw-r--r--spec/frontend/vue_shared/components/members/action_buttons/remove_member_button_spec.js66
-rw-r--r--spec/frontend/vue_shared/components/members/action_buttons/resend_invite_button_spec.js66
-rw-r--r--spec/frontend/vue_shared/components/members/action_buttons/user_action_buttons_spec.js89
-rw-r--r--spec/frontend/vue_shared/components/members/avatars/group_avatar_spec.js46
-rw-r--r--spec/frontend/vue_shared/components/members/avatars/invite_avatar_spec.js38
-rw-r--r--spec/frontend/vue_shared/components/members/avatars/user_avatar_spec.js115
-rw-r--r--spec/frontend/vue_shared/components/members/mock_data.js70
-rw-r--r--spec/frontend/vue_shared/components/members/modals/leave_modal_spec.js91
-rw-r--r--spec/frontend/vue_shared/components/members/modals/remove_group_link_modal_spec.js106
-rw-r--r--spec/frontend/vue_shared/components/members/table/created_at_spec.js61
-rw-r--r--spec/frontend/vue_shared/components/members/table/expires_at_spec.js86
-rw-r--r--spec/frontend/vue_shared/components/members/table/member_action_buttons_spec.js43
-rw-r--r--spec/frontend/vue_shared/components/members/table/member_avatar_spec.js39
-rw-r--r--spec/frontend/vue_shared/components/members/table/member_source_spec.js71
-rw-r--r--spec/frontend/vue_shared/components/members/table/member_table_cell_spec.js251
-rw-r--r--spec/frontend/vue_shared/components/members/table/members_table_spec.js141
-rw-r--r--spec/frontend/vue_shared/components/members/table/role_dropdown_spec.js150
-rw-r--r--spec/frontend/vue_shared/components/members/utils_spec.js29
-rw-r--r--spec/frontend/vue_shared/components/paginated_table_with_search_and_tabs/mocks/items.json15
-rw-r--r--spec/frontend/vue_shared/components/paginated_table_with_search_and_tabs/mocks/items_filters.json14
-rw-r--r--spec/frontend/vue_shared/components/paginated_table_with_search_and_tabs/paginated_table_with_search_and_tabs_spec.js350
-rw-r--r--spec/frontend/vue_shared/components/registry/__snapshots__/code_instruction_spec.js.snap7
-rw-r--r--spec/frontend/vue_shared/components/registry/list_item_spec.js8
-rw-r--r--spec/frontend/vue_shared/components/registry/title_area_spec.js39
-rw-r--r--spec/frontend/vue_shared/components/rich_content_editor/editor_service_spec.js56
-rw-r--r--spec/frontend/vue_shared/components/rich_content_editor/modals/insert_video_modal_spec.js44
-rw-r--r--spec/frontend/vue_shared/components/rich_content_editor/rich_content_editor_spec.js41
-rw-r--r--spec/frontend/vue_shared/components/rich_content_editor/services/renderers/render_html_block_spec.js27
-rw-r--r--spec/frontend/vue_shared/components/rich_content_editor/services/sanitize_html_spec.js11
-rw-r--r--spec/frontend/vue_shared/components/sidebar/collapsed_calendar_icon_spec.js2
-rw-r--r--spec/frontend/vue_shared/components/sidebar/collapsed_grouped_date_picker_spec.js2
-rw-r--r--spec/frontend/vue_shared/components/sidebar/labels_select_vue/dropdown_contents_labels_view_spec.js23
-rw-r--r--spec/frontend/vue_shared/components/sidebar/labels_select_vue/mock_data.js7
-rw-r--r--spec/frontend/vue_shared/components/sidebar/labels_select_vue/store/actions_spec.js15
-rw-r--r--spec/frontend/vue_shared/components/sidebar/labels_select_vue/store/mutations_spec.js13
-rw-r--r--spec/frontend/vue_shared/components/sidebar/toggle_sidebar_spec.js11
-rw-r--r--spec/frontend/vue_shared/components/split_button_spec.js6
-rw-r--r--spec/frontend/vue_shared/components/todo_button_spec.js2
-rw-r--r--spec/frontend/vue_shared/components/user_popover/user_popover_spec.js30
-rw-r--r--spec/frontend/vue_shared/components/web_ide_link_spec.js71
-rw-r--r--spec/frontend/vue_shared/directives/tooltip_spec.js169
-rw-r--r--spec/frontend/vue_shared/droplab_dropdown_button_spec.js132
-rw-r--r--spec/frontend/vue_shared/security_reports/security_reports_app_spec.js118
-rw-r--r--spec/frontend/vuex_shared/modules/members/actions_spec.js110
-rw-r--r--spec/frontend/vuex_shared/modules/members/mutations_spec.js90
-rw-r--r--spec/frontend/vuex_shared/modules/members/utils_spec.js14
-rw-r--r--spec/frontend/whats_new/components/app_spec.js42
-rw-r--r--spec/frontend/whats_new/store/actions_spec.js33
-rw-r--r--spec/frontend/whats_new/store/mutations_spec.js7
-rw-r--r--spec/frontend/wikis_spec.js2
-rw-r--r--spec/frontend_integration/.eslintrc.yml2
-rw-r--r--spec/frontend_integration/ide/__snapshots__/ide_integration_spec.js.snap1
-rw-r--r--spec/frontend_integration/ide/ide_helper.js102
-rw-r--r--spec/frontend_integration/ide/ide_integration_spec.js47
-rw-r--r--spec/frontend_integration/test_helpers/setup/setup_mock_server.js9
-rw-r--r--spec/graphql/features/feature_flag_spec.rb4
-rw-r--r--spec/graphql/mutations/design_management/move_spec.rb2
-rw-r--r--spec/graphql/mutations/discussions/toggle_resolve_spec.rb4
-rw-r--r--spec/graphql/mutations/issues/create_spec.rb146
-rw-r--r--spec/graphql/mutations/issues/move_spec.rb41
-rw-r--r--spec/graphql/mutations/issues/update_spec.rb17
-rw-r--r--spec/graphql/mutations/todos/mark_done_spec.rb3
-rw-r--r--spec/graphql/mutations/todos/restore_many_spec.rb33
-rw-r--r--spec/graphql/mutations/todos/restore_spec.rb11
-rw-r--r--spec/graphql/resolvers/admin/analytics/instance_statistics/measurements_resolver_spec.rb35
-rw-r--r--spec/graphql/resolvers/board_lists_resolver_spec.rb8
-rw-r--r--spec/graphql/resolvers/board_resolver_spec.rb72
-rw-r--r--spec/graphql/resolvers/ci/runner_platforms_resolver_spec.rb19
-rw-r--r--spec/graphql/resolvers/concerns/looks_ahead_spec.rb14
-rw-r--r--spec/graphql/resolvers/group_milestones_resolver_spec.rb23
-rw-r--r--spec/graphql/resolvers/issues_resolver_spec.rb33
-rw-r--r--spec/graphql/resolvers/project_milestones_resolver_spec.rb61
-rw-r--r--spec/graphql/resolvers/projects_resolver_spec.rb65
-rw-r--r--spec/graphql/resolvers/snippets/blobs_resolver_spec.rb50
-rw-r--r--spec/graphql/resolvers/terraform/states_resolver_spec.rb33
-rw-r--r--spec/graphql/types/alert_management/alert_type_spec.rb1
-rw-r--r--spec/graphql/types/alert_management/status_enum_spec.rb8
-rw-r--r--spec/graphql/types/base_field_spec.rb4
-rw-r--r--spec/graphql/types/ci/detailed_status_type_spec.rb2
-rw-r--r--spec/graphql/types/ci/group_type_spec.rb1
-rw-r--r--spec/graphql/types/ci/job_type_spec.rb2
-rw-r--r--spec/graphql/types/ci/runner_architecture_type_spec.rb16
-rw-r--r--spec/graphql/types/ci/runner_platform_type_spec.rb17
-rw-r--r--spec/graphql/types/ci/stage_type_spec.rb1
-rw-r--r--spec/graphql/types/ci/status_action_type_spec.rb19
-rw-r--r--spec/graphql/types/design_management/design_collection_copy_state_enum_spec.rb11
-rw-r--r--spec/graphql/types/design_management/design_collection_type_spec.rb2
-rw-r--r--spec/graphql/types/environment_type_spec.rb15
-rw-r--r--spec/graphql/types/global_id_type_spec.rb26
-rw-r--r--spec/graphql/types/group_type_spec.rb1
-rw-r--r--spec/graphql/types/issue_sort_enum_spec.rb2
-rw-r--r--spec/graphql/types/merge_request_type_spec.rb39
-rw-r--r--spec/graphql/types/package_type_enum_spec.rb2
-rw-r--r--spec/graphql/types/project_type_spec.rb9
-rw-r--r--spec/graphql/types/query_type_spec.rb11
-rw-r--r--spec/graphql/types/range_input_type_spec.rb43
-rw-r--r--spec/graphql/types/root_storage_statistics_type_spec.rb3
-rw-r--r--spec/graphql/types/snippet_type_spec.rb54
-rw-r--r--spec/graphql/types/terraform/state_type_spec.rb21
-rw-r--r--spec/graphql/types/timeframe_type_spec.rb38
-rw-r--r--spec/haml_lint/linter/documentation_links_spec.rb98
-rw-r--r--spec/helpers/analytics/unique_visits_helper_spec.rb9
-rw-r--r--spec/helpers/application_helper_spec.rb26
-rw-r--r--spec/helpers/application_settings_helper_spec.rb20
-rw-r--r--spec/helpers/blob_helper_spec.rb48
-rw-r--r--spec/helpers/boards_helper_spec.rb59
-rw-r--r--spec/helpers/ci/runners_helper_spec.rb21
-rw-r--r--spec/helpers/clusters_helper_spec.rb44
-rw-r--r--spec/helpers/container_expiration_policies_helper_spec.rb25
-rw-r--r--spec/helpers/emails_helper_spec.rb112
-rw-r--r--spec/helpers/external_link_helper_spec.rb11
-rw-r--r--spec/helpers/feature_flags_helper_spec.rb21
-rw-r--r--spec/helpers/gitlab_routing_helper_spec.rb4
-rw-r--r--spec/helpers/groups/group_members_helper_spec.rb58
-rw-r--r--spec/helpers/icons_helper_spec.rb120
-rw-r--r--spec/helpers/invite_members_helper_spec.rb77
-rw-r--r--spec/helpers/issuables_helper_spec.rb80
-rw-r--r--spec/helpers/issues_helper_spec.rb21
-rw-r--r--spec/helpers/labels_helper_spec.rb50
-rw-r--r--spec/helpers/notes_helper_spec.rb59
-rw-r--r--spec/helpers/operations_helper_spec.rb4
-rw-r--r--spec/helpers/packages_helper_spec.rb35
-rw-r--r--spec/helpers/projects/alert_management_helper_spec.rb4
-rw-r--r--spec/helpers/projects/incidents_helper_spec.rb16
-rw-r--r--spec/helpers/projects_helper_spec.rb114
-rw-r--r--spec/helpers/releases_helper_spec.rb12
-rw-r--r--spec/helpers/search_helper_spec.rb116
-rw-r--r--spec/helpers/snippets_helper_spec.rb50
-rw-r--r--spec/helpers/startupjs_helper_spec.rb20
-rw-r--r--spec/helpers/tree_helper_spec.rb110
-rw-r--r--spec/helpers/user_callouts_helper_spec.rb22
-rw-r--r--spec/helpers/users_helper_spec.rb24
-rw-r--r--spec/helpers/visibility_level_helper_spec.rb24
-rw-r--r--spec/helpers/whats_new_helper_spec.rb47
-rw-r--r--spec/helpers/wiki_helper_spec.rb13
-rw-r--r--spec/initializers/sidekiq_spec.rb45
-rw-r--r--spec/lib/api/entities/snippet_spec.rb26
-rw-r--r--spec/lib/api/github/entities_spec.rb31
-rw-r--r--spec/lib/api/helpers/packages/dependency_proxy_helpers_spec.rb2
-rw-r--r--spec/lib/api/helpers_spec.rb19
-rw-r--r--spec/lib/backup/files_spec.rb2
-rw-r--r--spec/lib/backup/repositories_spec.rb308
-rw-r--r--spec/lib/backup/repository_spec.rb232
-rw-r--r--spec/lib/banzai/filter/design_reference_filter_spec.rb20
-rw-r--r--spec/lib/banzai/filter/external_issue_reference_filter_spec.rb10
-rw-r--r--spec/lib/banzai/filter/inline_grafana_metrics_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/issue_reference_filter_spec.rb6
-rw-r--r--spec/lib/banzai/filter/milestone_reference_filter_spec.rb44
-rw-r--r--spec/lib/banzai/reference_redactor_spec.rb7
-rw-r--r--spec/lib/feature/definition_spec.rb11
-rw-r--r--spec/lib/feature_spec.rb4
-rw-r--r--spec/lib/forever_spec.rb2
-rw-r--r--spec/lib/gitlab/alert_management/alert_params_spec.rb101
-rw-r--r--spec/lib/gitlab/alert_management/alert_status_counts_spec.rb4
-rw-r--r--spec/lib/gitlab/alert_management/payload/base_spec.rb103
-rw-r--r--spec/lib/gitlab/alert_management/payload/generic_spec.rb32
-rw-r--r--spec/lib/gitlab/alerting/alert_spec.rb299
-rw-r--r--spec/lib/gitlab/alerting/notification_payload_parser_spec.rb204
-rw-r--r--spec/lib/gitlab/analytics/unique_visits_spec.rb2
-rw-r--r--spec/lib/gitlab/auth/auth_finders_spec.rb26
-rw-r--r--spec/lib/gitlab/auth/current_user_mode_spec.rb2
-rw-r--r--spec/lib/gitlab/auth/otp/strategies/devise_spec.rb16
-rw-r--r--spec/lib/gitlab/auth/otp/strategies/forti_authenticator_spec.rb55
-rw-r--r--spec/lib/gitlab/auth/unique_ips_limiter_spec.rb2
-rw-r--r--spec/lib/gitlab/auth/user_access_denied_reason_spec.rb8
-rw-r--r--spec/lib/gitlab/auth_spec.rb6
-rw-r--r--spec/lib/gitlab/background_migration/add_modified_to_approval_merge_request_rule_spec.rb61
-rw-r--r--spec/lib/gitlab/background_migration/merge_request_assignees_migration_progress_check_spec.rb2
-rw-r--r--spec/lib/gitlab/background_migration/migrate_u2f_webauthn_spec.rb65
-rw-r--r--spec/lib/gitlab/background_migration/migrate_users_bio_to_user_details_spec.rb17
-rw-r--r--spec/lib/gitlab/background_migration/replace_blocked_by_links_spec.rb36
-rw-r--r--spec/lib/gitlab/background_migration/user_mentions/create_resource_user_mention_spec.rb8
-rw-r--r--spec/lib/gitlab/bitbucket_import/importer_spec.rb2
-rw-r--r--spec/lib/gitlab/bulk_import/client_spec.rb95
-rw-r--r--spec/lib/gitlab/checks/matching_merge_request_spec.rb31
-rw-r--r--spec/lib/gitlab/ci/ansi2json/line_spec.rb9
-rw-r--r--spec/lib/gitlab/ci/ansi2json_spec.rb38
-rw-r--r--spec/lib/gitlab/ci/artifact_file_reader_spec.rb11
-rw-r--r--spec/lib/gitlab/ci/config/entry/bridge_spec.rb62
-rw-r--r--spec/lib/gitlab/ci/config/entry/cache_spec.rb108
-rw-r--r--spec/lib/gitlab/ci/config/entry/include_spec.rb25
-rw-r--r--spec/lib/gitlab/ci/config/entry/job_spec.rb4
-rw-r--r--spec/lib/gitlab/ci/config/entry/product/matrix_spec.rb147
-rw-r--r--spec/lib/gitlab/ci/config/entry/product/variables_spec.rb77
-rw-r--r--spec/lib/gitlab/ci/config/entry/root_spec.rb12
-rw-r--r--spec/lib/gitlab/ci/config/entry/variables_spec.rb127
-rw-r--r--spec/lib/gitlab/ci/cron_parser_spec.rb14
-rw-r--r--spec/lib/gitlab/ci/lint_spec.rb43
-rw-r--r--spec/lib/gitlab/ci/parsers/test/junit_spec.rb110
-rw-r--r--spec/lib/gitlab/ci/pipeline/seed/build/cache_spec.rb3
-rw-r--r--spec/lib/gitlab/ci/pipeline/seed/build_spec.rb10
-rw-r--r--spec/lib/gitlab/ci/reports/test_case_spec.rb55
-rw-r--r--spec/lib/gitlab/ci/reports/test_suite_spec.rb14
-rw-r--r--spec/lib/gitlab/ci/runner/backoff_spec.rb126
-rw-r--r--spec/lib/gitlab/ci/status/bridge/common_spec.rb9
-rw-r--r--spec/lib/gitlab/ci/status/bridge/factory_spec.rb61
-rw-r--r--spec/lib/gitlab/ci/status/canceled_spec.rb4
-rw-r--r--spec/lib/gitlab/ci/status/created_spec.rb4
-rw-r--r--spec/lib/gitlab/ci/status/failed_spec.rb4
-rw-r--r--spec/lib/gitlab/ci/status/pending_spec.rb4
-rw-r--r--spec/lib/gitlab/ci/status/preparing_spec.rb4
-rw-r--r--spec/lib/gitlab/ci/status/running_spec.rb4
-rw-r--r--spec/lib/gitlab/ci/status/scheduled_spec.rb4
-rw-r--r--spec/lib/gitlab/ci/status/skipped_spec.rb4
-rw-r--r--spec/lib/gitlab/ci/status/success_spec.rb4
-rw-r--r--spec/lib/gitlab/ci/status/waiting_for_resource_spec.rb4
-rw-r--r--spec/lib/gitlab/ci/templates/Terraform/base_gitlab_ci_yaml_spec.rb27
-rw-r--r--spec/lib/gitlab/ci/templates/terraform_latest_gitlab_ci_yaml_spec.rb46
-rw-r--r--spec/lib/gitlab/ci/trace/checksum_spec.rb121
-rw-r--r--spec/lib/gitlab/ci/trace/metrics_spec.rb18
-rw-r--r--spec/lib/gitlab/ci/trace_spec.rb24
-rw-r--r--spec/lib/gitlab/ci/yaml_processor/result_spec.rb45
-rw-r--r--spec/lib/gitlab/ci/yaml_processor_spec.rb80
-rw-r--r--spec/lib/gitlab/cleanup/orphan_lfs_file_references_spec.rb12
-rw-r--r--spec/lib/gitlab/closing_issue_extractor_spec.rb19
-rw-r--r--spec/lib/gitlab/code_navigation_path_spec.rb14
-rw-r--r--spec/lib/gitlab/config/entry/composable_array_spec.rb69
-rw-r--r--spec/lib/gitlab/config/entry/composable_hash_spec.rb108
-rw-r--r--spec/lib/gitlab/conflict/file_spec.rb2
-rw-r--r--spec/lib/gitlab/cycle_analytics/events_spec.rb273
-rw-r--r--spec/lib/gitlab/danger/commit_linter_spec.rb14
-rw-r--r--spec/lib/gitlab/danger/helper_spec.rb26
-rw-r--r--spec/lib/gitlab/danger/roulette_spec.rb101
-rw-r--r--spec/lib/gitlab/danger/teammate_spec.rb5
-rw-r--r--spec/lib/gitlab/data_builder/deployment_spec.rb4
-rw-r--r--spec/lib/gitlab/database/background_migration_job_spec.rb2
-rw-r--r--spec/lib/gitlab/database/batch_count_spec.rb131
-rw-r--r--spec/lib/gitlab/database/bulk_update_spec.rb139
-rw-r--r--spec/lib/gitlab/database/concurrent_reindex_spec.rb207
-rw-r--r--spec/lib/gitlab/database/migration_helpers_spec.rb343
-rw-r--r--spec/lib/gitlab/database/obsolete_ignored_columns_spec.rb2
-rw-r--r--spec/lib/gitlab/database/partitioning/monthly_strategy_spec.rb2
-rw-r--r--spec/lib/gitlab/database/partitioning_migration_helpers/backfill_partitioned_table_spec.rb17
-rw-r--r--spec/lib/gitlab/database/partitioning_migration_helpers/table_management_helpers_spec.rb6
-rw-r--r--spec/lib/gitlab/database/postgres_index_spec.rb116
-rw-r--r--spec/lib/gitlab/database/reindexing/concurrent_reindex_spec.rb255
-rw-r--r--spec/lib/gitlab/database/reindexing/coordinator_spec.rb68
-rw-r--r--spec/lib/gitlab/database/reindexing/reindex_action_spec.rb86
-rw-r--r--spec/lib/gitlab/database/reindexing_spec.rb32
-rw-r--r--spec/lib/gitlab/database/similarity_score_spec.rb11
-rw-r--r--spec/lib/gitlab/database/with_lock_retries_spec.rb64
-rw-r--r--spec/lib/gitlab/database_spec.rb101
-rw-r--r--spec/lib/gitlab/diff/file_collection/merge_request_diff_batch_spec.rb2
-rw-r--r--spec/lib/gitlab/diff/highlight_cache_spec.rb34
-rw-r--r--spec/lib/gitlab/email/handler/create_note_handler_spec.rb23
-rw-r--r--spec/lib/gitlab/exclusive_lease_helpers_spec.rb15
-rw-r--r--spec/lib/gitlab/experimentation_spec.rb177
-rw-r--r--spec/lib/gitlab/git/branch_spec.rb6
-rw-r--r--spec/lib/gitlab/git/diff_collection_spec.rb46
-rw-r--r--spec/lib/gitlab/git/diff_spec.rb12
-rw-r--r--spec/lib/gitlab/git/object_pool_spec.rb4
-rw-r--r--spec/lib/gitlab/git/remote_mirror_spec.rb4
-rw-r--r--spec/lib/gitlab/git/repository_spec.rb37
-rw-r--r--spec/lib/gitlab/git/rugged_impl/use_rugged_spec.rb4
-rw-r--r--spec/lib/gitlab/git/wiki_spec.rb5
-rw-r--r--spec/lib/gitlab/git_access_snippet_spec.rb25
-rw-r--r--spec/lib/gitlab/git_access_spec.rb23
-rw-r--r--spec/lib/gitlab/git_access_wiki_spec.rb18
-rw-r--r--spec/lib/gitlab/gitaly_client/commit_service_spec.rb4
-rw-r--r--spec/lib/gitlab/gitaly_client/operation_service_spec.rb3
-rw-r--r--spec/lib/gitlab/gitpod_spec.rb31
-rw-r--r--spec/lib/gitlab/gl_repository/identifier_spec.rb12
-rw-r--r--spec/lib/gitlab/gl_repository/repo_type_spec.rb8
-rw-r--r--spec/lib/gitlab/gl_repository_spec.rb2
-rw-r--r--spec/lib/gitlab/gon_helper_spec.rb4
-rw-r--r--spec/lib/gitlab/grape_logging/loggers/queue_duration_logger_spec.rb2
-rw-r--r--spec/lib/gitlab/graphql/authorize/authorize_field_service_spec.rb49
-rw-r--r--spec/lib/gitlab/graphql/markdown_field/resolver_spec.rb33
-rw-r--r--spec/lib/gitlab/graphql/markdown_field_spec.rb59
-rw-r--r--spec/lib/gitlab/graphql/pagination/keyset/last_items_spec.rb26
-rw-r--r--spec/lib/gitlab/graphql/pagination/keyset/order_info_spec.rb23
-rw-r--r--spec/lib/gitlab/graphql/pagination/keyset/query_builder_spec.rb7
-rw-r--r--spec/lib/gitlab/graphql/query_analyzers/logger_analyzer_spec.rb2
-rw-r--r--spec/lib/gitlab/group_search_results_spec.rb7
-rw-r--r--spec/lib/gitlab/import_export/all_models.yml13
-rw-r--r--spec/lib/gitlab/import_export/fast_hash_serializer_spec.rb10
-rw-r--r--spec/lib/gitlab/import_export/group/relation_factory_spec.rb95
-rw-r--r--spec/lib/gitlab/import_export/import_test_coverage_spec.rb1
-rw-r--r--spec/lib/gitlab/import_export/json/ndjson_reader_spec.rb10
-rw-r--r--spec/lib/gitlab/import_export/lfs_saver_spec.rb8
-rw-r--r--spec/lib/gitlab/import_export/project/relation_factory_spec.rb73
-rw-r--r--spec/lib/gitlab/import_export/project/sample/date_calculator_spec.rb53
-rw-r--r--spec/lib/gitlab/import_export/project/sample/sample_data_relation_tree_restorer_spec.rb87
-rw-r--r--spec/lib/gitlab/import_export/project/tree_restorer_spec.rb35
-rw-r--r--spec/lib/gitlab/import_export/relation_tree_restorer_spec.rb10
-rw-r--r--spec/lib/gitlab/import_export/repo_restorer_spec.rb21
-rw-r--r--spec/lib/gitlab/import_export/safe_model_attributes.yml3
-rw-r--r--spec/lib/gitlab/issuables_count_for_state_spec.rb21
-rw-r--r--spec/lib/gitlab/job_waiter_spec.rb17
-rw-r--r--spec/lib/gitlab/kubernetes/kube_client_spec.rb32
-rw-r--r--spec/lib/gitlab/lfs/client_spec.rb132
-rw-r--r--spec/lib/gitlab/lfs_token_spec.rb2
-rw-r--r--spec/lib/gitlab/manifest_import/manifest_spec.rb14
-rw-r--r--spec/lib/gitlab/manifest_import/metadata_spec.rb62
-rw-r--r--spec/lib/gitlab/metrics/dashboard/importers/prometheus_metrics_spec.rb82
-rw-r--r--spec/lib/gitlab/metrics/requests_rack_middleware_spec.rb121
-rw-r--r--spec/lib/gitlab/middleware/go_spec.rb16
-rw-r--r--spec/lib/gitlab/middleware/handle_null_bytes_spec.rb88
-rw-r--r--spec/lib/gitlab/middleware/rails_queue_duration_spec.rb2
-rw-r--r--spec/lib/gitlab/middleware/same_site_cookies_spec.rb4
-rw-r--r--spec/lib/gitlab/pagination/offset_pagination_spec.rb30
-rw-r--r--spec/lib/gitlab/project_search_results_spec.rb6
-rw-r--r--spec/lib/gitlab/project_template_spec.rb6
-rw-r--r--spec/lib/gitlab/prometheus/queries/additional_metrics_deployment_query_spec.rb2
-rw-r--r--spec/lib/gitlab/prometheus/queries/deployment_query_spec.rb2
-rw-r--r--spec/lib/gitlab/prometheus/query_variables_spec.rb4
-rw-r--r--spec/lib/gitlab/redis/hll_spec.rb30
-rw-r--r--spec/lib/gitlab/regex_spec.rb221
-rw-r--r--spec/lib/gitlab/relative_positioning/mover_spec.rb17
-rw-r--r--spec/lib/gitlab/repo_path_spec.rb6
-rw-r--r--spec/lib/gitlab/repository_size_checker_spec.rb59
-rw-r--r--spec/lib/gitlab/repository_size_error_message_spec.rb6
-rw-r--r--spec/lib/gitlab/sample_data_template_spec.rb66
-rw-r--r--spec/lib/gitlab/search/recent_issues_spec.rb6
-rw-r--r--spec/lib/gitlab/search/recent_merge_requests_spec.rb6
-rw-r--r--spec/lib/gitlab/search_results_spec.rb58
-rw-r--r--spec/lib/gitlab/sidekiq_cluster_spec.rb6
-rw-r--r--spec/lib/gitlab/sidekiq_middleware/worker_context/server_spec.rb7
-rw-r--r--spec/lib/gitlab/snippet_search_results_spec.rb6
-rw-r--r--spec/lib/gitlab/sql/pattern_spec.rb37
-rw-r--r--spec/lib/gitlab/static_site_editor/config/file_config/entry/global_spec.rb245
-rw-r--r--spec/lib/gitlab/static_site_editor/config/file_config/entry/image_upload_path_spec.rb38
-rw-r--r--spec/lib/gitlab/static_site_editor/config/file_config/entry/mount_spec.rb101
-rw-r--r--spec/lib/gitlab/static_site_editor/config/file_config/entry/mounts_spec.rb53
-rw-r--r--spec/lib/gitlab/static_site_editor/config/file_config/entry/static_site_generator_spec.rb50
-rw-r--r--spec/lib/gitlab/static_site_editor/config/file_config_spec.rb82
-rw-r--r--spec/lib/gitlab/static_site_editor/config/generated_config_spec.rb22
-rw-r--r--spec/lib/gitlab/subscription_portal_spec.rb42
-rw-r--r--spec/lib/gitlab/themes_spec.rb14
-rw-r--r--spec/lib/gitlab/tracking_spec.rb2
-rw-r--r--spec/lib/gitlab/usage_data_counters/editor_unique_counter_spec.rb12
-rw-r--r--spec/lib/gitlab/usage_data_counters/hll_redis_counter_spec.rb28
-rw-r--r--spec/lib/gitlab/usage_data_counters/issue_activity_unique_counter_spec.rb210
-rw-r--r--spec/lib/gitlab/usage_data_counters/static_site_editor_counter_spec.rb10
-rw-r--r--spec/lib/gitlab/usage_data_counters/track_unique_events_spec.rb4
-rw-r--r--spec/lib/gitlab/usage_data_spec.rb119
-rw-r--r--spec/lib/gitlab/utils/usage_data_spec.rb17
-rw-r--r--spec/lib/gitlab/visibility_level_checker_spec.rb37
-rw-r--r--spec/lib/gitlab/webpack/manifest_spec.rb113
-rw-r--r--spec/lib/gitlab/workhorse_spec.rb34
-rw-r--r--spec/lib/gitlab_danger_spec.rb2
-rw-r--r--spec/lib/google_api/auth_spec.rb8
-rw-r--r--spec/lib/grafana/time_window_spec.rb6
-rw-r--r--spec/lib/marginalia_spec.rb25
-rw-r--r--spec/lib/pager_duty/webhook_payload_parser_spec.rb84
-rw-r--r--spec/lib/safe_zip/extract_spec.rb36
-rw-r--r--spec/mailers/abuse_report_mailer_spec.rb10
-rw-r--r--spec/mailers/emails/merge_requests_spec.rb33
-rw-r--r--spec/mailers/emails/projects_spec.rb119
-rw-r--r--spec/mailers/notify_spec.rb118
-rw-r--r--spec/migrations/20200929052138_create_initial_versions_for_pre_versioning_terraform_states_spec.rb46
-rw-r--r--spec/migrations/20201014205300_drop_backfill_jira_tracker_deployment_type_jobs_spec.rb58
-rw-r--r--spec/migrations/add_partial_index_to_ci_builds_table_on_user_id_name_spec.rb22
-rw-r--r--spec/migrations/backfill_status_page_published_incidents_spec.rb2
-rw-r--r--spec/migrations/cleanup_group_import_states_with_null_user_id_spec.rb101
-rw-r--r--spec/migrations/ensure_filled_file_store_on_package_files_spec.rb40
-rw-r--r--spec/migrations/migrate_compliance_framework_enum_to_database_framework_record_spec.rb70
-rw-r--r--spec/migrations/schedule_blocked_by_links_replacement_spec.rb37
-rw-r--r--spec/migrations/schedule_migrate_u2f_webauthn_spec.rb58
-rw-r--r--spec/migrations/set_job_waiter_ttl_spec.rb30
-rw-r--r--spec/models/alert_management/alert_spec.rb171
-rw-r--r--spec/models/alert_management/http_integration_spec.rb92
-rw-r--r--spec/models/analytics/instance_statistics/measurement_spec.rb30
-rw-r--r--spec/models/application_record_spec.rb8
-rw-r--r--spec/models/application_setting/term_spec.rb5
-rw-r--r--spec/models/application_setting_spec.rb48
-rw-r--r--spec/models/audit_event_spec.rb7
-rw-r--r--spec/models/authentication_event_spec.rb36
-rw-r--r--spec/models/blob_viewer/markup_spec.rb38
-rw-r--r--spec/models/bulk_import_spec.rb18
-rw-r--r--spec/models/bulk_imports/configuration_spec.rb17
-rw-r--r--spec/models/bulk_imports/entity_spec.rb85
-rw-r--r--spec/models/ci/bridge_spec.rb91
-rw-r--r--spec/models/ci/build_pending_state_spec.rb27
-rw-r--r--spec/models/ci/build_spec.rb162
-rw-r--r--spec/models/ci/build_trace_chunk_spec.rb138
-rw-r--r--spec/models/ci/deleted_object_spec.rb95
-rw-r--r--spec/models/ci/freeze_period_status_spec.rb4
-rw-r--r--spec/models/ci/job_artifact_spec.rb4
-rw-r--r--spec/models/ci/pipeline_schedule_spec.rb4
-rw-r--r--spec/models/ci/pipeline_spec.rb63
-rw-r--r--spec/models/ci_platform_metric_spec.rb6
-rw-r--r--spec/models/clusters/agent_spec.rb14
-rw-r--r--spec/models/clusters/applications/fluentd_spec.rb2
-rw-r--r--spec/models/clusters/applications/ingress_spec.rb2
-rw-r--r--spec/models/clusters/applications/prometheus_spec.rb4
-rw-r--r--spec/models/clusters/applications/runner_spec.rb4
-rw-r--r--spec/models/clusters/cluster_spec.rb1
-rw-r--r--spec/models/clusters/platforms/kubernetes_spec.rb5
-rw-r--r--spec/models/commit_status_spec.rb133
-rw-r--r--spec/models/concerns/avatarable_spec.rb4
-rw-r--r--spec/models/concerns/bulk_insertable_associations_spec.rb6
-rw-r--r--spec/models/concerns/cache_markdown_field_spec.rb6
-rw-r--r--spec/models/concerns/case_sensitivity_spec.rb4
-rw-r--r--spec/models/concerns/checksummable_spec.rb16
-rw-r--r--spec/models/concerns/counter_attribute_spec.rb30
-rw-r--r--spec/models/concerns/each_batch_spec.rb6
-rw-r--r--spec/models/concerns/featurable_spec.rb2
-rw-r--r--spec/models/concerns/has_user_type_spec.rb8
-rw-r--r--spec/models/concerns/issuable_spec.rb76
-rw-r--r--spec/models/concerns/mentionable_spec.rb6
-rw-r--r--spec/models/concerns/milestoneable_spec.rb2
-rw-r--r--spec/models/concerns/milestoneish_spec.rb8
-rw-r--r--spec/models/concerns/reactive_caching_spec.rb11
-rw-r--r--spec/models/concerns/resolvable_discussion_spec.rb6
-rw-r--r--spec/models/concerns/routable_spec.rb2
-rw-r--r--spec/models/concerns/schedulable_spec.rb2
-rw-r--r--spec/models/concerns/subscribable_spec.rb22
-rw-r--r--spec/models/concerns/token_authenticatable_spec.rb2
-rw-r--r--spec/models/container_expiration_policy_spec.rb12
-rw-r--r--spec/models/container_repository_spec.rb27
-rw-r--r--spec/models/deploy_token_spec.rb25
-rw-r--r--spec/models/deployment_spec.rb65
-rw-r--r--spec/models/design_management/design_at_version_spec.rb23
-rw-r--r--spec/models/design_management/design_collection_spec.rb12
-rw-r--r--spec/models/design_management/design_spec.rb9
-rw-r--r--spec/models/environment_spec.rb13
-rw-r--r--spec/models/environment_status_spec.rb12
-rw-r--r--spec/models/event_spec.rb50
-rw-r--r--spec/models/group_import_state_spec.rb1
-rw-r--r--spec/models/group_spec.rb371
-rw-r--r--spec/models/import_failure_spec.rb2
-rw-r--r--spec/models/integration_spec.rb18
-rw-r--r--spec/models/issue/metrics_spec.rb14
-rw-r--r--spec/models/issue_email_participant_spec.rb19
-rw-r--r--spec/models/issue_spec.rb158
-rw-r--r--spec/models/iteration_spec.rb45
-rw-r--r--spec/models/member_spec.rb76
-rw-r--r--spec/models/merge_request_diff_spec.rb53
-rw-r--r--spec/models/merge_request_spec.rb140
-rw-r--r--spec/models/milestone_release_spec.rb2
-rw-r--r--spec/models/namespace_setting_spec.rb68
-rw-r--r--spec/models/namespace_spec.rb184
-rw-r--r--spec/models/notification_setting_spec.rb1
-rw-r--r--spec/models/operations/feature_flag_spec.rb18
-rw-r--r--spec/models/operations/feature_flags/strategy_spec.rb176
-rw-r--r--spec/models/packages/package_spec.rb29
-rw-r--r--spec/models/pages_deployment_spec.rb17
-rw-r--r--spec/models/plan_limits_spec.rb1
-rw-r--r--spec/models/preloaders/merge_request_diff_preloader_spec.rb29
-rw-r--r--spec/models/project_feature_usage_spec.rb2
-rw-r--r--spec/models/project_repository_spec.rb5
-rw-r--r--spec/models/project_repository_storage_move_spec.rb12
-rw-r--r--spec/models/project_services/chat_message/deployment_message_spec.rb11
-rw-r--r--spec/models/project_services/chat_message/issue_message_spec.rb4
-rw-r--r--spec/models/project_services/prometheus_service_spec.rb12
-rw-r--r--spec/models/project_spec.rb101
-rw-r--r--spec/models/project_statistics_spec.rb52
-rw-r--r--spec/models/project_tracing_setting_spec.rb40
-rw-r--r--spec/models/project_wiki_spec.rb1
-rw-r--r--spec/models/repository_spec.rb21
-rw-r--r--spec/models/resource_label_event_spec.rb36
-rw-r--r--spec/models/resource_milestone_event_spec.rb1
-rw-r--r--spec/models/resource_state_event_spec.rb16
-rw-r--r--spec/models/resource_weight_event_spec.rb76
-rw-r--r--spec/models/service_spec.rb144
-rw-r--r--spec/models/snippet_input_action_spec.rb2
-rw-r--r--spec/models/snippet_repository_spec.rb39
-rw-r--r--spec/models/snippet_spec.rb17
-rw-r--r--spec/models/snippet_statistics_spec.rb19
-rw-r--r--spec/models/terraform/state_spec.rb56
-rw-r--r--spec/models/terraform/state_version_spec.rb2
-rw-r--r--spec/models/todo_spec.rb46
-rw-r--r--spec/models/user_spec.rb102
-rw-r--r--spec/models/wiki_directory_spec.rb78
-rw-r--r--spec/models/wiki_page_spec.rb293
-rw-r--r--spec/models/wiki_spec.rb14
-rw-r--r--spec/policies/ci/bridge_policy_spec.rb39
-rw-r--r--spec/policies/design_management/design_policy_spec.rb36
-rw-r--r--spec/policies/global_policy_spec.rb76
-rw-r--r--spec/policies/group_policy_spec.rb70
-rw-r--r--spec/policies/project_policy_spec.rb2
-rw-r--r--spec/policies/terraform/state_policy_spec.rb33
-rw-r--r--spec/presenters/ci/pipeline_presenter_spec.rb17
-rw-r--r--spec/presenters/event_presenter_spec.rb30
-rw-r--r--spec/presenters/label_presenter_spec.rb14
-rw-r--r--spec/presenters/merge_request_presenter_spec.rb21
-rw-r--r--spec/presenters/packages/detail/package_presenter_spec.rb2
-rw-r--r--spec/presenters/project_presenter_spec.rb51
-rw-r--r--spec/presenters/projects/prometheus/alert_presenter_spec.rb346
-rw-r--r--spec/presenters/release_presenter_spec.rb8
-rw-r--r--spec/presenters/sentry_error_presenter_spec.rb8
-rw-r--r--spec/presenters/snippet_blob_presenter_spec.rb122
-rw-r--r--spec/presenters/snippet_presenter_spec.rb21
-rw-r--r--spec/requests/api/admin/instance_clusters_spec.rb18
-rw-r--r--spec/requests/api/api_guard/response_coercer_middleware_spec.rb55
-rw-r--r--spec/requests/api/ci/runner/jobs_artifacts_spec.rb30
-rw-r--r--spec/requests/api/ci/runner/jobs_put_spec.rb45
-rw-r--r--spec/requests/api/ci/runner/jobs_request_post_spec.rb3
-rw-r--r--spec/requests/api/commits_spec.rb58
-rw-r--r--spec/requests/api/composer_packages_spec.rb28
-rw-r--r--spec/requests/api/debian_group_packages_spec.rb39
-rw-r--r--spec/requests/api/debian_project_packages_spec.rb46
-rw-r--r--spec/requests/api/doorkeeper_access_spec.rb8
-rw-r--r--spec/requests/api/feature_flag_scopes_spec.rb319
-rw-r--r--spec/requests/api/feature_flags_spec.rb1130
-rw-r--r--spec/requests/api/feature_flags_user_lists_spec.rb371
-rw-r--r--spec/requests/api/features_spec.rb2
-rw-r--r--spec/requests/api/files_spec.rb6
-rw-r--r--spec/requests/api/generic_packages_spec.rb419
-rw-r--r--spec/requests/api/graphql/boards/board_lists_query_spec.rb15
-rw-r--r--spec/requests/api/graphql/gitlab_schema_spec.rb4
-rw-r--r--spec/requests/api/graphql/group/merge_requests_spec.rb122
-rw-r--r--spec/requests/api/graphql/instance_statistics_measurements_spec.rb7
-rw-r--r--spec/requests/api/graphql/mutations/award_emojis/add_spec.rb5
-rw-r--r--spec/requests/api/graphql/mutations/award_emojis/remove_spec.rb5
-rw-r--r--spec/requests/api/graphql/mutations/award_emojis/toggle_spec.rb5
-rw-r--r--spec/requests/api/graphql/mutations/boards/create_spec.rb16
-rw-r--r--spec/requests/api/graphql/mutations/boards/lists/destroy_spec.rb77
-rw-r--r--spec/requests/api/graphql/mutations/issues/create_spec.rb48
-rw-r--r--spec/requests/api/graphql/mutations/issues/move_spec.rb73
-rw-r--r--spec/requests/api/graphql/mutations/issues/update_spec.rb15
-rw-r--r--spec/requests/api/graphql/mutations/metrics/dashboard/annotations/create_spec.rb32
-rw-r--r--spec/requests/api/graphql/mutations/notes/create/note_spec.rb8
-rw-r--r--spec/requests/api/graphql/mutations/notes/update/image_diff_note_spec.rb6
-rw-r--r--spec/requests/api/graphql/mutations/snippets/create_spec.rb21
-rw-r--r--spec/requests/api/graphql/mutations/snippets/update_spec.rb31
-rw-r--r--spec/requests/api/graphql/mutations/todos/mark_done_spec.rb6
-rw-r--r--spec/requests/api/graphql/mutations/todos/restore_spec.rb6
-rw-r--r--spec/requests/api/graphql/project/alert_management/alerts_spec.rb13
-rw-r--r--spec/requests/api/graphql/project/issue/designs/notes_spec.rb16
-rw-r--r--spec/requests/api/graphql/project/issues_spec.rb35
-rw-r--r--spec/requests/api/graphql/project/merge_requests_spec.rb75
-rw-r--r--spec/requests/api/graphql/project/milestones_spec.rb202
-rw-r--r--spec/requests/api/graphql/user_query_spec.rb40
-rw-r--r--spec/requests/api/graphql_spec.rb10
-rw-r--r--spec/requests/api/group_clusters_spec.rb18
-rw-r--r--spec/requests/api/group_container_repositories_spec.rb3
-rw-r--r--spec/requests/api/group_packages_spec.rb6
-rw-r--r--spec/requests/api/groups_spec.rb133
-rw-r--r--spec/requests/api/helpers_spec.rb63
-rw-r--r--spec/requests/api/internal/base_spec.rb334
-rw-r--r--spec/requests/api/internal/lfs_spec.rb93
-rw-r--r--spec/requests/api/jobs_spec.rb16
-rw-r--r--spec/requests/api/lint_spec.rb249
-rw-r--r--spec/requests/api/maven_packages_spec.rb74
-rw-r--r--spec/requests/api/members_spec.rb31
-rw-r--r--spec/requests/api/merge_requests_spec.rb51
-rw-r--r--spec/requests/api/npm_packages_spec.rb10
-rw-r--r--spec/requests/api/project_clusters_spec.rb18
-rw-r--r--spec/requests/api/project_container_repositories_spec.rb9
-rw-r--r--spec/requests/api/project_packages_spec.rb13
-rw-r--r--spec/requests/api/project_repository_storage_moves_spec.rb11
-rw-r--r--spec/requests/api/project_snippets_spec.rb125
-rw-r--r--spec/requests/api/projects_spec.rb2
-rw-r--r--spec/requests/api/pypi_packages_spec.rb156
-rw-r--r--spec/requests/api/releases_spec.rb185
-rw-r--r--spec/requests/api/repositories_spec.rb4
-rw-r--r--spec/requests/api/search_spec.rb67
-rw-r--r--spec/requests/api/services_spec.rb30
-rw-r--r--spec/requests/api/settings_spec.rb10
-rw-r--r--spec/requests/api/snippets_spec.rb175
-rw-r--r--spec/requests/api/terraform/state_spec.rb2
-rw-r--r--spec/requests/api/terraform/state_version_spec.rb210
-rw-r--r--spec/requests/api/unleash_spec.rb608
-rw-r--r--spec/requests/api/usage_data_spec.rb4
-rw-r--r--spec/requests/api/users_spec.rb144
-rw-r--r--spec/requests/git_http_spec.rb26
-rw-r--r--spec/requests/projects/cycle_analytics_events_spec.rb2
-rw-r--r--spec/requests/rack_attack_global_spec.rb2
-rw-r--r--spec/requests/request_profiler_spec.rb2
-rw-r--r--spec/requests/user_activity_spec.rb94
-rw-r--r--spec/requests/user_sends_null_bytes_spec.rb14
-rw-r--r--spec/requests/whats_new_controller_spec.rb35
-rw-r--r--spec/routing/admin_routing_spec.rb6
-rw-r--r--spec/routing/group_routing_spec.rb4
-rw-r--r--spec/routing/instance_statistics_routing_spec.rb11
-rw-r--r--spec/routing/project_routing_spec.rb21
-rw-r--r--spec/routing/routing_spec.rb29
-rw-r--r--spec/rubocop/cop/api/base_spec.rb35
-rw-r--r--spec/rubocop/cop/api/grape_api_instance_spec.rb29
-rw-r--r--spec/rubocop/cop/code_reuse/active_record_spec.rb6
-rw-r--r--spec/rubocop/cop/graphql/gid_expected_type_spec.rb26
-rw-r--r--spec/rubocop/cop/graphql/id_type_spec.rb36
-rw-r--r--spec/rubocop/cop/migration/add_concurrent_foreign_key_spec.rb10
-rw-r--r--spec/rubocop/cop/migration/add_limit_to_text_columns_spec.rb22
-rw-r--r--spec/rubocop/cop/migration/create_table_with_foreign_keys_spec.rb2
-rw-r--r--spec/rubocop/cop/migration/with_lock_retries_disallowed_method_spec.rb16
-rw-r--r--spec/rubocop/cop/rspec/expect_gitlab_tracking_spec.rb65
-rw-r--r--spec/rubocop/cop/rspec/factory_bot/inline_association_spec.rb132
-rw-r--r--spec/rubocop/cop/rspec/timecop_travel_spec.rb52
-rw-r--r--spec/serializers/blob_entity_spec.rb2
-rw-r--r--spec/serializers/ci/trigger_entity_spec.rb70
-rw-r--r--spec/serializers/ci/trigger_serializer_spec.rb15
-rw-r--r--spec/serializers/cluster_serializer_spec.rb1
-rw-r--r--spec/serializers/deployment_entity_spec.rb4
-rw-r--r--spec/serializers/diff_file_base_entity_spec.rb55
-rw-r--r--spec/serializers/diffs_entity_spec.rb10
-rw-r--r--spec/serializers/discussion_entity_spec.rb8
-rw-r--r--spec/serializers/feature_flag_entity_spec.rb22
-rw-r--r--spec/serializers/feature_flag_serializer_spec.rb23
-rw-r--r--spec/serializers/feature_flag_summary_entity_spec.rb21
-rw-r--r--spec/serializers/feature_flag_summary_serializer_spec.rb22
-rw-r--r--spec/serializers/feature_flags_client_serializer_spec.rb17
-rw-r--r--spec/serializers/group_group_link_entity_spec.rb22
-rw-r--r--spec/serializers/import/bulk_import_entity_spec.rb26
-rw-r--r--spec/serializers/label_serializer_spec.rb3
-rw-r--r--spec/serializers/merge_request_poll_cached_widget_entity_spec.rb61
-rw-r--r--spec/serializers/merge_request_poll_widget_entity_spec.rb33
-rw-r--r--spec/serializers/merge_request_widget_entity_spec.rb50
-rw-r--r--spec/serializers/paginated_diff_entity_spec.rb10
-rw-r--r--spec/serializers/pipeline_serializer_spec.rb9
-rw-r--r--spec/serializers/test_case_entity_spec.rb2
-rw-r--r--spec/services/admin/propagate_integration_service_spec.rb142
-rw-r--r--spec/services/admin/propagate_service_template_spec.rb125
-rw-r--r--spec/services/alert_management/alerts/update_service_spec.rb6
-rw-r--r--spec/services/alert_management/process_prometheus_alert_service_spec.rb38
-rw-r--r--spec/services/audit_event_service_spec.rb13
-rw-r--r--spec/services/bulk_create_integration_service_spec.rb107
-rw-r--r--spec/services/bulk_update_integration_service_spec.rb57
-rw-r--r--spec/services/ci/build_report_result_service_spec.rb21
-rw-r--r--spec/services/ci/create_downstream_pipeline_service_spec.rb14
-rw-r--r--spec/services/ci/create_pipeline_service/cache_spec.rb15
-rw-r--r--spec/services/ci/create_pipeline_service/parent_child_pipeline_spec.rb61
-rw-r--r--spec/services/ci/create_pipeline_service_spec.rb27
-rw-r--r--spec/services/ci/delete_objects_service_spec.rb133
-rw-r--r--spec/services/ci/destroy_expired_job_artifacts_service_spec.rb13
-rw-r--r--spec/services/ci/expire_pipeline_cache_service_spec.rb2
-rw-r--r--spec/services/ci/list_config_variables_service_spec.rb77
-rw-r--r--spec/services/ci/pipeline_processing/shared_processing_service.rb10
-rw-r--r--spec/services/ci/pipeline_processing/shared_processing_service_tests_with_yaml.rb4
-rw-r--r--spec/services/ci/pipelines/create_artifact_service_spec.rb10
-rw-r--r--spec/services/ci/play_bridge_service_spec.rb56
-rw-r--r--spec/services/ci/play_manual_stage_service_spec.rb42
-rw-r--r--spec/services/ci/retry_build_service_spec.rb37
-rw-r--r--spec/services/ci/update_build_queue_service_spec.rb16
-rw-r--r--spec/services/ci/update_build_state_service_spec.rb109
-rw-r--r--spec/services/clusters/gcp/finalize_creation_service_spec.rb15
-rw-r--r--spec/services/clusters/kubernetes/configure_istio_ingress_service_spec.rb20
-rw-r--r--spec/services/clusters/kubernetes/create_or_update_namespace_service_spec.rb8
-rw-r--r--spec/services/clusters/kubernetes/create_or_update_service_account_service_spec.rb70
-rw-r--r--spec/services/clusters/kubernetes/fetch_kubernetes_token_service_spec.rb32
-rw-r--r--spec/services/deployments/after_create_service_spec.rb287
-rw-r--r--spec/services/deployments/create_service_spec.rb10
-rw-r--r--spec/services/deployments/update_environment_service_spec.rb288
-rw-r--r--spec/services/design_management/copy_design_collection/copy_service_spec.rb259
-rw-r--r--spec/services/design_management/copy_design_collection/queue_service_spec.rb51
-rw-r--r--spec/services/design_management/delete_designs_service_spec.rb18
-rw-r--r--spec/services/design_management/generate_image_versions_service_spec.rb51
-rw-r--r--spec/services/design_management/save_designs_service_spec.rb43
-rw-r--r--spec/services/feature_flags/create_service_spec.rb79
-rw-r--r--spec/services/feature_flags/destroy_service_spec.rb61
-rw-r--r--spec/services/feature_flags/disable_service_spec.rb91
-rw-r--r--spec/services/feature_flags/enable_service_spec.rb153
-rw-r--r--spec/services/feature_flags/update_service_spec.rb250
-rw-r--r--spec/services/git/branch_hooks_service_spec.rb22
-rw-r--r--spec/services/git/wiki_push_service_spec.rb18
-rw-r--r--spec/services/groups/create_service_spec.rb96
-rw-r--r--spec/services/groups/import_export/import_service_spec.rb9
-rw-r--r--spec/services/groups/transfer_service_spec.rb71
-rw-r--r--spec/services/groups/update_service_spec.rb44
-rw-r--r--spec/services/groups/update_shared_runners_service_spec.rb194
-rw-r--r--spec/services/incident_management/create_incident_label_service_spec.rb62
-rw-r--r--spec/services/incident_management/incidents/update_severity_service_spec.rb86
-rw-r--r--spec/services/issuable/bulk_update_service_spec.rb2
-rw-r--r--spec/services/issuable/clone/attributes_rewriter_spec.rb10
-rw-r--r--spec/services/issuable/common_system_notes_service_spec.rb8
-rw-r--r--spec/services/issues/build_service_spec.rb70
-rw-r--r--spec/services/issues/close_service_spec.rb23
-rw-r--r--spec/services/issues/move_service_spec.rb43
-rw-r--r--spec/services/issues/update_service_spec.rb2
-rw-r--r--spec/services/jira/requests/projects/list_service_spec.rb4
-rw-r--r--spec/services/keys/last_used_service_spec.rb2
-rw-r--r--spec/services/lfs/push_service_spec.rb48
-rw-r--r--spec/services/members/destroy_service_spec.rb18
-rw-r--r--spec/services/members/invitation_reminder_email_service_spec.rb78
-rw-r--r--spec/services/merge_requests/cleanup_refs_service_spec.rb11
-rw-r--r--spec/services/merge_requests/close_service_spec.rb67
-rw-r--r--spec/services/merge_requests/create_from_issue_service_spec.rb2
-rw-r--r--spec/services/merge_requests/export_csv_service_spec.rb115
-rw-r--r--spec/services/merge_requests/ff_merge_service_spec.rb104
-rw-r--r--spec/services/merge_requests/merge_service_spec.rb22
-rw-r--r--spec/services/merge_requests/merge_to_ref_service_spec.rb11
-rw-r--r--spec/services/merge_requests/mergeability_check_service_spec.rb43
-rw-r--r--spec/services/merge_requests/refresh_service_spec.rb161
-rw-r--r--spec/services/merge_requests/reopen_service_spec.rb20
-rw-r--r--spec/services/merge_requests/update_service_spec.rb53
-rw-r--r--spec/services/metrics/dashboard/custom_dashboard_service_spec.rb17
-rw-r--r--spec/services/milestones/destroy_service_spec.rb2
-rw-r--r--spec/services/milestones/promote_service_spec.rb2
-rw-r--r--spec/services/milestones/transfer_service_spec.rb2
-rw-r--r--spec/services/namespace_settings/update_service_spec.rb48
-rw-r--r--spec/services/notes/create_service_spec.rb10
-rw-r--r--spec/services/notes/update_service_spec.rb2
-rw-r--r--spec/services/notification_service_spec.rb104
-rw-r--r--spec/services/packages/composer/composer_json_service_spec.rb4
-rw-r--r--spec/services/packages/create_event_service_spec.rb54
-rw-r--r--spec/services/packages/generic/create_package_file_service_spec.rb54
-rw-r--r--spec/services/packages/generic/find_or_create_package_service_spec.rb88
-rw-r--r--spec/services/projects/after_rename_service_spec.rb2
-rw-r--r--spec/services/projects/alerting/notify_service_spec.rb49
-rw-r--r--spec/services/projects/autocomplete_service_spec.rb4
-rw-r--r--spec/services/projects/container_repository/cleanup_tags_service_spec.rb2
-rw-r--r--spec/services/projects/container_repository/delete_tags_service_spec.rb58
-rw-r--r--spec/services/projects/create_service_spec.rb196
-rw-r--r--spec/services/projects/destroy_service_spec.rb2
-rw-r--r--spec/services/projects/fork_service_spec.rb4
-rw-r--r--spec/services/projects/hashed_storage/base_attachment_service_spec.rb2
-rw-r--r--spec/services/projects/move_access_service_spec.rb8
-rw-r--r--spec/services/projects/move_project_group_links_service_spec.rb14
-rw-r--r--spec/services/projects/operations/update_service_spec.rb92
-rw-r--r--spec/services/projects/overwrite_project_service_spec.rb6
-rw-r--r--spec/services/projects/transfer_service_spec.rb31
-rw-r--r--spec/services/projects/unlink_fork_service_spec.rb2
-rw-r--r--spec/services/projects/update_pages_service_spec.rb34
-rw-r--r--spec/services/projects/update_remote_mirror_service_spec.rb71
-rw-r--r--spec/services/projects/update_service_spec.rb34
-rw-r--r--spec/services/quick_actions/interpret_service_spec.rb76
-rw-r--r--spec/services/repositories/destroy_service_spec.rb20
-rw-r--r--spec/services/repository_archive_clean_up_service_spec.rb22
-rw-r--r--spec/services/resource_access_tokens/create_service_spec.rb63
-rw-r--r--spec/services/resource_access_tokens/revoke_service_spec.rb74
-rw-r--r--spec/services/search/global_service_spec.rb30
-rw-r--r--spec/services/search/group_service_spec.rb32
-rw-r--r--spec/services/search_service_spec.rb6
-rw-r--r--spec/services/snippets/repository_validation_service_spec.rb6
-rw-r--r--spec/services/snippets/update_service_spec.rb95
-rw-r--r--spec/services/static_site_editor/config_service_spec.rb86
-rw-r--r--spec/services/system_note_service_spec.rb24
-rw-r--r--spec/services/system_notes/incident_service_spec.rb59
-rw-r--r--spec/services/system_notes/issuables_service_spec.rb142
-rw-r--r--spec/services/system_notes/time_tracking_service_spec.rb201
-rw-r--r--spec/services/todos/destroy/entity_leave_service_spec.rb164
-rw-r--r--spec/services/users/approve_service_spec.rb106
-rw-r--r--spec/services/users/block_service_spec.rb10
-rw-r--r--spec/services/users/build_service_spec.rb20
-rw-r--r--spec/services/users/destroy_service_spec.rb8
-rw-r--r--spec/services/users/validate_otp_service_spec.rb34
-rw-r--r--spec/services/web_hooks/destroy_service_spec.rb56
-rw-r--r--spec/simplecov_env.rb3
-rw-r--r--spec/spec_helper.rb20
-rw-r--r--spec/support/capybara.rb8
-rw-r--r--spec/support/counter_attribute.rb6
-rw-r--r--spec/support/factory_bot.rb4
-rw-r--r--spec/support/google_api/cloud_platform_helpers.rb12
-rw-r--r--spec/support/helpers/api_internal_base_helpers.rb85
-rw-r--r--spec/support/helpers/cycle_analytics_helpers.rb8
-rw-r--r--spec/support/helpers/drag_to_helper.rb7
-rw-r--r--spec/support/helpers/features/blob_spec_helpers.rb22
-rw-r--r--spec/support/helpers/features/canonical_link_helpers.rb28
-rw-r--r--spec/support/helpers/features/snippet_helpers.rb64
-rw-r--r--spec/support/helpers/git_http_helpers.rb26
-rw-r--r--spec/support/helpers/graphql_helpers.rb6
-rw-r--r--spec/support/helpers/javascript_fixtures_helpers.rb11
-rw-r--r--spec/support/helpers/kubernetes_helpers.rb87
-rw-r--r--spec/support/helpers/multipart_helpers.rb2
-rw-r--r--spec/support/helpers/rack_attack_spec_helpers.rb4
-rw-r--r--spec/support/helpers/search_helpers.rb10
-rw-r--r--spec/support/helpers/snippet_helpers.rb2
-rw-r--r--spec/support/helpers/snowplow_helpers.rb12
-rw-r--r--spec/support/helpers/stub_experiments.rb4
-rw-r--r--spec/support/helpers/stub_feature_flags.rb4
-rw-r--r--spec/support/helpers/stub_object_storage.rb18
-rw-r--r--spec/support/helpers/stubbed_feature.rb26
-rw-r--r--spec/support/helpers/usage_data_helpers.rb10
-rw-r--r--spec/support/helpers/wait_for_requests.rb11
-rw-r--r--spec/support/helpers/wiki_helpers.rb10
-rw-r--r--spec/support/matchers/be_sorted.rb21
-rw-r--r--spec/support/migrations_helpers/cluster_helpers.rb10
-rw-r--r--spec/support/migrations_helpers/namespaces_helper.rb2
-rw-r--r--spec/support/migrations_helpers/schema_version_finder.rb34
-rw-r--r--spec/support/models/merge_request_without_merge_request_diff.rb7
-rw-r--r--spec/support/shared_contexts/cache_allowed_users_in_namespace_shared_context.rb2
-rw-r--r--spec/support/shared_contexts/email_shared_context.rb2
-rw-r--r--spec/support/shared_contexts/finders/group_projects_finder_shared_contexts.rb6
-rw-r--r--spec/support/shared_contexts/lib/gitlab/import_export/relation_tree_restorer_shared_context.rb13
-rw-r--r--spec/support/shared_contexts/mailers/notify_shared_context.rb2
-rw-r--r--spec/support/shared_contexts/navbar_structure_context.rb15
-rw-r--r--spec/support/shared_examples/boards/multiple_issue_boards_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/controllers/access_tokens_controller_shared_examples.rb106
-rw-r--r--spec/support/shared_examples/controllers/cache_control_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/controllers/destroy_hook_shared_examples.rb36
-rw-r--r--spec/support/shared_examples/controllers/githubish_import_controller_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/controllers/known_sign_in_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/controllers/milestone_tabs_shared_examples.rb23
-rw-r--r--spec/support/shared_examples/controllers/sessionless_auth_controller_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/controllers/unique_hll_events_examples.rb49
-rw-r--r--spec/support/shared_examples/controllers/wiki_actions_shared_examples.rb69
-rw-r--r--spec/support/shared_examples/features/editable_merge_request_shared_examples.rb28
-rw-r--r--spec/support/shared_examples/features/issuable_invite_members_shared_examples.rb68
-rw-r--r--spec/support/shared_examples/features/multiple_assignees_mr_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/features/multiple_reviewers_mr_shared_examples.rb47
-rw-r--r--spec/support/shared_examples/features/navbar_shared_examples.rb6
-rw-r--r--spec/support/shared_examples/features/packages_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/features/page_description_shared_examples.rb9
-rw-r--r--spec/support/shared_examples/features/protected_branches_with_deploy_keys_examples.rb95
-rw-r--r--spec/support/shared_examples/features/snippets_shared_examples.rb24
-rw-r--r--spec/support/shared_examples/features/wiki/file_attachments_shared_examples.rb86
-rw-r--r--spec/support/shared_examples/features/wiki/user_creates_wiki_page_shared_examples.rb245
-rw-r--r--spec/support/shared_examples/features/wiki/user_deletes_wiki_page_shared_examples.rb24
-rw-r--r--spec/support/shared_examples/features/wiki/user_previews_wiki_changes_shared_examples.rb110
-rw-r--r--spec/support/shared_examples/features/wiki/user_updates_wiki_page_shared_examples.rb231
-rw-r--r--spec/support/shared_examples/features/wiki/user_uses_wiki_shortcuts_shared_examples.rb20
-rw-r--r--spec/support/shared_examples/features/wiki/user_views_asciidoc_page_with_includes_shared_examples.rb77
-rw-r--r--spec/support/shared_examples/features/wiki/user_views_wiki_empty_shared_examples.rb62
-rw-r--r--spec/support/shared_examples/features/wiki/user_views_wiki_page_shared_examples.rb274
-rw-r--r--spec/support/shared_examples/features/wiki/user_views_wiki_pages_shared_examples.rb89
-rw-r--r--spec/support/shared_examples/features/wiki/user_views_wiki_sidebar_shared_examples.rb68
-rw-r--r--spec/support/shared_examples/features/wiki_file_attachments_shared_examples.rb88
-rw-r--r--spec/support/shared_examples/graphql/mutations/boards_create_shared_examples.rb75
-rw-r--r--spec/support/shared_examples/graphql/mutations/spammable_mutation_fields_examples.rb47
-rw-r--r--spec/support/shared_examples/graphql/notes_creation_shared_examples.rb8
-rw-r--r--spec/support/shared_examples/lib/gitlab/background_migration/mentions_migration_shared_examples.rb24
-rw-r--r--spec/support/shared_examples/lib/gitlab/ci/ci_trace_shared_examples.rb6
-rw-r--r--spec/support/shared_examples/lib/gitlab/diff_file_collections_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/lib/gitlab/import_export/relation_factory_shared_examples.rb107
-rw-r--r--spec/support/shared_examples/lib/gitlab/repository_size_checker_shared_examples.rb51
-rw-r--r--spec/support/shared_examples/lib/gitlab/search/recent_items.rb43
-rw-r--r--spec/support/shared_examples/lib/gitlab/search_confidential_filter_shared_examples.rb69
-rw-r--r--spec/support/shared_examples/lib/gitlab/search_results_sorted_shared_examples.rb19
-rw-r--r--spec/support/shared_examples/lib/gitlab/search_state_filter_shared_examples.rb (renamed from spec/support/shared_examples/lib/gitlab/search_issue_state_filter_shared_examples.rb)0
-rw-r--r--spec/support/shared_examples/mailers/notify_shared_examples.rb6
-rw-r--r--spec/support/shared_examples/models/concerns/has_repository_shared_examples.rb22
-rw-r--r--spec/support/shared_examples/models/concerns/shardable_shared_examples.rb21
-rw-r--r--spec/support/shared_examples/models/concerns/timebox_shared_examples.rb86
-rw-r--r--spec/support/shared_examples/models/mentionable_shared_examples.rb23
-rw-r--r--spec/support/shared_examples/models/project_latest_successful_build_for_shared_examples.rb16
-rw-r--r--spec/support/shared_examples/models/relative_positioning_shared_examples.rb182
-rw-r--r--spec/support/shared_examples/models/resource_timebox_event_shared_examples.rb10
-rw-r--r--spec/support/shared_examples/models/snippet_shared_examples.rb10
-rw-r--r--spec/support/shared_examples/models/throttled_touch_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/models/update_project_statistics_shared_examples.rb260
-rw-r--r--spec/support/shared_examples/models/wiki_shared_examples.rb85
-rw-r--r--spec/support/shared_examples/policies/resource_access_token_shared_examples.rb32
-rw-r--r--spec/support/shared_examples/quick_actions/issuable/issuable_quick_actions_shared_examples.rb8
-rw-r--r--spec/support/shared_examples/quick_actions/merge_request/merge_quick_action_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/requests/api/composer_packages_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/requests/api/container_repositories_shared_examples.rb8
-rw-r--r--spec/support/shared_examples/requests/api/debian_packages_shared_examples.rb309
-rw-r--r--spec/support/shared_examples/requests/api/graphql/group_and_project_boards_query_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/requests/api/nuget_packages_shared_examples.rb8
-rw-r--r--spec/support/shared_examples/requests/api/packages_shared_examples.rb8
-rw-r--r--spec/support/shared_examples/requests/api/pypi_packages_shared_examples.rb18
-rw-r--r--spec/support/shared_examples/requests/api/snippets_shared_examples.rb179
-rw-r--r--spec/support/shared_examples/requests/api/tracking_shared_examples.rb9
-rw-r--r--spec/support/shared_examples/requests/rack_attack_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/requests/snippet_shared_examples.rb12
-rw-r--r--spec/support/shared_examples/requests/user_activity_shared_examples.rb97
-rw-r--r--spec/support/shared_examples/serializers/note_entity_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/services/boards/boards_create_service_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/services/boards/issues_move_service_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/services/incident_shared_examples.rb71
-rw-r--r--spec/support/shared_examples/services/merge_request_shared_examples.rb8
-rw-r--r--spec/support/shared_examples/services/packages_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/services/projects/urls_with_escaped_elements_shared_example.rb20
-rw-r--r--spec/support/shared_examples/validators/ip_address_validator_shared_examples.rb10
-rw-r--r--spec/support/test_reports/test_reports_helper.rb8
-rw-r--r--spec/support_specs/helpers/stub_feature_flags_spec.rb31
-rw-r--r--spec/tasks/gitlab/backup_rake_spec.rb111
-rw-r--r--spec/tasks/gitlab/db_rake_spec.rb97
-rw-r--r--spec/tasks/gitlab/web_hook_rake_spec.rb4
-rw-r--r--spec/uploaders/file_uploader_spec.rb2
-rw-r--r--spec/uploaders/object_storage_spec.rb2
-rw-r--r--spec/uploaders/pages/deployment_uploader_spec.rb59
-rw-r--r--spec/uploaders/terraform/versioned_state_uploader_spec.rb20
-rw-r--r--spec/validators/ip_address_validator_spec.rb37
-rw-r--r--spec/views/admin/dashboard/index.html.haml_spec.rb2
-rw-r--r--spec/views/groups/edit.html.haml_spec.rb2
-rw-r--r--spec/views/jira_connect/subscriptions/index.html.haml_spec.rb30
-rw-r--r--spec/views/layouts/nav/sidebar/_admin.html.haml_spec.rb18
-rw-r--r--spec/views/layouts/nav/sidebar/_project.html.haml_spec.rb30
-rw-r--r--spec/views/profiles/preferences/show.html.haml_spec.rb10
-rw-r--r--spec/views/projects/merge_requests/diffs/_diffs.html.haml_spec.rb38
-rw-r--r--spec/views/projects/settings/operations/show.html.haml_spec.rb76
-rw-r--r--spec/views/projects/tracing/show.html.haml_spec.rb59
-rw-r--r--spec/views/search/_results.html.haml_spec.rb22
-rw-r--r--spec/views/shared/_label_row.html.haml_spec.rb139
-rw-r--r--spec/views/shared/milestones/_issuables.html.haml_spec.rb3
-rw-r--r--spec/workers/analytics/instance_statistics/count_job_trigger_worker_spec.rb12
-rw-r--r--spec/workers/analytics/instance_statistics/counter_job_worker_spec.rb20
-rw-r--r--spec/workers/authorized_project_update/periodic_recalculate_worker_spec.rb12
-rw-r--r--spec/workers/authorized_project_update/user_refresh_over_user_range_worker_spec.rb12
-rw-r--r--spec/workers/build_finished_worker_spec.rb2
-rw-r--r--spec/workers/ci/build_trace_chunk_flush_worker_spec.rb4
-rw-r--r--spec/workers/ci/delete_objects_worker_spec.rb49
-rw-r--r--spec/workers/ci/schedule_delete_objects_cron_worker_spec.rb15
-rw-r--r--spec/workers/cleanup_container_repository_worker_spec.rb23
-rw-r--r--spec/workers/concerns/limited_capacity/job_tracker_spec.rb100
-rw-r--r--spec/workers/concerns/limited_capacity/worker_spec.rb285
-rw-r--r--spec/workers/container_expiration_policy_worker_spec.rb46
-rw-r--r--spec/workers/deployments/drop_older_deployments_worker_spec.rb18
-rw-r--r--spec/workers/deployments/execute_hooks_worker_spec.rb51
-rw-r--r--spec/workers/deployments/link_merge_request_worker_spec.rb71
-rw-r--r--spec/workers/deployments/success_worker_spec.rb12
-rw-r--r--spec/workers/deployments/update_environment_worker_spec.rb63
-rw-r--r--spec/workers/design_management/copy_design_collection_worker_spec.rb39
-rw-r--r--spec/workers/design_management/new_version_worker_spec.rb4
-rw-r--r--spec/workers/disallow_two_factor_for_group_worker_spec.rb22
-rw-r--r--spec/workers/disallow_two_factor_for_subgroups_worker_spec.rb17
-rw-r--r--spec/workers/export_csv_worker_spec.rb20
-rw-r--r--spec/workers/git_garbage_collect_worker_spec.rb58
-rw-r--r--spec/workers/group_export_worker_spec.rb10
-rw-r--r--spec/workers/group_import_worker_spec.rb63
-rw-r--r--spec/workers/incident_management/add_severity_system_note_worker_spec.rb60
-rw-r--r--spec/workers/incident_management/process_alert_worker_spec.rb2
-rw-r--r--spec/workers/incident_management/process_prometheus_alert_worker_spec.rb2
-rw-r--r--spec/workers/issuable_export_csv_worker_spec.rb73
-rw-r--r--spec/workers/member_invitation_reminder_emails_worker_spec.rb39
-rw-r--r--spec/workers/metrics/dashboard/prune_old_annotations_worker_spec.rb2
-rw-r--r--spec/workers/metrics/dashboard/sync_dashboards_worker_spec.rb25
-rw-r--r--spec/workers/post_receive_spec.rb4
-rw-r--r--spec/workers/project_export_worker_spec.rb4
-rw-r--r--spec/workers/propagate_integration_group_worker_spec.rb44
-rw-r--r--spec/workers/propagate_integration_inherit_worker_spec.rb32
-rw-r--r--spec/workers/propagate_integration_project_worker_spec.rb44
-rw-r--r--spec/workers/web_hooks/destroy_worker_spec.rb59
-rw-r--r--tmp/feature_flags/.gitkeep0
-rw-r--r--vendor/Dockerfile/Golang-alpine.Dockerfile2
-rw-r--r--vendor/Dockerfile/Golang-scratch.Dockerfile2
-rw-r--r--vendor/Dockerfile/Golang.Dockerfile2
-rw-r--r--vendor/assets/stylesheets/cropper.css379
-rwxr-xr-xvendor/languages.yml1433
-rw-r--r--vendor/project_templates/gitpod_spring_petclinic.tar.gzbin0 -> 402980 bytes
-rw-r--r--vendor/sample_data_templates/basic.tar.gzbin0 -> 340647 bytes
-rw-r--r--vendor/sample_data_templates/serenity_valley.tar.gzbin0 -> 7399896 bytes
-rw-r--r--yarn.lock2942
6663 files changed, 242056 insertions, 88567 deletions
diff --git a/.gitignore b/.gitignore
index 2a07963eecc..25c42cdb56d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -96,4 +96,4 @@ apollo.config.js
/tmp/matching_foss_tests.txt
/tmp/matching_tests.txt
ee/changelogs/unreleased-ee
-
+/sitespeed-result
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 638613ab43e..f9c9c5888db 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -17,7 +17,7 @@ stages:
# in cases where jobs require Docker-in-Docker, the job
# definition must be extended with `.use-docker-in-docker`
default:
- image: "registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.6-golang-1.14-git-2.28-lfs-2.9-chrome-84-node-12.x-yarn-1.21-postgresql-11-graphicsmagick-1.3.34"
+ image: "registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.6-golang-1.14-git-2.28-lfs-2.9-chrome-85-node-12.18-yarn-1.22-postgresql-11-graphicsmagick-1.3.34"
tags:
- gitlab-org
# All jobs are interruptible by default
diff --git a/.gitlab/CODEOWNERS b/.gitlab/CODEOWNERS
index b4fd436cc58..5187ac01b58 100644
--- a/.gitlab/CODEOWNERS
+++ b/.gitlab/CODEOWNERS
@@ -184,7 +184,7 @@ Dangerfile @gl-quality/eng-prod
/lib/gitlab/auth/ldap/ @dblessing @mkozono
[Templates]
-/lib/gitlab/ci/templates/ @nolith @dosuken123
+/lib/gitlab/ci/templates/ @nolith @shinya.maeda
/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml @DylanGriffith @mayra-cabrera @tkuah
/lib/gitlab/ci/templates/Security/ @plafoucriere @gonzoyumo @twoodham @sethgitlab
@@ -213,10 +213,10 @@ Dangerfile @gl-quality/eng-prod
/ee/spec/lib/gitlab/code_owners/ @reprazent @kerrizor @garyh
/doc/user/project/code_owners.md @reprazent @kerrizor @garyh
-[Telemetry]
-/ee/lib/gitlab/usage_data_counters/ @gitlab-org/growth/telemetry/engineers
-/ee/lib/ee/gitlab/usage_data.rb @gitlab-org/growth/telemetry/engineers
-/lib/gitlab/grafana_embed_usage_data.rb @gitlab-org/growth/telemetry/engineers
-/lib/gitlab/usage_data.rb @gitlab-org/growth/telemetry/engineers
-/lib/gitlab/cycle_analytics/usage_data.rb @gitlab-org/growth/telemetry/engineers
-/lib/gitlab/usage_data_counters/ @gitlab-org/growth/telemetry/engineers
+[Product Analytics]
+/ee/lib/gitlab/usage_data_counters/ @gitlab-org/growth/product_analytics/engineers
+/ee/lib/ee/gitlab/usage_data.rb @gitlab-org/growth/product_analytics/engineers
+/lib/gitlab/grafana_embed_usage_data.rb @gitlab-org/growth/product_analytics/engineers
+/lib/gitlab/usage_data.rb @gitlab-org/growth/product_analytics/engineers
+/lib/gitlab/cycle_analytics/usage_data.rb @gitlab-org/growth/product_analytics/engineers
+/lib/gitlab/usage_data_counters/ @gitlab-org/growth/product_analytics/engineers
diff --git a/.gitlab/ci/dast.gitlab-ci.yml b/.gitlab/ci/dast.gitlab-ci.yml
index 93f64930822..33778b9cbd0 100644
--- a/.gitlab/ci/dast.gitlab-ci.yml
+++ b/.gitlab/ci/dast.gitlab-ci.yml
@@ -28,6 +28,8 @@
# Help pages are excluded from scan as they are static pages.
# profile/two_factor_auth is excluded from scan to prevent 2FA from being turned on from user profile, which will reduce coverage.
- 'export DAST_AUTH_EXCLUDE_URLS="${DAST_WEBSITE}/help/.*,${DAST_WEBSITE}/profile/two_factor_auth,${DAST_WEBSITE}/users/sign_out"'
+ # Exclude the automatically generated monitoring project from being tested due to https://gitlab.com/gitlab-org/gitlab/-/issues/260362
+ - 'DAST_AUTH_EXCLUDE_URLS="${DAST_AUTH_EXCLUDE_URLS},https://.*\.gitlab-review\.app/gitlab-instance-(administrators-)?[a-zA-Z0-9]{8}/.*"'
- enable_rule () { read all_rules; rule=$1; echo $all_rules | sed -r "s/(,)?$rule(,)?/\1-1\2/" ; }
# Sort ids in DAST_RULES ascendingly, which is required when using DAST_RULES as argument to enable_rule
- 'DAST_RULES=$(echo $DAST_RULES | tr "," "\n" | sort -n | paste -sd ",")'
diff --git a/.gitlab/ci/dev-fixtures.gitlab-ci.yml b/.gitlab/ci/dev-fixtures.gitlab-ci.yml
index fc3678a7d17..4141cc7f071 100644
--- a/.gitlab/ci/dev-fixtures.gitlab-ci.yml
+++ b/.gitlab/ci/dev-fixtures.gitlab-ci.yml
@@ -14,14 +14,17 @@
SIZE: 0 # number of external projects to fork, requires network connection
# SEED_NESTED_GROUPS: "false" # requires network connection
+.run-dev-fixtures-script: &run-dev-fixtures-script
+ - run_timed_command "scripts/gitaly-test-build"
+ - run_timed_command "scripts/gitaly-test-spawn"
+ - run_timed_command "RAILS_ENV=test bundle exec rake db:seed_fu"
+
run-dev-fixtures:
extends:
- .run-dev-fixtures
- .dev-fixtures:rules:ee-and-foss
script:
- - run_timed_command "scripts/gitaly-test-build"
- - run_timed_command "scripts/gitaly-test-spawn"
- - run_timed_command "RAILS_ENV=test bundle exec rake db:seed_fu"
+ - *run-dev-fixtures-script
run-dev-fixtures-ee:
extends:
@@ -29,7 +32,5 @@ run-dev-fixtures-ee:
- .dev-fixtures:rules:ee-only
- .use-pg11-ee
script:
- - run_timed_command "scripts/gitaly-test-build"
- - run_timed_command "scripts/gitaly-test-spawn"
- cp ee/db/fixtures/development/* $FIXTURE_PATH
- - run_timed_command "RAILS_ENV=test bundle exec rake db:seed_fu"
+ - *run-dev-fixtures-script
diff --git a/.gitlab/ci/docs.gitlab-ci.yml b/.gitlab/ci/docs.gitlab-ci.yml
index 0e0e156a64f..4b25908aa6a 100644
--- a/.gitlab/ci/docs.gitlab-ci.yml
+++ b/.gitlab/ci/docs.gitlab-ci.yml
@@ -4,7 +4,7 @@
- .docs:rules:review-docs
image: ruby:2.6-alpine
stage: review
- dependencies: []
+ needs: []
variables:
# We're cloning the repo instead of downloading the script for now
# because some repos are private and CI_JOB_TOKEN cannot access files.
@@ -42,7 +42,7 @@ docs lint:
extends:
- .default-retry
- .docs:rules:docs-lint
- image: "registry.gitlab.com/gitlab-org/gitlab-docs/lint:vale-2.3.4-markdownlint-0.23.2"
+ image: "registry.gitlab.com/gitlab-org/gitlab-docs/lint:ruby-2.7.2-alpine-3.12-vale-2.4.3-markdownlint-0.24.0"
stage: test
needs: []
script:
diff --git a/.gitlab/ci/frontend.gitlab-ci.yml b/.gitlab/ci/frontend.gitlab-ci.yml
index 27f56cd8667..e4c9f85cf62 100644
--- a/.gitlab/ci/frontend.gitlab-ci.yml
+++ b/.gitlab/ci/frontend.gitlab-ci.yml
@@ -7,19 +7,21 @@
# we override the max_old_space_size to prevent OOM errors
NODE_OPTIONS: --max_old_space_size=3584
+.yarn-install: &yarn-install
+ - source scripts/utils.sh
+ - run_timed_command "retry yarn install --frozen-lockfile"
+
.compile-assets-base:
extends:
- .frontend-base
- .assets-compile-cache
- image: registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.6-git-2.28-lfs-2.9-node-12.x-yarn-1.21-graphicsmagick-1.3.34
+ image: registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.6-git-2.28-lfs-2.9-node-12.18-yarn-1.22-graphicsmagick-1.3.34
variables:
WEBPACK_VENDOR_DLL: "true"
stage: prepare
script:
- - node --version
- - run_timed_command "retry yarn install --frozen-lockfile"
- - free -m
- - run_timed_command "bin/rake gitlab:assets:compile > assets-compile.log 2>&1"
+ - *yarn-install
+ - run_timed_command "bin/rake gitlab:assets:compile"
- run_timed_command "scripts/clean-old-cached-assets"
compile-production-assets:
@@ -34,7 +36,6 @@ compile-production-assets:
name: webpack-report
expire_in: 31d
paths:
- - assets-compile.log
# These assets are used in multiple locations:
# - in `build-assets-image` job to create assets image for packaging systems
# - GitLab UI for integration tests: https://gitlab.com/gitlab-org/gitlab-ui/-/blob/e88493b3c855aea30bf60baee692a64606b0eb1e/.storybook/preview-head.pug#L1
@@ -51,7 +52,6 @@ compile-test-assets:
artifacts:
expire_in: 7d
paths:
- - assets-compile.log
- public/assets/
- node_modules/@gitlab/svgs/dist/icons.json # app/helpers/icons_helper.rb uses this file
when: always
@@ -87,8 +87,7 @@ update-yarn-cache:
- .shared:rules:update-cache
stage: prepare
script:
- - source scripts/utils.sh
- - run_timed_command "retry yarn install --frozen-lockfile"
+ - *yarn-install
cache:
policy: push
@@ -139,14 +138,14 @@ eslint-as-if-foss:
- .as-if-foss
needs: []
script:
- - run_timed_command "retry yarn install --frozen-lockfile"
- - yarn run eslint
+ - *yarn-install
+ - run_timed_command "yarn run eslint"
.karma-base:
extends: .frontend-test-base
script:
- export BABEL_ENV=coverage CHROME_LOG_FILE=chrome_debug.log
- - run_timed_command "retry yarn install --frozen-lockfile"
+ - *yarn-install
- run_timed_command "yarn karma"
karma:
@@ -177,7 +176,7 @@ karma-as-if-foss:
.jest-base:
extends: .frontend-test-base
script:
- - run_timed_command "retry yarn install --frozen-lockfile"
+ - *yarn-install
- run_timed_command "yarn jest --ci --coverage --testSequencer ./scripts/frontend/parallel_ci_sequencer.js"
jest:
@@ -202,7 +201,7 @@ jest-integration:
- .frontend-test-base
- .frontend:rules:default-frontend-jobs
script:
- - run_timed_command "retry yarn install --frozen-lockfile"
+ - *yarn-install
- run_timed_command "yarn jest:integration --ci"
needs: ["frontend-fixtures"]
@@ -222,8 +221,7 @@ coverage-frontend:
needs: ["jest"]
stage: post-test
before_script:
- - source scripts/utils.sh
- - run_timed_command "retry yarn install --frozen-lockfile"
+ - *yarn-install
script:
- run_timed_command "yarn node scripts/frontend/merge_coverage_frontend.js"
coverage: '/^Statements\s*:\s*?(\d+(?:\.\d+)?)%/'
@@ -243,9 +241,8 @@ coverage-frontend:
stage: test
dependencies: []
script:
- - source scripts/utils.sh
- - run_timed_command "yarn install --frozen-lockfile"
- - run_timed_command "yarn run webpack-prod"
+ - *yarn-install
+ - run_timed_command "retry yarn run webpack-prod"
qa-frontend-node:10:
extends: .qa-frontend-node
@@ -268,8 +265,7 @@ webpack-dev-server:
WEBPACK_MEMORY_TEST: "true"
WEBPACK_VENDOR_DLL: "true"
script:
- - source scripts/utils.sh
- - run_timed_command "retry yarn install --frozen-lockfile"
+ - *yarn-install
- run_timed_command "retry yarn webpack-vendor"
- run_timed_command "node --expose-gc node_modules/.bin/webpack-dev-server --config config/webpack.config.js"
artifacts:
diff --git a/.gitlab/ci/global.gitlab-ci.yml b/.gitlab/ci/global.gitlab-ci.yml
index 238059bf972..fea3956bfe8 100644
--- a/.gitlab/ci/global.gitlab-ci.yml
+++ b/.gitlab/ci/global.gitlab-ci.yml
@@ -34,6 +34,13 @@
- tmp/rubocop_cache/
policy: pull
+.coverage-cache:
+ cache:
+ key: "coverage-cache-v1"
+ paths:
+ - vendor/ruby/
+ policy: pull
+
.qa-cache:
cache:
key: "qa-v1"
@@ -64,7 +71,7 @@
policy: pull
.use-pg11:
- image: "registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.6-golang-1.14-git-2.28-lfs-2.9-chrome-84-node-12.x-yarn-1.21-postgresql-11-graphicsmagick-1.3.34"
+ image: "registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.6-golang-1.14-git-2.28-lfs-2.9-chrome-85-node-12.18-yarn-1.22-postgresql-11-graphicsmagick-1.3.34"
services:
- name: postgres:11.6
command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"]
@@ -73,7 +80,7 @@
POSTGRES_HOST_AUTH_METHOD: trust
.use-pg12:
- image: "registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.6-golang-1.14-git-2.28-lfs-2.9-chrome-84-node-12.x-yarn-1.21-postgresql-12-graphicsmagick-1.3.34"
+ image: "registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.6-golang-1.14-git-2.28-lfs-2.9-chrome-85-node-12.18-yarn-1.22-postgresql-12-graphicsmagick-1.3.34"
services:
- name: postgres:12
command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"]
@@ -82,22 +89,24 @@
POSTGRES_HOST_AUTH_METHOD: trust
.use-pg11-ee:
- image: "registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.6-golang-1.14-git-2.28-lfs-2.9-chrome-84-node-12.x-yarn-1.21-postgresql-11-graphicsmagick-1.3.34"
+ image: "registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.6-golang-1.14-git-2.28-lfs-2.9-chrome-85-node-12.18-yarn-1.22-postgresql-11-graphicsmagick-1.3.34"
services:
- name: postgres:11.6
command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"]
- name: redis:4.0-alpine
- - name: elasticsearch:6.4.2
+ - name: elasticsearch:7.9.2
+ command: ["elasticsearch", "-E", "discovery.type=single-node"]
variables:
POSTGRES_HOST_AUTH_METHOD: trust
.use-pg12-ee:
- image: "registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.6-golang-1.14-git-2.28-lfs-2.9-chrome-84-node-12.x-yarn-1.21-postgresql-12-graphicsmagick-1.3.34"
+ image: "registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.6-golang-1.14-git-2.28-lfs-2.9-chrome-85-node-12.18-yarn-1.22-postgresql-12-graphicsmagick-1.3.34"
services:
- name: postgres:12
command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"]
- name: redis:4.0-alpine
- - name: elasticsearch:6.4.2
+ - name: elasticsearch:7.9.2
+ command: ["elasticsearch", "-E", "discovery.type=single-node"]
variables:
POSTGRES_HOST_AUTH_METHOD: trust
diff --git a/.gitlab/ci/notify.gitlab-ci.yml b/.gitlab/ci/notify.gitlab-ci.yml
index 6dcf19da942..e18a092bb8f 100644
--- a/.gitlab/ci/notify.gitlab-ci.yml
+++ b/.gitlab/ci/notify.gitlab-ci.yml
@@ -3,6 +3,8 @@
stage: notify
dependencies: []
cache: {}
+ variables:
+ MERGE_REQUEST_URL: ${CI_MERGE_REQUEST_PROJECT_URL}/-/merge_requests/${CI_MERGE_REQUEST_IID}
before_script:
- apk update && apk add git curl bash
@@ -16,8 +18,19 @@ notify-update-gitaly:
variables:
NOTIFY_CHANNEL: g_create_gitaly
GITALY_UPDATE_BRANCH: release-tools/update-gitaly
- MERGE_REQUEST_URL: ${CI_MERGE_REQUEST_PROJECT_URL}/-/merge_requests/${CI_MERGE_REQUEST_IID}
script:
- echo "NOTIFY_CHANNEL is ${NOTIFY_CHANNEL}"
- echo "CI_PIPELINE_URL is ${CI_PIPELINE_URL}"
- - scripts/slack ${NOTIFY_CHANNEL} "â˜ ï¸ \`${GITALY_UPDATE_BRANCH}\` failed! â˜ ï¸ See ${CI_PIPELINE_URL} (triggered from ${MERGE_REQUEST_URL})" ci_failing
+ - scripts/slack ${NOTIFY_CHANNEL} "â˜ ï¸ \`${GITALY_UPDATE_BRANCH}\` failed! â˜ ï¸ See ${CI_PIPELINE_URL} (triggered from ${MERGE_REQUEST_URL})" ci_failing "GitLab QA Bot"
+
+notify-security-pipeline:
+ extends:
+ - .notify-slack
+ - .delivery:rules:security-pipeline-merge-result-failure
+ variables:
+ NOTIFY_CHANNEL: f_upcoming_release
+ script:
+ - echo "NOTIFY_CHANNEL is ${NOTIFY_CHANNEL}"
+ - echo "CI_PIPELINE_URL is ${CI_PIPELINE_URL}"
+ # <!subteam^S0127FU8PDE> mentions the `@release-managers` group
+ - 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"
diff --git a/.gitlab/ci/rails.gitlab-ci.yml b/.gitlab/ci/rails.gitlab-ci.yml
index 165476678bb..c4167ce7bcb 100644
--- a/.gitlab/ci/rails.gitlab-ci.yml
+++ b/.gitlab/ci/rails.gitlab-ci.yml
@@ -6,14 +6,23 @@
- .default-before_script
- .rails-cache
+.base-script: &base-script
+ # Only install knapsack after bundle install! Otherwise oddly some native
+ # gems could not be found under some circumstance. No idea why, hours wasted.
+ - run_timed_command "gem install knapsack --no-document"
+ - run_timed_command "scripts/gitaly-test-build"
+ - run_timed_command "scripts/gitaly-test-spawn"
+ - source ./scripts/rspec_helpers.sh
+
.rspec-base:
extends: .rails-job-base
stage: test
+ variables:
+ RUBY_GC_MALLOC_LIMIT: 67108864
+ RUBY_GC_MALLOC_LIMIT_MAX: 134217728
needs: ["setup-test-env", "retrieve-tests-metadata", "compile-test-assets"]
script:
- - run_timed_command "scripts/gitaly-test-build"
- - run_timed_command "scripts/gitaly-test-spawn"
- - source scripts/rspec_helpers.sh
+ - *base-script
- rspec_paralellized_job "--tag ~quarantine --tag ~geo --tag ~level:migration"
artifacts:
expire_in: 31d
@@ -25,6 +34,7 @@
- rspec_profiling/
- tmp/capybara/
- tmp/memory_test/
+ - tmp/feature_flags/
- log/*.log
reports:
junit: junit_rspec.xml
@@ -32,9 +42,7 @@
.rspec-base-migration:
extends: .rails:rules:ee-and-foss-migration
script:
- - run_timed_command "scripts/gitaly-test-build"
- - run_timed_command "scripts/gitaly-test-spawn"
- - source scripts/rspec_helpers.sh
+ - *base-script
- rspec_paralellized_job "--tag ~quarantine --tag ~geo --tag level:migration"
.rspec-base-pg11:
@@ -67,9 +75,7 @@
.rspec-ee-base-geo:
extends: .rspec-base
script:
- - run_timed_command "scripts/gitaly-test-build"
- - run_timed_command "scripts/gitaly-test-spawn"
- - source scripts/rspec_helpers.sh
+ - *base-script
- rspec_paralellized_job "--tag ~quarantine --tag geo"
.rspec-ee-base-geo-pg11:
@@ -160,6 +166,25 @@ update-rails-cache:
cache:
policy: push # We want to rebuild the cache from scratch to ensure stale dependencies are cleaned up.
+.coverage-base:
+ extends:
+ - .default-retry
+ - .default-before_script
+ - .coverage-cache
+ variables:
+ SETUP_DB: "false"
+ USE_BUNDLE_INSTALL: "false"
+
+update-coverage-cache:
+ extends:
+ - .coverage-base
+ - .shared:rules:update-cache
+ stage: prepare
+ script:
+ - run_timed_command "bundle install --jobs=$(nproc) --path=vendor --retry=3 --quiet --without default development test production puma unicorn kerberos metrics omnibus ed25519"
+ cache:
+ policy: push # We want to rebuild the cache from scratch to ensure stale dependencies are cleaned up.
+
.static-analysis-base:
extends:
- .default-retry
@@ -178,7 +203,7 @@ update-static-analysis-cache:
script:
- rm -rf ./node_modules # We remove node_modules because there's no mechanism to remove stall entries.
- run_timed_command "retry yarn install --frozen-lockfile"
- - bundle exec rubocop --parallel # For the moment we only cache `vendor/ruby/`, `node_modules/`, and `tmp/rubocop_cache` so we don't need to run all the tasks,
+ - run_timed_command "bundle exec rubocop --parallel" # For the moment we only cache `vendor/ruby/`, `node_modules/`, and `tmp/rubocop_cache` so we don't need to run all the tasks,
cache:
# We want to rebuild the cache from scratch to ensure stale dependencies are cleaned up but RuboCop has a mechanism
# for keeping only the N latest cache files, so we take advantage of it with `pull-push` and removing `node_modules` at the start of the job.
@@ -287,8 +312,7 @@ gitlab:setup:
# db/fixtures/development/04_project.rb thanks to SIZE=1 below
- git clone https://gitlab.com/gitlab-org/gitlab-test.git
/home/git/repositories/gitlab-org/gitlab-test.git
- - run_timed_command "scripts/gitaly-test-build"
- - run_timed_command "scripts/gitaly-test-spawn"
+ - *base-script
- force=yes SIZE=1 FIXTURE_PATH="db/fixtures/development" bundle exec rake gitlab:setup
artifacts:
when: on_failure
@@ -313,7 +337,7 @@ db:backup_and_restore:
rspec:coverage:
extends:
- - .rails-job-base
+ - .coverage-base
- .rails:rules:rspec-coverage
stage: post-test
# We cannot use needs since it would mean needing 84 jobs (since most are parallelized)
@@ -333,11 +357,10 @@ rspec:coverage:
- rspec-ee system pg11 geo
- memory-static
- memory-on-boot
- variables:
- SETUP_DB: "false"
script:
- - bundle exec scripts/merge-simplecov
- - bundle exec scripts/gather-test-memory-data
+ - run_timed_command "bundle install --jobs=$(nproc) --path=vendor --retry=3 --quiet --without default development test production puma unicorn kerberos metrics omnibus ed25519"
+ - run_timed_command "bundle exec scripts/merge-simplecov"
+ - run_timed_command "bundle exec scripts/gather-test-memory-data"
coverage: '/LOC \((\d+\.\d+%)\) covered.$/'
artifacts:
name: coverage
@@ -348,6 +371,32 @@ rspec:coverage:
- tmp/memory_test/
reports:
cobertura: coverage/coverage.xml
+
+rspec:feature-flags:
+ extends:
+ - .coverage-base
+ - .rails:rules:rspec-feature-flags
+ stage: post-test
+ # We cannot use needs since it would mean needing 84 jobs (since most are parallelized)
+ # so we use `dependencies` here.
+ dependencies:
+ - setup-test-env
+ - rspec migration pg11
+ - rspec unit pg11
+ - rspec integration pg11
+ - rspec system pg11
+ - rspec-ee migration pg11
+ - rspec-ee unit pg11
+ - rspec-ee integration pg11
+ - rspec-ee system pg11
+ - rspec-ee unit pg11 geo
+ - rspec-ee integration pg11 geo
+ - rspec-ee system pg11 geo
+ - memory-static
+ - memory-on-boot
+ script:
+ - run_timed_command "bundle install --jobs=$(nproc) --path=vendor --retry=3 --quiet --without default development test production puma unicorn kerberos metrics omnibus ed25519"
+ - run_timed_command "bundle exec scripts/used-feature-flags"
# EE/FOSS: default refs (MRs, master, schedules) jobs #
#######################################################
@@ -512,9 +561,7 @@ rspec fail-fast:
stage: test
needs: ["setup-test-env", "retrieve-tests-metadata", "compile-test-assets", "detect-tests"]
script:
- - run_timed_command "scripts/gitaly-test-build"
- - run_timed_command "scripts/gitaly-test-spawn"
- - source scripts/rspec_helpers.sh
+ - *base-script
- rspec_fail_fast tmp/matching_tests.txt "--tag ~quarantine"
artifacts:
expire_in: 7d
@@ -527,9 +574,7 @@ rspec foss-impact:
- .rails:rules:rspec-foss-impact
needs: ["setup-test-env", "retrieve-tests-metadata", "compile-test-assets as-if-foss", "detect-tests as-if-foss"]
script:
- - run_timed_command "scripts/gitaly-test-build"
- - run_timed_command "scripts/gitaly-test-spawn"
- - source scripts/rspec_helpers.sh
+ - *base-script
- rspec_matched_foss_tests tmp/matching_foss_tests.txt "--tag ~quarantine"
artifacts:
expire_in: 7d
diff --git a/.gitlab/ci/reports.gitlab-ci.yml b/.gitlab/ci/reports.gitlab-ci.yml
index 0e2f12789db..168f60f0f65 100644
--- a/.gitlab/ci/reports.gitlab-ci.yml
+++ b/.gitlab/ci/reports.gitlab-ci.yml
@@ -151,3 +151,20 @@ dependency_scanning:
reports:
dependency_scanning: gl-dependency-scanning-report.json
expire_in: 1 week # GitLab-specific
+
+license_scanning:
+ extends:
+ - .default-retry
+ - .reports:rules:license_scanning
+ stage: test
+ image:
+ name: "registry.gitlab.com/gitlab-org/security-products/analyzers/license-finder:3"
+ entrypoint: [""]
+ needs: []
+ script:
+ - /run.sh analyze .
+ artifacts:
+ reports:
+ license_scanning: gl-license-scanning-report.json
+ expire_in: 1 week # GitLab-specific
+ dependencies: []
diff --git a/.gitlab/ci/review.gitlab-ci.yml b/.gitlab/ci/review.gitlab-ci.yml
index d34687cfdad..46a1a957692 100644
--- a/.gitlab/ci/review.gitlab-ci.yml
+++ b/.gitlab/ci/review.gitlab-ci.yml
@@ -16,6 +16,11 @@ review-cleanup:
- ruby -rrubygems scripts/review_apps/automated_cleanup.rb
- gcp_cleanup
+.base-before_script: &base-before_script
+ - source ./scripts/utils.sh
+ - source ./scripts/review_apps/review-apps.sh
+ - install_api_client_dependencies_with_apk
+
review-build-cng:
extends:
- .default-retry
@@ -23,7 +28,7 @@ review-build-cng:
image: ruby:2.6-alpine
stage: review-prepare
before_script:
- - source scripts/utils.sh
+ - source ./scripts/utils.sh
- install_api_client_dependencies_with_apk
- install_gitlab_gem
needs:
@@ -62,9 +67,7 @@ review-deploy:
- export GITALY_VERSION=$(<GITALY_SERVER_VERSION)
- export GITLAB_WORKHORSE_VERSION=$(<GITLAB_WORKHORSE_VERSION)
- echo "${CI_ENVIRONMENT_URL}" > environment_url.txt
- - source ./scripts/utils.sh
- - install_api_client_dependencies_with_apk
- - source scripts/review_apps/review-apps.sh
+ - *base-before_script
script:
- check_kube_domain
- ensure_namespace
@@ -72,7 +75,7 @@ review-deploy:
- download_chart
- date
- deploy || (display_deployment_debug && exit 1)
- - disable_sign_ups
+ - disable_sign_ups || (delete_release && exit 1)
# When the job is manual, review-qa-smoke is also manual and we don't want people
# to have to manually start the jobs in sequence, so we do it for them.
- '[ -z $CI_JOB_MANUAL ] || play_job "review-qa-smoke"'
@@ -81,10 +84,9 @@ review-deploy:
# 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.
- if [ "$DAST_RUN" == "true" ]; then source scripts/review_apps/seed-dast-test-data.sh; TRACE=1 trigger_proj_user_creation; fi
-
artifacts:
paths: [environment_url.txt]
- expire_in: 2 days
+ expire_in: 7 days
when: always
.review-stop-base:
@@ -98,9 +100,7 @@ review-deploy:
# See https://gitlab.com/gitlab-org/gitlab/issues/191273
GIT_DEPTH: 1
before_script:
- - apk add --update openssl
- - source ./scripts/utils.sh
- - source ./scripts/review_apps/review-apps.sh
+ - *base-before_script
review-stop-failed-deployment:
extends:
@@ -143,8 +143,7 @@ review-stop:
- export CI_ENVIRONMENT_URL="$(cat environment_url.txt)"
- echo "${CI_ENVIRONMENT_URL}"
- echo "${QA_IMAGE}"
- - source scripts/utils.sh
- - install_api_client_dependencies_with_apk
+ - *base-before_script
- gem install gitlab-qa --no-document ${GITLAB_QA_VERSION:+ --version ${GITLAB_QA_VERSION}}
artifacts:
paths:
@@ -174,7 +173,7 @@ review-performance:
- .default-retry
- .review:rules:review-performance
image:
- name: sitespeedio/sitespeed.io:6.3.1
+ name: sitespeedio/sitespeed.io
entrypoint: [""]
stage: qa
# This is needed so that manual jobs with needs don't block the pipeline.
@@ -232,6 +231,6 @@ danger-review:
stage: test
needs: []
script:
- - source scripts/utils.sh
- - retry yarn install --frozen-lockfile
+ - source ./scripts/utils.sh
+ - run_timed_command "retry yarn install --frozen-lockfile"
- danger --fail-on-errors=true --verbose
diff --git a/.gitlab/ci/rules.gitlab-ci.yml b/.gitlab/ci/rules.gitlab-ci.yml
index a8e0e1ccaaa..57d4a2a4cb7 100644
--- a/.gitlab/ci/rules.gitlab-ci.yml
+++ b/.gitlab/ci/rules.gitlab-ci.yml
@@ -73,6 +73,12 @@
.if-rspec-fail-fast-skipped: &if-rspec-fail-fast-skipped
if: '$CI_MERGE_REQUEST_TITLE =~ /SKIP RSPEC FAIL-FAST/'
+# For Security merge requests, the gitlab-release-tools-bot triggers a new
+# pipeline for the "Pipelines for merged results" feature. If the pipeline
+# fails, we notify release managers.
+.if-security-pipeline-merge-result: &if-security-pipeline-merge-result
+ if: '$CI_PIPELINE_SOURCE == "merge_request_event" && $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == $CI_DEFAULT_BRANCH && $CI_PROJECT_NAMESPACE == "gitlab-org/security" && $GITLAB_USER_LOGIN == "gitlab-release-tools-bot"'
+
####################
# Changes patterns #
####################
@@ -132,7 +138,10 @@
.db-patterns: &db-patterns
- "{,ee/}{,spec/}{db,migrations}/**/*"
+ - "{,ee/}{,spec/}lib/{,ee/}gitlab/database/**/*"
+ - "{,ee/}{,spec/}lib/{,ee/}gitlab/database{,_spec}.rb"
- "{,ee/}{,spec/}lib/{,ee/}gitlab/background_migration/**/*"
+ - "{,ee/}{,spec/}lib/{,ee/}gitlab/background_migration{,_spec}.rb"
- "config/prometheus/common_metrics.yml" # Used by Gitlab::DatabaseImporters::CommonMetrics::Importer
- "{,ee/}app/models/project_statistics.rb" # Used to calculate sizes in migration specs
@@ -282,6 +291,14 @@
when: manual
allow_failure: true
+##################
+# Delivery rules #
+##################
+.delivery:rules:security-pipeline-merge-result-failure:
+ rules:
+ - <<: *if-security-pipeline-merge-result
+ when: on_failure
+
######################
# Dev fixtures rules #
######################
@@ -336,6 +353,7 @@
.frontend:rules:compile-test-assets:
rules:
- changes: *code-backstage-qa-patterns
+ - <<: *if-merge-request-title-run-all-rspec
.frontend:rules:compile-test-assets-as-if-foss:
rules:
@@ -483,6 +501,7 @@
rules:
- <<: *if-default-refs
changes: *code-backstage-qa-patterns
+ - <<: *if-merge-request-title-run-all-rspec
.rails:rules:ee-only-migration:
rules:
@@ -628,6 +647,13 @@
- <<: *if-master-schedule-2-hourly
- <<: *if-merge-request-title-run-all-rspec
+.rails:rules:rspec-feature-flags:
+ rules:
+ - <<: *if-not-ee
+ when: never
+ - <<: *if-master-schedule-2-hourly
+ - <<: *if-merge-request-title-run-all-rspec
+
.rails:rules:master-schedule-nightly--code-backstage:
rules:
- <<: *if-master-schedule-nightly
@@ -702,6 +728,14 @@
- <<: *if-master-schedule-nightly
allow_failure: true
+.reports:rules:license_scanning:
+ rules:
+ - if: '$LICENSE_SCANNING_DISABLED || $GITLAB_FEATURES !~ /\blicense_scanning\b/'
+ when: never
+ - <<: *if-default-refs
+ changes: *code-backstage-qa-patterns
+ allow_failure: true
+
################
# Review rules #
################
@@ -859,6 +893,7 @@
- <<: *if-default-refs
changes: *code-backstage-patterns
when: on_success
+ - <<: *if-merge-request-title-run-all-rspec
.test-metadata:rules:update-tests-metadata:
rules:
diff --git a/.gitlab/ci/test-metadata.gitlab-ci.yml b/.gitlab/ci/test-metadata.gitlab-ci.yml
index 1764e9136a1..2d83531e1db 100644
--- a/.gitlab/ci/test-metadata.gitlab-ci.yml
+++ b/.gitlab/ci/test-metadata.gitlab-ci.yml
@@ -38,6 +38,6 @@ update-tests-metadata:
- rspec-ee integration pg11 geo
- rspec-ee system pg11 geo
script:
- - retry gem install fog-aws mime-types activesupport rspec_profiling postgres-copy --no-document
- - source scripts/rspec_helpers.sh
+ - run_timed_command "retry gem install fog-aws mime-types activesupport rspec_profiling postgres-copy --no-document"
+ - source ./scripts/rspec_helpers.sh
- update_tests_metadata
diff --git a/.gitlab/issue_templates/Feature Flag Roll Out.md b/.gitlab/issue_templates/Feature Flag Roll Out.md
index 69053b396a4..788b610a982 100644
--- a/.gitlab/issue_templates/Feature Flag Roll Out.md
+++ b/.gitlab/issue_templates/Feature Flag Roll Out.md
@@ -30,14 +30,14 @@ If applicable, any groups/projects that are happy to have this feature turned on
## Roll Out Steps
-- [ ] Enable on staging
+- [ ] Enable on staging (`/chatops run feature set feature_name true --staging`)
- [ ] Test on staging
- [ ] Ensure that documentation has been updated
-- [ ] Enable on GitLab.com for individual groups/projects listed above and verify behaviour
+- [ ] Enable on GitLab.com for individual groups/projects listed above and verify behaviour (`/chatops run feature set --project=gitlab-org/gitlab feature_name true`)
- [ ] Coordinate a time to enable the flag with `#production` and `#g_delivery` on slack.
- [ ] Announce on the issue an estimated time this will be enabled on GitLab.com
-- [ ] Enable on GitLab.com by running chatops command in `#production`
-- [ ] Cross post chatops slack command to `#support_gitlab-com` ([more guidance when this is necessary in the dev docs](https://docs.gitlab.com/ee/development/feature_flags/controls.html#where-to-run-commands)) and in your team channel
+- [ ] Enable on GitLab.com by running chatops command in `#production` (`/chatops run feature set feature_name true`)
+- [ ] Cross post chatops Slack command to `#support_gitlab-com` ([more guidance when this is necessary in the dev docs](https://docs.gitlab.com/ee/development/feature_flags/controls.html#where-to-run-commands)) and in your team channel
- [ ] Announce on the issue that the flag has been enabled
- [ ] Remove feature flag and add changelog entry
- [ ] After the flag removal is deployed, [clean up the feature flag](https://docs.gitlab.com/ee/development/feature_flags/controls.html#cleaning-up) by running chatops command in `#production` channel
diff --git a/.gitlab/issue_templates/Feature proposal.md b/.gitlab/issue_templates/Feature proposal.md
index 0f19b7c75f5..c80305312c3 100644
--- a/.gitlab/issue_templates/Feature proposal.md
+++ b/.gitlab/issue_templates/Feature proposal.md
@@ -1,6 +1,6 @@
<!-- The first section "Release notes" is required if you want to have your release post blog MR auto generated. Currently in BETA, details on the **release post item generator** can be found in the handbook: https://about.gitlab.com/handbook/marketing/blog/release-posts/#release-post-item-generator and this video: https://www.youtube.com/watch?v=rfn9ebgTwKg. The next four sections: "Problem to solve", "Intended users", "User experience goal", and "Proposal", are strongly recommended in your first draft, while the rest of the sections can be filled out during the problem validation or breakdown phase. However, keep in mind that providing complete and relevant information early helps our product team validate the problem and start working on a solution. -->
-### Release notes
+### Release notes
<!-- What is the problem and solution you're proposing? This content sets the overall vision for the feature and serves as the release notes that will populate in various places, including the [release post blog](https://about.gitlab.com/releases/categories/releases/) and [Gitlab project releases](https://gitlab.com/gitlab-org/gitlab/-/releases). " -->
@@ -22,19 +22,19 @@ Personas are described at https://about.gitlab.com/handbook/marketing/product-ma
* [Devon (DevOps Engineer)](https://about.gitlab.com/handbook/marketing/product-marketing/roles-personas/#devon-devops-engineer)
* [Sidney (Systems Administrator)](https://about.gitlab.com/handbook/marketing/product-marketing/roles-personas/#sidney-systems-administrator)
* [Sam (Security Analyst)](https://about.gitlab.com/handbook/marketing/product-marketing/roles-personas/#sam-security-analyst)
-* [Rachel (Release Manager)](https://about.gitlab.com/handbook/marketing/product-marketing/roles-personas/#rachel-release-manager)
+* [Rachel (Release Manager)](https://about.gitlab.com/handbook/marketing/product-marketing/roles-personas/#rachel-release-manager)
* [Alex (Security Operations Engineer)](https://about.gitlab.com/handbook/marketing/product-marketing/roles-personas/#alex-security-operations-engineer)
* [Simone (Software Engineer in Test)](https://about.gitlab.com/handbook/marketing/product-marketing/roles-personas/#simone-software-engineer-in-test)
-* [Allison (Application Ops)](https://about.gitlab.com/handbook/marketing/product-marketing/roles-personas/#allison-application-ops)
+* [Allison (Application Ops)](https://about.gitlab.com/handbook/marketing/product-marketing/roles-personas/#allison-application-ops)
* [Priyanka (Platform Engineer)](https://about.gitlab.com/handbook/marketing/product-marketing/roles-personas/#priyanka-platform-engineer)
* [Dana (Data Analyst)](https://about.gitlab.com/handbook/marketing/product-marketing/roles-personas/#dana-data-analyst)
-->
### User experience goal
-<!-- What is the single user experience workflow this problem addresses?
+<!-- What is the single user experience workflow this problem addresses?
For example, "The user should be able to use the UI/API/.gitlab-ci.yml with GitLab to <perform a specific task>"
-https://about.gitlab.com/handbook/engineering/ux/ux-research-training/user-story-mapping/ -->
+https://about.gitlab.com/handbook/engineering/ux/ux-research-training/user-story-mapping/ -->
### Proposal
@@ -52,7 +52,7 @@ Consider adding checkboxes and expectations of users with certain levels of memb
* [ ] Add expected impact to members with no access (0)
* [ ] Add expected impact to Guest (10) members
* [ ] Add expected impact to Reporter (20) members
-* [ ] Add expected impact to Developer (30) members
+* [ ] Add expected impact to Developer (30) members
* [ ] Add expected impact to Maintainer (40) members
* [ ] Add expected impact to Owner (50) members -->
@@ -78,7 +78,11 @@ See the test engineering planning process and reach out to your counterpart Soft
### What does success look like, and how can we measure that?
-<!-- Define both the success metrics and acceptance criteria. Note that success metrics indicate the desired business outcomes, while acceptance criteria indicate when the solution is working correctly. If there is no way to measure success, link to an issue that will implement a way to measure this. -->
+<!--
+Define both the success metrics and acceptance criteria. Note that success metrics indicate the desired business outcomes, while acceptance criteria indicate when the solution is working correctly. If there is no way to measure success, link to an issue that will implement a way to measure this.
+
+Create tracking issue using the the Snowplow event tracking template. See https://gitlab.com/gitlab-org/gitlab/-/blob/master/.gitlab/issue_templates/Snowplow%20event%20tracking.md
+-->
### What is the type of buyer?
diff --git a/.gitlab/issue_templates/Implementation.md b/.gitlab/issue_templates/Implementation.md
new file mode 100644
index 00000000000..dc5eb18a25e
--- /dev/null
+++ b/.gitlab/issue_templates/Implementation.md
@@ -0,0 +1,62 @@
+<!--
+Implementation issues are used break-up a large piece of work into small, discrete tasks that can
+move independently through the build workflow steps. They're typically used to populate a Feature
+Epic. Once created, an implementation issue is usually refined in order to populate and review the
+implementation plan and weight.
+Example workflow: https://about.gitlab.com/handbook/engineering/development/threat-management/planning/diagram.html#plan
+-->
+
+## Why are we doing this work
+<!--
+A brief explanation of the why, not the what or how. Assume the reader doesn't know the
+background and won't have time to dig-up information from comment threads.
+-->
+
+
+## Relevant links
+<!--
+Information that the developer might need to refer to when implementing the issue.
+
+- [Design Issue](https://gitlab.com/gitlab-org/gitlab/-/issues/<id>)
+ - [Design 1](https://gitlab.com/gitlab-org/gitlab/-/issues/<id>/designs/<image>.png)
+ - [Design 2](https://gitlab.com/gitlab-org/gitlab/-/issues/<id>/designs/<image>.png)
+- [Similar implementation](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/<id>)
+-->
+
+
+## Non-functional requirements
+<!--
+Add details for required items and delete others.
+-->
+
+- [ ] Documentation:
+- [ ] Feature flag:
+- [ ] Performance:
+- [ ] Testing:
+
+
+## Implementation plan
+<!--
+Steps and the parts of the code that will need to get updated. The plan can also
+call-out responsibilities for other team members or teams.
+-->
+
+- [ ] ~frontend Step 1
+ - [ ] @person Step 1a
+- [ ] ~frontend Step 2
+
+
+<!--
+Workflow and other relevant labels
+
+~"group::" ~"Category:" ~"GitLab Ultimate"
+-->
+/label ~"workflow::refinement"
+
+<!--
+Other settings you might want to include when creating the issue.
+
+/milestone %"Next 1-3 releases"
+/assign @
+/epic &
+-->
diff --git a/.gitlab/issue_templates/Migrations.md b/.gitlab/issue_templates/Migrations.md
index 38fc7a31b24..822722a0f71 100644
--- a/.gitlab/issue_templates/Migrations.md
+++ b/.gitlab/issue_templates/Migrations.md
@@ -16,7 +16,7 @@ Please add information here about why you're planning on migrating. Include any
<!-- Please complete as many items in this list as possible. If you're not sure yet, add "TBD" (To be Decided) or "Unknown" -->
* **Timeline.** -
- * **Product.** - GitLab Gold/Ultimate or Commnunity Edition
+ * **Product.** - GitLab Gold/Ultimate or Community Edition
* **Project's License.** What kind of OSI-approved license does your project use?
## Current Tooling and Replacements
@@ -64,4 +64,4 @@ Here is an example of what this list might look like once populated: https://git
------
/label ~"Open Source" ~movingtogitlab
-/cc @nuritzi \ No newline at end of file
+/cc @nuritzi
diff --git a/.gitlab/issue_templates/Security Release Tracking Issue.md b/.gitlab/issue_templates/Security Release Tracking Issue.md
index d2de7462ecb..fce68d61204 100644
--- a/.gitlab/issue_templates/Security Release Tracking Issue.md
+++ b/.gitlab/issue_templates/Security Release Tracking Issue.md
@@ -31,7 +31,7 @@ Your Security Implementation Issue should have `4` merge requests associated:
## Blog post
-Dev: {https://dev.gitlab.org/gitlab/www-gitlab-com/merge_requests/ link}<br/>
+Security: {https://gitlab.com/gitlab-org/security/www-gitlab-com/merge_requests/ link}<br/>
GitLab.com: {https://gitlab.com/gitlab-com/www-gitlab-com/merge_requests/ link}
## Email notification
diff --git a/.gitlab/issue_templates/Snowplow event tracking.md b/.gitlab/issue_templates/Snowplow event tracking.md
new file mode 100644
index 00000000000..47b97f377c2
--- /dev/null
+++ b/.gitlab/issue_templates/Snowplow event tracking.md
@@ -0,0 +1,42 @@
+<!--
+* Use this issue template for creating requests to track snowplow events
+* Snowplow events can be both Frontend (javascript) or Backend (Ruby)
+* Snowplow is currently not used for self-hosted instances of GitLab - Self-hosted still rely on usage ping for product analytics - Snowplow is used for GitLab SaaS
+* You do not need to create an issue to track generic front-end events, such as All page views, sessions, link clicks, some button clicks, etc.
+* What you should capture are specific events with defined business logic. For example, when a user creates an incident by escalating an existing alert, or when a user creates and pushes up a new Node package to the NPM registry.
+* For more details read https://about.gitlab.com/handbook/business-ops/data-team/programs/data-for-product-managers/
+ -->
+
+<!--
+We generally recommend events be tracked using a [structured event](https://docs.snowplowanalytics.com/docs/understanding-tracking-design/out-of-the-box-vs-custom-events-and-entities/#structured-events) which has 5 properties you can use. There may be instances where structured events are not sufficient. You may want to track an event where the property changes frequently or is general something very unique. In those cases, use a [self-describing event](https://docs.snowplowanalytics.com/docs/understanding-tracking-design/out-of-the-box-vs-custom-events-and-entities/#self-describing-events)
+
+-->
+
+## Structured Snowplow events to track
+
+* Category: The page or backend area of the application. Unless infeasible, please use the Rails page attribute by default in the frontend, and namespace + classname on the backend. If you're not sure what it is, work with your engineering manager to figure it out.
+* Action: A string that is used to define the user action. The first word should always describe the action or aspect: clicks should be `click`, activations should be `activate`, creations should be `create`, etc. Use underscores to describe what was acted on; for example, activating a form field would be `activate_form_input`. An interface action like clicking on a dropdown would be `click_dropdown`, while a behavior like creating a project record from the backend would be `create_project`
+* Label: Optional. The specific element, or object that's being acted on. This is either the label of the element (e.g. a tab labeled 'Create from template' may be `create_from_template`) or a unique identifier if no text is available (e.g. closing the Groups dropdown in the top navbar might be `groups_dropdown_close`), or it could be the name or title attribute of a record being created.
+* Property: Optional. Any additional property of the element, or object being acted on.
+* Value: Optional, numeric. Describes a numeric value or something directly related to the event. This could be the value of an input (e.g. `10` when clicking `internal` visibility)
+
+| Category | Action | Label | Property | Feature Issue | Additional Information |
+| ------ | ------ | ------ | ------ | ------ | ------ |
+| cell | cell | cell | cell | cell | cell |
+| cell | cell | cell | cell | cell | cell |
+
+<!--
+ Snowplow event tracking starts with instrumentation and completed after a chart is created in Sisense.
+
+ Use this checklist to ensure all steps are completed
+-->
+
+## Snowplow event tracking checklist
+* [ ] Engineering complete work and deploy changes to GitLab SaaS
+* [ ] Verify the new Snowplow events are listed in the [Snowplow Event Exploration](https://app.periscopedata.com/app/gitlab/539181/Snowplow-Event-Exploration---last-30-days) dashboard
+* [ ] Create chart(s) to track your event(s) in the relevant dashboard
+ * [ ] Use the [Chart Snowplow Actions](https://app.periscopedata.com/app/gitlab/snippet/Chart-Snowplow-Actions/5546da87ae2c4a3fbc98415c88b3eedd/edit) SQL snippet to quickly visualize usage. See [example](https://app.periscopedata.com/app/gitlab/737489/Health-Group-Dashboard?widget=9797112&udv=0)
+
+<!-- Label reminders - you should have one of each of the following labels if you can figure out the correct ones -->
+/label ~devops:: ~group: ~Category:
+/label ~"snowplow tracking events"
diff --git a/.gitlab/issue_templates/actionable_insight.md b/.gitlab/issue_templates/actionable_insight.md
index 7c65388eff4..68b2b153831 100644
--- a/.gitlab/issue_templates/actionable_insight.md
+++ b/.gitlab/issue_templates/actionable_insight.md
@@ -1,5 +1,5 @@
## Actionable Insights
-Actionable insights always have a follow-up action that needs to take place as a result of the research observation or data, and a clear recommendation or action associated with it. An actionable insight both defines the insight and clearly calls out the next step. These insights are tracked over time.
+Actionable insights always have a follow-up action that needs to take place as a result of the research observation or data, and a clear recommendation or action associated with it. An actionable insight both defines the insight and clearly calls out the next step. These insights are tracked over time and at the group level.
#### Link
@@ -10,6 +10,10 @@ Actionable insights always have a follow-up action that needs to take place as a
- [ ] Assign this issue to the appropriate Product Manager, Product Designer, or UX Researcher
+#### Group label
+
+- [ ] Add the appropriate `Group` (such as `~"group::source code"`) label to the issue. This is done to identify and track actionable insights at the group level.
+
#### Description
- [ ] Provide some brief details on the actionable insight and the action to take
diff --git a/.gitlab/merge_request_templates/Change Documentation Location.md b/.gitlab/merge_request_templates/Change Documentation Location.md
index f18957fdaaa..1197c6adc40 100644
--- a/.gitlab/merge_request_templates/Change Documentation Location.md
+++ b/.gitlab/merge_request_templates/Change Documentation Location.md
@@ -15,18 +15,16 @@ Closes
## Moving docs to a new location?
Read the guidelines:
-https://docs.gitlab.com/ee/development/documentation/index.html#changing-document-location
+https://docs.gitlab.com/ee/development/documentation/index.html#move-or-rename-a-page
- [ ] Make sure the old link is not removed and has its contents replaced with
a link to the new location.
- [ ] Make sure internal links pointing to the document in question are not broken.
- [ ] Search and replace any links referring to old docs in GitLab Rails app,
- specifically under the `app/views/` and `ee/app/views` (for GitLab EE) directories.
-- [ ] Make sure to add [`redirect_from`](https://docs.gitlab.com/ce/development/documentation/index.html#redirections-for-pages-with-disqus-comments)
+ specifically under the `app/views/` and `ee/app/views` (for GitLab EE) directories.
+- [ ] Make sure to add [`redirect_from`](https://docs.gitlab.com/ee/development/documentation/index.html#redirections-for-pages-with-disqus-comments)
to the new document if there are any Disqus comments on the old document thread.
- [ ] Update the link in `features.yml` (if applicable)
-- [ ] If working on CE and the `ee-compat-check` jobs fails, submit an MR to EE
- with the changes as well (https://docs.gitlab.com/ce/development/documentation/index.html#cherry-picking-from-ce-to-ee).
-- [ ] Ping one of the technical writers for review.
+- [ ] Assign one of the technical writers for review.
/label ~documentation
diff --git a/.gitlab/merge_request_templates/Documentation.md b/.gitlab/merge_request_templates/Documentation.md
index b17043fd3b9..8713405033b 100644
--- a/.gitlab/merge_request_templates/Documentation.md
+++ b/.gitlab/merge_request_templates/Documentation.md
@@ -48,10 +48,13 @@ All reviewers can help ensure accuracy, clarity, completeness, and adherence to
- [ ] Technical writer review. If not requested for this MR, must be scheduled post-merge. To request for this MR, assign the writer listed for the applicable [DevOps stage](https://about.gitlab.com/handbook/product/product-categories/#devops-stages).
- [ ] Ensure docs metadata are present and up-to-date.
- [ ] Ensure ~"Technical Writing" and ~"documentation" are added.
- - [ ] Add the corresponding `docs::` scoped label.
+ - [ ] Add the corresponding `docs::` [scoped label](https://gitlab.com/groups/gitlab-org/-/labels?utf8=%E2%9C%93&subscribed=&search=docs%3A%3A).
+ - [ ] If working on UI text, add the corresponding `UI Text` [scoped label](https://gitlab.com/groups/gitlab-org/-/labels?utf8=%E2%9C%93&subscribed=&search=ui+text).
- [ ] Add ~"tw::doing" when starting work on the MR.
- [ ] Add ~"tw::finished" if Technical Writing team work on the MR is complete but it remains open.
+For more information about labels, see [Technical Writing workflows - Labels](https://about.gitlab.com/handbook/engineering/ux/technical-writing/workflow/#labels).
+
**3. Maintainer**
1. [ ] Review by assigned maintainer, who can always request/require the above reviews. Maintainer's review can occur before or after a technical writer review.
diff --git a/.gitlab/merge_request_templates/New Static Analysis Check.md b/.gitlab/merge_request_templates/New Static Analysis Check.md
index 8bbb3effb1c..5fd2d31767a 100644
--- a/.gitlab/merge_request_templates/New Static Analysis Check.md
+++ b/.gitlab/merge_request_templates/New Static Analysis Check.md
@@ -22,6 +22,6 @@ Please describe the proposal and add a link to the source (for example, http://w
- [ ] In the relevant Slack channels (e.g. `#development`, `#backend`, `#frontend`)
- [ ] (Optional depending on the impact of the change) In the Engineering Week in Review
-/label ~"Engineering Productivity" ~"Style decision" ~"development guidelines" ~"static analysis"
+/label ~"Engineering Productivity" ~"development guidelines" ~"static code analysis"
/cc @gitlab-org/maintainers/rails-backend
diff --git a/.gitlab/merge_request_templates/Security Release.md b/.gitlab/merge_request_templates/Security Release.md
index eda16747c13..fccfad18ef0 100644
--- a/.gitlab/merge_request_templates/Security Release.md
+++ b/.gitlab/merge_request_templates/Security Release.md
@@ -21,7 +21,7 @@ See [the general developer security release guidelines](https://gitlab.com/gitla
- [ ] Assign to a reviewer and maintainer, per our [Code Review process].
- [ ] Ensure it's approved according to our [Approval Guidelines].
- [ ] Ensure it's approved by an AppSec engineer.
- - If you're unsure who should approve, find the AppSec engineer associated to the issue in the [Canonical repository], or ask #sec-appsec on Slack.
+ - Please see the security release [Code reviews and Approvals](https://gitlab.com/gitlab-org/release/docs/blob/master/general/security/developer.md#code-reviews-and-approvals) documentation for details on which AppSec team member to ping for approval.
- Trigger the [`package-and-qa` build]. The docker image generated will be used by the AppSec engineer to validate the security vulnerability has been remediated.
- [ ] For a backport MR targeting a versioned stable branch (`X-Y-stable-ee`)
- [ ] Ensure it's approved by a maintainer.
diff --git a/.gitpod.yml b/.gitpod.yml
new file mode 100644
index 00000000000..1a8a8e8555e
--- /dev/null
+++ b/.gitpod.yml
@@ -0,0 +1,89 @@
+image: registry.gitlab.com/gitlab-org/gitlab-development-kit/gitpod-workspace:gitpod-workspace-image
+
+tasks:
+
+ - name: GDK
+ command: gp sync-await gdk-copied && cd /workspace/gitlab-development-kit && gdk help
+
+ - init: |
+ echo "$(date) – Copying GDK" | tee -a /workspace/startup.log
+ mv $HOME/.rvm-workspace /workspace/.rvm
+ cp -r $HOME/gitlab-development-kit /workspace/
+ (
+ set -e
+ cd /workspace/gitlab-development-kit
+ [[ ! -L /workspace/gitlab-development-kit/gitlab ]] && ln -fs /workspace/gitlab /workspace/gitlab-development-kit/gitlab
+ # make webpack static, prevents that GitLab tries to connect to localhost webpack from browser outside the workspace
+ echo "webpack:" >> gdk.yml
+ echo " static: true" >> gdk.yml
+ # reconfigure GDK
+ echo "$(date) – Reconfiguring GDK" | tee -a /workspace/startup.log
+ gdk reconfigure
+ # run DB migrations
+ echo "$(date) – Running DB migrations" | tee -a /workspace/startup.log
+ make gitlab-db-migrate
+ cd -
+ # stop GDK
+ echo "$(date) – Stopping GDK" | tee -a /workspace/startup.log
+ gdk stop
+ echo "$(date) – GDK stopped" | tee -a /workspace/startup.log
+ )
+ command: |
+ (
+ set -e
+ gp sync-done gdk-copied
+ SECONDS=0
+ cd /workspace/gitlab-development-kit
+ # update GDK
+ if [ "$GITLAB_UPDATE_GDK" == true ]; then
+ echo "$(date) – Updating GDK" | tee -a /workspace/startup.log
+ gdk update
+ fi
+ # start GDK
+ echo "$(date) – Starting GDK" | tee -a /workspace/startup.log
+ export RAILS_HOSTS=$(gp url 3000 | sed -e 's+^http[s]*://++')
+ gdk start
+ # Run DB migrations
+ if [ "$GITLAB_RUN_DB_MIGRATIONS" == true ]; then
+ make gitlab-db-migrate
+ fi
+ # Fix DB key
+ if [ "$GITLAB_FIX_DB_KEY" = true ]; then
+ echo "$(date) – Fixing DB key" | tee -a /workspace/startup.log
+ cd gitlab
+ # see https://gitlab.com/gitlab-org/gitlab-foss/-/issues/56403#note_132515069
+ printf 'ApplicationSetting.last.update_column(:runners_registration_token_encrypted, nil)\nexit\n' | bundle exec rails c
+ cd -
+ fi
+ # Waiting for GitLab ...
+ gp await-port 3000
+ printf "Waiting for GitLab at $(gp url 3000) ..."
+ until $(curl -sNL $(gp url 3000) | grep -q "GitLab"); do printf '.'; sleep 5; done && echo ""
+ # Give Gitpod a few more seconds to set up everything ...
+ sleep 5
+ 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
+ )
+
+ports:
+ - port: 3000 # rails-web
+ onOpen: ignore
+ - port: 3010 # gitlab-pages
+ onOpen: ignore
+ - port: 3808 # webpack
+ onOpen: ignore
+ - port: 5000 # auto_devops
+ onOpen: ignore
+ - port: 5778 # jaeger
+ onOpen: ignore
+ - port: 9000 # object_store / minio
+ onOpen: ignore
+
+vscode:
+ extensions:
+ - rebornix.ruby@0.27.0:QyGBeRyslOfdRgOPRGm6PQ==
+ - wingrunr21.vscode-ruby@0.27.0:beIqQUhLRuJ5Vao4B2Lyng==
+ - karunamurti.haml@1.1.0:twCwOYt3/Ttfb3+iwblPDA==
+ - octref.vetur@0.25.0:UofirBhedyhdx/jCnPeJDg==
+ - dbaeumer.vscode-eslint@2.1.3:1NRvj3UKNTNwmYjptmUmIw==
+ - GitLab.gitlab-workflow@3.3.0:50q1byIi4M01G9qrTCCAYQ==
diff --git a/.haml-lint_todo.yml b/.haml-lint_todo.yml
index 83aba188d2b..57c0e014a03 100644
--- a/.haml-lint_todo.yml
+++ b/.haml-lint_todo.yml
@@ -7,377 +7,374 @@
# versions of Haml-Lint, may require this file to be generated again.
linters:
-
# Offense count: 1552
NoPlainNodes:
enabled: true
exclude:
- - "app/views/admin/abuse_reports/_abuse_report.html.haml"
- - "app/views/admin/abuse_reports/index.html.haml"
- - "app/views/admin/appearances/_form.html.haml"
- - "app/views/admin/application_settings/_abuse.html.haml"
- - "app/views/admin/application_settings/_diff_limits.html.haml"
- - "app/views/admin/application_settings/_gitaly.html.haml"
- - "app/views/admin/application_settings/_ip_limits.html.haml"
- - "app/views/admin/application_settings/_performance.html.haml"
- - "app/views/admin/application_settings/_plantuml.html.haml"
- - "app/views/admin/application_settings/_prometheus.html.haml"
- - "app/views/admin/application_settings/_realtime.html.haml"
- - "app/views/admin/application_settings/_repository_check.html.haml"
- - "app/views/admin/application_settings/_signin.html.haml"
- - "app/views/admin/application_settings/_signup.html.haml"
- - "app/views/admin/application_settings/_spam.html.haml"
- - "app/views/admin/application_settings/_terminal.html.haml"
- - "app/views/admin/application_settings/_usage.html.haml"
- - "app/views/admin/application_settings/_visibility_and_access.html.haml"
- - "app/views/admin/applications/_delete_form.html.haml"
- - "app/views/admin/applications/_form.html.haml"
- - "app/views/admin/applications/edit.html.haml"
- - "app/views/admin/applications/index.html.haml"
- - "app/views/admin/applications/new.html.haml"
- - "app/views/admin/applications/show.html.haml"
- - "app/views/admin/background_jobs/show.html.haml"
- - "app/views/admin/broadcast_messages/index.html.haml"
- - "app/views/admin/dashboard/index.html.haml"
- - "app/views/admin/deploy_keys/new.html.haml"
- - "app/views/admin/health_check/show.html.haml"
- - "app/views/admin/hook_logs/_index.html.haml"
- - "app/views/admin/hook_logs/show.html.haml"
- - "app/views/admin/hooks/_form.html.haml"
- - "app/views/admin/hooks/edit.html.haml"
- - "app/views/admin/logs/show.html.haml"
- - "app/views/admin/projects/_projects.html.haml"
- - "app/views/admin/requests_profiles/index.html.haml"
- - "app/views/admin/runners/_runner.html.haml"
- - "app/views/admin/runners/index.html.haml"
- - "app/views/admin/runners/show.html.haml"
- - "app/views/admin/services/_form.html.haml"
- - "app/views/admin/services/index.html.haml"
- - "app/views/admin/spam_logs/_spam_log.html.haml"
- - "app/views/admin/spam_logs/index.html.haml"
- - "app/views/admin/system_info/show.html.haml"
- - "app/views/admin/users/_form.html.haml"
- - "app/views/admin/users/_head.html.haml"
- - "app/views/admin/users/_profile.html.haml"
- - "app/views/admin/users/_projects.html.haml"
- - "app/views/admin/users/new.html.haml"
- - "app/views/admin/users/projects.html.haml"
- - "app/views/admin/users/show.html.haml"
+ - 'app/views/admin/abuse_reports/_abuse_report.html.haml'
+ - 'app/views/admin/abuse_reports/index.html.haml'
+ - 'app/views/admin/appearances/_form.html.haml'
+ - 'app/views/admin/application_settings/_abuse.html.haml'
+ - 'app/views/admin/application_settings/_diff_limits.html.haml'
+ - 'app/views/admin/application_settings/_gitaly.html.haml'
+ - 'app/views/admin/application_settings/_ip_limits.html.haml'
+ - 'app/views/admin/application_settings/_performance.html.haml'
+ - 'app/views/admin/application_settings/_plantuml.html.haml'
+ - 'app/views/admin/application_settings/_prometheus.html.haml'
+ - 'app/views/admin/application_settings/_realtime.html.haml'
+ - 'app/views/admin/application_settings/_repository_check.html.haml'
+ - 'app/views/admin/application_settings/_signin.html.haml'
+ - 'app/views/admin/application_settings/_signup.html.haml'
+ - 'app/views/admin/application_settings/_spam.html.haml'
+ - 'app/views/admin/application_settings/_terminal.html.haml'
+ - 'app/views/admin/application_settings/_usage.html.haml'
+ - 'app/views/admin/application_settings/_visibility_and_access.html.haml'
+ - 'app/views/admin/applications/_delete_form.html.haml'
+ - 'app/views/admin/applications/_form.html.haml'
+ - 'app/views/admin/applications/edit.html.haml'
+ - 'app/views/admin/applications/index.html.haml'
+ - 'app/views/admin/applications/new.html.haml'
+ - 'app/views/admin/applications/show.html.haml'
+ - 'app/views/admin/background_jobs/show.html.haml'
+ - 'app/views/admin/broadcast_messages/index.html.haml'
+ - 'app/views/admin/dashboard/index.html.haml'
+ - 'app/views/admin/deploy_keys/new.html.haml'
+ - 'app/views/admin/health_check/show.html.haml'
+ - 'app/views/admin/hook_logs/_index.html.haml'
+ - 'app/views/admin/hook_logs/show.html.haml'
+ - 'app/views/admin/hooks/_form.html.haml'
+ - 'app/views/admin/hooks/edit.html.haml'
+ - 'app/views/admin/logs/show.html.haml'
+ - 'app/views/admin/projects/_projects.html.haml'
+ - 'app/views/admin/requests_profiles/index.html.haml'
+ - 'app/views/admin/runners/_runner.html.haml'
+ - 'app/views/admin/runners/index.html.haml'
+ - 'app/views/admin/runners/show.html.haml'
+ - 'app/views/admin/services/_form.html.haml'
+ - 'app/views/admin/services/index.html.haml'
+ - 'app/views/admin/spam_logs/_spam_log.html.haml'
+ - 'app/views/admin/spam_logs/index.html.haml'
+ - 'app/views/admin/system_info/show.html.haml'
+ - 'app/views/admin/users/_form.html.haml'
+ - 'app/views/admin/users/_head.html.haml'
+ - 'app/views/admin/users/_profile.html.haml'
+ - 'app/views/admin/users/_projects.html.haml'
+ - 'app/views/admin/users/new.html.haml'
+ - 'app/views/admin/users/projects.html.haml'
+ - 'app/views/admin/users/show.html.haml'
- 'app/views/authentication/_authenticate.html.haml'
- 'app/views/authentication/_register.html.haml'
- - "app/views/clusters/clusters/_cluster.html.haml"
- - "app/views/clusters/clusters/new.html.haml"
- - "app/views/dashboard/milestones/index.html.haml"
- - "app/views/dashboard/projects/_blank_state_admin_welcome.html.haml"
- - "app/views/dashboard/projects/_blank_state_welcome.html.haml"
- - "app/views/dashboard/todos/_todo.html.haml"
- - "app/views/dashboard/todos/index.html.haml"
- - "app/views/devise/confirmations/almost_there.haml"
- - "app/views/devise/mailer/_confirmation_instructions_account.html.haml"
- - "app/views/devise/mailer/_confirmation_instructions_secondary.html.haml"
- - "app/views/devise/mailer/email_changed.html.haml"
- - "app/views/devise/mailer/password_change.html.haml"
- - "app/views/devise/mailer/reset_password_instructions.html.haml"
- - "app/views/devise/mailer/unlock_instructions.html.haml"
- - "app/views/devise/passwords/edit.html.haml"
- - "app/views/devise/sessions/_new_base.html.haml"
- - "app/views/devise/sessions/_new_crowd.html.haml"
- - "app/views/devise/sessions/_new_ldap.html.haml"
- - "app/views/devise/sessions/new.html.haml"
- - "app/views/devise/sessions/two_factor.html.haml"
- - "app/views/devise/shared/_omniauth_box.html.haml"
- - "app/views/devise/shared/_sign_in_link.html.haml"
- - "app/views/devise/shared/_tabs_normal.html.haml"
- - "app/views/discussions/_discussion.html.haml"
- - "app/views/discussions/_headline.html.haml"
- - "app/views/discussions/_notes.html.haml"
- - "app/views/doorkeeper/applications/_delete_form.html.haml"
- - "app/views/doorkeeper/authorized_applications/_delete_form.html.haml"
- - "app/views/errors/encoding.html.haml"
- - "app/views/errors/git_not_found.html.haml"
- - "app/views/errors/omniauth_error.html.haml"
- - "app/views/errors/precondition_failed.html.haml"
- - "app/views/events/_event_push.atom.haml"
- - "app/views/events/event/_push.html.haml"
- - "app/views/groups/_create_chat_team.html.haml"
- - "app/views/groups/_group_admin_settings.html.haml"
- - "app/views/groups/labels/edit.html.haml"
- - "app/views/groups/labels/new.html.haml"
- - "app/views/groups/milestones/edit.html.haml"
- - "app/views/groups/milestones/index.html.haml"
- - "app/views/groups/milestones/new.html.haml"
- - "app/views/groups/projects.html.haml"
- - "app/views/groups/runners/edit.html.haml"
- - "app/views/groups/settings/_advanced.html.haml"
- - "app/views/groups/settings/_lfs.html.haml"
- - "app/views/help/_shortcuts.html.haml"
- - "app/views/help/index.html.haml"
- - "app/views/help/instance_configuration.html.haml"
- - "app/views/help/instance_configuration/_gitlab_ci.html.haml"
- - "app/views/help/instance_configuration/_gitlab_pages.html.haml"
- - "app/views/import/bitbucket/status.html.haml"
- - "app/views/import/bitbucket_server/status.html.haml"
- - "app/views/invites/show.html.haml"
- - "app/views/jira_connect/subscriptions/index.html.haml"
- - "app/views/layouts/_mailer.html.haml"
- - "app/views/layouts/experiment_mailer.html.haml"
- - "app/views/layouts/header/_default.html.haml"
- - "app/views/layouts/header/_new_dropdown.haml"
- - "app/views/layouts/jira_connect.html.haml"
- - "app/views/layouts/notify.html.haml"
- - "app/views/notify/_failed_builds.html.haml"
- - "app/views/notify/_reassigned_issuable_email.html.haml"
- - "app/views/notify/_removal_notification.html.haml"
- - "app/views/notify/_successful_pipeline.html.haml"
- - "app/views/notify/autodevops_disabled_email.html.haml"
- - "app/views/notify/changed_milestone_email.html.haml"
- - "app/views/notify/import_issues_csv_email.html.haml"
- - "app/views/notify/issue_moved_email.html.haml"
- - "app/views/notify/member_access_denied_email.html.haml"
- - "app/views/notify/member_invite_accepted_email.html.haml"
- - "app/views/notify/member_invited_email.html.haml"
- - "app/views/notify/new_gpg_key_email.html.haml"
- - "app/views/notify/new_mention_in_issue_email.html.haml"
- - "app/views/notify/new_ssh_key_email.html.haml"
- - "app/views/notify/new_user_email.html.haml"
- - "app/views/notify/pages_domain_disabled_email.html.haml"
- - "app/views/notify/pages_domain_enabled_email.html.haml"
- - "app/views/notify/pages_domain_verification_failed_email.html.haml"
- - "app/views/notify/pages_domain_verification_succeeded_email.html.haml"
- - "app/views/notify/pipeline_failed_email.html.haml"
- - "app/views/notify/project_was_exported_email.html.haml"
- - "app/views/notify/project_was_moved_email.html.haml"
- - "app/views/notify/project_was_not_exported_email.html.haml"
- - "app/views/notify/push_to_merge_request_email.html.haml"
- - "app/views/notify/remote_mirror_update_failed_email.html.haml"
- - "app/views/notify/removed_milestone_issue_email.html.haml"
- - "app/views/notify/removed_milestone_merge_request_email.html.haml"
- - "app/views/notify/repository_push_email.html.haml"
- - "app/views/profiles/chat_names/_chat_name.html.haml"
- - "app/views/profiles/chat_names/index.html.haml"
- - "app/views/profiles/chat_names/new.html.haml"
- - "app/views/projects/_bitbucket_import_modal.html.haml"
- - "app/views/projects/_customize_workflow.html.haml"
- - "app/views/projects/_deletion_failed.html.haml"
- - "app/views/projects/_fork_suggestion.html.haml"
- - "app/views/projects/_gitlab_import_modal.html.haml"
- - "app/views/projects/_home_panel.html.haml"
- - "app/views/projects/_import_project_pane.html.haml"
- - "app/views/projects/_issuable_by_email.html.haml"
- - "app/views/projects/_readme.html.haml"
- - "app/views/projects/artifacts/_artifact.html.haml"
- - "app/views/projects/artifacts/_tree_file.html.haml"
- - "app/views/projects/artifacts/browse.html.haml"
- - "app/views/projects/blame/_age_map_legend.html.haml"
- - "app/views/projects/blame/show.html.haml"
- - "app/views/projects/blob/_editor.html.haml"
- - "app/views/projects/blob/_header_content.html.haml"
- - "app/views/projects/blob/_remove.html.haml"
- - "app/views/projects/blob/_render_error.html.haml"
- - "app/views/projects/blob/edit.html.haml"
- - "app/views/projects/blob/new.html.haml"
- - "app/views/projects/blob/preview.html.haml"
- - "app/views/projects/blob/viewers/_empty.html.haml"
- - "app/views/projects/blob/viewers/_stl.html.haml"
- - "app/views/projects/branches/_branch.html.haml"
- - "app/views/projects/branches/_delete_protected_modal.html.haml"
- - "app/views/projects/branches/new.html.haml"
- - "app/views/projects/ci/builds/_build.html.haml"
- - "app/views/projects/ci/lints/_create.html.haml"
- - "app/views/projects/compare/_form.html.haml"
- - "app/views/projects/compare/index.html.haml"
- - "app/views/projects/cycle_analytics/_empty_stage.html.haml"
- - "app/views/projects/cycle_analytics/_no_access.html.haml"
- - "app/views/projects/cycle_analytics/_overview.html.haml"
- - "app/views/projects/cycle_analytics/show.html.haml"
- - "app/views/projects/deploy_keys/_form.html.haml"
- - "app/views/projects/deploy_keys/_index.html.haml"
- - "app/views/projects/deploy_keys/edit.html.haml"
- - "app/views/projects/deployments/_deployment.html.haml"
- - "app/views/projects/diffs/_file_header.html.haml"
- - "app/views/projects/diffs/_replaced_image_diff.html.haml"
- - "app/views/projects/diffs/_stats.html.haml"
- - "app/views/projects/empty.html.haml"
- - "app/views/projects/generic_commit_statuses/_generic_commit_status.html.haml"
- - "app/views/projects/hook_logs/_index.html.haml"
- - "app/views/projects/hook_logs/show.html.haml"
- - "app/views/projects/hooks/edit.html.haml"
- - "app/views/projects/imports/new.html.haml"
- - "app/views/projects/imports/show.html.haml"
- - "app/views/projects/issues/_new_branch.html.haml"
- - "app/views/projects/issues/import_csv/_modal.html.haml"
- - "app/views/projects/issues/show.html.haml"
- - "app/views/projects/jobs/_header.html.haml"
- - "app/views/projects/jobs/_table.html.haml"
- - "app/views/projects/jobs/index.html.haml"
- - "app/views/projects/labels/edit.html.haml"
- - "app/views/projects/labels/new.html.haml"
- - "app/views/projects/mattermosts/_no_teams.html.haml"
- - "app/views/projects/mattermosts/_team_selection.html.haml"
- - "app/views/projects/mattermosts/new.html.haml"
- - "app/views/projects/merge_requests/_commits.html.haml"
- - "app/views/projects/merge_requests/_discussion.html.haml"
- - "app/views/projects/merge_requests/_how_to_merge.html.haml"
- - "app/views/projects/merge_requests/_mr_title.html.haml"
- - "app/views/projects/merge_requests/conflicts/_commit_stats.html.haml"
- - "app/views/projects/merge_requests/conflicts/_file_actions.html.haml"
- - "app/views/projects/merge_requests/conflicts/_submit_form.html.haml"
- - "app/views/projects/merge_requests/conflicts/components/_diff_file_editor.html.haml"
- - "app/views/projects/merge_requests/conflicts/components/_inline_conflict_lines.html.haml"
- - "app/views/projects/merge_requests/conflicts/show.html.haml"
- - "app/views/projects/merge_requests/creations/_diffs.html.haml"
- - "app/views/projects/merge_requests/creations/_new_compare.html.haml"
- - "app/views/projects/merge_requests/creations/_new_submit.html.haml"
- - "app/views/projects/merge_requests/diffs/_different_base.html.haml"
- - "app/views/projects/merge_requests/diffs/_diffs.html.haml"
- - "app/views/projects/merge_requests/diffs/_version_controls.html.haml"
- - "app/views/projects/merge_requests/invalid.html.haml"
- - "app/views/projects/merge_requests/widget/open/_error.html.haml"
- - "app/views/projects/mirrors/_regenerate_public_ssh_key_confirm_modal.html.haml"
- - "app/views/projects/mirrors/_ssh_host_keys.html.haml"
- - "app/views/projects/no_repo.html.haml"
- - "app/views/projects/pipeline_schedules/_pipeline_schedule.html.haml"
- - "app/views/projects/pipelines/_info.html.haml"
- - "app/views/projects/protected_branches/shared/_dropdown.html.haml"
- - "app/views/projects/protected_branches/shared/_index.html.haml"
- - "app/views/projects/protected_branches/shared/_matching_branch.html.haml"
- - "app/views/projects/protected_branches/shared/_protected_branch.html.haml"
- - "app/views/projects/protected_branches/show.html.haml"
- - "app/views/projects/protected_tags/shared/_create_protected_tag.html.haml"
- - "app/views/projects/protected_tags/shared/_dropdown.html.haml"
- - "app/views/projects/protected_tags/shared/_index.html.haml"
- - "app/views/projects/protected_tags/shared/_matching_tag.html.haml"
- - "app/views/projects/protected_tags/shared/_protected_tag.html.haml"
- - "app/views/projects/protected_tags/shared/_tags_list.html.haml"
- - "app/views/projects/protected_tags/show.html.haml"
- - "app/views/projects/registry/repositories/_tag.html.haml"
- - "app/views/projects/repositories/_feed.html.haml"
- - "app/views/projects/runners/_shared_runners.html.haml"
- - "app/views/projects/runners/edit.html.haml"
- - "app/views/projects/services/mattermost_slash_commands/_detailed_help.html.haml"
- - "app/views/projects/services/mattermost_slash_commands/_help.html.haml"
- - "app/views/projects/services/prometheus/_metrics.html.haml"
- - "app/views/projects/services/slack_slash_commands/_help.html.haml"
- - "app/views/projects/settings/ci_cd/_badge.html.haml"
- - "app/views/projects/settings/ci_cd/_form.html.haml"
- - "app/views/projects/tags/index.html.haml"
- - "app/views/projects/tags/releases/edit.html.haml"
- - "app/views/projects/tree/_tree_row.html.haml"
- - "app/views/projects/tree/_truncated_notice_tree_row.html.haml"
- - "app/views/projects/triggers/_form.html.haml"
- - "app/views/projects/triggers/_index.html.haml"
- - "app/views/projects/triggers/_trigger.html.haml"
- - "app/views/projects/triggers/edit.html.haml"
- - "app/views/search/results/_issue.html.haml"
- - "app/views/search/results/_note.html.haml"
- - "app/views/search/results/_snippet_blob.html.haml"
- - "app/views/search/results/_snippet_title.html.haml"
- - "app/views/shared/_auto_devops_implicitly_enabled_banner.html.haml"
- - "app/views/shared/_commit_message_container.html.haml"
- - "app/views/shared/_delete_label_modal.html.haml"
- - "app/views/shared/_group_form.html.haml"
- - "app/views/shared/_group_tips.html.haml"
- - "app/views/shared/_md_preview.html.haml"
- - "app/views/shared/_milestone_expired.html.haml"
- - "app/views/shared/_no_password.html.haml"
- - "app/views/shared/_ping_consent.html.haml"
- - "app/views/shared/_project_limit.html.haml"
- - "app/views/shared/boards/components/_sidebar.html.haml"
- - "app/views/shared/boards/components/sidebar/_due_date.html.haml"
- - "app/views/shared/boards/components/sidebar/_labels.html.haml"
- - "app/views/shared/boards/components/sidebar/_milestone.html.haml"
- - "app/views/shared/hook_logs/_content.html.haml"
- - "app/views/shared/issuable/_assignees.html.haml"
- - "app/views/shared/issuable/_board_create_list_dropdown.html.haml"
- - "app/views/shared/issuable/_close_reopen_report_toggle.html.haml"
- - "app/views/shared/issuable/_form.html.haml"
- - "app/views/shared/issuable/_search_bar.html.haml"
- - "app/views/shared/issuable/_sidebar.html.haml"
- - "app/views/shared/issuable/form/_default_templates.html.haml"
- - "app/views/shared/issuable/form/_template_selector.html.haml"
- - "app/views/shared/issuable/form/_title.html.haml"
- - "app/views/shared/labels/_form.html.haml"
- - "app/views/shared/members/_member.html.haml"
- - "app/views/shared/milestones/_form_dates.html.haml"
- - "app/views/shared/milestones/_issuable.html.haml"
- - "app/views/shared/milestones/_milestone.html.haml"
- - "app/views/shared/milestones/_sidebar.html.haml"
- - "app/views/shared/milestones/_top.html.haml"
- - "app/views/shared/notes/_hints.html.haml"
- - "app/views/shared/notifications/_button.html.haml"
- - "app/views/shared/notifications/_new_button.html.haml"
- - "app/views/shared/runners/_runner_description.html.haml"
- - "app/views/shared/runners/show.html.haml"
- - "app/views/shared/snippets/_header.html.haml"
- - "app/views/shared/snippets/_snippet.html.haml"
- - "app/views/shared/web_hooks/_form.html.haml"
- - "app/views/shared/web_hooks/_hook.html.haml"
- - "app/views/shared/wikis/_pages_wiki_page.html.haml"
- - "app/views/users/_deletion_guidance.html.haml"
- - "ee/app/views/admin/_namespace_plan_info.html.haml"
- - "ee/app/views/admin/application_settings/_templates.html.haml"
- - "ee/app/views/admin/audit_logs/index.html.haml"
- - "ee/app/views/admin/emails/show.html.haml"
- - "ee/app/views/admin/geo/projects/_registry_failed.html.haml"
- - "ee/app/views/admin/geo/projects/_registry_never.html.haml"
- - "ee/app/views/admin/licenses/_upload_trial_license.html.haml"
- - "ee/app/views/admin/licenses/new.html.haml"
- - "ee/app/views/admin/monitoring/ee/_nav.html.haml"
- - "ee/app/views/admin/projects/_shared_runner_status.html.haml"
- - "ee/app/views/admin/users/_auditor_access_level_radio.html.haml"
- - "ee/app/views/admin/users/_auditor_user_badge.html.haml"
- - "ee/app/views/admin/users/_limits.html.haml"
- - "ee/app/views/admin/users/_user_detail_note.html.haml"
- - "ee/app/views/dashboard/projects/_blank_state_ee_trial.html.haml"
- - "ee/app/views/errors/kerberos_denied.html.haml"
- - "ee/app/views/groups/ee/_settings_nav.html.haml"
- - "ee/app/views/groups/group_members/_ldap_sync.html.haml"
- - "ee/app/views/groups/group_members/_sync_button.html.haml"
- - "ee/app/views/groups/hooks/edit.html.haml"
- - "ee/app/views/groups/ldap_group_links/index.html.haml"
- - "ee/app/views/layouts/nav/ee/admin/_new_monitoring_sidebar.html.haml"
- - "ee/app/views/layouts/service_desk.html.haml"
- - "ee/app/views/ldap_group_links/_form.html.haml"
- - "ee/app/views/ldap_group_links/_ldap_group_link.html.haml"
- - "ee/app/views/ldap_group_links/_ldap_group_links.html.haml"
- - "ee/app/views/ldap_group_links/_ldap_group_links_show.html.haml"
- - "ee/app/views/ldap_group_links/_ldap_group_links_synchronizations.html.haml"
- - "ee/app/views/namespaces/_shared_runner_status.html.haml"
- - "ee/app/views/namespaces/_shared_runners_minutes_setting.html.haml"
- - "ee/app/views/namespaces/pipelines_quota/_extra_shared_runners_minutes_quota.html.haml"
- - "ee/app/views/namespaces/pipelines_quota/_list.haml"
- - "ee/app/views/notify/approved_merge_request_email.html.haml"
- - "ee/app/views/notify/epic_status_changed_email.html.haml"
- - "ee/app/views/notify/new_review_email.html.haml"
- - "ee/app/views/notify/send_admin_notification.html.haml"
- - "ee/app/views/notify/send_unsubscribed_notification.html.haml"
- - "ee/app/views/notify/unapproved_merge_request_email.html.haml"
- - "ee/app/views/oauth/geo_auth/error.html.haml"
- - "ee/app/views/projects/commits/_mirror_status.html.haml"
- - "ee/app/views/projects/merge_requests/_approvals_count.html.haml"
- - "ee/app/views/projects/merge_requests/widget/open/_geo.html.haml"
- - "ee/app/views/projects/mirrors/_mirrored_repositories_count.html.haml"
- - "ee/app/views/projects/protected_branches/_update_protected_branch.html.haml"
- - "ee/app/views/projects/protected_branches/ee/_create_protected_branch.html.haml"
- - "ee/app/views/projects/protected_branches/ee/_dropdown.html.haml"
- - "ee/app/views/projects/protected_tags/_protected_tag_extra_create_access_levels.haml"
- - "ee/app/views/projects/protected_tags/ee/_create_protected_tag.html.haml"
- - "ee/app/views/projects/push_rules/_index.html.haml"
- - "ee/app/views/projects/services/gitlab_slack_application/_help.html.haml"
- - "ee/app/views/projects/services/gitlab_slack_application/_slack_integration_form.html.haml"
- - "ee/app/views/projects/settings/slacks/edit.html.haml"
- - "ee/app/views/shared/_mirror_update_button.html.haml"
- - "ee/app/views/shared/epic/_search_bar.html.haml"
- - "ee/app/views/shared/issuable/_approvals.html.haml"
- - "ee/app/views/shared/issuable/_board_create_list_dropdown.html.haml"
- - "ee/app/views/shared/issuable/_filter_weight.html.haml"
- - "ee/app/views/shared/members/ee/_ldap_tag.html.haml"
- - "ee/app/views/shared/members/ee/_override_member_buttons.html.haml"
- - "ee/app/views/shared/members/ee/_sso_badge.html.haml"
- - "ee/app/views/shared/milestones/_burndown.html.haml"
- - "ee/app/views/shared/milestones/_weight.html.haml"
- - "ee/app/views/shared/promotions/_promote_issue_weights.html.haml"
- - "ee/app/views/shared/promotions/_promote_repository_features.html.haml"
- - "ee/app/views/shared/promotions/_promote_servicedesk.html.haml"
- - "ee/app/views/shared/push_rules/_form.html.haml"
- - "ee/app/views/unsubscribes/show.html.haml"
+ - 'app/views/clusters/clusters/_cluster.html.haml'
+ - 'app/views/clusters/clusters/new.html.haml'
+ - 'app/views/dashboard/milestones/index.html.haml'
+ - 'app/views/dashboard/projects/_blank_state_admin_welcome.html.haml'
+ - 'app/views/dashboard/projects/_blank_state_welcome.html.haml'
+ - 'app/views/dashboard/todos/_todo.html.haml'
+ - 'app/views/dashboard/todos/index.html.haml'
+ - 'app/views/devise/confirmations/almost_there.haml'
+ - 'app/views/devise/mailer/_confirmation_instructions_account.html.haml'
+ - 'app/views/devise/mailer/_confirmation_instructions_secondary.html.haml'
+ - 'app/views/devise/mailer/email_changed.html.haml'
+ - 'app/views/devise/mailer/password_change.html.haml'
+ - 'app/views/devise/mailer/reset_password_instructions.html.haml'
+ - 'app/views/devise/mailer/unlock_instructions.html.haml'
+ - 'app/views/devise/passwords/edit.html.haml'
+ - 'app/views/devise/sessions/_new_base.html.haml'
+ - 'app/views/devise/sessions/_new_crowd.html.haml'
+ - 'app/views/devise/sessions/_new_ldap.html.haml'
+ - 'app/views/devise/sessions/new.html.haml'
+ - 'app/views/devise/sessions/two_factor.html.haml'
+ - 'app/views/devise/shared/_omniauth_box.html.haml'
+ - 'app/views/devise/shared/_sign_in_link.html.haml'
+ - 'app/views/devise/shared/_tabs_normal.html.haml'
+ - 'app/views/discussions/_discussion.html.haml'
+ - 'app/views/discussions/_headline.html.haml'
+ - 'app/views/discussions/_notes.html.haml'
+ - 'app/views/doorkeeper/applications/_delete_form.html.haml'
+ - 'app/views/doorkeeper/authorized_applications/_delete_form.html.haml'
+ - 'app/views/errors/encoding.html.haml'
+ - 'app/views/errors/git_not_found.html.haml'
+ - 'app/views/errors/omniauth_error.html.haml'
+ - 'app/views/errors/precondition_failed.html.haml'
+ - 'app/views/events/_event_push.atom.haml'
+ - 'app/views/events/event/_push.html.haml'
+ - 'app/views/groups/_create_chat_team.html.haml'
+ - 'app/views/groups/_group_admin_settings.html.haml'
+ - 'app/views/groups/labels/edit.html.haml'
+ - 'app/views/groups/labels/new.html.haml'
+ - 'app/views/groups/milestones/edit.html.haml'
+ - 'app/views/groups/milestones/index.html.haml'
+ - 'app/views/groups/milestones/new.html.haml'
+ - 'app/views/groups/projects.html.haml'
+ - 'app/views/groups/runners/edit.html.haml'
+ - 'app/views/groups/settings/_advanced.html.haml'
+ - 'app/views/groups/settings/_lfs.html.haml'
+ - 'app/views/help/_shortcuts.html.haml'
+ - 'app/views/help/index.html.haml'
+ - 'app/views/help/instance_configuration.html.haml'
+ - 'app/views/help/instance_configuration/_gitlab_ci.html.haml'
+ - 'app/views/help/instance_configuration/_gitlab_pages.html.haml'
+ - 'app/views/import/bitbucket/status.html.haml'
+ - 'app/views/import/bitbucket_server/status.html.haml'
+ - 'app/views/invites/show.html.haml'
+ - 'app/views/jira_connect/subscriptions/index.html.haml'
+ - 'app/views/layouts/_mailer.html.haml'
+ - 'app/views/layouts/experiment_mailer.html.haml'
+ - 'app/views/layouts/header/_default.html.haml'
+ - 'app/views/layouts/header/_new_dropdown.haml'
+ - 'app/views/layouts/jira_connect.html.haml'
+ - 'app/views/layouts/notify.html.haml'
+ - 'app/views/notify/_failed_builds.html.haml'
+ - 'app/views/notify/_reassigned_issuable_email.html.haml'
+ - 'app/views/notify/_removal_notification.html.haml'
+ - 'app/views/notify/_successful_pipeline.html.haml'
+ - 'app/views/notify/autodevops_disabled_email.html.haml'
+ - 'app/views/notify/changed_milestone_email.html.haml'
+ - 'app/views/notify/import_issues_csv_email.html.haml'
+ - 'app/views/notify/issue_moved_email.html.haml'
+ - 'app/views/notify/member_access_denied_email.html.haml'
+ - 'app/views/notify/member_invite_accepted_email.html.haml'
+ - 'app/views/notify/member_invited_email.html.haml'
+ - 'app/views/notify/new_gpg_key_email.html.haml'
+ - 'app/views/notify/new_mention_in_issue_email.html.haml'
+ - 'app/views/notify/new_ssh_key_email.html.haml'
+ - 'app/views/notify/new_user_email.html.haml'
+ - 'app/views/notify/pages_domain_disabled_email.html.haml'
+ - 'app/views/notify/pages_domain_enabled_email.html.haml'
+ - 'app/views/notify/pages_domain_verification_failed_email.html.haml'
+ - 'app/views/notify/pages_domain_verification_succeeded_email.html.haml'
+ - 'app/views/notify/pipeline_failed_email.html.haml'
+ - 'app/views/notify/project_was_exported_email.html.haml'
+ - 'app/views/notify/project_was_moved_email.html.haml'
+ - 'app/views/notify/project_was_not_exported_email.html.haml'
+ - 'app/views/notify/push_to_merge_request_email.html.haml'
+ - 'app/views/notify/remote_mirror_update_failed_email.html.haml'
+ - 'app/views/notify/removed_milestone_issue_email.html.haml'
+ - 'app/views/notify/removed_milestone_merge_request_email.html.haml'
+ - 'app/views/notify/repository_push_email.html.haml'
+ - 'app/views/profiles/chat_names/_chat_name.html.haml'
+ - 'app/views/profiles/chat_names/index.html.haml'
+ - 'app/views/profiles/chat_names/new.html.haml'
+ - 'app/views/projects/_bitbucket_import_modal.html.haml'
+ - 'app/views/projects/_customize_workflow.html.haml'
+ - 'app/views/projects/_deletion_failed.html.haml'
+ - 'app/views/projects/_fork_suggestion.html.haml'
+ - 'app/views/projects/_gitlab_import_modal.html.haml'
+ - 'app/views/projects/_home_panel.html.haml'
+ - 'app/views/projects/_import_project_pane.html.haml'
+ - 'app/views/projects/_issuable_by_email.html.haml'
+ - 'app/views/projects/_readme.html.haml'
+ - 'app/views/projects/artifacts/_artifact.html.haml'
+ - 'app/views/projects/artifacts/_tree_file.html.haml'
+ - 'app/views/projects/artifacts/browse.html.haml'
+ - 'app/views/projects/blame/_age_map_legend.html.haml'
+ - 'app/views/projects/blame/show.html.haml'
+ - 'app/views/projects/blob/_editor.html.haml'
+ - 'app/views/projects/blob/_header_content.html.haml'
+ - 'app/views/projects/blob/_remove.html.haml'
+ - 'app/views/projects/blob/_render_error.html.haml'
+ - 'app/views/projects/blob/edit.html.haml'
+ - 'app/views/projects/blob/new.html.haml'
+ - 'app/views/projects/blob/preview.html.haml'
+ - 'app/views/projects/blob/viewers/_empty.html.haml'
+ - 'app/views/projects/blob/viewers/_stl.html.haml'
+ - 'app/views/projects/branches/_branch.html.haml'
+ - 'app/views/projects/branches/_delete_protected_modal.html.haml'
+ - 'app/views/projects/branches/new.html.haml'
+ - 'app/views/projects/ci/builds/_build.html.haml'
+ - 'app/views/projects/ci/lints/_create.html.haml'
+ - 'app/views/projects/compare/_form.html.haml'
+ - 'app/views/projects/compare/index.html.haml'
+ - 'app/views/projects/cycle_analytics/_empty_stage.html.haml'
+ - 'app/views/projects/cycle_analytics/_no_access.html.haml'
+ - 'app/views/projects/cycle_analytics/_overview.html.haml'
+ - 'app/views/projects/cycle_analytics/show.html.haml'
+ - 'app/views/projects/deploy_keys/_form.html.haml'
+ - 'app/views/projects/deploy_keys/_index.html.haml'
+ - 'app/views/projects/deploy_keys/edit.html.haml'
+ - 'app/views/projects/deployments/_deployment.html.haml'
+ - 'app/views/projects/diffs/_file_header.html.haml'
+ - 'app/views/projects/diffs/_replaced_image_diff.html.haml'
+ - 'app/views/projects/diffs/_stats.html.haml'
+ - 'app/views/projects/empty.html.haml'
+ - 'app/views/projects/generic_commit_statuses/_generic_commit_status.html.haml'
+ - 'app/views/projects/hook_logs/_index.html.haml'
+ - 'app/views/projects/hook_logs/show.html.haml'
+ - 'app/views/projects/hooks/edit.html.haml'
+ - 'app/views/projects/imports/new.html.haml'
+ - 'app/views/projects/imports/show.html.haml'
+ - 'app/views/projects/issues/_new_branch.html.haml'
+ - 'app/views/projects/issues/import_csv/_modal.html.haml'
+ - 'app/views/projects/issues/show.html.haml'
+ - 'app/views/projects/jobs/_header.html.haml'
+ - 'app/views/projects/jobs/_table.html.haml'
+ - 'app/views/projects/jobs/index.html.haml'
+ - 'app/views/projects/labels/edit.html.haml'
+ - 'app/views/projects/labels/new.html.haml'
+ - 'app/views/projects/mattermosts/_no_teams.html.haml'
+ - 'app/views/projects/mattermosts/_team_selection.html.haml'
+ - 'app/views/projects/mattermosts/new.html.haml'
+ - 'app/views/projects/merge_requests/_commits.html.haml'
+ - 'app/views/projects/merge_requests/_how_to_merge.html.haml'
+ - 'app/views/projects/merge_requests/_mr_title.html.haml'
+ - 'app/views/projects/merge_requests/conflicts/_commit_stats.html.haml'
+ - 'app/views/projects/merge_requests/conflicts/_file_actions.html.haml'
+ - 'app/views/projects/merge_requests/conflicts/_submit_form.html.haml'
+ - 'app/views/projects/merge_requests/conflicts/components/_diff_file_editor.html.haml'
+ - 'app/views/projects/merge_requests/conflicts/components/_inline_conflict_lines.html.haml'
+ - 'app/views/projects/merge_requests/conflicts/show.html.haml'
+ - 'app/views/projects/merge_requests/creations/_diffs.html.haml'
+ - 'app/views/projects/merge_requests/creations/_new_compare.html.haml'
+ - 'app/views/projects/merge_requests/creations/_new_submit.html.haml'
+ - 'app/views/projects/merge_requests/diffs/_different_base.html.haml'
+ - 'app/views/projects/merge_requests/diffs/_diffs.html.haml'
+ - 'app/views/projects/merge_requests/diffs/_version_controls.html.haml'
+ - 'app/views/projects/merge_requests/invalid.html.haml'
+ - 'app/views/projects/merge_requests/widget/open/_error.html.haml'
+ - 'app/views/projects/mirrors/_regenerate_public_ssh_key_confirm_modal.html.haml'
+ - 'app/views/projects/mirrors/_ssh_host_keys.html.haml'
+ - 'app/views/projects/no_repo.html.haml'
+ - 'app/views/projects/pipeline_schedules/_pipeline_schedule.html.haml'
+ - 'app/views/projects/pipelines/_info.html.haml'
+ - 'app/views/projects/protected_branches/shared/_dropdown.html.haml'
+ - 'app/views/projects/protected_branches/shared/_index.html.haml'
+ - 'app/views/projects/protected_branches/shared/_matching_branch.html.haml'
+ - 'app/views/projects/protected_branches/shared/_protected_branch.html.haml'
+ - 'app/views/projects/protected_branches/show.html.haml'
+ - 'app/views/projects/protected_tags/shared/_create_protected_tag.html.haml'
+ - 'app/views/projects/protected_tags/shared/_dropdown.html.haml'
+ - 'app/views/projects/protected_tags/shared/_index.html.haml'
+ - 'app/views/projects/protected_tags/shared/_matching_tag.html.haml'
+ - 'app/views/projects/protected_tags/shared/_protected_tag.html.haml'
+ - 'app/views/projects/protected_tags/shared/_tags_list.html.haml'
+ - 'app/views/projects/protected_tags/show.html.haml'
+ - 'app/views/projects/registry/repositories/_tag.html.haml'
+ - 'app/views/projects/repositories/_feed.html.haml'
+ - 'app/views/projects/runners/_shared_runners.html.haml'
+ - 'app/views/projects/runners/edit.html.haml'
+ - 'app/views/projects/services/mattermost_slash_commands/_detailed_help.html.haml'
+ - 'app/views/projects/services/mattermost_slash_commands/_help.html.haml'
+ - 'app/views/projects/services/prometheus/_metrics.html.haml'
+ - 'app/views/projects/services/slack_slash_commands/_help.html.haml'
+ - 'app/views/projects/settings/ci_cd/_badge.html.haml'
+ - 'app/views/projects/settings/ci_cd/_form.html.haml'
+ - 'app/views/projects/tags/index.html.haml'
+ - 'app/views/projects/tags/releases/edit.html.haml'
+ - 'app/views/projects/tree/_tree_row.html.haml'
+ - 'app/views/projects/tree/_truncated_notice_tree_row.html.haml'
+ - 'app/views/projects/triggers/_form.html.haml'
+ - 'app/views/projects/triggers/_index.html.haml'
+ - 'app/views/projects/triggers/_trigger.html.haml'
+ - 'app/views/projects/triggers/edit.html.haml'
+ - 'app/views/search/results/_issue.html.haml'
+ - 'app/views/search/results/_note.html.haml'
+ - 'app/views/search/results/_snippet_blob.html.haml'
+ - 'app/views/search/results/_snippet_title.html.haml'
+ - 'app/views/shared/_auto_devops_implicitly_enabled_banner.html.haml'
+ - 'app/views/shared/_commit_message_container.html.haml'
+ - 'app/views/shared/_delete_label_modal.html.haml'
+ - 'app/views/shared/_group_form.html.haml'
+ - 'app/views/shared/_group_tips.html.haml'
+ - 'app/views/shared/_md_preview.html.haml'
+ - 'app/views/shared/_milestone_expired.html.haml'
+ - 'app/views/shared/_no_password.html.haml'
+ - 'app/views/shared/_ping_consent.html.haml'
+ - 'app/views/shared/_project_limit.html.haml'
+ - 'app/views/shared/boards/components/_sidebar.html.haml'
+ - 'app/views/shared/boards/components/sidebar/_due_date.html.haml'
+ - 'app/views/shared/boards/components/sidebar/_labels.html.haml'
+ - 'app/views/shared/boards/components/sidebar/_milestone.html.haml'
+ - 'app/views/shared/hook_logs/_content.html.haml'
+ - 'app/views/shared/issuable/_assignees.html.haml'
+ - 'app/views/shared/issuable/_board_create_list_dropdown.html.haml'
+ - 'app/views/shared/issuable/_close_reopen_report_toggle.html.haml'
+ - 'app/views/shared/issuable/_form.html.haml'
+ - 'app/views/shared/issuable/_search_bar.html.haml'
+ - 'app/views/shared/issuable/_sidebar.html.haml'
+ - 'app/views/shared/issuable/form/_default_templates.html.haml'
+ - 'app/views/shared/issuable/form/_template_selector.html.haml'
+ - 'app/views/shared/issuable/form/_title.html.haml'
+ - 'app/views/shared/labels/_form.html.haml'
+ - 'app/views/shared/members/_member.html.haml'
+ - 'app/views/shared/milestones/_form_dates.html.haml'
+ - 'app/views/shared/milestones/_issuable.html.haml'
+ - 'app/views/shared/milestones/_milestone.html.haml'
+ - 'app/views/shared/milestones/_sidebar.html.haml'
+ - 'app/views/shared/milestones/_top.html.haml'
+ - 'app/views/shared/notes/_hints.html.haml'
+ - 'app/views/shared/notifications/_button.html.haml'
+ - 'app/views/shared/notifications/_new_button.html.haml'
+ - 'app/views/shared/runners/_runner_description.html.haml'
+ - 'app/views/shared/runners/show.html.haml'
+ - 'app/views/shared/snippets/_header.html.haml'
+ - 'app/views/shared/snippets/_snippet.html.haml'
+ - 'app/views/shared/web_hooks/_form.html.haml'
+ - 'app/views/shared/web_hooks/_hook.html.haml'
+ - 'app/views/shared/wikis/_pages_wiki_page.html.haml'
+ - 'app/views/users/_deletion_guidance.html.haml'
+ - 'ee/app/views/admin/_namespace_plan_info.html.haml'
+ - 'ee/app/views/admin/application_settings/_templates.html.haml'
+ - 'ee/app/views/admin/audit_logs/index.html.haml'
+ - 'ee/app/views/admin/emails/show.html.haml'
+ - 'ee/app/views/admin/geo/projects/_registry_failed.html.haml'
+ - 'ee/app/views/admin/geo/projects/_registry_never.html.haml'
+ - 'ee/app/views/admin/licenses/_upload_trial_license.html.haml'
+ - 'ee/app/views/admin/licenses/new.html.haml'
+ - 'ee/app/views/admin/monitoring/ee/_nav.html.haml'
+ - 'ee/app/views/admin/projects/_shared_runner_status.html.haml'
+ - 'ee/app/views/admin/users/_auditor_access_level_radio.html.haml'
+ - 'ee/app/views/admin/users/_auditor_user_badge.html.haml'
+ - 'ee/app/views/admin/users/_limits.html.haml'
+ - 'ee/app/views/admin/users/_user_detail_note.html.haml'
+ - 'ee/app/views/dashboard/projects/_blank_state_ee_trial.html.haml'
+ - 'ee/app/views/errors/kerberos_denied.html.haml'
+ - 'ee/app/views/groups/ee/_settings_nav.html.haml'
+ - 'ee/app/views/groups/group_members/_ldap_sync.html.haml'
+ - 'ee/app/views/groups/group_members/_sync_button.html.haml'
+ - 'ee/app/views/groups/hooks/edit.html.haml'
+ - 'ee/app/views/groups/ldap_group_links/index.html.haml'
+ - 'ee/app/views/layouts/nav/ee/admin/_new_monitoring_sidebar.html.haml'
+ - 'ee/app/views/layouts/service_desk.html.haml'
+ - 'ee/app/views/ldap_group_links/_form.html.haml'
+ - 'ee/app/views/ldap_group_links/_ldap_group_link.html.haml'
+ - 'ee/app/views/ldap_group_links/_ldap_group_links.html.haml'
+ - 'ee/app/views/ldap_group_links/_ldap_group_links_show.html.haml'
+ - 'ee/app/views/namespaces/_shared_runner_status.html.haml'
+ - 'ee/app/views/namespaces/_shared_runners_minutes_setting.html.haml'
+ - 'ee/app/views/namespaces/pipelines_quota/_extra_shared_runners_minutes_quota.html.haml'
+ - 'ee/app/views/namespaces/pipelines_quota/_list.haml'
+ - 'ee/app/views/notify/approved_merge_request_email.html.haml'
+ - 'ee/app/views/notify/epic_status_changed_email.html.haml'
+ - 'ee/app/views/notify/new_review_email.html.haml'
+ - 'ee/app/views/notify/send_admin_notification.html.haml'
+ - 'ee/app/views/notify/send_unsubscribed_notification.html.haml'
+ - 'ee/app/views/notify/unapproved_merge_request_email.html.haml'
+ - 'ee/app/views/oauth/geo_auth/error.html.haml'
+ - 'ee/app/views/projects/commits/_mirror_status.html.haml'
+ - 'ee/app/views/projects/merge_requests/_approvals_count.html.haml'
+ - 'ee/app/views/projects/merge_requests/widget/open/_geo.html.haml'
+ - 'ee/app/views/projects/mirrors/_mirrored_repositories_count.html.haml'
+ - 'ee/app/views/projects/protected_branches/_update_protected_branch.html.haml'
+ - 'ee/app/views/projects/protected_branches/ee/_create_protected_branch.html.haml'
+ - 'ee/app/views/projects/protected_branches/ee/_dropdown.html.haml'
+ - 'ee/app/views/projects/protected_tags/_protected_tag_extra_create_access_levels.haml'
+ - 'ee/app/views/projects/protected_tags/ee/_create_protected_tag.html.haml'
+ - 'ee/app/views/projects/push_rules/_index.html.haml'
+ - 'ee/app/views/projects/services/gitlab_slack_application/_help.html.haml'
+ - 'ee/app/views/projects/services/gitlab_slack_application/_slack_integration_form.html.haml'
+ - 'ee/app/views/projects/settings/slacks/edit.html.haml'
+ - 'ee/app/views/shared/_mirror_update_button.html.haml'
+ - 'ee/app/views/shared/epic/_search_bar.html.haml'
+ - 'ee/app/views/shared/issuable/_approvals.html.haml'
+ - 'ee/app/views/shared/issuable/_board_create_list_dropdown.html.haml'
+ - 'ee/app/views/shared/issuable/_filter_weight.html.haml'
+ - 'ee/app/views/shared/members/ee/_ldap_tag.html.haml'
+ - 'ee/app/views/shared/members/ee/_override_member_buttons.html.haml'
+ - 'ee/app/views/shared/members/ee/_sso_badge.html.haml'
+ - 'ee/app/views/shared/milestones/_burndown.html.haml'
+ - 'ee/app/views/shared/milestones/_weight.html.haml'
+ - 'ee/app/views/shared/promotions/_promote_issue_weights.html.haml'
+ - 'ee/app/views/shared/promotions/_promote_repository_features.html.haml'
+ - 'ee/app/views/shared/promotions/_promote_servicedesk.html.haml'
+ - 'ee/app/views/shared/push_rules/_form.html.haml'
+ - 'ee/app/views/unsubscribes/show.html.haml'
diff --git a/.rubocop.yml b/.rubocop.yml
index 47dc85a79f0..cc65727e94d 100644
--- a/.rubocop.yml
+++ b/.rubocop.yml
@@ -293,7 +293,15 @@ Gitlab/AvoidFeatureGet:
Enabled: true
RSpec/TimecopFreeze:
- Enabled: false
+ Enabled: true
+ AutoCorrect: true
+ Include:
+ - 'spec/**/*.rb'
+ - 'ee/spec/**/*.rb'
+ - 'qa/spec/**/*.rb'
+
+RSpec/TimecopTravel:
+ Enabled: true
AutoCorrect: true
Include:
- 'spec/**/*.rb'
@@ -327,7 +335,7 @@ Gitlab/Union:
- 'spec/**/*'
- 'ee/spec/**/*'
-API/GrapeAPIInstance:
+API/Base:
Enabled: true
Include:
- 'lib/**/api/**/*.rb'
@@ -354,6 +362,21 @@ Graphql/AuthorizeTypes:
- 'spec/**/*.rb'
- 'ee/spec/**/*.rb'
+Graphql/GIDExpectedType:
+ Enabled: true
+ Include:
+ - 'app/graphql/**/*'
+ - 'ee/app/graphql/**/*'
+ Exclude:
+ - 'spec/**/*.rb'
+ - 'ee/spec/**/*.rb'
+
+Graphql/IDType:
+ Enabled: true
+ Include:
+ - 'app/graphql/**/*'
+ - 'ee/app/graphql/**/*'
+
Graphql/JSONType:
Enabled: true
Include:
@@ -548,3 +571,9 @@ Gitlab/RailsLogger:
Exclude:
- 'spec/**/*.rb'
- 'ee/spec/**/*.rb'
+
+# WIP See https://gitlab.com/gitlab-org/gitlab/-/issues/267606
+FactoryBot/InlineAssociation:
+ Include:
+ - 'spec/factories/**/*.rb'
+ - 'ee/spec/factories/**/*.rb'
diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml
index 228fb7bd6ea..cf29b7cb1d1 100644
--- a/.rubocop_todo.yml
+++ b/.rubocop_todo.yml
@@ -105,14 +105,6 @@ Lint/StructNewOverride:
- 'app/serializers/environment_serializer.rb'
- 'lib/gitlab/ci/pipeline/duration.rb'
-# Offense count: 7
-Lint/UriEscapeUnescape:
- Exclude:
- - 'app/controllers/application_controller.rb'
- - 'app/models/project_services/drone_ci_service.rb'
- - 'spec/lib/google_api/auth_spec.rb'
- - 'spec/requests/api/files_spec.rb'
-
# Offense count: 65
# Cop supports --auto-correct.
Migration/DepartmentName:
@@ -162,8 +154,6 @@ Performance/Count:
- 'app/helpers/groups_helper.rb'
- 'app/services/merge_requests/add_context_service.rb'
- 'ee/lib/gitlab/graphql/aggregations/epics/epic_node.rb'
- - 'ee/spec/controllers/projects/feature_flags_controller_spec.rb'
- - 'ee/spec/requests/api/feature_flags_spec.rb'
- 'lib/gitlab/sidekiq_status.rb'
- 'spec/lib/gitlab/conflict/file_spec.rb'
- 'spec/lib/gitlab/git/tree_spec.rb'
@@ -175,8 +165,6 @@ Performance/Count:
Performance/Detect:
Exclude:
- 'ee/spec/controllers/projects/dependencies_controller_spec.rb'
- - 'ee/spec/controllers/projects/feature_flags_controller_spec.rb'
- - 'ee/spec/requests/api/unleash_spec.rb'
- 'spec/lib/gitlab/git/tree_spec.rb'
- 'spec/lib/gitlab/import_export/project/tree_restorer_spec.rb'
- 'spec/models/event_spec.rb'
@@ -195,6 +183,35 @@ RSpec/ContextWording:
RSpec/ExpectChange:
Enabled: false
+# Offense count: 47
+RSpec/ExpectGitlabTracking:
+ Exclude:
+ - 'ee/spec/controllers/groups/analytics/coverage_reports_controller_spec.rb'
+ - 'ee/spec/controllers/projects/settings/operations_controller_spec.rb'
+ - 'ee/spec/controllers/registrations_controller_spec.rb'
+ - 'ee/spec/requests/api/visual_review_discussions_spec.rb'
+ - 'ee/spec/services/epics/issue_promote_service_spec.rb'
+ - 'spec/controllers/groups/registry/repositories_controller_spec.rb'
+ - 'spec/controllers/groups_controller_spec.rb'
+ - 'spec/controllers/projects/registry/repositories_controller_spec.rb'
+ - 'spec/controllers/projects/registry/tags_controller_spec.rb'
+ - 'spec/controllers/projects/settings/operations_controller_spec.rb'
+ - 'spec/controllers/registrations_controller_spec.rb'
+ - 'spec/lib/api/helpers_spec.rb'
+ - 'spec/lib/gitlab/experimentation_spec.rb'
+ - 'spec/mailers/notify_spec.rb'
+ - 'spec/models/project_services/prometheus_service_spec.rb'
+ - 'spec/requests/api/project_container_repositories_spec.rb'
+ - 'spec/services/clusters/applications/check_installation_progress_service_spec.rb'
+ - 'spec/services/issues/zoom_link_service_spec.rb'
+ - 'spec/support/helpers/snowplow_helpers.rb'
+ - 'spec/support/shared_examples/controllers/trackable_shared_examples.rb'
+ - 'spec/support/shared_examples/requests/api/container_repositories_shared_examples.rb'
+ - 'spec/support/shared_examples/requests/api/discussions_shared_examples.rb'
+ - 'spec/support/shared_examples/requests/api/packages_shared_examples.rb'
+ - 'spec/support/shared_examples/requests/api/tracking_shared_examples.rb'
+ - 'spec/support/snowplow.rb'
+
# Offense count: 751
RSpec/ExpectInHook:
Enabled: false
@@ -700,13 +717,9 @@ Rails/SaveBang:
- 'ee/spec/models/application_setting_spec.rb'
- 'ee/spec/models/approval_merge_request_rule_spec.rb'
- 'ee/spec/models/approval_project_rule_spec.rb'
- - 'ee/spec/models/approval_state_spec.rb'
- 'ee/spec/models/burndown_spec.rb'
- 'ee/spec/models/ci/pipeline_spec.rb'
- 'ee/spec/models/ci/subscriptions/project_spec.rb'
- - 'ee/spec/models/concerns/approver_migrate_hook_spec.rb'
- - 'ee/spec/models/concerns/deprecated_approvals_before_merge_spec.rb'
- - 'ee/spec/models/concerns/elastic/note_spec.rb'
- 'ee/spec/models/ee/appearance_spec.rb'
- 'ee/spec/models/ee/ci/job_artifact_spec.rb'
- 'ee/spec/models/ee/protected_branch_spec.rb'
@@ -954,16 +967,12 @@ Rails/SaveBang:
- 'spec/lib/gitlab/ci/ansi2json/style_spec.rb'
- 'spec/lib/gitlab/ci/status/build/common_spec.rb'
- 'spec/lib/gitlab/cycle_analytics/base_event_fetcher_spec.rb'
- - 'spec/lib/gitlab/cycle_analytics/events_spec.rb'
- 'spec/lib/gitlab/database/custom_structure_spec.rb'
- 'spec/lib/gitlab/database/partitioning_migration_helpers/table_management_helpers_spec.rb'
- 'spec/lib/gitlab/database_importers/self_monitoring/project/create_service_spec.rb'
- 'spec/lib/gitlab/email/handler/create_note_handler_spec.rb'
- 'spec/lib/gitlab/email/handler/unsubscribe_handler_spec.rb'
- 'spec/lib/gitlab/gfm/reference_rewriter_spec.rb'
- - 'spec/lib/gitlab/git/object_pool_spec.rb'
- - 'spec/lib/gitlab/git/remote_mirror_spec.rb'
- - 'spec/lib/gitlab/git/repository_spec.rb'
- 'spec/lib/gitlab/git_access_spec.rb'
- 'spec/lib/gitlab/gitaly_client/object_pool_service_spec.rb'
- 'spec/lib/gitlab/gitaly_client/repository_service_spec.rb'
@@ -1042,18 +1051,6 @@ Rails/SaveBang:
- 'spec/models/clusters/applications/helm_spec.rb'
- 'spec/models/commit_spec.rb'
- 'spec/models/commit_status_spec.rb'
- - 'spec/models/concerns/avatarable_spec.rb'
- - 'spec/models/concerns/bulk_insertable_associations_spec.rb'
- - 'spec/models/concerns/cache_markdown_field_spec.rb'
- - 'spec/models/concerns/case_sensitivity_spec.rb'
- - 'spec/models/concerns/featurable_spec.rb'
- - 'spec/models/concerns/issuable_spec.rb'
- - 'spec/models/concerns/mentionable_spec.rb'
- - 'spec/models/concerns/milestoneable_spec.rb'
- - 'spec/models/concerns/milestoneish_spec.rb'
- - 'spec/models/concerns/routable_spec.rb'
- - 'spec/models/concerns/subscribable_spec.rb'
- - 'spec/models/concerns/token_authenticatable_spec.rb'
- 'spec/models/container_repository_spec.rb'
- 'spec/models/deploy_keys_project_spec.rb'
- 'spec/models/deploy_token_spec.rb'
@@ -1085,7 +1082,6 @@ Rails/SaveBang:
- 'spec/models/note_spec.rb'
- 'spec/models/notification_setting_spec.rb'
- 'spec/models/operations/feature_flag_scope_spec.rb'
- - 'spec/models/operations/feature_flag_spec.rb'
- 'spec/models/operations/feature_flags/strategy_spec.rb'
- 'spec/models/operations/feature_flags/user_list_spec.rb'
- 'spec/models/pages_domain_spec.rb'
@@ -1140,31 +1136,11 @@ Rails/SaveBang:
- 'spec/services/emails/confirm_service_spec.rb'
- 'spec/services/groups/destroy_service_spec.rb'
- 'spec/services/groups/import_export/import_service_spec.rb'
- - 'spec/services/issuable/bulk_update_service_spec.rb'
- - 'spec/services/issuable/clone/attributes_rewriter_spec.rb'
- - 'spec/services/issuable/common_system_notes_service_spec.rb'
- 'spec/services/labels/promote_service_spec.rb'
- - 'spec/services/milestones/destroy_service_spec.rb'
- - 'spec/services/milestones/promote_service_spec.rb'
- - 'spec/services/milestones/transfer_service_spec.rb'
- 'spec/services/notes/create_service_spec.rb'
- 'spec/services/notification_recipients/build_service_spec.rb'
- 'spec/services/notification_service_spec.rb'
- 'spec/services/packages/conan/create_package_file_service_spec.rb'
- - 'spec/services/projects/after_rename_service_spec.rb'
- - 'spec/services/projects/autocomplete_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/hashed_storage/base_attachment_service_spec.rb'
- - 'spec/services/projects/move_access_service_spec.rb'
- - 'spec/services/projects/move_project_group_links_service_spec.rb'
- - 'spec/services/projects/overwrite_project_service_spec.rb'
- - 'spec/services/projects/propagate_service_template_spec.rb'
- - 'spec/services/projects/unlink_fork_service_spec.rb'
- - 'spec/services/projects/update_pages_service_spec.rb'
- - 'spec/services/projects/update_service_spec.rb'
- - 'spec/services/quick_actions/interpret_service_spec.rb'
- 'spec/services/reset_project_cache_service_spec.rb'
- 'spec/services/resource_events/change_milestone_service_spec.rb'
- 'spec/services/system_hooks_service_spec.rb'
@@ -1176,20 +1152,188 @@ Rails/SaveBang:
- 'spec/services/users/repair_ldap_blocked_service_spec.rb'
- 'spec/services/verify_pages_domain_service_spec.rb'
- 'spec/sidekiq/cron/job_gem_dependency_spec.rb'
- - 'spec/support/migrations_helpers/cluster_helpers.rb'
- - 'spec/support/migrations_helpers/namespaces_helper.rb'
- - 'spec/support/shared_contexts/email_shared_context.rb'
- - 'spec/support/shared_contexts/finders/group_projects_finder_shared_contexts.rb'
- - 'spec/support/shared_contexts/mailers/notify_shared_context.rb'
- - 'spec/support/shared_examples/controllers/cache_control_shared_examples.rb'
- - 'spec/support/shared_examples/controllers/githubish_import_controller_shared_examples.rb'
- - 'spec/support/shared_examples/controllers/sessionless_auth_controller_shared_examples.rb'
- - 'spec/support/shared_examples/features/editable_merge_request_shared_examples.rb'
- - 'spec/support/shared_examples/lib/gitlab/ci/ci_trace_shared_examples.rb'
- - 'spec/support/shared_examples/policies/project_policy_shared_examples.rb'
- - 'spec/support/shared_examples/quick_actions/issuable/issuable_quick_actions_shared_examples.rb'
- - 'spec/support/shared_examples/quick_actions/merge_request/merge_quick_action_shared_examples.rb'
- - 'spec/support/shared_examples/serializers/note_entity_shared_examples.rb'
- - 'spec/tasks/gitlab/web_hook_rake_spec.rb'
- - 'spec/uploaders/file_uploader_spec.rb'
- - 'spec/uploaders/object_storage_spec.rb'
+
+# Offense count: 187
+# Cop supports --auto-correct.
+RSpec/TimecopFreeze:
+ Exclude:
+ - 'ee/spec/controllers/admin/application_settings_controller_spec.rb'
+ - 'ee/spec/controllers/projects/security/network_policies_controller_spec.rb'
+ - 'ee/spec/features/admin/admin_reset_pipeline_minutes_spec.rb'
+ - 'ee/spec/features/boards/sidebar_spec.rb'
+ - 'ee/spec/features/groups/analytics/cycle_analytics/filters_and_data_spec.rb'
+ - 'ee/spec/features/groups/iteration_spec.rb'
+ - 'ee/spec/features/projects/mirror_spec.rb'
+ - 'ee/spec/features/projects/services/prometheus_custom_metrics_spec.rb'
+ - 'ee/spec/finders/productivity_analytics_finder_spec.rb'
+ - 'ee/spec/frontend/fixtures/analytics.rb'
+ - 'ee/spec/helpers/vulnerabilities_helper_spec.rb'
+ - 'ee/spec/lib/analytics/merge_request_metrics_refresh_spec.rb'
+ - 'ee/spec/lib/analytics/productivity_analytics_request_params_spec.rb'
+ - 'ee/spec/lib/ee/gitlab/background_migration/populate_vulnerability_historical_statistics_spec.rb'
+ - 'ee/spec/lib/gitlab/analytics/cycle_analytics/data_collector_spec.rb'
+ - 'ee/spec/lib/gitlab/analytics/cycle_analytics/group_stage_time_summary_spec.rb'
+ - 'ee/spec/lib/gitlab/analytics/cycle_analytics/summary/group/stage_time_summary_spec.rb'
+ - 'ee/spec/lib/gitlab/analytics/type_of_work/tasks_by_type_spec.rb'
+ - 'ee/spec/lib/gitlab/auth/group_saml/sso_enforcer_spec.rb'
+ - 'ee/spec/lib/gitlab/database/load_balancing/host_spec.rb'
+ - 'ee/spec/lib/gitlab/geo/base_request_spec.rb'
+ - 'ee/spec/lib/gitlab/geo/event_gap_tracking_spec.rb'
+ - 'ee/spec/lib/gitlab/geo/git_push_http_spec.rb'
+ - 'ee/spec/lib/gitlab/geo/log_cursor/daemon_spec.rb'
+ - 'ee/spec/lib/gitlab/geo/log_cursor/events/repository_updated_event_spec.rb'
+ - 'ee/spec/lib/gitlab/geo/oauth/login_state_spec.rb'
+ - 'ee/spec/lib/gitlab/insights/reducers/count_per_period_reducer_spec.rb'
+ - 'ee/spec/lib/gitlab/prometheus/queries/additional_metrics_environment_query_spec.rb'
+ - 'ee/spec/lib/gitlab/prometheus/queries/cluster_query_spec.rb'
+ - 'ee/spec/migrations/populate_vulnerability_historical_statistics_for_year_spec.rb'
+ - 'ee/spec/migrations/remove_duplicated_cs_findings_spec.rb'
+ - 'ee/spec/migrations/remove_duplicated_cs_findings_without_vulnerability_id_spec.rb'
+ - 'ee/spec/migrations/schedule_fix_orphan_promoted_issues_spec.rb'
+ - 'ee/spec/migrations/schedule_merge_request_any_approval_rule_migration_spec.rb'
+ - 'ee/spec/migrations/schedule_populate_resolved_on_default_branch_column_spec.rb'
+ - 'ee/spec/migrations/schedule_populate_vulnerability_historical_statistics_spec.rb'
+ - 'ee/spec/migrations/schedule_project_any_approval_rule_migration_spec.rb'
+ - 'ee/spec/migrations/set_resolved_state_on_vulnerabilities_spec.rb'
+ - 'ee/spec/migrations/20190926180443_schedule_epic_issues_after_epics_move_spec.rb'
+ - 'ee/spec/models/analytics/cycle_analytics/group_level_spec.rb'
+ - 'ee/spec/models/burndown_spec.rb'
+ - 'ee/spec/models/ee/namespace_spec.rb'
+ - 'ee/spec/models/geo/project_registry_spec.rb'
+ - 'ee/spec/models/merge_train_spec.rb'
+ - 'ee/spec/models/productivity_analytics_spec.rb'
+ - 'ee/spec/models/project_spec.rb'
+ - 'ee/spec/models/vulnerabilities/export_spec.rb'
+ - 'ee/spec/requests/api/vulnerabilities_spec.rb'
+ - 'ee/spec/services/geo/file_download_service_spec.rb'
+ - 'ee/spec/services/vulnerabilities/confirm_service_spec.rb'
+ - 'ee/spec/services/vulnerabilities/dismiss_service_spec.rb'
+ - 'ee/spec/services/vulnerabilities/resolve_service_spec.rb'
+ - 'ee/spec/services/vulnerabilities/revert_to_detected_service_spec.rb'
+ - 'ee/spec/services/vulnerability_exports/export_service_spec.rb'
+ - 'ee/spec/support/shared_contexts/lib/gitlab/insights/reducers/reducers_shared_contexts.rb'
+ - 'qa/spec/support/repeater_spec.rb'
+ - 'spec/features/profiles/active_sessions_spec.rb'
+ - 'spec/features/projects/environments/environment_metrics_spec.rb'
+ - 'spec/features/users/active_sessions_spec.rb'
+ - 'spec/lib/atlassian/jira_connect/client_spec.rb'
+ - 'spec/lib/gitlab/analytics/cycle_analytics/base_query_builder_spec.rb'
+ - 'spec/lib/gitlab/analytics/cycle_analytics/median_spec.rb'
+ - 'spec/lib/gitlab/analytics/cycle_analytics/records_fetcher_spec.rb'
+ - 'spec/lib/gitlab/anonymous_session_spec.rb'
+ - 'spec/lib/gitlab/auth/unique_ips_limiter_spec.rb'
+ - 'spec/lib/gitlab/checks/timed_logger_spec.rb'
+ - 'spec/lib/gitlab/cycle_analytics/stage_summary_spec.rb'
+ - 'spec/lib/gitlab/cycle_analytics/usage_data_spec.rb'
+ - 'spec/lib/gitlab/instrumentation_helper_spec.rb'
+ - 'spec/lib/gitlab/omniauth_logging/json_formatter_spec.rb'
+ - 'spec/lib/gitlab/puma_logging/json_formatter_spec.rb'
+ - 'spec/lib/gitlab/sidekiq_logging/structured_logger_spec.rb'
+ - 'spec/lib/json_web_token/hmac_token_spec.rb'
+ - 'spec/lib/rspec_flaky/flaky_example_spec.rb'
+ - 'spec/lib/rspec_flaky/listener_spec.rb'
+ - 'spec/models/active_session_spec.rb'
+ - 'spec/models/container_repository_spec.rb'
+ - 'spec/models/pages/lookup_path_spec.rb'
+ - 'spec/models/project_feature_usage_spec.rb'
+ - 'spec/requests/api/v3/github_spec.rb'
+ - 'spec/serializers/entity_date_helper_spec.rb'
+ - 'spec/support/cycle_analytics_helpers/test_generation.rb'
+ - 'spec/support/helpers/cycle_analytics_helpers.rb'
+ - 'spec/support/helpers/javascript_fixtures_helpers.rb'
+ - 'spec/support/shared_contexts/rack_attack_shared_context.rb'
+ - 'spec/support/shared_examples/workers/concerns/reenqueuer_shared_examples.rb'
+ - 'spec/workers/concerns/reenqueuer_spec.rb'
+ - 'spec/workers/metrics/dashboard/prune_old_annotations_worker_spec.rb'
+
+# Offense count: 54
+# Cop supports --auto-correct.
+RSpec/TimecopTravel:
+ Exclude:
+ - 'ee/spec/lib/gitlab/geo/event_gap_tracking_spec.rb'
+ - 'ee/spec/lib/gitlab/geo/git_push_http_spec.rb'
+ - 'ee/spec/lib/gitlab/geo/jwt_request_decoder_spec.rb'
+ - 'ee/spec/lib/gitlab/geo/log_cursor/daemon_spec.rb'
+ - 'ee/spec/models/broadcast_message_spec.rb'
+ - 'ee/spec/models/burndown_spec.rb'
+ - 'qa/spec/support/repeater_spec.rb'
+ - 'spec/features/users/terms_spec.rb'
+ - 'spec/lib/feature_spec.rb'
+ - 'spec/models/broadcast_message_spec.rb'
+ - 'spec/models/concerns/issuable_spec.rb'
+ - 'spec/requests/api/ci/runner/jobs_trace_spec.rb'
+ - 'spec/requests/api/issues/put_projects_issues_spec.rb'
+ - 'spec/support/shared_contexts/cache_allowed_users_in_namespace_shared_context.rb'
+ - 'spec/support/shared_examples/requests/api/time_tracking_shared_examples.rb'
+ - 'spec/support/shared_examples/workers/concerns/reenqueuer_shared_examples.rb'
+ - 'spec/workers/concerns/reenqueuer_spec.rb'
+ - 'spec/lib/gitlab/analytics/cycle_analytics/median_spec.rb'
+
+# Offense count: 43
+Graphql/IDType:
+ Exclude:
+ - 'ee/app/graphql/ee/mutations/issues/update.rb'
+ - 'ee/app/graphql/ee/types/boards/board_issue_input_base_type.rb'
+ - 'ee/app/graphql/mutations/issues/set_epic.rb'
+ - 'ee/app/graphql/mutations/iterations/update.rb'
+ - 'ee/app/graphql/resolvers/iterations_resolver.rb'
+ - 'app/graphql/mutations/boards/create.rb'
+ - 'app/graphql/mutations/boards/issues/issue_move_list.rb'
+ - 'app/graphql/mutations/boards/lists/update.rb'
+ - 'app/graphql/mutations/issues/update.rb'
+ - 'app/graphql/mutations/metrics/dashboard/annotations/delete.rb'
+ - 'app/graphql/mutations/snippets/destroy.rb'
+ - 'app/graphql/mutations/snippets/mark_as_spam.rb'
+ - 'app/graphql/mutations/snippets/update.rb'
+ - 'app/graphql/resolvers/board_lists_resolver.rb'
+ - 'app/graphql/resolvers/boards_resolver.rb'
+ - 'app/graphql/resolvers/design_management/design_at_version_resolver.rb'
+ - 'app/graphql/resolvers/design_management/design_resolver.rb'
+ - 'app/graphql/resolvers/design_management/designs_resolver.rb'
+ - 'app/graphql/resolvers/design_management/version/design_at_version_resolver.rb'
+ - 'app/graphql/resolvers/design_management/version_in_collection_resolver.rb'
+ - 'app/graphql/resolvers/design_management/version_resolver.rb'
+ - 'app/graphql/resolvers/design_management/versions_resolver.rb'
+ - 'app/graphql/resolvers/error_tracking/sentry_detailed_error_resolver.rb'
+ - 'app/graphql/resolvers/error_tracking/sentry_error_stack_trace_resolver.rb'
+ - 'app/graphql/resolvers/snippets_resolver.rb'
+ - 'app/graphql/resolvers/user_merge_requests_resolver.rb'
+ - 'app/graphql/resolvers/user_resolver.rb'
+
+# Offense count: 86
+# Cop supports --auto-correct.
+FactoryBot/InlineAssociation:
+ Exclude:
+ - 'ee/spec/factories/analytics/cycle_analytics/group_stages.rb'
+ - 'ee/spec/factories/geo/event_log.rb'
+ - 'ee/spec/factories/groups.rb'
+ - 'ee/spec/factories/merge_request_blocks.rb'
+ - 'ee/spec/factories/resource_iteration_event.rb'
+ - 'ee/spec/factories/resource_weight_events.rb'
+ - 'ee/spec/factories/vulnerabilities/feedback.rb'
+ - 'spec/factories/atlassian_identities.rb'
+ - 'spec/factories/audit_events.rb'
+ - 'spec/factories/design_management/design_at_version.rb'
+ - 'spec/factories/design_management/designs.rb'
+ - 'spec/factories/design_management/versions.rb'
+ - 'spec/factories/events.rb'
+ - 'spec/factories/git_wiki_commit_details.rb'
+ - 'spec/factories/gitaly/commit.rb'
+ - 'spec/factories/go_module_commits.rb'
+ - 'spec/factories/go_module_versions.rb'
+ - 'spec/factories/go_modules.rb'
+ - 'spec/factories/group_group_links.rb'
+ - 'spec/factories/import_export_uploads.rb'
+ - 'spec/factories/merge_requests.rb'
+ - 'spec/factories/notes.rb'
+ - 'spec/factories/packages.rb'
+ - 'spec/factories/packages/package_file.rb'
+ - 'spec/factories/resource_label_events.rb'
+ - 'spec/factories/resource_milestone_event.rb'
+ - 'spec/factories/resource_state_event.rb'
+ - 'spec/factories/sent_notifications.rb'
+ - 'spec/factories/serverless/domain.rb'
+ - 'spec/factories/serverless/domain_cluster.rb'
+ - 'spec/factories/terraform/state.rb'
+ - 'spec/factories/uploads.rb'
+ - 'spec/factories/wiki_pages.rb'
diff --git a/.test_license_encryption_key.pub b/.test_license_encryption_key.pub
new file mode 100644
index 00000000000..d3936e5e07e
--- /dev/null
+++ b/.test_license_encryption_key.pub
@@ -0,0 +1,9 @@
+-----BEGIN PUBLIC KEY-----
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtgemxR8RUJXi3p7G/dkh
+Yuln1L4lA6GtQsT83X0yTVDbLVsI2C6bepsRjGiLV0R/9JGvTojORx+9F/ZQAiEC
+g6QXWasAOSmrzr4EjADG6cWcCnOju8hX9yib1HUIBxl+jHkmXP3NPuwyb8p2G149
+EG1o4apEqE5RtqV/Xyx/u57xTYYZShJ/c7o4iA8xvt6IAKFPFKpQwb5hv4KvUZBP
+h0xG2qvOjDu430fK8JclPlXHqPjXDkXOZyLd4FvRStdEQU3RVXvUQfuGt/tOMS7J
+nPQ94fr/xdaEbcEtIlr32+tcgsMWyhqtDCPUWJT1aRPviUgaJKLoVs8tRKwYMV9+
+1wIDAQAB
+-----END PUBLIC KEY-----
diff --git a/.theia/settings.json b/.theia/settings.json
new file mode 100644
index 00000000000..8ad32b373f4
--- /dev/null
+++ b/.theia/settings.json
@@ -0,0 +1,11 @@
+{
+ "ruby.codeCompletion": "rcodetools",
+ "ruby.format": "standard",
+ "ruby.intellisense": "rubyLocate",
+ "ruby.useBundler": true,
+ "ruby.useLanguageServer": true,
+ "ruby.lint": {
+ "rubocop": true,
+ "useBundler": true
+ }
+}
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7d8186407f5..44e2be627ae 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -23,42 +23,6 @@ entry.
- Fix large backups not working with Azure Blob storage. !44233
-## 13.4.2 (2020-10-01)
-
-### Security (14 changes)
-
-- Do not store session id in Redis.
-- Fix permission checks when updating confidentiality and milestone on issues or merge requests.
-- Purge unaccepted member invitations older than 90 days.
-- Adds feature flags plan limits.
-- Prevent SVG XSS via Web IDE.
-- Ensure user has no solo owned groups before triggering account deletion.
-- Security fix safe params helper.
-- Do not bypass admin mode when authenticated with deploy token.
-- Fixes release asset link filepath ReDoS.
-- Ensure global ID is of Annotation type in GraphQL destroy mutation.
-- Validate that membership expiry dates are not in the past.
-- Rate limit adding new email and re-sending email confirmation.
-- Fix redaction of confidential Todos.
-- Update GitLab Runner Helm Chart to 0.20.2.
-
-
-## 13.4.1 (2020-09-24)
-
-### Fixed (2 changes)
-
-- Revert required encryption on CI runner tokens. !42623
-- Allow Unleash clients to request feature flags when repository is private. !43059
-
-### Added (1 change)
-
-- Add missing fontawesome file icon classes. !43091
-
-### Other (1 change)
-
-- Notifications icon: Render empty string for custom setting. !42848
-
-
## 13.4.0 (2020-09-22)
### Security (2 changes, 1 of them is from the community)
@@ -1283,6 +1247,26 @@ entry.
- Replace fa-pencil icon with GitLab SVG. !39648
+## 13.2.10 (2020-10-01)
+
+### Security (14 changes)
+
+- Do not store session id in Redis.
+- Fix permission checks when updating confidentiality and milestone on issues or merge requests.
+- Purge unaccepted member invitations older than 90 days.
+- Adds feature flags plan limits.
+- Prevent SVG XSS via Web IDE.
+- Ensure user has no solo owned groups before triggering account deletion.
+- Security fix safe params helper.
+- Do not bypass admin mode when authenticated with deploy token.
+- Fixes release asset link filepath ReDoS.
+- Ensure global ID is of Annotation type in GraphQL destroy mutation.
+- Validate that membership expiry dates are not in the past.
+- Rate limit adding new email and re-sending email confirmation.
+- Fix redaction of confidential Todos.
+- Update GitLab Runner Helm Chart to 0.19.4.
+
+
## 13.2.8 (2020-09-02)
### Security (1 change)
diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION
index 24a9ec7aa95..6ebe641f7d7 100644
--- a/GITALY_SERVER_VERSION
+++ b/GITALY_SERVER_VERSION
@@ -1 +1 @@
-13.4.4 \ No newline at end of file
+60aaf7cdd17b4efdf4dab23eb83aa86fe596a55b
diff --git a/GITLAB_KAS_VERSION b/GITLAB_KAS_VERSION
index bbdeab6222c..1750564f270 100644
--- a/GITLAB_KAS_VERSION
+++ b/GITLAB_KAS_VERSION
@@ -1 +1 @@
-0.0.5
+0.0.6
diff --git a/GITLAB_PAGES_VERSION b/GITLAB_PAGES_VERSION
index ad2191947f7..cfc730712d5 100644
--- a/GITLAB_PAGES_VERSION
+++ b/GITLAB_PAGES_VERSION
@@ -1 +1 @@
-1.25.0
+1.28.0
diff --git a/GITLAB_SHELL_VERSION b/GITLAB_SHELL_VERSION
index d6ef99820ff..c554e7e8652 100644
--- a/GITLAB_SHELL_VERSION
+++ b/GITLAB_SHELL_VERSION
@@ -1 +1 @@
-13.7.0
+13.10.0
diff --git a/GITLAB_WORKHORSE_VERSION b/GITLAB_WORKHORSE_VERSION
index f850905cea7..f66efe38785 100644
--- a/GITLAB_WORKHORSE_VERSION
+++ b/GITLAB_WORKHORSE_VERSION
@@ -1 +1 @@
-8.46.0
+8.51.0
diff --git a/Gemfile b/Gemfile
index 0e28aa7a2d4..51f9d36cef9 100644
--- a/Gemfile
+++ b/Gemfile
@@ -19,13 +19,15 @@ gem 'default_value_for', '~> 3.3.0'
gem 'pg', '~> 1.1'
gem 'rugged', '~> 0.28'
-gem 'grape-path-helpers', '~> 1.3'
+gem 'grape-path-helpers', '~> 1.4'
gem 'faraday', '~> 1.0'
gem 'marginalia', '~> 1.9.0'
# Authentication libraries
-gem 'devise', '~> 4.6'
+gem 'devise', '~> 4.7.2'
+# TODO: verify ARM compile issue on 3.1.13+ version (see https://gitlab.com/gitlab-org/gitlab/-/merge_requests/18828)
+gem 'bcrypt', '3.1.12'
gem 'doorkeeper', '~> 5.3.0'
gem 'doorkeeper-openid_connect', '~> 1.7.4'
gem 'omniauth', '~> 1.8'
@@ -97,6 +99,7 @@ gem 'graphiql-rails', '~> 1.4.10'
gem 'apollo_upload_server', '~> 2.0.2'
gem 'graphql-docs', '~> 1.6.0', group: [:development, :test]
+gem 'hashie'
# Disable strong_params so that Mash does not respond to :permitted?
gem 'hashie-forbidden_attributes'
@@ -108,7 +111,7 @@ gem 'hamlit', '~> 2.11.0'
# Files attachments
gem 'carrierwave', '~> 1.3'
-gem 'mini_magick'
+gem 'mini_magick', '~> 4.10.1'
# for backups
gem 'fog-aws', '~> 3.5'
@@ -155,7 +158,7 @@ gem 'wikicloth', '0.8.1'
gem 'asciidoctor', '~> 2.0.10'
gem 'asciidoctor-include-ext', '~> 0.3.1', require: false
gem 'asciidoctor-plantuml', '~> 0.0.12'
-gem 'rouge', '~> 3.21.0'
+gem 'rouge', '~> 3.24.0'
gem 'truncato', '~> 0.7.11'
gem 'bootstrap_form', '~> 4.2.0'
gem 'nokogiri', '~> 1.10.9'
@@ -169,7 +172,7 @@ gem 'diffy', '~> 3.3'
gem 'diff_match_patch', '~> 0.1.0'
# Application server
-gem 'rack', '~> 2.0.9'
+gem 'rack', '~> 2.1.4'
# https://github.com/sharpstone/rack-timeout/blob/master/README.md#rails-apps-manually
gem 'rack-timeout', '~> 0.5.1', require: 'rack/timeout/base'
@@ -244,7 +247,7 @@ gem 'atlassian-jwt', '~> 0.2.0'
gem 'flowdock', '~> 0.7'
# Slack integration
-gem 'slack-messenger', '~> 2.3.3'
+gem 'slack-messenger', '~> 2.3.4'
# Hangouts Chat integration
gem 'hangouts-chat', '~> 0.0.5'
@@ -256,7 +259,7 @@ gem 'asana', '0.10.2'
gem 'ruby-fogbugz', '~> 0.2.1'
# Kubernetes integration
-gem 'kubeclient', '~> 4.6.0'
+gem 'kubeclient', '~> 4.9.1'
# Sanitize user input
gem 'sanitize', '~> 5.2.1'
@@ -272,7 +275,7 @@ gem 'licensee', '~> 8.9'
gem 'ace-rails-ap', '~> 4.1.0'
# Detect and convert string character encoding
-gem 'charlock_holmes', '~> 0.7.5'
+gem 'charlock_holmes', '~> 0.7.7'
# Detect mime content type from content
gem 'mimemagic', '~> 0.3.2'
@@ -284,11 +287,10 @@ gem 'fast_blank'
gem 'gitlab-chronic', '~> 0.10.5'
gem 'gitlab_chronic_duration', '~> 0.10.6.2'
-gem 'webpack-rails', '~> 0.9.10'
gem 'rack-proxy', '~> 0.6.0'
gem 'sassc-rails', '~> 2.1.0'
-gem 'uglifier', '~> 2.7.2'
+gem 'terser', '1.0.2'
gem 'addressable', '~> 2.7'
gem 'font-awesome-rails', '~> 4.7'
@@ -308,7 +310,7 @@ gem 'sentry-raven', '~> 3.0'
gem 'premailer-rails', '~> 1.10.3'
# LabKit: Tracing and Correlation
-gem 'gitlab-labkit', '0.12.1'
+gem 'gitlab-labkit', '0.12.2'
# I18n
gem 'ruby_parser', '~> 3.8', require: false
@@ -330,13 +332,13 @@ group :metrics do
gem 'method_source', '~> 1.0', require: false
# Prometheus
- gem 'prometheus-client-mmap', '~> 0.11.0'
+ gem 'prometheus-client-mmap', '~> 0.12.0'
gem 'raindrops', '~> 0.18'
end
group :development do
gem 'brakeman', '~> 4.2', require: false
- gem 'danger', '~> 8.0', require: false
+ gem 'danger', '~> 8.0.6', require: false
gem 'letter_opener_web', '~> 1.3.4'
@@ -375,8 +377,6 @@ group :development, :test do
gem 'scss_lint', '~> 0.56.0', require: false
gem 'haml_lint', '~> 0.34.0', require: false
- gem 'simplecov', '~> 0.18.5', require: false
- gem 'simplecov-cobertura', '~> 1.3.1', require: false
gem 'bundler-audit', '~> 0.6.1', require: false
gem 'benchmark-ips', '~> 2.3.0', require: false
@@ -394,9 +394,14 @@ group :development, :test do
gem 'rblineprof', '~> 0.3.6', platform: :mri, require: false
end
+group :development, :test, :coverage do
+ gem 'simplecov', '~> 0.18.5', require: false
+ gem 'simplecov-cobertura', '~> 1.3.1', require: false
+end
+
# Gems required in omnibus-gitlab pipeline
group :development, :test, :omnibus do
- gem 'license_finder', '~> 5.4', require: false
+ gem 'license_finder', '~> 6.0', require: false
end
group :test do
@@ -411,7 +416,7 @@ group :test do
gem 'shoulda-matchers', '~> 4.0.1', require: false
gem 'email_spec', '~> 2.2.0'
- gem 'webmock', '~> 3.5.1'
+ gem 'webmock', '~> 3.9.1'
gem 'rails-controller-testing'
gem 'concurrent-ruby', '~> 1.1'
gem 'test-prof', '~> 0.12.0'
@@ -425,7 +430,7 @@ end
gem 'octokit', '~> 4.15'
# https://gitlab.com/gitlab-org/gitlab/issues/207207
-gem 'gitlab-mail_room', '~> 0.0.6', require: 'mail_room'
+gem 'gitlab-mail_room', '~> 0.0.7', require: 'mail_room'
gem 'email_reply_trimmer', '~> 0.1'
gem 'html2text'
@@ -461,7 +466,7 @@ group :ed25519 do
end
# Gitaly GRPC protocol definitions
-gem 'gitaly', '~> 13.3.0-rc1'
+gem 'gitaly', '~> 13.5.0-rc2'
gem 'grpc', '~> 1.30.2'
@@ -512,3 +517,6 @@ gem 'multi_json', '~> 1.14.1'
gem 'yajl-ruby', '~> 1.4.1', require: 'yajl'
gem 'webauthn', '~> 2.3'
+
+# IPAddress utilities
+gem 'ipaddress', '~> 0.8.3'
diff --git a/Gemfile.lock b/Gemfile.lock
index 8d36a89b410..93670d22920 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -6,59 +6,59 @@ GEM
ace-rails-ap (4.1.2)
acme-client (2.0.6)
faraday (>= 0.17, < 2.0.0)
- actioncable (6.0.3.1)
- actionpack (= 6.0.3.1)
+ actioncable (6.0.3.3)
+ actionpack (= 6.0.3.3)
nio4r (~> 2.0)
websocket-driver (>= 0.6.1)
- actionmailbox (6.0.3.1)
- actionpack (= 6.0.3.1)
- activejob (= 6.0.3.1)
- activerecord (= 6.0.3.1)
- activestorage (= 6.0.3.1)
- activesupport (= 6.0.3.1)
+ actionmailbox (6.0.3.3)
+ actionpack (= 6.0.3.3)
+ activejob (= 6.0.3.3)
+ activerecord (= 6.0.3.3)
+ activestorage (= 6.0.3.3)
+ activesupport (= 6.0.3.3)
mail (>= 2.7.1)
- actionmailer (6.0.3.1)
- actionpack (= 6.0.3.1)
- actionview (= 6.0.3.1)
- activejob (= 6.0.3.1)
+ actionmailer (6.0.3.3)
+ actionpack (= 6.0.3.3)
+ actionview (= 6.0.3.3)
+ activejob (= 6.0.3.3)
mail (~> 2.5, >= 2.5.4)
rails-dom-testing (~> 2.0)
- actionpack (6.0.3.1)
- actionview (= 6.0.3.1)
- activesupport (= 6.0.3.1)
+ actionpack (6.0.3.3)
+ actionview (= 6.0.3.3)
+ activesupport (= 6.0.3.3)
rack (~> 2.0, >= 2.0.8)
rack-test (>= 0.6.3)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.2.0)
- actiontext (6.0.3.1)
- actionpack (= 6.0.3.1)
- activerecord (= 6.0.3.1)
- activestorage (= 6.0.3.1)
- activesupport (= 6.0.3.1)
+ actiontext (6.0.3.3)
+ actionpack (= 6.0.3.3)
+ activerecord (= 6.0.3.3)
+ activestorage (= 6.0.3.3)
+ activesupport (= 6.0.3.3)
nokogiri (>= 1.8.5)
- actionview (6.0.3.1)
- activesupport (= 6.0.3.1)
+ actionview (6.0.3.3)
+ activesupport (= 6.0.3.3)
builder (~> 3.1)
erubi (~> 1.4)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.1, >= 1.2.0)
- activejob (6.0.3.1)
- activesupport (= 6.0.3.1)
+ activejob (6.0.3.3)
+ activesupport (= 6.0.3.3)
globalid (>= 0.3.6)
- activemodel (6.0.3.1)
- activesupport (= 6.0.3.1)
- activerecord (6.0.3.1)
- activemodel (= 6.0.3.1)
- activesupport (= 6.0.3.1)
+ activemodel (6.0.3.3)
+ activesupport (= 6.0.3.3)
+ activerecord (6.0.3.3)
+ activemodel (= 6.0.3.3)
+ activesupport (= 6.0.3.3)
activerecord-explain-analyze (0.1.0)
activerecord (>= 4)
pg
- activestorage (6.0.3.1)
- actionpack (= 6.0.3.1)
- activejob (= 6.0.3.1)
- activerecord (= 6.0.3.1)
+ activestorage (6.0.3.3)
+ actionpack (= 6.0.3.3)
+ activejob (= 6.0.3.3)
+ activerecord (= 6.0.3.3)
marcel (~> 0.3.1)
- activesupport (6.0.3.1)
+ activesupport (6.0.3.3)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 0.7, < 2)
minitest (~> 5.1)
@@ -167,7 +167,7 @@ GEM
mime-types (>= 1.16)
cbor (0.5.9.6)
character_set (1.4.0)
- charlock_holmes (0.7.6)
+ charlock_holmes (0.7.7)
childprocess (3.0.0)
chunky_png (1.3.5)
citrus (3.0.2)
@@ -183,7 +183,7 @@ GEM
concord (0.1.5)
adamantium (~> 0.2.0)
equalizer (~> 0.0.9)
- concurrent-ruby (1.1.6)
+ concurrent-ruby (1.1.7)
connection_pool (2.2.2)
contracts (0.11.0)
cork (0.3.0)
@@ -202,7 +202,7 @@ GEM
css_parser (1.7.0)
addressable
daemons (1.2.6)
- danger (8.0.5)
+ danger (8.0.6)
claide (~> 1.0)
claide-plugins (>= 0.9.2)
colored2 (~> 3.1)
@@ -235,7 +235,7 @@ GEM
thor (>= 0.19, < 2)
unicode_plot (>= 0.0.4, < 1.0.0)
device_detector (1.0.0)
- devise (4.7.1)
+ devise (4.7.3)
bcrypt (~> 3.0)
orm_adapter (~> 0.1)
railties (>= 4.1.0)
@@ -253,7 +253,7 @@ GEM
discordrb-webhooks-blackst0ne (3.3.0)
rest-client (~> 2.0)
docile (1.3.2)
- domain_name (0.5.20180417)
+ domain_name (0.5.20190701)
unf (>= 0.0.5, < 1.0.0)
doorkeeper (5.3.3)
railties (>= 5)
@@ -312,7 +312,7 @@ GEM
tzinfo
eventmachine (1.2.7)
excon (0.71.1)
- execjs (2.6.0)
+ execjs (2.7.0)
expression_parser (0.9.0)
extended-markdown-filter (0.6.0)
html-pipeline (~> 2.0)
@@ -416,7 +416,7 @@ GEM
rails (>= 3.2.0)
git (1.7.0)
rchardet (~> 1.8)
- gitaly (13.3.0.pre.rc2)
+ gitaly (13.5.0.pre.rc2)
grpc (~> 1.0)
github-markup (1.7.0)
gitlab-chronic (0.10.5)
@@ -428,7 +428,7 @@ GEM
fog-json (~> 1.2.0)
mime-types
ms_rest_azure (~> 0.12.0)
- gitlab-labkit (0.12.1)
+ gitlab-labkit (0.12.2)
actionpack (>= 5.0.0, < 6.1.0)
activesupport (>= 5.0.0, < 6.1.0)
grpc (~> 1.19)
@@ -436,7 +436,7 @@ GEM
opentracing (~> 0.4)
redis (> 3.0.0, < 5.0.0)
gitlab-license (1.0.0)
- gitlab-mail_room (0.0.6)
+ gitlab-mail_room (0.0.7)
gitlab-markup (1.7.1)
gitlab-net-dns (0.9.1)
gitlab-puma (4.3.5.gitlab.3)
@@ -495,7 +495,7 @@ GEM
grape-entity (0.7.1)
activesupport (>= 4.0)
multi_json (>= 1.3.2)
- grape-path-helpers (1.3.0)
+ grape-path-helpers (1.4.0)
activesupport
grape (~> 1.3)
rake (~> 12)
@@ -547,7 +547,7 @@ GEM
tilt
hana (1.3.6)
hangouts-chat (0.0.5)
- hashdiff (0.3.8)
+ hashdiff (1.0.1)
hashie (3.6.0)
hashie-forbidden_attributes (0.1.1)
hashie (>= 3.0)
@@ -563,21 +563,22 @@ GEM
html2text (0.2.0)
nokogiri (~> 1.6)
htmlentities (4.3.4)
- http (4.2.0)
+ http (4.4.1)
addressable (~> 2.3)
http-cookie (~> 1.0)
- http-form_data (~> 2.0)
+ http-form_data (~> 2.2)
http-parser (~> 1.2.0)
+ http-accept (1.7.0)
http-cookie (1.0.3)
domain_name (~> 0.5)
- http-form_data (2.1.1)
+ http-form_data (2.3.0)
http-parser (1.2.1)
ffi-compiler (>= 1.0, < 2.0)
httparty (0.16.4)
mime-types (~> 3.0)
multi_xml (>= 0.5.2)
httpclient (2.8.3)
- i18n (1.8.3)
+ i18n (1.8.5)
concurrent-ruby (~> 1.0)
i18n_data (0.8.0)
icalendar (2.4.1)
@@ -611,6 +612,9 @@ GEM
hana (~> 1.3)
regexp_parser (~> 1.5)
uri_template (~> 0.7)
+ jsonpath (1.0.5)
+ multi_json
+ to_regexp (~> 0.2.1)
jwt (2.1.0)
kaminari (1.2.1)
activesupport (>= 4.1.0)
@@ -631,9 +635,10 @@ GEM
rexml
kramdown-parser-gfm (1.1.0)
kramdown (~> 2.0)
- kubeclient (4.6.0)
+ kubeclient (4.9.1)
http (>= 3.0, < 5.0)
- recursive-open-struct (~> 1.0, >= 1.0.4)
+ jsonpath (~> 1.0)
+ recursive-open-struct (~> 1.1, >= 1.1.1)
rest-client (~> 2.0)
launchy (2.4.3)
addressable (~> 2.3)
@@ -643,9 +648,9 @@ GEM
actionmailer (>= 3.2)
letter_opener (~> 1.0)
railties (>= 3.2)
- license_finder (5.4.0)
+ license_finder (6.0.0)
bundler
- rubyzip
+ rubyzip (>= 1, < 3)
thor
toml (= 0.2.0)
with_env (= 1.1.0)
@@ -662,7 +667,7 @@ GEM
activesupport (>= 4)
railties (>= 4)
request_store (~> 1.0)
- loofah (2.5.0)
+ loofah (2.7.0)
crass (~> 1.0.2)
nokogiri (>= 1.5.9)
lru_redux (1.1.0)
@@ -684,7 +689,7 @@ GEM
mime-types-data (3.2020.0512)
mimemagic (0.3.5)
mini_histogram (0.1.3)
- mini_magick (4.9.5)
+ mini_magick (4.10.1)
mini_mime (1.0.2)
mini_portile2 (2.4.0)
minitest (5.11.3)
@@ -713,7 +718,7 @@ GEM
net-ntp (2.1.3)
net-ssh (6.0.0)
netrc (0.11.0)
- nio4r (2.5.2)
+ nio4r (2.5.4)
no_proxy_fix (0.1.2)
nokogiri (1.10.10)
mini_portile2 (~> 2.4.0)
@@ -838,7 +843,7 @@ GEM
parser
unparser
procto (0.0.3)
- prometheus-client-mmap (0.11.0)
+ prometheus-client-mmap (0.12.0)
pry (0.13.1)
coderay (~> 1.1)
method_source (~> 1.0)
@@ -847,10 +852,10 @@ GEM
pry (~> 0.13.0)
pry-rails (0.3.9)
pry (>= 0.10.4)
- public_suffix (4.0.3)
+ public_suffix (4.0.6)
pyu-ruby-sasl (0.0.3.3)
raabro (1.1.6)
- rack (2.0.9)
+ rack (2.1.4)
rack-accept (0.4.5)
rack (>= 0.4)
rack-attack (6.3.0)
@@ -870,25 +875,25 @@ GEM
rack-test (1.1.0)
rack (>= 1.0, < 3)
rack-timeout (0.5.2)
- rails (6.0.3.1)
- actioncable (= 6.0.3.1)
- actionmailbox (= 6.0.3.1)
- actionmailer (= 6.0.3.1)
- actionpack (= 6.0.3.1)
- actiontext (= 6.0.3.1)
- actionview (= 6.0.3.1)
- activejob (= 6.0.3.1)
- activemodel (= 6.0.3.1)
- activerecord (= 6.0.3.1)
- activestorage (= 6.0.3.1)
- activesupport (= 6.0.3.1)
+ rails (6.0.3.3)
+ actioncable (= 6.0.3.3)
+ actionmailbox (= 6.0.3.3)
+ actionmailer (= 6.0.3.3)
+ actionpack (= 6.0.3.3)
+ actiontext (= 6.0.3.3)
+ actionview (= 6.0.3.3)
+ activejob (= 6.0.3.3)
+ activemodel (= 6.0.3.3)
+ activerecord (= 6.0.3.3)
+ activestorage (= 6.0.3.3)
+ activesupport (= 6.0.3.3)
bundler (>= 1.3.0)
- railties (= 6.0.3.1)
+ railties (= 6.0.3.3)
sprockets-rails (>= 2.0.0)
- rails-controller-testing (1.0.4)
- actionpack (>= 5.0.1.x)
- actionview (>= 5.0.1.x)
- activesupport (>= 5.0.1.x)
+ rails-controller-testing (1.0.5)
+ actionpack (>= 5.0.1.rc1)
+ actionview (>= 5.0.1.rc1)
+ activesupport (>= 5.0.1.rc1)
rails-dom-testing (2.0.3)
activesupport (>= 4.2.0)
nokogiri (>= 1.6)
@@ -897,9 +902,9 @@ GEM
rails-i18n (6.0.0)
i18n (>= 0.7, < 2)
railties (>= 6.0.0, < 7)
- railties (6.0.3.1)
- actionpack (= 6.0.3.1)
- activesupport (= 6.0.3.1)
+ railties (6.0.3.3)
+ actionpack (= 6.0.3.3)
+ activesupport (= 6.0.3.3)
method_source
rake (>= 0.8.7)
thor (>= 0.20.3, < 2.0)
@@ -920,7 +925,7 @@ GEM
re2 (1.2.0)
recaptcha (4.13.1)
json
- recursive-open-struct (1.1.1)
+ recursive-open-struct (1.1.2)
redis (4.1.3)
redis-actionpack (5.2.0)
actionpack (>= 5, < 7)
@@ -951,7 +956,8 @@ GEM
responders (3.0.0)
actionpack (>= 5.0)
railties (>= 5.0)
- rest-client (2.0.2)
+ rest-client (2.1.0)
+ http-accept (>= 1.7.0, < 2.0)
http-cookie (>= 1.0.2, < 2.0)
mime-types (>= 1.16, < 4.0)
netrc (~> 0.8)
@@ -959,7 +965,7 @@ GEM
rexml (3.2.4)
rinku (2.0.0)
rotp (2.1.2)
- rouge (3.21.0)
+ rouge (3.24.0)
rqrcode (0.7.0)
chunky_png
rqrcode-rails3 (0.1.7)
@@ -1065,7 +1071,7 @@ GEM
seed-fu (2.3.7)
activerecord (>= 3.1)
activesupport (>= 3.1)
- selenium-webdriver (3.142.6)
+ selenium-webdriver (3.142.7)
childprocess (>= 0.5, < 4.0)
rubyzip (>= 1.2.2)
sentry-raven (3.0.4)
@@ -1096,7 +1102,7 @@ GEM
simplecov (~> 0.8)
simplecov-html (0.12.2)
sixarm_ruby_unaccent (1.2.0)
- slack-messenger (2.3.3)
+ slack-messenger (2.3.4)
snowplow-tracker (0.6.1)
contracts (~> 0.7, <= 0.11)
spring (2.0.2)
@@ -1106,7 +1112,7 @@ GEM
sprockets (3.7.2)
concurrent-ruby (~> 1.0)
rack (> 1, < 3)
- sprockets-rails (3.2.1)
+ sprockets-rails (3.2.2)
actionpack (>= 4.0)
activesupport (>= 4.0)
sprockets (>= 3.0.0)
@@ -1130,6 +1136,8 @@ GEM
temple (0.8.2)
terminal-table (1.8.0)
unicode-display_width (~> 1.1, >= 1.1.1)
+ terser (1.0.2)
+ execjs (>= 0.3.0, < 3)
test-prof (0.12.0)
text (1.3.1)
thin (1.7.2)
@@ -1143,6 +1151,7 @@ GEM
timecop (0.9.1)
timeliness (0.3.10)
timfel-krb5-auth (0.8.3)
+ to_regexp (0.2.1)
toml (0.2.0)
parslet (~> 1.8.0)
toml-rb (1.0.0)
@@ -1157,12 +1166,9 @@ GEM
thread_safe (~> 0.1)
u2f (0.2.1)
uber (0.1.0)
- uglifier (2.7.2)
- execjs (>= 0.3.0)
- json (>= 1.8.0)
unf (0.1.4)
unf_ext
- unf_ext (0.0.7.5)
+ unf_ext (0.0.7.7)
unicode-display_width (1.7.0)
unicode_plot (0.0.4)
enumerable-statistics (>= 2.0.1)
@@ -1214,13 +1220,11 @@ GEM
webfinger (1.1.0)
activesupport
httpclient (>= 2.4)
- webmock (3.5.1)
+ webmock (3.9.1)
addressable (>= 2.3.6)
crack (>= 0.3.2)
- hashdiff
- webpack-rails (0.9.11)
- railties (>= 3.2.0)
- websocket-driver (0.7.1)
+ hashdiff (>= 0.4.0, < 2.0.0)
+ websocket-driver (0.7.3)
websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.5)
wikicloth (0.8.1)
@@ -1232,7 +1236,7 @@ GEM
xpath (3.2.0)
nokogiri (~> 1.8)
yajl-ruby (1.4.1)
- zeitwerk (2.3.0)
+ zeitwerk (2.4.0)
PLATFORMS
ruby
@@ -1259,6 +1263,7 @@ DEPENDENCIES
babosa (~> 1.0.2)
base32 (~> 0.3.0)
batch-loader (~> 1.4.0)
+ bcrypt (= 3.1.12)
bcrypt_pbkdf (~> 1.0)
benchmark-ips (~> 2.3.0)
benchmark-memory (~> 0.1)
@@ -1272,19 +1277,19 @@ DEPENDENCIES
capybara (~> 3.33.0)
capybara-screenshot (~> 1.0.22)
carrierwave (~> 1.3)
- charlock_holmes (~> 0.7.5)
+ charlock_holmes (~> 0.7.7)
commonmarker (~> 0.20)
concurrent-ruby (~> 1.1)
connection_pool (~> 2.0)
countries (~> 3.0)
creole (~> 0.5.0)
- danger (~> 8.0)
+ danger (~> 8.0.6)
database_cleaner (~> 1.7.0)
deckar01-task_list (= 2.3.1)
default_value_for (~> 3.3.0)
derailed_benchmarks
device_detector
- devise (~> 4.6)
+ devise (~> 4.7.2)
devise-two-factor (~> 3.1.0)
diff_match_patch (~> 0.1.0)
diffy (~> 3.3)
@@ -1322,13 +1327,13 @@ DEPENDENCIES
gettext (~> 3.3)
gettext_i18n_rails (~> 1.8.0)
gettext_i18n_rails_js (~> 1.3)
- gitaly (~> 13.3.0.pre.rc1)
+ gitaly (~> 13.5.0.pre.rc2)
github-markup (~> 1.7.0)
gitlab-chronic (~> 0.10.5)
gitlab-fog-azure-rm (~> 1.0)
- gitlab-labkit (= 0.12.1)
+ gitlab-labkit (= 0.12.2)
gitlab-license (~> 1.0)
- gitlab-mail_room (~> 0.0.6)
+ gitlab-mail_room (~> 0.0.7)
gitlab-markup (~> 1.7.1)
gitlab-net-dns (~> 0.9.1)
gitlab-puma (~> 4.3.3.gitlab.2)
@@ -1343,7 +1348,7 @@ DEPENDENCIES
gpgme (~> 2.0.19)
grape (= 1.4.0)
grape-entity (~> 0.7.1)
- grape-path-helpers (~> 1.3)
+ grape-path-helpers (~> 1.4)
grape_logging (~> 1.7)
graphiql-rails (~> 1.4.10)
graphql (~> 1.11.4)
@@ -1354,6 +1359,7 @@ DEPENDENCIES
haml_lint (~> 0.34.0)
hamlit (~> 2.11.0)
hangouts-chat (~> 0.0.5)
+ hashie
hashie-forbidden_attributes
health_check (~> 3.0)
hipchat (~> 1.5.0)
@@ -1362,6 +1368,7 @@ DEPENDENCIES
httparty (~> 0.16.4)
icalendar
invisible_captcha (~> 0.12.1)
+ ipaddress (~> 0.8.3)
jira-ruby (~> 2.0.0)
js_regex (~> 3.4)
json (~> 2.3.0)
@@ -1371,9 +1378,9 @@ DEPENDENCIES
kaminari (~> 1.0)
knapsack (~> 1.17)
kramdown (~> 2.3.0)
- kubeclient (~> 4.6.0)
+ kubeclient (~> 4.9.1)
letter_opener_web (~> 1.3.4)
- license_finder (~> 5.4)
+ license_finder (~> 6.0)
licensee (~> 8.9)
lockbox (~> 0.3.3)
lograge (~> 0.5)
@@ -1384,7 +1391,7 @@ DEPENDENCIES
memory_profiler (~> 0.9)
method_source (~> 1.0)
mimemagic (~> 0.3.2)
- mini_magick
+ mini_magick (~> 4.10.1)
minitest (~> 5.11.0)
multi_json (~> 1.14.1)
nakayoshi_fork (~> 0.0.4)
@@ -1419,10 +1426,10 @@ DEPENDENCIES
pg (~> 1.1)
png_quantizator (~> 0.2.1)
premailer-rails (~> 1.10.3)
- prometheus-client-mmap (~> 0.11.0)
+ prometheus-client-mmap (~> 0.12.0)
pry-byebug (~> 3.9.0)
pry-rails (~> 0.3.9)
- rack (~> 2.0.9)
+ rack (~> 2.1.4)
rack-attack (~> 6.3.0)
rack-cors (~> 1.0.6)
rack-oauth2 (~> 1.9.3)
@@ -1444,7 +1451,7 @@ DEPENDENCIES
request_store (~> 1.5)
responders (~> 3.0)
retriable (~> 3.1.2)
- rouge (~> 3.21.0)
+ rouge (~> 3.24.0)
rqrcode-rails3 (~> 0.1.7)
rspec-parameterized
rspec-rails (~> 4.0.0)
@@ -1473,7 +1480,7 @@ DEPENDENCIES
simple_po_parser (~> 1.1.2)
simplecov (~> 0.18.5)
simplecov-cobertura (~> 1.3.1)
- slack-messenger (~> 2.3.3)
+ slack-messenger (~> 2.3.4)
snowplow-tracker (~> 0.6.1)
spring (~> 2.0.0)
spring-commands-rspec (~> 1.0.4)
@@ -1482,13 +1489,13 @@ DEPENDENCIES
stackprof (~> 0.2.15)
state_machines-activerecord (~> 0.6.0)
sys-filesystem (~> 1.1.6)
+ terser (= 1.0.2)
test-prof (~> 0.12.0)
thin (~> 1.7.0)
timecop (~> 0.9.1)
toml-rb (~> 1.0.0)
truncato (~> 0.7.11)
u2f (~> 0.2.1)
- uglifier (~> 2.7.2)
unf (~> 0.1.4)
unicorn (~> 5.5)
unicorn-worker-killer (~> 0.4.4)
@@ -1498,8 +1505,7 @@ DEPENDENCIES
version_sorter (~> 2.2.4)
vmstat (~> 2.3.0)
webauthn (~> 2.3)
- webmock (~> 3.5.1)
- webpack-rails (~> 0.9.10)
+ webmock (~> 3.9.1)
wikicloth (= 0.8.1)
yajl-ruby (~> 1.4.1)
diff --git a/PROCESS.md b/PROCESS.md
index 45f28b33a63..820f19a290b 100644
--- a/PROCESS.md
+++ b/PROCESS.md
@@ -73,7 +73,7 @@ sensitive as to how you word things. Use Emoji to express your feelings (heart,
star, smile, etc.). Some good tips about code reviews can be found in our
[Code Review Guidelines].
-[Code Review Guidelines]: https://docs.gitlab.com/ce/development/code_review.html
+[Code Review Guidelines]: https://docs.gitlab.com/ee/development/code_review.html
## Feature flags
@@ -217,5 +217,5 @@ rebase with master to see if that solves the issue.
[team]: https://about.gitlab.com/team/
[done]: https://docs.gitlab.com/ee/development/contributing/merge_request_workflow.html#definition-of-done
-[automatic_ce_ee_merge]: https://docs.gitlab.com/ce/development/automatic_ce_ee_merge.html
-[ee_features]: https://docs.gitlab.com/ce/development/ee_features.html
+[automatic_ce_ee_merge]: https://docs.gitlab.com/ee/development/automatic_ce_ee_merge.html
+[ee_features]: https://docs.gitlab.com/ee/development/ee_features.html
diff --git a/app/assets/javascripts/admin/cohorts/components/usage_ping_disabled.vue b/app/assets/javascripts/admin/cohorts/components/usage_ping_disabled.vue
index 2ea55d44420..bc2d96832fa 100644
--- a/app/assets/javascripts/admin/cohorts/components/usage_ping_disabled.vue
+++ b/app/assets/javascripts/admin/cohorts/components/usage_ping_disabled.vue
@@ -9,13 +9,13 @@ export default {
},
inject: {
svgPath: {
- type: String,
+ default: '',
},
docsLink: {
- type: String,
+ default: '',
},
primaryButtonPath: {
- type: String,
+ default: '',
},
},
};
diff --git a/app/assets/javascripts/admin/dev_ops_report/components/usage_ping_disabled.vue b/app/assets/javascripts/admin/dev_ops_report/components/usage_ping_disabled.vue
index 5429ec403d3..316827e1b07 100644
--- a/app/assets/javascripts/admin/dev_ops_report/components/usage_ping_disabled.vue
+++ b/app/assets/javascripts/admin/dev_ops_report/components/usage_ping_disabled.vue
@@ -10,16 +10,16 @@ export default {
},
inject: {
isAdmin: {
- type: Boolean,
+ default: false,
},
svgPath: {
- type: String,
+ default: '',
},
docsLink: {
- type: String,
+ default: '',
},
primaryButtonPath: {
- type: String,
+ default: '',
},
},
};
diff --git a/app/assets/javascripts/alert_handler.js b/app/assets/javascripts/alert_handler.js
index 8fffb61d1dd..26b0142f6a2 100644
--- a/app/assets/javascripts/alert_handler.js
+++ b/app/assets/javascripts/alert_handler.js
@@ -1,13 +1,21 @@
-// This allows us to dismiss alerts that we've migrated from bootstrap
-// Note: This ONLY works on alerts that are created on page load
+// This allows us to dismiss alerts and banners that we've migrated from bootstrap
+// Note: This ONLY works on elements that are created on page load
// You can follow this effort in the following epic
// https://gitlab.com/groups/gitlab-org/-/epics/4070
export default function initAlertHandler() {
- const ALERT_SELECTOR = '.gl-alert';
- const CLOSE_SELECTOR = '.gl-alert-dismiss';
+ const DISMISSIBLE_SELECTORS = ['.gl-alert', '.gl-banner'];
+ const DISMISS_LABEL = '[aria-label="Dismiss"]';
+ const DISMISS_CLASS = '.gl-alert-dismiss';
- const dismissAlert = ({ target }) => target.closest(ALERT_SELECTOR).remove();
- const closeButtons = document.querySelectorAll(`${ALERT_SELECTOR} ${CLOSE_SELECTOR}`);
- closeButtons.forEach(alert => alert.addEventListener('click', dismissAlert));
+ DISMISSIBLE_SELECTORS.forEach(selector => {
+ const elements = document.querySelectorAll(selector);
+ elements.forEach(element => {
+ const button = element.querySelector(DISMISS_LABEL) || element.querySelector(DISMISS_CLASS);
+ if (!button) {
+ return;
+ }
+ button.addEventListener('click', () => element.remove());
+ });
+ });
}
diff --git a/app/assets/javascripts/alert_management/components/alert_details.vue b/app/assets/javascripts/alert_management/components/alert_details.vue
index c6605452616..f7a5d31b835 100644
--- a/app/assets/javascripts/alert_management/components/alert_details.vue
+++ b/app/assets/javascripts/alert_management/components/alert_details.vue
@@ -1,16 +1,17 @@
<script>
-/* eslint-disable vue/no-v-html */
-import * as Sentry from '@sentry/browser';
import {
GlAlert,
GlBadge,
GlIcon,
+ GlLink,
GlLoadingIcon,
GlSprintf,
GlTabs,
GlTab,
GlButton,
+ GlSafeHtmlDirective,
} from '@gitlab/ui';
+import * as Sentry from '~/sentry/wrapper';
import { s__ } from '~/locale';
import alertQuery from '../graphql/queries/details.query.graphql';
import sidebarStatusQuery from '../graphql/queries/sidebar_status.query.graphql';
@@ -28,6 +29,8 @@ import SystemNote from './system_notes/system_note.vue';
import AlertSidebar from './alert_sidebar.vue';
import AlertMetrics from './alert_metrics.vue';
import AlertDetailsTable from '~/vue_shared/components/alert_details_table.vue';
+import AlertSummaryRow from './alert_summary_row.vue';
+import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
const containerEl = document.querySelector('.page-with-contextual-sidebar');
@@ -39,6 +42,9 @@ export default {
reportedAt: s__('AlertManagement|Reported %{when}'),
reportedAtWithTool: s__('AlertManagement|Reported %{when} by %{tool}'),
},
+ directives: {
+ SafeHtml: GlSafeHtmlDirective,
+ },
severityLabels: ALERTS_SEVERITY_LABELS,
tabsConfig: [
{
@@ -56,9 +62,11 @@ export default {
],
components: {
AlertDetailsTable,
+ AlertSummaryRow,
GlBadge,
GlAlert,
GlIcon,
+ GlLink,
GlLoadingIcon,
GlSprintf,
GlTab,
@@ -69,20 +77,18 @@ export default {
SystemNote,
AlertMetrics,
},
+ mixins: [glFeatureFlagsMixin()],
inject: {
projectPath: {
default: '',
},
alertId: {
- type: String,
default: '',
},
projectId: {
- type: String,
default: '',
},
projectIssuesPath: {
- type: String,
default: '',
},
},
@@ -143,6 +149,15 @@ export default {
this.$router.replace({ name: 'tab', params: { tabId } });
},
},
+ environmentName() {
+ return this.shouldDisplayEnvironment && this.alert?.environment?.name;
+ },
+ environmentPath() {
+ return this.shouldDisplayEnvironment && this.alert?.environment?.path;
+ },
+ shouldDisplayEnvironment() {
+ return this.glFeatures.exposeEnvironmentPathInAlertDetails;
+ },
},
mounted() {
this.trackPageViews();
@@ -211,7 +226,7 @@ export default {
<template>
<div>
<gl-alert v-if="showErrorMsg" variant="danger" @dismiss="dismissError">
- <p v-html="sidebarErrorMessage || $options.i18n.errorMsg"></p>
+ <p v-safe-html="sidebarErrorMessage || $options.i18n.errorMsg"></p>
</gl-alert>
<gl-alert
v-if="createIncidentError"
@@ -270,10 +285,9 @@ export default {
variant="default"
class="d-sm-none gl-absolute toggle-sidebar-mobile-button"
type="button"
+ icon="chevron-double-lg-left"
@click="toggleSidebar"
- >
- <i class="fa fa-angle-double-left"></i>
- </gl-button>
+ />
</div>
<div
v-if="alert"
@@ -283,54 +297,65 @@ export default {
</div>
<gl-tabs v-if="alert" v-model="currentTabIndex" data-testid="alertDetailsTabs">
<gl-tab :data-testid="$options.tabsConfig[0].id" :title="$options.tabsConfig[0].title">
- <div v-if="alert.severity" class="gl-mt-3 gl-mb-5 gl-display-flex">
- <div class="gl-font-weight-bold gl-w-13 gl-text-right gl-pr-3">
- {{ s__('AlertManagement|Severity') }}:
- </div>
- <div class="gl-pl-2" data-testid="severity">
- <span>
- <gl-icon
- class="gl-vertical-align-middle"
- :size="12"
- :name="`severity-${alert.severity.toLowerCase()}`"
- :class="`icon-${alert.severity.toLowerCase()}`"
- />
- </span>
+ <alert-summary-row v-if="alert.severity" :label="`${s__('AlertManagement|Severity')}:`">
+ <span data-testid="severity">
+ <gl-icon
+ class="gl-vertical-align-middle"
+ :size="12"
+ :name="`severity-${alert.severity.toLowerCase()}`"
+ :class="`icon-${alert.severity.toLowerCase()}`"
+ />
{{ $options.severityLabels[alert.severity] }}
- </div>
- </div>
- <div v-if="alert.startedAt" class="gl-my-5 gl-display-flex">
- <div class="gl-font-weight-bold gl-w-13 gl-text-right gl-pr-3">
- {{ s__('AlertManagement|Start time') }}:
- </div>
- <div class="gl-pl-2">
- <time-ago-tooltip data-testid="startTimeItem" :time="alert.startedAt" />
- </div>
- </div>
- <div v-if="alert.eventCount" class="gl-my-5 gl-display-flex">
- <div class="gl-font-weight-bold gl-w-13 gl-text-right gl-pr-3">
- {{ s__('AlertManagement|Events') }}:
- </div>
- <div class="gl-pl-2" data-testid="eventCount">{{ alert.eventCount }}</div>
- </div>
- <div v-if="alert.monitoringTool" class="gl-my-5 gl-display-flex">
- <div class="gl-font-weight-bold gl-w-13 gl-text-right gl-pr-3">
- {{ s__('AlertManagement|Tool') }}:
- </div>
- <div class="gl-pl-2" data-testid="monitoringTool">{{ alert.monitoringTool }}</div>
- </div>
- <div v-if="alert.service" class="gl-my-5 gl-display-flex">
- <div class="bold gl-w-13 gl-text-right gl-pr-3">
- {{ s__('AlertManagement|Service') }}:
- </div>
- <div class="gl-pl-2" data-testid="service">{{ alert.service }}</div>
- </div>
- <div v-if="alert.runbook" class="gl-my-5 gl-display-flex">
- <div class="bold gl-w-13 gl-text-right gl-pr-3">
- {{ s__('AlertManagement|Runbook') }}:
- </div>
- <div class="gl-pl-2" data-testid="runbook">{{ alert.runbook }}</div>
- </div>
+ </span>
+ </alert-summary-row>
+ <alert-summary-row
+ v-if="environmentName"
+ :label="`${s__('AlertManagement|Environment')}:`"
+ >
+ <gl-link
+ v-if="environmentPath"
+ class="gl-display-inline-block"
+ data-testid="environmentPath"
+ :href="environmentPath"
+ >
+ {{ environmentName }}
+ </gl-link>
+ <span v-else data-testid="environmentName">{{ environmentName }}</span>
+ </alert-summary-row>
+ <alert-summary-row
+ v-if="alert.startedAt"
+ :label="`${s__('AlertManagement|Start time')}:`"
+ >
+ <time-ago-tooltip data-testid="startTimeItem" :time="alert.startedAt" />
+ </alert-summary-row>
+ <alert-summary-row
+ v-if="alert.eventCount"
+ :label="`${s__('AlertManagement|Events')}:`"
+ data-testid="eventCount"
+ >
+ {{ alert.eventCount }}
+ </alert-summary-row>
+ <alert-summary-row
+ v-if="alert.monitoringTool"
+ :label="`${s__('AlertManagement|Tool')}:`"
+ data-testid="monitoringTool"
+ >
+ {{ alert.monitoringTool }}
+ </alert-summary-row>
+ <alert-summary-row
+ v-if="alert.service"
+ :label="`${s__('AlertManagement|Service')}:`"
+ data-testid="service"
+ >
+ {{ alert.service }}
+ </alert-summary-row>
+ <alert-summary-row
+ v-if="alert.runbook"
+ :label="`${s__('AlertManagement|Runbook')}:`"
+ data-testid="runbook"
+ >
+ {{ alert.runbook }}
+ </alert-summary-row>
<alert-details-table :alert="alert" :loading="loading" />
</gl-tab>
<gl-tab :data-testid="$options.tabsConfig[1].id" :title="$options.tabsConfig[1].title">
diff --git a/app/assets/javascripts/alert_management/components/alert_management_empty_state.vue b/app/assets/javascripts/alert_management/components/alert_management_empty_state.vue
index 68443166f40..c5ff2dc0d11 100644
--- a/app/assets/javascripts/alert_management/components/alert_management_empty_state.vue
+++ b/app/assets/javascripts/alert_management/components/alert_management_empty_state.vue
@@ -33,30 +33,13 @@ export default {
query: alertsHelpUrlQuery,
},
},
- props: {
- enableAlertManagementPath: {
- type: String,
- required: true,
- },
- userCanEnableAlertManagement: {
- type: Boolean,
- required: true,
- },
- emptyAlertSvgPath: {
- type: String,
- required: true,
- },
- opsgenieMvcEnabled: {
- type: Boolean,
- required: false,
- default: false,
- },
- opsgenieMvcTargetUrl: {
- type: String,
- required: false,
- default: '',
- },
- },
+ inject: [
+ 'enableAlertManagementPath',
+ 'userCanEnableAlertManagement',
+ 'emptyAlertSvgPath',
+ 'opsgenieMvcEnabled',
+ 'opsgenieMvcTargetUrl',
+ ],
data() {
return {
alertsHelpUrl: '',
diff --git a/app/assets/javascripts/alert_management/components/alert_management_list_wrapper.vue b/app/assets/javascripts/alert_management/components/alert_management_list_wrapper.vue
index 094f33fed3b..5e9cdfb3fed 100644
--- a/app/assets/javascripts/alert_management/components/alert_management_list_wrapper.vue
+++ b/app/assets/javascripts/alert_management/components/alert_management_list_wrapper.vue
@@ -1,6 +1,4 @@
<script>
-import Tracking from '~/tracking';
-import { trackAlertListViewsOptions } from '../constants';
import AlertManagementEmptyState from './alert_management_empty_state.vue';
import AlertManagementTable from './alert_management_table.vue';
@@ -9,67 +7,12 @@ export default {
AlertManagementEmptyState,
AlertManagementTable,
},
- props: {
- projectPath: {
- type: String,
- required: true,
- },
- alertManagementEnabled: {
- type: Boolean,
- required: true,
- },
- enableAlertManagementPath: {
- type: String,
- required: true,
- },
- populatingAlertsHelpUrl: {
- type: String,
- required: true,
- },
- userCanEnableAlertManagement: {
- type: Boolean,
- required: true,
- },
- emptyAlertSvgPath: {
- type: String,
- required: true,
- },
- opsgenieMvcEnabled: {
- type: Boolean,
- required: false,
- default: false,
- },
- opsgenieMvcTargetUrl: {
- type: String,
- required: false,
- default: '',
- },
- },
- mounted() {
- this.trackPageViews();
- },
- methods: {
- trackPageViews() {
- const { category, action } = trackAlertListViewsOptions;
- Tracking.event(category, action);
- },
- },
+ inject: ['alertManagementEnabled'],
};
</script>
<template>
<div>
- <alert-management-table
- v-if="alertManagementEnabled"
- :populating-alerts-help-url="populatingAlertsHelpUrl"
- :project-path="projectPath"
- />
- <alert-management-empty-state
- v-else
- :empty-alert-svg-path="emptyAlertSvgPath"
- :enable-alert-management-path="enableAlertManagementPath"
- :user-can-enable-alert-management="userCanEnableAlertManagement"
- :opsgenie-mvc-enabled="opsgenieMvcEnabled"
- :opsgenie-mvc-target-url="opsgenieMvcTargetUrl"
- />
+ <alert-management-table v-if="alertManagementEnabled" />
+ <alert-management-empty-state v-else />
</div>
</template>
diff --git a/app/assets/javascripts/alert_management/components/alert_management_table.vue b/app/assets/javascripts/alert_management/components/alert_management_table.vue
index 0fd00fe90eb..f287b425826 100644
--- a/app/assets/javascripts/alert_management/components/alert_management_table.vue
+++ b/app/assets/javascripts/alert_management/components/alert_management_table.vue
@@ -1,58 +1,43 @@
<script>
-/* eslint-disable vue/no-v-html */
import {
+ GlAlert,
GlLoadingIcon,
GlTable,
- GlAlert,
GlAvatarsInline,
GlAvatarLink,
GlAvatar,
GlIcon,
GlLink,
- GlTabs,
- GlTab,
- GlBadge,
- GlPagination,
- GlSearchBoxByType,
GlSprintf,
GlTooltipDirective,
} from '@gitlab/ui';
-import { debounce, trim } from 'lodash';
-import { __, s__ } from '~/locale';
-import { joinPaths, visitUrl } from '~/lib/utils/url_utility';
+import { s__, __ } from '~/locale';
import { fetchPolicies } from '~/lib/graphql';
+import { joinPaths, visitUrl } from '~/lib/utils/url_utility';
+import PaginatedTableWithSearchAndTabs from '~/vue_shared/components/paginated_table_with_search_and_tabs/paginated_table_with_search_and_tabs.vue';
+import {
+ tdClass,
+ thClass,
+ bodyTrClass,
+ initialPaginationState,
+} from '~/vue_shared/components/paginated_table_with_search_and_tabs/constants';
import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue';
import { convertToSnakeCase } from '~/lib/utils/text_utility';
-import Tracking from '~/tracking';
import getAlerts from '../graphql/queries/get_alerts.query.graphql';
import getAlertsCountByStatus from '../graphql/queries/get_count_by_status.query.graphql';
import {
ALERTS_STATUS_TABS,
ALERTS_SEVERITY_LABELS,
- DEFAULT_PAGE_SIZE,
trackAlertListViewsOptions,
- trackAlertStatusUpdateOptions,
} from '../constants';
import AlertStatus from './alert_status.vue';
-const tdClass =
- 'table-col gl-display-flex d-md-table-cell gl-align-items-center gl-white-space-nowrap';
-const thClass = 'gl-hover-bg-blue-50';
-const bodyTrClass =
- 'gl-border-1 gl-border-t-solid gl-border-gray-100 gl-hover-bg-blue-50 gl-hover-cursor-pointer gl-hover-border-b-solid gl-hover-border-blue-200';
const TH_TEST_ID = { 'data-testid': 'alert-management-severity-sort' };
-const initialPaginationState = {
- currentPage: 1,
- prevPageCursor: '',
- nextPageCursor: '',
- firstPageSize: DEFAULT_PAGE_SIZE,
- lastPageSize: null,
-};
-
const TWELVE_HOURS_IN_MS = 12 * 60 * 60 * 1000;
export default {
+ trackAlertListViewsOptions,
i18n: {
noAlertsMsg: s__(
'AlertManagement|No alerts available to display. See %{linkStart}enabling alert management%{linkEnd} for more information on adding alerts to the list.',
@@ -60,7 +45,6 @@ export default {
errorMsg: s__(
"AlertManagement|There was an error displaying the alerts. Confirm your endpoint's configuration details to ensure alerts appear.",
),
- searchPlaceholder: __('Search or filter results...'),
unassigned: __('Unassigned'),
},
fields: [
@@ -94,7 +78,7 @@ export default {
},
{
key: 'issue',
- label: s__('AlertManagement|Issue'),
+ label: s__('AlertManagement|Incident'),
thClass: 'gl-w-12 gl-pointer-events-none',
tdClass,
},
@@ -115,36 +99,23 @@ export default {
severityLabels: ALERTS_SEVERITY_LABELS,
statusTabs: ALERTS_STATUS_TABS,
components: {
+ GlAlert,
GlLoadingIcon,
GlTable,
- GlAlert,
GlAvatarsInline,
GlAvatarLink,
GlAvatar,
TimeAgo,
GlIcon,
GlLink,
- GlTabs,
- GlTab,
- GlBadge,
- GlPagination,
- GlSearchBoxByType,
GlSprintf,
AlertStatus,
+ PaginatedTableWithSearchAndTabs,
},
directives: {
GlTooltip: GlTooltipDirective,
},
- props: {
- projectPath: {
- type: String,
- required: true,
- },
- populatingAlertsHelpUrl: {
- type: String,
- required: true,
- },
- },
+ inject: ['projectPath', 'textQuery', 'assigneeUsernameQuery', 'populatingAlertsHelpUrl'],
apollo: {
alerts: {
fetchPolicy: fetchPolicies.CACHE_AND_NETWORK,
@@ -152,6 +123,7 @@ export default {
variables() {
return {
searchTerm: this.searchTerm,
+ assigneeUsername: this.assigneeUsername,
projectPath: this.projectPath,
statuses: this.statusFilter,
sort: this.sort,
@@ -182,14 +154,16 @@ export default {
};
},
error() {
- this.hasError = true;
+ this.errored = true;
},
},
alertsCount: {
+ fetchPolicy: fetchPolicies.CACHE_AND_NETWORK,
query: getAlertsCountByStatus,
variables() {
return {
searchTerm: this.searchTerm,
+ assigneeUsername: this.assigneeUsername,
projectPath: this.projectPath,
};
},
@@ -200,83 +174,53 @@ export default {
},
data() {
return {
- searchTerm: '',
- hasError: false,
- errorMessage: '',
- isAlertDismissed: false,
+ errored: false,
+ serverErrorMessage: '',
+ isErrorAlertDismissed: false,
sort: 'STARTED_AT_DESC',
statusFilter: [],
filteredByStatus: '',
- pagination: initialPaginationState,
+ alerts: {},
+ alertsCount: {},
sortBy: 'startedAt',
sortDesc: true,
sortDirection: 'desc',
+ searchTerm: this.textQuery,
+ assigneeUsername: this.assigneeUsernameQuery,
+ pagination: initialPaginationState,
};
},
computed: {
+ showErrorMsg() {
+ return this.errored && !this.isErrorAlertDismissed;
+ },
showNoAlertsMsg() {
return (
- !this.hasError &&
+ !this.errored &&
!this.loading &&
this.alertsCount?.all === 0 &&
!this.searchTerm &&
- !this.isAlertDismissed
+ !this.assigneeUsername &&
+ !this.isErrorAlertDismissed
);
},
loading() {
return this.$apollo.queries.alerts.loading;
},
- hasAlerts() {
- return this.alerts?.list?.length;
- },
- showPaginationControls() {
- return Boolean(this.prevPage || this.nextPage);
- },
- alertsForCurrentTab() {
- return this.alertsCount ? this.alertsCount[this.filteredByStatus.toLowerCase()] : 0;
- },
- prevPage() {
- return Math.max(this.pagination.currentPage - 1, 0);
- },
- nextPage() {
- const nextPage = this.pagination.currentPage + 1;
- return nextPage > Math.ceil(this.alertsForCurrentTab / DEFAULT_PAGE_SIZE) ? null : nextPage;
+ isEmpty() {
+ return !this.alerts?.list?.length;
},
},
- mounted() {
- this.trackPageViews();
- },
methods: {
- filterAlertsByStatus(tabIndex) {
- this.resetPagination();
- const { filters, status } = this.$options.statusTabs[tabIndex];
- this.statusFilter = filters;
- this.filteredByStatus = status;
- },
fetchSortedData({ sortBy, sortDesc }) {
const sortingDirection = sortDesc ? 'DESC' : 'ASC';
const sortingColumn = convertToSnakeCase(sortBy).toUpperCase();
- this.resetPagination();
+ this.pagination = initialPaginationState;
this.sort = `${sortingColumn}_${sortingDirection}`;
},
- onInputChange: debounce(function debounceSearch(input) {
- const trimmedInput = trim(input);
- if (trimmedInput !== this.searchTerm) {
- this.resetPagination();
- this.searchTerm = trimmedInput;
- }
- }, 500),
- navigateToAlertDetails({ iid }) {
- return visitUrl(joinPaths(window.location.pathname, iid, 'details'));
- },
- trackPageViews() {
- const { category, action } = trackAlertListViewsOptions;
- Tracking.event(category, action);
- },
- trackStatusUpdate(status) {
- const { category, action, label } = trackAlertStatusUpdateOptions;
- Tracking.event(category, action, { label, property: status });
+ navigateToAlertDetails({ iid }, index, { metaKey }) {
+ return visitUrl(joinPaths(window.location.pathname, iid, 'details'), metaKey);
},
hasAssignees(assignees) {
return Boolean(assignees.nodes?.length);
@@ -284,204 +228,180 @@ export default {
getIssueLink(item) {
return joinPaths('/', this.projectPath, '-', 'issues', item.issueIid);
},
- handlePageChange(page) {
- const { startCursor, endCursor } = this.alerts.pageInfo;
-
- if (page > this.pagination.currentPage) {
- this.pagination = {
- ...initialPaginationState,
- nextPageCursor: endCursor,
- currentPage: page,
- };
- } else {
- this.pagination = {
- lastPageSize: DEFAULT_PAGE_SIZE,
- firstPageSize: null,
- prevPageCursor: startCursor,
- nextPageCursor: '',
- currentPage: page,
- };
- }
- },
- resetPagination() {
- this.pagination = initialPaginationState;
- },
tbodyTrClass(item) {
return {
- [bodyTrClass]: !this.loading && this.hasAlerts,
+ [bodyTrClass]: !this.loading && !this.isEmpty,
'new-alert': item?.isNew,
};
},
handleAlertError(errorMessage) {
- this.hasError = true;
- this.errorMessage = errorMessage;
+ this.errored = true;
+ this.serverErrorMessage = errorMessage;
},
- dismissError() {
- this.hasError = false;
- this.errorMessage = '';
+ handleStatusUpdate() {
+ this.$apollo.queries.alerts.refetch();
+ this.$apollo.queries.alertsCount.refetch();
+ },
+ pageChanged(pagination) {
+ this.pagination = pagination;
+ },
+ statusChanged({ filters, status }) {
+ this.statusFilter = filters;
+ this.filteredByStatus = status;
+ },
+ filtersChanged({ searchTerm, assigneeUsername }) {
+ this.searchTerm = searchTerm;
+ this.assigneeUsername = assigneeUsername;
+ },
+ errorAlertDismissed() {
+ this.errored = false;
+ this.serverErrorMessage = '';
+ this.isErrorAlertDismissed = true;
},
},
};
</script>
<template>
<div>
- <div class="incident-management-list">
- <gl-alert v-if="showNoAlertsMsg" @dismiss="isAlertDismissed = true">
- <gl-sprintf :message="$options.i18n.noAlertsMsg">
- <template #link="{ content }">
- <gl-link
- class="gl-display-inline-block"
- :href="populatingAlertsHelpUrl"
- target="_blank"
- >
- {{ content }}
- </gl-link>
- </template>
- </gl-sprintf>
- </gl-alert>
- <gl-alert v-if="hasError" variant="danger" data-testid="alert-error" @dismiss="dismissError">
- <p v-html="errorMessage || $options.i18n.errorMsg"></p>
- </gl-alert>
-
- <gl-tabs
- content-class="gl-p-0 gl-border-b-solid gl-border-b-1 gl-border-gray-100"
- @input="filterAlertsByStatus"
- >
- <gl-tab v-for="tab in $options.statusTabs" :key="tab.status">
- <template slot="title">
- <span>{{ tab.title }}</span>
- <gl-badge v-if="alertsCount" pill size="sm" class="gl-tab-counter-badge">
- {{ alertsCount[tab.status.toLowerCase()] }}
- </gl-badge>
- </template>
- </gl-tab>
- </gl-tabs>
+ <gl-alert v-if="showNoAlertsMsg" @dismiss="errorAlertDismissed">
+ <gl-sprintf :message="$options.i18n.noAlertsMsg">
+ <template #link="{ content }">
+ <gl-link class="gl-display-inline-block" :href="populatingAlertsHelpUrl" target="_blank">
+ {{ content }}
+ </gl-link>
+ </template>
+ </gl-sprintf>
+ </gl-alert>
- <div class="gl-bg-gray-10 gl-p-5 gl-border-b-solid gl-border-b-1 gl-border-gray-100">
- <gl-search-box-by-type
- class="gl-bg-white"
- :placeholder="$options.i18n.searchPlaceholder"
- @input="onInputChange"
- />
- </div>
+ <paginated-table-with-search-and-tabs
+ :show-error-msg="showErrorMsg"
+ :i18n="$options.i18n"
+ :items="alerts.list || []"
+ :page-info="alerts.pageInfo"
+ :items-count="alertsCount"
+ :status-tabs="$options.statusTabs"
+ :track-views-options="$options.trackAlertListViewsOptions"
+ :server-error-message="serverErrorMessage"
+ :filter-search-tokens="['assignee_username']"
+ filter-search-key="alerts"
+ @page-changed="pageChanged"
+ @tabs-changed="statusChanged"
+ @filters-changed="filtersChanged"
+ @error-alert-dismissed="errorAlertDismissed"
+ >
+ <template #header-actions></template>
- <h4 class="d-block d-md-none my-3">
+ <template #title>
{{ s__('AlertManagement|Alerts') }}
- </h4>
- <gl-table
- class="alert-management-table"
- :items="alerts ? alerts.list : []"
- :fields="$options.fields"
- :show-empty="true"
- :busy="loading"
- stacked="md"
- :tbody-tr-class="tbodyTrClass"
- :no-local-sorting="true"
- :sort-direction="sortDirection"
- :sort-desc.sync="sortDesc"
- :sort-by.sync="sortBy"
- sort-icon-left
- fixed
- @row-clicked="navigateToAlertDetails"
- @sort-changed="fetchSortedData"
- >
- <template #cell(severity)="{ item }">
- <div
- class="d-inline-flex align-items-center justify-content-between"
- data-testid="severityField"
- >
- <gl-icon
- class="mr-2"
- :size="12"
- :name="`severity-${item.severity.toLowerCase()}`"
- :class="`icon-${item.severity.toLowerCase()}`"
- />
- {{ $options.severityLabels[item.severity] }}
- </div>
- </template>
+ </template>
- <template #cell(startedAt)="{ item }">
- <time-ago v-if="item.startedAt" :time="item.startedAt" />
- </template>
+ <template #table>
+ <gl-table
+ class="alert-management-table"
+ :items="alerts ? alerts.list : []"
+ :fields="$options.fields"
+ :show-empty="true"
+ :busy="loading"
+ stacked="md"
+ :tbody-tr-class="tbodyTrClass"
+ :no-local-sorting="true"
+ :sort-direction="sortDirection"
+ :sort-desc.sync="sortDesc"
+ :sort-by.sync="sortBy"
+ sort-icon-left
+ fixed
+ @row-clicked="navigateToAlertDetails"
+ @sort-changed="fetchSortedData"
+ >
+ <template #cell(severity)="{ item }">
+ <div
+ class="d-inline-flex align-items-center justify-content-between"
+ data-testid="severityField"
+ >
+ <gl-icon
+ class="mr-2"
+ :size="12"
+ :name="`severity-${item.severity.toLowerCase()}`"
+ :class="`icon-${item.severity.toLowerCase()}`"
+ />
+ {{ $options.severityLabels[item.severity] }}
+ </div>
+ </template>
- <template #cell(eventCount)="{ item }">
- {{ item.eventCount }}
- </template>
+ <template #cell(startedAt)="{ item }">
+ <time-ago v-if="item.startedAt" :time="item.startedAt" />
+ </template>
- <template #cell(alertLabel)="{ item }">
- <div
- class="gl-max-w-full text-truncate"
- :title="`${item.iid} - ${item.title}`"
- data-testid="idField"
- >
- #{{ item.iid }} {{ item.title }}
- </div>
- </template>
+ <template #cell(eventCount)="{ item }">
+ {{ item.eventCount }}
+ </template>
- <template #cell(issue)="{ item }">
- <gl-link v-if="item.issueIid" data-testid="issueField" :href="getIssueLink(item)">
- #{{ item.issueIid }}
- </gl-link>
- <div v-else data-testid="issueField">{{ s__('AlertManagement|None') }}</div>
- </template>
+ <template #cell(alertLabel)="{ item }">
+ <div
+ class="gl-max-w-full text-truncate"
+ :title="`${item.iid} - ${item.title}`"
+ data-testid="idField"
+ >
+ #{{ item.iid }} {{ item.title }}
+ </div>
+ </template>
- <template #cell(assignees)="{ item }">
- <div data-testid="assigneesField">
- <template v-if="hasAssignees(item.assignees)">
- <gl-avatars-inline
- :avatars="item.assignees.nodes"
- :collapsed="true"
- :max-visible="4"
- :avatar-size="24"
- badge-tooltip-prop="name"
- :badge-tooltip-max-chars="100"
- >
- <template #avatar="{ avatar }">
- <gl-avatar-link
- :key="avatar.username"
- v-gl-tooltip
- target="_blank"
- :href="avatar.webUrl"
- :title="avatar.name"
- >
- <gl-avatar :src="avatar.avatarUrl" :label="avatar.name" :size="24" />
- </gl-avatar-link>
- </template>
- </gl-avatars-inline>
- </template>
- <template v-else>
- {{ $options.i18n.unassigned }}
- </template>
- </div>
- </template>
+ <template #cell(issue)="{ item }">
+ <gl-link v-if="item.issueIid" data-testid="issueField" :href="getIssueLink(item)">
+ #{{ item.issueIid }}
+ </gl-link>
+ <div v-else data-testid="issueField">{{ s__('AlertManagement|None') }}</div>
+ </template>
- <template #cell(status)="{ item }">
- <alert-status
- :alert="item"
- :project-path="projectPath"
- :is-sidebar="false"
- @alert-error="handleAlertError"
- />
- </template>
+ <template #cell(assignees)="{ item }">
+ <div data-testid="assigneesField">
+ <template v-if="hasAssignees(item.assignees)">
+ <gl-avatars-inline
+ :avatars="item.assignees.nodes"
+ :collapsed="true"
+ :max-visible="4"
+ :avatar-size="24"
+ badge-tooltip-prop="name"
+ :badge-tooltip-max-chars="100"
+ >
+ <template #avatar="{ avatar }">
+ <gl-avatar-link
+ :key="avatar.username"
+ v-gl-tooltip
+ target="_blank"
+ :href="avatar.webUrl"
+ :title="avatar.name"
+ >
+ <gl-avatar :src="avatar.avatarUrl" :label="avatar.name" :size="24" />
+ </gl-avatar-link>
+ </template>
+ </gl-avatars-inline>
+ </template>
+ <template v-else>
+ {{ $options.i18n.unassigned }}
+ </template>
+ </div>
+ </template>
- <template #empty>
- {{ s__('AlertManagement|No alerts to display.') }}
- </template>
+ <template #cell(status)="{ item }">
+ <alert-status
+ :alert="item"
+ :project-path="projectPath"
+ :is-sidebar="false"
+ @alert-error="handleAlertError"
+ @hide-dropdown="handleStatusUpdate"
+ />
+ </template>
- <template #table-busy>
- <gl-loading-icon size="lg" color="dark" class="mt-3" />
- </template>
- </gl-table>
+ <template #empty>
+ {{ s__('AlertManagement|No alerts to display.') }}
+ </template>
- <gl-pagination
- v-if="showPaginationControls"
- :value="pagination.currentPage"
- :prev-page="prevPage"
- :next-page="nextPage"
- align="center"
- class="gl-pagination gl-mt-3"
- @input="handlePageChange"
- />
- </div>
+ <template #table-busy>
+ <gl-loading-icon size="lg" color="dark" class="mt-3" />
+ </template>
+ </gl-table>
+ </template>
+ </paginated-table-with-search-and-tabs>
</div>
</template>
diff --git a/app/assets/javascripts/alert_management/components/alert_metrics.vue b/app/assets/javascripts/alert_management/components/alert_metrics.vue
index c5b40edc672..8a6490ecd5c 100644
--- a/app/assets/javascripts/alert_management/components/alert_metrics.vue
+++ b/app/assets/javascripts/alert_management/components/alert_metrics.vue
@@ -1,7 +1,7 @@
<script>
import Vue from 'vue';
import Vuex from 'vuex';
-import * as Sentry from '@sentry/browser';
+import * as Sentry from '~/sentry/wrapper';
Vue.use(Vuex);
diff --git a/app/assets/javascripts/alert_management/components/alert_sidebar.vue b/app/assets/javascripts/alert_management/components/alert_sidebar.vue
index 64e4089c85a..41d77716592 100644
--- a/app/assets/javascripts/alert_management/components/alert_sidebar.vue
+++ b/app/assets/javascripts/alert_management/components/alert_sidebar.vue
@@ -18,7 +18,6 @@ export default {
default: '',
},
projectId: {
- type: String,
default: '',
},
},
diff --git a/app/assets/javascripts/alert_management/components/alert_status.vue b/app/assets/javascripts/alert_management/components/alert_status.vue
index ff71b348cc9..3083a85cbd9 100644
--- a/app/assets/javascripts/alert_management/components/alert_status.vue
+++ b/app/assets/javascripts/alert_management/components/alert_status.vue
@@ -1,9 +1,9 @@
<script>
-import { GlDeprecatedDropdown, GlDeprecatedDropdownItem, GlButton } from '@gitlab/ui';
+import { GlDropdown, GlDropdownItem } from '@gitlab/ui';
import { s__ } from '~/locale';
import Tracking from '~/tracking';
import { trackAlertStatusUpdateOptions } from '../constants';
-import updateAlertStatus from '../graphql/mutations/update_alert_status.mutation.graphql';
+import updateAlertStatusMutation from '../graphql/mutations/update_alert_status.mutation.graphql';
export default {
i18n: {
@@ -18,9 +18,8 @@ export default {
RESOLVED: s__('AlertManagement|Resolved'),
},
components: {
- GlDeprecatedDropdown,
- GlDeprecatedDropdownItem,
- GlButton,
+ GlDropdown,
+ GlDropdownItem,
},
props: {
projectPath: {
@@ -51,7 +50,7 @@ export default {
this.$emit('handle-updating', true);
this.$apollo
.mutate({
- mutation: updateAlertStatus,
+ mutation: updateAlertStatusMutation,
variables: {
iid: this.alert.iid,
status: status.toUpperCase(),
@@ -60,8 +59,6 @@ export default {
})
.then(resp => {
this.trackStatusUpdate(status);
- this.$emit('hide-dropdown');
-
const errors = resp.data?.updateAlertStatus?.errors || [];
if (errors[0]) {
@@ -70,6 +67,8 @@ export default {
`${this.$options.i18n.UPDATE_ALERT_STATUS_ERROR} ${errors[0]}`,
);
}
+
+ this.$emit('hide-dropdown');
})
.catch(() => {
this.$emit(
@@ -91,39 +90,30 @@ export default {
<template>
<div class="dropdown dropdown-menu-selectable" :class="dropdownClass">
- <gl-deprecated-dropdown
+ <gl-dropdown
ref="dropdown"
right
:text="$options.statuses[alert.status]"
class="w-100"
toggle-class="dropdown-menu-toggle"
- variant="outline-default"
@keydown.esc.native="$emit('hide-dropdown')"
@hide="$emit('hide-dropdown')"
>
- <div v-if="isSidebar" class="dropdown-title gl-display-flex">
- <span class="alert-title gl-ml-auto">{{ s__('AlertManagement|Assign status') }}</span>
- <gl-button
- :aria-label="__('Close')"
- variant="link"
- class="dropdown-title-button dropdown-menu-close gl-ml-auto gl-text-black-normal!"
- icon="close"
- @click="$emit('hide-dropdown')"
- />
- </div>
+ <p v-if="isSidebar" class="gl-new-dropdown-header-top" data-testid="dropdown-header">
+ {{ s__('AlertManagement|Assign status') }}
+ </p>
<div class="dropdown-content dropdown-body">
- <gl-deprecated-dropdown-item
+ <gl-dropdown-item
v-for="(label, field) in $options.statuses"
:key="field"
data-testid="statusDropdownItem"
- class="gl-vertical-align-middle"
:active="label.toUpperCase() === alert.status"
:active-class="'is-active'"
@click="updateAlertStatus(label)"
>
{{ label }}
- </gl-deprecated-dropdown-item>
+ </gl-dropdown-item>
</div>
- </gl-deprecated-dropdown>
+ </gl-dropdown>
</div>
</template>
diff --git a/app/assets/javascripts/alert_management/components/alert_summary_row.vue b/app/assets/javascripts/alert_management/components/alert_summary_row.vue
new file mode 100644
index 00000000000..13835b7e2fa
--- /dev/null
+++ b/app/assets/javascripts/alert_management/components/alert_summary_row.vue
@@ -0,0 +1,18 @@
+<script>
+export default {
+ props: {
+ label: {
+ type: String,
+ required: true,
+ },
+ },
+};
+</script>
+<template>
+ <div class="gl-my-5 gl-display-flex">
+ <div class="gl-font-weight-bold gl-w-13 gl-text-right gl-pr-3">{{ label }}</div>
+ <div class="gl-pl-2">
+ <slot></slot>
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/alert_management/components/sidebar/sidebar_assignee.vue b/app/assets/javascripts/alert_management/components/sidebar/sidebar_assignee.vue
index 0a1478ef5fe..df07038151e 100644
--- a/app/assets/javascripts/alert_management/components/sidebar/sidebar_assignee.vue
+++ b/app/assets/javascripts/alert_management/components/sidebar/sidebar_assignee.vue
@@ -1,9 +1,9 @@
<script>
-import { GlDeprecatedDropdownItem } from '@gitlab/ui';
+import { GlDropdownItem } from '@gitlab/ui';
export default {
components: {
- GlDeprecatedDropdownItem,
+ GlDropdownItem,
},
props: {
user: {
@@ -24,7 +24,7 @@ export default {
</script>
<template>
- <gl-deprecated-dropdown-item
+ <gl-dropdown-item
:key="user.username"
data-testid="assigneeDropdownItem"
class="assignee-dropdown-item gl-vertical-align-middle"
@@ -47,5 +47,5 @@ export default {
</strong>
<span class="dropdown-menu-user-username"> {{ user.username }}</span>
</span>
- </gl-deprecated-dropdown-item>
+ </gl-dropdown-item>
</template>
diff --git a/app/assets/javascripts/alert_management/components/sidebar/sidebar_assignees.vue b/app/assets/javascripts/alert_management/components/sidebar/sidebar_assignees.vue
index 0f354e85e96..5e4fd56738b 100644
--- a/app/assets/javascripts/alert_management/components/sidebar/sidebar_assignees.vue
+++ b/app/assets/javascripts/alert_management/components/sidebar/sidebar_assignees.vue
@@ -1,10 +1,11 @@
<script>
import {
GlIcon,
- GlDeprecatedDropdown,
- GlDeprecatedDropdownDivider,
- GlDeprecatedDropdownHeader,
- GlDeprecatedDropdownItem,
+ GlDropdown,
+ GlDropdownDivider,
+ GlDropdownSectionHeader,
+ GlDropdownItem,
+ GlSearchBoxByType,
GlLoadingIcon,
GlTooltip,
GlButton,
@@ -33,10 +34,11 @@ export default {
},
components: {
GlIcon,
- GlDeprecatedDropdown,
- GlDeprecatedDropdownItem,
- GlDeprecatedDropdownDivider,
- GlDeprecatedDropdownHeader,
+ GlDropdown,
+ GlDropdownItem,
+ GlDropdownDivider,
+ GlDropdownSectionHeader,
+ GlSearchBoxByType,
GlLoadingIcon,
GlTooltip,
GlButton,
@@ -216,48 +218,32 @@ export default {
</p>
<div class="dropdown dropdown-menu-selectable" :class="dropdownClass">
- <gl-deprecated-dropdown
+ <gl-dropdown
ref="dropdown"
:text="userName"
class="w-100"
toggle-class="dropdown-menu-toggle"
- variant="outline-default"
@keydown.esc.native="hideDropdown"
@hide="hideDropdown"
>
- <div class="dropdown-title gl-display-flex">
- <span class="alert-title gl-ml-auto">{{ __('Assign To') }}</span>
- <gl-button
- :aria-label="__('Close')"
- variant="link"
- class="dropdown-title-button dropdown-menu-close gl-ml-auto gl-text-black-normal!"
- icon="close"
- @click="hideDropdown"
- />
- </div>
- <div class="dropdown-input">
- <input
- v-model.trim="search"
- class="dropdown-input-field"
- type="search"
- :placeholder="__('Search users')"
- />
- <gl-icon name="search" class="dropdown-input-search ic-search" data-hidden="true" />
- </div>
+ <p class="gl-new-dropdown-header-top">
+ {{ __('Assign To') }}
+ </p>
+ <gl-search-box-by-type v-model.trim="search" :placeholder="__('Search users')" />
<div class="dropdown-content dropdown-body">
<template v-if="userListValid">
- <gl-deprecated-dropdown-item
+ <gl-dropdown-item
:active="!userName"
active-class="is-active"
@click="updateAlertAssignees('')"
>
{{ __('Unassigned') }}
- </gl-deprecated-dropdown-item>
- <gl-deprecated-dropdown-divider />
+ </gl-dropdown-item>
+ <gl-dropdown-divider />
- <gl-deprecated-dropdown-header class="mt-0">
+ <gl-dropdown-section-header>
{{ __('Assignee') }}
- </gl-deprecated-dropdown-header>
+ </gl-dropdown-section-header>
<sidebar-assignee
v-for="user in sortedUsers"
:key="user.username"
@@ -266,12 +252,12 @@ export default {
@update-alert-assignees="updateAlertAssignees"
/>
</template>
- <gl-deprecated-dropdown-item v-else-if="userListEmpty">
+ <p v-else-if="userListEmpty" class="mx-3 my-2">
{{ __('No Matching Results') }}
- </gl-deprecated-dropdown-item>
+ </p>
<gl-loading-icon v-else />
</div>
- </gl-deprecated-dropdown>
+ </gl-dropdown>
</div>
<gl-loading-icon v-if="isUpdating" :inline="true" />
diff --git a/app/assets/javascripts/alert_management/components/system_notes/system_note.vue b/app/assets/javascripts/alert_management/components/system_notes/system_note.vue
index 0b206ce42f4..3705e36a579 100644
--- a/app/assets/javascripts/alert_management/components/system_notes/system_note.vue
+++ b/app/assets/javascripts/alert_management/components/system_notes/system_note.vue
@@ -1,11 +1,12 @@
<script>
/* eslint-disable vue/no-v-html */
+import { GlIcon } from '@gitlab/ui';
import NoteHeader from '~/notes/components/note_header.vue';
-import { spriteIcon } from '~/lib/utils/common_utils';
export default {
components: {
NoteHeader,
+ GlIcon,
},
props: {
note: {
@@ -24,23 +25,23 @@ export default {
} = this.note;
return { ...author, id: id?.split('/').pop() };
},
- iconHtml() {
- return spriteIcon(this.note?.systemNoteIconName);
- },
},
};
</script>
<template>
- <li :id="noteAnchorId" class="timeline-entry note system-note note-wrapper gl-px-0!">
- <div class="timeline-entry-inner">
- <div class="timeline-icon" v-html="iconHtml"></div>
- <div class="timeline-content">
- <div class="note-header">
- <note-header :author="noteAuthor" :created-at="note.createdAt" :note-id="note.id">
- <span v-html="note.bodyHtml"></span>
- </note-header>
- </div>
+ <li :id="noteAnchorId" class="timeline-entry note system-note note-wrapper gl-p-0!">
+ <div class="gl-display-inline-flex gl-align-items-center">
+ <div
+ class="gl-display-inline gl-bg-white gl-text-gray-200 gl-border-gray-100 gl-border-1 gl-border-solid gl-rounded-full gl-box-sizing-content-box gl-p-3 gl-mt-n2 gl-mr-6"
+ >
+ <gl-icon :name="note.systemNoteIconName" />
+ </div>
+
+ <div class="note-header">
+ <note-header :author="noteAuthor" :created-at="note.createdAt" :note-id="note.id">
+ <span v-html="note.bodyHtml"></span>
+ </note-header>
</div>
</div>
</li>
diff --git a/app/assets/javascripts/alert_management/constants.js b/app/assets/javascripts/alert_management/constants.js
index 73cb5ecdf98..b79a64646eb 100644
--- a/app/assets/javascripts/alert_management/constants.js
+++ b/app/assets/javascripts/alert_management/constants.js
@@ -63,5 +63,3 @@ export const trackAlertStatusUpdateOptions = {
action: 'update_alert_status',
label: 'Status',
};
-
-export const DEFAULT_PAGE_SIZE = 20;
diff --git a/app/assets/javascripts/alert_management/details.js b/app/assets/javascripts/alert_management/details.js
index c2020dfcbe3..cbbdecae390 100644
--- a/app/assets/javascripts/alert_management/details.js
+++ b/app/assets/javascripts/alert_management/details.js
@@ -1,11 +1,11 @@
+import { defaultDataIdFromObject } from 'apollo-cache-inmemory';
+import produce from 'immer';
import Vue from 'vue';
import VueApollo from 'vue-apollo';
-import produce from 'immer';
-import { defaultDataIdFromObject } from 'apollo-cache-inmemory';
import createDefaultClient from '~/lib/graphql';
-import createRouter from './router';
import AlertDetails from './components/alert_details.vue';
import sidebarStatusQuery from './graphql/queries/sidebar_status.query.graphql';
+import createRouter from './router';
Vue.use(VueApollo);
diff --git a/app/assets/javascripts/alert_management/graphql/fragments/detail_item.fragment.graphql b/app/assets/javascripts/alert_management/graphql/fragments/detail_item.fragment.graphql
index 0712ff12c23..406dfe97ce0 100644
--- a/app/assets/javascripts/alert_management/graphql/fragments/detail_item.fragment.graphql
+++ b/app/assets/javascripts/alert_management/graphql/fragments/detail_item.fragment.graphql
@@ -10,6 +10,11 @@ fragment AlertDetailItem on AlertManagementAlert {
description
updatedAt
endedAt
+ hosts
+ environment {
+ name
+ path
+ }
details
runbook
todos {
diff --git a/app/assets/javascripts/alert_management/graphql/queries/get_alerts.query.graphql b/app/assets/javascripts/alert_management/graphql/queries/get_alerts.query.graphql
index 8ac00bbc6b5..bc7e51a2e90 100644
--- a/app/assets/javascripts/alert_management/graphql/queries/get_alerts.query.graphql
+++ b/app/assets/javascripts/alert_management/graphql/queries/get_alerts.query.graphql
@@ -1,7 +1,6 @@
#import "../fragments/list_item.fragment.graphql"
query getAlerts(
- $searchTerm: String
$projectPath: ID!
$statuses: [AlertManagementStatus!]
$sort: AlertManagementAlertSort
@@ -9,10 +8,13 @@ query getAlerts(
$lastPageSize: Int
$prevPageCursor: String = ""
$nextPageCursor: String = ""
+ $searchTerm: String = ""
+ $assigneeUsername: String = ""
) {
project(fullPath: $projectPath) {
alertManagementAlerts(
search: $searchTerm
+ assigneeUsername: $assigneeUsername
statuses: $statuses
sort: $sort
first: $firstPageSize
diff --git a/app/assets/javascripts/alert_management/graphql/queries/get_count_by_status.query.graphql b/app/assets/javascripts/alert_management/graphql/queries/get_count_by_status.query.graphql
index 5a6faea5cd8..40ec4c56171 100644
--- a/app/assets/javascripts/alert_management/graphql/queries/get_count_by_status.query.graphql
+++ b/app/assets/javascripts/alert_management/graphql/queries/get_count_by_status.query.graphql
@@ -1,6 +1,6 @@
-query getAlertsCount($searchTerm: String, $projectPath: ID!) {
+query getAlertsCount($searchTerm: String, $projectPath: ID!, $assigneeUsername: String = "") {
project(fullPath: $projectPath) {
- alertManagementAlertStatusCounts(search: $searchTerm) {
+ alertManagementAlertStatusCounts(search: $searchTerm, assigneeUsername: $assigneeUsername) {
all
open
acknowledged
diff --git a/app/assets/javascripts/alert_management/list.js b/app/assets/javascripts/alert_management/list.js
index e180ab5f7e3..e34450204fb 100644
--- a/app/assets/javascripts/alert_management/list.js
+++ b/app/assets/javascripts/alert_management/list.js
@@ -18,12 +18,12 @@ export default () => {
populatingAlertsHelpUrl,
alertsHelpUrl,
opsgenieMvcTargetUrl,
+ textQuery,
+ assigneeUsernameQuery,
+ alertManagementEnabled,
+ userCanEnableAlertManagement,
+ opsgenieMvcEnabled,
} = domEl.dataset;
- let { alertManagementEnabled, userCanEnableAlertManagement, opsgenieMvcEnabled } = domEl.dataset;
-
- alertManagementEnabled = parseBoolean(alertManagementEnabled);
- userCanEnableAlertManagement = parseBoolean(userCanEnableAlertManagement);
- opsgenieMvcEnabled = parseBoolean(opsgenieMvcEnabled);
const apolloProvider = new VueApollo({
defaultClient: createDefaultClient(
@@ -50,23 +50,24 @@ export default () => {
return new Vue({
el: selector,
+ provide: {
+ projectPath,
+ textQuery,
+ assigneeUsernameQuery,
+ enableAlertManagementPath,
+ populatingAlertsHelpUrl,
+ emptyAlertSvgPath,
+ opsgenieMvcTargetUrl,
+ alertManagementEnabled: parseBoolean(alertManagementEnabled),
+ userCanEnableAlertManagement: parseBoolean(userCanEnableAlertManagement),
+ opsgenieMvcEnabled: parseBoolean(opsgenieMvcEnabled),
+ },
apolloProvider,
components: {
AlertManagementList,
},
render(createElement) {
- return createElement('alert-management-list', {
- props: {
- projectPath,
- enableAlertManagementPath,
- populatingAlertsHelpUrl,
- emptyAlertSvgPath,
- alertManagementEnabled,
- userCanEnableAlertManagement,
- opsgenieMvcTargetUrl,
- opsgenieMvcEnabled,
- },
- });
+ return createElement('alert-management-list');
},
});
};
diff --git a/app/assets/javascripts/alerts_service_settings/components/alerts_service_form.vue b/app/assets/javascripts/alerts_service_settings/components/alerts_service_form.vue
index c5e213d7dc9..f2394ce385f 100644
--- a/app/assets/javascripts/alerts_service_settings/components/alerts_service_form.vue
+++ b/app/assets/javascripts/alerts_service_settings/components/alerts_service_form.vue
@@ -180,11 +180,9 @@ export default {
/>
</span>
</div>
- <span class="gl-display-flex gl-justify-content-end">
- <gl-button v-gl-modal.authKeyModal class="gl-mt-2" :disabled="isDisabled">{{
- $options.RESET_KEY
- }}</gl-button>
- </span>
+ <gl-button v-gl-modal.authKeyModal class="gl-mt-2" :disabled="isDisabled">{{
+ $options.RESET_KEY
+ }}</gl-button>
<gl-modal
modal-id="authKeyModal"
:title="$options.RESET_KEY"
diff --git a/app/assets/javascripts/alerts_settings/components/alerts_integrations_list.vue b/app/assets/javascripts/alerts_settings/components/alerts_integrations_list.vue
new file mode 100644
index 00000000000..217442e6131
--- /dev/null
+++ b/app/assets/javascripts/alerts_settings/components/alerts_integrations_list.vue
@@ -0,0 +1,109 @@
+<script>
+import { GlTable, GlIcon, GlTooltipDirective } from '@gitlab/ui';
+import { s__, __ } from '~/locale';
+import Tracking from '~/tracking';
+import { trackAlertIntergrationsViewsOptions } from '../constants';
+
+export const i18n = {
+ title: s__('AlertsIntegrations|Current integrations'),
+ emptyState: s__('AlertsIntegrations|No integrations have been added yet'),
+ status: {
+ enabled: {
+ name: __('Enabled'),
+ tooltip: s__('AlertsIntegrations|Alerts will be created through this integration'),
+ },
+ disabled: {
+ name: __('Disabled'),
+ tooltip: s__('AlertsIntegrations|Alerts will not be created through this integration'),
+ },
+ },
+};
+
+const bodyTrClass =
+ 'gl-border-1 gl-border-t-solid gl-border-b-solid gl-border-gray-100 gl-hover-cursor-pointer gl-hover-bg-blue-50 gl-hover-border-blue-200';
+
+export default {
+ i18n,
+ components: {
+ GlTable,
+ GlIcon,
+ },
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ },
+ props: {
+ integrations: {
+ type: Array,
+ required: false,
+ default: () => [],
+ },
+ },
+ fields: [
+ {
+ key: 'activated',
+ label: __('Status'),
+ },
+ {
+ key: 'name',
+ label: s__('AlertsIntegrations|Integration Name'),
+ },
+ {
+ key: 'type',
+ label: __('Type'),
+ },
+ ],
+ computed: {
+ tbodyTrClass() {
+ return {
+ [bodyTrClass]: this.integrations.length,
+ };
+ },
+ },
+ mounted() {
+ this.trackPageViews();
+ },
+ methods: {
+ trackPageViews() {
+ const { category, action } = trackAlertIntergrationsViewsOptions;
+ Tracking.event(category, action);
+ },
+ },
+};
+</script>
+
+<template>
+ <div class="incident-management-list">
+ <h5 class="gl-font-lg">{{ $options.i18n.title }}</h5>
+ <gl-table
+ :empty-text="$options.i18n.emptyState"
+ :items="integrations"
+ :fields="$options.fields"
+ stacked="md"
+ :tbody-tr-class="tbodyTrClass"
+ show-empty
+ >
+ <template #cell(activated)="{ item }">
+ <span v-if="item.activated" data-testid="integration-activated-status">
+ <gl-icon
+ v-gl-tooltip
+ name="check-circle-filled"
+ :size="16"
+ class="gl-text-green-500 gl-hover-cursor-pointer gl-mr-3"
+ :title="$options.i18n.status.enabled.tooltip"
+ />
+ {{ $options.i18n.status.enabled.name }}
+ </span>
+ <span v-else data-testid="integration-activated-status">
+ <gl-icon
+ v-gl-tooltip
+ name="warning-solid"
+ :size="16"
+ class="gl-text-red-600 gl-hover-cursor-pointer gl-mr-3"
+ :title="$options.i18n.status.disabled.tooltip"
+ />
+ {{ $options.i18n.status.disabled.name }}
+ </span>
+ </template>
+ </gl-table>
+ </div>
+</template>
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 f0bb8b0a90f..f885afae378 100644
--- a/app/assets/javascripts/alerts_settings/components/alerts_settings_form.vue
+++ b/app/assets/javascripts/alerts_settings/components/alerts_settings_form.vue
@@ -14,9 +14,11 @@ import {
GlFormSelect,
} from '@gitlab/ui';
import { debounce } from 'lodash';
-import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
+import { s__ } from '~/locale';
+import { doesHashExistInUrl } from '~/lib/utils/url_utility';
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
import ToggleButton from '~/vue_shared/components/toggle_button.vue';
+import IntegrationsList from './alerts_integrations_list.vue';
import csrf from '~/lib/utils/csrf';
import service from '../services';
import {
@@ -25,7 +27,9 @@ import {
JSON_VALIDATE_DELAY,
targetPrometheusUrlPlaceholder,
targetOpsgenieUrlPlaceholder,
+ sectionHash,
} from '../constants';
+import createFlash, { FLASH_TYPES } from '~/flash';
export default {
i18n,
@@ -46,11 +50,11 @@ export default {
GlSprintf,
ClipboardButton,
ToggleButton,
+ IntegrationsList,
},
directives: {
'gl-modal': GlModalDirective,
},
- mixins: [glFeatureFlagsMixin()],
inject: ['prometheus', 'generic', 'opsgenie'],
data() {
return {
@@ -148,6 +152,20 @@ export default {
? this.$options.targetOpsgenieUrlPlaceholder
: this.$options.targetPrometheusUrlPlaceholder;
},
+ integrations() {
+ return [
+ {
+ name: s__('AlertSettings|HTTP endpoint'),
+ type: s__('AlertsIntegrations|HTTP endpoint'),
+ activated: this.generic.activated,
+ },
+ {
+ name: s__('AlertSettings|External Prometheus'),
+ type: s__('AlertsIntegrations|Prometheus'),
+ activated: this.prometheus.activated,
+ },
+ ];
+ },
},
watch: {
'testAlert.json': debounce(function debouncedJsonValidate() {
@@ -173,9 +191,12 @@ export default {
this.authKey = this.selectedService.authKey ?? '';
},
methods: {
- createUserErrorMessage(errors = { error: [''] }) {
- // eslint-disable-next-line prefer-destructuring
- this.serverError = errors.error[0];
+ createUserErrorMessage(errors = {}) {
+ const error = Object.entries(errors)?.[0];
+ if (error) {
+ const [field, [msg]] = error;
+ this.serverError = `${field} ${msg}`;
+ }
},
setOpsgenieAsDefault() {
this.options = this.options.map(el => {
@@ -245,29 +266,11 @@ export default {
? { service: { opsgenie_mvc_target_url: this.targetUrl, opsgenie_mvc_enabled: value } }
: { service: { active: value } },
})
- .then(() => {
- this.active = value;
- this.toggleSuccess(value);
-
- if (!this.isOpsgenie && value) {
- if (!this.selectedService.authKey) {
- return window.location.reload();
- }
-
- return this.removeOpsGenieOption();
- }
-
- if (this.isOpsgenie && value) {
- return this.setOpsgenieAsDefault();
- }
-
- // eslint-disable-next-line no-return-assign
- return (this.options = serviceOptions);
- })
+ .then(() => this.notifySuccessAndReload())
.catch(({ response: { data: { errors } = {} } = {} }) => {
this.createUserErrorMessage(errors);
this.setFeedback({
- feedbackMessage: `${this.$options.i18n.errorMsg}.`,
+ feedbackMessage: this.$options.i18n.errorMsg,
variant: 'danger',
});
})
@@ -276,6 +279,12 @@ export default {
this.canSaveForm = false;
});
},
+ reload() {
+ if (!doesHashExistInUrl(sectionHash)) {
+ window.location.hash = sectionHash;
+ }
+ window.location.reload();
+ },
togglePrometheusActive(value) {
this.loading = true;
return service
@@ -288,15 +297,11 @@ export default {
redirect: window.location,
},
})
- .then(() => {
- this.active = value;
- this.toggleSuccess(value);
- this.removeOpsGenieOption();
- })
+ .then(() => this.notifySuccessAndReload())
.catch(({ response: { data: { errors } = {} } = {} }) => {
this.createUserErrorMessage(errors);
this.setFeedback({
- feedbackMessage: `${this.$options.i18n.errorMsg}.`,
+ feedbackMessage: this.$options.i18n.errorMsg,
variant: 'danger',
});
})
@@ -305,18 +310,9 @@ export default {
this.canSaveForm = false;
});
},
- toggleSuccess(value) {
- if (value) {
- this.setFeedback({
- feedbackMessage: this.$options.i18n.endPointActivated,
- variant: 'info',
- });
- } else {
- this.setFeedback({
- feedbackMessage: this.$options.i18n.changesSaved,
- variant: 'info',
- });
- }
+ notifySuccessAndReload() {
+ createFlash({ message: this.$options.i18n.changesSaved, type: FLASH_TYPES.NOTICE });
+ setTimeout(() => this.reload(), 1000);
},
setFeedback({ feedbackMessage, variant }) {
this.feedback = { feedbackMessage, variant };
@@ -375,47 +371,50 @@ export default {
<template>
<div>
- <gl-alert v-if="showFeedbackMsg" :variant="feedback.variant" @dismiss="dismissFeedback">
- {{ feedback.feedbackMessage }}
- <br />
- <i v-if="serverError">{{ __('Error message:') }} {{ serverError }}</i>
- <gl-button
- v-if="showAlertSave"
- variant="danger"
- category="primary"
- class="gl-display-block gl-mt-3"
- @click="toggle(active)"
- >
- {{ __('Save anyway') }}
- </gl-button>
- </gl-alert>
- <div data-testid="alert-settings-description" class="gl-mt-5">
- <p v-for="section in sections" :key="section.text">
- <gl-sprintf :message="section.text">
- <template #link="{ content }">
- <gl-link :href="section.url" target="_blank">{{ content }}</gl-link>
- </template>
- </gl-sprintf>
- </p>
- </div>
+ <integrations-list :integrations="integrations" />
+
<gl-form @submit.prevent="onSubmit" @reset.prevent="onReset">
- <gl-form-group
- :label="$options.i18n.integrationsLabel"
- label-for="integrations"
- label-class="label-bold"
- >
+ <h5 class="gl-font-lg gl-my-5">{{ $options.i18n.integrationsLabel }}</h5>
+
+ <gl-alert v-if="showFeedbackMsg" :variant="feedback.variant" @dismiss="dismissFeedback">
+ {{ feedback.feedbackMessage }}
+ <br />
+ <i v-if="serverError">{{ __('Error message:') }} {{ serverError }}</i>
+ <gl-button
+ v-if="showAlertSave"
+ variant="danger"
+ category="primary"
+ class="gl-display-block gl-mt-3"
+ @click="toggle(active)"
+ >
+ {{ __('Save anyway') }}
+ </gl-button>
+ </gl-alert>
+
+ <div data-testid="alert-settings-description">
+ <p v-for="section in sections" :key="section.text">
+ <gl-sprintf :message="section.text">
+ <template #link="{ content }">
+ <gl-link :href="section.url" target="_blank">{{ content }}</gl-link>
+ </template>
+ </gl-sprintf>
+ </p>
+ </div>
+
+ <gl-form-group label-for="integration-type" :label="$options.i18n.integration">
<gl-form-select
+ id="integration-type"
v-model="selectedEndpoint"
:options="options"
data-testid="alert-settings-select"
@change="resetFormValues"
/>
- <span class="gl-text-gray-200">
+ <span class="gl-text-gray-500">
<gl-sprintf :message="$options.i18n.integrationsInfo">
<template #link="{ content }">
<gl-link
class="gl-display-inline-block"
- href="https://gitlab.com/groups/gitlab-org/-/epics/3362"
+ href="https://gitlab.com/groups/gitlab-org/-/epics/4390"
target="_blank"
>{{ content }}</gl-link
>
@@ -423,11 +422,7 @@ export default {
</gl-sprintf>
</span>
</gl-form-group>
- <gl-form-group
- :label="$options.i18n.activeLabel"
- label-for="activated"
- label-class="label-bold"
- >
+ <gl-form-group :label="$options.i18n.activeLabel" label-for="activated">
<toggle-button
id="activated"
:disabled-input="loading"
@@ -440,7 +435,6 @@ export default {
v-if="isOpsgenie || isPrometheus"
:label="$options.i18n.apiBaseUrlLabel"
label-for="api-url"
- label-class="label-bold"
>
<gl-form-input
id="api-url"
@@ -449,12 +443,12 @@ export default {
:placeholder="baseUrlPlaceholder"
:disabled="!active"
/>
- <span class="gl-text-gray-200">
+ <span class="gl-text-gray-500">
{{ $options.i18n.apiBaseUrlHelpText }}
</span>
</gl-form-group>
<template v-if="!isOpsgenie">
- <gl-form-group :label="$options.i18n.urlLabel" label-for="url" label-class="label-bold">
+ <gl-form-group :label="$options.i18n.urlLabel" label-for="url">
<gl-form-input-group id="url" readonly :value="selectedService.url">
<template #append>
<clipboard-button
@@ -464,15 +458,11 @@ export default {
/>
</template>
</gl-form-input-group>
- <span class="gl-text-gray-200">
+ <span class="gl-text-gray-500">
{{ prometheusInfo }}
</span>
</gl-form-group>
- <gl-form-group
- :label="$options.i18n.authKeyLabel"
- label-for="authorization-key"
- label-class="label-bold"
- >
+ <gl-form-group :label="$options.i18n.authKeyLabel" label-for="authorization-key">
<gl-form-input-group id="authorization-key" class="gl-mb-2" readonly :value="authKey">
<template #append>
<clipboard-button
@@ -498,7 +488,6 @@ export default {
<gl-form-group
:label="$options.i18n.alertJson"
label-for="alert-json"
- label-class="label-bold"
:invalid-feedback="testAlert.error"
>
<gl-form-textarea
@@ -511,16 +500,11 @@ export default {
max-rows="10"
/>
</gl-form-group>
- <div class="gl-display-flex gl-justify-content-end">
- <gl-button :disabled="!canTestAlert" @click="validateTestAlert">{{
- $options.i18n.testAlertInfo
- }}</gl-button>
- </div>
+ <gl-button :disabled="!canTestAlert" @click="validateTestAlert">{{
+ $options.i18n.testAlertInfo
+ }}</gl-button>
</template>
<div class="footer-block row-content-block gl-display-flex gl-justify-content-space-between">
- <gl-button category="primary" :disabled="!canSaveConfig" @click="onReset">
- {{ __('Cancel') }}
- </gl-button>
<gl-button
variant="success"
category="primary"
@@ -529,6 +513,9 @@ export default {
>
{{ __('Save changes') }}
</gl-button>
+ <gl-button category="primary" :disabled="!canSaveConfig" @click="onReset">
+ {{ __('Cancel') }}
+ </gl-button>
</div>
</gl-form>
</div>
diff --git a/app/assets/javascripts/alerts_settings/constants.js b/app/assets/javascripts/alerts_settings/constants.js
index fc669995875..4220dbde0c7 100644
--- a/app/assets/javascripts/alerts_settings/constants.js
+++ b/app/assets/javascripts/alerts_settings/constants.js
@@ -7,22 +7,21 @@ export const i18n = {
setupSection: s__(
"AlertSettings|Review your external service's documentation to learn where to provide this information to your external service, and the %{linkStart}GitLab documentation%{linkEnd} to learn more about configuring your endpoint.",
),
- errorMsg: s__('AlertSettings|There was an error updating the alert settings'),
+ errorMsg: s__('AlertSettings|There was an error updating the alert settings.'),
errorKeyMsg: s__(
'AlertSettings|There was an error while trying to reset the key. Please refresh the page to try again.',
),
restKeyInfo: s__(
'AlertSettings|Resetting the authorization key for this project will require updating the authorization key in every alert source it is enabled in.',
),
- endPointActivated: s__('AlertSettings|Alerts endpoint successfully activated.'),
- changesSaved: s__('AlertSettings|Your changes were successfully updated.'),
+ changesSaved: s__('AlertSettings|Your integration was successfully updated.'),
prometheusInfo: s__('AlertSettings|Add URL and auth key to your Prometheus config file'),
integrationsInfo: s__(
- 'AlertSettings|Learn more about our %{linkStart}upcoming integrations%{linkEnd}',
+ 'AlertSettings|Learn more about our improvements for %{linkStart}integrations%{linkEnd}',
),
resetKey: s__('AlertSettings|Reset key'),
copyToClipboard: s__('AlertSettings|Copy'),
- integrationsLabel: s__('AlertSettings|Integrations'),
+ integrationsLabel: s__('AlertSettings|Add new integrations'),
apiBaseUrlLabel: s__('AlertSettings|API URL'),
authKeyLabel: s__('AlertSettings|Authorization key'),
urlLabel: s__('AlertSettings|Webhook URL'),
@@ -38,10 +37,11 @@ export const i18n = {
authKeyRest: s__(
'AlertSettings|Authorization key has been successfully reset. Please save your changes now.',
),
+ integration: s__('AlertSettings|Integration'),
};
export const serviceOptions = [
- { value: 'generic', text: s__('AlertSettings|Generic') },
+ { value: 'generic', text: s__('AlertSettings|HTTP Endpoint') },
{ value: 'prometheus', text: s__('AlertSettings|External Prometheus') },
{ value: 'opsgenie', text: s__('AlertSettings|Opsgenie') },
];
@@ -50,3 +50,15 @@ export const JSON_VALIDATE_DELAY = 250;
export const targetPrometheusUrlPlaceholder = 'http://prometheus.example.com/';
export const targetOpsgenieUrlPlaceholder = 'https://app.opsgenie.com/alert/list/';
+
+export const sectionHash = 'js-alert-management-settings';
+
+/* eslint-disable @gitlab/require-i18n-strings */
+
+/**
+ * Tracks snowplow event when user views alerts intergration list
+ */
+export const trackAlertIntergrationsViewsOptions = {
+ category: 'Alert Intergrations',
+ action: 'view_alert_integrations_list',
+};
diff --git a/app/assets/javascripts/analytics/instance_statistics/components/app.vue b/app/assets/javascripts/analytics/instance_statistics/components/app.vue
new file mode 100644
index 00000000000..7aa5c98aa0b
--- /dev/null
+++ b/app/assets/javascripts/analytics/instance_statistics/components/app.vue
@@ -0,0 +1,30 @@
+<script>
+import InstanceCounts from './instance_counts.vue';
+import PipelinesChart from './pipelines_chart.vue';
+import UsersChart from './users_chart.vue';
+import { TODAY, TOTAL_DAYS_TO_SHOW, START_DATE } from '../constants';
+
+export default {
+ name: 'InstanceStatisticsApp',
+ components: {
+ InstanceCounts,
+ PipelinesChart,
+ UsersChart,
+ },
+ TOTAL_DAYS_TO_SHOW,
+ START_DATE,
+ TODAY,
+};
+</script>
+
+<template>
+ <div>
+ <instance-counts />
+ <users-chart
+ :start-date="$options.START_DATE"
+ :end-date="$options.TODAY"
+ :total-data-points="$options.TOTAL_DAYS_TO_SHOW"
+ />
+ <pipelines-chart />
+ </div>
+</template>
diff --git a/app/assets/javascripts/analytics/instance_statistics/components/instance_counts.vue b/app/assets/javascripts/analytics/instance_statistics/components/instance_counts.vue
new file mode 100644
index 00000000000..4fbfb4daf22
--- /dev/null
+++ b/app/assets/javascripts/analytics/instance_statistics/components/instance_counts.vue
@@ -0,0 +1,64 @@
+<script>
+import * as Sentry from '~/sentry/wrapper';
+import { s__ } from '~/locale';
+import { deprecatedCreateFlash as createFlash } from '~/flash';
+import { SUPPORTED_FORMATS, getFormatter } from '~/lib/utils/unit_format';
+import MetricCard from '~/analytics/shared/components/metric_card.vue';
+import instanceStatisticsCountQuery from '../graphql/queries/instance_statistics_count.query.graphql';
+
+const defaultPrecision = 0;
+
+export default {
+ name: 'InstanceCounts',
+ components: {
+ MetricCard,
+ },
+ data() {
+ return {
+ counts: [],
+ };
+ },
+ apollo: {
+ counts: {
+ query: instanceStatisticsCountQuery,
+ update(data) {
+ return Object.entries(data).map(([key, obj]) => {
+ const label = this.$options.i18n.labels[key];
+ const formatter = getFormatter(SUPPORTED_FORMATS.number);
+ const value = obj.nodes?.length ? formatter(obj.nodes[0].count, defaultPrecision) : null;
+
+ return {
+ key,
+ value,
+ label,
+ };
+ });
+ },
+ error(error) {
+ createFlash(this.$options.i18n.loadCountsError);
+ Sentry.captureException(error);
+ },
+ },
+ },
+ i18n: {
+ labels: {
+ users: s__('InstanceStatistics|Users'),
+ projects: s__('InstanceStatistics|Projects'),
+ groups: s__('InstanceStatistics|Groups'),
+ issues: s__('InstanceStatistics|Issues'),
+ mergeRequests: s__('InstanceStatistics|Merge Requests'),
+ pipelines: s__('InstanceStatistics|Pipelines'),
+ },
+ loadCountsError: s__('Could not load instance counts. Please refresh the page to try again.'),
+ },
+};
+</script>
+
+<template>
+ <metric-card
+ :title="__('Instance Statistics')"
+ :metrics="counts"
+ :is-loading="$apollo.queries.counts.loading"
+ class="gl-mt-4"
+ />
+</template>
diff --git a/app/assets/javascripts/analytics/instance_statistics/components/pipelines_chart.vue b/app/assets/javascripts/analytics/instance_statistics/components/pipelines_chart.vue
new file mode 100644
index 00000000000..b16d960402b
--- /dev/null
+++ b/app/assets/javascripts/analytics/instance_statistics/components/pipelines_chart.vue
@@ -0,0 +1,215 @@
+<script>
+import { GlLineChart } from '@gitlab/ui/dist/charts';
+import { GlAlert } from '@gitlab/ui';
+import { mapKeys, mapValues, pick, some, sum } from 'lodash';
+import ChartSkeletonLoader from '~/vue_shared/components/resizable_chart/skeleton_loader.vue';
+import { s__ } from '~/locale';
+import {
+ differenceInMonths,
+ formatDateAsMonth,
+ getDayDifference,
+} from '~/lib/utils/datetime_utility';
+import { getAverageByMonth, sortByDate, extractValues } from '../utils';
+import pipelineStatsQuery from '../graphql/queries/pipeline_stats.query.graphql';
+import { TODAY, START_DATE } from '../constants';
+
+const DATA_KEYS = [
+ 'pipelinesTotal',
+ 'pipelinesSucceeded',
+ 'pipelinesFailed',
+ 'pipelinesCanceled',
+ 'pipelinesSkipped',
+];
+const PREFIX = 'pipelines';
+
+export default {
+ name: 'PipelinesChart',
+ components: {
+ GlLineChart,
+ GlAlert,
+ ChartSkeletonLoader,
+ },
+ startDate: START_DATE,
+ endDate: TODAY,
+ i18n: {
+ loadPipelineChartError: s__(
+ 'InstanceAnalytics|Could not load the pipelines chart. Please refresh the page to try again.',
+ ),
+ noDataMessage: s__('InstanceAnalytics|There is no data available.'),
+ total: s__('InstanceAnalytics|Total'),
+ succeeded: s__('InstanceAnalytics|Succeeded'),
+ failed: s__('InstanceAnalytics|Failed'),
+ canceled: s__('InstanceAnalytics|Canceled'),
+ skipped: s__('InstanceAnalytics|Skipped'),
+ chartTitle: s__('InstanceAnalytics|Pipelines'),
+ yAxisTitle: s__('InstanceAnalytics|Items'),
+ xAxisTitle: s__('InstanceAnalytics|Month'),
+ },
+ data() {
+ return {
+ loading: true,
+ loadingError: null,
+ };
+ },
+ apollo: {
+ pipelineStats: {
+ query: pipelineStatsQuery,
+ variables() {
+ return {
+ firstTotal: this.totalDaysToShow,
+ firstSucceeded: this.totalDaysToShow,
+ firstFailed: this.totalDaysToShow,
+ firstCanceled: this.totalDaysToShow,
+ firstSkipped: this.totalDaysToShow,
+ };
+ },
+ update(data) {
+ const allData = extractValues(data, DATA_KEYS, PREFIX, 'nodes');
+ const allPageInfo = extractValues(data, DATA_KEYS, PREFIX, 'pageInfo');
+
+ return {
+ ...mapValues(allData, sortByDate),
+ ...allPageInfo,
+ };
+ },
+ result() {
+ if (this.hasNextPage) {
+ this.fetchNextPage();
+ }
+ },
+ error() {
+ this.handleError();
+ },
+ },
+ },
+ computed: {
+ isLoading() {
+ return this.$apollo.queries.pipelineStats.loading;
+ },
+ totalDaysToShow() {
+ return getDayDifference(this.$options.startDate, this.$options.endDate);
+ },
+ firstVariables() {
+ const allData = pick(this.pipelineStats, [
+ 'nodesTotal',
+ 'nodesSucceeded',
+ 'nodesFailed',
+ 'nodesCanceled',
+ 'nodesSkipped',
+ ]);
+ const allDayDiffs = mapValues(allData, data => {
+ const firstdataPoint = data[0];
+ if (!firstdataPoint) {
+ return 0;
+ }
+
+ return Math.max(
+ 0,
+ getDayDifference(this.$options.startDate, new Date(firstdataPoint.recordedAt)),
+ );
+ });
+
+ return mapKeys(allDayDiffs, (value, key) => key.replace('nodes', 'first'));
+ },
+ cursorVariables() {
+ const pageInfoKeys = [
+ 'pageInfoTotal',
+ 'pageInfoSucceeded',
+ 'pageInfoFailed',
+ 'pageInfoCanceled',
+ 'pageInfoSkipped',
+ ];
+
+ return extractValues(this.pipelineStats, pageInfoKeys, 'pageInfo', 'endCursor');
+ },
+ hasNextPage() {
+ return (
+ sum(Object.values(this.firstVariables)) > 0 &&
+ some(this.pipelineStats, ({ hasNextPage }) => hasNextPage)
+ );
+ },
+ hasEmptyDataSet() {
+ return this.chartData.every(({ data }) => data.length === 0);
+ },
+ chartData() {
+ const allData = pick(this.pipelineStats, [
+ 'nodesTotal',
+ 'nodesSucceeded',
+ 'nodesFailed',
+ 'nodesCanceled',
+ 'nodesSkipped',
+ ]);
+ const options = { shouldRound: true };
+ return Object.keys(allData).map(key => {
+ const i18nName = key.slice('nodes'.length).toLowerCase();
+ return {
+ name: this.$options.i18n[i18nName],
+ data: getAverageByMonth(allData[key], options),
+ };
+ });
+ },
+ range() {
+ return {
+ min: this.$options.startDate,
+ max: this.$options.endDate,
+ };
+ },
+ chartOptions() {
+ const { endDate, startDate, i18n } = this.$options;
+ return {
+ xAxis: {
+ ...this.range,
+ name: i18n.xAxisTitle,
+ type: 'time',
+ splitNumber: differenceInMonths(startDate, endDate) + 1,
+ axisLabel: {
+ interval: 0,
+ showMinLabel: false,
+ showMaxLabel: false,
+ align: 'right',
+ formatter: formatDateAsMonth,
+ },
+ },
+ yAxis: {
+ name: i18n.yAxisTitle,
+ },
+ };
+ },
+ },
+ methods: {
+ handleError() {
+ this.loadingError = true;
+ },
+ fetchNextPage() {
+ this.$apollo.queries.pipelineStats
+ .fetchMore({
+ variables: {
+ ...this.firstVariables,
+ ...this.cursorVariables,
+ },
+ updateQuery: (previousResult, { fetchMoreResult }) => {
+ return Object.keys(fetchMoreResult).reduce((memo, key) => {
+ const { nodes, ...rest } = fetchMoreResult[key];
+ const previousNodes = previousResult[key].nodes;
+ return { ...memo, [key]: { ...rest, nodes: [...previousNodes, ...nodes] } };
+ }, {});
+ },
+ })
+ .catch(this.handleError);
+ },
+ },
+};
+</script>
+<template>
+ <div>
+ <h3>{{ $options.i18n.chartTitle }}</h3>
+ <gl-alert v-if="loadingError" variant="danger" :dismissible="false" class="gl-mt-3">
+ {{ this.$options.i18n.loadPipelineChartError }}
+ </gl-alert>
+ <chart-skeleton-loader v-else-if="isLoading" />
+ <gl-alert v-else-if="hasEmptyDataSet" variant="info" :dismissible="false" class="gl-mt-3">
+ {{ $options.i18n.noDataMessage }}
+ </gl-alert>
+ <gl-line-chart v-else :option="chartOptions" :include-legend-avg-max="true" :data="chartData" />
+ </div>
+</template>
diff --git a/app/assets/javascripts/analytics/instance_statistics/components/users_chart.vue b/app/assets/javascripts/analytics/instance_statistics/components/users_chart.vue
new file mode 100644
index 00000000000..a4a1d40b70b
--- /dev/null
+++ b/app/assets/javascripts/analytics/instance_statistics/components/users_chart.vue
@@ -0,0 +1,143 @@
+<script>
+import { GlAlert } from '@gitlab/ui';
+import { GlAreaChart } from '@gitlab/ui/dist/charts';
+import produce from 'immer';
+import { sortBy } from 'lodash';
+import * as Sentry from '~/sentry/wrapper';
+import ChartSkeletonLoader from '~/vue_shared/components/resizable_chart/skeleton_loader.vue';
+import { __ } from '~/locale';
+import { formatDateAsMonth } from '~/lib/utils/datetime_utility';
+import usersQuery from '../graphql/queries/users.query.graphql';
+import { getAverageByMonth } from '../utils';
+
+const sortByDate = data => sortBy(data, item => new Date(item[0]).getTime());
+
+export default {
+ name: 'UsersChart',
+ components: { GlAlert, GlAreaChart, ChartSkeletonLoader },
+ props: {
+ startDate: {
+ type: Date,
+ required: true,
+ },
+ endDate: {
+ type: Date,
+ required: true,
+ },
+ totalDataPoints: {
+ type: Number,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ loadingError: null,
+ users: [],
+ pageInfo: null,
+ };
+ },
+ apollo: {
+ users: {
+ query: usersQuery,
+ variables() {
+ return {
+ first: this.totalDataPoints,
+ after: null,
+ };
+ },
+ update(data) {
+ return data.users?.nodes || [];
+ },
+ result({ data }) {
+ const {
+ users: { pageInfo },
+ } = data;
+ this.pageInfo = pageInfo;
+ this.fetchNextPage();
+ },
+ error(error) {
+ this.handleError(error);
+ },
+ },
+ },
+ i18n: {
+ yAxisTitle: __('Total users'),
+ xAxisTitle: __('Month'),
+ loadUserChartError: __('Could not load the user chart. Please refresh the page to try again.'),
+ noDataMessage: __('There is no data available.'),
+ },
+ computed: {
+ isLoading() {
+ return this.$apollo.queries.users.loading || this.pageInfo?.hasNextPage;
+ },
+ chartUserData() {
+ const averaged = getAverageByMonth(
+ this.users.length > this.totalDataPoints
+ ? this.users.slice(0, this.totalDataPoints)
+ : this.users,
+ { shouldRound: true },
+ );
+ return sortByDate(averaged);
+ },
+ options() {
+ return {
+ xAxis: {
+ name: this.$options.i18n.xAxisTitle,
+ type: 'category',
+ axisLabel: {
+ formatter: formatDateAsMonth,
+ },
+ },
+ yAxis: {
+ name: this.$options.i18n.yAxisTitle,
+ },
+ };
+ },
+ },
+ methods: {
+ handleError(error) {
+ this.loadingError = true;
+ this.users = [];
+ Sentry.captureException(error);
+ },
+ fetchNextPage() {
+ if (this.pageInfo?.hasNextPage) {
+ this.$apollo.queries.users
+ .fetchMore({
+ variables: { first: this.totalDataPoints, after: this.pageInfo.endCursor },
+ updateQuery: (previousResult, { fetchMoreResult }) => {
+ return produce(fetchMoreResult, newUsers => {
+ // eslint-disable-next-line no-param-reassign
+ newUsers.users.nodes = [...previousResult.users.nodes, ...newUsers.users.nodes];
+ });
+ },
+ })
+ .catch(this.handleError);
+ }
+ },
+ },
+};
+</script>
+<template>
+ <div>
+ <h3>{{ $options.i18n.yAxisTitle }}</h3>
+ <gl-alert v-if="loadingError" variant="danger" :dismissible="false" class="gl-mt-3">
+ {{ this.$options.i18n.loadUserChartError }}
+ </gl-alert>
+ <chart-skeleton-loader v-else-if="isLoading" />
+ <gl-alert v-else-if="!chartUserData.length" variant="info" :dismissible="false" class="gl-mt-3">
+ {{ $options.i18n.noDataMessage }}
+ </gl-alert>
+ <gl-area-chart
+ v-else
+ :option="options"
+ :include-legend-avg-max="true"
+ :data="[
+ {
+ name: $options.i18n.yAxisTitle,
+ data: chartUserData,
+ },
+ ]"
+ />
+ </div>
+</template>
diff --git a/app/assets/javascripts/analytics/instance_statistics/constants.js b/app/assets/javascripts/analytics/instance_statistics/constants.js
new file mode 100644
index 00000000000..846c0ef408b
--- /dev/null
+++ b/app/assets/javascripts/analytics/instance_statistics/constants.js
@@ -0,0 +1,5 @@
+import { getDateInPast } from '~/lib/utils/datetime_utility';
+
+export const TOTAL_DAYS_TO_SHOW = 365;
+export const TODAY = new Date();
+export const START_DATE = getDateInPast(TODAY, TOTAL_DAYS_TO_SHOW);
diff --git a/app/assets/javascripts/analytics/instance_statistics/graphql/fragments/count.fragment.graphql b/app/assets/javascripts/analytics/instance_statistics/graphql/fragments/count.fragment.graphql
new file mode 100644
index 00000000000..40cef95c2e7
--- /dev/null
+++ b/app/assets/javascripts/analytics/instance_statistics/graphql/fragments/count.fragment.graphql
@@ -0,0 +1,4 @@
+fragment Count on InstanceStatisticsMeasurement {
+ count
+ recordedAt
+}
diff --git a/app/assets/javascripts/analytics/instance_statistics/graphql/queries/count.fragment.graphql b/app/assets/javascripts/analytics/instance_statistics/graphql/queries/count.fragment.graphql
new file mode 100644
index 00000000000..40cef95c2e7
--- /dev/null
+++ b/app/assets/javascripts/analytics/instance_statistics/graphql/queries/count.fragment.graphql
@@ -0,0 +1,4 @@
+fragment Count on InstanceStatisticsMeasurement {
+ count
+ recordedAt
+}
diff --git a/app/assets/javascripts/analytics/instance_statistics/graphql/queries/instance_statistics_count.query.graphql b/app/assets/javascripts/analytics/instance_statistics/graphql/queries/instance_statistics_count.query.graphql
new file mode 100644
index 00000000000..f14c2658674
--- /dev/null
+++ b/app/assets/javascripts/analytics/instance_statistics/graphql/queries/instance_statistics_count.query.graphql
@@ -0,0 +1,34 @@
+#import "../fragments/count.fragment.graphql"
+
+query getInstanceCounts {
+ projects: instanceStatisticsMeasurements(identifier: PROJECTS, first: 1) {
+ nodes {
+ ...Count
+ }
+ }
+ groups: instanceStatisticsMeasurements(identifier: GROUPS, first: 1) {
+ nodes {
+ ...Count
+ }
+ }
+ users: instanceStatisticsMeasurements(identifier: USERS, first: 1) {
+ nodes {
+ ...Count
+ }
+ }
+ issues: instanceStatisticsMeasurements(identifier: ISSUES, first: 1) {
+ nodes {
+ ...Count
+ }
+ }
+ mergeRequests: instanceStatisticsMeasurements(identifier: MERGE_REQUESTS, first: 1) {
+ nodes {
+ ...Count
+ }
+ }
+ pipelines: instanceStatisticsMeasurements(identifier: PIPELINES, first: 1) {
+ nodes {
+ ...Count
+ }
+ }
+}
diff --git a/app/assets/javascripts/analytics/instance_statistics/graphql/queries/pipeline_stats.query.graphql b/app/assets/javascripts/analytics/instance_statistics/graphql/queries/pipeline_stats.query.graphql
new file mode 100644
index 00000000000..3bf40403f91
--- /dev/null
+++ b/app/assets/javascripts/analytics/instance_statistics/graphql/queries/pipeline_stats.query.graphql
@@ -0,0 +1,76 @@
+#import "~/graphql_shared/fragments/pageInfo.fragment.graphql"
+#import "./count.fragment.graphql"
+
+query pipelineStats(
+ $firstTotal: Int
+ $firstSucceeded: Int
+ $firstFailed: Int
+ $firstCanceled: Int
+ $firstSkipped: Int
+ $endCursorTotal: String
+ $endCursorSucceeded: String
+ $endCursorFailed: String
+ $endCursorCanceled: String
+ $endCursorSkipped: String
+) {
+ pipelinesTotal: instanceStatisticsMeasurements(
+ identifier: PIPELINES
+ first: $firstTotal
+ after: $endCursorTotal
+ ) {
+ nodes {
+ ...Count
+ }
+ pageInfo {
+ ...PageInfo
+ }
+ }
+ pipelinesSucceeded: instanceStatisticsMeasurements(
+ identifier: PIPELINES_SUCCEEDED
+ first: $firstSucceeded
+ after: $endCursorSucceeded
+ ) {
+ nodes {
+ ...Count
+ }
+ pageInfo {
+ ...PageInfo
+ }
+ }
+ pipelinesFailed: instanceStatisticsMeasurements(
+ identifier: PIPELINES_FAILED
+ first: $firstFailed
+ after: $endCursorFailed
+ ) {
+ nodes {
+ ...Count
+ }
+ pageInfo {
+ ...PageInfo
+ }
+ }
+ pipelinesCanceled: instanceStatisticsMeasurements(
+ identifier: PIPELINES_CANCELED
+ first: $firstCanceled
+ after: $endCursorCanceled
+ ) {
+ nodes {
+ ...Count
+ }
+ pageInfo {
+ ...PageInfo
+ }
+ }
+ pipelinesSkipped: instanceStatisticsMeasurements(
+ identifier: PIPELINES_SKIPPED
+ first: $firstSkipped
+ after: $endCursorSkipped
+ ) {
+ nodes {
+ ...Count
+ }
+ pageInfo {
+ ...PageInfo
+ }
+ }
+}
diff --git a/app/assets/javascripts/analytics/instance_statistics/graphql/queries/users.query.graphql b/app/assets/javascripts/analytics/instance_statistics/graphql/queries/users.query.graphql
new file mode 100644
index 00000000000..6235e36eb89
--- /dev/null
+++ b/app/assets/javascripts/analytics/instance_statistics/graphql/queries/users.query.graphql
@@ -0,0 +1,13 @@
+#import "~/graphql_shared/fragments/pageInfo.fragment.graphql"
+#import "../fragments/count.fragment.graphql"
+
+query getUsersCount($first: Int, $after: String) {
+ users: instanceStatisticsMeasurements(identifier: USERS, first: $first, after: $after) {
+ nodes {
+ ...Count
+ }
+ pageInfo {
+ ...PageInfo
+ }
+ }
+}
diff --git a/app/assets/javascripts/analytics/instance_statistics/index.js b/app/assets/javascripts/analytics/instance_statistics/index.js
new file mode 100644
index 00000000000..0d7dcf6ace8
--- /dev/null
+++ b/app/assets/javascripts/analytics/instance_statistics/index.js
@@ -0,0 +1,24 @@
+import Vue from 'vue';
+import VueApollo from 'vue-apollo';
+import createDefaultClient from '~/lib/graphql';
+import InstanceStatisticsApp from './components/app.vue';
+
+Vue.use(VueApollo);
+
+const apolloProvider = new VueApollo({
+ defaultClient: createDefaultClient(),
+});
+
+export default () => {
+ const el = document.getElementById('js-instance-statistics-app');
+
+ if (!el) return false;
+
+ return new Vue({
+ el,
+ apolloProvider,
+ render(h) {
+ return h(InstanceStatisticsApp);
+ },
+ });
+};
diff --git a/app/assets/javascripts/analytics/instance_statistics/utils.js b/app/assets/javascripts/analytics/instance_statistics/utils.js
new file mode 100644
index 00000000000..907482c0c72
--- /dev/null
+++ b/app/assets/javascripts/analytics/instance_statistics/utils.js
@@ -0,0 +1,69 @@
+import { masks } from 'dateformat';
+import { mapKeys, mapValues, pick, sortBy } from 'lodash';
+import { formatDate } from '~/lib/utils/datetime_utility';
+
+const { isoDate } = masks;
+
+/**
+ * Takes an array of items and returns one item per month with the average of the `count`s from that month
+ * @param {Array} items
+ * @param {Number} items[index].count value to be averaged
+ * @param {String} items[index].recordedAt item dateTime time stamp to be collected into a month
+ * @param {Object} options
+ * @param {Object} options.shouldRound an option to specify whether the retuned averages should be rounded
+ * @return {Array} items collected into [month, average],
+ * where month is a dateTime string representing the first of the given month
+ * and average is the average of the count
+ */
+export function getAverageByMonth(items = [], options = {}) {
+ const { shouldRound = false } = options;
+ const itemsMap = items.reduce((memo, item) => {
+ const { count, recordedAt } = item;
+ const date = new Date(recordedAt);
+ const month = formatDate(new Date(date.getFullYear(), date.getMonth(), 1), isoDate);
+ if (memo[month]) {
+ const { sum, recordCount } = memo[month];
+ return { ...memo, [month]: { sum: sum + count, recordCount: recordCount + 1 } };
+ }
+
+ return { ...memo, [month]: { sum: count, recordCount: 1 } };
+ }, {});
+
+ return Object.keys(itemsMap).map(month => {
+ const { sum, recordCount } = itemsMap[month];
+ const avg = sum / recordCount;
+ if (shouldRound) {
+ return [month, Math.round(avg)];
+ }
+
+ return [month, avg];
+ });
+}
+
+/**
+ * Extracts values given a data set and a set of keys
+ * @example
+ * const data = { fooBar: { baz: 'quis' }, ignored: 'ignored' };
+ * extractValues(data, ['fooBar'], 'foo', 'baz') => { bazBar: 'quis' }
+ * @param {Object} data set to extract values from
+ * @param {Array} dataKeys keys describing where to look for values in the data set
+ * @param {String} replaceKey name key to be replaced in the data set
+ * @param {String} nestedKey key nested in the data set to be extracted,
+ * this is also used to rename the newly created data set
+ * @return {Object} the newly created data set with the extracted values
+ */
+export function extractValues(data, dataKeys = [], replaceKey, nestedKey) {
+ return mapKeys(pick(mapValues(data, nestedKey), dataKeys), (value, key) =>
+ key.replace(replaceKey, nestedKey),
+ );
+}
+
+/**
+ * Creates a new array of items sorted by the date string of each item
+ * @param {Array} items [description]
+ * @param {String} items[0] date string
+ * @return {Array} the new sorted array.
+ */
+export function sortByDate(items = []) {
+ return sortBy(items, ({ recordedAt }) => new Date(recordedAt).getTime());
+}
diff --git a/app/assets/javascripts/analytics/shared/components/metric_card.vue b/app/assets/javascripts/analytics/shared/components/metric_card.vue
new file mode 100644
index 00000000000..cee186c057c
--- /dev/null
+++ b/app/assets/javascripts/analytics/shared/components/metric_card.vue
@@ -0,0 +1,80 @@
+<script>
+import {
+ GlCard,
+ GlDeprecatedSkeletonLoading as GlSkeletonLoading,
+ GlLink,
+ GlIcon,
+ GlTooltipDirective,
+} from '@gitlab/ui';
+
+export default {
+ name: 'MetricCard',
+ components: {
+ GlCard,
+ GlSkeletonLoading,
+ GlLink,
+ GlIcon,
+ },
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ },
+ props: {
+ title: {
+ type: String,
+ required: true,
+ },
+ metrics: {
+ type: Array,
+ required: true,
+ },
+ isLoading: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ },
+ methods: {
+ valueText(metric) {
+ const { value = null, unit = null } = metric;
+ if (!value || value === '-') return '-';
+ return unit && value ? `${value} ${unit}` : value;
+ },
+ },
+};
+</script>
+<template>
+ <gl-card>
+ <template #header>
+ <strong ref="title">{{ title }}</strong>
+ </template>
+ <template #default>
+ <gl-skeleton-loading v-if="isLoading" class="gl-h-auto gl-py-3" />
+ <div v-else ref="metricsWrapper" class="gl-display-flex">
+ <div
+ v-for="metric in metrics"
+ :key="metric.key"
+ ref="metricItem"
+ class="js-metric-card-item gl-flex-grow-1 gl-text-center"
+ >
+ <gl-link v-if="metric.link" :href="metric.link">
+ <h3 class="gl-my-2 gl-text-blue-700">{{ valueText(metric) }}</h3>
+ </gl-link>
+ <h3 v-else class="gl-my-2">{{ valueText(metric) }}</h3>
+ <p class="text-secondary gl-font-sm gl-mb-2">
+ {{ metric.label }}
+ <span v-if="metric.tooltipText">
+ &nbsp;
+ <gl-icon
+ v-gl-tooltip="{ title: metric.tooltipText }"
+ :size="14"
+ class="gl-vertical-align-middle"
+ name="question"
+ data-testid="tooltip"
+ />
+ </span>
+ </p>
+ </div>
+ </div>
+ </template>
+ </gl-card>
+</template>
diff --git a/app/assets/javascripts/api.js b/app/assets/javascripts/api.js
index dbc7ff67d9d..63b75cdb734 100644
--- a/app/assets/javascripts/api.js
+++ b/app/assets/javascripts/api.js
@@ -30,6 +30,7 @@ const Api = {
projectProtectedBranchesPath: '/api/:version/projects/:id/protected_branches',
projectSearchPath: '/api/:version/projects/:id/search',
projectMilestonesPath: '/api/:version/projects/:id/milestones',
+ projectIssuePath: '/api/:version/projects/:id/issues/:issue_iid',
mergeRequestsPath: '/api/:version/merge_requests',
groupLabelsPath: '/groups/:namespace_path/-/labels',
issuableTemplatePath: '/:namespace_path/:project_path/templates/:type/:key',
@@ -54,6 +55,7 @@ const Api = {
releaseLinkPath: '/api/:version/projects/:id/releases/:tag_name/assets/links/:link_id',
mergeRequestsPipeline: '/api/:version/projects/:id/merge_requests/:merge_request_iid/pipelines',
adminStatisticsPath: '/api/:version/application/statistics',
+ pipelineJobsPath: '/api/:version/projects/:id/pipelines/:pipeline_id/jobs',
pipelineSinglePath: '/api/:version/projects/:id/pipelines/:pipeline_id',
pipelinesPath: '/api/:version/projects/:id/pipelines/',
createPipelinePath: '/api/:version/projects/:id/pipeline',
@@ -64,6 +66,10 @@ const Api = {
issuePath: '/api/:version/projects/:id/issues/:issue_iid',
tagsPath: '/api/:version/projects/:id/repository/tags',
freezePeriodsPath: '/api/:version/projects/:id/freeze_periods',
+ usageDataIncrementUniqueUsersPath: '/api/:version/usage_data/increment_unique_users',
+ featureFlagUserLists: '/api/:version/projects/:id/feature_flags_user_lists',
+ featureFlagUserList: '/api/:version/projects/:id/feature_flags_user_lists/:list_iid',
+ billableGroupMembersPath: '/api/:version/groups/:id/billable_members',
group(groupId, callback = () => {}) {
const url = Api.buildUrl(Api.groupPath).replace(':id', groupId);
@@ -111,6 +117,12 @@ const Api = {
});
},
+ inviteGroupMember(id, data) {
+ const url = Api.buildUrl(this.groupMembersPath).replace(':id', encodeURIComponent(id));
+
+ return axios.post(url, data);
+ },
+
groupMilestones(id, options) {
const url = Api.buildUrl(this.groupMilestonesPath).replace(':id', encodeURIComponent(id));
@@ -317,6 +329,14 @@ const Api = {
});
},
+ addProjectIssueAsTodo(projectId, issueIid) {
+ const url = Api.buildUrl(Api.projectIssuePath)
+ .replace(':id', encodeURIComponent(projectId))
+ .replace(':issue_iid', encodeURIComponent(issueIid));
+
+ return axios.post(`${url}/todo`);
+ },
+
mergeRequests(params = {}) {
const url = Api.buildUrl(Api.mergeRequestsPath);
@@ -366,7 +386,7 @@ const Api = {
},
commitMultiple(id, data) {
- // see https://docs.gitlab.com/ce/api/commits.html#create-a-commit-with-multiple-files-and-actions
+ // see https://docs.gitlab.com/ee/api/commits.html#create-a-commit-with-multiple-files-and-actions
const url = Api.buildUrl(Api.commitsPath).replace(':id', encodeURIComponent(id));
return axios.post(url, JSON.stringify(data), {
headers: {
@@ -590,6 +610,14 @@ const Api = {
return axios.get(url);
},
+ pipelineJobs(projectId, pipelineId) {
+ const url = Api.buildUrl(this.pipelineJobsPath)
+ .replace(':id', encodeURIComponent(projectId))
+ .replace(':pipeline_id', encodeURIComponent(pipelineId));
+
+ return axios.get(url);
+ },
+
// Return all pipelines for a project or filter by query params
pipelines(id, options = {}) {
const url = Api.buildUrl(this.pipelinesPath).replace(':id', encodeURIComponent(id));
@@ -686,9 +714,78 @@ const Api = {
return axios.post(url, freezePeriod);
},
+ trackRedisHllUserEvent(event) {
+ if (!gon.features?.usageDataApi) {
+ return null;
+ }
+
+ const url = Api.buildUrl(this.usageDataIncrementUniqueUsersPath);
+ const headers = {
+ 'Content-Type': 'application/json',
+ };
+
+ return axios.post(url, { event }, { headers });
+ },
+
buildUrl(url) {
return joinPaths(gon.relative_url_root || '', url.replace(':version', gon.api_version));
},
+
+ fetchFeatureFlagUserLists(id, page) {
+ const url = Api.buildUrl(this.featureFlagUserLists).replace(':id', id);
+
+ return axios.get(url, { params: { page } });
+ },
+
+ createFeatureFlagUserList(id, list) {
+ const url = Api.buildUrl(this.featureFlagUserLists).replace(':id', id);
+
+ return axios.post(url, list);
+ },
+
+ fetchFeatureFlagUserList(id, listIid) {
+ const url = Api.buildUrl(this.featureFlagUserList)
+ .replace(':id', id)
+ .replace(':list_iid', listIid);
+
+ return axios.get(url);
+ },
+
+ updateFeatureFlagUserList(id, list) {
+ const url = Api.buildUrl(this.featureFlagUserList)
+ .replace(':id', id)
+ .replace(':list_iid', list.iid);
+
+ return axios.put(url, list);
+ },
+
+ deleteFeatureFlagUserList(id, listIid) {
+ const url = Api.buildUrl(this.featureFlagUserList)
+ .replace(':id', id)
+ .replace(':list_iid', listIid);
+
+ return axios.delete(url);
+ },
+
+ fetchBillableGroupMembersList(namespaceId, options = {}, callback = () => {}) {
+ const url = Api.buildUrl(this.billableGroupMembersPath).replace(':id', namespaceId);
+ const defaults = {
+ per_page: DEFAULT_PER_PAGE,
+ page: 1,
+ };
+
+ return axios
+ .get(url, {
+ params: {
+ ...defaults,
+ ...options,
+ },
+ })
+ .then(({ data, headers }) => {
+ callback(data);
+ return { data, headers };
+ });
+ },
};
export default Api;
diff --git a/app/assets/javascripts/awards_handler.js b/app/assets/javascripts/awards_handler.js
index cb71047e00c..7055cd42978 100644
--- a/app/assets/javascripts/awards_handler.js
+++ b/app/assets/javascripts/awards_handler.js
@@ -572,7 +572,7 @@ export class AwardsHandler {
}
findMatchingEmojiElements(query) {
- const emojiMatches = this.emoji.filterEmojiNamesByAlias(query);
+ const emojiMatches = this.emoji.searchEmoji(query, { match: 'fuzzy' }).map(({ name }) => name);
const $emojiElements = $('.emoji-menu-list:not(.frequent-emojis) [data-name]');
const $matchingElements = $emojiElements.filter(
(i, elm) => emojiMatches.indexOf(elm.dataset.name) >= 0,
diff --git a/app/assets/javascripts/badges/components/badge_form.vue b/app/assets/javascripts/badges/components/badge_form.vue
index 6afb10dd2ad..0a8479519f1 100644
--- a/app/assets/javascripts/badges/components/badge_form.vue
+++ b/app/assets/javascripts/badges/components/badge_form.vue
@@ -218,7 +218,7 @@ export default {
</p>
</div>
- <div v-if="isEditing" class="row-content-block gl-display-flex gl-justify-content-end">
+ <div v-if="isEditing" class="row-content-block">
<gl-button class="btn-cancel gl-mr-4" data-testid="cancelEditing" @click="onCancel">
{{ __('Cancel') }}
</gl-button>
@@ -232,7 +232,7 @@ export default {
{{ s__('Badges|Save changes') }}
</gl-button>
</div>
- <div v-else class="gl-display-flex gl-justify-content-end form-group">
+ <div v-else class="form-group">
<gl-button :loading="isSaving" type="submit" variant="success" category="primary">
{{ s__('Badges|Add badge') }}
</gl-button>
diff --git a/app/assets/javascripts/badges/components/badge_list_row.vue b/app/assets/javascripts/badges/components/badge_list_row.vue
index 3343634ecad..4ca91e7a589 100644
--- a/app/assets/javascripts/badges/components/badge_list_row.vue
+++ b/app/assets/javascripts/badges/components/badge_list_row.vue
@@ -1,6 +1,6 @@
<script>
import { mapActions, mapState } from 'vuex';
-import { GlLoadingIcon, GlIcon } from '@gitlab/ui';
+import { GlLoadingIcon, GlButton, GlModalDirective } from '@gitlab/ui';
import { s__ } from '~/locale';
import { PROJECT_BADGE } from '../constants';
import Badge from './badge.vue';
@@ -9,8 +9,11 @@ export default {
name: 'BadgeListRow',
components: {
Badge,
- GlIcon,
GlLoadingIcon,
+ GlButton,
+ },
+ directives: {
+ GlModal: GlModalDirective,
},
props: {
badge: {
@@ -51,24 +54,25 @@ export default {
<span class="table-section section-30 str-truncated">{{ badge.linkUrl }}</span>
<div class="table-section section-10 table-button-footer">
<div v-if="canEditBadge" class="table-action-buttons">
- <button
+ <gl-button
:disabled="badge.isDeleting"
- class="btn btn-default gl-mr-3"
- type="button"
+ class="gl-mr-3"
+ variant="default"
+ icon="pencil"
+ size="medium"
+ :aria-label="__('Edit')"
@click="editBadge(badge)"
- >
- <gl-icon :size="16" :aria-label="__('Edit')" name="pencil" />
- </button>
- <button
+ />
+ <gl-button
+ v-gl-modal.delete-badge-modal
:disabled="badge.isDeleting"
- class="btn btn-danger"
- type="button"
- data-toggle="modal"
- data-target="#delete-badge-modal"
+ variant="danger"
+ icon="remove"
+ size="medium"
+ :aria-label="__('Delete')"
+ data-testid="delete-badge"
@click="updateBadgeInModal(badge)"
- >
- <gl-icon :size="16" :aria-label="__('Delete')" name="remove" />
- </button>
+ />
<gl-loading-icon v-show="badge.isDeleting" :inline="true" />
</div>
</div>
diff --git a/app/assets/javascripts/badges/components/badge_settings.vue b/app/assets/javascripts/badges/components/badge_settings.vue
index 531742e49e3..19781783100 100644
--- a/app/assets/javascripts/badges/components/badge_settings.vue
+++ b/app/assets/javascripts/badges/components/badge_settings.vue
@@ -1,9 +1,8 @@
<script>
import { mapState, mapActions } from 'vuex';
-import { GlSprintf } from '@gitlab/ui';
+import { GlSprintf, GlModal } from '@gitlab/ui';
import { deprecatedCreateFlash as createFlash } from '~/flash';
import { s__ } from '~/locale';
-import DeprecatedModal2 from '~/vue_shared/components/deprecated_modal_2.vue';
import Badge from './badge.vue';
import BadgeForm from './badge_form.vue';
import BadgeList from './badge_list.vue';
@@ -14,7 +13,7 @@ export default {
Badge,
BadgeForm,
BadgeList,
- GlModal: DeprecatedModal2,
+ GlModal,
GlSprintf,
},
i18n: {
@@ -24,6 +23,17 @@ export default {
},
computed: {
...mapState(['badgeInModal', 'isEditing']),
+ primaryProps() {
+ return {
+ text: s__('Delete badge'),
+ attributes: [{ category: 'primary' }, { variant: 'danger' }],
+ };
+ },
+ cancelProps() {
+ return {
+ text: s__('Cancel'),
+ };
+ },
},
methods: {
...mapActions(['deleteBadge']),
@@ -44,11 +54,11 @@ export default {
<template>
<div class="badge-settings">
<gl-modal
- id="delete-badge-modal"
- :header-title-text="s__('Badges|Delete badge?')"
- :footer-primary-button-text="s__('Badges|Delete badge')"
- footer-primary-button-variant="danger"
- @submit="onSubmitModal"
+ modal-id="delete-badge-modal"
+ :title="s__('Badges|Delete badge?')"
+ :action-primary="primaryProps"
+ :action-cancel="cancelProps"
+ @primary="onSubmitModal"
>
<div class="well">
<badge
@@ -65,9 +75,9 @@ export default {
</p>
</gl-modal>
- <badge-form v-show="isEditing" :is-editing="true" />
+ <badge-form v-show="isEditing" :is-editing="true" data-testid="edit-badge" />
- <badge-form v-show="!isEditing" :is-editing="false" />
+ <badge-form v-show="!isEditing" :is-editing="false" data-testid="add-new-badge" />
<badge-list v-show="!isEditing" />
</div>
</template>
diff --git a/app/assets/javascripts/batch_comments/components/draft_note.vue b/app/assets/javascripts/batch_comments/components/draft_note.vue
index a6cd36caede..74069b61f07 100644
--- a/app/assets/javascripts/batch_comments/components/draft_note.vue
+++ b/app/assets/javascripts/batch_comments/components/draft_note.vue
@@ -18,11 +18,6 @@ export default {
type: Object,
required: true,
},
- diffFile: {
- type: Object,
- required: false,
- default: () => ({}),
- },
line: {
type: Object,
required: false,
diff --git a/app/assets/javascripts/batch_comments/components/preview_dropdown.vue b/app/assets/javascripts/batch_comments/components/preview_dropdown.vue
index 2b37ed19176..e18dc344cd7 100644
--- a/app/assets/javascripts/batch_comments/components/preview_dropdown.vue
+++ b/app/assets/javascripts/batch_comments/components/preview_dropdown.vue
@@ -1,114 +1,43 @@
<script>
-import { mapActions, mapGetters, mapState } from 'vuex';
-import { GlButton, GlLoadingIcon, GlIcon } from '@gitlab/ui';
-import { sprintf, n__ } from '~/locale';
-import DraftsCount from './drafts_count.vue';
-import PublishButton from './publish_button.vue';
+import { mapActions, mapGetters } from 'vuex';
+import { GlDropdown, GlDropdownItem, GlIcon } from '@gitlab/ui';
import PreviewItem from './preview_item.vue';
export default {
components: {
- GlButton,
- GlLoadingIcon,
+ GlDropdown,
+ GlDropdownItem,
GlIcon,
- DraftsCount,
- PublishButton,
PreviewItem,
},
computed: {
- ...mapGetters(['isNotesFetched']),
...mapGetters('batchComments', ['draftsCount', 'sortedDrafts']),
- ...mapState('batchComments', ['showPreviewDropdown']),
- dropdownTitle() {
- return sprintf(
- n__('%{count} pending comment', '%{count} pending comments', this.draftsCount),
- { count: this.draftsCount },
- );
- },
- },
- watch: {
- showPreviewDropdown() {
- if (this.showPreviewDropdown && this.$refs.dropdown) {
- this.$nextTick(() => this.$refs.dropdown.$el.focus());
- }
- },
- },
- mounted() {
- document.addEventListener('click', this.onClickDocument);
- },
- beforeDestroy() {
- document.removeEventListener('click', this.onClickDocument);
},
methods: {
- ...mapActions('batchComments', ['toggleReviewDropdown']),
+ ...mapActions('batchComments', ['scrollToDraft']),
isLast(index) {
return index === this.sortedDrafts.length - 1;
},
- onClickDocument({ target }) {
- if (
- this.showPreviewDropdown &&
- !target.closest('.review-preview-dropdown, .js-publish-draft-button')
- ) {
- this.toggleReviewDropdown();
- }
- },
},
};
</script>
<template>
- <div
- class="dropdown float-right review-preview-dropdown"
- :class="{
- show: showPreviewDropdown,
- }"
+ <gl-dropdown
+ :header-text="n__('%d pending comment', '%d pending comments', draftsCount)"
+ dropup
+ toggle-class="qa-review-preview-toggle"
>
- <gl-button
- ref="dropdown"
- type="button"
- category="primary"
- variant="success"
- class="review-preview-dropdown-toggle qa-review-preview-toggle"
- @click="toggleReviewDropdown"
- >
- {{ __('Finish review') }}
- <drafts-count />
- <gl-icon name="angle-up" />
- </gl-button>
- <div
- class="dropdown-menu dropdown-menu-large dropdown-menu-right dropdown-open-top"
- :class="{
- show: showPreviewDropdown,
- }"
+ <template #button-content>
+ {{ __('Pending comments') }}
+ <gl-icon class="dropdown-chevron" name="chevron-up" />
+ </template>
+ <gl-dropdown-item
+ v-for="(draft, index) in sortedDrafts"
+ :key="draft.id"
+ @click="scrollToDraft(draft)"
>
- <div class="dropdown-title gl-display-flex gl-align-items-center">
- <span class="gl-ml-auto">{{ dropdownTitle }}</span>
- <gl-button
- :aria-label="__('Close')"
- type="button"
- category="tertiary"
- size="small"
- class="dropdown-title-button gl-ml-auto gl-p-0!"
- icon="close"
- @click="toggleReviewDropdown"
- />
- </div>
- <div class="dropdown-content">
- <ul v-if="isNotesFetched">
- <li v-for="(draft, index) in sortedDrafts" :key="draft.id">
- <preview-item :draft="draft" :is-last="isLast(index)" />
- </li>
- </ul>
- <gl-loading-icon v-else size="lg" class="gl-mt-3 gl-mb-3" />
- </div>
- <div class="dropdown-footer">
- <publish-button
- :show-count="false"
- :should-publish="true"
- :label="__('Submit review')"
- class="float-right gl-mr-3"
- />
- </div>
- </div>
- </div>
+ <preview-item :draft="draft" :is-last="isLast(index)" />
+ </gl-dropdown-item>
+ </gl-dropdown>
</template>
diff --git a/app/assets/javascripts/batch_comments/components/preview_item.vue b/app/assets/javascripts/batch_comments/components/preview_item.vue
index c89a6b537ef..dca6d90fbcb 100644
--- a/app/assets/javascripts/batch_comments/components/preview_item.vue
+++ b/app/assets/javascripts/batch_comments/components/preview_item.vue
@@ -1,5 +1,5 @@
<script>
-import { mapActions, mapGetters } from 'vuex';
+import { mapGetters } from 'vuex';
import { GlSprintf, GlIcon } from '@gitlab/ui';
import { IMAGE_DIFF_POSITION_TYPE } from '~/diffs/constants';
import { sprintf, __ } from '~/locale';
@@ -78,7 +78,6 @@ export default {
},
},
methods: {
- ...mapActions('batchComments', ['scrollToDraft']),
getLineClasses(lineNumber) {
return getLineClasses(lineNumber);
},
@@ -88,17 +87,7 @@ export default {
</script>
<template>
- <button
- type="button"
- class="review-preview-item menu-item"
- :class="[
- componentClasses,
- {
- 'is-last': isLast,
- },
- ]"
- @click="scrollToDraft(draft)"
- >
+ <span>
<span class="review-preview-item-header">
<gl-icon class="flex-shrink-0" :name="iconName" />
<span
@@ -139,5 +128,5 @@ export default {
>
<gl-icon class="gl-mr-3" name="status_success" /> {{ resolvedStatusMessage }}
</span>
- </button>
+ </span>
</template>
diff --git a/app/assets/javascripts/batch_comments/components/publish_button.vue b/app/assets/javascripts/batch_comments/components/publish_button.vue
index 0c79e185f06..ecced36771e 100644
--- a/app/assets/javascripts/batch_comments/components/publish_button.vue
+++ b/app/assets/javascripts/batch_comments/components/publish_button.vue
@@ -1,7 +1,6 @@
<script>
import { mapActions, mapState } from 'vuex';
import { GlButton } from '@gitlab/ui';
-import { __ } from '~/locale';
import DraftsCount from './drafts_count.vue';
export default {
@@ -15,11 +14,6 @@ export default {
required: false,
default: false,
},
- label: {
- type: String,
- required: false,
- default: __('Finish review'),
- },
category: {
type: String,
required: false,
@@ -30,22 +24,14 @@ export default {
required: false,
default: 'success',
},
- shouldPublish: {
- type: Boolean,
- required: true,
- },
},
computed: {
...mapState('batchComments', ['isPublishing']),
},
methods: {
- ...mapActions('batchComments', ['publishReview', 'toggleReviewDropdown']),
+ ...mapActions('batchComments', ['publishReview']),
onClick() {
- if (this.shouldPublish) {
- this.publishReview();
- } else {
- this.toggleReviewDropdown();
- }
+ this.publishReview();
},
},
};
@@ -59,7 +45,7 @@ export default {
:variant="variant"
@click="onClick"
>
- {{ label }}
+ {{ __('Submit review') }}
<drafts-count v-if="showCount" />
</gl-button>
</template>
diff --git a/app/assets/javascripts/batch_comments/components/review_bar.vue b/app/assets/javascripts/batch_comments/components/review_bar.vue
index e51888eabc1..035d6f4e0ab 100644
--- a/app/assets/javascripts/batch_comments/components/review_bar.vue
+++ b/app/assets/javascripts/batch_comments/components/review_bar.vue
@@ -1,22 +1,15 @@
<script>
-/* eslint-disable vue/no-v-html */
-import { mapActions, mapState, mapGetters } from 'vuex';
-import { GlModal, GlModalDirective, GlButton } from '@gitlab/ui';
-import { sprintf, s__ } from '~/locale';
+import { mapActions, mapGetters } from 'vuex';
import PreviewDropdown from './preview_dropdown.vue';
+import PublishButton from './publish_button.vue';
export default {
components: {
- GlButton,
- GlModal,
PreviewDropdown,
- },
- directives: {
- 'gl-modal': GlModalDirective,
+ PublishButton,
},
computed: {
...mapGetters(['isNotesFetched']),
- ...mapState('batchComments', ['isDiscarding']),
...mapGetters('batchComments', ['draftsCount']),
},
watch: {
@@ -27,45 +20,17 @@ export default {
},
},
methods: {
- ...mapActions('batchComments', ['discardReview', 'expandAllDiscussions']),
+ ...mapActions('batchComments', ['expandAllDiscussions']),
},
- modalId: 'discard-draft-review',
- text: sprintf(
- s__(
- `BatchComments|You're about to discard your review which will delete all of your pending comments.
- The deleted comments %{strong_start}cannot%{strong_end} be restored.`,
- ),
- {
- strong_start: '<strong>',
- strong_end: '</strong>',
- },
- false,
- ),
};
</script>
<template>
<div v-show="draftsCount > 0">
<nav class="review-bar-component">
- <div class="review-bar-content qa-review-bar">
+ <div class="review-bar-content qa-review-bar d-flex gl-justify-content-end">
<preview-dropdown />
- <gl-button
- v-gl-modal="$options.modalId"
- :loading="isDiscarding"
- class="qa-discard-review float-right"
- >
- {{ __('Discard review') }}
- </gl-button>
+ <publish-button class="gl-ml-3" show-count />
</div>
</nav>
- <gl-modal
- :title="s__('BatchComments|Discard review?')"
- :ok-title="s__('BatchComments|Delete all pending comments')"
- :modal-id="$options.modalId"
- title-tag="h4"
- ok-variant="danger qa-modal-delete-pending-comments"
- @ok="discardReview"
- >
- <p v-html="$options.text"></p>
- </gl-modal>
</div>
</template>
diff --git a/app/assets/javascripts/batch_comments/stores/modules/batch_comments/actions.js b/app/assets/javascripts/batch_comments/stores/modules/batch_comments/actions.js
index d9b92113103..ebd821125fb 100644
--- a/app/assets/javascripts/batch_comments/stores/modules/batch_comments/actions.js
+++ b/app/assets/javascripts/batch_comments/stores/modules/batch_comments/actions.js
@@ -75,15 +75,6 @@ export const updateDiscussionsAfterPublish = ({ dispatch, getters, rootGetters }
}),
);
-export const discardReview = ({ commit, getters }) => {
- commit(types.REQUEST_DISCARD_REVIEW);
-
- return service
- .discard(getters.getNotesData.draftsDiscardPath)
- .then(() => commit(types.RECEIVE_DISCARD_REVIEW_SUCCESS))
- .catch(() => commit(types.RECEIVE_DISCARD_REVIEW_ERROR));
-};
-
export const updateDraft = (
{ commit, getters },
{ note, noteText, resolveDiscussion, position, callback },
@@ -108,8 +99,6 @@ export const scrollToDraft = ({ dispatch, rootGetters }, draft) => {
const draftID = `note_${draft.id}`;
const el = document.querySelector(`#${tabEl} #${draftID}`);
- dispatch('closeReviewDropdown');
-
window.location.hash = draftID;
if (window.mrTabs.currentAction !== tab) {
@@ -125,17 +114,6 @@ export const scrollToDraft = ({ dispatch, rootGetters }, draft) => {
}
};
-export const toggleReviewDropdown = ({ dispatch, state }) => {
- if (state.showPreviewDropdown) {
- dispatch('closeReviewDropdown');
- } else {
- dispatch('openReviewDropdown');
- }
-};
-
-export const openReviewDropdown = ({ commit }) => commit(types.OPEN_REVIEW_DROPDOWN);
-export const closeReviewDropdown = ({ commit }) => commit(types.CLOSE_REVIEW_DROPDOWN);
-
export const expandAllDiscussions = ({ dispatch, state }) =>
state.drafts
.filter(draft => draft.discussion_id)
diff --git a/app/assets/javascripts/batch_comments/stores/modules/batch_comments/mutation_types.js b/app/assets/javascripts/batch_comments/stores/modules/batch_comments/mutation_types.js
index c8f0658c21c..df523a692d3 100644
--- a/app/assets/javascripts/batch_comments/stores/modules/batch_comments/mutation_types.js
+++ b/app/assets/javascripts/batch_comments/stores/modules/batch_comments/mutation_types.js
@@ -11,13 +11,6 @@ export const REQUEST_PUBLISH_REVIEW = 'REQUEST_PUBLISH_REVIEW';
export const RECEIVE_PUBLISH_REVIEW_SUCCESS = 'RECEIVE_PUBLISH_REVIEW_SUCCESS';
export const RECEIVE_PUBLISH_REVIEW_ERROR = 'RECEIVE_PUBLISH_REVIEW_ERROR';
-export const REQUEST_DISCARD_REVIEW = 'REQUEST_DISCARD_REVIEW';
-export const RECEIVE_DISCARD_REVIEW_SUCCESS = 'RECEIVE_DISCARD_REVIEW_SUCCESS';
-export const RECEIVE_DISCARD_REVIEW_ERROR = 'RECEIVE_DISCARD_REVIEW_ERROR';
-
export const RECEIVE_DRAFT_UPDATE_SUCCESS = 'RECEIVE_DRAFT_UPDATE_SUCCESS';
-export const OPEN_REVIEW_DROPDOWN = 'OPEN_REVIEW_DROPDOWN';
-export const CLOSE_REVIEW_DROPDOWN = 'CLOSE_REVIEW_DROPDOWN';
-
export const TOGGLE_RESOLVE_DISCUSSION = 'TOGGLE_RESOLVE_DISCUSSION';
diff --git a/app/assets/javascripts/batch_comments/stores/modules/batch_comments/mutations.js b/app/assets/javascripts/batch_comments/stores/modules/batch_comments/mutations.js
index 81ceef7b160..731f4b6d12a 100644
--- a/app/assets/javascripts/batch_comments/stores/modules/batch_comments/mutations.js
+++ b/app/assets/javascripts/batch_comments/stores/modules/batch_comments/mutations.js
@@ -43,16 +43,6 @@ export default {
[types.RECEIVE_PUBLISH_REVIEW_ERROR](state) {
state.isPublishing = false;
},
- [types.REQUEST_DISCARD_REVIEW](state) {
- state.isDiscarding = true;
- },
- [types.RECEIVE_DISCARD_REVIEW_SUCCESS](state) {
- state.isDiscarding = false;
- state.drafts = [];
- },
- [types.RECEIVE_DISCARD_REVIEW_ERROR](state) {
- state.isDiscarding = false;
- },
[types.RECEIVE_DRAFT_UPDATE_SUCCESS](state, data) {
const index = state.drafts.findIndex(draft => draft.id === data.id);
@@ -60,12 +50,6 @@ export default {
state.drafts.splice(index, 1, processDraft(data));
}
},
- [types.OPEN_REVIEW_DROPDOWN](state) {
- state.showPreviewDropdown = true;
- },
- [types.CLOSE_REVIEW_DROPDOWN](state) {
- state.showPreviewDropdown = false;
- },
[types.TOGGLE_RESOLVE_DISCUSSION](state, draftId) {
state.drafts = state.drafts.map(draft => {
if (draft.id === draftId) {
diff --git a/app/assets/javascripts/batch_comments/stores/modules/batch_comments/state.js b/app/assets/javascripts/batch_comments/stores/modules/batch_comments/state.js
index 80c710deab0..6b97fc242c8 100644
--- a/app/assets/javascripts/batch_comments/stores/modules/batch_comments/state.js
+++ b/app/assets/javascripts/batch_comments/stores/modules/batch_comments/state.js
@@ -4,6 +4,4 @@ export default () => ({
drafts: [],
isPublishing: false,
currentlyPublishingDrafts: [],
- isDiscarding: false,
- showPreviewDropdown: false,
});
diff --git a/app/assets/javascripts/behaviors/autosize.js b/app/assets/javascripts/behaviors/autosize.js
index d61797b7ae4..3e9d77cdf6b 100644
--- a/app/assets/javascripts/behaviors/autosize.js
+++ b/app/assets/javascripts/behaviors/autosize.js
@@ -1,5 +1,5 @@
import Autosize from 'autosize';
-import { waitForCSSLoaded } from '../helpers/startup_css_helper';
+import { waitForCSSLoaded } from '~/helpers/startup_css_helper';
document.addEventListener('DOMContentLoaded', () => {
waitForCSSLoaded(() => {
diff --git a/app/assets/javascripts/behaviors/collapse_sidebar_on_window_resize.js b/app/assets/javascripts/behaviors/collapse_sidebar_on_window_resize.js
index d9164f6204a..c4af34b848b 100644
--- a/app/assets/javascripts/behaviors/collapse_sidebar_on_window_resize.js
+++ b/app/assets/javascripts/behaviors/collapse_sidebar_on_window_resize.js
@@ -8,7 +8,6 @@ import { GlBreakpointInstance as bp } from '@gitlab/ui/dist/utils';
* @sentrify
*/
export default () => {
- const $sidebarGutterToggle = $('.js-sidebar-toggle');
let bootstrapBreakpoint = bp.getBreakpointSize();
$(window).on('resize.app', () => {
@@ -19,8 +18,13 @@ export default () => {
const breakpointSizes = ['md', 'sm', 'xs'];
if (breakpointSizes.includes(bootstrapBreakpoint)) {
- const $gutterIcon = $sidebarGutterToggle.find('i');
- if ($gutterIcon.hasClass('fa-angle-double-right')) {
+ const $toggleContainer = $('.js-sidebar-toggle-container');
+ const isExpanded = $toggleContainer.data('is-expanded');
+ const $expandIcon = $('.js-sidebar-expand');
+
+ if (isExpanded) {
+ const $sidebarGutterToggle = $expandIcon.closest('.js-sidebar-toggle');
+
$sidebarGutterToggle.trigger('click');
}
@@ -28,11 +32,12 @@ export default () => {
// Sidebar has an icon which corresponds to collapsing the sidebar
// only then trigger the click.
- if (sidebarGutterVueToggleEl) {
- const collapseIcon = sidebarGutterVueToggleEl.querySelector('i.fa-angle-double-right');
-
- if (collapseIcon) {
- collapseIcon.click();
+ if (
+ sidebarGutterVueToggleEl &&
+ !sidebarGutterVueToggleEl.classList.contains('js-sidebar-collapsed')
+ ) {
+ if (sidebarGutterVueToggleEl) {
+ sidebarGutterVueToggleEl.click();
}
}
}
diff --git a/app/assets/javascripts/behaviors/copy_to_clipboard.js b/app/assets/javascripts/behaviors/copy_to_clipboard.js
index 48bcba7bcca..430a8c38387 100644
--- a/app/assets/javascripts/behaviors/copy_to_clipboard.js
+++ b/app/assets/javascripts/behaviors/copy_to_clipboard.js
@@ -1,19 +1,24 @@
import $ from 'jquery';
import Clipboard from 'clipboard';
import { sprintf, __ } from '~/locale';
+import { fixTitle, show } from '~/tooltips';
function showTooltip(target, title) {
- const $target = $(target);
- const originalTitle = $target.data('originalTitle');
+ const { originalTitle } = target.dataset;
+ const hideTooltip = () => {
+ target.removeEventListener('mouseout', hideTooltip);
+ setTimeout(() => {
+ target.setAttribute('title', originalTitle);
+ fixTitle(target);
+ }, 100);
+ };
- if (!$target.data('hideTooltip')) {
- $target
- .attr('title', title)
- .tooltip('_fixTitle')
- .tooltip('show')
- .attr('title', originalTitle)
- .tooltip('_fixTitle');
- }
+ target.setAttribute('title', title);
+
+ fixTitle(target);
+ show(target);
+
+ target.addEventListener('mouseout', hideTooltip);
}
function genericSuccess(e) {
diff --git a/app/assets/javascripts/behaviors/gl_emoji.js b/app/assets/javascripts/behaviors/gl_emoji.js
index bcf732e9522..16373b523b2 100644
--- a/app/assets/javascripts/behaviors/gl_emoji.js
+++ b/app/assets/javascripts/behaviors/gl_emoji.js
@@ -3,9 +3,7 @@ import isEmojiUnicodeSupported from '../emoji/support';
import { initEmojiMap, getEmojiInfo, emojiFallbackImageSrc, emojiImageTag } from '../emoji';
class GlEmoji extends HTMLElement {
- constructor() {
- super();
-
+ connectedCallback() {
this.initialize();
}
initialize() {
diff --git a/app/assets/javascripts/behaviors/index.js b/app/assets/javascripts/behaviors/index.js
index fd12c282b62..613309a1c5a 100644
--- a/app/assets/javascripts/behaviors/index.js
+++ b/app/assets/javascripts/behaviors/index.js
@@ -13,6 +13,9 @@ import './toggler_behavior';
import './preview_markdown';
import initCollapseSidebarOnWindowResize from './collapse_sidebar_on_window_resize';
import initSelect2Dropdowns from './select2';
+import { loadStartupCSS } from './load_startup_css';
+
+loadStartupCSS();
installGlEmojiElement();
diff --git a/app/assets/javascripts/behaviors/load_startup_css.js b/app/assets/javascripts/behaviors/load_startup_css.js
new file mode 100644
index 00000000000..1d7bf716475
--- /dev/null
+++ b/app/assets/javascripts/behaviors/load_startup_css.js
@@ -0,0 +1,15 @@
+export const loadStartupCSS = () => {
+ // We need to fallback to dispatching `load` in case our event listener was added too late
+ // or the browser environment doesn't load media=print.
+ // Do this on `window.load` so that the default deferred behavior takes precedence.
+ // https://gitlab.com/gitlab-org/gitlab/-/issues/239357
+ window.addEventListener(
+ 'load',
+ () => {
+ document
+ .querySelectorAll('link[media=print]')
+ .forEach(x => x.dispatchEvent(new Event('load')));
+ },
+ { once: true },
+ );
+};
diff --git a/app/assets/javascripts/behaviors/markdown/gfm_auto_complete.js b/app/assets/javascripts/behaviors/markdown/gfm_auto_complete.js
index d712c90242c..83f2ca0bdc2 100644
--- a/app/assets/javascripts/behaviors/markdown/gfm_auto_complete.js
+++ b/app/assets/javascripts/behaviors/markdown/gfm_auto_complete.js
@@ -14,7 +14,6 @@ export default function initGFMInput($els) {
milestones: enableGFM,
mergeRequests: enableGFM,
labels: enableGFM,
- vulnerabilities: enableGFM,
});
});
}
diff --git a/app/assets/javascripts/behaviors/shortcuts/keybindings.js b/app/assets/javascripts/behaviors/shortcuts/keybindings.js
new file mode 100644
index 00000000000..bbcc40ab9fe
--- /dev/null
+++ b/app/assets/javascripts/behaviors/shortcuts/keybindings.js
@@ -0,0 +1,96 @@
+import { flatten } from 'lodash';
+import { s__ } from '~/locale';
+import AccessorUtilities from '~/lib/utils/accessor';
+import { shouldDisableShortcuts } from './shortcuts_toggle';
+
+export const LOCAL_STORAGE_KEY = 'gl-keyboard-shortcuts-customizations';
+
+let parsedCustomizations = {};
+const localStorageIsSafe = AccessorUtilities.isLocalStorageAccessSafe();
+
+if (localStorageIsSafe) {
+ try {
+ parsedCustomizations = JSON.parse(localStorage.getItem(LOCAL_STORAGE_KEY) || '{}');
+ } catch (e) {
+ /* do nothing */
+ }
+}
+
+/**
+ * A map of command => keys of all keyboard shortcuts
+ * that have been customized by the user.
+ *
+ * @example
+ * { "globalShortcuts.togglePerformanceBar": ["p e r f"] }
+ *
+ * @type { Object.<string, string[]> }
+ */
+export const customizations = parsedCustomizations;
+
+// All available commands
+export const TOGGLE_PERFORMANCE_BAR = 'globalShortcuts.togglePerformanceBar';
+
+/** All keybindings, grouped and ordered with descriptions */
+export const keybindingGroups = [
+ {
+ groupId: 'globalShortcuts',
+ name: s__('KeyboardShortcuts|Global Shortcuts'),
+ keybindings: [
+ {
+ description: s__('KeyboardShortcuts|Toggle the Performance Bar'),
+ command: TOGGLE_PERFORMANCE_BAR,
+ // eslint-disable-next-line @gitlab/require-i18n-strings
+ defaultKeys: ['p b'],
+ },
+ ],
+ },
+]
+
+ // For each keybinding object, add a `customKeys` property populated with the
+ // user's custom keybindings (if the command has been customized).
+ // `customKeys` will be `undefined` if the command hasn't been customized.
+ .map(group => {
+ return {
+ ...group,
+ keybindings: group.keybindings.map(binding => ({
+ ...binding,
+ customKeys: customizations[binding.command],
+ })),
+ };
+ });
+
+/**
+ * A simple map of command => keys. All user customizations are included in this map.
+ * This mapping is used to simplify `keysFor` below.
+ *
+ * @example
+ * { "globalShortcuts.togglePerformanceBar": ["p e r f"] }
+ */
+const commandToKeys = flatten(keybindingGroups.map(group => group.keybindings)).reduce(
+ (acc, binding) => {
+ acc[binding.command] = binding.customKeys || binding.defaultKeys;
+ return acc;
+ },
+ {},
+);
+
+/**
+ * Gets keyboard shortcuts associated with a command
+ *
+ * @param {string} command The command string. All command
+ * strings are available as imports from this file.
+ *
+ * @returns {string[]} An array of keyboard shortcut strings bound to the command
+ *
+ * @example
+ * import { keysFor, TOGGLE_PERFORMANCE_BAR } from '~/behaviors/shortcuts/keybindings'
+ *
+ * Mousetrap.bind(keysFor(TOGGLE_PERFORMANCE_BAR), handler);
+ */
+export const keysFor = command => {
+ if (shouldDisableShortcuts()) {
+ return [];
+ }
+
+ return commandToKeys[command];
+};
diff --git a/app/assets/javascripts/behaviors/shortcuts/shortcuts.js b/app/assets/javascripts/behaviors/shortcuts/shortcuts.js
index 8a8b61a57cd..a53150f8d61 100644
--- a/app/assets/javascripts/behaviors/shortcuts/shortcuts.js
+++ b/app/assets/javascripts/behaviors/shortcuts/shortcuts.js
@@ -9,6 +9,7 @@ import axios from '../../lib/utils/axios_utils';
import { refreshCurrentPage, visitUrl } from '../../lib/utils/url_utility';
import findAndFollowLink from '../../lib/utils/navigation_utility';
import { parseBoolean, getCspNonceValue } from '~/lib/utils/common_utils';
+import { keysFor, TOGGLE_PERFORMANCE_BAR } from './keybindings';
const defaultStopCallback = Mousetrap.prototype.stopCallback;
Mousetrap.prototype.stopCallback = function customStopCallback(e, element, combo) {
@@ -70,7 +71,7 @@ export default class Shortcuts {
Mousetrap.bind('s', Shortcuts.focusSearch);
Mousetrap.bind('/', Shortcuts.focusSearch);
Mousetrap.bind('f', this.focusFilter.bind(this));
- Mousetrap.bind('p b', Shortcuts.onTogglePerfBar);
+ Mousetrap.bind(keysFor(TOGGLE_PERFORMANCE_BAR), Shortcuts.onTogglePerfBar);
const findFileURL = document.body.dataset.findFile;
@@ -117,9 +118,9 @@ export default class Shortcuts {
e.preventDefault();
const performanceBarCookieName = 'perf_bar_enabled';
if (parseBoolean(Cookies.get(performanceBarCookieName))) {
- Cookies.set(performanceBarCookieName, 'false', { path: '/' });
+ Cookies.set(performanceBarCookieName, 'false', { expires: 365, path: '/' });
} else {
- Cookies.set(performanceBarCookieName, 'true', { path: '/' });
+ Cookies.set(performanceBarCookieName, 'true', { expires: 365, path: '/' });
}
refreshCurrentPage();
}
diff --git a/app/assets/javascripts/blob/components/blob_edit_content.vue b/app/assets/javascripts/blob/components/blob_edit_content.vue
index 6293f3bed1c..a013d637c1d 100644
--- a/app/assets/javascripts/blob/components/blob_edit_content.vue
+++ b/app/assets/javascripts/blob/components/blob_edit_content.vue
@@ -1,12 +1,9 @@
<script>
import { debounce } from 'lodash';
import { initEditorLite } from '~/blob/utils';
-import {
- SNIPPET_MARK_BLOBS_CONTENT,
- SNIPPET_MARK_EDIT_APP_START,
- SNIPPET_MEASURE_BLOBS_CONTENT,
- SNIPPET_MEASURE_BLOBS_CONTENT_WITHIN_APP,
-} from '~/performance_constants';
+import { SNIPPET_MEASURE_BLOBS_CONTENT } from '~/performance_constants';
+
+import eventHub from './eventhub';
export default {
props: {
@@ -48,13 +45,7 @@ export default {
this.editor.onDidChangeModelContent(debounce(this.onFileChange.bind(this), 250));
- window.requestAnimationFrame(() => {
- if (!performance.getEntriesByName(SNIPPET_MARK_BLOBS_CONTENT).length) {
- performance.mark(SNIPPET_MARK_BLOBS_CONTENT);
- performance.measure(SNIPPET_MEASURE_BLOBS_CONTENT);
- performance.measure(SNIPPET_MEASURE_BLOBS_CONTENT_WITHIN_APP, SNIPPET_MARK_EDIT_APP_START);
- }
- });
+ eventHub.$emit(SNIPPET_MEASURE_BLOBS_CONTENT);
},
beforeDestroy() {
this.editor.dispose();
diff --git a/app/assets/javascripts/blob/components/blob_header_filepath.vue b/app/assets/javascripts/blob/components/blob_header_filepath.vue
index 601b694db87..f99ecba2324 100644
--- a/app/assets/javascripts/blob/components/blob_header_filepath.vue
+++ b/app/assets/javascripts/blob/components/blob_header_filepath.vue
@@ -43,6 +43,7 @@ export default {
:text="blob.path"
:gfm="gfmCopyText"
:title="__('Copy file path')"
+ category="tertiary"
css-class="btn-clipboard btn-transparent lh-100 position-static"
/>
</div>
diff --git a/app/assets/javascripts/blob/components/eventhub.js b/app/assets/javascripts/blob/components/eventhub.js
new file mode 100644
index 00000000000..e31806ad199
--- /dev/null
+++ b/app/assets/javascripts/blob/components/eventhub.js
@@ -0,0 +1,3 @@
+import createEventHub from '~/helpers/event_hub_factory';
+
+export default createEventHub();
diff --git a/app/assets/javascripts/blob/pipeline_tour_success_modal.vue b/app/assets/javascripts/blob/pipeline_tour_success_modal.vue
index 411241b72d5..1412e49836d 100644
--- a/app/assets/javascripts/blob/pipeline_tour_success_modal.vue
+++ b/app/assets/javascripts/blob/pipeline_tour_success_modal.vue
@@ -1,8 +1,7 @@
<script>
import { GlModal, GlSprintf, GlLink, GlButton } from '@gitlab/ui';
import Cookies from 'js-cookie';
-import { sprintf, s__, __ } from '~/locale';
-import { glEmojiTag } from '~/emoji';
+import { s__ } from '~/locale';
import Tracking from '~/tracking';
const trackingMixin = Tracking.mixin();
@@ -12,21 +11,6 @@ export default {
'https://about.gitlab.com/blog/2018/01/22/a-beginners-guide-to-continuous-integration/',
exampleLink: 'https://docs.gitlab.com/ee/ci/examples/',
codeQualityLink: 'https://docs.gitlab.com/ee/user/project/merge_requests/code_quality.html',
- bodyMessage: s__(
- `MR widget|The pipeline will test your code on every commit. A %{codeQualityLinkStart}code quality report%{codeQualityLinkEnd} will appear in your merge requests to warn you about potential code degradations.`,
- ),
- helpMessage: s__(
- `MR widget|Take a look at our %{beginnerLinkStart}Beginner's Guide to Continuous Integration%{beginnerLinkEnd} and our %{exampleLinkStart}examples of GitLab CI/CD%{exampleLinkEnd} to learn more.`,
- ),
- pipelinesButton: s__('MR widget|See your pipeline in action'),
- mergeRequestButton: s__('MR widget|Back to the Merge request'),
- modalTitle: sprintf(
- __("That's it, well done!%{celebrate}"),
- {
- celebrate: glEmojiTag('tada'),
- },
- false,
- ),
goToTrackValuePipelines: 10,
goToTrackValueMergeRequest: 20,
trackEvent: 'click_button',
@@ -78,6 +62,17 @@ export default {
return '';
},
},
+ i18n: {
+ modalTitle: s__("That's it, well done!"),
+ pipelinesButton: s__('MR widget|See your pipeline in action'),
+ mergeRequestButton: s__('MR widget|Back to the Merge request'),
+ bodyMessage: s__(
+ `MR widget|The pipeline will test your code on every commit. A %{codeQualityLinkStart}code quality report%{codeQualityLinkEnd} will appear in your merge requests to warn you about potential code degradations.`,
+ ),
+ helpMessage: s__(
+ `MR widget|Take a look at our %{beginnerLinkStart}Beginner's Guide to Continuous Integration%{beginnerLinkEnd} and our %{exampleLinkStart}examples of GitLab CI/CD%{exampleLinkEnd} to learn more.`,
+ ),
+ },
mounted() {
this.track();
this.disableModalFromRenderingAgain();
@@ -90,14 +85,13 @@ export default {
};
</script>
<template>
- <gl-modal
- visible
- size="sm"
- :title="$options.modalTitle"
- modal-id="success-pipeline-modal-id-not-used"
- >
+ <gl-modal visible size="sm" modal-id="success-pipeline-modal-id-not-used">
+ <template #modal-title>
+ {{ $options.i18n.modalTitle }}
+ <gl-emoji class="gl-vertical-align-baseline font-size-inherit gl-mr-1" data-name="tada" />
+ </template>
<p>
- <gl-sprintf :message="$options.bodyMessage">
+ <gl-sprintf :message="$options.i18n.bodyMessage">
<template #codeQualityLink="{content}">
<gl-link :href="$options.codeQualityLink" target="_blank" class="font-size-inherit">{{
content
@@ -105,7 +99,7 @@ export default {
</template>
</gl-sprintf>
</p>
- <gl-sprintf :message="$options.helpMessage">
+ <gl-sprintf :message="$options.i18n.helpMessage">
<template #beginnerLink="{content}">
<gl-link :href="$options.beginnerLink" target="_blank">
{{ content }}
@@ -127,7 +121,7 @@ export default {
:data-track-event="$options.trackEvent"
:data-track-label="trackLabel"
>
- {{ $options.mergeRequestButton }}
+ {{ $options.i18n.mergeRequestButton }}
</gl-button>
<gl-button
ref="goToPipelines"
@@ -138,7 +132,7 @@ export default {
:data-track-event="$options.trackEvent"
:data-track-label="trackLabel"
>
- {{ $options.pipelinesButton }}
+ {{ $options.i18n.pipelinesButton }}
</gl-button>
</template>
</gl-modal>
diff --git a/app/assets/javascripts/blob/suggest_web_ide_ci/components/web_ide_alert.vue b/app/assets/javascripts/blob/suggest_web_ide_ci/components/web_ide_alert.vue
deleted file mode 100644
index 1308ca53e74..00000000000
--- a/app/assets/javascripts/blob/suggest_web_ide_ci/components/web_ide_alert.vue
+++ /dev/null
@@ -1,50 +0,0 @@
-<script>
-import { GlAlert, GlButton } from '@gitlab/ui';
-import axios from '~/lib/utils/axios_utils';
-
-export default {
- components: {
- GlAlert,
- GlButton,
- },
- props: {
- dismissEndpoint: {
- type: String,
- required: true,
- },
- featureId: {
- type: String,
- required: true,
- },
- editPath: {
- type: String,
- required: true,
- },
- },
- data() {
- return {
- showAlert: true,
- };
- },
- methods: {
- dismissAlert() {
- this.showAlert = false;
-
- return axios.post(this.dismissEndpoint, {
- feature_name: this.featureId,
- });
- },
- },
-};
-</script>
-
-<template>
- <gl-alert v-if="showAlert" class="gl-mt-5" @dismiss="dismissAlert">
- {{ __('The Web IDE offers advanced syntax highlighting capabilities and more.') }}
- <div class="gl-mt-5">
- <gl-button :href="editPath" category="primary" variant="info">{{
- __('Open Web IDE')
- }}</gl-button>
- </div>
- </gl-alert>
-</template>
diff --git a/app/assets/javascripts/blob/suggest_web_ide_ci/index.js b/app/assets/javascripts/blob/suggest_web_ide_ci/index.js
deleted file mode 100644
index eadf3cd6216..00000000000
--- a/app/assets/javascripts/blob/suggest_web_ide_ci/index.js
+++ /dev/null
@@ -1,20 +0,0 @@
-import Vue from 'vue';
-import WebIdeAlert from './components/web_ide_alert.vue';
-
-export default el => {
- const { dismissEndpoint, featureId, editPath } = el.dataset;
-
- // eslint-disable-next-line no-new
- new Vue({
- el,
- render(createElement) {
- return createElement(WebIdeAlert, {
- props: {
- dismissEndpoint,
- featureId,
- editPath,
- },
- });
- },
- });
-};
diff --git a/app/assets/javascripts/blob/viewer/index.js b/app/assets/javascripts/blob/viewer/index.js
index 05ee8e49eb1..aa76364c466 100644
--- a/app/assets/javascripts/blob/viewer/index.js
+++ b/app/assets/javascripts/blob/viewer/index.js
@@ -5,6 +5,7 @@ import { handleLocationHash } from '../../lib/utils/common_utils';
import axios from '../../lib/utils/axios_utils';
import eventHub from '../../notes/event_hub';
import { __ } from '~/locale';
+import { fixTitle } from '~/tooltips';
const loadRichBlobViewer = type => {
switch (type) {
@@ -124,7 +125,7 @@ export default class BlobViewer {
this.copySourceBtn.classList.add('disabled');
}
- $(this.copySourceBtn).tooltip('_fixTitle');
+ fixTitle($(this.copySourceBtn));
}
switchToViewer(name) {
@@ -179,9 +180,7 @@ export default class BlobViewer {
viewer.innerHTML = data.html;
viewer.setAttribute('data-loaded', 'true');
- if (window.gon?.features?.codeNavigation) {
- eventHub.$emit('showBlobInteractionZones', viewer.dataset.path);
- }
+ eventHub.$emit('showBlobInteractionZones', viewer.dataset.path);
return viewer;
});
diff --git a/app/assets/javascripts/blob_edit/blob_bundle.js b/app/assets/javascripts/blob_edit/blob_bundle.js
index c9972f0b43c..2d426ee663a 100644
--- a/app/assets/javascripts/blob_edit/blob_bundle.js
+++ b/app/assets/javascripts/blob_edit/blob_bundle.js
@@ -2,19 +2,17 @@
import $ from 'jquery';
import NewCommitForm from '../new_commit_form';
-import EditBlob from './edit_blob';
+import { deprecatedCreateFlash as createFlash } from '~/flash';
import BlobFileDropzone from '../blob/blob_file_dropzone';
import initPopover from '~/blob/suggest_gitlab_ci_yml';
import { disableButtonIfEmptyField, setCookie } from '~/lib/utils/common_utils';
import Tracking from '~/tracking';
-import initWebIdeAlert from '~/blob/suggest_web_ide_ci';
export default () => {
const editBlobForm = $('.js-edit-blob-form');
const uploadBlobForm = $('.js-upload-blob-form');
const deleteBlobForm = $('.js-delete-blob-form');
const suggestEl = document.querySelector('.js-suggest-gitlab-ci-yml');
- const alertEl = document.getElementById('js-suggest-web-ide-ci');
if (editBlobForm.length) {
const urlRoot = editBlobForm.data('relativeUrlRoot');
@@ -26,6 +24,18 @@ export default () => {
const commitButton = $('.js-commit-button');
const cancelLink = $('.btn.btn-cancel');
+ import('./edit_blob')
+ .then(({ default: EditBlob } = {}) => {
+ new EditBlob({
+ assetsPath: `${urlRoot}${assetsPath}`,
+ filePath,
+ currentAction,
+ projectId,
+ isMarkdown,
+ });
+ })
+ .catch(e => createFlash(e));
+
cancelLink.on('click', () => {
window.onbeforeunload = null;
});
@@ -34,13 +44,6 @@ export default () => {
window.onbeforeunload = null;
});
- new EditBlob({
- assetsPath: `${urlRoot}${assetsPath}`,
- filePath,
- currentAction,
- projectId,
- isMarkdown,
- });
new NewCommitForm(editBlobForm);
// returning here blocks page navigation
@@ -85,8 +88,4 @@ export default () => {
});
}
}
-
- if (alertEl) {
- initWebIdeAlert(alertEl);
- }
};
diff --git a/app/assets/javascripts/blob_edit/edit_blob.js b/app/assets/javascripts/blob_edit/edit_blob.js
index 2a4ab4b8827..e6b0a6fc1c5 100644
--- a/app/assets/javascripts/blob_edit/edit_blob.js
+++ b/app/assets/javascripts/blob_edit/edit_blob.js
@@ -1,91 +1,56 @@
-/* global ace */
-
import $ from 'jquery';
import axios from '~/lib/utils/axios_utils';
import { deprecatedCreateFlash as createFlash } from '~/flash';
import { BLOB_EDITOR_ERROR, BLOB_PREVIEW_ERROR } from './constants';
import TemplateSelectorMediator from '../blob/file_template_mediator';
-import getModeByFileExtension from '~/lib/utils/ace_utils';
import { addEditorMarkdownListeners } from '~/lib/utils/text_markdown';
-
-const monacoEnabledGlobally = window.gon.features?.monacoBlobs;
+import EditorLite from '~/editor/editor_lite';
+import FileTemplateExtension from '~/editor/editor_file_template_ext';
export default class EditBlob {
// The options object has:
// assetsPath, filePath, currentAction, projectId, isMarkdown
constructor(options) {
this.options = options;
- this.options.monacoEnabled = this.options.monacoEnabled ?? monacoEnabledGlobally;
- const { isMarkdown, monacoEnabled } = this.options;
- return Promise.resolve()
- .then(() => {
- return monacoEnabled ? this.configureMonacoEditor() : this.configureAceEditor();
- })
- .then(() => {
- this.initModePanesAndLinks();
- this.initFileSelectors();
- this.initSoftWrap();
- if (isMarkdown) {
+ this.configureMonacoEditor();
+
+ if (this.options.isMarkdown) {
+ import('~/editor/editor_markdown_ext')
+ .then(MarkdownExtension => {
+ this.editor.use(MarkdownExtension.default);
addEditorMarkdownListeners(this.editor);
- }
- this.editor.focus();
- })
- .catch(() => createFlash(BLOB_EDITOR_ERROR));
+ })
+ .catch(() => createFlash(BLOB_EDITOR_ERROR));
+ }
+
+ this.initModePanesAndLinks();
+ this.initFileSelectors();
+ this.initSoftWrap();
+ this.editor.focus();
}
configureMonacoEditor() {
- const EditorPromise = import(
- /* webpackChunkName: 'monaco_editor_lite' */ '~/editor/editor_lite'
- );
- const MarkdownExtensionPromise = this.options.isMarkdown
- ? import('~/editor/editor_markdown_ext')
- : Promise.resolve(false);
- const FileTemplateExtensionPromise = import('~/editor/editor_file_template_ext');
-
- return Promise.all([EditorPromise, MarkdownExtensionPromise, FileTemplateExtensionPromise])
- .then(([EditorModule, MarkdownExtension, FileTemplateExtension]) => {
- const EditorLite = EditorModule.default;
- const editorEl = document.getElementById('editor');
- const fileNameEl =
- document.getElementById('file_path') || document.getElementById('file_name');
- const fileContentEl = document.getElementById('file-content');
- const form = document.querySelector('.js-edit-blob-form');
-
- const rootEditor = new EditorLite();
-
- this.editor = rootEditor.createInstance({
- el: editorEl,
- blobPath: fileNameEl.value,
- blobContent: editorEl.innerText,
- });
-
- rootEditor.use([MarkdownExtension.default, FileTemplateExtension.default], this.editor);
-
- fileNameEl.addEventListener('change', () => {
- this.editor.updateModelLanguage(fileNameEl.value);
- });
-
- form.addEventListener('submit', () => {
- fileContentEl.value = this.editor.getValue();
- });
- })
- .catch(() => createFlash(BLOB_EDITOR_ERROR));
- }
+ const editorEl = document.getElementById('editor');
+ const fileNameEl = document.getElementById('file_path') || document.getElementById('file_name');
+ const fileContentEl = document.getElementById('file-content');
+ const form = document.querySelector('.js-edit-blob-form');
- configureAceEditor() {
- const { filePath, assetsPath } = this.options;
- ace.config.set('modePath', `${assetsPath}/ace`);
- ace.config.loadModule('ace/ext/searchbox');
- ace.config.loadModule('ace/ext/modelist');
+ const rootEditor = new EditorLite();
- this.editor = ace.edit('editor');
+ this.editor = rootEditor.createInstance({
+ el: editorEl,
+ blobPath: fileNameEl.value,
+ blobContent: editorEl.innerText,
+ });
+ this.editor.use(FileTemplateExtension);
- // This prevents warnings re: automatic scrolling being logged
- this.editor.$blockScrolling = Infinity;
+ fileNameEl.addEventListener('change', () => {
+ this.editor.updateModelLanguage(fileNameEl.value);
+ });
- if (filePath) {
- this.editor.getSession().setMode(getModeByFileExtension(filePath));
- }
+ form.addEventListener('submit', () => {
+ fileContentEl.value = this.editor.getValue();
+ });
}
initFileSelectors() {
@@ -137,7 +102,7 @@ export default class EditBlob {
}
initSoftWrap() {
- this.isSoftWrapped = Boolean(this.options.monacoEnabled);
+ this.isSoftWrapped = true;
this.$toggleButton = $('.soft-wrap-toggle');
this.$toggleButton.toggleClass('soft-wrap-active', this.isSoftWrapped);
this.$toggleButton.on('click', () => this.toggleSoftWrap());
@@ -146,10 +111,6 @@ export default class EditBlob {
toggleSoftWrap() {
this.isSoftWrapped = !this.isSoftWrapped;
this.$toggleButton.toggleClass('soft-wrap-active', this.isSoftWrapped);
- if (this.options.monacoEnabled) {
- this.editor.updateOptions({ wordWrap: this.isSoftWrapped ? 'on' : 'off' });
- } else {
- this.editor.getSession().setUseWrapMode(this.isSoftWrapped);
- }
+ this.editor.updateOptions({ wordWrap: this.isSoftWrapped ? 'on' : 'off' });
}
}
diff --git a/app/assets/javascripts/boards/boards_util.js b/app/assets/javascripts/boards/boards_util.js
index 5c8df94ca90..6b7b0c2e28d 100644
--- a/app/assets/javascripts/boards/boards_util.js
+++ b/app/assets/javascripts/boards/boards_util.js
@@ -2,11 +2,24 @@ import { sortBy } from 'lodash';
import ListIssue from 'ee_else_ce/boards/models/issue';
import { ListType } from './constants';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
+import boardsStore from '~/boards/stores/boards_store';
export function getMilestone() {
return null;
}
+export function formatBoardLists(lists) {
+ const formattedLists = lists.nodes.map(list =>
+ boardsStore.updateListPosition({ ...list, doNotFetchIssues: true }),
+ );
+ return formattedLists.reduce((map, list) => {
+ return {
+ ...map,
+ [list.id]: list,
+ };
+ }, {});
+}
+
export function formatIssue(issue) {
return new ListIssue({
...issue,
@@ -17,9 +30,15 @@ export function formatIssue(issue) {
export function formatListIssues(listIssues) {
const issues = {};
+ let listIssuesCount;
const listData = listIssues.nodes.reduce((map, list) => {
- const sortedIssues = sortBy(list.issues.nodes, 'relativePosition');
+ listIssuesCount = list.issues.count;
+ let sortedIssues = list.issues.edges.map(issueNode => ({
+ ...issueNode.node,
+ }));
+ sortedIssues = sortBy(sortedIssues, 'relativePosition');
+
return {
...map,
[list.id]: sortedIssues.map(i => {
@@ -39,13 +58,30 @@ export function formatListIssues(listIssues) {
};
}, {});
- return { listData, issues };
+ return { listData, issues, listIssuesCount };
+}
+
+export function formatListsPageInfo(lists) {
+ const listData = lists.nodes.reduce((map, list) => {
+ return {
+ ...map,
+ [list.id]: list.issues.pageInfo,
+ };
+ }, {});
+ return listData;
}
export function fullBoardId(boardId) {
return `gid://gitlab/Board/${boardId}`;
}
+export function fullLabelId(label) {
+ if (label.project_id !== null) {
+ return `gid://gitlab/ProjectLabel/${label.id}`;
+ }
+ return `gid://gitlab/GroupLabel/${label.id}`;
+}
+
export function moveIssueListHelper(issue, fromList, toList) {
if (toList.type === ListType.label) {
issue.addLabel(toList.label);
@@ -69,4 +105,5 @@ export default {
formatIssue,
formatListIssues,
fullBoardId,
+ fullLabelId,
};
diff --git a/app/assets/javascripts/boards/components/board_blank_state.vue b/app/assets/javascripts/boards/components/board_blank_state.vue
deleted file mode 100644
index 55e3e4a6329..00000000000
--- a/app/assets/javascripts/boards/components/board_blank_state.vue
+++ /dev/null
@@ -1,104 +0,0 @@
-<script>
-import { GlButton } from '@gitlab/ui';
-import Cookies from 'js-cookie';
-import { __ } from '~/locale';
-import ListLabel from '~/boards/models/label';
-import boardsStore from '../stores/boards_store';
-
-export default {
- components: {
- GlButton,
- },
- data() {
- return {
- predefinedLabels: [
- new ListLabel({ title: __('To Do'), color: '#F0AD4E' }),
- new ListLabel({ title: __('Doing'), color: '#5CB85C' }),
- ],
- };
- },
- methods: {
- addDefaultLists() {
- this.clearBlankState();
-
- this.predefinedLabels.forEach((label, i) => {
- boardsStore.addList({
- title: label.title,
- position: i,
- list_type: 'label',
- label: {
- title: label.title,
- color: label.color,
- },
- });
- });
-
- const loadListIssues = listObj => {
- const list = boardsStore.findList('title', listObj.title);
-
- if (!list) {
- return null;
- }
-
- list.id = listObj.id;
- list.label.id = listObj.label.id;
- return list.getIssues().catch(() => {
- // TODO: handle request error
- });
- };
-
- // Save the labels
- boardsStore
- .generateDefaultLists()
- .then(res => res.data)
- .then(data => Promise.all(data.map(loadListIssues)))
- .catch(() => {
- boardsStore.removeList(undefined, 'label');
- Cookies.remove('issue_board_welcome_hidden', {
- path: '',
- });
- boardsStore.addBlankState();
- });
- },
- clearBlankState: boardsStore.removeBlankState.bind(boardsStore),
- },
-};
-</script>
-
-<template>
- <div class="board-blank-state p-3">
- <p>
- {{
- s__('BoardBlankState|Add the following default lists to your Issue Board with one click:')
- }}
- </p>
- <ul class="list-unstyled board-blank-state-list">
- <li v-for="(label, index) in predefinedLabels" :key="index">
- <span
- :style="{ backgroundColor: label.color }"
- class="label-color position-relative d-inline-block rounded"
- ></span>
- {{ label.title }}
- </li>
- </ul>
- <p>
- {{
- s__(
- 'BoardBlankState|Starting out with the default set of lists will get you right on the way to making the most of your board.',
- )
- }}
- </p>
- <gl-button
- category="secondary"
- variant="success"
- block="block"
- class="gl-mb-0"
- @click.stop="addDefaultLists"
- >
- {{ s__('BoardBlankState|Add default lists') }}
- </gl-button>
- <gl-button category="secondary" variant="default" block="block" @click.stop="clearBlankState">
- {{ s__("BoardBlankState|Nevermind, I'll use my own") }}
- </gl-button>
- </div>
-</template>
diff --git a/app/assets/javascripts/boards/components/board_column.vue b/app/assets/javascripts/boards/components/board_column.vue
index 6d216911798..9295065b7b7 100644
--- a/app/assets/javascripts/boards/components/board_column.vue
+++ b/app/assets/javascripts/boards/components/board_column.vue
@@ -1,13 +1,12 @@
<script>
import { mapGetters, mapActions } from 'vuex';
import Sortable from 'sortablejs';
-import isWipLimitsOn from 'ee_else_ce/boards/mixins/is_wip_limits';
import BoardListHeader from 'ee_else_ce/boards/components/board_list_header.vue';
import Tooltip from '~/vue_shared/directives/tooltip';
import EmptyComponent from '~/vue_shared/components/empty_component';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
-import BoardBlankState from './board_blank_state.vue';
import BoardList from './board_list.vue';
+import BoardListNew from './board_list_new.vue';
import boardsStore from '../stores/boards_store';
import eventHub from '../eventhub';
import { getBoardSortableDefaultOptions, sortableEnd } from '../mixins/sortable_default_options';
@@ -16,14 +15,13 @@ import { ListType } from '../constants';
export default {
components: {
BoardPromotionState: EmptyComponent,
- BoardBlankState,
BoardListHeader,
- BoardList,
+ BoardList: gon.features?.graphqlBoardLists ? BoardListNew : BoardList,
},
directives: {
Tooltip,
},
- mixins: [isWipLimitsOn, glFeatureFlagMixin()],
+ mixins: [glFeatureFlagMixin()],
props: {
list: {
type: Object,
@@ -42,7 +40,7 @@ export default {
},
inject: {
boardId: {
- type: String,
+ default: '',
},
},
data() {
@@ -54,7 +52,7 @@ export default {
computed: {
...mapGetters(['getIssues']),
showBoardListAndBoardInfo() {
- return this.list.type !== ListType.blank && this.list.type !== ListType.promotion;
+ return this.list.type !== ListType.promotion;
},
uniqueKey() {
// eslint-disable-next-line @gitlab/require-i18n-strings
@@ -74,7 +72,7 @@ export default {
filter: {
handler() {
if (this.shouldFetchIssues) {
- this.fetchIssuesForList(this.list.id);
+ this.fetchIssuesForList({ listId: this.list.id });
} else {
this.list.page = 1;
this.list.getIssues(true).catch(() => {
@@ -87,7 +85,7 @@ export default {
},
mounted() {
if (this.shouldFetchIssues) {
- this.fetchIssuesForList(this.list.id);
+ this.fetchIssuesForList({ listId: this.list.id });
}
const instance = this;
@@ -146,9 +144,7 @@ export default {
:disabled="disabled"
:issues="listIssues"
:list="list"
- :loading="list.loading"
/>
- <board-blank-state v-if="canAdminList && list.id === 'blank'" />
<!-- Will be only available in EE -->
<board-promotion-state v-if="list.id === 'promotion'" />
diff --git a/app/assets/javascripts/boards/components/board_configuration_options.vue b/app/assets/javascripts/boards/components/board_configuration_options.vue
new file mode 100644
index 00000000000..ad3d653b905
--- /dev/null
+++ b/app/assets/javascripts/boards/components/board_configuration_options.vue
@@ -0,0 +1,65 @@
+<script>
+import { GlFormCheckbox } from '@gitlab/ui';
+
+export default {
+ components: {
+ GlFormCheckbox,
+ },
+ props: {
+ currentBoard: {
+ type: Object,
+ required: true,
+ },
+ board: {
+ type: Object,
+ required: true,
+ },
+ isNewForm: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ },
+ data() {
+ const { hide_backlog_list: hideBacklogList, hide_closed_list: hideClosedList } = this.isNewForm
+ ? this.board
+ : this.currentBoard;
+
+ return {
+ hideClosedList,
+ hideBacklogList,
+ };
+ },
+ methods: {
+ changeClosedList(checked) {
+ this.board.hideClosedList = !checked;
+ },
+ changeBacklogList(checked) {
+ this.board.hideBacklogList = !checked;
+ },
+ },
+};
+</script>
+
+<template>
+ <div class="append-bottom-20">
+ <label class="form-section-title label-bold" for="board-new-name">
+ {{ __('List options') }}
+ </label>
+ <p class="text-secondary gl-mb-3">
+ {{ __('Configure which lists are shown for anyone who visits this board') }}
+ </p>
+ <gl-form-checkbox
+ :checked="!hideBacklogList"
+ data-testid="backlog-list-checkbox"
+ @change="changeBacklogList"
+ >{{ __('Show the Open list') }}
+ </gl-form-checkbox>
+ <gl-form-checkbox
+ :checked="!hideClosedList"
+ data-testid="closed-list-checkbox"
+ @change="changeClosedList"
+ >{{ __('Show the Closed list') }}
+ </gl-form-checkbox>
+ </div>
+</template>
diff --git a/app/assets/javascripts/boards/components/board_content.vue b/app/assets/javascripts/boards/components/board_content.vue
index c7b3da0e672..2515f471379 100644
--- a/app/assets/javascripts/boards/components/board_content.vue
+++ b/app/assets/javascripts/boards/components/board_content.vue
@@ -1,5 +1,6 @@
<script>
import { mapState, mapGetters, mapActions } from 'vuex';
+import { sortBy } from 'lodash';
import BoardColumn from 'ee_else_ce/boards/components/board_column.vue';
import { GlAlert } from '@gitlab/ui';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
@@ -30,7 +31,9 @@ export default {
...mapState(['boardLists', 'error']),
...mapGetters(['isSwimlanesOn']),
boardListsToUse() {
- return this.glFeatures.graphqlBoardLists ? this.boardLists : this.lists;
+ const lists =
+ this.glFeatures.graphqlBoardLists || this.isSwimlanesOn ? this.boardLists : this.lists;
+ return sortBy([...Object.values(lists)], 'position');
},
},
mounted() {
@@ -68,7 +71,7 @@ export default {
<template v-else>
<epics-swimlanes
ref="swimlanes"
- :lists="boardLists"
+ :lists="boardListsToUse"
:can-admin-list="canAdminList"
:disabled="disabled"
/>
diff --git a/app/assets/javascripts/boards/components/board_delete.js b/app/assets/javascripts/boards/components/board_delete.js
deleted file mode 100644
index b74234a2e3c..00000000000
--- a/app/assets/javascripts/boards/components/board_delete.js
+++ /dev/null
@@ -1,30 +0,0 @@
-import $ from 'jquery';
-import Vue from 'vue';
-import { GlButton, GlTooltipDirective } from '@gitlab/ui';
-import { __ } from '~/locale';
-
-export default Vue.extend({
- components: {
- GlButton,
- },
- directives: {
- GlTooltip: GlTooltipDirective,
- },
- props: {
- list: {
- type: Object,
- default: () => ({}),
- required: false,
- },
- },
- methods: {
- deleteBoard() {
- $(this.$el).tooltip('hide');
-
- // eslint-disable-next-line no-alert
- if (window.confirm(__('Are you sure you want to delete this list?'))) {
- this.list.destroy();
- }
- },
- },
-});
diff --git a/app/assets/javascripts/boards/components/board_extra_actions.vue b/app/assets/javascripts/boards/components/board_extra_actions.vue
new file mode 100644
index 00000000000..b802ccc7882
--- /dev/null
+++ b/app/assets/javascripts/boards/components/board_extra_actions.vue
@@ -0,0 +1,57 @@
+<script>
+import { GlTooltip, GlButton } from '@gitlab/ui';
+import { __ } from '~/locale';
+
+export default {
+ name: 'BoardExtraActions',
+ components: {
+ GlTooltip,
+ GlButton,
+ },
+ props: {
+ canAdminList: {
+ type: Boolean,
+ required: true,
+ },
+ disabled: {
+ type: Boolean,
+ required: true,
+ },
+ openModal: {
+ type: Function,
+ required: true,
+ },
+ },
+ computed: {
+ tooltipTitle() {
+ if (this.disabled) {
+ return __('Please add a list to your board first');
+ }
+
+ return '';
+ },
+ },
+};
+</script>
+
+<template>
+ <div class="board-extra-actions">
+ <span ref="addIssuesButtonTooltip" class="gl-ml-3">
+ <gl-button
+ v-if="canAdminList"
+ type="button"
+ data-placement="bottom"
+ data-track-event="click_button"
+ data-track-label="board_add_issues"
+ :disabled="disabled"
+ :aria-disabled="disabled"
+ @click="openModal"
+ >
+ {{ __('Add issues') }}
+ </gl-button>
+ </span>
+ <gl-tooltip v-if="disabled" :target="() => $refs.addIssuesButtonTooltip" placement="bottom">
+ {{ tooltipTitle }}
+ </gl-tooltip>
+ </div>
+</template>
diff --git a/app/assets/javascripts/boards/components/board_form.vue b/app/assets/javascripts/boards/components/board_form.vue
index 385dd5fdc71..793c594cf16 100644
--- a/app/assets/javascripts/boards/components/board_form.vue
+++ b/app/assets/javascripts/boards/components/board_form.vue
@@ -5,6 +5,8 @@ import DeprecatedModal from '~/vue_shared/components/deprecated_modal.vue';
import { visitUrl } from '~/lib/utils/url_utility';
import boardsStore from '~/boards/stores/boards_store';
+import BoardConfigurationOptions from './board_configuration_options.vue';
+
const boardDefaults = {
id: false,
name: '',
@@ -13,12 +15,15 @@ const boardDefaults = {
assignee: {},
assignee_id: undefined,
weight: null,
+ hide_backlog_list: false,
+ hide_closed_list: false,
};
export default {
components: {
BoardScope: () => import('ee_component/boards/components/board_scope.vue'),
DeprecatedModal,
+ BoardConfigurationOptions,
},
props: {
canAdminBoard: {
@@ -140,7 +145,17 @@ export default {
} else {
boardsStore
.createBoard(this.board)
- .then(resp => resp.data)
+ .then(resp => {
+ // This handles 2 use cases
+ // - In create call we only get one parameter, the new board
+ // - In update call, due to Promise.all, we get REST response in
+ // array index 0
+
+ if (Array.isArray(resp)) {
+ return resp[0].data;
+ }
+ return resp.data ? resp.data : resp;
+ })
.then(data => {
visitUrl(data.board_path);
})
@@ -182,7 +197,7 @@ export default {
<form v-else class="js-board-config-modal" @submit.prevent>
<div v-if="!readonly" class="append-bottom-20">
<label class="form-section-title label-bold" for="board-new-name">{{
- __('Board name')
+ __('Title')
}}</label>
<input
id="board-new-name"
@@ -196,6 +211,12 @@ export default {
/>
</div>
+ <board-configuration-options
+ :is-new-form="isNewForm"
+ :board="board"
+ :current-board="currentBoard"
+ />
+
<board-scope
v-if="scopedIssueBoardFeatureEnabled"
:collapse-scope="isNewForm"
diff --git a/app/assets/javascripts/boards/components/board_list.vue b/app/assets/javascripts/boards/components/board_list.vue
index 25f8ffca633..d01df44e7e4 100644
--- a/app/assets/javascripts/boards/components/board_list.vue
+++ b/app/assets/javascripts/boards/components/board_list.vue
@@ -14,6 +14,8 @@ import {
sortableEnd,
} from '../mixins/sortable_default_options';
+// This component is being replaced in favor of './board_list_new.vue' for GraphQL boards
+
if (gon.features && gon.features.multiSelectBoard) {
Sortable.mount(new MultiDrag());
}
@@ -39,10 +41,6 @@ export default {
type: Array,
required: true,
},
- loading: {
- type: Boolean,
- required: true,
- },
},
data() {
return {
@@ -62,6 +60,9 @@ export default {
issuesSizeExceedsMax() {
return this.list.maxIssueCount > 0 && this.list.issuesSize > this.list.maxIssueCount;
},
+ loading() {
+ return this.list.loading;
+ },
},
watch: {
filters: {
@@ -72,7 +73,6 @@ export default {
deep: true,
},
issues() {
- if (this.glFeatures.graphqlBoardLists) return;
this.$nextTick(() => {
if (
this.scrollHeight() <= this.listHeight() &&
@@ -98,6 +98,8 @@ export default {
eventHub.$on(`scroll-board-list-${this.list.id}`, this.scrollToTop);
},
mounted() {
+ // TODO: Use Draggable in ./board_list_new.vue to drag & drop issue
+ // https://gitlab.com/gitlab-org/gitlab/-/issues/218164
const multiSelectOpts = {};
if (gon.features && gon.features.multiSelectBoard) {
multiSelectOpts.multiDrag = true;
@@ -403,8 +405,6 @@ export default {
this.showIssueForm = !this.showIssueForm;
},
onScroll() {
- if (this.glFeatures.graphqlBoardLists) return;
-
if (!this.list.loadingMore && this.scrollTop() > this.scrollHeight() - this.scrollOffset) {
this.loadNextPage();
}
diff --git a/app/assets/javascripts/boards/components/board_list_header.vue b/app/assets/javascripts/boards/components/board_list_header.vue
index 361fe252afb..bb9a1b79d91 100644
--- a/app/assets/javascripts/boards/components/board_list_header.vue
+++ b/app/assets/javascripts/boards/components/board_list_header.vue
@@ -1,5 +1,5 @@
<script>
-import { mapActions } from 'vuex';
+import { mapActions, mapState } from 'vuex';
import {
GlButton,
GlButtonGroup,
@@ -9,20 +9,18 @@ import {
GlSprintf,
GlTooltipDirective,
} from '@gitlab/ui';
-import isWipLimitsOn from 'ee_else_ce/boards/mixins/is_wip_limits';
import { n__, s__ } from '~/locale';
import AccessorUtilities from '../../lib/utils/accessor';
-import BoardDelete from './board_delete';
import IssueCount from './issue_count.vue';
import boardsStore from '../stores/boards_store';
import eventHub from '../eventhub';
-import { ListType } from '../constants';
+import sidebarEventHub from '~/sidebar/event_hub';
+import { inactiveId, LIST, ListType } from '../constants';
import { isScopedLabel } from '~/lib/utils/common_utils';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
export default {
components: {
- BoardDelete,
GlButtonGroup,
GlButton,
GlLabel,
@@ -34,7 +32,7 @@ export default {
directives: {
GlTooltip: GlTooltipDirective,
},
- mixins: [isWipLimitsOn, glFeatureFlagMixin()],
+ mixins: [glFeatureFlagMixin()],
props: {
list: {
type: Object,
@@ -45,11 +43,6 @@ export default {
type: Boolean,
required: true,
},
- canAdminList: {
- type: Boolean,
- required: false,
- default: false,
- },
isSwimlanesHeader: {
type: Boolean,
required: false,
@@ -58,7 +51,7 @@ export default {
},
inject: {
boardId: {
- type: String,
+ default: '',
},
},
data() {
@@ -67,6 +60,7 @@ export default {
};
},
computed: {
+ ...mapState(['activeId']),
isLoggedIn() {
return Boolean(gon.current_user_id);
},
@@ -114,10 +108,7 @@ export default {
},
isSettingsShown() {
return (
- this.listType !== ListType.backlog &&
- this.showListHeaderButton &&
- this.list.isExpanded &&
- this.isWipLimitsOn
+ this.listType !== ListType.backlog && this.showListHeaderButton && this.list.isExpanded
);
},
showBoardListAndBoardInfo() {
@@ -135,7 +126,14 @@ export default {
},
},
methods: {
- ...mapActions(['updateList']),
+ ...mapActions(['updateList', 'setActiveId']),
+ openSidebarSettings() {
+ if (this.activeId === inactiveId) {
+ sidebarEventHub.$emit('sidebar.closeAll');
+ }
+
+ this.setActiveId({ id: this.list.id, sidebarType: LIST });
+ },
showScopedLabels(label) {
return boardsStore.scopedLabels.enabled && isScopedLabel(label);
},
@@ -176,7 +174,6 @@ export default {
<header
:class="{
'has-border': list.label && list.label.color,
- 'gl-relative': list.isExpanded,
'gl-h-full': !list.isExpanded,
'board-inner gl-rounded-top-left-base gl-rounded-top-right-base': isSwimlanesHeader,
}"
@@ -279,22 +276,6 @@ export default {
</div>
</gl-tooltip>
- <board-delete
- v-if="canAdminList && !list.preset && list.id"
- :list="list"
- inline-template="true"
- >
- <gl-button
- v-gl-tooltip.hover.bottom
- :class="{ 'gl-display-none': !list.isExpanded }"
- :aria-label="__('Delete list')"
- class="board-delete no-drag gl-pr-0 gl-shadow-none! gl-mr-3"
- :title="__('Delete list')"
- icon="remove"
- size="small"
- @click.stop="deleteBoard"
- />
- </board-delete>
<div
v-if="showBoardListAndBoardInfo"
class="issue-count-badge gl-display-inline-flex gl-pr-0 no-drag text-secondary"
diff --git a/app/assets/javascripts/boards/components/board_list_new.vue b/app/assets/javascripts/boards/components/board_list_new.vue
new file mode 100644
index 00000000000..0a495d05122
--- /dev/null
+++ b/app/assets/javascripts/boards/components/board_list_new.vue
@@ -0,0 +1,166 @@
+<script>
+import { mapActions, mapState } from 'vuex';
+import { GlLoadingIcon } from '@gitlab/ui';
+import BoardNewIssue from './board_new_issue.vue';
+import BoardCard from './board_card.vue';
+import eventHub from '../eventhub';
+import boardsStore from '../stores/boards_store';
+import { sprintf, __ } from '~/locale';
+import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
+
+export default {
+ name: 'BoardList',
+ components: {
+ BoardCard,
+ BoardNewIssue,
+ GlLoadingIcon,
+ },
+ mixins: [glFeatureFlagMixin()],
+ props: {
+ disabled: {
+ type: Boolean,
+ required: true,
+ },
+ list: {
+ type: Object,
+ required: true,
+ },
+ issues: {
+ type: Array,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ scrollOffset: 250,
+ filters: boardsStore.state.filters,
+ showCount: false,
+ showIssueForm: false,
+ };
+ },
+ computed: {
+ ...mapState(['pageInfoByListId', 'listsFlags']),
+ paginatedIssueText() {
+ return sprintf(__('Showing %{pageSize} of %{total} issues'), {
+ pageSize: this.issues.length,
+ total: this.list.issuesSize,
+ });
+ },
+ issuesSizeExceedsMax() {
+ return this.list.maxIssueCount > 0 && this.list.issuesSize > this.list.maxIssueCount;
+ },
+ hasNextPage() {
+ return this.pageInfoByListId[this.list.id].hasNextPage;
+ },
+ loading() {
+ return this.listsFlags[this.list.id]?.isLoading;
+ },
+ },
+ watch: {
+ filters: {
+ handler() {
+ this.list.loadingMore = false;
+ this.$refs.list.scrollTop = 0;
+ },
+ deep: true,
+ },
+ issues() {
+ this.$nextTick(() => {
+ this.showCount = this.scrollHeight() > Math.ceil(this.listHeight());
+ });
+ },
+ },
+ created() {
+ eventHub.$on(`toggle-issue-form-${this.list.id}`, this.toggleForm);
+ eventHub.$on(`scroll-board-list-${this.list.id}`, this.scrollToTop);
+ },
+ mounted() {
+ // Scroll event on list to load more
+ this.$refs.list.addEventListener('scroll', this.onScroll);
+ },
+ beforeDestroy() {
+ eventHub.$off(`toggle-issue-form-${this.list.id}`, this.toggleForm);
+ eventHub.$off(`scroll-board-list-${this.list.id}`, this.scrollToTop);
+ this.$refs.list.removeEventListener('scroll', this.onScroll);
+ },
+ methods: {
+ ...mapActions(['fetchIssuesForList']),
+ listHeight() {
+ return this.$refs.list.getBoundingClientRect().height;
+ },
+ scrollHeight() {
+ return this.$refs.list.scrollHeight;
+ },
+ scrollTop() {
+ return this.$refs.list.scrollTop + this.listHeight();
+ },
+ scrollToTop() {
+ this.$refs.list.scrollTop = 0;
+ },
+ loadNextPage() {
+ const loadingDone = () => {
+ this.list.loadingMore = false;
+ };
+ this.list.loadingMore = true;
+ this.fetchIssuesForList({ listId: this.list.id, fetchNext: true })
+ .then(loadingDone)
+ .catch(loadingDone);
+ },
+ toggleForm() {
+ this.showIssueForm = !this.showIssueForm;
+ },
+ onScroll() {
+ window.requestAnimationFrame(() => {
+ if (
+ !this.list.loadingMore &&
+ this.scrollTop() > this.scrollHeight() - this.scrollOffset &&
+ this.hasNextPage
+ ) {
+ this.loadNextPage();
+ }
+ });
+ },
+ },
+};
+</script>
+
+<template>
+ <div
+ v-show="list.isExpanded"
+ class="board-list-component gl-relative gl-h-full gl-display-flex gl-flex-direction-column"
+ data-qa-selector="board_list_cards_area"
+ >
+ <div
+ v-if="loading"
+ class="gl-mt-4 gl-text-center"
+ :aria-label="__('Loading issues')"
+ data-testid="board_list_loading"
+ >
+ <gl-loading-icon />
+ </div>
+ <board-new-issue v-if="list.type !== 'closed' && showIssueForm" :list="list" />
+ <ul
+ v-show="!loading"
+ ref="list"
+ :data-board="list.id"
+ :data-board-type="list.type"
+ :class="{ 'bg-danger-100': issuesSizeExceedsMax }"
+ class="board-list gl-w-full gl-h-full gl-list-style-none gl-mb-0 gl-p-2 js-board-list"
+ >
+ <board-card
+ v-for="(issue, index) in issues"
+ ref="issue"
+ :key="issue.id"
+ :index="index"
+ :list="list"
+ :issue="issue"
+ :disabled="disabled"
+ />
+ <li v-if="showCount" class="board-list-count gl-text-center" data-issue-id="-1">
+ <gl-loading-icon v-show="list.loadingMore" label="Loading more issues" />
+ <span v-if="issues.length === list.issuesSize">{{ __('Showing all issues') }}</span>
+ <span v-else>{{ paginatedIssueText }}</span>
+ </li>
+ </ul>
+ </div>
+</template>
diff --git a/app/assets/javascripts/boards/components/board_new_issue.vue b/app/assets/javascripts/boards/components/board_new_issue.vue
index 348d485ff37..0a665b82880 100644
--- a/app/assets/javascripts/boards/components/board_new_issue.vue
+++ b/app/assets/javascripts/boards/components/board_new_issue.vue
@@ -22,11 +22,7 @@ export default {
required: true,
},
},
- inject: {
- groupId: {
- type: Number,
- },
- },
+ inject: ['groupId'],
data() {
return {
title: '',
diff --git a/app/assets/javascripts/boards/components/board_settings_sidebar.vue b/app/assets/javascripts/boards/components/board_settings_sidebar.vue
index e2600883e89..392e056dcbf 100644
--- a/app/assets/javascripts/boards/components/board_settings_sidebar.vue
+++ b/app/assets/javascripts/boards/components/board_settings_sidebar.vue
@@ -1,5 +1,5 @@
<script>
-import { GlDrawer, GlLabel } from '@gitlab/ui';
+import { GlButton, GlDrawer, GlLabel } from '@gitlab/ui';
import { mapActions, mapState, mapGetters } from 'vuex';
import { __ } from '~/locale';
import boardsStore from '~/boards/stores/boards_store';
@@ -17,6 +17,7 @@ export default {
label: 'label',
labelListText: __('Label'),
components: {
+ GlButton,
GlDrawer,
GlLabel,
BoardSettingsSidebarWipLimit: () =>
@@ -25,16 +26,23 @@ export default {
import('ee_component/boards/components/board_settings_list_types.vue'),
},
mixins: [glFeatureFlagMixin()],
+ props: {
+ canAdminList: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ },
computed: {
- ...mapGetters(['isSidebarOpen']),
+ ...mapGetters(['isSidebarOpen', 'shouldUseGraphQL']),
...mapState(['activeId', 'sidebarType', 'boardLists']),
activeList() {
/*
Warning: Though a computed property it is not reactive because we are
referencing a List Model class. Reactivity only applies to plain JS objects
*/
- if (this.glFeatures.graphqlBoardLists) {
- return this.boardLists.find(({ id }) => id === this.activeId);
+ if (this.shouldUseGraphQL) {
+ return this.boardLists[this.activeId];
}
return boardsStore.state.lists.find(({ id }) => id === this.activeId);
},
@@ -62,6 +70,13 @@ export default {
showScopedLabels(label) {
return boardsStore.scopedLabels.enabled && isScopedLabel(label);
},
+ deleteBoard() {
+ // eslint-disable-next-line no-alert
+ if (window.confirm(__('Are you sure you want to delete this list?'))) {
+ this.activeList.destroy();
+ this.unsetActiveId();
+ }
+ },
},
};
</script>
@@ -91,6 +106,16 @@ export default {
:board-list-type="boardListType"
/>
<board-settings-sidebar-wip-limit :max-issue-count="activeList.maxIssueCount" />
+ <div v-if="canAdminList && !activeList.preset && activeList.id" class="gl-m-4">
+ <gl-button
+ variant="danger"
+ category="secondary"
+ icon="remove"
+ data-testid="remove-list"
+ @click.stop="deleteBoard"
+ >{{ __('Remove list') }}
+ </gl-button>
+ </div>
</template>
</gl-drawer>
</template>
diff --git a/app/assets/javascripts/boards/components/issue_card_inner.vue b/app/assets/javascripts/boards/components/issue_card_inner.vue
index 8658f51e5cf..a181ea51c4a 100644
--- a/app/assets/javascripts/boards/components/issue_card_inner.vue
+++ b/app/assets/javascripts/boards/components/issue_card_inner.vue
@@ -41,14 +41,7 @@ export default {
default: false,
},
},
- inject: {
- groupId: {
- type: Number,
- },
- rootPath: {
- type: String,
- },
- },
+ inject: ['groupId', 'rootPath'],
data() {
return {
limitBeforeCounter: 2,
diff --git a/app/assets/javascripts/boards/components/modal/tabs.vue b/app/assets/javascripts/boards/components/modal/tabs.vue
index a71fda9d7c5..b066fb25360 100644
--- a/app/assets/javascripts/boards/components/modal/tabs.vue
+++ b/app/assets/javascripts/boards/components/modal/tabs.vue
@@ -1,9 +1,15 @@
<script>
/* eslint-disable @gitlab/vue-require-i18n-strings */
+import { GlTabs, GlTab, GlBadge } from '@gitlab/ui';
import ModalStore from '../../stores/modal_store';
import modalMixin from '../../mixins/modal_mixins';
export default {
+ components: {
+ GlTabs,
+ GlTab,
+ GlBadge,
+ },
mixins: [modalMixin],
data() {
return ModalStore.store;
@@ -19,18 +25,18 @@ export default {
};
</script>
<template>
- <div class="top-area gl-mt-3 gl-mb-3">
- <ul class="nav-links issues-state-filters">
- <li :class="{ active: activeTab == 'all' }">
- <a href="#" role="button" @click.prevent="changeTab('all')">
- Open issues <span class="badge badge-pill"> {{ issuesCount }} </span>
- </a>
- </li>
- <li :class="{ active: activeTab == 'selected' }">
- <a href="#" role="button" @click.prevent="changeTab('selected')">
- Selected issues <span class="badge badge-pill"> {{ selectedCount }} </span>
- </a>
- </li>
- </ul>
- </div>
+ <gl-tabs class="gl-mt-3">
+ <gl-tab @click.prevent="changeTab('all')">
+ <template slot="title">
+ <span>Open issues</span>
+ <gl-badge size="sm" class="gl-tab-counter-badge">{{ issuesCount }}</gl-badge>
+ </template>
+ </gl-tab>
+ <gl-tab @click.prevent="changeTab('selected')">
+ <template slot="title">
+ <span>Selected issues</span>
+ <gl-badge size="sm" class="gl-tab-counter-badge">{{ selectedCount }}</gl-badge>
+ </template>
+ </gl-tab>
+ </gl-tabs>
</template>
diff --git a/app/assets/javascripts/boards/components/new_list_dropdown.js b/app/assets/javascripts/boards/components/new_list_dropdown.js
index 2e356f1353a..c8926c5ef2a 100644
--- a/app/assets/javascripts/boards/components/new_list_dropdown.js
+++ b/app/assets/javascripts/boards/components/new_list_dropdown.js
@@ -6,8 +6,14 @@ import axios from '~/lib/utils/axios_utils';
import { deprecatedCreateFlash as flash } from '~/flash';
import CreateLabelDropdown from '../../create_label';
import boardsStore from '../stores/boards_store';
+import { fullLabelId } from '../boards_util';
+import store from '~/boards/stores';
import initDeprecatedJQueryDropdown from '~/deprecated_jquery_dropdown';
+function shouldCreateListGraphQL(label) {
+ return store.getters.shouldUseGraphQL && !store.getters.getListByLabelId(fullLabelId(label));
+}
+
$(document)
.off('created.label')
.on('created.label', (e, label, addNewList) => {
@@ -15,16 +21,20 @@ $(document)
return;
}
- boardsStore.new({
- title: label.title,
- position: boardsStore.state.lists.length - 2,
- list_type: 'label',
- label: {
- id: label.id,
+ if (shouldCreateListGraphQL(label)) {
+ store.dispatch('createList', { labelId: fullLabelId(label) });
+ } else {
+ boardsStore.new({
title: label.title,
- color: label.color,
- },
- });
+ position: boardsStore.state.lists.length - 2,
+ list_type: 'label',
+ label: {
+ id: label.id,
+ title: label.title,
+ color: label.color,
+ },
+ });
+ }
});
export default function initNewListDropdown() {
@@ -74,7 +84,9 @@ export default function initNewListDropdown() {
const label = options.selectedObj;
e.preventDefault();
- if (!boardsStore.findListByLabelId(label.id)) {
+ if (shouldCreateListGraphQL(label)) {
+ store.dispatch('createList', { labelId: fullLabelId(label) });
+ } else if (!boardsStore.findListByLabelId(label.id)) {
boardsStore.new({
title: label.title,
position: boardsStore.state.lists.length - 2,
diff --git a/app/assets/javascripts/boards/components/project_select.vue b/app/assets/javascripts/boards/components/project_select.vue
index 59e7620962a..566c0081b9d 100644
--- a/app/assets/javascripts/boards/components/project_select.vue
+++ b/app/assets/javascripts/boards/components/project_select.vue
@@ -20,11 +20,7 @@ export default {
required: true,
},
},
- inject: {
- groupId: {
- type: Number,
- },
- },
+ inject: ['groupId'],
data() {
return {
loading: true,
diff --git a/app/assets/javascripts/boards/components/sidebar/board_editable_item.vue b/app/assets/javascripts/boards/components/sidebar/board_editable_item.vue
index 8df03ea581f..5fb7a9b210c 100644
--- a/app/assets/javascripts/boards/components/sidebar/board_editable_item.vue
+++ b/app/assets/javascripts/boards/components/sidebar/board_editable_item.vue
@@ -36,16 +36,18 @@ export default {
}
this.edit = true;
- this.$emit('changed', this.edit);
+ this.$emit('open');
window.addEventListener('click', this.collapseWhenOffClick);
},
- collapse() {
+ collapse({ emitEvent = true } = {}) {
if (!this.edit) {
return;
}
this.edit = false;
- this.$emit('changed', this.edit);
+ if (emitEvent) {
+ this.$emit('close');
+ }
window.removeEventListener('click', this.collapseWhenOffClick);
},
},
diff --git a/app/assets/javascripts/boards/components/sidebar/board_sidebar_labels_select.vue b/app/assets/javascripts/boards/components/sidebar/board_sidebar_labels_select.vue
new file mode 100644
index 00000000000..0f063c7582e
--- /dev/null
+++ b/app/assets/javascripts/boards/components/sidebar/board_sidebar_labels_select.vue
@@ -0,0 +1,120 @@
+<script>
+import { mapGetters, mapActions } from 'vuex';
+import { GlLabel } from '@gitlab/ui';
+import LabelsSelect from '~/vue_shared/components/sidebar/labels_select_vue/labels_select_root.vue';
+import { getIdFromGraphQLId } from '~/graphql_shared/utils';
+import BoardEditableItem from '~/boards/components/sidebar/board_editable_item.vue';
+import { isScopedLabel } from '~/lib/utils/common_utils';
+import createFlash from '~/flash';
+import { __ } from '~/locale';
+
+export default {
+ components: {
+ BoardEditableItem,
+ LabelsSelect,
+ GlLabel,
+ },
+ data() {
+ return {
+ loading: false,
+ };
+ },
+ inject: ['labelsFetchPath', 'labelsManagePath', 'labelsFilterBasePath'],
+ computed: {
+ ...mapGetters({ issue: 'getActiveIssue' }),
+ selectedLabels() {
+ const { labels = [] } = this.issue;
+
+ return labels.map(label => ({
+ ...label,
+ id: getIdFromGraphQLId(label.id),
+ }));
+ },
+ issueLabels() {
+ const { labels = [] } = this.issue;
+
+ return labels.map(label => ({
+ ...label,
+ scoped: isScopedLabel(label),
+ }));
+ },
+ projectPath() {
+ const { referencePath = '' } = this.issue;
+ return referencePath.slice(0, referencePath.indexOf('#'));
+ },
+ },
+ methods: {
+ ...mapActions(['setActiveIssueLabels']),
+ async setLabels(payload) {
+ this.loading = true;
+ this.$refs.sidebarItem.collapse();
+
+ try {
+ const addLabelIds = payload.filter(label => label.set).map(label => label.id);
+ const removeLabelIds = this.selectedLabels
+ .filter(label => !payload.find(selected => selected.id === label.id))
+ .map(label => label.id);
+
+ const input = { addLabelIds, removeLabelIds, projectPath: this.projectPath };
+ await this.setActiveIssueLabels(input);
+ } catch (e) {
+ createFlash({ message: __('An error occurred while updating labels.') });
+ } finally {
+ this.loading = false;
+ }
+ },
+ async removeLabel(id) {
+ this.loading = true;
+
+ try {
+ const removeLabelIds = [getIdFromGraphQLId(id)];
+ const input = { removeLabelIds, projectPath: this.projectPath };
+ await this.setActiveIssueLabels(input);
+ } catch (e) {
+ createFlash({ message: __('An error occurred when removing the label.') });
+ } finally {
+ this.loading = false;
+ }
+ },
+ },
+};
+</script>
+
+<template>
+ <board-editable-item ref="sidebarItem" :title="__('Labels')" :loading="loading">
+ <template #collapsed>
+ <gl-label
+ v-for="label in issueLabels"
+ :key="label.id"
+ :background-color="label.color"
+ :title="label.title"
+ :description="label.description"
+ :scoped="label.scoped"
+ :show-close-button="true"
+ :disabled="loading"
+ class="gl-mr-2 gl-mb-2"
+ @close="removeLabel(label.id)"
+ />
+ </template>
+ <template>
+ <labels-select
+ ref="labelsSelect"
+ :allow-label-edit="false"
+ :allow-label-create="false"
+ :allow-multiselect="true"
+ :allow-scoped-labels="true"
+ :selected-labels="selectedLabels"
+ :labels-fetch-path="labelsFetchPath"
+ :labels-manage-path="labelsManagePath"
+ :labels-filter-base-path="labelsFilterBasePath"
+ :labels-list-title="__('Select label')"
+ :dropdown-button-text="__('Choose labels')"
+ variant="embedded"
+ class="gl-display-block labels gl-w-full"
+ @updateSelectedLabels="setLabels"
+ >
+ {{ __('None') }}
+ </labels-select>
+ </template>
+ </board-editable-item>
+</template>
diff --git a/app/assets/javascripts/boards/ee_functions.js b/app/assets/javascripts/boards/ee_functions.js
index 583270fcae5..419a640d5c5 100644
--- a/app/assets/javascripts/boards/ee_functions.js
+++ b/app/assets/javascripts/boards/ee_functions.js
@@ -1,6 +1,6 @@
export const setPromotionState = () => {};
-export const setWeigthFetchingState = () => {};
+export const setWeightFetchingState = () => {};
export const setEpicFetchingState = () => {};
export const getMilestoneTitle = () => ({});
diff --git a/app/assets/javascripts/boards/filtered_search_boards.js b/app/assets/javascripts/boards/filtered_search_boards.js
index fff89832bf0..4fa78ecd5a4 100644
--- a/app/assets/javascripts/boards/filtered_search_boards.js
+++ b/app/assets/javascripts/boards/filtered_search_boards.js
@@ -25,7 +25,8 @@ export default class FilteredSearchBoards extends FilteredSearchManager {
}
updateObject(path) {
- this.store.path = path.substr(1);
+ const groupByParam = new URLSearchParams(window.location.search).get('group_by');
+ this.store.path = `${path.substr(1)}${groupByParam ? `&group_by=${groupByParam}` : ''}`;
if (gon.features.boardsWithSwimlanes || gon.features.graphqlBoardLists) {
boardsStore.updateFiltersUrl();
diff --git a/app/assets/javascripts/boards/icons/fullscreen_collapse.svg b/app/assets/javascripts/boards/icons/fullscreen_collapse.svg
deleted file mode 100644
index 6bd773dc4c5..00000000000
--- a/app/assets/javascripts/boards/icons/fullscreen_collapse.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg width="17" height="17" viewBox="0 0 17 17" xmlns="http://www.w3.org/2000/svg"><path d="M.147 15.496l2.146-2.146-1.286-1.286a.55.55 0 0 1-.125-.616c.101-.238.277-.357.527-.357h4a.55.55 0 0 1 .402.17.55.55 0 0 1 .17.401v4c0 .25-.12.426-.358.527-.232.101-.437.06-.616-.125l-1.286-1.286-2.146 2.146-1.428-1.428zM14.996.646l1.428 1.43-2.146 2.145 1.286 1.286c.185.179.226.384.125.616-.101.238-.277.357-.527.357h-4a.55.55 0 0 1-.402-.17.55.55 0 0 1-.17-.401v-4c0-.25.12-.426.358-.527a.553.553 0 0 1 .616.125l1.286 1.286L14.996.647zm-13.42 0L3.72 2.794l1.286-1.286a.55.55 0 0 1 .616-.125c.238.101.357.277.357.527v4a.55.55 0 0 1-.17.402.55.55 0 0 1-.401.17h-4c-.25 0-.426-.12-.527-.358-.101-.232-.06-.437.125-.616l1.286-1.286L.147 2.075 1.575.647zm14.848 14.85l-1.428 1.428-2.146-2.146-1.286 1.286c-.179.185-.384.226-.616.125-.238-.101-.357-.277-.357-.527v-4a.55.55 0 0 1 .17-.402.55.55 0 0 1 .401-.17h4c.25 0 .426.12.527.358a.553.553 0 0 1-.125.616l-1.286 1.286 2.146 2.146z" fill-rule="evenodd"/></svg>
diff --git a/app/assets/javascripts/boards/icons/fullscreen_expand.svg b/app/assets/javascripts/boards/icons/fullscreen_expand.svg
deleted file mode 100644
index 306073b8af2..00000000000
--- a/app/assets/javascripts/boards/icons/fullscreen_expand.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg width="15" height="15" viewBox="0 0 15 15" xmlns="http://www.w3.org/2000/svg"><path d="M8.591 5.056l2.147-2.146-1.286-1.286a.55.55 0 0 1-.125-.616c.101-.238.277-.357.527-.357h4a.55.55 0 0 1 .402.17.55.55 0 0 1 .17.401v4c0 .25-.12.426-.358.527-.232.101-.437.06-.616-.125l-1.286-1.286-2.146 2.147-1.429-1.43zM5.018 8.553l1.429 1.43L4.3 12.127l1.286 1.286c.185.179.226.384.125.616-.101.238-.277.357-.527.357h-4a.55.55 0 0 1-.402-.17.55.55 0 0 1-.17-.401v-4c0-.25.12-.426.358-.527a.553.553 0 0 1 .616.125L2.872 10.7l2.146-2.147zm4.964 0l2.146 2.147 1.286-1.286a.55.55 0 0 1 .616-.125c.238.101.357.277.357.527v4a.55.55 0 0 1-.17.402.55.55 0 0 1-.401.17h-4c-.25 0-.426-.12-.527-.358-.101-.232-.06-.437.125-.616l1.286-1.286-2.147-2.146 1.43-1.429zM6.447 5.018l-1.43 1.429L2.873 4.3 1.586 5.586c-.179.185-.384.226-.616.125-.238-.101-.357-.277-.357-.527v-4a.55.55 0 0 1 .17-.402.55.55 0 0 1 .401-.17h4c.25 0 .426.12.527.358a.553.553 0 0 1-.125.616L4.3 2.872l2.147 2.146z" fill-rule="evenodd"/></svg>
diff --git a/app/assets/javascripts/boards/index.js b/app/assets/javascripts/boards/index.js
index 1173c6d0578..887abe79059 100644
--- a/app/assets/javascripts/boards/index.js
+++ b/app/assets/javascripts/boards/index.js
@@ -1,4 +1,3 @@
-import $ from 'jquery';
import Vue from 'vue';
import { mapActions, mapState } from 'vuex';
@@ -11,7 +10,7 @@ import toggleLabels from 'ee_else_ce/boards/toggle_labels';
import toggleEpicsSwimlanes from 'ee_else_ce/boards/toggle_epics_swimlanes';
import {
setPromotionState,
- setWeigthFetchingState,
+ setWeightFetchingState,
setEpicFetchingState,
getMilestoneTitle,
getBoardsModalData,
@@ -19,6 +18,7 @@ import {
import VueApollo from 'vue-apollo';
import BoardContent from '~/boards/components/board_content.vue';
+import BoardExtraActions from '~/boards/components/board_extra_actions.vue';
import createDefaultClient from '~/lib/graphql';
import { deprecatedCreateFlash as Flash } from '~/flash';
import { __ } from '~/locale';
@@ -84,8 +84,12 @@ export default () => {
},
provide: {
boardId: $boardApp.dataset.boardId,
- groupId: Number($boardApp.dataset.groupId) || null,
+ groupId: Number($boardApp.dataset.groupId),
rootPath: $boardApp.dataset.rootPath,
+ canUpdate: $boardApp.dataset.canUpdate,
+ labelsFetchPath: $boardApp.dataset.labelsFetchPath,
+ labelsManagePath: $boardApp.dataset.labelsManagePath,
+ labelsFilterBasePath: $boardApp.dataset.labelsFilterBasePath,
},
store,
apolloProvider,
@@ -131,6 +135,7 @@ export default () => {
eventHub.$on('clearDetailIssue', this.clearDetailIssue);
sidebarEventHub.$on('toggleSubscription', this.toggleSubscription);
eventHub.$on('performSearch', this.performSearch);
+ eventHub.$on('initialBoardLoad', this.initialBoardLoad);
},
beforeDestroy() {
eventHub.$off('updateTokens', this.updateTokens);
@@ -138,6 +143,7 @@ export default () => {
eventHub.$off('clearDetailIssue', this.clearDetailIssue);
sidebarEventHub.$off('toggleSubscription', this.toggleSubscription);
eventHub.$off('performSearch', this.performSearch);
+ eventHub.$off('initialBoardLoad', this.initialBoardLoad);
},
mounted() {
this.filterManager = new FilteredSearchBoards(boardsStore.filter, true, boardsStore.cantEdit);
@@ -148,6 +154,19 @@ export default () => {
boardsStore.disabled = this.disabled;
if (!gon.features.graphqlBoardLists) {
+ this.initialBoardLoad();
+ }
+ },
+ methods: {
+ ...mapActions([
+ 'setInitialBoardData',
+ 'setFilters',
+ 'fetchEpicsSwimlanes',
+ 'resetIssues',
+ 'resetEpics',
+ 'fetchLists',
+ ]),
+ initialBoardLoad() {
boardsStore
.all()
.then(res => res.data)
@@ -160,30 +179,26 @@ export default () => {
.catch(() => {
Flash(__('An error occurred while fetching the board lists. Please try again.'));
});
- }
- },
- methods: {
- ...mapActions([
- 'setInitialBoardData',
- 'setFilters',
- 'fetchEpicsSwimlanes',
- 'fetchIssuesForAllLists',
- ]),
+ },
updateTokens() {
this.filterManager.updateTokens();
},
performSearch() {
this.setFilters(convertObjectPropsToCamelCase(urlParamsToObject(window.location.search)));
if (gon.features.boardsWithSwimlanes && this.isShowingEpicsSwimlanes) {
- this.fetchEpicsSwimlanes(false);
- this.fetchIssuesForAllLists();
+ this.resetEpics();
+ this.resetIssues();
+ this.fetchEpicsSwimlanes({});
+ } else if (gon.features.graphqlBoardLists && !this.isShowingEpicsSwimlanes) {
+ this.fetchLists();
+ this.resetIssues();
}
},
updateDetailIssue(newIssue, multiSelect = false) {
const { sidebarInfoEndpoint } = newIssue;
if (sidebarInfoEndpoint && newIssue.subscribed === undefined) {
newIssue.setFetchingState('subscriptions', true);
- setWeigthFetchingState(newIssue, true);
+ setWeightFetchingState(newIssue, true);
setEpicFetchingState(newIssue, true);
boardsStore
.getIssueInfo(sidebarInfoEndpoint)
@@ -201,7 +216,7 @@ export default () => {
} = convertObjectPropsToCamelCase(data);
newIssue.setFetchingState('subscriptions', false);
- setWeigthFetchingState(newIssue, false);
+ setWeightFetchingState(newIssue, false);
setEpicFetchingState(newIssue, false);
newIssue.updateData({
humanTimeSpent: humanTotalTimeSpent,
@@ -216,7 +231,7 @@ export default () => {
})
.catch(() => {
newIssue.setFetchingState('subscriptions', false);
- setWeigthFetchingState(newIssue, false);
+ setWeightFetchingState(newIssue, false);
Flash(__('An error occurred while fetching sidebar data'));
});
}
@@ -300,63 +315,32 @@ export default () => {
}
return !this.store.lists.filter(list => !list.preset).length;
},
- tooltipTitle() {
- if (this.disabled) {
- return __('Please add a list to your board first');
- }
-
- return '';
- },
- },
- watch: {
- disabled() {
- this.updateTooltip();
- },
- },
- mounted() {
- this.updateTooltip();
},
methods: {
- updateTooltip() {
- const $tooltip = $(this.$refs.addIssuesButton);
-
- this.$nextTick(() => {
- if (this.disabled) {
- $tooltip.tooltip();
- } else {
- $tooltip.tooltip('dispose');
- }
- });
- },
openModal() {
if (!this.disabled) {
this.toggleModal(true);
}
},
},
- template: `
- <div class="board-extra-actions">
- <button
- class="btn btn-success gl-ml-3"
- type="button"
- data-placement="bottom"
- data-track-event="click_button"
- data-track-label="board_add_issues"
- ref="addIssuesButton"
- :class="{ 'disabled': disabled }"
- :title="tooltipTitle"
- :aria-disabled="disabled"
- v-if="canAdminList"
- @click="openModal">
- Add issues
- </button>
- </div>
- `,
+ render(createElement) {
+ return createElement(BoardExtraActions, {
+ props: {
+ canAdminList: this.$options.el.hasAttribute('data-can-admin-list'),
+ openModal: this.openModal,
+ disabled: this.disabled,
+ },
+ });
+ },
});
}
toggleFocusMode(ModalStore, boardsStore);
toggleLabels();
- toggleEpicsSwimlanes();
+
+ if (gon.features?.swimlanes) {
+ toggleEpicsSwimlanes();
+ }
+
mountMultipleBoardsSwitcher();
};
diff --git a/app/assets/javascripts/boards/mixins/is_wip_limits.js b/app/assets/javascripts/boards/mixins/is_wip_limits.js
deleted file mode 100644
index f172179d3c7..00000000000
--- a/app/assets/javascripts/boards/mixins/is_wip_limits.js
+++ /dev/null
@@ -1,7 +0,0 @@
-export default {
- computed: {
- isWipLimitsOn() {
- return false;
- },
- },
-};
diff --git a/app/assets/javascripts/boards/models/list.js b/app/assets/javascripts/boards/models/list.js
index 2f6caffbf84..09f5d5b4dd8 100644
--- a/app/assets/javascripts/boards/models/list.js
+++ b/app/assets/javascripts/boards/models/list.js
@@ -1,4 +1,4 @@
-/* eslint-disable no-underscore-dangle, class-methods-use-this */
+/* eslint-disable class-methods-use-this */
import { __ } from '~/locale';
import ListLabel from './label';
import ListAssignee from './assignee';
@@ -34,7 +34,6 @@ const TYPES = {
class List {
constructor(obj) {
this.id = obj.id;
- this._uid = this.guid();
this.position = obj.position;
this.title = (obj.list_type || obj.listType) === 'backlog' ? __('Open') : obj.title;
this.type = obj.list_type || obj.listType;
diff --git a/app/assets/javascripts/boards/queries/board.mutation.graphql b/app/assets/javascripts/boards/queries/board.mutation.graphql
new file mode 100644
index 00000000000..ef2b81a7939
--- /dev/null
+++ b/app/assets/javascripts/boards/queries/board.mutation.graphql
@@ -0,0 +1,11 @@
+mutation UpdateBoard($id: ID!, $hideClosedList: Boolean, $hideBacklogList: Boolean) {
+ updateBoard(
+ input: { id: $id, hideClosedList: $hideClosedList, hideBacklogList: $hideBacklogList }
+ ) {
+ board {
+ id
+ hideClosedList
+ hideBacklogList
+ }
+ }
+}
diff --git a/app/assets/javascripts/boards/queries/board_list_create.mutation.graphql b/app/assets/javascripts/boards/queries/board_list_create.mutation.graphql
index dcfe69222a0..48420b349ae 100644
--- a/app/assets/javascripts/boards/queries/board_list_create.mutation.graphql
+++ b/app/assets/javascripts/boards/queries/board_list_create.mutation.graphql
@@ -1,7 +1,21 @@
-#import "./board_list.fragment.graphql"
+#import "ee_else_ce/boards/queries/board_list.fragment.graphql"
-mutation CreateBoardList($boardId: BoardID!, $backlog: Boolean) {
- boardListCreate(input: { boardId: $boardId, backlog: $backlog }) {
+mutation CreateBoardList(
+ $boardId: BoardID!
+ $backlog: Boolean
+ $labelId: LabelID
+ $milestoneId: MilestoneID
+ $assigneeId: UserID
+) {
+ boardListCreate(
+ input: {
+ boardId: $boardId
+ backlog: $backlog
+ labelId: $labelId
+ milestoneId: $milestoneId
+ assigneeId: $assigneeId
+ }
+ ) {
list {
...BoardListFragment
}
diff --git a/app/assets/javascripts/boards/queries/board_lists.query.graphql b/app/assets/javascripts/boards/queries/board_lists.query.graphql
new file mode 100644
index 00000000000..88425e9a9c1
--- /dev/null
+++ b/app/assets/javascripts/boards/queries/board_lists.query.graphql
@@ -0,0 +1,28 @@
+#import "ee_else_ce/boards/queries/board_list.fragment.graphql"
+
+query ListIssues(
+ $fullPath: ID!
+ $boardId: ID!
+ $filters: BoardIssueInput
+ $isGroup: Boolean = false
+ $isProject: Boolean = false
+) {
+ group(fullPath: $fullPath) @include(if: $isGroup) {
+ board(id: $boardId) {
+ lists(issueFilters: $filters) {
+ nodes {
+ ...BoardListFragment
+ }
+ }
+ }
+ }
+ project(fullPath: $fullPath) @include(if: $isProject) {
+ board(id: $boardId) {
+ lists(issueFilters: $filters) {
+ nodes {
+ ...BoardListFragment
+ }
+ }
+ }
+ }
+}
diff --git a/app/assets/javascripts/boards/queries/group_board.query.graphql b/app/assets/javascripts/boards/queries/group_board.query.graphql
deleted file mode 100644
index cb42cb3f73d..00000000000
--- a/app/assets/javascripts/boards/queries/group_board.query.graphql
+++ /dev/null
@@ -1,13 +0,0 @@
-#import "ee_else_ce/boards/queries/board_list.fragment.graphql"
-
-query GroupBoard($fullPath: ID!, $boardId: ID!) {
- group(fullPath: $fullPath) {
- board(id: $boardId) {
- lists {
- nodes {
- ...BoardListFragment
- }
- }
- }
- }
-}
diff --git a/app/assets/javascripts/boards/queries/issue_set_labels.mutation.graphql b/app/assets/javascripts/boards/queries/issue_set_labels.mutation.graphql
new file mode 100644
index 00000000000..3c5f4b3e3bd
--- /dev/null
+++ b/app/assets/javascripts/boards/queries/issue_set_labels.mutation.graphql
@@ -0,0 +1,15 @@
+mutation issueSetLabels($input: UpdateIssueInput!) {
+ updateIssue(input: $input) {
+ issue {
+ labels {
+ nodes {
+ id
+ title
+ color
+ description
+ }
+ }
+ }
+ errors
+ }
+}
diff --git a/app/assets/javascripts/boards/queries/lists_issues.query.graphql b/app/assets/javascripts/boards/queries/lists_issues.query.graphql
index c66cdf68cf4..5dbfe4675c6 100644
--- a/app/assets/javascripts/boards/queries/lists_issues.query.graphql
+++ b/app/assets/javascripts/boards/queries/lists_issues.query.graphql
@@ -7,15 +7,24 @@ query ListIssues(
$filters: BoardIssueInput
$isGroup: Boolean = false
$isProject: Boolean = false
+ $after: String
+ $first: Int
) {
group(fullPath: $fullPath) @include(if: $isGroup) {
board(id: $boardId) {
lists(id: $id) {
nodes {
id
- issues(filters: $filters) {
- nodes {
- ...IssueNode
+ issues(first: $first, filters: $filters, after: $after) {
+ count
+ edges {
+ node {
+ ...IssueNode
+ }
+ }
+ pageInfo {
+ endCursor
+ hasNextPage
}
}
}
@@ -27,9 +36,16 @@ query ListIssues(
lists(id: $id) {
nodes {
id
- issues(filters: $filters) {
- nodes {
- ...IssueNode
+ issues(first: $first, filters: $filters, after: $after) {
+ count
+ edges {
+ node {
+ ...IssueNode
+ }
+ }
+ pageInfo {
+ endCursor
+ hasNextPage
}
}
}
diff --git a/app/assets/javascripts/boards/queries/project_board.query.graphql b/app/assets/javascripts/boards/queries/project_board.query.graphql
deleted file mode 100644
index 4620a7e0fd5..00000000000
--- a/app/assets/javascripts/boards/queries/project_board.query.graphql
+++ /dev/null
@@ -1,13 +0,0 @@
-#import "ee_else_ce/boards/queries/board_list.fragment.graphql"
-
-query ProjectBoard($fullPath: ID!, $boardId: ID!) {
- project(fullPath: $fullPath) {
- board(id: $boardId) {
- lists {
- nodes {
- ...BoardListFragment
- }
- }
- }
- }
-}
diff --git a/app/assets/javascripts/boards/stores/actions.js b/app/assets/javascripts/boards/stores/actions.js
index 4b81d9c73ef..1fed1228106 100644
--- a/app/assets/javascripts/boards/stores/actions.js
+++ b/app/assets/javascripts/boards/stores/actions.js
@@ -1,28 +1,38 @@
import Cookies from 'js-cookie';
-import { sortBy, pick } from 'lodash';
-import createFlash from '~/flash';
+import { pick } from 'lodash';
+
+import boardListsQuery from 'ee_else_ce/boards/queries/board_lists.query.graphql';
import { __ } from '~/locale';
import { parseBoolean } from '~/lib/utils/common_utils';
-import createDefaultClient from '~/lib/graphql';
+import createGqClient, { fetchPolicies } from '~/lib/graphql';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import { BoardType, ListType, inactiveId } from '~/boards/constants';
import * as types from './mutation_types';
-import { formatListIssues, fullBoardId } from '../boards_util';
+import {
+ formatBoardLists,
+ formatListIssues,
+ fullBoardId,
+ formatListsPageInfo,
+} from '../boards_util';
import boardStore from '~/boards/stores/boards_store';
import listsIssuesQuery from '../queries/lists_issues.query.graphql';
-import projectBoardQuery from '../queries/project_board.query.graphql';
-import groupBoardQuery from '../queries/group_board.query.graphql';
import createBoardListMutation from '../queries/board_list_create.mutation.graphql';
import updateBoardListMutation from '../queries/board_list_update.mutation.graphql';
import issueMoveListMutation from '../queries/issue_move_list.mutation.graphql';
+import issueSetLabels from '../queries/issue_set_labels.mutation.graphql';
const notImplemented = () => {
/* eslint-disable-next-line @gitlab/require-i18n-strings */
throw new Error('Not implemented!');
};
-export const gqlClient = createDefaultClient();
+export const gqlClient = createGqClient(
+ {},
+ {
+ fetchPolicy: fetchPolicies.NO_CACHE,
+ },
+);
export default {
setInitialBoardData: ({ commit }, data) => {
@@ -50,62 +60,46 @@ export default {
},
fetchLists: ({ commit, state, dispatch }) => {
- const { endpoints, boardType } = state;
+ const { endpoints, boardType, filterParams } = state;
const { fullPath, boardId } = endpoints;
- let query;
- if (boardType === BoardType.group) {
- query = groupBoardQuery;
- } else if (boardType === BoardType.project) {
- query = projectBoardQuery;
- } else {
- createFlash(__('Invalid board'));
- return Promise.reject();
- }
-
const variables = {
fullPath,
boardId: fullBoardId(boardId),
+ filters: filterParams,
+ isGroup: boardType === BoardType.group,
+ isProject: boardType === BoardType.project,
};
return gqlClient
.query({
- query,
+ query: boardListsQuery,
variables,
})
.then(({ data }) => {
- let { lists } = data[boardType]?.board;
- // Temporarily using positioning logic from boardStore
- lists = lists.nodes.map(list =>
- boardStore.updateListPosition({
- ...list,
- doNotFetchIssues: true,
- }),
- );
- commit(types.RECEIVE_BOARD_LISTS_SUCCESS, sortBy(lists, 'position'));
- // Backlog list needs to be created if it doesn't exist
- if (!lists.find(l => l.type === ListType.backlog)) {
+ const { lists, hideBacklogList } = data[boardType]?.board;
+ commit(types.RECEIVE_BOARD_LISTS_SUCCESS, formatBoardLists(lists));
+ // Backlog list needs to be created if it doesn't exist and it's not hidden
+ if (!lists.nodes.find(l => l.listType === ListType.backlog) && !hideBacklogList) {
dispatch('createList', { backlog: true });
}
dispatch('showWelcomeList');
})
- .catch(() => {
- createFlash(
- __('An error occurred while fetching the board lists. Please reload the page.'),
- );
- });
+ .catch(() => commit(types.RECEIVE_BOARD_LISTS_FAILURE));
},
- // This action only supports backlog list creation at this stage
- // Future iterations will add the ability to create other list types
- createList: ({ state, commit, dispatch }, { backlog = false }) => {
+ createList: ({ state, commit, dispatch }, { backlog, labelId, milestoneId, assigneeId }) => {
const { boardId } = state.endpoints;
+
gqlClient
.mutate({
mutation: createBoardListMutation,
variables: {
boardId: fullBoardId(boardId),
backlog,
+ labelId,
+ milestoneId,
+ assigneeId,
},
})
.then(({ data }) => {
@@ -116,16 +110,15 @@ export default {
dispatch('addList', list);
}
})
- .catch(() => {
- commit(types.CREATE_LIST_FAILURE);
- });
+ .catch(() => commit(types.CREATE_LIST_FAILURE));
},
- addList: ({ state, commit }, list) => {
- const lists = state.boardLists;
+ addList: ({ commit }, list) => {
// Temporarily using positioning logic from boardStore
- lists.push(boardStore.updateListPosition({ ...list, doNotFetchIssues: true }));
- commit(types.RECEIVE_BOARD_LISTS_SUCCESS, sortBy(lists, 'position'));
+ commit(
+ types.RECEIVE_ADD_LIST_SUCCESS,
+ boardStore.updateListPosition({ ...list, doNotFetchIssues: true }),
+ );
},
showWelcomeList: ({ state, dispatch }) => {
@@ -133,7 +126,9 @@ export default {
return;
}
if (
- state.boardLists.find(list => list.type !== ListType.backlog && list.type !== ListType.closed)
+ Object.entries(state.boardLists).find(
+ ([, list]) => list.type !== ListType.backlog && list.type !== ListType.closed,
+ )
) {
return;
}
@@ -155,13 +150,16 @@ export default {
notImplemented();
},
- moveList: ({ state, commit, dispatch }, { listId, newIndex, adjustmentValue }) => {
+ moveList: (
+ { state, commit, dispatch },
+ { listId, replacedListId, newIndex, adjustmentValue },
+ ) => {
const { boardLists } = state;
- const backupList = [...boardLists];
- const movedList = boardLists.find(({ id }) => id === listId);
+ const backupList = { ...boardLists };
+ const movedList = boardLists[listId];
const newPosition = newIndex - 1;
- const listAtNewIndex = boardLists[newIndex];
+ const listAtNewIndex = boardLists[replacedListId];
movedList.position = newPosition;
listAtNewIndex.position += adjustmentValue;
@@ -197,7 +195,9 @@ export default {
notImplemented();
},
- fetchIssuesForList: ({ state, commit }, listId) => {
+ fetchIssuesForList: ({ state, commit }, { listId, fetchNext = false }) => {
+ commit(types.REQUEST_ISSUES_FOR_LIST, { listId, fetchNext });
+
const { endpoints, boardType, filterParams } = state;
const { fullPath, boardId } = endpoints;
@@ -208,6 +208,8 @@ export default {
filters: filterParams,
isGroup: boardType === BoardType.group,
isProject: boardType === BoardType.project,
+ first: 20,
+ after: fetchNext ? state.pageInfoByListId[listId].endCursor : undefined,
};
return gqlClient
@@ -221,36 +223,14 @@ export default {
.then(({ data }) => {
const { lists } = data[boardType]?.board;
const listIssues = formatListIssues(lists);
- commit(types.RECEIVE_ISSUES_FOR_LIST_SUCCESS, { listIssues, listId });
+ const listPageInfo = formatListsPageInfo(lists);
+ commit(types.RECEIVE_ISSUES_FOR_LIST_SUCCESS, { listIssues, listPageInfo, listId });
})
.catch(() => commit(types.RECEIVE_ISSUES_FOR_LIST_FAILURE, listId));
},
- fetchIssuesForAllLists: ({ state, commit }) => {
- commit(types.REQUEST_ISSUES_FOR_ALL_LISTS);
-
- const { endpoints, boardType, filterParams } = state;
- const { fullPath, boardId } = endpoints;
-
- const variables = {
- fullPath,
- boardId: fullBoardId(boardId),
- filters: filterParams,
- isGroup: boardType === BoardType.group,
- isProject: boardType === BoardType.project,
- };
-
- return gqlClient
- .query({
- query: listsIssuesQuery,
- variables,
- })
- .then(({ data }) => {
- const { lists } = data[boardType]?.board;
- const listIssues = formatListIssues(lists);
- commit(types.RECEIVE_ISSUES_FOR_ALL_LISTS_SUCCESS, listIssues);
- })
- .catch(() => commit(types.RECEIVE_ISSUES_FOR_ALL_LISTS_FAILURE));
+ resetIssues: ({ commit }) => {
+ commit(types.RESET_ISSUES);
},
moveIssue: (
@@ -303,6 +283,31 @@ export default {
commit(types.ADD_ISSUE_TO_LIST_FAILURE, { list, issue });
},
+ setActiveIssueLabels: async ({ commit, getters }, input) => {
+ const activeIssue = getters.getActiveIssue;
+ const { data } = await gqlClient.mutate({
+ mutation: issueSetLabels,
+ variables: {
+ input: {
+ iid: String(activeIssue.iid),
+ addLabelIds: input.addLabelIds ?? [],
+ removeLabelIds: input.removeLabelIds ?? [],
+ projectPath: input.projectPath,
+ },
+ },
+ });
+
+ if (data.updateIssue?.errors?.length > 0) {
+ throw new Error(data.updateIssue.errors);
+ }
+
+ commit(types.UPDATE_ISSUE_BY_ID, {
+ issueId: activeIssue.id,
+ prop: 'labels',
+ value: data.updateIssue.issue.labels.nodes,
+ });
+ },
+
fetchBacklog: () => {
notImplemented();
},
diff --git a/app/assets/javascripts/boards/stores/boards_store.js b/app/assets/javascripts/boards/stores/boards_store.js
index faf4f9ebfd3..d1a5db1bcc5 100644
--- a/app/assets/javascripts/boards/stores/boards_store.js
+++ b/app/assets/javascripts/boards/stores/boards_store.js
@@ -2,7 +2,7 @@
/* global List */
/* global ListIssue */
import $ from 'jquery';
-import { sortBy } from 'lodash';
+import { sortBy, pick } from 'lodash';
import Vue from 'vue';
import Cookies from 'js-cookie';
import BoardsStoreEE from 'ee_else_ce/boards/stores/boards_store_ee';
@@ -12,7 +12,7 @@ import {
parseBoolean,
convertObjectPropsToCamelCase,
} from '~/lib/utils/common_utils';
-import { __ } from '~/locale';
+import createDefaultClient from '~/lib/graphql';
import axios from '~/lib/utils/axios_utils';
import { mergeUrlParams } from '~/lib/utils/url_utility';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
@@ -23,7 +23,11 @@ import ListLabel from '../models/label';
import ListAssignee from '../models/assignee';
import ListMilestone from '../models/milestone';
+import createBoardMutation from '../queries/board.mutation.graphql';
+
const PER_PAGE = 20;
+export const gqlClient = createDefaultClient();
+
const boardsStore = {
disabled: false,
timeTracking: {
@@ -114,7 +118,6 @@ const boardsStore = {
.catch(() => {
// https://gitlab.com/gitlab-org/gitlab-foss/issues/30821
});
- this.removeBlankState();
},
updateNewListDropdown(listId) {
$(`.js-board-list-${listId}`).removeClass('is-active');
@@ -124,22 +127,14 @@ const boardsStore = {
return !this.state.lists.filter(list => list.type !== 'backlog' && list.type !== 'closed')[0];
},
addBlankState() {
- if (!this.shouldAddBlankState() || this.welcomeIsHidden() || this.disabled) return;
-
- this.addList({
- id: 'blank',
- list_type: 'blank',
- title: __('Welcome to your Issue Board!'),
- position: 0,
- });
- },
- removeBlankState() {
- this.removeList('blank');
+ if (!this.shouldAddBlankState() || this.welcomeIsHidden()) return;
- Cookies.set('issue_board_welcome_hidden', 'true', {
- expires: 365 * 10,
- path: '',
- });
+ this.generateDefaultLists()
+ .then(res => res.data)
+ .then(data => Promise.all(data.map(list => this.addList(list))))
+ .catch(() => {
+ this.removeList(undefined, 'label');
+ });
},
findIssueLabel(issue, findLabel) {
@@ -542,6 +537,10 @@ const boardsStore = {
this.timeTracking.limitToHours = parseBoolean(limitToHours);
},
+ generateBoardGid(boardId) {
+ return `gid://gitlab/Board/${boardId}`;
+ },
+
generateBoardsPath(id) {
return `${this.state.endpoints.boardsEndpoint}${id ? `/${id}` : ''}.json`;
},
@@ -800,9 +799,33 @@ const boardsStore = {
}
if (boardPayload.id) {
- return axios.put(this.generateBoardsPath(boardPayload.id), { board: boardPayload });
+ const input = {
+ ...pick(boardPayload, ['hideClosedList', 'hideBacklogList']),
+ id: this.generateBoardGid(boardPayload.id),
+ };
+
+ return Promise.all([
+ axios.put(this.generateBoardsPath(boardPayload.id), { board: boardPayload }),
+ gqlClient.mutate({
+ mutation: createBoardMutation,
+ variables: input,
+ }),
+ ]);
}
- return axios.post(this.generateBoardsPath(), { board: boardPayload });
+
+ return axios
+ .post(this.generateBoardsPath(), { board: boardPayload })
+ .then(resp => resp.data)
+ .then(data => {
+ gqlClient.mutate({
+ mutation: createBoardMutation,
+ variables: {
+ ...pick(boardPayload, ['hideClosedList', 'hideBacklogList']),
+ id: this.generateBoardGid(data.id),
+ },
+ });
+ return data;
+ });
},
deleteBoard({ id }) {
diff --git a/app/assets/javascripts/boards/stores/getters.js b/app/assets/javascripts/boards/stores/getters.js
index 3688476dc5f..89a3b14b262 100644
--- a/app/assets/javascripts/boards/stores/getters.js
+++ b/app/assets/javascripts/boards/stores/getters.js
@@ -1,10 +1,11 @@
+import { find } from 'lodash';
import { inactiveId } from '../constants';
export default {
getLabelToggleState: state => (state.isShowingLabels ? 'on' : 'off'),
isSidebarOpen: state => state.activeId !== inactiveId,
isSwimlanesOn: state => {
- if (!gon?.features?.boardsWithSwimlanes) {
+ if (!gon?.features?.boardsWithSwimlanes && !gon?.features?.swimlanes) {
return false;
}
@@ -22,4 +23,16 @@ export default {
getActiveIssue: state => {
return state.issues[state.activeId] || {};
},
+
+ getListByLabelId: state => labelId => {
+ return find(state.boardLists, l => l.label?.id === labelId);
+ },
+
+ getListByTitle: state => title => {
+ return find(state.boardLists, l => l.title === title);
+ },
+
+ shouldUseGraphQL: () => {
+ return gon?.features?.graphqlBoardLists;
+ },
};
diff --git a/app/assets/javascripts/boards/stores/mutation_types.js b/app/assets/javascripts/boards/stores/mutation_types.js
index f0a283f6161..09ab08062df 100644
--- a/app/assets/javascripts/boards/stores/mutation_types.js
+++ b/app/assets/javascripts/boards/stores/mutation_types.js
@@ -3,6 +3,7 @@ export const SET_FILTERS = 'SET_FILTERS';
export const CREATE_LIST_SUCCESS = 'CREATE_LIST_SUCCESS';
export const CREATE_LIST_FAILURE = 'CREATE_LIST_FAILURE';
export const RECEIVE_BOARD_LISTS_SUCCESS = 'RECEIVE_BOARD_LISTS_SUCCESS';
+export const RECEIVE_BOARD_LISTS_FAILURE = 'RECEIVE_BOARD_LISTS_FAILURE';
export const SHOW_PROMOTION_LIST = 'SHOW_PROMOTION_LIST';
export const REQUEST_ADD_LIST = 'REQUEST_ADD_LIST';
export const RECEIVE_ADD_LIST_SUCCESS = 'RECEIVE_ADD_LIST_SUCCESS';
@@ -12,11 +13,9 @@ export const UPDATE_LIST_FAILURE = 'UPDATE_LIST_FAILURE';
export const REQUEST_REMOVE_LIST = 'REQUEST_REMOVE_LIST';
export const RECEIVE_REMOVE_LIST_SUCCESS = 'RECEIVE_REMOVE_LIST_SUCCESS';
export const RECEIVE_REMOVE_LIST_ERROR = 'RECEIVE_REMOVE_LIST_ERROR';
-export const REQUEST_ISSUES_FOR_ALL_LISTS = 'REQUEST_ISSUES_FOR_ALL_LISTS';
+export const REQUEST_ISSUES_FOR_LIST = 'REQUEST_ISSUES_FOR_LIST';
export const RECEIVE_ISSUES_FOR_LIST_FAILURE = 'RECEIVE_ISSUES_FOR_LIST_FAILURE';
export const RECEIVE_ISSUES_FOR_LIST_SUCCESS = 'RECEIVE_ISSUES_FOR_LIST_SUCCESS';
-export const RECEIVE_ISSUES_FOR_ALL_LISTS_SUCCESS = 'RECEIVE_ISSUES_FOR_ALL_LISTS_SUCCESS';
-export const RECEIVE_ISSUES_FOR_ALL_LISTS_FAILURE = 'RECEIVE_ISSUES_FOR_ALL_LISTS_FAILURE';
export const REQUEST_ADD_ISSUE = 'REQUEST_ADD_ISSUE';
export const RECEIVE_ADD_ISSUE_SUCCESS = 'RECEIVE_ADD_ISSUE_SUCCESS';
export const RECEIVE_ADD_ISSUE_ERROR = 'RECEIVE_ADD_ISSUE_ERROR';
@@ -32,3 +31,4 @@ export const SET_CURRENT_PAGE = 'SET_CURRENT_PAGE';
export const TOGGLE_EMPTY_STATE = 'TOGGLE_EMPTY_STATE';
export const SET_ACTIVE_ID = 'SET_ACTIVE_ID';
export const UPDATE_ISSUE_BY_ID = 'UPDATE_ISSUE_BY_ID';
+export const RESET_ISSUES = 'RESET_ISSUES';
diff --git a/app/assets/javascripts/boards/stores/mutations.js b/app/assets/javascripts/boards/stores/mutations.js
index faeb3e25a71..0c7dbc0d2ef 100644
--- a/app/assets/javascripts/boards/stores/mutations.js
+++ b/app/assets/javascripts/boards/stores/mutations.js
@@ -1,8 +1,8 @@
import Vue from 'vue';
-import { sortBy, pull } from 'lodash';
+import { pull, union } from 'lodash';
import { formatIssue, moveIssueListHelper } from '../boards_util';
import * as mutationTypes from './mutation_types';
-import { __ } from '~/locale';
+import { s__ } from '~/locale';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
const notImplemented = () => {
@@ -10,11 +10,13 @@ const notImplemented = () => {
throw new Error('Not implemented!');
};
-const removeIssueFromList = (state, listId, issueId) => {
+export const removeIssueFromList = ({ state, listId, issueId }) => {
Vue.set(state.issuesByListId, listId, pull(state.issuesByListId[listId], issueId));
+ const list = state.boardLists[listId];
+ Vue.set(state.boardLists, listId, { ...list, issuesSize: list.issuesSize - 1 });
};
-const addIssueToList = ({ state, listId, issueId, moveBeforeId, moveAfterId, atIndex }) => {
+export const addIssueToList = ({ state, listId, issueId, moveBeforeId, moveAfterId, atIndex }) => {
const listIssues = state.issuesByListId[listId];
let newIndex = atIndex || 0;
if (moveBeforeId) {
@@ -24,6 +26,8 @@ const addIssueToList = ({ state, listId, issueId, moveBeforeId, moveAfterId, atI
}
listIssues.splice(newIndex, 0, issueId);
Vue.set(state.issuesByListId, listId, listIssues);
+ const list = state.boardLists[listId];
+ Vue.set(state.boardLists, listId, { ...list, issuesSize: list.issuesSize + 1 });
};
export default {
@@ -39,6 +43,12 @@ export default {
state.boardLists = lists;
},
+ [mutationTypes.RECEIVE_BOARD_LISTS_FAILURE]: state => {
+ state.error = s__(
+ 'Boards|An error occurred while fetching the board lists. Please reload the page.',
+ );
+ },
+
[mutationTypes.SET_ACTIVE_ID](state, { id, sidebarType }) {
state.activeId = id;
state.sidebarType = sidebarType;
@@ -49,15 +59,15 @@ export default {
},
[mutationTypes.CREATE_LIST_FAILURE]: state => {
- state.error = __('An error occurred while creating the list. Please try again.');
+ state.error = s__('Boards|An error occurred while creating the list. Please try again.');
},
[mutationTypes.REQUEST_ADD_LIST]: () => {
notImplemented();
},
- [mutationTypes.RECEIVE_ADD_LIST_SUCCESS]: () => {
- notImplemented();
+ [mutationTypes.RECEIVE_ADD_LIST_SUCCESS]: (state, list) => {
+ Vue.set(state.boardLists, list.id, list);
},
[mutationTypes.RECEIVE_ADD_LIST_ERROR]: () => {
@@ -66,14 +76,12 @@ export default {
[mutationTypes.MOVE_LIST]: (state, { movedList, listAtNewIndex }) => {
const { boardLists } = state;
- const movedListIndex = state.boardLists.findIndex(l => l.id === movedList.id);
- Vue.set(boardLists, movedListIndex, movedList);
- Vue.set(boardLists, movedListIndex.position + 1, listAtNewIndex);
- Vue.set(state, 'boardLists', sortBy(boardLists, 'position'));
+ Vue.set(boardLists, movedList.id, movedList);
+ Vue.set(boardLists, listAtNewIndex.id, listAtNewIndex);
},
[mutationTypes.UPDATE_LIST_FAILURE]: (state, backupList) => {
- state.error = __('An error occurred while updating the list. Please try again.');
+ state.error = s__('Boards|An error occurred while updating the list. Please try again.');
Vue.set(state, 'boardLists', backupList);
},
@@ -89,28 +97,36 @@ export default {
notImplemented();
},
- [mutationTypes.RECEIVE_ISSUES_FOR_LIST_SUCCESS]: (state, { listIssues, listId }) => {
+ [mutationTypes.REQUEST_ISSUES_FOR_LIST]: (state, { listId, fetchNext }) => {
+ Vue.set(state.listsFlags, listId, { [fetchNext ? 'isLoadingMore' : 'isLoading']: true });
+ },
+
+ [mutationTypes.RECEIVE_ISSUES_FOR_LIST_SUCCESS]: (
+ state,
+ { listIssues, listPageInfo, listId },
+ ) => {
const { listData, issues } = listIssues;
Vue.set(state, 'issues', { ...state.issues, ...issues });
- Vue.set(state.issuesByListId, listId, listData[listId]);
- const listIndex = state.boardLists.findIndex(l => l.id === listId);
- Vue.set(state.boardLists[listIndex], 'loading', false);
+ Vue.set(
+ state.issuesByListId,
+ listId,
+ union(state.issuesByListId[listId] || [], listData[listId]),
+ );
+ Vue.set(state.pageInfoByListId, listId, listPageInfo[listId]);
+ Vue.set(state.listsFlags, listId, { isLoading: false, isLoadingMore: false });
},
[mutationTypes.RECEIVE_ISSUES_FOR_LIST_FAILURE]: (state, listId) => {
- state.error = __('An error occurred while fetching the board issues. Please reload the page.');
- const listIndex = state.boardLists.findIndex(l => l.id === listId);
- Vue.set(state.boardLists[listIndex], 'loading', false);
- },
-
- [mutationTypes.REQUEST_ISSUES_FOR_ALL_LISTS]: state => {
- state.isLoadingIssues = true;
+ state.error = s__(
+ 'Boards|An error occurred while fetching the board issues. Please reload the page.',
+ );
+ Vue.set(state.listsFlags, listId, { isLoading: false, isLoadingMore: false });
},
- [mutationTypes.RECEIVE_ISSUES_FOR_ALL_LISTS_SUCCESS]: (state, { listData, issues }) => {
- state.issuesByListId = listData;
- state.issues = issues;
- state.isLoadingIssues = false;
+ [mutationTypes.RESET_ISSUES]: state => {
+ Object.keys(state.issuesByListId).forEach(listId => {
+ Vue.set(state.issuesByListId, listId, []);
+ });
},
[mutationTypes.UPDATE_ISSUE_BY_ID]: (state, { issueId, prop, value }) => {
@@ -122,11 +138,6 @@ export default {
Vue.set(state.issues[issueId], prop, value);
},
- [mutationTypes.RECEIVE_ISSUES_FOR_ALL_LISTS_FAILURE]: state => {
- state.error = __('An error occurred while fetching the board issues. Please reload the page.');
- state.isLoadingIssues = false;
- },
-
[mutationTypes.REQUEST_ADD_ISSUE]: () => {
notImplemented();
},
@@ -143,13 +154,13 @@ export default {
state,
{ originalIssue, fromListId, toListId, moveBeforeId, moveAfterId },
) => {
- const fromList = state.boardLists.find(l => l.id === fromListId);
- const toList = state.boardLists.find(l => l.id === toListId);
+ const fromList = state.boardLists[fromListId];
+ const toList = state.boardLists[toListId];
const issue = moveIssueListHelper(originalIssue, fromList, toList);
Vue.set(state.issues, issue.id, issue);
- removeIssueFromList(state, fromListId, issue.id);
+ removeIssueFromList({ state, listId: fromListId, issueId: issue.id });
addIssueToList({ state, listId: toListId, issueId: issue.id, moveBeforeId, moveAfterId });
},
@@ -162,9 +173,9 @@ export default {
state,
{ originalIssue, fromListId, toListId, originalIndex },
) => {
- state.error = __('An error occurred while moving the issue. Please try again.');
+ state.error = s__('Boards|An error occurred while moving the issue. Please try again.');
Vue.set(state.issues, originalIssue.id, originalIssue);
- removeIssueFromList(state, toListId, originalIssue.id);
+ removeIssueFromList({ state, listId: toListId, issueId: originalIssue.id });
addIssueToList({
state,
listId: fromListId,
@@ -193,8 +204,8 @@ export default {
},
[mutationTypes.ADD_ISSUE_TO_LIST_FAILURE]: (state, { list, issue }) => {
- state.error = __('An error occurred while creating the issue. Please try again.');
- removeIssueFromList(state, list.id, issue.id);
+ state.error = s__('Boards|An error occurred while creating the issue. Please try again.');
+ removeIssueFromList({ state, listId: list.id, issueId: issue.id });
},
[mutationTypes.SET_CURRENT_PAGE]: () => {
diff --git a/app/assets/javascripts/boards/stores/state.js b/app/assets/javascripts/boards/stores/state.js
index be937d68c6c..b91c09f8051 100644
--- a/app/assets/javascripts/boards/stores/state.js
+++ b/app/assets/javascripts/boards/stores/state.js
@@ -8,10 +8,11 @@ export default () => ({
isShowingLabels: true,
activeId: inactiveId,
sidebarType: '',
- boardLists: [],
+ boardLists: {},
+ listsFlags: {},
issuesByListId: {},
+ pageInfoByListId: {},
issues: {},
- isLoadingIssues: false,
filterParams: {},
error: undefined,
// TODO: remove after ce/ee split of board_content.vue
diff --git a/app/assets/javascripts/boards/toggle_focus.js b/app/assets/javascripts/boards/toggle_focus.js
index e60e7059192..fa13d3a9e3c 100644
--- a/app/assets/javascripts/boards/toggle_focus.js
+++ b/app/assets/javascripts/boards/toggle_focus.js
@@ -1,13 +1,15 @@
import $ from 'jquery';
import Vue from 'vue';
-import collapseIcon from './icons/fullscreen_collapse.svg';
-import expandIcon from './icons/fullscreen_expand.svg';
+import { GlIcon } from '@gitlab/ui';
export default (ModalStore, boardsStore) => {
const issueBoardsContent = document.querySelector('.content-wrapper > .js-focus-mode-board');
return new Vue({
el: document.getElementById('js-toggle-focus-btn'),
+ components: {
+ GlIcon,
+ },
data: {
modal: ModalStore.store,
store: boardsStore.state,
@@ -32,12 +34,7 @@ export default (ModalStore, boardsStore) => {
title="Toggle focus mode"
ref="toggleFocusModeButton"
@click="toggleFocusMode">
- <span v-show="isFullscreen">
- ${collapseIcon}
- </span>
- <span v-show="!isFullscreen">
- ${expandIcon}
- </span>
+ <gl-icon :name="isFullscreen ? 'minimize' : 'maximize'" />
</a>
</div>
`,
diff --git a/app/assets/javascripts/breadcrumb.js b/app/assets/javascripts/breadcrumb.js
index a37838694ec..ff7f734f998 100644
--- a/app/assets/javascripts/breadcrumb.js
+++ b/app/assets/javascripts/breadcrumb.js
@@ -1,4 +1,5 @@
import $ from 'jquery';
+import { hide } from '~/tooltips';
export const addTooltipToEl = el => {
const textEl = el.querySelector('.js-breadcrumb-item-text');
@@ -23,9 +24,11 @@ export default () => {
topLevelLinks.forEach(el => addTooltipToEl(el));
$expander.closest('.dropdown').on('show.bs.dropdown hide.bs.dropdown', e => {
- $('.js-breadcrumbs-collapsed-expander', e.currentTarget)
- .toggleClass('open')
- .tooltip('hide');
+ const $el = $('.js-breadcrumbs-collapsed-expander', e.currentTarget);
+
+ $el.toggleClass('open');
+
+ hide($el);
});
}
};
diff --git a/app/assets/javascripts/build_artifacts.js b/app/assets/javascripts/build_artifacts.js
index 2955f0f014b..8324c649538 100644
--- a/app/assets/javascripts/build_artifacts.js
+++ b/app/assets/javascripts/build_artifacts.js
@@ -3,6 +3,7 @@
import $ from 'jquery';
import { visitUrl } from './lib/utils/url_utility';
import { parseBoolean } from './lib/utils/common_utils';
+import { hide, initTooltips, show } from '~/tooltips';
export default class BuildArtifacts {
constructor() {
@@ -10,6 +11,7 @@ export default class BuildArtifacts {
this.setupEntryClick();
this.setupTooltips();
}
+
// eslint-disable-next-line class-methods-use-this
disablePropagation() {
$('.top-block').on('click', '.download', e => {
@@ -19,15 +21,17 @@ export default class BuildArtifacts {
e.stopImmediatePropagation();
});
}
+
// eslint-disable-next-line class-methods-use-this
setupEntryClick() {
return $('.tree-holder').on('click', 'tr[data-link]', function() {
visitUrl(this.dataset.link, parseBoolean(this.dataset.externalLink));
});
}
+
// eslint-disable-next-line class-methods-use-this
setupTooltips() {
- $('.js-artifact-tree-tooltip').tooltip({
+ initTooltips({
placement: 'bottom',
// Stop the tooltip from hiding when we stop hovering the element directly
// We handle all the showing/hiding below
@@ -38,14 +42,14 @@ export default class BuildArtifacts {
// But be placed below and in the middle of the file name
$('.js-artifact-tree-row')
.on('mouseenter', e => {
- $(e.currentTarget)
- .find('.js-artifact-tree-tooltip')
- .tooltip('show');
+ const $el = $(e.currentTarget).find('.js-artifact-tree-tooltip');
+
+ show($el);
})
.on('mouseleave', e => {
- $(e.currentTarget)
- .find('.js-artifact-tree-tooltip')
- .tooltip('hide');
+ const $el = $(e.currentTarget).find('.js-artifact-tree-tooltip');
+
+ hide($el);
});
}
}
diff --git a/app/assets/javascripts/ci_lint/components/ci_lint.vue b/app/assets/javascripts/ci_lint/components/ci_lint.vue
index 135d02e4f76..2532f4b86d2 100644
--- a/app/assets/javascripts/ci_lint/components/ci_lint.vue
+++ b/app/assets/javascripts/ci_lint/components/ci_lint.vue
@@ -1,14 +1,120 @@
<script>
+import { GlButton, GlFormCheckbox, GlIcon, GlLink, GlAlert } from '@gitlab/ui';
+import EditorLite from '~/vue_shared/components/editor_lite.vue';
+import CiLintResults from './ci_lint_results.vue';
+import lintCIMutation from '../graphql/mutations/lint_ci.mutation.graphql';
+
export default {
+ components: {
+ GlButton,
+ GlFormCheckbox,
+ GlIcon,
+ GlLink,
+ GlAlert,
+ CiLintResults,
+ EditorLite,
+ },
props: {
endpoint: {
type: String,
required: true,
},
+ helpPagePath: {
+ type: String,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ content: '',
+ valid: false,
+ errors: null,
+ warnings: null,
+ jobs: [],
+ dryRun: false,
+ showingResults: false,
+ apiError: null,
+ isErrorDismissed: false,
+ };
+ },
+ computed: {
+ shouldShowError() {
+ return this.apiError && !this.isErrorDismissed;
+ },
+ },
+ methods: {
+ async lint() {
+ try {
+ const {
+ data: {
+ lintCI: { valid, errors, warnings, jobs },
+ },
+ } = await this.$apollo.mutate({
+ mutation: lintCIMutation,
+ variables: { endpoint: this.endpoint, content: this.content, dry: this.dryRun },
+ });
+
+ this.showingResults = true;
+ this.valid = valid;
+ this.errors = errors;
+ this.warnings = warnings;
+ this.jobs = jobs;
+ } catch (error) {
+ this.apiError = error;
+ this.isErrorDismissed = false;
+ }
+ },
+ clear() {
+ this.content = '';
+ },
},
};
</script>
-<template
- ><div></div
-></template>
+<template>
+ <div class="row">
+ <div class="col-sm-12">
+ <gl-alert
+ v-if="shouldShowError"
+ class="gl-mb-3"
+ variant="danger"
+ @dismiss="isErrorDismissed = true"
+ >{{ apiError }}</gl-alert
+ >
+ <div class="file-holder gl-mb-3">
+ <div class="js-file-title file-title clearfix">
+ {{ __('Contents of .gitlab-ci.yml') }}
+ </div>
+ <editor-lite v-model="content" file-name="*.yml" />
+ </div>
+ </div>
+
+ <div class="col-sm-12 gl-display-flex gl-justify-content-space-between">
+ <div class="gl-display-flex gl-align-items-center">
+ <gl-button
+ class="gl-mr-4"
+ category="primary"
+ variant="success"
+ data-testid="ci-lint-validate"
+ @click="lint"
+ >{{ __('Validate') }}</gl-button
+ >
+ <gl-form-checkbox v-model="dryRun"
+ >{{ __('Simulate a pipeline created for the default branch') }}
+ <gl-link :href="helpPagePath" target="_blank"
+ ><gl-icon class="gl-text-blue-600" name="question-o"/></gl-link
+ ></gl-form-checkbox>
+ </div>
+ <gl-button data-testid="ci-lint-clear" @click="clear">{{ __('Clear') }}</gl-button>
+ </div>
+
+ <ci-lint-results
+ v-if="showingResults"
+ :valid="valid"
+ :jobs="jobs"
+ :errors="errors"
+ :warnings="warnings"
+ :dry-run="dryRun"
+ />
+ </div>
+</template>
diff --git a/app/assets/javascripts/ci_lint/components/ci_lint_results.vue b/app/assets/javascripts/ci_lint/components/ci_lint_results.vue
index 9fd1bd30c49..28b2a028b29 100644
--- a/app/assets/javascripts/ci_lint/components/ci_lint_results.vue
+++ b/app/assets/javascripts/ci_lint/components/ci_lint_results.vue
@@ -1,9 +1,116 @@
<script>
+import { GlAlert, GlTable } from '@gitlab/ui';
+import CiLintWarnings from './ci_lint_warnings.vue';
+import CiLintResultsValue from './ci_lint_results_value.vue';
+import CiLintResultsParam from './ci_lint_results_param.vue';
+import { __ } from '~/locale';
+
+const thBorderColor = 'gl-border-gray-100!';
+
export default {
- props: {},
+ correct: { variant: 'success', text: __('syntax is correct') },
+ incorrect: { variant: 'danger', text: __('syntax is incorrect') },
+ warningTitle: __('The form contains the following warning:'),
+ fields: [
+ {
+ key: 'parameter',
+ label: __('Parameter'),
+ thClass: thBorderColor,
+ },
+ {
+ key: 'value',
+ label: __('Value'),
+ thClass: thBorderColor,
+ },
+ ],
+ components: {
+ GlAlert,
+ GlTable,
+ CiLintWarnings,
+ CiLintResultsValue,
+ CiLintResultsParam,
+ },
+ props: {
+ valid: {
+ type: Boolean,
+ required: true,
+ },
+ jobs: {
+ type: Array,
+ required: true,
+ },
+ errors: {
+ type: Array,
+ required: true,
+ },
+ warnings: {
+ type: Array,
+ required: true,
+ },
+ dryRun: {
+ type: Boolean,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ isWarningDismissed: false,
+ };
+ },
+ computed: {
+ status() {
+ return this.valid ? this.$options.correct : this.$options.incorrect;
+ },
+ shouldShowTable() {
+ return this.errors.length === 0;
+ },
+ shouldShowError() {
+ return this.errors.length > 0;
+ },
+ shouldShowWarning() {
+ return this.warnings.length > 0 && !this.isWarningDismissed;
+ },
+ },
};
</script>
-<template
- ><div></div
-></template>
+<template>
+ <div class="col-sm-12 gl-mt-5">
+ <gl-alert
+ class="gl-mb-5"
+ :variant="status.variant"
+ :title="__('Status:')"
+ :dismissible="false"
+ data-testid="ci-lint-status"
+ >{{ status.text }}</gl-alert
+ >
+
+ <pre
+ v-if="shouldShowError"
+ class="gl-mb-5"
+ data-testid="ci-lint-errors"
+ ><div v-for="error in errors" :key="error">{{ error }}</div></pre>
+
+ <ci-lint-warnings
+ v-if="shouldShowWarning"
+ :warnings="warnings"
+ data-testid="ci-lint-warnings"
+ @dismiss="isWarningDismissed = true"
+ />
+
+ <gl-table
+ v-if="shouldShowTable"
+ :items="jobs"
+ :fields="$options.fields"
+ bordered
+ data-testid="ci-lint-table"
+ >
+ <template #cell(parameter)="{ item }">
+ <ci-lint-results-param :stage="item.stage" :job-name="item.name" />
+ </template>
+ <template #cell(value)="{ item }">
+ <ci-lint-results-value :item="item" :dry-run="dryRun" />
+ </template>
+ </gl-table>
+ </div>
+</template>
diff --git a/app/assets/javascripts/ci_lint/components/ci_lint_results_param.vue b/app/assets/javascripts/ci_lint/components/ci_lint_results_param.vue
new file mode 100644
index 00000000000..23808bcb292
--- /dev/null
+++ b/app/assets/javascripts/ci_lint/components/ci_lint_results_param.vue
@@ -0,0 +1,26 @@
+<script>
+import { __ } from '~/locale';
+import { capitalizeFirstCharacter } from '~/lib/utils/text_utility';
+
+export default {
+ props: {
+ stage: {
+ type: String,
+ required: true,
+ },
+ jobName: {
+ type: String,
+ required: true,
+ },
+ },
+ computed: {
+ formatParameter() {
+ return __(`${capitalizeFirstCharacter(this.stage)} Job - ${this.jobName}`);
+ },
+ },
+};
+</script>
+
+<template>
+ <span data-testid="ci-lint-parameter">{{ formatParameter }}</span>
+</template>
diff --git a/app/assets/javascripts/ci_lint/components/ci_lint_results_value.vue b/app/assets/javascripts/ci_lint/components/ci_lint_results_value.vue
new file mode 100644
index 00000000000..4929c3206df
--- /dev/null
+++ b/app/assets/javascripts/ci_lint/components/ci_lint_results_value.vue
@@ -0,0 +1,81 @@
+<script>
+import { isEmpty } from 'lodash';
+
+export default {
+ props: {
+ item: {
+ type: Object,
+ required: true,
+ },
+ dryRun: {
+ type: Boolean,
+ required: true,
+ },
+ },
+ computed: {
+ tagList() {
+ return this.item.tagList.join(', ');
+ },
+ onlyPolicy() {
+ return this.item.only ? this.item.only.refs.join(', ') : this.item.only;
+ },
+ exceptPolicy() {
+ return this.item.except ? this.item.except.refs.join(', ') : this.item.except;
+ },
+ scripts() {
+ return {
+ beforeScript: {
+ show: !isEmpty(this.item.beforeScript),
+ content: this.item.beforeScript.join('\n'),
+ },
+ script: {
+ show: !isEmpty(this.item.script),
+ content: this.item.script.join('\n'),
+ },
+ afterScript: {
+ show: !isEmpty(this.item.afterScript),
+ content: this.item.afterScript.join('\n'),
+ },
+ };
+ },
+ },
+};
+</script>
+
+<template>
+ <div>
+ <pre v-if="scripts.beforeScript.show" data-testid="ci-lint-before-script">{{
+ scripts.beforeScript.content
+ }}</pre>
+ <pre v-if="scripts.script.show" data-testid="ci-lint-script">{{ scripts.script.content }}</pre>
+ <pre v-if="scripts.afterScript.show" data-testid="ci-lint-after-script">{{
+ scripts.afterScript.content
+ }}</pre>
+
+ <ul class="gl-list-style-none gl-pl-0 gl-mb-0">
+ <li>
+ <b>{{ __('Tag list:') }}</b>
+ {{ tagList }}
+ </li>
+ <div v-if="!dryRun" data-testid="ci-lint-only-except">
+ <li>
+ <b>{{ __('Only policy:') }}</b>
+ {{ onlyPolicy }}
+ </li>
+ <li>
+ <b>{{ __('Except policy:') }}</b>
+ {{ exceptPolicy }}
+ </li>
+ </div>
+ <li>
+ <b>{{ __('Environment:') }}</b>
+ {{ item.environment }}
+ </li>
+ <li>
+ <b>{{ __('When:') }}</b>
+ {{ item.when }}
+ <b v-if="item.allowFailure">{{ __('Allowed to fail') }}</b>
+ </li>
+ </ul>
+ </div>
+</template>
diff --git a/app/assets/javascripts/ci_lint/components/ci_lint_warnings.vue b/app/assets/javascripts/ci_lint/components/ci_lint_warnings.vue
new file mode 100644
index 00000000000..ac0332cb0bd
--- /dev/null
+++ b/app/assets/javascripts/ci_lint/components/ci_lint_warnings.vue
@@ -0,0 +1,69 @@
+<script>
+import { GlAlert, GlSprintf } from '@gitlab/ui';
+import { __, n__ } from '~/locale';
+
+export default {
+ maxWarningsSummary: __('%{total} warnings found: showing first %{warningsDisplayed}'),
+ components: {
+ GlAlert,
+ GlSprintf,
+ },
+ props: {
+ warnings: {
+ type: Array,
+ required: true,
+ },
+ maxWarnings: {
+ type: Number,
+ required: false,
+ default: 25,
+ },
+ title: {
+ type: String,
+ required: false,
+ default: __('The form contains the following warning:'),
+ },
+ },
+ computed: {
+ totalWarnings() {
+ return this.warnings.length;
+ },
+ overMaxWarningsLimit() {
+ return this.totalWarnings > this.maxWarnings;
+ },
+ warningsSummary() {
+ return n__('%d warning found:', '%d warnings found:', this.totalWarnings);
+ },
+ summaryMessage() {
+ return this.overMaxWarningsLimit ? this.$options.maxWarningsSummary : this.warningsSummary;
+ },
+ limitWarnings() {
+ return this.warnings.slice(0, this.maxWarnings);
+ },
+ },
+};
+</script>
+
+<template>
+ <gl-alert class="gl-mb-4" :title="title" variant="warning" @dismiss="$emit('dismiss')">
+ <details>
+ <summary>
+ <gl-sprintf :message="summaryMessage">
+ <template #total>
+ {{ totalWarnings }}
+ </template>
+ <template #warningsDisplayed>
+ {{ maxWarnings }}
+ </template>
+ </gl-sprintf>
+ </summary>
+ <p
+ v-for="(warning, index) in limitWarnings"
+ :key="`warning-${index}`"
+ data-testid="ci-lint-warning"
+ >
+ {{ warning }}
+ </p>
+ </details>
+ </gl-alert>
+</template>
diff --git a/app/assets/javascripts/ci_lint/graphql/mutations/lint_ci.mutation.graphql b/app/assets/javascripts/ci_lint/graphql/mutations/lint_ci.mutation.graphql
new file mode 100644
index 00000000000..496036f690f
--- /dev/null
+++ b/app/assets/javascripts/ci_lint/graphql/mutations/lint_ci.mutation.graphql
@@ -0,0 +1,22 @@
+mutation lintCI($endpoint: String, $content: String, $dry: Boolean) {
+ lintCI(endpoint: $endpoint, content: $content, dry_run: $dry) @client {
+ valid
+ errors
+ warnings
+ jobs {
+ afterScript
+ allowFailure
+ beforeScript
+ environment
+ except
+ name
+ only {
+ refs
+ }
+ afterScript
+ stage
+ tagList
+ when
+ }
+ }
+}
diff --git a/app/assets/javascripts/ci_lint/index.js b/app/assets/javascripts/ci_lint/index.js
index ed2cf1fe714..c41e6d47d75 100644
--- a/app/assets/javascripts/ci_lint/index.js
+++ b/app/assets/javascripts/ci_lint/index.js
@@ -1,16 +1,57 @@
import Vue from 'vue';
-import CILint from './components/ci_lint.vue';
+import VueApollo from 'vue-apollo';
+import axios from '~/lib/utils/axios_utils';
+import createDefaultClient from '~/lib/graphql';
+import CiLint from './components/ci_lint.vue';
+
+Vue.use(VueApollo);
+
+const resolvers = {
+ Mutation: {
+ lintCI: (_, { endpoint, content, dry_run }) => {
+ return axios.post(endpoint, { content, dry_run }).then(({ data }) => ({
+ valid: data.valid,
+ errors: data.errors,
+ warnings: data.warnings,
+ jobs: data.jobs.map(job => ({
+ name: job.name,
+ stage: job.stage,
+ beforeScript: job.before_script,
+ script: job.script,
+ afterScript: job.after_script,
+ tagList: job.tag_list,
+ environment: job.environment,
+ when: job.when,
+ allowFailure: job.allow_failure,
+ only: {
+ refs: job.only.refs,
+ __typename: 'CiLintJobOnlyPolicy',
+ },
+ except: job.except,
+ __typename: 'CiLintJob',
+ })),
+ __typename: 'CiLintContent',
+ }));
+ },
+ },
+};
+
+const apolloProvider = new VueApollo({
+ defaultClient: createDefaultClient(resolvers),
+});
export default (containerId = '#js-ci-lint') => {
const containerEl = document.querySelector(containerId);
- const { endpoint } = containerEl.dataset;
+ const { endpoint, helpPagePath } = containerEl.dataset;
return new Vue({
el: containerEl,
+ apolloProvider,
render(createElement) {
- return createElement(CILint, {
+ return createElement(CiLint, {
props: {
endpoint,
+ helpPagePath,
},
});
},
diff --git a/app/assets/javascripts/ci_settings_pipeline_triggers/components/triggers_list.vue b/app/assets/javascripts/ci_settings_pipeline_triggers/components/triggers_list.vue
new file mode 100644
index 00000000000..ad07052a298
--- /dev/null
+++ b/app/assets/javascripts/ci_settings_pipeline_triggers/components/triggers_list.vue
@@ -0,0 +1,143 @@
+<script>
+import { GlTable, GlButton, GlBadge, GlTooltipDirective } from '@gitlab/ui';
+import { s__ } from '~/locale';
+import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
+import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate.vue';
+import UserAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue';
+import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
+
+export default {
+ components: {
+ GlTable,
+ GlButton,
+ GlBadge,
+ ClipboardButton,
+ TooltipOnTruncate,
+ UserAvatarLink,
+ TimeAgoTooltip,
+ },
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ },
+ props: {
+ triggers: {
+ type: Array,
+ required: false,
+ default: () => [],
+ },
+ },
+ fields: [
+ {
+ key: 'token',
+ label: s__('Pipelines|Token'),
+ },
+ {
+ key: 'description',
+ label: s__('Pipelines|Description'),
+ },
+ {
+ key: 'owner',
+ label: s__('Pipelines|Owner'),
+ },
+ {
+ key: 'lastUsed',
+ label: s__('Pipelines|Last Used'),
+ },
+ {
+ key: 'actions',
+ label: '',
+ tdClass: 'gl-text-right gl-white-space-nowrap',
+ },
+ ],
+};
+</script>
+
+<template>
+ <div>
+ <gl-table
+ v-if="triggers.length"
+ :fields="$options.fields"
+ :items="triggers"
+ class="triggers-list"
+ responsive
+ >
+ <template #cell(token)="{item}">
+ {{ item.token }}
+ <clipboard-button
+ v-if="item.hasTokenExposed"
+ :text="item.token"
+ data-testid="clipboard-btn"
+ data-qa-selector="clipboard_button"
+ :title="s__('Pipelines|Copy trigger token')"
+ css-class="gl-border-none gl-py-0 gl-px-2"
+ />
+ <div class="label-container">
+ <gl-badge v-if="!item.canAccessProject" variant="danger">
+ <span
+ v-gl-tooltip.viewport
+ boundary="viewport"
+ :title="s__('Pipelines|Trigger user has insufficient permissions to project')"
+ >{{ s__('Pipelines|invalid') }}</span
+ >
+ </gl-badge>
+ </div>
+ </template>
+ <template #cell(description)="{item}">
+ <tooltip-on-truncate
+ :title="item.description"
+ truncate-target="child"
+ placement="top"
+ class="trigger-description gl-display-flex"
+ >
+ <div class="gl-flex-fill-1 gl-text-truncate">{{ item.description }}</div>
+ </tooltip-on-truncate>
+ </template>
+ <template #cell(owner)="{item}">
+ <span class="trigger-owner sr-only">{{ item.owner.name }}</span>
+ <user-avatar-link
+ v-if="item.owner"
+ :link-href="item.owner.path"
+ :img-src="item.owner.avatarUrl"
+ :tooltip-text="item.owner.name"
+ :img-alt="item.owner.name"
+ />
+ </template>
+ <template #cell(lastUsed)="{item}">
+ <time-ago-tooltip v-if="item.lastUsed" :time="item.lastUsed" />
+ <span v-else>{{ __('Never') }}</span>
+ </template>
+ <template #cell(actions)="{item}">
+ <gl-button
+ :title="s__('Pipelines|Edit')"
+ icon="pencil"
+ data-testid="edit-btn"
+ :href="item.editProjectTriggerPath"
+ />
+ <gl-button
+ :title="s__('Pipelines|Revoke')"
+ icon="remove"
+ variant="warning"
+ :data-confirm="
+ s__(
+ 'Pipelines|By revoking a trigger you will break any processes making use of it. Are you sure?',
+ )
+ "
+ data-method="delete"
+ rel="nofollow"
+ class="gl-ml-3"
+ data-testid="trigger_revoke_button"
+ data-qa-selector="trigger_revoke_button"
+ :href="item.projectTriggerPath"
+ />
+ </template>
+ </gl-table>
+ <div
+ v-else
+ data-testid="no_triggers_content"
+ data-qa-selector="no_triggers_content"
+ class="settings-message gl-text-center gl-mb-3"
+ >
+ {{ s__('Pipelines|No triggers have been created yet. Add one using the form above.') }}
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/ci_settings_pipeline_triggers/index.js b/app/assets/javascripts/ci_settings_pipeline_triggers/index.js
new file mode 100644
index 00000000000..182d5ca5ffb
--- /dev/null
+++ b/app/assets/javascripts/ci_settings_pipeline_triggers/index.js
@@ -0,0 +1,36 @@
+import Vue from 'vue';
+import TriggersList from './components/triggers_list.vue';
+import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
+
+const parseJsonArray = triggers => {
+ try {
+ return convertObjectPropsToCamelCase(JSON.parse(triggers), { deep: true });
+ } catch {
+ return [];
+ }
+};
+
+export default (containerId = 'js-ci-pipeline-triggers-list') => {
+ const containerEl = document.getElementById(containerId);
+
+ // Note: Remove this check when FF `ci_pipeline_triggers_settings_vue_ui` is removed.
+ if (!containerEl) {
+ return null;
+ }
+
+ const triggers = parseJsonArray(containerEl.dataset.triggers);
+
+ return new Vue({
+ el: containerEl,
+ components: {
+ TriggersList,
+ },
+ render(h) {
+ return h(TriggersList, {
+ props: {
+ triggers,
+ },
+ });
+ },
+ });
+};
diff --git a/app/assets/javascripts/ci_variable_list/components/ci_environments_dropdown.vue b/app/assets/javascripts/ci_variable_list/components/ci_environments_dropdown.vue
index 0e09ae108ea..ceb94b1f0f8 100644
--- a/app/assets/javascripts/ci_variable_list/components/ci_environments_dropdown.vue
+++ b/app/assets/javascripts/ci_variable_list/components/ci_environments_dropdown.vue
@@ -1,22 +1,15 @@
<script>
-import {
- GlDeprecatedDropdown,
- GlDeprecatedDropdownItem,
- GlDeprecatedDropdownDivider,
- GlSearchBoxByType,
- GlIcon,
-} from '@gitlab/ui';
+import { GlDropdown, GlDropdownItem, GlDropdownDivider, GlSearchBoxByType } from '@gitlab/ui';
import { mapGetters } from 'vuex';
import { __, sprintf } from '~/locale';
export default {
name: 'CiEnvironmentsDropdown',
components: {
- GlDeprecatedDropdown,
- GlDeprecatedDropdownItem,
- GlDeprecatedDropdownDivider,
+ GlDropdown,
+ GlDropdownItem,
+ GlDropdownDivider,
GlSearchBoxByType,
- GlIcon,
},
props: {
value: {
@@ -66,28 +59,25 @@ export default {
};
</script>
<template>
- <gl-deprecated-dropdown :text="value">
- <gl-search-box-by-type v-model.trim="searchTerm" class="gl-m-3" />
- <gl-deprecated-dropdown-item
+ <gl-dropdown :text="value">
+ <gl-search-box-by-type v-model.trim="searchTerm" />
+ <gl-dropdown-item
v-for="environment in filteredResults"
:key="environment"
+ :is-checked="isSelected(environment)"
+ is-check-item
@click="selectEnvironment(environment)"
>
- <gl-icon
- :class="{ invisible: !isSelected(environment) }"
- name="mobile-issue-close"
- class="vertical-align-middle"
- />
{{ environment }}
- </gl-deprecated-dropdown-item>
- <gl-deprecated-dropdown-item v-if="!filteredResults.length" ref="noMatchingResults">{{
+ </gl-dropdown-item>
+ <gl-dropdown-item v-if="!filteredResults.length" ref="noMatchingResults">{{
__('No matching results')
- }}</gl-deprecated-dropdown-item>
+ }}</gl-dropdown-item>
<template v-if="shouldRenderCreateButton">
- <gl-deprecated-dropdown-divider />
- <gl-deprecated-dropdown-item @click="createClicked">
+ <gl-dropdown-divider />
+ <gl-dropdown-item @click="createClicked">
{{ composedCreateButtonLabel }}
- </gl-deprecated-dropdown-item>
+ </gl-dropdown-item>
</template>
- </gl-deprecated-dropdown>
+ </gl-dropdown>
</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 fbf19847e9d..a2f4bea2f61 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
@@ -6,7 +6,6 @@ import {
GlFormCheckbox,
GlFormCombobox,
GlFormGroup,
- GlFormInput,
GlFormSelect,
GlFormTextarea,
GlIcon,
@@ -41,7 +40,6 @@ export default {
GlFormCheckbox,
GlFormCombobox,
GlFormGroup,
- GlFormInput,
GlFormSelect,
GlFormTextarea,
GlIcon,
@@ -122,11 +120,6 @@ export default {
return '';
},
tokenValidationState() {
- // If the feature flag is off, do not validate. Remove when flag is removed.
- if (!this.glFeatures.ciKeyAutocomplete) {
- return true;
- }
-
const validator = this.$options.tokens?.[this.variable.key]?.validation;
if (validator) {
@@ -204,21 +197,12 @@ export default {
>
<form>
<gl-form-combobox
- v-if="glFeatures.ciKeyAutocomplete"
v-model="key"
:token-list="$options.tokenList"
:label-text="__('Key')"
data-qa-selector="ci_variable_key_field"
/>
- <gl-form-group v-else :label="__('Key')" label-for="ci-variable-key">
- <gl-form-input
- id="ci-variable-key"
- v-model="key"
- data-qa-selector="ci_variable_key_field"
- />
- </gl-form-group>
-
<gl-form-group
:label="__('Value')"
label-for="ci-variable-value"
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 501c82b419e..07278bb442c 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
@@ -163,10 +163,7 @@ export default {
</p>
</template>
</gl-table>
- <div
- class="ci-variable-actions d-flex justify-content-end"
- :class="{ 'justify-content-center': !tableIsNotEmpty }"
- >
+ <div class="ci-variable-actions" :class="{ 'justify-content-center': !tableIsNotEmpty }">
<gl-button
v-if="tableIsNotEmpty"
ref="secret-value-reveal-button"
diff --git a/app/assets/javascripts/clusters/components/applications.vue b/app/assets/javascripts/clusters/components/applications.vue
index 039237042ea..b03cf6fc31b 100644
--- a/app/assets/javascripts/clusters/components/applications.vue
+++ b/app/assets/javascripts/clusters/components/applications.vue
@@ -360,7 +360,7 @@ export default {
>
<template #link="{ content }">
<gl-link
- href="https://docs.gitlab.com/ce/user/project/integrations/prometheus.html"
+ href="https://docs.gitlab.com/ee/user/project/integrations/prometheus.html"
target="_blank"
>{{ content }}</gl-link
>
@@ -481,7 +481,7 @@ export default {
type="text"
class="form-control js-hostname"
/>
- <span class="input-group-btn">
+ <span class="input-group-append">
<clipboard-button
:text="jupyterHostname"
:title="s__('ClusterIntegration|Copy Jupyter Hostname')"
diff --git a/app/assets/javascripts/clusters/components/crossplane_provider_stack.vue b/app/assets/javascripts/clusters/components/crossplane_provider_stack.vue
index c816fc56d7a..6b99bb09504 100644
--- a/app/assets/javascripts/clusters/components/crossplane_provider_stack.vue
+++ b/app/assets/javascripts/clusters/components/crossplane_provider_stack.vue
@@ -1,12 +1,12 @@
<script>
-import { GlDeprecatedDropdown, GlDeprecatedDropdownItem, GlIcon } from '@gitlab/ui';
+import { GlDropdown, GlDropdownItem, GlIcon } from '@gitlab/ui';
import { s__ } from '../../locale';
export default {
name: 'CrossplaneProviderStack',
components: {
- GlDeprecatedDropdown,
- GlDeprecatedDropdownItem,
+ GlDropdown,
+ GlDropdownItem,
GlIcon,
},
props: {
@@ -67,21 +67,17 @@ export default {
<label>
{{ s__('ClusterIntegration|Enabled stack') }}
</label>
- <gl-deprecated-dropdown
+ <gl-dropdown
:disabled="crossplane.installed"
:text="dropdownText"
toggle-class="dropdown-menu-toggle gl-field-error-outline"
class="w-100"
:class="{ 'gl-show-field-errors': validationError }"
>
- <gl-deprecated-dropdown-item
- v-for="stack in stacks"
- :key="stack.code"
- @click="selectStack(stack)"
- >
+ <gl-dropdown-item v-for="stack in stacks" :key="stack.code" @click="selectStack(stack)">
<span class="ml-1">{{ stack.name }}</span>
- </gl-deprecated-dropdown-item>
- </gl-deprecated-dropdown>
+ </gl-dropdown-item>
+ </gl-dropdown>
<span v-if="validationError" class="gl-field-error">{{ validationError }}</span>
<p class="form-text text-muted">
{{ s__(`You must select a stack for configuring your cloud provider. Learn more about`) }}
diff --git a/app/assets/javascripts/clusters/components/fluentd_output_settings.vue b/app/assets/javascripts/clusters/components/fluentd_output_settings.vue
index e6001b11296..b37fc3894f8 100644
--- a/app/assets/javascripts/clusters/components/fluentd_output_settings.vue
+++ b/app/assets/javascripts/clusters/components/fluentd_output_settings.vue
@@ -1,11 +1,5 @@
<script>
-import {
- GlAlert,
- GlDeprecatedButton,
- GlDeprecatedDropdown,
- GlDeprecatedDropdownItem,
- GlFormCheckbox,
-} from '@gitlab/ui';
+import { GlAlert, GlButton, GlDropdown, GlDropdownItem, GlFormCheckbox } from '@gitlab/ui';
import { mapValues } from 'lodash';
import { __ } from '~/locale';
import { APPLICATION_STATUS, FLUENTD } from '~/clusters/constants';
@@ -16,9 +10,9 @@ const { UPDATING, UNINSTALLING, INSTALLING, INSTALLED, UPDATED } = APPLICATION_S
export default {
components: {
GlAlert,
- GlDeprecatedButton,
- GlDeprecatedDropdown,
- GlDeprecatedDropdownItem,
+ GlButton,
+ GlDropdown,
+ GlDropdownItem,
GlFormCheckbox,
},
props: {
@@ -203,15 +197,15 @@ export default {
<label for="fluentd-protocol">
<strong>{{ s__('ClusterIntegration|SIEM Protocol') }}</strong>
</label>
- <gl-deprecated-dropdown :text="protocolName" class="w-100">
- <gl-deprecated-dropdown-item
+ <gl-dropdown :text="protocolName" class="w-100">
+ <gl-dropdown-item
v-for="(value, index) in protocols"
:key="index"
@click="selectProtocol(value.toLowerCase())"
>
{{ value }}
- </gl-deprecated-dropdown-item>
- </gl-deprecated-dropdown>
+ </gl-dropdown-item>
+ </gl-dropdown>
</div>
<div class="form-group flex flex-wrap">
<gl-form-checkbox :checked="wafLogEnabled" @input="wafLogChanged">
@@ -221,20 +215,21 @@ export default {
<strong>{{ s__('ClusterIntegration|Send Container Network Policies Logs') }}</strong>
</gl-form-checkbox>
</div>
- <div v-if="showButtons" class="mt-3">
- <gl-deprecated-button
+ <div v-if="showButtons" class="gl-mt-5 gl-display-flex">
+ <gl-button
ref="saveBtn"
- class="mr-1"
+ class="gl-mr-3"
variant="success"
+ category="primary"
:loading="isSaving"
:disabled="saveButtonDisabled"
@click="updateApplication"
>
{{ saveButtonLabel }}
- </gl-deprecated-button>
- <gl-deprecated-button ref="cancelBtn" :disabled="saveButtonDisabled" @click="resetStatus">
+ </gl-button>
+ <gl-button ref="cancelBtn" :disabled="saveButtonDisabled" @click="resetStatus">
{{ __('Cancel') }}
- </gl-deprecated-button>
+ </gl-button>
</div>
</div>
</div>
diff --git a/app/assets/javascripts/clusters/components/ingress_modsecurity_settings.vue b/app/assets/javascripts/clusters/components/ingress_modsecurity_settings.vue
index 5e8e1a76182..f05c8db5d56 100644
--- a/app/assets/javascripts/clusters/components/ingress_modsecurity_settings.vue
+++ b/app/assets/javascripts/clusters/components/ingress_modsecurity_settings.vue
@@ -5,9 +5,9 @@ import {
GlSprintf,
GlLink,
GlToggle,
- GlDeprecatedButton,
- GlDeprecatedDropdown,
- GlDeprecatedDropdownItem,
+ GlButton,
+ GlDropdown,
+ GlDropdownItem,
GlIcon,
} from '@gitlab/ui';
import modSecurityLogo from 'images/cluster_app_logos/gitlab.png';
@@ -25,9 +25,9 @@ export default {
GlSprintf,
GlLink,
GlToggle,
- GlDeprecatedButton,
- GlDeprecatedDropdown,
- GlDeprecatedDropdownItem,
+ GlButton,
+ GlDropdown,
+ GlDropdownItem,
GlIcon,
},
props: {
@@ -221,29 +221,31 @@ export default {
</strong>
</p>
</div>
- <gl-deprecated-dropdown :text="modSecurityModeName" :disabled="saveButtonDisabled">
- <gl-deprecated-dropdown-item
- v-for="(mode, key) in modes"
- :key="key"
- @click="selectMode(key)"
- >
+ <gl-dropdown :text="modSecurityModeName" :disabled="saveButtonDisabled">
+ <gl-dropdown-item v-for="(mode, key) in modes" :key="key" @click="selectMode(key)">
{{ mode.name }}
- </gl-deprecated-dropdown-item>
- </gl-deprecated-dropdown>
+ </gl-dropdown-item>
+ </gl-dropdown>
</div>
</div>
- <div v-if="showButtons" class="mt-3">
- <gl-deprecated-button
- class="btn-success inline mr-1"
+ <div v-if="showButtons" class="gl-mt-5 gl-display-flex">
+ <gl-button
+ variant="success"
+ category="primary"
+ data-qa-selector="save_ingress_modsecurity_settings"
:loading="saving"
:disabled="saveButtonDisabled"
@click="updateApplication"
>
{{ saveButtonLabel }}
- </gl-deprecated-button>
- <gl-deprecated-button :disabled="saveButtonDisabled" @click="resetStatus">
+ </gl-button>
+ <gl-button
+ data-qa-selector="cancel_ingress_modsecurity_settings"
+ :disabled="saveButtonDisabled"
+ @click="resetStatus"
+ >
{{ __('Cancel') }}
- </gl-deprecated-button>
+ </gl-button>
</div>
</div>
</div>
diff --git a/app/assets/javascripts/clusters/components/knative_domain_editor.vue b/app/assets/javascripts/clusters/components/knative_domain_editor.vue
index 2617ea0bdea..cb415d902e8 100644
--- a/app/assets/javascripts/clusters/components/knative_domain_editor.vue
+++ b/app/assets/javascripts/clusters/components/knative_domain_editor.vue
@@ -1,8 +1,8 @@
<script>
import {
- GlDeprecatedDropdown,
- GlDeprecatedDropdownDivider,
- GlDeprecatedDropdownItem,
+ GlDropdown,
+ GlDropdownDivider,
+ GlDropdownItem,
GlLoadingIcon,
GlSearchBoxByType,
GlSprintf,
@@ -20,9 +20,9 @@ export default {
GlButton,
ClipboardButton,
GlLoadingIcon,
- GlDeprecatedDropdown,
- GlDeprecatedDropdownDivider,
- GlDeprecatedDropdownItem,
+ GlDropdown,
+ GlDropdownDivider,
+ GlDropdownItem,
GlSearchBoxByType,
GlSprintf,
},
@@ -121,7 +121,7 @@ export default {
<strong>{{ s__('ClusterIntegration|Knative Domain Name:') }}</strong>
</label>
- <gl-deprecated-dropdown
+ <gl-dropdown
v-if="showDomainsDropdown"
:text="domainDropdownText"
toggle-class="dropdown-menu-toggle"
@@ -130,18 +130,17 @@ export default {
<gl-search-box-by-type
v-model.trim="searchQuery"
:placeholder="s__('ClusterIntegration|Search domains')"
- class="gl-m-3"
/>
- <gl-deprecated-dropdown-item
+ <gl-dropdown-item
v-for="domain in filteredDomains"
:key="domain.id"
@click="selectDomain(domain)"
>
<span class="ml-1">{{ domain.domain }}</span>
- </gl-deprecated-dropdown-item>
+ </gl-dropdown-item>
<template v-if="searchQuery">
- <gl-deprecated-dropdown-divider />
- <gl-deprecated-dropdown-item key="custom-domain" @click="selectCustomDomain(searchQuery)">
+ <gl-dropdown-divider />
+ <gl-dropdown-item key="custom-domain" @click="selectCustomDomain(searchQuery)">
<span class="ml-1">
<gl-sprintf :message="s__('ClusterIntegration|Use %{query}')">
<template #query>
@@ -149,9 +148,9 @@ export default {
</template>
</gl-sprintf>
</span>
- </gl-deprecated-dropdown-item>
+ </gl-dropdown-item>
</template>
- </gl-deprecated-dropdown>
+ </gl-dropdown>
<input
v-else
diff --git a/app/assets/javascripts/clusters/components/uninstall_application_confirmation_modal.vue b/app/assets/javascripts/clusters/components/uninstall_application_confirmation_modal.vue
index f82f4dd5012..477dd13db4f 100644
--- a/app/assets/javascripts/clusters/components/uninstall_application_confirmation_modal.vue
+++ b/app/assets/javascripts/clusters/components/uninstall_application_confirmation_modal.vue
@@ -1,6 +1,5 @@
<script>
-/* eslint-disable vue/no-v-html */
-import { GlModal } from '@gitlab/ui';
+import { GlModal, GlSafeHtmlDirective as SafeHtml } from '@gitlab/ui';
import trackUninstallButtonClickMixin from 'ee_else_ce/clusters/mixins/track_uninstall_button_click';
import { sprintf, s__ } from '~/locale';
import {
@@ -45,6 +44,9 @@ export default {
components: {
GlModal,
},
+ directives: {
+ SafeHtml,
+ },
mixins: [trackUninstallButtonClickMixin],
props: {
application: {
@@ -94,6 +96,6 @@ export default {
:title="title"
@ok="confirmUninstall()"
>
- {{ warningText }} <span v-html="customAppWarningText"></span>
+ {{ warningText }} <span v-safe-html="customAppWarningText"></span>
</gl-modal>
</template>
diff --git a/app/assets/javascripts/clusters/forms/components/integration_form.vue b/app/assets/javascripts/clusters/forms/components/integration_form.vue
index 53e004b4fc0..f0dafa7ef53 100644
--- a/app/assets/javascripts/clusters/forms/components/integration_form.vue
+++ b/app/assets/javascripts/clusters/forms/components/integration_form.vue
@@ -24,10 +24,10 @@ export default {
},
inject: {
autoDevopsHelpPath: {
- type: String,
+ default: '',
},
externalEndpointHelpPath: {
- type: String,
+ default: '',
},
},
data() {
diff --git a/app/assets/javascripts/clusters_list/components/clusters.vue b/app/assets/javascripts/clusters_list/components/clusters.vue
index 7b53020fc49..f8fb58cdca2 100644
--- a/app/assets/javascripts/clusters_list/components/clusters.vue
+++ b/app/assets/javascripts/clusters_list/components/clusters.vue
@@ -10,6 +10,7 @@ import {
GlTable,
} from '@gitlab/ui';
import AncestorNotice from './ancestor_notice.vue';
+import NodeErrorHelpText from './node_error_help_text.vue';
import tooltip from '~/vue_shared/directives/tooltip';
import { CLUSTER_TYPES, STATUSES } from '../constants';
import { __, sprintf } from '~/locale';
@@ -26,6 +27,7 @@ export default {
GlSkeletonLoading,
GlSprintf,
GlTable,
+ NodeErrorHelpText,
},
directives: {
tooltip,
@@ -199,7 +201,13 @@ export default {
<section v-else>
<ancestor-notice />
- <gl-table :items="clusters" :fields="fields" stacked="md" class="qa-clusters-table">
+ <gl-table
+ :items="clusters"
+ :fields="fields"
+ stacked="md"
+ class="qa-clusters-table"
+ data-testid="cluster_list_table"
+ >
<template #cell(name)="{ item }">
<div :class="[contentAlignClasses, 'js-status']">
<img
@@ -231,9 +239,12 @@ export default {
<gl-skeleton-loading v-else-if="loadingNodes" :lines="1" :class="contentAlignClasses" />
- <small v-else class="gl-font-sm gl-font-style-italic gl-text-gray-200">{{
- __('Unknown')
- }}</small>
+ <NodeErrorHelpText
+ v-else-if="item.kubernetes_errors"
+ :class="contentAlignClasses"
+ :error-type="item.kubernetes_errors.connection_error"
+ :popover-id="`nodeSizeError${item.id}`"
+ />
</template>
<template #cell(total_cpu)="{ item }">
@@ -250,6 +261,13 @@ export default {
</span>
<gl-skeleton-loading v-else-if="loadingNodes" :lines="1" :class="contentAlignClasses" />
+
+ <NodeErrorHelpText
+ v-else-if="item.kubernetes_errors"
+ :class="contentAlignClasses"
+ :error-type="item.kubernetes_errors.node_connection_error"
+ :popover-id="`nodeCpuError${item.id}`"
+ />
</template>
<template #cell(total_memory)="{ item }">
@@ -266,6 +284,13 @@ export default {
</span>
<gl-skeleton-loading v-else-if="loadingNodes" :lines="1" :class="contentAlignClasses" />
+
+ <NodeErrorHelpText
+ v-else-if="item.kubernetes_errors"
+ :class="contentAlignClasses"
+ :error-type="item.kubernetes_errors.metrics_connection_error"
+ :popover-id="`nodeMemoryError${item.id}`"
+ />
</template>
<template #cell(cluster_type)="{value}">
diff --git a/app/assets/javascripts/clusters_list/components/node_error_help_text.vue b/app/assets/javascripts/clusters_list/components/node_error_help_text.vue
new file mode 100644
index 00000000000..1a396694bc8
--- /dev/null
+++ b/app/assets/javascripts/clusters_list/components/node_error_help_text.vue
@@ -0,0 +1,53 @@
+<script>
+import { GlIcon, GlPopover } from '@gitlab/ui';
+import { CLUSTER_ERRORS } from '../constants';
+
+export default {
+ components: {
+ GlIcon,
+ GlPopover,
+ },
+ props: {
+ errorType: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ popoverId: {
+ type: String,
+ required: true,
+ },
+ },
+ computed: {
+ errorContent() {
+ return CLUSTER_ERRORS[this.errorType] || CLUSTER_ERRORS.default;
+ },
+ },
+};
+</script>
+
+<template>
+ <div :id="popoverId">
+ <span class="gl-font-style-italic">
+ {{ errorContent.tableText }}
+ </span>
+
+ <gl-icon name="status_warning" :size="24" class="gl-p-2" />
+
+ <gl-popover :container="popoverId" :target="popoverId" placement="top" triggers="hover focus">
+ <template #title>
+ <span class="gl-display-block gl-text-left">{{ errorContent.title }}</span>
+ </template>
+
+ <p class="gl-text-left">{{ errorContent.description }}</p>
+
+ <p class="gl-text-left">{{ s__('ClusterIntegration|Troubleshooting tips:') }}</p>
+
+ <ul class="gl-text-left">
+ <li v-for="tip in errorContent.troubleshootingTips" :key="tip">
+ {{ tip }}
+ </li>
+ </ul>
+ </gl-popover>
+ </div>
+</template>
diff --git a/app/assets/javascripts/clusters_list/constants.js b/app/assets/javascripts/clusters_list/constants.js
index 3e8ef3151a6..f39678b73dc 100644
--- a/app/assets/javascripts/clusters_list/constants.js
+++ b/app/assets/javascripts/clusters_list/constants.js
@@ -1,4 +1,45 @@
-import { __ } from '~/locale';
+import { __, s__ } from '~/locale';
+
+export const CLUSTER_ERRORS = {
+ default: {
+ tableText: s__('ClusterIntegration|Unknown Error'),
+ title: s__('ClusterIntegration|Unknown Error'),
+ description: s__(
+ 'ClusterIntegration|An unknown error occurred while attempting to connect to Kubernetes.',
+ ),
+ troubleshootingTips: [
+ s__('ClusterIntegration|Check your cluster status'),
+ s__('ClusterIntegration|Make sure your API endpoint is correct'),
+ s__(
+ 'ClusterIntegration|Node calculations use the Kubernetes Metrics API. Make sure your cluster has metrics installed',
+ ),
+ ],
+ },
+ authentication_error: {
+ tableText: s__('ClusterIntegration|Unable to Authenticate'),
+ title: s__('ClusterIntegration|Authentication Error'),
+ description: s__('ClusterIntegration|GitLab failed to authenticate.'),
+ troubleshootingTips: [
+ s__('ClusterIntegration|Check your token'),
+ s__('ClusterIntegration|Check your CA certificate'),
+ ],
+ },
+ connection_error: {
+ tableText: s__('ClusterIntegration|Unable to Connect'),
+ title: s__('ClusterIntegration|Connection Error'),
+ description: s__('ClusterIntegration|GitLab failed to connect to the cluster.'),
+ troubleshootingTips: [
+ s__('ClusterIntegration|Check your cluster status'),
+ s__('ClusterIntegration|Make sure your API endpoint is correct'),
+ ],
+ },
+ http_error: {
+ tableText: s__('ClusterIntegration|Unable to Connect'),
+ title: s__('ClusterIntegration|HTTP Error'),
+ description: s__('ClusterIntegration|There was an HTTP error when connecting to your cluster.'),
+ troubleshootingTips: [s__('ClusterIntegration|Check your cluster status')],
+ },
+};
export const CLUSTER_TYPES = {
project_type: __('Project'),
diff --git a/app/assets/javascripts/clusters_list/index.js b/app/assets/javascripts/clusters_list/index.js
index 51ad8769250..daa82892773 100644
--- a/app/assets/javascripts/clusters_list/index.js
+++ b/app/assets/javascripts/clusters_list/index.js
@@ -1,20 +1,6 @@
import Vue from 'vue';
-import Clusters from './components/clusters.vue';
-import { createStore } from './store';
+import loadClusters from './load_clusters';
export default () => {
- const entryPoint = document.querySelector('#js-clusters-list-app');
-
- if (!entryPoint) {
- return;
- }
-
- // eslint-disable-next-line no-new
- new Vue({
- el: '#js-clusters-list-app',
- store: createStore(entryPoint.dataset),
- render(createElement) {
- return createElement(Clusters);
- },
- });
+ loadClusters(Vue);
};
diff --git a/app/assets/javascripts/clusters_list/load_clusters.js b/app/assets/javascripts/clusters_list/load_clusters.js
new file mode 100644
index 00000000000..98bc5880898
--- /dev/null
+++ b/app/assets/javascripts/clusters_list/load_clusters.js
@@ -0,0 +1,18 @@
+import Clusters from './components/clusters.vue';
+import { createStore } from './store';
+
+export default Vue => {
+ const el = document.querySelector('#js-clusters-list-app');
+
+ if (!el) {
+ return null;
+ }
+
+ return new Vue({
+ el,
+ store: createStore(el.dataset),
+ render(createElement) {
+ return createElement(Clusters);
+ },
+ });
+};
diff --git a/app/assets/javascripts/clusters_list/store/actions.js b/app/assets/javascripts/clusters_list/store/actions.js
index ff711877621..1be82988db0 100644
--- a/app/assets/javascripts/clusters_list/store/actions.js
+++ b/app/assets/javascripts/clusters_list/store/actions.js
@@ -1,4 +1,4 @@
-import * as Sentry from '@sentry/browser';
+import * as Sentry from '~/sentry/wrapper';
import Poll from '~/lib/utils/poll';
import axios from '~/lib/utils/axios_utils';
import { deprecatedCreateFlash as flash } from '~/flash';
diff --git a/app/assets/javascripts/code_navigation/index.js b/app/assets/javascripts/code_navigation/index.js
index 362c26ae065..fa5835245bc 100644
--- a/app/assets/javascripts/code_navigation/index.js
+++ b/app/assets/javascripts/code_navigation/index.js
@@ -1,13 +1,17 @@
import Vue from 'vue';
import Vuex from 'vuex';
-import store from './store';
+import createStore from './store';
import App from './components/app.vue';
-Vue.use(Vuex);
-
export default initialData => {
const el = document.getElementById('js-code-navigation');
+ if (!el) return null;
+
+ Vue.use(Vuex);
+
+ const store = createStore();
+
store.dispatch('setInitialData', initialData);
return new Vue({
diff --git a/app/assets/javascripts/code_navigation/store/index.js b/app/assets/javascripts/code_navigation/store/index.js
index fe48f3ac7f5..9b60fc337fe 100644
--- a/app/assets/javascripts/code_navigation/store/index.js
+++ b/app/assets/javascripts/code_navigation/store/index.js
@@ -3,8 +3,9 @@ import createState from './state';
import actions from './actions';
import mutations from './mutations';
-export default new Vuex.Store({
- actions,
- mutations,
- state: createState(),
-});
+export default () =>
+ new Vuex.Store({
+ actions,
+ mutations,
+ state: createState(),
+ });
diff --git a/app/assets/javascripts/commit/pipelines/pipelines_bundle.js b/app/assets/javascripts/commit/pipelines/pipelines_bundle.js
index 340a93e4e66..c8168afbcb0 100644
--- a/app/assets/javascripts/commit/pipelines/pipelines_bundle.js
+++ b/app/assets/javascripts/commit/pipelines/pipelines_bundle.js
@@ -3,9 +3,10 @@ import commitPipelinesTable from './pipelines_table.vue';
/**
* Used in:
- * - Commit details View > Pipelines Tab > Pipelines Table.
- * - Merge Request details View > Pipelines Tab > Pipelines Table.
- * - New Merge Request View > Pipelines Tab > Pipelines Table.
+ * - Project Pipelines List (projects:pipelines:index)
+ * - Commit details View > Pipelines Tab > Pipelines Table (projects:commit:pipelines)
+ * - Merge Request details View > Pipelines Tab > Pipelines Table (projects:merge_requests:show)
+ * - New Merge Request View > Pipelines Tab > Pipelines Table (projects:merge_requests:creations:new)
*/
const CommitPipelinesTable = Vue.extend(commitPipelinesTable);
diff --git a/app/assets/javascripts/commit/pipelines/pipelines_table.vue b/app/assets/javascripts/commit/pipelines/pipelines_table.vue
index 2f4118c1717..fe32868e6d8 100644
--- a/app/assets/javascripts/commit/pipelines/pipelines_table.vue
+++ b/app/assets/javascripts/commit/pipelines/pipelines_table.vue
@@ -1,6 +1,5 @@
<script>
import { GlButton, GlLoadingIcon, GlModal, GlLink } from '@gitlab/ui';
-import { GlBreakpointInstance as bp } from '@gitlab/ui/dist/utils';
import PipelinesService from '~/pipelines/services/pipelines_service';
import PipelineStore from '~/pipelines/stores/pipelines_store';
import pipelinesMixin from '~/pipelines/mixins/pipelines';
@@ -126,16 +125,6 @@ export default {
(latest.flags.detached_merge_request_pipeline || latest.flags.merge_request_pipeline)
);
},
- /**
- * When we are on Desktop and the button is visible
- * we need to add a negative margin to the table
- * to make it inline with the button
- *
- * @returns {Boolean}
- */
- shouldAddNegativeMargin() {
- return this.canRenderPipelineButton && bp.isDesktop();
- },
},
created() {
this.service = new PipelinesService(this.endpoint);
@@ -204,66 +193,77 @@ export default {
"
/>
- <div v-else-if="shouldRenderTable" class="table-holder">
- <div v-if="canRenderPipelineButton" class="nav justify-content-end">
- <gl-button
- variant="success"
- class="js-run-mr-pipeline gl-mt-3 btn-wide-on-xs"
- :disabled="state.isRunningMergeRequestPipeline"
- @click="tryRunPipeline"
- >
- <gl-loading-icon v-if="state.isRunningMergeRequestPipeline" inline />
- {{ s__('Pipelines|Run Pipeline') }}
- </gl-button>
-
- <gl-modal
- :id="modalId"
- ref="modal"
- :modal-id="modalId"
- :title="s__('Pipelines|Are you sure you want to run this pipeline?')"
- :ok-title="s__('Pipelines|Run Pipeline')"
- ok-variant="danger"
- @ok="onClickRunPipeline"
- >
- <p>
- {{
- s__(
- 'Pipelines|This pipeline will run code originating from a forked project merge request. This means that the code can potentially have security considerations like exposing CI variables.',
- )
- }}
- </p>
- <p>
- {{
- s__(
- "Pipelines|It is recommended the code is reviewed thoroughly before running this pipeline with the parent project's CI resource.",
- )
- }}
- </p>
- <p>
- {{
- s__(
- 'Pipelines|If you are unsure, please ask a project maintainer to review it for you.',
- )
- }}
- </p>
- <gl-link
- href="/help/ci/merge_request_pipelines/index.html#run-pipelines-in-the-parent-project-for-merge-requests-from-a-forked-project"
- target="_blank"
- >
- {{ s__('Pipelines|More Information') }}
- </gl-link>
- </gl-modal>
- </div>
+ <div v-else-if="shouldRenderTable">
+ <gl-button
+ v-if="canRenderPipelineButton"
+ block
+ class="gl-mt-3 gl-mb-0 gl-display-md-none"
+ variant="success"
+ data-testid="run_pipeline_button_mobile"
+ :loading="state.isRunningMergeRequestPipeline"
+ @click="tryRunPipeline"
+ >
+ {{ s__('Pipelines|Run Pipeline') }}
+ </gl-button>
<pipelines-table-component
:pipelines="state.pipelines"
:update-graph-dropdown="updateGraphDropdown"
:auto-devops-help-path="autoDevopsHelpPath"
:view-type="viewType"
- :class="{ 'negative-margin-top': shouldAddNegativeMargin }"
- />
+ >
+ <template #table-header-actions>
+ <div v-if="canRenderPipelineButton" class="gl-text-right">
+ <gl-button
+ variant="success"
+ data-testid="run_pipeline_button"
+ :loading="state.isRunningMergeRequestPipeline"
+ @click="tryRunPipeline"
+ >
+ {{ s__('Pipelines|Run Pipeline') }}
+ </gl-button>
+ </div>
+ </template>
+ </pipelines-table-component>
</div>
+ <gl-modal
+ v-if="canRenderPipelineButton"
+ :id="modalId"
+ ref="modal"
+ :modal-id="modalId"
+ :title="s__('Pipelines|Are you sure you want to run this pipeline?')"
+ :ok-title="s__('Pipelines|Run Pipeline')"
+ ok-variant="danger"
+ @ok="onClickRunPipeline"
+ >
+ <p>
+ {{
+ s__(
+ 'Pipelines|This pipeline will run code originating from a forked project merge request. This means that the code can potentially have security considerations like exposing CI variables.',
+ )
+ }}
+ </p>
+ <p>
+ {{
+ s__(
+ "Pipelines|It is recommended the code is reviewed thoroughly before running this pipeline with the parent project's CI resource.",
+ )
+ }}
+ </p>
+ <p>
+ {{
+ s__('Pipelines|If you are unsure, please ask a project maintainer to review it for you.')
+ }}
+ </p>
+ <gl-link
+ href="/help/ci/merge_request_pipelines/index.html#run-pipelines-in-the-parent-project-for-merge-requests-from-a-forked-project"
+ target="_blank"
+ >
+ {{ s__('Pipelines|More Information') }}
+ </gl-link>
+ </gl-modal>
+
<table-pagination
v-if="shouldRenderPagination"
:change="onChangePage"
diff --git a/app/assets/javascripts/commons/index.js b/app/assets/javascripts/commons/index.js
index e0d012cef23..77c85d85e27 100644
--- a/app/assets/javascripts/commons/index.js
+++ b/app/assets/javascripts/commons/index.js
@@ -1,5 +1,4 @@
import './polyfills';
-import './jquery';
import './bootstrap';
import './vue';
import '../lib/utils/axios_utils';
diff --git a/app/assets/javascripts/commons/jquery.js b/app/assets/javascripts/commons/jquery.js
deleted file mode 100644
index 334f95bb27f..00000000000
--- a/app/assets/javascripts/commons/jquery.js
+++ /dev/null
@@ -1,4 +0,0 @@
-import 'jquery';
-
-// common jQuery plugins
-import 'jquery-ujs';
diff --git a/app/assets/javascripts/confidential_merge_request/components/dropdown.vue b/app/assets/javascripts/confidential_merge_request/components/dropdown.vue
index 5b4bdca46e4..6bb654a434f 100644
--- a/app/assets/javascripts/confidential_merge_request/components/dropdown.vue
+++ b/app/assets/javascripts/confidential_merge_request/components/dropdown.vue
@@ -1,12 +1,11 @@
<script>
-import { GlDeprecatedDropdown, GlDeprecatedDropdownItem, GlIcon } from '@gitlab/ui';
+import { GlDropdown, GlDropdownItem } from '@gitlab/ui';
import { __ } from '~/locale';
export default {
components: {
- GlDeprecatedDropdown,
- GlDeprecatedDropdownItem,
- GlIcon,
+ GlDropdown,
+ GlDropdownItem,
},
props: {
projects: {
@@ -37,25 +36,15 @@ export default {
</script>
<template>
- <gl-deprecated-dropdown toggle-class="d-flex align-items-center w-100" class="w-100">
- <template #button-content>
- <span class="str-truncated-100 mr-2">
- <gl-icon name="lock" />
- {{ dropdownText }}
- </span>
- <gl-icon name="chevron-down" class="ml-auto" />
- </template>
- <gl-deprecated-dropdown-item
+ <gl-dropdown block icon="lock" :text="dropdownText">
+ <gl-dropdown-item
v-for="project in projects"
:key="project.id"
+ :is-check-item="true"
+ :is-checked="project.id === selectedProject.id"
@click="selectProject(project)"
>
- <gl-icon
- name="mobile-issue-close"
- :class="{ icon: project.id !== selectedProject.id }"
- class="js-active-project-check"
- />
- <span class="ml-1">{{ project.name }}</span>
- </gl-deprecated-dropdown-item>
- </gl-deprecated-dropdown>
+ {{ project.name }}
+ </gl-dropdown-item>
+ </gl-dropdown>
</template>
diff --git a/app/assets/javascripts/confirm_danger_modal.js b/app/assets/javascripts/confirm_danger_modal.js
index 262d501bfba..7321e4d18cc 100644
--- a/app/assets/javascripts/confirm_danger_modal.js
+++ b/app/assets/javascripts/confirm_danger_modal.js
@@ -1,4 +1,5 @@
import $ from 'jquery';
+import { Rails } from '~/lib/utils/rails_ujs';
import { rstrip } from './lib/utils/common_utils';
function openConfirmDangerModal($form, $modal, text) {
@@ -21,9 +22,16 @@ function openConfirmDangerModal($form, $modal, text) {
$submit.disable();
}
});
+
$('.js-confirm-danger-submit', $modal)
.off('click')
- .on('click', () => $form.submit());
+ .on('click', () => {
+ if ($form.data('remote')) {
+ Rails.fire($form[0], 'submit');
+ } else {
+ $form.submit();
+ }
+ });
}
function getModal($btn) {
diff --git a/app/assets/javascripts/confirm_modal.js b/app/assets/javascripts/confirm_modal.js
index 4b4fdf03873..bf2ea3ce38a 100644
--- a/app/assets/javascripts/confirm_modal.js
+++ b/app/assets/javascripts/confirm_modal.js
@@ -1,14 +1,16 @@
import Vue from 'vue';
import ConfirmModal from '~/vue_shared/components/confirm_modal.vue';
-const mountConfirmModal = () => {
- return new Vue({
+const mountConfirmModal = optionalProps =>
+ new Vue({
render(h) {
return h(ConfirmModal, {
- props: { selector: '.js-confirm-modal-button' },
+ props: {
+ selector: '.js-confirm-modal-button',
+ ...optionalProps,
+ },
});
},
}).$mount();
-};
-export default () => mountConfirmModal();
+export default (optionalProps = {}) => mountConfirmModal(optionalProps);
diff --git a/app/assets/javascripts/create_cluster/eks_cluster/components/create_eks_cluster.vue b/app/assets/javascripts/create_cluster/eks_cluster/components/create_eks_cluster.vue
index 3f7c2204b9f..eb195ad2b30 100644
--- a/app/assets/javascripts/create_cluster/eks_cluster/components/create_eks_cluster.vue
+++ b/app/assets/javascripts/create_cluster/eks_cluster/components/create_eks_cluster.vue
@@ -13,6 +13,10 @@ export default {
type: String,
required: true,
},
+ namespacePerEnvironmentHelpPath: {
+ type: String,
+ required: true,
+ },
kubernetesIntegrationHelpPath: {
type: String,
required: true,
@@ -40,6 +44,7 @@ export default {
<eks-cluster-configuration-form
v-if="hasCredentials"
:gitlab-managed-cluster-help-path="gitlabManagedClusterHelpPath"
+ :namespace-per-environment-help-path="namespacePerEnvironmentHelpPath"
:kubernetes-integration-help-path="kubernetesIntegrationHelpPath"
:external-link-icon="externalLinkIcon"
/>
diff --git a/app/assets/javascripts/create_cluster/eks_cluster/components/eks_cluster_configuration_form.vue b/app/assets/javascripts/create_cluster/eks_cluster/components/eks_cluster_configuration_form.vue
index a653e228e3f..d403f370f9d 100644
--- a/app/assets/javascripts/create_cluster/eks_cluster/components/eks_cluster_configuration_form.vue
+++ b/app/assets/javascripts/create_cluster/eks_cluster/components/eks_cluster_configuration_form.vue
@@ -1,9 +1,7 @@
<script>
-/* eslint-disable vue/no-v-html */
import { createNamespacedHelpers, mapState, mapActions, mapGetters } from 'vuex';
-import { escape } from 'lodash';
-import { GlFormInput, GlFormCheckbox } from '@gitlab/ui';
-import { sprintf, s__ } from '~/locale';
+import { GlFormInput, GlFormCheckbox, GlIcon, GlLink, GlSprintf } from '@gitlab/ui';
+import { s__ } from '~/locale';
import ClusterFormDropdown from '~/create_cluster/components/cluster_form_dropdown.vue';
import { KUBERNETES_VERSIONS } from '../constants';
import LoadingButton from '~/vue_shared/components/loading_button.vue';
@@ -28,8 +26,11 @@ const { mapState: mapInstanceTypesState } = createNamespacedHelpers('instanceTyp
export default {
components: {
ClusterFormDropdown,
- GlFormInput,
GlFormCheckbox,
+ GlFormInput,
+ GlIcon,
+ GlLink,
+ GlSprintf,
LoadingButton,
},
props: {
@@ -37,6 +38,10 @@ export default {
type: String,
required: true,
},
+ namespacePerEnvironmentHelpPath: {
+ type: String,
+ required: true,
+ },
kubernetesIntegrationHelpPath: {
type: String,
required: true,
@@ -46,6 +51,49 @@ export default {
required: true,
},
},
+ i18n: {
+ kubernetesIntegrationHelpText: s__(
+ 'ClusterIntegration|Read our %{linkStart}help page%{linkEnd} on Kubernetes cluster integration.',
+ ),
+ roleDropdownHelpText: s__(
+ 'ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{linkStart}Amazon Web Services%{linkEnd}.',
+ ),
+ roleDropdownHelpPath:
+ 'https://docs.aws.amazon.com/eks/latest/userguide/service_IAM_role.html#create-service-role',
+ regionsDropdownHelpText: s__(
+ 'ClusterIntegration|Learn more about %{linkStart}Regions%{linkEnd}.',
+ ),
+ regionsDropdownHelpPath:
+ 'https://aws.amazon.com/about-aws/global-infrastructure/regional-product-services/',
+ keyPairDropdownHelpText: s__(
+ 'ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{linkStart}Amazon Web Services%{linkEnd}.',
+ ),
+ keyPairDropdownHelpPath:
+ 'https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-key-pairs.html#having-ec2-create-your-key-pair',
+ vpcDropdownHelpText: s__(
+ 'ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{linkStart}Amazon Web Services %{linkEnd}.',
+ ),
+ vpcDropdownHelpPath:
+ 'https://docs.aws.amazon.com/eks/latest/userguide/getting-started-console.html#vpc-create',
+ subnetDropdownHelpText: s__(
+ 'ClusterIntegration|Choose the %{linkStart}subnets %{linkEnd} in your VPC where your worker nodes will run.',
+ ),
+ subnetDropdownHelpPath: 'https://console.aws.amazon.com/vpc/home?#subnets',
+ securityGroupDropdownHelpText: s__(
+ 'ClusterIntegration|Choose the %{linkStart}security group %{linkEnd} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets.',
+ ),
+ securityGroupDropdownHelpPath: 'https://console.aws.amazon.com/vpc/home?#securityGroups',
+ instanceTypesDropdownHelpText: s__(
+ 'ClusterIntegration|Choose the worker node %{linkStart}instance type%{linkEnd}.',
+ ),
+ instanceTypesDropdownHelpPath: 'https://aws.amazon.com/ec2/instance-types',
+ gitlabManagedClusterHelpText: s__(
+ 'ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{linkStart}More information%{linkEnd}',
+ ),
+ namespacePerEnvironmentHelpText: s__(
+ 'ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared. %{linkStart}More information%{linkEnd}',
+ ),
+ },
computed: {
...mapState([
'clusterName',
@@ -60,6 +108,7 @@ export default {
'selectedInstanceType',
'nodeCount',
'gitlabManagedCluster',
+ 'namespacePerEnvironment',
'isCreatingCluster',
]),
...mapGetters(['subnetValid']),
@@ -137,90 +186,6 @@ export default {
? s__('ClusterIntegration|Creating Kubernetes cluster')
: s__('ClusterIntegration|Create Kubernetes cluster');
},
- kubernetesIntegrationHelpText() {
- const escapedUrl = escape(this.kubernetesIntegrationHelpPath);
-
- return sprintf(
- s__(
- 'ClusterIntegration|Read our %{link_start}help page%{link_end} on Kubernetes cluster integration.',
- ),
- {
- link_start: `<a href="${escapedUrl}" target="_blank" rel="noopener noreferrer">`,
- link_end: '</a>',
- },
- false,
- );
- },
- roleDropdownHelpText() {
- return sprintf(
- s__(
- 'ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}.',
- ),
- {
- startLink:
- '<a href="https://docs.aws.amazon.com/eks/latest/userguide/service_IAM_role.html#create-service-role" target="_blank" rel="noopener noreferrer">',
- externalLinkIcon: this.externalLinkIcon,
- endLink: '</a>',
- },
- false,
- );
- },
- regionsDropdownHelpText() {
- return sprintf(
- s__(
- 'ClusterIntegration|Learn more about %{startLink}Regions %{externalLinkIcon}%{endLink}.',
- ),
- {
- startLink:
- '<a href="https://aws.amazon.com/about-aws/global-infrastructure/regional-product-services/" target="_blank" rel="noopener noreferrer">',
- externalLinkIcon: this.externalLinkIcon,
- endLink: '</a>',
- },
- false,
- );
- },
- keyPairDropdownHelpText() {
- return sprintf(
- s__(
- 'ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}.',
- ),
- {
- startLink:
- '<a href="https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-key-pairs.html#having-ec2-create-your-key-pair" target="_blank" rel="noopener noreferrer">',
- externalLinkIcon: this.externalLinkIcon,
- endLink: '</a>',
- },
- false,
- );
- },
- vpcDropdownHelpText() {
- return sprintf(
- s__(
- 'ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}.',
- ),
- {
- startLink:
- '<a href="https://docs.aws.amazon.com/eks/latest/userguide/getting-started-console.html#vpc-create" target="_blank" rel="noopener noreferrer">',
- externalLinkIcon: this.externalLinkIcon,
- endLink: '</a>',
- },
- false,
- );
- },
- subnetDropdownHelpText() {
- return sprintf(
- s__(
- 'ClusterIntegration|Choose the %{startLink}subnets %{externalLinkIcon} %{endLink} in your VPC where your worker nodes will run.',
- ),
- {
- startLink:
- '<a href="https://console.aws.amazon.com/vpc/home?#subnets" target="_blank" rel="noopener noreferrer">',
- externalLinkIcon: this.externalLinkIcon,
- endLink: '</a>',
- },
- false,
- );
- },
subnetValidationErrorText() {
if (this.loadingSubnetsError) {
return s__('ClusterIntegration|Could not load subnets for the selected VPC');
@@ -228,48 +193,6 @@ export default {
return s__('ClusterIntegration|You should select at least two subnets');
},
- securityGroupDropdownHelpText() {
- return sprintf(
- s__(
- 'ClusterIntegration|Choose the %{startLink}security group %{externalLinkIcon} %{endLink} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets.',
- ),
- {
- startLink:
- '<a href="https://console.aws.amazon.com/vpc/home?#securityGroups" target="_blank" rel="noopener noreferrer">',
- externalLinkIcon: this.externalLinkIcon,
- endLink: '</a>',
- },
- false,
- );
- },
- instanceTypesDropdownHelpText() {
- return sprintf(
- s__(
- 'ClusterIntegration|Choose the worker node %{startLink}instance type %{externalLinkIcon} %{endLink}.',
- ),
- {
- startLink:
- '<a href="https://aws.amazon.com/ec2/instance-types" target="_blank" rel="noopener noreferrer">',
- externalLinkIcon: this.externalLinkIcon,
- endLink: '</a>',
- },
- false,
- );
- },
- gitlabManagedHelpText() {
- const escapedUrl = escape(this.gitlabManagedClusterHelpPath);
-
- return sprintf(
- s__(
- 'ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{startLink}More information%{endLink}',
- ),
- {
- startLink: `<a href="${escapedUrl}" target="_blank" rel="noopener noreferrer">`,
- endLink: '</a>',
- },
- false,
- );
- },
},
mounted() {
this.fetchRegions();
@@ -290,6 +213,7 @@ export default {
'setInstanceType',
'setNodeCount',
'setGitlabManagedCluster',
+ 'setNamespacePerEnvironment',
]),
...mapRegionsActions({ fetchRegions: 'fetchItems' }),
...mapVpcActions({ fetchVpcs: 'fetchItems' }),
@@ -321,7 +245,15 @@ export default {
<h4>
{{ s__('ClusterIntegration|Enter the details for your Amazon EKS Kubernetes cluster') }}
</h4>
- <div class="mb-3" v-html="kubernetesIntegrationHelpText"></div>
+ <div class="mb-3">
+ <gl-sprintf :message="$options.i18n.kubernetesIntegrationHelpText">
+ <template #link="{ content }">
+ <gl-link :href="kubernetesIntegrationHelpPath">
+ {{ content }}
+ </gl-link>
+ </template>
+ </gl-sprintf>
+ </div>
<div class="form-group">
<label class="label-bold" for="eks-cluster-name">{{
s__('ClusterIntegration|Kubernetes cluster name')
@@ -371,7 +303,16 @@ export default {
:error-message="s__('ClusterIntegration|Could not load IAM roles')"
@input="setRole({ role: $event })"
/>
- <p class="form-text text-muted" v-html="roleDropdownHelpText"></p>
+ <p class="form-text text-muted">
+ <gl-sprintf :message="$options.i18n.roleDropdownHelpText">
+ <template #link="{ content }">
+ <gl-link :href="$options.i18n.roleDropdownHelpPath" target="_blank">
+ {{ content }}
+ <gl-icon name="external-link" class="gl-vertical-align-middle" />
+ </gl-link>
+ </template>
+ </gl-sprintf>
+ </p>
</div>
<div class="form-group">
<label class="label-bold" for="eks-role">{{ s__('ClusterIntegration|Region') }}</label>
@@ -389,7 +330,16 @@ export default {
:error-message="s__('ClusterIntegration|Could not load regions from your AWS account')"
@input="setRegionAndFetchVpcsAndKeyPairs($event)"
/>
- <p class="form-text text-muted" v-html="regionsDropdownHelpText"></p>
+ <p class="form-text text-muted">
+ <gl-sprintf :message="$options.i18n.regionsDropdownHelpText">
+ <template #link="{ content }">
+ <gl-link :href="$options.i18n.regionsDropdownHelpPath" target="_blank">
+ {{ content }}
+ <gl-icon name="external-link" class="gl-vertical-align-middle" />
+ </gl-link>
+ </template>
+ </gl-sprintf>
+ </p>
</div>
<div class="form-group">
<label class="label-bold" for="eks-key-pair">{{
@@ -411,7 +361,16 @@ export default {
:error-message="s__('ClusterIntegration|Could not load Key Pairs')"
@input="setKeyPair({ keyPair: $event })"
/>
- <p class="form-text text-muted" v-html="keyPairDropdownHelpText"></p>
+ <p class="form-text text-muted">
+ <gl-sprintf :message="$options.i18n.keyPairDropdownHelpText">
+ <template #link="{ content }">
+ <gl-link :href="$options.i18n.keyPairDropdownHelpPath" target="_blank">
+ {{ content }}
+ <gl-icon name="external-link" class="gl-vertical-align-middle" />
+ </gl-link>
+ </template>
+ </gl-sprintf>
+ </p>
</div>
<div class="form-group">
<label class="label-bold" for="eks-vpc">{{ s__('ClusterIntegration|VPC') }}</label>
@@ -431,7 +390,16 @@ export default {
:error-message="s__('ClusterIntegration|Could not load VPCs for the selected region')"
@input="setVpcAndFetchSubnets($event)"
/>
- <p class="form-text text-muted" v-html="vpcDropdownHelpText"></p>
+ <p class="form-text text-muted">
+ <gl-sprintf :message="$options.i18n.vpcDropdownHelpText">
+ <template #link="{ content }">
+ <gl-link :href="$options.i18n.vpcDropdownHelpPath" target="_blank">
+ {{ content }}
+ <gl-icon name="external-link" class="gl-vertical-align-middle" />
+ </gl-link>
+ </template>
+ </gl-sprintf>
+ </p>
</div>
<div class="form-group">
<label class="label-bold" for="eks-role">{{ s__('ClusterIntegration|Subnets') }}</label>
@@ -452,7 +420,16 @@ export default {
:error-message="subnetValidationErrorText"
@input="setSubnet({ subnet: $event })"
/>
- <p class="form-text text-muted" v-html="subnetDropdownHelpText"></p>
+ <p class="form-text text-muted">
+ <gl-sprintf :message="$options.i18n.subnetDropdownHelpText">
+ <template #link="{ content }">
+ <gl-link :href="$options.i18n.subnetDropdownHelpPath" target="_blank">
+ {{ content }}
+ <gl-icon name="external-link" class="gl-vertical-align-middle" />
+ </gl-link>
+ </template>
+ </gl-sprintf>
+ </p>
</div>
<div class="form-group">
<label class="label-bold" for="eks-security-group">{{
@@ -476,7 +453,16 @@ export default {
"
@input="setSecurityGroup({ securityGroup: $event })"
/>
- <p class="form-text text-muted" v-html="securityGroupDropdownHelpText"></p>
+ <p class="form-text text-muted">
+ <gl-sprintf :message="$options.i18n.securityGroupDropdownHelpText">
+ <template #link="{ content }">
+ <gl-link :href="$options.i18n.securityGroupDropdownHelpPath" target="_blank">
+ {{ content }}
+ <gl-icon name="external-link" class="gl-vertical-align-middle" />
+ </gl-link>
+ </template>
+ </gl-sprintf>
+ </p>
</div>
<div class="form-group">
<label class="label-bold" for="eks-instance-type">{{
@@ -496,7 +482,16 @@ export default {
:error-message="s__('ClusterIntegration|Could not load instance types')"
@input="setInstanceType({ instanceType: $event })"
/>
- <p class="form-text text-muted" v-html="instanceTypesDropdownHelpText"></p>
+ <p class="form-text text-muted">
+ <gl-sprintf :message="$options.i18n.instanceTypesDropdownHelpText">
+ <template #link="{ content }">
+ <gl-link :href="$options.i18n.instanceTypesDropdownHelpPath" target="_blank">
+ {{ content }}
+ <gl-icon name="external-link" class="gl-vertical-align-middle" />
+ </gl-link>
+ </template>
+ </gl-sprintf>
+ </p>
</div>
<div class="form-group">
<label class="label-bold" for="eks-node-count">{{
@@ -517,7 +512,31 @@ export default {
@input="setGitlabManagedCluster({ gitlabManagedCluster: $event })"
>{{ s__('ClusterIntegration|GitLab-managed cluster') }}</gl-form-checkbox
>
- <p class="form-text text-muted" v-html="gitlabManagedHelpText"></p>
+ <p class="form text text-muted">
+ <gl-sprintf :message="$options.i18n.gitlabManagedClusterHelpText">
+ <template #link="{ content }">
+ <gl-link :href="gitlabManagedClusterHelpPath" target="_blank">
+ {{ content }}
+ </gl-link>
+ </template>
+ </gl-sprintf>
+ </p>
+ </div>
+ <div class="form-group">
+ <gl-form-checkbox
+ :checked="namespacePerEnvironment"
+ @input="setNamespacePerEnvironment({ namespacePerEnvironment: $event })"
+ >{{ s__('ClusterIntegration|Namespace per environment') }}</gl-form-checkbox
+ >
+ <p class="form text text-muted">
+ <gl-sprintf :message="$options.i18n.namespacePerEnvironmentHelpText">
+ <template #link="{ content }">
+ <gl-link :href="namespacePerEnvironmentHelpPath" target="_blank">
+ {{ content }}
+ </gl-link>
+ </template>
+ </gl-sprintf>
+ </p>
</div>
<div class="form-group">
<loading-button
diff --git a/app/assets/javascripts/create_cluster/eks_cluster/index.js b/app/assets/javascripts/create_cluster/eks_cluster/index.js
index fb993a7aa59..6d1034b4a72 100644
--- a/app/assets/javascripts/create_cluster/eks_cluster/index.js
+++ b/app/assets/javascripts/create_cluster/eks_cluster/index.js
@@ -9,6 +9,7 @@ Vue.use(Vuex);
export default el => {
const {
gitlabManagedClusterHelpPath,
+ namespacePerEnvironmentHelpPath,
kubernetesIntegrationHelpPath,
accountAndExternalIdsHelpPath,
createRoleArnHelpPath,
@@ -42,6 +43,7 @@ export default el => {
return createElement('create-eks-cluster', {
props: {
gitlabManagedClusterHelpPath,
+ namespacePerEnvironmentHelpPath,
kubernetesIntegrationHelpPath,
accountAndExternalIdsHelpPath,
createRoleArnHelpPath,
diff --git a/app/assets/javascripts/create_cluster/eks_cluster/store/actions.js b/app/assets/javascripts/create_cluster/eks_cluster/store/actions.js
index 5abff3c7831..48c85ff627f 100644
--- a/app/assets/javascripts/create_cluster/eks_cluster/store/actions.js
+++ b/app/assets/javascripts/create_cluster/eks_cluster/store/actions.js
@@ -55,6 +55,7 @@ export const createCluster = ({ dispatch, state }) => {
name: state.clusterName,
environment_scope: state.environmentScope,
managed: state.gitlabManagedCluster,
+ namespace_per_environment: state.namespacePerEnvironment,
provider_aws_attributes: {
kubernetes_version: state.kubernetesVersion,
region: state.selectedRegion,
@@ -114,6 +115,10 @@ export const setGitlabManagedCluster = ({ commit }, payload) => {
commit(types.SET_GITLAB_MANAGED_CLUSTER, payload);
};
+export const setNamespacePerEnvironment = ({ commit }, payload) => {
+ commit(types.SET_NAMESPACE_PER_ENVIRONMENT, payload);
+};
+
export const setInstanceType = ({ commit }, payload) => {
commit(types.SET_INSTANCE_TYPE, payload);
};
diff --git a/app/assets/javascripts/create_cluster/eks_cluster/store/mutation_types.js b/app/assets/javascripts/create_cluster/eks_cluster/store/mutation_types.js
index 9dee6abae5f..4a48195a27b 100644
--- a/app/assets/javascripts/create_cluster/eks_cluster/store/mutation_types.js
+++ b/app/assets/javascripts/create_cluster/eks_cluster/store/mutation_types.js
@@ -10,6 +10,7 @@ export const SET_SECURITY_GROUP = 'SET_SECURITY_GROUP';
export const SET_INSTANCE_TYPE = 'SET_INSTANCE_TYPE';
export const SET_NODE_COUNT = 'SET_NODE_COUNT';
export const SET_GITLAB_MANAGED_CLUSTER = 'SET_GITLAB_MANAGED_CLUSTER';
+export const SET_NAMESPACE_PER_ENVIRONMENT = 'SET_NAMESPACE_PER_ENVIRONMENT';
export const REQUEST_CREATE_ROLE = 'REQUEST_CREATE_ROLE';
export const CREATE_ROLE_SUCCESS = 'CREATE_ROLE_SUCCESS';
export const CREATE_ROLE_ERROR = 'CREATE_ROLE_ERROR';
diff --git a/app/assets/javascripts/create_cluster/eks_cluster/store/mutations.js b/app/assets/javascripts/create_cluster/eks_cluster/store/mutations.js
index c331d27d255..f57236e0e31 100644
--- a/app/assets/javascripts/create_cluster/eks_cluster/store/mutations.js
+++ b/app/assets/javascripts/create_cluster/eks_cluster/store/mutations.js
@@ -37,6 +37,9 @@ export default {
[types.SET_GITLAB_MANAGED_CLUSTER](state, { gitlabManagedCluster }) {
state.gitlabManagedCluster = gitlabManagedCluster;
},
+ [types.SET_NAMESPACE_PER_ENVIRONMENT](state, { namespacePerEnvironment }) {
+ state.namespacePerEnvironment = namespacePerEnvironment;
+ },
[types.REQUEST_CREATE_ROLE](state) {
state.isCreatingRole = true;
state.createRoleError = null;
diff --git a/app/assets/javascripts/create_cluster/eks_cluster/store/state.js b/app/assets/javascripts/create_cluster/eks_cluster/store/state.js
index ed51e95e434..c957eca1f7a 100644
--- a/app/assets/javascripts/create_cluster/eks_cluster/store/state.js
+++ b/app/assets/javascripts/create_cluster/eks_cluster/store/state.js
@@ -30,4 +30,5 @@ export default () => ({
createClusterError: false,
gitlabManagedCluster: true,
+ namespacePerEnvironment: true,
});
diff --git a/app/assets/javascripts/custom_metrics/components/delete_custom_metric_modal.vue b/app/assets/javascripts/custom_metrics/components/delete_custom_metric_modal.vue
index 34e4aeb290f..7c4117d7e8b 100644
--- a/app/assets/javascripts/custom_metrics/components/delete_custom_metric_modal.vue
+++ b/app/assets/javascripts/custom_metrics/components/delete_custom_metric_modal.vue
@@ -1,11 +1,11 @@
<script>
-import { GlModal, GlModalDirective, GlDeprecatedButton } from '@gitlab/ui';
+import { GlModal, GlModalDirective, GlButton } from '@gitlab/ui';
import { s__ } from '~/locale';
export default {
components: {
GlModal,
- GlDeprecatedButton,
+ GlButton,
},
directives: {
'gl-modal': GlModalDirective,
@@ -33,9 +33,9 @@ export default {
</script>
<template>
<div class="d-inline-block float-right mr-3">
- <gl-deprecated-button v-gl-modal="$options.modalId" variant="danger">
+ <gl-button v-gl-modal="$options.modalId" variant="danger" category="primary">
{{ __('Delete') }}
- </gl-deprecated-button>
+ </gl-button>
<gl-modal
:title="s__('Metrics|Delete metric?')"
:ok-title="s__('Metrics|Delete metric')"
diff --git a/app/assets/javascripts/cycle_analytics/components/limit_warning_component.vue b/app/assets/javascripts/cycle_analytics/components/limit_warning_component.vue
index ff0f352b333..b2c9cd4e597 100644
--- a/app/assets/javascripts/cycle_analytics/components/limit_warning_component.vue
+++ b/app/assets/javascripts/cycle_analytics/components/limit_warning_component.vue
@@ -1,7 +1,10 @@
<script>
-import { GlTooltipDirective } from '@gitlab/ui';
+import { GlIcon, GlTooltipDirective } from '@gitlab/ui';
export default {
+ components: {
+ GlIcon,
+ },
directives: {
GlTooltip: GlTooltipDirective,
},
@@ -15,15 +18,17 @@ export default {
</script>
<template>
<span v-if="count === 50" class="events-info float-right">
- <i
- v-gl-tooltip
- :title="
- n__('Limited to showing %d event at most', 'Limited to showing %d events at most', 50)
- "
- class="fa fa-warning"
+ <gl-icon
+ v-gl-tooltip="{
+ title: n__(
+ 'Limited to showing %d event at most',
+ 'Limited to showing %d events at most',
+ 50,
+ ),
+ }"
+ name="warning"
aria-hidden="true"
- >
- </i>
+ />
{{ n__('Showing %d event', 'Showing %d events', 50) }}
</span>
</template>
diff --git a/app/assets/javascripts/cycle_analytics/components/stage_staging_component.vue b/app/assets/javascripts/cycle_analytics/components/stage_staging_component.vue
index ba2be2e5167..6d8f711c13b 100644
--- a/app/assets/javascripts/cycle_analytics/components/stage_staging_component.vue
+++ b/app/assets/javascripts/cycle_analytics/components/stage_staging_component.vue
@@ -1,8 +1,6 @@
<script>
-/* eslint-disable vue/no-v-html */
-import { GlIcon } from '@gitlab/ui';
+import { GlIcon, GlSafeHtmlDirective as SafeHtml } from '@gitlab/ui';
import userAvatarImage from '../../vue_shared/components/user_avatar/user_avatar_image.vue';
-import iconBranch from '../svg/icon_branch.svg';
import limitWarning from './limit_warning_component.vue';
import totalTime from './total_time_component.vue';
@@ -13,6 +11,9 @@ export default {
limitWarning,
GlIcon,
},
+ directives: {
+ SafeHtml,
+ },
props: {
items: {
type: Array,
@@ -25,11 +26,6 @@ export default {
required: false,
},
},
- computed: {
- iconBranch() {
- return iconBranch;
- },
- },
};
</script>
<template>
@@ -47,7 +43,9 @@ export default {
<a :href="build.url" class="pipeline-id"> #{{ build.id }} </a>
<gl-icon :size="16" name="fork" />
<a :href="build.branch.url" class="ref-name"> {{ build.branch.name }} </a>
- <span class="icon-branch" v-html="iconBranch"> </span>
+ <span class="icon-branch gl-text-gray-400">
+ <gl-icon name="commit" :size="14" />
+ </span>
<a :href="build.commitUrl" class="commit-sha"> {{ build.shortSha }} </a>
</h5>
<span>
diff --git a/app/assets/javascripts/cycle_analytics/components/stage_test_component.vue b/app/assets/javascripts/cycle_analytics/components/stage_test_component.vue
index cd49b3c5222..c165c8cee78 100644
--- a/app/assets/javascripts/cycle_analytics/components/stage_test_component.vue
+++ b/app/assets/javascripts/cycle_analytics/components/stage_test_component.vue
@@ -1,8 +1,5 @@
<script>
-/* eslint-disable vue/no-v-html */
import { GlIcon } from '@gitlab/ui';
-import iconBuildStatus from '../svg/icon_build_status.svg';
-import iconBranch from '../svg/icon_branch.svg';
import limitWarning from './limit_warning_component.vue';
import totalTime from './total_time_component.vue';
@@ -24,14 +21,6 @@ export default {
required: false,
},
},
- computed: {
- iconBuildStatus() {
- return iconBuildStatus;
- },
- iconBranch() {
- return iconBranch;
- },
- },
};
</script>
<template>
@@ -44,12 +33,16 @@ export default {
<li v-for="(build, i) in items" :key="i" class="stage-event-item item-build-component">
<div class="item-details">
<h5 class="item-title">
- <span class="icon-build-status" v-html="iconBuildStatus"> </span>
+ <span class="icon-build-status gl-text-green-500">
+ <gl-icon name="status_success" :size="14" />
+ </span>
<a :href="build.url" class="item-build-name"> {{ build.name }} </a> &middot;
<a :href="build.url" class="pipeline-id"> #{{ build.id }} </a>
<gl-icon :size="16" name="fork" />
<a :href="build.branch.url" class="ref-name"> {{ build.branch.name }} </a>
- <span class="icon-branch" v-html="iconBranch"> </span>
+ <span class="icon-branch gl-text-gray-400">
+ <gl-icon name="commit" :size="14" />
+ </span>
<a :href="build.commitUrl" class="commit-sha"> {{ build.shortSha }} </a>
</h5>
<span>
diff --git a/app/assets/javascripts/cycle_analytics/cycle_analytics_bundle.js b/app/assets/javascripts/cycle_analytics/cycle_analytics_bundle.js
index f6bad5dce41..4cccabca28b 100644
--- a/app/assets/javascripts/cycle_analytics/cycle_analytics_bundle.js
+++ b/app/assets/javascripts/cycle_analytics/cycle_analytics_bundle.js
@@ -36,12 +36,6 @@ export default () => {
'stage-review-component': stageReviewComponent,
'stage-staging-component': stageStagingComponent,
'stage-production-component': stageComponent,
- GroupsDropdownFilter: () =>
- import('ee_component/analytics/shared/components/groups_dropdown_filter.vue'),
- ProjectsDropdownFilter: () =>
- import('ee_component/analytics/shared/components/projects_dropdown_filter.vue'),
- DateRangeDropdown: () =>
- import('ee_component/analytics/shared/components/date_range_dropdown.vue'),
'stage-nav-item': stageNavItem,
},
data() {
diff --git a/app/assets/javascripts/cycle_analytics/svg/icon_branch.svg b/app/assets/javascripts/cycle_analytics/svg/icon_branch.svg
deleted file mode 100644
index 9f547d3d744..00000000000
--- a/app/assets/javascripts/cycle_analytics/svg/icon_branch.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14"><path fill="#8C8C8C" fill-rule="evenodd" d="M9.678 6.722C9.353 5.167 8.053 4 6.5 4S3.647 5.167 3.322 6.722h-2.6c-.397 0-.722.35-.722.778 0 .428.325.778.722.778h2.6C3.647 9.833 4.947 11 6.5 11s2.853-1.167 3.178-2.722h2.6c.397 0 .722-.35.722-.778 0-.428-.325-.778-.722-.778h-2.6zM4.694 7.5c0-1.09.795-1.944 1.806-1.944 1.01 0 1.806.855 1.806 1.944 0 1.09-.795 1.944-1.806 1.944-1.01 0-1.806-.855-1.806-1.944z"/></svg>
diff --git a/app/assets/javascripts/cycle_analytics/svg/icon_build_status.svg b/app/assets/javascripts/cycle_analytics/svg/icon_build_status.svg
deleted file mode 100644
index b932d90618a..00000000000
--- a/app/assets/javascripts/cycle_analytics/svg/icon_build_status.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14"><g fill="#31AF64" fill-rule="evenodd"><path d="M12.5 7c0-3.038-2.462-5.5-5.5-5.5S1.5 3.962 1.5 7s2.462 5.5 5.5 5.5 5.5-2.462 5.5-5.5zM0 7c0-3.866 3.134-7 7-7s7 3.134 7 7-3.134 7-7 7-7-3.134-7-7z"/><path d="M6.28 7.697L5.045 6.464c-.117-.117-.305-.117-.42-.002l-.614.614c-.11.113-.11.303.007.42l1.91 1.91c.19.19.51.197.703.004l.264-.265L9.997 6.04c.108-.107.107-.293-.01-.408l-.612-.614c-.114-.113-.298-.12-.41-.01L6.28 7.7z"/></g></svg>
diff --git a/app/assets/javascripts/cycle_analytics/svg/icon_commit.svg b/app/assets/javascripts/cycle_analytics/svg/icon_commit.svg
deleted file mode 100644
index 6a517756058..00000000000
--- a/app/assets/javascripts/cycle_analytics/svg/icon_commit.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40"><path fill="#8F8F8F" fill-rule="evenodd" d="M28.777 18c-.91-4.008-4.494-7-8.777-7-4.283 0-7.868 2.992-8.777 7H4.01C2.9 18 2 18.895 2 20c0 1.112.9 2 2.01 2h7.213c.91 4.008 4.494 7 8.777 7 4.283 0 7.868-2.992 8.777-7h7.214C37.1 22 38 21.105 38 20c0-1.112-.9-2-2.01-2h-7.213zM20 25c2.76 0 5-2.24 5-5s-2.24-5-5-5-5 2.24-5 5 2.24 5 5 5z"/></svg>
diff --git a/app/assets/javascripts/deploy_freeze/components/deploy_freeze_table.vue b/app/assets/javascripts/deploy_freeze/components/deploy_freeze_table.vue
index 159f5ddd755..0d6657973c3 100644
--- a/app/assets/javascripts/deploy_freeze/components/deploy_freeze_table.vue
+++ b/app/assets/javascripts/deploy_freeze/components/deploy_freeze_table.vue
@@ -69,15 +69,13 @@ export default {
</p>
</template>
</gl-table>
- <div class="gl-display-flex gl-justify-content-center">
- <gl-button
- v-gl-modal.deploy-freeze-modal
- data-testid="add-deploy-freeze"
- category="primary"
- variant="success"
- >
- {{ $options.translations.addDeployFreeze }}
- </gl-button>
- </div>
+ <gl-button
+ v-gl-modal.deploy-freeze-modal
+ data-testid="add-deploy-freeze"
+ category="primary"
+ variant="success"
+ >
+ {{ $options.translations.addDeployFreeze }}
+ </gl-button>
</div>
</template>
diff --git a/app/assets/javascripts/design_management/components/delete_button.vue b/app/assets/javascripts/design_management/components/delete_button.vue
index 970197ef41b..273fa3f6be2 100644
--- a/app/assets/javascripts/design_management/components/delete_button.vue
+++ b/app/assets/javascripts/design_management/components/delete_button.vue
@@ -63,7 +63,7 @@ export default {
title: s__('DesignManagement|Are you sure you want to archive the selected designs?'),
actionPrimary: {
text: s__('DesignManagement|Archive designs'),
- attributes: { variant: 'warning' },
+ attributes: { variant: 'warning', 'data-qa-selector': 'confirm_archiving_button' },
},
actionCancel: {
text: __('Cancel'),
diff --git a/app/assets/javascripts/design_management/components/design_note_pin.vue b/app/assets/javascripts/design_management/components/design_note_pin.vue
index 2b5e62c2870..320e0654aab 100644
--- a/app/assets/javascripts/design_management/components/design_note_pin.vue
+++ b/app/assets/javascripts/design_management/components/design_note_pin.vue
@@ -17,19 +17,11 @@ export default {
required: false,
default: null,
},
- repositioning: {
- type: Boolean,
- required: false,
- default: false,
- },
},
computed: {
isNewNote() {
return this.label === null;
},
- pinStyle() {
- return this.repositioning ? { ...this.position, cursor: 'move' } : this.position;
- },
pinLabel() {
return this.isNewNote
? __('Comment form position')
@@ -41,13 +33,13 @@ export default {
<template>
<button
- :style="pinStyle"
+ :style="position"
:aria-label="pinLabel"
:class="{
- 'btn-transparent comment-indicator': isNewNote,
+ 'btn-transparent comment-indicator gl-p-0': isNewNote,
'js-image-badge badge badge-pill': !isNewNote,
}"
- class="design-pin gl-absolute gl-display-flex gl-align-items-center gl-justify-content-center gl-p-0"
+ class="gl-absolute gl-display-flex gl-align-items-center gl-justify-content-center gl-font-lg gl-outline-0!"
type="button"
@mousedown="$emit('mousedown', $event)"
@mouseup="$emit('mouseup', $event)"
diff --git a/app/assets/javascripts/design_management/components/design_overlay.vue b/app/assets/javascripts/design_management/components/design_overlay.vue
index 5c4a3ab5f94..88f3ce0b8ea 100644
--- a/app/assets/javascripts/design_management/components/design_overlay.vue
+++ b/app/assets/javascripts/design_management/components/design_overlay.vue
@@ -266,7 +266,7 @@ export default {
type="button"
role="button"
:aria-label="$options.i18n.newCommentButtonLabel"
- class="gl-absolute gl-w-full gl-h-full gl-p-0 gl-top-0 gl-left-0 gl-outline-0! btn-transparent design-detail-overlay-add-comment"
+ class="gl-absolute gl-w-full gl-h-full gl-p-0 gl-top-0 gl-left-0 gl-outline-0! btn-transparent gl-hover-cursor-crosshair"
data-qa-selector="design_image_button"
@mouseup="onAddCommentMouseup"
></button>
@@ -276,7 +276,6 @@ export default {
v-if="resolvedDiscussionsExpanded || !note.resolved"
:key="note.id"
:label="note.index"
- :repositioning="isMovingNote(note.id)"
:position="
isMovingNote(note.id) && movingNoteNewPosition
? getNotePositionStyle(movingNoteNewPosition)
@@ -290,7 +289,6 @@ export default {
<design-note-pin
v-if="currentCommentForm"
:position="currentCommentPositionStyle"
- :repositioning="isMovingCurrentComment"
@mousedown.stop="onNoteMousedown"
@mouseup.stop="onNoteMouseup"
/>
diff --git a/app/assets/javascripts/design_management/components/design_presentation.vue b/app/assets/javascripts/design_management/components/design_presentation.vue
index 84dbb2809d9..c4d904e0d91 100644
--- a/app/assets/javascripts/design_management/components/design_presentation.vue
+++ b/app/assets/javascripts/design_management/components/design_presentation.vue
@@ -286,7 +286,7 @@ export default {
<template>
<div
ref="presentationViewport"
- class="h-100 w-100 p-3 overflow-auto position-relative"
+ class="gl-h-full gl-w-full gl-p-5 overflow-auto gl-relative"
:style="presentationStyle"
@mousedown="onPresentationMousedown"
@mousemove="onPresentationMousemove"
@@ -297,7 +297,7 @@ export default {
@touchend="onPresentationMouseup"
@touchcancel="onPresentationMouseup"
>
- <div class="h-100 w-100 d-flex align-items-center position-relative">
+ <div class="gl-h-full gl-w-full gl-display-flex gl-align-items-center gl-relative">
<design-image
v-if="image"
:image="image"
diff --git a/app/assets/javascripts/design_management/components/design_scaler.vue b/app/assets/javascripts/design_management/components/design_scaler.vue
index 55dee74bef5..8d26f84641e 100644
--- a/app/assets/javascripts/design_management/components/design_scaler.vue
+++ b/app/assets/javascripts/design_management/components/design_scaler.vue
@@ -51,7 +51,7 @@ export default {
<template>
<div class="design-scaler btn-group" role="group">
<button class="btn" :disabled="disableDecrease" @click="decrementScale">
- <span class="d-flex-center gl-icon s16">
+ <span class="gl-display-flex gl-justify-content-center gl-align-items-center gl-icon s16">
–
</span>
</button>
diff --git a/app/assets/javascripts/design_management/components/design_sidebar.vue b/app/assets/javascripts/design_management/components/design_sidebar.vue
index df425e3b96d..fb8e74c8c4c 100644
--- a/app/assets/javascripts/design_management/components/design_sidebar.vue
+++ b/app/assets/javascripts/design_management/components/design_sidebar.vue
@@ -71,14 +71,6 @@ export default {
resolvedCommentsToggleIcon() {
return this.resolvedDiscussionsExpanded ? 'chevron-down' : 'chevron-right';
},
- showTodoButton() {
- return this.glFeatures.designManagementTodoButton;
- },
- sidebarWrapperClass() {
- return {
- 'gl-pt-0': this.showTodoButton,
- };
- },
},
watch: {
isResolvedCommentsPopoverHidden(newVal) {
@@ -121,12 +113,11 @@ export default {
</script>
<template>
- <div class="image-notes" :class="sidebarWrapperClass" @click="handleSidebarClick">
+ <div class="image-notes gl-pt-0" @click="handleSidebarClick">
<div
- v-if="showTodoButton"
class="gl-py-4 gl-mb-4 gl-display-flex gl-justify-content-space-between gl-align-items-center gl-border-b-1 gl-border-b-solid gl-border-b-gray-100"
>
- <span>{{ __('To-Do') }}</span>
+ <span>{{ __('To Do') }}</span>
<design-todo-button :design="design" @error="$emit('todoError', $event)" />
</div>
<h2 class="gl-font-weight-bold gl-mt-0">
diff --git a/app/assets/javascripts/design_management/components/image.vue b/app/assets/javascripts/design_management/components/image.vue
index 91b7b576e0c..53062e6ebb0 100644
--- a/app/assets/javascripts/design_management/components/image.vue
+++ b/app/assets/javascripts/design_management/components/image.vue
@@ -93,8 +93,8 @@ export default {
</script>
<template>
- <div class="m-auto js-design-image">
- <gl-icon v-if="imageError" class="text-secondary-100" name="media-broken" :size="48" />
+ <div class="gl-mx-auto gl-my-auto js-design-image">
+ <gl-icon v-if="imageError" class="gl-text-gray-200" name="media-broken" :size="48" />
<img
v-show="!imageError"
ref="contentImg"
diff --git a/app/assets/javascripts/design_management/components/list/item.vue b/app/assets/javascripts/design_management/components/list/item.vue
index 36ea812d92e..fa09c7c15cc 100644
--- a/app/assets/javascripts/design_management/components/list/item.vue
+++ b/app/assets/javascripts/design_management/components/list/item.vue
@@ -132,7 +132,13 @@ export default {
>
<div v-if="icon.name" data-testid="designEvent" class="design-event gl-absolute">
<span :title="icon.tooltip" :aria-label="icon.tooltip">
- <gl-icon :name="icon.name" :size="18" :class="icon.classes" />
+ <gl-icon
+ :name="icon.name"
+ :size="18"
+ :class="icon.classes"
+ data-qa-selector="design_status_icon"
+ :data-qa-status="icon.name"
+ />
</span>
</div>
<gl-intersection-observer @appear="onAppear">
@@ -149,6 +155,7 @@ export default {
:alt="filename"
class="gl-display-block gl-mx-auto gl-max-w-full mh-100 design-img"
data-qa-selector="design_image"
+ :data-qa-filename="filename"
@load="onImageLoad"
@error="onImageError"
/>
diff --git a/app/assets/javascripts/design_management/components/toolbar/design_navigation.vue b/app/assets/javascripts/design_management/components/toolbar/design_navigation.vue
index afca8ed2c6f..2719d701c12 100644
--- a/app/assets/javascripts/design_management/components/toolbar/design_navigation.vue
+++ b/app/assets/javascripts/design_management/components/toolbar/design_navigation.vue
@@ -64,9 +64,9 @@ export default {
</script>
<template>
- <div v-if="designsCount" class="d-flex align-items-center">
+ <div v-if="designsCount" class="gl-display-flex gl-align-items-center">
{{ paginationText }}
- <gl-button-group class="ml-3 mr-3">
+ <gl-button-group class="gl-mx-5">
<gl-button
:disabled="!previousDesign"
:title="s__('DesignManagement|Go to previous design')"
diff --git a/app/assets/javascripts/design_management/components/toolbar/index.vue b/app/assets/javascripts/design_management/components/toolbar/index.vue
index a1cb57123ab..8d25d467d59 100644
--- a/app/assets/javascripts/design_management/components/toolbar/index.vue
+++ b/app/assets/javascripts/design_management/components/toolbar/index.vue
@@ -106,12 +106,12 @@ export default {
>
<gl-icon name="close" />
</router-link>
- <div class="overflow-hidden d-flex align-items-center">
- <h2 class="m-0 str-truncated-100 gl-font-base">{{ filename }}</h2>
- <small v-if="updatedAt" class="text-secondary">{{ updatedText }}</small>
+ <div class="gl-overflow-hidden gl-display-flex gl-align-items-center">
+ <h2 class="gl-m-0 str-truncated-100 gl-font-base">{{ filename }}</h2>
+ <small v-if="updatedAt" class="gl-text-gray-500">{{ updatedText }}</small>
</div>
</div>
- <design-navigation :id="id" class="ml-auto flex-shrink-0" />
+ <design-navigation :id="id" class="gl-ml-auto gl-flex-shrink-0" />
<gl-button :href="image" icon="download" />
<delete-button
v-if="isLatestVersion && canDeleteDesign"
diff --git a/app/assets/javascripts/design_management/components/upload/design_dropzone.vue b/app/assets/javascripts/design_management/components/upload/design_dropzone.vue
index 7254b7cd16a..6694b0dab8d 100644
--- a/app/assets/javascripts/design_management/components/upload/design_dropzone.vue
+++ b/app/assets/javascripts/design_management/components/upload/design_dropzone.vue
@@ -83,7 +83,7 @@ export default {
<template>
<div
- class="w-100 position-relative"
+ class="gl-w-full gl-relative"
@dragstart.prevent.stop
@dragend.prevent.stop
@dragover.prevent.stop
@@ -93,7 +93,7 @@ export default {
>
<slot>
<button
- class="card design-dropzone-card design-dropzone-border w-100 h-100 gl-align-items-center gl-justify-content-center gl-p-3"
+ class="card design-dropzone-card design-dropzone-border gl-w-full gl-h-full gl-align-items-center gl-justify-content-center gl-p-3"
@click="openFileUpload"
>
<div
@@ -127,9 +127,9 @@ export default {
<transition name="design-dropzone-fade">
<div
v-show="dragging && !isDraggingDesign"
- class="card design-dropzone-border design-dropzone-overlay w-100 h-100 position-absolute d-flex-center p-3 bg-white"
+ class="card design-dropzone-border design-dropzone-overlay gl-w-full gl-h-full gl-absolute gl-display-flex gl-align-items-center gl-justify-content-center gl-p-3 gl-bg-white"
>
- <div v-show="!isDragDataValid" class="mw-50 text-center">
+ <div v-show="!isDragDataValid" class="mw-50 gl-text-center">
<h3 :class="{ 'gl-font-base gl-display-inline': !hasDesigns }">{{ __('Oh no!') }}</h3>
<span>{{
__(
@@ -137,7 +137,7 @@ export default {
)
}}</span>
</div>
- <div v-show="isDragDataValid" class="mw-50 text-center">
+ <div v-show="isDragDataValid" class="mw-50 gl-text-center">
<h3 :class="{ 'gl-font-base gl-display-inline': !hasDesigns }">{{ __('Incoming!') }}</h3>
<span>{{ __('Drop your designs to start your upload.') }}</span>
</div>
diff --git a/app/assets/javascripts/design_management/graphql/queries/get_design_list.query.graphql b/app/assets/javascripts/design_management/graphql/queries/get_design_list.query.graphql
index 96efa8e8242..efa61edf51a 100644
--- a/app/assets/javascripts/design_management/graphql/queries/get_design_list.query.graphql
+++ b/app/assets/javascripts/design_management/graphql/queries/get_design_list.query.graphql
@@ -6,6 +6,7 @@ query getDesignList($fullPath: ID!, $iid: String!, $atVersion: ID) {
id
issue(iid: $iid) {
designCollection {
+ copyState
designs(atVersion: $atVersion) {
nodes {
...DesignListItem
diff --git a/app/assets/javascripts/design_management/mixins/all_designs.js b/app/assets/javascripts/design_management/mixins/all_designs.js
index 0c2858bb14b..62bcf216add 100644
--- a/app/assets/javascripts/design_management/mixins/all_designs.js
+++ b/app/assets/javascripts/design_management/mixins/all_designs.js
@@ -8,7 +8,7 @@ import { DESIGNS_ROUTE_NAME } from '../router/constants';
export default {
mixins: [allVersionsMixin],
apollo: {
- designs: {
+ designCollection: {
query: getDesignListQuery,
variables() {
return {
@@ -25,10 +25,11 @@ export default {
'designs',
'nodes',
]);
- if (designNodes) {
- return designNodes;
- }
- return [];
+ const copyState = propertyOf(data)(['project', 'issue', 'designCollection', 'copyState']);
+ return {
+ designs: designNodes,
+ copyState,
+ };
},
error() {
this.error = true;
@@ -42,13 +43,26 @@ export default {
);
this.$router.replace({ name: DESIGNS_ROUTE_NAME, query: { version: undefined } });
}
+ if (this.designCollection.copyState === 'ERROR') {
+ createFlash(
+ s__(
+ 'DesignManagement|There was an error moving your designs. Please upload your designs below.',
+ ),
+ 'warning',
+ );
+ }
},
},
},
data() {
return {
- designs: [],
+ designCollection: null,
error: false,
};
},
+ computed: {
+ designs() {
+ return this.designCollection?.designs || [];
+ },
+ },
};
diff --git a/app/assets/javascripts/design_management/pages/design/index.vue b/app/assets/javascripts/design_management/pages/design/index.vue
index c6225c516e2..6a96b06dcd8 100644
--- a/app/assets/javascripts/design_management/pages/design/index.vue
+++ b/app/assets/javascripts/design_management/pages/design/index.vue
@@ -40,6 +40,8 @@ import { trackDesignDetailView } from '../../utils/tracking';
import { DESIGNS_ROUTE_NAME } from '../../router/constants';
import { ACTIVE_DISCUSSION_SOURCE_TYPES } from '../../constants';
+const DEFAULT_SCALE = 1;
+
export default {
components: {
ApolloMutation,
@@ -65,7 +67,7 @@ export default {
comment: '',
annotationCoordinates: null,
errorMessage: '',
- scale: 1,
+ scale: DEFAULT_SCALE,
resolvedDiscussionsExpanded: false,
};
},
@@ -157,6 +159,11 @@ export default {
beforeDestroy() {
Mousetrap.unbind('esc', this.closeDesign);
},
+ beforeRouteUpdate(to, from, next) {
+ // reset scale when the active design changes
+ this.scale = DEFAULT_SCALE;
+ next();
+ },
methods: {
addImageDiffNoteToStore(
store,
@@ -300,11 +307,13 @@ export default {
<template>
<div
- class="design-detail js-design-detail fixed-top w-100 position-bottom-0 d-flex justify-content-center flex-column flex-lg-row"
+ class="design-detail js-design-detail fixed-top gl-w-full gl-bottom-0 gl-display-flex gl-justify-content-center gl-flex-direction-column gl-lg-flex-direction-row"
>
- <gl-loading-icon v-if="isFirstLoading" size="xl" class="align-self-center" />
+ <gl-loading-icon v-if="isFirstLoading" size="xl" class="gl-align-self-center" />
<template v-else>
- <div class="d-flex overflow-hidden flex-grow-1 flex-column position-relative">
+ <div
+ class="gl-display-flex gl-overflow-hidden gl-flex-grow-1 gl-flex-direction-column gl-relative"
+ >
<design-destroyer
:filenames="[design.filename]"
:project-path="projectPath"
@@ -323,7 +332,7 @@ export default {
</template>
</design-destroyer>
- <div v-if="errorMessage" class="p-3">
+ <div v-if="errorMessage" class="gl-p-5">
<gl-alert variant="danger" @dismiss="errorMessage = null">
{{ errorMessage }}
</gl-alert>
@@ -340,7 +349,9 @@ export default {
@moveNote="onMoveNote"
/>
- <div class="design-scaler-wrapper position-absolute mb-4 d-flex-center">
+ <div
+ class="design-scaler-wrapper gl-absolute gl-mb-6 gl-display-flex gl-justify-content-center gl-align-items-center"
+ >
<design-scaler @scale="scale = $event" />
</div>
</div>
diff --git a/app/assets/javascripts/design_management/pages/index.vue b/app/assets/javascripts/design_management/pages/index.vue
index 6c4c8c75054..6e71dca41e9 100644
--- a/app/assets/javascripts/design_management/pages/index.vue
+++ b/app/assets/javascripts/design_management/pages/index.vue
@@ -3,6 +3,7 @@ import { GlLoadingIcon, GlButton, GlAlert } from '@gitlab/ui';
import VueDraggable from 'vuedraggable';
import { deprecatedCreateFlash as createFlash } from '~/flash';
import { s__, sprintf } from '~/locale';
+import { getFilename } from '~/lib/utils/file_upload';
import UploadButton from '../components/upload/button.vue';
import DeleteButton from '../components/delete_button.vue';
import Design from '../components/list/item.vue';
@@ -31,7 +32,7 @@ import {
isValidDesignFile,
moveDesignOptimisticResponse,
} from '../utils/design_management_utils';
-import { getFilename } from '~/lib/utils/file_upload';
+import { trackDesignCreate, trackDesignUpdate } from '../utils/tracking';
import { DESIGNS_ROUTE_NAME } from '../router/constants';
const MAXIMUM_FILE_UPLOAD_LIMIT = 10;
@@ -71,11 +72,14 @@ export default {
selectedDesigns: [],
isDraggingDesign: false,
reorderedDesigns: null,
+ isReorderingInProgress: false,
};
},
computed: {
isLoading() {
- return this.$apollo.queries.designs.loading || this.$apollo.queries.permissions.loading;
+ return (
+ this.$apollo.queries.designCollection.loading || this.$apollo.queries.permissions.loading
+ );
},
isSaving() {
return this.filesToBeSaved.length > 0;
@@ -109,6 +113,9 @@ export default {
isDesignListEmpty() {
return !this.isSaving && !this.hasDesigns;
},
+ isDesignCollectionCopying() {
+ return this.designCollection && this.designCollection.copyState === 'IN_PROGRESS';
+ },
designDropzoneWrapperClass() {
return this.isDesignListEmpty
? 'col-12'
@@ -180,6 +187,7 @@ export default {
updateStoreAfterUploadDesign(store, designManagementUpload, this.projectQueryBody);
},
onUploadDesignDone(res) {
+ // display any warnings, if necessary
const skippedFiles = res?.data?.designManagementUpload?.skippedDesigns || [];
const skippedWarningMessage = designUploadSkippedWarning(this.filesToBeSaved, skippedFiles);
if (skippedWarningMessage) {
@@ -190,7 +198,19 @@ export default {
if (!this.isLatestVersion) {
this.$router.push({ name: DESIGNS_ROUTE_NAME });
}
+
+ // reset state
this.resetFilesToBeSaved();
+ this.trackUploadDesign(res);
+ },
+ trackUploadDesign(res) {
+ (res?.data?.designManagementUpload?.designs || []).forEach(design => {
+ if (design.event === 'CREATION') {
+ trackDesignCreate();
+ } else if (design.event === 'MODIFICATION') {
+ trackDesignUpdate();
+ }
+ });
},
onUploadDesignError() {
this.resetFilesToBeSaved();
@@ -277,6 +297,7 @@ export default {
return variables;
},
reorderDesigns({ moved: { newIndex, element } }) {
+ this.isReorderingInProgress = true;
this.$apollo
.mutate({
mutation: moveDesignMutation,
@@ -287,6 +308,9 @@ export default {
})
.catch(() => {
createFlash(MOVE_DESIGN_ERROR);
+ })
+ .finally(() => {
+ this.isReorderingInProgress = false;
});
},
onDesignMove(designs) {
@@ -311,7 +335,7 @@ export default {
@mouseenter="toggleOnPasteListener"
@mouseleave="toggleOffPasteListener"
>
- <header v-if="showToolbar" class="row-content-block border-top-0 p-2 d-flex">
+ <header v-if="showToolbar" class="row-content-block gl-border-t-0 gl-p-3 gl-display-flex">
<div class="gl-display-flex gl-justify-content-space-between gl-align-items-center gl-w-full">
<div>
<span class="gl-font-weight-bold gl-mr-3">{{ s__('DesignManagement|Designs') }}</span>
@@ -339,6 +363,7 @@ export default {
button-category="secondary"
button-class="gl-mr-3"
button-size="small"
+ data-qa-selector="archive_button"
:loading="loading"
:has-selected-designs="hasSelectedDesigns"
@deleteSelectedDesigns="mutate()"
@@ -350,15 +375,30 @@ export default {
</div>
</div>
</header>
- <div class="mt-4">
+ <div class="gl-mt-6">
<gl-loading-icon v-if="isLoading" size="md" />
<gl-alert v-else-if="error" variant="danger" :dismissible="false">
{{ __('An error occurred while loading designs. Please try again.') }}
</gl-alert>
+ <header
+ v-else-if="isDesignCollectionCopying"
+ class="card"
+ data-testid="design-collection-is-copying"
+ >
+ <div class="card-header design-card-header gl-border-b-0">
+ <div class="card-title gl-display-flex gl-align-items-center gl-my-0 gl-h-7">
+ {{
+ s__(
+ 'DesignManagement|Your designs are being copied and are on their way… Please refresh to update.',
+ )
+ }}
+ </div>
+ </div>
+ </header>
<vue-draggable
v-else
:value="designs"
- :disabled="!isLatestVersion"
+ :disabled="!isLatestVersion || isReorderingInProgress"
v-bind="$options.dragOptions"
tag="ol"
draggable=".js-design-tile"
@@ -390,6 +430,8 @@ export default {
:checked="isDesignSelected(design.filename)"
type="checkbox"
class="design-checkbox"
+ data-qa-selector="design_checkbox"
+ :data-qa-design="design.filename"
@change="changeSelectedDesigns(design.filename)"
/>
</li>
@@ -399,6 +441,7 @@ export default {
:is-dragging-design="isDraggingDesign"
:class="{ 'design-list-item design-list-item-new': !isDesignListEmpty }"
:has-designs="hasDesigns"
+ data-qa-selector="design_dropzone_content"
@change="onUploadDesign"
/>
</li>
diff --git a/app/assets/javascripts/design_management/utils/cache_update.js b/app/assets/javascripts/design_management/utils/cache_update.js
index ff41136fd54..fc0530ff977 100644
--- a/app/assets/javascripts/design_management/utils/cache_update.js
+++ b/app/assets/javascripts/design_management/utils/cache_update.js
@@ -1,6 +1,6 @@
/* eslint-disable @gitlab/require-i18n-strings */
-import { groupBy } from 'lodash';
+import { differenceBy } from 'lodash';
import produce from 'immer';
import { deprecatedCreateFlash as createFlash } from '~/flash';
import { extractCurrentDiscussion, extractDesign, extractDesigns } from './design_management_utils';
@@ -132,10 +132,13 @@ const addNewDesignToStore = (store, designManagementUpload, query) => {
const data = produce(sourceData, draftData => {
const currentDesigns = extractDesigns(draftData);
- const existingDesigns = groupBy(currentDesigns, 'filename');
- const newDesigns = currentDesigns.concat(
- designManagementUpload.designs.filter(d => !existingDesigns[d.filename]),
- );
+ const difference = differenceBy(designManagementUpload.designs, currentDesigns, 'filename');
+
+ const newDesigns = currentDesigns
+ .map(design => {
+ return designManagementUpload.designs.find(d => d.filename === design.filename) || design;
+ })
+ .concat(difference);
let newVersionNode;
const findNewVersions = designManagementUpload.designs.find(design => design.versions);
@@ -155,6 +158,7 @@ const addNewDesignToStore = (store, designManagementUpload, query) => {
const updatedDesigns = {
__typename: 'DesignCollection',
+ copyState: 'READY',
designs: {
__typename: 'DesignConnection',
nodes: newDesigns,
diff --git a/app/assets/javascripts/design_management/utils/design_management_utils.js b/app/assets/javascripts/design_management/utils/design_management_utils.js
index 93e4d6060c3..687e793d3df 100644
--- a/app/assets/javascripts/design_management/utils/design_management_utils.js
+++ b/app/assets/javascripts/design_management/utils/design_management_utils.js
@@ -65,6 +65,10 @@ export const designUploadOptimisticResponse = files => {
fullPath: '',
notesCount: 0,
event: 'NONE',
+ currentUserTodos: {
+ __typename: 'TodoConnection',
+ nodes: [],
+ },
diffRefs: {
__typename: 'DiffRefs',
baseSha: '',
diff --git a/app/assets/javascripts/design_management/utils/tracking.js b/app/assets/javascripts/design_management/utils/tracking.js
index 49fa306914c..4a39268c38b 100644
--- a/app/assets/javascripts/design_management/utils/tracking.js
+++ b/app/assets/javascripts/design_management/utils/tracking.js
@@ -1,9 +1,16 @@
import Tracking from '~/tracking';
// Tracking Constants
-const DESIGN_TRACKING_CONTEXT_SCHEMA = 'iglu:com.gitlab/design_management_context/jsonschema/1-0-0';
-const DESIGN_TRACKING_PAGE_NAME = 'projects:issues:design';
-const DESIGN_TRACKING_EVENT_NAME = 'view_design';
+const DESIGN_TRACKING_CONTEXT_SCHEMAS = {
+ VIEW_DESIGN_SCHEMA: 'iglu:com.gitlab/design_management_context/jsonschema/1-0-0',
+};
+const DESIGN_TRACKING_EVENTS = {
+ VIEW_DESIGN: 'view_design',
+ CREATE_DESIGN: 'create_design',
+ UPDATE_DESIGN: 'update_design',
+};
+
+export const DESIGN_TRACKING_PAGE_NAME = 'projects:issues:design';
export function trackDesignDetailView(
referer = '',
@@ -11,10 +18,11 @@ export function trackDesignDetailView(
designVersion = 1,
latestVersion = false,
) {
- Tracking.event(DESIGN_TRACKING_PAGE_NAME, DESIGN_TRACKING_EVENT_NAME, {
- label: DESIGN_TRACKING_EVENT_NAME,
+ const eventName = DESIGN_TRACKING_EVENTS.VIEW_DESIGN;
+ Tracking.event(DESIGN_TRACKING_PAGE_NAME, eventName, {
+ label: eventName,
context: {
- schema: DESIGN_TRACKING_CONTEXT_SCHEMA,
+ schema: DESIGN_TRACKING_CONTEXT_SCHEMAS.VIEW_DESIGN_SCHEMA,
data: {
'design-version-number': designVersion,
'design-is-current-version': latestVersion,
@@ -24,3 +32,11 @@ export function trackDesignDetailView(
},
});
}
+
+export function trackDesignCreate() {
+ return Tracking.event(DESIGN_TRACKING_PAGE_NAME, DESIGN_TRACKING_EVENTS.CREATE_DESIGN);
+}
+
+export function trackDesignUpdate() {
+ return Tracking.event(DESIGN_TRACKING_PAGE_NAME, DESIGN_TRACKING_EVENTS.UPDATE_DESIGN);
+}
diff --git a/app/assets/javascripts/diff_notes/components/comment_resolve_btn.js b/app/assets/javascripts/diff_notes/components/comment_resolve_btn.js
deleted file mode 100644
index dd60e2c7684..00000000000
--- a/app/assets/javascripts/diff_notes/components/comment_resolve_btn.js
+++ /dev/null
@@ -1,65 +0,0 @@
-/* global CommentsStore */
-
-import $ from 'jquery';
-import Vue from 'vue';
-import { __ } from '~/locale';
-
-const CommentAndResolveBtn = Vue.extend({
- props: {
- discussionId: {
- type: String,
- required: true,
- },
- },
- data() {
- return {
- textareaIsEmpty: true,
- discussion: {},
- };
- },
- computed: {
- showButton() {
- if (this.discussion) {
- return this.discussion.isResolvable();
- }
- return false;
- },
- isDiscussionResolved() {
- return this.discussion.isResolved();
- },
- buttonText() {
- if (this.textareaIsEmpty) {
- return this.isDiscussionResolved ? __('Unresolve thread') : __('Resolve thread');
- }
- return this.isDiscussionResolved
- ? __('Comment & unresolve thread')
- : __('Comment & resolve thread');
- },
- },
- created() {
- if (this.discussionId) {
- this.discussion = CommentsStore.state[this.discussionId];
- }
- },
- mounted() {
- if (!this.discussionId) return;
-
- const $textarea = $(
- `.js-discussion-note-form[data-discussion-id=${this.discussionId}] .note-textarea`,
- );
- this.textareaIsEmpty = $textarea.val() === '';
-
- $textarea.on('input.comment-and-resolve-btn', () => {
- this.textareaIsEmpty = $textarea.val() === '';
- });
- },
- destroyed() {
- if (!this.discussionId) return;
-
- $(`.js-discussion-note-form[data-discussion-id=${this.discussionId}] .note-textarea`).off(
- 'input.comment-and-resolve-btn',
- );
- },
-});
-
-Vue.component('comment-and-resolve-btn', CommentAndResolveBtn);
diff --git a/app/assets/javascripts/diff_notes/components/diff_note_avatars.js b/app/assets/javascripts/diff_notes/components/diff_note_avatars.js
deleted file mode 100644
index b5a781cbc92..00000000000
--- a/app/assets/javascripts/diff_notes/components/diff_note_avatars.js
+++ /dev/null
@@ -1,189 +0,0 @@
-/* global CommentsStore */
-
-import $ from 'jquery';
-import Vue from 'vue';
-import collapseIcon from '../icons/collapse_icon.svg';
-import Notes from '../../notes';
-import userAvatarImage from '../../vue_shared/components/user_avatar/user_avatar_image.vue';
-import { n__ } from '~/locale';
-
-const DiffNoteAvatars = Vue.extend({
- components: {
- userAvatarImage,
- },
- props: {
- discussionId: {
- type: String,
- required: true,
- },
- },
- data() {
- return {
- isVisible: false,
- lineType: '',
- storeState: CommentsStore.state,
- shownAvatars: 3,
- collapseIcon,
- };
- },
- computed: {
- discussionClassName() {
- return `js-diff-avatars-${this.discussionId}`;
- },
- notesSubset() {
- let notes = [];
-
- if (this.discussion) {
- notes = Object.keys(this.discussion.notes)
- .slice(0, this.shownAvatars)
- .map(noteId => this.discussion.notes[noteId]);
- }
-
- return notes;
- },
- extraNotesTitle() {
- if (this.discussion) {
- const extra = this.discussion.notesCount() - this.shownAvatars;
-
- return n__('%d more comment', '%d more comments', extra);
- }
-
- return '';
- },
- discussion() {
- return this.storeState[this.discussionId];
- },
- notesCount() {
- if (this.discussion) {
- return this.discussion.notesCount();
- }
-
- return 0;
- },
- moreText() {
- const plusSign = this.notesCount < 100 ? '+' : '';
-
- return `${plusSign}${this.notesCount - this.shownAvatars}`;
- },
- },
- watch: {
- storeState: {
- handler() {
- this.$nextTick(() => {
- $('.has-tooltip', this.$el).tooltip('_fixTitle');
-
- // We need to add/remove a class to an element that is outside the Vue instance
- this.addNoCommentClass();
- });
- },
- deep: true,
- },
- },
- mounted() {
- this.$nextTick(() => {
- this.addNoCommentClass();
- this.setDiscussionVisible();
-
- this.lineType = $(this.$el)
- .closest('.diff-line-num')
- .hasClass('old_line')
- ? 'old'
- : 'new';
- });
-
- $(document).on('toggle.comments', () => {
- this.$nextTick(() => {
- this.setDiscussionVisible();
- });
- });
- },
- beforeDestroy() {
- this.addNoCommentClass();
- $(document).off('toggle.comments');
- },
- methods: {
- clickedAvatar(e) {
- Notes.instance.onAddDiffNote(e);
-
- // Toggle the active state of the toggle all button
- this.toggleDiscussionsToggleState();
-
- this.$nextTick(() => {
- this.setDiscussionVisible();
-
- $('.has-tooltip', this.$el).tooltip('_fixTitle');
- $('.has-tooltip', this.$el).tooltip('hide');
- });
- },
- addNoCommentClass() {
- const { notesCount } = this;
-
- $(this.$el)
- .closest('.js-avatar-container')
- .toggleClass('no-comment-btn', notesCount > 0)
- .nextUntil('.js-avatar-container')
- .toggleClass('no-comment-btn', notesCount > 0);
- },
- toggleDiscussionsToggleState() {
- const $notesHolders = $(this.$el)
- .closest('.code')
- .find('.notes_holder');
- const $visibleNotesHolders = $notesHolders.filter(':visible');
- const $toggleDiffCommentsBtn = $(this.$el)
- .closest('.diff-file')
- .find('.js-toggle-diff-comments');
-
- $toggleDiffCommentsBtn.toggleClass(
- 'active',
- $notesHolders.length === $visibleNotesHolders.length,
- );
- },
- setDiscussionVisible() {
- this.isVisible = $(`.diffs .notes[data-discussion-id="${this.discussion.id}"]`).is(
- ':visible',
- );
- },
- getTooltipText(note) {
- return `${note.authorName}: ${note.noteTruncated}`;
- },
- },
- template: `
- <div class="diff-comment-avatar-holders"
- :class="discussionClassName"
- v-show="notesCount !== 0">
- <div v-if="!isVisible">
- <!-- FIXME: Pass an alt attribute here for accessibility -->
- <user-avatar-image
- v-for="note in notesSubset"
- :key="note.id"
- class="diff-comment-avatar js-diff-comment-avatar"
- @click.native="clickedAvatar($event)"
- :img-src="note.authorAvatar"
- :tooltip-text="getTooltipText(note)"
- :data-line-type="lineType"
- :size="19"
- data-html="true"
- />
- <span v-if="notesCount > shownAvatars"
- class="diff-comments-more-count has-tooltip js-diff-comment-avatar"
- data-container="body"
- data-placement="top"
- ref="extraComments"
- role="button"
- :data-line-type="lineType"
- :title="extraNotesTitle"
- @click="clickedAvatar($event)">{{ moreText }}</span>
- </div>
- <button class="diff-notes-collapse js-diff-comment-avatar"
- type="button"
- aria-label="Show comments"
- :data-line-type="lineType"
- @click="clickedAvatar($event)"
- v-if="isVisible"
- v-html="collapseIcon">
- </button>
- </div>
- `,
-});
-
-Vue.component('diff-note-avatars', DiffNoteAvatars);
diff --git a/app/assets/javascripts/diff_notes/components/jump_to_discussion.js b/app/assets/javascripts/diff_notes/components/jump_to_discussion.js
deleted file mode 100644
index 1de00c9f08b..00000000000
--- a/app/assets/javascripts/diff_notes/components/jump_to_discussion.js
+++ /dev/null
@@ -1,210 +0,0 @@
-/* eslint-disable func-names, no-continue */
-/* global CommentsStore */
-
-import $ from 'jquery';
-import 'vendor/jquery.scrollTo';
-import Vue from 'vue';
-import { __ } from '~/locale';
-
-import DiscussionMixins from '../mixins/discussion';
-
-const JumpToDiscussion = Vue.extend({
- mixins: [DiscussionMixins],
- props: {
- discussionId: {
- type: String,
- required: true,
- },
- },
- data() {
- return {
- discussions: CommentsStore.state,
- discussion: {},
- };
- },
- computed: {
- buttonText() {
- if (this.discussionId) {
- return __('Jump to next unresolved thread');
- }
- return __('Jump to first unresolved thread');
- },
- allResolved() {
- return this.unresolvedDiscussionCount === 0;
- },
- showButton() {
- if (this.discussionId) {
- if (this.unresolvedDiscussionCount > 1) {
- return true;
- }
- return this.discussionId !== this.lastResolvedId;
- }
- return this.unresolvedDiscussionCount >= 1;
- },
- lastResolvedId() {
- let lastId;
- Object.keys(this.discussions).forEach(discussionId => {
- const discussion = this.discussions[discussionId];
-
- if (!discussion.isResolved()) {
- lastId = discussion.id;
- }
- });
- return lastId;
- },
- },
- created() {
- this.discussion = this.discussions[this.discussionId];
- },
- methods: {
- jumpToNextUnresolvedDiscussion() {
- let discussionsSelector;
- let discussionIdsInScope;
- let firstUnresolvedDiscussionId;
- let nextUnresolvedDiscussionId;
- let activeTab = window.mrTabs.currentAction;
- let hasDiscussionsToJumpTo = true;
- let jumpToFirstDiscussion = !this.discussionId;
-
- const discussionIdsForElements = function(elements) {
- return elements
- .map(function() {
- return $(this).attr('data-discussion-id');
- })
- .toArray();
- };
-
- const { discussions } = this;
-
- if (activeTab === 'diffs') {
- discussionsSelector = '.diffs .notes[data-discussion-id]';
- discussionIdsInScope = discussionIdsForElements($(discussionsSelector));
-
- let unresolvedDiscussionCount = 0;
-
- for (let i = 0; i < discussionIdsInScope.length; i += 1) {
- const discussionId = discussionIdsInScope[i];
- const discussion = discussions[discussionId];
- if (discussion && !discussion.isResolved()) {
- unresolvedDiscussionCount += 1;
- }
- }
-
- if (this.discussionId && !this.discussion.isResolved()) {
- // If this is the last unresolved discussion on the diffs tab,
- // there are no discussions to jump to.
- if (unresolvedDiscussionCount === 1) {
- hasDiscussionsToJumpTo = false;
- }
- } else if (unresolvedDiscussionCount === 0) {
- // If there are no unresolved discussions on the diffs tab at all,
- // there are no discussions to jump to.
- hasDiscussionsToJumpTo = false;
- }
- } else if (activeTab !== 'show') {
- // If we are on the commits or builds tabs,
- // there are no discussions to jump to.
- hasDiscussionsToJumpTo = false;
- }
-
- if (!hasDiscussionsToJumpTo) {
- // If there are no discussions to jump to on the current page,
- // switch to the notes tab and jump to the first discussion there.
- window.mrTabs.activateTab('show');
- activeTab = 'show';
- jumpToFirstDiscussion = true;
- }
-
- if (activeTab === 'show') {
- discussionsSelector = '.discussion[data-discussion-id]';
- discussionIdsInScope = discussionIdsForElements($(discussionsSelector));
- }
-
- let currentDiscussionFound = false;
- for (let i = 0; i < discussionIdsInScope.length; i += 1) {
- const discussionId = discussionIdsInScope[i];
- const discussion = discussions[discussionId];
-
- if (!discussion) {
- // Discussions for comments on commits in this MR don't have a resolved status.
- continue;
- }
-
- if (!firstUnresolvedDiscussionId && !discussion.isResolved()) {
- firstUnresolvedDiscussionId = discussionId;
-
- if (jumpToFirstDiscussion) {
- break;
- }
- }
-
- if (!jumpToFirstDiscussion) {
- if (currentDiscussionFound) {
- if (!discussion.isResolved()) {
- nextUnresolvedDiscussionId = discussionId;
- break;
- } else {
- continue;
- }
- }
-
- if (discussionId === this.discussionId) {
- currentDiscussionFound = true;
- }
- }
- }
-
- nextUnresolvedDiscussionId = nextUnresolvedDiscussionId || firstUnresolvedDiscussionId;
-
- if (!nextUnresolvedDiscussionId) {
- return;
- }
-
- let $target = $(`${discussionsSelector}[data-discussion-id="${nextUnresolvedDiscussionId}"]`);
-
- if (activeTab === 'show') {
- $target = $target.closest('.note-discussion');
-
- // If the next discussion is closed, toggle it open.
- if ($target.find('.js-toggle-content').is(':hidden')) {
- $target.find('.js-toggle-button i').trigger('click');
- }
- } else if (activeTab === 'diffs') {
- // Resolved discussions are hidden in the diffs tab by default.
- // If they are marked unresolved on the notes tab, they will still be hidden on the diffs tab.
- // When jumping between unresolved discussions on the diffs tab, we show them.
- $target.closest('.content').show();
-
- const $notesHolder = $target.closest('tr.notes_holder');
-
- // Image diff discussions does not use notes_holder
- // so we should keep original $target value in those cases
- if ($notesHolder.length > 0) {
- $target = $notesHolder;
- }
-
- $target.show();
-
- // If we are on the diffs tab, we don't scroll to the discussion itself, but to
- // 4 diff lines above it: the line the discussion was in response to + 3 context
- let prevEl;
- for (let i = 0; i < 4; i += 1) {
- prevEl = $target.prev();
-
- // If the discussion doesn't have 4 lines above it, we'll have to do with fewer.
- if (!prevEl.hasClass('line_holder')) {
- break;
- }
-
- $target = prevEl;
- }
- }
-
- $.scrollTo($target, {
- offset: -150,
- });
- },
- },
-});
-
-Vue.component('jump-to-discussion', JumpToDiscussion);
diff --git a/app/assets/javascripts/diff_notes/components/new_issue_for_discussion.js b/app/assets/javascripts/diff_notes/components/new_issue_for_discussion.js
deleted file mode 100644
index e0c09aa0eee..00000000000
--- a/app/assets/javascripts/diff_notes/components/new_issue_for_discussion.js
+++ /dev/null
@@ -1,28 +0,0 @@
-/* global CommentsStore */
-
-import Vue from 'vue';
-
-const NewIssueForDiscussion = Vue.extend({
- props: {
- discussionId: {
- type: String,
- required: true,
- },
- },
- data() {
- return {
- discussions: CommentsStore.state,
- };
- },
- computed: {
- discussion() {
- return this.discussions[this.discussionId];
- },
- showButton() {
- if (this.discussion) return !this.discussion.isResolved();
- return false;
- },
- },
-});
-
-Vue.component('new-issue-for-discussion-btn', NewIssueForDiscussion);
diff --git a/app/assets/javascripts/diff_notes/components/resolve_btn.js b/app/assets/javascripts/diff_notes/components/resolve_btn.js
deleted file mode 100644
index 0943712d0c5..00000000000
--- a/app/assets/javascripts/diff_notes/components/resolve_btn.js
+++ /dev/null
@@ -1,145 +0,0 @@
-/* global CommentsStore */
-/* global ResolveService */
-
-import $ from 'jquery';
-import Vue from 'vue';
-import { deprecatedCreateFlash as Flash } from '../../flash';
-import { sprintf, __ } from '~/locale';
-
-const ResolveBtn = Vue.extend({
- props: {
- noteId: {
- type: Number,
- required: true,
- },
- discussionId: {
- type: String,
- required: true,
- },
- resolved: {
- type: Boolean,
- required: true,
- },
- canResolve: {
- type: Boolean,
- required: true,
- },
- resolvedBy: {
- type: String,
- required: true,
- },
- authorName: {
- type: String,
- required: true,
- },
- authorAvatar: {
- type: String,
- required: true,
- },
- noteTruncated: {
- type: String,
- required: true,
- },
- },
- data() {
- return {
- discussions: CommentsStore.state,
- loading: false,
- };
- },
- computed: {
- discussion() {
- return this.discussions[this.discussionId];
- },
- note() {
- return this.discussion ? this.discussion.getNote(this.noteId) : {};
- },
- buttonText() {
- if (this.isResolved) {
- return sprintf(__('Resolved by %{resolvedByName}'), {
- resolvedByName: this.resolvedByName,
- });
- } else if (this.canResolve) {
- return __('Mark as resolved');
- }
-
- return __('Unable to resolve');
- },
- isResolved() {
- if (this.note) {
- return this.note.resolved;
- }
-
- return false;
- },
- resolvedByName() {
- return this.note.resolved_by;
- },
- },
- watch: {
- discussions: {
- handler: 'updateTooltip',
- deep: true,
- },
- },
- mounted() {
- $(this.$refs.button).tooltip({
- container: 'body',
- });
- },
- beforeDestroy() {
- CommentsStore.delete(this.discussionId, this.noteId);
- },
- created() {
- CommentsStore.create({
- discussionId: this.discussionId,
- noteId: this.noteId,
- canResolve: this.canResolve,
- resolved: this.resolved,
- resolvedBy: this.resolvedBy,
- authorName: this.authorName,
- authorAvatar: this.authorAvatar,
- noteTruncated: this.noteTruncated,
- });
- },
- methods: {
- updateTooltip() {
- this.$nextTick(() => {
- $(this.$refs.button)
- .tooltip('hide')
- .tooltip('_fixTitle');
- });
- },
- resolve() {
- if (!this.canResolve) return;
-
- let promise;
- this.loading = true;
-
- if (this.isResolved) {
- promise = ResolveService.unresolve(this.noteId);
- } else {
- promise = ResolveService.resolve(this.noteId);
- }
-
- promise
- .then(resp => resp.json())
- .then(data => {
- this.loading = false;
-
- const resolvedBy = data ? data.resolved_by : null;
-
- CommentsStore.update(this.discussionId, this.noteId, !this.isResolved, resolvedBy);
- this.discussion.updateHeadline(data);
- gl.mrWidget.checkStatus();
- this.updateTooltip();
- })
- .catch(
- () =>
- new Flash(__('An error occurred when trying to resolve a comment. Please try again.')),
- );
- },
- },
-});
-
-Vue.component('resolve-btn', ResolveBtn);
diff --git a/app/assets/javascripts/diff_notes/components/resolve_count.js b/app/assets/javascripts/diff_notes/components/resolve_count.js
deleted file mode 100644
index f960853b25b..00000000000
--- a/app/assets/javascripts/diff_notes/components/resolve_count.js
+++ /dev/null
@@ -1,28 +0,0 @@
-/* global CommentsStore */
-
-import Vue from 'vue';
-
-import DiscussionMixins from '../mixins/discussion';
-
-window.ResolveCount = Vue.extend({
- mixins: [DiscussionMixins],
- props: {
- loggedOut: {
- type: Boolean,
- required: true,
- },
- },
- data() {
- return {
- discussions: CommentsStore.state,
- };
- },
- computed: {
- allResolved() {
- return this.resolvedDiscussionCount === this.discussionCount;
- },
- resolvedCountText() {
- return this.discussionCount === 1 ? 'discussion' : 'discussions';
- },
- },
-});
diff --git a/app/assets/javascripts/diff_notes/diff_notes_bundle.js b/app/assets/javascripts/diff_notes/diff_notes_bundle.js
deleted file mode 100644
index 92862d4c933..00000000000
--- a/app/assets/javascripts/diff_notes/diff_notes_bundle.js
+++ /dev/null
@@ -1,72 +0,0 @@
-/* eslint-disable func-names, new-cap */
-
-import $ from 'jquery';
-import Vue from 'vue';
-import './models/discussion';
-import './models/note';
-import './stores/comments';
-import './services/resolve';
-import './mixins/discussion';
-import './components/comment_resolve_btn';
-import './components/jump_to_discussion';
-import './components/resolve_btn';
-import './components/resolve_count';
-import './components/diff_note_avatars';
-import './components/new_issue_for_discussion';
-
-export default () => {
- const projectPathHolder =
- document.querySelector('.merge-request') || document.querySelector('.commit-box');
- const { projectPath } = projectPathHolder.dataset;
- const COMPONENT_SELECTOR =
- 'resolve-btn, jump-to-discussion, comment-and-resolve-btn, new-issue-for-discussion-btn';
-
- window.gl = window.gl || {};
- window.gl.diffNoteApps = {};
-
- window.ResolveService = new gl.DiffNotesResolveServiceClass(projectPath);
-
- gl.diffNotesCompileComponents = () => {
- $('diff-note-avatars').each(function() {
- const tmp = Vue.extend({
- template: $(this).get(0).outerHTML,
- });
- const tmpApp = new tmp().$mount();
-
- $(this).replaceWith(tmpApp.$el);
- $(tmpApp.$el).one('remove.vue', () => {
- tmpApp.$destroy();
- tmpApp.$el.remove();
- });
- });
-
- const $components = $(COMPONENT_SELECTOR).filter(function() {
- return $(this).closest('resolve-count').length !== 1;
- });
-
- if ($components) {
- $components.each(function() {
- const $this = $(this);
- const noteId = $this.attr(':note-id');
- const discussionId = $this.attr(':discussion-id');
-
- if ($this.is('comment-and-resolve-btn') && !discussionId) return;
-
- const tmp = Vue.extend({
- template: $this.get(0).outerHTML,
- });
- const tmpApp = new tmp().$mount();
-
- if (noteId) {
- gl.diffNoteApps[`note_${noteId}`] = tmpApp;
- }
-
- $this.replaceWith(tmpApp.$el);
- });
- }
- };
-
- gl.diffNotesCompileComponents();
-
- $(window).trigger('resize.nav');
-};
diff --git a/app/assets/javascripts/diff_notes/icons/collapse_icon.svg b/app/assets/javascripts/diff_notes/icons/collapse_icon.svg
deleted file mode 100644
index bd4b393cfaa..00000000000
--- a/app/assets/javascripts/diff_notes/icons/collapse_icon.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg width="11" height="11" viewBox="0 0 9 13"><path d="M2.57568253,6.49866948 C2.50548852,6.57199715 2.44637866,6.59708255 2.39835118,6.57392645 C2.3503237,6.55077034 2.32631032,6.48902165 2.32631032,6.38867852 L2.32631032,-2.13272614 C2.32631032,-2.23306927 2.3503237,-2.29481796 2.39835118,-2.31797406 C2.44637866,-2.34113017 2.50548852,-2.31604477 2.57568253,-2.24271709 L6.51022184,1.86747129 C6.53977721,1.8983461 6.56379059,1.93500939 6.5822627,1.97746225 L6.5822627,2.27849013 C6.56379059,2.31708364 6.53977721,2.35374693 6.51022184,2.38848109 L2.57568253,6.49866948 Z" transform="translate(4.454287, 2.127976) rotate(90.000000) translate(-4.454287, -2.127976) "></path><path d="M3.74312342,2.09553332 C3.74312342,1.99519019 3.77821989,1.9083561 3.8484139,1.83502843 C3.91860791,1.76170075 4.00173115,1.72503747 4.09778611,1.72503747 L4.80711151,1.72503747 C4.90316647,1.72503747 4.98628971,1.76170075 5.05648372,1.83502843 C5.12667773,1.9083561 5.16177421,1.99519019 5.16177421,2.09553332 L5.16177421,10.2464421 C5.16177421,10.3467853 5.12667773,10.4336194 5.05648372,10.506947 C4.98628971,10.5802747 4.90316647,10.616938 4.80711151,10.616938 L4.09778611,10.616938 C4.00173115,10.616938 3.91860791,10.5802747 3.8484139,10.506947 C3.77821989,10.4336194 3.74312342,10.3467853 3.74312342,10.2464421 L3.74312342,2.09553332 Z" transform="translate(4.452449, 6.170988) rotate(-90.000000) translate(-4.452449, -6.170988) "></path><path d="M2.57568253,14.6236695 C2.50548852,14.6969971 2.44637866,14.7220826 2.39835118,14.6989264 C2.3503237,14.6757703 2.32631032,14.6140216 2.32631032,14.5136785 L2.32631032,5.99227386 C2.32631032,5.89193073 2.3503237,5.83018204 2.39835118,5.80702594 C2.44637866,5.78386983 2.50548852,5.80895523 2.57568253,5.88228291 L6.51022184,9.99247129 C6.53977721,10.0233461 6.56379059,10.0600094 6.5822627,10.1024622 L6.5822627,10.4034901 C6.56379059,10.4420836 6.53977721,10.4787469 6.51022184,10.5134811 L2.57568253,14.6236695 Z" transform="translate(4.454287, 10.252976) scale(1, -1) rotate(90.000000) translate(-4.454287, -10.252976) "></path></svg>
diff --git a/app/assets/javascripts/diff_notes/mixins/discussion.js b/app/assets/javascripts/diff_notes/mixins/discussion.js
deleted file mode 100644
index ef3001393cf..00000000000
--- a/app/assets/javascripts/diff_notes/mixins/discussion.js
+++ /dev/null
@@ -1,37 +0,0 @@
-/* eslint-disable guard-for-in, no-restricted-syntax, */
-
-const DiscussionMixins = {
- computed: {
- discussionCount() {
- return Object.keys(this.discussions).length;
- },
- resolvedDiscussionCount() {
- let resolvedCount = 0;
-
- for (const discussionId in this.discussions) {
- const discussion = this.discussions[discussionId];
-
- if (discussion.isResolved()) {
- resolvedCount += 1;
- }
- }
-
- return resolvedCount;
- },
- unresolvedDiscussionCount() {
- let unresolvedCount = 0;
-
- for (const discussionId in this.discussions) {
- const discussion = this.discussions[discussionId];
-
- if (!discussion.isResolved()) {
- unresolvedCount += 1;
- }
- }
-
- return unresolvedCount;
- },
- },
-};
-
-export default DiscussionMixins;
diff --git a/app/assets/javascripts/diff_notes/models/discussion.js b/app/assets/javascripts/diff_notes/models/discussion.js
deleted file mode 100644
index 97296a40d6e..00000000000
--- a/app/assets/javascripts/diff_notes/models/discussion.js
+++ /dev/null
@@ -1,99 +0,0 @@
-/* eslint-disable guard-for-in, no-restricted-syntax */
-/* global NoteModel */
-
-import $ from 'jquery';
-import Vue from 'vue';
-import { localTimeAgo } from '../../lib/utils/datetime_utility';
-
-class DiscussionModel {
- constructor(discussionId) {
- this.id = discussionId;
- this.notes = {};
- this.loading = false;
- this.canResolve = false;
- }
-
- createNote(noteObj) {
- Vue.set(this.notes, noteObj.noteId, new NoteModel(this.id, noteObj));
- }
-
- deleteNote(noteId) {
- Vue.delete(this.notes, noteId);
- }
-
- getNote(noteId) {
- return this.notes[noteId];
- }
-
- notesCount() {
- return Object.keys(this.notes).length;
- }
-
- isResolved() {
- for (const noteId in this.notes) {
- const note = this.notes[noteId];
-
- if (!note.resolved) {
- return false;
- }
- }
- return true;
- }
-
- resolveAllNotes(resolvedBy) {
- for (const noteId in this.notes) {
- const note = this.notes[noteId];
-
- if (!note.resolved) {
- note.resolved = true;
- note.resolved_by = resolvedBy;
- }
- }
- }
-
- unResolveAllNotes() {
- for (const noteId in this.notes) {
- const note = this.notes[noteId];
-
- if (note.resolved) {
- note.resolved = false;
- note.resolved_by = null;
- }
- }
- }
-
- updateHeadline(data) {
- const discussionSelector = `.discussion[data-discussion-id="${this.id}"]`;
- const $discussionHeadline = $(`${discussionSelector} .js-discussion-headline`);
-
- if (data.discussion_headline_html) {
- if ($discussionHeadline.length) {
- $discussionHeadline.replaceWith(data.discussion_headline_html);
- } else {
- $(`${discussionSelector} .discussion-header`).append(data.discussion_headline_html);
- }
-
- localTimeAgo($('.js-timeago', `${discussionSelector}`));
- } else {
- $discussionHeadline.remove();
- }
- }
-
- isResolvable() {
- if (!this.canResolve) {
- return false;
- }
-
- for (const noteId in this.notes) {
- const note = this.notes[noteId];
-
- if (note.canResolve) {
- return true;
- }
- }
-
- return false;
- }
-}
-
-window.DiscussionModel = DiscussionModel;
diff --git a/app/assets/javascripts/diff_notes/models/note.js b/app/assets/javascripts/diff_notes/models/note.js
deleted file mode 100644
index 825a69deeec..00000000000
--- a/app/assets/javascripts/diff_notes/models/note.js
+++ /dev/null
@@ -1,14 +0,0 @@
-class NoteModel {
- constructor(discussionId, noteObj) {
- this.discussionId = discussionId;
- this.id = noteObj.noteId;
- this.canResolve = noteObj.canResolve;
- this.resolved = noteObj.resolved;
- this.resolved_by = noteObj.resolvedBy;
- this.authorName = noteObj.authorName;
- this.authorAvatar = noteObj.authorAvatar;
- this.noteTruncated = noteObj.noteTruncated;
- }
-}
-
-window.NoteModel = NoteModel;
diff --git a/app/assets/javascripts/diff_notes/services/resolve.js b/app/assets/javascripts/diff_notes/services/resolve.js
deleted file mode 100644
index d6975963977..00000000000
--- a/app/assets/javascripts/diff_notes/services/resolve.js
+++ /dev/null
@@ -1,86 +0,0 @@
-/* global CommentsStore */
-
-import Vue from 'vue';
-import { deprecatedCreateFlash as Flash } from '../../flash';
-import { __ } from '~/locale';
-
-window.gl = window.gl || {};
-
-class ResolveServiceClass {
- constructor(root) {
- this.noteResource = Vue.resource(`${root}/notes{/noteId}/resolve?html=true`);
- this.discussionResource = Vue.resource(
- `${root}/merge_requests{/mergeRequestId}/discussions{/discussionId}/resolve?html=true`,
- );
- }
-
- resolve(noteId) {
- return this.noteResource.save({ noteId }, {});
- }
-
- unresolve(noteId) {
- return this.noteResource.delete({ noteId }, {});
- }
-
- toggleResolveForDiscussion(mergeRequestId, discussionId) {
- const discussion = CommentsStore.state[discussionId];
- const isResolved = discussion.isResolved();
- let promise;
-
- if (isResolved) {
- promise = this.unResolveAll(mergeRequestId, discussionId);
- } else {
- promise = this.resolveAll(mergeRequestId, discussionId);
- }
-
- promise
- .then(resp => resp.json())
- .then(data => {
- discussion.loading = false;
- const resolvedBy = data ? data.resolved_by : null;
-
- if (isResolved) {
- discussion.unResolveAllNotes();
- } else {
- discussion.resolveAllNotes(resolvedBy);
- }
-
- if (gl.mrWidget) gl.mrWidget.checkStatus();
- discussion.updateHeadline(data);
- })
- .catch(
- () =>
- new Flash(__('An error occurred when trying to resolve a discussion. Please try again.')),
- );
- }
-
- resolveAll(mergeRequestId, discussionId) {
- const discussion = CommentsStore.state[discussionId];
-
- discussion.loading = true;
-
- return this.discussionResource.save(
- {
- mergeRequestId,
- discussionId,
- },
- {},
- );
- }
-
- unResolveAll(mergeRequestId, discussionId) {
- const discussion = CommentsStore.state[discussionId];
-
- discussion.loading = true;
-
- return this.discussionResource.delete(
- {
- mergeRequestId,
- discussionId,
- },
- {},
- );
- }
-}
-
-gl.DiffNotesResolveServiceClass = ResolveServiceClass;
diff --git a/app/assets/javascripts/diff_notes/stores/comments.js b/app/assets/javascripts/diff_notes/stores/comments.js
deleted file mode 100644
index 9bde18c4edf..00000000000
--- a/app/assets/javascripts/diff_notes/stores/comments.js
+++ /dev/null
@@ -1,56 +0,0 @@
-/* eslint-disable no-restricted-syntax, guard-for-in */
-/* global DiscussionModel */
-
-import Vue from 'vue';
-
-window.CommentsStore = {
- state: {},
- get(discussionId, noteId) {
- return this.state[discussionId].getNote(noteId);
- },
- createDiscussion(discussionId, canResolve) {
- let discussion = this.state[discussionId];
- if (!this.state[discussionId]) {
- discussion = new DiscussionModel(discussionId);
- Vue.set(this.state, discussionId, discussion);
- }
-
- if (canResolve !== undefined) {
- discussion.canResolve = canResolve;
- }
-
- return discussion;
- },
- create(noteObj) {
- const discussion = this.createDiscussion(noteObj.discussionId);
-
- discussion.createNote(noteObj);
- },
- update(discussionId, noteId, resolved, resolvedBy) {
- const discussion = this.state[discussionId];
- const note = discussion.getNote(noteId);
- note.resolved = resolved;
- note.resolved_by = resolvedBy;
- },
- delete(discussionId, noteId) {
- const discussion = this.state[discussionId];
- discussion.deleteNote(noteId);
-
- if (discussion.notesCount() === 0) {
- Vue.delete(this.state, discussionId);
- }
- },
- unresolvedDiscussionIds() {
- const ids = [];
-
- for (const discussionId in this.state) {
- const discussion = this.state[discussionId];
-
- if (!discussion.isResolved()) {
- ids.push(discussion.id);
- }
- }
-
- return ids;
- },
-};
diff --git a/app/assets/javascripts/diffs/components/app.vue b/app/assets/javascripts/diffs/components/app.vue
index dd5addbf1e3..085f951147f 100644
--- a/app/assets/javascripts/diffs/components/app.vue
+++ b/app/assets/javascripts/diffs/components/app.vue
@@ -474,7 +474,7 @@ export default {
<div
v-if="showTreeList"
:style="{ width: `${treeWidth}px` }"
- class="diff-tree-list js-diff-tree-list mr-3"
+ class="diff-tree-list js-diff-tree-list px-3 pr-md-0"
>
<panel-resizer
:size.sync="treeWidth"
@@ -487,7 +487,7 @@ export default {
<tree-list :hide-file-stats="hideFileStats" />
</div>
<div
- class="diff-files-holder"
+ class="col-12 col-md-auto diff-files-holder"
:class="{
[CENTERED_LIMITED_CONTAINER_CLASSES]: isLimitedContainer,
}"
diff --git a/app/assets/javascripts/diffs/components/collapsed_files_warning.vue b/app/assets/javascripts/diffs/components/collapsed_files_warning.vue
index dded3643115..270bbfb99b7 100644
--- a/app/assets/javascripts/diffs/components/collapsed_files_warning.vue
+++ b/app/assets/javascripts/diffs/components/collapsed_files_warning.vue
@@ -50,7 +50,7 @@ export default {
</script>
<template>
- <div v-if="!isDismissed" data-testid="root" :class="containerClasses">
+ <div v-if="!isDismissed" data-testid="root" :class="containerClasses" class="col-12">
<gl-alert
:dismissible="true"
:title="__('Some changes are not shown')"
diff --git a/app/assets/javascripts/diffs/components/commit_item.vue b/app/assets/javascripts/diffs/components/commit_item.vue
index 23669eecce2..1b747fb7f20 100644
--- a/app/assets/javascripts/diffs/components/commit_item.vue
+++ b/app/assets/javascripts/diffs/components/commit_item.vue
@@ -1,7 +1,7 @@
<script>
/* eslint-disable vue/no-v-html */
import { mapActions } from 'vuex';
-import { GlButtonGroup, GlButton, GlIcon, GlTooltipDirective } from '@gitlab/ui';
+import { GlButtonGroup, GlButton, GlTooltipDirective, GlIcon } from '@gitlab/ui';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
@@ -122,74 +122,27 @@ export default {
</script>
<template>
- <li :class="{ 'js-toggle-container': collapsible }" class="commit flex-row">
- <div class="d-flex align-items-center align-self-start">
- <input
- v-if="isSelectable"
- class="mr-2"
- type="checkbox"
- :checked="checked"
- @change="$emit('handleCheckboxChange', $event.target.checked)"
- />
- <user-avatar-link
- :link-href="authorUrl"
- :img-src="authorAvatar"
- :img-alt="authorName"
- :img-size="40"
- class="avatar-cell d-none d-sm-block"
- />
- </div>
- <div class="commit-detail flex-list">
- <div class="commit-content qa-commit-content">
- <a
- :href="commit.commit_url"
- class="commit-row-message item-title"
- v-html="commit.title_html"
- ></a>
-
- <span class="commit-row-message d-block d-sm-none">&middot; {{ commit.short_id }}</span>
-
- <gl-button
- v-if="commit.description_html && collapsible"
- class="js-toggle-button"
- size="small"
- icon="ellipsis_h"
- :aria-label="__('Toggle commit description')"
- />
-
- <div class="committer">
- <a
- :href="authorUrl"
- :class="authorClass"
- :data-user-id="authorId"
- v-text="authorName"
- ></a>
- {{ s__('CommitWidget|authored') }}
- <time-ago-tooltip :time="commit.authored_date" />
- </div>
-
- <pre
- v-if="commit.description_html"
- :class="{ 'js-toggle-content': collapsible, 'd-block': !collapsible }"
- class="commit-row-description gl-mb-3 text-dark"
- v-html="commitDescription"
- ></pre>
- </div>
- <div class="commit-actions flex-row d-none d-sm-flex">
+ <li :class="{ 'js-toggle-container': collapsible }" class="commit">
+ <div
+ class="d-block d-sm-flex flex-row-reverse justify-content-between align-items-start flex-lg-row-reverse"
+ >
+ <div
+ class="commit-actions flex-row d-none d-sm-flex align-items-start flex-wrap justify-content-end"
+ >
<div v-if="commit.signature_html" v-html="commit.signature_html"></div>
<commit-pipeline-status
v-if="commit.pipeline_status_path"
:endpoint="commit.pipeline_status_path"
- class="d-inline-flex"
+ class="d-inline-flex mb-2"
/>
- <div class="commit-sha-group">
- <div class="label label-monospace monospace" v-text="commit.short_id"></div>
+ <gl-button-group class="gl-ml-4 gl-mb-4" data-testid="commit-sha-group">
+ <gl-button label class="gl-font-monospace" v-text="commit.short_id" />
<clipboard-button
:text="commit.id"
:title="__('Copy commit SHA')"
- class="btn btn-default"
+ class="input-group-text"
/>
- </div>
+ </gl-button-group>
<div
v-if="hasNeighborCommits && glFeatures.mrCommitNeighborNav"
class="commit-nav-buttons ml-3"
@@ -226,6 +179,62 @@ export default {
</gl-button-group>
</div>
</div>
+ <div>
+ <div class="d-flex float-left align-items-center align-self-start">
+ <input
+ v-if="isSelectable"
+ class="mr-2"
+ type="checkbox"
+ :checked="checked"
+ @change="$emit('handleCheckboxChange', $event.target.checked)"
+ />
+ <user-avatar-link
+ :link-href="authorUrl"
+ :img-src="authorAvatar"
+ :img-alt="authorName"
+ :img-size="40"
+ class="avatar-cell d-none d-sm-block"
+ />
+ </div>
+ <div class="commit-detail flex-list">
+ <div class="commit-content qa-commit-content">
+ <a
+ :href="commit.commit_url"
+ class="commit-row-message item-title"
+ v-html="commit.title_html"
+ ></a>
+
+ <span class="commit-row-message d-block d-sm-none">&middot; {{ commit.short_id }}</span>
+
+ <gl-button
+ v-if="commit.description_html && collapsible"
+ class="js-toggle-button"
+ size="small"
+ icon="ellipsis_h"
+ :aria-label="__('Toggle commit description')"
+ />
+
+ <div class="committer">
+ <a
+ :href="authorUrl"
+ :class="authorClass"
+ :data-user-id="authorId"
+ v-text="authorName"
+ ></a>
+ {{ s__('CommitWidget|authored') }}
+ <time-ago-tooltip :time="commit.authored_date" />
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div>
+ <pre
+ v-if="commit.description_html"
+ :class="{ 'js-toggle-content': collapsible, 'd-block': !collapsible }"
+ class="commit-row-description gl-mb-3 text-dark"
+ v-html="commitDescription"
+ ></pre>
</div>
</li>
</template>
diff --git a/app/assets/javascripts/diffs/components/commit_widget.vue b/app/assets/javascripts/diffs/components/commit_widget.vue
index 5c7e84bd87c..b1a2b2a72ea 100644
--- a/app/assets/javascripts/diffs/components/commit_widget.vue
+++ b/app/assets/javascripts/diffs/components/commit_widget.vue
@@ -1,19 +1,6 @@
<script>
import CommitItem from './commit_item.vue';
-/**
- * CommitWidget
- *
- * -----------------------------------------------------------------
- * WARNING: Please keep changes up-to-date with the following files:
- * - `views/projects/merge_requests/diffs/_commit_widget.html.haml`
- * -----------------------------------------------------------------
- *
- * This Component was cloned from a HAML view. For the time being,
- * they coexist, but there is an issue to remove the duplication.
- * https://gitlab.com/gitlab-org/gitlab-foss/issues/51613
- *
- */
export default {
components: {
CommitItem,
diff --git a/app/assets/javascripts/diffs/components/compare_dropdown_layout.vue b/app/assets/javascripts/diffs/components/compare_dropdown_layout.vue
index 8263e938e69..adef5d94624 100644
--- a/app/assets/javascripts/diffs/components/compare_dropdown_layout.vue
+++ b/app/assets/javascripts/diffs/components/compare_dropdown_layout.vue
@@ -32,7 +32,7 @@ export default {
<gl-icon :size="12" name="angle-down" class="position-absolute" />
</a>
<div class="dropdown-menu dropdown-select dropdown-menu-selectable">
- <div class="dropdown-content">
+ <div class="dropdown-content" data-qa-selector="dropdown_content">
<ul>
<li v-for="version in versions" :key="version.id">
<a :class="{ 'is-active': version.selected }" :href="version.href">
diff --git a/app/assets/javascripts/diffs/components/compare_versions.vue b/app/assets/javascripts/diffs/components/compare_versions.vue
index b94874c5644..b1ebd8e6ebc 100644
--- a/app/assets/javascripts/diffs/components/compare_versions.vue
+++ b/app/assets/javascripts/diffs/components/compare_versions.vue
@@ -100,6 +100,7 @@ export default {
<compare-dropdown-layout
:versions="diffCompareDropdownTargetVersions"
class="mr-version-compare-dropdown"
+ data-qa-selector="target_version_dropdown"
/>
</template>
<template #source>
diff --git a/app/assets/javascripts/diffs/components/diff_content.vue b/app/assets/javascripts/diffs/components/diff_content.vue
index 9ecb9a44443..e68260b3e62 100644
--- a/app/assets/javascripts/diffs/components/diff_content.vue
+++ b/app/assets/javascripts/diffs/components/diff_content.vue
@@ -85,11 +85,9 @@ export default {
},
},
updated() {
- if (window.gon?.features?.codeNavigation) {
- this.$nextTick(() => {
- eventHub.$emit('showBlobInteractionZones', this.diffFile.new_path);
- });
- }
+ this.$nextTick(() => {
+ eventHub.$emit('showBlobInteractionZones', this.diffFile.new_path);
+ });
},
methods: {
...mapActions('diffs', ['saveDiffDiscussion', 'closeDiffFileCommentForm']),
diff --git a/app/assets/javascripts/diffs/components/diff_file.vue b/app/assets/javascripts/diffs/components/diff_file.vue
index 02396a4ba1b..529723a349d 100644
--- a/app/assets/javascripts/diffs/components/diff_file.vue
+++ b/app/assets/javascripts/diffs/components/diff_file.vue
@@ -44,7 +44,7 @@ export default {
return {
isLoadingCollapsedDiff: false,
forkMessageVisible: false,
- isCollapsed: this.file.viewer.collapsed || false,
+ isCollapsed: this.file.viewer.automaticallyCollapsed || false,
};
},
computed: {
@@ -96,16 +96,16 @@ export default {
},
'file.file_hash': {
handler: function watchFileHash() {
- if (this.viewDiffsFileByFile && this.file.viewer.collapsed) {
+ if (this.viewDiffsFileByFile && this.file.viewer.automaticallyCollapsed) {
this.isCollapsed = false;
this.handleLoadCollapsedDiff();
} else {
- this.isCollapsed = this.file.viewer.collapsed || false;
+ this.isCollapsed = this.file.viewer.automaticallyCollapsed || false;
}
},
immediate: true,
},
- 'file.viewer.collapsed': function setIsCollapsed(newVal) {
+ 'file.viewer.automaticallyCollapsed': function setIsCollapsed(newVal) {
if (!this.viewDiffsFileByFile) {
this.isCollapsed = newVal;
}
diff --git a/app/assets/javascripts/diffs/components/diff_file_header.vue b/app/assets/javascripts/diffs/components/diff_file_header.vue
index fded391cc84..b08b9df13a4 100644
--- a/app/assets/javascripts/diffs/components/diff_file_header.vue
+++ b/app/assets/javascripts/diffs/components/diff_file_header.vue
@@ -1,39 +1,44 @@
<script>
-/* eslint-disable vue/no-v-html */
import { escape } from 'lodash';
import { mapActions, mapGetters } from 'vuex';
import {
- GlDeprecatedButton,
GlTooltipDirective,
GlSafeHtmlDirective,
- GlLoadingIcon,
GlIcon,
GlButton,
+ GlButtonGroup,
+ GlDropdown,
+ GlDropdownItem,
+ GlDropdownDivider,
} from '@gitlab/ui';
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
import FileIcon from '~/vue_shared/components/file_icon.vue';
import { truncateSha } from '~/lib/utils/text_utility';
import { __, s__, sprintf } from '~/locale';
import { diffViewerModes } from '~/ide/constants';
-import EditButton from './edit_button.vue';
import DiffStats from './diff_stats.vue';
import { scrollToElement } from '~/lib/utils/common_utils';
+import { DIFF_FILE_HEADER } from '../i18n';
export default {
components: {
- GlLoadingIcon,
- GlDeprecatedButton,
ClipboardButton,
- EditButton,
GlIcon,
FileIcon,
DiffStats,
GlButton,
+ GlButtonGroup,
+ GlDropdown,
+ GlDropdownItem,
+ GlDropdownDivider,
},
directives: {
GlTooltip: GlTooltipDirective,
SafeHtml: GlSafeHtmlDirective,
},
+ i18n: {
+ ...DIFF_FILE_HEADER,
+ },
props: {
discussionPath: {
type: String,
@@ -69,6 +74,11 @@ export default {
default: false,
},
},
+ data() {
+ return {
+ moreActionsShown: false,
+ };
+ },
computed: {
...mapGetters('diffs', ['diffHasExpandedDiscussions', 'diffHasDiscussions']),
diffContentIDSelector() {
@@ -128,13 +138,9 @@ export default {
},
viewReplacedFileButtonText() {
const truncatedBaseSha = escape(truncateSha(this.diffFile.diff_refs.base_sha));
- return sprintf(
- s__('MergeRequests|View replaced file @ %{commitId}'),
- {
- commitId: `<span class="commit-sha">${truncatedBaseSha}</span>`,
- },
- false,
- );
+ return sprintf(s__('MergeRequests|View replaced file @ %{commitId}'), {
+ commitId: truncatedBaseSha,
+ });
},
gfmCopyText() {
return `\`${this.diffFile.file_path}\``;
@@ -151,6 +157,13 @@ export default {
}
return s__('MRDiff|Show full file');
},
+ showEditButton() {
+ return (
+ this.diffFile.blob?.readable_text &&
+ !this.diffFile.deleted_file &&
+ (this.diffFile.edit_path || this.diffFile.ide_edit_path)
+ );
+ },
},
methods: {
...mapActions('diffs', [
@@ -162,8 +175,11 @@ export default {
handleToggleFile() {
this.$emit('toggleFile');
},
- showForkMessage() {
- this.$emit('showForkMessage');
+ showForkMessage(e) {
+ if (this.canCurrentUserFork && !this.diffFile.can_modify_blob) {
+ e.preventDefault();
+ this.$emit('showForkMessage');
+ }
},
handleFileNameClick(e) {
const isLinkToOtherPage =
@@ -179,6 +195,9 @@ export default {
}
}
},
+ setMoreActionsShown(val) {
+ this.moreActionsShown = val;
+ },
},
};
</script>
@@ -186,10 +205,11 @@ export default {
<template>
<div
ref="header"
+ :class="{ 'gl-z-dropdown-menu!': moreActionsShown }"
class="js-file-title file-title file-title-flex-parent"
@click.self="handleToggleFile"
>
- <div class="file-header-content">
+ <div class="file-header-content gl-display-flex gl-align-items-center gl-pr-0!">
<gl-icon
v-if="collapsible"
ref="collapseIcon"
@@ -202,7 +222,7 @@ export default {
<a
ref="titleWrapper"
:v-once="!viewDiffsFileByFile"
- class="gl-mr-2"
+ class="gl-mr-2 gl-text-decoration-none!"
:href="titleLink"
@click="handleFileNameClick"
>
@@ -210,20 +230,27 @@ export default {
<span v-if="isFileRenamed">
<strong
v-gl-tooltip
+ v-safe-html="diffFile.old_path_html"
:title="diffFile.old_path"
class="file-title-name"
- v-html="diffFile.old_path_html"
></strong>
→
<strong
v-gl-tooltip
+ v-safe-html="diffFile.new_path_html"
:title="diffFile.new_path"
class="file-title-name"
- v-html="diffFile.new_path_html"
></strong>
</span>
- <strong v-else v-gl-tooltip :title="filePath" class="file-title-name" data-container="body">
+ <strong
+ v-else
+ v-gl-tooltip
+ :title="filePath"
+ class="file-title-name"
+ data-container="body"
+ data-qa-selector="file_name_content"
+ >
{{ filePath }}
</strong>
</a>
@@ -232,7 +259,8 @@ export default {
:title="__('Copy file path')"
:text="diffFile.file_path"
:gfm="gfmCopyText"
- css-class="btn-default btn-transparent btn-clipboard"
+ data-testid="diff-file-copy-clipboard"
+ category="tertiary"
data-track-event="click_copy_file_button"
data-track-label="diff_copy_file_path_button"
data-track-property="diff_copy_file"
@@ -247,93 +275,93 @@ export default {
<div
v-if="!diffFile.submodule && addMergeRequestButtons"
- class="file-actions d-none d-sm-flex align-items-center flex-wrap"
+ class="file-actions d-flex align-items-center flex-wrap"
>
<diff-stats :added-lines="diffFile.added_lines" :removed-lines="diffFile.removed_lines" />
- <div class="btn-group" role="group">
- <template v-if="diffFile.blob && diffFile.blob.readable_text">
- <span v-gl-tooltip.hover :title="s__('MergeRequests|Toggle comments for this file')">
- <gl-deprecated-button
- ref="toggleDiscussionsButton"
- :disabled="!diffHasDiscussions(diffFile)"
- :class="{ active: diffHasExpandedDiscussions(diffFile) }"
- class="js-btn-vue-toggle-comments btn"
- data-qa-selector="toggle_comments_button"
- data-track-event="click_toggle_comments_button"
- data-track-label="diff_toggle_comments_button"
- data-track-property="diff_toggle_comments"
- type="button"
- @click="toggleFileDiscussionWrappers(diffFile)"
- >
- <gl-icon name="comment" />
- </gl-deprecated-button>
- </span>
-
- <edit-button
- v-if="!diffFile.deleted_file"
- :can-current-user-fork="canCurrentUserFork"
- :edit-path="diffFile.edit_path"
- :can-modify-blob="diffFile.can_modify_blob"
- data-track-event="click_toggle_edit_button"
- data-track-label="diff_toggle_edit_button"
- data-track-property="diff_toggle_edit"
- @showForkMessage="showForkMessage"
- />
- </template>
-
- <a
- v-if="diffFile.replaced_view_path"
- ref="replacedFileButton"
- :href="diffFile.replaced_view_path"
- class="btn view-file"
- v-html="viewReplacedFileButtonText"
- >
- </a>
- <gl-deprecated-button
- v-if="!diffFile.is_fully_expanded"
- ref="expandDiffToFullFileButton"
- v-gl-tooltip.hover
- :title="expandDiffToFullFileTitle"
- class="expand-file"
- data-track-event="click_toggle_view_full_button"
- data-track-label="diff_toggle_view_full_button"
- data-track-property="diff_toggle_view_full"
- @click="toggleFullDiff(diffFile.file_path)"
- >
- <gl-loading-icon v-if="diffFile.isLoadingFullFile" color="dark" inline />
- <gl-icon v-else-if="diffFile.isShowingFullFile" name="doc-changes" />
- <gl-icon v-else name="doc-expand" />
- </gl-deprecated-button>
- <gl-deprecated-button
- ref="viewButton"
- v-gl-tooltip.hover
- :href="diffFile.view_path"
- target="_blank"
- class="view-file"
- data-track-event="click_toggle_view_sha_button"
- data-track-label="diff_toggle_view_sha_button"
- data-track-property="diff_toggle_view_sha"
- :title="viewFileButtonText"
- >
- <gl-icon name="doc-text" />
- </gl-deprecated-button>
-
- <a
+ <gl-button-group class="gl-pt-0!">
+ <gl-button
v-if="diffFile.external_url"
ref="externalLink"
v-gl-tooltip.hover
:href="diffFile.external_url"
:title="`View on ${diffFile.formatted_external_url}`"
target="_blank"
- rel="noopener noreferrer"
data-track-event="click_toggle_external_button"
data-track-label="diff_toggle_external_button"
data-track-property="diff_toggle_external"
- class="btn btn-file-option"
+ icon="external-link"
+ />
+ <gl-dropdown
+ v-gl-tooltip.hover.focus="$options.i18n.optionsDropdownTitle"
+ right
+ toggle-class="btn-icon js-diff-more-actions"
+ class="gl-pt-0!"
+ @show="setMoreActionsShown(true)"
+ @hidden="setMoreActionsShown(false)"
>
- <gl-icon name="external-link" />
- </a>
- </div>
+ <template #button-content>
+ <gl-icon name="ellipsis_v" class="mr-0" />
+ <span class="sr-only">{{ $options.i18n.optionsDropdownTitle }}</span>
+ </template>
+ <gl-dropdown-item
+ v-if="diffFile.replaced_view_path"
+ ref="replacedFileButton"
+ :href="diffFile.replaced_view_path"
+ target="_blank"
+ >
+ {{ viewReplacedFileButtonText }}
+ </gl-dropdown-item>
+ <gl-dropdown-item ref="viewButton" :href="diffFile.view_path" target="_blank">
+ {{ viewFileButtonText }}
+ </gl-dropdown-item>
+ <template v-if="showEditButton">
+ <gl-dropdown-item
+ v-if="diffFile.edit_path"
+ ref="editButton"
+ :href="diffFile.edit_path"
+ class="js-edit-blob"
+ @click="showForkMessage"
+ >
+ {{ __('Edit in single-file editor') }}
+ </gl-dropdown-item>
+ <gl-dropdown-item
+ v-if="diffFile.edit_path"
+ ref="ideEditButton"
+ :href="diffFile.ide_edit_path"
+ class="js-ide-edit-blob"
+ >
+ {{ __('Edit in Web IDE') }}
+ </gl-dropdown-item>
+ </template>
+
+ <template v-if="!diffFile.viewer.automaticallyCollapsed">
+ <gl-dropdown-divider
+ v-if="!diffFile.is_fully_expanded || diffHasDiscussions(diffFile)"
+ />
+
+ <gl-dropdown-item
+ v-if="diffHasDiscussions(diffFile)"
+ ref="toggleDiscussionsButton"
+ data-qa-selector="toggle_comments_button"
+ @click="toggleFileDiscussionWrappers(diffFile)"
+ >
+ <template v-if="diffHasExpandedDiscussions(diffFile)">
+ {{ __('Hide comments on this file') }}
+ </template>
+ <template v-else>
+ {{ __('Show comments on this file') }}
+ </template>
+ </gl-dropdown-item>
+ <gl-dropdown-item
+ v-if="!diffFile.is_fully_expanded"
+ ref="expandDiffToFullFileButton"
+ @click="toggleFullDiff(diffFile.file_path)"
+ >
+ {{ expandDiffToFullFileTitle }}
+ </gl-dropdown-item>
+ </template>
+ </gl-dropdown>
+ </gl-button-group>
</div>
<div
diff --git a/app/assets/javascripts/diffs/components/diff_row_utils.js b/app/assets/javascripts/diffs/components/diff_row_utils.js
new file mode 100644
index 00000000000..08b87a4bade
--- /dev/null
+++ b/app/assets/javascripts/diffs/components/diff_row_utils.js
@@ -0,0 +1,85 @@
+import { __ } from '~/locale';
+import {
+ MATCH_LINE_TYPE,
+ CONTEXT_LINE_TYPE,
+ LINE_HOVER_CLASS_NAME,
+ OLD_NO_NEW_LINE_TYPE,
+ NEW_NO_NEW_LINE_TYPE,
+ EMPTY_CELL_TYPE,
+} from '../constants';
+
+export const isHighlighted = (state, line, isCommented) => {
+ if (isCommented) return true;
+
+ const lineCode = line?.line_code;
+ return lineCode ? lineCode === state.diffs.highlightedRow : false;
+};
+
+export const isContextLine = type => type === CONTEXT_LINE_TYPE;
+
+export const isMatchLine = type => type === MATCH_LINE_TYPE;
+
+export const isMetaLine = type =>
+ [OLD_NO_NEW_LINE_TYPE, NEW_NO_NEW_LINE_TYPE, EMPTY_CELL_TYPE].includes(type);
+
+export const shouldRenderCommentButton = (isLoggedIn, isCommentButtonRendered) => {
+ return isCommentButtonRendered && isLoggedIn;
+};
+
+export const hasDiscussions = line => line?.discussions?.length > 0;
+
+export const lineHref = line => `#${line?.line_code || ''}`;
+
+export const lineCode = line => {
+ if (!line) return undefined;
+ return line.line_code || line.left?.line_code || line.right?.line_code;
+};
+
+export const classNameMapCell = (line, hll, isLoggedIn, isHover) => {
+ if (!line) return [];
+ const { type } = line;
+
+ return [
+ type,
+ {
+ hll,
+ [LINE_HOVER_CLASS_NAME]: isLoggedIn && isHover && !isContextLine(type) && !isMetaLine(type),
+ },
+ ];
+};
+
+export const addCommentTooltip = line => {
+ let tooltip;
+ if (!line) return tooltip;
+
+ tooltip = __('Add a comment to this line');
+ const brokenSymlinks = line.commentsDisabled;
+
+ if (brokenSymlinks) {
+ if (brokenSymlinks.wasSymbolic || brokenSymlinks.isSymbolic) {
+ tooltip = __(
+ 'Commenting on symbolic links that replace or are replaced by files is currently not supported.',
+ );
+ } else if (brokenSymlinks.wasReal || brokenSymlinks.isReal) {
+ tooltip = __(
+ 'Commenting on files that replace or are replaced by symbolic links is currently not supported.',
+ );
+ }
+ }
+
+ return tooltip;
+};
+
+export const parallelViewLeftLineType = (line, hll) => {
+ if (line?.right?.type === NEW_NO_NEW_LINE_TYPE) {
+ return OLD_NO_NEW_LINE_TYPE;
+ }
+
+ const lineTypeClass = line?.left ? line.left.type : EMPTY_CELL_TYPE;
+
+ return [lineTypeClass, { hll }];
+};
+
+export const shouldShowCommentButton = (hover, context, meta, discussions) => {
+ return hover && !context && !meta && !discussions;
+};
diff --git a/app/assets/javascripts/diffs/components/diff_stats.vue b/app/assets/javascripts/diffs/components/diff_stats.vue
index 05fbbd39fae..f229fc4cf60 100644
--- a/app/assets/javascripts/diffs/components/diff_stats.vue
+++ b/app/assets/javascripts/diffs/components/diff_stats.vue
@@ -42,7 +42,7 @@ export default {
class="diff-stats"
:class="{
'is-compare-versions-header d-none d-lg-inline-flex': isCompareVersionsHeader,
- 'd-inline-flex': !isCompareVersionsHeader,
+ 'd-none d-sm-inline-flex': !isCompareVersionsHeader,
}"
>
<div v-if="hasDiffFiles" class="diff-stats-group">
diff --git a/app/assets/javascripts/diffs/components/diff_table_cell.vue b/app/assets/javascripts/diffs/components/diff_table_cell.vue
deleted file mode 100644
index 49982a81372..00000000000
--- a/app/assets/javascripts/diffs/components/diff_table_cell.vue
+++ /dev/null
@@ -1,206 +0,0 @@
-<script>
-import { mapGetters, mapActions } from 'vuex';
-import { GlIcon, GlTooltipDirective } from '@gitlab/ui';
-import { getParameterByName, parseBoolean } from '~/lib/utils/common_utils';
-import DiffGutterAvatars from './diff_gutter_avatars.vue';
-import { __ } from '~/locale';
-import {
- CONTEXT_LINE_TYPE,
- LINE_POSITION_RIGHT,
- EMPTY_CELL_TYPE,
- OLD_NO_NEW_LINE_TYPE,
- OLD_LINE_TYPE,
- NEW_NO_NEW_LINE_TYPE,
- LINE_HOVER_CLASS_NAME,
-} from '../constants';
-
-export default {
- components: {
- DiffGutterAvatars,
- GlIcon,
- },
- directives: {
- GlTooltip: GlTooltipDirective,
- },
- props: {
- line: {
- type: Object,
- required: true,
- },
- fileHash: {
- type: String,
- required: true,
- },
- isHighlighted: {
- type: Boolean,
- required: true,
- },
- showCommentButton: {
- type: Boolean,
- required: false,
- default: false,
- },
- linePosition: {
- type: String,
- required: false,
- default: '',
- },
- lineType: {
- type: String,
- required: false,
- default: '',
- },
- isBottom: {
- type: Boolean,
- required: false,
- default: false,
- },
- isHover: {
- type: Boolean,
- required: false,
- default: false,
- },
- },
- data() {
- return {
- isCommentButtonRendered: false,
- };
- },
- computed: {
- ...mapGetters(['isLoggedIn']),
- lineCode() {
- return (
- this.line.line_code ||
- (this.line.left && this.line.left.line_code) ||
- (this.line.right && this.line.right.line_code)
- );
- },
- lineHref() {
- return `#${this.line.line_code || ''}`;
- },
- shouldShowCommentButton() {
- return this.isHover && !this.isContextLine && !this.isMetaLine && !this.hasDiscussions;
- },
- hasDiscussions() {
- return this.line.discussions && this.line.discussions.length > 0;
- },
- shouldShowAvatarsOnGutter() {
- if (!this.line.type && this.linePosition === LINE_POSITION_RIGHT) {
- return false;
- }
- return this.showCommentButton && this.hasDiscussions;
- },
- shouldRenderCommentButton() {
- if (!this.isCommentButtonRendered) {
- return false;
- }
-
- if (this.isLoggedIn && this.showCommentButton) {
- const isDiffHead = parseBoolean(getParameterByName('diff_head'));
- return !isDiffHead || gon.features?.mergeRefHeadComments;
- }
-
- return false;
- },
- isContextLine() {
- return this.line.type === CONTEXT_LINE_TYPE;
- },
- isMetaLine() {
- const { type } = this.line;
-
- return (
- type === OLD_NO_NEW_LINE_TYPE || type === NEW_NO_NEW_LINE_TYPE || type === EMPTY_CELL_TYPE
- );
- },
- classNameMap() {
- const { type } = this.line;
-
- return [
- type,
- {
- hll: this.isHighlighted,
- [LINE_HOVER_CLASS_NAME]:
- this.isLoggedIn && this.isHover && !this.isContextLine && !this.isMetaLine,
- },
- ];
- },
- lineNumber() {
- return this.lineType === OLD_LINE_TYPE ? this.line.old_line : this.line.new_line;
- },
- addCommentTooltip() {
- const brokenSymlinks = this.line.commentsDisabled;
- let tooltip = __('Add a comment to this line');
-
- if (brokenSymlinks) {
- if (brokenSymlinks.wasSymbolic || brokenSymlinks.isSymbolic) {
- tooltip = __(
- 'Commenting on symbolic links that replace or are replaced by files is currently not supported.',
- );
- } else if (brokenSymlinks.wasReal || brokenSymlinks.isReal) {
- tooltip = __(
- 'Commenting on files that replace or are replaced by symbolic links is currently not supported.',
- );
- }
- }
-
- return tooltip;
- },
- },
- mounted() {
- this.unwatchShouldShowCommentButton = this.$watch('shouldShowCommentButton', newVal => {
- if (newVal) {
- this.isCommentButtonRendered = true;
- this.unwatchShouldShowCommentButton();
- }
- });
- },
- beforeDestroy() {
- this.unwatchShouldShowCommentButton();
- },
- methods: {
- ...mapActions('diffs', ['showCommentForm', 'setHighlightedRow', 'toggleLineDiscussions']),
- handleCommentButton() {
- this.showCommentForm({ lineCode: this.line.line_code, fileHash: this.fileHash });
- },
- },
-};
-</script>
-
-<template>
- <td ref="td" :class="classNameMap">
- <span
- ref="addNoteTooltip"
- v-gl-tooltip
- class="add-diff-note tooltip-wrapper"
- :title="addCommentTooltip"
- >
- <button
- v-if="shouldRenderCommentButton"
- v-show="shouldShowCommentButton"
- ref="addDiffNoteButton"
- type="button"
- class="add-diff-note note-button js-add-diff-note-button qa-diff-comment"
- :disabled="line.commentsDisabled"
- @click="handleCommentButton"
- >
- <gl-icon :size="12" name="comment" />
- </button>
- </span>
- <a
- v-if="lineNumber"
- ref="lineNumberRef"
- :data-linenumber="lineNumber"
- :href="lineHref"
- @click="setHighlightedRow(lineCode)"
- >
- </a>
- <diff-gutter-avatars
- v-if="shouldShowAvatarsOnGutter"
- :discussions="line.discussions"
- :discussions-expanded="line.discussionsExpanded"
- @toggleLineDiscussions="
- toggleLineDiscussions({ lineCode, fileHash, expanded: !line.discussionsExpanded })
- "
- />
- </td>
-</template>
diff --git a/app/assets/javascripts/diffs/components/edit_button.vue b/app/assets/javascripts/diffs/components/edit_button.vue
deleted file mode 100644
index ff1af5569dc..00000000000
--- a/app/assets/javascripts/diffs/components/edit_button.vue
+++ /dev/null
@@ -1,64 +0,0 @@
-<script>
-import { GlTooltipDirective, GlDeprecatedButton, GlIcon } from '@gitlab/ui';
-import { __ } from '~/locale';
-
-export default {
- components: {
- GlDeprecatedButton,
- GlIcon,
- },
- directives: {
- GlTooltip: GlTooltipDirective,
- },
- props: {
- editPath: {
- type: String,
- required: false,
- default: '',
- },
- canCurrentUserFork: {
- type: Boolean,
- required: true,
- },
- canModifyBlob: {
- type: Boolean,
- required: false,
- default: false,
- },
- },
- computed: {
- tooltipTitle() {
- if (this.isDisabled) {
- return __("Can't edit as source branch was deleted");
- }
-
- return __('Edit file');
- },
- isDisabled() {
- return !this.editPath;
- },
- },
- methods: {
- handleEditClick(evt) {
- if (this.canCurrentUserFork && !this.canModifyBlob) {
- evt.preventDefault();
- this.$emit('showForkMessage');
- }
- },
- },
-};
-</script>
-
-<template>
- <span v-gl-tooltip.top :title="tooltipTitle">
- <gl-deprecated-button
- :href="editPath"
- :disabled="isDisabled"
- :class="{ 'cursor-not-allowed': isDisabled }"
- class="rounded-0 js-edit-blob"
- @click.native="handleEditClick"
- >
- <gl-icon name="pencil" />
- </gl-deprecated-button>
- </span>
-</template>
diff --git a/app/assets/javascripts/diffs/components/inline_diff_table_row.vue b/app/assets/javascripts/diffs/components/inline_diff_table_row.vue
index 7fab750089e..99cf79a70d4 100644
--- a/app/assets/javascripts/diffs/components/inline_diff_table_row.vue
+++ b/app/assets/javascripts/diffs/components/inline_diff_table_row.vue
@@ -1,22 +1,9 @@
<script>
import { mapActions, mapGetters, mapState } from 'vuex';
import { GlTooltipDirective, GlIcon, GlSafeHtmlDirective as SafeHtml } from '@gitlab/ui';
-import {
- MATCH_LINE_TYPE,
- NEW_LINE_TYPE,
- OLD_LINE_TYPE,
- CONTEXT_LINE_TYPE,
- CONTEXT_LINE_CLASS_NAME,
- LINE_POSITION_LEFT,
- LINE_POSITION_RIGHT,
- LINE_HOVER_CLASS_NAME,
- OLD_NO_NEW_LINE_TYPE,
- NEW_NO_NEW_LINE_TYPE,
- EMPTY_CELL_TYPE,
-} from '../constants';
-import { __ } from '~/locale';
-import { getParameterByName, parseBoolean } from '~/lib/utils/common_utils';
+import { CONTEXT_LINE_CLASS_NAME } from '../constants';
import DiffGutterAvatars from './diff_gutter_avatars.vue';
+import * as utils from './diff_row_utils';
export default {
components: {
@@ -61,14 +48,11 @@ export default {
...mapGetters('diffs', ['fileLineCoverage']),
...mapState({
isHighlighted(state) {
- if (this.isCommented) return true;
-
- const lineCode = this.line.line_code;
- return lineCode ? lineCode === state.diffs.highlightedRow : false;
+ return utils.isHighlighted(state, this.line, this.isCommented);
},
}),
isContextLine() {
- return this.line.type === CONTEXT_LINE_TYPE;
+ return utils.isContextLine(this.line.type);
},
classNameMap() {
return [
@@ -82,82 +66,44 @@ export default {
return this.line.line_code || `${this.fileHash}_${this.line.old_line}_${this.line.new_line}`;
},
isMatchLine() {
- return this.line.type === MATCH_LINE_TYPE;
+ return utils.isMatchLine(this.line.type);
},
coverageState() {
return this.fileLineCoverage(this.filePath, this.line.new_line);
},
isMetaLine() {
- const { type } = this.line;
-
- return (
- type === OLD_NO_NEW_LINE_TYPE || type === NEW_NO_NEW_LINE_TYPE || type === EMPTY_CELL_TYPE
- );
+ return utils.isMetaLine(this.line.type);
},
classNameMapCell() {
- const { type } = this.line;
-
- return [
- type,
- {
- hll: this.isHighlighted,
- [LINE_HOVER_CLASS_NAME]:
- this.isLoggedIn && this.isHover && !this.isContextLine && !this.isMetaLine,
- },
- ];
+ return utils.classNameMapCell(this.line, this.isHighlighted, this.isLoggedIn, this.isHover);
},
addCommentTooltip() {
- const brokenSymlinks = this.line.commentsDisabled;
- let tooltip = __('Add a comment to this line');
-
- if (brokenSymlinks) {
- if (brokenSymlinks.wasSymbolic || brokenSymlinks.isSymbolic) {
- tooltip = __(
- 'Commenting on symbolic links that replace or are replaced by files is currently not supported.',
- );
- } else if (brokenSymlinks.wasReal || brokenSymlinks.isReal) {
- tooltip = __(
- 'Commenting on files that replace or are replaced by symbolic links is currently not supported.',
- );
- }
- }
-
- return tooltip;
+ return utils.addCommentTooltip(this.line);
},
shouldRenderCommentButton() {
- if (this.isLoggedIn) {
- const isDiffHead = parseBoolean(getParameterByName('diff_head'));
- return !isDiffHead || gon.features?.mergeRefHeadComments;
- }
-
- return false;
+ return utils.shouldRenderCommentButton(this.isLoggedIn, true);
},
shouldShowCommentButton() {
- return this.isHover && !this.isContextLine && !this.isMetaLine && !this.hasDiscussions;
+ return utils.shouldShowCommentButton(
+ this.isHover,
+ this.isContextLine,
+ this.isMetaLine,
+ this.hasDiscussions,
+ );
},
hasDiscussions() {
- return this.line.discussions && this.line.discussions.length > 0;
+ return utils.hasDiscussions(this.line);
},
lineHref() {
- return `#${this.line.line_code || ''}`;
+ return utils.lineHref(this.line);
},
lineCode() {
- return (
- this.line.line_code ||
- (this.line.left && this.line.left.line_code) ||
- (this.line.right && this.line.right.line_code)
- );
+ return utils.lineCode(this.line);
},
shouldShowAvatarsOnGutter() {
return this.hasDiscussions;
},
},
- created() {
- this.newLineType = NEW_LINE_TYPE;
- this.oldLineType = OLD_LINE_TYPE;
- this.linePositionLeft = LINE_POSITION_LEFT;
- this.linePositionRight = LINE_POSITION_RIGHT;
- },
mounted() {
this.scrollToLineIfNeededInline(this.line);
},
@@ -242,6 +188,7 @@ export default {
class="line-coverage"
></td>
<td
+ :key="line.line_code"
v-safe-html="line.rich_text"
:class="[
line.type,
diff --git a/app/assets/javascripts/diffs/components/parallel_diff_comment_row.vue b/app/assets/javascripts/diffs/components/parallel_diff_comment_row.vue
index b525490f7cc..127e3f214cf 100644
--- a/app/assets/javascripts/diffs/components/parallel_diff_comment_row.vue
+++ b/app/assets/javascripts/diffs/components/parallel_diff_comment_row.vue
@@ -113,8 +113,8 @@ export default {
},
methods: {
...mapActions('diffs', ['showCommentForm']),
- showNewDiscussionForm() {
- this.showCommentForm({ lineCode: this.line.line_code, fileHash: this.diffFileHash });
+ showNewDiscussionForm(lineCode) {
+ this.showCommentForm({ lineCode, fileHash: this.diffFileHash });
},
},
};
@@ -134,7 +134,7 @@ export default {
v-if="!hasDraftLeft"
:has-form="showLeftSideCommentForm"
:render-reply-placeholder="shouldRenderReplyPlaceholderOnLeft"
- @showNewDiscussionForm="showNewDiscussionForm"
+ @showNewDiscussionForm="showNewDiscussionForm(line.left.line_code)"
>
<template #form>
<diff-line-note-form
@@ -159,7 +159,7 @@ export default {
v-if="!hasDraftRight"
:has-form="showRightSideCommentForm"
:render-reply-placeholder="shouldRenderReplyPlaceholderOnRight"
- @showNewDiscussionForm="showNewDiscussionForm"
+ @showNewDiscussionForm="showNewDiscussionForm(line.right.line_code)"
>
<template #form>
<diff-line-note-form
diff --git a/app/assets/javascripts/diffs/components/parallel_diff_table_row.vue b/app/assets/javascripts/diffs/components/parallel_diff_table_row.vue
index 0bf47dc77a6..cdc6db791f0 100644
--- a/app/assets/javascripts/diffs/components/parallel_diff_table_row.vue
+++ b/app/assets/javascripts/diffs/components/parallel_diff_table_row.vue
@@ -2,21 +2,9 @@
import { mapActions, mapGetters, mapState } from 'vuex';
import $ from 'jquery';
import { GlTooltipDirective, GlIcon, GlSafeHtmlDirective as SafeHtml } from '@gitlab/ui';
-import {
- MATCH_LINE_TYPE,
- NEW_LINE_TYPE,
- OLD_LINE_TYPE,
- CONTEXT_LINE_TYPE,
- CONTEXT_LINE_CLASS_NAME,
- OLD_NO_NEW_LINE_TYPE,
- PARALLEL_DIFF_VIEW_TYPE,
- NEW_NO_NEW_LINE_TYPE,
- EMPTY_CELL_TYPE,
- LINE_HOVER_CLASS_NAME,
-} from '../constants';
-import { __ } from '~/locale';
-import { getParameterByName, parseBoolean } from '~/lib/utils/common_utils';
+import { CONTEXT_LINE_CLASS_NAME, PARALLEL_DIFF_VIEW_TYPE } from '../constants';
import DiffGutterAvatars from './diff_gutter_avatars.vue';
+import * as utils from './diff_row_utils';
export default {
components: {
@@ -63,20 +51,15 @@ export default {
...mapGetters(['isLoggedIn']),
...mapState({
isHighlighted(state) {
- if (this.isCommented) return true;
-
- const lineCode =
- (this.line.left && this.line.left.line_code) ||
- (this.line.right && this.line.right.line_code);
-
- return lineCode ? lineCode === state.diffs.highlightedRow : false;
+ const line = this.line.left?.line_code ? this.line.left : this.line.right;
+ return utils.isHighlighted(state, line, this.isCommented);
},
}),
isContextLineLeft() {
- return this.line.left && this.line.left.type === CONTEXT_LINE_TYPE;
+ return utils.isContextLine(this.line.left?.type);
},
isContextLineRight() {
- return this.line.right && this.line.right.type === CONTEXT_LINE_TYPE;
+ return utils.isContextLine(this.line.right?.type);
},
classNameMap() {
return {
@@ -85,157 +68,80 @@ export default {
};
},
parallelViewLeftLineType() {
- if (this.line.right && this.line.right.type === NEW_NO_NEW_LINE_TYPE) {
- return OLD_NO_NEW_LINE_TYPE;
- }
-
- const lineTypeClass = this.line.left ? this.line.left.type : EMPTY_CELL_TYPE;
-
- return [
- lineTypeClass,
- {
- hll: this.isHighlighted,
- },
- ];
+ return utils.parallelViewLeftLineType(this.line, this.isHighlighted);
},
isMatchLineLeft() {
- return this.line.left && this.line.left.type === MATCH_LINE_TYPE;
+ return utils.isMatchLine(this.line.left?.type);
},
isMatchLineRight() {
- return this.line.right && this.line.right.type === MATCH_LINE_TYPE;
+ return utils.isMatchLine(this.line.right?.type);
},
coverageState() {
return this.fileLineCoverage(this.filePath, this.line.right.new_line);
},
classNameMapCellLeft() {
- const { type } = this.line.left;
-
- return [
- type,
- {
- hll: this.isHighlighted,
- [LINE_HOVER_CLASS_NAME]:
- this.isLoggedIn && this.isLeftHover && !this.isContextLineLeft && !this.isMetaLineLeft,
- },
- ];
+ return utils.classNameMapCell(
+ this.line.left,
+ this.isHighlighted,
+ this.isLoggedIn,
+ this.isLeftHover,
+ );
},
classNameMapCellRight() {
- const { type } = this.line.right;
-
- return [
- type,
- {
- hll: this.isHighlighted,
- [LINE_HOVER_CLASS_NAME]:
- this.isLoggedIn &&
- this.isRightHover &&
- !this.isContextLineRight &&
- !this.isMetaLineRight,
- },
- ];
+ return utils.classNameMapCell(
+ this.line.right,
+ this.isHighlighted,
+ this.isLoggedIn,
+ this.isRightHover,
+ );
},
addCommentTooltipLeft() {
- const brokenSymlinks = this.line.left.commentsDisabled;
- let tooltip = __('Add a comment to this line');
-
- if (brokenSymlinks) {
- if (brokenSymlinks.wasSymbolic || brokenSymlinks.isSymbolic) {
- tooltip = __(
- 'Commenting on symbolic links that replace or are replaced by files is currently not supported.',
- );
- } else if (brokenSymlinks.wasReal || brokenSymlinks.isReal) {
- tooltip = __(
- 'Commenting on files that replace or are replaced by symbolic links is currently not supported.',
- );
- }
- }
-
- return tooltip;
+ return utils.addCommentTooltip(this.line.left);
},
addCommentTooltipRight() {
- const brokenSymlinks = this.line.right.commentsDisabled;
- let tooltip = __('Add a comment to this line');
-
- if (brokenSymlinks) {
- if (brokenSymlinks.wasSymbolic || brokenSymlinks.isSymbolic) {
- tooltip = __(
- 'Commenting on symbolic links that replace or are replaced by files is currently not supported.',
- );
- } else if (brokenSymlinks.wasReal || brokenSymlinks.isReal) {
- tooltip = __(
- 'Commenting on files that replace or are replaced by symbolic links is currently not supported.',
- );
- }
- }
-
- return tooltip;
+ return utils.addCommentTooltip(this.line.right);
},
shouldRenderCommentButton() {
- if (!this.isCommentButtonRendered) {
- return false;
- }
-
- if (this.isLoggedIn) {
- const isDiffHead = parseBoolean(getParameterByName('diff_head'));
- return !isDiffHead || gon.features?.mergeRefHeadComments;
- }
-
- return false;
+ return utils.shouldRenderCommentButton(this.isLoggedIn, this.isCommentButtonRendered);
},
shouldShowCommentButtonLeft() {
- return (
- this.isLeftHover &&
- !this.isContextLineLeft &&
- !this.isMetaLineLeft &&
- !this.hasDiscussionsLeft
+ return utils.shouldShowCommentButton(
+ this.isLeftHover,
+ this.isContextLineLeft,
+ this.isMetaLineLeft,
+ this.hasDiscussionsLeft,
);
},
shouldShowCommentButtonRight() {
- return (
- this.isRightHover &&
- !this.isContextLineRight &&
- !this.isMetaLineRight &&
- !this.hasDiscussionsRight
+ return utils.shouldShowCommentButton(
+ this.isRightHover,
+ this.isContextLineRight,
+ this.isMetaLineRight,
+ this.hasDiscussionsRight,
);
},
hasDiscussionsLeft() {
- return this.line.left?.discussions?.length > 0;
+ return utils.hasDiscussions(this.line.left);
},
hasDiscussionsRight() {
- return this.line.right?.discussions?.length > 0;
+ return utils.hasDiscussions(this.line.right);
},
lineHrefOld() {
- return `#${this.line.left.line_code || ''}`;
+ return utils.lineHref(this.line.left);
},
lineHrefNew() {
- return `#${this.line.right.line_code || ''}`;
+ return utils.lineHref(this.line.right);
},
lineCode() {
- return (
- (this.line.left && this.line.left.line_code) ||
- (this.line.right && this.line.right.line_code)
- );
+ return utils.lineCode(this.line);
},
isMetaLineLeft() {
- const type = this.line.left?.type;
-
- return (
- type === OLD_NO_NEW_LINE_TYPE || type === NEW_NO_NEW_LINE_TYPE || type === EMPTY_CELL_TYPE
- );
+ return utils.isMetaLine(this.line.left?.type);
},
isMetaLineRight() {
- const type = this.line.right?.type;
-
- return (
- type === OLD_NO_NEW_LINE_TYPE || type === NEW_NO_NEW_LINE_TYPE || type === EMPTY_CELL_TYPE
- );
+ return utils.isMetaLine(this.line.right?.type);
},
},
- created() {
- this.newLineType = NEW_LINE_TYPE;
- this.oldLineType = OLD_LINE_TYPE;
- this.parallelDiffViewType = PARALLEL_DIFF_VIEW_TYPE;
- },
mounted() {
this.scrollToLineIfNeededParallel(this.line);
this.unwatchShouldShowCommentButton = this.$watch(
@@ -341,6 +247,7 @@ export default {
<td :class="parallelViewLeftLineType" class="line-coverage left-side"></td>
<td
:id="line.left.line_code"
+ :key="line.left.line_code"
v-safe-html="line.left.rich_text"
:class="parallelViewLeftLineType"
class="line_content with-coverage parallel left-side"
@@ -401,6 +308,7 @@ export default {
></td>
<td
:id="line.right.line_code"
+ :key="line.right.rich_text"
v-safe-html="line.right.rich_text"
:class="[
line.right.type,
diff --git a/app/assets/javascripts/diffs/diff_file.js b/app/assets/javascripts/diffs/diff_file.js
index 610b71235d9..933197a2c7f 100644
--- a/app/assets/javascripts/diffs/diff_file.js
+++ b/app/assets/javascripts/diffs/diff_file.js
@@ -18,9 +18,21 @@ function fileSymlinkInformation(file, fileList) {
);
}
+function collapsed(file) {
+ const viewer = file.viewer || {};
+
+ return {
+ automaticallyCollapsed: viewer.automaticallyCollapsed || viewer.collapsed || false,
+ };
+}
+
export function prepareRawDiffFile({ file, allFiles }) {
Object.assign(file, {
brokenSymlink: fileSymlinkInformation(file, allFiles),
+ viewer: {
+ ...file.viewer,
+ ...collapsed(file),
+ },
});
return file;
diff --git a/app/assets/javascripts/diffs/i18n.js b/app/assets/javascripts/diffs/i18n.js
new file mode 100644
index 00000000000..8699cd88a18
--- /dev/null
+++ b/app/assets/javascripts/diffs/i18n.js
@@ -0,0 +1,5 @@
+import { __ } from '~/locale';
+
+export const DIFF_FILE_HEADER = {
+ optionsDropdownTitle: __('Options'),
+};
diff --git a/app/assets/javascripts/diffs/store/actions.js b/app/assets/javascripts/diffs/store/actions.js
index 0f275f1cb3e..966b706fc31 100644
--- a/app/assets/javascripts/diffs/store/actions.js
+++ b/app/assets/javascripts/diffs/store/actions.js
@@ -103,7 +103,7 @@ export const fetchDiffFilesBatch = ({ commit, state, dispatch }) => {
commit(types.VIEW_DIFF_FILE, state.diffFiles[0].file_hash);
}
- if (gon.features?.codeNavigation) {
+ if (state.diffFiles?.length) {
// eslint-disable-next-line promise/catch-or-return,promise/no-nesting
import('~/code_navigation').then(m =>
m.default({
@@ -236,7 +236,7 @@ export const renderFileForDiscussionId = ({ commit, rootState, state }, discussi
commit(types.RENDER_FILE, file);
}
- if (file.viewer.collapsed) {
+ if (file.viewer.automaticallyCollapsed) {
eventHub.$emit(`loadCollapsedDiff/${file.file_hash}`);
scrollToElement(document.getElementById(file.file_hash));
} else {
@@ -252,7 +252,8 @@ export const startRenderDiffsQueue = ({ state, commit }) => {
const nextFile = state.diffFiles.find(
file =>
!file.renderIt &&
- (file.viewer && (!file.viewer.collapsed || file.viewer.name !== diffViewerModes.text)),
+ (file.viewer &&
+ (!file.viewer.automaticallyCollapsed || file.viewer.name !== diffViewerModes.text)),
);
if (nextFile) {
@@ -631,7 +632,7 @@ export function switchToFullDiffFromRenamedFile({ commit, dispatch, state }, { d
filePath: diffFile.file_path,
viewer: {
...diffFile.alternate_viewer,
- collapsed: false,
+ automaticallyCollapsed: false,
},
});
commit(types.SET_CURRENT_VIEW_DIFF_FILE_LINES, { filePath: diffFile.file_path, lines });
diff --git a/app/assets/javascripts/diffs/store/getters.js b/app/assets/javascripts/diffs/store/getters.js
index 42df5873a41..91425c7825b 100644
--- a/app/assets/javascripts/diffs/store/getters.js
+++ b/app/assets/javascripts/diffs/store/getters.js
@@ -9,7 +9,7 @@ export const isParallelView = state => state.diffViewType === PARALLEL_DIFF_VIEW
export const isInlineView = state => state.diffViewType === INLINE_DIFF_VIEW_TYPE;
export const hasCollapsedFile = state =>
- state.diffFiles.some(file => file.viewer && file.viewer.collapsed);
+ state.diffFiles.some(file => file.viewer && file.viewer.automaticallyCollapsed);
export const commitId = state => (state.commit && state.commit.id ? state.commit.id : null);
@@ -46,15 +46,24 @@ export const diffHasAllCollapsedDiscussions = (state, getters) => diff => {
* @param {Object} diff
* @returns {Boolean}
*/
-export const diffHasExpandedDiscussions = (state, getters) => diff => {
- const discussions = getters.getDiffFileDiscussions(diff);
-
- return (
- (discussions &&
- discussions.length &&
- discussions.find(discussion => discussion.expanded) !== undefined) ||
- false
- );
+export const diffHasExpandedDiscussions = state => diff => {
+ const lines = {
+ [INLINE_DIFF_VIEW_TYPE]: diff.highlighted_diff_lines || [],
+ [PARALLEL_DIFF_VIEW_TYPE]: (diff.parallel_diff_lines || []).reduce((acc, line) => {
+ if (line.left) {
+ acc.push(line.left);
+ }
+
+ if (line.right) {
+ acc.push(line.right);
+ }
+
+ return acc;
+ }, []),
+ };
+ return lines[window.gon?.features?.unifiedDiffLines ? 'inline' : state.diffViewType]
+ .filter(l => l.discussions.length >= 1)
+ .some(l => l.discussionsExpanded);
};
/**
@@ -62,8 +71,25 @@ export const diffHasExpandedDiscussions = (state, getters) => diff => {
* @param {Boolean} diff
* @returns {Boolean}
*/
-export const diffHasDiscussions = (state, getters) => diff =>
- getters.getDiffFileDiscussions(diff).length > 0;
+export const diffHasDiscussions = state => diff => {
+ const lines = {
+ [INLINE_DIFF_VIEW_TYPE]: diff.highlighted_diff_lines || [],
+ [PARALLEL_DIFF_VIEW_TYPE]: (diff.parallel_diff_lines || []).reduce((acc, line) => {
+ if (line.left) {
+ acc.push(line.left);
+ }
+
+ if (line.right) {
+ acc.push(line.right);
+ }
+
+ return acc;
+ }, []),
+ };
+ return lines[window.gon?.features?.unifiedDiffLines ? 'inline' : state.diffViewType].some(
+ l => l.discussions.length >= 1,
+ );
+};
/**
* Returns an array with the discussions of the given diff
diff --git a/app/assets/javascripts/diffs/store/mutations.js b/app/assets/javascripts/diffs/store/mutations.js
index 7925c620c4e..13ecf6a997d 100644
--- a/app/assets/javascripts/diffs/store/mutations.js
+++ b/app/assets/javascripts/diffs/store/mutations.js
@@ -172,7 +172,7 @@ export default {
state.diffFiles.forEach(file => {
Object.assign(file, {
viewer: Object.assign(file.viewer, {
- collapsed: false,
+ automaticallyCollapsed: false,
}),
});
});
@@ -355,7 +355,7 @@ export default {
const file = state.diffFiles.find(f => f.file_path === filePath);
if (file && file.viewer) {
- file.viewer.collapsed = collapsed;
+ file.viewer.automaticallyCollapsed = collapsed;
}
},
[types.SET_HIDDEN_VIEW_DIFF_FILE_LINES](state, { filePath, lines }) {
diff --git a/app/assets/javascripts/editor/constants.js b/app/assets/javascripts/editor/constants.js
index 9ee692e953a..b02eb37206a 100644
--- a/app/assets/javascripts/editor/constants.js
+++ b/app/assets/javascripts/editor/constants.js
@@ -5,3 +5,4 @@ export const EDITOR_LITE_INSTANCE_ERROR_NO_EL = __(
);
export const URI_PREFIX = 'gitlab';
+export const CONTENT_UPDATE_DEBOUNCE = 250;
diff --git a/app/assets/javascripts/editor/editor_lite.js b/app/assets/javascripts/editor/editor_lite.js
index bbd5461ae4d..e52e64d4c2d 100644
--- a/app/assets/javascripts/editor/editor_lite.js
+++ b/app/assets/javascripts/editor/editor_lite.js
@@ -39,6 +39,26 @@ export default class Editor {
monacoEditor.setModelLanguage(model, id);
}
+ static pushToImportsArray(arr, toImport) {
+ arr.push(import(toImport));
+ }
+
+ static loadExtensions(extensions) {
+ if (!extensions) {
+ return Promise.resolve();
+ }
+ const promises = [];
+ const extensionsArray = typeof extensions === 'string' ? extensions.split(',') : extensions;
+
+ extensionsArray.forEach(ext => {
+ const prefix = ext.includes('/') ? '' : 'editor/';
+ const trimmedExt = ext.replace(/^\//, '').trim();
+ Editor.pushToImportsArray(promises, `~/${prefix}${trimmedExt}`);
+ });
+
+ return Promise.all(promises);
+ }
+
/**
* Creates a monaco instance with the given options.
*
@@ -53,6 +73,7 @@ export default class Editor {
blobPath = '',
blobContent = '',
blobGlobalId = '',
+ extensions = [],
...instanceOptions
} = {}) {
if (!el) {
@@ -80,6 +101,22 @@ export default class Editor {
model.dispose();
});
instance.updateModelLanguage = path => Editor.updateModelLanguage(path, instance);
+ instance.use = args => this.use(args, instance);
+
+ Editor.loadExtensions(extensions, instance)
+ .then(modules => {
+ if (modules) {
+ modules.forEach(module => {
+ instance.use(module.default);
+ });
+ }
+ })
+ .then(() => {
+ el.dispatchEvent(new Event('editor-ready'));
+ })
+ .catch(e => {
+ throw e;
+ });
this.instances.push(instance);
return instance;
diff --git a/app/assets/javascripts/emoji/index.js b/app/assets/javascripts/emoji/index.js
index 4567c807c40..4a56843c0b5 100644
--- a/app/assets/javascripts/emoji/index.js
+++ b/app/assets/javascripts/emoji/index.js
@@ -1,53 +1,57 @@
-import { uniq } from 'lodash';
+import fuzzaldrinPlus from 'fuzzaldrin-plus';
import emojiAliases from 'emojis/aliases.json';
import axios from '../lib/utils/axios_utils';
-
import AccessorUtilities from '../lib/utils/accessor';
let emojiMap = null;
-let emojiPromise = null;
let validEmojiNames = null;
export const EMOJI_VERSION = '1';
const isLocalStorageAvailable = AccessorUtilities.isLocalStorageAccessSafe();
-export function initEmojiMap() {
- emojiPromise =
- emojiPromise ||
- new Promise((resolve, reject) => {
- if (emojiMap) {
- resolve(emojiMap);
- } else if (
- isLocalStorageAvailable &&
- window.localStorage.getItem('gl-emoji-map-version') === EMOJI_VERSION &&
- window.localStorage.getItem('gl-emoji-map')
- ) {
- emojiMap = JSON.parse(window.localStorage.getItem('gl-emoji-map'));
- validEmojiNames = [...Object.keys(emojiMap), ...Object.keys(emojiAliases)];
- resolve(emojiMap);
- } else {
- // We load the JSON file direct from the server
- // because it can't be loaded from a CDN due to
- // cross domain problems with JSON
- axios
- .get(`${gon.relative_url_root || ''}/-/emojis/${EMOJI_VERSION}/emojis.json`)
- .then(({ data }) => {
- emojiMap = data;
- validEmojiNames = [...Object.keys(emojiMap), ...Object.keys(emojiAliases)];
- resolve(emojiMap);
- if (isLocalStorageAvailable) {
- window.localStorage.setItem('gl-emoji-map-version', EMOJI_VERSION);
- window.localStorage.setItem('gl-emoji-map', JSON.stringify(emojiMap));
- }
- })
- .catch(err => {
- reject(err);
- });
- }
- });
+async function loadEmoji() {
+ if (
+ isLocalStorageAvailable &&
+ window.localStorage.getItem('gl-emoji-map-version') === EMOJI_VERSION &&
+ window.localStorage.getItem('gl-emoji-map')
+ ) {
+ return JSON.parse(window.localStorage.getItem('gl-emoji-map'));
+ }
+
+ // We load the JSON file direct from the server
+ // because it can't be loaded from a CDN due to
+ // cross domain problems with JSON
+ const { data } = await axios.get(
+ `${gon.relative_url_root || ''}/-/emojis/${EMOJI_VERSION}/emojis.json`,
+ );
+ window.localStorage.setItem('gl-emoji-map-version', EMOJI_VERSION);
+ window.localStorage.setItem('gl-emoji-map', JSON.stringify(data));
+ return data;
+}
+
+async function prepareEmojiMap() {
+ emojiMap = await loadEmoji();
+
+ validEmojiNames = [...Object.keys(emojiMap), ...Object.keys(emojiAliases)];
+
+ Object.keys(emojiMap).forEach(name => {
+ emojiMap[name].aliases = [];
+ emojiMap[name].name = name;
+ });
+ Object.entries(emojiAliases).forEach(([alias, name]) => {
+ // This check, `if (name in emojiMap)` is necessary during testing. In
+ // production, it shouldn't be necessary, because at no point should there
+ // be an entry in aliases.json with no corresponding entry in emojis.json.
+ // However, during testing, the endpoint for emojis.json is mocked with a
+ // small dataset, whereas aliases.json is always `import`ed directly.
+ if (name in emojiMap) emojiMap[name].aliases.push(alias);
+ });
+}
- return emojiPromise;
+export function initEmojiMap() {
+ initEmojiMap.promise = initEmojiMap.promise || prepareEmojiMap();
+ return initEmojiMap.promise;
}
export function normalizeEmojiName(name) {
@@ -62,13 +66,148 @@ export function isEmojiNameValid(name) {
return validEmojiNames.indexOf(name) >= 0;
}
-export function filterEmojiNames(filter) {
- const match = filter.toLowerCase();
- return validEmojiNames.filter(name => name.indexOf(match) >= 0);
+export function getAllEmoji() {
+ return emojiMap;
+}
+
+/**
+ * Retrieves an emoji by name or alias.
+ *
+ * Note: `initEmojiMap` must have been called and completed before this method
+ * can safely be called.
+ *
+ * @param {String} query The emoji name
+ * @param {Boolean} fallback If true, a fallback emoji will be returned if the
+ * named emoji does not exist. Defaults to false.
+ * @returns {Object} The matching emoji.
+ */
+export function getEmoji(query, fallback = false) {
+ // TODO https://gitlab.com/gitlab-org/gitlab/-/issues/268208
+ const fallbackEmoji = emojiMap.grey_question;
+ if (!query) {
+ return fallback ? fallbackEmoji : null;
+ }
+
+ if (!emojiMap) {
+ // eslint-disable-next-line @gitlab/require-i18n-strings
+ throw new Error('The emoji map is uninitialized or initialization has not completed');
+ }
+
+ const lowercaseQuery = query.toLowerCase();
+ const name = normalizeEmojiName(lowercaseQuery);
+
+ if (name in emojiMap) {
+ return emojiMap[name];
+ }
+
+ return fallback ? fallbackEmoji : null;
}
-export function filterEmojiNamesByAlias(filter) {
- return uniq(filterEmojiNames(filter).map(name => normalizeEmojiName(name)));
+const searchMatchers = {
+ // Fuzzy matching compares using a fuzzy matching library
+ fuzzy: (value, query) => {
+ const score = fuzzaldrinPlus.score(value, query) > 0;
+ return { score, success: score > 0 };
+ },
+ // Contains matching compares by indexOf
+ contains: (value, query) => {
+ const index = value.indexOf(query.toLowerCase());
+ return { index, success: index >= 0 };
+ },
+ // Exact matching compares by equality
+ exact: (value, query) => {
+ return { success: value === query.toLowerCase() };
+ },
+};
+
+const searchPredicates = {
+ // Search by name
+ name: (matcher, query) => emoji => {
+ const m = matcher(emoji.name, query);
+ return [{ ...m, emoji, field: emoji.name }];
+ },
+ // Search by alias
+ alias: (matcher, query) => emoji =>
+ emoji.aliases.map(alias => {
+ const m = matcher(alias, query);
+ return { ...m, emoji, field: alias };
+ }),
+ // Search by description
+ description: (matcher, query) => emoji => {
+ const m = matcher(emoji.d, query);
+ return [{ ...m, emoji, field: emoji.d }];
+ },
+ // Search by unicode value (always exact)
+ unicode: (matcher, query) => emoji => {
+ return [{ emoji, field: emoji.e, success: emoji.e === query }];
+ },
+};
+
+/**
+ * Searches emoji by name, aliases, description, and unicode value and returns
+ * an array of matches.
+ *
+ * Behavior is undefined if `opts.fields` is empty or if `opts.match` is fuzzy
+ * and the query is empty.
+ *
+ * Note: `initEmojiMap` must have been called and completed before this method
+ * can safely be called.
+ *
+ * @param {String} query Search query.
+ * @param {Object} opts Search options (optional).
+ * @param {String[]} opts.fields Fields to search. Choices are 'name', 'alias',
+ * 'description', and 'unicode' (value). Default is all (four) fields.
+ * @param {String} opts.match Search method to use. Choices are 'exact',
+ * 'contains', or 'fuzzy'. All methods are case-insensitive. Exact matching (the
+ * default) compares by equality. Contains matching compares by indexOf. Fuzzy
+ * matching compares using a fuzzy matching library.
+ * @param {Boolean} opts.fallback If true, a fallback emoji will be returned if
+ * the result set is empty. Defaults to false.
+ * @param {Boolean} opts.raw Returns the raw match data instead of just the
+ * matching emoji.
+ * @returns {Object[]} A list of emoji that match the query.
+ */
+export function searchEmoji(query, opts) {
+ if (!emojiMap) {
+ // eslint-disable-next-line @gitlab/require-i18n-strings
+ throw new Error('The emoji map is uninitialized or initialization has not completed');
+ }
+
+ const {
+ fields = ['name', 'alias', 'description', 'unicode'],
+ match = 'exact',
+ fallback = false,
+ raw = false,
+ } = opts || {};
+
+ const fallbackEmoji = emojiMap.grey_question;
+ if (!query) {
+ if (fallback) {
+ return raw ? [{ emoji: fallbackEmoji }] : [fallbackEmoji];
+ }
+
+ return [];
+ }
+
+ // optimization for an exact match in name and alias
+ if (match === 'exact' && new Set([...fields, 'name', 'alias']).size === 2) {
+ const emoji = getEmoji(query, fallback);
+ return emoji ? [emoji] : [];
+ }
+
+ const matcher = searchMatchers[match] || searchMatchers.exact;
+ const predicates = fields.map(f => searchPredicates[f](matcher, query));
+
+ const results = Object.values(emojiMap)
+ .flatMap(emoji => predicates.flatMap(predicate => predicate(emoji)))
+ .filter(r => r.success);
+
+ // Fallback to question mark for unknown emojis
+ if (fallback && results.length === 0) {
+ return raw ? [{ emoji: fallbackEmoji }] : [fallbackEmoji];
+ }
+
+ return raw ? results : results.map(r => r.emoji);
}
let emojiCategoryMap;
@@ -95,16 +234,10 @@ export function getEmojiCategoryMap() {
}
export function getEmojiInfo(query) {
- let name = normalizeEmojiName(query);
- let emojiInfo = emojiMap[name];
-
- // Fallback to question mark for unknown emojis
- if (!emojiInfo) {
- name = 'grey_question';
- emojiInfo = emojiMap[name];
- }
-
- return { ...emojiInfo, name };
+ return searchEmoji(query, {
+ fields: ['name', 'alias'],
+ fallback: true,
+ })[0];
}
export function emojiFallbackImageSrc(inputName) {
diff --git a/app/assets/javascripts/emoji/support/index.js b/app/assets/javascripts/emoji/support/index.js
index 1f7852dd487..14b80be9b43 100644
--- a/app/assets/javascripts/emoji/support/index.js
+++ b/app/assets/javascripts/emoji/support/index.js
@@ -5,6 +5,14 @@ import getUnicodeSupportMap from './unicode_support_map';
let browserUnicodeSupportMap;
export default function isEmojiUnicodeSupportedByBrowser(emojiUnicode, unicodeVersion) {
+ // Skipping the map creation for Bots + RSPec
+ if (
+ navigator.userAgent.indexOf('HeadlessChrome') > -1 ||
+ navigator.userAgent.indexOf('Lighthouse') > -1 ||
+ navigator.userAgent.indexOf('Speedindex') > -1
+ ) {
+ return true;
+ }
browserUnicodeSupportMap = browserUnicodeSupportMap || getUnicodeSupportMap();
return isEmojiUnicodeSupported(browserUnicodeSupportMap, emojiUnicode, unicodeVersion);
}
diff --git a/app/assets/javascripts/environments/components/enable_review_app_button.vue b/app/assets/javascripts/environments/components/enable_review_app_button.vue
deleted file mode 100644
index 8fbbc5189bf..00000000000
--- a/app/assets/javascripts/environments/components/enable_review_app_button.vue
+++ /dev/null
@@ -1,109 +0,0 @@
-<script>
-import { GlButton, GlModal, GlModalDirective, GlLink, GlSprintf } from '@gitlab/ui';
-import ModalCopyButton from '~/vue_shared/components/modal_copy_button.vue';
-import { s__ } from '~/locale';
-
-export default {
- components: {
- GlButton,
- GlLink,
- GlModal,
- GlSprintf,
- ModalCopyButton,
- },
- directives: {
- 'gl-modal': GlModalDirective,
- },
- instructionText: {
- step1: s__(
- 'EnableReviewApp|%{stepStart}Step 1%{stepEnd}. Ensure you have Kubernetes set up and have a base domain for your %{linkStart}cluster%{linkEnd}.',
- ),
- step2: s__('EnableReviewApp|%{stepStart}Step 2%{stepEnd}. Copy the following snippet:'),
- step3: s__(
- `EnableReviewApp|%{stepStart}Step 3%{stepEnd}. Add it to the project %{linkStart}gitlab-ci.yml%{linkEnd} file.`,
- ),
- },
- modalInfo: {
- closeText: s__('EnableReviewApp|Close'),
- copyToClipboardText: s__('EnableReviewApp|Copy snippet text'),
- copyString: `deploy_review:
- stage: deploy
- script:
- - echo "Deploy a review app"
- environment:
- name: review/$CI_COMMIT_REF_NAME
- url: https://$CI_ENVIRONMENT_SLUG.example.com
- only:
- - branches
- except:
- - master`,
- id: 'enable-review-app-info',
- title: s__('ReviewApp|Enable Review App'),
- },
-};
-</script>
-<template>
- <div>
- <gl-button
- v-gl-modal="$options.modalInfo.id"
- variant="info"
- category="secondary"
- type="button"
- class="js-enable-review-app-button"
- >
- {{ s__('Environments|Enable review app') }}
- </gl-button>
- <gl-modal
- :modal-id="$options.modalInfo.id"
- :title="$options.modalInfo.title"
- size="lg"
- class="text-2 ws-normal"
- ok-only
- ok-variant="light"
- :ok-title="$options.modalInfo.closeText"
- >
- <p>
- <gl-sprintf :message="$options.instructionText.step1">
- <template #step="{ content }">
- <strong>{{ content }}</strong>
- </template>
- <template #link="{ content }">
- <gl-link
- href="https://docs.gitlab.com/ee/user/project/clusters/add_remove_clusters.html"
- target="_blank"
- >{{ content }}</gl-link
- >
- </template>
- </gl-sprintf>
- </p>
- <div>
- <p>
- <gl-sprintf :message="$options.instructionText.step2">
- <template #step="{ content }">
- <strong>{{ content }}</strong>
- </template>
- </gl-sprintf>
- </p>
- <div class="flex align-items-start">
- <pre class="w-100"> {{ $options.modalInfo.copyString }} </pre>
- <modal-copy-button
- :title="$options.modalInfo.copyToClipboardText"
- :text="$options.modalInfo.copyString"
- :modal-id="$options.modalInfo.id"
- css-classes="border-0"
- />
- </div>
- </div>
- <p>
- <gl-sprintf :message="$options.instructionText.step3">
- <template #step="{ content }">
- <strong>{{ content }}</strong>
- </template>
- <template #link="{ content }">
- <gl-link href="blob/master/.gitlab-ci.yml" target="_blank">{{ content }}</gl-link>
- </template>
- </gl-sprintf>
- </p>
- </gl-modal>
- </div>
-</template>
diff --git a/app/assets/javascripts/environments/components/enable_review_app_modal.vue b/app/assets/javascripts/environments/components/enable_review_app_modal.vue
new file mode 100644
index 00000000000..3dd1d5a1bcc
--- /dev/null
+++ b/app/assets/javascripts/environments/components/enable_review_app_modal.vue
@@ -0,0 +1,98 @@
+<script>
+import { GlLink, GlModal, GlSprintf } from '@gitlab/ui';
+import ModalCopyButton from '~/vue_shared/components/modal_copy_button.vue';
+import { s__ } from '~/locale';
+
+export default {
+ components: {
+ GlLink,
+ GlModal,
+ GlSprintf,
+ ModalCopyButton,
+ },
+ props: {
+ modalId: {
+ type: String,
+ required: true,
+ },
+ },
+ instructionText: {
+ step1: s__(
+ 'EnableReviewApp|%{stepStart}Step 1%{stepEnd}. Ensure you have Kubernetes set up and have a base domain for your %{linkStart}cluster%{linkEnd}.',
+ ),
+ step2: s__('EnableReviewApp|%{stepStart}Step 2%{stepEnd}. Copy the following snippet:'),
+ step3: s__(
+ `EnableReviewApp|%{stepStart}Step 3%{stepEnd}. Add it to the project %{linkStart}gitlab-ci.yml%{linkEnd} file.`,
+ ),
+ },
+ modalInfo: {
+ closeText: s__('EnableReviewApp|Close'),
+ copyToClipboardText: s__('EnableReviewApp|Copy snippet text'),
+ copyString: `deploy_review:
+ stage: deploy
+ script:
+ - echo "Deploy a review app"
+ environment:
+ name: review/$CI_COMMIT_REF_NAME
+ url: https://$CI_ENVIRONMENT_SLUG.example.com
+ only:
+ - branches
+ except:
+ - master`,
+ title: s__('ReviewApp|Enable Review App'),
+ },
+};
+</script>
+<template>
+ <gl-modal
+ :modal-id="modalId"
+ :title="$options.modalInfo.title"
+ size="lg"
+ ok-only
+ ok-variant="light"
+ :ok-title="$options.modalInfo.closeText"
+ >
+ <p>
+ <gl-sprintf :message="$options.instructionText.step1">
+ <template #step="{ content }">
+ <strong>{{ content }}</strong>
+ </template>
+ <template #link="{ content }">
+ <gl-link
+ href="https://docs.gitlab.com/ee/user/project/clusters/add_remove_clusters.html"
+ target="_blank"
+ >{{ content }}</gl-link
+ >
+ </template>
+ </gl-sprintf>
+ </p>
+ <div>
+ <p>
+ <gl-sprintf :message="$options.instructionText.step2">
+ <template #step="{ content }">
+ <strong>{{ content }}</strong>
+ </template>
+ </gl-sprintf>
+ </p>
+ <div class="gl-display-flex align-items-start">
+ <pre class="gl-w-full"> {{ $options.modalInfo.copyString }} </pre>
+ <modal-copy-button
+ :title="$options.modalInfo.copyToClipboardText"
+ :text="$options.modalInfo.copyString"
+ :modal-id="modalId"
+ css-classes="border-0"
+ />
+ </div>
+ </div>
+ <p>
+ <gl-sprintf :message="$options.instructionText.step3">
+ <template #step="{ content }">
+ <strong>{{ content }}</strong>
+ </template>
+ <template #link="{ content }">
+ <gl-link href="blob/master/.gitlab-ci.yml" target="_blank">{{ content }}</gl-link>
+ </template>
+ </gl-sprintf>
+ </p>
+ </gl-modal>
+</template>
diff --git a/app/assets/javascripts/environments/components/environment_actions.vue b/app/assets/javascripts/environments/components/environment_actions.vue
index 035b276bc3b..bc35a07fe4a 100644
--- a/app/assets/javascripts/environments/components/environment_actions.vue
+++ b/app/assets/javascripts/environments/components/environment_actions.vue
@@ -1,13 +1,12 @@
<script>
-import { GlButton, GlIcon, GlLoadingIcon } from '@gitlab/ui';
+import { GlButton, GlIcon, GlLoadingIcon, GlTooltipDirective } from '@gitlab/ui';
import { __, s__, sprintf } from '~/locale';
import { formatTime } from '~/lib/utils/datetime_utility';
import eventHub from '../event_hub';
-import tooltip from '../../vue_shared/directives/tooltip';
export default {
directives: {
- tooltip,
+ GlTooltip: GlTooltipDirective,
},
components: {
GlButton,
@@ -70,13 +69,14 @@ export default {
<template>
<div class="btn-group" role="group">
<gl-button
- v-tooltip
+ v-gl-tooltip
:title="title"
:aria-label="title"
:disabled="isLoading"
class="dropdown dropdown-new js-environment-actions-dropdown"
data-container="body"
data-toggle="dropdown"
+ data-testid="environment-actions-button"
>
<span>
<gl-icon name="play" />
diff --git a/app/assets/javascripts/environments/components/environment_delete.vue b/app/assets/javascripts/environments/components/environment_delete.vue
index 55aaa6d57bd..039b40a3596 100644
--- a/app/assets/javascripts/environments/components/environment_delete.vue
+++ b/app/assets/javascripts/environments/components/environment_delete.vue
@@ -4,7 +4,6 @@
* Used in the environments table and the environment detail view.
*/
-import $ from 'jquery';
import { GlTooltipDirective, GlIcon } from '@gitlab/ui';
import { s__ } from '~/locale';
import eventHub from '../event_hub';
@@ -42,7 +41,7 @@ export default {
},
methods: {
onClick() {
- $(this.$el).tooltip('dispose');
+ this.$root.$emit('bv::hide::tooltip', this.$options.deleteEnvironmentTooltipId);
eventHub.$emit('requestDeleteEnvironment', this.environment);
},
onDeleteEnvironment(environment) {
@@ -51,15 +50,16 @@ export default {
}
},
},
+ deleteEnvironmentTooltipId: 'delete-environment-button-tooltip',
};
</script>
<template>
<loading-button
- v-gl-tooltip
+ v-gl-tooltip="{ id: $options.deleteEnvironmentTooltipId }"
:loading="isLoading"
:title="title"
:aria-label="title"
- container-class="btn btn-danger d-none d-sm-none d-md-block"
+ container-class="btn btn-danger d-none d-md-block"
data-toggle="modal"
data-target="#delete-environment-modal"
@click="onClick"
diff --git a/app/assets/javascripts/environments/components/environment_item.vue b/app/assets/javascripts/environments/components/environment_item.vue
index 8850ed19a4b..48e81b168ec 100644
--- a/app/assets/javascripts/environments/components/environment_item.vue
+++ b/app/assets/javascripts/environments/components/environment_item.vue
@@ -570,7 +570,7 @@ export default {
</div>
<div
- class="table-section deployment-column d-none d-sm-none d-md-block"
+ class="table-section deployment-column d-none d-md-block"
:class="tableData.deploy.spacing"
role="gridcell"
>
@@ -594,11 +594,7 @@ export default {
</div>
</div>
- <div
- class="table-section d-none d-sm-none d-md-block"
- :class="tableData.build.spacing"
- role="gridcell"
- >
+ <div class="table-section d-none d-md-block" :class="tableData.build.spacing" role="gridcell">
<a v-if="shouldRenderBuildName" :href="buildPath" class="build-link cgray">
<tooltip-on-truncate
:title="buildName"
diff --git a/app/assets/javascripts/environments/components/environment_stop.vue b/app/assets/javascripts/environments/components/environment_stop.vue
index c63d54d586d..ff74f81c98e 100644
--- a/app/assets/javascripts/environments/components/environment_stop.vue
+++ b/app/assets/javascripts/environments/components/environment_stop.vue
@@ -4,7 +4,6 @@
* Used in environments table.
*/
-import $ from 'jquery';
import { GlTooltipDirective, GlButton } from '@gitlab/ui';
import { s__ } from '~/locale';
import eventHub from '../event_hub';
@@ -40,7 +39,7 @@ export default {
},
methods: {
onClick() {
- $(this.$el).tooltip('dispose');
+ this.$root.$emit('bv::hide::tooltip', this.$options.stopEnvironmentTooltipId);
eventHub.$emit('requestStopEnvironment', this.environment);
},
onStopEnvironment(environment) {
@@ -49,11 +48,12 @@ export default {
}
},
},
+ stopEnvironmentTooltipId: 'stop-environment-button-tooltip',
};
</script>
<template>
<gl-button
- v-gl-tooltip
+ v-gl-tooltip="{ id: $options.stopEnvironmentTooltipId }"
:loading="isLoading"
:title="title"
:aria-label="title"
diff --git a/app/assets/javascripts/environments/components/environment_terminal_button.vue b/app/assets/javascripts/environments/components/environment_terminal_button.vue
index b5a7be90204..4750b8ef01b 100644
--- a/app/assets/javascripts/environments/components/environment_terminal_button.vue
+++ b/app/assets/javascripts/environments/components/environment_terminal_button.vue
@@ -39,7 +39,7 @@ export default {
:aria-label="title"
:href="terminalPath"
:class="{ disabled: disabled }"
- class="btn terminal-button d-none d-sm-none d-md-block text-secondary"
+ class="btn terminal-button d-none d-md-block text-secondary"
>
<gl-icon name="terminal" />
</a>
diff --git a/app/assets/javascripts/environments/components/environments_app.vue b/app/assets/javascripts/environments/components/environments_app.vue
index f0e74d96f09..9bafc7ed153 100644
--- a/app/assets/javascripts/environments/components/environments_app.vue
+++ b/app/assets/javascripts/environments/components/environments_app.vue
@@ -1,28 +1,39 @@
<script>
-import { GlDeprecatedButton } from '@gitlab/ui';
+import { GlBadge, GlButton, GlModalDirective, GlTab, GlTabs } from '@gitlab/ui';
import { deprecatedCreateFlash as Flash } from '~/flash';
import { s__ } from '~/locale';
import emptyState from './empty_state.vue';
import eventHub from '../event_hub';
import environmentsMixin from '../mixins/environments_mixin';
import CIPaginationMixin from '~/vue_shared/mixins/ci_pagination_api_mixin';
-import EnableReviewAppButton from './enable_review_app_button.vue';
+import EnableReviewAppModal from './enable_review_app_modal.vue';
import StopEnvironmentModal from './stop_environment_modal.vue';
import DeleteEnvironmentModal from './delete_environment_modal.vue';
import ConfirmRollbackModal from './confirm_rollback_modal.vue';
export default {
+ i18n: {
+ newEnvironmentButtonLabel: s__('Environments|New environment'),
+ reviewAppButtonLabel: s__('Environments|Enable review app'),
+ },
+ modal: {
+ id: 'enable-review-app-info',
+ },
components: {
ConfirmRollbackModal,
emptyState,
- EnableReviewAppButton,
- GlDeprecatedButton,
+ EnableReviewAppModal,
+ GlBadge,
+ GlButton,
+ GlTab,
+ GlTabs,
StopEnvironmentModal,
DeleteEnvironmentModal,
},
-
+ directives: {
+ 'gl-modal': GlModalDirective,
+ },
mixins: [CIPaginationMixin, environmentsMixin],
-
props: {
endpoint: {
type: String,
@@ -124,43 +135,108 @@ export default {
};
</script>
<template>
- <div>
+ <div class="environments-section">
<stop-environment-modal :environment="environmentInStopModal" />
<delete-environment-modal :environment="environmentInDeleteModal" />
<confirm-rollback-modal :environment="environmentInRollbackModal" />
- <div class="top-area">
- <tabs :tabs="tabs" scope="environments" @onChangeTab="onChangeTab" />
-
- <div class="nav-controls">
- <enable-review-app-button v-if="state.reviewAppDetails.can_setup_review_app" class="mr-2" />
- <gl-deprecated-button
- v-if="canCreateEnvironment && !isLoading"
+ <div class="gl-w-full">
+ <div
+ class="
+ gl-display-flex
+ gl-flex-direction-column
+ gl-mt-3
+ gl-display-md-none!"
+ >
+ <gl-button
+ v-if="state.reviewAppDetails.can_setup_review_app"
+ v-gl-modal="$options.modal.id"
+ data-testid="enable-review-app"
+ variant="info"
+ category="secondary"
+ type="button"
+ class="gl-mb-3 gl-flex-fill-1"
+ >
+ {{ $options.i18n.reviewAppButtonLabel }}
+ </gl-button>
+ <gl-button
+ v-if="canCreateEnvironment"
:href="newEnvironmentPath"
+ data-testid="new-environment"
category="primary"
variant="success"
>
- {{ s__('Environments|New environment') }}
- </gl-deprecated-button>
+ {{ $options.i18n.newEnvironmentButtonLabel }}
+ </gl-button>
</div>
+ <gl-tabs content-class="gl-display-none">
+ <gl-tab
+ v-for="(tab, idx) in tabs"
+ :key="idx"
+ :title-item-class="`js-environments-tab-${tab.scope}`"
+ @click="onChangeTab(tab.scope)"
+ >
+ <template #title>
+ <span>{{ tab.name }}</span>
+ <gl-badge size="sm" class="gl-tab-counter-badge">{{ tab.count }}</gl-badge>
+ </template>
+ </gl-tab>
+ <template #tabs-end>
+ <div
+ class="
+ gl-display-none
+ gl-display-md-flex
+ gl-lg-align-items-center
+ gl-lg-flex-direction-row
+ gl-lg-flex-fill-1
+ gl-lg-justify-content-end
+ gl-lg-mt-0"
+ >
+ <gl-button
+ v-if="state.reviewAppDetails.can_setup_review_app"
+ v-gl-modal="$options.modal.id"
+ data-testid="enable-review-app"
+ variant="info"
+ category="secondary"
+ type="button"
+ class="gl-mb-3 gl-lg-mr-3 gl-lg-mb-0"
+ >
+ {{ $options.i18n.reviewAppButtonLabel }}
+ </gl-button>
+ <gl-button
+ v-if="canCreateEnvironment"
+ :href="newEnvironmentPath"
+ data-testid="new-environment"
+ category="primary"
+ variant="success"
+ >
+ {{ $options.i18n.newEnvironmentButtonLabel }}
+ </gl-button>
+ </div>
+ </template>
+ </gl-tabs>
+ <container
+ :is-loading="isLoading"
+ :environments="state.environments"
+ :pagination="state.paginationInformation"
+ :can-read-environment="canReadEnvironment"
+ :canary-deployment-feature-id="canaryDeploymentFeatureId"
+ :show-canary-deployment-callout="showCanaryDeploymentCallout"
+ :user-callouts-path="userCalloutsPath"
+ :lock-promotion-svg-path="lockPromotionSvgPath"
+ :help-canary-deployments-path="helpCanaryDeploymentsPath"
+ :deploy-boards-help-path="deployBoardsHelpPath"
+ @onChangePage="onChangePage"
+ >
+ <template v-if="!isLoading && state.environments.length === 0" #emptyState>
+ <empty-state :help-path="helpPagePath" />
+ </template>
+ </container>
+ <enable-review-app-modal
+ v-if="state.reviewAppDetails.can_setup_review_app"
+ :modal-id="$options.modal.id"
+ data-testid="enable-review-app-modal"
+ />
</div>
-
- <container
- :is-loading="isLoading"
- :environments="state.environments"
- :pagination="state.paginationInformation"
- :can-read-environment="canReadEnvironment"
- :canary-deployment-feature-id="canaryDeploymentFeatureId"
- :show-canary-deployment-callout="showCanaryDeploymentCallout"
- :user-callouts-path="userCalloutsPath"
- :lock-promotion-svg-path="lockPromotionSvgPath"
- :help-canary-deployments-path="helpCanaryDeploymentsPath"
- :deploy-boards-help-path="deployBoardsHelpPath"
- @onChangePage="onChangePage"
- >
- <template v-if="!isLoading && state.environments.length === 0" #emptyState>
- <empty-state :help-path="helpPagePath" />
- </template>
- </container>
</div>
</template>
diff --git a/app/assets/javascripts/environments/components/environments_table.vue b/app/assets/javascripts/environments/components/environments_table.vue
index c06ab265915..c1b3eabec16 100644
--- a/app/assets/javascripts/environments/components/environments_table.vue
+++ b/app/assets/javascripts/environments/components/environments_table.vue
@@ -184,7 +184,6 @@ export default {
:deploy-boards-help-path="deployBoardsHelpPath"
:is-loading="model.isLoadingDeployBoard"
:is-empty="model.isEmptyDeployBoard"
- :has-legacy-app-label="model.hasLegacyAppLabel"
:logs-path="model.logs_path"
/>
</div>
diff --git a/app/assets/javascripts/environments/components/stop_environment_modal.vue b/app/assets/javascripts/environments/components/stop_environment_modal.vue
index 88612376b6e..f0dafe0620e 100644
--- a/app/assets/javascripts/environments/components/stop_environment_modal.vue
+++ b/app/assets/javascripts/environments/components/stop_environment_modal.vue
@@ -1,8 +1,7 @@
<script>
-/* eslint-disable @gitlab/vue-require-i18n-strings, vue/no-v-html */
-import { GlTooltipDirective } from '@gitlab/ui';
+/* eslint-disable @gitlab/vue-require-i18n-strings */
+import { GlSprintf, GlTooltipDirective } from '@gitlab/ui';
import DeprecatedModal2 from '~/vue_shared/components/deprecated_modal_2.vue';
-import { s__, sprintf } from '~/locale';
import eventHub from '../event_hub';
export default {
@@ -11,6 +10,7 @@ export default {
components: {
GlModal: DeprecatedModal2,
+ GlSprintf,
},
directives: {
@@ -24,27 +24,6 @@ export default {
},
},
- computed: {
- noStopActionMessage() {
- return sprintf(
- s__(
- `Environments|Note that this action will stop the environment,
- but it will %{emphasisStart}not%{emphasisEnd} have an effect on any existing deployment
- due to no “stop environment action†being defined
- in the %{ciConfigLinkStart}.gitlab-ci.yml%{ciConfigLinkEnd} file.`,
- ),
- {
- emphasisStart: '<strong>',
- emphasisEnd: '</strong>',
- ciConfigLinkStart:
- '<a href="https://docs.gitlab.com/ee/ci/yaml/" target="_blank" rel="noopener noreferrer">',
- ciConfigLinkEnd: '</a>',
- },
- false,
- );
- },
- },
-
methods: {
onSubmit() {
eventHub.$emit('stopEnvironment', this.environment);
@@ -72,9 +51,27 @@ export default {
<p>{{ s__('Environments|Are you sure you want to stop this environment?') }}</p>
<div v-if="!environment.has_stop_action" class="warning_message">
- <p v-html="noStopActionMessage"></p>
+ <p>
+ <gl-sprintf
+ :message="
+ s__(`Environments|Note that this action will stop the environment,
+ but it will %{emphasisStart}not%{emphasisEnd} have an effect on any existing deployment
+ due to no “stop environment action†being defined
+ in the %{ciConfigLinkStart}.gitlab-ci.yml%{ciConfigLinkEnd} file.`)
+ "
+ >
+ <template #emphasis="{ content }">
+ <strong>{{ content }}</strong>
+ </template>
+ <template #ciConfigLink="{ content }">
+ <a href="https://docs.gitlab.com/ee/ci/yaml/" target="_blank" rel="noopener noreferrer">
+ {{ content }}</a
+ >
+ </template>
+ </gl-sprintf>
+ </p>
<a
- href="https://docs.gitlab.com/ee/ci/environments.html#stopping-an-environment"
+ href="https://docs.gitlab.com/ee/ci/environments/#stopping-an-environment"
target="_blank"
rel="noopener noreferrer"
>{{ s__('Environments|Learn more about stopping environments') }}</a
diff --git a/app/assets/javascripts/environments/folder/environments_folder_view.vue b/app/assets/javascripts/environments/folder/environments_folder_view.vue
index 16d25615779..25f5483c58b 100644
--- a/app/assets/javascripts/environments/folder/environments_folder_view.vue
+++ b/app/assets/javascripts/environments/folder/environments_folder_view.vue
@@ -1,4 +1,5 @@
<script>
+import { GlBadge, GlTab, GlTabs } from '@gitlab/ui';
import environmentsMixin from '../mixins/environments_mixin';
import CIPaginationMixin from '../../vue_shared/mixins/ci_pagination_api_mixin';
import StopEnvironmentModal from '../components/stop_environment_modal.vue';
@@ -6,8 +7,11 @@ import DeleteEnvironmentModal from '../components/delete_environment_modal.vue';
export default {
components: {
- StopEnvironmentModal,
DeleteEnvironmentModal,
+ GlBadge,
+ GlTab,
+ GlTabs,
+ StopEnvironmentModal,
},
mixins: [environmentsMixin, CIPaginationMixin],
@@ -68,14 +72,26 @@ export default {
<stop-environment-modal :environment="environmentInStopModal" />
<delete-environment-modal :environment="environmentInDeleteModal" />
- <h4 class="js-folder-name environments-folder-name">
+ <h4 class="gl-font-weight-normal" data-testid="folder-name">
{{ s__('Environments|Environments') }} /
<b>{{ folderName }}</b>
</h4>
- <div class="top-area">
- <tabs v-if="!isLoading" :tabs="tabs" scope="environments" @onChangeTab="onChangeTab" />
- </div>
+ <gl-tabs v-if="!isLoading" scope="environments" content-class="gl-display-none">
+ <gl-tab
+ v-for="(tab, i) in tabs"
+ :key="`${tab.name}-${i}`"
+ :active="tab.isActive"
+ :title-item-class="tab.isActive ? 'gl-outline-none' : ''"
+ :title-link-attributes="{ 'data-testid': `environments-tab-${tab.scope}` }"
+ @click="onChangeTab(tab.scope)"
+ >
+ <template #title>
+ <span>{{ tab.name }}</span>
+ <gl-badge size="sm" class="gl-tab-counter-badge">{{ tab.count }}</gl-badge>
+ </template>
+ </gl-tab>
+ </gl-tabs>
<container
:is-loading="isLoading"
diff --git a/app/assets/javascripts/error_tracking/components/stacktrace_entry.vue b/app/assets/javascripts/error_tracking/components/stacktrace_entry.vue
index a4938fe13ed..cd4bb476b6e 100644
--- a/app/assets/javascripts/error_tracking/components/stacktrace_entry.vue
+++ b/app/assets/javascripts/error_tracking/components/stacktrace_entry.vue
@@ -94,7 +94,9 @@ export default {
<clipboard-button
:title="__('Copy file path')"
:text="filePath"
- css-class="btn-default btn-transparent btn-clipboard position-static"
+ category="tertiary"
+ size="small"
+ css-class="gl-mr-1"
/>
<gl-sprintf v-if="errorFn" :message="__('%{spanStart}in%{spanEnd} %{errorFn}')">
diff --git a/app/assets/javascripts/error_tracking_settings/components/app.vue b/app/assets/javascripts/error_tracking_settings/components/app.vue
index db90ac1c740..786abc8ce49 100644
--- a/app/assets/javascripts/error_tracking_settings/components/app.vue
+++ b/app/assets/javascripts/error_tracking_settings/components/app.vue
@@ -92,15 +92,13 @@ export default {
@select-project="updateSelectedProject"
/>
</div>
- <div class="gl-display-flex gl-justify-content-end">
- <gl-button
- :disabled="settingsLoading"
- class="js-error-tracking-button"
- variant="success"
- @click="handleSubmit"
- >
- {{ __('Save changes') }}
- </gl-button>
- </div>
+ <gl-button
+ :disabled="settingsLoading"
+ class="js-error-tracking-button"
+ variant="success"
+ @click="handleSubmit"
+ >
+ {{ __('Save changes') }}
+ </gl-button>
</div>
</template>
diff --git a/app/assets/javascripts/error_tracking_settings/components/error_tracking_form.vue b/app/assets/javascripts/error_tracking_settings/components/error_tracking_form.vue
index f1fb1a44758..b1b699d2e2a 100644
--- a/app/assets/javascripts/error_tracking_settings/components/error_tracking_form.vue
+++ b/app/assets/javascripts/error_tracking_settings/components/error_tracking_form.vue
@@ -1,10 +1,9 @@
<script>
import { mapActions, mapState } from 'vuex';
-import { GlFormInput, GlIcon } from '@gitlab/ui';
-import LoadingButton from '~/vue_shared/components/loading_button.vue';
+import { GlFormInput, GlIcon, GlButton } from '@gitlab/ui';
export default {
- components: { GlFormInput, GlIcon, LoadingButton },
+ components: { GlFormInput, GlIcon, GlButton },
computed: {
...mapState(['apiHost', 'connectError', 'connectSuccessful', 'isLoadingProjects', 'token']),
tokenInputState() {
@@ -57,12 +56,16 @@ export default {
/>
</div>
<div class="col-4 col-md-3 gl-pl-0">
- <loading-button
+ <gl-button
class="js-error-tracking-connect gl-ml-2 d-inline-flex"
- :label="isLoadingProjects ? __('Connecting') : __('Connect')"
+ category="secondary"
+ variant="default"
:loading="isLoadingProjects"
@click="fetchProjects"
- />
+ >
+ {{ isLoadingProjects ? __('Connecting') : __('Connect') }}
+ </gl-button>
+
<gl-icon
v-show="connectSuccessful"
class="js-error-tracking-connect-success gl-ml-2 text-success align-middle"
diff --git a/app/assets/javascripts/feature_flags/components/configure_feature_flags_modal.vue b/app/assets/javascripts/feature_flags/components/configure_feature_flags_modal.vue
new file mode 100644
index 00000000000..686399843dd
--- /dev/null
+++ b/app/assets/javascripts/feature_flags/components/configure_feature_flags_modal.vue
@@ -0,0 +1,258 @@
+<script>
+import {
+ GlFormGroup,
+ GlFormInput,
+ GlModal,
+ GlTooltipDirective,
+ GlLoadingIcon,
+ GlSprintf,
+ GlLink,
+ GlIcon,
+} from '@gitlab/ui';
+import { s__, __ } from '~/locale';
+import ModalCopyButton from '~/vue_shared/components/modal_copy_button.vue';
+import Callout from '~/vue_shared/components/callout.vue';
+
+export default {
+ components: {
+ GlFormGroup,
+ GlFormInput,
+ GlModal,
+ ModalCopyButton,
+ GlIcon,
+ Callout,
+ GlLoadingIcon,
+ GlSprintf,
+ GlLink,
+ },
+
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ },
+
+ props: {
+ instanceId: {
+ type: String,
+ required: true,
+ },
+ modalId: {
+ type: String,
+ required: false,
+ default: 'configure-feature-flags',
+ },
+ isRotating: {
+ type: Boolean,
+ required: true,
+ },
+ hasRotateError: {
+ type: Boolean,
+ required: true,
+ },
+ canUserRotateToken: {
+ type: Boolean,
+ required: true,
+ },
+ },
+ inject: [
+ 'projectName',
+ 'featureFlagsHelpPagePath',
+ 'unleashApiUrl',
+ 'featureFlagsClientExampleHelpPagePath',
+ 'featureFlagsClientLibrariesHelpPagePath',
+ ],
+ translations: {
+ cancelActionLabel: __('Close'),
+ modalTitle: s__('FeatureFlags|Configure feature flags'),
+ apiUrlLabelText: s__('FeatureFlags|API URL'),
+ apiUrlCopyText: __('Copy URL'),
+ instanceIdLabelText: s__('FeatureFlags|Instance ID'),
+ instanceIdCopyText: __('Copy ID'),
+ instanceIdRegenerateError: __('Unable to generate new instance ID'),
+ instanceIdRegenerateText: __(
+ 'Regenerating the instance ID can break integration depending on the client you are using.',
+ ),
+ instanceIdRegenerateActionLabel: __('Regenerate instance ID'),
+ },
+ data() {
+ return {
+ enteredProjectName: '',
+ };
+ },
+ computed: {
+ cancelActionProps() {
+ return {
+ text: this.$options.translations.cancelActionLabel,
+ };
+ },
+ canRegenerateInstanceId() {
+ return this.canUserRotateToken && this.enteredProjectName === this.projectName;
+ },
+ regenerateInstanceIdActionProps() {
+ return this.canUserRotateToken
+ ? {
+ text: this.$options.translations.instanceIdRegenerateActionLabel,
+ attributes: [
+ {
+ category: 'secondary',
+ disabled: !this.canRegenerateInstanceId,
+ loading: this.isRotating,
+ variant: 'danger',
+ },
+ ],
+ }
+ : null;
+ },
+ },
+
+ methods: {
+ clearState() {
+ this.enteredProjectName = '';
+ },
+ rotateToken() {
+ this.$emit('token');
+ this.clearState();
+ },
+ },
+};
+</script>
+<template>
+ <gl-modal
+ :modal-id="modalId"
+ :action-cancel="cancelActionProps"
+ :action-primary="regenerateInstanceIdActionProps"
+ @canceled="clearState"
+ @hide="clearState"
+ @primary.prevent="rotateToken"
+ >
+ <template #modal-title>
+ {{ $options.translations.modalTitle }}
+ </template>
+ <p>
+ <gl-sprintf
+ :message="
+ s__(
+ '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}',
+ )
+ "
+ >
+ <template #docsLinkAnchored="{ content }">
+ <gl-link
+ :href="featureFlagsClientLibrariesHelpPagePath"
+ target="_blank"
+ data-testid="help-client-link"
+ >
+ {{ content }}
+ </gl-link>
+ </template>
+ <template #docsLink="{ content }">
+ <gl-link :href="featureFlagsHelpPagePath" target="_blank" data-testid="help-link">{{
+ content
+ }}</gl-link>
+ </template>
+ </gl-sprintf>
+ </p>
+
+ <callout category="warning">
+ <gl-sprintf
+ :message="
+ s__(
+ 'FeatureFlags|Set the Unleash client application name to the name of the environment your application runs in. This value is used to match environment scopes. See the %{linkStart}example client configuration%{linkEnd}.',
+ )
+ "
+ >
+ <template #link="{ content }">
+ <gl-link :href="featureFlagsClientExampleHelpPagePath" target="_blank">{{
+ content
+ }}</gl-link>
+ </template>
+ </gl-sprintf>
+ </callout>
+ <div class="form-group">
+ <label for="api_url" class="label-bold">{{ $options.translations.apiUrlLabelText }}</label>
+ <div class="input-group">
+ <input
+ id="api_url"
+ :value="unleashApiUrl"
+ readonly
+ class="form-control"
+ type="text"
+ name="api_url"
+ />
+ <span class="input-group-append">
+ <modal-copy-button
+ :text="unleashApiUrl"
+ :title="$options.translations.apiUrlCopyText"
+ :modal-id="modalId"
+ class="input-group-text"
+ />
+ </span>
+ </div>
+ </div>
+ <div class="form-group">
+ <label for="instance_id" class="label-bold">{{
+ $options.translations.instanceIdLabelText
+ }}</label>
+ <div class="input-group">
+ <input
+ id="instance_id"
+ :value="instanceId"
+ class="form-control"
+ type="text"
+ name="instance_id"
+ readonly
+ :disabled="isRotating"
+ />
+
+ <gl-loading-icon
+ v-if="isRotating"
+ class="position-absolute align-self-center instance-id-loading-icon"
+ />
+
+ <div class="input-group-append">
+ <modal-copy-button
+ :text="instanceId"
+ :title="$options.translations.instanceIdCopyText"
+ :modal-id="modalId"
+ :disabled="isRotating"
+ class="input-group-text"
+ />
+ </div>
+ </div>
+ </div>
+ <div
+ v-if="hasRotateError"
+ class="text-danger d-flex align-items-center font-weight-normal mb-2"
+ >
+ <gl-icon name="warning" class="mr-1" />
+ <span>{{ $options.translations.instanceIdRegenerateError }}</span>
+ </div>
+ <callout
+ v-if="canUserRotateToken"
+ category="danger"
+ :message="$options.translations.instanceIdRegenerateText"
+ />
+ <p v-if="canUserRotateToken" data-testid="prevent-accident-text">
+ <gl-sprintf
+ :message="
+ s__(
+ 'FeatureFlags|To prevent accidental actions we ask you to confirm your intention. Please type %{projectName} to proceed or close this modal to cancel.',
+ )
+ "
+ >
+ <template #projectName>
+ <span class="gl-font-weight-bold gl-text-red-500">{{ projectName }}</span>
+ </template>
+ </gl-sprintf>
+ </p>
+ <gl-form-group>
+ <gl-form-input
+ v-if="canUserRotateToken"
+ id="project_name_verification"
+ v-model="enteredProjectName"
+ name="project_name"
+ type="text"
+ :disabled="isRotating"
+ />
+ </gl-form-group>
+ </gl-modal>
+</template>
diff --git a/app/assets/javascripts/feature_flags/components/edit_feature_flag.vue b/app/assets/javascripts/feature_flags/components/edit_feature_flag.vue
new file mode 100644
index 00000000000..26b18f9bf5a
--- /dev/null
+++ b/app/assets/javascripts/feature_flags/components/edit_feature_flag.vue
@@ -0,0 +1,144 @@
+<script>
+import { GlAlert, GlLoadingIcon, GlToggle } from '@gitlab/ui';
+import { mapState, mapActions } from 'vuex';
+import axios from '~/lib/utils/axios_utils';
+import { sprintf, s__ } from '~/locale';
+import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
+import { LEGACY_FLAG, NEW_FLAG_ALERT } from '../constants';
+import FeatureFlagForm from './form.vue';
+
+export default {
+ components: {
+ GlAlert,
+ GlLoadingIcon,
+ GlToggle,
+ FeatureFlagForm,
+ },
+ mixins: [glFeatureFlagMixin()],
+ inject: {
+ showUserCallout: {},
+ userCalloutId: {
+ default: '',
+ },
+ userCalloutsPath: {
+ default: '',
+ },
+ },
+ data() {
+ return {
+ userShouldSeeNewFlagAlert: this.showUserCallout,
+ };
+ },
+ translations: {
+ legacyFlagAlert: s__(
+ 'FeatureFlags|GitLab is moving to a new way of managing feature flags, and in 13.4, this feature flag will become read-only. Please create a new feature flag.',
+ ),
+ legacyReadOnlyFlagAlert: s__(
+ 'FeatureFlags|GitLab is moving to a new way of managing feature flags. This feature flag is read-only, and it will be removed in 14.0. Please create a new feature flag.',
+ ),
+ newFlagAlert: NEW_FLAG_ALERT,
+ },
+ computed: {
+ ...mapState([
+ 'path',
+ 'error',
+ 'name',
+ 'description',
+ 'scopes',
+ 'strategies',
+ 'isLoading',
+ 'hasError',
+ 'iid',
+ 'active',
+ 'version',
+ ]),
+ title() {
+ return this.iid
+ ? `^${this.iid} ${this.name}`
+ : sprintf(s__('Edit %{name}'), { name: this.name });
+ },
+ deprecated() {
+ return this.hasNewVersionFlags && this.version === LEGACY_FLAG;
+ },
+ deprecatedAndEditable() {
+ return this.deprecated && !this.hasLegacyReadOnlyFlags;
+ },
+ deprecatedAndReadOnly() {
+ return this.deprecated && this.hasLegacyReadOnlyFlags;
+ },
+ hasNewVersionFlags() {
+ return this.glFeatures.featureFlagsNewVersion;
+ },
+ hasLegacyReadOnlyFlags() {
+ return (
+ this.glFeatures.featureFlagsLegacyReadOnly &&
+ !this.glFeatures.featureFlagsLegacyReadOnlyOverride
+ );
+ },
+ shouldShowNewFlagAlert() {
+ return !this.hasNewVersionFlags && this.userShouldSeeNewFlagAlert;
+ },
+ },
+ created() {
+ return this.fetchFeatureFlag();
+ },
+ methods: {
+ ...mapActions(['updateFeatureFlag', 'fetchFeatureFlag', 'toggleActive']),
+ dismissNewVersionFlagAlert() {
+ this.userShouldSeeNewFlagAlert = false;
+ axios.post(this.userCalloutsPath, {
+ feature_name: this.userCalloutId,
+ });
+ },
+ },
+};
+</script>
+<template>
+ <div>
+ <gl-alert
+ v-if="shouldShowNewFlagAlert"
+ variant="warning"
+ class="gl-my-5"
+ @dismiss="dismissNewVersionFlagAlert"
+ >
+ {{ $options.translations.newFlagAlert }}
+ </gl-alert>
+ <gl-loading-icon v-if="isLoading" />
+
+ <template v-else-if="!isLoading && !hasError">
+ <gl-alert v-if="deprecatedAndEditable" variant="warning" :dismissible="false" class="gl-my-5">
+ {{ $options.translations.legacyFlagAlert }}
+ </gl-alert>
+ <gl-alert v-if="deprecatedAndReadOnly" variant="warning" :dismissible="false" class="gl-my-5">
+ {{ $options.translations.legacyReadOnlyFlagAlert }}
+ </gl-alert>
+ <div class="gl-display-flex gl-align-items-center gl-mb-4 gl-mt-4">
+ <gl-toggle
+ :value="active"
+ data-testid="feature-flag-status-toggle"
+ data-track-event="click_button"
+ data-track-label="feature_flag_toggle"
+ class="gl-mr-4"
+ @change="toggleActive"
+ />
+ <h3 class="page-title gl-m-0">{{ title }}</h3>
+ </div>
+
+ <div v-if="error.length" class="alert alert-danger">
+ <p v-for="(message, index) in error" :key="index" class="gl-mb-0">{{ message }}</p>
+ </div>
+
+ <feature-flag-form
+ :name="name"
+ :description="description"
+ :scopes="scopes"
+ :strategies="strategies"
+ :cancel-path="path"
+ :submit-text="__('Save changes')"
+ :active="active"
+ :version="version"
+ @handleSubmit="data => updateFeatureFlag(data)"
+ />
+ </template>
+ </div>
+</template>
diff --git a/app/assets/javascripts/feature_flags/components/environments_dropdown.vue b/app/assets/javascripts/feature_flags/components/environments_dropdown.vue
new file mode 100644
index 00000000000..3caf536b6a2
--- /dev/null
+++ b/app/assets/javascripts/feature_flags/components/environments_dropdown.vue
@@ -0,0 +1,181 @@
+<script>
+import { debounce } from 'lodash';
+import { GlDeprecatedButton, GlSearchBoxByType } from '@gitlab/ui';
+import axios from '~/lib/utils/axios_utils';
+import { __ } from '~/locale';
+import { deprecatedCreateFlash as createFlash } from '~/flash';
+
+/**
+ * Creates a searchable input for environments.
+ *
+ * When given a value, it will render it as selected value
+ * Otherwise it will render a placeholder for the search input.
+ * It will fetch the available environments on focus.
+ *
+ * When the user types, it will trigger an event to allow
+ * for API queries outside of the component.
+ *
+ * When results are returned, it renders a selectable
+ * list with the suggestions
+ *
+ * When no results are returned, it will render a
+ * button with a `Create` label. When clicked, it will
+ * emit an event to allow for the creation of a new
+ * record.
+ *
+ */
+
+export default {
+ name: 'EnvironmentsSearchableInput',
+ components: {
+ GlDeprecatedButton,
+ GlSearchBoxByType,
+ },
+ props: {
+ value: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ placeholder: {
+ type: String,
+ required: false,
+ default: __('Search an environment spec'),
+ },
+ createButtonLabel: {
+ type: String,
+ required: false,
+ default: __('Create'),
+ },
+ disabled: {
+ type: Boolean,
+ default: false,
+ required: false,
+ },
+ },
+ inject: ['environmentsEndpoint'],
+ data() {
+ return {
+ environmentSearch: this.value,
+ results: [],
+ showSuggestions: false,
+ isLoading: false,
+ };
+ },
+ computed: {
+ /**
+ * Creates a label with the value of the filter
+ * @returns {String}
+ */
+ composedCreateButtonLabel() {
+ return `${this.createButtonLabel} ${this.environmentSearch}`;
+ },
+ shouldRenderCreateButton() {
+ return !this.isLoading && !this.results.length;
+ },
+ },
+ methods: {
+ fetchEnvironments: debounce(function debouncedFetchEnvironments() {
+ this.isLoading = true;
+ this.openSuggestions();
+ axios
+ .get(this.environmentsEndpoint, { params: { query: this.environmentSearch } })
+ .then(({ data }) => {
+ this.results = data || [];
+ this.isLoading = false;
+ })
+ .catch(() => {
+ this.isLoading = false;
+ this.closeSuggestions();
+ createFlash(__('Something went wrong on our end. Please try again.'));
+ });
+ }, 250),
+ /**
+ * Opens the list of suggestions
+ */
+ openSuggestions() {
+ this.showSuggestions = true;
+ },
+ /**
+ * Closes the list of suggestions and cleans the results
+ */
+ closeSuggestions() {
+ this.showSuggestions = false;
+ this.environmentSearch = '';
+ },
+ /**
+ * On click, it will:
+ * 1. clear the input value
+ * 2. close the list of suggestions
+ * 3. emit an event
+ */
+ clearInput() {
+ this.closeSuggestions();
+ this.$emit('clearInput');
+ },
+ /**
+ * When the user selects a value from the list of suggestions
+ *
+ * It emits an event with the selected value
+ * Clears the filter
+ * and closes the list of suggestions
+ *
+ * @param {String} selected
+ */
+ selectEnvironment(selected) {
+ this.$emit('selectEnvironment', selected);
+ this.results = [];
+ this.closeSuggestions();
+ },
+
+ /**
+ * When the user clicks the create button
+ * it emits an event with the filter value
+ */
+ createClicked() {
+ this.$emit('createClicked', this.environmentSearch);
+ this.closeSuggestions();
+ },
+ },
+};
+</script>
+<template>
+ <div>
+ <div class="dropdown position-relative">
+ <gl-search-box-by-type
+ v-model.trim="environmentSearch"
+ class="js-env-search"
+ :aria-label="placeholder"
+ :placeholder="placeholder"
+ :disabled="disabled"
+ :is-loading="isLoading"
+ @focus="fetchEnvironments"
+ @keyup="fetchEnvironments"
+ />
+ <div
+ v-if="showSuggestions"
+ class="dropdown-menu d-block dropdown-menu-selectable dropdown-menu-full-width"
+ >
+ <div class="dropdown-content">
+ <ul v-if="results.length">
+ <li v-for="(result, i) in results" :key="i">
+ <gl-deprecated-button class="btn-transparent" @click="selectEnvironment(result)">{{
+ result
+ }}</gl-deprecated-button>
+ </li>
+ </ul>
+ <div v-else-if="!results.length" class="text-secondary gl-p-3">
+ {{ __('No matching results') }}
+ </div>
+ <div v-if="shouldRenderCreateButton" class="dropdown-footer">
+ <gl-deprecated-button
+ class="js-create-button btn-blank dropdown-item"
+ @click="createClicked"
+ >{{ composedCreateButtonLabel }}</gl-deprecated-button
+ >
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/feature_flags/components/feature_flags.vue b/app/assets/javascripts/feature_flags/components/feature_flags.vue
new file mode 100644
index 00000000000..eb7046a3d9b
--- /dev/null
+++ b/app/assets/javascripts/feature_flags/components/feature_flags.vue
@@ -0,0 +1,326 @@
+<script>
+import { mapState, mapActions } from 'vuex';
+import { isEmpty } from 'lodash';
+import { GlAlert, GlButton, GlModalDirective, GlSprintf, GlTabs } from '@gitlab/ui';
+
+import { FEATURE_FLAG_SCOPE, USER_LIST_SCOPE } from '../constants';
+import FeatureFlagsTab from './feature_flags_tab.vue';
+import FeatureFlagsTable from './feature_flags_table.vue';
+import UserListsTable from './user_lists_table.vue';
+import { s__ } from '~/locale';
+import TablePagination from '~/vue_shared/components/pagination/table_pagination.vue';
+import {
+ buildUrlWithCurrentLocation,
+ getParameterByName,
+ historyPushState,
+} from '~/lib/utils/common_utils';
+
+import ConfigureFeatureFlagsModal from './configure_feature_flags_modal.vue';
+
+const SCOPES = { FEATURE_FLAG_SCOPE, USER_LIST_SCOPE };
+
+export default {
+ components: {
+ ConfigureFeatureFlagsModal,
+ FeatureFlagsTab,
+ FeatureFlagsTable,
+ GlAlert,
+ GlButton,
+ GlSprintf,
+ GlTabs,
+ TablePagination,
+ UserListsTable,
+ },
+ directives: {
+ GlModal: GlModalDirective,
+ },
+ inject: {
+ newUserListPath: { default: '' },
+ newFeatureFlagPath: { default: '' },
+ canUserConfigure: { required: true },
+ featureFlagsLimitExceeded: { required: true },
+ },
+ data() {
+ const scope = getParameterByName('scope') || SCOPES.FEATURE_FLAG_SCOPE;
+ return {
+ scope,
+ page: getParameterByName('page') || '1',
+ isUserListAlertDismissed: false,
+ shouldShowFeatureFlagsLimitWarning: this.featureFlagsLimitExceeded,
+ selectedTab: Object.values(SCOPES).indexOf(scope),
+ };
+ },
+ computed: {
+ ...mapState([
+ FEATURE_FLAG_SCOPE,
+ USER_LIST_SCOPE,
+ 'alerts',
+ 'count',
+ 'pageInfo',
+ 'isLoading',
+ 'hasError',
+ 'options',
+ 'instanceId',
+ 'isRotating',
+ 'hasRotateError',
+ ]),
+ topAreaBaseClasses() {
+ return ['gl-display-flex', 'gl-flex-direction-column'];
+ },
+ canUserRotateToken() {
+ return this.rotateInstanceIdPath !== '';
+ },
+ currentlyDisplayedData() {
+ return this.dataForScope(this.scope);
+ },
+ shouldRenderPagination() {
+ return (
+ !this.isLoading &&
+ !this.hasError &&
+ this.currentlyDisplayedData.length > 0 &&
+ this.pageInfo[this.scope].total > this.pageInfo[this.scope].perPage
+ );
+ },
+ shouldShowEmptyState() {
+ return !this.isLoading && !this.hasError && this.currentlyDisplayedData.length === 0;
+ },
+ shouldRenderErrorState() {
+ return this.hasError && !this.isLoading;
+ },
+ shouldRenderFeatureFlags() {
+ return this.shouldRenderTable(SCOPES.FEATURE_FLAG_SCOPE);
+ },
+ shouldRenderUserLists() {
+ return this.shouldRenderTable(SCOPES.USER_LIST_SCOPE);
+ },
+ hasNewPath() {
+ return !isEmpty(this.newFeatureFlagPath);
+ },
+ emptyStateTitle() {
+ return s__('FeatureFlags|Get started with feature flags');
+ },
+ },
+ created() {
+ this.setFeatureFlagsOptions({ scope: this.scope, page: this.page });
+ this.fetchFeatureFlags();
+ this.fetchUserLists();
+ },
+ methods: {
+ ...mapActions([
+ 'setFeatureFlagsOptions',
+ 'fetchFeatureFlags',
+ 'fetchUserLists',
+ 'rotateInstanceId',
+ 'toggleFeatureFlag',
+ 'deleteUserList',
+ 'clearAlert',
+ ]),
+ onChangeTab(scope) {
+ this.scope = scope;
+ this.updateFeatureFlagOptions({
+ scope,
+ page: '1',
+ });
+ },
+ onFeatureFlagsTab() {
+ this.onChangeTab(SCOPES.FEATURE_FLAG_SCOPE);
+ },
+ onUserListsTab() {
+ this.onChangeTab(SCOPES.USER_LIST_SCOPE);
+ },
+ onChangePage(page) {
+ this.updateFeatureFlagOptions({
+ scope: this.scope,
+ /* URLS parameters are strings, we need to parse to match types */
+ page: Number(page).toString(),
+ });
+ },
+ updateFeatureFlagOptions(parameters) {
+ const queryString = Object.keys(parameters)
+ .map(parameter => {
+ const value = parameters[parameter];
+ return `${parameter}=${encodeURIComponent(value)}`;
+ })
+ .join('&');
+
+ historyPushState(buildUrlWithCurrentLocation(`?${queryString}`));
+ this.setFeatureFlagsOptions(parameters);
+ if (this.scope === SCOPES.FEATURE_FLAG_SCOPE) {
+ this.fetchFeatureFlags();
+ } else {
+ this.fetchUserLists();
+ }
+ },
+ shouldRenderTable(scope) {
+ return (
+ !this.isLoading &&
+ this.dataForScope(scope).length > 0 &&
+ !this.hasError &&
+ this.scope === scope
+ );
+ },
+ dataForScope(scope) {
+ return this[scope];
+ },
+ onDismissFeatureFlagsLimitWarning() {
+ this.shouldShowFeatureFlagsLimitWarning = false;
+ },
+ onNewFeatureFlagCLick() {
+ if (this.featureFlagsLimitExceeded) {
+ this.shouldShowFeatureFlagsLimitWarning = true;
+ }
+ },
+ },
+};
+</script>
+<template>
+ <div>
+ <gl-alert
+ v-if="shouldShowFeatureFlagsLimitWarning"
+ variant="warning"
+ @dismiss="onDismissFeatureFlagsLimitWarning"
+ >
+ <gl-sprintf
+ :message="
+ s__(
+ 'FeatureFlags|Feature flags limit reached (%{featureFlagsLimit}). Delete one or more feature flags before adding new ones.',
+ )
+ "
+ >
+ <template #featureFlagsLimit>
+ <span>{{ featureFlagsLimit }}</span>
+ </template>
+ </gl-sprintf>
+ </gl-alert>
+ <configure-feature-flags-modal
+ v-if="canUserConfigure"
+ :instance-id="instanceId"
+ :is-rotating="isRotating"
+ :has-rotate-error="hasRotateError"
+ :can-user-rotate-token="canUserRotateToken"
+ modal-id="configure-feature-flags"
+ @token="rotateInstanceId()"
+ />
+ <div :class="topAreaBaseClasses">
+ <div class="gl-display-flex gl-flex-direction-column gl-display-md-none!">
+ <gl-button
+ v-if="canUserConfigure"
+ v-gl-modal="'configure-feature-flags'"
+ variant="info"
+ category="secondary"
+ data-qa-selector="configure_feature_flags_button"
+ data-testid="ff-configure-button"
+ class="gl-mb-3"
+ >
+ {{ s__('FeatureFlags|Configure') }}
+ </gl-button>
+
+ <gl-button
+ v-if="newUserListPath"
+ :href="newUserListPath"
+ variant="success"
+ category="secondary"
+ class="gl-mb-3"
+ data-testid="ff-new-list-button"
+ >
+ {{ s__('FeatureFlags|New user list') }}
+ </gl-button>
+
+ <gl-button
+ v-if="hasNewPath"
+ :href="featureFlagsLimitExceeded ? '' : newFeatureFlagPath"
+ variant="success"
+ data-testid="ff-new-button"
+ @click="onNewFeatureFlagCLick"
+ >
+ {{ s__('FeatureFlags|New feature flag') }}
+ </gl-button>
+ </div>
+ <gl-tabs v-model="selectedTab" class="gl-align-items-center gl-w-full">
+ <feature-flags-tab
+ :title="s__('FeatureFlags|Feature Flags')"
+ :count="count.featureFlags"
+ :alerts="alerts"
+ :is-loading="isLoading"
+ :loading-label="s__('FeatureFlags|Loading feature flags')"
+ :error-state="shouldRenderErrorState"
+ :error-title="s__(`FeatureFlags|There was an error fetching the feature flags.`)"
+ :empty-state="shouldShowEmptyState"
+ :empty-title="emptyStateTitle"
+ data-testid="feature-flags-tab"
+ @dismissAlert="clearAlert"
+ @changeTab="onFeatureFlagsTab"
+ >
+ <feature-flags-table
+ v-if="shouldRenderFeatureFlags"
+ :feature-flags="featureFlags"
+ @toggle-flag="toggleFeatureFlag"
+ />
+ </feature-flags-tab>
+ <feature-flags-tab
+ :title="s__('FeatureFlags|User Lists')"
+ :count="count.userLists"
+ :alerts="alerts"
+ :is-loading="isLoading"
+ :loading-label="s__('FeatureFlags|Loading user lists')"
+ :error-state="shouldRenderErrorState"
+ :error-title="s__(`FeatureFlags|There was an error fetching the user lists.`)"
+ :empty-state="shouldShowEmptyState"
+ :empty-title="emptyStateTitle"
+ data-testid="user-lists-tab"
+ @dismissAlert="clearAlert"
+ @changeTab="onUserListsTab"
+ >
+ <user-lists-table
+ v-if="shouldRenderUserLists"
+ :user-lists="userLists"
+ @delete="deleteUserList"
+ />
+ </feature-flags-tab>
+ <template #tabs-end>
+ <div
+ class="gl-display-none gl-display-md-flex gl-align-items-center gl-flex-fill-1 gl-justify-content-end"
+ >
+ <gl-button
+ v-if="canUserConfigure"
+ v-gl-modal="'configure-feature-flags'"
+ variant="info"
+ category="secondary"
+ data-qa-selector="configure_feature_flags_button"
+ data-testid="ff-configure-button"
+ class="gl-mb-0 gl-mr-4"
+ >
+ {{ s__('FeatureFlags|Configure') }}
+ </gl-button>
+
+ <gl-button
+ v-if="newUserListPath"
+ :href="newUserListPath"
+ variant="success"
+ category="secondary"
+ class="gl-mb-0 gl-mr-4"
+ data-testid="ff-new-list-button"
+ >
+ {{ s__('FeatureFlags|New user list') }}
+ </gl-button>
+
+ <gl-button
+ v-if="hasNewPath"
+ :href="featureFlagsLimitExceeded ? '' : newFeatureFlagPath"
+ variant="success"
+ data-testid="ff-new-button"
+ @click="onNewFeatureFlagCLick"
+ >
+ {{ s__('FeatureFlags|New feature flag') }}
+ </gl-button>
+ </div>
+ </template>
+ </gl-tabs>
+ </div>
+ <table-pagination
+ v-if="shouldRenderPagination"
+ :change="onChangePage"
+ :page-info="pageInfo[scope]"
+ />
+ </div>
+</template>
diff --git a/app/assets/javascripts/feature_flags/components/feature_flags_tab.vue b/app/assets/javascripts/feature_flags/components/feature_flags_tab.vue
new file mode 100644
index 00000000000..5c35aa33e14
--- /dev/null
+++ b/app/assets/javascripts/feature_flags/components/feature_flags_tab.vue
@@ -0,0 +1,108 @@
+<script>
+import { GlAlert, GlBadge, GlEmptyState, GlLink, GlLoadingIcon, GlTab } from '@gitlab/ui';
+
+export default {
+ components: { GlAlert, GlBadge, GlEmptyState, GlLink, GlLoadingIcon, GlTab },
+ props: {
+ title: {
+ required: true,
+ type: String,
+ },
+ count: {
+ required: false,
+ type: Number,
+ default: null,
+ },
+ alerts: {
+ required: true,
+ type: Array,
+ },
+ isLoading: {
+ required: true,
+ type: Boolean,
+ },
+ loadingLabel: {
+ required: true,
+ type: String,
+ },
+ errorState: {
+ required: true,
+ type: Boolean,
+ },
+ errorTitle: {
+ required: true,
+ type: String,
+ },
+ emptyState: {
+ required: true,
+ type: Boolean,
+ },
+ emptyTitle: {
+ required: true,
+ type: String,
+ },
+ },
+ inject: ['errorStateSvgPath', 'featureFlagsHelpPagePath'],
+ computed: {
+ itemCount() {
+ return this.count ?? 0;
+ },
+ },
+ methods: {
+ clearAlert(index) {
+ this.$emit('dismissAlert', index);
+ },
+ onClick(event) {
+ return this.$emit('changeTab', event);
+ },
+ },
+};
+</script>
+<template>
+ <gl-tab @click="onClick">
+ <template #title>
+ <span data-testid="feature-flags-tab-title">{{ title }}</span>
+ <gl-badge size="sm" class="gl-tab-counter-badge">{{ itemCount }}</gl-badge>
+ </template>
+ <template>
+ <gl-alert
+ v-for="(message, index) in alerts"
+ :key="index"
+ data-testid="serverErrors"
+ variant="danger"
+ @dismiss="clearAlert(index)"
+ >
+ {{ message }}
+ </gl-alert>
+
+ <gl-loading-icon v-if="isLoading" :label="loadingLabel" size="md" class="gl-mt-4" />
+
+ <gl-empty-state
+ v-else-if="errorState"
+ :title="errorTitle"
+ :description="s__(`FeatureFlags|Try again in a few moments or contact your support team.`)"
+ :svg-path="errorStateSvgPath"
+ data-testid="error-state"
+ />
+
+ <gl-empty-state
+ v-else-if="emptyState"
+ :title="emptyTitle"
+ :svg-path="errorStateSvgPath"
+ data-testid="empty-state"
+ >
+ <template #description>
+ {{
+ s__(
+ 'FeatureFlags|Feature flags allow you to configure your code into different flavors by dynamically toggling certain functionality.',
+ )
+ }}
+ <gl-link :href="featureFlagsHelpPagePath" target="_blank">
+ {{ s__('FeatureFlags|More information') }}
+ </gl-link>
+ </template>
+ </gl-empty-state>
+ <slot> </slot>
+ </template>
+ </gl-tab>
+</template>
diff --git a/app/assets/javascripts/feature_flags/components/feature_flags_table.vue b/app/assets/javascripts/feature_flags/components/feature_flags_table.vue
new file mode 100644
index 00000000000..54d038606f4
--- /dev/null
+++ b/app/assets/javascripts/feature_flags/components/feature_flags_table.vue
@@ -0,0 +1,271 @@
+<script>
+import { GlBadge, GlButton, GlTooltipDirective, GlModal, GlToggle, GlIcon } from '@gitlab/ui';
+import { sprintf, s__ } from '~/locale';
+import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
+import { ROLLOUT_STRATEGY_PERCENT_ROLLOUT, NEW_VERSION_FLAG, LEGACY_FLAG } from '../constants';
+import { labelForStrategy } from '../utils';
+
+export default {
+ components: {
+ GlBadge,
+ GlButton,
+ GlIcon,
+ GlModal,
+ GlToggle,
+ },
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ },
+ mixins: [glFeatureFlagMixin()],
+ props: {
+ featureFlags: {
+ type: Array,
+ required: true,
+ },
+ },
+ inject: ['csrfToken'],
+ data() {
+ return {
+ deleteFeatureFlagUrl: null,
+ deleteFeatureFlagName: null,
+ };
+ },
+ translations: {
+ legacyFlagAlert: s__('FeatureFlags|Flag becomes read only soon'),
+ legacyFlagReadOnlyAlert: s__('FeatureFlags|Flag is read-only'),
+ },
+ computed: {
+ permissions() {
+ return this.glFeatures.featureFlagPermissions;
+ },
+ isNewVersionFlagsEnabled() {
+ return this.glFeatures.featureFlagsNewVersion;
+ },
+ isLegacyReadOnlyFlagsEnabled() {
+ return (
+ this.glFeatures.featureFlagsLegacyReadOnly &&
+ !this.glFeatures.featureFlagsLegacyReadOnlyOverride
+ );
+ },
+ modalTitle() {
+ return sprintf(s__('FeatureFlags|Delete %{name}?'), {
+ name: this.deleteFeatureFlagName,
+ });
+ },
+ deleteModalMessage() {
+ return sprintf(s__('FeatureFlags|Feature flag %{name} will be removed. Are you sure?'), {
+ name: this.deleteFeatureFlagName,
+ });
+ },
+ modalId() {
+ return 'delete-feature-flag';
+ },
+ legacyFlagToolTipText() {
+ const { legacyFlagReadOnlyAlert, legacyFlagAlert } = this.$options.translations;
+
+ return this.isLegacyReadOnlyFlagsEnabled ? legacyFlagReadOnlyAlert : legacyFlagAlert;
+ },
+ },
+ methods: {
+ isLegacyFlag(flag) {
+ return !this.isNewVersionFlagsEnabled || flag.version !== NEW_VERSION_FLAG;
+ },
+ statusToggleDisabled(flag) {
+ return this.isLegacyReadOnlyFlagsEnabled && flag.version === LEGACY_FLAG;
+ },
+ scopeTooltipText(scope) {
+ return !scope.active
+ ? sprintf(s__('FeatureFlags|Inactive flag for %{scope}'), {
+ scope: scope.environmentScope,
+ })
+ : '';
+ },
+ badgeText(scope) {
+ const displayName =
+ scope.environmentScope === '*'
+ ? s__('FeatureFlags|* (All environments)')
+ : scope.environmentScope;
+
+ const displayPercentage =
+ scope.rolloutStrategy === ROLLOUT_STRATEGY_PERCENT_ROLLOUT
+ ? `: ${scope.rolloutPercentage}%`
+ : '';
+
+ return `${displayName}${displayPercentage}`;
+ },
+ badgeVariant(scope) {
+ return scope.active ? 'info' : 'muted';
+ },
+ strategyBadgeText(strategy) {
+ return labelForStrategy(strategy);
+ },
+ featureFlagIidText(featureFlag) {
+ return featureFlag.iid ? `^${featureFlag.iid}` : '';
+ },
+ canDeleteFlag(flag) {
+ return !this.permissions || (flag.scopes || []).every(scope => scope.can_update);
+ },
+ setDeleteModalData(featureFlag) {
+ this.deleteFeatureFlagUrl = featureFlag.destroy_path;
+ this.deleteFeatureFlagName = featureFlag.name;
+
+ this.$refs[this.modalId].show();
+ },
+ onSubmit() {
+ this.$refs.form.submit();
+ },
+ toggleFeatureFlag(flag) {
+ this.$emit('toggle-flag', {
+ ...flag,
+ active: !flag.active,
+ });
+ },
+ },
+};
+</script>
+<template>
+ <div class="table-holder js-feature-flag-table">
+ <div class="gl-responsive-table-row table-row-header" role="row">
+ <div class="table-section section-10">
+ {{ s__('FeatureFlags|ID') }}
+ </div>
+ <div class="table-section section-10" role="columnheader">
+ {{ s__('FeatureFlags|Status') }}
+ </div>
+ <div class="table-section section-20" role="columnheader">
+ {{ s__('FeatureFlags|Feature Flag') }}
+ </div>
+ <div class="table-section section-40" role="columnheader">
+ {{ s__('FeatureFlags|Environment Specs') }}
+ </div>
+ </div>
+
+ <template v-for="featureFlag in featureFlags">
+ <div :key="featureFlag.id" class="gl-responsive-table-row" role="row">
+ <div class="table-section section-10" role="gridcell">
+ <div class="table-mobile-header" role="rowheader">{{ s__('FeatureFlags|ID') }}</div>
+ <div class="table-mobile-content js-feature-flag-id">
+ {{ featureFlagIidText(featureFlag) }}
+ </div>
+ </div>
+ <div class="table-section section-10" role="gridcell">
+ <div class="table-mobile-header" role="rowheader">{{ s__('FeatureFlags|Status') }}</div>
+ <div class="table-mobile-content">
+ <gl-toggle
+ v-if="featureFlag.update_path"
+ :value="featureFlag.active"
+ :disabled="statusToggleDisabled(featureFlag)"
+ data-testid="feature-flag-status-toggle"
+ data-track-event="click_button"
+ data-track-label="feature_flag_toggle"
+ @change="toggleFeatureFlag(featureFlag)"
+ />
+ <gl-badge
+ v-else-if="featureFlag.active"
+ variant="success"
+ data-testid="feature-flag-status-badge"
+ >
+ {{ s__('FeatureFlags|Active') }}
+ </gl-badge>
+ <gl-badge v-else variant="danger">{{ s__('FeatureFlags|Inactive') }}</gl-badge>
+ </div>
+ </div>
+
+ <div class="table-section section-20" role="gridcell">
+ <div class="table-mobile-header" role="rowheader">
+ {{ s__('FeatureFlags|Feature Flag') }}
+ </div>
+ <div class="table-mobile-content d-flex flex-column js-feature-flag-title">
+ <div class="gl-display-flex gl-align-items-center">
+ <div class="feature-flag-name text-monospace text-truncate">
+ {{ featureFlag.name }}
+ </div>
+ <gl-icon
+ v-if="isLegacyFlag(featureFlag)"
+ v-gl-tooltip.hover="legacyFlagToolTipText"
+ class="gl-ml-3"
+ name="information-o"
+ />
+ </div>
+ <div class="feature-flag-description text-secondary text-truncate">
+ {{ featureFlag.description }}
+ </div>
+ </div>
+ </div>
+
+ <div class="table-section section-40" role="gridcell">
+ <div class="table-mobile-header" role="rowheader">
+ {{ s__('FeatureFlags|Environment Specs') }}
+ </div>
+ <div
+ class="table-mobile-content d-flex flex-wrap justify-content-end justify-content-md-start js-feature-flag-environments"
+ >
+ <template v-if="isLegacyFlag(featureFlag)">
+ <gl-badge
+ v-for="scope in featureFlag.scopes"
+ :key="scope.id"
+ v-gl-tooltip.hover="scopeTooltipText(scope)"
+ :variant="badgeVariant(scope)"
+ :data-qa-selector="`feature-flag-scope-${badgeVariant(scope)}-badge`"
+ class="gl-mr-3 gl-mt-2"
+ >
+ {{ badgeText(scope) }}
+ </gl-badge>
+ </template>
+ <template v-else>
+ <gl-badge
+ v-for="strategy in featureFlag.strategies"
+ :key="strategy.id"
+ data-testid="strategy-badge"
+ variant="info"
+ class="gl-mr-3 gl-mt-2"
+ >
+ {{ strategyBadgeText(strategy) }}
+ </gl-badge>
+ </template>
+ </div>
+ </div>
+
+ <div class="table-section section-20 table-button-footer" role="gridcell">
+ <div class="table-action-buttons btn-group">
+ <template v-if="featureFlag.edit_path">
+ <gl-button
+ v-gl-tooltip.hover.bottom="__('Edit')"
+ class="js-feature-flag-edit-button"
+ icon="pencil"
+ :href="featureFlag.edit_path"
+ />
+ </template>
+ <template v-if="featureFlag.destroy_path">
+ <gl-button
+ v-gl-tooltip.hover.bottom="__('Delete')"
+ class="js-feature-flag-delete-button"
+ variant="danger"
+ icon="remove"
+ :disabled="!canDeleteFlag(featureFlag)"
+ @click="setDeleteModalData(featureFlag)"
+ />
+ </template>
+ </div>
+ </div>
+ </div>
+ </template>
+
+ <gl-modal
+ :ref="modalId"
+ :title="modalTitle"
+ :ok-title="s__('FeatureFlags|Delete feature flag')"
+ :modal-id="modalId"
+ title-tag="h4"
+ ok-variant="danger"
+ category="primary"
+ @ok="onSubmit"
+ >
+ {{ deleteModalMessage }}
+ <form ref="form" :action="deleteFeatureFlagUrl" method="post" class="js-requires-input">
+ <input ref="method" type="hidden" name="_method" value="delete" />
+ <input :value="csrfToken" type="hidden" name="authenticity_token" />
+ </form>
+ </gl-modal>
+ </div>
+</template>
diff --git a/app/assets/javascripts/feature_flags/components/form.vue b/app/assets/javascripts/feature_flags/components/form.vue
new file mode 100644
index 00000000000..3c1944d91bd
--- /dev/null
+++ b/app/assets/javascripts/feature_flags/components/form.vue
@@ -0,0 +1,606 @@
+<script>
+import Vue from 'vue';
+import { memoize, isString, cloneDeep, isNumber, uniqueId } from 'lodash';
+import {
+ GlButton,
+ GlDeprecatedBadge as GlBadge,
+ GlTooltip,
+ GlTooltipDirective,
+ GlFormTextarea,
+ GlFormCheckbox,
+ GlSprintf,
+ GlIcon,
+} from '@gitlab/ui';
+import Api from '~/api';
+import RelatedIssuesRoot from '~/related_issues/components/related_issues_root.vue';
+import { s__ } from '~/locale';
+import { deprecatedCreateFlash as flash, FLASH_TYPES } from '~/flash';
+import featureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
+import ToggleButton from '~/vue_shared/components/toggle_button.vue';
+import EnvironmentsDropdown from './environments_dropdown.vue';
+import Strategy from './strategy.vue';
+import {
+ ROLLOUT_STRATEGY_ALL_USERS,
+ ROLLOUT_STRATEGY_PERCENT_ROLLOUT,
+ ROLLOUT_STRATEGY_USER_ID,
+ ALL_ENVIRONMENTS_NAME,
+ INTERNAL_ID_PREFIX,
+ NEW_VERSION_FLAG,
+ LEGACY_FLAG,
+} from '../constants';
+import { createNewEnvironmentScope } from '../store/helpers';
+
+export default {
+ components: {
+ GlButton,
+ GlBadge,
+ GlFormTextarea,
+ GlFormCheckbox,
+ GlTooltip,
+ GlSprintf,
+ GlIcon,
+ ToggleButton,
+ EnvironmentsDropdown,
+ Strategy,
+ RelatedIssuesRoot,
+ },
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ },
+ mixins: [featureFlagsMixin()],
+ props: {
+ active: {
+ type: Boolean,
+ required: false,
+ default: true,
+ },
+ name: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ description: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ scopes: {
+ type: Array,
+ required: false,
+ default: () => [],
+ },
+ cancelPath: {
+ type: String,
+ required: true,
+ },
+ submitText: {
+ type: String,
+ required: true,
+ },
+ strategies: {
+ type: Array,
+ required: false,
+ default: () => [],
+ },
+ version: {
+ type: String,
+ required: false,
+ default: LEGACY_FLAG,
+ },
+ },
+ inject: {
+ projectId: {},
+ featureFlagIssuesEndpoint: {
+ default: '',
+ },
+ },
+ translations: {
+ allEnvironmentsText: s__('FeatureFlags|* (All Environments)'),
+
+ helpText: s__(
+ 'FeatureFlags|Feature Flag behavior is built up by creating a set of rules to define the status of target environments. A default wildcard rule %{codeStart}*%{codeEnd} for %{boldStart}All Environments%{boldEnd} is set, and you are able to add as many rules as you need by choosing environment specs below. You can toggle the behavior for each of your rules to set them %{boldStart}Active%{boldEnd} or %{boldStart}Inactive%{boldEnd}.',
+ ),
+
+ newHelpText: s__(
+ 'FeatureFlags|Enable features for specific users and environments by configuring feature flag strategies.',
+ ),
+ noStrategiesText: s__('FeatureFlags|Feature Flag has no strategies'),
+ },
+
+ ROLLOUT_STRATEGY_ALL_USERS,
+ ROLLOUT_STRATEGY_PERCENT_ROLLOUT,
+ ROLLOUT_STRATEGY_USER_ID,
+
+ // Matches numbers 0 through 100
+ rolloutPercentageRegex: /^[0-9]$|^[1-9][0-9]$|^100$/,
+
+ data() {
+ return {
+ formName: this.name,
+ formDescription: this.description,
+
+ // operate on a clone to avoid mutating props
+ formScopes: this.scopes.map(s => ({ ...s })),
+ formStrategies: cloneDeep(this.strategies),
+
+ newScope: '',
+ userLists: [],
+ };
+ },
+ computed: {
+ filteredScopes() {
+ return this.formScopes.filter(scope => !scope.shouldBeDestroyed);
+ },
+ filteredStrategies() {
+ return this.formStrategies.filter(s => !s.shouldBeDestroyed);
+ },
+ canUpdateFlag() {
+ return !this.permissionsFlag || (this.formScopes || []).every(scope => scope.canUpdate);
+ },
+ permissionsFlag() {
+ return this.glFeatures.featureFlagPermissions;
+ },
+ supportsStrategies() {
+ return this.glFeatures.featureFlagsNewVersion && this.version === NEW_VERSION_FLAG;
+ },
+ showRelatedIssues() {
+ return this.featureFlagIssuesEndpoint.length > 0;
+ },
+ readOnly() {
+ return (
+ this.glFeatures.featureFlagsNewVersion &&
+ this.glFeatures.featureFlagsLegacyReadOnly &&
+ !this.glFeatures.featureFlagsLegacyReadOnlyOverride &&
+ this.version === LEGACY_FLAG
+ );
+ },
+ },
+ mounted() {
+ if (this.supportsStrategies) {
+ Api.fetchFeatureFlagUserLists(this.projectId)
+ .then(({ data }) => {
+ this.userLists = data;
+ })
+ .catch(() => {
+ flash(s__('FeatureFlags|There was an error retrieving user lists'), FLASH_TYPES.WARNING);
+ });
+ }
+ },
+ methods: {
+ keyFor(strategy) {
+ if (strategy.id) {
+ return strategy.id;
+ }
+
+ return uniqueId('strategy_');
+ },
+
+ addStrategy() {
+ this.formStrategies.push({ name: ROLLOUT_STRATEGY_ALL_USERS, parameters: {}, scopes: [] });
+ },
+
+ deleteStrategy(s) {
+ if (isNumber(s.id)) {
+ Vue.set(s, 'shouldBeDestroyed', true);
+ } else {
+ this.formStrategies = this.formStrategies.filter(strategy => strategy !== s);
+ }
+ },
+
+ isAllEnvironment(name) {
+ return name === ALL_ENVIRONMENTS_NAME;
+ },
+
+ /**
+ * When the user clicks the remove button we delete the scope
+ *
+ * If the scope has an ID, we need to add the `shouldBeDestroyed` flag.
+ * If the scope does *not* have an ID, we can just remove it.
+ *
+ * This flag will be used when submitting the data to the backend
+ * to determine which records to delete (via a "_destroy" property).
+ *
+ * @param {Object} scope
+ */
+ removeScope(scope) {
+ if (isString(scope.id) && scope.id.startsWith(INTERNAL_ID_PREFIX)) {
+ this.formScopes = this.formScopes.filter(s => s !== scope);
+ } else {
+ Vue.set(scope, 'shouldBeDestroyed', true);
+ }
+ },
+
+ /**
+ * Creates a new scope and adds it to the list of scopes
+ *
+ * @param overrides An object whose properties will
+ * be used override the default scope options
+ */
+ createNewScope(overrides) {
+ this.formScopes.push(createNewEnvironmentScope(overrides, this.permissionsFlag));
+ this.newScope = '';
+ },
+
+ /**
+ * When the user clicks the submit button
+ * it triggers an event with the form data
+ */
+ handleSubmit() {
+ const flag = {
+ name: this.formName,
+ description: this.formDescription,
+ active: this.active,
+ version: this.version,
+ };
+
+ if (this.version === LEGACY_FLAG) {
+ flag.scopes = this.formScopes;
+ } else {
+ flag.strategies = this.formStrategies;
+ }
+
+ this.$emit('handleSubmit', flag);
+ },
+
+ canUpdateScope(scope) {
+ return !this.permissionsFlag || scope.canUpdate;
+ },
+
+ isRolloutPercentageInvalid: memoize(function isRolloutPercentageInvalid(percentage) {
+ return !this.$options.rolloutPercentageRegex.test(percentage);
+ }),
+
+ /**
+ * Generates a unique ID for the strategy based on the v-for index
+ *
+ * @param index The index of the strategy
+ */
+ rolloutStrategyId(index) {
+ return `rollout-strategy-${index}`;
+ },
+
+ /**
+ * Generates a unique ID for the percentage based on the v-for index
+ *
+ * @param index The index of the percentage
+ */
+ rolloutPercentageId(index) {
+ return `rollout-percentage-${index}`;
+ },
+ rolloutUserId(index) {
+ return `rollout-user-id-${index}`;
+ },
+
+ shouldDisplayIncludeUserIds(scope) {
+ return ![ROLLOUT_STRATEGY_ALL_USERS, ROLLOUT_STRATEGY_USER_ID].includes(
+ scope.rolloutStrategy,
+ );
+ },
+ shouldDisplayUserIds(scope) {
+ return scope.rolloutStrategy === ROLLOUT_STRATEGY_USER_ID || scope.shouldIncludeUserIds;
+ },
+ onStrategyChange(index) {
+ const scope = this.filteredScopes[index];
+ scope.shouldIncludeUserIds =
+ scope.rolloutUserIds.length > 0 &&
+ scope.rolloutStrategy === ROLLOUT_STRATEGY_PERCENT_ROLLOUT;
+ },
+ onFormStrategyChange(strategy, index) {
+ Object.assign(this.filteredStrategies[index], strategy);
+ },
+ },
+};
+</script>
+<template>
+ <form class="feature-flags-form">
+ <fieldset>
+ <div class="row">
+ <div class="form-group col-md-4">
+ <label for="feature-flag-name" class="label-bold">{{ s__('FeatureFlags|Name') }} *</label>
+ <input
+ id="feature-flag-name"
+ v-model="formName"
+ :disabled="!canUpdateFlag"
+ class="form-control"
+ />
+ </div>
+ </div>
+
+ <div class="row">
+ <div class="form-group col-md-4">
+ <label for="feature-flag-description" class="label-bold">
+ {{ s__('FeatureFlags|Description') }}
+ </label>
+ <textarea
+ id="feature-flag-description"
+ v-model="formDescription"
+ :disabled="!canUpdateFlag"
+ class="form-control"
+ rows="4"
+ ></textarea>
+ </div>
+ </div>
+
+ <related-issues-root
+ v-if="showRelatedIssues"
+ :endpoint="featureFlagIssuesEndpoint"
+ :can-admin="true"
+ :show-categorized-issues="false"
+ />
+
+ <template v-if="supportsStrategies">
+ <div class="row">
+ <div class="col-md-12">
+ <h4>{{ s__('FeatureFlags|Strategies') }}</h4>
+ <div class="flex align-items-baseline justify-content-between">
+ <p class="mr-3">{{ $options.translations.newHelpText }}</p>
+ <gl-button variant="success" category="secondary" @click="addStrategy">
+ {{ s__('FeatureFlags|Add strategy') }}
+ </gl-button>
+ </div>
+ </div>
+ </div>
+ <div v-if="filteredStrategies.length > 0" data-testid="feature-flag-strategies">
+ <strategy
+ v-for="(strategy, index) in filteredStrategies"
+ :key="keyFor(strategy)"
+ :strategy="strategy"
+ :index="index"
+ :user-lists="userLists"
+ @change="onFormStrategyChange($event, index)"
+ @delete="deleteStrategy(strategy)"
+ />
+ </div>
+ <div v-else class="flex justify-content-center border-top py-4 w-100">
+ <span>{{ $options.translations.noStrategiesText }}</span>
+ </div>
+ </template>
+
+ <div v-else class="row">
+ <div class="form-group col-md-12">
+ <h4>{{ s__('FeatureFlags|Target environments') }}</h4>
+ <gl-sprintf :message="$options.translations.helpText">
+ <template #code="{ content }">
+ <code>{{ content }}</code>
+ </template>
+ <template #bold="{ content }">
+ <b>{{ content }}</b>
+ </template>
+ </gl-sprintf>
+
+ <div class="js-scopes-table gl-mt-3">
+ <div class="gl-responsive-table-row table-row-header" role="row">
+ <div class="table-section section-30" role="columnheader">
+ {{ s__('FeatureFlags|Environment Spec') }}
+ </div>
+ <div class="table-section section-20 text-center" role="columnheader">
+ {{ s__('FeatureFlags|Status') }}
+ </div>
+ <div class="table-section section-40" role="columnheader">
+ {{ s__('FeatureFlags|Rollout Strategy') }}
+ </div>
+ </div>
+
+ <div
+ v-for="(scope, index) in filteredScopes"
+ :key="scope.id"
+ ref="scopeRow"
+ class="gl-responsive-table-row"
+ role="row"
+ >
+ <div class="table-section section-30" role="gridcell">
+ <div class="table-mobile-header" role="rowheader">
+ {{ s__('FeatureFlags|Environment Spec') }}
+ </div>
+ <div
+ class="table-mobile-content js-feature-flag-status d-flex align-items-center justify-content-start"
+ >
+ <p v-if="isAllEnvironment(scope.environmentScope)" class="js-scope-all pl-3">
+ {{ $options.translations.allEnvironmentsText }}
+ </p>
+
+ <environments-dropdown
+ v-else
+ class="col-12"
+ :value="scope.environmentScope"
+ :disabled="!canUpdateScope(scope) || scope.environmentScope !== ''"
+ @selectEnvironment="env => (scope.environmentScope = env)"
+ @createClicked="env => (scope.environmentScope = env)"
+ @clearInput="env => (scope.environmentScope = '')"
+ />
+
+ <gl-badge v-if="permissionsFlag && scope.protected" variant="success">
+ {{ s__('FeatureFlags|Protected') }}
+ </gl-badge>
+ </div>
+ </div>
+
+ <div class="table-section section-20 text-center" role="gridcell">
+ <div class="table-mobile-header" role="rowheader">
+ {{ s__('FeatureFlags|Status') }}
+ </div>
+ <div class="table-mobile-content js-feature-flag-status">
+ <toggle-button
+ :value="scope.active"
+ :disabled-input="!active || !canUpdateScope(scope)"
+ @change="status => (scope.active = status)"
+ />
+ </div>
+ </div>
+
+ <div class="table-section section-40" role="gridcell">
+ <div class="table-mobile-header" role="rowheader">
+ {{ s__('FeatureFlags|Rollout Strategy') }}
+ </div>
+ <div class="table-mobile-content js-rollout-strategy form-inline">
+ <label class="sr-only" :for="rolloutStrategyId(index)">
+ {{ s__('FeatureFlags|Rollout Strategy') }}
+ </label>
+ <div class="select-wrapper col-12 col-md-8 p-0">
+ <select
+ :id="rolloutStrategyId(index)"
+ v-model="scope.rolloutStrategy"
+ :disabled="!scope.active"
+ class="form-control select-control w-100 js-rollout-strategy"
+ @change="onStrategyChange(index)"
+ >
+ <option :value="$options.ROLLOUT_STRATEGY_ALL_USERS">
+ {{ s__('FeatureFlags|All users') }}
+ </option>
+ <option :value="$options.ROLLOUT_STRATEGY_PERCENT_ROLLOUT">
+ {{ s__('FeatureFlags|Percent rollout (logged in users)') }}
+ </option>
+ <option :value="$options.ROLLOUT_STRATEGY_USER_ID">
+ {{ s__('FeatureFlags|User IDs') }}
+ </option>
+ </select>
+ <gl-icon
+ name="chevron-down"
+ class="gl-absolute gl-top-3 gl-right-3 gl-text-gray-500"
+ :size="16"
+ />
+ </div>
+
+ <div
+ v-if="scope.rolloutStrategy === $options.ROLLOUT_STRATEGY_PERCENT_ROLLOUT"
+ class="d-flex-center mt-2 mt-md-0 ml-md-2"
+ >
+ <label class="sr-only" :for="rolloutPercentageId(index)">
+ {{ s__('FeatureFlags|Rollout Percentage') }}
+ </label>
+ <div class="gl-w-9">
+ <input
+ :id="rolloutPercentageId(index)"
+ v-model="scope.rolloutPercentage"
+ :disabled="!scope.active"
+ :class="{
+ 'is-invalid': isRolloutPercentageInvalid(scope.rolloutPercentage),
+ }"
+ type="number"
+ min="0"
+ max="100"
+ :pattern="$options.rolloutPercentageRegex.source"
+ class="rollout-percentage js-rollout-percentage form-control text-right w-100"
+ />
+ </div>
+ <gl-tooltip
+ v-if="isRolloutPercentageInvalid(scope.rolloutPercentage)"
+ :target="rolloutPercentageId(index)"
+ >
+ {{
+ s__('FeatureFlags|Percent rollout must be a whole number between 0 and 100')
+ }}
+ </gl-tooltip>
+ <span class="ml-1">%</span>
+ </div>
+ <div class="d-flex flex-column align-items-start mt-2 w-100">
+ <gl-form-checkbox
+ v-if="shouldDisplayIncludeUserIds(scope)"
+ v-model="scope.shouldIncludeUserIds"
+ >{{ s__('FeatureFlags|Include additional user IDs') }}</gl-form-checkbox
+ >
+ <template v-if="shouldDisplayUserIds(scope)">
+ <label :for="rolloutUserId(index)" class="mb-2">
+ {{ s__('FeatureFlags|User IDs') }}
+ </label>
+ <gl-form-textarea
+ :id="rolloutUserId(index)"
+ v-model="scope.rolloutUserIds"
+ class="w-100"
+ />
+ </template>
+ </div>
+ </div>
+ </div>
+
+ <div class="table-section section-10 text-right" role="gridcell">
+ <div class="table-mobile-header" role="rowheader">
+ {{ s__('FeatureFlags|Remove') }}
+ </div>
+ <div class="table-mobile-content js-feature-flag-delete">
+ <gl-button
+ v-if="!isAllEnvironment(scope.environmentScope) && canUpdateScope(scope)"
+ v-gl-tooltip
+ :title="s__('FeatureFlags|Remove')"
+ class="js-delete-scope btn-transparent pr-3 pl-3"
+ icon="clear"
+ @click="removeScope(scope)"
+ />
+ </div>
+ </div>
+ </div>
+
+ <div class="js-add-new-scope gl-responsive-table-row" role="row">
+ <div class="table-section section-30" role="gridcell">
+ <div class="table-mobile-header" role="rowheader">
+ {{ s__('FeatureFlags|Environment Spec') }}
+ </div>
+ <div class="table-mobile-content js-feature-flag-status">
+ <environments-dropdown
+ class="js-new-scope-name col-12"
+ :value="newScope"
+ @selectEnvironment="env => createNewScope({ environmentScope: env })"
+ @createClicked="env => createNewScope({ environmentScope: env })"
+ />
+ </div>
+ </div>
+
+ <div class="table-section section-20 text-center" role="gridcell">
+ <div class="table-mobile-header" role="rowheader">
+ {{ s__('FeatureFlags|Status') }}
+ </div>
+ <div class="table-mobile-content js-feature-flag-status">
+ <toggle-button
+ :disabled-input="!active"
+ :value="false"
+ @change="createNewScope({ active: true })"
+ />
+ </div>
+ </div>
+
+ <div class="table-section section-40" role="gridcell">
+ <div class="table-mobile-header" role="rowheader">
+ {{ s__('FeatureFlags|Rollout Strategy') }}
+ </div>
+ <div class="table-mobile-content js-rollout-strategy form-inline">
+ <label class="sr-only" for="new-rollout-strategy-placeholder">{{
+ s__('FeatureFlags|Rollout Strategy')
+ }}</label>
+ <div class="select-wrapper col-12 col-md-8 p-0">
+ <select
+ id="new-rollout-strategy-placeholder"
+ disabled
+ class="form-control select-control w-100"
+ >
+ <option>{{ s__('FeatureFlags|All users') }}</option>
+ </select>
+ <gl-icon
+ name="chevron-down"
+ class="gl-absolute gl-top-3 gl-right-3 gl-text-gray-500"
+ :size="16"
+ />
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </fieldset>
+
+ <div class="form-actions">
+ <gl-button
+ ref="submitButton"
+ :disabled="readOnly"
+ type="button"
+ variant="success"
+ class="js-ff-submit col-xs-12"
+ @click="handleSubmit"
+ >{{ submitText }}</gl-button
+ >
+ <gl-button :href="cancelPath" class="js-ff-cancel col-xs-12 float-right">
+ {{ __('Cancel') }}
+ </gl-button>
+ </div>
+ </form>
+</template>
diff --git a/app/assets/javascripts/feature_flags/components/new_environments_dropdown.vue b/app/assets/javascripts/feature_flags/components/new_environments_dropdown.vue
new file mode 100644
index 00000000000..f2017c22abf
--- /dev/null
+++ b/app/assets/javascripts/feature_flags/components/new_environments_dropdown.vue
@@ -0,0 +1,100 @@
+<script>
+import { debounce } from 'lodash';
+import {
+ GlDropdown,
+ GlDropdownDivider,
+ GlDropdownItem,
+ GlIcon,
+ GlLoadingIcon,
+ GlSearchBoxByType,
+} from '@gitlab/ui';
+import axios from '~/lib/utils/axios_utils';
+import { __, sprintf } from '~/locale';
+import { deprecatedCreateFlash as createFlash } from '~/flash';
+
+export default {
+ components: {
+ GlDropdown,
+ GlDropdownDivider,
+ GlDropdownItem,
+ GlSearchBoxByType,
+ GlIcon,
+ GlLoadingIcon,
+ },
+ inject: ['environmentsEndpoint'],
+ data() {
+ return {
+ environmentSearch: '',
+ results: [],
+ isLoading: false,
+ };
+ },
+ translations: {
+ addEnvironmentsLabel: __('Add environment'),
+ noResultsLabel: __('No matching results'),
+ },
+ computed: {
+ createEnvironmentLabel() {
+ return sprintf(__('Create %{environment}'), { environment: this.environmentSearch });
+ },
+ },
+ methods: {
+ addEnvironment(newEnvironment) {
+ this.$emit('add', newEnvironment);
+ this.environmentSearch = '';
+ this.results = [];
+ },
+ fetchEnvironments: debounce(function debouncedFetchEnvironments() {
+ this.isLoading = true;
+ axios
+ .get(this.environmentsEndpoint, { params: { query: this.environmentSearch } })
+ .then(({ data }) => {
+ this.results = data || [];
+ })
+ .catch(() => {
+ createFlash(__('Something went wrong on our end. Please try again.'));
+ })
+ .finally(() => {
+ this.isLoading = false;
+ });
+ }, 250),
+ setFocus() {
+ this.$refs.searchBox.focusInput();
+ },
+ },
+};
+</script>
+<template>
+ <gl-dropdown class="js-new-environments-dropdown" @shown="setFocus">
+ <template #button-content>
+ <span class="d-md-none mr-1">
+ {{ $options.translations.addEnvironmentsLabel }}
+ </span>
+ <gl-icon class="d-none d-md-inline-flex" name="plus" />
+ </template>
+ <gl-search-box-by-type
+ ref="searchBox"
+ v-model.trim="environmentSearch"
+ @focus="fetchEnvironments"
+ @keyup="fetchEnvironments"
+ />
+ <gl-loading-icon v-if="isLoading" />
+ <gl-dropdown-item
+ v-for="environment in results"
+ v-else-if="results.length"
+ :key="environment"
+ @click="addEnvironment(environment)"
+ >
+ {{ environment }}
+ </gl-dropdown-item>
+ <template v-else-if="environmentSearch.length">
+ <span ref="noResults" class="text-secondary gl-p-3">
+ {{ $options.translations.noMatchingResults }}
+ </span>
+ <gl-dropdown-divider />
+ <gl-dropdown-item @click="addEnvironment(environmentSearch)">
+ {{ createEnvironmentLabel }}
+ </gl-dropdown-item>
+ </template>
+ </gl-dropdown>
+</template>
diff --git a/app/assets/javascripts/feature_flags/components/new_feature_flag.vue b/app/assets/javascripts/feature_flags/components/new_feature_flag.vue
new file mode 100644
index 00000000000..9472eddf336
--- /dev/null
+++ b/app/assets/javascripts/feature_flags/components/new_feature_flag.vue
@@ -0,0 +1,101 @@
+<script>
+import { mapState, mapActions } from 'vuex';
+import { GlAlert } from '@gitlab/ui';
+import axios from '~/lib/utils/axios_utils';
+import FeatureFlagForm from './form.vue';
+import {
+ LEGACY_FLAG,
+ NEW_VERSION_FLAG,
+ NEW_FLAG_ALERT,
+ ROLLOUT_STRATEGY_ALL_USERS,
+} from '../constants';
+import { createNewEnvironmentScope } from '../store/helpers';
+
+import featureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
+
+export default {
+ components: {
+ GlAlert,
+ FeatureFlagForm,
+ },
+ mixins: [featureFlagsMixin()],
+ inject: {
+ showUserCallout: {},
+ userCalloutId: {
+ default: '',
+ },
+ userCalloutsPath: {
+ default: '',
+ },
+ },
+ data() {
+ return {
+ userShouldSeeNewFlagAlert: this.showUserCallout,
+ };
+ },
+ translations: {
+ newFlagAlert: NEW_FLAG_ALERT,
+ },
+ computed: {
+ ...mapState(['error', 'path']),
+ scopes() {
+ return [
+ createNewEnvironmentScope(
+ {
+ environmentScope: '*',
+ active: true,
+ },
+ this.glFeatures.featureFlagsPermissions,
+ ),
+ ];
+ },
+ version() {
+ return this.hasNewVersionFlags ? NEW_VERSION_FLAG : LEGACY_FLAG;
+ },
+ hasNewVersionFlags() {
+ return this.glFeatures.featureFlagsNewVersion;
+ },
+ shouldShowNewFlagAlert() {
+ return !this.hasNewVersionFlags && this.userShouldSeeNewFlagAlert;
+ },
+ strategies() {
+ return [{ name: ROLLOUT_STRATEGY_ALL_USERS, parameters: {}, scopes: [] }];
+ },
+ },
+ methods: {
+ ...mapActions(['createFeatureFlag']),
+ dismissNewVersionFlagAlert() {
+ this.userShouldSeeNewFlagAlert = false;
+ axios.post(this.userCalloutsPath, {
+ feature_name: this.userCalloutId,
+ });
+ },
+ },
+};
+</script>
+<template>
+ <div>
+ <gl-alert
+ v-if="shouldShowNewFlagAlert"
+ variant="warning"
+ class="gl-my-5"
+ @dismiss="dismissNewVersionFlagAlert"
+ >
+ {{ $options.translations.newFlagAlert }}
+ </gl-alert>
+ <h3 class="page-title">{{ s__('FeatureFlags|New feature flag') }}</h3>
+
+ <div v-if="error.length" class="alert alert-danger">
+ <p v-for="(message, index) in error" :key="index" class="mb-0">{{ message }}</p>
+ </div>
+
+ <feature-flag-form
+ :cancel-path="path"
+ :submit-text="s__('FeatureFlags|Create feature flag')"
+ :scopes="scopes"
+ :strategies="strategies"
+ :version="version"
+ @handleSubmit="data => createFeatureFlag(data)"
+ />
+ </div>
+</template>
diff --git a/app/assets/javascripts/feature_flags/components/strategies/default.vue b/app/assets/javascripts/feature_flags/components/strategies/default.vue
new file mode 100644
index 00000000000..cb8ffbddfbd
--- /dev/null
+++ b/app/assets/javascripts/feature_flags/components/strategies/default.vue
@@ -0,0 +1,10 @@
+<script>
+export default {
+ mounted() {
+ this.$emit('change', { parameters: {} });
+ },
+ render() {
+ return this.$slots.default;
+ },
+};
+</script>
diff --git a/app/assets/javascripts/feature_flags/components/strategies/flexible_rollout.vue b/app/assets/javascripts/feature_flags/components/strategies/flexible_rollout.vue
new file mode 100644
index 00000000000..020a0d43096
--- /dev/null
+++ b/app/assets/javascripts/feature_flags/components/strategies/flexible_rollout.vue
@@ -0,0 +1,121 @@
+<script>
+import { GlFormInput, GlFormSelect } from '@gitlab/ui';
+import { __ } from '~/locale';
+import { PERCENT_ROLLOUT_GROUP_ID } from '../../constants';
+import ParameterFormGroup from './parameter_form_group.vue';
+
+export default {
+ components: {
+ GlFormInput,
+ GlFormSelect,
+ ParameterFormGroup,
+ },
+ props: {
+ strategy: {
+ required: true,
+ type: Object,
+ },
+ },
+ i18n: {
+ percentageDescription: __('Enter a whole number between 0 and 100'),
+ percentageInvalid: __('Percent rollout must be a whole number between 0 and 100'),
+ percentageLabel: __('Percentage'),
+ stickinessDescription: __('Consistency guarantee method'),
+ stickinessLabel: __('Based on'),
+ },
+ stickinessOptions: [
+ {
+ value: 'DEFAULT',
+ text: __('Available ID'),
+ },
+ {
+ value: 'USERID',
+ text: __('User ID'),
+ },
+ {
+ value: 'SESSIONID',
+ text: __('Session ID'),
+ },
+ {
+ value: 'RANDOM',
+ text: __('Random'),
+ },
+ ],
+ computed: {
+ isValid() {
+ const percentageNum = Number(this.percentage);
+ return Number.isInteger(percentageNum) && percentageNum >= 0 && percentageNum <= 100;
+ },
+ percentage() {
+ return this.strategy?.parameters?.rollout ?? '100';
+ },
+ stickiness() {
+ return this.strategy?.parameters?.stickiness ?? this.$options.stickinessOptions[0].value;
+ },
+ },
+ methods: {
+ onPercentageChange(value) {
+ this.$emit('change', {
+ parameters: {
+ groupId: PERCENT_ROLLOUT_GROUP_ID,
+ rollout: value,
+ stickiness: this.stickiness,
+ },
+ });
+ },
+ onStickinessChange(value) {
+ this.$emit('change', {
+ parameters: {
+ groupId: PERCENT_ROLLOUT_GROUP_ID,
+ rollout: this.percentage,
+ stickiness: value,
+ },
+ });
+ },
+ },
+};
+</script>
+<template>
+ <div class="gl-display-flex">
+ <div class="gl-mr-7" data-testid="strategy-flexible-rollout-percentage">
+ <parameter-form-group
+ :label="$options.i18n.percentageLabel"
+ :description="isValid ? $options.i18n.percentageDescription : ''"
+ :invalid-feedback="$options.i18n.percentageInvalid"
+ :state="isValid"
+ >
+ <template #default="{ inputId }">
+ <div class="gl-display-flex gl-align-items-center">
+ <gl-form-input
+ :id="inputId"
+ :value="percentage"
+ :state="isValid"
+ class="rollout-percentage gl-text-right gl-w-9"
+ type="number"
+ min="0"
+ max="100"
+ @input="onPercentageChange"
+ />
+ <span class="ml-1">%</span>
+ </div>
+ </template>
+ </parameter-form-group>
+ </div>
+
+ <div class="gl-mr-7" data-testid="strategy-flexible-rollout-stickiness">
+ <parameter-form-group
+ :label="$options.i18n.stickinessLabel"
+ :description="$options.i18n.stickinessDescription"
+ >
+ <template #default="{ inputId }">
+ <gl-form-select
+ :id="inputId"
+ :value="stickiness"
+ :options="$options.stickinessOptions"
+ @change="onStickinessChange"
+ />
+ </template>
+ </parameter-form-group>
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/feature_flags/components/strategies/gitlab_user_list.vue b/app/assets/javascripts/feature_flags/components/strategies/gitlab_user_list.vue
new file mode 100644
index 00000000000..ec97e8b1350
--- /dev/null
+++ b/app/assets/javascripts/feature_flags/components/strategies/gitlab_user_list.vue
@@ -0,0 +1,63 @@
+<script>
+import { GlFormSelect } from '@gitlab/ui';
+import { s__ } from '~/locale';
+import ParameterFormGroup from './parameter_form_group.vue';
+
+export default {
+ components: {
+ GlFormSelect,
+ ParameterFormGroup,
+ },
+ props: {
+ strategy: {
+ required: true,
+ type: Object,
+ },
+ userLists: {
+ required: false,
+ type: Array,
+ default: () => [],
+ },
+ },
+ translations: {
+ rolloutUserListLabel: s__('FeatureFlag|List'),
+ rolloutUserListDescription: s__('FeatureFlag|Select a user list'),
+ rolloutUserListNoListError: s__('FeatureFlag|There are no configured user lists'),
+ },
+ computed: {
+ userListOptions() {
+ return this.userLists.map(({ name, id }) => ({ value: id, text: name }));
+ },
+ hasUserLists() {
+ return this.userListOptions.length > 0;
+ },
+ userListId() {
+ return this.strategy?.userListId ?? '';
+ },
+ },
+ methods: {
+ onUserListChange(list) {
+ this.$emit('change', {
+ userListId: list,
+ });
+ },
+ },
+};
+</script>
+<template>
+ <parameter-form-group
+ :state="hasUserLists"
+ :invalid-feedback="$options.translations.rolloutUserListNoListError"
+ :label="$options.translations.rolloutUserListLabel"
+ :description="hasUserLists ? $options.translations.rolloutUserListDescription : ''"
+ >
+ <template #default="{ inputId }">
+ <gl-form-select
+ :id="inputId"
+ :value="userListId"
+ :options="userListOptions"
+ @change="onUserListChange"
+ />
+ </template>
+ </parameter-form-group>
+</template>
diff --git a/app/assets/javascripts/feature_flags/components/strategies/parameter_form_group.vue b/app/assets/javascripts/feature_flags/components/strategies/parameter_form_group.vue
new file mode 100644
index 00000000000..7f2c6d55db8
--- /dev/null
+++ b/app/assets/javascripts/feature_flags/components/strategies/parameter_form_group.vue
@@ -0,0 +1,22 @@
+<script>
+import { uniqueId } from 'lodash';
+import { GlFormGroup } from '@gitlab/ui';
+
+export default {
+ components: {
+ GlFormGroup,
+ },
+ props: {
+ inputId: {
+ required: false,
+ type: String,
+ default: () => uniqueId('feature_flag_strategies_'),
+ },
+ },
+};
+</script>
+<template>
+ <gl-form-group :label-for="inputId" v-bind="$attrs">
+ <slot v-bind="{ inputId }"></slot>
+ </gl-form-group>
+</template>
diff --git a/app/assets/javascripts/feature_flags/components/strategies/percent_rollout.vue b/app/assets/javascripts/feature_flags/components/strategies/percent_rollout.vue
new file mode 100644
index 00000000000..d262769c891
--- /dev/null
+++ b/app/assets/javascripts/feature_flags/components/strategies/percent_rollout.vue
@@ -0,0 +1,69 @@
+<script>
+import { GlFormInput } from '@gitlab/ui';
+import { s__, __ } from '~/locale';
+import { PERCENT_ROLLOUT_GROUP_ID } from '../../constants';
+import ParameterFormGroup from './parameter_form_group.vue';
+
+export default {
+ components: {
+ GlFormInput,
+ ParameterFormGroup,
+ },
+ props: {
+ strategy: {
+ required: true,
+ type: Object,
+ },
+ },
+ i18n: {
+ rolloutPercentageDescription: __('Enter a whole number between 0 and 100'),
+ rolloutPercentageInvalid: s__(
+ 'FeatureFlags|Percent rollout must be a whole number between 0 and 100',
+ ),
+ rolloutPercentageLabel: s__('FeatureFlag|Percentage'),
+ },
+ computed: {
+ isValid() {
+ const percentageNum = Number(this.percentage);
+ return Number.isInteger(percentageNum) && percentageNum >= 0 && percentageNum <= 100;
+ },
+ percentage() {
+ return this.strategy?.parameters?.percentage ?? '100';
+ },
+ },
+ methods: {
+ onPercentageChange(value) {
+ this.$emit('change', {
+ parameters: {
+ percentage: value,
+ groupId: PERCENT_ROLLOUT_GROUP_ID,
+ },
+ });
+ },
+ },
+};
+</script>
+<template>
+ <parameter-form-group
+ :label="$options.i18n.rolloutPercentageLabel"
+ :description="isValid ? $options.i18n.rolloutPercentageDescription : ''"
+ :invalid-feedback="$options.i18n.rolloutPercentageInvalid"
+ :state="isValid"
+ >
+ <template #default="{ inputId }">
+ <div class="gl-display-flex gl-align-items-center">
+ <gl-form-input
+ :id="inputId"
+ :value="percentage"
+ :state="isValid"
+ class="rollout-percentage gl-text-right gl-w-9"
+ type="number"
+ min="0"
+ max="100"
+ @input="onPercentageChange"
+ />
+ <span class="gl-ml-2">%</span>
+ </div>
+ </template>
+ </parameter-form-group>
+</template>
diff --git a/app/assets/javascripts/feature_flags/components/strategies/users_with_id.vue b/app/assets/javascripts/feature_flags/components/strategies/users_with_id.vue
new file mode 100644
index 00000000000..094127fb710
--- /dev/null
+++ b/app/assets/javascripts/feature_flags/components/strategies/users_with_id.vue
@@ -0,0 +1,47 @@
+<script>
+import { GlFormTextarea } from '@gitlab/ui';
+import { __, s__ } from '~/locale';
+
+import ParameterFormGroup from './parameter_form_group.vue';
+
+export default {
+ components: {
+ ParameterFormGroup,
+ GlFormTextarea,
+ },
+ props: {
+ strategy: {
+ required: true,
+ type: Object,
+ },
+ },
+ translations: {
+ rolloutUserIdsDescription: __('Enter one or more user ID separated by commas'),
+ rolloutUserIdsLabel: s__('FeatureFlag|User IDs'),
+ },
+ computed: {
+ userIds() {
+ return this.strategy?.parameters?.userIds ?? '';
+ },
+ },
+ methods: {
+ onUserIdsChange(value) {
+ this.$emit('change', {
+ parameters: {
+ userIds: value,
+ },
+ });
+ },
+ },
+};
+</script>
+<template>
+ <parameter-form-group
+ :label="$options.translations.rolloutUserIdsLabel"
+ :description="$options.translations.rolloutUserIdsDescription"
+ >
+ <template #default="{ inputId }">
+ <gl-form-textarea :id="inputId" :value="userIds" @input="onUserIdsChange" />
+ </template>
+ </parameter-form-group>
+</template>
diff --git a/app/assets/javascripts/feature_flags/components/strategy.vue b/app/assets/javascripts/feature_flags/components/strategy.vue
new file mode 100644
index 00000000000..9c41dde62e4
--- /dev/null
+++ b/app/assets/javascripts/feature_flags/components/strategy.vue
@@ -0,0 +1,206 @@
+<script>
+import Vue from 'vue';
+import { isNumber } from 'lodash';
+import { GlAlert, GlButton, GlFormSelect, GlFormGroup, GlIcon, GlLink, GlToken } from '@gitlab/ui';
+import { s__, __ } from '~/locale';
+import {
+ EMPTY_PARAMETERS,
+ STRATEGY_SELECTIONS,
+ ROLLOUT_STRATEGY_PERCENT_ROLLOUT,
+} from '../constants';
+
+import NewEnvironmentsDropdown from './new_environments_dropdown.vue';
+import StrategyParameters from './strategy_parameters.vue';
+
+export default {
+ components: {
+ GlAlert,
+ GlButton,
+ GlFormGroup,
+ GlFormSelect,
+ GlIcon,
+ GlLink,
+ GlToken,
+ NewEnvironmentsDropdown,
+ StrategyParameters,
+ },
+ inject: {
+ strategyTypeDocsPagePath: {
+ default: '',
+ },
+ environmentsScopeDocsPath: {
+ default: '',
+ },
+ },
+ props: {
+ strategy: {
+ type: Object,
+ required: true,
+ },
+ index: {
+ type: Number,
+ required: true,
+ },
+ userLists: {
+ type: Array,
+ required: false,
+ default: () => [],
+ },
+ },
+
+ i18n: {
+ allEnvironments: __('All environments'),
+ environmentsLabel: __('Environments'),
+ strategyTypeDescription: __('Select strategy activation method'),
+ strategyTypeLabel: s__('FeatureFlag|Type'),
+ environmentsSelectDescription: s__(
+ 'FeatureFlag|Select the environment scope for this feature flag',
+ ),
+ considerFlexibleRollout: s__(
+ 'FeatureFlags|Consider using the more flexible "Percent rollout" strategy instead.',
+ ),
+ },
+
+ strategies: STRATEGY_SELECTIONS,
+
+ data() {
+ return {
+ environments: this.strategy.scopes || [],
+ formStrategy: { ...this.strategy },
+ };
+ },
+ computed: {
+ strategyTypeId() {
+ return `strategy-type-${this.index}`;
+ },
+ environmentsDropdownId() {
+ return `environments-dropdown-${this.index}`;
+ },
+ appliesToAllEnvironments() {
+ return (
+ this.filteredEnvironments.length === 1 &&
+ this.filteredEnvironments[0].environmentScope === '*'
+ );
+ },
+ filteredEnvironments() {
+ return this.environments.filter(e => !e.shouldBeDestroyed);
+ },
+ isPercentUserRollout() {
+ return this.formStrategy.name === ROLLOUT_STRATEGY_PERCENT_ROLLOUT;
+ },
+ },
+ methods: {
+ addEnvironment(environment) {
+ const allEnvironmentsScope = this.environments.find(scope => scope.environmentScope === '*');
+ if (allEnvironmentsScope) {
+ allEnvironmentsScope.shouldBeDestroyed = true;
+ }
+ this.environments.push({ environmentScope: environment });
+ this.onStrategyChange({ ...this.formStrategy, scopes: this.environments });
+ },
+ onStrategyTypeChange(name) {
+ this.onStrategyChange({
+ ...this.formStrategy,
+ ...EMPTY_PARAMETERS,
+ name,
+ });
+ },
+ onStrategyChange(s) {
+ this.$emit('change', s);
+ this.formStrategy = s;
+ },
+ removeScope(environment) {
+ if (isNumber(environment.id)) {
+ Vue.set(environment, 'shouldBeDestroyed', true);
+ } else {
+ this.environments = this.environments.filter(e => e !== environment);
+ }
+ if (this.filteredEnvironments.length === 0) {
+ this.environments.push({ environmentScope: '*' });
+ }
+ this.onStrategyChange({ ...this.formStrategy, scopes: this.environments });
+ },
+ },
+};
+</script>
+<template>
+ <div>
+ <gl-alert v-if="isPercentUserRollout" variant="tip" :dismissible="false">
+ {{ $options.i18n.considerFlexibleRollout }}
+ </gl-alert>
+
+ <div class="gl-border-t-solid gl-border-t-1 gl-border-t-gray-100 gl-py-6">
+ <div class="gl-display-flex gl-flex-direction-column gl-md-flex-direction-row flex-md-wrap">
+ <div class="mr-5">
+ <gl-form-group :label="$options.i18n.strategyTypeLabel" :label-for="strategyTypeId">
+ <template #description>
+ {{ $options.i18n.strategyTypeDescription }}
+ <gl-link :href="strategyTypeDocsPagePath" target="_blank">
+ <gl-icon name="question" />
+ </gl-link>
+ </template>
+ <gl-form-select
+ :id="strategyTypeId"
+ :value="formStrategy.name"
+ :options="$options.strategies"
+ @change="onStrategyTypeChange"
+ />
+ </gl-form-group>
+ </div>
+
+ <div data-testid="strategy">
+ <strategy-parameters
+ :strategy="strategy"
+ :user-lists="userLists"
+ @change="onStrategyChange"
+ />
+ </div>
+
+ <div
+ class="align-self-end align-self-md-stretch order-first offset-md-0 order-md-0 gl-ml-auto"
+ >
+ <gl-button
+ data-testid="delete-strategy-button"
+ variant="danger"
+ icon="remove"
+ @click="$emit('delete')"
+ />
+ </div>
+ </div>
+
+ <label class="gl-display-block" :for="environmentsDropdownId">{{
+ $options.i18n.environmentsLabel
+ }}</label>
+ <div class="gl-display-flex gl-flex-direction-column">
+ <div
+ class="gl-display-flex gl-flex-direction-column gl-md-flex-direction-row align-items-start gl-md-align-items-center"
+ >
+ <new-environments-dropdown
+ :id="environmentsDropdownId"
+ class="gl-mr-3"
+ @add="addEnvironment"
+ />
+ <span v-if="appliesToAllEnvironments" class="text-secondary gl-mt-3 mt-md-0 ml-md-3">
+ {{ $options.i18n.allEnvironments }}
+ </span>
+ <div v-else class="gl-display-flex gl-align-items-center">
+ <gl-token
+ v-for="environment in filteredEnvironments"
+ :key="environment.id"
+ class="gl-mt-3 gl-mr-3 mt-md-0 mr-md-0 ml-md-2 rounded-pill"
+ @close="removeScope(environment)"
+ >
+ {{ environment.environmentScope }}
+ </gl-token>
+ </div>
+ </div>
+ </div>
+ <span class="gl-display-inline-block gl-py-3">
+ {{ $options.i18n.environmentsSelectDescription }}
+ </span>
+ <gl-link :href="environmentsScopeDocsPath" target="_blank">
+ <gl-icon name="question" />
+ </gl-link>
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/feature_flags/components/strategy_parameters.vue b/app/assets/javascripts/feature_flags/components/strategy_parameters.vue
new file mode 100644
index 00000000000..b6e06880315
--- /dev/null
+++ b/app/assets/javascripts/feature_flags/components/strategy_parameters.vue
@@ -0,0 +1,54 @@
+<script>
+import {
+ ROLLOUT_STRATEGY_ALL_USERS,
+ ROLLOUT_STRATEGY_FLEXIBLE_ROLLOUT,
+ ROLLOUT_STRATEGY_PERCENT_ROLLOUT,
+ ROLLOUT_STRATEGY_USER_ID,
+ ROLLOUT_STRATEGY_GITLAB_USER_LIST,
+} from '../constants';
+
+import Default from './strategies/default.vue';
+import FlexibleRollout from './strategies/flexible_rollout.vue';
+import PercentRollout from './strategies/percent_rollout.vue';
+import UsersWithId from './strategies/users_with_id.vue';
+import GitlabUserList from './strategies/gitlab_user_list.vue';
+
+const STRATEGIES = Object.freeze({
+ [ROLLOUT_STRATEGY_ALL_USERS]: Default,
+ [ROLLOUT_STRATEGY_FLEXIBLE_ROLLOUT]: FlexibleRollout,
+ [ROLLOUT_STRATEGY_PERCENT_ROLLOUT]: PercentRollout,
+ [ROLLOUT_STRATEGY_USER_ID]: UsersWithId,
+ [ROLLOUT_STRATEGY_GITLAB_USER_LIST]: GitlabUserList,
+});
+
+export default {
+ props: {
+ strategy: {
+ type: Object,
+ required: true,
+ },
+ },
+ computed: {
+ strategyComponent() {
+ return STRATEGIES[(this.strategy?.name)];
+ },
+ },
+ methods: {
+ onChange(value) {
+ this.$emit('change', {
+ ...this.strategy,
+ ...value,
+ });
+ },
+ },
+};
+</script>
+<template>
+ <component
+ :is="strategyComponent"
+ v-if="strategyComponent"
+ :strategy="strategy"
+ v-bind="$attrs"
+ @change="onChange"
+ />
+</template>
diff --git a/app/assets/javascripts/feature_flags/components/user_lists_table.vue b/app/assets/javascripts/feature_flags/components/user_lists_table.vue
new file mode 100644
index 00000000000..0bfd18f992c
--- /dev/null
+++ b/app/assets/javascripts/feature_flags/components/user_lists_table.vue
@@ -0,0 +1,122 @@
+<script>
+import {
+ GlButton,
+ GlButtonGroup,
+ GlModal,
+ GlSprintf,
+ GlTooltipDirective,
+ GlModalDirective,
+} from '@gitlab/ui';
+import { s__, sprintf } from '~/locale';
+import timeagoMixin from '~/vue_shared/mixins/timeago';
+
+export default {
+ components: { GlButton, GlButtonGroup, GlModal, GlSprintf },
+ directives: { GlTooltip: GlTooltipDirective, GlModal: GlModalDirective },
+ mixins: [timeagoMixin],
+ props: {
+ userLists: {
+ type: Array,
+ required: true,
+ },
+ },
+ translations: {
+ createdTimeagoLabel: s__('UserList|created %{timeago}'),
+ deleteListTitle: s__('UserList|Delete %{name}?'),
+ deleteListMessage: s__('User list %{name} will be removed. Are you sure?'),
+ },
+ modal: {
+ id: 'deleteListModal',
+ actionPrimary: {
+ text: s__('Delete user list'),
+ attributes: { variant: 'danger', 'data-testid': 'modal-confirm' },
+ },
+ },
+ data() {
+ return {
+ deleteUserList: null,
+ };
+ },
+ computed: {
+ deleteListName() {
+ return this.deleteUserList?.name;
+ },
+ modalTitle() {
+ return sprintf(this.$options.translations.deleteListTitle, {
+ name: this.deleteListName,
+ });
+ },
+ },
+ methods: {
+ createdTimeago(list) {
+ return sprintf(this.$options.translations.createdTimeagoLabel, {
+ timeago: this.timeFormatted(list.created_at),
+ });
+ },
+ displayList(list) {
+ return list.user_xids.replace(/,/g, ', ');
+ },
+ onDelete() {
+ this.$emit('delete', this.deleteUserList);
+ },
+ confirmDeleteList(list) {
+ this.deleteUserList = list;
+ },
+ },
+};
+</script>
+<template>
+ <div>
+ <div
+ v-for="list in userLists"
+ :key="list.id"
+ data-testid="ffUserList"
+ class="gl-border-b-solid gl-border-gray-100 gl-border-b-1 gl-w-full gl-py-4 gl-display-flex gl-justify-content-space-between"
+ >
+ <div class="gl-display-flex gl-flex-direction-column gl-overflow-hidden gl-flex-grow-1">
+ <span data-testid="ffUserListName" class="gl-font-weight-bold gl-mb-2">
+ {{ list.name }}
+ </span>
+ <span
+ v-gl-tooltip
+ :title="tooltipTitle(list.created_at)"
+ data-testid="ffUserListTimestamp"
+ class="gl-text-gray-300 gl-mb-2"
+ >
+ {{ createdTimeago(list) }}
+ </span>
+ <span data-testid="ffUserListIds" class="gl-str-truncated">{{ displayList(list) }}</span>
+ </div>
+
+ <gl-button-group class="gl-align-self-start gl-mt-2">
+ <gl-button
+ :href="list.path"
+ category="secondary"
+ icon="pencil"
+ data-testid="edit-user-list"
+ />
+ <gl-button
+ v-gl-modal="$options.modal.id"
+ category="secondary"
+ variant="danger"
+ icon="remove"
+ data-testid="delete-user-list"
+ @click="confirmDeleteList(list)"
+ />
+ </gl-button-group>
+ </div>
+ <gl-modal
+ :title="modalTitle"
+ :modal-id="$options.modal.id"
+ :action-primary="$options.modal.actionPrimary"
+ static
+ @primary="onDelete"
+ >
+ <gl-sprintf :message="$options.translations.deleteListMessage">
+ <template #name>
+ <b>{{ deleteListName }}</b>
+ </template>
+ </gl-sprintf>
+ </gl-modal>
+ </div>
+</template>
diff --git a/app/assets/javascripts/feature_flags/constants.js b/app/assets/javascripts/feature_flags/constants.js
new file mode 100644
index 00000000000..4843eca149a
--- /dev/null
+++ b/app/assets/javascripts/feature_flags/constants.js
@@ -0,0 +1,54 @@
+import { property } from 'lodash';
+import { s__ } from '~/locale';
+
+export const ROLLOUT_STRATEGY_ALL_USERS = 'default';
+export const ROLLOUT_STRATEGY_PERCENT_ROLLOUT = 'gradualRolloutUserId';
+export const ROLLOUT_STRATEGY_FLEXIBLE_ROLLOUT = 'flexibleRollout';
+export const ROLLOUT_STRATEGY_USER_ID = 'userWithId';
+export const ROLLOUT_STRATEGY_GITLAB_USER_LIST = 'gitlabUserList';
+
+export const PERCENT_ROLLOUT_GROUP_ID = 'default';
+
+export const DEFAULT_PERCENT_ROLLOUT = '100';
+
+export const ALL_ENVIRONMENTS_NAME = '*';
+
+export const INTERNAL_ID_PREFIX = 'internal_';
+
+export const fetchPercentageParams = property(['parameters', 'percentage']);
+export const fetchUserIdParams = property(['parameters', 'userIds']);
+
+export const NEW_VERSION_FLAG = 'new_version_flag';
+export const LEGACY_FLAG = 'legacy_flag';
+
+export const NEW_FLAG_ALERT = s__(
+ 'FeatureFlags|Feature Flags will look different in the next milestone. No action is needed, but you may notice the functionality was changed to improve the workflow.',
+);
+
+export const FEATURE_FLAG_SCOPE = 'featureFlags';
+export const USER_LIST_SCOPE = 'userLists';
+
+export const EMPTY_PARAMETERS = { parameters: {}, userListId: undefined };
+
+export const STRATEGY_SELECTIONS = [
+ {
+ value: ROLLOUT_STRATEGY_ALL_USERS,
+ text: s__('FeatureFlags|All users'),
+ },
+ {
+ value: ROLLOUT_STRATEGY_FLEXIBLE_ROLLOUT,
+ text: s__('FeatureFlags|Percent rollout'),
+ },
+ {
+ value: ROLLOUT_STRATEGY_PERCENT_ROLLOUT,
+ text: s__('FeatureFlags|Percent of users'),
+ },
+ {
+ value: ROLLOUT_STRATEGY_USER_ID,
+ text: s__('FeatureFlags|User IDs'),
+ },
+ {
+ value: ROLLOUT_STRATEGY_GITLAB_USER_LIST,
+ text: s__('FeatureFlags|User List'),
+ },
+];
diff --git a/app/assets/javascripts/feature_flags/edit.js b/app/assets/javascripts/feature_flags/edit.js
new file mode 100644
index 00000000000..b4d2111acf3
--- /dev/null
+++ b/app/assets/javascripts/feature_flags/edit.js
@@ -0,0 +1,41 @@
+import Vue from 'vue';
+import Vuex from 'vuex';
+import { parseBoolean } from '~/lib/utils/common_utils';
+import createStore from './store/edit';
+import EditFeatureFlag from './components/edit_feature_flag.vue';
+
+Vue.use(Vuex);
+
+export default () => {
+ const el = document.querySelector('#js-edit-feature-flag');
+ const {
+ environmentsScopeDocsPath,
+ strategyTypeDocsPagePath,
+ endpoint,
+ featureFlagsPath,
+ environmentsEndpoint,
+ projectId,
+ featureFlagIssuesEndpoint,
+ userCalloutsPath,
+ userCalloutId,
+ showUserCallout,
+ } = el.dataset;
+
+ return new Vue({
+ store: createStore({ endpoint, path: featureFlagsPath }),
+ el,
+ provide: {
+ environmentsScopeDocsPath,
+ strategyTypeDocsPagePath,
+ environmentsEndpoint,
+ projectId,
+ featureFlagIssuesEndpoint,
+ userCalloutsPath,
+ userCalloutId,
+ showUserCallout: parseBoolean(showUserCallout),
+ },
+ render(createElement) {
+ return createElement(EditFeatureFlag);
+ },
+ });
+};
diff --git a/app/assets/javascripts/feature_flags/index.js b/app/assets/javascripts/feature_flags/index.js
new file mode 100644
index 00000000000..a92805d5d85
--- /dev/null
+++ b/app/assets/javascripts/feature_flags/index.js
@@ -0,0 +1,49 @@
+import Vue from 'vue';
+import Vuex from 'vuex';
+import csrf from '~/lib/utils/csrf';
+import FeatureFlagsComponent from './components/feature_flags.vue';
+import createStore from './store/index';
+
+Vue.use(Vuex);
+
+export default () => {
+ const el = document.querySelector('#feature-flags-vue');
+
+ const {
+ projectName,
+ featureFlagsHelpPagePath,
+ errorStateSvgPath,
+ endpoint,
+ projectId,
+ unleashApiInstanceId,
+ rotateInstanceIdPath,
+ featureFlagsClientLibrariesHelpPagePath,
+ featureFlagsClientExampleHelpPagePath,
+ unleashApiUrl,
+ canUserAdminFeatureFlag,
+ newFeatureFlagPath,
+ newUserListPath,
+ featureFlagsLimitExceeded,
+ } = el.dataset;
+
+ return new Vue({
+ el,
+ store: createStore({ endpoint, projectId, unleashApiInstanceId, rotateInstanceIdPath }),
+ provide: {
+ projectName,
+ featureFlagsHelpPagePath,
+ errorStateSvgPath,
+ featureFlagsClientLibrariesHelpPagePath,
+ featureFlagsClientExampleHelpPagePath,
+ unleashApiUrl,
+ csrfToken: csrf.token,
+ canUserConfigure: canUserAdminFeatureFlag !== undefined,
+ newFeatureFlagPath,
+ newUserListPath,
+ featureFlagsLimitExceeded,
+ },
+ render(createElement) {
+ return createElement(FeatureFlagsComponent);
+ },
+ });
+};
diff --git a/app/assets/javascripts/feature_flags/new.js b/app/assets/javascripts/feature_flags/new.js
new file mode 100644
index 00000000000..a1efbd87ec4
--- /dev/null
+++ b/app/assets/javascripts/feature_flags/new.js
@@ -0,0 +1,39 @@
+import Vue from 'vue';
+import Vuex from 'vuex';
+import { parseBoolean } from '~/lib/utils/common_utils';
+import createStore from './store/new';
+import NewFeatureFlag from './components/new_feature_flag.vue';
+
+Vue.use(Vuex);
+
+export default () => {
+ const el = document.querySelector('#js-new-feature-flag');
+ const {
+ environmentsScopeDocsPath,
+ strategyTypeDocsPagePath,
+ endpoint,
+ featureFlagsPath,
+ environmentsEndpoint,
+ projectId,
+ userCalloutsPath,
+ userCalloutId,
+ showUserCallout,
+ } = el.dataset;
+
+ return new Vue({
+ el,
+ store: createStore({ endpoint, path: featureFlagsPath }),
+ provide: {
+ environmentsScopeDocsPath,
+ strategyTypeDocsPagePath,
+ environmentsEndpoint,
+ projectId,
+ userCalloutsPath,
+ userCalloutId,
+ showUserCallout: parseBoolean(showUserCallout),
+ },
+ render(createElement) {
+ return createElement(NewFeatureFlag);
+ },
+ });
+};
diff --git a/app/assets/javascripts/feature_flags/store/edit/actions.js b/app/assets/javascripts/feature_flags/store/edit/actions.js
new file mode 100644
index 00000000000..3678c2f7788
--- /dev/null
+++ b/app/assets/javascripts/feature_flags/store/edit/actions.js
@@ -0,0 +1,61 @@
+import * as types from './mutation_types';
+import axios from '~/lib/utils/axios_utils';
+import { visitUrl } from '~/lib/utils/url_utility';
+import { deprecatedCreateFlash as createFlash } from '~/flash';
+import { __ } from '~/locale';
+import { NEW_VERSION_FLAG } from '../../constants';
+import { mapFromScopesViewModel, mapStrategiesToRails } from '../helpers';
+
+/**
+ * Handles the edition of a feature flag.
+ *
+ * Will dispatch `requestUpdateFeatureFlag`
+ * Serializes the params and makes a put request
+ * Dispatches an action acording to the request status.
+ *
+ * @param {Object} params
+ */
+export const updateFeatureFlag = ({ state, dispatch }, params) => {
+ dispatch('requestUpdateFeatureFlag');
+
+ axios
+ .put(
+ state.endpoint,
+ params.version === NEW_VERSION_FLAG
+ ? mapStrategiesToRails(params)
+ : mapFromScopesViewModel(params),
+ )
+ .then(() => {
+ dispatch('receiveUpdateFeatureFlagSuccess');
+ visitUrl(state.path);
+ })
+ .catch(error => dispatch('receiveUpdateFeatureFlagError', error.response.data));
+};
+
+export const requestUpdateFeatureFlag = ({ commit }) => commit(types.REQUEST_UPDATE_FEATURE_FLAG);
+export const receiveUpdateFeatureFlagSuccess = ({ commit }) =>
+ commit(types.RECEIVE_UPDATE_FEATURE_FLAG_SUCCESS);
+export const receiveUpdateFeatureFlagError = ({ commit }, error) =>
+ commit(types.RECEIVE_UPDATE_FEATURE_FLAG_ERROR, error);
+
+/**
+ * Fetches the feature flag data for the edit form
+ */
+export const fetchFeatureFlag = ({ state, dispatch }) => {
+ dispatch('requestFeatureFlag');
+
+ axios
+ .get(state.endpoint)
+ .then(({ data }) => dispatch('receiveFeatureFlagSuccess', data))
+ .catch(() => dispatch('receiveFeatureFlagError'));
+};
+
+export const requestFeatureFlag = ({ commit }) => commit(types.REQUEST_FEATURE_FLAG);
+export const receiveFeatureFlagSuccess = ({ commit }, response) =>
+ commit(types.RECEIVE_FEATURE_FLAG_SUCCESS, response);
+export const receiveFeatureFlagError = ({ commit }) => {
+ commit(types.RECEIVE_FEATURE_FLAG_ERROR);
+ createFlash(__('Something went wrong on our end. Please try again!'));
+};
+
+export const toggleActive = ({ commit }, active) => commit(types.TOGGLE_ACTIVE, active);
diff --git a/app/assets/javascripts/feature_flags/store/edit/index.js b/app/assets/javascripts/feature_flags/store/edit/index.js
new file mode 100644
index 00000000000..f737e0517fc
--- /dev/null
+++ b/app/assets/javascripts/feature_flags/store/edit/index.js
@@ -0,0 +1,11 @@
+import Vuex from 'vuex';
+import state from './state';
+import * as actions from './actions';
+import mutations from './mutations';
+
+export default data =>
+ new Vuex.Store({
+ actions,
+ mutations,
+ state: state(data),
+ });
diff --git a/app/assets/javascripts/feature_flags/store/edit/mutation_types.js b/app/assets/javascripts/feature_flags/store/edit/mutation_types.js
new file mode 100644
index 00000000000..c215dad3513
--- /dev/null
+++ b/app/assets/javascripts/feature_flags/store/edit/mutation_types.js
@@ -0,0 +1,9 @@
+export const REQUEST_UPDATE_FEATURE_FLAG = 'REQUEST_UPDATE_FEATURE_FLAG';
+export const RECEIVE_UPDATE_FEATURE_FLAG_SUCCESS = 'RECEIVE_UPDATE_FEATURE_FLAG_SUCCESS';
+export const RECEIVE_UPDATE_FEATURE_FLAG_ERROR = 'RECEIVE_UPDATE_FEATURE_FLAG_ERROR';
+
+export const REQUEST_FEATURE_FLAG = 'REQUEST_FEATURE_FLAG';
+export const RECEIVE_FEATURE_FLAG_SUCCESS = 'RECEIVE_FEATURE_FLAG_SUCCESS';
+export const RECEIVE_FEATURE_FLAG_ERROR = 'RECEIVE_FEATURE_FLAG_ERROR';
+
+export const TOGGLE_ACTIVE = 'TOGGLE_ACTIVE';
diff --git a/app/assets/javascripts/feature_flags/store/edit/mutations.js b/app/assets/javascripts/feature_flags/store/edit/mutations.js
new file mode 100644
index 00000000000..e60dbaf4a34
--- /dev/null
+++ b/app/assets/javascripts/feature_flags/store/edit/mutations.js
@@ -0,0 +1,39 @@
+import * as types from './mutation_types';
+import { mapToScopesViewModel, mapStrategiesToViewModel } from '../helpers';
+import { LEGACY_FLAG } from '../../constants';
+
+export default {
+ [types.REQUEST_FEATURE_FLAG](state) {
+ state.isLoading = true;
+ },
+ [types.RECEIVE_FEATURE_FLAG_SUCCESS](state, response) {
+ state.isLoading = false;
+ state.hasError = false;
+
+ state.name = response.name;
+ state.description = response.description;
+ state.iid = response.iid;
+ state.active = response.active;
+ state.scopes = mapToScopesViewModel(response.scopes);
+ state.strategies = mapStrategiesToViewModel(response.strategies);
+ state.version = response.version || LEGACY_FLAG;
+ },
+ [types.RECEIVE_FEATURE_FLAG_ERROR](state) {
+ state.isLoading = false;
+ state.hasError = true;
+ },
+ [types.REQUEST_UPDATE_FEATURE_FLAG](state) {
+ state.isSendingRequest = true;
+ state.error = [];
+ },
+ [types.RECEIVE_UPDATE_FEATURE_FLAG_SUCCESS](state) {
+ state.isSendingRequest = false;
+ },
+ [types.RECEIVE_UPDATE_FEATURE_FLAG_ERROR](state, error) {
+ state.isSendingRequest = false;
+ state.error = error.message || [];
+ },
+ [types.TOGGLE_ACTIVE](state, active) {
+ state.active = active;
+ },
+};
diff --git a/app/assets/javascripts/feature_flags/store/edit/state.js b/app/assets/javascripts/feature_flags/store/edit/state.js
new file mode 100644
index 00000000000..ec507532d6a
--- /dev/null
+++ b/app/assets/javascripts/feature_flags/store/edit/state.js
@@ -0,0 +1,18 @@
+import { LEGACY_FLAG } from '../../constants';
+
+export default ({ path, endpoint }) => ({
+ endpoint,
+ path,
+ isSendingRequest: false,
+ error: [],
+
+ name: null,
+ description: null,
+ scopes: [],
+ isLoading: false,
+ hasError: false,
+ iid: null,
+ active: true,
+ strategies: [],
+ version: LEGACY_FLAG,
+});
diff --git a/app/assets/javascripts/feature_flags/store/helpers.js b/app/assets/javascripts/feature_flags/store/helpers.js
new file mode 100644
index 00000000000..db6da815abf
--- /dev/null
+++ b/app/assets/javascripts/feature_flags/store/helpers.js
@@ -0,0 +1,213 @@
+import { isEmpty, uniqueId, isString } from 'lodash';
+import {
+ ROLLOUT_STRATEGY_ALL_USERS,
+ ROLLOUT_STRATEGY_PERCENT_ROLLOUT,
+ ROLLOUT_STRATEGY_USER_ID,
+ ROLLOUT_STRATEGY_GITLAB_USER_LIST,
+ INTERNAL_ID_PREFIX,
+ DEFAULT_PERCENT_ROLLOUT,
+ PERCENT_ROLLOUT_GROUP_ID,
+ fetchPercentageParams,
+ fetchUserIdParams,
+ LEGACY_FLAG,
+} from '../constants';
+
+/**
+ * Converts raw scope objects fetched from the API into an array of scope
+ * objects that is easier/nicer to bind to in Vue.
+ * @param {Array} scopesFromRails An array of scope objects fetched from the API
+ */
+export const mapToScopesViewModel = scopesFromRails =>
+ (scopesFromRails || []).map(s => {
+ const percentStrategy = (s.strategies || []).find(
+ strat => strat.name === ROLLOUT_STRATEGY_PERCENT_ROLLOUT,
+ );
+
+ const rolloutPercentage = fetchPercentageParams(percentStrategy) || DEFAULT_PERCENT_ROLLOUT;
+
+ const userStrategy = (s.strategies || []).find(
+ strat => strat.name === ROLLOUT_STRATEGY_USER_ID,
+ );
+
+ const rolloutStrategy =
+ (percentStrategy && percentStrategy.name) ||
+ (userStrategy && userStrategy.name) ||
+ ROLLOUT_STRATEGY_ALL_USERS;
+
+ const rolloutUserIds = (fetchUserIdParams(userStrategy) || '')
+ .split(',')
+ .filter(id => id)
+ .join(', ');
+
+ return {
+ id: s.id,
+ environmentScope: s.environment_scope,
+ active: Boolean(s.active),
+ canUpdate: Boolean(s.can_update),
+ protected: Boolean(s.protected),
+ rolloutStrategy,
+ rolloutPercentage,
+ rolloutUserIds,
+
+ // eslint-disable-next-line no-underscore-dangle
+ shouldBeDestroyed: Boolean(s._destroy),
+ shouldIncludeUserIds: rolloutUserIds.length > 0 && percentStrategy !== null,
+ };
+ });
+/**
+ * Converts the parameters emitted by the Vue component into
+ * the shape that the Rails API expects.
+ * @param {Array} scopesFromVue An array of scope objects from the Vue component
+ */
+export const mapFromScopesViewModel = params => {
+ const scopes = (params.scopes || []).map(s => {
+ const parameters = {};
+ if (s.rolloutStrategy === ROLLOUT_STRATEGY_PERCENT_ROLLOUT) {
+ parameters.groupId = PERCENT_ROLLOUT_GROUP_ID;
+ parameters.percentage = s.rolloutPercentage;
+ } else if (s.rolloutStrategy === ROLLOUT_STRATEGY_USER_ID) {
+ parameters.userIds = (s.rolloutUserIds || '').replace(/, /g, ',');
+ }
+
+ const userIdParameters = {};
+
+ if (s.shouldIncludeUserIds && s.rolloutStrategy !== ROLLOUT_STRATEGY_USER_ID) {
+ userIdParameters.userIds = (s.rolloutUserIds || '').replace(/, /g, ',');
+ }
+
+ // Strip out any internal IDs
+ const id = isString(s.id) && s.id.startsWith(INTERNAL_ID_PREFIX) ? undefined : s.id;
+
+ const strategies = [
+ {
+ name: s.rolloutStrategy,
+ parameters,
+ },
+ ];
+
+ if (!isEmpty(userIdParameters)) {
+ strategies.push({ name: ROLLOUT_STRATEGY_USER_ID, parameters: userIdParameters });
+ }
+
+ return {
+ id,
+ environment_scope: s.environmentScope,
+ active: s.active,
+ can_update: s.canUpdate,
+ protected: s.protected,
+ _destroy: s.shouldBeDestroyed,
+ strategies,
+ };
+ });
+
+ const model = {
+ operations_feature_flag: {
+ name: params.name,
+ description: params.description,
+ active: params.active,
+ scopes_attributes: scopes,
+ version: LEGACY_FLAG,
+ },
+ };
+
+ return model;
+};
+
+/**
+ * Creates a new feature flag environment scope object for use
+ * in a Vue component. An optional parameter can be passed to
+ * override the property values that are created by default.
+ *
+ * @param {Object} overrides An optional object whose
+ * property values will be used to override the default values.
+ *
+ */
+export const createNewEnvironmentScope = (overrides = {}, featureFlagPermissions = false) => {
+ const defaultScope = {
+ environmentScope: '',
+ active: false,
+ id: uniqueId(INTERNAL_ID_PREFIX),
+ rolloutStrategy: ROLLOUT_STRATEGY_ALL_USERS,
+ rolloutPercentage: DEFAULT_PERCENT_ROLLOUT,
+ rolloutUserIds: '',
+ };
+
+ const newScope = {
+ ...defaultScope,
+ ...overrides,
+ };
+
+ if (featureFlagPermissions) {
+ newScope.canUpdate = true;
+ newScope.protected = false;
+ }
+
+ return newScope;
+};
+
+const mapStrategyScopesToRails = scopes =>
+ scopes.length === 0
+ ? [{ environment_scope: '*' }]
+ : scopes.map(s => ({
+ id: s.id,
+ _destroy: s.shouldBeDestroyed,
+ environment_scope: s.environmentScope,
+ }));
+
+const mapStrategyScopesToView = scopes =>
+ scopes.map(s => ({
+ id: s.id,
+ // eslint-disable-next-line no-underscore-dangle
+ shouldBeDestroyed: Boolean(s._destroy),
+ environmentScope: s.environment_scope,
+ }));
+
+const mapStrategiesParametersToViewModel = params => {
+ if (params.userIds) {
+ return { ...params, userIds: params.userIds.split(',').join(', ') };
+ }
+ return params;
+};
+
+export const mapStrategiesToViewModel = strategiesFromRails =>
+ (strategiesFromRails || []).map(s => ({
+ id: s.id,
+ name: s.name,
+ parameters: mapStrategiesParametersToViewModel(s.parameters),
+ userListId: s.user_list?.id,
+ // eslint-disable-next-line no-underscore-dangle
+ shouldBeDestroyed: Boolean(s._destroy),
+ scopes: mapStrategyScopesToView(s.scopes),
+ }));
+
+const mapStrategiesParametersToRails = params => {
+ if (params.userIds) {
+ return { ...params, userIds: params.userIds.replace(/\s*,\s*/g, ',') };
+ }
+ return params;
+};
+
+const mapStrategyToRails = strategy => {
+ const mappedStrategy = {
+ id: strategy.id,
+ name: strategy.name,
+ _destroy: strategy.shouldBeDestroyed,
+ scopes_attributes: mapStrategyScopesToRails(strategy.scopes || []),
+ parameters: mapStrategiesParametersToRails(strategy.parameters),
+ };
+
+ if (strategy.name === ROLLOUT_STRATEGY_GITLAB_USER_LIST) {
+ mappedStrategy.user_list_id = strategy.userListId;
+ }
+ return mappedStrategy;
+};
+
+export const mapStrategiesToRails = params => ({
+ operations_feature_flag: {
+ name: params.name,
+ description: params.description,
+ version: params.version,
+ active: params.active,
+ strategies_attributes: (params.strategies || []).map(mapStrategyToRails),
+ },
+});
diff --git a/app/assets/javascripts/feature_flags/store/index/actions.js b/app/assets/javascripts/feature_flags/store/index/actions.js
new file mode 100644
index 00000000000..a8c1a72c016
--- /dev/null
+++ b/app/assets/javascripts/feature_flags/store/index/actions.js
@@ -0,0 +1,97 @@
+import Api from '~/api';
+import * as types from './mutation_types';
+import axios from '~/lib/utils/axios_utils';
+
+export const setFeatureFlagsOptions = ({ commit }, options) =>
+ commit(types.SET_FEATURE_FLAGS_OPTIONS, options);
+
+export const fetchFeatureFlags = ({ state, dispatch }) => {
+ dispatch('requestFeatureFlags');
+
+ axios
+ .get(state.endpoint, {
+ params: state.options,
+ })
+ .then(response =>
+ dispatch('receiveFeatureFlagsSuccess', {
+ data: response.data || {},
+ headers: response.headers,
+ }),
+ )
+ .catch(() => dispatch('receiveFeatureFlagsError'));
+};
+
+export const requestFeatureFlags = ({ commit }) => commit(types.REQUEST_FEATURE_FLAGS);
+export const receiveFeatureFlagsSuccess = ({ commit }, response) =>
+ commit(types.RECEIVE_FEATURE_FLAGS_SUCCESS, response);
+export const receiveFeatureFlagsError = ({ commit }) => commit(types.RECEIVE_FEATURE_FLAGS_ERROR);
+
+export const fetchUserLists = ({ state, dispatch }) => {
+ dispatch('requestUserLists');
+
+ return Api.fetchFeatureFlagUserLists(state.projectId, state.options.page)
+ .then(({ data, headers }) => dispatch('receiveUserListsSuccess', { data, headers }))
+ .catch(() => dispatch('receiveUserListsError'));
+};
+
+export const requestUserLists = ({ commit }) => commit(types.REQUEST_USER_LISTS);
+export const receiveUserListsSuccess = ({ commit }, response) =>
+ commit(types.RECEIVE_USER_LISTS_SUCCESS, response);
+export const receiveUserListsError = ({ commit }) => commit(types.RECEIVE_USER_LISTS_ERROR);
+
+export const toggleFeatureFlag = ({ dispatch }, flag) => {
+ dispatch('updateFeatureFlag', flag);
+
+ axios
+ .put(flag.update_path, {
+ operations_feature_flag: flag,
+ })
+ .then(response => dispatch('receiveUpdateFeatureFlagSuccess', response.data))
+ .catch(() => dispatch('receiveUpdateFeatureFlagError', flag.id));
+};
+
+export const updateFeatureFlag = ({ commit }, flag) => commit(types.UPDATE_FEATURE_FLAG, flag);
+
+export const receiveUpdateFeatureFlagSuccess = ({ commit }, data) =>
+ commit(types.RECEIVE_UPDATE_FEATURE_FLAG_SUCCESS, data);
+export const receiveUpdateFeatureFlagError = ({ commit }, id) =>
+ commit(types.RECEIVE_UPDATE_FEATURE_FLAG_ERROR, id);
+
+export const deleteUserList = ({ state, dispatch }, list) => {
+ dispatch('requestDeleteUserList', list);
+
+ return Api.deleteFeatureFlagUserList(state.projectId, list.iid)
+ .then(() => dispatch('fetchUserLists'))
+ .catch(error =>
+ dispatch('receiveDeleteUserListError', {
+ list,
+ error: error?.response?.data ?? error,
+ }),
+ );
+};
+
+export const requestDeleteUserList = ({ commit }, list) =>
+ commit(types.REQUEST_DELETE_USER_LIST, list);
+
+export const receiveDeleteUserListError = ({ commit }, { error, list }) => {
+ commit(types.RECEIVE_DELETE_USER_LIST_ERROR, { error, list });
+};
+
+export const rotateInstanceId = ({ state, dispatch }) => {
+ dispatch('requestRotateInstanceId');
+
+ axios
+ .post(state.rotateEndpoint)
+ .then(({ data = {}, headers }) => dispatch('receiveRotateInstanceIdSuccess', { data, headers }))
+ .catch(() => dispatch('receiveRotateInstanceIdError'));
+};
+
+export const requestRotateInstanceId = ({ commit }) => commit(types.REQUEST_ROTATE_INSTANCE_ID);
+export const receiveRotateInstanceIdSuccess = ({ commit }, response) =>
+ commit(types.RECEIVE_ROTATE_INSTANCE_ID_SUCCESS, response);
+export const receiveRotateInstanceIdError = ({ commit }) =>
+ commit(types.RECEIVE_ROTATE_INSTANCE_ID_ERROR);
+
+export const clearAlert = ({ commit }, index) => {
+ commit(types.RECEIVE_CLEAR_ALERT, index);
+};
diff --git a/app/assets/javascripts/feature_flags/store/index/index.js b/app/assets/javascripts/feature_flags/store/index/index.js
new file mode 100644
index 00000000000..f737e0517fc
--- /dev/null
+++ b/app/assets/javascripts/feature_flags/store/index/index.js
@@ -0,0 +1,11 @@
+import Vuex from 'vuex';
+import state from './state';
+import * as actions from './actions';
+import mutations from './mutations';
+
+export default data =>
+ new Vuex.Store({
+ actions,
+ mutations,
+ state: state(data),
+ });
diff --git a/app/assets/javascripts/feature_flags/store/index/mutation_types.js b/app/assets/javascripts/feature_flags/store/index/mutation_types.js
new file mode 100644
index 00000000000..189c763782e
--- /dev/null
+++ b/app/assets/javascripts/feature_flags/store/index/mutation_types.js
@@ -0,0 +1,22 @@
+export const SET_FEATURE_FLAGS_OPTIONS = 'SET_FEATURE_FLAGS_OPTIONS';
+
+export const REQUEST_FEATURE_FLAGS = 'REQUEST_FEATURE_FLAGS';
+export const RECEIVE_FEATURE_FLAGS_SUCCESS = 'RECEIVE_FEATURE_FLAGS_SUCCESS';
+export const RECEIVE_FEATURE_FLAGS_ERROR = 'RECEIVE_FEATURE_FLAGS_ERROR';
+
+export const REQUEST_USER_LISTS = 'REQUEST_USER_LISTS';
+export const RECEIVE_USER_LISTS_SUCCESS = 'RECEIVE_USER_LISTS_SUCCESS';
+export const RECEIVE_USER_LISTS_ERROR = 'RECEIVE_USER_LISTS_ERROR';
+
+export const REQUEST_DELETE_USER_LIST = 'REQUEST_DELETE_USER_LIST';
+export const RECEIVE_DELETE_USER_LIST_ERROR = 'RECEIVE_DELETE_USER_LIST_ERROR';
+
+export const UPDATE_FEATURE_FLAG = 'UPDATE_FEATURE_FLAG';
+export const RECEIVE_UPDATE_FEATURE_FLAG_SUCCESS = 'RECEIVE_UPDATE_FEATURE_FLAG_SUCCESS';
+export const RECEIVE_UPDATE_FEATURE_FLAG_ERROR = 'RECEIVE_UPDATE_FEATURE_FLAG_ERROR';
+
+export const REQUEST_ROTATE_INSTANCE_ID = 'REQUEST_ROTATE_INSTANCE_ID';
+export const RECEIVE_ROTATE_INSTANCE_ID_SUCCESS = 'RECEIVE_ROTATE_INSTANCE_ID_SUCCESS';
+export const RECEIVE_ROTATE_INSTANCE_ID_ERROR = 'RECEIVE_ROTATE_INSTANCE_ID_ERROR';
+
+export const RECEIVE_CLEAR_ALERT = 'RECEIVE_CLEAR_ALERT';
diff --git a/app/assets/javascripts/feature_flags/store/index/mutations.js b/app/assets/javascripts/feature_flags/store/index/mutations.js
new file mode 100644
index 00000000000..bdc23e66214
--- /dev/null
+++ b/app/assets/javascripts/feature_flags/store/index/mutations.js
@@ -0,0 +1,113 @@
+import Vue from 'vue';
+import * as types from './mutation_types';
+import { parseIntPagination, normalizeHeaders } from '~/lib/utils/common_utils';
+import { FEATURE_FLAG_SCOPE, USER_LIST_SCOPE } from '../../constants';
+import { mapToScopesViewModel } from '../helpers';
+
+const mapFlag = flag => ({ ...flag, scopes: mapToScopesViewModel(flag.scopes || []) });
+
+const updateFlag = (state, flag) => {
+ const index = state[FEATURE_FLAG_SCOPE].findIndex(({ id }) => id === flag.id);
+ Vue.set(state[FEATURE_FLAG_SCOPE], index, flag);
+};
+
+const createPaginationInfo = (state, headers) => {
+ let paginationInfo;
+ if (Object.keys(headers).length) {
+ const normalizedHeaders = normalizeHeaders(headers);
+ paginationInfo = parseIntPagination(normalizedHeaders);
+ } else {
+ paginationInfo = headers;
+ }
+ return paginationInfo;
+};
+
+export default {
+ [types.SET_FEATURE_FLAGS_OPTIONS](state, options = {}) {
+ state.options = options;
+ },
+ [types.REQUEST_FEATURE_FLAGS](state) {
+ state.isLoading = true;
+ },
+ [types.RECEIVE_FEATURE_FLAGS_SUCCESS](state, response) {
+ state.isLoading = false;
+ state.hasError = false;
+ state[FEATURE_FLAG_SCOPE] = (response.data.feature_flags || []).map(mapFlag);
+
+ const paginationInfo = createPaginationInfo(state, response.headers);
+ state.count = {
+ ...state.count,
+ [FEATURE_FLAG_SCOPE]: paginationInfo?.total ?? state[FEATURE_FLAG_SCOPE].length,
+ };
+ state.pageInfo = {
+ ...state.pageInfo,
+ [FEATURE_FLAG_SCOPE]: paginationInfo,
+ };
+ },
+ [types.RECEIVE_FEATURE_FLAGS_ERROR](state) {
+ state.isLoading = false;
+ state.hasError = true;
+ },
+ [types.REQUEST_USER_LISTS](state) {
+ state.isLoading = true;
+ },
+ [types.RECEIVE_USER_LISTS_SUCCESS](state, response) {
+ state.isLoading = false;
+ state.hasError = false;
+ state[USER_LIST_SCOPE] = response.data || [];
+
+ const paginationInfo = createPaginationInfo(state, response.headers);
+ state.count = {
+ ...state.count,
+ [USER_LIST_SCOPE]: paginationInfo?.total ?? state[USER_LIST_SCOPE].length,
+ };
+ state.pageInfo = {
+ ...state.pageInfo,
+ [USER_LIST_SCOPE]: paginationInfo,
+ };
+ },
+ [types.RECEIVE_USER_LISTS_ERROR](state) {
+ state.isLoading = false;
+ state.hasError = true;
+ },
+ [types.REQUEST_ROTATE_INSTANCE_ID](state) {
+ state.isRotating = true;
+ state.hasRotateError = false;
+ },
+ [types.RECEIVE_ROTATE_INSTANCE_ID_SUCCESS](
+ state,
+ {
+ data: { token },
+ },
+ ) {
+ state.isRotating = false;
+ state.instanceId = token;
+ state.hasRotateError = false;
+ },
+ [types.RECEIVE_ROTATE_INSTANCE_ID_ERROR](state) {
+ state.isRotating = false;
+ state.hasRotateError = true;
+ },
+ [types.UPDATE_FEATURE_FLAG](state, flag) {
+ updateFlag(state, flag);
+ },
+ [types.RECEIVE_UPDATE_FEATURE_FLAG_SUCCESS](state, data) {
+ updateFlag(state, mapFlag(data));
+ },
+ [types.RECEIVE_UPDATE_FEATURE_FLAG_ERROR](state, i) {
+ const flag = state[FEATURE_FLAG_SCOPE].find(({ id }) => i === id);
+ updateFlag(state, { ...flag, active: !flag.active });
+ },
+ [types.REQUEST_DELETE_USER_LIST](state, list) {
+ state.userLists = state.userLists.filter(l => l !== list);
+ },
+ [types.RECEIVE_DELETE_USER_LIST_ERROR](state, { error, list }) {
+ state.isLoading = false;
+ state.hasError = false;
+ state.alerts = [].concat(error.message);
+ state.userLists = state.userLists.concat(list).sort((l1, l2) => l1.iid - l2.iid);
+ },
+ [types.RECEIVE_CLEAR_ALERT](state, index) {
+ state.alerts.splice(index, 1);
+ },
+};
diff --git a/app/assets/javascripts/feature_flags/store/index/state.js b/app/assets/javascripts/feature_flags/store/index/state.js
new file mode 100644
index 00000000000..f8439b02639
--- /dev/null
+++ b/app/assets/javascripts/feature_flags/store/index/state.js
@@ -0,0 +1,18 @@
+import { FEATURE_FLAG_SCOPE, USER_LIST_SCOPE } from '../../constants';
+
+export default ({ endpoint, projectId, unleashApiInstanceId, rotateInstanceIdPath }) => ({
+ [FEATURE_FLAG_SCOPE]: [],
+ [USER_LIST_SCOPE]: [],
+ alerts: [],
+ count: {},
+ pageInfo: { [FEATURE_FLAG_SCOPE]: {}, [USER_LIST_SCOPE]: {} },
+ isLoading: true,
+ hasError: false,
+ endpoint,
+ rotateEndpoint: rotateInstanceIdPath,
+ instanceId: unleashApiInstanceId,
+ isRotating: false,
+ hasRotateError: false,
+ options: {},
+ projectId,
+});
diff --git a/app/assets/javascripts/feature_flags/store/new/actions.js b/app/assets/javascripts/feature_flags/store/new/actions.js
new file mode 100644
index 00000000000..e21c128cd39
--- /dev/null
+++ b/app/assets/javascripts/feature_flags/store/new/actions.js
@@ -0,0 +1,37 @@
+import * as types from './mutation_types';
+import axios from '~/lib/utils/axios_utils';
+import { visitUrl } from '~/lib/utils/url_utility';
+import { NEW_VERSION_FLAG } from '../../constants';
+import { mapFromScopesViewModel, mapStrategiesToRails } from '../helpers';
+
+/**
+ * Handles the creation of a new feature flag.
+ *
+ * Will dispatch `requestCreateFeatureFlag`
+ * Serializes the params and makes a post request
+ * Dispatches an action acording to the request status.
+ *
+ * @param {Object} params
+ */
+export const createFeatureFlag = ({ state, dispatch }, params) => {
+ dispatch('requestCreateFeatureFlag');
+
+ return axios
+ .post(
+ state.endpoint,
+ params.version === NEW_VERSION_FLAG
+ ? mapStrategiesToRails(params)
+ : mapFromScopesViewModel(params),
+ )
+ .then(() => {
+ dispatch('receiveCreateFeatureFlagSuccess');
+ visitUrl(state.path);
+ })
+ .catch(error => dispatch('receiveCreateFeatureFlagError', error.response.data));
+};
+
+export const requestCreateFeatureFlag = ({ commit }) => commit(types.REQUEST_CREATE_FEATURE_FLAG);
+export const receiveCreateFeatureFlagSuccess = ({ commit }) =>
+ commit(types.RECEIVE_CREATE_FEATURE_FLAG_SUCCESS);
+export const receiveCreateFeatureFlagError = ({ commit }, error) =>
+ commit(types.RECEIVE_CREATE_FEATURE_FLAG_ERROR, error);
diff --git a/app/assets/javascripts/feature_flags/store/new/index.js b/app/assets/javascripts/feature_flags/store/new/index.js
new file mode 100644
index 00000000000..f737e0517fc
--- /dev/null
+++ b/app/assets/javascripts/feature_flags/store/new/index.js
@@ -0,0 +1,11 @@
+import Vuex from 'vuex';
+import state from './state';
+import * as actions from './actions';
+import mutations from './mutations';
+
+export default data =>
+ new Vuex.Store({
+ actions,
+ mutations,
+ state: state(data),
+ });
diff --git a/app/assets/javascripts/feature_flags/store/new/mutation_types.js b/app/assets/javascripts/feature_flags/store/new/mutation_types.js
new file mode 100644
index 00000000000..71cc57c8d2e
--- /dev/null
+++ b/app/assets/javascripts/feature_flags/store/new/mutation_types.js
@@ -0,0 +1,3 @@
+export const REQUEST_CREATE_FEATURE_FLAG = 'REQUEST_CREATE_FEATURE_FLAG';
+export const RECEIVE_CREATE_FEATURE_FLAG_SUCCESS = 'RECEIVE_CREATE_FEATURE_FLAG_SUCCESS';
+export const RECEIVE_CREATE_FEATURE_FLAG_ERROR = 'RECEIVE_CREATE_FEATURE_FLAG_ERROR';
diff --git a/app/assets/javascripts/feature_flags/store/new/mutations.js b/app/assets/javascripts/feature_flags/store/new/mutations.js
new file mode 100644
index 00000000000..eeefc8413e8
--- /dev/null
+++ b/app/assets/javascripts/feature_flags/store/new/mutations.js
@@ -0,0 +1,15 @@
+import * as types from './mutation_types';
+
+export default {
+ [types.REQUEST_CREATE_FEATURE_FLAG](state) {
+ state.isSendingRequest = true;
+ state.error = [];
+ },
+ [types.RECEIVE_CREATE_FEATURE_FLAG_SUCCESS](state) {
+ state.isSendingRequest = false;
+ },
+ [types.RECEIVE_CREATE_FEATURE_FLAG_ERROR](state, error) {
+ state.isSendingRequest = false;
+ state.error = error.message || [];
+ },
+};
diff --git a/app/assets/javascripts/feature_flags/store/new/state.js b/app/assets/javascripts/feature_flags/store/new/state.js
new file mode 100644
index 00000000000..56940925aa0
--- /dev/null
+++ b/app/assets/javascripts/feature_flags/store/new/state.js
@@ -0,0 +1,6 @@
+export default ({ endpoint, path }) => ({
+ endpoint,
+ path,
+ isSendingRequest: false,
+ error: [],
+});
diff --git a/app/assets/javascripts/feature_flags/utils.js b/app/assets/javascripts/feature_flags/utils.js
new file mode 100644
index 00000000000..24c570657e6
--- /dev/null
+++ b/app/assets/javascripts/feature_flags/utils.js
@@ -0,0 +1,66 @@
+import { s__, n__, sprintf } from '~/locale';
+import {
+ ALL_ENVIRONMENTS_NAME,
+ ROLLOUT_STRATEGY_ALL_USERS,
+ ROLLOUT_STRATEGY_FLEXIBLE_ROLLOUT,
+ ROLLOUT_STRATEGY_PERCENT_ROLLOUT,
+ ROLLOUT_STRATEGY_USER_ID,
+ ROLLOUT_STRATEGY_GITLAB_USER_LIST,
+} from './constants';
+
+const badgeTextByType = {
+ [ROLLOUT_STRATEGY_ALL_USERS]: {
+ name: s__('FeatureFlags|All Users'),
+ parameters: null,
+ },
+ [ROLLOUT_STRATEGY_FLEXIBLE_ROLLOUT]: {
+ name: s__('FeatureFlags|Percent rollout'),
+ parameters: ({ parameters: { rollout, stickiness } }) => {
+ switch (stickiness) {
+ case 'USERID':
+ return sprintf(s__('FeatureFlags|%{percent} by user ID'), { percent: `${rollout}%` });
+ case 'SESSIONID':
+ return sprintf(s__('FeatureFlags|%{percent} by session ID'), { percent: `${rollout}%` });
+ case 'RANDOM':
+ return sprintf(s__('FeatureFlags|%{percent} randomly'), { percent: `${rollout}%` });
+ default:
+ return sprintf(s__('FeatureFlags|%{percent} by available ID'), {
+ percent: `${rollout}%`,
+ });
+ }
+ },
+ },
+ [ROLLOUT_STRATEGY_PERCENT_ROLLOUT]: {
+ name: s__('FeatureFlags|Percent of users'),
+ parameters: ({ parameters: { percentage } }) => `${percentage}%`,
+ },
+ [ROLLOUT_STRATEGY_USER_ID]: {
+ name: s__('FeatureFlags|User IDs'),
+ parameters: ({ parameters: { userIds } }) =>
+ sprintf(n__('FeatureFlags|%d user', 'FeatureFlags|%d users', userIds.split(',').length)),
+ },
+ [ROLLOUT_STRATEGY_GITLAB_USER_LIST]: {
+ name: s__('FeatureFlags|User List'),
+ parameters: ({ user_list: { name } }) => name,
+ },
+};
+
+const scopeName = ({ environment_scope: scope }) =>
+ scope === ALL_ENVIRONMENTS_NAME ? s__('FeatureFlags|All Environments') : scope;
+
+export const labelForStrategy = strategy => {
+ const { name, parameters } = badgeTextByType[strategy.name];
+
+ if (parameters) {
+ return sprintf('%{name} - %{parameters}: %{scopes}', {
+ name,
+ parameters: parameters(strategy),
+ scopes: strategy.scopes.map(scopeName).join(', '),
+ });
+ }
+
+ return sprintf('%{name}: %{scopes}', {
+ name,
+ scopes: strategy.scopes.map(scopeName).join(', '),
+ });
+};
diff --git a/app/assets/javascripts/filtered_search/add_extra_tokens_for_merge_requests.js b/app/assets/javascripts/filtered_search/add_extra_tokens_for_merge_requests.js
index 80f78c154ee..51077296e20 100644
--- a/app/assets/javascripts/filtered_search/add_extra_tokens_for_merge_requests.js
+++ b/app/assets/javascripts/filtered_search/add_extra_tokens_for_merge_requests.js
@@ -1,6 +1,6 @@
import { __ } from '~/locale';
-export default IssuableTokenKeys => {
+export default (IssuableTokenKeys, disableTargetBranchFilter = false) => {
const draftToken = {
token: {
formattedKey: __('Draft'),
@@ -51,16 +51,101 @@ export default IssuableTokenKeys => {
IssuableTokenKeys.tokenKeysWithAlternative.push(draftToken.token);
IssuableTokenKeys.conditions.push(...draftToken.conditions);
- const targetBranchToken = {
- formattedKey: __('Target-Branch'),
- key: 'target-branch',
- type: 'string',
- param: '',
- symbol: '',
- icon: 'arrow-right',
- tag: 'branch',
+ if (!disableTargetBranchFilter) {
+ const targetBranchToken = {
+ formattedKey: __('Target-Branch'),
+ key: 'target-branch',
+ type: 'string',
+ param: '',
+ symbol: '',
+ icon: 'arrow-right',
+ tag: 'branch',
+ };
+
+ IssuableTokenKeys.tokenKeys.push(targetBranchToken);
+ IssuableTokenKeys.tokenKeysWithAlternative.push(targetBranchToken);
+ }
+
+ const approvedBy = {
+ token: {
+ formattedKey: __('Approved-By'),
+ key: 'approved-by',
+ type: 'array',
+ param: 'usernames[]',
+ symbol: '@',
+ icon: 'approval',
+ tag: '@approved-by',
+ },
+ condition: [
+ {
+ url: 'approved_by_usernames[]=None',
+ tokenKey: 'approved-by',
+ value: __('None'),
+ operator: '=',
+ },
+ {
+ url: 'not[approved_by_usernames][]=None',
+ tokenKey: 'approved-by',
+ value: __('None'),
+ operator: '!=',
+ },
+ {
+ url: 'approved_by_usernames[]=Any',
+ tokenKey: 'approved-by',
+ value: __('Any'),
+ operator: '=',
+ },
+ {
+ url: 'not[approved_by_usernames][]=Any',
+ tokenKey: 'approved-by',
+ value: __('Any'),
+ operator: '!=',
+ },
+ ],
};
- IssuableTokenKeys.tokenKeys.push(targetBranchToken);
- IssuableTokenKeys.tokenKeysWithAlternative.push(targetBranchToken);
+ const tokenPosition = 2;
+ IssuableTokenKeys.tokenKeys.splice(tokenPosition, 0, ...[approvedBy.token]);
+ IssuableTokenKeys.tokenKeysWithAlternative.splice(tokenPosition, 0, ...[approvedBy.token]);
+ IssuableTokenKeys.conditions.push(...approvedBy.condition);
+
+ if (gon?.features?.deploymentFilters) {
+ const environmentToken = {
+ formattedKey: __('Environment'),
+ key: 'environment',
+ type: 'string',
+ param: '',
+ symbol: '',
+ icon: 'cloud-gear',
+ tag: 'environment',
+ };
+
+ const deployedBeforeToken = {
+ formattedKey: __('Deployed-before'),
+ key: 'deployed-before',
+ type: 'string',
+ param: '',
+ symbol: '',
+ icon: 'clock',
+ tag: 'deployed_before',
+ };
+
+ const deployedAfterToken = {
+ formattedKey: __('Deployed-after'),
+ key: 'deployed-after',
+ type: 'string',
+ param: '',
+ symbol: '',
+ icon: 'clock',
+ tag: 'deployed_after',
+ };
+
+ IssuableTokenKeys.tokenKeys.push(environmentToken, deployedBeforeToken, deployedAfterToken);
+
+ IssuableTokenKeys.tokenKeysWithAlternative.push(
+ environmentToken,
+ deployedBeforeToken,
+ deployedAfterToken,
+ );
+ }
};
diff --git a/app/assets/javascripts/filtered_search/available_dropdown_mappings.js b/app/assets/javascripts/filtered_search/available_dropdown_mappings.js
index 49bd3cda127..d7645f96406 100644
--- a/app/assets/javascripts/filtered_search/available_dropdown_mappings.js
+++ b/app/assets/javascripts/filtered_search/available_dropdown_mappings.js
@@ -15,6 +15,7 @@ export default class AvailableDropdownMappings {
labelsEndpoint,
milestonesEndpoint,
releasesEndpoint,
+ environmentsEndpoint,
groupsOnly,
includeAncestorGroups,
includeDescendantGroups,
@@ -24,6 +25,7 @@ export default class AvailableDropdownMappings {
this.labelsEndpoint = labelsEndpoint;
this.milestonesEndpoint = milestonesEndpoint;
this.releasesEndpoint = releasesEndpoint;
+ this.environmentsEndpoint = environmentsEndpoint;
this.groupsOnly = groupsOnly;
this.includeAncestorGroups = includeAncestorGroups;
this.includeDescendantGroups = includeDescendantGroups;
@@ -69,6 +71,11 @@ export default class AvailableDropdownMappings {
gl: DropdownUser,
element: this.container.querySelector('#js-dropdown-assignee'),
},
+ 'approved-by': {
+ reference: null,
+ gl: DropdownUser,
+ element: this.container.querySelector('#js-dropdown-approved-by'),
+ },
milestone: {
reference: null,
gl: DropdownNonUser,
@@ -144,6 +151,16 @@ export default class AvailableDropdownMappings {
},
element: this.container.querySelector('#js-dropdown-target-branch'),
},
+ environment: {
+ reference: null,
+ gl: DropdownNonUser,
+ extraArguments: {
+ endpoint: this.getEnvironmentsEndpoint(),
+ symbol: '',
+ preprocessing: data => data.map(env => ({ title: env })),
+ },
+ element: this.container.querySelector('#js-dropdown-environment'),
+ },
};
}
@@ -189,6 +206,10 @@ export default class AvailableDropdownMappings {
return mergeUrlParams(params, endpoint);
}
+ getEnvironmentsEndpoint() {
+ return `${this.environmentsEndpoint}.json`;
+ }
+
getGroupId() {
return this.filteredSearchInput.getAttribute('data-group-id') || '';
}
diff --git a/app/assets/javascripts/filtered_search/constants.js b/app/assets/javascripts/filtered_search/constants.js
index 0b9fe969da1..6cd6f9c9906 100644
--- a/app/assets/javascripts/filtered_search/constants.js
+++ b/app/assets/javascripts/filtered_search/constants.js
@@ -1,4 +1,4 @@
-export const USER_TOKEN_TYPES = ['author', 'assignee'];
+export const USER_TOKEN_TYPES = ['author', 'assignee', 'approved-by'];
export const DROPDOWN_TYPE = {
hint: 'hint',
diff --git a/app/assets/javascripts/filtered_search/filtered_search_dropdown_manager.js b/app/assets/javascripts/filtered_search/filtered_search_dropdown_manager.js
index 161a65c511d..762383f5a1d 100644
--- a/app/assets/javascripts/filtered_search/filtered_search_dropdown_manager.js
+++ b/app/assets/javascripts/filtered_search/filtered_search_dropdown_manager.js
@@ -13,6 +13,7 @@ export default class FilteredSearchDropdownManager {
labelsEndpoint = '',
milestonesEndpoint = '',
releasesEndpoint = '',
+ environmentsEndpoint = '',
epicsEndpoint = '',
tokenizer,
page,
@@ -29,6 +30,7 @@ export default class FilteredSearchDropdownManager {
this.milestonesEndpoint = removeTrailingSlash(milestonesEndpoint);
this.releasesEndpoint = removeTrailingSlash(releasesEndpoint);
this.epicsEndpoint = removeTrailingSlash(epicsEndpoint);
+ this.environmentsEndpoint = removeTrailingSlash(environmentsEndpoint);
this.tokenizer = tokenizer;
this.filteredSearchTokenKeys = filteredSearchTokenKeys || FilteredSearchTokenKeys;
this.filteredSearchInput = this.container.querySelector('.filtered-search');
diff --git a/app/assets/javascripts/filtered_search/filtered_search_manager.js b/app/assets/javascripts/filtered_search/filtered_search_manager.js
index 3e4a9880134..261532f8867 100644
--- a/app/assets/javascripts/filtered_search/filtered_search_manager.js
+++ b/app/assets/javascripts/filtered_search/filtered_search_manager.js
@@ -110,6 +110,7 @@ export default class FilteredSearchManager {
labelsEndpoint = '',
milestonesEndpoint = '',
releasesEndpoint = '',
+ environmentsEndpoint = '',
epicsEndpoint = '',
} = this.filteredSearchInput.dataset;
@@ -118,6 +119,7 @@ export default class FilteredSearchManager {
labelsEndpoint,
milestonesEndpoint,
releasesEndpoint,
+ environmentsEndpoint,
epicsEndpoint,
tokenizer: this.tokenizer,
page: this.page,
diff --git a/app/assets/javascripts/flash.js b/app/assets/javascripts/flash.js
index f2dd8d5ace5..1d5f09a265b 100644
--- a/app/assets/javascripts/flash.js
+++ b/app/assets/javascripts/flash.js
@@ -1,5 +1,5 @@
-import * as Sentry from '@sentry/browser';
import { escape } from 'lodash';
+import * as Sentry from '~/sentry/wrapper';
import { spriteIcon } from './lib/utils/common_utils';
const FLASH_TYPES = {
diff --git a/app/assets/javascripts/frequent_items/index.js b/app/assets/javascripts/frequent_items/index.js
index 1998bf4358a..5b03e1d19db 100644
--- a/app/assets/javascripts/frequent_items/index.js
+++ b/app/assets/javascripts/frequent_items/index.js
@@ -16,53 +16,63 @@ const frequentItemDropdowns = [
},
];
+const initFrequentItemList = (namespace, key) => {
+ const el = document.getElementById(`js-${namespace}-dropdown`);
+
+ // Don't do anything if element doesn't exist (No groups dropdown)
+ // This is for when the user accesses GitLab without logging in
+ if (!el) {
+ return;
+ }
+
+ import('./components/app.vue')
+ .then(({ default: FrequentItems }) => {
+ // eslint-disable-next-line no-new
+ new Vue({
+ el,
+ data() {
+ const { dataset } = this.$options.el;
+ const item = {
+ id: Number(dataset[`${key}Id`]),
+ name: dataset[`${key}Name`],
+ namespace: dataset[`${key}Namespace`],
+ webUrl: dataset[`${key}WebUrl`],
+ avatarUrl: dataset[`${key}AvatarUrl`] || null,
+ lastAccessedOn: Date.now(),
+ };
+
+ return {
+ currentUserName: dataset.userName,
+ currentItem: item,
+ };
+ },
+ render(createElement) {
+ return createElement(FrequentItems, {
+ props: {
+ namespace,
+ currentUserName: this.currentUserName,
+ currentItem: this.currentItem,
+ },
+ });
+ },
+ });
+ })
+ .catch(() => {});
+};
+
export default function initFrequentItemDropdowns() {
frequentItemDropdowns.forEach(dropdown => {
const { namespace, key } = dropdown;
- const el = document.getElementById(`js-${namespace}-dropdown`);
const navEl = document.getElementById(`nav-${namespace}-dropdown`);
// Don't do anything if element doesn't exist (No groups dropdown)
// This is for when the user accesses GitLab without logging in
- if (!el || !navEl) {
+ if (!navEl) {
return;
}
- import('./components/app.vue')
- .then(({ default: FrequentItems }) => {
- // eslint-disable-next-line no-new
- new Vue({
- el,
- data() {
- const { dataset } = this.$options.el;
- const item = {
- id: Number(dataset[`${key}Id`]),
- name: dataset[`${key}Name`],
- namespace: dataset[`${key}Namespace`],
- webUrl: dataset[`${key}WebUrl`],
- avatarUrl: dataset[`${key}AvatarUrl`] || null,
- lastAccessedOn: Date.now(),
- };
-
- return {
- currentUserName: dataset.userName,
- currentItem: item,
- };
- },
- render(createElement) {
- return createElement(FrequentItems, {
- props: {
- namespace,
- currentUserName: this.currentUserName,
- currentItem: this.currentItem,
- },
- });
- },
- });
- })
- .catch(() => {});
-
$(navEl).on('shown.bs.dropdown', () => {
+ initFrequentItemList(namespace, key);
eventHub.$emit(`${namespace}-dropdownOpen`);
});
});
diff --git a/app/assets/javascripts/frequent_items/utils.js b/app/assets/javascripts/frequent_items/utils.js
index 112e8eaaf17..954d426c86c 100644
--- a/app/assets/javascripts/frequent_items/utils.js
+++ b/app/assets/javascripts/frequent_items/utils.js
@@ -1,6 +1,6 @@
import { take } from 'lodash';
import { GlBreakpointInstance as bp } from '@gitlab/ui/dist/utils';
-import { sanitize } from 'dompurify';
+import { sanitize } from '~/lib/dompurify';
import { FREQUENT_ITEMS, HOUR_IN_MS } from './constants';
export const isMobile = () => ['md', 'sm', 'xs'].includes(bp.getBreakpointSize());
diff --git a/app/assets/javascripts/gfm_auto_complete.js b/app/assets/javascripts/gfm_auto_complete.js
index 409733c73b9..62948f74aaa 100644
--- a/app/assets/javascripts/gfm_auto_complete.js
+++ b/app/assets/javascripts/gfm_auto_complete.js
@@ -52,7 +52,6 @@ export const defaultAutocompleteConfig = {
milestones: true,
labels: true,
snippets: true,
- vulnerabilities: true,
};
class GfmAutoComplete {
@@ -179,6 +178,9 @@ class GfmAutoComplete {
}
setupEmoji($input) {
+ const self = this;
+ const { filter, ...defaults } = this.getDefaultCallbacks();
+
// Emoji
$input.atwho({
at: ':',
@@ -189,18 +191,47 @@ class GfmAutoComplete {
}
return tmpl;
},
- // eslint-disable-next-line no-template-curly-in-string
- insertTpl: ':${name}:',
+ insertTpl: GfmAutoComplete.Emoji.insertTemplateFunction,
skipSpecialCharacterTest: true,
data: GfmAutoComplete.defaultLoadingData,
callbacks: {
- ...this.getDefaultCallbacks(),
+ ...defaults,
matcher(flag, subtext) {
const regexp = new RegExp(`(?:[^${glRegexp.unicodeLetters}0-9:]|\n|^):([^:]*)$`, 'gi');
const match = regexp.exec(subtext);
return match && match.length ? match[1] : null;
},
+ filter(query, items, searchKey) {
+ const filtered = filter.call(this, query, items, searchKey);
+ if (query.length === 0 || GfmAutoComplete.isLoading(items)) {
+ return filtered;
+ }
+
+ // map from value to "<value> is <field> of <emoji>", arranged by emoji
+ const emojis = {};
+ filtered.forEach(({ name: value }) => {
+ self.emojiLookup[value].forEach(({ emoji: { name }, kind }) => {
+ let entry = emojis[name];
+ if (!entry) {
+ entry = {};
+ emojis[name] = entry;
+ }
+ if (!(kind in entry) || value.localeCompare(entry[kind]) < 0) {
+ entry[kind] = value;
+ }
+ });
+ });
+
+ // collate results to list, prefering name > unicode > alias > description
+ const results = [];
+ Object.values(emojis).forEach(({ name, unicode, alias, description }) => {
+ results.push(name || unicode || alias || description);
+ });
+
+ // return to the form atwho wants
+ return results.map(name => ({ name }));
+ },
},
});
}
@@ -593,12 +624,7 @@ class GfmAutoComplete {
if (this.cachedData[at]) {
this.loadData($input, at, this.cachedData[at]);
} else if (GfmAutoComplete.atTypeMap[at] === 'emojis') {
- Emoji.initEmojiMap()
- .then(() => {
- this.loadData($input, at, Emoji.getValidEmojiNames());
- GfmAutoComplete.glEmojiTag = Emoji.glEmojiTag;
- })
- .catch(() => {});
+ this.loadEmojiData($input, at).catch(() => {});
} else if (dataSource) {
AjaxCache.retrieve(dataSource, true)
.then(data => {
@@ -621,6 +647,39 @@ class GfmAutoComplete {
return $input.trigger('keyup');
}
+ async loadEmojiData($input, at) {
+ await Emoji.initEmojiMap();
+
+ // All the emoji
+ const emojis = Emoji.getAllEmoji();
+
+ // Add all of the fields to atwho's database
+ this.loadData($input, at, [
+ ...Object.keys(emojis), // Names
+ ...Object.values(emojis).flatMap(({ aliases }) => aliases), // Aliases
+ ...Object.values(emojis).map(({ e }) => e), // Unicode values
+ ...Object.values(emojis).map(({ d }) => d), // Descriptions
+ ]);
+
+ // Construct a lookup that can correlate a value to "<value> is the <field> of <emoji>"
+ const lookup = {};
+ const add = (key, kind, emoji) => {
+ if (!(key in lookup)) {
+ lookup[key] = [];
+ }
+ lookup[key].push({ kind, emoji });
+ };
+ Object.values(emojis).forEach(emoji => {
+ add(emoji.name, 'name', emoji);
+ add(emoji.d, 'description', emoji);
+ add(emoji.e, 'unicode', emoji);
+ emoji.aliases.forEach(a => add(a, 'alias', emoji));
+ });
+ this.emojiLookup = lookup;
+
+ GfmAutoComplete.glEmojiTag = Emoji.glEmojiTag;
+ }
+
clearCache() {
this.cachedData = {};
}
@@ -648,8 +707,7 @@ class GfmAutoComplete {
// https://github.com/ichord/At.js
const atSymbolsWithBar = Object.keys(controllers)
.join('|')
- .replace(/[$]/, '\\$&')
- .replace(/[+]/, '\\+');
+ .replace(/[$]/, '\\$&');
const atSymbolsWithoutBar = Object.keys(controllers).join('');
const targetSubtext = subtext.split(GfmAutoComplete.regexSubtext).pop();
const resultantFlag = flag.replace(/[-[\]/{}()*+?.\\^$|]/g, '\\$&');
@@ -680,19 +738,39 @@ GfmAutoComplete.atTypeMap = {
'~': 'labels',
'%': 'milestones',
'/': 'commands',
- '+': 'vulnerabilities',
$: 'snippets',
};
+function findEmoji(name) {
+ return Emoji.searchEmoji(name, { match: 'contains', raw: true }).sort((a, b) => {
+ if (a.index !== b.index) {
+ return a.index - b.index;
+ }
+ return a.field.localeCompare(b.field);
+ });
+}
+
// Emoji
GfmAutoComplete.glEmojiTag = null;
GfmAutoComplete.Emoji = {
+ insertTemplateFunction(value) {
+ const results = findEmoji(value.name);
+ if (results.length) {
+ return `:${results[0].emoji.name}:`;
+ }
+ return `:${value.name}:`;
+ },
templateFunction(name) {
// glEmojiTag helper is loaded on-demand in fetchData()
- if (GfmAutoComplete.glEmojiTag) {
+ if (!GfmAutoComplete.glEmojiTag) return `<li>${name}</li>`;
+
+ const results = findEmoji(name);
+ if (!results.length) {
return `<li>${name} ${GfmAutoComplete.glEmojiTag(name)}</li>`;
}
- return `<li>${name}</li>`;
+
+ const { field, emoji } = results[0];
+ return `<li>${field} ${GfmAutoComplete.glEmojiTag(emoji.name)}</li>`;
},
};
// Team Members
diff --git a/app/assets/javascripts/gl_form.js b/app/assets/javascripts/gl_form.js
index 0a1e5490237..6958cf4c173 100644
--- a/app/assets/javascripts/gl_form.js
+++ b/app/assets/javascripts/gl_form.js
@@ -6,7 +6,14 @@ import { addMarkdownListeners, removeMarkdownListeners } from './lib/utils/text_
import { disableButtonIfEmptyField } from '~/lib/utils/common_utils';
export default class GLForm {
- constructor(form, enableGFM = {}) {
+ /**
+ * Create a GLForm
+ *
+ * @param {jQuery} form Root element of the GLForm
+ * @param {Object} enableGFM Which autocomplete features should be enabled?
+ * @param {Boolean} forceNew If true, treat the element as a **new** form even if `gfm-form` class already exists.
+ */
+ constructor(form, enableGFM = {}, forceNew = false) {
this.form = form;
this.textarea = this.form.find('textarea.js-gfm-input');
this.enableGFM = { ...defaultAutocompleteConfig, ...enableGFM };
@@ -22,7 +29,7 @@ export default class GLForm {
// Before we start, we should clean up any previous data for this form
this.destroy();
// Set up the form
- this.setupForm();
+ this.setupForm(forceNew);
this.form.data('glForm', this);
}
@@ -39,8 +46,8 @@ export default class GLForm {
this.form.data('glForm', null);
}
- setupForm() {
- const isNewForm = this.form.is(':not(.gfm-form)');
+ setupForm(forceNew = false) {
+ const isNewForm = this.form.is(':not(.gfm-form)') || forceNew;
this.form.removeClass('js-new-note-form');
if (isNewForm) {
this.form.find('.div-dropzone').remove();
diff --git a/app/assets/javascripts/grafana_integration/components/grafana_integration.vue b/app/assets/javascripts/grafana_integration/components/grafana_integration.vue
index 79494cb173b..7a991ac2455 100644
--- a/app/assets/javascripts/grafana_integration/components/grafana_integration.vue
+++ b/app/assets/javascripts/grafana_integration/components/grafana_integration.vue
@@ -92,11 +92,9 @@ export default {
</a>
</p>
</gl-form-group>
- <div class="gl-display-flex gl-justify-content-end">
- <gl-button variant="success" category="primary" @click="updateGrafanaIntegration">
- {{ __('Save Changes') }}
- </gl-button>
- </div>
+ <gl-button variant="success" category="primary" @click="updateGrafanaIntegration">
+ {{ __('Save Changes') }}
+ </gl-button>
</form>
</div>
</section>
diff --git a/app/assets/javascripts/group_label_subscription.js b/app/assets/javascripts/group_label_subscription.js
index 8c6c0714ee8..bfaa54080bd 100644
--- a/app/assets/javascripts/group_label_subscription.js
+++ b/app/assets/javascripts/group_label_subscription.js
@@ -2,6 +2,7 @@ import $ from 'jquery';
import { __ } from '~/locale';
import axios from './lib/utils/axios_utils';
import { deprecatedCreateFlash as flash } from './flash';
+import { fixTitle, hide } from '~/tooltips';
const tooltipTitles = {
group: __('Unsubscribe at group level'),
@@ -59,9 +60,9 @@ export default class GroupLabelSubscription {
const type = $button.hasClass('js-group-level') ? 'group' : 'project';
const newTitle = tooltipTitles[type];
- $('.js-unsubscribe-button', $button.closest('.label-actions-list'))
- .tooltip('hide')
- .attr('title', newTitle)
- .tooltip('_fixTitle');
+ const $el = $('.js-unsubscribe-button', $button.closest('.label-actions-list'));
+ hide($el);
+ $el.attr('title', `${newTitle}`);
+ fixTitle($el);
}
}
diff --git a/app/assets/javascripts/group_settings/components/shared_runners_form.vue b/app/assets/javascripts/group_settings/components/shared_runners_form.vue
new file mode 100644
index 00000000000..e396521ce7c
--- /dev/null
+++ b/app/assets/javascripts/group_settings/components/shared_runners_form.vue
@@ -0,0 +1,139 @@
+<script>
+import { GlToggle, GlLoadingIcon, GlTooltip, GlAlert } from '@gitlab/ui';
+import { debounce } from 'lodash';
+import { __ } from '~/locale';
+import axios from '~/lib/utils/axios_utils';
+import {
+ DEBOUNCE_TOGGLE_DELAY,
+ ERROR_MESSAGE,
+ ENABLED,
+ DISABLED,
+ ALLOW_OVERRIDE,
+} from '../constants';
+
+export default {
+ components: {
+ GlToggle,
+ GlLoadingIcon,
+ GlTooltip,
+ GlAlert,
+ },
+ props: {
+ updatePath: {
+ type: String,
+ required: true,
+ },
+ sharedRunnersAvailability: {
+ type: String,
+ required: true,
+ },
+ parentSharedRunnersAvailability: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ },
+ data() {
+ return {
+ isLoading: false,
+ enabled: true,
+ allowOverride: false,
+ error: null,
+ };
+ },
+ computed: {
+ toggleDisabled() {
+ return this.parentSharedRunnersAvailability === DISABLED || this.isLoading;
+ },
+ enabledOrDisabledSetting() {
+ return this.enabled ? ENABLED : DISABLED;
+ },
+ disabledWithOverrideSetting() {
+ return this.allowOverride ? ALLOW_OVERRIDE : DISABLED;
+ },
+ },
+ created() {
+ if (this.sharedRunnersAvailability !== ENABLED) {
+ this.enabled = false;
+ }
+
+ if (this.sharedRunnersAvailability === ALLOW_OVERRIDE) {
+ this.allowOverride = true;
+ }
+ },
+ methods: {
+ generatePayload(data) {
+ return { shared_runners_setting: data };
+ },
+ enableOrDisable() {
+ this.updateRunnerSettings(this.generatePayload(this.enabledOrDisabledSetting));
+
+ // reset override toggle to false if shared runners are enabled
+ this.allowOverride = false;
+ },
+ override() {
+ this.updateRunnerSettings(this.generatePayload(this.disabledWithOverrideSetting));
+ },
+ updateRunnerSettings: debounce(function debouncedUpdateRunnerSettings(setting) {
+ this.isLoading = true;
+
+ axios
+ .put(this.updatePath, setting)
+ .then(() => {
+ this.isLoading = false;
+ })
+ .catch(error => {
+ const message = [
+ error.response?.data?.error || __('An error occurred while updating configuration.'),
+ ERROR_MESSAGE,
+ ].join(' ');
+
+ this.error = message;
+ });
+ }, DEBOUNCE_TOGGLE_DELAY),
+ },
+};
+</script>
+
+<template>
+ <div ref="sharedRunnersForm">
+ <gl-alert v-if="error" variant="danger" :dismissible="false">{{ error }}</gl-alert>
+
+ <h4 class="gl-display-flex gl-align-items-center">
+ {{ __('Set up shared runner availability') }}
+ <gl-loading-icon v-if="isLoading" class="gl-ml-3" inline />
+ </h4>
+
+ <section class="gl-mt-5">
+ <gl-toggle
+ v-model="enabled"
+ :disabled="toggleDisabled"
+ :label="__('Enable shared runners for this group')"
+ data-testid="enable-runners-toggle"
+ @change="enableOrDisable"
+ />
+
+ <span class="gl-text-gray-600">
+ {{ __('Enable shared runners for all projects and subgroups in this group.') }}
+ </span>
+ </section>
+
+ <section v-if="!enabled" class="gl-mt-5">
+ <gl-toggle
+ v-model="allowOverride"
+ :disabled="toggleDisabled"
+ :label="__('Allow projects and subgroups to override the group setting')"
+ data-testid="override-runners-toggle"
+ @change="override"
+ />
+
+ <span class="gl-text-gray-600">
+ {{ __('Allows projects or subgroups in this group to override the global setting.') }}
+ </span>
+ </section>
+
+ <gl-tooltip v-if="toggleDisabled" :target="() => $refs.sharedRunnersForm">
+ {{ __('Shared runners are disabled for the parent group') }}
+ </gl-tooltip>
+ </div>
+</template>
diff --git a/app/assets/javascripts/group_settings/constants.js b/app/assets/javascripts/group_settings/constants.js
new file mode 100644
index 00000000000..c7bb851c06b
--- /dev/null
+++ b/app/assets/javascripts/group_settings/constants.js
@@ -0,0 +1,11 @@
+import { __ } from '~/locale';
+
+// Debounce delay in milliseconds
+export const DEBOUNCE_TOGGLE_DELAY = 1000;
+
+export const ERROR_MESSAGE = __('Refresh the page and try again.');
+
+// runner setting options
+export const ENABLED = 'enabled';
+export const DISABLED = 'disabled_and_unoverridable';
+export const ALLOW_OVERRIDE = 'disabled_with_override';
diff --git a/app/assets/javascripts/group_settings/mount_shared_runners.js b/app/assets/javascripts/group_settings/mount_shared_runners.js
new file mode 100644
index 00000000000..44284204c41
--- /dev/null
+++ b/app/assets/javascripts/group_settings/mount_shared_runners.js
@@ -0,0 +1,15 @@
+import Vue from 'vue';
+import UpdateSharedRunnersForm from './components/shared_runners_form.vue';
+
+export default (containerId = 'update-shared-runners-form') => {
+ const containerEl = document.getElementById(containerId);
+
+ return new Vue({
+ el: containerEl,
+ render(createElement) {
+ return createElement(UpdateSharedRunnersForm, {
+ props: containerEl.dataset,
+ });
+ },
+ });
+};
diff --git a/app/assets/javascripts/groups/components/group_folder.vue b/app/assets/javascripts/groups/components/group_folder.vue
index 8c7192b49a0..d2a613bed4f 100644
--- a/app/assets/javascripts/groups/components/group_folder.vue
+++ b/app/assets/javascripts/groups/components/group_folder.vue
@@ -1,8 +1,12 @@
<script>
+import { GlIcon } from '@gitlab/ui';
import { n__ } from '../../locale';
import { MAX_CHILDREN_COUNT } from '../constants';
export default {
+ components: {
+ GlIcon,
+ },
props: {
parentGroup: {
type: Object,
@@ -45,7 +49,7 @@ export default {
/>
<li v-if="hasMoreChildren" class="group-row">
<a :href="parentGroup.relativePath" class="group-row-contents has-more-items py-2">
- <i class="fa fa-external-link" aria-hidden="true"> </i> {{ moreChildrenStats }}
+ <gl-icon name="external-link" aria-hidden="true" /> {{ moreChildrenStats }}
</a>
</li>
</ul>
diff --git a/app/assets/javascripts/groups/components/item_actions.vue b/app/assets/javascripts/groups/components/item_actions.vue
index 5487e25066e..2e92a608f76 100644
--- a/app/assets/javascripts/groups/components/item_actions.vue
+++ b/app/assets/javascripts/groups/components/item_actions.vue
@@ -53,6 +53,7 @@ export default {
:aria-label="leaveBtnTitle"
data-container="body"
data-placement="bottom"
+ data-testid="leave-group-btn"
class="leave-group btn btn-xs no-expand gl-text-gray-500 gl-ml-5"
@click.prevent="onLeaveGroup"
>
@@ -66,6 +67,7 @@ export default {
:aria-label="editBtnTitle"
data-container="body"
data-placement="bottom"
+ data-testid="edit-group-btn"
class="edit-group btn btn-xs no-expand gl-text-gray-500 gl-ml-5"
>
<gl-icon name="settings" class="position-top-0 align-middle" />
diff --git a/app/assets/javascripts/groups/components/item_stats_value.vue b/app/assets/javascripts/groups/components/item_stats_value.vue
index 18efd8c6823..52dc7cfa19d 100644
--- a/app/assets/javascripts/groups/components/item_stats_value.vue
+++ b/app/assets/javascripts/groups/components/item_stats_value.vue
@@ -1,13 +1,12 @@
<script>
-import { GlIcon } from '@gitlab/ui';
-import tooltip from '~/vue_shared/directives/tooltip';
+import { GlIcon, GlTooltipDirective } from '@gitlab/ui';
export default {
components: {
GlIcon,
},
directives: {
- tooltip,
+ GlTooltip: GlTooltipDirective,
},
props: {
title: {
@@ -51,12 +50,13 @@ export default {
<template>
<span
- v-tooltip
+ v-gl-tooltip
:data-placement="tooltipPlacement"
:class="cssClass"
:title="title"
data-container="body"
>
- <gl-icon :name="iconName" /> <span v-if="isValuePresent" class="stat-value"> {{ value }} </span>
+ <gl-icon :name="iconName" />
+ <span v-if="isValuePresent" class="stat-value" data-testid="itemStatValue"> {{ value }} </span>
</span>
</template>
diff --git a/app/assets/javascripts/groups/members/components/app.vue b/app/assets/javascripts/groups/members/components/app.vue
index e94b28f5773..2e6dd4a0bad 100644
--- a/app/assets/javascripts/groups/members/components/app.vue
+++ b/app/assets/javascripts/groups/members/components/app.vue
@@ -1,11 +1,38 @@
<script>
+import { mapState, mapMutations } from 'vuex';
+import { GlAlert } from '@gitlab/ui';
+import MembersTable from '~/vue_shared/components/members/table/members_table.vue';
+import { scrollToElement } from '~/lib/utils/common_utils';
+import { HIDE_ERROR } from '~/vuex_shared/modules/members/mutation_types';
+
export default {
name: 'GroupMembersApp',
+ components: { MembersTable, GlAlert },
+ computed: {
+ ...mapState(['showError', 'errorMessage']),
+ },
+ watch: {
+ showError(value) {
+ if (value) {
+ this.$nextTick(() => {
+ scrollToElement(this.$refs.errorAlert.$el);
+ });
+ }
+ },
+ },
+ methods: {
+ ...mapMutations({
+ hideError: HIDE_ERROR,
+ }),
+ },
};
</script>
<template>
- <span>
- <!-- Temporary empty template -->
- </span>
+ <div>
+ <gl-alert v-if="showError" ref="errorAlert" variant="danger" @dismiss="hideError">{{
+ errorMessage
+ }}</gl-alert>
+ <members-table />
+ </div>
</template>
diff --git a/app/assets/javascripts/groups/members/constants.js b/app/assets/javascripts/groups/members/constants.js
new file mode 100644
index 00000000000..6d71b666d7a
--- /dev/null
+++ b/app/assets/javascripts/groups/members/constants.js
@@ -0,0 +1,5 @@
+export const GROUP_MEMBER_BASE_PROPERTY_NAME = 'group_member';
+export const GROUP_MEMBER_ACCESS_LEVEL_PROPERTY_NAME = 'access_level';
+
+export const GROUP_LINK_BASE_PROPERTY_NAME = 'group_link';
+export const GROUP_LINK_ACCESS_LEVEL_PROPERTY_NAME = 'group_access';
diff --git a/app/assets/javascripts/groups/members/index.js b/app/assets/javascripts/groups/members/index.js
index 4ca1756f10c..3bbef14d199 100644
--- a/app/assets/javascripts/groups/members/index.js
+++ b/app/assets/javascripts/groups/members/index.js
@@ -1,23 +1,24 @@
import Vue from 'vue';
import Vuex from 'vuex';
+import { GlToast } from '@gitlab/ui';
+import { parseDataAttributes } from 'ee_else_ce/groups/members/utils';
import App from './components/app.vue';
import membersModule from '~/vuex_shared/modules/members';
-import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
-export default el => {
+export const initGroupMembersApp = (el, tableFields, requestFormatter) => {
if (!el) {
return () => {};
}
Vue.use(Vuex);
-
- const { members, groupId } = el.dataset;
+ Vue.use(GlToast);
const store = new Vuex.Store({
...membersModule({
- members: convertObjectPropsToCamelCase(JSON.parse(members), { deep: true }),
- sourceId: parseInt(groupId, 10),
+ ...parseDataAttributes(el),
currentUserId: gon.current_user_id || null,
+ tableFields,
+ requestFormatter,
}),
});
diff --git a/app/assets/javascripts/groups/members/utils.js b/app/assets/javascripts/groups/members/utils.js
new file mode 100644
index 00000000000..662eecc4e38
--- /dev/null
+++ b/app/assets/javascripts/groups/members/utils.js
@@ -0,0 +1,44 @@
+import { isUndefined } from 'lodash';
+import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
+import {
+ GROUP_MEMBER_BASE_PROPERTY_NAME,
+ GROUP_MEMBER_ACCESS_LEVEL_PROPERTY_NAME,
+ GROUP_LINK_BASE_PROPERTY_NAME,
+ GROUP_LINK_ACCESS_LEVEL_PROPERTY_NAME,
+} from './constants';
+
+export const parseDataAttributes = el => {
+ const { members, groupId, memberPath } = el.dataset;
+
+ return {
+ members: convertObjectPropsToCamelCase(JSON.parse(members), { deep: true }),
+ sourceId: parseInt(groupId, 10),
+ memberPath,
+ };
+};
+
+const baseRequestFormatter = (basePropertyName, accessLevelPropertyName) => ({
+ accessLevel,
+ ...otherProperties
+}) => {
+ const accessLevelProperty = !isUndefined(accessLevel)
+ ? { [accessLevelPropertyName]: accessLevel }
+ : {};
+
+ return {
+ [basePropertyName]: {
+ ...accessLevelProperty,
+ ...otherProperties,
+ },
+ };
+};
+
+export const memberRequestFormatter = baseRequestFormatter(
+ GROUP_MEMBER_BASE_PROPERTY_NAME,
+ GROUP_MEMBER_ACCESS_LEVEL_PROPERTY_NAME,
+);
+
+export const groupLinkRequestFormatter = baseRequestFormatter(
+ GROUP_LINK_BASE_PROPERTY_NAME,
+ GROUP_LINK_ACCESS_LEVEL_PROPERTY_NAME,
+);
diff --git a/app/assets/javascripts/ide/components/activity_bar.vue b/app/assets/javascripts/ide/components/activity_bar.vue
index 183816921c1..644808cb83a 100644
--- a/app/assets/javascripts/ide/components/activity_bar.vue
+++ b/app/assets/javascripts/ide/components/activity_bar.vue
@@ -1,8 +1,6 @@
<script>
-import $ from 'jquery';
import { mapActions, mapState } from 'vuex';
-import { GlIcon } from '@gitlab/ui';
-import tooltip from '~/vue_shared/directives/tooltip';
+import { GlIcon, GlTooltipDirective } from '@gitlab/ui';
import { leftSidebarViews } from '../constants';
export default {
@@ -10,7 +8,7 @@ export default {
GlIcon,
},
directives: {
- tooltip,
+ GlTooltip: GlTooltipDirective,
},
computed: {
...mapState(['currentActivityView']),
@@ -22,9 +20,7 @@ export default {
this.updateActivityBarView(view);
- // TODO: We must use JQuery here to interact with the Bootstrap tooltip API
- // https://gitlab.com/gitlab-org/gitlab/-/issues/217577
- $(e.currentTarget).tooltip('hide');
+ this.$root.$emit('bv::hide::tooltip');
},
},
leftSidebarViews,
@@ -32,11 +28,11 @@ export default {
</script>
<template>
- <nav class="ide-activity-bar">
+ <nav class="ide-activity-bar" data-testid="left-sidebar">
<ul class="list-unstyled">
<li>
<button
- v-tooltip
+ v-gl-tooltip.right.viewport
:class="{
active: currentActivityView === $options.leftSidebarViews.edit.name,
}"
@@ -54,7 +50,7 @@ export default {
</li>
<li>
<button
- v-tooltip
+ v-gl-tooltip.right.viewport
:class="{
active: currentActivityView === $options.leftSidebarViews.review.name,
}"
@@ -71,7 +67,7 @@ export default {
</li>
<li>
<button
- v-tooltip
+ v-gl-tooltip.right.viewport
:class="{
active: currentActivityView === $options.leftSidebarViews.commit.name,
}"
diff --git a/app/assets/javascripts/ide/components/commit_sidebar/actions.vue b/app/assets/javascripts/ide/components/commit_sidebar/actions.vue
index de4b0a34002..b89329c92ec 100644
--- a/app/assets/javascripts/ide/components/commit_sidebar/actions.vue
+++ b/app/assets/javascripts/ide/components/commit_sidebar/actions.vue
@@ -1,8 +1,8 @@
<script>
-/* eslint-disable vue/no-v-html */
import { escape } from 'lodash';
import { mapState, mapGetters, createNamespacedHelpers } from 'vuex';
-import { sprintf, s__ } from '~/locale';
+import { GlSprintf } from '@gitlab/ui';
+import { s__ } from '~/locale';
import consts from '../../stores/modules/commit/constants';
import RadioGroup from './radio_group.vue';
import NewMergeRequestOption from './new_merge_request_option.vue';
@@ -13,6 +13,7 @@ const { mapState: mapCommitState, mapActions: mapCommitActions } = createNamespa
export default {
components: {
+ GlSprintf,
RadioGroup,
NewMergeRequestOption,
},
@@ -20,12 +21,8 @@ export default {
...mapState(['currentBranchId', 'changedFiles', 'stagedFiles']),
...mapCommitState(['commitAction']),
...mapGetters(['currentBranch', 'emptyRepo', 'canPushToBranch']),
- commitToCurrentBranchText() {
- return sprintf(
- s__('IDE|Commit to %{branchName} branch'),
- { branchName: `<strong class="monospace">${escape(this.currentBranchId)}</strong>` },
- false,
- );
+ currentBranchText() {
+ return escape(this.currentBranchId);
},
containsStagedChanges() {
return this.changedFiles.length > 0 && this.stagedFiles.length > 0;
@@ -77,11 +74,13 @@ export default {
:disabled="!canPushToBranch"
:title="$options.currentBranchPermissionsTooltip"
>
- <span
- class="ide-option-label"
- data-qa-selector="commit_to_current_branch_radio"
- v-html="commitToCurrentBranchText"
- ></span>
+ <span class="ide-option-label" data-qa-selector="commit_to_current_branch_radio">
+ <gl-sprintf :message="s__('IDE|Commit to %{branchName} branch')">
+ <template #branchName>
+ <strong class="monospace">{{ currentBranchText }}</strong>
+ </template>
+ </gl-sprintf>
+ </span>
</radio-group>
<template v-if="!emptyRepo">
<radio-group
diff --git a/app/assets/javascripts/ide/components/commit_sidebar/editor_header.vue b/app/assets/javascripts/ide/components/commit_sidebar/editor_header.vue
index bbcb866c758..53fac09ab66 100644
--- a/app/assets/javascripts/ide/components/commit_sidebar/editor_header.vue
+++ b/app/assets/javascripts/ide/components/commit_sidebar/editor_header.vue
@@ -1,6 +1,6 @@
<script>
import { mapActions } from 'vuex';
-import { GlModal } from '@gitlab/ui';
+import { GlModal, GlButton } from '@gitlab/ui';
import { sprintf, __ } from '~/locale';
import FileIcon from '~/vue_shared/components/file_icon.vue';
import ChangedFileIcon from '~/vue_shared/components/changed_file_icon.vue';
@@ -8,6 +8,7 @@ import ChangedFileIcon from '~/vue_shared/components/changed_file_icon.vue';
export default {
components: {
GlModal,
+ GlButton,
FileIcon,
ChangedFileIcon,
},
@@ -52,15 +53,16 @@ export default {
</strong>
<changed-file-icon :file="activeFile" :is-centered="false" />
<div class="ml-auto">
- <button
+ <gl-button
v-if="canDiscard"
ref="discardButton"
- type="button"
- class="btn btn-remove btn-inverted gl-mr-3"
+ category="secondary"
+ variant="danger"
+ class="gl-mr-3"
@click="showDiscardModal"
>
{{ __('Discard changes') }}
- </button>
+ </gl-button>
</div>
<gl-modal
ref="discardModal"
diff --git a/app/assets/javascripts/ide/components/commit_sidebar/form.vue b/app/assets/javascripts/ide/components/commit_sidebar/form.vue
index 73c56514fce..f36fe87ccfa 100644
--- a/app/assets/javascripts/ide/components/commit_sidebar/form.vue
+++ b/app/assets/javascripts/ide/components/commit_sidebar/form.vue
@@ -7,7 +7,6 @@ import CommitMessageField from './message_field.vue';
import Actions from './actions.vue';
import SuccessMessage from './success_message.vue';
import { leftSidebarViews, MAX_WINDOW_HEIGHT_COMPACT } from '../../constants';
-import consts from '../../stores/modules/commit/constants';
import { createUnexpectedCommitError } from '../../lib/errors';
export default {
@@ -45,12 +44,11 @@ export default {
return this.currentActivityView === leftSidebarViews.commit.name;
},
commitErrorPrimaryAction() {
- if (!this.lastCommitError?.canCreateBranch) {
- return undefined;
- }
+ const { primaryAction } = this.lastCommitError || {};
return {
- text: __('Create new branch'),
+ button: primaryAction ? { text: primaryAction.text } : undefined,
+ callback: primaryAction?.callback?.bind(this, this.$store) || (() => {}),
};
},
},
@@ -78,9 +76,6 @@ export default {
commit() {
return this.commitChanges();
},
- forceCreateNewBranch() {
- return this.updateCommitAction(consts.COMMIT_TO_NEW_BRANCH).then(() => this.commit());
- },
handleCompactState() {
if (this.lastCommitMsg) {
this.isCompact = false;
@@ -188,9 +183,9 @@ export default {
ref="commitErrorModal"
modal-id="ide-commit-error-modal"
:title="lastCommitError.title"
- :action-primary="commitErrorPrimaryAction"
+ :action-primary="commitErrorPrimaryAction.button"
:action-cancel="{ text: __('Cancel') }"
- @ok="forceCreateNewBranch"
+ @ok="commitErrorPrimaryAction.callback"
>
<div v-safe-html="lastCommitError.messageHTML"></div>
</gl-modal>
diff --git a/app/assets/javascripts/ide/components/commit_sidebar/message_field.vue b/app/assets/javascripts/ide/components/commit_sidebar/message_field.vue
index 2787b10a48b..7d08815b033 100644
--- a/app/assets/javascripts/ide/components/commit_sidebar/message_field.vue
+++ b/app/assets/javascripts/ide/components/commit_sidebar/message_field.vue
@@ -1,5 +1,5 @@
<script>
-import { GlIcon } from '@gitlab/ui';
+import { GlIcon, GlPopover } from '@gitlab/ui';
import { __, sprintf } from '../../../locale';
import popover from '../../../vue_shared/directives/popover';
import { MAX_TITLE_LENGTH, MAX_BODY_LENGTH } from '../../constants';
@@ -10,6 +10,7 @@ export default {
},
components: {
GlIcon,
+ GlPopover,
},
props: {
text: {
@@ -58,7 +59,7 @@ export default {
},
},
popoverOptions: {
- trigger: 'hover',
+ triggers: 'hover',
placement: 'top',
content: sprintf(
__(`
@@ -83,9 +84,16 @@ export default {
<ul class="nav-links">
<li>
{{ __('Commit Message') }}
- <span v-popover="$options.popoverOptions" class="form-text text-muted gl-ml-3">
- <gl-icon name="question" />
- </span>
+ <div id="ide-commit-message-popover-container">
+ <span id="ide-commit-message-question" class="form-text text-muted gl-ml-3">
+ <gl-icon name="question" />
+ </span>
+ <gl-popover
+ target="ide-commit-message-question"
+ container="ide-commit-message-popover-container"
+ v-bind="$options.popoverOptions"
+ />
+ </div>
</li>
</ul>
</div>
@@ -108,6 +116,7 @@ export default {
:placeholder="placeholder"
:value="text"
class="note-textarea ide-commit-message-textarea"
+ data-qa-selector="ide_commit_message_field"
dir="auto"
name="commit-message"
@scroll="handleScroll"
diff --git a/app/assets/javascripts/ide/components/editor_mode_dropdown.vue b/app/assets/javascripts/ide/components/editor_mode_dropdown.vue
index 732fa0786b0..dec8aa61838 100644
--- a/app/assets/javascripts/ide/components/editor_mode_dropdown.vue
+++ b/app/assets/javascripts/ide/components/editor_mode_dropdown.vue
@@ -1,8 +1,12 @@
<script>
+import { GlButton } from '@gitlab/ui';
import { __, sprintf } from '~/locale';
import { viewerTypes } from '../constants';
export default {
+ components: {
+ GlButton,
+ },
props: {
viewer: {
type: String,
@@ -31,7 +35,7 @@ export default {
<template>
<div class="dropdown">
- <button type="button" class="btn btn-link" data-toggle="dropdown">{{ __('Edit') }}</button>
+ <gl-button variant="link" data-toggle="dropdown">{{ __('Edit') }}</gl-button>
<div class="dropdown-menu dropdown-menu-selectable dropdown-open-left">
<ul>
<li>
diff --git a/app/assets/javascripts/ide/components/file_templates/bar.vue b/app/assets/javascripts/ide/components/file_templates/bar.vue
index b6a57d1b6e6..88dca2f0556 100644
--- a/app/assets/javascripts/ide/components/file_templates/bar.vue
+++ b/app/assets/javascripts/ide/components/file_templates/bar.vue
@@ -1,10 +1,12 @@
<script>
+import { GlButton } from '@gitlab/ui';
import { mapActions, mapGetters, mapState } from 'vuex';
import Dropdown from './dropdown.vue';
export default {
components: {
Dropdown,
+ GlButton,
},
computed: {
...mapGetters(['activeFile']),
@@ -65,9 +67,9 @@ export default {
@click="selectTemplate"
/>
<transition name="fade">
- <button v-show="updateSuccess" type="button" class="btn btn-default" @click="undo">
+ <gl-button v-show="updateSuccess" category="secondary" variant="default" @click="undo">
{{ __('Undo') }}
- </button>
+ </gl-button>
</transition>
</div>
</template>
diff --git a/app/assets/javascripts/ide/components/file_templates/dropdown.vue b/app/assets/javascripts/ide/components/file_templates/dropdown.vue
index d80662f6ae1..cfd2555b769 100644
--- a/app/assets/javascripts/ide/components/file_templates/dropdown.vue
+++ b/app/assets/javascripts/ide/components/file_templates/dropdown.vue
@@ -1,12 +1,13 @@
<script>
import $ from 'jquery';
import { mapActions, mapState } from 'vuex';
-import { GlLoadingIcon } from '@gitlab/ui';
+import { GlIcon, GlLoadingIcon } from '@gitlab/ui';
import DropdownButton from '~/vue_shared/components/dropdown/dropdown_button.vue';
export default {
components: {
DropdownButton,
+ GlIcon,
GlLoadingIcon,
},
props: {
@@ -85,7 +86,7 @@ export default {
type="search"
class="dropdown-input-field qa-dropdown-filter-input"
/>
- <i aria-hidden="true" class="fa fa-search dropdown-input-search"></i>
+ <gl-icon name="search" class="dropdown-input-search" aria-hidden="true" />
</div>
<div class="dropdown-content">
<gl-loading-icon v-if="showLoading" size="lg" />
diff --git a/app/assets/javascripts/ide/components/ide.vue b/app/assets/javascripts/ide/components/ide.vue
index 1b03d9eee8b..8f23856fd6c 100644
--- a/app/assets/javascripts/ide/components/ide.vue
+++ b/app/assets/javascripts/ide/components/ide.vue
@@ -2,7 +2,18 @@
import { mapActions, mapGetters, mapState } from 'vuex';
import { GlButton, GlLoadingIcon } from '@gitlab/ui';
import { __ } from '~/locale';
+import {
+ WEBIDE_MARK_APP_START,
+ WEBIDE_MARK_FILE_FINISH,
+ WEBIDE_MARK_FILE_CLICKED,
+ WEBIDE_MARK_TREE_FINISH,
+ WEBIDE_MEASURE_TREE_FROM_REQUEST,
+ WEBIDE_MEASURE_FILE_FROM_REQUEST,
+ WEBIDE_MEASURE_FILE_AFTER_INTERACTION,
+} from '~/performance_constants';
+import { performanceMarkAndMeasure } from '~/performance_utils';
import { modalTypes } from '../constants';
+import eventHub from '../eventhub';
import FindFile from '~/vue_shared/components/file_finder/index.vue';
import NewModal from './new_dropdown/modal.vue';
import IdeSidebar from './ide_side_bar.vue';
@@ -14,6 +25,22 @@ import ErrorMessage from './error_message.vue';
import CommitEditorHeader from './commit_sidebar/editor_header.vue';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
+import { measurePerformance } from '../utils';
+
+eventHub.$on(WEBIDE_MEASURE_TREE_FROM_REQUEST, () =>
+ measurePerformance(WEBIDE_MARK_TREE_FINISH, WEBIDE_MEASURE_TREE_FROM_REQUEST),
+);
+eventHub.$on(WEBIDE_MEASURE_FILE_FROM_REQUEST, () =>
+ measurePerformance(WEBIDE_MARK_FILE_FINISH, WEBIDE_MEASURE_FILE_FROM_REQUEST),
+);
+eventHub.$on(WEBIDE_MEASURE_FILE_AFTER_INTERACTION, () =>
+ measurePerformance(
+ WEBIDE_MARK_FILE_FINISH,
+ WEBIDE_MEASURE_FILE_AFTER_INTERACTION,
+ WEBIDE_MARK_FILE_CLICKED,
+ ),
+);
+
export default {
components: {
NewModal,
@@ -59,6 +86,9 @@ export default {
if (this.themeName)
document.querySelector('.navbar-gitlab').classList.add(`theme-${this.themeName}`);
},
+ beforeCreate() {
+ performanceMarkAndMeasure({ mark: WEBIDE_MARK_APP_START });
+ },
methods: {
...mapActions(['toggleFileFinder']),
onBeforeUnload(e = {}) {
diff --git a/app/assets/javascripts/ide/components/ide_review.vue b/app/assets/javascripts/ide/components/ide_review.vue
index e36d0a5a5b1..7d2f0acb08c 100644
--- a/app/assets/javascripts/ide/components/ide_review.vue
+++ b/app/assets/javascripts/ide/components/ide_review.vue
@@ -23,26 +23,32 @@ export default {
},
},
mounted() {
- if (this.activeFile && this.activeFile.pending && !this.activeFile.deleted) {
- this.$router.push(this.getUrlForPath(this.activeFile.path), () => {
- this.updateViewer('editor');
- });
- } else if (this.activeFile && this.activeFile.deleted) {
- this.resetOpenFiles();
- }
-
- this.$nextTick(() => {
- this.updateViewer(this.currentMergeRequestId ? viewerTypes.mr : viewerTypes.diff);
- });
+ this.initialize();
+ },
+ activated() {
+ this.initialize();
},
methods: {
...mapActions(['updateViewer', 'resetOpenFiles']),
+ initialize() {
+ if (this.activeFile && this.activeFile.pending && !this.activeFile.deleted) {
+ this.$router.push(this.getUrlForPath(this.activeFile.path), () => {
+ this.updateViewer(viewerTypes.edit);
+ });
+ } else if (this.activeFile && this.activeFile.deleted) {
+ this.resetOpenFiles();
+ }
+
+ this.$nextTick(() => {
+ this.updateViewer(this.currentMergeRequestId ? viewerTypes.mr : viewerTypes.diff);
+ });
+ },
},
};
</script>
<template>
- <ide-tree-list :viewer-type="viewer" header-class="ide-review-header">
+ <ide-tree-list header-class="ide-review-header">
<template #header>
<div class="ide-review-button-holder">
{{ __('Review') }}
diff --git a/app/assets/javascripts/ide/components/ide_side_bar.vue b/app/assets/javascripts/ide/components/ide_side_bar.vue
index ed68ca5cae9..53dfc133fc8 100644
--- a/app/assets/javascripts/ide/components/ide_side_bar.vue
+++ b/app/assets/javascripts/ide/components/ide_side_bar.vue
@@ -7,9 +7,8 @@ import ActivityBar from './activity_bar.vue';
import RepoCommitSection from './repo_commit_section.vue';
import CommitForm from './commit_sidebar/form.vue';
import IdeReview from './ide_review.vue';
-import SuccessMessage from './commit_sidebar/success_message.vue';
import IdeProjectHeader from './ide_project_header.vue';
-import { leftSidebarViews, SIDEBAR_INIT_WIDTH } from '../constants';
+import { SIDEBAR_INIT_WIDTH } from '../constants';
export default {
components: {
@@ -20,18 +19,11 @@ export default {
IdeTree,
CommitForm,
IdeReview,
- SuccessMessage,
IdeProjectHeader,
},
computed: {
...mapState(['loading', 'currentActivityView', 'changedFiles', 'stagedFiles', 'lastCommitMsg']),
...mapGetters(['currentProject', 'someUncommittedChanges']),
- showSuccessMessage() {
- return (
- this.currentActivityView === leftSidebarViews.edit.name &&
- (this.lastCommitMsg && !this.someUncommittedChanges)
- );
- },
},
SIDEBAR_INIT_WIDTH,
};
@@ -44,7 +36,7 @@ export default {
class="multi-file-commit-panel flex-column"
>
<template v-if="loading">
- <div class="multi-file-commit-panel-inner">
+ <div class="multi-file-commit-panel-inner" data-testid="ide-side-bar-inner">
<div v-for="n in 3" :key="n" class="multi-file-loading-container">
<gl-skeleton-loading />
</div>
@@ -54,9 +46,11 @@ export default {
<ide-project-header :project="currentProject" />
<div class="ide-context-body d-flex flex-fill">
<activity-bar />
- <div class="multi-file-commit-panel-inner">
+ <div class="multi-file-commit-panel-inner" data-testid="ide-side-bar-inner">
<div class="multi-file-commit-panel-inner-content">
- <component :is="currentActivityView" />
+ <keep-alive>
+ <component :is="currentActivityView" />
+ </keep-alive>
</div>
<commit-form />
</div>
diff --git a/app/assets/javascripts/ide/components/ide_status_bar.vue b/app/assets/javascripts/ide/components/ide_status_bar.vue
index 146e818d654..ee292190e06 100644
--- a/app/assets/javascripts/ide/components/ide_status_bar.vue
+++ b/app/assets/javascripts/ide/components/ide_status_bar.vue
@@ -1,10 +1,9 @@
<script>
/* eslint-disable @gitlab/vue-require-i18n-strings */
import { mapActions, mapState, mapGetters } from 'vuex';
-import { GlIcon } from '@gitlab/ui';
+import { GlIcon, GlTooltipDirective } from '@gitlab/ui';
import IdeStatusList from './ide_status_list.vue';
import IdeStatusMr from './ide_status_mr.vue';
-import tooltip from '~/vue_shared/directives/tooltip';
import timeAgoMixin from '~/vue_shared/mixins/timeago';
import CiIcon from '../../vue_shared/components/ci_icon.vue';
import userAvatarImage from '../../vue_shared/components/user_avatar/user_avatar_image.vue';
@@ -19,7 +18,7 @@ export default {
IdeStatusMr,
},
directives: {
- tooltip,
+ GlTooltip: GlTooltipDirective,
},
mixins: [timeAgoMixin],
data() {
@@ -85,7 +84,7 @@ export default {
@click="openRightPane($options.rightSidebarViews.pipelines)"
>
<ci-icon
- v-tooltip
+ v-gl-tooltip
:status="latestPipeline.details.status"
:title="latestPipeline.details.status.text"
/>
@@ -99,7 +98,7 @@ export default {
<gl-icon name="commit" />
<a
- v-tooltip
+ v-gl-tooltip
:title="lastCommit.message"
:href="getCommitPath(lastCommit.short_id)"
class="commit-sha"
@@ -116,7 +115,7 @@ export default {
/>
{{ lastCommit.author_name }}
<time
- v-tooltip
+ v-gl-tooltip
:datetime="lastCommit.committed_date"
:title="tooltipTitle(lastCommit.committed_date)"
data-placement="top"
diff --git a/app/assets/javascripts/ide/components/ide_tree.vue b/app/assets/javascripts/ide/components/ide_tree.vue
index 747d5044790..51d783df0ad 100644
--- a/app/assets/javascripts/ide/components/ide_tree.vue
+++ b/app/assets/javascripts/ide/components/ide_tree.vue
@@ -1,6 +1,6 @@
<script>
import { mapState, mapGetters, mapActions } from 'vuex';
-import { modalTypes } from '../constants';
+import { modalTypes, viewerTypes } from '../constants';
import IdeTreeList from './ide_tree_list.vue';
import Upload from './new_dropdown/upload.vue';
import NewEntryButton from './new_dropdown/button.vue';
@@ -18,15 +18,10 @@ export default {
...mapGetters(['currentProject', 'currentTree', 'activeFile', 'getUrlForPath']),
},
mounted() {
- if (!this.activeFile) return;
-
- if (this.activeFile.pending && !this.activeFile.deleted) {
- this.$router.push(this.getUrlForPath(this.activeFile.path), () => {
- this.updateViewer('editor');
- });
- } else if (this.activeFile.deleted) {
- this.resetOpenFiles();
- }
+ this.initialize();
+ },
+ activated() {
+ this.initialize();
},
methods: {
...mapActions(['updateViewer', 'createTempEntry', 'resetOpenFiles']),
@@ -36,12 +31,27 @@ export default {
createNewFolder() {
this.$refs.newModal.open(modalTypes.tree);
},
+ initialize() {
+ this.$nextTick(() => {
+ this.updateViewer(viewerTypes.edit);
+ });
+
+ if (!this.activeFile) return;
+
+ if (this.activeFile.pending && !this.activeFile.deleted) {
+ this.$router.push(this.getUrlForPath(this.activeFile.path), () => {
+ this.updateViewer(viewerTypes.edit);
+ });
+ } else if (this.activeFile.deleted) {
+ this.resetOpenFiles();
+ }
+ },
},
};
</script>
<template>
- <ide-tree-list viewer-type="editor">
+ <ide-tree-list>
<template #header>
{{ __('Edit') }}
<div class="ide-tree-actions ml-auto d-flex">
diff --git a/app/assets/javascripts/ide/components/ide_tree_list.vue b/app/assets/javascripts/ide/components/ide_tree_list.vue
index 776d8459515..dd226f07fb0 100644
--- a/app/assets/javascripts/ide/components/ide_tree_list.vue
+++ b/app/assets/javascripts/ide/components/ide_tree_list.vue
@@ -2,6 +2,13 @@
import { mapActions, mapGetters, mapState } from 'vuex';
import { GlDeprecatedSkeletonLoading as GlSkeletonLoading } from '@gitlab/ui';
import FileTree from '~/vue_shared/components/file_tree.vue';
+import {
+ WEBIDE_MARK_TREE_START,
+ WEBIDE_MEASURE_TREE_FROM_REQUEST,
+ WEBIDE_MARK_FILE_CLICKED,
+} from '~/performance_constants';
+import { performanceMarkAndMeasure } from '~/performance_utils';
+import eventHub from '../eventhub';
import IdeFileRow from './ide_file_row.vue';
import NavDropdown from './nav_dropdown.vue';
@@ -12,10 +19,6 @@ export default {
FileTree,
},
props: {
- viewerType: {
- type: String,
- required: true,
- },
headerClass: {
type: String,
required: false,
@@ -29,11 +32,19 @@ export default {
return !this.currentTree || this.currentTree.loading;
},
},
- mounted() {
- this.updateViewer(this.viewerType);
+ beforeCreate() {
+ performanceMarkAndMeasure({ mark: WEBIDE_MARK_TREE_START });
+ },
+ updated() {
+ if (this.currentTree?.tree?.length) {
+ eventHub.$emit(WEBIDE_MEASURE_TREE_FROM_REQUEST);
+ }
},
methods: {
- ...mapActions(['updateViewer', 'toggleTreeOpen']),
+ ...mapActions(['toggleTreeOpen']),
+ clickedFile() {
+ performanceMarkAndMeasure({ mark: WEBIDE_MARK_FILE_CLICKED });
+ },
},
IdeFileRow,
};
@@ -51,7 +62,7 @@ export default {
<nav-dropdown />
<slot name="header"></slot>
</header>
- <div class="ide-tree-body h-100">
+ <div class="ide-tree-body h-100" data-testid="ide-tree-body">
<template v-if="currentTree.tree.length">
<file-tree
v-for="file in currentTree.tree"
@@ -60,6 +71,7 @@ export default {
:level="0"
:file-row-component="$options.IdeFileRow"
@toggleTreeOpen="toggleTreeOpen"
+ @clickFile="clickedFile"
/>
</template>
<div v-else class="file-row">{{ __('No files') }}</div>
diff --git a/app/assets/javascripts/ide/components/jobs/detail.vue b/app/assets/javascripts/ide/components/jobs/detail.vue
index 11033a5cc88..a5ae8bbfe9a 100644
--- a/app/assets/javascripts/ide/components/jobs/detail.vue
+++ b/app/assets/javascripts/ide/components/jobs/detail.vue
@@ -2,9 +2,8 @@
/* eslint-disable vue/no-v-html */
import { mapActions, mapState } from 'vuex';
import { throttle } from 'lodash';
-import { GlIcon } from '@gitlab/ui';
+import { GlIcon, GlTooltipDirective } from '@gitlab/ui';
import { __ } from '../../../locale';
-import tooltip from '../../../vue_shared/directives/tooltip';
import ScrollButton from './detail/scroll_button.vue';
import JobDescription from './detail/description.vue';
@@ -15,7 +14,7 @@ const scrollPositions = {
export default {
directives: {
- tooltip,
+ GlTooltip: GlTooltipDirective,
},
components: {
GlIcon,
@@ -84,7 +83,7 @@ export default {
<job-description :job="detailJob" />
<div class="controllers ml-auto">
<a
- v-tooltip
+ v-gl-tooltip
:title="__('Show complete raw log')"
:href="detailJob.rawPath"
data-placement="top"
@@ -92,7 +91,7 @@ export default {
class="controllers-buttons"
target="_blank"
>
- <i aria-hidden="true" class="fa fa-file-text-o"></i>
+ <gl-icon name="doc-text" aria-hidden="true" />
</a>
<scroll-button :disabled="isScrolledToTop" direction="up" @click="scrollUp" />
<scroll-button :disabled="isScrolledToBottom" direction="down" @click="scrollDown" />
diff --git a/app/assets/javascripts/ide/components/jobs/detail/scroll_button.vue b/app/assets/javascripts/ide/components/jobs/detail/scroll_button.vue
index 2c679a3edc7..f4859b9f312 100644
--- a/app/assets/javascripts/ide/components/jobs/detail/scroll_button.vue
+++ b/app/assets/javascripts/ide/components/jobs/detail/scroll_button.vue
@@ -1,7 +1,6 @@
<script>
-import { GlIcon } from '@gitlab/ui';
+import { GlIcon, GlTooltipDirective } from '@gitlab/ui';
import { __ } from '../../../../locale';
-import tooltip from '../../../../vue_shared/directives/tooltip';
const directions = {
up: 'up',
@@ -10,7 +9,7 @@ const directions = {
export default {
directives: {
- tooltip,
+ GlTooltip: GlTooltipDirective,
},
components: {
GlIcon,
@@ -46,7 +45,7 @@ export default {
<template>
<div
- v-tooltip
+ v-gl-tooltip
:title="tooltipTitle"
class="controllers-buttons"
data-container="body"
diff --git a/app/assets/javascripts/ide/components/jobs/stage.vue b/app/assets/javascripts/ide/components/jobs/stage.vue
index 0b643947139..6c7f084c164 100644
--- a/app/assets/javascripts/ide/components/jobs/stage.vue
+++ b/app/assets/javascripts/ide/components/jobs/stage.vue
@@ -1,12 +1,11 @@
<script>
-import { GlLoadingIcon, GlIcon } from '@gitlab/ui';
-import tooltip from '../../../vue_shared/directives/tooltip';
+import { GlLoadingIcon, GlIcon, GlTooltipDirective } from '@gitlab/ui';
import CiIcon from '../../../vue_shared/components/ci_icon.vue';
import Item from './item.vue';
export default {
directives: {
- tooltip,
+ GlTooltip: GlTooltipDirective,
},
components: {
GlIcon,
@@ -67,7 +66,7 @@ export default {
<ci-icon :status="stage.status" :size="24" />
<strong
ref="stageTitle"
- v-tooltip="showTooltip"
+ v-gl-tooltip="showTooltip"
:title="showTooltip ? stage.name : null"
data-container="body"
class="gl-ml-3 text-truncate"
diff --git a/app/assets/javascripts/ide/components/new_dropdown/modal.vue b/app/assets/javascripts/ide/components/new_dropdown/modal.vue
index 528475849de..5ad836f346a 100644
--- a/app/assets/javascripts/ide/components/new_dropdown/modal.vue
+++ b/app/assets/javascripts/ide/components/new_dropdown/modal.vue
@@ -152,6 +152,7 @@ export default {
v-model.trim="entryName"
type="text"
class="form-control"
+ data-testid="file-name-field"
data-qa-selector="file_name_field"
:placeholder="placeholder"
/>
diff --git a/app/assets/javascripts/ide/components/new_dropdown/upload.vue b/app/assets/javascripts/ide/components/new_dropdown/upload.vue
index 84ff05c9750..4a9a2a57acd 100644
--- a/app/assets/javascripts/ide/components/new_dropdown/upload.vue
+++ b/app/assets/javascripts/ide/components/new_dropdown/upload.vue
@@ -35,7 +35,7 @@ export default {
name: `${this.path ? `${this.path}/` : ''}${name}`,
type: 'blob',
content,
- rawPath: !isText ? target.result : '',
+ rawPath: !isText ? URL.createObjectURL(file) : '',
});
if (isText) {
@@ -44,7 +44,7 @@ export default {
reader.addEventListener('load', e => emitCreateEvent(e.target.result), { once: true });
reader.readAsText(file);
} else {
- emitCreateEvent(encodedContent);
+ emitCreateEvent(rawContent);
}
},
readFile(file) {
diff --git a/app/assets/javascripts/ide/components/repo_commit_section.vue b/app/assets/javascripts/ide/components/repo_commit_section.vue
index 5eed57bb6c5..92b99b5c731 100644
--- a/app/assets/javascripts/ide/components/repo_commit_section.vue
+++ b/app/assets/javascripts/ide/components/repo_commit_section.vue
@@ -26,28 +26,34 @@ export default {
},
},
mounted() {
- const file =
- this.lastOpenedFile && this.lastOpenedFile.type !== 'tree'
- ? this.lastOpenedFile
- : this.activeFile;
-
- if (!file) return;
-
- this.openPendingTab({
- file,
- keyPrefix: file.staged ? stageKeys.staged : stageKeys.unstaged,
- })
- .then(changeViewer => {
- if (changeViewer) {
- this.updateViewer('diff');
- }
- })
- .catch(e => {
- throw e;
- });
+ this.initialize();
+ },
+ activated() {
+ this.initialize();
},
methods: {
...mapActions(['openPendingTab', 'updateViewer', 'updateActivityBarView']),
+ initialize() {
+ const file =
+ this.lastOpenedFile && this.lastOpenedFile.type !== 'tree'
+ ? this.lastOpenedFile
+ : this.activeFile;
+
+ if (!file) return;
+
+ this.openPendingTab({
+ file,
+ keyPrefix: file.staged ? stageKeys.staged : stageKeys.unstaged,
+ })
+ .then(changeViewer => {
+ if (changeViewer) {
+ this.updateViewer('diff');
+ }
+ })
+ .catch(e => {
+ throw e;
+ });
+ },
},
stageKeys,
};
diff --git a/app/assets/javascripts/ide/components/repo_editor.vue b/app/assets/javascripts/ide/components/repo_editor.vue
index f342ce1739c..56bbb6349cd 100644
--- a/app/assets/javascripts/ide/components/repo_editor.vue
+++ b/app/assets/javascripts/ide/components/repo_editor.vue
@@ -5,6 +5,14 @@ import { deprecatedCreateFlash as flash } from '~/flash';
import ContentViewer from '~/vue_shared/components/content_viewer/content_viewer.vue';
import DiffViewer from '~/vue_shared/components/diff_viewer/diff_viewer.vue';
import {
+ WEBIDE_MARK_FILE_CLICKED,
+ WEBIDE_MARK_FILE_START,
+ WEBIDE_MEASURE_FILE_AFTER_INTERACTION,
+ WEBIDE_MEASURE_FILE_FROM_REQUEST,
+} from '~/performance_constants';
+import { performanceMarkAndMeasure } from '~/performance_utils';
+import eventHub from '../eventhub';
+import {
leftSidebarViews,
viewerTypes,
FILE_VIEW_MODE_EDITOR,
@@ -60,7 +68,7 @@ export default {
]),
...mapGetters('fileTemplates', ['showFileTemplatesBar']),
shouldHideEditor() {
- return this.file && !isTextFile(this.file);
+ return this.file && !this.file.loading && !isTextFile(this.file);
},
showContentViewer() {
return (
@@ -164,6 +172,9 @@ export default {
}
},
},
+ beforeCreate() {
+ performanceMarkAndMeasure({ mark: WEBIDE_MARK_FILE_START });
+ },
beforeDestroy() {
this.editor.dispose();
},
@@ -224,6 +235,7 @@ export default {
return this.getFileData({
path: this.file.path,
makeFileActive: false,
+ toggleLoading: false,
}).then(() =>
this.getRawFileData({
path: this.file.path,
@@ -289,6 +301,11 @@ export default {
});
this.$emit('editorSetup');
+ if (performance.getEntriesByName(WEBIDE_MARK_FILE_CLICKED).length) {
+ eventHub.$emit(WEBIDE_MEASURE_FILE_AFTER_INTERACTION);
+ } else {
+ eventHub.$emit(WEBIDE_MEASURE_FILE_FROM_REQUEST);
+ }
},
refreshEditorDimensions() {
if (this.showEditor) {
diff --git a/app/assets/javascripts/ide/constants.js b/app/assets/javascripts/ide/constants.js
index 59b1969face..bdb11e6b004 100644
--- a/app/assets/javascripts/ide/constants.js
+++ b/app/assets/javascripts/ide/constants.js
@@ -47,9 +47,9 @@ export const diffViewerErrors = Object.freeze({
});
export const leftSidebarViews = {
- edit: { name: 'ide-tree', keepAlive: false },
- review: { name: 'ide-review', keepAlive: false },
- commit: { name: 'repo-commit-section', keepAlive: false },
+ edit: { name: 'ide-tree' },
+ review: { name: 'ide-review' },
+ commit: { name: 'repo-commit-section' },
};
export const rightSidebarViews = {
diff --git a/app/assets/javascripts/ide/index.js b/app/assets/javascripts/ide/index.js
index 7c767009de5..56d48e87c18 100644
--- a/app/assets/javascripts/ide/index.js
+++ b/app/assets/javascripts/ide/index.js
@@ -73,11 +73,9 @@ export function initIde(el, options = {}) {
* @param {Objects} options - Extra options for the IDE (Used by EE).
*/
export function startIde(options) {
- document.addEventListener('DOMContentLoaded', () => {
- const ideElement = document.getElementById('ide');
- if (ideElement) {
- resetServiceWorkersPublicPath();
- initIde(ideElement, options);
- }
- });
+ const ideElement = document.getElementById('ide');
+ if (ideElement) {
+ resetServiceWorkersPublicPath();
+ initIde(ideElement, options);
+ }
}
diff --git a/app/assets/javascripts/ide/lib/editor.js b/app/assets/javascripts/ide/lib/editor.js
index 2b12230c7cd..493dedcd89a 100644
--- a/app/assets/javascripts/ide/lib/editor.js
+++ b/app/assets/javascripts/ide/lib/editor.js
@@ -157,8 +157,10 @@ export default class Editor {
}
updateDimensions() {
- this.instance.layout();
- this.updateDiffView();
+ if (this.instance) {
+ this.instance.layout();
+ this.updateDiffView();
+ }
}
setPosition({ lineNumber, column }) {
diff --git a/app/assets/javascripts/ide/lib/errors.js b/app/assets/javascripts/ide/lib/errors.js
index 6ae18bc8180..e62d9d1e77f 100644
--- a/app/assets/javascripts/ide/lib/errors.js
+++ b/app/assets/javascripts/ide/lib/errors.js
@@ -1,25 +1,49 @@
import { escape } from 'lodash';
import { __ } from '~/locale';
+import consts from '../stores/modules/commit/constants';
const CODEOWNERS_REGEX = /Push.*protected branches.*CODEOWNERS/;
const BRANCH_CHANGED_REGEX = /changed.*since.*start.*edit/;
+const BRANCH_ALREADY_EXISTS = /branch.*already.*exists/;
-export const createUnexpectedCommitError = () => ({
+const createNewBranchAndCommit = store =>
+ store
+ .dispatch('commit/updateCommitAction', consts.COMMIT_TO_NEW_BRANCH)
+ .then(() => store.dispatch('commit/commitChanges'));
+
+export const createUnexpectedCommitError = message => ({
title: __('Unexpected error'),
- messageHTML: __('Could not commit. An unexpected error occurred.'),
- canCreateBranch: false,
+ messageHTML: escape(message) || __('Could not commit. An unexpected error occurred.'),
});
export const createCodeownersCommitError = message => ({
title: __('CODEOWNERS rule violation'),
messageHTML: escape(message),
- canCreateBranch: true,
+ primaryAction: {
+ text: __('Create new branch'),
+ callback: createNewBranchAndCommit,
+ },
});
export const createBranchChangedCommitError = message => ({
title: __('Branch changed'),
messageHTML: `${escape(message)}<br/><br/>${__('Would you like to create a new branch?')}`,
- canCreateBranch: true,
+ primaryAction: {
+ text: __('Create new branch'),
+ callback: createNewBranchAndCommit,
+ },
+});
+
+export const branchAlreadyExistsCommitError = message => ({
+ title: __('Branch already exists'),
+ messageHTML: `${escape(message)}<br/><br/>${__(
+ 'Would you like to try auto-generating a branch name?',
+ )}`,
+ primaryAction: {
+ text: __('Create new branch'),
+ callback: store =>
+ store.dispatch('commit/addSuffixToBranchName').then(() => createNewBranchAndCommit(store)),
+ },
});
export const parseCommitError = e => {
@@ -33,7 +57,9 @@ export const parseCommitError = e => {
return createCodeownersCommitError(message);
} else if (BRANCH_CHANGED_REGEX.test(message)) {
return createBranchChangedCommitError(message);
+ } else if (BRANCH_ALREADY_EXISTS.test(message)) {
+ return branchAlreadyExistsCommitError(message);
}
- return createUnexpectedCommitError();
+ return createUnexpectedCommitError(message);
};
diff --git a/app/assets/javascripts/ide/lib/languages/README.md b/app/assets/javascripts/ide/lib/languages/README.md
index e4d1a4c7818..c4f3de00783 100644
--- a/app/assets/javascripts/ide/lib/languages/README.md
+++ b/app/assets/javascripts/ide/lib/languages/README.md
@@ -1,7 +1,7 @@
# Web IDE Languages
The Web IDE uses the [Monaco editor](https://microsoft.github.io/monaco-editor/) which uses the [Monarch library](https://microsoft.github.io/monaco-editor/monarch.html) for syntax highlighting.
-The Web IDE currently supports all langauges defined in the [monaco-languages](https://github.com/microsoft/monaco-languages/tree/master/src) repository.
+The Web IDE currently supports all languages defined in the [monaco-languages](https://github.com/microsoft/monaco-languages/tree/master/src) repository.
## Adding New Languages
@@ -14,7 +14,7 @@ Should you be willing to help us and add support to GitLab for any missing langu
2. Create a new file in this folder called `{languageName}.js`, where `{languageName}` is the name of the language you want to add support for.
3. Follow the [Monarch documentation](https://microsoft.github.io/monaco-editor/monarch.html) to add a configuration for the new language.
- Example: The [`vue.js`](./vue.js) file in the current directory adds support for Vue.js Syntax Highlighting.
-4. Add tests for the new langauge implementation in `spec/frontend/ide/lib/languages/{langaugeName}.js`.
+4. Add tests for the new language implementation in `spec/frontend/ide/lib/languages/{langaugeName}.js`.
- Example: See [`vue_spec.js`](spec/frontend/ide/lib/languages/vue_spec.js).
5. Create a [Merge Request](https://docs.gitlab.com/ee/user/project/merge_requests/creating_merge_requests.html) with your newly added language.
diff --git a/app/assets/javascripts/ide/lib/languages/hcl.js b/app/assets/javascripts/ide/lib/languages/hcl.js
new file mode 100644
index 00000000000..4539719b1f2
--- /dev/null
+++ b/app/assets/javascripts/ide/lib/languages/hcl.js
@@ -0,0 +1,192 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See https://github.com/microsoft/monaco-languages/blob/master/LICENSE.md
+ *--------------------------------------------------------------------------------------------*/
+
+/* eslint-disable no-useless-escape */
+/* eslint-disable @gitlab/require-i18n-strings */
+
+const conf = {
+ comments: {
+ lineComment: '//',
+ blockComment: ['/*', '*/'],
+ },
+ brackets: [['{', '}'], ['[', ']'], ['(', ')']],
+ autoClosingPairs: [
+ { open: '{', close: '}' },
+ { open: '[', close: ']' },
+ { open: '(', close: ')' },
+ { open: '"', close: '"', notIn: ['string'] },
+ ],
+ surroundingPairs: [
+ { open: '{', close: '}' },
+ { open: '[', close: ']' },
+ { open: '(', close: ')' },
+ { open: '"', close: '"' },
+ ],
+};
+
+const language = {
+ defaultToken: '',
+ tokenPostfix: '.hcl',
+
+ keywords: [
+ 'var',
+ 'local',
+ 'path',
+ 'for_each',
+ 'any',
+ 'string',
+ 'number',
+ 'bool',
+ 'true',
+ 'false',
+ 'null',
+ 'if ',
+ 'else ',
+ 'endif ',
+ 'for ',
+ 'in',
+ 'endfor',
+ ],
+
+ operators: [
+ '=',
+ '>=',
+ '<=',
+ '==',
+ '!=',
+ '+',
+ '-',
+ '*',
+ '/',
+ '%',
+ '&&',
+ '||',
+ '!',
+ '<',
+ '>',
+ '?',
+ '...',
+ ':',
+ ],
+
+ symbols: /[=><!~?:&|+\-*\/\^%]+/,
+ escapes: /\\(?:[abfnrtv\\"']|x[0-9A-Fa-f]{1,4}|u[0-9A-Fa-f]{4}|U[0-9A-Fa-f]{8})/,
+ terraformFunctions: /(abs|ceil|floor|log|max|min|pow|signum|chomp|format|formatlist|indent|join|lower|regex|regexall|replace|split|strrev|substr|title|trimspace|upper|chunklist|coalesce|coalescelist|compact|concat|contains|distinct|element|flatten|index|keys|length|list|lookup|map|matchkeys|merge|range|reverse|setintersection|setproduct|setunion|slice|sort|transpose|values|zipmap|base64decode|base64encode|base64gzip|csvdecode|jsondecode|jsonencode|urlencode|yamldecode|yamlencode|abspath|dirname|pathexpand|basename|file|fileexists|fileset|filebase64|templatefile|formatdate|timeadd|timestamp|base64sha256|base64sha512|bcrypt|filebase64sha256|filebase64sha512|filemd5|filemd1|filesha256|filesha512|md5|rsadecrypt|sha1|sha256|sha512|uuid|uuidv5|cidrhost|cidrnetmask|cidrsubnet|tobool|tolist|tomap|tonumber|toset|tostring)/,
+ terraformMainBlocks: /(module|data|terraform|resource|provider|variable|output|locals)/,
+ tokenizer: {
+ root: [
+ // highlight main blocks
+ [
+ /^@terraformMainBlocks([ \t]*)([\w-]+|"[\w-]+"|)([ \t]*)([\w-]+|"[\w-]+"|)([ \t]*)(\{)/,
+ ['type', '', 'string', '', 'string', '', '@brackets'],
+ ],
+ // highlight all the remaining blocks
+ [
+ /(\w+[ \t]+)([ \t]*)([\w-]+|"[\w-]+"|)([ \t]*)([\w-]+|"[\w-]+"|)([ \t]*)(\{)/,
+ ['identifier', '', 'string', '', 'string', '', '@brackets'],
+ ],
+ // highlight block
+ [
+ /(\w+[ \t]+)([ \t]*)([\w-]+|"[\w-]+"|)([ \t]*)([\w-]+|"[\w-]+"|)(=)(\{)/,
+ ['identifier', '', 'string', '', 'operator', '', '@brackets'],
+ ],
+ // terraform general highlight - shared with expressions
+ { include: '@terraform' },
+ ],
+ terraform: [
+ // highlight terraform functions
+ [/@terraformFunctions(\()/, ['type', '@brackets']],
+ // all other words are variables or keywords
+ [
+ /[a-zA-Z_]\w*-*/, // must work with variables such as foo-bar and also with negative numbers
+ {
+ cases: {
+ '@keywords': { token: 'keyword.$0' },
+ '@default': 'variable',
+ },
+ },
+ ],
+ { include: '@whitespace' },
+ { include: '@heredoc' },
+ // delimiters and operators
+ [/[{}()\[\]]/, '@brackets'],
+ [/[<>](?!@symbols)/, '@brackets'],
+ [
+ /@symbols/,
+ {
+ cases: {
+ '@operators': 'operator',
+ '@default': '',
+ },
+ },
+ ],
+ // numbers
+ [/\d*\d+[eE]([\-+]?\d+)?/, 'number.float'],
+ [/\d*\.\d+([eE][\-+]?\d+)?/, 'number.float'],
+ [/\d[\d']*/, 'number'],
+ [/\d/, 'number'],
+ [/[;,.]/, 'delimiter'], // delimiter: after number because of .\d floats
+ // strings
+ [/"/, 'string', '@string'], // this will include expressions
+ [/'/, 'invalid'],
+ ],
+ heredoc: [
+ [
+ /<<[-]*\s*["]?([\w\-]+)["]?/,
+ { token: 'string.heredoc.delimiter', next: '@heredocBody.$1' },
+ ],
+ ],
+ heredocBody: [
+ [
+ /^([\w\-]+)$/,
+ {
+ cases: {
+ '$1==$S2': [
+ {
+ token: 'string.heredoc.delimiter',
+ next: '@popall',
+ },
+ ],
+ '@default': 'string.heredoc',
+ },
+ },
+ ],
+ [/./, 'string.heredoc'],
+ ],
+ whitespace: [
+ [/[ \t\r\n]+/, ''],
+ [/\/\*/, 'comment', '@comment'],
+ [/\/\/.*$/, 'comment'],
+ [/#.*$/, 'comment'],
+ ],
+ comment: [[/[^\/*]+/, 'comment'], [/\*\//, 'comment', '@pop'], [/[\/*]/, 'comment']],
+ string: [
+ [/\$\{/, { token: 'delimiter', next: '@stringExpression' }],
+ [/[^\\"\$]+/, 'string'],
+ [/@escapes/, 'string.escape'],
+ [/\\./, 'string.escape.invalid'],
+ [/"/, 'string', '@popall'],
+ ],
+ stringInsideExpression: [
+ [/[^\\"]+/, 'string'],
+ [/@escapes/, 'string.escape'],
+ [/\\./, 'string.escape.invalid'],
+ [/"/, 'string', '@pop'],
+ ],
+ stringExpression: [
+ [/\}/, { token: 'delimiter', next: '@pop' }],
+ [/"/, 'string', '@stringInsideExpression'],
+ { include: '@terraform' },
+ ],
+ },
+};
+
+export default {
+ id: 'hcl',
+ extensions: ['.tf', '.tfvars', '.hcl'],
+ aliases: ['Terraform', 'tf', 'HCL', 'hcl'],
+ conf,
+ language,
+};
diff --git a/app/assets/javascripts/ide/lib/languages/index.js b/app/assets/javascripts/ide/lib/languages/index.js
index 0c85a1104fc..580ad820bf9 100644
--- a/app/assets/javascripts/ide/lib/languages/index.js
+++ b/app/assets/javascripts/ide/lib/languages/index.js
@@ -1,5 +1,6 @@
import vue from './vue';
+import hcl from './hcl';
-const languages = [vue];
+const languages = [vue, hcl];
export default languages;
diff --git a/app/assets/javascripts/ide/stores/actions/file.js b/app/assets/javascripts/ide/stores/actions/file.js
index 3515d1fc933..a0df85540f9 100644
--- a/app/assets/javascripts/ide/stores/actions/file.js
+++ b/app/assets/javascripts/ide/stores/actions/file.js
@@ -59,7 +59,7 @@ export const setFileActive = ({ commit, state, getters, dispatch }, path) => {
export const getFileData = (
{ state, commit, dispatch, getters },
- { path, makeFileActive = true, openFile = makeFileActive },
+ { path, makeFileActive = true, openFile = makeFileActive, toggleLoading = true },
) => {
const file = state.entries[path];
const fileDeletedAndReadded = getters.isFileDeletedAndReadded(path);
@@ -99,7 +99,7 @@ export const getFileData = (
});
})
.finally(() => {
- commit(types.TOGGLE_LOADING, { entry: file, forceValue: false });
+ if (toggleLoading) commit(types.TOGGLE_LOADING, { entry: file, forceValue: false });
});
};
diff --git a/app/assets/javascripts/ide/stores/getters.js b/app/assets/javascripts/ide/stores/getters.js
index b8304a9b68d..500ce9f32d5 100644
--- a/app/assets/javascripts/ide/stores/getters.js
+++ b/app/assets/javascripts/ide/stores/getters.js
@@ -6,6 +6,7 @@ import {
PERMISSION_CREATE_MR,
PERMISSION_PUSH_CODE,
} from '../constants';
+import { addNumericSuffix } from '~/ide/utils';
import Api from '~/api';
export const activeFile = state => state.openFiles.find(file => file.active) || null;
@@ -167,10 +168,7 @@ export const getAvailableFileName = (state, getters) => path => {
let newPath = path;
while (getters.entryExists(newPath)) {
- newPath = newPath.replace(
- /([ _-]?)(\d*)(\..+?$|$)/,
- (_, before, number, after) => `${before || '_'}${Number(number) + 1}${after}`,
- );
+ newPath = addNumericSuffix(newPath);
}
return newPath;
diff --git a/app/assets/javascripts/ide/stores/modules/commit/actions.js b/app/assets/javascripts/ide/stores/modules/commit/actions.js
index 90a6c644d17..e0d2028d2e1 100644
--- a/app/assets/javascripts/ide/stores/modules/commit/actions.js
+++ b/app/assets/javascripts/ide/stores/modules/commit/actions.js
@@ -8,6 +8,7 @@ import consts from './constants';
import { leftSidebarViews } from '../../../constants';
import eventHub from '../../../eventhub';
import { parseCommitError } from '../../../lib/errors';
+import { addNumericSuffix } from '~/ide/utils';
export const updateCommitMessage = ({ commit }, message) => {
commit(types.UPDATE_COMMIT_MESSAGE, message);
@@ -17,11 +18,8 @@ export const discardDraft = ({ commit }) => {
commit(types.UPDATE_COMMIT_MESSAGE, '');
};
-export const updateCommitAction = ({ commit, getters }, commitAction) => {
- commit(types.UPDATE_COMMIT_ACTION, {
- commitAction,
- });
- commit(types.TOGGLE_SHOULD_CREATE_MR, !getters.shouldHideNewMrOption);
+export const updateCommitAction = ({ commit }, commitAction) => {
+ commit(types.UPDATE_COMMIT_ACTION, { commitAction });
};
export const toggleShouldCreateMR = ({ commit }) => {
@@ -32,6 +30,12 @@ export const updateBranchName = ({ commit }, branchName) => {
commit(types.UPDATE_NEW_BRANCH_NAME, branchName);
};
+export const addSuffixToBranchName = ({ commit, state }) => {
+ const newBranchName = addNumericSuffix(state.newBranchName, true);
+
+ commit(types.UPDATE_NEW_BRANCH_NAME, newBranchName);
+};
+
export const setLastCommitMessage = ({ commit, rootGetters }, data) => {
const { currentProject } = rootGetters;
const commitStats = data.stats
@@ -107,7 +111,7 @@ export const updateFilesAfterCommit = ({ commit, dispatch, rootState, rootGetter
export const commitChanges = ({ commit, state, getters, dispatch, rootState, rootGetters }) => {
// Pull commit options out because they could change
// During some of the pre and post commit processing
- const { shouldCreateMR, isCreatingNewBranch, branchName } = getters;
+ const { shouldCreateMR, shouldHideNewMrOption, isCreatingNewBranch, branchName } = getters;
const newBranch = state.commitAction !== consts.COMMIT_TO_CURRENT_BRANCH;
const stageFilesPromise = rootState.stagedFiles.length
? Promise.resolve()
@@ -167,7 +171,7 @@ export const commitChanges = ({ commit, state, getters, dispatch, rootState, roo
commit(rootTypes.SET_LAST_COMMIT_MSG, '', { root: true });
}, 5000);
- if (shouldCreateMR) {
+ if (shouldCreateMR && !shouldHideNewMrOption) {
const { currentProject } = rootGetters;
const targetBranch = isCreatingNewBranch
? rootState.currentBranchId
diff --git a/app/assets/javascripts/ide/stores/modules/commit/mutations.js b/app/assets/javascripts/ide/stores/modules/commit/mutations.js
index 2cf6e8e6f36..c4bfad6405e 100644
--- a/app/assets/javascripts/ide/stores/modules/commit/mutations.js
+++ b/app/assets/javascripts/ide/stores/modules/commit/mutations.js
@@ -10,9 +10,7 @@ export default {
Object.assign(state, { commitAction });
},
[types.UPDATE_NEW_BRANCH_NAME](state, newBranchName) {
- Object.assign(state, {
- newBranchName,
- });
+ Object.assign(state, { newBranchName });
},
[types.UPDATE_LOADING](state, submitCommitLoading) {
Object.assign(state, {
diff --git a/app/assets/javascripts/ide/stores/mutations/file.js b/app/assets/javascripts/ide/stores/mutations/file.js
index c90bc2a3320..a981f86fa40 100644
--- a/app/assets/javascripts/ide/stores/mutations/file.js
+++ b/app/assets/javascripts/ide/stores/mutations/file.js
@@ -19,19 +19,20 @@ export default {
}
},
[types.TOGGLE_FILE_OPEN](state, path) {
- Object.assign(state.entries[path], {
- opened: !state.entries[path].opened,
- });
+ const entry = state.entries[path];
- if (state.entries[path].opened) {
+ entry.opened = !entry.opened;
+ if (entry.opened && !entry.tempFile) {
+ entry.loading = true;
+ }
+
+ if (entry.opened) {
Object.assign(state, {
openFiles: state.openFiles.filter(f => f.path !== path).concat(state.entries[path]),
});
} else {
- const file = state.entries[path];
-
Object.assign(state, {
- openFiles: state.openFiles.filter(f => f.key !== file.key),
+ openFiles: state.openFiles.filter(f => f.key !== entry.key),
});
}
},
diff --git a/app/assets/javascripts/ide/stores/utils.js b/app/assets/javascripts/ide/stores/utils.js
index d9cdc7727ad..b7ced3a271a 100644
--- a/app/assets/javascripts/ide/stores/utils.js
+++ b/app/assets/javascripts/ide/stores/utils.js
@@ -3,7 +3,7 @@ import {
relativePathToAbsolute,
isAbsolute,
isRootRelative,
- isBase64DataUrl,
+ isBlobUrl,
} from '~/lib/utils/url_utility';
export const dataStructure = () => ({
@@ -110,14 +110,19 @@ export const createCommitPayload = ({
}) => ({
branch,
commit_message: state.commitMessage || getters.preBuiltCommitMessage,
- actions: getCommitFiles(rootState.stagedFiles).map(f => ({
- action: commitActionForFile(f),
- file_path: f.path,
- previous_path: f.prevPath || undefined,
- content: f.prevPath && !f.changed ? null : f.content || undefined,
- encoding: isBase64DataUrl(f.rawPath) ? 'base64' : 'text',
- last_commit_id: newBranch || f.deleted || f.prevPath ? undefined : f.lastCommitSha,
- })),
+ actions: getCommitFiles(rootState.stagedFiles).map(f => {
+ const isBlob = isBlobUrl(f.rawPath);
+ const content = isBlob ? btoa(f.content) : f.content;
+
+ return {
+ action: commitActionForFile(f),
+ file_path: f.path,
+ previous_path: f.prevPath || undefined,
+ content: f.prevPath && !f.changed ? null : content || undefined,
+ encoding: isBlob ? 'base64' : 'text',
+ last_commit_id: newBranch || f.deleted || f.prevPath ? undefined : f.lastCommitSha,
+ };
+ }),
start_sha: newBranch ? rootGetters.lastCommit.id : undefined,
});
diff --git a/app/assets/javascripts/ide/utils.js b/app/assets/javascripts/ide/utils.js
index cde53e1ef00..4cf4f5e1d81 100644
--- a/app/assets/javascripts/ide/utils.js
+++ b/app/assets/javascripts/ide/utils.js
@@ -1,6 +1,7 @@
import { languages } from 'monaco-editor';
import { flatten, isString } from 'lodash';
import { SIDE_LEFT, SIDE_RIGHT } from './constants';
+import { performanceMarkAndMeasure } from '~/performance_utils';
const toLowerCase = x => x.toLowerCase();
@@ -42,16 +43,17 @@ const KNOWN_TYPES = [
},
];
-export function isTextFile({ name, content, mimeType = '' }) {
+export function isTextFile({ name, raw, content, mimeType = '' }) {
const knownType = KNOWN_TYPES.find(type => type.isMatch(mimeType, name));
-
if (knownType) return knownType.isText;
// does the string contain ascii characters only (ranges from space to tilde, tabs and new lines)
const asciiRegex = /^[ -~\t\n\r]+$/;
+ const fileContents = raw || content;
+
// for unknown types, determine the type by evaluating the file contents
- return isString(content) && (content === '' || asciiRegex.test(content));
+ return isString(fileContents) && (fileContents === '' || asciiRegex.test(fileContents));
}
export const createPathWithExt = p => {
@@ -137,3 +139,49 @@ export function readFileAsDataURL(file) {
export function getFileEOL(content = '') {
return content.includes('\r\n') ? 'CRLF' : 'LF';
}
+
+/**
+ * Adds or increments the numeric suffix to a filename/branch name.
+ * Retains underscore or dash before the numeric suffix if it already exists.
+ *
+ * Examples:
+ * hello -> hello-1
+ * hello-2425 -> hello-2425
+ * hello.md -> hello-1.md
+ * hello_2.md -> hello_3.md
+ * hello_ -> hello_1
+ * master-patch-22432 -> master-patch-22433
+ * patch_332 -> patch_333
+ *
+ * @param {string} filename File name or branch name
+ * @param {number} [randomize] Should randomize the numeric suffix instead of auto-incrementing?
+ */
+export function addNumericSuffix(filename, randomize = false) {
+ return filename.replace(/([ _-]?)(\d*)(\..+?$|$)/, (_, before, number, after) => {
+ const n = randomize
+ ? Math.random()
+ .toString()
+ .substring(2, 7)
+ .slice(-5)
+ : Number(number) + 1;
+ return `${before || '-'}${n}${after}`;
+ });
+}
+
+export const measurePerformance = (
+ mark,
+ measureName,
+ measureStart = undefined,
+ measureEnd = mark,
+) => {
+ performanceMarkAndMeasure({
+ mark,
+ measures: [
+ {
+ name: measureName,
+ start: measureStart,
+ end: measureEnd,
+ },
+ ],
+ });
+};
diff --git a/app/assets/javascripts/incidents/components/incidents_list.vue b/app/assets/javascripts/incidents/components/incidents_list.vue
index 670c42cbdac..e1f9d858f2b 100644
--- a/app/assets/javascripts/incidents/components/incidents_list.vue
+++ b/app/assets/javascripts/incidents/components/incidents_list.vue
@@ -2,95 +2,107 @@
import {
GlLoadingIcon,
GlTable,
- GlAlert,
GlAvatarsInline,
GlAvatarLink,
GlAvatar,
GlTooltipDirective,
GlButton,
- GlSearchBoxByType,
GlIcon,
- GlPagination,
- GlTabs,
- GlTab,
- GlBadge,
GlEmptyState,
} from '@gitlab/ui';
-import { debounce } from 'lodash';
+import Tracking from '~/tracking';
import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
+import PaginatedTableWithSearchAndTabs from '~/vue_shared/components/paginated_table_with_search_and_tabs/paginated_table_with_search_and_tabs.vue';
+import {
+ tdClass,
+ thClass,
+ bodyTrClass,
+ initialPaginationState,
+} from '~/vue_shared/components/paginated_table_with_search_and_tabs/constants';
import { convertToSnakeCase } from '~/lib/utils/text_utility';
import { s__ } from '~/locale';
-import { mergeUrlParams, joinPaths, visitUrl } from '~/lib/utils/url_utility';
+import { visitUrl, mergeUrlParams, joinPaths } from '~/lib/utils/url_utility';
import getIncidents from '../graphql/queries/get_incidents.query.graphql';
import getIncidentsCountByStatus from '../graphql/queries/get_count_by_status.query.graphql';
import SeverityToken from '~/sidebar/components/severity/severity.vue';
import { INCIDENT_SEVERITY } from '~/sidebar/components/severity/constants';
-import { I18N, DEFAULT_PAGE_SIZE, INCIDENT_SEARCH_DELAY, INCIDENT_STATUS_TABS } from '../constants';
-
-const TH_TEST_ID = { 'data-testid': 'incident-management-created-at-sort' };
-const tdClass =
- 'table-col gl-display-flex d-md-table-cell gl-align-items-center gl-white-space-nowrap';
-const thClass = 'gl-hover-bg-blue-50';
-const bodyTrClass =
- 'gl-border-1 gl-border-t-solid gl-border-gray-100 gl-hover-cursor-pointer gl-hover-bg-blue-50 gl-hover-border-b-solid gl-hover-border-blue-200';
-
-const initialPaginationState = {
- currentPage: 1,
- prevPageCursor: '',
- nextPageCursor: '',
- firstPageSize: DEFAULT_PAGE_SIZE,
- lastPageSize: null,
-};
+import {
+ I18N,
+ INCIDENT_STATUS_TABS,
+ TH_CREATED_AT_TEST_ID,
+ TH_INCIDENT_SLA_TEST_ID,
+ TH_SEVERITY_TEST_ID,
+ TH_PUBLISHED_TEST_ID,
+ INCIDENT_DETAILS_PATH,
+ trackIncidentCreateNewOptions,
+ trackIncidentListViewsOptions,
+} from '../constants';
export default {
+ trackIncidentCreateNewOptions,
+ trackIncidentListViewsOptions,
i18n: I18N,
statusTabs: INCIDENT_STATUS_TABS,
fields: [
{
key: 'severity',
label: s__('IncidentManagement|Severity'),
- thClass: `gl-pointer-events-none`,
- tdClass,
+ thClass: `${thClass} w-15p`,
+ tdClass: `${tdClass} sortable-cell`,
+ sortable: true,
+ thAttr: TH_SEVERITY_TEST_ID,
},
{
key: 'title',
label: s__('IncidentManagement|Incident'),
- thClass: `gl-pointer-events-none gl-w-half`,
+ thClass: `gl-pointer-events-none`,
tdClass,
},
{
key: 'createdAt',
label: s__('IncidentManagement|Date created'),
- thClass,
+ thClass: `${thClass} gl-w-eighth`,
tdClass: `${tdClass} sortable-cell`,
sortable: true,
- thAttr: TH_TEST_ID,
+ thAttr: TH_CREATED_AT_TEST_ID,
+ },
+ {
+ key: 'incidentSla',
+ label: s__('IncidentManagement|Time to SLA'),
+ thClass: `gl-pointer-events-none gl-text-right gl-w-eighth`,
+ tdClass: `${tdClass} gl-text-right`,
+ thAttr: TH_INCIDENT_SLA_TEST_ID,
},
{
key: 'assignees',
label: s__('IncidentManagement|Assignees'),
- thClass: 'gl-pointer-events-none',
+ thClass: 'gl-pointer-events-none w-15p',
tdClass,
},
+ {
+ key: 'published',
+ label: s__('IncidentManagement|Published'),
+ thClass: `${thClass} w-15p`,
+ tdClass: `${tdClass} sortable-cell`,
+ sortable: true,
+ thAttr: TH_PUBLISHED_TEST_ID,
+ },
],
components: {
GlLoadingIcon,
GlTable,
- GlAlert,
GlAvatarsInline,
GlAvatarLink,
GlAvatar,
GlButton,
TimeAgoTooltip,
- GlSearchBoxByType,
GlIcon,
- GlPagination,
- GlTabs,
- GlTab,
PublishedCell: () => import('ee_component/incidents/components/published_cell.vue'),
- GlBadge,
+ ServiceLevelAgreementCell: () =>
+ import('ee_component/incidents/components/service_level_agreement_cell.vue'),
GlEmptyState,
SeverityToken,
+ PaginatedTableWithSearchAndTabs,
},
directives: {
GlTooltip: GlTooltipDirective,
@@ -103,6 +115,10 @@ export default {
'issuePath',
'publishedAvailable',
'emptyListSvgPath',
+ 'textQuery',
+ 'authorUsernameQuery',
+ 'assigneeUsernameQuery',
+ 'slaFeatureAvailable',
],
apollo: {
incidents: {
@@ -110,8 +126,10 @@ export default {
variables() {
return {
searchTerm: this.searchTerm,
- status: this.statusFilter,
+ authorUsername: this.authorUsername,
+ assigneeUsername: this.assigneeUsername,
projectPath: this.projectPath,
+ status: this.statusFilter,
issueTypes: ['INCIDENT'],
sort: this.sort,
firstPageSize: this.pagination.firstPageSize,
@@ -135,6 +153,8 @@ export default {
variables() {
return {
searchTerm: this.searchTerm,
+ authorUsername: this.authorUsername,
+ assigneeUsername: this.assigneeUsername,
projectPath: this.projectPath,
issueTypes: ['INCIDENT'],
};
@@ -149,14 +169,17 @@ export default {
errored: false,
isErrorAlertDismissed: false,
redirecting: false,
- searchTerm: '',
- pagination: initialPaginationState,
incidents: {},
+ incidentsCount: {},
sort: 'created_desc',
sortBy: 'createdAt',
sortDesc: true,
statusFilter: '',
filteredByStatus: '',
+ searchTerm: this.textQuery,
+ authorUsername: this.authorUsernameQuery,
+ assigneeUsername: this.assigneeUsernameQuery,
+ pagination: initialPaginationState,
};
},
computed: {
@@ -166,29 +189,15 @@ export default {
loading() {
return this.$apollo.queries.incidents.loading;
},
- hasIncidents() {
- return this.incidents?.list?.length;
- },
- incidentsForCurrentTab() {
- return this.incidentsCount?.[this.filteredByStatus.toLowerCase()] ?? 0;
- },
- showPaginationControls() {
- return Boolean(
- this.incidents?.pageInfo?.hasNextPage || this.incidents?.pageInfo?.hasPreviousPage,
- );
- },
- prevPage() {
- return Math.max(this.pagination.currentPage - 1, 0);
+ isEmpty() {
+ return !this.incidents?.list?.length;
},
- nextPage() {
- const nextPage = this.pagination.currentPage + 1;
- return nextPage > Math.ceil(this.incidentsForCurrentTab / DEFAULT_PAGE_SIZE)
- ? null
- : nextPage;
+ showList() {
+ return !this.isEmpty || this.errored || this.loading;
},
tbodyTrClass() {
return {
- [bodyTrClass]: !this.loading && this.hasIncidents,
+ [bodyTrClass]: !this.loading && !this.isEmpty,
};
},
newIncidentPath() {
@@ -201,24 +210,12 @@ export default {
);
},
availableFields() {
- return this.publishedAvailable
- ? [
- ...this.$options.fields,
- ...[
- {
- key: 'published',
- label: s__('IncidentManagement|Published'),
- thClass: 'gl-pointer-events-none',
- },
- ],
- ]
- : this.$options.fields;
- },
- isEmpty() {
- return !this.incidents.list?.length;
- },
- showList() {
- return !this.isEmpty || this.errored || this.loading;
+ const isHidden = {
+ published: !this.publishedAvailable,
+ incidentSla: !this.slaFeatureAvailable,
+ };
+
+ return this.$options.fields.filter(({ key }) => !isHidden[key]);
},
activeClosedTabHasNoIncidents() {
const { all, closed } = this.incidentsCount || {};
@@ -244,205 +241,181 @@ export default {
},
},
methods: {
- onInputChange: debounce(function debounceSearch(input) {
- const trimmedInput = input.trim();
- if (trimmedInput !== this.searchTerm) {
- this.searchTerm = trimmedInput;
- }
- }, INCIDENT_SEARCH_DELAY),
- filterIncidentsByStatus(tabIndex) {
- const { filters, status } = this.$options.statusTabs[tabIndex];
- this.statusFilter = filters;
- this.filteredByStatus = status;
- },
hasAssignees(assignees) {
return Boolean(assignees.nodes?.length);
},
navigateToIncidentDetails({ iid }) {
- return visitUrl(joinPaths(this.issuePath, iid));
+ return visitUrl(joinPaths(this.issuePath, INCIDENT_DETAILS_PATH, iid));
},
- handlePageChange(page) {
- const { startCursor, endCursor } = this.incidents.pageInfo;
-
- if (page > this.pagination.currentPage) {
- this.pagination = {
- ...initialPaginationState,
- nextPageCursor: endCursor,
- currentPage: page,
- };
- } else {
- this.pagination = {
- lastPageSize: DEFAULT_PAGE_SIZE,
- firstPageSize: null,
- prevPageCursor: startCursor,
- nextPageCursor: '',
- currentPage: page,
- };
- }
- },
- resetPagination() {
- this.pagination = initialPaginationState;
+ navigateToCreateNewIncident() {
+ const { category, action } = this.$options.trackIncidentCreateNewOptions;
+ Tracking.event(category, action);
+ this.redirecting = true;
},
fetchSortedData({ sortBy, sortDesc }) {
- const sortingDirection = sortDesc ? 'desc' : 'asc';
- const sortingColumn = convertToSnakeCase(sortBy).replace(/_.*/, '');
+ const sortingDirection = sortDesc ? 'DESC' : 'ASC';
+ const sortingColumn = convertToSnakeCase(sortBy)
+ .replace(/_.*/, '')
+ .toUpperCase();
+ this.pagination = initialPaginationState;
this.sort = `${sortingColumn}_${sortingDirection}`;
},
getSeverity(severity) {
return INCIDENT_SEVERITY[severity];
},
+ pageChanged(pagination) {
+ this.pagination = pagination;
+ },
+ statusChanged({ filters, status }) {
+ this.statusFilter = filters;
+ this.filteredByStatus = status;
+ },
+ filtersChanged({ searchTerm, authorUsername, assigneeUsername }) {
+ this.searchTerm = searchTerm;
+ this.authorUsername = authorUsername;
+ this.assigneeUsername = assigneeUsername;
+ },
+ errorAlertDismissed() {
+ this.isErrorAlertDismissed = true;
+ },
},
};
</script>
<template>
- <div class="incident-management-list">
- <gl-alert v-if="showErrorMsg" variant="danger" @dismiss="isErrorAlertDismissed = true">
- {{ $options.i18n.errorMsg }}
- </gl-alert>
-
- <div
- class="incident-management-list-header gl-display-flex gl-justify-content-space-between gl-border-b-solid gl-border-b-1 gl-border-gray-100"
- >
- <gl-tabs content-class="gl-p-0" @input="filterIncidentsByStatus">
- <gl-tab v-for="tab in $options.statusTabs" :key="tab.status" :data-testid="tab.status">
- <template #title>
- <span>{{ tab.title }}</span>
- <gl-badge v-if="incidentsCount" pill size="sm" class="gl-tab-counter-badge">
- {{ incidentsCount[tab.status.toLowerCase()] }}
- </gl-badge>
- </template>
- </gl-tab>
- </gl-tabs>
-
- <gl-button
- v-if="!isEmpty || activeClosedTabHasNoIncidents"
- class="gl-my-3 gl-mr-5 create-incident-button"
- data-testid="createIncidentBtn"
- data-qa-selector="create_incident_button"
- :loading="redirecting"
- :disabled="redirecting"
- category="primary"
- variant="success"
- :href="newIncidentPath"
- @click="redirecting = true"
- >
- {{ $options.i18n.createIncidentBtnLabel }}
- </gl-button>
- </div>
-
- <div class="gl-bg-gray-10 gl-p-5 gl-border-b-solid gl-border-b-1 gl-border-gray-100">
- <gl-search-box-by-type
- :value="searchTerm"
- class="gl-bg-white"
- :placeholder="$options.i18n.searchPlaceholder"
- @input="onInputChange"
- />
- </div>
-
- <h4 class="gl-display-block d-md-none my-3">
- {{ s__('IncidentManagement|Incidents') }}
- </h4>
- <gl-table
- v-if="showList"
+ <div>
+ <paginated-table-with-search-and-tabs
+ :show-items="showList"
+ :show-error-msg="showErrorMsg"
+ :i18n="$options.i18n"
:items="incidents.list || []"
- :fields="availableFields"
- :show-empty="true"
- :busy="loading"
- stacked="md"
- :tbody-tr-class="tbodyTrClass"
- :no-local-sorting="true"
- :sort-direction="'desc'"
- :sort-desc.sync="sortDesc"
- :sort-by.sync="sortBy"
- sort-icon-left
- fixed
- @row-clicked="navigateToIncidentDetails"
- @sort-changed="fetchSortedData"
+ :page-info="incidents.pageInfo"
+ :items-count="incidentsCount"
+ :status-tabs="$options.statusTabs"
+ :track-views-options="$options.trackIncidentListViewsOptions"
+ filter-search-key="incidents"
+ @page-changed="pageChanged"
+ @tabs-changed="statusChanged"
+ @filters-changed="filtersChanged"
+ @error-alert-dismissed="errorAlertDismissed"
>
- <template #cell(severity)="{ item }">
- <severity-token :severity="getSeverity(item.severity)" />
+ <template #header-actions>
+ <gl-button
+ v-if="!isEmpty || activeClosedTabHasNoIncidents"
+ class="gl-my-3 gl-mr-5 create-incident-button"
+ data-testid="createIncidentBtn"
+ data-qa-selector="create_incident_button"
+ :loading="redirecting"
+ :disabled="redirecting"
+ category="primary"
+ variant="success"
+ :href="newIncidentPath"
+ @click="navigateToCreateNewIncident"
+ >
+ {{ $options.i18n.createIncidentBtnLabel }}
+ </gl-button>
</template>
- <template #cell(title)="{ item }">
- <div :class="{ 'gl-display-flex gl-align-items-center': item.state === 'closed' }">
- <div class="gl-max-w-full text-truncate" :title="item.title">{{ item.title }}</div>
- <gl-icon
- v-if="item.state === 'closed'"
- name="issue-close"
- class="gl-mx-1 gl-fill-blue-500 gl-flex-shrink-0"
- :size="16"
- data-testid="incident-closed"
- />
- </div>
+ <template #title>
+ {{ s__('IncidentManagement|Incidents') }}
</template>
- <template #cell(createdAt)="{ item }">
- <time-ago-tooltip :time="item.createdAt" />
- </template>
+ <template #table>
+ <gl-table
+ :items="incidents.list || []"
+ :fields="availableFields"
+ :show-empty="true"
+ :busy="loading"
+ stacked="md"
+ :tbody-tr-class="tbodyTrClass"
+ :no-local-sorting="true"
+ :sort-direction="'desc'"
+ :sort-desc.sync="sortDesc"
+ :sort-by.sync="sortBy"
+ sort-icon-left
+ fixed
+ @row-clicked="navigateToIncidentDetails"
+ @sort-changed="fetchSortedData"
+ >
+ <template #cell(severity)="{ item }">
+ <severity-token :severity="getSeverity(item.severity)" />
+ </template>
+
+ <template #cell(title)="{ item }">
+ <div :class="{ 'gl-display-flex gl-align-items-center': item.state === 'closed' }">
+ <div class="gl-max-w-full text-truncate" :title="item.title">{{ item.title }}</div>
+ <gl-icon
+ v-if="item.state === 'closed'"
+ name="issue-close"
+ class="gl-mx-1 gl-fill-blue-500 gl-flex-shrink-0"
+ :size="16"
+ data-testid="incident-closed"
+ />
+ </div>
+ </template>
+
+ <template #cell(createdAt)="{ item }">
+ <time-ago-tooltip :time="item.createdAt" />
+ </template>
+
+ <template v-if="slaFeatureAvailable" #cell(incidentSla)="{ item }">
+ <service-level-agreement-cell :sla-due-at="item.slaDueAt" data-testid="incident-sla" />
+ </template>
- <template #cell(assignees)="{ item }">
- <div data-testid="incident-assignees">
- <template v-if="hasAssignees(item.assignees)">
- <gl-avatars-inline
- :avatars="item.assignees.nodes"
- :collapsed="true"
- :max-visible="4"
- :avatar-size="24"
- badge-tooltip-prop="name"
- :badge-tooltip-max-chars="100"
- >
- <template #avatar="{ avatar }">
- <gl-avatar-link
- :key="avatar.username"
- v-gl-tooltip
- target="_blank"
- :href="avatar.webUrl"
- :title="avatar.name"
+ <template #cell(assignees)="{ item }">
+ <div data-testid="incident-assignees">
+ <template v-if="hasAssignees(item.assignees)">
+ <gl-avatars-inline
+ :avatars="item.assignees.nodes"
+ :collapsed="true"
+ :max-visible="4"
+ :avatar-size="24"
+ badge-tooltip-prop="name"
+ :badge-tooltip-max-chars="100"
>
- <gl-avatar :src="avatar.avatarUrl" :label="avatar.name" :size="24" />
- </gl-avatar-link>
+ <template #avatar="{ avatar }">
+ <gl-avatar-link
+ :key="avatar.username"
+ v-gl-tooltip
+ target="_blank"
+ :href="avatar.webUrl"
+ :title="avatar.name"
+ >
+ <gl-avatar :src="avatar.avatarUrl" :label="avatar.name" :size="24" />
+ </gl-avatar-link>
+ </template>
+ </gl-avatars-inline>
</template>
- </gl-avatars-inline>
+ <template v-else>
+ {{ $options.i18n.unassigned }}
+ </template>
+ </div>
</template>
- <template v-else>
- {{ $options.i18n.unassigned }}
+
+ <template v-if="publishedAvailable" #cell(published)="{ item }">
+ <published-cell
+ :status-page-published-incident="item.statusPagePublishedIncident"
+ :un-published="$options.i18n.unPublished"
+ />
+ </template>
+ <template #table-busy>
+ <gl-loading-icon size="lg" color="dark" class="mt-3" />
</template>
- </div>
- </template>
- <template v-if="publishedAvailable" #cell(published)="{ item }">
- <published-cell
- :status-page-published-incident="item.statusPagePublishedIncident"
- :un-published="$options.i18n.unPublished"
- />
- </template>
- <template #table-busy>
- <gl-loading-icon size="lg" color="dark" class="mt-3" />
+ <template v-if="errored" #empty>
+ {{ $options.i18n.noIncidents }}
+ </template>
+ </gl-table>
</template>
-
- <template v-if="errored" #empty>
- {{ $options.i18n.noIncidents }}
+ <template #emtpy-state>
+ <gl-empty-state
+ :title="emptyStateData.title"
+ :svg-path="emptyListSvgPath"
+ :description="emptyStateData.description"
+ :primary-button-link="emptyStateData.btnLink"
+ :primary-button-text="emptyStateData.btnText"
+ />
</template>
- </gl-table>
-
- <gl-empty-state
- v-else
- :title="emptyStateData.title"
- :svg-path="emptyListSvgPath"
- :description="emptyStateData.description"
- :primary-button-link="emptyStateData.btnLink"
- :primary-button-text="emptyStateData.btnText"
- />
-
- <gl-pagination
- v-if="showPaginationControls"
- :value="pagination.currentPage"
- :prev-page="prevPage"
- :next-page="nextPage"
- align="center"
- class="gl-pagination gl-mt-3"
- @input="handlePageChange"
- />
+ </paginated-table-with-search-and-tabs>
</div>
</template>
diff --git a/app/assets/javascripts/incidents/constants.js b/app/assets/javascripts/incidents/constants.js
index 289b36d9848..b82980b5628 100644
--- a/app/assets/javascripts/incidents/constants.js
+++ b/app/assets/javascripts/incidents/constants.js
@@ -1,4 +1,5 @@
-import { s__, __ } from '~/locale';
+/* eslint-disable @gitlab/require-i18n-strings */
+import { s__ } from '~/locale';
export const I18N = {
errorMsg: s__('IncidentManagement|There was an error displaying the incidents.'),
@@ -6,7 +7,6 @@ export const I18N = {
unassigned: s__('IncidentManagement|Unassigned'),
createIncidentBtnLabel: s__('IncidentManagement|Create incident'),
unPublished: s__('IncidentManagement|Unpublished'),
- searchPlaceholder: __('Search results…'),
emptyState: {
title: s__('IncidentManagement|Display your incidents in a dedicated view'),
emptyClosedTabTitle: s__('IncidentManagement|There are no closed incidents'),
@@ -34,5 +34,33 @@ export const INCIDENT_STATUS_TABS = [
},
];
-export const INCIDENT_SEARCH_DELAY = 300;
export const DEFAULT_PAGE_SIZE = 20;
+export const TH_CREATED_AT_TEST_ID = { 'data-testid': 'incident-management-created-at-sort' };
+export const TH_SEVERITY_TEST_ID = { 'data-testid': 'incident-management-severity-sort' };
+export const TH_INCIDENT_SLA_TEST_ID = { 'data-testid': 'incident-management-sla' };
+export const TH_PUBLISHED_TEST_ID = { 'data-testid': 'incident-management-published-sort' };
+export const INCIDENT_DETAILS_PATH = 'incident';
+
+/**
+ * Tracks snowplow event when user clicks create new incident
+ */
+export const trackIncidentCreateNewOptions = {
+ category: 'Incident Management',
+ action: 'create_incident_button_clicks',
+};
+
+/**
+ * Tracks snowplow event when user views incidents list
+ */
+export const trackIncidentListViewsOptions = {
+ category: 'Incident Management',
+ action: 'view_incidents_list',
+};
+
+/**
+ * Tracks snowplow event when user views incident details
+ */
+export const trackIncidentDetailsViewsOptions = {
+ category: 'Incident Management',
+ action: 'view_incident_details',
+};
diff --git a/app/assets/javascripts/incidents/graphql/queries/get_count_by_status.query.graphql b/app/assets/javascripts/incidents/graphql/queries/get_count_by_status.query.graphql
index 0b784b104a8..4e44a506c4f 100644
--- a/app/assets/javascripts/incidents/graphql/queries/get_count_by_status.query.graphql
+++ b/app/assets/javascripts/incidents/graphql/queries/get_count_by_status.query.graphql
@@ -1,6 +1,17 @@
-query getIncidentsCountByStatus($searchTerm: String, $projectPath: ID!, $issueTypes: [IssueType!]) {
+query getIncidentsCountByStatus(
+ $searchTerm: String
+ $projectPath: ID!
+ $issueTypes: [IssueType!]
+ $authorUsername: String = ""
+ $assigneeUsername: String = ""
+) {
project(fullPath: $projectPath) {
- issueStatusCounts(search: $searchTerm, types: $issueTypes) {
+ issueStatusCounts(
+ search: $searchTerm
+ types: $issueTypes
+ authorUsername: $authorUsername
+ assigneeUsername: $assigneeUsername
+ ) {
all
opened
closed
diff --git a/app/assets/javascripts/incidents/graphql/queries/get_incidents.query.graphql b/app/assets/javascripts/incidents/graphql/queries/get_incidents.query.graphql
index dab130835e2..f97664a3b77 100644
--- a/app/assets/javascripts/incidents/graphql/queries/get_incidents.query.graphql
+++ b/app/assets/javascripts/incidents/graphql/queries/get_incidents.query.graphql
@@ -9,7 +9,9 @@ query getIncidents(
$lastPageSize: Int
$prevPageCursor: String = ""
$nextPageCursor: String = ""
- $searchTerm: String
+ $searchTerm: String = ""
+ $authorUsername: String = ""
+ $assigneeUsername: String = ""
) {
project(fullPath: $projectPath) {
issues(
@@ -17,6 +19,8 @@ query getIncidents(
types: $issueTypes
sort: $sort
state: $status
+ authorUsername: $authorUsername
+ assigneeUsername: $assigneeUsername
first: $firstPageSize
last: $lastPageSize
after: $nextPageCursor
diff --git a/app/assets/javascripts/incidents/list.js b/app/assets/javascripts/incidents/list.js
index 7505d07449c..6f87fbbe775 100644
--- a/app/assets/javascripts/incidents/list.js
+++ b/app/assets/javascripts/incidents/list.js
@@ -1,6 +1,7 @@
import Vue from 'vue';
import VueApollo from 'vue-apollo';
import createDefaultClient from '~/lib/graphql';
+import { parseBoolean } from '~/lib/utils/common_utils';
import IncidentsList from './components/incidents_list.vue';
Vue.use(VueApollo);
@@ -16,6 +17,10 @@ export default () => {
issuePath,
publishedAvailable,
emptyListSvgPath,
+ textQuery,
+ authorUsernameQuery,
+ assigneeUsernameQuery,
+ slaFeatureAvailable,
} = domEl.dataset;
const apolloProvider = new VueApollo({
@@ -30,8 +35,12 @@ export default () => {
incidentType,
newIssuePath,
issuePath,
- publishedAvailable,
+ publishedAvailable: parseBoolean(publishedAvailable),
emptyListSvgPath,
+ textQuery,
+ authorUsernameQuery,
+ assigneeUsernameQuery,
+ slaFeatureAvailable: parseBoolean(slaFeatureAvailable),
},
apolloProvider,
components: {
diff --git a/app/assets/javascripts/incidents_settings/components/alerts_form.vue b/app/assets/javascripts/incidents_settings/components/alerts_form.vue
index 17a77f650e0..5fe0badc56e 100644
--- a/app/assets/javascripts/incidents_settings/components/alerts_form.vue
+++ b/app/assets/javascripts/incidents_settings/components/alerts_form.vue
@@ -130,18 +130,16 @@ export default {
<span>{{ $options.i18n.autoCloseIncidents.label }}</span>
</gl-form-checkbox>
</gl-form-group>
- <div class="gl-display-flex gl-justify-content-end">
- <gl-button
- ref="submitBtn"
- data-qa-selector="save_changes_button"
- :disabled="loading"
- variant="success"
- type="submit"
- class="js-no-auto-disable"
- >
- {{ $options.i18n.saveBtnLabel }}
- </gl-button>
- </div>
+ <gl-button
+ ref="submitBtn"
+ data-qa-selector="save_changes_button"
+ :disabled="loading"
+ variant="success"
+ type="submit"
+ class="js-no-auto-disable"
+ >
+ {{ $options.i18n.saveBtnLabel }}
+ </gl-button>
</form>
</div>
</template>
diff --git a/app/assets/javascripts/incidents_settings/components/incidents_settings_tabs.vue b/app/assets/javascripts/incidents_settings/components/incidents_settings_tabs.vue
index d6e963c6f4f..c90ff8079b8 100644
--- a/app/assets/javascripts/incidents_settings/components/incidents_settings_tabs.vue
+++ b/app/assets/javascripts/incidents_settings/components/incidents_settings_tabs.vue
@@ -11,6 +11,8 @@ export default {
GlTab,
AlertsSettingsForm,
PagerDutySettingsForm,
+ ServiceLevelAgreementForm: () =>
+ import('ee_component/incidents_settings/components/service_level_agreement_form.vue'),
},
tabs: INTEGRATION_TABS_CONFIG,
i18n: I18N_INTEGRATION_TABS,
@@ -45,6 +47,7 @@ export default {
>
<component :is="tab.component" class="gl-pt-3" :data-testid="`${tab.component}-tab`" />
</gl-tab>
+ <service-level-agreement-form />
</gl-tabs>
</div>
</section>
diff --git a/app/assets/javascripts/incidents_settings/components/pagerduty_form.vue b/app/assets/javascripts/incidents_settings/components/pagerduty_form.vue
index 8b608d9f391..9a8c4bc5af9 100644
--- a/app/assets/javascripts/incidents_settings/components/pagerduty_form.vue
+++ b/app/assets/javascripts/incidents_settings/components/pagerduty_form.vue
@@ -124,7 +124,6 @@ export default {
class="col-8 col-md-9 gl-p-0"
:label="$options.i18n.webhookUrl.label"
label-for="url"
- label-class="label-bold"
>
<gl-form-input-group id="url" data-testid="webhook-url" readonly :value="webhookUrl">
<template #append>
@@ -149,17 +148,15 @@ export default {
</template>
</gl-sprintf>
</div>
- <div class="gl-display-flex gl-justify-content-end">
- <gl-button
- v-gl-modal.resetWebhookModal
- class="gl-mt-3"
- :disabled="loading"
- :loading="resettingWebhook"
- data-testid="webhook-reset-btn"
- >
- {{ $options.i18n.webhookUrl.resetWebhookUrl }}
- </gl-button>
- </div>
+ <gl-button
+ v-gl-modal.resetWebhookModal
+ class="gl-mt-3"
+ :disabled="loading"
+ :loading="resettingWebhook"
+ data-testid="webhook-reset-btn"
+ >
+ {{ $options.i18n.webhookUrl.resetWebhookUrl }}
+ </gl-button>
<gl-modal
modal-id="resetWebhookModal"
:title="$options.i18n.webhookUrl.resetWebhookUrl"
@@ -170,17 +167,15 @@ export default {
{{ $options.i18n.webhookUrl.restKeyInfo }}
</gl-modal>
</gl-form-group>
- <div class="gl-display-flex gl-justify-content-end">
- <gl-button
- ref="submitBtn"
- :disabled="isSaveDisabled"
- variant="success"
- type="submit"
- class="js-no-auto-disable"
- >
- {{ $options.i18n.saveBtnLabel }}
- </gl-button>
- </div>
+ <gl-button
+ ref="submitBtn"
+ :disabled="isSaveDisabled"
+ variant="success"
+ type="submit"
+ class="js-no-auto-disable"
+ >
+ {{ $options.i18n.saveBtnLabel }}
+ </gl-button>
</form>
</div>
</template>
diff --git a/app/assets/javascripts/incidents_settings/index.js b/app/assets/javascripts/incidents_settings/index.js
index ad875d49768..e9ba4294519 100644
--- a/app/assets/javascripts/incidents_settings/index.js
+++ b/app/assets/javascripts/incidents_settings/index.js
@@ -21,6 +21,9 @@ export default () => {
pagerdutyWebhookUrl,
pagerdutyResetKeyPath,
autoCloseIncident,
+ slaActive,
+ slaMinutes,
+ slaFeatureAvailable,
},
} = el;
@@ -40,6 +43,11 @@ export default () => {
active: parseBoolean(pagerdutyActive),
webhookUrl: pagerdutyWebhookUrl,
},
+ serviceLevelAgreementSettings: {
+ active: parseBoolean(slaActive),
+ minutes: slaMinutes,
+ available: parseBoolean(slaFeatureAvailable),
+ },
},
render(createElement) {
return createElement(SettingsTabs);
diff --git a/app/assets/javascripts/init_issuable_sidebar.js b/app/assets/javascripts/init_issuable_sidebar.js
index 528d5d8072f..1e82ecb05b5 100644
--- a/app/assets/javascripts/init_issuable_sidebar.js
+++ b/app/assets/javascripts/init_issuable_sidebar.js
@@ -5,10 +5,14 @@ import LabelsSelect from './labels_select';
import IssuableContext from './issuable_context';
import Sidebar from './right_sidebar';
import DueDateSelectors from './due_date_select';
-import { mountSidebarLabels } from '~/sidebar/mount_sidebar';
+import { mountSidebarLabels, getSidebarOptions } from '~/sidebar/mount_sidebar';
export default () => {
- const sidebarOptions = JSON.parse(document.querySelector('.js-sidebar-options').innerHTML);
+ const sidebarOptEl = document.querySelector('.js-sidebar-options');
+
+ if (!sidebarOptEl) return;
+
+ const sidebarOptions = getSidebarOptions(sidebarOptEl);
new MilestoneSelect({
full_path: sidebarOptions.fullPath,
diff --git a/app/assets/javascripts/integrations/edit/components/confirmation_modal.vue b/app/assets/javascripts/integrations/edit/components/confirmation_modal.vue
new file mode 100644
index 00000000000..890381a8f29
--- /dev/null
+++ b/app/assets/javascripts/integrations/edit/components/confirmation_modal.vue
@@ -0,0 +1,60 @@
+<script>
+import { mapGetters } from 'vuex';
+import { GlModal } from '@gitlab/ui';
+import { __ } from '~/locale';
+
+export default {
+ components: {
+ GlModal,
+ },
+ computed: {
+ ...mapGetters(['isSavingOrTesting']),
+ primaryProps() {
+ return {
+ text: __('Save'),
+ attributes: [
+ { variant: 'success' },
+ { category: 'primary' },
+ { disabled: this.isSavingOrTesting },
+ ],
+ };
+ },
+ cancelProps() {
+ return {
+ text: __('Cancel'),
+ };
+ },
+ },
+ methods: {
+ onSubmit() {
+ this.$emit('submit');
+ },
+ },
+};
+</script>
+
+<template>
+ <gl-modal
+ modal-id="confirmSaveIntegration"
+ size="sm"
+ :title="s__('Integrations|Save settings?')"
+ :action-primary="primaryProps"
+ :action-cancel="cancelProps"
+ @primary="onSubmit"
+ >
+ <p>
+ {{
+ s__(
+ 'Integrations|Saving will update the default settings for all projects that are not using custom settings.',
+ )
+ }}
+ </p>
+ <p class="gl-mb-0">
+ {{
+ s__(
+ 'Integrations|Projects using custom settings will not be impacted unless the project owner chooses to use instance-level defaults.',
+ )
+ }}
+ </p>
+ </gl-modal>
+</template>
diff --git a/app/assets/javascripts/integrations/edit/components/integration_form.vue b/app/assets/javascripts/integrations/edit/components/integration_form.vue
index 0460ed6791e..0fd39c5635d 100644
--- a/app/assets/javascripts/integrations/edit/components/integration_form.vue
+++ b/app/assets/javascripts/integrations/edit/components/integration_form.vue
@@ -1,8 +1,9 @@
<script>
import { mapState, mapActions, mapGetters } from 'vuex';
-import { GlButton } from '@gitlab/ui';
+import { GlButton, GlModalDirective } from '@gitlab/ui';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import eventHub from '../event_hub';
+import { integrationLevels } from '../constants';
import OverrideDropdown from './override_dropdown.vue';
import ActiveCheckbox from './active_checkbox.vue';
@@ -10,6 +11,7 @@ import JiraTriggerFields from './jira_trigger_fields.vue';
import JiraIssuesFields from './jira_issues_fields.vue';
import TriggerFields from './trigger_fields.vue';
import DynamicField from './dynamic_field.vue';
+import ConfirmationModal from './confirmation_modal.vue';
export default {
name: 'IntegrationForm',
@@ -20,8 +22,12 @@ export default {
JiraIssuesFields,
TriggerFields,
DynamicField,
+ ConfirmationModal,
GlButton,
},
+ directives: {
+ 'gl-modal': GlModalDirective,
+ },
mixins: [glFeatureFlagsMixin()],
computed: {
...mapGetters(['currentKey', 'propsSource', 'isSavingOrTesting']),
@@ -32,6 +38,9 @@ export default {
isJira() {
return this.propsSource.type === 'jira';
},
+ isInstanceLevel() {
+ return this.propsSource.integrationLevel === integrationLevels.INSTANCE;
+ },
showJiraIssuesFields() {
return this.isJira && this.glFeatures.jiraIssuesIntegration;
},
@@ -82,7 +91,21 @@ export default {
v-bind="propsSource.jiraIssuesProps"
/>
<div v-if="isEditable" class="footer-block row-content-block">
+ <template v-if="isInstanceLevel">
+ <gl-button
+ v-gl-modal.confirmSaveIntegration
+ category="primary"
+ variant="success"
+ :loading="isSaving"
+ :disabled="isSavingOrTesting"
+ data-qa-selector="save_changes_button"
+ >
+ {{ __('Save changes') }}
+ </gl-button>
+ <confirmation-modal @submit="onSaveClick" />
+ </template>
<gl-button
+ v-else
category="primary"
variant="success"
type="submit"
@@ -93,6 +116,7 @@ export default {
>
{{ __('Save changes') }}
</gl-button>
+
<gl-button
v-if="propsSource.canTest"
:loading="isTesting"
diff --git a/app/assets/javascripts/invite_member/components/invite_member_modal.vue b/app/assets/javascripts/invite_member/components/invite_member_modal.vue
new file mode 100644
index 00000000000..3df99bccdb0
--- /dev/null
+++ b/app/assets/javascripts/invite_member/components/invite_member_modal.vue
@@ -0,0 +1,64 @@
+<script>
+import { GlModal, GlLink } from '@gitlab/ui';
+import eventHub from '../event_hub';
+import { s__, __ } from '~/locale';
+import { OPEN_MODAL, MODAL_ID } from '../constants';
+
+export default {
+ cancelProps: {
+ text: __('Got it'),
+ attributes: [
+ {
+ variant: 'info',
+ },
+ ],
+ },
+ modalId: MODAL_ID,
+ components: {
+ GlLink,
+ GlModal,
+ },
+ inject: {
+ membersPath: {
+ default: '',
+ },
+ },
+ i18n: {
+ modalTitle: s__("InviteMember|Oops, this feature isn't ready yet"),
+ bodyTopMessage: s__(
+ "InviteMember|We're working to allow everyone to invite new members, making it easier for teams to get started with GitLab",
+ ),
+ bodyMiddleMessage: s__(
+ 'InviteMember|Until then, ask an owner to invite new project members for you',
+ ),
+ linkText: s__('InviteMember|See who can invite members for you'),
+ },
+ mounted() {
+ eventHub.$on(OPEN_MODAL, this.openModal);
+ },
+ methods: {
+ openModal() {
+ this.$root.$emit('bv::show::modal', MODAL_ID);
+ },
+ },
+};
+</script>
+<template>
+ <gl-modal :modal-id="$options.modalId" size="sm" :action-cancel="$options.cancelProps">
+ <template #modal-title>
+ {{ $options.i18n.modalTitle }}
+ <gl-emoji
+ class="gl-vertical-align-baseline font-size-inherit gl-mr-1"
+ data-name="sweat_smile"
+ />
+ </template>
+ <p>{{ $options.i18n.bodyTopMessage }}</p>
+ <p>{{ $options.i18n.bodyMiddleMessage }}</p>
+ <gl-link
+ :href="membersPath"
+ data-track-event="click_who_can_invite_link"
+ data-track-label="invite_members_message"
+ >{{ $options.i18n.linkText }}</gl-link
+ >
+ </gl-modal>
+</template>
diff --git a/app/assets/javascripts/invite_member/components/invite_member_trigger.vue b/app/assets/javascripts/invite_member/components/invite_member_trigger.vue
new file mode 100644
index 00000000000..6e886e0e002
--- /dev/null
+++ b/app/assets/javascripts/invite_member/components/invite_member_trigger.vue
@@ -0,0 +1,37 @@
+<script>
+import { GlLink } from '@gitlab/ui';
+import eventHub from '../event_hub';
+import { OPEN_MODAL } from '../constants';
+
+export default {
+ components: {
+ GlLink,
+ },
+ inject: {
+ displayText: {
+ default: '',
+ },
+ event: {
+ default: '',
+ },
+ label: {
+ default: '',
+ },
+ },
+ methods: {
+ openModal() {
+ eventHub.$emit(OPEN_MODAL);
+ },
+ },
+};
+</script>
+
+<template>
+ <gl-link
+ data-is-link="true"
+ :data-track-event="event"
+ :data-track-label="label"
+ @click="openModal"
+ >{{ displayText }}
+ </gl-link>
+</template>
diff --git a/app/assets/javascripts/invite_member/constants.js b/app/assets/javascripts/invite_member/constants.js
new file mode 100644
index 00000000000..fee6e7a260a
--- /dev/null
+++ b/app/assets/javascripts/invite_member/constants.js
@@ -0,0 +1,2 @@
+export const OPEN_MODAL = 'openModal';
+export const MODAL_ID = 'invite-member-modal';
diff --git a/app/assets/javascripts/invite_member/event_hub.js b/app/assets/javascripts/invite_member/event_hub.js
new file mode 100644
index 00000000000..e31806ad199
--- /dev/null
+++ b/app/assets/javascripts/invite_member/event_hub.js
@@ -0,0 +1,3 @@
+import createEventHub from '~/helpers/event_hub_factory';
+
+export default createEventHub();
diff --git a/app/assets/javascripts/invite_member/init_invite_member_modal.js b/app/assets/javascripts/invite_member/init_invite_member_modal.js
new file mode 100644
index 00000000000..7d60d78d3d9
--- /dev/null
+++ b/app/assets/javascripts/invite_member/init_invite_member_modal.js
@@ -0,0 +1,21 @@
+import Vue from 'vue';
+import { GlToast } from '@gitlab/ui';
+import InviteMemberModal from './components/invite_member_modal.vue';
+
+Vue.use(GlToast);
+
+export default function initInviteMembersModal() {
+ const el = document.querySelector('.js-invite-member-modal');
+
+ if (!el) {
+ return false;
+ }
+
+ const { membersPath } = el.dataset;
+
+ return new Vue({
+ el,
+ provide: { membersPath },
+ render: createElement => createElement(InviteMemberModal),
+ });
+}
diff --git a/app/assets/javascripts/invite_member/init_invite_member_trigger.js b/app/assets/javascripts/invite_member/init_invite_member_trigger.js
new file mode 100644
index 00000000000..a5f904b87a6
--- /dev/null
+++ b/app/assets/javascripts/invite_member/init_invite_member_trigger.js
@@ -0,0 +1,16 @@
+import Vue from 'vue';
+import InviteMemberTrigger from './components/invite_member_trigger.vue';
+
+export default function initInviteMembersTrigger() {
+ const el = document.querySelector('.js-invite-member-trigger');
+
+ if (!el) {
+ return false;
+ }
+
+ return new Vue({
+ el,
+ provide: { ...el.dataset },
+ render: createElement => createElement(InviteMemberTrigger),
+ });
+}
diff --git a/app/assets/javascripts/invite_members/components/invite_members_modal.vue b/app/assets/javascripts/invite_members/components/invite_members_modal.vue
new file mode 100644
index 00000000000..d2ea14a658b
--- /dev/null
+++ b/app/assets/javascripts/invite_members/components/invite_members_modal.vue
@@ -0,0 +1,224 @@
+<script>
+import {
+ GlModal,
+ GlDropdown,
+ GlDropdownItem,
+ GlDatepicker,
+ GlLink,
+ GlSprintf,
+ GlSearchBoxByType,
+ GlButton,
+ GlFormInput,
+} from '@gitlab/ui';
+import eventHub from '../event_hub';
+import { s__, sprintf } from '~/locale';
+import Api from '~/api';
+
+export default {
+ name: 'InviteMembersModal',
+ components: {
+ GlDatepicker,
+ GlLink,
+ GlModal,
+ GlDropdown,
+ GlDropdownItem,
+ GlSprintf,
+ GlSearchBoxByType,
+ GlButton,
+ GlFormInput,
+ },
+ props: {
+ groupId: {
+ type: String,
+ required: true,
+ },
+ groupName: {
+ type: String,
+ required: true,
+ },
+ accessLevels: {
+ type: Object,
+ required: true,
+ },
+ defaultAccessLevel: {
+ type: String,
+ required: true,
+ },
+ helpLink: {
+ type: String,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ visible: true,
+ modalId: 'invite-members-modal',
+ selectedAccessLevel: this.defaultAccessLevel,
+ newUsersToInvite: '',
+ selectedDate: undefined,
+ };
+ },
+ computed: {
+ introText() {
+ return sprintf(s__("InviteMembersModal|You're inviting members to the %{group_name} group"), {
+ group_name: this.groupName,
+ });
+ },
+ toastOptions() {
+ return {
+ onComplete: () => {
+ this.selectedAccessLevel = this.defaultAccessLevel;
+ this.newUsersToInvite = '';
+ },
+ };
+ },
+ postData() {
+ return {
+ user_id: this.newUsersToInvite,
+ access_level: this.selectedAccessLevel,
+ expires_at: this.selectedDate,
+ format: 'json',
+ };
+ },
+ selectedRoleName() {
+ return Object.keys(this.accessLevels).find(
+ key => this.accessLevels[key] === Number(this.selectedAccessLevel),
+ );
+ },
+ },
+ mounted() {
+ eventHub.$on('openModal', this.openModal);
+ },
+ methods: {
+ openModal() {
+ this.$root.$emit('bv::show::modal', this.modalId);
+ },
+ closeModal() {
+ this.$root.$emit('bv::hide::modal', this.modalId);
+ },
+ sendInvite() {
+ this.submitForm(this.postData);
+ this.closeModal();
+ },
+ cancelInvite() {
+ this.selectedAccessLevel = this.defaultAccessLevel;
+ this.selectedDate = undefined;
+ this.newUsersToInvite = '';
+ this.closeModal();
+ },
+ changeSelectedItem(item) {
+ this.selectedAccessLevel = item;
+ },
+ submitForm(formData) {
+ return Api.inviteGroupMember(this.groupId, formData)
+ .then(() => {
+ this.showToastMessageSuccess();
+ })
+ .catch(error => {
+ this.showToastMessageError(error);
+ });
+ },
+ showToastMessageSuccess() {
+ this.$toast.show(this.$options.labels.toastMessageSuccessful, this.toastOptions);
+ },
+ showToastMessageError(error) {
+ const message = error.response.data.message || this.$options.labels.toastMessageUnsuccessful;
+
+ this.$toast.show(message, this.toastOptions);
+ },
+ },
+ labels: {
+ modalTitle: s__('InviteMembersModal|Invite team members'),
+ userToInvite: s__('InviteMembersModal|GitLab member or Email address'),
+ userPlaceholder: s__('InviteMembersModal|Search for members to invite'),
+ accessLevel: s__('InviteMembersModal|Choose a role permission'),
+ accessExpireDate: s__('InviteMembersModal|Access expiration date (optional)'),
+ toastMessageSuccessful: s__('InviteMembersModal|Users were succesfully added'),
+ toastMessageUnsuccessful: s__('InviteMembersModal|User not invited. Feature coming soon!'),
+ readMoreText: s__(`InviteMembersModal|%{linkStart}Read more%{linkEnd} about role permissions`),
+ inviteButtonText: s__('InviteMembersModal|Invite'),
+ cancelButtonText: s__('InviteMembersModal|Cancel'),
+ },
+};
+</script>
+<template>
+ <gl-modal :modal-id="modalId" size="sm" :title="$options.labels.modalTitle">
+ <div class="gl-ml-5 gl-mr-5">
+ <div>{{ introText }}</div>
+
+ <label class="gl-font-weight-bold gl-mt-5">{{ $options.labels.userToInvite }}</label>
+ <div class="gl-mt-2">
+ <gl-search-box-by-type
+ v-model="newUsersToInvite"
+ :placeholder="$options.labels.userPlaceholder"
+ type="text"
+ autocomplete="off"
+ autocorrect="off"
+ autocapitalize="off"
+ spellcheck="false"
+ />
+ </div>
+
+ <label class="gl-font-weight-bold gl-mt-5">{{ $options.labels.accessLevel }}</label>
+ <div class="gl-mt-2 gl-w-half gl-xs-w-full">
+ <gl-dropdown
+ menu-class="dropdown-menu-selectable"
+ class="gl-shadow-none gl-w-full"
+ v-bind="$attrs"
+ :text="selectedRoleName"
+ >
+ <template v-for="(key, item) in accessLevels">
+ <gl-dropdown-item
+ :key="key"
+ active-class="is-active"
+ :is-checked="key === selectedAccessLevel"
+ @click="changeSelectedItem(key)"
+ >
+ <div>{{ item }}</div>
+ </gl-dropdown-item>
+ </template>
+ </gl-dropdown>
+ </div>
+
+ <div class="gl-mt-2">
+ <gl-sprintf :message="$options.labels.readMoreText">
+ <template #link="{content}">
+ <gl-link :href="helpLink" target="_blank">{{ content }}</gl-link>
+ </template>
+ </gl-sprintf>
+ </div>
+
+ <label class="gl-font-weight-bold gl-mt-5" for="expires_at">{{
+ $options.labels.accessExpireDate
+ }}</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="new Date()"
+ :target="null"
+ >
+ <template #default="{ formattedDate }">
+ <gl-form-input
+ class="gl-w-full"
+ :value="formattedDate"
+ :placeholder="__(`YYYY-MM-DD`)"
+ />
+ </template>
+ </gl-datepicker>
+ </div>
+ </div>
+
+ <template #modal-footer>
+ <div class="gl-display-flex gl-flex-direction-row gl-justify-content-end gl-flex-wrap gl-p-3">
+ <gl-button ref="cancelButton" @click="cancelInvite">
+ {{ $options.labels.cancelButtonText }}
+ </gl-button>
+ <div class="gl-mr-3"></div>
+ <gl-button ref="inviteButton" variant="success" @click="sendInvite">{{
+ $options.labels.inviteButtonText
+ }}</gl-button>
+ </div>
+ </template>
+ </gl-modal>
+</template>
diff --git a/app/assets/javascripts/invite_members/components/invite_members_trigger.vue b/app/assets/javascripts/invite_members/components/invite_members_trigger.vue
new file mode 100644
index 00000000000..d133e3655e3
--- /dev/null
+++ b/app/assets/javascripts/invite_members/components/invite_members_trigger.vue
@@ -0,0 +1,38 @@
+<script>
+import { GlLink, GlIcon } from '@gitlab/ui';
+import { s__ } from '~/locale';
+import eventHub from '../event_hub';
+
+export default {
+ components: {
+ GlLink,
+ GlIcon,
+ },
+ props: {
+ displayText: {
+ type: String,
+ required: false,
+ default: s__('InviteMembers|Invite team members'),
+ },
+ icon: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ },
+ methods: {
+ openModal() {
+ eventHub.$emit('openModal');
+ },
+ },
+};
+</script>
+
+<template>
+ <gl-link @click="openModal">
+ <div v-if="icon" class="nav-icon-container">
+ <gl-icon :size="16" :name="icon" />
+ </div>
+ <span class="nav-item-name"> {{ displayText }} </span>
+ </gl-link>
+</template>
diff --git a/app/assets/javascripts/invite_members/event_hub.js b/app/assets/javascripts/invite_members/event_hub.js
new file mode 100644
index 00000000000..e31806ad199
--- /dev/null
+++ b/app/assets/javascripts/invite_members/event_hub.js
@@ -0,0 +1,3 @@
+import createEventHub from '~/helpers/event_hub_factory';
+
+export default createEventHub();
diff --git a/app/assets/javascripts/invite_members/init_invite_members_modal.js b/app/assets/javascripts/invite_members/init_invite_members_modal.js
new file mode 100644
index 00000000000..92aa3187fc3
--- /dev/null
+++ b/app/assets/javascripts/invite_members/init_invite_members_modal.js
@@ -0,0 +1,25 @@
+import Vue from 'vue';
+import { GlToast } from '@gitlab/ui';
+import InviteMembersModal from '~/invite_members/components/invite_members_modal.vue';
+
+Vue.use(GlToast);
+
+export default function initInviteMembersModal() {
+ const el = document.querySelector('.js-invite-members-modal');
+
+ if (!el) {
+ return false;
+ }
+
+ return new Vue({
+ el,
+ render: createElement =>
+ createElement(InviteMembersModal, {
+ props: {
+ ...el.dataset,
+ accessLevels: JSON.parse(el.dataset.accessLevels),
+ groupName: el.dataset.groupName.toUpperCase(),
+ },
+ }),
+ });
+}
diff --git a/app/assets/javascripts/invite_members/init_invite_members_trigger.js b/app/assets/javascripts/invite_members/init_invite_members_trigger.js
new file mode 100644
index 00000000000..bee4f1c0f72
--- /dev/null
+++ b/app/assets/javascripts/invite_members/init_invite_members_trigger.js
@@ -0,0 +1,20 @@
+import Vue from 'vue';
+import InviteMembersTrigger from '~/invite_members/components/invite_members_trigger.vue';
+
+export default function initInviteMembersTrigger() {
+ const el = document.querySelector('.js-invite-members-trigger');
+
+ if (!el) {
+ return false;
+ }
+
+ return new Vue({
+ el,
+ render: createElement =>
+ createElement(InviteMembersTrigger, {
+ props: {
+ ...el.dataset,
+ },
+ }),
+ });
+}
diff --git a/app/assets/javascripts/issuable_context.js b/app/assets/javascripts/issuable_context.js
index 566efa0d7d6..6f2bd2da078 100644
--- a/app/assets/javascripts/issuable_context.js
+++ b/app/assets/javascripts/issuable_context.js
@@ -6,6 +6,7 @@ import UsersSelect from './users_select';
export default class IssuableContext {
constructor(currentUser) {
this.userSelect = new UsersSelect(currentUser);
+ this.reviewersSelect = new UsersSelect(currentUser, '.js-reviewer-search');
import(/* webpackChunkName: 'select2' */ 'select2/select2')
.then(() => {
diff --git a/app/assets/javascripts/issuable_create/components/issuable_form.vue b/app/assets/javascripts/issuable_create/components/issuable_form.vue
index 17e51b3dbac..d7b88cc7fc8 100644
--- a/app/assets/javascripts/issuable_create/components/issuable_form.vue
+++ b/app/assets/javascripts/issuable_create/components/issuable_form.vue
@@ -71,6 +71,7 @@ export default {
:markdown-docs-path="descriptionHelpPath"
:add-spacing-classes="false"
:show-suggest-popover="true"
+ :textarea-value="issuableDescription"
>
<textarea
id="issuable-description"
diff --git a/app/assets/javascripts/issuable_show/components/issuable_body.vue b/app/assets/javascripts/issuable_show/components/issuable_body.vue
new file mode 100644
index 00000000000..e6a05c1ab8b
--- /dev/null
+++ b/app/assets/javascripts/issuable_show/components/issuable_body.vue
@@ -0,0 +1,103 @@
+<script>
+import { GlLink } from '@gitlab/ui';
+
+import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
+
+import IssuableTitle from './issuable_title.vue';
+import IssuableDescription from './issuable_description.vue';
+import IssuableEditForm from './issuable_edit_form.vue';
+
+export default {
+ components: {
+ GlLink,
+ TimeAgoTooltip,
+ IssuableTitle,
+ IssuableDescription,
+ IssuableEditForm,
+ },
+ props: {
+ issuable: {
+ type: Object,
+ required: true,
+ },
+ statusBadgeClass: {
+ type: String,
+ required: true,
+ },
+ statusIcon: {
+ type: String,
+ required: true,
+ },
+ enableEdit: {
+ type: Boolean,
+ required: true,
+ },
+ enableAutocomplete: {
+ type: Boolean,
+ required: true,
+ },
+ editFormVisible: {
+ type: Boolean,
+ required: true,
+ },
+ descriptionPreviewPath: {
+ type: String,
+ required: true,
+ },
+ descriptionHelpPath: {
+ type: String,
+ required: true,
+ },
+ },
+ computed: {
+ isUpdated() {
+ return Boolean(this.issuable.updatedAt);
+ },
+ updatedBy() {
+ return this.issuable.updatedBy;
+ },
+ },
+};
+</script>
+
+<template>
+ <div class="issue-details issuable-details">
+ <div class="detail-page-description content-block">
+ <issuable-edit-form
+ v-if="editFormVisible"
+ :issuable="issuable"
+ :enable-autocomplete="enableAutocomplete"
+ :description-preview-path="descriptionPreviewPath"
+ :description-help-path="descriptionHelpPath"
+ >
+ <template #edit-form-actions="issuableMeta">
+ <slot name="edit-form-actions" v-bind="issuableMeta"></slot>
+ </template>
+ </issuable-edit-form>
+ <template v-else>
+ <issuable-title
+ :issuable="issuable"
+ :status-badge-class="statusBadgeClass"
+ :status-icon="statusIcon"
+ :enable-edit="enableEdit"
+ @edit-issuable="$emit('edit-issuable', $event)"
+ >
+ <template #status-badge>
+ <slot name="status-badge"></slot>
+ </template>
+ </issuable-title>
+ <issuable-description v-if="issuable.descriptionHtml" :issuable="issuable" />
+ <small v-if="isUpdated" class="edited-text gl-font-sm!">
+ {{ __('Edited') }}
+ <time-ago-tooltip :time="issuable.updatedAt" tooltip-placement="bottom" />
+ <span v-if="updatedBy">
+ {{ __('by') }}
+ <gl-link :href="updatedBy.webUrl" class="author-link gl-font-sm!">
+ <span>{{ updatedBy.name }}</span>
+ </gl-link>
+ </span>
+ </small>
+ </template>
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/issuable_show/components/issuable_description.vue b/app/assets/javascripts/issuable_show/components/issuable_description.vue
new file mode 100644
index 00000000000..091a4be5bd8
--- /dev/null
+++ b/app/assets/javascripts/issuable_show/components/issuable_description.vue
@@ -0,0 +1,31 @@
+<script>
+import $ from 'jquery';
+import { GlSafeHtmlDirective as SafeHtml } from '@gitlab/ui';
+import '~/behaviors/markdown/render_gfm';
+
+export default {
+ directives: {
+ SafeHtml,
+ },
+ props: {
+ issuable: {
+ type: Object,
+ required: true,
+ },
+ },
+ mounted() {
+ this.renderGFM();
+ },
+ methods: {
+ renderGFM() {
+ $(this.$refs.gfmContainer).renderGFM();
+ },
+ },
+};
+</script>
+
+<template>
+ <div class="description">
+ <div ref="gfmContainer" v-safe-html="issuable.descriptionHtml" class="md"></div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/issuable_show/components/issuable_edit_form.vue b/app/assets/javascripts/issuable_show/components/issuable_edit_form.vue
new file mode 100644
index 00000000000..7b9a83a740f
--- /dev/null
+++ b/app/assets/javascripts/issuable_show/components/issuable_edit_form.vue
@@ -0,0 +1,135 @@
+<script>
+import $ from 'jquery';
+import { GlForm, GlFormGroup, GlFormInput } from '@gitlab/ui';
+
+import Autosave from '~/autosave';
+import MarkdownField from '~/vue_shared/components/markdown/field.vue';
+
+import eventHub from '../event_hub';
+
+export default {
+ components: {
+ GlForm,
+ GlFormGroup,
+ GlFormInput,
+ MarkdownField,
+ },
+ props: {
+ issuable: {
+ type: Object,
+ required: true,
+ },
+ enableAutocomplete: {
+ type: Boolean,
+ required: true,
+ },
+ descriptionPreviewPath: {
+ type: String,
+ required: true,
+ },
+ descriptionHelpPath: {
+ type: String,
+ required: true,
+ },
+ },
+ data() {
+ const { title, description } = this.issuable;
+
+ return {
+ title,
+ description,
+ };
+ },
+ created() {
+ eventHub.$on('update.issuable', this.resetAutosave);
+ eventHub.$on('close.form', this.resetAutosave);
+ },
+ mounted() {
+ this.initAutosave();
+ },
+ beforeDestroy() {
+ eventHub.$off('update.issuable', this.resetAutosave);
+ eventHub.$off('close.form', this.resetAutosave);
+ },
+ methods: {
+ initAutosave() {
+ const { titleInput, descriptionInput } = this.$refs;
+
+ if (!titleInput || !descriptionInput) return;
+
+ this.autosaveTitle = new Autosave($(titleInput.$el), [
+ document.location.pathname,
+ document.location.search,
+ 'title',
+ ]);
+
+ this.autosaveDescription = new Autosave($(descriptionInput.$el), [
+ document.location.pathname,
+ document.location.search,
+ 'description',
+ ]);
+ },
+ resetAutosave() {
+ this.autosaveTitle.reset();
+ this.autosaveDescription.reset();
+ },
+ },
+};
+</script>
+
+<template>
+ <gl-form>
+ <gl-form-group
+ data-testid="title"
+ :label="__('Title')"
+ :label-sr-only="true"
+ label-for="issuable-title"
+ class="col-12"
+ >
+ <gl-form-input
+ id="issuable-title"
+ ref="titleInput"
+ v-model.trim="title"
+ :placeholder="__('Title')"
+ :aria-label="__('Title')"
+ :autofocus="true"
+ class="qa-title-input"
+ />
+ </gl-form-group>
+ <gl-form-group
+ data-testid="description"
+ :label="__('Description')"
+ :label-sr-only="true"
+ label-for="issuable-description"
+ class="col-12 common-note-form"
+ >
+ <markdown-field
+ :markdown-preview-path="descriptionPreviewPath"
+ :markdown-docs-path="descriptionHelpPath"
+ :enable-autocomplete="enableAutocomplete"
+ :textarea-value="description"
+ >
+ <template #textarea>
+ <textarea
+ id="issuable-description"
+ ref="descriptionInput"
+ v-model="description"
+ :data-supports-quick-actions="enableAutocomplete"
+ :aria-label="__('Description')"
+ :placeholder="__('Write a comment or drag your files here…')"
+ class="note-textarea js-gfm-input js-autosize markdown-area
+ qa-description-textarea"
+ dir="auto"
+ ></textarea>
+ </template>
+ </markdown-field>
+ </gl-form-group>
+ <div data-testid="actions" class="col-12 gl-mt-3 gl-mb-3 clearfix">
+ <slot
+ name="edit-form-actions"
+ :issuable-title="title"
+ :issuable-description="description"
+ ></slot>
+ </div>
+ </gl-form>
+</template>
diff --git a/app/assets/javascripts/issuable_show/components/issuable_header.vue b/app/assets/javascripts/issuable_show/components/issuable_header.vue
new file mode 100644
index 00000000000..3815c50cac6
--- /dev/null
+++ b/app/assets/javascripts/issuable_show/components/issuable_header.vue
@@ -0,0 +1,120 @@
+<script>
+import { GlIcon, GlButton, GlTooltipDirective, GlAvatarLink, GlAvatarLabeled } from '@gitlab/ui';
+
+import { getIdFromGraphQLId } from '~/graphql_shared/utils';
+import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
+
+export default {
+ components: {
+ GlIcon,
+ GlButton,
+ GlAvatarLink,
+ GlAvatarLabeled,
+ TimeAgoTooltip,
+ },
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ },
+ props: {
+ createdAt: {
+ type: String,
+ required: true,
+ },
+ author: {
+ type: Object,
+ required: true,
+ },
+ statusBadgeClass: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ statusIcon: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ blocked: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ confidential: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ },
+ computed: {
+ authorId() {
+ return getIdFromGraphQLId(`${this.author.id}`);
+ },
+ },
+ mounted() {
+ this.toggleSidebarButtonEl = document.querySelector('.js-toggle-right-sidebar-button');
+ },
+ methods: {
+ handleRightSidebarToggleClick() {
+ if (this.toggleSidebarButtonEl) {
+ this.toggleSidebarButtonEl.dispatchEvent(new Event('click'));
+ }
+ },
+ },
+};
+</script>
+
+<template>
+ <div class="detail-page-header">
+ <div class="detail-page-header-body">
+ <div data-testid="status" class="issuable-status-box status-box" :class="statusBadgeClass">
+ <gl-icon v-if="statusIcon" :name="statusIcon" class="d-block d-sm-none" />
+ <span class="d-none d-sm-block"><slot name="status-badge"></slot></span>
+ </div>
+ <div class="issuable-meta gl-display-flex gl-align-items-center">
+ <div class="gl-display-inline-block">
+ <div v-if="blocked" data-testid="blocked" class="issuable-warning-icon inline">
+ <gl-icon name="lock" :aria-label="__('Blocked')" />
+ </div>
+ <div v-if="confidential" data-testid="confidential" class="issuable-warning-icon inline">
+ <gl-icon name="eye-slash" :aria-label="__('Confidential')" />
+ </div>
+ </div>
+ <span>
+ {{ __('Opened') }}
+ <time-ago-tooltip data-testid="startTimeItem" :time="createdAt" />
+ {{ __('by') }}
+ </span>
+ <gl-avatar-link
+ data-testid="avatar"
+ :data-user-id="authorId"
+ :data-username="author.username"
+ :data-name="author.name"
+ :href="author.webUrl"
+ target="_blank"
+ class="js-user-link gl-ml-2"
+ >
+ <gl-avatar-labeled
+ :size="24"
+ :src="author.avatarUrl"
+ :label="author.name"
+ class="d-none d-sm-inline-flex gl-ml-1"
+ />
+ <strong class="author d-sm-none d-inline">@{{ author.username }}</strong>
+ </gl-avatar-link>
+ </div>
+ <gl-button
+ data-testid="sidebar-toggle"
+ icon="chevron-double-lg-left"
+ class="d-block d-sm-none gutter-toggle issuable-gutter-toggle"
+ :aria-label="__('Expand sidebar')"
+ @click="handleRightSidebarToggleClick"
+ />
+ </div>
+ <div
+ data-testid="header-actions"
+ class="detail-page-header-actions js-issuable-actions js-issuable-buttons gl-display-flex gl-display-md-block"
+ >
+ <slot name="header-actions"></slot>
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/issuable_show/components/issuable_show_root.vue b/app/assets/javascripts/issuable_show/components/issuable_show_root.vue
new file mode 100644
index 00000000000..b41f5e270a8
--- /dev/null
+++ b/app/assets/javascripts/issuable_show/components/issuable_show_root.vue
@@ -0,0 +1,98 @@
+<script>
+import IssuableSidebar from '~/issuable_sidebar/components/issuable_sidebar_root.vue';
+
+import IssuableHeader from './issuable_header.vue';
+import IssuableBody from './issuable_body.vue';
+
+export default {
+ components: {
+ IssuableSidebar,
+ IssuableHeader,
+ IssuableBody,
+ },
+ props: {
+ issuable: {
+ type: Object,
+ required: true,
+ },
+ statusBadgeClass: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ statusIcon: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ enableEdit: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ enableAutocomplete: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ editFormVisible: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ descriptionPreviewPath: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ descriptionHelpPath: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ },
+};
+</script>
+
+<template>
+ <div class="issuable-show-container">
+ <issuable-header
+ :status-badge-class="statusBadgeClass"
+ :status-icon="statusIcon"
+ :blocked="issuable.blocked"
+ :confidential="issuable.confidential"
+ :created-at="issuable.createdAt"
+ :author="issuable.author"
+ >
+ <template #status-badge>
+ <slot name="status-badge"></slot>
+ </template>
+ <template #header-actions>
+ <slot name="header-actions"></slot>
+ </template>
+ </issuable-header>
+ <issuable-body
+ :issuable="issuable"
+ :status-badge-class="statusBadgeClass"
+ :status-icon="statusIcon"
+ :enable-edit="enableEdit"
+ :enable-autocomplete="enableAutocomplete"
+ :edit-form-visible="editFormVisible"
+ :description-preview-path="descriptionPreviewPath"
+ :description-help-path="descriptionHelpPath"
+ @edit-issuable="$emit('edit-issuable', $event)"
+ >
+ <template #status-badge>
+ <slot name="status-badge"></slot>
+ </template>
+ <template #edit-form-actions="actionsProps">
+ <slot name="edit-form-actions" v-bind="actionsProps"></slot>
+ </template>
+ </issuable-body>
+ <issuable-sidebar @sidebar-toggle="$emit('sidebar-toggle', $event)">
+ <template #right-sidebar-items="sidebarProps">
+ <slot name="right-sidebar-items" v-bind="sidebarProps"></slot>
+ </template>
+ </issuable-sidebar>
+ </div>
+</template>
diff --git a/app/assets/javascripts/issuable_show/components/issuable_title.vue b/app/assets/javascripts/issuable_show/components/issuable_title.vue
new file mode 100644
index 00000000000..d3b42fd2ffb
--- /dev/null
+++ b/app/assets/javascripts/issuable_show/components/issuable_title.vue
@@ -0,0 +1,96 @@
+<script>
+import {
+ GlIcon,
+ GlButton,
+ GlIntersectionObserver,
+ GlTooltipDirective,
+ GlSafeHtmlDirective as SafeHtml,
+} from '@gitlab/ui';
+
+export default {
+ components: {
+ GlIcon,
+ GlButton,
+ GlIntersectionObserver,
+ },
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ SafeHtml,
+ },
+ props: {
+ issuable: {
+ type: Object,
+ required: true,
+ },
+ statusBadgeClass: {
+ type: String,
+ required: true,
+ },
+ statusIcon: {
+ type: String,
+ required: true,
+ },
+ enableEdit: {
+ type: Boolean,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ stickyTitleVisible: false,
+ };
+ },
+ methods: {
+ handleTitleAppear() {
+ this.stickyTitleVisible = false;
+ },
+ handleTitleDisappear() {
+ this.stickyTitleVisible = true;
+ },
+ },
+};
+</script>
+
+<template>
+ <div>
+ <div class="title-container">
+ <h2 v-safe-html="issuable.titleHtml" class="title qa-title" dir="auto"></h2>
+ <gl-button
+ v-if="enableEdit"
+ v-gl-tooltip.bottom
+ :title="__('Edit title and description')"
+ icon="pencil"
+ class="btn-edit js-issuable-edit qa-edit-button"
+ @click="$emit('edit-issuable', $event)"
+ />
+ </div>
+ <gl-intersection-observer @appear="handleTitleAppear" @disappear="handleTitleDisappear">
+ <transition name="issuable-header-slide">
+ <div
+ v-if="stickyTitleVisible"
+ class="issue-sticky-header gl-fixed gl-z-index-3 gl-bg-white gl-border-1 gl-border-b-solid gl-border-b-gray-100 gl-py-3"
+ data-testid="header"
+ >
+ <div
+ class="issue-sticky-header-text gl-display-flex gl-align-items-center gl-mx-auto gl-px-5"
+ >
+ <p
+ data-testid="status"
+ class="issuable-status-box status-box gl-my-0"
+ :class="statusBadgeClass"
+ >
+ <gl-icon :name="statusIcon" class="gl-display-block d-sm-none gl-h-6!" />
+ <span class="gl-display-none d-sm-block"><slot name="status-badge"></slot></span>
+ </p>
+ <p
+ class="gl-font-weight-bold gl-overflow-hidden gl-white-space-nowrap gl-text-overflow-ellipsis gl-my-0"
+ :title="issuable.title"
+ >
+ {{ issuable.title }}
+ </p>
+ </div>
+ </div>
+ </transition>
+ </gl-intersection-observer>
+ </div>
+</template>
diff --git a/app/assets/javascripts/issuable_show/constants.js b/app/assets/javascripts/issuable_show/constants.js
new file mode 100644
index 00000000000..346f45c7d90
--- /dev/null
+++ b/app/assets/javascripts/issuable_show/constants.js
@@ -0,0 +1,5 @@
+export const IssuableType = {
+ Issue: 'issue',
+ Incident: 'incident',
+ TestCase: 'test_case',
+};
diff --git a/app/assets/javascripts/issuable_show/event_hub.js b/app/assets/javascripts/issuable_show/event_hub.js
new file mode 100644
index 00000000000..e31806ad199
--- /dev/null
+++ b/app/assets/javascripts/issuable_show/event_hub.js
@@ -0,0 +1,3 @@
+import createEventHub from '~/helpers/event_hub_factory';
+
+export default createEventHub();
diff --git a/app/assets/javascripts/issuable_sidebar/components/issuable_sidebar_root.vue b/app/assets/javascripts/issuable_sidebar/components/issuable_sidebar_root.vue
new file mode 100644
index 00000000000..7d1339f833d
--- /dev/null
+++ b/app/assets/javascripts/issuable_sidebar/components/issuable_sidebar_root.vue
@@ -0,0 +1,88 @@
+<script>
+import Cookies from 'js-cookie';
+import { GlIcon } from '@gitlab/ui';
+import { GlBreakpointInstance as bp } from '@gitlab/ui/dist/utils';
+
+import { parseBoolean } from '~/lib/utils/common_utils';
+
+export default {
+ components: {
+ GlIcon,
+ },
+ data() {
+ const userExpanded = !parseBoolean(Cookies.get('collapsed_gutter'));
+
+ // We're deliberately keeping two different props for sidebar status;
+ // 1. userExpanded reflects value based on cookie `collapsed_gutter`.
+ // 2. isExpanded reflect actual sidebar state.
+ return {
+ userExpanded,
+ isExpanded: userExpanded ? bp.isDesktop() : userExpanded,
+ };
+ },
+ watch: {
+ isExpanded(expanded) {
+ this.$emit('sidebar-toggle', {
+ expanded,
+ });
+ },
+ },
+ mounted() {
+ window.addEventListener('resize', this.handleWindowResize);
+ },
+ beforeDestroy() {
+ window.removeEventListener('resize', this.handleWindowResize);
+ },
+ methods: {
+ updatePageContainerClass() {
+ const layoutPageEl = document.querySelector('.layout-page');
+
+ if (layoutPageEl) {
+ layoutPageEl.classList.toggle('right-sidebar-expanded', this.isExpanded);
+ layoutPageEl.classList.toggle('right-sidebar-collapsed', !this.isExpanded);
+ }
+ },
+ handleWindowResize() {
+ if (this.userExpanded) {
+ this.isExpanded = bp.isDesktop();
+ this.updatePageContainerClass();
+ }
+ },
+ handleToggleSidebarClick() {
+ this.isExpanded = !this.isExpanded;
+ this.userExpanded = this.isExpanded;
+
+ Cookies.set('collapsed_gutter', !this.userExpanded);
+ this.updatePageContainerClass();
+ },
+ },
+};
+</script>
+
+<template>
+ <aside
+ :class="{ 'right-sidebar-expanded': isExpanded, 'right-sidebar-collapsed': !isExpanded }"
+ class="right-sidebar"
+ aria-live="polite"
+ >
+ <button
+ class="toggle-right-sidebar-button js-toggle-right-sidebar-button w-100 gl-text-decoration-none! gl-display-flex gl-outline-0!"
+ :title="__('Toggle sidebar')"
+ @click="handleToggleSidebarClick"
+ >
+ <span v-if="isExpanded" class="collapse-text gl-flex-grow-1 gl-text-left">{{
+ __('Collapse sidebar')
+ }}</span>
+ <gl-icon v-show="isExpanded" data-testid="icon-collapse" name="chevron-double-lg-right" />
+ <gl-icon
+ v-show="!isExpanded"
+ data-testid="icon-expand"
+ name="chevron-double-lg-left"
+ class="gl-ml-2"
+ />
+ </button>
+ <div data-testid="sidebar-items" class="issuable-sidebar">
+ <slot name="right-sidebar-items" v-bind="{ sidebarExpanded: isExpanded }"></slot>
+ </div>
+ </aside>
+</template>
diff --git a/app/assets/javascripts/issuable_sidebar/components/sidebar_app.vue b/app/assets/javascripts/issuable_sidebar/components/sidebar_app.vue
deleted file mode 100644
index 06c50f62aab..00000000000
--- a/app/assets/javascripts/issuable_sidebar/components/sidebar_app.vue
+++ /dev/null
@@ -1,23 +0,0 @@
-<script>
-export default {
- props: {
- signedIn: {
- type: Boolean,
- required: true,
- },
- sidebarStatusClass: {
- type: String,
- required: false,
- default: '',
- },
- },
-};
-</script>
-
-<template>
- <aside
- :class="sidebarStatusClass"
- class="right-sidebar js-right-sidebar js-issuable-sidebar"
- aria-live="polite"
- ></aside>
-</template>
diff --git a/app/assets/javascripts/issuable_sidebar/sidebar_bundle.js b/app/assets/javascripts/issuable_sidebar/sidebar_bundle.js
deleted file mode 100644
index c8acafa8cd8..00000000000
--- a/app/assets/javascripts/issuable_sidebar/sidebar_bundle.js
+++ /dev/null
@@ -1,27 +0,0 @@
-import Vue from 'vue';
-
-import SidebarApp from './components/sidebar_app.vue';
-
-export default () => {
- const el = document.getElementById('js-vue-issuable-sidebar');
-
- if (!el) {
- return false;
- }
-
- const { sidebarStatusClass } = el.dataset;
- // An empty string is present when user is signed in.
- const signedIn = el.dataset.signedIn === '';
-
- return new Vue({
- el,
- components: { SidebarApp },
- render: createElement =>
- createElement('sidebar-app', {
- props: {
- signedIn,
- sidebarStatusClass,
- },
- }),
- });
-};
diff --git a/app/assets/javascripts/issue_show/components/fields/description_template.vue b/app/assets/javascripts/issue_show/components/fields/description_template.vue
index e1b308c6f57..8a1a8448bb8 100644
--- a/app/assets/javascripts/issue_show/components/fields/description_template.vue
+++ b/app/assets/javascripts/issue_show/components/fields/description_template.vue
@@ -1,5 +1,4 @@
<script>
-/* eslint-disable @gitlab/vue-require-i18n-strings */
import $ from 'jquery';
import { GlIcon } from '@gitlab/ui';
import IssuableTemplateSelectors from '../../../templates/issuable_template_selectors';
@@ -62,11 +61,15 @@ export default {
data-toggle="dropdown"
>
<span class="dropdown-toggle-text">{{ __('Choose a template') }}</span>
- <i aria-hidden="true" class="fa fa-chevron-down"> </i>
+ <gl-icon
+ name="chevron-down"
+ class="gl-absolute gl-top-3 gl-right-3 gl-text-gray-500"
+ aria-hidden="true"
+ />
</button>
<div class="dropdown-menu dropdown-select">
<div class="dropdown-title gl-display-flex gl-justify-content-center">
- <span class="gl-ml-auto">Choose a template</span>
+ <span class="gl-ml-auto">{{ __('Choose a template') }}</span>
<button
class="dropdown-title-button dropdown-menu-close gl-ml-auto"
:aria-label="__('Close')"
@@ -82,7 +85,7 @@ export default {
:placeholder="__('Filter')"
autocomplete="off"
/>
- <i aria-hidden="true" class="fa fa-search dropdown-input-search"> </i>
+ <gl-icon name="search" class="dropdown-input-search" aria-hidden="true" />
<gl-icon
name="close"
class="dropdown-input-clear js-dropdown-input-clear"
diff --git a/app/assets/javascripts/issue_show/components/incidents/graphql/queries/get_alert.graphql b/app/assets/javascripts/issue_show/components/incidents/graphql/queries/get_alert.graphql
index 00ddc80432d..bb637dea033 100644
--- a/app/assets/javascripts/issue_show/components/incidents/graphql/queries/get_alert.graphql
+++ b/app/assets/javascripts/issue_show/components/incidents/graphql/queries/get_alert.graphql
@@ -13,6 +13,7 @@ query getAlert($iid: String!, $fullPath: ID!) {
service
description
endedAt
+ hosts
details
}
}
diff --git a/app/assets/javascripts/issue_show/components/incidents/highlight_bar.vue b/app/assets/javascripts/issue_show/components/incidents/highlight_bar.vue
index a47fe4c84cf..96f187f26dd 100644
--- a/app/assets/javascripts/issue_show/components/incidents/highlight_bar.vue
+++ b/app/assets/javascripts/issue_show/components/incidents/highlight_bar.vue
@@ -1,42 +1,63 @@
<script>
-import { GlLink } from '@gitlab/ui';
+import { GlLink, GlTooltipDirective } from '@gitlab/ui';
import { formatDate } from '~/lib/utils/datetime_utility';
export default {
components: {
GlLink,
+ IncidentSla: () => import('ee_component/issue_show/components/incidents/incident_sla.vue'),
+ },
+ directives: {
+ GlTooltip: GlTooltipDirective,
},
props: {
alert: {
type: Object,
- required: true,
+ required: false,
+ default: null,
},
},
+ data() {
+ return { childHasData: false };
+ },
computed: {
startTime() {
return formatDate(this.alert.startedAt, 'yyyy-mm-dd Z');
},
+ showHighlightBar() {
+ return this.alert || this.childHasData;
+ },
+ },
+ methods: {
+ update(hasData) {
+ this.childHasData = hasData;
+ },
},
};
</script>
<template>
<div
- class="gl-border-solid gl-border-1 gl-border-gray-100 gl-p-5 gl-mb-3 gl-rounded-base gl-display-flex gl-justify-content-space-between"
+ v-show="showHighlightBar"
+ class="gl-border-solid gl-border-1 gl-border-gray-100 gl-p-5 gl-mb-3 gl-rounded-base gl-display-flex gl-justify-content-space-between gl-xs-flex-direction-column"
>
- <div class="text-truncate gl-pr-3">
+ <div v-if="alert" class="gl-mr-3">
<span class="gl-font-weight-bold">{{ s__('HighlightBar|Original alert:') }}</span>
- <gl-link :href="alert.detailsUrl">{{ alert.title }}</gl-link>
+ <gl-link v-gl-tooltip :title="alert.title" :href="alert.detailsUrl">
+ #{{ alert.iid }}
+ </gl-link>
</div>
- <div class="gl-pr-3 gl-white-space-nowrap">
+ <div v-if="alert" class="gl-mr-3">
<span class="gl-font-weight-bold">{{ s__('HighlightBar|Alert start time:') }}</span>
{{ startTime }}
</div>
- <div class="gl-white-space-nowrap">
+ <div v-if="alert" class="gl-mr-3">
<span class="gl-font-weight-bold">{{ s__('HighlightBar|Alert events:') }}</span>
<span>{{ alert.eventCount }}</span>
</div>
+
+ <incident-sla @update="update" />
</div>
</template>
diff --git a/app/assets/javascripts/issue_show/components/incidents/incident_tabs.vue b/app/assets/javascripts/issue_show/components/incidents/incident_tabs.vue
index 4104ddbf06f..c593fa33973 100644
--- a/app/assets/javascripts/issue_show/components/incidents/incident_tabs.vue
+++ b/app/assets/javascripts/issue_show/components/incidents/incident_tabs.vue
@@ -5,8 +5,10 @@ import HighlightBar from './highlight_bar.vue';
import createFlash from '~/flash';
import { s__ } from '~/locale';
import AlertDetailsTable from '~/vue_shared/components/alert_details_table.vue';
+import Tracking from '~/tracking';
import getAlert from './graphql/queries/get_alert.graphql';
+import { trackIncidentDetailsViewsOptions } from '~/incidents/constants';
export default {
components: {
@@ -45,12 +47,14 @@ export default {
loading() {
return this.$apollo.queries.alert.loading;
},
- alertTableFields() {
- if (this.alert) {
- const { detailsUrl, __typename, ...restDetails } = this.alert;
- return restDetails;
- }
- return null;
+ },
+ mounted() {
+ this.trackPageViews();
+ },
+ methods: {
+ trackPageViews() {
+ const { category, action } = trackIncidentDetailsViewsOptions;
+ Tracking.event(category, action);
},
},
};
@@ -60,11 +64,11 @@ export default {
<div>
<gl-tabs content-class="gl-reset-line-height" class="gl-mt-n3" data-testid="incident-tabs">
<gl-tab :title="s__('Incident|Summary')">
- <highlight-bar v-if="alert" :alert="alert" />
+ <highlight-bar :alert="alert" />
<description-component v-bind="$attrs" />
</gl-tab>
<gl-tab v-if="alert" class="alert-management-details" :title="s__('Incident|Alert details')">
- <alert-details-table :alert="alertTableFields" :loading="loading" />
+ <alert-details-table :alert="alert" :loading="loading" />
</gl-tab>
</gl-tabs>
</div>
diff --git a/app/assets/javascripts/issue_show/incident.js b/app/assets/javascripts/issue_show/incident.js
index a34e75ee64a..618fb551f28 100644
--- a/app/assets/javascripts/issue_show/incident.js
+++ b/app/assets/javascripts/issue_show/incident.js
@@ -3,6 +3,7 @@ import VueApollo from 'vue-apollo';
import createDefaultClient from '~/lib/graphql';
import issuableApp from './components/app.vue';
import incidentTabs from './components/incidents/incident_tabs.vue';
+import { parseBoolean } from '~/lib/utils/common_utils';
Vue.use(VueApollo);
@@ -11,7 +12,7 @@ export default function initIssuableApp(issuableData = {}) {
defaultClient: createDefaultClient(),
});
- const { projectNamespace, projectPath, iid } = issuableData;
+ const { iid, projectNamespace, projectPath, slaFeatureAvailable } = issuableData;
return new Vue({
el: document.getElementById('js-issuable-app'),
@@ -22,6 +23,7 @@ export default function initIssuableApp(issuableData = {}) {
provide: {
fullPath: `${projectNamespace}/${projectPath}`,
iid,
+ slaFeatureAvailable: parseBoolean(slaFeatureAvailable),
},
render(createElement) {
return createElement('issuable-app', {
diff --git a/app/assets/javascripts/issue_show/stores/index.js b/app/assets/javascripts/issue_show/stores/index.js
index c6f7e892f9b..06bbd406e3a 100644
--- a/app/assets/javascripts/issue_show/stores/index.js
+++ b/app/assets/javascripts/issue_show/stores/index.js
@@ -1,4 +1,4 @@
-import { sanitize } from 'dompurify';
+import { sanitize } from '~/lib/dompurify';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
import updateDescription from '../utils/update_description';
diff --git a/app/assets/javascripts/issue_show/utils/parse_data.js b/app/assets/javascripts/issue_show/utils/parse_data.js
index a62a5167961..620974901fb 100644
--- a/app/assets/javascripts/issue_show/utils/parse_data.js
+++ b/app/assets/javascripts/issue_show/utils/parse_data.js
@@ -1,4 +1,5 @@
-import { sanitize } from 'dompurify';
+import * as Sentry from '~/sentry/wrapper';
+import { sanitize } from '~/lib/dompurify';
// We currently load + parse the data from the issue app and related merge request
let cachedParsedData;
@@ -7,10 +8,9 @@ export const parseIssuableData = () => {
try {
if (cachedParsedData) return cachedParsedData;
- const initialDataEl = document.getElementById('js-issuable-app-initial-data');
-
- const parsedData = JSON.parse(initialDataEl.textContent.replace(/&quot;/g, '"'));
+ const initialDataEl = document.getElementById('js-issuable-app');
+ const parsedData = JSON.parse(initialDataEl.dataset.initial);
parsedData.initialTitleHtml = sanitize(parsedData.initialTitleHtml);
parsedData.initialDescriptionHtml = sanitize(parsedData.initialDescriptionHtml);
@@ -18,7 +18,7 @@ export const parseIssuableData = () => {
return parsedData;
} catch (e) {
- console.error(e); // eslint-disable-line no-console
+ Sentry.captureException(e);
return {};
}
diff --git a/app/assets/javascripts/issues_list/components/issuable.vue b/app/assets/javascripts/issues_list/components/issuable.vue
index adfb234fe7a..dc63d613b5b 100644
--- a/app/assets/javascripts/issues_list/components/issuable.vue
+++ b/app/assets/javascripts/issues_list/components/issuable.vue
@@ -351,7 +351,7 @@ export default {
:class="{ cred: isOverdue }"
:title="__('Due date')"
>
- <i class="fa fa-calendar"></i>
+ <gl-icon name="calendar" />
{{ dueDateWords }}
</span>
diff --git a/app/assets/javascripts/jira_connect.js b/app/assets/javascripts/jira_connect.js
index 895cdc4562c..0864a3024ac 100644
--- a/app/assets/javascripts/jira_connect.js
+++ b/app/assets/javascripts/jira_connect.js
@@ -18,6 +18,13 @@ function onLoaded() {
alert(res.responseJSON.error);
};
+ AP.getLocation(function(location) {
+ $('.js-jira-connect-sign-in').each(function() {
+ var updatedLink = `${$(this).attr('href')}?return_to=${location}`;
+ $(this).attr('href', updatedLink);
+ });
+ });
+
$('#add-subscription-form').on('submit', function(e) {
var actionUrl = $(this).attr('action');
e.preventDefault();
diff --git a/app/assets/javascripts/jira_import/components/jira_import_form.vue b/app/assets/javascripts/jira_import/components/jira_import_form.vue
index 4339021d9a0..4a1bca110fd 100644
--- a/app/assets/javascripts/jira_import/components/jira_import_form.vue
+++ b/app/assets/javascripts/jira_import/components/jira_import_form.vue
@@ -301,7 +301,7 @@ export default {
"
@hide="resetDropdown"
>
- <gl-search-box-by-type v-model.trim="searchTerm" class="gl-m-3" />
+ <gl-search-box-by-type v-model.trim="searchTerm" />
<gl-loading-icon v-if="isFetching" />
diff --git a/app/assets/javascripts/jira_import/index.js b/app/assets/javascripts/jira_import/index.js
index 695a237bf50..003f3c7107e 100644
--- a/app/assets/javascripts/jira_import/index.js
+++ b/app/assets/javascripts/jira_import/index.js
@@ -6,7 +6,7 @@ import App from './components/jira_import_app.vue';
Vue.use(VueApollo);
-const defaultClient = createDefaultClient();
+const defaultClient = createDefaultClient({}, { assumeImmutableResults: true });
const apolloProvider = new VueApollo({
defaultClient,
diff --git a/app/assets/javascripts/jira_import/queries/initiate_jira_import.mutation.graphql b/app/assets/javascripts/jira_import/queries/initiate_jira_import.mutation.graphql
index 8fda8287988..807374bf06c 100644
--- a/app/assets/javascripts/jira_import/queries/initiate_jira_import.mutation.graphql
+++ b/app/assets/javascripts/jira_import/queries/initiate_jira_import.mutation.graphql
@@ -2,7 +2,6 @@
mutation($input: JiraImportStartInput!) {
jiraImportStart(input: $input) {
- clientMutationId
jiraImport {
...JiraImport
}
diff --git a/app/assets/javascripts/jira_import/utils/cache_update.js b/app/assets/javascripts/jira_import/utils/cache_update.js
index 6aaf2010866..65b2e459f03 100644
--- a/app/assets/javascripts/jira_import/utils/cache_update.js
+++ b/app/assets/javascripts/jira_import/utils/cache_update.js
@@ -1,3 +1,4 @@
+import produce from 'immer';
import getJiraImportDetailsQuery from '../queries/get_jira_import_details.query.graphql';
import { IMPORT_STATE } from './jira_import_utils';
@@ -13,22 +14,20 @@ export const addInProgressImportToStore = (store, jiraImportStart, fullPath) =>
},
};
- const cacheData = store.readQuery({
+ const sourceData = store.readQuery({
...queryDetails,
});
store.writeQuery({
...queryDetails,
- data: {
- project: {
- ...cacheData.project,
- jiraImportStatus: IMPORT_STATE.SCHEDULED,
- jiraImports: {
- ...cacheData.project.jiraImports,
- nodes: cacheData.project.jiraImports.nodes.concat(jiraImportStart.jiraImport),
- },
- },
- },
+ data: produce(sourceData, draftData => {
+ draftData.project.jiraImportStatus = IMPORT_STATE.SCHEDULED; // eslint-disable-line no-param-reassign
+ // eslint-disable-next-line no-param-reassign
+ draftData.project.jiraImports.nodes = [
+ ...sourceData.project.jiraImports.nodes,
+ jiraImportStart.jiraImport,
+ ];
+ }),
});
};
diff --git a/app/assets/javascripts/jobs/components/commit_block.vue b/app/assets/javascripts/jobs/components/commit_block.vue
index c4f180f200c..222fae6d9a8 100644
--- a/app/assets/javascripts/jobs/components/commit_block.vue
+++ b/app/assets/javascripts/jobs/components/commit_block.vue
@@ -32,26 +32,25 @@ export default {
block: !isLastBlock,
}"
>
- <p class="gl-mb-2">
- <span class="font-weight-bold">{{ __('Commit') }}</span>
+ <span class="font-weight-bold">{{ __('Commit') }}</span>
- <gl-link :href="commit.commit_path" class="js-commit-sha commit-sha link-commit">
- {{ commit.short_id }}
- </gl-link>
+ <gl-link :href="commit.commit_path" class="js-commit-sha commit-sha link-commit">
+ {{ commit.short_id }}
+ </gl-link>
- <clipboard-button
- :text="commit.id"
- :title="__('Copy commit SHA')"
- css-class="btn btn-clipboard btn-transparent"
- />
+ <clipboard-button
+ :text="commit.id"
+ :title="__('Copy commit SHA')"
+ category="tertiary"
+ size="small"
+ />
- <span v-if="mergeRequest">
- in
- <gl-link :href="mergeRequest.path" class="js-link-commit link-commit"
- >!{{ mergeRequest.iid }}</gl-link
- >
- </span>
- </p>
+ <span v-if="mergeRequest">
+ in
+ <gl-link :href="mergeRequest.path" class="js-link-commit link-commit"
+ >!{{ mergeRequest.iid }}</gl-link
+ >
+ </span>
<p class="gl-mb-0">{{ commit.title }}</p>
</div>
diff --git a/app/assets/javascripts/jobs/components/job_container_item.vue b/app/assets/javascripts/jobs/components/job_container_item.vue
index 79e6623eca8..6b61dc5902b 100644
--- a/app/assets/javascripts/jobs/components/job_container_item.vue
+++ b/app/assets/javascripts/jobs/components/job_container_item.vue
@@ -1,6 +1,5 @@
<script>
-import { GlLink, GlIcon } from '@gitlab/ui';
-import tooltip from '~/vue_shared/directives/tooltip';
+import { GlLink, GlIcon, GlTooltipDirective } from '@gitlab/ui';
import CiIcon from '~/vue_shared/components/ci_icon.vue';
import delayedJobMixin from '~/jobs/mixins/delayed_job_mixin';
import { sprintf } from '~/locale';
@@ -12,7 +11,7 @@ export default {
GlLink,
},
directives: {
- tooltip,
+ GlTooltip: GlTooltipDirective,
},
mixins: [delayedJobMixin],
props: {
@@ -49,10 +48,9 @@ export default {
}"
>
<gl-link
- v-tooltip
+ v-gl-tooltip
:href="job.status.details_path"
:title="tooltipText"
- data-boundary="viewport"
class="js-job-link d-flex"
>
<gl-icon
diff --git a/app/assets/javascripts/jobs/components/log/line.vue b/app/assets/javascripts/jobs/components/log/line.vue
index e68d5b8eda4..791664c05d9 100644
--- a/app/assets/javascripts/jobs/components/log/line.vue
+++ b/app/assets/javascripts/jobs/components/log/line.vue
@@ -1,6 +1,24 @@
<script>
+import linkifyHtml from 'linkifyjs/html';
+import { sanitize } from '~/lib/dompurify';
+import { isAbsolute } from '~/lib/utils/url_utility';
import LineNumber from './line_number.vue';
+const linkifyOptions = {
+ attributes: {
+ // eslint-disable-next-line @gitlab/require-i18n-strings
+ rel: 'nofollow noopener',
+ },
+ className: 'gl-reset-color!',
+ defaultProtocol: 'https',
+ validate: {
+ email: false,
+ url(value) {
+ return isAbsolute(value);
+ },
+ },
+};
+
export default {
functional: true,
props: {
@@ -17,13 +35,15 @@ export default {
const { line, path } = props;
const chars = line.content.map(content => {
- return h(
- 'span',
- {
- class: ['gl-white-space-pre-wrap', content.style],
+ const linkfied = linkifyHtml(content.text, linkifyOptions);
+ return h('span', {
+ class: ['gl-white-space-pre-wrap', content.style],
+ domProps: {
+ innerHTML: sanitize(linkfied, {
+ ALLOWED_TAGS: ['a'],
+ }),
},
- content.text,
- );
+ });
});
return h('div', { class: 'js-line log-line' }, [
diff --git a/app/assets/javascripts/jobs/components/sidebar.vue b/app/assets/javascripts/jobs/components/sidebar.vue
index aa589989e8a..8701e05a01f 100644
--- a/app/assets/javascripts/jobs/components/sidebar.vue
+++ b/app/assets/javascripts/jobs/components/sidebar.vue
@@ -1,7 +1,7 @@
<script>
import { isEmpty } from 'lodash';
import { mapActions, mapState } from 'vuex';
-import { GlLink, GlDeprecatedButton, GlIcon } from '@gitlab/ui';
+import { GlLink, GlButton, GlIcon } from '@gitlab/ui';
import { __, sprintf } from '~/locale';
import timeagoMixin from '~/vue_shared/mixins/timeago';
import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate.vue';
@@ -24,7 +24,7 @@ export default {
StagesDropdown,
JobsContainer,
GlLink,
- GlDeprecatedButton,
+ GlButton,
TooltipOnTruncate,
},
mixins: [timeagoMixin],
@@ -143,14 +143,13 @@ export default {
>
</div>
- <gl-deprecated-button
+ <gl-button
:aria-label="__('Toggle Sidebar')"
- type="button"
- class="btn btn-blank gutter-toggle float-right d-block d-md-none js-sidebar-build-toggle"
+ class="d-md-none gl-ml-2 js-sidebar-build-toggle"
+ category="tertiary"
+ icon="chevron-double-lg-right"
@click="toggleSidebar"
- >
- <i aria-hidden="true" data-hidden="true" class="fa fa-angle-double-right"></i>
- </gl-deprecated-button>
+ />
</div>
<div v-if="job.terminal_path || job.new_issue_path" class="block retry-link">
diff --git a/app/assets/javascripts/jobs/components/trigger_block.vue b/app/assets/javascripts/jobs/components/trigger_block.vue
index f55429ecdae..3cb5e63fd36 100644
--- a/app/assets/javascripts/jobs/components/trigger_block.vue
+++ b/app/assets/javascripts/jobs/components/trigger_block.vue
@@ -1,12 +1,12 @@
<script>
-import { GlDeprecatedButton } from '@gitlab/ui';
+import { GlButton } from '@gitlab/ui';
import { __ } from '~/locale';
const HIDDEN_VALUE = '••••••';
export default {
components: {
- GlDeprecatedButton,
+ GlButton,
},
props: {
trigger: {
@@ -55,11 +55,12 @@ export default {
<p class="trigger-variables-btn-container d-flex">
<span class="font-weight-bold">{{ __('Trigger variables:') }}</span>
- <gl-deprecated-button
+ <gl-button
v-if="hasValues"
- class="btn-sm group js-reveal-variables trigger-variables-btn"
+ class="group js-reveal-variables trigger-variables-btn"
+ size="small"
@click="toggleValues"
- >{{ getToggleButtonText }}</gl-deprecated-button
+ >{{ getToggleButtonText }}</gl-button
>
</p>
diff --git a/app/assets/javascripts/jobs/store/utils.js b/app/assets/javascripts/jobs/store/utils.js
index 8d6e5aac566..ea9c214de32 100644
--- a/app/assets/javascripts/jobs/store/utils.js
+++ b/app/assets/javascripts/jobs/store/utils.js
@@ -1,3 +1,5 @@
+import { parseBoolean } from '../../lib/utils/common_utils';
+
/**
* Adds the line number property
* @param Object line
@@ -17,7 +19,7 @@ export const parseLine = (line = {}, lineNumber) => ({
* @param Number lineNumber
*/
export const parseHeaderLine = (line = {}, lineNumber) => ({
- isClosed: false,
+ isClosed: parseBoolean(line.section_options?.collapsed),
isHeader: true,
line: parseLine(line, lineNumber),
lines: [],
diff --git a/app/assets/javascripts/label_manager.js b/app/assets/javascripts/label_manager.js
index 4922166acd0..469f7ce94b0 100644
--- a/app/assets/javascripts/label_manager.js
+++ b/app/assets/javascripts/label_manager.js
@@ -6,6 +6,7 @@ import Sortable from 'sortablejs';
import { deprecatedCreateFlash as flash } from './flash';
import axios from './lib/utils/axios_utils';
import { __ } from './locale';
+import { hide, dispose } from '~/tooltips';
export default class LabelManager {
constructor({ togglePriorityButton, prioritizedLabels, otherLabels } = {}) {
@@ -40,14 +41,14 @@ export default class LabelManager {
const $label = $(`#${$btn.data('domId')}`);
const action = $btn.parents('.js-prioritized-labels').length ? 'remove' : 'add';
const $tooltip = $(`#${$btn.find('.has-tooltip:visible').attr('aria-describedby')}`);
- $tooltip.tooltip('dispose');
+ dispose($tooltip);
_this.toggleLabelPriority($label, action);
_this.toggleEmptyState($label, $btn, action);
}
onButtonActionClick(e) {
e.stopPropagation();
- $(e.currentTarget).tooltip('hide');
+ hide(e.currentTarget);
}
toggleEmptyState() {
diff --git a/app/assets/javascripts/labels_select.js b/app/assets/javascripts/labels_select.js
index 8e172b4827c..8bbd4300c96 100644
--- a/app/assets/javascripts/labels_select.js
+++ b/app/assets/javascripts/labels_select.js
@@ -4,7 +4,7 @@
import $ from 'jquery';
import { difference, isEqual, escape, sortBy, template, union } from 'lodash';
-import { sprintf, s__, __ } from './locale';
+import { sprintf, __ } from './locale';
import axios from './lib/utils/axios_utils';
import IssuableBulkUpdateActions from './issuable_bulk_update_actions';
import CreateLabelDropdown from './create_label';
@@ -43,7 +43,6 @@ export default class LabelsSelect {
const $block = $selectbox.closest('.block');
const $form = $dropdown.closest('form, .js-issuable-update');
const $sidebarCollapsedValue = $block.find('.sidebar-collapsed-icon span');
- const $sidebarLabelTooltip = $block.find('.js-sidebar-labels-tooltip');
const $value = $block.find('.value');
const $dropdownMenu = $dropdown.parent().find('.dropdown-menu');
// eslint-disable-next-line no-jquery/no-fade
@@ -57,7 +56,6 @@ export default class LabelsSelect {
.get();
const scopedLabels = $dropdown.data('scopedLabels');
const { handleClick } = options;
- $sidebarLabelTooltip.tooltip();
if ($dropdown.closest('.dropdown').find('.dropdown-new-label').length) {
new CreateLabelDropdown(
@@ -91,7 +89,6 @@ export default class LabelsSelect {
axios
.put(issueUpdateURL, data)
.then(({ data }) => {
- let labelTooltipTitle;
let template;
// eslint-disable-next-line no-jquery/no-fade
$loading.fadeOut();
@@ -151,23 +148,6 @@ export default class LabelsSelect {
$value.removeAttr('style').html(template);
$sidebarCollapsedValue.text(labelCount);
- if (data.labels.length) {
- let labelTitles = data.labels.map(label => label.title);
-
- if (labelTitles.length > 5) {
- labelTitles = labelTitles.slice(0, 5);
- labelTitles.push(
- sprintf(s__('Labels|and %{count} more'), { count: data.labels.length - 5 }),
- );
- }
-
- labelTooltipTitle = labelTitles.join(', ');
- } else {
- labelTooltipTitle = __('Labels');
- }
-
- $sidebarLabelTooltip.attr('title', labelTooltipTitle).tooltip('_fixTitle');
-
$('.has-tooltip', $value).tooltip({
container: 'body',
});
diff --git a/app/assets/javascripts/layout_nav.js b/app/assets/javascripts/layout_nav.js
index d7f5e6f8a5e..4d2955a8d3d 100644
--- a/app/assets/javascripts/layout_nav.js
+++ b/app/assets/javascripts/layout_nav.js
@@ -16,6 +16,15 @@ function initDeferred() {
const whatsNewTriggerEl = document.querySelector('.js-whats-new-trigger');
if (whatsNewTriggerEl) {
+ const storageKey = whatsNewTriggerEl.getAttribute('data-storage-key');
+
+ $('.header-help').on('show.bs.dropdown', () => {
+ const displayNotification = JSON.parse(localStorage.getItem(storageKey));
+ if (displayNotification === false) {
+ $('.js-whats-new-notification-count').remove();
+ }
+ });
+
whatsNewTriggerEl.addEventListener('click', () => {
import(/* webpackChunkName: 'whatsNewApp' */ '~/whats_new')
.then(({ default: initWhatsNew }) => {
diff --git a/app/assets/javascripts/lib/dompurify.js b/app/assets/javascripts/lib/dompurify.js
new file mode 100644
index 00000000000..d9ea57fbbce
--- /dev/null
+++ b/app/assets/javascripts/lib/dompurify.js
@@ -0,0 +1,53 @@
+import { sanitize as dompurifySanitize, addHook } from 'dompurify';
+import { getBaseURL, relativePathToAbsolute } from '~/lib/utils/url_utility';
+
+// Safely allow SVG <use> tags
+
+const defaultConfig = {
+ ADD_TAGS: ['use'],
+};
+
+// Only icons urls from `gon` are allowed
+const getAllowedIconUrls = (gon = window.gon) =>
+ [gon.sprite_file_icons, gon.sprite_icons].filter(Boolean);
+
+const isUrlAllowed = url => getAllowedIconUrls().some(allowedUrl => url.startsWith(allowedUrl));
+
+const isHrefSafe = url =>
+ isUrlAllowed(url) || isUrlAllowed(relativePathToAbsolute(url, getBaseURL()));
+
+const removeUnsafeHref = (node, attr) => {
+ if (!node.hasAttribute(attr)) {
+ return;
+ }
+
+ if (!isHrefSafe(node.getAttribute(attr))) {
+ node.removeAttribute(attr);
+ }
+};
+
+/**
+ * Sanitize icons' <use> tag attributes, to safely include
+ * svgs such as in:
+ *
+ * <svg viewBox="0 0 100 100">
+ * <use href="/assets/icons-xxx.svg#icon_name"></use>
+ * </svg>
+ *
+ * @param {Object} node - Node to sanitize
+ */
+const sanitizeSvgIcon = node => {
+ removeUnsafeHref(node, 'href');
+
+ // Note: `xlink:href` is deprecated, but still in use
+ // https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/xlink:href
+ removeUnsafeHref(node, 'xlink:href');
+};
+
+addHook('afterSanitizeAttributes', node => {
+ if (node.tagName.toLowerCase() === 'use') {
+ sanitizeSvgIcon(node);
+ }
+});
+
+export const sanitize = (val, config = defaultConfig) => dompurifySanitize(val, config);
diff --git a/app/assets/javascripts/lib/graphql.js b/app/assets/javascripts/lib/graphql.js
index d2907f401c0..0e07f7d8e44 100644
--- a/app/assets/javascripts/lib/graphql.js
+++ b/app/assets/javascripts/lib/graphql.js
@@ -31,6 +31,7 @@ export default (resolvers = {}, config = {}) => {
// We set to `same-origin` which is default value in modern browsers.
// See https://github.com/whatwg/fetch/pull/585 for more information.
credentials: 'same-origin',
+ batchMax: config.batchMax || 10,
};
const uploadsLink = ApolloLink.split(
diff --git a/app/assets/javascripts/lib/utils/axios_startup_calls.js b/app/assets/javascripts/lib/utils/axios_startup_calls.js
index 7e2665b910c..7bb1da5aed5 100644
--- a/app/assets/javascripts/lib/utils/axios_startup_calls.js
+++ b/app/assets/javascripts/lib/utils/axios_startup_calls.js
@@ -7,7 +7,7 @@ const removeGitLabUrl = url => url.replace(gon.gitlab_url, '');
const getFullUrl = req => {
const url = removeGitLabUrl(req.url);
- return mergeUrlParams(req.params || {}, url);
+ return mergeUrlParams(req.params || {}, url, { sort: true });
};
const handleStartupCall = async ({ fetchCall }, req) => {
diff --git a/app/assets/javascripts/lib/utils/common_utils.js b/app/assets/javascripts/lib/utils/common_utils.js
index bcf302cc262..fe1ac00fd1d 100644
--- a/app/assets/javascripts/lib/utils/common_utils.js
+++ b/app/assets/javascripts/lib/utils/common_utils.js
@@ -44,6 +44,7 @@ export const checkPageAndAction = (page, action) => {
return pagePath === page && actionPath === action;
};
+export const isInIncidentPage = () => checkPageAndAction('incidents', 'show');
export const isInIssuePage = () => checkPageAndAction('issues', 'show');
export const isInMRPage = () => checkPageAndAction('merge_requests', 'show');
export const isInEpicPage = () => checkPageAndAction('epics', 'show');
diff --git a/app/assets/javascripts/lib/utils/constants.js b/app/assets/javascripts/lib/utils/constants.js
index 993d51370ec..1a4ecc12f01 100644
--- a/app/assets/javascripts/lib/utils/constants.js
+++ b/app/assets/javascripts/lib/utils/constants.js
@@ -1,4 +1,5 @@
export const BYTES_IN_KIB = 1024;
+export const BYTES_IN_KB = 1000;
export const HIDDEN_CLASS = 'hidden';
export const TRUNCATE_WIDTH_DEFAULT_WIDTH = 80;
export const TRUNCATE_WIDTH_DEFAULT_FONT_SIZE = 12;
diff --git a/app/assets/javascripts/lib/utils/csrf.js b/app/assets/javascripts/lib/utils/csrf.js
index ca9828c4682..3114a2a0dfb 100644
--- a/app/assets/javascripts/lib/utils/csrf.js
+++ b/app/assets/javascripts/lib/utils/csrf.js
@@ -1,5 +1,3 @@
-import $ from 'jquery';
-
/*
This module provides easy access to the CSRF token and caches
it for re-use. It also exposes some values commonly used in relation
@@ -20,7 +18,6 @@ If you need to compose a headers object, use the spread operator:
see also http://guides.rubyonrails.org/security.html#cross-site-request-forgery-csrf
and https://github.com/rails/jquery-rails/blob/v4.3.1/vendor/assets/javascripts/jquery_ujs.js#L59-L62
*/
-
const csrf = {
init() {
const tokenEl = document.querySelector('meta[name=csrf-token]');
@@ -52,9 +49,4 @@ const csrf = {
csrf.init();
-// use our cached token for any $.rails-generated AJAX requests
-if ($.rails) {
- $.rails.csrfToken = () => csrf.token;
-}
-
export default csrf;
diff --git a/app/assets/javascripts/lib/utils/css_utils.js b/app/assets/javascripts/lib/utils/css_utils.js
new file mode 100644
index 00000000000..90213221443
--- /dev/null
+++ b/app/assets/javascripts/lib/utils/css_utils.js
@@ -0,0 +1,19 @@
+export function loadCSSFile(path) {
+ return new Promise(resolve => {
+ if (document.querySelector(`link[href="${path}"]`)) {
+ resolve();
+ } else {
+ const linkElement = document.createElement('link');
+ linkElement.type = 'text/css';
+ linkElement.rel = 'stylesheet';
+ // eslint-disable-next-line @gitlab/require-i18n-strings
+ linkElement.media = 'screen,print';
+ linkElement.onload = () => {
+ resolve();
+ };
+ linkElement.href = path;
+
+ document.head.appendChild(linkElement);
+ }
+ });
+}
diff --git a/app/assets/javascripts/lib/utils/datetime_utility.js b/app/assets/javascripts/lib/utils/datetime_utility.js
index b193a8b2c9a..6e78dc87c02 100644
--- a/app/assets/javascripts/lib/utils/datetime_utility.js
+++ b/app/assets/javascripts/lib/utils/datetime_utility.js
@@ -86,6 +86,21 @@ export const getDayName = date =>
][date.getDay()];
/**
+ * Returns the i18n month name from a given date
+ * @example
+ * formatDateAsMonth(new Date('2020-06-28')) -> 'Jun'
+ * @param {String} datetime where month is extracted from
+ * @param {Object} options
+ * @param {Boolean} options.abbreviated whether to use the abbreviated month string, or not
+ * @return {String} the i18n month name
+ */
+export function formatDateAsMonth(datetime, options = {}) {
+ const { abbreviated = true } = options;
+ const month = new Date(datetime).getMonth();
+ return getMonthNames(abbreviated)[month];
+}
+
+/**
* @example
* dateFormat('2017-12-05','mmm d, yyyy h:MMtt Z' ) -> "Dec 5, 2017 12:00am GMT+0000"
* @param {date} datetime
@@ -730,6 +745,21 @@ export const differenceInSeconds = (startDate, endDate) => {
};
/**
+ * A utility function which computes the difference in months
+ * between 2 dates.
+ *
+ * @param {Date} startDate the start date
+ * @param {Date} endDate the end date
+ *
+ * @return {Int} the difference in months
+ */
+export const differenceInMonths = (startDate, endDate) => {
+ const yearDiff = endDate.getYear() - startDate.getYear();
+ const monthDiff = endDate.getMonth() - startDate.getMonth();
+ return monthDiff + 12 * yearDiff;
+};
+
+/**
* A utility function which computes the difference in milliseconds
* between 2 dates.
*
@@ -743,3 +773,22 @@ export const differenceInMilliseconds = (startDate, endDate = Date.now()) => {
const endDateInMS = endDate instanceof Date ? endDate.getTime() : endDate;
return endDateInMS - startDateInMS;
};
+
+/**
+ * A utility which returns a new date at the first day of the month for any given date.
+ *
+ * @param {Date} date
+ *
+ * @return {Date} the date at the first day of the month
+ */
+export const dateAtFirstDayOfMonth = date => new Date(newDate(date).setDate(1));
+
+/**
+ * A utility function which checks if two dates match.
+ *
+ * @param {Date|Int} date1 Can be either a date object or a unix timestamp.
+ * @param {Date|Int} date2 Can be either a date object or a unix timestamp.
+ *
+ * @return {Boolean} true if the dates match
+ */
+export const datesMatch = (date1, date2) => differenceInMilliseconds(date1, date2) === 0;
diff --git a/app/assets/javascripts/lib/utils/experimentation.js b/app/assets/javascripts/lib/utils/experimentation.js
new file mode 100644
index 00000000000..555e76055e0
--- /dev/null
+++ b/app/assets/javascripts/lib/utils/experimentation.js
@@ -0,0 +1,3 @@
+export function isExperimentEnabled(experimentKey) {
+ return Boolean(window.gon?.experiments?.[experimentKey]);
+}
diff --git a/app/assets/javascripts/lib/utils/highlight.js b/app/assets/javascripts/lib/utils/highlight.js
index 32553af9af3..8fa8af670b3 100644
--- a/app/assets/javascripts/lib/utils/highlight.js
+++ b/app/assets/javascripts/lib/utils/highlight.js
@@ -1,5 +1,5 @@
import fuzzaldrinPlus from 'fuzzaldrin-plus';
-import { sanitize } from 'dompurify';
+import { sanitize } from '~/lib/dompurify';
/**
* Wraps substring matches with HTML `<span>` elements.
diff --git a/app/assets/javascripts/lib/utils/number_utils.js b/app/assets/javascripts/lib/utils/number_utils.js
index bc87232f40b..2424d6cbf3b 100644
--- a/app/assets/javascripts/lib/utils/number_utils.js
+++ b/app/assets/javascripts/lib/utils/number_utils.js
@@ -1,4 +1,4 @@
-import { BYTES_IN_KIB } from './constants';
+import { BYTES_IN_KIB, BYTES_IN_KB } from './constants';
import { sprintf, __ } from '~/locale';
/**
@@ -35,6 +35,18 @@ export function formatRelevantDigits(number) {
}
/**
+ * Utility function that calculates KB of the given bytes.
+ * Note: This method calculates KiloBytes as opposed to
+ * Kibibytes. For Kibibytes, bytesToKiB should be used.
+ *
+ * @param {Number} number bytes
+ * @return {Number} KiB
+ */
+export function bytesToKB(number) {
+ return number / BYTES_IN_KB;
+}
+
+/**
* Utility function that calculates KiB of the given bytes.
*
* @param {Number} number bytes
diff --git a/app/assets/javascripts/lib/utils/rails_ujs.js b/app/assets/javascripts/lib/utils/rails_ujs.js
new file mode 100644
index 00000000000..8b40cc7bd11
--- /dev/null
+++ b/app/assets/javascripts/lib/utils/rails_ujs.js
@@ -0,0 +1,20 @@
+import Rails from '@rails/ujs';
+
+export const initRails = () => {
+ // eslint-disable-next-line no-underscore-dangle
+ if (!window._rails_loaded) {
+ Rails.start();
+
+ // Count XHR requests for tests. See spec/support/helpers/wait_for_requests.rb
+ window.pendingRailsUJSRequests = 0;
+ document.body.addEventListener('ajax:complete', () => {
+ window.pendingRailsUJSRequests -= 1;
+ });
+
+ document.body.addEventListener('ajax:beforeSend', () => {
+ window.pendingRailsUJSRequests += 1;
+ });
+ }
+};
+
+export { Rails };
diff --git a/app/assets/javascripts/lib/utils/text_markdown.js b/app/assets/javascripts/lib/utils/text_markdown.js
index f4c6e4e3584..dfb86787788 100644
--- a/app/assets/javascripts/lib/utils/text_markdown.js
+++ b/app/assets/javascripts/lib/utils/text_markdown.js
@@ -42,9 +42,7 @@ function convertMonacoSelectionToAceFormat(sel) {
}
function getEditorSelectionRange(editor) {
- return window.gon.features?.monacoBlobs
- ? convertMonacoSelectionToAceFormat(editor.getSelection())
- : editor.getSelectionRange();
+ return convertMonacoSelectionToAceFormat(editor.getSelection());
}
function editorBlockTagText(text, blockTag, selected, editor) {
@@ -56,9 +54,6 @@ function editorBlockTagText(text, blockTag, selected, editor) {
if (shouldRemoveBlock) {
if (blockTag !== null) {
- // ace is globally defined
- // eslint-disable-next-line no-undef
- const { Range } = ace.require('ace/range');
const lastLine = lines[selectionRange.end.row + 1];
const rangeWithBlockTags = new Range(
lines[selectionRange.start.row - 1],
@@ -110,12 +105,7 @@ function moveCursor({
const endPosition = startPosition + select.length;
return textArea.setSelectionRange(startPosition, endPosition);
} else if (editor) {
- if (window.gon.features?.monacoBlobs) {
- editor.selectWithinSelection(select, tag);
- } else {
- editor.navigateLeft(tag.length - tag.indexOf(select));
- editor.getSelection().selectAWord();
- }
+ editor.selectWithinSelection(select, tag);
return;
}
}
@@ -139,11 +129,7 @@ function moveCursor({
}
} else if (editor && editorSelectionStart.row === editorSelectionEnd.row) {
if (positionBetweenTags) {
- if (window.gon.features?.monacoBlobs) {
- editor.moveCursor(tag.length * -1);
- } else {
- editor.navigateLeft(tag.length);
- }
+ editor.moveCursor(tag.length * -1);
}
}
}
@@ -166,6 +152,7 @@ export function insertMarkdownText({
let editorSelectionEnd;
let lastNewLine;
let textToInsert;
+ selected = selected.toString();
if (editor) {
const selectionRange = getEditorSelectionRange(editor);
@@ -265,11 +252,7 @@ export function insertMarkdownText({
}
if (editor) {
- if (window.gon.features?.monacoBlobs) {
- editor.replaceSelectedText(textToInsert, select);
- } else {
- editor.insert(textToInsert);
- }
+ editor.replaceSelectedText(textToInsert, select);
} else {
insertText(textArea, textToInsert);
}
diff --git a/app/assets/javascripts/lib/utils/unit_format/index.js b/app/assets/javascripts/lib/utils/unit_format/index.js
index adf374db66c..9f979f7ea4b 100644
--- a/app/assets/javascripts/lib/utils/unit_format/index.js
+++ b/app/assets/javascripts/lib/utils/unit_format/index.js
@@ -61,8 +61,8 @@ export const getFormatter = (format = SUPPORTED_FORMATS.engineering) => {
* @function
* @param {Number} value - Number to format
* @param {Number} fractionDigits - precision decimals
- * @param {Number} maxLength - Max lenght of formatted number
- * if lenght is exceeded, exponential format is used.
+ * @param {Number} maxLength - Max length of formatted number
+ * if length is exceeded, exponential format is used.
*/
return numberFormatter();
}
@@ -73,8 +73,8 @@ export const getFormatter = (format = SUPPORTED_FORMATS.engineering) => {
* @function
* @param {Number} value - Number to format, `1` is rendered as `100%`
* @param {Number} fractionDigits - number of precision decimals
- * @param {Number} maxLength - Max lenght of formatted number
- * if lenght is exceeded, exponential format is used.
+ * @param {Number} maxLength - Max length of formatted number
+ * if length is exceeded, exponential format is used.
*/
return numberFormatter('percent');
}
@@ -85,8 +85,8 @@ export const getFormatter = (format = SUPPORTED_FORMATS.engineering) => {
* @function
* @param {Number} value - Number to format, `100` is rendered as `100%`
* @param {Number} fractionDigits - number of precision decimals
- * @param {Number} maxLength - Max lenght of formatted number
- * if lenght is exceeded, exponential format is used.
+ * @param {Number} maxLength - Max length of formatted number
+ * if length is exceeded, exponential format is used.
*/
return numberFormatter('percent', 1 / 100);
}
@@ -100,8 +100,8 @@ export const getFormatter = (format = SUPPORTED_FORMATS.engineering) => {
* @function
* @param {Number} value - Number to format, `1` is rendered as `1s`
* @param {Number} fractionDigits - number of precision decimals
- * @param {Number} maxLength - Max lenght of formatted number
- * if lenght is exceeded, exponential format is used.
+ * @param {Number} maxLength - Max length of formatted number
+ * if length is exceeded, exponential format is used.
*/
return suffixFormatter(s__('Units|s'));
}
@@ -112,8 +112,8 @@ export const getFormatter = (format = SUPPORTED_FORMATS.engineering) => {
* @function
* @param {Number} value - Number to format, `1` is formatted as `1ms`
* @param {Number} fractionDigits - number of precision decimals
- * @param {Number} maxLength - Max lenght of formatted number
- * if lenght is exceeded, exponential format is used.
+ * @param {Number} maxLength - Max length of formatted number
+ * if length is exceeded, exponential format is used.
*/
return suffixFormatter(s__('Units|ms'));
}
diff --git a/app/assets/javascripts/lib/utils/url_utility.js b/app/assets/javascripts/lib/utils/url_utility.js
index e9c3fe0a406..a9f6901de32 100644
--- a/app/assets/javascripts/lib/utils/url_utility.js
+++ b/app/assets/javascripts/lib/utils/url_utility.js
@@ -16,7 +16,7 @@ function decodeUrlParameter(val) {
return decodeURIComponent(val.replace(/\+/g, '%20'));
}
-function cleanLeadingSeparator(path) {
+export function cleanLeadingSeparator(path) {
return path.replace(PATH_SEPARATOR_LEADING_REGEX, '');
}
@@ -73,6 +73,7 @@ export function getParameterValues(sParam, url = window.location) {
* @param {String} url
* @param {Object} options
* @param {Boolean} options.spreadArrays - split array values into separate key/value-pairs
+ * @param {Boolean} options.sort - alphabetically sort params in the returned url (in asc order, i.e., a-z)
*/
export function mergeUrlParams(params, url, options = {}) {
const { spreadArrays = false, sort = false } = options;
@@ -255,6 +256,15 @@ export function getBaseURL() {
}
/**
+ * Takes a URL and returns content from the start until the final '/'
+ *
+ * @param {String} url - full url, including protocol and host
+ */
+export function stripFinalUrlSegment(url) {
+ return new URL('.', url).href;
+}
+
+/**
* Returns true if url is an absolute URL
*
* @param {String} url
@@ -282,6 +292,15 @@ export function isBase64DataUrl(url) {
}
/**
+ * Returns true if url is a blob: type url
+ *
+ * @param {String} url
+ */
+export function isBlobUrl(url) {
+ return /^blob:/.test(url);
+}
+
+/**
* Returns true if url is an absolute or root-relative URL
*
* @param {String} url
@@ -434,3 +453,24 @@ export function getHTTPProtocol(url) {
const protocol = url.split(':');
return protocol.length > 1 ? protocol[0] : undefined;
}
+
+/**
+ * Strips the filename from the given path by removing every non-slash character from the end of the
+ * passed parameter.
+ * @param {string} path
+ */
+export function stripPathTail(path = '') {
+ return path.replace(/[^/]+$/, '');
+}
+
+export function getURLOrigin(url) {
+ if (!url) {
+ return window.location.origin;
+ }
+
+ try {
+ return new URL(url).origin;
+ } catch (e) {
+ return null;
+ }
+}
diff --git a/app/assets/javascripts/logs/components/environment_logs.vue b/app/assets/javascripts/logs/components/environment_logs.vue
index 97b96cb5839..f7c0bd5ae13 100644
--- a/app/assets/javascripts/logs/components/environment_logs.vue
+++ b/app/assets/javascripts/logs/components/environment_logs.vue
@@ -3,12 +3,11 @@ import { throttle } from 'lodash';
import { mapActions, mapState, mapGetters } from 'vuex';
import {
GlSprintf,
- GlIcon,
GlAlert,
- GlDeprecatedDropdown,
- GlDeprecatedDropdownHeader,
- GlDeprecatedDropdownItem,
- GlDeprecatedDropdownDivider,
+ GlDropdown,
+ GlDropdownSectionHeader,
+ GlDropdownItem,
+ GlDropdownDivider,
GlInfiniteScroll,
} from '@gitlab/ui';
@@ -23,12 +22,11 @@ import { formatDate } from '../utils';
export default {
components: {
GlSprintf,
- GlIcon,
GlAlert,
- GlDeprecatedDropdown,
- GlDeprecatedDropdownHeader,
- GlDeprecatedDropdownItem,
- GlDeprecatedDropdownDivider,
+ GlDropdown,
+ GlDropdownSectionHeader,
+ GlDropdownItem,
+ GlDropdownDivider,
GlInfiniteScroll,
LogSimpleFilters,
LogAdvancedFilters,
@@ -174,46 +172,38 @@ export default {
<div class="top-bar d-md-flex border bg-secondary-50 pt-2 pr-1 pb-0 pl-2">
<div class="flex-grow-0">
- <gl-deprecated-dropdown
+ <gl-dropdown
id="environments-dropdown"
:text="environments.current || managedApps.current"
:disabled="environments.isLoading"
- class="mb-2 gl-h-32 pr-2 d-flex d-md-block js-environments-dropdown"
+ class="gl-mr-3 gl-mb-3 gl-display-flex gl-display-md-block js-environments-dropdown"
>
- <gl-deprecated-dropdown-header class="gl-text-center">
+ <gl-dropdown-section-header>
{{ s__('Environments|Environments') }}
- </gl-deprecated-dropdown-header>
- <gl-deprecated-dropdown-item
+ </gl-dropdown-section-header>
+ <gl-dropdown-item
v-for="env in environments.options"
:key="env.id"
+ :is-check-item="true"
+ :is-checked="isCurrentEnvironment(env.name)"
@click="showEnvironment(env.name)"
>
- <div class="d-flex">
- <gl-icon
- :class="{ invisible: !isCurrentEnvironment(env.name) }"
- name="status_success_borderless"
- />
- <div class="gl-flex-grow-1">{{ env.name }}</div>
- </div>
- </gl-deprecated-dropdown-item>
- <gl-deprecated-dropdown-divider />
- <gl-deprecated-dropdown-header class="gl-text-center">
+ {{ env.name }}
+ </gl-dropdown-item>
+ <gl-dropdown-divider />
+ <gl-dropdown-section-header>
{{ s__('Environments|Managed apps') }}
- </gl-deprecated-dropdown-header>
- <gl-deprecated-dropdown-item
+ </gl-dropdown-section-header>
+ <gl-dropdown-item
v-for="app in managedApps.options"
:key="app.id"
+ :is-check-item="true"
+ :is-checked="isCurrentManagedApp(app.name)"
@click="showManagedApp(app.name)"
>
- <div class="gl-display-flex">
- <gl-icon
- :class="{ invisible: !isCurrentManagedApp(app.name) }"
- name="status_success_borderless"
- />
- <div class="gl-flex-grow-1">{{ app.name }}</div>
- </div>
- </gl-deprecated-dropdown-item>
- </gl-deprecated-dropdown>
+ {{ app.name }}
+ </gl-dropdown-item>
+ </gl-dropdown>
</div>
<log-advanced-filters
diff --git a/app/assets/javascripts/logs/components/log_simple_filters.vue b/app/assets/javascripts/logs/components/log_simple_filters.vue
index 2e1270b5428..ba30d4628c9 100644
--- a/app/assets/javascripts/logs/components/log_simple_filters.vue
+++ b/app/assets/javascripts/logs/components/log_simple_filters.vue
@@ -1,19 +1,13 @@
<script>
import { mapActions, mapState } from 'vuex';
-import {
- GlIcon,
- GlDeprecatedDropdown,
- GlDeprecatedDropdownHeader,
- GlDeprecatedDropdownItem,
-} from '@gitlab/ui';
+import { GlDropdown, GlDropdownSectionHeader, GlDropdownItem } from '@gitlab/ui';
import { s__ } from '~/locale';
export default {
components: {
- GlIcon,
- GlDeprecatedDropdown,
- GlDeprecatedDropdownHeader,
- GlDeprecatedDropdownItem,
+ GlDropdown,
+ GlDropdownSectionHeader,
+ GlDropdownItem,
},
props: {
disabled: {
@@ -44,35 +38,31 @@ export default {
</script>
<template>
<div>
- <gl-deprecated-dropdown
+ <gl-dropdown
ref="podsDropdown"
:text="podDropdownText"
:disabled="disabled"
- class="mb-2 gl-h-32 pr-2 d-flex d-md-block flex-grow-0 qa-pods-dropdown"
+ class="gl-mr-3 gl-mb-3 gl-display-flex gl-display-md-block qa-pods-dropdown"
>
- <gl-deprecated-dropdown-header class="text-center">
+ <gl-dropdown-section-header>
{{ s__('Environments|Select pod') }}
- </gl-deprecated-dropdown-header>
+ </gl-dropdown-section-header>
- <gl-deprecated-dropdown-item v-if="!pods.options.length" disabled>
+ <gl-dropdown-item v-if="!pods.options.length" disabled>
<span ref="noPodsMsg" class="text-muted">
{{ s__('Environments|No pods to display') }}
</span>
- </gl-deprecated-dropdown-item>
- <gl-deprecated-dropdown-item
+ </gl-dropdown-item>
+ <gl-dropdown-item
v-for="podName in pods.options"
:key="podName"
+ :is-check-item="true"
+ :is-checked="isCurrentPod(podName)"
class="text-nowrap"
@click="showPodLogs(podName)"
>
- <div class="d-flex">
- <gl-icon
- :class="{ invisible: !isCurrentPod(podName) }"
- name="status_success_borderless"
- />
- <div class="flex-grow-1">{{ podName }}</div>
- </div>
- </gl-deprecated-dropdown-item>
- </gl-deprecated-dropdown>
+ {{ podName }}
+ </gl-dropdown-item>
+ </gl-dropdown>
</div>
</template>
diff --git a/app/assets/javascripts/main.js b/app/assets/javascripts/main.js
index 9fcf881a1ac..d60f949c49d 100644
--- a/app/assets/javascripts/main.js
+++ b/app/assets/javascripts/main.js
@@ -11,6 +11,7 @@ import './behaviors';
// lib/utils
import applyGitLabUIConfig from '@gitlab/ui/dist/config';
import { GlBreakpointInstance as bp } from '@gitlab/ui/dist/utils';
+import { initRails } from '~/lib/utils/rails_ujs';
import {
handleLocationHash,
addSelectOnFocusBehaviour,
@@ -38,6 +39,8 @@ import initPersistentUserCallouts from './persistent_user_callouts';
import { initUserTracking, initDefaultTrackers } from './tracking';
import { __ } from './locale';
+import * as tooltips from '~/tooltips';
+
import 'ee_else_ce/main_ee';
applyGitLabUIConfig();
@@ -76,7 +79,7 @@ document.addEventListener('beforeunload', () => {
// Unbind scroll events
$(document).off('scroll');
// Close any open tooltips
- $('.has-tooltip, [data-toggle="tooltip"]').tooltip('dispose');
+ tooltips.dispose(document.querySelectorAll('.has-tooltip, [data-toggle="tooltip"]'));
// Close any open popover
$('[data-toggle="popover"]').popover('dispose');
});
@@ -96,6 +99,8 @@ gl.lazyLoader = new LazyLoader({
observerNode: '#content-body',
});
+initRails();
+
// Put all initialisations here that can also wait after everything is rendered and ready
function deferredInitialisation() {
const $body = $('body');
@@ -130,8 +135,10 @@ function deferredInitialisation() {
addSelectOnFocusBehaviour('.js-select-on-focus');
$('.remove-row').on('ajax:success', function removeRowAjaxSuccessCallback() {
+ tooltips.dispose(this);
+
+ // eslint-disable-next-line no-jquery/no-fade
$(this)
- .tooltip('dispose')
.closest('li')
.fadeOut();
});
@@ -151,7 +158,7 @@ function deferredInitialisation() {
const delay = glTooltipDelay ? JSON.parse(glTooltipDelay) : 0;
// Initialize tooltips
- $body.tooltip({
+ tooltips.initTooltips({
selector: '.has-tooltip, [data-toggle="tooltip"]',
trigger: 'hover',
boundary: 'viewport',
diff --git a/app/assets/javascripts/members.js b/app/assets/javascripts/members.js
index c3fbb5d6acf..6dd4018f87a 100644
--- a/app/assets/javascripts/members.js
+++ b/app/assets/javascripts/members.js
@@ -1,6 +1,8 @@
import $ from 'jquery';
+import { Rails } from '~/lib/utils/rails_ujs';
import { disableButtonIfEmptyField } from '~/lib/utils/common_utils';
import initDeprecatedJQueryDropdown from '~/deprecated_jquery_dropdown';
+import { __, sprintf } from '~/locale';
export default class Members {
constructor() {
@@ -54,15 +56,43 @@ export default class Members {
formSubmit(e, $el = null) {
const $this = e ? $(e.currentTarget) : $el;
const { $toggle, $dateInput } = this.getMemberListItems($this);
+ const formEl = $this.closest('form').get(0);
- $this.closest('form').trigger('submit.rails');
+ Rails.fire(formEl, 'submit');
$toggle.disable();
$dateInput.disable();
}
formSuccess(e) {
- const { $toggle, $dateInput } = this.getMemberListItems($(e.currentTarget).closest('.member'));
+ const { $toggle, $dateInput, $expiresIn, $expiresInText } = this.getMemberListItems(
+ $(e.currentTarget).closest('.js-member'),
+ );
+
+ const [data] = e.detail;
+ const expiresIn = data?.expires_in;
+
+ if (expiresIn) {
+ $expiresIn.removeClass('gl-display-none');
+
+ $expiresInText.text(sprintf(__('Expires in %{expires_at}'), { expires_at: expiresIn }));
+
+ const { expires_soon: expiresSoon, expires_at_formatted: expiresAtFormatted } = data;
+
+ if (expiresSoon) {
+ $expiresInText.addClass('text-warning');
+ } else {
+ $expiresInText.removeClass('text-warning');
+ }
+
+ // Update tooltip
+ if (expiresAtFormatted) {
+ $expiresInText.attr('title', expiresAtFormatted);
+ $expiresInText.attr('data-original-title', expiresAtFormatted);
+ }
+ } else {
+ $expiresIn.addClass('gl-display-none');
+ }
$toggle.enable();
$dateInput.enable();
@@ -70,10 +100,12 @@ export default class Members {
// eslint-disable-next-line class-methods-use-this
getMemberListItems($el) {
- const $memberListItem = $el.is('.member') ? $el : $(`#${$el.data('elId')}`);
+ const $memberListItem = $el.is('.js-member') ? $el : $(`#${$el.data('elId')}`);
return {
$memberListItem,
+ $expiresIn: $memberListItem.find('.js-expires-in'),
+ $expiresInText: $memberListItem.find('.js-expires-in-text'),
$toggle: $memberListItem.find('.dropdown-menu-toggle'),
$dateInput: $memberListItem.find('.js-access-expiration-date'),
};
diff --git a/app/assets/javascripts/merge_request.js b/app/assets/javascripts/merge_request.js
index 79a4c3700ef..fe4e2cee69f 100644
--- a/app/assets/javascripts/merge_request.js
+++ b/app/assets/javascripts/merge_request.js
@@ -3,11 +3,12 @@
import $ from 'jquery';
import axios from './lib/utils/axios_utils';
import { __ } from '~/locale';
+import eventHub from '~/vue_merge_request_widget/event_hub';
import { deprecatedCreateFlash as createFlash } from '~/flash';
import TaskList from './task_list';
import MergeRequestTabs from './merge_request_tabs';
-import IssuablesHelper from './helpers/issuables_helper';
import { addDelimiter } from './lib/utils/text_utility';
+import { getParameterValues, setUrlParams } from './lib/utils/url_utility';
function MergeRequest(opts) {
// Initialize MergeRequest behavior
@@ -23,7 +24,6 @@ function MergeRequest(opts) {
this.initTabs();
this.initMRBtnListeners();
this.initCommitMessageListeners();
- this.closeReopenReportToggle = IssuablesHelper.initCloseReopenReport();
if ($('.description.js-task-list-container').length) {
this.taskList = new TaskList({
@@ -66,13 +66,38 @@ MergeRequest.prototype.showAllCommits = function() {
MergeRequest.prototype.initMRBtnListeners = function() {
const _this = this;
+ const draftToggles = document.querySelectorAll('.js-draft-toggle-button');
- $('.report-abuse-link').on('click', e => {
- // this is needed because of the implementation of
- // the dropdown toggle and Report Abuse needing to be
- // linked to another page.
- e.stopPropagation();
- });
+ if (draftToggles.length) {
+ draftToggles.forEach(draftToggle => {
+ draftToggle.addEventListener('click', e => {
+ e.preventDefault();
+ e.stopImmediatePropagation();
+
+ const url = draftToggle.href;
+ const wipEvent = getParameterValues('merge_request[wip_event]', url)[0];
+ const mobileDropdown = draftToggle.closest('.dropdown.show');
+
+ if (mobileDropdown) {
+ $(mobileDropdown.firstElementChild).dropdown('toggle');
+ }
+
+ draftToggle.setAttribute('disabled', 'disabled');
+
+ axios
+ .put(draftToggle.href, null, { params: { format: 'json' } })
+ .then(({ data }) => {
+ draftToggle.removeAttribute('disabled');
+ eventHub.$emit('MRWidgetUpdateRequested');
+ MergeRequest.toggleDraftStatus(data.title, wipEvent === 'unwip');
+ })
+ .catch(() => {
+ draftToggle.removeAttribute('disabled');
+ createFlash(__('Something went wrong. Please try again.'));
+ });
+ });
+ });
+ }
return $('.btn-close, .btn-reopen').on('click', function(e) {
const $this = $(this);
@@ -89,8 +114,6 @@ MergeRequest.prototype.initMRBtnListeners = function() {
return;
}
- if (this.closeReopenReportToggle) this.closeReopenReportToggle.setDisable();
-
if (shouldSubmit) {
if ($this.hasClass('btn-comment-and-close') || $this.hasClass('btn-comment-and-reopen')) {
e.preventDefault();
@@ -151,14 +174,35 @@ MergeRequest.hideCloseButton = function() {
const closeDropdownItem = el.querySelector('li.close-item');
if (closeDropdownItem) {
closeDropdownItem.classList.add('hidden');
- // Selects the next dropdown item
- el.querySelector('li.report-item').click();
- } else {
- // No dropdown just hide the Close button
- el.querySelector('.btn-close').classList.add('hidden');
}
// Dropdown for mobile screen
el.querySelector('li.js-close-item').classList.add('hidden');
};
+MergeRequest.toggleDraftStatus = function(title, isReady) {
+ if (isReady) {
+ createFlash(__('The merge request can now be merged.'), 'notice');
+ }
+ const titleEl = document.querySelector('.merge-request .detail-page-description .title');
+
+ if (titleEl) {
+ titleEl.textContent = title;
+ }
+
+ const draftToggles = document.querySelectorAll('.js-draft-toggle-button');
+
+ if (draftToggles.length) {
+ draftToggles.forEach(el => {
+ const draftToggle = el;
+ const url = setUrlParams(
+ { 'merge_request[wip_event]': isReady ? 'wip' : 'unwip' },
+ draftToggle.href,
+ );
+
+ draftToggle.setAttribute('href', url);
+ draftToggle.textContent = isReady ? __('Mark as draft') : __('Mark as ready');
+ });
+ }
+};
+
export default MergeRequest;
diff --git a/app/assets/javascripts/merge_request_tabs.js b/app/assets/javascripts/merge_request_tabs.js
index b7cf39db00c..bdcdabe8f78 100644
--- a/app/assets/javascripts/merge_request_tabs.js
+++ b/app/assets/javascripts/merge_request_tabs.js
@@ -396,10 +396,6 @@ export default class MergeRequestTabs {
initChangesDropdown(this.stickyTop);
- if (typeof gl.diffNotesCompileComponents !== 'undefined') {
- gl.diffNotesCompileComponents();
- }
-
localTimeAgo($('.js-timeago', 'div#diffs'));
syntaxHighlight($('#diffs .js-syntax-highlight'));
@@ -482,13 +478,14 @@ export default class MergeRequestTabs {
}
shrinkView() {
- const $gutterIcon = $('.js-sidebar-toggle i:visible');
+ const $gutterBtn = $('.js-sidebar-toggle:visible');
+ const $expandSvg = $gutterBtn.find('.js-sidebar-expand');
// Wait until listeners are set
setTimeout(() => {
// Only when sidebar is expanded
- if ($gutterIcon.is('.fa-angle-double-right')) {
- $gutterIcon.closest('a').trigger('click', [true]);
+ if ($expandSvg.length && $expandSvg.hasClass('hidden')) {
+ $gutterBtn.trigger('click', [true]);
}
}, 0);
}
@@ -498,13 +495,14 @@ export default class MergeRequestTabs {
if (parseBoolean(Cookies.get('collapsed_gutter'))) {
return;
}
- const $gutterIcon = $('.js-sidebar-toggle i:visible');
+ const $gutterBtn = $('.js-sidebar-toggle');
+ const $collapseSvg = $gutterBtn.find('.js-sidebar-collapse');
// Wait until listeners are set
setTimeout(() => {
// Only when sidebar is collapsed
- if ($gutterIcon.is('.fa-angle-double-left')) {
- $gutterIcon.closest('a').trigger('click', [true]);
+ if ($collapseSvg.length && !$collapseSvg.hasClass('hidden')) {
+ $gutterBtn.trigger('click', [true]);
}
}, 0);
}
diff --git a/app/assets/javascripts/milestone.js b/app/assets/javascripts/milestone.js
index 20d9fb82554..52e9b67c77d 100644
--- a/app/assets/javascripts/milestone.js
+++ b/app/assets/javascripts/milestone.js
@@ -7,11 +7,6 @@ import { __ } from './locale';
export default class Milestone {
constructor() {
this.bindTabsSwitching();
-
- // Load merge request tab if it is active
- // merge request tab is active based on different conditions in the backend
- this.loadTab($('.js-milestone-tabs .active a'));
-
this.loadInitialTab();
}
@@ -23,12 +18,14 @@ export default class Milestone {
this.loadTab($target);
});
}
- // eslint-disable-next-line class-methods-use-this
+
loadInitialTab() {
- const $target = $(`.js-milestone-tabs a[href="${window.location.hash}"]`);
+ const $target = $(`.js-milestone-tabs a:not(.active)[href="${window.location.hash}"]`);
if ($target.length) {
$target.tab('show');
+ } else {
+ this.loadTab($('.js-milestone-tabs a.active'));
}
}
// eslint-disable-next-line class-methods-use-this
diff --git a/app/assets/javascripts/milestones/project_milestone_combobox.vue b/app/assets/javascripts/milestones/project_milestone_combobox.vue
index 5ee917573ce..0fa5585e858 100644
--- a/app/assets/javascripts/milestones/project_milestone_combobox.vue
+++ b/app/assets/javascripts/milestones/project_milestone_combobox.vue
@@ -205,7 +205,6 @@ export default {
<gl-search-box-by-type
ref="searchBox"
v-model.trim="searchQuery"
- class="gl-m-3"
:placeholder="this.$options.translations.searchMilestones"
@input="onSearchBoxInput"
@keydown.enter.prevent="onSearchBoxEnter"
diff --git a/app/assets/javascripts/milestones/stores/actions.js b/app/assets/javascripts/milestones/stores/actions.js
new file mode 100644
index 00000000000..3859771aeba
--- /dev/null
+++ b/app/assets/javascripts/milestones/stores/actions.js
@@ -0,0 +1,58 @@
+import Api from '~/api';
+import * as types from './mutation_types';
+
+export const setProjectId = ({ commit }, projectId) => commit(types.SET_PROJECT_ID, projectId);
+
+export const setSelectedMilestones = ({ commit }, selectedMilestones) =>
+ commit(types.SET_SELECTED_MILESTONES, selectedMilestones);
+
+export const toggleMilestones = ({ commit, state }, selectedMilestone) => {
+ const removeMilestone = state.selectedMilestones.includes(selectedMilestone);
+
+ if (removeMilestone) {
+ commit(types.REMOVE_SELECTED_MILESTONE, selectedMilestone);
+ } else {
+ commit(types.ADD_SELECTED_MILESTONE, selectedMilestone);
+ }
+};
+
+export const search = ({ dispatch, commit }, query) => {
+ commit(types.SET_QUERY, query);
+
+ dispatch('searchMilestones');
+};
+
+export const fetchMilestones = ({ commit, state }) => {
+ commit(types.REQUEST_START);
+
+ Api.projectMilestones(state.projectId)
+ .then(response => {
+ commit(types.RECEIVE_PROJECT_MILESTONES_SUCCESS, response);
+ })
+ .catch(error => {
+ commit(types.RECEIVE_PROJECT_MILESTONES_ERROR, error);
+ })
+ .finally(() => {
+ commit(types.REQUEST_FINISH);
+ });
+};
+
+export const searchMilestones = ({ commit, state }) => {
+ commit(types.REQUEST_START);
+
+ const options = {
+ search: state.query,
+ scope: 'milestones',
+ };
+
+ Api.projectSearch(state.projectId, options)
+ .then(response => {
+ commit(types.RECEIVE_PROJECT_MILESTONES_SUCCESS, response);
+ })
+ .catch(error => {
+ commit(types.RECEIVE_PROJECT_MILESTONES_ERROR, error);
+ })
+ .finally(() => {
+ commit(types.REQUEST_FINISH);
+ });
+};
diff --git a/app/assets/javascripts/milestones/stores/getters.js b/app/assets/javascripts/milestones/stores/getters.js
new file mode 100644
index 00000000000..d8a283403ec
--- /dev/null
+++ b/app/assets/javascripts/milestones/stores/getters.js
@@ -0,0 +1,2 @@
+/** Returns `true` if there is at least one in-progress request */
+export const isLoading = ({ requestCount }) => requestCount > 0;
diff --git a/app/assets/javascripts/milestones/stores/index.js b/app/assets/javascripts/milestones/stores/index.js
new file mode 100644
index 00000000000..2bebffc19ab
--- /dev/null
+++ b/app/assets/javascripts/milestones/stores/index.js
@@ -0,0 +1,16 @@
+import Vue from 'vue';
+import Vuex from 'vuex';
+import * as actions from './actions';
+import * as getters from './getters';
+import mutations from './mutations';
+import createState from './state';
+
+Vue.use(Vuex);
+
+export default () =>
+ new Vuex.Store({
+ actions,
+ getters,
+ mutations,
+ state: createState(),
+ });
diff --git a/app/assets/javascripts/milestones/stores/mutation_types.js b/app/assets/javascripts/milestones/stores/mutation_types.js
new file mode 100644
index 00000000000..370d386dba2
--- /dev/null
+++ b/app/assets/javascripts/milestones/stores/mutation_types.js
@@ -0,0 +1,13 @@
+export const SET_PROJECT_ID = 'SET_PROJECT_ID';
+
+export const SET_SELECTED_MILESTONES = 'SET_SELECTED_MILESTONES';
+export const ADD_SELECTED_MILESTONE = 'ADD_SELECTED_MILESTONE';
+export const REMOVE_SELECTED_MILESTONE = 'REMOVE_SELECTED_MILESTONE';
+
+export const SET_QUERY = 'SET_QUERY';
+
+export const REQUEST_START = 'REQUEST_START';
+export const REQUEST_FINISH = 'REQUEST_FINISH';
+
+export const RECEIVE_PROJECT_MILESTONES_SUCCESS = 'RECEIVE_PROJECT_MILESTONES_SUCCESS';
+export const RECEIVE_PROJECT_MILESTONES_ERROR = 'RECEIVE_PROJECT_MILESTONES_ERROR';
diff --git a/app/assets/javascripts/milestones/stores/mutations.js b/app/assets/javascripts/milestones/stores/mutations.js
new file mode 100644
index 00000000000..7c75d09766c
--- /dev/null
+++ b/app/assets/javascripts/milestones/stores/mutations.js
@@ -0,0 +1,44 @@
+import Vue from 'vue';
+import * as types from './mutation_types';
+import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
+
+export default {
+ [types.SET_PROJECT_ID](state, projectId) {
+ state.projectId = projectId;
+ },
+ [types.SET_SELECTED_MILESTONES](state, selectedMilestones) {
+ Vue.set(state, 'selectedMilestones', selectedMilestones);
+ },
+ [types.ADD_SELECTED_MILESTONE](state, selectedMilestone) {
+ state.selectedMilestones.push(selectedMilestone);
+ },
+ [types.REMOVE_SELECTED_MILESTONE](state, selectedMilestone) {
+ const filteredMilestones = state.selectedMilestones.filter(
+ milestone => milestone !== selectedMilestone,
+ );
+ Vue.set(state, 'selectedMilestones', filteredMilestones);
+ },
+ [types.SET_QUERY](state, query) {
+ state.query = query;
+ },
+ [types.REQUEST_START](state) {
+ state.requestCount += 1;
+ },
+ [types.REQUEST_FINISH](state) {
+ state.requestCount -= 1;
+ },
+ [types.RECEIVE_PROJECT_MILESTONES_SUCCESS](state, response) {
+ state.matches.projectMilestones = {
+ list: convertObjectPropsToCamelCase(response.data).map(({ title }) => ({ title })),
+ totalCount: parseInt(response.headers['x-total'], 10),
+ error: null,
+ };
+ },
+ [types.RECEIVE_PROJECT_MILESTONES_ERROR](state, error) {
+ state.matches.projectMilestones = {
+ list: [],
+ totalCount: 0,
+ error,
+ };
+ },
+};
diff --git a/app/assets/javascripts/milestones/stores/state.js b/app/assets/javascripts/milestones/stores/state.js
new file mode 100644
index 00000000000..0944539f367
--- /dev/null
+++ b/app/assets/javascripts/milestones/stores/state.js
@@ -0,0 +1,14 @@
+export default () => ({
+ projectId: null,
+ groupId: null,
+ query: '',
+ matches: {
+ projectMilestones: {
+ list: [],
+ totalCount: 0,
+ error: null,
+ },
+ },
+ selectedMilestones: [],
+ requestCount: 0,
+});
diff --git a/app/assets/javascripts/mirrors/mirror_repos.js b/app/assets/javascripts/mirrors/mirror_repos.js
index cc787613c52..818ca8aa847 100644
--- a/app/assets/javascripts/mirrors/mirror_repos.js
+++ b/app/assets/javascripts/mirrors/mirror_repos.js
@@ -4,6 +4,7 @@ import { __ } from '~/locale';
import { deprecatedCreateFlash as Flash } from '~/flash';
import axios from '~/lib/utils/axios_utils';
import SSHMirror from './ssh_mirror';
+import { hide } from '~/tooltips';
export default class MirrorRepos {
constructor(container) {
@@ -115,7 +116,7 @@ export default class MirrorRepos {
/* eslint-disable class-methods-use-this */
removeRow($target) {
const row = $target.closest('tr');
- $('.js-delete-mirror', row).tooltip('hide');
+ hide($('.js-delete-mirror', row));
row.remove();
}
/* eslint-enable class-methods-use-this */
diff --git a/app/assets/javascripts/monitoring/components/alert_widget_form.vue b/app/assets/javascripts/monitoring/components/alert_widget_form.vue
index 132df9c9516..6f29b34141d 100644
--- a/app/assets/javascripts/monitoring/components/alert_widget_form.vue
+++ b/app/assets/javascripts/monitoring/components/alert_widget_form.vue
@@ -3,7 +3,7 @@ import { isEmpty, findKey } from 'lodash';
import Vue from 'vue';
import {
GlLink,
- GlDeprecatedButton,
+ GlButton,
GlButtonGroup,
GlFormGroup,
GlFormInput,
@@ -36,7 +36,7 @@ const SUBMIT_BUTTON_CLASS = {
export default {
components: {
- GlDeprecatedButton,
+ GlButton,
GlButtonGroup,
GlFormGroup,
GlFormInput,
@@ -267,30 +267,27 @@ export default {
</gl-dropdown>
</gl-form-group>
<gl-button-group class="mb-3" :label="s__('PrometheusAlerts|Operator')">
- <gl-deprecated-button
+ <gl-button
:class="{ active: operator === operators.greaterThan }"
:disabled="formDisabled"
- type="button"
@click="operator = operators.greaterThan"
>
{{ operators.greaterThan }}
- </gl-deprecated-button>
- <gl-deprecated-button
+ </gl-button>
+ <gl-button
:class="{ active: operator === operators.equalTo }"
:disabled="formDisabled"
- type="button"
@click="operator = operators.equalTo"
>
{{ operators.equalTo }}
- </gl-deprecated-button>
- <gl-deprecated-button
+ </gl-button>
+ <gl-button
:class="{ active: operator === operators.lessThan }"
:disabled="formDisabled"
- type="button"
@click="operator = operators.lessThan"
>
{{ operators.lessThan }}
- </gl-deprecated-button>
+ </gl-button>
</gl-button-group>
<gl-form-group :label="s__('PrometheusAlerts|Threshold')" label-for="alerts-threshold">
<gl-form-input
diff --git a/app/assets/javascripts/monitoring/components/dashboard_header.vue b/app/assets/javascripts/monitoring/components/dashboard_header.vue
index e468728a954..0f6a9ce3814 100644
--- a/app/assets/javascripts/monitoring/components/dashboard_header.vue
+++ b/app/assets/javascripts/monitoring/components/dashboard_header.vue
@@ -192,7 +192,7 @@ export default {
>
<div class="d-flex flex-column overflow-hidden">
<gl-dropdown-section-header>{{ __('Environment') }}</gl-dropdown-section-header>
- <gl-search-box-by-type class="gl-m-3" @input="debouncedEnvironmentsSearch" />
+ <gl-search-box-by-type @input="debouncedEnvironmentsSearch" />
<gl-loading-icon v-if="environmentsLoading" :inline="true" />
<div v-else class="flex-fill overflow-auto">
diff --git a/app/assets/javascripts/monitoring/components/dashboards_dropdown.vue b/app/assets/javascripts/monitoring/components/dashboards_dropdown.vue
index 932efeaaf0e..1a349aa154a 100644
--- a/app/assets/javascripts/monitoring/components/dashboards_dropdown.vue
+++ b/app/assets/javascripts/monitoring/components/dashboards_dropdown.vue
@@ -80,11 +80,7 @@ export default {
>
<div class="d-flex flex-column overflow-hidden">
<gl-dropdown-section-header>{{ __('Dashboard') }}</gl-dropdown-section-header>
- <gl-search-box-by-type
- ref="monitorDashboardsDropdownSearch"
- v-model="searchTerm"
- class="gl-m-3"
- />
+ <gl-search-box-by-type ref="monitorDashboardsDropdownSearch" v-model="searchTerm" />
<div class="flex-fill overflow-auto">
<gl-dropdown-item
diff --git a/app/assets/javascripts/monitoring/components/group_empty_state.vue b/app/assets/javascripts/monitoring/components/group_empty_state.vue
index 499823fae3f..0365fc66331 100644
--- a/app/assets/javascripts/monitoring/components/group_empty_state.vue
+++ b/app/assets/javascripts/monitoring/components/group_empty_state.vue
@@ -1,6 +1,5 @@
<script>
-/* eslint-disable vue/no-v-html */
-import { GlEmptyState } from '@gitlab/ui';
+import { GlEmptyState, GlSafeHtmlDirective as SafeHtml } from '@gitlab/ui';
import { __, sprintf } from '~/locale';
import { metricStates } from '../constants';
@@ -8,6 +7,9 @@ export default {
components: {
GlEmptyState,
},
+ directives: {
+ SafeHtml,
+ },
props: {
documentationPath: {
type: String,
@@ -100,7 +102,7 @@ export default {
:compact="true"
>
<template v-if="currentState.slottedDescription" #description>
- <div v-html="currentState.slottedDescription"></div>
+ <div v-safe-html="currentState.slottedDescription"></div>
</template>
</gl-empty-state>
</template>
diff --git a/app/assets/javascripts/monitoring/stores/actions.js b/app/assets/javascripts/monitoring/stores/actions.js
index 16a685305dc..e7391a4c9d1 100644
--- a/app/assets/javascripts/monitoring/stores/actions.js
+++ b/app/assets/javascripts/monitoring/stores/actions.js
@@ -1,4 +1,4 @@
-import * as Sentry from '@sentry/browser';
+import * as Sentry from '~/sentry/wrapper';
import * as types from './mutation_types';
import axios from '~/lib/utils/axios_utils';
import { deprecatedCreateFlash as createFlash } from '~/flash';
diff --git a/app/assets/javascripts/namespaces/leave_by_url.js b/app/assets/javascripts/namespaces/leave_by_url.js
index bf77617d516..7b15253d872 100644
--- a/app/assets/javascripts/namespaces/leave_by_url.js
+++ b/app/assets/javascripts/namespaces/leave_by_url.js
@@ -1,3 +1,4 @@
+import { initRails } from '~/lib/utils/rails_ujs';
import { deprecatedCreateFlash as Flash } from '~/flash';
import { __, sprintf } from '~/locale';
import { getParameterByName } from '~/lib/utils/common_utils';
@@ -11,6 +12,8 @@ export default function leaveByUrl(namespaceType) {
const param = getParameterByName(PARAMETER_NAME);
if (!param) return;
+ initRails();
+
const leaveLink = document.querySelector(LEAVE_LINK_SELECTOR);
if (leaveLink) {
leaveLink.click();
diff --git a/app/assets/javascripts/notebook/cells/markdown.vue b/app/assets/javascripts/notebook/cells/markdown.vue
index 3bbaa44ec42..c04f2a2d465 100644
--- a/app/assets/javascripts/notebook/cells/markdown.vue
+++ b/app/assets/javascripts/notebook/cells/markdown.vue
@@ -1,8 +1,8 @@
<script>
/* eslint-disable vue/no-v-html */
import marked from 'marked';
-import { sanitize } from 'dompurify';
import katex from 'katex';
+import { sanitize } from '~/lib/dompurify';
import Prompt from './prompt.vue';
const renderer = new marked.Renderer();
diff --git a/app/assets/javascripts/notebook/cells/output/html.vue b/app/assets/javascripts/notebook/cells/output/html.vue
index 856c8f31796..4d527baf730 100644
--- a/app/assets/javascripts/notebook/cells/output/html.vue
+++ b/app/assets/javascripts/notebook/cells/output/html.vue
@@ -1,6 +1,6 @@
<script>
/* eslint-disable vue/no-v-html */
-import { sanitize } from 'dompurify';
+import { sanitize } from '~/lib/dompurify';
import Prompt from '../prompt.vue';
export default {
diff --git a/app/assets/javascripts/notes.js b/app/assets/javascripts/notes.js
index 340fbe4d887..37bb79defd1 100644
--- a/app/assets/javascripts/notes.js
+++ b/app/assets/javascripts/notes.js
@@ -479,11 +479,6 @@ export default class Notes {
row = form;
}
- const lineType = this.isParallelView() ? form.find('#line_type').val() : 'old';
- const diffAvatarContainer = row
- .prevAll('.line_holder')
- .first()
- .find(`.js-avatar-container.${lineType}_line`);
// is this the first note of discussion?
discussionContainer = $(`.notes[data-discussion-id="${noteEntity.discussion_id}"]`);
if (!discussionContainer.length) {
@@ -519,12 +514,6 @@ export default class Notes {
Notes.animateAppendNote(noteEntity.html, discussionContainer);
}
- if (typeof gl.diffNotesCompileComponents !== 'undefined' && noteEntity.discussion_resolvable) {
- gl.diffNotesCompileComponents();
-
- this.renderDiscussionAvatar(diffAvatarContainer, noteEntity);
- }
-
localTimeAgo($('.js-timeago'), false);
Notes.checkMergeRequestStatus();
return this.updateNotesCount(1);
@@ -538,19 +527,6 @@ export default class Notes {
.get(0);
}
- renderDiscussionAvatar(diffAvatarContainer, noteEntity) {
- let avatarHolder = diffAvatarContainer.find('.diff-comment-avatar-holders');
-
- if (!avatarHolder.length) {
- avatarHolder = document.createElement('diff-note-avatars');
- avatarHolder.setAttribute('discussion-id', noteEntity.discussion_id);
-
- diffAvatarContainer.append(avatarHolder);
-
- gl.diffNotesCompileComponents();
- }
- }
-
/**
* Called in response the main target form has been successfully submitted.
*
@@ -605,10 +581,6 @@ export default class Notes {
form.find('#note_type').val('');
form.find('#note_project_id').remove();
form.find('#in_reply_to_discussion_id').remove();
- form
- .find('.js-comment-resolve-button')
- .closest('comment-and-resolve-btn')
- .remove();
this.parentTimeline = form.parents('.timeline');
if (form.length) {
@@ -714,10 +686,6 @@ export default class Notes {
$note_li.replaceWith($noteEntityEl);
this.setupNewNote($noteEntityEl);
-
- if (typeof gl.diffNotesCompileComponents !== 'undefined') {
- gl.diffNotesCompileComponents();
- }
}
checkContentToAllowEditing($el) {
@@ -844,12 +812,6 @@ export default class Notes {
const $notes = $note.closest('.discussion-notes');
const discussionId = $('.notes', $notes).data('discussionId');
- if (typeof gl.diffNotesCompileComponents !== 'undefined') {
- if (gl.diffNoteApps[noteElId]) {
- gl.diffNoteApps[noteElId].$destroy();
- }
- }
-
$note.remove();
// check if this is the last note for this line
@@ -979,13 +941,6 @@ export default class Notes {
form.removeClass('js-main-target-form').addClass('discussion-form js-discussion-note-form');
- if (typeof gl.diffNotesCompileComponents !== 'undefined') {
- const $commentBtn = form.find('comment-and-resolve-btn');
- $commentBtn.attr(':discussion-id', `'${discussionID}'`);
-
- gl.diffNotesCompileComponents();
- }
-
form.find('.js-note-text').focus();
form.find('.js-comment-resolve-button').attr('data-discussion-id', discussionID);
}
diff --git a/app/assets/javascripts/notes/components/comment_form.vue b/app/assets/javascripts/notes/components/comment_form.vue
index 54fcf41ca50..cfdadbceaf6 100644
--- a/app/assets/javascripts/notes/components/comment_form.vue
+++ b/app/assets/javascripts/notes/components/comment_form.vue
@@ -371,6 +371,7 @@ export default {
:markdown-docs-path="markdownDocsPath"
:quick-actions-docs-path="quickActionsDocsPath"
:add-spacing-classes="false"
+ :textarea-value="note"
>
<textarea
id="note-body"
@@ -380,7 +381,8 @@ export default {
dir="auto"
:disabled="isSubmitting"
name="note[note]"
- class="note-textarea js-vue-comment-form js-note-text js-gfm-input js-autosize markdown-area qa-comment-input"
+ class="note-textarea js-vue-comment-form js-note-text js-gfm-input js-autosize markdown-area"
+ data-qa-selector="comment_field"
data-supports-quick-actions="true"
:aria-label="__('Description')"
:placeholder="__('Write a comment or drag your files here…')"
@@ -425,7 +427,8 @@ export default {
>
<gl-button
:disabled="isSubmitButtonDisabled"
- class="js-comment-button js-comment-submit-button qa-comment-button"
+ class="js-comment-button js-comment-submit-button"
+ data-qa-selector="comment_button"
type="submit"
category="primary"
variant="success"
@@ -439,7 +442,8 @@ export default {
name="button"
category="primary"
variant="success"
- class="note-type-toggle js-note-new-discussion dropdown-toggle qa-note-dropdown"
+ class="note-type-toggle js-note-new-discussion dropdown-toggle"
+ data-qa-selector="note_dropdown"
data-display="static"
data-toggle="dropdown"
icon="chevron-down"
@@ -468,7 +472,10 @@ export default {
</li>
<li class="divider droplab-item-ignore"></li>
<li :class="{ 'droplab-item-selected': noteType === 'discussion' }">
- <button class="qa-discussion-option" @click.prevent="setNoteType('discussion')">
+ <button
+ data-qa-selector="discussion_menu_item"
+ @click.prevent="setNoteType('discussion')"
+ >
<i aria-hidden="true" class="fa fa-check icon"></i>
<div class="description">
<strong>{{ __('Start thread') }}</strong>
diff --git a/app/assets/javascripts/notes/components/diff_discussion_header.vue b/app/assets/javascripts/notes/components/diff_discussion_header.vue
index 8e6c01ba63f..ee39a529345 100644
--- a/app/assets/javascripts/notes/components/diff_discussion_header.vue
+++ b/app/assets/javascripts/notes/components/diff_discussion_header.vue
@@ -1,7 +1,7 @@
<script>
-/* eslint-disable vue/no-v-html */
import { mapActions } from 'vuex';
import { escape } from 'lodash';
+import { GlSafeHtmlDirective as SafeHtml } from '@gitlab/ui';
import { s__, __, sprintf } from '~/locale';
import { truncateSha } from '~/lib/utils/text_utility';
@@ -17,6 +17,9 @@ export default {
noteEditedText,
noteHeader,
},
+ directives: {
+ SafeHtml,
+ },
props: {
discussion: {
type: Object,
@@ -113,7 +116,7 @@ export default {
:expanded="discussion.expanded"
@toggleHandler="toggleDiscussionHandler"
>
- <span v-html="headerText"></span>
+ <span v-safe-html="headerText"></span>
</note-header>
<note-edited-text
v-if="discussion.resolved"
diff --git a/app/assets/javascripts/notes/components/diff_with_note.vue b/app/assets/javascripts/notes/components/diff_with_note.vue
index c01cd8f8037..a4271852563 100644
--- a/app/assets/javascripts/notes/components/diff_with_note.vue
+++ b/app/assets/javascripts/notes/components/diff_with_note.vue
@@ -76,7 +76,7 @@ export default {
:discussion-path="discussion.discussion_path"
:diff-file="discussion.diff_file"
:can-current-user-fork="false"
- :expanded="!discussion.diff_file.viewer.collapsed"
+ :expanded="!discussion.diff_file.viewer.automaticallyCollapsed"
/>
<div v-if="isTextFile" class="diff-content">
<table class="code js-syntax-highlight" :class="$options.userColorSchemeClass">
diff --git a/app/assets/javascripts/notes/components/discussion_counter.vue b/app/assets/javascripts/notes/components/discussion_counter.vue
index c6fab271376..2427a3f98ad 100644
--- a/app/assets/javascripts/notes/components/discussion_counter.vue
+++ b/app/assets/javascripts/notes/components/discussion_counter.vue
@@ -1,6 +1,7 @@
<script>
import { mapGetters, mapActions } from 'vuex';
-import { GlTooltipDirective, GlIcon } from '@gitlab/ui';
+import { GlTooltipDirective, GlIcon, GlButton, GlButtonGroup } from '@gitlab/ui';
+import { __ } from '~/locale';
import discussionNavigation from '../mixins/discussion_navigation';
export default {
@@ -9,6 +10,8 @@ export default {
},
components: {
GlIcon,
+ GlButton,
+ GlButtonGroup,
},
mixins: [discussionNavigation],
computed: {
@@ -34,6 +37,12 @@ export default {
allExpanded() {
return this.toggeableDiscussions.every(discussion => discussion.expanded);
},
+ lineResolveClass() {
+ return this.allResolved ? 'line-resolve-btn is-active' : 'line-resolve-text';
+ },
+ toggleThreadsLabel() {
+ return this.allExpanded ? __('Collapse all threads') : __('Expand all threads');
+ },
},
methods: {
...mapActions(['setExpandDiscussions']),
@@ -51,59 +60,49 @@ export default {
<div
v-if="resolvableDiscussionsCount > 0"
ref="discussionCounter"
- class="line-resolve-all-container full-width-mobile"
+ class="line-resolve-all-container full-width-mobile gl-display-flex d-sm-flex"
>
- <div class="full-width-mobile d-flex d-sm-flex">
- <div class="line-resolve-all">
- <span
- :class="{ 'line-resolve-btn is-active': allResolved, 'line-resolve-text': !allResolved }"
- >
- <template v-if="allResolved">
- <gl-icon name="check-circle-filled" />
- {{ __('All threads resolved') }}
- </template>
- <template v-else>
- {{ n__('%d unresolved thread', '%d unresolved threads', unresolvedDiscussionsCount) }}
- </template>
- </span>
- </div>
- <div
- v-if="resolveAllDiscussionsIssuePath && !allResolved"
- class="btn-group btn-group-sm"
- role="group"
- >
- <a
- v-gl-tooltip
- :href="resolveAllDiscussionsIssuePath"
- :title="s__('Resolve all threads in new issue')"
- class="new-issue-for-discussion btn btn-default discussion-create-issue-btn"
- >
- <gl-icon name="issue-new" />
- </a>
- </div>
- <div v-if="isLoggedIn && !allResolved" class="btn-group btn-group-sm" role="group">
- <button
- v-gl-tooltip
- :title="__('Jump to next unresolved thread')"
- class="btn btn-default discussion-next-btn"
- data-track-event="click_button"
- data-track-label="mr_next_unresolved_thread"
- data-track-property="click_next_unresolved_thread_top"
- @click="jumpToNextDiscussion"
- >
- <gl-icon name="comment-next" />
- </button>
- </div>
- <div class="btn-group btn-group-sm" role="group">
- <button
- v-gl-tooltip
- :title="__('Toggle all threads')"
- class="btn btn-default toggle-all-discussions-btn"
- @click="handleExpandDiscussions"
- >
- <gl-icon :name="allExpanded ? 'angle-up' : 'angle-down'" />
- </button>
- </div>
+ <div class="line-resolve-all">
+ <span :class="lineResolveClass">
+ <template v-if="allResolved">
+ <gl-icon name="check-circle-filled" />
+ {{ __('All threads resolved') }}
+ </template>
+ <template v-else>
+ {{ n__('%d unresolved thread', '%d unresolved threads', unresolvedDiscussionsCount) }}
+ </template>
+ </span>
</div>
+ <gl-button-group>
+ <gl-button
+ v-if="resolveAllDiscussionsIssuePath && !allResolved"
+ v-gl-tooltip
+ :href="resolveAllDiscussionsIssuePath"
+ :title="s__('Resolve all threads in new issue')"
+ :aria-label="s__('Resolve all threads in new issue')"
+ class="new-issue-for-discussion discussion-create-issue-btn"
+ icon="issue-new"
+ />
+ <gl-button
+ v-if="isLoggedIn && !allResolved"
+ v-gl-tooltip
+ :title="__('Jump to next unresolved thread')"
+ :aria-label="__('Jump to next unresolved thread')"
+ class="discussion-next-btn"
+ data-track-event="click_button"
+ data-track-label="mr_next_unresolved_thread"
+ data-track-property="click_next_unresolved_thread_top"
+ icon="comment-next"
+ @click="jumpToNextDiscussion"
+ />
+ <gl-button
+ v-gl-tooltip
+ :title="toggleThreadsLabel"
+ :aria-label="toggleThreadsLabel"
+ class="toggle-all-discussions-btn"
+ :icon="allExpanded ? 'angle-up' : 'angle-down'"
+ @click="handleExpandDiscussions"
+ />
+ </gl-button-group>
</div>
</template>
diff --git a/app/assets/javascripts/notes/components/discussion_filter.vue b/app/assets/javascripts/notes/components/discussion_filter.vue
index 989ce9ff144..e4b191b55a7 100644
--- a/app/assets/javascripts/notes/components/discussion_filter.vue
+++ b/app/assets/javascripts/notes/components/discussion_filter.vue
@@ -1,11 +1,11 @@
<script>
-import $ from 'jquery';
import { mapGetters, mapActions } from 'vuex';
-import { GlIcon } from '@gitlab/ui';
+import { GlDropdown, GlDropdownItem, GlDropdownDivider } from '@gitlab/ui';
import { getLocationHash, doesHashExistInUrl } from '../../lib/utils/url_utility';
import {
DISCUSSION_FILTERS_DEFAULT_VALUE,
HISTORY_ONLY_FILTER_VALUE,
+ COMMENTS_ONLY_FILTER_VALUE,
DISCUSSION_TAB_LABEL,
DISCUSSION_FILTER_TYPES,
NOTE_UNDERSCORE,
@@ -14,7 +14,9 @@ import notesEventHub from '../event_hub';
export default {
components: {
- GlIcon,
+ GlDropdown,
+ GlDropdownItem,
+ GlDropdownDivider,
},
props: {
filters: {
@@ -37,7 +39,7 @@ export default {
};
},
computed: {
- ...mapGetters(['getNotesDataByProp']),
+ ...mapGetters(['getNotesDataByProp', 'timelineEnabled']),
currentFilter() {
if (!this.currentValue) return this.filters[0];
return this.filters.find(filter => filter.value === this.currentValue);
@@ -62,14 +64,20 @@ export default {
window.removeEventListener('hashchange', this.handleLocationHash);
},
methods: {
- ...mapActions(['filterDiscussion', 'setCommentsDisabled', 'setTargetNoteHash']),
+ ...mapActions([
+ 'filterDiscussion',
+ 'setCommentsDisabled',
+ 'setTargetNoteHash',
+ 'setTimelineView',
+ ]),
selectFilter(value, persistFilter = true) {
const filter = parseInt(value, 10);
- // close dropdown
- this.toggleDropdown();
-
if (filter === this.currentValue) return;
+
+ if (this.timelineEnabled && filter !== COMMENTS_ONLY_FILTER_VALUE) {
+ this.setTimelineView(false);
+ }
this.currentValue = filter;
this.filterDiscussion({
path: this.getNotesDataByProp('discussionsPath'),
@@ -78,9 +86,6 @@ export default {
});
this.toggleCommentsForm();
},
- toggleDropdown() {
- $(this.$refs.dropdownToggle).dropdown('toggle');
- },
toggleCommentsForm() {
this.setCommentsDisabled(this.currentValue === HISTORY_ONLY_FILTER_VALUE);
},
@@ -92,7 +97,6 @@ export default {
if (/^note_/.test(hash) && this.currentValue !== DISCUSSION_FILTERS_DEFAULT_VALUE) {
this.selectFilter(this.defaultValue, false);
- this.toggleDropdown(); // close dropdown
this.setTargetNoteHash(hash);
}
},
@@ -109,43 +113,24 @@ export default {
</script>
<template>
- <div
+ <gl-dropdown
v-if="displayFilters"
- class="discussion-filter-container js-discussion-filter-container d-inline-block align-bottom full-width-mobile"
+ id="discussion-filter-dropdown"
+ class="gl-mr-3 full-width-mobile discussion-filter-container js-discussion-filter-container qa-discussion-filter"
+ :text="currentFilter.title"
>
- <button
- id="discussion-filter-dropdown"
- ref="dropdownToggle"
- class="btn btn-sm qa-discussion-filter"
- data-toggle="dropdown"
- aria-expanded="false"
- >
- {{ currentFilter.title }} <gl-icon name="chevron-down" />
- </button>
- <div
- ref="dropdownMenu"
- class="dropdown-menu dropdown-menu-selectable dropdown-menu-right"
- aria-labelledby="discussion-filter-dropdown"
- >
- <div class="dropdown-content">
- <ul>
- <li
- v-for="filter in filters"
- :key="filter.value"
- :data-filter-type="filterType(filter.value)"
- >
- <button
- :class="{ 'is-active': filter.value === currentValue }"
- class="qa-filter-options"
- type="button"
- @click="selectFilter(filter.value)"
- >
- {{ filter.title }}
- </button>
- <div v-if="filter.value === defaultValue" class="dropdown-divider"></div>
- </li>
- </ul>
- </div>
+ <div v-for="filter in filters" :key="filter.value" class="dropdown-item-wrapper">
+ <gl-dropdown-item
+ :is-check-item="true"
+ :is-checked="filter.value === currentValue"
+ :class="{ 'is-active': filter.value === currentValue }"
+ :data-filter-type="filterType(filter.value)"
+ class="qa-filter-options"
+ @click.prevent="selectFilter(filter.value)"
+ >
+ {{ filter.title }}
+ </gl-dropdown-item>
+ <gl-dropdown-divider v-if="filter.value === defaultValue" />
</div>
- </div>
+ </gl-dropdown>
</template>
diff --git a/app/assets/javascripts/notes/components/note_actions.vue b/app/assets/javascripts/notes/components/note_actions.vue
index a8057276f1a..c2f40b2d21a 100644
--- a/app/assets/javascripts/notes/components/note_actions.vue
+++ b/app/assets/javascripts/notes/components/note_actions.vue
@@ -160,7 +160,7 @@ export default {
});
},
displayMemberBadgeText() {
- return sprintf(__('This user is a %{access} of the %{name} project.'), {
+ return sprintf(__('This user has the %{access} role in the %{name} project.'), {
access: this.accessLevel.toLowerCase(),
name: this.projectName,
});
@@ -275,7 +275,8 @@ export default {
v-gl-tooltip
type="button"
title="Edit comment"
- class="note-action-button js-note-edit btn btn-transparent qa-note-edit-button"
+ class="note-action-button js-note-edit btn btn-transparent"
+ data-qa-selector="note_edit_button"
@click="onEdit"
>
<gl-icon name="pencil" class="link-highlight" />
diff --git a/app/assets/javascripts/notes/components/note_body.vue b/app/assets/javascripts/notes/components/note_body.vue
index 314fa762768..65b89b94eaa 100644
--- a/app/assets/javascripts/notes/components/note_body.vue
+++ b/app/assets/javascripts/notes/components/note_body.vue
@@ -45,7 +45,7 @@ export default {
},
},
computed: {
- ...mapGetters(['getDiscussion']),
+ ...mapGetters(['getDiscussion', 'suggestionsCount']),
discussion() {
if (!this.note.isDraft) return {};
@@ -125,6 +125,7 @@ export default {
<suggestions
v-if="hasSuggestion && !isEditing"
:suggestions="note.suggestions"
+ :suggestions-count="suggestionsCount"
:batch-suggestions-info="batchSuggestionsInfo"
:note-html="note.note_html"
:line-type="lineType"
diff --git a/app/assets/javascripts/notes/components/note_form.vue b/app/assets/javascripts/notes/components/note_form.vue
index 88b4461cf38..4b3f23e742d 100644
--- a/app/assets/javascripts/notes/components/note_form.vue
+++ b/app/assets/javascripts/notes/components/note_form.vue
@@ -328,6 +328,7 @@ export default {
:add-spacing-classes="false"
:help-page-path="helpPagePath"
:show-suggest-popover="showSuggestPopover"
+ :textarea-value="updatedNoteBody"
@handleSuggestDismissed="() => $emit('handleSuggestDismissed')"
>
<textarea
@@ -337,7 +338,8 @@ export default {
v-model="updatedNoteBody"
:data-supports-quick-actions="!isEditing"
name="note[note]"
- class="note-textarea js-gfm-input js-note-text js-autosize markdown-area js-vue-issue-note-form qa-reply-input"
+ class="note-textarea js-gfm-input js-note-text js-autosize markdown-area js-vue-issue-note-form"
+ data-qa-selector="reply_field"
dir="auto"
:aria-label="__('Description')"
:placeholder="__('Write a comment or drag your files here…')"
@@ -376,7 +378,8 @@ export default {
<button
:disabled="isDisabled"
type="button"
- class="btn btn-success qa-start-review"
+ class="btn btn-success"
+ data-qa-selector="start_review_button"
@click="handleAddToReview"
>
<template v-if="hasDrafts">{{ __('Add to review') }}</template>
@@ -385,7 +388,8 @@ export default {
<button
:disabled="isDisabled"
type="button"
- class="btn qa-comment-now js-comment-button"
+ class="btn js-comment-button"
+ data-qa-selector="comment_now_button"
@click="handleUpdate()"
>
{{ __('Add comment now') }}
@@ -404,7 +408,8 @@ export default {
<button
:disabled="isDisabled"
type="button"
- class="js-vue-issue-save btn btn-success js-comment-button qa-reply-comment-button"
+ class="js-vue-issue-save btn btn-success js-comment-button"
+ data-qa-selector="reply_comment_button"
@click="handleUpdate()"
>
{{ saveButtonTitle }}
diff --git a/app/assets/javascripts/notes/components/notes_app.vue b/app/assets/javascripts/notes/components/notes_app.vue
index fb18be9386e..9eaa4e422d5 100644
--- a/app/assets/javascripts/notes/components/notes_app.vue
+++ b/app/assets/javascripts/notes/components/notes_app.vue
@@ -73,6 +73,7 @@ export default {
'userCanReply',
'discussionTabCounter',
'sortDirection',
+ 'timelineEnabled',
]),
sortDirDesc() {
return this.sortDirection === constants.DESC;
@@ -95,7 +96,7 @@ export default {
return this.discussions;
},
canReply() {
- return this.userCanReply && !this.commentsDisabled;
+ return this.userCanReply && !this.commentsDisabled && !this.timelineEnabled;
},
slotKeys() {
return this.sortDirDesc ? ['form', 'comments'] : ['comments', 'form'];
@@ -252,7 +253,7 @@ export default {
<ordered-layout :slot-keys="slotKeys">
<template #form>
<comment-form
- v-if="!commentsDisabled"
+ v-if="!(commentsDisabled || timelineEnabled)"
class="js-comment-form"
:noteable-type="noteableType"
/>
diff --git a/app/assets/javascripts/notes/components/sort_discussion.vue b/app/assets/javascripts/notes/components/sort_discussion.vue
index 60b531d7597..c279a7107c7 100644
--- a/app/assets/javascripts/notes/components/sort_discussion.vue
+++ b/app/assets/javascripts/notes/components/sort_discussion.vue
@@ -1,6 +1,5 @@
-gs
<script>
-import { GlIcon } from '@gitlab/ui';
+import { GlDropdown, GlDropdownItem } from '@gitlab/ui';
import { mapActions, mapGetters } from 'vuex';
import { __ } from '~/locale';
import LocalStorageSync from '~/vue_shared/components/local_storage_sync.vue';
@@ -15,12 +14,13 @@ const SORT_OPTIONS = [
export default {
SORT_OPTIONS,
components: {
- GlIcon,
+ GlDropdown,
+ GlDropdownItem,
LocalStorageSync,
},
mixins: [Tracking.mixin()],
computed: {
- ...mapGetters(['sortDirection', 'noteableType']),
+ ...mapGetters(['sortDirection', 'persistSortOrder', 'noteableType']),
selectedOption() {
return SORT_OPTIONS.find(({ key }) => this.sortDirection === key);
},
@@ -38,7 +38,7 @@ export default {
return;
}
- this.setDiscussionSortDirection(direction);
+ this.setDiscussionSortDirection({ direction });
this.track('change_discussion_sort_direction', { property: direction });
},
isDropdownItemActive(sortDir) {
@@ -49,33 +49,28 @@ export default {
</script>
<template>
- <div
- data-testid="sort-discussion-filter"
- class="gl-mr-2 gl-display-inline-block gl-vertical-align-bottom full-width-mobile"
- >
+ <div class="gl-mr-3 gl-display-inline-block gl-vertical-align-bottom full-width-mobile">
<local-storage-sync
:value="sortDirection"
:storage-key="storageKey"
- @input="setDiscussionSortDirection"
+ :persist="persistSortOrder"
+ @input="setDiscussionSortDirection({ direction: $event })"
/>
- <button class="btn btn-sm js-dropdown-text" data-toggle="dropdown" aria-expanded="false">
- {{ dropdownText }}
- <gl-icon name="chevron-down" />
- </button>
- <div ref="dropdownMenu" class="dropdown-menu dropdown-menu-selectable dropdown-menu-right">
- <div class="dropdown-content">
- <ul>
- <li v-for="{ text, key, cls } in $options.SORT_OPTIONS" :key="key">
- <button
- :class="[cls, { 'is-active': isDropdownItemActive(key) }]"
- type="button"
- @click="fetchSortedDiscussions(key)"
- >
- {{ text }}
- </button>
- </li>
- </ul>
- </div>
- </div>
+ <gl-dropdown
+ :text="dropdownText"
+ data-testid="sort-discussion-filter"
+ class="js-dropdown-text full-width-mobile"
+ >
+ <gl-dropdown-item
+ v-for="{ text, key, cls } in $options.SORT_OPTIONS"
+ :key="key"
+ :class="cls"
+ :is-check-item="true"
+ :is-checked="isDropdownItemActive(key)"
+ @click="fetchSortedDiscussions(key)"
+ >
+ {{ text }}
+ </gl-dropdown-item>
+ </gl-dropdown>
</div>
</template>
diff --git a/app/assets/javascripts/notes/components/timeline_toggle.vue b/app/assets/javascripts/notes/components/timeline_toggle.vue
new file mode 100644
index 00000000000..d1ffe0a3601
--- /dev/null
+++ b/app/assets/javascripts/notes/components/timeline_toggle.vue
@@ -0,0 +1,60 @@
+<script>
+import { GlButton, GlTooltipDirective } from '@gitlab/ui';
+import { mapActions, mapGetters } from 'vuex';
+import { s__ } from '~/locale';
+import { COMMENTS_ONLY_FILTER_VALUE, DESC } from '../constants';
+import notesEventHub from '../event_hub';
+import TrackEventDirective from '~/vue_shared/directives/track_event';
+import { trackToggleTimelineView } from '../utils';
+
+export const timelineEnabledTooltip = s__('Timeline|Turn timeline view off');
+export const timelineDisabledTooltip = s__('Timeline|Turn timeline view on');
+
+export default {
+ components: {
+ GlButton,
+ },
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ TrackEvent: TrackEventDirective,
+ },
+ computed: {
+ ...mapGetters(['timelineEnabled', 'sortDirection']),
+ tooltip() {
+ return this.timelineEnabled ? timelineEnabledTooltip : timelineDisabledTooltip;
+ },
+ },
+ methods: {
+ ...mapActions(['setTimelineView', 'setDiscussionSortDirection']),
+ trackToggleTimelineView,
+ setSort() {
+ if (this.timelineEnabled && this.sortDirection !== DESC) {
+ this.setDiscussionSortDirection({ direction: DESC, persist: false });
+ }
+ },
+ setFilter() {
+ notesEventHub.$emit('dropdownSelect', COMMENTS_ONLY_FILTER_VALUE, false);
+ },
+ toggleTimeline(event) {
+ event.currentTarget.blur();
+ this.setTimelineView(!this.timelineEnabled);
+ this.setSort();
+ this.setFilter();
+ },
+ },
+};
+</script>
+
+<template>
+ <gl-button
+ v-gl-tooltip
+ v-track-event="trackToggleTimelineView(timelineEnabled)"
+ icon="comments"
+ size="small"
+ :selected="timelineEnabled"
+ :title="tooltip"
+ :aria-label="tooltip"
+ class="gl-mr-3"
+ @click="toggleTimeline"
+ />
+</template>
diff --git a/app/assets/javascripts/notes/components/toggle_replies_widget.vue b/app/assets/javascripts/notes/components/toggle_replies_widget.vue
index bddac60647d..f49fd2c3fa3 100644
--- a/app/assets/javascripts/notes/components/toggle_replies_widget.vue
+++ b/app/assets/javascripts/notes/components/toggle_replies_widget.vue
@@ -57,7 +57,12 @@ export default {
tooltip-placement="bottom"
/>
</div>
- <button class="btn btn-link js-replies-text qa-expand-replies" type="button" @click="toggle">
+ <button
+ class="btn btn-link js-replies-text"
+ data-qa-selector="expand_replies_button"
+ type="button"
+ @click="toggle"
+ >
{{ replies.length }} {{ n__('reply', 'replies', replies.length) }}
</button>
{{ __('Last reply by') }}
@@ -68,7 +73,8 @@ export default {
</template>
<span
v-else
- class="collapse-replies-btn js-collapse-replies qa-collapse-replies"
+ class="collapse-replies-btn js-collapse-replies"
+ data-qa-selector="collapse_replies_button"
@click="toggle"
>
<gl-icon name="chevron-down" /> {{ s__('Notes|Collapse replies') }}
diff --git a/app/assets/javascripts/notes/constants.js b/app/assets/javascripts/notes/constants.js
index b81aae7c257..7acf2ad57c8 100644
--- a/app/assets/javascripts/notes/constants.js
+++ b/app/assets/javascripts/notes/constants.js
@@ -14,8 +14,9 @@ export const MERGE_REQUEST_NOTEABLE_TYPE = 'MergeRequest';
export const UNRESOLVE_NOTE_METHOD_NAME = 'delete';
export const RESOLVE_NOTE_METHOD_NAME = 'post';
export const DESCRIPTION_TYPE = 'changed the description';
-export const HISTORY_ONLY_FILTER_VALUE = 2;
export const DISCUSSION_FILTERS_DEFAULT_VALUE = 0;
+export const COMMENTS_ONLY_FILTER_VALUE = 1;
+export const HISTORY_ONLY_FILTER_VALUE = 2;
export const DISCUSSION_TAB_LABEL = 'show';
export const NOTE_UNDERSCORE = 'note_';
export const TIME_DIFFERENCE_VALUE = 10;
diff --git a/app/assets/javascripts/notes/index.js b/app/assets/javascripts/notes/index.js
index 7bf465482b3..1f0b2afab9e 100644
--- a/app/assets/javascripts/notes/index.js
+++ b/app/assets/javascripts/notes/index.js
@@ -2,18 +2,21 @@ import Vue from 'vue';
import notesApp from './components/notes_app.vue';
import initDiscussionFilters from './discussion_filters';
import initSortDiscussions from './sort_discussions';
+import initTimelineToggle from './timeline';
import { store } from './stores';
-document.addEventListener('DOMContentLoaded', () => {
+const el = document.getElementById('js-vue-notes');
+
+if (el) {
// eslint-disable-next-line no-new
new Vue({
- el: '#js-vue-notes',
+ el,
components: {
notesApp,
},
store,
data() {
- const notesDataset = document.getElementById('js-vue-notes').dataset;
+ const notesDataset = el.dataset;
const parsedUserData = JSON.parse(notesDataset.currentUserData);
const noteableData = JSON.parse(notesDataset.noteableData);
let currentUserData = {};
@@ -55,4 +58,5 @@ document.addEventListener('DOMContentLoaded', () => {
initDiscussionFilters(store);
initSortDiscussions(store);
-});
+ initTimelineToggle(store);
+}
diff --git a/app/assets/javascripts/notes/stores/actions.js b/app/assets/javascripts/notes/stores/actions.js
index 9c63a7e3cd4..37986c8a02d 100644
--- a/app/assets/javascripts/notes/stores/actions.js
+++ b/app/assets/javascripts/notes/stores/actions.js
@@ -99,8 +99,12 @@ export const updateDiscussion = ({ commit, state }, discussion) => {
return utils.findNoteObjectById(state.discussions, discussion.id);
};
-export const setDiscussionSortDirection = ({ commit }, direction) => {
- commit(types.SET_DISCUSSIONS_SORT, direction);
+export const setDiscussionSortDirection = ({ commit }, { direction, persist = true }) => {
+ commit(types.SET_DISCUSSIONS_SORT, { direction, persist });
+};
+
+export const setTimelineView = ({ commit }, enabled) => {
+ commit(types.SET_TIMELINE_VIEW, enabled);
};
export const setSelectedCommentPosition = ({ commit }, position) => {
diff --git a/app/assets/javascripts/notes/stores/getters.js b/app/assets/javascripts/notes/stores/getters.js
index 7d60fbffb10..5b3ffa425a0 100644
--- a/app/assets/javascripts/notes/stores/getters.js
+++ b/app/assets/javascripts/notes/stores/getters.js
@@ -5,6 +5,23 @@ import { collapseSystemNotes } from './collapse_utils';
export const discussions = state => {
let discussionsInState = clone(state.discussions);
// NOTE: not testing bc will be removed when backend is finished.
+
+ if (state.isTimelineEnabled) {
+ discussionsInState = discussionsInState
+ .reduce((acc, discussion) => {
+ const transformedToIndividualNotes = discussion.notes.map(note => ({
+ ...discussion,
+ id: note.id,
+ created_at: note.created_at,
+ individual_note: true,
+ notes: [note],
+ }));
+
+ return acc.concat(transformedToIndividualNotes);
+ }, [])
+ .sort((a, b) => new Date(a.created_at) - new Date(b.created_at));
+ }
+
if (state.discussionSortOrder === constants.DESC) {
discussionsInState = discussionsInState.reverse();
}
@@ -27,6 +44,10 @@ export const isNotesFetched = state => state.isNotesFetched;
export const sortDirection = state => state.discussionSortOrder;
+export const persistSortOrder = state => state.persistSortOrder;
+
+export const timelineEnabled = state => state.isTimelineEnabled;
+
export const isLoading = state => state.isLoading;
export const getNotesDataByProp = state => prop => state.notesData[prop];
@@ -231,3 +252,6 @@ export const getDiscussion = state => discussionId =>
state.discussions.find(discussion => discussion.id === discussionId);
export const commentsDisabled = state => state.commentsDisabled;
+
+export const suggestionsCount = (state, getters) =>
+ Object.values(getters.notesById).filter(n => n.suggestions.length).length;
diff --git a/app/assets/javascripts/notes/stores/modules/index.js b/app/assets/javascripts/notes/stores/modules/index.js
index 161c9b8b1b5..a8738fa7c5f 100644
--- a/app/assets/javascripts/notes/stores/modules/index.js
+++ b/app/assets/javascripts/notes/stores/modules/index.js
@@ -7,6 +7,7 @@ export default () => ({
state: {
discussions: [],
discussionSortOrder: ASC,
+ persistSortOrder: true,
convertedDisscussionIds: [],
targetNoteHash: null,
lastFetchedAt: null,
@@ -45,6 +46,7 @@ export default () => ({
resolvableDiscussionsCount: 0,
unresolvedDiscussionsCount: 0,
descriptionVersions: {},
+ isTimelineEnabled: false,
},
actions,
getters,
diff --git a/app/assets/javascripts/notes/stores/mutation_types.js b/app/assets/javascripts/notes/stores/mutation_types.js
index 23515cdd9e3..7496dd630f6 100644
--- a/app/assets/javascripts/notes/stores/mutation_types.js
+++ b/app/assets/javascripts/notes/stores/mutation_types.js
@@ -34,6 +34,7 @@ export const SET_EXPAND_DISCUSSIONS = 'SET_EXPAND_DISCUSSIONS';
export const UPDATE_RESOLVABLE_DISCUSSIONS_COUNTS = 'UPDATE_RESOLVABLE_DISCUSSIONS_COUNTS';
export const SET_CURRENT_DISCUSSION_ID = 'SET_CURRENT_DISCUSSION_ID';
export const SET_DISCUSSIONS_SORT = 'SET_DISCUSSIONS_SORT';
+export const SET_TIMELINE_VIEW = 'SET_TIMELINE_VIEW';
export const SET_SELECTED_COMMENT_POSITION = 'SET_SELECTED_COMMENT_POSITION';
export const SET_SELECTED_COMMENT_POSITION_HOVER = 'SET_SELECTED_COMMENT_POSITION_HOVER';
export const SET_FETCHING_DISCUSSIONS = 'SET_FETCHING_DISCUSSIONS';
diff --git a/app/assets/javascripts/notes/stores/mutations.js b/app/assets/javascripts/notes/stores/mutations.js
index a8bd94cc763..6c11d53dba3 100644
--- a/app/assets/javascripts/notes/stores/mutations.js
+++ b/app/assets/javascripts/notes/stores/mutations.js
@@ -313,8 +313,13 @@ export default {
discussion.truncated_diff_lines = utils.prepareDiffLines(diffLines);
},
- [types.SET_DISCUSSIONS_SORT](state, sort) {
- state.discussionSortOrder = sort;
+ [types.SET_DISCUSSIONS_SORT](state, { direction, persist }) {
+ state.discussionSortOrder = direction;
+ state.persistSortOrder = persist;
+ },
+
+ [types.SET_TIMELINE_VIEW](state, value) {
+ state.isTimelineEnabled = value;
},
[types.SET_SELECTED_COMMENT_POSITION](state, position) {
diff --git a/app/assets/javascripts/notes/timeline.js b/app/assets/javascripts/notes/timeline.js
new file mode 100644
index 00000000000..df6d1b21400
--- /dev/null
+++ b/app/assets/javascripts/notes/timeline.js
@@ -0,0 +1,16 @@
+import Vue from 'vue';
+import TimelineToggle from './components/timeline_toggle.vue';
+
+export default function initTimelineToggle(store) {
+ const el = document.getElementById('js-incidents-timeline-toggle');
+
+ if (!el) return null;
+
+ return new Vue({
+ el,
+ store,
+ render(createElement) {
+ return createElement(TimelineToggle);
+ },
+ });
+}
diff --git a/app/assets/javascripts/notes/utils.js b/app/assets/javascripts/notes/utils.js
new file mode 100644
index 00000000000..e6c2eb06a51
--- /dev/null
+++ b/app/assets/javascripts/notes/utils.js
@@ -0,0 +1,12 @@
+/* eslint-disable @gitlab/require-i18n-strings */
+
+/**
+ * Tracks snowplow event when User toggles timeline view
+ * @param {Boolean} enabled that will be send as a property for the event
+ */
+export const trackToggleTimelineView = enabled => ({
+ category: 'Incident Management',
+ action: 'toggle_incident_comments_into_timeline_view',
+ label: 'Status',
+ property: enabled,
+});
diff --git a/app/assets/javascripts/notifications_dropdown.js b/app/assets/javascripts/notifications_dropdown.js
index 47fb5b271d1..ae992dd5dc5 100644
--- a/app/assets/javascripts/notifications_dropdown.js
+++ b/app/assets/javascripts/notifications_dropdown.js
@@ -1,4 +1,5 @@
import $ from 'jquery';
+import { Rails } from '~/lib/utils/rails_ujs';
import { deprecatedCreateFlash as Flash } from './flash';
import { __ } from '~/locale';
@@ -21,10 +22,12 @@ export default function notificationsDropdown() {
form.find('.js-notifications-icon').toggleClass('hidden');
}
form.find('#notification_setting_level').val(notificationLevel);
- form.submit();
+ Rails.fire(form[0], 'submit');
});
- $(document).on('ajax:success', '.notification-form', (e, data) => {
+ $(document).on('ajax:success', '.notification-form', e => {
+ const data = e.detail[0];
+
if (data.saved) {
$(e.currentTarget)
.closest('.js-notification-dropdown')
diff --git a/app/assets/javascripts/operation_settings/components/metrics_settings.vue b/app/assets/javascripts/operation_settings/components/metrics_settings.vue
index 9df6a412930..2e972dd7154 100644
--- a/app/assets/javascripts/operation_settings/components/metrics_settings.vue
+++ b/app/assets/javascripts/operation_settings/components/metrics_settings.vue
@@ -44,11 +44,9 @@ export default {
<form>
<dashboard-timezone />
<external-dashboard />
- <div class="gl-display-flex gl-justify-content-end">
- <gl-button variant="success" category="primary" @click="saveChanges">
- {{ __('Save Changes') }}
- </gl-button>
- </div>
+ <gl-button variant="success" category="primary" @click="saveChanges">
+ {{ __('Save Changes') }}
+ </gl-button>
</form>
</div>
</section>
diff --git a/app/assets/javascripts/packages/details/components/additional_metadata.vue b/app/assets/javascripts/packages/details/components/additional_metadata.vue
index 76e0976ac05..4e99099b0a1 100644
--- a/app/assets/javascripts/packages/details/components/additional_metadata.vue
+++ b/app/assets/javascripts/packages/details/components/additional_metadata.vue
@@ -2,7 +2,6 @@
import { GlLink, GlSprintf } from '@gitlab/ui';
import { s__ } from '~/locale';
import DetailsRow from '~/vue_shared/components/registry/details_row.vue';
-import { generateConanRecipe } from '../utils';
import { PackageType } from '../../shared/constants';
export default {
@@ -25,9 +24,6 @@ export default {
},
},
computed: {
- conanRecipe() {
- return generateConanRecipe(this.packageEntity);
- },
showMetadata() {
const visibilityConditions = {
[PackageType.NUGET]: this.packageEntity.nuget_metadatum,
@@ -73,7 +69,7 @@ export default {
data-testid="conan-recipe"
>
<gl-sprintf :message="$options.i18n.recipeText">
- <template #recipe>{{ conanRecipe }}</template>
+ <template #recipe>{{ packageEntity.name }}</template>
</gl-sprintf>
</details-row>
diff --git a/app/assets/javascripts/packages/details/components/composer_installation.vue b/app/assets/javascripts/packages/details/components/composer_installation.vue
index 60ad468c293..9d87ae8f836 100644
--- a/app/assets/javascripts/packages/details/components/composer_installation.vue
+++ b/app/assets/javascripts/packages/details/components/composer_installation.vue
@@ -14,12 +14,12 @@ export default {
},
computed: {
...mapState(['composerHelpPath']),
- ...mapGetters(['composerRegistryInclude', 'composerPackageInclude']),
+ ...mapGetters(['composerRegistryInclude', 'composerPackageInclude', 'groupExists']),
},
i18n: {
- registryInclude: s__('PackageRegistry|composer.json registry include'),
+ registryInclude: s__('PackageRegistry|Add composer registry'),
copyRegistryInclude: s__('PackageRegistry|Copy registry include'),
- packageInclude: s__('PackageRegistry|composer.json require package include'),
+ packageInclude: s__('PackageRegistry|Install package version'),
copyPackageInclude: s__('PackageRegistry|Copy require package include'),
infoLine: s__(
'PackageRegistry|For more information on Composer packages in GitLab, %{linkStart}see the documentation.%{linkEnd}',
@@ -31,7 +31,7 @@ export default {
</script>
<template>
- <div>
+ <div v-if="groupExists" data-testid="root-node">
<h3 class="gl-font-lg">{{ __('Installation') }}</h3>
<code-instruction
diff --git a/app/assets/javascripts/packages/details/components/package_title.vue b/app/assets/javascripts/packages/details/components/package_title.vue
index 69dd494f11a..2789be30818 100644
--- a/app/assets/javascripts/packages/details/components/package_title.vue
+++ b/app/assets/javascripts/packages/details/components/package_title.vue
@@ -54,15 +54,15 @@ export default {
</gl-sprintf>
</template>
- <template v-if="packageTypeDisplay" #metadata_type>
+ <template v-if="packageTypeDisplay" #metadata-type>
<metadata-item data-testid="package-type" icon="package" :text="packageTypeDisplay" />
</template>
- <template #metadata_size>
+ <template #metadata-size>
<metadata-item data-testid="package-size" icon="disk" :text="totalSize" />
</template>
- <template v-if="packagePipeline" #metadata_pipeline>
+ <template v-if="packagePipeline" #metadata-pipeline>
<metadata-item
data-testid="pipeline-project"
icon="review-list"
@@ -71,11 +71,11 @@ export default {
/>
</template>
- <template v-if="packagePipeline" #metadata_ref>
+ <template v-if="packagePipeline" #metadata-ref>
<metadata-item data-testid="package-ref" icon="branch" :text="packagePipeline.ref" />
</template>
- <template v-if="hasTagsToDisplay" #metadata_tags>
+ <template v-if="hasTagsToDisplay" #metadata-tags>
<package-tags :tag-display-limit="2" :tags="packageEntity.tags" hide-label />
</template>
diff --git a/app/assets/javascripts/packages/details/store/getters.js b/app/assets/javascripts/packages/details/store/getters.js
index ede6d39bde7..14e76ac84bd 100644
--- a/app/assets/javascripts/packages/details/store/getters.js
+++ b/app/assets/javascripts/packages/details/store/getters.js
@@ -1,4 +1,3 @@
-import { generateConanRecipe } from '../utils';
import { PackageType } from '../../shared/constants';
import { getPackageTypeLabel } from '../../shared/utils';
import { NpmManager } from '../constants';
@@ -20,10 +19,8 @@ export const packageIcon = ({ packageEntity }) => {
};
export const conanInstallationCommand = ({ packageEntity }) => {
- const recipe = generateConanRecipe(packageEntity);
-
// eslint-disable-next-line @gitlab/require-i18n-strings
- return `conan install ${recipe} --remote=gitlab`;
+ return `conan install ${packageEntity.name} --remote=gitlab`;
};
export const conanSetupCommand = ({ conanPath }) =>
@@ -98,18 +95,19 @@ export const nugetSetupCommand = ({ nugetPath }) =>
export const pypiPipCommand = ({ pypiPath, packageEntity }) =>
// eslint-disable-next-line @gitlab/require-i18n-strings
- `pip install ${packageEntity.name} --index-url ${pypiPath}`;
+ `pip install ${packageEntity.name} --extra-index-url ${pypiPath}`;
export const pypiSetupCommand = ({ pypiSetupPath }) => `[gitlab]
repository = ${pypiSetupPath}
username = __token__
password = <your personal access token>`;
-export const composerRegistryInclude = ({ composerPath }) => {
- const base = { type: 'composer', url: composerPath };
- return JSON.stringify(base);
-};
-export const composerPackageInclude = ({ packageEntity }) => {
- const base = { [packageEntity.name]: packageEntity.version };
- return JSON.stringify(base);
-};
+export const composerRegistryInclude = ({ composerPath, composerConfigRepositoryName }) =>
+ // eslint-disable-next-line @gitlab/require-i18n-strings
+ `composer config repositories.${composerConfigRepositoryName} '{"type": "composer", "url": "${composerPath}"}'`;
+
+export const composerPackageInclude = ({ packageEntity }) =>
+ // eslint-disable-next-line @gitlab/require-i18n-strings
+ `composer req ${[packageEntity.name]}:${packageEntity.version}`;
+
+export const groupExists = ({ groupListUrl }) => groupListUrl.length > 0;
diff --git a/app/assets/javascripts/packages/details/utils.js b/app/assets/javascripts/packages/details/utils.js
index 454c83c9ccd..27cc95566d3 100644
--- a/app/assets/javascripts/packages/details/utils.js
+++ b/app/assets/javascripts/packages/details/utils.js
@@ -8,16 +8,3 @@ export const trackInstallationTabChange = {
},
},
};
-
-export function generateConanRecipe(packageEntity = {}) {
- const {
- name = '',
- version = '',
- conan_metadatum: {
- package_username: packageUsername = '',
- package_channel: packageChannel = '',
- } = {},
- } = packageEntity;
-
- return `${name}/${version}@${packageUsername}/${packageChannel}`;
-}
diff --git a/app/assets/javascripts/packages/list/coming_soon/helpers.js b/app/assets/javascripts/packages/list/coming_soon/helpers.js
deleted file mode 100644
index 5b6a4b3aa87..00000000000
--- a/app/assets/javascripts/packages/list/coming_soon/helpers.js
+++ /dev/null
@@ -1,55 +0,0 @@
-/**
- * Context:
- * https://gitlab.com/gitlab-org/gitlab/-/issues/198524
- * https://gitlab.com/gitlab-org/gitlab/-/merge_requests/29491
- *
- */
-
-/**
- * Constants
- *
- * LABEL_NAMES - an array of labels to filter issues in the GraphQL query
- * WORKFLOW_PREFIX - the prefix for workflow labels
- * ACCEPTING_CONTRIBUTIONS_TITLE - the accepting contributions label
- */
-export const LABEL_NAMES = ['Package::Coming soon'];
-const WORKFLOW_PREFIX = 'workflow::';
-const ACCEPTING_CONTRIBUTIONS_TITLE = 'accepting merge requests';
-
-const setScoped = (label, scoped) => (label ? { ...label, scoped } : label);
-
-/**
- * Finds workflow:: scoped labels and returns the first or null.
- * @param {Object[]} labels Labels from the issue
- */
-export const findWorkflowLabel = (labels = []) =>
- labels.find(l => l.title.toLowerCase().includes(WORKFLOW_PREFIX.toLowerCase()));
-
-/**
- * Determines if an issue is accepting community contributions by checking if
- * the "Accepting merge requests" label is present.
- * @param {Object[]} labels
- */
-export const findAcceptingContributionsLabel = (labels = []) =>
- labels.find(l => l.title.toLowerCase() === ACCEPTING_CONTRIBUTIONS_TITLE.toLowerCase());
-
-/**
- * Formats the GraphQL response into the format that the view template expects.
- * @param {Object} data GraphQL response
- */
-export const toViewModel = data => {
- // This just flatterns the issues -> nodes and labels -> nodes hierarchy
- // into an array of objects.
- const issues = (data.project?.issues?.nodes || []).map(i => ({
- ...i,
- labels: (i.labels?.nodes || []).map(node => node),
- }));
-
- return issues.map(x => ({
- ...x,
- labels: [
- setScoped(findWorkflowLabel(x.labels), true),
- setScoped(findAcceptingContributionsLabel(x.labels), false),
- ].filter(Boolean),
- }));
-};
diff --git a/app/assets/javascripts/packages/list/coming_soon/packages_coming_soon.vue b/app/assets/javascripts/packages/list/coming_soon/packages_coming_soon.vue
deleted file mode 100644
index 766402d3619..00000000000
--- a/app/assets/javascripts/packages/list/coming_soon/packages_coming_soon.vue
+++ /dev/null
@@ -1,172 +0,0 @@
-<script>
-import {
- GlAlert,
- GlEmptyState,
- GlIcon,
- GlLabel,
- GlLink,
- GlSkeletonLoader,
- GlSprintf,
-} from '@gitlab/ui';
-import { ApolloQuery } from 'vue-apollo';
-import Tracking from '~/tracking';
-import { TrackingActions } from '../../shared/constants';
-import { s__ } from '~/locale';
-import comingSoonIssuesQuery from './queries/issues.graphql';
-import { toViewModel, LABEL_NAMES } from './helpers';
-
-export default {
- name: 'ComingSoon',
- components: {
- GlAlert,
- GlEmptyState,
- GlIcon,
- GlLabel,
- GlLink,
- GlSkeletonLoader,
- GlSprintf,
- ApolloQuery,
- },
- mixins: [Tracking.mixin()],
- props: {
- illustration: {
- type: String,
- required: true,
- },
- projectPath: {
- type: String,
- required: true,
- },
- suggestedContributionsPath: {
- type: String,
- required: true,
- },
- },
- computed: {
- variables() {
- return {
- projectPath: this.projectPath,
- labelNames: LABEL_NAMES,
- };
- },
- },
- mounted() {
- this.track(TrackingActions.COMING_SOON_REQUESTED);
- },
- methods: {
- onIssueLinkClick(issueIid, label) {
- this.track(TrackingActions.COMING_SOON_LIST, {
- label,
- value: issueIid,
- });
- },
- onDocsLinkClick() {
- this.track(TrackingActions.COMING_SOON_HELP);
- },
- },
- loadingRows: 5,
- i18n: {
- alertTitle: s__('PackageRegistry|Upcoming package managers'),
- alertIntro: s__(
- "PackageRegistry|Is your favorite package manager missing? We'd love your help in building first-class support for it into GitLab! %{contributionLinkStart}Visit the contribution documentation%{contributionLinkEnd} to learn more about how to build support for new package managers into GitLab. Below is a list of package managers that are on our radar.",
- ),
- emptyStateTitle: s__('PackageRegistry|No upcoming issues'),
- emptyStateDescription: s__('PackageRegistry|There are no upcoming issues to display.'),
- },
- comingSoonIssuesQuery,
- toViewModel,
-};
-</script>
-
-<template>
- <apollo-query
- :query="$options.comingSoonIssuesQuery"
- :variables="variables"
- :update="$options.toViewModel"
- >
- <template #default="{ result: { data }, isLoading }">
- <div>
- <gl-alert :title="$options.i18n.alertTitle" :dismissible="false" variant="tip">
- <gl-sprintf :message="$options.i18n.alertIntro">
- <template #contributionLink="{ content }">
- <gl-link
- :href="suggestedContributionsPath"
- target="_blank"
- @click="onDocsLinkClick"
- >{{ content }}</gl-link
- >
- </template>
- </gl-sprintf>
- </gl-alert>
- </div>
-
- <div v-if="isLoading" class="gl-display-flex gl-flex-direction-column">
- <gl-skeleton-loader
- v-for="index in $options.loadingRows"
- :key="index"
- :width="1000"
- :height="80"
- preserve-aspect-ratio="xMinYMax meet"
- >
- <rect width="700" height="10" x="0" y="16" rx="4" />
- <rect width="60" height="10" x="0" y="45" rx="4" />
- <rect width="60" height="10" x="70" y="45" rx="4" />
- </gl-skeleton-loader>
- </div>
-
- <template v-else-if="data && data.length">
- <div
- v-for="issue in data"
- :key="issue.iid"
- data-testid="issue-row"
- class="gl-responsive-table-row gl-flex-direction-column gl-align-items-baseline"
- >
- <div class="table-section section-100 gl-white-space-normal text-truncate">
- <gl-link
- data-testid="issue-title-link"
- :href="issue.webUrl"
- class="gl-text-gray-900 gl-font-weight-bold"
- @click="onIssueLinkClick(issue.iid, issue.title)"
- >
- {{ issue.title }}
- </gl-link>
- </div>
-
- <div class="table-section section-100 gl-white-space-normal mt-md-3">
- <div class="gl-display-flex gl-text-gray-400">
- <gl-icon name="issues" class="gl-mr-2" />
- <gl-link
- data-testid="issue-id-link"
- :href="issue.webUrl"
- class="gl-text-gray-400 gl-mr-5"
- @click="onIssueLinkClick(issue.iid, issue.title)"
- >#{{ issue.iid }}</gl-link
- >
-
- <div v-if="issue.milestone" class="gl-display-flex gl-align-items-center gl-mr-5">
- <gl-icon name="clock" class="gl-mr-2" />
- <span data-testid="milestone">{{ issue.milestone.title }}</span>
- </div>
-
- <gl-label
- v-for="label in issue.labels"
- :key="label.title"
- class="gl-mr-3"
- size="sm"
- :background-color="label.color"
- :title="label.title"
- :scoped="Boolean(label.scoped)"
- />
- </div>
- </div>
- </div>
- </template>
-
- <gl-empty-state v-else :title="$options.i18n.emptyStateTitle" :svg-path="illustration">
- <template #description>
- <p>{{ $options.i18n.emptyStateDescription }}</p>
- </template>
- </gl-empty-state>
- </template>
- </apollo-query>
-</template>
diff --git a/app/assets/javascripts/packages/list/coming_soon/queries/issues.graphql b/app/assets/javascripts/packages/list/coming_soon/queries/issues.graphql
deleted file mode 100644
index 36c27d9ad70..00000000000
--- a/app/assets/javascripts/packages/list/coming_soon/queries/issues.graphql
+++ /dev/null
@@ -1,20 +0,0 @@
-query getComingSoonIssues($projectPath: ID!, $labelNames: [String]) {
- project(fullPath: $projectPath) {
- issues(state: opened, labelName: $labelNames) {
- nodes {
- iid
- title
- webUrl
- labels {
- nodes {
- title
- color
- }
- }
- milestone {
- title
- }
- }
- }
- }
-}
diff --git a/app/assets/javascripts/packages/list/components/package_title.vue b/app/assets/javascripts/packages/list/components/package_title.vue
new file mode 100644
index 00000000000..f94a98e4ca7
--- /dev/null
+++ b/app/assets/javascripts/packages/list/components/package_title.vue
@@ -0,0 +1,47 @@
+<script>
+import { n__ } from '~/locale';
+import TitleArea from '~/vue_shared/components/registry/title_area.vue';
+import MetadataItem from '~/vue_shared/components/registry/metadata_item.vue';
+import { LIST_INTRO_TEXT, LIST_TITLE_TEXT } from '../constants';
+
+export default {
+ name: 'PackageTitle',
+ components: {
+ TitleArea,
+ MetadataItem,
+ },
+ props: {
+ packagesCount: {
+ type: Number,
+ required: false,
+ default: null,
+ },
+ packageHelpUrl: {
+ type: String,
+ required: true,
+ },
+ },
+ computed: {
+ showPackageCount() {
+ return Number.isInteger(this.packagesCount);
+ },
+ packageAmountText() {
+ return n__(`%d Package`, `%d Packages`, this.packagesCount);
+ },
+ infoMessages() {
+ return [{ text: LIST_INTRO_TEXT, link: this.packageHelpUrl }];
+ },
+ },
+ i18n: {
+ LIST_TITLE_TEXT,
+ },
+};
+</script>
+
+<template>
+ <title-area :title="$options.i18n.LIST_TITLE_TEXT" :info-messages="infoMessages">
+ <template #metadata-amount>
+ <metadata-item v-if="showPackageCount" icon="package" :text="packageAmountText" />
+ </template>
+ </title-area>
+</template>
diff --git a/app/assets/javascripts/packages/list/components/packages_list_app.vue b/app/assets/javascripts/packages/list/components/packages_list_app.vue
index 6304f723f6a..cbb3bfd35ac 100644
--- a/app/assets/javascripts/packages/list/components/packages_list_app.vue
+++ b/app/assets/javascripts/packages/list/components/packages_list_app.vue
@@ -3,13 +3,13 @@ import { mapActions, mapState } from 'vuex';
import { GlEmptyState, GlTab, GlTabs, GlLink, GlSprintf } from '@gitlab/ui';
import { s__, sprintf } from '~/locale';
import createFlash from '~/flash';
+import { historyReplaceState } from '~/lib/utils/common_utils';
+import { SHOW_DELETE_SUCCESS_ALERT } from '~/packages/shared/constants';
import PackageFilter from './packages_filter.vue';
import PackageList from './packages_list.vue';
import PackageSort from './packages_sort.vue';
import { PACKAGE_REGISTRY_TABS, DELETE_PACKAGE_SUCCESS_MESSAGE } from '../constants';
-import PackagesComingSoon from '../coming_soon/packages_coming_soon.vue';
-import { SHOW_DELETE_SUCCESS_ALERT } from '~/packages/shared/constants';
-import { historyReplaceState } from '~/lib/utils/common_utils';
+import PackageTitle from './package_title.vue';
export default {
components: {
@@ -21,15 +21,16 @@ export default {
PackageFilter,
PackageList,
PackageSort,
- PackagesComingSoon,
+ PackageTitle,
},
computed: {
...mapState({
emptyListIllustration: state => state.config.emptyListIllustration,
emptyListHelpUrl: state => state.config.emptyListHelpUrl,
- comingSoon: state => state.config.comingSoon,
filterQuery: state => state.filterQuery,
selectedType: state => state.selectedType,
+ packageHelpUrl: state => state.config.packageHelpUrl,
+ packagesCount: state => state.pagination?.total,
}),
tabsToRender() {
return PACKAGE_REGISTRY_TABS;
@@ -89,39 +90,35 @@ export default {
</script>
<template>
- <gl-tabs @input="tabChanged">
- <template #tabs-end>
- <div
- class="gl-display-flex gl-align-self-center gl-py-2 gl-flex-grow-1 gl-justify-content-end"
- >
- <package-filter class="mr-1" @filter="requestPackagesList" />
- <package-sort @sort:changed="requestPackagesList" />
- </div>
- </template>
+ <div>
+ <package-title :package-help-url="packageHelpUrl" :packages-count="packagesCount" />
- <gl-tab v-for="(tab, index) in tabsToRender" :key="index" :title="tab.title">
- <package-list @page:changed="onPageChanged" @package:delete="onPackageDeleteRequest">
- <template #empty-state>
- <gl-empty-state :title="emptyStateTitle(tab)" :svg-path="emptyListIllustration">
- <template #description>
- <gl-sprintf v-if="filterQuery" :message="$options.i18n.widenFilters" />
- <gl-sprintf v-else :message="$options.i18n.noResults">
- <template #noPackagesLink="{content}">
- <gl-link :href="emptyListHelpUrl" target="_blank">{{ content }}</gl-link>
- </template>
- </gl-sprintf>
- </template>
- </gl-empty-state>
- </template>
- </package-list>
- </gl-tab>
+ <gl-tabs @input="tabChanged">
+ <template #tabs-end>
+ <div
+ class="gl-display-flex gl-align-self-center gl-py-2 gl-flex-grow-1 gl-justify-content-end"
+ >
+ <package-filter class="gl-mr-2" @filter="requestPackagesList" />
+ <package-sort @sort:changed="requestPackagesList" />
+ </div>
+ </template>
- <gl-tab v-if="comingSoon" :title="__('Coming soon')" lazy>
- <packages-coming-soon
- :illustration="emptyListIllustration"
- :project-path="comingSoon.projectPath"
- :suggested-contributions-path="comingSoon.suggestedContributions"
- />
- </gl-tab>
- </gl-tabs>
+ <gl-tab v-for="(tab, index) in tabsToRender" :key="index" :title="tab.title">
+ <package-list @page:changed="onPageChanged" @package:delete="onPackageDeleteRequest">
+ <template #empty-state>
+ <gl-empty-state :title="emptyStateTitle(tab)" :svg-path="emptyListIllustration">
+ <template #description>
+ <gl-sprintf v-if="filterQuery" :message="$options.i18n.widenFilters" />
+ <gl-sprintf v-else :message="$options.i18n.noResults">
+ <template #noPackagesLink="{content}">
+ <gl-link :href="emptyListHelpUrl" target="_blank">{{ content }}</gl-link>
+ </template>
+ </gl-sprintf>
+ </template>
+ </gl-empty-state>
+ </template>
+ </package-list>
+ </gl-tab>
+ </gl-tabs>
+ </div>
</template>
diff --git a/app/assets/javascripts/packages/list/components/packages_sort.vue b/app/assets/javascripts/packages/list/components/packages_sort.vue
index fa8f4f39d54..47e51bbdca5 100644
--- a/app/assets/javascripts/packages/list/components/packages_sort.vue
+++ b/app/assets/javascripts/packages/list/components/packages_sort.vue
@@ -51,7 +51,7 @@ export default {
<gl-sorting-item
v-for="item in sortableFields"
ref="packageListSortItem"
- :key="item.key"
+ :key="item.orderBy"
@click="onSortItemClick(item.orderBy)"
>
{{ item.label }}
diff --git a/app/assets/javascripts/packages/list/constants.js b/app/assets/javascripts/packages/list/constants.js
index 0ff8c86362d..6a0e92bff2d 100644
--- a/app/assets/javascripts/packages/list/constants.js
+++ b/app/assets/javascripts/packages/list/constants.js
@@ -15,7 +15,7 @@ export const GROUP_PAGE_TYPE = 'groups';
export const LIST_KEY_NAME = 'name';
export const LIST_KEY_PROJECT = 'project_path';
export const LIST_KEY_VERSION = 'version';
-export const LIST_KEY_PACKAGE_TYPE = 'package_type';
+export const LIST_KEY_PACKAGE_TYPE = 'type';
export const LIST_KEY_CREATED_AT = 'created_at';
export const LIST_KEY_ACTIONS = 'actions';
@@ -23,47 +23,35 @@ export const LIST_LABEL_NAME = __('Name');
export const LIST_LABEL_PROJECT = __('Project');
export const LIST_LABEL_VERSION = __('Version');
export const LIST_LABEL_PACKAGE_TYPE = __('Type');
-export const LIST_LABEL_CREATED_AT = __('Created');
+export const LIST_LABEL_CREATED_AT = __('Published');
export const LIST_LABEL_ACTIONS = '';
-export const LIST_ORDER_BY_PACKAGE_TYPE = 'type';
-
export const ASCENDING_ODER = 'asc';
export const DESCENDING_ORDER = 'desc';
// The following is not translated because it is used to build a JavaScript exception error message
export const MISSING_DELETE_PATH_ERROR = 'Missing delete_api_path link';
-export const TABLE_HEADER_FIELDS = [
+export const SORT_FIELDS = [
{
- key: LIST_KEY_NAME,
- label: LIST_LABEL_NAME,
orderBy: LIST_KEY_NAME,
- class: ['text-left'],
+ label: LIST_LABEL_NAME,
},
{
- key: LIST_KEY_PROJECT,
- label: LIST_LABEL_PROJECT,
orderBy: LIST_KEY_PROJECT,
- class: ['text-left'],
+ label: LIST_LABEL_PROJECT,
},
{
- key: LIST_KEY_VERSION,
- label: LIST_LABEL_VERSION,
orderBy: LIST_KEY_VERSION,
- class: ['text-center'],
+ label: LIST_LABEL_VERSION,
},
{
- key: LIST_KEY_PACKAGE_TYPE,
+ orderBy: LIST_KEY_PACKAGE_TYPE,
label: LIST_LABEL_PACKAGE_TYPE,
- orderBy: LIST_ORDER_BY_PACKAGE_TYPE,
- class: ['text-center'],
},
{
- key: LIST_KEY_CREATED_AT,
- label: LIST_LABEL_CREATED_AT,
orderBy: LIST_KEY_CREATED_AT,
- class: ['text-center'],
+ label: LIST_LABEL_CREATED_AT,
},
];
@@ -94,7 +82,13 @@ export const PACKAGE_REGISTRY_TABS = [
type: PackageType.NUGET,
},
{
- title: s__('PackageRegistry|PyPi'),
+ title: s__('PackageRegistry|PyPI'),
type: PackageType.PYPI,
},
];
+
+export const LIST_TITLE_TEXT = s__('PackageRegistry|Package Registry');
+
+export const LIST_INTRO_TEXT = s__(
+ 'PackageRegistry|Publish and share packages for a variety of common package managers. %{docLinkStart}More information%{docLinkEnd}',
+);
diff --git a/app/assets/javascripts/packages/list/stores/mutations.js b/app/assets/javascripts/packages/list/stores/mutations.js
index a47ba356c0a..2fe7981b3d9 100644
--- a/app/assets/javascripts/packages/list/stores/mutations.js
+++ b/app/assets/javascripts/packages/list/stores/mutations.js
@@ -1,19 +1,12 @@
import * as types from './mutation_types';
-import {
- parseIntPagination,
- normalizeHeaders,
- convertObjectPropsToCamelCase,
-} from '~/lib/utils/common_utils';
+import { parseIntPagination, normalizeHeaders } from '~/lib/utils/common_utils';
import { GROUP_PAGE_TYPE } from '../constants';
export default {
[types.SET_INITIAL_STATE](state, config) {
const { comingSoonJson, ...rest } = config;
- const comingSoonObj = JSON.parse(comingSoonJson);
-
state.config = {
...rest,
- comingSoon: comingSoonObj && convertObjectPropsToCamelCase(comingSoonObj),
isGroupPage: config.pageType === GROUP_PAGE_TYPE,
};
},
diff --git a/app/assets/javascripts/packages/list/utils.js b/app/assets/javascripts/packages/list/utils.js
index 98d78db8706..6a300d7bfe6 100644
--- a/app/assets/javascripts/packages/list/utils.js
+++ b/app/assets/javascripts/packages/list/utils.js
@@ -1,7 +1,6 @@
-import { LIST_KEY_PROJECT, TABLE_HEADER_FIELDS } from './constants';
+import { LIST_KEY_PROJECT, SORT_FIELDS } from './constants';
-export default isGroupPage =>
- TABLE_HEADER_FIELDS.filter(f => f.key !== LIST_KEY_PROJECT || isGroupPage);
+export default isGroupPage => SORT_FIELDS.filter(f => f.key !== LIST_KEY_PROJECT || isGroupPage);
/**
* A small util function that works out if the delete action has deleted the
diff --git a/app/assets/javascripts/packages/shared/components/package_list_row.vue b/app/assets/javascripts/packages/shared/components/package_list_row.vue
index f93bc51d185..d55ca80a7fc 100644
--- a/app/assets/javascripts/packages/shared/components/package_list_row.vue
+++ b/app/assets/javascripts/packages/shared/components/package_list_row.vue
@@ -1,6 +1,7 @@
<script>
import { GlButton, GlIcon, GlLink, GlSprintf, GlTooltipDirective, GlTruncate } from '@gitlab/ui';
import PackageTags from './package_tags.vue';
+import PackagePath from './package_path.vue';
import PublishMethod from './publish_method.vue';
import { getPackageTypeLabel } from '../utils';
import timeagoMixin from '~/vue_shared/mixins/timeago';
@@ -15,6 +16,7 @@ export default {
GlSprintf,
GlTruncate,
PackageTags,
+ PackagePath,
PublishMethod,
ListItem,
},
@@ -92,22 +94,12 @@ export default {
</gl-sprintf>
</div>
- <div v-if="hasProjectLink" class="gl-display-flex gl-align-items-center">
- <gl-icon name="review-list" class="gl-ml-3 gl-mr-2 gl-min-w-0" />
-
- <gl-link
- class="gl-text-body gl-min-w-0"
- data-testid="packages-row-project"
- :href="`/${packageEntity.project_path}`"
- >
- <gl-truncate :text="packageEntity.projectPathName" />
- </gl-link>
- </div>
-
<div v-if="showPackageType" class="d-flex align-items-center" data-testid="package-type">
<gl-icon name="package" class="gl-ml-3 gl-mr-2" />
<span>{{ packageType }}</span>
</div>
+
+ <package-path v-if="hasProjectLink" :path="packageEntity.project_path" />
</div>
</template>
diff --git a/app/assets/javascripts/packages/shared/components/package_path.vue b/app/assets/javascripts/packages/shared/components/package_path.vue
new file mode 100644
index 00000000000..9afe06ab497
--- /dev/null
+++ b/app/assets/javascripts/packages/shared/components/package_path.vue
@@ -0,0 +1,71 @@
+<script>
+import { GlIcon, GlLink, GlTooltipDirective } from '@gitlab/ui';
+import { joinPaths } from '~/lib/utils/url_utility';
+
+export default {
+ name: 'PackagePath',
+ components: {
+ GlIcon,
+ GlLink,
+ },
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ },
+ props: {
+ path: {
+ type: String,
+ required: true,
+ },
+ },
+ computed: {
+ pathPieces() {
+ return this.path.split('/');
+ },
+ root() {
+ // we skip the first part of the path since is the 'base' group
+ return this.pathPieces[1];
+ },
+ rootLink() {
+ return joinPaths(this.pathPieces[0], this.root);
+ },
+ leaf() {
+ return this.pathPieces[this.pathPieces.length - 1];
+ },
+ deeplyNested() {
+ return this.pathPieces.length > 3;
+ },
+ hasGroup() {
+ return this.root !== this.leaf;
+ },
+ },
+};
+</script>
+
+<template>
+ <div data-qa-selector="package-path" class="gl-display-flex gl-align-items-center">
+ <gl-icon data-testid="base-icon" name="project" class="gl-mx-3 gl-min-w-0" />
+
+ <gl-link data-testid="root-link" class="gl-text-gray-500 gl-min-w-0" :href="`/${rootLink}`">
+ {{ root }}
+ </gl-link>
+
+ <template v-if="hasGroup">
+ <gl-icon data-testid="root-chevron" name="chevron-right" class="gl-mx-2 gl-min-w-0" />
+
+ <template v-if="deeplyNested">
+ <span
+ v-gl-tooltip="{ title: path }"
+ data-testid="ellipsis-icon"
+ class="gl-inset-border-1-gray-200 gl-rounded-base gl-px-2 gl-min-w-0"
+ >
+ <gl-icon name="ellipsis_h" />
+ </span>
+ <gl-icon data-testid="ellipsis-chevron" name="chevron-right" class="gl-mx-2 gl-min-w-0" />
+ </template>
+
+ <gl-link data-testid="leaf-link" class="gl-text-gray-500 gl-min-w-0" :href="`/${path}`">
+ {{ leaf }}
+ </gl-link>
+ </template>
+ </div>
+</template>
diff --git a/app/assets/javascripts/packages/shared/components/publish_method.vue b/app/assets/javascripts/packages/shared/components/publish_method.vue
index d17e23c4032..8a66a33f2ab 100644
--- a/app/assets/javascripts/packages/shared/components/publish_method.vue
+++ b/app/assets/javascripts/packages/shared/components/publish_method.vue
@@ -49,7 +49,8 @@ export default {
<clipboard-button
:text="packageEntity.pipeline.sha"
:title="__('Copy commit SHA')"
- css-class="gl-border-0 gl-py-0 gl-px-2"
+ category="tertiary"
+ size="small"
/>
</template>
diff --git a/app/assets/javascripts/packages/shared/constants.js b/app/assets/javascripts/packages/shared/constants.js
index e5131db59bf..c481abd8658 100644
--- a/app/assets/javascripts/packages/shared/constants.js
+++ b/app/assets/javascripts/packages/shared/constants.js
@@ -14,9 +14,6 @@ export const TrackingActions = {
REQUEST_DELETE_PACKAGE: 'request_delete_package',
CANCEL_DELETE_PACKAGE: 'cancel_delete_package',
PULL_PACKAGE: 'pull_package',
- COMING_SOON_REQUESTED: 'activate_coming_soon_requested',
- COMING_SOON_LIST: 'click_coming_soon_issue_link',
- COMING_SOON_HELP: 'click_coming_soon_documentation_link',
};
export const TrackingCategories = {
diff --git a/app/assets/javascripts/packages/shared/utils.js b/app/assets/javascripts/packages/shared/utils.js
index a0c7389651d..b0807558266 100644
--- a/app/assets/javascripts/packages/shared/utils.js
+++ b/app/assets/javascripts/packages/shared/utils.js
@@ -18,7 +18,7 @@ export const getPackageTypeLabel = packageType => {
case PackageType.NUGET:
return s__('PackageType|NuGet');
case PackageType.PYPI:
- return s__('PackageType|PyPi');
+ return s__('PackageType|PyPI');
case PackageType.COMPOSER:
return s__('PackageType|Composer');
diff --git a/app/assets/javascripts/pages/admin/credentials/index.js b/app/assets/javascripts/pages/admin/credentials/index.js
new file mode 100644
index 00000000000..868c8e33077
--- /dev/null
+++ b/app/assets/javascripts/pages/admin/credentials/index.js
@@ -0,0 +1,3 @@
+import initConfirmModal from '~/confirm_modal';
+
+initConfirmModal();
diff --git a/app/assets/javascripts/pages/admin/instance_statistics/index.js b/app/assets/javascripts/pages/admin/instance_statistics/index.js
new file mode 100644
index 00000000000..d6b0a834ce3
--- /dev/null
+++ b/app/assets/javascripts/pages/admin/instance_statistics/index.js
@@ -0,0 +1,3 @@
+import initInstanceStatisticsApp from '~/analytics/instance_statistics';
+
+document.addEventListener('DOMContentLoaded', () => initInstanceStatisticsApp());
diff --git a/app/assets/javascripts/pages/admin/keys/index.js b/app/assets/javascripts/pages/admin/keys/index.js
new file mode 100644
index 00000000000..45b83ffcd67
--- /dev/null
+++ b/app/assets/javascripts/pages/admin/keys/index.js
@@ -0,0 +1,5 @@
+import initConfirmModal from '~/confirm_modal';
+
+document.addEventListener('DOMContentLoaded', () => {
+ initConfirmModal();
+});
diff --git a/app/assets/javascripts/pages/admin/users/keys/index.js b/app/assets/javascripts/pages/admin/users/keys/index.js
new file mode 100644
index 00000000000..45b83ffcd67
--- /dev/null
+++ b/app/assets/javascripts/pages/admin/users/keys/index.js
@@ -0,0 +1,5 @@
+import initConfirmModal from '~/confirm_modal';
+
+document.addEventListener('DOMContentLoaded', () => {
+ initConfirmModal();
+});
diff --git a/app/assets/javascripts/pages/dashboard/merge_requests/index.js b/app/assets/javascripts/pages/dashboard/merge_requests/index.js
index 10df18c85e7..7adae2cdb05 100644
--- a/app/assets/javascripts/pages/dashboard/merge_requests/index.js
+++ b/app/assets/javascripts/pages/dashboard/merge_requests/index.js
@@ -5,7 +5,7 @@ import IssuableFilteredSearchTokenKeys from '~/filtered_search/issuable_filtered
import { FILTERED_SEARCH } from '~/pages/constants';
document.addEventListener('DOMContentLoaded', () => {
- addExtraTokensForMergeRequests(IssuableFilteredSearchTokenKeys);
+ addExtraTokensForMergeRequests(IssuableFilteredSearchTokenKeys, true);
initFilteredSearch({
page: FILTERED_SEARCH.MERGE_REQUESTS,
diff --git a/app/assets/javascripts/pages/groups/group_members/index.js b/app/assets/javascripts/pages/groups/group_members/index.js
index 3fa3a132dfa..dc647f5d3cb 100644
--- a/app/assets/javascripts/pages/groups/group_members/index.js
+++ b/app/assets/javascripts/pages/groups/group_members/index.js
@@ -4,7 +4,8 @@ import memberExpirationDate from '~/member_expiration_date';
import UsersSelect from '~/users_select';
import groupsSelect from '~/groups_select';
import RemoveMemberModal from '~/vue_shared/components/remove_member_modal.vue';
-import initGroupMembersApp from '~/groups/members';
+import { initGroupMembersApp } from '~/groups/members';
+import { memberRequestFormatter, groupLinkRequestFormatter } from '~/groups/members/utils';
function mountRemoveMemberModal() {
const el = document.querySelector('.js-remove-member-modal');
@@ -26,10 +27,28 @@ document.addEventListener('DOMContentLoaded', () => {
memberExpirationDate('.js-access-expiration-date-groups');
mountRemoveMemberModal();
- initGroupMembersApp(document.querySelector('.js-group-members-list'));
- initGroupMembersApp(document.querySelector('.js-group-linked-list'));
- initGroupMembersApp(document.querySelector('.js-group-invited-members-list'));
- initGroupMembersApp(document.querySelector('.js-group-access-requests-list'));
+ const SHARED_FIELDS = ['account', 'expires', 'maxRole', 'expiration', 'actions'];
+
+ initGroupMembersApp(
+ document.querySelector('.js-group-members-list'),
+ SHARED_FIELDS.concat(['source', 'granted']),
+ memberRequestFormatter,
+ );
+ initGroupMembersApp(
+ document.querySelector('.js-group-linked-list'),
+ SHARED_FIELDS.concat('granted'),
+ groupLinkRequestFormatter,
+ );
+ initGroupMembersApp(
+ document.querySelector('.js-group-invited-members-list'),
+ SHARED_FIELDS.concat('invited'),
+ memberRequestFormatter,
+ );
+ initGroupMembersApp(
+ document.querySelector('.js-group-access-requests-list'),
+ SHARED_FIELDS.concat('requested'),
+ memberRequestFormatter,
+ );
new Members(); // eslint-disable-line no-new
new UsersSelect(); // eslint-disable-line no-new
diff --git a/app/assets/javascripts/pages/groups/issues/index.js b/app/assets/javascripts/pages/groups/issues/index.js
index ae481d16ee9..4d0a03e151a 100644
--- a/app/assets/javascripts/pages/groups/issues/index.js
+++ b/app/assets/javascripts/pages/groups/issues/index.js
@@ -8,18 +8,16 @@ import initManualOrdering from '~/manual_ordering';
const ISSUE_BULK_UPDATE_PREFIX = 'issue_';
-document.addEventListener('DOMContentLoaded', () => {
- IssuableFilteredSearchTokenKeys.addExtraTokensForIssues();
- issuableInitBulkUpdateSidebar.init(ISSUE_BULK_UPDATE_PREFIX);
+IssuableFilteredSearchTokenKeys.addExtraTokensForIssues();
+issuableInitBulkUpdateSidebar.init(ISSUE_BULK_UPDATE_PREFIX);
- initIssuablesList();
+initIssuablesList();
- initFilteredSearch({
- page: FILTERED_SEARCH.ISSUES,
- isGroupDecendent: true,
- useDefaultState: true,
- filteredSearchTokenKeys: IssuableFilteredSearchTokenKeys,
- });
- projectSelect();
- initManualOrdering();
+initFilteredSearch({
+ page: FILTERED_SEARCH.ISSUES,
+ isGroupDecendent: true,
+ useDefaultState: true,
+ filteredSearchTokenKeys: IssuableFilteredSearchTokenKeys,
});
+projectSelect();
+initManualOrdering();
diff --git a/app/assets/javascripts/pages/groups/registry/repositories/index.js b/app/assets/javascripts/pages/groups/registry/repositories/index.js
index cdafe838994..6fd32321568 100644
--- a/app/assets/javascripts/pages/groups/registry/repositories/index.js
+++ b/app/assets/javascripts/pages/groups/registry/repositories/index.js
@@ -1,10 +1,8 @@
import registryExplorer from '~/registry/explorer/index';
-document.addEventListener('DOMContentLoaded', () => {
- const explorer = registryExplorer();
+const explorer = registryExplorer();
- if (explorer) {
- explorer.attachBreadcrumb();
- explorer.attachMainComponent();
- }
-});
+if (explorer) {
+ explorer.attachBreadcrumb();
+ explorer.attachMainComponent();
+}
diff --git a/app/assets/javascripts/pages/groups/security/credentials/index.js b/app/assets/javascripts/pages/groups/security/credentials/index.js
new file mode 100644
index 00000000000..868c8e33077
--- /dev/null
+++ b/app/assets/javascripts/pages/groups/security/credentials/index.js
@@ -0,0 +1,3 @@
+import initConfirmModal from '~/confirm_modal';
+
+initConfirmModal();
diff --git a/app/assets/javascripts/pages/groups/settings/ci_cd/show/index.js b/app/assets/javascripts/pages/groups/settings/ci_cd/show/index.js
index add483843df..67eb09da5e0 100644
--- a/app/assets/javascripts/pages/groups/settings/ci_cd/show/index.js
+++ b/app/assets/javascripts/pages/groups/settings/ci_cd/show/index.js
@@ -4,6 +4,7 @@ import initVariableList from '~/ci_variable_list';
import initFilteredSearch from '~/pages/search/init_filtered_search';
import GroupRunnersFilteredSearchTokenKeys from '~/filtered_search/group_runners_filtered_search_token_keys';
import { FILTERED_SEARCH } from '~/pages/constants';
+import initSharedRunnersForm from '~/group_settings/mount_shared_runners';
document.addEventListener('DOMContentLoaded', () => {
// Initialize expandable settings panels
@@ -29,4 +30,6 @@ document.addEventListener('DOMContentLoaded', () => {
maskableRegex: variableListEl.dataset.maskableRegex,
});
}
+
+ initSharedRunnersForm();
});
diff --git a/app/assets/javascripts/pages/milestones/shared/components/delete_milestone_modal.vue b/app/assets/javascripts/pages/milestones/shared/components/delete_milestone_modal.vue
index 983062c79f1..93fe38831be 100644
--- a/app/assets/javascripts/pages/milestones/shared/components/delete_milestone_modal.vue
+++ b/app/assets/javascripts/pages/milestones/shared/components/delete_milestone_modal.vue
@@ -1,16 +1,15 @@
<script>
-import { GlSafeHtmlDirective as SafeHtml } from '@gitlab/ui';
+import { GlSafeHtmlDirective as SafeHtml, GlModal } from '@gitlab/ui';
import axios from '~/lib/utils/axios_utils';
import { deprecatedCreateFlash as Flash } from '~/flash';
-import DeprecatedModal from '~/vue_shared/components/deprecated_modal.vue';
-import { n__, s__, sprintf } from '~/locale';
+import { __, n__, s__, sprintf } from '~/locale';
import { redirectTo } from '~/lib/utils/url_utility';
import eventHub from '../event_hub';
export default {
components: {
- DeprecatedModal,
+ GlModal,
},
directives: {
SafeHtml,
@@ -115,20 +114,24 @@ Once deleted, it cannot be undone or recovered.`),
});
},
},
+ primaryProps: {
+ text: s__('Milestones|Delete milestone'),
+ attributes: [{ variant: 'danger' }, { category: 'primary' }],
+ },
+ cancelProps: {
+ text: __('Cancel'),
+ },
};
</script>
<template>
- <deprecated-modal
- id="delete-milestone-modal"
+ <gl-modal
+ modal-id="delete-milestone-modal"
:title="title"
- :text="text"
- :primary-button-label="s__('Milestones|Delete milestone')"
- kind="danger"
- @submit="onSubmit"
+ :action-primary="$options.primaryProps"
+ :action-cancel="$options.cancelProps"
+ @primary="onSubmit"
>
- <template #body="props">
- <p v-safe-html="props.text"></p>
- </template>
- </deprecated-modal>
+ <p v-safe-html="text"></p>
+ </gl-modal>
</template>
diff --git a/app/assets/javascripts/pages/milestones/shared/delete_milestone_modal_init.js b/app/assets/javascripts/pages/milestones/shared/delete_milestone_modal_init.js
index 1d559dc6e41..6e68114e04b 100644
--- a/app/assets/javascripts/pages/milestones/shared/delete_milestone_modal_init.js
+++ b/app/assets/javascripts/pages/milestones/shared/delete_milestone_modal_init.js
@@ -1,6 +1,6 @@
import Vue from 'vue';
import Translate from '~/vue_shared/translate';
-import deleteMilestoneModal from './components/delete_milestone_modal.vue';
+import DeleteMilestoneModal from './components/delete_milestone_modal.vue';
import eventHub from './event_hub';
export default () => {
@@ -18,6 +18,8 @@ export default () => {
button.querySelector('.js-loading-icon').classList.add('hidden');
};
+ const deleteMilestoneButtons = document.querySelectorAll('.js-delete-milestone-button');
+
const onRequestStarted = milestoneUrl => {
const button = document.querySelector(
`.js-delete-milestone-button[data-milestone-url="${milestoneUrl}"]`,
@@ -27,35 +29,8 @@ export default () => {
eventHub.$once('deleteMilestoneModal.requestFinished', onRequestFinished);
};
- const onDeleteButtonClick = event => {
- const button = event.currentTarget;
- const modalProps = {
- milestoneId: parseInt(button.dataset.milestoneId, 10),
- milestoneTitle: button.dataset.milestoneTitle,
- milestoneUrl: button.dataset.milestoneUrl,
- issueCount: parseInt(button.dataset.milestoneIssueCount, 10),
- mergeRequestCount: parseInt(button.dataset.milestoneMergeRequestCount, 10),
- };
- eventHub.$once('deleteMilestoneModal.requestStarted', onRequestStarted);
- eventHub.$emit('deleteMilestoneModal.props', modalProps);
- };
-
- const deleteMilestoneButtons = document.querySelectorAll('.js-delete-milestone-button');
- deleteMilestoneButtons.forEach(button => {
- button.addEventListener('click', onDeleteButtonClick);
- });
-
- eventHub.$once('deleteMilestoneModal.mounted', () => {
- deleteMilestoneButtons.forEach(button => {
- button.removeAttribute('disabled');
- });
- });
-
return new Vue({
- el: '#delete-milestone-modal',
- components: {
- deleteMilestoneModal,
- },
+ el: '#js-delete-milestone-modal',
data() {
return {
modalProps: {
@@ -69,10 +44,21 @@ export default () => {
},
mounted() {
eventHub.$on('deleteMilestoneModal.props', this.setModalProps);
- eventHub.$emit('deleteMilestoneModal.mounted');
- },
- beforeDestroy() {
- eventHub.$off('deleteMilestoneModal.props', this.setModalProps);
+ deleteMilestoneButtons.forEach(button => {
+ button.removeAttribute('disabled');
+ button.addEventListener('click', () => {
+ this.$root.$emit('bv::show::modal', 'delete-milestone-modal');
+ eventHub.$once('deleteMilestoneModal.requestStarted', onRequestStarted);
+
+ this.setModalProps({
+ milestoneId: parseInt(button.dataset.milestoneId, 10),
+ milestoneTitle: button.dataset.milestoneTitle,
+ milestoneUrl: button.dataset.milestoneUrl,
+ issueCount: parseInt(button.dataset.milestoneIssueCount, 10),
+ mergeRequestCount: parseInt(button.dataset.milestoneMergeRequestCount, 10),
+ });
+ });
+ });
},
methods: {
setModalProps(modalProps) {
@@ -80,7 +66,7 @@ export default () => {
},
},
render(createElement) {
- return createElement(deleteMilestoneModal, {
+ return createElement(DeleteMilestoneModal, {
props: this.modalProps,
});
},
diff --git a/app/assets/javascripts/pages/profiles/keys/index.js b/app/assets/javascripts/pages/profiles/keys/index.js
index d3dcd21f456..4214d5bffb2 100644
--- a/app/assets/javascripts/pages/profiles/keys/index.js
+++ b/app/assets/javascripts/pages/profiles/keys/index.js
@@ -1,6 +1,9 @@
+import initConfirmModal from '~/confirm_modal';
import AddSshKeyValidation from '~/profile/add_ssh_key_validation';
document.addEventListener('DOMContentLoaded', () => {
+ initConfirmModal();
+
const input = document.querySelector('.js-add-ssh-key-validation-input');
if (!input) return;
diff --git a/app/assets/javascripts/pages/projects/blob/show/index.js b/app/assets/javascripts/pages/projects/blob/show/index.js
index 46e59cd6572..f2e8cb38ef5 100644
--- a/app/assets/javascripts/pages/projects/blob/show/index.js
+++ b/app/assets/javascripts/pages/projects/blob/show/index.js
@@ -3,34 +3,33 @@ import commitPipelineStatus from '~/projects/tree/components/commit_pipeline_sta
import BlobViewer from '~/blob/viewer/index';
import initBlob from '~/pages/projects/init_blob';
import GpgBadges from '~/gpg_badges';
+import initWebIdeLink from '~/pages/projects/shared/web_ide_link';
import '~/sourcegraph/load';
import PipelineTourSuccessModal from '~/blob/pipeline_tour_success_modal.vue';
+import { parseBoolean } from '~/lib/utils/common_utils';
+import { isExperimentEnabled } from '~/lib/utils/experimentation';
const createGitlabCiYmlVisualization = (containerId = '#js-blob-toggle-graph-preview') => {
const el = document.querySelector(containerId);
- const { filename, blobData } = el?.dataset;
+ const { isCiConfigFile, blobData } = el?.dataset;
- const nameRegexp = /\.gitlab-ci.yml/;
-
- if (!el || !nameRegexp.test(filename)) {
- return;
+ if (el && parseBoolean(isCiConfigFile)) {
+ // eslint-disable-next-line no-new
+ new Vue({
+ el,
+ components: {
+ GitlabCiYamlVisualization: () =>
+ import('~/pipelines/components/pipeline_graph/gitlab_ci_yaml_visualization.vue'),
+ },
+ render(createElement) {
+ return createElement('gitlabCiYamlVisualization', {
+ props: {
+ blobData,
+ },
+ });
+ },
+ });
}
-
- // eslint-disable-next-line no-new
- new Vue({
- el,
- components: {
- GitlabCiYamlVisualization: () =>
- import('~/pipelines/components/pipeline_graph/gitlab_ci_yaml_visualization.vue'),
- },
- render(createElement) {
- return createElement('gitlabCiYamlVisualization', {
- props: {
- blobData,
- },
- });
- },
- });
};
document.addEventListener('DOMContentLoaded', () => {
@@ -57,11 +56,13 @@ document.addEventListener('DOMContentLoaded', () => {
});
}
+ initWebIdeLink({ el: document.getElementById('js-blob-web-ide-link') });
+
GpgBadges.fetch();
const codeNavEl = document.getElementById('js-code-navigation');
- if (gon.features?.codeNavigation && codeNavEl) {
+ if (codeNavEl) {
const { codeNavigationPath, blobPath, definitionPathPrefix } = codeNavEl.dataset;
// eslint-disable-next-line promise/catch-or-return
@@ -73,7 +74,7 @@ document.addEventListener('DOMContentLoaded', () => {
);
}
- if (gon.features?.suggestPipeline) {
+ if (isExperimentEnabled('suggestPipeline')) {
const successPipelineEl = document.querySelector('.js-success-pipeline-modal');
if (successPipelineEl) {
diff --git a/app/assets/javascripts/pages/projects/ci/lints/ci_lint_editor.js b/app/assets/javascripts/pages/projects/ci/lints/ci_lint_editor.js
index d270bee25c7..df635522e94 100644
--- a/app/assets/javascripts/pages/projects/ci/lints/ci_lint_editor.js
+++ b/app/assets/javascripts/pages/projects/ci/lints/ci_lint_editor.js
@@ -1,13 +1,11 @@
-import createFlash from '~/flash';
-import { BLOB_EDITOR_ERROR } from '~/blob_edit/constants';
+import EditorLite from '~/editor/editor_lite';
export default class CILintEditor {
constructor() {
- const monacoEnabled = window?.gon?.features?.monacoCi;
this.clearYml = document.querySelector('.clear-yml');
this.clearYml.addEventListener('click', this.clear.bind(this));
- return monacoEnabled ? this.initEditorLite() : this.initAce();
+ return this.initEditorLite();
}
clear() {
@@ -15,34 +13,20 @@ export default class CILintEditor {
}
initEditorLite() {
- import(/* webpackChunkName: 'monaco_editor_lite' */ '~/editor/editor_lite')
- .then(({ default: EditorLite }) => {
- const editorEl = document.getElementById('editor');
- const fileContentEl = document.getElementById('content');
- const form = document.querySelector('.js-ci-lint-form');
+ const editorEl = document.getElementById('editor');
+ const fileContentEl = document.getElementById('content');
+ const form = document.querySelector('.js-ci-lint-form');
- const rootEditor = new EditorLite();
+ const rootEditor = new EditorLite();
- this.editor = rootEditor.createInstance({
- el: editorEl,
- blobPath: '.gitlab-ci.yml',
- blobContent: editorEl.innerText,
- });
-
- form.addEventListener('submit', () => {
- fileContentEl.value = this.editor.getValue();
- });
- })
- .catch(() => createFlash({ message: BLOB_EDITOR_ERROR }));
- }
-
- initAce() {
- this.editor = window.ace.edit('ci-editor');
- this.textarea = document.getElementById('content');
+ this.editor = rootEditor.createInstance({
+ el: editorEl,
+ blobPath: '.gitlab-ci.yml',
+ blobContent: editorEl.innerText,
+ });
- this.editor.getSession().setMode('ace/mode/yaml');
- this.editor.on('input', () => {
- this.textarea.value = this.editor.getSession().getValue();
+ form.addEventListener('submit', () => {
+ fileContentEl.value = this.editor.getValue();
});
}
}
diff --git a/app/assets/javascripts/pages/projects/ci/lints/new/index.js b/app/assets/javascripts/pages/projects/ci/lints/new/index.js
index 02bfee9810f..957801320c9 100644
--- a/app/assets/javascripts/pages/projects/ci/lints/new/index.js
+++ b/app/assets/javascripts/pages/projects/ci/lints/new/index.js
@@ -1,11 +1,17 @@
-import CILintEditor from '../ci_lint_editor';
-import initCILint from '~/ci_lint/index';
+import createFlash from '~/flash';
+import { __ } from '~/locale';
+
+const ERROR = __('An error occurred while rendering the linter');
document.addEventListener('DOMContentLoaded', () => {
if (gon?.features?.ciLintVue) {
- initCILint();
+ import(/* webpackChunkName: 'ciLintIndex' */ '~/ci_lint/index')
+ .then(module => module.default())
+ .catch(() => createFlash(ERROR));
} else {
- // eslint-disable-next-line no-new
- new CILintEditor();
+ import(/* webpackChunkName: 'ciLintEditor' */ '../ci_lint_editor')
+ // eslint-disable-next-line new-cap
+ .then(module => new module.default())
+ .catch(() => createFlash(ERROR));
}
});
diff --git a/app/assets/javascripts/pages/projects/ci/lints/show/index.js b/app/assets/javascripts/pages/projects/ci/lints/show/index.js
index 8e8a843da0b..957801320c9 100644
--- a/app/assets/javascripts/pages/projects/ci/lints/show/index.js
+++ b/app/assets/javascripts/pages/projects/ci/lints/show/index.js
@@ -1,3 +1,17 @@
-import CILintEditor from '../ci_lint_editor';
+import createFlash from '~/flash';
+import { __ } from '~/locale';
-document.addEventListener('DOMContentLoaded', () => new CILintEditor());
+const ERROR = __('An error occurred while rendering the linter');
+
+document.addEventListener('DOMContentLoaded', () => {
+ if (gon?.features?.ciLintVue) {
+ import(/* webpackChunkName: 'ciLintIndex' */ '~/ci_lint/index')
+ .then(module => module.default())
+ .catch(() => createFlash(ERROR));
+ } else {
+ import(/* webpackChunkName: 'ciLintEditor' */ '../ci_lint_editor')
+ // eslint-disable-next-line new-cap
+ .then(module => new module.default())
+ .catch(() => createFlash(ERROR));
+ }
+});
diff --git a/app/assets/javascripts/pages/projects/clusters/index/index.js b/app/assets/javascripts/pages/projects/clusters/index/index.js
index 744be65bfbe..1124eb5d939 100644
--- a/app/assets/javascripts/pages/projects/clusters/index/index.js
+++ b/app/assets/javascripts/pages/projects/clusters/index/index.js
@@ -1,5 +1,5 @@
+import initClustersListApp from 'ee_else_ce/clusters_list';
import PersistentUserCallout from '~/persistent_user_callout';
-import initClustersListApp from '~/clusters_list';
document.addEventListener('DOMContentLoaded', () => {
const callout = document.querySelector('.gcp-signup-offer');
diff --git a/app/assets/javascripts/pages/projects/commit/pipelines/index.js b/app/assets/javascripts/pages/projects/commit/pipelines/index.js
index 1415a6f60c8..26dea17ca8a 100644
--- a/app/assets/javascripts/pages/projects/commit/pipelines/index.js
+++ b/app/assets/javascripts/pages/projects/commit/pipelines/index.js
@@ -1,14 +1,8 @@
-import $ from 'jquery';
-import MiniPipelineGraph from '~/mini_pipeline_graph_dropdown';
+import { initCommitBoxInfo } from '~/projects/commit_box/info';
import initPipelines from '~/commit/pipelines/pipelines_bundle';
-import { fetchCommitMergeRequests } from '~/commit_merge_requests';
document.addEventListener('DOMContentLoaded', () => {
- new MiniPipelineGraph({
- container: '.js-commit-pipeline-graph',
- }).bindEvents();
- // eslint-disable-next-line no-jquery/no-load
- $('.commit-info.branches').load(document.querySelector('.js-commit-box').dataset.commitPath);
- fetchCommitMergeRequests();
+ initCommitBoxInfo();
+
initPipelines();
});
diff --git a/app/assets/javascripts/pages/projects/commit/show/index.js b/app/assets/javascripts/pages/projects/commit/show/index.js
index d5fb2a8be3c..32fb35f97e3 100644
--- a/app/assets/javascripts/pages/projects/commit/show/index.js
+++ b/app/assets/javascripts/pages/projects/commit/show/index.js
@@ -4,10 +4,8 @@ import $ from 'jquery';
import Diff from '~/diff';
import ZenMode from '~/zen_mode';
import ShortcutsNavigation from '~/behaviors/shortcuts/shortcuts_navigation';
-import MiniPipelineGraph from '~/mini_pipeline_graph_dropdown';
import initNotes from '~/init_notes';
import initChangesDropdown from '~/init_changes_dropdown';
-import { fetchCommitMergeRequests } from '~/commit_merge_requests';
import '~/sourcegraph/load';
import { handleLocationHash } from '~/lib/utils/common_utils';
import axios from '~/lib/utils/axios_utils';
@@ -15,6 +13,7 @@ import syntaxHighlight from '~/syntax_highlight';
import flash from '~/flash';
import { __ } from '~/locale';
import loadAwardsHandler from '~/awards_handler';
+import { initCommitBoxInfo } from '~/projects/commit_box/info';
document.addEventListener('DOMContentLoaded', () => {
const hasPerfBar = document.querySelector('.with-performance-bar');
@@ -22,13 +21,10 @@ document.addEventListener('DOMContentLoaded', () => {
initChangesDropdown(document.querySelector('.navbar-gitlab').offsetHeight + performanceHeight);
new ZenMode();
new ShortcutsNavigation();
- new MiniPipelineGraph({
- container: '.js-commit-pipeline-graph',
- }).bindEvents();
+
+ initCommitBoxInfo();
+
initNotes();
- // eslint-disable-next-line no-jquery/no-load
- $('.commit-info.branches').load(document.querySelector('.js-commit-box').dataset.commitPath);
- fetchCommitMergeRequests();
const filesContainer = $('.js-diffs-batch');
diff --git a/app/assets/javascripts/pages/projects/environments/index/index.js b/app/assets/javascripts/pages/projects/environments/index/index.js
index ace8af00ece..4d5106f6d5f 100644
--- a/app/assets/javascripts/pages/projects/environments/index/index.js
+++ b/app/assets/javascripts/pages/projects/environments/index/index.js
@@ -1,3 +1,3 @@
-import initEnviroments from '~/environments/';
+import initEnvironments from '~/environments/';
-document.addEventListener('DOMContentLoaded', initEnviroments);
+document.addEventListener('DOMContentLoaded', initEnvironments);
diff --git a/app/assets/javascripts/pages/projects/feature_flags/edit/index.js b/app/assets/javascripts/pages/projects/feature_flags/edit/index.js
new file mode 100644
index 00000000000..36b1d800103
--- /dev/null
+++ b/app/assets/javascripts/pages/projects/feature_flags/edit/index.js
@@ -0,0 +1,3 @@
+import initEditFeatureFlags from '~/feature_flags/edit';
+
+initEditFeatureFlags();
diff --git a/app/assets/javascripts/pages/projects/feature_flags/index/index.js b/app/assets/javascripts/pages/projects/feature_flags/index/index.js
new file mode 100644
index 00000000000..c11a5c929ee
--- /dev/null
+++ b/app/assets/javascripts/pages/projects/feature_flags/index/index.js
@@ -0,0 +1,3 @@
+import initFeatureFlags from '~/feature_flags';
+
+initFeatureFlags();
diff --git a/app/assets/javascripts/pages/projects/feature_flags/new/index.js b/app/assets/javascripts/pages/projects/feature_flags/new/index.js
new file mode 100644
index 00000000000..d598f6b31dd
--- /dev/null
+++ b/app/assets/javascripts/pages/projects/feature_flags/new/index.js
@@ -0,0 +1,3 @@
+import initNewFeatureFlags from '~/feature_flags/new';
+
+initNewFeatureFlags();
diff --git a/app/assets/javascripts/pages/projects/feature_flags_user_lists/edit/index.js b/app/assets/javascripts/pages/projects/feature_flags_user_lists/edit/index.js
new file mode 100644
index 00000000000..bbe84322462
--- /dev/null
+++ b/app/assets/javascripts/pages/projects/feature_flags_user_lists/edit/index.js
@@ -0,0 +1,19 @@
+import Vue from 'vue';
+import Vuex from 'vuex';
+import EditUserList from '~/user_lists/components/edit_user_list.vue';
+import createStore from '~/user_lists/store/edit';
+
+Vue.use(Vuex);
+
+document.addEventListener('DOMContentLoaded', () => {
+ const el = document.getElementById('js-edit-user-list');
+ const { userListsDocsPath } = el.dataset;
+ return new Vue({
+ el,
+ store: createStore(el.dataset),
+ provide: { userListsDocsPath },
+ render(h) {
+ return h(EditUserList, {});
+ },
+ });
+});
diff --git a/app/assets/javascripts/pages/projects/feature_flags_user_lists/new/index.js b/app/assets/javascripts/pages/projects/feature_flags_user_lists/new/index.js
new file mode 100644
index 00000000000..679f0af8efc
--- /dev/null
+++ b/app/assets/javascripts/pages/projects/feature_flags_user_lists/new/index.js
@@ -0,0 +1,22 @@
+import Vue from 'vue';
+import Vuex from 'vuex';
+import NewUserList from '~/user_lists/components/new_user_list.vue';
+import createStore from '~/user_lists/store/new';
+
+Vue.use(Vuex);
+
+document.addEventListener('DOMContentLoaded', () => {
+ const el = document.getElementById('js-new-user-list');
+ const { userListsDocsPath, featureFlagsPath } = el.dataset;
+ return new Vue({
+ el,
+ store: createStore(el.dataset),
+ provide: {
+ userListsDocsPath,
+ featureFlagsPath,
+ },
+ render(h) {
+ return h(NewUserList);
+ },
+ });
+});
diff --git a/app/assets/javascripts/pages/projects/feature_flags_user_lists/show/index.js b/app/assets/javascripts/pages/projects/feature_flags_user_lists/show/index.js
new file mode 100644
index 00000000000..bccd9dce2ec
--- /dev/null
+++ b/app/assets/javascripts/pages/projects/feature_flags_user_lists/show/index.js
@@ -0,0 +1,18 @@
+import Vue from 'vue';
+import Vuex from 'vuex';
+import UserList from '~/user_lists/components/user_list.vue';
+import createStore from '~/user_lists/store/show';
+
+Vue.use(Vuex);
+
+document.addEventListener('DOMContentLoaded', () => {
+ const el = document.getElementById('js-edit-user-list');
+ return new Vue({
+ el,
+ store: createStore(el.dataset),
+ render(h) {
+ const { emptyStatePath } = el.dataset;
+ return h(UserList, { props: { emptyStatePath } });
+ },
+ });
+});
diff --git a/app/assets/javascripts/pages/projects/graphs/charts/index.js b/app/assets/javascripts/pages/projects/graphs/charts/index.js
index 384216f29eb..74abd1f67a5 100644
--- a/app/assets/javascripts/pages/projects/graphs/charts/index.js
+++ b/app/assets/javascripts/pages/projects/graphs/charts/index.js
@@ -1,6 +1,6 @@
-import Vue from 'vue';
import { GlColumnChart } from '@gitlab/ui/dist/charts';
-import { waitForCSSLoaded } from '../../../../helpers/startup_css_helper';
+import Vue from 'vue';
+import { waitForCSSLoaded } from '~/helpers/startup_css_helper';
import { __ } from '~/locale';
import CodeCoverage from '../components/code_coverage.vue';
import SeriesDataMixin from './series_data_mixin';
diff --git a/app/assets/javascripts/pages/projects/graphs/components/code_coverage.vue b/app/assets/javascripts/pages/projects/graphs/components/code_coverage.vue
index 5d59880d497..a9079f91f50 100644
--- a/app/assets/javascripts/pages/projects/graphs/components/code_coverage.vue
+++ b/app/assets/javascripts/pages/projects/graphs/components/code_coverage.vue
@@ -1,11 +1,5 @@
<script>
-import {
- GlAlert,
- GlDeprecatedDropdown,
- GlDeprecatedDropdownItem,
- GlIcon,
- GlSprintf,
-} from '@gitlab/ui';
+import { GlAlert, GlDropdown, GlDropdownItem, GlSprintf } from '@gitlab/ui';
import { GlAreaChart } from '@gitlab/ui/dist/charts';
import dateFormat from 'dateformat';
import { get } from 'lodash';
@@ -17,9 +11,8 @@ export default {
components: {
GlAlert,
GlAreaChart,
- GlDeprecatedDropdown,
- GlDeprecatedDropdownItem,
- GlIcon,
+ GlDropdown,
+ GlDropdownItem,
GlSprintf,
},
props: {
@@ -140,25 +133,18 @@ export default {
{{ __('It seems that there is currently no available data for code coverage') }}
</span>
</gl-alert>
- <gl-deprecated-dropdown v-if="canShowData" :text="selectedDailyCoverageName">
- <gl-deprecated-dropdown-item
+ <gl-dropdown v-if="canShowData" :text="selectedDailyCoverageName">
+ <gl-dropdown-item
v-for="({ group_name }, index) in dailyCoverageData"
:key="index"
:value="group_name"
+ :is-check-item="true"
+ :is-checked="index === selectedCoverageIndex"
@click="setSelectedCoverage(index)"
>
- <div class="gl-display-flex">
- <gl-icon
- v-if="index === selectedCoverageIndex"
- name="mobile-issue-close"
- class="gl-absolute"
- />
- <span class="gl-display-flex align-items-center ml-4">
- {{ group_name }}
- </span>
- </div>
- </gl-deprecated-dropdown-item>
- </gl-deprecated-dropdown>
+ {{ group_name }}
+ </gl-dropdown-item>
+ </gl-dropdown>
</div>
<gl-area-chart
v-if="!isLoading"
diff --git a/app/assets/javascripts/pages/projects/incidents/show/index.js b/app/assets/javascripts/pages/projects/incidents/show/index.js
new file mode 100644
index 00000000000..3324cfc0335
--- /dev/null
+++ b/app/assets/javascripts/pages/projects/incidents/show/index.js
@@ -0,0 +1,11 @@
+import initSidebarBundle from '~/sidebar/sidebar_bundle';
+import initRelatedIssues from '~/related_issues';
+import initShow from '../../issues/show';
+
+document.addEventListener('DOMContentLoaded', () => {
+ initShow();
+ if (!gon.features?.vueIssuableSidebar) {
+ initSidebarBundle();
+ }
+ initRelatedIssues();
+});
diff --git a/app/assets/javascripts/pages/projects/index.js b/app/assets/javascripts/pages/projects/index.js
index 8e0af018b61..3e9962a4e72 100644
--- a/app/assets/javascripts/pages/projects/index.js
+++ b/app/assets/javascripts/pages/projects/index.js
@@ -1,7 +1,5 @@
import Project from './project';
import ShortcutsNavigation from '../../behaviors/shortcuts/shortcuts_navigation';
-document.addEventListener('DOMContentLoaded', () => {
- new Project(); // eslint-disable-line no-new
- new ShortcutsNavigation(); // eslint-disable-line no-new
-});
+new Project(); // eslint-disable-line no-new
+new ShortcutsNavigation(); // eslint-disable-line no-new
diff --git a/app/assets/javascripts/pages/projects/issues/index/index.js b/app/assets/javascripts/pages/projects/issues/index/index.js
index e1add4a2af3..f3ccedc47c8 100644
--- a/app/assets/javascripts/pages/projects/issues/index/index.js
+++ b/app/assets/javascripts/pages/projects/issues/index/index.js
@@ -11,20 +11,18 @@ import initIssuablesList from '~/issues_list';
import initManualOrdering from '~/manual_ordering';
import { showLearnGitLabIssuesPopover } from '~/onboarding_issues';
-document.addEventListener('DOMContentLoaded', () => {
- IssuableFilteredSearchTokenKeys.addExtraTokensForIssues();
+IssuableFilteredSearchTokenKeys.addExtraTokensForIssues();
- initFilteredSearch({
- page: FILTERED_SEARCH.ISSUES,
- filteredSearchTokenKeys: IssuableFilteredSearchTokenKeys,
- useDefaultState: true,
- });
+initFilteredSearch({
+ page: FILTERED_SEARCH.ISSUES,
+ filteredSearchTokenKeys: IssuableFilteredSearchTokenKeys,
+ useDefaultState: true,
+});
- new IssuableIndex(ISSUABLE_INDEX.ISSUE);
- new ShortcutsNavigation();
- new UsersSelect();
+new IssuableIndex(ISSUABLE_INDEX.ISSUE);
+new ShortcutsNavigation();
+new UsersSelect();
- initManualOrdering();
- initIssuablesList();
- showLearnGitLabIssuesPopover();
-});
+initManualOrdering();
+initIssuablesList();
+showLearnGitLabIssuesPopover();
diff --git a/app/assets/javascripts/pages/projects/issues/new/index.js b/app/assets/javascripts/pages/projects/issues/new/index.js
index aecc6484b26..48afd2142ee 100644
--- a/app/assets/javascripts/pages/projects/issues/new/index.js
+++ b/app/assets/javascripts/pages/projects/issues/new/index.js
@@ -1,3 +1,3 @@
import initForm from 'ee_else_ce/pages/projects/issues/form';
-document.addEventListener('DOMContentLoaded', initForm);
+initForm();
diff --git a/app/assets/javascripts/pages/projects/issues/service_desk/index.js b/app/assets/javascripts/pages/projects/issues/service_desk/index.js
index e0c1332796f..231ee6732e9 100644
--- a/app/assets/javascripts/pages/projects/issues/service_desk/index.js
+++ b/app/assets/javascripts/pages/projects/issues/service_desk/index.js
@@ -1,17 +1,15 @@
import FilteredSearchServiceDesk from './filtered_search';
import initIssuablesList from '~/issues_list';
-document.addEventListener('DOMContentLoaded', () => {
- const supportBotData = JSON.parse(
- document.querySelector('.js-service-desk-issues').dataset.supportBot,
- );
+const supportBotData = JSON.parse(
+ document.querySelector('.js-service-desk-issues').dataset.supportBot,
+);
- if (document.querySelector('.filtered-search')) {
- const filteredSearchManager = new FilteredSearchServiceDesk(supportBotData);
- filteredSearchManager.setup();
- }
+if (document.querySelector('.filtered-search')) {
+ const filteredSearchManager = new FilteredSearchServiceDesk(supportBotData);
+ filteredSearchManager.setup();
+}
- if (gon.features?.vueIssuablesList) {
- initIssuablesList();
- }
-});
+if (gon.features?.vueIssuablesList) {
+ initIssuablesList();
+}
diff --git a/app/assets/javascripts/pages/projects/issues/show.js b/app/assets/javascripts/pages/projects/issues/show.js
index 98ae4e26257..a58b5d3f37c 100644
--- a/app/assets/javascripts/pages/projects/issues/show.js
+++ b/app/assets/javascripts/pages/projects/issues/show.js
@@ -10,16 +10,24 @@ import initIncidentApp from '~/issue_show/incident';
import initIssuableHeaderWarning from '~/vue_shared/components/issuable/init_issuable_header_warning';
import initSentryErrorStackTraceApp from '~/sentry_error_stack_trace';
import initRelatedMergeRequestsApp from '~/related_merge_requests';
-import initVueIssuableSidebarApp from '~/issuable_sidebar/sidebar_bundle';
import { parseIssuableData } from '~/issue_show/utils/parse_data';
+import initInviteMemberTrigger from '~/invite_member/init_invite_member_trigger';
+import initInviteMemberModal from '~/invite_member/init_invite_member_modal';
+
+import { IssuableType } from '~/issuable_show/constants';
export default function() {
const { issueType, ...issuableData } = parseIssuableData();
- if (issueType === 'incident') {
- initIncidentApp(issuableData);
- } else {
- initIssueApp(issuableData);
+ switch (issueType) {
+ case IssuableType.Incident:
+ initIncidentApp(issuableData);
+ break;
+ case IssuableType.Issue:
+ initIssueApp(issuableData);
+ break;
+ default:
+ break;
}
initIssuableHeaderWarning(store);
@@ -30,14 +38,14 @@ export default function() {
.then(module => module.default())
.catch(() => {});
- new Issue(); // eslint-disable-line no-new
- new ShortcutsIssuable(); // eslint-disable-line no-new
new ZenMode(); // eslint-disable-line no-new
- if (gon.features && gon.features.vueIssuableSidebar) {
- initVueIssuableSidebarApp();
- } else {
+
+ if (issueType !== IssuableType.TestCase) {
+ new Issue(); // eslint-disable-line no-new
+ new ShortcutsIssuable(); // eslint-disable-line no-new
initIssuableSidebar();
+ loadAwardsHandler();
+ initInviteMemberModal();
+ initInviteMemberTrigger();
}
-
- loadAwardsHandler();
}
diff --git a/app/assets/javascripts/pages/projects/issues/show/index.js b/app/assets/javascripts/pages/projects/issues/show/index.js
index aef4feef42c..630add51a97 100644
--- a/app/assets/javascripts/pages/projects/issues/show/index.js
+++ b/app/assets/javascripts/pages/projects/issues/show/index.js
@@ -2,10 +2,8 @@ import initSidebarBundle from '~/sidebar/sidebar_bundle';
import initRelatedIssues from '~/related_issues';
import initShow from '../show';
-document.addEventListener('DOMContentLoaded', () => {
- initShow();
- if (gon.features && !gon.features.vueIssuableSidebar) {
- initSidebarBundle();
- }
- initRelatedIssues();
-});
+initShow();
+if (gon.features && !gon.features.vueIssuableSidebar) {
+ initSidebarBundle();
+}
+initRelatedIssues();
diff --git a/app/assets/javascripts/pages/projects/merge_requests/index/index.js b/app/assets/javascripts/pages/projects/merge_requests/index/index.js
index ce0b5c80927..94a12cc2706 100644
--- a/app/assets/javascripts/pages/projects/merge_requests/index/index.js
+++ b/app/assets/javascripts/pages/projects/merge_requests/index/index.js
@@ -7,16 +7,15 @@ import IssuableFilteredSearchTokenKeys from '~/filtered_search/issuable_filtered
import { FILTERED_SEARCH } from '~/pages/constants';
import { ISSUABLE_INDEX } from '~/pages/projects/constants';
-document.addEventListener('DOMContentLoaded', () => {
- addExtraTokensForMergeRequests(IssuableFilteredSearchTokenKeys);
+new IssuableIndex(ISSUABLE_INDEX.MERGE_REQUEST); // eslint-disable-line no-new
- initFilteredSearch({
- page: FILTERED_SEARCH.MERGE_REQUESTS,
- filteredSearchTokenKeys: IssuableFilteredSearchTokenKeys,
- useDefaultState: true,
- });
+addExtraTokensForMergeRequests(IssuableFilteredSearchTokenKeys);
- new IssuableIndex(ISSUABLE_INDEX.MERGE_REQUEST); // eslint-disable-line no-new
- new ShortcutsNavigation(); // eslint-disable-line no-new
- new UsersSelect(); // eslint-disable-line no-new
+initFilteredSearch({
+ page: FILTERED_SEARCH.MERGE_REQUESTS,
+ filteredSearchTokenKeys: IssuableFilteredSearchTokenKeys,
+ useDefaultState: true,
});
+
+new UsersSelect(); // eslint-disable-line no-new
+new ShortcutsNavigation(); // eslint-disable-line no-new
diff --git a/app/assets/javascripts/pages/projects/merge_requests/init_merge_request_show.js b/app/assets/javascripts/pages/projects/merge_requests/init_merge_request_show.js
index 11af50169f5..868e001b182 100644
--- a/app/assets/javascripts/pages/projects/merge_requests/init_merge_request_show.js
+++ b/app/assets/javascripts/pages/projects/merge_requests/init_merge_request_show.js
@@ -4,21 +4,20 @@ import ShortcutsIssuable from '~/behaviors/shortcuts/shortcuts_issuable';
import { handleLocationHash } from '~/lib/utils/common_utils';
import howToMerge from '~/how_to_merge';
import initPipelines from '~/commit/pipelines/pipelines_bundle';
-import initVueIssuableSidebarApp from '~/issuable_sidebar/sidebar_bundle';
import initSourcegraph from '~/sourcegraph';
import loadAwardsHandler from '~/awards_handler';
+import initInviteMemberTrigger from '~/invite_member/init_invite_member_trigger';
+import initInviteMemberModal from '~/invite_member/init_invite_member_modal';
export default function() {
new ZenMode(); // eslint-disable-line no-new
- if (gon.features && gon.features.vueIssuableSidebar) {
- initVueIssuableSidebarApp();
- } else {
- initIssuableSidebar();
- }
+ initIssuableSidebar();
initPipelines();
new ShortcutsIssuable(true); // eslint-disable-line no-new
handleLocationHash();
howToMerge();
initSourcegraph();
loadAwardsHandler();
+ initInviteMemberModal();
+ initInviteMemberTrigger();
}
diff --git a/app/assets/javascripts/pages/projects/merge_requests/show/index.js b/app/assets/javascripts/pages/projects/merge_requests/show/index.js
index 29ebf656fe1..602d749ee07 100644
--- a/app/assets/javascripts/pages/projects/merge_requests/show/index.js
+++ b/app/assets/javascripts/pages/projects/merge_requests/show/index.js
@@ -5,12 +5,10 @@ import initShow from '../init_merge_request_show';
import initIssuableHeaderWarning from '~/vue_shared/components/issuable/init_issuable_header_warning';
import store from '~/mr_notes/stores';
-document.addEventListener('DOMContentLoaded', () => {
- initShow();
- if (gon.features && !gon.features.vueIssuableSidebar) {
- initSidebarBundle();
- }
- initMrNotes();
- initReviewBar();
- initIssuableHeaderWarning(store);
-});
+initShow();
+if (gon.features && !gon.features.vueIssuableSidebar) {
+ initSidebarBundle();
+}
+initMrNotes();
+initReviewBar();
+initIssuableHeaderWarning(store);
diff --git a/app/assets/javascripts/pages/projects/new/index.js b/app/assets/javascripts/pages/projects/new/index.js
index 637ed28a758..477a1ab887b 100644
--- a/app/assets/javascripts/pages/projects/new/index.js
+++ b/app/assets/javascripts/pages/projects/new/index.js
@@ -3,13 +3,14 @@ import initProjectNew from '../../../projects/project_new';
import { __ } from '~/locale';
import { deprecatedCreateFlash as createFlash } from '~/flash';
import Tracking from '~/tracking';
+import { isExperimentEnabled } from '~/lib/utils/experimentation';
document.addEventListener('DOMContentLoaded', () => {
initProjectVisibilitySelector();
initProjectNew.bindEvents();
const { category, property } = gon.tracking_data ?? { category: 'projects:new' };
- const hasNewCreateProjectUi = 'newCreateProjectUi' in gon?.features;
+ const hasNewCreateProjectUi = isExperimentEnabled('newCreateProjectUi');
if (!hasNewCreateProjectUi) {
// Setting additional tracking for HAML template
diff --git a/app/assets/javascripts/pages/projects/packages/packages/index/index.js b/app/assets/javascripts/pages/projects/packages/packages/index/index.js
index 4836900aa28..c94782fdf1b 100644
--- a/app/assets/javascripts/pages/projects/packages/packages/index/index.js
+++ b/app/assets/javascripts/pages/projects/packages/packages/index/index.js
@@ -1,7 +1,3 @@
import initPackageList from '~/packages/list/packages_list_app_bundle';
-document.addEventListener('DOMContentLoaded', () => {
- if (document.getElementById('js-vue-packages-list')) {
- initPackageList();
- }
-});
+initPackageList();
diff --git a/app/assets/javascripts/pages/projects/packages/packages/show/index.js b/app/assets/javascripts/pages/projects/packages/packages/show/index.js
index 1fde4ddfc1d..1afb900ed88 100644
--- a/app/assets/javascripts/pages/projects/packages/packages/show/index.js
+++ b/app/assets/javascripts/pages/projects/packages/packages/show/index.js
@@ -1,3 +1,3 @@
import initPackageDetail from '~/packages/details/';
-document.addEventListener('DOMContentLoaded', initPackageDetail);
+initPackageDetail();
diff --git a/app/assets/javascripts/pages/projects/pipeline_schedules/shared/components/pipeline_schedules_callout.vue b/app/assets/javascripts/pages/projects/pipeline_schedules/shared/components/pipeline_schedules_callout.vue
index 7a3923dfefd..a138a3a3425 100644
--- a/app/assets/javascripts/pages/projects/pipeline_schedules/shared/components/pipeline_schedules_callout.vue
+++ b/app/assets/javascripts/pages/projects/pipeline_schedules/shared/components/pipeline_schedules_callout.vue
@@ -1,11 +1,8 @@
<script>
-/* eslint-disable vue/no-v-html */
import Vue from 'vue';
import Cookies from 'js-cookie';
import { GlIcon } from '@gitlab/ui';
import Translate from '../../../../../vue_shared/translate';
-// Full path is needed for Jest to be able to correctly mock this file
-import illustrationSvg from '~/pages/projects/pipeline_schedules/shared/icons/intro_illustration.svg';
import { parseBoolean } from '~/lib/utils/common_utils';
Vue.use(Translate);
@@ -20,12 +17,10 @@ export default {
data() {
return {
docsUrl: document.getElementById('pipeline-schedules-callout').dataset.docsUrl,
+ imageUrl: document.getElementById('pipeline-schedules-callout').dataset.imageUrl,
calloutDismissed: parseBoolean(Cookies.get(cookieKey)),
};
},
- created() {
- this.illustrationSvg = illustrationSvg;
- },
methods: {
dismissCallout() {
this.calloutDismissed = true;
@@ -40,7 +35,9 @@ export default {
<button id="dismiss-callout-btn" class="btn btn-default close" @click="dismissCallout">
<gl-icon name="close" aria-hidden="true" />
</button>
- <div class="svg-container" v-html="illustrationSvg"></div>
+ <div class="svg-container">
+ <img :src="imageUrl" />
+ </div>
<div class="user-callout-copy">
<h4>{{ __('Scheduling Pipelines') }}</h4>
<p>
diff --git a/app/assets/javascripts/pages/projects/pipeline_schedules/shared/icons/intro_illustration.svg b/app/assets/javascripts/pages/projects/pipeline_schedules/shared/icons/intro_illustration.svg
deleted file mode 100644
index 26d1ff97b3e..00000000000
--- a/app/assets/javascripts/pages/projects/pipeline_schedules/shared/icons/intro_illustration.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg width="140" height="102" viewBox="0 0 140 102" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><title>illustration</title><defs><rect id="a" width="12.033" height="40.197" rx="3"/><rect id="b" width="12.033" height="40.197" rx="3"/></defs><g fill="none" fill-rule="evenodd"><g transform="translate(-.446)"><path d="M91.747 35.675v-6.039a2.996 2.996 0 0 0-2.999-3.005H54.635a2.997 2.997 0 0 0-2.999 3.005v6.039H40.092a3.007 3.007 0 0 0-2.996 3.005v34.187a2.995 2.995 0 0 0 2.996 3.005h11.544V79.9a2.996 2.996 0 0 0 2.999 3.005h34.113a2.997 2.997 0 0 0 2.999-3.005v-4.03h11.544a3.007 3.007 0 0 0 2.996-3.004V38.68a2.995 2.995 0 0 0-2.996-3.005H91.747z" stroke="#B5A7DD" stroke-width="2"/><rect stroke="#E5E5E5" stroke-width="2" fill="#FFF" x="21.556" y="38.69" width="98.27" height="34.167" rx="3"/><path d="M121.325 38.19c.55 0 .995.444.995 1.002 0 .554-.453 1.003-.995 1.003h-4.039a1.004 1.004 0 0 1 0-2.006h4.039zm9.044 0c.55 0 .996.444.996 1.002 0 .554-.454 1.003-.996 1.003h-4.038a1.004 1.004 0 0 1 0-2.006h4.038zm9.044 0c.55 0 .996.444.996 1.002 0 .554-.453 1.003-.996 1.003h-4.038a1.004 1.004 0 0 1 0-2.006h4.038zM121.325 71.854a1.004 1.004 0 0 1 0 2.006h-4.039a1.004 1.004 0 0 1 0-2.006h4.039zm9.044 0a1.004 1.004 0 0 1 0 2.006h-4.038a1.004 1.004 0 0 1 0-2.006h4.038zm9.044 0a1.004 1.004 0 0 1 0 2.006h-4.038a1.004 1.004 0 0 1 0-2.006h4.038z" fill="#E5E5E5"/><g transform="translate(110.3 35.675)"><use fill="#FFF" xlink:href="#a"/><rect stroke="#FDE5D8" stroke-width="2" x="1" y="1" width="10.033" height="38.197" rx="3"/><ellipse fill="#FC8A51" cx="6.017" cy="9.547" rx="1.504" ry="1.507"/><ellipse fill="#FC8A51" cx="6.017" cy="20.099" rx="1.504" ry="1.507"/><ellipse fill="#FC8A51" cx="6.017" cy="30.65" rx="1.504" ry="1.507"/></g><path d="M6.008 38.19c.55 0 .996.444.996 1.002 0 .554-.454 1.003-.996 1.003H1.97a1.004 1.004 0 0 1 0-2.006h4.038zm9.044 0c.55 0 .996.444.996 1.002 0 .554-.453 1.003-.996 1.003h-4.038a1.004 1.004 0 0 1 0-2.006h4.038zm9.045 0c.55 0 .995.444.995 1.002 0 .554-.453 1.003-.995 1.003h-4.039a1.004 1.004 0 0 1 0-2.006h4.039zM6.008 71.854a1.004 1.004 0 0 1 0 2.006H1.97a1.004 1.004 0 0 1 0-2.006h4.038zm9.044 0a1.004 1.004 0 0 1 0 2.006h-4.038a1.004 1.004 0 0 1 0-2.006h4.038zm9.045 0a1.004 1.004 0 0 1 0 2.006h-4.039a1.004 1.004 0 0 1 0-2.006h4.039z" fill="#E5E5E5"/><g transform="translate(19.05 35.675)"><use fill="#FFF" xlink:href="#b"/><rect stroke="#FDE5D8" stroke-width="2" x="1" y="1" width="10.033" height="38.197" rx="3"/><ellipse fill="#FC8A51" cx="6.017" cy="10.049" rx="1.504" ry="1.507"/><ellipse fill="#FC8A51" cx="6.017" cy="20.601" rx="1.504" ry="1.507"/><ellipse fill="#FC8A51" cx="6.017" cy="31.153" rx="1.504" ry="1.507"/></g><g transform="translate(47.096)"><g transform="translate(7.05)"><ellipse fill="#FC8A51" cx="17.548" cy="5.025" rx="4.512" ry="4.522"/><rect stroke="#B5A7DD" stroke-width="2" fill="#FFF" x="13.036" y="4.02" width="9.025" height="20.099" rx="1.5"/><rect stroke="#FDE5D8" stroke-width="2" fill="#FFF" y="4.02" width="35.096" height="4.02" rx="2.01"/><rect stroke="#6B4FBB" stroke-width="2" fill="#FFF" x="4.512" y="18.089" width="26.072" height="17.084" rx="1.5"/></g><rect stroke="#6B4FBB" stroke-width="2" fill="#FFF" transform="rotate(-45 43.117 35.117)" x="38.168" y="31.416" width="9.899" height="7.403" rx="3.702"/><ellipse stroke="#6B4FBB" stroke-width="2" fill="#FFF" cx="25" cy="55" rx="25" ry="25"/><ellipse stroke="#6B4FBB" stroke-width="2" fill="#FFF" cx="25" cy="55" rx="21" ry="21"/><rect stroke="#6B4FBB" stroke-width="2" fill="#FFF" x="43.05" y="53.281" width="2.95" height="1.538" rx=".769"/><rect stroke="#6B4FBB" stroke-width="2" fill="#FFF" x="4.305" y="53.281" width="2.95" height="1.538" rx=".769"/><rect stroke="#6B4FBB" stroke-width="2" fill="#FFF" transform="rotate(90 25.153 74.422)" x="23.677" y="73.653" width="2.95" height="1.538" rx=".769"/><rect stroke="#6B4FBB" stroke-width="2" fill="#FFF" transform="rotate(90 25.153 35.51)" x="23.844" y="34.742" width="2.616" height="1.538" rx=".769"/><path d="M13.362 42.502c-.124-.543.198-.854.74-.69l2.321.704c.533.161.643.592.235.972l-.22.206 7.06 7.572a1.002 1.002 0 1 1-1.467 1.368l-7.06-7.573-.118.11c-.402.375-.826.248-.952-.304l-.54-2.365zM21.606 67.576c-.408.38-.84.255-.968-.295l-.551-2.363c-.127-.542.191-.852.725-.69l.288.089 3.027-9.901a1.002 1.002 0 1 1 1.918.586l-3.027 9.901.154.047c.525.16.627.592.213.977l-1.779 1.65z" fill="#FC8A51"/><ellipse stroke="#6B4FBB" stroke-width="2" fill="#FFF" cx="25.099" cy="54.768" rx="2.507" ry="2.512"/></g></g><path d="M52.697 96.966a1.004 1.004 0 0 1 2.006 0v4.038a1.004 1.004 0 0 1-2.006 0v-4.038zm0-9.044a1.004 1.004 0 0 1 2.006 0v4.038a1.004 1.004 0 0 1-2.006 0v-4.038zM86.29 96.966c0-.55.444-.996 1.002-.996.554 0 1.003.454 1.003.996v4.038a1.004 1.004 0 0 1-2.006 0v-4.038zm0-9.044c0-.55.444-.996 1.002-.996.554 0 1.003.453 1.003.996v4.038a1.004 1.004 0 0 1-2.006 0v-4.038z" fill="#E5E5E5"/></g></svg> \ No newline at end of file
diff --git a/app/assets/javascripts/pages/projects/registry/repositories/index.js b/app/assets/javascripts/pages/projects/registry/repositories/index.js
index cdafe838994..6fd32321568 100644
--- a/app/assets/javascripts/pages/projects/registry/repositories/index.js
+++ b/app/assets/javascripts/pages/projects/registry/repositories/index.js
@@ -1,10 +1,8 @@
import registryExplorer from '~/registry/explorer/index';
-document.addEventListener('DOMContentLoaded', () => {
- const explorer = registryExplorer();
+const explorer = registryExplorer();
- if (explorer) {
- explorer.attachBreadcrumb();
- explorer.attachMainComponent();
- }
-});
+if (explorer) {
+ explorer.attachBreadcrumb();
+ explorer.attachMainComponent();
+}
diff --git a/app/assets/javascripts/pages/projects/settings/ci_cd/show/index.js b/app/assets/javascripts/pages/projects/settings/ci_cd/show/index.js
index ab2a7c099c4..40816420eef 100644
--- a/app/assets/javascripts/pages/projects/settings/ci_cd/show/index.js
+++ b/app/assets/javascripts/pages/projects/settings/ci_cd/show/index.js
@@ -4,6 +4,7 @@ import AjaxVariableList from '~/ci_variable_list/ajax_variable_list';
import registrySettingsApp from '~/registry/settings/registry_settings_bundle';
import initVariableList from '~/ci_variable_list';
import initDeployFreeze from '~/deploy_freeze';
+import initSettingsPipelinesTriggers from '~/ci_settings_pipeline_triggers';
document.addEventListener('DOMContentLoaded', () => {
// Initialize expandable settings panels
@@ -42,4 +43,6 @@ document.addEventListener('DOMContentLoaded', () => {
registrySettingsApp();
initDeployFreeze();
+
+ initSettingsPipelinesTriggers();
});
diff --git a/app/assets/javascripts/pages/projects/shared/permissions/components/project_feature_setting.vue b/app/assets/javascripts/pages/projects/shared/permissions/components/project_feature_setting.vue
index 533065b2d4d..0f145dbc170 100644
--- a/app/assets/javascripts/pages/projects/shared/permissions/components/project_feature_setting.vue
+++ b/app/assets/javascripts/pages/projects/shared/permissions/components/project_feature_setting.vue
@@ -1,17 +1,17 @@
<script>
+import { GlIcon } from '@gitlab/ui';
import projectFeatureToggle from '~/vue_shared/components/toggle_button.vue';
import { featureAccessLevelNone } from '../constants';
export default {
components: {
+ GlIcon,
projectFeatureToggle,
},
-
model: {
prop: 'value',
event: 'change',
},
-
props: {
name: {
type: String,
@@ -34,7 +34,6 @@ export default {
default: false,
},
},
-
computed: {
featureEnabled() {
return this.value !== 0;
@@ -51,7 +50,6 @@ export default {
return this.disabledInput || !this.featureEnabled || this.displayOptions.length < 2;
},
},
-
methods: {
toggleFeature(featureEnabled) {
if (featureEnabled === false || this.options.length < 1) {
@@ -70,14 +68,18 @@ export default {
</script>
<template>
- <div :data-for="name" class="project-feature-controls">
+ <div
+ :data-for="name"
+ class="project-feature-controls gl-display-flex gl-align-items-center gl-my-3 gl-mx-0"
+ >
<input v-if="name" :name="name" :value="value" type="hidden" />
<project-feature-toggle
+ class="gl-flex-grow-0 gl-mr-3"
:value="featureEnabled"
:disabled-input="disabledInput"
@change="toggleFeature"
/>
- <div class="select-wrapper">
+ <div class="select-wrapper gl-flex-fill-1">
<select
:disabled="displaySelectInput"
class="form-control project-repo-select select-control"
@@ -92,7 +94,11 @@ export default {
{{ optionName }}
</option>
</select>
- <i aria-hidden="true" class="fa fa-chevron-down"> </i>
+ <gl-icon
+ name="chevron-down"
+ aria-hidden="true"
+ class="gl-absolute gl-top-3 gl-right-3 gl-text-gray-500"
+ />
</div>
</div>
</template>
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 a95f0af46cd..bcf82e264d1 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
@@ -1,5 +1,5 @@
<script>
-import { GlSprintf, GlLink, GlFormCheckbox } from '@gitlab/ui';
+import { GlIcon, GlSprintf, GlLink, GlFormCheckbox } from '@gitlab/ui';
import settingsMixin from 'ee_else_ce/pages/projects/shared/permissions/mixins/settings_pannel_mixin';
import { s__ } from '~/locale';
@@ -22,6 +22,7 @@ export default {
projectFeatureSetting,
projectFeatureToggle,
projectSettingRow,
+ GlIcon,
GlSprintf,
GlLink,
GlFormCheckbox,
@@ -292,14 +293,16 @@ export default {
<template>
<div>
- <div class="project-visibility-setting">
+ <div
+ class="project-visibility-setting gl-border-1 gl-border-solid gl-border-gray-100 gl-py-3 gl-px-7 gl-sm-pr-5 gl-sm-pl-5"
+ >
<project-setting-row
ref="project-visibility-settings"
:help-path="visibilityHelpPath"
:label="s__('ProjectSettings|Project visibility')"
>
- <div class="project-feature-controls">
- <div class="select-wrapper">
+ <div class="project-feature-controls gl-display-flex gl-align-items-center gl-my-3 gl-mx-0">
+ <div class="select-wrapper gl-flex-fill-1">
<select
v-model="visibilityLevel"
:disabled="!canChangeVisibilityLevel"
@@ -323,11 +326,16 @@ export default {
>{{ s__('ProjectSettings|Public') }}</option
>
</select>
- <i aria-hidden="true" data-hidden="true" class="fa fa-chevron-down"></i>
+ <gl-icon
+ name="chevron-down"
+ aria-hidden="true"
+ data-hidden="true"
+ class="gl-absolute gl-top-3 gl-right-3 gl-text-gray-500"
+ />
</div>
</div>
<span class="form-text text-muted">{{ visibilityLevelDescription }}</span>
- <label v-if="visibilityLevel !== visibilityOptions.PRIVATE" class="request-access">
+ <label v-if="visibilityLevel !== visibilityOptions.PRIVATE" class="gl-line-height-28">
<input
:value="requestAccessEnabled"
type="hidden"
@@ -338,7 +346,10 @@ export default {
</label>
</project-setting-row>
</div>
- <div :class="{ 'highlight-changes': highlightChangesClass }" class="project-feature-settings">
+ <div
+ :class="{ 'highlight-changes': highlightChangesClass }"
+ class="gl-border-1 gl-border-solid gl-border-t-none gl-border-gray-100 gl-mb-5 gl-py-3 gl-px-7 gl-sm-pr-5 gl-sm-pl-5 gl-bg-gray-10"
+ >
<project-setting-row
ref="issues-settings"
:label="s__('ProjectSettings|Issues')"
@@ -361,7 +372,7 @@ export default {
name="project[project_feature_attributes][repository_access_level]"
/>
</project-setting-row>
- <div class="project-feature-setting-group">
+ <div class="project-feature-setting-group gl-pl-7 gl-sm-pl-5">
<project-setting-row
ref="merge-request-settings"
:label="s__('ProjectSettings|Merge requests')"
@@ -516,8 +527,8 @@ export default {
)
"
>
- <div class="project-feature-controls">
- <div class="select-wrapper">
+ <div class="project-feature-controls gl-display-flex gl-align-items-center gl-my-3 gl-mx-0">
+ <div class="select-wrapper gl-flex-fill-1">
<select
v-model="metricsDashboardAccessLevel"
:disabled="metricsOptionsDropdownEnabled"
@@ -535,7 +546,12 @@ export default {
>{{ featureAccessLevelEveryone[1] }}</option
>
</select>
- <i aria-hidden="true" data-hidden="true" class="fa fa-chevron-down"></i>
+ <gl-icon
+ name="chevron-down"
+ aria-hidden="true"
+ data-hidden="true"
+ class="gl-absolute gl-top-3 gl-right-3 gl-text-gray-500"
+ />
</div>
</div>
</project-setting-row>
diff --git a/app/assets/javascripts/pages/projects/shared/web_ide_link/index.js b/app/assets/javascripts/pages/projects/shared/web_ide_link/index.js
new file mode 100644
index 00000000000..5f08943d211
--- /dev/null
+++ b/app/assets/javascripts/pages/projects/shared/web_ide_link/index.js
@@ -0,0 +1,31 @@
+import Vue from 'vue';
+import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
+import { joinPaths, webIDEUrl } from '~/lib/utils/url_utility';
+import WebIdeButton from '~/vue_shared/components/web_ide_link.vue';
+
+export default ({ el, router }) => {
+ if (!el) return;
+
+ const { projectPath, ref, isBlob, webIdeUrl, ...options } = convertObjectPropsToCamelCase(
+ JSON.parse(el.dataset.options),
+ );
+
+ // eslint-disable-next-line no-new
+ new Vue({
+ el,
+ router,
+ render(h) {
+ return h(WebIdeButton, {
+ props: {
+ isBlob,
+ webIdeUrl: isBlob
+ ? webIdeUrl
+ : webIDEUrl(
+ joinPaths('/', projectPath, 'edit', ref, '-', this.$route?.params.path || '', '/'),
+ ),
+ ...options,
+ },
+ });
+ },
+ });
+};
diff --git a/app/assets/javascripts/pages/projects/show/index.js b/app/assets/javascripts/pages/projects/show/index.js
index fd522b975a6..dd8141d34c7 100644
--- a/app/assets/javascripts/pages/projects/show/index.js
+++ b/app/assets/javascripts/pages/projects/show/index.js
@@ -11,34 +11,34 @@ import Star from '../../../star';
import notificationsDropdown from '../../../notifications_dropdown';
import { showLearnGitLabProjectPopover } from '~/onboarding_issues';
-document.addEventListener('DOMContentLoaded', () => {
- initReadMore();
- new Star(); // eslint-disable-line no-new
- notificationsDropdown();
- new ShortcutsNavigation(); // eslint-disable-line no-new
- new NotificationsForm(); // eslint-disable-line no-new
- // eslint-disable-next-line no-new
- new UserCallout({
- setCalloutPerProject: false,
- className: 'js-autodevops-banner',
- });
-
- // Project show page loads different overview content based on user preferences
- const treeSlider = document.getElementById('js-tree-list');
- if (treeSlider) {
- initBlob();
- initTree();
- }
-
- if (document.querySelector('.blob-viewer')) {
- new BlobViewer(); // eslint-disable-line no-new
- }
-
- if (document.querySelector('.project-show-activity')) {
- new Activities(); // eslint-disable-line no-new
- }
-
- leaveByUrl('project');
-
- showLearnGitLabProjectPopover();
+initReadMore();
+new Star(); // eslint-disable-line no-new
+
+new NotificationsForm(); // eslint-disable-line no-new
+// eslint-disable-next-line no-new
+new UserCallout({
+ setCalloutPerProject: false,
+ className: 'js-autodevops-banner',
});
+
+// Project show page loads different overview content based on user preferences
+const treeSlider = document.getElementById('js-tree-list');
+if (treeSlider) {
+ initBlob();
+ initTree();
+}
+
+if (document.querySelector('.blob-viewer')) {
+ new BlobViewer(); // eslint-disable-line no-new
+}
+
+if (document.querySelector('.project-show-activity')) {
+ new Activities(); // eslint-disable-line no-new
+}
+
+leaveByUrl('project');
+
+showLearnGitLabProjectPopover();
+
+notificationsDropdown();
+new ShortcutsNavigation(); // eslint-disable-line no-new
diff --git a/app/assets/javascripts/pages/projects/tags/index/index.js b/app/assets/javascripts/pages/projects/tags/index/index.js
new file mode 100644
index 00000000000..ec56fa3e075
--- /dev/null
+++ b/app/assets/javascripts/pages/projects/tags/index/index.js
@@ -0,0 +1,12 @@
+import { initRemoveTag } from '../remove_tag';
+
+document.addEventListener('DOMContentLoaded', () => {
+ initRemoveTag({
+ onDelete: path => {
+ document
+ .querySelector(`[data-path="${path}"]`)
+ .closest('.js-tag-list')
+ .remove();
+ },
+ });
+});
diff --git a/app/assets/javascripts/pages/projects/tags/remove_tag.js b/app/assets/javascripts/pages/projects/tags/remove_tag.js
new file mode 100644
index 00000000000..7e83dbe0565
--- /dev/null
+++ b/app/assets/javascripts/pages/projects/tags/remove_tag.js
@@ -0,0 +1,16 @@
+import createFlash from '~/flash';
+import axios from '~/lib/utils/axios_utils';
+import initConfirmModal from '~/confirm_modal';
+
+export const initRemoveTag = ({ onDelete = () => {} }) => {
+ return initConfirmModal({
+ handleSubmit: (path = '') =>
+ axios
+ .delete(path)
+ .then(() => onDelete(path))
+ .catch(({ response: { data } }) => {
+ const { message } = data;
+ createFlash({ message });
+ }),
+ });
+};
diff --git a/app/assets/javascripts/pages/projects/tags/show/index.js b/app/assets/javascripts/pages/projects/tags/show/index.js
new file mode 100644
index 00000000000..651cc05ca4f
--- /dev/null
+++ b/app/assets/javascripts/pages/projects/tags/show/index.js
@@ -0,0 +1,10 @@
+import { redirectTo, getBaseURL, stripFinalUrlSegment } from '~/lib/utils/url_utility';
+import { initRemoveTag } from '../remove_tag';
+
+document.addEventListener('DOMContentLoaded', () => {
+ initRemoveTag({
+ onDelete: (path = '') => {
+ redirectTo(stripFinalUrlSegment([getBaseURL(), path].join('')));
+ },
+ });
+});
diff --git a/app/assets/javascripts/pages/projects/tree/show/index.js b/app/assets/javascripts/pages/projects/tree/show/index.js
index b19abda2821..4bb461aadad 100644
--- a/app/assets/javascripts/pages/projects/tree/show/index.js
+++ b/app/assets/javascripts/pages/projects/tree/show/index.js
@@ -4,9 +4,7 @@ import initBlob from '~/blob_edit/blob_bundle';
import ShortcutsNavigation from '../../../../behaviors/shortcuts/shortcuts_navigation';
import NewCommitForm from '../../../../new_commit_form';
-document.addEventListener('DOMContentLoaded', () => {
- new ShortcutsNavigation(); // eslint-disable-line no-new
- new NewCommitForm($('.js-create-dir-form')); // eslint-disable-line no-new
- initBlob();
- initTree();
-});
+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/search/show/index.js b/app/assets/javascripts/pages/search/show/index.js
index 92d01343bd5..721219874cf 100644
--- a/app/assets/javascripts/pages/search/show/index.js
+++ b/app/assets/javascripts/pages/search/show/index.js
@@ -1,7 +1,7 @@
import Search from './search';
-import initStateFilter from '~/search/state_filter';
+import initSearchApp from '~/search';
document.addEventListener('DOMContentLoaded', () => {
- initStateFilter();
+ initSearchApp();
return new Search();
});
diff --git a/app/assets/javascripts/pages/search/show/search.js b/app/assets/javascripts/pages/search/show/search.js
index 6ff74325a5e..2cd333f26e1 100644
--- a/app/assets/javascripts/pages/search/show/search.js
+++ b/app/assets/javascripts/pages/search/show/search.js
@@ -4,6 +4,7 @@ import { deprecatedCreateFlash as Flash } from '~/flash';
import Api from '~/api';
import { __ } from '~/locale';
import Project from '~/pages/projects/project';
+import { visitUrl } from '~/lib/utils/url_utility';
import refreshCounts from './refresh_counts';
import setHighlightClass from './highlight_blob_search_result';
@@ -86,6 +87,10 @@ export default class Search {
$(document)
.off('click', this.searchClear)
.on('click', this.searchClear, this.clearSearchField.bind(this));
+
+ $('a.js-search-clear')
+ .off('click', this.clearSearchFilter)
+ .on('click', this.clearSearchFilter);
}
static submitSearch() {
@@ -108,6 +113,17 @@ export default class Search {
.focus();
}
+ // We need to manually follow the link on the anchors
+ // that have this event bound, as their `click` default
+ // behavior is prevented by the toggle logic.
+ /* eslint-disable-next-line class-methods-use-this */
+ clearSearchFilter(ev) {
+ const $target = $(ev.currentTarget);
+
+ visitUrl($target.href);
+ ev.stopPropagation();
+ }
+
getProjectsData(term) {
return new Promise(resolve => {
if (this.groupId) {
diff --git a/app/assets/javascripts/pages/shared/wikis/wikis.js b/app/assets/javascripts/pages/shared/wikis/wikis.js
index 41d43812b5d..ab948fd106f 100644
--- a/app/assets/javascripts/pages/shared/wikis/wikis.js
+++ b/app/assets/javascripts/pages/shared/wikis/wikis.js
@@ -10,7 +10,7 @@ const MARKDOWN_LINK_TEXT = {
};
const TRACKING_EVENT_NAME = 'view_wiki_page';
-const TRACKING_CONTEXT_SCHEMA = 'iglu:com.gitlab/wiki_page_context/jsonschema/1-0-0';
+const TRACKING_CONTEXT_SCHEMA = 'iglu:com.gitlab/wiki_page_context/jsonschema/1-0-1';
export default class Wikis {
constructor() {
diff --git a/app/assets/javascripts/performance_bar/components/performance_bar_app.vue b/app/assets/javascripts/performance_bar/components/performance_bar_app.vue
index 165feb1b6aa..e38771785b7 100644
--- a/app/assets/javascripts/performance_bar/components/performance_bar_app.vue
+++ b/app/assets/javascripts/performance_bar/components/performance_bar_app.vue
@@ -36,7 +36,7 @@ export default {
metric: 'active-record',
title: 'pg',
header: s__('PerformanceBar|SQL queries'),
- keys: ['sql'],
+ keys: ['sql', 'cached'],
},
{
metric: 'bullet',
diff --git a/app/assets/javascripts/performance_bar/performance_bar_log.js b/app/assets/javascripts/performance_bar/performance_bar_log.js
index 638c544f2e1..55b4d626e56 100644
--- a/app/assets/javascripts/performance_bar/performance_bar_log.js
+++ b/app/assets/javascripts/performance_bar/performance_bar_log.js
@@ -1,5 +1,6 @@
/* eslint-disable no-console */
import { getCLS, getFID, getLCP } from 'web-vitals';
+import { PERFORMANCE_TYPE_MARK, PERFORMANCE_TYPE_MEASURE } from '~/performance_constants';
const initVitalsLog = () => {
const reportVital = data => {
@@ -16,6 +17,29 @@ const initVitalsLog = () => {
getLCP(reportVital);
};
+const logUserTimingMetrics = () => {
+ const metricsProcessor = list => {
+ const entries = list.getEntries();
+ entries.forEach(entry => {
+ const { name, entryType, startTime, duration } = entry;
+ const typeMapper = {
+ [PERFORMANCE_TYPE_MARK]: String.fromCodePoint(0x1f3af),
+ [PERFORMANCE_TYPE_MEASURE]: String.fromCodePoint(0x1f4d0),
+ };
+ console.group(`${typeMapper[entryType]} ${name}`);
+ if (entryType === PERFORMANCE_TYPE_MARK) {
+ console.log(`Start time: ${startTime}`);
+ } else if (entryType === PERFORMANCE_TYPE_MEASURE) {
+ console.log(`Duration: ${duration}`);
+ }
+ console.log(entry);
+ console.groupEnd();
+ });
+ };
+ const observer = new PerformanceObserver(metricsProcessor);
+ observer.observe({ entryTypes: [PERFORMANCE_TYPE_MEASURE, PERFORMANCE_TYPE_MARK] });
+};
+
const initPerformanceBarLog = () => {
console.log(
`%c ${String.fromCodePoint(0x1f98a)} GitLab performance bar`,
@@ -23,6 +47,7 @@ const initPerformanceBarLog = () => {
);
initVitalsLog();
+ logUserTimingMetrics();
};
export default initPerformanceBarLog;
diff --git a/app/assets/javascripts/performance_constants.js b/app/assets/javascripts/performance_constants.js
index 1a53b925aa4..6b6b6f1da40 100644
--- a/app/assets/javascripts/performance_constants.js
+++ b/app/assets/javascripts/performance_constants.js
@@ -1,12 +1,31 @@
+export const PERFORMANCE_TYPE_MARK = 'mark';
+export const PERFORMANCE_TYPE_MEASURE = 'measure';
+
//
// SNIPPET namespace
//
-// marks
+// Marks
export const SNIPPET_MARK_VIEW_APP_START = 'snippet-view-app-start';
export const SNIPPET_MARK_EDIT_APP_START = 'snippet-edit-app-start';
export const SNIPPET_MARK_BLOBS_CONTENT = 'snippet-blobs-content-finished';
// Measures
export const SNIPPET_MEASURE_BLOBS_CONTENT = 'snippet-blobs-content';
-export const SNIPPET_MEASURE_BLOBS_CONTENT_WITHIN_APP = 'snippet-blobs-content-within-app';
+
+//
+// WebIDE namespace
+//
+
+// Marks
+export const WEBIDE_MARK_APP_START = 'webide-app-start';
+export const WEBIDE_MARK_TREE_START = 'webide-tree-start';
+export const WEBIDE_MARK_TREE_FINISH = 'webide-tree-finished';
+export const WEBIDE_MARK_FILE_START = 'webide-file-start';
+export const WEBIDE_MARK_FILE_CLICKED = 'webide-file-clicked';
+export const WEBIDE_MARK_FILE_FINISH = 'webide-file-finished';
+
+// Measures
+export const WEBIDE_MEASURE_TREE_FROM_REQUEST = 'webide-tree-loading-from-request';
+export const WEBIDE_MEASURE_FILE_FROM_REQUEST = 'webide-file-loading-from-request';
+export const WEBIDE_MEASURE_FILE_AFTER_INTERACTION = 'webide-file-loading-after-interaction';
diff --git a/app/assets/javascripts/performance_utils.js b/app/assets/javascripts/performance_utils.js
new file mode 100644
index 00000000000..1c87ee2086e
--- /dev/null
+++ b/app/assets/javascripts/performance_utils.js
@@ -0,0 +1,10 @@
+export const performanceMarkAndMeasure = ({ mark, measures = [] } = {}) => {
+ window.requestAnimationFrame(() => {
+ if (mark && !performance.getEntriesByName(mark).length) {
+ performance.mark(mark);
+ }
+ measures.forEach(measure => {
+ performance.measure(measure.name, measure.start, measure.end);
+ });
+ });
+};
diff --git a/app/assets/javascripts/pipeline_new/components/pipeline_new_form.vue b/app/assets/javascripts/pipeline_new/components/pipeline_new_form.vue
index be8ce832d20..20067f6646f 100644
--- a/app/assets/javascripts/pipeline_new/components/pipeline_new_form.vue
+++ b/app/assets/javascripts/pipeline_new/components/pipeline_new_form.vue
@@ -3,6 +3,7 @@ import Vue from 'vue';
import { uniqueId } from 'lodash';
import {
GlAlert,
+ GlIcon,
GlButton,
GlForm,
GlFormGroup,
@@ -27,12 +28,13 @@ export default {
variablesDescription: s__(
'Pipeline|Specify variable values to be used in this run. The values specified in %{linkStart}CI/CD settings%{linkEnd} will be used by default.',
),
- formElementClasses: 'gl-mr-3 gl-mb-3 table-section section-15',
+ formElementClasses: 'gl-mr-3 gl-mb-3 gl-flex-basis-quarter gl-flex-shrink-0 gl-flex-grow-0',
errorTitle: __('The form contains the following error:'),
warningTitle: __('The form contains the following warning:'),
maxWarningsSummary: __('%{total} warnings found: showing first %{warningsDisplayed}'),
components: {
GlAlert,
+ GlIcon,
GlButton,
GlForm,
GlFormGroup,
@@ -49,6 +51,10 @@ export default {
type: String,
required: true,
},
+ configVariablesPath: {
+ type: String,
+ required: true,
+ },
projectId: {
type: String,
required: true,
@@ -85,7 +91,7 @@ export default {
return {
searchTerm: '',
refValue: this.refParam,
- variables: {},
+ form: {},
error: null,
warnings: [],
totalWarnings: 0,
@@ -97,9 +103,6 @@ export default {
const lowerCasedSearchTerm = this.searchTerm.toLowerCase();
return this.refs.filter(ref => ref.toLowerCase().includes(lowerCasedSearchTerm));
},
- variablesLength() {
- return Object.keys(this.variables).length;
- },
overMaxWarningsLimit() {
return this.totalWarnings > this.maxWarnings;
},
@@ -112,64 +115,135 @@ export default {
shouldShowWarning() {
return this.warnings.length > 0 && !this.isWarningDismissed;
},
+ variables() {
+ return this.form[this.refValue]?.variables ?? [];
+ },
+ descriptions() {
+ return this.form[this.refValue]?.descriptions ?? {};
+ },
},
created() {
- if (this.variableParams) {
- this.setVariableParams(VARIABLE_TYPE, this.variableParams);
- }
-
- if (this.fileParams) {
- this.setVariableParams(FILE_TYPE, this.fileParams);
- }
-
- this.addEmptyVariable();
+ this.setRefSelected(this.refValue);
},
methods: {
- addEmptyVariable() {
- this.variables[uniqueId('var')] = {
+ addEmptyVariable(refValue) {
+ const { variables } = this.form[refValue];
+
+ const lastVar = variables[variables.length - 1];
+ if (lastVar?.key === '' && lastVar?.value === '') {
+ return;
+ }
+
+ variables.push({
+ uniqueId: uniqueId(`var-${refValue}`),
variable_type: VARIABLE_TYPE,
key: '',
value: '',
- };
+ });
},
- setVariableParams(type, paramsObj) {
- Object.entries(paramsObj).forEach(([key, value]) => {
- this.variables[uniqueId('var')] = {
+ setVariable(refValue, type, key, value) {
+ const { variables } = this.form[refValue];
+
+ const variable = variables.find(v => v.key === key);
+ if (variable) {
+ variable.type = type;
+ variable.value = value;
+ } else {
+ variables.push({
+ uniqueId: uniqueId(`var-${refValue}`),
key,
value,
variable_type: type,
- };
+ });
+ }
+ },
+ setVariableParams(refValue, type, paramsObj) {
+ Object.entries(paramsObj).forEach(([key, value]) => {
+ this.setVariable(refValue, type, key, value);
});
},
- setRefSelected(ref) {
- this.refValue = ref;
+ setRefSelected(refValue) {
+ this.refValue = refValue;
+
+ if (!this.form[refValue]) {
+ this.fetchConfigVariables(refValue)
+ .then(({ descriptions, params }) => {
+ Vue.set(this.form, refValue, {
+ variables: [],
+ descriptions,
+ });
+
+ // Add default variables from yml
+ this.setVariableParams(refValue, VARIABLE_TYPE, params);
+ })
+ .catch(() => {
+ Vue.set(this.form, refValue, {
+ variables: [],
+ descriptions: {},
+ });
+ })
+ .finally(() => {
+ // Add/update variables, e.g. from query string
+ if (this.variableParams) {
+ this.setVariableParams(refValue, VARIABLE_TYPE, this.variableParams);
+ }
+ if (this.fileParams) {
+ this.setVariableParams(refValue, FILE_TYPE, this.fileParams);
+ }
+
+ // Adds empty var at the end of the form
+ this.addEmptyVariable(refValue);
+ });
+ }
},
+
isSelected(ref) {
return ref === this.refValue;
},
- insertNewVariable() {
- Vue.set(this.variables, uniqueId('var'), {
- variable_type: VARIABLE_TYPE,
- key: '',
- value: '',
- });
+ removeVariable(index) {
+ this.variables.splice(index, 1);
},
- removeVariable(key) {
- Vue.delete(this.variables, key);
+ canRemove(index) {
+ return index < this.variables.length - 1;
},
- canRemove(index) {
- return index < this.variablesLength - 1;
+ fetchConfigVariables(refValue) {
+ if (gon?.features?.newPipelineFormPrefilledVars) {
+ return axios
+ .get(this.configVariablesPath, {
+ params: {
+ sha: refValue,
+ },
+ })
+ .then(({ data }) => {
+ const params = {};
+ const descriptions = {};
+
+ Object.entries(data).forEach(([key, { value, description }]) => {
+ if (description !== null) {
+ params[key] = value;
+ descriptions[key] = description;
+ }
+ });
+
+ return { params, descriptions };
+ });
+ }
+ return Promise.resolve({ params: {}, descriptions: {} });
},
createPipeline() {
- const filteredVariables = Object.values(this.variables).filter(
- ({ key, value }) => key !== '' && value !== '',
- );
+ const filteredVariables = this.variables
+ .filter(({ key, value }) => key !== '' && value !== '')
+ .map(({ variable_type, key, value }) => ({
+ variable_type,
+ key,
+ secret_value: value,
+ }));
return axios
.post(this.pipelinesPath, {
ref: this.refValue,
- variables: filteredVariables,
+ variables_attributes: filteredVariables,
})
.then(({ data }) => {
redirectTo(`${this.pipelinesPath}/${data.id}`);
@@ -230,7 +304,6 @@ export default {
<gl-search-box-by-type
v-model.trim="searchTerm"
:placeholder="__('Search branches and tags')"
- class="gl-p-2"
/>
<gl-dropdown-item
v-for="(ref, index) in filteredRefs"
@@ -253,35 +326,55 @@ export default {
<gl-form-group :label="s__('Pipeline|Variables')">
<div
- v-for="(value, key, index) in variables"
- :key="key"
- class="gl-display-flex gl-align-items-center gl-mb-4 gl-pb-2 gl-border-b-solid gl-border-gray-200 gl-border-b-1 gl-flex-direction-column gl-md-flex-direction-row"
+ v-for="(variable, index) in variables"
+ :key="variable.uniqueId"
+ class="gl-mb-3 gl-ml-n3 gl-pb-2"
data-testid="ci-variable-row"
>
- <gl-form-select
- v-model="variables[key].variable_type"
- :class="$options.formElementClasses"
- :options="$options.typeOptions"
- />
- <gl-form-input
- v-model="variables[key].key"
- :placeholder="s__('CiVariables|Input variable key')"
- :class="$options.formElementClasses"
- data-testid="pipeline-form-ci-variable-key"
- @change.once="insertNewVariable()"
- />
- <gl-form-input
- v-model="variables[key].value"
- :placeholder="s__('CiVariables|Input variable value')"
- class="gl-mr-5 gl-mb-3 table-section section-15"
- />
- <gl-button
- v-if="canRemove(index)"
- icon="issue-close"
- class="gl-mb-3"
- data-testid="remove-ci-variable-row"
- @click="removeVariable(key)"
- />
+ <div
+ class="gl-display-flex gl-align-items-stretch gl-flex-direction-column gl-md-flex-direction-row"
+ >
+ <gl-form-select
+ v-model="variable.variable_type"
+ :class="$options.formElementClasses"
+ :options="$options.typeOptions"
+ />
+ <gl-form-input
+ v-model="variable.key"
+ :placeholder="s__('CiVariables|Input variable key')"
+ :class="$options.formElementClasses"
+ data-testid="pipeline-form-ci-variable-key"
+ @change="addEmptyVariable(refValue)"
+ />
+ <gl-form-input
+ v-model="variable.value"
+ :placeholder="s__('CiVariables|Input variable value')"
+ class="gl-mb-3"
+ data-testid="pipeline-form-ci-variable-value"
+ />
+
+ <template v-if="variables.length > 1">
+ <gl-button
+ v-if="canRemove(index)"
+ class="gl-md-ml-3 gl-mb-3"
+ data-testid="remove-ci-variable-row"
+ variant="danger"
+ category="secondary"
+ @click="removeVariable(index)"
+ >
+ <gl-icon class="gl-mr-0! gl-display-none gl-display-md-block" name="clear" />
+ <span class="gl-display-md-none">{{ s__('CiVariables|Remove variable') }}</span>
+ </gl-button>
+ <gl-button
+ v-else
+ class="gl-md-ml-3 gl-mb-3 gl-display-none gl-display-md-block gl-visibility-hidden"
+ icon="clear"
+ />
+ </template>
+ </div>
+ <div v-if="descriptions[variable.key]" class="gl-text-gray-500 gl-mb-3">
+ {{ descriptions[variable.key] }}
+ </div>
</div>
<template #description
@@ -295,9 +388,14 @@ export default {
<div
class="gl-border-t-solid gl-border-gray-100 gl-border-t-1 gl-p-5 gl-bg-gray-10 gl-display-flex gl-justify-content-space-between"
>
- <gl-button type="submit" category="primary" variant="success">{{
- s__('Pipeline|Run Pipeline')
- }}</gl-button>
+ <gl-button
+ type="submit"
+ category="primary"
+ variant="success"
+ class="js-no-auto-disable"
+ data-qa-selector="run_pipeline_button"
+ >{{ s__('Pipeline|Run Pipeline') }}</gl-button
+ >
<gl-button :href="pipelinesPath">{{ __('Cancel') }}</gl-button>
</div>
</gl-form>
diff --git a/app/assets/javascripts/pipeline_new/index.js b/app/assets/javascripts/pipeline_new/index.js
index f1ea86f8c5f..ff4f677654e 100644
--- a/app/assets/javascripts/pipeline_new/index.js
+++ b/app/assets/javascripts/pipeline_new/index.js
@@ -6,6 +6,7 @@ export default () => {
const {
projectId,
pipelinesPath,
+ configVariablesPath,
refParam,
varParam,
fileParam,
@@ -25,6 +26,7 @@ export default () => {
props: {
projectId,
pipelinesPath,
+ configVariablesPath,
refParam,
variableParams,
fileParams,
diff --git a/app/assets/javascripts/pipelines/components/dag/constants.js b/app/assets/javascripts/pipelines/components/dag/constants.js
index b6a98fdc488..cd89055737f 100644
--- a/app/assets/javascripts/pipelines/components/dag/constants.js
+++ b/app/assets/javascripts/pipelines/components/dag/constants.js
@@ -1,9 +1,3 @@
-/* Error constants */
-export const PARSE_FAILURE = 'parse_failure';
-export const LOAD_FAILURE = 'load_failure';
-export const UNSUPPORTED_DATA = 'unsupported_data';
-export const DEFAULT = 'default';
-
/* Interaction handles */
export const IS_HIGHLIGHTED = 'dag-highlighted';
export const LINK_SELECTOR = 'dag-link';
diff --git a/app/assets/javascripts/pipelines/components/dag/dag.vue b/app/assets/javascripts/pipelines/components/dag/dag.vue
index 8487da3d621..6267b63328c 100644
--- a/app/assets/javascripts/pipelines/components/dag/dag.vue
+++ b/app/assets/javascripts/pipelines/components/dag/dag.vue
@@ -6,16 +6,9 @@ import { fetchPolicies } from '~/lib/graphql';
import getDagVisData from '../../graphql/queries/get_dag_vis_data.query.graphql';
import DagGraph from './dag_graph.vue';
import DagAnnotations from './dag_annotations.vue';
-import {
- DEFAULT,
- PARSE_FAILURE,
- LOAD_FAILURE,
- UNSUPPORTED_DATA,
- ADD_NOTE,
- REMOVE_NOTE,
- REPLACE_NOTES,
-} from './constants';
-import { parseData } from './parsing_utils';
+import { ADD_NOTE, REMOVE_NOTE, REPLACE_NOTES } from './constants';
+import { parseData } from '../parsing_utils';
+import { DEFAULT, PARSE_FAILURE, LOAD_FAILURE, UNSUPPORTED_DATA } from '../../constants';
export default {
// eslint-disable-next-line @gitlab/require-i18n-strings
diff --git a/app/assets/javascripts/pipelines/components/dag/dag_graph.vue b/app/assets/javascripts/pipelines/components/dag/dag_graph.vue
index d12baa9617e..42d1debcddf 100644
--- a/app/assets/javascripts/pipelines/components/dag/dag_graph.vue
+++ b/app/assets/javascripts/pipelines/components/dag/dag_graph.vue
@@ -1,14 +1,7 @@
<script>
import * as d3 from 'd3';
import { uniqueId } from 'lodash';
-import {
- LINK_SELECTOR,
- NODE_SELECTOR,
- PARSE_FAILURE,
- ADD_NOTE,
- REMOVE_NOTE,
- REPLACE_NOTES,
-} from './constants';
+import { LINK_SELECTOR, NODE_SELECTOR, ADD_NOTE, REMOVE_NOTE, REPLACE_NOTES } from './constants';
import {
currentIsLive,
getLiveLinksAsDict,
@@ -17,8 +10,9 @@ import {
toggleLinkHighlight,
togglePathHighlights,
} from './interactions';
-import { getMaxNodes, removeOrphanNodes } from './parsing_utils';
+import { getMaxNodes, removeOrphanNodes } from '../parsing_utils';
import { calculateClip, createLinkPath, createSankey, labelPosition } from './drawing_utils';
+import { PARSE_FAILURE } from '../../constants';
export default {
viewOptions: {
diff --git a/app/assets/javascripts/pipelines/components/graph/action_component.vue b/app/assets/javascripts/pipelines/components/graph/action_component.vue
index efa11580c41..a580ee11627 100644
--- a/app/assets/javascripts/pipelines/components/graph/action_component.vue
+++ b/app/assets/javascripts/pipelines/components/graph/action_component.vue
@@ -88,7 +88,7 @@ export default {
:class="cssClass"
:disabled="isDisabled"
class="js-ci-action ci-action-icon-container ci-action-icon-wrapper gl-display-flex gl-align-items-center gl-justify-content-center"
- @click="onClickAction"
+ @click.stop="onClickAction"
>
<gl-loading-icon v-if="isLoading" class="js-action-icon-loading" />
<gl-icon v-else :name="actionIcon" class="gl-mr-0!" />
diff --git a/app/assets/javascripts/pipelines/components/graph/graph_component.vue b/app/assets/javascripts/pipelines/components/graph/graph_component.vue
index 924cdeebba1..0f5a8cb8fbf 100644
--- a/app/assets/javascripts/pipelines/components/graph/graph_component.vue
+++ b/app/assets/javascripts/pipelines/components/graph/graph_component.vue
@@ -1,7 +1,7 @@
<script>
+import { escape, capitalize } from 'lodash';
import { GlLoadingIcon } from '@gitlab/ui';
import StageColumnComponent from './stage_column_component.vue';
-import GraphMixin from '../../mixins/graph_component_mixin';
import GraphWidthMixin from '../../mixins/graph_width_mixin';
import LinkedPipelinesColumn from './linked_pipelines_column.vue';
import GraphBundleMixin from '../../mixins/graph_pipeline_bundle_mixin';
@@ -13,7 +13,7 @@ export default {
GlLoadingIcon,
LinkedPipelinesColumn,
},
- mixins: [GraphMixin, GraphWidthMixin, GraphBundleMixin],
+ mixins: [GraphWidthMixin, GraphBundleMixin],
props: {
isLoading: {
type: Boolean,
@@ -51,6 +51,9 @@ export default {
};
},
computed: {
+ graph() {
+ return this.pipeline.details?.stages;
+ },
hasTriggeredBy() {
return (
this.type !== this.$options.downstream &&
@@ -92,6 +95,39 @@ export default {
},
},
methods: {
+ capitalizeStageName(name) {
+ const escapedName = escape(name);
+ return capitalize(escapedName);
+ },
+ isFirstColumn(index) {
+ return index === 0;
+ },
+ stageConnectorClass(index, stage) {
+ let className;
+
+ // If it's the first stage column and only has one job
+ if (this.isFirstColumn(index) && stage.groups.length === 1) {
+ className = 'no-margin';
+ } else if (index > 0) {
+ // If it is not the first column
+ className = 'left-margin';
+ }
+
+ return className;
+ },
+ refreshPipelineGraph() {
+ this.$emit('refreshPipelineGraph');
+ },
+ /**
+ * CSS class is applied:
+ * - if pipeline graph contains only one stage column component
+ *
+ * @param {number} index
+ * @returns {boolean}
+ */
+ shouldAddRightMargin(index) {
+ return !(index === this.graph.length - 1);
+ },
handleClickedDownstream(pipeline, clickedIndex, downstreamNode) {
/**
* Calculates the margin top of the clicked downstream pipeline by
diff --git a/app/assets/javascripts/pipelines/components/graph/job_group_dropdown.vue b/app/assets/javascripts/pipelines/components/graph/job_group_dropdown.vue
index 11fb2b18e9d..49591a80752 100644
--- a/app/assets/javascripts/pipelines/components/graph/job_group_dropdown.vue
+++ b/app/assets/javascripts/pipelines/components/graph/job_group_dropdown.vue
@@ -1,5 +1,4 @@
<script>
-import $ from 'jquery';
import { GlTooltipDirective } from '@gitlab/ui';
import CiIcon from '~/vue_shared/components/ci_icon.vue';
import JobItem from './job_item.vue';
@@ -30,27 +29,7 @@ export default {
return `${name} - ${status.label}`;
},
},
- mounted() {
- this.stopDropdownClickPropagation();
- },
methods: {
- /**
- * When the user right clicks or cmd/ctrl + click in the group name or the action icon
- * the dropdown should not be closed so we stop propagation
- * of the click event inside the dropdown.
- *
- * Since this component is rendered multiple times per page we need to guarantee we only
- * target the click event of this component.
- */
- stopDropdownClickPropagation() {
- $(
- '.js-grouped-pipeline-dropdown button, .js-grouped-pipeline-dropdown a.mini-pipeline-graph-dropdown-item',
- this.$el,
- ).on('click', e => {
- e.stopPropagation();
- });
- },
-
pipelineActionRequestComplete() {
this.$emit('pipelineActionRequestComplete');
},
@@ -69,7 +48,9 @@ export default {
>
<ci-icon :status="group.status" />
- <span class="ci-status-text text-truncate mw-70p gl-pl-2 d-inline-block align-bottom">
+ <span
+ class="gl-text-truncate mw-70p gl-pl-2 gl-display-inline-block gl-vertical-align-bottom"
+ >
{{ group.name }}
</span>
diff --git a/app/assets/javascripts/pipelines/components/graph/job_item.vue b/app/assets/javascripts/pipelines/components/graph/job_item.vue
index 0fe0b671273..7aee2573ce1 100644
--- a/app/assets/javascripts/pipelines/components/graph/job_item.vue
+++ b/app/assets/javascripts/pipelines/components/graph/job_item.vue
@@ -126,7 +126,7 @@ export default {
};
</script>
<template>
- <div class="ci-job-component">
+ <div class="ci-job-component" data-qa-selector="job_item_container">
<gl-link
v-if="status.has_details"
v-gl-tooltip="{ boundary, placement: 'bottom' }"
@@ -135,6 +135,7 @@ export default {
:class="jobClasses"
class="js-pipeline-graph-job-link qa-job-link menu-item"
data-testid="job-with-link"
+ @click.stop
>
<job-name-component :name="job.name" :status="job.status" />
</gl-link>
@@ -155,6 +156,7 @@ export default {
:tooltip-text="status.action.title"
:link="status.action.path"
:action-icon="status.action.icon"
+ data-qa-selector="action_button"
@pipelineActionRequestComplete="pipelineActionRequestComplete"
/>
</div>
diff --git a/app/assets/javascripts/pipelines/components/graph/job_name_component.vue b/app/assets/javascripts/pipelines/components/graph/job_name_component.vue
index 30ba243077e..1b71949784a 100644
--- a/app/assets/javascripts/pipelines/components/graph/job_name_component.vue
+++ b/app/assets/javascripts/pipelines/components/graph/job_name_component.vue
@@ -27,7 +27,7 @@ export default {
<template>
<span class="ci-job-name-component mw-100">
<ci-icon :status="status" />
- <span class="ci-status-text text-truncate mw-70p gl-pl-2 d-inline-block align-bottom">
+ <span class="gl-text-truncate mw-70p gl-pl-2 gl-display-inline-block gl-vertical-align-bottom">
{{ name }}
</span>
</span>
diff --git a/app/assets/javascripts/pipelines/components/graph/stage_column_component.vue b/app/assets/javascripts/pipelines/components/graph/stage_column_component.vue
index 1453c349f44..a75ec585b95 100644
--- a/app/assets/javascripts/pipelines/components/graph/stage_column_component.vue
+++ b/app/assets/javascripts/pipelines/components/graph/stage_column_component.vue
@@ -71,7 +71,7 @@ export default {
:action-icon="action.icon"
:tooltip-text="action.title"
:link="action.path"
- class="js-stage-action stage-action position-absolute position-top-0 rounded"
+ class="js-stage-action stage-action rounded"
@pipelineActionRequestComplete="pipelineActionRequestComplete"
/>
</div>
diff --git a/app/assets/javascripts/pipelines/components/header_component.vue b/app/assets/javascripts/pipelines/components/header_component.vue
index c7b72be36ad..b26f28fa6af 100644
--- a/app/assets/javascripts/pipelines/components/header_component.vue
+++ b/app/assets/javascripts/pipelines/components/header_component.vue
@@ -1,8 +1,11 @@
<script>
-import { GlLoadingIcon, GlModal, GlModalDirective, GlButton } from '@gitlab/ui';
-import ciHeader from '~/vue_shared/components/header_ci_component.vue';
-import eventHub from '../event_hub';
+import { GlAlert, GlButton, GlLoadingIcon, GlModal, GlModalDirective } from '@gitlab/ui';
import { __ } from '~/locale';
+import axios from '~/lib/utils/axios_utils';
+import ciHeader from '~/vue_shared/components/header_ci_component.vue';
+import { setUrlFragment, redirectTo } from '~/lib/utils/url_utility';
+import getPipelineQuery from '../graphql/queries/get_pipeline_header_data.query.graphql';
+import { LOAD_FAILURE, POST_FAILURE, DELETE_FAILURE, DEFAULT } from '../constants';
const DELETE_MODAL_ID = 'pipeline-delete-modal';
@@ -10,57 +13,143 @@ export default {
name: 'PipelineHeaderSection',
components: {
ciHeader,
+ GlAlert,
+ GlButton,
GlLoadingIcon,
GlModal,
- GlButton,
},
directives: {
GlModal: GlModalDirective,
},
- props: {
- pipeline: {
- type: Object,
- required: true,
+ errorTexts: {
+ [LOAD_FAILURE]: __('We are currently unable to fetch data for the pipeline header.'),
+ [POST_FAILURE]: __('An error occurred while making the request.'),
+ [DELETE_FAILURE]: __('An error occurred while deleting the pipeline.'),
+ [DEFAULT]: __('An unknown error occurred.'),
+ },
+ inject: {
+ // Receive `cancel`, `delete`, `fullProject` and `retry`
+ paths: {
+ default: {},
+ },
+ pipelineId: {
+ default: '',
},
- isLoading: {
- type: Boolean,
- required: true,
+ pipelineIid: {
+ default: '',
+ },
+ },
+ apollo: {
+ pipeline: {
+ query: getPipelineQuery,
+ variables() {
+ return {
+ fullPath: this.paths.fullProject,
+ iid: this.pipelineIid,
+ };
+ },
+ update: data => data.project.pipeline,
+ error() {
+ this.reportFailure(LOAD_FAILURE);
+ },
+ pollInterval: 10000,
+ watchLoading(isLoading) {
+ if (!isLoading) {
+ // To ensure apollo has updated the cache,
+ // we only remove the loading state in sync with GraphQL
+ this.isCanceling = false;
+ this.isRetrying = false;
+ }
+ },
},
},
data() {
return {
+ pipeline: null,
+ failureType: null,
isCanceling: false,
isRetrying: false,
isDeleting: false,
};
},
-
computed: {
- status() {
- return this.pipeline.details && this.pipeline.details.status;
- },
- shouldRenderContent() {
- return !this.isLoading && Object.keys(this.pipeline).length;
- },
deleteModalConfirmationText() {
return __(
'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.',
);
},
+ hasError() {
+ return this.failureType;
+ },
+ hasPipelineData() {
+ return Boolean(this.pipeline);
+ },
+ isLoadingInitialQuery() {
+ return this.$apollo.queries.pipeline.loading && !this.hasPipelineData;
+ },
+ status() {
+ return this.pipeline?.status;
+ },
+ shouldRenderContent() {
+ return !this.isLoadingInitialQuery && this.hasPipelineData;
+ },
+ failure() {
+ switch (this.failureType) {
+ case LOAD_FAILURE:
+ return {
+ text: this.$options.errorTexts[LOAD_FAILURE],
+ variant: 'danger',
+ };
+ case POST_FAILURE:
+ return {
+ text: this.$options.errorTexts[POST_FAILURE],
+ variant: 'danger',
+ };
+ case DELETE_FAILURE:
+ return {
+ text: this.$options.errorTexts[DELETE_FAILURE],
+ variant: 'danger',
+ };
+ default:
+ return {
+ text: this.$options.errorTexts[DEFAULT],
+ variant: 'danger',
+ };
+ }
+ },
},
-
methods: {
- cancelPipeline() {
+ reportFailure(errorType) {
+ this.failureType = errorType;
+ },
+ async postAction(path) {
+ try {
+ await axios.post(path);
+ this.$apollo.queries.pipeline.refetch();
+ } catch {
+ this.reportFailure(POST_FAILURE);
+ }
+ },
+ async cancelPipeline() {
this.isCanceling = true;
- eventHub.$emit('headerPostAction', this.pipeline.cancel_path);
+ this.postAction(this.paths.cancel);
},
- retryPipeline() {
+ async retryPipeline() {
this.isRetrying = true;
- eventHub.$emit('headerPostAction', this.pipeline.retry_path);
+ this.postAction(this.paths.retry);
},
- deletePipeline() {
+ async deletePipeline() {
this.isDeleting = true;
- eventHub.$emit('headerDeleteAction', this.pipeline.delete_path);
+ this.$apollo.queries.pipeline.stopPolling();
+
+ try {
+ const { request } = await axios.delete(this.paths.delete);
+ redirectTo(setUrlFragment(request.responseURL, 'delete_success'));
+ } catch {
+ this.$apollo.queries.pipeline.startPolling();
+ this.reportFailure(DELETE_FAILURE);
+ this.isDeleting = false;
+ }
},
},
DELETE_MODAL_ID,
@@ -68,54 +157,53 @@ export default {
</script>
<template>
<div class="pipeline-header-container">
+ <gl-alert v-if="hasError" :variant="failure.variant">{{ failure.text }}</gl-alert>
<ci-header
v-if="shouldRenderContent"
- :status="status"
- :item-id="pipeline.id"
- :time="pipeline.created_at"
+ :status="pipeline.detailedStatus"
+ :time="pipeline.createdAt"
:user="pipeline.user"
+ :item-id="Number(pipelineId)"
item-name="Pipeline"
>
<gl-button
- v-if="pipeline.retry_path"
+ v-if="pipeline.retryable"
:loading="isRetrying"
:disabled="isRetrying"
- data-testid="retryButton"
category="secondary"
variant="info"
+ data-testid="retryPipeline"
+ class="js-retry-button"
@click="retryPipeline()"
>
{{ __('Retry') }}
</gl-button>
<gl-button
- v-if="pipeline.cancel_path"
+ v-if="pipeline.cancelable"
:loading="isCanceling"
:disabled="isCanceling"
- data-testid="cancelPipeline"
- class="gl-ml-3"
- category="primary"
variant="danger"
+ data-testid="cancelPipeline"
@click="cancelPipeline()"
>
{{ __('Cancel running') }}
</gl-button>
<gl-button
- v-if="pipeline.delete_path"
+ v-if="pipeline.userPermissions.destroyPipeline"
v-gl-modal="$options.DELETE_MODAL_ID"
:loading="isDeleting"
:disabled="isDeleting"
- data-testid="deletePipeline"
class="gl-ml-3"
- category="secondary"
variant="danger"
+ category="secondary"
+ data-testid="deletePipeline"
>
{{ __('Delete') }}
</gl-button>
</ci-header>
-
- <gl-loading-icon v-if="isLoading" size="lg" class="gl-mt-3 gl-mb-3" />
+ <gl-loading-icon v-if="isLoadingInitialQuery" size="lg" class="gl-mt-3 gl-mb-3" />
<gl-modal
:modal-id="$options.DELETE_MODAL_ID"
diff --git a/app/assets/javascripts/pipelines/components/legacy_header_component.vue b/app/assets/javascripts/pipelines/components/legacy_header_component.vue
new file mode 100644
index 00000000000..c7b72be36ad
--- /dev/null
+++ b/app/assets/javascripts/pipelines/components/legacy_header_component.vue
@@ -0,0 +1,132 @@
+<script>
+import { GlLoadingIcon, GlModal, GlModalDirective, GlButton } from '@gitlab/ui';
+import ciHeader from '~/vue_shared/components/header_ci_component.vue';
+import eventHub from '../event_hub';
+import { __ } from '~/locale';
+
+const DELETE_MODAL_ID = 'pipeline-delete-modal';
+
+export default {
+ name: 'PipelineHeaderSection',
+ components: {
+ ciHeader,
+ GlLoadingIcon,
+ GlModal,
+ GlButton,
+ },
+ directives: {
+ GlModal: GlModalDirective,
+ },
+ props: {
+ pipeline: {
+ type: Object,
+ required: true,
+ },
+ isLoading: {
+ type: Boolean,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ isCanceling: false,
+ isRetrying: false,
+ isDeleting: false,
+ };
+ },
+
+ computed: {
+ status() {
+ return this.pipeline.details && this.pipeline.details.status;
+ },
+ shouldRenderContent() {
+ return !this.isLoading && Object.keys(this.pipeline).length;
+ },
+ deleteModalConfirmationText() {
+ return __(
+ '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.',
+ );
+ },
+ },
+
+ methods: {
+ cancelPipeline() {
+ this.isCanceling = true;
+ eventHub.$emit('headerPostAction', this.pipeline.cancel_path);
+ },
+ retryPipeline() {
+ this.isRetrying = true;
+ eventHub.$emit('headerPostAction', this.pipeline.retry_path);
+ },
+ deletePipeline() {
+ this.isDeleting = true;
+ eventHub.$emit('headerDeleteAction', this.pipeline.delete_path);
+ },
+ },
+ DELETE_MODAL_ID,
+};
+</script>
+<template>
+ <div class="pipeline-header-container">
+ <ci-header
+ v-if="shouldRenderContent"
+ :status="status"
+ :item-id="pipeline.id"
+ :time="pipeline.created_at"
+ :user="pipeline.user"
+ item-name="Pipeline"
+ >
+ <gl-button
+ v-if="pipeline.retry_path"
+ :loading="isRetrying"
+ :disabled="isRetrying"
+ data-testid="retryButton"
+ category="secondary"
+ variant="info"
+ @click="retryPipeline()"
+ >
+ {{ __('Retry') }}
+ </gl-button>
+
+ <gl-button
+ v-if="pipeline.cancel_path"
+ :loading="isCanceling"
+ :disabled="isCanceling"
+ data-testid="cancelPipeline"
+ class="gl-ml-3"
+ category="primary"
+ variant="danger"
+ @click="cancelPipeline()"
+ >
+ {{ __('Cancel running') }}
+ </gl-button>
+
+ <gl-button
+ v-if="pipeline.delete_path"
+ v-gl-modal="$options.DELETE_MODAL_ID"
+ :loading="isDeleting"
+ :disabled="isDeleting"
+ data-testid="deletePipeline"
+ class="gl-ml-3"
+ category="secondary"
+ variant="danger"
+ >
+ {{ __('Delete') }}
+ </gl-button>
+ </ci-header>
+
+ <gl-loading-icon v-if="isLoading" size="lg" class="gl-mt-3 gl-mb-3" />
+
+ <gl-modal
+ :modal-id="$options.DELETE_MODAL_ID"
+ :title="__('Delete pipeline')"
+ :ok-title="__('Delete pipeline')"
+ ok-variant="danger"
+ @ok="deletePipeline()"
+ >
+ <p>
+ {{ deleteModalConfirmationText }}
+ </p>
+ </gl-modal>
+ </div>
+</template>
diff --git a/app/assets/javascripts/pipelines/components/dag/parsing_utils.js b/app/assets/javascripts/pipelines/components/parsing_utils.js
index 1ed415688f2..1ed415688f2 100644
--- a/app/assets/javascripts/pipelines/components/dag/parsing_utils.js
+++ b/app/assets/javascripts/pipelines/components/parsing_utils.js
diff --git a/app/assets/javascripts/pipelines/components/pipeline_graph/drawing_utils.js b/app/assets/javascripts/pipelines/components/pipeline_graph/drawing_utils.js
new file mode 100644
index 00000000000..45940d4a39c
--- /dev/null
+++ b/app/assets/javascripts/pipelines/components/pipeline_graph/drawing_utils.js
@@ -0,0 +1,96 @@
+import * as d3 from 'd3';
+import { createUniqueJobId } from '../../utils';
+/**
+ * This function expects its first argument data structure
+ * to be the same shaped as the one generated by `parseData`,
+ * which contains nodes and links. For each link,
+ * we find the nodes in the graph, calculate their coordinates and
+ * trace the lines that represent the needs of each job.
+ * @param {Object} nodeDict - Resulting object of `parseData` with nodes and links
+ * @param {Object} jobs - An object where each key is the job name that contains the job data
+ * @param {ref} svg - Reference to the svg we draw in
+ * @returns {Array} Links that contain all the information about them
+ */
+
+export const generateLinksData = ({ links }, jobs, containerID) => {
+ const containerEl = document.getElementById(containerID);
+ return links.map(link => {
+ const path = d3.path();
+
+ const sourceId = jobs[link.source].id;
+ const targetId = jobs[link.target].id;
+
+ const sourceNodeEl = document.getElementById(sourceId);
+ const targetNodeEl = document.getElementById(targetId);
+
+ const sourceNodeCoordinates = sourceNodeEl.getBoundingClientRect();
+ const targetNodeCoordinates = targetNodeEl.getBoundingClientRect();
+ const containerCoordinates = containerEl.getBoundingClientRect();
+
+ // Because we add the svg dynamically and calculate the coordinates
+ // with plain JS and not D3, we need to account for the fact that
+ // the coordinates we are getting are absolutes, but we want to draw
+ // relative to the svg container, which starts at `containerCoordinates(x,y)`
+ // so we substract these from the total. We also need to remove the padding
+ // from the total to make sure it's aligned properly. We then make the line
+ // positioned in the center of the job node by adding half the height
+ // of the job pill.
+ const paddingLeft = Number(
+ window
+ .getComputedStyle(containerEl, null)
+ .getPropertyValue('padding-left')
+ .replace('px', ''),
+ );
+ const paddingTop = Number(
+ window
+ .getComputedStyle(containerEl, null)
+ .getPropertyValue('padding-top')
+ .replace('px', ''),
+ );
+
+ const sourceNodeX = sourceNodeCoordinates.right - containerCoordinates.x - paddingLeft;
+ const sourceNodeY =
+ sourceNodeCoordinates.top -
+ containerCoordinates.y -
+ paddingTop +
+ sourceNodeCoordinates.height / 2;
+ const targetNodeX = targetNodeCoordinates.x - containerCoordinates.x - paddingLeft;
+ const targetNodeY =
+ targetNodeCoordinates.y -
+ containerCoordinates.y -
+ paddingTop +
+ sourceNodeCoordinates.height / 2;
+
+ // Start point
+ path.moveTo(sourceNodeX, sourceNodeY);
+
+ // Make cross-stages lines a straight line all the way
+ // until we can safely draw the bezier to look nice.
+ const straightLineDestinationX = targetNodeX - 100;
+ const controlPointX = straightLineDestinationX + (targetNodeX - straightLineDestinationX) / 2;
+
+ if (straightLineDestinationX > 0) {
+ path.lineTo(straightLineDestinationX, sourceNodeY);
+ }
+
+ // Add bezier curve. The first 4 coordinates are the 2 control
+ // points to create the curve, and the last one is the end point (x, y).
+ // We want our control points to be in the middle of the line
+ path.bezierCurveTo(
+ controlPointX,
+ sourceNodeY,
+ controlPointX,
+ targetNodeY,
+ targetNodeX,
+ targetNodeY,
+ );
+
+ return {
+ ...link,
+ source: sourceId,
+ target: targetId,
+ ref: createUniqueJobId(sourceId, targetId),
+ path: path.toString(),
+ };
+ });
+};
diff --git a/app/assets/javascripts/pipelines/components/pipeline_graph/job_pill.vue b/app/assets/javascripts/pipelines/components/pipeline_graph/job_pill.vue
index 19d41b166c3..8eec0110865 100644
--- a/app/assets/javascripts/pipelines/components/pipeline_graph/job_pill.vue
+++ b/app/assets/javascripts/pipelines/components/pipeline_graph/job_pill.vue
@@ -10,13 +10,57 @@ export default {
type: String,
required: true,
},
+ jobId: {
+ type: String,
+ required: true,
+ },
+ isHighlighted: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ isFadedOut: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ handleMouseOver: {
+ type: Function,
+ required: false,
+ default: () => {},
+ },
+ handleMouseLeave: {
+ type: Function,
+ required: false,
+ default: () => {},
+ },
+ },
+ computed: {
+ jobPillClasses() {
+ return [
+ { 'gl-opacity-3': this.isFadedOut },
+ this.isHighlighted ? 'gl-shadow-blue-200-x0-y0-b4-s2' : 'gl-inset-border-2-green-400',
+ ];
+ },
+ },
+ methods: {
+ onMouseEnter() {
+ this.$emit('on-mouse-enter', this.jobId);
+ },
+ onMouseLeave() {
+ this.$emit('on-mouse-leave');
+ },
},
};
</script>
<template>
<tooltip-on-truncate :title="jobName" truncate-target="child" placement="top">
<div
- class="gl-bg-white gl-text-center gl-text-truncate gl-rounded-pill gl-inset-border-1-green-600 gl-mb-3 gl-px-5 gl-py-2 pipeline-job-pill "
+ :id="jobId"
+ class="pipeline-job-pill gl-bg-white gl-text-center gl-text-truncate gl-rounded-pill gl-mb-3 gl-px-5 gl-py-2 gl-relative gl-z-index-1 gl-transition-duration-slow gl-transition-timing-function-ease"
+ :class="jobPillClasses"
+ @mouseover="onMouseEnter"
+ @mouseleave="onMouseLeave"
>
{{ jobName }}
</div>
diff --git a/app/assets/javascripts/pipelines/components/pipeline_graph/pipeline_graph.vue b/app/assets/javascripts/pipelines/components/pipeline_graph/pipeline_graph.vue
index 6a0d3cce1f3..3a2b8a20bae 100644
--- a/app/assets/javascripts/pipelines/components/pipeline_graph/pipeline_graph.vue
+++ b/app/assets/javascripts/pipelines/components/pipeline_graph/pipeline_graph.vue
@@ -1,8 +1,13 @@
<script>
import { isEmpty } from 'lodash';
import { GlAlert } from '@gitlab/ui';
+import { __ } from '~/locale';
import JobPill from './job_pill.vue';
import StagePill from './stage_pill.vue';
+import { generateLinksData } from './drawing_utils';
+import { parseData } from '../parsing_utils';
+import { DRAW_FAILURE, DEFAULT } from '../../constants';
+import { generateJobNeedsDict } from '../../utils';
export default {
components: {
@@ -10,28 +15,174 @@ export default {
JobPill,
StagePill,
},
+ CONTAINER_REF: 'PIPELINE_GRAPH_CONTAINER_REF',
+ CONTAINER_ID: 'pipeline-graph-container',
+ STROKE_WIDTH: 2,
+ errorTexts: {
+ [DRAW_FAILURE]: __('Could not draw the lines for job relationships'),
+ [DEFAULT]: __('An unknown error occurred.'),
+ },
props: {
pipelineData: {
required: true,
type: Object,
},
},
+ data() {
+ return {
+ failureType: null,
+ highlightedJob: null,
+ links: [],
+ needsObject: null,
+ height: 0,
+ width: 0,
+ };
+ },
computed: {
isPipelineDataEmpty() {
return isEmpty(this.pipelineData);
},
- emptyClass() {
- return !this.isPipelineDataEmpty ? 'gl-py-7' : '';
+ hasError() {
+ return this.failureType;
+ },
+ hasHighlightedJob() {
+ return Boolean(this.highlightedJob);
+ },
+ failure() {
+ const text = this.$options.errorTexts[this.failureType] || this.$options.errorTexts[DEFAULT];
+
+ return { text, variant: 'danger' };
+ },
+ viewBox() {
+ return [0, 0, this.width, this.height];
+ },
+ highlightedJobs() {
+ // If you are hovering on a job, then the jobs we want to highlight are:
+ // The job you are currently hovering + all of its needs.
+ return this.hasHighlightedJob
+ ? [this.highlightedJob, ...this.needsObject[this.highlightedJob]]
+ : [];
+ },
+ highlightedLinks() {
+ // If you are hovering on a job, then the links we want to highlight are:
+ // All the links whose `source` and `target` are highlighted jobs.
+ if (this.hasHighlightedJob) {
+ const filteredLinks = this.links.filter(link => {
+ return (
+ this.highlightedJobs.includes(link.source) && this.highlightedJobs.includes(link.target)
+ );
+ });
+
+ return filteredLinks.map(link => link.ref);
+ }
+
+ return [];
+ },
+ },
+ mounted() {
+ if (!this.isPipelineDataEmpty) {
+ this.getGraphDimensions();
+ this.drawJobLinks();
+ }
+ },
+ methods: {
+ drawJobLinks() {
+ const { stages, jobs } = this.pipelineData;
+ const unwrappedGroups = this.unwrapPipelineData(stages);
+
+ try {
+ const parsedData = parseData(unwrappedGroups);
+ this.links = generateLinksData(parsedData, jobs, this.$options.CONTAINER_ID);
+ } catch {
+ this.reportFailure(DRAW_FAILURE);
+ }
+ },
+ getStageBackgroundClass(index) {
+ const { length } = this.pipelineData.stages;
+
+ if (length === 1) {
+ return 'stage-rounded';
+ } else if (index === 0) {
+ return 'stage-left-rounded';
+ } else if (index === length - 1) {
+ return 'stage-right-rounded';
+ }
+
+ return '';
+ },
+ highlightNeeds(uniqueJobId) {
+ // The first time we hover, we create the object where
+ // we store all the data to properly highlight the needs.
+ if (!this.needsObject) {
+ this.needsObject = generateJobNeedsDict(this.pipelineData) ?? {};
+ }
+
+ this.highlightedJob = uniqueJobId;
+ },
+ removeHighlightNeeds() {
+ this.highlightedJob = null;
+ },
+ unwrapPipelineData(stages) {
+ return stages
+ .map(({ name, groups }) => {
+ return groups.map(group => {
+ return { category: name, ...group };
+ });
+ })
+ .flat(2);
+ },
+ getGraphDimensions() {
+ this.width = `${this.$refs[this.$options.CONTAINER_REF].scrollWidth}px`;
+ this.height = `${this.$refs[this.$options.CONTAINER_REF].scrollHeight}px`;
+ },
+ reportFailure(errorType) {
+ this.failureType = errorType;
+ },
+ resetFailure() {
+ this.failureType = null;
+ },
+ isJobHighlighted(jobName) {
+ return this.highlightedJobs.includes(jobName);
+ },
+ isLinkHighlighted(linkRef) {
+ return this.highlightedLinks.includes(linkRef);
+ },
+ getLinkClasses(link) {
+ return [
+ this.isLinkHighlighted(link.ref) ? 'gl-stroke-blue-400' : 'gl-stroke-gray-200',
+ { 'gl-opacity-3': this.hasHighlightedJob && !this.isLinkHighlighted(link.ref) },
+ ];
},
},
};
</script>
<template>
- <div class="gl-display-flex gl-bg-gray-50 gl-px-4 gl-overflow-auto" :class="emptyClass">
+ <div>
+ <gl-alert v-if="hasError" :variant="failure.variant" @dismiss="resetFailure">
+ {{ failure.text }}
+ </gl-alert>
<gl-alert v-if="isPipelineDataEmpty" variant="tip" :dismissible="false">
{{ __('No content to show') }}
</gl-alert>
- <template v-else>
+ <div
+ v-else
+ :id="$options.CONTAINER_ID"
+ :ref="$options.CONTAINER_REF"
+ class="gl-display-flex gl-bg-gray-50 gl-px-4 gl-overflow-auto gl-relative gl-py-7"
+ >
+ <svg :viewBox="viewBox" :width="width" :height="height" class="gl-absolute">
+ <template>
+ <path
+ v-for="link in links"
+ :key="link.path"
+ :ref="link.ref"
+ :d="link.path"
+ class="gl-fill-transparent gl-transition-duration-slow gl-transition-timing-function-ease"
+ :class="getLinkClasses(link)"
+ :stroke-width="$options.STROKE_WIDTH"
+ />
+ </template>
+ </svg>
<div
v-for="(stage, index) in pipelineData.stages"
:key="`${stage.name}-${index}`"
@@ -39,19 +190,25 @@ export default {
>
<div
class="gl-display-flex gl-align-items-center gl-bg-white gl-w-full gl-px-8 gl-py-4 gl-mb-5"
- :class="{
- 'stage-left-rounded': index === 0,
- 'stage-right-rounded': index === pipelineData.stages.length - 1,
- }"
+ :class="getStageBackgroundClass(index)"
>
<stage-pill :stage-name="stage.name" :is-empty="stage.groups.length === 0" />
</div>
<div
class="gl-display-flex gl-flex-direction-column gl-align-items-center gl-w-full gl-px-8"
>
- <job-pill v-for="group in stage.groups" :key="group.name" :job-name="group.name" />
+ <job-pill
+ v-for="group in stage.groups"
+ :key="group.name"
+ :job-id="group.id"
+ :job-name="group.name"
+ :is-highlighted="hasHighlightedJob && isJobHighlighted(group.id)"
+ :is-faded-out="hasHighlightedJob && !isJobHighlighted(group.id)"
+ @on-mouse-enter="highlightNeeds"
+ @on-mouse-leave="removeHighlightNeeds"
+ />
</div>
</div>
- </template>
+ </div>
</div>
</template>
diff --git a/app/assets/javascripts/pipelines/components/pipelines_list/empty_state.vue b/app/assets/javascripts/pipelines/components/pipelines_list/empty_state.vue
index fe8e3bd2b78..c5f30c8aef0 100644
--- a/app/assets/javascripts/pipelines/components/pipelines_list/empty_state.vue
+++ b/app/assets/javascripts/pipelines/components/pipelines_list/empty_state.vue
@@ -48,6 +48,7 @@ export default {
variant="info"
category="primary"
class="js-get-started-pipelines"
+ data-testid="get-started-pipelines"
>
{{ s__('Pipelines|Get started with Pipelines') }}
</gl-button>
diff --git a/app/assets/javascripts/pipelines/components/pipelines_list/nav_controls.vue b/app/assets/javascripts/pipelines/components/pipelines_list/nav_controls.vue
index d7b6e033bd1..cf0849751df 100644
--- a/app/assets/javascripts/pipelines/components/pipelines_list/nav_controls.vue
+++ b/app/assets/javascripts/pipelines/components/pipelines_list/nav_controls.vue
@@ -46,6 +46,8 @@ export default {
variant="success"
category="primary"
class="js-run-pipeline"
+ data-testid="run-pipeline-button"
+ data-qa-selector="run_pipeline_button"
>
{{ s__('Pipelines|Run Pipeline') }}
</gl-button>
@@ -54,12 +56,13 @@ export default {
v-if="resetCachePath"
:loading="isResetCacheButtonLoading"
class="js-clear-cache"
+ data-testid="clear-cache-button"
@click="onClickResetCache"
>
{{ s__('Pipelines|Clear Runner Caches') }}
</gl-button>
- <gl-button v-if="ciLintPath" :href="ciLintPath" class="js-ci-lint">
+ <gl-button v-if="ciLintPath" :href="ciLintPath" class="js-ci-lint" data-testid="ci-lint-button">
{{ s__('Pipelines|CI Lint') }}
</gl-button>
</div>
diff --git a/app/assets/javascripts/pipelines/components/pipelines_list/pipeline_stop_modal.vue b/app/assets/javascripts/pipelines/components/pipelines_list/pipeline_stop_modal.vue
index 43a54090e18..1569b326b31 100644
--- a/app/assets/javascripts/pipelines/components/pipelines_list/pipeline_stop_modal.vue
+++ b/app/assets/javascripts/pipelines/components/pipelines_list/pipeline_stop_modal.vue
@@ -1,10 +1,9 @@
<script>
/* eslint-disable vue/no-v-html */
import { isEmpty } from 'lodash';
-import { GlLink } from '@gitlab/ui';
-import DeprecatedModal2 from '~/vue_shared/components/deprecated_modal_2.vue';
+import { GlLink, GlModal } from '@gitlab/ui';
import CiIcon from '~/vue_shared/components/ci_icon.vue';
-import { s__, sprintf } from '~/locale';
+import { __, s__, sprintf } from '~/locale';
/**
* Pipeline Stop Modal.
@@ -13,7 +12,7 @@ import { s__, sprintf } from '~/locale';
*/
export default {
components: {
- GlModal: DeprecatedModal2,
+ GlModal,
GlLink,
CiIcon,
},
@@ -46,6 +45,17 @@ export default {
hasRef() {
return !isEmpty(this.pipeline.ref);
},
+ primaryProps() {
+ return {
+ text: s__('Pipeline|Stop pipeline'),
+ attributes: [{ variant: 'danger' }],
+ };
+ },
+ cancelProps() {
+ return {
+ text: __('Cancel'),
+ };
+ },
},
methods: {
emitSubmit(event) {
@@ -56,11 +66,11 @@ export default {
</script>
<template>
<gl-modal
- id="confirmation-modal"
- :header-title-text="modalTitle"
- :footer-primary-button-text="s__('Pipeline|Stop pipeline')"
- footer-primary-button-variant="danger"
- @submit="emitSubmit($event)"
+ modal-id="confirmation-modal"
+ :title="modalTitle"
+ :action-primary="primaryProps"
+ :action-cancel="cancelProps"
+ @primary="emitSubmit($event)"
>
<p v-html="modalText"></p>
diff --git a/app/assets/javascripts/pipelines/components/pipelines_list/pipeline_triggerer.vue b/app/assets/javascripts/pipelines/components/pipelines_list/pipeline_triggerer.vue
index 35fd9837b3e..6ac60727f23 100644
--- a/app/assets/javascripts/pipelines/components/pipelines_list/pipeline_triggerer.vue
+++ b/app/assets/javascripts/pipelines/components/pipelines_list/pipeline_triggerer.vue
@@ -19,7 +19,7 @@ export default {
};
</script>
<template>
- <div class="table-section section-10 d-none d-sm-none d-md-block pipeline-triggerer">
+ <div class="table-section section-10 d-none d-md-block pipeline-triggerer">
<user-avatar-link
v-if="user"
:link-href="user.path"
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 f0614298bd3..63262cc79fd 100644
--- a/app/assets/javascripts/pipelines/components/pipelines_list/pipeline_url.vue
+++ b/app/assets/javascripts/pipelines/components/pipelines_list/pipeline_url.vue
@@ -36,7 +36,7 @@ export default {
};
</script>
<template>
- <div class="table-section section-10 d-none d-sm-none d-md-block pipeline-tags">
+ <div class="table-section section-10 d-none d-md-block pipeline-tags">
<gl-link
:href="pipeline.path"
class="js-pipeline-url-link js-onboarding-pipeline-item"
@@ -98,7 +98,7 @@ export default {
placement="top"
>
<template #title>
- <div class="autodevops-title">
+ <div class="gl-font-weight-normal gl-line-height-normal">
<gl-sprintf
:message="
__(
@@ -112,12 +112,7 @@ export default {
</gl-sprintf>
</div>
</template>
- <gl-link
- class="autodevops-link"
- :href="autoDevopsHelpPath"
- target="_blank"
- rel="noopener noreferrer nofollow"
- >
+ <gl-link :href="autoDevopsHelpPath" target="_blank" rel="noopener noreferrer nofollow">
{{ __('Learn more about Auto DevOps') }}
</gl-link>
</gl-popover>
diff --git a/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_table.vue b/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_table.vue
index b8112149778..6c60594efca 100644
--- a/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_table.vue
+++ b/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_table.vue
@@ -91,6 +91,10 @@ export default {
<div class="table-section section-15 js-pipeline-stages pipeline-stages" role="rowheader">
{{ s__('Pipeline|Stages') }}
</div>
+ <div class="table-section section-15" role="rowheader"></div>
+ <div class="table-section section-20" role="rowheader">
+ <slot name="table-header-actions"></slot>
+ </div>
</div>
<pipelines-table-row-component
v-for="model in pipelines"
diff --git a/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_table_row.vue b/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_table_row.vue
index 1bdb7d18f04..7224ec455f6 100644
--- a/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_table_row.vue
+++ b/app/assets/javascripts/pipelines/components/pipelines_list/pipelines_table_row.vue
@@ -1,6 +1,7 @@
<script>
-import { GlButton } from '@gitlab/ui';
+import { GlButton, GlTooltipDirective, GlModalDirective } from '@gitlab/ui';
import eventHub from '../../event_hub';
+import { __ } from '~/locale';
import PipelinesActionsComponent from './pipelines_actions.vue';
import PipelinesArtifactsComponent from './pipelines_artifacts.vue';
import CiBadge from '~/vue_shared/components/ci_badge_link.vue';
@@ -17,6 +18,14 @@ import { PIPELINES_TABLE } from '../../constants';
* Given the received object renders a table row in the pipelines' table.
*/
export default {
+ i18n: {
+ cancelTitle: __('Cancel'),
+ redeployTitle: __('Retry'),
+ },
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ GlModalDirective,
+ },
components: {
PipelinesActionsComponent,
PipelinesArtifactsComponent,
@@ -321,7 +330,11 @@ export default {
</div>
</div>
- <pipelines-timeago :duration="pipelineDuration" :finished-time="pipelineFinishedAt" />
+ <pipelines-timeago
+ class="gl-text-right"
+ :duration="pipelineDuration"
+ :finished-time="pipelineFinishedAt"
+ />
<div
v-if="displayPipelineActions"
@@ -338,8 +351,11 @@ export default {
<gl-button
v-if="pipeline.flags.retryable"
- :loading="isRetrying"
+ v-gl-tooltip.hover
+ :aria-label="$options.i18n.redeployTitle"
+ :title="$options.i18n.redeployTitle"
:disabled="isRetrying"
+ :loading="isRetrying"
class="js-pipelines-retry-button btn-retry"
data-qa-selector="pipeline_retry_button"
icon="repeat"
@@ -350,10 +366,12 @@ export default {
<gl-button
v-if="pipeline.flags.cancelable"
+ v-gl-tooltip.hover
+ v-gl-modal-directive="'confirmation-modal'"
+ :aria-label="$options.i18n.cancelTitle"
+ :title="$options.i18n.cancelTitle"
:loading="isCancelling"
:disabled="isCancelling"
- data-toggle="modal"
- data-target="#confirmation-modal"
icon="close"
variant="danger"
category="primary"
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 7d13ee582c6..dd09247337c 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,11 @@
<script>
-import { GlIcon } from '@gitlab/ui';
+import { GlIcon, GlTooltipDirective } from '@gitlab/ui';
import '~/lib/utils/datetime_utility';
-import tooltip from '~/vue_shared/directives/tooltip';
import timeagoMixin from '~/vue_shared/mixins/timeago';
export default {
directives: {
- tooltip,
+ GlTooltip: GlTooltipDirective,
},
components: { GlIcon },
mixins: [timeagoMixin],
@@ -51,7 +50,7 @@ export default {
};
</script>
<template>
- <div class="table-section section-15 pipelines-time-ago">
+ <div class="table-section section-15">
<div class="table-mobile-header" role="rowheader">{{ s__('Pipeline|Duration') }}</div>
<div class="table-mobile-content">
<p v-if="hasDuration" class="duration">
@@ -59,11 +58,11 @@ export default {
{{ durationFormatted }}
</p>
- <p v-if="hasFinishedTime" class="finished-at d-none d-sm-none d-md-block">
+ <p v-if="hasFinishedTime" class="finished-at d-none d-md-block">
<gl-icon name="calendar" class="gl-vertical-align-baseline!" aria-hidden="true" />
<time
- v-tooltip
+ v-gl-tooltip
:title="tooltipTitle(finishedTime)"
data-placement="top"
data-container="body"
diff --git a/app/assets/javascripts/pipelines/components/pipelines_list/tokens/pipeline_trigger_author_token.vue b/app/assets/javascripts/pipelines/components/pipelines_list/tokens/pipeline_trigger_author_token.vue
index dfa6d8c13a5..ae5758233bc 100644
--- a/app/assets/javascripts/pipelines/components/pipelines_list/tokens/pipeline_trigger_author_token.vue
+++ b/app/assets/javascripts/pipelines/components/pipelines_list/tokens/pipeline_trigger_author_token.vue
@@ -3,7 +3,7 @@ import {
GlFilteredSearchToken,
GlAvatar,
GlFilteredSearchSuggestion,
- GlDeprecatedDropdownDivider,
+ GlDropdownDivider,
GlLoadingIcon,
} from '@gitlab/ui';
import { debounce } from 'lodash';
@@ -21,7 +21,7 @@ export default {
GlFilteredSearchToken,
GlAvatar,
GlFilteredSearchSuggestion,
- GlDeprecatedDropdownDivider,
+ GlDropdownDivider,
GlLoadingIcon,
},
props: {
@@ -94,7 +94,7 @@ export default {
<gl-filtered-search-suggestion :value="$options.anyTriggerAuthor">{{
$options.anyTriggerAuthor
}}</gl-filtered-search-suggestion>
- <gl-deprecated-dropdown-divider />
+ <gl-dropdown-divider />
<gl-loading-icon v-if="loading" />
<template v-else>
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 aa53c5040e8..2b92ffc3f26 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
@@ -1,6 +1,6 @@
<script>
import { mapGetters } from 'vuex';
-import { GlTooltipDirective, GlFriendlyWrap, GlIcon } from '@gitlab/ui';
+import { GlTooltipDirective, GlFriendlyWrap, GlIcon, GlButton } from '@gitlab/ui';
import { __ } from '~/locale';
export default {
@@ -8,6 +8,7 @@ export default {
components: {
GlIcon,
GlFriendlyWrap,
+ GlButton,
},
directives: {
GlTooltip: GlTooltipDirective,
@@ -45,6 +46,9 @@ export default {
<div role="rowheader" class="table-section section-20">
{{ __('Name') }}
</div>
+ <div role="rowheader" class="table-section section-10">
+ {{ __('Filename') }}
+ </div>
<div role="rowheader" class="table-section section-10 text-center">
{{ __('Status') }}
</div>
@@ -63,18 +67,30 @@ export default {
>
<div class="table-section section-20 section-wrap">
<div role="rowheader" class="table-mobile-header">{{ __('Suite') }}</div>
- <div class="table-mobile-content pr-md-1 gl-overflow-wrap-break">
+ <div class="table-mobile-content gl-md-pr-2 gl-overflow-wrap-break">
<gl-friendly-wrap :symbols="$options.wrapSymbols" :text="testCase.classname" />
</div>
</div>
<div class="table-section section-20 section-wrap">
<div role="rowheader" class="table-mobile-header">{{ __('Name') }}</div>
- <div class="table-mobile-content pr-md-1 gl-overflow-wrap-break">
- <gl-friendly-wrap
- data-testid="caseName"
- :symbols="$options.wrapSymbols"
- :text="testCase.name"
+ <div class="table-mobile-content gl-md-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">
+ <gl-friendly-wrap :symbols="$options.wrapSymbols" :text="testCase.file" />
+ <gl-button
+ v-gl-tooltip
+ size="small"
+ category="tertiary"
+ icon="copy-to-clipboard"
+ :title="__('Copy to clipboard')"
+ :data-clipboard-text="testCase.file"
+ :aria-label="__('Copy to clipboard')"
/>
</div>
</div>
diff --git a/app/assets/javascripts/pipelines/constants.js b/app/assets/javascripts/pipelines/constants.js
index abe5e1060c8..607e7a66f44 100644
--- a/app/assets/javascripts/pipelines/constants.js
+++ b/app/assets/javascripts/pipelines/constants.js
@@ -13,6 +13,8 @@ export const TestStatus = {
FAILED: 'failed',
SKIPPED: 'skipped',
SUCCESS: 'success',
+ ERROR: 'error',
+ UNKNOWN: 'unknown',
};
export const FETCH_AUTHOR_ERROR_MESSAGE = __('There was a problem fetching project users.');
@@ -21,3 +23,12 @@ export const FETCH_TAG_ERROR_MESSAGE = __('There was a problem fetching project
export const RAW_TEXT_WARNING = s__(
'Pipeline|Raw text search is not currently supported. Please use the available search tokens.',
);
+
+/* Error constants shared across graphs */
+export const DEFAULT = 'default';
+export const DELETE_FAILURE = 'delete_pipeline_failure';
+export const DRAW_FAILURE = 'draw_failure';
+export const LOAD_FAILURE = 'load_failure';
+export const PARSE_FAILURE = 'parse_failure';
+export const POST_FAILURE = 'post_failure';
+export const UNSUPPORTED_DATA = 'unsupported_data';
diff --git a/app/assets/javascripts/pipelines/graphql/queries/get_pipeline_header_data.query.graphql b/app/assets/javascripts/pipelines/graphql/queries/get_pipeline_header_data.query.graphql
new file mode 100644
index 00000000000..06083daeca0
--- /dev/null
+++ b/app/assets/javascripts/pipelines/graphql/queries/get_pipeline_header_data.query.graphql
@@ -0,0 +1,30 @@
+query getPipelineHeaderData($fullPath: ID!, $iid: ID!) {
+ project(fullPath: $fullPath) {
+ pipeline(iid: $iid) {
+ id
+ status
+ retryable
+ cancelable
+ userPermissions {
+ destroyPipeline
+ }
+ detailedStatus {
+ detailsPath
+ icon
+ group
+ text
+ }
+ createdAt
+ user {
+ name
+ webPath
+ email
+ avatarUrl
+ status {
+ message
+ emoji
+ }
+ }
+ }
+ }
+}
diff --git a/app/assets/javascripts/pipelines/mixins/graph_component_mixin.js b/app/assets/javascripts/pipelines/mixins/graph_component_mixin.js
deleted file mode 100644
index 53b7a174517..00000000000
--- a/app/assets/javascripts/pipelines/mixins/graph_component_mixin.js
+++ /dev/null
@@ -1,54 +0,0 @@
-import { escape } from 'lodash';
-
-export default {
- props: {
- isLoading: {
- type: Boolean,
- required: true,
- },
- pipeline: {
- type: Object,
- required: true,
- },
- },
- computed: {
- graph() {
- return this.pipeline.details && this.pipeline.details.stages;
- },
- },
- methods: {
- capitalizeStageName(name) {
- const escapedName = escape(name);
- return escapedName.charAt(0).toUpperCase() + escapedName.slice(1);
- },
- isFirstColumn(index) {
- return index === 0;
- },
- stageConnectorClass(index, stage) {
- let className;
-
- // If it's the first stage column and only has one job
- if (index === 0 && stage.groups.length === 1) {
- className = 'no-margin';
- } else if (index > 0) {
- // If it is not the first column
- className = 'left-margin';
- }
-
- return className;
- },
- refreshPipelineGraph() {
- this.$emit('refreshPipelineGraph');
- },
- /**
- * CSS class is applied:
- * - if pipeline graph contains only one stage column component
- *
- * @param {number} index
- * @returns {boolean}
- */
- shouldAddRightMargin(index) {
- return !(index === this.graph.length - 1);
- },
- },
-};
diff --git a/app/assets/javascripts/pipelines/pipeline_details_bundle.js b/app/assets/javascripts/pipelines/pipeline_details_bundle.js
index 745f5b886a5..67aec12655a 100644
--- a/app/assets/javascripts/pipelines/pipeline_details_bundle.js
+++ b/app/assets/javascripts/pipelines/pipeline_details_bundle.js
@@ -7,10 +7,11 @@ import pipelineGraph from './components/graph/graph_component.vue';
import createDagApp from './pipeline_details_dag';
import GraphBundleMixin from './mixins/graph_pipeline_bundle_mixin';
import PipelinesMediator from './pipeline_details_mediator';
-import pipelineHeader from './components/header_component.vue';
+import legacyPipelineHeader from './components/legacy_header_component.vue';
import eventHub from './event_hub';
import TestReports from './components/test_reports/test_reports.vue';
import createTestReportsStore from './stores/test_reports';
+import { createPipelineHeaderApp } from './pipeline_details_header';
Vue.use(Translate);
@@ -56,7 +57,7 @@ const createPipelinesDetailApp = mediator => {
});
};
-const createPipelineHeaderApp = mediator => {
+const createLegacyPipelineHeaderApp = mediator => {
if (!document.querySelector(SELECTORS.PIPELINE_HEADER)) {
return;
}
@@ -64,7 +65,7 @@ const createPipelineHeaderApp = mediator => {
new Vue({
el: SELECTORS.PIPELINE_HEADER,
components: {
- pipelineHeader,
+ legacyPipelineHeader,
},
data() {
return {
@@ -95,7 +96,7 @@ const createPipelineHeaderApp = mediator => {
},
},
render(createElement) {
- return createElement('pipeline-header', {
+ return createElement('legacy-pipeline-header', {
props: {
isLoading: this.mediator.state.isLoading,
pipeline: this.mediator.store.state.pipeline,
@@ -132,7 +133,12 @@ export default () => {
mediator.fetchPipeline();
createPipelinesDetailApp(mediator);
- createPipelineHeaderApp(mediator);
+
+ if (gon.features.graphqlPipelineHeader) {
+ createPipelineHeaderApp(SELECTORS.PIPELINE_HEADER);
+ } else {
+ createLegacyPipelineHeaderApp(mediator);
+ }
createTestDetails();
createDagApp();
};
diff --git a/app/assets/javascripts/pipelines/pipeline_details_header.js b/app/assets/javascripts/pipelines/pipeline_details_header.js
new file mode 100644
index 00000000000..27fe9ba3f19
--- /dev/null
+++ b/app/assets/javascripts/pipelines/pipeline_details_header.js
@@ -0,0 +1,41 @@
+import Vue from 'vue';
+import VueApollo from 'vue-apollo';
+import createDefaultClient from '~/lib/graphql';
+import pipelineHeader from './components/header_component.vue';
+
+Vue.use(VueApollo);
+
+const apolloProvider = new VueApollo({
+ defaultClient: createDefaultClient(),
+});
+
+export const createPipelineHeaderApp = elSelector => {
+ const el = document.querySelector(elSelector);
+
+ if (!el) {
+ return;
+ }
+
+ const { cancelPath, deletePath, fullPath, pipelineId, pipelineIid, retryPath } = el?.dataset;
+ // eslint-disable-next-line no-new
+ new Vue({
+ el,
+ components: {
+ pipelineHeader,
+ },
+ apolloProvider,
+ provide: {
+ paths: {
+ cancel: cancelPath,
+ delete: deletePath,
+ fullProject: fullPath,
+ retry: retryPath,
+ },
+ pipelineId,
+ pipelineIid,
+ },
+ render(createElement) {
+ return createElement('pipeline-header', {});
+ },
+ });
+};
diff --git a/app/assets/javascripts/pipelines/stores/test_reports/utils.js b/app/assets/javascripts/pipelines/stores/test_reports/utils.js
index 8f1ac305cda..42406e5a67a 100644
--- a/app/assets/javascripts/pipelines/stores/test_reports/utils.js
+++ b/app/assets/javascripts/pipelines/stores/test_reports/utils.js
@@ -1,13 +1,19 @@
import { __, sprintf } from '../../../locale';
+import { TestStatus } from '../../constants';
export function iconForTestStatus(status) {
switch (status) {
- case 'success':
+ case TestStatus.SUCCESS:
return 'status_success_borderless';
- case 'failed':
+ case TestStatus.FAILED:
return 'status_failed_borderless';
- default:
+ case TestStatus.ERROR:
+ return 'status_warning_borderless';
+ case TestStatus.SKIPPED:
return 'status_skipped_borderless';
+ case TestStatus.UNKNOWN:
+ default:
+ return 'status_notfound_borderless';
}
}
diff --git a/app/assets/javascripts/pipelines/utils.js b/app/assets/javascripts/pipelines/utils.js
index bd53b22784c..7d1a1762e0d 100644
--- a/app/assets/javascripts/pipelines/utils.js
+++ b/app/assets/javascripts/pipelines/utils.js
@@ -5,6 +5,8 @@ export const validateParams = params => {
return pickBy(params, (val, key) => SUPPORTED_FILTER_PARAMETERS.includes(key) && val);
};
+export const createUniqueJobId = (stageName, jobName) => `${stageName}-${jobName}`;
+
/**
* This function takes a json payload that comes from a yml
* file converted to json through `jsyaml` library. Because we
@@ -18,6 +20,16 @@ export const validateParams = params => {
export const preparePipelineGraphData = jsonData => {
const jsonKeys = Object.keys(jsonData);
const jobNames = jsonKeys.filter(job => jsonData[job]?.stage);
+ // Creates an object with only the valid jobs
+ const jobs = jsonKeys.reduce((acc, val) => {
+ if (jobNames.includes(val)) {
+ return {
+ ...acc,
+ [val]: { ...jsonData[val], id: createUniqueJobId(jsonData[val].stage, val) },
+ };
+ }
+ return { ...acc };
+ }, {});
// We merge both the stages from the "stages" key in the yaml and the stage associated
// with each job to show the user both the stages they explicitly defined, and those
@@ -40,10 +52,45 @@ export const preparePipelineGraphData = jsonData => {
return {
name: stage,
groups: stageJobs.map(job => {
- return { name: job, jobs: [{ ...jsonData[job] }] };
+ return {
+ name: job,
+ jobs: [{ ...jsonData[job] }],
+ id: createUniqueJobId(stage, job),
+ };
}),
};
});
- return { stages: pipelineData };
+ return { stages: pipelineData, jobs };
+};
+
+export const generateJobNeedsDict = ({ jobs }) => {
+ const arrOfJobNames = Object.keys(jobs);
+
+ return arrOfJobNames.reduce((acc, value) => {
+ const recursiveNeeds = jobName => {
+ if (!jobs[jobName]?.needs) {
+ return [];
+ }
+
+ return jobs[jobName].needs
+ .map(job => {
+ const { id } = jobs[job];
+ // If we already have the needs of a job in the accumulator,
+ // then we use the memoized data instead of the recursive call
+ // to save some performance.
+ const newNeeds = acc[id] ?? recursiveNeeds(job);
+
+ return [id, ...newNeeds];
+ })
+ .flat(Infinity);
+ };
+
+ // To ensure we don't have duplicates job relationship when 2 jobs
+ // needed by another both depends on the same jobs, we remove any
+ // duplicates from the array.
+ const uniqueValues = Array.from(new Set(recursiveNeeds(value)));
+
+ return { ...acc, [jobs[value].id]: uniqueValues };
+ }, {});
};
diff --git a/app/assets/javascripts/profile/account/components/update_username.vue b/app/assets/javascripts/profile/account/components/update_username.vue
index 4aaa2cff2ac..200e5ba255f 100644
--- a/app/assets/javascripts/profile/account/components/update_username.vue
+++ b/app/assets/javascripts/profile/account/components/update_username.vue
@@ -1,6 +1,7 @@
<script>
/* eslint-disable vue/no-v-html */
import { escape } from 'lodash';
+import { GlButton } from '@gitlab/ui';
import axios from '~/lib/utils/axios_utils';
import DeprecatedModal2 from '~/vue_shared/components/deprecated_modal_2.vue';
import { s__, sprintf } from '~/locale';
@@ -9,6 +10,7 @@ import { deprecatedCreateFlash as Flash } from '~/flash';
export default {
components: {
GlModal: DeprecatedModal2,
+ GlButton,
},
props: {
actionUrl: {
@@ -100,15 +102,15 @@ Please update your Git repository remotes as soon as possible.`),
</div>
<p class="form-text text-muted">{{ path }}</p>
</div>
- <button
+ <gl-button
:data-target="`#${$options.modalId}`"
:disabled="isRequestPending || newUsername === username"
- class="btn btn-warning"
- type="button"
+ category="primary"
+ variant="warning"
data-toggle="modal"
>
{{ $options.buttonText }}
- </button>
+ </gl-button>
<gl-modal
:id="$options.modalId"
:header-title-text="s__('Profiles|Change username') + '?'"
diff --git a/app/assets/javascripts/profile/gl_crop.js b/app/assets/javascripts/profile/gl_crop.js
index 55bc9fb8955..ecb69422287 100644
--- a/app/assets/javascripts/profile/gl_crop.js
+++ b/app/assets/javascripts/profile/gl_crop.js
@@ -3,6 +3,7 @@
import $ from 'jquery';
import 'cropper';
import { isString } from 'lodash';
+import { loadCSSFile } from '../lib/utils/css_utils';
(() => {
// Matches everything but the file name
@@ -180,6 +181,9 @@ import { isString } from 'lodash';
}
}
+ const cropModal = document.querySelector('.modal-profile-crop');
+ if (cropModal) loadCSSFile(cropModal.dataset.cropperCssPath);
+
$.fn.glCrop = function(opts) {
return this.each(function() {
return $(this).data('glcrop', new GitLabCrop(this, opts));
diff --git a/app/assets/javascripts/profile/profile.js b/app/assets/javascripts/profile/profile.js
index 6822fa8f7c7..4755a4aa9ba 100644
--- a/app/assets/javascripts/profile/profile.js
+++ b/app/assets/javascripts/profile/profile.js
@@ -1,5 +1,6 @@
import $ from 'jquery';
import axios from '~/lib/utils/axios_utils';
+import { Rails } from '~/lib/utils/rails_ujs';
import { deprecatedCreateFlash as flash } from '../flash';
import { parseBoolean } from '~/lib/utils/common_utils';
import TimezoneDropdown, {
@@ -48,9 +49,13 @@ export default class Profile {
}
submitForm() {
- return $(this)
- .parents('form')
- .submit();
+ const $form = $(this).parents('form');
+
+ if ($form.data('remote')) {
+ Rails.fire($form[0], 'submit');
+ } else {
+ $form.submit();
+ }
}
onSubmitForm(e) {
diff --git a/app/assets/javascripts/project_find_file.js b/app/assets/javascripts/project_find_file.js
index 70fce4a4d09..2f35c4485f9 100644
--- a/app/assets/javascripts/project_find_file.js
+++ b/app/assets/javascripts/project_find_file.js
@@ -2,9 +2,10 @@
import $ from 'jquery';
import fuzzaldrinPlus from 'fuzzaldrin-plus';
-import { sanitize } from 'dompurify';
+import { sanitize } from '~/lib/dompurify';
import axios from '~/lib/utils/axios_utils';
import { joinPaths, escapeFileUrl } from '~/lib/utils/url_utility';
+import { spriteIcon } from '~/lib/utils/common_utils';
import { deprecatedCreateFlash as flash } from '~/flash';
import { __ } from '~/locale';
@@ -125,7 +126,10 @@ export default class ProjectFindFile {
// make tbody row html
static makeHtml(filePath, matches, blobItemUrl) {
const $tr = $(
- "<tr class='tree-item'><td class='tree-item-file-name link-container'><a><i class='fa fa-file-text-o fa-fw'></i><span class='str-truncated'></span></a></td></tr>",
+ `<tr class='tree-item'><td class='tree-item-file-name link-container'><a>${spriteIcon(
+ 'doc-text',
+ 's16 vertical-align-middle gl-mr-1',
+ )}<span class='str-truncated'></span></a></td></tr>`,
);
if (matches) {
$tr
diff --git a/app/assets/javascripts/project_label_subscription.js b/app/assets/javascripts/project_label_subscription.js
index 12c77b09b64..4fefc2ed569 100644
--- a/app/assets/javascripts/project_label_subscription.js
+++ b/app/assets/javascripts/project_label_subscription.js
@@ -2,6 +2,7 @@ import $ from 'jquery';
import { __ } from './locale';
import axios from './lib/utils/axios_utils';
import { deprecatedCreateFlash as flash } from './flash';
+import { fixTitle } from '~/tooltips';
const tooltipTitles = {
group: {
@@ -66,6 +67,7 @@ export default class ProjectLabelSubscription {
const type = /group/.test(originalTitle) ? 'group' : 'project';
const newTitle = tooltipTitles[type][newStatus];
- $button.attr('title', newTitle).tooltip('_fixTitle');
+ $button.attr('title', newTitle);
+ fixTitle($button);
}
}
diff --git a/app/assets/javascripts/projects/commit_box/info/index.js b/app/assets/javascripts/projects/commit_box/info/index.js
new file mode 100644
index 00000000000..352ac39f3c4
--- /dev/null
+++ b/app/assets/javascripts/projects/commit_box/info/index.js
@@ -0,0 +1,18 @@
+import { loadBranches } from './load_branches';
+import { fetchCommitMergeRequests } from '~/commit_merge_requests';
+import MiniPipelineGraph from '~/mini_pipeline_graph_dropdown';
+
+export const initCommitBoxInfo = (containerSelector = '.js-commit-box-info') => {
+ const containerEl = document.querySelector(containerSelector);
+
+ // Display commit related branches
+ loadBranches(containerEl);
+
+ // Related merge requests to this commit
+ fetchCommitMergeRequests();
+
+ // Display pipeline info for this commit
+ new MiniPipelineGraph({
+ container: '.js-commit-pipeline-graph',
+ }).bindEvents();
+};
diff --git a/app/assets/javascripts/projects/commit_box/info/load_branches.js b/app/assets/javascripts/projects/commit_box/info/load_branches.js
new file mode 100644
index 00000000000..0efa1998507
--- /dev/null
+++ b/app/assets/javascripts/projects/commit_box/info/load_branches.js
@@ -0,0 +1,20 @@
+import axios from 'axios';
+import { sanitize } from '~/lib/dompurify';
+import { __ } from '~/locale';
+
+export const loadBranches = containerEl => {
+ if (!containerEl) {
+ return;
+ }
+
+ const { commitPath } = containerEl.dataset;
+ const branchesEl = containerEl.querySelector('.commit-info.branches');
+ axios
+ .get(commitPath)
+ .then(({ data }) => {
+ branchesEl.innerHTML = sanitize(data);
+ })
+ .catch(() => {
+ branchesEl.textContent = __('Failed to load branches. Please try again.');
+ });
+};
diff --git a/app/assets/javascripts/projects/commits/components/author_select.vue b/app/assets/javascripts/projects/commits/components/author_select.vue
index 2204ec3cbe7..3bc772fe60a 100644
--- a/app/assets/javascripts/projects/commits/components/author_select.vue
+++ b/app/assets/javascripts/projects/commits/components/author_select.vue
@@ -119,7 +119,6 @@ export default {
<gl-dropdown-divider />
<gl-search-box-by-type
v-model.trim="authorInput"
- class="gl-m-3"
:placeholder="__('Search')"
@input="searchAuthors"
/>
diff --git a/app/assets/javascripts/projects/commits/store/actions.js b/app/assets/javascripts/projects/commits/store/actions.js
index 927501748a5..157e2409f7f 100644
--- a/app/assets/javascripts/projects/commits/store/actions.js
+++ b/app/assets/javascripts/projects/commits/store/actions.js
@@ -1,4 +1,4 @@
-import * as Sentry from '@sentry/browser';
+import * as Sentry from '~/sentry/wrapper';
import * as types from './mutation_types';
import axios from '~/lib/utils/axios_utils';
import { deprecatedCreateFlash as createFlash } from '~/flash';
diff --git a/app/assets/javascripts/projects/default_project_templates.js b/app/assets/javascripts/projects/default_project_templates.js
index 2d321ead33e..a6019e9c01b 100644
--- a/app/assets/javascripts/projects/default_project_templates.js
+++ b/app/assets/javascripts/projects/default_project_templates.js
@@ -57,6 +57,10 @@ export default {
text: s__('ProjectTemplates|Static Site Editor/Middleman'),
icon: '.template-option .icon-sse_middleman',
},
+ gitpod_spring_petclinic: {
+ text: s__('ProjectTemplates|Gitpod/Spring Petclinic'),
+ icon: '.template-option .icon-gitpod_spring_petclinic',
+ },
nfhugo: {
text: s__('ProjectTemplates|Netlify/Hugo'),
icon: '.template-option .icon-nfhugo',
diff --git a/app/assets/javascripts/projects/default_sample_data_templates.js b/app/assets/javascripts/projects/default_sample_data_templates.js
new file mode 100644
index 00000000000..7c45e7ac62f
--- /dev/null
+++ b/app/assets/javascripts/projects/default_sample_data_templates.js
@@ -0,0 +1,12 @@
+import { s__ } from '~/locale';
+
+export default {
+ basic: {
+ text: s__('ProjectTemplates|Basic'),
+ icon: '.template-option .icon-basic',
+ },
+ serenity_valley: {
+ text: s__('ProjectTemplates|Serenity Valley'),
+ icon: '.template-option .icon-serenity_valley',
+ },
+};
diff --git a/app/assets/javascripts/projects/project_new.js b/app/assets/javascripts/projects/project_new.js
index 599aa52831b..d74a2d06786 100644
--- a/app/assets/javascripts/projects/project_new.js
+++ b/app/assets/javascripts/projects/project_new.js
@@ -1,5 +1,6 @@
import $ from 'jquery';
import DEFAULT_PROJECT_TEMPLATES from 'ee_else_ce/projects/default_project_templates';
+import DEFAULT_SAMPLE_DATA_TEMPLATES from '~/projects/default_sample_data_templates';
import { addSelectOnFocusBehaviour } from '../lib/utils/common_utils';
import {
convertToTitleCase,
@@ -146,7 +147,8 @@ const bindEvents = () => {
$selectedIcon.empty();
const value = $(this).val();
- const selectedTemplate = DEFAULT_PROJECT_TEMPLATES[value];
+ const selectedTemplate =
+ DEFAULT_PROJECT_TEMPLATES[value] || DEFAULT_SAMPLE_DATA_TEMPLATES[value];
$selectedTemplateText.text(selectedTemplate.text);
$(selectedTemplate.icon)
.clone()
diff --git a/app/assets/javascripts/projects/settings/access_dropdown.js b/app/assets/javascripts/projects/settings/access_dropdown.js
index 5d51b7ea57b..3ca5bca4bf2 100644
--- a/app/assets/javascripts/projects/settings/access_dropdown.js
+++ b/app/assets/javascripts/projects/settings/access_dropdown.js
@@ -1,9 +1,9 @@
/* eslint-disable no-underscore-dangle, class-methods-use-this */
import { escape, find, countBy } from 'lodash';
import axios from '~/lib/utils/axios_utils';
-import { deprecatedCreateFlash as Flash } from '~/flash';
-import { n__, s__, __ } from '~/locale';
-import { LEVEL_TYPES, LEVEL_ID_PROP, ACCESS_LEVEL_NONE } from './constants';
+import createFlash from '~/flash';
+import { n__, s__, __, sprintf } from '~/locale';
+import { LEVEL_TYPES, LEVEL_ID_PROP, ACCESS_LEVELS, ACCESS_LEVEL_NONE } from './constants';
import initDeprecatedJQueryDropdown from '~/deprecated_jquery_dropdown';
export default class AccessDropdown {
@@ -11,6 +11,7 @@ export default class AccessDropdown {
const { $dropdown, accessLevel, accessLevelsData, hasLicense = true } = options;
this.options = options;
this.hasLicense = hasLicense;
+ this.deployKeysOnProtectedBranchesEnabled = gon.features.deployKeysOnProtectedBranches;
this.groups = [];
this.accessLevel = accessLevel;
this.accessLevelsData = accessLevelsData.roles;
@@ -18,6 +19,7 @@ export default class AccessDropdown {
this.$wrap = this.$dropdown.closest(`.${this.accessLevel}-container`);
this.usersPath = '/-/autocomplete/users.json';
this.groupsPath = '/-/autocomplete/project_groups.json';
+ this.deployKeysPath = '/-/autocomplete/deploy_keys_with_owners.json';
this.defaultLabel = this.$dropdown.data('defaultLabel');
this.setSelectedItems([]);
@@ -146,6 +148,8 @@ export default class AccessDropdown {
obj.access_level = item.access_level;
} else if (item.type === LEVEL_TYPES.USER) {
obj.user_id = item.user_id;
+ } else if (item.type === LEVEL_TYPES.DEPLOY_KEY) {
+ obj.deploy_key_id = item.deploy_key_id;
} else if (item.type === LEVEL_TYPES.GROUP) {
obj.group_id = item.group_id;
}
@@ -177,6 +181,9 @@ export default class AccessDropdown {
case LEVEL_TYPES.GROUP:
comparator = LEVEL_ID_PROP.GROUP;
break;
+ case LEVEL_TYPES.DEPLOY_KEY:
+ comparator = LEVEL_ID_PROP.DEPLOY_KEY;
+ break;
case LEVEL_TYPES.USER:
comparator = LEVEL_ID_PROP.USER;
break;
@@ -218,6 +225,11 @@ export default class AccessDropdown {
group_id: selectedItem.id,
type: LEVEL_TYPES.GROUP,
};
+ } else if (selectedItem.type === LEVEL_TYPES.DEPLOY_KEY) {
+ itemToAdd = {
+ deploy_key_id: selectedItem.id,
+ type: LEVEL_TYPES.DEPLOY_KEY,
+ };
}
this.items.push(itemToAdd);
@@ -233,11 +245,12 @@ export default class AccessDropdown {
return true;
}
- if (item.type === LEVEL_TYPES.USER && item.user_id === itemToDelete.id) {
- index = i;
- } else if (item.type === LEVEL_TYPES.ROLE && item.access_level === itemToDelete.id) {
- index = i;
- } else if (item.type === LEVEL_TYPES.GROUP && item.group_id === itemToDelete.id) {
+ if (
+ (item.type === LEVEL_TYPES.USER && item.user_id === itemToDelete.id) ||
+ (item.type === LEVEL_TYPES.ROLE && item.access_level === itemToDelete.id) ||
+ (item.type === LEVEL_TYPES.DEPLOY_KEY && item.deploy_key_id === itemToDelete.id) ||
+ (item.type === LEVEL_TYPES.GROUP && item.group_id === itemToDelete.id)
+ ) {
index = i;
}
@@ -289,6 +302,10 @@ export default class AccessDropdown {
labelPieces.push(n__('1 user', '%d users', counts[LEVEL_TYPES.USER]));
}
+ if (counts[LEVEL_TYPES.DEPLOY_KEY] > 0) {
+ labelPieces.push(n__('1 deploy key', '%d deploy keys', counts[LEVEL_TYPES.DEPLOY_KEY]));
+ }
+
if (counts[LEVEL_TYPES.GROUP] > 0) {
labelPieces.push(n__('1 group', '%d groups', counts[LEVEL_TYPES.GROUP]));
}
@@ -299,20 +316,31 @@ export default class AccessDropdown {
getData(query, callback) {
if (this.hasLicense) {
Promise.all([
+ this.getDeployKeys(query),
this.getUsers(query),
this.groupsData ? Promise.resolve(this.groupsData) : this.getGroups(),
])
- .then(([usersResponse, groupsResponse]) => {
+ .then(([deployKeysResponse, usersResponse, groupsResponse]) => {
this.groupsData = groupsResponse;
- callback(this.consolidateData(usersResponse.data, groupsResponse.data));
+ callback(
+ this.consolidateData(deployKeysResponse.data, usersResponse.data, groupsResponse.data),
+ );
})
- .catch(() => Flash(__('Failed to load groups & users.')));
+ .catch(() => {
+ if (this.deployKeysOnProtectedBranchesEnabled) {
+ createFlash({ message: __('Failed to load groups, users and deploy keys.') });
+ } else {
+ createFlash({ message: __('Failed to load groups & users.') });
+ }
+ });
} else {
- callback(this.consolidateData());
+ this.getDeployKeys(query)
+ .then(deployKeysResponse => callback(this.consolidateData(deployKeysResponse.data)))
+ .catch(() => createFlash({ message: __('Failed to load deploy keys.') }));
}
}
- consolidateData(usersResponse = [], groupsResponse = []) {
+ consolidateData(deployKeysResponse, usersResponse = [], groupsResponse = []) {
let consolidatedData = [];
// ID property is handled differently locally from the server
@@ -328,6 +356,10 @@ export default class AccessDropdown {
// For Users
// In dropdown: `id`
// For submit: `user_id`
+ //
+ // For Deploy Keys
+ // In dropdown: `id`
+ // For submit: `deploy_key_id`
/*
* Build roles
@@ -410,6 +442,38 @@ export default class AccessDropdown {
}
}
+ if (this.deployKeysOnProtectedBranchesEnabled) {
+ const deployKeys = deployKeysResponse.map(response => {
+ const {
+ id,
+ fingerprint,
+ title,
+ owner: { avatar_url, name, username },
+ } = response;
+
+ const shortFingerprint = `(${fingerprint.substring(0, 14)}...)`;
+
+ return {
+ id,
+ title: title.concat(' ', shortFingerprint),
+ avatar_url,
+ fullname: name,
+ username,
+ type: LEVEL_TYPES.DEPLOY_KEY,
+ };
+ });
+
+ if (this.accessLevel === ACCESS_LEVELS.PUSH) {
+ if (deployKeys.length) {
+ consolidatedData = consolidatedData.concat(
+ [{ type: 'divider' }],
+ [{ type: 'header', content: s__('AccessDropdown|Deploy Keys') }],
+ deployKeys,
+ );
+ }
+ }
+ }
+
return consolidatedData;
}
@@ -433,6 +497,22 @@ export default class AccessDropdown {
});
}
+ getDeployKeys(query) {
+ if (this.deployKeysOnProtectedBranchesEnabled) {
+ return axios.get(this.buildUrl(gon.relative_url_root, this.deployKeysPath), {
+ params: {
+ search: query,
+ per_page: 20,
+ active: true,
+ project_id: gon.current_project_id,
+ push_code: true,
+ },
+ });
+ }
+
+ return Promise.resolve({ data: [] });
+ }
+
buildUrl(urlRoot, url) {
let newUrl;
if (urlRoot != null) {
@@ -454,6 +534,9 @@ export default class AccessDropdown {
case LEVEL_TYPES.ROLE:
criteria = { access_level: item.id };
break;
+ case LEVEL_TYPES.DEPLOY_KEY:
+ criteria = { deploy_key_id: item.id };
+ break;
case LEVEL_TYPES.GROUP:
criteria = { group_id: item.id };
break;
@@ -470,6 +553,10 @@ export default class AccessDropdown {
case LEVEL_TYPES.ROLE:
groupRowEl = this.roleRowHtml(item, isActive);
break;
+ case LEVEL_TYPES.DEPLOY_KEY:
+ groupRowEl =
+ this.accessLevel === ACCESS_LEVELS.PUSH ? this.deployKeyRowHtml(item, isActive) : '';
+ break;
case LEVEL_TYPES.GROUP:
groupRowEl = this.groupRowHtml(item, isActive);
break;
@@ -495,6 +582,31 @@ export default class AccessDropdown {
`;
}
+ deployKeyRowHtml(key, isActive) {
+ const isActiveClass = isActive || '';
+
+ return `
+ <li>
+ <a href="#" class="${isActiveClass}">
+ <strong>${key.title}</strong>
+ <p>
+ ${sprintf(
+ __('Owned by %{image_tag}'),
+ {
+ image_tag: `<img src="${key.avatar_url}" class="avatar avatar-inline s26" width="30">`,
+ },
+ false,
+ )}
+ <strong class="dropdown-menu-user-full-name gl-display-inline">${escape(
+ key.fullname,
+ )}</strong>
+ <span class="dropdown-menu-user-username gl-display-inline">${key.username}</span>
+ </p>
+ </a>
+ </li>
+ `;
+ }
+
groupRowHtml(group, isActive) {
const isActiveClass = isActive || '';
const avatarEl = group.avatar_url
diff --git a/app/assets/javascripts/projects/settings/constants.js b/app/assets/javascripts/projects/settings/constants.js
index fadb1f4f178..f5591c43dc4 100644
--- a/app/assets/javascripts/projects/settings/constants.js
+++ b/app/assets/javascripts/projects/settings/constants.js
@@ -1,13 +1,20 @@
export const LEVEL_TYPES = {
ROLE: 'role',
USER: 'user',
+ DEPLOY_KEY: 'deploy_key',
GROUP: 'group',
};
export const LEVEL_ID_PROP = {
ROLE: 'access_level',
USER: 'user_id',
+ DEPLOY_KEY: 'deploy_key_id',
GROUP: 'group_id',
};
+export const ACCESS_LEVELS = {
+ MERGE: 'merge_access_levels',
+ PUSH: 'push_access_levels',
+};
+
export const ACCESS_LEVEL_NONE = 0;
diff --git a/app/assets/javascripts/projects/settings_service_desk/components/service_desk_root.vue b/app/assets/javascripts/projects/settings_service_desk/components/service_desk_root.vue
index 81367f7d6b4..4bfed6d489d 100644
--- a/app/assets/javascripts/projects/settings_service_desk/components/service_desk_root.vue
+++ b/app/assets/javascripts/projects/settings_service_desk/components/service_desk_root.vue
@@ -1,6 +1,6 @@
<script>
import { GlAlert } from '@gitlab/ui';
-import { __ } from '~/locale';
+import { __, sprintf } from '~/locale';
import ServiceDeskSetting from './service_desk_setting.vue';
import ServiceDeskService from '../services/service_desk_service';
import eventHub from '../event_hub';
@@ -122,11 +122,13 @@ export default {
this.incomingEmail = data?.service_desk_address;
this.showAlert(__('Changes were successfully made.'), 'success');
})
- .catch(() =>
+ .catch(err => {
this.showAlert(
- __('An error occurred while saving the template. Please check if the template exists.'),
- ),
- )
+ sprintf(__('An error occured while making the changes: %{error}'), {
+ error: err?.response?.data?.message,
+ }),
+ );
+ })
.finally(() => {
this.isTemplateSaving = false;
});
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 6a0810ad3a1..e18cfefc3ca 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
@@ -1,22 +1,19 @@
<script>
-import { GlButton, GlFormSelect, GlToggle, GlLoadingIcon } from '@gitlab/ui';
+import { GlButton, GlFormSelect, GlToggle, GlLoadingIcon, GlSprintf } from '@gitlab/ui';
import { __ } from '~/locale';
-import tooltip from '~/vue_shared/directives/tooltip';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
import eventHub from '../event_hub';
export default {
name: 'ServiceDeskSetting',
- directives: {
- tooltip,
- },
components: {
ClipboardButton,
GlButton,
GlFormSelect,
GlToggle,
GlLoadingIcon,
+ GlSprintf,
},
mixins: [glFeatureFlagsMixin()],
props: {
@@ -60,6 +57,7 @@ export default {
selectedTemplate: this.initialSelectedTemplate,
outgoingName: this.initialOutgoingName || __('GitLab Support Bot'),
projectKey: this.initialProjectKey,
+ baseEmail: this.incomingEmail.replace(this.initialProjectKey, ''),
};
},
computed: {
@@ -108,7 +106,7 @@ export default {
<input
ref="service-desk-incoming-email"
type="text"
- class="form-control incoming-email h-auto"
+ class="form-control incoming-email"
:placeholder="__('Incoming email')"
:aria-label="__('Incoming email')"
aria-describedby="incoming-email-describer"
@@ -119,16 +117,37 @@ export default {
<clipboard-button
:title="__('Copy')"
:text="incomingEmail"
- css-class="btn qa-clipboard-button"
+ css-class="input-group-text qa-clipboard-button"
/>
</div>
</div>
+ <span v-if="projectKey" class="form-text text-muted">
+ <gl-sprintf :message="__('Emails sent to %{email} will still be supported')">
+ <template #email>
+ <code>{{ baseEmail }}</code>
+ </template>
+ </gl-sprintf>
+ </span>
</template>
<template v-else>
<gl-loading-icon :inline="true" />
<span class="sr-only">{{ __('Fetching incoming email') }}</span>
</template>
+ <template v-if="hasProjectKeySupport">
+ <label for="service-desk-project-suffix" class="mt-3">
+ {{ __('Project name suffix') }}
+ </label>
+ <input id="service-desk-project-suffix" v-model.trim="projectKey" class="form-control" />
+ <span class="form-text text-muted">
+ {{
+ __(
+ 'Project name suffix is a user-defined string which will be appended to the project path, and will form the Service Desk email address.',
+ )
+ }}
+ </span>
+ </template>
+
<label for="service-desk-template-select" class="mt-3">
{{ __('Template to append to all Service Desk issues') }}
</label>
@@ -144,19 +163,6 @@ export default {
<span class="form-text text-muted">
{{ __('Emails sent from Service Desk will have this name') }}
</span>
- <template v-if="hasProjectKeySupport">
- <label for="service-desk-project-suffix" class="mt-3">
- {{ __('Project name suffix') }}
- </label>
- <input id="service-desk-project-suffix" v-model.trim="projectKey" class="form-control" />
- <span class="form-text text-muted mb-3">
- {{
- __(
- 'Project name suffix is a user-defined string which will be appended to the project path, and will form the Service Desk email address.',
- )
- }}
- </span>
- </template>
<div class="gl-display-flex gl-justify-content-end">
<gl-button
variant="success"
diff --git a/app/assets/javascripts/projects/tree/components/commit_pipeline_status_component.vue b/app/assets/javascripts/projects/tree/components/commit_pipeline_status_component.vue
index e691f675e59..e582d5c3e47 100644
--- a/app/assets/javascripts/projects/tree/components/commit_pipeline_status_component.vue
+++ b/app/assets/javascripts/projects/tree/components/commit_pipeline_status_component.vue
@@ -1,16 +1,15 @@
<script>
import Visibility from 'visibilityjs';
-import { GlLoadingIcon } from '@gitlab/ui';
+import { GlLoadingIcon, GlTooltipDirective } from '@gitlab/ui';
import ciIcon from '~/vue_shared/components/ci_icon.vue';
import Poll from '~/lib/utils/poll';
import { deprecatedCreateFlash as Flash } from '~/flash';
import { __, s__, sprintf } from '~/locale';
-import tooltip from '~/vue_shared/directives/tooltip';
import CommitPipelineService from '../services/commit_pipeline_service';
export default {
directives: {
- tooltip,
+ GlTooltip: GlTooltipDirective,
},
components: {
ciIcon,
@@ -97,7 +96,7 @@ export default {
<gl-loading-icon v-if="isLoading" size="lg" label="Loading pipeline status" />
<a v-else :href="ciStatus.details_path">
<ci-icon
- v-tooltip
+ v-gl-tooltip
:title="statusTitle"
:aria-label="statusTitle"
:status="ciStatus"
diff --git a/app/assets/javascripts/protected_branches/constants.js b/app/assets/javascripts/protected_branches/constants.js
index a17ae6811b7..ae5eaa8e622 100644
--- a/app/assets/javascripts/protected_branches/constants.js
+++ b/app/assets/javascripts/protected_branches/constants.js
@@ -7,12 +7,14 @@ export const LEVEL_TYPES = {
ROLE: 'role',
USER: 'user',
GROUP: 'group',
+ DEPLOY_KEY: 'deploy_key',
};
export const LEVEL_ID_PROP = {
ROLE: 'access_level',
USER: 'user_id',
GROUP: 'group_id',
+ DEPLOY_KEY: 'deploy_key_id',
};
export const ACCESS_LEVEL_NONE = 0;
diff --git a/app/assets/javascripts/protected_branches/protected_branch_create.js b/app/assets/javascripts/protected_branches/protected_branch_create.js
index 5ccffe9700e..19f6666fd52 100644
--- a/app/assets/javascripts/protected_branches/protected_branch_create.js
+++ b/app/assets/javascripts/protected_branches/protected_branch_create.js
@@ -108,6 +108,10 @@ export default class ProtectedBranchCreate {
levelAttributes.push({
group_id: item.group_id,
});
+ } else if (item.type === LEVEL_TYPES.DEPLOY_KEY) {
+ levelAttributes.push({
+ deploy_key_id: item.deploy_key_id,
+ });
}
});
diff --git a/app/assets/javascripts/ref/components/ref_selector.vue b/app/assets/javascripts/ref/components/ref_selector.vue
index 85b123530b5..0084450c9b0 100644
--- a/app/assets/javascripts/ref/components/ref_selector.vue
+++ b/app/assets/javascripts/ref/components/ref_selector.vue
@@ -139,7 +139,6 @@ export default {
<gl-search-box-by-type
ref="searchBox"
v-model.trim="query"
- class="gl-m-3"
:placeholder="i18n.searchPlaceholder"
@input="onSearchBoxInput"
@keydown.enter.prevent="onSearchBoxEnter"
diff --git a/app/assets/javascripts/registry/explorer/components/details_page/partial_cleanup_alert.vue b/app/assets/javascripts/registry/explorer/components/details_page/partial_cleanup_alert.vue
new file mode 100644
index 00000000000..d13d815a59e
--- /dev/null
+++ b/app/assets/javascripts/registry/explorer/components/details_page/partial_cleanup_alert.vue
@@ -0,0 +1,38 @@
+<script>
+import { GlSprintf, GlAlert, GlLink } from '@gitlab/ui';
+
+import { DELETE_ALERT_TITLE, DELETE_ALERT_LINK_TEXT } from '../../constants/index';
+
+export default {
+ components: {
+ GlSprintf,
+ GlAlert,
+ GlLink,
+ },
+ props: {
+ runCleanupPoliciesHelpPagePath: { type: String, required: false, default: '' },
+ cleanupPoliciesHelpPagePath: { type: String, required: false, default: '' },
+ },
+ i18n: {
+ DELETE_ALERT_TITLE,
+ DELETE_ALERT_LINK_TEXT,
+ },
+};
+</script>
+
+<template>
+ <gl-alert variant="warning" :title="$options.i18n.DELETE_ALERT_TITLE" @dismiss="$emit('dismiss')">
+ <gl-sprintf :message="$options.i18n.DELETE_ALERT_LINK_TEXT">
+ <template #adminLink="{content}">
+ <gl-link data-testid="run-link" :href="runCleanupPoliciesHelpPagePath" target="_blank">{{
+ content
+ }}</gl-link>
+ </template>
+ <template #docLink="{content}">
+ <gl-link data-testid="help-link" :href="cleanupPoliciesHelpPagePath" target="_blank">{{
+ content
+ }}</gl-link>
+ </template>
+ </gl-sprintf>
+ </gl-alert>
+</template>
diff --git a/app/assets/javascripts/registry/explorer/components/details_page/tags_list_row.vue b/app/assets/javascripts/registry/explorer/components/details_page/tags_list_row.vue
index 661213733ac..0f6297ca406 100644
--- a/app/assets/javascripts/registry/explorer/components/details_page/tags_list_row.vue
+++ b/app/assets/javascripts/registry/explorer/components/details_page/tags_list_row.vue
@@ -123,7 +123,7 @@ export default {
v-if="tag.location"
:title="tag.location"
:text="tag.location"
- css-class="btn-default btn-transparent btn-clipboard"
+ category="tertiary"
/>
<gl-icon
@@ -171,7 +171,7 @@ export default {
/>
</template>
- <template v-if="!invalidTag" #details_published>
+ <template v-if="!invalidTag" #details-published>
<details-row icon="clock" data-testid="published-date-detail">
<gl-sprintf :message="$options.i18n.PUBLISHED_DETAILS_ROW_TEXT">
<template #repositoryPath>
@@ -186,7 +186,7 @@ export default {
</gl-sprintf>
</details-row>
</template>
- <template v-if="!invalidTag" #details_manifest_digest>
+ <template v-if="!invalidTag" #details-manifest-digest>
<details-row icon="log" data-testid="manifest-detail">
<gl-sprintf :message="$options.i18n.MANIFEST_DETAILS_ROW_TEST">
<template #digest>
@@ -197,11 +197,12 @@ export default {
v-if="tag.digest"
:title="tag.digest"
:text="tag.digest"
- css-class="btn-default btn-transparent btn-clipboard gl-p-0"
+ category="tertiary"
+ size="small"
/>
</details-row>
</template>
- <template v-if="!invalidTag" #details_configuration_digest>
+ <template v-if="!invalidTag" #details-configuration-digest>
<details-row icon="cloud-gear" data-testid="configuration-detail">
<gl-sprintf :message="$options.i18n.CONFIGURATION_DETAILS_ROW_TEST">
<template #digest>
@@ -212,7 +213,8 @@ export default {
v-if="formattedRevision"
:title="formattedRevision"
:text="formattedRevision"
- css-class="btn-default btn-transparent btn-clipboard gl-p-0"
+ category="tertiary"
+ size="small"
/>
</details-row>
</template>
diff --git a/app/assets/javascripts/registry/explorer/components/list_page/image_list_row.vue b/app/assets/javascripts/registry/explorer/components/list_page/image_list_row.vue
index 32bf27f1143..cfd787b3f52 100644
--- a/app/assets/javascripts/registry/explorer/components/list_page/image_list_row.vue
+++ b/app/assets/javascripts/registry/explorer/components/list_page/image_list_row.vue
@@ -10,6 +10,7 @@ import {
LIST_DELETE_BUTTON_DISABLED,
REMOVE_REPOSITORY_LABEL,
ROW_SCHEDULED_FOR_DELETION,
+ CLEANUP_TIMED_OUT_ERROR_MESSAGE,
} from '../../constants/index';
export default {
@@ -34,7 +35,6 @@ export default {
LIST_DELETE_BUTTON_DISABLED,
REMOVE_REPOSITORY_LABEL,
ROW_SCHEDULED_FOR_DELETION,
- ASYNC_DELETE_IMAGE_ERROR_MESSAGE,
},
computed: {
encodedItem() {
@@ -42,6 +42,7 @@ export default {
name: this.item.path,
tags_path: this.item.tags_path,
id: this.item.id,
+ cleanup_policy_started_at: this.item.cleanup_policy_started_at,
});
return window.btoa(params);
},
@@ -55,6 +56,14 @@ export default {
this.item.tags_count,
);
},
+ warningIconText() {
+ if (this.item.failedDelete) {
+ return ASYNC_DELETE_IMAGE_ERROR_MESSAGE;
+ } else if (this.item.cleanup_policy_started_at) {
+ return CLEANUP_TIMED_OUT_ERROR_MESSAGE;
+ }
+ return null;
+ },
},
};
</script>
@@ -82,11 +91,12 @@ export default {
:disabled="item.deleting"
:text="item.location"
:title="item.location"
- css-class="btn-default btn-transparent btn-clipboard gl-text-gray-300"
+ category="tertiary"
/>
<gl-icon
- v-if="item.failedDelete"
- v-gl-tooltip="{ title: $options.i18n.ASYNC_DELETE_IMAGE_ERROR_MESSAGE }"
+ v-if="warningIconText"
+ v-gl-tooltip="{ title: warningIconText }"
+ data-testid="warning-icon"
name="warning"
class="gl-text-orange-500"
/>
diff --git a/app/assets/javascripts/registry/explorer/components/list_page/registry_header.vue b/app/assets/javascripts/registry/explorer/components/list_page/registry_header.vue
index 7be68e77def..c2bd01701df 100644
--- a/app/assets/javascripts/registry/explorer/components/list_page/registry_header.vue
+++ b/app/assets/javascripts/registry/explorer/components/list_page/registry_header.vue
@@ -1,5 +1,4 @@
<script>
-import { GlSprintf, GlLink } from '@gitlab/ui';
import TitleArea from '~/vue_shared/components/registry/title_area.vue';
import MetadataItem from '~/vue_shared/components/registry/metadata_item.vue';
import { n__, sprintf } from '~/locale';
@@ -15,8 +14,6 @@ import {
export default {
components: {
- GlSprintf,
- GlLink,
TitleArea,
MetadataItem,
},
@@ -54,8 +51,6 @@ export default {
},
i18n: {
CONTAINER_REGISTRY_TITLE,
- LIST_INTRO_TEXT,
- EXPIRATION_POLICY_DISABLED_MESSAGE,
},
computed: {
imagesCountText() {
@@ -83,52 +78,40 @@ export default {
!this.expirationPolicyEnabled && this.imagesCount > 0 && !this.hideExpirationPolicyData
);
},
+ infoMessages() {
+ const base = [{ text: LIST_INTRO_TEXT, link: this.helpPagePath }];
+ return this.showExpirationPolicyTip
+ ? [
+ ...base,
+ { text: EXPIRATION_POLICY_DISABLED_MESSAGE, link: this.expirationPolicyHelpPagePath },
+ ]
+ : base;
+ },
},
};
</script>
<template>
- <div>
- <title-area :title="$options.i18n.CONTAINER_REGISTRY_TITLE">
- <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>
- <template #metadata_exp_policies>
- <metadata-item
- v-if="!hideExpirationPolicyData"
- data-testid="expiration-policy"
- icon="expire"
- :text="expirationPolicyText"
- size="xl"
- />
- </template>
- </title-area>
-
- <div data-testid="info-area">
- <p>
- <span data-testid="default-intro">
- <gl-sprintf :message="$options.i18n.LIST_INTRO_TEXT">
- <template #docLink="{content}">
- <gl-link :href="helpPagePath" target="_blank">{{ content }}</gl-link>
- </template>
- </gl-sprintf>
- </span>
- <span v-if="showExpirationPolicyTip" data-testid="expiration-disabled-message">
- <gl-sprintf :message="$options.i18n.EXPIRATION_POLICY_DISABLED_MESSAGE">
- <template #docLink="{content}">
- <gl-link :href="expirationPolicyHelpPagePath" target="_blank">{{ content }}</gl-link>
- </template>
- </gl-sprintf>
- </span>
- </p>
- </div>
- </div>
+ <title-area :title="$options.i18n.CONTAINER_REGISTRY_TITLE" :info-messages="infoMessages">
+ <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>
+ <template #metadata-exp-policies>
+ <metadata-item
+ v-if="!hideExpirationPolicyData"
+ data-testid="expiration-policy"
+ icon="expire"
+ :text="expirationPolicyText"
+ size="xl"
+ />
+ </template>
+ </title-area>
</template>
diff --git a/app/assets/javascripts/registry/explorer/constants/expiration_policies.js b/app/assets/javascripts/registry/explorer/constants/expiration_policies.js
index 8af25ca6ecc..48a6a015461 100644
--- a/app/assets/javascripts/registry/explorer/constants/expiration_policies.js
+++ b/app/assets/javascripts/registry/explorer/constants/expiration_policies.js
@@ -9,3 +9,10 @@ export const EXPIRATION_POLICY_DISABLED_TEXT = s__(
export const EXPIRATION_POLICY_DISABLED_MESSAGE = s__(
'ContainerRegistry|Expiration policies help manage the storage space used by the Container Registry, but the expiration policies for this registry are disabled. Contact your administrator to enable. %{docLinkStart}More information%{docLinkEnd}',
);
+export const DELETE_ALERT_TITLE = s__('ContainerRegistry|Some tags were not deleted');
+export const DELETE_ALERT_LINK_TEXT = s__(
+ 'ContainerRegistry|The cleanup policy timed out before it could delete all tags. An administrator can %{adminLinkStart}manually run cleanup now%{adminLinkEnd} or you can wait for the cleanup policy to automatically run again. %{docLinkStart}More information%{docLinkEnd}',
+);
+export const CLEANUP_TIMED_OUT_ERROR_MESSAGE = s__(
+ 'ContainerRegistry|Cleanup timed out before it could delete all tags',
+);
diff --git a/app/assets/javascripts/registry/explorer/pages/details.vue b/app/assets/javascripts/registry/explorer/pages/details.vue
index b697bca6259..d2fb695dbfa 100644
--- a/app/assets/javascripts/registry/explorer/pages/details.vue
+++ b/app/assets/javascripts/registry/explorer/pages/details.vue
@@ -4,6 +4,7 @@ import { GlPagination, GlResizeObserverDirective } from '@gitlab/ui';
import { GlBreakpointInstance } from '@gitlab/ui/dist/utils';
import Tracking from '~/tracking';
import DeleteAlert from '../components/details_page/delete_alert.vue';
+import PartialCleanupAlert from '../components/details_page/partial_cleanup_alert.vue';
import DeleteModal from '../components/details_page/delete_modal.vue';
import DetailsHeader from '../components/details_page/details_header.vue';
import TagsList from '../components/details_page/tags_list.vue';
@@ -21,6 +22,7 @@ import {
export default {
components: {
DeleteAlert,
+ PartialCleanupAlert,
DetailsHeader,
GlPagination,
DeleteModal,
@@ -37,13 +39,16 @@ export default {
itemsToBeDeleted: [],
isDesktop: true,
deleteAlertType: null,
+ dismissPartialCleanupWarning: false,
};
},
computed: {
...mapState(['tagsPagination', 'isLoading', 'config', 'tags']),
- imageName() {
- const { name } = decodeAndParse(this.$route.params.id);
- return name;
+ queryParameters() {
+ return decodeAndParse(this.$route.params.id);
+ },
+ showPartialCleanupWarning() {
+ return this.queryParameters.cleanup_policy_started_at && !this.dismissPartialCleanupWarning;
},
tracking() {
return {
@@ -120,7 +125,14 @@ export default {
class="gl-my-2"
/>
- <details-header :image-name="imageName" />
+ <partial-cleanup-alert
+ v-if="showPartialCleanupWarning"
+ :run-cleanup-policies-help-page-path="config.runCleanupPoliciesHelpPagePath"
+ :cleanup-policies-help-page-path="config.cleanupPoliciesHelpPagePath"
+ @dismiss="dismissPartialCleanupWarning = true"
+ />
+
+ <details-header :image-name="queryParameters.name" />
<tags-loader v-if="isLoading" />
<template v-else>
diff --git a/app/assets/javascripts/registry/settings/components/registry_settings_app.vue b/app/assets/javascripts/registry/settings/components/registry_settings_app.vue
index 2ee7bbef4c6..264d39a406a 100644
--- a/app/assets/javascripts/registry/settings/components/registry_settings_app.vue
+++ b/app/assets/javascripts/registry/settings/components/registry_settings_app.vue
@@ -1,7 +1,7 @@
<script>
-import { mapActions, mapGetters, mapState } from 'vuex';
import { GlAlert, GlSprintf, GlLink } from '@gitlab/ui';
-
+import { isEqual, get } from 'lodash';
+import expirationPolicyQuery from '../graphql/queries/get_expiration_policy.graphql';
import { FETCH_SETTINGS_ERROR_MESSAGE } from '../../shared/constants';
import SettingsForm from './settings_form.vue';
@@ -19,21 +19,39 @@ export default {
GlSprintf,
GlLink,
},
+ inject: ['projectPath', 'isAdmin', 'adminSettingsPath', 'enableHistoricEntries'],
i18n: {
UNAVAILABLE_FEATURE_TITLE,
UNAVAILABLE_FEATURE_INTRO_TEXT,
FETCH_SETTINGS_ERROR_MESSAGE,
},
+ apollo: {
+ containerExpirationPolicy: {
+ query: expirationPolicyQuery,
+ variables() {
+ return {
+ projectPath: this.projectPath,
+ };
+ },
+ update: data => data.project?.containerExpirationPolicy,
+ result({ data }) {
+ this.workingCopy = { ...get(data, 'project.containerExpirationPolicy', {}) };
+ },
+ error(e) {
+ this.fetchSettingsError = e;
+ },
+ },
+ },
data() {
return {
fetchSettingsError: false,
+ containerExpirationPolicy: null,
+ workingCopy: {},
};
},
computed: {
- ...mapState(['isAdmin', 'adminSettingsPath']),
- ...mapGetters({ isDisabled: 'getIsDisabled' }),
- showSettingForm() {
- return !this.isDisabled && !this.fetchSettingsError;
+ isDisabled() {
+ return !(this.containerExpirationPolicy || this.enableHistoricEntries);
},
showDisabledFormMessage() {
return this.isDisabled && !this.fetchSettingsError;
@@ -41,21 +59,27 @@ export default {
unavailableFeatureMessage() {
return this.isAdmin ? UNAVAILABLE_ADMIN_FEATURE_TEXT : UNAVAILABLE_USER_FEATURE_TEXT;
},
- },
- mounted() {
- this.fetchSettings().catch(() => {
- this.fetchSettingsError = true;
- });
+ isEdited() {
+ return !isEqual(this.containerExpirationPolicy, this.workingCopy);
+ },
},
methods: {
- ...mapActions(['fetchSettings']),
+ restoreOriginal() {
+ this.workingCopy = { ...this.containerExpirationPolicy };
+ },
},
};
</script>
<template>
<div>
- <settings-form v-if="showSettingForm" />
+ <settings-form
+ v-if="!isDisabled"
+ v-model="workingCopy"
+ :is-loading="$apollo.queries.containerExpirationPolicy.loading"
+ :is-edited="isEdited"
+ @reset="restoreOriginal"
+ />
<template v-else>
<gl-alert
v-if="showDisabledFormMessage"
diff --git a/app/assets/javascripts/registry/settings/components/settings_form.vue b/app/assets/javascripts/registry/settings/components/settings_form.vue
index 7a26fb5cbee..a9b35d4e29f 100644
--- a/app/assets/javascripts/registry/settings/components/settings_form.vue
+++ b/app/assets/javascripts/registry/settings/components/settings_form.vue
@@ -1,28 +1,45 @@
<script>
-import { get } from 'lodash';
-import { mapActions, mapState, mapGetters } from 'vuex';
-import { GlCard, GlButton, GlLoadingIcon } from '@gitlab/ui';
+import { GlCard, GlButton } from '@gitlab/ui';
import Tracking from '~/tracking';
-import { mapComputed } from '~/vuex_shared/bindings';
import {
UPDATE_SETTINGS_ERROR_MESSAGE,
UPDATE_SETTINGS_SUCCESS_MESSAGE,
} from '../../shared/constants';
import ExpirationPolicyFields from '../../shared/components/expiration_policy_fields.vue';
import { SET_CLEANUP_POLICY_BUTTON, CLEANUP_POLICY_CARD_HEADER } from '../constants';
+import { formOptionsGenerator } from '~/registry/shared/utils';
+import updateContainerExpirationPolicyMutation from '../graphql/mutations/update_container_expiration_policy.graphql';
+import { updateContainerExpirationPolicy } from '../graphql/utils/cache_update';
export default {
components: {
GlCard,
GlButton,
- GlLoadingIcon,
ExpirationPolicyFields,
},
mixins: [Tracking.mixin()],
+ inject: ['projectPath'],
+ props: {
+ value: {
+ type: Object,
+ required: true,
+ },
+ isLoading: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ isEdited: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ },
labelsConfig: {
cols: 3,
align: 'right',
},
+ formOptions: formOptionsGenerator(),
i18n: {
CLEANUP_POLICY_CARD_HEADER,
SET_CLEANUP_POLICY_BUTTON,
@@ -34,49 +51,85 @@ export default {
},
fieldsAreValid: true,
apiErrors: null,
+ mutationLoading: false,
};
},
computed: {
- ...mapState(['formOptions', 'isLoading']),
- ...mapGetters({ isEdited: 'getIsEdited' }),
- ...mapComputed([{ key: 'settings', getter: 'getSettings' }], 'updateSettings'),
+ prefilledForm() {
+ return {
+ ...this.value,
+ cadence: this.findDefaultOption('cadence'),
+ keepN: this.findDefaultOption('keepN'),
+ olderThan: this.findDefaultOption('olderThan'),
+ };
+ },
+ showLoadingIcon() {
+ return this.isLoading || this.mutationLoading;
+ },
isSubmitButtonDisabled() {
- return !this.fieldsAreValid || this.isLoading;
+ return !this.fieldsAreValid || this.showLoadingIcon;
},
isCancelButtonDisabled() {
- return !this.isEdited || this.isLoading;
+ return !this.isEdited || this.isLoading || this.mutationLoading;
+ },
+ mutationVariables() {
+ return {
+ projectPath: this.projectPath,
+ enabled: this.value.enabled,
+ cadence: this.value.cadence,
+ olderThan: this.value.olderThan,
+ keepN: this.value.keepN,
+ nameRegex: this.value.nameRegex,
+ nameRegexKeep: this.value.nameRegexKeep,
+ };
},
},
methods: {
- ...mapActions(['resetSettings', 'saveSettings']),
+ findDefaultOption(option) {
+ return this.value[option] || this.$options.formOptions[option].find(f => f.default)?.key;
+ },
reset() {
this.track('reset_form');
this.apiErrors = null;
- this.resetSettings();
+ this.$emit('reset');
},
setApiErrors(response) {
- const messages = get(response, 'data.message', []);
-
- this.apiErrors = Object.keys(messages).reduce((acc, curr) => {
- if (curr.startsWith('container_expiration_policy.')) {
- const key = curr.replace('container_expiration_policy.', '');
- acc[key] = get(messages, [curr, 0], '');
- }
+ this.apiErrors = response.graphQLErrors.reduce((acc, curr) => {
+ curr.extensions.problems.forEach(item => {
+ acc[item.path[0]] = item.message;
+ });
return acc;
}, {});
},
submit() {
this.track('submit_form');
this.apiErrors = null;
- this.saveSettings()
- .then(() => this.$toast.show(UPDATE_SETTINGS_SUCCESS_MESSAGE, { type: 'success' }))
- .catch(({ response }) => {
- this.setApiErrors(response);
+ this.mutationLoading = true;
+ return this.$apollo
+ .mutate({
+ mutation: updateContainerExpirationPolicyMutation,
+ variables: {
+ input: this.mutationVariables,
+ },
+ update: updateContainerExpirationPolicy(this.projectPath),
+ })
+ .then(({ data }) => {
+ const errorMessage = data?.updateContainerExpirationPolicy?.errors[0];
+ if (errorMessage) {
+ this.$toast.show(errorMessage, { type: 'error' });
+ }
+ this.$toast.show(UPDATE_SETTINGS_SUCCESS_MESSAGE, { type: 'success' });
+ })
+ .catch(error => {
+ this.setApiErrors(error);
this.$toast.show(UPDATE_SETTINGS_ERROR_MESSAGE, { type: 'error' });
+ })
+ .finally(() => {
+ this.mutationLoading = false;
});
},
onModelChange(changePayload) {
- this.settings = changePayload.newValue;
+ this.$emit('input', changePayload.newValue);
if (this.apiErrors) {
this.apiErrors[changePayload.modified] = undefined;
}
@@ -93,8 +146,8 @@ export default {
</template>
<template #default>
<expiration-policy-fields
- :value="settings"
- :form-options="formOptions"
+ :value="prefilledForm"
+ :form-options="$options.formOptions"
:is-loading="isLoading"
:api-errors="apiErrors"
@validated="fieldsAreValid = true"
@@ -103,27 +156,25 @@ export default {
/>
</template>
<template #footer>
- <div class="gl-display-flex gl-justify-content-end">
- <gl-button
- ref="cancel-button"
- type="reset"
- class="gl-mr-3 gl-display-block"
- :disabled="isCancelButtonDisabled"
- >
- {{ __('Cancel') }}
- </gl-button>
- <gl-button
- ref="save-button"
- type="submit"
- :disabled="isSubmitButtonDisabled"
- variant="success"
- category="primary"
- class="gl-display-flex gl-justify-content-center gl-align-items-center js-no-auto-disable"
- >
- {{ $options.i18n.SET_CLEANUP_POLICY_BUTTON }}
- <gl-loading-icon v-if="isLoading" class="gl-ml-3" />
- </gl-button>
- </div>
+ <gl-button
+ ref="cancel-button"
+ type="reset"
+ class="gl-mr-3 gl-display-block float-right"
+ :disabled="isCancelButtonDisabled"
+ >
+ {{ __('Cancel') }}
+ </gl-button>
+ <gl-button
+ ref="save-button"
+ type="submit"
+ :disabled="isSubmitButtonDisabled"
+ :loading="showLoadingIcon"
+ variant="success"
+ category="primary"
+ class="js-no-auto-disable"
+ >
+ {{ $options.i18n.SET_CLEANUP_POLICY_BUTTON }}
+ </gl-button>
</template>
</gl-card>
</form>
diff --git a/app/assets/javascripts/registry/settings/graphql/fragments/container_expiration_policy.fragment.graphql b/app/assets/javascripts/registry/settings/graphql/fragments/container_expiration_policy.fragment.graphql
new file mode 100644
index 00000000000..224e0ed9472
--- /dev/null
+++ b/app/assets/javascripts/registry/settings/graphql/fragments/container_expiration_policy.fragment.graphql
@@ -0,0 +1,8 @@
+fragment ContainerExpirationPolicyFields on ContainerExpirationPolicy {
+ cadence
+ enabled
+ keepN
+ nameRegex
+ nameRegexKeep
+ olderThan
+}
diff --git a/app/assets/javascripts/registry/settings/graphql/index.js b/app/assets/javascripts/registry/settings/graphql/index.js
new file mode 100644
index 00000000000..16152eb81f6
--- /dev/null
+++ b/app/assets/javascripts/registry/settings/graphql/index.js
@@ -0,0 +1,14 @@
+import Vue from 'vue';
+import VueApollo from 'vue-apollo';
+import createDefaultClient from '~/lib/graphql';
+
+Vue.use(VueApollo);
+
+export const apolloProvider = new VueApollo({
+ defaultClient: createDefaultClient(
+ {},
+ {
+ assumeImmutableResults: true,
+ },
+ ),
+});
diff --git a/app/assets/javascripts/registry/settings/graphql/mutations/update_container_expiration_policy.graphql b/app/assets/javascripts/registry/settings/graphql/mutations/update_container_expiration_policy.graphql
new file mode 100644
index 00000000000..c40cd115ab0
--- /dev/null
+++ b/app/assets/javascripts/registry/settings/graphql/mutations/update_container_expiration_policy.graphql
@@ -0,0 +1,10 @@
+#import "../fragments/container_expiration_policy.fragment.graphql"
+
+mutation updateContainerExpirationPolicy($input: UpdateContainerExpirationPolicyInput!) {
+ updateContainerExpirationPolicy(input: $input) {
+ containerExpirationPolicy {
+ ...ContainerExpirationPolicyFields
+ }
+ errors
+ }
+}
diff --git a/app/assets/javascripts/registry/settings/graphql/queries/get_expiration_policy.graphql b/app/assets/javascripts/registry/settings/graphql/queries/get_expiration_policy.graphql
new file mode 100644
index 00000000000..c171be0ad07
--- /dev/null
+++ b/app/assets/javascripts/registry/settings/graphql/queries/get_expiration_policy.graphql
@@ -0,0 +1,9 @@
+#import "../fragments/container_expiration_policy.fragment.graphql"
+
+query getProjectExpirationPolicy($projectPath: ID!) {
+ project(fullPath: $projectPath) {
+ containerExpirationPolicy {
+ ...ContainerExpirationPolicyFields
+ }
+ }
+}
diff --git a/app/assets/javascripts/registry/settings/graphql/utils/cache_update.js b/app/assets/javascripts/registry/settings/graphql/utils/cache_update.js
new file mode 100644
index 00000000000..88067d52b51
--- /dev/null
+++ b/app/assets/javascripts/registry/settings/graphql/utils/cache_update.js
@@ -0,0 +1,22 @@
+import { produce } from 'immer';
+import expirationPolicyQuery from '../queries/get_expiration_policy.graphql';
+
+export const updateContainerExpirationPolicy = projectPath => (client, { data: updatedData }) => {
+ const queryAndParams = {
+ query: expirationPolicyQuery,
+ variables: { projectPath },
+ };
+ const sourceData = client.readQuery(queryAndParams);
+
+ const data = produce(sourceData, draftState => {
+ // eslint-disable-next-line no-param-reassign
+ draftState.project.containerExpirationPolicy = {
+ ...updatedData.updateContainerExpirationPolicy.containerExpirationPolicy,
+ };
+ });
+
+ client.writeQuery({
+ ...queryAndParams,
+ data,
+ });
+};
diff --git a/app/assets/javascripts/registry/settings/registry_settings_bundle.js b/app/assets/javascripts/registry/settings/registry_settings_bundle.js
index a318aa2a694..f7b1c5abd3a 100644
--- a/app/assets/javascripts/registry/settings/registry_settings_bundle.js
+++ b/app/assets/javascripts/registry/settings/registry_settings_bundle.js
@@ -1,8 +1,9 @@
import Vue from 'vue';
import { GlToast } from '@gitlab/ui';
import Translate from '~/vue_shared/translate';
-import store from './store';
+import { parseBoolean } from '~/lib/utils/common_utils';
import RegistrySettingsApp from './components/registry_settings_app.vue';
+import { apolloProvider } from './graphql/index';
Vue.use(GlToast);
Vue.use(Translate);
@@ -12,13 +13,19 @@ export default () => {
if (!el) {
return null;
}
- store.dispatch('setInitialState', el.dataset);
+ const { projectPath, isAdmin, adminSettingsPath, enableHistoricEntries } = el.dataset;
return new Vue({
el,
- store,
+ apolloProvider,
components: {
RegistrySettingsApp,
},
+ provide: {
+ projectPath,
+ isAdmin: parseBoolean(isAdmin),
+ adminSettingsPath,
+ enableHistoricEntries: parseBoolean(enableHistoricEntries),
+ },
render(createElement) {
return createElement('registry-settings-app', {});
},
diff --git a/app/assets/javascripts/registry/settings/store/actions.js b/app/assets/javascripts/registry/settings/store/actions.js
deleted file mode 100644
index 0530a870ecc..00000000000
--- a/app/assets/javascripts/registry/settings/store/actions.js
+++ /dev/null
@@ -1,30 +0,0 @@
-import Api from '~/api';
-import * as types from './mutation_types';
-
-export const setInitialState = ({ commit }, data) => commit(types.SET_INITIAL_STATE, data);
-export const updateSettings = ({ commit }, data) => commit(types.UPDATE_SETTINGS, data);
-export const toggleLoading = ({ commit }) => commit(types.TOGGLE_LOADING);
-export const receiveSettingsSuccess = ({ commit }, data) => {
- commit(types.SET_SETTINGS, data);
-};
-export const resetSettings = ({ commit }) => commit(types.RESET_SETTINGS);
-
-export const fetchSettings = ({ dispatch, state }) => {
- dispatch('toggleLoading');
- return Api.project(state.projectId)
- .then(({ data: { container_expiration_policy } }) =>
- dispatch('receiveSettingsSuccess', container_expiration_policy),
- )
- .finally(() => dispatch('toggleLoading'));
-};
-
-export const saveSettings = ({ dispatch, state }) => {
- dispatch('toggleLoading');
- return Api.updateProject(state.projectId, {
- container_expiration_policy_attributes: state.settings,
- })
- .then(({ data: { container_expiration_policy } }) =>
- dispatch('receiveSettingsSuccess', container_expiration_policy),
- )
- .finally(() => dispatch('toggleLoading'));
-};
diff --git a/app/assets/javascripts/registry/settings/store/getters.js b/app/assets/javascripts/registry/settings/store/getters.js
deleted file mode 100644
index ac1a931d8e0..00000000000
--- a/app/assets/javascripts/registry/settings/store/getters.js
+++ /dev/null
@@ -1,26 +0,0 @@
-import { isEqual } from 'lodash';
-import { findDefaultOption } from '../../shared/utils';
-
-export const getCadence = state =>
- state.settings.cadence || findDefaultOption(state.formOptions.cadence);
-
-export const getKeepN = state =>
- state.settings.keep_n || findDefaultOption(state.formOptions.keepN);
-
-export const getOlderThan = state =>
- state.settings.older_than || findDefaultOption(state.formOptions.olderThan);
-
-export const getSettings = (state, getters) => ({
- enabled: state.settings.enabled,
- cadence: getters.getCadence,
- older_than: getters.getOlderThan,
- keep_n: getters.getKeepN,
- name_regex: state.settings.name_regex,
- name_regex_keep: state.settings.name_regex_keep,
-});
-
-export const getIsEdited = state => !isEqual(state.original, state.settings);
-
-export const getIsDisabled = state => {
- return !(state.original || state.enableHistoricEntries);
-};
diff --git a/app/assets/javascripts/registry/settings/store/index.js b/app/assets/javascripts/registry/settings/store/index.js
deleted file mode 100644
index c2500454d8e..00000000000
--- a/app/assets/javascripts/registry/settings/store/index.js
+++ /dev/null
@@ -1,18 +0,0 @@
-import Vue from 'vue';
-import Vuex from 'vuex';
-import * as actions from './actions';
-import mutations from './mutations';
-import * as getters from './getters';
-import state from './state';
-
-Vue.use(Vuex);
-
-export const createStore = () =>
- new Vuex.Store({
- state,
- actions,
- mutations,
- getters,
- });
-
-export default createStore();
diff --git a/app/assets/javascripts/registry/settings/store/mutation_types.js b/app/assets/javascripts/registry/settings/store/mutation_types.js
deleted file mode 100644
index db499ffa761..00000000000
--- a/app/assets/javascripts/registry/settings/store/mutation_types.js
+++ /dev/null
@@ -1,5 +0,0 @@
-export const SET_INITIAL_STATE = 'SET_INITIAL_STATE';
-export const UPDATE_SETTINGS = 'UPDATE_SETTINGS';
-export const TOGGLE_LOADING = 'TOGGLE_LOADING';
-export const SET_SETTINGS = 'SET_SETTINGS';
-export const RESET_SETTINGS = 'RESET_SETTINGS';
diff --git a/app/assets/javascripts/registry/settings/store/mutations.js b/app/assets/javascripts/registry/settings/store/mutations.js
deleted file mode 100644
index 3ba13419b98..00000000000
--- a/app/assets/javascripts/registry/settings/store/mutations.js
+++ /dev/null
@@ -1,29 +0,0 @@
-import { parseBoolean } from '~/lib/utils/common_utils';
-import * as types from './mutation_types';
-
-export default {
- [types.SET_INITIAL_STATE](state, initialState) {
- state.projectId = initialState.projectId;
- state.formOptions = {
- cadence: JSON.parse(initialState.cadenceOptions),
- keepN: JSON.parse(initialState.keepNOptions),
- olderThan: JSON.parse(initialState.olderThanOptions),
- };
- state.enableHistoricEntries = parseBoolean(initialState.enableHistoricEntries);
- state.isAdmin = parseBoolean(initialState.isAdmin);
- state.adminSettingsPath = initialState.adminSettingsPath;
- },
- [types.UPDATE_SETTINGS](state, data) {
- state.settings = { ...state.settings, ...data.settings };
- },
- [types.SET_SETTINGS](state, settings) {
- state.settings = settings ?? state.settings;
- state.original = Object.freeze(settings);
- },
- [types.RESET_SETTINGS](state) {
- state.settings = { ...state.original };
- },
- [types.TOGGLE_LOADING](state) {
- state.isLoading = !state.isLoading;
- },
-};
diff --git a/app/assets/javascripts/registry/settings/store/state.js b/app/assets/javascripts/registry/settings/store/state.js
deleted file mode 100644
index fccc0991c1c..00000000000
--- a/app/assets/javascripts/registry/settings/store/state.js
+++ /dev/null
@@ -1,42 +0,0 @@
-export default () => ({
- /*
- * Project Id used to build the API call
- */
- projectId: '',
- /*
- * Boolean to determine if the UI is loading data from the API
- */
- isLoading: false,
- /*
- * Boolean to determine if the user is an admin
- */
- isAdmin: false,
- /*
- * String containing the full path to the admin config page for CI/CD
- */
- adminSettingsPath: '',
- /*
- * Boolean to determine if project created before 12.8 can use this feature
- */
- enableHistoricEntries: false,
- /*
- * This contains the data shown and manipulated in the UI
- * Has the following structure:
- * {
- * enabled: Boolean
- * cadence: String,
- * older_than: String,
- * keep_n: String,
- * name_regex: String
- * }
- */
- settings: {},
- /*
- * Same structure as settings, above but Frozen object and used only in case the user clicks 'cancel', initialized to null
- */
- original: null,
- /*
- * Contains the options used to populate the form selects
- */
- formOptions: {},
-});
diff --git a/app/assets/javascripts/registry/shared/components/expiration_policy_fields.vue b/app/assets/javascripts/registry/shared/components/expiration_policy_fields.vue
index 1ff2f6f99e5..2b8e9f6ff64 100644
--- a/app/assets/javascripts/registry/shared/components/expiration_policy_fields.vue
+++ b/app/assets/javascripts/registry/shared/components/expiration_policy_fields.vue
@@ -68,34 +68,31 @@ export default {
{
name: 'expiration-policy-interval',
label: EXPIRATION_INTERVAL_LABEL,
- model: 'older_than',
- optionKey: 'olderThan',
+ model: 'olderThan',
},
{
name: 'expiration-policy-schedule',
label: EXPIRATION_SCHEDULE_LABEL,
model: 'cadence',
- optionKey: 'cadence',
},
{
name: 'expiration-policy-latest',
label: KEEP_N_LABEL,
- model: 'keep_n',
- optionKey: 'keepN',
+ model: 'keepN',
},
],
textAreaList: [
{
name: 'expiration-policy-name-matching',
label: NAME_REGEX_LABEL,
- model: 'name_regex',
+ model: 'nameRegex',
placeholder: NAME_REGEX_PLACEHOLDER,
description: NAME_REGEX_DESCRIPTION,
},
{
name: 'expiration-policy-keep-name',
label: NAME_REGEX_KEEP_LABEL,
- model: 'name_regex_keep',
+ model: 'nameRegexKeep',
placeholder: NAME_REGEX_KEEP_PLACEHOLDER,
description: NAME_REGEX_KEEP_DESCRIPTION,
},
@@ -107,17 +104,16 @@ export default {
},
computed: {
...mapComputedToEvent(
- ['enabled', 'cadence', 'older_than', 'keep_n', 'name_regex', 'name_regex_keep'],
+ ['enabled', 'cadence', 'olderThan', 'keepN', 'nameRegex', 'nameRegexKeep'],
'value',
),
policyEnabledText() {
return this.enabled ? ENABLED_TEXT : DISABLED_TEXT;
},
textAreaValidation() {
- const nameRegexErrors =
- this.apiErrors?.name_regex || this.validateRegexLength(this.name_regex);
+ const nameRegexErrors = this.apiErrors?.nameRegex || this.validateRegexLength(this.nameRegex);
const nameKeepRegexErrors =
- this.apiErrors?.name_regex_keep || this.validateRegexLength(this.name_regex_keep);
+ this.apiErrors?.nameRegexKeep || this.validateRegexLength(this.nameRegexKeep);
return {
/*
@@ -127,11 +123,11 @@ export default {
* false: red border, error message
* So in this function we keep null if the are no message otherwise we 'invert' the error message
*/
- name_regex: {
+ nameRegex: {
state: nameRegexErrors === null ? null : !nameRegexErrors,
message: nameRegexErrors,
},
- name_regex_keep: {
+ nameRegexKeep: {
state: nameKeepRegexErrors === null ? null : !nameKeepRegexErrors,
message: nameKeepRegexErrors,
},
@@ -139,8 +135,8 @@ export default {
},
fieldsValidity() {
return (
- this.textAreaValidation.name_regex.state !== false &&
- this.textAreaValidation.name_regex_keep.state !== false
+ this.textAreaValidation.nameRegex.state !== false &&
+ this.textAreaValidation.nameRegexKeep.state !== false
);
},
isFormElementDisabled() {
@@ -216,11 +212,7 @@ export default {
:disabled="isFormElementDisabled"
@input="updateModel($event, select.model)"
>
- <option
- v-for="option in formOptions[select.optionKey]"
- :key="option.key"
- :value="option.key"
- >
+ <option v-for="option in formOptions[select.model]" :key="option.key" :value="option.key">
{{ option.label }}
</option>
</gl-form-select>
diff --git a/app/assets/javascripts/registry/shared/constants.js b/app/assets/javascripts/registry/shared/constants.js
index 36d55c7610e..735d72972e6 100644
--- a/app/assets/javascripts/registry/shared/constants.js
+++ b/app/assets/javascripts/registry/shared/constants.js
@@ -43,3 +43,27 @@ export const NAME_REGEX_KEEP_PLACEHOLDER = '';
export const NAME_REGEX_KEEP_DESCRIPTION = s__(
'ContainerRegistry|Wildcards such as %{codeStart}.*-master%{codeEnd} or %{codeStart}release-.*%{codeEnd} are supported',
);
+
+export const KEEP_N_OPTIONS = [
+ { variable: 1, key: 'ONE_TAG', default: false },
+ { variable: 5, key: 'FIVE_TAGS', default: false },
+ { variable: 10, key: 'TEN_TAGS', default: true },
+ { variable: 25, key: 'TWENTY_FIVE_TAGS', default: false },
+ { variable: 50, key: 'FIFTY_TAGS', default: false },
+ { variable: 100, key: 'ONE_HUNDRED_TAGS', default: false },
+];
+
+export const CADENCE_OPTIONS = [
+ { key: 'EVERY_DAY', label: __('Every day'), default: true },
+ { key: 'EVERY_WEEK', label: __('Every week'), default: false },
+ { key: 'EVERY_TWO_WEEKS', label: __('Every two weeks'), default: false },
+ { key: 'EVERY_MONTH', label: __('Every month'), default: false },
+ { key: 'EVERY_THREE_MONTHS', label: __('Every three months'), default: false },
+];
+
+export const OLDER_THAN_OPTIONS = [
+ { key: 'SEVEN_DAYS', variable: 7, default: false },
+ { key: 'FOURTEEN_DAYS', variable: 14, default: false },
+ { key: 'THIRTY_DAYS', variable: 30, default: false },
+ { key: 'NINETY_DAYS', variable: 90, default: true },
+];
diff --git a/app/assets/javascripts/registry/shared/utils.js b/app/assets/javascripts/registry/shared/utils.js
index a7377773842..bdf1ab9507d 100644
--- a/app/assets/javascripts/registry/shared/utils.js
+++ b/app/assets/javascripts/registry/shared/utils.js
@@ -1,3 +1,6 @@
+import { n__ } from '~/locale';
+import { KEEP_N_OPTIONS, CADENCE_OPTIONS, OLDER_THAN_OPTIONS } from './constants';
+
export const findDefaultOption = options => {
const item = options.find(o => o.default);
return item ? item.key : null;
@@ -17,3 +20,27 @@ export const mapComputedToEvent = (list, root) => {
});
return result;
};
+
+export const olderThanTranslationGenerator = variable =>
+ n__(
+ '%d day until tags are automatically removed',
+ '%d days until tags are automatically removed',
+ variable,
+ );
+
+export const keepNTranslationGenerator = variable =>
+ n__('%d tag per image name', '%d tags per image name', variable);
+
+export const optionLabelGenerator = (collection, translationFn) =>
+ collection.map(option => ({
+ ...option,
+ label: translationFn(option.variable),
+ }));
+
+export const formOptionsGenerator = () => {
+ return {
+ olderThan: optionLabelGenerator(OLDER_THAN_OPTIONS, olderThanTranslationGenerator),
+ cadence: CADENCE_OPTIONS,
+ keepN: optionLabelGenerator(KEEP_N_OPTIONS, keepNTranslationGenerator),
+ };
+};
diff --git a/app/assets/javascripts/related_issues/components/add_issuable_form.vue b/app/assets/javascripts/related_issues/components/add_issuable_form.vue
index 63d61989cba..6fbae95094a 100644
--- a/app/assets/javascripts/related_issues/components/add_issuable_form.vue
+++ b/app/assets/javascripts/related_issues/components/add_issuable_form.vue
@@ -195,7 +195,8 @@ export default {
:disabled="isSubmitButtonDisabled"
:loading="isSubmitting"
type="submit"
- class="js-add-issuable-form-add-button float-left qa-add-issue-button"
+ class="js-add-issuable-form-add-button float-left"
+ data-qa-selector="add_issue_button"
>
{{ __('Add') }}
</gl-button>
diff --git a/app/assets/javascripts/related_issues/components/issue_token.vue b/app/assets/javascripts/related_issues/components/issue_token.vue
index 31d0c7dbbb0..bbbdf2cdb49 100644
--- a/app/assets/javascripts/related_issues/components/issue_token.vue
+++ b/app/assets/javascripts/related_issues/components/issue_token.vue
@@ -90,6 +90,7 @@ export default {
:size="12"
:title="stateTitle"
:aria-label="state"
+ data-testid="referenceIcon"
/>
{{ displayReference }}
</component>
@@ -105,6 +106,7 @@ export default {
:title="removeButtonLabel"
:aria-label="removeButtonLabel"
:disabled="removeDisabled"
+ data-testid="removeBtn"
type="button"
class="js-issue-token-remove-button"
@click="onRemoveRequest"
diff --git a/app/assets/javascripts/related_issues/components/related_issuable_input.vue b/app/assets/javascripts/related_issues/components/related_issuable_input.vue
index 1931cfb2c00..9809b228308 100644
--- a/app/assets/javascripts/related_issues/components/related_issuable_input.vue
+++ b/app/assets/javascripts/related_issues/components/related_issuable_input.vue
@@ -219,7 +219,8 @@ export default {
:value="inputValue"
:placeholder="inputPlaceholder"
type="text"
- class="js-add-issuable-form-input add-issuable-form-input qa-add-issue-input"
+ class="js-add-issuable-form-input add-issuable-form-input"
+ data-qa-selector="add_issue_field"
@input="onInput"
@focus="onFocus"
@blur="onBlur"
diff --git a/app/assets/javascripts/releases/components/app_edit_new.vue b/app/assets/javascripts/releases/components/app_edit_new.vue
index e1edf3d689d..1a07e0ed762 100644
--- a/app/assets/javascripts/releases/components/app_edit_new.vue
+++ b/app/assets/javascripts/releases/components/app_edit_new.vue
@@ -1,13 +1,11 @@
<script>
-/* eslint-disable vue/no-v-html */
import { mapState, mapActions, mapGetters } from 'vuex';
-import { GlButton, GlFormInput, GlFormGroup } from '@gitlab/ui';
-import { __, sprintf } from '~/locale';
+import { GlButton, GlFormInput, GlFormGroup, GlSprintf } from '@gitlab/ui';
+import { __ } from '~/locale';
import MarkdownField from '~/vue_shared/components/markdown/field.vue';
import { BACK_URL_PARAM } from '~/releases/constants';
import { getParameterByName } from '~/lib/utils/common_utils';
import AssetLinksForm from './asset_links_form.vue';
-import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import MilestoneCombobox from '~/milestones/project_milestone_combobox.vue';
import TagField from './tag_field.vue';
@@ -17,12 +15,12 @@ export default {
GlFormInput,
GlFormGroup,
GlButton,
+ GlSprintf,
MarkdownField,
AssetLinksForm,
MilestoneCombobox,
TagField,
},
- mixins: [glFeatureFlagsMixin()],
computed: {
...mapState('detail', [
'isFetchingRelease',
@@ -41,18 +39,6 @@ export default {
showForm() {
return Boolean(!this.isFetchingRelease && !this.fetchError && this.release);
},
- subtitleText() {
- return sprintf(
- __(
- 'Releases are based on Git tags. We recommend tags that use semantic versioning, for example %{codeStart}v1.0%{codeEnd}, %{codeStart}v2.0-pre%{codeEnd}.',
- ),
- {
- codeStart: '<code>',
- codeEnd: '</code>',
- },
- false,
- );
- },
releaseTitle: {
get() {
return this.$store.state.detail.release.name;
@@ -80,9 +66,6 @@ export default {
cancelPath() {
return getParameterByName(BACK_URL_PARAM) || this.releasesPagePath;
},
- showAssetLinksForm() {
- return this.glFeatures.releaseAssetLinkEditing;
- },
saveButtonLabel() {
return this.isExistingRelease ? __('Save changes') : __('Create release');
},
@@ -127,7 +110,19 @@ export default {
</script>
<template>
<div class="d-flex flex-column">
- <p class="pt-3 js-subtitle-text" v-html="subtitleText"></p>
+ <p class="pt-3 js-subtitle-text">
+ <gl-sprintf
+ :message="
+ __(
+ 'Releases are based on Git tags. We recommend tags that use semantic versioning, for example %{codeStart}v1.0%{codeEnd}, %{codeStart}v2.0-pre%{codeEnd}.',
+ )
+ "
+ >
+ <template #code="{ content }">
+ <code>{{ content }}</code>
+ </template>
+ </gl-sprintf>
+ </p>
<form v-if="showForm" class="js-quick-submit" @submit.prevent="submitForm">
<tag-field />
<gl-form-group>
@@ -150,7 +145,7 @@ export default {
/>
</div>
</gl-form-group>
- <gl-form-group>
+ <gl-form-group data-testid="release-notes">
<label for="release-notes">{{ __('Release notes') }}</label>
<div class="bordered-box pr-3 pl-3">
<markdown-field
@@ -158,6 +153,7 @@ export default {
:markdown-preview-path="markdownPreviewPath"
:markdown-docs-path="markdownDocsPath"
:add-spacing-classes="false"
+ :textarea-value="releaseNotes"
class="gl-mt-3 gl-mb-3"
>
<template #textarea>
@@ -175,7 +171,7 @@ export default {
</div>
</gl-form-group>
- <asset-links-form v-if="showAssetLinksForm" />
+ <asset-links-form />
<div class="d-flex pt-3">
<gl-button
diff --git a/app/assets/javascripts/releases/components/app_index.vue b/app/assets/javascripts/releases/components/app_index.vue
index b8cf6ce478f..422d8bf630d 100644
--- a/app/assets/javascripts/releases/components/app_index.vue
+++ b/app/assets/javascripts/releases/components/app_index.vue
@@ -1,29 +1,21 @@
<script>
import { mapState, mapActions } from 'vuex';
-import {
- GlDeprecatedSkeletonLoading as GlSkeletonLoading,
- GlEmptyState,
- GlLink,
- GlButton,
-} from '@gitlab/ui';
-import {
- getParameterByName,
- historyPushState,
- buildUrlWithCurrentLocation,
-} from '~/lib/utils/common_utils';
+import { GlEmptyState, GlLink, GlButton } from '@gitlab/ui';
+import { getParameterByName } from '~/lib/utils/common_utils';
import { __ } from '~/locale';
-import TablePagination from '~/vue_shared/components/pagination/table_pagination.vue';
import ReleaseBlock from './release_block.vue';
+import ReleasesPagination from './releases_pagination.vue';
+import ReleaseSkeletonLoader from './release_skeleton_loader.vue';
export default {
name: 'ReleasesApp',
components: {
- GlSkeletonLoading,
GlEmptyState,
- ReleaseBlock,
- TablePagination,
GlLink,
GlButton,
+ ReleaseBlock,
+ ReleasesPagination,
+ ReleaseSkeletonLoader,
},
computed: {
...mapState('list', [
@@ -33,7 +25,6 @@ export default {
'isLoading',
'releases',
'hasError',
- 'pageInfo',
]),
shouldRenderEmptyState() {
return !this.releases.length && !this.hasError && !this.isLoading;
@@ -48,15 +39,23 @@ export default {
},
},
created() {
- this.fetchReleases({
- page: getParameterByName('page'),
- });
+ this.fetchReleases();
+
+ window.addEventListener('popstate', this.fetchReleases);
},
methods: {
- ...mapActions('list', ['fetchReleases']),
- onChangePage(page) {
- historyPushState(buildUrlWithCurrentLocation(`?page=${page}`));
- this.fetchReleases({ page });
+ ...mapActions('list', {
+ fetchReleasesStoreAction: 'fetchReleases',
+ }),
+ fetchReleases() {
+ this.fetchReleasesStoreAction({
+ // these two parameters are only used in "GraphQL mode"
+ before: getParameterByName('before'),
+ after: getParameterByName('after'),
+
+ // this parameter is only used when in "REST mode"
+ page: getParameterByName('page'),
+ });
},
},
};
@@ -74,7 +73,7 @@ export default {
{{ __('New release') }}
</gl-button>
- <gl-skeleton-loading v-if="isLoading" class="js-loading" />
+ <release-skeleton-loader v-if="isLoading" class="js-loading" />
<gl-empty-state
v-else-if="shouldRenderEmptyState"
@@ -105,7 +104,7 @@ export default {
/>
</div>
- <table-pagination v-if="!isLoading" :change="onChangePage" :page-info="pageInfo" />
+ <releases-pagination v-if="!isLoading" />
</div>
</template>
<style>
diff --git a/app/assets/javascripts/releases/components/app_show.vue b/app/assets/javascripts/releases/components/app_show.vue
index 8b89f0cf3fc..9ef38503c10 100644
--- a/app/assets/javascripts/releases/components/app_show.vue
+++ b/app/assets/javascripts/releases/components/app_show.vue
@@ -1,13 +1,13 @@
<script>
import { mapState, mapActions } from 'vuex';
-import { GlDeprecatedSkeletonLoading as GlSkeletonLoading } from '@gitlab/ui';
import ReleaseBlock from './release_block.vue';
+import ReleaseSkeletonLoader from './release_skeleton_loader.vue';
export default {
name: 'ReleaseShowApp',
components: {
- GlSkeletonLoading,
ReleaseBlock,
+ ReleaseSkeletonLoader,
},
computed: {
...mapState('detail', ['isFetchingRelease', 'fetchError', 'release']),
@@ -22,7 +22,7 @@ export default {
</script>
<template>
<div class="gl-mt-3">
- <gl-skeleton-loading v-if="isFetchingRelease" />
+ <release-skeleton-loader v-if="isFetchingRelease" />
<release-block v-else-if="!fetchError" :release="release" />
</div>
diff --git a/app/assets/javascripts/releases/components/asset_links_form.vue b/app/assets/javascripts/releases/components/asset_links_form.vue
index 07fab840067..331cc8ade6c 100644
--- a/app/assets/javascripts/releases/components/asset_links_form.vue
+++ b/app/assets/javascripts/releases/components/asset_links_form.vue
@@ -10,7 +10,6 @@ import {
GlFormInput,
GlFormSelect,
} from '@gitlab/ui';
-import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { DEFAULT_ASSET_LINK_TYPE, ASSET_LINK_TYPE } from '../constants';
import { s__ } from '~/locale';
@@ -26,7 +25,6 @@ export default {
GlFormSelect,
},
directives: { GlTooltip: GlTooltipDirective },
- mixins: [glFeatureFlagsMixin()],
computed: {
...mapState('detail', ['release', 'releaseAssetsDocsPath']),
...mapGetters('detail', ['validationErrors']),
@@ -195,7 +193,6 @@ export default {
</gl-form-group>
<gl-form-group
- v-if="glFeatures.releaseAssetLinkType"
class="link-type-field col-auto px-sm-2"
:label="__('Type')"
:label-for="`asset-type-${index}`"
diff --git a/app/assets/javascripts/releases/components/evidence_block.vue b/app/assets/javascripts/releases/components/evidence_block.vue
index 3724162f6d5..6e6017637d4 100644
--- a/app/assets/javascripts/releases/components/evidence_block.vue
+++ b/app/assets/javascripts/releases/components/evidence_block.vue
@@ -83,11 +83,7 @@ export default {
<span class="js-expanded monospace gl-pl-2">{{ sha(index) }}</span>
</template>
</expand-button>
- <clipboard-button
- :title="__('Copy evidence SHA')"
- :text="sha(index)"
- css-class="btn-default btn-transparent btn-clipboard"
- />
+ <clipboard-button :title="__('Copy evidence SHA')" :text="sha(index)" category="tertiary" />
</div>
<div class="d-flex align-items-center text-muted">
diff --git a/app/assets/javascripts/releases/components/release_block.vue b/app/assets/javascripts/releases/components/release_block.vue
index 2629df08be7..e9163a52792 100644
--- a/app/assets/javascripts/releases/components/release_block.vue
+++ b/app/assets/javascripts/releases/components/release_block.vue
@@ -11,7 +11,6 @@ import EvidenceBlock from './evidence_block.vue';
import ReleaseBlockAssets from './release_block_assets.vue';
import ReleaseBlockFooter from './release_block_footer.vue';
import ReleaseBlockHeader from './release_block_header.vue';
-import ReleaseBlockMetadata from './release_block_metadata.vue';
import ReleaseBlockMilestoneInfo from './release_block_milestone_info.vue';
export default {
@@ -21,7 +20,6 @@ export default {
ReleaseBlockAssets,
ReleaseBlockFooter,
ReleaseBlockHeader,
- ReleaseBlockMetadata,
ReleaseBlockMilestoneInfo,
},
mixins: [glFeatureFlagsMixin()],
@@ -54,22 +52,13 @@ export default {
milestones() {
return this.release.milestones || [];
},
- shouldShowEvidence() {
- return this.glFeatures.releaseEvidenceCollection;
- },
- shouldShowFooter() {
- return this.glFeatures.releaseIssueSummary;
- },
shouldRenderAssets() {
return Boolean(
this.assets.links.length || (this.assets.sources && this.assets.sources.length),
);
},
- shouldRenderReleaseMetaData() {
- return !this.glFeatures.releaseIssueSummary;
- },
shouldRenderMilestoneInfo() {
- return Boolean(this.glFeatures.releaseIssueSummary && !isEmpty(this.release.milestones));
+ return Boolean(!isEmpty(this.release.milestones));
},
},
@@ -105,9 +94,8 @@ export default {
<hr class="mb-3 mt-0" />
</div>
- <release-block-metadata v-if="shouldRenderReleaseMetaData" :release="release" />
<release-block-assets v-if="shouldRenderAssets" :assets="assets" />
- <evidence-block v-if="hasEvidence && shouldShowEvidence" :release="release" />
+ <evidence-block v-if="hasEvidence" :release="release" />
<div ref="gfm-content" class="card-text gl-mt-3">
<div class="md" v-html="release.descriptionHtml"></div>
@@ -115,7 +103,6 @@ export default {
</div>
<release-block-footer
- v-if="shouldShowFooter"
class="card-footer"
:commit="release.commit"
:commit-path="release.commitPath"
diff --git a/app/assets/javascripts/releases/components/release_block_assets.vue b/app/assets/javascripts/releases/components/release_block_assets.vue
index 8824cbefd7e..eb83d8657c0 100644
--- a/app/assets/javascripts/releases/components/release_block_assets.vue
+++ b/app/assets/javascripts/releases/components/release_block_assets.vue
@@ -1,7 +1,6 @@
<script>
import { GlTooltipDirective, GlLink, GlButton, GlCollapse, GlIcon, GlBadge } from '@gitlab/ui';
import { difference, get } from 'lodash';
-import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { ASSET_LINK_TYPE } from '../constants';
import { __, s__, sprintf } from '~/locale';
@@ -17,7 +16,6 @@ export default {
directives: {
GlTooltip: GlTooltipDirective,
},
- mixins: [glFeatureFlagsMixin()],
props: {
assets: {
type: Object,
@@ -30,9 +28,6 @@ export default {
};
},
computed: {
- hasAssets() {
- return Boolean(this.assets.count);
- },
imageLinks() {
return this.linksForType(ASSET_LINK_TYPE.IMAGE);
},
@@ -95,94 +90,50 @@ export default {
<template>
<div class="card-text gl-mt-3">
- <template v-if="glFeatures.releaseAssetLinkType">
- <gl-button
- data-testid="accordion-button"
- variant="link"
- class="gl-font-weight-bold"
- @click="toggleAssetsExpansion"
- >
- <gl-icon
- name="chevron-right"
- class="gl-transition-medium"
- :class="{ 'gl-rotate-90': isAssetsExpanded }"
- />
- {{ __('Assets') }}
- <gl-badge size="sm" variant="neutral" class="gl-display-inline-block">{{
- assets.count
- }}</gl-badge>
- </gl-button>
- <gl-collapse v-model="isAssetsExpanded">
- <div class="gl-pl-6 gl-pt-3 js-assets-list">
- <template v-for="(section, index) in sections">
- <h5 v-if="section.title" :key="`section-header-${index}`" class="gl-mb-2">
- {{ section.title }}
- </h5>
- <ul :key="`section-body-${index}`" class="list-unstyled gl-m-0">
- <li v-for="link in section.links" :key="link.url">
- <gl-link
- :href="link.directAssetUrl || link.url"
- class="gl-display-flex gl-align-items-center gl-line-height-24"
- >
- <gl-icon
- :name="section.iconName"
- class="gl-mr-2 gl-flex-shrink-0 gl-flex-grow-0"
- />
- {{ link.name }}
- <gl-icon
- v-if="link.external"
- v-gl-tooltip
- name="external-link"
- :aria-label="$options.externalLinkTooltipText"
- :title="$options.externalLinkTooltipText"
- data-testid="external-link-indicator"
- class="gl-ml-2 gl-flex-shrink-0 gl-flex-grow-0 gl-text-gray-400"
- />
- </gl-link>
- </li>
- </ul>
- </template>
- </div>
- </gl-collapse>
- </template>
-
- <template v-else>
- <b>
- {{ __('Assets') }}
- <span class="js-assets-count badge badge-pill">{{ assets.count }}</span>
- </b>
-
- <ul v-if="assets.links.length" class="pl-0 mb-0 gl-mt-3 list-unstyled js-assets-list">
- <li v-for="link in assets.links" :key="link.name" class="gl-mb-3">
- <gl-link v-gl-tooltip.bottom :title="__('Download asset')" :href="link.directAssetUrl">
- <gl-icon name="package" class="align-middle gl-mr-2 align-text-bottom" />
- {{ link.name }}
- <span v-if="link.external" data-testid="external-link-indicator">{{
- __('(external source)')
- }}</span>
- </gl-link>
- </li>
- </ul>
-
- <div v-if="hasAssets" class="dropdown">
- <button
- type="button"
- class="btn btn-link"
- data-toggle="dropdown"
- aria-haspopup="true"
- aria-expanded="false"
- >
- <gl-icon name="doc-code" class="align-top gl-mr-2" />
- {{ __('Source code') }}
- <gl-icon name="chevron-down" />
- </button>
-
- <div class="js-sources-dropdown dropdown-menu">
- <li v-for="asset in assets.sources" :key="asset.url">
- <gl-link :href="asset.url">{{ __('Download') }} {{ asset.format }}</gl-link>
- </li>
- </div>
+ <gl-button
+ data-testid="accordion-button"
+ variant="link"
+ class="gl-font-weight-bold"
+ @click="toggleAssetsExpansion"
+ >
+ <gl-icon
+ name="chevron-right"
+ class="gl-transition-medium"
+ :class="{ 'gl-rotate-90': isAssetsExpanded }"
+ />
+ {{ __('Assets') }}
+ <gl-badge size="sm" variant="neutral" class="gl-display-inline-block">{{
+ assets.count
+ }}</gl-badge>
+ </gl-button>
+ <gl-collapse v-model="isAssetsExpanded">
+ <div class="gl-pl-6 gl-pt-3 js-assets-list">
+ <template v-for="(section, index) in sections">
+ <h5 v-if="section.title" :key="`section-header-${index}`" class="gl-mb-2">
+ {{ section.title }}
+ </h5>
+ <ul :key="`section-body-${index}`" class="list-unstyled gl-m-0">
+ <li v-for="link in section.links" :key="link.url" class="gl-display-flex">
+ <gl-link
+ :href="link.directAssetUrl || link.url"
+ class="gl-display-flex gl-align-items-center gl-line-height-24"
+ >
+ <gl-icon :name="section.iconName" class="gl-mr-2 gl-flex-shrink-0 gl-flex-grow-0" />
+ {{ link.name }}
+ <gl-icon
+ v-if="link.external"
+ v-gl-tooltip
+ name="external-link"
+ :aria-label="$options.externalLinkTooltipText"
+ :title="$options.externalLinkTooltipText"
+ data-testid="external-link-indicator"
+ class="gl-ml-2 gl-flex-shrink-0 gl-flex-grow-0 gl-text-gray-400"
+ />
+ </gl-link>
+ </li>
+ </ul>
+ </template>
</div>
- </template>
+ </gl-collapse>
</div>
</template>
diff --git a/app/assets/javascripts/releases/components/release_block_author.vue b/app/assets/javascripts/releases/components/release_block_author.vue
deleted file mode 100644
index 72c578068cd..00000000000
--- a/app/assets/javascripts/releases/components/release_block_author.vue
+++ /dev/null
@@ -1,42 +0,0 @@
-<script>
-import { GlSprintf } from '@gitlab/ui';
-import { __, sprintf } from '~/locale';
-import UserAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue';
-
-export default {
- name: 'ReleaseBlockAuthor',
- components: {
- GlSprintf,
- UserAvatarLink,
- },
- props: {
- author: {
- type: Object,
- required: true,
- },
- },
- computed: {
- userImageAltDescription() {
- return this.author && this.author.username
- ? sprintf(__("%{username}'s avatar"), { username: this.author.username })
- : null;
- },
- },
-};
-</script>
-
-<template>
- <div class="d-flex">
- <gl-sprintf :message="__('by %{user}')">
- <template #user>
- <user-avatar-link
- class="gl-ml-2"
- :link-href="author.webUrl"
- :img-src="author.avatarUrl"
- :img-alt="userImageAltDescription"
- :tooltip-text="author.username"
- />
- </template>
- </gl-sprintf>
- </div>
-</template>
diff --git a/app/assets/javascripts/releases/components/release_block_header.vue b/app/assets/javascripts/releases/components/release_block_header.vue
index 95292a26bce..87538244f1a 100644
--- a/app/assets/javascripts/releases/components/release_block_header.vue
+++ b/app/assets/javascripts/releases/components/release_block_header.vue
@@ -1,5 +1,5 @@
<script>
-import { GlTooltipDirective, GlLink, GlBadge, GlButton, GlIcon } from '@gitlab/ui';
+import { GlTooltipDirective, GlLink, GlBadge, GlButton } from '@gitlab/ui';
import { BACK_URL_PARAM } from '~/releases/constants';
import { setUrlParams } from '~/lib/utils/url_utility';
@@ -8,7 +8,6 @@ export default {
components: {
GlLink,
GlBadge,
- GlIcon,
GlButton,
},
directives: {
@@ -55,11 +54,10 @@ export default {
v-gl-tooltip
category="primary"
variant="default"
+ icon="pencil"
class="gl-mr-3 js-edit-button ml-2 pb-2"
:title="__('Edit this release')"
:href="editLink"
- >
- <gl-icon name="pencil" />
- </gl-button>
+ />
</div>
</template>
diff --git a/app/assets/javascripts/releases/components/release_block_metadata.vue b/app/assets/javascripts/releases/components/release_block_metadata.vue
deleted file mode 100644
index 2247b4c0064..00000000000
--- a/app/assets/javascripts/releases/components/release_block_metadata.vue
+++ /dev/null
@@ -1,90 +0,0 @@
-<script>
-import { GlTooltipDirective, GlLink, GlIcon } from '@gitlab/ui';
-import { __, sprintf } from '~/locale';
-import timeagoMixin from '~/vue_shared/mixins/timeago';
-import ReleaseBlockAuthor from './release_block_author.vue';
-import ReleaseBlockMilestones from './release_block_milestones.vue';
-
-export default {
- name: 'ReleaseBlockMetadata',
- components: {
- GlIcon,
- GlLink,
- ReleaseBlockAuthor,
- ReleaseBlockMilestones,
- },
- directives: {
- GlTooltip: GlTooltipDirective,
- },
- mixins: [timeagoMixin],
- props: {
- release: {
- type: Object,
- required: true,
- },
- },
- computed: {
- author() {
- return this.release.author;
- },
- commit() {
- return this.release.commit || {};
- },
- commitUrl() {
- return this.release.commitPath;
- },
- hasAuthor() {
- return Boolean(this.author);
- },
- releasedTimeAgo() {
- const now = new Date();
- const isFuture = now < new Date(this.release.releasedAt);
- const time = this.timeFormatted(this.release.releasedAt);
- return isFuture
- ? sprintf(__('will be released %{time}'), { time })
- : sprintf(__('released %{time}'), { time });
- },
- shouldRenderMilestones() {
- return Boolean(this.release.milestones?.length);
- },
- tagUrl() {
- return this.release.tagPath;
- },
- },
-};
-</script>
-
-<template>
- <div class="card-subtitle d-flex flex-wrap text-secondary">
- <div class="gl-mr-3">
- <gl-icon name="commit" class="align-middle" />
- <gl-link v-if="commitUrl" v-gl-tooltip.bottom :title="commit.title" :href="commitUrl">
- {{ commit.shortId }}
- </gl-link>
- <span v-else v-gl-tooltip.bottom :title="commit.title">{{ commit.shortId }}</span>
- </div>
-
- <div class="gl-mr-3">
- <gl-icon name="tag" class="align-middle" />
- <gl-link v-if="tagUrl" v-gl-tooltip.bottom :title="__('Tag')" :href="tagUrl">
- {{ release.tagName }}
- </gl-link>
- <span v-else v-gl-tooltip.bottom :title="__('Tag')">{{ release.tagName }}</span>
- </div>
-
- <release-block-milestones v-if="shouldRenderMilestones" :milestones="release.milestones" />
-
- <div class="gl-mr-2">
- &bull;
- <span
- v-gl-tooltip.bottom
- class="js-release-date-info"
- :title="tooltipTitle(release.releasedAt)"
- >
- {{ releasedTimeAgo }}
- </span>
- </div>
-
- <release-block-author v-if="hasAuthor" :author="author" />
- </div>
-</template>
diff --git a/app/assets/javascripts/releases/components/release_block_milestones.vue b/app/assets/javascripts/releases/components/release_block_milestones.vue
deleted file mode 100644
index 1da683764b3..00000000000
--- a/app/assets/javascripts/releases/components/release_block_milestones.vue
+++ /dev/null
@@ -1,50 +0,0 @@
-<script>
-import { GlTooltipDirective, GlLink, GlIcon } from '@gitlab/ui';
-import { n__ } from '~/locale';
-
-export default {
- name: 'ReleaseBlockMilestones',
- components: {
- GlLink,
- GlIcon,
- },
- directives: {
- GlTooltip: GlTooltipDirective,
- },
- props: {
- milestones: {
- type: Array,
- required: true,
- },
- },
- computed: {
- labelText() {
- return n__('Milestone', 'Milestones', this.milestones.length);
- },
- },
-};
-</script>
-
-<template>
- <div>
- <div class="js-milestone-list-label">
- <gl-icon name="flag" class="align-middle" />
- <span class="js-label-text">{{ labelText }}</span>
- </div>
-
- <template v-for="(milestone, index) in milestones">
- <gl-link
- :key="milestone.id"
- v-gl-tooltip
- :title="milestone.description"
- :href="milestone.webUrl"
- class="mx-1 js-milestone-link"
- >
- {{ milestone.title }}
- </gl-link>
- <template v-if="index !== milestones.length - 1">
- &bull;
- </template>
- </template>
- </div>
-</template>
diff --git a/app/assets/javascripts/releases/components/release_skeleton_loader.vue b/app/assets/javascripts/releases/components/release_skeleton_loader.vue
new file mode 100644
index 00000000000..054620af636
--- /dev/null
+++ b/app/assets/javascripts/releases/components/release_skeleton_loader.vue
@@ -0,0 +1,51 @@
+<script>
+import { GlSkeletonLoader } from '@gitlab/ui';
+
+export default {
+ name: 'ReleaseSkeletonLoader',
+ components: { GlSkeletonLoader },
+};
+</script>
+<template>
+ <gl-skeleton-loader :width="1248" :height="420">
+ <!-- Outside border -->
+ <path
+ d="M 4.5 0 C 2.0156486 0 0 2.0156486 0 4.5 L 0 415.5 C 0 417.98435 2.0156486 420 4.5 420 L 1243.5 420 C 1245.9844 420 1248 417.98435 1248 415.5 L 1248 4.5 C 1248 2.0156486 1245.9844 0 1243.5 0 L 4.5 0 z M 4.5 1 L 1243.5 1 C 1245.4476 1 1247 2.5523514 1247 4.5 L 1247 415.5 C 1247 417.44765 1245.4476 419 1243.5 419 L 4.5 419 C 2.5523514 419 1 417.44765 1 415.5 L 1 4.5 C 1 2.5523514 2.5523514 1 4.5 1 z "
+ />
+
+ <!-- Header bottom border -->
+ <rect x="0" y="63.5" width="1248" height="1" />
+
+ <!-- Release title -->
+ <rect x="16" y="20" width="293" height="24" />
+
+ <!-- Edit (pencil) button -->
+ <rect x="1207" y="16" rx="4" width="32" height="32" />
+
+ <!-- Asset link 1 -->
+ <rect x="40" y="121" rx="4" width="16" height="16" />
+ <rect x="60" y="125" width="116" height="8" />
+
+ <!-- Asset link 2 -->
+ <rect x="40" y="145" rx="4" width="16" height="16" />
+ <rect x="60" y="149" width="132" height="8" />
+
+ <!-- Asset link 3 -->
+ <rect x="40" y="169" rx="4" width="16" height="16" />
+ <rect x="60" y="173" width="140" height="8" />
+
+ <!-- Asset link 4 -->
+ <rect x="40" y="193" rx="4" width="16" height="16" />
+ <rect x="60" y="197" width="112" height="8" />
+
+ <!-- Release notes -->
+ <rect x="16" y="228" width="480" height="8" />
+ <rect x="16" y="252" width="560" height="8" />
+ <rect x="16" y="276" width="480" height="8" />
+ <rect x="16" y="300" width="560" height="8" />
+ <rect x="16" y="324" width="320" height="8" />
+
+ <!-- Footer top border -->
+ <rect x="0" y="373" width="1248" height="1" />
+ </gl-skeleton-loader>
+</template>
diff --git a/app/assets/javascripts/releases/components/releases_pagination_graphql.vue b/app/assets/javascripts/releases/components/releases_pagination_graphql.vue
index a4fe407a5bd..cb6f1fa18a1 100644
--- a/app/assets/javascripts/releases/components/releases_pagination_graphql.vue
+++ b/app/assets/javascripts/releases/components/releases_pagination_graphql.vue
@@ -13,14 +13,14 @@ export default {
},
},
methods: {
- ...mapActions('list', ['fetchReleasesGraphQl']),
+ ...mapActions('list', ['fetchReleases']),
onPrev(before) {
historyPushState(buildUrlWithCurrentLocation(`?before=${before}`));
- this.fetchReleasesGraphQl({ before });
+ this.fetchReleases({ before });
},
onNext(after) {
historyPushState(buildUrlWithCurrentLocation(`?after=${after}`));
- this.fetchReleasesGraphQl({ after });
+ this.fetchReleases({ after });
},
},
};
diff --git a/app/assets/javascripts/releases/components/releases_pagination_rest.vue b/app/assets/javascripts/releases/components/releases_pagination_rest.vue
index 992cc4cd469..334458a2302 100644
--- a/app/assets/javascripts/releases/components/releases_pagination_rest.vue
+++ b/app/assets/javascripts/releases/components/releases_pagination_rest.vue
@@ -7,18 +7,18 @@ export default {
name: 'ReleasesPaginationRest',
components: { TablePagination },
computed: {
- ...mapState('list', ['pageInfo']),
+ ...mapState('list', ['restPageInfo']),
},
methods: {
- ...mapActions('list', ['fetchReleasesRest']),
+ ...mapActions('list', ['fetchReleases']),
onChangePage(page) {
historyPushState(buildUrlWithCurrentLocation(`?page=${page}`));
- this.fetchReleasesRest({ page });
+ this.fetchReleases({ page });
},
},
};
</script>
<template>
- <table-pagination :change="onChangePage" :page-info="pageInfo" />
+ <table-pagination :change="onChangePage" :page-info="restPageInfo" />
</template>
diff --git a/app/assets/javascripts/releases/constants.js b/app/assets/javascripts/releases/constants.js
index 361cee70747..953e7b4189c 100644
--- a/app/assets/javascripts/releases/constants.js
+++ b/app/assets/javascripts/releases/constants.js
@@ -10,3 +10,5 @@ export const ASSET_LINK_TYPE = Object.freeze({
});
export const DEFAULT_ASSET_LINK_TYPE = ASSET_LINK_TYPE.OTHER;
+
+export const PAGE_SIZE = 20;
diff --git a/app/assets/javascripts/releases/mount_edit.js b/app/assets/javascripts/releases/mount_edit.js
index 623b18591a0..2f4b0e64e36 100644
--- a/app/assets/javascripts/releases/mount_edit.js
+++ b/app/assets/javascripts/releases/mount_edit.js
@@ -13,9 +13,6 @@ export default () => {
modules: {
detail: createDetailModule(el.dataset),
},
- featureFlags: {
- releaseShowPage: Boolean(gon.features?.releaseShowPage),
- },
});
return new Vue({
diff --git a/app/assets/javascripts/releases/mount_new.js b/app/assets/javascripts/releases/mount_new.js
index 10725e47740..5c481498ffb 100644
--- a/app/assets/javascripts/releases/mount_new.js
+++ b/app/assets/javascripts/releases/mount_new.js
@@ -13,9 +13,6 @@ export default () => {
modules: {
detail: createDetailModule(el.dataset),
},
- featureFlags: {
- releaseShowPage: Boolean(gon.features?.releaseShowPage),
- },
});
return new Vue({
diff --git a/app/assets/javascripts/releases/mount_show.js b/app/assets/javascripts/releases/mount_show.js
index eef015ee0a6..b09ecc9fb55 100644
--- a/app/assets/javascripts/releases/mount_show.js
+++ b/app/assets/javascripts/releases/mount_show.js
@@ -13,6 +13,9 @@ export default () => {
modules: {
detail: createDetailModule(el.dataset),
},
+ featureFlags: {
+ graphqlIndividualReleasePage: Boolean(gon.features?.graphqlIndividualReleasePage),
+ },
});
return new Vue({
diff --git a/app/assets/javascripts/releases/queries/all_releases.query.graphql b/app/assets/javascripts/releases/queries/all_releases.query.graphql
index 7a99f32fdfa..c35306f163d 100644
--- a/app/assets/javascripts/releases/queries/all_releases.query.graphql
+++ b/app/assets/javascripts/releases/queries/all_releases.query.graphql
@@ -1,68 +1,16 @@
-query allReleases($fullPath: ID!) {
+#import "./release.fragment.graphql"
+
+query allReleases($fullPath: ID!, $first: Int, $last: Int, $before: String, $after: String) {
project(fullPath: $fullPath) {
- releases(first: 20) {
- count
+ releases(first: $first, last: $last, before: $before, after: $after) {
nodes {
- name
- tagName
- tagPath
- descriptionHtml
- releasedAt
- upcomingRelease
- assets {
- count
- sources {
- nodes {
- format
- url
- }
- }
- links {
- nodes {
- id
- name
- url
- directAssetUrl
- linkType
- external
- }
- }
- }
- evidences {
- nodes {
- filepath
- collectedAt
- sha
- }
- }
- links {
- editUrl
- issuesUrl
- mergeRequestsUrl
- selfUrl
- }
- commit {
- sha
- webUrl
- title
- }
- author {
- webUrl
- avatarUrl
- username
- }
- milestones {
- nodes {
- id
- title
- description
- webPath
- stats {
- totalIssuesCount
- closedIssuesCount
- }
- }
- }
+ ...Release
+ }
+ pageInfo {
+ startCursor
+ hasPreviousPage
+ hasNextPage
+ endCursor
}
}
}
diff --git a/app/assets/javascripts/releases/queries/one_release.query.graphql b/app/assets/javascripts/releases/queries/one_release.query.graphql
new file mode 100644
index 00000000000..b893aea94b0
--- /dev/null
+++ b/app/assets/javascripts/releases/queries/one_release.query.graphql
@@ -0,0 +1,9 @@
+#import "./release.fragment.graphql"
+
+query oneRelease($fullPath: ID!, $tagName: String!) {
+ project(fullPath: $fullPath) {
+ release(tagName: $tagName) {
+ ...Release
+ }
+ }
+}
diff --git a/app/assets/javascripts/releases/queries/release.fragment.graphql b/app/assets/javascripts/releases/queries/release.fragment.graphql
new file mode 100644
index 00000000000..445ed616348
--- /dev/null
+++ b/app/assets/javascripts/releases/queries/release.fragment.graphql
@@ -0,0 +1,62 @@
+fragment Release on Release {
+ name
+ tagName
+ tagPath
+ descriptionHtml
+ releasedAt
+ upcomingRelease
+ assets {
+ count
+ sources {
+ nodes {
+ format
+ url
+ }
+ }
+ links {
+ nodes {
+ id
+ name
+ url
+ directAssetUrl
+ linkType
+ external
+ }
+ }
+ }
+ evidences {
+ nodes {
+ filepath
+ collectedAt
+ sha
+ }
+ }
+ links {
+ editUrl
+ issuesUrl
+ mergeRequestsUrl
+ selfUrl
+ }
+ commit {
+ sha
+ webUrl
+ title
+ }
+ author {
+ webUrl
+ avatarUrl
+ username
+ }
+ milestones {
+ nodes {
+ id
+ title
+ description
+ webPath
+ stats {
+ totalIssuesCount
+ closedIssuesCount
+ }
+ }
+ }
+}
diff --git a/app/assets/javascripts/releases/stores/getters.js b/app/assets/javascripts/releases/stores/getters.js
new file mode 100644
index 00000000000..6a1da63289c
--- /dev/null
+++ b/app/assets/javascripts/releases/stores/getters.js
@@ -0,0 +1,11 @@
+/**
+ * @returns {Boolean} `true` if all the feature flags
+ * required to enable the GraphQL endpoint are enabled
+ */
+export const useGraphQLEndpoint = rootState => {
+ return Boolean(
+ rootState.featureFlags.graphqlReleaseData &&
+ rootState.featureFlags.graphqlReleasesPage &&
+ rootState.featureFlags.graphqlMilestoneStats,
+ );
+};
diff --git a/app/assets/javascripts/releases/stores/index.js b/app/assets/javascripts/releases/stores/index.js
index b2e93d789d7..cc8b586964f 100644
--- a/app/assets/javascripts/releases/stores/index.js
+++ b/app/assets/javascripts/releases/stores/index.js
@@ -1,7 +1,9 @@
import Vuex from 'vuex';
+import * as getters from './getters';
export default ({ modules, featureFlags }) =>
new Vuex.Store({
modules,
state: { featureFlags },
+ getters,
});
diff --git a/app/assets/javascripts/releases/stores/modules/detail/actions.js b/app/assets/javascripts/releases/stores/modules/detail/actions.js
index 5b682a0ab0f..e8a46f40d20 100644
--- a/app/assets/javascripts/releases/stores/modules/detail/actions.js
+++ b/app/assets/javascripts/releases/stores/modules/detail/actions.js
@@ -3,7 +3,13 @@ import api from '~/api';
import { deprecatedCreateFlash as createFlash } from '~/flash';
import { s__ } from '~/locale';
import { redirectTo } from '~/lib/utils/url_utility';
-import { releaseToApiJson, apiJsonToRelease } from '~/releases/util';
+import {
+ releaseToApiJson,
+ apiJsonToRelease,
+ gqClient,
+ convertOneReleaseGraphQLResponse,
+} from '~/releases/util';
+import oneReleaseQuery from '~/releases/queries/one_release.query.graphql';
export const initializeRelease = ({ commit, dispatch, getters }) => {
if (getters.isExistingRelease) {
@@ -18,9 +24,29 @@ export const initializeRelease = ({ commit, dispatch, getters }) => {
return Promise.resolve();
};
-export const fetchRelease = ({ commit, state }) => {
+export const fetchRelease = ({ commit, state, rootState }) => {
commit(types.REQUEST_RELEASE);
+ if (rootState.featureFlags?.graphqlIndividualReleasePage) {
+ return gqClient
+ .query({
+ query: oneReleaseQuery,
+ variables: {
+ fullPath: state.projectPath,
+ tagName: state.tagName,
+ },
+ })
+ .then(response => {
+ const { data: release } = convertOneReleaseGraphQLResponse(response);
+
+ commit(types.RECEIVE_RELEASE_SUCCESS, release);
+ })
+ .catch(error => {
+ commit(types.RECEIVE_RELEASE_ERROR, error);
+ createFlash(s__('Release|Something went wrong while getting the release details'));
+ });
+ }
+
return api
.release(state.projectId, state.tagName)
.then(({ data }) => {
@@ -45,6 +71,9 @@ export const updateReleaseNotes = ({ commit }, notes) => commit(types.UPDATE_REL
export const updateReleaseMilestones = ({ commit }, milestones) =>
commit(types.UPDATE_RELEASE_MILESTONES, milestones);
+export const updateReleaseGroupMilestones = ({ commit }, groupMilestones) =>
+ commit(types.UPDATE_RELEASE_GROUP_MILESTONES, groupMilestones);
+
export const addEmptyAssetLink = ({ commit }) => {
commit(types.ADD_EMPTY_ASSET_LINK);
};
@@ -65,9 +94,9 @@ export const removeAssetLink = ({ commit }, linkIdToRemove) => {
commit(types.REMOVE_ASSET_LINK, linkIdToRemove);
};
-export const receiveSaveReleaseSuccess = ({ commit, state, rootState }, release) => {
+export const receiveSaveReleaseSuccess = ({ commit }, release) => {
commit(types.RECEIVE_SAVE_RELEASE_SUCCESS);
- redirectTo(rootState.featureFlags.releaseShowPage ? release._links.self : state.releasesPagePath);
+ redirectTo(release._links.self);
};
export const saveRelease = ({ commit, dispatch, getters }) => {
diff --git a/app/assets/javascripts/releases/stores/modules/detail/mutation_types.js b/app/assets/javascripts/releases/stores/modules/detail/mutation_types.js
index 7784e0cc741..1b2f5f33f02 100644
--- a/app/assets/javascripts/releases/stores/modules/detail/mutation_types.js
+++ b/app/assets/javascripts/releases/stores/modules/detail/mutation_types.js
@@ -9,6 +9,7 @@ export const UPDATE_CREATE_FROM = 'UPDATE_CREATE_FROM';
export const UPDATE_RELEASE_TITLE = 'UPDATE_RELEASE_TITLE';
export const UPDATE_RELEASE_NOTES = 'UPDATE_RELEASE_NOTES';
export const UPDATE_RELEASE_MILESTONES = 'UPDATE_RELEASE_MILESTONES';
+export const UPDATE_RELEASE_GROUP_MILESTONES = 'UPDATE_RELEASE_GROUP_MILESTONES';
export const REQUEST_SAVE_RELEASE = 'REQUEST_SAVE_RELEASE';
export const RECEIVE_SAVE_RELEASE_SUCCESS = 'RECEIVE_SAVE_RELEASE_SUCCESS';
diff --git a/app/assets/javascripts/releases/stores/modules/detail/mutations.js b/app/assets/javascripts/releases/stores/modules/detail/mutations.js
index 750f496665d..58a1958c5e2 100644
--- a/app/assets/javascripts/releases/stores/modules/detail/mutations.js
+++ b/app/assets/javascripts/releases/stores/modules/detail/mutations.js
@@ -13,6 +13,7 @@ export default {
name: '',
description: '',
milestones: [],
+ groupMilestones: [],
assets: {
links: [],
},
@@ -51,6 +52,10 @@ export default {
state.release.milestones = milestones;
},
+ [types.UPDATE_RELEASE_GROUP_MILESTONES](state, groupMilestones) {
+ state.release.groupMilestones = groupMilestones;
+ },
+
[types.REQUEST_SAVE_RELEASE](state) {
state.isUpdatingRelease = true;
},
diff --git a/app/assets/javascripts/releases/stores/modules/detail/state.js b/app/assets/javascripts/releases/stores/modules/detail/state.js
index a46e750df53..782a5c46d6c 100644
--- a/app/assets/javascripts/releases/stores/modules/detail/state.js
+++ b/app/assets/javascripts/releases/stores/modules/detail/state.js
@@ -1,5 +1,6 @@
export default ({
projectId,
+ projectPath,
markdownDocsPath,
markdownPreviewPath,
updateReleaseApiDocsPath,
@@ -12,6 +13,7 @@ export default ({
defaultBranch = null,
}) => ({
projectId,
+ projectPath,
markdownDocsPath,
markdownPreviewPath,
updateReleaseApiDocsPath,
diff --git a/app/assets/javascripts/releases/stores/modules/list/actions.js b/app/assets/javascripts/releases/stores/modules/list/actions.js
index 945b093b983..02e67415e63 100644
--- a/app/assets/javascripts/releases/stores/modules/list/actions.js
+++ b/app/assets/javascripts/releases/stores/modules/list/actions.js
@@ -8,55 +8,90 @@ import {
convertObjectPropsToCamelCase,
} from '~/lib/utils/common_utils';
import allReleasesQuery from '~/releases/queries/all_releases.query.graphql';
-import { gqClient, convertGraphQLResponse } from '../../../util';
+import { gqClient, convertAllReleasesGraphQLResponse } from '../../../util';
+import { PAGE_SIZE } from '../../../constants';
/**
- * Commits a mutation to update the state while the main endpoint is being requested.
+ * Gets a paginated list of releases from the server
+ *
+ * @param {Object} vuexParams
+ * @param {Object} actionParams
+ * @param {Number} [actionParams.page] The page number of results to fetch
+ * (this parameter is only used when fetching results from the REST API)
+ * @param {String} [actionParams.before] A GraphQL cursor. If provided,
+ * the items returned will proceed the provided cursor (this parameter is only
+ * used when fetching results from the GraphQL API).
+ * @param {String} [actionParams.after] A GraphQL cursor. If provided,
+ * the items returned will follow the provided cursor (this parameter is only
+ * used when fetching results from the GraphQL API).
*/
-export const requestReleases = ({ commit }) => commit(types.REQUEST_RELEASES);
+export const fetchReleases = ({ dispatch, rootGetters }, { page = 1, before, after }) => {
+ if (rootGetters.useGraphQLEndpoint) {
+ dispatch('fetchReleasesGraphQl', { before, after });
+ } else {
+ dispatch('fetchReleasesRest', { page });
+ }
+};
/**
- * Fetches the main endpoint.
- * Will dispatch requestNamespace action before starting the request.
- * Will dispatch receiveNamespaceSuccess if the request is successful
- * Will dispatch receiveNamesapceError if the request returns an error
- *
- * @param {String} projectId
+ * Gets a paginated list of releases from the GraphQL endpoint
*/
-export const fetchReleases = ({ dispatch, rootState, state }, { page = '1' }) => {
- dispatch('requestReleases');
+export const fetchReleasesGraphQl = (
+ { dispatch, commit, state },
+ { before = null, after = null },
+) => {
+ commit(types.REQUEST_RELEASES);
- if (
- rootState.featureFlags.graphqlReleaseData &&
- rootState.featureFlags.graphqlReleasesPage &&
- rootState.featureFlags.graphqlMilestoneStats
- ) {
- gqClient
- .query({
- query: allReleasesQuery,
- variables: {
- fullPath: state.projectPath,
- },
- })
- .then(response => {
- dispatch('receiveReleasesSuccess', convertGraphQLResponse(response));
- })
- .catch(() => dispatch('receiveReleasesError'));
+ let paginationParams;
+ if (!before && !after) {
+ paginationParams = { first: PAGE_SIZE };
+ } else if (before && !after) {
+ paginationParams = { last: PAGE_SIZE, before };
+ } else if (!before && after) {
+ paginationParams = { first: PAGE_SIZE, after };
} else {
- api
- .releases(state.projectId, { page })
- .then(response => dispatch('receiveReleasesSuccess', response))
- .catch(() => dispatch('receiveReleasesError'));
+ throw new Error(
+ 'Both a `before` and an `after` parameter were provided to fetchReleasesGraphQl. These parameters cannot be used together.',
+ );
}
+
+ gqClient
+ .query({
+ query: allReleasesQuery,
+ variables: {
+ fullPath: state.projectPath,
+ ...paginationParams,
+ },
+ })
+ .then(response => {
+ const { data, paginationInfo: graphQlPageInfo } = convertAllReleasesGraphQLResponse(response);
+
+ commit(types.RECEIVE_RELEASES_SUCCESS, {
+ data,
+ graphQlPageInfo,
+ });
+ })
+ .catch(() => dispatch('receiveReleasesError'));
};
-export const receiveReleasesSuccess = ({ commit }, { data, headers }) => {
- const pageInfo = parseIntPagination(normalizeHeaders(headers));
- const camelCasedReleases = convertObjectPropsToCamelCase(data, { deep: true });
- commit(types.RECEIVE_RELEASES_SUCCESS, {
- data: camelCasedReleases,
- pageInfo,
- });
+/**
+ * Gets a paginated list of releases from the REST endpoint
+ */
+export const fetchReleasesRest = ({ dispatch, commit, state }, { page }) => {
+ commit(types.REQUEST_RELEASES);
+
+ api
+ .releases(state.projectId, { page })
+ .then(({ data, headers }) => {
+ const restPageInfo = parseIntPagination(normalizeHeaders(headers));
+ const camelCasedReleases = convertObjectPropsToCamelCase(data, { deep: true });
+
+ commit(types.RECEIVE_RELEASES_SUCCESS, {
+ data: camelCasedReleases,
+ restPageInfo,
+ });
+ })
+ .catch(() => dispatch('receiveReleasesError'));
};
export const receiveReleasesError = ({ commit }) => {
diff --git a/app/assets/javascripts/releases/stores/modules/list/mutations.js b/app/assets/javascripts/releases/stores/modules/list/mutations.js
index 99fc096264a..296487cfee2 100644
--- a/app/assets/javascripts/releases/stores/modules/list/mutations.js
+++ b/app/assets/javascripts/releases/stores/modules/list/mutations.js
@@ -17,11 +17,12 @@ export default {
* @param {Object} state
* @param {Object} resp
*/
- [types.RECEIVE_RELEASES_SUCCESS](state, { data, pageInfo }) {
+ [types.RECEIVE_RELEASES_SUCCESS](state, { data, restPageInfo, graphQlPageInfo }) {
state.hasError = false;
state.isLoading = false;
state.releases = data;
- state.pageInfo = pageInfo;
+ state.restPageInfo = restPageInfo;
+ state.graphQlPageInfo = graphQlPageInfo;
},
/**
@@ -35,5 +36,7 @@ export default {
state.isLoading = false;
state.releases = [];
state.hasError = true;
+ state.restPageInfo = {};
+ state.graphQlPageInfo = {};
},
};
diff --git a/app/assets/javascripts/releases/stores/modules/list/state.js b/app/assets/javascripts/releases/stores/modules/list/state.js
index 9fe313745fc..0bffaa0f9db 100644
--- a/app/assets/javascripts/releases/stores/modules/list/state.js
+++ b/app/assets/javascripts/releases/stores/modules/list/state.js
@@ -14,5 +14,6 @@ export default ({
isLoading: false,
hasError: false,
releases: [],
- pageInfo: {},
+ restPageInfo: {},
+ graphQlPageInfo: {},
});
diff --git a/app/assets/javascripts/releases/util.js b/app/assets/javascripts/releases/util.js
index d7fac7a9b65..445c429fd96 100644
--- a/app/assets/javascripts/releases/util.js
+++ b/app/assets/javascripts/releases/util.js
@@ -107,7 +107,24 @@ const convertMilestones = graphQLRelease => ({
});
/**
- * Converts the response from the GraphQL endpoint into the
+ * Converts a single release object fetched from GraphQL
+ * into a release object that matches the shape of the REST API
+ * (the same shape that is returned by `apiJsonToRelease` above.)
+ *
+ * @param graphQLRelease The release object returned from a GraphQL query
+ */
+export const convertGraphQLRelease = graphQLRelease => ({
+ ...convertScalarProperties(graphQLRelease),
+ ...convertAssets(graphQLRelease),
+ ...convertEvidences(graphQLRelease),
+ ...convertLinks(graphQLRelease),
+ ...convertCommit(graphQLRelease),
+ ...convertAuthor(graphQLRelease),
+ ...convertMilestones(graphQLRelease),
+});
+
+/**
+ * Converts the response from all_releases.query.graphql into the
* same shape as is returned from the Releases REST API.
*
* This allows the release components to use the response
@@ -115,16 +132,27 @@ const convertMilestones = graphQLRelease => ({
*
* @param response The response received from the GraphQL endpoint
*/
-export const convertGraphQLResponse = response => {
- const releases = response.data.project.releases.nodes.map(r => ({
- ...convertScalarProperties(r),
- ...convertAssets(r),
- ...convertEvidences(r),
- ...convertLinks(r),
- ...convertCommit(r),
- ...convertAuthor(r),
- ...convertMilestones(r),
- }));
-
- return { data: releases };
+export const convertAllReleasesGraphQLResponse = response => {
+ const releases = response.data.project.releases.nodes.map(convertGraphQLRelease);
+
+ const paginationInfo = {
+ ...response.data.project.releases.pageInfo,
+ };
+
+ return { data: releases, paginationInfo };
+};
+
+/**
+ * Converts the response from one_release.query.graphql into the
+ * same shape as is returned from the Releases REST API.
+ *
+ * This allows the release components to use the response
+ * from either endpoint interchangeably.
+ *
+ * @param response The response received from the GraphQL endpoint
+ */
+export const convertOneReleaseGraphQLResponse = response => {
+ const release = convertGraphQLRelease(response.data.project.release);
+
+ return { data: release };
};
diff --git a/app/assets/javascripts/repository/components/breadcrumbs.vue b/app/assets/javascripts/repository/components/breadcrumbs.vue
index 74437f286b4..677cb265942 100644
--- a/app/assets/javascripts/repository/components/breadcrumbs.vue
+++ b/app/assets/javascripts/repository/components/breadcrumbs.vue
@@ -1,9 +1,9 @@
<script>
import {
- GlDeprecatedDropdown,
- GlDeprecatedDropdownDivider,
- GlDeprecatedDropdownHeader,
- GlDeprecatedDropdownItem,
+ GlDropdown,
+ GlDropdownDivider,
+ GlDropdownSectionHeader,
+ GlDropdownItem,
GlIcon,
} from '@gitlab/ui';
import { joinPaths, escapeFileUrl } from '~/lib/utils/url_utility';
@@ -20,10 +20,10 @@ const ROW_TYPES = {
export default {
components: {
- GlDeprecatedDropdown,
- GlDeprecatedDropdownDivider,
- GlDeprecatedDropdownHeader,
- GlDeprecatedDropdownItem,
+ GlDropdown,
+ GlDropdownDivider,
+ GlDropdownSectionHeader,
+ GlDropdownItem,
GlIcon,
},
apollo: {
@@ -226,11 +226,11 @@ export default {
getComponent(type) {
switch (type) {
case ROW_TYPES.divider:
- return 'gl-deprecated-dropdown-divider';
+ return 'gl-dropdown-divider';
case ROW_TYPES.header:
- return 'gl-deprecated-dropdown-header';
+ return 'gl-dropdown-section-header';
default:
- return 'gl-deprecated-dropdown-item';
+ return 'gl-dropdown-item';
}
},
},
@@ -246,7 +246,7 @@ export default {
</router-link>
</li>
<li v-if="renderAddToTreeDropdown" class="breadcrumb-item">
- <gl-deprecated-dropdown toggle-class="add-to-tree qa-add-to-tree ml-1">
+ <gl-dropdown toggle-class="add-to-tree qa-add-to-tree gl-ml-2">
<template #button-content>
<span class="sr-only">{{ __('Add to tree') }}</span>
<gl-icon name="plus" :size="16" class="float-left" />
@@ -257,7 +257,7 @@ export default {
{{ item.text }}
</component>
</template>
- </gl-deprecated-dropdown>
+ </gl-dropdown>
</li>
</ol>
</nav>
diff --git a/app/assets/javascripts/repository/components/last_commit.vue b/app/assets/javascripts/repository/components/last_commit.vue
index 59831890a4e..0e2bccfabdd 100644
--- a/app/assets/javascripts/repository/components/last_commit.vue
+++ b/app/assets/javascripts/repository/components/last_commit.vue
@@ -1,7 +1,8 @@
<script>
/* eslint-disable vue/no-v-html */
-import { GlTooltipDirective, GlLink, GlDeprecatedButton, GlLoadingIcon, GlIcon } from '@gitlab/ui';
+import { GlTooltipDirective, GlLink, GlButton, GlButtonGroup, GlLoadingIcon } from '@gitlab/ui';
import defaultAvatarUrl from 'images/no_avatar.png';
+import pathLastCommitQuery from 'shared_queries/repository/path_last_commit.query.graphql';
import { sprintf, s__ } from '~/locale';
import UserAvatarLink from '../../vue_shared/components/user_avatar/user_avatar_link.vue';
import TimeagoTooltip from '../../vue_shared/components/time_ago_tooltip.vue';
@@ -9,17 +10,16 @@ import CiIcon from '../../vue_shared/components/ci_icon.vue';
import ClipboardButton from '../../vue_shared/components/clipboard_button.vue';
import getRefMixin from '../mixins/get_ref';
import projectPathQuery from '../queries/project_path.query.graphql';
-import pathLastCommitQuery from '../queries/path_last_commit.query.graphql';
export default {
components: {
- GlIcon,
UserAvatarLink,
TimeagoTooltip,
ClipboardButton,
CiIcon,
+ GlButton,
+ GlButtonGroup,
GlLink,
- GlDeprecatedButton,
GlLoadingIcon,
},
directives: {
@@ -123,15 +123,14 @@ export default {
class="commit-row-message item-title"
v-html="commit.titleHtml"
/>
- <gl-deprecated-button
+ <gl-button
v-if="commit.descriptionHtml"
:class="{ open: showDescription }"
:aria-label="__('Show commit description')"
- class="text-expander"
+ class="text-expander gl-vertical-align-bottom!"
+ icon="ellipsis_h"
@click="toggleShowDescription"
- >
- <gl-icon name="ellipsis_h" :size="10" />
- </gl-deprecated-button>
+ />
<div class="committer">
<gl-link
v-if="commit.author"
@@ -169,16 +168,19 @@ export default {
/>
</gl-link>
</div>
- <div class="commit-sha-group d-flex">
- <div class="label label-monospace monospace">
- {{ showCommitId }}
- </div>
+ <gl-button-group class="gl-ml-4 js-commit-sha-group">
+ <gl-button
+ label
+ class="gl-font-monospace"
+ data-testid="last-commit-id-label"
+ v-text="showCommitId"
+ />
<clipboard-button
:text="commit.sha"
:title="__('Copy commit SHA')"
- tooltip-placement="bottom"
+ class="input-group-text"
/>
- </div>
+ </gl-button-group>
</div>
</div>
</template>
diff --git a/app/assets/javascripts/repository/components/preview/index.vue b/app/assets/javascripts/repository/components/preview/index.vue
index eca53f73a7f..4e2c8332f37 100644
--- a/app/assets/javascripts/repository/components/preview/index.vue
+++ b/app/assets/javascripts/repository/components/preview/index.vue
@@ -2,7 +2,7 @@
/* eslint-disable vue/no-v-html */
import $ from 'jquery';
import '~/behaviors/markdown/render_gfm';
-import { GlLink, GlLoadingIcon } from '@gitlab/ui';
+import { GlIcon, GlLink, GlLoadingIcon } from '@gitlab/ui';
import { handleLocationHash } from '~/lib/utils/common_utils';
import readmeQuery from '../../queries/readme.query.graphql';
@@ -19,6 +19,7 @@ export default {
},
},
components: {
+ GlIcon,
GlLink,
GlLoadingIcon,
},
@@ -51,7 +52,7 @@ export default {
<article class="file-holder limited-width-container readme-holder">
<div class="js-file-title file-title-flex-parent">
<div class="file-header-content">
- <i aria-hidden="true" class="fa fa-file-text-o fa-fw"></i>
+ <gl-icon name="doc-text" aria-hidden="true" />
<gl-link :href="blob.webPath">
<strong>{{ blob.name }}</strong>
</gl-link>
diff --git a/app/assets/javascripts/repository/components/tree_content.vue b/app/assets/javascripts/repository/components/tree_content.vue
index 365b6cbb550..78b8baaa75e 100644
--- a/app/assets/javascripts/repository/components/tree_content.vue
+++ b/app/assets/javascripts/repository/components/tree_content.vue
@@ -75,6 +75,7 @@ export default {
},
methods: {
fetchFiles() {
+ const originalPath = this.path || '/';
this.isLoadingFiles = true;
return this.$apollo
@@ -83,14 +84,14 @@ export default {
variables: {
projectPath: this.projectPath,
ref: this.ref,
- path: this.path || '/',
+ path: originalPath,
nextPageCursor: this.nextPageCursor,
pageSize: this.pageSize,
},
})
.then(({ data }) => {
if (data.errors) throw data.errors;
- if (!data?.project?.repository) return;
+ if (!data?.project?.repository || originalPath !== (this.path || '/')) return;
const pageInfo = this.hasNextPage(data.project.repository.tree);
diff --git a/app/assets/javascripts/repository/index.js b/app/assets/javascripts/repository/index.js
index 7f72524b6fe..a62b2d96c54 100644
--- a/app/assets/javascripts/repository/index.js
+++ b/app/assets/javascripts/repository/index.js
@@ -1,16 +1,17 @@
import Vue from 'vue';
-import { escapeFileUrl, joinPaths, webIDEUrl } from '../lib/utils/url_utility';
+import PathLastCommitQuery from 'shared_queries/repository/path_last_commit.query.graphql';
+import { escapeFileUrl } from '../lib/utils/url_utility';
import createRouter from './router';
import App from './components/app.vue';
import Breadcrumbs from './components/breadcrumbs.vue';
import LastCommit from './components/last_commit.vue';
import TreeActionLink from './components/tree_action_link.vue';
-import WebIdeLink from '~/vue_shared/components/web_ide_link.vue';
+import initWebIdeLink from '~/pages/projects/shared/web_ide_link';
import DirectoryDownloadLinks from './components/directory_download_links.vue';
import apolloProvider from './graphql';
import { setTitle } from './utils/title';
import { updateFormAction } from './utils/dom';
-import { convertObjectPropsToCamelCase, parseBoolean } from '../lib/utils/common_utils';
+import { parseBoolean } from '../lib/utils/common_utils';
import { __ } from '../locale';
export default function setupVueRepositoryList() {
@@ -18,6 +19,10 @@ export default function setupVueRepositoryList() {
const { dataset } = el;
const { projectPath, projectShortPath, ref, escapedRef, fullName } = dataset;
const router = createRouter(projectPath, escapedRef);
+ const pathRegex = /-\/tree\/[^/]+\/(.+$)/;
+ const matches = window.location.href.match(pathRegex);
+
+ const currentRoutePath = matches ? matches[1] : '';
apolloProvider.clients.defaultClient.cache.writeData({
data: {
@@ -29,6 +34,43 @@ export default function setupVueRepositoryList() {
},
});
+ const initLastCommitApp = () =>
+ new Vue({
+ el: document.getElementById('js-last-commit'),
+ router,
+ apolloProvider,
+ render(h) {
+ return h(LastCommit, {
+ props: {
+ currentPath: this.$route.params.path,
+ },
+ });
+ },
+ });
+
+ if (window.gl.startup_graphql_calls) {
+ const query = window.gl.startup_graphql_calls.find(
+ call => call.operationName === 'pathLastCommit',
+ );
+ query.fetchCall
+ .then(res => res.json())
+ .then(res => {
+ apolloProvider.clients.defaultClient.writeQuery({
+ query: PathLastCommitQuery,
+ data: res.data,
+ variables: {
+ projectPath,
+ ref,
+ path: currentRoutePath,
+ },
+ });
+ })
+ .catch(() => {})
+ .finally(() => initLastCommitApp());
+ } else {
+ initLastCommitApp();
+ }
+
router.afterEach(({ params: { path } }) => {
setTitle(path, ref, fullName);
});
@@ -77,20 +119,6 @@ export default function setupVueRepositoryList() {
});
}
- // eslint-disable-next-line no-new
- new Vue({
- el: document.getElementById('js-last-commit'),
- router,
- apolloProvider,
- render(h) {
- return h(LastCommit, {
- props: {
- currentPath: this.$route.params.path,
- },
- });
- },
- });
-
const treeHistoryLinkEl = document.getElementById('js-tree-history-link');
const { historyLink } = treeHistoryLinkEl.dataset;
@@ -110,29 +138,7 @@ export default function setupVueRepositoryList() {
},
});
- const webIdeLinkEl = document.getElementById('js-tree-web-ide-link');
-
- if (webIdeLinkEl) {
- const { ideBasePath, ...options } = convertObjectPropsToCamelCase(
- JSON.parse(webIdeLinkEl.dataset.options),
- );
-
- // eslint-disable-next-line no-new
- new Vue({
- el: webIdeLinkEl,
- router,
- render(h) {
- return h(WebIdeLink, {
- props: {
- webIdeUrl: webIDEUrl(
- joinPaths('/', ideBasePath, 'edit', ref, '-', this.$route.params.path || '', '/'),
- ),
- ...options,
- },
- });
- },
- });
- }
+ initWebIdeLink({ el: document.getElementById('js-tree-web-ide-link'), router });
const directoryDownloadLinks = document.getElementById('js-directory-downloads');
diff --git a/app/assets/javascripts/repository/log_tree.js b/app/assets/javascripts/repository/log_tree.js
index 361e0b62bb7..fc8fa40a855 100644
--- a/app/assets/javascripts/repository/log_tree.js
+++ b/app/assets/javascripts/repository/log_tree.js
@@ -5,8 +5,8 @@ import commitsQuery from './queries/commits.query.graphql';
import projectPathQuery from './queries/project_path.query.graphql';
import refQuery from './queries/ref.query.graphql';
-let fetchpromise;
-let resolvers = [];
+const fetchpromises = {};
+const resolvers = {};
export function resolveCommit(commits, path, { resolve, entry }) {
const commit = commits.find(c => c.filePath === `${path}/${entry.name}` && c.type === entry.type);
@@ -18,15 +18,19 @@ export function resolveCommit(commits, path, { resolve, entry }) {
export function fetchLogsTree(client, path, offset, resolver = null) {
if (resolver) {
- resolvers.push(resolver);
+ if (!resolvers[path]) {
+ resolvers[path] = [resolver];
+ } else {
+ resolvers[path].push(resolver);
+ }
}
- if (fetchpromise) return fetchpromise;
+ if (fetchpromises[path]) return fetchpromises[path];
const { projectPath } = client.readQuery({ query: projectPathQuery });
const { escapedRef } = client.readQuery({ query: refQuery });
- fetchpromise = axios
+ fetchpromises[path] = axios
.get(
`${gon.relative_url_root}/${projectPath}/-/refs/${escapedRef}/logs_tree/${encodeURIComponent(
path.replace(/^\//, ''),
@@ -46,16 +50,16 @@ export function fetchLogsTree(client, path, offset, resolver = null) {
data,
});
- resolvers.forEach(r => resolveCommit(data.commits, path, r));
+ resolvers[path].forEach(r => resolveCommit(data.commits, path, r));
- fetchpromise = null;
+ delete fetchpromises[path];
if (headerLogsOffset) {
fetchLogsTree(client, path, headerLogsOffset);
} else {
- resolvers = [];
+ delete resolvers[path];
}
});
- return fetchpromise;
+ return fetchpromises[path];
}
diff --git a/app/assets/javascripts/repository/queries/path_last_commit.query.graphql b/app/assets/javascripts/repository/queries/path_last_commit.query.graphql
deleted file mode 100644
index 51f3f790a5d..00000000000
--- a/app/assets/javascripts/repository/queries/path_last_commit.query.graphql
+++ /dev/null
@@ -1,38 +0,0 @@
-query pathLastCommit($projectPath: ID!, $path: String, $ref: String!) {
- project(fullPath: $projectPath) {
- repository {
- tree(path: $path, ref: $ref) {
- lastCommit {
- sha
- title
- titleHtml
- descriptionHtml
- message
- webPath
- authoredDate
- authorName
- authorGravatar
- author {
- name
- avatarUrl
- webPath
- }
- signatureHtml
- pipelines(ref: $ref, first: 1) {
- edges {
- node {
- detailedStatus {
- detailsPath
- icon
- tooltip
- text
- group
- }
- }
- }
- }
- }
- }
- }
- }
-}
diff --git a/app/assets/javascripts/repository/utils/icon.js b/app/assets/javascripts/repository/utils/icon.js
deleted file mode 100644
index 47b045c7eaf..00000000000
--- a/app/assets/javascripts/repository/utils/icon.js
+++ /dev/null
@@ -1,98 +0,0 @@
-const entryTypeIcons = {
- tree: 'folder',
- commit: 'archive',
-};
-
-const fileTypeIcons = [
- { extensions: ['pdf'], name: 'file-pdf-o' },
- {
- extensions: [
- 'jpg',
- 'jpeg',
- 'jif',
- 'jfif',
- 'jp2',
- 'jpx',
- 'j2k',
- 'j2c',
- 'png',
- 'gif',
- 'tif',
- 'tiff',
- 'svg',
- 'ico',
- 'bmp',
- ],
- name: 'file-image-o',
- },
- {
- extensions: ['zip', 'zipx', 'tar', 'gz', 'bz', 'bzip', 'xz', 'rar', '7z'],
- name: 'file-archive-o',
- },
- { extensions: ['mp3', 'wma', 'ogg', 'oga', 'wav', 'flac', 'aac'], name: 'file-audio-o' },
- {
- extensions: [
- 'mp4',
- 'm4p',
- 'm4v',
- 'mpg',
- 'mp2',
- 'mpeg',
- 'mpe',
- 'mpv',
- 'm2v',
- 'avi',
- 'mkv',
- 'flv',
- 'ogv',
- 'mov',
- '3gp',
- '3g2',
- ],
- name: 'file-video-o',
- },
- { extensions: ['doc', 'dot', 'docx', 'docm', 'dotx', 'dotm', 'docb'], name: 'file-word-o' },
- {
- extensions: [
- 'xls',
- 'xlt',
- 'xlm',
- 'xlsx',
- 'xlsm',
- 'xltx',
- 'xltm',
- 'xlsb',
- 'xla',
- 'xlam',
- 'xll',
- 'xlw',
- ],
- name: 'file-excel-o',
- },
- {
- extensions: [
- 'ppt',
- 'pot',
- 'pps',
- 'pptx',
- 'pptm',
- 'potx',
- 'potm',
- 'ppam',
- 'ppsx',
- 'ppsm',
- 'sldx',
- 'sldm',
- ],
- name: 'file-powerpoint-o',
- },
-];
-
-export const getIconName = (type, path) => {
- if (entryTypeIcons[type]) return entryTypeIcons[type];
-
- const extension = path.split('.').pop();
- const file = fileTypeIcons.find(t => t.extensions.some(ext => ext === extension));
-
- return file ? file.name : 'file-text-o';
-};
diff --git a/app/assets/javascripts/right_sidebar.js b/app/assets/javascripts/right_sidebar.js
index 8bebd16ace7..87c8aa541d8 100644
--- a/app/assets/javascripts/right_sidebar.js
+++ b/app/assets/javascripts/right_sidebar.js
@@ -5,6 +5,7 @@ import Cookies from 'js-cookie';
import { deprecatedCreateFlash as flash } from './flash';
import axios from './lib/utils/axios_utils';
import { sprintf, s__, __ } from './locale';
+import { fixTitle, hide } from '~/tooltips';
function Sidebar() {
this.toggleTodo = this.toggleTodo.bind(this);
@@ -42,13 +43,17 @@ Sidebar.prototype.addEventListeners = function() {
Sidebar.prototype.sidebarToggleClicked = function(e, triggered) {
const $this = $(this);
- const isExpanded = $this.find('i').hasClass('fa-angle-double-right');
+ const $collapseIcon = $('.js-sidebar-collapse');
+ const $expandIcon = $('.js-sidebar-expand');
+ const $toggleContainer = $('.js-sidebar-toggle-container');
+ const isExpanded = $toggleContainer.data('is-expanded');
const tooltipLabel = isExpanded ? __('Expand sidebar') : __('Collapse sidebar');
- const $allGutterToggleIcons = $('.js-sidebar-toggle i');
e.preventDefault();
if (isExpanded) {
- $allGutterToggleIcons.removeClass('fa-angle-double-right').addClass('fa-angle-double-left');
+ $toggleContainer.data('is-expanded', false);
+ $collapseIcon.addClass('hidden');
+ $expandIcon.removeClass('hidden');
$('aside.right-sidebar')
.removeClass('right-sidebar-expanded')
.addClass('right-sidebar-collapsed');
@@ -56,7 +61,9 @@ Sidebar.prototype.sidebarToggleClicked = function(e, triggered) {
.removeClass('right-sidebar-expanded')
.addClass('right-sidebar-collapsed');
} else {
- $allGutterToggleIcons.removeClass('fa-angle-double-left').addClass('fa-angle-double-right');
+ $toggleContainer.data('is-expanded', true);
+ $expandIcon.addClass('hidden');
+ $collapseIcon.removeClass('hidden');
$('aside.right-sidebar')
.removeClass('right-sidebar-collapsed')
.addClass('right-sidebar-expanded');
@@ -77,7 +84,7 @@ Sidebar.prototype.toggleTodo = function(e) {
const ajaxType = $this.data('deletePath') ? 'delete' : 'post';
const url = String($this.data('deletePath') || $this.data('createPath'));
- $this.tooltip('hide');
+ hide($this);
$('.js-issuable-todo')
.disable()
@@ -119,7 +126,7 @@ Sidebar.prototype.todoUpdateDone = function(data) {
.data('deletePath', deletePath);
if ($el.hasClass('has-tooltip')) {
- $el.tooltip('_fixTitle');
+ fixTitle($el);
}
if (typeof $el.data('isCollapsed') !== 'undefined') {
diff --git a/app/assets/javascripts/search/dropdown_filter/components/dropdown_filter.vue b/app/assets/javascripts/search/dropdown_filter/components/dropdown_filter.vue
new file mode 100644
index 00000000000..b6e2dd46358
--- /dev/null
+++ b/app/assets/javascripts/search/dropdown_filter/components/dropdown_filter.vue
@@ -0,0 +1,100 @@
+<script>
+import { mapState } from 'vuex';
+import { GlDropdown, GlDropdownItem, GlDropdownDivider } from '@gitlab/ui';
+import { setUrlParams, visitUrl } from '~/lib/utils/url_utility';
+import { sprintf, s__ } from '~/locale';
+
+export default {
+ name: 'DropdownFilter',
+ components: {
+ GlDropdown,
+ GlDropdownItem,
+ GlDropdownDivider,
+ },
+ props: {
+ filterData: {
+ type: Object,
+ required: true,
+ },
+ },
+ computed: {
+ ...mapState(['query']),
+ scope() {
+ return this.query.scope;
+ },
+ supportedScopes() {
+ return Object.values(this.filterData.scopes);
+ },
+ initialFilter() {
+ return this.query[this.filterData.filterParam];
+ },
+ filter() {
+ return this.initialFilter || this.filterData.filters.ANY.value;
+ },
+ filtersArray() {
+ return this.filterData.filterByScope[this.scope];
+ },
+ selectedFilter: {
+ get() {
+ if (this.filtersArray.some(({ value }) => value === this.filter)) {
+ return this.filter;
+ }
+
+ return this.filterData.filters.ANY.value;
+ },
+ set(filter) {
+ visitUrl(setUrlParams({ [this.filterData.filterParam]: filter }));
+ },
+ },
+ selectedFilterText() {
+ const f = this.filtersArray.find(({ value }) => value === this.selectedFilter);
+ if (!f || f === this.filterData.filters.ANY) {
+ return sprintf(s__('Any %{header}'), { header: this.filterData.header });
+ }
+
+ return f.label;
+ },
+ showDropdown() {
+ return this.supportedScopes.includes(this.scope);
+ },
+ },
+ methods: {
+ dropDownItemClass(filter) {
+ return {
+ 'gl-border-b-solid gl-border-b-gray-100 gl-border-b-1 gl-pb-2! gl-mb-2':
+ filter === this.filterData.filters.ANY,
+ };
+ },
+ isFilterSelected(filter) {
+ return filter === this.selectedFilter;
+ },
+ handleFilterChange(filter) {
+ this.selectedFilter = filter;
+ },
+ },
+};
+</script>
+
+<template>
+ <gl-dropdown
+ v-if="showDropdown"
+ :text="selectedFilterText"
+ class="col-3 gl-pt-4 gl-pl-0 gl-pr-0 gl-mr-4"
+ menu-class="gl-w-full! gl-pl-0"
+ >
+ <header class="gl-text-center gl-font-weight-bold gl-font-lg">
+ {{ filterData.header }}
+ </header>
+ <gl-dropdown-divider />
+ <gl-dropdown-item
+ v-for="f in filtersArray"
+ :key="f.value"
+ :is-check-item="true"
+ :is-checked="isFilterSelected(f.value)"
+ :class="dropDownItemClass(f)"
+ @click="handleFilterChange(f.value)"
+ >
+ {{ f.label }}
+ </gl-dropdown-item>
+ </gl-dropdown>
+</template>
diff --git a/app/assets/javascripts/search/dropdown_filter/constants/confidential_filter_data.js b/app/assets/javascripts/search/dropdown_filter/constants/confidential_filter_data.js
new file mode 100644
index 00000000000..b29daca89cb
--- /dev/null
+++ b/app/assets/javascripts/search/dropdown_filter/constants/confidential_filter_data.js
@@ -0,0 +1,36 @@
+import { __ } from '~/locale';
+
+const header = __('Confidentiality');
+
+const filters = {
+ ANY: {
+ label: __('Any'),
+ value: null,
+ },
+ CONFIDENTIAL: {
+ label: __('Confidential'),
+ value: 'yes',
+ },
+ NOT_CONFIDENTIAL: {
+ label: __('Not confidential'),
+ value: 'no',
+ },
+};
+
+const scopes = {
+ ISSUES: 'issues',
+};
+
+const filterByScope = {
+ [scopes.ISSUES]: [filters.ANY, filters.CONFIDENTIAL, filters.NOT_CONFIDENTIAL],
+};
+
+const filterParam = 'confidential';
+
+export default {
+ header,
+ filters,
+ scopes,
+ filterByScope,
+ filterParam,
+};
diff --git a/app/assets/javascripts/search/dropdown_filter/constants/state_filter_data.js b/app/assets/javascripts/search/dropdown_filter/constants/state_filter_data.js
new file mode 100644
index 00000000000..0b93aa0be29
--- /dev/null
+++ b/app/assets/javascripts/search/dropdown_filter/constants/state_filter_data.js
@@ -0,0 +1,42 @@
+import { __ } from '~/locale';
+
+const header = __('Status');
+
+const filters = {
+ ANY: {
+ label: __('Any'),
+ value: 'all',
+ },
+ OPEN: {
+ label: __('Open'),
+ value: 'opened',
+ },
+ CLOSED: {
+ label: __('Closed'),
+ value: 'closed',
+ },
+ MERGED: {
+ label: __('Merged'),
+ value: 'merged',
+ },
+};
+
+const scopes = {
+ ISSUES: 'issues',
+ MERGE_REQUESTS: 'merge_requests',
+};
+
+const filterByScope = {
+ [scopes.ISSUES]: [filters.ANY, filters.OPEN, filters.CLOSED],
+ [scopes.MERGE_REQUESTS]: [filters.ANY, filters.OPEN, filters.MERGED, filters.CLOSED],
+};
+
+const filterParam = 'state';
+
+export default {
+ header,
+ filters,
+ scopes,
+ filterByScope,
+ filterParam,
+};
diff --git a/app/assets/javascripts/search/dropdown_filter/index.js b/app/assets/javascripts/search/dropdown_filter/index.js
new file mode 100644
index 00000000000..e5e0745d990
--- /dev/null
+++ b/app/assets/javascripts/search/dropdown_filter/index.js
@@ -0,0 +1,38 @@
+import Vue from 'vue';
+import Translate from '~/vue_shared/translate';
+import DropdownFilter from './components/dropdown_filter.vue';
+import stateFilterData from './constants/state_filter_data';
+import confidentialFilterData from './constants/confidential_filter_data';
+
+Vue.use(Translate);
+
+const mountDropdownFilter = (store, { id, filterData }) => {
+ const el = document.getElementById(id);
+
+ if (!el) return false;
+
+ return new Vue({
+ el,
+ store,
+ render(createElement) {
+ return createElement(DropdownFilter, {
+ props: {
+ filterData,
+ },
+ });
+ },
+ });
+};
+
+const dropdownFilters = [
+ {
+ id: 'js-search-filter-by-state',
+ filterData: stateFilterData,
+ },
+ {
+ id: 'js-search-filter-by-confidential',
+ filterData: confidentialFilterData,
+ },
+];
+
+export default store => [...dropdownFilters].map(filter => mountDropdownFilter(store, filter));
diff --git a/app/assets/javascripts/search/index.js b/app/assets/javascripts/search/index.js
new file mode 100644
index 00000000000..780d3ff0d25
--- /dev/null
+++ b/app/assets/javascripts/search/index.js
@@ -0,0 +1,9 @@
+import { queryToObject } from '~/lib/utils/url_utility';
+import createStore from './store';
+import initDropdownFilters from './dropdown_filter';
+
+export default () => {
+ const store = createStore({ query: queryToObject(window.location.search) });
+
+ initDropdownFilters(store);
+};
diff --git a/app/assets/javascripts/search/state_filter/components/state_filter.vue b/app/assets/javascripts/search/state_filter/components/state_filter.vue
deleted file mode 100644
index f08adaf8c83..00000000000
--- a/app/assets/javascripts/search/state_filter/components/state_filter.vue
+++ /dev/null
@@ -1,94 +0,0 @@
-<script>
-import { GlDropdown, GlDropdownItem, GlDropdownDivider } from '@gitlab/ui';
-import {
- FILTER_STATES,
- SCOPES,
- FILTER_STATES_BY_SCOPE,
- FILTER_HEADER,
- FILTER_TEXT,
-} from '../constants';
-import { setUrlParams, visitUrl } from '~/lib/utils/url_utility';
-
-const FILTERS_ARRAY = Object.values(FILTER_STATES);
-
-export default {
- name: 'StateFilter',
- components: {
- GlDropdown,
- GlDropdownItem,
- GlDropdownDivider,
- },
- props: {
- scope: {
- type: String,
- required: true,
- },
- state: {
- type: String,
- required: false,
- default: FILTER_STATES.ANY.value,
- validator: v => FILTERS_ARRAY.some(({ value }) => value === v),
- },
- },
- computed: {
- selectedFilterText() {
- const filter = FILTERS_ARRAY.find(({ value }) => value === this.selectedFilter);
- if (!filter || filter === FILTER_STATES.ANY) {
- return FILTER_TEXT;
- }
-
- return filter.label;
- },
- showDropdown() {
- return Object.values(SCOPES).includes(this.scope);
- },
- selectedFilter: {
- get() {
- if (FILTERS_ARRAY.some(({ value }) => value === this.state)) {
- return this.state;
- }
-
- return FILTER_STATES.ANY.value;
- },
- set(state) {
- visitUrl(setUrlParams({ state }));
- },
- },
- },
- methods: {
- dropDownItemClass(filter) {
- return {
- 'gl-border-b-solid gl-border-b-gray-100 gl-border-b-1 gl-pb-2! gl-mb-2':
- filter === FILTER_STATES.ANY,
- };
- },
- isFilterSelected(filter) {
- return filter === this.selectedFilter;
- },
- handleFilterChange(state) {
- this.selectedFilter = state;
- },
- },
- filterStates: FILTER_STATES,
- filterHeader: FILTER_HEADER,
- filtersByScope: FILTER_STATES_BY_SCOPE,
-};
-</script>
-
-<template>
- <gl-dropdown v-if="showDropdown" :text="selectedFilterText" class="col-sm-3 gl-pt-4 gl-pl-0">
- <header class="gl-text-center gl-font-weight-bold gl-font-lg">
- {{ $options.filterHeader }}
- </header>
- <gl-dropdown-divider />
- <gl-dropdown-item
- v-for="filter in $options.filtersByScope[scope]"
- :key="filter.value"
- :is-check-item="true"
- :is-checked="isFilterSelected(filter.value)"
- :class="dropDownItemClass(filter)"
- @click="handleFilterChange(filter.value)"
- >{{ filter.label }}</gl-dropdown-item
- >
- </gl-dropdown>
-</template>
diff --git a/app/assets/javascripts/search/state_filter/constants.js b/app/assets/javascripts/search/state_filter/constants.js
deleted file mode 100644
index 2f11cab9044..00000000000
--- a/app/assets/javascripts/search/state_filter/constants.js
+++ /dev/null
@@ -1,39 +0,0 @@
-import { __ } from '~/locale';
-
-export const FILTER_HEADER = __('Status');
-
-export const FILTER_TEXT = __('Any Status');
-
-export const FILTER_STATES = {
- ANY: {
- label: __('Any'),
- value: 'all',
- },
- OPEN: {
- label: __('Open'),
- value: 'opened',
- },
- CLOSED: {
- label: __('Closed'),
- value: 'closed',
- },
- MERGED: {
- label: __('Merged'),
- value: 'merged',
- },
-};
-
-export const SCOPES = {
- ISSUES: 'issues',
- MERGE_REQUESTS: 'merge_requests',
-};
-
-export const FILTER_STATES_BY_SCOPE = {
- [SCOPES.ISSUES]: [FILTER_STATES.ANY, FILTER_STATES.OPEN, FILTER_STATES.CLOSED],
- [SCOPES.MERGE_REQUESTS]: [
- FILTER_STATES.ANY,
- FILTER_STATES.OPEN,
- FILTER_STATES.MERGED,
- FILTER_STATES.CLOSED,
- ],
-};
diff --git a/app/assets/javascripts/search/state_filter/index.js b/app/assets/javascripts/search/state_filter/index.js
deleted file mode 100644
index 13708574cfb..00000000000
--- a/app/assets/javascripts/search/state_filter/index.js
+++ /dev/null
@@ -1,34 +0,0 @@
-import Vue from 'vue';
-import Translate from '~/vue_shared/translate';
-import StateFilter from './components/state_filter.vue';
-
-Vue.use(Translate);
-
-export default () => {
- const el = document.getElementById('js-search-filter-by-state');
-
- if (!el) return false;
-
- return new Vue({
- el,
- components: {
- StateFilter,
- },
- data() {
- const { dataset } = this.$options.el;
- return {
- scope: dataset.scope,
- state: dataset.state,
- };
- },
-
- render(createElement) {
- return createElement('state-filter', {
- props: {
- scope: this.scope,
- state: this.state,
- },
- });
- },
- });
-};
diff --git a/app/assets/javascripts/search/store/index.js b/app/assets/javascripts/search/store/index.js
new file mode 100644
index 00000000000..10cfb647a92
--- /dev/null
+++ b/app/assets/javascripts/search/store/index.js
@@ -0,0 +1,12 @@
+import Vue from 'vue';
+import Vuex from 'vuex';
+import createState from './state';
+
+Vue.use(Vuex);
+
+export const getStoreConfig = ({ query }) => ({
+ state: createState({ query }),
+});
+
+const createStore = config => new Vuex.Store(getStoreConfig(config));
+export default createStore;
diff --git a/app/assets/javascripts/search/store/state.js b/app/assets/javascripts/search/store/state.js
new file mode 100644
index 00000000000..9115a613767
--- /dev/null
+++ b/app/assets/javascripts/search/store/state.js
@@ -0,0 +1,4 @@
+const createState = ({ query }) => ({
+ query,
+});
+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 1ccf5e9e032..6776a9ebb22 100644
--- a/app/assets/javascripts/self_monitor/components/self_monitor_form.vue
+++ b/app/assets/javascripts/self_monitor/components/self_monitor_form.vue
@@ -1,7 +1,7 @@
<script>
/* eslint-disable vue/no-v-html */
import Vue from 'vue';
-import { GlFormGroup, GlDeprecatedButton, GlModal, GlToast, GlToggle } from '@gitlab/ui';
+import { GlFormGroup, GlButton, GlModal, GlToast, GlToggle } from '@gitlab/ui';
import { mapState, mapActions } from 'vuex';
import { __, s__, sprintf } from '~/locale';
import { visitUrl, getBaseURL } from '~/lib/utils/url_utility';
@@ -11,7 +11,7 @@ Vue.use(GlToast);
export default {
components: {
GlFormGroup,
- GlDeprecatedButton,
+ GlButton,
GlModal,
GlToggle,
},
@@ -123,7 +123,7 @@ export default {
<h4 class="js-section-header">
{{ s__('SelfMonitoring|Self monitoring') }}
</h4>
- <gl-deprecated-button class="js-settings-toggle">{{ __('Expand') }}</gl-deprecated-button>
+ <gl-button class="js-settings-toggle">{{ __('Expand') }}</gl-button>
<p class="js-section-sub-header">
{{ s__('SelfMonitoring|Enable or disable instance self monitoring') }}
</p>
@@ -146,6 +146,7 @@ export default {
:ok-title="__('Delete project')"
:cancel-title="__('Cancel')"
ok-variant="danger"
+ category="primary"
@ok="deleteProject"
@cancel="hideSelfMonitorModal"
>
diff --git a/app/assets/javascripts/sentry/sentry_config.js b/app/assets/javascripts/sentry/sentry_config.js
index bc3b2f16a6a..631d5448d1e 100644
--- a/app/assets/javascripts/sentry/sentry_config.js
+++ b/app/assets/javascripts/sentry/sentry_config.js
@@ -1,5 +1,5 @@
-import * as Sentry from '@sentry/browser';
import $ from 'jquery';
+import * as Sentry from '~/sentry/wrapper';
import { __ } from '~/locale';
const IGNORE_ERRORS = [
diff --git a/app/assets/javascripts/sentry/wrapper.js b/app/assets/javascripts/sentry/wrapper.js
new file mode 100644
index 00000000000..24039e6141c
--- /dev/null
+++ b/app/assets/javascripts/sentry/wrapper.js
@@ -0,0 +1,26 @@
+// Temporarily commented out to investigate performance: https://gitlab.com/gitlab-org/gitlab/-/issues/251179
+// export * from '@sentry/browser';
+
+export function init(...args) {
+ return args;
+}
+
+export function setUser(...args) {
+ return args;
+}
+
+export function captureException(...args) {
+ return args;
+}
+
+export function captureMessage(...args) {
+ return args;
+}
+
+export function withScope(fn) {
+ fn({
+ setTag(...args) {
+ return args;
+ },
+ });
+}
diff --git a/app/assets/javascripts/serverless/components/functions.vue b/app/assets/javascripts/serverless/components/functions.vue
index e15549f5864..d662cc7b802 100644
--- a/app/assets/javascripts/serverless/components/functions.vue
+++ b/app/assets/javascripts/serverless/components/functions.vue
@@ -1,7 +1,6 @@
<script>
-/* eslint-disable vue/no-v-html */
import { mapState, mapActions, mapGetters } from 'vuex';
-import { GlLink, GlLoadingIcon } from '@gitlab/ui';
+import { GlLink, GlLoadingIcon, GlSafeHtmlDirective as SafeHtml } from '@gitlab/ui';
import { sprintf, s__ } from '~/locale';
import EnvironmentRow from './environment_row.vue';
import EmptyState from './empty_state.vue';
@@ -14,6 +13,9 @@ export default {
GlLink,
GlLoadingIcon,
},
+ directives: {
+ SafeHtml,
+ },
computed: {
...mapState(['installed', 'isLoading', 'hasFunctionData', 'helpPath', 'statusPath']),
...mapGetters(['getFunctions']),
@@ -92,9 +94,9 @@ export default {
}}
</p>
<ul>
- <li v-html="noServerlessConfigFile"></li>
- <li v-html="noGitlabYamlConfigured"></li>
- <li v-html="mismatchedServerlessFunctions"></li>
+ <li v-safe-html="noServerlessConfigFile"></li>
+ <li v-safe-html="noGitlabYamlConfigured"></li>
+ <li v-safe-html="mismatchedServerlessFunctions"></li>
<li>{{ s__('Serverless|The deploy job has not finished.') }}</li>
</ul>
diff --git a/app/assets/javascripts/serverless/components/missing_prometheus.vue b/app/assets/javascripts/serverless/components/missing_prometheus.vue
index 0d2c9f5151c..0b83d4b36eb 100644
--- a/app/assets/javascripts/serverless/components/missing_prometheus.vue
+++ b/app/assets/javascripts/serverless/components/missing_prometheus.vue
@@ -1,11 +1,11 @@
<script>
-import { GlDeprecatedButton, GlLink } from '@gitlab/ui';
+import { GlButton, GlLink } from '@gitlab/ui';
import { mapState } from 'vuex';
import { s__ } from '../../locale';
export default {
components: {
- GlDeprecatedButton,
+ GlButton,
GlLink,
},
props: {
@@ -47,9 +47,9 @@ export default {
</p>
<div v-if="!missingData" class="text-left">
- <gl-deprecated-button :href="clustersPath" variant="success">
+ <gl-button :href="clustersPath" variant="success" category="primary">
{{ s__('ServerlessDetails|Install Prometheus') }}
- </gl-deprecated-button>
+ </gl-button>
</div>
</div>
</div>
diff --git a/app/assets/javascripts/serverless/components/url.vue b/app/assets/javascripts/serverless/components/url.vue
index d6de5e56a5c..79a1f39c7dd 100644
--- a/app/assets/javascripts/serverless/components/url.vue
+++ b/app/assets/javascripts/serverless/components/url.vue
@@ -16,7 +16,9 @@ export default {
<template>
<div class="clipboard-group">
- <div class="url-text-field label label-monospace monospace">{{ uri }}</div>
+ <div class="gl-cursor-text label label-monospace monospace" data-testid="url-text-field">
+ {{ uri }}
+ </div>
<clipboard-button
:text="uri"
:title="s__('ServerlessURL|Copy URL')"
diff --git a/app/assets/javascripts/shared/milestones/form.js b/app/assets/javascripts/shared/milestones/form.js
index 9ee02f923d5..0ff84dc4667 100644
--- a/app/assets/javascripts/shared/milestones/form.js
+++ b/app/assets/javascripts/shared/milestones/form.js
@@ -16,6 +16,5 @@ export default (initGFM = true) => {
milestones: initGFM,
labels: initGFM,
snippets: initGFM,
- vulnerabilities: initGFM,
});
};
diff --git a/app/assets/javascripts/sidebar/components/assignees/assignee_title.vue b/app/assets/javascripts/sidebar/components/assignees/assignee_title.vue
index 5c67e429383..20dc7cb07e7 100644
--- a/app/assets/javascripts/sidebar/components/assignees/assignee_title.vue
+++ b/app/assets/javascripts/sidebar/components/assignees/assignee_title.vue
@@ -1,11 +1,12 @@
<script>
-import { GlLoadingIcon } from '@gitlab/ui';
-import { n__ } from '~/locale';
+import { GlLoadingIcon, GlIcon } from '@gitlab/ui';
+import { n__, __ } from '~/locale';
export default {
name: 'AssigneeTitle',
components: {
GlLoadingIcon,
+ GlIcon,
},
props: {
loading: {
@@ -26,12 +27,19 @@ export default {
required: false,
default: false,
},
+ changing: {
+ type: Boolean,
+ required: true,
+ },
},
computed: {
assigneeTitle() {
const assignees = this.numberOfAssignees;
return n__('Assignee', `%d Assignees`, assignees);
},
+ titleCopy() {
+ return this.changing ? __('Apply') : __('Edit');
+ },
},
};
</script>
@@ -43,11 +51,12 @@ export default {
v-if="editable"
class="js-sidebar-dropdown-toggle edit-link float-right"
href="#"
+ data-test-id="edit-link"
data-track-event="click_edit_button"
data-track-label="right_sidebar"
data-track-property="assignee"
>
- {{ __('Edit') }}
+ {{ titleCopy }}
</a>
<a
v-if="showToggle"
@@ -56,7 +65,7 @@ export default {
href="#"
role="button"
>
- <i aria-hidden="true" data-hidden="true" class="fa fa-angle-double-right"></i>
+ <gl-icon aria-hidden="true" data-hidden="true" name="chevron-double-lg-right" :size="12" />
</a>
</div>
</template>
diff --git a/app/assets/javascripts/sidebar/components/assignees/sidebar_assignees.vue b/app/assets/javascripts/sidebar/components/assignees/sidebar_assignees.vue
index 2f714ac3847..b9f268629fb 100644
--- a/app/assets/javascripts/sidebar/components/assignees/sidebar_assignees.vue
+++ b/app/assets/javascripts/sidebar/components/assignees/sidebar_assignees.vue
@@ -56,6 +56,9 @@ export default {
// Note: Realtime is only available on issues right now, future support for MR wil be built later.
return this.glFeatures.realTimeIssueSidebar && this.issuableType === 'issue';
},
+ relativeUrlRoot() {
+ return gon.relative_url_root ?? '';
+ },
},
created() {
this.removeAssignee = this.store.removeAssignee.bind(this.store);
@@ -89,6 +92,8 @@ export default {
.saveAssignees(this.field)
.then(() => {
this.loading = false;
+ this.store.resetChanging();
+
refreshUserMergeRequestCounts();
})
.catch(() => {
@@ -113,10 +118,11 @@ export default {
:loading="loading || store.isFetching.assignees"
:editable="store.editable"
:show-toggle="!signedIn"
+ :changing="store.changing"
/>
<assignees
v-if="!store.isFetching.assignees"
- :root-path="store.rootPath"
+ :root-path="relativeUrlRoot"
:users="store.assignees"
:editable="store.editable"
:issuable-type="issuableType"
diff --git a/app/assets/javascripts/sidebar/components/confidential/edit_form_buttons.vue b/app/assets/javascripts/sidebar/components/confidential/edit_form_buttons.vue
index 86bfacbfb9e..46d51138ccf 100644
--- a/app/assets/javascripts/sidebar/components/confidential/edit_form_buttons.vue
+++ b/app/assets/javascripts/sidebar/components/confidential/edit_form_buttons.vue
@@ -1,6 +1,6 @@
<script>
import $ from 'jquery';
-import { GlLoadingIcon } from '@gitlab/ui';
+import { GlButton } from '@gitlab/ui';
import { mapActions } from 'vuex';
import { __ } from '~/locale';
import { deprecatedCreateFlash as Flash } from '~/flash';
@@ -8,7 +8,7 @@ import eventHub from '../../event_hub';
export default {
components: {
- GlLoadingIcon,
+ GlButton,
},
props: {
fullPath: {
@@ -64,18 +64,18 @@ export default {
<template>
<div class="sidebar-item-warning-message-actions">
- <button type="button" class="btn btn-default gl-mr-3" @click="closeForm">
+ <gl-button class="gl-mr-3" @click="closeForm">
{{ __('Cancel') }}
- </button>
- <button
- type="button"
- class="btn btn-close"
- data-testid="confidential-toggle"
+ </gl-button>
+ <gl-button
+ category="secondary"
+ variant="warning"
:disabled="isLoading"
+ :loading="isLoading"
+ data-testid="confidential-toggle"
@click.prevent="submitForm"
>
- <gl-loading-icon v-if="isLoading" inline />
{{ toggleButtonText }}
- </button>
+ </gl-button>
</div>
</template>
diff --git a/app/assets/javascripts/sidebar/components/labels/sidebar_labels.vue b/app/assets/javascripts/sidebar/components/labels/sidebar_labels.vue
index d7be8927c29..1af1bc18e3e 100644
--- a/app/assets/javascripts/sidebar/components/labels/sidebar_labels.vue
+++ b/app/assets/javascripts/sidebar/components/labels/sidebar_labels.vue
@@ -1,7 +1,6 @@
<script>
import $ from 'jquery';
import { difference, union } from 'lodash';
-import { mapState, mapActions } from 'vuex';
import flash from '~/flash';
import axios from '~/lib/utils/axios_utils';
import { __ } from '~/locale';
@@ -26,47 +25,49 @@ export default {
'projectIssuesPath',
'projectPath',
],
- data: () => ({
- labelsSelectInProgress: false,
- }),
- computed: {
- ...mapState(['selectedLabels']),
- },
- mounted() {
- this.setInitialState({
+ data() {
+ return {
+ isLabelsSelectInProgress: false,
selectedLabels: this.initiallySelectedLabels,
- });
+ };
},
methods: {
- ...mapActions(['setInitialState', 'replaceSelectedLabels']),
handleDropdownClose() {
$(this.$el).trigger('hidden.gl.dropdown');
},
- handleUpdateSelectedLabels(labels) {
+ handleUpdateSelectedLabels(dropdownLabels) {
const currentLabelIds = this.selectedLabels.map(label => label.id);
- const userAddedLabelIds = labels.filter(label => label.set).map(label => label.id);
- const userRemovedLabelIds = labels.filter(label => !label.set).map(label => label.id);
+ const userAddedLabelIds = dropdownLabels.filter(label => label.set).map(label => label.id);
+ const userRemovedLabelIds = dropdownLabels.filter(label => !label.set).map(label => label.id);
- const issuableLabels = difference(
- union(currentLabelIds, userAddedLabelIds),
- userRemovedLabelIds,
- );
+ const labelIds = difference(union(currentLabelIds, userAddedLabelIds), userRemovedLabelIds);
- this.labelsSelectInProgress = true;
+ this.updateSelectedLabels(labelIds);
+ },
+ handleLabelRemove(labelId) {
+ const currentLabelIds = this.selectedLabels.map(label => label.id);
+ const labelIds = difference(currentLabelIds, [labelId]);
+
+ this.updateSelectedLabels(labelIds);
+ },
+ updateSelectedLabels(labelIds) {
+ this.isLabelsSelectInProgress = true;
axios({
data: {
[this.issuableType]: {
- label_ids: issuableLabels,
+ label_ids: labelIds,
},
},
method: 'put',
url: this.labelsUpdatePath,
})
- .then(({ data }) => this.replaceSelectedLabels(data.labels))
+ .then(({ data }) => {
+ this.selectedLabels = data.labels;
+ })
.catch(() => flash(__('An error occurred while updating labels.')))
.finally(() => {
- this.labelsSelectInProgress = false;
+ this.isLabelsSelectInProgress = false;
});
},
},
@@ -76,6 +77,7 @@ export default {
<template>
<labels-select
class="block labels js-labels-block"
+ :allow-label-remove="allowLabelEdit"
:allow-label-create="allowLabelCreate"
:allow-label-edit="allowLabelEdit"
:allow-multiselect="true"
@@ -86,10 +88,12 @@ export default {
:labels-fetch-path="labelsFetchPath"
:labels-filter-base-path="projectIssuesPath"
:labels-manage-path="labelsManagePath"
- :labels-select-in-progress="labelsSelectInProgress"
+ :labels-select-in-progress="isLabelsSelectInProgress"
:selected-labels="selectedLabels"
:variant="$options.sidebar"
+ data-qa-selector="labels_block"
@onDropdownClose="handleDropdownClose"
+ @onLabelRemove="handleLabelRemove"
@updateSelectedLabels="handleUpdateSelectedLabels"
>
{{ __('None') }}
diff --git a/app/assets/javascripts/sidebar/components/lock/edit_form_buttons.vue b/app/assets/javascripts/sidebar/components/lock/edit_form_buttons.vue
index ea7230ae488..26a7c8e4a80 100644
--- a/app/assets/javascripts/sidebar/components/lock/edit_form_buttons.vue
+++ b/app/assets/javascripts/sidebar/components/lock/edit_form_buttons.vue
@@ -1,6 +1,6 @@
<script>
import $ from 'jquery';
-import { GlLoadingIcon } from '@gitlab/ui';
+import { GlButton } from '@gitlab/ui';
import { mapActions } from 'vuex';
import { __, sprintf } from '../../../locale';
import { deprecatedCreateFlash as Flash } from '~/flash';
@@ -8,7 +8,7 @@ import eventHub from '../../event_hub';
export default {
components: {
- GlLoadingIcon,
+ GlButton,
},
inject: ['fullPath'],
props: {
@@ -65,19 +65,19 @@ export default {
<template>
<div class="sidebar-item-warning-message-actions">
- <button type="button" class="btn btn-default gl-mr-3" @click="closeForm">
+ <gl-button class="gl-mr-3" @click="closeForm">
{{ __('Cancel') }}
- </button>
+ </gl-button>
- <button
- type="button"
+ <gl-button
data-testid="lock-toggle"
- class="btn btn-close"
+ category="secondary"
+ variant="warning"
:disabled="isLoading"
+ :loading="isLoading"
@click.prevent="submitForm"
>
- <gl-loading-icon v-if="isLoading" inline />
{{ buttonText }}
- </button>
+ </gl-button>
</div>
</template>
diff --git a/app/assets/javascripts/sidebar/components/lock/issuable_lock_form.vue b/app/assets/javascripts/sidebar/components/lock/issuable_lock_form.vue
index 53ee7f46ad9..b96a2b93712 100644
--- a/app/assets/javascripts/sidebar/components/lock/issuable_lock_form.vue
+++ b/app/assets/javascripts/sidebar/components/lock/issuable_lock_form.vue
@@ -1,8 +1,7 @@
<script>
import { mapGetters } from 'vuex';
-import { GlIcon } from '@gitlab/ui';
+import { GlIcon, GlTooltipDirective } from '@gitlab/ui';
import { __ } from '~/locale';
-import tooltip from '~/vue_shared/directives/tooltip';
import eventHub from '~/sidebar/event_hub';
import editForm from './edit_form.vue';
@@ -26,7 +25,7 @@ export default {
},
directives: {
- tooltip,
+ GlTooltip: GlTooltipDirective,
},
props: {
@@ -79,13 +78,9 @@ export default {
<template>
<div class="block issuable-sidebar-item lock">
<div
- v-tooltip
- :title="tooltipLabel"
+ v-gl-tooltip.left.viewport="{ title: tooltipLabel }"
class="sidebar-collapsed-icon"
data-testid="sidebar-collapse-icon"
- data-container="body"
- data-placement="left"
- data-boundary="viewport"
@click="toggleForm"
>
<gl-icon :name="lockStatus.icon" class="sidebar-item-icon is-active" />
diff --git a/app/assets/javascripts/sidebar/components/participants/participants.vue b/app/assets/javascripts/sidebar/components/participants/participants.vue
index e7dbc47aea1..c3a08f760a0 100644
--- a/app/assets/javascripts/sidebar/components/participants/participants.vue
+++ b/app/assets/javascripts/sidebar/components/participants/participants.vue
@@ -1,12 +1,11 @@
<script>
-import { GlIcon, GlLoadingIcon } from '@gitlab/ui';
+import { GlIcon, GlLoadingIcon, GlTooltipDirective } from '@gitlab/ui';
import { __, n__, sprintf } from '~/locale';
-import tooltip from '~/vue_shared/directives/tooltip';
import userAvatarImage from '~/vue_shared/components/user_avatar/user_avatar_image.vue';
export default {
directives: {
- tooltip,
+ GlTooltip: GlTooltipDirective,
},
components: {
userAvatarImage,
@@ -87,12 +86,9 @@ export default {
<div>
<div
v-if="showParticipantLabel"
- v-tooltip
+ v-gl-tooltip.left.viewport
:title="participantLabel"
class="sidebar-collapsed-icon"
- data-container="body"
- data-placement="left"
- data-boundary="viewport"
@click="onClickCollapsedIcon"
>
<gl-icon name="users" />
diff --git a/app/assets/javascripts/sidebar/components/reviewers/collapsed_reviewer.vue b/app/assets/javascripts/sidebar/components/reviewers/collapsed_reviewer.vue
new file mode 100644
index 00000000000..6de926e0ff9
--- /dev/null
+++ b/app/assets/javascripts/sidebar/components/reviewers/collapsed_reviewer.vue
@@ -0,0 +1,24 @@
+<script>
+// NOTE! For the first iteration, we are simply copying the implementation of Assignees
+// It will soon be overhauled in Issue https://gitlab.com/gitlab-org/gitlab/-/issues/233736
+import ReviewerAvatar from './reviewer_avatar.vue';
+
+export default {
+ components: {
+ ReviewerAvatar,
+ },
+ props: {
+ user: {
+ type: Object,
+ required: true,
+ },
+ },
+};
+</script>
+
+<template>
+ <button type="button" class="btn-link">
+ <reviewer-avatar :user="user" :img-size="24" />
+ <span class="author"> {{ user.name }} </span>
+ </button>
+</template>
diff --git a/app/assets/javascripts/sidebar/components/reviewers/collapsed_reviewer_list.vue b/app/assets/javascripts/sidebar/components/reviewers/collapsed_reviewer_list.vue
new file mode 100644
index 00000000000..45707c18f7b
--- /dev/null
+++ b/app/assets/javascripts/sidebar/components/reviewers/collapsed_reviewer_list.vue
@@ -0,0 +1,107 @@
+<script>
+// NOTE! For the first iteration, we are simply copying the implementation of Assignees
+// It will soon be overhauled in Issue https://gitlab.com/gitlab-org/gitlab/-/issues/233736
+import { GlIcon, GlTooltipDirective } from '@gitlab/ui';
+import { __, sprintf } from '~/locale';
+import CollapsedReviewer from './collapsed_reviewer.vue';
+
+const DEFAULT_MAX_COUNTER = 99;
+const DEFAULT_RENDER_COUNT = 5;
+
+export default {
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ },
+ components: {
+ CollapsedReviewer,
+ GlIcon,
+ },
+ props: {
+ users: {
+ type: Array,
+ required: true,
+ },
+ },
+ computed: {
+ hasNoUsers() {
+ return !this.users.length;
+ },
+ hasMoreThanOneReviewer() {
+ return this.users.length > 1;
+ },
+ hasMoreThanTwoReviewers() {
+ return this.users.length > 2;
+ },
+ allReviewersCanMerge() {
+ return this.users.every(user => user.can_merge);
+ },
+ sidebarAvatarCounter() {
+ if (this.users.length > DEFAULT_MAX_COUNTER) {
+ return `${DEFAULT_MAX_COUNTER}+`;
+ }
+
+ return `+${this.users.length - 1}`;
+ },
+ collapsedUsers() {
+ const collapsedLength = this.hasMoreThanTwoReviewers ? 1 : this.users.length;
+
+ return this.users.slice(0, collapsedLength);
+ },
+ tooltipTitleMergeStatus() {
+ const mergeLength = this.users.filter(u => u.can_merge).length;
+
+ if (mergeLength === this.users.length) {
+ return '';
+ } else if (mergeLength > 0) {
+ return sprintf(__('%{mergeLength}/%{usersLength} can merge'), {
+ mergeLength,
+ usersLength: this.users.length,
+ });
+ }
+
+ return this.users.length === 1 ? __('cannot merge') : __('no one can merge');
+ },
+ tooltipTitle() {
+ const maxRender = Math.min(DEFAULT_RENDER_COUNT, this.users.length);
+ const renderUsers = this.users.slice(0, maxRender);
+ const names = renderUsers.map(u => u.name);
+
+ if (!this.users.length) {
+ return __('Reviewer(s)');
+ }
+
+ if (this.users.length > names.length) {
+ names.push(sprintf(__('+ %{amount} more'), { amount: this.users.length - names.length }));
+ }
+
+ const text = names.join(', ');
+
+ return this.tooltipTitleMergeStatus ? `${text} (${this.tooltipTitleMergeStatus})` : text;
+ },
+
+ tooltipOptions() {
+ return { container: 'body', placement: 'left', boundary: 'viewport' };
+ },
+ },
+};
+</script>
+
+<template>
+ <div
+ v-gl-tooltip="tooltipOptions"
+ :class="{ 'multiple-users': hasMoreThanOneReviewer }"
+ :title="tooltipTitle"
+ class="sidebar-collapsed-icon sidebar-collapsed-user"
+ >
+ <gl-icon v-if="hasNoUsers" name="user" :aria-label="__('None')" />
+ <collapsed-reviewer v-for="user in collapsedUsers" :key="user.id" :user="user" />
+ <button v-if="hasMoreThanTwoReviewers" class="btn-link" type="button">
+ <span class="avatar-counter sidebar-avatar-counter"> {{ sidebarAvatarCounter }} </span>
+ <i
+ v-if="!allReviewersCanMerge"
+ aria-hidden="true"
+ class="fa fa-exclamation-triangle merge-icon"
+ ></i>
+ </button>
+ </div>
+</template>
diff --git a/app/assets/javascripts/sidebar/components/reviewers/reviewer_avatar.vue b/app/assets/javascripts/sidebar/components/reviewers/reviewer_avatar.vue
new file mode 100644
index 00000000000..9fa3fa38eac
--- /dev/null
+++ b/app/assets/javascripts/sidebar/components/reviewers/reviewer_avatar.vue
@@ -0,0 +1,43 @@
+<script>
+// NOTE! For the first iteration, we are simply copying the implementation of Assignees
+// It will soon be overhauled in Issue https://gitlab.com/gitlab-org/gitlab/-/issues/233736
+import { __, sprintf } from '~/locale';
+
+export default {
+ props: {
+ user: {
+ type: Object,
+ required: true,
+ },
+ imgSize: {
+ type: Number,
+ required: true,
+ },
+ },
+ computed: {
+ reviewerAlt() {
+ return sprintf(__("%{userName}'s avatar"), { userName: this.user.name });
+ },
+ avatarUrl() {
+ return this.user.avatar || this.user.avatar_url || gon.default_avatar_url;
+ },
+ hasMergeIcon() {
+ return !this.user.can_merge;
+ },
+ },
+};
+</script>
+
+<template>
+ <span class="position-relative">
+ <img
+ :alt="reviewerAlt"
+ :src="avatarUrl"
+ :width="imgSize"
+ :class="`s${imgSize}`"
+ class="avatar avatar-inline m-0"
+ data-qa-selector="avatar_image"
+ />
+ <i v-if="hasMergeIcon" aria-hidden="true" class="fa fa-exclamation-triangle merge-icon"></i>
+ </span>
+</template>
diff --git a/app/assets/javascripts/sidebar/components/reviewers/reviewer_avatar_link.vue b/app/assets/javascripts/sidebar/components/reviewers/reviewer_avatar_link.vue
new file mode 100644
index 00000000000..b1b04564a62
--- /dev/null
+++ b/app/assets/javascripts/sidebar/components/reviewers/reviewer_avatar_link.vue
@@ -0,0 +1,84 @@
+<script>
+// NOTE! For the first iteration, we are simply copying the implementation of Assignees
+// It will soon be overhauled in Issue https://gitlab.com/gitlab-org/gitlab/-/issues/233736
+import { GlTooltipDirective, GlLink } from '@gitlab/ui';
+import { __, sprintf } from '~/locale';
+import ReviewerAvatar from './reviewer_avatar.vue';
+
+export default {
+ components: {
+ ReviewerAvatar,
+ GlLink,
+ },
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ },
+ props: {
+ user: {
+ type: Object,
+ required: true,
+ },
+ rootPath: {
+ type: String,
+ required: true,
+ },
+ tooltipPlacement: {
+ type: String,
+ default: 'bottom',
+ required: false,
+ },
+ tooltipHasName: {
+ type: Boolean,
+ default: true,
+ required: false,
+ },
+ issuableType: {
+ type: String,
+ default: 'issue',
+ required: false,
+ },
+ },
+ computed: {
+ cannotMerge() {
+ return this.issuableType === 'merge_request' && !this.user.can_merge;
+ },
+ tooltipTitle() {
+ if (this.cannotMerge && this.tooltipHasName) {
+ return sprintf(__('%{userName} (cannot merge)'), { userName: this.user.name });
+ } else if (this.cannotMerge) {
+ return __('Cannot merge');
+ } else if (this.tooltipHasName) {
+ return this.user.name;
+ }
+
+ return '';
+ },
+ tooltipOption() {
+ return {
+ container: 'body',
+ placement: this.tooltipPlacement,
+ boundary: 'viewport',
+ };
+ },
+ reviewerUrl() {
+ return this.user.web_url;
+ },
+ },
+};
+</script>
+
+<template>
+ <!-- must be `d-inline-block` or parent flex-basis causes width issues -->
+ <gl-link
+ v-gl-tooltip="tooltipOption"
+ :href="reviewerUrl"
+ :title="tooltipTitle"
+ class="d-inline-block"
+ >
+ <!-- use d-flex so that slot can be appropriately styled -->
+ <span class="d-flex">
+ <reviewer-avatar :user="user" :img-size="32" :issuable-type="issuableType" />
+ <slot :user="user"></slot>
+ </span>
+ </gl-link>
+</template>
diff --git a/app/assets/javascripts/sidebar/components/reviewers/reviewer_title.vue b/app/assets/javascripts/sidebar/components/reviewers/reviewer_title.vue
new file mode 100644
index 00000000000..4f4f7002dc9
--- /dev/null
+++ b/app/assets/javascripts/sidebar/components/reviewers/reviewer_title.vue
@@ -0,0 +1,65 @@
+<script>
+// NOTE! For the first iteration, we are simply copying the implementation of Assignees
+// It will soon be overhauled in Issue https://gitlab.com/gitlab-org/gitlab/-/issues/233736
+import { GlLoadingIcon, GlIcon } from '@gitlab/ui';
+import { n__ } from '~/locale';
+
+export default {
+ name: 'ReviewerTitle',
+ components: {
+ GlLoadingIcon,
+ GlIcon,
+ },
+ props: {
+ loading: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ numberOfReviewers: {
+ type: Number,
+ required: true,
+ },
+ editable: {
+ type: Boolean,
+ required: true,
+ },
+ showToggle: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ },
+ computed: {
+ reviewerTitle() {
+ const reviewers = this.numberOfReviewers;
+ return n__('Reviewer', `%d Reviewers`, reviewers);
+ },
+ },
+};
+</script>
+<template>
+ <div class="title hide-collapsed">
+ {{ reviewerTitle }}
+ <gl-loading-icon v-if="loading" inline class="align-bottom" />
+ <a
+ v-if="editable"
+ class="js-sidebar-dropdown-toggle edit-link float-right"
+ href="#"
+ data-track-event="click_edit_button"
+ data-track-label="right_sidebar"
+ data-track-property="reviewer"
+ >
+ {{ __('Edit') }}
+ </a>
+ <a
+ v-if="showToggle"
+ :aria-label="__('Toggle sidebar')"
+ class="gutter-toggle float-right js-sidebar-toggle"
+ href="#"
+ role="button"
+ >
+ <gl-icon aria-hidden="true" data-hidden="true" name="chevron-double-lg-right" :size="12" />
+ </a>
+ </div>
+</template>
diff --git a/app/assets/javascripts/sidebar/components/reviewers/reviewers.vue b/app/assets/javascripts/sidebar/components/reviewers/reviewers.vue
new file mode 100644
index 00000000000..6a3d88f6385
--- /dev/null
+++ b/app/assets/javascripts/sidebar/components/reviewers/reviewers.vue
@@ -0,0 +1,72 @@
+<script>
+// NOTE! For the first iteration, we are simply copying the implementation of Assignees
+// It will soon be overhauled in Issue https://gitlab.com/gitlab-org/gitlab/-/issues/233736
+import CollapsedReviewerList from './collapsed_reviewer_list.vue';
+import UncollapsedReviewerList from './uncollapsed_reviewer_list.vue';
+
+export default {
+ // name: 'Reviewers' is a false positive: https://gitlab.com/gitlab-org/frontend/eslint-plugin-i18n/issues/26#possible-false-positives
+ // eslint-disable-next-line @gitlab/require-i18n-strings
+ name: 'Reviewers',
+ components: {
+ CollapsedReviewerList,
+ UncollapsedReviewerList,
+ },
+ props: {
+ rootPath: {
+ type: String,
+ required: true,
+ },
+ users: {
+ type: Array,
+ required: true,
+ },
+ editable: {
+ type: Boolean,
+ required: true,
+ },
+ issuableType: {
+ type: String,
+ required: false,
+ default: 'issue',
+ },
+ },
+ computed: {
+ hasNoUsers() {
+ return !this.users.length;
+ },
+ sortedReviewers() {
+ const canMergeUsers = this.users.filter(user => user.can_merge);
+ const canNotMergeUsers = this.users.filter(user => !user.can_merge);
+
+ return [...canMergeUsers, ...canNotMergeUsers];
+ },
+ },
+ methods: {
+ assignSelf() {
+ this.$emit('assign-self');
+ },
+ },
+};
+</script>
+
+<template>
+ <div>
+ <collapsed-reviewer-list :users="sortedReviewers" :issuable-type="issuableType" />
+
+ <div class="value hide-collapsed">
+ <template v-if="hasNoUsers">
+ <span class="assign-yourself no-value qa-assign-yourself">
+ {{ __('None') }}
+ </span>
+ </template>
+
+ <uncollapsed-reviewer-list
+ v-else
+ :users="sortedReviewers"
+ :root-path="rootPath"
+ :issuable-type="issuableType"
+ />
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/sidebar/components/reviewers/sidebar_reviewers.vue b/app/assets/javascripts/sidebar/components/reviewers/sidebar_reviewers.vue
new file mode 100644
index 00000000000..aee94a55134
--- /dev/null
+++ b/app/assets/javascripts/sidebar/components/reviewers/sidebar_reviewers.vue
@@ -0,0 +1,112 @@
+<script>
+// NOTE! For the first iteration, we are simply copying the implementation of Assignees
+// It will soon be overhauled in Issue https://gitlab.com/gitlab-org/gitlab/-/issues/233736
+import { deprecatedCreateFlash as Flash } from '~/flash';
+import eventHub from '~/sidebar/event_hub';
+import Store from '~/sidebar/stores/sidebar_store';
+import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
+import ReviewerTitle from './reviewer_title.vue';
+import Reviewers from './reviewers.vue';
+import { __ } from '~/locale';
+
+export default {
+ name: 'SidebarReviewers',
+ components: {
+ ReviewerTitle,
+ Reviewers,
+ },
+ mixins: [glFeatureFlagsMixin()],
+ props: {
+ mediator: {
+ type: Object,
+ required: true,
+ },
+ field: {
+ type: String,
+ required: true,
+ },
+ signedIn: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ issuableType: {
+ type: String,
+ required: false,
+ default: 'issue',
+ },
+ issuableIid: {
+ type: String,
+ required: true,
+ },
+ projectPath: {
+ type: String,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ store: new Store(),
+ loading: false,
+ };
+ },
+ computed: {
+ relativeUrlRoot() {
+ return gon.relative_url_root ?? '';
+ },
+ },
+ created() {
+ this.removeReviewer = this.store.removeReviewer.bind(this.store);
+ this.addReviewer = this.store.addReviewer.bind(this.store);
+ this.removeAllReviewers = this.store.removeAllReviewers.bind(this.store);
+
+ // Get events from deprecatedJQueryDropdown
+ eventHub.$on('sidebar.removeReviewer', this.removeReviewer);
+ eventHub.$on('sidebar.addReviewer', this.addReviewer);
+ eventHub.$on('sidebar.removeAllReviewers', this.removeAllReviewers);
+ eventHub.$on('sidebar.saveReviewers', this.saveReviewers);
+ },
+ beforeDestroy() {
+ eventHub.$off('sidebar.removeReviewer', this.removeReviewer);
+ eventHub.$off('sidebar.addReviewer', this.addReviewer);
+ eventHub.$off('sidebar.removeAllReviewers', this.removeAllReviewers);
+ eventHub.$off('sidebar.saveReviewers', this.saveReviewers);
+ },
+ methods: {
+ saveReviewers() {
+ this.loading = true;
+
+ this.mediator
+ .saveReviewers(this.field)
+ .then(() => {
+ this.loading = false;
+ // Uncomment once this issue has been addressed > https://gitlab.com/gitlab-org/gitlab/-/issues/237922
+ // refreshUserMergeRequestCounts();
+ })
+ .catch(() => {
+ this.loading = false;
+ return new Flash(__('Error occurred when saving reviewers'));
+ });
+ },
+ },
+};
+</script>
+
+<template>
+ <div>
+ <reviewer-title
+ :number-of-reviewers="store.reviewers.length"
+ :loading="loading || store.isFetching.reviewers"
+ :editable="store.editable"
+ :show-toggle="!signedIn"
+ />
+ <reviewers
+ v-if="!store.isFetching.reviewers"
+ :root-path="relativeUrlRoot"
+ :users="store.reviewers"
+ :editable="store.editable"
+ :issuable-type="issuableType"
+ class="value"
+ />
+ </div>
+</template>
diff --git a/app/assets/javascripts/sidebar/components/reviewers/uncollapsed_reviewer_list.vue b/app/assets/javascripts/sidebar/components/reviewers/uncollapsed_reviewer_list.vue
new file mode 100644
index 00000000000..e82a271d007
--- /dev/null
+++ b/app/assets/javascripts/sidebar/components/reviewers/uncollapsed_reviewer_list.vue
@@ -0,0 +1,103 @@
+<script>
+// NOTE! For the first iteration, we are simply copying the implementation of Assignees
+// It will soon be overhauled in Issue https://gitlab.com/gitlab-org/gitlab/-/issues/233736
+import { __, sprintf } from '~/locale';
+import ReviewerAvatarLink from './reviewer_avatar_link.vue';
+
+const DEFAULT_RENDER_COUNT = 5;
+
+export default {
+ components: {
+ ReviewerAvatarLink,
+ },
+ props: {
+ users: {
+ type: Array,
+ required: true,
+ },
+ rootPath: {
+ type: String,
+ required: true,
+ },
+ issuableType: {
+ type: String,
+ required: false,
+ default: 'issue',
+ },
+ },
+ data() {
+ return {
+ showLess: true,
+ };
+ },
+ computed: {
+ firstUser() {
+ return this.users[0];
+ },
+ hasOneUser() {
+ return this.users.length === 1;
+ },
+ hiddenReviewersLabel() {
+ const { numberOfHiddenReviewers } = this;
+ return sprintf(__('+ %{numberOfHiddenReviewers} more'), { numberOfHiddenReviewers });
+ },
+ renderShowMoreSection() {
+ return this.users.length > DEFAULT_RENDER_COUNT;
+ },
+ numberOfHiddenReviewers() {
+ return this.users.length - DEFAULT_RENDER_COUNT;
+ },
+ uncollapsedUsers() {
+ const uncollapsedLength = this.showLess
+ ? Math.min(this.users.length, DEFAULT_RENDER_COUNT)
+ : this.users.length;
+ return this.showLess ? this.users.slice(0, uncollapsedLength) : this.users;
+ },
+ username() {
+ return `@${this.firstUser.username}`;
+ },
+ },
+ methods: {
+ toggleShowLess() {
+ this.showLess = !this.showLess;
+ },
+ },
+};
+</script>
+
+<template>
+ <reviewer-avatar-link
+ v-if="hasOneUser"
+ #default="{ user }"
+ tooltip-placement="left"
+ :tooltip-has-name="false"
+ :user="firstUser"
+ :root-path="rootPath"
+ :issuable-type="issuableType"
+ >
+ <div class="gl-ml-3 gl-line-height-normal">
+ <div class="author">{{ user.name }}</div>
+ <div class="username">{{ username }}</div>
+ </div>
+ </reviewer-avatar-link>
+ <div v-else>
+ <div class="user-list">
+ <div v-for="user in uncollapsedUsers" :key="user.id" class="user-item">
+ <reviewer-avatar-link :user="user" :root-path="rootPath" :issuable-type="issuableType" />
+ </div>
+ </div>
+ <div v-if="renderShowMoreSection" class="user-list-more">
+ <button
+ type="button"
+ class="btn-link"
+ data-qa-selector="more_reviewers_link"
+ @click="toggleShowLess"
+ >
+ <template v-if="showLess">
+ {{ hiddenReviewersLabel }}
+ </template>
+ <template v-else>{{ __('- show less') }}</template>
+ </button>
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/sidebar/components/time_tracking/collapsed_state.vue b/app/assets/javascripts/sidebar/components/time_tracking/collapsed_state.vue
index bc2319c0f36..9d72bf4394e 100644
--- a/app/assets/javascripts/sidebar/components/time_tracking/collapsed_state.vue
+++ b/app/assets/javascripts/sidebar/components/time_tracking/collapsed_state.vue
@@ -1,7 +1,6 @@
<script>
-import { GlIcon } from '@gitlab/ui';
+import { GlIcon, GlTooltipDirective } from '@gitlab/ui';
import { __, sprintf } from '~/locale';
-import tooltip from '~/vue_shared/directives/tooltip';
export default {
name: 'TimeTrackingCollapsedState',
@@ -9,7 +8,7 @@ export default {
GlIcon,
},
directives: {
- tooltip,
+ GlTooltip: GlTooltipDirective,
},
props: {
showComparisonState: {
@@ -97,14 +96,7 @@ export default {
</script>
<template>
- <div
- v-tooltip
- :title="tooltipText"
- class="sidebar-collapsed-icon"
- data-container="body"
- data-placement="left"
- data-boundary="viewport"
- >
+ <div v-gl-tooltip:body.viewport.left :title="tooltipText" class="sidebar-collapsed-icon">
<gl-icon name="timer" />
<div class="time-tracking-collapsed-summary">
<div :class="divClass">
diff --git a/app/assets/javascripts/sidebar/components/time_tracking/comparison_pane.vue b/app/assets/javascripts/sidebar/components/time_tracking/comparison_pane.vue
index 4cb8d9ebd62..d4cc98e3743 100644
--- a/app/assets/javascripts/sidebar/components/time_tracking/comparison_pane.vue
+++ b/app/assets/javascripts/sidebar/components/time_tracking/comparison_pane.vue
@@ -1,7 +1,6 @@
<script>
-import { GlProgressBar } from '@gitlab/ui';
+import { GlProgressBar, GlTooltipDirective } from '@gitlab/ui';
import { parseSeconds, stringifyTime } from '~/lib/utils/datetime_utility';
-import tooltip from '../../../vue_shared/directives/tooltip';
import { s__, sprintf } from '~/locale';
export default {
@@ -10,7 +9,7 @@ export default {
GlProgressBar,
},
directives: {
- tooltip,
+ GlTooltip: GlTooltipDirective,
},
props: {
timeSpent: {
@@ -73,7 +72,7 @@ export default {
<template>
<div class="time-tracking-comparison-pane">
<div
- v-tooltip
+ v-gl-tooltip
:title="timeRemainingTooltip"
:class="timeRemainingStatusClass"
class="compare-meter"
diff --git a/app/assets/javascripts/sidebar/components/time_tracking/sidebar_time_tracking.vue b/app/assets/javascripts/sidebar/components/time_tracking/sidebar_time_tracking.vue
index 05ad7b4ea3e..406677941b7 100644
--- a/app/assets/javascripts/sidebar/components/time_tracking/sidebar_time_tracking.vue
+++ b/app/assets/javascripts/sidebar/components/time_tracking/sidebar_time_tracking.vue
@@ -26,11 +26,14 @@ export default {
methods: {
listenForQuickActions() {
$(document).on('ajax:success', '.gfm-form', this.quickActionListened);
+
eventHub.$on('timeTrackingUpdated', data => {
- this.quickActionListened(null, data);
+ this.quickActionListened({ detail: [data] });
});
},
- quickActionListened(e, data) {
+ quickActionListened(e) {
+ const data = e.detail[0];
+
const subscribedCommands = ['spend_time', 'time_estimate'];
let changedCommands;
if (data !== undefined) {
diff --git a/app/assets/javascripts/sidebar/mount_sidebar.js b/app/assets/javascripts/sidebar/mount_sidebar.js
index be559b16420..00b4e2de5e5 100644
--- a/app/assets/javascripts/sidebar/mount_sidebar.js
+++ b/app/assets/javascripts/sidebar/mount_sidebar.js
@@ -1,10 +1,10 @@
import $ from 'jquery';
import Vue from 'vue';
import VueApollo from 'vue-apollo';
-import Vuex from 'vuex';
import SidebarTimeTracking from './components/time_tracking/sidebar_time_tracking.vue';
import SidebarAssignees from './components/assignees/sidebar_assignees.vue';
import SidebarLabels from './components/labels/sidebar_labels.vue';
+import SidebarReviewers from './components/reviewers/sidebar_reviewers.vue';
import ConfidentialIssueSidebar from './components/confidential/confidential_issue_sidebar.vue';
import SidebarMoveIssue from './lib/sidebar_move_issue';
import IssuableLockForm from './components/lock/issuable_lock_form.vue';
@@ -13,17 +13,15 @@ import sidebarSubscriptions from './components/subscriptions/sidebar_subscriptio
import SidebarSeverity from './components/severity/sidebar_severity.vue';
import Translate from '../vue_shared/translate';
import createDefaultClient from '~/lib/graphql';
-import { store } from '~/notes/stores';
-import { isInIssuePage, parseBoolean } from '~/lib/utils/common_utils';
-import mergeRequestStore from '~/mr_notes/stores';
-import labelsSelectModule from '~/vue_shared/components/sidebar/labels_select_vue/store';
+import { isInIssuePage, isInIncidentPage, parseBoolean } from '~/lib/utils/common_utils';
+import createFlash from '~/flash';
+import { __ } from '~/locale';
Vue.use(Translate);
Vue.use(VueApollo);
-Vue.use(Vuex);
-function getSidebarOptions() {
- return JSON.parse(document.querySelector('.js-sidebar-options').innerHTML);
+function getSidebarOptions(sidebarOptEl = document.querySelector('.js-sidebar-options')) {
+ return JSON.parse(sidebarOptEl.innerHTML);
}
function mountAssigneesComponent(mediator) {
@@ -50,6 +48,36 @@ function mountAssigneesComponent(mediator) {
projectPath: fullPath,
field: el.dataset.field,
signedIn: el.hasAttribute('data-signed-in'),
+ issuableType: isInIssuePage() || isInIncidentPage() ? 'issue' : 'merge_request',
+ },
+ }),
+ });
+}
+
+function mountReviewersComponent(mediator) {
+ const el = document.getElementById('js-vue-sidebar-reviewers');
+ const apolloProvider = new VueApollo({
+ defaultClient: createDefaultClient(),
+ });
+
+ if (!el) return;
+
+ const { iid, fullPath } = getSidebarOptions();
+ // eslint-disable-next-line no-new
+ new Vue({
+ el,
+ apolloProvider,
+ components: {
+ SidebarReviewers,
+ },
+ render: createElement =>
+ createElement('sidebar-reviewers', {
+ props: {
+ mediator,
+ issuableIid: String(iid),
+ projectPath: fullPath,
+ field: el.dataset.field,
+ signedIn: el.hasAttribute('data-signed-in'),
issuableType: isInIssuePage() ? 'issue' : 'merge_request',
},
}),
@@ -63,8 +91,6 @@ export function mountSidebarLabels() {
return false;
}
- const labelsStore = new Vuex.Store(labelsSelectModule());
-
return new Vue({
el,
provide: {
@@ -74,7 +100,6 @@ export function mountSidebarLabels() {
allowScopedLabels: parseBoolean(el.dataset.allowScopedLabels),
initiallySelectedLabels: JSON.parse(el.dataset.selectedLabels),
},
- store: labelsStore,
render: createElement => createElement(SidebarLabels),
});
}
@@ -89,47 +114,74 @@ function mountConfidentialComponent(mediator) {
const dataNode = document.getElementById('js-confidential-issue-data');
const initialData = JSON.parse(dataNode.innerHTML);
- // eslint-disable-next-line no-new
- new Vue({
- el,
- store,
- components: {
- ConfidentialIssueSidebar,
- },
- render: createElement =>
- createElement('confidential-issue-sidebar', {
- props: {
- iid: String(iid),
- fullPath,
- isEditable: initialData.is_editable,
- service: mediator.service,
- },
- }),
- });
+ import(/* webpackChunkName: 'notesStore' */ '~/notes/stores')
+ .then(
+ ({ store }) =>
+ new Vue({
+ el,
+ store,
+ components: {
+ ConfidentialIssueSidebar,
+ },
+ render: createElement =>
+ createElement('confidential-issue-sidebar', {
+ props: {
+ iid: String(iid),
+ fullPath,
+ isEditable: initialData.is_editable,
+ service: mediator.service,
+ },
+ }),
+ }),
+ )
+ .catch(() => {
+ createFlash({ message: __('Failed to load sidebar confidential toggle') });
+ });
}
function mountLockComponent() {
const el = document.getElementById('js-lock-entry-point');
+
+ if (!el) {
+ return;
+ }
+
const { fullPath } = getSidebarOptions();
const dataNode = document.getElementById('js-lock-issue-data');
const initialData = JSON.parse(dataNode.innerHTML);
- return el
- ? new Vue({
- el,
- store: isInIssuePage() ? store : mergeRequestStore,
- provide: {
- fullPath,
- },
- render: createElement =>
- createElement(IssuableLockForm, {
- props: {
- isEditable: initialData.is_editable,
- },
- }),
- })
- : undefined;
+ let importStore;
+ if (isInIssuePage() || isInIncidentPage()) {
+ importStore = import(/* webpackChunkName: 'notesStore' */ '~/notes/stores').then(
+ ({ store }) => store,
+ );
+ } else {
+ importStore = import(/* webpackChunkName: 'mrNotesStore' */ '~/mr_notes/stores').then(
+ store => store.default,
+ );
+ }
+
+ importStore
+ .then(
+ store =>
+ new Vue({
+ el,
+ store,
+ provide: {
+ fullPath,
+ },
+ render: createElement =>
+ createElement(IssuableLockForm, {
+ props: {
+ isEditable: initialData.is_editable,
+ },
+ }),
+ }),
+ )
+ .catch(() => {
+ createFlash({ message: __('Failed to load sidebar lock status') });
+ });
}
function mountParticipantsComponent(mediator) {
@@ -218,8 +270,9 @@ function mountSeverityComponent() {
export function mountSidebar(mediator) {
mountAssigneesComponent(mediator);
+ mountReviewersComponent(mediator);
mountConfidentialComponent(mediator);
- mountLockComponent(mediator);
+ mountLockComponent();
mountParticipantsComponent(mediator);
mountSubscriptionsComponent(mediator);
diff --git a/app/assets/javascripts/sidebar/sidebar_mediator.js b/app/assets/javascripts/sidebar/sidebar_mediator.js
index 8f1f76a2e02..2146fb83b13 100644
--- a/app/assets/javascripts/sidebar/sidebar_mediator.js
+++ b/app/assets/javascripts/sidebar/sidebar_mediator.js
@@ -40,6 +40,17 @@ export default class SidebarMediator {
return this.service.update(field, data);
}
+ saveReviewers(field) {
+ const selected = this.store.reviewers.map(u => u.id);
+
+ // If there are no ids, that means we have to unassign (which is id = 0)
+ // And it only accepts an array, hence [0]
+ const reviewers = selected.length === 0 ? [0] : selected;
+ const data = { reviewer_ids: reviewers };
+
+ return this.service.update(field, data);
+ }
+
setMoveToProjectId(projectId) {
this.store.setMoveToProjectId(projectId);
}
@@ -55,6 +66,7 @@ export default class SidebarMediator {
processFetchedData(data) {
this.store.setAssigneeData(data);
+ this.store.setReviewerData(data);
this.store.setTimeTrackingData(data);
this.store.setParticipantsData(data);
this.store.setSubscriptionsData(data);
diff --git a/app/assets/javascripts/sidebar/stores/sidebar_store.js b/app/assets/javascripts/sidebar/stores/sidebar_store.js
index 095f93b72a9..d53393052eb 100644
--- a/app/assets/javascripts/sidebar/stores/sidebar_store.js
+++ b/app/assets/javascripts/sidebar/stores/sidebar_store.js
@@ -18,8 +18,10 @@ export default class SidebarStore {
this.humanTimeSpent = '';
this.timeTrackingLimitToHours = timeTrackingLimitToHours;
this.assignees = [];
+ this.reviewers = [];
this.isFetching = {
assignees: true,
+ reviewers: true,
participants: true,
subscriptions: true,
};
@@ -31,17 +33,29 @@ export default class SidebarStore {
this.projectEmailsDisabled = false;
this.subscribeDisabledDescription = '';
this.subscribed = null;
+ this.changing = false;
SidebarStore.singleton = this;
}
- setAssigneeData(data) {
+ setAssigneeData({ assignees }) {
this.isFetching.assignees = false;
- if (data.assignees) {
- this.assignees = data.assignees;
+ if (assignees) {
+ this.assignees = assignees;
}
}
+ setReviewerData({ reviewers }) {
+ this.isFetching.reviewers = false;
+ if (reviewers) {
+ this.reviewers = reviewers;
+ }
+ }
+
+ resetChanging() {
+ this.changing = false;
+ }
+
setTimeTrackingData(data) {
this.timeEstimate = data.time_estimate;
this.totalTimeSpent = data.total_time_spent;
@@ -71,24 +85,47 @@ export default class SidebarStore {
addAssignee(assignee) {
if (!this.findAssignee(assignee)) {
+ this.changing = true;
this.assignees.push(assignee);
}
}
+ addReviewer(reviewer) {
+ if (!this.findReviewer(reviewer)) {
+ this.reviewers.push(reviewer);
+ }
+ }
+
findAssignee(findAssignee) {
- return this.assignees.find(assignee => assignee.id === findAssignee.id);
+ return this.assignees.find(({ id }) => id === findAssignee.id);
}
- removeAssignee(removeAssignee) {
- if (removeAssignee) {
- this.assignees = this.assignees.filter(assignee => assignee.id !== removeAssignee.id);
+ findReviewer(findReviewer) {
+ return this.reviewers.find(({ id }) => id === findReviewer.id);
+ }
+
+ removeAssignee(assignee) {
+ if (assignee) {
+ this.changing = true;
+ this.assignees = this.assignees.filter(({ id }) => id !== assignee.id);
+ }
+ }
+
+ removeReviewer(reviewer) {
+ if (reviewer) {
+ this.reviewers = this.reviewers.filter(({ id }) => id !== reviewer.id);
}
}
removeAllAssignees() {
+ this.changing = true;
this.assignees = [];
}
+ removeAllReviewers() {
+ this.reviewers = [];
+ }
+
setAssigneesFromRealtime(data) {
this.assignees = data;
}
diff --git a/app/assets/javascripts/single_file_diff.js b/app/assets/javascripts/single_file_diff.js
index 586d1e62c2f..5fa6cef7195 100644
--- a/app/assets/javascripts/single_file_diff.js
+++ b/app/assets/javascripts/single_file_diff.js
@@ -57,16 +57,10 @@ export default class SingleFileDiff {
this.content.hide();
this.$toggleIcon.addClass('fa-caret-right').removeClass('fa-caret-down');
this.collapsedContent.show();
- if (typeof gl.diffNotesCompileComponents !== 'undefined') {
- gl.diffNotesCompileComponents();
- }
} else if (this.content) {
this.collapsedContent.hide();
this.content.show();
this.$toggleIcon.addClass('fa-caret-down').removeClass('fa-caret-right');
- if (typeof gl.diffNotesCompileComponents !== 'undefined') {
- gl.diffNotesCompileComponents();
- }
} else {
this.$toggleIcon.addClass('fa-caret-down').removeClass('fa-caret-right');
return this.getContentHTML(cb);
@@ -90,10 +84,6 @@ export default class SingleFileDiff {
}
this.collapsedContent.after(this.content);
- if (typeof gl.diffNotesCompileComponents !== 'undefined') {
- gl.diffNotesCompileComponents();
- }
-
const $file = $(this.file);
FilesCommentButton.init($file);
diff --git a/app/assets/javascripts/snippet/snippet_bundle.js b/app/assets/javascripts/snippet/snippet_bundle.js
deleted file mode 100644
index 76a1f6d1458..00000000000
--- a/app/assets/javascripts/snippet/snippet_bundle.js
+++ /dev/null
@@ -1,30 +0,0 @@
-import { initEditorLite } from '~/blob/utils';
-import setupCollapsibleInputs from './collapsible_input';
-
-let editor;
-
-const initMonaco = () => {
- const editorEl = document.getElementById('editor');
- const contentEl = document.querySelector('.snippet-file-content');
- const fileNameEl = document.querySelector('.js-snippet-file-name');
- const form = document.querySelector('.snippet-form-holder form');
-
- editor = initEditorLite({
- el: editorEl,
- blobPath: fileNameEl.value,
- blobContent: contentEl.value,
- });
-
- fileNameEl.addEventListener('change', () => {
- editor.updateModelLanguage(fileNameEl.value);
- });
-
- form.addEventListener('submit', () => {
- contentEl.value = editor.getValue();
- });
-};
-
-export default () => {
- initMonaco();
- setupCollapsibleInputs();
-};
diff --git a/app/assets/javascripts/snippet/snippet_edit.js b/app/assets/javascripts/snippet/snippet_edit.js
index 3dc74922a77..88677ddd15f 100644
--- a/app/assets/javascripts/snippet/snippet_edit.js
+++ b/app/assets/javascripts/snippet/snippet_edit.js
@@ -1,33 +1,6 @@
-import $ from 'jquery';
-import initSnippet from '~/snippet/snippet_bundle';
import ZenMode from '~/zen_mode';
-import GLForm from '~/gl_form';
-import { SnippetEditInit } from '~/snippets';
+import SnippetsEdit from '~/snippets/components/edit.vue';
+import SnippetsAppFactory from '~/snippets';
-document.addEventListener('DOMContentLoaded', () => {
- const form = document.querySelector('.snippet-form');
- const personalSnippetOptions = {
- members: false,
- issues: false,
- mergeRequests: false,
- epics: false,
- milestones: false,
- labels: false,
- snippets: false,
- vulnerabilities: false,
- };
- const projectSnippetOptions = {};
-
- const options =
- form.dataset.snippetType === 'project' || form.dataset.projectPath
- ? projectSnippetOptions
- : personalSnippetOptions;
-
- if (gon?.features?.snippetsEditVue) {
- SnippetEditInit();
- } else {
- initSnippet();
- new GLForm($(form), options); // eslint-disable-line no-new
- }
- new ZenMode(); // eslint-disable-line no-new
-});
+SnippetsAppFactory(document.getElementById('js-snippet-edit'), SnippetsEdit);
+new ZenMode(); // eslint-disable-line no-new
diff --git a/app/assets/javascripts/snippet/snippet_embed.js b/app/assets/javascripts/snippet/snippet_embed.js
deleted file mode 100644
index 65dd62f6af9..00000000000
--- a/app/assets/javascripts/snippet/snippet_embed.js
+++ /dev/null
@@ -1,37 +0,0 @@
-import { __ } from '~/locale';
-import { parseUrlPathname, parseUrl } from '../lib/utils/common_utils';
-
-function swapActiveState(activateBtn, deactivateBtn) {
- activateBtn.classList.add('is-active');
- deactivateBtn.classList.remove('is-active');
-}
-
-export default () => {
- const shareBtn = document.querySelector('.js-share-btn');
-
- if (shareBtn) {
- const embedBtn = document.querySelector('.js-embed-btn');
- const snippetUrlArea = document.querySelector('.js-snippet-url-area');
- const embedAction = document.querySelector('.js-embed-action');
- const dataUrl = snippetUrlArea.getAttribute('data-url');
-
- snippetUrlArea.addEventListener('click', () => snippetUrlArea.select());
-
- shareBtn.addEventListener('click', () => {
- swapActiveState(shareBtn, embedBtn);
- snippetUrlArea.value = dataUrl;
- embedAction.innerText = __('Share');
- });
-
- embedBtn.addEventListener('click', () => {
- const parser = parseUrl(dataUrl);
- const url = `${parser.origin + parseUrlPathname(dataUrl)}`;
- const params = parser.search;
- const scriptTag = `<script src="${url}.js${params}"></script>`;
-
- swapActiveState(embedBtn, shareBtn);
- snippetUrlArea.value = scriptTag;
- embedAction.innerText = __('Embed');
- });
- }
-};
diff --git a/app/assets/javascripts/snippet/snippet_show.js b/app/assets/javascripts/snippet/snippet_show.js
index bbddfc579c5..caa76fc9988 100644
--- a/app/assets/javascripts/snippet/snippet_show.js
+++ b/app/assets/javascripts/snippet/snippet_show.js
@@ -1,21 +1,13 @@
-import LineHighlighter from '~/line_highlighter';
-import BlobViewer from '~/blob/viewer';
-import ZenMode from '~/zen_mode';
import initNotes from '~/init_notes';
-import snippetEmbed from '~/snippet/snippet_embed';
-import { SnippetShowInit } from '~/snippets';
import loadAwardsHandler from '~/awards_handler';
+import SnippetsShow from '~/snippets/components/show.vue';
+import SnippetsAppFactory from '~/snippets';
+import ZenMode from '~/zen_mode';
+
+SnippetsAppFactory(document.getElementById('js-snippet-view'), SnippetsShow);
+
+initNotes();
+loadAwardsHandler();
-document.addEventListener('DOMContentLoaded', () => {
- if (!gon.features.snippetsVue) {
- new LineHighlighter(); // eslint-disable-line no-new
- new BlobViewer(); // eslint-disable-line no-new
- initNotes();
- new ZenMode(); // eslint-disable-line no-new
- snippetEmbed();
- } else {
- SnippetShowInit();
- initNotes();
- }
- loadAwardsHandler();
-});
+// eslint-disable-next-line no-new
+new ZenMode();
diff --git a/app/assets/javascripts/snippets/components/edit.vue b/app/assets/javascripts/snippets/components/edit.vue
index 1a539aa0876..dd77d49803f 100644
--- a/app/assets/javascripts/snippets/components/edit.vue
+++ b/app/assets/javascripts/snippets/components/edit.vue
@@ -6,7 +6,12 @@ import { __, sprintf } from '~/locale';
import TitleField from '~/vue_shared/components/form/title.vue';
import { redirectTo, joinPaths } from '~/lib/utils/url_utility';
import FormFooterActions from '~/vue_shared/components/form/form_footer_actions.vue';
-import { SNIPPET_MARK_EDIT_APP_START } from '~/performance_constants';
+import {
+ SNIPPET_MARK_EDIT_APP_START,
+ SNIPPET_MEASURE_BLOBS_CONTENT,
+} from '~/performance_constants';
+import eventHub from '~/blob/components/eventhub';
+import { performanceMarkAndMeasure } from '~/performance_utils';
import UpdateSnippetMutation from '../mutations/updateSnippet.mutation.graphql';
import CreateSnippetMutation from '../mutations/createSnippet.mutation.graphql';
@@ -17,11 +22,14 @@ import {
SNIPPET_VISIBILITY_PRIVATE,
} from '../constants';
import defaultVisibilityQuery from '../queries/snippet_visibility.query.graphql';
+import { markBlobPerformance } from '../utils/blob';
import SnippetBlobActionsEdit from './snippet_blob_actions_edit.vue';
import SnippetVisibilityEdit from './snippet_visibility_edit.vue';
import SnippetDescriptionEdit from './snippet_description_edit.vue';
+eventHub.$on(SNIPPET_MEASURE_BLOBS_CONTENT, markBlobPerformance);
+
export default {
components: {
SnippetDescriptionEdit,
@@ -104,12 +112,6 @@ export default {
}
return this.snippet.webUrl;
},
- titleFieldId() {
- return `${this.isProjectSnippet ? 'project' : 'personal'}_snippet_title`;
- },
- descriptionFieldId() {
- return `${this.isProjectSnippet ? 'project' : 'personal'}_snippet_description`;
- },
newSnippetSchema() {
return {
title: '',
@@ -119,7 +121,7 @@ export default {
},
},
beforeCreate() {
- performance.mark(SNIPPET_MARK_EDIT_APP_START);
+ performanceMarkAndMeasure({ mark: SNIPPET_MARK_EDIT_APP_START });
},
created() {
window.addEventListener('beforeunload', this.onBeforeUnload);
@@ -151,7 +153,7 @@ export default {
this.newSnippet = false;
},
onSnippetFetch(snippetRes) {
- if (snippetRes.data.snippets.edges.length === 0) {
+ if (snippetRes.data.snippets.nodes.length === 0) {
this.onNewSnippetFetched();
} else {
this.onExistingSnippetFetched();
@@ -220,14 +222,13 @@ export default {
/>
<template v-else>
<title-field
- :id="titleFieldId"
+ id="snippet-title"
v-model="snippet.title"
data-qa-selector="snippet_title_field"
required
:autofocus="true"
/>
<snippet-description-edit
- :id="descriptionFieldId"
v-model="snippet.description"
:markdown-preview-path="markdownPreviewPath"
:markdown-docs-path="markdownDocsPath"
diff --git a/app/assets/javascripts/snippets/components/embed_dropdown.vue b/app/assets/javascripts/snippets/components/embed_dropdown.vue
index 589754a8b19..a5d2c337d67 100644
--- a/app/assets/javascripts/snippets/components/embed_dropdown.vue
+++ b/app/assets/javascripts/snippets/components/embed_dropdown.vue
@@ -60,7 +60,7 @@ export default {
class="gl-dropdown-text-py-0 gl-dropdown-text-block"
data-testid="input"
>
- <gl-form-input-group :value="value" readonly select-on-click>
+ <gl-form-input-group :value="value" readonly select-on-click :aria-label="name">
<template #append>
<gl-button
v-gl-tooltip.hover
diff --git a/app/assets/javascripts/snippets/components/show.vue b/app/assets/javascripts/snippets/components/show.vue
index 43be2cb7ed8..4a2f060ff7c 100644
--- a/app/assets/javascripts/snippets/components/show.vue
+++ b/app/assets/javascripts/snippets/components/show.vue
@@ -5,11 +5,18 @@ import SnippetHeader from './snippet_header.vue';
import SnippetTitle from './snippet_title.vue';
import SnippetBlob from './snippet_blob_view.vue';
import CloneDropdownButton from '~/vue_shared/components/clone_dropdown.vue';
+import { SNIPPET_VISIBILITY_PUBLIC } from '~/snippets/constants';
+import {
+ SNIPPET_MARK_VIEW_APP_START,
+ SNIPPET_MEASURE_BLOBS_CONTENT,
+} from '~/performance_constants';
+import { performanceMarkAndMeasure } from '~/performance_utils';
+import eventHub from '~/blob/components/eventhub';
import { getSnippetMixin } from '../mixins/snippets';
-import { SNIPPET_VISIBILITY_PUBLIC } from '~/snippets/constants';
+import { markBlobPerformance } from '../utils/blob';
-import { SNIPPET_MARK_VIEW_APP_START } from '~/performance_constants';
+eventHub.$on(SNIPPET_MEASURE_BLOBS_CONTENT, markBlobPerformance);
export default {
components: {
@@ -30,7 +37,7 @@ export default {
},
},
beforeCreate() {
- performance.mark(SNIPPET_MARK_VIEW_APP_START);
+ performanceMarkAndMeasure({ mark: SNIPPET_MARK_VIEW_APP_START });
},
};
</script>
diff --git a/app/assets/javascripts/snippets/components/snippet_blob_actions_edit.vue b/app/assets/javascripts/snippets/components/snippet_blob_actions_edit.vue
index 55cd13a6930..ab2553265a2 100644
--- a/app/assets/javascripts/snippets/components/snippet_blob_actions_edit.vue
+++ b/app/assets/javascripts/snippets/components/snippet_blob_actions_edit.vue
@@ -2,7 +2,6 @@
import { GlButton } from '@gitlab/ui';
import { cloneDeep } from 'lodash';
import { s__, sprintf } from '~/locale';
-import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import SnippetBlobEdit from './snippet_blob_edit.vue';
import { SNIPPET_MAX_BLOBS } from '../constants';
import { createBlob, decorateBlob, diffAll } from '../utils/blob';
@@ -12,7 +11,6 @@ export default {
SnippetBlobEdit,
GlButton,
},
- mixins: [glFeatureFlagsMixin()],
props: {
initBlobs: {
type: Array,
@@ -52,12 +50,6 @@ export default {
canAdd() {
return this.count < SNIPPET_MAX_BLOBS;
},
- hasMultiFilesEnabled() {
- return this.glFeatures.snippetMultipleFiles;
- },
- filesLabel() {
- return this.hasMultiFilesEnabled ? s__('Snippets|Files') : s__('Snippets|File');
- },
firstInputId() {
const blobId = this.blobIds[0];
@@ -131,24 +123,23 @@ export default {
};
</script>
<template>
- <div class="form-group file-editor">
- <label :for="firstInputId">{{ filesLabel }}</label>
+ <div class="form-group">
+ <label :for="firstInputId">{{ s__('Snippets|Files') }}</label>
<snippet-blob-edit
v-for="(blobId, index) in blobIds"
:key="blobId"
:class="{ 'gl-mt-3': index > 0 }"
:blob="blobs[blobId]"
:can-delete="canDelete"
- :show-delete="hasMultiFilesEnabled"
@blob-updated="updateBlob(blobId, $event)"
@delete="deleteBlob(blobId)"
/>
<gl-button
- v-if="hasMultiFilesEnabled"
:disabled="!canAdd"
data-testid="add_button"
class="gl-my-3"
variant="dashed"
+ data-qa-selector="add_file_button"
@click="addBlob"
>{{ addLabel }}</gl-button
>
diff --git a/app/assets/javascripts/snippets/components/snippet_blob_edit.vue b/app/assets/javascripts/snippets/components/snippet_blob_edit.vue
index f3f894ed649..6a10dc38f2c 100644
--- a/app/assets/javascripts/snippets/components/snippet_blob_edit.vue
+++ b/app/assets/javascripts/snippets/components/snippet_blob_edit.vue
@@ -1,7 +1,7 @@
<script>
import { GlLoadingIcon } from '@gitlab/ui';
import BlobHeaderEdit from '~/blob/components/blob_edit_header.vue';
-import BlobContentEdit from '~/blob/components/blob_edit_content.vue';
+import EditorLite from '~/vue_shared/components/editor_lite.vue';
import { getBaseURL, joinPaths } from '~/lib/utils/url_utility';
import axios from '~/lib/utils/axios_utils';
import { SNIPPET_BLOB_CONTENT_FETCH_ERROR } from '~/snippets/constants';
@@ -11,8 +11,8 @@ import { sprintf } from '~/locale';
export default {
components: {
BlobHeaderEdit,
- BlobContentEdit,
GlLoadingIcon,
+ EditorLite,
},
inheritAttrs: false,
props: {
@@ -28,7 +28,7 @@ export default {
showDelete: {
type: Boolean,
required: false,
- default: false,
+ default: true,
},
},
computed: {
@@ -69,7 +69,7 @@ export default {
};
</script>
<template>
- <div class="file-holder snippet">
+ <div class="file-holder snippet" data-qa-selector="file_holder_container">
<blob-header-edit
:id="inputId"
:value="blob.path"
@@ -85,7 +85,7 @@ export default {
size="lg"
class="loading-animation prepend-top-20 gl-mb-6"
/>
- <blob-content-edit
+ <editor-lite
v-else
:value="blob.content"
:file-global-id="blob.id"
diff --git a/app/assets/javascripts/snippets/components/snippet_blob_view.vue b/app/assets/javascripts/snippets/components/snippet_blob_view.vue
index b38be5bb9a4..e88126ea56a 100644
--- a/app/assets/javascripts/snippets/components/snippet_blob_view.vue
+++ b/app/assets/javascripts/snippets/components/snippet_blob_view.vue
@@ -23,6 +23,7 @@ export default {
return {
ids: this.snippet.id,
rich: this.activeViewerType === RICH_BLOB_VIEWER,
+ paths: [this.blob.path],
};
},
update(data) {
@@ -79,8 +80,10 @@ export default {
},
onContentUpdate(data) {
const { path: blobPath } = this.blob;
- const { blobs } = data.snippets.edges[0].node;
- const updatedBlobData = blobs.find(blob => blob.path === blobPath);
+ const {
+ blobs: { nodes: dataBlobs },
+ } = data.snippets.nodes[0];
+ const updatedBlobData = dataBlobs.find(blob => blob.path === blobPath);
return updatedBlobData.richData || updatedBlobData.plainData;
},
},
diff --git a/app/assets/javascripts/snippets/components/snippet_description_edit.vue b/app/assets/javascripts/snippets/components/snippet_description_edit.vue
index 737845d09b8..5e6caf27bdd 100644
--- a/app/assets/javascripts/snippets/components/snippet_description_edit.vue
+++ b/app/assets/javascripts/snippets/components/snippet_description_edit.vue
@@ -49,6 +49,7 @@ export default {
:add-spacing-classes="false"
:markdown-preview-path="markdownPreviewPath"
:markdown-docs-path="markdownDocsPath"
+ :textarea-value="value"
>
<template #textarea>
<textarea
diff --git a/app/assets/javascripts/snippets/components/snippet_header.vue b/app/assets/javascripts/snippets/components/snippet_header.vue
index 0ca69f3161a..30de5a9d0e0 100644
--- a/app/assets/javascripts/snippets/components/snippet_header.vue
+++ b/app/assets/javascripts/snippets/components/snippet_header.vue
@@ -18,6 +18,7 @@ import DeleteSnippetMutation from '../mutations/deleteSnippet.mutation.graphql';
import CanCreatePersonalSnippet from '../queries/userPermissions.query.graphql';
import CanCreateProjectSnippet from '../queries/projectPermissions.query.graphql';
import { joinPaths } from '~/lib/utils/url_utility';
+import { fetchPolicies } from '~/lib/graphql';
export default {
components: {
@@ -37,6 +38,7 @@ export default {
},
apollo: {
canCreateSnippet: {
+ fetchPolicy: fetchPolicies.NO_CACHE,
query() {
return this.snippet.project ? CanCreateProjectSnippet : CanCreatePersonalSnippet;
},
diff --git a/app/assets/javascripts/snippets/fragments/snippetBase.fragment.graphql b/app/assets/javascripts/snippets/fragments/snippetBase.fragment.graphql
index 2cca71708ca..d75b4011d1c 100644
--- a/app/assets/javascripts/snippets/fragments/snippetBase.fragment.graphql
+++ b/app/assets/javascripts/snippets/fragments/snippetBase.fragment.graphql
@@ -12,18 +12,20 @@ fragment SnippetBase on Snippet {
httpUrlToRepo
sshUrlToRepo
blobs {
- binary
- name
- path
- rawPath
- size
- externalStorage
- renderedAsText
- simpleViewer {
- ...BlobViewer
- }
- richViewer {
- ...BlobViewer
+ nodes {
+ binary
+ name
+ path
+ rawPath
+ size
+ externalStorage
+ renderedAsText
+ simpleViewer {
+ ...BlobViewer
+ }
+ richViewer {
+ ...BlobViewer
+ }
}
}
userPermissions {
diff --git a/app/assets/javascripts/snippets/index.js b/app/assets/javascripts/snippets/index.js
index c70ad9b95f8..b55e1baf41e 100644
--- a/app/assets/javascripts/snippets/index.js
+++ b/app/assets/javascripts/snippets/index.js
@@ -3,20 +3,18 @@ import VueApollo from 'vue-apollo';
import Translate from '~/vue_shared/translate';
import createDefaultClient from '~/lib/graphql';
-import SnippetsShow from './components/show.vue';
-import SnippetsEdit from './components/edit.vue';
import { SNIPPET_LEVELS_MAP, SNIPPET_VISIBILITY_PRIVATE } from '~/snippets/constants';
Vue.use(VueApollo);
Vue.use(Translate);
-function appFactory(el, Component) {
+export default function appFactory(el, Component) {
if (!el) {
return false;
}
const apolloProvider = new VueApollo({
- defaultClient: createDefaultClient(),
+ defaultClient: createDefaultClient({}, { batchMax: 1 }),
});
const {
@@ -46,11 +44,3 @@ function appFactory(el, Component) {
},
});
}
-
-export const SnippetShowInit = () => {
- appFactory(document.getElementById('js-snippet-view'), SnippetsShow);
-};
-
-export const SnippetEditInit = () => {
- appFactory(document.getElementById('js-snippet-edit'), SnippetsEdit);
-};
diff --git a/app/assets/javascripts/snippets/mixins/snippets.js b/app/assets/javascripts/snippets/mixins/snippets.js
index 15daaa8d84a..d5e69e2a889 100644
--- a/app/assets/javascripts/snippets/mixins/snippets.js
+++ b/app/assets/javascripts/snippets/mixins/snippets.js
@@ -11,9 +11,16 @@ export const getSnippetMixin = {
ids: this.snippetGid,
};
},
- update: data => data.snippets.edges[0]?.node,
+ update: data => {
+ const res = data.snippets.nodes[0];
+ if (res) {
+ res.blobs = res.blobs.nodes;
+ }
+
+ return res;
+ },
result(res) {
- this.blobs = res.data.snippets.edges[0]?.node?.blobs || blobsDefault;
+ this.blobs = res.data.snippets.nodes[0]?.blobs || blobsDefault;
if (this.onSnippetFetch) {
this.onSnippetFetch(res);
}
diff --git a/app/assets/javascripts/snippets/queries/snippet.blob.content.query.graphql b/app/assets/javascripts/snippets/queries/snippet.blob.content.query.graphql
index 8f1f16b76c2..0e04ee9b7b8 100644
--- a/app/assets/javascripts/snippets/queries/snippet.blob.content.query.graphql
+++ b/app/assets/javascripts/snippets/queries/snippet.blob.content.query.graphql
@@ -1,9 +1,9 @@
-query SnippetBlobContent($ids: [ID!], $rich: Boolean!) {
+query SnippetBlobContent($ids: [ID!], $rich: Boolean!, $paths: [String!]) {
snippets(ids: $ids) {
- edges {
- node {
- id
- blobs {
+ nodes {
+ id
+ blobs(paths: $paths) {
+ nodes {
path
richData @include(if: $rich)
plainData @skip(if: $rich)
diff --git a/app/assets/javascripts/snippets/queries/snippet.query.graphql b/app/assets/javascripts/snippets/queries/snippet.query.graphql
index b23ab862439..2f385050d89 100644
--- a/app/assets/javascripts/snippets/queries/snippet.query.graphql
+++ b/app/assets/javascripts/snippets/queries/snippet.query.graphql
@@ -4,13 +4,11 @@
query GetSnippetQuery($ids: [ID!]) {
snippets(ids: $ids) {
- edges {
- node {
- ...SnippetBase
- ...SnippetProject
- author {
- ...Author
- }
+ nodes {
+ ...SnippetBase
+ ...SnippetProject
+ author {
+ ...Author
}
}
}
diff --git a/app/assets/javascripts/snippets/utils/blob.js b/app/assets/javascripts/snippets/utils/blob.js
index 21f52671801..c47559b82b8 100644
--- a/app/assets/javascripts/snippets/utils/blob.js
+++ b/app/assets/javascripts/snippets/utils/blob.js
@@ -7,6 +7,8 @@ import {
SNIPPET_LEVELS_MAP,
SNIPPET_VISIBILITY,
} from '../constants';
+import { performanceMarkAndMeasure } from '~/performance_utils';
+import { SNIPPET_MARK_BLOBS_CONTENT, SNIPPET_MEASURE_BLOBS_CONTENT } from '~/performance_constants';
const createLocalId = () => uniqueId('blob_local_');
@@ -79,3 +81,16 @@ export const defaultSnippetVisibilityLevels = arr => {
}
return [];
};
+
+export const markBlobPerformance = () => {
+ performanceMarkAndMeasure({
+ mark: SNIPPET_MARK_BLOBS_CONTENT,
+ measures: [
+ {
+ name: SNIPPET_MEASURE_BLOBS_CONTENT,
+ start: undefined,
+ end: SNIPPET_MARK_BLOBS_CONTENT,
+ },
+ ],
+ });
+};
diff --git a/app/assets/javascripts/static_site_editor/components/edit_meta_controls.vue b/app/assets/javascripts/static_site_editor/components/edit_meta_controls.vue
new file mode 100644
index 00000000000..9f75c65a316
--- /dev/null
+++ b/app/assets/javascripts/static_site_editor/components/edit_meta_controls.vue
@@ -0,0 +1,104 @@
+<script>
+import { GlForm, GlFormGroup, GlFormInput, GlFormTextarea } from '@gitlab/ui';
+import AccessorUtilities from '~/lib/utils/accessor';
+
+export default {
+ components: {
+ GlForm,
+ GlFormGroup,
+ GlFormInput,
+ GlFormTextarea,
+ },
+ props: {
+ title: {
+ type: String,
+ required: true,
+ },
+ description: {
+ type: String,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ editable: {
+ title: this.title,
+ description: this.description,
+ },
+ };
+ },
+ computed: {
+ editableStorageKey() {
+ return this.getId('local-storage', 'editable');
+ },
+ hasLocalStorage() {
+ return AccessorUtilities.isLocalStorageAccessSafe();
+ },
+ },
+ mounted() {
+ this.initCachedEditable();
+ this.preSelect();
+ },
+ methods: {
+ getId(type, key) {
+ return `sse-merge-request-meta-${type}-${key}`;
+ },
+ initCachedEditable() {
+ if (this.hasLocalStorage) {
+ const cachedEditable = JSON.parse(localStorage.getItem(this.editableStorageKey));
+ if (cachedEditable) {
+ this.editable = cachedEditable;
+ }
+ }
+ },
+ preSelect() {
+ this.$nextTick(() => {
+ this.$refs.title.$el.select();
+ });
+ },
+ resetCachedEditable() {
+ if (this.hasLocalStorage) {
+ window.localStorage.removeItem(this.editableStorageKey);
+ }
+ },
+ onUpdate() {
+ const payload = { ...this.editable };
+ this.$emit('updateSettings', payload);
+
+ if (this.hasLocalStorage) {
+ window.localStorage.setItem(this.editableStorageKey, JSON.stringify(payload));
+ }
+ },
+ },
+};
+</script>
+
+<template>
+ <gl-form>
+ <gl-form-group
+ key="title"
+ :label="__('Brief title about the change')"
+ :label-for="getId('control', 'title')"
+ >
+ <gl-form-input
+ :id="getId('control', 'title')"
+ ref="title"
+ v-model.lazy="editable.title"
+ type="text"
+ @input="onUpdate"
+ />
+ </gl-form-group>
+
+ <gl-form-group
+ key="description"
+ :label="__('Goal of the changes and what reviewers should be aware of')"
+ :label-for="getId('control', 'description')"
+ >
+ <gl-form-textarea
+ :id="getId('control', 'description')"
+ v-model.lazy="editable.description"
+ @input="onUpdate"
+ />
+ </gl-form-group>
+ </gl-form>
+</template>
diff --git a/app/assets/javascripts/static_site_editor/components/edit_meta_modal.vue b/app/assets/javascripts/static_site_editor/components/edit_meta_modal.vue
new file mode 100644
index 00000000000..4e5245bd892
--- /dev/null
+++ b/app/assets/javascripts/static_site_editor/components/edit_meta_modal.vue
@@ -0,0 +1,85 @@
+<script>
+import { GlModal } from '@gitlab/ui';
+import { __, s__, sprintf } from '~/locale';
+
+import EditMetaControls from './edit_meta_controls.vue';
+
+export default {
+ components: {
+ GlModal,
+ EditMetaControls,
+ },
+ props: {
+ sourcePath: {
+ type: String,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ mergeRequestMeta: {
+ title: sprintf(s__(`StaticSiteEditor|Update %{sourcePath} file`), {
+ sourcePath: this.sourcePath,
+ }),
+ description: s__('StaticSiteEditor|Copy update'),
+ },
+ };
+ },
+ computed: {
+ disabled() {
+ return this.mergeRequestMeta.title === '';
+ },
+ primaryProps() {
+ return {
+ text: __('Submit changes'),
+ attributes: [{ variant: 'success' }, { disabled: this.disabled }],
+ };
+ },
+ secondaryProps() {
+ return {
+ text: __('Keep editing'),
+ attributes: [{ variant: 'default' }],
+ };
+ },
+ },
+ methods: {
+ hide() {
+ this.$refs.modal.hide();
+ },
+ show() {
+ this.$refs.modal.show();
+ },
+ onPrimary() {
+ this.$emit('primary', this.mergeRequestMeta);
+ this.$refs.editMetaControls.resetCachedEditable();
+ },
+ onSecondary() {
+ this.hide();
+ },
+ onUpdateSettings(mergeRequestMeta) {
+ this.mergeRequestMeta = { ...mergeRequestMeta };
+ },
+ },
+};
+</script>
+
+<template>
+ <gl-modal
+ ref="modal"
+ modal-id="edit-meta-modal"
+ :title="__('Submit your changes')"
+ :action-primary="primaryProps"
+ :action-secondary="secondaryProps"
+ size="sm"
+ @primary="onPrimary"
+ @secondary="onSecondary"
+ @hide="() => $emit('hide')"
+ >
+ <edit-meta-controls
+ ref="editMetaControls"
+ :title="mergeRequestMeta.title"
+ :description="mergeRequestMeta.description"
+ @updateSettings="onUpdateSettings"
+ />
+ </gl-modal>
+</template>
diff --git a/app/assets/javascripts/static_site_editor/components/publish_toolbar.vue b/app/assets/javascripts/static_site_editor/components/publish_toolbar.vue
index 2d62964cb3b..3bb5a0b8fd5 100644
--- a/app/assets/javascripts/static_site_editor/components/publish_toolbar.vue
+++ b/app/assets/javascripts/static_site_editor/components/publish_toolbar.vue
@@ -41,7 +41,7 @@ export default {
:disabled="savingChanges"
@click="$emit('editSettings')"
>
- {{ __('Settings') }}
+ {{ __('Page settings') }}
</gl-button>
<gl-button
ref="submit"
@@ -50,7 +50,7 @@ export default {
:loading="savingChanges"
@click="$emit('submit')"
>
- {{ __('Submit changes') }}
+ {{ __('Submit changes...') }}
</gl-button>
</div>
</div>
diff --git a/app/assets/javascripts/static_site_editor/graphql/index.js b/app/assets/javascripts/static_site_editor/graphql/index.js
index 0a5d8c07ad9..cc68bc57bb0 100644
--- a/app/assets/javascripts/static_site_editor/graphql/index.js
+++ b/app/assets/javascripts/static_site_editor/graphql/index.js
@@ -4,6 +4,7 @@ import createDefaultClient from '~/lib/graphql';
import typeDefs from './typedefs.graphql';
import fileResolver from './resolvers/file';
import submitContentChangesResolver from './resolvers/submit_content_changes';
+import hasSubmittedChangesResolver from './resolvers/has_submitted_changes';
Vue.use(VueApollo);
@@ -15,10 +16,12 @@ const createApolloProvider = appData => {
},
Mutation: {
submitContentChanges: submitContentChangesResolver,
+ hasSubmittedChanges: hasSubmittedChangesResolver,
},
},
{
typeDefs,
+ assumeImmutableResults: true,
},
);
diff --git a/app/assets/javascripts/static_site_editor/graphql/mutations/has_submitted_changes.mutation.graphql b/app/assets/javascripts/static_site_editor/graphql/mutations/has_submitted_changes.mutation.graphql
new file mode 100644
index 00000000000..1f47929556a
--- /dev/null
+++ b/app/assets/javascripts/static_site_editor/graphql/mutations/has_submitted_changes.mutation.graphql
@@ -0,0 +1,5 @@
+mutation hasSubmittedChanges($input: HasSubmittedChangesInput) {
+ hasSubmittedChanges(input: $input) @client {
+ hasSubmittedChanges
+ }
+}
diff --git a/app/assets/javascripts/static_site_editor/graphql/queries/app_data.query.graphql b/app/assets/javascripts/static_site_editor/graphql/queries/app_data.query.graphql
index 946d80efff0..9f4b0afe55f 100644
--- a/app/assets/javascripts/static_site_editor/graphql/queries/app_data.query.graphql
+++ b/app/assets/javascripts/static_site_editor/graphql/queries/app_data.query.graphql
@@ -1,6 +1,7 @@
query appData {
appData @client {
isSupportedContent
+ hasSubmittedChanges
project
sourcePath
username
diff --git a/app/assets/javascripts/static_site_editor/graphql/resolvers/has_submitted_changes.js b/app/assets/javascripts/static_site_editor/graphql/resolvers/has_submitted_changes.js
new file mode 100644
index 00000000000..ea49b21eb0d
--- /dev/null
+++ b/app/assets/javascripts/static_site_editor/graphql/resolvers/has_submitted_changes.js
@@ -0,0 +1,25 @@
+import { produce } from 'immer';
+import query from '../queries/app_data.query.graphql';
+
+const hasSubmittedChangesResolver = (_, { input: { hasSubmittedChanges } }, { cache }) => {
+ const oldData = cache.readQuery({ query });
+
+ const data = produce(oldData, draftState => {
+ // punctually modifying draftState as per immer docs upsets our linters
+ return {
+ ...draftState,
+ appData: {
+ __typename: 'AppData',
+ ...draftState.appData,
+ hasSubmittedChanges,
+ },
+ };
+ });
+
+ cache.writeQuery({
+ query,
+ data,
+ });
+};
+
+export default hasSubmittedChangesResolver;
diff --git a/app/assets/javascripts/static_site_editor/graphql/resolvers/submit_content_changes.js b/app/assets/javascripts/static_site_editor/graphql/resolvers/submit_content_changes.js
index 0cb26f88785..4137ede49c6 100644
--- a/app/assets/javascripts/static_site_editor/graphql/resolvers/submit_content_changes.js
+++ b/app/assets/javascripts/static_site_editor/graphql/resolvers/submit_content_changes.js
@@ -1,24 +1,34 @@
+import { produce } from 'immer';
import submitContentChanges from '../../services/submit_content_changes';
import savedContentMetaQuery from '../queries/saved_content_meta.query.graphql';
const submitContentChangesResolver = (
_,
- { input: { project: projectId, username, sourcePath, content, images } },
+ { input: { project: projectId, username, sourcePath, content, images, mergeRequestMeta } },
{ cache },
) => {
- return submitContentChanges({ projectId, username, sourcePath, content, images }).then(
- savedContentMeta => {
- cache.writeQuery({
- query: savedContentMetaQuery,
- data: {
- savedContentMeta: {
- __typename: 'SavedContentMeta',
- ...savedContentMeta,
- },
+ return submitContentChanges({
+ projectId,
+ username,
+ sourcePath,
+ content,
+ images,
+ mergeRequestMeta,
+ }).then(savedContentMeta => {
+ const data = produce(savedContentMeta, draftState => {
+ return {
+ savedContentMeta: {
+ __typename: 'SavedContentMeta',
+ ...draftState,
},
- });
- },
- );
+ };
+ });
+
+ cache.writeQuery({
+ query: savedContentMetaQuery,
+ data,
+ });
+ });
};
export default submitContentChangesResolver;
diff --git a/app/assets/javascripts/static_site_editor/graphql/typedefs.graphql b/app/assets/javascripts/static_site_editor/graphql/typedefs.graphql
index 78cc1746cdb..0ded1722d26 100644
--- a/app/assets/javascripts/static_site_editor/graphql/typedefs.graphql
+++ b/app/assets/javascripts/static_site_editor/graphql/typedefs.graphql
@@ -16,12 +16,17 @@ type SavedContentMeta {
type AppData {
isSupportedContent: Boolean!
+ hasSubmittedChanges: Boolean!
project: String!
returnUrl: String
sourcePath: String!
username: String!
}
+input HasSubmittedChangesInput {
+ hasSubmittedChanges: Boolean!
+}
+
input SubmitContentChangesInput {
project: String!
sourcePath: String!
@@ -40,4 +45,5 @@ extend type Query {
extend type Mutation {
submitContentChanges(input: SubmitContentChangesInput!): SavedContentMeta
+ hasSubmittedChanges(input: HasSubmittedChangesInput!): AppData
}
diff --git a/app/assets/javascripts/static_site_editor/index.js b/app/assets/javascripts/static_site_editor/index.js
index b7e5ea4eee3..fceef8f9084 100644
--- a/app/assets/javascripts/static_site_editor/index.js
+++ b/app/assets/javascripts/static_site_editor/index.js
@@ -12,13 +12,23 @@ const initStaticSiteEditor = el => {
namespace,
project,
mergeRequestsIllustrationPath,
+ // NOTE: The following variables are not yet used, but are supported by the config file,
+ // so we are adding them here as a convenience for future use.
+ // eslint-disable-next-line no-unused-vars
+ staticSiteGenerator,
+ // eslint-disable-next-line no-unused-vars
+ imageUploadPath,
+ mounts,
} = el.dataset;
+ // NOTE that the object in 'mounts' is a JSON string from the data attribute, so it must be parsed into an object.
+ // eslint-disable-next-line no-unused-vars
+ const mountsObject = JSON.parse(mounts);
const { current_username: username } = window.gon;
const returnUrl = el.dataset.returnUrl || null;
-
const router = createRouter(baseUrl);
const apolloProvider = createApolloProvider({
isSupportedContent: parseBoolean(isSupportedContent),
+ hasSubmittedChanges: false,
project: `${namespace}/${project}`,
returnUrl,
sourcePath,
diff --git a/app/assets/javascripts/static_site_editor/pages/home.vue b/app/assets/javascripts/static_site_editor/pages/home.vue
index eef2bd88f0e..27bd1c99ae2 100644
--- a/app/assets/javascripts/static_site_editor/pages/home.vue
+++ b/app/assets/javascripts/static_site_editor/pages/home.vue
@@ -1,13 +1,16 @@
<script>
+import { deprecatedCreateFlash as createFlash } from '~/flash';
+import Tracking from '~/tracking';
+
import SkeletonLoader from '../components/skeleton_loader.vue';
import EditArea from '../components/edit_area.vue';
+import EditMetaModal from '../components/edit_meta_modal.vue';
import InvalidContentMessage from '../components/invalid_content_message.vue';
import SubmitChangesError from '../components/submit_changes_error.vue';
import appDataQuery from '../graphql/queries/app_data.query.graphql';
import sourceContentQuery from '../graphql/queries/source_content.query.graphql';
+import hasSubmittedChangesMutation from '../graphql/mutations/has_submitted_changes.mutation.graphql';
import submitContentChangesMutation from '../graphql/mutations/submit_content_changes.mutation.graphql';
-import { deprecatedCreateFlash as createFlash } from '~/flash';
-import Tracking from '~/tracking';
import { LOAD_CONTENT_ERROR, TRACKING_ACTION_INITIALIZE_EDITOR } from '../constants';
import { SUCCESS_ROUTE } from '../router/constants';
@@ -15,6 +18,7 @@ export default {
components: {
SkeletonLoader,
EditArea,
+ EditMetaModal,
InvalidContentMessage,
SubmitChangesError,
},
@@ -48,6 +52,7 @@ export default {
data() {
return {
content: null,
+ images: null,
submitChangesError: null,
isSavingChanges: false,
};
@@ -64,15 +69,34 @@ export default {
Tracking.event(document.body.dataset.page, TRACKING_ACTION_INITIALIZE_EDITOR);
},
methods: {
+ onHideModal() {
+ this.isSavingChanges = false;
+ this.$refs.editMetaModal.hide();
+ },
onDismissError() {
this.submitChangesError = null;
},
- onSubmit({ content, images }) {
+ onPrepareSubmit({ content, images }) {
this.content = content;
- this.submitChanges(images);
- },
- submitChanges(images) {
+ this.images = images;
+
this.isSavingChanges = true;
+ this.$refs.editMetaModal.show();
+ },
+ onSubmit(mergeRequestMeta) {
+ // eslint-disable-next-line promise/catch-or-return
+ this.$apollo
+ .mutate({
+ mutation: hasSubmittedChangesMutation,
+ variables: {
+ input: {
+ hasSubmittedChanges: true,
+ },
+ },
+ })
+ .finally(() => {
+ this.$router.push(SUCCESS_ROUTE);
+ });
this.$apollo
.mutate({
@@ -83,13 +107,11 @@ export default {
username: this.appData.username,
sourcePath: this.appData.sourcePath,
content: this.content,
- images,
+ images: this.images,
+ mergeRequestMeta,
},
},
})
- .then(() => {
- this.$router.push(SUCCESS_ROUTE);
- })
.catch(e => {
this.submitChangesError = e.message;
})
@@ -107,7 +129,7 @@ export default {
<submit-changes-error
v-if="submitChangesError"
:error="submitChangesError"
- @retry="submitChanges"
+ @retry="onSubmit"
@dismiss="onDismissError"
/>
<edit-area
@@ -116,7 +138,13 @@ export default {
:content="sourceContent.content"
:saving-changes="isSavingChanges"
:return-url="appData.returnUrl"
- @submit="onSubmit"
+ @submit="onPrepareSubmit"
+ />
+ <edit-meta-modal
+ ref="editMetaModal"
+ :source-path="appData.sourcePath"
+ @primary="onSubmit"
+ @hide="onHideModal"
/>
</template>
diff --git a/app/assets/javascripts/static_site_editor/pages/success.vue b/app/assets/javascripts/static_site_editor/pages/success.vue
index f0d597d7c9b..1ee1a3b0edf 100644
--- a/app/assets/javascripts/static_site_editor/pages/success.vue
+++ b/app/assets/javascripts/static_site_editor/pages/success.vue
@@ -1,5 +1,5 @@
<script>
-import { GlEmptyState, GlButton } from '@gitlab/ui';
+import { GlButton, GlEmptyState, GlLoadingIcon } from '@gitlab/ui';
import { s__, __, sprintf } from '~/locale';
import savedContentMetaQuery from '../graphql/queries/saved_content_meta.query.graphql';
@@ -8,8 +8,9 @@ import { HOME_ROUTE } from '../router/constants';
export default {
components: {
- GlEmptyState,
GlButton,
+ GlEmptyState,
+ GlLoadingIcon,
},
props: {
mergeRequestsIllustrationPath: {
@@ -33,7 +34,7 @@ export default {
},
},
created() {
- if (!this.savedContentMeta) {
+ if (!this.appData.hasSubmittedChanges) {
this.$router.push(HOME_ROUTE);
}
},
@@ -50,40 +51,56 @@ export default {
assignMergeRequestInstruction: s__(
'StaticSiteEditor|3. Assign a person to review and accept the merge request.',
),
+ submittingTitle: s__('StaticSiteEditor|Creating your merge request'),
+ submittingNotePrimary: s__(
+ 'StaticSiteEditor|You can set an assignee to get your changes reviewed and deployed once your merge request is created.',
+ ),
+ submittingNoteSecondary: s__(
+ 'StaticSiteEditor|A link to view the merge request will appear once ready.',
+ ),
};
</script>
<template>
- <div
- v-if="savedContentMeta"
- class="container gl-flex-grow-1 gl-display-flex gl-flex-direction-column"
- >
- <div class="gl-fixed gl-left-0 gl-right-0 gl-border-b-solid gl-border-b-1 gl-border-b-gray-100">
+ <div>
+ <div class="gl-border-b-solid gl-border-b-1 gl-border-b-gray-100">
<div class="container gl-py-4">
- <gl-button
- v-if="appData.returnUrl"
- ref="returnToSiteButton"
- class="gl-mr-5"
- :href="appData.returnUrl"
- >{{ $options.returnToSiteBtnText }}</gl-button
- >
- <strong>
- {{ updatedFileDescription }}
- </strong>
+ <div class="gl-display-flex">
+ <gl-button
+ v-if="appData.returnUrl"
+ ref="returnToSiteButton"
+ class="gl-mr-5 gl-align-self-start"
+ :href="appData.returnUrl"
+ >{{ $options.returnToSiteBtnText }}</gl-button
+ >
+ <strong class="gl-mt-2">
+ {{ updatedFileDescription }}
+ </strong>
+ </div>
</div>
</div>
- <gl-empty-state
- class="gl-my-9"
- :primary-button-text="$options.primaryButtonText"
- :title="$options.title"
- :primary-button-link="savedContentMeta.mergeRequest.url"
- :svg-path="mergeRequestsIllustrationPath"
- >
- <template #description>
- <p>{{ $options.mergeRequestInstructionsHeading }}</p>
- <p>{{ $options.addTitleInstruction }}</p>
- <p>{{ $options.addDescriptionInstruction }}</p>
- <p>{{ $options.assignMergeRequestInstruction }}</p>
- </template>
- </gl-empty-state>
+ <div class="container">
+ <gl-empty-state
+ class="gl-my-7"
+ :title="savedContentMeta ? $options.title : $options.submittingTitle"
+ :primary-button-text="savedContentMeta && $options.primaryButtonText"
+ :primary-button-link="savedContentMeta && savedContentMeta.mergeRequest.url"
+ :svg-path="mergeRequestsIllustrationPath"
+ :svg-height="146"
+ >
+ <template #description>
+ <div v-if="savedContentMeta">
+ <p>{{ $options.mergeRequestInstructionsHeading }}</p>
+ <p>{{ $options.addTitleInstruction }}</p>
+ <p>{{ $options.addDescriptionInstruction }}</p>
+ <p>{{ $options.assignMergeRequestInstruction }}</p>
+ </div>
+ <div v-else>
+ <p>{{ $options.submittingNotePrimary }}</p>
+ <p>{{ $options.submittingNoteSecondary }}</p>
+ <gl-loading-icon size="xl" />
+ </div>
+ </template>
+ </gl-empty-state>
+ </div>
</div>
</template>
diff --git a/app/assets/javascripts/static_site_editor/services/front_matterify.js b/app/assets/javascripts/static_site_editor/services/front_matterify.js
new file mode 100644
index 00000000000..cbf0fffd515
--- /dev/null
+++ b/app/assets/javascripts/static_site_editor/services/front_matterify.js
@@ -0,0 +1,73 @@
+import jsYaml from 'js-yaml';
+
+const NEW_LINE = '\n';
+
+const hasMatter = (firstThreeChars, fourthChar) => {
+ const isYamlDelimiter = firstThreeChars === '---';
+ const isFourthCharNewline = fourthChar === NEW_LINE;
+ return isYamlDelimiter && isFourthCharNewline;
+};
+
+export const frontMatterify = source => {
+ let index = 3;
+ let offset;
+ const delimiter = source.slice(0, index);
+ const type = 'yaml';
+ const NO_FRONTMATTER = {
+ source,
+ matter: null,
+ spacing: null,
+ content: source,
+ delimiter: null,
+ type: null,
+ };
+
+ if (!hasMatter(delimiter, source.charAt(index))) {
+ return NO_FRONTMATTER;
+ }
+
+ offset = source.indexOf(delimiter, index);
+
+ // Finds the end delimiter that starts at a new line
+ while (offset !== -1 && source.charAt(offset - 1) !== NEW_LINE) {
+ index = offset + delimiter.length;
+ offset = source.indexOf(delimiter, index);
+ }
+
+ if (offset === -1) {
+ return NO_FRONTMATTER;
+ }
+
+ const matterStr = source.slice(index, offset);
+ const matter = jsYaml.safeLoad(matterStr);
+
+ let content = source.slice(offset + delimiter.length);
+ let spacing = '';
+ let idx = 0;
+ while (content.charAt(idx).match(/(\s|\n)/)) {
+ spacing += content.charAt(idx);
+ idx += 1;
+ }
+ content = content.replace(spacing, '');
+
+ return {
+ source,
+ matter,
+ spacing,
+ content,
+ delimiter,
+ type,
+ };
+};
+
+export const stringify = ({ matter, spacing, content, delimiter }, newMatter) => {
+ const matterObj = newMatter || matter;
+
+ if (!matterObj) {
+ return content;
+ }
+
+ const header = `${delimiter}${NEW_LINE}${jsYaml.safeDump(matterObj)}${delimiter}`;
+ const body = `${spacing}${content}`;
+ return `${header}${body}`;
+};
diff --git a/app/assets/javascripts/static_site_editor/services/parse_source_file.js b/app/assets/javascripts/static_site_editor/services/parse_source_file.js
index 640186ee1d0..d4fc8b2edb6 100644
--- a/app/assets/javascripts/static_site_editor/services/parse_source_file.js
+++ b/app/assets/javascripts/static_site_editor/services/parse_source_file.js
@@ -1,7 +1,7 @@
-import grayMatter from 'gray-matter';
+import { frontMatterify, stringify } from './front_matterify';
const parseSourceFile = raw => {
- const remake = source => grayMatter(source, {});
+ const remake = source => frontMatterify(source);
let editable = remake(raw);
@@ -13,20 +13,17 @@ const parseSourceFile = raw => {
}
};
- const trimmedEditable = () => grayMatter.stringify(editable).trim();
+ const content = (isBody = false) => (isBody ? editable.content : stringify(editable));
- const content = (isBody = false) => (isBody ? editable.content.trim() : trimmedEditable()); // gray-matter internally adds an eof newline so we trim to bypass, open issue: https://github.com/jonschlinkert/gray-matter/issues/96
-
- const matter = () => editable.data;
+ const matter = () => editable.matter;
const syncMatter = settings => {
- const source = grayMatter.stringify(editable.content, settings);
- syncContent(source);
+ editable.matter = settings;
};
- const isModified = () => trimmedEditable() !== raw;
+ const isModified = () => stringify(editable) !== raw;
- const hasMatter = () => editable.matter.length > 0;
+ const hasMatter = () => Boolean(editable.matter);
return {
matter,
diff --git a/app/assets/javascripts/static_site_editor/services/submit_content_changes.js b/app/assets/javascripts/static_site_editor/services/submit_content_changes.js
index da62d3fa4fc..8623a671a7d 100644
--- a/app/assets/javascripts/static_site_editor/services/submit_content_changes.js
+++ b/app/assets/javascripts/static_site_editor/services/submit_content_changes.js
@@ -1,6 +1,5 @@
import Api from '~/api';
import Tracking from '~/tracking';
-import { s__, sprintf } from '~/locale';
import { convertObjectPropsToSnakeCase } from '~/lib/utils/common_utils';
import generateBranchName from '~/static_site_editor/services/generate_branch_name';
@@ -71,6 +70,7 @@ const commitContent = (projectId, message, branch, sourcePath, content, images)
const createMergeRequest = (
projectId,
title,
+ description,
sourceBranch,
targetBranch = DEFAULT_TARGET_BRANCH,
) => {
@@ -80,6 +80,7 @@ const createMergeRequest = (
projectId,
convertObjectPropsToSnakeCase({
title,
+ description,
sourceBranch,
targetBranch,
}),
@@ -88,11 +89,16 @@ const createMergeRequest = (
});
};
-const submitContentChanges = ({ username, projectId, sourcePath, content, images }) => {
+const submitContentChanges = ({
+ username,
+ projectId,
+ sourcePath,
+ content,
+ images,
+ mergeRequestMeta,
+}) => {
const branch = generateBranchName(username);
- const mergeRequestTitle = sprintf(s__(`StaticSiteEditor|Update %{sourcePath} file`), {
- sourcePath,
- });
+ const { title: mergeRequestTitle, description: mergeRequestDescription } = mergeRequestMeta;
const meta = {};
return createBranch(projectId, branch)
@@ -104,7 +110,7 @@ const submitContentChanges = ({ username, projectId, sourcePath, content, images
.then(({ data: { short_id: label, web_url: url } }) => {
Object.assign(meta, { commit: { label, url } });
- return createMergeRequest(projectId, mergeRequestTitle, branch);
+ return createMergeRequest(projectId, mergeRequestTitle, mergeRequestDescription, branch);
})
.then(({ data: { iid: label, web_url: url } }) => {
Object.assign(meta, { mergeRequest: { label: label.toString(), url } });
diff --git a/app/assets/javascripts/static_site_editor/services/templater.js b/app/assets/javascripts/static_site_editor/services/templater.js
index a1c1bb6b8d6..d302aea78a3 100644
--- a/app/assets/javascripts/static_site_editor/services/templater.js
+++ b/app/assets/javascripts/static_site_editor/services/templater.js
@@ -15,7 +15,7 @@ const markPrefix = `${marker}-${Date.now()}`;
const reHelpers = {
template: `.| |\\t|\\n(?!(\\n|${markPrefix}))`,
- openTag: '<[a-zA-Z]+.*?>',
+ openTag: '<(?!figure|iframe)[a-zA-Z]+.*?>',
closeTag: '</.+>',
};
const reTemplated = new RegExp(`(^${wrapPrefix}(${reHelpers.template})+?${wrapPostfix}$)`, 'gm');
diff --git a/app/assets/javascripts/task_list.js b/app/assets/javascripts/task_list.js
index f2b05946a08..b51951674d5 100644
--- a/app/assets/javascripts/task_list.js
+++ b/app/assets/javascripts/task_list.js
@@ -31,6 +31,15 @@ export default class TaskList {
init() {
this.disable(); // Prevent duplicate event bindings
+ const taskListFields = document.querySelectorAll(
+ `${this.taskListContainerSelector} .js-task-list-field[data-value]`,
+ );
+
+ taskListFields.forEach(taskListField => {
+ // eslint-disable-next-line no-param-reassign
+ taskListField.value = taskListField.dataset.value;
+ });
+
$(this.taskListContainerSelector).taskList('enable');
$(document).on('tasklist:changed', this.taskListContainerSelector, this.updateHandler);
}
diff --git a/app/assets/javascripts/test_utils/simulate_drag.js b/app/assets/javascripts/test_utils/simulate_drag.js
index f4090de3f1e..321315d531b 100644
--- a/app/assets/javascripts/test_utils/simulate_drag.js
+++ b/app/assets/javascripts/test_utils/simulate_drag.js
@@ -143,7 +143,7 @@ export default function simulateDrag(options) {
const dragInterval = setInterval(() => {
const progress = (new Date().getTime() - startTime) / duration;
const x = fromRect.cx + (toRect.cx - fromRect.cx) * progress;
- const y = fromRect.cy + (toRect.cy - fromRect.cy) * progress;
+ const y = fromRect.cy + (toRect.cy - fromRect.cy + options.extraHeight) * progress;
const overEl = fromEl.ownerDocument.elementFromPoint(x, y);
simulateEvent(overEl, 'pointermove', {
diff --git a/app/assets/javascripts/tooltips/index.js b/app/assets/javascripts/tooltips/index.js
index cfbd88d6c40..9f5dce4183c 100644
--- a/app/assets/javascripts/tooltips/index.js
+++ b/app/assets/javascripts/tooltips/index.js
@@ -1,6 +1,6 @@
import Vue from 'vue';
import jQuery from 'jquery';
-import { toArray, isFunction } from 'lodash';
+import { toArray, isFunction, isElement } from 'lodash';
import Tooltips from './components/tooltips.vue';
let app;
@@ -54,10 +54,16 @@ const handleTooltipEvent = (rootTarget, e, selector, config = {}) => {
}
};
-const applyToElements = (elements, handler) => toArray(elements).forEach(handler);
+const applyToElements = (elements, handler) => {
+ const iterable = isElement(elements) ? [elements] : toArray(elements);
+
+ toArray(iterable).forEach(handler);
+};
const invokeBootstrapApi = (elements, method) => {
if (isFunction(elements.tooltip)) {
+ elements.tooltip(method);
+ } else {
jQuery(elements).tooltip(method);
}
};
diff --git a/app/assets/javascripts/tracking.js b/app/assets/javascripts/tracking.js
index 37ebe6b6c4d..c1521882682 100644
--- a/app/assets/javascripts/tracking.js
+++ b/app/assets/javascripts/tracking.js
@@ -9,7 +9,7 @@ const DEFAULT_SNOWPLOW_OPTIONS = {
respectDoNotTrack: true,
forceSecureTracker: true,
eventMethod: 'post',
- contexts: { webPage: true },
+ contexts: { webPage: true, performanceTiming: true },
formTracking: false,
linkClickTracking: false,
};
diff --git a/app/assets/javascripts/user_lists/components/add_user_modal.vue b/app/assets/javascripts/user_lists/components/add_user_modal.vue
new file mode 100644
index 00000000000..a8dde1f681e
--- /dev/null
+++ b/app/assets/javascripts/user_lists/components/add_user_modal.vue
@@ -0,0 +1,72 @@
+<script>
+import { GlModal, GlFormGroup, GlFormTextarea } from '@gitlab/ui';
+import { s__ } from '~/locale';
+import { ADD_USER_MODAL_ID } from '../constants/show';
+
+export default {
+ components: {
+ GlFormGroup,
+ GlFormTextarea,
+ GlModal,
+ },
+ props: {
+ visible: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ },
+ modalOptions: {
+ actionPrimary: {
+ text: s__('UserLists|Add'),
+ attributes: [{ 'data-testid': 'confirm-add-user-ids' }],
+ },
+ actionCancel: {
+ text: s__('UserLists|Cancel'),
+ attributes: [{ 'data-testid': 'cancel-add-user-ids' }],
+ },
+ modalId: ADD_USER_MODAL_ID,
+ static: true,
+ },
+ translations: {
+ title: s__('UserLists|Add users'),
+ description: s__(
+ 'UserLists|Enter a comma separated list of user IDs. These IDs should be the users of the system in which the feature flag is set, not GitLab IDs',
+ ),
+ userIdsLabel: s__('UserLists|User IDs'),
+ },
+ data() {
+ return {
+ userIds: '',
+ };
+ },
+ methods: {
+ submitUsers() {
+ this.$emit('addUsers', this.userIds);
+ this.clearInput();
+ },
+ clearInput() {
+ this.userIds = '';
+ },
+ },
+};
+</script>
+<template>
+ <gl-modal
+ v-bind="$options.modalOptions"
+ :visible="visible"
+ data-testid="add-users-modal"
+ @primary="submitUsers"
+ @canceled="clearInput"
+ >
+ <template #modal-title>
+ {{ $options.translations.title }}
+ </template>
+ <template #default>
+ <p data-testid="add-userids-description">{{ $options.translations.description }}</p>
+ <gl-form-group label-for="add-user-ids" :label="$options.translations.userIdsLabel">
+ <gl-form-textarea id="add-user-ids" v-model="userIds" />
+ </gl-form-group>
+ </template>
+ </gl-modal>
+</template>
diff --git a/app/assets/javascripts/user_lists/components/edit_user_list.vue b/app/assets/javascripts/user_lists/components/edit_user_list.vue
new file mode 100644
index 00000000000..d56c3d61027
--- /dev/null
+++ b/app/assets/javascripts/user_lists/components/edit_user_list.vue
@@ -0,0 +1,74 @@
+<script>
+import { mapActions, mapState } from 'vuex';
+import { GlAlert, GlLoadingIcon } from '@gitlab/ui';
+import { s__, sprintf } from '~/locale';
+import statuses from '../constants/edit';
+import UserListForm from './user_list_form.vue';
+
+export default {
+ components: {
+ GlAlert,
+ GlLoadingIcon,
+ UserListForm,
+ },
+ inject: ['userListsDocsPath'],
+ translations: {
+ saveButtonLabel: s__('UserLists|Save'),
+ },
+ computed: {
+ ...mapState(['userList', 'status', 'errorMessage']),
+ title() {
+ return sprintf(s__('UserLists|Edit %{name}'), { name: this.userList?.name });
+ },
+ isLoading() {
+ return this.status === statuses.LOADING;
+ },
+ isError() {
+ return this.status === statuses.ERROR;
+ },
+ hasUserList() {
+ return Boolean(this.userList);
+ },
+ },
+ mounted() {
+ this.fetchUserList();
+ },
+ methods: {
+ ...mapActions(['fetchUserList', 'updateUserList', 'dismissErrorAlert']),
+ },
+};
+</script>
+<template>
+ <div>
+ <gl-alert
+ v-if="isError"
+ :dismissible="hasUserList"
+ variant="danger"
+ @dismiss="dismissErrorAlert"
+ >
+ <ul class="gl-mb-0">
+ <li v-for="(message, index) in errorMessage" :key="index">
+ {{ message }}
+ </li>
+ </ul>
+ </gl-alert>
+
+ <gl-loading-icon v-if="isLoading" size="xl" />
+
+ <template v-else-if="hasUserList">
+ <h3
+ data-testid="user-list-title"
+ class="gl-font-weight-bold gl-pb-5 gl-border-b-solid gl-border-gray-100 gl-border-1"
+ >
+ {{ title }}
+ </h3>
+ <user-list-form
+ :cancel-path="userList.path"
+ :save-button-label="$options.translations.saveButtonLabel"
+ :user-lists-docs-path="userListsDocsPath"
+ :user-list="userList"
+ @submit="updateUserList"
+ />
+ </template>
+ </div>
+</template>
diff --git a/app/assets/javascripts/user_lists/components/new_user_list.vue b/app/assets/javascripts/user_lists/components/new_user_list.vue
new file mode 100644
index 00000000000..522e077fb25
--- /dev/null
+++ b/app/assets/javascripts/user_lists/components/new_user_list.vue
@@ -0,0 +1,50 @@
+<script>
+import { mapActions, mapState } from 'vuex';
+import { GlAlert } from '@gitlab/ui';
+import { s__ } from '~/locale';
+import UserListForm from './user_list_form.vue';
+
+export default {
+ components: {
+ GlAlert,
+ UserListForm,
+ },
+ inject: ['userListsDocsPath', 'featureFlagsPath'],
+ translations: {
+ pageTitle: s__('UserLists|New list'),
+ createButtonLabel: s__('UserLists|Create'),
+ },
+ computed: {
+ ...mapState(['userList', 'errorMessage']),
+ isError() {
+ return Array.isArray(this.errorMessage) && this.errorMessage.length > 0;
+ },
+ },
+ methods: {
+ ...mapActions(['createUserList', 'dismissErrorAlert']),
+ },
+};
+</script>
+<template>
+ <div>
+ <gl-alert v-if="isError" variant="danger" @dismiss="dismissErrorAlert">
+ <ul class="gl-mb-0">
+ <li v-for="(message, index) in errorMessage" :key="index">
+ {{ message }}
+ </li>
+ </ul>
+ </gl-alert>
+
+ <h3 class="gl-font-weight-bold gl-pb-5 gl-border-b-solid gl-border-gray-100 gl-border-1">
+ {{ $options.translations.pageTitle }}
+ </h3>
+
+ <user-list-form
+ :cancel-path="featureFlagsPath"
+ :save-button-label="$options.translations.createButtonLabel"
+ :user-lists-docs-path="userListsDocsPath"
+ :user-list="userList"
+ @submit="createUserList"
+ />
+ </div>
+</template>
diff --git a/app/assets/javascripts/user_lists/components/user_list.vue b/app/assets/javascripts/user_lists/components/user_list.vue
new file mode 100644
index 00000000000..0e2b72c1423
--- /dev/null
+++ b/app/assets/javascripts/user_lists/components/user_list.vue
@@ -0,0 +1,142 @@
+<script>
+import { mapActions, mapState } from 'vuex';
+import {
+ GlAlert,
+ GlButton,
+ GlEmptyState,
+ GlLoadingIcon,
+ GlModalDirective as GlModal,
+} from '@gitlab/ui';
+import { s__, __ } from '~/locale';
+import { states, ADD_USER_MODAL_ID } from '../constants/show';
+import AddUserModal from './add_user_modal.vue';
+
+const commonTableClasses = ['gl-py-5', 'gl-border-b-1', 'gl-border-b-solid', 'gl-border-gray-100'];
+
+export default {
+ components: {
+ GlAlert,
+ GlButton,
+ GlEmptyState,
+ GlLoadingIcon,
+ AddUserModal,
+ },
+ directives: {
+ GlModal,
+ },
+ props: {
+ emptyStatePath: {
+ required: true,
+ type: String,
+ },
+ },
+ translations: {
+ addUserButtonLabel: s__('UserLists|Add Users'),
+ emptyStateTitle: s__('UserLists|There are no users'),
+ emptyStateDescription: s__(
+ 'UserLists|Define a set of users to be used within feature flag strategies',
+ ),
+ userIdLabel: s__('UserLists|User IDs'),
+ userIdColumnHeader: s__('UserLists|User ID'),
+ errorMessage: __('Something went wrong on our end. Please try again!'),
+ editButtonLabel: s__('UserLists|Edit'),
+ },
+ classes: {
+ headerClasses: [
+ 'gl-display-flex',
+ 'gl-justify-content-space-between',
+ 'gl-pb-5',
+ 'gl-border-b-1',
+ 'gl-border-b-solid',
+ 'gl-border-gray-100',
+ ].join(' '),
+ tableHeaderClasses: commonTableClasses.join(' '),
+ tableRowClasses: [
+ ...commonTableClasses,
+ 'gl-display-flex',
+ 'gl-justify-content-space-between',
+ 'gl-align-items-center',
+ ].join(' '),
+ },
+ ADD_USER_MODAL_ID,
+ computed: {
+ ...mapState(['userList', 'userIds', 'state']),
+ name() {
+ return this.userList?.name ?? '';
+ },
+ hasUserIds() {
+ return this.userIds.length > 0;
+ },
+ isLoading() {
+ return this.state === states.LOADING;
+ },
+ hasError() {
+ return this.state === states.ERROR;
+ },
+ editPath() {
+ return this.userList?.edit_path;
+ },
+ },
+ mounted() {
+ this.fetchUserList();
+ },
+ methods: {
+ ...mapActions(['fetchUserList', 'dismissErrorAlert', 'removeUserId', 'addUserIds']),
+ },
+};
+</script>
+<template>
+ <div>
+ <gl-alert v-if="hasError" variant="danger" @dismiss="dismissErrorAlert">
+ {{ $options.translations.errorMessage }}
+ </gl-alert>
+ <gl-loading-icon v-if="isLoading" size="xl" class="gl-mt-6" />
+ <div v-else>
+ <add-user-modal @addUsers="addUserIds" />
+ <div :class="$options.classes.headerClasses">
+ <div>
+ <h3>{{ name }}</h3>
+ <h4 class="gl-text-gray-500">{{ $options.translations.userIdLabel }}</h4>
+ </div>
+ <div class="gl-mt-6">
+ <gl-button v-if="editPath" :href="editPath" data-testid="edit-user-list" class="gl-mr-3">
+ {{ $options.translations.editButtonLabel }}
+ </gl-button>
+ <gl-button
+ v-gl-modal="$options.ADD_USER_MODAL_ID"
+ data-testid="add-users"
+ variant="success"
+ >
+ {{ $options.translations.addUserButtonLabel }}
+ </gl-button>
+ </div>
+ </div>
+ <div v-if="hasUserIds">
+ <div :class="$options.classes.tableHeaderClasses">
+ {{ $options.translations.userIdColumnHeader }}
+ </div>
+ <div
+ v-for="id in userIds"
+ :key="id"
+ data-testid="user-id-row"
+ :class="$options.classes.tableRowClasses"
+ >
+ <span data-testid="user-id">{{ id }}</span>
+ <gl-button
+ category="secondary"
+ variant="danger"
+ icon="remove"
+ data-testid="delete-user-id"
+ @click="removeUserId(id)"
+ />
+ </div>
+ </div>
+ <gl-empty-state
+ v-else
+ :title="$options.translations.emptyStateTitle"
+ :description="$options.translations.emptyStateDescription"
+ :svg-path="emptyStatePath"
+ />
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/user_lists/components/user_list_form.vue b/app/assets/javascripts/user_lists/components/user_list_form.vue
new file mode 100644
index 00000000000..657acb51fee
--- /dev/null
+++ b/app/assets/javascripts/user_lists/components/user_list_form.vue
@@ -0,0 +1,97 @@
+<script>
+import { GlButton, GlFormGroup, GlFormInput, GlLink, GlSprintf } from '@gitlab/ui';
+import { s__ } from '~/locale';
+
+export default {
+ components: {
+ GlButton,
+ GlFormGroup,
+ GlFormInput,
+ GlLink,
+ GlSprintf,
+ },
+ props: {
+ cancelPath: {
+ type: String,
+ required: true,
+ },
+ saveButtonLabel: {
+ type: String,
+ required: true,
+ },
+ userListsDocsPath: {
+ type: String,
+ required: true,
+ },
+ userList: {
+ type: Object,
+ required: true,
+ },
+ },
+ classes: {
+ actionContainer: [
+ 'gl-py-5',
+ 'gl-display-flex',
+ 'gl-justify-content-space-between',
+ 'gl-px-4',
+ 'gl-border-t-solid',
+ 'gl-border-gray-100',
+ 'gl-border-1',
+ 'gl-bg-gray-10',
+ ],
+ },
+ translations: {
+ formLabel: s__('UserLists|Feature flag list'),
+ formSubtitle: s__(
+ 'UserLists|Lists allow you to define a set of users to be used with feature flags. %{linkStart}Read more about feature flag lists.%{linkEnd}',
+ ),
+ nameLabel: s__('UserLists|Name'),
+ cancelButtonLabel: s__('UserLists|Cancel'),
+ },
+ data() {
+ return {
+ name: this.userList.name,
+ };
+ },
+ methods: {
+ submit() {
+ this.$emit('submit', { ...this.userList, name: this.name });
+ },
+ },
+};
+</script>
+<template>
+ <div>
+ <div class="gl-display-flex gl-mt-7">
+ <div class="gl-flex-basis-0 gl-mr-7">
+ <h4 class="gl-min-width-fit-content gl-white-space-nowrap">
+ {{ $options.translations.formLabel }}
+ </h4>
+ <gl-sprintf :message="$options.translations.formSubtitle" class="gl-text-gray-500">
+ <template #link="{ content }">
+ <gl-link :href="userListsDocsPath" data-testid="user-list-docs-link">
+ {{ content }}
+ </gl-link>
+ </template>
+ </gl-sprintf>
+ </div>
+ <div class="gl-flex-fill-1 gl-ml-7">
+ <gl-form-group
+ label-for="user-list-name"
+ :label="$options.translations.nameLabel"
+ class="gl-mb-7"
+ >
+ <gl-form-input id="user-list-name" v-model="name" data-testid="user-list-name" required />
+ </gl-form-group>
+ <div :class="$options.classes.actionContainer">
+ <gl-button variant="success" data-testid="save-user-list" @click="submit">
+ {{ saveButtonLabel }}
+ </gl-button>
+ <gl-button :href="cancelPath" data-testid="user-list-cancel">
+ {{ $options.translations.cancelButtonLabel }}
+ </gl-button>
+ </div>
+ </div>
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/user_lists/constants/edit.js b/app/assets/javascripts/user_lists/constants/edit.js
new file mode 100644
index 00000000000..33378f0d39f
--- /dev/null
+++ b/app/assets/javascripts/user_lists/constants/edit.js
@@ -0,0 +1,6 @@
+export default Object.freeze({
+ LOADING: 'LOADING',
+ SUCCESS: 'SUCCESS',
+ ERROR: 'ERROR',
+ UNSYNCED: 'UNSYNCED',
+});
diff --git a/app/assets/javascripts/user_lists/constants/show.js b/app/assets/javascripts/user_lists/constants/show.js
new file mode 100644
index 00000000000..045375d5900
--- /dev/null
+++ b/app/assets/javascripts/user_lists/constants/show.js
@@ -0,0 +1,8 @@
+export const states = Object.freeze({
+ LOADING: 'LOADING',
+ SUCCESS: 'SUCCESS',
+ ERROR: 'ERROR',
+ ERROR_DISMISSED: 'ERROR_DISMISSED',
+});
+
+export const ADD_USER_MODAL_ID = 'add-userids-modal';
diff --git a/app/assets/javascripts/user_lists/store/edit/actions.js b/app/assets/javascripts/user_lists/store/edit/actions.js
new file mode 100644
index 00000000000..8f0a2bafec7
--- /dev/null
+++ b/app/assets/javascripts/user_lists/store/edit/actions.js
@@ -0,0 +1,22 @@
+import Api from '~/api';
+import { redirectTo } from '~/lib/utils/url_utility';
+import { getErrorMessages } from '../utils';
+import * as types from './mutation_types';
+
+export const fetchUserList = ({ commit, state }) => {
+ commit(types.REQUEST_USER_LIST);
+ return Api.fetchFeatureFlagUserList(state.projectId, state.userListIid)
+ .then(({ data }) => commit(types.RECEIVE_USER_LIST_SUCCESS, data))
+ .catch(response => commit(types.RECEIVE_USER_LIST_ERROR, getErrorMessages(response)));
+};
+
+export const dismissErrorAlert = ({ commit }) => commit(types.DISMISS_ERROR_ALERT);
+
+export const updateUserList = ({ commit, state }, userList) => {
+ return Api.updateFeatureFlagUserList(state.projectId, {
+ iid: userList.iid,
+ name: userList.name,
+ })
+ .then(({ data }) => redirectTo(data.path))
+ .catch(response => commit(types.RECEIVE_USER_LIST_ERROR, getErrorMessages(response)));
+};
diff --git a/app/assets/javascripts/user_lists/store/edit/index.js b/app/assets/javascripts/user_lists/store/edit/index.js
new file mode 100644
index 00000000000..b30b0b04b9e
--- /dev/null
+++ b/app/assets/javascripts/user_lists/store/edit/index.js
@@ -0,0 +1,11 @@
+import Vuex from 'vuex';
+import createState from './state';
+import * as actions from './actions';
+import mutations from './mutations';
+
+export default initialState =>
+ new Vuex.Store({
+ actions,
+ mutations,
+ state: createState(initialState),
+ });
diff --git a/app/assets/javascripts/user_lists/store/edit/mutation_types.js b/app/assets/javascripts/user_lists/store/edit/mutation_types.js
new file mode 100644
index 00000000000..8b572e36839
--- /dev/null
+++ b/app/assets/javascripts/user_lists/store/edit/mutation_types.js
@@ -0,0 +1,5 @@
+export const REQUEST_USER_LIST = 'REQUEST_USER_LIST';
+export const RECEIVE_USER_LIST_SUCCESS = 'RECEIVE_USER_LIST_SUCCESS';
+export const RECEIVE_USER_LIST_ERROR = 'RECEIVE_USER_LIST_ERROR';
+
+export const DISMISS_ERROR_ALERT = 'DISMISS_ERROR_ALERT';
diff --git a/app/assets/javascripts/user_lists/store/edit/mutations.js b/app/assets/javascripts/user_lists/store/edit/mutations.js
new file mode 100644
index 00000000000..8a202885069
--- /dev/null
+++ b/app/assets/javascripts/user_lists/store/edit/mutations.js
@@ -0,0 +1,19 @@
+import statuses from '../../constants/edit';
+import * as types from './mutation_types';
+
+export default {
+ [types.REQUEST_USER_LIST](state) {
+ state.status = statuses.LOADING;
+ },
+ [types.RECEIVE_USER_LIST_SUCCESS](state, userList) {
+ state.status = statuses.SUCCESS;
+ state.userList = userList;
+ },
+ [types.RECEIVE_USER_LIST_ERROR](state, error) {
+ state.status = statuses.ERROR;
+ state.errorMessage = error;
+ },
+ [types.DISMISS_ERROR_ALERT](state) {
+ state.status = statuses.UNSYNCED;
+ },
+};
diff --git a/app/assets/javascripts/user_lists/store/edit/state.js b/app/assets/javascripts/user_lists/store/edit/state.js
new file mode 100644
index 00000000000..66fbe3c2ba9
--- /dev/null
+++ b/app/assets/javascripts/user_lists/store/edit/state.js
@@ -0,0 +1,9 @@
+import statuses from '../../constants/edit';
+
+export default ({ projectId = '', userListIid = '' }) => ({
+ status: statuses.LOADING,
+ projectId,
+ userListIid,
+ userList: null,
+ errorMessage: [],
+});
diff --git a/app/assets/javascripts/user_lists/store/new/actions.js b/app/assets/javascripts/user_lists/store/new/actions.js
new file mode 100644
index 00000000000..185508bcfbc
--- /dev/null
+++ b/app/assets/javascripts/user_lists/store/new/actions.js
@@ -0,0 +1,15 @@
+import Api from '~/api';
+import { redirectTo } from '~/lib/utils/url_utility';
+import { getErrorMessages } from '../utils';
+import * as types from './mutation_types';
+
+export const dismissErrorAlert = ({ commit }) => commit(types.DISMISS_ERROR_ALERT);
+
+export const createUserList = ({ commit, state }, userList) => {
+ return Api.createFeatureFlagUserList(state.projectId, {
+ ...state.userList,
+ ...userList,
+ })
+ .then(({ data }) => redirectTo(data.path))
+ .catch(response => commit(types.RECEIVE_CREATE_USER_LIST_ERROR, getErrorMessages(response)));
+};
diff --git a/app/assets/javascripts/user_lists/store/new/index.js b/app/assets/javascripts/user_lists/store/new/index.js
new file mode 100644
index 00000000000..b30b0b04b9e
--- /dev/null
+++ b/app/assets/javascripts/user_lists/store/new/index.js
@@ -0,0 +1,11 @@
+import Vuex from 'vuex';
+import createState from './state';
+import * as actions from './actions';
+import mutations from './mutations';
+
+export default initialState =>
+ new Vuex.Store({
+ actions,
+ mutations,
+ state: createState(initialState),
+ });
diff --git a/app/assets/javascripts/user_lists/store/new/mutation_types.js b/app/assets/javascripts/user_lists/store/new/mutation_types.js
new file mode 100644
index 00000000000..9a5ce6e99f5
--- /dev/null
+++ b/app/assets/javascripts/user_lists/store/new/mutation_types.js
@@ -0,0 +1,3 @@
+export const RECEIVE_CREATE_USER_LIST_ERROR = 'RECEIVE_CREATE_USER_LIST_ERROR';
+
+export const DISMISS_ERROR_ALERT = 'DISMISS_ERROR_ALERT';
diff --git a/app/assets/javascripts/user_lists/store/new/mutations.js b/app/assets/javascripts/user_lists/store/new/mutations.js
new file mode 100644
index 00000000000..d7c1276bd72
--- /dev/null
+++ b/app/assets/javascripts/user_lists/store/new/mutations.js
@@ -0,0 +1,10 @@
+import * as types from './mutation_types';
+
+export default {
+ [types.RECEIVE_CREATE_USER_LIST_ERROR](state, error) {
+ state.errorMessage = error;
+ },
+ [types.DISMISS_ERROR_ALERT](state) {
+ state.errorMessage = '';
+ },
+};
diff --git a/app/assets/javascripts/user_lists/store/new/state.js b/app/assets/javascripts/user_lists/store/new/state.js
new file mode 100644
index 00000000000..0fa73b4ffc1
--- /dev/null
+++ b/app/assets/javascripts/user_lists/store/new/state.js
@@ -0,0 +1,5 @@
+export default ({ projectId = '' }) => ({
+ projectId,
+ userList: { name: '', user_xids: '' },
+ errorMessage: [],
+});
diff --git a/app/assets/javascripts/user_lists/store/show/actions.js b/app/assets/javascripts/user_lists/store/show/actions.js
new file mode 100644
index 00000000000..15b971aa5e8
--- /dev/null
+++ b/app/assets/javascripts/user_lists/store/show/actions.js
@@ -0,0 +1,32 @@
+import Api from '~/api';
+import { stringifyUserIds } from '../utils';
+import * as types from './mutation_types';
+
+export const fetchUserList = ({ commit, state }) => {
+ commit(types.REQUEST_USER_LIST);
+ return Api.fetchFeatureFlagUserList(state.projectId, state.userListIid)
+ .then(response => commit(types.RECEIVE_USER_LIST_SUCCESS, response.data))
+ .catch(() => commit(types.RECEIVE_USER_LIST_ERROR));
+};
+
+export const dismissErrorAlert = ({ commit }) => commit(types.DISMISS_ERROR_ALERT);
+export const addUserIds = ({ dispatch, commit }, userIds) => {
+ commit(types.ADD_USER_IDS, userIds);
+ return dispatch('updateUserList');
+};
+
+export const removeUserId = ({ commit, dispatch }, userId) => {
+ commit(types.REMOVE_USER_ID, userId);
+ return dispatch('updateUserList');
+};
+
+export const updateUserList = ({ commit, state }) => {
+ commit(types.REQUEST_USER_LIST);
+
+ return Api.updateFeatureFlagUserList(state.projectId, {
+ ...state.userList,
+ user_xids: stringifyUserIds(state.userIds),
+ })
+ .then(response => commit(types.RECEIVE_USER_LIST_SUCCESS, response.data))
+ .catch(() => commit(types.RECEIVE_USER_LIST_ERROR));
+};
diff --git a/app/assets/javascripts/user_lists/store/show/index.js b/app/assets/javascripts/user_lists/store/show/index.js
new file mode 100644
index 00000000000..b30b0b04b9e
--- /dev/null
+++ b/app/assets/javascripts/user_lists/store/show/index.js
@@ -0,0 +1,11 @@
+import Vuex from 'vuex';
+import createState from './state';
+import * as actions from './actions';
+import mutations from './mutations';
+
+export default initialState =>
+ new Vuex.Store({
+ actions,
+ mutations,
+ state: createState(initialState),
+ });
diff --git a/app/assets/javascripts/user_lists/store/show/mutation_types.js b/app/assets/javascripts/user_lists/store/show/mutation_types.js
new file mode 100644
index 00000000000..fb967f06beb
--- /dev/null
+++ b/app/assets/javascripts/user_lists/store/show/mutation_types.js
@@ -0,0 +1,8 @@
+export const REQUEST_USER_LIST = 'REQUEST_USER_LIST';
+export const RECEIVE_USER_LIST_SUCCESS = 'RECEIVE_USER_LIST_SUCCESS';
+export const RECEIVE_USER_LIST_ERROR = 'RECEIVE_USER_LIST_ERROR';
+
+export const DISMISS_ERROR_ALERT = 'DISMISS_ERROR_ALERT';
+
+export const ADD_USER_IDS = 'ADD_USER_IDS';
+export const REMOVE_USER_ID = 'REMOVE_USER_ID';
diff --git a/app/assets/javascripts/user_lists/store/show/mutations.js b/app/assets/javascripts/user_lists/store/show/mutations.js
new file mode 100644
index 00000000000..c3e766465a7
--- /dev/null
+++ b/app/assets/javascripts/user_lists/store/show/mutations.js
@@ -0,0 +1,29 @@
+import { states } from '../../constants/show';
+import * as types from './mutation_types';
+import { parseUserIds } from '../utils';
+
+export default {
+ [types.REQUEST_USER_LIST](state) {
+ state.state = states.LOADING;
+ },
+ [types.RECEIVE_USER_LIST_SUCCESS](state, userList) {
+ state.state = states.SUCCESS;
+ state.userIds = userList.user_xids?.length > 0 ? parseUserIds(userList.user_xids) : [];
+ state.userList = userList;
+ },
+ [types.RECEIVE_USER_LIST_ERROR](state) {
+ state.state = states.ERROR;
+ },
+ [types.DISMISS_ERROR_ALERT](state) {
+ state.state = states.ERROR_DISMISSED;
+ },
+ [types.ADD_USER_IDS](state, ids) {
+ state.userIds = [
+ ...state.userIds,
+ ...parseUserIds(ids).filter(id => id && !state.userIds.includes(id)),
+ ];
+ },
+ [types.REMOVE_USER_ID](state, id) {
+ state.userIds = state.userIds.filter(uid => uid !== id);
+ },
+};
diff --git a/app/assets/javascripts/user_lists/store/show/state.js b/app/assets/javascripts/user_lists/store/show/state.js
new file mode 100644
index 00000000000..a5780893ccb
--- /dev/null
+++ b/app/assets/javascripts/user_lists/store/show/state.js
@@ -0,0 +1,9 @@
+import { states } from '../../constants/show';
+
+export default ({ projectId = '', userListIid = '' }) => ({
+ state: states.LOADING,
+ projectId,
+ userListIid,
+ userIds: [],
+ userList: null,
+});
diff --git a/app/assets/javascripts/user_lists/store/utils.js b/app/assets/javascripts/user_lists/store/utils.js
new file mode 100644
index 00000000000..f4e46947759
--- /dev/null
+++ b/app/assets/javascripts/user_lists/store/utils.js
@@ -0,0 +1,5 @@
+export const parseUserIds = userIds => userIds.split(/\s*,\s*/g);
+
+export const stringifyUserIds = userIds => userIds.join(',');
+
+export const getErrorMessages = error => [].concat(error?.response?.data?.message ?? error.message);
diff --git a/app/assets/javascripts/user_popovers.js b/app/assets/javascripts/user_popovers.js
index c8f95dac48e..3521c1a105f 100644
--- a/app/assets/javascripts/user_popovers.js
+++ b/app/assets/javascripts/user_popovers.js
@@ -1,6 +1,6 @@
import Vue from 'vue';
-import { sanitize } from 'dompurify';
+import { sanitize } from '~/lib/dompurify';
import UsersCache from './lib/utils/users_cache';
import UserPopover from './vue_shared/components/user_popover/user_popover.vue';
@@ -42,6 +42,7 @@ const populateUserInfo = user => {
bio: userData.bio,
bioHtml: sanitize(userData.bio_html),
workInformation: userData.work_information,
+ websiteUrl: userData.website_url,
loaded: true,
});
}
diff --git a/app/assets/javascripts/users_select/index.js b/app/assets/javascripts/users_select/index.js
index 5f4260f26ff..20d1a3c1fcd 100644
--- a/app/assets/javascripts/users_select/index.js
+++ b/app/assets/javascripts/users_select/index.js
@@ -19,6 +19,7 @@ import initDeprecatedJQueryDropdown from '~/deprecated_jquery_dropdown';
window.emitSidebarEvent = window.emitSidebarEvent || $.noop;
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);
@@ -127,9 +128,16 @@ function UsersSelect(currentUser, els, options = {}) {
.find(`input[name='${$dropdown.data('fieldName')}'][value=${firstSelectedId}]`);
firstSelected.remove();
- emitSidebarEvent('sidebar.removeAssignee', {
- id: firstSelectedId,
- });
+
+ if ($dropdown.hasClass(elsClassName)) {
+ emitSidebarEvent('sidebar.removeReviewer', {
+ id: firstSelectedId,
+ });
+ } else {
+ emitSidebarEvent('sidebar.removeAssignee', {
+ id: firstSelectedId,
+ });
+ }
}
}
};
@@ -392,7 +400,11 @@ function UsersSelect(currentUser, els, options = {}) {
defaultLabel,
hidden() {
if ($dropdown.hasClass('js-multiselect')) {
- emitSidebarEvent('sidebar.saveAssignees');
+ if ($dropdown.hasClass(elsClassName)) {
+ emitSidebarEvent('sidebar.saveReviewers');
+ } else {
+ emitSidebarEvent('sidebar.saveAssignees');
+ }
}
if (!$dropdown.data('alwaysShowSelectbox')) {
@@ -428,10 +440,18 @@ function UsersSelect(currentUser, els, options = {}) {
previouslySelected.each((index, element) => {
element.remove();
});
- emitSidebarEvent('sidebar.removeAllAssignees');
+ if ($dropdown.hasClass(elsClassName)) {
+ emitSidebarEvent('sidebar.removeAllReviewers');
+ } else {
+ emitSidebarEvent('sidebar.removeAllAssignees');
+ }
} else if (isActive) {
// user selected
- emitSidebarEvent('sidebar.addAssignee', user);
+ if ($dropdown.hasClass(elsClassName)) {
+ emitSidebarEvent('sidebar.addReviewer', user);
+ } else {
+ emitSidebarEvent('sidebar.addAssignee', user);
+ }
// Remove unassigned selection (if it was previously selected)
const unassignedSelected = $dropdown
@@ -448,7 +468,11 @@ function UsersSelect(currentUser, els, options = {}) {
}
// User unselected
- emitSidebarEvent('sidebar.removeAssignee', user);
+ if ($dropdown.hasClass(elsClassName)) {
+ emitSidebarEvent('sidebar.removeReviewer', user);
+ } else {
+ emitSidebarEvent('sidebar.removeAssignee', user);
+ }
}
if (getSelected().find(u => u === gon.current_user_id)) {
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/deployment/deployment_actions.vue b/app/assets/javascripts/vue_merge_request_widget/components/deployment/deployment_actions.vue
index 208df03b6a4..b90cbfd1a1a 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/deployment/deployment_actions.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/deployment/deployment_actions.vue
@@ -74,9 +74,6 @@ export default {
canBeManuallyRedeployed() {
return this.computedDeploymentStatus === FAILED && Boolean(this.redeployPath);
},
- shouldShowManualButtons() {
- return this.glFeatures.deployFromFooter;
- },
hasExternalUrls() {
return Boolean(this.deployment.external_url && this.deployment.external_url_formatted);
},
@@ -154,7 +151,7 @@ export default {
<template>
<div>
<deployment-action-button
- v-if="shouldShowManualButtons && canBeManuallyDeployed"
+ v-if="canBeManuallyDeployed"
:action-in-progress="actionInProgress"
:actions-configuration="$options.actionsConfiguration[constants.DEPLOYING]"
:computed-deployment-status="computedDeploymentStatus"
@@ -165,7 +162,7 @@ export default {
<span>{{ $options.actionsConfiguration[constants.DEPLOYING].buttonText }}</span>
</deployment-action-button>
<deployment-action-button
- v-if="shouldShowManualButtons && canBeManuallyRedeployed"
+ v-if="canBeManuallyRedeployed"
:action-in-progress="actionInProgress"
:actions-configuration="$options.actionsConfiguration[constants.REDEPLOYING]"
:computed-deployment-status="computedDeploymentStatus"
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 157d6d60290..e3c0b7935d7 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,12 +72,7 @@ export default {
css-class="deploy-link js-deploy-url inline"
/>
<gl-dropdown size="small" class="js-mr-wigdet-deployment-dropdown">
- <gl-search-box-by-type
- v-model.trim="searchTerm"
- v-autofocusonshow
- autofocus
- class="gl-m-3"
- />
+ <gl-search-box-by-type v-model.trim="searchTerm" v-autofocusonshow autofocus />
<gl-dropdown-item
v-for="change in filteredChanges"
:key="change.path"
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_author_time.vue b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_author_time.vue
index 6b3007fce51..c762922d890 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_author_time.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_author_time.vue
@@ -1,5 +1,5 @@
<script>
-import tooltip from '~/vue_shared/directives/tooltip';
+import { GlTooltipDirective } from '@gitlab/ui';
import MrWidgetAuthor from './mr_widget_author.vue';
export default {
@@ -8,7 +8,7 @@ export default {
MrWidgetAuthor,
},
directives: {
- tooltip,
+ GlTooltip: GlTooltipDirective,
},
props: {
actionText: {
@@ -34,6 +34,7 @@ export default {
<h4 class="js-mr-widget-author">
{{ actionText }}
<mr-widget-author :author="author" />
- <time v-tooltip :title="dateTitle" data-container="body"> {{ dateReadable }} </time>
+ <span class="sr-only">{{ dateReadable }} ({{ dateTitle }})</span>
+ <time v-gl-tooltip.hover aria-hidden :title="dateTitle"> {{ dateReadable }} </time>
</h4>
</template>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_header.vue b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_header.vue
index 814d4e8341e..eb8989adb2a 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_header.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_header.vue
@@ -111,9 +111,10 @@ export default {
v-html="mr.sourceBranchLink"
/><clipboard-button
ref="copyBranchNameButton"
+ data-testid="mr-widget-copy-clipboard"
:text="branchNameClipboardData"
:title="__('Copy branch name')"
- css-class="btn-default btn-transparent btn-clipboard"
+ category="tertiary"
/>
{{ s__('mrWidget|into') }}
<tooltip-on-truncate
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/source_branch_removal_status.vue b/app/assets/javascripts/vue_merge_request_widget/components/source_branch_removal_status.vue
index 859f2c57598..c917b69953f 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/source_branch_removal_status.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/source_branch_removal_status.vue
@@ -1,6 +1,5 @@
<script>
-import { GlIcon, GlSprintf } from '@gitlab/ui';
-import tooltip from '../../vue_shared/directives/tooltip';
+import { GlIcon, GlSprintf, GlTooltipDirective } from '@gitlab/ui';
import { __ } from '../../locale';
export default {
@@ -13,7 +12,7 @@ export default {
GlSprintf,
},
directives: {
- tooltip,
+ GlTooltip: GlTooltipDirective,
},
};
</script>
@@ -28,7 +27,7 @@ export default {
</gl-sprintf>
</span>
<gl-icon
- v-tooltip
+ v-gl-tooltip.hover
:title="$options.i18n.tooltipTitle"
:aria-label="$options.i18n.tooltipTitle"
name="question-o"
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_archived.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_archived.vue
index 7ddcdd49df5..29c26f4fb3e 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_archived.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_archived.vue
@@ -1,9 +1,11 @@
<script>
+import { GlButton } from '@gitlab/ui';
import statusIcon from '../mr_widget_status_icon.vue';
export default {
name: 'MRWidgetArchived',
components: {
+ GlButton,
statusIcon,
},
};
@@ -12,9 +14,9 @@ export default {
<div class="mr-widget-body media">
<div class="space-children">
<status-icon status="warning" />
- <button type="button" class="btn btn-success btn-sm" disabled="true">
+ <gl-button category="secondary" variant="success" :disabled="true">
{{ s__('mrWidget|Merge') }}
- </button>
+ </gl-button>
</div>
<div class="media-body">
<span class="bold">
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 83e7d6db9fa..30da9947859 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,5 +1,5 @@
<script>
-import { GlLoadingIcon } from '@gitlab/ui';
+import { GlLoadingIcon, GlButton } from '@gitlab/ui';
import eventHub from '../../event_hub';
import statusIcon from '../mr_widget_status_icon.vue';
@@ -8,6 +8,7 @@ export default {
components: {
statusIcon,
GlLoadingIcon,
+ GlButton,
},
props: {
mr: {
@@ -33,20 +34,21 @@ export default {
<template>
<div class="mr-widget-body media">
<status-icon status="warning" />
- <div class="media-body space-children">
+ <div class="media-body space-children gl-display-flex gl-flex-wrap gl-align-items-center">
<span class="bold">
<template v-if="mr.mergeError">{{ mr.mergeError }}</template>
{{ s__('mrWidget|This merge request failed to be merged automatically') }}
</span>
- <button
+ <gl-button
:disabled="isRefreshing"
- type="button"
- class="btn btn-sm btn-default"
+ category="secondary"
+ variant="default"
+ size="small"
@click="refreshWidget"
>
<gl-loading-icon v-if="isRefreshing" :inline="true" />
{{ s__('mrWidget|Refresh') }}
- </button>
+ </gl-button>
</div>
</div>
</template>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merged.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merged.vue
index 58839251edc..17cd740ddd9 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merged.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merged.vue
@@ -1,8 +1,7 @@
<script>
/* eslint-disable @gitlab/vue-require-i18n-strings */
-import { GlLoadingIcon, GlButton } from '@gitlab/ui';
+import { GlLoadingIcon, GlButton, GlTooltipDirective } from '@gitlab/ui';
import { deprecatedCreateFlash as Flash } from '~/flash';
-import tooltip from '~/vue_shared/directives/tooltip';
import { s__, __ } from '~/locale';
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
import MrWidgetAuthorTime from '../mr_widget_author_time.vue';
@@ -12,7 +11,7 @@ import eventHub from '../../event_hub';
export default {
name: 'MRWidgetMerged',
directives: {
- tooltip,
+ GlTooltip: GlTooltipDirective,
},
components: {
MrWidgetAuthorTime,
@@ -115,7 +114,7 @@ export default {
/>
<gl-button
v-if="mr.canRevertInCurrentMR"
- v-tooltip
+ v-gl-tooltip.hover
:title="revertTitle"
size="small"
category="secondary"
@@ -128,7 +127,7 @@ export default {
</gl-button>
<gl-button
v-else-if="mr.revertInForkPath"
- v-tooltip
+ v-gl-tooltip.hover
:href="mr.revertInForkPath"
:title="revertTitle"
size="small"
@@ -140,7 +139,7 @@ export default {
</gl-button>
<gl-button
v-if="mr.canCherryPickInCurrentMR"
- v-tooltip
+ v-gl-tooltip.hover
:title="cherryPickTitle"
size="small"
href="#modal-cherry-pick-commit"
@@ -151,7 +150,7 @@ export default {
</gl-button>
<gl-button
v-else-if="mr.cherryPickInForkPath"
- v-tooltip
+ v-gl-tooltip.hover
:href="mr.cherryPickInForkPath"
:title="cherryPickTitle"
size="small"
@@ -177,7 +176,9 @@ export default {
<clipboard-button
:title="__('Copy commit SHA')"
:text="mr.mergeCommitSha"
- css-class="btn-default btn-transparent btn-clipboard js-mr-merged-copy-sha"
+ css-class="js-mr-merged-copy-sha"
+ category="tertiary"
+ size="small"
/>
</template>
</p>
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 83783528cc1..6489569cf68 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,13 +1,12 @@
<script>
-import { GlIcon } from '@gitlab/ui';
+import { GlIcon, GlTooltipDirective } from '@gitlab/ui';
import { sprintf, s__ } from '~/locale';
-import tooltip from '~/vue_shared/directives/tooltip';
import statusIcon from '../mr_widget_status_icon.vue';
export default {
name: 'MRWidgetMissingBranch',
directives: {
- tooltip,
+ GlTooltip: GlTooltipDirective,
},
components: {
GlIcon,
@@ -52,7 +51,7 @@ export default {
<span class="bold js-branch-text">
<span class="capitalize"> {{ missingBranchName }} </span>
{{ s__('mrWidget|branch does not exist.') }} {{ missingBranchNameMessage }}
- <gl-icon v-tooltip :title="message" :aria-label="message" name="question-o" />
+ <gl-icon v-gl-tooltip :title="message" :aria-label="message" name="question-o" />
</span>
</div>
</div>
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 ec0934c5b4b..14c2e9fa828 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_rebase.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_rebase.vue
@@ -1,6 +1,6 @@
<script>
/* eslint-disable vue/no-v-html */
-import { GlLoadingIcon } from '@gitlab/ui';
+import { GlButton } from '@gitlab/ui';
import { escape } from 'lodash';
import simplePoll from '../../../lib/utils/simple_poll';
import eventHub from '../../event_hub';
@@ -12,7 +12,7 @@ export default {
name: 'MRWidgetRebase',
components: {
statusIcon,
- GlLoadingIcon,
+ GlButton,
},
props: {
mr: {
@@ -109,29 +109,29 @@ export default {
<div class="rebase-state-find-class-convention media media-body space-children">
<template v-if="mr.rebaseInProgress || isMakingRequest">
- <span class="bold">{{ __('Rebase in progress') }}</span>
+ <span class="bold" data-testid="rebase-message">{{ __('Rebase in progress') }}</span>
</template>
<template v-if="!mr.rebaseInProgress && !mr.canPushToSourceBranch">
- <span class="bold" v-html="fastForwardMergeText"></span>
+ <span class="bold" data-testid="rebase-message" v-html="fastForwardMergeText"></span>
</template>
<template v-if="!mr.rebaseInProgress && mr.canPushToSourceBranch && !isMakingRequest">
<div
class="accept-merge-holder clearfix js-toggle-container accept-action media space-children"
>
- <button
- :disabled="isMakingRequest"
- type="button"
- class="btn btn-sm btn-reopen btn-success qa-mr-rebase-button"
+ <gl-button
+ :loading="isMakingRequest"
+ variant="success"
+ class="qa-mr-rebase-button"
@click="rebase"
>
- <gl-loading-icon v-if="isMakingRequest" />{{ __('Rebase') }}
- </button>
- <span v-if="!rebasingError" class="bold">{{
+ {{ __('Rebase') }}
+ </gl-button>
+ <span v-if="!rebasingError" class="bold" data-testid="rebase-message">{{
__(
'Fast-forward merge is not possible. Rebase the source branch onto the target branch.',
)
}}</span>
- <span v-else class="bold danger">{{ rebasingError }}</span>
+ <span v-else class="bold danger" data-testid="rebase-message">{{ rebasingError }}</span>
</div>
</template>
</div>
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 240bab58297..835f7b9e9a9 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
@@ -1,12 +1,9 @@
<script>
-/* eslint-disable vue/no-v-html */
import { isEmpty } from 'lodash';
import { GlIcon, GlButton, GlSprintf, GlLink } from '@gitlab/ui';
-import successSvg from 'icons/_icon_status_success.svg';
-import warningSvg from 'icons/_icon_status_warning.svg';
import readyToMergeMixin from 'ee_else_ce/vue_merge_request_widget/mixins/ready_to_merge';
import simplePoll from '~/lib/utils/simple_poll';
-import { __, sprintf } from '~/locale';
+import { __ } from '~/locale';
import MergeRequest from '../../../merge_request';
import { refreshUserMergeRequestCounts } from '~/commons/nav/user_merge_requests';
import { deprecatedCreateFlash as Flash } from '../../../flash';
@@ -59,8 +56,6 @@ export default {
commitMessage: this.mr.commitMessage,
squashBeforeMerge: this.mr.squashIsSelected,
isSquashReadOnly: this.mr.squashIsReadonly,
- successSvg,
- warningSvg,
squashCommitMessage: this.mr.squashCommitMessage,
};
},
@@ -147,16 +142,7 @@ export default {
return !this.mr.ffOnlyEnabled;
},
shaMismatchLink() {
- const href = this.mr.mergeRequestDiffsPath;
-
- return sprintf(
- __('New changes were added. %{linkStart}Reload the page to review them%{linkEnd}'),
- {
- linkStart: `<a href="${href}">`,
- linkEnd: '</a>',
- },
- false,
- );
+ return this.mr.mergeRequestDiffsPath;
},
},
methods: {
@@ -331,7 +317,7 @@ export default {
@click.prevent="handleMergeButtonClick(true)"
>
<span class="media">
- <span class="merge-opt-icon" aria-hidden="true" v-html="successSvg"></span>
+ <gl-icon name="status_success" class="merge-opt-icon" aria-hidden="true" />
<span class="media-body merge-opt-title">{{ autoMergeText }}</span>
</span>
</a>
@@ -349,7 +335,7 @@ export default {
@click.prevent="handleMergeImmediatelyButtonClick"
>
<span class="media">
- <span class="merge-opt-icon" aria-hidden="true" v-html="warningSvg"></span>
+ <gl-icon name="status_warning" class="merge-opt-icon" aria-hidden="true" />
<span class="media-body merge-opt-title">{{ __('Merge immediately') }}</span>
</span>
</a>
@@ -400,7 +386,17 @@ export default {
</div>
<div v-if="mr.isSHAMismatch" class="d-flex align-items-center mt-2 js-sha-mismatch">
<gl-icon name="warning-solid" class="text-warning mr-1" />
- <span class="text-warning" v-html="shaMismatchLink"></span>
+ <span class="text-warning">
+ <gl-sprintf
+ :message="
+ __('New changes were added. %{linkStart}Reload the page to review them%{linkEnd}')
+ "
+ >
+ <template #link="{ content }">
+ <gl-link :href="mr.mergeRequestDiffsPath">{{ content }}</gl-link>
+ </template>
+ </gl-sprintf>
+ </span>
</div>
</div>
</div>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/squash_before_merge.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/squash_before_merge.vue
index 6608381f348..ff0d065c71d 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/squash_before_merge.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/squash_before_merge.vue
@@ -1,14 +1,16 @@
<script>
-import { GlIcon } from '@gitlab/ui';
-import tooltip from '~/vue_shared/directives/tooltip';
-import { __ } from '~/locale';
+import { GlIcon, GlTooltipDirective } from '@gitlab/ui';
+import { SQUASH_BEFORE_MERGE } from '../../i18n';
export default {
components: {
GlIcon,
},
directives: {
- tooltip,
+ GlTooltip: GlTooltipDirective,
+ },
+ i18n: {
+ ...SQUASH_BEFORE_MERGE,
},
props: {
value: {
@@ -28,7 +30,10 @@ export default {
},
computed: {
tooltipTitle() {
- return this.isDisabled ? __('Required in this project.') : false;
+ return this.isDisabled ? this.$options.i18n.tooltipTitle : null;
+ },
+ tooltipFocusable() {
+ return this.isDisabled ? '0' : null;
},
},
};
@@ -37,10 +42,11 @@ export default {
<template>
<div class="inline">
<label
- v-tooltip
+ v-gl-tooltip
:class="{ 'gl-text-gray-400': isDisabled }"
+ :tabindex="tooltipFocusable"
data-testid="squashLabel"
- :data-title="tooltipTitle"
+ :title="tooltipTitle"
>
<input
:checked="value"
@@ -50,19 +56,20 @@ export default {
class="qa-squash-checkbox js-squash-checkbox"
@change="$emit('input', $event.target.checked)"
/>
- {{ __('Squash commits') }}
+ {{ $options.i18n.checkboxLabel }}
</label>
<a
v-if="helpPath"
- v-tooltip
+ v-gl-tooltip
:href="helpPath"
- data-title="About this feature"
- data-placement="bottom"
+ :title="$options.i18n.helpLabel"
target="_blank"
rel="noopener noreferrer nofollow"
- data-container="body"
>
<gl-icon name="question" />
+ <span class="sr-only">
+ {{ $options.i18n.helpLabel }}
+ </span>
</a>
</div>
</template>
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 61cc950f058..eba3d50fdc9 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
@@ -3,13 +3,13 @@ import $ from 'jquery';
import { GlButton } from '@gitlab/ui';
import { __ } from '~/locale';
import { deprecatedCreateFlash as createFlash } from '~/flash';
+import MergeRequest from '~/merge_request';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import mergeRequestQueryVariablesMixin from '../../mixins/merge_request_query_variables';
import getStateQuery from '../../queries/get_state.query.graphql';
import workInProgressQuery from '../../queries/states/work_in_progress.query.graphql';
import removeWipMutation from '../../queries/toggle_wip.mutation.graphql';
import StatusIcon from '../mr_widget_status_icon.vue';
-import tooltip from '../../../vue_shared/directives/tooltip';
import eventHub from '../../event_hub';
export default {
@@ -18,9 +18,6 @@ export default {
StatusIcon,
GlButton,
},
- directives: {
- tooltip,
- },
mixins: [glFeatureFlagMixin(), mergeRequestQueryVariablesMixin],
apollo: {
userPermissions: {
@@ -128,8 +125,7 @@ export default {
.then(res => res.data)
.then(data => {
eventHub.$emit('UpdateWidgetData', data);
- createFlash(__('The merge request can now be merged.'), 'notice');
- $('.merge-request .detail-page-description .title').text(this.mr.title);
+ MergeRequest.toggleDraftStatus(this.mr.title, true);
})
.catch(() => {
this.isMakingRequest = false;
diff --git a/app/assets/javascripts/vue_merge_request_widget/i18n.js b/app/assets/javascripts/vue_merge_request_widget/i18n.js
new file mode 100644
index 00000000000..e8e522a01e9
--- /dev/null
+++ b/app/assets/javascripts/vue_merge_request_widget/i18n.js
@@ -0,0 +1,7 @@
+import { __ } from '~/locale';
+
+export const SQUASH_BEFORE_MERGE = {
+ tooltipTitle: __('Required in this project.'),
+ checkboxLabel: __('Squash commits'),
+ helpLabel: __('What is squashing?'),
+};
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 43ce748b41d..46749fc5e87 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
@@ -4,6 +4,7 @@ import MRWidgetStore from 'ee_else_ce/vue_merge_request_widget/stores/mr_widget_
import MRWidgetService from 'ee_else_ce/vue_merge_request_widget/services/mr_widget_service';
import MrWidgetApprovals from 'ee_else_ce/vue_merge_request_widget/components/approvals/approvals.vue';
import stateMaps from 'ee_else_ce/vue_merge_request_widget/stores/state_maps';
+import { GlSafeHtmlDirective } from '@gitlab/ui';
import { sprintf, s__, __ } from '~/locale';
import Project from '~/pages/projects/project';
import SmartInterval from '~/smart_interval';
@@ -45,12 +46,16 @@ import GroupedTestReportsApp from '../reports/components/grouped_test_reports_ap
import { setFaviconOverlay } from '../lib/utils/common_utils';
import GroupedAccessibilityReportsApp from '../reports/accessibility_report/grouped_accessibility_reports_app.vue';
import getStateQuery from './queries/get_state.query.graphql';
+import { isExperimentEnabled } from '~/lib/utils/experimentation';
export default {
el: '#js-vue-mr-widget',
// False positive i18n lint: https://gitlab.com/gitlab-org/frontend/eslint-plugin-i18n/issues/25
// eslint-disable-next-line @gitlab/require-i18n-strings
name: 'MRWidget',
+ directives: {
+ SafeHtml: GlSafeHtmlDirective,
+ },
components: {
Loading,
'mr-widget-header': WidgetHeader,
@@ -85,6 +90,7 @@ export default {
TerraformPlan,
GroupedAccessibilityReportsApp,
MrWidgetApprovals,
+ SecurityReportsApp: () => import('~/vue_shared/security_reports/security_reports_app.vue'),
},
apollo: {
state: {
@@ -148,7 +154,7 @@ export default {
},
shouldSuggestPipelines() {
return (
- gon.features?.suggestPipeline &&
+ isExperimentEnabled('suggestPipeline') &&
!this.mr.hasCI &&
this.mr.mergeRequestAddCiConfigPath &&
!this.mr.isDismissedSuggestPipeline
@@ -178,6 +184,9 @@ export default {
this.mr.mergePipelinesEnabled && this.mr.sourceProjectId !== this.mr.targetProjectId,
);
},
+ shouldRenderSecurityReport() {
+ return Boolean(window.gon?.features?.coreSecurityMrWidget && this.mr.pipeline.id);
+ },
mergeError() {
let { mergeError } = this.mr;
@@ -455,6 +464,13 @@ export default {
:codequality-help-path="mr.codequalityHelpPath"
/>
+ <security-reports-app
+ v-if="shouldRenderSecurityReport"
+ :pipeline-id="mr.pipeline.id"
+ :project-id="mr.targetProjectId"
+ :security-reports-docs-path="mr.securityReportsDocsPath"
+ />
+
<grouped-test-reports-app
v-if="mr.testResultsPath"
class="js-reports-container"
@@ -498,7 +514,7 @@ export default {
</mr-widget-alert-message>
<mr-widget-alert-message v-if="mr.mergeError" type="danger">
- {{ mergeError }}
+ <span v-safe-html="mergeError"></span>
</mr-widget-alert-message>
<source-branch-removal-status v-if="shouldRenderSourceBranchRemovalStatus" />
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 846b1c453a1..8b235b20ad4 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
@@ -232,6 +232,7 @@ export default class MergeRequestStore {
this.userCalloutsPath = data.user_callouts_path;
this.suggestPipelineFeatureId = data.suggest_pipeline_feature_id;
this.isDismissedSuggestPipeline = data.is_dismissed_suggest_pipeline;
+ this.securityReportsDocsPath = data.security_reports_docs_path;
// codeclimate
const blobPath = data.blob_path || {};
diff --git a/app/assets/javascripts/vue_shared/components/actions_button.vue b/app/assets/javascripts/vue_shared/components/actions_button.vue
index f333ab49ead..9b21de19185 100644
--- a/app/assets/javascripts/vue_shared/components/actions_button.vue
+++ b/app/assets/javascripts/vue_shared/components/actions_button.vue
@@ -3,7 +3,7 @@ import {
GlDropdown,
GlDropdownItem,
GlDropdownDivider,
- GlLink,
+ GlButton,
GlTooltipDirective,
} from '@gitlab/ui';
@@ -12,7 +12,7 @@ export default {
GlDropdown,
GlDropdownItem,
GlDropdownDivider,
- GlLink,
+ GlButton,
},
directives: {
GlTooltip: GlTooltipDirective,
@@ -27,6 +27,16 @@ export default {
required: false,
default: '',
},
+ category: {
+ type: String,
+ required: false,
+ default: 'secondary',
+ },
+ variant: {
+ type: String,
+ required: false,
+ default: 'default',
+ },
},
computed: {
hasMultipleActions() {
@@ -54,6 +64,8 @@ export default {
class="gl-button-deprecated-adapter"
:text="selectedAction.text"
:split-href="selectedAction.href"
+ :variant="variant"
+ :category="category"
split
@click="handleClick(selectedAction, $event)"
>
@@ -77,14 +89,15 @@ export default {
<gl-dropdown-divider v-if="index != actions.length - 1" :key="action.key + '_divider'" />
</template>
</gl-dropdown>
- <gl-link
+ <gl-button
v-else-if="selectedAction"
v-gl-tooltip="selectedAction.tooltip"
v-bind="selectedAction.attrs"
- class="btn"
+ :variant="variant"
+ :category="category"
:href="selectedAction.href"
@click="handleClick(selectedAction, $event)"
>
{{ selectedAction.text }}
- </gl-link>
+ </gl-button>
</template>
diff --git a/app/assets/javascripts/vue_shared/components/alert_details_table.vue b/app/assets/javascripts/vue_shared/components/alert_details_table.vue
index c94e784c01e..34f6d384f7b 100644
--- a/app/assets/javascripts/vue_shared/components/alert_details_table.vue
+++ b/app/assets/javascripts/vue_shared/components/alert_details_table.vue
@@ -1,20 +1,38 @@
<script>
import { GlLoadingIcon, GlTable } from '@gitlab/ui';
+import { reduce } from 'lodash';
import { s__ } from '~/locale';
import {
capitalizeFirstCharacter,
convertToSentenceCase,
splitCamelCase,
} from '~/lib/utils/text_utility';
+import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
const thClass = 'gl-bg-transparent! gl-border-1! gl-border-b-solid! gl-border-gray-200!';
const tdClass = 'gl-border-gray-100! gl-p-5!';
+const allowedFields = [
+ 'iid',
+ 'title',
+ 'severity',
+ 'status',
+ 'startedAt',
+ 'eventCount',
+ 'monitoringTool',
+ 'service',
+ 'description',
+ 'endedAt',
+ 'details',
+ 'hosts',
+];
+
export default {
components: {
GlLoadingIcon,
GlTable,
},
+ mixins: [glFeatureFlagsMixin()],
props: {
alert: {
type: Object,
@@ -42,14 +60,37 @@ export default {
},
],
computed: {
+ flaggedAllowedFields() {
+ return this.shouldDisplayEnvironment ? [...allowedFields, 'environment'] : allowedFields;
+ },
items() {
if (!this.alert) {
return [];
}
- return Object.entries(this.alert).map(([fieldName, value]) => ({
- fieldName,
- value,
- }));
+ return reduce(
+ this.alert,
+ (allowedItems, fieldValue, fieldName) => {
+ if (this.isAllowed(fieldName)) {
+ let value;
+ if (fieldName === 'environment') {
+ value = fieldValue?.name;
+ } else {
+ value = fieldValue;
+ }
+ return [...allowedItems, { fieldName, value }];
+ }
+ return allowedItems;
+ },
+ [],
+ );
+ },
+ shouldDisplayEnvironment() {
+ return this.glFeatures.exposeEnvironmentPathInAlertDetails;
+ },
+ },
+ methods: {
+ isAllowed(fieldName) {
+ return this.flaggedAllowedFields.includes(fieldName);
},
},
};
diff --git a/app/assets/javascripts/vue_shared/components/awards_list.vue b/app/assets/javascripts/vue_shared/components/awards_list.vue
index e1f54b62223..2e4b9b9a135 100644
--- a/app/assets/javascripts/vue_shared/components/awards_list.vue
+++ b/app/assets/javascripts/vue_shared/components/awards_list.vue
@@ -1,7 +1,7 @@
<script>
/* eslint-disable vue/no-v-html */
import { groupBy } from 'lodash';
-import { GlIcon } from '@gitlab/ui';
+import { GlIcon, GlLoadingIcon } from '@gitlab/ui';
import tooltip from '~/vue_shared/directives/tooltip';
import { glEmojiTag } from '../../emoji';
import { __, sprintf } from '~/locale';
@@ -12,6 +12,7 @@ const NO_USER_ID = -1;
export default {
components: {
GlIcon,
+ GlLoadingIcon,
},
directives: {
tooltip,
@@ -184,10 +185,7 @@ export default {
<span class="award-control-icon award-control-icon-super-positive">
<gl-icon aria-hidden="true" name="smiley" />
</span>
- <i
- aria-hidden="true"
- class="fa fa-spinner fa-spin award-control-icon award-control-icon-loading"
- ></i>
+ <gl-loading-icon size="md" color="dark" class="award-control-icon-loading" />
</button>
</div>
</div>
diff --git a/app/assets/javascripts/vue_shared/components/blob_viewers/mixins.js b/app/assets/javascripts/vue_shared/components/blob_viewers/mixins.js
index 9e2b3097499..7a76888c916 100644
--- a/app/assets/javascripts/vue_shared/components/blob_viewers/mixins.js
+++ b/app/assets/javascripts/vue_shared/components/blob_viewers/mixins.js
@@ -1,9 +1,5 @@
-import {
- SNIPPET_MARK_VIEW_APP_START,
- SNIPPET_MARK_BLOBS_CONTENT,
- SNIPPET_MEASURE_BLOBS_CONTENT,
- SNIPPET_MEASURE_BLOBS_CONTENT_WITHIN_APP,
-} from '~/performance_constants';
+import { SNIPPET_MEASURE_BLOBS_CONTENT } from '~/performance_constants';
+import eventHub from '~/blob/components/eventhub';
export default {
props: {
@@ -17,12 +13,6 @@ export default {
},
},
mounted() {
- window.requestAnimationFrame(() => {
- if (!performance.getEntriesByName(SNIPPET_MARK_BLOBS_CONTENT).length) {
- performance.mark(SNIPPET_MARK_BLOBS_CONTENT);
- performance.measure(SNIPPET_MEASURE_BLOBS_CONTENT);
- performance.measure(SNIPPET_MEASURE_BLOBS_CONTENT_WITHIN_APP, SNIPPET_MARK_VIEW_APP_START);
- }
- });
+ eventHub.$emit(SNIPPET_MEASURE_BLOBS_CONTENT);
},
};
diff --git a/app/assets/javascripts/vue_shared/components/ci_badge_link.vue b/app/assets/javascripts/vue_shared/components/ci_badge_link.vue
index d7af3b3298e..1b7e51b7d02 100644
--- a/app/assets/javascripts/vue_shared/components/ci_badge_link.vue
+++ b/app/assets/javascripts/vue_shared/components/ci_badge_link.vue
@@ -7,7 +7,7 @@ import CiIcon from './ci_icon.vue';
*
* Receives status object containing:
* status: {
- * details_path: "/gitlab-org/gitlab-foss/pipelines/8150156" // url
+ * details_path or detailsPath: "/gitlab-org/gitlab-foss/pipelines/8150156" // url
* group:"running" // used for CSS class
* icon: "icon_status_running" // used to render the icon
* label:"running" // used for potential tooltip
@@ -46,6 +46,13 @@ export default {
},
},
computed: {
+ title() {
+ return !this.showText ? this.status?.text : '';
+ },
+ detailsPath() {
+ // For now, this can either come from graphQL with camelCase or REST API in snake_case
+ return this.status.detailsPath || this.status.details_path;
+ },
cssClass() {
const className = this.status.group;
return className ? `ci-status ci-${className} qa-status-badge` : 'ci-status qa-status-badge';
@@ -54,12 +61,7 @@ export default {
};
</script>
<template>
- <a
- v-gl-tooltip
- :href="status.details_path"
- :class="cssClass"
- :title="!showText ? status.text : ''"
- >
+ <a v-gl-tooltip :href="detailsPath" :class="cssClass" :title="title">
<ci-icon :status="status" :css-classes="iconClasses" />
<template v-if="showText">
diff --git a/app/assets/javascripts/vue_shared/components/clipboard_button.vue b/app/assets/javascripts/vue_shared/components/clipboard_button.vue
index 0234b6bf848..960551fae91 100644
--- a/app/assets/javascripts/vue_shared/components/clipboard_button.vue
+++ b/app/assets/javascripts/vue_shared/components/clipboard_button.vue
@@ -12,7 +12,7 @@
* css-class="btn-transparent"
* />
*/
-import { GlDeprecatedButton, GlTooltipDirective, GlIcon } from '@gitlab/ui';
+import { GlButton, GlTooltipDirective } from '@gitlab/ui';
export default {
name: 'ClipboardButton',
@@ -20,8 +20,7 @@ export default {
GlTooltip: GlTooltipDirective,
},
components: {
- GlDeprecatedButton,
- GlIcon,
+ GlButton,
},
props: {
text: {
@@ -50,7 +49,17 @@ export default {
cssClass: {
type: String,
required: false,
- default: 'btn-default',
+ default: null,
+ },
+ category: {
+ type: String,
+ required: false,
+ default: 'secondary',
+ },
+ size: {
+ type: String,
+ required: false,
+ default: 'medium',
},
},
computed: {
@@ -65,13 +74,15 @@ export default {
</script>
<template>
- <gl-deprecated-button
+ <gl-button
v-gl-tooltip="{ placement: tooltipPlacement, container: tooltipContainer }"
v-gl-tooltip.hover.blur
:class="cssClass"
:title="title"
:data-clipboard-text="clipboardText"
- >
- <gl-icon name="copy-to-clipboard" />
- </gl-deprecated-button>
+ :category="category"
+ :size="size"
+ icon="copy-to-clipboard"
+ :aria-label="__('Copy this value')"
+ />
</template>
diff --git a/app/assets/javascripts/vue_shared/components/commit.vue b/app/assets/javascripts/vue_shared/components/commit.vue
index c1c8fb3a6e2..e01a651806d 100644
--- a/app/assets/javascripts/vue_shared/components/commit.vue
+++ b/app/assets/javascripts/vue_shared/components/commit.vue
@@ -139,7 +139,7 @@ export default {
<template>
<div class="branch-commit cgray">
<template v-if="shouldShowRefInfo">
- <div class="icon-container">
+ <div class="icon-container gl-display-inline-block">
<gl-icon v-if="tag" name="tag" />
<gl-icon v-else-if="mergeRequestRef" name="git-merge" />
<gl-icon v-else name="branch" />
diff --git a/app/assets/javascripts/vue_shared/components/confirm_modal.vue b/app/assets/javascripts/vue_shared/components/confirm_modal.vue
index e7f6cc1abc0..a42a606d446 100644
--- a/app/assets/javascripts/vue_shared/components/confirm_modal.vue
+++ b/app/assets/javascripts/vue_shared/components/confirm_modal.vue
@@ -12,6 +12,11 @@ export default {
type: String,
required: true,
},
+ handleSubmit: {
+ type: Function,
+ required: false,
+ default: null,
+ },
},
data() {
return {
@@ -41,7 +46,11 @@ export default {
this.$refs.modal.hide();
},
submitModal() {
- this.$refs.form.submit();
+ if (this.handleSubmit) {
+ this.handleSubmit(this.path);
+ } else {
+ this.$refs.form.submit();
+ }
},
},
csrf,
diff --git a/app/assets/javascripts/vue_shared/components/content_viewer/content_viewer.vue b/app/assets/javascripts/vue_shared/components/content_viewer/content_viewer.vue
index fe488ab6cfa..5ac30424f98 100644
--- a/app/assets/javascripts/vue_shared/components/content_viewer/content_viewer.vue
+++ b/app/assets/javascripts/vue_shared/components/content_viewer/content_viewer.vue
@@ -4,6 +4,11 @@ import ImageViewer from './viewers/image_viewer.vue';
import DownloadViewer from './viewers/download_viewer.vue';
export default {
+ components: {
+ MarkdownViewer,
+ ImageViewer,
+ DownloadViewer,
+ },
props: {
content: {
type: String,
@@ -45,35 +50,25 @@ export default {
default: () => ({}),
},
},
- computed: {
- viewer() {
- if (!this.path) return null;
- if (!this.type) return DownloadViewer;
-
- switch (this.type) {
- case 'markdown':
- return MarkdownViewer;
- case 'image':
- return ImageViewer;
- default:
- return DownloadViewer;
- }
- },
- },
};
</script>
<template>
<div class="preview-container">
- <component
- :is="viewer"
- :path="path"
+ <image-viewer v-if="type === 'image'" :path="path" :file-size="fileSize" />
+ <markdown-viewer
+ v-if="type === 'markdown'"
+ :content="content"
+ :commit-sha="commitSha"
:file-path="filePath"
- :file-size="fileSize"
:project-path="projectPath"
- :content="content"
:images="images"
- :commit-sha="commitSha"
+ />
+ <download-viewer
+ v-if="!type && path"
+ :path="path"
+ :file-path="filePath"
+ :file-size="fileSize"
/>
</div>
</template>
diff --git a/app/assets/javascripts/vue_shared/components/content_viewer/viewers/download_viewer.vue b/app/assets/javascripts/vue_shared/components/content_viewer/viewers/download_viewer.vue
index f9d3d76e7f5..8d55701f499 100644
--- a/app/assets/javascripts/vue_shared/components/content_viewer/viewers/download_viewer.vue
+++ b/app/assets/javascripts/vue_shared/components/content_viewer/viewers/download_viewer.vue
@@ -1,10 +1,9 @@
<script>
-import { GlLink, GlIcon } from '@gitlab/ui';
+import { GlIcon } from '@gitlab/ui';
import { numberToHumanSize } from '../../../../lib/utils/number_utils';
export default {
components: {
- GlLink,
GlIcon,
},
props: {
@@ -44,16 +43,10 @@ export default {
({{ fileSizeReadable }})
</template>
</p>
- <gl-link
- :href="path"
- class="btn btn-default"
- rel="nofollow"
- :download="fileName"
- target="_blank"
- >
+ <a :href="path" class="btn btn-default" rel="nofollow" :download="fileName" target="_blank">
<gl-icon :size="16" name="download" class="float-left gl-mr-3" />
{{ __('Download') }}
- </gl-link>
+ </a>
</div>
</div>
</template>
diff --git a/app/assets/javascripts/vue_shared/components/deprecated_modal_2.vue b/app/assets/javascripts/vue_shared/components/deprecated_modal_2.vue
index 543547b37fe..c4bce860ae4 100644
--- a/app/assets/javascripts/vue_shared/components/deprecated_modal_2.vue
+++ b/app/assets/javascripts/vue_shared/components/deprecated_modal_2.vue
@@ -1,5 +1,6 @@
<script>
import $ from 'jquery';
+import { GlButton } from '@gitlab/ui';
const buttonVariants = ['danger', 'primary', 'success', 'warning'];
const sizeVariants = ['sm', 'md', 'lg', 'xl'];
@@ -7,6 +8,9 @@ const sizeVariants = ['sm', 'md', 'lg', 'xl'];
export default {
name: 'DeprecatedModal2', // use GlModal instead
+ components: {
+ GlButton,
+ },
props: {
id: {
type: String,
@@ -72,20 +76,21 @@ export default {
<div :id="id" class="modal fade" tabindex="-1" role="dialog">
<div :class="modalSizeClass" class="modal-dialog" role="document">
<div class="modal-content">
- <div class="modal-header">
+ <div class="modal-header gl-pr-4">
<slot name="header">
<h4 class="modal-title">
<slot name="title"> {{ headerTitleText }} </slot>
</h4>
- <button
+ <gl-button
:aria-label="s__('Modal|Close')"
- type="button"
- class="close js-modal-close-action"
+ variant="default"
+ category="tertiary"
+ size="small"
+ icon="close"
+ class="js-modal-close-action"
data-dismiss="modal"
@click="emitCancel($event)"
- >
- <span aria-hidden="true">&times;</span>
- </button>
+ />
</slot>
</div>
@@ -93,23 +98,21 @@ export default {
<div class="modal-footer">
<slot name="footer">
- <button
- type="button"
- class="btn js-modal-cancel-action qa-modal-cancel-button"
+ <gl-button
+ class="js-modal-cancel-action qa-modal-cancel-button"
data-dismiss="modal"
@click="emitCancel($event)"
>
{{ s__('Modal|Cancel') }}
- </button>
- <button
+ </gl-button>
+ <gl-button
:class="`btn-${footerPrimaryButtonVariant}`"
- type="button"
- class="btn js-modal-primary-action qa-modal-primary-button"
+ class="js-modal-primary-action qa-modal-primary-button"
data-dismiss="modal"
@click="emitSubmit($event)"
>
{{ footerPrimaryButtonText }}
- </button>
+ </gl-button>
</slot>
</div>
</div>
diff --git a/app/assets/javascripts/vue_shared/components/dismissible_feedback_alert.vue b/app/assets/javascripts/vue_shared/components/dismissible_feedback_alert.vue
index c7d7c3a1d24..2a28b13e7bf 100644
--- a/app/assets/javascripts/vue_shared/components/dismissible_feedback_alert.vue
+++ b/app/assets/javascripts/vue_shared/components/dismissible_feedback_alert.vue
@@ -22,7 +22,7 @@ export default {
},
data() {
return {
- isDismissed: 'false',
+ isDismissed: false,
};
},
computed: {
@@ -30,12 +30,12 @@ export default {
return `${slugifyWithUnderscore(this.featureName)}_feedback_dismissed`;
},
showAlert() {
- return this.isDismissed === 'false';
+ return !this.isDismissed;
},
},
methods: {
dismissFeedbackAlert() {
- this.isDismissed = 'true';
+ this.isDismissed = true;
},
},
};
@@ -43,16 +43,12 @@ export default {
<template>
<div v-show="showAlert">
- <local-storage-sync
- :value="isDismissed"
- :storage-key="storageKey"
- @input="dismissFeedbackAlert"
- />
+ <local-storage-sync v-model="isDismissed" :storage-key="storageKey" as-json />
<gl-alert v-if="showAlert" class="gl-mt-5" @dismiss="dismissFeedbackAlert">
<gl-sprintf
:message="
__(
- 'We’ve been making changes to %{featureName} and we’d love your feedback %{linkStart}in this issue%{linkEnd} to help us improve the experience.',
+ 'Please share your feedback about %{featureName} %{linkStart}in this issue%{linkEnd} to help us improve the experience.',
)
"
>
diff --git a/app/assets/javascripts/vue_shared/components/dropdown/dropdown_search_input.vue b/app/assets/javascripts/vue_shared/components/dropdown/dropdown_search_input.vue
index 7157337f8f3..48b94fdc181 100644
--- a/app/assets/javascripts/vue_shared/components/dropdown/dropdown_search_input.vue
+++ b/app/assets/javascripts/vue_shared/components/dropdown/dropdown_search_input.vue
@@ -1,7 +1,11 @@
<script>
+import { GlIcon } from '@gitlab/ui';
import { __ } from '~/locale';
export default {
+ components: {
+ GlIcon,
+ },
props: {
placeholderText: {
type: String,
@@ -40,6 +44,6 @@ export default {
type="search"
autocomplete="off"
/>
- <i class="fa fa-search dropdown-input-search" aria-hidden="true" data-hidden="true"> </i>
+ <gl-icon name="search" class="dropdown-input-search" aria-hidden="true" data-hidden="true" />
</div>
</template>
diff --git a/app/assets/javascripts/vue_shared/components/droplab_dropdown_button.vue b/app/assets/javascripts/vue_shared/components/droplab_dropdown_button.vue
deleted file mode 100644
index 4d85726065b..00000000000
--- a/app/assets/javascripts/vue_shared/components/droplab_dropdown_button.vue
+++ /dev/null
@@ -1,92 +0,0 @@
-<script>
-import { GlDeprecatedButton, GlIcon } from '@gitlab/ui';
-
-export default {
- components: {
- GlIcon,
- GlDeprecatedButton,
- },
- props: {
- size: {
- type: String,
- required: false,
- default: '',
- },
- primaryButtonClass: {
- type: String,
- required: false,
- default: '',
- },
- dropdownClass: {
- type: String,
- required: false,
- default: '',
- },
- actions: {
- type: Array,
- required: true,
- },
- defaultAction: {
- type: Number,
- required: true,
- },
- },
- data() {
- return {
- selectedAction: this.defaultAction,
- };
- },
- computed: {
- selectedActionTitle() {
- return this.actions[this.selectedAction].title;
- },
- buttonSizeClass() {
- return `btn-${this.size}`;
- },
- },
- methods: {
- handlePrimaryActionClick() {
- this.$emit('onActionClick', this.actions[this.selectedAction]);
- },
- handleActionClick(selectedAction) {
- this.selectedAction = selectedAction;
- this.$emit('onActionSelect', selectedAction);
- },
- },
-};
-</script>
-
-<template>
- <div class="btn-group droplab-dropdown comment-type-dropdown">
- <gl-deprecated-button
- :class="primaryButtonClass"
- :size="size"
- @click.prevent="handlePrimaryActionClick"
- >
- {{ selectedActionTitle }}
- </gl-deprecated-button>
- <button
- :class="buttonSizeClass"
- type="button"
- class="btn dropdown-toggle pl-2 pr-2"
- data-display="static"
- data-toggle="dropdown"
- >
- <gl-icon name="chevron-down" :aria-label="__('toggle dropdown')" />
- </button>
- <ul :class="dropdownClass" class="dropdown-menu dropdown-open-top">
- <template v-for="(action, index) in actions">
- <li :key="index" :class="{ 'droplab-item-selected': selectedAction === index }">
- <gl-deprecated-button class="btn-transparent" @click.prevent="handleActionClick(index)">
- <i aria-hidden="true" class="fa fa-check icon"> </i>
- <div class="description">
- <strong>{{ action.title }}</strong>
- <p>{{ action.description }}</p>
- </div>
- </gl-deprecated-button>
- </li>
- <li v-if="index === 0" :key="`${index}-separator`" class="divider droplab-item-ignore"></li>
- </template>
- </ul>
- </div>
-</template>
diff --git a/app/assets/javascripts/vue_shared/components/editor_lite.vue b/app/assets/javascripts/vue_shared/components/editor_lite.vue
new file mode 100644
index 00000000000..cfe3ce0a11c
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/editor_lite.vue
@@ -0,0 +1,99 @@
+<script>
+import { debounce } from 'lodash';
+import Editor from '~/editor/editor_lite';
+import { CONTENT_UPDATE_DEBOUNCE } from '~/editor/constants';
+
+function initEditorLite({ el, ...args }) {
+ const editor = new Editor({
+ scrollbar: {
+ alwaysConsumeMouseWheel: false,
+ },
+ });
+
+ return editor.createInstance({
+ el,
+ ...args,
+ });
+}
+
+export default {
+ inheritAttrs: false,
+ 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: '',
+ },
+ extensions: {
+ type: [String, Array],
+ required: false,
+ default: () => null,
+ },
+ editorOptions: {
+ type: Object,
+ required: false,
+ default: () => ({}),
+ },
+ },
+ data() {
+ return {
+ loading: true,
+ editor: null,
+ };
+ },
+ watch: {
+ fileName(newVal) {
+ this.editor.updateModelLanguage(newVal);
+ },
+ value(newVal) {
+ if (this.editor.getValue() !== newVal) {
+ this.editor.setValue(newVal);
+ }
+ },
+ },
+ mounted() {
+ this.editor = initEditorLite({
+ el: this.$refs.editor,
+ blobPath: this.fileName,
+ blobContent: this.value,
+ blobGlobalId: this.fileGlobalId,
+ extensions: this.extensions,
+ ...this.editorOptions,
+ });
+
+ this.editor.onDidChangeModelContent(
+ debounce(this.onFileChange.bind(this), CONTENT_UPDATE_DEBOUNCE),
+ );
+ },
+ beforeDestroy() {
+ this.editor.dispose();
+ },
+ methods: {
+ onFileChange() {
+ this.$emit('input', this.editor.getValue());
+ },
+ },
+};
+</script>
+<template>
+ <div
+ :id="`editor-lite-${fileGlobalId}`"
+ ref="editor"
+ data-editor-loading
+ @editor-ready="$emit('editor-ready')"
+ >
+ <pre class="editor-loading-content">{{ value }}</pre>
+ </div>
+</template>
diff --git a/app/assets/javascripts/vue_shared/components/file_finder/index.vue b/app/assets/javascripts/vue_shared/components/file_finder/index.vue
index 012aca8105a..386df617d47 100644
--- a/app/assets/javascripts/vue_shared/components/file_finder/index.vue
+++ b/app/assets/javascripts/vue_shared/components/file_finder/index.vue
@@ -230,13 +230,12 @@ export default {
@keydown="onKeydown($event)"
@keyup="onKeyup($event)"
/>
- <i
- :class="{
- hidden: showClearInputButton,
- }"
+ <gl-icon
+ name="search"
+ class="dropdown-input-search"
+ :class="{ hidden: showClearInputButton }"
aria-hidden="true"
- class="fa fa-search dropdown-input-search"
- ></i>
+ />
<gl-icon
name="close"
class="dropdown-input-clear"
diff --git a/app/assets/javascripts/vue_shared/components/file_icon/file_icon_map.js b/app/assets/javascripts/vue_shared/components/file_icon/file_icon_map.js
index b70f093e930..91a0ac3aa92 100644
--- a/app/assets/javascripts/vue_shared/components/file_icon/file_icon_map.js
+++ b/app/assets/javascripts/vue_shared/components/file_icon/file_icon_map.js
@@ -9,6 +9,12 @@ const fileExtensionIcons = {
'md.rendered': 'markdown',
markdown: 'markdown',
'markdown.rendered': 'markdown',
+ mdown: 'markdown',
+ 'mdown.rendered': 'markdown',
+ mkd: 'markdown',
+ 'mkd.rendered': 'markdown',
+ mkdn: 'markdown',
+ 'mkdn.rendered': 'markdown',
rst: 'markdown',
blink: 'blink',
css: 'css',
diff --git a/app/assets/javascripts/vue_shared/components/filtered_search_bar/store/modules/filters/actions.js b/app/assets/javascripts/vue_shared/components/filtered_search_bar/store/modules/filters/actions.js
new file mode 100644
index 00000000000..443cb28cf10
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/filtered_search_bar/store/modules/filters/actions.js
@@ -0,0 +1,121 @@
+import { deprecatedCreateFlash as createFlash } from '~/flash';
+import axios from '~/lib/utils/axios_utils';
+import { __ } from '~/locale';
+import Api from '~/api';
+import * as types from './mutation_types';
+
+export const setEndpoints = ({ commit }, params) => {
+ const { milestonesEndpoint, labelsEndpoint, groupEndpoint, projectEndpoint } = params;
+ commit(types.SET_MILESTONES_ENDPOINT, milestonesEndpoint);
+ commit(types.SET_LABELS_ENDPOINT, labelsEndpoint);
+ commit(types.SET_GROUP_ENDPOINT, groupEndpoint);
+ commit(types.SET_PROJECT_ENDPOINT, projectEndpoint);
+};
+
+export function fetchBranches({ commit, state }, search = '') {
+ const { projectEndpoint } = state;
+ commit(types.REQUEST_BRANCHES);
+
+ return Api.branches(projectEndpoint, search)
+ .then(response => {
+ commit(types.RECEIVE_BRANCHES_SUCCESS, response.data);
+ return response;
+ })
+ .catch(({ response }) => {
+ const { status } = response;
+ commit(types.RECEIVE_BRANCHES_ERROR, status);
+ createFlash(__('Failed to load branches. Please try again.'));
+ });
+}
+
+export const fetchMilestones = ({ commit, state }, search_title = '') => {
+ commit(types.REQUEST_MILESTONES);
+ const { milestonesEndpoint } = state;
+
+ return axios
+ .get(milestonesEndpoint, { params: { search_title } })
+ .then(response => {
+ commit(types.RECEIVE_MILESTONES_SUCCESS, response.data);
+ return response;
+ })
+ .catch(({ response }) => {
+ const { status } = response;
+ commit(types.RECEIVE_MILESTONES_ERROR, status);
+ createFlash(__('Failed to load milestones. Please try again.'));
+ });
+};
+
+export const fetchLabels = ({ commit, state }, search = '') => {
+ commit(types.REQUEST_LABELS);
+
+ return axios
+ .get(state.labelsEndpoint, { params: { search } })
+ .then(response => {
+ commit(types.RECEIVE_LABELS_SUCCESS, response.data);
+ return response;
+ })
+ .catch(({ response }) => {
+ const { status } = response;
+ commit(types.RECEIVE_LABELS_ERROR, status);
+ createFlash(__('Failed to load labels. Please try again.'));
+ });
+};
+
+function fetchUser(options = {}) {
+ const { commit, projectEndpoint, groupEndpoint, query, action, errorMessage } = options;
+ commit(`REQUEST_${action}`);
+
+ let fetchUserPromise;
+ if (projectEndpoint) {
+ fetchUserPromise = Api.projectUsers(projectEndpoint, query).then(data => ({ data }));
+ } else {
+ fetchUserPromise = Api.groupMembers(groupEndpoint, { query });
+ }
+
+ return fetchUserPromise
+ .then(response => {
+ commit(`RECEIVE_${action}_SUCCESS`, response.data);
+ return response;
+ })
+ .catch(({ response }) => {
+ const { status } = response;
+ commit(`RECEIVE_${action}_ERROR`, status);
+ createFlash(errorMessage);
+ });
+}
+
+export const fetchAuthors = ({ commit, state }, query = '') => {
+ const { projectEndpoint, groupEndpoint } = state;
+
+ return fetchUser({
+ commit,
+ query,
+ projectEndpoint,
+ groupEndpoint,
+ action: 'AUTHORS',
+ errorMessage: __('Failed to load authors. Please try again.'),
+ });
+};
+
+export const fetchAssignees = ({ commit, state }, query = '') => {
+ const { projectEndpoint, groupEndpoint } = state;
+
+ return fetchUser({
+ commit,
+ query,
+ projectEndpoint,
+ groupEndpoint,
+ action: 'ASSIGNEES',
+ errorMessage: __('Failed to load assignees. Please try again.'),
+ });
+};
+
+export const setFilters = ({ commit, dispatch }, filters) => {
+ commit(types.SET_SELECTED_FILTERS, filters);
+
+ return dispatch('setFilters', filters, { root: true });
+};
+
+export const initialize = ({ commit }, initialFilters) => {
+ commit(types.SET_SELECTED_FILTERS, initialFilters);
+};
diff --git a/app/assets/javascripts/vue_shared/components/filtered_search_bar/store/modules/filters/index.js b/app/assets/javascripts/vue_shared/components/filtered_search_bar/store/modules/filters/index.js
new file mode 100644
index 00000000000..665bb29a17e
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/filtered_search_bar/store/modules/filters/index.js
@@ -0,0 +1,10 @@
+import state from './state';
+import * as actions from './actions';
+import mutations from './mutations';
+
+export default {
+ namespaced: true,
+ actions,
+ mutations,
+ state: state(),
+};
diff --git a/app/assets/javascripts/vue_shared/components/filtered_search_bar/store/modules/filters/mutation_types.js b/app/assets/javascripts/vue_shared/components/filtered_search_bar/store/modules/filters/mutation_types.js
new file mode 100644
index 00000000000..07163550524
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/filtered_search_bar/store/modules/filters/mutation_types.js
@@ -0,0 +1,26 @@
+export const SET_MILESTONES_ENDPOINT = 'SET_MILESTONES_ENDPOINT';
+export const SET_LABELS_ENDPOINT = 'SET_LABELS_ENDPOINT';
+export const SET_GROUP_ENDPOINT = 'SET_GROUP_ENDPOINT';
+export const SET_PROJECT_ENDPOINT = 'SET_PROJECT_ENDPOINT';
+
+export const REQUEST_BRANCHES = 'REQUEST_BRANCHES';
+export const RECEIVE_BRANCHES_SUCCESS = 'RECEIVE_BRANCHES_SUCCESS';
+export const RECEIVE_BRANCHES_ERROR = 'RECEIVE_BRANCHES_ERROR';
+
+export const REQUEST_MILESTONES = 'REQUEST_MILESTONES';
+export const RECEIVE_MILESTONES_SUCCESS = 'RECEIVE_MILESTONES_SUCCESS';
+export const RECEIVE_MILESTONES_ERROR = 'RECEIVE_MILESTONES_ERROR';
+
+export const REQUEST_LABELS = 'REQUEST_LABELS';
+export const RECEIVE_LABELS_SUCCESS = 'RECEIVE_LABELS_SUCCESS';
+export const RECEIVE_LABELS_ERROR = 'RECEIVE_LABELS_ERROR';
+
+export const REQUEST_AUTHORS = 'REQUEST_AUTHORS';
+export const RECEIVE_AUTHORS_SUCCESS = 'RECEIVE_AUTHORS_SUCCESS';
+export const RECEIVE_AUTHORS_ERROR = 'RECEIVE_AUTHORS_ERROR';
+
+export const REQUEST_ASSIGNEES = 'REQUEST_ASSIGNEES';
+export const RECEIVE_ASSIGNEES_SUCCESS = 'RECEIVE_ASSIGNEES_SUCCESS';
+export const RECEIVE_ASSIGNEES_ERROR = 'RECEIVE_ASSIGNEES_ERROR';
+
+export const SET_SELECTED_FILTERS = 'SET_SELECTED_FILTERS';
diff --git a/app/assets/javascripts/vue_shared/components/filtered_search_bar/store/modules/filters/mutations.js b/app/assets/javascripts/vue_shared/components/filtered_search_bar/store/modules/filters/mutations.js
new file mode 100644
index 00000000000..056b1c6310f
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/filtered_search_bar/store/modules/filters/mutations.js
@@ -0,0 +1,109 @@
+import * as types from './mutation_types';
+
+export default {
+ [types.SET_SELECTED_FILTERS](state, params) {
+ const {
+ selectedSourceBranch = null,
+ selectedSourceBranchList = [],
+ selectedTargetBranch = null,
+ selectedTargetBranchList = [],
+ selectedAuthor = null,
+ selectedAuthorList = [],
+ selectedMilestone = null,
+ selectedMilestoneList = [],
+ selectedAssignee = null,
+ selectedAssigneeList = [],
+ selectedLabel = null,
+ selectedLabelList = [],
+ } = params;
+ state.branches.source.selected = selectedSourceBranch;
+ state.branches.source.selectedList = selectedSourceBranchList;
+ state.branches.target.selected = selectedTargetBranch;
+ state.branches.target.selectedList = selectedTargetBranchList;
+ state.authors.selected = selectedAuthor;
+ state.authors.selectedList = selectedAuthorList;
+ state.assignees.selected = selectedAssignee;
+ state.assignees.selectedList = selectedAssigneeList;
+ state.milestones.selected = selectedMilestone;
+ state.milestones.selectedList = selectedMilestoneList;
+ state.labels.selected = selectedLabel;
+ state.labels.selectedList = selectedLabelList;
+ },
+ [types.SET_MILESTONES_ENDPOINT](state, milestonesEndpoint) {
+ state.milestonesEndpoint = milestonesEndpoint;
+ },
+ [types.SET_LABELS_ENDPOINT](state, labelsEndpoint) {
+ state.labelsEndpoint = labelsEndpoint;
+ },
+ [types.SET_GROUP_ENDPOINT](state, groupEndpoint) {
+ state.groupEndpoint = groupEndpoint;
+ },
+ [types.SET_PROJECT_ENDPOINT](state, projectEndpoint) {
+ state.projectEndpoint = projectEndpoint;
+ },
+ [types.REQUEST_MILESTONES](state) {
+ state.milestones.isLoading = true;
+ },
+ [types.RECEIVE_MILESTONES_SUCCESS](state, data) {
+ state.milestones.isLoading = false;
+ state.milestones.data = data;
+ state.milestones.errorCode = null;
+ },
+ [types.RECEIVE_MILESTONES_ERROR](state, errorCode) {
+ state.milestones.isLoading = false;
+ state.milestones.errorCode = errorCode;
+ state.milestones.data = [];
+ },
+ [types.REQUEST_LABELS](state) {
+ state.labels.isLoading = true;
+ },
+ [types.RECEIVE_LABELS_SUCCESS](state, data) {
+ state.labels.isLoading = false;
+ state.labels.data = data;
+ state.labels.errorCode = null;
+ },
+ [types.RECEIVE_LABELS_ERROR](state, errorCode) {
+ state.labels.isLoading = false;
+ state.labels.errorCode = errorCode;
+ state.labels.data = [];
+ },
+ [types.REQUEST_AUTHORS](state) {
+ state.authors.isLoading = true;
+ },
+ [types.RECEIVE_AUTHORS_SUCCESS](state, data) {
+ state.authors.isLoading = false;
+ state.authors.data = data;
+ state.authors.errorCode = null;
+ },
+ [types.RECEIVE_AUTHORS_ERROR](state, errorCode) {
+ state.authors.isLoading = false;
+ state.authors.errorCode = errorCode;
+ state.authors.data = [];
+ },
+ [types.REQUEST_ASSIGNEES](state) {
+ state.assignees.isLoading = true;
+ },
+ [types.RECEIVE_ASSIGNEES_SUCCESS](state, data) {
+ state.assignees.isLoading = false;
+ state.assignees.data = data;
+ state.assignees.errorCode = null;
+ },
+ [types.RECEIVE_ASSIGNEES_ERROR](state, errorCode) {
+ state.assignees.isLoading = false;
+ state.assignees.errorCode = errorCode;
+ state.assignees.data = [];
+ },
+ [types.REQUEST_BRANCHES](state) {
+ state.branches.isLoading = true;
+ },
+ [types.RECEIVE_BRANCHES_SUCCESS](state, data) {
+ state.branches.isLoading = false;
+ state.branches.data = data;
+ state.branches.errorCode = null;
+ },
+ [types.RECEIVE_BRANCHES_ERROR](state, errorCode) {
+ state.branches.isLoading = false;
+ state.branches.errorCode = errorCode;
+ state.branches.data = [];
+ },
+};
diff --git a/app/assets/javascripts/vue_shared/components/filtered_search_bar/store/modules/filters/state.js b/app/assets/javascripts/vue_shared/components/filtered_search_bar/store/modules/filters/state.js
new file mode 100644
index 00000000000..f89f5efc341
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/filtered_search_bar/store/modules/filters/state.js
@@ -0,0 +1,47 @@
+export default () => ({
+ milestonesEndpoint: '',
+ labelsEndpoint: '',
+ groupEndpoint: '',
+ projectEndpoint: '',
+ branches: {
+ isLoading: false,
+ errorCode: null,
+ data: [],
+ source: {
+ selected: null,
+ selectedList: [],
+ },
+ target: {
+ selected: null,
+ selectedList: [],
+ },
+ },
+ milestones: {
+ isLoading: false,
+ errorCode: null,
+ data: [],
+ selected: null,
+ selectedList: [],
+ },
+ labels: {
+ isLoading: false,
+ errorCode: null,
+ data: [],
+ selected: null,
+ selectedList: [],
+ },
+ authors: {
+ isLoading: false,
+ errorCode: null,
+ data: [],
+ selected: null,
+ selectedList: [],
+ },
+ assignees: {
+ isLoading: false,
+ errorCode: null,
+ data: [],
+ selected: null,
+ selectedList: [],
+ },
+});
diff --git a/app/assets/javascripts/vue_shared/components/gl_mentions.vue b/app/assets/javascripts/vue_shared/components/gl_mentions.vue
index da4b0aedef5..e895a7a52ab 100644
--- a/app/assets/javascripts/vue_shared/components/gl_mentions.vue
+++ b/app/assets/javascripts/vue_shared/components/gl_mentions.vue
@@ -1,5 +1,5 @@
<script>
-import { escape } from 'lodash';
+import { escape, last } from 'lodash';
import Tribute from 'tributejs';
import axios from '~/lib/utils/axios_utils';
import { spriteIcon } from '~/lib/utils/common_utils';
@@ -12,6 +12,8 @@ const AutoComplete = {
MergeRequests: 'mergeRequests',
};
+const groupType = 'Group'; // eslint-disable-line @gitlab/require-i18n-strings
+
function doesCurrentLineStartWith(searchString, fullText, selectionStart) {
const currentLineNumber = fullText.slice(0, selectionStart).split('\n').length;
const currentLine = fullText.split('\n')[currentLineNumber - 1];
@@ -74,30 +76,40 @@ const autoCompleteMap = {
return this.members;
},
menuItemTemplate({ original }) {
- const rectAvatarClass = original.type === 'Group' ? 'rect-avatar' : '';
-
- const avatarClasses = `avatar avatar-inline center s26 ${rectAvatarClass}
- gl-display-inline-flex! gl-align-items-center gl-justify-content-center`;
-
- const avatarTag = original.avatar_url
- ? `<img
- src="${original.avatar_url}"
- alt="${original.username}'s avatar"
- class="${avatarClasses}"/>`
- : `<div class="${avatarClasses}">${original.username.charAt(0).toUpperCase()}</div>`;
-
- const name = escape(original.name);
+ const commonClasses = 'gl-avatar gl-avatar-s24 gl-flex-shrink-0';
+ const noAvatarClasses = `${commonClasses} gl-rounded-small
+ gl-display-flex gl-align-items-center gl-justify-content-center`;
+
+ const avatar = original.avatar_url
+ ? `<img class="${commonClasses} gl-avatar-circle" src="${original.avatar_url}" alt="" />`
+ : `<div class="${noAvatarClasses}" aria-hidden="true">
+ ${original.username.charAt(0).toUpperCase()}</div>`;
+
+ let displayName = original.name;
+ let parentGroupOrUsername = `@${original.username}`;
+
+ if (original.type === groupType) {
+ const splitName = original.name.split(' / ');
+ displayName = splitName.pop();
+ parentGroupOrUsername = splitName.pop();
+ }
const count = original.count && !original.mentionsDisabled ? ` (${original.count})` : '';
- const icon = original.mentionsDisabled
- ? spriteIcon('notifications-off', 's16 gl-vertical-align-middle gl-ml-3')
+ const disabledMentionsIcon = original.mentionsDisabled
+ ? spriteIcon('notifications-off', 's16 gl-ml-3')
: '';
- return `${avatarTag}
- ${original.username}
- <small class="gl-text-small gl-font-weight-normal gl-reset-color">${name}${count}</small>
- ${icon}`;
+ return `
+ <div class="gl-display-flex gl-align-items-center">
+ ${avatar}
+ <div class="gl-font-sm gl-line-height-normal gl-ml-3">
+ <div>${escape(displayName)}${count}</div>
+ <div class="gl-text-gray-700">${escape(parentGroupOrUsername)}</div>
+ </div>
+ ${disabledMentionsIcon}
+ </div>
+ `;
},
},
[AutoComplete.MergeRequests]: {
@@ -134,7 +146,8 @@ export default {
{
trigger: '@',
fillAttr: 'username',
- lookup: value => value.name + value.username,
+ lookup: value =>
+ value.type === groupType ? last(value.name.split(' / ')) : value.name + value.username,
menuItemTemplate: autoCompleteMap[AutoComplete.Members].menuItemTemplate,
values: this.getValues(AutoComplete.Members),
},
diff --git a/app/assets/javascripts/vue_shared/components/header_ci_component.vue b/app/assets/javascripts/vue_shared/components/header_ci_component.vue
index 6ff6f10f786..79d9ba6df57 100644
--- a/app/assets/javascripts/vue_shared/components/header_ci_component.vue
+++ b/app/assets/javascripts/vue_shared/components/header_ci_component.vue
@@ -1,10 +1,11 @@
<script>
/* eslint-disable vue/no-v-html */
-import { GlTooltipDirective, GlLink, GlDeprecatedButton } from '@gitlab/ui';
-import { __, sprintf } from '~/locale';
+import { GlTooltipDirective, GlLink, GlButton, GlTooltip } from '@gitlab/ui';
import CiIconBadge from './ci_badge_link.vue';
import TimeagoTooltip from './time_ago_tooltip.vue';
import UserAvatarImage from './user_avatar/user_avatar_image.vue';
+import { glEmojiTag } from '../../emoji';
+import { __, sprintf } from '../../locale';
/**
* Renders header component for job and pipeline page based on UI mockups
@@ -19,11 +20,13 @@ export default {
TimeagoTooltip,
UserAvatarImage,
GlLink,
- GlDeprecatedButton,
+ GlButton,
+ GlTooltip,
},
directives: {
GlTooltip: GlTooltipDirective,
},
+ EMOJI_REF: 'EMOJI_REF',
props: {
status: {
type: Object,
@@ -62,6 +65,27 @@ export default {
userAvatarAltText() {
return sprintf(__(`%{username}'s avatar`), { username: this.user.name });
},
+ userPath() {
+ // GraphQL returns `webPath` and Rest `path`
+ return this.user?.webPath || this.user?.path;
+ },
+ avatarUrl() {
+ // GraphQL returns `avatarUrl` and Rest `avatar_url`
+ return this.user?.avatarUrl || this.user?.avatar_url;
+ },
+ statusTooltipHTML() {
+ // Rest `status_tooltip_html` which is a ready to work
+ // html for the emoji and the status text inside a tooltip.
+ // GraphQL returns `status.emoji` and `status.message` which
+ // needs to be combined to make the html we want.
+ const { emoji } = this.user?.status || {};
+ const emojiHtml = emoji ? glEmojiTag(emoji) : '';
+
+ return emojiHtml || this.user?.status_tooltip_html;
+ },
+ message() {
+ return this.user?.status?.message;
+ },
},
methods: {
@@ -73,7 +97,11 @@ export default {
</script>
<template>
- <header class="page-content-header ci-header-container">
+ <header
+ class="page-content-header gl-display-flex gl-min-h-7"
+ data-qa-selector="pipeline_header"
+ data-testid="ci-header-content"
+ >
<section class="header-main-content">
<ci-icon-badge :status="status" />
@@ -89,12 +117,12 @@ export default {
<template v-if="user">
<gl-link
v-gl-tooltip
- :href="user.path"
+ :href="userPath"
:title="user.email"
class="js-user-link commit-committer-link"
>
<user-avatar-image
- :img-src="user.avatar_url"
+ :img-src="avatarUrl"
:img-alt="userAvatarAltText"
:tooltip-text="user.name"
:img-size="24"
@@ -102,21 +130,27 @@ export default {
{{ user.name }}
</gl-link>
- <span v-if="user.status_tooltip_html" v-html="user.status_tooltip_html"></span>
+ <gl-tooltip v-if="message" :target="() => $refs[$options.EMOJI_REF]">
+ {{ message }}
+ </gl-tooltip>
+ <span
+ v-if="statusTooltipHTML"
+ :ref="$options.EMOJI_REF"
+ :data-testid="message"
+ v-html="statusTooltipHTML"
+ ></span>
</template>
</section>
<section v-if="$slots.default" data-testid="headerButtons" class="gl-display-flex">
<slot></slot>
</section>
- <gl-deprecated-button
+ <gl-button
v-if="hasSidebarButton"
- id="toggleSidebar"
- class="d-block d-sm-none
-sidebar-toggle-btn js-sidebar-build-toggle js-sidebar-build-toggle-header"
+ class="d-sm-none js-sidebar-build-toggle gl-ml-auto"
+ icon="angle-double-left"
+ :aria-label="__('Toggle sidebar')"
@click="onClickSidebarButton"
- >
- <i class="fa fa-angle-double-left" aria-hidden="true" aria-labelledby="toggleSidebar"> </i>
- </gl-deprecated-button>
+ />
</header>
</template>
diff --git a/app/assets/javascripts/vue_shared/components/local_storage_sync.vue b/app/assets/javascripts/vue_shared/components/local_storage_sync.vue
index b5d6b872547..80c03342f11 100644
--- a/app/assets/javascripts/vue_shared/components/local_storage_sync.vue
+++ b/app/assets/javascripts/vue_shared/components/local_storage_sync.vue
@@ -1,4 +1,6 @@
<script>
+import { isEqual } from 'lodash';
+
export default {
props: {
storageKey: {
@@ -6,31 +8,65 @@ export default {
required: true,
},
value: {
- type: String,
+ type: [String, Number, Boolean, Array, Object],
required: false,
default: '',
},
+ asJson: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ persist: {
+ type: Boolean,
+ required: false,
+ default: true,
+ },
},
watch: {
value(newVal) {
- this.saveValue(newVal);
+ this.saveValue(this.serialize(newVal));
},
},
mounted() {
// On mount, trigger update if we actually have a localStorageValue
- const value = this.getValue();
+ const { exists, value } = this.getStorageValue();
- if (value && this.value !== value) {
+ if (exists && !isEqual(value, this.value)) {
this.$emit('input', value);
}
},
methods: {
- getValue() {
- return localStorage.getItem(this.storageKey);
+ getStorageValue() {
+ const value = localStorage.getItem(this.storageKey);
+
+ if (value === null) {
+ return { exists: false };
+ }
+
+ try {
+ return { exists: true, value: this.deserialize(value) };
+ } catch {
+ // eslint-disable-next-line no-console
+ console.warn(
+ `[gitlab] Failed to deserialize value from localStorage (key=${this.storageKey})`,
+ value,
+ );
+ // default to "don't use localStorage value"
+ return { exists: false };
+ }
},
saveValue(val) {
+ if (!this.persist) return;
+
localStorage.setItem(this.storageKey, val);
},
+ serialize(val) {
+ return this.asJson ? JSON.stringify(val) : val;
+ },
+ deserialize(val) {
+ return this.asJson ? JSON.parse(val) : val;
+ },
},
render() {
return this.$slots.default;
diff --git a/app/assets/javascripts/vue_shared/components/markdown/field.vue b/app/assets/javascripts/vue_shared/components/markdown/field.vue
index a48c279d0e3..65116ed8ca3 100644
--- a/app/assets/javascripts/vue_shared/components/markdown/field.vue
+++ b/app/assets/javascripts/vue_shared/components/markdown/field.vue
@@ -25,6 +25,18 @@ export default {
},
mixins: [glFeatureFlagsMixin()],
props: {
+ /**
+ * This prop should be bound to the value of the `<textarea>` element
+ * that is rendered as a child of this component (in the `textarea` slot)
+ */
+ textareaValue: {
+ type: String,
+ required: true,
+ },
+ markdownDocsPath: {
+ type: String,
+ required: true,
+ },
isSubmitting: {
type: Boolean,
required: false,
@@ -35,10 +47,6 @@ export default {
required: false,
default: '',
},
- markdownDocsPath: {
- type: String,
- required: true,
- },
addSpacingClasses: {
type: Boolean,
required: false,
@@ -84,12 +92,6 @@ export default {
required: false,
default: false,
},
- // This prop is used as a fallback in case if textarea.elm is undefined
- textareaValue: {
- type: String,
- required: false,
- default: '',
- },
},
data() {
return {
@@ -165,17 +167,20 @@ export default {
},
mounted() {
// GLForm class handles all the toolbar buttons
- return new GLForm($(this.$refs['gl-form']), {
- emojis: this.enableAutocomplete,
- members: this.enableAutocomplete && !this.glFeatures.tributeAutocomplete,
- issues: this.enableAutocomplete && !this.glFeatures.tributeAutocomplete,
- mergeRequests: this.enableAutocomplete && !this.glFeatures.tributeAutocomplete,
- epics: this.enableAutocomplete,
- milestones: this.enableAutocomplete,
- labels: this.enableAutocomplete && !this.glFeatures.tributeAutocomplete,
- snippets: this.enableAutocomplete,
- vulnerabilities: this.enableAutocomplete,
- });
+ return new GLForm(
+ $(this.$refs['gl-form']),
+ {
+ emojis: this.enableAutocomplete,
+ members: this.enableAutocomplete && !this.glFeatures.tributeAutocomplete,
+ issues: this.enableAutocomplete && !this.glFeatures.tributeAutocomplete,
+ mergeRequests: this.enableAutocomplete && !this.glFeatures.tributeAutocomplete,
+ epics: this.enableAutocomplete,
+ milestones: this.enableAutocomplete,
+ labels: this.enableAutocomplete && !this.glFeatures.tributeAutocomplete,
+ snippets: this.enableAutocomplete,
+ },
+ true,
+ );
},
beforeDestroy() {
const glForm = $(this.$refs['gl-form']).data('glForm');
@@ -189,17 +194,11 @@ export default {
this.previewMarkdown = true;
- /*
- Can't use `$refs` as the component is technically in the parent component
- so we access the VNode & then get the element
- */
- const text = this.$slots.textarea[0]?.elm?.value || this.textareaValue;
-
- if (text) {
+ if (this.textareaValue) {
this.markdownPreviewLoading = true;
this.markdownPreview = __('Loading…');
axios
- .post(this.markdownPreviewPath, { text })
+ .post(this.markdownPreviewPath, { text: this.textareaValue })
.then(response => this.renderMarkdown(response.data))
.catch(() => new Flash(__('Error loading markdown preview')));
} else {
@@ -234,7 +233,7 @@ export default {
<div
ref="gl-form"
:class="{ 'gl-mt-3 gl-mb-3': addSpacingClasses }"
- class="js-vue-markdown-field md-area position-relative"
+ class="js-vue-markdown-field md-area position-relative gfm-form"
>
<markdown-header
:preview-markdown="previewMarkdown"
diff --git a/app/assets/javascripts/vue_shared/components/markdown/suggestion_diff.vue b/app/assets/javascripts/vue_shared/components/markdown/suggestion_diff.vue
index 13c42d35b04..13ec7a6ada9 100644
--- a/app/assets/javascripts/vue_shared/components/markdown/suggestion_diff.vue
+++ b/app/assets/javascripts/vue_shared/components/markdown/suggestion_diff.vue
@@ -27,6 +27,11 @@ export default {
type: String,
required: true,
},
+ suggestionsCount: {
+ type: Number,
+ required: false,
+ default: 0,
+ },
},
computed: {
batchSuggestionsCount() {
@@ -62,6 +67,7 @@ export default {
<div class="md-suggestion">
<suggestion-diff-header
class="qa-suggestion-diff-header js-suggestion-diff-header"
+ :suggestions-count="suggestionsCount"
:can-apply="suggestion.appliable && suggestion.current_user.can_apply && !disabled"
:is-applied="suggestion.applied"
:is-batched="isBatched"
diff --git a/app/assets/javascripts/vue_shared/components/markdown/suggestion_diff_header.vue b/app/assets/javascripts/vue_shared/components/markdown/suggestion_diff_header.vue
index 1fc54d2f52e..fb9636ba734 100644
--- a/app/assets/javascripts/vue_shared/components/markdown/suggestion_diff_header.vue
+++ b/app/assets/javascripts/vue_shared/components/markdown/suggestion_diff_header.vue
@@ -42,6 +42,11 @@ export default {
required: false,
default: null,
},
+ suggestionsCount: {
+ type: Number,
+ required: false,
+ default: 0,
+ },
},
data() {
return {
@@ -127,7 +132,7 @@ export default {
</div>
<div v-else class="d-flex align-items-center">
<gl-button
- v-if="canBeBatched && !isDisableButton"
+ v-if="suggestionsCount > 1 && canBeBatched && !isDisableButton"
class="btn-inverted js-add-to-batch-btn btn-grouped"
:disabled="isDisableButton"
@click="addSuggestionToBatch"
diff --git a/app/assets/javascripts/vue_shared/components/markdown/suggestions.vue b/app/assets/javascripts/vue_shared/components/markdown/suggestions.vue
index 083f581af05..927a93487e6 100644
--- a/app/assets/javascripts/vue_shared/components/markdown/suggestions.vue
+++ b/app/assets/javascripts/vue_shared/components/markdown/suggestions.vue
@@ -38,6 +38,11 @@ export default {
type: String,
required: true,
},
+ suggestionsCount: {
+ type: Number,
+ required: false,
+ default: 0,
+ },
},
data() {
return {
@@ -77,12 +82,12 @@ export default {
this.isRendered = true;
},
generateDiff(suggestionIndex) {
- const { suggestions, disabled, batchSuggestionsInfo, helpPagePath } = this;
+ const { suggestions, disabled, batchSuggestionsInfo, helpPagePath, suggestionsCount } = this;
const suggestion =
suggestions && suggestions[suggestionIndex] ? suggestions[suggestionIndex] : {};
const SuggestionDiffComponent = Vue.extend(SuggestionDiff);
const suggestionDiff = new SuggestionDiffComponent({
- propsData: { disabled, suggestion, batchSuggestionsInfo, helpPagePath },
+ propsData: { disabled, suggestion, batchSuggestionsInfo, helpPagePath, suggestionsCount },
});
suggestionDiff.$on('apply', ({ suggestionId, callback }) => {
diff --git a/app/assets/javascripts/vue_shared/components/members/action_buttons/access_request_action_buttons.vue b/app/assets/javascripts/vue_shared/components/members/action_buttons/access_request_action_buttons.vue
new file mode 100644
index 00000000000..10078d5cd64
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/members/action_buttons/access_request_action_buttons.vue
@@ -0,0 +1,59 @@
+<script>
+import ActionButtonGroup from './action_button_group.vue';
+import RemoveMemberButton from './remove_member_button.vue';
+import ApproveAccessRequestButton from './approve_access_request_button.vue';
+import { s__, sprintf } from '~/locale';
+
+export default {
+ name: 'AccessRequestActionButtons',
+ components: { ActionButtonGroup, RemoveMemberButton, ApproveAccessRequestButton },
+ props: {
+ member: {
+ type: Object,
+ required: true,
+ },
+ permissions: {
+ type: Object,
+ required: true,
+ },
+ isCurrentUser: {
+ type: Boolean,
+ required: true,
+ },
+ },
+ computed: {
+ message() {
+ const { user, source } = this.member;
+
+ if (this.isCurrentUser) {
+ return sprintf(
+ s__('Members|Are you sure you want to withdraw your access request for "%{source}"'),
+ { source: source.name },
+ );
+ }
+
+ return sprintf(
+ s__('Members|Are you sure you want to deny %{usersName}\'s request to join "%{source}"'),
+ { usersName: user.name, source: source.name },
+ );
+ },
+ },
+};
+</script>
+
+<template>
+ <action-button-group>
+ <div v-if="permissions.canUpdate" class="gl-px-1">
+ <approve-access-request-button :member-id="member.id" />
+ </div>
+ <div v-if="permissions.canRemove" class="gl-px-1">
+ <remove-member-button
+ :member-id="member.id"
+ :message="message"
+ :title="s__('Member|Deny access')"
+ :is-access-request="true"
+ icon="close"
+ />
+ </div>
+ </action-button-group>
+</template>
diff --git a/app/assets/javascripts/vue_shared/components/members/action_buttons/action_button_group.vue b/app/assets/javascripts/vue_shared/components/members/action_buttons/action_button_group.vue
new file mode 100644
index 00000000000..8356fdb60b1
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/members/action_buttons/action_button_group.vue
@@ -0,0 +1,11 @@
+<script>
+export default {
+ name: 'ActionButtonGroup',
+};
+</script>
+
+<template>
+ <div class="gl-display-flex gl-flex-align-items-center gl-justify-content-end gl-mx-n1">
+ <slot></slot>
+ </div>
+</template>
diff --git a/app/assets/javascripts/vue_shared/components/members/action_buttons/approve_access_request_button.vue b/app/assets/javascripts/vue_shared/components/members/action_buttons/approve_access_request_button.vue
new file mode 100644
index 00000000000..e8a53ff173d
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/members/action_buttons/approve_access_request_button.vue
@@ -0,0 +1,42 @@
+<script>
+import { mapState } from 'vuex';
+import { GlButton, GlForm, GlTooltipDirective } from '@gitlab/ui';
+import csrf from '~/lib/utils/csrf';
+import { __ } from '~/locale';
+
+export default {
+ name: 'ApproveAccessRequestButton',
+ csrf,
+ title: __('Grant access'),
+ components: { GlButton, GlForm },
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ },
+ props: {
+ memberId: {
+ type: Number,
+ required: true,
+ },
+ },
+ computed: {
+ ...mapState(['memberPath']),
+ approvePath() {
+ return this.memberPath.replace(/:id$/, `${this.memberId}/approve_access_request`);
+ },
+ },
+};
+</script>
+
+<template>
+ <gl-form :action="approvePath" method="post">
+ <input :value="$options.csrf.token" type="hidden" name="authenticity_token" />
+ <gl-button
+ v-gl-tooltip.hover
+ :title="$options.title"
+ :aria-label="$options.title"
+ icon="check"
+ variant="success"
+ type="submit"
+ />
+ </gl-form>
+</template>
diff --git a/app/assets/javascripts/vue_shared/components/members/action_buttons/group_action_buttons.vue b/app/assets/javascripts/vue_shared/components/members/action_buttons/group_action_buttons.vue
new file mode 100644
index 00000000000..2aebfe80db5
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/members/action_buttons/group_action_buttons.vue
@@ -0,0 +1,27 @@
+<script>
+import ActionButtonGroup from './action_button_group.vue';
+import RemoveGroupLinkButton from './remove_group_link_button.vue';
+
+export default {
+ name: 'GroupActionButtons',
+ components: { ActionButtonGroup, RemoveGroupLinkButton },
+ props: {
+ member: {
+ type: Object,
+ required: true,
+ },
+ permissions: {
+ type: Object,
+ required: true,
+ },
+ },
+};
+</script>
+
+<template>
+ <action-button-group>
+ <div v-if="permissions.canRemove" class="gl-px-1">
+ <remove-group-link-button :group-link="member" />
+ </div>
+ </action-button-group>
+</template>
diff --git a/app/assets/javascripts/vue_shared/components/members/action_buttons/invite_action_buttons.vue b/app/assets/javascripts/vue_shared/components/members/action_buttons/invite_action_buttons.vue
new file mode 100644
index 00000000000..2b0a75640e2
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/members/action_buttons/invite_action_buttons.vue
@@ -0,0 +1,48 @@
+<script>
+import ActionButtonGroup from './action_button_group.vue';
+import RemoveMemberButton from './remove_member_button.vue';
+import ResendInviteButton from './resend_invite_button.vue';
+import { s__, sprintf } from '~/locale';
+
+export default {
+ name: 'InviteActionButtons',
+ components: { ActionButtonGroup, RemoveMemberButton, ResendInviteButton },
+ props: {
+ member: {
+ type: Object,
+ required: true,
+ },
+ permissions: {
+ type: Object,
+ required: true,
+ },
+ },
+ computed: {
+ message() {
+ const { invite, source } = this.member;
+
+ return sprintf(
+ s__(
+ 'Members|Are you sure you want to revoke the invitation for %{inviteEmail} to join "%{source}"',
+ ),
+ { inviteEmail: invite.email, source: source.name },
+ );
+ },
+ },
+};
+</script>
+
+<template>
+ <action-button-group>
+ <div v-if="permissions.canResend" class="gl-px-1">
+ <resend-invite-button :member-id="member.id" />
+ </div>
+ <div v-if="permissions.canRemove" class="gl-px-1">
+ <remove-member-button
+ :member-id="member.id"
+ :message="message"
+ :title="s__('Member|Revoke invite')"
+ />
+ </div>
+ </action-button-group>
+</template>
diff --git a/app/assets/javascripts/vue_shared/components/members/action_buttons/leave_button.vue b/app/assets/javascripts/vue_shared/components/members/action_buttons/leave_button.vue
new file mode 100644
index 00000000000..d9976e7181c
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/members/action_buttons/leave_button.vue
@@ -0,0 +1,40 @@
+<script>
+import { GlButton, GlModalDirective, GlTooltipDirective } from '@gitlab/ui';
+import { __ } from '~/locale';
+import LeaveModal from '../modals/leave_modal.vue';
+import { LEAVE_MODAL_ID } from '../constants';
+
+export default {
+ name: 'LeaveButton',
+ title: __('Leave'),
+ modalId: LEAVE_MODAL_ID,
+ components: {
+ GlButton,
+ LeaveModal,
+ },
+ directives: {
+ GlModal: GlModalDirective,
+ GlTooltip: GlTooltipDirective,
+ },
+ props: {
+ member: {
+ type: Object,
+ required: true,
+ },
+ },
+};
+</script>
+
+<template>
+ <div>
+ <gl-button
+ v-gl-tooltip.hover
+ v-gl-modal="$options.modalId"
+ :title="$options.title"
+ :aria-label="$options.title"
+ icon="leave"
+ variant="danger"
+ />
+ <leave-modal :member="member" />
+ </div>
+</template>
diff --git a/app/assets/javascripts/vue_shared/components/members/action_buttons/remove_group_link_button.vue b/app/assets/javascripts/vue_shared/components/members/action_buttons/remove_group_link_button.vue
new file mode 100644
index 00000000000..9d89cb40676
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/members/action_buttons/remove_group_link_button.vue
@@ -0,0 +1,36 @@
+<script>
+import { mapActions } from 'vuex';
+import { GlButton, GlTooltipDirective } from '@gitlab/ui';
+import { s__ } from '~/locale';
+
+export default {
+ name: 'RemoveGroupLinkButton',
+ i18n: {
+ buttonTitle: s__('Members|Remove group'),
+ },
+ components: { GlButton },
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ },
+ props: {
+ groupLink: {
+ type: Object,
+ required: true,
+ },
+ },
+ methods: {
+ ...mapActions(['showRemoveGroupLinkModal']),
+ },
+};
+</script>
+
+<template>
+ <gl-button
+ v-gl-tooltip.hover
+ variant="danger"
+ :title="$options.i18n.buttonTitle"
+ :aria-label="$options.i18n.buttonTitle"
+ icon="remove"
+ @click="showRemoveGroupLinkModal(groupLink)"
+ />
+</template>
diff --git a/app/assets/javascripts/vue_shared/components/members/action_buttons/remove_member_button.vue b/app/assets/javascripts/vue_shared/components/members/action_buttons/remove_member_button.vue
new file mode 100644
index 00000000000..b0b7ff4ce9a
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/members/action_buttons/remove_member_button.vue
@@ -0,0 +1,57 @@
+<script>
+import { mapState } from 'vuex';
+import { GlButton, GlTooltipDirective } from '@gitlab/ui';
+
+export default {
+ name: 'RemoveMemberButton',
+ components: { GlButton },
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ },
+ props: {
+ memberId: {
+ type: Number,
+ required: true,
+ },
+ message: {
+ type: String,
+ required: true,
+ },
+ title: {
+ type: String,
+ required: true,
+ },
+ icon: {
+ type: String,
+ required: false,
+ default: 'remove',
+ },
+ isAccessRequest: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ },
+ computed: {
+ ...mapState(['memberPath']),
+ computedMemberPath() {
+ return this.memberPath.replace(':id', this.memberId);
+ },
+ },
+};
+</script>
+
+<template>
+ <gl-button
+ v-gl-tooltip.hover
+ class="js-remove-member-button"
+ variant="danger"
+ :title="title"
+ :aria-label="title"
+ :icon="icon"
+ :data-member-path="computedMemberPath"
+ :data-is-access-request="isAccessRequest"
+ :data-message="message"
+ data-qa-selector="delete_member_button"
+ />
+</template>
diff --git a/app/assets/javascripts/vue_shared/components/members/action_buttons/resend_invite_button.vue b/app/assets/javascripts/vue_shared/components/members/action_buttons/resend_invite_button.vue
new file mode 100644
index 00000000000..1cc3fd17e98
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/members/action_buttons/resend_invite_button.vue
@@ -0,0 +1,41 @@
+<script>
+import { mapState } from 'vuex';
+import { GlButton, GlTooltipDirective } from '@gitlab/ui';
+import csrf from '~/lib/utils/csrf';
+import { __ } from '~/locale';
+
+export default {
+ name: 'ResendInviteButton',
+ csrf,
+ title: __('Resend invite'),
+ components: { GlButton },
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ },
+ props: {
+ memberId: {
+ type: Number,
+ required: true,
+ },
+ },
+ computed: {
+ ...mapState(['memberPath']),
+ resendPath() {
+ return this.memberPath.replace(/:id$/, `${this.memberId}/resend_invite`);
+ },
+ },
+};
+</script>
+
+<template>
+ <form :action="resendPath" method="post">
+ <input :value="$options.csrf.token" type="hidden" name="authenticity_token" />
+ <gl-button
+ v-gl-tooltip.hover
+ :title="$options.title"
+ :aria-label="$options.title"
+ icon="paper-airplane"
+ type="submit"
+ />
+ </form>
+</template>
diff --git a/app/assets/javascripts/vue_shared/components/members/action_buttons/user_action_buttons.vue b/app/assets/javascripts/vue_shared/components/members/action_buttons/user_action_buttons.vue
new file mode 100644
index 00000000000..8fa3d439fc1
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/members/action_buttons/user_action_buttons.vue
@@ -0,0 +1,61 @@
+<script>
+import ActionButtonGroup from './action_button_group.vue';
+import RemoveMemberButton from './remove_member_button.vue';
+import LeaveButton from './leave_button.vue';
+import { s__, sprintf } from '~/locale';
+
+export default {
+ name: 'UserActionButtons',
+ components: { ActionButtonGroup, RemoveMemberButton, LeaveButton },
+ props: {
+ member: {
+ type: Object,
+ required: true,
+ },
+ isCurrentUser: {
+ type: Boolean,
+ required: true,
+ },
+ permissions: {
+ type: Object,
+ required: true,
+ },
+ },
+ computed: {
+ message() {
+ const { user, source } = this.member;
+
+ if (user) {
+ return sprintf(
+ s__('Members|Are you sure you want to remove %{usersName} from "%{source}"'),
+ {
+ usersName: user.name,
+ source: source.name,
+ },
+ );
+ }
+
+ return sprintf(
+ s__('Members|Are you sure you want to remove this orphaned member from "%{source}"'),
+ {
+ source: source.name,
+ },
+ );
+ },
+ },
+};
+</script>
+
+<template>
+ <action-button-group>
+ <div v-if="permissions.canRemove" class="gl-px-1">
+ <leave-button v-if="isCurrentUser" :member="member" />
+ <remove-member-button
+ v-else
+ :member-id="member.id"
+ :message="message"
+ :title="s__('Member|Remove member')"
+ />
+ </div>
+ </action-button-group>
+</template>
diff --git a/app/assets/javascripts/vue_shared/components/members/avatars/group_avatar.vue b/app/assets/javascripts/vue_shared/components/members/avatars/group_avatar.vue
new file mode 100644
index 00000000000..12b748f9ab6
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/members/avatars/group_avatar.vue
@@ -0,0 +1,34 @@
+<script>
+import { GlAvatarLink, GlAvatarLabeled } from '@gitlab/ui';
+import { AVATAR_SIZE } from '../constants';
+
+export default {
+ name: 'GroupAvatar',
+ avatarSize: AVATAR_SIZE,
+ components: { GlAvatarLink, GlAvatarLabeled },
+ props: {
+ member: {
+ type: Object,
+ required: true,
+ },
+ },
+ computed: {
+ group() {
+ return this.member.sharedWithGroup;
+ },
+ },
+};
+</script>
+
+<template>
+ <gl-avatar-link :href="group.webUrl">
+ <gl-avatar-labeled
+ :label="group.fullName"
+ :src="group.avatarUrl"
+ :alt="group.fullName"
+ :size="$options.avatarSize"
+ :entity-name="group.name"
+ :entity-id="group.id"
+ />
+ </gl-avatar-link>
+</template>
diff --git a/app/assets/javascripts/vue_shared/components/members/avatars/invite_avatar.vue b/app/assets/javascripts/vue_shared/components/members/avatars/invite_avatar.vue
new file mode 100644
index 00000000000..28654a60860
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/members/avatars/invite_avatar.vue
@@ -0,0 +1,32 @@
+<script>
+import { GlAvatarLabeled } from '@gitlab/ui';
+import { AVATAR_SIZE } from '../constants';
+
+export default {
+ name: 'InviteAvatar',
+ avatarSize: AVATAR_SIZE,
+ components: { GlAvatarLabeled },
+ props: {
+ member: {
+ type: Object,
+ required: true,
+ },
+ },
+ computed: {
+ invite() {
+ return this.member.invite;
+ },
+ },
+};
+</script>
+
+<template>
+ <gl-avatar-labeled
+ :label="invite.email"
+ :src="invite.avatarUrl"
+ :alt="invite.email"
+ :size="$options.avatarSize"
+ :entity-name="invite.email"
+ :entity-id="member.id"
+ />
+</template>
diff --git a/app/assets/javascripts/vue_shared/components/members/avatars/user_avatar.vue b/app/assets/javascripts/vue_shared/components/members/avatars/user_avatar.vue
new file mode 100644
index 00000000000..e5e7cdf149c
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/members/avatars/user_avatar.vue
@@ -0,0 +1,91 @@
+<script>
+import {
+ GlAvatarLink,
+ GlAvatarLabeled,
+ GlBadge,
+ GlSafeHtmlDirective as SafeHtml,
+} from '@gitlab/ui';
+import { generateBadges } from 'ee_else_ce/vue_shared/components/members/utils';
+import { __ } from '~/locale';
+import { AVATAR_SIZE } from '../constants';
+import { glEmojiTag } from '~/emoji';
+
+export default {
+ name: 'UserAvatar',
+ avatarSize: AVATAR_SIZE,
+ orphanedUserLabel: __('Orphaned member'),
+ safeHtmlConfig: { ADD_TAGS: ['gl-emoji'] },
+ components: {
+ GlAvatarLink,
+ GlAvatarLabeled,
+ GlBadge,
+ },
+ directives: {
+ SafeHtml,
+ },
+ props: {
+ member: {
+ type: Object,
+ required: true,
+ },
+ isCurrentUser: {
+ type: Boolean,
+ required: true,
+ },
+ },
+ computed: {
+ user() {
+ return this.member.user;
+ },
+ badges() {
+ return generateBadges(this.member, this.isCurrentUser).filter(badge => badge.show);
+ },
+ statusEmoji() {
+ return this.user?.status?.emoji;
+ },
+ },
+ methods: {
+ glEmojiTag,
+ },
+};
+</script>
+
+<template>
+ <gl-avatar-link
+ v-if="user"
+ class="js-user-link"
+ :href="user.webUrl"
+ :data-user-id="user.id"
+ :data-username="user.username"
+ >
+ <gl-avatar-labeled
+ :label="user.name"
+ :sub-label="`@${user.username}`"
+ :src="user.avatarUrl"
+ :alt="user.name"
+ :size="$options.avatarSize"
+ :entity-name="user.name"
+ :entity-id="user.id"
+ >
+ <template #meta>
+ <div v-if="statusEmoji" class="gl-p-1">
+ <span v-safe-html:[$options.safeHtmlConfig]="glEmojiTag(statusEmoji)"></span>
+ </div>
+ <div v-for="badge in badges" :key="badge.text" class="gl-p-1">
+ <gl-badge size="sm" :variant="badge.variant">
+ {{ badge.text }}
+ </gl-badge>
+ </div>
+ </template>
+ </gl-avatar-labeled>
+ </gl-avatar-link>
+
+ <gl-avatar-labeled
+ v-else
+ :label="$options.orphanedUserLabel"
+ :alt="$options.orphanedUserLabel"
+ :size="$options.avatarSize"
+ :entity-name="$options.orphanedUserLabel"
+ :entity-id="member.id"
+ />
+</template>
diff --git a/app/assets/javascripts/vue_shared/components/members/constants.js b/app/assets/javascripts/vue_shared/components/members/constants.js
new file mode 100644
index 00000000000..6509779053e
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/members/constants.js
@@ -0,0 +1,70 @@
+import { __ } from '~/locale';
+
+export const FIELDS = [
+ {
+ key: 'account',
+ label: __('Account'),
+ },
+ {
+ key: 'source',
+ label: __('Source'),
+ thClass: 'col-meta',
+ tdClass: 'col-meta',
+ },
+ {
+ key: 'granted',
+ label: __('Access granted'),
+ thClass: 'col-meta',
+ tdClass: 'col-meta',
+ },
+ {
+ key: 'invited',
+ label: __('Invited'),
+ thClass: 'col-meta',
+ tdClass: 'col-meta',
+ },
+ {
+ key: 'requested',
+ label: __('Requested'),
+ thClass: 'col-meta',
+ tdClass: 'col-meta',
+ },
+ {
+ key: 'expires',
+ label: __('Access expires'),
+ thClass: 'col-meta',
+ tdClass: 'col-meta',
+ },
+ {
+ key: 'maxRole',
+ label: __('Max role'),
+ thClass: 'col-max-role',
+ tdClass: 'col-max-role',
+ },
+ {
+ key: 'expiration',
+ label: __('Expiration'),
+ thClass: 'col-expiration',
+ tdClass: 'col-expiration',
+ },
+ {
+ key: 'actions',
+ thClass: 'col-actions',
+ tdClass: 'col-actions',
+ },
+];
+
+export const AVATAR_SIZE = 48;
+
+export const MEMBER_TYPES = {
+ user: 'user',
+ group: 'group',
+ invite: 'invite',
+ accessRequest: 'accessRequest',
+};
+
+export const DAYS_TO_EXPIRE_SOON = 7;
+
+export const LEAVE_MODAL_ID = 'member-leave-modal';
+
+export const REMOVE_GROUP_LINK_MODAL_ID = 'remove-group-link-modal-id';
diff --git a/app/assets/javascripts/vue_shared/components/members/modals/leave_modal.vue b/app/assets/javascripts/vue_shared/components/members/modals/leave_modal.vue
new file mode 100644
index 00000000000..9a2ce0d4931
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/members/modals/leave_modal.vue
@@ -0,0 +1,70 @@
+<script>
+import { mapState } from 'vuex';
+import { GlModal, GlForm, GlSprintf, GlTooltipDirective } from '@gitlab/ui';
+import csrf from '~/lib/utils/csrf';
+import { __, s__, sprintf } from '~/locale';
+import { LEAVE_MODAL_ID } from '../constants';
+
+export default {
+ name: 'LeaveModal',
+ actionCancel: {
+ text: __('Cancel'),
+ },
+ actionPrimary: {
+ text: __('Leave'),
+ attributes: {
+ variant: 'danger',
+ },
+ },
+ csrf,
+ modalId: LEAVE_MODAL_ID,
+ modalContent: s__('Members|Are you sure you want to leave "%{source}"?'),
+ components: { GlModal, GlForm, GlSprintf },
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ },
+ props: {
+ member: {
+ type: Object,
+ required: true,
+ },
+ },
+ computed: {
+ ...mapState(['memberPath']),
+ leavePath() {
+ return this.memberPath.replace(/:id$/, 'leave');
+ },
+ modalTitle() {
+ return sprintf(s__('Members|Leave "%{source}"'), { source: this.member.source.name });
+ },
+ },
+ methods: {
+ handlePrimary() {
+ this.$refs.form.$el.submit();
+ },
+ },
+};
+</script>
+
+<template>
+ <gl-modal
+ v-bind="$attrs"
+ :modal-id="$options.modalId"
+ :title="modalTitle"
+ :action-primary="$options.actionPrimary"
+ :action-cancel="$options.actionCancel"
+ size="sm"
+ @primary="handlePrimary"
+ >
+ <gl-form ref="form" :action="leavePath" method="post">
+ <p>
+ <gl-sprintf :message="$options.modalContent">
+ <template #source>{{ member.source.name }}</template>
+ </gl-sprintf>
+ </p>
+
+ <input type="hidden" name="_method" value="delete" />
+ <input :value="$options.csrf.token" type="hidden" name="authenticity_token" />
+ </gl-form>
+ </gl-modal>
+</template>
diff --git a/app/assets/javascripts/vue_shared/components/members/modals/remove_group_link_modal.vue b/app/assets/javascripts/vue_shared/components/members/modals/remove_group_link_modal.vue
new file mode 100644
index 00000000000..e8890717724
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/members/modals/remove_group_link_modal.vue
@@ -0,0 +1,69 @@
+<script>
+import { mapState, mapActions } from 'vuex';
+import { GlModal, GlSprintf, GlForm } from '@gitlab/ui';
+import csrf from '~/lib/utils/csrf';
+import { __, s__, sprintf } from '~/locale';
+import { REMOVE_GROUP_LINK_MODAL_ID } from '../constants';
+
+export default {
+ name: 'RemoveGroupLinkModal',
+ actionCancel: {
+ text: __('Cancel'),
+ },
+ actionPrimary: {
+ text: s__('Members|Remove group'),
+ attributes: {
+ variant: 'danger',
+ },
+ },
+ csrf,
+ i18n: {
+ modalBody: s__('Members|Are you sure you want to remove "%{groupName}"?'),
+ },
+ modalId: REMOVE_GROUP_LINK_MODAL_ID,
+ components: { GlModal, GlSprintf, GlForm },
+ computed: {
+ ...mapState(['memberPath', 'groupLinkToRemove', 'removeGroupLinkModalVisible']),
+ groupLinkPath() {
+ return this.memberPath.replace(/:id$/, this.groupLinkToRemove?.id);
+ },
+ groupName() {
+ return this.groupLinkToRemove?.sharedWithGroup.fullName;
+ },
+ modalTitle() {
+ return sprintf(s__('Members|Remove "%{groupName}"'), { groupName: this.groupName });
+ },
+ },
+ methods: {
+ ...mapActions(['hideRemoveGroupLinkModal']),
+ handlePrimary() {
+ this.$refs.form.$el.submit();
+ },
+ },
+};
+</script>
+
+<template>
+ <gl-modal
+ v-bind="$attrs"
+ :modal-id="$options.modalId"
+ :visible="removeGroupLinkModalVisible"
+ :title="modalTitle"
+ :action-primary="$options.actionPrimary"
+ :action-cancel="$options.actionCancel"
+ size="sm"
+ @primary="handlePrimary"
+ @hide="hideRemoveGroupLinkModal"
+ >
+ <gl-form ref="form" :action="groupLinkPath" method="post">
+ <p>
+ <gl-sprintf :message="$options.i18n.modalBody">
+ <template #groupName>{{ groupName }}</template>
+ </gl-sprintf>
+ </p>
+
+ <input type="hidden" name="_method" value="delete" />
+ <input :value="$options.csrf.token" type="hidden" name="authenticity_token" />
+ </gl-form>
+ </gl-modal>
+</template>
diff --git a/app/assets/javascripts/vue_shared/components/members/table/created_at.vue b/app/assets/javascripts/vue_shared/components/members/table/created_at.vue
new file mode 100644
index 00000000000..0bad70894f9
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/members/table/created_at.vue
@@ -0,0 +1,40 @@
+<script>
+import { GlSprintf } from '@gitlab/ui';
+import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
+
+export default {
+ name: 'CreatedAt',
+ components: { GlSprintf, TimeAgoTooltip },
+ props: {
+ date: {
+ type: String,
+ required: false,
+ default: null,
+ },
+ createdBy: {
+ type: Object,
+ required: false,
+ default: null,
+ },
+ },
+ computed: {
+ showCreatedBy() {
+ return this.createdBy?.name && this.createdBy?.webUrl;
+ },
+ },
+};
+</script>
+
+<template>
+ <span>
+ <gl-sprintf v-if="showCreatedBy" :message="s__('Members|%{time} by %{user}')">
+ <template #time>
+ <time-ago-tooltip :time="date" />
+ </template>
+ <template #user>
+ <a :href="createdBy.webUrl">{{ createdBy.name }}</a>
+ </template>
+ </gl-sprintf>
+ <time-ago-tooltip v-else :time="date" />
+ </span>
+</template>
diff --git a/app/assets/javascripts/vue_shared/components/members/table/expires_at.vue b/app/assets/javascripts/vue_shared/components/members/table/expires_at.vue
new file mode 100644
index 00000000000..de65e3fb10f
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/members/table/expires_at.vue
@@ -0,0 +1,66 @@
+<script>
+import { GlSprintf, GlTooltipDirective } from '@gitlab/ui';
+import {
+ approximateDuration,
+ differenceInSeconds,
+ formatDate,
+ getDayDifference,
+} from '~/lib/utils/datetime_utility';
+import { DAYS_TO_EXPIRE_SOON } from '../constants';
+
+export default {
+ name: 'ExpiresAt',
+ components: { GlSprintf },
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ },
+ props: {
+ date: {
+ type: String,
+ required: false,
+ default: null,
+ },
+ },
+ computed: {
+ noExpirationSet() {
+ return this.date === null;
+ },
+ parsed() {
+ return new Date(this.date);
+ },
+ differenceInSeconds() {
+ return differenceInSeconds(new Date(), this.parsed);
+ },
+ isExpired() {
+ return this.differenceInSeconds <= 0;
+ },
+ inWords() {
+ return approximateDuration(this.differenceInSeconds);
+ },
+ formatted() {
+ return formatDate(this.parsed);
+ },
+ expiresSoon() {
+ return getDayDifference(new Date(), this.parsed) < DAYS_TO_EXPIRE_SOON;
+ },
+ cssClass() {
+ return {
+ 'gl-text-red-500': this.isExpired,
+ 'gl-text-orange-500': this.expiresSoon,
+ };
+ },
+ },
+};
+</script>
+
+<template>
+ <span v-if="noExpirationSet">{{ s__('Members|No expiration set') }}</span>
+ <span v-else v-gl-tooltip.hover :title="formatted" :class="cssClass">
+ <template v-if="isExpired">{{ s__('Members|Expired') }}</template>
+ <gl-sprintf v-else :message="s__('Members|in %{time}')">
+ <template #time>
+ {{ inWords }}
+ </template>
+ </gl-sprintf>
+ </span>
+</template>
diff --git a/app/assets/javascripts/vue_shared/components/members/table/member_action_buttons.vue b/app/assets/javascripts/vue_shared/components/members/table/member_action_buttons.vue
new file mode 100644
index 00000000000..320d8c99223
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/members/table/member_action_buttons.vue
@@ -0,0 +1,57 @@
+<script>
+import UserActionButtons from '../action_buttons/user_action_buttons.vue';
+import GroupActionButtons from '../action_buttons/group_action_buttons.vue';
+import InviteActionButtons from '../action_buttons/invite_action_buttons.vue';
+import AccessRequestActionButtons from '../action_buttons/access_request_action_buttons.vue';
+import { MEMBER_TYPES } from '../constants';
+
+export default {
+ name: 'MemberActionButtons',
+ components: {
+ UserActionButtons,
+ GroupActionButtons,
+ InviteActionButtons,
+ AccessRequestActionButtons,
+ },
+ props: {
+ member: {
+ type: Object,
+ required: true,
+ },
+ memberType: {
+ type: String,
+ required: true,
+ },
+ permissions: {
+ type: Object,
+ required: true,
+ },
+ isCurrentUser: {
+ type: Boolean,
+ required: true,
+ },
+ },
+ computed: {
+ actionButtonComponent() {
+ const dictionary = {
+ [MEMBER_TYPES.user]: 'user-action-buttons',
+ [MEMBER_TYPES.group]: 'group-action-buttons',
+ [MEMBER_TYPES.invite]: 'invite-action-buttons',
+ [MEMBER_TYPES.accessRequest]: 'access-request-action-buttons',
+ };
+
+ return dictionary[this.memberType];
+ },
+ },
+};
+</script>
+
+<template>
+ <component
+ :is="actionButtonComponent"
+ v-if="actionButtonComponent"
+ :member="member"
+ :permissions="permissions"
+ :is-current-user="isCurrentUser"
+ />
+</template>
diff --git a/app/assets/javascripts/vue_shared/components/members/table/member_avatar.vue b/app/assets/javascripts/vue_shared/components/members/table/member_avatar.vue
new file mode 100644
index 00000000000..a1f98d4008a
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/members/table/member_avatar.vue
@@ -0,0 +1,35 @@
+<script>
+import { kebabCase } from 'lodash';
+import UserAvatar from '../avatars/user_avatar.vue';
+import InviteAvatar from '../avatars/invite_avatar.vue';
+import GroupAvatar from '../avatars/group_avatar.vue';
+
+export default {
+ name: 'MemberAvatar',
+ components: { UserAvatar, InviteAvatar, GroupAvatar, AccessRequestAvatar: UserAvatar },
+ props: {
+ memberType: {
+ type: String,
+ required: true,
+ },
+ isCurrentUser: {
+ type: Boolean,
+ required: true,
+ },
+ member: {
+ type: Object,
+ required: true,
+ },
+ },
+ computed: {
+ avatarComponent() {
+ // eslint-disable-next-line @gitlab/require-i18n-strings
+ return `${kebabCase(this.memberType)}-avatar`;
+ },
+ },
+};
+</script>
+
+<template>
+ <component :is="avatarComponent" :member="member" :is-current-user="isCurrentUser" />
+</template>
diff --git a/app/assets/javascripts/vue_shared/components/members/table/member_source.vue b/app/assets/javascripts/vue_shared/components/members/table/member_source.vue
new file mode 100644
index 00000000000..030d72c3420
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/members/table/member_source.vue
@@ -0,0 +1,27 @@
+<script>
+import { GlTooltipDirective } from '@gitlab/ui';
+
+export default {
+ name: 'MemberSource',
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ },
+ props: {
+ memberSource: {
+ type: Object,
+ required: true,
+ },
+ isDirectMember: {
+ type: Boolean,
+ required: true,
+ },
+ },
+};
+</script>
+
+<template>
+ <span v-if="isDirectMember">{{ __('Direct member') }}</span>
+ <a v-else v-gl-tooltip.hover :title="__('Inherited')" :href="memberSource.webUrl">{{
+ memberSource.name
+ }}</a>
+</template>
diff --git a/app/assets/javascripts/vue_shared/components/members/table/members_table.vue b/app/assets/javascripts/vue_shared/components/members/table/members_table.vue
new file mode 100644
index 00000000000..c1a80a85dbe
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/members/table/members_table.vue
@@ -0,0 +1,110 @@
+<script>
+import { mapState } from 'vuex';
+import { GlTable, GlBadge } from '@gitlab/ui';
+import { FIELDS } from '../constants';
+import initUserPopovers from '~/user_popovers';
+import MemberAvatar from './member_avatar.vue';
+import MemberSource from './member_source.vue';
+import CreatedAt from './created_at.vue';
+import ExpiresAt from './expires_at.vue';
+import MemberActionButtons from './member_action_buttons.vue';
+import MembersTableCell from './members_table_cell.vue';
+import RoleDropdown from './role_dropdown.vue';
+import RemoveGroupLinkModal from '../modals/remove_group_link_modal.vue';
+
+export default {
+ name: 'MembersTable',
+ components: {
+ GlTable,
+ GlBadge,
+ MemberAvatar,
+ CreatedAt,
+ ExpiresAt,
+ MembersTableCell,
+ MemberSource,
+ MemberActionButtons,
+ RoleDropdown,
+ RemoveGroupLinkModal,
+ },
+ computed: {
+ ...mapState(['members', 'tableFields']),
+ filteredFields() {
+ return FIELDS.filter(field => this.tableFields.includes(field.key));
+ },
+ },
+ mounted() {
+ initUserPopovers(this.$el.querySelectorAll('.js-user-link'));
+ },
+};
+</script>
+
+<template>
+ <div>
+ <gl-table
+ class="members-table"
+ head-variant="white"
+ stacked="lg"
+ :fields="filteredFields"
+ :items="members"
+ primary-key="id"
+ thead-class="border-bottom"
+ :empty-text="__('No members found')"
+ show-empty
+ >
+ <template #cell(account)="{ item: member }">
+ <members-table-cell #default="{ memberType, isCurrentUser }" :member="member">
+ <member-avatar
+ :member-type="memberType"
+ :is-current-user="isCurrentUser"
+ :member="member"
+ />
+ </members-table-cell>
+ </template>
+
+ <template #cell(source)="{ item: member }">
+ <members-table-cell #default="{ isDirectMember }" :member="member">
+ <member-source :is-direct-member="isDirectMember" :member-source="member.source" />
+ </members-table-cell>
+ </template>
+
+ <template #cell(granted)="{ item: { createdAt, createdBy } }">
+ <created-at :date="createdAt" :created-by="createdBy" />
+ </template>
+
+ <template #cell(invited)="{ item: { createdAt, createdBy } }">
+ <created-at :date="createdAt" :created-by="createdBy" />
+ </template>
+
+ <template #cell(requested)="{ item: { createdAt } }">
+ <created-at :date="createdAt" />
+ </template>
+
+ <template #cell(expires)="{ item: { expiresAt } }">
+ <expires-at :date="expiresAt" />
+ </template>
+
+ <template #cell(maxRole)="{ item: member }">
+ <members-table-cell #default="{ permissions }" :member="member">
+ <role-dropdown v-if="permissions.canUpdate" :member="member" />
+ <gl-badge v-else>{{ member.accessLevel.stringValue }}</gl-badge>
+ </members-table-cell>
+ </template>
+
+ <template #cell(actions)="{ item: member }">
+ <members-table-cell #default="{ memberType, isCurrentUser, permissions }" :member="member">
+ <member-action-buttons
+ :member-type="memberType"
+ :is-current-user="isCurrentUser"
+ :permissions="permissions"
+ :member="member"
+ />
+ </members-table-cell>
+ </template>
+
+ <template #head(actions)="{ label }">
+ <span data-testid="col-actions" class="gl-sr-only">{{ label }}</span>
+ </template>
+ </gl-table>
+ <remove-group-link-modal />
+ </div>
+</template>
diff --git a/app/assets/javascripts/vue_shared/components/members/table/members_table_cell.vue b/app/assets/javascripts/vue_shared/components/members/table/members_table_cell.vue
new file mode 100644
index 00000000000..5602978bb6c
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/members/table/members_table_cell.vue
@@ -0,0 +1,64 @@
+<script>
+import { mapState } from 'vuex';
+import { MEMBER_TYPES } from '../constants';
+
+export default {
+ name: 'MembersTableCell',
+ props: {
+ member: {
+ type: Object,
+ required: true,
+ },
+ },
+ computed: {
+ ...mapState(['sourceId', 'currentUserId']),
+ isGroup() {
+ return Boolean(this.member.sharedWithGroup);
+ },
+ isInvite() {
+ return Boolean(this.member.invite);
+ },
+ isAccessRequest() {
+ return Boolean(this.member.requestedAt);
+ },
+ memberType() {
+ if (this.isGroup) {
+ return MEMBER_TYPES.group;
+ } else if (this.isInvite) {
+ return MEMBER_TYPES.invite;
+ } else if (this.isAccessRequest) {
+ return MEMBER_TYPES.accessRequest;
+ }
+
+ return MEMBER_TYPES.user;
+ },
+ isDirectMember() {
+ return this.isGroup || this.member.source?.id === this.sourceId;
+ },
+ isCurrentUser() {
+ return this.member.user?.id === this.currentUserId;
+ },
+ canRemove() {
+ return this.isDirectMember && this.member.canRemove;
+ },
+ canResend() {
+ return Boolean(this.member.invite?.canResend);
+ },
+ canUpdate() {
+ return !this.isCurrentUser && this.isDirectMember && this.member.canUpdate;
+ },
+ },
+ render() {
+ return this.$scopedSlots.default({
+ memberType: this.memberType,
+ isDirectMember: this.isDirectMember,
+ isCurrentUser: this.isCurrentUser,
+ permissions: {
+ canRemove: this.canRemove,
+ canResend: this.canResend,
+ canUpdate: this.canUpdate,
+ },
+ });
+ },
+};
+</script>
diff --git a/app/assets/javascripts/vue_shared/components/members/table/role_dropdown.vue b/app/assets/javascripts/vue_shared/components/members/table/role_dropdown.vue
new file mode 100644
index 00000000000..2b40ccc3a9d
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/members/table/role_dropdown.vue
@@ -0,0 +1,70 @@
+<script>
+import { GlDropdown, GlDropdownItem } from '@gitlab/ui';
+import { GlBreakpointInstance as bp } from '@gitlab/ui/dist/utils';
+import { mapActions } from 'vuex';
+import { s__ } from '~/locale';
+
+export default {
+ name: 'RoleDropdown',
+ components: {
+ GlDropdown,
+ GlDropdownItem,
+ },
+ props: {
+ member: {
+ type: Object,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ isDesktop: false,
+ busy: false,
+ };
+ },
+ mounted() {
+ this.isDesktop = bp.isDesktop();
+ },
+ methods: {
+ ...mapActions(['updateMemberRole']),
+ handleSelect(value, name) {
+ if (value === this.member.accessLevel.integerValue) {
+ return;
+ }
+
+ this.busy = true;
+
+ this.updateMemberRole({
+ memberId: this.member.id,
+ accessLevel: { integerValue: value, stringValue: name },
+ })
+ .then(() => {
+ this.$toast.show(s__('Members|Role updated successfully.'));
+ this.busy = false;
+ })
+ .catch(() => {
+ this.busy = false;
+ });
+ },
+ },
+};
+</script>
+
+<template>
+ <gl-dropdown
+ :right="!isDesktop"
+ :text="member.accessLevel.stringValue"
+ :header-text="__('Change permissions')"
+ :disabled="busy"
+ >
+ <gl-dropdown-item
+ v-for="(value, name) in member.validRoles"
+ :key="value"
+ is-check-item
+ :is-checked="value === member.accessLevel.integerValue"
+ @click="handleSelect(value, name)"
+ >
+ {{ name }}
+ </gl-dropdown-item>
+ </gl-dropdown>
+</template>
diff --git a/app/assets/javascripts/vue_shared/components/members/utils.js b/app/assets/javascripts/vue_shared/components/members/utils.js
new file mode 100644
index 00000000000..782a0b7f96b
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/members/utils.js
@@ -0,0 +1,19 @@
+import { __ } from '~/locale';
+
+export const generateBadges = (member, isCurrentUser) => [
+ {
+ show: isCurrentUser,
+ text: __("It's you"),
+ variant: 'success',
+ },
+ {
+ show: member.user?.blocked,
+ text: __('Blocked'),
+ variant: 'danger',
+ },
+ {
+ show: member.user?.twoFactorEnabled,
+ text: __('2FA'),
+ variant: 'info',
+ },
+];
diff --git a/app/assets/javascripts/vue_shared/components/modal_copy_button.vue b/app/assets/javascripts/vue_shared/components/modal_copy_button.vue
index 35ba7c665d5..cad4439ecea 100644
--- a/app/assets/javascripts/vue_shared/components/modal_copy_button.vue
+++ b/app/assets/javascripts/vue_shared/components/modal_copy_button.vue
@@ -1,19 +1,16 @@
<script>
import $ from 'jquery';
-import { GlDeprecatedButton, GlTooltipDirective, GlIcon } from '@gitlab/ui';
+import { GlButton, GlTooltipDirective } from '@gitlab/ui';
import Clipboard from 'clipboard';
import { __ } from '~/locale';
export default {
components: {
- GlDeprecatedButton,
- GlIcon,
+ GlButton,
},
-
directives: {
GlTooltip: GlTooltipDirective,
},
-
props: {
text: {
type: String,
@@ -55,15 +52,12 @@ export default {
default: null,
},
},
-
copySuccessText: __('Copied'),
-
computed: {
modalDomId() {
return this.modalId ? `#${this.modalId}` : '';
},
},
-
mounted() {
this.$nextTick(() => {
this.clipboard = new Clipboard(this.$el, {
@@ -83,13 +77,11 @@ export default {
.on('error', e => this.$emit('error', e));
});
},
-
destroyed() {
if (this.clipboard) {
this.clipboard.destroy();
}
},
-
methods: {
updateTooltip(target) {
const $target = $(target);
@@ -112,15 +104,12 @@ export default {
};
</script>
<template>
- <gl-deprecated-button
+ <gl-button
v-gl-tooltip="{ placement: tooltipPlacement, container: tooltipContainer }"
:class="cssClasses"
:data-clipboard-target="target"
:data-clipboard-text="text"
:title="title"
- >
- <slot>
- <gl-icon name="copy-to-clipboard" />
- </slot>
- </gl-deprecated-button>
+ icon="copy-to-clipboard"
+ />
</template>
diff --git a/app/assets/javascripts/vue_shared/components/navigation_tabs.vue b/app/assets/javascripts/vue_shared/components/navigation_tabs.vue
index f8983a3d29a..3749888ee36 100644
--- a/app/assets/javascripts/vue_shared/components/navigation_tabs.vue
+++ b/app/assets/javascripts/vue_shared/components/navigation_tabs.vue
@@ -58,7 +58,12 @@ export default {
active: tab.isActive,
}"
>
- <a :class="`js-${scope}-tab-${tab.scope}`" role="button" @click="onTabClick(tab)">
+ <a
+ :class="`js-${scope}-tab-${tab.scope}`"
+ :data-testid="`${scope}-tab-${tab.scope}`"
+ role="button"
+ @click="onTabClick(tab)"
+ >
{{ tab.name }}
<span v-if="shouldRenderBadge(tab.count)" class="badge badge-pill"> {{ tab.count }} </span>
diff --git a/app/assets/javascripts/vue_shared/components/notes/skeleton_note.vue b/app/assets/javascripts/vue_shared/components/notes/skeleton_note.vue
index 53dbae39608..3aca068c074 100644
--- a/app/assets/javascripts/vue_shared/components/notes/skeleton_note.vue
+++ b/app/assets/javascripts/vue_shared/components/notes/skeleton_note.vue
@@ -12,7 +12,7 @@ export default {
</script>
<template>
- <timeline-entry-item class="note note-wrapper" data-qa-selector="skeleton_note">
+ <timeline-entry-item class="note note-wrapper" data-qa-selector="skeleton_note_placeholder">
<div class="timeline-icon"></div>
<div class="timeline-content">
<div class="note-header"></div>
diff --git a/app/assets/javascripts/vue_shared/components/paginated_table_with_search_and_tabs/constants.js b/app/assets/javascripts/vue_shared/components/paginated_table_with_search_and_tabs/constants.js
new file mode 100644
index 00000000000..b7768cfa5b9
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/paginated_table_with_search_and_tabs/constants.js
@@ -0,0 +1,21 @@
+import { __ } from '~/locale';
+
+export const tdClass =
+ 'table-col gl-display-flex d-md-table-cell gl-align-items-center gl-white-space-nowrap';
+export const thClass = 'gl-hover-bg-blue-50';
+export const bodyTrClass =
+ 'gl-border-1 gl-border-t-solid gl-border-gray-100 gl-hover-cursor-pointer gl-hover-bg-blue-50 gl-hover-border-b-solid gl-hover-border-blue-200';
+
+export const defaultPageSize = 20;
+
+export const initialPaginationState = {
+ page: 1,
+ prevPageCursor: '',
+ nextPageCursor: '',
+ firstPageSize: defaultPageSize,
+ lastPageSize: null,
+};
+
+export const defaultI18n = {
+ searchPlaceholder: __('Search or filter results…'),
+};
diff --git a/app/assets/javascripts/vue_shared/components/paginated_table_with_search_and_tabs/paginated_table_with_search_and_tabs.vue b/app/assets/javascripts/vue_shared/components/paginated_table_with_search_and_tabs/paginated_table_with_search_and_tabs.vue
new file mode 100644
index 00000000000..8e85d93e6d1
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/paginated_table_with_search_and_tabs/paginated_table_with_search_and_tabs.vue
@@ -0,0 +1,313 @@
+<script>
+import { GlAlert, GlBadge, GlPagination, GlTab, GlTabs } from '@gitlab/ui';
+import Api from '~/api';
+import Tracking from '~/tracking';
+import { __ } from '~/locale';
+import { updateHistory, setUrlParams } from '~/lib/utils/url_utility';
+import { initialPaginationState, defaultI18n, defaultPageSize } from './constants';
+import { isAny } from './utils';
+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';
+
+export default {
+ defaultI18n,
+ components: {
+ GlAlert,
+ GlBadge,
+ GlPagination,
+ GlTabs,
+ GlTab,
+ FilteredSearchBar,
+ },
+ inject: {
+ projectPath: {
+ default: '',
+ },
+ textQuery: {
+ default: '',
+ },
+ assigneeUsernameQuery: {
+ default: '',
+ },
+ authorUsernameQuery: {
+ default: '',
+ },
+ },
+ props: {
+ items: {
+ type: Array,
+ required: true,
+ },
+ itemsCount: {
+ type: Object,
+ required: false,
+ default: () => {},
+ },
+ pageInfo: {
+ type: Object,
+ required: false,
+ default: () => {},
+ },
+ statusTabs: {
+ type: Array,
+ required: true,
+ },
+ showItems: {
+ type: Boolean,
+ required: false,
+ default: true,
+ },
+ showErrorMsg: {
+ type: Boolean,
+ required: true,
+ },
+ trackViewsOptions: {
+ type: Object,
+ required: true,
+ },
+ i18n: {
+ type: Object,
+ required: true,
+ },
+ serverErrorMessage: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ filterSearchKey: {
+ type: String,
+ required: true,
+ },
+ filterSearchTokens: {
+ type: Array,
+ required: false,
+ default: () => ['author_username', 'assignee_username'],
+ },
+ },
+ data() {
+ return {
+ searchTerm: this.textQuery,
+ authorUsername: this.authorUsernameQuery,
+ assigneeUsername: this.assigneeUsernameQuery,
+ filterParams: {},
+ pagination: initialPaginationState,
+ filteredByStatus: '',
+ statusFilter: '',
+ };
+ },
+ computed: {
+ defaultTokens() {
+ return [
+ {
+ type: 'author_username',
+ icon: 'user',
+ title: __('Author'),
+ unique: true,
+ symbol: '@',
+ token: AuthorToken,
+ operators: [{ value: '=', description: __('is'), default: 'true' }],
+ fetchPath: this.projectPath,
+ fetchAuthors: Api.projectUsers.bind(Api),
+ },
+ {
+ type: 'assignee_username',
+ icon: 'user',
+ title: __('Assignee'),
+ unique: true,
+ symbol: '@',
+ token: AuthorToken,
+ operators: [{ value: '=', description: __('is'), default: 'true' }],
+ fetchPath: this.projectPath,
+ fetchAuthors: Api.projectUsers.bind(Api),
+ },
+ ];
+ },
+ filteredSearchTokens() {
+ return this.defaultTokens.filter(({ type }) => this.filterSearchTokens.includes(type));
+ },
+ filteredSearchValue() {
+ const value = [];
+
+ if (this.authorUsername) {
+ value.push({
+ type: 'author_username',
+ value: { data: this.authorUsername },
+ });
+ }
+
+ if (this.assigneeUsername) {
+ value.push({
+ type: 'assignee_username',
+ value: { data: this.assigneeUsername },
+ });
+ }
+
+ if (this.searchTerm) {
+ value.push(this.searchTerm);
+ }
+
+ return value;
+ },
+ itemsForCurrentTab() {
+ return this.itemsCount?.[this.filteredByStatus.toLowerCase()] ?? 0;
+ },
+ showPaginationControls() {
+ return Boolean(this.pageInfo?.hasNextPage || this.pageInfo?.hasPreviousPage);
+ },
+ previousPage() {
+ return Math.max(this.pagination.page - 1, 0);
+ },
+ nextPage() {
+ const nextPage = this.pagination.page + 1;
+ return nextPage > Math.ceil(this.itemsForCurrentTab / defaultPageSize) ? null : nextPage;
+ },
+ },
+ mounted() {
+ this.trackPageViews();
+ },
+ methods: {
+ filterItemsByStatus(tabIndex) {
+ this.resetPagination();
+ const { filters, status } = this.statusTabs[tabIndex];
+ this.statusFilter = filters;
+ this.filteredByStatus = status;
+
+ this.$emit('tabs-changed', { filters, status });
+ },
+ handlePageChange(page) {
+ const { startCursor, endCursor } = this.pageInfo;
+
+ if (page > this.pagination.page) {
+ this.pagination = {
+ ...initialPaginationState,
+ nextPageCursor: endCursor,
+ page,
+ };
+ } else {
+ this.pagination = {
+ lastPageSize: defaultPageSize,
+ firstPageSize: null,
+ prevPageCursor: startCursor,
+ nextPageCursor: '',
+ page,
+ };
+ }
+
+ this.$emit('page-changed', this.pagination);
+ },
+ resetPagination() {
+ this.pagination = initialPaginationState;
+ this.$emit('page-changed', this.pagination);
+ },
+ handleFilterItems(filters) {
+ this.resetPagination();
+ const filterParams = { authorUsername: '', assigneeUsername: '', search: '' };
+
+ filters.forEach(filter => {
+ if (typeof filter === 'object') {
+ switch (filter.type) {
+ case 'author_username':
+ filterParams.authorUsername = isAny(filter.value.data);
+ break;
+ case 'assignee_username':
+ filterParams.assigneeUsername = isAny(filter.value.data);
+ break;
+ case 'filtered-search-term':
+ if (filter.value.data !== '') filterParams.search = filter.value.data;
+ break;
+ default:
+ break;
+ }
+ }
+ });
+
+ this.filterParams = filterParams;
+ this.updateUrl();
+ this.searchTerm = filterParams?.search;
+ this.authorUsername = filterParams?.authorUsername;
+ this.assigneeUsername = filterParams?.assigneeUsername;
+
+ this.$emit('filters-changed', {
+ searchTerm: this.searchTerm,
+ authorUsername: this.authorUsername,
+ assigneeUsername: this.assigneeUsername,
+ });
+ },
+ updateUrl() {
+ const { authorUsername, assigneeUsername, search } = this.filterParams || {};
+
+ const params = {
+ ...(authorUsername !== '' && { author_username: authorUsername }),
+ ...(assigneeUsername !== '' && { assignee_username: assigneeUsername }),
+ ...(search !== '' && { search }),
+ };
+
+ updateHistory({
+ url: setUrlParams(params, window.location.href, true),
+ title: document.title,
+ replace: true,
+ });
+ },
+ trackPageViews() {
+ const { category, action } = this.trackViewsOptions;
+ Tracking.event(category, action);
+ },
+ },
+};
+</script>
+<template>
+ <div class="incident-management-list">
+ <gl-alert v-if="showErrorMsg" variant="danger" @dismiss="$emit('error-alert-dismissed')">
+ <!-- eslint-disable-next-line vue/no-v-html -->
+ <p v-html="serverErrorMessage || i18n.errorMsg"></p>
+ </gl-alert>
+
+ <div
+ class="list-header gl-display-flex gl-justify-content-space-between gl-border-b-solid gl-border-b-1 gl-border-gray-100"
+ >
+ <gl-tabs content-class="gl-p-0" @input="filterItemsByStatus">
+ <gl-tab v-for="tab in statusTabs" :key="tab.status" :data-testid="tab.status">
+ <template #title>
+ <span>{{ tab.title }}</span>
+ <gl-badge v-if="itemsCount" pill size="sm" class="gl-tab-counter-badge">
+ {{ itemsCount[tab.status.toLowerCase()] }}
+ </gl-badge>
+ </template>
+ </gl-tab>
+ </gl-tabs>
+
+ <slot name="header-actions"></slot>
+ </div>
+
+ <div class="filtered-search-wrapper">
+ <filtered-search-bar
+ :namespace="projectPath"
+ :search-input-placeholder="$options.defaultI18n.searchPlaceholder"
+ :tokens="filteredSearchTokens"
+ :initial-filter-value="filteredSearchValue"
+ initial-sortby="created_desc"
+ :recent-searches-storage-key="filterSearchKey"
+ class="row-content-block"
+ @onFilter="handleFilterItems"
+ />
+ </div>
+
+ <h4 class="gl-display-block d-md-none my-3">
+ <slot name="title"></slot>
+ </h4>
+
+ <slot v-if="showItems" name="table"></slot>
+
+ <gl-pagination
+ v-if="showPaginationControls"
+ :value="pagination.page"
+ :prev-page="previousPage"
+ :next-page="nextPage"
+ align="center"
+ class="gl-pagination gl-mt-3"
+ @input="handlePageChange"
+ />
+
+ <slot v-if="!showItems" name="emtpy-state"></slot>
+ </div>
+</template>
diff --git a/app/assets/javascripts/vue_shared/components/paginated_table_with_search_and_tabs/utils.js b/app/assets/javascripts/vue_shared/components/paginated_table_with_search_and_tabs/utils.js
new file mode 100644
index 00000000000..7de4263acbb
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/paginated_table_with_search_and_tabs/utils.js
@@ -0,0 +1,11 @@
+import { __ } from '~/locale';
+
+/**
+ * Return a empty string when passed a value of 'Any'
+ *
+ * @param {String} value
+ * @returns {String}
+ */
+export const isAny = value => {
+ return value === __('Any') ? '' : value;
+};
diff --git a/app/assets/javascripts/vue_shared/components/registry/list_item.vue b/app/assets/javascripts/vue_shared/components/registry/list_item.vue
index 50a19dc2156..7046ac5be03 100644
--- a/app/assets/javascripts/vue_shared/components/registry/list_item.vue
+++ b/app/assets/javascripts/vue_shared/components/registry/list_item.vue
@@ -39,7 +39,7 @@ export default {
},
},
mounted() {
- this.detailsSlots = Object.keys(this.$slots).filter(k => k.startsWith('details_'));
+ this.detailsSlots = Object.keys(this.$slots).filter(k => k.startsWith('details-'));
},
methods: {
toggleDetails() {
diff --git a/app/assets/javascripts/vue_shared/components/registry/title_area.vue b/app/assets/javascripts/vue_shared/components/registry/title_area.vue
index cc33b8f85cd..06b4309ad42 100644
--- a/app/assets/javascripts/vue_shared/components/registry/title_area.vue
+++ b/app/assets/javascripts/vue_shared/components/registry/title_area.vue
@@ -1,10 +1,12 @@
<script>
-import { GlAvatar } from '@gitlab/ui';
+import { GlAvatar, GlSprintf, GlLink } from '@gitlab/ui';
export default {
name: 'TitleArea',
components: {
GlAvatar,
+ GlSprintf,
+ GlLink,
},
props: {
avatar: {
@@ -17,6 +19,11 @@ export default {
default: null,
required: false,
},
+ infoMessages: {
+ type: Array,
+ default: () => [],
+ required: false,
+ },
},
data() {
return {
@@ -24,43 +31,64 @@ export default {
};
},
mounted() {
- this.metadataSlots = Object.keys(this.$slots).filter(k => k.startsWith('metadata_'));
+ this.metadataSlots = Object.keys(this.$slots).filter(k => k.startsWith('metadata-'));
},
};
</script>
<template>
- <div class="gl-display-flex gl-justify-content-space-between gl-py-3">
- <div class="gl-flex-direction-column">
- <div class="gl-display-flex">
- <gl-avatar v-if="avatar" :src="avatar" shape="rect" class="gl-align-self-center gl-mr-4" />
+ <div class="gl-display-flex gl-flex-direction-column">
+ <div class="gl-display-flex gl-justify-content-space-between gl-py-3">
+ <div class="gl-flex-direction-column">
+ <div class="gl-display-flex">
+ <gl-avatar
+ v-if="avatar"
+ :src="avatar"
+ shape="rect"
+ class="gl-align-self-center gl-mr-4"
+ />
- <div class="gl-display-flex gl-flex-direction-column">
- <h1 class="gl-font-size-h1 gl-mt-3 gl-mb-2" data-testid="title">
- <slot name="title">{{ title }}</slot>
- </h1>
+ <div class="gl-display-flex gl-flex-direction-column">
+ <h1 class="gl-font-size-h1 gl-mt-3 gl-mb-2" data-testid="title">
+ <slot name="title">{{ title }}</slot>
+ </h1>
+
+ <div
+ v-if="$slots['sub-header']"
+ class="gl-display-flex gl-align-items-center gl-text-gray-500 gl-mt-1"
+ >
+ <slot name="sub-header"></slot>
+ </div>
+ </div>
+ </div>
+ <div class="gl-display-flex gl-flex-wrap gl-align-items-center gl-mt-3">
<div
- v-if="$slots['sub-header']"
- class="gl-display-flex gl-align-items-center gl-text-gray-500 gl-mt-1"
+ v-for="(row, metadataIndex) in metadataSlots"
+ :key="metadataIndex"
+ class="gl-display-flex gl-align-items-center gl-mr-5"
>
- <slot name="sub-header"></slot>
+ <slot :name="row"></slot>
</div>
</div>
</div>
-
- <div class="gl-display-flex gl-flex-wrap gl-align-items-center gl-mt-3">
- <div
- v-for="(row, metadataIndex) in metadataSlots"
- :key="metadataIndex"
- class="gl-display-flex gl-align-items-center gl-mr-5"
- >
- <slot :name="row"></slot>
- </div>
+ <div v-if="$slots['right-actions']" class="gl-mt-3">
+ <slot name="right-actions"></slot>
</div>
</div>
- <div v-if="$slots['right-actions']" class="gl-mt-3">
- <slot name="right-actions"></slot>
- </div>
+ <p>
+ <span
+ v-for="(message, index) in infoMessages"
+ :key="index"
+ class="gl-mr-2"
+ data-testid="info-message"
+ >
+ <gl-sprintf :message="message.text">
+ <template #docLink="{content}">
+ <gl-link :href="message.link" target="_blank">{{ content }}</gl-link>
+ </template>
+ </gl-sprintf>
+ </span>
+ </p>
</div>
</template>
diff --git a/app/assets/javascripts/vue_shared/components/rich_content_editor/constants.js b/app/assets/javascripts/vue_shared/components/rich_content_editor/constants.js
index c08659919fa..cbb30baa488 100644
--- a/app/assets/javascripts/vue_shared/components/rich_content_editor/constants.js
+++ b/app/assets/javascripts/vue_shared/components/rich_content_editor/constants.js
@@ -2,8 +2,15 @@ import { __ } from '~/locale';
export const CUSTOM_EVENTS = {
openAddImageModal: 'gl_openAddImageModal',
+ openInsertVideoModal: 'gl_openInsertVideoModal',
};
+export const YOUTUBE_URL = 'https://www.youtube.com';
+
+export const YOUTUBE_EMBED_URL = `${YOUTUBE_URL}/embed`;
+
+export const ALLOWED_VIDEO_ORIGINS = [YOUTUBE_URL];
+
/* eslint-disable @gitlab/require-i18n-strings */
export const TOOLBAR_ITEM_CONFIGS = [
{ icon: 'heading', event: 'openHeadingSelect', classes: 'tui-heading', tooltip: __('Headings') },
@@ -23,6 +30,7 @@ export const TOOLBAR_ITEM_CONFIGS = [
{ icon: 'dash', command: 'HR', tooltip: __('Add a line') },
{ icon: 'table', event: 'openPopupAddTable', classes: 'tui-table', tooltip: __('Add a table') },
{ icon: 'doc-image', event: CUSTOM_EVENTS.openAddImageModal, tooltip: __('Insert an image') },
+ { icon: 'live-preview', event: CUSTOM_EVENTS.openInsertVideoModal, tooltip: __('Insert video') },
{ isDivider: true },
{ icon: 'code', command: 'Code', tooltip: __('Insert inline code') },
{ icon: 'doc-code', command: 'CodeBlock', tooltip: __('Insert a code block') },
@@ -40,3 +48,10 @@ export const EDITOR_PREVIEW_STYLE = 'horizontal';
export const IMAGE_TABS = { UPLOAD_TAB: 0, URL_TAB: 1 };
export const MAX_FILE_SIZE = 2097152; // 2Mb
+
+export const VIDEO_ATTRIBUTES = {
+ width: '560',
+ height: '315',
+ frameBorder: '0',
+ allow: 'accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture',
+};
diff --git a/app/assets/javascripts/vue_shared/components/rich_content_editor/modals/add_image/add_image_modal.vue b/app/assets/javascripts/vue_shared/components/rich_content_editor/modals/add_image/add_image_modal.vue
index 429a4e04110..e1652f54982 100644
--- a/app/assets/javascripts/vue_shared/components/rich_content_editor/modals/add_image/add_image_modal.vue
+++ b/app/assets/javascripts/vue_shared/components/rich_content_editor/modals/add_image/add_image_modal.vue
@@ -32,8 +32,8 @@ export default {
uploadImageTab: null,
};
},
- modalTitle: __('Image Details'),
- okTitle: __('Insert'),
+ modalTitle: __('Image details'),
+ okTitle: __('Insert image'),
urlTabTitle: __('By URL'),
urlLabel: __('Image URL'),
descriptionLabel: __('Description'),
diff --git a/app/assets/javascripts/vue_shared/components/rich_content_editor/modals/insert_video_modal.vue b/app/assets/javascripts/vue_shared/components/rich_content_editor/modals/insert_video_modal.vue
new file mode 100644
index 00000000000..99bb2080610
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/rich_content_editor/modals/insert_video_modal.vue
@@ -0,0 +1,91 @@
+<script>
+import { GlModal, GlFormGroup, GlFormInput, GlSprintf } from '@gitlab/ui';
+import { isSafeURL } from '~/lib/utils/url_utility';
+import { __ } from '~/locale';
+import { YOUTUBE_URL, YOUTUBE_EMBED_URL } from '../constants';
+
+export default {
+ components: {
+ GlModal,
+ GlFormGroup,
+ GlFormInput,
+ GlSprintf,
+ },
+ data() {
+ return {
+ url: null,
+ urlError: null,
+ description: __(
+ 'If the YouTube URL is https://www.youtube.com/watch?v=0t1DgySidms then the video ID is %{id}',
+ ),
+ };
+ },
+ modalTitle: __('Insert a video'),
+ okTitle: __('Insert video'),
+ label: __('YouTube URL or ID'),
+ methods: {
+ show() {
+ this.urlError = null;
+ this.url = null;
+
+ this.$refs.modal.show();
+ },
+ onPrimary(event) {
+ this.submitURL(event);
+ },
+ submitURL(event) {
+ const url = this.generateUrl();
+
+ if (!url) {
+ event.preventDefault();
+ return;
+ }
+
+ this.$emit('insertVideo', url);
+ },
+ generateUrl() {
+ let { url } = this;
+ const reYouTubeId = /^[A-z0-9]*$/;
+ const reYouTubeUrl = RegExp(`${YOUTUBE_URL}/(embed/|watch\\?v=)([A-z0-9]+)`);
+
+ if (reYouTubeId.test(url)) {
+ url = `${YOUTUBE_EMBED_URL}/${url}`;
+ } else if (reYouTubeUrl.test(url)) {
+ url = `${YOUTUBE_EMBED_URL}/${reYouTubeUrl.exec(url)[2]}`;
+ }
+
+ if (!isSafeURL(url) || !reYouTubeUrl.test(url)) {
+ this.urlError = __('Please provide a valid YouTube URL or ID');
+ this.$refs.urlInput.$el.focus();
+ return null;
+ }
+
+ return url;
+ },
+ },
+};
+</script>
+<template>
+ <gl-modal
+ ref="modal"
+ size="sm"
+ modal-id="insert-video-modal"
+ :title="$options.modalTitle"
+ :ok-title="$options.okTitle"
+ @primary="onPrimary"
+ >
+ <gl-form-group
+ :label="$options.label"
+ label-for="video-modal-url-input"
+ :state="!Boolean(urlError)"
+ :invalid-feedback="urlError"
+ >
+ <gl-form-input id="video-modal-url-input" ref="urlInput" v-model="url" />
+ <gl-sprintf slot="description" :message="description" class="text-gl-muted">
+ <template #id>
+ <strong>{{ __('0t1DgySidms') }}</strong>
+ </template>
+ </gl-sprintf>
+ </gl-form-group>
+ </gl-modal>
+</template>
diff --git a/app/assets/javascripts/vue_shared/components/rich_content_editor/rich_content_editor.vue b/app/assets/javascripts/vue_shared/components/rich_content_editor/rich_content_editor.vue
index d96fe46522e..c2518441506 100644
--- a/app/assets/javascripts/vue_shared/components/rich_content_editor/rich_content_editor.vue
+++ b/app/assets/javascripts/vue_shared/components/rich_content_editor/rich_content_editor.vue
@@ -3,6 +3,7 @@ import 'codemirror/lib/codemirror.css';
import '@toast-ui/editor/dist/toastui-editor.css';
import AddImageModal from './modals/add_image/add_image_modal.vue';
+import InsertVideoModal from './modals/insert_video_modal.vue';
import { EDITOR_TYPES, EDITOR_HEIGHT, EDITOR_PREVIEW_STYLE, CUSTOM_EVENTS } from './constants';
import {
@@ -12,6 +13,7 @@ import {
removeCustomEventListener,
addImage,
getMarkdown,
+ insertVideo,
} from './services/editor_service';
export default {
@@ -21,6 +23,7 @@ export default {
toast => toast.Editor,
),
AddImageModal,
+ InsertVideoModal,
},
props: {
content: {
@@ -63,6 +66,12 @@ export default {
editorInstance() {
return this.$refs.editor;
},
+ customEventListeners() {
+ return [
+ { event: CUSTOM_EVENTS.openAddImageModal, listener: this.onOpenAddImageModal },
+ { event: CUSTOM_EVENTS.openInsertVideoModal, listener: this.onOpenInsertVideoModal },
+ ];
+ },
},
created() {
this.editorOptions = getEditorOptions(this.options);
@@ -72,16 +81,16 @@ export default {
},
methods: {
addListeners(editorApi) {
- addCustomEventListener(editorApi, CUSTOM_EVENTS.openAddImageModal, this.onOpenAddImageModal);
+ this.customEventListeners.forEach(({ event, listener }) => {
+ addCustomEventListener(editorApi, event, listener);
+ });
editorApi.eventManager.listen('changeMode', this.onChangeMode);
},
removeListeners() {
- removeCustomEventListener(
- this.editorApi,
- CUSTOM_EVENTS.openAddImageModal,
- this.onOpenAddImageModal,
- );
+ this.customEventListeners.forEach(({ event, listener }) => {
+ removeCustomEventListener(this.editorApi, event, listener);
+ });
this.editorApi.eventManager.removeEventHandler('changeMode', this.onChangeMode);
},
@@ -111,6 +120,12 @@ export default {
addImage(this.editorInstance, image);
},
+ onOpenInsertVideoModal() {
+ this.$refs.insertVideoModal.show();
+ },
+ onInsertVideo(url) {
+ insertVideo(this.editorInstance, url);
+ },
onChangeMode(newMode) {
this.$emit('modeChange', newMode);
},
@@ -130,5 +145,6 @@ export default {
@load="onLoad"
/>
<add-image-modal ref="addImageModal" :image-root="imageRoot" @addImage="onAddImage" />
+ <insert-video-modal ref="insertVideoModal" @insertVideo="onInsertVideo" />
</div>
</template>
diff --git a/app/assets/javascripts/vue_shared/components/rich_content_editor/services/editor_service.js b/app/assets/javascripts/vue_shared/components/rich_content_editor/services/editor_service.js
index 51ba033dff0..8b3fbcabcfa 100644
--- a/app/assets/javascripts/vue_shared/components/rich_content_editor/services/editor_service.js
+++ b/app/assets/javascripts/vue_shared/components/rich_content_editor/services/editor_service.js
@@ -3,7 +3,8 @@ import { defaults } from 'lodash';
import ToolbarItem from '../toolbar_item.vue';
import buildHtmlToMarkdownRenderer from './build_html_to_markdown_renderer';
import buildCustomHTMLRenderer from './build_custom_renderer';
-import { TOOLBAR_ITEM_CONFIGS } from '../constants';
+import { TOOLBAR_ITEM_CONFIGS, VIDEO_ATTRIBUTES } from '../constants';
+import sanitizeHTML from './sanitize_html';
const buildWrapper = propsData => {
const instance = new Vue({
@@ -16,6 +17,23 @@ const buildWrapper = propsData => {
return instance.$el;
};
+const buildVideoIframe = src => {
+ const wrapper = document.createElement('figure');
+ const iframe = document.createElement('iframe');
+ const videoAttributes = { ...VIDEO_ATTRIBUTES, src };
+ const wrapperClasses = ['gl-relative', 'gl-h-0', 'video_container'];
+ const iframeClasses = ['gl-absolute', 'gl-top-0', 'gl-left-0', 'gl-w-full', 'gl-h-full'];
+
+ wrapper.setAttribute('contenteditable', 'false');
+ wrapper.classList.add(...wrapperClasses);
+ iframe.classList.add(...iframeClasses);
+ Object.assign(iframe, videoAttributes);
+
+ wrapper.appendChild(iframe);
+
+ return wrapper;
+};
+
export const generateToolbarItem = config => {
const { icon, classes, event, command, tooltip, isDivider } = config;
@@ -43,6 +61,16 @@ export const removeCustomEventListener = (editorApi, event, handler) =>
export const addImage = ({ editor }, image) => editor.exec('AddImage', image);
+export const insertVideo = ({ editor }, url) => {
+ const videoIframe = buildVideoIframe(url);
+
+ if (editor.isWysiwygMode()) {
+ editor.getSquire().insertElement(videoIframe);
+ } else {
+ editor.insertText(videoIframe.outerHTML);
+ }
+};
+
export const getMarkdown = editorInstance => editorInstance.invoke('getMarkdown');
/**
@@ -62,5 +90,6 @@ export const getEditorOptions = externalOptions => {
return defaults({
customHTMLRenderer: buildCustomHTMLRenderer(externalOptions?.customRenderers),
toolbarItems: TOOLBAR_ITEM_CONFIGS.map(toolbarItem => generateToolbarItem(toolbarItem)),
+ customHTMLSanitizer: html => sanitizeHTML(html),
});
};
diff --git a/app/assets/javascripts/vue_shared/components/rich_content_editor/services/renderers/render_html_block.js b/app/assets/javascripts/vue_shared/components/rich_content_editor/services/renderers/render_html_block.js
index b179ca61dba..18bd17d43d9 100644
--- a/app/assets/javascripts/vue_shared/components/rich_content_editor/services/renderers/render_html_block.js
+++ b/app/assets/javascripts/vue_shared/components/rich_content_editor/services/renderers/render_html_block.js
@@ -1,7 +1,21 @@
import { buildUneditableHtmlAsTextTokens } from './build_uneditable_token';
+import { ALLOWED_VIDEO_ORIGINS } from '../../constants';
+import { getURLOrigin } from '~/lib/utils/url_utility';
-const canRender = ({ type }) => {
- return type === 'htmlBlock';
+const isVideoFrame = html => {
+ const parser = new DOMParser();
+ const doc = parser.parseFromString(html, 'text/html');
+ const {
+ children: { length },
+ } = doc;
+ const iframe = doc.querySelector('iframe');
+ const origin = iframe && getURLOrigin(iframe.getAttribute('src'));
+
+ return length === 1 && ALLOWED_VIDEO_ORIGINS.includes(origin);
+};
+
+const canRender = ({ type, literal }) => {
+ return type === 'htmlBlock' && !isVideoFrame(literal);
};
const render = node => buildUneditableHtmlAsTextTokens(node);
diff --git a/app/assets/javascripts/vue_shared/components/rich_content_editor/services/sanitize_html.js b/app/assets/javascripts/vue_shared/components/rich_content_editor/services/sanitize_html.js
new file mode 100644
index 00000000000..eae2e0335c1
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/rich_content_editor/services/sanitize_html.js
@@ -0,0 +1,22 @@
+import createSanitizer from 'dompurify';
+import { ALLOWED_VIDEO_ORIGINS } from '../constants';
+import { getURLOrigin } from '~/lib/utils/url_utility';
+
+const sanitizer = createSanitizer(window);
+const ADD_TAGS = ['iframe'];
+
+sanitizer.addHook('uponSanitizeElement', node => {
+ if (node.tagName !== 'IFRAME') {
+ return;
+ }
+
+ const origin = getURLOrigin(node.getAttribute('src'));
+
+ if (!ALLOWED_VIDEO_ORIGINS.includes(origin)) {
+ node.remove();
+ }
+});
+
+const sanitize = content => sanitizer.sanitize(content, { ADD_TAGS });
+
+export default sanitize;
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/collapsed_calendar_icon.vue b/app/assets/javascripts/vue_shared/components/sidebar/collapsed_calendar_icon.vue
index 0ed5a050fe4..6511c8d8c31 100644
--- a/app/assets/javascripts/vue_shared/components/sidebar/collapsed_calendar_icon.vue
+++ b/app/assets/javascripts/vue_shared/components/sidebar/collapsed_calendar_icon.vue
@@ -1,11 +1,10 @@
<script>
-import { GlIcon } from '@gitlab/ui';
-import tooltip from '~/vue_shared/directives/tooltip';
+import { GlIcon, GlTooltipDirective } from '@gitlab/ui';
export default {
name: 'CollapsedCalendarIcon',
directives: {
- tooltip,
+ GlTooltip: GlTooltipDirective,
},
components: {
GlIcon,
@@ -41,16 +40,7 @@ export default {
</script>
<template>
- <div
- v-tooltip
- :class="containerClass"
- :title="tooltipText"
- data-container="body"
- data-placement="left"
- data-html="true"
- data-boundary="viewport"
- @click="click"
- >
+ <div v-gl-tooltip.left.viewport :class="containerClass" :title="tooltipText" @click="click">
<gl-icon v-if="showIcon" name="calendar" />
<slot>
<span> {{ text }} </span>
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/dropdown_contents.vue b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/dropdown_contents.vue
index 6839354fb3a..267c3be5f50 100644
--- a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/dropdown_contents.vue
+++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/dropdown_contents.vue
@@ -38,6 +38,7 @@ export default {
<template>
<div
class="labels-select-dropdown-contents w-100 mt-1 mb-3 py-2 rounded-top rounded-bottom position-absolute"
+ data-qa-selector="labels_dropdown_content"
:style="directionStyle"
>
<component :is="dropdownContentsView" />
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/dropdown_contents_labels_view.vue b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/dropdown_contents_labels_view.vue
index 0b763aa4b72..c8dee81d746 100644
--- a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/dropdown_contents_labels_view.vue
+++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/dropdown_contents_labels_view.vue
@@ -1,6 +1,7 @@
<script>
import { mapState, mapGetters, mapActions } from 'vuex';
import { GlLoadingIcon, GlButton, GlSearchBoxByType, GlLink } from '@gitlab/ui';
+import fuzzaldrinPlus from 'fuzzaldrin-plus';
import { UP_KEY_CODE, DOWN_KEY_CODE, ENTER_KEY_CODE, ESC_KEY_CODE } from '~/lib/utils/keycodes';
import SmartVirtualList from '~/vue_shared/components/smart_virtual_list.vue';
@@ -39,9 +40,9 @@ export default {
...mapGetters(['selectedLabelsList', 'isDropdownVariantSidebar', 'isDropdownVariantEmbedded']),
visibleLabels() {
if (this.searchKey) {
- return this.labels.filter(label =>
- label.title.toLowerCase().includes(this.searchKey.toLowerCase()),
- );
+ return fuzzaldrinPlus.filter(this.labels, this.searchKey, {
+ key: ['title'],
+ });
}
return this.labels;
},
@@ -112,6 +113,7 @@ export default {
this.currentHighlightItem += 1;
} else if (e.keyCode === ENTER_KEY_CODE && this.currentHighlightItem > -1) {
this.updateSelectedLabels([this.visibleLabels[this.currentHighlightItem]]);
+ this.searchKey = '';
} else if (e.keyCode === ESC_KEY_CODE) {
this.toggleDropdownContents();
}
@@ -155,7 +157,11 @@ export default {
/>
</div>
<div class="dropdown-input" @click.stop="() => {}">
- <gl-search-box-by-type v-model="searchKey" :autofocus="true" />
+ <gl-search-box-by-type
+ v-model="searchKey"
+ :autofocus="true"
+ data-qa-selector="dropdown_input_field"
+ />
</div>
<div
v-show="showListContainer"
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/dropdown_value.vue b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/dropdown_value.vue
index 12ad2acf308..a6f99289df4 100644
--- a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/dropdown_value.vue
+++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/dropdown_value.vue
@@ -8,8 +8,20 @@ export default {
components: {
GlLabel,
},
+ props: {
+ disableLabels: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ },
computed: {
- ...mapState(['selectedLabels', 'allowScopedLabels', 'labelsFilterBasePath']),
+ ...mapState([
+ 'selectedLabels',
+ 'allowLabelRemove',
+ 'allowScopedLabels',
+ 'labelsFilterBasePath',
+ ]),
},
methods: {
labelFilterUrl(label) {
@@ -35,12 +47,17 @@ export default {
<template v-for="label in selectedLabels" v-else>
<gl-label
:key="label.id"
+ data-qa-selector="selected_label_content"
+ :data-qa-label-name="label.title"
:title="label.title"
:description="label.description"
:background-color="label.color"
:target="labelFilterUrl(label)"
:scoped="scopedLabel(label)"
+ :show-close-button="allowLabelRemove"
+ :disabled="disableLabels"
tooltip-placement="top"
+ @close="$emit('onLabelRemove', label.id)"
/>
</template>
</div>
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/labels_select_root.vue b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/labels_select_root.vue
index 34f5517ef99..c651013c5f5 100644
--- a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/labels_select_root.vue
+++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/labels_select_root.vue
@@ -28,6 +28,11 @@ export default {
DropdownValueCollapsed,
},
props: {
+ allowLabelRemove: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
allowLabelEdit: {
type: Boolean,
required: true,
@@ -130,6 +135,7 @@ export default {
mounted() {
this.setInitialState({
variant: this.variant,
+ allowLabelRemove: this.allowLabelRemove,
allowLabelEdit: this.allowLabelEdit,
allowLabelCreate: this.allowLabelCreate,
allowMultiselect: this.allowMultiselect,
@@ -252,7 +258,10 @@ export default {
:allow-label-edit="allowLabelEdit"
:labels-select-in-progress="labelsSelectInProgress"
/>
- <dropdown-value>
+ <dropdown-value
+ :disable-labels="labelsSelectInProgress"
+ @onLabelRemove="$emit('onLabelRemove', $event)"
+ >
<slot></slot>
</dropdown-value>
<dropdown-button v-show="dropdownButtonVisible" class="gl-mt-2" />
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/store/actions.js b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/store/actions.js
index 2d236566b3d..e624bd1eaee 100644
--- a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/store/actions.js
+++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/store/actions.js
@@ -54,8 +54,5 @@ export const createLabel = ({ state, dispatch }, label) => {
});
};
-export const replaceSelectedLabels = ({ commit }, selectedLabels) =>
- commit(types.REPLACE_SELECTED_LABELS, selectedLabels);
-
export const updateSelectedLabels = ({ commit }, labels) =>
commit(types.UPDATE_SELECTED_LABELS, { labels });
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/store/mutation_types.js b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/store/mutation_types.js
index af92665d4eb..2e044dc3b3c 100644
--- a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/store/mutation_types.js
+++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/store/mutation_types.js
@@ -15,7 +15,6 @@ export const RECEIVE_CREATE_LABEL_FAILURE = 'RECEIVE_CREATE_LABEL_FAILURE';
export const TOGGLE_DROPDOWN_BUTTON = 'TOGGLE_DROPDOWN_VISIBILITY';
export const TOGGLE_DROPDOWN_CONTENTS = 'TOGGLE_DROPDOWN_CONTENTS';
-export const REPLACE_SELECTED_LABELS = 'REPLACE_SELECTED_LABELS';
export const UPDATE_SELECTED_LABELS = 'UPDATE_SELECTED_LABELS';
export const TOGGLE_DROPDOWN_CONTENTS_CREATE_VIEW = 'TOGGLE_DROPDOWN_CONTENTS_CREATE_VIEW';
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/store/mutations.js b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/store/mutations.js
index 7edd290a819..54f8c78b4e1 100644
--- a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/store/mutations.js
+++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/store/mutations.js
@@ -57,10 +57,6 @@ export default {
state.labelCreateInProgress = false;
},
- [types.REPLACE_SELECTED_LABELS](state, selectedLabels = []) {
- state.selectedLabels = selectedLabels;
- },
-
[types.UPDATE_SELECTED_LABELS](state, { labels }) {
// Find the label to update from all the labels
// and change `set` prop value to represent their current state.
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/store/state.js b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/store/state.js
index 3f3358d4805..d66cfed4163 100644
--- a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/store/state.js
+++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/store/state.js
@@ -15,6 +15,7 @@ export default () => ({
// UI Flags
variant: '',
+ allowLabelRemove: false,
allowLabelCreate: false,
allowLabelEdit: false,
allowScopedLabels: false,
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/toggle_sidebar.vue b/app/assets/javascripts/vue_shared/components/sidebar/toggle_sidebar.vue
index 040a15406e0..6dacf4e10d3 100644
--- a/app/assets/javascripts/vue_shared/components/sidebar/toggle_sidebar.vue
+++ b/app/assets/javascripts/vue_shared/components/sidebar/toggle_sidebar.vue
@@ -1,11 +1,14 @@
<script>
+import { GlButton, GlTooltipDirective } from '@gitlab/ui';
import { __ } from '~/locale';
-import tooltip from '~/vue_shared/directives/tooltip';
export default {
name: 'ToggleSidebar',
+ components: {
+ GlButton,
+ },
directives: {
- tooltip,
+ GlTooltip: GlTooltipDirective,
},
props: {
collapsed: {
@@ -22,6 +25,12 @@ export default {
tooltipLabel() {
return this.collapsed ? __('Expand sidebar') : __('Collapse sidebar');
},
+ buttonIcon() {
+ return this.collapsed ? 'chevron-double-lg-left' : 'chevron-double-lg-right';
+ },
+ allCssClasses() {
+ return [this.cssClasses, { 'js-sidebar-collapsed': this.collapsed }];
+ },
},
methods: {
toggle() {
@@ -32,25 +41,15 @@ export default {
</script>
<template>
- <button
- v-tooltip
+ <gl-button
+ v-gl-tooltip:body.viewport.left
:title="tooltipLabel"
- :class="cssClasses"
- type="button"
- class="btn btn-blank gutter-toggle btn-sidebar-action js-sidebar-vue-toggle"
- data-container="body"
- data-placement="left"
- data-boundary="viewport"
+ :class="allCssClasses"
+ class="gutter-toggle btn-sidebar-action js-sidebar-vue-toggle"
+ :icon="buttonIcon"
+ category="tertiary"
+ size="small"
+ :aria-label="__('toggle collapse')"
@click="toggle"
- >
- <i
- :class="{
- 'fa-angle-double-right': !collapsed,
- 'fa-angle-double-left': collapsed,
- }"
- :aria-label="__('toggle collapse')"
- class="fa"
- >
- </i>
- </button>
+ />
</template>
diff --git a/app/assets/javascripts/vue_shared/components/split_button.vue b/app/assets/javascripts/vue_shared/components/split_button.vue
index e9b99c6ea78..11049028ff6 100644
--- a/app/assets/javascripts/vue_shared/components/split_button.vue
+++ b/app/assets/javascripts/vue_shared/components/split_button.vue
@@ -1,19 +1,15 @@
<script>
import { isString } from 'lodash';
-import {
- GlDeprecatedDropdown,
- GlDeprecatedDropdownDivider,
- GlDeprecatedDropdownItem,
-} from '@gitlab/ui';
+import { GlDropdown, GlDropdownDivider, GlDropdownItem } from '@gitlab/ui';
const isValidItem = item =>
isString(item.eventName) && isString(item.title) && isString(item.description);
export default {
components: {
- GlDeprecatedDropdown,
- GlDeprecatedDropdownDivider,
- GlDeprecatedDropdownItem,
+ GlDropdown,
+ GlDropdownDivider,
+ GlDropdownItem,
},
props: {
@@ -32,7 +28,7 @@ export default {
variant: {
type: String,
required: false,
- default: 'secondary',
+ default: 'default',
},
},
@@ -61,8 +57,8 @@ export default {
</script>
<template>
- <gl-deprecated-dropdown
- :menu-class="`dropdown-menu-selectable ${menuClass}`"
+ <gl-dropdown
+ :menu-class="menuClass"
split
:text="dropdownToggleText"
:variant="variant"
@@ -70,20 +66,20 @@ export default {
@click="triggerEvent"
>
<template v-for="(item, itemIndex) in actionItems">
- <gl-deprecated-dropdown-item
+ <gl-dropdown-item
:key="item.eventName"
- :active="selectedItem === item"
- active-class="is-active"
+ :is-check-item="true"
+ :is-checked="selectedItem === item"
@click="changeSelectedItem(item)"
>
<strong>{{ item.title }}</strong>
<div>{{ item.description }}</div>
- </gl-deprecated-dropdown-item>
+ </gl-dropdown-item>
- <gl-deprecated-dropdown-divider
+ <gl-dropdown-divider
v-if="itemIndex < actionItems.length - 1"
:key="`${item.eventName}-divider`"
/>
</template>
- </gl-deprecated-dropdown>
+ </gl-dropdown>
</template>
diff --git a/app/assets/javascripts/vue_shared/components/stacked_progress_bar.vue b/app/assets/javascripts/vue_shared/components/stacked_progress_bar.vue
index a0c161a335a..f2e9c4a4fbb 100644
--- a/app/assets/javascripts/vue_shared/components/stacked_progress_bar.vue
+++ b/app/assets/javascripts/vue_shared/components/stacked_progress_bar.vue
@@ -1,11 +1,11 @@
<script>
+import { GlTooltipDirective } from '@gitlab/ui';
import { __ } from '~/locale';
import { roundOffFloat } from '~/lib/utils/common_utils';
-import tooltip from '~/vue_shared/directives/tooltip';
export default {
directives: {
- tooltip,
+ GlTooltip: GlTooltipDirective,
},
props: {
cssClass: {
@@ -112,7 +112,7 @@ export default {
<span v-if="!totalCount" class="status-unavailable">{{ unavailableLabel }}</span>
<span
v-if="successPercent"
- v-tooltip
+ v-gl-tooltip
:title="successTooltip"
:style="successBarStyle"
class="status-green"
@@ -122,7 +122,7 @@ export default {
</span>
<span
v-if="neutralPercent"
- v-tooltip
+ v-gl-tooltip
:title="neutralTooltip"
:style="neutralBarStyle"
class="status-neutral"
@@ -132,7 +132,7 @@ export default {
</span>
<span
v-if="failurePercent"
- v-tooltip
+ v-gl-tooltip
:title="failureTooltip"
:style="failureBarStyle"
class="status-red"
diff --git a/app/assets/javascripts/vue_shared/components/timezone_dropdown.vue b/app/assets/javascripts/vue_shared/components/timezone_dropdown.vue
index 135b9842cbf..f6721f5a27b 100644
--- a/app/assets/javascripts/vue_shared/components/timezone_dropdown.vue
+++ b/app/assets/javascripts/vue_shared/components/timezone_dropdown.vue
@@ -1,5 +1,5 @@
<script>
-import { GlDropdown, GlDeprecatedDropdownItem, GlSearchBoxByType, GlIcon } from '@gitlab/ui';
+import { GlDropdown, GlDropdownItem, GlSearchBoxByType } from '@gitlab/ui';
import { __ } from '~/locale';
import autofocusonshow from '~/vue_shared/directives/autofocusonshow';
@@ -7,9 +7,8 @@ export default {
name: 'TimezoneDropdown',
components: {
GlDropdown,
- GlDeprecatedDropdownItem,
+ GlDropdownItem,
GlSearchBoxByType,
- GlIcon,
},
directives: {
autofocusonshow,
@@ -74,29 +73,23 @@ export default {
};
</script>
<template>
- <gl-dropdown :text="value" block lazy menu-class="gl-w-full!">
- <template #button-content>
- <span class="gl-flex-grow-1" :class="{ 'gl-text-gray-300': !value }">
- {{ selectedTimezoneLabel }}
- </span>
- <gl-icon name="chevron-down" />
- </template>
-
- <gl-search-box-by-type v-model.trim="searchTerm" v-autofocusonshow autofocus class="gl-m-3" />
- <gl-deprecated-dropdown-item
+ <gl-dropdown :text="selectedTimezoneLabel" block lazy menu-class="gl-w-full!">
+ <gl-search-box-by-type v-model.trim="searchTerm" v-autofocusonshow autofocus />
+ <gl-dropdown-item
v-for="timezone in filteredResults"
:key="timezone.formattedTimezone"
+ :is-checked="isSelected(timezone)"
+ :is-check-item="true"
@click="selectTimezone(timezone)"
>
- <gl-icon
- :class="{ invisible: !isSelected(timezone) }"
- name="mobile-issue-close"
- class="gl-vertical-align-middle"
- />
{{ timezone.formattedTimezone }}
- </gl-deprecated-dropdown-item>
- <gl-deprecated-dropdown-item v-if="!filteredResults.length" data-testid="noMatchingResults">
+ </gl-dropdown-item>
+ <gl-dropdown-item
+ v-if="!filteredResults.length"
+ class="gl-pointer-events-none"
+ data-testid="noMatchingResults"
+ >
{{ $options.tranlations.noResultsText }}
- </gl-deprecated-dropdown-item>
+ </gl-dropdown-item>
</gl-dropdown>
</template>
diff --git a/app/assets/javascripts/vue_shared/components/todo_button.vue b/app/assets/javascripts/vue_shared/components/todo_button.vue
index debf19ccca6..a9d4f8403fa 100644
--- a/app/assets/javascripts/vue_shared/components/todo_button.vue
+++ b/app/assets/javascripts/vue_shared/components/todo_button.vue
@@ -15,7 +15,7 @@ export default {
},
computed: {
buttonLabel() {
- return this.isTodo ? __('Mark as done') : __('Add a To-Do');
+ return this.isTodo ? __('Mark as done') : __('Add a To Do');
},
},
};
diff --git a/app/assets/javascripts/vue_shared/components/toggle_button.vue b/app/assets/javascripts/vue_shared/components/toggle_button.vue
index 29d4516bece..861661d3519 100644
--- a/app/assets/javascripts/vue_shared/components/toggle_button.vue
+++ b/app/assets/javascripts/vue_shared/components/toggle_button.vue
@@ -59,7 +59,7 @@ export default {
</script>
<template>
- <label class="toggle-wrapper">
+ <label class="gl-mt-2">
<input v-if="name" :name="name" :value="value" type="hidden" />
<button
type="button"
diff --git a/app/assets/javascripts/vue_shared/components/user_popover/user_popover.vue b/app/assets/javascripts/vue_shared/components/user_popover/user_popover.vue
index 6aaff000845..3f5738b2b93 100644
--- a/app/assets/javascripts/vue_shared/components/user_popover/user_popover.vue
+++ b/app/assets/javascripts/vue_shared/components/user_popover/user_popover.vue
@@ -1,16 +1,27 @@
<script>
/* eslint-disable vue/no-v-html */
-import { GlPopover, GlDeprecatedSkeletonLoading as GlSkeletonLoading, GlIcon } from '@gitlab/ui';
+import {
+ GlPopover,
+ GlLink,
+ GlDeprecatedSkeletonLoading as GlSkeletonLoading,
+ GlIcon,
+} from '@gitlab/ui';
import UserAvatarImage from '../user_avatar/user_avatar_image.vue';
import { glEmojiTag } from '../../../emoji';
const MAX_SKELETON_LINES = 4;
+const SECURITY_BOT_USER_DATA = {
+ username: 'GitLab-Security-Bot',
+ name: 'GitLab Security Bot',
+};
+
export default {
name: 'UserPopover',
maxSkeletonLines: MAX_SKELETON_LINES,
components: {
GlIcon,
+ GlLink,
GlPopover,
GlSkeletonLoading,
UserAvatarImage,
@@ -43,6 +54,15 @@ export default {
userIsLoading() {
return !this.user?.loaded;
},
+ isSecurityBot() {
+ const { username, name, websiteUrl = '' } = this.user;
+ return (
+ gon.features?.securityAutoFix &&
+ username === SECURITY_BOT_USER_DATA.username &&
+ name === SECURITY_BOT_USER_DATA.name &&
+ websiteUrl.length
+ );
+ },
},
};
</script>
@@ -89,6 +109,12 @@ export default {
<div v-if="statusHtml" class="js-user-status gl-mt-3">
<span v-html="statusHtml"></span>
</div>
+ <div v-if="isSecurityBot" class="gl-text-blue-500">
+ <gl-icon name="question" />
+ <gl-link data-testid="user-popover-bot-docs-link" :href="user.websiteUrl">
+ {{ sprintf(__('Learn more about %{username}'), { username: user.name }) }}
+ </gl-link>
+ </div>
</template>
</div>
</div>
diff --git a/app/assets/javascripts/vue_shared/components/web_ide_link.vue b/app/assets/javascripts/vue_shared/components/web_ide_link.vue
index 8307c6d3b55..877414519f7 100644
--- a/app/assets/javascripts/vue_shared/components/web_ide_link.vue
+++ b/app/assets/javascripts/vue_shared/components/web_ide_link.vue
@@ -4,6 +4,7 @@ import { __ } from '~/locale';
import LocalStorageSync from '~/vue_shared/components/local_storage_sync.vue';
import ActionsButton from '~/vue_shared/components/actions_button.vue';
+const KEY_EDIT = 'edit';
const KEY_WEB_IDE = 'webide';
const KEY_GITPOD = 'gitpod';
@@ -13,15 +14,31 @@ export default {
LocalStorageSync,
},
props: {
- webIdeUrl: {
- type: String,
- required: true,
+ isFork: {
+ type: Boolean,
+ required: false,
+ default: false,
},
needsToFork: {
type: Boolean,
required: false,
default: false,
},
+ gitpodEnabled: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ isBlob: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ showEditButton: {
+ type: Boolean,
+ required: false,
+ default: true,
+ },
showWebIdeButton: {
type: Boolean,
required: false,
@@ -32,15 +49,20 @@ export default {
required: false,
default: false,
},
- gitpodUrl: {
+ editUrl: {
type: String,
required: false,
default: '',
},
- gitpodEnabled: {
- type: Boolean,
+ webIdeUrl: {
+ type: String,
required: false,
- default: false,
+ default: '',
+ },
+ gitpodUrl: {
+ type: String,
+ required: false,
+ default: '',
},
},
data() {
@@ -50,7 +72,33 @@ export default {
},
computed: {
actions() {
- return [this.webIdeAction, this.gitpodAction].filter(x => x);
+ return [this.webIdeAction, this.editAction, this.gitpodAction].filter(action => action);
+ },
+ editAction() {
+ if (!this.showEditButton) {
+ return null;
+ }
+
+ const handleOptions = this.needsToFork
+ ? {
+ href: '#modal-confirm-fork-edit',
+ handle: () => this.showModal('#modal-confirm-fork-edit'),
+ }
+ : { href: this.editUrl };
+
+ return {
+ key: KEY_EDIT,
+ text: __('Edit'),
+ secondaryText: __('Edit this file only.'),
+ tooltip: '',
+ attrs: {
+ 'data-qa-selector': 'edit_button',
+ 'data-track-event': 'click_edit',
+ // eslint-disable-next-line @gitlab/require-i18n-strings
+ 'data-track-label': 'Edit',
+ },
+ ...handleOptions,
+ };
},
webIdeAction() {
if (!this.showWebIdeButton) {
@@ -58,16 +106,30 @@ export default {
}
const handleOptions = this.needsToFork
- ? { href: '#modal-confirm-fork', handle: () => this.showModal('#modal-confirm-fork') }
+ ? {
+ href: '#modal-confirm-fork-webide',
+ handle: () => this.showModal('#modal-confirm-fork-webide'),
+ }
: { href: this.webIdeUrl };
+ let text = __('Web IDE');
+
+ if (this.isBlob) {
+ text = __('Edit in Web IDE');
+ } else if (this.isFork) {
+ text = __('Edit fork in Web IDE');
+ }
+
return {
key: KEY_WEB_IDE,
- text: __('Web IDE'),
+ text,
secondaryText: __('Quickly and easily edit multiple files in your project.'),
tooltip: '',
attrs: {
'data-qa-selector': 'web_ide_button',
+ 'data-track-event': 'click_edit_ide',
+ // eslint-disable-next-line @gitlab/require-i18n-strings
+ 'data-track-label': 'Web IDE',
},
...handleOptions,
};
@@ -107,8 +169,14 @@ export default {
</script>
<template>
- <div>
- <actions-button :actions="actions" :selected-key="selection" @select="select" />
+ <div class="d-inline-block gl-ml-3">
+ <actions-button
+ :actions="actions"
+ :selected-key="selection"
+ :variant="isBlob ? 'info' : 'default'"
+ :category="isBlob ? 'primary' : 'secondary'"
+ @select="select"
+ />
<local-storage-sync
storage-key="gl-web-ide-button-selected"
:value="selection"
diff --git a/app/assets/javascripts/vue_shared/directives/tooltip.js b/app/assets/javascripts/vue_shared/directives/tooltip.js
index 73e92728cb9..0eb505bfce8 100644
--- a/app/assets/javascripts/vue_shared/directives/tooltip.js
+++ b/app/assets/javascripts/vue_shared/directives/tooltip.js
@@ -1,5 +1,6 @@
import $ from 'jquery';
import '~/commons/bootstrap';
+import { parseBoolean } from '~/lib/utils/common_utils';
export default {
bind(el) {
@@ -9,6 +10,10 @@ export default {
$(el).tooltip({
trigger: 'hover',
delay,
+ // By default, sanitize is run even if there is no `html` or `template` present
+ // so let's optimize to only run this when necessary.
+ // https://github.com/twbs/bootstrap/blob/c5966de27395a407f9a3d20d0eb2ff8e8fb7b564/js/src/tooltip.js#L716
+ sanitize: parseBoolean(el.dataset.html) || Boolean(el.dataset.template),
});
},
diff --git a/app/assets/javascripts/vue_shared/mixins/ci_pagination_api_mixin.js b/app/assets/javascripts/vue_shared/mixins/ci_pagination_api_mixin.js
index a740a3fa6b9..cdbde55901d 100644
--- a/app/assets/javascripts/vue_shared/mixins/ci_pagination_api_mixin.js
+++ b/app/assets/javascripts/vue_shared/mixins/ci_pagination_api_mixin.js
@@ -10,6 +10,10 @@ import { validateParams } from '~/pipelines/utils';
export default {
methods: {
onChangeTab(scope) {
+ if (this.scope === scope) {
+ return;
+ }
+
let params = {
scope,
page: '1',
diff --git a/app/assets/javascripts/vue_shared/mixins/related_issuable_mixin.js b/app/assets/javascripts/vue_shared/mixins/related_issuable_mixin.js
index be5f55a5220..c0fc055a01b 100644
--- a/app/assets/javascripts/vue_shared/mixins/related_issuable_mixin.js
+++ b/app/assets/javascripts/vue_shared/mixins/related_issuable_mixin.js
@@ -111,7 +111,7 @@ const mixins = {
return this.isMergeRequest && this.pipelineStatus && Object.keys(this.pipelineStatus).length;
},
isOpen() {
- return this.state === 'opened';
+ return this.state === 'opened' || this.state === 'reopened';
},
isClosed() {
return this.state === 'closed';
diff --git a/app/assets/javascripts/vue_shared/security_reports/security_reports_app.vue b/app/assets/javascripts/vue_shared/security_reports/security_reports_app.vue
new file mode 100644
index 00000000000..d5696e3c8cf
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/security_reports/security_reports_app.vue
@@ -0,0 +1,107 @@
+<script>
+import { GlIcon, GlLink, GlSprintf } from '@gitlab/ui';
+import ReportSection from '~/reports/components/report_section.vue';
+import { status } from '~/reports/constants';
+import { s__ } from '~/locale';
+import Flash from '~/flash';
+import Api from '~/api';
+
+export default {
+ components: {
+ GlIcon,
+ GlLink,
+ GlSprintf,
+ ReportSection,
+ },
+ props: {
+ pipelineId: {
+ type: Number,
+ required: true,
+ },
+ projectId: {
+ type: Number,
+ required: true,
+ },
+ securityReportsDocsPath: {
+ type: String,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ hasSecurityReports: false,
+
+ // Error state is shown even when successfully loaded, since success
+ // state suggests that the security scans detected no security problems,
+ // which is not necessarily the case. A future iteration will actually
+ // check whether problems were found and display the appropriate status.
+ status: status.ERROR,
+ };
+ },
+ created() {
+ this.checkHasSecurityReports(this.$options.reportTypes)
+ .then(hasSecurityReports => {
+ this.hasSecurityReports = hasSecurityReports;
+ })
+ .catch(error => {
+ Flash({
+ message: this.$options.i18n.apiError,
+ captureError: true,
+ error,
+ });
+ });
+ },
+ methods: {
+ checkHasSecurityReports(reportTypes) {
+ return Api.pipelineJobs(this.projectId, this.pipelineId).then(({ data: jobs }) =>
+ jobs.some(({ artifacts = [] }) =>
+ artifacts.some(({ file_type }) => reportTypes.includes(file_type)),
+ ),
+ );
+ },
+ activatePipelinesTab() {
+ if (window.mrTabs) {
+ window.mrTabs.tabShown('pipelines');
+ }
+ },
+ },
+ reportTypes: ['sast', 'secret_detection'],
+ i18n: {
+ apiError: s__(
+ 'SecurityReports|Failed to get security report information. Please reload the page or try again later.',
+ ),
+ scansHaveRun: s__(
+ 'SecurityReports|Security scans have run. Go to the %{linkStart}pipelines tab%{linkEnd} to download the security reports',
+ ),
+ securityReportsHelp: s__('SecurityReports|Security reports help page link'),
+ },
+};
+</script>
+<template>
+ <report-section
+ v-if="hasSecurityReports"
+ :status="status"
+ :has-issues="false"
+ class="mr-widget-border-top mr-report"
+ data-testid="security-mr-widget"
+ >
+ <template #error>
+ <gl-sprintf :message="$options.i18n.scansHaveRun">
+ <template #link="{ content }">
+ <gl-link data-testid="show-pipelines" @click="activatePipelinesTab">{{
+ content
+ }}</gl-link>
+ </template>
+ </gl-sprintf>
+
+ <gl-link
+ target="_blank"
+ data-testid="help"
+ :href="securityReportsDocsPath"
+ :aria-label="$options.i18n.securityReportsHelp"
+ >
+ <gl-icon name="question" />
+ </gl-link>
+ </template>
+ </report-section>
+</template>
diff --git a/app/assets/javascripts/vuex_shared/modules/members/actions.js b/app/assets/javascripts/vuex_shared/modules/members/actions.js
new file mode 100644
index 00000000000..f7fdddfd070
--- /dev/null
+++ b/app/assets/javascripts/vuex_shared/modules/members/actions.js
@@ -0,0 +1,25 @@
+import * as types from './mutation_types';
+import axios from '~/lib/utils/axios_utils';
+
+export const updateMemberRole = async ({ state, commit }, { memberId, accessLevel }) => {
+ try {
+ await axios.put(
+ state.memberPath.replace(/:id$/, memberId),
+ state.requestFormatter({ accessLevel: accessLevel.integerValue }),
+ );
+
+ commit(types.RECEIVE_MEMBER_ROLE_SUCCESS, { memberId, accessLevel });
+ } catch (error) {
+ commit(types.RECEIVE_MEMBER_ROLE_ERROR);
+
+ throw error;
+ }
+};
+
+export const showRemoveGroupLinkModal = ({ commit }, groupLink) => {
+ commit(types.SHOW_REMOVE_GROUP_LINK_MODAL, groupLink);
+};
+
+export const hideRemoveGroupLinkModal = ({ commit }) => {
+ commit(types.HIDE_REMOVE_GROUP_LINK_MODAL);
+};
diff --git a/app/assets/javascripts/vuex_shared/modules/members/index.js b/app/assets/javascripts/vuex_shared/modules/members/index.js
index ec6a94178f3..682e85298ad 100644
--- a/app/assets/javascripts/vuex_shared/modules/members/index.js
+++ b/app/assets/javascripts/vuex_shared/modules/members/index.js
@@ -1,6 +1,10 @@
-import createState from './state';
+import createState from 'ee_else_ce/vuex_shared/modules/members/state';
+import * as actions from './actions';
+import mutations from './mutations';
export default initialState => ({
namespaced: true,
state: createState(initialState),
+ actions,
+ mutations,
});
diff --git a/app/assets/javascripts/vuex_shared/modules/members/mutation_types.js b/app/assets/javascripts/vuex_shared/modules/members/mutation_types.js
new file mode 100644
index 00000000000..00f4c910669
--- /dev/null
+++ b/app/assets/javascripts/vuex_shared/modules/members/mutation_types.js
@@ -0,0 +1,7 @@
+export const RECEIVE_MEMBER_ROLE_SUCCESS = 'RECEIVE_MEMBER_ROLE_SUCCESS';
+export const RECEIVE_MEMBER_ROLE_ERROR = 'RECEIVE_MEMBER_ROLE_ERROR';
+
+export const HIDE_ERROR = 'HIDE_ERROR';
+
+export const SHOW_REMOVE_GROUP_LINK_MODAL = 'SHOW_REMOVE_GROUP_LINK_MODAL';
+export const HIDE_REMOVE_GROUP_LINK_MODAL = 'HIDE_REMOVE_GROUP_LINK_MODAL';
diff --git a/app/assets/javascripts/vuex_shared/modules/members/mutations.js b/app/assets/javascripts/vuex_shared/modules/members/mutations.js
new file mode 100644
index 00000000000..281c947e68f
--- /dev/null
+++ b/app/assets/javascripts/vuex_shared/modules/members/mutations.js
@@ -0,0 +1,33 @@
+import Vue from 'vue';
+import { s__ } from '~/locale';
+import * as types from './mutation_types';
+import { findMember } from './utils';
+
+export default {
+ [types.RECEIVE_MEMBER_ROLE_SUCCESS](state, { memberId, accessLevel }) {
+ const member = findMember(state, memberId);
+
+ if (!member) {
+ return;
+ }
+
+ Vue.set(member, 'accessLevel', accessLevel);
+ },
+ [types.RECEIVE_MEMBER_ROLE_ERROR](state) {
+ state.errorMessage = s__(
+ "Members|An error occurred while updating the member's role, please try again.",
+ );
+ state.showError = true;
+ },
+ [types.HIDE_ERROR](state) {
+ state.showError = false;
+ state.errorMessage = '';
+ },
+ [types.SHOW_REMOVE_GROUP_LINK_MODAL](state, groupLink) {
+ state.removeGroupLinkModalVisible = true;
+ state.groupLinkToRemove = groupLink;
+ },
+ [types.HIDE_REMOVE_GROUP_LINK_MODAL](state) {
+ state.removeGroupLinkModalVisible = false;
+ },
+};
diff --git a/app/assets/javascripts/vuex_shared/modules/members/state.js b/app/assets/javascripts/vuex_shared/modules/members/state.js
index 1511961245c..e4867819e17 100644
--- a/app/assets/javascripts/vuex_shared/modules/members/state.js
+++ b/app/assets/javascripts/vuex_shared/modules/members/state.js
@@ -1,5 +1,19 @@
-export default ({ members, sourceId, currentUserId }) => ({
+export default ({
members,
sourceId,
currentUserId,
+ tableFields,
+ memberPath,
+ requestFormatter,
+}) => ({
+ members,
+ sourceId,
+ currentUserId,
+ tableFields,
+ memberPath,
+ requestFormatter,
+ showError: false,
+ errorMessage: '',
+ removeGroupLinkModalVisible: false,
+ groupLinkToRemove: null,
});
diff --git a/app/assets/javascripts/vuex_shared/modules/members/utils.js b/app/assets/javascripts/vuex_shared/modules/members/utils.js
new file mode 100644
index 00000000000..7dcd33111e8
--- /dev/null
+++ b/app/assets/javascripts/vuex_shared/modules/members/utils.js
@@ -0,0 +1 @@
+export const findMember = (state, memberId) => state.members.find(member => member.id === memberId);
diff --git a/app/assets/javascripts/whats_new/components/app.vue b/app/assets/javascripts/whats_new/components/app.vue
index a00661c214d..9400dacedc2 100644
--- a/app/assets/javascripts/whats_new/components/app.vue
+++ b/app/assets/javascripts/whats_new/components/app.vue
@@ -1,6 +1,10 @@
<script>
import { mapState, mapActions } from 'vuex';
import { GlDrawer, GlBadge, GlIcon, GlLink } from '@gitlab/ui';
+import SkeletonLoader from './skeleton_loader.vue';
+import Tracking from '~/tracking';
+
+const trackingMixin = Tracking.mixin();
export default {
components: {
@@ -8,66 +12,90 @@ export default {
GlBadge,
GlIcon,
GlLink,
+ SkeletonLoader,
},
+ mixins: [trackingMixin],
props: {
- features: {
+ storageKey: {
type: String,
- required: false,
+ required: true,
default: null,
},
},
computed: {
- ...mapState(['open']),
- parsedFeatures() {
- let features;
-
- try {
- features = JSON.parse(this.$props.features) || [];
- } catch (err) {
- features = [];
- }
-
- return features;
- },
+ ...mapState(['open', 'features']),
},
mounted() {
- this.openDrawer();
+ this.openDrawer(this.storageKey);
+ this.fetchItems();
+
+ const body = document.querySelector('body');
+ const namespaceId = body.getAttribute('data-namespace-id');
+
+ this.track('click_whats_new_drawer', { label: 'namespace_id', value: namespaceId });
},
methods: {
- ...mapActions(['openDrawer', 'closeDrawer']),
+ ...mapActions(['openDrawer', 'closeDrawer', 'fetchItems']),
},
};
</script>
<template>
<div>
- <gl-drawer class="mt-6" :open="open" @close="closeDrawer">
+ <gl-drawer class="whats-new-drawer" :open="open" @close="closeDrawer">
<template #header>
<h4 class="page-title my-2">{{ __("What's new at GitLab") }}</h4>
</template>
<div class="pb-6">
- <div v-for="feature in parsedFeatures" :key="feature.title" class="mb-6">
- <gl-link :href="feature.url" target="_blank">
- <h5 class="gl-font-base">{{ feature.title }}</h5>
- </gl-link>
- <div class="mb-2">
- <template v-for="package_name in feature.packages">
- <gl-badge :key="package_name" size="sm" class="whats-new-item-badge mr-1">
- <gl-icon name="license" />{{ package_name }}
- </gl-badge>
- </template>
+ <template v-if="features">
+ <div v-for="feature in features" :key="feature.title" class="mb-6">
+ <gl-link
+ :href="feature.url"
+ target="_blank"
+ data-testid="whats-new-title-link"
+ data-track-event="click_whats_new_item"
+ :data-track-label="feature.title"
+ :data-track-property="feature.url"
+ >
+ <h5 class="gl-font-base">{{ feature.title }}</h5>
+ </gl-link>
+ <div v-if="feature.packages" class="gl-mb-3">
+ <template v-for="package_name in feature.packages">
+ <gl-badge :key="package_name" size="sm" class="whats-new-item-badge gl-mr-2">
+ <gl-icon name="license" />{{ package_name }}
+ </gl-badge>
+ </template>
+ </div>
+ <gl-link
+ :href="feature.url"
+ target="_blank"
+ data-track-event="click_whats_new_item"
+ :data-track-label="feature.title"
+ :data-track-property="feature.url"
+ >
+ <img
+ :alt="feature.title"
+ :src="feature.image_url"
+ class="img-thumbnail px-6 gl-py-3 whats-new-item-image"
+ />
+ </gl-link>
+ <p class="gl-pt-3">{{ feature.body }}</p>
+ <gl-link
+ :href="feature.url"
+ target="_blank"
+ data-track-event="click_whats_new_item"
+ :data-track-label="feature.title"
+ :data-track-property="feature.url"
+ >{{ __('Learn more') }}</gl-link
+ >
</div>
- <gl-link :href="feature.url" target="_blank">
- <img
- :alt="feature.title"
- :src="feature.image_url"
- class="img-thumbnail px-6 py-2 whats-new-item-image"
- />
- </gl-link>
- <p class="pt-2">{{ feature.body }}</p>
- <gl-link :href="feature.url" target="_blank">{{ __('Learn more') }}</gl-link>
+ </template>
+ <div v-else class="gl-mt-5">
+ <skeleton-loader />
+ <skeleton-loader />
</div>
</div>
</gl-drawer>
+ <div v-if="open" class="whats-new-modal-backdrop modal-backdrop"></div>
</div>
</template>
diff --git a/app/assets/javascripts/whats_new/components/skeleton_loader.vue b/app/assets/javascripts/whats_new/components/skeleton_loader.vue
new file mode 100644
index 00000000000..41e7790f300
--- /dev/null
+++ b/app/assets/javascripts/whats_new/components/skeleton_loader.vue
@@ -0,0 +1,25 @@
+<script>
+import { GlSkeletonLoader } from '@gitlab/ui';
+
+export default {
+ components: {
+ GlSkeletonLoader,
+ },
+};
+</script>
+
+<template>
+ <gl-skeleton-loader :width="350" :height="420">
+ <rect width="350" height="16" />
+ <rect y="25" width="110" height="16" rx="8" />
+ <rect x="115" y="25" width="110" height="16" rx="8" />
+ <rect x="230" y="25" width="110" height="16" rx="8" />
+ <rect y="50" width="350" height="165" rx="12" />
+ <rect y="230" width="480" height="8" />
+ <rect y="254" width="560" height="8" />
+ <rect y="278" width="320" height="8" />
+ <rect y="302" width="480" height="8" />
+ <rect y="326" width="560" height="8" />
+ <rect y="365" width="80" height="8" />
+ </gl-skeleton-loader>
+</template>
diff --git a/app/assets/javascripts/whats_new/index.js b/app/assets/javascripts/whats_new/index.js
index 19cdb590ae2..a57c9718156 100644
--- a/app/assets/javascripts/whats_new/index.js
+++ b/app/assets/javascripts/whats_new/index.js
@@ -19,7 +19,7 @@ export default () => {
render(createElement) {
return createElement('app', {
props: {
- features: whatsNewElm.getAttribute('data-features'),
+ storageKey: whatsNewElm.getAttribute('data-storage-key'),
},
});
},
diff --git a/app/assets/javascripts/whats_new/store/actions.js b/app/assets/javascripts/whats_new/store/actions.js
index 53488413d9e..a84dfb399d8 100644
--- a/app/assets/javascripts/whats_new/store/actions.js
+++ b/app/assets/javascripts/whats_new/store/actions.js
@@ -1,10 +1,20 @@
import * as types from './mutation_types';
+import axios from '~/lib/utils/axios_utils';
export default {
closeDrawer({ commit }) {
commit(types.CLOSE_DRAWER);
},
- openDrawer({ commit }) {
+ openDrawer({ commit }, storageKey) {
commit(types.OPEN_DRAWER);
+
+ if (storageKey) {
+ localStorage.setItem(storageKey, JSON.stringify(false));
+ }
+ },
+ fetchItems({ commit }) {
+ return axios.get('/-/whats_new').then(({ data }) => {
+ commit(types.SET_FEATURES, data);
+ });
},
};
diff --git a/app/assets/javascripts/whats_new/store/mutation_types.js b/app/assets/javascripts/whats_new/store/mutation_types.js
index daa65230101..124d33a88b1 100644
--- a/app/assets/javascripts/whats_new/store/mutation_types.js
+++ b/app/assets/javascripts/whats_new/store/mutation_types.js
@@ -1,2 +1,3 @@
export const CLOSE_DRAWER = 'CLOSE_DRAWER';
export const OPEN_DRAWER = 'OPEN_DRAWER';
+export const SET_FEATURES = 'SET_FEATURES';
diff --git a/app/assets/javascripts/whats_new/store/mutations.js b/app/assets/javascripts/whats_new/store/mutations.js
index f7e84ee81a9..4fb7b17244e 100644
--- a/app/assets/javascripts/whats_new/store/mutations.js
+++ b/app/assets/javascripts/whats_new/store/mutations.js
@@ -7,4 +7,7 @@ export default {
[types.OPEN_DRAWER](state) {
state.open = true;
},
+ [types.SET_FEATURES](state, data) {
+ state.features = data;
+ },
};
diff --git a/app/assets/javascripts/whats_new/store/state.js b/app/assets/javascripts/whats_new/store/state.js
index 97089a095f1..4c76284b865 100644
--- a/app/assets/javascripts/whats_new/store/state.js
+++ b/app/assets/javascripts/whats_new/store/state.js
@@ -1,3 +1,4 @@
export default {
open: false,
+ features: null,
};
diff --git a/app/assets/stylesheets/_page_specific_files.scss b/app/assets/stylesheets/_page_specific_files.scss
index f706b615e7e..a31cb0b0485 100644
--- a/app/assets/stylesheets/_page_specific_files.scss
+++ b/app/assets/stylesheets/_page_specific_files.scss
@@ -1,41 +1,27 @@
@import './pages/admin';
@import './pages/alert_management/details';
@import './pages/alert_management/severity-icons';
-@import './pages/boards';
@import './pages/branches';
@import './pages/builds';
@import './pages/ci_projects';
@import './pages/clusters';
@import './pages/commits';
-@import './pages/cycle_analytics';
@import './pages/deploy_keys';
@import './pages/detail_page';
-@import './pages/dev_ops_report';
-@import './pages/diff';
@import './pages/editor';
@import './pages/environment_logs';
-@import './pages/environments';
-@import './pages/error_details';
-@import './pages/error_list';
-@import './pages/error_tracking_list';
@import './pages/events';
-@import './pages/experience_level';
-@import './pages/experimental_separate_sign_up';
-@import './pages/graph';
@import './pages/groups';
@import './pages/help';
@import './pages/import';
@import './pages/incident_management_list';
@import './pages/issuable';
@import './pages/issues/issue_count_badge';
-@import './pages/issues/issues_list';
@import './pages/issues';
@import './pages/labels';
@import './pages/login';
@import './pages/members';
-@import './pages/merge_conflicts';
@import './pages/merge_requests';
-@import './pages/milestone';
@import './pages/monitor';
@import './pages/note_form';
@import './pages/notes';
@@ -47,19 +33,14 @@
@import './pages/profiles/preferences';
@import './pages/projects';
@import './pages/prometheus';
-@import './pages/reports';
@import './pages/runners';
@import './pages/search';
-@import './pages/serverless';
@import './pages/service_desk';
@import './pages/settings';
@import './pages/settings_ci_cd';
@import './pages/sherlock';
@import './pages/status';
@import './pages/storage_quota';
-@import './pages/tags';
@import './pages/tree';
@import './pages/trials';
-@import './pages/ui_dev_kit';
@import './pages/users';
-@import './pages/wiki';
diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss
index 8acd338fff8..4b1139d2354 100644
--- a/app/assets/stylesheets/application.scss
+++ b/app/assets/stylesheets/application.scss
@@ -1,11 +1,3 @@
-/*
- * This is a manifest file that'll automatically include all the stylesheets available in this directory
- * and any sub-directories. You're free to add application-wide styles to this file and they'll appear at
- * the top of the compiled file, but it's generally better to create a new file per style scope.
- *= require_self
- *= require cropper.css
-*/
-
// Welcome to GitLab css!
// If you need to add or modify UI component that is common for many pages
// like a table or typography then make changes in the framework/ directory.
@@ -36,17 +28,6 @@
// EE-only stylesheets
@import 'application_ee';
-// CSS util classes
-/**
- These are deprecated in favor of the Gitlab UI utilities imported below.
- Please check https://unpkg.com/browse/@gitlab/ui/src/scss/utilities.scss
- to see the available utility classes.
-**/
-@import 'utilities';
-
-// Gitlab UI util classes
-@import '@gitlab/ui/src/scss/utilities';
-
/* print styles */
@media print {
@import 'print';
diff --git a/app/assets/stylesheets/application_utilities.scss b/app/assets/stylesheets/application_utilities.scss
new file mode 100644
index 00000000000..817e983a0ec
--- /dev/null
+++ b/app/assets/stylesheets/application_utilities.scss
@@ -0,0 +1,12 @@
+@import 'page_bundles/mixins_and_variables_and_functions';
+
+// CSS util classes
+/**
+ These are deprecated in favor of the Gitlab UI utilities imported below.
+ Please check https://unpkg.com/browse/@gitlab/ui/src/scss/utilities.scss
+ to see the available utility classes.
+**/
+@import 'utilities';
+
+// Gitlab UI util classes
+@import '@gitlab/ui/src/scss/utilities';
diff --git a/app/assets/stylesheets/application_utilities_dark.scss b/app/assets/stylesheets/application_utilities_dark.scss
new file mode 100644
index 00000000000..eb32cdfc444
--- /dev/null
+++ b/app/assets/stylesheets/application_utilities_dark.scss
@@ -0,0 +1,3 @@
+@import './themes/dark';
+
+@import 'application_utilities';
diff --git a/app/assets/stylesheets/components/design_management/design.scss b/app/assets/stylesheets/components/design_management/design.scss
index 21133316291..81f2091e915 100644
--- a/app/assets/stylesheets/components/design_management/design.scss
+++ b/app/assets/stylesheets/components/design_management/design.scss
@@ -1,3 +1,6 @@
+$design-pin-diameter: 28px;
+$t-gray-a-16-design-pin: rgba($black, 0.16);
+
.layout-page.design-detail-layout {
max-height: 100vh;
}
@@ -9,34 +12,61 @@
top: 35px;
}
- .design-pin {
- transition: opacity $gl-transition-duration-medium $general-hover-transition-curve;
-
- &.inactive {
- @include gl-opacity-5;
-
- &:hover {
- @include gl-opacity-10;
- }
- }
- }
-
.badge.badge-pill {
display: flex;
- height: 28px;
- width: 28px;
- background-color: $blue-400;
+ height: $design-pin-diameter;
+ width: $design-pin-diameter;
+ box-sizing: content-box;
+ background-color: $purple-500;
color: $white;
- border: $white 1px solid;
+ font-weight: $gl-font-weight-bold;
border-radius: 50%;
+ z-index: 1;
+ padding: 0;
&.resolved {
background-color: $gray-500;
}
}
- .design-detail-overlay-add-comment {
- cursor: crosshair;
+ .comment-indicator {
+ border-radius: 50%;
+ }
+
+ .comment-indicator,
+ .frame .badge.badge-pill {
+ &:active {
+ cursor: grabbing;
+ }
+ }
+
+ /**
+ * Design pin that overlays the design
+ */
+ .frame .badge.badge-pill {
+ box-shadow: 0 2px 4px $t-gray-a-08, 0 0 1px $t-gray-a-24;
+ border: $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;
+ }
+ }
}
}
@@ -105,8 +135,8 @@
border-left: 1px solid $gray-100;
position: absolute;
left: 28px;
- top: -18px;
- height: 18px;
+ top: -17px;
+ height: 17px;
}
.design-note {
@@ -152,6 +182,10 @@
}
}
+.design-card-header {
+ background: transparent;
+}
+
.design-dropzone-border {
border: 2px dashed $gray-100;
}
diff --git a/app/assets/stylesheets/components/rich_content_editor.scss b/app/assets/stylesheets/components/rich_content_editor.scss
index b1189137d59..d97a9bc227d 100644
--- a/app/assets/stylesheets/components/rich_content_editor.scss
+++ b/app/assets/stylesheets/components/rich_content_editor.scss
@@ -44,3 +44,11 @@
@include gl-line-height-20;
}
}
+
+/**
+* Styling below ensures that YouTube videos are displayed in the editor the same as they would in about.gitlab.com
+* https://gitlab.com/gitlab-com/www-gitlab-com/-/blob/master/source/stylesheets/_base.scss#L977
+*/
+.video_container {
+ padding-bottom: 56.25%;
+}
diff --git a/app/assets/stylesheets/components/whats_new.scss b/app/assets/stylesheets/components/whats_new.scss
index 4fff900f5a5..6c58346b750 100644
--- a/app/assets/stylesheets/components/whats_new.scss
+++ b/app/assets/stylesheets/components/whats_new.scss
@@ -1,9 +1,32 @@
+.whats-new-drawer {
+ margin-top: $header-height;
+ @include gl-shadow-none;
+}
+
+.with-performance-bar .whats-new-drawer {
+ margin-top: calc(#{$performance-bar-height} + #{$header-height});
+}
+
.gl-badge.whats-new-item-badge {
background-color: $purple-light;
color: $purple;
- font-weight: bold;
+ @include gl-font-weight-bold;
}
.whats-new-item-image {
border-color: $gray-50;
}
+
+.whats-new-modal-backdrop {
+ z-index: 9;
+}
+
+.whats-new-notification-count {
+ @include gl-bg-gray-900;
+ @include gl-font-sm;
+ @include gl-line-height-normal;
+ @include gl-text-white;
+ @include gl-vertical-align-top;
+ border-radius: 20px;
+ padding: 3px 10px;
+}
diff --git a/app/assets/stylesheets/fontawesome_custom.scss b/app/assets/stylesheets/fontawesome_custom.scss
index 46e5e5a28ea..a3338ff13b5 100644
--- a/app/assets/stylesheets/fontawesome_custom.scss
+++ b/app/assets/stylesheets/fontawesome_custom.scss
@@ -88,11 +88,6 @@
content: '\f078';
}
-.fa-remove::before,
-.fa-times::before {
- content: '\f00d';
-}
-
.fa-caret-down::before {
content: '\f0d7';
}
@@ -101,10 +96,6 @@
content: '\f00c';
}
-.fa-search::before {
- content: '\f002';
-}
-
.fa-warning::before,
.fa-exclamation-triangle::before {
content: '\f071';
@@ -118,18 +109,6 @@
content: '\f110';
}
-.fa-calendar::before {
- content: '\f073';
-}
-
-.fa-angle-double-right::before {
- content: '\f101';
-}
-
-.fa-angle-double-left::before {
- content: '\f100';
-}
-
.fa-trash-o::before {
content: '\f014';
}
@@ -146,14 +125,6 @@
content: '\f077';
}
-.fa-file-text-o::before {
- content: '\f0f6';
-}
-
-.fa-github::before {
- content: '\f09b';
-}
-
.fa-paperclip::before {
content: '\f0c6';
}
@@ -162,10 +133,6 @@
content: '\f188';
}
-.fa-google::before {
- content: '\f1a0';
-}
-
.fa-exclamation-circle::before {
content: '\f06a';
}
@@ -174,10 +141,6 @@
content: '\f0f3';
}
-.fa-bitbucket-square::before {
- content: '\f172';
-}
-
.fa-file-o::before {
content: '\f016';
}
@@ -190,22 +153,10 @@
content: '\f111';
}
-.fa-bitbucket::before {
- content: '\f171';
-}
-
.fa-git::before {
content: '\f1d3';
}
-.fa-folder::before {
- content: '\f07b';
-}
-
-.fa-archive::before {
- content: '\f187';
-}
-
.fa-thumb-tack::before {
content: '\f08d';
}
@@ -214,10 +165,6 @@
content: '\f06d';
}
-.fa-globe::before {
- content: '\f0ac';
-}
-
.fa-pause::before {
content: '\f04c';
}
@@ -226,14 +173,6 @@
content: '\f04b';
}
-.fa-search-plus::before {
- content: '\f00e';
-}
-
-.fa-search-minus::before {
- content: '\f010';
-}
-
.fa-share::before {
content: '\f064';
}
@@ -258,10 +197,6 @@
content: '\f081';
}
-.fa-unlink::before {
- content: '\f127';
-}
-
.fa-file-pdf-o::before {
content: '\f1c1';
}
diff --git a/app/assets/stylesheets/framework.scss b/app/assets/stylesheets/framework.scss
index f875420b9c9..e40b95cdce6 100644
--- a/app/assets/stylesheets/framework.scss
+++ b/app/assets/stylesheets/framework.scss
@@ -70,3 +70,4 @@
@import 'framework/spinner';
@import 'framework/card';
@import 'framework/editor-lite';
+@import 'framework/diffs';
diff --git a/app/assets/stylesheets/framework/animations.scss b/app/assets/stylesheets/framework/animations.scss
index 136ff82e0f8..196fb3a7088 100644
--- a/app/assets/stylesheets/framework/animations.scss
+++ b/app/assets/stylesheets/framework/animations.scss
@@ -112,8 +112,7 @@ a {
}
.dropdown-menu a,
-.dropdown-menu button,
-.dropdown-menu-nav a {
+.dropdown-menu button {
transition: none;
}
diff --git a/app/assets/stylesheets/framework/buttons.scss b/app/assets/stylesheets/framework/buttons.scss
index a9c1652d00d..a8cc685d880 100644
--- a/app/assets/stylesheets/framework/buttons.scss
+++ b/app/assets/stylesheets/framework/buttons.scss
@@ -417,12 +417,6 @@
}
}
-@include media-breakpoint-down(xs) {
- .btn-wide-on-xs {
- width: 100%;
- }
-}
-
.btn-blank {
padding: 0;
background: transparent;
diff --git a/app/assets/stylesheets/framework/common.scss b/app/assets/stylesheets/framework/common.scss
index 714ef8b2175..8dbed9c03f2 100644
--- a/app/assets/stylesheets/framework/common.scss
+++ b/app/assets/stylesheets/framework/common.scss
@@ -324,15 +324,8 @@ img.emoji {
}
.project-item-select-holder {
- display: inline-block;
- position: relative;
-
.project-item-select {
- position: absolute;
- top: 0;
- right: 0;
min-width: 250px;
- visibility: hidden;
}
}
@@ -428,7 +421,6 @@ img.emoji {
/** COMMON SIZING CLASSES **/
.w-0 { width: 0; }
.w-8em { width: 8em; }
-.w-3rem { width: 3rem; }
.w-15p { width: 15%; }
.w-30p { width: 30%; }
.w-60p { width: 60%; }
diff --git a/app/assets/stylesheets/framework/contextual_sidebar.scss b/app/assets/stylesheets/framework/contextual_sidebar.scss
index 7004bcc121d..48252762546 100644
--- a/app/assets/stylesheets/framework/contextual_sidebar.scss
+++ b/app/assets/stylesheets/framework/contextual_sidebar.scss
@@ -363,20 +363,30 @@
// Collapsed nav
.toggle-sidebar-button,
-.close-nav-button {
- width: $contextual-sidebar-width - 1px;
+.close-nav-button,
+.toggle-right-sidebar-button {
transition: width $sidebar-transition-duration;
- position: fixed;
height: $toggle-sidebar-height;
- bottom: 0;
padding: 0 $gl-padding;
background-color: $gray-light;
border: 0;
- border-top: 1px solid $border-color;
color: $gl-text-color-secondary;
display: flex;
align-items: center;
+ &:hover {
+ background-color: $border-color;
+ color: $gl-text-color;
+ }
+}
+
+.toggle-sidebar-button,
+.close-nav-button {
+ position: fixed;
+ bottom: 0;
+ width: $contextual-sidebar-width - 1px;
+ border-top: 1px solid $border-color;
+
svg {
margin-right: 8px;
}
@@ -384,11 +394,10 @@
.icon-chevron-double-lg-right {
display: none;
}
+}
- &:hover {
- background-color: $border-color;
- color: $gl-text-color;
- }
+.toggle-right-sidebar-button {
+ border-bottom: 1px solid $border-color;
}
.collapse-text {
diff --git a/app/assets/stylesheets/framework/diffs.scss b/app/assets/stylesheets/framework/diffs.scss
new file mode 100644
index 00000000000..c0a2350d080
--- /dev/null
+++ b/app/assets/stylesheets/framework/diffs.scss
@@ -0,0 +1,1129 @@
+// Common
+.diff-file {
+ margin-bottom: $gl-padding;
+
+ &.conflict {
+ border-top: 1px solid $border-color;
+ }
+
+ .file-title,
+ .file-title-flex-parent {
+ border-top-left-radius: $border-radius-default;
+ border-top-right-radius: $border-radius-default;
+ box-shadow: 0 -2px 0 0 var(--white);
+ cursor: pointer;
+
+ .dropdown-menu {
+ cursor: auto;
+ }
+
+ @media (max-width: map-get($grid-breakpoints, sm)-1) {
+ .file-header-content {
+ width: 0;
+ flex: 1;
+ }
+
+ .file-actions {
+ margin-left: $gl-spacing-scale-2;
+ }
+ }
+
+ @media (min-width: map-get($grid-breakpoints, md)) {
+ // The `+11` is to ensure the file header border shows when scrolled -
+ // the bottom of the compare-versions header and the top of the file header
+ $mr-file-header-top: $mr-version-controls-height + $header-height + $mr-tabs-height + 11;
+
+ position: -webkit-sticky;
+ position: sticky;
+ top: $mr-file-header-top;
+ z-index: 120;
+
+ .with-system-header & {
+ top: $mr-file-header-top + $system-header-height;
+ }
+
+ .with-system-header.with-performance-bar & {
+ top: $mr-file-header-top + $system-header-height + $performance-bar-height;
+ }
+
+ &::before {
+ content: '';
+ position: absolute;
+ top: -1px;
+ left: -11px;
+ width: 10px;
+ height: calc(100% + 1px);
+ background: $white;
+ pointer-events: none;
+ }
+
+ .with-performance-bar & {
+ top: $mr-file-header-top + $performance-bar-height;
+ }
+
+ &.is-commit {
+ top: $header-height + $commit-stat-summary-height;
+
+ .with-performance-bar & {
+ top: $header-height + $commit-stat-summary-height + $performance-bar-height;
+ }
+ }
+
+ &.is-compare {
+ top: $header-height + $compare-branches-sticky-header-height;
+
+ .with-performance-bar & {
+ top: $performance-bar-height + $header-height + $compare-branches-sticky-header-height;
+ }
+ }
+ }
+
+ &:hover {
+ background-color: $gray-normal;
+ }
+
+ svg {
+ vertical-align: middle;
+ top: -1px;
+ }
+ }
+
+ @media (min-width: map-get($grid-breakpoints, md)) {
+ &.conflict .file-title,
+ &.conflict .file-title-flex-parent {
+ top: $header-height;
+ }
+
+ .with-performance-bar &.conflict .file-title,
+ .with-performance-bar &.conflict .file-title-flex-parent {
+ top: $header-height + $performance-bar-height;
+ }
+
+ .with-system-header &.conflict .file-title,
+ .with-system-header &.conflict .file-title-flex-parent {
+ top: $header-height + $system-header-height;
+ }
+
+ .with-system-header.with-performance-bar &.conflict .file-title,
+ .with-system-header.with-performance-bar &.conflict .file-title-flex-parent {
+ top: $header-height + $performance-bar-height + $system-header-height;
+ }
+ }
+
+ .diff-content {
+ background: $white;
+ color: $gl-text-color;
+ border-radius: 0 0 3px 3px;
+
+ .unfold {
+ cursor: pointer;
+ }
+
+ .file-mode-changed {
+ padding: 10px;
+ color: $gray-500;
+ }
+
+ .suppressed-container {
+ padding: ($padding-base-vertical + 5px) $padding-base-horizontal;
+ text-align: center;
+
+ // "Changes suppressed. Click to show." link
+ .show-suppressed-diff {
+ font-size: 110%;
+ font-weight: $gl-font-weight-bold;
+ }
+ }
+
+ .diff-loading-error-block {
+ padding: $gl-padding * 2 $gl-padding;
+ text-align: center;
+ }
+ }
+
+ .image {
+ background: $gray-darker;
+ text-align: center;
+ padding: 30px;
+
+ .wrap {
+ display: inline-block;
+ }
+
+ .frame {
+ display: inline-block;
+ background-color: $white;
+ line-height: 0;
+
+ img {
+ border: 1px solid $white;
+ background-image: linear-gradient(45deg,
+ $border-color 25%,
+ transparent 25%,
+ transparent 75%,
+ $border-color 75%,
+ $border-color 100%),
+ linear-gradient(45deg,
+ $border-color 25%,
+ transparent 25%,
+ transparent 75%,
+ $border-color 75%,
+ $border-color 100%);
+ background-size: 10px 10px;
+ background-position: 0 0, 5px 5px;
+ max-width: 100%;
+ }
+
+ &.deleted {
+ border: 1px solid $deleted;
+ }
+
+ &.added {
+ border: 1px solid $added;
+ }
+ }
+
+ .image-info {
+ font-size: 12px;
+ margin: 5px 0 0;
+ color: $diff-image-info-color;
+ }
+
+ .view.swipe {
+ position: relative;
+
+ .swipe-frame {
+ display: block;
+ margin: auto;
+ position: relative;
+ }
+
+ .swipe-wrap {
+ overflow: hidden;
+ border-right: 1px solid $gray-300;
+ position: absolute;
+ display: block;
+ top: 13px;
+ right: 7px;
+
+ &.left-oriented {
+ /* only for commit view (different swipe viewer) */
+ border-right: 0;
+ border-left: 1px solid $gray-300;
+ }
+ }
+
+ .frame {
+ top: 0;
+ right: 0;
+
+ &.old-diff {
+ /* only for commit / compare view */
+ position: absolute;
+ }
+
+ &.deleted {
+ margin: 0;
+ display: block;
+ top: 13px;
+ right: 7px;
+ }
+ }
+
+ .swipe-bar {
+ display: block;
+ height: 100%;
+ width: 15px;
+ z-index: 100;
+ position: absolute;
+ cursor: pointer;
+
+ &:hover {
+ .top-handle {
+ background-position: -15px 3px;
+ }
+
+ .bottom-handle {
+ background-position: -15px -11px;
+ }
+ }
+
+ .top-handle {
+ display: block;
+ height: 14px;
+ width: 15px;
+ position: absolute;
+ top: 0;
+ background: image-url('swipemode_sprites.gif') 0 3px no-repeat;
+ }
+
+ .bottom-handle {
+ display: block;
+ height: 14px;
+ width: 15px;
+ position: absolute;
+ bottom: 0;
+ background: image-url('swipemode_sprites.gif') 0 -11px no-repeat;
+ }
+ }
+ }
+
+ //.view.swipe
+ .view.onion-skin {
+ .onion-skin-frame {
+ display: block;
+ margin: auto;
+ position: relative;
+ }
+
+ .frame.added,
+ .frame.deleted {
+ position: absolute;
+ display: block;
+ top: 0;
+ left: 0;
+ }
+
+ .controls {
+ display: block;
+ height: 14px;
+ width: 300px;
+ z-index: 100;
+ position: absolute;
+ bottom: 0;
+ left: 50%;
+ margin-left: -150px;
+
+ .drag-track {
+ display: block;
+ position: absolute;
+ top: 0;
+ left: 12px;
+ height: 10px;
+ width: 276px;
+ background: image-url('onion_skin_sprites.gif') -4px -20px repeat-x;
+ }
+
+ .dragger {
+ display: block;
+ position: absolute;
+ left: 0;
+ top: 0;
+ height: 14px;
+ width: 14px;
+ background: image-url('onion_skin_sprites.gif') 0 -34px repeat-x;
+ cursor: pointer;
+ }
+
+ .transparent {
+ display: block;
+ position: absolute;
+ top: 2px;
+ right: 0;
+ height: 10px;
+ width: 10px;
+ background: image-url('onion_skin_sprites.gif') -2px 0 no-repeat;
+ }
+
+ .opaque {
+ display: block;
+ position: absolute;
+ top: 2px;
+ left: 0;
+ height: 10px;
+ width: 10px;
+ background: image-url('onion_skin_sprites.gif') -2px -10px no-repeat;
+ }
+ }
+ }
+
+ //.view.onion-skin
+ }
+
+ .view-modes {
+ padding: 10px;
+ text-align: center;
+ background: $gray-darker;
+
+ ul,
+ li {
+ list-style: none;
+ margin: 0;
+ padding: 0;
+ display: inline-block;
+ }
+
+ li {
+ color: $diff-view-modes-color;
+ border-left: 1px solid $diff-view-modes-border;
+ padding: 0 12px 0 16px;
+ cursor: pointer;
+
+ &:first-child {
+ border-left: 0;
+ }
+
+ &:hover {
+ text-decoration: underline;
+ }
+
+ &.active {
+ cursor: default;
+ color: $gl-text-color;
+
+ &:hover {
+ text-decoration: none;
+ }
+ }
+
+ &.disabled {
+ display: none;
+ }
+ }
+ }
+
+ .diff-file-container {
+ .frame.deleted {
+ border: 1px solid $deleted;
+ background-color: inherit;
+ }
+
+ .frame.added {
+ border: 1px solid $added;
+ background-color: inherit;
+ }
+
+ .swipe.view,
+ .onion-skin.view {
+ .swipe-wrap {
+ top: 0;
+ left: 0;
+ }
+
+ .frame.deleted {
+ top: 0;
+ right: 0;
+ }
+
+ .swipe-bar {
+ top: 0;
+
+ .top-handle {
+ top: -14px;
+ left: -7px;
+ }
+
+ .bottom-handle {
+ bottom: -14px;
+ left: -7px;
+ }
+ }
+
+ .file-container {
+ display: inline-block;
+
+ .file-content {
+ padding: 0;
+
+ img {
+ max-width: none;
+ }
+ }
+ }
+ }
+
+ .onion-skin.view .controls {
+ bottom: -25px;
+ }
+ }
+
+ .discussion-notes .discussion-notes {
+ margin-left: 0;
+ border-left: 0;
+ }
+}
+
+table.code {
+ width: 100%;
+ font-family: $monospace-font;
+ border: 0;
+ border-collapse: separate;
+ margin: 0;
+ padding: 0;
+ table-layout: fixed;
+ border-radius: 0 0 $border-radius-default $border-radius-default;
+
+ tr:first-of-type.line_expansion > td {
+ border-top: 0;
+ }
+
+ tr:nth-last-of-type(2).line_expansion > td {
+ border-bottom: 0;
+ }
+
+ tr.line_holder td {
+ line-height: $code-line-height;
+ font-size: $code-font-size;
+ vertical-align: top;
+
+ span {
+ white-space: break-spaces;
+
+ &.context-cell {
+ display: inline-block;
+ width: 100%;
+ height: 100%;
+ }
+
+ &.line {
+ word-wrap: break-word;
+ }
+ }
+
+ &.diff-line-num {
+ user-select: none;
+ margin: 0;
+ padding: 0 10px 0 5px;
+ border-right-width: 1px;
+ border-right-style: solid;
+ text-align: right;
+ width: 50px;
+ position: relative;
+ white-space: nowrap;
+
+ a {
+ transition: none;
+ float: left;
+ width: 100%;
+ font-weight: $gl-font-weight-normal;
+
+ &[disabled] {
+ cursor: default;
+
+ &:hover,
+ &:active {
+ text-decoration: none;
+ }
+ }
+ }
+
+ &:not(.js-unfold-bottom) a::before {
+ content: attr(data-linenumber);
+ }
+ }
+
+ &.line_content {
+ display: block;
+ margin: 0;
+ padding: 0 1.5em;
+ border: 0;
+ position: relative;
+ white-space: pre-wrap;
+
+ &.parallel {
+ display: table-cell;
+ width: 46%;
+
+ span {
+ word-break: break-all;
+ }
+ }
+
+ &.old {
+ &::before {
+ content: '-';
+ position: absolute;
+ left: 0.5em;
+ }
+
+ &.with-coverage::before {
+ left: 0;
+ }
+ }
+
+ &.new {
+ &::before {
+ content: '+';
+ position: absolute;
+ left: 0.5em;
+ }
+
+ &.with-coverage::before {
+ left: 0;
+ }
+ }
+ }
+ }
+
+ .line_holder:last-of-type {
+ td:first-child {
+ border-bottom-left-radius: $border-radius-default;
+ }
+ }
+
+ &.left-side-selected {
+ td.line_content.parallel.right-side {
+ user-select: none;
+ }
+ }
+
+ &.right-side-selected {
+ td.line_content.parallel.left-side {
+ user-select: none;
+ }
+ }
+}
+
+.diff-stats {
+ align-items: center;
+ padding: 0 1rem;
+
+ .diff-stats-group {
+ padding: 0 0.25rem;
+ }
+
+ svg.diff-stats-icon {
+ vertical-align: text-bottom;
+ }
+
+ &.is-compare-versions-header {
+ .diff-stats-group {
+ padding: 0 0.25rem;
+ }
+ }
+}
+
+.file-content .diff-file {
+ margin: 0;
+ border: 0;
+}
+
+.diff-wrap-lines .line_content {
+ white-space: pre-wrap;
+}
+
+.inline-parallel-buttons {
+ float: right;
+}
+
+.files-changed {
+ border-bottom: 0;
+}
+
+.merge-request-details .file-content.image_file img {
+ max-height: 50vh;
+}
+
+.diff-stats-summary-toggler {
+ padding: 0;
+ background-color: transparent;
+ border: 0;
+ color: $blue-600;
+ font-weight: $gl-font-weight-bold;
+
+ &:hover,
+ &:focus {
+ outline: none;
+ color: $blue-800;
+ }
+
+ .caret-icon {
+ position: relative;
+ top: 2px;
+ left: -1px;
+ }
+}
+
+// Mobile
+@media (max-width: 480px) {
+ .diff-title {
+ margin: 0;
+
+ .file-mode {
+ display: none;
+ }
+ }
+
+ .diff-controls {
+ position: static;
+ text-align: center;
+ }
+}
+
+// Bigger screens
+@media (min-width: 481px) {
+ .diff-title {
+ margin-right: 200px;
+
+ .file-mode {
+ margin-left: 10px;
+ }
+ }
+
+ .diff-controls {
+ float: right;
+ position: absolute;
+ top: 5px;
+ right: 15px;
+ }
+}
+
+.files {
+ .diff-file:last-child {
+ margin-bottom: 0;
+ }
+}
+
+.diff-comment-avatar-holders {
+ position: absolute;
+ margin-left: -$gl-padding;
+ z-index: 100;
+ @include code-icon-size();
+
+ &:hover {
+ .diff-comment-avatar,
+ .diff-comments-more-count {
+ @for $i from 1 through 4 {
+ $x-pos: 14px;
+
+ &:nth-child(#{$i}) {
+ @if $i == 4 {
+ $x-pos: 14.5px;
+ }
+
+ transform: translateX((($i * $x-pos) - $x-pos));
+
+ &:hover {
+ transform: translateX((($i * $x-pos) - $x-pos));
+ }
+ }
+ }
+ }
+
+ .diff-comments-more-count {
+ padding-left: 2px;
+ padding-right: 2px;
+ width: auto;
+ }
+ }
+}
+
+.diff-comment-avatar,
+.diff-comments-more-count {
+ position: absolute;
+ left: 0;
+ margin-right: 0;
+ border-color: $white;
+ cursor: pointer;
+ transition: all 0.1s ease-out;
+ @include code-icon-size();
+
+ @for $i from 1 through 4 {
+ &:nth-child(#{$i}) {
+ z-index: (4 - $i);
+ }
+ }
+
+ .avatar {
+ @include code-icon-size();
+ }
+}
+
+.diff-comments-more-count {
+ padding-left: 0;
+ padding-right: 0;
+ overflow: hidden;
+ @include code-icon-size();
+}
+
+.diff-comments-more-count,
+.diff-notes-collapse {
+ @include avatar-counter(50%);
+}
+
+.diff-notes-collapse {
+ border: 0;
+ border-radius: 50%;
+ padding: 0;
+ transition: transform 0.1s ease-out;
+ z-index: 100;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ @include code-icon-size();
+
+ .collapse-icon {
+ height: 50%;
+ width: 100%;
+ }
+
+ svg {
+ vertical-align: middle;
+ }
+
+ .collapse-icon,
+ path {
+ fill: $white;
+ }
+
+ &:focus {
+ outline: 0;
+ }
+}
+
+.diff-files-changed {
+ .inline-parallel-buttons {
+ position: relative;
+ z-index: 1;
+ }
+
+ .commit-stat-summary {
+ @include media-breakpoint-up(sm) {
+ margin-left: -$gl-padding;
+ padding-left: $gl-padding;
+ background-color: $white;
+ }
+ }
+
+ @include media-breakpoint-up(sm) {
+ position: -webkit-sticky;
+ position: sticky;
+ top: $header-height;
+ background-color: $white;
+ z-index: 200;
+
+ .with-performance-bar & {
+ top: $header-height + $performance-bar-height;
+ }
+
+ &.is-stuck {
+ padding-top: 0;
+ padding-bottom: 0;
+ border-top: 1px solid $white-dark;
+ border-bottom: 1px solid $white-dark;
+
+ .diff-stats-additions-deletions-expanded,
+ .inline-parallel-buttons {
+ display: none !important;
+ }
+ }
+ }
+
+ @include media-breakpoint-up(lg) {
+ &.is-stuck {
+ .diff-stats-additions-deletions-collapsed {
+ display: block !important;
+ }
+ }
+ }
+}
+
+.diff-file-changes {
+ max-width: 560px;
+ width: 100%;
+ z-index: 150;
+ min-height: $dropdown-min-height;
+ max-height: $dropdown-max-height;
+ overflow-y: auto;
+ margin-bottom: 0;
+
+ @include media-breakpoint-up(sm) {
+ left: $gl-padding;
+ }
+
+ .dropdown-input .dropdown-input-search {
+ pointer-events: all;
+ }
+
+ .diff-changed-file {
+ display: flex;
+ padding-top: 8px;
+ padding-bottom: 8px;
+ min-width: 0;
+ }
+
+ .diff-file-changed-icon {
+ margin-top: 2px;
+ }
+
+ .diff-changed-file-content {
+ display: flex;
+ flex-direction: column;
+ min-width: 0;
+ }
+
+ .diff-changed-file-name,
+ .diff-changed-blank-file-name {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
+
+ .diff-changed-blank-file-name {
+ color: $gl-text-color-tertiary;
+ font-style: italic;
+ }
+
+ .diff-changed-file-path {
+ color: $gl-text-color-tertiary;
+ }
+
+ .diff-changed-stats {
+ margin-left: auto;
+ white-space: nowrap;
+ }
+}
+
+.diff-file-changes-path {
+ flex: 1;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.note-container {
+ background-color: $gray-light;
+ border-top: 1px solid $white-normal;
+
+ // double jagged line divider
+ .discussion-notes + .discussion-notes::before,
+ .diff-file-discussions + .discussion-form::before {
+ content: '';
+ position: relative;
+ display: block;
+ width: 100%;
+ height: 10px;
+ background-color: $white;
+ background-image: linear-gradient(45deg,
+ transparent,
+ transparent 73%,
+ $diff-jagged-border-gradient-color 75%,
+ $white 80%),
+ linear-gradient(225deg,
+ transparent,
+ transparent 73%,
+ $diff-jagged-border-gradient-color 75%,
+ $white 80%),
+ linear-gradient(135deg,
+ transparent,
+ transparent 73%,
+ $diff-jagged-border-gradient-color 75%,
+ $white 80%),
+ linear-gradient(-45deg,
+ transparent,
+ transparent 73%,
+ $diff-jagged-border-gradient-color 75%,
+ $white 80%);
+ background-position: 5px 5px, 0 5px, 0 5px, 5px 5px;
+ background-size: 10px 10px;
+ background-repeat: repeat;
+ }
+
+ .diff-file-discussions + .discussion-form {
+ padding: $gl-padding;
+
+ &::before {
+ width: auto;
+ margin-left: -$gl-padding;
+ margin-right: -$gl-padding;
+ margin-bottom: $gl-padding;
+ }
+ }
+
+ .notes {
+ position: relative;
+ }
+
+ .diff-notes-collapse {
+ position: absolute;
+ left: -12px;
+ }
+}
+
+.diff-file .note-container > .new-note,
+.note-container .discussion-notes.diff-discussions {
+ margin-left: 100px;
+ border-left: 1px solid $white-normal;
+}
+
+.notes.active {
+ .diff-file .note-container > .new-note,
+ .note-container .discussion-notes {
+ // Override our margin and border (set for diff tab)
+ // when user is on the discussion tab for MR
+ margin-left: inherit;
+ border-left: inherit;
+ }
+}
+
+.files:not([data-can-create-note]) .frame {
+ cursor: auto;
+}
+
+.frame.click-to-comment,
+.btn-transparent.image-diff-overlay-add-comment {
+ position: relative;
+ cursor: image-url('illustrations/image_comment_light_cursor.svg') $image-comment-cursor-left-offset $image-comment-cursor-top-offset,
+ auto;
+
+ // Retina cursor
+ // scss-lint:disable DuplicateProperty
+ cursor: image-set(image-url('illustrations/image_comment_light_cursor.svg') 1x,
+ image-url('illustrations/image_comment_light_cursor@2x.svg') 2x) $image-comment-cursor-left-offset $image-comment-cursor-top-offset,
+ auto;
+
+ .comment-indicator {
+ position: absolute;
+ padding: 0;
+ width: (2px * $image-comment-cursor-left-offset);
+ height: (2px * $image-comment-cursor-top-offset);
+ color: $blue-400;
+ // center the indicator to match the top left click region
+ margin-top: (-1px * $image-comment-cursor-top-offset) + 2;
+ margin-left: (-1px * $image-comment-cursor-left-offset) + 1;
+
+ svg {
+ width: 100%;
+ height: 100%;
+ }
+
+ &:focus {
+ outline: none;
+ }
+ }
+}
+
+.frame .badge.badge-pill,
+.image-diff-avatar-link .badge.badge-pill,
+.user-avatar-link .badge.badge-pill,
+.notes > .badge.badge-pill {
+ position: absolute;
+ background-color: $blue-400;
+ color: $white;
+ border: $white 1px solid;
+ min-height: $gl-padding;
+ padding: 5px 8px;
+ border-radius: 12px;
+
+ &:focus {
+ outline: none;
+ }
+}
+
+.frame .badge.badge-pill,
+.frame .image-comment-badge,
+.frame .comment-indicator {
+ // Center align badges on the frame
+ transform: translate(-50%, -50%);
+}
+
+.image-comment-badge {
+ position: absolute;
+ width: 24px;
+ height: 24px;
+ padding: 0;
+ background: none;
+ border: 0;
+
+ > svg {
+ width: 100%;
+ height: 100%;
+ }
+}
+
+.image-diff-avatar-link,
+.user-avatar-link {
+ position: relative;
+
+ .badge.badge-pill,
+ .image-comment-badge {
+ top: 25px;
+ right: 8px;
+ }
+}
+
+.notes > .badge.badge-pill {
+ display: none;
+ left: -13px;
+}
+
+.discussion-notes {
+ min-height: 35px;
+
+ &:first-child {
+ // First child does not have the jagged borders
+ min-height: 25px;
+ }
+
+ &.collapsed {
+ background-color: $white;
+
+ .diff-notes-collapse,
+ .note,
+ .discussion-reply-holder {
+ display: none;
+ }
+
+ .notes > .badge.badge-pill {
+ display: block;
+ }
+ }
+
+ .note-edit-form {
+ margin-left: $note-icon-gutter-width;
+ }
+}
+
+.discussion-body .image .frame {
+ position: relative;
+}
+
+.discussion-collapsible {
+ margin: 0 $gl-padding $gl-padding 71px;
+
+ .notes {
+ border-radius: $border-radius-default;
+ }
+}
+
+.parallel {
+ .discussion-collapsible {
+ margin: $gl-padding;
+ margin-top: 0;
+ }
+}
+
+.image-diff-overlay,
+.image-diff-overlay-add-comment {
+ top: 0;
+ left: 0;
+
+ &:active,
+ &:focus {
+ outline: 0;
+ }
+}
+
+.diff-suggest-popover {
+ &.popover {
+ width: 250px;
+ min-width: 250px;
+ z-index: 210;
+ }
+
+ .popover-header {
+ display: none;
+ }
+}
+
+@media (max-width: map-get($grid-breakpoints, md)-1) {
+ .diffs .files {
+ @include fixed-width-container;
+ flex-direction: column;
+ }
+
+ .discussion-collapsible {
+ margin: $gl-padding;
+ margin-top: 0;
+ }
+}
diff --git a/app/assets/stylesheets/framework/dropdowns.scss b/app/assets/stylesheets/framework/dropdowns.scss
index ad5864ef6d9..e8d37fcf40b 100644
--- a/app/assets/stylesheets/framework/dropdowns.scss
+++ b/app/assets/stylesheets/framework/dropdowns.scss
@@ -33,8 +33,7 @@
}
.show.dropdown {
- .dropdown-menu,
- .dropdown-menu-nav {
+ .dropdown-menu {
@include set-visible;
min-height: $dropdown-min-height;
max-height: $dropdown-max-height;
@@ -190,15 +189,6 @@
background-color: $gray-darker;
color: $gl-text-color;
outline: 0;
-
- // make sure the text color is not overridden
- &.text-danger {
- color: $brand-danger;
- }
-
- .avatar {
- border-color: $white;
- }
}
@mixin dropdown-link {
@@ -217,11 +207,6 @@
text-align: left;
width: 100%;
- // make sure the text color is not overridden
- &.text-danger {
- color: $brand-danger;
- }
-
&.disable-hover {
text-decoration: none;
}
@@ -233,10 +218,6 @@
@include dropdown-item-hover;
text-decoration: none;
-
- .badge.badge-pill {
- background-color: darken($blue-50, 5%);
- }
}
&.dropdown-menu-user-link {
@@ -258,8 +239,7 @@
}
}
-.dropdown-menu,
-.dropdown-menu-nav {
+.dropdown-menu {
display: none;
position: absolute;
width: auto;
@@ -393,49 +373,56 @@
pointer-events: none;
}
- .dropdown-menu li {
- cursor: pointer;
+ .dropdown-menu {
+ display: none;
+ opacity: 1;
+ visibility: visible;
+ transform: translateY(0);
- &.droplab-item-active button {
- @include dropdown-item-hover;
- }
+ li {
+ cursor: pointer;
- > a,
- > button {
- display: flex;
- margin: 0;
- text-overflow: inherit;
- text-align: left;
+ &.droplab-item-active button {
+ @include dropdown-item-hover;
+ }
- &.btn .fa:not(:last-child) {
- margin-left: 5px;
+ > a,
+ > button {
+ display: flex;
+ margin: 0;
+ text-overflow: inherit;
+ text-align: left;
+
+ &.btn .fa:not(:last-child) {
+ margin-left: 5px;
+ }
}
- }
- > button.dropdown-epic-button {
- flex-direction: column;
+ > button.dropdown-epic-button {
+ flex-direction: column;
- .reference {
- color: $gray-300;
- margin-top: $gl-padding-4;
+ .reference {
+ color: $gray-300;
+ margin-top: $gl-padding-4;
+ }
}
- }
- &.droplab-item-selected i {
- visibility: visible;
- }
+ &.droplab-item-selected i {
+ visibility: visible;
+ }
- .icon {
- visibility: hidden;
- }
+ .icon {
+ visibility: hidden;
+ }
- .description {
- display: inline-block;
- white-space: normal;
- margin-left: 5px;
+ .description {
+ display: inline-block;
+ white-space: normal;
+ margin-left: 5px;
- p {
- margin-bottom: 0;
+ p {
+ margin-bottom: 0;
+ }
}
}
}
@@ -447,21 +434,12 @@
}
}
-.droplab-dropdown .dropdown-menu,
-.droplab-dropdown .dropdown-menu-nav {
- display: none;
- opacity: 1;
- visibility: visible;
- transform: translateY(0);
-}
-
.comment-type-dropdown.show .dropdown-menu {
display: block;
}
.filtered-search-box-input-container {
- .dropdown-menu,
- .dropdown-menu-nav {
+ .dropdown-menu {
max-width: 280px;
}
}
@@ -850,8 +828,7 @@
}
header.navbar-gitlab .dropdown {
- .dropdown-menu,
- .dropdown-menu-nav {
+ .dropdown-menu {
width: 100%;
min-width: 100%;
}
diff --git a/app/assets/stylesheets/framework/editor-lite.scss b/app/assets/stylesheets/framework/editor-lite.scss
index 75d511d7f66..20fea7a82ca 100644
--- a/app/assets/stylesheets/framework/editor-lite.scss
+++ b/app/assets/stylesheets/framework/editor-lite.scss
@@ -1,5 +1,3 @@
-.monaco-editor.gl-editor-lite {
- .line-numbers {
- @include gl-pt-0;
- }
+[id^='editor-lite-'] {
+ height: 500px;
}
diff --git a/app/assets/stylesheets/framework/files.scss b/app/assets/stylesheets/framework/files.scss
index 76c6e03377c..f8710cc1346 100644
--- a/app/assets/stylesheets/framework/files.scss
+++ b/app/assets/stylesheets/framework/files.scss
@@ -50,7 +50,7 @@
right: 15px;
margin-left: auto;
- .btn {
+ .btn:not(.btn-icon) {
padding: 0 10px;
font-size: 13px;
line-height: 28px;
@@ -372,7 +372,7 @@ span.idiff {
color: $gl-text-color;
}
- .file-actions .btn {
+ .file-actions .btn:not(.btn-icon) {
padding: 0 10px;
font-size: 13px;
line-height: 28px;
diff --git a/app/assets/stylesheets/framework/filters.scss b/app/assets/stylesheets/framework/filters.scss
index 1a394ad124b..5f56fa3be86 100644
--- a/app/assets/stylesheets/framework/filters.scss
+++ b/app/assets/stylesheets/framework/filters.scss
@@ -355,28 +355,45 @@
background-color: $white;
}
- .boards-switcher {
- margin: 0 0 10px;
+ .filtered-search-block .boards-switcher {
+ @include gl-mr-0;
+ margin-bottom: $gl-input-padding;
.boards-selector-wrapper,
.dropdown {
- display: block;
+ @include gl-display-block;
}
}
.filter-dropdown-container {
> div {
- margin: 0;
+ @include gl-m-0;
> .btn {
- margin: 0 0 10px;
- width: 100%;
+ margin: 0 0 $gl-input-padding;
+ @include gl-w-full;
}
}
.board-labels-toggle-wrapper {
margin-bottom: $gl-input-padding;
}
+
+ .board-swimlanes-toggle-wrapper {
+ @include gl-h-auto;
+ margin-bottom: $gl-input-padding;
+
+ > span,
+ > .dropdown,
+ .gl-dropdown-toggle {
+ @include gl-w-full;
+ @include gl-m-0;
+ }
+
+ > .dropdown {
+ @include gl-mt-2;
+ }
+ }
}
.boards-add-list > .btn {
diff --git a/app/assets/stylesheets/framework/header.scss b/app/assets/stylesheets/framework/header.scss
index cf21c23cb17..52319d9658b 100644
--- a/app/assets/stylesheets/framework/header.scss
+++ b/app/assets/stylesheets/framework/header.scss
@@ -203,18 +203,6 @@
margin-right: 0;
}
}
-
- &:hover,
- &:focus {
- text-decoration: none;
- outline: 0;
- opacity: 1;
- color: $white;
-
- &.header-user-dropdown-toggle .header-user-avatar {
- border-color: $white;
- }
- }
}
.header-new-dropdown-toggle {
diff --git a/app/assets/stylesheets/framework/icons.scss b/app/assets/stylesheets/framework/icons.scss
index ec0755b1614..5623d38d66e 100644
--- a/app/assets/stylesheets/framework/icons.scss
+++ b/app/assets/stylesheets/framework/icons.scss
@@ -9,6 +9,7 @@
}
}
+.ci-status-icon-error,
.ci-status-icon-failed {
svg {
fill: $red-500;
diff --git a/app/assets/stylesheets/framework/mixins.scss b/app/assets/stylesheets/framework/mixins.scss
index 61e8c0d4718..63be2bdef8e 100644
--- a/app/assets/stylesheets/framework/mixins.scss
+++ b/app/assets/stylesheets/framework/mixins.scss
@@ -215,7 +215,7 @@
}
&.build-trace-rounded {
- border-radius: $border-radius-base;
+ border-radius: $gl-border-radius-base;
}
}
diff --git a/app/assets/stylesheets/framework/secondary_navigation_elements.scss b/app/assets/stylesheets/framework/secondary_navigation_elements.scss
index 292d57f132c..7ebc972ac37 100644
--- a/app/assets/stylesheets/framework/secondary_navigation_elements.scss
+++ b/app/assets/stylesheets/framework/secondary_navigation_elements.scss
@@ -28,10 +28,6 @@
text-decoration: none;
color: $black;
border-bottom: 2px solid $gray-darkest;
-
- .badge.badge-pill {
- color: $black;
- }
}
}
@@ -380,33 +376,11 @@
}
.project-item-select-holder.btn-group {
- display: flex;
- overflow: hidden;
- float: right;
-
- .new-project-item-link {
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
- }
-
.new-project-item-select-button {
- width: 32px;
+ max-width: 44px;
}
}
.empty-state .project-item-select-holder.btn-group {
- float: none;
- justify-content: center;
-
- .btn {
- // overrides styles applied to plain `.empty-state .btn`
- margin: 10px 0;
- max-width: 300px;
- width: auto;
-
- @include media-breakpoint-down(xs) {
- max-width: 250px;
- }
- }
+ max-width: 320px;
}
diff --git a/app/assets/stylesheets/framework/snippets.scss b/app/assets/stylesheets/framework/snippets.scss
index 4c1c9d15121..47184804353 100644
--- a/app/assets/stylesheets/framework/snippets.scss
+++ b/app/assets/stylesheets/framework/snippets.scss
@@ -18,18 +18,6 @@
}
}
-.snippet-form-holder .file-holder .file-title {
- padding: 2px;
-}
-
-.markdown-snippet-copy {
- position: fixed;
- top: -10px;
- left: -10px;
- max-height: 0;
- max-width: 0;
-}
-
.snippet-file-content {
border-radius: 3px;
@@ -49,21 +37,6 @@
min-height: $header-height;
}
-.snippet-actions {
- @include media-breakpoint-up(sm) {
- float: right;
- }
-}
-
.snippet-scope-menu .btn-success {
margin-top: 15px;
}
-
-.embed-snippet {
- padding-right: 0;
- padding-top: $gl-padding;
-
- .embed-toggle-list li button {
- padding: 8px 40px;
- }
-}
diff --git a/app/assets/stylesheets/framework/tables.scss b/app/assets/stylesheets/framework/tables.scss
index 59e83608d9d..39d9e9a77f9 100644
--- a/app/assets/stylesheets/framework/tables.scss
+++ b/app/assets/stylesheets/framework/tables.scss
@@ -9,11 +9,15 @@ table {
* This is a temporary workaround until we fix the neutral
* color palette in https://gitlab.com/gitlab-org/gitlab/-/issues/213570
*
- * The overwrites here affected the security dashboard tables, when removing
- * this code, table-th-transparent and original-text-color classes should
- * be removed there.
+ * The overwrites here affected the following areas:
+ * - The security dashboard tables. When removing
+ * this code, table-th-transparent and original-text-color classes should
+ * be removed there.
+ * - The subscription seats table. When removing this code, the .seats-table
+ * <th> and margin overrides should be removed there.
*
* Remove this code as soon as this happens
+ *
*/
&.gl-table {
@include gl-text-gray-500;
@@ -186,6 +190,7 @@ table {
.checkbox {
padding-left: $gl-spacing-scale-4;
padding-right: 0;
+ width: 1px;
+ td,
+ th {
@@ -205,12 +210,20 @@ table {
width: 10%;
}
+ .description {
+ max-width: 0;
+ }
+
.identifier {
width: 16%;
}
.scanner {
- width: 15%;
+ width: 10%;
+ }
+
+ .activity {
+ width: 5%;
}
}
}
diff --git a/app/assets/stylesheets/framework/typography.scss b/app/assets/stylesheets/framework/typography.scss
index 8b5fa6c1b6c..c15d46d43b2 100644
--- a/app/assets/stylesheets/framework/typography.scss
+++ b/app/assets/stylesheets/framework/typography.scss
@@ -439,10 +439,6 @@
content: '\f0c6';
}
- &:hover::before {
- text-decoration: none;
- }
-
&.no-attachment-icon {
&::before {
display: none;
diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss
index 8cebfc430e0..f0b1e859139 100644
--- a/app/assets/stylesheets/framework/variables.scss
+++ b/app/assets/stylesheets/framework/variables.scss
@@ -780,7 +780,6 @@ $login-brand-holder-color: #888;
* Projects
*/
$project-option-descr-color: #54565b;
-$project-network-controls-color: #888;
/*
* Monitor Charts
@@ -819,7 +818,6 @@ $pipeline-dropdown-line-height: 20px;
$pipeline-dropdown-status-icon-size: 18px;
$ci-action-dropdown-button-size: 24px;
$ci-action-dropdown-svg-size: 12px;
-$pipelines-table-header-height: 40px;
/*
CI variable lists
@@ -868,9 +866,6 @@ $add-to-slack-popup-max-width: 400px;
$add-to-slack-gif-max-width: 850px;
$add-to-slack-well-max-width: 750px;
$add-to-slack-logo-size: 100px;
-$double-headed-arrow-width: 100px;
-$double-headed-arrow-height: 25px;
-$right-arrow-size: 16px;
/*
Popup
diff --git a/app/assets/stylesheets/framework/wells.scss b/app/assets/stylesheets/framework/wells.scss
index 55996a074c6..d550a1faa18 100644
--- a/app/assets/stylesheets/framework/wells.scss
+++ b/app/assets/stylesheets/framework/wells.scss
@@ -3,7 +3,6 @@
color: $gl-text-color;
border: 1px solid $border-color;
border-radius: $border-radius-default;
- margin-bottom: $gl-padding-8;
.card.card-body-segment {
padding: $gl-padding;
@@ -29,11 +28,6 @@
.ref-name {
font-size: 12px;
-
- &:hover {
- text-decoration: underline;
- color: $gl-text-color;
- }
}
}
diff --git a/app/assets/stylesheets/lazy_bundles/cropper.css b/app/assets/stylesheets/lazy_bundles/cropper.css
new file mode 100644
index 00000000000..9c7fdded117
--- /dev/null
+++ b/app/assets/stylesheets/lazy_bundles/cropper.css
@@ -0,0 +1,378 @@
+/*!
+ * Cropper v2.3.0
+ * https://github.com/fengyuanchen/cropper
+ *
+ * Copyright (c) 2014-2016 Fengyuan Chen and contributors
+ * Released under the MIT license
+ *
+ * Date: 2016-02-22T02:13:13.332Z
+ */
+.cropper-container {
+ font-size: 0;
+ line-height: 0;
+
+ position: relative;
+
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+
+ direction: ltr !important;
+ touch-action: none;
+ -webkit-tap-highlight-color: transparent;
+ -webkit-touch-callout: none;
+}
+
+.cropper-container img {
+ display: block;
+
+ width: 100%;
+ min-width: 0 !important;
+ max-width: none !important;
+ height: 100%;
+ min-height: 0 !important;
+ max-height: none !important;
+
+ image-orientation: 0deg !important;
+}
+
+.cropper-wrap-box,
+.cropper-canvas,
+.cropper-drag-box,
+.cropper-crop-box,
+.cropper-modal {
+ position: absolute;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+}
+
+.cropper-wrap-box {
+ overflow: hidden;
+}
+
+.cropper-drag-box {
+ opacity: 0;
+ background-color: #fff;
+
+ filter: alpha(opacity=0);
+}
+
+.cropper-modal {
+ opacity: 0.5;
+ background-color: #000;
+
+ filter: alpha(opacity=50);
+}
+
+.cropper-view-box {
+ display: block;
+ overflow: hidden;
+
+ width: 100%;
+ height: 100%;
+
+ outline: 1px solid #39f;
+ outline-color: rgba(51, 153, 255, 0.75);
+}
+
+.cropper-dashed {
+ position: absolute;
+
+ display: block;
+
+ opacity: 0.5;
+ border: 0 dashed #eee;
+
+ filter: alpha(opacity=50);
+}
+
+.cropper-dashed.dashed-h {
+ top: 33.33333%;
+ left: 0;
+
+ width: 100%;
+ height: 33.33333%;
+
+ border-top-width: 1px;
+ border-bottom-width: 1px;
+}
+
+.cropper-dashed.dashed-v {
+ top: 0;
+ left: 33.33333%;
+
+ width: 33.33333%;
+ height: 100%;
+
+ border-right-width: 1px;
+ border-left-width: 1px;
+}
+
+.cropper-center {
+ position: absolute;
+ top: 50%;
+ left: 50%;
+
+ display: block;
+
+ width: 0;
+ height: 0;
+
+ opacity: 0.75;
+
+ filter: alpha(opacity=75);
+}
+
+.cropper-center::before,
+.cropper-center::after {
+ position: absolute;
+
+ display: block;
+
+ content: ' ';
+
+ background-color: #eee;
+}
+
+.cropper-center::before {
+ top: 0;
+ left: -3px;
+
+ width: 7px;
+ height: 1px;
+}
+
+.cropper-center::after {
+ top: -3px;
+ left: 0;
+
+ width: 1px;
+ height: 7px;
+}
+
+.cropper-face,
+.cropper-line,
+.cropper-point {
+ position: absolute;
+
+ display: block;
+
+ width: 100%;
+ height: 100%;
+
+ opacity: 0.1;
+
+ filter: alpha(opacity=10);
+}
+
+.cropper-face {
+ top: 0;
+ left: 0;
+
+ background-color: #fff;
+}
+
+.cropper-line {
+ background-color: #39f;
+}
+
+.cropper-line.line-e {
+ top: 0;
+ right: -3px;
+
+ width: 5px;
+
+ cursor: e-resize;
+}
+
+.cropper-line.line-n {
+ top: -3px;
+ left: 0;
+
+ height: 5px;
+
+ cursor: n-resize;
+}
+
+.cropper-line.line-w {
+ top: 0;
+ left: -3px;
+
+ width: 5px;
+
+ cursor: w-resize;
+}
+
+.cropper-line.line-s {
+ bottom: -3px;
+ left: 0;
+
+ height: 5px;
+
+ cursor: s-resize;
+}
+
+.cropper-point {
+ width: 5px;
+ height: 5px;
+
+ opacity: 0.75;
+ background-color: #39f;
+
+ filter: alpha(opacity=75);
+}
+
+.cropper-point.point-e {
+ top: 50%;
+ right: -3px;
+
+ margin-top: -3px;
+
+ cursor: e-resize;
+}
+
+.cropper-point.point-n {
+ top: -3px;
+ left: 50%;
+
+ margin-left: -3px;
+
+ cursor: n-resize;
+}
+
+.cropper-point.point-w {
+ top: 50%;
+ left: -3px;
+
+ margin-top: -3px;
+
+ cursor: w-resize;
+}
+
+.cropper-point.point-s {
+ bottom: -3px;
+ left: 50%;
+
+ margin-left: -3px;
+
+ cursor: s-resize;
+}
+
+.cropper-point.point-ne {
+ top: -3px;
+ right: -3px;
+
+ cursor: ne-resize;
+}
+
+.cropper-point.point-nw {
+ top: -3px;
+ left: -3px;
+
+ cursor: nw-resize;
+}
+
+.cropper-point.point-sw {
+ bottom: -3px;
+ left: -3px;
+
+ cursor: sw-resize;
+}
+
+.cropper-point.point-se {
+ right: -3px;
+ bottom: -3px;
+
+ width: 20px;
+ height: 20px;
+
+ cursor: se-resize;
+
+ opacity: 1;
+
+ filter: alpha(opacity=100);
+}
+
+.cropper-point.point-se::before {
+ position: absolute;
+ right: -50%;
+ bottom: -50%;
+
+ display: block;
+
+ width: 200%;
+ height: 200%;
+
+ content: ' ';
+
+ opacity: 0;
+ background-color: #39f;
+
+ filter: alpha(opacity=0);
+}
+
+@media (min-width: 768px) {
+ .cropper-point.point-se {
+ width: 15px;
+ height: 15px;
+ }
+}
+
+@media (min-width: 992px) {
+ .cropper-point.point-se {
+ width: 10px;
+ height: 10px;
+ }
+}
+
+@media (min-width: 1200px) {
+ .cropper-point.point-se {
+ width: 5px;
+ height: 5px;
+
+ opacity: 0.75;
+
+ filter: alpha(opacity=75);
+ }
+}
+
+.cropper-invisible {
+ opacity: 0;
+
+ filter: alpha(opacity=0);
+}
+
+.cropper-bg {
+ background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAAA3NCSVQICAjb4U/gAAAABlBMVEXMzMz////TjRV2AAAACXBIWXMAAArrAAAK6wGCiw1aAAAAHHRFWHRTb2Z0d2FyZQBBZG9iZSBGaXJld29ya3MgQ1M26LyyjAAAABFJREFUCJlj+M/AgBVhF/0PAH6/D/HkDxOGAAAAAElFTkSuQmCC');
+}
+
+.cropper-hide {
+ position: absolute;
+
+ display: block;
+
+ width: 0;
+ height: 0;
+}
+
+.cropper-hidden {
+ display: none !important;
+}
+
+.cropper-move {
+ cursor: move;
+}
+
+.cropper-crop {
+ cursor: crosshair;
+}
+
+.cropper-disabled .cropper-drag-box,
+.cropper-disabled .cropper-face,
+.cropper-disabled .cropper-line,
+.cropper-disabled .cropper-point {
+ cursor: not-allowed;
+}
diff --git a/app/assets/stylesheets/mailer.scss b/app/assets/stylesheets/mailer.scss
index a5fc92237df..b2050c0e73f 100644
--- a/app/assets/stylesheets/mailer.scss
+++ b/app/assets/stylesheets/mailer.scss
@@ -52,6 +52,10 @@ a {
margin-top: 0;
}
+.invite-body {
+ width: 360px;
+}
+
.invite-actions {
margin-top: 24px;
}
@@ -64,6 +68,15 @@ a {
color: $white;
}
+.invite-btn-decline {
+ border-radius: $border-radius-default;
+ border: 1px solid $purple;
+ padding: $gl-btn-vert-padding $gl-btn-horz-padding;
+ cursor: pointer;
+ color: $purple;
+ margin-left: 4px;
+}
+
tr td {
font-family: $mailer-font;
}
diff --git a/app/assets/stylesheets/page_bundles/_ide_theme_overrides.scss b/app/assets/stylesheets/page_bundles/_ide_theme_overrides.scss
index 1e239877428..d1f7c2e9865 100644
--- a/app/assets/stylesheets/page_bundles/_ide_theme_overrides.scss
+++ b/app/assets/stylesheets/page_bundles/_ide_theme_overrides.scss
@@ -6,9 +6,10 @@
$bs-input-focus-box-shadow: rgba(0, 123, 255, 0.25);
a:not(.btn),
- .btn-link:hover,
- .btn-link:focus,
- .btn-link:active {
+ .gl-button.btn-link,
+ .gl-button.btn-link:hover,
+ .gl-button.btn-link:focus,
+ .gl-button.btn-link:active {
color: var(--ide-link-color, $blue-600);
}
@@ -225,20 +226,20 @@
@return calc(#{$original-padding + $original-border} - var(--ide-btn-hover-border-width, #{$original-border}));
}
- .btn:not(.btn-link):not([disabled]):hover {
+ .btn:not(.gl-button):not(.btn-link):not([disabled]):hover {
border-width: var(--ide-btn-hover-border-width, 1px);
padding: calc-btn-hover-padding(6px) calc-btn-hover-padding(10px);
}
- .btn:not([disabled]).btn-sm:hover {
+ .btn:not(.gl-button):not([disabled]).btn-sm:hover {
padding: calc-btn-hover-padding(4px) calc-btn-hover-padding(10px);
}
- .btn:not([disabled]).btn-block:hover {
+ .btn:not(.gl-button):not([disabled]).btn-block:hover {
padding: calc-btn-hover-padding(6px) 0;
}
- .btn-default,
+ .btn-default:not(.gl-button),
.dropdown,
.dropdown-menu-toggle {
background-color: var(--ide-input-background, $white) !important;
@@ -257,7 +258,7 @@
}
// In IDE, the only inverted buttons are `.btn-remove`
- .btn-inverted.btn-remove {
+ .btn-inverted.btn-remove:not(.gl-button) {
color: var(--ide-input-color, $red-500) !important;
background-color: var(--ide-input-background, $white) !important;
border-color: var(--ide-btn-default-border, $red-500);
@@ -276,17 +277,21 @@
}
}
- .btn-default {
+ // todo: remove this block after all default buttons have been migrated to gl-button
+ .btn-default:not(.gl-button) {
+ background-color: var(--ide-btn-default-background, $white) !important;
+ border-color: var(--ide-btn-default-border, $border-color);
+
&:hover,
&:focus {
border-color: var(--ide-btn-default-hover-border, $border-white-normal) !important;
- background-color: var(--ide-input-background, $white-normal) !important;
+ background-color: var(--ide-btn-default-background, $white-normal) !important;
}
&:active,
.active {
border-color: var(--ide-btn-default-hover-border, $border-white-normal) !important;
- background-color: var(--ide-input-background, $white-dark) !important;
+ background-color: var(--ide-btn-default-background, $white-dark) !important;
}
}
@@ -320,8 +325,9 @@
border-color: var(--ide-dropdown-hover-background, $gray-100) !important;
}
- .btn-primary,
- .btn-info {
+ // todo: remove this block after all primary/info buttons have been migrated to gl-button
+ .btn-primary:not(.gl-button),
+ .btn-info:not(.gl-button) {
background-color: var(--ide-btn-primary-background, $blue-500);
border-color: var(--ide-btn-primary-border, $blue-600) !important;
@@ -338,7 +344,8 @@
}
}
- .btn-success {
+ // todo: remove this block after all success buttons have been migrated to gl-button
+ .btn-success:not(.gl-button) {
background-color: var(--ide-btn-success-background, $green-500);
border-color: var(--ide-btn-success-border, $green-600) !important;
@@ -355,12 +362,70 @@
}
}
- .btn[disabled] {
+ // todo: remove this block after all disabled buttons have been migrated to gl-button
+ .btn[disabled]:not(.gl-button) {
background-color: var(--ide-btn-default-background, $gray-light) !important;
border: 1px solid var(--ide-btn-disabled-border, $gray-100) !important;
color: var(--ide-btn-disabled-color, $gl-text-color-disabled) !important;
}
+ @function ide-btn-var($btn-type, $var-type, $value) {
+ @return var(--ide-btn-#{$btn-type}-#{$var-type}, $value);
+ }
+
+ @mixin ide-gl-button($btn-type, $bg-normal, $bg-hover, $bg-active, $border-normal, $border-hover, $border-focus, $border-active, $border-width-hover: 2px, $box-shadow-hover: $t-gray-a-08, $box-shadow-focus: 0 0 0 4px rgba($blue-500, 0.25)) {
+ background-color: ide-btn-var($btn-type, background, $bg-normal);
+ box-shadow: inset 0 0 0 1px ide-btn-var($btn-type, border, $border-normal);
+
+ &:hover,
+ &:focus {
+ background-color: ide-btn-var($btn-type, background, $bg-hover);
+ }
+
+ &:hover {
+ box-shadow: inset 0 0 0 ide-btn-var($btn-type, hover-border-width, $border-width-hover) ide-btn-var($btn-type, hover-border, $border-hover),
+ 0 2px 2px 0 $box-shadow-hover;
+ }
+
+ &:focus {
+ box-shadow: inset 0 0 0 ide-btn-var($btn-type, hover-border-width, $border-width-hover) ide-btn-var($btn-type, hover-border, $border-focus),
+ ide-btn-var($btn-type, focus-box-shadow, $box-shadow-focus);
+ }
+
+ &:active:focus {
+ background-color: ide-btn-var($btn-type, background, $bg-active);
+ box-shadow: inset 0 0 0 ide-btn-var($btn-type, hover-border-width, $border-width-hover) ide-btn-var($btn-type, hover-border, $border-active),
+ ide-btn-var($btn-type, focus-box-shadow, $box-shadow-focus);
+ }
+ }
+
+ .btn-default.gl-button.gl-button {
+ color: var(--ide-input-color, $gl-text-color);
+
+ @include ide-gl-button(default, $white, $gray-50, $gray-100, $gray-200, $gray-300, $gray-300, $gray-400);
+ }
+
+ .btn-success.gl-button.gl-button {
+ @include ide-gl-button(success, $green-500, $green-600, $green-800, $green-600, $green-800, $green-800, $green-900);
+ }
+
+ .btn-info.gl-button.gl-button,
+ .btn-primary.gl-button.gl-button {
+ @include ide-gl-button(primary, $blue-500, $blue-600, $blue-800, $blue-600, $blue-800, $blue-800, $blue-900);
+ }
+
+ .btn-danger.btn-danger-secondary.gl-button.gl-button {
+ color: var(--ide-input-color, $red-500);
+
+ @include ide-gl-button(danger-secondary, $white, $red-50, $red-100, $red-500, $red-600, $red-600, $red-700);
+ }
+
+ .btn[disabled].gl-button.gl-button {
+ color: var(--ide-btn-disabled-color, $gl-text-color-disabled);
+
+ @include ide-gl-button(disabled, $gray-10, $gray-10, $gray-10, $gray-100, $gray-100, $gray-100, $gray-100, 1px, transparent, transparent);
+ }
+
.md table:not(.code) tbody {
background-color: var(--ide-border-color, $white);
}
diff --git a/app/assets/stylesheets/page_bundles/_pipeline_mixins.scss b/app/assets/stylesheets/page_bundles/_pipeline_mixins.scss
new file mode 100644
index 00000000000..499394ad960
--- /dev/null
+++ b/app/assets/stylesheets/page_bundles/_pipeline_mixins.scss
@@ -0,0 +1,233 @@
+@mixin flat-connector-before($length: 44px) {
+ &::before {
+ content: '';
+ position: absolute;
+ top: 48%;
+ left: -$length;
+ border-top: 2px solid $border-color;
+ width: $length;
+ height: 1px;
+ }
+}
+
+@mixin build-content($border-radius: 30px) {
+ display: inline-block;
+ padding: 8px 10px 9px;
+ width: 100%;
+ border: 1px solid $border-color;
+ border-radius: $border-radius;
+ background-color: $white;
+
+ &:hover {
+ background-color: $gray-darker;
+ border: 1px solid $dropdown-toggle-active-border-color;
+ color: $gl-text-color;
+ }
+}
+
+@mixin mini-pipeline-graph-color(
+ $color-background-default,
+ $color-background-hover-focus,
+ $color-background-active,
+ $color-foreground-default,
+ $color-foreground-hover-focus,
+ $color-foreground-active
+) {
+ background-color: $color-background-default;
+ border-color: $color-foreground-default;
+
+ svg {
+ fill: $color-foreground-default;
+ }
+
+ &:hover,
+ &:focus {
+ background-color: $color-background-hover-focus;
+ border-color: $color-foreground-hover-focus;
+
+ svg {
+ fill: $color-foreground-hover-focus;
+ }
+ }
+
+ &:active {
+ background-color: $color-background-active;
+ border-color: $color-foreground-active;
+
+ svg {
+ fill: $color-foreground-active;
+ }
+ }
+
+ &:focus {
+ box-shadow: 0 0 4px 1px $blue-300;
+ }
+}
+
+@mixin mini-pipeline-item() {
+ border-radius: 100px;
+ background-color: $white;
+ border-width: 1px;
+ border-style: solid;
+ width: $ci-action-icon-size;
+ height: $ci-action-icon-size;
+ margin: 0;
+ padding: 0;
+ position: relative;
+ vertical-align: middle;
+
+ &:hover,
+ &:active,
+ &:focus {
+ outline: none;
+ border-width: 2px;
+ }
+
+ // Dropdown button animation in mini pipeline graph
+ &.ci-status-icon-success {
+ @include mini-pipeline-graph-color($white, $green-100, $green-200, $green-500, $green-600, $green-700);
+ }
+
+ &.ci-status-icon-failed {
+ @include mini-pipeline-graph-color($white, $red-100, $red-200, $red-500, $red-600, $red-700);
+ }
+
+ &.ci-status-icon-pending,
+ &.ci-status-icon-waiting-for-resource,
+ &.ci-status-icon-success-with-warnings {
+ @include mini-pipeline-graph-color($white, $orange-50, $orange-100, $orange-500, $orange-600, $orange-700);
+ }
+
+ &.ci-status-icon-preparing,
+ &.ci-status-icon-running {
+ @include mini-pipeline-graph-color($white, $blue-100, $blue-200, $blue-500, $blue-600, $blue-700);
+ }
+
+ &.ci-status-icon-canceled,
+ &.ci-status-icon-scheduled,
+ &.ci-status-icon-disabled,
+ &.ci-status-icon-not-found,
+ &.ci-status-icon-manual {
+ @include mini-pipeline-graph-color($white, $gray-500, $gray-700, $gray-900, $gray-950, $black);
+ }
+
+ &.ci-status-icon-created,
+ &.ci-status-icon-skipped {
+ @include mini-pipeline-graph-color($white, $gray-100, $gray-200, $gray-300, $gray-400, $gray-500);
+ }
+}
+
+/**
+ Action icons inside dropdowns:
+ - mini graph in pipelines table
+ - dropdown in big graph
+ - mini graph in MR widget pipeline
+ - mini graph in Commit widget pipeline
+*/
+@mixin pipeline-graph-dropdown-menu() {
+ width: 240px;
+ max-width: 240px;
+
+ // override dropdown.scss
+ &.dropdown-menu li button,
+ &.dropdown-menu li a.ci-action-icon-container {
+ padding: 0;
+ text-align: center;
+ }
+
+ .ci-action-icon-container {
+ position: absolute;
+ right: 8px;
+ top: 8px;
+
+ &.ci-action-icon-wrapper {
+ height: $ci-action-dropdown-button-size;
+ width: $ci-action-dropdown-button-size;
+ border-radius: 50%;
+ display: block;
+
+ &:hover {
+ box-shadow: inset 0 0 0 0.0625rem $dropdown-toggle-active-border-color;
+ background-color: $gray-darker;
+
+ svg {
+ fill: $gl-text-color;
+ }
+ }
+
+ .spinner,
+ svg {
+ width: $ci-action-dropdown-svg-size;
+ height: $ci-action-dropdown-svg-size;
+ fill: $gl-text-color-secondary;
+ position: relative;
+ top: 1px;
+ vertical-align: initial;
+ }
+ }
+ }
+
+ // SVGs in the commit widget and mr widget
+ a.ci-action-icon-container.ci-action-icon-wrapper svg {
+ top: 5px;
+ }
+
+ .scrollable-menu {
+ padding: 0;
+ max-height: 245px;
+ overflow: auto;
+ }
+
+ li {
+ position: relative;
+
+ // ensure .mini-pipeline-graph-dropdown-item has hover style when action-icon is hovered
+ &:hover > .mini-pipeline-graph-dropdown-item,
+ &:hover > .ci-job-component > .mini-pipeline-graph-dropdown-item {
+ @extend .mini-pipeline-graph-dropdown-item:hover;
+ }
+
+ // link to the build
+ .mini-pipeline-graph-dropdown-item {
+ align-items: center;
+ clear: both;
+ display: flex;
+ font-weight: normal;
+ line-height: $line-height-base;
+ white-space: nowrap;
+
+ // Match dropdown.scss for all `a` tags
+ &.non-details-job-component {
+ padding: $gl-padding-8 $gl-btn-horz-padding;
+ }
+
+ .ci-job-name-component {
+ align-items: center;
+ display: flex;
+ flex: 1;
+ }
+
+ .ci-status-icon {
+ @include gl-mr-3;
+
+ position: relative;
+
+ > svg {
+ width: $pipeline-dropdown-status-icon-size;
+ height: $pipeline-dropdown-status-icon-size;
+ margin: 3px 0;
+ position: relative;
+ overflow: visible;
+ display: block;
+ }
+ }
+
+ &:hover,
+ &:focus {
+ outline: none;
+ text-decoration: none;
+ background-color: $gray-darker;
+ }
+ }
+ }
+}
diff --git a/app/assets/stylesheets/page_bundles/boards.scss b/app/assets/stylesheets/page_bundles/boards.scss
new file mode 100644
index 00000000000..e908e3622ed
--- /dev/null
+++ b/app/assets/stylesheets/page_bundles/boards.scss
@@ -0,0 +1,613 @@
+@import 'mixins_and_variables_and_functions';
+
+.user-can-drag {
+ cursor: grab;
+}
+
+.is-ghost {
+ opacity: 0.3;
+ pointer-events: none;
+}
+
+.dropdown-projects {
+ .dropdown-content {
+ max-height: 200px;
+ }
+}
+
+.dropdown-menu-issues-board-new {
+ width: 320px;
+
+ .dropdown-content {
+ max-height: 140px;
+ }
+}
+
+.issue-board-dropdown-content {
+ margin: 0;
+ padding: $gl-padding-4 $gl-padding $gl-padding;
+ border-bottom: 0;
+ color: var(--gray-500, $gray-500);
+}
+
+.issue-boards-page {
+ .content-wrapper {
+ padding-bottom: 0;
+ }
+}
+
+.boards-app {
+ @include media-breakpoint-up(sm) {
+ transition: width $sidebar-transition-duration;
+ width: 100%;
+
+ &.is-compact {
+ width: calc(100% - #{$gutter-width});
+ }
+ }
+}
+
+.boards-list,
+.board-swimlanes {
+ height: calc(100vh - #{$issue-board-list-difference-xs});
+ overflow-x: scroll;
+ min-height: 200px;
+
+ @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 {
+ // the next line cannot be replaced with .d-inline-block because it breaks display: none of SortableJS
+ // see https://gitlab.com/gitlab-org/gitlab-foss/issues/64828
+ display: inline-block;
+ width: calc(85vw - 15px);
+
+ @include media-breakpoint-up(sm) {
+ width: 400px;
+ }
+
+ .board-title-caret {
+ border-radius: $border-radius-default;
+ line-height: $gl-spacing-scale-5;
+ height: $gl-spacing-scale-5;
+
+ &.btn svg {
+ top: 0;
+ }
+
+ &:hover {
+ background-color: var(--gray-50, $gray-50);
+ transition: background-color 0.1s linear;
+ }
+ }
+
+ &:not(.is-collapsed) {
+ .board-title-caret {
+ margin-right: $gl-padding-4;
+ }
+ }
+
+ &.is-collapsed {
+ width: 50px;
+
+ .board-title {
+ flex-direction: column;
+ }
+
+ .board-title-caret {
+ margin-top: 1px;
+ }
+
+ .user-avatar-link,
+ .milestone-icon {
+ margin-top: $gl-padding-8;
+ transform: rotate(90deg);
+ }
+
+ .board-title-text {
+ flex-grow: 0;
+ margin: $gl-padding-8 0;
+
+ .board-title-main-text {
+ display: block;
+ }
+
+ .board-title-sub-text {
+ display: none;
+ }
+ }
+
+ .issue-count-badge {
+ border: 0;
+ white-space: nowrap;
+ padding: 0;
+ }
+
+ .board-title-text > span,
+ .issue-count-badge > span {
+ height: 16px;
+
+ // Force the height to be equal to the parent's width while centering the contents.
+ // The contents *should* be about 16 px.
+ // We do this because the flow of elements isn't affected by the rotate transform, so we must ensure that a
+ // rotated element has square dimensions so it won't overlap with its siblings.
+ margin: calc(50% - 8px) 0;
+
+ transform: rotate(90deg);
+ transform-origin: center;
+ }
+ }
+}
+
+.board-inner {
+ font-size: $issue-boards-font-size;
+ background: var(--gray-10, $gray-10);
+ border: 1px solid var(--gray-100, $gray-100);
+}
+
+.board-header {
+ &.has-border::before {
+ border-top: 3px solid;
+ border-color: inherit;
+ border-top-left-radius: $border-radius-default;
+ border-top-right-radius: $border-radius-default;
+ content: '';
+ position: absolute;
+ width: calc(100% + 2px);
+ top: 0;
+ left: 0;
+ margin-top: -1px;
+ margin-right: -1px;
+ margin-left: -1px;
+ padding-top: 1px;
+ padding-right: 1px;
+ padding-left: 1px;
+
+ .board-title {
+ padding-top: ($gl-padding - 3px);
+ padding-bottom: $gl-padding;
+ }
+ }
+}
+
+.board-title {
+ align-items: center;
+ font-size: 1em;
+ border-bottom: 1px solid var(--gray-100, $gray-100);
+ padding: 0 $gl-spacing-scale-3;
+ height: 3rem;
+
+ .js-max-issue-size::before {
+ content: '/';
+ }
+}
+
+.board-title-text {
+ flex-grow: 1;
+}
+
+.board-delete.gl-button {
+ background-color: transparent;
+ outline: 0;
+
+ &:hover {
+ color: var(--blue-600, $blue-600);
+ box-shadow: none;
+ }
+}
+
+.board-blank-state,
+.board-promotion-state {
+ background-color: var(--white, $white);
+ flex: 1;
+ overflow-y: auto;
+ overflow-x: hidden;
+}
+
+.board-blank-state-list {
+ > li:not(:last-child) {
+ margin-bottom: 8px;
+ }
+
+ .label-color {
+ top: 2px;
+ width: 16px;
+ height: 16px;
+ margin-right: 3px;
+ }
+}
+
+.board-list-component {
+ min-height: 0; // firefox fix
+}
+
+.board-list {
+ overflow-y: auto;
+ overflow-x: hidden;
+}
+
+.board-list-loading {
+ margin-top: 10px;
+ font-size: (26px / $issue-boards-font-size) * 1em;
+}
+
+.board-card {
+ background: var(--white, $white);
+ border: 1px solid var(--gray-100, $gray-100);
+ box-shadow: 0 1px 2px rgba(var(--black, $black), 0.1);
+ line-height: $gl-padding;
+ list-style: none;
+ position: relative;
+
+ &:not(:last-child) {
+ margin-bottom: $gl-padding-8;
+ }
+
+ &.is-active,
+ &.is-active .board-card-assignee:hover a {
+ background-color: var(--blue-50, $blue-50);
+ }
+
+ &.multi-select {
+ border-color: var(--blue-200, $blue-200);
+ background-color: var(--blue-50, $blue-50);
+ }
+
+ .gl-label {
+ margin-top: 4px;
+ margin-right: 4px;
+ }
+
+ .confidential-icon {
+ color: var(--orange-500, $orange-500);
+ cursor: help;
+ }
+
+ .issue-blocked-icon {
+ color: var(--red-500, $red-500);
+ }
+
+ @include media-breakpoint-down(md) {
+ padding: $gl-padding-8;
+ }
+}
+
+.board-card-title {
+ @include overflow-break-word();
+ font-size: 1em;
+
+ a {
+ color: var(--gray-900, $gray-900);
+ }
+
+ @include media-breakpoint-down(md) {
+ font-size: $label-font-size;
+ }
+}
+
+.board-card-header {
+ text-align: initial;
+}
+
+.board-card-assignee {
+ margin-top: -$gl-padding-4;
+ margin-bottom: -$gl-padding-4;
+
+ .avatar-counter {
+ vertical-align: middle;
+ line-height: $gl-padding-24;
+ min-width: $gl-padding-24;
+ height: $gl-padding-24;
+ border-radius: $gl-padding-24;
+ background-color: var(--gray-400, $gray-400);
+ font-size: $gl-font-size-xs;
+ cursor: help;
+ font-weight: $gl-font-weight-bold;
+ margin-left: -$gl-padding-4;
+ border: 0;
+ padding: 0 $gl-padding-4;
+
+ @include media-breakpoint-down(md) {
+ min-width: auto;
+ height: $gl-padding;
+ border-radius: $gl-padding;
+ line-height: $gl-padding;
+ }
+ }
+
+ img {
+ vertical-align: top;
+ }
+
+ .user-avatar-link:not(:only-child) {
+ margin-left: -$gl-padding-4;
+
+ &:nth-of-type(1) {
+ z-index: 2;
+ }
+
+ &:nth-of-type(2) {
+ z-index: 1;
+ }
+ }
+
+ .avatar {
+ @include media-breakpoint-down(md) {
+ width: $gl-padding;
+ height: $gl-padding;
+ }
+ }
+
+ @include media-breakpoint-down(md) {
+ margin-top: 0;
+ margin-bottom: 0;
+ }
+}
+
+.board-card-number {
+ font-size: $gl-font-size-xs;
+ color: var(--gray-500, $gray-500);
+
+ @include media-breakpoint-up(md) {
+ font-size: $label-font-size;
+ }
+}
+
+.board-list-count {
+ padding: 10px 0;
+ color: var(--gray-500, $gray-500);
+ font-size: 13px;
+}
+
+.board-new-issue-form {
+ z-index: 4;
+ margin: 5px;
+}
+
+.right-sidebar.issue-boards-sidebar {
+ .gutter-toggle {
+ bottom: 15px;
+ width: 22px;
+ padding-left: $gl-padding-32;
+
+ svg {
+ position: absolute;
+ top: 50%;
+ right: 0;
+ margin-top: (-11px / 2);
+ height: $gl-font-size-12;
+ width: $gl-font-size-12;
+ }
+ }
+
+ .issuable-header-text {
+ @include overflow-break-word();
+ padding-right: 35px;
+ }
+}
+
+.right-sidebar.right-sidebar-expanded {
+ &.boards-sidebar-slide-enter-active,
+ &.boards-sidebar-slide-leave-active {
+ transition: width $sidebar-transition-duration, padding $sidebar-transition-duration;
+ }
+
+ &.boards-sidebar-slide-enter,
+ &.boards-sidebar-slide-leave-active {
+ width: 0;
+ padding-left: 0;
+ padding-right: 0;
+ }
+}
+
+.add-issues-modal {
+ background-color: rgba($black, 0.3);
+ z-index: 9999;
+}
+
+.add-issues-container {
+ width: 90vw;
+ height: 85vh;
+ max-width: 1100px;
+ min-height: 500px;
+ padding: 25px 15px 0;
+ background-color: var(--white, $white);
+ box-shadow: 0 2px 12px rgba(var(--black, $black), 0.5);
+
+ .empty-state {
+ &.add-issues-empty-state-filter {
+ flex-direction: column;
+ justify-content: center;
+ }
+
+ .svg-content {
+ margin-top: -40px;
+ }
+ }
+}
+
+.add-issues-header {
+ margin: -25px -15px -5px;
+ border-bottom: 1px solid $border-color;
+ border-top-right-radius: $border-radius-default;
+ border-top-left-radius: $border-radius-default;
+
+ > h2 {
+ font-size: 18px;
+ }
+}
+
+.add-issues-list-column {
+ width: 100%;
+
+ @include media-breakpoint-up(sm) {
+ width: 50%;
+ }
+
+ @include media-breakpoint-up(md) {
+ width: (100% / 3);
+ }
+}
+
+.add-issues-list {
+ padding-top: 3px;
+ margin-left: -$gl-vert-padding;
+ margin-right: -$gl-vert-padding;
+ overflow-y: scroll;
+
+ .board-card-parent {
+ padding: 0 5px 5px;
+ }
+
+ .board-card {
+ border: 1px solid var(--gray-900, $gray-900);
+ box-shadow: 0 1px 2px rgba(var(--black, $black), 0.4);
+ cursor: pointer;
+ }
+}
+
+.add-issues-footer {
+ margin: auto -15px 0;
+ padding-left: 15px;
+ padding-right: 15px;
+ border-bottom-right-radius: $border-radius-default;
+ border-bottom-left-radius: $border-radius-default;
+}
+
+.add-issues-footer-to-list {
+ padding-left: $gl-vert-padding;
+ padding-right: $gl-vert-padding;
+ line-height: $input-height;
+}
+
+.issue-card-selected {
+ position: absolute;
+ right: -3px;
+ top: -3px;
+ width: 17px;
+ background-color: var(--blue-500, $blue-500);
+ color: $white;
+ border: 1px solid var(--blue-600, $blue-600);
+ font-size: 9px;
+ line-height: 15px;
+ border-radius: 50%;
+}
+
+.board-card-info {
+ color: var(--gray-500, $gray-500);
+ white-space: nowrap;
+ margin-right: $gl-padding-8;
+
+ &:not(.board-card-weight) {
+ cursor: help;
+ }
+
+ &.board-card-weight {
+ color: var(--gray-500, $gray-500);
+ cursor: pointer;
+
+ &:hover {
+ color: initial;
+ text-decoration: underline;
+ }
+ }
+
+ .board-card-info-icon {
+ color: var(--gray-500, $gray-500);
+ margin-right: $gl-padding-4;
+ vertical-align: text-top;
+ }
+
+ @include media-breakpoint-down(md) {
+ font-size: $label-font-size;
+ }
+}
+
+.board-issue-path.js-show-tooltip {
+ cursor: help;
+}
+
+.board-labels-toggle-wrapper,
+.board-swimlanes-toggle-wrapper {
+ /**
+ * Make the wrapper the same height as a button so it aligns properly when the
+ * filtered-search-box input element increases in size on Linux smaller breakpoints
+ */
+ height: $input-height;
+}
+
+.issue-boards-content.is-focused {
+ position: fixed;
+ width: 100%;
+ height: 100%;
+ top: 0;
+ left: 0;
+ background: var(--white, $white);
+ z-index: 9000;
+
+ @include media-breakpoint-down(sm) {
+ padding-top: 10px;
+ }
+
+ .boards-list {
+ height: calc(100vh - #{$issue-boards-filter-height});
+ overflow-x: scroll;
+ }
+
+ .issue-boards-sidebar {
+ height: 100%;
+ top: 0;
+ }
+}
+
+.board-swimlanes {
+ overflow-x: auto;
+}
+
+.board-header-collapsed-info-icon:hover {
+ color: var(--gray-900, $gray-900);
+}
+
+$epic-icons-spacing: 40px;
+
+.board-epic-lane {
+ max-width: calc(100vw - #{$contextual-sidebar-width} - #{$epic-icons-spacing});
+
+ .page-with-icon-sidebar & {
+ max-width: calc(100vw - #{$contextual-sidebar-collapsed-width} - #{$epic-icons-spacing});
+ }
+
+ .page-with-icon-sidebar .is-compact & {
+ max-width: calc(100vw - #{$contextual-sidebar-collapsed-width} - #{$gutter-width} - #{$epic-icons-spacing});
+ }
+
+ .is-compact & {
+ max-width: calc(100vw - #{$contextual-sidebar-width} - #{$gutter-width} - #{$epic-icons-spacing});
+ }
+}
diff --git a/app/assets/stylesheets/page_bundles/cycle_analytics.scss b/app/assets/stylesheets/page_bundles/cycle_analytics.scss
new file mode 100644
index 00000000000..3a5e2e4159d
--- /dev/null
+++ b/app/assets/stylesheets/page_bundles/cycle_analytics.scss
@@ -0,0 +1,355 @@
+@import 'mixins_and_variables_and_functions';
+
+#cycle-analytics,
+.cycle-analytics {
+ margin: 24px auto 0;
+ position: relative;
+
+ .landing {
+ margin-top: 0;
+
+ .inner-content {
+ white-space: normal;
+
+ h4,
+ p {
+ margin: 7px 0 0;
+ max-width: 480px;
+ padding: 0 $gl-padding;
+
+ @include media-breakpoint-down(sm) {
+ margin: 0 auto;
+ }
+ }
+ }
+
+ .svg-container svg {
+ width: 136px;
+ height: 136px;
+ }
+ }
+
+ .col-headers {
+ ul {
+ @include clearfix;
+ margin: 0;
+ padding: 0;
+ }
+
+ li {
+ display: inline-block;
+ float: left;
+ line-height: 50px;
+ width: 20%;
+ }
+
+ .stage-header {
+ width: 20.5%;
+ }
+
+ .median-header {
+ width: 19.5%;
+ }
+
+ .event-header {
+ width: 45%;
+ }
+
+ .total-time-header {
+ width: 15%;
+ }
+ }
+
+ .card {
+ .content-block {
+ padding: 24px 0;
+ border-bottom: 0;
+ position: relative;
+
+ @include media-breakpoint-down(xs) {
+ padding: 6px 0 24px;
+ }
+ }
+
+ .column {
+ text-align: center;
+
+ @include media-breakpoint-down(xs) {
+ padding: 15px 0;
+ }
+
+ .header {
+ font-size: 30px;
+ line-height: 38px;
+ font-weight: $gl-font-weight-normal;
+ margin: 0;
+ }
+
+ .text {
+ color: var(--gray-500, $gray-500);
+ margin: 0;
+ }
+
+ &:last-child {
+ @include media-breakpoint-down(xs) {
+ text-align: center;
+ }
+ }
+ }
+ }
+
+ .stage-panel-body {
+ display: flex;
+ flex-wrap: wrap;
+ }
+
+ .stage-nav,
+ .stage-entries {
+ display: flex;
+ vertical-align: top;
+ font-size: $gl-font-size;
+ }
+
+ .stage-nav {
+ width: 40%;
+ margin-bottom: 0;
+
+ ul {
+ padding: 0;
+ margin: 0;
+ width: 100%;
+ }
+
+ li {
+ @include clearfix;
+ list-style-type: none;
+ }
+
+ .stage-nav-item {
+ line-height: 65px;
+
+ &.active {
+ background: var(--blue-50, $blue-50);
+ border-color: var(--blue-300, $blue-300);
+ box-shadow: inset 4px 0 0 0 var(--blue-500, $blue-500);
+ }
+
+ &:hover:not(.active) {
+ background-color: var(--gray-10, $gray-10);
+ box-shadow: inset 2px 0 0 0 var(--border-color, $border-color);
+ cursor: pointer;
+ }
+
+ .stage-nav-item-cell.stage-name {
+ width: 44.5%;
+ }
+
+ .stage-nav-item-cell.stage-median {
+ min-width: 43%;
+ }
+
+ .stage-empty,
+ .not-available {
+ color: var(--gray-500, $gray-500);
+ }
+ }
+ }
+
+ .stage-panel-container {
+ width: 100%;
+ overflow: auto;
+ }
+
+ .stage-panel {
+ min-width: 968px;
+
+ .card-header {
+ padding: 0;
+ background-color: transparent;
+ }
+
+ .events-description {
+ line-height: 65px;
+ padding: 0 $gl-padding;
+ }
+
+ .events-info {
+ color: var(--gray-500, $gray-500);
+ }
+ }
+
+ .stage-events {
+ width: 60%;
+ min-height: 467px;
+ }
+
+ .stage-event-list {
+ margin: 0;
+ padding: 0;
+ }
+
+ .stage-event-item {
+ @include clearfix;
+ list-style-type: none;
+ padding: 0 0 $gl-padding;
+ margin: 0 $gl-padding $gl-padding;
+ border-bottom: 1px solid var(--gray-50, $gray-50);
+
+ &:last-child {
+ border-bottom: 0;
+ margin-bottom: 0;
+ }
+
+ .item-details,
+ .item-time {
+ float: left;
+ }
+
+ .item-details {
+ width: 75%;
+ }
+
+ .item-title {
+ margin: 0 0 2px;
+
+ &.issue-title,
+ &.commit-title,
+ &.merge-request-title {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ max-width: 100%;
+ display: block;
+
+ a {
+ color: var(--gl-text-color, $gl-text-color);
+ }
+ }
+ }
+
+ .item-time {
+ width: 25%;
+ text-align: right;
+ }
+
+ .total-time {
+ font-size: $cycle-analytics-big-font;
+ color: var(--gl-text-color, $gl-text-color);
+
+ span {
+ color: var(--gl-text-color, $gl-text-color);
+ font-size: $gl-font-size;
+ }
+ }
+
+ .issue-date,
+ .build-date {
+ color: var(--gl-text-color, $gl-text-color);
+ }
+
+ .mr-link,
+ .issue-link,
+ .commit-author-link,
+ .issue-author-link {
+ color: var(--gl-text-color, $gl-text-color);
+ }
+
+ // Custom CSS for components
+ .item-conmmit-component {
+ .commit-icon {
+ svg {
+ display: inline-block;
+ width: 20px;
+ height: 20px;
+ vertical-align: bottom;
+ }
+ }
+ }
+
+ .merge-request-branch {
+ a {
+ max-width: 180px;
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ display: inline-block;
+ vertical-align: bottom;
+ }
+ }
+ }
+
+ // Custom Styles for stage items
+ .item-build-component {
+ .item-title {
+ .icon-build-status {
+ float: left;
+ margin-right: 5px;
+ position: relative;
+ top: 2px;
+ }
+
+ .item-build-name {
+ color: var(--gl-text-color, $gl-text-color);
+ }
+
+ .pipeline-id {
+ color: var(--gl-text-color, $gl-text-color);
+ padding: 0 3px 0 0;
+ }
+
+ .ref-name {
+ color: var(--gray-900, $gray-900);
+ display: inline-block;
+ max-width: 180px;
+ text-overflow: ellipsis;
+ overflow: hidden;
+ white-space: nowrap;
+ line-height: 1.3;
+ vertical-align: top;
+ }
+
+ .commit-sha {
+ color: var(--blue-600, $blue-600);
+ line-height: 1.3;
+ vertical-align: top;
+ font-weight: $gl-font-weight-normal;
+ }
+
+ .fa {
+ color: var(--gray-500, $gray-500);
+ font-size: $code-font-size;
+ }
+ }
+ }
+
+ .empty-stage,
+ .no-access-stage {
+ text-align: center;
+ width: 75%;
+ margin: 0 auto;
+ padding-top: 130px;
+ color: var(--gray-500, $gray-500);
+
+ h4 {
+ color: var(--gl-text-color, $gl-text-color);
+ }
+ }
+
+ .empty-stage {
+ .icon-no-data {
+ height: 36px;
+ width: 78px;
+ display: inline-block;
+ margin-bottom: 20px;
+ }
+ }
+
+ .no-access-stage {
+ .icon-lock {
+ height: 36px;
+ width: 78px;
+ display: inline-block;
+ margin-bottom: 20px;
+ }
+ }
+}
diff --git a/app/assets/stylesheets/page_bundles/dev_ops_report.scss b/app/assets/stylesheets/page_bundles/dev_ops_report.scss
new file mode 100644
index 00000000000..5c6019efce6
--- /dev/null
+++ b/app/assets/stylesheets/page_bundles/dev_ops_report.scss
@@ -0,0 +1,261 @@
+@import 'mixins_and_variables_and_functions';
+
+$space-between-cards: 8px;
+
+.devops-empty svg {
+ margin: 64px auto 32px;
+ max-width: 420px;
+}
+
+.devops-header {
+ margin-top: $gl-padding;
+ margin-bottom: $gl-padding;
+ padding: 0 4px;
+ display: flex;
+ align-items: center;
+
+ .devops-header-title {
+ font-size: 48px;
+ line-height: 1;
+ margin: 0;
+ }
+
+ .devops-header-subtitle {
+ font-size: 22px;
+ line-height: 1;
+ color: var(--gl-text-color-secondary, $gl-text-color-secondary);
+ margin-left: 8px;
+ font-weight: $gl-font-weight-normal;
+
+ .devops-header-icon {
+ vertical-align: px-to-rem(-$gl-spacing-scale-1);
+ }
+
+ a {
+ font-size: 18px;
+ color: var(--gl-text-color-secondary, $gl-text-color-secondary);
+
+ &:hover {
+ color: var(--blue-500, $blue-500);
+ }
+ }
+ }
+}
+
+.devops-cards {
+ display: flex;
+ justify-content: center;
+ flex-wrap: wrap;
+}
+
+.devops-card-wrapper {
+ display: flex;
+ flex-direction: column;
+ align-items: stretch;
+ text-align: center;
+ width: 50%;
+ border-color: var(--border-color, $border-color);
+ margin: 0 0 32px;
+ padding: $space-between-cards / 2;
+ position: relative;
+
+ @include media-breakpoint-up(xs) {
+ width: percentage(1 / 4);
+ }
+
+ @include media-breakpoint-up(sm) {
+ width: percentage(1 / 5);
+ }
+
+ @include media-breakpoint-up(md) {
+ width: percentage(1 / 6);
+ }
+
+ @include media-breakpoint-up(lg) {
+ width: percentage(1 / 10);
+ }
+}
+
+.devops-card {
+ border: solid 1px var(--border-color, $border-color);
+ border-radius: 3px;
+ border-top-width: 3px;
+ display: flex;
+ flex-direction: column;
+ flex-grow: 1;
+}
+
+.devops-card-low {
+ border-top-color: var(--red-400, $red-400);
+
+ .board-card-score-big {
+ background-color: var(--red-50, $red-50);
+ }
+}
+
+.devops-card-average {
+ border-top-color: var(--orange-200, $orange-200);
+
+ .board-card-score-big {
+ background-color: var(--orange-50, $orange-50);
+ }
+}
+
+.devops-card-high {
+ border-top-color: var(--green-400, $green-400);
+
+ .board-card-score-big {
+ background-color: var(--green-50, $green-50);
+ }
+}
+
+.devops-card-title {
+ margin: $gl-padding auto auto;
+ max-width: 100px;
+
+ h3 {
+ font-size: 14px;
+ margin: 0 0 2px;
+ }
+
+ .light-text {
+ font-size: 13px;
+ line-height: 1.25;
+ color: var(--gl-text-color-secondary, $gl-text-color-secondary);
+ }
+}
+
+.board-card-scores {
+ display: flex;
+ justify-content: space-around;
+ align-items: center;
+ margin: $gl-padding $gl-btn-padding;
+ line-height: 1;
+}
+
+.board-card-score {
+ color: var(--gl-text-color-secondary, $gl-text-color-secondary);
+
+ .board-card-score-name {
+ font-size: 13px;
+ margin-top: 4px;
+ }
+}
+
+.board-card-score-value {
+ font-size: 16px;
+ color: var(--gl-text-color, $gl-text-color);
+ font-weight: $gl-font-weight-normal;
+}
+
+.board-card-score-big {
+ border-top: 2px solid var(--border-color, $border-color);
+ border-bottom: 1px solid var(--border-color, $border-color);
+ font-size: 22px;
+ padding: 10px 0;
+ font-weight: $gl-font-weight-normal;
+}
+
+.board-card-buttons {
+ display: flex;
+
+ > * {
+ font-size: 16px;
+ color: var(--gl-text-color-secondary, $gl-text-color-secondary);
+ padding: 10px;
+ flex-grow: 1;
+
+ &:hover {
+ background-color: var(--border-color, $border-color);
+ color: var(--border-color, $border-color);
+ }
+
+ + * {
+ border-left: solid 1px var(--border-color, $border-color);
+ }
+ }
+}
+
+.devops-steps {
+ margin-top: $gl-padding;
+ height: 1px;
+ min-width: 100%;
+ justify-content: space-around;
+ position: relative;
+ background: var(--border-color, $border-color);
+}
+
+.devops-step {
+ $step-positions: 5% 10% 30% 42% 48% 55% 60% 70% 75% 90%;
+ @each $pos in $step-positions {
+ $i: index($step-positions, $pos);
+
+ &:nth-child(#{$i}) {
+ left: $pos;
+ }
+ }
+
+ position: absolute;
+ transform-origin: 75% 50%;
+ padding: 8px;
+ height: 50px;
+ width: 50px;
+ border-radius: 3px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ border: solid 1px var(--border-color, $border-color);
+ background: var(--white, $white);
+ transform: translate(-50%, -50%);
+ color: var(--gl-text-color-secondary, $gl-text-color-secondary);
+ fill: var(--gl-text-color-secondary, $gl-text-color-secondary);
+ box-shadow: 0 2px 4px var(--dropdown-shadow-color, $dropdown-shadow-color);
+
+ &:hover {
+ padding: 8px 10px;
+ fill: currentColor;
+ z-index: 100;
+ height: auto;
+ width: auto;
+
+ .devops-step-title {
+ max-height: 2em;
+ opacity: 1;
+ transition: opacity 0.2s;
+ }
+
+ svg {
+ transform: scale(1.5);
+ margin: $gl-btn-padding;
+ }
+ }
+
+ svg {
+ transition: transform 0.1s;
+ width: 30px;
+ height: 30px;
+ min-height: 30px;
+ min-width: 30px;
+ }
+}
+
+.devops-step-title {
+ max-height: 0;
+ opacity: 0;
+ text-transform: uppercase;
+ margin: $gl-vert-padding 0 0;
+ text-align: center;
+ font-size: 12px;
+}
+
+.devops-high-score {
+ color: var(--green-400, $green-400);
+}
+
+.devops-average-score {
+ color: var(--orange-500, $orange-500);
+}
+
+.devops-low-score {
+ color: var(--red-400, $red-400);
+}
diff --git a/app/assets/stylesheets/page_bundles/environments.scss b/app/assets/stylesheets/page_bundles/environments.scss
new file mode 100644
index 00000000000..871f118ea9d
--- /dev/null
+++ b/app/assets/stylesheets/page_bundles/environments.scss
@@ -0,0 +1,131 @@
+@import 'page_bundles/mixins_and_variables_and_functions';
+
+.environments-container {
+ .ci-table {
+ .commit-title {
+ margin: 0;
+ }
+
+ .external-url,
+ .dropdown-new {
+ color: var(--gray-500, $gray-500);
+ }
+
+ .build-link,
+ .ref-name {
+ color: var(--gray-900, $gray-900);
+ }
+
+ .folder-icon {
+ margin-right: 3px;
+ color: var(--gray-500, $gray-500);
+ display: inline-block;
+ vertical-align: text-top;
+ }
+
+ .folder-name {
+ cursor: pointer;
+ color: var(--gray-500, $gray-500);
+ display: inline-block;
+ }
+
+ .icon-container {
+ width: 20px;
+ text-align: center;
+ }
+
+ .no-btn {
+ border: 0;
+ background: none;
+ outline: none;
+ width: 100%;
+ text-align: left;
+ }
+
+ .environment-child-row {
+ padding-left: 20px;
+ }
+ }
+}
+
+.gl-responsive-table-row {
+ .branch-commit {
+ max-width: 100%;
+ }
+}
+
+.folder-row {
+ border-left: 0;
+ border-right: 0;
+
+ @media (min-width: map-get($grid-breakpoints, md)-1) {
+ border-top: 0;
+ }
+}
+
+.x-axis path,
+.y-axis path,
+.label-x-axis-line,
+.label-y-axis-line {
+ fill: none;
+ stroke-width: 1;
+ shape-rendering: crispEdges;
+}
+
+.x-axis path,
+.y-axis path {
+ stroke: var(--gray-300, $gray-300);
+}
+
+.label-x-axis-line,
+.label-y-axis-line {
+ stroke: var(--gray-100, $gray-100);
+}
+
+.y-axis {
+ line {
+ stroke: var(--gray-300, $gray-300);
+ stroke-width: 1;
+ }
+}
+
+.metric-area {
+ opacity: 0.25;
+}
+
+.rect-text-metric {
+ fill: var(--white, $white);
+ stroke-width: 1;
+ stroke: var(--gray-600, $gray-600);
+}
+
+.rect-axis-text {
+ fill: var(--white, $white);
+}
+
+.text-metric {
+ font-size: 12px;
+}
+
+.selected-metric-line {
+ stroke: var(--gray-900, $gray-900);
+ stroke-width: 1;
+}
+
+.deployment-line {
+ stroke: var(--white, $white);
+ stroke-width: 1;
+}
+
+.divider-line {
+ stroke-width: 1;
+ stroke: var(--gray-600, $gray-600);
+}
+
+.environments-actions {
+ .external-url,
+ .monitoring-url,
+ .terminal-button {
+ width: 38px;
+ }
+}
diff --git a/app/assets/stylesheets/page_bundles/error_tracking_details.scss b/app/assets/stylesheets/page_bundles/error_tracking_details.scss
new file mode 100644
index 00000000000..a47c5cc9b3e
--- /dev/null
+++ b/app/assets/stylesheets/page_bundles/error_tracking_details.scss
@@ -0,0 +1,51 @@
+@import 'page_bundles/mixins_and_variables_and_functions';
+
+.error-details {
+ li {
+ @include gl-line-height-32;
+ }
+
+ .btn-outline-info {
+ color: var(--blue-500, $blue-500);
+ border-color: var(--blue-500, $blue-500);
+ }
+
+ .error-details-header {
+ border-bottom: 1px solid var(--border-color, $border-color);
+
+ @include media-breakpoint-down(xs) {
+ flex-flow: column;
+
+ .error-details-meta-culprit {
+ display: flex;
+ }
+
+ .error-details-options {
+ width: 100%;
+
+ .dropdown-toggle {
+ text-align: center;
+ }
+ }
+ }
+ }
+}
+
+.stacktrace {
+ .file-title {
+ svg {
+ vertical-align: middle;
+ top: -1px;
+ }
+ }
+
+ .file-title-name {
+ &.limited-width {
+ max-width: 80%;
+ }
+ }
+
+ .line_content.old::before {
+ content: none !important;
+ }
+}
diff --git a/app/assets/stylesheets/page_bundles/error_tracking_index.scss b/app/assets/stylesheets/page_bundles/error_tracking_index.scss
new file mode 100644
index 00000000000..65bddfb7890
--- /dev/null
+++ b/app/assets/stylesheets/page_bundles/error_tracking_index.scss
@@ -0,0 +1,40 @@
+@import 'page_bundles/mixins_and_variables_and_functions';
+
+.error-list {
+ .dropdown {
+ min-width: auto;
+ }
+
+ .sort-control {
+ .btn {
+ padding-right: 2rem;
+ }
+
+ .gl-dropdown-caret {
+ position: absolute;
+ right: 0.5rem;
+ top: 0.5rem;
+ }
+ }
+
+ @include media-breakpoint-down(sm) {
+ .error-list-table {
+ .table-col {
+ min-height: 68px;
+
+ &:last-child {
+ background-color: var(--gray-10, $gray-10);
+
+ &::before {
+ content: none !important;
+ }
+
+ div {
+ width: 100% !important;
+ padding: 0 !important;
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/app/assets/stylesheets/page_bundles/experimental_separate_sign_up.scss b/app/assets/stylesheets/page_bundles/experimental_separate_sign_up.scss
new file mode 100644
index 00000000000..337b5b001fe
--- /dev/null
+++ b/app/assets/stylesheets/page_bundles/experimental_separate_sign_up.scss
@@ -0,0 +1,96 @@
+@import 'mixins_and_variables_and_functions';
+
+.signup-page {
+ .page-wrap {
+ background-color: var(--gray-10, $gray-10);
+ }
+
+ .signup-box-container {
+ max-width: 960px;
+ }
+
+ .signup-box {
+ background-color: var(--white, $white);
+ box-shadow: 0 0 0 1px var(--border-color, $border-color);
+ border-radius: $border-radius;
+ }
+
+ .form-control {
+ &:active,
+ &:focus {
+ background-color: var(--white, $white);
+ }
+ }
+
+ .devise-errors {
+ h2 {
+ font-size: $gl-font-size;
+ color: var(--red-700, $red-700);
+ }
+ }
+
+ .omniauth-divider {
+ &::before,
+ &::after {
+ content: '';
+ flex: 1;
+ border-bottom: 1px solid var(--gray-100, $gray-100);
+ margin: $gl-padding-24 0;
+ }
+
+ &::before {
+ margin-right: $gl-padding;
+ }
+
+ &::after {
+ margin-left: $gl-padding;
+ }
+ }
+
+ .omniauth-btn {
+ width: 48%;
+
+ @include media-breakpoint-down(md) {
+ width: 100%;
+ }
+
+ img {
+ width: $default-icon-size;
+ height: $default-icon-size;
+ }
+ }
+
+ .decline-page {
+ width: 350px;
+ }
+}
+
+.signup-page[data-page^='registrations:experience_levels'] {
+ $card-shadow-color: rgba(var(--black, $black), 0.2);
+
+ .page-wrap {
+ background-color: var(--white, $white);
+ }
+
+ .card-deck {
+ max-width: 828px;
+ }
+
+ .card {
+ transition: box-shadow 0.3s ease-in-out;
+ }
+
+ .card:hover {
+ box-shadow: 0 $gl-spacing-scale-3 $gl-spacing-scale-5 $card-shadow-color;
+ }
+
+ @media (min-width: $breakpoint-sm) {
+ .card-deck .card {
+ margin: 0 $gl-spacing-scale-3;
+ }
+ }
+
+ .stretched-link:hover {
+ text-decoration: none;
+ }
+}
diff --git a/app/assets/stylesheets/page_bundles/ide_themes/_dark.scss b/app/assets/stylesheets/page_bundles/ide_themes/_dark.scss
index 37e6be9849b..41f9a8e6db7 100644
--- a/app/assets/stylesheets/page_bundles/ide_themes/_dark.scss
+++ b/app/assets/stylesheets/page_bundles/ide_themes/_dark.scss
@@ -20,20 +20,28 @@
--ide-btn-default-background: transparent;
--ide-btn-default-border: #bfbfbf;
--ide-btn-default-hover-border: #d8d8d8;
+ --ide-btn-default-hover-border-width: 2px;
+ --ide-btn-default-focus-box-shadow: 0 0 0 1px #bfbfbf;
--ide-btn-primary-background: #1068bf;
--ide-btn-primary-border: #428fdc;
--ide-btn-primary-hover-border: #63a6e9;
+ --ide-btn-primary-hover-border-width: 2px;
+ --ide-btn-primary-focus-box-shadow: 0 0 0 1px #63a6e9;
--ide-btn-success-background: #217645;
--ide-btn-success-border: #108548;
--ide-btn-success-hover-border: #2da160;
+ --ide-btn-success-hover-border-width: 2px;
+ --ide-btn-success-focus-box-shadow: 0 0 0 1px #2da160;
+ --ide-btn-disabled-background: transparent;
--ide-btn-disabled-border: rgba(223, 223, 223, 0.24);
+ --ide-btn-disabled-hover-border: rgba(223, 223, 223, 0.24);
+ --ide-btn-disabled-hover-border-width: 1px;
+ --ide-btn-disabled-focus-box-shadow: 0 0 0 0 transparent;
--ide-btn-disabled-color: rgba(145, 145, 145, 0.48);
- --ide-btn-hover-border-width: 2px;
-
--ide-dropdown-background: #404040;
--ide-dropdown-hover-background: #525252;
diff --git a/app/assets/stylesheets/page_bundles/ide_themes/_solarized-dark.scss b/app/assets/stylesheets/page_bundles/ide_themes/_solarized-dark.scss
index 0ef0834d8db..ccb6f7a333b 100644
--- a/app/assets/stylesheets/page_bundles/ide_themes/_solarized-dark.scss
+++ b/app/assets/stylesheets/page_bundles/ide_themes/_solarized-dark.scss
@@ -18,22 +18,30 @@
--ide-input-color: #fff;
--ide-btn-default-background: transparent;
- --ide-btn-default-border: var(--ide-input-border);
+ --ide-btn-default-border: #d8d8d8;
--ide-btn-default-hover-border: #d8d8d8;
+ --ide-btn-default-hover-border-width: 2px;
+ --ide-btn-default-focus-box-shadow: 0 0 0 1px #d8d8d8;
--ide-btn-primary-background: #1068bf;
--ide-btn-primary-border: #428fdc;
--ide-btn-primary-hover-border: #63a6e9;
+ --ide-btn-primary-hover-border-width: 2px;
+ --ide-btn-primary-focus-box-shadow: 0 0 0 1px #63a6e9;
--ide-btn-success-background: #217645;
--ide-btn-success-border: #108548;
--ide-btn-success-hover-border: #2da160;
+ --ide-btn-success-hover-border-width: 2px;
+ --ide-btn-success-focus-box-shadow: 0 0 0 1px #2da160;
+ --ide-btn-disabled-background: transparent;
--ide-btn-disabled-border: rgba(223, 223, 223, 0.24);
+ --ide-btn-disabled-hover-border: rgba(223, 223, 223, 0.24);
+ --ide-btn-disabled-hover-border-width: 1px;
+ --ide-btn-disabled-focus-box-shadow: transparent;
--ide-btn-disabled-color: rgba(145, 145, 145, 0.48);
- --ide-btn-hover-border-width: 2px;
-
--ide-dropdown-background: #004c61;
--ide-dropdown-hover-background: #00617a;
diff --git a/app/assets/stylesheets/page_bundles/issues_list.scss b/app/assets/stylesheets/page_bundles/issues_list.scss
new file mode 100644
index 00000000000..8a958bdf0c5
--- /dev/null
+++ b/app/assets/stylesheets/page_bundles/issues_list.scss
@@ -0,0 +1,45 @@
+@import 'mixins_and_variables_and_functions';
+
+.issues-list {
+ &.manual-ordering {
+ background-color: var(--gray-10, $gray-10);
+ border-radius: $border-radius-default;
+ padding: $gl-padding-8;
+
+ .issue {
+ background-color: var(--white, $white);
+ margin-bottom: $gl-padding-8;
+ border-radius: $border-radius-default;
+ border: 1px solid var(--border-color, $border-color);
+ box-shadow: 0 1px 2px $issue-boards-card-shadow;
+ }
+ }
+
+ .issue {
+ padding: 10px $gl-padding;
+ position: relative;
+
+ .title {
+ margin-bottom: 2px;
+ }
+
+ .issue-labels,
+ .author-link {
+ display: inline-block;
+ }
+
+ .icon-merge-request-unmerged {
+ height: 13px;
+ margin-bottom: 3px;
+ }
+ }
+}
+
+.user-can-drag {
+ cursor: grab;
+}
+
+.is-ghost {
+ opacity: 0.3;
+ pointer-events: none;
+}
diff --git a/app/assets/stylesheets/page_bundles/jira_connect.scss b/app/assets/stylesheets/page_bundles/jira_connect.scss
index 83d16f29d49..b8cdd120e04 100644
--- a/app/assets/stylesheets/page_bundles/jira_connect.scss
+++ b/app/assets/stylesheets/page_bundles/jira_connect.scss
@@ -13,6 +13,7 @@ $atlaskit-border-color: #dfe1e6;
padding-top: $gl-padding-4;
.ak-button {
+ align-items: center;
height: auto;
margin-left: $btn-margin-5;
}
@@ -20,6 +21,74 @@ $atlaskit-border-color: #dfe1e6;
}
}
+$header-height: 40px;
+
+.jira-connect-header {
+ border-bottom: 1px solid $gray-100;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ min-height: $header-height;
+ padding-left: 16px;
+ padding-right: 16px;
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+}
+
+.jira-connect-user {
+ float: right;
+ position: relative;
+ top: -30px;
+}
+
+.jira-connect-app {
+ margin-top: $header-height;
+ max-width: 600px;
+ padding-top: 48px;
+ padding-left: 16px;
+ padding-right: 16px;
+ margin-left: auto;
+ margin-right: auto;
+ text-align: center;
+}
+
+.gl-mt-5 {
+ margin-top: 16px;
+}
+
+.heading-with-border {
+ border-bottom: 1px solid $gray-100;
+ display: inline-block;
+ padding-bottom: 16px;
+}
+
+svg {
+ fill: currentColor;
+
+ &.s16 {
+ height: 16px;
+ width: 16px;
+ }
+}
+
+.ak-field-group label {
+ text-align: left;
+}
+
+.ak-button__appearance-primary {
+ &:hover {
+ color: $white;
+ text-decoration: none;
+ }
+
+ svg {
+ align-self: center;
+ margin-left: 4px;
+ }
+}
+
.subscriptions {
tbody {
tr {
@@ -31,3 +100,11 @@ $atlaskit-border-color: #dfe1e6;
}
}
}
+
+.empty-subscriptions {
+ color: $gray-900;
+}
+
+.browser-limitations-notice {
+ margin-top: 32px;
+}
diff --git a/app/assets/stylesheets/page_bundles/jira_connect_users.scss b/app/assets/stylesheets/page_bundles/jira_connect_users.scss
new file mode 100644
index 00000000000..6725bf8f1a1
--- /dev/null
+++ b/app/assets/stylesheets/page_bundles/jira_connect_users.scss
@@ -0,0 +1,13 @@
+@import 'mixins_and_variables_and_functions';
+
+.jira-connect-users-container {
+ margin-left: auto;
+ margin-right: auto;
+ width: px-to-rem(350px);
+}
+
+.devise-layout-html body .navless-container {
+ @include media-breakpoint-down(xs) {
+ padding-top: 65px;
+ }
+}
diff --git a/app/assets/stylesheets/page_bundles/merge_conflicts.scss b/app/assets/stylesheets/page_bundles/merge_conflicts.scss
new file mode 100644
index 00000000000..b0655408edf
--- /dev/null
+++ b/app/assets/stylesheets/page_bundles/merge_conflicts.scss
@@ -0,0 +1,316 @@
+@import 'mixins_and_variables_and_functions';
+// Disabled to use the color map for creating color schemes
+// scss-lint:disable ColorVariable
+$colors: (
+ white-header-head-neutral : #e1fad7,
+ white-line-head-neutral : #effdec,
+ white-button-head-neutral : #9adb84,
+
+ white-header-head-chosen : #baf0a8,
+ white-line-head-chosen : #e1fad7,
+ white-button-head-chosen : #52c22d,
+
+ white-header-origin-neutral : #e0f0ff,
+ white-line-origin-neutral : #f2f9ff,
+ white-button-origin-neutral : #87c2fa,
+
+ white-header-origin-chosen : #add8ff,
+ white-line-origin-chosen : #e0f0ff,
+ white-button-origin-chosen : #268ced,
+
+ white-header-not-chosen : #f0f0f0,
+ white-line-not-chosen : $gray-light,
+
+ dark-header-head-neutral : rgba(#3f3, 0.2),
+ dark-line-head-neutral : rgba(#3f3, 0.1),
+ dark-button-head-neutral : #40874f,
+
+ dark-header-head-chosen : rgba(#3f3, 0.33),
+ dark-line-head-chosen : rgba(#3f3, 0.2),
+ dark-button-head-chosen : #258537,
+
+ dark-header-origin-neutral : rgba(#2878c9, 0.4),
+ dark-line-origin-neutral : rgba(#2878c9, 0.3),
+ dark-button-origin-neutral : #2a5c8c,
+
+ dark-header-origin-chosen : rgba(#2878c9, 0.6),
+ dark-line-origin-chosen : rgba(#2878c9, 0.4),
+ dark-button-origin-chosen : #1d6cbf,
+
+ dark-header-not-chosen : rgba(#fff, 0.25),
+ dark-line-not-chosen : rgba(#fff, 0.1),
+
+ monokai-header-head-neutral : rgba(#a6e22e, 0.25),
+ monokai-line-head-neutral : rgba(#a6e22e, 0.1),
+ monokai-button-head-neutral : #376b20,
+
+ monokai-header-head-chosen : rgba(#a6e22e, 0.4),
+ monokai-line-head-chosen : rgba(#a6e22e, 0.25),
+ monokai-button-head-chosen : #39800d,
+
+ monokai-header-origin-neutral : rgba(#60d9f1, 0.35),
+ monokai-line-origin-neutral : rgba(#60d9f1, 0.15),
+ monokai-button-origin-neutral : #38848c,
+
+ monokai-header-origin-chosen : rgba(#60d9f1, 0.5),
+ monokai-line-origin-chosen : rgba(#60d9f1, 0.35),
+ monokai-button-origin-chosen : #3ea4b2,
+
+ monokai-header-not-chosen : rgba(#76715d, 0.24),
+ monokai-line-not-chosen : rgba(#76715d, 0.1),
+
+ solarized-light-header-head-neutral : rgba(#859900, 0.37),
+ solarized-light-line-head-neutral : rgba(#859900, 0.2),
+ solarized-light-button-head-neutral : #afb262,
+
+ solarized-light-header-head-chosen : rgba(#859900, 0.5),
+ solarized-light-line-head-chosen : rgba(#859900, 0.37),
+ solarized-light-button-head-chosen : #94993d,
+
+ solarized-light-header-origin-neutral : rgba(#2878c9, 0.37),
+ solarized-light-line-origin-neutral : rgba(#2878c9, 0.15),
+ solarized-light-button-origin-neutral : #60a1bf,
+
+ solarized-light-header-origin-chosen : rgba(#2878c9, 0.6),
+ solarized-light-line-origin-chosen : rgba(#2878c9, 0.37),
+ solarized-light-button-origin-chosen : #2482b2,
+
+ solarized-light-header-not-chosen : rgba(#839496, 0.37),
+ solarized-light-line-not-chosen : rgba(#839496, 0.2),
+
+ solarized-dark-header-head-neutral : rgba(#859900, 0.35),
+ solarized-dark-line-head-neutral : rgba(#859900, 0.15),
+ solarized-dark-button-head-neutral : #376b20,
+
+ solarized-dark-header-head-chosen : rgba(#859900, 0.5),
+ solarized-dark-line-head-chosen : rgba(#859900, 0.35),
+ solarized-dark-button-head-chosen : #39800d,
+
+ solarized-dark-header-origin-neutral : rgba(#2878c9, 0.35),
+ solarized-dark-line-origin-neutral : rgba(#2878c9, 0.15),
+ solarized-dark-button-origin-neutral : #086799,
+
+ solarized-dark-header-origin-chosen : rgba(#2878c9, 0.6),
+ solarized-dark-line-origin-chosen : rgba(#2878c9, 0.35),
+ solarized-dark-button-origin-chosen : #0082cc,
+
+ solarized_dark_header_not_chosen : rgba(#839496, 0.25),
+ solarized_dark_line_not_chosen : rgba(#839496, 0.15),
+
+ none_header_head_neutral : $gray-normal,
+ none_line_head_neutral : $gray-normal,
+ none_button_head_neutral : $gray-normal,
+
+ none_header_head_chosen : $gray-darker,
+ none_line_head_chosen : $gray-darker,
+ none_button_head_chosen : $gray-darker,
+
+ none_header_origin_neutral : $gray-normal,
+ none_line_origin_neutral : $gray-normal,
+ none_button_origin_neutral : $gray-normal,
+
+ none_header_origin_chosen : $gray-darker,
+ none_line_origin_chosen : $gray-darker,
+ none_button_origin_chosen : $gray-darker,
+
+ none_header_not_chosen : $gray-light,
+ none_line_not_chosen : $gray-light
+
+);
+// scss-lint:enable ColorVariable
+
+@mixin color-scheme($color) {
+ .header.line_content,
+ .diff-line-num {
+ &.origin {
+ background-color: map-get($colors, #{$color}-header-origin-neutral);
+ border-color: map-get($colors, #{$color}-header-origin-neutral);
+
+ button {
+ background-color: map-get($colors, #{$color}-button-origin-neutral);
+ border-color: darken(map-get($colors, #{$color}-button-origin-neutral), 15);
+ }
+
+ &.selected {
+ background-color: map-get($colors, #{$color}-header-origin-chosen);
+ border-color: map-get($colors, #{$color}-header-origin-chosen);
+
+ button {
+ background-color: map-get($colors, #{$color}-button-origin-chosen);
+ border-color: darken(map-get($colors, #{$color}-button-origin-chosen), 15);
+ }
+ }
+
+ &.unselected {
+ background-color: map-get($colors, #{$color}-header-not-chosen);
+ border-color: map-get($colors, #{$color}-header-not-chosen);
+
+ button {
+ background-color: lighten(map-get($colors, #{$color}-button-origin-neutral), 15);
+ border-color: map-get($colors, #{$color}-button-origin-neutral);
+ }
+ }
+ }
+
+ &.head {
+ background-color: map-get($colors, #{$color}-header-head-neutral);
+ border-color: map-get($colors, #{$color}-header-head-neutral);
+
+ button {
+ background-color: map-get($colors, #{$color}-button-head-neutral);
+ border-color: darken(map-get($colors, #{$color}-button-head-neutral), 15);
+ }
+
+ &.selected {
+ background-color: map-get($colors, #{$color}-header-head-chosen);
+ border-color: map-get($colors, #{$color}-header-head-chosen);
+
+ button {
+ background-color: map-get($colors, #{$color}-button-head-chosen);
+ border-color: darken(map-get($colors, #{$color}-button-head-chosen), 15);
+ }
+ }
+
+ &.unselected {
+ background-color: map-get($colors, #{$color}-header-not-chosen);
+ border-color: map-get($colors, #{$color}-header-not-chosen);
+
+ button {
+ background-color: lighten(map-get($colors, #{$color}-button-head-neutral), 15);
+ border-color: map-get($colors, #{$color}-button-head-neutral);
+ }
+ }
+ }
+ }
+
+ .line_content {
+ &.origin {
+ background-color: map-get($colors, #{$color}-line-origin-neutral);
+
+ &.selected {
+ background-color: map-get($colors, #{$color}-line-origin-chosen);
+ }
+
+ &.unselected {
+ background-color: map-get($colors, #{$color}-line-not-chosen);
+ }
+ }
+
+ &.head {
+ background-color: map-get($colors, #{$color}-line-head-neutral);
+
+ &.selected {
+ background-color: map-get($colors, #{$color}-line-head-chosen);
+ }
+
+ &.unselected {
+ background-color: map-get($colors, #{$color}-line-not-chosen);
+ }
+ }
+ }
+}
+
+#conflicts {
+ .white {
+ @include color-scheme('white'); }
+
+ .dark {
+ @include color-scheme('dark'); }
+
+ .monokai {
+ @include color-scheme('monokai'); }
+
+ .solarized-light {
+ @include color-scheme('solarized-light'); }
+
+ .solarized-dark {
+ @include color-scheme('solarized-dark'); }
+
+ .none {
+ .line_content.header {
+ button {
+ color: $gray-900;
+ }
+ }
+ }
+
+ .diff-wrap-lines .line_content {
+ white-space: normal;
+ min-height: 19px;
+ }
+
+ .line_content.header {
+ position: relative;
+
+ button {
+ border-radius: 2px;
+ font-size: 10px;
+ position: absolute;
+ right: 10px;
+ padding: 0;
+ outline: none;
+ color: var(--white, $white);
+ width: 75px; // static width to make 2 buttons have same width
+ height: 19px;
+ }
+ }
+
+ .btn-success .fa-spinner {
+ color: var(--white, $white);
+ }
+
+ .editor-wrap {
+ &.is-loading {
+ .editor {
+ display: none;
+ }
+
+ .loading {
+ display: block;
+ }
+ }
+
+ &.saved {
+ .editor {
+ border-top: solid 2px var(--green-300, $green-300);
+ }
+ }
+
+ .editor {
+ pre {
+ height: 350px;
+ border: 0;
+ border-radius: 0;
+ margin-bottom: 0;
+ }
+ }
+
+ .loading {
+ display: none;
+ }
+ }
+
+ .discard-changes-alert {
+ background-color: var(--gray-10, $gray-10);
+ text-align: right;
+ padding: $gl-padding-top $gl-padding;
+ color: var(--gl-text-color, $gl-text-color);
+
+ .discard-actions {
+ display: inline-block;
+ margin-left: 10px;
+ }
+ }
+
+ .resolve-conflicts-form {
+ h4 {
+ margin-top: 0;
+ }
+
+ .resolve-info {
+ @media(max-width: map-get($grid-breakpoints, lg)-1) {
+ margin-bottom: $gl-padding;
+ }
+ }
+ }
+}
diff --git a/app/assets/stylesheets/page_bundles/merge_requests.scss b/app/assets/stylesheets/page_bundles/merge_requests.scss
new file mode 100644
index 00000000000..5553dffac05
--- /dev/null
+++ b/app/assets/stylesheets/page_bundles/merge_requests.scss
@@ -0,0 +1,96 @@
+@import 'mixins_and_variables_and_functions';
+
+.compare-versions-container {
+ min-width: 0;
+}
+
+.diff-files-holder {
+ flex: 1;
+ min-width: 0;
+ z-index: 201;
+}
+
+.diff-tree-list {
+ position: -webkit-sticky;
+ position: sticky;
+ $top-pos: $header-height + $mr-tabs-height + $mr-version-controls-height + 15px;
+ top: $top-pos;
+ max-height: calc(100vh - #{$top-pos});
+ z-index: 202;
+
+ .with-system-header & {
+ top: $top-pos + $system-header-height;
+ }
+
+ .with-system-header.with-performance-bar & {
+ top: $top-pos + $system-header-height + $performance-bar-height;
+ }
+
+ .with-performance-bar & {
+ $performance-bar-top-pos: $performance-bar-height + $top-pos;
+ top: $performance-bar-top-pos;
+ max-height: calc(100vh - #{$performance-bar-top-pos});
+ }
+
+ .drag-handle {
+ bottom: 16px;
+ transform: translateX(10px);
+ }
+}
+
+.tree-list-holder {
+ height: 100%;
+
+ .file-row {
+ margin-left: 0;
+ margin-right: 0;
+ }
+}
+
+.tree-list-scroll {
+ max-height: 100%;
+ padding-bottom: $grid-size;
+ overflow-y: scroll;
+ overflow-x: auto;
+}
+
+.tree-list-search {
+ flex: 0 0 34px;
+
+ .form-control {
+ padding-left: 30px;
+ }
+}
+
+.tree-list-icon {
+ top: 50%;
+ left: 10px;
+ transform: translateY(-50%);
+
+ &,
+ svg {
+ fill: var(--gray-400, $gray-400);
+ }
+}
+
+.tree-list-clear-icon {
+ right: 10px;
+ left: auto;
+ line-height: 0;
+}
+
+@media (max-width: map-get($grid-breakpoints, md)-1) {
+ .diffs .files {
+ .diff-tree-list {
+ position: relative;
+ top: 0;
+ // !important is required to override inline styles of resizable sidebar
+ width: 100% !important;
+ }
+
+ .tree-list-holder {
+ max-height: calc(50px + 50vh);
+ padding-right: 0;
+ }
+ }
+}
diff --git a/app/assets/stylesheets/page_bundles/milestone.scss b/app/assets/stylesheets/page_bundles/milestone.scss
new file mode 100644
index 00000000000..858e13fc558
--- /dev/null
+++ b/app/assets/stylesheets/page_bundles/milestone.scss
@@ -0,0 +1,254 @@
+@import 'mixins_and_variables_and_functions';
+
+$status-box-line-height: 26px;
+
+.issues-sortable-list .str-truncated {
+ max-width: 90%;
+}
+
+.milestones {
+ padding: $gl-padding-8;
+ margin-top: $gl-padding-8;
+ border-radius: $border-radius-default;
+ background-color: var(--gray-100, $gray-100);
+
+ .milestone {
+ border: 0;
+ padding: $gl-padding-top $gl-padding;
+ border-radius: $border-radius-default;
+ background-color: var(--white, $white);
+
+ &:not(:last-child) {
+ margin-bottom: $gl-padding-4;
+ }
+
+ h4 {
+ font-weight: $gl-font-weight-bold;
+ }
+
+ .progress {
+ width: 100%;
+ height: 6px;
+ margin-bottom: $gl-padding-4;
+ }
+
+ .milestone-progress,
+ .milestone-release-links {
+ a {
+ color: var(--blue-600, $blue-600);
+ }
+ }
+
+ .status-box {
+ font-size: $tooltip-font-size;
+ margin-top: 0;
+ margin-right: $gl-padding-4;
+ line-height: $status-box-line-height;
+
+ @include media-breakpoint-down(xs) {
+ line-height: unset;
+ padding: $gl-padding-4 $gl-input-padding;
+ }
+ }
+ }
+}
+
+.milestone-content {
+ .issues-count {
+ margin-right: 17px;
+ float: right;
+ width: 105px;
+ }
+
+ .issuable-row {
+ span {
+ a {
+ color: var(--gray-900, $gray-900);
+ word-wrap: break-word;
+ }
+
+ .gl-label-link {
+ color: inherit;
+ }
+ }
+ }
+
+ .card-header {
+ line-height: $line-height-base;
+ padding: 14px 16px;
+ display: flex;
+
+ .title {
+ flex: 1;
+ flex-grow: 2;
+ }
+
+ .counter {
+ flex: 0;
+ padding-left: 16px;
+ }
+ }
+}
+
+.milestone-sidebar {
+ .milestone-progress {
+ .title {
+ padding-top: 5px;
+ }
+
+ .progress {
+ height: 6px;
+ margin: 0;
+ }
+
+ .sidebar-collapsed-icon {
+ clear: both;
+ padding: 15px 5px 5px;
+
+ .progress {
+ margin: 5px 0;
+ }
+ }
+ }
+
+ .collapsed-milestone-date {
+ font-size: 12px;
+ }
+
+ .milestone-date {
+ display: block;
+ }
+
+ .date-separator {
+ line-height: 5px;
+ }
+
+ .remaining-days strong {
+ font-weight: $gl-font-weight-normal;
+ }
+
+ .milestone-stat {
+ float: left;
+ margin-right: 14px;
+ }
+
+ .milestone-stat:last-child {
+ margin-right: 0;
+ }
+
+ .right-sidebar-expanded & {
+ .gutter-toggle {
+ margin-bottom: $sidebar-milestone-toggle-bottom-margin;
+ }
+ }
+
+ .right-sidebar-collapsed & {
+ .milestone-progress {
+ padding-top: 0;
+ }
+
+ .reference {
+ border-top: 1px solid $border-gray-normal;
+ }
+ }
+}
+
+.milestone-issues-list,
+.milestone-merge_requests-list {
+ .issuable-detail {
+ display: block;
+ margin-top: 7px;
+
+ .issue-link {
+ display: inline-block;
+ }
+
+ .issuable-number {
+ color: var(--gray-500, $gray-500);
+ margin-right: 5px;
+ }
+
+ .avatar {
+ float: none;
+ }
+
+ > a:not(:last-of-type) {
+ margin-right: 5px;
+ }
+ }
+}
+
+.milestone-detail {
+ border-bottom: 1px solid var(--border-color, $border-color);
+}
+
+@include media-breakpoint-down(xs) {
+ .milestone-actions {
+ @include clearfix();
+ padding-top: $gl-vert-padding;
+
+ .btn:first-child {
+ margin-left: 0;
+ }
+ }
+}
+
+.milestone-page-header {
+ display: flex;
+ flex-flow: row;
+ align-items: center;
+ flex-wrap: wrap;
+
+ .status-box {
+ margin-top: 0;
+ order: 1;
+ }
+
+ .milestone-buttons {
+ margin-left: auto;
+ order: 2;
+
+ .verbose {
+ display: none;
+ }
+ }
+
+ .header-text-content {
+ order: 3;
+ width: 100%;
+ }
+
+ @include media-breakpoint-up(xs) {
+ .milestone-buttons .verbose {
+ display: inline;
+ }
+
+ .header-text-content {
+ order: 2;
+ width: auto;
+ }
+
+ .milestone-buttons {
+ order: 3;
+ }
+ }
+}
+
+.issuable-row {
+ background-color: var(--white, $white);
+}
+
+.milestone-popover-instructions-list {
+ padding-left: 2em;
+
+ > li {
+ padding-left: 1em;
+ }
+}
+
+@include media-breakpoint-down(xs) {
+ .milestone-banner-text,
+ .milestone-banner-link {
+ display: inline;
+ }
+}
diff --git a/app/assets/stylesheets/page_bundles/pipeline.scss b/app/assets/stylesheets/page_bundles/pipeline.scss
new file mode 100644
index 00000000000..8e7be629481
--- /dev/null
+++ b/app/assets/stylesheets/page_bundles/pipeline.scss
@@ -0,0 +1,484 @@
+@import 'mixins_and_variables_and_functions';
+@import './pipeline_mixins';
+
+/**
+ * Pipeline Page Bundle
+ *
+ * Styles used to render a single pipeline page.
+ *
+ * Includes its tabs:
+ *
+ * - [data-page='projects:pipelines:show']
+ * - [data-page='projects:pipelines:dag']
+ * - [data-page='projects:pipelines:builds']
+ * - [data-page='projects:pipelines:failures']
+ * - [data-page='projects:pipelines:tests']
+ * - ...
+ */
+
+.tab-pane {
+ .ci-table {
+ thead th {
+ border-top: 0;
+ }
+ }
+}
+
+.build-failures {
+ .build-state {
+ padding: 20px 2px;
+
+ .build-name {
+ font-weight: $gl-font-weight-normal;
+ }
+
+ .stage {
+ color: $gl-text-color-secondary;
+ font-weight: $gl-font-weight-normal;
+ vertical-align: middle;
+ }
+ }
+
+ .build-log {
+ border: 0;
+ line-height: initial;
+ }
+
+ .build-trace-row td {
+ border-top: 0;
+ border-bottom-width: 1px;
+ border-bottom-style: solid;
+ padding-top: 0;
+ }
+
+ .build-trace {
+ width: 100%;
+ text-align: left;
+ margin-top: $gl-padding;
+ }
+
+ .build-name {
+ width: 196px;
+
+ a {
+ font-weight: $gl-font-weight-bold;
+ color: $gl-text-color;
+ text-decoration: none;
+
+ &:focus,
+ &:hover {
+ text-decoration: underline;
+ }
+ }
+ }
+
+ .build-actions {
+ width: 70px;
+ text-align: right;
+ }
+
+ .build-stage {
+ width: 140px;
+ }
+
+ .ci-status-icon-failed {
+ padding: 10px 0 10px 12px;
+ width: 12px + 24px; // padding-left + svg width
+ }
+
+ .build-icon svg {
+ width: 24px;
+ height: 24px;
+ vertical-align: middle;
+ }
+
+ .build-state,
+ .build-trace-row {
+ > td:last-child {
+ padding-right: 0;
+ }
+ }
+
+ @include media-breakpoint-down(sm) {
+ td:empty {
+ display: none;
+ }
+
+ .ci-table {
+ margin-top: 2 * $gl-padding;
+ }
+
+ .build-trace-container {
+ padding-top: $gl-padding;
+ padding-bottom: $gl-padding;
+ }
+
+ .build-trace {
+ margin-bottom: 0;
+ margin-top: 0;
+ }
+ }
+}
+
+.pipeline-tab-content {
+ display: flex;
+ width: 100%;
+ min-height: $dropdown-max-height-lg;
+ background-color: $gray-light;
+ padding: $gl-padding 0;
+ overflow: auto;
+}
+
+// Pipeline graph, used at
+// app/assets/javascripts/pipelines/components/graph/graph_component.vue
+.pipeline-graph {
+ white-space: nowrap;
+ transition: max-height 0.3s, padding 0.3s;
+
+ .stage-column-list,
+ .builds-container > ul {
+ padding: 0;
+ }
+
+ a {
+ text-decoration: none;
+ color: $gl-text-color;
+ }
+
+ svg {
+ vertical-align: middle;
+ }
+
+ .stage-column {
+ display: inline-block;
+ vertical-align: top;
+
+ &.left-margin {
+ &:not(:first-child) {
+ margin-left: 44px;
+
+ .left-connector {
+ @include flat-connector-before;
+ }
+ }
+ }
+
+ &.no-margin {
+ margin: 0;
+ }
+
+ li {
+ list-style: none;
+ }
+
+ // when downstream pipelines are present, the last stage isn't the last column
+ &:last-child:not(.has-downstream) {
+ .build {
+ // Remove right connecting horizontal line from first build in last stage
+ &:first-child::after {
+ border: 0;
+ }
+ // Remove right curved connectors from all builds in last stage
+ &:not(:first-child)::after {
+ border: 0;
+ }
+ // Remove opposite curve
+ .curve::before {
+ display: none;
+ }
+ }
+ }
+
+ // when upstream pipelines are present, the first stage isn't the first column
+ &:first-child:not(.has-upstream) {
+ .build {
+ // Remove left curved connectors from all builds in first stage
+ &:not(:first-child)::before {
+ border: 0;
+ }
+ // Remove opposite curve
+ .curve::after {
+ display: none;
+ }
+ }
+ }
+
+ // Curve first child connecting lines in opposite direction
+ .curve {
+ display: none;
+
+ &::before,
+ &::after {
+ content: '';
+ width: 21px;
+ height: 25px;
+ position: absolute;
+ top: -31px;
+ border-top: 2px solid $border-color;
+ }
+
+ &::after {
+ left: -44px;
+ border-right: 2px solid $border-color;
+ border-radius: 0 20px;
+ }
+
+ &::before {
+ right: -44px;
+ border-left: 2px solid $border-color;
+ border-radius: 20px 0 0;
+ }
+ }
+ }
+
+ .stage-name {
+ margin: 0 0 15px 10px;
+ font-weight: $gl-font-weight-bold;
+ width: 176px;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ line-height: 2.2em;
+ }
+
+ .build {
+ position: relative;
+ width: 186px;
+ margin-bottom: 10px;
+ white-space: normal;
+
+ .ci-job-dropdown-container {
+ // override dropdown.scss
+ .dropdown-menu li button {
+ padding: 0;
+ text-align: center;
+ }
+ }
+
+ // ensure .build-content has hover style when action-icon is hovered
+ .ci-job-dropdown-container:hover .build-content {
+ @extend .build-content:hover;
+ }
+
+ .ci-status-icon svg {
+ height: 24px;
+ width: 24px;
+ }
+
+ .dropdown-menu-toggle {
+ background-color: transparent;
+ border: 0;
+ padding: 0;
+
+ &:focus {
+ outline: none;
+ }
+ }
+
+ .build-content {
+ @include build-content();
+ }
+
+ a.build-content:hover,
+ button.build-content:hover {
+ background-color: $gray-darker;
+ border: 1px solid $dropdown-toggle-active-border-color;
+ }
+
+ // Connect first build in each stage with right horizontal line
+ &:first-child {
+ &::after {
+ content: '';
+ position: absolute;
+ top: 48%;
+ right: -48px;
+ border-top: 2px solid $border-color;
+ width: 48px;
+ height: 1px;
+ }
+ }
+
+ // Connect each build (except for first) with curved lines
+ &:not(:first-child) {
+ &::after,
+ &::before {
+ content: '';
+ top: -49px;
+ position: absolute;
+ border-bottom: 2px solid $border-color;
+ width: 25px;
+ height: 69px;
+ }
+
+ // Right connecting curves
+ &::after {
+ right: -25px;
+ border-right: 2px solid $border-color;
+ border-radius: 0 0 20px;
+ }
+
+ // Left connecting curves
+ &::before {
+ left: -25px;
+ border-left: 2px solid $border-color;
+ border-radius: 0 0 0 20px;
+ }
+ }
+
+ // Connect second build to first build with smaller curved line
+ &:nth-child(2) {
+ &::after,
+ &::before {
+ height: 29px;
+ top: -9px;
+ }
+
+ .curve {
+ display: block;
+ }
+ }
+ }
+
+ .ci-action-icon-container {
+ position: absolute;
+ right: 5px;
+ top: 50%;
+ transform: translateY(-50%);
+
+ // Action Icons in big pipeline-graph nodes
+ &.ci-action-icon-wrapper {
+ height: 30px;
+ width: 30px;
+ border-radius: 100%;
+ display: block;
+ padding: 0;
+ line-height: 0;
+
+ svg {
+ fill: $gl-text-color-secondary;
+ }
+
+ .spinner {
+ top: 2px;
+ }
+
+ &.play {
+ svg {
+ left: 1px;
+ top: 1px;
+ }
+ }
+ }
+ }
+
+ .stage-action svg {
+ left: 1px;
+ top: -2px;
+ }
+}
+
+// Triggers the dropdown in the big pipeline graph
+.dropdown-counter-badge {
+ font-weight: 100;
+ font-size: 15px;
+ position: absolute;
+ right: 13px;
+ top: 8px;
+}
+
+.split-report-section {
+ border-bottom: 1px solid var(--gray-50, $gray-50);
+
+ .report-block-container {
+ max-height: 500px;
+ overflow: auto;
+ }
+
+ .space-children,
+ .space-children > span {
+ display: flex;
+ align-self: center;
+ }
+
+ .media {
+ align-items: center;
+ padding: 10px;
+ line-height: 20px;
+
+ /*
+ This fixes the wrapping div of the icon in the report header.
+ Apparently the borderless status icons are half the size of the status icons with border.
+ This means we have to double the size of the wrapping div for borderless icons.
+ */
+ .space-children:first-child {
+ width: 32px;
+ height: 32px;
+ align-items: center;
+ justify-content: center;
+ margin-right: 5px;
+ margin-left: 1px;
+ }
+ }
+
+ .code-text {
+ width: 100%;
+ flex: 1;
+ }
+}
+
+.big-pipeline-graph-dropdown-menu {
+ @include pipeline-graph-dropdown-menu();
+ width: 195px;
+ min-width: 195px;
+ left: 100%;
+ top: -10px;
+ box-shadow: 0 1px 5px $black-transparent;
+
+ /**
+ * Top arrow in the dropdown in the big pipeline graph
+ */
+ &::before,
+ &::after {
+ content: '';
+ display: inline-block;
+ position: absolute;
+ width: 0;
+ height: 0;
+ border-color: transparent;
+ border-style: solid;
+ top: 18px;
+ }
+
+ &::before {
+ left: -6px;
+ margin-top: 3px;
+ border-width: 7px 5px 7px 0;
+ border-right-color: $border-color;
+ }
+
+ &::after {
+ left: -5px;
+ border-width: 10px 7px 10px 0;
+ border-right-color: $white;
+ }
+}
+
+.codequality-report {
+ .media {
+ padding: $gl-padding;
+ }
+
+ .media-body {
+ flex-direction: row;
+ }
+
+ .report-block-container {
+ height: auto !important;
+ }
+}
+
+.test-reports-table {
+ .build-trace {
+ @include build-trace();
+ }
+}
diff --git a/app/assets/stylesheets/page_bundles/pipelines.scss b/app/assets/stylesheets/page_bundles/pipelines.scss
new file mode 100644
index 00000000000..6ff07017d2e
--- /dev/null
+++ b/app/assets/stylesheets/page_bundles/pipelines.scss
@@ -0,0 +1,195 @@
+@import 'mixins_and_variables_and_functions';
+@import './pipeline_mixins';
+
+/**
+ * Pipelines Bundle: Pipeline lists and Mini Pipelines
+ */
+
+// Pipelines list
+// Should affect pipelines table components rendered by:
+// - app/assets/javascripts/commit/pipelines/pipelines_bundle.js
+
+.pipelines {
+ .badge {
+ margin-bottom: 3px;
+ }
+
+ .pipeline-actions {
+ min-width: 170px; //Guarantees buttons don't break in several lines.
+
+ .btn-default {
+ color: $gl-text-color-secondary;
+ }
+
+ .btn.btn-retry:hover,
+ .btn.btn-retry:focus {
+ border-color: $dropdown-toggle-active-border-color;
+ background-color: $white-normal;
+ }
+
+ svg path {
+ fill: $gl-text-color-secondary;
+ }
+
+ .dropdown-menu {
+ max-height: $dropdown-max-height;
+ overflow-y: auto;
+ }
+
+ .dropdown-toggle,
+ .dropdown-menu {
+ color: $gl-text-color-secondary;
+
+ .fa {
+ color: $gl-text-color-secondary;
+ font-size: 14px;
+ }
+ }
+
+ .btn-group.open .btn-default {
+ background-color: $white-normal;
+ border-color: $border-white-normal;
+ }
+
+ .btn .text-center {
+ display: inline;
+ }
+
+ .tooltip {
+ white-space: nowrap;
+ }
+ }
+
+ .pipeline-tags .label-container {
+ white-space: normal;
+ }
+}
+
+// Mini Pipelines
+
+.stage-cell {
+ .mini-pipeline-graph-dropdown-toggle {
+ svg {
+ height: $ci-action-icon-size;
+ width: $ci-action-icon-size;
+ position: absolute;
+ top: -1px;
+ left: -1px;
+ z-index: 2;
+ overflow: visible;
+ }
+
+ &:hover,
+ &:active,
+ &:focus {
+ svg {
+ top: -2px;
+ left: -2px;
+ }
+ }
+ }
+
+ .stage-container {
+ display: inline-block;
+ position: relative;
+ vertical-align: middle;
+ height: $ci-action-icon-size;
+ margin: 3px 0;
+
+ + .stage-container {
+ margin-left: 6px;
+ }
+
+ // Hack to show a button tooltip inline
+ button.has-tooltip + .tooltip {
+ min-width: 105px;
+ }
+
+ // Bootstrap way of showing the content inline for anchors.
+ a.has-tooltip {
+ white-space: nowrap;
+ }
+
+ &:not(:last-child) {
+ &::after {
+ content: '';
+ width: 7px;
+ position: absolute;
+ right: -7px;
+ top: 11px;
+ border-bottom: 2px solid $border-color;
+ }
+ }
+
+ //delete when all pipelines are updated to new size
+ &.mr-widget-pipeline-stages {
+ + .stage-container {
+ margin-left: 4px;
+ }
+
+ &:not(:last-child) {
+ &::after {
+ width: 4px;
+ right: -4px;
+ top: 11px;
+ }
+ }
+ }
+ }
+}
+
+// Dropdown button in mini pipeline graph
+button.mini-pipeline-graph-dropdown-toggle {
+ @include mini-pipeline-item();
+}
+
+// Action icons inside dropdowns:
+// mini graph in pipelines table
+// mini graph in MR widget pipeline
+// mini graph in Commit widget pipeline
+.mini-pipeline-graph-dropdown-menu {
+ @include pipeline-graph-dropdown-menu();
+
+ &::before,
+ &::after {
+ content: '';
+ display: inline-block;
+ position: absolute;
+ width: 0;
+ height: 0;
+ border-color: transparent;
+ border-style: solid;
+ top: -6px;
+ left: 50%;
+ transform: translate(-50%, 0);
+ border-width: 0 5px 6px;
+
+ @include media-breakpoint-down(sm) {
+ left: 100%;
+ margin-left: -12px;
+ }
+ }
+
+ &::before {
+ border-width: 0 5px 5px;
+ border-bottom-color: $border-color;
+ }
+
+ &::after {
+ margin-top: 1px;
+ border-bottom-color: $white;
+ }
+
+ /**
+ * Center dropdown menu in mini graph
+ */
+ .dropdown &.dropdown-menu {
+ transform: translate(-80%, 0);
+
+ @media (min-width: map-get($grid-breakpoints, md)) {
+ transform: translate(-50%, 0);
+ right: auto;
+ left: 50%;
+ }
+ }
+}
diff --git a/app/assets/stylesheets/page_bundles/reports.scss b/app/assets/stylesheets/page_bundles/reports.scss
new file mode 100644
index 00000000000..5a9dd454970
--- /dev/null
+++ b/app/assets/stylesheets/page_bundles/reports.scss
@@ -0,0 +1,94 @@
+@import 'mixins_and_variables_and_functions';
+
+.mr-widget-grouped-section {
+ .report-block-container {
+ max-height: 170px;
+ overflow: auto;
+ }
+
+ .report-block-list-issue-parent {
+ padding: $gl-padding-top $gl-padding;
+ border-top: 1px solid $border-color;
+ }
+}
+
+.report-block-container {
+ border-top: 1px solid $border-color;
+ padding: $gl-padding - 2;
+ background-color: $gray-light;
+
+ // Clean MR widget CSS
+ line-height: 20px;
+}
+
+.report-block-list {
+ list-style: none;
+ padding: 0 1px;
+ margin: 0;
+}
+
+.report-block-list-icon {
+ display: flex;
+
+ &.failed svg {
+ color: var(--red-500, $red-500);
+ }
+
+ &.success svg {
+ color: var(--green-500, $green-500);
+ }
+
+ &.neutral svg {
+ color: var(--gray-500, $gray-500);
+ }
+
+ .ci-status-icon {
+ svg {
+ width: 24px;
+ height: 24px;
+ }
+ }
+}
+
+.report-block-list-issue {
+ display: flex;
+}
+
+.is-dismissed .report-block-list-issue-description,
+.is-dismissed .vulnerability-name-button {
+ text-decoration: line-through;
+}
+
+.report-block-list-issue-description-text::after {
+ content: '\00a0';
+}
+
+.report-block-list-issue-description {
+ align-content: space-around;
+ align-items: flex-start;
+ flex-wrap: wrap;
+ display: flex;
+ align-self: center;
+}
+
+.report-block {
+ .break-link {
+ word-wrap: break-word;
+ word-break: break-all;
+ }
+}
+
+.report-block-issue-code {
+ width: 600px;
+}
+
+.modal-security-report-dast {
+ .modal-dialog {
+ max-width: $modal-lg;
+ }
+
+ // This is temporary till we get the new modals hooked up
+ &.modal-hide-footer .modal-footer {
+ display: none;
+ }
+}
diff --git a/app/assets/stylesheets/page_bundles/terminal.scss b/app/assets/stylesheets/page_bundles/terminal.scss
new file mode 100644
index 00000000000..627baf96d6f
--- /dev/null
+++ b/app/assets/stylesheets/page_bundles/terminal.scss
@@ -0,0 +1,3 @@
+#terminal > div {
+ min-height: 450px;
+}
diff --git a/app/assets/stylesheets/page_bundles/wiki.scss b/app/assets/stylesheets/page_bundles/wiki.scss
new file mode 100644
index 00000000000..eb34e7f3876
--- /dev/null
+++ b/app/assets/stylesheets/page_bundles/wiki.scss
@@ -0,0 +1,159 @@
+@import 'mixins_and_variables_and_functions';
+
+.title .edit-wiki-header {
+ width: 780px;
+ margin-left: auto;
+ margin-right: auto;
+ padding-right: 7px;
+}
+
+.wiki-page-header {
+ position: relative;
+
+ .wiki-breadcrumb {
+ border-bottom: 1px solid var(--gray-50, $gray-50);
+ padding: 11px 0;
+ }
+
+ .wiki-page-title {
+ margin: 0;
+ font-size: 22px;
+ }
+
+ .wiki-last-edit-by {
+ display: block;
+ color: var(--gray-500, $gray-500);
+
+ strong {
+ color: var(--gl-text-color, $gl-text-color);
+ }
+ }
+
+ .light {
+ font-weight: $gl-font-weight-normal;
+ color: var(--gray-500, $gray-500);
+ }
+
+ .git-clone-holder {
+ .input-group-prepend,
+ .input-group-append {
+ background-color: transparent;
+ }
+ }
+
+ button.sidebar-toggle {
+ position: absolute;
+ right: 0;
+ top: 11px;
+ display: block;
+ }
+
+ &.has-sidebar-toggle .git-access-header {
+ padding-right: $sidebar-toggle-width;
+ }
+
+ @include media-breakpoint-up(md) {
+ &.has-sidebar-toggle {
+ padding-right: 0;
+ }
+
+ button.sidebar-toggle {
+ display: none;
+ }
+ }
+}
+
+.wiki-git-access {
+ margin: $gl-padding 0;
+
+ h3 {
+ font-size: 19px;
+ font-weight: $gl-font-weight-normal;
+ margin: $gl-padding 0;
+ }
+}
+
+.right-sidebar.wiki-sidebar {
+ padding: 0;
+
+ &.right-sidebar-collapsed {
+ display: none;
+ }
+
+ .sidebar-container {
+ padding: $gl-padding 0;
+ padding-right: 100px;
+ height: 100%;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ -webkit-overflow-scrolling: touch;
+ }
+
+ .blocks-container {
+ padding: 0 $gl-padding;
+ }
+
+ a {
+ color: var(--gray-400, $gray-400);
+
+ &:hover,
+ &.active {
+ text-decoration: none;
+
+ span {
+ text-decoration: underline;
+ }
+ }
+ }
+
+ .active > a {
+ color: var(--black, $black);
+ }
+
+ ul.wiki-pages,
+ ul.wiki-pages li {
+ list-style: none;
+ padding: 0;
+ margin: 0;
+ }
+
+ ul.wiki-pages li {
+ margin: 5px 0 10px;
+ }
+
+ ul.wiki-pages ul {
+ padding-left: 15px;
+ }
+
+ .wiki-sidebar-header {
+ padding: 0 $gl-padding $gl-padding;
+
+ .gutter-toggle {
+ margin-top: 0;
+ }
+ }
+}
+
+ul.wiki-pages-list.content-list {
+ a {
+ color: var(--blue-600, $blue-600);
+ }
+
+ ul {
+ list-style: none;
+ margin-left: 0;
+ padding-left: 15px;
+
+ li {
+ padding: 5px 0;
+ }
+ }
+}
+
+.empty-state-wiki .text-content {
+ max-width: 490px; // Widen to allow for the Confluence button
+}
+
+.wiki-form .markdown-area {
+ max-height: none;
+}
diff --git a/app/assets/stylesheets/pages/alert_management/details.scss b/app/assets/stylesheets/pages/alert_management/details.scss
index a104c06c853..514f228e223 100644
--- a/app/assets/stylesheets/pages/alert_management/details.scss
+++ b/app/assets/stylesheets/pages/alert_management/details.scss
@@ -33,7 +33,7 @@
}
.main-notes-list::before {
- left: 15px !important;
+ left: $gl-spacing-scale-5 !important;
}
.note-header-info {
diff --git a/app/assets/stylesheets/pages/boards.scss b/app/assets/stylesheets/pages/boards.scss
deleted file mode 100644
index c4852974a4d..00000000000
--- a/app/assets/stylesheets/pages/boards.scss
+++ /dev/null
@@ -1,613 +0,0 @@
-.user-can-drag {
- cursor: grab;
-}
-
-.is-ghost {
- opacity: 0.3;
- pointer-events: none;
-}
-
-.dropdown-projects {
- .dropdown-content {
- max-height: 200px;
- }
-}
-
-.dropdown-menu-issues-board-new {
- width: 320px;
-
- .dropdown-content {
- max-height: 140px;
- }
-}
-
-.issue-board-dropdown-content {
- margin: 0;
- padding: $gl-padding-4 $gl-padding $gl-padding;
- border-bottom: 0;
- color: $gl-text-color-secondary;
-}
-
-.issue-boards-page {
- .content-wrapper {
- padding-bottom: 0;
- }
-}
-
-.boards-app {
- @include media-breakpoint-up(sm) {
- transition: width $sidebar-transition-duration;
- width: 100%;
-
- &.is-compact {
- width: calc(100% - #{$gutter-width});
- }
- }
-}
-
-.boards-list,
-.board-swimlanes {
- height: calc(100vh - #{$issue-board-list-difference-xs});
- overflow-x: scroll;
- min-height: 200px;
-
- @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 {
- // the next line cannot be replaced with .d-inline-block because it breaks display: none of SortableJS
- // see https://gitlab.com/gitlab-org/gitlab-foss/issues/64828
- display: inline-block;
- width: calc(85vw - 15px);
-
- @include media-breakpoint-up(sm) {
- width: 400px;
- }
-
- .board-title-caret {
- border-radius: $border-radius-default;
- line-height: $gl-spacing-scale-5;
- height: $gl-spacing-scale-5;
-
- &.btn svg {
- top: 0;
- }
-
- &:hover {
- background-color: $gray-50;
- transition: background-color 0.1s linear;
- }
- }
-
- &:not(.is-collapsed) {
- .board-title-caret {
- margin-right: $gl-padding-4;
- }
- }
-
- &.is-collapsed {
- width: 50px;
-
- .board-title {
- flex-direction: column;
- }
-
- .board-title-caret {
- margin-top: 1px;
- }
-
- .user-avatar-link,
- .milestone-icon {
- margin-top: $gl-padding-8;
- transform: rotate(90deg);
- }
-
- .board-title-text {
- flex-grow: 0;
- margin: $gl-padding-8 0;
-
- .board-title-main-text {
- display: block;
- }
-
- .board-title-sub-text {
- display: none;
- }
- }
-
- .issue-count-badge {
- border: 0;
- white-space: nowrap;
- padding: 0;
- }
-
- .board-title-text > span,
- .issue-count-badge > span {
- height: 16px;
-
- // Force the height to be equal to the parent's width while centering the contents.
- // The contents *should* be about 16 px.
- // We do this because the flow of elements isn't affected by the rotate transform, so we must ensure that a
- // rotated element has square dimensions so it won't overlap with its siblings.
- margin: calc(50% - 8px) 0;
-
- transform: rotate(90deg);
- transform-origin: center;
- }
- }
-}
-
-.board-inner {
- font-size: $issue-boards-font-size;
- background: $gray-light;
- border: 1px solid $gray-100;
-}
-
-.board-header {
- &.has-border::before {
- border-top: 3px solid;
- border-color: inherit;
- border-top-left-radius: $border-radius-default;
- border-top-right-radius: $border-radius-default;
- content: '';
- position: absolute;
- width: calc(100% + 2px);
- top: 0;
- left: 0;
- margin-top: -1px;
- margin-right: -1px;
- margin-left: -1px;
- padding-top: 1px;
- padding-right: 1px;
- padding-left: 1px;
-
- .board-title {
- padding-top: ($gl-padding - 3px);
- padding-bottom: $gl-padding;
- }
- }
-}
-
-.board-title {
- align-items: center;
- font-size: 1em;
- border-bottom: 1px solid $gray-100;
- padding: 0 $gl-spacing-scale-3;
- height: 3rem;
-
- .js-max-issue-size::before {
- content: '/';
- }
-}
-
-.board-title-text {
- flex-grow: 1;
-}
-
-.board-delete.gl-button {
- background-color: transparent;
- outline: 0;
-
- &:hover {
- color: $blue-600;
- box-shadow: none;
- }
-}
-
-.board-blank-state,
-.board-promotion-state {
- background-color: $white;
- flex: 1;
- overflow-y: auto;
- overflow-x: hidden;
-}
-
-.board-blank-state-list {
- > li:not(:last-child) {
- margin-bottom: 8px;
- }
-
- .label-color {
- top: 2px;
- width: 16px;
- height: 16px;
- margin-right: 3px;
- }
-}
-
-.board-list-component {
- min-height: 0; // firefox fix
-}
-
-.board-list {
- overflow-y: auto;
- overflow-x: hidden;
-}
-
-.board-list-loading {
- margin-top: 10px;
- font-size: (26px / $issue-boards-font-size) * 1em;
-}
-
-.board-card {
- background: $white;
- border: 1px solid $gray-100;
- box-shadow: 0 1px 2px $issue-boards-card-shadow;
- line-height: $gl-padding;
- list-style: none;
- position: relative;
-
- &:not(:last-child) {
- margin-bottom: $gl-padding-8;
- }
-
- &.is-active,
- &.is-active .board-card-assignee:hover a {
- background-color: $blue-50;
- }
-
- &.multi-select {
- border-color: $blue-200;
- background-color: $blue-50;
- }
-
- .gl-label {
- margin-top: 4px;
- margin-right: 4px;
- }
-
- .confidential-icon {
- color: $orange-500;
- cursor: help;
- }
-
- .issue-blocked-icon {
- color: $red-500;
- }
-
- @include media-breakpoint-down(md) {
- padding: $gl-padding-8;
- }
-}
-
-.board-card-title {
- @include overflow-break-word();
- font-size: 1em;
-
- a {
- color: $gl-text-color;
- }
-
- @include media-breakpoint-down(md) {
- font-size: $label-font-size;
- }
-}
-
-.board-card-header {
- text-align: initial;
-}
-
-.board-card-assignee {
- margin-top: -$gl-padding-4;
- margin-bottom: -$gl-padding-4;
-
- .avatar-counter {
- vertical-align: middle;
- line-height: $gl-padding-24;
- min-width: $gl-padding-24;
- height: $gl-padding-24;
- border-radius: $gl-padding-24;
- background-color: $gl-text-color-tertiary;
- font-size: $gl-font-size-xs;
- cursor: help;
- font-weight: $gl-font-weight-bold;
- margin-left: -$gl-padding-4;
- border: 0;
- padding: 0 $gl-padding-4;
-
- @include media-breakpoint-down(md) {
- min-width: auto;
- height: $gl-padding;
- border-radius: $gl-padding;
- line-height: $gl-padding;
- }
- }
-
- img {
- vertical-align: top;
- }
-
- .user-avatar-link:not(:only-child) {
- margin-left: -$gl-padding-4;
-
- &:nth-of-type(1) {
- z-index: 2;
- }
-
- &:nth-of-type(2) {
- z-index: 1;
- }
- }
-
- .avatar {
- margin: 0;
-
- @include media-breakpoint-down(md) {
- width: $gl-padding;
- height: $gl-padding;
- }
- }
-
- @include media-breakpoint-down(md) {
- margin-top: 0;
- margin-bottom: 0;
- }
-}
-
-.board-card-number {
- font-size: $gl-font-size-xs;
- color: $gl-text-color-secondary;
-
- @include media-breakpoint-up(md) {
- font-size: $label-font-size;
- }
-}
-
-.board-list-count {
- padding: 10px 0;
- color: $gl-text-color-secondary;
- font-size: 13px;
-}
-
-.board-new-issue-form {
- z-index: 4;
- margin: 5px;
-}
-
-.right-sidebar.issue-boards-sidebar {
- .gutter-toggle {
- bottom: 15px;
- width: 22px;
- padding-left: $gl-padding-32;
-
- svg {
- position: absolute;
- top: 50%;
- right: 0;
- margin-top: (-11px / 2);
- height: $gl-font-size-12;
- width: $gl-font-size-12;
- }
- }
-
- .issuable-header-text {
- @include overflow-break-word();
- padding-right: 35px;
- }
-}
-
-.right-sidebar.right-sidebar-expanded {
- &.boards-sidebar-slide-enter-active,
- &.boards-sidebar-slide-leave-active {
- transition: width $sidebar-transition-duration, padding $sidebar-transition-duration;
- }
-
- &.boards-sidebar-slide-enter,
- &.boards-sidebar-slide-leave-active {
- width: 0;
- padding-left: 0;
- padding-right: 0;
- }
-}
-
-.add-issues-modal {
- background-color: rgba($black, 0.3);
- z-index: 9999;
-}
-
-.add-issues-container {
- width: 90vw;
- height: 85vh;
- max-width: 1100px;
- min-height: 500px;
- padding: 25px 15px 0;
- background-color: $white;
- box-shadow: 0 2px 12px rgba($black, 0.5);
-
- .empty-state {
- &.add-issues-empty-state-filter {
- flex-direction: column;
- justify-content: center;
- }
-
- .svg-content {
- margin-top: -40px;
- }
- }
-}
-
-.add-issues-header {
- margin: -25px -15px -5px;
- border-bottom: 1px solid $border-color;
- border-top-right-radius: $border-radius-default;
- border-top-left-radius: $border-radius-default;
-
- > h2 {
- font-size: 18px;
- }
-}
-
-.add-issues-list-column {
- width: 100%;
-
- @include media-breakpoint-up(sm) {
- width: 50%;
- }
-
- @include media-breakpoint-up(md) {
- width: (100% / 3);
- }
-}
-
-.add-issues-list {
- padding-top: 3px;
- margin-left: -$gl-vert-padding;
- margin-right: -$gl-vert-padding;
- overflow-y: scroll;
-
- .board-card-parent {
- padding: 0 5px 5px;
- }
-
- .board-card {
- border: 1px solid $border-white-normal;
- box-shadow: 0 1px 2px rgba($issue-boards-card-shadow, 0.3);
- cursor: pointer;
- }
-}
-
-.add-issues-footer {
- margin: auto -15px 0;
- padding-left: 15px;
- padding-right: 15px;
- border-bottom-right-radius: $border-radius-default;
- border-bottom-left-radius: $border-radius-default;
-}
-
-.add-issues-footer-to-list {
- padding-left: $gl-vert-padding;
- padding-right: $gl-vert-padding;
- line-height: $input-height;
-}
-
-.issue-card-selected {
- position: absolute;
- right: -3px;
- top: -3px;
- width: 17px;
- background-color: $blue-500;
- color: $white;
- border: 1px solid $blue-600;
- font-size: 9px;
- line-height: 15px;
- border-radius: 50%;
-}
-
-.board-card-info {
- color: $gl-text-color-secondary;
- white-space: nowrap;
- margin-right: $gl-padding-8;
-
- &:not(.board-card-weight) {
- cursor: help;
- }
-
- &.board-card-weight {
- color: $gl-text-color-secondary;
- cursor: pointer;
-
- &:hover {
- color: initial;
- text-decoration: underline;
- }
- }
-
- .board-card-info-icon {
- color: $gray-500;
- margin-right: $gl-padding-4;
- vertical-align: text-top;
- }
-
- @include media-breakpoint-down(md) {
- font-size: $label-font-size;
- }
-}
-
-.board-issue-path.js-show-tooltip {
- cursor: help;
-}
-
-.board-labels-toggle-wrapper,
-.board-swimlanes-toggle-wrapper {
- /**
- * Make the wrapper the same height as a button so it aligns properly when the
- * filtered-search-box input element increases in size on Linux smaller breakpoints
- */
- height: $input-height;
-}
-
-.issue-boards-content.is-focused {
- position: fixed;
- width: 100%;
- height: 100%;
- top: 0;
- left: 0;
- background: $white;
- z-index: 9000;
-
- @include media-breakpoint-down(sm) {
- padding-top: 10px;
- }
-
- .boards-list {
- height: calc(100vh - #{$issue-boards-filter-height});
- overflow-x: scroll;
- }
-
- .issue-boards-sidebar {
- height: 100%;
- top: 0;
- }
-}
-
-.board-swimlanes {
- overflow-x: auto;
-}
-
-.board-header-collapsed-info-icon:hover {
- color: $gray-900;
-}
-
-$epic-icons-spacing: 40px;
-
-.board-epic-lane {
- max-width: calc(100vw - #{$contextual-sidebar-width} - #{$epic-icons-spacing});
-
- .page-with-icon-sidebar & {
- max-width: calc(100vw - #{$contextual-sidebar-collapsed-width} - #{$epic-icons-spacing});
- }
-
- .page-with-icon-sidebar .is-compact & {
- max-width: calc(100vw - #{$contextual-sidebar-collapsed-width} - #{$gutter-width} - #{$epic-icons-spacing});
- }
-
- .is-compact & {
- max-width: calc(100vw - #{$contextual-sidebar-width} - #{$gutter-width} - #{$epic-icons-spacing});
- }
-}
diff --git a/app/assets/stylesheets/pages/builds.scss b/app/assets/stylesheets/pages/builds.scss
index 04167cbee1b..d7b4db3840e 100644
--- a/app/assets/stylesheets/pages/builds.scss
+++ b/app/assets/stylesheets/pages/builds.scss
@@ -123,20 +123,13 @@
}
.build-header {
- .ci-header-container,
- .header-action-buttons {
- display: flex;
- }
-
- .ci-header-container {
- min-height: 54px;
- }
-
.page-content-header {
padding: 10px 0 9px;
}
.header-action-buttons {
+ display: flex;
+
@include media-breakpoint-down(xs) {
.sidebar-toggle-btn {
margin-top: 0;
diff --git a/app/assets/stylesheets/pages/commits.scss b/app/assets/stylesheets/pages/commits.scss
index e6378fd9168..c55bfeb7b15 100644
--- a/app/assets/stylesheets/pages/commits.scss
+++ b/app/assets/stylesheets/pages/commits.scss
@@ -306,7 +306,6 @@
.commit,
.generic-commit-status,
.branch-commit {
- .autodevops-link,
.commit-sha {
color: $blue-600;
}
diff --git a/app/assets/stylesheets/pages/cycle_analytics.scss b/app/assets/stylesheets/pages/cycle_analytics.scss
deleted file mode 100644
index c509bf121bc..00000000000
--- a/app/assets/stylesheets/pages/cycle_analytics.scss
+++ /dev/null
@@ -1,353 +0,0 @@
-#cycle-analytics,
-.cycle-analytics {
- margin: 24px auto 0;
- position: relative;
-
- .landing {
- margin-top: 0;
-
- .inner-content {
- white-space: normal;
-
- h4,
- p {
- margin: 7px 0 0;
- max-width: 480px;
- padding: 0 $gl-padding;
-
- @include media-breakpoint-down(sm) {
- margin: 0 auto;
- }
- }
- }
-
- .svg-container svg {
- width: 136px;
- height: 136px;
- }
- }
-
- .col-headers {
- ul {
- @include clearfix;
- margin: 0;
- padding: 0;
- }
-
- li {
- display: inline-block;
- float: left;
- line-height: 50px;
- width: 20%;
- }
-
- .stage-header {
- width: 20.5%;
- }
-
- .median-header {
- width: 19.5%;
- }
-
- .event-header {
- width: 45%;
- }
-
- .total-time-header {
- width: 15%;
- }
- }
-
- .card {
- .content-block {
- padding: 24px 0;
- border-bottom: 0;
- position: relative;
-
- @include media-breakpoint-down(xs) {
- padding: 6px 0 24px;
- }
- }
-
- .column {
- text-align: center;
-
- @include media-breakpoint-down(xs) {
- padding: 15px 0;
- }
-
- .header {
- font-size: 30px;
- line-height: 38px;
- font-weight: $gl-font-weight-normal;
- margin: 0;
- }
-
- .text {
- color: $layout-link-gray;
- margin: 0;
- }
-
- &:last-child {
- @include media-breakpoint-down(xs) {
- text-align: center;
- }
- }
- }
- }
-
- .stage-panel-body {
- display: flex;
- flex-wrap: wrap;
- }
-
- .stage-nav,
- .stage-entries {
- display: flex;
- vertical-align: top;
- font-size: $gl-font-size;
- }
-
- .stage-nav {
- width: 40%;
- margin-bottom: 0;
-
- ul {
- padding: 0;
- margin: 0;
- width: 100%;
- }
-
- li {
- @include clearfix;
- list-style-type: none;
- }
-
- .stage-nav-item {
- line-height: 65px;
-
- &.active {
- background: $blue-50;
- border-color: $blue-300;
- box-shadow: inset 4px 0 0 0 $blue-500;
- }
-
- &:hover:not(.active) {
- background-color: $gray-lightest;
- box-shadow: inset 2px 0 0 0 $border-color;
- cursor: pointer;
- }
-
- .stage-nav-item-cell.stage-name {
- width: 44.5%;
- }
-
- .stage-nav-item-cell.stage-median {
- min-width: 43%;
- }
-
- .stage-empty,
- .not-available {
- color: $gl-text-color-secondary;
- }
- }
- }
-
- .stage-panel-container {
- width: 100%;
- overflow: auto;
- }
-
- .stage-panel {
- min-width: 968px;
-
- .card-header {
- padding: 0;
- background-color: transparent;
- }
-
- .events-description {
- line-height: 65px;
- padding: 0 $gl-padding;
- }
-
- .events-info {
- color: $gl-text-color-secondary;
- }
- }
-
- .stage-events {
- width: 60%;
- min-height: 467px;
- }
-
- .stage-event-list {
- margin: 0;
- padding: 0;
- }
-
- .stage-event-item {
- @include clearfix;
- list-style-type: none;
- padding: 0 0 $gl-padding;
- margin: 0 $gl-padding $gl-padding;
- border-bottom: 1px solid $gray-darker;
-
- &:last-child {
- border-bottom: 0;
- margin-bottom: 0;
- }
-
- .item-details,
- .item-time {
- float: left;
- }
-
- .item-details {
- width: 75%;
- }
-
- .item-title {
- margin: 0 0 2px;
-
- &.issue-title,
- &.commit-title,
- &.merge-request-title {
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- max-width: 100%;
- display: block;
-
- a {
- color: $gl-text-color;
- }
- }
- }
-
- .item-time {
- width: 25%;
- text-align: right;
- }
-
- .total-time {
- font-size: $cycle-analytics-big-font;
- color: $gl-text-color;
-
- span {
- color: $gl-text-color;
- font-size: $gl-font-size;
- }
- }
-
- .issue-date,
- .build-date {
- color: $gl-text-color;
- }
-
- .mr-link,
- .issue-link,
- .commit-author-link,
- .issue-author-link {
- color: $gl-text-color;
- }
-
- // Custom CSS for components
- .item-conmmit-component {
- .commit-icon {
- svg {
- display: inline-block;
- width: 20px;
- height: 20px;
- vertical-align: bottom;
- }
- }
- }
-
- .merge-request-branch {
- a {
- max-width: 180px;
- overflow: hidden;
- white-space: nowrap;
- text-overflow: ellipsis;
- display: inline-block;
- vertical-align: bottom;
- }
- }
- }
-
- // Custom Styles for stage items
- .item-build-component {
- .item-title {
- .icon-build-status {
- float: left;
- margin-right: 5px;
- position: relative;
- top: 2px;
- }
-
- .item-build-name {
- color: $gl-text-color;
- }
-
- .pipeline-id {
- color: $gl-text-color;
- padding: 0 3px 0 0;
- }
-
- .ref-name {
- color: $black;
- display: inline-block;
- max-width: 180px;
- text-overflow: ellipsis;
- overflow: hidden;
- white-space: nowrap;
- line-height: 1.3;
- vertical-align: top;
- }
-
- .commit-sha {
- color: $blue-600;
- line-height: 1.3;
- vertical-align: top;
- font-weight: $gl-font-weight-normal;
- }
-
- .fa {
- color: $gl-text-color-secondary;
- font-size: $code-font-size;
- }
- }
- }
-
- .empty-stage,
- .no-access-stage {
- text-align: center;
- width: 75%;
- margin: 0 auto;
- padding-top: 130px;
- color: $gl-text-color-secondary;
-
- h4 {
- color: $gl-text-color;
- }
- }
-
- .empty-stage {
- .icon-no-data {
- height: 36px;
- width: 78px;
- display: inline-block;
- margin-bottom: 20px;
- }
- }
-
- .no-access-stage {
- .icon-lock {
- height: 36px;
- width: 78px;
- display: inline-block;
- margin-bottom: 20px;
- }
- }
-}
diff --git a/app/assets/stylesheets/pages/dev_ops_report.scss b/app/assets/stylesheets/pages/dev_ops_report.scss
deleted file mode 100644
index 871cd9c4f02..00000000000
--- a/app/assets/stylesheets/pages/dev_ops_report.scss
+++ /dev/null
@@ -1,259 +0,0 @@
-$space-between-cards: 8px;
-
-.devops-empty svg {
- margin: 64px auto 32px;
- max-width: 420px;
-}
-
-.devops-header {
- margin-top: $gl-padding;
- margin-bottom: $gl-padding;
- padding: 0 4px;
- display: flex;
- align-items: center;
-
- .devops-header-title {
- font-size: 48px;
- line-height: 1;
- margin: 0;
- }
-
- .devops-header-subtitle {
- font-size: 22px;
- line-height: 1;
- color: $gl-text-color-secondary;
- margin-left: 8px;
- font-weight: $gl-font-weight-normal;
-
- .devops-header-icon {
- vertical-align: px-to-rem(-$gl-spacing-scale-1);
- }
-
- a {
- font-size: 18px;
- color: $gl-text-color-secondary;
-
- &:hover {
- color: $blue-500;
- }
- }
- }
-}
-
-.devops-cards {
- display: flex;
- justify-content: center;
- flex-wrap: wrap;
-}
-
-.devops-card-wrapper {
- display: flex;
- flex-direction: column;
- align-items: stretch;
- text-align: center;
- width: 50%;
- border-color: $border-color;
- margin: 0 0 32px;
- padding: $space-between-cards / 2;
- position: relative;
-
- @include media-breakpoint-up(xs) {
- width: percentage(1 / 4);
- }
-
- @include media-breakpoint-up(sm) {
- width: percentage(1 / 5);
- }
-
- @include media-breakpoint-up(md) {
- width: percentage(1 / 6);
- }
-
- @include media-breakpoint-up(lg) {
- width: percentage(1 / 10);
- }
-}
-
-.devops-card {
- border: solid 1px $border-color;
- border-radius: 3px;
- border-top-width: 3px;
- display: flex;
- flex-direction: column;
- flex-grow: 1;
-}
-
-.devops-card-low {
- border-top-color: $red-400;
-
- .board-card-score-big {
- background-color: $red-50;
- }
-}
-
-.devops-card-average {
- border-top-color: $orange-200;
-
- .board-card-score-big {
- background-color: $orange-50;
- }
-}
-
-.devops-card-high {
- border-top-color: $green-400;
-
- .board-card-score-big {
- background-color: $green-50;
- }
-}
-
-.devops-card-title {
- margin: $gl-padding auto auto;
- max-width: 100px;
-
- h3 {
- font-size: 14px;
- margin: 0 0 2px;
- }
-
- .light-text {
- font-size: 13px;
- line-height: 1.25;
- color: $gl-text-color-secondary;
- }
-}
-
-.board-card-scores {
- display: flex;
- justify-content: space-around;
- align-items: center;
- margin: $gl-padding $gl-btn-padding;
- line-height: 1;
-}
-
-.board-card-score {
- color: $gl-text-color-secondary;
-
- .board-card-score-name {
- font-size: 13px;
- margin-top: 4px;
- }
-}
-
-.board-card-score-value {
- font-size: 16px;
- color: $gl-text-color;
- font-weight: $gl-font-weight-normal;
-}
-
-.board-card-score-big {
- border-top: 2px solid $border-color;
- border-bottom: 1px solid $border-color;
- font-size: 22px;
- padding: 10px 0;
- font-weight: $gl-font-weight-normal;
-}
-
-.board-card-buttons {
- display: flex;
-
- > * {
- font-size: 16px;
- color: $gl-text-color-secondary;
- padding: 10px;
- flex-grow: 1;
-
- &:hover {
- background-color: $border-color;
- color: $gl-text-color;
- }
-
- + * {
- border-left: solid 1px $border-color;
- }
- }
-}
-
-.devops-steps {
- margin-top: $gl-padding;
- height: 1px;
- min-width: 100%;
- justify-content: space-around;
- position: relative;
- background: $border-color;
-}
-
-.devops-step {
- $step-positions: 5% 10% 30% 42% 48% 55% 60% 70% 75% 90%;
- @each $pos in $step-positions {
- $i: index($step-positions, $pos);
-
- &:nth-child(#{$i}) {
- left: $pos;
- }
- }
-
- position: absolute;
- transform-origin: 75% 50%;
- padding: 8px;
- height: 50px;
- width: 50px;
- border-radius: 3px;
- display: flex;
- flex-direction: column;
- align-items: center;
- border: solid 1px $border-color;
- background: $white;
- transform: translate(-50%, -50%);
- color: $gl-text-color-secondary;
- fill: $gl-text-color-secondary;
- box-shadow: 0 2px 4px $dropdown-shadow-color;
-
- &:hover {
- padding: 8px 10px;
- fill: currentColor;
- z-index: 100;
- height: auto;
- width: auto;
-
- .devops-step-title {
- max-height: 2em;
- opacity: 1;
- transition: opacity 0.2s;
- }
-
- svg {
- transform: scale(1.5);
- margin: $gl-btn-padding;
- }
- }
-
- svg {
- transition: transform 0.1s;
- width: 30px;
- height: 30px;
- min-height: 30px;
- min-width: 30px;
- }
-}
-
-.devops-step-title {
- max-height: 0;
- opacity: 0;
- text-transform: uppercase;
- margin: $gl-vert-padding 0 0;
- text-align: center;
- font-size: 12px;
-}
-
-.devops-high-score {
- color: $green-400;
-}
-
-.devops-average-score {
- color: $orange-500;
-}
-
-.devops-low-score {
- color: $red-400;
-}
diff --git a/app/assets/stylesheets/pages/diff.scss b/app/assets/stylesheets/pages/diff.scss
deleted file mode 100644
index 62af7103b39..00000000000
--- a/app/assets/stylesheets/pages/diff.scss
+++ /dev/null
@@ -1,1193 +0,0 @@
-// Common
-.diff-file {
- margin-bottom: $gl-padding;
-
- &.conflict {
- border-top: 1px solid $border-color;
- }
-
- .file-title,
- .file-title-flex-parent {
- border-top-left-radius: $border-radius-default;
- border-top-right-radius: $border-radius-default;
- box-shadow: 0 -2px 0 0 var(--white);
- cursor: pointer;
-
- @media (min-width: map-get($grid-breakpoints, md)) {
- // The `+11` is to ensure the file header border shows when scrolled -
- // the bottom of the compare-versions header and the top of the file header
- $mr-file-header-top: $mr-version-controls-height + $header-height + $mr-tabs-height + 11;
-
- position: -webkit-sticky;
- position: sticky;
- top: $mr-file-header-top;
- z-index: 120;
-
- &::before {
- content: '';
- position: absolute;
- top: -1px;
- left: -11px;
- width: 10px;
- height: calc(100% + 1px);
- background: $white;
- pointer-events: none;
- }
-
- .with-performance-bar & {
- top: $mr-file-header-top + $performance-bar-height;
- }
-
- &.is-commit {
- top: $header-height + $commit-stat-summary-height;
-
- .with-performance-bar & {
- top: $header-height + $commit-stat-summary-height + $performance-bar-height;
- }
- }
-
- &.is-compare {
- top: $header-height + $compare-branches-sticky-header-height;
-
- .with-performance-bar & {
- top: $performance-bar-height + $header-height + $compare-branches-sticky-header-height;
- }
- }
- }
-
- a:hover {
- text-decoration: none;
- }
-
- &:hover {
- background-color: $gray-normal;
- }
-
- svg {
- vertical-align: middle;
- top: -1px;
- }
- }
-
- @media (min-width: map-get($grid-breakpoints, md)) {
- &.conflict .file-title,
- &.conflict .file-title-flex-parent {
- top: $header-height;
- }
-
- .with-performance-bar &.conflict .file-title,
- .with-performance-bar &.conflict .file-title-flex-parent {
- top: $header-height + $performance-bar-height;
- }
-
- .with-system-header &.conflict .file-title,
- .with-system-header &.conflict .file-title-flex-parent {
- top: $header-height + $system-header-height;
- }
-
- .with-system-header.with-performance-bar &.conflict .file-title,
- .with-system-header.with-performance-bar &.conflict .file-title-flex-parent {
- top: $header-height + $performance-bar-height + $system-header-height;
- }
- }
-
- .diff-content {
- background: $white;
- color: $gl-text-color;
- border-radius: 0 0 3px 3px;
-
- .unfold {
- cursor: pointer;
- }
-
- .file-mode-changed {
- padding: 10px;
- color: $gray-500;
- }
-
- .suppressed-container {
- padding: ($padding-base-vertical + 5px) $padding-base-horizontal;
- text-align: center;
-
- // "Changes suppressed. Click to show." link
- .show-suppressed-diff {
- font-size: 110%;
- font-weight: $gl-font-weight-bold;
- }
- }
-
- .diff-loading-error-block {
- padding: $gl-padding * 2 $gl-padding;
- text-align: center;
- }
- }
-
- .image {
- background: $gray-darker;
- text-align: center;
- padding: 30px;
-
- .wrap {
- display: inline-block;
- }
-
- .frame {
- display: inline-block;
- background-color: $white;
- line-height: 0;
-
- img {
- border: 1px solid $white;
- background-image: linear-gradient(45deg,
- $border-color 25%,
- transparent 25%,
- transparent 75%,
- $border-color 75%,
- $border-color 100%),
- linear-gradient(45deg,
- $border-color 25%,
- transparent 25%,
- transparent 75%,
- $border-color 75%,
- $border-color 100%);
- background-size: 10px 10px;
- background-position: 0 0, 5px 5px;
- max-width: 100%;
- }
-
- &.deleted {
- border: 1px solid $deleted;
- }
-
- &.added {
- border: 1px solid $added;
- }
- }
-
- .image-info {
- font-size: 12px;
- margin: 5px 0 0;
- color: $diff-image-info-color;
- }
-
- .view.swipe {
- position: relative;
-
- .swipe-frame {
- display: block;
- margin: auto;
- position: relative;
- }
-
- .swipe-wrap {
- overflow: hidden;
- border-right: 1px solid $gray-300;
- position: absolute;
- display: block;
- top: 13px;
- right: 7px;
-
- &.left-oriented {
- /* only for commit view (different swipe viewer) */
- border-right: 0;
- border-left: 1px solid $gray-300;
- }
- }
-
- .frame {
- top: 0;
- right: 0;
-
- &.old-diff {
- /* only for commit / compare view */
- position: absolute;
- }
-
- &.deleted {
- margin: 0;
- display: block;
- top: 13px;
- right: 7px;
- }
- }
-
- .swipe-bar {
- display: block;
- height: 100%;
- width: 15px;
- z-index: 100;
- position: absolute;
- cursor: pointer;
-
- &:hover {
- .top-handle {
- background-position: -15px 3px;
- }
-
- .bottom-handle {
- background-position: -15px -11px;
- }
- }
-
- .top-handle {
- display: block;
- height: 14px;
- width: 15px;
- position: absolute;
- top: 0;
- background: image-url('swipemode_sprites.gif') 0 3px no-repeat;
- }
-
- .bottom-handle {
- display: block;
- height: 14px;
- width: 15px;
- position: absolute;
- bottom: 0;
- background: image-url('swipemode_sprites.gif') 0 -11px no-repeat;
- }
- }
- }
- //.view.swipe
- .view.onion-skin {
- .onion-skin-frame {
- display: block;
- margin: auto;
- position: relative;
- }
-
- .frame.added,
- .frame.deleted {
- position: absolute;
- display: block;
- top: 0;
- left: 0;
- }
-
- .controls {
- display: block;
- height: 14px;
- width: 300px;
- z-index: 100;
- position: absolute;
- bottom: 0;
- left: 50%;
- margin-left: -150px;
-
- .drag-track {
- display: block;
- position: absolute;
- top: 0;
- left: 12px;
- height: 10px;
- width: 276px;
- background: image-url('onion_skin_sprites.gif') -4px -20px repeat-x;
- }
-
- .dragger {
- display: block;
- position: absolute;
- left: 0;
- top: 0;
- height: 14px;
- width: 14px;
- background: image-url('onion_skin_sprites.gif') 0 -34px repeat-x;
- cursor: pointer;
- }
-
- .transparent {
- display: block;
- position: absolute;
- top: 2px;
- right: 0;
- height: 10px;
- width: 10px;
- background: image-url('onion_skin_sprites.gif') -2px 0 no-repeat;
- }
-
- .opaque {
- display: block;
- position: absolute;
- top: 2px;
- left: 0;
- height: 10px;
- width: 10px;
- background: image-url('onion_skin_sprites.gif') -2px -10px no-repeat;
- }
- }
- }
- //.view.onion-skin
- }
-
- .view-modes {
- padding: 10px;
- text-align: center;
- background: $gray-darker;
-
- ul,
- li {
- list-style: none;
- margin: 0;
- padding: 0;
- display: inline-block;
- }
-
- li {
- color: $diff-view-modes-color;
- border-left: 1px solid $diff-view-modes-border;
- padding: 0 12px 0 16px;
- cursor: pointer;
-
- &:first-child {
- border-left: 0;
- }
-
- &:hover {
- text-decoration: underline;
- }
-
- &.active {
- cursor: default;
- color: $gl-text-color;
-
- &:hover {
- text-decoration: none;
- }
- }
-
- &.disabled {
- display: none;
- }
- }
- }
-
- .diff-file-container {
- .frame.deleted {
- border: 1px solid $deleted;
- background-color: inherit;
- }
-
- .frame.added {
- border: 1px solid $added;
- background-color: inherit;
- }
-
- .swipe.view,
- .onion-skin.view {
- .swipe-wrap {
- top: 0;
- left: 0;
- }
-
- .frame.deleted {
- top: 0;
- right: 0;
- }
-
- .swipe-bar {
- top: 0;
-
- .top-handle {
- top: -14px;
- left: -7px;
- }
-
- .bottom-handle {
- bottom: -14px;
- left: -7px;
- }
- }
-
- .file-container {
- display: inline-block;
-
- .file-content {
- padding: 0;
-
- img {
- max-width: none;
- }
- }
- }
- }
-
- .onion-skin.view .controls {
- bottom: -25px;
- }
- }
-
- .discussion-notes .discussion-notes {
- margin-left: 0;
- border-left: 0;
- }
-}
-
-table.code {
- width: 100%;
- font-family: $monospace-font;
- border: 0;
- border-collapse: separate;
- margin: 0;
- padding: 0;
- table-layout: fixed;
- border-radius: 0 0 $border-radius-default $border-radius-default;
-
- tr:first-of-type.line_expansion > td {
- border-top: 0;
- }
-
- tr:nth-last-of-type(2).line_expansion > td {
- border-bottom: 0;
- }
-
- tr.line_holder td {
- line-height: $code-line-height;
- font-size: $code-font-size;
- vertical-align: top;
-
- span {
- white-space: break-spaces;
-
- &.context-cell {
- display: inline-block;
- width: 100%;
- height: 100%;
- }
-
- &.line {
- word-wrap: break-word;
- }
- }
-
- &.diff-line-num {
- user-select: none;
- margin: 0;
- padding: 0 10px 0 5px;
- border-right-width: 1px;
- border-right-style: solid;
- text-align: right;
- width: 50px;
- position: relative;
- white-space: nowrap;
-
- a {
- transition: none;
- float: left;
- width: 100%;
- font-weight: $gl-font-weight-normal;
-
- &[disabled] {
- cursor: default;
-
- &:hover,
- &:active {
- text-decoration: none;
- }
- }
- }
-
- &:not(.js-unfold-bottom) a::before {
- content: attr(data-linenumber);
- }
- }
-
- &.line_content {
- display: block;
- margin: 0;
- padding: 0 1.5em;
- border: 0;
- position: relative;
- white-space: pre-wrap;
-
- &.parallel {
- display: table-cell;
- width: 46%;
-
- span {
- word-break: break-all;
- }
- }
-
- &.old {
- &::before {
- content: '-';
- position: absolute;
- left: 0.5em;
- }
-
- &.with-coverage::before {
- left: 0;
- }
- }
-
- &.new {
- &::before {
- content: '+';
- position: absolute;
- left: 0.5em;
- }
-
- &.with-coverage::before {
- left: 0;
- }
- }
- }
- }
-
- .line_holder:last-of-type {
- td:first-child {
- border-bottom-left-radius: $border-radius-default;
- }
- }
-
- &.left-side-selected {
- td.line_content.parallel.right-side {
- user-select: none;
- }
- }
-
- &.right-side-selected {
- td.line_content.parallel.left-side {
- user-select: none;
- }
- }
-}
-
-.diff-stats {
- align-items: center;
- padding: 0 1rem;
-
- .diff-stats-group {
- padding: 0 0.25rem;
- }
-
- svg.diff-stats-icon {
- vertical-align: text-bottom;
- }
-
- &.is-compare-versions-header {
- .diff-stats-group {
- padding: 0 0.25rem;
- }
- }
-}
-
-.file-content .diff-file {
- margin: 0;
- border: 0;
-}
-
-.diff-wrap-lines .line_content {
- white-space: pre-wrap;
-}
-
-.inline-parallel-buttons {
- float: right;
-}
-
-.files-changed {
- border-bottom: 0;
-}
-
-.merge-request-details .file-content.image_file img {
- max-height: 50vh;
-}
-
-.diff-stats-summary-toggler {
- padding: 0;
- background-color: transparent;
- border: 0;
- color: $blue-600;
- font-weight: $gl-font-weight-bold;
-
- &:hover,
- &:focus {
- outline: none;
- color: $blue-800;
- }
-
- .caret-icon {
- position: relative;
- top: 2px;
- left: -1px;
- }
-}
-
-// Mobile
-@media (max-width: 480px) {
- .diff-title {
- margin: 0;
-
- .file-mode {
- display: none;
- }
- }
-
- .diff-controls {
- position: static;
- text-align: center;
- }
-}
-
-// Bigger screens
-@media (min-width: 481px) {
- .diff-title {
- margin-right: 200px;
-
- .file-mode {
- margin-left: 10px;
- }
- }
-
- .diff-controls {
- float: right;
- position: absolute;
- top: 5px;
- right: 15px;
- }
-}
-
-.files {
- .diff-file:last-child {
- margin-bottom: 0;
- }
-}
-
-.diff-comment-avatar-holders {
- position: absolute;
- margin-left: -$gl-padding;
- z-index: 100;
- @include code-icon-size();
-
- &:hover {
- .diff-comment-avatar,
- .diff-comments-more-count {
- @for $i from 1 through 4 {
- $x-pos: 14px;
-
- &:nth-child(#{$i}) {
- @if $i == 4 {
- $x-pos: 14.5px;
- }
-
- transform: translateX((($i * $x-pos) - $x-pos));
-
- &:hover {
- transform: translateX((($i * $x-pos) - $x-pos));
- }
- }
- }
- }
-
- .diff-comments-more-count {
- padding-left: 2px;
- padding-right: 2px;
- width: auto;
- }
- }
-}
-
-.diff-comment-avatar,
-.diff-comments-more-count {
- position: absolute;
- left: 0;
- margin-right: 0;
- border-color: $white;
- cursor: pointer;
- transition: all 0.1s ease-out;
- @include code-icon-size();
-
- @for $i from 1 through 4 {
- &:nth-child(#{$i}) {
- z-index: (4 - $i);
- }
- }
-
- .avatar {
- @include code-icon-size();
- }
-}
-
-.diff-comments-more-count {
- padding-left: 0;
- padding-right: 0;
- overflow: hidden;
- @include code-icon-size();
-}
-
-.diff-comments-more-count,
-.diff-notes-collapse {
- @include avatar-counter(50%);
-}
-
-.diff-notes-collapse {
- border: 0;
- border-radius: 50%;
- padding: 0;
- transition: transform 0.1s ease-out;
- z-index: 100;
- display: flex;
- justify-content: center;
- align-items: center;
- @include code-icon-size();
-
- .collapse-icon {
- height: 50%;
- width: 100%;
- }
-
- svg {
- vertical-align: middle;
- }
-
- .collapse-icon,
- path {
- fill: $white;
- }
-
- &:focus {
- outline: 0;
- }
-}
-
-.diff-files-changed {
- .inline-parallel-buttons {
- position: relative;
- z-index: 1;
- }
-
- .commit-stat-summary {
- @include media-breakpoint-up(sm) {
- margin-left: -$gl-padding;
- padding-left: $gl-padding;
- background-color: $white;
- }
- }
-
- @include media-breakpoint-up(sm) {
- position: -webkit-sticky;
- position: sticky;
- top: $header-height;
- background-color: $white;
- z-index: 200;
-
- .with-performance-bar & {
- top: $header-height + $performance-bar-height;
- }
-
- &.is-stuck {
- padding-top: 0;
- padding-bottom: 0;
- border-top: 1px solid $white-dark;
- border-bottom: 1px solid $white-dark;
-
- .diff-stats-additions-deletions-expanded,
- .inline-parallel-buttons {
- display: none !important;
- }
- }
- }
-
- @include media-breakpoint-up(lg) {
- &.is-stuck {
- .diff-stats-additions-deletions-collapsed {
- display: block !important;
- }
- }
- }
-}
-
-.diff-file-changes {
- max-width: 560px;
- width: 100%;
- z-index: 150;
- min-height: $dropdown-min-height;
- max-height: $dropdown-max-height;
- overflow-y: auto;
- margin-bottom: 0;
-
- @include media-breakpoint-up(sm) {
- left: $gl-padding;
- }
-
- .dropdown-input .dropdown-input-search {
- pointer-events: all;
- }
-
- .diff-changed-file {
- display: flex;
- padding-top: 8px;
- padding-bottom: 8px;
- min-width: 0;
- }
-
- .diff-file-changed-icon {
- margin-top: 2px;
- }
-
- .diff-changed-file-content {
- display: flex;
- flex-direction: column;
- min-width: 0;
- }
-
- .diff-changed-file-name,
- .diff-changed-blank-file-name {
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- }
-
- .diff-changed-blank-file-name {
- color: $gl-text-color-tertiary;
- font-style: italic;
- }
-
- .diff-changed-file-path {
- color: $gl-text-color-tertiary;
- }
-
- .diff-changed-stats {
- margin-left: auto;
- white-space: nowrap;
- }
-}
-
-.diff-file-changes-path {
- flex: 1;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-
-.note-container {
- background-color: $gray-light;
- border-top: 1px solid $white-normal;
-
- // double jagged line divider
- .discussion-notes + .discussion-notes::before,
- .diff-file-discussions + .discussion-form::before {
- content: '';
- position: relative;
- display: block;
- width: 100%;
- height: 10px;
- background-color: $white;
- background-image: linear-gradient(45deg,
- transparent,
- transparent 73%,
- $diff-jagged-border-gradient-color 75%,
- $white 80%),
- linear-gradient(225deg,
- transparent,
- transparent 73%,
- $diff-jagged-border-gradient-color 75%,
- $white 80%),
- linear-gradient(135deg,
- transparent,
- transparent 73%,
- $diff-jagged-border-gradient-color 75%,
- $white 80%),
- linear-gradient(-45deg,
- transparent,
- transparent 73%,
- $diff-jagged-border-gradient-color 75%,
- $white 80%);
- background-position: 5px 5px, 0 5px, 0 5px, 5px 5px;
- background-size: 10px 10px;
- background-repeat: repeat;
- }
-
- .diff-file-discussions + .discussion-form {
- padding: $gl-padding;
-
- &::before {
- width: auto;
- margin-left: -$gl-padding;
- margin-right: -$gl-padding;
- margin-bottom: $gl-padding;
- }
- }
-
- .notes {
- position: relative;
- }
-
- .diff-notes-collapse {
- position: absolute;
- left: -12px;
- }
-}
-
-.diff-file .note-container > .new-note,
-.note-container .discussion-notes.diff-discussions {
- margin-left: 100px;
- border-left: 1px solid $white-normal;
-}
-
-.notes.active {
- .diff-file .note-container > .new-note,
- .note-container .discussion-notes {
- // Override our margin and border (set for diff tab)
- // when user is on the discussion tab for MR
- margin-left: inherit;
- border-left: inherit;
- }
-}
-
-.files:not([data-can-create-note]) .frame {
- cursor: auto;
-}
-
-.frame.click-to-comment,
-.btn-transparent.image-diff-overlay-add-comment {
- position: relative;
- cursor: image-url('illustrations/image_comment_light_cursor.svg')
- $image-comment-cursor-left-offset $image-comment-cursor-top-offset,
- auto;
-
- // Retina cursor
- // scss-lint:disable DuplicateProperty
- cursor: image-set(image-url('illustrations/image_comment_light_cursor.svg') 1x,
- image-url('illustrations/image_comment_light_cursor@2x.svg') 2x)
- $image-comment-cursor-left-offset $image-comment-cursor-top-offset,
- auto;
-
- .comment-indicator {
- position: absolute;
- padding: 0;
- width: (2px * $image-comment-cursor-left-offset);
- height: (2px * $image-comment-cursor-top-offset);
- color: $blue-400;
- // center the indicator to match the top left click region
- margin-top: (-1px * $image-comment-cursor-top-offset) + 2;
- margin-left: (-1px * $image-comment-cursor-left-offset) + 1;
-
- svg {
- width: 100%;
- height: 100%;
- }
-
- &:focus {
- outline: none;
- }
- }
-}
-
-.frame .badge.badge-pill,
-.image-diff-avatar-link .badge.badge-pill,
-.user-avatar-link .badge.badge-pill,
-.notes > .badge.badge-pill {
- position: absolute;
- background-color: $blue-400;
- color: $white;
- border: $white 1px solid;
- min-height: $gl-padding;
- padding: 5px 8px;
- border-radius: 12px;
-
- &:focus {
- outline: none;
- }
-}
-
-.frame .badge.badge-pill,
-.frame .image-comment-badge,
-.frame .comment-indicator {
- // Center align badges on the frame
- transform: translate(-50%, -50%);
-}
-
-.image-comment-badge {
- position: absolute;
- width: 24px;
- height: 24px;
- padding: 0;
- background: none;
- border: 0;
-
- > svg {
- width: 100%;
- height: 100%;
- }
-}
-
-.image-diff-avatar-link,
-.user-avatar-link {
- position: relative;
-
- .badge.badge-pill,
- .image-comment-badge {
- top: 25px;
- right: 8px;
- }
-}
-
-.notes > .badge.badge-pill {
- display: none;
- left: -13px;
-}
-
-.discussion-notes {
- min-height: 35px;
-
- &:first-child {
- // First child does not have the jagged borders
- min-height: 25px;
- }
-
- &.collapsed {
- background-color: $white;
-
- .diff-notes-collapse,
- .note,
- .discussion-reply-holder {
- display: none;
- }
-
- .notes > .badge.badge-pill {
- display: block;
- }
- }
-
- .note-edit-form {
- margin-left: $note-icon-gutter-width;
- }
-}
-
-.discussion-body .image .frame {
- position: relative;
-}
-
-.diff-tree-list {
- position: -webkit-sticky;
- position: sticky;
- $top-pos: $header-height + $mr-tabs-height + $mr-version-controls-height + 15px;
- top: $top-pos;
- max-height: calc(100vh - #{$top-pos});
- z-index: 202;
-
- .with-performance-bar & {
- $performance-bar-top-pos: $performance-bar-height + $top-pos;
- top: $performance-bar-top-pos;
- max-height: calc(100vh - #{$performance-bar-top-pos});
- }
-
- .drag-handle {
- bottom: 16px;
- transform: translateX(10px);
- }
-}
-
-.diff-files-holder {
- flex: 1;
- min-width: 0;
- z-index: 201;
-}
-
-.compare-versions-container {
- min-width: 0;
-}
-
-.tree-list-holder {
- height: 100%;
-
- .file-row {
- margin-left: 0;
- margin-right: 0;
- }
-}
-
-.tree-list-scroll {
- max-height: 100%;
- padding-bottom: $grid-size;
- overflow-y: scroll;
- overflow-x: auto;
-}
-
-.tree-list-search {
- flex: 0 0 34px;
-
- .form-control {
- padding-left: 30px;
- }
-}
-
-.tree-list-icon {
- top: 50%;
- left: 10px;
- transform: translateY(-50%);
-
- &,
- svg {
- fill: $gl-text-color-tertiary;
- }
-}
-
-.tree-list-clear-icon {
- right: 10px;
- left: auto;
- line-height: 0;
-}
-
-.discussion-collapsible {
- margin: 0 $gl-padding $gl-padding 71px;
-
- .notes {
- border-radius: $border-radius-default;
- }
-}
-
-.parallel {
- .discussion-collapsible {
- margin: $gl-padding;
- margin-top: 0;
- }
-}
-
-@media (max-width: map-get($grid-breakpoints, md)-1) {
- .diffs .files {
- @include fixed-width-container;
- flex-direction: column;
-
- .diff-tree-list {
- position: relative;
- top: 0;
- // !important is required to override inline styles of resizable sidebar
- width: 100% !important;
- }
-
- .tree-list-holder {
- max-height: calc(50px + 50vh);
- padding-right: 0;
- }
- }
-
- .discussion-collapsible {
- margin: $gl-padding;
- margin-top: 0;
- }
-}
-
-.image-diff-overlay,
-.image-diff-overlay-add-comment {
- top: 0;
- left: 0;
-
- &:active,
- &:focus {
- outline: 0;
- }
-}
-
-.diff-suggest-popover {
- &.popover {
- width: 250px;
- min-width: 250px;
- z-index: 210;
- }
-
- .popover-header {
- display: none;
- }
-}
diff --git a/app/assets/stylesheets/pages/environments.scss b/app/assets/stylesheets/pages/environments.scss
deleted file mode 100644
index 5ce500dad1d..00000000000
--- a/app/assets/stylesheets/pages/environments.scss
+++ /dev/null
@@ -1,140 +0,0 @@
-@include media-breakpoint-down(md) {
- .deployments-container {
- width: 100%;
- overflow: auto;
- }
-}
-
-.environments-folder-name {
- font-weight: $gl-font-weight-normal;
-}
-
-.environments-container {
- .ci-table {
- .commit-title {
- margin: 0;
- }
-
- .external-url,
- .dropdown-new {
- color: $gl-text-color-secondary;
- }
-
- .build-link,
- .ref-name {
- color: $gl-text-color;
- }
-
- .folder-icon {
- margin-right: 3px;
- color: $gl-text-color-secondary;
- display: inline-block;
- vertical-align: text-top;
- }
-
- .folder-name {
- cursor: pointer;
- color: $gl-text-color-secondary;
- display: inline-block;
- }
-
- .icon-container {
- width: 20px;
- text-align: center;
- }
-
- .no-btn {
- border: 0;
- background: none;
- outline: none;
- width: 100%;
- text-align: left;
- }
-
- .environment-child-row {
- padding-left: 20px;
- }
- }
-}
-
-.gl-responsive-table-row {
- .branch-commit {
- max-width: 100%;
- }
-}
-
-.folder-row {
- border-left: 0;
- border-right: 0;
-
- @media (min-width: map-get($grid-breakpoints, md)-1) {
- border-top: 0;
- }
-}
-
-.x-axis path,
-.y-axis path,
-.label-x-axis-line,
-.label-y-axis-line {
- fill: none;
- stroke-width: 1;
- shape-rendering: crispEdges;
-}
-
-.x-axis path,
-.y-axis path {
- stroke: $gray-300;
-}
-
-.label-x-axis-line,
-.label-y-axis-line {
- stroke: $border-color;
-}
-
-.y-axis {
- line {
- stroke: $gray-300;
- stroke-width: 1;
- }
-}
-
-.metric-area {
- opacity: 0.25;
-}
-
-.rect-text-metric {
- fill: $white;
- stroke-width: 1;
- stroke: $gray-darkest;
-}
-
-.rect-axis-text {
- fill: $white;
-}
-
-.text-metric {
- font-size: 12px;
-}
-
-.selected-metric-line {
- stroke: $gray-900;
- stroke-width: 1;
-}
-
-.deployment-line {
- stroke: $black;
- stroke-width: 1;
-}
-
-.divider-line {
- stroke-width: 1;
- stroke: $gray-darkest;
-}
-
-.environments-actions {
- .external-url,
- .monitoring-url,
- .terminal-button {
- width: 38px;
- }
-}
diff --git a/app/assets/stylesheets/pages/error_details.scss b/app/assets/stylesheets/pages/error_details.scss
deleted file mode 100644
index 78cac12d6be..00000000000
--- a/app/assets/stylesheets/pages/error_details.scss
+++ /dev/null
@@ -1,49 +0,0 @@
-.error-details {
- li {
- @include gl-line-height-32;
- }
-
- .btn-outline-info {
- color: $blue-500;
- border-color: $blue-500;
- }
-
- .error-details-header {
- border-bottom: 1px solid $border-color;
-
- @include media-breakpoint-down(xs) {
- flex-flow: column;
-
- .error-details-meta-culprit {
- display: flex;
- }
-
- .error-details-options {
- width: 100%;
-
- .dropdown-toggle {
- text-align: center;
- }
- }
- }
- }
-}
-
-.stacktrace {
- .file-title {
- svg {
- vertical-align: middle;
- top: -1px;
- }
- }
-
- .file-title-name {
- &.limited-width {
- max-width: 80%;
- }
- }
-
- .line_content.old::before {
- content: none !important;
- }
-}
diff --git a/app/assets/stylesheets/pages/error_list.scss b/app/assets/stylesheets/pages/error_list.scss
deleted file mode 100644
index 3ec3e4f6b43..00000000000
--- a/app/assets/stylesheets/pages/error_list.scss
+++ /dev/null
@@ -1,34 +0,0 @@
-.error-list {
- .sort-control {
- .btn {
- padding-right: 2rem;
- }
-
- .gl-dropdown-caret {
- position: absolute;
- right: 0.5rem;
- top: 0.5rem;
- }
- }
-
- @include media-breakpoint-down(sm) {
- .error-list-table {
- .table-col {
- min-height: 68px;
-
- &:last-child {
- background-color: $gray-10;
-
- &::before {
- content: none !important;
- }
-
- div {
- width: 100% !important;
- padding: 0 !important;
- }
- }
- }
- }
- }
-}
diff --git a/app/assets/stylesheets/pages/error_tracking_list.scss b/app/assets/stylesheets/pages/error_tracking_list.scss
deleted file mode 100644
index cc391ca6c97..00000000000
--- a/app/assets/stylesheets/pages/error_tracking_list.scss
+++ /dev/null
@@ -1,5 +0,0 @@
-.error-list {
- .dropdown {
- min-width: auto;
- }
-}
diff --git a/app/assets/stylesheets/pages/experience_level.scss b/app/assets/stylesheets/pages/experience_level.scss
deleted file mode 100644
index e57ad6321a5..00000000000
--- a/app/assets/stylesheets/pages/experience_level.scss
+++ /dev/null
@@ -1,29 +0,0 @@
-.signup-page[data-page^='registrations:experience_levels'] {
- $card-shadow-color: rgba($black, 0.2);
-
- .page-wrap {
- background-color: $white;
- }
-
- .card-deck {
- max-width: 828px;
- }
-
- .card {
- transition: box-shadow 0.3s ease-in-out;
- }
-
- .card:hover {
- box-shadow: 0 $gl-spacing-scale-3 $gl-spacing-scale-5 $card-shadow-color;
- }
-
- @media (min-width: $breakpoint-sm) {
- .card-deck .card {
- margin: 0 $gl-spacing-scale-3;
- }
- }
-
- .stretched-link:hover {
- text-decoration: none;
- }
-}
diff --git a/app/assets/stylesheets/pages/experimental_separate_sign_up.scss b/app/assets/stylesheets/pages/experimental_separate_sign_up.scss
deleted file mode 100644
index dfc56654229..00000000000
--- a/app/assets/stylesheets/pages/experimental_separate_sign_up.scss
+++ /dev/null
@@ -1,60 +0,0 @@
-.signup-page {
- .page-wrap {
- background-color: $gray-light;
- }
-
- .signup-box-container {
- max-width: 960px;
- }
-
- .signup-box {
- background-color: $white;
- box-shadow: 0 0 0 1px $border-color;
- border-radius: $border-radius;
- }
-
- .form-control {
- &:active,
- &:focus {
- background-color: $white;
- }
- }
-
- .devise-errors {
- h2 {
- font-size: $gl-font-size;
- color: $red-700;
- }
- }
-
- .omniauth-divider {
- &::before,
- &::after {
- content: '';
- flex: 1;
- border-bottom: 1px solid $gray-dark;
- margin: $gl-padding-24 0;
- }
-
- &::before {
- margin-right: $gl-padding;
- }
-
- &::after {
- margin-left: $gl-padding;
- }
- }
-
- .omniauth-btn {
- width: 48%;
-
- @include media-breakpoint-down(md) {
- width: 100%;
- }
-
- img {
- width: $default-icon-size;
- height: $default-icon-size;
- }
- }
-}
diff --git a/app/assets/stylesheets/pages/graph.scss b/app/assets/stylesheets/pages/graph.scss
deleted file mode 100644
index bca4d50973a..00000000000
--- a/app/assets/stylesheets/pages/graph.scss
+++ /dev/null
@@ -1,74 +0,0 @@
-.project-network {
- border: 1px solid $border-color;
-
- .controls {
- color: $project-network-controls-color;
- font-size: 14px;
- padding: 5px;
- border-bottom: 1px solid $border-color;
- background: $gray-darker;
- }
-
- .network-graph {
- background: $white;
- height: 500px;
- overflow-y: scroll;
- overflow-x: hidden;
- }
-}
-
-.svg-graph-container {
- width: 100%;
-
- .axis-tick {
- opacity: 0.4;
- }
-
- .tick-text {
- fill: $gl-text-color-secondary;
- }
-
- .x-axis-text {
- fill: $gray-900;
- }
-
- .bar-rect {
- fill: rgba($blue-500, 0.1);
- stroke: $blue-500;
- }
-
- .bar-rect:hover {
- fill: rgba($blue-700, 0.3);
- }
-
- .y-axis-label {
- line {
- stroke: $gray-300;
- }
-
- text {
- font-weight: bold;
- font-size: 12px;
- fill: $gray-700;
- }
- }
-}
-
-.svg-graph-container-with-grab {
- cursor: grab;
-}
-
-.svg-graph-container-grabbed {
- cursor: grabbing;
-}
-
-@keyframes flickerAnimation {
- 0% { opacity: 1; }
- 50% { opacity: 0; }
- 100% { opacity: 1; }
-}
-
-.animate-flicker {
- animation: flickerAnimation 1.5s infinite;
- fill: $gray-300;
-}
diff --git a/app/assets/stylesheets/pages/groups.scss b/app/assets/stylesheets/pages/groups.scss
index 69fd094f83b..ee4f74882a1 100644
--- a/app/assets/stylesheets/pages/groups.scss
+++ b/app/assets/stylesheets/pages/groups.scss
@@ -95,6 +95,78 @@
}
}
+.group-home-panel {
+ margin-top: $gl-padding;
+ margin-bottom: $gl-padding;
+
+ .home-panel-avatar {
+ width: $home-panel-title-row-height;
+ height: $home-panel-title-row-height;
+ flex-shrink: 0;
+ flex-basis: $home-panel-title-row-height;
+ }
+
+ .home-panel-title {
+ font-size: 20px;
+ line-height: $gl-line-height-24;
+ font-weight: bold;
+
+ .icon {
+ vertical-align: -1px;
+ }
+
+ .home-panel-topic-list {
+ font-size: $gl-font-size;
+ font-weight: $gl-font-weight-normal;
+
+ .icon {
+ position: relative;
+ top: 3px;
+ margin-right: $gl-padding-4;
+ }
+ }
+ }
+
+ .home-panel-title-row {
+ @include media-breakpoint-down(sm) {
+ .home-panel-avatar {
+ width: $home-panel-avatar-mobile-size;
+ height: $home-panel-avatar-mobile-size;
+ flex-basis: $home-panel-avatar-mobile-size;
+
+ .avatar {
+ font-size: 20px;
+ line-height: 46px;
+ }
+ }
+
+ .home-panel-title {
+ margin-top: 4px;
+ margin-bottom: 2px;
+ font-size: $gl-font-size;
+ line-height: $gl-font-size-large;
+ }
+
+ .home-panel-topic-list,
+ .home-panel-metadata {
+ font-size: $gl-font-size-small;
+ }
+ }
+ }
+
+ .home-panel-metadata {
+ font-weight: normal;
+ font-size: 14px;
+ line-height: $gl-btn-line-height;
+ }
+
+ .home-panel-description {
+ @include media-breakpoint-up(md) {
+ font-size: $gl-font-size-large;
+ }
+ }
+}
+
.home-panel-buttons {
.home-panel-action-button {
vertical-align: top;
diff --git a/app/assets/stylesheets/pages/incident_management_list.scss b/app/assets/stylesheets/pages/incident_management_list.scss
index 316066694a8..c0a1fa72b1f 100644
--- a/app/assets/stylesheets/pages/incident_management_list.scss
+++ b/app/assets/stylesheets/pages/incident_management_list.scss
@@ -7,6 +7,19 @@
table {
@include gl-text-gray-500;
+ tbody {
+ tr:not(.b-table-busy-slot) {
+ // TODO replace with gitlab/ui utilities: https://gitlab.com/gitlab-org/gitlab-ui/-/merge_requests/1791
+ &:hover {
+ border-top-style: double;
+
+ td {
+ border-bottom-style: initial;
+ }
+ }
+ }
+ }
+
tr {
&:focus {
outline: none;
@@ -119,7 +132,7 @@
}
@include media-breakpoint-down(xs) {
- .incident-management-list-header {
+ .list-header {
flex-direction: column-reverse;
}
@@ -127,9 +140,4 @@
@include gl-w-full;
}
}
-
- // TODO: Abstract to `@gitlab/ui` utility set: https://gitlab.com/gitlab-org/gitlab-ui/-/issues/921
- .gl-fill-green-500 {
- fill: $green-500;
- }
}
diff --git a/app/assets/stylesheets/pages/issuable.scss b/app/assets/stylesheets/pages/issuable.scss
index 53525a4d877..7097c2b10c4 100644
--- a/app/assets/stylesheets/pages/issuable.scss
+++ b/app/assets/stylesheets/pages/issuable.scss
@@ -117,7 +117,8 @@
}
}
-.assignee {
+.assignee,
+.reviewer {
.merge-icon {
color: $orange-400;
position: absolute;
@@ -240,16 +241,6 @@
.avatar {
margin-left: 0;
}
-
- a.edit-link:not([href]):hover {
- color: rgba($gray-normal, 0.2);
- }
-
- .confidential-edit,
- .lock-edit,
- .edit-link {
- @extend .btn-link;
- }
}
.cross-project-reference,
diff --git a/app/assets/stylesheets/pages/issues.scss b/app/assets/stylesheets/pages/issues.scss
index 03603f637c8..d2eb00c4a4d 100644
--- a/app/assets/stylesheets/pages/issues.scss
+++ b/app/assets/stylesheets/pages/issues.scss
@@ -1,38 +1,3 @@
-.issues-list {
- &.manual-ordering {
- background-color: $gray-light;
- border-radius: $border-radius-default;
- padding: $gl-padding-8;
-
- .issue {
- background-color: $white;
- margin-bottom: $gl-padding-8;
- border-radius: $border-radius-default;
- border: 1px solid $gray-100;
- box-shadow: 0 1px 2px $issue-boards-card-shadow;
- }
- }
-
- .issue {
- padding: 10px $gl-padding;
- position: relative;
-
- .title {
- margin-bottom: 2px;
- }
-
- .issue-labels,
- .author-link {
- display: inline-block;
- }
-
- .icon-merge-request-unmerged {
- height: 13px;
- margin-bottom: 3px;
- }
- }
-}
-
.issue-realtime-pre-pulse {
opacity: 0;
}
@@ -369,13 +334,3 @@ ul.related-merge-requests > li {
.issuable-header-slide-leave-to {
transform: translateY(-100%);
}
-
-.issuable-list-root {
- .gl-label-link {
- text-decoration: none;
-
- &:hover {
- color: inherit;
- }
- }
-}
diff --git a/app/assets/stylesheets/pages/issues/issues_list.scss b/app/assets/stylesheets/pages/issues/issues_list.scss
deleted file mode 100644
index c0af7a6af6d..00000000000
--- a/app/assets/stylesheets/pages/issues/issues_list.scss
+++ /dev/null
@@ -1,5 +0,0 @@
-.svg-container.jira-logo-container {
- svg {
- vertical-align: text-bottom;
- }
-}
diff --git a/app/assets/stylesheets/pages/labels.scss b/app/assets/stylesheets/pages/labels.scss
index e37b26187e7..31606cb3ba5 100644
--- a/app/assets/stylesheets/pages/labels.scss
+++ b/app/assets/stylesheets/pages/labels.scss
@@ -134,11 +134,6 @@
}
}
-.label-description-wrapper {
- margin-right: 8px;
- margin-left: 8px;
-}
-
.prioritized-labels {
margin-bottom: 30px;
@@ -201,10 +196,6 @@
}
}
-.label-options-toggle {
- width: 100%;
-}
-
.label-subscription {
vertical-align: middle;
@@ -239,20 +230,6 @@
}
}
-.label-link {
- display: inline-flex;
- vertical-align: text-bottom;
-
- &:hover .color-label {
- text-decoration: underline;
- }
-
- .label {
- vertical-align: inherit;
- font-size: $label-font-size;
- }
-}
-
.labels-container {
background-color: $gray-light;
border-radius: $border-radius-default;
@@ -270,41 +247,13 @@
.label-badge {
color: $gray-900;
+ display: inline-block;
font-weight: $gl-font-weight-normal;
padding: $gl-padding-4 $gl-padding-8;
border-radius: $border-radius-default;
font-size: $label-font-size;
}
-.label-badge-blue {
- background-color: $theme-blue-100;
-}
-
-.label-badge-gray {
- background-color: $gray-50;
-}
-
-.label-links {
- list-style: none;
- margin: 0;
- padding: 0;
- white-space: nowrap;
-}
-
-.label-link-item {
- padding: 0;
-}
-
-.label-description {
- .description-text {
- margin-bottom: 10px;
-
- .admin-labels & {
- margin-bottom: 0;
- }
- }
-}
-
.label-list-item {
.content-list &::before,
.content-list &::after {
@@ -313,21 +262,12 @@
.label-name {
width: 200px;
- flex-shrink: 0;
.gl-label {
line-height: $gl-line-height;
}
}
- .label-description {
- flex-grow: 1;
-
- a {
- color: $blue-600;
- }
- }
-
.label {
padding: 4px $grid-size;
font-size: $label-font-size;
@@ -382,31 +322,8 @@
text-align: left;
}
- .label-links {
- white-space: normal;
- }
-
.label-description {
order: 3;
- width: 100%;
-
- > .label-description-wrapper {
- margin-left: 0;
- margin-right: 0;
- }
- }
- }
-}
-
-@media (max-width: 910px) {
- .priority-badge {
- display: block;
- width: 100%;
- margin-left: 0;
- margin-top: $gl-padding;
-
- .label-badge {
- display: inline-block;
}
}
}
@@ -426,3 +343,9 @@
box-shadow: 0 0 0 1px inset;
}
}
+
+/* Fix scoped label padding in cases where old markdown uses the old label structure */
+.gl-label-text + .gl-label-text {
+ @include gl-pl-2;
+ @include gl-pr-3;
+}
diff --git a/app/assets/stylesheets/pages/members.scss b/app/assets/stylesheets/pages/members.scss
index 2d9a9f3029f..922f95ff5df 100644
--- a/app/assets/stylesheets/pages/members.scss
+++ b/app/assets/stylesheets/pages/members.scss
@@ -209,6 +209,27 @@
}
}
+
+.members-table {
+ @include media-breakpoint-up(lg) {
+ .col-meta {
+ width: px-to-rem(150px);
+ }
+
+ .col-max-role {
+ width: px-to-rem(175px);
+ }
+
+ .col-expiration {
+ width: px-to-rem(200px);
+ }
+
+ .col-actions {
+ width: px-to-rem(50px);
+ }
+ }
+}
+
.card-mobile {
.content-list.members-list li {
display: block;
diff --git a/app/assets/stylesheets/pages/merge_conflicts.scss b/app/assets/stylesheets/pages/merge_conflicts.scss
deleted file mode 100644
index 9d583dcaa52..00000000000
--- a/app/assets/stylesheets/pages/merge_conflicts.scss
+++ /dev/null
@@ -1,307 +0,0 @@
-// Disabled to use the color map for creating color schemes
-// scss-lint:disable ColorVariable
-$colors: (
- white-header-head-neutral : #e1fad7,
- white-line-head-neutral : #effdec,
- white-button-head-neutral : #9adb84,
-
- white-header-head-chosen : #baf0a8,
- white-line-head-chosen : #e1fad7,
- white-button-head-chosen : #52c22d,
-
- white-header-origin-neutral : #e0f0ff,
- white-line-origin-neutral : #f2f9ff,
- white-button-origin-neutral : #87c2fa,
-
- white-header-origin-chosen : #add8ff,
- white-line-origin-chosen : #e0f0ff,
- white-button-origin-chosen : #268ced,
-
- white-header-not-chosen : #f0f0f0,
- white-line-not-chosen : $gray-light,
-
- dark-header-head-neutral : rgba(#3f3, 0.2),
- dark-line-head-neutral : rgba(#3f3, 0.1),
- dark-button-head-neutral : #40874f,
-
- dark-header-head-chosen : rgba(#3f3, 0.33),
- dark-line-head-chosen : rgba(#3f3, 0.2),
- dark-button-head-chosen : #258537,
-
- dark-header-origin-neutral : rgba(#2878c9, 0.4),
- dark-line-origin-neutral : rgba(#2878c9, 0.3),
- dark-button-origin-neutral : #2a5c8c,
-
- dark-header-origin-chosen : rgba(#2878c9, 0.6),
- dark-line-origin-chosen : rgba(#2878c9, 0.4),
- dark-button-origin-chosen : #1d6cbf,
-
- dark-header-not-chosen : rgba(#fff, 0.25),
- dark-line-not-chosen : rgba(#fff, 0.1),
-
- monokai-header-head-neutral : rgba(#a6e22e, 0.25),
- monokai-line-head-neutral : rgba(#a6e22e, 0.1),
- monokai-button-head-neutral : #376b20,
-
- monokai-header-head-chosen : rgba(#a6e22e, 0.4),
- monokai-line-head-chosen : rgba(#a6e22e, 0.25),
- monokai-button-head-chosen : #39800d,
-
- monokai-header-origin-neutral : rgba(#60d9f1, 0.35),
- monokai-line-origin-neutral : rgba(#60d9f1, 0.15),
- monokai-button-origin-neutral : #38848c,
-
- monokai-header-origin-chosen : rgba(#60d9f1, 0.5),
- monokai-line-origin-chosen : rgba(#60d9f1, 0.35),
- monokai-button-origin-chosen : #3ea4b2,
-
- monokai-header-not-chosen : rgba(#76715d, 0.24),
- monokai-line-not-chosen : rgba(#76715d, 0.1),
-
- solarized-light-header-head-neutral : rgba(#859900, 0.37),
- solarized-light-line-head-neutral : rgba(#859900, 0.2),
- solarized-light-button-head-neutral : #afb262,
-
- solarized-light-header-head-chosen : rgba(#859900, 0.5),
- solarized-light-line-head-chosen : rgba(#859900, 0.37),
- solarized-light-button-head-chosen : #94993d,
-
- solarized-light-header-origin-neutral : rgba(#2878c9, 0.37),
- solarized-light-line-origin-neutral : rgba(#2878c9, 0.15),
- solarized-light-button-origin-neutral : #60a1bf,
-
- solarized-light-header-origin-chosen : rgba(#2878c9, 0.6),
- solarized-light-line-origin-chosen : rgba(#2878c9, 0.37),
- solarized-light-button-origin-chosen : #2482b2,
-
- solarized-light-header-not-chosen : rgba(#839496, 0.37),
- solarized-light-line-not-chosen : rgba(#839496, 0.2),
-
- solarized-dark-header-head-neutral : rgba(#859900, 0.35),
- solarized-dark-line-head-neutral : rgba(#859900, 0.15),
- solarized-dark-button-head-neutral : #376b20,
-
- solarized-dark-header-head-chosen : rgba(#859900, 0.5),
- solarized-dark-line-head-chosen : rgba(#859900, 0.35),
- solarized-dark-button-head-chosen : #39800d,
-
- solarized-dark-header-origin-neutral : rgba(#2878c9, 0.35),
- solarized-dark-line-origin-neutral : rgba(#2878c9, 0.15),
- solarized-dark-button-origin-neutral : #086799,
-
- solarized-dark-header-origin-chosen : rgba(#2878c9, 0.6),
- solarized-dark-line-origin-chosen : rgba(#2878c9, 0.35),
- solarized-dark-button-origin-chosen : #0082cc,
-
- solarized_dark_header_not_chosen : rgba(#839496, 0.25),
- solarized_dark_line_not_chosen : rgba(#839496, 0.15),
-
- none_header_head_neutral : $gray-normal,
- none_line_head_neutral : $gray-normal,
- none_button_head_neutral : $gray-normal,
-
- none_header_head_chosen : $gray-darker,
- none_line_head_chosen : $gray-darker,
- none_button_head_chosen : $gray-darker,
-
- none_header_origin_neutral : $gray-normal,
- none_line_origin_neutral : $gray-normal,
- none_button_origin_neutral : $gray-normal,
-
- none_header_origin_chosen : $gray-darker,
- none_line_origin_chosen : $gray-darker,
- none_button_origin_chosen : $gray-darker,
-
- none_header_not_chosen : $gray-light,
- none_line_not_chosen : $gray-light
-
-);
-// scss-lint:enable ColorVariable
-
-@mixin color-scheme($color) {
- .header.line_content,
- .diff-line-num {
- &.origin {
- background-color: map-get($colors, #{$color}-header-origin-neutral);
- border-color: map-get($colors, #{$color}-header-origin-neutral);
-
- button {
- background-color: map-get($colors, #{$color}-button-origin-neutral);
- border-color: darken(map-get($colors, #{$color}-button-origin-neutral), 15);
- }
-
- &.selected {
- background-color: map-get($colors, #{$color}-header-origin-chosen);
- border-color: map-get($colors, #{$color}-header-origin-chosen);
-
- button {
- background-color: map-get($colors, #{$color}-button-origin-chosen);
- border-color: darken(map-get($colors, #{$color}-button-origin-chosen), 15);
- }
- }
-
- &.unselected {
- background-color: map-get($colors, #{$color}-header-not-chosen);
- border-color: map-get($colors, #{$color}-header-not-chosen);
-
- button {
- background-color: lighten(map-get($colors, #{$color}-button-origin-neutral), 15);
- border-color: map-get($colors, #{$color}-button-origin-neutral);
- }
- }
- }
-
- &.head {
- background-color: map-get($colors, #{$color}-header-head-neutral);
- border-color: map-get($colors, #{$color}-header-head-neutral);
-
- button {
- background-color: map-get($colors, #{$color}-button-head-neutral);
- border-color: darken(map-get($colors, #{$color}-button-head-neutral), 15);
- }
-
- &.selected {
- background-color: map-get($colors, #{$color}-header-head-chosen);
- border-color: map-get($colors, #{$color}-header-head-chosen);
-
- button {
- background-color: map-get($colors, #{$color}-button-head-chosen);
- border-color: darken(map-get($colors, #{$color}-button-head-chosen), 15);
- }
- }
-
- &.unselected {
- background-color: map-get($colors, #{$color}-header-not-chosen);
- border-color: map-get($colors, #{$color}-header-not-chosen);
-
- button {
- background-color: lighten(map-get($colors, #{$color}-button-head-neutral), 15);
- border-color: map-get($colors, #{$color}-button-head-neutral);
- }
- }
- }
- }
-
- .line_content {
- &.origin {
- background-color: map-get($colors, #{$color}-line-origin-neutral);
-
- &.selected {
- background-color: map-get($colors, #{$color}-line-origin-chosen);
- }
-
- &.unselected {
- background-color: map-get($colors, #{$color}-line-not-chosen);
- }
- }
-
- &.head {
- background-color: map-get($colors, #{$color}-line-head-neutral);
-
- &.selected {
- background-color: map-get($colors, #{$color}-line-head-chosen);
- }
-
- &.unselected {
- background-color: map-get($colors, #{$color}-line-not-chosen);
- }
- }
- }
-}
-
-#conflicts {
- .white {
- @include color-scheme('white'); }
-
- .dark {
- @include color-scheme('dark'); }
-
- .monokai {
- @include color-scheme('monokai'); }
-
- .solarized-light {
- @include color-scheme('solarized-light'); }
-
- .solarized-dark {
- @include color-scheme('solarized-dark'); }
-
- .diff-wrap-lines .line_content {
- white-space: normal;
- min-height: 19px;
- }
-
- .line_content.header {
- position: relative;
-
- button {
- border-radius: 2px;
- font-size: 10px;
- position: absolute;
- right: 10px;
- padding: 0;
- outline: none;
- color: $white;
- width: 75px; // static width to make 2 buttons have same width
- height: 19px;
- }
- }
-
- .btn-success .fa-spinner {
- color: $white;
- }
-
- .editor-wrap {
- &.is-loading {
- .editor {
- display: none;
- }
-
- .loading {
- display: block;
- }
- }
-
- &.saved {
- .editor {
- border-top: solid 2px $green-300;
- }
- }
-
- .editor {
- pre {
- height: 350px;
- border: 0;
- border-radius: 0;
- margin-bottom: 0;
- }
- }
-
- .loading {
- display: none;
- }
- }
-
- .discard-changes-alert {
- background-color: $gray-light;
- text-align: right;
- padding: $gl-padding-top $gl-padding;
- color: $gl-text-color;
-
- .discard-actions {
- display: inline-block;
- margin-left: 10px;
- }
- }
-
- .resolve-conflicts-form {
- h4 {
- margin-top: 0;
- }
-
- .resolve-info {
- @media(max-width: map-get($grid-breakpoints, lg)-1) {
- margin-bottom: $gl-padding;
- }
- }
- }
-}
diff --git a/app/assets/stylesheets/pages/merge_requests.scss b/app/assets/stylesheets/pages/merge_requests.scss
index 8aaeb92eb7a..6f71177e870 100644
--- a/app/assets/stylesheets/pages/merge_requests.scss
+++ b/app/assets/stylesheets/pages/merge_requests.scss
@@ -471,12 +471,6 @@ $mr-widget-min-height: 69px;
flex: 1;
}
- .issuable-meta {
- .author-link {
- display: inline-block;
- }
- }
-
.merge-request-title {
margin-bottom: 2px;
@@ -770,8 +764,14 @@ $mr-widget-min-height: 69px;
position: -webkit-sticky;
position: sticky;
top: $header-height + $mr-tabs-height;
- margin-left: -16px;
- width: calc(100% + 32px);
+
+ .with-system-header & {
+ top: $header-height + $mr-tabs-height + $system-header-height;
+ }
+
+ .with-system-header.with-performance-bar & {
+ top: $header-height + $mr-tabs-height + $system-header-height + $performance-bar-height;
+ }
.mr-version-menus-container {
flex-wrap: nowrap;
@@ -790,6 +790,14 @@ $mr-widget-min-height: 69px;
background-color: $white;
border-bottom: 1px solid $border-color;
+ .with-system-header & {
+ top: $header-height + $system-header-height;
+ }
+
+ .with-system-header.with-performance-bar & {
+ top: $header-height + $system-header-height + $performance-bar-height;
+ }
+
@include media-breakpoint-up(sm) {
position: -webkit-sticky;
position: sticky;
@@ -868,6 +876,13 @@ $mr-widget-min-height: 69px;
}
}
+.container-fluid {
+ // Negative margins for mobile/tablet screen
+ .diffs.tab-pane {
+ margin: 0 (-$gl-padding);
+ }
+}
+
// Wrap MR tabs/buttons so you don't have to scroll on desktop
@include media-breakpoint-down(md) {
.merge-request-tabs-container,
diff --git a/app/assets/stylesheets/pages/milestone.scss b/app/assets/stylesheets/pages/milestone.scss
deleted file mode 100644
index e9eb79b071c..00000000000
--- a/app/assets/stylesheets/pages/milestone.scss
+++ /dev/null
@@ -1,252 +0,0 @@
-$status-box-line-height: 26px;
-
-.issues-sortable-list .str-truncated {
- max-width: 90%;
-}
-
-.milestones {
- padding: $gl-padding-8;
- margin-top: $gl-padding-8;
- border-radius: $border-radius-default;
- background-color: $gray-100;
-
- .milestone {
- border: 0;
- padding: $gl-padding-top $gl-padding;
- border-radius: $border-radius-default;
- background-color: $white;
-
- &:not(:last-child) {
- margin-bottom: $gl-padding-4;
- }
-
- h4 {
- font-weight: $gl-font-weight-bold;
- }
-
- .progress {
- width: 100%;
- height: 6px;
- margin-bottom: $gl-padding-4;
- }
-
- .milestone-progress,
- .milestone-release-links {
- a {
- color: $blue-600;
- }
- }
-
- .status-box {
- font-size: $tooltip-font-size;
- margin-top: 0;
- margin-right: $gl-padding-4;
- line-height: $status-box-line-height;
-
- @include media-breakpoint-down(xs) {
- line-height: unset;
- padding: $gl-padding-4 $gl-input-padding;
- }
- }
- }
-}
-
-.milestone-content {
- .issues-count {
- margin-right: 17px;
- float: right;
- width: 105px;
- }
-
- .issuable-row {
- span {
- a {
- color: $gl-text-color;
- word-wrap: break-word;
- }
-
- .gl-label-link {
- color: inherit;
- }
- }
- }
-
- .card-header {
- line-height: $line-height-base;
- padding: 14px 16px;
- display: flex;
-
- .title {
- flex: 1;
- flex-grow: 2;
- }
-
- .counter {
- flex: 0;
- padding-left: 16px;
- }
- }
-}
-
-.milestone-sidebar {
- .milestone-progress {
- .title {
- padding-top: 5px;
- }
-
- .progress {
- height: 6px;
- margin: 0;
- }
-
- .sidebar-collapsed-icon {
- clear: both;
- padding: 15px 5px 5px;
-
- .progress {
- margin: 5px 0;
- }
- }
- }
-
- .collapsed-milestone-date {
- font-size: 12px;
- }
-
- .milestone-date {
- display: block;
- }
-
- .date-separator {
- line-height: 5px;
- }
-
- .remaining-days strong {
- font-weight: $gl-font-weight-normal;
- }
-
- .milestone-stat {
- float: left;
- margin-right: 14px;
- }
-
- .milestone-stat:last-child {
- margin-right: 0;
- }
-
- .right-sidebar-expanded & {
- .gutter-toggle {
- margin-bottom: $sidebar-milestone-toggle-bottom-margin;
- }
- }
-
- .right-sidebar-collapsed & {
- .milestone-progress {
- padding-top: 0;
- }
-
- .reference {
- border-top: 1px solid $border-gray-normal;
- }
- }
-}
-
-.milestone-issues-list,
-.milestone-merge_requests-list {
- .issuable-detail {
- display: block;
- margin-top: 7px;
-
- .issue-link {
- display: inline-block;
- }
-
- .issuable-number {
- color: $gl-text-color-secondary;
- margin-right: 5px;
- }
-
- .avatar {
- float: none;
- }
-
- > a:not(:last-of-type) {
- margin-right: 5px;
- }
- }
-}
-
-.milestone-detail {
- border-bottom: 1px solid $border-color;
-}
-
-@include media-breakpoint-down(xs) {
- .milestone-actions {
- @include clearfix();
- padding-top: $gl-vert-padding;
-
- .btn:first-child {
- margin-left: 0;
- }
- }
-}
-
-.milestone-page-header {
- display: flex;
- flex-flow: row;
- align-items: center;
- flex-wrap: wrap;
-
- .status-box {
- margin-top: 0;
- order: 1;
- }
-
- .milestone-buttons {
- margin-left: auto;
- order: 2;
-
- .verbose {
- display: none;
- }
- }
-
- .header-text-content {
- order: 3;
- width: 100%;
- }
-
- @include media-breakpoint-up(xs) {
- .milestone-buttons .verbose {
- display: inline;
- }
-
- .header-text-content {
- order: 2;
- width: auto;
- }
-
- .milestone-buttons {
- order: 3;
- }
- }
-}
-
-.issuable-row {
- background-color: $white;
-}
-
-.milestone-popover-instructions-list {
- padding-left: 2em;
-
- > li {
- padding-left: 1em;
- }
-}
-
-@include media-breakpoint-down(xs) {
- .milestone-banner-text,
- .milestone-banner-link {
- display: inline;
- }
-}
diff --git a/app/assets/stylesheets/pages/notes.scss b/app/assets/stylesheets/pages/notes.scss
index c144fb13322..b510822a20a 100644
--- a/app/assets/stylesheets/pages/notes.scss
+++ b/app/assets/stylesheets/pages/notes.scss
@@ -858,68 +858,28 @@ $note-form-margin-left: 72px;
}
.line-resolve-all-container {
- margin: $gl-padding-4;
-
> div {
white-space: nowrap;
}
- .discussion-next-btn {
- border-radius: 0;
- }
-
- .toggle-all-discussions-btn {
+ .btn-group .btn:first-child {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
-
- .btn {
- line-height: $gl-line-height;
-
- svg {
- fill: $gray-500;
- }
-
- &.discussion-create-issue-btn {
- border-radius: 0;
- border-right: 0;
-
- a {
- padding: 0;
- line-height: 0;
-
- &:hover {
- text-decoration: none;
- border: 0;
- }
- }
- }
-
- &.discussion-next-btn {
- border-right: 0;
- }
- }
}
.line-resolve-all {
vertical-align: middle;
display: inline-block;
- padding: $gl-padding-4 10px;
+ padding: $gl-padding-8 $gl-padding-12;
background-color: $gray-light;
border: 1px solid $border-color;
+ border-right: 0;
border-radius: $border-radius-default;
- font-size: $gl-btn-small-font-size;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
- border-right: 0;
-
- .line-resolve-btn {
- color: $gray-500;
-
- svg {
- vertical-align: text-top;
- }
- }
+ font-size: $gl-font-size;
+ line-height: 1rem;
@include media-breakpoint-down(xs) {
flex: 1;
diff --git a/app/assets/stylesheets/pages/pipelines.scss b/app/assets/stylesheets/pages/pipelines.scss
index 8b104ce9017..2df43b861b2 100644
--- a/app/assets/stylesheets/pages/pipelines.scss
+++ b/app/assets/stylesheets/pages/pipelines.scss
@@ -1,119 +1,3 @@
-@mixin flat-connector-before($length: 44px) {
- &::before {
- content: '';
- position: absolute;
- top: 48%;
- left: -$length;
- border-top: 2px solid $border-color;
- width: $length;
- height: 1px;
- }
-}
-
-@mixin build-content($border-radius: 30px) {
- display: inline-block;
- padding: 8px 10px 9px;
- width: 100%;
- border: 1px solid $border-color;
- border-radius: $border-radius;
- background-color: $white;
-
- &:hover {
- background-color: $gray-darker;
- border: 1px solid $dropdown-toggle-active-border-color;
- color: $gl-text-color;
- }
-}
-
-.pipelines {
- .negative-margin-top {
- margin-top: -$pipelines-table-header-height;
- }
-
- .stage {
- max-width: 90px;
- width: 90px;
- text-align: center;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- }
-
- .table-holder {
- overflow: unset;
- width: 100%;
- }
-
- .commit-title {
- margin: 0;
- white-space: normal;
-
- @include media-breakpoint-down(sm) {
- justify-content: flex-end;
- }
- }
-
- .ci-table {
- .badge {
- margin-bottom: 3px;
- }
-
- .pipeline-id {
- color: $black;
- }
-
- .pipelines-time-ago {
- text-align: right;
- }
-
- .pipeline-actions {
- min-width: 170px; //Guarantees buttons don't break in several lines.
-
- .btn-default {
- color: $gl-text-color-secondary;
- }
-
- .btn.btn-retry:hover,
- .btn.btn-retry:focus {
- border-color: $dropdown-toggle-active-border-color;
- background-color: $white-normal;
- }
-
- svg path {
- fill: $gl-text-color-secondary;
- }
-
- .dropdown-menu {
- max-height: $dropdown-max-height;
- overflow-y: auto;
- }
-
- .dropdown-toggle,
- .dropdown-menu {
- color: $gl-text-color-secondary;
-
- .fa {
- color: $gl-text-color-secondary;
- font-size: 14px;
- }
- }
-
- .btn-group.open .btn-default {
- background-color: $white-normal;
- border-color: $border-white-normal;
- }
-
- .btn .text-center {
- display: inline;
- }
-
- .tooltip {
- white-space: nowrap;
- }
- }
- }
-}
-
@include media-breakpoint-down(md) {
.content-list {
&.builds-content-list {
@@ -124,22 +8,6 @@
}
.ci-table {
- .build.retried {
- background-color: $gray-lightest;
- }
-
- .commit-link {
- a {
- &:focus {
- text-decoration: none;
- }
- }
-
- a:hover {
- text-decoration: none;
- }
- }
-
.avatar {
margin-left: 0;
float: none;
@@ -160,7 +28,10 @@
height: 14px;
width: 14px;
vertical-align: middle;
- fill: $gl-text-color-secondary;
+
+ &:not(.text-warning) {
+ fill: $gl-text-color-secondary;
+ }
}
.sprite {
@@ -191,45 +62,12 @@
}
}
- .icon-container {
- display: inline-block;
-
- &.commit-icon {
- width: 15px;
- text-align: center;
- }
- }
-
- /**
- * Play button with icon in dropdowns
- */
- .no-btn {
- border: 0;
- background: none;
- outline: none;
- width: 100%;
- text-align: left;
-
- .icon-play {
- position: relative;
- top: 2px;
- margin-right: 5px;
- height: 13px;
- width: 12px;
- }
- }
-
.duration,
.finished-at {
color: $gl-text-color-secondary;
margin: 0;
white-space: nowrap;
- .fa {
- font-size: 12px;
- margin-right: 4px;
- }
-
svg {
width: 12px;
height: 12px;
@@ -241,843 +79,20 @@
.build-link a {
color: $gl-text-color;
}
-
- .btn-group.open .dropdown-toggle {
- box-shadow: none;
- }
-
- .pipeline-tags .label-container {
- white-space: normal;
- }
}
-.stage-cell {
- .mini-pipeline-graph-dropdown-toggle {
- svg {
- height: $ci-action-icon-size;
- width: $ci-action-icon-size;
- position: absolute;
- top: -1px;
- left: -1px;
- z-index: 2;
- overflow: visible;
- }
-
- &:hover,
- &:active,
- &:focus {
- svg {
- top: -2px;
- left: -2px;
- }
+[data-page='admin:jobs:index'] {
+ .admin-builds-table {
+ td:last-child {
+ min-width: 120px;
}
}
-
- .stage-container {
- display: inline-block;
- position: relative;
- vertical-align: middle;
- height: $ci-action-icon-size;
- margin: 3px 0;
-
- + .stage-container {
- margin-left: 6px;
- }
-
- // Hack to show a button tooltip inline
- button.has-tooltip + .tooltip {
- min-width: 105px;
- }
-
- // Bootstrap way of showing the content inline for anchors.
- a.has-tooltip {
- white-space: nowrap;
- }
-
- &:not(:last-child) {
- &::after {
- content: '';
- width: 7px;
- position: absolute;
- right: -7px;
- top: 11px;
- border-bottom: 2px solid $border-color;
- }
- }
-
- //delete when all pipelines are updated to new size
- &.mr-widget-pipeline-stages {
- + .stage-container {
- margin-left: 4px;
- }
-
- &:not(:last-child) {
- &::after {
- width: 4px;
- right: -4px;
- top: 11px;
- }
- }
- }
- }
-}
-
-.admin-builds-table {
- .ci-table td:last-child {
- min-width: 120px;
- }
-}
-
-// Pipeline visualization
-.pipeline-actions {
- border-bottom: 0;
-}
-
-.tab-pane {
- &.builds .ci-table tr {
- height: 71px;
- }
-
- .ci-table {
- thead th {
- border-top: 0;
- }
- }
-}
-
-.build-failures {
- .build-state {
- padding: 20px 2px;
-
- .build-name {
- font-weight: $gl-font-weight-normal;
- }
-
- .stage {
- color: $gl-text-color-secondary;
- font-weight: $gl-font-weight-normal;
- vertical-align: middle;
- }
- }
-
- .build-log {
- border: 0;
- line-height: initial;
- }
-
- .build-trace-row td {
- border-top: 0;
- border-bottom-width: 1px;
- border-bottom-style: solid;
- padding-top: 0;
- }
-
- .build-trace {
- width: 100%;
- text-align: left;
- margin-top: $gl-padding;
- }
-
- .build-name {
- width: 196px;
-
- a {
- font-weight: $gl-font-weight-bold;
- color: $gl-text-color;
- text-decoration: none;
-
- &:focus,
- &:hover {
- text-decoration: underline;
- }
- }
- }
-
- .build-actions {
- width: 70px;
- text-align: right;
- }
-
- .build-stage {
- width: 140px;
- }
-
- .ci-status-icon-failed {
- padding: 10px 0 10px 12px;
- width: 12px + 24px; // padding-left + svg width
- }
-
- .build-icon svg {
- width: 24px;
- height: 24px;
- vertical-align: middle;
- }
-
- .build-state,
- .build-trace-row {
- > td:last-child {
- padding-right: 0;
- }
- }
-
- @include media-breakpoint-down(sm) {
- td:empty {
- display: none;
- }
-
- .ci-table {
- margin-top: 2 * $gl-padding;
- }
-
- .build-trace-container {
- padding-top: $gl-padding;
- padding-bottom: $gl-padding;
- }
-
- .build-trace {
- margin-bottom: 0;
- margin-top: 0;
- }
- }
-}
-
-.pipeline-tab-content {
- display: flex;
- width: 100%;
- min-height: $dropdown-max-height-lg;
- background-color: $gray-light;
- padding: $gl-padding 0;
- overflow: auto;
-}
-
-// Pipeline graph
-.pipeline-graph {
- white-space: nowrap;
- transition: max-height 0.3s, padding 0.3s;
-
- .stage-column-list,
- .builds-container > ul {
- padding: 0;
- }
-
- a {
- text-decoration: none;
- color: $gl-text-color;
- }
-
- svg {
- vertical-align: middle;
- }
-
- .stage-column {
- display: inline-block;
- vertical-align: top;
-
- &.left-margin {
- &:not(:first-child) {
- margin-left: 44px;
-
- .left-connector {
- @include flat-connector-before;
- }
- }
- }
-
- &.no-margin {
- margin: 0;
- }
-
- li {
- list-style: none;
- }
-
- // when downstream pipelines are present, the last stage isn't the last column
- &:last-child:not(.has-downstream) {
- .build {
- // Remove right connecting horizontal line from first build in last stage
- &:first-child::after {
- border: 0;
- }
- // Remove right curved connectors from all builds in last stage
- &:not(:first-child)::after {
- border: 0;
- }
- // Remove opposite curve
- .curve::before {
- display: none;
- }
- }
- }
-
- // when upstream pipelines are present, the first stage isn't the first column
- &:first-child:not(.has-upstream) {
- .build {
- // Remove left curved connectors from all builds in first stage
- &:not(:first-child)::before {
- border: 0;
- }
- // Remove opposite curve
- .curve::after {
- display: none;
- }
- }
- }
-
- // Curve first child connecting lines in opposite direction
- .curve {
- display: none;
-
- &::before,
- &::after {
- content: '';
- width: 21px;
- height: 25px;
- position: absolute;
- top: -31px;
- border-top: 2px solid $border-color;
- }
-
- &::after {
- left: -44px;
- border-right: 2px solid $border-color;
- border-radius: 0 20px;
- }
-
- &::before {
- right: -44px;
- border-left: 2px solid $border-color;
- border-radius: 20px 0 0;
- }
- }
- }
-
- .stage-name {
- margin: 0 0 15px 10px;
- font-weight: $gl-font-weight-bold;
- width: 176px;
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
- line-height: 2.2em;
- }
-
- .build {
- position: relative;
- width: 186px;
- margin-bottom: 10px;
- white-space: normal;
-
- .ci-job-dropdown-container {
- // override dropdown.scss
- .dropdown-menu li button {
- padding: 0;
- text-align: center;
- }
- }
-
- // ensure .build-content has hover style when action-icon is hovered
- .ci-job-dropdown-container:hover .build-content {
- @extend .build-content:hover;
- }
-
- .ci-status-icon svg {
- height: 24px;
- width: 24px;
- }
-
- .dropdown-menu-toggle {
- background-color: transparent;
- border: 0;
- padding: 0;
-
- &:focus {
- outline: none;
- }
- }
-
- .build-content {
- @include build-content();
- }
-
- a.build-content:hover,
- button.build-content:hover {
- background-color: $gray-darker;
- border: 1px solid $dropdown-toggle-active-border-color;
- }
-
- // Connect first build in each stage with right horizontal line
- &:first-child {
- &::after {
- content: '';
- position: absolute;
- top: 48%;
- right: -48px;
- border-top: 2px solid $border-color;
- width: 48px;
- height: 1px;
- }
- }
-
- // Connect each build (except for first) with curved lines
- &:not(:first-child) {
- &::after,
- &::before {
- content: '';
- top: -49px;
- position: absolute;
- border-bottom: 2px solid $border-color;
- width: 25px;
- height: 69px;
- }
-
- // Right connecting curves
- &::after {
- right: -25px;
- border-right: 2px solid $border-color;
- border-radius: 0 0 20px;
- }
-
- // Left connecting curves
- &::before {
- left: -25px;
- border-left: 2px solid $border-color;
- border-radius: 0 0 0 20px;
- }
- }
-
- // Connect second build to first build with smaller curved line
- &:nth-child(2) {
- &::after,
- &::before {
- height: 29px;
- top: -9px;
- }
-
- .curve {
- display: block;
- }
- }
- }
-
- .ci-action-icon-container {
- position: absolute;
- right: 5px;
- top: 50%;
- transform: translateY(-50%);
-
- // Action Icons in big pipeline-graph nodes
- &.ci-action-icon-wrapper {
- height: 30px;
- width: 30px;
- border-radius: 100%;
- display: block;
- padding: 0;
- line-height: 0;
-
- svg {
- fill: $gl-text-color-secondary;
- }
-
- .spinner {
- top: 2px;
- }
-
- &.play {
- svg {
- left: 1px;
- top: 1px;
- }
- }
- }
- }
-
- .stage-action svg {
- left: 1px;
- top: -2px;
- }
-}
-
-// Triggers the dropdown in the big pipeline graph
-.dropdown-counter-badge {
- font-weight: 100;
- font-size: 15px;
- position: absolute;
- right: 13px;
- top: 8px;
-}
-
-.ci-build-text,
-.ci-status-text {
- font-weight: 200;
-}
-
-@mixin mini-pipeline-graph-color(
- $color-background-default,
- $color-background-hover-focus,
- $color-background-active,
- $color-foreground-default,
- $color-foreground-hover-focus,
- $color-foreground-active
-) {
- background-color: $color-background-default;
- border-color: $color-foreground-default;
-
- svg {
- fill: $color-foreground-default;
- }
-
- &:hover,
- &:focus {
- background-color: $color-background-hover-focus;
- border-color: $color-foreground-hover-focus;
-
- svg {
- fill: $color-foreground-hover-focus;
- }
- }
-
- &:active {
- background-color: $color-background-active;
- border-color: $color-foreground-active;
-
- svg {
- fill: $color-foreground-active;
- }
- }
-
- &:focus {
- box-shadow: 0 0 4px 1px $blue-300;
- }
-}
-
-@mixin mini-pipeline-item() {
- border-radius: 100px;
- background-color: $white;
- border-width: 1px;
- border-style: solid;
- width: $ci-action-icon-size;
- height: $ci-action-icon-size;
- margin: 0;
- padding: 0;
- position: relative;
- vertical-align: middle;
-
- &:hover,
- &:active,
- &:focus {
- outline: none;
- border-width: 2px;
- }
-
- // Dropdown button animation in mini pipeline graph
- &.ci-status-icon-success {
- @include mini-pipeline-graph-color($white, $green-100, $green-200, $green-500, $green-600, $green-700);
- }
-
- &.ci-status-icon-failed {
- @include mini-pipeline-graph-color($white, $red-100, $red-200, $red-500, $red-600, $red-700);
- }
-
- &.ci-status-icon-pending,
- &.ci-status-icon-waiting-for-resource,
- &.ci-status-icon-success-with-warnings {
- @include mini-pipeline-graph-color($white, $orange-50, $orange-100, $orange-500, $orange-600, $orange-700);
- }
-
- &.ci-status-icon-preparing,
- &.ci-status-icon-running {
- @include mini-pipeline-graph-color($white, $blue-100, $blue-200, $blue-500, $blue-600, $blue-700);
- }
-
- &.ci-status-icon-canceled,
- &.ci-status-icon-scheduled,
- &.ci-status-icon-disabled,
- &.ci-status-icon-not-found,
- &.ci-status-icon-manual {
- @include mini-pipeline-graph-color($white, $gray-500, $gray-700, $gray-900, $gray-950, $black);
- }
-
- &.ci-status-icon-created,
- &.ci-status-icon-skipped {
- @include mini-pipeline-graph-color($white, $gray-100, $gray-200, $gray-300, $gray-400, $gray-500);
- }
-}
-
-// Dropdown button in mini pipeline graph
-button.mini-pipeline-graph-dropdown-toggle {
- @include mini-pipeline-item();
-}
-
-/**
- Action icons inside dropdowns:
- - mini graph in pipelines table
- - dropdown in big graph
- - mini graph in MR widget pipeline
- - mini graph in Commit widget pipeline
-*/
-.big-pipeline-graph-dropdown-menu,
-.mini-pipeline-graph-dropdown-menu {
- width: 240px;
- max-width: 240px;
-
- // override dropdown.scss
- &.dropdown-menu li button,
- &.dropdown-menu li a.ci-action-icon-container {
- padding: 0;
- text-align: center;
- }
-
- .ci-action-icon-container {
- position: absolute;
- right: 8px;
- top: 8px;
-
- &.ci-action-icon-wrapper {
- height: $ci-action-dropdown-button-size;
- width: $ci-action-dropdown-button-size;
- border-radius: 50%;
- display: block;
-
- &:hover {
- box-shadow: inset 0 0 0 0.0625rem $dropdown-toggle-active-border-color;
- background-color: $gray-darker;
-
- svg {
- fill: $gl-text-color;
- }
- }
-
- .spinner,
- svg {
- width: $ci-action-dropdown-svg-size;
- height: $ci-action-dropdown-svg-size;
- fill: $gl-text-color-secondary;
- position: relative;
- top: 1px;
- vertical-align: initial;
- }
- }
- }
-
- // SVGs in the commit widget and mr widget
- a.ci-action-icon-container.ci-action-icon-wrapper svg {
- top: 5px;
- }
-
- .scrollable-menu {
- padding: 0;
- max-height: 245px;
- overflow: auto;
- }
-
- li {
- position: relative;
-
- // ensure .mini-pipeline-graph-dropdown-item has hover style when action-icon is hovered
- &:hover > .mini-pipeline-graph-dropdown-item,
- &:hover > .ci-job-component > .mini-pipeline-graph-dropdown-item {
- @extend .mini-pipeline-graph-dropdown-item:hover;
- }
-
- // link to the build
- .mini-pipeline-graph-dropdown-item {
- align-items: center;
- clear: both;
- display: flex;
- font-weight: normal;
- line-height: $line-height-base;
- white-space: nowrap;
-
- // Match dropdown.scss for all `a` tags
- &.non-details-job-component {
- padding: $gl-padding-8 $gl-btn-horz-padding;
- }
-
- .ci-job-name-component {
- align-items: center;
- display: flex;
- flex: 1;
- }
-
-
- .ci-status-icon {
- @include gl-mr-3;
-
- position: relative;
-
- > svg {
- width: $pipeline-dropdown-status-icon-size;
- height: $pipeline-dropdown-status-icon-size;
- margin: 3px 0;
- position: relative;
- overflow: visible;
- display: block;
- }
- }
-
- &:hover,
- &:focus {
- outline: none;
- text-decoration: none;
- background-color: $gray-darker;
- }
- }
- }
-}
-
-// Dropdown in the big pipeline graph
-.big-pipeline-graph-dropdown-menu {
- width: 195px;
- min-width: 195px;
- left: 100%;
- top: -10px;
- box-shadow: 0 1px 5px $black-transparent;
-
- /**
- * Top arrow in the dropdown in the big pipeline graph
- */
- &::before,
- &::after {
- content: '';
- display: inline-block;
- position: absolute;
- width: 0;
- height: 0;
- border-color: transparent;
- border-style: solid;
- top: 18px;
- }
-
- &::before {
- left: -6px;
- margin-top: 3px;
- border-width: 7px 5px 7px 0;
- border-right-color: $border-color;
- }
-
- &::after {
- left: -5px;
- border-width: 10px 7px 10px 0;
- border-right-color: $white;
- }
-}
-
-/**
- * Top arrow in the dropdown in the mini pipeline graph
- */
-.mini-pipeline-graph-dropdown-menu {
- &::before,
- &::after {
- content: '';
- display: inline-block;
- position: absolute;
- width: 0;
- height: 0;
- border-color: transparent;
- border-style: solid;
- top: -6px;
- left: 50%;
- transform: translate(-50%, 0);
- border-width: 0 5px 6px;
-
- @include media-breakpoint-down(sm) {
- left: 100%;
- margin-left: -12px;
- }
- }
-
- &::before {
- border-width: 0 5px 5px;
- border-bottom-color: $border-color;
- }
-
- &::after {
- margin-top: 1px;
- border-bottom-color: $white;
- }
-
- /**
- * Center dropdown menu in mini graph
- */
- .dropdown &.dropdown-menu {
- transform: translate(-80%, 0);
-
- @media (min-width: map-get($grid-breakpoints, md)) {
- transform: translate(-50%, 0);
- right: auto;
- left: 50%;
- }
- }
-}
-
-/**
- * Terminal
- */
-.terminal-icon {
- margin-left: 3px;
-}
-
-.terminal-container {
- .content-block {
- border-bottom: 0;
- }
-
- #terminal {
- margin-top: 10px;
- min-height: 450px;
- box-sizing: border-box;
-
- > div {
- min-height: 450px;
- }
- }
-}
-
-.ci-header-container {
- min-height: 55px;
-
- .text-center {
- padding-top: 12px;
- }
}
.pipelines-container .top-area .nav-controls > .btn:last-child {
float: none;
}
-.autodevops-title {
- font-weight: $gl-font-weight-normal;
- line-height: 1.5;
-}
-
-.legend-all {
- color: $gl-text-color-secondary;
-}
-
-.legend-success {
- color: $green-500;
-}
-
-.test-reports-table {
- .build-trace {
- @include build-trace();
- }
-}
-
-.codequality-report {
- .media {
- padding: $gl-padding;
- }
-
- .media-body {
- flex-direction: row;
- }
-
- .report-block-container {
- height: auto !important;
- }
-}
-
.progress-bar.bg-primary {
background-color: $blue-500 !important;
}
@@ -1090,6 +105,10 @@ button.mini-pipeline-graph-dropdown-toggle {
width: 8rem;
}
+.stage-rounded {
+ border-radius: 2rem;
+}
+
.stage-left-rounded {
border-radius: 2rem 0 0 2rem;
}
diff --git a/app/assets/stylesheets/pages/profile.scss b/app/assets/stylesheets/pages/profile.scss
index 4dc1f2034f3..3605283245f 100644
--- a/app/assets/stylesheets/pages/profile.scss
+++ b/app/assets/stylesheets/pages/profile.scss
@@ -227,6 +227,10 @@
padding-left: 40px;
}
+ .gl-label-scoped {
+ --label-inset-border: inset 0 0 0 1px currentColor;
+ }
+
@include media-breakpoint-up(lg) {
margin-right: 5px;
}
@@ -443,20 +447,3 @@ table.u2f-registrations,
width: 100%;
max-width: $add-to-slack-popup-max-width;
}
-
-.gitlab-slack-right-arrow svg {
- fill: $white-dark;
- width: $right-arrow-size;
- height: $right-arrow-size;
- vertical-align: text-bottom;
-}
-
-.gitlab-slack-double-headed-arrow {
- vertical-align: text-top;
-
- svg {
- fill: $gray-darker;
- width: $double-headed-arrow-width;
- height: $double-headed-arrow-height;
- }
-}
diff --git a/app/assets/stylesheets/pages/projects.scss b/app/assets/stylesheets/pages/projects.scss
index a2f8447c0b6..938d8d34717 100644
--- a/app/assets/stylesheets/pages/projects.scss
+++ b/app/assets/stylesheets/pages/projects.scss
@@ -1,11 +1,3 @@
-.alert_holder {
- margin: -16px;
-
- .alert-link {
- font-weight: $gl-font-weight-normal;
- }
-}
-
.new_project,
.edit-project,
.import-project {
@@ -67,38 +59,7 @@
}
}
-.classification-label {
- background-color: $red-500;
-}
-
-.toggle-wrapper {
- margin-top: 5px;
-}
-
-.project-feature-row > .toggle-wrapper {
- margin: 10px 0;
-}
-
-.project-visibility-setting,
-.project-feature-settings {
- border: 1px solid $border-color;
- padding: 10px 32px;
-
- @include media-breakpoint-down(xs) {
- padding: 10px 20px;
- }
-}
-
-.project-visibility-setting .request-access {
- line-height: 2;
-}
-
-.project-feature-settings {
- background: $gray-lighter;
- border-top: 0;
- margin-bottom: 16px;
-}
-
+// INFO Scoped to project_feature_setting and settings_panel components in app/assets/javascripts/pages/projects/shared/permissions/components
.project-repo-select {
transition: background 2s ease-out;
@@ -113,63 +74,31 @@
}
}
+// INFO Scoped to project_feature_setting and settings_panel components in app/assets/javascripts/pages/projects/shared/permissions/components
.project-feature-controls {
- display: flex;
- align-items: center;
- margin: $gl-padding-8 0;
max-width: 432px;
-
- .toggle-wrapper {
- flex: 0;
- margin-right: 10px;
- }
-
- .select-wrapper {
- flex: 1;
- }
}
+// INFO Scoped to settings_panel component in app/assets/javascripts/pages/projects/shared/permissions/components
.project-feature-setting-group {
- padding-left: 32px;
-
.project-feature-controls {
max-width: 400px;
}
-
- @include media-breakpoint-down(xs) {
- padding-left: 20px;
- }
}
-.group-home-panel,
.project-home-panel {
- margin-top: $gl-padding;
- margin-bottom: $gl-padding;
-
.home-panel-avatar {
- width: $home-panel-title-row-height;
- height: $home-panel-title-row-height;
- flex-shrink: 0;
flex-basis: $home-panel-title-row-height;
}
.home-panel-title {
- font-size: 20px;
- line-height: $gl-line-height-24;
- font-weight: bold;
-
.icon {
vertical-align: -1px;
}
.home-panel-topic-list {
- font-size: $gl-font-size;
- font-weight: $gl-font-weight-normal;
-
.icon {
- position: relative;
top: 3px;
- margin-right: $gl-padding-4;
}
}
}
@@ -201,24 +130,6 @@
}
}
- .home-panel-metadata {
- font-weight: normal;
- font-size: 14px;
- line-height: $gl-btn-line-height;
-
- .home-panel-license {
- .btn {
- line-height: 0;
- border-width: 0;
- }
- }
-
- .access-request-link {
- padding-left: $gl-padding-8;
- border-left: 1px solid $gl-text-color-secondary;
- }
- }
-
.home-panel-description {
@include media-breakpoint-up(md) {
font-size: $gl-font-size-large;
@@ -778,7 +689,7 @@
}
.btn {
- margin-top: $gl-padding-8;
+ margin-bottom: $gl-padding-8;
padding: $gl-btn-vert-padding $gl-btn-padding;
line-height: $gl-btn-line-height;
@@ -794,11 +705,6 @@
}
.project-buttons {
- .stat-text {
- @extend .btn;
- @extend .btn-default;
- }
-
.nav > li:not(:last-child) {
margin-right: $gl-padding-8;
}
diff --git a/app/assets/stylesheets/pages/reports.scss b/app/assets/stylesheets/pages/reports.scss
deleted file mode 100644
index 0c0605b0b3d..00000000000
--- a/app/assets/stylesheets/pages/reports.scss
+++ /dev/null
@@ -1,132 +0,0 @@
-.split-report-section {
- border-bottom: 1px solid $gray-darker;
-
- .report-block-container {
- max-height: 500px;
- overflow: auto;
- }
-
- .space-children,
- .space-children > span {
- display: flex;
- align-self: center;
- }
-
- .media {
- align-items: center;
- padding: 10px;
- line-height: 20px;
-
- /*
- This fixes the wrapping div of the icon in the report header.
- Apparently the borderless status icons are half the size of the status icons with border.
- This means we have to double the size of the wrapping div for borderless icons.
- */
- .space-children:first-child {
- width: 32px;
- height: 32px;
- align-items: center;
- justify-content: center;
- margin-right: 5px;
- margin-left: 1px;
- }
- }
-
- .code-text {
- width: 100%;
- flex: 1;
- }
-}
-
-.mr-widget-grouped-section {
- .report-block-container {
- max-height: 170px;
- overflow: auto;
- }
-
- .report-block-list-issue-parent {
- padding: $gl-padding-top $gl-padding;
- border-top: 1px solid $border-color;
- }
-}
-
-.report-block-container {
- border-top: 1px solid $border-color;
- padding: $gl-padding - 2;
- background-color: $gray-light;
-
- // Clean MR widget CSS
- line-height: 20px;
-}
-
-.report-block-list {
- list-style: none;
- padding: 0 1px;
- margin: 0;
-}
-
-.report-block-list-icon {
- display: flex;
-
- &.failed svg {
- color: $red-500;
- }
-
- &.success svg {
- color: $green-500;
- }
-
- &.neutral svg {
- color: $gray-500;
- }
-
- .ci-status-icon {
- svg {
- width: 24px;
- height: 24px;
- }
- }
-}
-
-.report-block-list-issue {
- display: flex;
-}
-
-.is-dismissed .report-block-list-issue-description,
-.is-dismissed .vulnerability-name-button {
- text-decoration: line-through;
-}
-
-.report-block-list-issue-description-text::after {
- content: '\00a0';
-}
-
-.report-block-list-issue-description {
- align-content: space-around;
- align-items: flex-start;
- flex-wrap: wrap;
- display: flex;
- align-self: center;
-}
-
-.report-block {
- .break-link {
- word-wrap: break-word;
- word-break: break-all;
- }
-}
-
-.report-block-issue-code {
- width: 600px;
-}
-
-.modal-security-report-dast {
- .modal-dialog {
- max-width: $modal-lg;
- }
-
- // This is temporary till we get the new modals hooked up
- &.modal-hide-footer .modal-footer {
- display: none;
- }
-}
diff --git a/app/assets/stylesheets/pages/search.scss b/app/assets/stylesheets/pages/search.scss
index 4b8e1da4867..a62e28a9b8a 100644
--- a/app/assets/stylesheets/pages/search.scss
+++ b/app/assets/stylesheets/pages/search.scss
@@ -198,11 +198,20 @@ input[type='checkbox']:hover {
}
}
+ .search-clear {
+ position: absolute;
+ right: 10px;
+ top: 9px;
+ padding: 0;
+ line-height: 0;
+ background: none;
+ border: 0;
+ }
.search-icon {
position: absolute;
left: 10px;
- top: 10px;
+ top: 9px;
color: $gray-darkest;
pointer-events: none;
}
@@ -247,14 +256,7 @@ input[type='checkbox']:hover {
}
.search-clear {
- position: absolute;
- right: 10px;
- top: 9px;
- padding: 0;
color: $gray-darkest;
- line-height: 0;
- background: none;
- border: 0;
&:hover,
&:focus {
@@ -281,6 +283,10 @@ input[type='checkbox']:hover {
}
}
+.ref-truncated {
+ @include str-truncated(10em);
+}
+
// Disable webkit input icons, link to solution: https://stackoverflow.com/questions/9421551/how-do-i-remove-all-default-webkit-search-field-styling
/* stylelint-disable property-no-vendor-prefix */
input[type='search']::-webkit-search-decoration,
diff --git a/app/assets/stylesheets/pages/serverless.scss b/app/assets/stylesheets/pages/serverless.scss
deleted file mode 100644
index a5b73492380..00000000000
--- a/app/assets/stylesheets/pages/serverless.scss
+++ /dev/null
@@ -1,3 +0,0 @@
-.url-text-field {
- cursor: text;
-}
diff --git a/app/assets/stylesheets/pages/settings_ci_cd.scss b/app/assets/stylesheets/pages/settings_ci_cd.scss
index 239123fc3ab..ebf21f58208 100644
--- a/app/assets/stylesheets/pages/settings_ci_cd.scss
+++ b/app/assets/stylesheets/pages/settings_ci_cd.scss
@@ -5,6 +5,10 @@
}
}
+.trigger-description {
+ max-width: 100px;
+}
+
.trigger-actions {
white-space: nowrap;
diff --git a/app/assets/stylesheets/pages/tags.scss b/app/assets/stylesheets/pages/tags.scss
deleted file mode 100644
index a6d30522ff7..00000000000
--- a/app/assets/stylesheets/pages/tags.scss
+++ /dev/null
@@ -1,3 +0,0 @@
-.tag-release-link {
- color: $blue-600 !important;
-}
diff --git a/app/assets/stylesheets/pages/ui_dev_kit.scss b/app/assets/stylesheets/pages/ui_dev_kit.scss
deleted file mode 100644
index 288da4da5c3..00000000000
--- a/app/assets/stylesheets/pages/ui_dev_kit.scss
+++ /dev/null
@@ -1,17 +0,0 @@
-.gitlab-ui-dev-kit {
- > h2 {
- margin: 35px 0 20px;
- font-weight: $gl-font-weight-bold;
- }
-
- .example {
- padding: 15px;
- border: 1px dashed $gray-100;
- margin-bottom: 15px;
-
- &::before {
- content: 'Example';
- color: $ui-dev-kit-example-color;
- }
- }
-}
diff --git a/app/assets/stylesheets/pages/wiki.scss b/app/assets/stylesheets/pages/wiki.scss
deleted file mode 100644
index ccf11058b5b..00000000000
--- a/app/assets/stylesheets/pages/wiki.scss
+++ /dev/null
@@ -1,157 +0,0 @@
-.title .edit-wiki-header {
- width: 780px;
- margin-left: auto;
- margin-right: auto;
- padding-right: 7px;
-}
-
-.wiki-page-header {
- position: relative;
-
- .wiki-breadcrumb {
- border-bottom: 1px solid $white-normal;
- padding: 11px 0;
- }
-
- .wiki-page-title {
- margin: 0;
- font-size: 22px;
- }
-
- .wiki-last-edit-by {
- display: block;
- color: $gl-text-color-secondary;
-
- strong {
- color: $gl-text-color;
- }
- }
-
- .light {
- font-weight: $gl-font-weight-normal;
- color: $gl-text-color-secondary;
- }
-
- .git-clone-holder {
- .input-group-prepend,
- .input-group-append {
- background-color: transparent;
- }
- }
-
- button.sidebar-toggle {
- position: absolute;
- right: 0;
- top: 11px;
- display: block;
- }
-
- &.has-sidebar-toggle .git-access-header {
- padding-right: $sidebar-toggle-width;
- }
-
- @include media-breakpoint-up(md) {
- &.has-sidebar-toggle {
- padding-right: 0;
- }
-
- button.sidebar-toggle {
- display: none;
- }
- }
-}
-
-.wiki-git-access {
- margin: $gl-padding 0;
-
- h3 {
- font-size: 19px;
- font-weight: $gl-font-weight-normal;
- margin: $gl-padding 0;
- }
-}
-
-.right-sidebar.wiki-sidebar {
- padding: 0;
-
- &.right-sidebar-collapsed {
- display: none;
- }
-
- .sidebar-container {
- padding: $gl-padding 0;
- padding-right: 100px;
- height: 100%;
- overflow-y: scroll;
- overflow-x: hidden;
- -webkit-overflow-scrolling: touch;
- }
-
- .blocks-container {
- padding: 0 $gl-padding;
- }
-
- a {
- color: $layout-link-gray;
-
- &:hover,
- &.active {
- text-decoration: none;
-
- span {
- text-decoration: underline;
- }
- }
- }
-
- .active > a {
- color: $black;
- }
-
- ul.wiki-pages,
- ul.wiki-pages li {
- list-style: none;
- padding: 0;
- margin: 0;
- }
-
- ul.wiki-pages li {
- margin: 5px 0 10px;
- }
-
- ul.wiki-pages ul {
- padding-left: 15px;
- }
-
- .wiki-sidebar-header {
- padding: 0 $gl-padding $gl-padding;
-
- .gutter-toggle {
- margin-top: 0;
- }
- }
-}
-
-ul.wiki-pages-list.content-list {
- a {
- color: $blue-600;
- }
-
- ul {
- list-style: none;
- margin-left: 0;
- padding-left: 15px;
-
- li {
- padding: 5px 0;
- }
- }
-}
-
-.empty-state-wiki .text-content {
- max-width: 490px; // Widen to allow for the Confluence button
-}
-
-.wiki-form .markdown-area {
- max-height: none;
-}
diff --git a/app/assets/stylesheets/themes/_dark.scss b/app/assets/stylesheets/themes/_dark.scss
index bfbcb8c13c6..66cc4452858 100644
--- a/app/assets/stylesheets/themes/_dark.scss
+++ b/app/assets/stylesheets/themes/_dark.scss
@@ -163,6 +163,9 @@ body.gl-dark {
--gl-text-color: #{$gray-900};
--border-color: #{$border-color};
+
+ --white: #{$white};
+ --black: #{$black};
}
$border-white-light: $gray-900;
diff --git a/app/assets/stylesheets/utilities.scss b/app/assets/stylesheets/utilities.scss
index 9c666331c4f..e236c264f5c 100644
--- a/app/assets/stylesheets/utilities.scss
+++ b/app/assets/stylesheets/utilities.scss
@@ -44,13 +44,10 @@
}
.border-width-1px { border-width: 1px; }
-.border-bottom-width-1px { border-bottom-width: 1px; }
.border-style-dashed { border-style: dashed; }
.border-style-solid { border-style: solid; }
-.border-bottom-style-solid { border-bottom-style: solid; }
.border-color-blue-300 { border-color: $blue-300; }
.border-color-default { border-color: $border-color; }
-.border-bottom-color-default { border-bottom-color: $border-color; }
.border-radius-default { border-radius: $border-radius-default; }
.border-radius-small { border-radius: $border-radius-small; }
.box-shadow-default { box-shadow: 0 2px 4px 0 $black-transparent; }
@@ -95,11 +92,6 @@
padding-bottom: $gl-spacing-scale-8;
}
-// move this to GitLab UI once onboarding experiment is considered a success
-.gl-pl-7 {
- padding-left: $gl-spacing-scale-7;
-}
-
.gl-transition-property-stroke-opacity {
transition-property: stroke-opacity;
}
@@ -116,43 +108,17 @@
box-shadow: inset 0 0 3px $gl-border-size-1 $blue-500;
}
-
-.gl-sm-align-items-flex-end {
- @media (min-width: $breakpoint-sm) {
- align-items: flex-end;
- }
-}
-
-.gl-sm-text-body {
- @media (min-width: $breakpoint-sm) {
- color: $body-color;
- }
+// This utility is used to force the z-index to match that of dropdown menu's
+.gl-z-dropdown-menu\! {
+ z-index: 300 !important;
}
-.gl-sm-font-weight-bold {
- @media (min-width: $breakpoint-sm) {
- font-weight: $gl-font-weight-bold;
- }
-}
-
-.gl-min-h-6 {
- min-height: $gl-spacing-scale-6;
-}
-
-.gl-md-justify-content-end {
- @media (min-width: $breakpoint-md) {
- width: auto !important;
- }
-}
-
-.gl-display-md-flex {
- @media (min-width: $breakpoint-md) {
- display: flex;
- }
+.gl-flex-basis-quarter {
+ flex-basis: 25%;
}
-.gl-display-md-none {
+.gl-md-ml-3 {
@media (min-width: $breakpoint-md) {
- display: none;
+ margin-left: $gl-spacing-scale-3;
}
}
diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb
index b2d98d243f9..bdd9d00ca7f 100644
--- a/app/channels/application_cable/connection.rb
+++ b/app/channels/application_cable/connection.rb
@@ -15,12 +15,14 @@ module ApplicationCable
private
def find_user_from_session_store
- session = ActiveSession.sessions_from_ids([session_id.private_id]).first
+ session = ActiveSession.sessions_from_ids(Array.wrap(session_id)).first
Warden::SessionSerializer.new('rack.session' => session).fetch(:user)
end
def session_id
- Rack::Session::SessionId.new(cookies[Gitlab::Application.config.session_options[:key]])
+ session_cookie = cookies[Gitlab::Application.config.session_options[:key]]
+
+ Rack::Session::SessionId.new(session_cookie).private_id if session_cookie.present?
end
def notification_payload(_)
diff --git a/app/controllers/abuse_reports_controller.rb b/app/controllers/abuse_reports_controller.rb
index 7d8016f763d..5e613c47fc5 100644
--- a/app/controllers/abuse_reports_controller.rb
+++ b/app/controllers/abuse_reports_controller.rb
@@ -3,6 +3,8 @@
class AbuseReportsController < ApplicationController
before_action :set_user, only: [:new]
+ feature_category :users
+
def new
@abuse_report = AbuseReport.new
@abuse_report.user_id = @user.id
diff --git a/app/controllers/admin/abuse_reports_controller.rb b/app/controllers/admin/abuse_reports_controller.rb
index 31d825c235b..6f80ed3c172 100644
--- a/app/controllers/admin/abuse_reports_controller.rb
+++ b/app/controllers/admin/abuse_reports_controller.rb
@@ -1,6 +1,8 @@
# frozen_string_literal: true
class Admin::AbuseReportsController < Admin::ApplicationController
+ feature_category :users
+
def index
@abuse_reports = AbuseReportsFinder.new(params).execute
end
diff --git a/app/controllers/admin/appearances_controller.rb b/app/controllers/admin/appearances_controller.rb
index 8405f2a5cf8..c2614a158b7 100644
--- a/app/controllers/admin/appearances_controller.rb
+++ b/app/controllers/admin/appearances_controller.rb
@@ -3,6 +3,8 @@
class Admin::AppearancesController < Admin::ApplicationController
before_action :set_appearance, except: :create
+ feature_category :navigation
+
def show
end
diff --git a/app/controllers/admin/application_settings_controller.rb b/app/controllers/admin/application_settings_controller.rb
index 73f71f7ad55..786ba73a96f 100644
--- a/app/controllers/admin/application_settings_controller.rb
+++ b/app/controllers/admin/application_settings_controller.rb
@@ -2,6 +2,7 @@
class Admin::ApplicationSettingsController < Admin::ApplicationController
include InternalRedirect
+ include ServicesHelper
# NOTE: Use @application_setting in this controller when you need to access
# application_settings after it has been modified. This is because the
@@ -16,6 +17,24 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
push_frontend_feature_flag(:ci_instance_variables_ui, default_enabled: true)
end
+ feature_category :not_owned, [
+ :general, :reporting, :metrics_and_profiling, :network,
+ :preferences, :update, :reset_health_check_token
+ ]
+
+ feature_category :metrics, [
+ :create_self_monitoring_project,
+ :status_create_self_monitoring_project,
+ :delete_self_monitoring_project,
+ :status_delete_self_monitoring_project
+ ]
+
+ feature_category :source_code_management, [:repository, :clear_repository_check_states]
+ feature_category :continuous_integration, [:ci_cd, :reset_registration_token]
+ feature_category :collection, [:usage_data]
+ feature_category :integrations, [:integrations]
+ feature_category :pages, [:lets_encrypt_terms_of_service]
+
VALID_SETTING_PANELS = %w(general repository
ci_cd reporting metrics_and_profiling
network preferences).freeze
@@ -32,6 +51,8 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
end
def integrations
+ return not_found unless instance_level_integrations?
+
@integrations = Service.find_or_initialize_all(Service.for_instance).sort_by(&:title)
end
diff --git a/app/controllers/admin/applications_controller.rb b/app/controllers/admin/applications_controller.rb
index c017ecee054..449aa90b0e6 100644
--- a/app/controllers/admin/applications_controller.rb
+++ b/app/controllers/admin/applications_controller.rb
@@ -6,6 +6,8 @@ class Admin::ApplicationsController < Admin::ApplicationController
before_action :set_application, only: [:show, :edit, :update, :destroy]
before_action :load_scopes, only: [:new, :create, :edit, :update]
+ feature_category :authentication_and_authorization
+
def index
applications = ApplicationsFinder.new.execute
@applications = Kaminari.paginate_array(applications).page(params[:page])
diff --git a/app/controllers/admin/background_jobs_controller.rb b/app/controllers/admin/background_jobs_controller.rb
index fc877142418..d4b906d5e33 100644
--- a/app/controllers/admin/background_jobs_controller.rb
+++ b/app/controllers/admin/background_jobs_controller.rb
@@ -1,4 +1,5 @@
# frozen_string_literal: true
class Admin::BackgroundJobsController < Admin::ApplicationController
+ feature_category :not_owned
end
diff --git a/app/controllers/admin/broadcast_messages_controller.rb b/app/controllers/admin/broadcast_messages_controller.rb
index 3233c765941..4660b0bfbb0 100644
--- a/app/controllers/admin/broadcast_messages_controller.rb
+++ b/app/controllers/admin/broadcast_messages_controller.rb
@@ -5,6 +5,8 @@ class Admin::BroadcastMessagesController < Admin::ApplicationController
before_action :finder, only: [:edit, :update, :destroy]
+ feature_category :navigation
+
# rubocop: disable CodeReuse/ActiveRecord
def index
@broadcast_messages = BroadcastMessage.order(ends_at: :desc).page(params[:page])
diff --git a/app/controllers/admin/ci/variables_controller.rb b/app/controllers/admin/ci/variables_controller.rb
index ca9b393550d..f30ee37fa58 100644
--- a/app/controllers/admin/ci/variables_controller.rb
+++ b/app/controllers/admin/ci/variables_controller.rb
@@ -1,6 +1,8 @@
# frozen_string_literal: true
class Admin::Ci::VariablesController < Admin::ApplicationController
+ feature_category :continuous_integration
+
def show
respond_to do |format|
format.json { render_instance_variables }
diff --git a/app/controllers/admin/cohorts_controller.rb b/app/controllers/admin/cohorts_controller.rb
index e3df98b7917..d5cd9c55422 100644
--- a/app/controllers/admin/cohorts_controller.rb
+++ b/app/controllers/admin/cohorts_controller.rb
@@ -5,6 +5,8 @@ class Admin::CohortsController < Admin::ApplicationController
track_unique_visits :index, target_id: 'i_analytics_cohorts'
+ feature_category :instance_statistics
+
def index
if Gitlab::CurrentSettings.usage_ping_enabled
cohorts_results = Rails.cache.fetch('cohorts', expires_in: 1.day) do
diff --git a/app/controllers/admin/concerns/authenticates_2fa_for_admin_mode.rb b/app/controllers/admin/concerns/authenticates_2fa_for_admin_mode.rb
deleted file mode 100644
index 03783cd75a3..00000000000
--- a/app/controllers/admin/concerns/authenticates_2fa_for_admin_mode.rb
+++ /dev/null
@@ -1,110 +0,0 @@
-# frozen_string_literal: true
-
-module Authenticates2FAForAdminMode
- extend ActiveSupport::Concern
-
- included do
- include AuthenticatesWithTwoFactor
- end
-
- def admin_mode_prompt_for_two_factor(user)
- return handle_locked_user(user) unless user.can?(:log_in)
-
- session[:otp_user_id] = user.id
- push_frontend_feature_flag(:webauthn)
-
- if user.two_factor_webauthn_enabled?
- setup_webauthn_authentication(user)
- else
- setup_u2f_authentication(user)
- end
-
- render 'admin/sessions/two_factor', layout: 'application'
- end
-
- def admin_mode_authenticate_with_two_factor
- user = current_user
-
- return handle_locked_user(user) unless user.can?(:log_in)
-
- if user_params[:otp_attempt].present? && session[:otp_user_id]
- admin_mode_authenticate_with_two_factor_via_otp(user)
- elsif user_params[:device_response].present? && session[:otp_user_id]
- if user.two_factor_webauthn_enabled?
- admin_mode_authenticate_with_two_factor_via_webauthn(user)
- else
- admin_mode_authenticate_with_two_factor_via_u2f(user)
- end
- elsif user && user.valid_password?(user_params[:password])
- admin_mode_prompt_for_two_factor(user)
- else
- invalid_login_redirect
- end
- end
-
- def admin_mode_authenticate_with_two_factor_via_otp(user)
- if valid_otp_attempt?(user)
- # Remove any lingering user data from login
- session.delete(:otp_user_id)
-
- user.save! unless Gitlab::Database.read_only?
-
- # The admin user has successfully passed 2fa, enable admin mode ignoring password
- enable_admin_mode
- else
- user.increment_failed_attempts!
- Gitlab::AppLogger.info("Failed Admin Mode Login: user=#{user.username} ip=#{request.remote_ip} method=OTP")
- flash.now[:alert] = _('Invalid two-factor code.')
-
- admin_mode_prompt_for_two_factor(user)
- end
- end
-
- def admin_mode_authenticate_with_two_factor_via_u2f(user)
- if U2fRegistration.authenticate(user, u2f_app_id, user_params[:device_response], session[:challenge])
- admin_handle_two_factor_success
- else
- admin_handle_two_factor_failure(user, 'U2F')
- end
- end
-
- def admin_mode_authenticate_with_two_factor_via_webauthn(user)
- if Webauthn::AuthenticateService.new(user, user_params[:device_response], session[:challenge]).execute
- admin_handle_two_factor_success
- else
- admin_handle_two_factor_failure(user, 'WebAuthn')
- end
- end
-
- private
-
- def enable_admin_mode
- if current_user_mode.enable_admin_mode!(skip_password_validation: true)
- redirect_to redirect_path, notice: _('Admin mode enabled')
- else
- invalid_login_redirect
- end
- end
-
- def invalid_login_redirect
- flash.now[:alert] = _('Invalid login or password')
- render :new
- end
-
- def admin_handle_two_factor_success
- # Remove any lingering user data from login
- session.delete(:otp_user_id)
- session.delete(:challenge)
-
- # The admin user has successfully passed 2fa, enable admin mode ignoring password
- enable_admin_mode
- end
-
- def admin_handle_two_factor_failure(user, method)
- user.increment_failed_attempts!
- Gitlab::AppLogger.info("Failed Admin Mode Login: user=#{user.username} ip=#{request.remote_ip} method=#{method}")
- flash.now[:alert] = _('Authentication via %{method} device failed.') % { method: method }
-
- admin_mode_prompt_for_two_factor(user)
- end
-end
diff --git a/app/controllers/admin/dashboard_controller.rb b/app/controllers/admin/dashboard_controller.rb
index b7b535e70df..7d981d67840 100644
--- a/app/controllers/admin/dashboard_controller.rb
+++ b/app/controllers/admin/dashboard_controller.rb
@@ -6,6 +6,8 @@ class Admin::DashboardController < Admin::ApplicationController
COUNTED_ITEMS = [Project, User, Group].freeze
+ feature_category :not_owned
+
# rubocop: disable CodeReuse/ActiveRecord
def index
@counts = Gitlab::Database::Count.approximate_counts(COUNTED_ITEMS)
diff --git a/app/controllers/admin/deploy_keys_controller.rb b/app/controllers/admin/deploy_keys_controller.rb
index 180f7d4c803..ed63e65d4df 100644
--- a/app/controllers/admin/deploy_keys_controller.rb
+++ b/app/controllers/admin/deploy_keys_controller.rb
@@ -4,6 +4,8 @@ class Admin::DeployKeysController < Admin::ApplicationController
before_action :deploy_keys, only: [:index]
before_action :deploy_key, only: [:destroy, :edit, :update]
+ feature_category :continuous_delivery
+
def index
end
diff --git a/app/controllers/admin/dev_ops_report_controller.rb b/app/controllers/admin/dev_ops_report_controller.rb
index bed0d51c331..59b2200fb59 100644
--- a/app/controllers/admin/dev_ops_report_controller.rb
+++ b/app/controllers/admin/dev_ops_report_controller.rb
@@ -5,6 +5,8 @@ class Admin::DevOpsReportController < Admin::ApplicationController
track_unique_visits :show, target_id: 'i_analytics_dev_ops_score'
+ feature_category :devops_reports
+
# rubocop: disable CodeReuse/ActiveRecord
def show
@metric = DevOpsReport::Metric.order(:created_at).last&.present
diff --git a/app/controllers/admin/gitaly_servers_controller.rb b/app/controllers/admin/gitaly_servers_controller.rb
index 0a5566bfe70..827791c8a4a 100644
--- a/app/controllers/admin/gitaly_servers_controller.rb
+++ b/app/controllers/admin/gitaly_servers_controller.rb
@@ -1,6 +1,8 @@
# frozen_string_literal: true
class Admin::GitalyServersController < Admin::ApplicationController
+ feature_category :gitaly
+
def index
@gitaly_servers = Gitaly::Server.all
end
diff --git a/app/controllers/admin/groups_controller.rb b/app/controllers/admin/groups_controller.rb
index 6414792dd43..032e449f995 100644
--- a/app/controllers/admin/groups_controller.rb
+++ b/app/controllers/admin/groups_controller.rb
@@ -5,6 +5,8 @@ class Admin::GroupsController < Admin::ApplicationController
before_action :group, only: [:edit, :update, :destroy, :project_update, :members_update]
+ feature_category :subgroups
+
def index
@groups = groups.sort_by_attribute(@sort = params[:sort])
@groups = @groups.search(params[:name]) if params[:name].present?
diff --git a/app/controllers/admin/health_check_controller.rb b/app/controllers/admin/health_check_controller.rb
index 7668c799cba..e013b5fbd72 100644
--- a/app/controllers/admin/health_check_controller.rb
+++ b/app/controllers/admin/health_check_controller.rb
@@ -1,6 +1,8 @@
# frozen_string_literal: true
class Admin::HealthCheckController < Admin::ApplicationController
+ feature_category :not_owned
+
def show
@errors = HealthCheck::Utils.process_checks(checks)
end
diff --git a/app/controllers/admin/hook_logs_controller.rb b/app/controllers/admin/hook_logs_controller.rb
index 8301b3aa880..444ad17f86d 100644
--- a/app/controllers/admin/hook_logs_controller.rb
+++ b/app/controllers/admin/hook_logs_controller.rb
@@ -8,6 +8,8 @@ class Admin::HookLogsController < Admin::ApplicationController
respond_to :html
+ feature_category :integrations
+
def show
end
diff --git a/app/controllers/admin/hooks_controller.rb b/app/controllers/admin/hooks_controller.rb
index 51b0f45c5be..ca24f671b9d 100644
--- a/app/controllers/admin/hooks_controller.rb
+++ b/app/controllers/admin/hooks_controller.rb
@@ -5,6 +5,8 @@ class Admin::HooksController < Admin::ApplicationController
before_action :hook_logs, only: :edit
+ feature_category :integrations
+
def index
@hooks = SystemHook.all
@hook = SystemHook.new
@@ -34,7 +36,7 @@ class Admin::HooksController < Admin::ApplicationController
end
def destroy
- hook.destroy
+ destroy_hook(hook)
redirect_to admin_hooks_path, status: :found
end
diff --git a/app/controllers/admin/identities_controller.rb b/app/controllers/admin/identities_controller.rb
index 327538f1e93..dcec50e882d 100644
--- a/app/controllers/admin/identities_controller.rb
+++ b/app/controllers/admin/identities_controller.rb
@@ -4,6 +4,8 @@ class Admin::IdentitiesController < Admin::ApplicationController
before_action :user
before_action :identity, except: [:index, :new, :create]
+ feature_category :authentication_and_authorization
+
def new
@identity = Identity.new
end
diff --git a/app/controllers/admin/impersonation_tokens_controller.rb b/app/controllers/admin/impersonation_tokens_controller.rb
index c35619a944e..c3166d5dd82 100644
--- a/app/controllers/admin/impersonation_tokens_controller.rb
+++ b/app/controllers/admin/impersonation_tokens_controller.rb
@@ -3,6 +3,8 @@
class Admin::ImpersonationTokensController < Admin::ApplicationController
before_action :user
+ feature_category :authentication_and_authorization
+
def index
set_index_vars
end
diff --git a/app/controllers/admin/impersonations_controller.rb b/app/controllers/admin/impersonations_controller.rb
index 65fe22bd8f4..6c45b03455e 100644
--- a/app/controllers/admin/impersonations_controller.rb
+++ b/app/controllers/admin/impersonations_controller.rb
@@ -4,6 +4,8 @@ class Admin::ImpersonationsController < Admin::ApplicationController
skip_before_action :authenticate_admin!
before_action :authenticate_impersonator!
+ feature_category :authentication_and_authorization
+
def destroy
original_user = stop_impersonation
redirect_to admin_user_path(original_user), status: :found
diff --git a/app/controllers/admin/instance_review_controller.rb b/app/controllers/admin/instance_review_controller.rb
new file mode 100644
index 00000000000..db304c82dd6
--- /dev/null
+++ b/app/controllers/admin/instance_review_controller.rb
@@ -0,0 +1,39 @@
+# frozen_string_literal: true
+class Admin::InstanceReviewController < Admin::ApplicationController
+ feature_category :instance_statistics
+
+ def index
+ redirect_to("#{::Gitlab::SubscriptionPortal::SUBSCRIPTIONS_URL}/instance_review?#{instance_review_params}")
+ end
+
+ def instance_review_params
+ result = {
+ instance_review: {
+ email: current_user.email,
+ last_name: current_user.name,
+ version: ::Gitlab::VERSION
+ }
+ }
+
+ if Gitlab::CurrentSettings.usage_ping_enabled?
+ data = ::Gitlab::UsageData.data
+ counts = data[:counts]
+
+ result[:instance_review].merge!(
+ users_count: data[:active_user_count],
+ projects_count: counts[:projects],
+ groups_count: counts[:groups],
+ issues_count: counts[:issues],
+ merge_requests_count: counts[:merge_requests],
+ internal_pipelines_count: counts[:ci_internal_pipelines],
+ external_pipelines_count: counts[:ci_external_pipelines],
+ labels_count: counts[:labels],
+ milestones_count: counts[:milestones],
+ snippets_count: counts[:snippets],
+ notes_count: counts[:notes]
+ )
+ end
+
+ result.to_query
+ end
+end
diff --git a/app/controllers/admin/instance_statistics_controller.rb b/app/controllers/admin/instance_statistics_controller.rb
index 3aee26b97a2..dfbd704cb0c 100644
--- a/app/controllers/admin/instance_statistics_controller.rb
+++ b/app/controllers/admin/instance_statistics_controller.rb
@@ -7,6 +7,8 @@ class Admin::InstanceStatisticsController < Admin::ApplicationController
track_unique_visits :index, target_id: 'i_analytics_instance_statistics'
+ feature_category :instance_statistics
+
def index
end
diff --git a/app/controllers/admin/integrations_controller.rb b/app/controllers/admin/integrations_controller.rb
index 1e2a99f7078..9a1d5a11f7f 100644
--- a/app/controllers/admin/integrations_controller.rb
+++ b/app/controllers/admin/integrations_controller.rb
@@ -2,6 +2,9 @@
class Admin::IntegrationsController < Admin::ApplicationController
include IntegrationsActions
+ include ServicesHelper
+
+ feature_category :integrations
private
@@ -10,7 +13,7 @@ class Admin::IntegrationsController < Admin::ApplicationController
end
def integrations_enabled?
- true
+ instance_level_integrations?
end
def scoped_edit_integration_path(integration)
diff --git a/app/controllers/admin/jobs_controller.rb b/app/controllers/admin/jobs_controller.rb
index 7b50a45a9cd..b800ca79d6b 100644
--- a/app/controllers/admin/jobs_controller.rb
+++ b/app/controllers/admin/jobs_controller.rb
@@ -3,6 +3,8 @@
class Admin::JobsController < Admin::ApplicationController
BUILDS_PER_PAGE = 30
+ feature_category :continuous_integration
+
def index
# We need all builds for tabs counters
@all_builds = Ci::JobsFinder.new(current_user: current_user).execute
diff --git a/app/controllers/admin/keys_controller.rb b/app/controllers/admin/keys_controller.rb
index 58ea19d1210..03383604e30 100644
--- a/app/controllers/admin/keys_controller.rb
+++ b/app/controllers/admin/keys_controller.rb
@@ -3,6 +3,8 @@
class Admin::KeysController < Admin::ApplicationController
before_action :user, only: [:show, :destroy]
+ feature_category :authentication_and_authorization
+
def show
@key = user.keys.find(params[:id])
diff --git a/app/controllers/admin/labels_controller.rb b/app/controllers/admin/labels_controller.rb
index 6cb206c1686..be63bf4c7ce 100644
--- a/app/controllers/admin/labels_controller.rb
+++ b/app/controllers/admin/labels_controller.rb
@@ -3,6 +3,8 @@
class Admin::LabelsController < Admin::ApplicationController
before_action :set_label, only: [:show, :edit, :update, :destroy]
+ feature_category :issue_tracking
+
def index
@labels = Label.templates.page(params[:page])
end
diff --git a/app/controllers/admin/plan_limits_controller.rb b/app/controllers/admin/plan_limits_controller.rb
index 2620db8aec5..0a5cdc06d61 100644
--- a/app/controllers/admin/plan_limits_controller.rb
+++ b/app/controllers/admin/plan_limits_controller.rb
@@ -5,6 +5,8 @@ class Admin::PlanLimitsController < Admin::ApplicationController
before_action :set_plan_limits
+ feature_category :not_owned
+
def create
redirect_path = referer_path(request) || general_admin_application_settings_path
diff --git a/app/controllers/admin/projects_controller.rb b/app/controllers/admin/projects_controller.rb
index 9fe1f22c342..c4564478462 100644
--- a/app/controllers/admin/projects_controller.rb
+++ b/app/controllers/admin/projects_controller.rb
@@ -6,6 +6,9 @@ class Admin::ProjectsController < Admin::ApplicationController
before_action :project, only: [:show, :transfer, :repository_check, :destroy]
before_action :group, only: [:show, :transfer]
+ feature_category :projects, [:index, :show, :transfer, :destroy]
+ feature_category :source_code_management, [:repository_check]
+
def index
params[:sort] ||= 'latest_activity_desc'
@sort = params[:sort]
diff --git a/app/controllers/admin/requests_profiles_controller.rb b/app/controllers/admin/requests_profiles_controller.rb
index 24383455064..fbbe8c24637 100644
--- a/app/controllers/admin/requests_profiles_controller.rb
+++ b/app/controllers/admin/requests_profiles_controller.rb
@@ -1,6 +1,8 @@
# frozen_string_literal: true
class Admin::RequestsProfilesController < Admin::ApplicationController
+ feature_category :not_owned
+
def index
@profile_token = Gitlab::RequestProfiler.profile_token
@profiles = Gitlab::RequestProfiler.all.group_by(&:request_path)
diff --git a/app/controllers/admin/runner_projects_controller.rb b/app/controllers/admin/runner_projects_controller.rb
index 774ce04d079..7761ffaac84 100644
--- a/app/controllers/admin/runner_projects_controller.rb
+++ b/app/controllers/admin/runner_projects_controller.rb
@@ -3,6 +3,8 @@
class Admin::RunnerProjectsController < Admin::ApplicationController
before_action :project, only: [:create]
+ feature_category :continuous_integration
+
def create
@runner = Ci::Runner.find(params[:runner_project][:runner_id])
diff --git a/app/controllers/admin/runners_controller.rb b/app/controllers/admin/runners_controller.rb
index 7a377a33d41..576b148fbff 100644
--- a/app/controllers/admin/runners_controller.rb
+++ b/app/controllers/admin/runners_controller.rb
@@ -1,7 +1,11 @@
# frozen_string_literal: true
class Admin::RunnersController < Admin::ApplicationController
- before_action :runner, except: [:index, :tag_list]
+ include RunnerSetupScripts
+
+ before_action :runner, except: [:index, :tag_list, :runner_setup_scripts]
+
+ feature_category :continuous_integration
def index
finder = Ci::RunnersFinder.new(current_user: current_user, params: params)
@@ -53,6 +57,10 @@ class Admin::RunnersController < Admin::ApplicationController
render json: ActsAsTaggableOn::TagSerializer.new.represent(tags)
end
+ def runner_setup_scripts
+ private_runner_setup_scripts
+ end
+
private
def runner
diff --git a/app/controllers/admin/serverless/domains_controller.rb b/app/controllers/admin/serverless/domains_controller.rb
index 1d4f10e033f..49cd9f7a36d 100644
--- a/app/controllers/admin/serverless/domains_controller.rb
+++ b/app/controllers/admin/serverless/domains_controller.rb
@@ -4,6 +4,8 @@ class Admin::Serverless::DomainsController < Admin::ApplicationController
before_action :check_feature_flag
before_action :domain, only: [:update, :verify, :destroy]
+ feature_category :serverless
+
def index
@domain = PagesDomain.instance_serverless.first_or_initialize
end
diff --git a/app/controllers/admin/services_controller.rb b/app/controllers/admin/services_controller.rb
index 1f4250639c4..379e74bb249 100644
--- a/app/controllers/admin/services_controller.rb
+++ b/app/controllers/admin/services_controller.rb
@@ -6,6 +6,8 @@ class Admin::ServicesController < Admin::ApplicationController
before_action :service, only: [:edit, :update]
before_action :whitelist_query_limiting, only: [:index]
+ feature_category :integrations
+
def index
@services = Service.find_or_create_templates.sort_by(&:title)
@existing_instance_types = Service.for_instance.pluck(:type) # rubocop: disable CodeReuse/ActiveRecord
diff --git a/app/controllers/admin/sessions_controller.rb b/app/controllers/admin/sessions_controller.rb
index 0c0bbaf4d93..9c378f4c883 100644
--- a/app/controllers/admin/sessions_controller.rb
+++ b/app/controllers/admin/sessions_controller.rb
@@ -1,12 +1,14 @@
# frozen_string_literal: true
class Admin::SessionsController < ApplicationController
- include Authenticates2FAForAdminMode
+ include AuthenticatesWithTwoFactorForAdminMode
include InternalRedirect
include RendersLdapServers
before_action :user_is_admin!
+ feature_category :authentication_and_authorization
+
def new
if current_user_mode.admin_mode?
redirect_to redirect_path, notice: _('Admin mode already enabled')
@@ -65,7 +67,10 @@ class Admin::SessionsController < ApplicationController
end
def valid_otp_attempt?(user)
- valid_otp_attempt = user.validate_and_consume_otp!(user_params[:otp_attempt])
+ otp_validation_result =
+ ::Users::ValidateOtpService.new(user).execute(user_params[:otp_attempt])
+ valid_otp_attempt = otp_validation_result[:status] == :success
+
return valid_otp_attempt if Gitlab::Database.read_only?
valid_otp_attempt || user.invalidate_otp_backup_code!(user_params[:otp_attempt])
diff --git a/app/controllers/admin/spam_logs_controller.rb b/app/controllers/admin/spam_logs_controller.rb
index 689e502a221..67d991c8b03 100644
--- a/app/controllers/admin/spam_logs_controller.rb
+++ b/app/controllers/admin/spam_logs_controller.rb
@@ -1,6 +1,8 @@
# frozen_string_literal: true
class Admin::SpamLogsController < Admin::ApplicationController
+ feature_category :not_owned
+
# rubocop: disable CodeReuse/ActiveRecord
def index
@spam_logs = SpamLog.order(id: :desc).page(params[:page])
diff --git a/app/controllers/admin/system_info_controller.rb b/app/controllers/admin/system_info_controller.rb
index 657aa177ecf..f14305528a3 100644
--- a/app/controllers/admin/system_info_controller.rb
+++ b/app/controllers/admin/system_info_controller.rb
@@ -1,6 +1,8 @@
# frozen_string_literal: true
class Admin::SystemInfoController < Admin::ApplicationController
+ feature_category :not_owned
+
EXCLUDED_MOUNT_OPTIONS = %w[
nobrowse
read-only
diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb
index e19b09e1324..bd7b69384b2 100644
--- a/app/controllers/admin/users_controller.rb
+++ b/app/controllers/admin/users_controller.rb
@@ -6,10 +6,14 @@ class Admin::UsersController < Admin::ApplicationController
before_action :user, except: [:index, :new, :create]
before_action :check_impersonation_availability, only: :impersonate
before_action :ensure_destroy_prerequisites_met, only: [:destroy]
+ before_action :check_admin_approval_feature_available!, only: [:approve]
+
+ feature_category :users
def index
@users = User.filter_items(params[:filter]).order_name_asc
@users = @users.search_with_secondary_emails(params[:search_query]) if params[:search_query].present?
+ @users = @users.includes(:authorized_projects) # rubocop: disable CodeReuse/ActiveRecord
@users = @users.sort_by_attribute(@sort = params[:sort])
@users = @users.page(params[:page])
end
@@ -59,6 +63,16 @@ class Admin::UsersController < Admin::ApplicationController
end
end
+ def approve
+ result = Users::ApproveService.new(current_user).execute(user)
+
+ if result[:status] == :success
+ redirect_back_or_admin_user(notice: _("Successfully approved"))
+ else
+ redirect_back_or_admin_user(alert: result[:message])
+ end
+ end
+
def activate
return redirect_back_or_admin_user(notice: _("Error occurred. A blocked user must be unblocked to be activated")) if user.blocked?
@@ -69,6 +83,7 @@ class Admin::UsersController < Admin::ApplicationController
def deactivate
return redirect_back_or_admin_user(notice: _("Error occurred. A blocked user cannot be deactivated")) if user.blocked?
return redirect_back_or_admin_user(notice: _("Successfully deactivated")) if user.deactivated?
+ return redirect_back_or_admin_user(notice: _("Internal users cannot be deactivated")) if user.internal?
return redirect_back_or_admin_user(notice: _("The user you are trying to deactivate has been active in the past %{minimum_inactive_days} days and cannot be deactivated") % { minimum_inactive_days: ::User::MINIMUM_INACTIVE_DAYS }) unless user.can_be_deactivated?
user.deactivate
@@ -78,7 +93,7 @@ class Admin::UsersController < Admin::ApplicationController
def block
result = Users::BlockService.new(current_user).execute(user)
- if result[:status] = :success
+ if result[:status] == :success
redirect_back_or_admin_user(notice: _("Successfully blocked"))
else
redirect_back_or_admin_user(alert: _("Error occurred. User was not blocked"))
@@ -168,7 +183,7 @@ class Admin::UsersController < Admin::ApplicationController
# restore username to keep form action url.
user.username = params[:id]
format.html { render "edit" }
- format.json { render json: [result[:message]], status: result[:status] }
+ format.json { render json: [result[:message]], status: :internal_server_error }
end
end
end
@@ -283,6 +298,10 @@ 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 check_admin_approval_feature_available!
+ access_denied! unless Feature.enabled?(:admin_approval_for_new_user_signups, default_enabled: true)
+ end
end
Admin::UsersController.prepend_if_ee('EE::Admin::UsersController')
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 5f05337e59e..05f496c3b99 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -271,6 +271,7 @@ class ApplicationController < ActionController::Base
headers['X-XSS-Protection'] = '1; mode=block'
headers['X-UA-Compatible'] = 'IE=edge'
headers['X-Content-Type-Options'] = 'nosniff'
+ headers[Gitlab::Metrics::RequestsRackMiddleware::FEATURE_CATEGORY_HEADER] = feature_category
end
def default_cache_headers
@@ -465,7 +466,8 @@ class ApplicationController < ActionController::Base
user: -> { auth_user if strong_memoized?(:auth_user) },
project: -> { @project if @project&.persisted? },
namespace: -> { @group if @group&.persisted? },
- caller_id: full_action_name) do
+ caller_id: caller_id,
+ feature_category: feature_category) do
yield
ensure
@current_context = Labkit::Context.current.to_h
@@ -484,7 +486,7 @@ class ApplicationController < ActionController::Base
def set_page_title_header
# Per https://tools.ietf.org/html/rfc5987, headers need to be ISO-8859-1, not UTF-8
- response.headers['Page-Title'] = URI.escape(page_title('GitLab'))
+ response.headers['Page-Title'] = Addressable::URI.encode_component(page_title('GitLab'))
end
def set_current_admin(&block)
@@ -547,10 +549,14 @@ class ApplicationController < ActionController::Base
end
end
- def full_action_name
+ def caller_id
"#{self.class.name}##{action_name}"
end
+ def feature_category
+ self.class.feature_category_for_action(action_name).to_s
+ end
+
def required_signup_info
return unless current_user
return unless current_user.role_required?
diff --git a/app/controllers/autocomplete_controller.rb b/app/controllers/autocomplete_controller.rb
index 99fa17e202a..ac4ee14c6a9 100644
--- a/app/controllers/autocomplete_controller.rb
+++ b/app/controllers/autocomplete_controller.rb
@@ -3,6 +3,12 @@
class AutocompleteController < ApplicationController
skip_before_action :authenticate_user!, only: [:users, :award_emojis, :merge_request_target_branches]
+ feature_category :users, [:users, :user]
+ feature_category :projects, [:projects]
+ feature_category :issue_tracking, [:award_emojis]
+ feature_category :code_review, [:merge_request_target_branches]
+ feature_category :continuous_delivery, [:deploy_keys_with_owners]
+
def users
group = Autocomplete::GroupFinder
.new(current_user, project, params)
diff --git a/app/controllers/boards/issues_controller.rb b/app/controllers/boards/issues_controller.rb
index a18c80b996e..f5a9b9b61db 100644
--- a/app/controllers/boards/issues_controller.rb
+++ b/app/controllers/boards/issues_controller.rb
@@ -21,6 +21,8 @@ module Boards
before_action :validate_id_list, only: [:bulk_move]
before_action :can_move_issues?, only: [:bulk_move]
+ feature_category :boards
+
def index
list_service = Boards::Issues::ListService.new(board_parent, current_user, filter_params)
issues = issues_from(list_service)
diff --git a/app/controllers/boards/lists_controller.rb b/app/controllers/boards/lists_controller.rb
index 0b8469e8290..aecd287370f 100644
--- a/app/controllers/boards/lists_controller.rb
+++ b/app/controllers/boards/lists_controller.rb
@@ -8,6 +8,8 @@ module Boards
before_action :authorize_read_list, only: [:index]
skip_before_action :authenticate_user!, only: [:index]
+ feature_category :boards
+
def index
lists = Boards::Lists::ListService.new(board.resource_parent, current_user).execute(board)
@@ -42,7 +44,7 @@ module Boards
list = board.lists.destroyable.find(params[:id])
service = Boards::Lists::DestroyService.new(board_parent, current_user)
- if service.execute(list)
+ if service.execute(list).success?
head :ok
else
head :unprocessable_entity
diff --git a/app/controllers/clusters/base_controller.rb b/app/controllers/clusters/base_controller.rb
index 188805c6106..b1ffdf00b87 100644
--- a/app/controllers/clusters/base_controller.rb
+++ b/app/controllers/clusters/base_controller.rb
@@ -8,6 +8,8 @@ class Clusters::BaseController < ApplicationController
helper_method :clusterable
+ feature_category :kubernetes_management
+
private
def cluster
diff --git a/app/controllers/clusters/clusters_controller.rb b/app/controllers/clusters/clusters_controller.rb
index 7006c23321c..52719e90e04 100644
--- a/app/controllers/clusters/clusters_controller.rb
+++ b/app/controllers/clusters/clusters_controller.rb
@@ -180,13 +180,20 @@ class Clusters::ClustersController < Clusters::BaseController
params.permit(:cleanup)
end
+ def base_permitted_cluster_params
+ [
+ :enabled,
+ :environment_scope,
+ :managed,
+ :namespace_per_environment
+ ]
+ end
+
def update_params
if cluster.provided_by_user?
params.require(:cluster).permit(
- :enabled,
+ *base_permitted_cluster_params,
:name,
- :environment_scope,
- :managed,
:base_domain,
:management_project_id,
platform_kubernetes_attributes: [
@@ -198,9 +205,7 @@ class Clusters::ClustersController < Clusters::BaseController
)
else
params.require(:cluster).permit(
- :enabled,
- :environment_scope,
- :managed,
+ *base_permitted_cluster_params,
:base_domain,
:management_project_id,
platform_kubernetes_attributes: [
@@ -212,10 +217,8 @@ class Clusters::ClustersController < Clusters::BaseController
def create_gcp_cluster_params
params.require(:cluster).permit(
- :enabled,
+ *base_permitted_cluster_params,
:name,
- :environment_scope,
- :managed,
provider_gcp_attributes: [
:gcp_project_id,
:zone,
@@ -232,10 +235,8 @@ class Clusters::ClustersController < Clusters::BaseController
def create_aws_cluster_params
params.require(:cluster).permit(
- :enabled,
+ *base_permitted_cluster_params,
:name,
- :environment_scope,
- :managed,
provider_aws_attributes: [
:kubernetes_version,
:key_name,
@@ -255,10 +256,8 @@ class Clusters::ClustersController < Clusters::BaseController
def create_user_cluster_params
params.require(:cluster).permit(
- :enabled,
+ *base_permitted_cluster_params,
:name,
- :environment_scope,
- :managed,
platform_kubernetes_attributes: [
:namespace,
:api_url,
diff --git a/app/controllers/concerns/authenticates_with_two_factor.rb b/app/controllers/concerns/authenticates_with_two_factor.rb
index 9ff97f398f5..5c74d79951f 100644
--- a/app/controllers/concerns/authenticates_with_two_factor.rb
+++ b/app/controllers/concerns/authenticates_with_two_factor.rb
@@ -89,10 +89,7 @@ module AuthenticatesWithTwoFactor
user.save!
sign_in(user, message: :two_factor_authenticated, event: :authentication)
else
- user.increment_failed_attempts!
- Gitlab::AppLogger.info("Failed Login: user=#{user.username} ip=#{request.remote_ip} method=OTP")
- flash.now[:alert] = _('Invalid two-factor code.')
- prompt_for_two_factor(user)
+ handle_two_factor_failure(user, 'OTP', _('Invalid two-factor code.'))
end
end
@@ -101,7 +98,7 @@ module AuthenticatesWithTwoFactor
if U2fRegistration.authenticate(user, u2f_app_id, user_params[:device_response], session[:challenge])
handle_two_factor_success(user)
else
- handle_two_factor_failure(user, 'U2F')
+ handle_two_factor_failure(user, 'U2F', _('Authentication via U2F device failed.'))
end
end
@@ -109,7 +106,7 @@ module AuthenticatesWithTwoFactor
if Webauthn::AuthenticateService.new(user, user_params[:device_response], session[:challenge]).execute
handle_two_factor_success(user)
else
- handle_two_factor_failure(user, 'WebAuthn')
+ handle_two_factor_failure(user, 'WebAuthn', _('Authentication via WebAuthn device failed.'))
end
end
@@ -152,13 +149,19 @@ module AuthenticatesWithTwoFactor
sign_in(user, message: :two_factor_authenticated, event: :authentication)
end
- def handle_two_factor_failure(user, method)
+ def handle_two_factor_failure(user, method, message)
user.increment_failed_attempts!
+ log_failed_two_factor(user, method, request.remote_ip)
+
Gitlab::AppLogger.info("Failed Login: user=#{user.username} ip=#{request.remote_ip} method=#{method}")
- flash.now[:alert] = _('Authentication via %{method} device failed.') % { method: method }
+ flash.now[:alert] = message
prompt_for_two_factor(user)
end
+ def log_failed_two_factor(user, method, ip_address)
+ # overridden in EE
+ end
+
def handle_changed_user(user)
clear_two_factor_attempt!
@@ -173,3 +176,5 @@ module AuthenticatesWithTwoFactor
Digest::SHA256.hexdigest(user.encrypted_password) != session[:user_password_hash]
end
end
+
+AuthenticatesWithTwoFactor.prepend_if_ee('EE::AuthenticatesWithTwoFactor')
diff --git a/app/controllers/concerns/authenticates_with_two_factor_for_admin_mode.rb b/app/controllers/concerns/authenticates_with_two_factor_for_admin_mode.rb
new file mode 100644
index 00000000000..a8155f1e639
--- /dev/null
+++ b/app/controllers/concerns/authenticates_with_two_factor_for_admin_mode.rb
@@ -0,0 +1,107 @@
+# frozen_string_literal: true
+
+module AuthenticatesWithTwoFactorForAdminMode
+ extend ActiveSupport::Concern
+
+ included do
+ include AuthenticatesWithTwoFactor
+ end
+
+ def admin_mode_prompt_for_two_factor(user)
+ return handle_locked_user(user) unless user.can?(:log_in)
+
+ session[:otp_user_id] = user.id
+ push_frontend_feature_flag(:webauthn)
+
+ if user.two_factor_webauthn_enabled?
+ setup_webauthn_authentication(user)
+ else
+ setup_u2f_authentication(user)
+ end
+
+ render 'admin/sessions/two_factor', layout: 'application'
+ end
+
+ def admin_mode_authenticate_with_two_factor
+ user = current_user
+
+ return handle_locked_user(user) unless user.can?(:log_in)
+
+ if user_params[:otp_attempt].present? && session[:otp_user_id]
+ admin_mode_authenticate_with_two_factor_via_otp(user)
+ elsif user_params[:device_response].present? && session[:otp_user_id]
+ if user.two_factor_webauthn_enabled?
+ admin_mode_authenticate_with_two_factor_via_webauthn(user)
+ else
+ admin_mode_authenticate_with_two_factor_via_u2f(user)
+ end
+ elsif user && user.valid_password?(user_params[:password])
+ admin_mode_prompt_for_two_factor(user)
+ else
+ invalid_login_redirect
+ end
+ end
+
+ def admin_mode_authenticate_with_two_factor_via_otp(user)
+ if valid_otp_attempt?(user)
+ # Remove any lingering user data from login
+ session.delete(:otp_user_id)
+
+ user.save! unless Gitlab::Database.read_only?
+
+ # The admin user has successfully passed 2fa, enable admin mode ignoring password
+ enable_admin_mode
+ else
+ admin_handle_two_factor_failure(user, 'OTP', _('Invalid two-factor code.'))
+ end
+ end
+
+ def admin_mode_authenticate_with_two_factor_via_u2f(user)
+ if U2fRegistration.authenticate(user, u2f_app_id, user_params[:device_response], session[:challenge])
+ admin_handle_two_factor_success
+ else
+ admin_handle_two_factor_failure(user, 'U2F', _('Authentication via U2F device failed.'))
+ end
+ end
+
+ def admin_mode_authenticate_with_two_factor_via_webauthn(user)
+ if Webauthn::AuthenticateService.new(user, user_params[:device_response], session[:challenge]).execute
+ admin_handle_two_factor_success
+ else
+ admin_handle_two_factor_failure(user, 'WebAuthn', _('Authentication via WebAuthn device failed.'))
+ end
+ end
+
+ private
+
+ def enable_admin_mode
+ if current_user_mode.enable_admin_mode!(skip_password_validation: true)
+ redirect_to redirect_path, notice: _('Admin mode enabled')
+ else
+ invalid_login_redirect
+ end
+ end
+
+ def invalid_login_redirect
+ flash.now[:alert] = _('Invalid login or password')
+ render :new
+ end
+
+ def admin_handle_two_factor_success
+ # Remove any lingering user data from login
+ session.delete(:otp_user_id)
+ session.delete(:challenge)
+
+ # The admin user has successfully passed 2fa, enable admin mode ignoring password
+ enable_admin_mode
+ end
+
+ def admin_handle_two_factor_failure(user, method, message)
+ user.increment_failed_attempts!
+ log_failed_two_factor(user, method, request.remote_ip)
+
+ Gitlab::AppLogger.info("Failed Admin Mode Login: user=#{user.username} ip=#{request.remote_ip} method=#{method}")
+ flash.now[:alert] = message
+ admin_mode_prompt_for_two_factor(user)
+ end
+end
diff --git a/app/controllers/concerns/boards_actions.rb b/app/controllers/concerns/boards_actions.rb
index 9d40b9e8c88..b382e338a78 100644
--- a/app/controllers/concerns/boards_actions.rb
+++ b/app/controllers/concerns/boards_actions.rb
@@ -9,7 +9,7 @@ module BoardsActions
before_action :boards, only: :index
before_action :board, only: :show
- before_action :push_wip_limits, only: [:index, :show]
+ before_action :push_licensed_features, only: [:index, :show]
before_action do
push_frontend_feature_flag(:not_issuable_queries, parent, default_enabled: true)
end
@@ -29,7 +29,7 @@ module BoardsActions
private
# Noop on FOSS
- def push_wip_limits
+ def push_licensed_features
end
def boards
diff --git a/app/controllers/concerns/controller_with_feature_category.rb b/app/controllers/concerns/controller_with_feature_category.rb
index f8985cf0950..c1ff9ef2e69 100644
--- a/app/controllers/concerns/controller_with_feature_category.rb
+++ b/app/controllers/concerns/controller_with_feature_category.rb
@@ -5,35 +5,38 @@ module ControllerWithFeatureCategory
include Gitlab::ClassAttributes
class_methods do
- def feature_category(category, config = {})
- validate_config!(config)
+ def feature_category(category, actions = [])
+ feature_category_configuration[category] ||= []
+ feature_category_configuration[category] += actions.map(&:to_s)
- category_config = Config.new(category, config[:only], config[:except], config[:if], config[:unless])
- # Add the config to the beginning. That way, the last defined one takes precedence.
- feature_category_configuration.unshift(category_config)
+ validate_config!(feature_category_configuration)
end
def feature_category_for_action(action)
- category_config = feature_category_configuration.find { |config| config.matches?(action) }
+ category_config = feature_category_configuration.find do |_, actions|
+ actions.empty? || actions.include?(action)
+ end
- category_config&.category || superclass_feature_category_for_action(action)
+ category_config&.first || superclass_feature_category_for_action(action)
end
private
def validate_config!(config)
- invalid_keys = config.keys - [:only, :except, :if, :unless]
- if invalid_keys.any?
- raise ArgumentError, "unknown arguments: #{invalid_keys} "
+ empty = config.find { |_, actions| actions.empty? }
+ duplicate_actions = config.values.flatten.group_by(&:itself).select { |_, v| v.count > 1 }.keys
+
+ if config.length > 1 && empty
+ raise ArgumentError, "#{empty.first} is defined for all actions, but other categories are set"
end
- if config.key?(:only) && config.key?(:except)
- raise ArgumentError, "cannot configure both `only` and `except`"
+ if duplicate_actions.any?
+ raise ArgumentError, "Actions have multiple feature categories: #{duplicate_actions.join(', ')}"
end
end
def feature_category_configuration
- class_attributes[:feature_category_config] ||= []
+ class_attributes[:feature_category_config] ||= {}
end
def superclass_feature_category_for_action(action)
diff --git a/app/controllers/concerns/controller_with_feature_category/config.rb b/app/controllers/concerns/controller_with_feature_category/config.rb
deleted file mode 100644
index 624691ee4f6..00000000000
--- a/app/controllers/concerns/controller_with_feature_category/config.rb
+++ /dev/null
@@ -1,38 +0,0 @@
-# frozen_string_literal: true
-
-module ControllerWithFeatureCategory
- class Config
- attr_reader :category
-
- def initialize(category, only, except, if_proc, unless_proc)
- @category = category.to_sym
- @only, @except = only&.map(&:to_s), except&.map(&:to_s)
- @if_proc, @unless_proc = if_proc, unless_proc
- end
-
- def matches?(action)
- included?(action) && !excluded?(action) &&
- if_proc?(action) && !unless_proc?(action)
- end
-
- private
-
- attr_reader :only, :except, :if_proc, :unless_proc
-
- def if_proc?(action)
- if_proc.nil? || if_proc.call(action)
- end
-
- def unless_proc?(action)
- unless_proc.present? && unless_proc.call(action)
- end
-
- def included?(action)
- only.nil? || only.include?(action)
- end
-
- def excluded?(action)
- except.present? && except.include?(action)
- end
- end
-end
diff --git a/app/controllers/concerns/hooks_execution.rb b/app/controllers/concerns/hooks_execution.rb
index ad1f8341109..87d215f50e7 100644
--- a/app/controllers/concerns/hooks_execution.rb
+++ b/app/controllers/concerns/hooks_execution.rb
@@ -5,6 +5,21 @@ module HooksExecution
private
+ def destroy_hook(hook)
+ result = WebHooks::DestroyService.new(current_user).execute(hook)
+
+ if result[:status] == :success
+ flash[:notice] =
+ if result[:async]
+ _("%{hook_type} was scheduled for deletion") % { hook_type: hook.model_name.human }
+ else
+ _("%{hook_type} was deleted") % { hook_type: hook.model_name.human }
+ end
+ else
+ flash[:alert] = result[:message]
+ end
+ end
+
def set_hook_execution_notice(result)
http_status = result[:http_status]
message = result[:message]
diff --git a/app/controllers/concerns/integrations_actions.rb b/app/controllers/concerns/integrations_actions.rb
index 6060dc729af..39f63bbaaec 100644
--- a/app/controllers/concerns/integrations_actions.rb
+++ b/app/controllers/concerns/integrations_actions.rb
@@ -20,7 +20,7 @@ module IntegrationsActions
respond_to do |format|
format.html do
if saved
- PropagateIntegrationWorker.perform_async(integration.id, false)
+ PropagateIntegrationWorker.perform_async(integration.id)
redirect_to scoped_edit_integration_path(integration), notice: success_message
else
render 'shared/integrations/edit'
diff --git a/app/controllers/concerns/issuable_collections.rb b/app/controllers/concerns/issuable_collections.rb
index 89ba2175b60..0d7af57328a 100644
--- a/app/controllers/concerns/issuable_collections.rb
+++ b/app/controllers/concerns/issuable_collections.rb
@@ -41,10 +41,13 @@ module IssuableCollections
end
def set_pagination
+ row_count = finder.row_count
+
@issuables = @issuables.page(params[:page])
@issuables = per_page_for_relative_position if params[:sort] == 'relative_position'
+ @issuables = @issuables.without_count if row_count == -1
@issuable_meta_data = Gitlab::IssuableMetadata.new(current_user, @issuables).data
- @total_pages = issuable_page_count(@issuables)
+ @total_pages = page_count_for_relation(@issuables, row_count)
end
# rubocop:enable Gitlab/ModuleWithInstanceVariables
@@ -58,14 +61,11 @@ module IssuableCollections
end
# rubocop: enable CodeReuse/ActiveRecord
- def issuable_page_count(relation)
- page_count_for_relation(relation, finder.row_count)
- end
-
def page_count_for_relation(relation, row_count)
limit = relation.limit_value.to_f
return 1 if limit == 0
+ return (params[:page] || 1).to_i + 1 if row_count == -1
(row_count.to_f / limit).ceil
end
diff --git a/app/controllers/concerns/issuable_collections_action.rb b/app/controllers/concerns/issuable_collections_action.rb
index e3ac117660b..7ed66027da3 100644
--- a/app/controllers/concerns/issuable_collections_action.rb
+++ b/app/controllers/concerns/issuable_collections_action.rb
@@ -59,6 +59,9 @@ module IssuableCollectionsAction
end
def finder_options
- super.merge(non_archived: true)
+ super.merge(
+ non_archived: true,
+ issue_types: Issue::TYPES_FOR_LIST
+ )
end
end
diff --git a/app/controllers/concerns/membership_actions.rb b/app/controllers/concerns/membership_actions.rb
index 8c7f156f7f8..816a93f14c6 100644
--- a/app/controllers/concerns/membership_actions.rb
+++ b/app/controllers/concerns/membership_actions.rb
@@ -22,10 +22,14 @@ module MembershipActions
.new(current_user, update_params)
.execute(member)
- member = present_members([member]).first
-
- respond_to do |format|
- format.js { render 'shared/members/update', locals: { member: member } }
+ if member.expires?
+ render json: {
+ expires_in: helpers.distance_of_time_in_words_to_now(member.expires_at),
+ expires_soon: member.expires_soon?,
+ expires_at_formatted: member.expires_at.to_time.in_time_zone.to_s(:medium)
+ }
+ else
+ render json: {}
end
end
@@ -101,7 +105,7 @@ module MembershipActions
# rubocop: enable CodeReuse/ActiveRecord
def resend_invite
- member = membershipable.members.find(params[:id])
+ member = membershipable_members.find(params[:id])
if member.invite?
member.resend_invite
@@ -118,6 +122,10 @@ module MembershipActions
raise NotImplementedError
end
+ def membershipable_members
+ raise NotImplementedError
+ end
+
def root_params_key
case membershipable
when Namespace
diff --git a/app/controllers/concerns/milestone_actions.rb b/app/controllers/concerns/milestone_actions.rb
index 29138e7b014..6470c75dfbd 100644
--- a/app/controllers/concerns/milestone_actions.rb
+++ b/app/controllers/concerns/milestone_actions.rb
@@ -3,13 +3,25 @@
module MilestoneActions
extend ActiveSupport::Concern
+ def issues
+ respond_to do |format|
+ format.html { redirect_to milestone_redirect_path }
+ format.json do
+ render json: tabs_json("shared/milestones/_issues_tab", {
+ issues: @milestone.sorted_issues(current_user), # rubocop:disable Gitlab/ModuleWithInstanceVariables
+ show_project_name: Gitlab::Utils.to_boolean(params[:show_project_name])
+ })
+ end
+ end
+ end
+
def merge_requests
respond_to do |format|
format.html { redirect_to milestone_redirect_path }
format.json do
render json: tabs_json("shared/milestones/_merge_requests_tab", {
merge_requests: @milestone.sorted_merge_requests(current_user), # rubocop:disable Gitlab/ModuleWithInstanceVariables
- show_project_name: true
+ show_project_name: Gitlab::Utils.to_boolean(params[:show_project_name])
})
end
end
diff --git a/app/controllers/concerns/multiple_boards_actions.rb b/app/controllers/concerns/multiple_boards_actions.rb
index 95a6800f55c..370b8c72bfe 100644
--- a/app/controllers/concerns/multiple_boards_actions.rb
+++ b/app/controllers/concerns/multiple_boards_actions.rb
@@ -21,11 +21,13 @@ module MultipleBoardsActions
end
def create
- board = Boards::CreateService.new(parent, current_user, board_params).execute
+ response = Boards::CreateService.new(parent, current_user, board_params).execute
respond_to do |format|
format.json do
- if board.persisted?
+ board = response.payload
+
+ if response.success?
extra_json = { board_path: board_path(board) }
render json: serialize_as_json(board).merge(extra_json)
else
diff --git a/app/controllers/concerns/redis_tracking.rb b/app/controllers/concerns/redis_tracking.rb
index fa5eef981d1..d81bd10d5bb 100644
--- a/app/controllers/concerns/redis_tracking.rb
+++ b/app/controllers/concerns/redis_tracking.rb
@@ -11,12 +11,17 @@
#
# if the feature flag is enabled by default you should use
# track_redis_hll_event :index, :show, name: 'i_analytics_dev_ops_score', feature: :my_feature, feature_default_enabled: true
+#
+# You can also pass custom conditions using `if:`, using the same format as with Rails callbacks.
module RedisTracking
extend ActiveSupport::Concern
class_methods do
- def track_redis_hll_event(*controller_actions, name:, feature:, feature_default_enabled: false)
- after_action only: controller_actions, if: -> { request.format.html? && request.headers['DNT'] != '1' } do
+ def track_redis_hll_event(*controller_actions, name:, feature:, feature_default_enabled: false, if: nil)
+ custom_conditions = Array.wrap(binding.local_variable_get('if'))
+ conditions = [:trackable_request?, *custom_conditions]
+
+ after_action only: controller_actions, if: conditions do
track_unique_redis_hll_event(name, feature, feature_default_enabled)
end
end
@@ -26,12 +31,15 @@ module RedisTracking
def track_unique_redis_hll_event(event_name, feature, feature_default_enabled)
return unless metric_feature_enabled?(feature, feature_default_enabled)
- return unless Gitlab::CurrentSettings.usage_ping_enabled?
return unless visitor_id
Gitlab::UsageDataCounters::HLLRedisCounter.track_event(visitor_id, event_name)
end
+ def trackable_request?
+ request.format.html? && request.headers['DNT'] != '1'
+ end
+
def metric_feature_enabled?(feature, default_enabled)
Feature.enabled?(feature, default_enabled: default_enabled)
end
diff --git a/app/controllers/concerns/runner_setup_scripts.rb b/app/controllers/concerns/runner_setup_scripts.rb
new file mode 100644
index 00000000000..c0e657a32d1
--- /dev/null
+++ b/app/controllers/concerns/runner_setup_scripts.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+module RunnerSetupScripts
+ extend ActiveSupport::Concern
+
+ private
+
+ def private_runner_setup_scripts(**kwargs)
+ instructions = Gitlab::Ci::RunnerInstructions.new(current_user: current_user, os: script_params[:os], arch: script_params[:arch], **kwargs)
+ output = {
+ install: instructions.install_script,
+ register: instructions.register_command
+ }
+
+ if instructions.errors.any?
+ render json: { errors: instructions.errors }, status: :bad_request
+ else
+ render json: output
+ end
+ end
+
+ def script_params
+ params.permit(:os, :arch)
+ end
+end
diff --git a/app/controllers/concerns/show_inherited_labels_checker.rb b/app/controllers/concerns/show_inherited_labels_checker.rb
new file mode 100644
index 00000000000..9847226f599
--- /dev/null
+++ b/app/controllers/concerns/show_inherited_labels_checker.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+module ShowInheritedLabelsChecker
+ extend ActiveSupport::Concern
+
+ private
+
+ def show_inherited_labels?(include_ancestor_groups)
+ Feature.enabled?(:show_inherited_labels, @project || @group, default_enabled: true) || include_ancestor_groups # rubocop:disable Gitlab/ModuleWithInstanceVariables
+ end
+end
diff --git a/app/controllers/concerns/snippets_actions.rb b/app/controllers/concerns/snippets_actions.rb
index 4548595d968..e4c3df6ccc3 100644
--- a/app/controllers/concerns/snippets_actions.rb
+++ b/app/controllers/concerns/snippets_actions.rb
@@ -17,13 +17,7 @@ module SnippetsActions
respond_to :html
end
- def edit
- # We need to load some info from the existing blob
- snippet.content = blob.data
- snippet.file_name = blob.path
-
- render 'edit'
- end
+ def edit; end
# This endpoint is being replaced by Snippets::BlobController#raw
# Support for old raw links will be maintainted via this action but
@@ -55,7 +49,6 @@ module SnippetsActions
def show
respond_to do |format|
format.html do
- conditionally_expand_blob(blob)
@note = Note.new(noteable: @snippet, project: @snippet.project)
@noteable = @snippet
@@ -80,29 +73,6 @@ module SnippetsActions
end
end
end
-
- def update
- update_params = snippet_params.merge(spammable_params)
-
- service_response = Snippets::UpdateService.new(@snippet.project, current_user, update_params).execute(@snippet)
- @snippet = service_response.payload[:snippet]
-
- handle_repository_error(:edit)
- end
-
- def destroy
- service_response = Snippets::DestroyService.new(current_user, @snippet).execute
-
- if service_response.success?
- redirect_to gitlab_dashboard_snippets_path(@snippet), status: :found
- elsif service_response.http_status == 403
- access_denied!
- else
- redirect_to gitlab_snippet_path(@snippet),
- status: :found,
- alert: service_response.message
- end
- end
# rubocop:enable Gitlab/ModuleWithInstanceVariables
private
@@ -124,12 +94,4 @@ module SnippetsActions
def convert_line_endings(content)
params[:line_ending] == 'raw' ? content : content.gsub(/\r\n/, "\n")
end
-
- def handle_repository_error(action)
- errors = Array(snippet.errors.delete(:repository))
-
- flash.now[:alert] = errors.first if errors.present?
-
- recaptcha_check_with_fallback(errors.empty?) { render action }
- end
end
diff --git a/app/controllers/concerns/wiki_actions.rb b/app/controllers/concerns/wiki_actions.rb
index 5a5b634da40..aed109309e3 100644
--- a/app/controllers/concerns/wiki_actions.rb
+++ b/app/controllers/concerns/wiki_actions.rb
@@ -5,6 +5,7 @@ module WikiActions
include PreviewMarkdown
include SendsBlob
include Gitlab::Utils::StrongMemoize
+ include RedisTracking
extend ActiveSupport::Concern
included do
@@ -31,6 +32,11 @@ module WikiActions
end
end
+ # NOTE: We want to include wiki page views in the same counter as the other
+ # Event-based wiki actions tracked through TrackUniqueEvents, so we use the same event name.
+ track_redis_hll_event :show, name: Gitlab::UsageDataCounters::TrackUniqueEvents::WIKI_ACTION.to_s,
+ feature: :track_unique_wiki_page_views, feature_default_enabled: true
+
helper_method :view_file_button, :diff_file_html_data
end
@@ -44,7 +50,7 @@ module WikiActions
wiki.list_pages(sort: params[:sort], direction: params[:direction])
).page(params[:page])
- @wiki_entries = WikiPage.group_by_directory(@wiki_pages)
+ @wiki_entries = WikiDirectory.group_pages(@wiki_pages)
render 'shared/wikis/pages'
end
diff --git a/app/controllers/confirmations_controller.rb b/app/controllers/confirmations_controller.rb
index a27c4027380..c42c9827eaf 100644
--- a/app/controllers/confirmations_controller.rb
+++ b/app/controllers/confirmations_controller.rb
@@ -3,6 +3,8 @@
class ConfirmationsController < Devise::ConfirmationsController
include AcceptsPendingInvitations
+ feature_category :users
+
def almost_there
flash[:notice] = nil
render layout: "devise_empty"
diff --git a/app/controllers/dashboard/groups_controller.rb b/app/controllers/dashboard/groups_controller.rb
index f82cde8e10a..23ffcd50369 100644
--- a/app/controllers/dashboard/groups_controller.rb
+++ b/app/controllers/dashboard/groups_controller.rb
@@ -5,6 +5,8 @@ class Dashboard::GroupsController < Dashboard::ApplicationController
skip_cross_project_access_check :index
+ feature_category :subgroups
+
def index
groups = GroupsFinder.new(current_user, all_available: false).execute
render_group_tree(groups)
diff --git a/app/controllers/dashboard/labels_controller.rb b/app/controllers/dashboard/labels_controller.rb
index 89d87c2d5c8..b661efa12c0 100644
--- a/app/controllers/dashboard/labels_controller.rb
+++ b/app/controllers/dashboard/labels_controller.rb
@@ -1,6 +1,8 @@
# frozen_string_literal: true
class Dashboard::LabelsController < Dashboard::ApplicationController
+ feature_category :issue_tracking
+
def index
respond_to do |format|
format.json { render json: LabelSerializer.new.represent_appearance(labels) }
@@ -9,8 +11,8 @@ class Dashboard::LabelsController < Dashboard::ApplicationController
def labels
finder_params = { project_ids: projects.select(:id) }
- labels = LabelsFinder.new(current_user, finder_params).execute
- GlobalLabel.build_collection(labels)
+ LabelsFinder.new(current_user, finder_params).execute
+ .select('DISTINCT ON (labels.title) labels.*')
end
end
diff --git a/app/controllers/dashboard/milestones_controller.rb b/app/controllers/dashboard/milestones_controller.rb
index 14f9a026688..e17b16c26a2 100644
--- a/app/controllers/dashboard/milestones_controller.rb
+++ b/app/controllers/dashboard/milestones_controller.rb
@@ -4,6 +4,8 @@ class Dashboard::MilestonesController < Dashboard::ApplicationController
before_action :projects
before_action :groups, only: :index
+ feature_category :issue_tracking
+
def index
respond_to do |format|
format.html do
diff --git a/app/controllers/dashboard/projects_controller.rb b/app/controllers/dashboard/projects_controller.rb
index 2bd6fd85381..f7a74f40e4b 100644
--- a/app/controllers/dashboard/projects_controller.rb
+++ b/app/controllers/dashboard/projects_controller.rb
@@ -14,6 +14,8 @@ class Dashboard::ProjectsController < Dashboard::ApplicationController
before_action :projects, only: [:index]
skip_cross_project_access_check :index, :starred
+ feature_category :projects
+
def index
respond_to do |format|
format.html do
diff --git a/app/controllers/dashboard/snippets_controller.rb b/app/controllers/dashboard/snippets_controller.rb
index a8ca3dbd0e7..6fe3d878639 100644
--- a/app/controllers/dashboard/snippets_controller.rb
+++ b/app/controllers/dashboard/snippets_controller.rb
@@ -7,6 +7,8 @@ class Dashboard::SnippetsController < Dashboard::ApplicationController
skip_cross_project_access_check :index
+ feature_category :snippets
+
def index
@snippet_counts = Snippets::CountService
.new(current_user, author: current_user)
diff --git a/app/controllers/dashboard/todos_controller.rb b/app/controllers/dashboard/todos_controller.rb
index 4fc2f7b0571..0ae326b5d94 100644
--- a/app/controllers/dashboard/todos_controller.rb
+++ b/app/controllers/dashboard/todos_controller.rb
@@ -9,6 +9,8 @@ class Dashboard::TodosController < Dashboard::ApplicationController
before_action :authorize_read_group!, only: :index
before_action :find_todos, only: [:index, :destroy_all]
+ feature_category :issue_tracking
+
def index
@sort = params[:sort]
@todos = @todos.page(params[:page])
diff --git a/app/controllers/dashboard_controller.rb b/app/controllers/dashboard_controller.rb
index 07cc31fb7d3..a88cf64d842 100644
--- a/app/controllers/dashboard_controller.rb
+++ b/app/controllers/dashboard_controller.rb
@@ -15,6 +15,10 @@ class DashboardController < Dashboard::ApplicationController
respond_to :html
+ feature_category :audit_events, [:activity]
+ feature_category :issue_tracking, [:issues, :issues_calendar]
+ feature_category :code_review, [:merge_requests]
+
def activity
respond_to do |format|
format.html
diff --git a/app/controllers/explore/groups_controller.rb b/app/controllers/explore/groups_controller.rb
index 67db797b80a..aa4196b1c18 100644
--- a/app/controllers/explore/groups_controller.rb
+++ b/app/controllers/explore/groups_controller.rb
@@ -3,6 +3,8 @@
class Explore::GroupsController < Explore::ApplicationController
include GroupTree
+ feature_category :subgroups
+
def index
render_group_tree GroupsFinder.new(current_user).execute
end
diff --git a/app/controllers/explore/projects_controller.rb b/app/controllers/explore/projects_controller.rb
index b3fa089a712..42795e418a4 100644
--- a/app/controllers/explore/projects_controller.rb
+++ b/app/controllers/explore/projects_controller.rb
@@ -18,6 +18,8 @@ class Explore::ProjectsController < Explore::ApplicationController
rescue_from PageOutOfBoundsError, with: :page_out_of_bounds
+ feature_category :projects
+
def index
@projects = load_projects
diff --git a/app/controllers/explore/snippets_controller.rb b/app/controllers/explore/snippets_controller.rb
index 3a56a48e578..91ab18f2f55 100644
--- a/app/controllers/explore/snippets_controller.rb
+++ b/app/controllers/explore/snippets_controller.rb
@@ -3,6 +3,8 @@
class Explore::SnippetsController < Explore::ApplicationController
include Gitlab::NoteableMetadata
+ feature_category :snippets
+
def index
@snippets = SnippetsFinder.new(current_user, explore: true)
.execute
diff --git a/app/controllers/google_api/authorizations_controller.rb b/app/controllers/google_api/authorizations_controller.rb
index 5723ccc14a7..76a1c43dfa3 100644
--- a/app/controllers/google_api/authorizations_controller.rb
+++ b/app/controllers/google_api/authorizations_controller.rb
@@ -6,6 +6,8 @@ module GoogleApi
before_action :validate_session_key!
+ feature_category :kubernetes_management
+
def callback
token, expires_at = GoogleApi::CloudPlatform::Client
.new(nil, callback_google_api_auth_url)
diff --git a/app/controllers/graphql_controller.rb b/app/controllers/graphql_controller.rb
index 123102bf793..b5deed70380 100644
--- a/app/controllers/graphql_controller.rb
+++ b/app/controllers/graphql_controller.rb
@@ -26,6 +26,8 @@ class GraphqlController < ApplicationController
# callback execution order here
around_action :sessionless_bypass_admin_mode!, if: :sessionless_user?
+ feature_category :not_owned
+
def execute
result = multiplex? ? execute_multiplex : execute_query
@@ -46,6 +48,10 @@ class GraphqlController < ApplicationController
render_error(exception.message, status: :unprocessable_entity)
end
+ rescue_from ::GraphQL::CoercionError do |exception|
+ render_error(exception.message, status: :unprocessable_entity)
+ end
+
private
def set_user_last_activity
@@ -81,7 +87,7 @@ class GraphqlController < ApplicationController
end
def context
- @context ||= { current_user: current_user, is_sessionless_user: !!sessionless_user? }
+ @context ||= { current_user: current_user, is_sessionless_user: !!sessionless_user?, request: request }
end
def build_variables(variable_info)
@@ -113,6 +119,12 @@ class GraphqlController < ApplicationController
# Merging to :metadata will ensure these are logged as top level keys
payload[:metadata] ||= {}
- payload[:metadata].merge!(graphql: { operation_name: params[:operationName] })
+ payload[:metadata].merge!(graphql: logs)
+ end
+
+ def logs
+ RequestStore.store[:graphql_logs].to_h
+ .except(:duration_s, :query_string)
+ .merge(operation_name: params[:operationName])
end
end
diff --git a/app/controllers/groups/avatars_controller.rb b/app/controllers/groups/avatars_controller.rb
index 8e4dc2bb6e9..1f13be449a9 100644
--- a/app/controllers/groups/avatars_controller.rb
+++ b/app/controllers/groups/avatars_controller.rb
@@ -5,6 +5,8 @@ class Groups::AvatarsController < Groups::ApplicationController
skip_cross_project_access_check :destroy
+ feature_category :subgroups
+
def destroy
@group.remove_avatar!
@group.save
diff --git a/app/controllers/groups/boards_controller.rb b/app/controllers/groups/boards_controller.rb
index ea7e83a2caf..b971c5783a8 100644
--- a/app/controllers/groups/boards_controller.rb
+++ b/app/controllers/groups/boards_controller.rb
@@ -12,6 +12,8 @@ class Groups::BoardsController < Groups::ApplicationController
push_frontend_feature_flag(:boards_with_swimlanes, group, default_enabled: false)
end
+ feature_category :boards
+
private
def assign_endpoint_vars
diff --git a/app/controllers/groups/children_controller.rb b/app/controllers/groups/children_controller.rb
index 236a19a8dc4..718914dea35 100644
--- a/app/controllers/groups/children_controller.rb
+++ b/app/controllers/groups/children_controller.rb
@@ -5,6 +5,8 @@ module Groups
before_action :group
skip_cross_project_access_check :index
+ feature_category :subgroups
+
def index
parent = if params[:parent_id].present?
GroupFinder.new(current_user).execute(id: params[:parent_id])
diff --git a/app/controllers/groups/deploy_tokens_controller.rb b/app/controllers/groups/deploy_tokens_controller.rb
index de951f2cb9f..79152bf2695 100644
--- a/app/controllers/groups/deploy_tokens_controller.rb
+++ b/app/controllers/groups/deploy_tokens_controller.rb
@@ -3,6 +3,8 @@
class Groups::DeployTokensController < Groups::ApplicationController
before_action :authorize_destroy_deploy_token!
+ feature_category :continuous_delivery
+
def revoke
@token = @group.deploy_tokens.find(params[:id])
@token.revoke!
diff --git a/app/controllers/groups/group_links_controller.rb b/app/controllers/groups/group_links_controller.rb
index c395b93f4e7..3b775af9722 100644
--- a/app/controllers/groups/group_links_controller.rb
+++ b/app/controllers/groups/group_links_controller.rb
@@ -4,6 +4,8 @@ class Groups::GroupLinksController < Groups::ApplicationController
before_action :authorize_admin_group!
before_action :group_link, only: [:update, :destroy]
+ feature_category :subgroups
+
def create
shared_with_group = Group.find(params[:shared_with_group_id]) if params[:shared_with_group_id].present?
@@ -24,6 +26,15 @@ class Groups::GroupLinksController < Groups::ApplicationController
def update
Groups::GroupLinks::UpdateService.new(@group_link).execute(group_link_params)
+
+ if @group_link.expires?
+ render json: {
+ expires_in: helpers.distance_of_time_in_words_to_now(@group_link.expires_at),
+ expires_soon: @group_link.expires_soon?
+ }
+ else
+ render json: {}
+ end
end
def destroy
diff --git a/app/controllers/groups/group_members_controller.rb b/app/controllers/groups/group_members_controller.rb
index 63311ab983b..5df7ff0632a 100644
--- a/app/controllers/groups/group_members_controller.rb
+++ b/app/controllers/groups/group_members_controller.rb
@@ -19,6 +19,8 @@ class Groups::GroupMembersController < Groups::ApplicationController
:approve_access_request, :leave, :resend_invite,
:override
+ feature_category :authentication_and_authorization
+
def index
@sort = params[:sort].presence || sort_value_name
@@ -69,6 +71,10 @@ class Groups::GroupMembersController < Groups::ApplicationController
def filter_params
params.permit(:two_factor, :search).merge(sort: @sort)
end
+
+ def membershipable_members
+ group.members
+ end
end
Groups::GroupMembersController.prepend_if_ee('EE::Groups::GroupMembersController')
diff --git a/app/controllers/groups/imports_controller.rb b/app/controllers/groups/imports_controller.rb
index b611685f9bc..7cf39e378db 100644
--- a/app/controllers/groups/imports_controller.rb
+++ b/app/controllers/groups/imports_controller.rb
@@ -3,6 +3,8 @@
class Groups::ImportsController < Groups::ApplicationController
include ContinueParams
+ feature_category :importers
+
def show
if @group.import_state.nil? || @group.import_state.finished?
if continue_params[:to]
diff --git a/app/controllers/groups/labels_controller.rb b/app/controllers/groups/labels_controller.rb
index 1034ca6cd7b..34856f8d84e 100644
--- a/app/controllers/groups/labels_controller.rb
+++ b/app/controllers/groups/labels_controller.rb
@@ -2,6 +2,7 @@
class Groups::LabelsController < Groups::ApplicationController
include ToggleSubscriptionAction
+ include ShowInheritedLabelsChecker
before_action :label, only: [:edit, :update, :destroy]
before_action :authorize_admin_labels!, only: [:new, :create, :edit, :update, :destroy]
@@ -9,11 +10,14 @@ class Groups::LabelsController < Groups::ApplicationController
respond_to :html
+ feature_category :issue_tracking
+
def index
respond_to do |format|
format.html do
- @labels = GroupLabelsFinder
- .new(current_user, @group, params.merge(sort: sort)).execute
+ # at group level we do not want to list project labels,
+ # we only want `only_group_labels = false` when pulling labels for label filter dropdowns, fetched through json
+ @labels = available_labels(params.merge(only_group_labels: true)).page(params[:page])
end
format.json do
render json: LabelSerializer.new.represent_appearance(available_labels)
@@ -60,13 +64,7 @@ class Groups::LabelsController < Groups::ApplicationController
def destroy
@label.destroy
-
- respond_to do |format|
- format.html do
- redirect_to group_labels_path(@group), status: :found, notice: "#{@label.name} deleted permanently"
- end
- format.js
- end
+ redirect_to group_labels_path(@group), status: :found, notice: "#{@label.name} deleted permanently"
end
protected
@@ -80,7 +78,7 @@ class Groups::LabelsController < Groups::ApplicationController
end
def label
- @label ||= @group.labels.find(params[:id])
+ @label ||= available_labels(params.merge(only_group_labels: true)).find(params[:id])
end
alias_method :subscribable_resource, :label
@@ -108,15 +106,17 @@ class Groups::LabelsController < Groups::ApplicationController
session[:previous_labels_path] = URI(request.referer || '').path
end
- def available_labels
+ def available_labels(options = params)
@available_labels ||=
LabelsFinder.new(
current_user,
group_id: @group.id,
- only_group_labels: params[:only_group_labels],
- include_ancestor_groups: params[:include_ancestor_groups],
- include_descendant_groups: params[:include_descendant_groups],
- search: params[:search]).execute
+ only_group_labels: options[:only_group_labels],
+ include_ancestor_groups: show_inherited_labels?(params[:include_ancestor_groups]),
+ sort: sort,
+ subscribed: options[:subscribed],
+ include_descendant_groups: options[:include_descendant_groups],
+ search: options[:search]).execute
end
def sort
diff --git a/app/controllers/groups/milestones_controller.rb b/app/controllers/groups/milestones_controller.rb
index df3fb6b67c2..173a24ceb74 100644
--- a/app/controllers/groups/milestones_controller.rb
+++ b/app/controllers/groups/milestones_controller.rb
@@ -3,12 +3,14 @@
class Groups::MilestonesController < Groups::ApplicationController
include MilestoneActions
- before_action :milestone, only: [:edit, :show, :update, :merge_requests, :participants, :labels, :destroy]
+ before_action :milestone, only: [:edit, :show, :update, :issues, :merge_requests, :participants, :labels, :destroy]
before_action :authorize_admin_milestones!, only: [:edit, :new, :create, :update, :destroy]
before_action do
push_frontend_feature_flag(:burnup_charts, @group)
end
+ feature_category :issue_tracking
+
def index
respond_to do |format|
format.html do
diff --git a/app/controllers/groups/packages_controller.rb b/app/controllers/groups/packages_controller.rb
index 600acc72e67..47f1816cc4c 100644
--- a/app/controllers/groups/packages_controller.rb
+++ b/app/controllers/groups/packages_controller.rb
@@ -4,6 +4,8 @@ module Groups
class PackagesController < Groups::ApplicationController
before_action :verify_packages_enabled!
+ feature_category :package_registry
+
private
def verify_packages_enabled!
diff --git a/app/controllers/groups/registry/repositories_controller.rb b/app/controllers/groups/registry/repositories_controller.rb
index 14651e0794a..d914e0bffc6 100644
--- a/app/controllers/groups/registry/repositories_controller.rb
+++ b/app/controllers/groups/registry/repositories_controller.rb
@@ -2,9 +2,13 @@
module Groups
module Registry
class RepositoriesController < Groups::ApplicationController
+ include PackagesHelper
+
before_action :verify_container_registry_enabled!
before_action :authorize_read_container_image!
+ feature_category :package_registry
+
def index
respond_to do |format|
format.html
@@ -13,7 +17,7 @@ module Groups
.execute
.with_api_entity_associations
- track_event(:list_repositories)
+ track_package_event(:list_repositories, :container)
serializer = ContainerRepositoriesSerializer
.new(current_user: current_user)
diff --git a/app/controllers/groups/releases_controller.rb b/app/controllers/groups/releases_controller.rb
index 500c57a6f3e..6a42f30b847 100644
--- a/app/controllers/groups/releases_controller.rb
+++ b/app/controllers/groups/releases_controller.rb
@@ -2,6 +2,8 @@
module Groups
class ReleasesController < Groups::ApplicationController
+ feature_category :release_evidence
+
def index
respond_to do |format|
format.json do
diff --git a/app/controllers/groups/runners_controller.rb b/app/controllers/groups/runners_controller.rb
index edebffe2912..dbfd31ebcad 100644
--- a/app/controllers/groups/runners_controller.rb
+++ b/app/controllers/groups/runners_controller.rb
@@ -7,6 +7,8 @@ class Groups::RunnersController < Groups::ApplicationController
before_action :runner, only: [:edit, :update, :destroy, :pause, :resume, :show]
+ feature_category :continuous_integration
+
def show
render 'shared/runners/show'
end
diff --git a/app/controllers/groups/settings/ci_cd_controller.rb b/app/controllers/groups/settings/ci_cd_controller.rb
index bf3a38ce57b..0c72c8a037b 100644
--- a/app/controllers/groups/settings/ci_cd_controller.rb
+++ b/app/controllers/groups/settings/ci_cd_controller.rb
@@ -3,6 +3,8 @@
module Groups
module Settings
class CiCdController < Groups::ApplicationController
+ include RunnerSetupScripts
+
skip_cross_project_access_check :show
before_action :authorize_admin_group!
before_action :authorize_update_max_artifacts_size!, only: [:update]
@@ -11,6 +13,8 @@ module Groups
end
before_action :define_variables, only: [:show]
+ feature_category :continuous_integration
+
NUMBER_OF_RUNNERS_PER_PAGE = 4
def show
@@ -49,6 +53,10 @@ module Groups
redirect_to group_settings_ci_cd_path
end
+ def runner_setup_scripts
+ private_runner_setup_scripts(group: group)
+ end
+
private
def define_variables
diff --git a/app/controllers/groups/settings/integrations_controller.rb b/app/controllers/groups/settings/integrations_controller.rb
index e8551a7f270..b089cfdf341 100644
--- a/app/controllers/groups/settings/integrations_controller.rb
+++ b/app/controllers/groups/settings/integrations_controller.rb
@@ -7,6 +7,8 @@ module Groups
before_action :authorize_admin_group!
+ feature_category :integrations
+
def index
@integrations = Service.find_or_initialize_all(Service.for_group(group)).sort_by(&:title)
end
diff --git a/app/controllers/groups/settings/repository_controller.rb b/app/controllers/groups/settings/repository_controller.rb
index e2fbdc39692..ccc1fa12458 100644
--- a/app/controllers/groups/settings/repository_controller.rb
+++ b/app/controllers/groups/settings/repository_controller.rb
@@ -10,6 +10,8 @@ module Groups
push_frontend_feature_flag(:ajax_new_deploy_token, @group)
end
+ feature_category :continuous_delivery
+
def create_deploy_token
result = Groups::DeployTokens::CreateService.new(@group, current_user, deploy_token_params).execute
@new_deploy_token = result[:deploy_token]
diff --git a/app/controllers/groups/shared_projects_controller.rb b/app/controllers/groups/shared_projects_controller.rb
index 30b7bfc70ae..90ec64d4768 100644
--- a/app/controllers/groups/shared_projects_controller.rb
+++ b/app/controllers/groups/shared_projects_controller.rb
@@ -6,6 +6,8 @@ module Groups
before_action :group
skip_cross_project_access_check :index
+ feature_category :subgroups
+
def index
shared_projects = GroupProjectsFinder.new(
group: group,
diff --git a/app/controllers/groups/uploads_controller.rb b/app/controllers/groups/uploads_controller.rb
index 3ae7e36c740..49249f87d31 100644
--- a/app/controllers/groups/uploads_controller.rb
+++ b/app/controllers/groups/uploads_controller.rb
@@ -9,6 +9,8 @@ class Groups::UploadsController < Groups::ApplicationController
before_action :authorize_upload_file!, only: [:create, :authorize]
before_action :verify_workhorse_api!, only: [:authorize]
+ feature_category :subgroups
+
private
def upload_model_class
diff --git a/app/controllers/groups/variables_controller.rb b/app/controllers/groups/variables_controller.rb
index fb639f6e472..51670325ce3 100644
--- a/app/controllers/groups/variables_controller.rb
+++ b/app/controllers/groups/variables_controller.rb
@@ -6,6 +6,8 @@ module Groups
skip_cross_project_access_check :show, :update
+ feature_category :continuous_integration
+
def show
respond_to do |format|
format.json do
diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb
index 2d6f5d0377a..6f8dc75f6bd 100644
--- a/app/controllers/groups_controller.rb
+++ b/app/controllers/groups_controller.rb
@@ -30,6 +30,7 @@ class GroupsController < Groups::ApplicationController
before_action do
push_frontend_feature_flag(:vue_issuables_list, @group)
+ push_frontend_feature_flag(:deployment_filters)
end
before_action do
@@ -46,6 +47,17 @@ class GroupsController < Groups::ApplicationController
layout :determine_layout
+ feature_category :subgroups, [
+ :index, :new, :create, :show, :edit, :update,
+ :destroy, :details, :transfer
+ ]
+
+ feature_category :audit_events, [:activity]
+ feature_category :issue_tracking, [:issues, :issues_calendar, :preview_markdown]
+ feature_category :code_review, [:merge_requests, :unfoldered_environment_names]
+ feature_category :projects, [:projects]
+ feature_category :importers, [:export, :download_export]
+
def index
redirect_to(current_user ? dashboard_groups_path : explore_groups_path)
end
@@ -168,6 +180,16 @@ class GroupsController < Groups::ApplicationController
end
end
+ def unfoldered_environment_names
+ return render_404 unless Feature.enabled?(:deployment_filters)
+
+ respond_to do |format|
+ format.json do
+ render json: EnvironmentNamesFinder.new(@group, current_user).execute
+ end
+ end
+ end
+
protected
def render_show_html
@@ -230,7 +252,9 @@ class GroupsController < Groups::ApplicationController
:two_factor_grace_period,
:project_creation_level,
:subgroup_creation_level,
- :default_branch_protection
+ :default_branch_protection,
+ :default_branch_name,
+ :allow_mfa_for_subgroups
]
end
diff --git a/app/controllers/help_controller.rb b/app/controllers/help_controller.rb
index a1bbcf34f69..5a5200452de 100644
--- a/app/controllers/help_controller.rb
+++ b/app/controllers/help_controller.rb
@@ -2,6 +2,7 @@
class HelpController < ApplicationController
skip_before_action :authenticate_user!, unless: :public_visibility_restricted?
+ feature_category :not_owned
layout 'help'
@@ -26,17 +27,10 @@ class HelpController < ApplicationController
respond_to do |format|
format.any(:markdown, :md, :html) do
- # Note: We are purposefully NOT using `Rails.root.join` because of https://gitlab.com/gitlab-org/gitlab/-/issues/216028.
- path = File.join(Rails.root, 'doc', "#{@path}.md")
-
- if File.exist?(path)
- # Remove YAML frontmatter so that it doesn't look weird
- @markdown = File.read(path).gsub(YAML_FRONT_MATTER_REGEXP, '')
-
- render 'show.html.haml'
+ if redirect_to_documentation_website?
+ redirect_to documentation_url
else
- # Force template to Haml
- render 'errors/not_found.html.haml', layout: 'errors', status: :not_found
+ render_documentation
end
end
@@ -75,4 +69,47 @@ class HelpController < ApplicationController
params
end
+
+ def redirect_to_documentation_website?
+ return false unless Feature.enabled?(:help_page_documentation_redirect)
+ return false unless Gitlab::UrlSanitizer.valid_web?(documentation_url)
+
+ true
+ end
+
+ def documentation_url
+ return unless documentation_base_url
+
+ @documentation_url ||= Gitlab::Utils.append_path(documentation_base_url, documentation_file_path)
+ end
+
+ def documentation_base_url
+ @documentation_base_url ||= Gitlab::CurrentSettings.current_application_settings.help_page_documentation_base_url.presence
+ end
+
+ def documentation_file_path
+ @documentation_file_path ||= [version_segment, 'ee', "#{@path}.html"].compact.join('/')
+ end
+
+ def version_segment
+ return if Gitlab.pre_release?
+
+ version = Gitlab.version_info
+ [version.major, version.minor].join('.')
+ end
+
+ def render_documentation
+ # Note: We are purposefully NOT using `Rails.root.join` because of https://gitlab.com/gitlab-org/gitlab/-/issues/216028.
+ path = File.join(Rails.root, 'doc', "#{@path}.md")
+
+ if File.exist?(path)
+ # Remove YAML frontmatter so that it doesn't look weird
+ @markdown = File.read(path).gsub(YAML_FRONT_MATTER_REGEXP, '')
+
+ render 'show.html.haml'
+ else
+ # Force template to Haml
+ render 'errors/not_found.html.haml', layout: 'errors', status: :not_found
+ end
+ end
end
diff --git a/app/controllers/ide_controller.rb b/app/controllers/ide_controller.rb
index 2c17f5b5542..8c0414ad5da 100644
--- a/app/controllers/ide_controller.rb
+++ b/app/controllers/ide_controller.rb
@@ -11,6 +11,8 @@ class IdeController < ApplicationController
push_frontend_feature_flag(:schema_linting)
end
+ feature_category :web_ide
+
def index
Gitlab::UsageDataCounters::WebIdeCounter.increment_views_count
end
diff --git a/app/controllers/import/available_namespaces_controller.rb b/app/controllers/import/available_namespaces_controller.rb
index 7983b4f20b5..c6211b33d28 100644
--- a/app/controllers/import/available_namespaces_controller.rb
+++ b/app/controllers/import/available_namespaces_controller.rb
@@ -1,6 +1,8 @@
# frozen_string_literal: true
class Import::AvailableNamespacesController < ApplicationController
+ feature_category :importers
+
def index
render json: NamespaceSerializer.new.represent(current_user.manageable_groups_with_routes)
end
diff --git a/app/controllers/import/base_controller.rb b/app/controllers/import/base_controller.rb
index 8a7a4c92b37..151ba46e629 100644
--- a/app/controllers/import/base_controller.rb
+++ b/app/controllers/import/base_controller.rb
@@ -4,6 +4,7 @@ class Import::BaseController < ApplicationController
include ActionView::Helpers::SanitizeHelper
before_action :import_rate_limit, only: [:create]
+ feature_category :importers
def status
respond_to do |format|
diff --git a/app/controllers/import/bulk_imports_controller.rb b/app/controllers/import/bulk_imports_controller.rb
new file mode 100644
index 00000000000..cb2922c2d47
--- /dev/null
+++ b/app/controllers/import/bulk_imports_controller.rb
@@ -0,0 +1,109 @@
+# frozen_string_literal: true
+
+class Import::BulkImportsController < ApplicationController
+ before_action :ensure_group_import_enabled
+ before_action :verify_blocked_uri, only: :status
+
+ feature_category :importers
+
+ rescue_from Gitlab::BulkImport::Client::ConnectionError, with: :bulk_import_connection_error
+
+ def configure
+ session[access_token_key] = params[access_token_key]&.strip
+ session[url_key] = params[url_key]
+
+ redirect_to status_import_bulk_import_url
+ end
+
+ def status
+ respond_to do |format|
+ format.json do
+ render json: { importable_data: serialized_importable_data }
+ end
+
+ format.html
+ end
+ end
+
+ private
+
+ def serialized_importable_data
+ serializer.represent(importable_data, {}, Import::BulkImportEntity)
+ end
+
+ def serializer
+ @serializer ||= BaseSerializer.new(current_user: current_user)
+ end
+
+ def importable_data
+ client.get('groups', top_level_only: true)
+ end
+
+ def client
+ @client ||= Gitlab::BulkImport::Client.new(
+ uri: session[url_key],
+ token: session[access_token_key]
+ )
+ end
+
+ def import_params
+ params.permit(access_token_key, url_key)
+ end
+
+ def ensure_group_import_enabled
+ render_404 unless Feature.enabled?(:bulk_import)
+ end
+
+ def access_token_key
+ :bulk_import_gitlab_access_token
+ end
+
+ def url_key
+ :bulk_import_gitlab_url
+ end
+
+ def verify_blocked_uri
+ Gitlab::UrlBlocker.validate!(
+ session[url_key],
+ **{
+ allow_localhost: allow_local_requests?,
+ allow_local_network: allow_local_requests?,
+ schemes: %w(http https)
+ }
+ )
+ rescue Gitlab::UrlBlocker::BlockedUrlError => e
+ clear_session_data
+
+ redirect_to new_group_path, alert: _('Specified URL cannot be used: "%{reason}"') % { reason: e.message }
+ end
+
+ def allow_local_requests?
+ Gitlab::CurrentSettings.allow_local_requests_from_web_hooks_and_services?
+ end
+
+ def bulk_import_connection_error(error)
+ clear_session_data
+
+ error_message = _("Unable to connect to server: %{error}") % { error: error }
+ flash[:alert] = error_message
+
+ respond_to do |format|
+ format.json do
+ render json: {
+ error: {
+ message: error_message,
+ redirect: new_group_path
+ }
+ }, status: :unprocessable_entity
+ end
+ format.html do
+ redirect_to new_group_path
+ end
+ end
+ end
+
+ def clear_session_data
+ session[url_key] = nil
+ session[access_token_key] = nil
+ end
+end
diff --git a/app/controllers/import/fogbugz_controller.rb b/app/controllers/import/fogbugz_controller.rb
index a34bc9c953f..bcbf5938e11 100644
--- a/app/controllers/import/fogbugz_controller.rb
+++ b/app/controllers/import/fogbugz_controller.rb
@@ -136,7 +136,7 @@ class Import::FogbugzController < Import::BaseController
def verify_blocked_uri
Gitlab::UrlBlocker.validate!(
params[:uri],
- {
+ **{
allow_localhost: allow_local_requests?,
allow_local_network: allow_local_requests?,
schemes: %w(http https)
diff --git a/app/controllers/import/github_controller.rb b/app/controllers/import/github_controller.rb
index 29fe34f0734..a1adc6e062a 100644
--- a/app/controllers/import/github_controller.rb
+++ b/app/controllers/import/github_controller.rb
@@ -108,7 +108,7 @@ class Import::GithubController < Import::BaseController
@client ||= if Feature.enabled?(:remove_legacy_github_client)
Gitlab::GithubImport::Client.new(session[access_token_key])
else
- Gitlab::LegacyGithubImport::Client.new(session[access_token_key], client_options)
+ Gitlab::LegacyGithubImport::Client.new(session[access_token_key], **client_options)
end
end
diff --git a/app/controllers/import/gitlab_groups_controller.rb b/app/controllers/import/gitlab_groups_controller.rb
index 330af68385e..d8118477a80 100644
--- a/app/controllers/import/gitlab_groups_controller.rb
+++ b/app/controllers/import/gitlab_groups_controller.rb
@@ -6,6 +6,8 @@ class Import::GitlabGroupsController < ApplicationController
before_action :ensure_group_import_enabled
before_action :import_rate_limit, only: %i[create]
+ feature_category :importers
+
def create
unless file_is_valid?(group_params[:file])
return redirect_back_or_default(options: { alert: s_('GroupImport|Unable to process group import file') })
diff --git a/app/controllers/import/manifest_controller.rb b/app/controllers/import/manifest_controller.rb
index 9c47e6d4b0b..fdca6da95c5 100644
--- a/app/controllers/import/manifest_controller.rb
+++ b/app/controllers/import/manifest_controller.rb
@@ -26,8 +26,7 @@ class Import::ManifestController < Import::BaseController
manifest = Gitlab::ManifestImport::Manifest.new(params[:manifest].tempfile)
if manifest.valid?
- session[:manifest_import_repositories] = manifest.projects
- session[:manifest_import_group_id] = group.id
+ manifest_import_metadata.save(manifest.projects, group.id)
redirect_to status_import_manifest_path
else
@@ -96,12 +95,16 @@ class Import::ManifestController < Import::BaseController
# rubocop: disable CodeReuse/ActiveRecord
def group
- @group ||= Group.find_by(id: session[:manifest_import_group_id])
+ @group ||= Group.find_by(id: manifest_import_metadata.group_id)
end
# rubocop: enable CodeReuse/ActiveRecord
+ def manifest_import_metadata
+ @manifest_import_status ||= Gitlab::ManifestImport::Metadata.new(current_user, fallback: session)
+ end
+
def repositories
- @repositories ||= session[:manifest_import_repositories]
+ @repositories ||= manifest_import_metadata.repositories
end
def find_jobs
diff --git a/app/controllers/invites_controller.rb b/app/controllers/invites_controller.rb
index aa9c7d01ba3..c7b8486d1c9 100644
--- a/app/controllers/invites_controller.rb
+++ b/app/controllers/invites_controller.rb
@@ -4,6 +4,7 @@ class InvitesController < ApplicationController
include Gitlab::Utils::StrongMemoize
before_action :member
+ before_action :ensure_member_exists
before_action :invite_details
skip_before_action :authenticate_user!, only: :decline
@@ -11,14 +12,17 @@ class InvitesController < ApplicationController
respond_to :html
+ feature_category :authentication_and_authorization
+
def show
- track_experiment('opened')
+ track_new_user_invite_experiment('opened')
accept if skip_invitation_prompt?
end
def accept
if member.accept_invite!(current_user)
- track_experiment('accepted')
+ track_new_user_invite_experiment('accepted')
+ track_invitation_reminders_experiment('accepted')
redirect_to invite_details[:path], notice: _("You have been granted %{member_human_access} access to %{title} %{name}.") %
{ member_human_access: member.human_access, title: invite_details[:title], name: invite_details[:name] }
else
@@ -28,6 +32,8 @@ class InvitesController < ApplicationController
def decline
if member.decline_invite!
+ return render layout: 'devise_experimental_onboarding_issues' if !current_user && member.invite_to_unknown_user? && member.created_by
+
path =
if current_user
dashboard_projects_path
@@ -59,14 +65,16 @@ class InvitesController < ApplicationController
end
def member
- return @member if defined?(@member)
-
- @token = params[:id]
- @member = Member.find_by_invite_token(@token)
+ strong_memoize(:member) do
+ @token = params[:id]
+ Member.find_by_invite_token(@token)
+ end
+ end
- return render_404 unless @member
+ def ensure_member_exists
+ return if member
- @member
+ render_404
end
def authenticate_user!
@@ -76,10 +84,7 @@ class InvitesController < ApplicationController
notice << "or create an account" if Gitlab::CurrentSettings.allow_signup?
notice = notice.join(' ') + "."
- # this is temporary finder instead of using member method due to render_404 possibility
- # will be resolved via https://gitlab.com/gitlab-org/gitlab/-/issues/245325
- initial_member = Member.find_by_invite_token(params[:id])
- redirect_params = initial_member ? { invite_email: initial_member.invite_email } : {}
+ redirect_params = member ? { invite_email: member.invite_email } : {}
store_location_for :user, request.fullpath
@@ -87,31 +92,43 @@ class InvitesController < ApplicationController
end
def invite_details
- @invite_details ||= case @member.source
+ @invite_details ||= case member.source
when Project
{
- name: @member.source.full_name,
- url: project_url(@member.source),
+ name: member.source.full_name,
+ url: project_url(member.source),
title: _("project"),
- path: project_path(@member.source)
+ path: project_path(member.source)
}
when Group
{
- name: @member.source.name,
- url: group_url(@member.source),
+ name: member.source.name,
+ url: group_url(member.source),
title: _("group"),
- path: group_path(@member.source)
+ path: group_path(member.source)
}
end
end
- def track_experiment(action)
+ def track_new_user_invite_experiment(action)
return unless params[:new_user_invite]
property = params[:new_user_invite] == 'experiment' ? 'experiment_group' : 'control_group'
+ track_experiment(:invite_email, action, property)
+ end
+
+ def track_invitation_reminders_experiment(action)
+ return unless Gitlab::Experimentation.enabled?(:invitation_reminders)
+
+ property = Gitlab::Experimentation.enabled_for_attribute?(:invitation_reminders, member.invite_email) ? 'experimental_group' : 'control_group'
+
+ track_experiment(:invitation_reminders, action, property)
+ end
+
+ def track_experiment(experiment_key, action, property)
Gitlab::Tracking.event(
- Gitlab::Experimentation::EXPERIMENTS[:invite_email][:tracking_category],
+ Gitlab::Experimentation.experiment(experiment_key).tracking_category,
action,
property: property,
label: Digest::MD5.hexdigest(member.to_global_id.to_s)
diff --git a/app/controllers/jira_connect/application_controller.rb b/app/controllers/jira_connect/application_controller.rb
index a84f25998a6..9c311f92b69 100644
--- a/app/controllers/jira_connect/application_controller.rb
+++ b/app/controllers/jira_connect/application_controller.rb
@@ -7,6 +7,8 @@ class JiraConnect::ApplicationController < ApplicationController
skip_before_action :verify_authenticity_token
before_action :verify_atlassian_jwt!
+ feature_category :integrations
+
attr_reader :current_jira_installation
private
diff --git a/app/controllers/jira_connect/events_controller.rb b/app/controllers/jira_connect/events_controller.rb
index 8f79c82d847..d833491b8f7 100644
--- a/app/controllers/jira_connect/events_controller.rb
+++ b/app/controllers/jira_connect/events_controller.rb
@@ -1,10 +1,14 @@
# frozen_string_literal: true
class JiraConnect::EventsController < JiraConnect::ApplicationController
+ # See https://developer.atlassian.com/cloud/jira/software/app-descriptor/#lifecycle
+
skip_before_action :verify_atlassian_jwt!, only: :installed
before_action :verify_qsh_claim!, only: :uninstalled
def installed
+ return head :ok if atlassian_jwt_valid?
+
installation = JiraConnectInstallation.new(install_params)
if installation.save
diff --git a/app/controllers/jira_connect/users_controller.rb b/app/controllers/jira_connect/users_controller.rb
new file mode 100644
index 00000000000..571d9f87779
--- /dev/null
+++ b/app/controllers/jira_connect/users_controller.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+class JiraConnect::UsersController < ApplicationController
+ feature_category :integrations
+
+ layout 'devise_experimental_onboarding_issues'
+
+ def show
+ @jira_app_link = params.delete(:return_to)
+ end
+end
diff --git a/app/controllers/jwt_controller.rb b/app/controllers/jwt_controller.rb
index 3e7755046cd..5199bb25c8c 100644
--- a/app/controllers/jwt_controller.rb
+++ b/app/controllers/jwt_controller.rb
@@ -8,6 +8,8 @@ class JwtController < ApplicationController
# Add this before other actions, since we want to have the user or project
prepend_before_action :auth_user, :authenticate_project_or_user
+ feature_category :authentication_and_authorization
+
SERVICES = {
Auth::ContainerRegistryAuthenticationService::AUDIENCE => Auth::ContainerRegistryAuthenticationService
}.freeze
diff --git a/app/controllers/notification_settings_controller.rb b/app/controllers/notification_settings_controller.rb
index e5d4a4bb073..7d8c035c852 100644
--- a/app/controllers/notification_settings_controller.rb
+++ b/app/controllers/notification_settings_controller.rb
@@ -3,6 +3,8 @@
class NotificationSettingsController < ApplicationController
before_action :authenticate_user!
+ feature_category :users
+
def create
return render_404 unless can_read?(resource)
diff --git a/app/controllers/oauth/jira/authorizations_controller.rb b/app/controllers/oauth/jira/authorizations_controller.rb
index f552b0dc10c..f23149c8544 100644
--- a/app/controllers/oauth/jira/authorizations_controller.rb
+++ b/app/controllers/oauth/jira/authorizations_controller.rb
@@ -8,6 +8,8 @@ class Oauth::Jira::AuthorizationsController < ApplicationController
skip_before_action :authenticate_user!
skip_before_action :verify_authenticity_token
+ feature_category :integrations
+
# 1. Rewire Jira OAuth initial request to our stablished OAuth authorization URL.
def new
session[:redirect_uri] = params['redirect_uri']
diff --git a/app/controllers/omniauth_callbacks_controller.rb b/app/controllers/omniauth_callbacks_controller.rb
index b798d6680bc..c9791703413 100644
--- a/app/controllers/omniauth_callbacks_controller.rb
+++ b/app/controllers/omniauth_callbacks_controller.rb
@@ -1,8 +1,7 @@
# frozen_string_literal: true
class OmniauthCallbacksController < Devise::OmniauthCallbacksController
- include AuthenticatesWithTwoFactor
- include Authenticates2FAForAdminMode
+ include AuthenticatesWithTwoFactorForAdminMode
include Devise::Controllers::Rememberable
include AuthHelper
include InitializesCurrentUserMode
@@ -12,6 +11,8 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
protect_from_forgery except: [:kerberos, :saml, :cas3, :failure], with: :exception, prepend: true
+ feature_category :authentication_and_authorization
+
def handle_omniauth
omniauth_flow(Gitlab::Auth::OAuth)
end
diff --git a/app/controllers/passwords_controller.rb b/app/controllers/passwords_controller.rb
index c27226c3f3f..bc6975f8953 100644
--- a/app/controllers/passwords_controller.rb
+++ b/app/controllers/passwords_controller.rb
@@ -7,6 +7,8 @@ class PasswordsController < Devise::PasswordsController
before_action :check_password_authentication_available, only: [:create]
before_action :throttle_reset, only: [:create]
+ feature_category :authentication_and_authorization
+
# rubocop: disable CodeReuse/ActiveRecord
def edit
super
diff --git a/app/controllers/profiles/accounts_controller.rb b/app/controllers/profiles/accounts_controller.rb
index b19285e98bb..d8419be9f23 100644
--- a/app/controllers/profiles/accounts_controller.rb
+++ b/app/controllers/profiles/accounts_controller.rb
@@ -3,6 +3,8 @@
class Profiles::AccountsController < Profiles::ApplicationController
include AuthHelper
+ feature_category :users
+
def show
render(locals: show_view_variables)
end
diff --git a/app/controllers/profiles/active_sessions_controller.rb b/app/controllers/profiles/active_sessions_controller.rb
index e4cd5d65e1a..1233c906406 100644
--- a/app/controllers/profiles/active_sessions_controller.rb
+++ b/app/controllers/profiles/active_sessions_controller.rb
@@ -1,6 +1,8 @@
# frozen_string_literal: true
class Profiles::ActiveSessionsController < Profiles::ApplicationController
+ feature_category :users
+
def index
@sessions = ActiveSession.list(current_user).reject(&:is_impersonated)
end
diff --git a/app/controllers/profiles/avatars_controller.rb b/app/controllers/profiles/avatars_controller.rb
index 3378a09628c..d9e4b9a149d 100644
--- a/app/controllers/profiles/avatars_controller.rb
+++ b/app/controllers/profiles/avatars_controller.rb
@@ -1,6 +1,8 @@
# frozen_string_literal: true
class Profiles::AvatarsController < Profiles::ApplicationController
+ feature_category :users
+
def destroy
@user = current_user
diff --git a/app/controllers/profiles/chat_names_controller.rb b/app/controllers/profiles/chat_names_controller.rb
index 80b8279e91e..8cfec247b7a 100644
--- a/app/controllers/profiles/chat_names_controller.rb
+++ b/app/controllers/profiles/chat_names_controller.rb
@@ -4,6 +4,8 @@ class Profiles::ChatNamesController < Profiles::ApplicationController
before_action :chat_name_token, only: [:new]
before_action :chat_name_params, only: [:new, :create, :deny]
+ feature_category :users
+
def index
@chat_names = current_user.chat_names
end
diff --git a/app/controllers/profiles/emails_controller.rb b/app/controllers/profiles/emails_controller.rb
index da553e34ef6..6e5b18cb885 100644
--- a/app/controllers/profiles/emails_controller.rb
+++ b/app/controllers/profiles/emails_controller.rb
@@ -5,6 +5,8 @@ class Profiles::EmailsController < Profiles::ApplicationController
before_action -> { rate_limit!(:profile_add_new_email) }, only: [:create]
before_action -> { rate_limit!(:profile_resend_email_confirmation) }, only: [:resend_confirmation_instructions]
+ feature_category :users
+
def index
@primary_email = current_user.email
@emails = current_user.emails.order_id_desc
diff --git a/app/controllers/profiles/gpg_keys_controller.rb b/app/controllers/profiles/gpg_keys_controller.rb
index 8c34a66c374..7f04927f517 100644
--- a/app/controllers/profiles/gpg_keys_controller.rb
+++ b/app/controllers/profiles/gpg_keys_controller.rb
@@ -3,6 +3,8 @@
class Profiles::GpgKeysController < Profiles::ApplicationController
before_action :set_gpg_key, only: [:destroy, :revoke]
+ feature_category :users
+
def index
@gpg_keys = current_user.gpg_keys.with_subkeys
@gpg_key = GpgKey.new
diff --git a/app/controllers/profiles/groups_controller.rb b/app/controllers/profiles/groups_controller.rb
index 04b5ee270dc..e76ee0a6cea 100644
--- a/app/controllers/profiles/groups_controller.rb
+++ b/app/controllers/profiles/groups_controller.rb
@@ -3,6 +3,8 @@
class Profiles::GroupsController < Profiles::ApplicationController
include RoutableActions
+ feature_category :users
+
def update
group = find_routable!(Group, params[:id])
notification_setting = current_user.notification_settings_for(group)
diff --git a/app/controllers/profiles/keys_controller.rb b/app/controllers/profiles/keys_controller.rb
index 965493955ac..1e6340f285e 100644
--- a/app/controllers/profiles/keys_controller.rb
+++ b/app/controllers/profiles/keys_controller.rb
@@ -3,6 +3,8 @@
class Profiles::KeysController < Profiles::ApplicationController
skip_before_action :authenticate_user!, only: [:get_keys]
+ feature_category :users
+
def index
@keys = current_user.keys.order_id_desc
@key = Key.new
diff --git a/app/controllers/profiles/notifications_controller.rb b/app/controllers/profiles/notifications_controller.rb
index bc51830c119..a3e7638cdbc 100644
--- a/app/controllers/profiles/notifications_controller.rb
+++ b/app/controllers/profiles/notifications_controller.rb
@@ -1,6 +1,8 @@
# frozen_string_literal: true
class Profiles::NotificationsController < Profiles::ApplicationController
+ feature_category :users
+
# rubocop: disable CodeReuse/ActiveRecord
def show
@user = current_user
diff --git a/app/controllers/profiles/passwords_controller.rb b/app/controllers/profiles/passwords_controller.rb
index fccbc29f598..85e901eb3eb 100644
--- a/app/controllers/profiles/passwords_controller.rb
+++ b/app/controllers/profiles/passwords_controller.rb
@@ -9,6 +9,8 @@ class Profiles::PasswordsController < Profiles::ApplicationController
layout :determine_layout
+ feature_category :authentication_and_authorization
+
def new
end
diff --git a/app/controllers/profiles/personal_access_tokens_controller.rb b/app/controllers/profiles/personal_access_tokens_controller.rb
index 21adc032940..b005347c43a 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
+ feature_category :authentication_and_authorization
+
def index
set_index_vars
@personal_access_token = finder.build
diff --git a/app/controllers/profiles/preferences_controller.rb b/app/controllers/profiles/preferences_controller.rb
index ea4d3e861be..4d88491e9a8 100644
--- a/app/controllers/profiles/preferences_controller.rb
+++ b/app/controllers/profiles/preferences_controller.rb
@@ -3,6 +3,8 @@
class Profiles::PreferencesController < Profiles::ApplicationController
before_action :user
+ feature_category :users
+
def show
end
diff --git a/app/controllers/profiles/two_factor_auths_controller.rb b/app/controllers/profiles/two_factor_auths_controller.rb
index 5de6d84fdd9..e2f8baa8226 100644
--- a/app/controllers/profiles/two_factor_auths_controller.rb
+++ b/app/controllers/profiles/two_factor_auths_controller.rb
@@ -6,6 +6,8 @@ class Profiles::TwoFactorAuthsController < Profiles::ApplicationController
push_frontend_feature_flag(:webauthn)
end
+ feature_category :authentication_and_authorization
+
def show
unless current_user.two_factor_enabled?
current_user.otp_secret = User.generate_otp_secret(32)
@@ -45,7 +47,10 @@ class Profiles::TwoFactorAuthsController < Profiles::ApplicationController
end
def create
- if current_user.validate_and_consume_otp!(params[:pin_code])
+ otp_validation_result =
+ ::Users::ValidateOtpService.new(current_user).execute(params[:pin_code])
+
+ if otp_validation_result[:status] == :success
ActiveSession.destroy_all_but_current(current_user, session)
Users::UpdateService.new(current_user, user: current_user, otp_required_for_login: true).execute! do |user|
diff --git a/app/controllers/profiles/u2f_registrations_controller.rb b/app/controllers/profiles/u2f_registrations_controller.rb
index 84ce4a56e64..32ca303e722 100644
--- a/app/controllers/profiles/u2f_registrations_controller.rb
+++ b/app/controllers/profiles/u2f_registrations_controller.rb
@@ -1,6 +1,8 @@
# frozen_string_literal: true
class Profiles::U2fRegistrationsController < Profiles::ApplicationController
+ feature_category :authentication_and_authorization
+
def destroy
u2f_registration = current_user.u2f_registrations.find(params[:id])
u2f_registration.destroy
diff --git a/app/controllers/profiles/webauthn_registrations_controller.rb b/app/controllers/profiles/webauthn_registrations_controller.rb
index 81b1dd6f710..a4a6d84f1ae 100644
--- a/app/controllers/profiles/webauthn_registrations_controller.rb
+++ b/app/controllers/profiles/webauthn_registrations_controller.rb
@@ -1,6 +1,8 @@
# frozen_string_literal: true
class Profiles::WebauthnRegistrationsController < Profiles::ApplicationController
+ feature_category :authentication_and_authorization
+
def destroy
webauthn_registration = current_user.webauthn_registrations.find(params[:id])
webauthn_registration.destroy
diff --git a/app/controllers/profiles_controller.rb b/app/controllers/profiles_controller.rb
index 248d5755d92..c85c83688a4 100644
--- a/app/controllers/profiles_controller.rb
+++ b/app/controllers/profiles_controller.rb
@@ -2,6 +2,7 @@
class ProfilesController < Profiles::ApplicationController
include ActionView::Helpers::SanitizeHelper
+ include Gitlab::Tracking
before_action :user
before_action :authorize_change_username!, only: :update_username
@@ -10,6 +11,8 @@ class ProfilesController < Profiles::ApplicationController
push_frontend_feature_flag(:webauthn)
end
+ feature_category :users
+
def show
end
@@ -63,6 +66,8 @@ class ProfilesController < Profiles::ApplicationController
@events = AuditEvent.where(entity_type: "User", entity_id: current_user.id)
.order("created_at DESC")
.page(params[:page])
+
+ Gitlab::Tracking.event(self.class.name, 'search_audit_event')
end
# rubocop: enable CodeReuse/ActiveRecord
diff --git a/app/controllers/projects/alert_management_controller.rb b/app/controllers/projects/alert_management_controller.rb
index 054dc8e6a35..0d0ef9b05cb 100644
--- a/app/controllers/projects/alert_management_controller.rb
+++ b/app/controllers/projects/alert_management_controller.rb
@@ -3,10 +3,13 @@
class Projects::AlertManagementController < Projects::ApplicationController
before_action :authorize_read_alert_management_alert!
+ feature_category :alert_management
+
def index
end
def details
@alert_id = params[:id]
+ push_frontend_feature_flag(:expose_environment_path_in_alert_details, @project)
end
end
diff --git a/app/controllers/projects/alerting/notifications_controller.rb b/app/controllers/projects/alerting/notifications_controller.rb
index fef8235628d..2241ded2db8 100644
--- a/app/controllers/projects/alerting/notifications_controller.rb
+++ b/app/controllers/projects/alerting/notifications_controller.rb
@@ -10,6 +10,8 @@ module Projects
prepend_before_action :repository, :project_without_auth
+ feature_category :alert_management
+
def create
token = extract_alert_manager_token(request)
result = notify_service.execute(token)
diff --git a/app/controllers/projects/artifacts_controller.rb b/app/controllers/projects/artifacts_controller.rb
index 652687932fd..f6a92b07295 100644
--- a/app/controllers/projects/artifacts_controller.rb
+++ b/app/controllers/projects/artifacts_controller.rb
@@ -15,6 +15,8 @@ class Projects::ArtifactsController < Projects::ApplicationController
MAX_PER_PAGE = 20
+ feature_category :continuous_integration
+
def index
# Loading artifacts is very expensive in projects with a lot of artifacts.
# This feature flag prevents a DOS attack vector.
diff --git a/app/controllers/projects/autocomplete_sources_controller.rb b/app/controllers/projects/autocomplete_sources_controller.rb
index 605d70d440b..e9c533daa80 100644
--- a/app/controllers/projects/autocomplete_sources_controller.rb
+++ b/app/controllers/projects/autocomplete_sources_controller.rb
@@ -3,6 +3,11 @@
class Projects::AutocompleteSourcesController < Projects::ApplicationController
before_action :authorize_read_milestone!, only: :milestones
+ feature_category :issue_tracking, [:issues, :labels, :milestones, :commands]
+ feature_category :code_review, [:merge_requests]
+ feature_category :users, [:members]
+ feature_category :snippets, [:snippets]
+
def members
render json: ::Projects::ParticipantsService.new(@project, current_user).execute(target)
end
diff --git a/app/controllers/projects/avatars_controller.rb b/app/controllers/projects/avatars_controller.rb
index 6e6bf09a32a..f228206032d 100644
--- a/app/controllers/projects/avatars_controller.rb
+++ b/app/controllers/projects/avatars_controller.rb
@@ -5,6 +5,8 @@ class Projects::AvatarsController < Projects::ApplicationController
before_action :authorize_admin_project!, only: [:destroy]
+ feature_category :projects
+
def show
@blob = @repository.blob_at_branch(@repository.root_ref, @project.avatar_in_git)
diff --git a/app/controllers/projects/badges_controller.rb b/app/controllers/projects/badges_controller.rb
index eb47fec2b7e..855965ca6e1 100644
--- a/app/controllers/projects/badges_controller.rb
+++ b/app/controllers/projects/badges_controller.rb
@@ -6,6 +6,8 @@ class Projects::BadgesController < Projects::ApplicationController
before_action :no_cache_headers, only: [:pipeline, :coverage]
before_action :authorize_read_build!, only: [:pipeline, :coverage]
+ feature_category :continuous_integration
+
def pipeline
pipeline_status = Gitlab::Badge::Pipeline::Status
.new(project, params[:ref], opts: {
diff --git a/app/controllers/projects/blame_controller.rb b/app/controllers/projects/blame_controller.rb
index 374b4921dbc..d5de0d38152 100644
--- a/app/controllers/projects/blame_controller.rb
+++ b/app/controllers/projects/blame_controller.rb
@@ -9,6 +9,8 @@ class Projects::BlameController < Projects::ApplicationController
before_action :assign_ref_vars
before_action :authorize_download_code!
+ feature_category :source_code_management
+
def show
@blob = @repository.blob_at(@commit.id, @path)
diff --git a/app/controllers/projects/blob_controller.rb b/app/controllers/projects/blob_controller.rb
index 1568d9966dd..c6251d27b05 100644
--- a/app/controllers/projects/blob_controller.rb
+++ b/app/controllers/projects/blob_controller.rb
@@ -33,13 +33,14 @@ class Projects::BlobController < Projects::ApplicationController
before_action :set_last_commit_sha, only: [:edit, :update]
before_action only: :show do
- push_frontend_feature_flag(:code_navigation, @project, default_enabled: true)
- push_frontend_feature_flag(:suggest_pipeline) if experiment_enabled?(:suggest_pipeline)
+ push_frontend_experiment(:suggest_pipeline)
push_frontend_feature_flag(:gitlab_ci_yml_preview, @project, default_enabled: false)
end
track_redis_hll_event :create, :update, name: 'g_edit_by_sfe', feature: :track_editor_edit_actions, feature_default_enabled: true
+ feature_category :source_code_management
+
def new
commit unless @repository.empty?
end
diff --git a/app/controllers/projects/boards_controller.rb b/app/controllers/projects/boards_controller.rb
index 5ed35094476..193352ffa70 100644
--- a/app/controllers/projects/boards_controller.rb
+++ b/app/controllers/projects/boards_controller.rb
@@ -12,6 +12,8 @@ class Projects::BoardsController < Projects::ApplicationController
push_frontend_feature_flag(:boards_with_swimlanes, project, default_enabled: false)
end
+ feature_category :boards
+
private
def assign_endpoint_vars
diff --git a/app/controllers/projects/branches_controller.rb b/app/controllers/projects/branches_controller.rb
index 7cfb4a508da..9124728ee25 100644
--- a/app/controllers/projects/branches_controller.rb
+++ b/app/controllers/projects/branches_controller.rb
@@ -13,6 +13,8 @@ class Projects::BranchesController < Projects::ApplicationController
before_action :redirect_for_legacy_index_sort_or_search, only: [:index]
before_action :limit_diverging_commit_counts!, only: [:diverging_commit_counts]
+ feature_category :source_code_management
+
def index
respond_to do |format|
format.html do
diff --git a/app/controllers/projects/build_artifacts_controller.rb b/app/controllers/projects/build_artifacts_controller.rb
index 99f4524eec5..148080a71f4 100644
--- a/app/controllers/projects/build_artifacts_controller.rb
+++ b/app/controllers/projects/build_artifacts_controller.rb
@@ -8,6 +8,8 @@ class Projects::BuildArtifactsController < Projects::ApplicationController
before_action :extract_ref_name_and_path
before_action :validate_artifacts!, except: [:download]
+ feature_category :continuous_integration
+
def download
redirect_to download_project_job_artifacts_path(project, job, params: request.query_parameters)
end
diff --git a/app/controllers/projects/builds_controller.rb b/app/controllers/projects/builds_controller.rb
index 6b3d70cb720..c5f6ed1c105 100644
--- a/app/controllers/projects/builds_controller.rb
+++ b/app/controllers/projects/builds_controller.rb
@@ -3,6 +3,8 @@
class Projects::BuildsController < Projects::ApplicationController
before_action :authorize_read_build!
+ feature_category :continuous_integration
+
def index
redirect_to project_jobs_path(project)
end
diff --git a/app/controllers/projects/ci/daily_build_group_report_results_controller.rb b/app/controllers/projects/ci/daily_build_group_report_results_controller.rb
index b36c5f1aea6..d05ab1b4977 100644
--- a/app/controllers/projects/ci/daily_build_group_report_results_controller.rb
+++ b/app/controllers/projects/ci/daily_build_group_report_results_controller.rb
@@ -6,10 +6,11 @@ class Projects::Ci::DailyBuildGroupReportResultsController < Projects::Applicati
MAX_ITEMS = 1000
REPORT_WINDOW = 90.days
- before_action :validate_feature_flag!
before_action :authorize_read_build_report_results!
before_action :validate_param_type!
+ feature_category :continuous_integration
+
def index
respond_to do |format|
format.csv { send_data(render_csv(report_results), type: 'text/csv; charset=utf-8') }
@@ -19,10 +20,6 @@ class Projects::Ci::DailyBuildGroupReportResultsController < Projects::Applicati
private
- def validate_feature_flag!
- render_404 unless Feature.enabled?(:ci_download_daily_code_coverage, project, default_enabled: true)
- end
-
def validate_param_type!
respond_422 unless allowed_param_types.include?(param_type)
end
@@ -43,7 +40,7 @@ class Projects::Ci::DailyBuildGroupReportResultsController < Projects::Applicati
end
def report_results
- Ci::DailyBuildGroupReportResultsFinder.new(finder_params).execute
+ Ci::DailyBuildGroupReportResultsFinder.new(**finder_params).execute
end
def finder_params
diff --git a/app/controllers/projects/ci/lints_controller.rb b/app/controllers/projects/ci/lints_controller.rb
index 813a0a9ddd5..7e900fc6051 100644
--- a/app/controllers/projects/ci/lints_controller.rb
+++ b/app/controllers/projects/ci/lints_controller.rb
@@ -6,6 +6,8 @@ class Projects::Ci::LintsController < Projects::ApplicationController
push_frontend_feature_flag(:ci_lint_vue, project)
end
+ feature_category :pipeline_authoring
+
def show
end
diff --git a/app/controllers/projects/commit_controller.rb b/app/controllers/projects/commit_controller.rb
index b0c6f3cc6a1..2e48f2f0e45 100644
--- a/app/controllers/projects/commit_controller.rb
+++ b/app/controllers/projects/commit_controller.rb
@@ -21,6 +21,8 @@ class Projects::CommitController < Projects::ApplicationController
BRANCH_SEARCH_LIMIT = 1000
+ feature_category :source_code_management
+
def show
apply_diff_view_cookie!
diff --git a/app/controllers/projects/commits_controller.rb b/app/controllers/projects/commits_controller.rb
index b161e44660e..d267ab732f9 100644
--- a/app/controllers/projects/commits_controller.rb
+++ b/app/controllers/projects/commits_controller.rb
@@ -15,6 +15,8 @@ class Projects::CommitsController < Projects::ApplicationController
before_action :validate_ref!, except: :commits_root
before_action :set_commits, except: :commits_root
+ feature_category :source_code_management
+
def commits_root
redirect_to project_commits_path(@project, @project.default_branch)
end
diff --git a/app/controllers/projects/compare_controller.rb b/app/controllers/projects/compare_controller.rb
index 943277afe95..6be0b465402 100644
--- a/app/controllers/projects/compare_controller.rb
+++ b/app/controllers/projects/compare_controller.rb
@@ -19,6 +19,8 @@ class Projects::CompareController < Projects::ApplicationController
# Validation
before_action :validate_refs!
+ feature_category :source_code_management
+
def index
end
diff --git a/app/controllers/projects/confluences_controller.rb b/app/controllers/projects/confluences_controller.rb
index d563b34a362..fccbdf0bf91 100644
--- a/app/controllers/projects/confluences_controller.rb
+++ b/app/controllers/projects/confluences_controller.rb
@@ -3,6 +3,8 @@
class Projects::ConfluencesController < Projects::ApplicationController
before_action :ensure_confluence
+ feature_category :integrations
+
def show
end
diff --git a/app/controllers/projects/cycle_analytics/events_controller.rb b/app/controllers/projects/cycle_analytics/events_controller.rb
index c69bf029c73..3a5dd23047c 100644
--- a/app/controllers/projects/cycle_analytics/events_controller.rb
+++ b/app/controllers/projects/cycle_analytics/events_controller.rb
@@ -11,6 +11,8 @@ module Projects
before_action :authorize_read_issue!, only: [:issue, :production]
before_action :authorize_read_merge_request!, only: [:code, :review]
+ feature_category :planning_analytics
+
def issue
render_events(cycle_analytics[:issue].events)
end
diff --git a/app/controllers/projects/cycle_analytics_controller.rb b/app/controllers/projects/cycle_analytics_controller.rb
index ef97bc795f9..1ddc9d567e0 100644
--- a/app/controllers/projects/cycle_analytics_controller.rb
+++ b/app/controllers/projects/cycle_analytics_controller.rb
@@ -12,6 +12,8 @@ class Projects::CycleAnalyticsController < Projects::ApplicationController
track_unique_visits :show, target_id: 'p_analytics_valuestream'
+ feature_category :planning_analytics
+
def show
@cycle_analytics = ::CycleAnalytics::ProjectLevel.new(@project, options: options(cycle_analytics_project_params))
diff --git a/app/controllers/projects/deploy_keys_controller.rb b/app/controllers/projects/deploy_keys_controller.rb
index 4f4adaea56e..ce25f86d692 100644
--- a/app/controllers/projects/deploy_keys_controller.rb
+++ b/app/controllers/projects/deploy_keys_controller.rb
@@ -10,6 +10,8 @@ class Projects::DeployKeysController < Projects::ApplicationController
layout 'project_settings'
+ feature_category :continuous_delivery
+
def index
respond_to do |format|
format.html { redirect_to_repository }
diff --git a/app/controllers/projects/deploy_tokens_controller.rb b/app/controllers/projects/deploy_tokens_controller.rb
index 830b1f4fe4a..3c890bbafdf 100644
--- a/app/controllers/projects/deploy_tokens_controller.rb
+++ b/app/controllers/projects/deploy_tokens_controller.rb
@@ -3,6 +3,8 @@
class Projects::DeployTokensController < Projects::ApplicationController
before_action :authorize_admin_project!
+ feature_category :continuous_delivery
+
def revoke
@token = @project.deploy_tokens.find(params[:id])
@token.revoke!
diff --git a/app/controllers/projects/deployments_controller.rb b/app/controllers/projects/deployments_controller.rb
index 1344cf775e4..231684427fb 100644
--- a/app/controllers/projects/deployments_controller.rb
+++ b/app/controllers/projects/deployments_controller.rb
@@ -3,6 +3,8 @@
class Projects::DeploymentsController < Projects::ApplicationController
before_action :authorize_read_deployment!
+ feature_category :continuous_delivery
+
# rubocop: disable CodeReuse/ActiveRecord
def index
deployments = environment.deployments.reorder(created_at: :desc)
diff --git a/app/controllers/projects/design_management/designs_controller.rb b/app/controllers/projects/design_management/designs_controller.rb
index fec09fa9515..550d8578396 100644
--- a/app/controllers/projects/design_management/designs_controller.rb
+++ b/app/controllers/projects/design_management/designs_controller.rb
@@ -3,6 +3,8 @@
class Projects::DesignManagement::DesignsController < Projects::ApplicationController
before_action :authorize_read_design!
+ feature_category :design_management
+
private
def authorize_read_design!
diff --git a/app/controllers/projects/discussions_controller.rb b/app/controllers/projects/discussions_controller.rb
index 06231607f73..b9ab1076999 100644
--- a/app/controllers/projects/discussions_controller.rb
+++ b/app/controllers/projects/discussions_controller.rb
@@ -9,6 +9,8 @@ class Projects::DiscussionsController < Projects::ApplicationController
before_action :discussion, only: [:resolve, :unresolve]
before_action :authorize_resolve_discussion!, only: [:resolve, :unresolve]
+ feature_category :issue_tracking
+
def resolve
Discussions::ResolveService.new(project, current_user, one_or_more_discussions: discussion).execute
diff --git a/app/controllers/projects/environments/prometheus_api_controller.rb b/app/controllers/projects/environments/prometheus_api_controller.rb
index f0bb5360f84..97810d7d439 100644
--- a/app/controllers/projects/environments/prometheus_api_controller.rb
+++ b/app/controllers/projects/environments/prometheus_api_controller.rb
@@ -5,6 +5,8 @@ class Projects::Environments::PrometheusApiController < Projects::ApplicationCon
before_action :proxyable
+ feature_category :metrics
+
private
def proxyable
diff --git a/app/controllers/projects/environments/sample_metrics_controller.rb b/app/controllers/projects/environments/sample_metrics_controller.rb
index 9176c7cbd56..3df20810cb3 100644
--- a/app/controllers/projects/environments/sample_metrics_controller.rb
+++ b/app/controllers/projects/environments/sample_metrics_controller.rb
@@ -1,6 +1,8 @@
# frozen_string_literal: true
class Projects::Environments::SampleMetricsController < Projects::ApplicationController
+ feature_category :metrics
+
def query
result = Metrics::SampleMetricsService.new(params[:identifier], range_start: params[:start], range_end: params[:end]).query
diff --git a/app/controllers/projects/environments_controller.rb b/app/controllers/projects/environments_controller.rb
index 71195fdb892..c37abf82fe9 100644
--- a/app/controllers/projects/environments_controller.rb
+++ b/app/controllers/projects/environments_controller.rb
@@ -25,6 +25,8 @@ class Projects::EnvironmentsController < Projects::ApplicationController
before_action :expire_etag_cache, only: [:index], unless: -> { request.format.json? }
after_action :expire_etag_cache, only: [:cancel_auto_stop]
+ feature_category :continuous_delivery
+
def index
@environments = project.environments
.with_state(params[:scope] || :available)
diff --git a/app/controllers/projects/error_tracking/base_controller.rb b/app/controllers/projects/error_tracking/base_controller.rb
index 6efc6d00702..ffbe487d8a1 100644
--- a/app/controllers/projects/error_tracking/base_controller.rb
+++ b/app/controllers/projects/error_tracking/base_controller.rb
@@ -3,6 +3,8 @@
class Projects::ErrorTracking::BaseController < Projects::ApplicationController
POLLING_INTERVAL = 1_000
+ feature_category :error_tracking
+
def set_polling_interval
Gitlab::PollingInterval.set_header(response, interval: POLLING_INTERVAL)
end
diff --git a/app/controllers/projects/error_tracking/projects_controller.rb b/app/controllers/projects/error_tracking/projects_controller.rb
index 75a2c976d8b..d59cbc25d25 100644
--- a/app/controllers/projects/error_tracking/projects_controller.rb
+++ b/app/controllers/projects/error_tracking/projects_controller.rb
@@ -7,6 +7,8 @@ module Projects
before_action :authorize_read_sentry_issue!
+ feature_category :error_tracking
+
def index
service = ::ErrorTracking::ListProjectsService.new(
project,
diff --git a/app/controllers/projects/feature_flags_clients_controller.rb b/app/controllers/projects/feature_flags_clients_controller.rb
new file mode 100644
index 00000000000..9a1f8932a27
--- /dev/null
+++ b/app/controllers/projects/feature_flags_clients_controller.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+class Projects::FeatureFlagsClientsController < Projects::ApplicationController
+ before_action :authorize_admin_feature_flags_client!
+ before_action :feature_flags_client
+
+ feature_category :feature_flags
+
+ def reset_token
+ feature_flags_client.reset_token!
+
+ respond_to do |format|
+ format.json do
+ render json: feature_flags_client_token_json, status: :ok
+ end
+ end
+ end
+
+ private
+
+ def feature_flags_client
+ project.operations_feature_flags_client || not_found
+ end
+
+ def feature_flags_client_token_json
+ FeatureFlagsClientSerializer.new
+ .represent_token(feature_flags_client)
+ end
+end
diff --git a/app/controllers/projects/feature_flags_controller.rb b/app/controllers/projects/feature_flags_controller.rb
new file mode 100644
index 00000000000..e9d450a6ce3
--- /dev/null
+++ b/app/controllers/projects/feature_flags_controller.rb
@@ -0,0 +1,174 @@
+# frozen_string_literal: true
+
+class Projects::FeatureFlagsController < Projects::ApplicationController
+ respond_to :html
+
+ before_action :authorize_read_feature_flag!
+ before_action :authorize_create_feature_flag!, only: [:new, :create]
+ before_action :authorize_update_feature_flag!, only: [:edit, :update]
+ before_action :authorize_destroy_feature_flag!, only: [:destroy]
+
+ before_action :feature_flag, only: [:edit, :update, :destroy]
+
+ before_action :ensure_legacy_flags_writable!, only: [:update]
+
+ before_action do
+ push_frontend_feature_flag(:feature_flag_permissions)
+ push_frontend_feature_flag(:feature_flags_new_version, project, default_enabled: true)
+ push_frontend_feature_flag(:feature_flags_legacy_read_only, project, default_enabled: true)
+ push_frontend_feature_flag(:feature_flags_legacy_read_only_override, project)
+ end
+
+ feature_category :feature_flags
+
+ def index
+ @feature_flags = FeatureFlagsFinder
+ .new(project, current_user, scope: params[:scope])
+ .execute
+ .page(params[:page])
+ .per(30)
+
+ respond_to do |format|
+ format.html
+ format.json do
+ Gitlab::PollingInterval.set_header(response, interval: 10_000)
+
+ render json: { feature_flags: feature_flags_json }.merge(summary_json)
+ end
+ end
+ end
+
+ def new
+ end
+
+ def show
+ respond_to do |format|
+ format.json do
+ Gitlab::PollingInterval.set_header(response, interval: 10_000)
+
+ render_success_json(feature_flag)
+ end
+ end
+ end
+
+ def create
+ result = FeatureFlags::CreateService.new(project, current_user, create_params).execute
+
+ if result[:status] == :success
+ respond_to do |format|
+ format.json { render_success_json(result[:feature_flag]) }
+ end
+ else
+ respond_to do |format|
+ format.json { render_error_json(result[:message]) }
+ end
+ end
+ end
+
+ def edit
+ end
+
+ def update
+ result = FeatureFlags::UpdateService.new(project, current_user, update_params).execute(feature_flag)
+
+ if result[:status] == :success
+ respond_to do |format|
+ format.json { render_success_json(result[:feature_flag]) }
+ end
+ else
+ respond_to do |format|
+ format.json { render_error_json(result[:message]) }
+ end
+ end
+ end
+
+ def destroy
+ result = FeatureFlags::DestroyService.new(project, current_user).execute(feature_flag)
+
+ if result[:status] == :success
+ respond_to do |format|
+ format.html { redirect_to_index(notice: _('Feature flag was successfully removed.')) }
+ format.json { render_success_json(feature_flag) }
+ end
+ else
+ respond_to do |format|
+ format.html { redirect_to_index(alert: _('Feature flag was not removed.')) }
+ format.json { render_error_json(result[:message]) }
+ end
+ end
+ end
+
+ protected
+
+ def feature_flag
+ @feature_flag ||= @noteable = if new_version_feature_flags_enabled?
+ project.operations_feature_flags.find_by_iid!(params[:iid])
+ else
+ project.operations_feature_flags.legacy_flag.find_by_iid!(params[:iid])
+ end
+ end
+
+ def new_version_feature_flags_enabled?
+ ::Feature.enabled?(:feature_flags_new_version, project, default_enabled: true)
+ end
+
+ def ensure_legacy_flags_writable!
+ if ::Feature.enabled?(:feature_flags_legacy_read_only, project, default_enabled: true) &&
+ ::Feature.disabled?(:feature_flags_legacy_read_only_override, project) &&
+ feature_flag.legacy_flag?
+ render_error_json(['Legacy feature flags are read-only'])
+ end
+ end
+
+ def create_params
+ params.require(:operations_feature_flag)
+ .permit(:name, :description, :active, :version,
+ scopes_attributes: [:environment_scope, :active,
+ strategies: [:name, parameters: [:groupId, :percentage, :userIds]]],
+ strategies_attributes: [:name, :user_list_id,
+ parameters: [:groupId, :percentage, :userIds, :rollout, :stickiness],
+ scopes_attributes: [:environment_scope]])
+ end
+
+ def update_params
+ params.require(:operations_feature_flag)
+ .permit(:name, :description, :active,
+ scopes_attributes: [:id, :environment_scope, :active, :_destroy,
+ strategies: [:name, parameters: [:groupId, :percentage, :userIds]]],
+ strategies_attributes: [:id, :name, :user_list_id, :_destroy,
+ parameters: [:groupId, :percentage, :userIds, :rollout, :stickiness],
+ scopes_attributes: [:id, :environment_scope, :_destroy]])
+ end
+
+ def feature_flag_json(feature_flag)
+ FeatureFlagSerializer
+ .new(project: @project, current_user: @current_user)
+ .represent(feature_flag)
+ end
+
+ def feature_flags_json
+ FeatureFlagSerializer
+ .new(project: @project, current_user: @current_user)
+ .with_pagination(request, response)
+ .represent(@feature_flags)
+ end
+
+ def summary_json
+ FeatureFlagSummarySerializer
+ .new(project: @project, current_user: @current_user)
+ .represent(@project)
+ end
+
+ def redirect_to_index(**args)
+ redirect_to project_feature_flags_path(@project), status: :found, **args
+ end
+
+ def render_success_json(feature_flag)
+ render json: feature_flag_json(feature_flag), status: :ok
+ end
+
+ def render_error_json(messages)
+ render json: { message: messages },
+ status: :bad_request
+ end
+end
diff --git a/app/controllers/projects/feature_flags_user_lists_controller.rb b/app/controllers/projects/feature_flags_user_lists_controller.rb
new file mode 100644
index 00000000000..7be3254e966
--- /dev/null
+++ b/app/controllers/projects/feature_flags_user_lists_controller.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+class Projects::FeatureFlagsUserListsController < Projects::ApplicationController
+ before_action :authorize_admin_feature_flags_user_lists!
+ before_action :user_list, only: [:edit, :show]
+
+ feature_category :feature_flags
+
+ def new
+ end
+
+ def edit
+ end
+
+ def show
+ end
+
+ private
+
+ def user_list
+ @user_list = project.operations_feature_flags_user_lists.find_by_iid!(params[:iid])
+ end
+end
diff --git a/app/controllers/projects/find_file_controller.rb b/app/controllers/projects/find_file_controller.rb
index c026e9ff332..89e72d98a33 100644
--- a/app/controllers/projects/find_file_controller.rb
+++ b/app/controllers/projects/find_file_controller.rb
@@ -10,6 +10,8 @@ class Projects::FindFileController < Projects::ApplicationController
before_action :assign_ref_vars
before_action :authorize_download_code!
+ feature_category :source_code_management
+
def show
return render_404 unless @repository.commit(@ref)
diff --git a/app/controllers/projects/forks_controller.rb b/app/controllers/projects/forks_controller.rb
index c6b6b825bb7..1c2930f6e9b 100644
--- a/app/controllers/projects/forks_controller.rb
+++ b/app/controllers/projects/forks_controller.rb
@@ -14,6 +14,8 @@ class Projects::ForksController < Projects::ApplicationController
before_action :authorize_fork_project!, only: [:new, :create]
before_action :authorize_fork_namespace!, only: [:create]
+ feature_category :source_code_management
+
def index
@total_forks_count = project.forks.size
@public_forks_count = project.forks.public_only.size
diff --git a/app/controllers/projects/grafana_api_controller.rb b/app/controllers/projects/grafana_api_controller.rb
index c9870f1be2b..9c5d6c8ebc3 100644
--- a/app/controllers/projects/grafana_api_controller.rb
+++ b/app/controllers/projects/grafana_api_controller.rb
@@ -4,6 +4,8 @@ class Projects::GrafanaApiController < Projects::ApplicationController
include RenderServiceResults
include MetricsDashboard
+ feature_category :metrics
+
def proxy
result = ::Grafana::ProxyService.new(
project,
diff --git a/app/controllers/projects/graphs_controller.rb b/app/controllers/projects/graphs_controller.rb
index 9b889f9e837..2b030793c58 100644
--- a/app/controllers/projects/graphs_controller.rb
+++ b/app/controllers/projects/graphs_controller.rb
@@ -11,6 +11,8 @@ class Projects::GraphsController < Projects::ApplicationController
track_unique_visits :charts, target_id: 'p_analytics_repo'
+ feature_category :source_code_management
+
def show
respond_to do |format|
format.html
@@ -57,7 +59,6 @@ class Projects::GraphsController < Projects::ApplicationController
end
def get_daily_coverage_options
- return unless Feature.enabled?(:ci_download_daily_code_coverage, @project, default_enabled: true)
return unless can?(current_user, :read_build_report_results, project)
date_today = Date.current
diff --git a/app/controllers/projects/group_links_controller.rb b/app/controllers/projects/group_links_controller.rb
index a30c455a7e4..c6c90ffaba2 100644
--- a/app/controllers/projects/group_links_controller.rb
+++ b/app/controllers/projects/group_links_controller.rb
@@ -5,6 +5,8 @@ class Projects::GroupLinksController < Projects::ApplicationController
before_action :authorize_admin_project!
before_action :authorize_admin_project_member!, only: [:update]
+ feature_category :subgroups
+
def create
group = Group.find(params[:link_group_id]) if params[:link_group_id].present?
@@ -21,8 +23,17 @@ class Projects::GroupLinksController < Projects::ApplicationController
end
def update
- @group_link = @project.project_group_links.find(params[:id])
- Projects::GroupLinks::UpdateService.new(@group_link).execute(group_link_params)
+ group_link = @project.project_group_links.find(params[:id])
+ Projects::GroupLinks::UpdateService.new(group_link).execute(group_link_params)
+
+ if group_link.expires?
+ render json: {
+ expires_in: helpers.distance_of_time_in_words_to_now(group_link.expires_at),
+ expires_soon: group_link.expires_soon?
+ }
+ else
+ render json: {}
+ end
end
def destroy
diff --git a/app/controllers/projects/hook_logs_controller.rb b/app/controllers/projects/hook_logs_controller.rb
index ed7e7b68acb..99ebe3335c0 100644
--- a/app/controllers/projects/hook_logs_controller.rb
+++ b/app/controllers/projects/hook_logs_controller.rb
@@ -12,6 +12,8 @@ class Projects::HookLogsController < Projects::ApplicationController
layout 'project_settings'
+ feature_category :integrations
+
def show
end
diff --git a/app/controllers/projects/hooks_controller.rb b/app/controllers/projects/hooks_controller.rb
index 2f4dc1ddc3a..8dabf3e640b 100644
--- a/app/controllers/projects/hooks_controller.rb
+++ b/app/controllers/projects/hooks_controller.rb
@@ -12,6 +12,8 @@ class Projects::HooksController < Projects::ApplicationController
layout "project_settings"
+ feature_category :integrations
+
def index
@hooks = @project.hooks
@hook = ProjectHook.new
@@ -50,7 +52,7 @@ class Projects::HooksController < Projects::ApplicationController
end
def destroy
- hook.destroy
+ destroy_hook(hook)
redirect_to action: :index, status: :found
end
diff --git a/app/controllers/projects/import/jira_controller.rb b/app/controllers/projects/import/jira_controller.rb
index 976ac7df976..8418a607659 100644
--- a/app/controllers/projects/import/jira_controller.rb
+++ b/app/controllers/projects/import/jira_controller.rb
@@ -7,6 +7,8 @@ module Projects
before_action :authorize_read_project!
before_action :validate_jira_import_settings!
+ feature_category :integrations
+
def show
end
diff --git a/app/controllers/projects/imports_controller.rb b/app/controllers/projects/imports_controller.rb
index 9bed12fd151..6cdd1c0bc8c 100644
--- a/app/controllers/projects/imports_controller.rb
+++ b/app/controllers/projects/imports_controller.rb
@@ -11,6 +11,8 @@ class Projects::ImportsController < Projects::ApplicationController
before_action :redirect_if_progress, except: :show
before_action :redirect_if_no_import, only: :show
+ feature_category :importers
+
def new
end
diff --git a/app/controllers/projects/incident_management/pager_duty_incidents_controller.rb b/app/controllers/projects/incident_management/pager_duty_incidents_controller.rb
index dac1640dd08..f1264ca4a45 100644
--- a/app/controllers/projects/incident_management/pager_duty_incidents_controller.rb
+++ b/app/controllers/projects/incident_management/pager_duty_incidents_controller.rb
@@ -10,6 +10,8 @@ module Projects
prepend_before_action :project_without_auth
+ feature_category :incident_management
+
def create
result = webhook_processor.execute(params[:token])
diff --git a/app/controllers/projects/incidents_controller.rb b/app/controllers/projects/incidents_controller.rb
index 12cc4dde1f4..3395e75666e 100644
--- a/app/controllers/projects/incidents_controller.rb
+++ b/app/controllers/projects/incidents_controller.rb
@@ -1,8 +1,45 @@
# frozen_string_literal: true
class Projects::IncidentsController < Projects::ApplicationController
- before_action :authorize_read_incidents!
+ include IssuableActions
+ include Gitlab::Utils::StrongMemoize
+
+ before_action :authorize_read_issue!
+ before_action :load_incident, only: [:show]
+
+ feature_category :incident_management
def index
end
+
+ private
+
+ def incident
+ strong_memoize(:incident) do
+ incident_finder
+ .execute
+ .inc_relations_for_view
+ .iid_in(params[:id])
+ .without_order
+ .first
+ end
+ end
+
+ def load_incident
+ @issue = incident # needed by rendered view
+ return render_404 unless can?(current_user, :read_issue, incident)
+
+ @noteable = incident
+ @note = incident.project.notes.new(noteable: issuable)
+ end
+
+ alias_method :issuable, :incident
+
+ def incident_finder
+ IssuesFinder.new(current_user, project_id: @project.id, issue_types: :incident)
+ end
+
+ def serializer
+ IssueSerializer.new(current_user: current_user, project: incident.project)
+ end
end
diff --git a/app/controllers/projects/issue_links_controller.rb b/app/controllers/projects/issue_links_controller.rb
index 2f7489373ed..35f3e00fae7 100644
--- a/app/controllers/projects/issue_links_controller.rb
+++ b/app/controllers/projects/issue_links_controller.rb
@@ -7,6 +7,8 @@ module Projects
before_action :authorize_admin_issue_link!, only: [:create, :destroy]
before_action :authorize_issue_link_association!, only: :destroy
+ feature_category :issue_tracking
+
private
def authorize_admin_issue_link!
diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb
index 7f0d23b79ce..9a8965dbeb6 100644
--- a/app/controllers/projects/issues_controller.rb
+++ b/app/controllers/projects/issues_controller.rb
@@ -44,8 +44,6 @@ class Projects::IssuesController < Projects::ApplicationController
push_frontend_feature_flag(:vue_issuable_sidebar, project.group)
push_frontend_feature_flag(:tribute_autocomplete, @project)
push_frontend_feature_flag(:vue_issuables_list, project)
- push_frontend_feature_flag(:design_management_todo_button, project, default_enabled: true)
- push_frontend_feature_flag(:vue_sidebar_labels, @project)
end
before_action only: :show do
@@ -53,10 +51,13 @@ class Projects::IssuesController < Projects::ApplicationController
real_time_enabled = Gitlab::ActionCable::Config.in_app? || Feature.enabled?(real_time_feature_flag, @project)
gon.push({ features: { real_time_feature_flag.to_s.camelize(:lower) => real_time_enabled } }, true)
+
+ record_experiment_user(:invite_members_version_a)
+ record_experiment_user(:invite_members_version_b)
end
before_action only: :index do
- push_frontend_feature_flag(:scoped_labels, @project)
+ push_frontend_feature_flag(:scoped_labels, @project, type: :licensed)
end
around_action :allow_gitaly_ref_name_caching, only: [:discussions]
@@ -65,6 +66,17 @@ class Projects::IssuesController < Projects::ApplicationController
alias_method :designs, :show
+ feature_category :issue_tracking, [
+ :index, :calendar, :show, :new, :create, :edit, :update,
+ :destroy, :move, :reorder, :designs, :toggle_subscription,
+ :discussions, :bulk_update, :realtime_changes,
+ :toggle_award_emoji, :mark_as_spam, :related_branches,
+ :can_create_branch, :create_merge_request
+ ]
+
+ feature_category :service_desk, [:service_desk]
+ feature_category :importers, [:import_csv, :export_csv]
+
def index
@issues = @issuables
@@ -204,7 +216,7 @@ class Projects::IssuesController < Projects::ApplicationController
end
def export_csv
- ExportCsvWorker.perform_async(current_user.id, project.id, finder_options.to_h) # rubocop:disable CodeReuse/Worker
+ IssuableExportCsvWorker.perform_async(:issue, current_user.id, project.id, finder_options.to_h) # rubocop:disable CodeReuse/Worker
index_path = project_issues_path(project)
message = _('Your CSV export has started. It will be emailed to %{email} when complete.') % { email: current_user.notification_email }
@@ -239,7 +251,7 @@ class Projects::IssuesController < Projects::ApplicationController
return @issue if defined?(@issue)
# The Sortable default scope causes performance issues when used with find_by
- @issuable = @noteable = @issue ||= @project.issues.includes(author: :status).where(iid: params[:id]).reorder(nil).take!
+ @issuable = @noteable = @issue ||= @project.issues.inc_relations_for_view.iid_in(params[:id]).without_order.take!
@note = @project.notes.new(noteable: @issuable)
return render_404 unless can?(current_user, :read_issue, @issue)
@@ -313,7 +325,7 @@ class Projects::IssuesController < Projects::ApplicationController
end
def store_uri
- if request.get? && !request.xhr?
+ if request.get? && request.format.html?
store_location_for :user, request.fullpath
end
end
diff --git a/app/controllers/projects/jobs_controller.rb b/app/controllers/projects/jobs_controller.rb
index 3f7f8da3478..3ceb60a6aef 100644
--- a/app/controllers/projects/jobs_controller.rb
+++ b/app/controllers/projects/jobs_controller.rb
@@ -4,7 +4,8 @@ class Projects::JobsController < Projects::ApplicationController
include SendFileUpload
include ContinueParams
- before_action :build, except: [:index]
+ before_action :find_job_as_build, except: [:index, :play]
+ before_action :find_job_as_processable, only: [:play]
before_action :authorize_read_build!
before_action :authorize_update_build!,
except: [:index, :show, :status, :raw, :trace, :erase]
@@ -16,6 +17,8 @@ class Projects::JobsController < Projects::ApplicationController
layout 'project'
+ feature_category :continuous_integration
+
def index
# We need all builds for tabs counters
@all_builds = Ci::JobsFinder.new(current_user: current_user, project: @project).execute
@@ -28,11 +31,6 @@ class Projects::JobsController < Projects::ApplicationController
# rubocop: disable CodeReuse/ActiveRecord
def show
- @pipeline = @build.pipeline
- @builds = @pipeline.builds
- .order('id DESC')
- .present(current_user: current_user)
-
respond_to do |format|
format.html
format.json do
@@ -47,10 +45,10 @@ class Projects::JobsController < Projects::ApplicationController
# rubocop: enable CodeReuse/ActiveRecord
def trace
- build.trace.read do |stream|
+ @build.trace.read do |stream|
respond_to do |format|
format.json do
- build.trace.being_watched!
+ @build.trace.being_watched!
build_trace = Ci::BuildTrace.new(
build: @build,
@@ -75,8 +73,13 @@ class Projects::JobsController < Projects::ApplicationController
def play
return respond_422 unless @build.playable?
- build = @build.play(current_user, play_params[:job_variables_attributes])
- redirect_to build_path(build)
+ job = @build.play(current_user, play_params[:job_variables_attributes])
+
+ if job.is_a?(Ci::Bridge)
+ redirect_to pipeline_path(job.pipeline)
+ else
+ redirect_to build_path(job)
+ end
end
def cancel
@@ -120,7 +123,7 @@ class Projects::JobsController < Projects::ApplicationController
send_params: raw_send_params,
redirect_params: raw_redirect_params)
else
- build.trace.read do |stream|
+ @build.trace.read do |stream|
if stream.file?
workhorse_set_content_type!
send_file stream.path, type: 'text/plain; charset=utf-8', disposition: 'inline'
@@ -152,19 +155,19 @@ class Projects::JobsController < Projects::ApplicationController
private
def authorize_update_build!
- return access_denied! unless can?(current_user, :update_build, build)
+ return access_denied! unless can?(current_user, :update_build, @build)
end
def authorize_erase_build!
- return access_denied! unless can?(current_user, :erase_build, build)
+ return access_denied! unless can?(current_user, :erase_build, @build)
end
def authorize_use_build_terminal!
- return access_denied! unless can?(current_user, :create_build_terminal, build)
+ return access_denied! unless can?(current_user, :create_build_terminal, @build)
end
def authorize_create_proxy_build!
- return access_denied! unless can?(current_user, :create_build_service_proxy, build)
+ return access_denied! unless can?(current_user, :create_build_service_proxy, @build)
end
def verify_api_request!
@@ -189,14 +192,22 @@ class Projects::JobsController < Projects::ApplicationController
end
def trace_artifact_file
- @trace_artifact_file ||= build.job_artifacts_trace&.file
+ @trace_artifact_file ||= @build.job_artifacts_trace&.file
end
- def build
- @build ||= project.builds.find(params[:id])
+ def find_job_as_build
+ @build = project.builds.find(params[:id])
.present(current_user: current_user)
end
+ def find_job_as_processable
+ if ::Gitlab::Ci::Features.manual_bridges_enabled?(project)
+ @build = project.processables.find(params[:id])
+ else
+ find_job_as_build
+ end
+ end
+
def build_path(build)
project_job_path(build.project, build)
end
@@ -211,10 +222,10 @@ class Projects::JobsController < Projects::ApplicationController
end
def build_service_specification
- build.service_specification(service: params['service'],
- port: params['port'],
- path: params['path'],
- subprotocols: proxy_subprotocol)
+ @build.service_specification(service: params['service'],
+ port: params['port'],
+ path: params['path'],
+ subprotocols: proxy_subprotocol)
end
def proxy_subprotocol
diff --git a/app/controllers/projects/labels_controller.rb b/app/controllers/projects/labels_controller.rb
index b7aeab8f5ff..ba8e6b90971 100644
--- a/app/controllers/projects/labels_controller.rb
+++ b/app/controllers/projects/labels_controller.rb
@@ -2,6 +2,7 @@
class Projects::LabelsController < Projects::ApplicationController
include ToggleSubscriptionAction
+ include ShowInheritedLabelsChecker
before_action :check_issuables_available!
before_action :label, only: [:edit, :update, :destroy, :promote]
@@ -14,6 +15,8 @@ class Projects::LabelsController < Projects::ApplicationController
respond_to :js, :html
+ feature_category :issue_tracking
+
def index
@prioritized_labels = @available_labels.prioritized(@project)
@labels = @available_labels.unprioritized(@project).page(params[:page])
@@ -161,7 +164,7 @@ class Projects::LabelsController < Projects::ApplicationController
@available_labels ||=
LabelsFinder.new(current_user,
project_id: @project.id,
- include_ancestor_groups: params[:include_ancestor_groups],
+ include_ancestor_groups: show_inherited_labels?(params[:include_ancestor_groups]),
search: params[:search],
subscribed: params[:subscribed],
sort: sort).execute
diff --git a/app/controllers/projects/logs_controller.rb b/app/controllers/projects/logs_controller.rb
index b9027b3a2cb..b9aa9bfc947 100644
--- a/app/controllers/projects/logs_controller.rb
+++ b/app/controllers/projects/logs_controller.rb
@@ -7,6 +7,8 @@ module Projects
before_action :authorize_read_pod_logs!
before_action :ensure_deployments, only: %i(k8s elasticsearch)
+ feature_category :logging
+
def index
if environment || cluster
render :index
diff --git a/app/controllers/projects/mattermosts_controller.rb b/app/controllers/projects/mattermosts_controller.rb
index cfaeddf711a..63a36732d87 100644
--- a/app/controllers/projects/mattermosts_controller.rb
+++ b/app/controllers/projects/mattermosts_controller.rb
@@ -10,6 +10,8 @@ class Projects::MattermostsController < Projects::ApplicationController
before_action :service
before_action :teams, only: [:new]
+ feature_category :integrations
+
def new
end
diff --git a/app/controllers/projects/merge_requests/application_controller.rb b/app/controllers/projects/merge_requests/application_controller.rb
index 921da788ad2..9cac9f37eb7 100644
--- a/app/controllers/projects/merge_requests/application_controller.rb
+++ b/app/controllers/projects/merge_requests/application_controller.rb
@@ -5,6 +5,8 @@ class Projects::MergeRequests::ApplicationController < Projects::ApplicationCont
before_action :merge_request
before_action :authorize_read_merge_request!
+ feature_category :code_review
+
private
def merge_request
@@ -35,6 +37,7 @@ class Projects::MergeRequests::ApplicationController < Projects::ApplicationCont
:source_branch,
:source_project_id,
:state_event,
+ :wip_event,
:squash,
:target_branch,
:target_project_id,
diff --git a/app/controllers/projects/merge_requests/diffs_controller.rb b/app/controllers/projects/merge_requests/diffs_controller.rb
index 8aacfdce094..07c38431f0f 100644
--- a/app/controllers/projects/merge_requests/diffs_controller.rb
+++ b/app/controllers/projects/merge_requests/diffs_controller.rb
@@ -64,7 +64,7 @@ class Projects::MergeRequests::DiffsController < Projects::MergeRequests::Applic
render: ->(partial, locals) { view_to_html_string(partial, locals) }
}
- options = additional_attributes.merge(diff_view: Feature.enabled?(:unified_diff_lines, @merge_request.project) ? "inline" : diff_view)
+ options = additional_attributes.merge(diff_view: Feature.enabled?(:unified_diff_lines, @merge_request.project, default_enabled: true) ? "inline" : diff_view)
if @merge_request.project.context_commits_enabled?
options[:context_commits] = @merge_request.recent_context_commits
@@ -173,7 +173,6 @@ class Projects::MergeRequests::DiffsController < Projects::MergeRequests::Applic
end
def update_diff_discussion_positions!
- return unless Feature.enabled?(:merge_ref_head_comments, @merge_request.target_project, default_enabled: true)
return unless Feature.enabled?(:merge_red_head_comments_position_on_demand, @merge_request.target_project, default_enabled: true)
return if @merge_request.has_any_diff_note_positions?
diff --git a/app/controllers/projects/merge_requests/drafts_controller.rb b/app/controllers/projects/merge_requests/drafts_controller.rb
index f4846b1aa81..ca3f36cafe1 100644
--- a/app/controllers/projects/merge_requests/drafts_controller.rb
+++ b/app/controllers/projects/merge_requests/drafts_controller.rb
@@ -45,7 +45,7 @@ class Projects::MergeRequests::DraftsController < Projects::MergeRequests::Appli
if result[:status] == :success
head :ok
else
- render json: { message: result[:message] }, status: result[:status]
+ render json: { message: result[:message] }, status: :internal_server_error
end
end
diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb
index 92785540172..91a041bb35b 100644
--- a/app/controllers/projects/merge_requests_controller.rb
+++ b/app/controllers/projects/merge_requests_controller.rb
@@ -27,11 +27,8 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
before_action :authenticate_user!, only: [:assign_related_issues]
before_action :check_user_can_push_to_source_branch!, only: [:rebase]
before_action only: [:show] do
- push_frontend_feature_flag(:deploy_from_footer, @project, default_enabled: true)
- push_frontend_feature_flag(:suggest_pipeline) if experiment_enabled?(:suggest_pipeline)
- push_frontend_feature_flag(:code_navigation, @project, default_enabled: true)
+ push_frontend_experiment(:suggest_pipeline)
push_frontend_feature_flag(:widget_visibility_polling, @project, default_enabled: true)
- push_frontend_feature_flag(:merge_ref_head_comments, @project, default_enabled: true)
push_frontend_feature_flag(:mr_commit_neighbor_nav, @project, default_enabled: true)
push_frontend_feature_flag(:multiline_comments, @project, default_enabled: true)
push_frontend_feature_flag(:file_identifier_hash)
@@ -39,25 +36,35 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
push_frontend_feature_flag(:approvals_commented_by, @project, default_enabled: true)
push_frontend_feature_flag(:hide_jump_to_next_unresolved_in_threads, default_enabled: true)
push_frontend_feature_flag(:merge_request_widget_graphql, @project)
- push_frontend_feature_flag(:unified_diff_lines, @project)
+ push_frontend_feature_flag(:unified_diff_lines, @project, default_enabled: true)
push_frontend_feature_flag(:highlight_current_diff_row, @project)
push_frontend_feature_flag(:default_merge_ref_for_diffs, @project)
+ push_frontend_feature_flag(:core_security_mr_widget, @project, default_enabled: true)
+
+ record_experiment_user(:invite_members_version_a)
+ record_experiment_user(:invite_members_version_b)
end
before_action do
push_frontend_feature_flag(:vue_issuable_sidebar, @project.group)
+ push_frontend_feature_flag(:deployment_filters)
end
around_action :allow_gitaly_ref_name_caching, only: [:index, :show, :discussions]
after_action :log_merge_request_show, only: [:show]
- feature_category :source_code_management,
- unless: -> (action) { action.ends_with?("_reports") }
- feature_category :code_testing,
- only: [:test_reports, :coverage_reports, :terraform_reports]
- feature_category :accessibility_testing,
- only: [:accessibility_reports]
+ feature_category :code_review, [
+ :assign_related_issues, :bulk_update, :cancel_auto_merge,
+ :ci_environments_status, :commit_change_content, :commits,
+ :context_commits, :destroy, :diff_for_path, :discussions,
+ :edit, :exposed_artifacts, :index, :merge,
+ :pipeline_status, :pipelines, :rebase, :remove_wip, :show,
+ :toggle_award_emoji, :toggle_subscription, :update
+ ]
+
+ feature_category :code_testing, [:test_reports, :coverage_reports, :terraform_reports]
+ feature_category :accessibility_testing, [:accessibility_reports]
def index
@merge_requests = @issuables
diff --git a/app/controllers/projects/metrics/dashboards/builder_controller.rb b/app/controllers/projects/metrics/dashboards/builder_controller.rb
index 2ab574d7d10..96ca6d89111 100644
--- a/app/controllers/projects/metrics/dashboards/builder_controller.rb
+++ b/app/controllers/projects/metrics/dashboards/builder_controller.rb
@@ -6,6 +6,8 @@ module Projects
class BuilderController < Projects::ApplicationController
before_action :authorize_metrics_dashboard!
+ feature_category :metrics
+
def panel_preview
respond_to do |format|
format.json do
diff --git a/app/controllers/projects/metrics_dashboard_controller.rb b/app/controllers/projects/metrics_dashboard_controller.rb
index bc0a701b9fd..3f10749602e 100644
--- a/app/controllers/projects/metrics_dashboard_controller.rb
+++ b/app/controllers/projects/metrics_dashboard_controller.rb
@@ -14,6 +14,8 @@ module Projects
push_frontend_feature_flag(:disable_metric_dashboard_refresh_rate)
end
+ feature_category :metrics
+
def show
if environment
render 'projects/environments/metrics'
diff --git a/app/controllers/projects/milestones_controller.rb b/app/controllers/projects/milestones_controller.rb
index 16d63cc184f..e6c4af00b29 100644
--- a/app/controllers/projects/milestones_controller.rb
+++ b/app/controllers/projects/milestones_controller.rb
@@ -5,7 +5,7 @@ class Projects::MilestonesController < Projects::ApplicationController
include MilestoneActions
before_action :check_issuables_available!
- before_action :milestone, only: [:edit, :update, :destroy, :show, :merge_requests, :participants, :labels, :promote]
+ before_action :milestone, only: [:edit, :update, :destroy, :show, :issues, :merge_requests, :participants, :labels, :promote]
before_action do
push_frontend_feature_flag(:burnup_charts, @project)
end
@@ -14,13 +14,15 @@ class Projects::MilestonesController < Projects::ApplicationController
before_action :authorize_read_milestone!
# Allow admin milestone
- before_action :authorize_admin_milestone!, except: [:index, :show, :merge_requests, :participants, :labels]
+ before_action :authorize_admin_milestone!, except: [:index, :show, :issues, :merge_requests, :participants, :labels]
# Allow to promote milestone
before_action :authorize_promote_milestone!, only: :promote
respond_to :html
+ feature_category :issue_tracking
+
def index
@sort = params[:sort] || 'due_date_asc'
@milestones = milestones.sort_by_attribute(@sort)
diff --git a/app/controllers/projects/mirrors_controller.rb b/app/controllers/projects/mirrors_controller.rb
index 518e6a92afa..01abb72fc86 100644
--- a/app/controllers/projects/mirrors_controller.rb
+++ b/app/controllers/projects/mirrors_controller.rb
@@ -10,6 +10,8 @@ class Projects::MirrorsController < Projects::ApplicationController
layout "project_settings"
+ feature_category :source_code_management
+
def show
redirect_to_repository_settings(project, anchor: 'js-push-remote-settings')
end
diff --git a/app/controllers/projects/network_controller.rb b/app/controllers/projects/network_controller.rb
index 47788438da9..89b679fc033 100644
--- a/app/controllers/projects/network_controller.rb
+++ b/app/controllers/projects/network_controller.rb
@@ -11,6 +11,8 @@ class Projects::NetworkController < Projects::ApplicationController
before_action :assign_options
before_action :assign_commit
+ feature_category :source_code_management
+
def show
@url = project_network_path(@project, @ref, @options.merge(format: :json))
@commit_url = project_commit_path(@project, 'ae45ca32').gsub("ae45ca32", "%s")
diff --git a/app/controllers/projects/notes_controller.rb b/app/controllers/projects/notes_controller.rb
index c0b8c9e550d..e50e293a103 100644
--- a/app/controllers/projects/notes_controller.rb
+++ b/app/controllers/projects/notes_controller.rb
@@ -11,6 +11,8 @@ class Projects::NotesController < Projects::ApplicationController
before_action :authorize_create_note!, only: [:create]
before_action :authorize_resolve_note!, only: [:resolve, :unresolve]
+ feature_category :issue_tracking
+
def delete_attachment
note.remove_attachment!
note.update_attribute(:attachment, nil)
diff --git a/app/controllers/projects/packages/package_files_controller.rb b/app/controllers/projects/packages/package_files_controller.rb
index dd6d875cd1e..32aadb4fcf4 100644
--- a/app/controllers/projects/packages/package_files_controller.rb
+++ b/app/controllers/projects/packages/package_files_controller.rb
@@ -6,6 +6,8 @@ module Projects
include PackagesAccess
include SendFileUpload
+ feature_category :package_registry
+
def download
package_file = project.package_files.find(params[:id])
diff --git a/app/controllers/projects/packages/packages_controller.rb b/app/controllers/projects/packages/packages_controller.rb
index fc4ef7a01dc..15dc11f5df8 100644
--- a/app/controllers/projects/packages/packages_controller.rb
+++ b/app/controllers/projects/packages/packages_controller.rb
@@ -5,20 +5,13 @@ module Projects
class PackagesController < Projects::ApplicationController
include PackagesAccess
- before_action :authorize_destroy_package!, only: [:destroy]
+ feature_category :package_registry
def show
@package = project.packages.find(params[:id])
@package_files = @package.package_files.recent
@maven_metadatum = @package.maven_metadatum
end
-
- def destroy
- @package = project.packages.find(params[:id])
- @package.destroy
-
- redirect_to project_packages_path(@project), status: :found, notice: _('Package was removed')
- end
end
end
end
diff --git a/app/controllers/projects/pages_controller.rb b/app/controllers/projects/pages_controller.rb
index 9ad6bf4095a..0aac517e3e3 100644
--- a/app/controllers/projects/pages_controller.rb
+++ b/app/controllers/projects/pages_controller.rb
@@ -8,6 +8,8 @@ class Projects::PagesController < Projects::ApplicationController
before_action :authorize_update_pages!, except: [:show, :destroy]
before_action :authorize_remove_pages!, only: [:destroy]
+ feature_category :pages
+
# rubocop: disable CodeReuse/ActiveRecord
def show
@domains = @project.pages_domains.order(:domain).present(current_user: current_user)
diff --git a/app/controllers/projects/pages_domains_controller.rb b/app/controllers/projects/pages_domains_controller.rb
index cccf8fe4358..a6b22a28b17 100644
--- a/app/controllers/projects/pages_domains_controller.rb
+++ b/app/controllers/projects/pages_domains_controller.rb
@@ -9,6 +9,8 @@ class Projects::PagesDomainsController < Projects::ApplicationController
helper_method :domain_presenter
+ feature_category :pages
+
def show
end
diff --git a/app/controllers/projects/performance_monitoring/dashboards_controller.rb b/app/controllers/projects/performance_monitoring/dashboards_controller.rb
index ec5a33f5dd6..51a07c1b7a5 100644
--- a/app/controllers/projects/performance_monitoring/dashboards_controller.rb
+++ b/app/controllers/projects/performance_monitoring/dashboards_controller.rb
@@ -12,6 +12,8 @@ module Projects
respond_error(http_status: :bad_request, message: _('Request parameter %{param} is missing.') % { param: exception.param })
end
+ feature_category :metrics
+
def create
result = ::Metrics::Dashboard::CloneDashboardService.new(project, current_user, dashboard_params).execute
diff --git a/app/controllers/projects/pipeline_schedules_controller.rb b/app/controllers/projects/pipeline_schedules_controller.rb
index e7e8a900060..5655d3b4c0d 100644
--- a/app/controllers/projects/pipeline_schedules_controller.rb
+++ b/app/controllers/projects/pipeline_schedules_controller.rb
@@ -10,6 +10,8 @@ class Projects::PipelineSchedulesController < Projects::ApplicationController
before_action :authorize_update_pipeline_schedule!, except: [:index, :new, :create, :play]
before_action :authorize_admin_pipeline_schedule!, only: [:destroy]
+ feature_category :continuous_integration
+
# rubocop: disable CodeReuse/ActiveRecord
def index
@scope = params[:scope]
diff --git a/app/controllers/projects/pipelines/application_controller.rb b/app/controllers/projects/pipelines/application_controller.rb
index 92887750813..c147d697888 100644
--- a/app/controllers/projects/pipelines/application_controller.rb
+++ b/app/controllers/projects/pipelines/application_controller.rb
@@ -10,6 +10,8 @@ module Projects
before_action :pipeline
before_action :authorize_read_pipeline!
+ feature_category :continuous_integration
+
private
def pipeline
diff --git a/app/controllers/projects/pipelines_controller.rb b/app/controllers/projects/pipelines_controller.rb
index c1734d2cd8a..953dce4d63c 100644
--- a/app/controllers/projects/pipelines_controller.rb
+++ b/app/controllers/projects/pipelines_controller.rb
@@ -5,17 +5,19 @@ class Projects::PipelinesController < Projects::ApplicationController
include Analytics::UniqueVisitsHelper
before_action :whitelist_query_limiting, only: [:create, :retry]
- before_action :pipeline, except: [:index, :new, :create, :charts]
+ before_action :pipeline, except: [:index, :new, :create, :charts, :config_variables]
before_action :set_pipeline_path, only: [:show]
before_action :authorize_read_pipeline!
before_action :authorize_read_build!, only: [:index]
- before_action :authorize_create_pipeline!, only: [:new, :create]
+ before_action :authorize_create_pipeline!, only: [:new, :create, :config_variables]
before_action :authorize_update_pipeline!, only: [:retry, :cancel]
before_action do
push_frontend_feature_flag(:filter_pipelines_search, project, default_enabled: true)
push_frontend_feature_flag(:dag_pipeline_tab, project, default_enabled: true)
push_frontend_feature_flag(:pipelines_security_report_summary, project)
- push_frontend_feature_flag(:new_pipeline_form)
+ push_frontend_feature_flag(:new_pipeline_form, project)
+ push_frontend_feature_flag(:graphql_pipeline_header, project, type: :development, default_enabled: false)
+ push_frontend_feature_flag(:new_pipeline_form_prefilled_vars, project, type: :development)
end
before_action :ensure_pipeline, only: [:show]
@@ -30,6 +32,8 @@ class Projects::PipelinesController < Projects::ApplicationController
POLLING_INTERVAL = 10_000
+ feature_category :continuous_integration
+
def index
@pipelines = Ci::PipelinesFinder
.new(project, current_user, index_params)
@@ -206,6 +210,14 @@ class Projects::PipelinesController < Projects::ApplicationController
end
end
+ def config_variables
+ respond_to do |format|
+ format.json do
+ render json: Ci::ListConfigVariablesService.new(@project).execute(params[:sha])
+ end
+ end
+ end
+
private
def serialize_pipelines
diff --git a/app/controllers/projects/pipelines_settings_controller.rb b/app/controllers/projects/pipelines_settings_controller.rb
index 7f988110977..6e08a889520 100644
--- a/app/controllers/projects/pipelines_settings_controller.rb
+++ b/app/controllers/projects/pipelines_settings_controller.rb
@@ -3,6 +3,8 @@
class Projects::PipelinesSettingsController < Projects::ApplicationController
before_action :authorize_admin_pipeline!
+ feature_category :continuous_integration
+
def show
redirect_to project_settings_ci_cd_path(@project, params: params.to_unsafe_h)
end
diff --git a/app/controllers/projects/product_analytics_controller.rb b/app/controllers/projects/product_analytics_controller.rb
index c019dc191d6..5db7585d8e0 100644
--- a/app/controllers/projects/product_analytics_controller.rb
+++ b/app/controllers/projects/product_analytics_controller.rb
@@ -5,6 +5,8 @@ class Projects::ProductAnalyticsController < Projects::ApplicationController
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
diff --git a/app/controllers/projects/project_members_controller.rb b/app/controllers/projects/project_members_controller.rb
index 3e52248f292..631f627838b 100644
--- a/app/controllers/projects/project_members_controller.rb
+++ b/app/controllers/projects/project_members_controller.rb
@@ -8,6 +8,8 @@ class Projects::ProjectMembersController < Projects::ApplicationController
# Authorize
before_action :authorize_admin_project_member!, except: [:index, :leave, :request_access]
+ feature_category :authentication_and_authorization
+
def index
@sort = params[:sort].presence || sort_value_name
@@ -55,6 +57,10 @@ class Projects::ProjectMembersController < Projects::ApplicationController
def filter_params
params.permit(:search).merge(sort: @sort)
end
+
+ def membershipable_members
+ project.members
+ end
end
Projects::ProjectMembersController.prepend_if_ee('EE::Projects::ProjectMembersController')
diff --git a/app/controllers/projects/prometheus/alerts_controller.rb b/app/controllers/projects/prometheus/alerts_controller.rb
index c6ae65f7832..2892542e63c 100644
--- a/app/controllers/projects/prometheus/alerts_controller.rb
+++ b/app/controllers/projects/prometheus/alerts_controller.rb
@@ -16,6 +16,8 @@ module Projects
before_action :authorize_read_prometheus_alerts!, except: [:notify]
before_action :alert, only: [:update, :show, :destroy, :metrics_dashboard]
+ feature_category :alert_management
+
def index
render json: serialize_as_json(alerts)
end
diff --git a/app/controllers/projects/prometheus/metrics_controller.rb b/app/controllers/projects/prometheus/metrics_controller.rb
index 0340cb5beb0..d70d29a341f 100644
--- a/app/controllers/projects/prometheus/metrics_controller.rb
+++ b/app/controllers/projects/prometheus/metrics_controller.rb
@@ -6,6 +6,8 @@ module Projects
before_action :authorize_admin_project!
before_action :require_prometheus_metrics!
+ feature_category :metrics
+
def active_common
respond_to do |format|
format.json do
diff --git a/app/controllers/projects/protected_refs_controller.rb b/app/controllers/projects/protected_refs_controller.rb
index 060403a9cd9..4cba1a75330 100644
--- a/app/controllers/projects/protected_refs_controller.rb
+++ b/app/controllers/projects/protected_refs_controller.rb
@@ -10,6 +10,8 @@ class Projects::ProtectedRefsController < Projects::ApplicationController
layout "project_settings"
+ feature_category :source_code_management
+
def index
redirect_to_repository_settings(@project)
end
@@ -62,7 +64,7 @@ class Projects::ProtectedRefsController < Projects::ApplicationController
end
def access_level_attributes
- %i[access_level id _destroy]
+ %i[access_level id _destroy deploy_key_id]
end
end
diff --git a/app/controllers/projects/raw_controller.rb b/app/controllers/projects/raw_controller.rb
index 29f1e4bfd44..a9490c106d4 100644
--- a/app/controllers/projects/raw_controller.rb
+++ b/app/controllers/projects/raw_controller.rb
@@ -15,6 +15,8 @@ class Projects::RawController < Projects::ApplicationController
before_action :no_cache_headers, only: [:show]
before_action :redirect_to_external_storage, only: :show, if: :static_objects_external_storage_enabled?
+ feature_category :source_code_management
+
def show
@blob = @repository.blob_at(@commit.id, @path)
diff --git a/app/controllers/projects/refs_controller.rb b/app/controllers/projects/refs_controller.rb
index db770d3e438..4d23c853334 100644
--- a/app/controllers/projects/refs_controller.rb
+++ b/app/controllers/projects/refs_controller.rb
@@ -11,6 +11,8 @@ class Projects::RefsController < Projects::ApplicationController
before_action :assign_ref_vars
before_action :authorize_download_code!
+ feature_category :source_code_management
+
def switch
respond_to do |format|
format.html do
diff --git a/app/controllers/projects/registry/application_controller.rb b/app/controllers/projects/registry/application_controller.rb
index 2f891d78c91..e7bf8c8e757 100644
--- a/app/controllers/projects/registry/application_controller.rb
+++ b/app/controllers/projects/registry/application_controller.rb
@@ -8,6 +8,8 @@ module Projects
before_action :verify_registry_enabled!
before_action :authorize_read_container_image!
+ feature_category :container_registry
+
private
def verify_registry_enabled!
diff --git a/app/controllers/projects/registry/repositories_controller.rb b/app/controllers/projects/registry/repositories_controller.rb
index 19d0cb9acdc..28a86ecc9f0 100644
--- a/app/controllers/projects/registry/repositories_controller.rb
+++ b/app/controllers/projects/registry/repositories_controller.rb
@@ -3,6 +3,8 @@
module Projects
module Registry
class RepositoriesController < ::Projects::Registry::ApplicationController
+ include PackagesHelper
+
before_action :authorize_update_container_image!, only: [:destroy]
before_action :ensure_root_container_repository!, only: [:index]
@@ -13,7 +15,7 @@ module Projects
@images = ContainerRepositoriesFinder.new(user: current_user, subject: project, params: params.slice(:name))
.execute
- track_event(:list_repositories)
+ track_package_event(:list_repositories, :container)
serializer = ContainerRepositoriesSerializer
.new(project: project, current_user: current_user)
@@ -31,7 +33,7 @@ module Projects
def destroy
image.delete_scheduled!
DeleteContainerRepositoryWorker.perform_async(current_user.id, image.id) # rubocop:disable CodeReuse/Worker
- track_event(:delete_repository)
+ track_package_event(:delete_repository, :container)
respond_to do |format|
format.json { head :no_content }
diff --git a/app/controllers/projects/registry/tags_controller.rb b/app/controllers/projects/registry/tags_controller.rb
index c42e3f6bdba..ebdb668207f 100644
--- a/app/controllers/projects/registry/tags_controller.rb
+++ b/app/controllers/projects/registry/tags_controller.rb
@@ -3,12 +3,15 @@
module Projects
module Registry
class TagsController < ::Projects::Registry::ApplicationController
+ include PackagesHelper
+
before_action :authorize_destroy_container_image!, only: [:destroy]
LIMIT = 15
def index
- track_event(:list_tags)
+ track_package_event(:list_tags, :tag)
+
respond_to do |format|
format.json do
render json: ContainerTagsSerializer
@@ -23,7 +26,7 @@ module Projects
result = Projects::ContainerRepository::DeleteTagsService
.new(image.project, current_user, tags: [params[:id]])
.execute(image)
- track_event(:delete_tag)
+ track_package_event(:delete_tag, :tag)
respond_to do |format|
format.json { head(result[:status] == :success ? :ok : bad_request) }
@@ -40,7 +43,7 @@ module Projects
result = Projects::ContainerRepository::DeleteTagsService
.new(image.project, current_user, tags: tag_names)
.execute(image)
- track_event(:delete_tag_bulk)
+ track_package_event(:delete_tag_bulk, :tag)
respond_to do |format|
format.json { head(result[:status] == :success ? :no_content : :bad_request) }
diff --git a/app/controllers/projects/releases/evidences_controller.rb b/app/controllers/projects/releases/evidences_controller.rb
index 34e450d903f..1e2dbf8047c 100644
--- a/app/controllers/projects/releases/evidences_controller.rb
+++ b/app/controllers/projects/releases/evidences_controller.rb
@@ -7,6 +7,8 @@ module Projects
before_action :release
before_action :authorize_read_release_evidence!
+ feature_category :release_evidence
+
def show
respond_to do |format|
format.json do
diff --git a/app/controllers/projects/releases_controller.rb b/app/controllers/projects/releases_controller.rb
index bd24aae980c..4e8260d9e53 100644
--- a/app/controllers/projects/releases_controller.rb
+++ b/app/controllers/projects/releases_controller.rb
@@ -6,18 +6,16 @@ class Projects::ReleasesController < Projects::ApplicationController
before_action :release, only: %i[edit show update downloads]
before_action :authorize_read_release!
before_action do
- push_frontend_feature_flag(:release_issue_summary, project, default_enabled: true)
- push_frontend_feature_flag(:release_evidence_collection, project, default_enabled: true)
- push_frontend_feature_flag(:release_show_page, project, default_enabled: true)
- push_frontend_feature_flag(:release_asset_link_editing, project, default_enabled: true)
- push_frontend_feature_flag(:release_asset_link_type, project, default_enabled: true)
push_frontend_feature_flag(:graphql_release_data, project, default_enabled: true)
push_frontend_feature_flag(:graphql_milestone_stats, project, default_enabled: true)
- push_frontend_feature_flag(:graphql_releases_page, project, default_enabled: false)
+ push_frontend_feature_flag(:graphql_releases_page, project, default_enabled: true)
+ push_frontend_feature_flag(:graphql_individual_release_page, project, default_enabled: true)
end
before_action :authorize_update_release!, only: %i[edit update]
before_action :authorize_create_release!, only: :new
+ feature_category :release_orchestration
+
def index
respond_to do |format|
format.html do
@@ -27,10 +25,6 @@ class Projects::ReleasesController < Projects::ApplicationController
end
end
- def show
- return render_404 unless Feature.enabled?(:release_show_page, project, default_enabled: true)
- end
-
def new
unless Feature.enabled?(:new_release_page, project, default_enabled: true)
redirect_to(new_project_tag_path(@project))
diff --git a/app/controllers/projects/repositories_controller.rb b/app/controllers/projects/repositories_controller.rb
index 303326bbe23..ba3ab52e3af 100644
--- a/app/controllers/projects/repositories_controller.rb
+++ b/app/controllers/projects/repositories_controller.rb
@@ -18,6 +18,8 @@ class Projects::RepositoriesController < Projects::ApplicationController
before_action :authorize_admin_project!, only: :create
before_action :redirect_to_external_storage, only: :archive, if: :static_objects_external_storage_enabled?
+ feature_category :source_code_management
+
def create
@project.create_repository
diff --git a/app/controllers/projects/runner_projects_controller.rb b/app/controllers/projects/runner_projects_controller.rb
index cbeb32fd610..d225d5e104c 100644
--- a/app/controllers/projects/runner_projects_controller.rb
+++ b/app/controllers/projects/runner_projects_controller.rb
@@ -5,6 +5,8 @@ class Projects::RunnerProjectsController < Projects::ApplicationController
layout 'project_settings'
+ feature_category :continuous_integration
+
def create
@runner = Ci::Runner.find(params[:runner_project][:runner_id])
diff --git a/app/controllers/projects/runners_controller.rb b/app/controllers/projects/runners_controller.rb
index ca62f54813b..544074f9840 100644
--- a/app/controllers/projects/runners_controller.rb
+++ b/app/controllers/projects/runners_controller.rb
@@ -6,6 +6,8 @@ class Projects::RunnersController < Projects::ApplicationController
layout 'project_settings'
+ feature_category :continuous_integration
+
def index
redirect_to project_settings_ci_cd_path(@project, anchor: 'js-runners-settings')
end
@@ -50,6 +52,10 @@ class Projects::RunnersController < Projects::ApplicationController
end
def toggle_shared_runners
+ if Feature.enabled?(:disable_shared_runners_on_group, default_enabled: true) && !project.shared_runners_enabled && project.group && project.group.shared_runners_setting == 'disabled_and_unoverridable'
+ return redirect_to project_runners_path(@project), alert: _("Cannot enable shared runners because parent group does not allow it")
+ end
+
project.toggle!(:shared_runners_enabled)
redirect_to project_settings_ci_cd_path(@project, anchor: 'js-runners-settings')
diff --git a/app/controllers/projects/serverless/functions_controller.rb b/app/controllers/projects/serverless/functions_controller.rb
index 0b55414d390..4168880001c 100644
--- a/app/controllers/projects/serverless/functions_controller.rb
+++ b/app/controllers/projects/serverless/functions_controller.rb
@@ -5,6 +5,8 @@ module Projects
class FunctionsController < Projects::ApplicationController
before_action :authorize_read_cluster!
+ feature_category :serverless
+
def index
respond_to do |format|
format.json do
diff --git a/app/controllers/projects/service_desk_controller.rb b/app/controllers/projects/service_desk_controller.rb
index bcd190bbc2c..f7c0a54fb9e 100644
--- a/app/controllers/projects/service_desk_controller.rb
+++ b/app/controllers/projects/service_desk_controller.rb
@@ -3,6 +3,8 @@
class Projects::ServiceDeskController < Projects::ApplicationController
before_action :authorize_admin_project!
+ feature_category :service_desk
+
def show
json_response
end
diff --git a/app/controllers/projects/services_controller.rb b/app/controllers/projects/services_controller.rb
index 9a69ef991dd..93ad549bc50 100644
--- a/app/controllers/projects/services_controller.rb
+++ b/app/controllers/projects/services_controller.rb
@@ -12,13 +12,15 @@ class Projects::ServicesController < Projects::ApplicationController
before_action :set_deprecation_notice_for_prometheus_service, only: [:edit, :update]
before_action :redirect_deprecated_prometheus_service, only: [:update]
before_action only: :edit do
- push_frontend_feature_flag(:jira_issues_integration, @project, { default_enabled: true })
+ push_frontend_feature_flag(:jira_issues_integration, @project, type: :licensed, default_enabled: true)
end
respond_to :html
layout "project_settings"
+ feature_category :integrations
+
def edit
@default_integration = Service.default_integration(service.type, project)
end
diff --git a/app/controllers/projects/settings/access_tokens_controller.rb b/app/controllers/projects/settings/access_tokens_controller.rb
index d6b4c4dd5dc..cbd6716fdf7 100644
--- a/app/controllers/projects/settings/access_tokens_controller.rb
+++ b/app/controllers/projects/settings/access_tokens_controller.rb
@@ -7,6 +7,8 @@ module Projects
before_action :check_feature_availability
+ feature_category :authentication_and_authorization
+
def index
@project_access_token = PersonalAccessToken.new
set_index_vars
diff --git a/app/controllers/projects/settings/ci_cd_controller.rb b/app/controllers/projects/settings/ci_cd_controller.rb
index d0d100fd88c..2963321f803 100644
--- a/app/controllers/projects/settings/ci_cd_controller.rb
+++ b/app/controllers/projects/settings/ci_cd_controller.rb
@@ -3,15 +3,25 @@
module Projects
module Settings
class CiCdController < Projects::ApplicationController
+ include RunnerSetupScripts
+
before_action :authorize_admin_pipeline!
before_action :define_variables
before_action do
push_frontend_feature_flag(:new_variables_ui, @project, default_enabled: true)
push_frontend_feature_flag(:ajax_new_deploy_token, @project)
- push_frontend_feature_flag(:ci_key_autocomplete, default_enabled: true)
end
+ helper_method :highlight_badge
+
+ feature_category :continuous_integration
+
def show
+ if Feature.enabled?(:ci_pipeline_triggers_settings_vue_ui, @project)
+ @triggers_json = ::Ci::TriggerSerializer.new.represent(
+ @project.triggers, current_user: current_user, project: @project
+ ).to_json
+ end
end
def update
@@ -48,8 +58,16 @@ module Projects
redirect_to namespace_project_settings_ci_cd_path
end
+ def runner_setup_scripts
+ private_runner_setup_scripts(project: @project)
+ end
+
private
+ def highlight_badge(name, content, language = nil)
+ Gitlab::Highlight.highlight(name, content, language: language)
+ end
+
def update_params
params.require(:project).permit(*permitted_project_params)
end
@@ -58,9 +76,9 @@ module Projects
[
:runners_token, :builds_enabled, :build_allow_git_fetch,
:build_timeout_human_readable, :build_coverage_regex, :public_builds,
- :auto_cancel_pending_pipelines, :forward_deployment_enabled, :ci_config_path,
+ :auto_cancel_pending_pipelines, :ci_config_path,
auto_devops_attributes: [:id, :domain, :enabled, :deploy_strategy],
- ci_cd_settings_attributes: [:default_git_depth]
+ ci_cd_settings_attributes: [:default_git_depth, :forward_deployment_enabled]
].tap do |list|
list << :max_artifacts_size if can?(current_user, :update_max_artifacts_size, project)
end
@@ -116,6 +134,7 @@ module Projects
def define_triggers_variables
@triggers = @project.triggers
.present(current_user: current_user)
+
@trigger = ::Ci::Trigger.new
.present(current_user: current_user)
end
diff --git a/app/controllers/projects/settings/integrations_controller.rb b/app/controllers/projects/settings/integrations_controller.rb
index 96bf7f474d1..fba11ff1497 100644
--- a/app/controllers/projects/settings/integrations_controller.rb
+++ b/app/controllers/projects/settings/integrations_controller.rb
@@ -6,6 +6,8 @@ module Projects
before_action :authorize_admin_project!
layout "project_settings"
+ feature_category :integrations
+
def show
@services = @project.find_or_initialize_services
end
diff --git a/app/controllers/projects/settings/operations_controller.rb b/app/controllers/projects/settings/operations_controller.rb
index 781b850ddfe..c407b15e29f 100644
--- a/app/controllers/projects/settings/operations_controller.rb
+++ b/app/controllers/projects/settings/operations_controller.rb
@@ -9,6 +9,9 @@ module Projects
respond_to :json, only: [:reset_alerting_token, :reset_pagerduty_token]
helper_method :error_tracking_setting
+ helper_method :tracing_setting
+
+ feature_category :incident_management
def update
result = ::Projects::Operations::UpdateService.new(project, current_user, update_params).execute
@@ -17,15 +20,6 @@ module Projects
render_update_response(result)
end
- # overridden in EE
- def track_events(result)
- if result[:status] == :success
- ::Gitlab::Tracking::IncidentManagement.track_from_params(
- update_params[:incident_management_setting_attributes]
- )
- end
- end
-
def reset_alerting_token
result = ::Projects::Operations::UpdateService
.new(project, current_user, alerting_params)
@@ -55,6 +49,24 @@ module Projects
private
+ def track_events(result)
+ if result[:status] == :success
+ ::Gitlab::Tracking::IncidentManagement.track_from_params(
+ update_params[:incident_management_setting_attributes]
+ )
+ track_tracing_external_url
+ end
+ end
+
+ def track_tracing_external_url
+ external_url_previous_change = project&.tracing_setting&.external_url_previous_change
+
+ return unless external_url_previous_change
+ return unless external_url_previous_change[0].blank? && external_url_previous_change[1].present?
+
+ ::Gitlab::Tracking.event('project:operations:tracing', 'external_url_populated')
+ end
+
def alerting_params
{ alerting_setting_attributes: { regenerate_token: true } }
end
@@ -106,6 +118,10 @@ module Projects
project.build_error_tracking_setting
end
+ def tracing_setting
+ @tracing_setting ||= project.tracing_setting || project.build_tracing_setting
+ end
+
def update_params
params.require(:project).permit(permitted_project_params)
end
@@ -124,7 +140,8 @@ module Projects
project: [:slug, :name, :organization_slug, :organization_name]
],
- grafana_integration_attributes: [:token, :grafana_url, :enabled]
+ grafana_integration_attributes: [:token, :grafana_url, :enabled],
+ tracing_setting_attributes: [:external_url]
}
if Feature.enabled?(:settings_operations_prometheus_service, project)
diff --git a/app/controllers/projects/settings/repository_controller.rb b/app/controllers/projects/settings/repository_controller.rb
index 35ca9336613..0994bebb1d0 100644
--- a/app/controllers/projects/settings/repository_controller.rb
+++ b/app/controllers/projects/settings/repository_controller.rb
@@ -7,8 +7,12 @@ module Projects
before_action :define_variables, only: [:create_deploy_token]
before_action do
push_frontend_feature_flag(:ajax_new_deploy_token, @project)
+ push_frontend_feature_flag(:deploy_keys_on_protected_branches, @project)
end
+ feature_category :source_code_management, [:show, :cleanup]
+ feature_category :continuous_delivery, [:create_deploy_token]
+
def show
render_show
end
@@ -125,6 +129,7 @@ module Projects
gon.push(protectable_tags_for_dropdown)
gon.push(protectable_branches_for_dropdown)
gon.push(access_levels_options)
+ gon.push(current_project_id: project.id) if project
end
end
end
diff --git a/app/controllers/projects/snippets/application_controller.rb b/app/controllers/projects/snippets/application_controller.rb
index 3f488b07e96..8ee12bf3795 100644
--- a/app/controllers/projects/snippets/application_controller.rb
+++ b/app/controllers/projects/snippets/application_controller.rb
@@ -4,6 +4,8 @@ class Projects::Snippets::ApplicationController < Projects::ApplicationControlle
include FindSnippet
include SnippetAuthorizations
+ feature_category :snippets
+
private
# This overrides the default snippet create authorization
diff --git a/app/controllers/projects/snippets_controller.rb b/app/controllers/projects/snippets_controller.rb
index 632e8db9796..779e149bb9c 100644
--- a/app/controllers/projects/snippets_controller.rb
+++ b/app/controllers/projects/snippets_controller.rb
@@ -7,16 +7,11 @@ class Projects::SnippetsController < Projects::Snippets::ApplicationController
before_action :check_snippets_available!
- before_action :snippet, only: [:show, :edit, :destroy, :update, :raw, :toggle_award_emoji, :mark_as_spam]
+ before_action :snippet, only: [:show, :edit, :raw, :toggle_award_emoji, :mark_as_spam]
- before_action :authorize_create_snippet!, only: [:new, :create]
- before_action :authorize_read_snippet!, except: [:new, :create, :index]
- before_action :authorize_update_snippet!, only: [:edit, :update]
- before_action :authorize_admin_snippet!, only: [:destroy]
-
- before_action do
- push_frontend_feature_flag(:snippet_multiple_files, current_user)
- end
+ before_action :authorize_create_snippet!, only: :new
+ before_action :authorize_read_snippet!, except: [:new, :index]
+ before_action :authorize_update_snippet!, only: :edit
def index
@snippet_counts = ::Snippets::CountService
@@ -37,14 +32,6 @@ class Projects::SnippetsController < Projects::Snippets::ApplicationController
@snippet = @noteable = @project.snippets.build
end
- def create
- create_params = snippet_params.merge(spammable_params)
- service_response = ::Snippets::CreateService.new(project, current_user, create_params).execute
- @snippet = service_response.payload[:snippet]
-
- handle_repository_error(:new)
- end
-
protected
alias_method :awardable, :snippet
@@ -53,8 +40,4 @@ class Projects::SnippetsController < Projects::Snippets::ApplicationController
def spammable_path
project_snippet_path(@project, @snippet)
end
-
- def snippet_params
- params.require(:project_snippet).permit(:title, :content, :file_name, :private, :visibility_level, :description)
- end
end
diff --git a/app/controllers/projects/starrers_controller.rb b/app/controllers/projects/starrers_controller.rb
index d9654f4f72a..91f49fc4d66 100644
--- a/app/controllers/projects/starrers_controller.rb
+++ b/app/controllers/projects/starrers_controller.rb
@@ -3,6 +3,8 @@
class Projects::StarrersController < Projects::ApplicationController
include SortingHelper
+ feature_category :projects
+
def index
@starrers = UsersStarProjectsFinder.new(@project, params, current_user: @current_user).execute
@sort = params[:sort].presence || sort_value_name
diff --git a/app/controllers/projects/static_site_editor_controller.rb b/app/controllers/projects/static_site_editor_controller.rb
index e97a8db0b79..7e2e32a843f 100644
--- a/app/controllers/projects/static_site_editor_controller.rb
+++ b/app/controllers/projects/static_site_editor_controller.rb
@@ -13,6 +13,8 @@ class Projects::StaticSiteEditorController < Projects::ApplicationController
push_frontend_feature_flag(:sse_image_uploads)
end
+ feature_category :static_site_editor
+
def show
service_response = ::StaticSiteEditor::ConfigService.new(
container: project,
@@ -25,14 +27,32 @@ class Projects::StaticSiteEditorController < Projects::ApplicationController
).execute
if service_response.success?
- @data = service_response.payload
+ Gitlab::UsageDataCounters::StaticSiteEditorCounter.increment_views_count
+
+ @data = serialize_necessary_payload_values_to_json(service_response.payload)
else
- respond_422
+ # TODO: For now, if the service returns any error, the user is redirected
+ # to the root project page with the error message displayed as an alert.
+ # See https://gitlab.com/gitlab-org/gitlab/-/issues/213285#note_414808004
+ # for discussion of plans to handle this via a page owned by the Static Site Editor.
+ flash[:alert] = service_response.message
+ redirect_to project_path(project)
end
end
private
+ def serialize_necessary_payload_values_to_json(payload)
+ # This will convert booleans, Array-like and Hash-like objects to JSON
+ payload.transform_values do |value|
+ if value.is_a?(String) || value.is_a?(Integer)
+ value
+ else
+ value.to_json
+ end
+ end
+ end
+
def assign_ref_and_path
@ref, @path = extract_ref(params.fetch(:id))
diff --git a/app/controllers/projects/tags/releases_controller.rb b/app/controllers/projects/tags/releases_controller.rb
index c1f4cbce054..8e5539f546b 100644
--- a/app/controllers/projects/tags/releases_controller.rb
+++ b/app/controllers/projects/tags/releases_controller.rb
@@ -8,6 +8,8 @@ class Projects::Tags::ReleasesController < Projects::ApplicationController
before_action :tag
before_action :release
+ feature_category :release_evidence
+
def edit
end
diff --git a/app/controllers/projects/tags_controller.rb b/app/controllers/projects/tags_controller.rb
index 475ca8894e4..1d783241196 100644
--- a/app/controllers/projects/tags_controller.rb
+++ b/app/controllers/projects/tags_controller.rb
@@ -10,6 +10,9 @@ class Projects::TagsController < Projects::ApplicationController
before_action :authorize_download_code!
before_action :authorize_admin_tag!, only: [:new, :create, :destroy]
+ feature_category :source_code_management, [:index, :show, :new, :destroy]
+ feature_category :release_evidence, [:create]
+
# rubocop: disable CodeReuse/ActiveRecord
def index
params[:sort] = params[:sort].presence || sort_value_recently_updated
@@ -76,25 +79,10 @@ class Projects::TagsController < Projects::ApplicationController
def destroy
result = ::Tags::DestroyService.new(project, current_user).execute(params[:id])
- respond_to do |format|
- if result[:status] == :success
- format.html do
- redirect_to project_tags_path(@project), status: :see_other
- end
-
- format.js
- else
- @error = result[:message]
-
- format.html do
- redirect_to project_tags_path(@project),
- alert: @error, status: :see_other
- end
-
- format.js do
- render status: :ok
- end
- end
+ if result[:status] == :success
+ render json: result
+ else
+ render json: { message: result[:message] }, status: result[:return_code]
end
end
diff --git a/app/controllers/projects/templates_controller.rb b/app/controllers/projects/templates_controller.rb
index 95739f96d39..7ab23e39cf0 100644
--- a/app/controllers/projects/templates_controller.rb
+++ b/app/controllers/projects/templates_controller.rb
@@ -5,6 +5,8 @@ class Projects::TemplatesController < Projects::ApplicationController
before_action :authorize_can_read_issuable!
before_action :get_template_class
+ feature_category :templates
+
def show
template = @template_type.find(params[:key], project)
diff --git a/app/controllers/projects/todos_controller.rb b/app/controllers/projects/todos_controller.rb
index 33205b93317..6ba89ab34f8 100644
--- a/app/controllers/projects/todos_controller.rb
+++ b/app/controllers/projects/todos_controller.rb
@@ -6,6 +6,8 @@ class Projects::TodosController < Projects::ApplicationController
before_action :authenticate_user!, only: [:create]
+ feature_category :issue_tracking
+
private
def issuable
diff --git a/app/controllers/projects/tracings_controller.rb b/app/controllers/projects/tracings_controller.rb
new file mode 100644
index 00000000000..2bc0c590e8d
--- /dev/null
+++ b/app/controllers/projects/tracings_controller.rb
@@ -0,0 +1,28 @@
+# frozen_string_literal: true
+
+module Projects
+ class TracingsController < Projects::ApplicationController
+ content_security_policy do |p|
+ next if p.directives.blank?
+
+ global_frame_src = p.frame_src
+
+ p.frame_src -> { frame_src_csp_policy(global_frame_src) }
+ end
+
+ before_action :authorize_update_environment!
+
+ feature_category :tracing
+
+ def show
+ end
+
+ private
+
+ def frame_src_csp_policy(global_frame_src)
+ external_url = @project&.tracing_setting&.external_url
+
+ external_url.presence || global_frame_src
+ end
+ end
+end
diff --git a/app/controllers/projects/tree_controller.rb b/app/controllers/projects/tree_controller.rb
index 638e1a05c18..b5cfc3990b2 100644
--- a/app/controllers/projects/tree_controller.rb
+++ b/app/controllers/projects/tree_controller.rb
@@ -15,6 +15,8 @@ class Projects::TreeController < Projects::ApplicationController
before_action :authorize_download_code!
before_action :authorize_edit_tree!, only: [:create_dir]
+ feature_category :source_code_management
+
def show
return render_404 unless @commit
diff --git a/app/controllers/projects/triggers_controller.rb b/app/controllers/projects/triggers_controller.rb
index 7159d0243a3..eec35fcec8d 100644
--- a/app/controllers/projects/triggers_controller.rb
+++ b/app/controllers/projects/triggers_controller.rb
@@ -8,6 +8,8 @@ class Projects::TriggersController < Projects::ApplicationController
layout 'project_settings'
+ feature_category :continuous_integration
+
def index
redirect_to project_settings_ci_cd_path(@project, anchor: 'js-pipeline-triggers')
end
diff --git a/app/controllers/projects/uploads_controller.rb b/app/controllers/projects/uploads_controller.rb
index 72251988b5e..c15768e7bbb 100644
--- a/app/controllers/projects/uploads_controller.rb
+++ b/app/controllers/projects/uploads_controller.rb
@@ -11,6 +11,8 @@ class Projects::UploadsController < Projects::ApplicationController
before_action :authorize_upload_file!, only: [:create, :authorize]
before_action :verify_workhorse_api!, only: [:authorize]
+ feature_category :not_owned
+
private
def upload_model_class
diff --git a/app/controllers/projects/usage_ping_controller.rb b/app/controllers/projects/usage_ping_controller.rb
index 0e2c8f879b1..9b4ddb326c1 100644
--- a/app/controllers/projects/usage_ping_controller.rb
+++ b/app/controllers/projects/usage_ping_controller.rb
@@ -3,6 +3,8 @@
class Projects::UsagePingController < Projects::ApplicationController
before_action :authenticate_user!
+ feature_category :collection
+
def web_ide_clientside_preview
return render_404 unless Gitlab::CurrentSettings.web_ide_clientside_preview_enabled?
diff --git a/app/controllers/projects/variables_controller.rb b/app/controllers/projects/variables_controller.rb
index 0fd047f90cf..d8efc1b7b54 100644
--- a/app/controllers/projects/variables_controller.rb
+++ b/app/controllers/projects/variables_controller.rb
@@ -3,6 +3,8 @@
class Projects::VariablesController < Projects::ApplicationController
before_action :authorize_admin_build!
+ feature_category :continuous_integration
+
def show
respond_to do |format|
format.json do
diff --git a/app/controllers/projects/web_ide_schemas_controller.rb b/app/controllers/projects/web_ide_schemas_controller.rb
index 3d16a6fafd4..84a191815f4 100644
--- a/app/controllers/projects/web_ide_schemas_controller.rb
+++ b/app/controllers/projects/web_ide_schemas_controller.rb
@@ -3,6 +3,8 @@
class Projects::WebIdeSchemasController < Projects::ApplicationController
before_action :authenticate_user!
+ feature_category :web_ide
+
def show
return respond_422 unless branch_sha
diff --git a/app/controllers/projects/web_ide_terminals_controller.rb b/app/controllers/projects/web_ide_terminals_controller.rb
index 76bcaa9e80c..1d179765ad9 100644
--- a/app/controllers/projects/web_ide_terminals_controller.rb
+++ b/app/controllers/projects/web_ide_terminals_controller.rb
@@ -8,6 +8,8 @@ class Projects::WebIdeTerminalsController < Projects::ApplicationController
before_action :authorize_read_web_ide_terminal!, except: [:check_config, :create]
before_action :authorize_update_web_ide_terminal!, only: [:cancel, :retry]
+ feature_category :web_ide
+
def check_config
return respond_422 unless branch_sha
diff --git a/app/controllers/projects/wikis_controller.rb b/app/controllers/projects/wikis_controller.rb
index d0aa733cadb..8f794512486 100644
--- a/app/controllers/projects/wikis_controller.rb
+++ b/app/controllers/projects/wikis_controller.rb
@@ -5,6 +5,8 @@ class Projects::WikisController < Projects::ApplicationController
alias_method :container, :project
+ feature_category :wiki
+
def git_access
end
end
diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb
index 848625ff6b5..09e7563cefd 100644
--- a/app/controllers/projects_controller.rb
+++ b/app/controllers/projects_controller.rb
@@ -37,7 +37,7 @@ class ProjectsController < Projects::ApplicationController
# Experiments
before_action only: [:new, :create] do
frontend_experimentation_tracking_data(:new_create_project_ui, 'click_tab')
- push_frontend_feature_flag(:new_create_project_ui) if experiment_enabled?(:new_create_project_ui)
+ push_frontend_experiment(:new_create_project_ui)
end
before_action only: [:edit] do
@@ -47,6 +47,17 @@ class ProjectsController < Projects::ApplicationController
layout :determine_layout
+ feature_category :projects, [
+ :index, :show, :new, :create, :edit, :update, :transfer,
+ :destroy, :resolve, :archive, :unarchive, :toggle_star
+ ]
+
+ feature_category :source_code_management, [:remove_fork, :housekeeping, :refs]
+ feature_category :issue_tracking, [:preview_markdown, :new_issuable_address]
+ feature_category :importers, [:export, :remove_export, :generate_new_export, :download_export]
+ feature_category :audit_events, [:activity]
+ feature_category :code_review, [:unfoldered_environment_names]
+
def index
redirect_to(current_user ? root_path : explore_root_path)
end
@@ -305,6 +316,16 @@ class ProjectsController < Projects::ApplicationController
end
end
+ def unfoldered_environment_names
+ return render_404 unless Feature.enabled?(:deployment_filters)
+
+ respond_to do |format|
+ format.json do
+ render json: EnvironmentNamesFinder.new(@project, current_user).execute
+ end
+ end
+ end
+
private
# Render project landing depending of which features are available
diff --git a/app/controllers/registrations/experience_levels_controller.rb b/app/controllers/registrations/experience_levels_controller.rb
index 38cffff91eb..23126983eb5 100644
--- a/app/controllers/registrations/experience_levels_controller.rb
+++ b/app/controllers/registrations/experience_levels_controller.rb
@@ -7,12 +7,20 @@ module Registrations
before_action :check_experiment_enabled
before_action :ensure_namespace_path_param
+ feature_category :navigation
+
def update
current_user.experience_level = params[:experience_level]
if current_user.save
hide_advanced_issues
- redirect_to group_path(params[:namespace_path])
+ record_experiment_user(:default_to_issues_board)
+
+ if experiment_enabled?(:default_to_issues_board) && learn_gitlab.available?
+ redirect_to namespace_project_board_path(params[:namespace_path], learn_gitlab.project, learn_gitlab.board)
+ else
+ redirect_to group_path(params[:namespace_path])
+ end
else
render :show
end
diff --git a/app/controllers/registrations_controller.rb b/app/controllers/registrations_controller.rb
index 204520a3e71..b3dc0e986f4 100644
--- a/app/controllers/registrations_controller.rb
+++ b/app/controllers/registrations_controller.rb
@@ -6,19 +6,19 @@ class RegistrationsController < Devise::RegistrationsController
include RecaptchaExperimentHelper
include InvisibleCaptchaOnSignup
+ BLOCKED_PENDING_APPROVAL_STATE = 'blocked_pending_approval'.freeze
+
layout :choose_layout
skip_before_action :required_signup_info, :check_two_factor_requirement, only: [:welcome, :update_registration]
prepend_before_action :check_captcha, only: :create
before_action :whitelist_query_limiting, :ensure_destroy_prerequisites_met, only: [:destroy]
- before_action :ensure_terms_accepted,
- if: -> { action_name == 'create' && Gitlab::CurrentSettings.current_application_settings.enforce_terms? }
before_action :load_recaptcha, only: :new
+ feature_category :authentication_and_authorization
+
def new
if experiment_enabled?(:signup_flow)
- track_experiment_event(:terms_opt_in, 'start')
-
@resource = build_resource
else
redirect_to new_user_session_path(anchor: 'register-pane')
@@ -26,18 +26,18 @@ class RegistrationsController < Devise::RegistrationsController
end
def create
+ set_user_state
accept_pending_invitations
super do |new_user|
persist_accepted_terms_if_required(new_user)
set_role_required(new_user)
- track_terms_experiment(new_user)
yield new_user if block_given?
end
- # Devise sets a flash message on `create` for a successful signup,
- # which we don't want to show.
- flash[:notice] = nil
+ # Devise sets a flash message on both successful & failed signups,
+ # but we only want to show a message if the resource is blocked by a pending approval.
+ flash[:notice] = nil unless resource.blocked_pending_approval?
rescue Gitlab::Access::AccessDeniedError
redirect_to(new_user_session_path)
end
@@ -58,6 +58,8 @@ class RegistrationsController < Devise::RegistrationsController
end
def update_registration
+ return redirect_to new_user_registration_path unless current_user
+
user_params = params.require(:user).permit(:role, :setup_for_company)
result = ::Users::SignupService.new(current_user, user_params).execute
@@ -81,10 +83,8 @@ class RegistrationsController < Devise::RegistrationsController
return unless new_user.persisted?
return unless Gitlab::CurrentSettings.current_application_settings.enforce_terms?
- if terms_accepted?
- terms = ApplicationSetting::Term.latest
- Users::RespondToTermsService.new(new_user, terms).execute(accepted: true)
- end
+ terms = ApplicationSetting::Term.latest
+ Users::RespondToTermsService.new(new_user, terms).execute(accepted: true)
end
def set_role_required(new_user)
@@ -119,6 +119,8 @@ class RegistrationsController < Devise::RegistrationsController
def after_inactive_sign_up_path_for(resource)
Gitlab::AppLogger.info(user_created_message)
+ return new_user_session_path(anchor: 'login-pane') if resource.blocked_pending_approval?
+
Feature.enabled?(:soft_email_confirmation) ? dashboard_projects_path : users_almost_there_path
end
@@ -178,18 +180,6 @@ class RegistrationsController < Devise::RegistrationsController
Gitlab::QueryLimiting.whitelist('https://gitlab.com/gitlab-org/gitlab-foss/issues/42380')
end
- def ensure_terms_accepted
- return if terms_accepted?
-
- redirect_to new_user_session_path, alert: _('You must accept our Terms of Service and privacy policy in order to register an account')
- end
-
- def terms_accepted?
- return true if experiment_enabled?(:terms_opt_in)
-
- Gitlab::Utils.to_boolean(params[:terms_opt_in])
- end
-
def path_for_signed_in_user(user)
if requires_confirmation?(user)
users_almost_there_path
@@ -206,13 +196,6 @@ class RegistrationsController < Devise::RegistrationsController
true
end
- def track_terms_experiment(new_user)
- return unless new_user.persisted?
-
- track_experiment_event(:terms_opt_in, 'end')
- record_experiment_user(:terms_opt_in)
- end
-
def load_recaptcha
Gitlab::Recaptcha.load_configurations!
end
@@ -233,6 +216,13 @@ class RegistrationsController < Devise::RegistrationsController
!helpers.in_oauth_flow? &&
!helpers.in_trial_flow?
end
+
+ def set_user_state
+ return unless Feature.enabled?(:admin_approval_for_new_user_signups, default_enabled: true)
+ return unless Gitlab::CurrentSettings.require_admin_approval_after_user_signup
+
+ resource.state = BLOCKED_PENDING_APPROVAL_STATE
+ end
end
RegistrationsController.prepend_if_ee('EE::RegistrationsController')
diff --git a/app/controllers/repositories/git_http_client_controller.rb b/app/controllers/repositories/git_http_client_controller.rb
index e02955433b2..de452aa69b7 100644
--- a/app/controllers/repositories/git_http_client_controller.rb
+++ b/app/controllers/repositories/git_http_client_controller.rb
@@ -20,6 +20,8 @@ module Repositories
prepend_before_action :authenticate_user, :parse_repo_path
+ feature_category :source_code_management
+
private
def download_request?
diff --git a/app/controllers/runner_setup_controller.rb b/app/controllers/runner_setup_controller.rb
new file mode 100644
index 00000000000..e0e9c5b7c23
--- /dev/null
+++ b/app/controllers/runner_setup_controller.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+class RunnerSetupController < ApplicationController
+ feature_category :continuous_integration
+
+ def platforms
+ render json: Gitlab::Ci::RunnerInstructions::OS.merge(Gitlab::Ci::RunnerInstructions::OTHER_ENVIRONMENTS)
+ end
+end
diff --git a/app/controllers/search_controller.rb b/app/controllers/search_controller.rb
index dedaf0c903a..0380bc1c548 100644
--- a/app/controllers/search_controller.rb
+++ b/app/controllers/search_controller.rb
@@ -8,7 +8,8 @@ class SearchController < ApplicationController
SCOPE_PRELOAD_METHOD = {
projects: :with_web_entity_associations,
- issues: :with_web_entity_associations
+ issues: :with_web_entity_associations,
+ epics: :with_web_entity_associations
}.freeze
track_redis_hll_event :show, name: 'i_search_total', feature: :search_track_unique_users, feature_default_enabled: true
@@ -24,6 +25,8 @@ class SearchController < ApplicationController
layout 'search'
+ feature_category :global_search
+
def show
@project = search_service.project
@group = search_service.group
@@ -38,6 +41,7 @@ class SearchController < ApplicationController
@show_snippets = search_service.show_snippets?
@search_results = search_service.search_results
@search_objects = search_service.search_objects(preload_method)
+ @search_highlight = search_service.search_highlight
render_commits if @scope == 'commits'
eager_load_user_status if @scope == 'users'
@@ -96,8 +100,6 @@ class SearchController < ApplicationController
end
def eager_load_user_status
- return if Feature.disabled?(:users_search, default_enabled: true)
-
@search_objects = @search_objects.eager_load(:status) # rubocop:disable CodeReuse/ActiveRecord
end
diff --git a/app/controllers/sent_notifications_controller.rb b/app/controllers/sent_notifications_controller.rb
index 20134de81a0..db07b212d00 100644
--- a/app/controllers/sent_notifications_controller.rb
+++ b/app/controllers/sent_notifications_controller.rb
@@ -3,6 +3,8 @@
class SentNotificationsController < ApplicationController
skip_before_action :authenticate_user!
+ feature_category :users
+
def unsubscribe
@sent_notification = SentNotification.for(params[:id])
diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb
index 318553b5e0a..61120c5b7d1 100644
--- a/app/controllers/sessions_controller.rb
+++ b/app/controllers/sessions_controller.rb
@@ -49,6 +49,8 @@ class SessionsController < Devise::SessionsController
# token mismatch.
protect_from_forgery with: :exception, prepend: true, except: :destroy
+ feature_category :authentication_and_authorization
+
CAPTCHA_HEADER = 'X-GitLab-Show-Login-Captcha'
MAX_FAILED_LOGIN_ATTEMPTS = 5
@@ -262,8 +264,11 @@ class SessionsController < Devise::SessionsController
end
def valid_otp_attempt?(user)
- user.validate_and_consume_otp!(user_params[:otp_attempt]) ||
- user.invalidate_otp_backup_code!(user_params[:otp_attempt])
+ otp_validation_result =
+ ::Users::ValidateOtpService.new(user).execute(user_params[:otp_attempt])
+ return true if otp_validation_result[:status] == :success
+
+ user.invalidate_otp_backup_code!(user_params[:otp_attempt])
end
def log_audit_event(user, resource, options = {})
diff --git a/app/controllers/snippets/application_controller.rb b/app/controllers/snippets/application_controller.rb
index a533e46a75d..f259f4569ef 100644
--- a/app/controllers/snippets/application_controller.rb
+++ b/app/controllers/snippets/application_controller.rb
@@ -4,6 +4,8 @@ class Snippets::ApplicationController < ApplicationController
include FindSnippet
include SnippetAuthorizations
+ feature_category :snippets
+
private
def authorize_read_snippet!
diff --git a/app/controllers/snippets/notes_controller.rb b/app/controllers/snippets/notes_controller.rb
index a7e8ef0798b..8532257cb8d 100644
--- a/app/controllers/snippets/notes_controller.rb
+++ b/app/controllers/snippets/notes_controller.rb
@@ -8,6 +8,8 @@ class Snippets::NotesController < ApplicationController
before_action :authorize_read_snippet!, only: [:show, :index]
before_action :authorize_create_note!, only: [:create]
+ feature_category :snippets
+
private
def note
diff --git a/app/controllers/snippets_controller.rb b/app/controllers/snippets_controller.rb
index 486c7f1d028..913b1e3bb6e 100644
--- a/app/controllers/snippets_controller.rb
+++ b/app/controllers/snippets_controller.rb
@@ -6,21 +6,16 @@ class SnippetsController < Snippets::ApplicationController
include ToggleAwardEmoji
include SpammableActions
- before_action :snippet, only: [:show, :edit, :destroy, :update, :raw, :toggle_award_emoji, :mark_as_spam]
+ before_action :snippet, only: [:show, :edit, :raw, :toggle_award_emoji, :mark_as_spam]
- before_action :authorize_create_snippet!, only: [:new, :create]
+ before_action :authorize_create_snippet!, only: :new
before_action :authorize_read_snippet!, only: [:show, :raw]
- before_action :authorize_update_snippet!, only: [:edit, :update]
- before_action :authorize_admin_snippet!, only: [:destroy]
+ before_action :authorize_update_snippet!, only: :edit
skip_before_action :authenticate_user!, only: [:index, :show, :raw]
layout 'snippets'
- before_action do
- push_frontend_feature_flag(:snippet_multiple_files, current_user)
- end
-
def index
if params[:username].present?
@user = UserFinder.new(params[:username]).find_by_username!
@@ -44,18 +39,6 @@ class SnippetsController < Snippets::ApplicationController
@snippet = PersonalSnippet.new
end
- def create
- create_params = snippet_params.merge(files: params.delete(:files))
- service_response = Snippets::CreateService.new(nil, current_user, create_params).execute
- @snippet = service_response.payload[:snippet]
-
- if service_response.error? && @snippet.errors[:repository].present?
- handle_repository_error(:new)
- else
- recaptcha_check_with_fallback { render :new }
- end
- end
-
protected
alias_method :awardable, :snippet
@@ -64,8 +47,4 @@ class SnippetsController < Snippets::ApplicationController
def spammable_path
snippet_path(@snippet)
end
-
- def snippet_params
- params.require(:personal_snippet).permit(:title, :content, :file_name, :private, :visibility_level, :description).merge(spammable_params)
- end
end
diff --git a/app/controllers/uploads_controller.rb b/app/controllers/uploads_controller.rb
index 9510734bc9b..6692c285335 100644
--- a/app/controllers/uploads_controller.rb
+++ b/app/controllers/uploads_controller.rb
@@ -25,6 +25,8 @@ class UploadsController < ApplicationController
before_action :authorize_create_access!, only: [:create, :authorize]
before_action :verify_workhorse_api!, only: [:authorize]
+ feature_category :not_owned
+
def uploader_class
PersonalFileUploader
end
diff --git a/app/controllers/user_callouts_controller.rb b/app/controllers/user_callouts_controller.rb
index 06f422b9d90..cfec9d6d905 100644
--- a/app/controllers/user_callouts_controller.rb
+++ b/app/controllers/user_callouts_controller.rb
@@ -1,6 +1,8 @@
# frozen_string_literal: true
class UserCalloutsController < ApplicationController
+ feature_category :navigation
+
def create
callout = ensure_callout
diff --git a/app/controllers/users/terms_controller.rb b/app/controllers/users/terms_controller.rb
index 231e449f733..be670658048 100644
--- a/app/controllers/users/terms_controller.rb
+++ b/app/controllers/users/terms_controller.rb
@@ -14,6 +14,8 @@ module Users
layout 'terms'
+ feature_category :users
+
def index
@redirect = redirect_path
diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb
index 75a861423ed..672f36dedc0 100644
--- a/app/controllers/users_controller.rb
+++ b/app/controllers/users_controller.rb
@@ -21,6 +21,8 @@ class UsersController < ApplicationController
before_action :authorize_read_user_profile!,
only: [:calendar, :calendar_activities, :groups, :projects, :contributed_projects, :starred_projects, :snippets]
+ feature_category :users
+
def show
respond_to do |format|
format.html
@@ -106,7 +108,7 @@ class UsersController < ApplicationController
def calendar_activities
@calendar_date = Date.parse(params[:date]) rescue Date.today
- @events = contributions_calendar.events_by_date(@calendar_date)
+ @events = contributions_calendar.events_by_date(@calendar_date).map(&:present)
render 'calendar_activities', layout: false
end
diff --git a/app/controllers/whats_new_controller.rb b/app/controllers/whats_new_controller.rb
new file mode 100644
index 00000000000..7156faa4e49
--- /dev/null
+++ b/app/controllers/whats_new_controller.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+class WhatsNewController < ApplicationController
+ include Gitlab::WhatsNew
+
+ skip_before_action :authenticate_user!
+
+ before_action :check_feature_flag
+
+ feature_category :navigation
+
+ def index
+ respond_to do |format|
+ format.js do
+ render json: whats_new_most_recent_release_items
+ end
+ end
+ end
+
+ private
+
+ def check_feature_flag
+ render_404 unless Feature.enabled?(:whats_new_drawer, current_user)
+ end
+end
diff --git a/app/finders/README.md b/app/finders/README.md
index 1a1c69dea38..52f7378c484 100644
--- a/app/finders/README.md
+++ b/app/finders/README.md
@@ -1,10 +1,11 @@
# Finders
-This type of classes responsible for collection items based on different conditions.
-To prevent lookup methods in models like this:
+These types of classes are responsible for retrieving collection items based on different conditions.
+They prevent lookup methods in models like this:
+
```ruby
-class Project
+class Project < ApplicationRecord
def issues_for_user_filtered_by(user, filter)
# A lot of logic not related to project model itself
end
@@ -13,10 +14,10 @@ end
issues = project.issues_for_user_filtered_by(user, params)
```
-Better use this:
+The GitLab approach is to use a Finder:
```ruby
issues = IssuesFinder.new(project, user, filter).execute
```
-It will help keep models thiner.
+It will help keep models thinner.
diff --git a/app/finders/alert_management/alerts_finder.rb b/app/finders/alert_management/alerts_finder.rb
index cb35be43c15..1d6f790af31 100644
--- a/app/finders/alert_management/alerts_finder.rb
+++ b/app/finders/alert_management/alerts_finder.rb
@@ -2,8 +2,8 @@
module AlertManagement
class AlertsFinder
- # @return [Hash<Integer,Integer>] Mapping of status id to count
- # ex) { 0: 6, ...etc }
+ # @return [Hash<Symbol,Integer>] Mapping of status id to count
+ # ex) { triggered: 6, ...etc }
def self.counts_by_status(current_user, project, params = {})
new(current_user, project, params).execute.counts_by_status
end
@@ -19,8 +19,10 @@ module AlertManagement
collection = project.alert_management_alerts
collection = by_status(collection)
- collection = by_search(collection)
collection = by_iid(collection)
+ collection = by_assignee(collection)
+ collection = by_search(collection)
+
sort(collection)
end
@@ -35,7 +37,7 @@ module AlertManagement
end
def by_status(collection)
- values = AlertManagement::Alert::STATUSES.values & Array(params[:status])
+ values = AlertManagement::Alert.status_names & Array(params[:status])
values.present? ? collection.for_status(values) : collection
end
@@ -48,6 +50,10 @@ module AlertManagement
params[:sort] ? collection.sort_by_attribute(params[:sort]) : collection
end
+ def by_assignee(collection)
+ params[:assignee_username].present? ? collection.for_assignee_username(params[:assignee_username]) : collection
+ end
+
def authorized?
Ability.allowed?(current_user, :read_alert_management_alert, project)
end
diff --git a/app/finders/ci/jobs_finder.rb b/app/finders/ci/jobs_finder.rb
index 8515b77ec0b..40c610f8209 100644
--- a/app/finders/ci/jobs_finder.rb
+++ b/app/finders/ci/jobs_finder.rb
@@ -25,7 +25,7 @@ module Ci
attr_reader :current_user, :pipeline, :project, :params, :type
def init_collection
- if Feature.enabled?(:ci_jobs_finder_refactor)
+ if Feature.enabled?(:ci_jobs_finder_refactor, default_enabled: true)
pipeline_jobs || project_jobs || all_jobs
else
project ? project_builds : all_jobs
@@ -59,7 +59,7 @@ module Ci
end
def filter_by_scope(builds)
- if Feature.enabled?(:ci_jobs_finder_refactor)
+ if Feature.enabled?(:ci_jobs_finder_refactor, default_enabled: true)
return filter_by_statuses!(params[:scope], builds) if params[:scope].is_a?(Array)
end
diff --git a/app/finders/concerns/time_frame_filter.rb b/app/finders/concerns/time_frame_filter.rb
index e0baba25b64..d1ebed730f6 100644
--- a/app/finders/concerns/time_frame_filter.rb
+++ b/app/finders/concerns/time_frame_filter.rb
@@ -11,4 +11,11 @@ module TimeFrameFilter
rescue ArgumentError
items
end
+
+ def containing_date(items)
+ return items unless params[:containing_date]
+
+ date = params[:containing_date].to_date
+ items.within_timeframe(date, date)
+ end
end
diff --git a/app/finders/environment_names_finder.rb b/app/finders/environment_names_finder.rb
new file mode 100644
index 00000000000..a92998921c7
--- /dev/null
+++ b/app/finders/environment_names_finder.rb
@@ -0,0 +1,47 @@
+# frozen_string_literal: true
+
+# Finder for obtaining the unique environment names of a project or group.
+#
+# This finder exists so that the merge requests "environments" filter can be
+# populated with a unique list of environment names. If we retrieve _just_ the
+# environments, duplicates may be present (e.g. multiple projects in a group
+# having a "staging" environment).
+#
+# In addition, this finder only produces unfoldered environments. We do this
+# because when searching for environments we want to exclude review app
+# environments.
+class EnvironmentNamesFinder
+ attr_reader :project_or_group, :current_user
+
+ def initialize(project_or_group, current_user)
+ @project_or_group = project_or_group
+ @current_user = current_user
+ end
+
+ def execute
+ all_environments.unfoldered.order_by_name.pluck_unique_names
+ end
+
+ def all_environments
+ if project_or_group.is_a?(Namespace)
+ namespace_environments
+ else
+ project_environments
+ end
+ end
+
+ def namespace_environments
+ projects =
+ project_or_group.all_projects.public_or_visible_to_user(current_user)
+
+ Environment.for_project(projects)
+ end
+
+ def project_environments
+ if current_user.can?(:read_environment, project_or_group)
+ project_or_group.environments
+ else
+ Environment.none
+ end
+ end
+end
diff --git a/app/finders/group_labels_finder.rb b/app/finders/group_labels_finder.rb
deleted file mode 100644
index a668a0f0fae..00000000000
--- a/app/finders/group_labels_finder.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-# frozen_string_literal: true
-
-class GroupLabelsFinder
- attr_reader :current_user, :group, :params
-
- def initialize(current_user, group, params = {})
- @current_user = current_user
- @group = group
- @params = params
- end
-
- def execute
- group.labels
- .optionally_subscribed_by(subscriber_id)
- .optionally_search(params[:search])
- .order_by(params[:sort])
- .page(params[:page])
- end
-
- private
-
- def subscriber_id
- current_user&.id if subscribed?
- end
-
- def subscribed?
- params[:subscribed] == 'true'
- end
-end
diff --git a/app/finders/group_members_finder.rb b/app/finders/group_members_finder.rb
index ce0d52ad97a..09283f061c0 100644
--- a/app/finders/group_members_finder.rb
+++ b/app/finders/group_members_finder.rb
@@ -17,9 +17,8 @@ class GroupMembersFinder < UnionFinder
@params = params
end
- # rubocop: disable CodeReuse/ActiveRecord
def execute(include_relations: [:inherited, :direct])
- group_members = group.members
+ group_members = group_members_list
relations = []
return group_members if include_relations == [:direct]
@@ -27,17 +26,13 @@ class GroupMembersFinder < UnionFinder
relations << group_members if include_relations.include?(:direct)
if include_relations.include?(:inherited) && group.parent
- parents_members = GroupMember.non_request.non_minimal_access
- .where(source_id: group.ancestors.select(:id))
- .where.not(user_id: group.users.select(:id))
+ parents_members = relation_group_members(group.ancestors)
relations << parents_members
end
if include_relations.include?(:descendants)
- descendant_members = GroupMember.non_request.non_minimal_access
- .where(source_id: group.descendants.select(:id))
- .where.not(user_id: group.users.select(:id))
+ descendant_members = relation_group_members(group.descendants)
relations << descendant_members
end
@@ -47,7 +42,6 @@ class GroupMembersFinder < UnionFinder
members = find_union(relations, GroupMember)
filter_members(members)
end
- # rubocop: enable CodeReuse/ActiveRecord
private
@@ -67,6 +61,22 @@ class GroupMembersFinder < UnionFinder
def can_manage_members
Ability.allowed?(user, :admin_group_member, group)
end
+
+ def group_members_list
+ group.members
+ end
+
+ def relation_group_members(relation)
+ all_group_members(relation).non_minimal_access
+ end
+
+ # rubocop: disable CodeReuse/ActiveRecord
+ def all_group_members(relation)
+ GroupMember.non_request
+ .where(source_id: relation.select(:id))
+ .where.not(user_id: group.users.select(:id))
+ end
+ # rubocop: enable CodeReuse/ActiveRecord
end
GroupMembersFinder.prepend_if_ee('EE::GroupMembersFinder')
diff --git a/app/finders/groups_finder.rb b/app/finders/groups_finder.rb
index 54715557399..4b6b2716c64 100644
--- a/app/finders/groups_finder.rb
+++ b/app/finders/groups_finder.rb
@@ -12,6 +12,8 @@
# all_available: boolean (defaults to true)
# min_access_level: integer
# exclude_group_ids: array of integers
+# include_parent_descendants: boolean (defaults to false) - includes descendant groups when
+# filtering by parent. The parent param must be present.
#
# Users with full private access can see all groups. The `owned` and `parent`
# params can be used to restrict the groups that are returned.
@@ -84,7 +86,11 @@ class GroupsFinder < UnionFinder
def by_parent(groups)
return groups unless params[:parent]
- groups.where(parent: params[:parent])
+ if include_parent_descendants?
+ groups.id_in(params[:parent].descendants)
+ else
+ groups.where(parent: params[:parent])
+ end
end
# rubocop: enable CodeReuse/ActiveRecord
@@ -100,6 +106,10 @@ class GroupsFinder < UnionFinder
params.fetch(:all_available, true)
end
+ def include_parent_descendants?
+ params.fetch(:include_parent_descendants, false)
+ end
+
def min_access_level?
current_user && params[:min_access_level].present?
end
diff --git a/app/finders/issuable_finder.rb b/app/finders/issuable_finder.rb
index f13dc8c2451..9c4aecedd93 100644
--- a/app/finders/issuable_finder.rb
+++ b/app/finders/issuable_finder.rb
@@ -102,7 +102,7 @@ class IssuableFinder
items = filter_items(items)
# Let's see if we have to negate anything
- items = filter_negated_items(items)
+ items = filter_negated_items(items) if should_filter_negated_args?
# This has to be last as we use a CTE as an optimization fence
# for counts by passing the force_cte param and passing the
@@ -134,13 +134,15 @@ class IssuableFinder
by_my_reaction_emoji(items)
end
- # Negates all params found in `negatable_params`
- def filter_negated_items(items)
- return items unless Feature.enabled?(:not_issuable_queries, params.group || params.project, default_enabled: true)
+ def should_filter_negated_args?
+ return false unless Feature.enabled?(:not_issuable_queries, params.group || params.project, default_enabled: true)
# API endpoints send in `nil` values so we test if there are any non-nil
- return items unless not_params.present? && not_params.values.any?
+ not_params.present? && not_params.values.any?
+ end
+ # Negates all params found in `negatable_params`
+ def filter_negated_items(items)
items = by_negated_author(items)
items = by_negated_assignee(items)
items = by_negated_label(items)
@@ -151,7 +153,11 @@ class IssuableFinder
end
def row_count
- Gitlab::IssuablesCountForState.new(self).for_state_or_opened(params[:state])
+ fast_fail = Feature.enabled?(:soft_fail_count_by_state, params.group || params.project)
+
+ Gitlab::IssuablesCountForState
+ .new(self, nil, fast_fail: fast_fail)
+ .for_state_or_opened(params[:state])
end
# We often get counts for each state by running a query per state, and
diff --git a/app/finders/keys_finder.rb b/app/finders/keys_finder.rb
index e7e78d71a58..9c357e12205 100644
--- a/app/finders/keys_finder.rb
+++ b/app/finders/keys_finder.rb
@@ -1,5 +1,7 @@
# frozen_string_literal: true
class KeysFinder
+ delegate :find, :find_by_id, to: :execute
+
InvalidFingerprint = Class.new(StandardError)
GitLabAccessDeniedError = Class.new(StandardError)
diff --git a/app/finders/merge_requests/by_approvals_finder.rb b/app/finders/merge_requests/by_approvals_finder.rb
new file mode 100644
index 00000000000..e6ab1467f06
--- /dev/null
+++ b/app/finders/merge_requests/by_approvals_finder.rb
@@ -0,0 +1,93 @@
+# frozen_string_literal: true
+
+module MergeRequests
+ # Used to filter MergeRequest collections by approvers
+ class ByApprovalsFinder
+ attr_reader :usernames, :ids
+
+ # We apply a limitation to the amount of elements that can be part of the filter condition
+ MAX_FILTER_ELEMENTS = 5
+
+ # Initialize the finder
+ #
+ # @param [Array<String>] usernames
+ # @param [Array<Integers>] ids
+ def initialize(usernames, ids)
+ # rubocop:disable CodeReuse/ActiveRecord
+ @usernames = Array(usernames).map(&:to_s).uniq.take(MAX_FILTER_ELEMENTS)
+ @ids = Array(ids).uniq.take(MAX_FILTER_ELEMENTS)
+ # rubocop:enable CodeReuse/ActiveRecord
+ end
+
+ # Filter MergeRequest collections by approvers
+ #
+ # @param [ActiveRecord::Relation] items the activerecord relation
+ def execute(items)
+ if by_no_approvals?
+ without_approvals(items)
+ elsif by_any_approvals?
+ with_any_approvals(items)
+ elsif ids.present?
+ find_approved_by_ids(items)
+ elsif usernames.present?
+ find_approved_by_names(items)
+ else
+ items
+ end
+ end
+
+ private
+
+ # Is param using special condition: "None" ?
+ #
+ # @return [Boolean] whether special condition "None" is being used
+ def by_no_approvals?
+ includes_special_label?(IssuableFinder::Params::FILTER_NONE)
+ end
+
+ # Is param using special condition: "Any" ?
+ #
+ # @return [Boolean] whether special condition "Any" is being used
+ def by_any_approvals?
+ includes_special_label?(IssuableFinder::Params::FILTER_ANY)
+ end
+
+ # Check if we have the special label in ids or usernames field
+ #
+ # @param [String] label the special label
+ # @return [Boolean] whether ids or usernames includes the special label
+ def includes_special_label?(label)
+ ids.first.to_s.downcase == label || usernames.map(&:downcase).include?(label)
+ end
+
+ # Merge Requests without any approval
+ #
+ # @param [ActiveRecord::Relation] items
+ def without_approvals(items)
+ items.without_approvals
+ end
+
+ # Merge Requests with any number of approvals
+ #
+ # @param [ActiveRecord::Relation] items the activerecord relation
+ def with_any_approvals(items)
+ items.select_from_union([
+ items.with_approvals
+ ])
+ end
+
+ # Merge Requests approved by given usernames
+ #
+ # @param [ActiveRecord::Relation] items the activerecord relation
+ def find_approved_by_names(items)
+ items.approved_by_users_with_usernames(*usernames)
+ end
+
+ # Merge Requests approved by given user IDs
+ #
+ # @param [ActiveRecord::Relation] items the activerecord relation
+ def find_approved_by_ids(items)
+ items.approved_by_users_with_ids(*ids)
+ end
+ end
+end
diff --git a/app/finders/merge_requests_finder.rb b/app/finders/merge_requests_finder.rb
index 37da29b32ff..c998de75ab2 100644
--- a/app/finders/merge_requests_finder.rb
+++ b/app/finders/merge_requests_finder.rb
@@ -33,7 +33,21 @@ class MergeRequestsFinder < IssuableFinder
include MergedAtFilter
def self.scalar_params
- @scalar_params ||= super + [:wip, :draft, :target_branch, :merged_after, :merged_before]
+ @scalar_params ||= super + [
+ :approved_by_ids,
+ :deployed_after,
+ :deployed_before,
+ :draft,
+ :environment,
+ :merged_after,
+ :merged_before,
+ :target_branch,
+ :wip
+ ]
+ end
+
+ def self.array_params
+ @array_params ||= super.merge(approved_by_usernames: [])
end
def klass
@@ -42,11 +56,13 @@ class MergeRequestsFinder < IssuableFinder
def filter_items(_items)
items = by_commit(super)
- items = by_deployment(items)
items = by_source_branch(items)
items = by_draft(items)
items = by_target_branch(items)
items = by_merged_at(items)
+ items = by_approvals(items)
+ items = by_deployments(items)
+
by_source_project_id(items)
end
@@ -80,17 +96,21 @@ class MergeRequestsFinder < IssuableFinder
items.where(target_branch: target_branch)
end
+ # rubocop: enable CodeReuse/ActiveRecord
def source_project_id
@source_project_id ||= params[:source_project_id].presence
end
+ # rubocop: disable CodeReuse/ActiveRecord
def by_source_project_id(items)
return items unless source_project_id
items.where(source_project_id: source_project_id)
end
+ # rubocop: enable CodeReuse/ActiveRecord
+ # rubocop: disable CodeReuse/ActiveRecord
def by_draft(items)
draft_param = params[:draft] || params[:wip]
@@ -102,6 +122,7 @@ class MergeRequestsFinder < IssuableFinder
items
end
end
+ # rubocop: enable CodeReuse/ActiveRecord
# WIP is deprecated in favor of Draft. Currently both options are supported
def wip_match(table)
@@ -121,16 +142,54 @@ class MergeRequestsFinder < IssuableFinder
.or(table[:title].matches('(Draft)%'))
end
+ # rubocop: disable CodeReuse/ActiveRecord
def by_deployment(items)
return items unless deployment_id
items.includes(:deployment_merge_requests)
.where(deployment_merge_requests: { deployment_id: deployment_id })
end
+ # rubocop: enable CodeReuse/ActiveRecord
def deployment_id
@deployment_id ||= params[:deployment_id].presence
end
+
+ # Filter by merge requests that had been approved by specific users
+ # rubocop: disable CodeReuse/Finder
+ def by_approvals(items)
+ MergeRequests::ByApprovalsFinder
+ .new(params[:approved_by_usernames], params[:approved_by_ids])
+ .execute(items)
+ end
+ # rubocop: enable CodeReuse/Finder
+
+ def by_deployments(items)
+ # Until this feature flag is enabled permanently, we retain the old
+ # filtering behaviour/code.
+ return by_deployment(items) unless Feature.enabled?(:deployment_filters)
+
+ env = params[:environment]
+ before = params[:deployed_before]
+ after = params[:deployed_after]
+ id = params[:deployment_id]
+
+ return items if !env && !before && !after && !id
+
+ # Each filter depends on the same JOIN+WHERE. To prevent this JOIN+WHERE
+ # from being duplicated for every filter, we only produce it once. The
+ # filter methods in turn expect the JOIN+WHERE to already be present.
+ #
+ # This approach ensures that query performance doesn't degrade as the number
+ # of deployment related filters increases.
+ deploys = DeploymentMergeRequest.join_deployments_for_merge_requests
+ deploys = deploys.by_deployment_id(id) if id
+ deploys = deploys.deployed_to(env) if env
+ deploys = deploys.deployed_before(before) if before
+ deploys = deploys.deployed_after(after) if after
+
+ items.where_exists(deploys)
+ end
end
MergeRequestsFinder.prepend_if_ee('EE::MergeRequestsFinder')
diff --git a/app/finders/milestones_finder.rb b/app/finders/milestones_finder.rb
index 16e59b31b36..5d2a54ac979 100644
--- a/app/finders/milestones_finder.rb
+++ b/app/finders/milestones_finder.rb
@@ -9,6 +9,8 @@
# order - Orders by field default due date asc.
# title - filter by title.
# state - filters by state.
+# start_date & end_date - filters by timeframe (see TimeFrameFilter)
+# containing_date - filters by point in time (see TimeFrameFilter)
class MilestonesFinder
include FinderMethods
@@ -28,6 +30,7 @@ class MilestonesFinder
items = by_search_title(items)
items = by_state(items)
items = by_timeframe(items)
+ items = containing_date(items)
order(items)
end
diff --git a/app/finders/packages/generic/package_finder.rb b/app/finders/packages/generic/package_finder.rb
new file mode 100644
index 00000000000..3a260e11fa3
--- /dev/null
+++ b/app/finders/packages/generic/package_finder.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+module Packages
+ module Generic
+ class PackageFinder
+ def initialize(project)
+ @project = project
+ end
+
+ def execute!(package_name, package_version)
+ project
+ .packages
+ .generic
+ .by_name_and_version!(package_name, package_version)
+ end
+
+ private
+
+ attr_reader :project
+ end
+ end
+end
diff --git a/app/finders/projects_finder.rb b/app/finders/projects_finder.rb
index 471029c1ef9..14b84d0bfa6 100644
--- a/app/finders/projects_finder.rb
+++ b/app/finders/projects_finder.rb
@@ -50,7 +50,12 @@ class ProjectsFinder < UnionFinder
use_cte = params.delete(:use_cte)
collection = Project.wrap_with_cte(collection) if use_cte
collection = filter_projects(collection)
- sort(collection)
+
+ if params[:sort] == 'similarity' && params[:search] && Feature.enabled?(:project_finder_similarity_sort)
+ collection.sorted_by_similarity_desc(params[:search])
+ else
+ sort(collection)
+ end
end
private
@@ -209,7 +214,11 @@ class ProjectsFinder < UnionFinder
end
def sort(items)
- params[:sort].present? ? items.sort_by_attribute(params[:sort]) : items.projects_order_id_desc
+ if params[:sort].present?
+ items.sort_by_attribute(params[:sort])
+ else
+ items.projects_order_id_desc
+ end
end
def by_archived(projects)
diff --git a/app/finders/releases_finder.rb b/app/finders/releases_finder.rb
index e961ad4c0ca..da72178169e 100644
--- a/app/finders/releases_finder.rb
+++ b/app/finders/releases_finder.rb
@@ -9,6 +9,9 @@ class ReleasesFinder
@parent = parent
@current_user = current_user
@params = params
+
+ params[:order_by] ||= 'released_at'
+ params[:sort] ||= 'desc'
end
def execute(preload: true)
@@ -17,7 +20,8 @@ class ReleasesFinder
releases = get_releases
releases = by_tag(releases)
releases = releases.preloaded if preload
- releases.sorted
+ releases = order_releases(releases)
+ releases
end
private
@@ -57,4 +61,8 @@ class ReleasesFinder
releases.where(tag: params[:tag])
end
# rubocop: enable CodeReuse/ActiveRecord
+
+ def order_releases(releases)
+ releases.sort_by_attribute("#{params[:order_by]}_#{params[:sort]}")
+ end
end
diff --git a/app/graphql/batch_loaders/merge_request_diff_summary_batch_loader.rb b/app/graphql/batch_loaders/merge_request_diff_summary_batch_loader.rb
new file mode 100644
index 00000000000..9b8737a6703
--- /dev/null
+++ b/app/graphql/batch_loaders/merge_request_diff_summary_batch_loader.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+module BatchLoaders
+ class MergeRequestDiffSummaryBatchLoader
+ NIL_STATS = { additions: 0, deletions: 0, file_count: 0 }.freeze
+
+ def self.load_for(merge_request)
+ BatchLoader::GraphQL.for(merge_request).batch(key: :diff_stats_summary) do |merge_requests, loader, args|
+ Preloaders::MergeRequestDiffPreloader.new(merge_requests).preload_all
+
+ merge_requests.each do |merge_request|
+ metrics = merge_request.metrics
+
+ summary = if metrics && metrics.added_lines && metrics.removed_lines
+ { additions: metrics.added_lines, deletions: metrics.removed_lines, file_count: merge_request.merge_request_diff&.files_count || 0 }
+ elsif merge_request.diff_stats.blank?
+ NIL_STATS
+ else
+ merge_request.diff_stats.each_with_object(NIL_STATS.dup) do |status, summary|
+ summary.merge!(additions: status.additions, deletions: status.deletions, file_count: 1) { |_, x, y| x + y }
+ end
+ end
+
+ loader.call(merge_request, summary)
+ end
+ end
+ end
+ end
+end
diff --git a/app/graphql/mutations/award_emojis/base.rb b/app/graphql/mutations/award_emojis/base.rb
index 583744c3884..df6b883529e 100644
--- a/app/graphql/mutations/award_emojis/base.rb
+++ b/app/graphql/mutations/award_emojis/base.rb
@@ -6,7 +6,7 @@ module Mutations
authorize :award_emoji
argument :awardable_id,
- GraphQL::ID_TYPE,
+ ::Types::GlobalIDType[::Awardable],
required: true,
description: 'The global id of the awardable resource'
@@ -23,7 +23,10 @@ module Mutations
private
def find_object(id:)
- GitlabSchema.object_from_id(id)
+ # TODO: remove this line when the compatibility layer is removed
+ # See: https://gitlab.com/gitlab-org/gitlab/-/issues/257883
+ id = ::Types::GlobalIDType[::Awardable].coerce_isolated_input(id)
+ GitlabSchema.find_by_gid(id)
end
# Called by mutations methods after performing an authorization check
diff --git a/app/graphql/mutations/base_mutation.rb b/app/graphql/mutations/base_mutation.rb
index 577f10545b3..ac5ddc5bd4c 100644
--- a/app/graphql/mutations/base_mutation.rb
+++ b/app/graphql/mutations/base_mutation.rb
@@ -4,6 +4,7 @@ module Mutations
class BaseMutation < GraphQL::Schema::RelayClassicMutation
prepend Gitlab::Graphql::Authorize::AuthorizeResource
prepend Gitlab::Graphql::CopyFieldDescription
+ prepend ::Gitlab::Graphql::GlobalIDCompatibility
ERROR_MESSAGE = 'You cannot perform write operations on a read-only instance'
diff --git a/app/graphql/mutations/boards/create.rb b/app/graphql/mutations/boards/create.rb
new file mode 100644
index 00000000000..e381205242e
--- /dev/null
+++ b/app/graphql/mutations/boards/create.rb
@@ -0,0 +1,78 @@
+# frozen_string_literal: true
+
+module Mutations
+ module Boards
+ class Create < ::Mutations::BaseMutation
+ include Mutations::ResolvesGroup
+ include ResolvesProject
+
+ graphql_name 'CreateBoard'
+
+ field :board,
+ Types::BoardType,
+ null: true,
+ description: 'The board after mutation.'
+
+ argument :project_path, GraphQL::ID_TYPE,
+ required: false,
+ description: 'The project full path the board is associated with.'
+ argument :group_path, GraphQL::ID_TYPE,
+ required: false,
+ description: 'The group full path the board is associated with.'
+ argument :name,
+ GraphQL::STRING_TYPE,
+ required: false,
+ description: 'The board name.'
+ argument :assignee_id,
+ GraphQL::STRING_TYPE,
+ required: false,
+ description: 'The ID of the user to be assigned to the board.'
+ argument :milestone_id,
+ GraphQL::ID_TYPE,
+ required: false,
+ description: 'The ID of the milestone to be assigned to the board.'
+ argument :weight,
+ GraphQL::BOOLEAN_TYPE,
+ required: false,
+ description: 'The weight of the board.'
+ argument :label_ids,
+ [GraphQL::ID_TYPE],
+ required: false,
+ description: 'The IDs of labels to be added to the board.'
+
+ authorize :admin_board
+
+ def resolve(args)
+ group_path = args.delete(:group_path)
+ project_path = args.delete(:project_path)
+
+ board_parent = authorized_find!(group_path: group_path, project_path: project_path)
+ response = ::Boards::CreateService.new(board_parent, current_user, args).execute
+
+ {
+ board: response.payload,
+ errors: response.errors
+ }
+ end
+
+ def ready?(**args)
+ if args.values_at(:project_path, :group_path).compact.blank?
+ raise Gitlab::Graphql::Errors::ArgumentError,
+ 'group_path or project_path arguments are required'
+ end
+
+ super
+ end
+
+ private
+
+ def find_object(group_path: nil, project_path: nil)
+ if group_path
+ resolve_group(full_path: group_path)
+ else
+ resolve_project(full_path: project_path)
+ end
+ end
+ end
+ end
+end
diff --git a/app/graphql/mutations/boards/lists/destroy.rb b/app/graphql/mutations/boards/lists/destroy.rb
new file mode 100644
index 00000000000..61ffae7c047
--- /dev/null
+++ b/app/graphql/mutations/boards/lists/destroy.rb
@@ -0,0 +1,41 @@
+# frozen_string_literal: true
+
+module Mutations
+ module Boards
+ module Lists
+ class Destroy < ::Mutations::BaseMutation
+ graphql_name 'DestroyBoardList'
+
+ field :list,
+ Types::BoardListType,
+ null: true,
+ description: 'The list after mutation.'
+
+ argument :list_id, ::Types::GlobalIDType[::List],
+ required: true,
+ loads: Types::BoardListType,
+ description: 'Global ID of the list to destroy. Only label lists are accepted.'
+
+ def resolve(list:)
+ raise_resource_not_available_error! unless can_admin_list?(list)
+
+ response = ::Boards::Lists::DestroyService.new(list.board.resource_parent, current_user)
+ .execute(list)
+
+ {
+ list: response.success? ? nil : list,
+ errors: response.errors
+ }
+ end
+
+ private
+
+ def can_admin_list?(list)
+ return false unless list.present?
+
+ Ability.allowed?(current_user, :admin_list, list.board)
+ end
+ end
+ end
+ end
+end
diff --git a/app/graphql/mutations/ci/base.rb b/app/graphql/mutations/ci/base.rb
index 09df4487a50..aaece2a3021 100644
--- a/app/graphql/mutations/ci/base.rb
+++ b/app/graphql/mutations/ci/base.rb
@@ -3,13 +3,18 @@
module Mutations
module Ci
class Base < BaseMutation
- argument :id, ::Types::GlobalIDType[::Ci::Pipeline],
+ PipelineID = ::Types::GlobalIDType[::Ci::Pipeline]
+
+ argument :id, PipelineID,
required: true,
description: 'The id of the pipeline to mutate'
private
def find_object(id:)
+ # TODO: remove this line when the compatibility layer is removed
+ # See: https://gitlab.com/gitlab-org/gitlab/-/issues/257883
+ id = PipelineID.coerce_isolated_input(id)
GlobalID::Locator.locate(id)
end
end
diff --git a/app/graphql/mutations/concerns/mutations/spammable_mutation_fields.rb b/app/graphql/mutations/concerns/mutations/spammable_mutation_fields.rb
new file mode 100644
index 00000000000..7aef55f8011
--- /dev/null
+++ b/app/graphql/mutations/concerns/mutations/spammable_mutation_fields.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+module Mutations
+ module SpammableMutationFields
+ extend ActiveSupport::Concern
+
+ included do
+ field :spam,
+ GraphQL::BOOLEAN_TYPE,
+ null: true,
+ description: 'Indicates whether the operation returns a record detected as spam'
+ end
+
+ def with_spam_params(&block)
+ request = Feature.enabled?(:snippet_spam) ? context[:request] : nil
+
+ yield.merge({ api: true, request: request })
+ end
+
+ def with_spam_fields(spammable, &block)
+ { spam: spammable.spam? }.merge!(yield)
+ end
+ end
+end
diff --git a/app/graphql/mutations/design_management/move.rb b/app/graphql/mutations/design_management/move.rb
index 6126af8b68b..aed4cfec0fd 100644
--- a/app/graphql/mutations/design_management/move.rb
+++ b/app/graphql/mutations/design_management/move.rb
@@ -21,7 +21,7 @@ module Mutations
description: "The current state of the collection"
def resolve(**args)
- service = ::DesignManagement::MoveDesignsService.new(current_user, parameters(args))
+ service = ::DesignManagement::MoveDesignsService.new(current_user, parameters(**args))
{ design_collection: service.collection, errors: service.execute.errors }
end
@@ -29,11 +29,18 @@ module Mutations
private
def parameters(**args)
- args.transform_values { |id| GitlabSchema.find_by_gid(id) }.transform_values(&:sync).tap do |hash|
+ args.transform_values { |id| find_design(id) }.transform_values(&:sync).tap do |hash|
hash.each { |k, design| not_found(args[k]) unless current_user.can?(:read_design, design) }
end
end
+ def find_design(id)
+ # TODO: remove this line when the compatibility layer is removed
+ # See: https://gitlab.com/gitlab-org/gitlab/-/issues/257883
+ id = DesignID.coerce_isolated_input(id)
+ GitlabSchema.find_by_gid(id)
+ end
+
def not_found(gid)
raise Gitlab::Graphql::Errors::ResourceNotAvailable, "Resource not available: #{gid}"
end
diff --git a/app/graphql/mutations/discussions/toggle_resolve.rb b/app/graphql/mutations/discussions/toggle_resolve.rb
index 41fd22c6b55..4492da74706 100644
--- a/app/graphql/mutations/discussions/toggle_resolve.rb
+++ b/app/graphql/mutations/discussions/toggle_resolve.rb
@@ -8,7 +8,7 @@ module Mutations
description 'Toggles the resolved state of a discussion'
argument :id,
- GraphQL::ID_TYPE,
+ Types::GlobalIDType[Discussion],
required: true,
description: 'The global id of the discussion'
@@ -54,7 +54,10 @@ module Mutations
end
def find_object(id:)
- GitlabSchema.object_from_id(id, expected_type: ::Discussion)
+ # TODO: remove explicit coercion once compatibility layer has been removed
+ # See: https://gitlab.com/gitlab-org/gitlab/-/issues/257883
+ id = Types::GlobalIDType[Discussion].coerce_isolated_input(id)
+ GitlabSchema.find_by_gid(id)
end
def resolve!(discussion)
diff --git a/app/graphql/mutations/issues/common_mutation_arguments.rb b/app/graphql/mutations/issues/common_mutation_arguments.rb
new file mode 100644
index 00000000000..4b5b246281f
--- /dev/null
+++ b/app/graphql/mutations/issues/common_mutation_arguments.rb
@@ -0,0 +1,28 @@
+# frozen_string_literal: true
+
+module Mutations
+ module Issues
+ module CommonMutationArguments
+ extend ActiveSupport::Concern
+
+ included do
+ argument :description, GraphQL::STRING_TYPE,
+ required: false,
+ description: copy_field_description(Types::IssueType, :description)
+
+ argument :due_date, GraphQL::Types::ISO8601Date,
+ required: false,
+ description: copy_field_description(Types::IssueType, :due_date)
+
+ argument :confidential, GraphQL::BOOLEAN_TYPE,
+ required: false,
+ description: copy_field_description(Types::IssueType, :confidential)
+
+ argument :locked, GraphQL::BOOLEAN_TYPE,
+ as: :discussion_locked,
+ required: false,
+ description: copy_field_description(Types::IssueType, :discussion_locked)
+ end
+ end
+ end
+end
diff --git a/app/graphql/mutations/issues/create.rb b/app/graphql/mutations/issues/create.rb
new file mode 100644
index 00000000000..1454916bc77
--- /dev/null
+++ b/app/graphql/mutations/issues/create.rb
@@ -0,0 +1,109 @@
+# frozen_string_literal: true
+
+module Mutations
+ module Issues
+ class Create < BaseMutation
+ include ResolvesProject
+ graphql_name 'CreateIssue'
+
+ authorize :create_issue
+
+ include CommonMutationArguments
+
+ argument :project_path, GraphQL::ID_TYPE,
+ required: true,
+ description: 'Project full path the issue is associated with'
+
+ argument :iid, GraphQL::INT_TYPE,
+ required: false,
+ description: 'The IID (internal ID) of a project issue. Only admins and project owners can modify'
+
+ argument :title, GraphQL::STRING_TYPE,
+ required: true,
+ description: copy_field_description(Types::IssueType, :title)
+
+ argument :milestone_id, ::Types::GlobalIDType[::Milestone],
+ required: false,
+ description: 'The ID of the milestone to assign to the issue. On update milestone will be removed if set to null'
+
+ argument :labels, [GraphQL::STRING_TYPE],
+ required: false,
+ description: copy_field_description(Types::IssueType, :labels)
+
+ argument :label_ids, [::Types::GlobalIDType[::Label]],
+ required: false,
+ description: 'The IDs of labels to be added to the issue'
+
+ argument :created_at, Types::TimeType,
+ required: false,
+ description: 'Timestamp when the issue was created. Available only for admins and project owners'
+
+ argument :merge_request_to_resolve_discussions_of, ::Types::GlobalIDType[::MergeRequest],
+ required: false,
+ description: 'The IID of a merge request for which to resolve discussions'
+
+ argument :discussion_to_resolve, GraphQL::STRING_TYPE,
+ required: false,
+ description: 'The ID of a discussion to resolve. Also pass `merge_request_to_resolve_discussions_of`'
+
+ argument :assignee_ids, [::Types::GlobalIDType[::User]],
+ required: false,
+ description: 'The array of user IDs to assign to the issue'
+
+ field :issue,
+ Types::IssueType,
+ null: true,
+ description: 'The issue after mutation'
+
+ def ready?(**args)
+ if args.slice(*mutually_exclusive_label_args).size > 1
+ arg_str = mutually_exclusive_label_args.map { |x| x.to_s.camelize(:lower) }.join(' or ')
+ raise Gitlab::Graphql::Errors::ArgumentError, "one and only one of #{arg_str} is required."
+ end
+
+ if args[:discussion_to_resolve].present? && args[:merge_request_to_resolve_discussions_of].blank?
+ raise Gitlab::Graphql::Errors::ArgumentError,
+ 'to resolve a discussion please also provide `merge_request_to_resolve_discussions_of` parameter'
+ end
+
+ super
+ end
+
+ def resolve(project_path:, **attributes)
+ project = authorized_find!(full_path: project_path)
+ params = build_create_issue_params(attributes.merge(author_id: current_user.id))
+
+ issue = ::Issues::CreateService.new(project, current_user, params).execute
+
+ if issue.spam?
+ issue.errors.add(:base, 'Spam detected.')
+ end
+
+ {
+ issue: issue.valid? ? issue : nil,
+ errors: errors_on_object(issue)
+ }
+ end
+
+ private
+
+ def build_create_issue_params(params)
+ params[:milestone_id] &&= params[:milestone_id]&.model_id
+ params[:assignee_ids] &&= params[:assignee_ids].map { |assignee_id| assignee_id&.model_id }
+ params[:label_ids] &&= params[:label_ids].map { |label_id| label_id&.model_id }
+
+ params
+ end
+
+ def mutually_exclusive_label_args
+ [:labels, :label_ids]
+ end
+
+ def find_object(full_path:)
+ resolve_project(full_path: full_path)
+ end
+ end
+ end
+end
+
+Mutations::Issues::Create.prepend_if_ee('::EE::Mutations::Issues::Create')
diff --git a/app/graphql/mutations/issues/move.rb b/app/graphql/mutations/issues/move.rb
new file mode 100644
index 00000000000..e6971c9df8c
--- /dev/null
+++ b/app/graphql/mutations/issues/move.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+module Mutations
+ module Issues
+ class Move < Base
+ graphql_name 'IssueMove'
+
+ argument :target_project_path,
+ GraphQL::ID_TYPE,
+ required: true,
+ description: 'The project to move the issue to'
+
+ def resolve(project_path:, iid:, target_project_path:)
+ Gitlab::QueryLimiting.whitelist('https://gitlab.com/gitlab-org/gitlab/-/issues/267762')
+
+ issue = authorized_find!(project_path: project_path, iid: iid)
+ source_project = issue.project
+ target_project = resolve_project(full_path: target_project_path).sync
+
+ begin
+ moved_issue = ::Issues::MoveService.new(source_project, current_user).execute(issue, target_project)
+ rescue ::Issues::MoveService::MoveError => error
+ errors = error.message
+ end
+
+ {
+ issue: moved_issue,
+ errors: Array.wrap(errors)
+ }
+ end
+ end
+ end
+end
diff --git a/app/graphql/mutations/issues/update.rb b/app/graphql/mutations/issues/update.rb
index cc03d32731b..9b216b31f9b 100644
--- a/app/graphql/mutations/issues/update.rb
+++ b/app/graphql/mutations/issues/update.rb
@@ -5,46 +5,27 @@ module Mutations
class Update < Base
graphql_name 'UpdateIssue'
- argument :title,
- GraphQL::STRING_TYPE,
- required: false,
- description: copy_field_description(Types::IssueType, :title)
+ include CommonMutationArguments
- argument :description,
- GraphQL::STRING_TYPE,
- required: false,
- description: copy_field_description(Types::IssueType, :description)
-
- argument :due_date,
- Types::TimeType,
- required: false,
- description: copy_field_description(Types::IssueType, :due_date)
-
- argument :confidential,
- GraphQL::BOOLEAN_TYPE,
+ argument :title, GraphQL::STRING_TYPE,
required: false,
- description: copy_field_description(Types::IssueType, :confidential)
+ description: copy_field_description(Types::IssueType, :title)
- argument :locked,
- GraphQL::BOOLEAN_TYPE,
- as: :discussion_locked,
+ argument :milestone_id, GraphQL::ID_TYPE,
required: false,
- description: copy_field_description(Types::IssueType, :discussion_locked)
+ description: 'The ID of the milestone to assign to the issue. On update milestone will be removed if set to null'
- argument :add_label_ids,
- [GraphQL::ID_TYPE],
+ argument :add_label_ids, [GraphQL::ID_TYPE],
required: false,
- description: 'The IDs of labels to be added to the issue.'
+ description: 'The IDs of labels to be added to the issue'
- argument :remove_label_ids,
- [GraphQL::ID_TYPE],
+ argument :remove_label_ids, [GraphQL::ID_TYPE],
required: false,
- description: 'The IDs of labels to be removed from the issue.'
+ description: 'The IDs of labels to be removed from the issue'
- argument :milestone_id,
- GraphQL::ID_TYPE,
- required: false,
- description: 'The ID of the milestone to be assigned, milestone will be removed if set to null.'
+ argument :state_event, Types::IssueStateEventEnum,
+ description: 'Close or reopen an issue',
+ required: false
def resolve(project_path:, iid:, **args)
issue = authorized_find!(project_path: project_path, iid: iid)
diff --git a/app/graphql/mutations/merge_requests/set_milestone.rb b/app/graphql/mutations/merge_requests/set_milestone.rb
index b3412dd9ed2..abcb1bda1f3 100644
--- a/app/graphql/mutations/merge_requests/set_milestone.rb
+++ b/app/graphql/mutations/merge_requests/set_milestone.rb
@@ -6,7 +6,7 @@ module Mutations
graphql_name 'MergeRequestSetMilestone'
argument :milestone_id,
- GraphQL::ID_TYPE,
+ ::Types::GlobalIDType[::Milestone],
required: false,
loads: Types::MilestoneType,
description: <<~DESC
diff --git a/app/graphql/mutations/metrics/dashboard/annotations/create.rb b/app/graphql/mutations/metrics/dashboard/annotations/create.rb
index f99688aeac6..b064f55825f 100644
--- a/app/graphql/mutations/metrics/dashboard/annotations/create.rb
+++ b/app/graphql/mutations/metrics/dashboard/annotations/create.rb
@@ -18,12 +18,12 @@ module Mutations
description: 'The created annotation'
argument :environment_id,
- GraphQL::ID_TYPE,
+ ::Types::GlobalIDType[::Environment],
required: false,
description: 'The global id of the environment to add an annotation to'
argument :cluster_id,
- GraphQL::ID_TYPE,
+ ::Types::GlobalIDType[::Clusters::Cluster],
required: false,
description: 'The global id of the cluster to add an annotation to'
@@ -80,11 +80,11 @@ module Mutations
raise Gitlab::Graphql::Errors::ArgumentError, ANNOTATION_SOURCE_ARGUMENT_ERROR
end
- super(args)
+ super(**args)
end
def find_object(id:)
- GitlabSchema.object_from_id(id)
+ GitlabSchema.find_by_gid(id)
end
def annotation_create_params(args)
@@ -96,7 +96,16 @@ module Mutations
end
def annotation_source(args)
- annotation_source_id = args[:cluster_id] || args[:environment_id]
+ # TODO: remove these lines when the compatibility layer is removed
+ # See: https://gitlab.com/gitlab-org/gitlab/-/issues/257883
+ annotation_source_id = if args[:cluster_id]
+ ::Types::GlobalIDType[::Clusters::Cluster].coerce_isolated_input(args[:cluster_id])
+ else
+ ::Types::GlobalIDType[::Environment].coerce_isolated_input(args[:environment_id])
+ end
+
+ # TODO: uncomment following line once lines above are removed
+ # annotation_source_id = args[:cluster_id] || args[:environment_id]
authorized_find!(id: annotation_source_id)
end
end
diff --git a/app/graphql/mutations/notes/base.rb b/app/graphql/mutations/notes/base.rb
index 31dabc0a660..f2678211335 100644
--- a/app/graphql/mutations/notes/base.rb
+++ b/app/graphql/mutations/notes/base.rb
@@ -11,21 +11,10 @@ module Mutations
private
def find_object(id:)
- GitlabSchema.object_from_id(id)
- end
-
- def check_object_is_noteable!(object)
- unless object.is_a?(Noteable)
- raise Gitlab::Graphql::Errors::ResourceNotAvailable,
- 'Cannot add notes to this resource'
- end
- end
-
- def check_object_is_note!(object)
- unless object.is_a?(Note)
- raise Gitlab::Graphql::Errors::ResourceNotAvailable,
- 'Resource is not a note'
- end
+ # TODO: remove explicit coercion once compatibility layer has been removed
+ # See: https://gitlab.com/gitlab-org/gitlab/-/issues/257883
+ id = ::Types::GlobalIDType[::Note].coerce_isolated_input(id)
+ GitlabSchema.find_by_gid(id)
end
end
end
diff --git a/app/graphql/mutations/notes/create/base.rb b/app/graphql/mutations/notes/create/base.rb
index f081eac368e..3cfdaf84760 100644
--- a/app/graphql/mutations/notes/create/base.rb
+++ b/app/graphql/mutations/notes/create/base.rb
@@ -9,7 +9,7 @@ module Mutations
authorize :create_note
argument :noteable_id,
- GraphQL::ID_TYPE,
+ ::Types::GlobalIDType[::Noteable],
required: true,
description: 'The global id of the resource to add a note to'
@@ -26,8 +26,6 @@ module Mutations
def resolve(args)
noteable = authorized_find!(id: args[:noteable_id])
- check_object_is_noteable!(noteable)
-
note = ::Notes::CreateService.new(
noteable.project,
current_user,
@@ -42,6 +40,13 @@ module Mutations
private
+ def find_object(id:)
+ # TODO: remove explicit coercion once compatibility layer has been removed
+ # See: https://gitlab.com/gitlab-org/gitlab/-/issues/257883
+ id = ::Types::GlobalIDType[::Noteable].coerce_isolated_input(id)
+ GitlabSchema.find_by_gid(id)
+ end
+
def create_note_params(noteable, args)
{
noteable: noteable,
diff --git a/app/graphql/mutations/notes/create/note.rb b/app/graphql/mutations/notes/create/note.rb
index 5236e48026e..e97037171f7 100644
--- a/app/graphql/mutations/notes/create/note.rb
+++ b/app/graphql/mutations/notes/create/note.rb
@@ -7,7 +7,7 @@ module Mutations
graphql_name 'CreateNote'
argument :discussion_id,
- GraphQL::ID_TYPE,
+ ::Types::GlobalIDType[::Discussion],
required: false,
description: 'The global id of the discussion this note is in reply to'
@@ -17,7 +17,11 @@ module Mutations
discussion_id = nil
if args[:discussion_id]
- discussion = GitlabSchema.object_from_id(args[:discussion_id])
+ # TODO: remove this line when the compatibility layer is removed
+ # See: https://gitlab.com/gitlab-org/gitlab/-/issues/257883
+ discussion_gid = ::Types::GlobalIDType[::Discussion].coerce_isolated_input(args[:discussion_id])
+ discussion = GitlabSchema.find_by_gid(discussion_gid)
+
authorize_discussion!(discussion)
discussion_id = discussion.id
diff --git a/app/graphql/mutations/notes/destroy.rb b/app/graphql/mutations/notes/destroy.rb
index a81322bc9b7..63e5eeb5ecf 100644
--- a/app/graphql/mutations/notes/destroy.rb
+++ b/app/graphql/mutations/notes/destroy.rb
@@ -8,15 +8,13 @@ module Mutations
authorize :admin_note
argument :id,
- GraphQL::ID_TYPE,
- required: true,
- description: 'The global id of the note to destroy'
+ ::Types::GlobalIDType[::Note],
+ required: true,
+ description: 'The global id of the note to destroy'
def resolve(id:)
note = authorized_find!(id: id)
- check_object_is_note!(note)
-
::Notes::DestroyService.new(note.project, current_user).execute(note)
{
diff --git a/app/graphql/mutations/notes/update/base.rb b/app/graphql/mutations/notes/update/base.rb
index 8a2a78a29ec..1d5738ada77 100644
--- a/app/graphql/mutations/notes/update/base.rb
+++ b/app/graphql/mutations/notes/update/base.rb
@@ -9,7 +9,7 @@ module Mutations
authorize :admin_note
argument :id,
- GraphQL::ID_TYPE,
+ ::Types::GlobalIDType[::Note],
required: true,
description: 'The global id of the note to update'
diff --git a/app/graphql/mutations/notes/update/image_diff_note.rb b/app/graphql/mutations/notes/update/image_diff_note.rb
index 7aad3af1e04..ef70a8d2bf4 100644
--- a/app/graphql/mutations/notes/update/image_diff_note.rb
+++ b/app/graphql/mutations/notes/update/image_diff_note.rb
@@ -28,12 +28,12 @@ module Mutations
'body or position arguments are required'
end
- super(args)
+ super(**args)
end
private
- def pre_update_checks!(note, args)
+ def pre_update_checks!(note, _args)
unless note.is_a?(DiffNote) && note.position.on_image?
raise Gitlab::Graphql::Errors::ResourceNotAvailable,
'Resource is not an ImageDiffNote'
diff --git a/app/graphql/mutations/notes/update/note.rb b/app/graphql/mutations/notes/update/note.rb
index ca97dad6ded..73b9b9bc49a 100644
--- a/app/graphql/mutations/notes/update/note.rb
+++ b/app/graphql/mutations/notes/update/note.rb
@@ -18,8 +18,8 @@ module Mutations
private
- def pre_update_checks!(note, _args)
- check_object_is_note!(note)
+ def pre_update_checks!(_note, _args)
+ # no-op
end
end
end
diff --git a/app/graphql/mutations/snippets/create.rb b/app/graphql/mutations/snippets/create.rb
index a8aeb15afcd..37c0f80310c 100644
--- a/app/graphql/mutations/snippets/create.rb
+++ b/app/graphql/mutations/snippets/create.rb
@@ -3,6 +3,7 @@
module Mutations
module Snippets
class Create < BaseMutation
+ include SpammableMutationFields
include ResolvesProject
graphql_name 'CreateSnippet'
@@ -56,10 +57,12 @@ module Mutations
::Gitlab::UsageDataCounters::EditorUniqueCounter.track_snippet_editor_edit_action(author: current_user)
end
- {
- snippet: service_response.success? ? snippet : nil,
- errors: errors_on_object(snippet)
- }
+ with_spam_fields(snippet) do
+ {
+ snippet: service_response.success? ? snippet : nil,
+ errors: errors_on_object(snippet)
+ }
+ end
end
private
@@ -81,14 +84,16 @@ module Mutations
end
def create_params(args)
- args.tap do |create_args|
- # We need to rename `blob_actions` into `snippet_actions` because
- # it's the expected key param
- create_args[:snippet_actions] = create_args.delete(:blob_actions)&.map(&:to_h)
-
- # We need to rename `uploaded_files` into `files` because
- # it's the expected key param
- create_args[:files] = create_args.delete(:uploaded_files)
+ with_spam_params do
+ args.tap do |create_args|
+ # We need to rename `blob_actions` into `snippet_actions` because
+ # it's the expected key param
+ create_args[:snippet_actions] = create_args.delete(:blob_actions)&.map(&:to_h)
+
+ # We need to rename `uploaded_files` into `files` because
+ # it's the expected key param
+ create_args[:files] = create_args.delete(:uploaded_files)
+ end
end
end
end
diff --git a/app/graphql/mutations/snippets/update.rb b/app/graphql/mutations/snippets/update.rb
index d0db5fa2eb9..74266880806 100644
--- a/app/graphql/mutations/snippets/update.rb
+++ b/app/graphql/mutations/snippets/update.rb
@@ -3,6 +3,8 @@
module Mutations
module Snippets
class Update < Base
+ include SpammableMutationFields
+
graphql_name 'UpdateSnippet'
argument :id,
@@ -39,10 +41,12 @@ module Mutations
::Gitlab::UsageDataCounters::EditorUniqueCounter.track_snippet_editor_edit_action(author: current_user)
end
- {
- snippet: result.success? ? snippet : snippet.reset,
- errors: errors_on_object(snippet)
- }
+ with_spam_fields(snippet) do
+ {
+ snippet: result.success? ? snippet : snippet.reset,
+ errors: errors_on_object(snippet)
+ }
+ end
end
private
@@ -52,10 +56,12 @@ module Mutations
end
def update_params(args)
- args.tap do |update_args|
- # We need to rename `blob_actions` into `snippet_actions` because
- # it's the expected key param
- update_args[:snippet_actions] = update_args.delete(:blob_actions)&.map(&:to_h)
+ with_spam_params do
+ args.tap do |update_args|
+ # We need to rename `blob_actions` into `snippet_actions` because
+ # it's the expected key param
+ update_args[:snippet_actions] = update_args.delete(:blob_actions)&.map(&:to_h)
+ end
end
end
end
diff --git a/app/graphql/mutations/todos/base.rb b/app/graphql/mutations/todos/base.rb
index 2a72019fbac..6db863796bc 100644
--- a/app/graphql/mutations/todos/base.rb
+++ b/app/graphql/mutations/todos/base.rb
@@ -6,7 +6,10 @@ module Mutations
private
def find_object(id:)
- GitlabSchema.object_from_id(id)
+ # TODO: remove this line when the compatibility layer is removed
+ # See: https://gitlab.com/gitlab-org/gitlab/-/issues/257883
+ id = ::Types::GlobalIDType[::Todo].coerce_isolated_input(id)
+ GitlabSchema.find_by_gid(id)
end
def map_to_global_ids(ids)
@@ -16,7 +19,7 @@ module Mutations
end
def to_global_id(id)
- ::URI::GID.build(app: GlobalID.app, model_name: Todo.name, model_id: id, params: nil).to_s
+ Gitlab::GlobalId.as_global_id(id, model_name: Todo.name).to_s
end
end
end
diff --git a/app/graphql/mutations/todos/mark_done.rb b/app/graphql/mutations/todos/mark_done.rb
index 748e02d8782..3d73022f266 100644
--- a/app/graphql/mutations/todos/mark_done.rb
+++ b/app/graphql/mutations/todos/mark_done.rb
@@ -8,7 +8,7 @@ module Mutations
authorize :update_todo
argument :id,
- GraphQL::ID_TYPE,
+ ::Types::GlobalIDType[::Todo],
required: true,
description: 'The global id of the todo to mark as done'
diff --git a/app/graphql/mutations/todos/restore.rb b/app/graphql/mutations/todos/restore.rb
index a0a1772db0a..7c8f92d32f5 100644
--- a/app/graphql/mutations/todos/restore.rb
+++ b/app/graphql/mutations/todos/restore.rb
@@ -8,7 +8,7 @@ module Mutations
authorize :update_todo
argument :id,
- GraphQL::ID_TYPE,
+ ::Types::GlobalIDType[::Todo],
required: true,
description: 'The global id of the todo to restore'
diff --git a/app/graphql/mutations/todos/restore_many.rb b/app/graphql/mutations/todos/restore_many.rb
index c5e2750768c..ea5f5414134 100644
--- a/app/graphql/mutations/todos/restore_many.rb
+++ b/app/graphql/mutations/todos/restore_many.rb
@@ -8,7 +8,7 @@ module Mutations
MAX_UPDATE_AMOUNT = 50
argument :ids,
- [GraphQL::ID_TYPE],
+ [::Types::GlobalIDType[::Todo]],
required: true,
description: 'The global ids of the todos to restore (a maximum of 50 is supported at once)'
@@ -37,24 +37,18 @@ module Mutations
private
def gids_of(ids)
- ids.map { |id| ::URI::GID.build(app: GlobalID.app, model_name: Todo.name, model_id: id, params: nil).to_s }
+ ids.map { |id| Gitlab::GlobalId.as_global_id(id, model_name: Todo.name).to_s }
end
def model_ids_of(ids)
ids.map do |gid|
- parsed_gid = ::URI::GID.parse(gid)
- parsed_gid.model_id.to_i if accessible_todo?(parsed_gid)
+ # TODO: remove this line when the compatibility layer is removed
+ # See: https://gitlab.com/gitlab-org/gitlab/-/issues/257883
+ gid = ::Types::GlobalIDType[::Todo].coerce_isolated_input(gid)
+ gid.model_id.to_i
end.compact
end
- def accessible_todo?(gid)
- gid.app == GlobalID.app && todo?(gid)
- end
-
- def todo?(gid)
- GlobalID.parse(gid)&.model_class&.ancestors&.include?(Todo)
- end
-
def raise_too_many_todos_requested_error
raise Gitlab::Graphql::Errors::ArgumentError, 'Too many todos requested.'
end
diff --git a/app/graphql/queries/repository/path_last_commit.query.graphql b/app/graphql/queries/repository/path_last_commit.query.graphql
new file mode 100644
index 00000000000..d845f7c6224
--- /dev/null
+++ b/app/graphql/queries/repository/path_last_commit.query.graphql
@@ -0,0 +1,47 @@
+query pathLastCommit($projectPath: ID!, $path: String, $ref: String!) {
+ project(fullPath: $projectPath) {
+ __typename
+ repository {
+ __typename
+ tree(path: $path, ref: $ref) {
+ __typename
+ lastCommit {
+ __typename
+ sha
+ title
+ titleHtml
+ descriptionHtml
+ message
+ webPath
+ authoredDate
+ authorName
+ authorGravatar
+ author {
+ __typename
+ name
+ avatarUrl
+ webPath
+ }
+ signatureHtml
+ pipelines(ref: $ref, first: 1) {
+ __typename
+ edges {
+ __typename
+ node {
+ __typename
+ detailedStatus {
+ __typename
+ detailsPath
+ icon
+ tooltip
+ text
+ group
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/app/graphql/resolvers/alert_management/alert_resolver.rb b/app/graphql/resolvers/alert_management/alert_resolver.rb
index 71a7615685a..dc9b1dbb5f4 100644
--- a/app/graphql/resolvers/alert_management/alert_resolver.rb
+++ b/app/graphql/resolvers/alert_management/alert_resolver.rb
@@ -22,6 +22,10 @@ module Resolvers
description: 'Search criteria for filtering alerts. This will search on title, description, service, monitoring_tool.',
required: false
+ argument :assignee_username, GraphQL::STRING_TYPE,
+ required: false,
+ description: 'Username of a user assigned to the issue'
+
type Types::AlertManagement::AlertType, null: true
def resolve_with_lookahead(**args)
diff --git a/app/graphql/resolvers/alert_management/alert_status_counts_resolver.rb b/app/graphql/resolvers/alert_management/alert_status_counts_resolver.rb
index a45de21002f..96ea4610aff 100644
--- a/app/graphql/resolvers/alert_management/alert_status_counts_resolver.rb
+++ b/app/graphql/resolvers/alert_management/alert_status_counts_resolver.rb
@@ -9,6 +9,10 @@ module Resolvers
description: 'Search criteria for filtering alerts. This will search on title, description, service, monitoring_tool.',
required: false
+ argument :assignee_username, GraphQL::STRING_TYPE,
+ required: false,
+ description: 'Username of a user assigned to the issue'
+
def resolve(**args)
::Gitlab::AlertManagement::AlertStatusCounts.new(context[:current_user], object, args)
end
diff --git a/app/graphql/resolvers/assigned_merge_requests_resolver.rb b/app/graphql/resolvers/assigned_merge_requests_resolver.rb
index fa08b142a7e..172a8e298ad 100644
--- a/app/graphql/resolvers/assigned_merge_requests_resolver.rb
+++ b/app/graphql/resolvers/assigned_merge_requests_resolver.rb
@@ -2,6 +2,8 @@
module Resolvers
class AssignedMergeRequestsResolver < UserMergeRequestsResolver
+ accept_author
+
def user_role
:assignee
end
diff --git a/app/graphql/resolvers/authored_merge_requests_resolver.rb b/app/graphql/resolvers/authored_merge_requests_resolver.rb
index e19bc9e8715..bc796f8685a 100644
--- a/app/graphql/resolvers/authored_merge_requests_resolver.rb
+++ b/app/graphql/resolvers/authored_merge_requests_resolver.rb
@@ -2,6 +2,8 @@
module Resolvers
class AuthoredMergeRequestsResolver < UserMergeRequestsResolver
+ accept_assignee
+
def user_role
:author
end
diff --git a/app/graphql/resolvers/base_resolver.rb b/app/graphql/resolvers/base_resolver.rb
index 791c6eab42f..2b8854fb4d0 100644
--- a/app/graphql/resolvers/base_resolver.rb
+++ b/app/graphql/resolvers/base_resolver.rb
@@ -4,6 +4,9 @@ module Resolvers
class BaseResolver < GraphQL::Schema::Resolver
extend ::Gitlab::Utils::Override
include ::Gitlab::Utils::StrongMemoize
+ include ::Gitlab::Graphql::GlobalIDCompatibility
+
+ argument_class ::Types::BaseArgument
def self.single
@single ||= Class.new(self) do
diff --git a/app/graphql/resolvers/board_list_issues_resolver.rb b/app/graphql/resolvers/board_list_issues_resolver.rb
index dba9f99edeb..3421e1024c0 100644
--- a/app/graphql/resolvers/board_list_issues_resolver.rb
+++ b/app/graphql/resolvers/board_list_issues_resolver.rb
@@ -14,7 +14,7 @@ module Resolvers
def resolve(**args)
filter_params = issue_filters(args[:filters]).merge(board_id: list.board.id, id: list.id)
- service = Boards::Issues::ListService.new(list.board.resource_parent, context[:current_user], filter_params)
+ service = ::Boards::Issues::ListService.new(list.board.resource_parent, context[:current_user], filter_params)
Gitlab::Graphql::Pagination::OffsetActiveRecordRelationConnection.new(service.execute)
end
diff --git a/app/graphql/resolvers/board_lists_resolver.rb b/app/graphql/resolvers/board_lists_resolver.rb
index b1d43934f24..3384b37e2ce 100644
--- a/app/graphql/resolvers/board_lists_resolver.rb
+++ b/app/graphql/resolvers/board_lists_resolver.rb
@@ -2,6 +2,7 @@
module Resolvers
class BoardListsResolver < BaseResolver
+ include BoardIssueFilterable
include Gitlab::Graphql::Authorize::AuthorizeResource
type Types::BoardListType, null: true
@@ -10,12 +11,17 @@ module Resolvers
required: false,
description: 'Find a list by its global ID'
+ argument :issue_filters, Types::Boards::BoardIssueInputType,
+ required: false,
+ description: 'Filters applied when getting issue metadata in the board list'
+
alias_method :board, :object
- def resolve(lookahead: nil, id: nil)
+ def resolve(lookahead: nil, id: nil, issue_filters: {})
authorize!(board)
lists = board_lists(id)
+ context.scoped_set!(:issue_filters, issue_filters(issue_filters))
if load_preferences?(lookahead)
List.preload_preferences_for_user(lists, context[:current_user])
@@ -27,7 +33,7 @@ module Resolvers
private
def board_lists(id)
- service = Boards::Lists::ListService.new(
+ service = ::Boards::Lists::ListService.new(
board.resource_parent,
context[:current_user],
list_id: extract_list_id(id)
diff --git a/app/graphql/resolvers/board_resolver.rb b/app/graphql/resolvers/board_resolver.rb
new file mode 100644
index 00000000000..517f4e514c9
--- /dev/null
+++ b/app/graphql/resolvers/board_resolver.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+module Resolvers
+ class BoardResolver < BaseResolver.single
+ alias_method :parent, :synchronized_object
+
+ type Types::BoardType, null: true
+
+ argument :id, ::Types::GlobalIDType[::Board],
+ required: true,
+ description: 'The board\'s ID'
+
+ def resolve(id: nil)
+ return unless parent
+
+ ::Boards::ListService.new(parent, context[:current_user], board_id: extract_board_id(id)).execute(create_default_board: false).first
+ rescue ActiveRecord::RecordNotFound
+ nil
+ end
+
+ private
+
+ def extract_board_id(gid)
+ GitlabSchema.parse_gid(gid, expected_type: ::Board).model_id
+ end
+ end
+end
diff --git a/app/graphql/resolvers/boards_resolver.rb b/app/graphql/resolvers/boards_resolver.rb
index eceb5b38031..82efd92d33f 100644
--- a/app/graphql/resolvers/boards_resolver.rb
+++ b/app/graphql/resolvers/boards_resolver.rb
@@ -16,7 +16,7 @@ module Resolvers
return Board.none unless parent
- Boards::ListService.new(parent, context[:current_user], board_id: extract_board_id(id)).execute(create_default_board: false)
+ ::Boards::ListService.new(parent, context[:current_user], board_id: extract_board_id(id)).execute(create_default_board: false)
rescue ActiveRecord::RecordNotFound
Board.none
end
diff --git a/app/graphql/resolvers/ci/runner_platforms_resolver.rb b/app/graphql/resolvers/ci/runner_platforms_resolver.rb
new file mode 100644
index 00000000000..9677c5139b4
--- /dev/null
+++ b/app/graphql/resolvers/ci/runner_platforms_resolver.rb
@@ -0,0 +1,30 @@
+# frozen_string_literal: true
+
+module Resolvers
+ module Ci
+ class RunnerPlatformsResolver < BaseResolver
+ type Types::Ci::RunnerPlatformType, null: false
+
+ def resolve(**args)
+ runner_instructions.map do |platform, data|
+ {
+ name: platform, human_readable_name: data[:human_readable_name],
+ architectures: parse_architectures(data[:download_locations])
+ }
+ end
+ end
+
+ private
+
+ def runner_instructions
+ Gitlab::Ci::RunnerInstructions::OS.merge(Gitlab::Ci::RunnerInstructions::OTHER_ENVIRONMENTS)
+ end
+
+ def parse_architectures(download_locations)
+ download_locations&.map do |architecture, download_location|
+ { name: architecture, download_location: download_location }
+ end
+ end
+ end
+ end
+end
diff --git a/app/graphql/resolvers/concerns/group_issuable_resolver.rb b/app/graphql/resolvers/concerns/group_issuable_resolver.rb
new file mode 100644
index 00000000000..49a79683e9f
--- /dev/null
+++ b/app/graphql/resolvers/concerns/group_issuable_resolver.rb
@@ -0,0 +1,14 @@
+# frozen_string_literal: true
+
+module GroupIssuableResolver
+ extend ActiveSupport::Concern
+
+ class_methods do
+ def include_subgroups(name_of_things)
+ argument :include_subgroups, GraphQL::BOOLEAN_TYPE,
+ required: false,
+ default_value: false,
+ description: "Include #{name_of_things} belonging to subgroups"
+ end
+ end
+end
diff --git a/app/graphql/resolvers/concerns/issue_resolver_arguments.rb b/app/graphql/resolvers/concerns/issue_resolver_arguments.rb
index 2b14d8275d1..fe6fa0bb262 100644
--- a/app/graphql/resolvers/concerns/issue_resolver_arguments.rb
+++ b/app/graphql/resolvers/concerns/issue_resolver_arguments.rb
@@ -18,9 +18,15 @@ module IssueResolverArguments
argument :milestone_title, GraphQL::STRING_TYPE.to_list_type,
required: false,
description: 'Milestone applied to this issue'
+ argument :author_username, GraphQL::STRING_TYPE,
+ required: false,
+ description: 'Username of the author of the issue'
argument :assignee_username, GraphQL::STRING_TYPE,
required: false,
description: 'Username of a user assigned to the issue'
+ argument :assignee_usernames, [GraphQL::STRING_TYPE],
+ required: false,
+ description: 'Usernames of users assigned to the issue'
argument :assignee_id, GraphQL::STRING_TYPE,
required: false,
description: 'ID of a user assigned to the issues, "none" and "any" values supported'
diff --git a/app/graphql/resolvers/concerns/looks_ahead.rb b/app/graphql/resolvers/concerns/looks_ahead.rb
index e7230287e13..61f23920ebb 100644
--- a/app/graphql/resolvers/concerns/looks_ahead.rb
+++ b/app/graphql/resolvers/concerns/looks_ahead.rb
@@ -3,8 +3,6 @@
module LooksAhead
extend ActiveSupport::Concern
- FEATURE_FLAG = :graphql_lookahead_support
-
included do
attr_accessor :lookahead
end
@@ -16,8 +14,6 @@ module LooksAhead
end
def apply_lookahead(query)
- return query unless Feature.enabled?(FEATURE_FLAG)
-
selection = node_selection
includes = preloads.each.flat_map do |name, requirements|
diff --git a/app/graphql/resolvers/concerns/resolves_merge_requests.rb b/app/graphql/resolvers/concerns/resolves_merge_requests.rb
index 0c01efd4f9a..ab83476ddea 100644
--- a/app/graphql/resolvers/concerns/resolves_merge_requests.rb
+++ b/app/graphql/resolvers/concerns/resolves_merge_requests.rb
@@ -12,7 +12,7 @@ module ResolvesMergeRequests
def resolve_with_lookahead(**args)
mr_finder = MergeRequestsFinder.new(current_user, args.compact)
- finder = Gitlab::Graphql::Loaders::IssuableLoader.new(project, mr_finder)
+ finder = Gitlab::Graphql::Loaders::IssuableLoader.new(mr_parent, mr_finder)
select_result(finder.batching_find_all { |query| apply_lookahead(query) })
end
@@ -29,6 +29,10 @@ module ResolvesMergeRequests
private
+ def mr_parent
+ project
+ end
+
def unconditional_includes
[:target_project]
end
@@ -40,7 +44,8 @@ module ResolvesMergeRequests
author: [:author],
merged_at: [:metrics],
commit_count: [:metrics],
- approved_by: [:approver_users],
+ diff_stats_summary: [:metrics],
+ approved_by: [:approved_by_users],
milestone: [:milestone],
head_pipeline: [:merge_request_diff, { head_pipeline: [:merge_request] }]
}
diff --git a/app/graphql/resolvers/concerns/time_frame_arguments.rb b/app/graphql/resolvers/concerns/time_frame_arguments.rb
index ef333dd05a5..94bfe6f7f9f 100644
--- a/app/graphql/resolvers/concerns/time_frame_arguments.rb
+++ b/app/graphql/resolvers/concerns/time_frame_arguments.rb
@@ -3,21 +3,33 @@
module TimeFrameArguments
extend ActiveSupport::Concern
+ OVERLAPPING_TIMEFRAME_DESC = 'List items overlapping a time frame defined by startDate..endDate (if one date is provided, both must be present)'
+
included do
argument :start_date, Types::TimeType,
required: false,
- description: 'List items within a time frame where items.start_date is between startDate and endDate parameters (endDate parameter must be present)'
+ description: OVERLAPPING_TIMEFRAME_DESC,
+ deprecated: { reason: 'Use timeframe.start', milestone: '13.5' }
argument :end_date, Types::TimeType,
required: false,
- description: 'List items within a time frame where items.end_date is between startDate and endDate parameters (startDate parameter must be present)'
+ description: OVERLAPPING_TIMEFRAME_DESC,
+ deprecated: { reason: 'Use timeframe.end', milestone: '13.5' }
+
+ argument :timeframe, Types::TimeframeInputType,
+ required: false,
+ description: 'List items overlapping the given timeframe'
end
+ # TODO: remove when the start_date and end_date arguments are removed
def validate_timeframe_params!(args)
- return unless args[:start_date].present? || args[:end_date].present?
+ return unless %i[start_date end_date timeframe].any? { |k| args[k].present? }
+ return if args[:timeframe] && %i[start_date end_date].all? { |k| args[k].nil? }
error_message =
- if args[:start_date].nil? || args[:end_date].nil?
+ if args[:timeframe].present?
+ "startDate and endDate are deprecated in favor of timeframe. Please use only timeframe."
+ elsif args[:start_date].nil? || args[:end_date].nil?
"Both startDate and endDate must be present."
elsif args[:start_date] > args[:end_date]
"startDate is after endDate"
diff --git a/app/graphql/resolvers/group_issues_resolver.rb b/app/graphql/resolvers/group_issues_resolver.rb
index ac51011eea8..1fa6c78e730 100644
--- a/app/graphql/resolvers/group_issues_resolver.rb
+++ b/app/graphql/resolvers/group_issues_resolver.rb
@@ -2,9 +2,8 @@
module Resolvers
class GroupIssuesResolver < IssuesResolver
- argument :include_subgroups, GraphQL::BOOLEAN_TYPE,
- required: false,
- default_value: false,
- description: 'Include issues belonging to subgroups.'
+ include GroupIssuableResolver
+
+ include_subgroups 'issues'
end
end
diff --git a/app/graphql/resolvers/group_merge_requests_resolver.rb b/app/graphql/resolvers/group_merge_requests_resolver.rb
new file mode 100644
index 00000000000..5ee72e3f781
--- /dev/null
+++ b/app/graphql/resolvers/group_merge_requests_resolver.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+module Resolvers
+ class GroupMergeRequestsResolver < MergeRequestsResolver
+ include GroupIssuableResolver
+
+ alias_method :group, :synchronized_object
+
+ include_subgroups 'merge requests'
+ accept_assignee
+ accept_author
+
+ def project
+ nil
+ end
+
+ def mr_parent
+ group
+ end
+
+ def no_results_possible?(args)
+ group.nil? || some_argument_is_empty?(args)
+ end
+ end
+end
diff --git a/app/graphql/resolvers/merge_requests_resolver.rb b/app/graphql/resolvers/merge_requests_resolver.rb
index 677f84e5795..cb4a76243ae 100644
--- a/app/graphql/resolvers/merge_requests_resolver.rb
+++ b/app/graphql/resolvers/merge_requests_resolver.rb
@@ -6,6 +6,18 @@ module Resolvers
alias_method :project, :synchronized_object
+ def self.accept_assignee
+ argument :assignee_username, GraphQL::STRING_TYPE,
+ required: false,
+ description: 'Username of the assignee'
+ end
+
+ def self.accept_author
+ argument :author_username, GraphQL::STRING_TYPE,
+ required: false,
+ description: 'Username of the author'
+ end
+
argument :iids, [GraphQL::STRING_TYPE],
required: false,
description: 'Array of IIDs of merge requests, for example `[1, 2]`'
diff --git a/app/graphql/resolvers/milestones_resolver.rb b/app/graphql/resolvers/milestones_resolver.rb
index 5f80506c01b..84712b674db 100644
--- a/app/graphql/resolvers/milestones_resolver.rb
+++ b/app/graphql/resolvers/milestones_resolver.rb
@@ -13,6 +13,18 @@ module Resolvers
required: false,
description: 'Filter milestones by state'
+ argument :title, GraphQL::STRING_TYPE,
+ required: false,
+ description: 'The title of the milestone'
+
+ argument :search_title, GraphQL::STRING_TYPE,
+ required: false,
+ description: 'A search string for the title'
+
+ argument :containing_date, Types::TimeType,
+ required: false,
+ description: 'A date that the milestone contains'
+
type Types::MilestoneType, null: true
def resolve(**args)
@@ -29,9 +41,18 @@ module Resolvers
{
ids: parse_gids(args[:ids]),
state: args[:state] || 'all',
- start_date: args[:start_date],
- end_date: args[:end_date]
- }.merge(parent_id_parameters(args))
+ title: args[:title],
+ search_title: args[:search_title],
+ containing_date: args[:containing_date]
+ }.merge!(timeframe_parameters(args)).merge!(parent_id_parameters(args))
+ end
+
+ def timeframe_parameters(args)
+ if args[:timeframe]
+ args[:timeframe].transform_keys { |k| :"#{k}_date" }
+ else
+ args.slice(:start_date, :end_date)
+ end
end
def parent
diff --git a/app/graphql/resolvers/project_merge_requests_resolver.rb b/app/graphql/resolvers/project_merge_requests_resolver.rb
index 0526ccd315f..ba13cb6e52c 100644
--- a/app/graphql/resolvers/project_merge_requests_resolver.rb
+++ b/app/graphql/resolvers/project_merge_requests_resolver.rb
@@ -2,11 +2,7 @@
module Resolvers
class ProjectMergeRequestsResolver < MergeRequestsResolver
- argument :assignee_username, GraphQL::STRING_TYPE,
- required: false,
- description: 'Username of the assignee'
- argument :author_username, GraphQL::STRING_TYPE,
- required: false,
- description: 'Username of the author'
+ accept_assignee
+ accept_author
end
end
diff --git a/app/graphql/resolvers/projects/jira_projects_resolver.rb b/app/graphql/resolvers/projects/jira_projects_resolver.rb
index ed382ac82d0..d017f973e17 100644
--- a/app/graphql/resolvers/projects/jira_projects_resolver.rb
+++ b/app/graphql/resolvers/projects/jira_projects_resolver.rb
@@ -22,7 +22,7 @@ module Resolvers
projects_array,
# override default max_page_size to whatever the size of the response is,
# see https://gitlab.com/gitlab-org/gitlab/-/issues/231394
- args.merge({ max_page_size: projects_array.size })
+ **args.merge({ max_page_size: projects_array.size })
)
else
raise Gitlab::Graphql::Errors::BaseError, response.message
diff --git a/app/graphql/resolvers/projects_resolver.rb b/app/graphql/resolvers/projects_resolver.rb
index 3bbadf87a71..69438229a50 100644
--- a/app/graphql/resolvers/projects_resolver.rb
+++ b/app/graphql/resolvers/projects_resolver.rb
@@ -13,8 +13,16 @@ module Resolvers
description: 'Search query for project name, path, or description'
argument :ids, [GraphQL::ID_TYPE],
- required: false,
- description: 'Filter projects by IDs'
+ required: false,
+ description: 'Filter projects by IDs'
+
+ argument :search_namespaces, GraphQL::BOOLEAN_TYPE,
+ required: false,
+ description: 'Include namespace in project search'
+
+ argument :sort, GraphQL::STRING_TYPE,
+ required: false,
+ description: 'Sort order of results'
def resolve(**args)
ProjectsFinder
@@ -28,7 +36,9 @@ module Resolvers
{
without_deleted: true,
non_public: params[:membership],
- search: params[:search]
+ search: params[:search],
+ search_namespaces: params[:search_namespaces],
+ sort: params[:sort]
}.compact
end
diff --git a/app/graphql/resolvers/snippets/blobs_resolver.rb b/app/graphql/resolvers/snippets/blobs_resolver.rb
new file mode 100644
index 00000000000..dc28358cab6
--- /dev/null
+++ b/app/graphql/resolvers/snippets/blobs_resolver.rb
@@ -0,0 +1,40 @@
+# frozen_string_literal: true
+
+module Resolvers
+ module Snippets
+ class BlobsResolver < BaseResolver
+ include Gitlab::Graphql::Authorize::AuthorizeResource
+
+ alias_method :snippet, :object
+
+ argument :paths, [GraphQL::STRING_TYPE],
+ required: false,
+ description: 'Paths of the blobs'
+
+ def resolve(**args)
+ authorize!(snippet)
+
+ return [snippet.blob] if snippet.empty_repo?
+
+ paths = Array(args.fetch(:paths, []))
+
+ if paths.empty?
+ snippet.blobs
+ else
+ snippet.repository.blobs_at(transformed_blob_paths(paths))
+ end
+ end
+
+ def authorized_resource?(snippet)
+ Ability.allowed?(context[:current_user], :read_snippet, snippet)
+ end
+
+ private
+
+ def transformed_blob_paths(paths)
+ ref = snippet.default_branch
+ paths.map { |path| [ref, path] }
+ end
+ end
+ end
+end
diff --git a/app/graphql/resolvers/terraform/states_resolver.rb b/app/graphql/resolvers/terraform/states_resolver.rb
new file mode 100644
index 00000000000..38b26a948b1
--- /dev/null
+++ b/app/graphql/resolvers/terraform/states_resolver.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+module Resolvers
+ module Terraform
+ class StatesResolver < BaseResolver
+ type Types::Terraform::StateType, null: true
+
+ alias_method :project, :object
+
+ def resolve(**args)
+ return ::Terraform::State.none unless can_read_terraform_states?
+
+ project.terraform_states.ordered_by_name
+ end
+
+ private
+
+ def can_read_terraform_states?
+ current_user.can?(:read_terraform_state, project)
+ end
+ end
+ end
+end
diff --git a/app/graphql/types/admin/analytics/instance_statistics/measurement_identifier_enum.rb b/app/graphql/types/admin/analytics/instance_statistics/measurement_identifier_enum.rb
index 13c67442c2e..c6ca5963588 100644
--- a/app/graphql/types/admin/analytics/instance_statistics/measurement_identifier_enum.rb
+++ b/app/graphql/types/admin/analytics/instance_statistics/measurement_identifier_enum.rb
@@ -8,12 +8,16 @@ module Types
graphql_name 'MeasurementIdentifier'
description 'Possible identifier types for a measurement'
- value 'PROJECTS', 'Project count', value: :projects
- value 'USERS', 'User count', value: :users
- value 'ISSUES', 'Issue count', value: :issues
- value 'MERGE_REQUESTS', 'Merge request count', value: :merge_requests
- value 'GROUPS', 'Group count', value: :groups
- value 'PIPELINES', 'Pipeline count', value: :pipelines
+ value 'PROJECTS', 'Project count', value: 'projects'
+ value 'USERS', 'User count', value: 'users'
+ value 'ISSUES', 'Issue count', value: 'issues'
+ value 'MERGE_REQUESTS', 'Merge request count', value: 'merge_requests'
+ value 'GROUPS', 'Group count', value: 'groups'
+ value 'PIPELINES', 'Pipeline count', value: 'pipelines'
+ value 'PIPELINES_SUCCEEDED', 'Pipeline count with success status', value: 'pipelines_succeeded'
+ value 'PIPELINES_FAILED', 'Pipeline count with failed status', value: 'pipelines_failed'
+ value 'PIPELINES_CANCELED', 'Pipeline count with canceled status', value: 'pipelines_canceled'
+ value 'PIPELINES_SKIPPED', 'Pipeline count with skipped status', value: 'pipelines_skipped'
end
end
end
diff --git a/app/graphql/types/alert_management/alert_status_counts_type.rb b/app/graphql/types/alert_management/alert_status_counts_type.rb
index f80b289eabc..a84be705445 100644
--- a/app/graphql/types/alert_management/alert_status_counts_type.rb
+++ b/app/graphql/types/alert_management/alert_status_counts_type.rb
@@ -9,11 +9,11 @@ module Types
authorize :read_alert_management_alert
- ::Gitlab::AlertManagement::AlertStatusCounts::STATUSES.each_key do |status|
+ ::AlertManagement::Alert.status_names.each do |status|
field status,
GraphQL::INT_TYPE,
null: true,
- description: "Number of alerts with status #{status.upcase} for the project"
+ description: "Number of alerts with status #{status.to_s.upcase} for the project"
end
field :open,
diff --git a/app/graphql/types/alert_management/alert_type.rb b/app/graphql/types/alert_management/alert_type.rb
index 2da97030b88..623762de208 100644
--- a/app/graphql/types/alert_management/alert_type.rb
+++ b/app/graphql/types/alert_management/alert_type.rb
@@ -40,7 +40,8 @@ module Types
field :status,
AlertManagement::StatusEnum,
null: true,
- description: 'Status of the alert'
+ description: 'Status of the alert',
+ method: :status_name
field :service,
GraphQL::STRING_TYPE,
@@ -67,6 +68,11 @@ module Types
null: true,
description: 'Timestamp the alert ended'
+ field :environment,
+ Types::EnvironmentType,
+ null: true,
+ description: 'Environment for the alert'
+
field :event_count,
GraphQL::INT_TYPE,
null: true,
diff --git a/app/graphql/types/alert_management/status_enum.rb b/app/graphql/types/alert_management/status_enum.rb
index 4ff6c4a9505..9d2c7316254 100644
--- a/app/graphql/types/alert_management/status_enum.rb
+++ b/app/graphql/types/alert_management/status_enum.rb
@@ -6,8 +6,8 @@ module Types
graphql_name 'AlertManagementStatus'
description 'Alert status values'
- ::AlertManagement::Alert::STATUSES.each do |name, value|
- value name.upcase, value: value, description: "#{name.to_s.titleize} status"
+ ::AlertManagement::Alert.status_names.each do |status|
+ value status.to_s.upcase, value: status, description: "#{status.to_s.titleize} status"
end
end
end
diff --git a/app/graphql/types/base_argument.rb b/app/graphql/types/base_argument.rb
new file mode 100644
index 00000000000..11774d0b59d
--- /dev/null
+++ b/app/graphql/types/base_argument.rb
@@ -0,0 +1,14 @@
+# frozen_string_literal: true
+
+module Types
+ class BaseArgument < GraphQL::Schema::Argument
+ include GitlabStyleDeprecations
+
+ def initialize(*args, **kwargs, &block)
+ kwargs = gitlab_deprecation(kwargs)
+ kwargs.delete(:deprecation_reason)
+
+ super(*args, **kwargs, &block)
+ end
+ end
+end
diff --git a/app/graphql/types/base_field.rb b/app/graphql/types/base_field.rb
index 1e72a4cddf5..5c8aabfe163 100644
--- a/app/graphql/types/base_field.rb
+++ b/app/graphql/types/base_field.rb
@@ -5,6 +5,8 @@ module Types
prepend Gitlab::Graphql::Authorize
include GitlabStyleDeprecations
+ argument_class ::Types::BaseArgument
+
DEFAULT_COMPLEXITY = 1
def initialize(*args, **kwargs, &block)
diff --git a/app/graphql/types/board_list_type.rb b/app/graphql/types/board_list_type.rb
index 24faf1fe8bc..6ee76b0d1f1 100644
--- a/app/graphql/types/board_list_type.rb
+++ b/app/graphql/types/board_list_type.rb
@@ -32,17 +32,14 @@ module Types
metadata[:size]
end
- def total_weight
- metadata[:total_weight]
- end
-
def metadata
strong_memoize(:metadata) do
list = self.object
user = context[:current_user]
+ params = (context[:issue_filters] || {}).merge(board_id: list.board_id, id: list.id)
::Boards::Issues::ListService
- .new(list.board.resource_parent, user, board_id: list.board_id, id: list.id)
+ .new(list.board.resource_parent, user, params)
.metadata
end
end
diff --git a/app/graphql/types/ci/detailed_status_type.rb b/app/graphql/types/ci/detailed_status_type.rb
index 90b5283fc9a..f4a50115ee6 100644
--- a/app/graphql/types/ci/detailed_status_type.rb
+++ b/app/graphql/types/ci/detailed_status_type.rb
@@ -6,24 +6,39 @@ module Types
class DetailedStatusType < BaseObject
graphql_name 'DetailedStatus'
- field :group, GraphQL::STRING_TYPE, null: false,
- description: 'Group of the pipeline status'
- field :icon, GraphQL::STRING_TYPE, null: false,
- description: 'Icon of the pipeline status'
- field :favicon, GraphQL::STRING_TYPE, null: false,
- description: 'Favicon of the pipeline status'
- field :details_path, GraphQL::STRING_TYPE, null: false,
- description: 'Path of the details for the pipeline status'
- field :has_details, GraphQL::BOOLEAN_TYPE, null: false,
- description: 'Indicates if the pipeline status has further details',
+ field :group, GraphQL::STRING_TYPE, null: true,
+ description: 'Group of the status'
+ field :icon, GraphQL::STRING_TYPE, null: true,
+ description: 'Icon of the status'
+ field :favicon, GraphQL::STRING_TYPE, null: true,
+ description: 'Favicon of the status'
+ field :details_path, GraphQL::STRING_TYPE, null: true,
+ description: 'Path of the details for the status'
+ field :has_details, GraphQL::BOOLEAN_TYPE, null: true,
+ description: 'Indicates if the status has further details',
method: :has_details?
- field :label, GraphQL::STRING_TYPE, null: false,
- description: 'Label of the pipeline status'
- field :text, GraphQL::STRING_TYPE, null: false,
- description: 'Text of the pipeline status'
- field :tooltip, GraphQL::STRING_TYPE, null: false,
- description: 'Tooltip associated with the pipeline status',
+ field :label, GraphQL::STRING_TYPE, null: true,
+ description: 'Label of the status'
+ field :text, GraphQL::STRING_TYPE, null: true,
+ description: 'Text of the status'
+ field :tooltip, GraphQL::STRING_TYPE, null: true,
+ description: 'Tooltip associated with the status',
method: :status_tooltip
+ field :action, Types::Ci::StatusActionType, null: true,
+ description: 'Action information for the status. This includes method, button title, icon, path, and title',
+ resolve: -> (obj, _args, _ctx) {
+ if obj.has_action?
+ {
+ button_title: obj.action_button_title,
+ icon: obj.icon,
+ method: obj.action_method,
+ path: obj.action_path,
+ title: obj.action_title
+ }
+ else
+ nil
+ end
+ }
end
# rubocop: enable Graphql/AuthorizeTypes
end
diff --git a/app/graphql/types/ci/group_type.rb b/app/graphql/types/ci/group_type.rb
index 04c0eb93068..d930ae311b7 100644
--- a/app/graphql/types/ci/group_type.rb
+++ b/app/graphql/types/ci/group_type.rb
@@ -12,6 +12,9 @@ module Types
description: 'Size of the group'
field :jobs, Ci::JobType.connection_type, null: true,
description: 'Jobs in group'
+ field :detailed_status, Types::Ci::DetailedStatusType, null: true,
+ description: 'Detailed status of the group',
+ resolve: -> (obj, _args, ctx) { obj.detailed_status(ctx[:current_user]) }
end
end
end
diff --git a/app/graphql/types/ci/job_type.rb b/app/graphql/types/ci/job_type.rb
index 4c18f3ffd52..0ee1ad47b62 100644
--- a/app/graphql/types/ci/job_type.rb
+++ b/app/graphql/types/ci/job_type.rb
@@ -10,6 +10,11 @@ module Types
description: 'Name of the job'
field :needs, JobType.connection_type, null: true,
description: 'Builds that must complete before the jobs run'
+ field :detailed_status, Types::Ci::DetailedStatusType, null: true,
+ description: 'Detailed status of the job',
+ resolve: -> (obj, _args, ctx) { obj.detailed_status(ctx[:current_user]) }
+ field :scheduled_at, Types::TimeType, null: true,
+ description: 'Schedule for the build'
end
end
end
diff --git a/app/graphql/types/ci/runner_architecture_type.rb b/app/graphql/types/ci/runner_architecture_type.rb
new file mode 100644
index 00000000000..526348abd9d
--- /dev/null
+++ b/app/graphql/types/ci/runner_architecture_type.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+module Types
+ module Ci
+ # rubocop: disable Graphql/AuthorizeTypes
+ class RunnerArchitectureType < BaseObject
+ graphql_name 'RunnerArchitecture'
+
+ field :name, GraphQL::STRING_TYPE, null: false,
+ description: 'Name of the runner platform architecture'
+ field :download_location, GraphQL::STRING_TYPE, null: false,
+ description: 'Download location for the runner for the platform architecture'
+ end
+ end
+end
diff --git a/app/graphql/types/ci/runner_platform_type.rb b/app/graphql/types/ci/runner_platform_type.rb
new file mode 100644
index 00000000000..64719bc4908
--- /dev/null
+++ b/app/graphql/types/ci/runner_platform_type.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+module Types
+ module Ci
+ # rubocop: disable Graphql/AuthorizeTypes
+ class RunnerPlatformType < BaseObject
+ graphql_name 'RunnerPlatform'
+
+ field :name, GraphQL::STRING_TYPE, null: false,
+ description: 'Name slug of the runner platform'
+ field :human_readable_name, GraphQL::STRING_TYPE, null: false,
+ description: 'Human readable name of the runner platform'
+ field :architectures, Types::Ci::RunnerArchitectureType.connection_type, null: true,
+ description: 'Runner architectures supported for the platform'
+ end
+ end
+end
diff --git a/app/graphql/types/ci/stage_type.rb b/app/graphql/types/ci/stage_type.rb
index 278c4d4d748..fc2c72d0d06 100644
--- a/app/graphql/types/ci/stage_type.rb
+++ b/app/graphql/types/ci/stage_type.rb
@@ -10,6 +10,9 @@ module Types
description: 'Name of the stage'
field :groups, Ci::GroupType.connection_type, null: true,
description: 'Group of jobs for the stage'
+ field :detailed_status, Types::Ci::DetailedStatusType, null: true,
+ description: 'Detailed status of the stage',
+ resolve: -> (obj, _args, ctx) { obj.detailed_status(ctx[:current_user]) }
end
end
end
diff --git a/app/graphql/types/ci/status_action_type.rb b/app/graphql/types/ci/status_action_type.rb
new file mode 100644
index 00000000000..08cbb6d3b59
--- /dev/null
+++ b/app/graphql/types/ci/status_action_type.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+module Types
+ module Ci
+ # rubocop: disable Graphql/AuthorizeTypes
+ class StatusActionType < BaseObject
+ graphql_name 'StatusAction'
+
+ field :button_title, GraphQL::STRING_TYPE, null: true,
+ description: 'Title for the button, for example: Retry this job'
+ field :icon, GraphQL::STRING_TYPE, null: true,
+ description: 'Icon used in the action button'
+ field :method, GraphQL::STRING_TYPE, null: true,
+ description: 'Method for the action, for example: :post',
+ resolver_method: :action_method
+ field :path, GraphQL::STRING_TYPE, null: true,
+ description: 'Path for the action'
+ field :title, GraphQL::STRING_TYPE, null: true,
+ description: 'Title for the action, for example: Retry'
+
+ def action_method
+ object[:method]
+ end
+ end
+ end
+end
diff --git a/app/graphql/types/date_type.rb b/app/graphql/types/date_type.rb
new file mode 100644
index 00000000000..7129b75b8bb
--- /dev/null
+++ b/app/graphql/types/date_type.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+module Types
+ class DateType < BaseScalar
+ graphql_name 'Date'
+ description 'Date represented in ISO 8601'
+
+ def self.coerce_input(value, ctx)
+ return if value.nil?
+
+ Date.iso8601(value)
+ rescue ArgumentError, TypeError => e
+ raise GraphQL::CoercionError, e.message
+ end
+
+ def self.coerce_result(value, ctx)
+ return if value.nil?
+
+ value.to_date.iso8601
+ end
+ end
+end
diff --git a/app/graphql/types/design_management/design_collection_copy_state_enum.rb b/app/graphql/types/design_management/design_collection_copy_state_enum.rb
new file mode 100644
index 00000000000..7e7303c50ef
--- /dev/null
+++ b/app/graphql/types/design_management/design_collection_copy_state_enum.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+module Types
+ module DesignManagement
+ class DesignCollectionCopyStateEnum < BaseEnum
+ graphql_name 'DesignCollectionCopyState'
+ description 'Copy state of a DesignCollection'
+
+ DESCRIPTION_VARIANTS = {
+ in_progress: 'is being copied',
+ error: 'encountered an error during a copy',
+ ready: 'has no copy in progress'
+ }.freeze
+
+ def self.description_variant(copy_state)
+ DESCRIPTION_VARIANTS[copy_state.to_sym] ||
+ (raise ArgumentError, "Unknown copy state: #{copy_state}")
+ end
+
+ ::DesignManagement::DesignCollection.state_machines[:copy_state].states.keys.each do |copy_state|
+ value copy_state.upcase,
+ value: copy_state.to_s,
+ description: "The DesignCollection #{description_variant(copy_state)}"
+ end
+ end
+ end
+end
diff --git a/app/graphql/types/design_management/design_collection_type.rb b/app/graphql/types/design_management/design_collection_type.rb
index 904fb270e11..9af1f4db425 100644
--- a/app/graphql/types/design_management/design_collection_type.rb
+++ b/app/graphql/types/design_management/design_collection_type.rb
@@ -39,6 +39,10 @@ module Types
null: true,
resolver: ::Resolvers::DesignManagement::DesignResolver,
description: 'Find a specific design'
+
+ field :copy_state, ::Types::DesignManagement::DesignCollectionCopyStateEnum,
+ null: true,
+ description: 'Copy state of the design collection'
end
end
end
diff --git a/app/graphql/types/design_management/design_type.rb b/app/graphql/types/design_management/design_type.rb
index 4e11a7aaf09..bab22015dc4 100644
--- a/app/graphql/types/design_management/design_type.rb
+++ b/app/graphql/types/design_management/design_type.rb
@@ -30,7 +30,7 @@ module Types
# most recent `Version` for an issue
Gitlab::SafeRequestStore.fetch([request_cache_base_key, 'stateful_version', object.issue_id, version_gid]) do
if version_gid
- GitlabSchema.object_from_id(version_gid)&.sync
+ GitlabSchema.object_from_id(version_gid, expected_type: ::DesignManagement::Version)&.sync
else
object.issue.design_versions.most_recent
end
diff --git a/app/graphql/types/environment_type.rb b/app/graphql/types/environment_type.rb
index 239b26f9c38..e4631a4a903 100644
--- a/app/graphql/types/environment_type.rb
+++ b/app/graphql/types/environment_type.rb
@@ -5,6 +5,8 @@ module Types
graphql_name 'Environment'
description 'Describes where code is deployed for a project'
+ present_using ::EnvironmentPresenter
+
authorize :read_environment
field :name, GraphQL::STRING_TYPE, null: false,
@@ -16,6 +18,10 @@ module Types
field :state, GraphQL::STRING_TYPE, null: false,
description: 'State of the environment, for example: available/stopped'
+ field :path, GraphQL::STRING_TYPE, null: true,
+ description: 'The path to the environment. Will always return null ' \
+ 'if `expose_environment_path_in_alert_details` feature flag is disabled'
+
field :metrics_dashboard, Types::Metrics::DashboardType, null: true,
description: 'Metrics dashboard schema for the environment',
resolver: Resolvers::Metrics::DashboardResolver
@@ -23,6 +29,6 @@ module Types
field :latest_opened_most_severe_alert,
Types::AlertManagement::AlertType,
null: true,
- description: 'The most severe open alert for the environment. If multiple alerts have equal severity, the most recent is returned.'
+ description: 'The most severe open alert for the environment. If multiple alerts have equal severity, the most recent is returned'
end
end
diff --git a/app/graphql/types/global_id_type.rb b/app/graphql/types/global_id_type.rb
index a3964ba83e1..9ae9ba32c13 100644
--- a/app/graphql/types/global_id_type.rb
+++ b/app/graphql/types/global_id_type.rb
@@ -1,5 +1,21 @@
# frozen_string_literal: true
+module GraphQLExtensions
+ module ScalarExtensions
+ # Allow ID to unify with GlobalID Types
+ def ==(other)
+ if name == 'ID' && other.is_a?(self.class) &&
+ other.type_class.ancestors.include?(::Types::GlobalIDType)
+ return true
+ end
+
+ super
+ end
+ end
+end
+
+::GraphQL::ScalarType.prepend(GraphQLExtensions::ScalarExtensions)
+
module Types
class GlobalIDType < BaseScalar
graphql_name 'GlobalID'
diff --git a/app/graphql/types/group_type.rb b/app/graphql/types/group_type.rb
index 60b2e3c7b6e..199cc0308c5 100644
--- a/app/graphql/types/group_type.rb
+++ b/app/graphql/types/group_type.rb
@@ -46,9 +46,15 @@ module Types
field :issues,
Types::IssueType.connection_type,
null: true,
- description: 'Issues of the group',
+ description: 'Issues for projects in this group',
resolver: Resolvers::GroupIssuesResolver
+ field :merge_requests,
+ Types::MergeRequestType.connection_type,
+ null: true,
+ description: 'Merge requests for projects in this group',
+ resolver: Resolvers::GroupMergeRequestsResolver
+
field :milestones, Types::MilestoneType.connection_type, null: true,
description: 'Milestones of the group',
resolver: Resolvers::GroupMilestonesResolver
@@ -64,7 +70,7 @@ module Types
Types::BoardType,
null: true,
description: 'A single board of the group',
- resolver: Resolvers::BoardsResolver.single
+ resolver: Resolvers::BoardResolver
field :label,
Types::LabelType,
diff --git a/app/graphql/types/issue_sort_enum.rb b/app/graphql/types/issue_sort_enum.rb
index e458d6e02c5..08762264b1b 100644
--- a/app/graphql/types/issue_sort_enum.rb
+++ b/app/graphql/types/issue_sort_enum.rb
@@ -8,6 +8,8 @@ module Types
value 'DUE_DATE_ASC', 'Due date by ascending order', value: :due_date_asc
value 'DUE_DATE_DESC', 'Due date by descending order', value: :due_date_desc
value 'RELATIVE_POSITION_ASC', 'Relative position by ascending order', value: :relative_position_asc
+ value 'SEVERITY_ASC', 'Severity from less critical to more critical', value: :severity_asc
+ value 'SEVERITY_DESC', 'Severity from more critical to less critical', value: :severity_desc
end
end
diff --git a/app/graphql/types/issue_state_event_enum.rb b/app/graphql/types/issue_state_event_enum.rb
new file mode 100644
index 00000000000..6a9d840831d
--- /dev/null
+++ b/app/graphql/types/issue_state_event_enum.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+module Types
+ class IssueStateEventEnum < BaseEnum
+ graphql_name 'IssueStateEvent'
+ description 'Values for issue state events'
+
+ value 'REOPEN', 'Reopens the issue', value: 'reopen'
+ value 'CLOSE', 'Closes the issue', value: 'close'
+ end
+end
diff --git a/app/graphql/types/issue_type.rb b/app/graphql/types/issue_type.rb
index d6253f74ce5..487508f448f 100644
--- a/app/graphql/types/issue_type.rb
+++ b/app/graphql/types/issue_type.rb
@@ -36,8 +36,7 @@ module Types
end
field :author, Types::UserType, null: false,
- description: 'User that created the issue',
- resolve: -> (obj, _args, _ctx) { Gitlab::Graphql::Loaders::BatchModelLoader.new(User, obj.author_id).find }
+ description: 'User that created the issue'
field :assignees, Types::UserType.connection_type, null: true,
description: 'Assignees of the issue'
@@ -45,16 +44,14 @@ module Types
field :labels, Types::LabelType.connection_type, null: true,
description: 'Labels of the issue'
field :milestone, Types::MilestoneType, null: true,
- description: 'Milestone of the issue',
- resolve: -> (obj, _args, _ctx) { Gitlab::Graphql::Loaders::BatchModelLoader.new(Milestone, obj.milestone_id).find }
+ description: 'Milestone of the issue'
field :due_date, Types::TimeType, null: true,
description: 'Due date of the issue'
field :confidential, GraphQL::BOOLEAN_TYPE, null: false,
description: 'Indicates the issue is confidential'
field :discussion_locked, GraphQL::BOOLEAN_TYPE, null: false,
- description: 'Indicates discussion is locked on the issue',
- resolve: -> (obj, _args, _ctx) { !!obj.discussion_locked }
+ description: 'Indicates discussion is locked on the issue'
field :upvotes, GraphQL::INT_TYPE, null: false,
description: 'Number of upvotes the issue has received'
@@ -108,6 +105,18 @@ module Types
field :severity, Types::IssuableSeverityEnum, null: true,
description: 'Severity level of the incident'
+
+ def author
+ Gitlab::Graphql::Loaders::BatchModelLoader.new(User, object.author_id).find
+ end
+
+ def milestone
+ Gitlab::Graphql::Loaders::BatchModelLoader.new(Milestone, object.milestone_id).find
+ end
+
+ def discussion_locked
+ !!object.discussion_locked
+ end
end
end
diff --git a/app/graphql/types/label_type.rb b/app/graphql/types/label_type.rb
index 738a00ad616..28dee2a9db5 100644
--- a/app/graphql/types/label_type.rb
+++ b/app/graphql/types/label_type.rb
@@ -4,6 +4,8 @@ module Types
class LabelType < BaseObject
graphql_name 'Label'
+ connection_type_class(Types::CountableConnectionType)
+
authorize :read_label
field :id, GraphQL::ID_TYPE, null: false,
diff --git a/app/graphql/types/merge_request_type.rb b/app/graphql/types/merge_request_type.rb
index 56c88491684..372aeac055b 100644
--- a/app/graphql/types/merge_request_type.rb
+++ b/app/graphql/types/merge_request_type.rb
@@ -152,6 +152,25 @@ module Types
field :auto_merge_enabled, GraphQL::BOOLEAN_TYPE, null: false,
description: 'Indicates if auto merge is enabled for the merge request'
+ field :approved_by, Types::UserType.connection_type, null: true,
+ description: 'Users who approved the merge request'
+
+ def approved_by
+ object.approved_by_users
+ end
+
+ # rubocop: disable CodeReuse/ActiveRecord
+ def user_notes_count
+ BatchLoader::GraphQL.for(object.id).batch(key: :merge_request_user_notes_count) do |ids, loader, args|
+ counts = Note.where(noteable_type: 'MergeRequest', noteable_id: ids).user.group(:noteable_id).count
+
+ ids.each do |id|
+ loader.call(id, counts[id] || 0)
+ end
+ end
+ end
+ # rubocop: enable CodeReuse/ActiveRecord
+
def diff_stats(path: nil)
stats = Array.wrap(object.diff_stats&.to_a)
@@ -163,21 +182,12 @@ module Types
end
def diff_stats_summary
- nil_stats = { additions: 0, deletions: 0, file_count: 0 }
- return nil_stats unless object.diff_stats.present?
-
- object.diff_stats.each_with_object(nil_stats) do |status, hash|
- hash.merge!(additions: status.additions, deletions: status.deletions, file_count: 1) { |_, x, y| x + y }
- end
+ BatchLoaders::MergeRequestDiffSummaryBatchLoader.load_for(object)
end
def commit_count
object&.metrics&.commits_count
end
-
- def approvers
- object.approver_users
- end
end
end
Types::MergeRequestType.prepend_if_ee('::EE::Types::MergeRequestType')
diff --git a/app/graphql/types/mutation_type.rb b/app/graphql/types/mutation_type.rb
index b2732d83aac..3f48e7b4a16 100644
--- a/app/graphql/types/mutation_type.rb
+++ b/app/graphql/types/mutation_type.rb
@@ -14,13 +14,16 @@ module Types
mount_mutation Mutations::AwardEmojis::Add
mount_mutation Mutations::AwardEmojis::Remove
mount_mutation Mutations::AwardEmojis::Toggle
+ mount_mutation Mutations::Boards::Create
mount_mutation Mutations::Boards::Destroy
mount_mutation Mutations::Boards::Issues::IssueMoveList
mount_mutation Mutations::Boards::Lists::Create
mount_mutation Mutations::Boards::Lists::Update
+ mount_mutation Mutations::Boards::Lists::Destroy
mount_mutation Mutations::Branches::Create, calls_gitaly: true
mount_mutation Mutations::Commits::Create, calls_gitaly: true
mount_mutation Mutations::Discussions::ToggleResolve
+ mount_mutation Mutations::Issues::Create
mount_mutation Mutations::Issues::SetAssignees
mount_mutation Mutations::Issues::SetConfidential
mount_mutation Mutations::Issues::SetLocked
@@ -28,6 +31,7 @@ module Types
mount_mutation Mutations::Issues::SetSeverity
mount_mutation Mutations::Issues::SetSubscription
mount_mutation Mutations::Issues::Update
+ mount_mutation Mutations::Issues::Move
mount_mutation Mutations::MergeRequests::Create
mount_mutation Mutations::MergeRequests::Update
mount_mutation Mutations::MergeRequests::SetLabels
@@ -71,4 +75,5 @@ module Types
end
::Types::MutationType.prepend(::Types::DeprecatedMutations)
+::Types::MutationType.prepend_if_ee('EE::Types::DeprecatedMutations')
::Types::MutationType.prepend_if_ee('::EE::Types::MutationType')
diff --git a/app/graphql/types/notes/noteable_type.rb b/app/graphql/types/notes/noteable_type.rb
index 3a16d54f9cd..602634d9292 100644
--- a/app/graphql/types/notes/noteable_type.rb
+++ b/app/graphql/types/notes/noteable_type.rb
@@ -8,24 +8,24 @@ module Types
field :notes, Types::Notes::NoteType.connection_type, null: false, description: "All notes on this noteable"
field :discussions, Types::Notes::DiscussionType.connection_type, null: false, description: "All discussions on this noteable"
- definition_methods do
- def resolve_type(object, context)
- case object
- when Issue
- Types::IssueType
- when MergeRequest
- Types::MergeRequestType
- when Snippet
- Types::SnippetType
- when ::DesignManagement::Design
- Types::DesignManagement::DesignType
- when ::AlertManagement::Alert
- Types::AlertManagement::AlertType
- else
- raise "Unknown GraphQL type for #{object}"
- end
+ def self.resolve_type(object, context)
+ case object
+ when Issue
+ Types::IssueType
+ when MergeRequest
+ Types::MergeRequestType
+ when Snippet
+ Types::SnippetType
+ when ::DesignManagement::Design
+ Types::DesignManagement::DesignType
+ when ::AlertManagement::Alert
+ Types::AlertManagement::AlertType
+ else
+ raise "Unknown GraphQL type for #{object}"
end
end
end
end
end
+
+Types::Notes::NoteableType.prepend_if_ee('::EE::Types::Notes::NoteableType')
diff --git a/app/graphql/types/package_type_enum.rb b/app/graphql/types/package_type_enum.rb
index bc03b8f5f8b..6f50c166da3 100644
--- a/app/graphql/types/package_type_enum.rb
+++ b/app/graphql/types/package_type_enum.rb
@@ -2,8 +2,14 @@
module Types
class PackageTypeEnum < BaseEnum
+ PACKAGE_TYPE_NAMES = {
+ pypi: 'PyPI',
+ npm: 'NPM'
+ }.freeze
+
::Packages::Package.package_types.keys.each do |package_type|
- value package_type.to_s.upcase, "Packages from the #{package_type} package manager", value: package_type.to_s
+ type_name = PACKAGE_TYPE_NAMES.fetch(package_type.to_sym, package_type.capitalize)
+ value package_type.to_s.upcase, "Packages from the #{type_name} package manager", value: package_type.to_s
end
end
end
diff --git a/app/graphql/types/project_member_type.rb b/app/graphql/types/project_member_type.rb
index f08781238d0..01731531ae2 100644
--- a/app/graphql/types/project_member_type.rb
+++ b/app/graphql/types/project_member_type.rb
@@ -12,7 +12,10 @@ module Types
authorize :read_project
field :project, Types::ProjectType, null: true,
- description: 'Project that User is a member of',
- resolve: -> (obj, _args, _ctx) { Gitlab::Graphql::Loaders::BatchModelLoader.new(Project, obj.source_id).find }
+ description: 'Project that User is a member of'
+
+ def project
+ Gitlab::Graphql::Loaders::BatchModelLoader.new(Project, object.source_id).find
+ end
end
end
diff --git a/app/graphql/types/project_type.rb b/app/graphql/types/project_type.rb
index 0fd54af1538..c7fc193abe8 100644
--- a/app/graphql/types/project_type.rb
+++ b/app/graphql/types/project_type.rb
@@ -234,7 +234,7 @@ module Types
Types::BoardType,
null: true,
description: 'A single board of the project',
- resolver: Resolvers::BoardsResolver.single
+ resolver: Resolvers::BoardResolver
field :jira_imports,
Types::JiraImportType.connection_type,
@@ -294,6 +294,12 @@ module Types
description: 'Title of the label'
end
+ field :terraform_states,
+ Types::Terraform::StateType.connection_type,
+ null: true,
+ description: 'Terraform states associated with the project',
+ resolver: Resolvers::Terraform::StatesResolver
+
def label(title:)
BatchLoader::GraphQL.for(title).batch(key: project) do |titles, loader, args|
LabelsFinder
diff --git a/app/graphql/types/query_type.rb b/app/graphql/types/query_type.rb
index 447ac63a294..bd4b53bdaa7 100644
--- a/app/graphql/types/query_type.rb
+++ b/app/graphql/types/query_type.rb
@@ -49,8 +49,7 @@ module Types
field :milestone, ::Types::MilestoneType,
null: true,
- description: 'Find a milestone',
- resolve: -> (_obj, args, _ctx) { GitlabSchema.find_by_gid(args[:id]) } do
+ description: 'Find a milestone' do
argument :id, ::Types::GlobalIDType[Milestone],
required: true,
description: 'Find a milestone by its ID'
@@ -81,12 +80,26 @@ module Types
description: 'Get statistics on the instance',
resolver: Resolvers::Admin::Analytics::InstanceStatistics::MeasurementsResolver
+ field :runner_platforms, Types::Ci::RunnerPlatformType.connection_type,
+ null: true, description: 'Supported runner platforms',
+ resolver: Resolvers::Ci::RunnerPlatformsResolver
+
def design_management
DesignManagementObject.new(nil)
end
def issue(id:)
- GitlabSchema.object_from_id(id, expected_type: ::Issue)
+ # TODO: remove this line when the compatibility layer is removed
+ # See: https://gitlab.com/gitlab-org/gitlab/-/issues/257883
+ id = ::Types::GlobalIDType[::Issue].coerce_isolated_input(id)
+ GitlabSchema.find_by_gid(id)
+ end
+
+ def milestone(id:)
+ # TODO: remove this line when the compatibility layer is removed
+ # See: https://gitlab.com/gitlab-org/gitlab/-/issues/257883
+ id = ::Types::GlobalIDType[Milestone].coerce_isolated_input(id)
+ GitlabSchema.find_by_gid(id)
end
end
end
diff --git a/app/graphql/types/range_input_type.rb b/app/graphql/types/range_input_type.rb
new file mode 100644
index 00000000000..766e523a99e
--- /dev/null
+++ b/app/graphql/types/range_input_type.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+module Types
+ # rubocop: disable Graphql/AuthorizeTypes
+ class RangeInputType < BaseInputObject
+ def self.[](type, closed = true)
+ @subtypes ||= {}
+
+ @subtypes[[type, closed]] ||= Class.new(self) do
+ argument :start, type,
+ required: closed,
+ description: 'The start of the range'
+
+ argument :end, type,
+ required: closed,
+ description: 'The end of the range'
+ end
+ end
+
+ def prepare
+ if self[:end] && self[:start] && self[:end] < self[:start]
+ raise ::Gitlab::Graphql::Errors::ArgumentError, 'start must be before end'
+ end
+
+ to_h
+ end
+ end
+ # rubocop: enable Graphql/AuthorizeTypes
+end
diff --git a/app/graphql/types/root_storage_statistics_type.rb b/app/graphql/types/root_storage_statistics_type.rb
index 3acc1d9ca44..224e8c7ee03 100644
--- a/app/graphql/types/root_storage_statistics_type.rb
+++ b/app/graphql/types/root_storage_statistics_type.rb
@@ -13,5 +13,6 @@ module Types
field :packages_size, GraphQL::FLOAT_TYPE, null: false, description: 'The packages size in bytes'
field :wiki_size, GraphQL::FLOAT_TYPE, null: false, description: 'The wiki size in bytes'
field :snippets_size, GraphQL::FLOAT_TYPE, null: false, description: 'The snippets size in bytes'
+ field :pipeline_artifacts_size, GraphQL::FLOAT_TYPE, null: false, description: 'The CI pipeline artifacts size in bytes'
end
end
diff --git a/app/graphql/types/snippet_type.rb b/app/graphql/types/snippet_type.rb
index db98e62c10a..495c25c1776 100644
--- a/app/graphql/types/snippet_type.rb
+++ b/app/graphql/types/snippet_type.rb
@@ -24,16 +24,14 @@ module Types
field :project, Types::ProjectType,
description: 'The project the snippet is associated with',
null: true,
- authorize: :read_project,
- resolve: -> (snippet, args, context) { Gitlab::Graphql::Loaders::BatchModelLoader.new(Project, snippet.project_id).find }
+ authorize: :read_project
# Author can be nil in some scenarios. For example,
# when the admin setting restricted visibility
# level is set to public
field :author, Types::UserType,
description: 'The owner of the snippet',
- null: true,
- resolve: -> (snippet, args, context) { Gitlab::Graphql::Loaders::BatchModelLoader.new(User, snippet.author_id).find }
+ null: true
field :file_name, GraphQL::STRING_TYPE,
description: 'File Name of the snippet',
@@ -69,10 +67,11 @@ module Types
null: false,
deprecated: { reason: 'Use `blobs`', milestone: '13.3' }
- field :blobs, type: [Types::Snippets::BlobType],
+ field :blobs, type: Types::Snippets::BlobType.connection_type,
description: 'Snippet blobs',
calls_gitaly: true,
- null: false
+ null: true,
+ resolver: Resolvers::Snippets::BlobsResolver
field :ssh_url_to_repo, type: GraphQL::STRING_TYPE,
description: 'SSH URL to the snippet repository',
@@ -85,5 +84,13 @@ module Types
null: true
markdown_field :description_html, null: true, method: :description
+
+ def author
+ Gitlab::Graphql::Loaders::BatchModelLoader.new(User, object.author_id).find
+ end
+
+ def project
+ Gitlab::Graphql::Loaders::BatchModelLoader.new(Project, object.project_id).find
+ end
end
end
diff --git a/app/graphql/types/sort_enum.rb b/app/graphql/types/sort_enum.rb
index 3245cb33e0d..d0a6eecb672 100644
--- a/app/graphql/types/sort_enum.rb
+++ b/app/graphql/types/sort_enum.rb
@@ -5,9 +5,16 @@ module Types
graphql_name 'Sort'
description 'Common sort values'
- value 'updated_desc', 'Updated at descending order'
- value 'updated_asc', 'Updated at ascending order'
- value 'created_desc', 'Created at descending order'
- value 'created_asc', 'Created at ascending order'
+ # Deprecated, as we prefer uppercase enums
+ # https://gitlab.com/groups/gitlab-org/-/epics/1838
+ value 'updated_desc', 'Updated at descending order', deprecated: { reason: 'Use UPDATED_DESC', milestone: '13.5' }
+ value 'updated_asc', 'Updated at ascending order', deprecated: { reason: 'Use UPDATED_ASC', milestone: '13.5' }
+ value 'created_desc', 'Created at descending order', deprecated: { reason: 'Use CREATED_DESC', milestone: '13.5' }
+ value 'created_asc', 'Created at ascending order', deprecated: { reason: 'Use CREATED_ASC', milestone: '13.5' }
+
+ value 'UPDATED_DESC', 'Updated at descending order', value: :updated_desc
+ value 'UPDATED_ASC', 'Updated at ascending order', value: :updated_asc
+ value 'CREATED_DESC', 'Created at descending order', value: :created_desc
+ value 'CREATED_ASC', 'Created at ascending order', value: :created_asc
end
end
diff --git a/app/graphql/types/terraform/state_type.rb b/app/graphql/types/terraform/state_type.rb
new file mode 100644
index 00000000000..f25f3a7789b
--- /dev/null
+++ b/app/graphql/types/terraform/state_type.rb
@@ -0,0 +1,37 @@
+# frozen_string_literal: true
+
+module Types
+ module Terraform
+ class StateType < BaseObject
+ graphql_name 'TerraformState'
+
+ authorize :read_terraform_state
+
+ field :id, GraphQL::ID_TYPE,
+ null: false,
+ description: 'ID of the Terraform state'
+
+ field :name, GraphQL::STRING_TYPE,
+ null: false,
+ description: 'Name of the Terraform state'
+
+ field :locked_by_user, Types::UserType,
+ null: true,
+ authorize: :read_user,
+ description: 'The user currently holding a lock on the Terraform state',
+ resolve: -> (state, _, _) { Gitlab::Graphql::Loaders::BatchModelLoader.new(User, state.locked_by_user_id).find }
+
+ field :locked_at, Types::TimeType,
+ null: true,
+ description: 'Timestamp the Terraform state was locked'
+
+ field :created_at, Types::TimeType,
+ null: false,
+ description: 'Timestamp the Terraform state was created'
+
+ field :updated_at, Types::TimeType,
+ null: false,
+ description: 'Timestamp the Terraform state was updated'
+ end
+ end
+end
diff --git a/app/graphql/types/timeframe_input_type.rb b/app/graphql/types/timeframe_input_type.rb
new file mode 100644
index 00000000000..79c1bc5cf01
--- /dev/null
+++ b/app/graphql/types/timeframe_input_type.rb
@@ -0,0 +1,10 @@
+# frozen_string_literal: true
+
+module Types
+ # rubocop: disable Graphql/AuthorizeTypes
+ class TimeframeInputType < RangeInputType[::Types::DateType]
+ graphql_name 'Timeframe'
+ description 'A time-frame defined as a closed inclusive range of two dates'
+ end
+ # rubocop: enable Graphql/AuthorizeTypes
+end
diff --git a/app/helpers/analytics/navbar_helper.rb b/app/helpers/analytics/navbar_helper.rb
index ddf2655c887..bc0b5e7c74f 100644
--- a/app/helpers/analytics/navbar_helper.rb
+++ b/app/helpers/analytics/navbar_helper.rb
@@ -28,7 +28,7 @@ module Analytics
private
def navbar_sub_item(args)
- NavbarSubItem.new(args)
+ NavbarSubItem.new(**args)
end
def cycle_analytics_navbar_link(project, current_user)
diff --git a/app/helpers/analytics/unique_visits_helper.rb b/app/helpers/analytics/unique_visits_helper.rb
index ded7f54e44e..4c709b2ed23 100644
--- a/app/helpers/analytics/unique_visits_helper.rb
+++ b/app/helpers/analytics/unique_visits_helper.rb
@@ -14,8 +14,7 @@ module Analytics
end
def track_visit(target_id)
- return unless Feature.enabled?(:track_unique_visits)
- return unless Gitlab::CurrentSettings.usage_ping_enabled?
+ return unless Feature.enabled?(:track_unique_visits, default_enabled: true)
return unless visitor_id
Gitlab::Analytics::UniqueVisits.new.track_visit(visitor_id, target_id)
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index a81225c8954..2a6b00c0bd8 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -6,10 +6,18 @@ require 'uri'
module ApplicationHelper
include StartupCssHelper
- # See https://docs.gitlab.com/ee/development/ee_features.html#code-in-app-views
+ # See https://docs.gitlab.com/ee/development/ee_features.html#code-in-appviews
# rubocop: disable CodeReuse/ActiveRecord
- def render_if_exists(partial, locals = {})
- render(partial, locals) if partial_exists?(partial)
+ # We allow partial to be nil so that collection views can be passed in
+ # `render partial: 'some/view', collection: @some_collection`
+ def render_if_exists(partial = nil, **options)
+ return unless partial_exists?(partial || options[:partial])
+
+ if partial.nil?
+ render(**options)
+ else
+ render(partial, options)
+ end
end
def partial_exists?(partial)
@@ -204,6 +212,10 @@ module ApplicationHelper
Gitlab::CurrentSettings.current_application_settings.help_page_support_url.presence || promo_url + '/getting-help/'
end
+ def instance_review_permitted?
+ ::Gitlab::CurrentSettings.instance_review_permitted? && current_user&.admin?
+ end
+
def static_objects_external_storage_enabled?
Gitlab::CurrentSettings.static_objects_external_storage_enabled?
end
@@ -349,6 +361,12 @@ module ApplicationHelper
}
end
+ def add_page_specific_style(path)
+ content_for :page_specific_styles do
+ stylesheet_link_tag_defer path
+ end
+ end
+
def page_startup_api_calls
@api_startup_calls
end
diff --git a/app/helpers/application_settings_helper.rb b/app/helpers/application_settings_helper.rb
index 9245cc1cb1c..9c408efe8cd 100644
--- a/app/helpers/application_settings_helper.rb
+++ b/app/helpers/application_settings_helper.rb
@@ -168,7 +168,7 @@ module ApplicationSettingsHelper
def visible_attributes
[
- :admin_notification_email,
+ :abuse_notification_email,
:after_sign_out_path,
:after_sign_up_text,
:akismet_api_key,
@@ -230,6 +230,7 @@ module ApplicationSettingsHelper
:hashed_storage_enabled,
:help_page_hide_commercial_content,
:help_page_support_url,
+ :help_page_documentation_base_url,
:help_page_text,
:hide_third_party_offers,
:home_page_url,
@@ -265,6 +266,7 @@ module ApplicationSettingsHelper
:receive_max_input_size,
:repository_checks_enabled,
:repository_storages_weighted,
+ :require_admin_approval_after_user_signup,
:require_two_factor_authentication,
:restricted_visibility_levels,
:rsa_key_restriction,
@@ -345,6 +347,12 @@ module ApplicationSettingsHelper
]
end
+ def deprecated_attributes
+ [
+ :admin_notification_email # ok to remove in REST API v5
+ ]
+ end
+
def expanded_by_default?
Rails.env.test?
end
@@ -382,6 +390,10 @@ module ApplicationSettingsHelper
Gitlab::CurrentSettings.self_monitoring_project&.full_path
}
end
+
+ def show_documentation_base_url_field?
+ Feature.enabled?(:help_page_documentation_redirect)
+ end
end
ApplicationSettingsHelper.prepend_if_ee('EE::ApplicationSettingsHelper')
diff --git a/app/helpers/avatars_helper.rb b/app/helpers/avatars_helper.rb
index 68dbc5b65d1..5457f96d506 100644
--- a/app/helpers/avatars_helper.rb
+++ b/app/helpers/avatars_helper.rb
@@ -60,7 +60,7 @@ module AvatarsHelper
avatar_size = options[:size] || 16
user_name = options[:user].try(:name) || options[:user_name]
- avatar_url = user_avatar_url_for(options.merge(size: avatar_size))
+ avatar_url = user_avatar_url_for(**options.merge(size: avatar_size))
has_tooltip = options[:has_tooltip].nil? ? true : options[:has_tooltip]
data_attributes = options[:data] || {}
diff --git a/app/helpers/blob_helper.rb b/app/helpers/blob_helper.rb
index 2eff87ae0ec..806fea3ab44 100644
--- a/app/helpers/blob_helper.rb
+++ b/app/helpers/blob_helper.rb
@@ -1,12 +1,6 @@
# frozen_string_literal: true
module BlobHelper
- def highlight(file_name, file_content, language: nil, plain: false)
- highlighted = Gitlab::Highlight.highlight(file_name, file_content, plain: plain, language: language)
-
- raw %(<pre class="code highlight"><code>#{highlighted}</code></pre>)
- end
-
def no_highlight_files
%w(credits changelog news copying copyright license authors)
end
@@ -33,11 +27,19 @@ module BlobHelper
end
def ide_fork_and_edit_path(project = @project, ref = @ref, path = @path, options = {})
- if current_user
- project_forks_path(project,
- namespace_key: current_user&.namespace&.id,
- continue: edit_blob_fork_params(ide_edit_path(project, ref, path)))
- end
+ fork_path_for_current_user(project, ide_edit_path(project, ref, path))
+ end
+
+ def fork_and_edit_path(project = @project, ref = @ref, path = @path, options = {})
+ fork_path_for_current_user(project, edit_blob_path(project, ref, path, options))
+ end
+
+ def fork_path_for_current_user(project, path)
+ return unless current_user
+
+ project_forks_path(project,
+ namespace_key: current_user.namespace&.id,
+ continue: edit_blob_fork_params(path))
end
def encode_ide_path(path)
@@ -148,7 +150,7 @@ module BlobHelper
# mode - File unix mode
# mode - File name
def blob_icon(mode, name)
- icon("#{file_type_icon_class('file', mode, name)} fw")
+ sprite_icon(file_type_icon_class('file', mode, name))
end
def blob_raw_url(**kwargs)
diff --git a/app/helpers/boards_helper.rb b/app/helpers/boards_helper.rb
index 6a4a7a8dfb2..c827fb4dd95 100644
--- a/app/helpers/boards_helper.rb
+++ b/app/helpers/boards_helper.rb
@@ -14,10 +14,14 @@ module BoardsHelper
root_path: root_path,
full_path: full_path,
bulk_update_path: @bulk_issues_path,
+ can_update: (!!can?(current_user, :admin_issue, board)).to_s,
time_tracking_limit_to_hours: Gitlab::CurrentSettings.time_tracking_limit_to_hours.to_s,
recent_boards_endpoint: recent_boards_path,
parent: current_board_parent.model_name.param_key,
- group_id: @group&.id
+ group_id: @group&.id,
+ labels_filter_base_path: build_issue_link_base,
+ labels_fetch_path: labels_fetch_path,
+ labels_manage_path: labels_manage_path
}
end
@@ -37,6 +41,22 @@ module BoardsHelper
end
end
+ def labels_fetch_path
+ if board.group_board?
+ group_labels_path(@group, format: :json, only_group_labels: true, include_ancestor_groups: true)
+ else
+ project_labels_path(@project, format: :json, include_ancestor_groups: true)
+ end
+ end
+
+ def labels_manage_path
+ if board.group_board?
+ group_labels_path(@group)
+ else
+ project_labels_path(@project)
+ end
+ end
+
def board_base_url
if board.group_board?
group_boards_url(@group)
diff --git a/app/helpers/ci/runners_helper.rb b/app/helpers/ci/runners_helper.rb
index 8cdb28b2874..552acf61f47 100644
--- a/app/helpers/ci/runners_helper.rb
+++ b/app/helpers/ci/runners_helper.rb
@@ -39,6 +39,14 @@ module Ci
runner.contacted_at
end
end
+
+ def group_shared_runners_settings_data(group)
+ {
+ update_path: api_v4_groups_path(id: group.id),
+ shared_runners_availability: group.shared_runners_setting,
+ parent_shared_runners_availability: group.parent&.shared_runners_setting
+ }
+ end
end
end
diff --git a/app/helpers/clusters_helper.rb b/app/helpers/clusters_helper.rb
index caad215e996..cc633df77f9 100644
--- a/app/helpers/clusters_helper.rb
+++ b/app/helpers/clusters_helper.rb
@@ -12,6 +12,18 @@ module ClustersHelper
end
end
+ def display_cluster_agents?(_clusterable)
+ false
+ end
+
+ def js_cluster_agents_list_data(clusterable_project)
+ {
+ default_branch_name: clusterable_project.default_branch,
+ empty_state_image: image_path('illustrations/clusters_empty.svg'),
+ project_path: clusterable_project.full_path
+ }
+ end
+
def js_clusters_list_data(path = nil)
{
ancestor_help_path: help_page_path('user/group/clusters/index', anchor: 'cluster-precedence'),
@@ -42,14 +54,6 @@ module ClustersHelper
}
end
- # This method is depreciated and will be removed when associated HAML files are moved to JavaScript
- def provider_icon(provider = nil)
- img_data = js_clusters_list_data.dig(:img_tags, provider&.to_sym) ||
- js_clusters_list_data.dig(:img_tags, :default)
-
- image_tag img_data[:path], alt: img_data[:text], class: 'gl-h-full'
- end
-
def render_gcp_signup_offer
return if Gitlab::CurrentSettings.current_application_settings.hide_third_party_offers?
return unless show_gcp_signup_offer?
diff --git a/app/helpers/container_expiration_policies_helper.rb b/app/helpers/container_expiration_policies_helper.rb
index cc6d717ce35..52f68ac53f0 100644
--- a/app/helpers/container_expiration_policies_helper.rb
+++ b/app/helpers/container_expiration_policies_helper.rb
@@ -24,4 +24,9 @@ module ContainerExpirationPoliciesHelper
end
end
end
+
+ def container_expiration_policies_historic_entry_enabled?(project)
+ Gitlab::CurrentSettings.container_expiration_policies_enable_historic_entries ||
+ Feature.enabled?(:container_expiration_policies_historic_entry, project)
+ end
end
diff --git a/app/helpers/dropdowns_helper.rb b/app/helpers/dropdowns_helper.rb
index 84aa08281f6..e1378e485e4 100644
--- a/app/helpers/dropdowns_helper.rb
+++ b/app/helpers/dropdowns_helper.rb
@@ -103,7 +103,7 @@ module DropdownsHelper
def dropdown_filter(placeholder, search_id: nil)
content_tag :div, class: "dropdown-input" do
filter_output = search_field_tag search_id, nil, class: "dropdown-input-field qa-dropdown-input-field", placeholder: placeholder, autocomplete: 'off'
- filter_output << icon('search', class: "dropdown-input-search")
+ filter_output << sprite_icon('search', css_class: 'dropdown-input-search')
filter_output << sprite_icon('close', size: 16, css_class: 'dropdown-input-clear js-dropdown-input-clear')
filter_output.html_safe
diff --git a/app/helpers/emails_helper.rb b/app/helpers/emails_helper.rb
index d5c22927991..0a0dc77e5e2 100644
--- a/app/helpers/emails_helper.rb
+++ b/app/helpers/emails_helper.rb
@@ -218,8 +218,28 @@ module EmailsHelper
_('Please contact your administrator with any questions.')
end
+ def change_reviewer_notification_text(new_reviewers, previous_reviewers, html_tag = nil)
+ new = new_reviewers.any? ? users_to_sentence(new_reviewers) : s_('ChangeReviewer|Unassigned')
+ old = previous_reviewers.any? ? users_to_sentence(previous_reviewers) : nil
+
+ if html_tag.present?
+ new = content_tag(html_tag, new)
+ old = content_tag(html_tag, old) if old.present?
+ end
+
+ if old.present?
+ s_('ChangeReviewer|Reviewer changed from %{old} to %{new}').html_safe % { old: old, new: new }
+ else
+ s_('ChangeReviewer|Reviewer changed to %{new}').html_safe % { new: new }
+ end
+ end
+
private
+ def users_to_sentence(users)
+ sanitize_name(users.map(&:name).to_sentence)
+ end
+
def generate_link(text, url)
link_to(text, url, target: :_blank, rel: 'noopener noreferrer')
end
diff --git a/app/helpers/events_helper.rb b/app/helpers/events_helper.rb
index 0167f2ef698..f40755b9439 100644
--- a/app/helpers/events_helper.rb
+++ b/app/helpers/events_helper.rb
@@ -28,19 +28,7 @@ module EventsHelper
end
def event_action_name(event)
- target = if event.target_type
- if event.design? || event.design_note?
- 'design'
- elsif event.wiki_page?
- 'wiki page'
- elsif event.note?
- event.note_target_type
- else
- event.target_type.titleize.downcase
- end
- else
- 'project'
- end
+ target = event.note_target_type_name || event.target_type_name
[event.action_name, target].join(" ")
end
@@ -229,7 +217,7 @@ module EventsHelper
def event_note_title_html(event)
if event.note_target
capture do
- concat content_tag(:span, event.note_target_type, class: "event-target-type gl-mr-2")
+ concat content_tag(:span, event.note_target_type_name, class: "event-target-type gl-mr-2")
concat link_to(event.note_target_reference, event_note_target_url(event), title: event.target_title, class: 'has-tooltip event-target-link gl-mr-2')
end
else
diff --git a/app/helpers/external_link_helper.rb b/app/helpers/external_link_helper.rb
index 9dbad1f5032..bf47087543f 100644
--- a/app/helpers/external_link_helper.rb
+++ b/app/helpers/external_link_helper.rb
@@ -3,7 +3,7 @@
module ExternalLinkHelper
def external_link(body, url, options = {})
link_to url, { target: '_blank', rel: 'noopener noreferrer' }.merge(options) do
- "#{body} #{icon('external-link')}".html_safe
+ "#{body} #{sprite_icon('external-link')}".html_safe
end
end
end
diff --git a/app/helpers/feature_flags_helper.rb b/app/helpers/feature_flags_helper.rb
new file mode 100644
index 00000000000..e50191a471f
--- /dev/null
+++ b/app/helpers/feature_flags_helper.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+module FeatureFlagsHelper
+ include ::API::Helpers::RelatedResourcesHelpers
+
+ def unleash_api_url(project)
+ expose_url(api_v4_feature_flags_unleash_path(project_id: project.id))
+ end
+
+ def unleash_api_instance_id(project)
+ project.feature_flags_client_token
+ end
+
+ def feature_flag_issues_links_endpoint(_project, _feature_flag, _user)
+ ''
+ end
+end
+
+FeatureFlagsHelper.prepend_if_ee('::EE::FeatureFlagsHelper')
diff --git a/app/helpers/form_helper.rb b/app/helpers/form_helper.rb
index 3dde5afcb92..8a8d708b0b2 100644
--- a/app/helpers/form_helper.rb
+++ b/app/helpers/form_helper.rb
@@ -56,7 +56,7 @@ module FormHelper
end
def reviewers_dropdown_options(issuable_type)
- {
+ dropdown_data = {
toggle_class: 'js-reviewer-search js-multiselect js-save-user-data',
title: 'Request review from',
filter: true,
@@ -69,13 +69,20 @@ module FormHelper
project_id: (@target_project || @project)&.id,
field_name: "#{issuable_type}[reviewer_ids][]",
default_label: 'Unassigned',
- 'dropdown-header': 'Reviewer(s)',
+ 'max-select': 1,
+ 'dropdown-header': 'Reviewer',
multi_select: true,
'input-meta': 'name',
'always-show-selectbox': true,
current_user_info: UserSerializer.new.represent(current_user)
}
}
+
+ if merge_request_supports_multiple_reviewers?
+ dropdown_data = multiple_reviewers_dropdown_options(dropdown_data)
+ end
+
+ dropdown_data
end
# Overwritten
@@ -88,6 +95,11 @@ module FormHelper
false
end
+ # Overwritten
+ def merge_request_supports_multiple_reviewers?
+ false
+ end
+
private
def multiple_assignees_dropdown_options(options)
@@ -99,6 +111,16 @@ module FormHelper
new_options
end
+
+ def multiple_reviewers_dropdown_options(options)
+ new_options = options.dup
+
+ new_options[:title] = _('Select reviewer(s)')
+ new_options[:data][:'dropdown-header'] = _('Reviewer(s)')
+ new_options[:data].delete(:'max-select')
+
+ new_options
+ end
end
FormHelper.prepend_if_ee('::EE::FormHelper')
diff --git a/app/helpers/gitlab_routing_helper.rb b/app/helpers/gitlab_routing_helper.rb
index d71e6b4c004..7df6bef7914 100644
--- a/app/helpers/gitlab_routing_helper.rb
+++ b/app/helpers/gitlab_routing_helper.rb
@@ -343,6 +343,18 @@ module GitlabRoutingHelper
Gitlab::UrlBuilder.wiki_page_url(wiki, page, only_path: true, **options)
end
+ def gitlab_ide_merge_request_path(merge_request)
+ target_project = merge_request.target_project
+ source_project = merge_request.source_project
+ params = {}
+
+ if target_project != source_project
+ params = { target_project: target_project.full_path }
+ end
+
+ ide_merge_request_path(source_project.namespace, source_project, merge_request, params)
+ end
+
private
def snippet_query_params(snippet, *args)
diff --git a/app/helpers/gitpod_helper.rb b/app/helpers/gitpod_helper.rb
new file mode 100644
index 00000000000..7edf7dc218d
--- /dev/null
+++ b/app/helpers/gitpod_helper.rb
@@ -0,0 +1,10 @@
+# frozen_string_literal: true
+
+module GitpodHelper
+ def gitpod_enable_description
+ link_start = '<a href="https://gitpod.io/" target="_blank" rel="noopener noreferrer">'.html_safe
+ link_end = "#{sprite_icon('external-link', size: 12, css_class: 'ml-1 vertical-align-center')}</a>".html_safe
+
+ s_('Enable %{link_start}Gitpod%{link_end} integration to launch a development environment in your browser directly from GitLab.').html_safe % { link_start: link_start, link_end: link_end }
+ end
+end
diff --git a/app/helpers/groups/group_members_helper.rb b/app/helpers/groups/group_members_helper.rb
index dcff2be34da..ee90585112b 100644
--- a/app/helpers/groups/group_members_helper.rb
+++ b/app/helpers/groups/group_members_helper.rb
@@ -10,17 +10,34 @@ module Groups::GroupMembersHelper
end
def render_invite_member_for_group(group, default_access_level)
- render 'shared/members/invite_member', submit_url: group_group_members_path(group), access_levels: GroupMember.access_level_roles, default_access_level: default_access_level
+ render 'shared/members/invite_member', submit_url: group_group_members_path(group), access_levels: group.access_level_roles, default_access_level: default_access_level
end
def linked_groups_data_json(group_links)
- GroupGroupLinkSerializer.new.represent(group_links).to_json
+ GroupGroupLinkSerializer.new.represent(group_links, { current_user: current_user }).to_json
end
def members_data_json(group, members)
members_data(group, members).to_json
end
+ # Overridden in `ee/app/helpers/ee/groups/group_members_helper.rb`
+ def group_members_list_data_attributes(group, members)
+ {
+ members: members_data_json(group, members),
+ member_path: group_group_member_path(group, ':id'),
+ group_id: group.id
+ }
+ end
+
+ def linked_groups_list_data_attributes(group)
+ {
+ members: linked_groups_data_json(group.shared_with_group_links),
+ member_path: group_group_link_path(group, ':id'),
+ group_id: group.id
+ }
+ end
+
private
def members_data(group, members)
@@ -35,7 +52,6 @@ module Groups::GroupMembersHelper
requested_at: member.requested_at,
can_update: member.can_update?,
can_remove: member.can_remove?,
- can_override: member.can_override?,
access_level: {
string_value: member.human_access,
integer_value: member.access_level
@@ -44,13 +60,14 @@ module Groups::GroupMembersHelper
id: source.id,
name: source.full_name,
web_url: Gitlab::UrlBuilder.build(source)
- }
+ },
+ valid_roles: member.valid_level_roles
}.merge(member_created_by_data(member.created_by))
- if user.present?
- data[:user] = member_user_data(user)
- else
+ if member.invite?
data[:invite] = member_invite_data(member)
+ elsif user.present?
+ data[:user] = member_user_data(user)
end
data
@@ -77,6 +94,17 @@ module Groups::GroupMembersHelper
avatar_url: avatar_icon_for_user(user, AVATAR_SIZE),
blocked: user.blocked?,
two_factor_enabled: user.two_factor_enabled?
+ }.merge(member_user_status_data(user.status))
+ end
+
+ def member_user_status_data(status)
+ return {} unless status.present?
+
+ {
+ status: {
+ emoji: status.emoji,
+ message_html: status.message_html
+ }
}
end
diff --git a/app/helpers/icons_helper.rb b/app/helpers/icons_helper.rb
index 0352b0ddf28..1d0001fde72 100644
--- a/app/helpers/icons_helper.rb
+++ b/app/helpers/icons_helper.rb
@@ -124,7 +124,7 @@ module IconsHelper
def file_type_icon_class(type, mode, name)
if type == 'folder'
- icon_class = 'folder'
+ icon_class = 'folder-o'
elsif type == 'archive'
icon_class = 'archive'
elsif mode == '120000'
@@ -135,36 +135,36 @@ module IconsHelper
case File.extname(name).downcase
when '.pdf'
- icon_class = 'file-pdf-o'
+ icon_class = 'document'
when '.jpg', '.jpeg', '.jif', '.jfif',
'.jp2', '.jpx', '.j2k', '.j2c',
'.apng', '.png', '.gif', '.tif', '.tiff',
'.svg', '.ico', '.bmp', '.webp'
- icon_class = 'file-image-o'
+ icon_class = 'doc-image'
when '.zip', '.zipx', '.tar', '.gz', '.gzip', '.tgz', '.bz', '.bzip',
'.bz2', '.bzip2', '.car', '.tbz', '.xz', 'txz', '.rar', '.7z',
'.lz', '.lzma', '.tlz'
- icon_class = 'file-archive-o'
+ icon_class = 'doc-compressed'
when '.mp3', '.wma', '.ogg', '.oga', '.wav', '.flac', '.aac', '.3ga',
'.ac3', '.midi', '.m4a', '.ape', '.mpa'
- icon_class = 'file-audio-o'
+ icon_class = 'volume-up'
when '.mp4', '.m4p', '.m4v',
'.mpg', '.mp2', '.mpeg', '.mpe', '.mpv',
'.mpg', '.mpeg', '.m2v', '.m2ts',
'.avi', '.mkv', '.flv', '.ogv', '.mov',
'.3gp', '.3g2'
- icon_class = 'file-video-o'
+ icon_class = 'live-preview'
when '.doc', '.dot', '.docx', '.docm', '.dotx', '.dotm', '.docb',
'.odt', '.ott', '.uot', '.rtf'
- icon_class = 'file-word-o'
+ icon_class = 'doc-text'
when '.xls', '.xlt', '.xlm', '.xlsx', '.xlsm', '.xltx', '.xltm',
'.xlsb', '.xla', '.xlam', '.xll', '.xlw', '.ots', '.ods', '.uos'
- icon_class = 'file-excel-o'
+ icon_class = 'document'
when '.ppt', '.pot', '.pps', '.pptx', '.pptm', '.potx', '.potm',
'.ppam', '.ppsx', '.ppsm', '.sldx', '.sldm', '.odp', '.otp', '.uop'
- icon_class = 'file-powerpoint-o'
+ icon_class = 'doc-chart'
else
- icon_class = 'file-text-o'
+ icon_class = 'doc-text'
end
end
diff --git a/app/helpers/invite_members_helper.rb b/app/helpers/invite_members_helper.rb
new file mode 100644
index 00000000000..ac6ac9979b3
--- /dev/null
+++ b/app/helpers/invite_members_helper.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+module InviteMembersHelper
+ include Gitlab::Utils::StrongMemoize
+
+ def invite_members_allowed?(group)
+ Feature.enabled?(:invite_members_group_modal, group) && can?(current_user, :admin_group_member, group)
+ end
+
+ def directly_invite_members?
+ strong_memoize(:directly_invite_members) do
+ experiment_enabled?(:invite_members_version_a) && can_import_members?
+ end
+ end
+
+ def indirectly_invite_members?
+ strong_memoize(:indirectly_invite_members) do
+ experiment_enabled?(:invite_members_version_b) && !can_import_members?
+ end
+ end
+end
diff --git a/app/helpers/issuables_helper.rb b/app/helpers/issuables_helper.rb
index b255597b18d..f8e7711959a 100644
--- a/app/helpers/issuables_helper.rb
+++ b/app/helpers/issuables_helper.rb
@@ -4,7 +4,10 @@ module IssuablesHelper
include GitlabRoutingHelper
def sidebar_gutter_toggle_icon
- sidebar_gutter_collapsed? ? icon('angle-double-left', { 'aria-hidden': 'true' }) : icon('angle-double-right', { 'aria-hidden': 'true' })
+ content_tag(:span, class: 'js-sidebar-toggle-container', data: { is_expanded: !sidebar_gutter_collapsed? }) do
+ sprite_icon('chevron-double-lg-left', css_class: "js-sidebar-expand #{'hidden' unless sidebar_gutter_collapsed?}") +
+ sprite_icon('chevron-double-lg-right', css_class: "js-sidebar-collapse #{'hidden' if sidebar_gutter_collapsed?}")
+ end
end
def sidebar_gutter_collapsed_class
@@ -46,12 +49,6 @@ module IssuablesHelper
"#{due_date.to_s(:medium)} (#{remaining_days_in_words(due_date, start_date)})"
end
- def sidebar_label_filter_path(base_path, label_name)
- query_params = { label_name: [label_name] }.to_query
-
- "#{base_path}?#{query_params}"
- end
-
def multi_label_name(current_labels, default_label)
return default_label if current_labels.blank?
@@ -79,6 +76,7 @@ module IssuablesHelper
when Issue
IssueSerializer
when MergeRequest
+ opts[:experiment_enabled] = :suggest_pipeline if experiment_enabled?(:suggest_pipeline) && opts[:serializer] == 'widget'
MergeRequestSerializer
end
@@ -206,7 +204,7 @@ module IssuablesHelper
end
if access = project.team.human_max_access(issuable.author_id)
- output << content_tag(:span, access, class: "user-access-role has-tooltip d-none d-xl-inline-block gl-ml-3 ", title: _("This user is a %{access} of the %{name} project.") % { access: access.downcase, name: project.name })
+ output << content_tag(:span, access, class: "user-access-role has-tooltip d-none d-xl-inline-block gl-ml-3 ", title: _("This user has the %{access} role in the %{name} project.") % { access: access.downcase, name: project.name })
elsif project.team.contributor?(issuable.author_id)
output << content_tag(:span, _("Contributor"), class: "user-access-role has-tooltip d-none d-xl-inline-block gl-ml-3", title: _("This user has previously committed to the %{name} project.") % { name: project.name })
end
@@ -224,19 +222,6 @@ module IssuablesHelper
nil
end
- def issuable_labels_tooltip(labels, limit: 5)
- first, last = labels.partition.with_index { |_, i| i < limit }
-
- if labels && labels.any?
- label_names = first.collect { |label| label.fetch(:title) }
- label_names << "and #{last.size} more" unless last.empty?
-
- label_names.join(', ')
- else
- _("Labels")
- end
- end
-
def issuables_state_counter_text(issuable_type, state, display_count)
titles = {
opened: "Open"
@@ -247,7 +232,22 @@ module IssuablesHelper
if display_count
count = issuables_count_for_state(issuable_type, state)
- html << " " << content_tag(:span, number_with_delimiter(count), class: 'badge badge-pill')
+ tag =
+ if count == -1
+ tooltip = _("Couldn't calculate number of %{issuables}.") % { issuables: issuable_type.to_s.humanize(capitalize: false) }
+
+ content_tag(
+ :span,
+ '?',
+ class: 'badge badge-pill has-tooltip',
+ aria: { label: tooltip },
+ title: tooltip
+ )
+ else
+ content_tag(:span, number_with_delimiter(count), class: 'badge badge-pill')
+ end
+
+ html << " " << tag
end
html.html_safe
@@ -342,6 +342,12 @@ module IssuablesHelper
issuable.closed? ^ should_inverse ? reopen_issuable_path(issuable) : close_issuable_path(issuable)
end
+ def toggle_draft_issuable_path(issuable)
+ wip_event = issuable.work_in_progress? ? 'unwip' : 'wip'
+
+ issuable_path(issuable, { merge_request: { wip_event: wip_event } })
+ end
+
def issuable_path(issuable, *options)
polymorphic_path(issuable, *options)
end
@@ -386,6 +392,12 @@ module IssuablesHelper
end
end
+ def reviewer_sidebar_data(reviewer, merge_request: nil)
+ { avatar_url: reviewer.avatar_url, name: reviewer.name, username: reviewer.username }.tap do |data|
+ data[:can_merge] = merge_request.can_be_merged_by?(reviewer) if merge_request
+ end
+ end
+
def issuable_squash_option?(issuable, project)
if issuable.persisted?
issuable.squash
@@ -420,7 +432,7 @@ module IssuablesHelper
def issuable_todo_button_data(issuable, is_collapsed)
{
- todo_text: _('Add a To Do'),
+ todo_text: _('Add a to do'),
mark_text: _('Mark as done'),
todo_icon: sprite_icon('todo-add'),
mark_icon: sprite_icon('todo-done', css_class: 'todo-undone'),
diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb
index e8ea39d7ffc..dbf284e70e4 100644
--- a/app/helpers/issues_helper.rb
+++ b/app/helpers/issues_helper.rb
@@ -137,6 +137,21 @@ module IssuesHelper
issue.moved_from.project.service_desk_enabled? && !issue.project.service_desk_enabled?
end
+
+ def use_startup_call?
+ request.query_parameters.empty? && @sort == 'created_date'
+ end
+
+ def startup_call_params
+ {
+ state: 'opened',
+ with_labels_details: 'true',
+ page: 1,
+ per_page: 20,
+ order_by: 'created_at',
+ sort: 'desc'
+ }
+ end
end
IssuesHelper.prepend_if_ee('EE::IssuesHelper')
diff --git a/app/helpers/labels_helper.rb b/app/helpers/labels_helper.rb
index 3142d7d7782..312d535a92c 100644
--- a/app/helpers/labels_helper.rb
+++ b/app/helpers/labels_helper.rb
@@ -36,11 +36,11 @@ module LabelsHelper
# link_to_label(label) { "My Custom Label Text" }
#
# Returns a String
- def link_to_label(label, type: :issue, tooltip: true, small: false, &block)
+ def link_to_label(label, type: :issue, tooltip: true, small: false, css_class: nil, &block)
link = label.filter_path(type: type)
if block_given?
- link_to link, &block
+ link_to link, class: css_class, &block
else
render_label(label, link: link, tooltip: tooltip, small: small)
end
@@ -61,7 +61,7 @@ module LabelsHelper
render_label_text(
label.name,
suffix: suffix,
- css_class: text_color_class_for_bg(label.color),
+ css_class: "gl-label-text #{text_color_class_for_bg(label.color)}",
bg_color: label.color
)
end
@@ -241,29 +241,14 @@ module LabelsHelper
}.merge(opts)
end
- def sidebar_label_dropdown_data(issuable_type, issuable_sidebar)
- label_dropdown_data(nil, {
- default_label: "Labels",
- field_name: "#{issuable_type}[label_names][]",
- ability_name: issuable_type,
- namespace_path: issuable_sidebar[:namespace_path],
- project_path: issuable_sidebar[:project_path],
- issue_update: issuable_sidebar[:issuable_json_path],
- labels: issuable_sidebar[:project_labels_path],
- display: 'static'
- })
- end
-
- def label_from_hash(hash)
- klass = hash[:group_id] ? GroupLabel : ProjectLabel
-
- klass.new(hash.slice(:color, :description, :title, :group_id, :project_id))
- end
-
def issuable_types
['issues', 'merge requests']
end
+ def show_labels_full_path?(project, group)
+ project || group&.subgroup?
+ end
+
private
def render_label_link(label_html, link:, title:, dataset:)
@@ -281,7 +266,7 @@ module LabelsHelper
def render_label_text(name, suffix: '', css_class: nil, bg_color: nil)
<<~HTML.chomp.html_safe
<span
- class="gl-label-text #{css_class}"
+ class="#{css_class}"
data-container="body"
data-html="true"
#{"style=\"background-color: #{bg_color}\"" if bg_color}
diff --git a/app/helpers/merge_requests_helper.rb b/app/helpers/merge_requests_helper.rb
index 1125ecb9b41..9cb7edbaeb6 100644
--- a/app/helpers/merge_requests_helper.rb
+++ b/app/helpers/merge_requests_helper.rb
@@ -109,10 +109,6 @@ module MergeRequestsHelper
@merge_request_diffs.size - @merge_request_diffs.index(merge_request_diff)
end
- def different_base?(version1, version2)
- version1 && version2 && version1.base_commit_sha != version2.base_commit_sha
- end
-
def merge_params(merge_request)
{
auto_merge_strategy: AutoMergeService::STRATEGY_MERGE_WHEN_PIPELINE_SUCCEEDS,
diff --git a/app/helpers/mirror_helper.rb b/app/helpers/mirror_helper.rb
index 50fc5e521fc..9d23ab87b98 100644
--- a/app/helpers/mirror_helper.rb
+++ b/app/helpers/mirror_helper.rb
@@ -9,7 +9,11 @@ module MirrorHelper
end
def mirror_lfs_sync_message
- html_escape(_('The Git LFS objects will %{strong_open}not%{strong_close} be synced.')) % { strong_open: '<strong>'.html_safe, strong_close: '</strong>'.html_safe }
+ docs_link_url = help_page_path('topics/git/lfs/index')
+ docs_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: docs_link_url }
+
+ html_escape(_('Git LFS objects will be synced if LFS is %{docs_link_start}enabled for the project%{docs_link_end}. Push mirrors will %{strong_open}not%{strong_close} sync LFS objects over SSH.')) %
+ { docs_link_start: docs_link_start, docs_link_end: '</a>'.html_safe, strong_open: '<strong>'.html_safe, strong_close: '</strong>'.html_safe }
end
end
diff --git a/app/helpers/namespaces_helper.rb b/app/helpers/namespaces_helper.rb
index 81451e398f2..8cf5cd49322 100644
--- a/app/helpers/namespaces_helper.rb
+++ b/app/helpers/namespaces_helper.rb
@@ -53,7 +53,7 @@ module NamespacesHelper
selected = options.delete(:selected) || :current_user
options[:groups] = current_user.manageable_groups_with_routes(include_groups_with_developer_maintainer_access: true)
- namespaces_options(selected, options)
+ namespaces_options(selected, **options)
end
private
diff --git a/app/helpers/nav_helper.rb b/app/helpers/nav_helper.rb
index 578c7ae7923..3c757a4ef26 100644
--- a/app/helpers/nav_helper.rb
+++ b/app/helpers/nav_helper.rb
@@ -55,7 +55,8 @@ module NavHelper
current_path?('projects/merge_requests/conflicts#show') ||
current_path?('issues#show') ||
current_path?('milestones#show') ||
- current_path?('issues#designs')
+ current_path?('issues#designs') ||
+ current_path?('incidents#show')
end
def admin_monitoring_nav_links
diff --git a/app/helpers/operations_helper.rb b/app/helpers/operations_helper.rb
index 521f394a920..9965a705a01 100644
--- a/app/helpers/operations_helper.rb
+++ b/app/helpers/operations_helper.rb
@@ -27,7 +27,7 @@ module OperationsHelper
'authorization_key' => alerts_service.token,
'prometheus_url' => notify_project_prometheus_alerts_url(@project, format: :json),
'url' => alerts_service.url,
- 'alerts_setup_url' => help_page_path('user/project/integrations/generic_alerts.md', anchor: 'setting-up-generic-alerts'),
+ 'alerts_setup_url' => help_page_path('operations/incident_management/alert_integrations.md', anchor: 'generic-http-endpoint'),
'alerts_usage_url' => project_alert_management_index_path(@project),
'disabled' => disabled.to_s
}
diff --git a/app/helpers/packages_helper.rb b/app/helpers/packages_helper.rb
index e6ecc403a88..8f365fd0786 100644
--- a/app/helpers/packages_helper.rb
+++ b/app/helpers/packages_helper.rb
@@ -34,26 +34,22 @@ module PackagesHelper
expose_url(api_v4_group___packages_composer_packages_path(id: group_id, format: '.json'))
end
- def packages_coming_soon_enabled?(resource)
- ::Feature.enabled?(:packages_coming_soon, resource) && ::Gitlab.dev_env_or_com?
- end
-
- def packages_coming_soon_data(resource)
- return unless packages_coming_soon_enabled?(resource)
-
- {
- project_path: ::Gitlab.com? ? 'gitlab-org/gitlab' : 'gitlab-org/gitlab-test',
- suggested_contributions: help_page_path('user/packages/index', anchor: 'suggested-contributions')
- }
+ def composer_config_repository_name(group_id)
+ "#{Gitlab.config.gitlab.host}/#{group_id}"
end
def packages_list_data(type, resource)
{
resource_id: resource.id,
page_type: type,
- empty_list_help_url: help_page_path('administration/packages/index'),
+ empty_list_help_url: help_page_path('user/packages/package_registry/index'),
empty_list_illustration: image_path('illustrations/no-packages.svg'),
- coming_soon_json: packages_coming_soon_data(resource).to_json
+ package_help_url: help_page_path('user/packages/index')
}
end
+
+ def track_package_event(event_name, scope, **args)
+ ::Packages::CreateEventService.new(nil, current_user, event_name: event_name, scope: scope).execute
+ track_event(event_name, **args)
+ end
end
diff --git a/app/helpers/page_layout_helper.rb b/app/helpers/page_layout_helper.rb
index a44760e85ca..6808ffc3e27 100644
--- a/app/helpers/page_layout_helper.rb
+++ b/app/helpers/page_layout_helper.rb
@@ -40,6 +40,14 @@ module PageLayoutHelper
end
end
+ def page_canonical_link(link = nil)
+ if link
+ @page_canonical_link = link
+ else
+ @page_canonical_link
+ end
+ end
+
def favicon
Gitlab::Favicon.main
end
diff --git a/app/helpers/pagination_helper.rb b/app/helpers/pagination_helper.rb
index d05153c9d4b..3167142e193 100644
--- a/app/helpers/pagination_helper.rb
+++ b/app/helpers/pagination_helper.rb
@@ -1,11 +1,13 @@
# frozen_string_literal: true
module PaginationHelper
- def paginate_collection(collection, remote: nil)
+ # total_pages will be inferred from the collection if nil. It is ignored if
+ # the collection is a Kaminari::PaginatableWithoutCount
+ def paginate_collection(collection, remote: nil, total_pages: nil)
if collection.is_a?(Kaminari::PaginatableWithoutCount)
paginate_without_count(collection)
elsif collection.respond_to?(:total_pages)
- paginate_with_count(collection, remote: remote)
+ paginate_with_count(collection, remote: remote, total_pages: total_pages)
end
end
@@ -17,7 +19,7 @@ module PaginationHelper
)
end
- def paginate_with_count(collection, remote: nil)
- paginate(collection, remote: remote, theme: 'gitlab')
+ def paginate_with_count(collection, remote: nil, total_pages: nil)
+ paginate(collection, remote: remote, theme: 'gitlab', total_pages: total_pages)
end
end
diff --git a/app/helpers/preferences_helper.rb b/app/helpers/preferences_helper.rb
index 2c406641882..9bf819febb0 100644
--- a/app/helpers/preferences_helper.rb
+++ b/app/helpers/preferences_helper.rb
@@ -61,8 +61,8 @@ module PreferencesHelper
@user_application_theme ||= Gitlab::Themes.for_user(current_user).css_class
end
- def user_application_theme_name
- @user_application_theme_name ||= Gitlab::Themes.for_user(current_user).name.downcase.tr(' ', '_')
+ def user_application_theme_css_filename
+ @user_application_theme_css_filename ||= Gitlab::Themes.for_user(current_user).css_filename
end
def user_color_scheme
diff --git a/app/helpers/projects/alert_management_helper.rb b/app/helpers/projects/alert_management_helper.rb
index c2f0b8854e1..5ce3736c8ef 100644
--- a/app/helpers/projects/alert_management_helper.rb
+++ b/app/helpers/projects/alert_management_helper.rb
@@ -9,7 +9,9 @@ module Projects::AlertManagementHelper
'populating-alerts-help-url' => help_page_url('operations/incident_management/index.md', anchor: 'enable-alert-management'),
'empty-alert-svg-path' => image_path('illustrations/alert-management-empty-state.svg'),
'user-can-enable-alert-management' => can?(current_user, :admin_operations, project).to_s,
- 'alert-management-enabled' => alert_management_enabled?(project).to_s
+ 'alert-management-enabled' => alert_management_enabled?(project).to_s,
+ 'text-query': params[:search],
+ 'assignee-username-query': params[:assignee_username]
}
end
diff --git a/app/helpers/projects/incidents_helper.rb b/app/helpers/projects/incidents_helper.rb
index e96f0f5a384..63504cb55b9 100644
--- a/app/helpers/projects/incidents_helper.rb
+++ b/app/helpers/projects/incidents_helper.rb
@@ -1,14 +1,17 @@
# frozen_string_literal: true
module Projects::IncidentsHelper
- def incidents_data(project)
+ def incidents_data(project, params)
{
'project-path' => project.full_path,
'new-issue-path' => new_project_issue_path(project),
'incident-template-name' => 'incident',
'incident-type' => 'incident',
'issue-path' => project_issues_path(project),
- 'empty-list-svg-path' => image_path('illustrations/incident-empty-state.svg')
+ 'empty-list-svg-path' => image_path('illustrations/incident-empty-state.svg'),
+ 'text-query': params[:search],
+ 'author-username-query': params[:author_username],
+ 'assignee-username-query': params[:assignee_username]
}
end
end
diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb
index 72cc07b13a5..ae46135e890 100644
--- a/app/helpers/projects_helper.rb
+++ b/app/helpers/projects_helper.rb
@@ -301,7 +301,6 @@ module ProjectsHelper
!disabled && !compact_mode
end
- # overridden in EE
def settings_operations_available?
can?(current_user, :read_environment, @project)
end
@@ -468,16 +467,25 @@ module ProjectsHelper
serverless: :read_cluster,
error_tracking: :read_sentry_issue,
alert_management: :read_alert_management_alert,
- incidents: :read_incidents,
+ incidents: :read_issue,
labels: :read_label,
issues: :read_issue,
project_members: :read_project_member,
- wiki: :read_wiki
+ wiki: :read_wiki,
+ feature_flags: :read_feature_flag
}
end
def can_view_operations_tab?(current_user, project)
- [:read_environment, :read_cluster, :metrics_dashboard].any? do |ability|
+ [
+ :metrics_dashboard,
+ :read_alert_management_alert,
+ :read_environment,
+ :read_issue,
+ :read_sentry_issue,
+ :read_cluster,
+ :read_feature_flag
+ ].any? do |ability|
can?(current_user, ability, project)
end
end
@@ -555,7 +563,11 @@ module ProjectsHelper
end
def sidebar_operations_link_path(project = @project)
- metrics_project_environments_path(project) if can?(current_user, :read_environment, project)
+ if can?(current_user, :read_environment, project)
+ metrics_project_environments_path(project)
+ else
+ project_feature_flags_path(project)
+ end
end
def project_last_activity(project)
@@ -748,6 +760,8 @@ module ProjectsHelper
logs
product_analytics
metrics_dashboard
+ feature_flags
+ tracings
]
end
@@ -758,10 +772,6 @@ module ProjectsHelper
!project.repository.gitlab_ci_yml
end
- def native_code_navigation_enabled?(project)
- Feature.enabled?(:code_navigation, project, default_enabled: true)
- end
-
def show_visibility_confirm_modal?(project)
project.unlink_forks_upon_visibility_decrease_enabled? && project.visibility_level > Gitlab::VisibilityLevel::PRIVATE && project.forks_count > 0
end
@@ -772,9 +782,7 @@ module ProjectsHelper
end
def project_access_token_available?(project)
- return false if ::Gitlab.com?
-
- ::Feature.enabled?(:resource_access_token, project, default_enabled: true)
+ can?(current_user, :admin_resource_access_tokens, project)
end
end
diff --git a/app/helpers/releases_helper.rb b/app/helpers/releases_helper.rb
index 979a68ecb7b..050b27840a0 100644
--- a/app/helpers/releases_helper.rb
+++ b/app/helpers/releases_helper.rb
@@ -29,6 +29,14 @@ module ReleasesHelper
end
end
+ def data_for_show_page
+ {
+ project_id: @project.id,
+ project_path: @project.full_path,
+ tag_name: @release.tag
+ }
+ end
+
def data_for_edit_release_page
new_edit_pages_shared_data.merge(
tag_name: @release.tag,
@@ -48,6 +56,7 @@ module ReleasesHelper
def new_edit_pages_shared_data
{
project_id: @project.id,
+ project_path: @project.full_path,
markdown_preview_path: preview_markdown_path(@project),
markdown_docs_path: help_page_path('user/markdown'),
update_release_api_docs_path: help_page_path('api/releases/index.md', anchor: 'update-a-release'),
diff --git a/app/helpers/reminder_emails_helper.rb b/app/helpers/reminder_emails_helper.rb
new file mode 100644
index 00000000000..bffb3cf7751
--- /dev/null
+++ b/app/helpers/reminder_emails_helper.rb
@@ -0,0 +1,76 @@
+# frozen_string_literal: true
+
+module ReminderEmailsHelper
+ def invitation_reminder_salutation(reminder_index, format: nil)
+ case reminder_index
+ when 0
+ s_('InviteReminderEmail|Invitation pending')
+ when 1
+ if format == :html
+ s_('InviteReminderEmail|Hey there %{wave_emoji}').html_safe % { wave_emoji: Gitlab::Emoji.gl_emoji_tag('wave') }
+ else
+ s_('InviteReminderEmail|Hey there!')
+ end
+ when 2
+ s_('InviteReminderEmail|In case you missed it...')
+ end
+ end
+
+ def invitation_reminder_body(member, reminder_index, format: nil)
+ options = {
+ inviter: sanitize_name(member.created_by.name),
+ strong_start: '',
+ strong_end: '',
+ project_or_group_name: member_source.human_name,
+ project_or_group: member_source.model_name.singular,
+ role: member.human_access.downcase
+ }
+
+ if format == :html
+ options.merge!(
+ inviter: (link_to member.created_by.name, user_url(member.created_by)).html_safe,
+ strong_start: '<strong>'.html_safe,
+ strong_end: '</strong>'.html_safe
+ )
+ end
+
+ if reminder_index == 2
+ options[:invitation_age] = (Date.current - member.created_at.to_date).to_i
+ end
+
+ body = invitation_reminder_body_text(reminder_index)
+
+ (format == :html ? html_escape(body) : body ) % options
+ end
+
+ def invitation_reminder_accept_link(token, format: nil)
+ case format
+ when :html
+ link_to s_('InviteReminderEmail|Accept invitation'), invite_url(token), class: 'invite-btn-join'
+ else
+ s_('InviteReminderEmail|Accept invitation: %{invite_url}') % { invite_url: invite_url(token) }
+ end
+ end
+
+ def invitation_reminder_decline_link(token, format: nil)
+ case format
+ when :html
+ link_to s_('InviteReminderEmail|Decline invitation'), decline_invite_url(token), class: 'invite-btn-decline'
+ else
+ s_('InviteReminderEmail|Decline invitation: %{decline_url}') % { decline_url: decline_invite_url(token) }
+ end
+ end
+
+ private
+
+ def invitation_reminder_body_text(reminder_index)
+ case reminder_index
+ when 0
+ s_('InviteReminderEmail|%{inviter} is waiting for you to join the %{strong_start}%{project_or_group_name}%{strong_end} %{project_or_group} as a %{role}.')
+ when 1
+ s_('InviteReminderEmail|This is a friendly reminder that %{inviter} invited you to join the %{strong_start}%{project_or_group_name}%{strong_end} %{project_or_group} as a %{role}.')
+ when 2
+ s_("InviteReminderEmail|It's been %{invitation_age} days since %{inviter} invited you to join the %{strong_start}%{project_or_group_name}%{strong_end} %{project_or_group} as a %{role}. What would you like to do?")
+ end
+ end
+end
diff --git a/app/helpers/search_helper.rb b/app/helpers/search_helper.rb
index d55ad878b92..3467f6e9a44 100644
--- a/app/helpers/search_helper.rb
+++ b/app/helpers/search_helper.rb
@@ -1,14 +1,13 @@
# frozen_string_literal: true
module SearchHelper
- SEARCH_PERMITTED_PARAMS = [:search, :scope, :project_id, :group_id, :repository_ref, :snippets, :state].freeze
+ SEARCH_PERMITTED_PARAMS = [:search, :scope, :project_id, :group_id, :repository_ref, :snippets, :sort, :state, :confidential].freeze
def search_autocomplete_opts(term)
return unless current_user
resources_results = [
- recent_merge_requests_autocomplete(term),
- recent_issues_autocomplete(term),
+ recent_items_autocomplete(term),
groups_autocomplete(term),
projects_autocomplete(term)
].flatten
@@ -27,6 +26,10 @@ module SearchHelper
end
end
+ def recent_items_autocomplete(term)
+ recent_merge_requests_autocomplete(term) + recent_issues_autocomplete(term)
+ end
+
def search_entries_info(collection, scope, term)
return if collection.to_a.empty?
@@ -86,13 +89,18 @@ module SearchHelper
}).html_safe
end
+ def repository_ref(project)
+ # Always #to_s the repository_ref param in case the value is also a number
+ params[:repository_ref].to_s.presence || project.default_branch
+ end
+
# Overridden in EE
def search_blob_title(project, path)
path
end
def search_service
- @search_service ||= ::SearchService.new(current_user, params)
+ @search_service ||= ::SearchService.new(current_user, params.merge(confidential: Gitlab::Utils.to_boolean(params[:confidential])))
end
private
@@ -123,8 +131,7 @@ module SearchHelper
{ category: "Help", label: _("Rake Tasks Help"), url: help_page_path("raketasks/README") },
{ category: "Help", label: _("SSH Keys Help"), url: help_page_path("ssh/README") },
{ category: "Help", label: _("System Hooks Help"), url: help_page_path("system_hooks/system_hooks") },
- { category: "Help", label: _("Webhooks Help"), url: help_page_path("user/project/integrations/webhooks") },
- { category: "Help", label: _("Workflow Help"), url: help_page_path("workflow/README") }
+ { category: "Help", label: _("Webhooks Help"), url: help_page_path("user/project/integrations/webhooks") }
]
end
@@ -181,10 +188,10 @@ module SearchHelper
end
end
- def recent_merge_requests_autocomplete(term, limit = 5)
+ def recent_merge_requests_autocomplete(term)
return [] unless current_user
- ::Gitlab::Search::RecentMergeRequests.new(user: current_user).search(term).limit(limit).map do |mr|
+ ::Gitlab::Search::RecentMergeRequests.new(user: current_user).search(term).map do |mr|
{
category: "Recent merge requests",
id: mr.id,
@@ -195,10 +202,10 @@ module SearchHelper
end
end
- def recent_issues_autocomplete(term, limit = 5)
+ def recent_issues_autocomplete(term)
return [] unless current_user
- ::Gitlab::Search::RecentIssues.new(user: current_user).search(term).limit(limit).map do |i|
+ ::Gitlab::Search::RecentIssues.new(user: current_user).search(term).map do |i|
{
category: "Recent issues",
id: i.id,
@@ -255,11 +262,15 @@ module SearchHelper
opts[:data]['labels-endpoint'] = project_labels_path(@project)
opts[:data]['milestones-endpoint'] = project_milestones_path(@project)
opts[:data]['releases-endpoint'] = project_releases_path(@project)
+ opts[:data]['environments-endpoint'] =
+ unfoldered_environment_names_project_path(@project)
elsif @group.present?
opts[:data]['group-id'] = @group.id
opts[:data]['labels-endpoint'] = group_labels_path(@group)
opts[:data]['milestones-endpoint'] = group_milestones_path(@group)
opts[:data]['releases-endpoint'] = group_releases_path(@group)
+ opts[:data]['environments-endpoint'] =
+ unfoldered_environment_names_group_path(@group)
else
opts[:data]['labels-endpoint'] = dashboard_labels_path
opts[:data]['milestones-endpoint'] = dashboard_milestones_path
@@ -294,9 +305,25 @@ module SearchHelper
sanitize(html, tags: %w(a p ol ul li pre code))
end
- def show_user_search_tab?
- return false if Feature.disabled?(:users_search, default_enabled: true)
+ def simple_search_highlight_and_truncate(text, phrase, options = {})
+ text = Truncato.truncate(
+ text,
+ count_tags: false,
+ count_tail: false,
+ max_length: options.delete(:length) { 200 }
+ )
+
+ highlight(text, phrase.split, options)
+ end
+
+ # _search_highlight is used in EE override
+ def highlight_and_truncate_issue(issue, search_term, _search_highlight)
+ return unless issue.description.present?
+ simple_search_highlight_and_truncate(issue.description, search_term, highlighter: '<span class="gl-text-black-normal gl-font-weight-bold">\1</span>')
+ end
+
+ def show_user_search_tab?
if @project
project_search_tabs?(:members)
else
diff --git a/app/helpers/services_helper.rb b/app/helpers/services_helper.rb
index 6b5de73a831..114bbf59ae1 100644
--- a/app/helpers/services_helper.rb
+++ b/app/helpers/services_helper.rb
@@ -24,7 +24,7 @@ module ServicesHelper
when "commit", "commit_events"
s_("ProjectService|Event will be triggered when a commit is created/updated")
when "deployment"
- s_("ProjectService|Event will be triggered when a deployment finishes")
+ s_("ProjectService|Event will be triggered when a deployment starts or finishes")
when "alert"
s_("ProjectService|Event will be triggered when a new, unique alert is recorded")
end
@@ -124,6 +124,10 @@ module ServicesHelper
@group.present? && Feature.enabled?(:group_level_integrations, @group)
end
+ def instance_level_integrations?
+ !Gitlab.com?
+ end
+
extend self
private
diff --git a/app/helpers/snippets_helper.rb b/app/helpers/snippets_helper.rb
index 94c46feb8ae..1be7e240c1a 100644
--- a/app/helpers/snippets_helper.rb
+++ b/app/helpers/snippets_helper.rb
@@ -32,31 +32,6 @@ module SnippetsHelper
end
end
- # Get an array of line numbers surrounding a matching
- # line, bounded by min/max.
- #
- # @returns Array of line numbers
- def bounded_line_numbers(line, min, max, surrounding_lines)
- lower = line - surrounding_lines > min ? line - surrounding_lines : min
- upper = line + surrounding_lines < max ? line + surrounding_lines : max
- (lower..upper).to_a
- end
-
- def snippet_embed_tag(snippet)
- content_tag(:script, nil, src: gitlab_snippet_url(snippet, format: :js))
- end
-
- def snippet_embed_input(snippet)
- content_tag(:input,
- nil,
- type: :text,
- readonly: true,
- class: 'js-snippet-url-area snippet-embed-input form-control',
- data: { url: gitlab_snippet_url(snippet) },
- value: snippet_embed_tag(snippet),
- autocomplete: 'off')
- end
-
def snippet_badge(snippet)
return unless attrs = snippet_badge_attributes(snippet)
diff --git a/app/helpers/ssh_keys_helper.rb b/app/helpers/ssh_keys_helper.rb
new file mode 100644
index 00000000000..381db893943
--- /dev/null
+++ b/app/helpers/ssh_keys_helper.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+module SshKeysHelper
+ def ssh_key_delete_modal_data(key, path)
+ {
+ path: path,
+ method: 'delete',
+ qa_selector: 'delete_ssh_key_button',
+ modal_attributes: {
+ 'data-qa-selector': 'ssh_key_delete_modal',
+ title: _('Are you sure you want to delete this SSH key?'),
+ message: _('This action cannot be undone, and will permanently delete the %{key} SSH key') % { key: key.title },
+ okVariant: 'danger',
+ okTitle: _('Delete')
+ }
+ }
+ end
+end
diff --git a/app/helpers/startupjs_helper.rb b/app/helpers/startupjs_helper.rb
new file mode 100644
index 00000000000..b595590c7c9
--- /dev/null
+++ b/app/helpers/startupjs_helper.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+module StartupjsHelper
+ def page_startup_graphql_calls
+ @graphql_startup_calls
+ end
+
+ def add_page_startup_graphql_call(query, variables = {})
+ @graphql_startup_calls ||= []
+ file_location = File.join(Rails.root, "app/graphql/queries/#{query}.query.graphql")
+
+ return unless File.exist?(file_location)
+
+ query_str = File.read(file_location)
+ @graphql_startup_calls << { query: query_str, variables: variables }
+ end
+end
diff --git a/app/helpers/suggest_pipeline_helper.rb b/app/helpers/suggest_pipeline_helper.rb
index aa67f0ea770..d64e8d6f2cd 100644
--- a/app/helpers/suggest_pipeline_helper.rb
+++ b/app/helpers/suggest_pipeline_helper.rb
@@ -2,7 +2,7 @@
module SuggestPipelineHelper
def should_suggest_gitlab_ci_yml?
- Feature.enabled?(:suggest_pipeline) &&
+ experiment_enabled?(:suggest_pipeline) &&
current_user &&
params[:suggest_gitlab_ci_yml] == 'true'
end
diff --git a/app/helpers/system_note_helper.rb b/app/helpers/system_note_helper.rb
index 0227ad1092d..79f4810e13a 100644
--- a/app/helpers/system_note_helper.rb
+++ b/app/helpers/system_note_helper.rb
@@ -2,6 +2,8 @@
module SystemNoteHelper
ICON_NAMES_BY_ACTION = {
+ 'approved' => 'approval',
+ 'unapproved' => 'unapproval',
'cherry_pick' => 'cherry-pick-commit',
'commit' => 'commit',
'description' => 'pencil-square',
@@ -11,6 +13,7 @@ module SystemNoteHelper
'closed' => 'issue-close',
'time_tracking' => 'timer',
'assignee' => 'user',
+ 'reviewer' => 'user',
'title' => 'pencil-square',
'task' => 'task-done',
'label' => 'label',
@@ -34,7 +37,8 @@ module SystemNoteHelper
'designs_discussion_added' => 'doc-image',
'status' => 'status',
'alert_issue_added' => 'issues',
- 'new_alert_added' => 'warning'
+ 'new_alert_added' => 'warning',
+ 'severity' => 'information-o'
}.freeze
def system_note_icon_name(note)
diff --git a/app/helpers/tags_helper.rb b/app/helpers/tags_helper.rb
index 4984b51555d..bfc8803f514 100644
--- a/app/helpers/tags_helper.rb
+++ b/app/helpers/tags_helper.rb
@@ -38,4 +38,13 @@ module TagsHelper
text.html_safe
end
+
+ def delete_tag_modal_attributes(tag_name)
+ {
+ title: s_('TagsPage|Delete tag'),
+ message: s_('TagsPage|Deleting the %{tag_name} tag cannot be undone. Are you sure?') % { tag_name: tag_name },
+ okVariant: 'danger',
+ okTitle: s_('TagsPage|Delete tag')
+ }.to_json
+ end
end
diff --git a/app/helpers/timeboxes_helper.rb b/app/helpers/timeboxes_helper.rb
index 34919f994ee..bbf8cf7dac3 100644
--- a/app/helpers/timeboxes_helper.rb
+++ b/app/helpers/timeboxes_helper.rb
@@ -228,8 +228,8 @@ module TimeboxesHelper
end
alias_method :milestone_date_range, :timebox_date_range
- def milestone_tab_path(milestone, tab)
- url_for(action: tab, format: :json)
+ def milestone_tab_path(milestone, tab, params = {})
+ url_for(params.merge(action: tab, format: :json))
end
def update_milestone_path(milestone, params = {})
diff --git a/app/helpers/todos_helper.rb b/app/helpers/todos_helper.rb
index 9865f7dfbef..7b0e0df8998 100644
--- a/app/helpers/todos_helper.rb
+++ b/app/helpers/todos_helper.rb
@@ -16,6 +16,7 @@ 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 then "mentioned #{todo_action_subject(todo)} on"
when Todo::BUILD_FAILED then 'The build failed for'
when Todo::MARKED then 'added a todo for'
@@ -26,6 +27,13 @@ module TodosHelper
end
end
+ def todo_self_addressing(todo)
+ case todo.action
+ when Todo::ASSIGNED then 'to yourself'
+ when Todo::REVIEW_REQUESTED then 'from yourself'
+ end
+ end
+
def todo_target_link(todo)
text = raw(todo_target_type_name(todo) + ' ') +
if todo.for_commit?
@@ -141,6 +149,7 @@ module TodosHelper
[
{ id: '', text: 'Any Action' },
{ id: Todo::ASSIGNED, text: 'Assigned' },
+ { id: Todo::REVIEW_REQUESTED, text: 'Review requested' },
{ id: Todo::MENTIONED, text: 'Mentioned' },
{ id: Todo::MARKED, text: 'Added' },
{ id: Todo::BUILD_FAILED, text: 'Pipelines' },
diff --git a/app/helpers/tree_helper.rb b/app/helpers/tree_helper.rb
index 7644ed783eb..563450159b5 100644
--- a/app/helpers/tree_helper.rb
+++ b/app/helpers/tree_helper.rb
@@ -1,6 +1,9 @@
# frozen_string_literal: true
module TreeHelper
+ include BlobHelper
+ include WebIdeButtonHelper
+
FILE_LIMIT = 1_000
# Sorts a repository's tree so that folders are before files and renders
@@ -31,7 +34,7 @@ module TreeHelper
# mode - File unix mode
# name - File name
def tree_icon(type, mode, name)
- icon([file_type_icon_class(type, mode, name), 'fw'])
+ sprite_icon(file_type_icon_class(type, mode, name))
end
# Using Rails `*_path` methods can be slow, especially when generating
@@ -199,38 +202,26 @@ module TreeHelper
}
end
- def ide_base_path(project)
- can_push_code = current_user&.can?(:push_code, project)
- fork_path = current_user&.fork_of(project)&.full_path
+ def web_ide_button_data(options = {})
+ {
+ project_path: project_to_use.full_path,
+ ref: ActionDispatch::Journey::Router::Utils.escape_path(@ref),
- if can_push_code
- project.full_path
- else
- fork_path || project.full_path
- end
- end
+ is_fork: fork?,
+ needs_to_fork: needs_to_fork?,
+ gitpod_enabled: !current_user.nil? && current_user.gitpod_enabled,
+ is_blob: !options[:blob].nil?,
- def vue_ide_link_data(project, ref)
- can_collaborate = can_collaborate_with_project?(project)
- can_create_mr_from_fork = can?(current_user, :fork_project, project) && can?(current_user, :create_merge_request_in, project)
- show_web_ide_button = (can_collaborate || current_user&.already_forked?(project) || can_create_mr_from_fork)
+ show_edit_button: show_edit_button?,
+ show_web_ide_button: show_web_ide_button?,
+ show_gitpod_button: show_gitpod_button?,
- {
- ide_base_path: ide_base_path(project),
- needs_to_fork: !can_collaborate && !current_user&.already_forked?(project),
- show_web_ide_button: show_web_ide_button,
- show_gitpod_button: show_web_ide_button && Gitlab::Gitpod.feature_and_settings_enabled?(project),
- gitpod_url: full_gitpod_url(project, ref),
- gitpod_enabled: current_user&.gitpod_enabled
+ web_ide_url: web_ide_url,
+ edit_url: edit_url,
+ gitpod_url: gitpod_url
}
end
- def full_gitpod_url(project, ref)
- return "" unless Gitlab::Gitpod.feature_and_settings_enabled?(project)
-
- "#{Gitlab::CurrentSettings.gitpod_url}##{project_tree_url(project, tree_join(ref, @path || ''))}"
- end
-
def directory_download_links(project, ref, archive_prefix)
Gitlab::Workhorse::ARCHIVE_FORMATS.map do |fmt|
{
diff --git a/app/helpers/user_callouts_helper.rb b/app/helpers/user_callouts_helper.rb
index 967271a8431..0cdf53d6174 100644
--- a/app/helpers/user_callouts_helper.rb
+++ b/app/helpers/user_callouts_helper.rb
@@ -9,7 +9,7 @@ module UserCalloutsHelper
TABS_POSITION_HIGHLIGHT = 'tabs_position_highlight'
WEBHOOKS_MOVED = 'webhooks_moved'
CUSTOMIZE_HOMEPAGE = 'customize_homepage'
- WEB_IDE_ALERT_DISMISSED = 'web_ide_alert_dismissed'
+ FEATURE_FLAGS_NEW_VERSION = 'feature_flags_new_version'
def show_admin_integrations_moved?
!user_dismissed?(ADMIN_INTEGRATIONS_MOVED)
@@ -51,8 +51,8 @@ module UserCalloutsHelper
customize_homepage && !user_dismissed?(CUSTOMIZE_HOMEPAGE)
end
- def show_web_ide_alert?
- !user_dismissed?(WEB_IDE_ALERT_DISMISSED)
+ def show_feature_flags_new_version?
+ !user_dismissed?(FEATURE_FLAGS_NEW_VERSION)
end
private
diff --git a/app/helpers/users_helper.rb b/app/helpers/users_helper.rb
index c1bca6b4c41..f47937e6d57 100644
--- a/app/helpers/users_helper.rb
+++ b/app/helpers/users_helper.rb
@@ -84,7 +84,7 @@ module UsersHelper
def user_badges_in_admin_section(user)
[].tap do |badges|
- badges << { text: s_('AdminUsers|Blocked'), variant: 'danger' } if user.blocked?
+ badges << blocked_user_badge(user) if user.blocked?
badges << { text: s_('AdminUsers|Admin'), variant: 'success' } if user.admin?
badges << { text: s_('AdminUsers|External'), variant: 'secondary' } if user.external?
badges << { text: s_("AdminUsers|It's you!"), variant: nil } if current_user == user
@@ -106,8 +106,19 @@ module UsersHelper
end
end
+ def can_force_email_confirmation?(user)
+ !user.confirmed?
+ end
+
private
+ def blocked_user_badge(user)
+ pending_approval_badge = { text: s_('AdminUsers|Pending approval'), variant: 'info' }
+ return pending_approval_badge if user.blocked_pending_approval?
+
+ { text: s_('AdminUsers|Blocked'), variant: 'danger' }
+ end
+
def get_profile_tabs
tabs = []
diff --git a/app/helpers/visibility_level_helper.rb b/app/helpers/visibility_level_helper.rb
index 304b58d232a..a7b9e17c898 100644
--- a/app/helpers/visibility_level_helper.rb
+++ b/app/helpers/visibility_level_helper.rb
@@ -23,8 +23,6 @@ module VisibilityLevelHelper
project_visibility_level_description(level)
when Group
group_visibility_level_description(level)
- when Snippet
- snippet_visibility_level_description(level, form_model)
end
end
@@ -50,21 +48,6 @@ module VisibilityLevelHelper
end
end
- def snippet_visibility_level_description(level, snippet = nil)
- case level
- when Gitlab::VisibilityLevel::PRIVATE
- if snippet.is_a? ProjectSnippet
- _("The snippet is visible only to project members.")
- else
- _("The snippet is visible only to me.")
- end
- when Gitlab::VisibilityLevel::INTERNAL
- _("The snippet is visible to any logged in user.")
- when Gitlab::VisibilityLevel::PUBLIC
- _("The snippet can be accessed without any authentication.")
- end
- end
-
# Note: these messages closely mirror the form validation strings found in the project
# model and any changes or additons to these may also need to be made there.
def disallowed_project_visibility_level_description(level, project)
diff --git a/app/helpers/web_ide_button_helper.rb b/app/helpers/web_ide_button_helper.rb
new file mode 100644
index 00000000000..0a4d47eed52
--- /dev/null
+++ b/app/helpers/web_ide_button_helper.rb
@@ -0,0 +1,61 @@
+# frozen_string_literal: true
+
+module WebIdeButtonHelper
+ def project_fork
+ current_user&.fork_of(@project)
+ end
+
+ def project_to_use
+ fork? ? project_fork : @project
+ end
+
+ def can_collaborate?
+ can_collaborate_with_project?(@project)
+ end
+
+ def can_create_mr_from_fork?
+ can?(current_user, :fork_project, @project) && can?(current_user, :create_merge_request_in, @project)
+ end
+
+ def show_web_ide_button?
+ can_collaborate? || can_create_mr_from_fork?
+ end
+
+ def show_edit_button?
+ readable_blob? && show_web_ide_button?
+ end
+
+ def show_gitpod_button?
+ show_web_ide_button? && Gitlab::Gitpod.feature_and_settings_enabled?(@project)
+ end
+
+ def can_push_code?
+ current_user&.can?(:push_code, @project)
+ end
+
+ def fork?
+ !project_fork.nil? && !can_push_code?
+ end
+
+ def readable_blob?
+ !readable_blob({}, @path, @project, @ref).nil?
+ end
+
+ def needs_to_fork?
+ !can_collaborate? && !current_user&.already_forked?(@project)
+ end
+
+ def web_ide_url
+ ide_edit_path(project_to_use, @ref, @path || '')
+ end
+
+ def edit_url
+ readable_blob? ? edit_blob_path(@project, @ref, @path || '') : ''
+ end
+
+ def gitpod_url
+ return "" unless Gitlab::Gitpod.feature_and_settings_enabled?(@project)
+
+ "#{Gitlab::CurrentSettings.gitpod_url}##{project_tree_url(@project, tree_join(@ref, @path || ''))}"
+ end
+end
diff --git a/app/helpers/webpack_helper.rb b/app/helpers/webpack_helper.rb
index 345ddcf023a..170e3c45a21 100644
--- a/app/helpers/webpack_helper.rb
+++ b/app/helpers/webpack_helper.rb
@@ -57,10 +57,12 @@ module WebpackHelper
end
def webpack_public_host
- if Rails.env.test? && Rails.configuration.webpack.dev_server.enabled
- host = Rails.configuration.webpack.dev_server.host
- port = Rails.configuration.webpack.dev_server.port
- protocol = Rails.configuration.webpack.dev_server.https ? 'https' : 'http'
+ # We do not proxy the webpack output in the 'test' environment,
+ # so we must reference the webpack dev server directly.
+ if Rails.env.test? && Gitlab.config.webpack.dev_server.enabled
+ host = Gitlab.config.webpack.dev_server.host
+ port = Gitlab.config.webpack.dev_server.port
+ protocol = Gitlab.config.webpack.dev_server.https ? 'https' : 'http'
"#{protocol}://#{host}:#{port}"
else
ActionController::Base.asset_host.try(:chomp, '/')
@@ -68,8 +70,8 @@ module WebpackHelper
end
def webpack_public_path
- relative_path = Rails.application.config.relative_url_root
- webpack_path = Rails.application.config.webpack.public_path
+ relative_path = Gitlab.config.gitlab.relative_url_root
+ webpack_path = Gitlab.config.webpack.public_path
File.join(webpack_public_host.to_s, relative_path.to_s, webpack_path.to_s, '')
end
end
diff --git a/app/helpers/whats_new_helper.rb b/app/helpers/whats_new_helper.rb
index f0044daa645..c183ed7f12a 100644
--- a/app/helpers/whats_new_helper.rb
+++ b/app/helpers/whats_new_helper.rb
@@ -1,24 +1,27 @@
# frozen_string_literal: true
module WhatsNewHelper
- EMPTY_JSON = ''.to_json
+ include Gitlab::WhatsNew
- def whats_new_most_recent_release_items
- YAML.load_file(most_recent_release_file_path).to_json
+ def whats_new_most_recent_release_items_count
+ Gitlab::ProcessMemoryCache.cache_backend.fetch('whats_new:release_items_count', expires_in: CACHE_DURATION) do
+ whats_new_most_recent_release_items&.count
+ end
+ end
- rescue => e
- Gitlab::ErrorTracking.track_exception(e, yaml_file_path: most_recent_release_file_path)
+ def whats_new_storage_key
+ return unless whats_new_most_recent_version
- EMPTY_JSON
+ ['display-whats-new-notification', whats_new_most_recent_version].join('-')
end
private
- def most_recent_release_file_path
- Dir.glob(files_path).max
- end
-
- def files_path
- Rails.root.join('data', 'whats_new', '*.yml')
+ def whats_new_most_recent_version
+ Gitlab::ProcessMemoryCache.cache_backend.fetch('whats_new:release_version', expires_in: CACHE_DURATION) do
+ if whats_new_most_recent_release_items
+ whats_new_most_recent_release_items.first.try(:[], 'release')
+ end
+ end
end
end
diff --git a/app/helpers/wiki_helper.rb b/app/helpers/wiki_helper.rb
index 8c756b9370b..786081ca815 100644
--- a/app/helpers/wiki_helper.rb
+++ b/app/helpers/wiki_helper.rb
@@ -142,7 +142,8 @@ module WikiHelper
'wiki-format' => page.format,
'wiki-title-size' => page.title.bytesize,
'wiki-content-size' => page.raw_content.bytesize,
- 'wiki-directory-nest-level' => page.path.scan('/').count
+ 'wiki-directory-nest-level' => page.path.scan('/').count,
+ 'wiki-container-type' => page.wiki.container.class.name
}
end
diff --git a/app/mailers/abuse_report_mailer.rb b/app/mailers/abuse_report_mailer.rb
index 0f2f63b43f5..20aabb6fe58 100644
--- a/app/mailers/abuse_report_mailer.rb
+++ b/app/mailers/abuse_report_mailer.rb
@@ -11,7 +11,7 @@ class AbuseReportMailer < ApplicationMailer
@abuse_report = AbuseReport.find(abuse_report_id)
mail(
- to: Gitlab::CurrentSettings.admin_notification_email,
+ to: Gitlab::CurrentSettings.abuse_notification_email,
subject: "#{@abuse_report.user.name} (#{@abuse_report.user.username}) was reported for abuse"
)
end
@@ -19,6 +19,6 @@ class AbuseReportMailer < ApplicationMailer
private
def deliverable?
- Gitlab::CurrentSettings.admin_notification_email.present?
+ Gitlab::CurrentSettings.abuse_notification_email.present?
end
end
diff --git a/app/mailers/emails/issues.rb b/app/mailers/emails/issues.rb
index bcf60bea0e0..10a1da90e9e 100644
--- a/app/mailers/emails/issues.rb
+++ b/app/mailers/emails/issues.rb
@@ -93,7 +93,7 @@ module Emails
def issues_csv_email(user, project, csv_data, export_status)
@project = project
- @issues_count = export_status.fetch(:rows_expected)
+ @count = export_status.fetch(:rows_expected)
@written_count = export_status.fetch(:rows_written)
@truncated = export_status.fetch(:truncated)
diff --git a/app/mailers/emails/members.rb b/app/mailers/emails/members.rb
index 3a13c5949bd..57e4c7df440 100644
--- a/app/mailers/emails/members.rb
+++ b/app/mailers/emails/members.rb
@@ -77,6 +77,38 @@ module Emails
Gitlab::Tracking.event(Gitlab::Experimentation::EXPERIMENTS[:invite_email][:tracking_category], 'sent', property: 'control_group')
end
end
+
+ if member.invite_to_unknown_user? && Gitlab::Experimentation.enabled?(:invitation_reminders)
+ Gitlab::Tracking.event(
+ Gitlab::Experimentation.experiment(:invitation_reminders).tracking_category,
+ 'sent',
+ property: Gitlab::Experimentation.enabled_for_attribute?(:invitation_reminders, member.invite_email) ? 'experimental_group' : 'control_group',
+ label: Digest::MD5.hexdigest(member.to_global_id.to_s)
+ )
+ end
+ end
+
+ def member_invited_reminder_email(member_source_type, member_id, token, reminder_index)
+ @member_source_type = member_source_type
+ @member_id = member_id
+ @token = token
+ @reminder_index = reminder_index
+
+ return unless member_exists? && member.created_by && member.invite_to_unknown_user?
+
+ subjects = {
+ 0 => s_("InviteReminderEmail|%{inviter}'s invitation to GitLab is pending"),
+ 1 => s_('InviteReminderEmail|%{inviter} is waiting for you to join GitLab'),
+ 2 => s_('InviteReminderEmail|%{inviter} is still waiting for you to join GitLab')
+ }
+
+ subject_line = subjects[reminder_index] % { inviter: member.created_by.name }
+
+ member_email_with_layout(
+ layout: 'experiment_mailer',
+ to: member.invite_email,
+ subject: subject(subject_line)
+ )
end
def member_invite_accepted_email(member_source_type, member_id)
diff --git a/app/mailers/emails/merge_requests.rb b/app/mailers/emails/merge_requests.rb
index c709c2950d6..28ac752f550 100644
--- a/app/mailers/emails/merge_requests.rb
+++ b/app/mailers/emails/merge_requests.rb
@@ -34,6 +34,17 @@ module Emails
end
# rubocop: enable CodeReuse/ActiveRecord
+ # rubocop: disable CodeReuse/ActiveRecord
+ def changed_reviewer_of_merge_request_email(recipient_id, merge_request_id, previous_reviewer_ids, updated_by_user_id, reason = nil)
+ setup_merge_request_mail(merge_request_id, recipient_id)
+
+ @previous_reviewers = []
+ @previous_reviewers = User.where(id: previous_reviewer_ids) if previous_reviewer_ids.any?
+
+ mail_answer_thread(@merge_request, merge_request_thread_options(updated_by_user_id, recipient_id, reason))
+ end
+ # rubocop: enable CodeReuse/ActiveRecord
+
def relabeled_merge_request_email(recipient_id, merge_request_id, label_names, updated_by_user_id, reason = nil)
setup_merge_request_mail(merge_request_id, recipient_id)
@@ -99,6 +110,20 @@ module Emails
mail_answer_thread(@merge_request, merge_request_thread_options(mwps_set_by_user_id, recipient_id, reason))
end
+ def merge_requests_csv_email(user, project, csv_data, export_status)
+ @project = project
+ @count = export_status.fetch(:rows_expected)
+ @written_count = export_status.fetch(:rows_written)
+ @truncated = export_status.fetch(:truncated)
+
+ filename = "#{project.full_path.parameterize}_merge_requests_#{Date.current.iso8601}.csv"
+ attachments[filename] = { content: csv_data, mime_type: 'text/csv' }
+ mail(to: user.notification_email_for(@project.group), subject: subject("Exported merge requests")) do |format|
+ format.html { render layout: 'mailer' }
+ format.text { render layout: 'mailer' }
+ end
+ end
+
private
def setup_merge_request_mail(merge_request_id, recipient_id, present: false)
diff --git a/app/mailers/emails/projects.rb b/app/mailers/emails/projects.rb
index fdf40a77ca4..17ef8b41e79 100644
--- a/app/mailers/emails/projects.rb
+++ b/app/mailers/emails/projects.rb
@@ -56,16 +56,14 @@ module Emails
subject: @message.subject)
end
- def prometheus_alert_fired_email(project_id, user_id, alert_payload)
+ def prometheus_alert_fired_email(project_id, user_id, alert_attributes)
@project = ::Project.find(project_id)
user = ::User.find(user_id)
- @alert = ::Gitlab::Alerting::Alert
- .new(project: @project, payload: alert_payload)
- .present
- return unless @alert.valid?
+ @alert = AlertManagement::Alert.new(alert_attributes.with_indifferent_access).present
+ return unless @alert.parsed_payload.has_required_attributes?
- subject_text = "Alert: #{@alert.full_title}"
+ subject_text = "Alert: #{@alert.email_title}"
mail(to: user.notification_email_for(@project.group), subject: subject(subject_text))
end
end
diff --git a/app/mailers/notify.rb b/app/mailers/notify.rb
index f9aba3fe4f2..ebf6dd68ec7 100644
--- a/app/mailers/notify.rb
+++ b/app/mailers/notify.rb
@@ -4,6 +4,7 @@ class Notify < ApplicationMailer
include ActionDispatch::Routing::PolymorphicRoutes
include GitlabRoutingHelper
include EmailsHelper
+ include ReminderEmailsHelper
include IssuablesHelper
include Emails::Issues
@@ -26,6 +27,7 @@ class Notify < ApplicationMailer
helper DiffHelper
helper BlobHelper
helper EmailsHelper
+ helper ReminderEmailsHelper
helper MembersHelper
helper AvatarsHelper
helper GitlabRoutingHelper
diff --git a/app/models/alert_management/alert.rb b/app/models/alert_management/alert.rb
index e9b89af45c6..61cc15a522e 100644
--- a/app/models/alert_management/alert.rb
+++ b/app/models/alert_management/alert.rb
@@ -20,18 +20,7 @@ module AlertManagement
resolved: 2,
ignored: 3
}.freeze
-
- STATUS_EVENTS = {
- triggered: :trigger,
- acknowledged: :acknowledge,
- resolved: :resolve,
- ignored: :ignore
- }.freeze
-
- OPEN_STATUSES = [
- :triggered,
- :acknowledged
- ].freeze
+ private_constant :STATUSES
belongs_to :project
belongs_to :issue, optional: true
@@ -49,12 +38,16 @@ module AlertManagement
sha_attribute :fingerprint
+ TITLE_MAX_LENGTH = 200
+ DESCRIPTION_MAX_LENGTH = 1_000
+ SERVICE_MAX_LENGTH = 100
+ TOOL_MAX_LENGTH = 100
HOSTS_MAX_LENGTH = 255
- validates :title, length: { maximum: 200 }, presence: true
- validates :description, length: { maximum: 1_000 }
- validates :service, length: { maximum: 100 }
- validates :monitoring_tool, length: { maximum: 100 }
+ validates :title, length: { maximum: TITLE_MAX_LENGTH }, presence: true
+ validates :description, length: { maximum: DESCRIPTION_MAX_LENGTH }
+ validates :service, length: { maximum: SERVICE_MAX_LENGTH }
+ validates :monitoring_tool, length: { maximum: TOOL_MAX_LENGTH }
validates :project, presence: true
validates :events, presence: true
validates :severity, presence: true
@@ -65,7 +58,7 @@ module AlertManagement
conditions: -> { not_resolved },
message: -> (object, data) { _('Cannot have multiple unresolved alerts') }
}, unless: :resolved?
- validate :hosts_length
+ validate :hosts_format
enum severity: {
critical: 0,
@@ -121,12 +114,13 @@ module AlertManagement
delegate :details_url, to: :present
scope :for_iid, -> (iid) { where(iid: iid) }
- scope :for_status, -> (status) { where(status: status) }
+ scope :for_status, -> (status) { with_status(status) }
scope :for_fingerprint, -> (project, fingerprint) { where(project: project, fingerprint: fingerprint) }
scope :for_environment, -> (environment) { where(environment: environment) }
+ scope :for_assignee_username, -> (assignee_username) { joins(:assignees).merge(User.by_username(assignee_username)) }
scope :search, -> (query) { fuzzy_search(query, [:title, :description, :monitoring_tool, :service]) }
- scope :open, -> { with_status(OPEN_STATUSES) }
- scope :not_resolved, -> { where.not(status: STATUSES[:resolved]) }
+ scope :open, -> { with_status(open_statuses) }
+ scope :not_resolved, -> { without_status(:resolved) }
scope :with_prometheus_alert, -> { includes(:prometheus_alert) }
scope :order_start_time, -> (sort_order) { order(started_at: sort_order) }
@@ -142,13 +136,33 @@ module AlertManagement
# Ascending sort order sorts statuses: Ignored > Resolved > Acknowledged > Triggered
# Descending sort order sorts statuses: Triggered > Acknowledged > Resolved > Ignored
# https://gitlab.com/gitlab-org/gitlab/-/issues/221242#what-is-the-expected-correct-behavior
- scope :order_status, -> (sort_order) { order(status: sort_order == :asc ? :desc : :asc) }
+ scope :order_status, -> (sort_order) { order(status: sort_order == :asc ? :desc : :asc) }
- scope :counts_by_status, -> { group(:status).count }
scope :counts_by_project_id, -> { group(:project_id).count }
alias_method :state, :status_name
+ def self.state_machine_statuses
+ @state_machine_statuses ||= state_machines[:status].states.to_h { |s| [s.name, s.value] }
+ end
+ private_class_method :state_machine_statuses
+
+ def self.status_value(name)
+ state_machine_statuses[name]
+ end
+
+ def self.status_name(raw_status)
+ state_machine_statuses.key(raw_status)
+ end
+
+ def self.counts_by_status
+ group(:status).count.transform_keys { |k| status_name(k) }
+ end
+
+ def self.status_names
+ @status_names ||= state_machine_statuses.keys
+ end
+
def self.sort_by_attribute(method)
case method.to_s
when 'started_at_asc' then order_start_time(:asc)
@@ -190,8 +204,25 @@ module AlertManagement
reference.to_i > 0 && reference.to_i <= Gitlab::Database::MAX_INT_VALUE
end
+ def self.open_statuses
+ [:triggered, :acknowledged]
+ end
+
+ def self.open_status?(status)
+ open_statuses.include?(status)
+ end
+
+ def status_event_for(status)
+ self.class.state_machines[:status].events.transitions_for(self, to: status.to_s.to_sym).first&.event
+ end
+
+ def change_status_to(new_status)
+ event = status_event_for(new_status)
+ event && fire_status_event(event)
+ end
+
def prometheus?
- monitoring_tool == Gitlab::AlertManagement::AlertParams::MONITORING_TOOLS[:prometheus]
+ monitoring_tool == Gitlab::AlertManagement::Payload::MONITORING_TOOLS[:prometheus]
end
def register_new_event!
@@ -224,10 +255,11 @@ module AlertManagement
Gitlab::DataBuilder::Alert.build(self)
end
- def hosts_length
+ def hosts_format
return unless hosts
errors.add(:hosts, "hosts array is over #{HOSTS_MAX_LENGTH} chars") if hosts.join.length > HOSTS_MAX_LENGTH
+ errors.add(:hosts, "hosts array cannot be nested") if hosts.flatten != hosts
end
end
end
diff --git a/app/models/alert_management/http_integration.rb b/app/models/alert_management/http_integration.rb
new file mode 100644
index 00000000000..7f954e1d384
--- /dev/null
+++ b/app/models/alert_management/http_integration.rb
@@ -0,0 +1,41 @@
+# frozen_string_literal: true
+
+module AlertManagement
+ class HttpIntegration < ApplicationRecord
+ belongs_to :project, inverse_of: :alert_management_http_integrations
+
+ attr_encrypted :token,
+ mode: :per_attribute_iv,
+ key: Settings.attr_encrypted_db_key_base_truncated,
+ algorithm: 'aes-256-gcm'
+
+ validates :project, presence: true
+ validates :active, inclusion: { in: [true, false] }
+
+ validates :token, presence: true
+ validates :name, presence: true, length: { maximum: 255 }
+ validates :endpoint_identifier, presence: true, length: { maximum: 255 }
+ validates :endpoint_identifier, uniqueness: { scope: [:project_id, :active] }, if: :active?
+
+ before_validation :prevent_token_assignment
+ before_validation :ensure_token
+
+ private
+
+ def prevent_token_assignment
+ if token.present? && token_changed?
+ self.token = nil
+ self.encrypted_token = encrypted_token_was
+ self.encrypted_token_iv = encrypted_token_iv_was
+ end
+ end
+
+ def ensure_token
+ self.token = generate_token if token.blank?
+ end
+
+ def generate_token
+ SecureRandom.hex
+ end
+ end
+end
diff --git a/app/models/analytics/instance_statistics/measurement.rb b/app/models/analytics/instance_statistics/measurement.rb
index eaaf9e999b3..76cc1111e90 100644
--- a/app/models/analytics/instance_statistics/measurement.rb
+++ b/app/models/analytics/instance_statistics/measurement.rb
@@ -3,13 +3,19 @@
module Analytics
module InstanceStatistics
class Measurement < ApplicationRecord
+ EXPERIMENTAL_IDENTIFIERS = %i[pipelines_succeeded pipelines_failed pipelines_canceled pipelines_skipped].freeze
+
enum identifier: {
projects: 1,
users: 2,
issues: 3,
merge_requests: 4,
groups: 5,
- pipelines: 6
+ pipelines: 6,
+ pipelines_succeeded: 7,
+ pipelines_failed: 8,
+ pipelines_canceled: 9,
+ pipelines_skipped: 10
}
IDENTIFIER_QUERY_MAPPING = {
@@ -18,7 +24,11 @@ module Analytics
identifiers[:issues] => -> { Issue },
identifiers[:merge_requests] => -> { MergeRequest },
identifiers[:groups] => -> { Group },
- identifiers[:pipelines] => -> { Ci::Pipeline }
+ identifiers[:pipelines] => -> { Ci::Pipeline },
+ identifiers[:pipelines_succeeded] => -> { Ci::Pipeline.success },
+ identifiers[:pipelines_failed] => -> { Ci::Pipeline.failed },
+ identifiers[:pipelines_canceled] => -> { Ci::Pipeline.canceled },
+ identifiers[:pipelines_skipped] => -> { Ci::Pipeline.skipped }
}.freeze
validates :recorded_at, :identifier, :count, presence: true
@@ -26,6 +36,14 @@ module Analytics
scope :order_by_latest, -> { order(recorded_at: :desc) }
scope :with_identifier, -> (identifier) { where(identifier: identifier) }
+
+ def self.measurement_identifier_values
+ if Feature.enabled?(:store_ci_pipeline_counts_by_status, default_enabled: true)
+ identifiers.values
+ else
+ identifiers.values - EXPERIMENTAL_IDENTIFIERS.map { |identifier| identifiers[identifier] }
+ end
+ end
end
end
end
diff --git a/app/models/application_record.rb b/app/models/application_record.rb
index 6ffb9b7642a..3542bb90dc0 100644
--- a/app/models/application_record.rb
+++ b/app/models/application_record.rb
@@ -52,6 +52,16 @@ class ApplicationRecord < ActiveRecord::Base
end
end
+ # Start a new transaction with a shorter-than-usual statement timeout. This is
+ # currently one third of the default 15-second timeout
+ def self.with_fast_statement_timeout
+ transaction(requires_new: true) do
+ connection.exec_query("SET LOCAL statement_timeout = 5000")
+
+ yield
+ end
+ end
+
def self.safe_find_or_create_by(*args, &block)
safe_ensure_unique(retries: 1) do
find_or_create_by(*args, &block)
@@ -61,4 +71,8 @@ class ApplicationRecord < ActiveRecord::Base
def self.underscore
Gitlab::SafeRequestStore.fetch("model:#{self}:underscore") { self.to_s.underscore }
end
+
+ def self.where_exists(query)
+ where('EXISTS (?)', query.select(1))
+ end
end
diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb
index e9a3dcf39df..d034630a085 100644
--- a/app/models/application_setting.rb
+++ b/app/models/application_setting.rb
@@ -11,6 +11,7 @@ class ApplicationSetting < ApplicationRecord
ignore_column :instance_statistics_visibility_private, remove_with: '13.6', remove_after: '2020-10-22'
ignore_column :snowplow_iglu_registry_url, remove_with: '13.6', remove_after: '2020-11-22'
+ INSTANCE_REVIEW_MIN_USERS = 50
GRAFANA_URL_ERROR_MESSAGE = 'Please check your Grafana URL setting in ' \
'Admin Area > Settings > Metrics and profiling > Metrics - Grafana'
@@ -91,11 +92,16 @@ class ApplicationSetting < ApplicationRecord
addressable_url: true,
if: :help_page_support_url_column_exists?
+ validates :help_page_documentation_base_url,
+ length: { maximum: 255, message: _("is too long (maximum is %{count} characters)") },
+ allow_blank: true,
+ addressable_url: true
+
validates :after_sign_out_path,
allow_blank: true,
addressable_url: true
- validates :admin_notification_email,
+ validates :abuse_notification_email,
devise_email: true,
allow_blank: true
@@ -432,6 +438,14 @@ class ApplicationSetting < ApplicationRecord
!!(sourcegraph_url =~ /\Ahttps:\/\/(www\.)?sourcegraph\.com/)
end
+ def instance_review_permitted?
+ users_count = Rails.cache.fetch('limited_users_count', expires_in: 1.day) do
+ ::User.limit(INSTANCE_REVIEW_MIN_USERS + 1).count(:all)
+ end
+
+ users_count >= INSTANCE_REVIEW_MIN_USERS
+ end
+
def self.create_from_defaults
check_schema!
diff --git a/app/models/application_setting/term.rb b/app/models/application_setting/term.rb
index 723540c9b91..bab036f5697 100644
--- a/app/models/application_setting/term.rb
+++ b/app/models/application_setting/term.rb
@@ -14,6 +14,8 @@ class ApplicationSetting
end
def accepted_by_user?(user)
+ return true if user.project_bot?
+
user.accepted_term_id == id ||
term_agreements.accepted.where(user: user).exists?
end
diff --git a/app/models/application_setting_implementation.rb b/app/models/application_setting_implementation.rb
index 7a869d16a31..8a7bd5a7ad9 100644
--- a/app/models/application_setting_implementation.rb
+++ b/app/models/application_setting_implementation.rb
@@ -82,6 +82,7 @@ module ApplicationSettingImplementation
group_import_limit: 6,
help_page_hide_commercial_content: false,
help_page_text: nil,
+ help_page_documentation_base_url: nil,
hide_third_party_offers: false,
housekeeping_bitmaps_enabled: true,
housekeeping_enabled: true,
@@ -119,6 +120,7 @@ module ApplicationSettingImplementation
repository_checks_enabled: true,
repository_storages_weighted: { default: 100 },
repository_storages: ['default'],
+ require_admin_approval_after_user_signup: false,
require_two_factor_authentication: false,
restricted_visibility_levels: Settings.gitlab['restricted_visibility_levels'],
rsa_key_restriction: 0,
diff --git a/app/models/audit_event.rb b/app/models/audit_event.rb
index f46803be057..34f03e769a0 100644
--- a/app/models/audit_event.rb
+++ b/app/models/audit_event.rb
@@ -4,8 +4,15 @@ class AuditEvent < ApplicationRecord
include CreatedAtFilterable
include IgnorableColumns
include BulkInsertSafe
+ include EachBatch
- PARALLEL_PERSISTENCE_COLUMNS = [:author_name, :entity_path, :target_details, :target_type].freeze
+ PARALLEL_PERSISTENCE_COLUMNS = [
+ :author_name,
+ :entity_path,
+ :target_details,
+ :target_type,
+ :target_id
+ ].freeze
ignore_column :type, remove_with: '13.6', remove_after: '2020-11-22'
@@ -16,6 +23,7 @@ class AuditEvent < ApplicationRecord
validates :author_id, presence: true
validates :entity_id, presence: true
validates :entity_type, presence: true
+ validates :ip_address, ip_address: true
scope :by_entity_type, -> (entity_type) { where(entity_type: entity_type) }
scope :by_entity_id, -> (entity_id) { where(entity_id: entity_id) }
@@ -47,7 +55,9 @@ class AuditEvent < ApplicationRecord
end
def initialize_details
- self.details = {} if details.nil?
+ return unless self.has_attribute?(:details)
+
+ self.details = {} if details&.nil?
end
def author_name
@@ -59,8 +69,8 @@ class AuditEvent < ApplicationRecord
end
def lazy_author
- BatchLoader.for(author_id).batch(default_value: default_author_value) do |author_ids, loader|
- User.where(id: author_ids).find_each do |user|
+ BatchLoader.for(author_id).batch(default_value: default_author_value, replace_methods: false) do |author_ids, loader|
+ User.select(:id, :name, :username).where(id: author_ids).find_each do |user|
loader.call(user.id, user)
end
end
diff --git a/app/models/authentication_event.rb b/app/models/authentication_event.rb
index 1ac3c5fbd9c..ac6e08caf50 100644
--- a/app/models/authentication_event.rb
+++ b/app/models/authentication_event.rb
@@ -1,12 +1,22 @@
# frozen_string_literal: true
class AuthenticationEvent < ApplicationRecord
+ include UsageStatistics
+
belongs_to :user, optional: true
validates :provider, :user_name, :result, presence: true
+ validates :ip_address, ip_address: true
enum result: {
failed: 0,
success: 1
}
+
+ scope :for_provider, ->(provider) { where(provider: provider) }
+ scope :ldap, -> { where('provider LIKE ?', 'ldap%')}
+
+ def self.providers
+ distinct.pluck(:provider)
+ end
end
diff --git a/app/models/blob_viewer/balsamiq.rb b/app/models/blob_viewer/balsamiq.rb
index 1af6c5474d7..6ab73730222 100644
--- a/app/models/blob_viewer/balsamiq.rb
+++ b/app/models/blob_viewer/balsamiq.rb
@@ -8,7 +8,7 @@ module BlobViewer
self.partial_name = 'balsamiq'
self.extensions = %w(bmpr)
self.binary = true
- self.switcher_icon = 'file-image-o'
+ self.switcher_icon = 'doc-image'
self.switcher_title = 'preview'
end
end
diff --git a/app/models/blob_viewer/markup.rb b/app/models/blob_viewer/markup.rb
index f525180048e..37a8e01d0f1 100644
--- a/app/models/blob_viewer/markup.rb
+++ b/app/models/blob_viewer/markup.rb
@@ -9,5 +9,15 @@ module BlobViewer
self.extensions = Gitlab::MarkupHelper::EXTENSIONS
self.file_types = %i(readme)
self.binary = false
+
+ def banzai_render_context
+ {}.tap do |h|
+ h[:rendered] = blob.rendered_markup if blob.respond_to?(:rendered_markup)
+
+ if Feature.enabled?(:cached_markdown_blob, blob.project, default_enabled: true)
+ h[:cache_key] = ['blob', blob.id, 'commit', blob.commit_id]
+ end
+ end
+ end
end
end
diff --git a/app/models/blob_viewer/pdf.rb b/app/models/blob_viewer/pdf.rb
index 2cf7752585c..e3542b91d5c 100644
--- a/app/models/blob_viewer/pdf.rb
+++ b/app/models/blob_viewer/pdf.rb
@@ -8,7 +8,7 @@ module BlobViewer
self.partial_name = 'pdf'
self.extensions = %w(pdf)
self.binary = true
- self.switcher_icon = 'file-pdf-o'
+ self.switcher_icon = 'document'
self.switcher_title = 'PDF'
end
end
diff --git a/app/models/blob_viewer/sketch.rb b/app/models/blob_viewer/sketch.rb
index 659ab11f30b..90bc9be29f4 100644
--- a/app/models/blob_viewer/sketch.rb
+++ b/app/models/blob_viewer/sketch.rb
@@ -8,7 +8,7 @@ module BlobViewer
self.partial_name = 'sketch'
self.extensions = %w(sketch)
self.binary = true
- self.switcher_icon = 'file-image-o'
+ self.switcher_icon = 'doc-image'
self.switcher_title = 'preview'
end
end
diff --git a/app/models/bulk_import.rb b/app/models/bulk_import.rb
new file mode 100644
index 00000000000..cabff86a9f9
--- /dev/null
+++ b/app/models/bulk_import.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+class BulkImport < ApplicationRecord
+ belongs_to :user, optional: false
+
+ has_one :configuration, class_name: 'BulkImports::Configuration'
+ has_many :entities, class_name: 'BulkImports::Entity'
+
+ validates :source_type, :status, presence: true
+
+ enum source_type: { gitlab: 0 }
+
+ state_machine :status, initial: :created do
+ state :created, value: 0
+ end
+end
diff --git a/app/models/bulk_imports/configuration.rb b/app/models/bulk_imports/configuration.rb
new file mode 100644
index 00000000000..8c3aff6f749
--- /dev/null
+++ b/app/models/bulk_imports/configuration.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+class BulkImports::Configuration < ApplicationRecord
+ self.table_name = 'bulk_import_configurations'
+
+ belongs_to :bulk_import, inverse_of: :configuration, optional: false
+
+ validates :url, :access_token, length: { maximum: 255 }, presence: true
+ validates :url, public_url: { schemes: %w[http https], enforce_sanitization: true, ascii_only: true },
+ allow_nil: true
+
+ attr_encrypted :url,
+ key: Settings.attr_encrypted_db_key_base_truncated,
+ mode: :per_attribute_iv,
+ algorithm: 'aes-256-gcm'
+ attr_encrypted :access_token,
+ key: Settings.attr_encrypted_db_key_base_truncated,
+ mode: :per_attribute_iv,
+ algorithm: 'aes-256-gcm'
+end
diff --git a/app/models/bulk_imports/entity.rb b/app/models/bulk_imports/entity.rb
new file mode 100644
index 00000000000..2d0bba7bccc
--- /dev/null
+++ b/app/models/bulk_imports/entity.rb
@@ -0,0 +1,43 @@
+# frozen_string_literal: true
+
+class BulkImports::Entity < ApplicationRecord
+ self.table_name = 'bulk_import_entities'
+
+ belongs_to :bulk_import, optional: false
+ belongs_to :parent, class_name: 'BulkImports::Entity', optional: true
+
+ belongs_to :project, optional: true
+ belongs_to :group, foreign_key: :namespace_id, optional: true
+
+ validates :project, absence: true, if: :group
+ validates :group, absence: true, if: :project
+ validates :source_type, :source_full_path, :destination_name,
+ :destination_namespace, presence: true
+
+ validate :validate_parent_is_a_group, if: :parent
+ validate :validate_imported_entity_type
+
+ enum source_type: { group_entity: 0, project_entity: 1 }
+
+ state_machine :status, initial: :created do
+ state :created, value: 0
+ end
+
+ private
+
+ def validate_parent_is_a_group
+ unless parent.group_entity?
+ errors.add(:parent, s_('BulkImport|must be a group'))
+ end
+ end
+
+ def validate_imported_entity_type
+ if group.present? && project_entity?
+ errors.add(:group, s_('BulkImport|expected an associated Project but has an associated Group'))
+ end
+
+ if project.present? && group_entity?
+ errors.add(:project, s_('BulkImport|expected an associated Group but has an associated Project'))
+ end
+ end
+end
diff --git a/app/models/ci/bridge.rb b/app/models/ci/bridge.rb
index 1697067f633..2e725e0baff 100644
--- a/app/models/ci/bridge.rb
+++ b/app/models/ci/bridge.rb
@@ -27,7 +27,7 @@ module Ci
# rubocop:enable Cop/ActiveRecordSerialize
state_machine :status do
- after_transition created: :pending do |bridge|
+ after_transition [:created, :manual] => :pending do |bridge|
next unless bridge.downstream_project
bridge.run_after_commit do
@@ -46,6 +46,10 @@ module Ci
event :scheduled do
transition all => :scheduled
end
+
+ event :actionize do
+ transition created: :manual
+ end
end
def self.retry(bridge, current_user)
@@ -126,9 +130,27 @@ module Ci
false
end
+ def playable?
+ return false unless ::Gitlab::Ci::Features.manual_bridges_enabled?(project)
+
+ action? && !archived? && manual?
+ end
+
def action?
- false
+ return false unless ::Gitlab::Ci::Features.manual_bridges_enabled?(project)
+
+ %w[manual].include?(self.when)
+ end
+
+ # rubocop: disable CodeReuse/ServiceClass
+ # We don't need it but we are taking `job_variables_attributes` parameter
+ # to make it consistent with `Ci::Build#play` method.
+ def play(current_user, job_variables_attributes = nil)
+ Ci::PlayBridgeService
+ .new(project, current_user)
+ .execute(self)
end
+ # rubocop: enable CodeReuse/ServiceClass
def artifacts?
false
@@ -185,6 +207,10 @@ module Ci
[]
end
+ def target_revision_ref
+ downstream_pipeline_params.dig(:target_revision, :ref)
+ end
+
private
def cross_project_params
diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb
index 99580a52e96..9ff70ece947 100644
--- a/app/models/ci/build.rb
+++ b/app/models/ci/build.rb
@@ -327,6 +327,8 @@ module Ci
after_transition any => [:success, :failed, :canceled] do |build|
build.run_after_commit do
+ build.run_status_commit_hooks!
+
BuildFinishedWorker.perform_async(id)
end
end
@@ -524,7 +526,6 @@ module Ci
.concat(job_jwt_variables)
.concat(scoped_variables)
.concat(job_variables)
- .concat(environment_changed_page_variables)
.concat(persisted_environment_variables)
.to_runner_variables
end
@@ -561,15 +562,6 @@ module Ci
end
end
- def environment_changed_page_variables
- Gitlab::Ci::Variables::Collection.new.tap do |variables|
- break variables unless environment_status && Feature.enabled?(:modifed_path_ci_variables, project)
-
- variables.append(key: 'CI_MERGE_REQUEST_CHANGED_PAGE_PATHS', value: environment_status.changed_paths.join(','))
- variables.append(key: 'CI_MERGE_REQUEST_CHANGED_PAGE_URLS', value: environment_status.changed_urls.join(','))
- end
- end
-
def deploy_token_variables
Gitlab::Ci::Variables::Collection.new.tap do |variables|
break variables unless gitlab_deploy_token
@@ -780,6 +772,11 @@ module Ci
end
end
+ def has_expired_locked_archive_artifacts?
+ locked_artifacts? &&
+ artifacts_expire_at.present? && artifacts_expire_at < Time.current
+ end
+
def has_expiring_archive_artifacts?
has_expiring_artifacts? && job_artifacts_archive.present?
end
@@ -901,7 +898,11 @@ module Ci
def collect_test_reports!(test_reports)
test_reports.get_suite(group_name).tap do |test_suite|
each_report(Ci::JobArtifact::TEST_REPORT_FILE_TYPES) do |file_type, blob|
- Gitlab::Ci::Parsers.fabricate!(file_type).parse!(blob, test_suite, job: self)
+ Gitlab::Ci::Parsers.fabricate!(file_type).parse!(
+ blob,
+ test_suite,
+ job: self
+ )
end
end
end
@@ -963,8 +964,30 @@ module Ci
pending_state.try(:delete)
end
+ def run_on_status_commit(&block)
+ status_commit_hooks.push(block)
+ end
+
+ def max_test_cases_per_report
+ # NOTE: This is temporary and will be replaced later by a value
+ # that would come from an actual application limit.
+ ::Gitlab.com? ? 500_000 : 0
+ end
+
+ protected
+
+ def run_status_commit_hooks!
+ status_commit_hooks.reverse_each do |hook|
+ instance_eval(&hook)
+ end
+ end
+
private
+ def status_commit_hooks
+ @status_commit_hooks ||= []
+ end
+
def auto_retry
strong_memoize(:auto_retry) do
Gitlab::Ci::Build::AutoRetry.new(self)
diff --git a/app/models/ci/build_pending_state.rb b/app/models/ci/build_pending_state.rb
index 45f323adec2..299c67f441d 100644
--- a/app/models/ci/build_pending_state.rb
+++ b/app/models/ci/build_pending_state.rb
@@ -9,4 +9,10 @@ class Ci::BuildPendingState < ApplicationRecord
enum failure_reason: CommitStatus.failure_reasons
validates :build, presence: true
+
+ def crc32
+ trace_checksum.try do |checksum|
+ checksum.to_s.split('crc32:').last.to_i(16)
+ end
+ end
end
diff --git a/app/models/ci/build_trace_chunk.rb b/app/models/ci/build_trace_chunk.rb
index 444742062d9..6926ccd9438 100644
--- a/app/models/ci/build_trace_chunk.rb
+++ b/app/models/ci/build_trace_chunk.rb
@@ -3,9 +3,11 @@
module Ci
class BuildTraceChunk < ApplicationRecord
extend ::Gitlab::Ci::Model
+ include ::Comparable
include ::FastDestroyAll
include ::Checksummable
include ::Gitlab::ExclusiveLeaseHelpers
+ include ::Gitlab::OptimisticLocking
belongs_to :build, class_name: "Ci::Build", foreign_key: :build_id
@@ -29,6 +31,7 @@ module Ci
}
scope :live, -> { redis }
+ scope :persisted, -> { not_redis.order(:chunk_index) }
class << self
def all_stores
@@ -63,12 +66,24 @@ module Ci
get_store_class(store).delete_keys(value)
end
end
+
+ ##
+ # Sometimes we do not want to read raw data. This method makes it easier
+ # to find attributes that are just metadata excluding raw data.
+ #
+ def metadata_attributes
+ attribute_names - %w[raw_data]
+ end
end
def data
@data ||= get_data.to_s
end
+ def crc32
+ checksum.to_i
+ end
+
def truncate(offset = 0)
raise ArgumentError, 'Offset is out of range' if offset > size || offset < 0
return if offset == size # Skip the following process as it doesn't affect anything
@@ -102,22 +117,47 @@ module Ci
(start_offset...end_offset)
end
- def persist_data!
- in_lock(*lock_params) { unsafe_persist_data! }
- end
-
def schedule_to_persist!
- return if persisted?
+ return if flushed?
Ci::BuildTraceChunkFlushWorker.perform_async(id)
end
- def persisted?
- !redis?
- end
+ ##
+ # It is possible that we run into two concurrent migrations. It might
+ # happen that a chunk gets migrated after being loaded by another worker
+ # but before the worker acquires a lock to perform the migration.
+ #
+ # We are using Redis locking to ensure that we perform this operation
+ # inside an exclusive lock, but this does not prevent us from running into
+ # race conditions related to updating a model representation in the
+ # database. Optimistic locking is another mechanism that help here.
+ #
+ # We are using optimistic locking combined with Redis locking to ensure
+ # that a chunk gets migrated properly.
+ #
+ # We are catching an exception related to an exclusive lock not being
+ # acquired because it is creating a lot of noise, and is a result of
+ # duplicated workers running in parallel for the same build trace chunk.
+ #
+ def persist_data!
+ in_lock(*lock_params) do # exclusive Redis lock is acquired first
+ raise FailedToPersistDataError, 'Modifed build trace chunk detected' if has_changes_to_save?
- def live?
- redis?
+ self.reset.then do |chunk| # we ensure having latest lock_version
+ chunk.unsafe_persist_data! # we migrate the data and update data store
+ end
+ end
+ rescue FailedToObtainLockError
+ metrics.increment_trace_operation(operation: :stalled)
+ rescue ActiveRecord::StaleObjectError
+ raise FailedToPersistDataError, <<~MSG
+ Data migration race condition detected
+
+ store: #{data_store}
+ build: #{build.id}
+ index: #{chunk_index}
+ MSG
end
##
@@ -126,11 +166,28 @@ module Ci
# no chunk with higher index in the database.
#
def final?
- build.pending_state.present? &&
- build.trace_chunks.maximum(:chunk_index).to_i == chunk_index
+ build.pending_state.present? && chunks_max_index == chunk_index
end
- private
+ def flushed?
+ !redis?
+ end
+
+ def migrated?
+ flushed?
+ end
+
+ def live?
+ redis?
+ end
+
+ def <=>(other)
+ return unless self.build_id == other.build_id
+
+ self.chunk_index <=> other.chunk_index
+ end
+
+ protected
def get_data
# Redis / database return UTF-8 encoded string by default
@@ -145,12 +202,19 @@ module Ci
current_size = current_data&.bytesize.to_i
unless current_size == CHUNK_SIZE || final?
- raise FailedToPersistDataError, 'Data is not fulfilled in a bucket'
+ raise FailedToPersistDataError, <<~MSG
+ data is not fulfilled in a bucket
+
+ size: #{current_size}
+ state: #{pending_state?}
+ max: #{chunks_max_index}
+ index: #{chunk_index}
+ MSG
end
self.raw_data = nil
self.data_store = new_store
- self.checksum = crc32(current_data)
+ self.checksum = self.class.crc32(current_data)
##
# We need to so persist data then save a new store identifier before we
@@ -199,10 +263,20 @@ module Ci
size == CHUNK_SIZE
end
+ private
+
+ def pending_state?
+ build.pending_state.present?
+ end
+
def current_store
self.class.get_store_class(data_store)
end
+ def chunks_max_index
+ build.trace_chunks.maximum(:chunk_index).to_i
+ end
+
def lock_params
["trace_write:#{build_id}:chunks:#{chunk_index}",
{ ttl: WRITE_LOCK_TTL,
diff --git a/app/models/ci/build_trace_chunks/database.rb b/app/models/ci/build_trace_chunks/database.rb
index ea8072099c6..7448afba4c2 100644
--- a/app/models/ci/build_trace_chunks/database.rb
+++ b/app/models/ci/build_trace_chunks/database.rb
@@ -17,6 +17,8 @@ module Ci
def data(model)
model.raw_data
+ rescue ActiveModel::MissingAttributeError
+ model.reset.raw_data
end
def set_data(model, new_data)
diff --git a/app/models/ci/deleted_object.rb b/app/models/ci/deleted_object.rb
new file mode 100644
index 00000000000..e74946eda16
--- /dev/null
+++ b/app/models/ci/deleted_object.rb
@@ -0,0 +1,37 @@
+# frozen_string_literal: true
+
+module Ci
+ class DeletedObject < ApplicationRecord
+ extend Gitlab::Ci::Model
+
+ mount_uploader :file, DeletedObjectUploader
+
+ scope :ready_for_destruction, ->(limit) do
+ where('pick_up_at < ?', Time.current).limit(limit)
+ end
+
+ scope :lock_for_destruction, ->(limit) do
+ ready_for_destruction(limit)
+ .select(:id)
+ .order(:pick_up_at)
+ .lock('FOR UPDATE SKIP LOCKED')
+ end
+
+ def self.bulk_import(artifacts)
+ attributes = artifacts.each.with_object([]) do |artifact, accumulator|
+ record = artifact.to_deleted_object_attrs
+ accumulator << record if record[:store_dir] && record[:file]
+ end
+
+ self.insert_all(attributes) if attributes.any?
+ end
+
+ def delete_file_from_storage
+ file.remove!
+ true
+ rescue => exception
+ Gitlab::ErrorTracking.track_exception(exception)
+ false
+ end
+ end
+end
diff --git a/app/models/ci/job_artifact.rb b/app/models/ci/job_artifact.rb
index 8bbb92e319f..02e17afdab0 100644
--- a/app/models/ci/job_artifact.rb
+++ b/app/models/ci/job_artifact.rb
@@ -46,7 +46,8 @@ module Ci
terraform: 'tfplan.json',
cluster_applications: 'gl-cluster-applications.json',
requirements: 'requirements.json',
- coverage_fuzzing: 'gl-coverage-fuzzing.json'
+ coverage_fuzzing: 'gl-coverage-fuzzing.json',
+ api_fuzzing: 'gl-api-fuzzing-report.json'
}.freeze
INTERNAL_TYPES = {
@@ -65,11 +66,8 @@ module Ci
cluster_applications: :gzip,
lsif: :zip,
- # All these file formats use `raw` as we need to store them uncompressed
- # for Frontend to fetch the files and do analysis
- # When they will be only used by backend, they can be `gzipped`.
- accessibility: :raw,
- codequality: :raw,
+ # Security reports and license scanning reports are raw artifacts
+ # because they used to be fetched by the frontend, but this is not the case anymore.
sast: :raw,
secret_detection: :raw,
dependency_scanning: :raw,
@@ -77,16 +75,24 @@ module Ci
dast: :raw,
license_management: :raw,
license_scanning: :raw,
+
+ # All these file formats use `raw` as we need to store them uncompressed
+ # for Frontend to fetch the files and do analysis
+ # When they will be only used by backend, they can be `gzipped`.
+ accessibility: :raw,
+ codequality: :raw,
performance: :raw,
browser_performance: :raw,
load_performance: :raw,
terraform: :raw,
requirements: :raw,
- coverage_fuzzing: :raw
+ coverage_fuzzing: :raw,
+ api_fuzzing: :raw
}.freeze
DOWNLOADABLE_TYPES = %w[
accessibility
+ api_fuzzing
archive
cobertura
codequality
@@ -194,7 +200,8 @@ module Ci
requirements: 22, ## EE-specific
coverage_fuzzing: 23, ## EE-specific
browser_performance: 24, ## EE-specific
- load_performance: 25 ## EE-specific
+ load_performance: 25, ## EE-specific
+ api_fuzzing: 26 ## EE-specific
}
# `file_location` indicates where actual files are stored.
@@ -283,6 +290,15 @@ module Ci
max_size&.megabytes.to_i
end
+ def to_deleted_object_attrs
+ {
+ file_store: file_store,
+ store_dir: file.store_dir.to_s,
+ file: file_identifier,
+ pick_up_at: expire_at || Time.current
+ }
+ end
+
private
def set_size
diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb
index 47eba685afe..684b6387ab1 100644
--- a/app/models/ci/pipeline.rb
+++ b/app/models/ci/pipeline.rb
@@ -27,6 +27,13 @@ module Ci
sha_attribute :source_sha
sha_attribute :target_sha
+ # Ci::CreatePipelineService returns Ci::Pipeline so this is the only place
+ # where we can pass additional information from the service. This accessor
+ # is used for storing the processed CI YAML contents for linting purposes.
+ # There is an open issue to address this:
+ # https://gitlab.com/gitlab-org/gitlab/-/issues/259010
+ attr_accessor :merged_yaml
+
belongs_to :project, inverse_of: :all_pipelines
belongs_to :user
belongs_to :auto_canceled_by, class_name: 'Ci::Pipeline'
@@ -42,6 +49,7 @@ module Ci
has_many :stages, -> { order(position: :asc) }, inverse_of: :pipeline
has_many :statuses, class_name: 'CommitStatus', foreign_key: :commit_id, inverse_of: :pipeline
has_many :latest_statuses_ordered_by_stage, -> { latest.order(:stage_idx, :stage) }, class_name: 'CommitStatus', foreign_key: :commit_id, inverse_of: :pipeline
+ has_many :latest_statuses, -> { latest }, class_name: 'CommitStatus', foreign_key: :commit_id, inverse_of: :pipeline
has_many :processables, class_name: 'Ci::Processable', foreign_key: :commit_id, inverse_of: :pipeline
has_many :bridges, class_name: 'Ci::Bridge', foreign_key: :commit_id, inverse_of: :pipeline
has_many :builds, foreign_key: :commit_id, inverse_of: :pipeline
@@ -577,11 +585,11 @@ module Ci
end
def retried
- @retried ||= (statuses.order(id: :desc) - statuses.latest)
+ @retried ||= (statuses.order(id: :desc) - latest_statuses)
end
def coverage
- coverage_array = statuses.latest.map(&:coverage).compact
+ coverage_array = latest_statuses.map(&:coverage).compact
if coverage_array.size >= 1
'%.2f' % (coverage_array.reduce(:+) / coverage_array.size)
end
@@ -821,16 +829,28 @@ module Ci
end
def same_family_pipeline_ids
- if ::Gitlab::Ci::Features.child_of_child_pipeline_enabled?(project)
- ::Gitlab::Ci::PipelineObjectHierarchy.new(
- base_and_ancestors(same_project: true), options: { same_project: true }
- ).base_and_descendants.select(:id)
- else
- # If pipeline is a child of another pipeline, include the parent
- # and the siblings, otherwise return only itself and children.
- parent = parent_pipeline || self
- [parent.id] + parent.child_pipelines.pluck(:id)
- end
+ ::Gitlab::Ci::PipelineObjectHierarchy.new(
+ base_and_ancestors(same_project: true), options: { same_project: true }
+ ).base_and_descendants.select(:id)
+ end
+
+ def build_with_artifacts_in_self_and_descendants(name)
+ builds_in_self_and_descendants
+ .ordered_by_pipeline # find job in hierarchical order
+ .with_downloadable_artifacts
+ .find_by_name(name)
+ end
+
+ def builds_in_self_and_descendants
+ Ci::Build.latest.where(pipeline: self_and_descendants)
+ end
+
+ # Without using `unscoped`, caller scope is also included into the query.
+ # Using `unscoped` here will be redundant after Rails 6.1
+ def self_and_descendants
+ ::Gitlab::Ci::PipelineObjectHierarchy
+ .new(self.class.unscoped.where(id: id), options: { same_project: true })
+ .base_and_descendants
end
def bridge_triggered?
@@ -875,7 +895,7 @@ module Ci
end
def builds_with_coverage
- builds.with_coverage
+ builds.latest.with_coverage
end
def has_reports?(reports_scope)
diff --git a/app/models/ci_platform_metric.rb b/app/models/ci_platform_metric.rb
index 5e6e3eddce9..ac4ab391bbf 100644
--- a/app/models/ci_platform_metric.rb
+++ b/app/models/ci_platform_metric.rb
@@ -14,7 +14,7 @@ class CiPlatformMetric < ApplicationRecord
numericality: { only_integer: true, greater_than: 0 }
CI_VARIABLE_KEY = 'AUTO_DEVOPS_PLATFORM_TARGET'
- ALLOWED_TARGETS = %w[ECS FARGATE].freeze
+ ALLOWED_TARGETS = %w[ECS FARGATE EC2].freeze
def self.insert_auto_devops_platform_targets!
recorded_at = Time.zone.now
diff --git a/app/models/clusters/agent.rb b/app/models/clusters/agent.rb
index 874415e7bf4..5feb3b0a1e6 100644
--- a/app/models/clusters/agent.rb
+++ b/app/models/clusters/agent.rb
@@ -8,6 +8,7 @@ module Clusters
has_many :agent_tokens, class_name: 'Clusters::AgentToken'
+ scope :ordered_by_name, -> { order(:name) }
scope :with_name, -> (name) { where(name: name) }
validates :name,
diff --git a/app/models/clusters/applications/fluentd.rb b/app/models/clusters/applications/fluentd.rb
index 3fd6e870edc..c608d37be77 100644
--- a/app/models/clusters/applications/fluentd.rb
+++ b/app/models/clusters/applications/fluentd.rb
@@ -22,7 +22,11 @@ module Clusters
validate :has_at_least_one_log_enabled?
def chart
- 'stable/fluentd'
+ 'fluentd/fluentd'
+ end
+
+ def repository
+ 'https://gitlab-org.gitlab.io/cluster-integration/helm-stable-archive'
end
def install_command
diff --git a/app/models/clusters/applications/ingress.rb b/app/models/clusters/applications/ingress.rb
index 1d08f38a2f1..d5412714858 100644
--- a/app/models/clusters/applications/ingress.rb
+++ b/app/models/clusters/applications/ingress.rb
@@ -46,7 +46,11 @@ module Clusters
end
def chart
- 'stable/nginx-ingress'
+ "#{name}/nginx-ingress"
+ end
+
+ def repository
+ 'https://gitlab-org.gitlab.io/cluster-integration/helm-stable-archive'
end
def values
@@ -60,6 +64,7 @@ module Clusters
def install_command
Gitlab::Kubernetes::Helm::InstallCommand.new(
name: name,
+ repository: repository,
version: VERSION,
rbac: cluster.platform_kubernetes_rbac?,
chart: chart,
diff --git a/app/models/clusters/applications/prometheus.rb b/app/models/clusters/applications/prometheus.rb
index dd6a4144608..7679296699f 100644
--- a/app/models/clusters/applications/prometheus.rb
+++ b/app/models/clusters/applications/prometheus.rb
@@ -51,7 +51,11 @@ module Clusters
end
def chart
- 'stable/prometheus'
+ "#{name}/prometheus"
+ end
+
+ def repository
+ 'https://gitlab-org.gitlab.io/cluster-integration/helm-stable-archive'
end
def service_name
@@ -65,6 +69,7 @@ module Clusters
def install_command
Gitlab::Kubernetes::Helm::InstallCommand.new(
name: name,
+ repository: repository,
version: VERSION,
rbac: cluster.platform_kubernetes_rbac?,
chart: chart,
@@ -76,6 +81,7 @@ module Clusters
def patch_command(values)
::Gitlab::Kubernetes::Helm::PatchCommand.new(
name: name,
+ repository: repository,
version: version,
rbac: cluster.platform_kubernetes_rbac?,
chart: chart,
diff --git a/app/models/clusters/applications/runner.rb b/app/models/clusters/applications/runner.rb
index f0b3c11ba1d..d07ea7b71dc 100644
--- a/app/models/clusters/applications/runner.rb
+++ b/app/models/clusters/applications/runner.rb
@@ -3,7 +3,7 @@
module Clusters
module Applications
class Runner < ApplicationRecord
- VERSION = '0.20.2'
+ VERSION = '0.21.1'
self.table_name = 'clusters_applications_runners'
diff --git a/app/models/clusters/platforms/kubernetes.rb b/app/models/clusters/platforms/kubernetes.rb
index 7af78960e35..b85a902d58b 100644
--- a/app/models/clusters/platforms/kubernetes.rb
+++ b/app/models/clusters/platforms/kubernetes.rb
@@ -11,6 +11,7 @@ module Clusters
RESERVED_NAMESPACES = %w(gitlab-managed-apps).freeze
self.table_name = 'cluster_platforms_kubernetes'
+ self.reactive_cache_work_type = :external_dependency
belongs_to :cluster, inverse_of: :platform_kubernetes, class_name: 'Clusters::Cluster'
@@ -101,7 +102,7 @@ module Clusters
def terminals(environment, data)
pods = filter_by_project_environment(data[:pods], environment.project.full_path_slug, environment.slug)
terminals = pods.flat_map { |pod| terminals_for_pod(api_url, environment.deployment_namespace, pod) }.compact
- terminals.each { |terminal| add_terminal_auth(terminal, terminal_auth) }
+ terminals.each { |terminal| add_terminal_auth(terminal, **terminal_auth) }
end
def kubeclient
diff --git a/app/models/commit.rb b/app/models/commit.rb
index 5e0fceb23a4..83400c9e533 100644
--- a/app/models/commit.rb
+++ b/app/models/commit.rb
@@ -29,12 +29,6 @@ class Commit
delegate :repository, to: :container
delegate :project, to: :repository, allow_nil: true
- DIFF_SAFE_LINES = Gitlab::Git::DiffCollection::DEFAULT_LIMITS[:max_lines]
-
- # Commits above this size will not be rendered in HTML
- DIFF_HARD_LIMIT_FILES = 1000
- DIFF_HARD_LIMIT_LINES = 50000
-
MIN_SHA_LENGTH = Gitlab::Git::Commit::MIN_SHA_LENGTH
COMMIT_SHA_PATTERN = /\h{#{MIN_SHA_LENGTH},40}/.freeze
EXACT_COMMIT_SHA_PATTERN = /\A#{COMMIT_SHA_PATTERN}\z/.freeze
@@ -80,10 +74,30 @@ class Commit
sha[0..MIN_SHA_LENGTH]
end
- def max_diff_options
+ def diff_safe_lines(project: nil)
+ Gitlab::Git::DiffCollection.default_limits(project: project)[:max_lines]
+ end
+
+ def diff_hard_limit_files(project: nil)
+ if Feature.enabled?(:increased_diff_limits, project)
+ 2000
+ else
+ 1000
+ end
+ end
+
+ def diff_hard_limit_lines(project: nil)
+ if Feature.enabled?(:increased_diff_limits, project)
+ 75000
+ else
+ 50000
+ end
+ end
+
+ def max_diff_options(project: nil)
{
- max_files: DIFF_HARD_LIMIT_FILES,
- max_lines: DIFF_HARD_LIMIT_LINES
+ max_files: diff_hard_limit_files(project: project),
+ max_lines: diff_hard_limit_lines(project: project)
}
end
diff --git a/app/models/commit_status.rb b/app/models/commit_status.rb
index 2f0596c93cc..4498e08d754 100644
--- a/app/models/commit_status.rb
+++ b/app/models/commit_status.rb
@@ -48,6 +48,7 @@ class CommitStatus < ApplicationRecord
scope :ordered_by_stage, -> { order(stage_idx: :asc) }
scope :latest_ordered, -> { latest.ordered.includes(project: :namespace) }
scope :retried_ordered, -> { retried.ordered.includes(project: :namespace) }
+ scope :ordered_by_pipeline, -> { order(pipeline_id: :asc) }
scope :before_stage, -> (index) { where('stage_idx < ?', index) }
scope :for_stage, -> (index) { where(stage_idx: index) }
scope :after_stage, -> (index) { where('stage_idx > ?', index) }
@@ -204,8 +205,13 @@ class CommitStatus < ApplicationRecord
# 'rspec:linux: 1/10' => 'rspec:linux'
common_name = name.to_s.gsub(%r{\d+[\s:\/\\]+\d+\s*}, '')
- # 'rspec:linux: [aws, max memory]' => 'rspec:linux'
- common_name.gsub!(%r{: \[.*, .*\]\s*\z}, '')
+ if ::Gitlab::Ci::Features.one_dimensional_matrix_enabled?
+ # 'rspec:linux: [aws, max memory]' => 'rspec:linux', 'rspec:linux: [aws]' => 'rspec:linux'
+ common_name.gsub!(%r{: \[.*\]\s*\z}, '')
+ else
+ # 'rspec:linux: [aws, max memory]' => 'rspec:linux', 'rspec:linux: [aws]' => 'rspec:linux: [aws]'
+ common_name.gsub!(%r{: \[.*, .*\]\s*\z}, '')
+ end
common_name.strip!
common_name
diff --git a/app/models/concerns/approvable_base.rb b/app/models/concerns/approvable_base.rb
index d07c4ec43ac..c2d94b50f8d 100644
--- a/app/models/concerns/approvable_base.rb
+++ b/app/models/concerns/approvable_base.rb
@@ -2,10 +2,34 @@
module ApprovableBase
extend ActiveSupport::Concern
+ include FromUnion
included do
has_many :approvals, dependent: :delete_all # rubocop:disable Cop/ActiveRecordDependent
has_many :approved_by_users, through: :approvals, source: :user
+
+ scope :without_approvals, -> { left_outer_joins(:approvals).where(approvals: { id: nil }) }
+ scope :with_approvals, -> { joins(:approvals) }
+ scope :approved_by_users_with_ids, -> (*user_ids) do
+ with_approvals
+ .merge(Approval.with_user)
+ .where(users: { id: user_ids })
+ .group(:id)
+ .having("COUNT(users.id) = ?", user_ids.size)
+ end
+ scope :approved_by_users_with_usernames, -> (*usernames) do
+ with_approvals
+ .merge(Approval.with_user)
+ .where(users: { username: usernames })
+ .group(:id)
+ .having("COUNT(users.id) = ?", usernames.size)
+ end
+ end
+
+ class_methods do
+ def select_from_union(relations)
+ where(id: from_union(relations))
+ end
end
def approved_by?(user)
diff --git a/app/models/concerns/avatarable.rb b/app/models/concerns/avatarable.rb
index 0dd55ab67b5..d342b526677 100644
--- a/app/models/concerns/avatarable.rb
+++ b/app/models/concerns/avatarable.rb
@@ -3,16 +3,11 @@
module Avatarable
extend ActiveSupport::Concern
- ALLOWED_IMAGE_SCALER_WIDTHS = [
- 400,
- 200,
- 64,
- 48,
- 40,
- 26,
- 20,
- 16
- ].freeze
+ USER_AVATAR_SIZES = [16, 20, 23, 24, 26, 32, 36, 38, 40, 48, 60, 64, 90, 96, 120, 160].freeze
+ PROJECT_AVATAR_SIZES = [15, 40, 48, 64, 88].freeze
+ GROUP_AVATAR_SIZES = [15, 37, 38, 39, 40, 64, 96].freeze
+
+ ALLOWED_IMAGE_SCALER_WIDTHS = (USER_AVATAR_SIZES | PROJECT_AVATAR_SIZES | GROUP_AVATAR_SIZES).freeze
included do
prepend ShadowMethods
diff --git a/app/models/concerns/checksummable.rb b/app/models/concerns/checksummable.rb
index d6d17bfc604..056abafd0ce 100644
--- a/app/models/concerns/checksummable.rb
+++ b/app/models/concerns/checksummable.rb
@@ -3,11 +3,11 @@
module Checksummable
extend ActiveSupport::Concern
- def crc32(data)
- Zlib.crc32(data)
- end
-
class_methods do
+ def crc32(data)
+ Zlib.crc32(data)
+ end
+
def hexdigest(path)
::Digest::SHA256.file(path).hexdigest
end
diff --git a/app/models/concerns/counter_attribute.rb b/app/models/concerns/counter_attribute.rb
index a5c7393e8f7..b468415c4c7 100644
--- a/app/models/concerns/counter_attribute.rb
+++ b/app/models/concerns/counter_attribute.rb
@@ -20,6 +20,14 @@
# To increment the counter we can use the method:
# delayed_increment_counter(:commit_count, 3)
#
+# It is possible to register callbacks to be executed after increments have
+# been flushed to the database. Callbacks are not executed if there are no increments
+# to flush.
+#
+# counter_attribute_after_flush do |statistic|
+# Namespaces::ScheduleAggregationWorker.perform_async(statistic.namespace_id)
+# end
+#
module CounterAttribute
extend ActiveSupport::Concern
extend AfterCommitQueue
@@ -48,6 +56,15 @@ module CounterAttribute
def counter_attributes
@counter_attributes ||= Set.new
end
+
+ def after_flush_callbacks
+ @after_flush_callbacks ||= []
+ end
+
+ # perform registered callbacks after increments have been flushed to the database
+ def counter_attribute_after_flush(&callback)
+ after_flush_callbacks << callback
+ end
end
# This method must only be called by FlushCounterIncrementsWorker
@@ -75,6 +92,8 @@ module CounterAttribute
unsafe_update_counters(id, attribute => increment_value)
redis_state { |redis| redis.del(flushed_key) }
end
+
+ execute_after_flush_callbacks
end
end
@@ -108,13 +127,13 @@ module CounterAttribute
counter_key(attribute) + ':lock'
end
- private
-
def counter_attribute_enabled?(attribute)
Feature.enabled?(:efficient_counter_attribute, project) &&
self.class.counter_attributes.include?(attribute)
end
+ private
+
def steal_increments(increment_key, flushed_key)
redis_state do |redis|
redis.eval(LUA_STEAL_INCREMENT_SCRIPT, keys: [increment_key, flushed_key])
@@ -129,6 +148,12 @@ module CounterAttribute
self.class.update_counters(id, increments)
end
+ def execute_after_flush_callbacks
+ self.class.after_flush_callbacks.each do |callback|
+ callback.call(self)
+ end
+ end
+
def redis_state(&block)
Gitlab::Redis::SharedState.with(&block)
end
diff --git a/app/models/concerns/has_repository.rb b/app/models/concerns/has_repository.rb
index d909b67d7ba..978a54bdee7 100644
--- a/app/models/concerns/has_repository.rb
+++ b/app/models/concerns/has_repository.rb
@@ -71,6 +71,10 @@ module HasRepository
raise NotImplementedError
end
+ def lfs_enabled?
+ false
+ end
+
def empty_repo?
repository.empty?
end
@@ -80,7 +84,11 @@ module HasRepository
end
def default_branch_from_preferences
- empty_repo? ? Gitlab::CurrentSettings.default_branch_name : nil
+ return unless empty_repo?
+
+ group_branch_default_name = group&.default_branch_name if respond_to?(:group)
+
+ group_branch_default_name || Gitlab::CurrentSettings.default_branch_name
end
def reload_default_branch
diff --git a/app/models/concerns/has_user_type.rb b/app/models/concerns/has_user_type.rb
index 8a238dc736c..468387115e5 100644
--- a/app/models/concerns/has_user_type.rb
+++ b/app/models/concerns/has_user_type.rb
@@ -11,16 +11,18 @@ module HasUserType
service_user: 4,
ghost: 5,
project_bot: 6,
- migration_bot: 7
+ migration_bot: 7,
+ security_bot: 8
}.with_indifferent_access.freeze
- BOT_USER_TYPES = %w[alert_bot project_bot support_bot visual_review_bot migration_bot].freeze
+ BOT_USER_TYPES = %w[alert_bot project_bot support_bot visual_review_bot migration_bot security_bot].freeze
NON_INTERNAL_USER_TYPES = %w[human project_bot service_user].freeze
INTERNAL_USER_TYPES = (USER_TYPES.keys - NON_INTERNAL_USER_TYPES).freeze
included do
scope :humans, -> { where(user_type: :human) }
scope :bots, -> { where(user_type: BOT_USER_TYPES) }
+ scope :without_bots, -> { humans.or(where.not(user_type: BOT_USER_TYPES)) }
scope :bots_without_project_bot, -> { where(user_type: BOT_USER_TYPES - ['project_bot']) }
scope :non_internal, -> { humans.or(where(user_type: NON_INTERNAL_USER_TYPES)) }
scope :without_ghosts, -> { humans.or(where.not(user_type: :ghost)) }
diff --git a/app/models/concerns/integration.rb b/app/models/concerns/integration.rb
index 34ff5bb1195..9d446841a9f 100644
--- a/app/models/concerns/integration.rb
+++ b/app/models/concerns/integration.rb
@@ -16,7 +16,7 @@ module Integration
Project.where(id: custom_integration_project_ids)
end
- def ids_without_integration(integration, limit)
+ def without_integration(integration)
services = Service
.select('1')
.where('services.project_id = projects.id')
@@ -26,8 +26,6 @@ module Integration
.where('NOT EXISTS (?)', services)
.where(pending_delete: false)
.where(archived: false)
- .limit(limit)
- .pluck(:id)
end
end
end
diff --git a/app/models/concerns/issuable.rb b/app/models/concerns/issuable.rb
index 888e1b384a2..7624a1a4e80 100644
--- a/app/models/concerns/issuable.rb
+++ b/app/models/concerns/issuable.rb
@@ -182,7 +182,7 @@ module Issuable
end
def supports_time_tracking?
- is_a?(TimeTrackable) && !incident?
+ is_a?(TimeTrackable)
end
def supports_severity?
@@ -203,15 +203,6 @@ module Issuable
issuable_severity&.severity || IssuableSeverity::DEFAULT
end
- def update_severity(severity)
- return unless incident?
-
- severity = severity.to_s.downcase
- severity = IssuableSeverity::DEFAULT unless IssuableSeverity.severities.key?(severity)
-
- (issuable_severity || build_issuable_severity(issue_id: id)).update(severity: severity)
- end
-
private
def description_max_length_for_new_records_is_valid
diff --git a/app/models/concerns/issue_available_features.rb b/app/models/concerns/issue_available_features.rb
new file mode 100644
index 00000000000..6efb8103b7b
--- /dev/null
+++ b/app/models/concerns/issue_available_features.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+# Verifies features availability based on issue type.
+# This can be used, for example, for hiding UI elements or blocking specific
+# quick actions for particular issue types;
+module IssueAvailableFeatures
+ extend ActiveSupport::Concern
+
+ # EE only features are listed on EE::IssueAvailableFeatures
+ def available_features_for_issue_types
+ {}.with_indifferent_access
+ end
+
+ def issue_type_supports?(feature)
+ unless available_features_for_issue_types.has_key?(feature)
+ raise ArgumentError, 'invalid feature'
+ end
+
+ available_features_for_issue_types[feature].include?(issue_type)
+ end
+end
+
+IssueAvailableFeatures.prepend_if_ee('EE::IssueAvailableFeatures')
diff --git a/app/models/concerns/mentionable.rb b/app/models/concerns/mentionable.rb
index 7b4485376d4..b10e8547e86 100644
--- a/app/models/concerns/mentionable.rb
+++ b/app/models/concerns/mentionable.rb
@@ -81,13 +81,6 @@ module Mentionable
end
def store_mentions!
- # if store_mentioned_users_to_db feature flag is not enabled then consider storing operation as succeeded
- # because we wrap this method in transaction with with_transaction_returning_status, and we need the status to be
- # successful if mentionable.save is successful.
- #
- # This line will get removed when we remove the feature flag.
- return true unless store_mentioned_users_to_db_enabled?
-
refs = all_references(self.author)
references = {}
@@ -253,15 +246,6 @@ module Mentionable
def model_user_mention
user_mentions.where(note_id: nil).first_or_initialize
end
-
- # We need this method to be checking that store_mentioned_users_to_db feature flag is enabled at the group level
- # and not the project level as epics are defined at group level and we want to have epics store user mentions as well
- # for the test period.
- # During the test period the flag should be enabled at the group level.
- def store_mentioned_users_to_db_enabled?
- return Feature.enabled?(:store_mentioned_users_to_db, self.project&.group, default_enabled: true) if self.respond_to?(:project)
- return Feature.enabled?(:store_mentioned_users_to_db, self.group, default_enabled: true) if self.respond_to?(:group)
- end
end
Mentionable.prepend_if_ee('EE::Mentionable')
diff --git a/app/models/concerns/presentable.rb b/app/models/concerns/presentable.rb
index 06c300c2e41..1f05abff2f4 100644
--- a/app/models/concerns/presentable.rb
+++ b/app/models/concerns/presentable.rb
@@ -5,13 +5,13 @@ module Presentable
class_methods do
def present(attributes)
- all.map { |klass_object| klass_object.present(attributes) }
+ all.map { |klass_object| klass_object.present(**attributes) }
end
end
def present(**attributes)
Gitlab::View::Presenter::Factory
- .new(self, attributes)
+ .new(self, **attributes)
.fabricate!
end
end
diff --git a/app/models/concerns/reactive_caching.rb b/app/models/concerns/reactive_caching.rb
index 5f30fc0c36c..3470bdab5fb 100644
--- a/app/models/concerns/reactive_caching.rb
+++ b/app/models/concerns/reactive_caching.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
# The usage of the ReactiveCaching module is documented here:
-# https://docs.gitlab.com/ee/development/utilities.html#reactivecaching
+# https://docs.gitlab.com/ee/development/reactive_caching.md
module ReactiveCaching
extend ActiveSupport::Concern
@@ -9,7 +9,7 @@ module ReactiveCaching
ExceededReactiveCacheLimit = Class.new(StandardError)
WORK_TYPE = {
- default: ReactiveCachingWorker,
+ no_dependency: ReactiveCachingWorker,
external_dependency: ExternalServiceReactiveCachingWorker
}.freeze
@@ -30,7 +30,6 @@ module ReactiveCaching
self.reactive_cache_refresh_interval = 1.minute
self.reactive_cache_lifetime = 10.minutes
self.reactive_cache_hard_limit = nil # this value should be set in megabytes. E.g: 1.megabyte
- self.reactive_cache_work_type = :default
self.reactive_cache_worker_finder = ->(id, *_args) do
find_by(primary_key => id)
end
diff --git a/app/models/concerns/reactive_service.rb b/app/models/concerns/reactive_service.rb
index af69da24994..c444f238944 100644
--- a/app/models/concerns/reactive_service.rb
+++ b/app/models/concerns/reactive_service.rb
@@ -8,5 +8,6 @@ module ReactiveService
# Default cache key: class name + project_id
self.reactive_cache_key = ->(service) { [service.class.model_name.singular, service.project_id] }
+ self.reactive_cache_work_type = :external_dependency
end
end
diff --git a/app/models/concerns/referable.rb b/app/models/concerns/referable.rb
index 40edd3b3ead..9a17131c91c 100644
--- a/app/models/concerns/referable.rb
+++ b/app/models/concerns/referable.rb
@@ -85,7 +85,7 @@ module Referable
\/#{route.is_a?(Regexp) ? route : Regexp.escape(route)}
\/#{pattern}
(?<path>
- (\/[a-z0-9_=-]+)*
+ (\/[a-z0-9_=-]+)*\/*
)?
(?<query>
\?[a-z0-9_=-]+
diff --git a/app/models/concerns/relative_positioning.rb b/app/models/concerns/relative_positioning.rb
index 3cbc174536c..7f559f0a7ed 100644
--- a/app/models/concerns/relative_positioning.rb
+++ b/app/models/concerns/relative_positioning.rb
@@ -102,33 +102,16 @@ module RelativePositioning
delta = at_end ? gap : -gap
indexed = (at_end ? objects : objects.reverse).each_with_index
- # Some classes are polymorphic, and not all siblings are in the same table.
- by_model = indexed.group_by { |pair| pair.first.class }
lower_bound, upper_bound = at_end ? [position, MAX_POSITION] : [MIN_POSITION, position]
- by_model.each do |model, pairs|
- model.transaction do
- pairs.each_slice(100) do |batch|
- # These are known to be integers, one from the DB, and the other
- # calculated by us, and thus safe to interpolate
- values = batch.map do |obj, i|
- desired_pos = position + delta * (i + 1)
- pos = desired_pos.clamp(lower_bound, upper_bound)
- obj.relative_position = pos
- "(#{obj.id}, #{pos})"
- end.join(', ')
-
- model.connection.exec_query(<<~SQL, "UPDATE #{model.table_name} positions")
- WITH cte(cte_id, new_pos) AS (
- SELECT *
- FROM (VALUES #{values}) as t (id, pos)
- )
- UPDATE #{model.table_name}
- SET relative_position = cte.new_pos
- FROM cte
- WHERE cte_id = id
- SQL
+ representative.model_class.transaction do
+ indexed.each_slice(100) do |batch|
+ mapping = batch.to_h.transform_values! do |i|
+ desired_pos = position + delta * (i + 1)
+ { relative_position: desired_pos.clamp(lower_bound, upper_bound) }
end
+
+ ::Gitlab::Database::BulkUpdate.execute([:relative_position], mapping, &:model_class)
end
end
@@ -200,4 +183,16 @@ module RelativePositioning
# Override if you want to be notified of failures to move
def could_not_move(exception)
end
+
+ # Override if the implementing class is not a simple application record, for
+ # example if the record is loaded from a union.
+ def reset_relative_position
+ reset.relative_position
+ end
+
+ # Override if the model class needs a more complicated computation (e.g. the
+ # object is a member of a union).
+ def model_class
+ self.class
+ end
end
diff --git a/app/models/concerns/shardable.rb b/app/models/concerns/shardable.rb
index 57cd77b44b4..c0883c08289 100644
--- a/app/models/concerns/shardable.rb
+++ b/app/models/concerns/shardable.rb
@@ -5,6 +5,10 @@ module Shardable
included do
belongs_to :shard
+
+ scope :for_repository_storage, -> (repository_storage) { joins(:shard).where(shards: { name: repository_storage }) }
+ scope :excluding_repository_storage, -> (repository_storage) { joins(:shard).where.not(shards: { name: repository_storage }) }
+
validates :shard, presence: true
end
diff --git a/app/models/concerns/timebox.rb b/app/models/concerns/timebox.rb
index 3e2cf9031d0..23fd73f2904 100644
--- a/app/models/concerns/timebox.rb
+++ b/app/models/concerns/timebox.rb
@@ -73,6 +73,32 @@ module Timebox
end
end
+ # A timebox is within the timeframe (start_date, end_date) if it overlaps
+ # with that timeframe:
+ #
+ # [ timeframe ]
+ # ----| ................ # Not overlapping
+ # |--| ................ # Not overlapping
+ # ------|............... # Overlapping
+ # -----------------------| # Overlapping
+ # ---------|............ # Overlapping
+ # |-----|............ # Overlapping
+ # |--------------| # Overlapping
+ # |--------------------| # Overlapping
+ # ...|-----|...... # Overlapping
+ # .........|-----| # Overlapping
+ # .........|--------- # Overlapping
+ # |-------------------- # Overlapping
+ # .........|--------| # Overlapping
+ # ...............|--| # Overlapping
+ # ............... |-| # Not Overlapping
+ # ............... |-- # Not Overlapping
+ #
+ # where: . = in timeframe
+ # ---| no start
+ # |--- no end
+ # |--| defined start and end
+ #
scope :within_timeframe, -> (start_date, end_date) do
where('start_date is not NULL or due_date is not NULL')
.where('start_date is NULL or start_date <= ?', end_date)
diff --git a/app/models/concerns/update_project_statistics.rb b/app/models/concerns/update_project_statistics.rb
index a7028e18451..586f1dbb65c 100644
--- a/app/models/concerns/update_project_statistics.rb
+++ b/app/models/concerns/update_project_statistics.rb
@@ -80,10 +80,7 @@ module UpdateProjectStatistics
run_after_commit do
ProjectStatistics.increment_statistic(
- project_id, self.class.project_statistics_name, delta)
-
- Namespaces::ScheduleAggregationWorker.perform_async(
- project.namespace_id)
+ project, self.class.project_statistics_name, delta)
end
end
end
diff --git a/app/models/container_expiration_policy.rb b/app/models/container_expiration_policy.rb
index b1dd720d908..641d244b665 100644
--- a/app/models/container_expiration_policy.rb
+++ b/app/models/container_expiration_policy.rb
@@ -3,6 +3,7 @@
class ContainerExpirationPolicy < ApplicationRecord
include Schedulable
include UsageStatistics
+ include EachBatch
belongs_to :project, inverse_of: :container_expiration_policy
@@ -19,6 +20,16 @@ class ContainerExpirationPolicy < ApplicationRecord
scope :active, -> { where(enabled: true) }
scope :preloaded, -> { preload(project: [:route]) }
+ def self.executable
+ runnable_schedules.where(
+ 'EXISTS (?)',
+ ContainerRepository.select(1)
+ .where(
+ 'container_repositories.project_id = container_expiration_policies.project_id'
+ )
+ )
+ end
+
def self.keep_n_options
{
1 => _('%{tags} tag per image name') % { tags: 1 },
diff --git a/app/models/container_repository.rb b/app/models/container_repository.rb
index b0f7edac2f3..d97b8776085 100644
--- a/app/models/container_repository.rb
+++ b/app/models/container_repository.rb
@@ -107,6 +107,14 @@ class ContainerRepository < ApplicationRecord
client.delete_repository_tag_by_name(self.path, name)
end
+ def reset_expiration_policy_started_at!
+ update!(expiration_policy_started_at: nil)
+ end
+
+ def start_expiration_policy!
+ update!(expiration_policy_started_at: Time.zone.now)
+ end
+
def self.build_from_path(path)
self.new(project: path.repository_project,
name: path.repository_name)
diff --git a/app/models/data_list.rb b/app/models/data_list.rb
index 2cee3447886..adad8e3013e 100644
--- a/app/models/data_list.rb
+++ b/app/models/data_list.rb
@@ -1,8 +1,8 @@
# frozen_string_literal: true
class DataList
- def initialize(batch_ids, data_fields_hash, klass)
- @batch_ids = batch_ids
+ def initialize(batch, data_fields_hash, klass)
+ @batch = batch
@data_fields_hash = data_fields_hash
@klass = klass
end
@@ -13,15 +13,15 @@ class DataList
private
- attr_reader :batch_ids, :data_fields_hash, :klass
+ attr_reader :batch, :data_fields_hash, :klass
def columns
data_fields_hash.keys << 'service_id'
end
def values
- batch_ids.map do |row|
- data_fields_hash.values << row['id']
+ batch.map do |record|
+ data_fields_hash.values << record['id']
end
end
end
diff --git a/app/models/deploy_token.rb b/app/models/deploy_token.rb
index 395260b5201..9355d73fae9 100644
--- a/app/models/deploy_token.rb
+++ b/app/models/deploy_token.rb
@@ -78,6 +78,20 @@ class DeployToken < ApplicationRecord
end
end
+ def group
+ strong_memoize(:group) do
+ groups.first
+ end
+ end
+
+ def accessible_projects
+ if project_type?
+ projects
+ elsif group_type?
+ group.all_projects
+ end
+ end
+
def holder
strong_memoize(:holder) do
if project_type?
diff --git a/app/models/deployment.rb b/app/models/deployment.rb
index 3978620c74d..2d0d98136ec 100644
--- a/app/models/deployment.rb
+++ b/app/models/deployment.rb
@@ -46,6 +46,8 @@ class Deployment < ApplicationRecord
scope :older_than, -> (deployment) { where('id < ?', deployment.id) }
scope :with_deployable, -> { includes(:deployable).where('deployable_id IS NOT NULL') }
+ FINISHED_STATUSES = %i[success failed canceled].freeze
+
state_machine :status, initial: :created do
event :run do
transition created: :running
@@ -63,27 +65,41 @@ class Deployment < ApplicationRecord
transition any - [:canceled] => :canceled
end
- before_transition any => [:success, :failed, :canceled] do |deployment|
+ before_transition any => FINISHED_STATUSES do |deployment|
deployment.finished_at = Time.current
end
- after_transition any => :success do |deployment|
+ after_transition any => :running do |deployment|
+ next unless deployment.project.ci_forward_deployment_enabled?
+
deployment.run_after_commit do
- Deployments::SuccessWorker.perform_async(id)
+ Deployments::DropOlderDeploymentsWorker.perform_async(id)
end
end
- after_transition any => [:success, :failed, :canceled] do |deployment|
+ after_transition any => :running do |deployment|
deployment.run_after_commit do
- Deployments::FinishedWorker.perform_async(id)
+ next unless Feature.enabled?(:ci_send_deployment_hook_when_start, deployment.project)
+
+ Deployments::ExecuteHooksWorker.perform_async(id)
end
end
- after_transition any => :running do |deployment|
- next unless deployment.project.forward_deployment_enabled?
+ after_transition any => :success do |deployment|
+ deployment.run_after_commit do
+ Deployments::UpdateEnvironmentWorker.perform_async(id)
+ end
+ end
+
+ after_transition any => FINISHED_STATUSES do |deployment|
+ deployment.run_after_commit do
+ Deployments::LinkMergeRequestWorker.perform_async(id)
+ end
+ end
+ after_transition any => FINISHED_STATUSES do |deployment|
deployment.run_after_commit do
- Deployments::ForwardDeploymentWorker.perform_async(id)
+ Deployments::ExecuteHooksWorker.perform_async(id)
end
end
end
@@ -273,7 +289,7 @@ class Deployment < ApplicationRecord
SQL
end
- # Changes the status of a deployment and triggers the correspinding state
+ # Changes the status of a deployment and triggers the corresponding state
# machine events.
def update_status(status)
case status
diff --git a/app/models/deployment_merge_request.rb b/app/models/deployment_merge_request.rb
index ff4d9f66202..b67f96906f5 100644
--- a/app/models/deployment_merge_request.rb
+++ b/app/models/deployment_merge_request.rb
@@ -3,4 +3,25 @@
class DeploymentMergeRequest < ApplicationRecord
belongs_to :deployment, optional: false
belongs_to :merge_request, optional: false
+
+ def self.join_deployments_for_merge_requests
+ joins(deployment: :environment)
+ .where('deployment_merge_requests.merge_request_id = merge_requests.id')
+ end
+
+ def self.by_deployment_id(id)
+ where('deployments.id = ?', id)
+ end
+
+ def self.deployed_to(name)
+ where('environments.name = ?', name)
+ end
+
+ def self.deployed_after(time)
+ where('deployments.finished_at > ?', time)
+ end
+
+ def self.deployed_before(time)
+ where('deployments.finished_at < ?', time)
+ end
end
diff --git a/app/models/design_management/design.rb b/app/models/design_management/design.rb
index 57bb250829d..62e4bd6cebc 100644
--- a/app/models/design_management/design.rb
+++ b/app/models/design_management/design.rb
@@ -167,6 +167,10 @@ module DesignManagement
end
end
+ def self.build_full_path(issue, design)
+ File.join(DesignManagement.designs_directory, "issue-#{issue.iid}", design.filename)
+ end
+
def to_ability_name
'design'
end
@@ -180,7 +184,7 @@ module DesignManagement
end
def full_path
- @full_path ||= File.join(DesignManagement.designs_directory, "issue-#{issue.iid}", filename)
+ @full_path ||= self.class.build_full_path(issue, self)
end
def diff_refs
@@ -224,6 +228,10 @@ module DesignManagement
!interloper.exists?
end
+ def notes_with_associations
+ notes.includes(:author)
+ end
+
private
def head_version
diff --git a/app/models/design_management/design_at_version.rb b/app/models/design_management/design_at_version.rb
index b4cafb93c2c..211211144f4 100644
--- a/app/models/design_management/design_at_version.rb
+++ b/app/models/design_management/design_at_version.rb
@@ -21,10 +21,6 @@ module DesignManagement
@design, @version = design, version
end
- def self.instantiate(attrs)
- new(attrs).tap { |obj| obj.validate! }
- end
-
# The ID, needed by GraphQL types and as part of the Lazy-fetch
# protocol, includes information about both the design and the version.
#
diff --git a/app/models/design_management/design_collection.rb b/app/models/design_management/design_collection.rb
index c48b36588c9..6deba14a6ba 100644
--- a/app/models/design_management/design_collection.rb
+++ b/app/models/design_management/design_collection.rb
@@ -5,6 +5,7 @@ module DesignManagement
attr_reader :issue
delegate :designs, :project, to: :issue
+ delegate :empty?, to: :designs
state_machine :copy_state, initial: :ready, namespace: :copy do
after_transition any => any, do: :update_stored_copy_state!
diff --git a/app/models/diff_viewer/rich.rb b/app/models/diff_viewer/rich.rb
index 5caefa2031c..0d94d8f773b 100644
--- a/app/models/diff_viewer/rich.rb
+++ b/app/models/diff_viewer/rich.rb
@@ -6,7 +6,7 @@ module DiffViewer
included do
self.type = :rich
- self.switcher_icon = 'file-text-o'
+ self.switcher_icon = 'doc-text'
self.switcher_title = _('rendered diff')
end
end
diff --git a/app/models/environment.rb b/app/models/environment.rb
index cfdcb0499e6..66613869915 100644
--- a/app/models/environment.rb
+++ b/app/models/environment.rb
@@ -4,12 +4,15 @@ class Environment < ApplicationRecord
include Gitlab::Utils::StrongMemoize
include ReactiveCaching
include FastDestroyAll::Helpers
+ include Presentable
self.reactive_cache_refresh_interval = 1.minute
self.reactive_cache_lifetime = 55.seconds
self.reactive_cache_hard_limit = 10.megabytes
self.reactive_cache_work_type = :external_dependency
+ PRODUCTION_ENVIRONMENT_IDENTIFIERS = %w[prod production].freeze
+
belongs_to :project, required: true
use_fast_destroy :all_deployments
@@ -67,6 +70,7 @@ class Environment < ApplicationRecord
scope :order_by_last_deployed_at_desc, -> do
order(Gitlab::Database.nulls_last_order("(#{max_deployment_id_sql})", 'DESC'))
end
+ scope :order_by_name, -> { order('environments.name ASC') }
scope :in_review_folder, -> { where(environment_type: "review") }
scope :for_name, -> (name) { where(name: name) }
@@ -86,6 +90,7 @@ class Environment < ApplicationRecord
scope :with_rank, -> do
select('environments.*, rank() OVER (PARTITION BY project_id ORDER BY id DESC)')
end
+ scope :for_id, -> (id) { where(id: id) }
state_machine :state, initial: :available do
event :start do
@@ -118,6 +123,10 @@ class Environment < ApplicationRecord
pluck(:name)
end
+ def self.pluck_unique_names
+ pluck('DISTINCT(environments.name)')
+ end
+
def self.find_or_create_by_name(name)
find_or_create_by(name: name)
end
@@ -211,7 +220,7 @@ class Environment < ApplicationRecord
end
def update_merge_request_metrics?
- folder_name == "production"
+ PRODUCTION_ENVIRONMENT_IDENTIFIERS.include?(folder_name.downcase)
end
def ref_path
diff --git a/app/models/environment_status.rb b/app/models/environment_status.rb
index 46e41c22139..55ea4e2fe18 100644
--- a/app/models/environment_status.rb
+++ b/app/models/environment_status.rb
@@ -72,14 +72,6 @@ class EnvironmentStatus
.merge_request_diff_files.where(deleted_file: false)
end
- def changed_paths
- changes.map { |change| change[:path] }
- end
-
- def changed_urls
- changes.map { |change| change[:external_url] }
- end
-
def has_route_map?
project.route_map_for(sha).present?
end
diff --git a/app/models/event.rb b/app/models/event.rb
index 92609144576..671def16151 100644
--- a/app/models/event.rb
+++ b/app/models/event.rb
@@ -242,6 +242,8 @@ class Event < ApplicationRecord
target if note?
end
+ # rubocop: disable Metrics/CyclomaticComplexity
+ # rubocop: disable Metrics/PerceivedComplexity
def action_name
if push_action?
push_action_name
@@ -267,10 +269,14 @@ class Event < ApplicationRecord
'updated'
elsif created_project_action?
created_project_action_name
+ elsif approved_action?
+ 'approved'
else
"opened"
end
end
+ # rubocop: enable Metrics/CyclomaticComplexity
+ # rubocop: enable Metrics/PerceivedComplexity
def target_iid
target.respond_to?(:iid) ? target.iid : target_id
@@ -323,14 +329,6 @@ class Event < ApplicationRecord
end
end
- def note_target_type
- if target.noteable_type.present?
- target.noteable_type.titleize
- else
- "Wall"
- end.downcase
- end
-
def body?
if push_action?
push_with_commits?
diff --git a/app/models/global_label.rb b/app/models/global_label.rb
deleted file mode 100644
index 7c020dd3b3d..00000000000
--- a/app/models/global_label.rb
+++ /dev/null
@@ -1,32 +0,0 @@
-# frozen_string_literal: true
-
-class GlobalLabel
- include Presentable
-
- attr_accessor :title, :labels
- alias_attribute :name, :title
-
- delegate :color, :text_color, :description, :scoped_label?, to: :@first_label
-
- def for_display
- @first_label
- end
-
- def self.build_collection(labels)
- labels = labels.group_by(&:title)
-
- labels.map do |title, labels|
- new(title, labels)
- end
- end
-
- def initialize(title, labels)
- @title = title
- @labels = labels
- @first_label = labels.find { |lbl| lbl.description.present? } || labels.first
- end
-
- def present(attributes)
- super(attributes.merge(presenter_class: ::LabelPresenter))
- end
-end
diff --git a/app/models/group.rb b/app/models/group.rb
index c0f145997cc..74f7efd253d 100644
--- a/app/models/group.rb
+++ b/app/models/group.rb
@@ -15,11 +15,10 @@ class Group < Namespace
include WithUploads
include Gitlab::Utils::StrongMemoize
include GroupAPICompatibility
+ include EachBatch
ACCESS_REQUEST_APPROVERS_TO_BE_NOTIFIED_LIMIT = 10
- UpdateSharedRunnersError = Class.new(StandardError)
-
has_many :all_group_members, -> { where(requested_at: nil) }, dependent: :destroy, as: :source, class_name: 'GroupMember' # rubocop:disable Cop/ActiveRecordDependent
has_many :group_members, -> { where(requested_at: nil).where.not(members: { access_level: Gitlab::Access::MINIMAL_ACCESS }) }, dependent: :destroy, as: :source # rubocop:disable Cop/ActiveRecordDependent
alias_method :members, :group_members
@@ -77,6 +76,7 @@ class Group < Namespace
validate :visibility_level_allowed_by_projects
validate :visibility_level_allowed_by_sub_groups
validate :visibility_level_allowed_by_parent
+ validate :two_factor_authentication_allowed
validates :variables, variable_duplicates: true
validates :two_factor_grace_period, presence: true, numericality: { greater_than_or_equal_to: 0 }
@@ -140,6 +140,15 @@ class Group < Namespace
end
end
+ def without_integration(integration)
+ services = Service
+ .select('1')
+ .where('services.group_id = namespaces.id')
+ .where(type: integration.type)
+
+ where('NOT EXISTS (?)', services)
+ end
+
private
def public_to_user_arel(user)
@@ -348,6 +357,7 @@ class Group < Namespace
end
group_hierarchy_members = GroupMember.active_without_invites_and_requests
+ .non_minimal_access
.where(source_id: source_ids)
GroupMember.from_union([group_hierarchy_members,
@@ -528,57 +538,37 @@ class Group < Namespace
preloader.preload(self, shared_with_group_links: [shared_with_group: :route])
end
- def shared_runners_allowed?
- shared_runners_enabled? || allow_descendants_override_disabled_shared_runners?
- end
-
- def parent_allows_shared_runners?
- return true unless has_parent?
+ def update_shared_runners_setting!(state)
+ raise ArgumentError unless SHARED_RUNNERS_SETTINGS.include?(state)
- parent.shared_runners_allowed?
+ case state
+ when 'disabled_and_unoverridable' then disable_shared_runners! # also disallows override
+ when 'disabled_with_override' then disable_shared_runners_and_allow_override!
+ when 'enabled' then enable_shared_runners! # set both to true
+ end
end
- def parent_enabled_shared_runners?
- return true unless has_parent?
-
- parent.shared_runners_enabled?
+ def default_owner
+ owners.first || parent&.default_owner || owner
end
- def enable_shared_runners!
- raise UpdateSharedRunnersError, 'Shared Runners disabled for the parent group' unless parent_enabled_shared_runners?
-
- update_column(:shared_runners_enabled, true)
+ def default_branch_name
+ namespace_settings&.default_branch_name
end
- def disable_shared_runners!
- group_ids = self_and_descendants
- return if group_ids.empty?
-
- Group.by_id(group_ids).update_all(shared_runners_enabled: false)
-
- all_projects.update_all(shared_runners_enabled: false)
+ def access_level_roles
+ GroupMember.access_level_roles
end
- def allow_descendants_override_disabled_shared_runners!
- raise UpdateSharedRunnersError, 'Shared Runners enabled' if shared_runners_enabled?
- raise UpdateSharedRunnersError, 'Group level shared Runners not allowed' unless parent_allows_shared_runners?
-
- update_column(:allow_descendants_override_disabled_shared_runners, true)
+ def access_level_values
+ access_level_roles.values
end
- def disallow_descendants_override_disabled_shared_runners!
- raise UpdateSharedRunnersError, 'Shared Runners enabled' if shared_runners_enabled?
-
- group_ids = self_and_descendants
- return if group_ids.empty?
-
- Group.by_id(group_ids).update_all(allow_descendants_override_disabled_shared_runners: false)
-
- all_projects.update_all(shared_runners_enabled: false)
- end
+ def parent_allows_two_factor_authentication?
+ return true unless has_parent?
- def default_owner
- owners.first || parent&.default_owner || owner
+ ancestor_settings = ancestors.find_by(parent_id: nil).namespace_settings
+ ancestor_settings.allow_mfa_for_subgroups
end
private
@@ -611,6 +601,15 @@ class Group < Namespace
errors.add(:visibility_level, "#{visibility} is not allowed since there are sub-groups with higher visibility.")
end
+ def two_factor_authentication_allowed
+ return unless has_parent?
+ return unless require_two_factor_authentication
+
+ return if parent_allows_two_factor_authentication?
+
+ errors.add(:require_two_factor_authentication, _('is forbidden by a top-level group'))
+ end
+
def members_from_self_and_ancestor_group_shares
group_group_link_table = GroupGroupLink.arel_table
group_member_table = GroupMember.arel_table
@@ -658,6 +657,45 @@ class Group < Namespace
.new(Group.where(id: group_ids))
.base_and_descendants
end
+
+ def disable_shared_runners!
+ update!(
+ shared_runners_enabled: false,
+ allow_descendants_override_disabled_shared_runners: false)
+
+ group_ids = descendants
+ unless group_ids.empty?
+ Group.by_id(group_ids).update_all(
+ shared_runners_enabled: false,
+ allow_descendants_override_disabled_shared_runners: false)
+ end
+
+ all_projects.update_all(shared_runners_enabled: false)
+ end
+
+ def disable_shared_runners_and_allow_override!
+ # enabled -> disabled_with_override
+ if shared_runners_enabled?
+ update!(
+ shared_runners_enabled: false,
+ allow_descendants_override_disabled_shared_runners: true)
+
+ group_ids = descendants
+ unless group_ids.empty?
+ Group.by_id(group_ids).update_all(shared_runners_enabled: false)
+ end
+
+ all_projects.update_all(shared_runners_enabled: false)
+
+ # disabled_and_unoverridable -> disabled_with_override
+ else
+ update!(allow_descendants_override_disabled_shared_runners: true)
+ end
+ end
+
+ def enable_shared_runners!
+ update!(shared_runners_enabled: true)
+ end
end
Group.prepend_if_ee('EE::Group')
diff --git a/app/models/group_import_state.rb b/app/models/group_import_state.rb
index d22c1ac5550..89602e40357 100644
--- a/app/models/group_import_state.rb
+++ b/app/models/group_import_state.rb
@@ -4,8 +4,9 @@ class GroupImportState < ApplicationRecord
self.primary_key = :group_id
belongs_to :group, inverse_of: :import_state
+ belongs_to :user, optional: false
- validates :group, :status, presence: true
+ validates :group, :status, :user, presence: true
validates :jid, presence: true, if: -> { started? || finished? }
state_machine :status, initial: :created do
diff --git a/app/models/incident_management/project_incident_management_setting.rb b/app/models/incident_management/project_incident_management_setting.rb
index c79acdb685f..4887265be88 100644
--- a/app/models/incident_management/project_incident_management_setting.rb
+++ b/app/models/incident_management/project_incident_management_setting.rb
@@ -51,3 +51,5 @@ module IncidentManagement
end
end
end
+
+IncidentManagement::ProjectIncidentManagementSetting.prepend_if_ee('EE::IncidentManagement::ProjectIncidentManagementSetting')
diff --git a/app/models/issuable_severity.rb b/app/models/issuable_severity.rb
index d68b3dc48ee..35d03a544bd 100644
--- a/app/models/issuable_severity.rb
+++ b/app/models/issuable_severity.rb
@@ -2,6 +2,13 @@
class IssuableSeverity < ApplicationRecord
DEFAULT = 'unknown'
+ SEVERITY_LABELS = {
+ unknown: 'Unknown',
+ low: 'Low - S4',
+ medium: 'Medium - S3',
+ high: 'High - S2',
+ critical: 'Critical - S1'
+ }.freeze
belongs_to :issue
diff --git a/app/models/issue.rb b/app/models/issue.rb
index 5a5de371301..5291b7890b6 100644
--- a/app/models/issue.rb
+++ b/app/models/issue.rb
@@ -19,6 +19,8 @@ class Issue < ApplicationRecord
include WhereComposite
include StateEventable
include IdInOrdered
+ include Presentable
+ include IssueAvailableFeatures
DueDateStruct = Struct.new(:title, :name).freeze
NoDueDate = DueDateStruct.new('No Due Date', '0').freeze
@@ -54,6 +56,7 @@ class Issue < ApplicationRecord
dependent: :delete_all # rubocop:disable Cop/ActiveRecordDependent
has_many :issue_assignees
+ has_many :issue_email_participants
has_many :assignees, class_name: "User", through: :issue_assignees
has_many :zoom_meetings
has_many :user_mentions, class_name: "IssueUserMention", dependent: :delete_all # rubocop:disable Cop/ActiveRecordDependent
@@ -87,6 +90,7 @@ class Issue < ApplicationRecord
alias_method :issuing_parent, :project
scope :in_projects, ->(project_ids) { where(project_id: project_ids) }
+ scope :not_in_projects, ->(project_ids) { where.not(project_id: project_ids) }
scope :with_due_date, -> { where.not(due_date: nil) }
scope :without_due_date, -> { where(due_date: nil) }
@@ -101,6 +105,8 @@ class Issue < ApplicationRecord
scope :order_relative_position_asc, -> { reorder(::Gitlab::Database.nulls_last_order('relative_position', 'ASC')) }
scope :order_closed_date_desc, -> { reorder(closed_at: :desc) }
scope :order_created_at_desc, -> { reorder(created_at: :desc) }
+ scope :order_severity_asc, -> { includes(:issuable_severity).order('issuable_severities.severity ASC NULLS FIRST') }
+ scope :order_severity_desc, -> { includes(:issuable_severity).order('issuable_severities.severity DESC NULLS LAST') }
scope :preload_associated_models, -> { preload(:assignees, :labels, project: :namespace) }
scope :with_web_entity_associations, -> { preload(:author, :project) }
@@ -122,6 +128,7 @@ class Issue < ApplicationRecord
scope :counts_by_state, -> { reorder(nil).group(:state_id).count }
scope :service_desk, -> { where(author: ::User.support_bot) }
+ scope :inc_relations_for_view, -> { includes(author: :status) }
# An issue can be uniquely identified by project_id and iid
# Takes one or more sets of composite IDs, expressed as hash-like records of
@@ -145,6 +152,7 @@ class Issue < ApplicationRecord
after_commit :expire_etag_cache, unless: :importing?
after_save :ensure_metrics, unless: :importing?
+ after_create_commit :record_create_action, unless: :importing?
attr_spammable :title, spam_title: true
attr_spammable :description, spam_description: true
@@ -232,6 +240,8 @@ class Issue < ApplicationRecord
when 'due_date', 'due_date_asc' then order_due_date_asc.with_order_id_desc
when 'due_date_desc' then order_due_date_desc.with_order_id_desc
when 'relative_position', 'relative_position_asc' then order_relative_position_asc.with_order_id_desc
+ when 'severity_asc' then order_severity_asc.with_order_id_desc
+ when 'severity_desc' then order_severity_desc.with_order_id_desc
else
super
end
@@ -413,6 +423,10 @@ class Issue < ApplicationRecord
IssueLink.inverse_link_type(type)
end
+ def relocation_target
+ moved_to || duplicated_to
+ end
+
private
def ensure_metrics
@@ -420,6 +434,10 @@ class Issue < ApplicationRecord
metrics.record!
end
+ def record_create_action
+ Gitlab::UsageDataCounters::IssueActivityUniqueCounter.track_issue_created_action(author: author)
+ end
+
# Returns `true` if the given User can read the current Issue.
#
# This method duplicates the same check of issue_policy.rb
diff --git a/app/models/issue_assignee.rb b/app/models/issue_assignee.rb
index e57acbae546..7f3d552b3d9 100644
--- a/app/models/issue_assignee.rb
+++ b/app/models/issue_assignee.rb
@@ -8,6 +8,7 @@ class IssueAssignee < ApplicationRecord
scope :in_projects, ->(project_ids) { joins(:issue).where("issues.project_id in (?)", project_ids) }
scope :on_issues, ->(issue_ids) { where(issue_id: issue_ids) }
+ scope :for_assignee, ->(user) { where(assignee: user) }
end
IssueAssignee.prepend_if_ee('EE::IssueAssignee')
diff --git a/app/models/issue_email_participant.rb b/app/models/issue_email_participant.rb
new file mode 100644
index 00000000000..8eb9b6a8152
--- /dev/null
+++ b/app/models/issue_email_participant.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+class IssueEmailParticipant < ApplicationRecord
+ belongs_to :issue
+
+ validates :email, presence: true, uniqueness: { scope: [:issue_id] }
+ validates :issue, presence: true
+ validate :validate_email_format
+
+ def validate_email_format
+ self.errors.add(:email, I18n.t(:invalid, scope: 'valid_email.validations.email')) unless ValidateEmail.valid?(self.email)
+ end
+end
diff --git a/app/models/iteration.rb b/app/models/iteration.rb
index d223c80fca0..bd245de411c 100644
--- a/app/models/iteration.rb
+++ b/app/models/iteration.rb
@@ -94,13 +94,25 @@ class Iteration < ApplicationRecord
private
+ def parent_group
+ group || project.group
+ end
+
def start_or_due_dates_changed?
start_date_changed? || due_date_changed?
end
- # ensure dates do not overlap with other Iterations in the same group/project
+ # ensure dates do not overlap with other Iterations in the same group/project tree
def dates_do_not_overlap
- return unless resource_parent.iterations.where.not(id: self.id).within_timeframe(start_date, due_date).exists?
+ iterations = if parent_group.present? && resource_parent.is_a?(Project)
+ Iteration.where(group: parent_group.self_and_ancestors).or(project.iterations)
+ elsif parent_group.present?
+ Iteration.where(group: parent_group.self_and_ancestors)
+ else
+ project.iterations
+ end
+
+ return unless iterations.where.not(id: self.id).within_timeframe(start_date, due_date).exists?
errors.add(:base, s_("Iteration|Dates cannot overlap with other existing Iterations"))
end
diff --git a/app/models/member.rb b/app/models/member.rb
index 7ea9caa45d3..498e03b2c1a 100644
--- a/app/models/member.rb
+++ b/app/models/member.rb
@@ -80,7 +80,10 @@ class Member < ApplicationRecord
scope :request, -> { where.not(requested_at: nil) }
scope :non_request, -> { where(requested_at: nil) }
- scope :not_accepted_invitations_by_user, -> (user) { invite.where(invite_accepted_at: nil, created_by: user) }
+ scope :not_accepted_invitations, -> { invite.where(invite_accepted_at: nil) }
+ scope :not_accepted_invitations_by_user, -> (user) { not_accepted_invitations.where(created_by: user) }
+ scope :not_expired, -> (today = Date.current) { where(arel_table[:expires_at].gt(today).or(arel_table[:expires_at].eq(nil))) }
+ scope :last_ten_days_excluding_today, -> (today = Date.current) { where(created_at: (today - 10).beginning_of_day..(today - 1).end_of_day) }
scope :has_access, -> { active.where('access_level > 0') }
@@ -372,6 +375,14 @@ class Member < ApplicationRecord
send_invite
end
+ def send_invitation_reminder(reminder_index)
+ return unless invite?
+
+ generate_invite_token! unless @raw_invite_token
+
+ run_after_commit_or_now { notification_service.invite_member_reminder(self, @raw_invite_token, reminder_index) }
+ end
+
def create_notification_setting
user.notification_settings.find_or_create_for(source)
end
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index 3fdc501644d..24541ba3218 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -31,6 +31,7 @@ class MergeRequest < ApplicationRecord
self.reactive_cache_key = ->(model) { [model.project.id, model.iid] }
self.reactive_cache_refresh_interval = 10.minutes
self.reactive_cache_lifetime = 10.minutes
+ self.reactive_cache_work_type = :no_dependency
SORTING_PREFERENCE_FIELD = :merge_requests_sort
@@ -121,6 +122,8 @@ class MergeRequest < ApplicationRecord
# when creating new merge request
attr_accessor :can_be_created, :compare_commits, :diff_options, :compare
+ participant :reviewers
+
# Keep states definition to be evaluated before the state_machine block to avoid spec failures.
# If this gets evaluated after, the `merged` and `locked` states which are overrided can be nil.
def self.available_state_names
@@ -255,11 +258,7 @@ class MergeRequest < ApplicationRecord
scope :join_project, -> { joins(:target_project) }
scope :join_metrics, -> do
query = joins(:metrics)
-
- if Feature.enabled?(:improved_mr_merged_at_queries, default_enabled: true)
- query = query.where(MergeRequest.arel_table[:target_project_id].eq(MergeRequest::Metrics.arel_table[:target_project_id]))
- end
-
+ query = query.where(MergeRequest.arel_table[:target_project_id].eq(MergeRequest::Metrics.arel_table[:target_project_id]))
query
end
scope :references_project, -> { references(:target_project) }
@@ -271,6 +270,8 @@ class MergeRequest < ApplicationRecord
metrics: [:latest_closed_by, :merged_by])
}
+ scope :with_csv_entity_associations, -> { preload(:assignees, :approved_by_users, :author, :milestone, metrics: [:merged_by]) }
+
scope :by_target_branch_wildcard, ->(wildcard_branch_name) do
where("target_branch LIKE ?", ApplicationRecord.sanitize_sql_like(wildcard_branch_name).tr('*', '%'))
end
@@ -629,7 +630,7 @@ class MergeRequest < ApplicationRecord
def diff_size
# Calling `merge_request_diff.diffs.real_size` will also perform
# highlighting, which we don't need here.
- merge_request_diff&.real_size || diff_stats&.real_size || diffs.real_size
+ merge_request_diff&.real_size || diff_stats&.real_size(project: project) || diffs.real_size
end
def modified_paths(past_merge_request_diff: nil, fallback_on_overflow: false)
@@ -928,7 +929,7 @@ class MergeRequest < ApplicationRecord
# rubocop: enable CodeReuse/ServiceClass
def diffable_merge_ref?
- can_be_merged? && merge_ref_head.present?
+ merge_ref_head.present? && (Feature.enabled?(:display_merge_conflicts_in_diff, project) || can_be_merged?)
end
# Returns boolean indicating the merge_status should be rechecked in order to
@@ -1301,6 +1302,14 @@ class MergeRequest < ApplicationRecord
unlock_mr
end
+ def update_and_mark_in_progress_merge_commit_sha(commit_id)
+ self.update(in_progress_merge_commit_sha: commit_id)
+ # Since another process checks for matching merge request, we need
+ # to make it possible to detect whether the query should go to the
+ # primary.
+ target_project.mark_primary_write_location
+ end
+
def diverged_commits_count
cache = Rails.cache.read(:"merge_request_#{id}_diverged_commits")
@@ -1375,8 +1384,6 @@ class MergeRequest < ApplicationRecord
end
def has_coverage_reports?
- return false unless Feature.enabled?(:coverage_report_view, project, default_enabled: true)
-
actual_head_pipeline&.has_coverage_reports?
end
@@ -1511,6 +1518,7 @@ class MergeRequest < ApplicationRecord
metrics&.merged_at ||
merge_event&.created_at ||
+ resource_state_events.find_by(state: :merged)&.created_at ||
notes.system.reorder(nil).find_by(note: 'merged')&.created_at
end
end
@@ -1591,6 +1599,12 @@ class MergeRequest < ApplicationRecord
.find_by(sha: diff_base_sha, ref: target_branch)
end
+ def merge_base_pipeline
+ @merge_base_pipeline ||= project.ci_pipelines
+ .order(id: :desc)
+ .find_by(sha: actual_head_pipeline.target_sha, ref: target_branch)
+ end
+
def discussions_rendered_on_frontend?
true
end
@@ -1680,6 +1694,10 @@ class MergeRequest < ApplicationRecord
Feature.enabled?(:merge_request_reviewers, project)
end
+ def allows_multiple_reviewers?
+ false
+ end
+
private
def with_rebase_lock
diff --git a/app/models/merge_request_context_commit.rb b/app/models/merge_request_context_commit.rb
index a2982a5dd73..59cc82cfaf5 100644
--- a/app/models/merge_request_context_commit.rb
+++ b/app/models/merge_request_context_commit.rb
@@ -22,8 +22,8 @@ class MergeRequestContextCommit < ApplicationRecord
end
# create MergeRequestContextCommit by given commit sha and it's diff file record
- def self.bulk_insert(*args)
- Gitlab::Database.bulk_insert('merge_request_context_commits', *args) # rubocop:disable Gitlab/BulkInsert
+ def self.bulk_insert(rows, **args)
+ Gitlab::Database.bulk_insert('merge_request_context_commits', rows, **args) # rubocop:disable Gitlab/BulkInsert
end
def to_commit
diff --git a/app/models/merge_request_diff.rb b/app/models/merge_request_diff.rb
index 880e3cc1ba5..24809141570 100644
--- a/app/models/merge_request_diff.rb
+++ b/app/models/merge_request_diff.rb
@@ -106,6 +106,17 @@ class MergeRequestDiff < ApplicationRecord
joins(merge_request: :metrics).where(condition)
end
+ scope :latest_diff_for_merge_requests, -> (merge_requests) do
+ inner_select = MergeRequestDiff
+ .default_scoped
+ .distinct
+ .select("FIRST_VALUE(id) OVER (PARTITION BY merge_request_id ORDER BY created_at DESC) as id")
+ .where(merge_request: merge_requests)
+
+ joins("INNER JOIN (#{inner_select.to_sql}) latest_diffs ON latest_diffs.id = merge_request_diffs.id")
+ .includes(:merge_request_diff_commits)
+ end
+
class << self
def ids_for_external_storage_migration(limit:)
return [] unless Gitlab.config.external_diffs.enabled
@@ -280,7 +291,13 @@ class MergeRequestDiff < ApplicationRecord
end
def commit_shas(limit: nil)
- merge_request_diff_commits.limit(limit).pluck(:sha)
+ if association(:merge_request_diff_commits).loaded?
+ sorted_diff_commits = merge_request_diff_commits.sort_by { |diff_commit| [diff_commit.id, diff_commit.relative_order] }
+ sorted_diff_commits = sorted_diff_commits.take(limit) if limit
+ sorted_diff_commits.map(&:sha)
+ else
+ merge_request_diff_commits.limit(limit).pluck(:sha)
+ end
end
def includes_any_commits?(shas)
@@ -509,6 +526,8 @@ class MergeRequestDiff < ApplicationRecord
end
def encode_in_base64?(diff_text)
+ return false if diff_text.nil?
+
(diff_text.encoding == Encoding::BINARY && !diff_text.ascii_only?) ||
diff_text.include?("\0")
end
@@ -536,7 +555,7 @@ class MergeRequestDiff < ApplicationRecord
rows.each do |row|
data = row.delete(:diff)
row[:external_diff_offset] = file.pos
- row[:external_diff_size] = data.bytesize
+ row[:external_diff_size] = data&.bytesize || 0
file.write(data)
end
@@ -651,7 +670,7 @@ class MergeRequestDiff < ApplicationRecord
if compare.commits.empty?
new_attributes[:state] = :empty
else
- diff_collection = compare.diffs(Commit.max_diff_options)
+ diff_collection = compare.diffs(Commit.max_diff_options(project: merge_request.project))
new_attributes[:real_size] = diff_collection.real_size
if diff_collection.any?
diff --git a/app/models/milestone.rb b/app/models/milestone.rb
index 55326b9a282..0a315ba8db2 100644
--- a/app/models/milestone.rb
+++ b/app/models/milestone.rb
@@ -46,6 +46,10 @@ class Milestone < ApplicationRecord
state :active
end
+ def self.min_chars_for_partial_matching
+ 2
+ end
+
def self.reference_prefix
'%'
end
diff --git a/app/models/milestone_release.rb b/app/models/milestone_release.rb
index 0a6165c8254..2f2bf91e436 100644
--- a/app/models/milestone_release.rb
+++ b/app/models/milestone_release.rb
@@ -11,6 +11,10 @@ class MilestoneRelease < ApplicationRecord
def same_project_between_milestone_and_release
return if milestone&.project_id == release&.project_id
+ return if milestone&.group_id
+
errors.add(:base, _('Release does not have the same project as the milestone'))
end
end
+
+MilestoneRelease.prepend_if_ee('EE::MilestoneRelease')
diff --git a/app/models/namespace.rb b/app/models/namespace.rb
index 527fa9d52d0..fd31042c2f6 100644
--- a/app/models/namespace.rb
+++ b/app/models/namespace.rb
@@ -18,6 +18,8 @@ class Namespace < ApplicationRecord
# Android repo (15) + some extra backup.
NUMBER_OF_ANCESTORS_ALLOWED = 20
+ SHARED_RUNNERS_SETTINGS = %w[disabled_and_unoverridable disabled_with_override enabled].freeze
+
cache_markdown_field :description, pipeline: :description
has_many :projects, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
@@ -59,6 +61,8 @@ class Namespace < ApplicationRecord
validates :max_artifacts_size, numericality: { only_integer: true, greater_than: 0, allow_nil: true }
validate :nesting_level_allowed
+ validate :changing_shared_runners_enabled_is_allowed
+ validate :changing_allow_descendants_override_disabled_shared_runners_is_allowed
validates_associated :runners
@@ -79,6 +83,7 @@ class Namespace < ApplicationRecord
scope :for_user, -> { where('type IS NULL') }
scope :sort_by_type, -> { order(Gitlab::Database.nulls_first_order(:type)) }
+ scope :include_route, -> { includes(:route) }
scope :with_statistics, -> do
joins('LEFT JOIN project_statistics ps ON ps.namespace_id = namespaces.id')
@@ -278,7 +283,11 @@ class Namespace < ApplicationRecord
# Includes projects from this namespace and projects from all subgroups
# that belongs to this namespace
def all_projects
- Project.inside_path(full_path)
+ if Feature.enabled?(:recursive_approach_for_all_projects)
+ Project.where(namespace: self_and_descendants)
+ else
+ Project.inside_path(full_path)
+ end
end
# Includes pipelines from this namespace and pipelines from all subgroups
@@ -378,6 +387,52 @@ class Namespace < ApplicationRecord
actual_plan.name
end
+ def changing_shared_runners_enabled_is_allowed
+ return unless Feature.enabled?(:disable_shared_runners_on_group, default_enabled: true)
+ return unless new_record? || changes.has_key?(:shared_runners_enabled)
+
+ if shared_runners_enabled && has_parent? && parent.shared_runners_setting == 'disabled_and_unoverridable'
+ errors.add(:shared_runners_enabled, _('cannot be enabled because parent group has shared Runners disabled'))
+ end
+ end
+
+ def changing_allow_descendants_override_disabled_shared_runners_is_allowed
+ return unless Feature.enabled?(:disable_shared_runners_on_group, default_enabled: true)
+ return unless new_record? || changes.has_key?(:allow_descendants_override_disabled_shared_runners)
+
+ if shared_runners_enabled && !new_record?
+ errors.add(:allow_descendants_override_disabled_shared_runners, _('cannot be changed if shared runners are enabled'))
+ end
+
+ if allow_descendants_override_disabled_shared_runners && has_parent? && parent.shared_runners_setting == 'disabled_and_unoverridable'
+ errors.add(:allow_descendants_override_disabled_shared_runners, _('cannot be enabled because parent group does not allow it'))
+ end
+ end
+
+ def shared_runners_setting
+ if shared_runners_enabled
+ 'enabled'
+ else
+ if allow_descendants_override_disabled_shared_runners
+ 'disabled_with_override'
+ else
+ 'disabled_and_unoverridable'
+ end
+ end
+ end
+
+ def shared_runners_setting_higher_than?(other_setting)
+ if other_setting == 'enabled'
+ false
+ elsif other_setting == 'disabled_with_override'
+ shared_runners_setting == 'enabled'
+ elsif other_setting == 'disabled_and_unoverridable'
+ shared_runners_setting == 'enabled' || shared_runners_setting == 'disabled_with_override'
+ else
+ raise ArgumentError
+ end
+ end
+
private
def all_projects_with_pages
diff --git a/app/models/namespace_setting.rb b/app/models/namespace_setting.rb
index 53bfa3d979e..6f31208f28b 100644
--- a/app/models/namespace_setting.rb
+++ b/app/models/namespace_setting.rb
@@ -3,7 +3,26 @@
class NamespaceSetting < ApplicationRecord
belongs_to :namespace, inverse_of: :namespace_settings
+ validate :default_branch_name_content
+ validate :allow_mfa_for_group
+
+ NAMESPACE_SETTINGS_PARAMS = [:default_branch_name].freeze
+
self.primary_key = :namespace_id
+
+ def default_branch_name_content
+ return if default_branch_name.nil?
+
+ if default_branch_name.blank?
+ errors.add(:default_branch_name, "can not be an empty string")
+ end
+ end
+
+ def allow_mfa_for_group
+ if namespace&.subgroup? && allow_mfa_for_subgroups == false
+ errors.add(:allow_mfa_for_subgroups, _('is not allowed since the group is not top-level group.'))
+ end
+ end
end
NamespaceSetting.prepend_if_ee('EE::NamespaceSetting')
diff --git a/app/models/note.rb b/app/models/note.rb
index 812d77d5f86..954843505d4 100644
--- a/app/models/note.rb
+++ b/app/models/note.rb
@@ -322,8 +322,6 @@ class Note < ApplicationRecord
end
def contributor?
- return false unless ::Feature.enabled?(:show_contributor_on_note, project)
-
project&.team&.contributor?(self.author_id)
end
diff --git a/app/models/notification_reason.rb b/app/models/notification_reason.rb
index a7967239417..c227626af9e 100644
--- a/app/models/notification_reason.rb
+++ b/app/models/notification_reason.rb
@@ -5,6 +5,7 @@
class NotificationReason
OWN_ACTIVITY = 'own_activity'
ASSIGNED = 'assigned'
+ REVIEW_REQUESTED = 'review_requested'
MENTIONED = 'mentioned'
SUBSCRIBED = 'subscribed'
@@ -12,6 +13,7 @@ class NotificationReason
REASON_PRIORITY = [
OWN_ACTIVITY,
ASSIGNED,
+ REVIEW_REQUESTED,
MENTIONED,
SUBSCRIBED
].freeze
diff --git a/app/models/notification_recipient.rb b/app/models/notification_recipient.rb
index 6a6b2bb1b58..79a84231083 100644
--- a/app/models/notification_recipient.rb
+++ b/app/models/notification_recipient.rb
@@ -5,7 +5,7 @@ class NotificationRecipient
attr_reader :user, :type, :reason
- def initialize(user, type, **opts)
+ def initialize(user, type, opts = {})
unless NotificationSetting.levels.key?(type) || type == :subscription
raise ArgumentError, "invalid type: #{type.inspect}"
end
diff --git a/app/models/notification_setting.rb b/app/models/notification_setting.rb
index c003a20f0fc..6066046a722 100644
--- a/app/models/notification_setting.rb
+++ b/app/models/notification_setting.rb
@@ -43,6 +43,7 @@ class NotificationSetting < ApplicationRecord
:reopen_merge_request,
:close_merge_request,
:reassign_merge_request,
+ :change_reviewer_merge_request,
:merge_merge_request,
:failed_pipeline,
:fixed_pipeline,
diff --git a/app/models/operations/feature_flags/strategy.rb b/app/models/operations/feature_flags/strategy.rb
index ff68af9741e..c70e10c72d5 100644
--- a/app/models/operations/feature_flags/strategy.rb
+++ b/app/models/operations/feature_flags/strategy.rb
@@ -6,14 +6,17 @@ module Operations
STRATEGY_DEFAULT = 'default'
STRATEGY_GITLABUSERLIST = 'gitlabUserList'
STRATEGY_GRADUALROLLOUTUSERID = 'gradualRolloutUserId'
+ STRATEGY_FLEXIBLEROLLOUT = 'flexibleRollout'
STRATEGY_USERWITHID = 'userWithId'
STRATEGIES = {
STRATEGY_DEFAULT => [].freeze,
STRATEGY_GITLABUSERLIST => [].freeze,
STRATEGY_GRADUALROLLOUTUSERID => %w[groupId percentage].freeze,
+ STRATEGY_FLEXIBLEROLLOUT => %w[groupId rollout stickiness].freeze,
STRATEGY_USERWITHID => ['userIds'].freeze
}.freeze
USERID_MAX_LENGTH = 256
+ STICKINESS_SETTINGS = %w[DEFAULT USERID SESSIONID RANDOM].freeze
self.table_name = 'operations_strategies'
@@ -67,16 +70,25 @@ module Operations
case name
when STRATEGY_GRADUALROLLOUTUSERID
gradual_rollout_user_id_parameters_validation
+ when STRATEGY_FLEXIBLEROLLOUT
+ flexible_rollout_parameters_validation
when STRATEGY_USERWITHID
FeatureFlagUserXidsValidator.validate_user_xids(self, :parameters, parameters['userIds'], 'userIds')
end
end
+ def within_range?(value, min, max)
+ return false unless value.is_a?(String)
+ return false unless value.match?(/\A\d+\z/)
+
+ value.to_i.between?(min, max)
+ end
+
def gradual_rollout_user_id_parameters_validation
percentage = parameters['percentage']
group_id = parameters['groupId']
- unless percentage.is_a?(String) && percentage.match(/\A[1-9]?[0-9]\z|\A100\z/)
+ unless within_range?(percentage, 0, 100)
parameters_error('percentage must be a string between 0 and 100 inclusive')
end
@@ -85,6 +97,25 @@ module Operations
end
end
+ def flexible_rollout_parameters_validation
+ stickiness = parameters['stickiness']
+ group_id = parameters['groupId']
+ rollout = parameters['rollout']
+
+ unless STICKINESS_SETTINGS.include?(stickiness)
+ options = STICKINESS_SETTINGS.to_sentence(last_word_connector: ', or ')
+ parameters_error("stickiness parameter must be #{options}")
+ end
+
+ unless group_id.is_a?(String) && group_id.match(/\A[a-z]{1,32}\z/)
+ parameters_error('groupId parameter is invalid')
+ end
+
+ unless within_range?(rollout, 0, 100)
+ parameters_error('rollout must be a string between 0 and 100 inclusive')
+ end
+ end
+
def parameters_error(message)
errors.add(:parameters, message)
false
diff --git a/app/models/packages/event.rb b/app/models/packages/event.rb
new file mode 100644
index 00000000000..f1d0af64ccd
--- /dev/null
+++ b/app/models/packages/event.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+class Packages::Event < ApplicationRecord
+ belongs_to :package, optional: true
+
+ EVENT_SCOPES = ::Packages::Package.package_types.merge(container: 1000, tag: 1001).freeze
+
+ enum event_scope: EVENT_SCOPES
+
+ enum event_type: {
+ push_package: 0,
+ delete_package: 1,
+ pull_package: 2,
+ search_package: 3,
+ list_package: 4,
+ list_repositories: 5,
+ delete_repository: 6,
+ delete_tag: 7,
+ delete_tag_bulk: 8,
+ list_tags: 9,
+ cli_metadata: 10
+ }
+
+ enum originator_type: { user: 0, deploy_token: 1, guest: 2 }
+end
diff --git a/app/models/packages/package.rb b/app/models/packages/package.rb
index bda11160957..a57d640ddc0 100644
--- a/app/models/packages/package.rb
+++ b/app/models/packages/package.rb
@@ -26,7 +26,7 @@ class Packages::Package < ApplicationRecord
validates :project, presence: true
validates :name, presence: true
- validates :name, format: { with: Gitlab::Regex.package_name_regex }, unless: :conan?
+ validates :name, format: { with: Gitlab::Regex.package_name_regex }, unless: -> { conan? || generic? }
validates :name,
uniqueness: { scope: %i[project_id version package_type] }, unless: :conan?
@@ -35,20 +35,24 @@ class Packages::Package < ApplicationRecord
validate :valid_npm_package_name, if: :npm?
validate :valid_composer_global_name, if: :composer?
validate :package_already_taken, if: :npm?
- validates :version, format: { with: Gitlab::Regex.semver_regex }, if: -> { npm? || nuget? }
validates :name, format: { with: Gitlab::Regex.conan_recipe_component_regex }, if: :conan?
+ validates :name, format: { with: Gitlab::Regex.generic_package_name_regex }, if: :generic?
+ validates :version, format: { with: Gitlab::Regex.semver_regex }, if: :npm?
+ validates :version, format: { with: Gitlab::Regex.nuget_version_regex }, if: :nuget?
validates :version, format: { with: Gitlab::Regex.conan_recipe_component_regex }, if: :conan?
validates :version, format: { with: Gitlab::Regex.maven_version_regex }, if: -> { version? && maven? }
validates :version, format: { with: Gitlab::Regex.pypi_version_regex }, if: :pypi?
+ validates :version, format: { with: Gitlab::Regex.prefixed_semver_regex }, if: :golang?
validates :version,
presence: true,
format: { with: Gitlab::Regex.generic_package_version_regex },
if: :generic?
- enum package_type: { maven: 1, npm: 2, conan: 3, nuget: 4, pypi: 5, composer: 6, generic: 7 }
+ enum package_type: { maven: 1, npm: 2, conan: 3, nuget: 4, pypi: 5, composer: 6, generic: 7, golang: 8, debian: 9 }
scope :with_name, ->(name) { where(name: name) }
scope :with_name_like, ->(name) { where(arel_table[:name].matches(name)) }
+ scope :with_normalized_pypi_name, ->(name) { where("LOWER(regexp_replace(name, '[-_.]+', '-', 'g')) = ?", name.downcase) }
scope :search_by_name, ->(query) { fuzzy_search(query, [:name], use_minimum_char_limit: false) }
scope :with_version, ->(version) { where(version: version) }
scope :without_version_like, -> (version) { where.not(arel_table[:version].matches(version)) }
@@ -119,6 +123,10 @@ class Packages::Package < ApplicationRecord
.where(packages_package_files: { file_name: file_name, file_sha256: sha256 }).last!
end
+ def self.by_name_and_version!(name, version)
+ find_by!(name: name, version: version)
+ end
+
def self.pluck_names
pluck(:name)
end
diff --git a/app/models/pages_deployment.rb b/app/models/pages_deployment.rb
index 78e0f185a11..cd952c32046 100644
--- a/app/models/pages_deployment.rb
+++ b/app/models/pages_deployment.rb
@@ -2,10 +2,24 @@
# PagesDeployment stores a zip archive containing GitLab Pages web-site
class PagesDeployment < ApplicationRecord
+ include FileStoreMounter
+
belongs_to :project, optional: false
belongs_to :ci_build, class_name: 'Ci::Build', optional: true
validates :file, presence: true
validates :file_store, presence: true, inclusion: { in: ObjectStorage::SUPPORTED_STORES }
validates :size, presence: true, numericality: { greater_than: 0, only_integer: true }
+
+ before_validation :set_size, if: :file_changed?
+
+ default_value_for(:file_store) { ::Pages::DeploymentUploader.default_store }
+
+ mount_file_store_uploader ::Pages::DeploymentUploader
+
+ private
+
+ def set_size
+ self.size = file.size
+ end
end
diff --git a/app/models/postgresql/replication_slot.rb b/app/models/postgresql/replication_slot.rb
index a4370eda5ba..c96786423e5 100644
--- a/app/models/postgresql/replication_slot.rb
+++ b/app/models/postgresql/replication_slot.rb
@@ -22,8 +22,8 @@ module Postgresql
def self.lag_too_great?(max = 100.megabytes)
return false unless in_use?
- lag_function = "#{Gitlab::Database.pg_wal_lsn_diff}" \
- "(#{Gitlab::Database.pg_current_wal_insert_lsn}(), restart_lsn)::bigint"
+ lag_function = "pg_wal_lsn_diff" \
+ "(pg_current_wal_insert_lsn(), restart_lsn)::bigint"
# We force the use of a transaction here so the query always goes to the
# primary, even when using the EE DB load balancer.
diff --git a/app/models/preloaders/merge_request_diff_preloader.rb b/app/models/preloaders/merge_request_diff_preloader.rb
new file mode 100644
index 00000000000..ee9995c497d
--- /dev/null
+++ b/app/models/preloaders/merge_request_diff_preloader.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+module Preloaders
+ # This class preloads the `merge_request_diff` association for the given merge request models.
+ #
+ # Usage:
+ # merge_requests = MergeRequest.where(...)
+ # Preloaders::MergeRequestDiffPreloader.new(merge_requests).preload_all
+ # merge_requests.first.merge_request_diff # won't fire any query
+ class MergeRequestDiffPreloader
+ def initialize(merge_requests)
+ @merge_requests = merge_requests
+ end
+
+ def preload_all
+ merge_request_diffs = MergeRequestDiff.latest_diff_for_merge_requests(@merge_requests)
+ cache = merge_request_diffs.index_by { |diff| diff.merge_request_id }
+
+ @merge_requests.each do |merge_request|
+ merge_request_diff = cache[merge_request.id]
+
+ merge_request.association(:merge_request_diff).target = merge_request_diff
+ merge_request.association(:merge_request_diff).loaded!
+ end
+ end
+ end
+end
diff --git a/app/models/project.rb b/app/models/project.rb
index 4db0eaa0442..dbedd6d120c 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -33,7 +33,9 @@ class Project < ApplicationRecord
include FromUnion
include IgnorableColumns
include Integration
+ include EachBatch
extend Gitlab::Cache::RequestCache
+ extend Gitlab::Utils::Override
extend Gitlab::ConfigHelper
@@ -198,6 +200,7 @@ class Project < ApplicationRecord
has_one :import_export_upload, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
has_many :export_jobs, class_name: 'ProjectExportJob'
has_one :project_repository, inverse_of: :project
+ has_one :tracing_setting, class_name: 'ProjectTracingSetting'
has_one :incident_management_setting, inverse_of: :project, class_name: 'IncidentManagement::ProjectIncidentManagementSetting'
has_one :error_tracking_setting, inverse_of: :project, class_name: 'ErrorTracking::ProjectErrorTrackingSetting'
has_one :metrics_setting, inverse_of: :project, class_name: 'ProjectMetricsSetting'
@@ -268,6 +271,7 @@ class Project < ApplicationRecord
has_many :metrics_users_starred_dashboards, class_name: 'Metrics::UsersStarredDashboard', inverse_of: :project
has_many :alert_management_alerts, class_name: 'AlertManagement::Alert', inverse_of: :project
+ has_many :alert_management_http_integrations, class_name: 'AlertManagement::HttpIntegration', inverse_of: :project
# Container repositories need to remove data from the container registry,
# which is not managed by the DB. Hence we're still using dependent: :destroy
@@ -294,6 +298,7 @@ class Project < ApplicationRecord
# bulk that doesn't involve loading the rows into memory. As a result we're
# still using `dependent: :destroy` here.
has_many :builds, class_name: 'Ci::Build', inverse_of: :project, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
+ has_many :processables, class_name: 'Ci::Processable', inverse_of: :project
has_many :build_trace_section_names, class_name: 'Ci::BuildTraceSectionName'
has_many :build_trace_chunks, class_name: 'Ci::BuildTraceChunk', through: :builds, source: :trace_chunks
has_many :build_report_results, class_name: 'Ci::BuildReportResult', inverse_of: :project
@@ -336,6 +341,8 @@ class Project < ApplicationRecord
has_many :webide_pipelines, -> { webide_source }, class_name: 'Ci::Pipeline', inverse_of: :project
has_many :reviews, inverse_of: :project
+ has_many :terraform_states, class_name: 'Terraform::State', inverse_of: :project
+
# GitLab Pages
has_many :pages_domains
has_one :pages_metadatum, class_name: 'ProjectPagesMetadatum', inverse_of: :project
@@ -361,6 +368,7 @@ class Project < ApplicationRecord
allow_destroy: true,
reject_if: ->(attrs) { attrs[:id].blank? && attrs[:url].blank? }
+ accepts_nested_attributes_for :tracing_setting, update_only: true, allow_destroy: true
accepts_nested_attributes_for :incident_management_setting, update_only: true
accepts_nested_attributes_for :error_tracking_setting, update_only: true
accepts_nested_attributes_for :metrics_setting, update_only: true, allow_destroy: true
@@ -392,7 +400,7 @@ class Project < ApplicationRecord
delegate :external_dashboard_url, to: :metrics_setting, allow_nil: true, prefix: true
delegate :dashboard_timezone, to: :metrics_setting, allow_nil: true, prefix: true
delegate :default_git_depth, :default_git_depth=, to: :ci_cd_settings, prefix: :ci
- delegate :forward_deployment_enabled, :forward_deployment_enabled=, :forward_deployment_enabled?, to: :ci_cd_settings
+ delegate :forward_deployment_enabled, :forward_deployment_enabled=, :forward_deployment_enabled?, to: :ci_cd_settings, prefix: :ci
delegate :actual_limits, :actual_plan_name, to: :namespace, allow_nil: true
delegate :allow_merge_on_skipped_pipeline, :allow_merge_on_skipped_pipeline?,
:allow_merge_on_skipped_pipeline=, :has_confluence?,
@@ -432,6 +440,7 @@ class Project < ApplicationRecord
validate :visibility_level_allowed_by_group, if: :should_validate_visibility_level?
validate :visibility_level_allowed_as_fork, if: :should_validate_visibility_level?
validate :validate_pages_https_only, if: -> { changes.has_key?(:pages_https_only) }
+ validate :changing_shared_runners_enabled_is_allowed
validates :repository_storage,
presence: true,
inclusion: { in: ->(_object) { Gitlab.config.repositories.storages.keys } }
@@ -560,6 +569,7 @@ class Project < ApplicationRecord
}
scope :imported_from, -> (type) { where(import_type: type) }
+ scope :with_tracing_enabled, -> { joins(:tracing_setting) }
enum auto_cancel_pending_pipelines: { disabled: 0, enabled: 1 }
@@ -595,7 +605,7 @@ class Project < ApplicationRecord
return public_to_user unless user
if user.is_a?(DeployToken)
- user.projects
+ user.accessible_projects
else
where('EXISTS (?) OR projects.visibility_level IN (?)',
user.authorizations_for_projects(min_access_level: min_access_level),
@@ -667,8 +677,6 @@ class Project < ApplicationRecord
scope :joins_import_state, -> { joins("INNER JOIN project_mirror_data import_state ON import_state.project_id = projects.id") }
scope :for_group, -> (group) { where(group: group) }
scope :for_group_and_its_subgroups, ->(group) { where(namespace_id: group.self_and_descendants.select(:id)) }
- scope :for_repository_storage, -> (repository_storage) { where(repository_storage: repository_storage) }
- scope :excluding_repository_storage, -> (repository_storage) { where.not(repository_storage: repository_storage) }
class << self
# Searches for a list of projects based on the query given in `query`.
@@ -842,6 +850,7 @@ class Project < ApplicationRecord
end
end
+ override :lfs_enabled?
def lfs_enabled?
return namespace.lfs_enabled? if self[:lfs_enabled].nil?
@@ -942,7 +951,7 @@ class Project < ApplicationRecord
latest_pipeline = ci_pipelines.latest_successful_for_ref(ref)
return unless latest_pipeline
- latest_pipeline.builds.latest.with_downloadable_artifacts.find_by(name: job_name)
+ latest_pipeline.build_with_artifacts_in_self_and_descendants(job_name)
end
def latest_successful_build_for_sha(job_name, sha)
@@ -951,7 +960,7 @@ class Project < ApplicationRecord
latest_pipeline = ci_pipelines.latest_successful_for_sha(sha)
return unless latest_pipeline
- latest_pipeline.builds.latest.with_downloadable_artifacts.find_by(name: job_name)
+ latest_pipeline.build_with_artifacts_in_self_and_descendants(job_name)
end
def latest_successful_build_for_ref!(job_name, ref = default_branch)
@@ -991,9 +1000,6 @@ class Project < ApplicationRecord
job_id =
if forked?
RepositoryForkWorker.perform_async(id)
- elsif gitlab_project_import?
- # Do not retry on Import/Export until https://gitlab.com/gitlab-org/gitlab-foss/issues/26189 is solved.
- RepositoryImportWorker.set(retry: false).perform_async(self.id)
else
RepositoryImportWorker.perform_async(self.id)
end
@@ -1186,6 +1192,15 @@ class Project < ApplicationRecord
end
end
+ def changing_shared_runners_enabled_is_allowed
+ return unless Feature.enabled?(:disable_shared_runners_on_group, default_enabled: true)
+ return unless new_record? || changes.has_key?(:shared_runners_enabled)
+
+ if shared_runners_enabled && group && group.shared_runners_setting == 'disabled_and_unoverridable'
+ errors.add(:shared_runners_enabled, _('cannot be enabled because parent group does not allow it'))
+ end
+ end
+
def to_param
if persisted? && errors.include?(:path)
path_was
@@ -1325,7 +1340,8 @@ class Project < ApplicationRecord
end
def find_or_initialize_services
- available_services_names = Service.available_services_names - disabled_services
+ available_services_names =
+ Service.available_services_names + Service.project_specific_services_names - disabled_services
available_services_names.map do |service_name|
find_or_initialize_service(service_name)
@@ -2292,6 +2308,10 @@ class Project < ApplicationRecord
[]
end
+ def mark_primary_write_location
+ # Overriden in EE
+ end
+
def toggle_ci_cd_settings!(settings_attribute)
ci_cd_settings.toggle!(settings_attribute)
end
@@ -2495,12 +2515,25 @@ class Project < ApplicationRecord
ci_config_path.presence || Ci::Pipeline::DEFAULT_CONFIG_PATH
end
+ def ci_config_for(sha)
+ repository.gitlab_ci_yml_for(sha, ci_config_path_or_default)
+ end
+
def enabled_group_deploy_keys
return GroupDeployKey.none unless group
GroupDeployKey.for_groups(group.self_and_ancestors_ids)
end
+ def feature_flags_client_token
+ instance = operations_feature_flags_client || create_operations_feature_flags_client!
+ instance.token
+ end
+
+ def tracing_external_url
+ tracing_setting&.external_url
+ end
+
private
def find_service(services, name)
@@ -2509,10 +2542,10 @@ class Project < ApplicationRecord
def build_from_instance_or_template(name)
instance = find_service(services_instances, name)
- return Service.build_from_integration(id, instance) if instance
+ return Service.build_from_integration(instance, project_id: id) if instance
template = find_service(services_templates, name)
- return Service.build_from_integration(id, template) if template
+ return Service.build_from_integration(template, project_id: id) if template
end
def services_templates
diff --git a/app/models/project_pages_metadatum.rb b/app/models/project_pages_metadatum.rb
index 8a1db4a9acf..bd1919fe7ed 100644
--- a/app/models/project_pages_metadatum.rb
+++ b/app/models/project_pages_metadatum.rb
@@ -5,6 +5,7 @@ class ProjectPagesMetadatum < ApplicationRecord
belongs_to :project, inverse_of: :pages_metadatum
belongs_to :artifacts_archive, class_name: 'Ci::JobArtifact'
+ belongs_to :pages_deployment
scope :deployed, -> { where(deployed: true) }
end
diff --git a/app/models/project_repository_storage_move.rb b/app/models/project_repository_storage_move.rb
index 2b74d9ccd88..76f428fe925 100644
--- a/app/models/project_repository_storage_move.rb
+++ b/app/models/project_repository_storage_move.rb
@@ -20,6 +20,10 @@ class ProjectRepositoryStorageMove < ApplicationRecord
inclusion: { in: ->(_) { Gitlab.config.repositories.storages.keys } }
validate :project_repository_writable, on: :create
+ default_value_for(:destination_storage_name, allows_nil: false) do
+ pick_repository_storage
+ end
+
state_machine initial: :initial do
event :schedule do
transition initial: :scheduled
@@ -77,6 +81,12 @@ class ProjectRepositoryStorageMove < ApplicationRecord
scope :order_created_at_desc, -> { order(created_at: :desc) }
scope :with_projects, -> { includes(project: :route) }
+ class << self
+ def pick_repository_storage
+ Project.pick_repository_storage
+ end
+ end
+
private
def project_repository_writable
diff --git a/app/models/project_services/chat_message/deployment_message.rb b/app/models/project_services/chat_message/deployment_message.rb
index dae3a56116e..5deb757e60f 100644
--- a/app/models/project_services/chat_message/deployment_message.rb
+++ b/app/models/project_services/chat_message/deployment_message.rb
@@ -38,7 +38,11 @@ module ChatMessage
private
def message
- "Deploy to #{environment} #{humanized_status}"
+ if running?
+ "Starting deploy to #{environment}"
+ else
+ "Deploy to #{environment} #{humanized_status}"
+ end
end
def color
@@ -73,5 +77,9 @@ module ChatMessage
def humanized_status
status == 'success' ? 'succeeded' : status
end
+
+ def running?
+ status == 'running'
+ end
end
end
diff --git a/app/models/project_services/chat_message/issue_message.rb b/app/models/project_services/chat_message/issue_message.rb
index 0cdcfcf0237..c8e90b66bae 100644
--- a/app/models/project_services/chat_message/issue_message.rb
+++ b/app/models/project_services/chat_message/issue_message.rb
@@ -41,15 +41,11 @@ module ChatMessage
private
def message
- if opened_issue?
- "[#{project_link}] Issue #{state} by #{user_combined_name}"
- else
- "[#{project_link}] Issue #{issue_link} #{state} by #{user_combined_name}"
- end
+ "[#{project_link}] Issue #{issue_link} #{state} by #{user_combined_name}"
end
def opened_issue?
- action == "open"
+ action == 'open'
end
def description_message
@@ -57,7 +53,7 @@ module ChatMessage
title: issue_title,
title_link: issue_url,
text: format(description),
- color: "#C95823"
+ color: '#C95823'
}]
end
diff --git a/app/models/project_services/confluence_service.rb b/app/models/project_services/confluence_service.rb
index dd44a0d1d56..6db446fc04c 100644
--- a/app/models/project_services/confluence_service.rb
+++ b/app/models/project_services/confluence_service.rb
@@ -27,7 +27,7 @@ class ConfluenceService < Service
end
def description
- s_('ConfluenceService|Connect a Confluence Cloud Workspace to your GitLab project')
+ s_('ConfluenceService|Connect a Confluence Cloud Workspace to GitLab')
end
def detailed_description
diff --git a/app/models/project_services/drone_ci_service.rb b/app/models/project_services/drone_ci_service.rb
index 4e4955b45d8..5a49f780d46 100644
--- a/app/models/project_services/drone_ci_service.rb
+++ b/app/models/project_services/drone_ci_service.rb
@@ -42,7 +42,7 @@ class DroneCiService < CiService
def commit_status_path(sha, ref)
Gitlab::Utils.append_path(
drone_url,
- "gitlab/#{project.full_path}/commits/#{sha}?branch=#{URI.encode(ref.to_s)}&access_token=#{token}")
+ "gitlab/#{project.full_path}/commits/#{sha}?branch=#{Addressable::URI.encode_component(ref.to_s)}&access_token=#{token}")
end
def commit_status(sha, ref)
@@ -75,7 +75,7 @@ class DroneCiService < CiService
def build_page(sha, ref)
Gitlab::Utils.append_path(
drone_url,
- "gitlab/#{project.full_path}/redirect/commits/#{sha}?branch=#{URI.encode(ref.to_s)}")
+ "gitlab/#{project.full_path}/redirect/commits/#{sha}?branch=#{Addressable::URI.encode_component(ref.to_s)}")
end
def title
diff --git a/app/models/project_services/packagist_service.rb b/app/models/project_services/packagist_service.rb
index 35dbedd1341..21f0a2b2463 100644
--- a/app/models/project_services/packagist_service.rb
+++ b/app/models/project_services/packagist_service.rb
@@ -16,7 +16,7 @@ class PackagistService < Service
end
def description
- 'Update your project on Packagist, the main Composer repository'
+ s_('Integrations|Update your projects on Packagist, the main Composer repository')
end
def self.to_param
diff --git a/app/models/project_statistics.rb b/app/models/project_statistics.rb
index 67ab2c0ce8a..0d2f89fb18d 100644
--- a/app/models/project_statistics.rb
+++ b/app/models/project_statistics.rb
@@ -2,6 +2,7 @@
class ProjectStatistics < ApplicationRecord
include AfterCommitQueue
+ include CounterAttribute
belongs_to :project
belongs_to :namespace
@@ -9,6 +10,13 @@ class ProjectStatistics < ApplicationRecord
default_value_for :wiki_size, 0
default_value_for :snippets_size, 0
+ counter_attribute :build_artifacts_size
+ counter_attribute :storage_size
+
+ counter_attribute_after_flush do |project_statistic|
+ Namespaces::ScheduleAggregationWorker.perform_async(project_statistic.namespace_id)
+ end
+
before_save :update_storage_size
COLUMNS_TO_REFRESH = [:repository_size, :wiki_size, :lfs_objects_size, :commit_count, :snippets_size].freeze
@@ -29,6 +37,8 @@ class ProjectStatistics < ApplicationRecord
end
def refresh!(only: [])
+ return if Gitlab::Database.read_only?
+
COLUMNS_TO_REFRESH.each do |column, generator|
if only.empty? || only.include?(column)
public_send("update_#{column}") # rubocop:disable GitlabSecurity/PublicSend
@@ -96,12 +106,27 @@ class ProjectStatistics < ApplicationRecord
# Additional columns are updated depending on key => [columns], which allows
# to update statistics which are and also those which aren't included in storage_size
# or any other additional summary column in the future.
- def self.increment_statistic(project_id, key, amount)
+ def self.increment_statistic(project, key, amount)
raise ArgumentError, "Cannot increment attribute: #{key}" unless INCREMENTABLE_COLUMNS.key?(key)
return if amount == 0
- where(project_id: project_id)
- .columns_to_increment(key, amount)
+ project.statistics.try do |project_statistics|
+ if project_statistics.counter_attribute_enabled?(key)
+ statistics_to_increment = [key] + INCREMENTABLE_COLUMNS[key].to_a
+ statistics_to_increment.each do |statistic|
+ project_statistics.delayed_increment_counter(statistic, amount)
+ end
+ else
+ legacy_increment_statistic(project, key, amount)
+ end
+ end
+ end
+
+ def self.legacy_increment_statistic(project, key, amount)
+ where(project_id: project.id).columns_to_increment(key, amount)
+
+ Namespaces::ScheduleAggregationWorker.perform_async( # rubocop: disable CodeReuse/Worker
+ project.namespace_id)
end
def self.columns_to_increment(key, amount)
diff --git a/app/models/project_tracing_setting.rb b/app/models/project_tracing_setting.rb
new file mode 100644
index 00000000000..93fa80aed67
--- /dev/null
+++ b/app/models/project_tracing_setting.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class ProjectTracingSetting < ApplicationRecord
+ belongs_to :project
+
+ validates :external_url, length: { maximum: 255 }, public_url: true
+
+ before_validation :sanitize_external_url
+
+ private
+
+ def sanitize_external_url
+ self.external_url = Rails::Html::FullSanitizer.new.sanitize(self.external_url)
+ end
+end
diff --git a/app/models/project_wiki.rb b/app/models/project_wiki.rb
index bd570cf7ead..91fb3d4e4ba 100644
--- a/app/models/project_wiki.rb
+++ b/app/models/project_wiki.rb
@@ -1,10 +1,11 @@
# frozen_string_literal: true
class ProjectWiki < Wiki
+ self.container_class = Project
alias_method :project, :container
# Project wikis are tied to the main project storage
- delegate :storage, :repository_storage, :hashed_storage?, to: :container
+ delegate :storage, :repository_storage, :hashed_storage?, :lfs_enabled?, to: :container
override :disk_path
def disk_path(*args, &block)
diff --git a/app/models/prometheus_alert.rb b/app/models/prometheus_alert.rb
index f0441d4a3cb..684f50d5f58 100644
--- a/app/models/prometheus_alert.rb
+++ b/app/models/prometheus_alert.rb
@@ -4,6 +4,7 @@ class PrometheusAlert < ApplicationRecord
include Sortable
include UsageStatistics
include Presentable
+ include EachBatch
OPERATORS_MAP = {
lt: "<",
@@ -35,6 +36,7 @@ class PrometheusAlert < ApplicationRecord
scope :for_metric, -> (metric) { where(prometheus_metric: metric) }
scope :for_project, -> (project) { where(project_id: project) }
scope :for_environment, -> (environment) { where(environment_id: environment) }
+ scope :get_environment_id, -> { select(:environment_id).pluck(:environment_id) }
def self.distinct_projects
sub_query = self.group(:project_id).select(1)
diff --git a/app/models/prometheus_metric.rb b/app/models/prometheus_metric.rb
index 9ddf66cd388..590eda62c11 100644
--- a/app/models/prometheus_metric.rb
+++ b/app/models/prometheus_metric.rb
@@ -1,6 +1,8 @@
# frozen_string_literal: true
class PrometheusMetric < ApplicationRecord
+ include EachBatch
+
belongs_to :project, validate: true, inverse_of: :prometheus_metrics
has_many :prometheus_alerts, inverse_of: :prometheus_metric
diff --git a/app/models/release.rb b/app/models/release.rb
index 4c9d89105d7..f2162a0f674 100644
--- a/app/models/release.rb
+++ b/app/models/release.rb
@@ -30,6 +30,12 @@ class Release < ApplicationRecord
scope :with_project_and_namespace, -> { includes(project: :namespace) }
scope :recent, -> { sorted.limit(MAX_NUMBER_TO_DISPLAY) }
+ # Sorting
+ scope :order_created, -> { reorder('created_at ASC') }
+ scope :order_created_desc, -> { reorder('created_at DESC') }
+ scope :order_released, -> { reorder('released_at ASC') }
+ scope :order_released_desc, -> { reorder('released_at DESC') }
+
delegate :repository, to: :project
MAX_NUMBER_TO_DISPLAY = 3
@@ -92,6 +98,17 @@ class Release < ApplicationRecord
def set_released_at
self.released_at ||= created_at
end
+
+ def self.sort_by_attribute(method)
+ case method.to_s
+ when 'created_at_asc' then order_created
+ when 'created_at_desc' then order_created_desc
+ when 'released_at_asc' then order_released
+ when 'released_at_desc' then order_released_desc
+ else
+ order_created_desc
+ end
+ end
end
Release.prepend_if_ee('EE::Release')
diff --git a/app/models/repository.rb b/app/models/repository.rb
index ef17e010ba8..d4fd202b966 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -26,6 +26,7 @@ class Repository
delegate :ref_name_for_sha, to: :raw_repository
delegate :bundle_to_disk, to: :raw_repository
+ delegate :lfs_enabled?, to: :container
CreateTreeError = Class.new(StandardError)
AmbiguousRefError = Class.new(StandardError)
@@ -853,16 +854,16 @@ class Repository
def merge(user, source_sha, merge_request, message)
with_cache_hooks do
raw_repository.merge(user, source_sha, merge_request.target_branch, message) do |commit_id|
- merge_request.update(in_progress_merge_commit_sha: commit_id)
+ merge_request.update_and_mark_in_progress_merge_commit_sha(commit_id)
nil # Return value does not matter.
end
end
end
- def merge_to_ref(user, source_sha, merge_request, target_ref, message, first_parent_ref)
+ def merge_to_ref(user, source_sha, merge_request, target_ref, message, first_parent_ref, allow_conflicts = false)
branch = merge_request.target_branch
- raw.merge_to_ref(user, source_sha, branch, target_ref, message, first_parent_ref)
+ raw.merge_to_ref(user, source_sha, branch, target_ref, message, first_parent_ref, allow_conflicts)
end
def delete_refs(*ref_names)
@@ -873,7 +874,7 @@ class Repository
their_commit_id = commit(source)&.id
raise 'Invalid merge source' if their_commit_id.nil?
- merge_request&.update(in_progress_merge_commit_sha: their_commit_id)
+ merge_request&.update_and_mark_in_progress_merge_commit_sha(their_commit_id)
with_cache_hooks { raw.ff_merge(user, their_commit_id, target_branch) }
end
@@ -1142,21 +1143,10 @@ class Repository
end
def project
- if repo_type.snippet?
- container.project
- elsif container.is_a?(Project)
- container
- end
- end
-
- # TODO: pass this in directly to `Blob` rather than delegating it to here
- #
- # https://gitlab.com/gitlab-org/gitlab/-/issues/201886
- def lfs_enabled?
if container.is_a?(Project)
- container.lfs_enabled?
+ container
else
- false # LFS is not supported for snippet or group repositories
+ container.try(:project)
end
end
diff --git a/app/models/resource_label_event.rb b/app/models/resource_label_event.rb
index cc96698be09..18e2944a9ca 100644
--- a/app/models/resource_label_event.rb
+++ b/app/models/resource_label_event.rb
@@ -15,6 +15,7 @@ class ResourceLabelEvent < ResourceEvent
validate :exactly_one_issuable
after_save :expire_etag_cache
+ after_save :usage_metrics
after_destroy :expire_etag_cache
enum action: {
@@ -113,6 +114,16 @@ class ResourceLabelEvent < ResourceEvent
def discussion_id_key
[self.class.name, created_at, user_id]
end
+
+ def for_issue?
+ issue_id.present?
+ end
+
+ def usage_metrics
+ return unless for_issue?
+
+ Gitlab::UsageDataCounters::IssueActivityUniqueCounter.track_issue_label_changed_action(author: user)
+ end
end
ResourceLabelEvent.prepend_if_ee('EE::ResourceLabelEvent')
diff --git a/app/models/resource_state_event.rb b/app/models/resource_state_event.rb
index 1ce4e14d289..6475633868a 100644
--- a/app/models/resource_state_event.rb
+++ b/app/models/resource_state_event.rb
@@ -11,6 +11,8 @@ class ResourceStateEvent < ResourceEvent
# state is used for issue and merge request states.
enum state: Issue.available_states.merge(MergeRequest.available_states).merge(reopened: 5)
+ after_save :usage_metrics
+
def self.issuable_attrs
%i(issue merge_request).freeze
end
@@ -18,6 +20,29 @@ class ResourceStateEvent < ResourceEvent
def issuable
issue || merge_request
end
+
+ def for_issue?
+ issue_id.present?
+ end
+
+ private
+
+ def usage_metrics
+ return unless for_issue?
+
+ case state
+ when 'closed'
+ issue_usage_counter.track_issue_closed_action(author: user)
+ when 'reopened'
+ issue_usage_counter.track_issue_reopened_action(author: user)
+ else
+ # no-op, nothing to do, not a state we're tracking
+ end
+ end
+
+ def issue_usage_counter
+ Gitlab::UsageDataCounters::IssueActivityUniqueCounter
+ end
end
ResourceStateEvent.prepend_if_ee('EE::ResourceStateEvent')
diff --git a/app/models/resource_timebox_event.rb b/app/models/resource_timebox_event.rb
index 44f48915425..dbb2b428c7b 100644
--- a/app/models/resource_timebox_event.rb
+++ b/app/models/resource_timebox_event.rb
@@ -13,6 +13,8 @@ class ResourceTimeboxEvent < ResourceEvent
remove: 2
}
+ after_save :usage_metrics
+
def self.issuable_attrs
%i(issue merge_request).freeze
end
@@ -20,4 +22,17 @@ class ResourceTimeboxEvent < ResourceEvent
def issuable
issue || merge_request
end
+
+ private
+
+ def usage_metrics
+ case self
+ when ResourceMilestoneEvent
+ Gitlab::UsageDataCounters::IssueActivityUniqueCounter.track_issue_milestone_changed_action(author: user)
+ when ResourceIterationEvent
+ Gitlab::UsageDataCounters::IssueActivityUniqueCounter.track_issue_iteration_changed_action(author: user)
+ else
+ # no-op
+ end
+ end
end
diff --git a/app/models/resource_weight_event.rb b/app/models/resource_weight_event.rb
deleted file mode 100644
index bbabd54325e..00000000000
--- a/app/models/resource_weight_event.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-# frozen_string_literal: true
-
-class ResourceWeightEvent < ResourceEvent
- validates :issue, presence: true
-
- include IssueResourceEvent
-end
diff --git a/app/models/service.rb b/app/models/service.rb
index e63e06bf46f..764f417362f 100644
--- a/app/models/service.rb
+++ b/app/models/service.rb
@@ -7,9 +7,7 @@ class Service < ApplicationRecord
include Importable
include ProjectServicesLoggable
include DataFields
- include IgnorableColumns
-
- ignore_columns %i[default], remove_with: '13.5', remove_after: '2020-10-22'
+ include FromUnion
SERVICE_NAMES = %w[
alerts asana assembla bamboo bugzilla buildkite campfire confluence custom_issue_tracker discord
@@ -65,6 +63,7 @@ class Service < ApplicationRecord
scope :active, -> { where(active: true) }
scope :by_type, -> (type) { where(type: type) }
scope :by_active_flag, -> (flag) { where(active: flag) }
+ scope :inherit_from_id, -> (id) { where(inherit_from_id: id) }
scope :for_group, -> (group) { where(group_id: group, type: available_services_types) }
scope :for_template, -> { where(template: true, type: available_services_types) }
scope :for_instance, -> { where(instance: true, type: available_services_types) }
@@ -209,6 +208,10 @@ class Service < ApplicationRecord
DEV_SERVICE_NAMES
end
+ def self.project_specific_services_names
+ []
+ end
+
def self.available_services_types
available_services_names.map { |service_name| "#{service_name}_service".camelize }
end
@@ -217,7 +220,7 @@ class Service < ApplicationRecord
services_names.map { |service_name| "#{service_name}_service".camelize }
end
- def self.build_from_integration(project_id, integration)
+ def self.build_from_integration(integration, project_id: nil, group_id: nil)
service = integration.dup
if integration.supports_data_fields?
@@ -227,8 +230,9 @@ class Service < ApplicationRecord
service.template = false
service.instance = false
- service.inherit_from_id = integration.id if integration.instance?
service.project_id = project_id
+ service.group_id = group_id
+ service.inherit_from_id = integration.id if integration.instance? || integration.group
service.active = false if service.invalid?
service
end
@@ -245,7 +249,7 @@ class Service < ApplicationRecord
group_ids = scope.ancestors.select(:id)
array = group_ids.to_sql.present? ? "array(#{group_ids.to_sql})" : 'ARRAY[]'
- where(type: type, group_id: group_ids)
+ where(type: type, group_id: group_ids, inherit_from_id: nil)
.order(Arel.sql("array_position(#{array}::bigint[], services.group_id)"))
.first
end
@@ -256,6 +260,19 @@ class Service < ApplicationRecord
end
private_class_method :instance_level_integration
+ def self.create_from_active_default_integrations(scope, association, with_templates: false)
+ group_ids = scope.ancestors.select(:id)
+ array = group_ids.to_sql.present? ? "array(#{group_ids.to_sql})" : 'ARRAY[]'
+
+ from_union([
+ with_templates ? active.where(template: true) : none,
+ active.where(instance: true),
+ active.where(group_id: group_ids, inherit_from_id: nil)
+ ]).order(Arel.sql("type ASC, array_position(#{array}::bigint[], services.group_id), instance DESC")).group_by(&:type).each do |type, records|
+ build_from_integration(records.first, association => scope.id).save!
+ end
+ end
+
def activated?
active
end
diff --git a/app/models/service_list.rb b/app/models/service_list.rb
index 9cbc5e68059..5eca5f2bda1 100644
--- a/app/models/service_list.rb
+++ b/app/models/service_list.rb
@@ -1,8 +1,8 @@
# frozen_string_literal: true
class ServiceList
- def initialize(batch_ids, service_hash, association)
- @batch_ids = batch_ids
+ def initialize(batch, service_hash, association)
+ @batch = batch
@service_hash = service_hash
@association = association
end
@@ -13,15 +13,15 @@ class ServiceList
private
- attr_reader :batch_ids, :service_hash, :association
+ attr_reader :batch, :service_hash, :association
def columns
- (service_hash.keys << "#{association}_id")
+ service_hash.keys << "#{association}_id"
end
def values
- batch_ids.map do |id|
- (service_hash.values << id)
+ batch.select(:id).map do |record|
+ service_hash.values << record.id
end
end
end
diff --git a/app/models/snippet.rb b/app/models/snippet.rb
index 1cf3097861c..d71853e11cf 100644
--- a/app/models/snippet.rb
+++ b/app/models/snippet.rb
@@ -19,7 +19,6 @@ class Snippet < ApplicationRecord
extend ::Gitlab::Utils::Override
MAX_FILE_COUNT = 10
- MAX_SINGLE_FILE_COUNT = 1
cache_markdown_field :title, pipeline: :single_line
cache_markdown_field :description
@@ -175,8 +174,8 @@ class Snippet < ApplicationRecord
Snippet.find_by(id: id, project: project)
end
- def self.max_file_limit(user)
- Feature.enabled?(:snippet_multiple_files, user) ? MAX_FILE_COUNT : MAX_SINGLE_FILE_COUNT
+ def self.max_file_limit
+ MAX_FILE_COUNT
end
def initialize(attributes = {})
@@ -283,7 +282,8 @@ class Snippet < ApplicationRecord
strong_memoize(:repository_size_checker) do
::Gitlab::RepositorySizeChecker.new(
current_size_proc: -> { repository.size.megabytes },
- limit: Gitlab::CurrentSettings.snippet_size_limit
+ limit: Gitlab::CurrentSettings.snippet_size_limit,
+ namespace: nil
)
end
end
diff --git a/app/models/snippet_input_action_collection.rb b/app/models/snippet_input_action_collection.rb
index 38313e3a980..1e886e98083 100644
--- a/app/models/snippet_input_action_collection.rb
+++ b/app/models/snippet_input_action_collection.rb
@@ -8,7 +8,11 @@ class SnippetInputActionCollection
delegate :empty?, :any?, :[], to: :actions
def initialize(actions = [], allowed_actions: nil)
- @actions = actions.map { |action| SnippetInputAction.new(action.merge(allowed_actions: allowed_actions)) }
+ @actions = actions.map do |action|
+ params = action.merge(allowed_actions: allowed_actions)
+
+ SnippetInputAction.new(**params)
+ end
end
def to_commit_actions
diff --git a/app/models/snippet_repository.rb b/app/models/snippet_repository.rb
index 2cfb201191d..fa25a6f8441 100644
--- a/app/models/snippet_repository.rb
+++ b/app/models/snippet_repository.rb
@@ -12,7 +12,7 @@ class SnippetRepository < ApplicationRecord
belongs_to :snippet, inverse_of: :snippet_repository
- delegate :repository, to: :snippet
+ delegate :repository, :repository_storage, to: :snippet
class << self
def find_snippet(disk_path)
diff --git a/app/models/snippet_statistics.rb b/app/models/snippet_statistics.rb
index 8545296d076..6fb6f0ef713 100644
--- a/app/models/snippet_statistics.rb
+++ b/app/models/snippet_statistics.rb
@@ -34,6 +34,8 @@ class SnippetStatistics < ApplicationRecord
end
def refresh!
+ return if Gitlab::Database.read_only?
+
update_commit_count
update_repository_size
update_file_count
diff --git a/app/models/system_note_metadata.rb b/app/models/system_note_metadata.rb
index 961212d0295..0ddf2c5fbcd 100644
--- a/app/models/system_note_metadata.rb
+++ b/app/models/system_note_metadata.rb
@@ -18,9 +18,9 @@ class SystemNoteMetadata < ApplicationRecord
commit description merge confidential visible label assignee cross_reference
designs_added designs_modified designs_removed designs_discussion_added
title time_tracking branch milestone discussion task moved
- opened closed merged duplicate locked unlocked outdated
+ opened closed merged duplicate locked unlocked outdated reviewer
tag due_date pinned_embed cherry_pick health_status approved unapproved
- status alert_issue_added relate unrelate new_alert_added
+ status alert_issue_added relate unrelate new_alert_added severity
].freeze
validates :note, presence: true
diff --git a/app/models/terraform/state.rb b/app/models/terraform/state.rb
index 419fffcb666..9d88db27449 100644
--- a/app/models/terraform/state.rb
+++ b/app/models/terraform/state.rb
@@ -4,6 +4,12 @@ module Terraform
class State < ApplicationRecord
include UsageStatistics
include FileStoreMounter
+ include IgnorableColumns
+ # These columns are being removed since geo replication falls to the versioned state
+ # Tracking in https://gitlab.com/gitlab-org/gitlab/-/issues/258262
+ ignore_columns %i[verification_failure verification_retry_at verified_at verification_retry_count verification_checksum],
+ remove_with: '13.7',
+ remove_after: '2020-12-22'
HEX_REGEXP = %r{\A\h+\z}.freeze
UUID_LENGTH = 32
@@ -15,6 +21,7 @@ module Terraform
has_one :latest_version, -> { ordered_by_version_desc }, class_name: 'Terraform::StateVersion', foreign_key: :terraform_state_id
scope :versioning_not_enabled, -> { where(versioning_enabled: false) }
+ scope :ordered_by_name, -> { order(:name) }
validates :project_id, presence: true
validates :uuid, presence: true, uniqueness: true, length: { is: UUID_LENGTH },
@@ -30,11 +37,11 @@ module Terraform
end
def latest_file
- versioning_enabled ? latest_version&.file : file
- end
-
- def local?
- file_store == ObjectStorage::Store::LOCAL
+ if versioning_enabled?
+ latest_version&.file
+ else
+ latest_version&.file || file
+ end
end
def locked?
@@ -43,15 +50,56 @@ module Terraform
def update_file!(data, version:)
if versioning_enabled?
- new_version = versions.build(version: version)
- new_version.assign_attributes(created_by_user: locked_by_user, file: data)
- new_version.save!
+ create_new_version!(data: data, version: version)
+ elsif latest_version.present?
+ migrate_legacy_version!(data: data, version: version)
else
self.file = data
save!
end
end
+
+ private
+
+ ##
+ # If a Terraform state was created before versioning support was
+ # introduced, it will have a single version record whose file
+ # uses a legacy naming scheme in object storage. To update
+ # these states and versions to use the new behaviour, we must do
+ # the following when creating the next version:
+ #
+ # * Read the current, non-versioned file from the old location.
+ # * Update the :versioning_enabled flag, which determines the
+ # naming scheme
+ # * Resave the existing file with the updated name and location,
+ # using a version number one prior to the new version
+ # * Create the new version as normal
+ #
+ # This migration only needs to happen once for each state, from
+ # then on the state will behave as if it was always versioned.
+ #
+ # The code can be removed in the next major version (14.0), after
+ # which any states that haven't been migrated will need to be
+ # recreated: https://gitlab.com/gitlab-org/gitlab/-/issues/258960
+ def migrate_legacy_version!(data:, version:)
+ current_file = latest_version.file.read
+ current_version = parse_serial(current_file) || version - 1
+
+ update!(versioning_enabled: true)
+
+ reload_latest_version.update!(version: current_version, file: CarrierWaveStringFile.new(current_file))
+ create_new_version!(data: data, version: version)
+ end
+
+ def create_new_version!(data:, version:)
+ new_version = versions.build(version: version, created_by_user: locked_by_user)
+ new_version.assign_attributes(file: data)
+ new_version.save!
+ end
+
+ def parse_serial(file)
+ Gitlab::Json.parse(file)["serial"]
+ rescue JSON::ParserError
+ end
end
end
-
-Terraform::State.prepend_if_ee('EE::Terraform::State')
diff --git a/app/models/terraform/state_version.rb b/app/models/terraform/state_version.rb
index d5e315d18a1..eff44485401 100644
--- a/app/models/terraform/state_version.rb
+++ b/app/models/terraform/state_version.rb
@@ -14,5 +14,11 @@ module Terraform
mount_file_store_uploader VersionedStateUploader
delegate :project_id, :uuid, to: :terraform_state, allow_nil: true
+
+ def local?
+ file_store == ObjectStorage::Store::LOCAL
+ end
end
end
+
+Terraform::StateVersion.prepend_if_ee('EE::Terraform::StateVersion')
diff --git a/app/models/todo.rb b/app/models/todo.rb
index 6c8e085762d..0d893b25253 100644
--- a/app/models/todo.rb
+++ b/app/models/todo.rb
@@ -227,7 +227,7 @@ class Todo < ApplicationRecord
end
def self_assigned?
- assigned? && self_added?
+ self_added? && (assigned? || review_requested?)
end
private
diff --git a/app/models/u2f_registration.rb b/app/models/u2f_registration.rb
index 81415eb383b..1a389081913 100644
--- a/app/models/u2f_registration.rb
+++ b/app/models/u2f_registration.rb
@@ -4,6 +4,19 @@
class U2fRegistration < ApplicationRecord
belongs_to :user
+ after_commit :schedule_webauthn_migration, on: :create
+ after_commit :update_webauthn_registration, on: :update, if: :counter_changed?
+
+ def schedule_webauthn_migration
+ BackgroundMigrationWorker.perform_async('MigrateU2fWebauthn', [id, id])
+ end
+
+ def update_webauthn_registration
+ # When we update the sign count of this registration
+ # we need to update the sign count of the corresponding webauthn registration
+ # as well if it exists already
+ WebauthnRegistration.find_by_credential_xid(webauthn_credential_xid)&.update_attribute(:counter, counter)
+ end
def self.register(user, app_id, params, challenges)
u2f = U2F::U2F.new(app_id)
@@ -40,4 +53,13 @@ class U2fRegistration < ApplicationRecord
rescue JSON::ParserError, NoMethodError, ArgumentError, U2F::Error
false
end
+
+ private
+
+ def webauthn_credential_xid
+ # To find the corresponding webauthn registration, we use that
+ # the key handle of the u2f reg corresponds to the credential xid of the webauthn reg
+ # (with some base64 back and forth)
+ Base64.strict_encode64(Base64.urlsafe_decode64(key_handle))
+ end
end
diff --git a/app/models/user.rb b/app/models/user.rb
index 0a784b30d8f..ef77e207215 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -64,14 +64,7 @@ class User < ApplicationRecord
# and should be added after Devise modules are initialized.
include AsyncDeviseEmail
- BLOCKED_MESSAGE = "Your account has been blocked. Please contact your GitLab " \
- "administrator if you think this is an error."
- LOGIN_FORBIDDEN = "Your account does not have the required permission to login. Please contact your GitLab " \
- "administrator if you think this is an error."
-
- MINIMUM_INACTIVE_DAYS = 180
-
- ignore_column :bio, remove_with: '13.4', remove_after: '2020-09-22'
+ MINIMUM_INACTIVE_DAYS = 90
# Override Devise::Models::Trackable#update_tracked_fields!
# to limit database writes to at most once every hour
@@ -134,6 +127,8 @@ class User < ApplicationRecord
-> { where(members: { access_level: [Gitlab::Access::REPORTER, Gitlab::Access::DEVELOPER, Gitlab::Access::MAINTAINER, Gitlab::Access::OWNER] }) },
through: :group_members,
source: :group
+ has_many :minimal_access_group_members, -> { where(access_level: [Gitlab::Access::MINIMAL_ACCESS]) }, source: 'GroupMember', class_name: 'GroupMember'
+ has_many :minimal_access_groups, through: :minimal_access_group_members, source: :group
# Projects
has_many :groups_projects, through: :groups, source: :projects
@@ -172,6 +167,8 @@ class User < ApplicationRecord
has_many :assigned_issues, class_name: "Issue", through: :issue_assignees, source: :issue
has_many :assigned_merge_requests, class_name: "MergeRequest", through: :merge_request_assignees, source: :merge_request
+ has_many :bulk_imports
+
has_many :custom_attributes, class_name: 'UserCustomAttribute'
has_many :callouts, class_name: 'UserCallout'
has_many :term_agreements
@@ -298,6 +295,7 @@ class User < ApplicationRecord
transition active: :blocked
transition deactivated: :blocked
transition ldap_blocked: :blocked
+ transition blocked_pending_approval: :blocked
end
event :ldap_block do
@@ -309,13 +307,18 @@ class User < ApplicationRecord
transition deactivated: :active
transition blocked: :active
transition ldap_blocked: :active
+ transition blocked_pending_approval: :active
+ end
+
+ event :block_pending_approval do
+ transition active: :blocked_pending_approval
end
event :deactivate do
transition active: :deactivated
end
- state :blocked, :ldap_blocked do
+ state :blocked, :ldap_blocked, :blocked_pending_approval do
def blocked?
true
end
@@ -339,6 +342,7 @@ class User < ApplicationRecord
# Scopes
scope :admins, -> { where(admin: true) }
scope :blocked, -> { with_states(:blocked, :ldap_blocked) }
+ scope :blocked_pending_approval, -> { with_states(:blocked_pending_approval) }
scope :external, -> { where(external: true) }
scope :confirmed, -> { where.not(confirmed_at: nil) }
scope :active, -> { with_state(:active).non_internal }
@@ -381,11 +385,14 @@ class User < ApplicationRecord
super && can?(:log_in)
end
+ # The messages for these keys are defined in `devise.en.yml`
def inactive_message
- if blocked?
- BLOCKED_MESSAGE
+ if blocked_pending_approval?
+ :blocked_pending_approval
+ elsif blocked?
+ :blocked
elsif internal?
- LOGIN_FORBIDDEN
+ :forbidden
else
super
end
@@ -535,6 +542,8 @@ class User < ApplicationRecord
admins
when 'blocked'
blocked
+ when 'blocked_pending_approval'
+ blocked_pending_approval
when 'two_factor_disabled'
without_two_factor
when 'two_factor_enabled'
@@ -687,6 +696,17 @@ class User < ApplicationRecord
end
end
+ def security_bot
+ email_pattern = "security-bot%s@#{Settings.gitlab.host}"
+
+ unique_internal(where(user_type: :security_bot), 'GitLab-Security-Bot', email_pattern) do |u|
+ u.bio = 'System bot that monitors detected vulnerabilities for solutions and creates merge requests with the fixes.'
+ u.name = 'GitLab Security Bot'
+ u.website_url = Gitlab::Routing.url_helpers.help_page_url('user/application_security/security_bot/index.md')
+ u.avatar = bot_avatar(image: 'security-bot.png')
+ end
+ end
+
def support_bot
email_pattern = "support%s@#{Settings.gitlab.host}"
@@ -773,7 +793,7 @@ class User < ApplicationRecord
end
def two_factor_otp_enabled?
- otp_required_for_login?
+ otp_required_for_login? || Feature.enabled?(:forti_authenticator, self)
end
def two_factor_u2f_enabled?
@@ -1676,6 +1696,8 @@ class User < ApplicationRecord
end
def terms_accepted?
+ return true if project_bot?
+
accepted_term_id.present?
end
@@ -1706,7 +1728,7 @@ class User < ApplicationRecord
end
def can_be_deactivated?
- active? && no_recent_activity?
+ active? && no_recent_activity? && !internal?
end
def last_active_at
diff --git a/app/models/user_callout.rb b/app/models/user_callout.rb
index 0ba319aa444..e39ff8712fc 100644
--- a/app/models/user_callout.rb
+++ b/app/models/user_callout.rb
@@ -19,7 +19,7 @@ class UserCallout < ApplicationRecord
webhooks_moved: 13,
service_templates_deprecated: 14,
admin_integrations_moved: 15,
- web_ide_alert_dismissed: 16,
+ web_ide_alert_dismissed: 16, # no longer in use
active_user_count_threshold: 18, # EE-only
buy_pipeline_minutes_notification_dot: 19, # EE-only
personal_access_token_expiry: 21, # EE-only
diff --git a/app/models/user_interacted_project.rb b/app/models/user_interacted_project.rb
index 1c615777018..7e7a387d3d4 100644
--- a/app/models/user_interacted_project.rb
+++ b/app/models/user_interacted_project.rb
@@ -21,7 +21,7 @@ class UserInteractedProject < ApplicationRecord
user_id: event.author_id
}
- cached_exists?(attributes) do
+ cached_exists?(**attributes) do
transaction(requires_new: true) do
where(attributes).select(1).first || create!(attributes)
true # not caching the whole record here for now
diff --git a/app/models/user_preference.rb b/app/models/user_preference.rb
index d3b3a46bf74..c05bc80415a 100644
--- a/app/models/user_preference.rb
+++ b/app/models/user_preference.rb
@@ -8,6 +8,9 @@ class UserPreference < ApplicationRecord
belongs_to :user
+ scope :with_user, -> { joins(:user) }
+ scope :gitpod_enabled, -> { where(gitpod_enabled: true) }
+
validates :issue_notes_filter, :merge_request_notes_filter, inclusion: { in: NOTES_FILTERS.values }, presence: true
validates :tab_width, numericality: {
only_integer: true,
diff --git a/app/models/vulnerability.rb b/app/models/vulnerability.rb
index 71d0b1db410..a4338c4e2bd 100644
--- a/app/models/vulnerability.rb
+++ b/app/models/vulnerability.rb
@@ -1,17 +1,7 @@
# frozen_string_literal: true
# Placeholder class for model that is implemented in EE
-# It reserves '+' as a reference prefix, but the table does not exist in FOSS
class Vulnerability < ApplicationRecord
- include IgnorableColumns
-
- def self.reference_prefix
- '+'
- end
-
- def self.reference_prefix_escaped
- '&plus;'
- end
end
Vulnerability.prepend_if_ee('EE::Vulnerability')
diff --git a/app/models/wiki.rb b/app/models/wiki.rb
index 9462f7401c4..e329a094319 100644
--- a/app/models/wiki.rb
+++ b/app/models/wiki.rb
@@ -4,6 +4,7 @@ class Wiki
extend ::Gitlab::Utils::Override
include HasRepository
include Gitlab::Utils::StrongMemoize
+ include GlobalID::Identification
MARKUPS = { # rubocop:disable Style/MultilineIfModifier
'Markdown' => :markdown,
@@ -28,14 +29,46 @@ class Wiki
# an operation fails.
attr_reader :error_message
- def self.for_container(container, user = nil)
- "#{container.class.name}Wiki".constantize.new(container, user)
+ # Support run_after_commit callbacks, since we don't have a DB record
+ # we delegate to the container.
+ delegate :run_after_commit, to: :container
+
+ class << self
+ attr_accessor :container_class
+
+ def for_container(container, user = nil)
+ "#{container.class.name}Wiki".constantize.new(container, user)
+ end
+
+ # This is needed to support repository lookup through Gitlab::GlRepository::Identifier
+ def find_by_id(container_id)
+ container_class.find_by_id(container_id)&.wiki
+ end
end
def initialize(container, user = nil)
+ raise ArgumentError, "user must be a User, got #{user.class}" if user && !user.is_a?(User)
+
@container = container
@user = user
- raise ArgumentError, "user must be a User, got #{user.class}" if user && !user.is_a?(User)
+ end
+
+ def ==(other)
+ other.is_a?(self.class) && container == other.container
+ end
+
+ # This is needed in:
+ # - Storage::Hashed
+ # - Gitlab::GlRepository::RepoType#identifier_for_container
+ #
+ # We also need an `#id` to support `build_stubbed` in tests, where the
+ # value doesn't matter.
+ #
+ # NOTE: Wikis don't have a DB record, so this ID can be the same
+ # for two wikis in different containers and should not be expected to
+ # be unique. Use `to_global_id` instead if you need a unique ID.
+ def id
+ container.id
end
def path
@@ -103,10 +136,10 @@ class Wiki
limited = pages.size > limit
pages = pages.first(limit) if limited
- [WikiPage.group_by_directory(pages), limited]
+ [WikiDirectory.group_pages(pages), limited]
end
- # Finds a page within the repository based on a tile
+ # Finds a page within the repository based on a title
# or slug.
#
# title - The human readable or parameterized title of
@@ -183,7 +216,7 @@ class Wiki
override :repository
def repository
- @repository ||= Gitlab::GlRepository::WIKI.repository_for(container)
+ @repository ||= Gitlab::GlRepository::WIKI.repository_for(self)
end
def repository_storage
@@ -198,7 +231,6 @@ class Wiki
def full_path
container.full_path + '.wiki'
end
- alias_method :id, :full_path
# @deprecated use full_path when you need it for an URL route or disk_path when you want to point to the filesystem
alias_method :path_with_namespace, :full_path
diff --git a/app/models/wiki_directory.rb b/app/models/wiki_directory.rb
index df2fe25b08b..3a2613e15d9 100644
--- a/app/models/wiki_directory.rb
+++ b/app/models/wiki_directory.rb
@@ -3,13 +3,46 @@
class WikiDirectory
include ActiveModel::Validations
- attr_accessor :slug, :pages
+ attr_accessor :slug, :entries
validates :slug, presence: true
- def initialize(slug, pages = [])
+ # Groups a list of wiki pages into a nested collection of WikiPage and WikiDirectory objects,
+ # preserving the order of the passed pages.
+ #
+ # Returns an array with all entries for the toplevel directory.
+ #
+ # @param [Array<WikiPage>] pages
+ # @return [Array<WikiPage, WikiDirectory>]
+ #
+ def self.group_pages(pages)
+ # Build a hash to map paths to created WikiDirectory objects,
+ # and recursively create them for each level of the path.
+ # For the toplevel directory we use '' as path, as that's what WikiPage#directory returns.
+ directories = Hash.new do |_, path|
+ directories[path] = new(path).tap do |directory|
+ if path.present?
+ parent = File.dirname(path)
+ parent = '' if parent == '.'
+ directories[parent].entries << directory
+ end
+ end
+ end
+
+ pages.each do |page|
+ directories[page.directory].entries << page
+ end
+
+ directories[''].entries
+ end
+
+ def initialize(slug, entries = [])
@slug = slug
- @pages = pages
+ @entries = entries
+ end
+
+ def title
+ WikiPage.unhyphenize(File.basename(slug))
end
# Relative path to the partial to be used when rendering collections
diff --git a/app/models/wiki_page.rb b/app/models/wiki_page.rb
index faf3d19d936..989128987d5 100644
--- a/app/models/wiki_page.rb
+++ b/app/models/wiki_page.rb
@@ -31,29 +31,6 @@ class WikiPage
alias_method :==, :eql?
- # Sorts and groups pages by directory.
- #
- # pages - an array of WikiPage objects.
- #
- # Returns an array of WikiPage and WikiDirectory objects. The entries are
- # sorted by alphabetical order (directories and pages inside each directory).
- # Pages at the root level come before everything.
- def self.group_by_directory(pages)
- return [] if pages.blank?
-
- pages.each_with_object([]) do |page, grouped_pages|
- next grouped_pages << page unless page.directory.present?
-
- directory = grouped_pages.find do |obj|
- obj.is_a?(WikiDirectory) && obj.slug == page.directory
- end
-
- next directory.pages << page if directory
-
- grouped_pages << WikiDirectory.new(page.directory, [page])
- end
- end
-
def self.unhyphenize(name)
name.gsub(/-+/, ' ')
end
diff --git a/app/policies/base_policy.rb b/app/policies/base_policy.rb
index 13d732e4edd..1c93073025d 100644
--- a/app/policies/base_policy.rb
+++ b/app/policies/base_policy.rb
@@ -27,10 +27,7 @@ class BasePolicy < DeclarativePolicy::Base
desc "User email is unconfirmed or user account is locked"
with_options scope: :user, score: 0
- condition(:inactive) do
- Feature.enabled?(:inactive_policy_condition, default_enabled: true) &&
- @user&.confirmation_required_on_sign_in? || @user&.access_locked?
- end
+ condition(:inactive) { @user&.confirmation_required_on_sign_in? || @user&.access_locked? }
with_options scope: :user, score: 0
condition(:external_user) { @user.nil? || @user.external? }
diff --git a/app/policies/ci/bridge_policy.rb b/app/policies/ci/bridge_policy.rb
new file mode 100644
index 00000000000..37a07ea8aaf
--- /dev/null
+++ b/app/policies/ci/bridge_policy.rb
@@ -0,0 +1,12 @@
+# frozen_string_literal: true
+
+module Ci
+ class BridgePolicy < CommitStatusPolicy
+ condition(:can_update_downstream_branch) do
+ ::Gitlab::UserAccess.new(@user, container: @subject.downstream_project)
+ .can_update_branch?(@subject.target_revision_ref)
+ end
+
+ rule { can_update_downstream_branch }.enable :play_job
+ end
+end
diff --git a/app/policies/ci/build_policy.rb b/app/policies/ci/build_policy.rb
index b3950c6a0e3..3efc07421e4 100644
--- a/app/policies/ci/build_policy.rb
+++ b/app/policies/ci/build_policy.rb
@@ -60,6 +60,8 @@ module Ci
rule { can?(:update_build) & terminal }.enable :create_build_terminal
+ rule { can?(:update_build) }.enable :play_job
+
rule { is_web_ide_terminal & can?(:create_web_ide_terminal) & (admin | owner_of_job) }.policy do
enable :read_web_ide_terminal
enable :update_web_ide_terminal
diff --git a/app/policies/global_policy.rb b/app/policies/global_policy.rb
index de69636b078..c1ea4dddb51 100644
--- a/app/policies/global_policy.rb
+++ b/app/policies/global_policy.rb
@@ -98,6 +98,7 @@ class GlobalPolicy < BasePolicy
rule { admin }.policy do
enable :read_custom_attribute
enable :update_custom_attribute
+ enable :approve_user
end
# We can't use `read_statistics` because the user may have different permissions for different projects
diff --git a/app/policies/group_policy.rb b/app/policies/group_policy.rb
index c98e82efef7..f9ec026a6d2 100644
--- a/app/policies/group_policy.rb
+++ b/app/policies/group_policy.rb
@@ -46,6 +46,19 @@ class GroupPolicy < BasePolicy
group_projects_for(user: @user, group: @subject, only_owned: false).any? { |p| p.design_management_enabled? }
end
+ desc "Deploy token with read_package_registry scope"
+ condition(:read_package_registry_deploy_token) do
+ @user.is_a?(DeployToken) && @user.groups.include?(@subject) && @user.read_package_registry
+ end
+
+ desc "Deploy token with write_package_registry scope"
+ condition(:write_package_registry_deploy_token) do
+ @user.is_a?(DeployToken) && @user.groups.include?(@subject) && @user.write_package_registry
+ end
+
+ with_scope :subject
+ condition(:resource_access_token_available) { resource_access_token_available? }
+
rule { design_management_enabled }.policy do
enable :read_design_activity
end
@@ -91,7 +104,6 @@ class GroupPolicy < BasePolicy
rule { developer }.policy do
enable :admin_milestone
- enable :read_package
enable :create_metrics_dashboard_annotation
enable :delete_metrics_dashboard_annotation
enable :update_metrics_dashboard_annotation
@@ -105,6 +117,7 @@ class GroupPolicy < BasePolicy
enable :admin_issue
enable :read_metrics_dashboard_annotation
enable :read_prometheus
+ enable :read_package
end
rule { maintainer }.policy do
@@ -167,6 +180,20 @@ class GroupPolicy < BasePolicy
rule { maintainer & can?(:create_projects) }.enable :transfer_projects
+ rule { read_package_registry_deploy_token }.policy do
+ enable :read_package
+ enable :read_group
+ end
+
+ rule { write_package_registry_deploy_token }.policy do
+ enable :create_package
+ enable :read_group
+ end
+
+ rule { resource_access_token_available & can?(:admin_group) }.policy do
+ enable :admin_resource_access_tokens
+ end
+
def access_level
return GroupMember::NO_ACCESS if @user.nil?
return GroupMember::NO_ACCESS unless user_is_user?
@@ -183,6 +210,14 @@ class GroupPolicy < BasePolicy
def user_is_user?
user.is_a?(User)
end
+
+ def group
+ @subject
+ end
+
+ def resource_access_token_available?
+ true
+ end
end
GroupPolicy.prepend_if_ee('EE::GroupPolicy')
diff --git a/app/policies/issue_policy.rb b/app/policies/issue_policy.rb
index b02bb8621ed..44c448eb601 100644
--- a/app/policies/issue_policy.rb
+++ b/app/policies/issue_policy.rb
@@ -15,9 +15,6 @@ class IssuePolicy < IssuablePolicy
desc "Issue is confidential"
condition(:confidential, scope: :subject) { @subject.confidential? }
- desc "Issue has moved"
- condition(:moved) { @subject.moved? }
-
rule { confidential & ~can_read_confidential }.policy do
prevent(*create_read_update_admin_destroy(:issue))
prevent :read_issue_iid
@@ -38,12 +35,6 @@ class IssuePolicy < IssuablePolicy
rule { ~can?(:read_design) }.policy do
prevent :move_design
end
-
- rule { locked | moved }.policy do
- prevent :create_design
- prevent :move_design
- prevent :destroy_design
- end
end
IssuePolicy.prepend_if_ee('EE::IssuePolicy')
diff --git a/app/policies/project_policy.rb b/app/policies/project_policy.rb
index 87ee7d201e4..59e2d617bf7 100644
--- a/app/policies/project_policy.rb
+++ b/app/policies/project_policy.rb
@@ -104,6 +104,9 @@ class ProjectPolicy < BasePolicy
with_scope :subject
condition(:service_desk_enabled) { @subject.service_desk_enabled? }
+ with_scope :subject
+ condition(:resource_access_token_available) { resource_access_token_available? }
+
# We aren't checking `:read_issue` or `:read_merge_request` in this case
# because it could be possible for a user to see an issuable-iid
# (`:read_issue_iid` or `:read_merge_request_iid`) but then wouldn't be
@@ -237,7 +240,6 @@ class ProjectPolicy < BasePolicy
enable :read_merge_request
enable :read_sentry_issue
enable :update_sentry_issue
- enable :read_incidents
enable :read_prometheus
enable :read_metrics_dashboard_annotation
enable :metrics_dashboard
@@ -589,6 +591,10 @@ class ProjectPolicy < BasePolicy
prevent :read_project
end
+ rule { resource_access_token_available & can?(:admin_project) }.policy do
+ enable :admin_resource_access_tokens
+ end
+
private
def user_is_user?
@@ -663,6 +669,10 @@ class ProjectPolicy < BasePolicy
end
end
+ def resource_access_token_available?
+ true
+ end
+
def project
@subject
end
diff --git a/app/policies/releases/evidence_policy.rb b/app/policies/releases/evidence_policy.rb
index 701913e6fe4..3e35f2f5e87 100644
--- a/app/policies/releases/evidence_policy.rb
+++ b/app/policies/releases/evidence_policy.rb
@@ -15,6 +15,7 @@ module Releases
# - Project
# - Milestones
# - Issues
+ # TODO: remove issues from this check: https://gitlab.com/gitlab-org/gitlab/-/issues/259674
condition(:allowed_to_read_evidence) do
can?(:read_release) &&
can?(:download_code) &&
diff --git a/app/policies/terraform/state_policy.rb b/app/policies/terraform/state_policy.rb
new file mode 100644
index 00000000000..ba6109e5975
--- /dev/null
+++ b/app/policies/terraform/state_policy.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+module Terraform
+ class StatePolicy < BasePolicy
+ alias_method :terraform_state, :subject
+
+ delegate { terraform_state.project }
+ end
+end
diff --git a/app/policies/wiki_policy.rb b/app/policies/wiki_policy.rb
new file mode 100644
index 00000000000..a551439d0d4
--- /dev/null
+++ b/app/policies/wiki_policy.rb
@@ -0,0 +1,6 @@
+# frozen_string_literal: true
+
+class WikiPolicy < ::BasePolicy
+ # Wiki policies are delegated to their container objects (Project or Group)
+ delegate { subject.container }
+end
diff --git a/app/presenters/alert_management/alert_presenter.rb b/app/presenters/alert_management/alert_presenter.rb
index 5debe6d5dbd..4bfa3dc9a13 100644
--- a/app/presenters/alert_management/alert_presenter.rb
+++ b/app/presenters/alert_management/alert_presenter.rb
@@ -8,10 +8,11 @@ module AlertManagement
MARKDOWN_LINE_BREAK = " \n"
HORIZONTAL_LINE = "\n\n---\n\n"
+ INCIDENT_LABEL_NAME = ::IncidentManagement::CreateIncidentLabelService::LABEL_PROPERTIES[:title]
delegate :metrics_dashboard_url, :runbook, to: :parsed_payload
- def initialize(alert, _attributes = {})
+ def initialize(alert, **attributes)
super
@alert = alert
@@ -38,6 +39,30 @@ module AlertManagement
Gitlab::Utils::InlineHash.merge_keys(payload)
end
+ def show_incident_issues_link?
+ project.incident_management_setting&.create_issue?
+ end
+
+ def show_performance_dashboard_link?
+ prometheus_alert.present?
+ end
+
+ def incident_issues_link
+ project_issues_url(project, label_name: INCIDENT_LABEL_NAME)
+ end
+
+ def performance_dashboard_link
+ if environment
+ metrics_project_environment_url(project, environment)
+ else
+ metrics_project_environments_url(project)
+ end
+ end
+
+ def email_title
+ [environment&.name, query_title].compact.join(': ')
+ end
+
private
attr_reader :alert, :project
@@ -80,5 +105,11 @@ module AlertManagement
def host_links
hosts.join(' ')
end
+
+ def query_title
+ return title unless prometheus_alert
+
+ "#{prometheus_alert.title} #{prometheus_alert.computed_operator} #{prometheus_alert.threshold} for 5 minutes"
+ end
end
end
diff --git a/app/presenters/clusterable_presenter.rb b/app/presenters/clusterable_presenter.rb
index efb3cf7f348..62488465c24 100644
--- a/app/presenters/clusterable_presenter.rb
+++ b/app/presenters/clusterable_presenter.rb
@@ -8,7 +8,7 @@ class ClusterablePresenter < Gitlab::View::Presenter::Delegated
attributes_with_presenter_class = attributes.merge(presenter_class: presenter_class)
Gitlab::View::Presenter::Factory
- .new(clusterable, attributes_with_presenter_class)
+ .new(clusterable, **attributes_with_presenter_class)
.fabricate!
end
diff --git a/app/presenters/environment_presenter.rb b/app/presenters/environment_presenter.rb
new file mode 100644
index 00000000000..3fa31eb69a2
--- /dev/null
+++ b/app/presenters/environment_presenter.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+class EnvironmentPresenter < Gitlab::View::Presenter::Delegated
+ include ActionView::Helpers::UrlHelper
+
+ presents :environment
+
+ def path
+ if Feature.enabled?(:expose_environment_path_in_alert_details, project)
+ project_environment_path(project, self)
+ end
+ end
+end
diff --git a/app/presenters/event_presenter.rb b/app/presenters/event_presenter.rb
index 8f2388c2c31..c37721f7213 100644
--- a/app/presenters/event_presenter.rb
+++ b/app/presenters/event_presenter.rb
@@ -29,4 +29,26 @@ class EventPresenter < Gitlab::View::Presenter::Delegated
''
end
end
+
+ def target_type_name
+ if design?
+ 'Design'
+ elsif wiki_page?
+ 'Wiki Page'
+ elsif target_type.present?
+ target_type.titleize
+ else
+ "Project"
+ end.downcase
+ end
+
+ def note_target_type_name
+ return unless note?
+
+ if design_note?
+ 'Design'
+ else
+ target.noteable_type.titleize
+ end.downcase
+ end
end
diff --git a/app/presenters/instance_clusterable_presenter.rb b/app/presenters/instance_clusterable_presenter.rb
index 7704e6b59c1..94c1195ed6a 100644
--- a/app/presenters/instance_clusterable_presenter.rb
+++ b/app/presenters/instance_clusterable_presenter.rb
@@ -8,7 +8,7 @@ class InstanceClusterablePresenter < ClusterablePresenter
attributes_with_presenter_class = attributes.merge(presenter_class: InstanceClusterablePresenter)
Gitlab::View::Presenter::Factory
- .new(clusterable, attributes_with_presenter_class)
+ .new(clusterable, **attributes_with_presenter_class)
.fabricate!
end
diff --git a/app/presenters/issue_presenter.rb b/app/presenters/issue_presenter.rb
index 185fcd3e934..0b498ce97d8 100644
--- a/app/presenters/issue_presenter.rb
+++ b/app/presenters/issue_presenter.rb
@@ -11,3 +11,5 @@ class IssuePresenter < Gitlab::View::Presenter::Delegated
issue.subscribed?(current_user, issue.project)
end
end
+
+IssuePresenter.prepend_if_ee('EE::IssuePresenter')
diff --git a/app/presenters/label_presenter.rb b/app/presenters/label_presenter.rb
index 68aa05ada8e..c23d6ce2218 100644
--- a/app/presenters/label_presenter.rb
+++ b/app/presenters/label_presenter.rb
@@ -2,6 +2,7 @@
class LabelPresenter < Gitlab::View::Presenter::Delegated
presents :label
+ delegate :name, :full_name, to: :label_subject, prefix: :subject
def edit_path
case label
@@ -39,8 +40,8 @@ class LabelPresenter < Gitlab::View::Presenter::Delegated
label.is_a?(ProjectLabel)
end
- def subject_name
- label.subject.name
+ def label_subject
+ @label_subject ||= label.subject
end
private
diff --git a/app/presenters/merge_request_presenter.rb b/app/presenters/merge_request_presenter.rb
index 1ff02412994..a22138011ae 100644
--- a/app/presenters/merge_request_presenter.rb
+++ b/app/presenters/merge_request_presenter.rb
@@ -37,7 +37,7 @@ class MergeRequestPresenter < Gitlab::View::Presenter::Delegated
end
def remove_wip_path
- if work_in_progress? && can?(current_user, :update_merge_request, merge_request.project)
+ if can?(current_user, :update_merge_request, merge_request.project)
remove_wip_project_merge_request_path(project, merge_request)
end
end
diff --git a/app/presenters/packages/detail/package_presenter.rb b/app/presenters/packages/detail/package_presenter.rb
index bdb2e34854e..e8223d6498b 100644
--- a/app/presenters/packages/detail/package_presenter.rb
+++ b/app/presenters/packages/detail/package_presenter.rb
@@ -8,10 +8,13 @@ module Packages
end
def detail_view
+ name = @package.name
+ name = @package.conan_recipe if @package.conan?
+
package_detail = {
id: @package.id,
created_at: @package.created_at,
- name: @package.name,
+ name: name,
package_files: @package.package_files.map { |pf| build_package_file_view(pf) },
package_type: @package.package_type,
project_id: @package.project_id,
@@ -20,6 +23,7 @@ module Packages
version: @package.version
}
+ package_detail[:conan_package_name] = @package.name if @package.conan?
package_detail[:maven_metadatum] = @package.maven_metadatum if @package.maven_metadatum
package_detail[:nuget_metadatum] = @package.nuget_metadatum if @package.nuget_metadatum
package_detail[:composer_metadatum] = @package.composer_metadatum if @package.composer_metadatum
diff --git a/app/presenters/packages/pypi/package_presenter.rb b/app/presenters/packages/pypi/package_presenter.rb
index 4192e974645..1cb11c7be1a 100644
--- a/app/presenters/packages/pypi/package_presenter.rb
+++ b/app/presenters/packages/pypi/package_presenter.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-# Display package version data acording to PyPi
+# Display package version data acording to PyPI
# Simple API: https://warehouse.pypa.io/api-reference/legacy/#simple-project-api
module Packages
module Pypi
@@ -12,7 +12,7 @@ module Packages
@project = project
end
- # Returns the HTML body for PyPi simple API.
+ # Returns the HTML body for PyPI simple API.
# Basically a list of package download links for a specific
# package
def body
diff --git a/app/presenters/project_presenter.rb b/app/presenters/project_presenter.rb
index ef75c160b2d..392eeafb2b4 100644
--- a/app/presenters/project_presenter.rb
+++ b/app/presenters/project_presenter.rb
@@ -65,14 +65,14 @@ class ProjectPresenter < Gitlab::View::Presenter::Delegated
if can?(current_user, :download_code, project)
user_view
- elsif user_view == "activity"
- "activity"
- elsif can?(current_user, :read_wiki, project)
- "wiki"
- elsif feature_available?(:issues, current_user)
- "projects/issues/issues"
+ elsif user_view == 'activity'
+ 'activity'
+ elsif project.wiki_repository_exists? && can?(current_user, :read_wiki, project)
+ 'wiki'
+ elsif can?(current_user, :read_issue, project)
+ 'projects/issues/issues'
else
- "customize_workflow"
+ 'activity'
end
end
@@ -106,26 +106,38 @@ class ProjectPresenter < Gitlab::View::Presenter::Delegated
add_special_file_path(file_name: 'LICENSE')
end
+ def add_license_ide_path
+ ide_edit_path(project, default_branch_or_master, 'LICENSE')
+ end
+
def add_changelog_path
add_special_file_path(file_name: 'CHANGELOG')
end
+ def add_changelog_ide_path
+ ide_edit_path(project, default_branch_or_master, 'CHANGELOG')
+ end
+
def add_contribution_guide_path
add_special_file_path(file_name: 'CONTRIBUTING.md', commit_message: 'Add CONTRIBUTING')
end
- def add_ci_yml_path
- add_special_file_path(file_name: ci_config_path_or_default)
+ def add_contribution_guide_ide_path
+ ide_edit_path(project, default_branch_or_master, 'CONTRIBUTING.md')
end
- def add_ci_yml_ide_path
- ide_edit_path(project, default_branch_or_master, ci_config_path_or_default)
+ def add_ci_yml_path
+ add_special_file_path(file_name: ci_config_path_or_default)
end
def add_readme_path
add_special_file_path(file_name: 'README.md')
end
+ def add_readme_ide_path
+ ide_edit_path(project, default_branch_or_master, 'README.md')
+ end
+
def license_short_name
license = repository.license
license&.nickname || license&.name || 'LICENSE'
@@ -222,9 +234,11 @@ class ProjectPresenter < Gitlab::View::Presenter::Delegated
def new_file_anchor_data
if current_user && can_current_user_push_to_default_branch?
+ new_file_path = empty_repo? ? ide_edit_path(project, default_branch_or_master) : project_new_blob_path(project, default_branch_or_master)
+
AnchorData.new(false,
statistic_icon + _('New file'),
- project_new_blob_path(project, default_branch_or_master),
+ new_file_path,
'missing')
end
end
@@ -233,7 +247,7 @@ class ProjectPresenter < Gitlab::View::Presenter::Delegated
if current_user && can_current_user_push_to_default_branch? && repository.readme.nil?
AnchorData.new(false,
statistic_icon + _('Add README'),
- add_readme_path)
+ empty_repo? ? add_readme_ide_path : add_readme_path)
elsif repository.readme
AnchorData.new(false,
statistic_icon('doc-text') + _('README'),
@@ -247,7 +261,7 @@ class ProjectPresenter < Gitlab::View::Presenter::Delegated
if current_user && can_current_user_push_to_default_branch? && repository.changelog.blank?
AnchorData.new(false,
statistic_icon + _('Add CHANGELOG'),
- add_changelog_path)
+ empty_repo? ? add_changelog_ide_path : add_changelog_path)
elsif repository.changelog.present?
AnchorData.new(false,
statistic_icon('doc-text') + _('CHANGELOG'),
@@ -268,7 +282,7 @@ class ProjectPresenter < Gitlab::View::Presenter::Delegated
if current_user && can_current_user_push_to_default_branch?
AnchorData.new(false,
content_tag(:span, statistic_icon + _('Add LICENSE'), class: 'add-license-link d-flex'),
- add_license_path)
+ empty_repo? ? add_license_ide_path : add_license_path)
else
AnchorData.new(false,
icon + content_tag(:span, _('No license. All rights reserved'), class: 'project-stat-value'),
@@ -281,7 +295,7 @@ class ProjectPresenter < Gitlab::View::Presenter::Delegated
if current_user && can_current_user_push_to_default_branch? && repository.contribution_guide.blank?
AnchorData.new(false,
statistic_icon + _('Add CONTRIBUTING'),
- add_contribution_guide_path)
+ empty_repo? ? add_contribution_guide_ide_path : add_contribution_guide_path)
elsif repository.contribution_guide.present?
AnchorData.new(false,
statistic_icon('doc-text') + _('CONTRIBUTING'),
@@ -330,7 +344,7 @@ class ProjectPresenter < Gitlab::View::Presenter::Delegated
if cicd_missing?
AnchorData.new(false,
statistic_icon + _('Set up CI/CD'),
- add_ci_yml_ide_path)
+ add_ci_yml_path)
elsif repository.gitlab_ci_yml.present?
AnchorData.new(false,
statistic_icon('doc-text') + _('CI/CD configuration'),
@@ -393,6 +407,10 @@ class ProjectPresenter < Gitlab::View::Presenter::Delegated
def anonymous_project_view
if !project.empty_repo? && can?(current_user, :download_code, project)
'files'
+ elsif project.wiki_repository_exists? && can?(current_user, :read_wiki, project)
+ 'wiki'
+ elsif can?(current_user, :read_issue, project)
+ 'projects/issues/issues'
else
'activity'
end
diff --git a/app/presenters/projects/prometheus/alert_presenter.rb b/app/presenters/projects/prometheus/alert_presenter.rb
deleted file mode 100644
index 783b2b2b1e0..00000000000
--- a/app/presenters/projects/prometheus/alert_presenter.rb
+++ /dev/null
@@ -1,179 +0,0 @@
-# frozen_string_literal: true
-
-module Projects
- module Prometheus
- class AlertPresenter < Gitlab::View::Presenter::Delegated
- GENERIC_ALERT_SUMMARY_ANNOTATIONS = %w(monitoring_tool service hosts).freeze
- MARKDOWN_LINE_BREAK = " \n".freeze
- INCIDENT_LABEL_NAME = ::IncidentManagement::CreateIncidentLabelService::LABEL_PROPERTIES[:title].freeze
- METRIC_TIME_WINDOW = 30.minutes
-
- def full_title
- [environment_name, alert_title].compact.join(': ')
- end
-
- def project_full_path
- project.full_path
- end
-
- def metric_query
- gitlab_alert&.full_query
- end
-
- def environment_name
- environment&.name
- end
-
- def performance_dashboard_link
- if environment
- metrics_project_environment_url(project, environment)
- else
- metrics_project_environments_url(project)
- end
- end
-
- def show_performance_dashboard_link?
- gitlab_alert.present?
- end
-
- def show_incident_issues_link?
- project.incident_management_setting&.create_issue?
- end
-
- def incident_issues_link
- project_issues_url(project, label_name: INCIDENT_LABEL_NAME)
- end
-
- def start_time
- starts_at&.strftime('%d %B %Y, %-l:%M%p (%Z)')
- end
-
- def issue_summary_markdown
- <<~MARKDOWN.chomp
- #{metadata_list}
- #{metric_embed_for_alert}
- MARKDOWN
- end
-
- def metric_embed_for_alert
- "\n[](#{metrics_dashboard_url})" if metrics_dashboard_url
- end
-
- def metrics_dashboard_url
- strong_memoize(:metrics_dashboard_url) do
- embed_url_for_gitlab_alert || embed_url_for_self_managed_alert
- end
- end
-
- def details_url
- return unless am_alert
-
- ::Gitlab::Routing.url_helpers.details_project_alert_management_url(
- project,
- am_alert.iid
- )
- end
-
- private
-
- def alert_title
- query_title || title
- end
-
- def query_title
- return unless gitlab_alert
-
- "#{gitlab_alert.title} #{gitlab_alert.computed_operator} #{gitlab_alert.threshold} for 5 minutes"
- end
-
- def metadata_list
- metadata = []
-
- metadata << list_item('Start time', start_time) if start_time
- metadata << list_item('full_query', backtick(full_query)) if full_query
- metadata << list_item(service.label.humanize, service.value) if service
- metadata << list_item(monitoring_tool.label.humanize, monitoring_tool.value) if monitoring_tool
- metadata << list_item(hosts.label.humanize, host_links) if hosts
- metadata << list_item('GitLab alert', details_url) if details_url
-
- metadata.join(MARKDOWN_LINE_BREAK)
- end
-
- def details
- Gitlab::Utils::InlineHash.merge_keys(payload)
- end
-
- def list_item(key, value)
- "**#{key}:** #{value}".strip
- end
-
- def backtick(value)
- "`#{value}`"
- end
-
- GENERIC_ALERT_SUMMARY_ANNOTATIONS.each do |annotation_name|
- define_method(annotation_name) do
- annotations.find { |a| a.label == annotation_name }
- end
- end
-
- def host_links
- Array(hosts.value).join(' ')
- end
-
- def embed_url_for_gitlab_alert
- return unless gitlab_alert
-
- metrics_dashboard_project_prometheus_alert_url(
- project,
- gitlab_alert.prometheus_metric_id,
- environment_id: environment.id,
- embedded: true,
- **alert_embed_window_params(embed_time)
- )
- end
-
- def embed_url_for_self_managed_alert
- return unless environment && full_query && title
-
- metrics_dashboard_project_environment_url(
- project,
- environment,
- embed_json: dashboard_for_self_managed_alert.to_json,
- embedded: true,
- **alert_embed_window_params(embed_time)
- )
- end
-
- def embed_time
- starts_at || Time.current
- end
-
- def alert_embed_window_params(time)
- {
- start: format_embed_timestamp(time - METRIC_TIME_WINDOW),
- end: format_embed_timestamp(time + METRIC_TIME_WINDOW)
- }
- end
-
- def format_embed_timestamp(time)
- time.utc.strftime('%FT%TZ')
- end
-
- def dashboard_for_self_managed_alert
- {
- panel_groups: [{
- panels: [{
- type: 'area-chart',
- title: title,
- y_label: y_label,
- metrics: [{
- query_range: full_query
- }]
- }]
- }]
- }
- end
- end
- end
-end
diff --git a/app/presenters/release_presenter.rb b/app/presenters/release_presenter.rb
index 4393ca05f48..c27059c6d63 100644
--- a/app/presenters/release_presenter.rb
+++ b/app/presenters/release_presenter.rb
@@ -20,8 +20,6 @@ class ReleasePresenter < Gitlab::View::Presenter::Delegated
end
def self_url
- return unless ::Feature.enabled?(:release_show_page, project, default_enabled: true)
-
project_release_url(project, release)
end
diff --git a/app/presenters/sentry_error_presenter.rb b/app/presenters/sentry_error_presenter.rb
index ba724b0f8be..669bcb68b7c 100644
--- a/app/presenters/sentry_error_presenter.rb
+++ b/app/presenters/sentry_error_presenter.rb
@@ -14,7 +14,7 @@ class SentryErrorPresenter < Gitlab::View::Presenter::Delegated
end
def project_id
- Gitlab::GlobalId.build(model_name: 'Project', id: error.project_id).to_s
+ Gitlab::GlobalId.build(model_name: 'SentryProject', id: error.project_id).to_s
end
def frequency
diff --git a/app/presenters/snippet_blob_presenter.rb b/app/presenters/snippet_blob_presenter.rb
index abe95f5c44d..597ef6ebc39 100644
--- a/app/presenters/snippet_blob_presenter.rb
+++ b/app/presenters/snippet_blob_presenter.rb
@@ -25,10 +25,6 @@ class SnippetBlobPresenter < BlobPresenter
private
- def snippet_multiple_files?
- blob.container.repository_exists? && Feature.enabled?(:snippet_multiple_files, current_user)
- end
-
def snippet
blob.container
end
@@ -52,8 +48,8 @@ class SnippetBlobPresenter < BlobPresenter
end
def snippet_blob_raw_route(only_path: false)
- return gitlab_raw_snippet_blob_url(snippet, blob.path, only_path: only_path) if snippet_multiple_files?
+ return gitlab_raw_snippet_url(snippet, only_path: only_path) unless snippet.repository_exists?
- gitlab_raw_snippet_url(snippet, only_path: only_path)
+ gitlab_raw_snippet_blob_url(snippet, blob.path, only_path: only_path)
end
end
diff --git a/app/presenters/snippet_presenter.rb b/app/presenters/snippet_presenter.rb
index d814c4404b6..695aa266e2c 100644
--- a/app/presenters/snippet_presenter.rb
+++ b/app/presenters/snippet_presenter.rb
@@ -32,15 +32,9 @@ class SnippetPresenter < Gitlab::View::Presenter::Delegated
end
def blob
- blobs.first
- end
+ return snippet.blob if snippet.empty_repo?
- def blobs
- if snippet.empty_repo?
- [snippet.blob]
- else
- snippet.blobs
- end
+ blobs.first
end
private
diff --git a/app/serializers/README.md b/app/serializers/README.md
index 2cbe6f9d263..89721f572e0 100644
--- a/app/serializers/README.md
+++ b/app/serializers/README.md
@@ -47,11 +47,11 @@ representation. It rarely happens that a serialization entity exists without
a corresponding domain model class. As an example, we have an `Issue` class and
a corresponding `IssueSerializer`.
-Serialization entites are designed to reuse other serialization entities, which
+Serialization entities are designed to reuse other serialization entities, which
is a convenient way to create a multi-level JSON representation of a piece of
a domain model you want to serialize.
-See [documentation for Grape Entites][grape-entity-readme] for more details.
+See [documentation for Grape Entities][grape-entity-readme] for more details.
## How to implement a serializer?
diff --git a/app/serializers/build_details_entity.rb b/app/serializers/build_details_entity.rb
index 2b8522539b4..109213ab729 100644
--- a/app/serializers/build_details_entity.rb
+++ b/app/serializers/build_details_entity.rb
@@ -35,7 +35,7 @@ class BuildDetailsEntity < JobEntity
browse_project_job_artifacts_path(project, build)
end
- expose :keep_path, if: -> (*) { (build.locked_artifacts? || build.has_expiring_archive_artifacts?) && can?(current_user, :update_build, build) } do |build|
+ expose :keep_path, if: -> (*) { (build.has_expired_locked_archive_artifacts? || build.has_expiring_archive_artifacts?) && can?(current_user, :update_build, build) } do |build|
keep_project_job_artifacts_path(project, build)
end
@@ -133,7 +133,7 @@ class BuildDetailsEntity < JobEntity
def callout_message
return super unless build.failure_reason.to_sym == :missing_dependency_failure
- docs_url = "https://docs.gitlab.com/ce/ci/yaml/README.html#dependencies"
+ docs_url = "https://docs.gitlab.com/ee/ci/yaml/README.html#dependencies"
[
failure_message.html_safe,
diff --git a/app/serializers/ci/trigger_entity.rb b/app/serializers/ci/trigger_entity.rb
new file mode 100644
index 00000000000..005a9b752ed
--- /dev/null
+++ b/app/serializers/ci/trigger_entity.rb
@@ -0,0 +1,42 @@
+# frozen_string_literal: true
+
+module Ci
+ class TriggerEntity < Grape::Entity
+ include Gitlab::Routing
+ include Gitlab::Allowable
+
+ expose :description
+ expose :owner, using: UserEntity
+ expose :last_used
+
+ expose :token do |trigger|
+ can_admin_trigger?(trigger) ? trigger.token : trigger.short_token
+ end
+
+ expose :has_token_exposed do |trigger|
+ can_admin_trigger?(trigger)
+ end
+
+ expose :can_access_project do |trigger|
+ trigger.can_access_project?
+ end
+
+ expose :project_trigger_path, if: -> (trigger) { can_manage_trigger?(trigger) } do |trigger|
+ project_trigger_path(options[:project], trigger)
+ end
+
+ expose :edit_project_trigger_path, if: -> (trigger) { can_admin_trigger?(trigger) } do |trigger|
+ edit_project_trigger_path(options[:project], trigger)
+ end
+
+ private
+
+ def can_manage_trigger?(trigger)
+ can?(options[:current_user], :manage_trigger, trigger)
+ end
+
+ def can_admin_trigger?(trigger)
+ can?(options[:current_user], :admin_trigger, trigger)
+ end
+ end
+end
diff --git a/app/serializers/ci/trigger_serializer.rb b/app/serializers/ci/trigger_serializer.rb
new file mode 100644
index 00000000000..8e42ec12c3f
--- /dev/null
+++ b/app/serializers/ci/trigger_serializer.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+module Ci
+ class TriggerSerializer < BaseSerializer
+ entity ::Ci::TriggerEntity
+ end
+end
diff --git a/app/serializers/cluster_entity.rb b/app/serializers/cluster_entity.rb
index eea0acdc11b..b904666971e 100644
--- a/app/serializers/cluster_entity.rb
+++ b/app/serializers/cluster_entity.rb
@@ -6,6 +6,8 @@ class ClusterEntity < Grape::Entity
expose :cluster_type
expose :enabled
expose :environment_scope
+ expose :id
+ expose :namespace_per_environment
expose :name
expose :nodes
expose :provider_type
diff --git a/app/serializers/cluster_serializer.rb b/app/serializers/cluster_serializer.rb
index 700a46040e3..f71591612a6 100644
--- a/app/serializers/cluster_serializer.rb
+++ b/app/serializers/cluster_serializer.rb
@@ -12,6 +12,7 @@ class ClusterSerializer < BaseSerializer
:environment_scope,
:gitlab_managed_apps_logs_path,
:enable_advanced_logs_querying,
+ :id,
:kubernetes_errors,
:name,
:nodes,
diff --git a/app/serializers/container_repository_entity.rb b/app/serializers/container_repository_entity.rb
index 4c87d1438b0..9a002971bef 100644
--- a/app/serializers/container_repository_entity.rb
+++ b/app/serializers/container_repository_entity.rb
@@ -4,6 +4,7 @@ class ContainerRepositoryEntity < Grape::Entity
include RequestAwareEntity
expose :id, :name, :path, :location, :created_at, :status, :tags_count
+ expose :expiration_policy_started_at, as: :cleanup_policy_started_at
expose :tags_path do |repository|
project_registry_repository_tags_path(project, repository, format: :json)
diff --git a/app/serializers/deployment_entity.rb b/app/serializers/deployment_entity.rb
index dc7c4654208..a37011d0100 100644
--- a/app/serializers/deployment_entity.rb
+++ b/app/serializers/deployment_entity.rb
@@ -17,6 +17,7 @@ class DeploymentEntity < Grape::Entity
end
end
+ expose :status
expose :created_at
expose :deployed_at
expose :tag
diff --git a/app/serializers/diff_file_base_entity.rb b/app/serializers/diff_file_base_entity.rb
index 9f27191c3c8..596f5d686da 100644
--- a/app/serializers/diff_file_base_entity.rb
+++ b/app/serializers/diff_file_base_entity.rb
@@ -34,7 +34,7 @@ class DiffFileBaseEntity < Grape::Entity
expose :edit_path, if: -> (_, options) { options[:merge_request] } do |diff_file|
merge_request = options[:merge_request]
- next unless merge_request.merged? || merge_request.source_branch_exists?
+ next unless has_edit_path?(merge_request)
target_project, target_branch = edit_project_branch_options(merge_request)
@@ -43,6 +43,14 @@ class DiffFileBaseEntity < Grape::Entity
project_edit_blob_path(target_project, tree_join(target_branch, diff_file.new_path), options)
end
+ expose :ide_edit_path, if: -> (_, options) { options[:merge_request] } do |diff_file|
+ merge_request = options[:merge_request]
+
+ next unless has_edit_path?(merge_request)
+
+ gitlab_ide_merge_request_path(merge_request)
+ end
+
expose :old_path_html do |diff_file|
old_path, _ = mark_inline_diffs(diff_file.old_path, diff_file.new_path)
old_path
@@ -125,4 +133,8 @@ class DiffFileBaseEntity < Grape::Entity
[merge_request.target_project, merge_request.target_branch]
end
end
+
+ def has_edit_path?(merge_request)
+ merge_request.merged? || merge_request.source_branch_exists?
+ end
end
diff --git a/app/serializers/diffs_entity.rb b/app/serializers/diffs_entity.rb
index 6ef524b5bec..0b4f21c55f4 100644
--- a/app/serializers/diffs_entity.rb
+++ b/app/serializers/diffs_entity.rb
@@ -78,7 +78,7 @@ class DiffsEntity < Grape::Entity
options[:merge_request_diffs]
end
- expose :definition_path_prefix, if: -> (diff_file) { Feature.enabled?(:code_navigation, merge_request.project, default_enabled: true) } do |diffs|
+ expose :definition_path_prefix do |diffs|
project_blob_path(merge_request.project, diffs.diff_refs&.head_sha)
end
@@ -89,8 +89,6 @@ class DiffsEntity < Grape::Entity
private
def code_navigation_path(diffs)
- return unless Feature.enabled?(:code_navigation, merge_request.project, default_enabled: true)
-
Gitlab::CodeNavigationPath.new(merge_request.project, diffs.diff_refs&.head_sha)
end
diff --git a/app/serializers/discussion_entity.rb b/app/serializers/discussion_entity.rb
index 2957205a81c..497471699b2 100644
--- a/app/serializers/discussion_entity.rb
+++ b/app/serializers/discussion_entity.rb
@@ -69,9 +69,6 @@ class DiscussionEntity < Grape::Entity
end
def display_merge_ref_discussions?(discussion)
- return unless discussion.diff_discussion?
- return if discussion.legacy_diff_discussion?
-
- Feature.enabled?(:merge_ref_head_comments, discussion.project, default_enabled: true)
+ discussion.diff_discussion? && !discussion.legacy_diff_discussion?
end
end
diff --git a/app/serializers/feature_flag_entity.rb b/app/serializers/feature_flag_entity.rb
new file mode 100644
index 00000000000..80cf869a389
--- /dev/null
+++ b/app/serializers/feature_flag_entity.rb
@@ -0,0 +1,48 @@
+# frozen_string_literal: true
+
+class FeatureFlagEntity < Grape::Entity
+ include RequestAwareEntity
+
+ expose :id
+ expose :iid
+ expose :active
+ expose :created_at
+ expose :updated_at
+ expose :name
+ expose :description
+ expose :version
+
+ expose :edit_path, if: -> (feature_flag, _) { can_update?(feature_flag) } do |feature_flag|
+ edit_project_feature_flag_path(feature_flag.project, feature_flag)
+ end
+
+ expose :update_path, if: -> (feature_flag, _) { can_update?(feature_flag) } do |feature_flag|
+ project_feature_flag_path(feature_flag.project, feature_flag)
+ end
+
+ expose :destroy_path, if: -> (feature_flag, _) { can_destroy?(feature_flag) } do |feature_flag|
+ project_feature_flag_path(feature_flag.project, feature_flag)
+ end
+
+ expose :scopes, with: FeatureFlagScopeEntity do |feature_flag|
+ feature_flag.scopes.sort_by(&:id)
+ end
+
+ expose :strategies, with: FeatureFlags::StrategyEntity do |feature_flag|
+ feature_flag.strategies.sort_by(&:id)
+ end
+
+ private
+
+ def can_update?(feature_flag)
+ can?(current_user, :update_feature_flag, feature_flag)
+ end
+
+ def can_destroy?(feature_flag)
+ can?(current_user, :destroy_feature_flag, feature_flag)
+ end
+
+ def current_user
+ request.current_user
+ end
+end
diff --git a/app/serializers/feature_flag_scope_entity.rb b/app/serializers/feature_flag_scope_entity.rb
new file mode 100644
index 00000000000..0450797a545
--- /dev/null
+++ b/app/serializers/feature_flag_scope_entity.rb
@@ -0,0 +1,12 @@
+# frozen_string_literal: true
+
+class FeatureFlagScopeEntity < Grape::Entity
+ include RequestAwareEntity
+
+ expose :id
+ expose :active
+ expose :environment_scope
+ expose :created_at
+ expose :updated_at
+ expose :strategies
+end
diff --git a/app/serializers/feature_flag_serializer.rb b/app/serializers/feature_flag_serializer.rb
new file mode 100644
index 00000000000..e0ff33cc61a
--- /dev/null
+++ b/app/serializers/feature_flag_serializer.rb
@@ -0,0 +1,10 @@
+# frozen_string_literal: true
+
+class FeatureFlagSerializer < BaseSerializer
+ include WithPagination
+ entity FeatureFlagEntity
+
+ def represent(resource, opts = {})
+ super(resource, opts)
+ end
+end
diff --git a/app/serializers/feature_flag_summary_entity.rb b/app/serializers/feature_flag_summary_entity.rb
new file mode 100644
index 00000000000..be4f02dabca
--- /dev/null
+++ b/app/serializers/feature_flag_summary_entity.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+class FeatureFlagSummaryEntity < Grape::Entity
+ include RequestAwareEntity
+
+ expose :count do
+ expose :all do |project|
+ project.operations_feature_flags.count
+ end
+
+ expose :enabled do |project|
+ project.operations_feature_flags.enabled.count
+ end
+
+ expose :disabled do |project|
+ project.operations_feature_flags.disabled.count
+ end
+ end
+end
diff --git a/app/serializers/feature_flag_summary_serializer.rb b/app/serializers/feature_flag_summary_serializer.rb
new file mode 100644
index 00000000000..46f70666e40
--- /dev/null
+++ b/app/serializers/feature_flag_summary_serializer.rb
@@ -0,0 +1,5 @@
+# frozen_string_literal: true
+
+class FeatureFlagSummarySerializer < BaseSerializer
+ entity FeatureFlagSummaryEntity
+end
diff --git a/app/serializers/feature_flags/scope_entity.rb b/app/serializers/feature_flags/scope_entity.rb
new file mode 100644
index 00000000000..1c9dd491652
--- /dev/null
+++ b/app/serializers/feature_flags/scope_entity.rb
@@ -0,0 +1,8 @@
+# frozen_string_literal: true
+
+module FeatureFlags
+ class ScopeEntity < Grape::Entity
+ expose :id
+ expose :environment_scope
+ end
+end
diff --git a/app/serializers/feature_flags/strategy_entity.rb b/app/serializers/feature_flags/strategy_entity.rb
new file mode 100644
index 00000000000..73450476869
--- /dev/null
+++ b/app/serializers/feature_flags/strategy_entity.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+module FeatureFlags
+ class StrategyEntity < Grape::Entity
+ expose :id
+ expose :name
+ expose :parameters
+ expose :scopes, with: FeatureFlags::ScopeEntity
+ expose :user_list, with: FeatureFlags::UserListEntity, expose_nil: false
+ end
+end
diff --git a/app/serializers/feature_flags/user_list_entity.rb b/app/serializers/feature_flags/user_list_entity.rb
new file mode 100644
index 00000000000..d3fddb4fa7a
--- /dev/null
+++ b/app/serializers/feature_flags/user_list_entity.rb
@@ -0,0 +1,10 @@
+# frozen_string_literal: true
+
+module FeatureFlags
+ class UserListEntity < Grape::Entity
+ expose :id
+ expose :iid
+ expose :name
+ expose :user_xids
+ end
+end
diff --git a/app/serializers/feature_flags_client_entity.rb b/app/serializers/feature_flags_client_entity.rb
new file mode 100644
index 00000000000..4a195c7d759
--- /dev/null
+++ b/app/serializers/feature_flags_client_entity.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+class FeatureFlagsClientEntity < Grape::Entity
+ include RequestAwareEntity
+
+ expose :token
+end
diff --git a/app/serializers/feature_flags_client_serializer.rb b/app/serializers/feature_flags_client_serializer.rb
new file mode 100644
index 00000000000..104729b6668
--- /dev/null
+++ b/app/serializers/feature_flags_client_serializer.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+class FeatureFlagsClientSerializer < BaseSerializer
+ entity FeatureFlagsClientEntity
+
+ def represent_token(resource, opts = {})
+ represent(resource, only: [:token])
+ end
+end
diff --git a/app/serializers/group_group_link_entity.rb b/app/serializers/group_group_link_entity.rb
index 7a51e1a9316..1e736214f54 100644
--- a/app/serializers/group_group_link_entity.rb
+++ b/app/serializers/group_group_link_entity.rb
@@ -1,17 +1,31 @@
# frozen_string_literal: true
class GroupGroupLinkEntity < Grape::Entity
+ include RequestAwareEntity
+
expose :id
expose :created_at
expose :expires_at do |group_link|
group_link.expires_at&.to_time
end
+ expose :can_update do |group_link|
+ can_manage?(group_link)
+ end
+
+ expose :can_remove do |group_link|
+ can_manage?(group_link)
+ end
+
expose :access_level do
expose :human_access, as: :string_value
expose :group_access, as: :integer_value
end
+ expose :valid_roles do |group_link|
+ group_link.class.access_options
+ end
+
expose :shared_with_group do
expose :avatar_url do |group_link|
group_link.shared_with_group.avatar_url(only_path: false)
@@ -23,4 +37,14 @@ class GroupGroupLinkEntity < Grape::Entity
expose :shared_with_group, merge: true, using: GroupBasicEntity
end
+
+ private
+
+ def current_user
+ options[:current_user]
+ end
+
+ def can_manage?(group_link)
+ can?(current_user, :admin_group_member, group_link.shared_group)
+ end
end
diff --git a/app/serializers/import/bulk_import_entity.rb b/app/serializers/import/bulk_import_entity.rb
new file mode 100644
index 00000000000..8f0a9dd4428
--- /dev/null
+++ b/app/serializers/import/bulk_import_entity.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class Import::BulkImportEntity < Grape::Entity
+ expose :id do |entity|
+ entity['id']
+ end
+
+ expose :full_name do |entity|
+ entity['full_name']
+ end
+
+ expose :full_path do |entity|
+ entity['full_path']
+ end
+end
diff --git a/app/serializers/label_entity.rb b/app/serializers/label_entity.rb
index 5082245dda9..e586d7f8407 100644
--- a/app/serializers/label_entity.rb
+++ b/app/serializers/label_entity.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
class LabelEntity < Grape::Entity
- expose :id, if: ->(label, _) { !label.is_a?(GlobalLabel) }
+ expose :id
expose :title
expose :color
diff --git a/app/serializers/label_serializer.rb b/app/serializers/label_serializer.rb
index 25b9f7de243..b09592da67f 100644
--- a/app/serializers/label_serializer.rb
+++ b/app/serializers/label_serializer.rb
@@ -4,6 +4,6 @@ class LabelSerializer < BaseSerializer
entity LabelEntity
def represent_appearance(resource)
- represent(resource, { only: [:id, :title, :color, :text_color] })
+ represent(resource, { only: [:id, :title, :color, :text_color, :project_id] })
end
end
diff --git a/app/serializers/merge_request_basic_entity.rb b/app/serializers/merge_request_basic_entity.rb
index ef1177e9967..9e2bce53c8a 100644
--- a/app/serializers/merge_request_basic_entity.rb
+++ b/app/serializers/merge_request_basic_entity.rb
@@ -1,6 +1,7 @@
# frozen_string_literal: true
class MergeRequestBasicEntity < Grape::Entity
+ expose :title
expose :public_merge_status, as: :merge_status
expose :merge_error
expose :state
diff --git a/app/serializers/merge_request_poll_cached_widget_entity.rb b/app/serializers/merge_request_poll_cached_widget_entity.rb
index 002be8be729..080b6554de1 100644
--- a/app/serializers/merge_request_poll_cached_widget_entity.rb
+++ b/app/serializers/merge_request_poll_cached_widget_entity.rb
@@ -15,7 +15,7 @@ class MergeRequestPollCachedWidgetEntity < IssuableEntity
expose :target_project_id
expose :squash
expose :rebase_in_progress?, as: :rebase_in_progress
- expose :default_squash_commit_message, if: -> (merge_request, _) { merge_request.mergeable? }
+ expose :default_squash_commit_message
expose :commits_count
expose :merge_ongoing?, as: :merge_ongoing
expose :work_in_progress?, as: :work_in_progress
@@ -25,10 +25,10 @@ class MergeRequestPollCachedWidgetEntity < IssuableEntity
expose :source_branch_exists?, as: :source_branch_exists
expose :branch_missing?, as: :branch_missing
- expose :commits_without_merge_commits, using: MergeRequestWidgetCommitEntity,
- if: -> (merge_request, _) { merge_request.mergeable? } do |merge_request|
+ expose :commits_without_merge_commits, using: MergeRequestWidgetCommitEntity do |merge_request|
merge_request.recent_commits.without_merge_commits
end
+
expose :diff_head_sha do |merge_request|
merge_request.diff_head_sha.presence
end
@@ -46,6 +46,12 @@ class MergeRequestPollCachedWidgetEntity < IssuableEntity
end
end
+ expose :actual_head_pipeline, as: :pipeline, if: -> (mr, _) {
+ Feature.enabled?(:merge_request_cached_pipeline_serializer, mr.project) && presenter(mr).can_read_pipeline?
+ } do |merge_request, options|
+ MergeRequests::PipelineEntity.represent(merge_request.actual_head_pipeline, options)
+ end
+
# Paths
#
expose :target_branch_commits_path do |merge_request|
diff --git a/app/serializers/merge_request_poll_widget_entity.rb b/app/serializers/merge_request_poll_widget_entity.rb
index 41ab5005091..9609a894e6d 100644
--- a/app/serializers/merge_request_poll_widget_entity.rb
+++ b/app/serializers/merge_request_poll_widget_entity.rb
@@ -19,20 +19,14 @@ class MergeRequestPollWidgetEntity < Grape::Entity
# User entities
expose :merge_user, using: UserEntity
- expose :actual_head_pipeline, as: :pipeline, if: -> (mr, _) { presenter(mr).can_read_pipeline? } do |merge_request, options|
- if Feature.enabled?(:merge_request_short_pipeline_serializer, merge_request.project, default_enabled: true)
- MergeRequests::PipelineEntity.represent(merge_request.actual_head_pipeline, options)
- else
- PipelineDetailsEntity.represent(merge_request.actual_head_pipeline, options)
- end
+ expose :actual_head_pipeline, as: :pipeline, if: -> (mr, _) {
+ Feature.disabled?(:merge_request_cached_pipeline_serializer, mr.project) && presenter(mr).can_read_pipeline?
+ } do |merge_request, options|
+ MergeRequests::PipelineEntity.represent(merge_request.actual_head_pipeline, options)
end
expose :merge_pipeline, if: ->(mr, _) { mr.merged? && can?(request.current_user, :read_pipeline, mr.target_project)} do |merge_request, options|
- if Feature.enabled?(:merge_request_short_pipeline_serializer, merge_request.project, default_enabled: true)
- MergeRequests::PipelineEntity.represent(merge_request.merge_pipeline, options)
- else
- PipelineDetailsEntity.represent(merge_request.merge_pipeline, options)
- end
+ MergeRequests::PipelineEntity.represent(merge_request.merge_pipeline, options)
end
expose :default_merge_commit_message
diff --git a/app/serializers/merge_request_widget_entity.rb b/app/serializers/merge_request_widget_entity.rb
index 494192c8dbb..44cbcfc5044 100644
--- a/app/serializers/merge_request_widget_entity.rb
+++ b/app/serializers/merge_request_widget_entity.rb
@@ -67,15 +67,15 @@ class MergeRequestWidgetEntity < Grape::Entity
)
end
- expose :user_callouts_path, if: -> (*) { Feature.enabled?(:suggest_pipeline) } do |merge_request|
+ expose :user_callouts_path, if: -> (_, opts) { opts[:experiment_enabled] == :suggest_pipeline } do |_merge_request|
user_callouts_path
end
- expose :suggest_pipeline_feature_id, if: -> (*) { Feature.enabled?(:suggest_pipeline) } do |merge_request|
+ expose :suggest_pipeline_feature_id, if: -> (_, opts) { opts[:experiment_enabled] == :suggest_pipeline } do |_merge_request|
SUGGEST_PIPELINE
end
- expose :is_dismissed_suggest_pipeline, if: -> (*) { Feature.enabled?(:suggest_pipeline) } do |merge_request|
+ expose :is_dismissed_suggest_pipeline, if: -> (_, opts) { opts[:experiment_enabled] == :suggest_pipeline } do |_merge_request|
current_user && current_user.dismissed_callout?(feature_name: SUGGEST_PIPELINE)
end
@@ -120,10 +120,18 @@ class MergeRequestWidgetEntity < Grape::Entity
end
expose :base_path do |merge_request|
- base_pipeline_downloadable_path_for_report_type(:codequality)
+ if use_merge_base_with_merged_results?
+ merge_base_pipeline_downloadable_path_for_report_type(:codequality)
+ else
+ base_pipeline_downloadable_path_for_report_type(:codequality)
+ end
end
end
+ expose :security_reports_docs_path do |merge_request|
+ help_page_path('user/application_security/sast/index.md', anchor: 'reports-json-format')
+ end
+
private
delegate :current_user, to: :request
@@ -152,6 +160,16 @@ class MergeRequestWidgetEntity < Grape::Entity
object.base_pipeline&.present(current_user: current_user)
&.downloadable_path_for_report_type(file_type)
end
+
+ def use_merge_base_with_merged_results?
+ Feature.enabled?(:merge_base_pipelines, object.target_project) &&
+ object.actual_head_pipeline&.merge_request_event_type == :merged_result
+ end
+
+ def merge_base_pipeline_downloadable_path_for_report_type(file_type)
+ object.merge_base_pipeline&.present(current_user: current_user)
+ &.downloadable_path_for_report_type(file_type)
+ end
end
MergeRequestWidgetEntity.prepend_if_ee('EE::MergeRequestWidgetEntity')
diff --git a/app/serializers/paginated_diff_entity.rb b/app/serializers/paginated_diff_entity.rb
index 37c48338e55..f24571f7d7d 100644
--- a/app/serializers/paginated_diff_entity.rb
+++ b/app/serializers/paginated_diff_entity.rb
@@ -37,8 +37,6 @@ class PaginatedDiffEntity < Grape::Entity
private
def code_navigation_path(diffs)
- return unless Feature.enabled?(:code_navigation, merge_request.project, default_enabled: true)
-
Gitlab::CodeNavigationPath.new(merge_request.project, diffs.diff_refs&.head_sha)
end
diff --git a/app/serializers/pipeline_entity.rb b/app/serializers/pipeline_entity.rb
index 64958b06f1d..2d278f0e30d 100644
--- a/app/serializers/pipeline_entity.rb
+++ b/app/serializers/pipeline_entity.rb
@@ -82,7 +82,9 @@ class PipelineEntity < Grape::Entity
end
expose :failed_builds, if: -> (*) { can_retry? }, using: JobEntity do |pipeline|
- pipeline.failed_builds
+ pipeline.failed_builds.each do |build|
+ build.project = pipeline.project
+ end
end
private
diff --git a/app/serializers/pipeline_serializer.rb b/app/serializers/pipeline_serializer.rb
index 45c5a1d3e1c..a45214670fa 100644
--- a/app/serializers/pipeline_serializer.rb
+++ b/app/serializers/pipeline_serializer.rb
@@ -47,6 +47,7 @@ class PipelineSerializer < BaseSerializer
:retryable_builds,
:scheduled_actions,
:stages,
+ :latest_statuses,
:trigger_requests,
:user,
{
@@ -62,7 +63,14 @@ class PipelineSerializer < BaseSerializer
pending_builds: :project,
project: [:route, { namespace: :route }],
triggered_by_pipeline: [{ project: [:route, { namespace: :route }] }, :user],
- triggered_pipelines: [{ project: [:route, { namespace: :route }] }, :user, :source_job]
+ triggered_pipelines: [
+ {
+ project: [:route, { namespace: :route }]
+ },
+ :source_job,
+ :latest_statuses,
+ :user
+ ]
}
]
end
diff --git a/app/serializers/test_case_entity.rb b/app/serializers/test_case_entity.rb
index d2e08590ef0..b44aa62ad73 100644
--- a/app/serializers/test_case_entity.rb
+++ b/app/serializers/test_case_entity.rb
@@ -6,6 +6,7 @@ class TestCaseEntity < Grape::Entity
expose :status
expose :name
expose :classname
+ expose :file
expose :execution_time
expose :system_output
expose :stack_trace
diff --git a/app/services/admin/propagate_integration_service.rb b/app/services/admin/propagate_integration_service.rb
index 34d6008cb6a..96a6d861e47 100644
--- a/app/services/admin/propagate_integration_service.rb
+++ b/app/services/admin/propagate_integration_service.rb
@@ -7,66 +7,45 @@ module Admin
def propagate
update_inherited_integrations
- create_integration_for_groups_without_integration if Feature.enabled?(:group_level_integrations)
- create_integration_for_projects_without_integration
+ if integration.instance?
+ create_integration_for_groups_without_integration if Feature.enabled?(:group_level_integrations)
+ create_integration_for_projects_without_integration
+ else
+ create_integration_for_groups_without_integration_belonging_to_group
+ create_integration_for_projects_without_integration_belonging_to_group
+ end
end
private
# rubocop: disable Cop/InBatches
- # rubocop: disable CodeReuse/ActiveRecord
def update_inherited_integrations
- Service.where(type: integration.type, inherit_from_id: integration.id).in_batches(of: BATCH_SIZE) do |batch|
- bulk_update_from_integration(batch)
+ Service.by_type(integration.type).inherit_from_id(integration.id).in_batches(of: BATCH_SIZE) do |services|
+ min_id, max_id = services.pick("MIN(services.id), MAX(services.id)")
+ PropagateIntegrationInheritWorker.perform_async(integration.id, min_id, max_id)
end
end
# rubocop: enable Cop/InBatches
- # rubocop: enable CodeReuse/ActiveRecord
-
- # rubocop: disable CodeReuse/ActiveRecord
- def bulk_update_from_integration(batch)
- # Retrieving the IDs instantiates the ActiveRecord relation (batch)
- # into concrete models, otherwise update_all will clear the relation.
- # https://stackoverflow.com/q/34811646/462015
- batch_ids = batch.pluck(:id)
-
- Service.transaction do
- batch.update_all(service_hash)
-
- if data_fields_present?
- integration.data_fields.class.where(service_id: batch_ids).update_all(data_fields_hash)
- end
- end
- end
- # rubocop: enable CodeReuse/ActiveRecord
def create_integration_for_groups_without_integration
- loop do
- batch = Group.uncached { group_ids_without_integration(integration, BATCH_SIZE) }
-
- bulk_create_from_integration(batch, 'group') unless batch.empty?
-
- break if batch.size < BATCH_SIZE
+ Group.without_integration(integration).each_batch(of: BATCH_SIZE) do |groups|
+ min_id, max_id = groups.pick("MIN(namespaces.id), MAX(namespaces.id)")
+ PropagateIntegrationGroupWorker.perform_async(integration.id, min_id, max_id)
end
end
- def service_hash
- @service_hash ||= integration.to_service_hash
- .tap { |json| json['inherit_from_id'] = integration.id }
+ def create_integration_for_groups_without_integration_belonging_to_group
+ integration.group.descendants.without_integration(integration).each_batch(of: BATCH_SIZE) do |groups|
+ min_id, max_id = groups.pick("MIN(namespaces.id), MAX(namespaces.id)")
+ PropagateIntegrationGroupWorker.perform_async(integration.id, min_id, max_id)
+ end
end
- # rubocop:disable CodeReuse/ActiveRecord
- def group_ids_without_integration(integration, limit)
- services = Service
- .select('1')
- .where('services.group_id = namespaces.id')
- .where(type: integration.type)
-
- Group
- .where('NOT EXISTS (?)', services)
- .limit(limit)
- .pluck(:id)
+ def create_integration_for_projects_without_integration_belonging_to_group
+ Project.without_integration(integration).in_namespace(integration.group.self_and_descendants).each_batch(of: BATCH_SIZE) do |projects|
+ min_id, max_id = projects.pick("MIN(projects.id), MAX(projects.id)")
+ PropagateIntegrationProjectWorker.perform_async(integration.id, min_id, max_id)
+ end
end
- # rubocop:enable CodeReuse/ActiveRecord
end
end
diff --git a/app/services/admin/propagate_service_template.rb b/app/services/admin/propagate_service_template.rb
index cd0d2d5d03f..07be3c1027d 100644
--- a/app/services/admin/propagate_service_template.rb
+++ b/app/services/admin/propagate_service_template.rb
@@ -9,11 +9,5 @@ module Admin
create_integration_for_projects_without_integration
end
-
- private
-
- def service_hash
- @service_hash ||= integration.to_service_hash
- end
end
end
diff --git a/app/services/alert_management/alerts/update_service.rb b/app/services/alert_management/alerts/update_service.rb
index 18d615aa7e7..464d5f2ecea 100644
--- a/app/services/alert_management/alerts/update_service.rb
+++ b/app/services/alert_management/alerts/update_service.rb
@@ -13,6 +13,7 @@ module AlertManagement
@current_user = current_user
@params = params
@param_errors = []
+ @status = params.delete(:status)
end
def execute
@@ -35,7 +36,7 @@ module AlertManagement
private
- attr_reader :alert, :current_user, :params, :param_errors
+ attr_reader :alert, :current_user, :params, :param_errors, :status
delegate :resolved?, to: :alert
def allowed?
@@ -68,8 +69,12 @@ module AlertManagement
param_errors << message
end
+ def param_errors?
+ params.empty? && status.blank?
+ end
+
def filter_params
- param_errors << _('Please provide attributes to update') if params.empty?
+ param_errors << _('Please provide attributes to update') if param_errors?
filter_status
filter_assignees
@@ -110,9 +115,9 @@ module AlertManagement
# ------ Status-related behavior -------
def filter_status
- return unless params[:status]
+ return unless status
- status_event = AlertManagement::Alert::STATUS_EVENTS[status_key]
+ status_event = alert.status_event_for(status)
unless status_event
param_errors << _('Invalid status')
@@ -122,13 +127,6 @@ module AlertManagement
params[:status_event] = status_event
end
- def status_key
- strong_memoize(:status_key) do
- status = params.delete(:status)
- AlertManagement::Alert::STATUSES.key(status)
- end
- end
-
def handle_status_change
add_status_change_system_note
resolve_todos if resolved?
@@ -144,7 +142,7 @@ module AlertManagement
def filter_duplicate
# Only need to check if changing to an open status
- return unless params[:status_event] && AlertManagement::Alert::OPEN_STATUSES.include?(status_key)
+ return unless params[:status_event] && AlertManagement::Alert.open_status?(status)
param_errors << unresolved_alert_error if duplicate_alert?
end
diff --git a/app/services/alert_management/process_prometheus_alert_service.rb b/app/services/alert_management/process_prometheus_alert_service.rb
index 95ae84a85a4..5c7698f724a 100644
--- a/app/services/alert_management/process_prometheus_alert_service.rb
+++ b/app/services/alert_management/process_prometheus_alert_service.rb
@@ -47,7 +47,7 @@ module AlertManagement
def create_alert_management_alert
if alert.save
alert.execute_services
- SystemNoteService.create_new_alert(alert, Gitlab::AlertManagement::AlertParams::MONITORING_TOOLS[:prometheus])
+ SystemNoteService.create_new_alert(alert, Gitlab::AlertManagement::Payload::MONITORING_TOOLS[:prometheus])
return
end
diff --git a/app/services/audit_event_service.rb b/app/services/audit_event_service.rb
index d7630dbdac9..3c21844ec62 100644
--- a/app/services/audit_event_service.rb
+++ b/app/services/audit_event_service.rb
@@ -53,7 +53,6 @@ class AuditEventService
private
- attr_accessor :authentication_event
attr_reader :ip_address
def build_author(author)
@@ -99,23 +98,35 @@ class AuditEventService
end
def mark_as_authentication_event!
- self.authentication_event = true
+ @authentication_event = true
end
def authentication_event?
- authentication_event
+ @authentication_event
end
def log_security_event_to_database
return if Gitlab::Database.read_only?
- AuditEvent.create(base_payload.merge(details: @details))
+ event = AuditEvent.new(base_payload.merge(details: @details))
+ save_or_track event
+
+ event
end
def log_authentication_event_to_database
return unless Gitlab::Database.read_write? && authentication_event?
- AuthenticationEvent.create(authentication_event_payload)
+ event = AuthenticationEvent.new(authentication_event_payload)
+ save_or_track event
+
+ event
+ end
+
+ def save_or_track(event)
+ event.save!
+ rescue => e
+ Gitlab::ErrorTracking.track_exception(e, audit_event_type: event.class.to_s)
end
end
diff --git a/app/services/boards/create_service.rb b/app/services/boards/create_service.rb
index 1a5dc790c41..2ccaea64d14 100644
--- a/app/services/boards/create_service.rb
+++ b/app/services/boards/create_service.rb
@@ -3,7 +3,11 @@
module Boards
class CreateService < Boards::BaseService
def execute
- create_board! if can_create_board?
+ unless can_create_board?
+ return ServiceResponse.error(message: "You don't have the permission to create a board for this resource.")
+ end
+
+ create_board!
end
private
@@ -15,12 +19,16 @@ module Boards
def create_board!
board = parent.boards.create(params)
- if board.persisted?
- board.lists.create(list_type: :backlog)
- board.lists.create(list_type: :closed)
+ unless board.persisted?
+ return ServiceResponse.error(message: "There was an error when creating a board.", payload: board)
+ end
+
+ board.tap do |created_board|
+ created_board.lists.create(list_type: :backlog)
+ created_board.lists.create(list_type: :closed)
end
- board
+ ServiceResponse.success(payload: board)
end
end
end
diff --git a/app/services/boards/issues/list_service.rb b/app/services/boards/issues/list_service.rb
index 140420a32bd..ab9d11abe98 100644
--- a/app/services/boards/issues/list_service.rb
+++ b/app/services/boards/issues/list_service.rb
@@ -80,6 +80,7 @@ module Boards
set_scope
set_non_archived
set_attempt_search_optimizations
+ set_issue_types
params
end
@@ -116,6 +117,10 @@ module Boards
end
end
+ def set_issue_types
+ params[:issue_types] = Issue::TYPES_FOR_LIST
+ end
+
# rubocop: disable CodeReuse/ActiveRecord
def board_label_ids
@board_label_ids ||= board.lists.movable.pluck(:label_id)
diff --git a/app/services/boards/lists/destroy_service.rb b/app/services/boards/lists/destroy_service.rb
index e20805d0405..ebac0f07fe1 100644
--- a/app/services/boards/lists/destroy_service.rb
+++ b/app/services/boards/lists/destroy_service.rb
@@ -4,7 +4,9 @@ module Boards
module Lists
class DestroyService < Boards::BaseService
def execute(list)
- return false unless list.destroyable?
+ unless list.destroyable?
+ return ServiceResponse.error(message: "The list cannot be destroyed. Only label lists can be destroyed.")
+ end
@board = list.board
@@ -12,6 +14,8 @@ module Boards
decrement_higher_lists(list)
remove_list(list)
end
+
+ ServiceResponse.success
end
private
@@ -26,7 +30,7 @@ module Boards
# rubocop: enable CodeReuse/ActiveRecord
def remove_list(list)
- list.destroy
+ list.destroy!
end
end
end
diff --git a/app/services/bulk_create_integration_service.rb b/app/services/bulk_create_integration_service.rb
new file mode 100644
index 00000000000..23b89b0d8a9
--- /dev/null
+++ b/app/services/bulk_create_integration_service.rb
@@ -0,0 +1,59 @@
+# frozen_string_literal: true
+
+class BulkCreateIntegrationService
+ def initialize(integration, batch, association)
+ @integration = integration
+ @batch = batch
+ @association = association
+ end
+
+ def execute
+ service_list = ServiceList.new(batch, service_hash, association).to_array
+
+ Service.transaction do
+ results = bulk_insert(*service_list)
+
+ if integration.data_fields_present?
+ data_list = DataList.new(results, data_fields_hash, integration.data_fields.class).to_array
+
+ bulk_insert(*data_list)
+ end
+
+ run_callbacks(batch) if association == 'project'
+ end
+ end
+
+ private
+
+ attr_reader :integration, :batch, :association
+
+ def bulk_insert(klass, columns, values_array)
+ items_to_insert = values_array.map { |array| Hash[columns.zip(array)] }
+
+ klass.insert_all(items_to_insert, returning: [:id])
+ end
+
+ # rubocop: disable CodeReuse/ActiveRecord
+ def run_callbacks(batch)
+ if integration.issue_tracker?
+ Project.where(id: batch.select(:id)).update_all(has_external_issue_tracker: true)
+ end
+
+ if integration.type == 'ExternalWikiService'
+ Project.where(id: batch.select(:id)).update_all(has_external_wiki: true)
+ end
+ end
+ # rubocop: enable CodeReuse/ActiveRecord
+
+ def service_hash
+ if integration.template?
+ integration.to_service_hash
+ else
+ integration.to_service_hash.tap { |json| json['inherit_from_id'] = integration.id }
+ end
+ end
+
+ def data_fields_hash
+ integration.to_data_fields_hash
+ end
+end
diff --git a/app/services/bulk_update_integration_service.rb b/app/services/bulk_update_integration_service.rb
new file mode 100644
index 00000000000..74d77618f2c
--- /dev/null
+++ b/app/services/bulk_update_integration_service.rb
@@ -0,0 +1,32 @@
+# frozen_string_literal: true
+
+class BulkUpdateIntegrationService
+ def initialize(integration, batch)
+ @integration = integration
+ @batch = batch
+ end
+
+ # rubocop: disable CodeReuse/ActiveRecord
+ def execute
+ Service.transaction do
+ batch.update_all(service_hash)
+
+ if integration.data_fields_present?
+ integration.data_fields.class.where(service_id: batch.select(:id)).update_all(data_fields_hash)
+ end
+ end
+ end
+ # rubocop: enable CodeReuse/ActiveRecord
+
+ private
+
+ attr_reader :integration, :batch
+
+ def service_hash
+ integration.to_service_hash.tap { |json| json['inherit_from_id'] = integration.id }
+ end
+
+ def data_fields_hash
+ integration.to_data_fields_hash
+ end
+end
diff --git a/app/services/ci/archive_trace_service.rb b/app/services/ci/archive_trace_service.rb
index 073ef465e13..9b2c7788897 100644
--- a/app/services/ci/archive_trace_service.rb
+++ b/app/services/ci/archive_trace_service.rb
@@ -27,7 +27,7 @@ module Ci
rescue => e
# Tracks this error with application logs, Sentry, and Prometheus.
# If `archive!` keeps failing for over a week, that could incur data loss.
- # (See more https://docs.gitlab.com/ee/administration/job_traces.html#new-live-trace-architecture)
+ # (See more https://docs.gitlab.com/ee/administration/job_logs.html#new-incremental-logging-architecture)
# In order to avoid interrupting the system, we do not raise an exception here.
archive_error(e, job, worker_name)
end
diff --git a/app/services/ci/build_report_result_service.rb b/app/services/ci/build_report_result_service.rb
index ca66ad8249d..76ecf428f11 100644
--- a/app/services/ci/build_report_result_service.rb
+++ b/app/services/ci/build_report_result_service.rb
@@ -2,12 +2,20 @@
module Ci
class BuildReportResultService
+ include Gitlab::Utils::UsageData
+
+ EVENT_NAME = 'i_testing_test_case_parsed'
+
def execute(build)
return unless build.has_test_reports?
+ test_suite = generate_test_suite_report(build)
+
+ track_test_cases(build, test_suite)
+
build.report_results.create!(
project_id: build.project_id,
- data: tests_params(build)
+ data: tests_params(test_suite)
)
end
@@ -17,9 +25,7 @@ module Ci
build.collect_test_reports!(Gitlab::Ci::Reports::TestReports.new)
end
- def tests_params(build)
- test_suite = generate_test_suite_report(build)
-
+ def tests_params(test_suite)
{
tests: {
name: test_suite.name,
@@ -31,5 +37,20 @@ module Ci
}
}
end
+
+ def track_test_cases(build, test_suite)
+ return if Feature.disabled?(:track_unique_test_cases_parsed, build.project)
+
+ track_usage_event(EVENT_NAME, test_case_hashes(build, test_suite))
+ end
+
+ def test_case_hashes(build, test_suite)
+ [].tap do |hashes|
+ test_suite.each_test_case do |test_case|
+ key = "#{build.project_id}-#{test_case.key}"
+ hashes << Digest::SHA256.hexdigest(key)
+ end
+ end
+ end
end
end
diff --git a/app/services/ci/create_downstream_pipeline_service.rb b/app/services/ci/create_downstream_pipeline_service.rb
index 0394cfb6119..86d0cf079fc 100644
--- a/app/services/ci/create_downstream_pipeline_service.rb
+++ b/app/services/ci/create_downstream_pipeline_service.rb
@@ -33,7 +33,7 @@ module Ci
pipeline_params.fetch(:target_revision))
downstream_pipeline = service.execute(
- pipeline_params.fetch(:source), pipeline_params[:execute_params]) do |pipeline|
+ pipeline_params.fetch(:source), **pipeline_params[:execute_params]) do |pipeline|
pipeline.variables.build(@bridge.downstream_variables)
end
@@ -77,16 +77,9 @@ module Ci
# TODO: Remove this condition if favour of model validation
# https://gitlab.com/gitlab-org/gitlab/issues/38338
- if ::Gitlab::Ci::Features.child_of_child_pipeline_enabled?(project)
- if has_max_descendants_depth?
- @bridge.drop!(:reached_max_descendant_pipelines_depth)
- return false
- end
- else
- if @bridge.triggers_child_pipeline? && @bridge.pipeline.parent_pipeline.present?
- @bridge.drop!(:bridge_pipeline_is_child_pipeline)
- return false
- end
+ if has_max_descendants_depth?
+ @bridge.drop!(:reached_max_descendant_pipelines_depth)
+ return false
end
unless can_create_downstream_pipeline?(target_ref)
diff --git a/app/services/ci/create_job_artifacts_service.rb b/app/services/ci/create_job_artifacts_service.rb
index 1fe65898d55..5efb3805bf7 100644
--- a/app/services/ci/create_job_artifacts_service.rb
+++ b/app/services/ci/create_job_artifacts_service.rb
@@ -52,24 +52,15 @@ module Ci
attr_reader :job, :project
def validate_requirements(artifact_type:, filesize:)
- return forbidden_type_error(artifact_type) if forbidden_type?(artifact_type)
return too_large_error if too_large?(artifact_type, filesize)
success
end
- def forbidden_type?(type)
- lsif?(type) && !code_navigation_enabled?
- end
-
def too_large?(type, size)
size > max_size(type) if size
end
- def code_navigation_enabled?
- Feature.enabled?(:code_navigation, project, default_enabled: true)
- end
-
def lsif?(type)
type == LSIF_ARTIFACT_TYPE
end
diff --git a/app/services/ci/create_pipeline_service.rb b/app/services/ci/create_pipeline_service.rb
index 70ad18e80eb..e7ede98fea4 100644
--- a/app/services/ci/create_pipeline_service.rb
+++ b/app/services/ci/create_pipeline_service.rb
@@ -70,7 +70,7 @@ module Ci
push_options: params[:push_options] || {},
chat_data: params[:chat_data],
bridge: bridge,
- **extra_options(options))
+ **extra_options(**options))
# Ensure we never persist the pipeline when dry_run: true
@pipeline.readonly! if command.dry_run?
@@ -82,8 +82,7 @@ module Ci
schedule_head_pipeline_update if pipeline.persisted?
# If pipeline is not persisted, try to recover IID
- pipeline.reset_project_iid unless pipeline.persisted? ||
- Feature.disabled?(:ci_pipeline_rewind_iid, project, default_enabled: true)
+ pipeline.reset_project_iid unless pipeline.persisted?
pipeline
end
diff --git a/app/services/ci/daily_build_group_report_result_service.rb b/app/services/ci/daily_build_group_report_result_service.rb
index 6cdf3c88f8c..c32fc27c274 100644
--- a/app/services/ci/daily_build_group_report_result_service.rb
+++ b/app/services/ci/daily_build_group_report_result_service.rb
@@ -3,8 +3,6 @@
module Ci
class DailyBuildGroupReportResultService
def execute(pipeline)
- return unless Feature.enabled?(:ci_daily_code_coverage, pipeline.project, default_enabled: true)
-
DailyBuildGroupReportResult.upsert_reports(coverage_reports(pipeline))
end
diff --git a/app/services/ci/delete_objects_service.rb b/app/services/ci/delete_objects_service.rb
new file mode 100644
index 00000000000..bac99abadc9
--- /dev/null
+++ b/app/services/ci/delete_objects_service.rb
@@ -0,0 +1,62 @@
+# frozen_string_literal: true
+
+module Ci
+ class DeleteObjectsService
+ TransactionInProgressError = Class.new(StandardError)
+ TRANSACTION_MESSAGE = "can't perform network calls inside a database transaction"
+ BATCH_SIZE = 100
+ RETRY_IN = 10.minutes
+
+ def execute
+ objects = load_next_batch
+ destroy_everything(objects)
+ end
+
+ def remaining_batches_count(max_batch_count:)
+ Ci::DeletedObject
+ .ready_for_destruction(max_batch_count * BATCH_SIZE)
+ .size
+ .fdiv(BATCH_SIZE)
+ .ceil
+ end
+
+ private
+
+ # rubocop: disable CodeReuse/ActiveRecord
+ def load_next_batch
+ # `find_by_sql` performs a write in this case and we need to wrap it in
+ # a transaction to stick to the primary database.
+ Ci::DeletedObject.transaction do
+ Ci::DeletedObject.find_by_sql([
+ next_batch_sql, new_pick_up_at: RETRY_IN.from_now
+ ])
+ end
+ end
+ # rubocop: enable CodeReuse/ActiveRecord
+
+ def next_batch_sql
+ <<~SQL.squish
+ UPDATE "ci_deleted_objects"
+ SET "pick_up_at" = :new_pick_up_at
+ WHERE "ci_deleted_objects"."id" IN (#{locked_object_ids_sql})
+ RETURNING *
+ SQL
+ end
+
+ def locked_object_ids_sql
+ Ci::DeletedObject.lock_for_destruction(BATCH_SIZE).to_sql
+ end
+
+ def destroy_everything(objects)
+ raise TransactionInProgressError, TRANSACTION_MESSAGE if transaction_open?
+ return unless objects.any?
+
+ deleted = objects.select(&:delete_file_from_storage)
+ Ci::DeletedObject.id_in(deleted.map(&:id)).delete_all
+ end
+
+ def transaction_open?
+ Ci::DeletedObject.connection.transaction_open?
+ end
+ end
+end
diff --git a/app/services/ci/destroy_expired_job_artifacts_service.rb b/app/services/ci/destroy_expired_job_artifacts_service.rb
index ca6e60f819a..438b5c7496d 100644
--- a/app/services/ci/destroy_expired_job_artifacts_service.rb
+++ b/app/services/ci/destroy_expired_job_artifacts_service.rb
@@ -39,6 +39,13 @@ module Ci
return false if artifacts.empty?
artifacts.each(&:destroy!)
+ run_after_destroy(artifacts)
+
+ true # This is required because of the design of `loop_until` method.
end
+
+ def run_after_destroy(artifacts); end
end
end
+
+Ci::DestroyExpiredJobArtifactsService.prepend_if_ee('EE::Ci::DestroyExpiredJobArtifactsService')
diff --git a/app/services/ci/expire_pipeline_cache_service.rb b/app/services/ci/expire_pipeline_cache_service.rb
index 32abd1a7626..8343e0f8cd0 100644
--- a/app/services/ci/expire_pipeline_cache_service.rb
+++ b/app/services/ci/expire_pipeline_cache_service.rb
@@ -32,11 +32,18 @@ module Ci
Gitlab::Routing.url_helpers.project_new_merge_request_path(project, format: :json)
end
+ def pipelines_project_merge_request_path(merge_request)
+ Gitlab::Routing.url_helpers.pipelines_project_merge_request_path(merge_request.target_project, merge_request, format: :json)
+ end
+
+ def merge_request_widget_path(merge_request)
+ Gitlab::Routing.url_helpers.cached_widget_project_json_merge_request_path(merge_request.project, merge_request, format: :json)
+ end
+
def each_pipelines_merge_request_path(pipeline)
pipeline.all_merge_requests.each do |merge_request|
- path = Gitlab::Routing.url_helpers.pipelines_project_merge_request_path(merge_request.target_project, merge_request, format: :json)
-
- yield(path)
+ yield(pipelines_project_merge_request_path(merge_request))
+ yield(merge_request_widget_path(merge_request))
end
end
diff --git a/app/services/ci/list_config_variables_service.rb b/app/services/ci/list_config_variables_service.rb
new file mode 100644
index 00000000000..b5dc192b512
--- /dev/null
+++ b/app/services/ci/list_config_variables_service.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+module Ci
+ class ListConfigVariablesService < ::BaseService
+ def execute(sha)
+ config = project.ci_config_for(sha)
+ return {} unless config
+
+ result = Gitlab::Ci::YamlProcessor.new(config).execute
+ result.valid? ? result.variables_with_data : {}
+ end
+ end
+end
diff --git a/app/services/ci/pipelines/create_artifact_service.rb b/app/services/ci/pipelines/create_artifact_service.rb
index b7d334e436d..bfaf317241a 100644
--- a/app/services/ci/pipelines/create_artifact_service.rb
+++ b/app/services/ci/pipelines/create_artifact_service.rb
@@ -3,7 +3,6 @@ module Ci
module Pipelines
class CreateArtifactService
def execute(pipeline)
- return unless ::Gitlab::Ci::Features.coverage_report_view?(pipeline.project)
return unless pipeline.can_generate_coverage_reports?
return if pipeline.has_coverage_reports?
diff --git a/app/services/ci/play_bridge_service.rb b/app/services/ci/play_bridge_service.rb
new file mode 100644
index 00000000000..70c4a8e6136
--- /dev/null
+++ b/app/services/ci/play_bridge_service.rb
@@ -0,0 +1,14 @@
+# frozen_string_literal: true
+
+module Ci
+ class PlayBridgeService < ::BaseService
+ def execute(bridge)
+ raise Gitlab::Access::AccessDeniedError unless can?(current_user, :play_job, bridge)
+
+ bridge.tap do |bridge|
+ bridge.user = current_user
+ bridge.enqueue!
+ end
+ end
+ end
+end
diff --git a/app/services/ci/play_build_service.rb b/app/services/ci/play_build_service.rb
index 9f922ffde81..6adeca624a8 100644
--- a/app/services/ci/play_build_service.rb
+++ b/app/services/ci/play_build_service.rb
@@ -3,9 +3,7 @@
module Ci
class PlayBuildService < ::BaseService
def execute(build, job_variables_attributes = nil)
- unless can?(current_user, :update_build, build)
- raise Gitlab::Access::AccessDeniedError
- end
+ raise Gitlab::Access::AccessDeniedError unless can?(current_user, :play_job, build)
# Try to enqueue the build, otherwise create a duplicate.
#
diff --git a/app/services/ci/play_manual_stage_service.rb b/app/services/ci/play_manual_stage_service.rb
index 2497fc52e6b..c6fa7803e52 100644
--- a/app/services/ci/play_manual_stage_service.rb
+++ b/app/services/ci/play_manual_stage_service.rb
@@ -9,12 +9,12 @@ module Ci
end
def execute(stage)
- stage.builds.manual.each do |build|
- next unless build.playable?
+ stage.processables.manual.each do |processable|
+ next unless processable.playable?
- build.play(current_user)
+ processable.play(current_user)
rescue Gitlab::Access::AccessDeniedError
- logger.error(message: 'Unable to play manual action', build_id: build.id)
+ logger.error(message: 'Unable to play manual action', processable_id: processable.id)
end
end
diff --git a/app/services/ci/process_pipeline_service.rb b/app/services/ci/process_pipeline_service.rb
index 18bae26613f..e511e26adfe 100644
--- a/app/services/ci/process_pipeline_service.rb
+++ b/app/services/ci/process_pipeline_service.rb
@@ -31,14 +31,14 @@ module Ci
# rubocop: disable CodeReuse/ActiveRecord
def update_retried
# find the latest builds for each name
- latest_statuses = pipeline.statuses.latest
+ latest_statuses = pipeline.latest_statuses
.group(:name)
.having('count(*) > 1')
.pluck(Arel.sql('MAX(id)'), 'name')
# mark builds that are retried
if latest_statuses.any?
- pipeline.statuses.latest
+ pipeline.latest_statuses
.where(name: latest_statuses.map(&:second))
.where.not(id: latest_statuses.map(&:first))
.update_all(retried: true)
diff --git a/app/services/ci/retry_build_service.rb b/app/services/ci/retry_build_service.rb
index 6b2e6c245f3..f397ada0696 100644
--- a/app/services/ci/retry_build_service.rb
+++ b/app/services/ci/retry_build_service.rb
@@ -58,7 +58,7 @@ module Ci
build = project.builds.new(attributes)
build.assign_attributes(::Gitlab::Ci::Pipeline::Seed::Build.environment_attributes_for(build))
build.retried = false
- BulkInsertableAssociations.with_bulk_insert(enabled: ::Gitlab::Ci::Features.bulk_insert_on_create?(project)) do
+ BulkInsertableAssociations.with_bulk_insert do
build.save!
end
build
diff --git a/app/services/ci/update_build_queue_service.rb b/app/services/ci/update_build_queue_service.rb
index 31c7178c9e7..241eba733ea 100644
--- a/app/services/ci/update_build_queue_service.rb
+++ b/app/services/ci/update_build_queue_service.rb
@@ -9,9 +9,7 @@ module Ci
private
def tick_for(build, runners)
- if Feature.enabled?(:ci_update_queues_for_online_runners, build.project, default_enabled: true)
- runners = runners.with_recent_runner_queue
- end
+ runners = runners.with_recent_runner_queue
runners.each do |runner|
runner.pick_build!(build)
diff --git a/app/services/ci/update_build_state_service.rb b/app/services/ci/update_build_state_service.rb
index 61e4c77c1e5..22a27906700 100644
--- a/app/services/ci/update_build_state_service.rb
+++ b/app/services/ci/update_build_state_service.rb
@@ -2,7 +2,11 @@
module Ci
class UpdateBuildStateService
- Result = Struct.new(:status, keyword_init: true)
+ include ::Gitlab::Utils::StrongMemoize
+ include ::Gitlab::ExclusiveLeaseHelpers
+
+ Result = Struct.new(:status, :backoff, keyword_init: true)
+ InvalidTraceError = Class.new(StandardError)
ACCEPT_TIMEOUT = 5.minutes.freeze
@@ -17,43 +21,77 @@ module Ci
def execute
overwrite_trace! if has_trace?
- if accept_request?
- accept_build_state!
- else
- check_migration_state
- update_build_state!
+ unless accept_available?
+ return update_build_state!
+ end
+
+ ensure_pending_state!
+
+ in_build_trace_lock do
+ process_build_state!
end
end
private
- def accept_build_state!
- if Time.current - ensure_pending_state.created_at > ACCEPT_TIMEOUT
- metrics.increment_trace_operation(operation: :discarded)
+ def overwrite_trace!
+ metrics.increment_trace_operation(operation: :overwrite)
- return update_build_state!
+ build.trace.set(params[:trace]) if Gitlab::Ci::Features.trace_overwrite?
+ end
+
+ def ensure_pending_state!
+ pending_state.created_at
+ end
+
+ def process_build_state!
+ if live_chunks_pending?
+ if pending_state_outdated?
+ discard_build_trace!
+ update_build_state!
+ else
+ accept_build_state!
+ end
+ else
+ validate_build_trace!
+ update_build_state!
end
+ end
+ def accept_build_state!
build.trace_chunks.live.find_each do |chunk|
chunk.schedule_to_persist!
end
metrics.increment_trace_operation(operation: :accepted)
- Result.new(status: 202)
+ ::Gitlab::Ci::Runner::Backoff.new(pending_state.created_at).then do |backoff|
+ Result.new(status: 202, backoff: backoff.to_seconds)
+ end
end
- def overwrite_trace!
- metrics.increment_trace_operation(operation: :overwrite)
+ def validate_build_trace!
+ return unless has_chunks?
- build.trace.set(params[:trace]) if Gitlab::Ci::Features.trace_overwrite?
- end
+ unless live_chunks_pending?
+ metrics.increment_trace_operation(operation: :finalized)
+ metrics.observe_migration_duration(pending_state_seconds)
+ end
- def check_migration_state
- return unless accept_available?
+ ::Gitlab::Ci::Trace::Checksum.new(build).then do |checksum|
+ unless checksum.valid?
+ metrics.increment_trace_operation(operation: :invalid)
- if has_chunks? && !live_chunks_pending?
- metrics.increment_trace_operation(operation: :finalized)
+ next unless log_invalid_chunks?
+
+ ::Gitlab::ErrorTracking.log_exception(InvalidTraceError.new,
+ project_path: build.project.full_path,
+ build_id: build.id,
+ state_crc32: checksum.state_crc32,
+ chunks_crc32: checksum.chunks_crc32,
+ chunks_count: checksum.chunks_count
+ )
+ end
end
end
@@ -76,12 +114,32 @@ module Ci
end
end
+ def discard_build_trace!
+ metrics.increment_trace_operation(operation: :discarded)
+ end
+
def accept_available?
!build_running? && has_checksum? && chunks_migration_enabled?
end
- def accept_request?
- accept_available? && live_chunks_pending?
+ def live_chunks_pending?
+ build.trace_chunks.live.any?
+ end
+
+ def has_chunks?
+ build.trace_chunks.any?
+ end
+
+ def pending_state_outdated?
+ pending_state_duration > ACCEPT_TIMEOUT
+ end
+
+ def pending_state_duration
+ Time.current - pending_state.created_at
+ end
+
+ def pending_state_seconds
+ pending_state_duration.seconds
end
def build_state
@@ -96,18 +154,14 @@ module Ci
params.dig(:checksum).present?
end
- def has_chunks?
- build.trace_chunks.any?
- end
-
- def live_chunks_pending?
- build.trace_chunks.live.any?
- end
-
def build_running?
build_state == 'running'
end
+ def pending_state
+ strong_memoize(:pending_state) { ensure_pending_state }
+ end
+
def ensure_pending_state
Ci::BuildPendingState.create_or_find_by!(
build_id: build.id,
@@ -121,8 +175,38 @@ module Ci
build.pending_state
end
+ ##
+ # This method is releasing an exclusive lock on a build trace the moment we
+ # conclude that build status has been written and the build state update
+ # has been committed to the database.
+ #
+ # Because a build state machine schedules a bunch of workers to run after
+ # build status transition to complete, we do not want to keep the lease
+ # until all the workers are scheduled because it opens a possibility of
+ # race conditions happening.
+ #
+ # Instead of keeping the lease until the transition is fully done and
+ # workers are scheduled, we immediately release the lock after the database
+ # commit happens.
+ #
+ def in_build_trace_lock(&block)
+ build.trace.lock do |_, lease| # rubocop:disable CodeReuse/ActiveRecord
+ build.run_on_status_commit { lease.cancel }
+
+ yield
+ end
+ rescue ::Gitlab::Ci::Trace::LockedError
+ metrics.increment_trace_operation(operation: :locked)
+
+ accept_build_state!
+ end
+
def chunks_migration_enabled?
::Gitlab::Ci::Features.accept_trace?(build.project)
end
+
+ def log_invalid_chunks?
+ ::Gitlab::Ci::Features.log_invalid_trace_chunks?(build.project)
+ end
end
end
diff --git a/app/services/clusters/kubernetes/create_or_update_service_account_service.rb b/app/services/clusters/kubernetes/create_or_update_service_account_service.rb
index b1820474c9d..2725a3aeaa5 100644
--- a/app/services/clusters/kubernetes/create_or_update_service_account_service.rb
+++ b/app/services/clusters/kubernetes/create_or_update_service_account_service.rb
@@ -117,9 +117,11 @@ module Clusters
end
def role_binding_resource
+ role_name = Feature.enabled?(:kubernetes_cluster_namespace_role_admin) ? 'admin' : Clusters::Kubernetes::PROJECT_CLUSTER_ROLE_NAME
+
Gitlab::Kubernetes::RoleBinding.new(
name: role_binding_name,
- role_name: Clusters::Kubernetes::PROJECT_CLUSTER_ROLE_NAME,
+ role_name: role_name,
role_kind: :ClusterRole,
namespace: service_account_namespace,
service_account_name: service_account_name
diff --git a/app/services/concerns/admin/propagate_service.rb b/app/services/concerns/admin/propagate_service.rb
index 974408f678c..065ab6f7ff9 100644
--- a/app/services/concerns/admin/propagate_service.rb
+++ b/app/services/concerns/admin/propagate_service.rb
@@ -4,9 +4,7 @@ module Admin
module PropagateService
extend ActiveSupport::Concern
- BATCH_SIZE = 100
-
- delegate :data_fields_present?, to: :integration
+ BATCH_SIZE = 10_000
class_methods do
def propagate(integration)
@@ -23,51 +21,10 @@ module Admin
attr_reader :integration
def create_integration_for_projects_without_integration
- loop do
- batch_ids = Project.uncached { Project.ids_without_integration(integration, BATCH_SIZE) }
-
- bulk_create_from_integration(batch_ids, 'project') unless batch_ids.empty?
-
- break if batch_ids.size < BATCH_SIZE
- end
- end
-
- def bulk_create_from_integration(batch_ids, association)
- service_list = ServiceList.new(batch_ids, service_hash, association).to_array
-
- Service.transaction do
- results = bulk_insert(*service_list)
-
- if data_fields_present?
- data_list = DataList.new(results, data_fields_hash, integration.data_fields.class).to_array
-
- bulk_insert(*data_list)
- end
-
- run_callbacks(batch_ids) if association == 'project'
+ Project.without_integration(integration).each_batch(of: BATCH_SIZE) do |projects|
+ min_id, max_id = projects.pick("MIN(projects.id), MAX(projects.id)")
+ PropagateIntegrationProjectWorker.perform_async(integration.id, min_id, max_id)
end
end
-
- def bulk_insert(klass, columns, values_array)
- items_to_insert = values_array.map { |array| Hash[columns.zip(array)] }
-
- klass.insert_all(items_to_insert, returning: [:id])
- end
-
- # rubocop: disable CodeReuse/ActiveRecord
- def run_callbacks(batch_ids)
- if integration.issue_tracker?
- Project.where(id: batch_ids).update_all(has_external_issue_tracker: true)
- end
-
- if integration.type == 'ExternalWikiService'
- Project.where(id: batch_ids).update_all(has_external_wiki: true)
- end
- end
- # rubocop: enable CodeReuse/ActiveRecord
-
- def data_fields_hash
- @data_fields_hash ||= integration.to_data_fields_hash
- end
end
end
diff --git a/app/services/deployments/after_create_service.rb b/app/services/deployments/after_create_service.rb
deleted file mode 100644
index 3560f9c983b..00000000000
--- a/app/services/deployments/after_create_service.rb
+++ /dev/null
@@ -1,67 +0,0 @@
-# frozen_string_literal: true
-
-module Deployments
- class AfterCreateService
- attr_reader :deployment
- attr_reader :deployable
-
- delegate :environment, to: :deployment
- delegate :variables, to: :deployable
- delegate :options, to: :deployable, allow_nil: true
-
- def initialize(deployment)
- @deployment = deployment
- @deployable = deployment.deployable
- end
-
- def execute
- deployment.create_ref
- deployment.invalidate_cache
-
- update_environment(deployment)
-
- deployment
- end
-
- def update_environment(deployment)
- ActiveRecord::Base.transaction do
- if (url = expanded_environment_url)
- environment.external_url = url
- end
-
- renew_auto_stop_in
- environment.fire_state_event(action)
-
- if environment.save && !environment.stopped?
- deployment.update_merge_request_metrics!
- end
- end
- end
-
- private
-
- def environment_options
- options&.dig(:environment) || {}
- end
-
- def expanded_environment_url
- ExpandVariables.expand(environment_url, -> { variables }) if environment_url
- end
-
- def environment_url
- environment_options[:url]
- end
-
- def action
- environment_options[:action] || 'start'
- end
-
- def renew_auto_stop_in
- return unless deployable
-
- environment.auto_stop_in = deployable.environment_auto_stop_in
- end
- end
-end
-
-Deployments::AfterCreateService.prepend_if_ee('EE::Deployments::AfterCreateService')
diff --git a/app/services/deployments/update_environment_service.rb b/app/services/deployments/update_environment_service.rb
new file mode 100644
index 00000000000..e9c2f41f626
--- /dev/null
+++ b/app/services/deployments/update_environment_service.rb
@@ -0,0 +1,67 @@
+# frozen_string_literal: true
+
+module Deployments
+ class UpdateEnvironmentService
+ attr_reader :deployment
+ attr_reader :deployable
+
+ delegate :environment, to: :deployment
+ delegate :variables, to: :deployable
+ delegate :options, to: :deployable, allow_nil: true
+
+ def initialize(deployment)
+ @deployment = deployment
+ @deployable = deployment.deployable
+ end
+
+ def execute
+ deployment.create_ref
+ deployment.invalidate_cache
+
+ update_environment(deployment)
+
+ deployment
+ end
+
+ def update_environment(deployment)
+ ActiveRecord::Base.transaction do
+ if (url = expanded_environment_url)
+ environment.external_url = url
+ end
+
+ renew_auto_stop_in
+ environment.fire_state_event(action)
+
+ if environment.save && !environment.stopped?
+ deployment.update_merge_request_metrics!
+ end
+ end
+ end
+
+ private
+
+ def environment_options
+ options&.dig(:environment) || {}
+ end
+
+ def expanded_environment_url
+ ExpandVariables.expand(environment_url, -> { variables }) if environment_url
+ end
+
+ def environment_url
+ environment_options[:url]
+ end
+
+ def action
+ environment_options[:action] || 'start'
+ end
+
+ def renew_auto_stop_in
+ return unless deployable
+
+ environment.auto_stop_in = deployable.environment_auto_stop_in
+ end
+ end
+end
+
+Deployments::UpdateEnvironmentService.prepend_if_ee('EE::Deployments::UpdateEnvironmentService')
diff --git a/app/services/design_management/copy_design_collection.rb b/app/services/design_management/copy_design_collection.rb
new file mode 100644
index 00000000000..66cf6112062
--- /dev/null
+++ b/app/services/design_management/copy_design_collection.rb
@@ -0,0 +1,6 @@
+# frozen_string_literal: true
+
+module DesignManagement
+ module CopyDesignCollection
+ end
+end
diff --git a/app/services/design_management/copy_design_collection/copy_service.rb b/app/services/design_management/copy_design_collection/copy_service.rb
new file mode 100644
index 00000000000..5099c2c5704
--- /dev/null
+++ b/app/services/design_management/copy_design_collection/copy_service.rb
@@ -0,0 +1,309 @@
+# frozen_string_literal: true
+
+# Service to copy a DesignCollection from one Issue to another.
+# Copies the DesignCollection's Designs, Versions, and Notes on Designs.
+module DesignManagement
+ module CopyDesignCollection
+ class CopyService < DesignService
+ # rubocop: disable CodeReuse/ActiveRecord
+ def initialize(project, user, params = {})
+ super
+
+ @target_issue = params.fetch(:target_issue)
+ @target_project = @target_issue.project
+ @target_repository = @target_project.design_repository
+ @target_design_collection = @target_issue.design_collection
+ @temporary_branch = "CopyDesignCollectionService_#{SecureRandom.hex}"
+ # The user who triggered the copy may not have permissions to push
+ # to the design repository.
+ @git_user = @target_project.default_owner
+
+ @designs = DesignManagement::Design.unscoped.where(issue: issue).order(:id).load
+ @versions = DesignManagement::Version.unscoped.where(issue: issue).order(:id).includes(:designs).load
+
+ @sha_attribute = Gitlab::Database::ShaAttribute.new
+ @shas = []
+ @event_enum_map = DesignManagement::DesignAction::EVENT_FOR_GITALY_ACTION.invert
+ end
+ # rubocop: enable CodeReuse/ActiveRecord
+
+ def execute
+ return error('User cannot copy design collection to issue') unless user_can_copy?
+ return error('Target design collection must first be queued') unless target_design_collection.copy_in_progress?
+ return error('Design collection has no designs') if designs.empty?
+ return error('Target design collection already has designs') unless target_design_collection.empty?
+
+ with_temporary_branch do
+ copy_commits!
+
+ ActiveRecord::Base.transaction do
+ design_ids = copy_designs!
+ version_ids = copy_versions!
+ copy_actions!(design_ids, version_ids)
+ link_lfs_files!
+ copy_notes!(design_ids)
+ finalize!
+ end
+ end
+
+ ServiceResponse.success
+ rescue => error
+ log_exception(error)
+
+ target_design_collection.error_copy!
+
+ error('Designs were unable to be copied successfully')
+ end
+
+ private
+
+ attr_reader :designs, :event_enum_map, :git_user, :sha_attribute, :shas,
+ :temporary_branch, :target_design_collection, :target_issue,
+ :target_repository, :target_project, :versions
+
+ alias_method :merge_branch, :target_branch
+
+ def log_exception(exception)
+ payload = {
+ issue_id: issue.id,
+ project_id: project.id,
+ target_issue_id: target_issue.id,
+ target_project: target_project.id
+ }
+
+ Gitlab::ErrorTracking.track_exception(exception, payload)
+ end
+
+ def error(message)
+ ServiceResponse.error(message: message)
+ end
+
+ def user_can_copy?
+ current_user.can?(:read_design, design_collection) &&
+ current_user.can?(:admin_issue, target_issue)
+ end
+
+ def with_temporary_branch(&block)
+ target_repository.create_if_not_exists
+
+ create_master_branch! if target_repository.empty?
+ create_temporary_branch!
+
+ yield
+ ensure
+ remove_temporary_branch!
+ end
+
+ # A project that does not have any designs will have a blank design
+ # repository. To create a temporary branch from `master` we need
+ # create `master` first by adding a file to it.
+ def create_master_branch!
+ target_repository.create_file(
+ git_user,
+ ".CopyDesignCollectionService_#{Time.now.to_i}",
+ '.gitlab',
+ message: "Commit to create #{merge_branch} branch in CopyDesignCollectionService",
+ branch_name: merge_branch
+ )
+ end
+
+ def create_temporary_branch!
+ target_repository.add_branch(
+ git_user,
+ temporary_branch,
+ target_repository.root_ref
+ )
+ end
+
+ def remove_temporary_branch!
+ return unless target_repository.branch_exists?(temporary_branch)
+
+ target_repository.rm_branch(git_user, temporary_branch)
+ end
+
+ # Merge the temporary branch containing the commits to `master`
+ # and update the state of the target_design_collection.
+ def finalize!
+ source_sha = shas.last
+
+ target_repository.raw.merge(
+ git_user,
+ source_sha,
+ merge_branch,
+ 'CopyDesignCollectionService finalize merge'
+ ) { nil }
+
+ target_design_collection.end_copy!
+ end
+
+ # rubocop: disable CodeReuse/ActiveRecord
+ def copy_commits!
+ # Execute another query to include actions and their designs
+ DesignManagement::Version.unscoped.where(id: versions).order(:id).includes(actions: :design).find_each(batch_size: 100) do |version|
+ gitaly_actions = version.actions.map do |action|
+ design = action.design
+ # Map the raw Action#event enum value to a Gitaly "action" for the
+ # `Repository#multi_action` call.
+ gitaly_action_name = @event_enum_map[action.event_before_type_cast]
+ # `content` will be the LfsPointer file and not the design file,
+ # and can be nil for deletions.
+ content = blobs.dig(version.sha, design.filename)&.data
+ file_path = DesignManagement::Design.build_full_path(target_issue, design)
+
+ {
+ action: gitaly_action_name,
+ file_path: file_path,
+ content: content
+ }.compact
+ end
+
+ sha = target_repository.multi_action(
+ git_user,
+ branch_name: temporary_branch,
+ message: commit_message(version),
+ actions: gitaly_actions
+ )
+
+ shas << sha
+ end
+ end
+ # rubocop: enable CodeReuse/ActiveRecord
+
+ def copy_designs!
+ design_attributes = attributes_config[:design_attributes]
+
+ new_rows = designs.map do |design|
+ design.attributes.slice(*design_attributes).merge(
+ issue_id: target_issue.id,
+ project_id: target_project.id
+ )
+ end
+
+ # TODO Replace `Gitlab::Database.bulk_insert` with `BulkInsertSafe`
+ # once https://gitlab.com/gitlab-org/gitlab/-/issues/247718 is fixed.
+ ::Gitlab::Database.bulk_insert( # rubocop:disable Gitlab/BulkInsert
+ DesignManagement::Design.table_name,
+ new_rows,
+ return_ids: true
+ )
+ end
+
+ def copy_versions!
+ version_attributes = attributes_config[:version_attributes]
+ # `shas` are the list of Git commits made during the Git copy phase,
+ # and will be ordered 1:1 with old versions
+ shas_enum = shas.to_enum
+
+ new_rows = versions.map do |version|
+ version.attributes.slice(*version_attributes).merge(
+ issue_id: target_issue.id,
+ sha: sha_attribute.serialize(shas_enum.next)
+ )
+ end
+
+ # TODO Replace `Gitlab::Database.bulk_insert` with `BulkInsertSafe`
+ # once https://gitlab.com/gitlab-org/gitlab/-/issues/247718 is fixed.
+ ::Gitlab::Database.bulk_insert( # rubocop:disable Gitlab/BulkInsert
+ DesignManagement::Version.table_name,
+ new_rows,
+ return_ids: true
+ )
+ end
+
+ # rubocop: disable CodeReuse/ActiveRecord
+ def copy_actions!(new_design_ids, new_version_ids)
+ # Create a map of <Old design id> => <New design id>
+ design_id_map = new_design_ids.each_with_index.to_h do |design_id, i|
+ [designs[i].id, design_id]
+ end
+
+ # Create a map of <Old version id> => <New version id>
+ version_id_map = new_version_ids.each_with_index.to_h do |version_id, i|
+ [versions[i].id, version_id]
+ end
+
+ actions = DesignManagement::Action.unscoped.select(:design_id, :version_id, :event).where(design: designs, version: versions)
+
+ new_rows = actions.map do |action|
+ {
+ design_id: design_id_map[action.design_id],
+ version_id: version_id_map[action.version_id],
+ event: action.event_before_type_cast
+ }
+ end
+
+ # We cannot use `BulkInsertSafe` because of the uploader mounted in `Action`.
+ ::Gitlab::Database.bulk_insert( # rubocop:disable Gitlab/BulkInsert
+ DesignManagement::Action.table_name,
+ new_rows
+ )
+ end
+ # rubocop: enable CodeReuse/ActiveRecord
+
+ def commit_message(version)
+ "Copy commit #{version.sha} from issue #{issue.to_reference(full: true)}"
+ end
+
+ # rubocop: disable CodeReuse/ActiveRecord
+ def copy_notes!(design_ids)
+ new_designs = DesignManagement::Design.unscoped.find(design_ids)
+
+ # Execute another query to filter only designs with notes
+ DesignManagement::Design.unscoped.where(id: designs).joins(:notes).distinct.find_each(batch_size: 100) do |old_design|
+ new_design = new_designs.find { |d| d.filename == old_design.filename }
+
+ Notes::CopyService.new(current_user, old_design, new_design).execute
+ end
+ end
+ # rubocop: enable CodeReuse/ActiveRecord
+
+ # rubocop: disable CodeReuse/ActiveRecord
+ def link_lfs_files!
+ oids = blobs.values.flat_map(&:values).map(&:lfs_oid)
+ repository_type = LfsObjectsProject.repository_types[:design]
+
+ new_rows = LfsObject.where(oid: oids).find_each(batch_size: 1000).map do |lfs_object|
+ {
+ project_id: target_project.id,
+ lfs_object_id: lfs_object.id,
+ repository_type: repository_type
+ }
+ end
+
+ # We cannot use `BulkInsertSafe` due to the LfsObjectsProject#update_project_statistics
+ # callback that fires after_commit.
+ ::Gitlab::Database.bulk_insert( # rubocop:disable Gitlab/BulkInsert
+ LfsObjectsProject.table_name,
+ new_rows,
+ on_conflict: :do_nothing # Upsert
+ )
+ end
+ # rubocop: enable CodeReuse/ActiveRecord
+
+ # Blob data is used to find the oids for LfsObjects and to copy to Git.
+ # Blobs are reasonably small in memory, as their data are LFS Pointer files.
+ #
+ # Returns all blobs for the designs as a Hash of `{ Blob#commit_id => { Design#filename => Blob } }`
+ def blobs
+ @blobs ||= begin
+ items = versions.flat_map { |v| v.designs.map { |d| [v.sha, DesignManagement::Design.build_full_path(issue, d)] } }
+
+ repository.blobs_at(items).each_with_object({}) do |blob, h|
+ design = designs.find { |d| DesignManagement::Design.build_full_path(issue, d) == blob.path }
+
+ h[blob.commit_id] ||= {}
+ h[blob.commit_id][design.filename] = blob
+ end
+ end
+ end
+
+ def attributes_config
+ @attributes_config ||= YAML.load_file(attributes_config_file).symbolize_keys
+ end
+
+ def attributes_config_file
+ Rails.root.join('lib/gitlab/design_management/copy_design_collection_model_attributes.yml')
+ end
+ end
+ end
+end
diff --git a/app/services/design_management/copy_design_collection/queue_service.rb b/app/services/design_management/copy_design_collection/queue_service.rb
new file mode 100644
index 00000000000..f76917dbe47
--- /dev/null
+++ b/app/services/design_management/copy_design_collection/queue_service.rb
@@ -0,0 +1,42 @@
+# frozen_string_literal: true
+
+# Service for setting the initial copy_state on the target DesignCollection
+# and queuing a CopyDesignCollectionWorker.
+module DesignManagement
+ module CopyDesignCollection
+ class QueueService
+ def initialize(current_user, issue, target_issue)
+ @current_user = current_user
+ @issue = issue
+ @target_issue = target_issue
+ @target_design_collection = target_issue.design_collection
+ end
+
+ def execute
+ return error('User cannot copy designs to issue') unless user_can_copy?
+ return error('Target design collection copy state must be `ready`') unless target_design_collection.can_start_copy?
+
+ target_design_collection.start_copy!
+
+ DesignManagement::CopyDesignCollectionWorker.perform_async(current_user.id, issue.id, target_issue.id)
+
+ ServiceResponse.success
+ end
+
+ private
+
+ delegate :design_collection, to: :issue
+
+ attr_reader :current_user, :issue, :target_design_collection, :target_issue
+
+ def error(message)
+ ServiceResponse.error(message: message)
+ end
+
+ def user_can_copy?
+ current_user.can?(:read_design, issue) &&
+ current_user.can?(:admin_issue, target_issue)
+ end
+ end
+ end
+end
diff --git a/app/services/design_management/delete_designs_service.rb b/app/services/design_management/delete_designs_service.rb
index 5d875c630a0..a90c34d4e34 100644
--- a/app/services/design_management/delete_designs_service.rb
+++ b/app/services/design_management/delete_designs_service.rb
@@ -16,6 +16,7 @@ module DesignManagement
version = delete_designs!
EventCreateService.new.destroy_designs(designs, current_user)
+ Gitlab::UsageDataCounters::IssueActivityUniqueCounter.track_issue_designs_removed_action(author: current_user)
success(version: version)
end
diff --git a/app/services/design_management/design_service.rb b/app/services/design_management/design_service.rb
index 54e53609646..5aa2a2f73bc 100644
--- a/app/services/design_management/design_service.rb
+++ b/app/services/design_management/design_service.rb
@@ -19,6 +19,7 @@ module DesignManagement
def collection
issue.design_collection
end
+ alias_method :design_collection, :collection
def repository
collection.repository
diff --git a/app/services/design_management/generate_image_versions_service.rb b/app/services/design_management/generate_image_versions_service.rb
index 213aac164ff..e56d163c461 100644
--- a/app/services/design_management/generate_image_versions_service.rb
+++ b/app/services/design_management/generate_image_versions_service.rb
@@ -48,6 +48,9 @@ module DesignManagement
# Store and process the file
action.image_v432x230.store!(raw_file)
action.save!
+ rescue CarrierWave::IntegrityError => e
+ Gitlab::ErrorTracking.log_exception(e, project_id: project.id, design_id: action.design_id, version_id: action.version_id)
+ log_error(e.message)
rescue CarrierWave::UploadError => e
Gitlab::ErrorTracking.track_exception(e, project_id: project.id, design_id: action.design_id, version_id: action.version_id)
log_error(e.message)
diff --git a/app/services/design_management/runs_design_actions.rb b/app/services/design_management/runs_design_actions.rb
index 4bd6bb45658..ee6aa9286d3 100644
--- a/app/services/design_management/runs_design_actions.rb
+++ b/app/services/design_management/runs_design_actions.rb
@@ -4,14 +4,15 @@ module DesignManagement
module RunsDesignActions
NoActions = Class.new(StandardError)
- # this concern requires the following methods to be implemented:
+ # This concern requires the following methods to be implemented:
# current_user, target_branch, repository, commit_message
#
# Before calling `run_actions`, you should ensure the repository exists, by
# calling `repository.create_if_not_exists`.
#
# @raise [NoActions] if actions are empty
- def run_actions(actions)
+ # @return [DesignManagement::Version]
+ def run_actions(actions, skip_system_notes: false)
raise NoActions if actions.empty?
sha = repository.multi_action(current_user,
@@ -21,14 +22,14 @@ module DesignManagement
::DesignManagement::Version
.create_for_designs(actions, sha, current_user)
- .tap { |version| post_process(version) }
+ .tap { |version| post_process(version, skip_system_notes) }
end
private
- def post_process(version)
+ def post_process(version, skip_system_notes)
version.run_after_commit_or_now do
- ::DesignManagement::NewVersionWorker.perform_async(id)
+ ::DesignManagement::NewVersionWorker.perform_async(id, skip_system_notes)
end
end
end
diff --git a/app/services/design_management/save_designs_service.rb b/app/services/design_management/save_designs_service.rb
index 0446d2f1ee8..c26d2e7ab47 100644
--- a/app/services/design_management/save_designs_service.rb
+++ b/app/services/design_management/save_designs_service.rb
@@ -16,11 +16,15 @@ module DesignManagement
def execute
return error("Not allowed!") unless can_create_designs?
return error("Only #{MAX_FILES} files are allowed simultaneously") if files.size > MAX_FILES
+ return error("Duplicate filenames are not allowed!") if files.map(&:original_filename).uniq.length != files.length
+ return error("Design copy is in progress") if design_collection.copy_in_progress?
uploaded_designs, version = upload_designs!
skipped_designs = designs - uploaded_designs
create_events
+ design_collection.reset_copy!
+
success({ designs: uploaded_designs, version: version, skipped_designs: skipped_designs })
rescue ::ActiveRecord::RecordInvalid => e
error(e.message)
@@ -34,7 +38,10 @@ module DesignManagement
::DesignManagement::Version.with_lock(project.id, repository) do
actions = build_actions
- [actions.map(&:design), actions.presence && run_actions(actions)]
+ [
+ actions.map(&:design),
+ actions.presence && run_actions(actions)
+ ]
end
end
@@ -59,7 +66,7 @@ module DesignManagement
action = new_file?(design) ? :create : :update
on_success do
- ::Gitlab::UsageDataCounters::DesignsCounter.count(action)
+ track_usage_metrics(action)
end
DesignManagement::DesignAction.new(design, action, content)
@@ -121,6 +128,16 @@ module DesignManagement
end
end
end
+
+ def track_usage_metrics(action)
+ if action == :update
+ ::Gitlab::UsageDataCounters::IssueActivityUniqueCounter.track_issue_designs_modified_action(author: current_user)
+ else
+ ::Gitlab::UsageDataCounters::IssueActivityUniqueCounter.track_issue_designs_added_action(author: current_user)
+ end
+
+ ::Gitlab::UsageDataCounters::DesignsCounter.count(action)
+ end
end
end
diff --git a/app/services/feature_flags/base_service.rb b/app/services/feature_flags/base_service.rb
new file mode 100644
index 00000000000..9b27df90992
--- /dev/null
+++ b/app/services/feature_flags/base_service.rb
@@ -0,0 +1,55 @@
+# frozen_string_literal: true
+
+module FeatureFlags
+ class BaseService < ::BaseService
+ include Gitlab::Utils::StrongMemoize
+
+ AUDITABLE_ATTRIBUTES = %w(name description active).freeze
+
+ protected
+
+ def audit_event(feature_flag)
+ message = audit_message(feature_flag)
+
+ return if message.blank?
+
+ details =
+ {
+ custom_message: message,
+ target_id: feature_flag.id,
+ target_type: feature_flag.class.name,
+ target_details: feature_flag.name
+ }
+
+ ::AuditEventService.new(
+ current_user,
+ feature_flag.project,
+ details
+ )
+ end
+
+ def save_audit_event(audit_event)
+ return unless audit_event
+
+ audit_event.security_event
+ end
+
+ def created_scope_message(scope)
+ "Created rule <strong>#{scope.environment_scope}</strong> "\
+ "and set it as <strong>#{scope.active ? "active" : "inactive"}</strong> "\
+ "with strategies <strong>#{scope.strategies}</strong>."
+ end
+
+ def feature_flag_by_name
+ strong_memoize(:feature_flag_by_name) do
+ project.operations_feature_flags.find_by_name(params[:name])
+ end
+ end
+
+ def feature_flag_scope_by_environment_scope
+ strong_memoize(:feature_flag_scope_by_environment_scope) do
+ feature_flag_by_name.scopes.find_by_environment_scope(params[:environment_scope])
+ end
+ end
+ end
+end
diff --git a/app/services/feature_flags/create_service.rb b/app/services/feature_flags/create_service.rb
new file mode 100644
index 00000000000..b4ca90f7aae
--- /dev/null
+++ b/app/services/feature_flags/create_service.rb
@@ -0,0 +1,52 @@
+# frozen_string_literal: true
+
+module FeatureFlags
+ class CreateService < FeatureFlags::BaseService
+ def execute
+ return error('Access Denied', 403) unless can_create?
+ return error('Version is invalid', :bad_request) unless valid_version?
+ return error('New version feature flags are not enabled for this project', :bad_request) unless flag_version_enabled?
+
+ ActiveRecord::Base.transaction do
+ feature_flag = project.operations_feature_flags.new(params)
+
+ if feature_flag.save
+ save_audit_event(audit_event(feature_flag))
+
+ success(feature_flag: feature_flag)
+ else
+ error(feature_flag.errors.full_messages, 400)
+ end
+ end
+ end
+
+ private
+
+ def audit_message(feature_flag)
+ message_parts = ["Created feature flag <strong>#{feature_flag.name}</strong>",
+ "with description <strong>\"#{feature_flag.description}\"</strong>."]
+
+ message_parts += feature_flag.scopes.map do |scope|
+ created_scope_message(scope)
+ end
+
+ message_parts.join(" ")
+ end
+
+ def can_create?
+ Ability.allowed?(current_user, :create_feature_flag, project)
+ end
+
+ def valid_version?
+ !params.key?(:version) || Operations::FeatureFlag.versions.key?(params[:version])
+ end
+
+ def flag_version_enabled?
+ params[:version] != 'new_version_flag' || new_version_feature_flags_enabled?
+ end
+
+ def new_version_feature_flags_enabled?
+ ::Feature.enabled?(:feature_flags_new_version, project, default_enabled: true)
+ end
+ end
+end
diff --git a/app/services/feature_flags/destroy_service.rb b/app/services/feature_flags/destroy_service.rb
new file mode 100644
index 00000000000..c77e3e03ec3
--- /dev/null
+++ b/app/services/feature_flags/destroy_service.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+module FeatureFlags
+ class DestroyService < FeatureFlags::BaseService
+ def execute(feature_flag)
+ destroy_feature_flag(feature_flag)
+ end
+
+ private
+
+ def destroy_feature_flag(feature_flag)
+ return error('Access Denied', 403) unless can_destroy?(feature_flag)
+
+ ActiveRecord::Base.transaction do
+ if feature_flag.destroy
+ save_audit_event(audit_event(feature_flag))
+
+ success(feature_flag: feature_flag)
+ else
+ error(feature_flag.errors.full_messages)
+ end
+ end
+ end
+
+ def audit_message(feature_flag)
+ "Deleted feature flag <strong>#{feature_flag.name}</strong>."
+ end
+
+ def can_destroy?(feature_flag)
+ Ability.allowed?(current_user, :destroy_feature_flag, feature_flag)
+ end
+ end
+end
diff --git a/app/services/feature_flags/disable_service.rb b/app/services/feature_flags/disable_service.rb
new file mode 100644
index 00000000000..8a443ac1795
--- /dev/null
+++ b/app/services/feature_flags/disable_service.rb
@@ -0,0 +1,46 @@
+# frozen_string_literal: true
+
+module FeatureFlags
+ class DisableService < BaseService
+ def execute
+ return error('Feature Flag not found', 404) unless feature_flag_by_name
+ return error('Feature Flag Scope not found', 404) unless feature_flag_scope_by_environment_scope
+ return error('Strategy not found', 404) unless strategy_exist_in_persisted_data?
+
+ ::FeatureFlags::UpdateService
+ .new(project, current_user, update_params)
+ .execute(feature_flag_by_name)
+ end
+
+ private
+
+ def update_params
+ if remaining_strategies.empty?
+ params_to_destroy_scope
+ else
+ params_to_update_scope
+ end
+ end
+
+ def remaining_strategies
+ strong_memoize(:remaining_strategies) do
+ feature_flag_scope_by_environment_scope.strategies.reject do |strategy|
+ strategy['name'] == params[:strategy]['name'] &&
+ strategy['parameters'] == params[:strategy]['parameters']
+ end
+ end
+ end
+
+ def strategy_exist_in_persisted_data?
+ feature_flag_scope_by_environment_scope.strategies != remaining_strategies
+ end
+
+ def params_to_destroy_scope
+ { scopes_attributes: [{ id: feature_flag_scope_by_environment_scope.id, _destroy: true }] }
+ end
+
+ def params_to_update_scope
+ { scopes_attributes: [{ id: feature_flag_scope_by_environment_scope.id, strategies: remaining_strategies }] }
+ end
+ end
+end
diff --git a/app/services/feature_flags/enable_service.rb b/app/services/feature_flags/enable_service.rb
new file mode 100644
index 00000000000..b4cbb32e003
--- /dev/null
+++ b/app/services/feature_flags/enable_service.rb
@@ -0,0 +1,93 @@
+# frozen_string_literal: true
+
+module FeatureFlags
+ class EnableService < BaseService
+ def execute
+ if feature_flag_by_name
+ update_feature_flag
+ else
+ create_feature_flag
+ end
+ end
+
+ private
+
+ def create_feature_flag
+ ::FeatureFlags::CreateService
+ .new(project, current_user, create_params)
+ .execute
+ end
+
+ def update_feature_flag
+ ::FeatureFlags::UpdateService
+ .new(project, current_user, update_params)
+ .execute(feature_flag_by_name)
+ end
+
+ def create_params
+ if params[:environment_scope] == '*'
+ params_to_create_flag_with_default_scope
+ else
+ params_to_create_flag_with_additional_scope
+ end
+ end
+
+ def update_params
+ if feature_flag_scope_by_environment_scope
+ params_to_update_scope
+ else
+ params_to_create_scope
+ end
+ end
+
+ def params_to_create_flag_with_default_scope
+ {
+ name: params[:name],
+ scopes_attributes: [
+ {
+ active: true,
+ environment_scope: '*',
+ strategies: [params[:strategy]]
+ }
+ ]
+ }
+ end
+
+ def params_to_create_flag_with_additional_scope
+ {
+ name: params[:name],
+ scopes_attributes: [
+ {
+ active: false,
+ environment_scope: '*'
+ },
+ {
+ active: true,
+ environment_scope: params[:environment_scope],
+ strategies: [params[:strategy]]
+ }
+ ]
+ }
+ end
+
+ def params_to_create_scope
+ {
+ scopes_attributes: [{
+ active: true,
+ environment_scope: params[:environment_scope],
+ strategies: [params[:strategy]]
+ }]
+ }
+ end
+
+ def params_to_update_scope
+ {
+ scopes_attributes: [{
+ id: feature_flag_scope_by_environment_scope.id,
+ active: true,
+ strategies: feature_flag_scope_by_environment_scope.strategies | [params[:strategy]]
+ }]
+ }
+ end
+ end
+end
diff --git a/app/services/feature_flags/update_service.rb b/app/services/feature_flags/update_service.rb
new file mode 100644
index 00000000000..c837e50b104
--- /dev/null
+++ b/app/services/feature_flags/update_service.rb
@@ -0,0 +1,87 @@
+# frozen_string_literal: true
+
+module FeatureFlags
+ class UpdateService < FeatureFlags::BaseService
+ AUDITABLE_SCOPE_ATTRIBUTES_HUMAN_NAMES = {
+ 'active' => 'active state',
+ 'environment_scope' => 'environment scope',
+ 'strategies' => 'strategies'
+ }.freeze
+
+ def execute(feature_flag)
+ return error('Access Denied', 403) unless can_update?(feature_flag)
+
+ ActiveRecord::Base.transaction do
+ feature_flag.assign_attributes(params)
+
+ feature_flag.strategies.each do |strategy|
+ if strategy.name_changed? && strategy.name_was == ::Operations::FeatureFlags::Strategy::STRATEGY_GITLABUSERLIST
+ strategy.user_list = nil
+ end
+ end
+
+ audit_event = audit_event(feature_flag)
+
+ if feature_flag.save
+ save_audit_event(audit_event)
+
+ success(feature_flag: feature_flag)
+ else
+ error(feature_flag.errors.full_messages, :bad_request)
+ end
+ end
+ end
+
+ private
+
+ def audit_message(feature_flag)
+ changes = changed_attributes_messages(feature_flag)
+ changes += changed_scopes_messages(feature_flag)
+
+ return if changes.empty?
+
+ "Updated feature flag <strong>#{feature_flag.name}</strong>. " + changes.join(" ")
+ end
+
+ def changed_attributes_messages(feature_flag)
+ feature_flag.changes.slice(*AUDITABLE_ATTRIBUTES).map do |attribute_name, changes|
+ "Updated #{attribute_name} "\
+ "from <strong>\"#{changes.first}\"</strong> to "\
+ "<strong>\"#{changes.second}\"</strong>."
+ end
+ end
+
+ def changed_scopes_messages(feature_flag)
+ feature_flag.scopes.map do |scope|
+ if scope.new_record?
+ created_scope_message(scope)
+ elsif scope.marked_for_destruction?
+ deleted_scope_message(scope)
+ else
+ updated_scope_message(scope)
+ end
+ end.compact # updated_scope_message can return nil if nothing has been changed
+ end
+
+ def deleted_scope_message(scope)
+ "Deleted rule <strong>#{scope.environment_scope}</strong>."
+ end
+
+ def updated_scope_message(scope)
+ changes = scope.changes.slice(*AUDITABLE_SCOPE_ATTRIBUTES_HUMAN_NAMES.keys)
+ return if changes.empty?
+
+ message = "Updated rule <strong>#{scope.environment_scope}</strong> "
+ message += changes.map do |attribute_name, change|
+ name = AUDITABLE_SCOPE_ATTRIBUTES_HUMAN_NAMES[attribute_name]
+ "#{name} from <strong>#{change.first}</strong> to <strong>#{change.second}</strong>"
+ end.join(' ')
+
+ message + '.'
+ end
+
+ def can_update?(feature_flag)
+ Ability.allowed?(current_user, :update_feature_flag, feature_flag)
+ end
+ end
+end
diff --git a/app/services/git/branch_hooks_service.rb b/app/services/git/branch_hooks_service.rb
index dcb32b4c84b..93a0d139001 100644
--- a/app/services/git/branch_hooks_service.rb
+++ b/app/services/git/branch_hooks_service.rb
@@ -76,12 +76,20 @@ module Git
def branch_change_hooks
enqueue_process_commit_messages
enqueue_jira_connect_sync_messages
+ enqueue_metrics_dashboard_sync
end
def branch_remove_hooks
project.repository.after_remove_branch(expire_cache: false)
end
+ def enqueue_metrics_dashboard_sync
+ return unless Feature.enabled?(:sync_metrics_dashboards, project)
+ return unless default_branch?
+
+ ::Metrics::Dashboard::SyncDashboardsWorker.perform_async(project.id)
+ end
+
# Schedules processing of commit messages
def enqueue_process_commit_messages
referencing_commits = limited_commits.select(&:matches_cross_reference_regex?)
diff --git a/app/services/git/wiki_push_service.rb b/app/services/git/wiki_push_service.rb
index fa3019ee9d6..87e2be858c0 100644
--- a/app/services/git/wiki_push_service.rb
+++ b/app/services/git/wiki_push_service.rb
@@ -34,9 +34,7 @@ module Git
def can_process_wiki_events?
# TODO: Support activity events for group wikis
# https://gitlab.com/gitlab-org/gitlab/-/issues/209306
- return false unless wiki.is_a?(ProjectWiki)
-
- Feature.enabled?(:wiki_events_on_git_push, wiki.container)
+ wiki.is_a?(ProjectWiki)
end
def push_changes
diff --git a/app/services/groups/create_service.rb b/app/services/groups/create_service.rb
index ce583095168..cf843d92862 100644
--- a/app/services/groups/create_service.rb
+++ b/app/services/groups/create_service.rb
@@ -15,6 +15,8 @@ module Groups
after_build_hook(@group, params)
+ inherit_group_shared_runners_settings
+
unless can_use_visibility_level? && can_create_group?
return @group
end
@@ -28,9 +30,12 @@ module Groups
@group.build_chat_team(name: response['name'], team_id: response['id'])
end
- if @group.save
- @group.add_owner(current_user)
- add_settings_record
+ Group.transaction do
+ if @group.save
+ @group.add_owner(current_user)
+ @group.create_namespace_settings
+ Service.create_from_active_default_integrations(@group, :group_id) if Feature.enabled?(:group_level_integrations)
+ end
end
@group
@@ -44,6 +49,7 @@ module Groups
def remove_unallowed_params
params.delete(:default_branch_protection) unless can?(current_user, :create_group_with_default_branch_protection)
+ params.delete(:allow_mfa_for_subgroups)
end
def create_chat_team?
@@ -84,8 +90,11 @@ module Groups
params[:visibility_level] = Gitlab::CurrentSettings.current_application_settings.default_group_visibility
end
- def add_settings_record
- @group.create_namespace_settings
+ def inherit_group_shared_runners_settings
+ return unless @group.parent
+
+ @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
end
end
diff --git a/app/services/groups/import_export/import_service.rb b/app/services/groups/import_export/import_service.rb
index a5c776f8fc2..a0ddc50e5e0 100644
--- a/app/services/groups/import_export/import_service.rb
+++ b/app/services/groups/import_export/import_service.rb
@@ -13,7 +13,7 @@ module Groups
end
def async_execute
- group_import_state = GroupImportState.safe_find_or_create_by!(group: group)
+ group_import_state = GroupImportState.safe_find_or_create_by!(group: group, user: current_user)
jid = GroupImportWorker.perform_async(current_user.id, group.id)
if jid.present?
diff --git a/app/services/groups/transfer_service.rb b/app/services/groups/transfer_service.rb
index 2bd571f60af..aad574aeaf5 100644
--- a/app/services/groups/transfer_service.rb
+++ b/app/services/groups/transfer_service.rb
@@ -38,6 +38,7 @@ module Groups
# Overridden in EE
def post_update_hooks(updated_project_ids)
refresh_project_authorizations
+ refresh_descendant_groups if @new_parent_group
end
def ensure_allowed_transfer
@@ -101,8 +102,13 @@ module Groups
@group.visibility_level = @new_parent_group.visibility_level
end
+ update_two_factor_authentication if @new_parent_group
+
@group.parent = @new_parent_group
@group.clear_memoization(:self_and_ancestors_ids)
+
+ inherit_group_shared_runners_settings
+
@group.save!
end
@@ -126,8 +132,26 @@ module Groups
projects_to_update
.update_all(visibility_level: @new_parent_group.visibility_level)
end
+
+ def update_two_factor_authentication
+ return if namespace_parent_allows_two_factor_auth
+
+ @group.require_two_factor_authentication = false
+ end
+
+ def refresh_descendant_groups
+ return if namespace_parent_allows_two_factor_auth
+
+ if @group.descendants.where(require_two_factor_authentication: true).any?
+ DisallowTwoFactorForSubgroupsWorker.perform_async(@group.id)
+ end
+ end
# rubocop: enable CodeReuse/ActiveRecord
+ def namespace_parent_allows_two_factor_auth
+ @new_parent_group.namespace_settings.allow_mfa_for_subgroups
+ end
+
def ensure_ownership
return if @new_parent_group
return unless @group.owners.empty?
@@ -161,6 +185,17 @@ module Groups
group_contains_npm_packages: s_('TransferGroup|Group contains projects with NPM packages.')
}.freeze
end
+
+ def inherit_group_shared_runners_settings
+ parent_setting = @group.parent&.shared_runners_setting
+ return unless parent_setting
+
+ if @group.shared_runners_setting_higher_than?(parent_setting)
+ result = Groups::UpdateSharedRunnersService.new(@group, current_user, shared_runners_setting: parent_setting).execute
+
+ raise TransferError, result[:message] unless result[:status] == :success
+ end
+ end
end
end
diff --git a/app/services/groups/update_service.rb b/app/services/groups/update_service.rb
index 81393681dc0..84385f5da25 100644
--- a/app/services/groups/update_service.rb
+++ b/app/services/groups/update_service.rb
@@ -4,6 +4,8 @@ module Groups
class UpdateService < Groups::BaseService
include UpdateVisibilityLevel
+ SETTINGS_PARAMS = [:allow_mfa_for_subgroups].freeze
+
def execute
reject_parent_id!
remove_unallowed_params
@@ -19,8 +21,14 @@ module Groups
return false unless valid_path_change_with_npm_packages?
+ return false unless update_shared_runners
+
+ handle_changes
+
before_assignment_hook(group, params)
+ handle_namespace_settings
+
group.assign_attributes(params)
begin
@@ -38,6 +46,18 @@ module Groups
private
+ def handle_namespace_settings
+ settings_params = params.slice(*::NamespaceSetting::NAMESPACE_SETTINGS_PARAMS)
+
+ return if settings_params.empty?
+
+ ::NamespaceSetting::NAMESPACE_SETTINGS_PARAMS.each do |nsp|
+ params.delete(nsp)
+ end
+
+ ::NamespaceSettings::UpdateService.new(current_user, group, settings_params).execute
+ end
+
def valid_path_change_with_npm_packages?
return true unless group.packages_feature_enabled?
return true if params[:path].blank?
@@ -73,6 +93,18 @@ module Groups
# don't enqueue immediately to prevent todos removal in case of a mistake
TodosDestroyer::GroupPrivateWorker.perform_in(Todo::WAIT_FOR_DELETE, group.id)
end
+
+ update_two_factor_requirement_for_subgroups
+ end
+
+ def update_two_factor_requirement_for_subgroups
+ settings = group.namespace_settings
+ return if settings.allow_mfa_for_subgroups
+
+ if settings.previous_changes.include?(:allow_mfa_for_subgroups)
+ # enque in batches members update
+ DisallowTwoFactorForSubgroupsWorker.perform_async(group.id)
+ end
end
def reject_parent_id!
@@ -85,6 +117,21 @@ module Groups
params.delete(:default_branch_protection) unless can?(current_user, :update_default_branch_protection, group)
end
+ def handle_changes
+ handle_settings_update
+ end
+
+ def handle_settings_update
+ settings_params = params.slice(*allowed_settings_params)
+ allowed_settings_params.each { |param| params.delete(param) }
+
+ ::NamespaceSettings::UpdateService.new(current_user, group, settings_params).execute
+ end
+
+ def allowed_settings_params
+ SETTINGS_PARAMS
+ end
+
def valid_share_with_group_lock_change?
return true unless changing_share_with_group_lock?
return true if can?(current_user, :change_share_with_group_lock, group)
@@ -98,6 +145,17 @@ module Groups
params[:share_with_group_lock] != group.share_with_group_lock
end
+
+ def update_shared_runners
+ return true if params[:shared_runners_setting].nil?
+
+ result = Groups::UpdateSharedRunnersService.new(group, current_user, shared_runners_setting: params.delete(:shared_runners_setting)).execute
+
+ return true if result[:status] == :success
+
+ group.errors.add(:update_shared_runners, result[:message])
+ false
+ end
end
end
diff --git a/app/services/groups/update_shared_runners_service.rb b/app/services/groups/update_shared_runners_service.rb
index 63f57104510..639c5bf6ae0 100644
--- a/app/services/groups/update_shared_runners_service.rb
+++ b/app/services/groups/update_shared_runners_service.rb
@@ -7,44 +7,24 @@ module Groups
validate_params
- enable_or_disable_shared_runners!
- allow_or_disallow_descendants_override_disabled_shared_runners!
+ update_shared_runners
success
- rescue Group::UpdateSharedRunnersError => error
+ rescue ActiveRecord::RecordInvalid, ArgumentError => error
error(error.message)
end
private
def validate_params
- if Gitlab::Utils.to_boolean(params[:shared_runners_enabled]) && !params[:allow_descendants_override_disabled_shared_runners].nil?
- raise Group::UpdateSharedRunnersError, 'Cannot set shared_runners_enabled to true and allow_descendants_override_disabled_shared_runners'
+ unless Namespace::SHARED_RUNNERS_SETTINGS.include?(params[:shared_runners_setting])
+ raise ArgumentError, "state must be one of: #{Namespace::SHARED_RUNNERS_SETTINGS.join(', ')}"
end
end
- def enable_or_disable_shared_runners!
- return if params[:shared_runners_enabled].nil?
-
- if Gitlab::Utils.to_boolean(params[:shared_runners_enabled])
- group.enable_shared_runners!
- else
- group.disable_shared_runners!
- end
- end
-
- def allow_or_disallow_descendants_override_disabled_shared_runners!
- return if params[:allow_descendants_override_disabled_shared_runners].nil?
-
- # Needs to reset group because if both params are present could result in error
- group.reset
-
- if Gitlab::Utils.to_boolean(params[:allow_descendants_override_disabled_shared_runners])
- group.allow_descendants_override_disabled_shared_runners!
- else
- group.disallow_descendants_override_disabled_shared_runners!
- end
+ def update_shared_runners
+ group.update_shared_runners_setting!(params[:shared_runners_setting])
end
end
end
diff --git a/app/services/incident_management/incidents/create_service.rb b/app/services/incident_management/incidents/create_service.rb
index 5b925e0f440..cff288d602b 100644
--- a/app/services/incident_management/incidents/create_service.rb
+++ b/app/services/incident_management/incidents/create_service.rb
@@ -24,7 +24,7 @@ module IncidentManagement
return error(issue.errors.full_messages.to_sentence, issue) unless issue.valid?
- issue.update_severity(severity)
+ update_severity_for(issue)
success(issue)
end
@@ -40,6 +40,10 @@ module IncidentManagement
def error(message, issue = nil)
ServiceResponse.error(payload: { issue: issue }, message: message)
end
+
+ def update_severity_for(issue)
+ ::IncidentManagement::Incidents::UpdateSeverityService.new(issue, current_user, severity).execute
+ end
end
end
end
diff --git a/app/services/incident_management/incidents/update_severity_service.rb b/app/services/incident_management/incidents/update_severity_service.rb
new file mode 100644
index 00000000000..5b150f3f02e
--- /dev/null
+++ b/app/services/incident_management/incidents/update_severity_service.rb
@@ -0,0 +1,38 @@
+# frozen_string_literal: true
+
+module IncidentManagement
+ module Incidents
+ class UpdateSeverityService < BaseService
+ def initialize(issuable, current_user, severity)
+ super(issuable.project, current_user)
+
+ @issuable = issuable
+ @severity = severity.to_s.downcase
+ @severity = IssuableSeverity::DEFAULT unless IssuableSeverity.severities.key?(@severity)
+ end
+
+ def execute
+ return unless issuable.incident?
+
+ update_severity!
+ add_system_note
+ end
+
+ private
+
+ attr_reader :issuable, :severity
+
+ def issuable_severity
+ issuable.issuable_severity || issuable.build_issuable_severity(issue_id: issuable.id)
+ end
+
+ def update_severity!
+ issuable_severity.update!(severity: severity)
+ end
+
+ def add_system_note
+ ::IncidentManagement::AddSeveritySystemNoteWorker.perform_async(issuable.id, current_user.id)
+ end
+ end
+ end
+end
diff --git a/app/services/incident_management/pager_duty/process_webhook_service.rb b/app/services/incident_management/pager_duty/process_webhook_service.rb
index fd8252f75fb..027425e4aaa 100644
--- a/app/services/incident_management/pager_duty/process_webhook_service.rb
+++ b/app/services/incident_management/pager_duty/process_webhook_service.rb
@@ -34,7 +34,7 @@ module IncidentManagement
strong_memoize(:pager_duty_processable_events) do
::PagerDuty::WebhookPayloadParser
.call(params.to_h)
- .filter { |msg| msg['event'].in?(PAGER_DUTY_PROCESSABLE_EVENT_TYPES) }
+ .filter { |msg| msg['event'].to_s.in?(PAGER_DUTY_PROCESSABLE_EVENT_TYPES) }
end
end
diff --git a/app/services/issuable/clone/attributes_rewriter.rb b/app/services/issuable/clone/attributes_rewriter.rb
index c84074039ea..3861d88bce9 100644
--- a/app/services/issuable/clone/attributes_rewriter.rb
+++ b/app/services/issuable/clone/attributes_rewriter.rb
@@ -18,7 +18,6 @@ module Issuable
new_entity.update(update_attributes)
copy_resource_label_events
- copy_resource_weight_events
copy_resource_milestone_events
copy_resource_state_events
end
@@ -55,16 +54,6 @@ module Issuable
end
end
- def copy_resource_weight_events
- return unless both_respond_to?(:resource_weight_events)
-
- copy_events(ResourceWeightEvent.table_name, original_entity.resource_weight_events) do |event|
- event.attributes
- .except('id', 'reference', 'reference_html')
- .merge('issue_id' => new_entity.id)
- end
- end
-
def copy_resource_milestone_events
return unless milestone_events_supported?
@@ -128,3 +117,5 @@ module Issuable
end
end
end
+
+Issuable::Clone::AttributesRewriter.prepend_if_ee('EE::Issuable::Clone::AttributesRewriter')
diff --git a/app/services/issuable_base_service.rb b/app/services/issuable_base_service.rb
index 1672ba2830a..60e5293e218 100644
--- a/app/services/issuable_base_service.rb
+++ b/app/services/issuable_base_service.rb
@@ -322,7 +322,7 @@ class IssuableBaseService < BaseService
def change_severity(issuable)
if severity = params.delete(:severity)
- issuable.update_severity(severity)
+ ::IncidentManagement::Incidents::UpdateSeverityService.new(issuable, current_user, severity).execute
end
end
@@ -366,6 +366,7 @@ class IssuableBaseService < BaseService
}
associations[:total_time_spent] = issuable.total_time_spent if issuable.respond_to?(:total_time_spent)
associations[:description] = issuable.description
+ associations[:reviewers] = issuable.reviewers.to_a if issuable.allows_reviewers?
associations
end
diff --git a/app/services/issues/base_service.rb b/app/services/issues/base_service.rb
index 0ed2b08b7b1..978ea6fe9bc 100644
--- a/app/services/issues/base_service.rb
+++ b/app/services/issues/base_service.rb
@@ -34,6 +34,18 @@ module Issues
private
+ def filter_params(merge_request)
+ super
+
+ moved_issue = params.delete(:moved_issue)
+
+ # Setting created_at, updated_at and iid is allowed only for admins and owners or
+ # when moving an issue as we preserve the original issue attributes except id and iid.
+ params.delete(:iid) unless current_user.can?(:set_issue_iid, project)
+ params.delete(:created_at) unless moved_issue || current_user.can?(:set_issue_created_at, project)
+ params.delete(:updated_at) unless moved_issue || current_user.can?(:set_issue_updated_at, project)
+ end
+
def create_assignee_note(issue, old_assignees)
SystemNoteService.change_issuable_assignees(
issue, issue.project, current_user, old_assignees)
diff --git a/app/services/issues/build_service.rb b/app/services/issues/build_service.rb
index 2de6ed9fa1c..3145739fe91 100644
--- a/app/services/issues/build_service.rb
+++ b/app/services/issues/build_service.rb
@@ -64,20 +64,26 @@ module Issues
private
- def whitelisted_issue_params
- base_params = [:title, :description, :confidential]
- admin_params = [:milestone_id, :issue_type]
+ def allowed_issue_base_params
+ [:title, :description, :confidential, :issue_type]
+ end
+
+ def allowed_issue_admin_params
+ [:milestone_id]
+ end
+ def allowed_issue_params
if can?(current_user, :admin_issue, project)
- params.slice(*(base_params + admin_params))
+ params.slice(*(allowed_issue_base_params + allowed_issue_admin_params))
else
- params.slice(*base_params)
+ params.slice(*allowed_issue_base_params)
end
end
def build_issue_params
- { author: current_user }.merge(issue_params_with_info_from_discussions)
- .merge(whitelisted_issue_params)
+ { author: current_user }
+ .merge(issue_params_with_info_from_discussions)
+ .merge(allowed_issue_params)
end
end
end
diff --git a/app/services/issues/move_service.rb b/app/services/issues/move_service.rb
index 60e0d1eec3d..90ccbd8ed21 100644
--- a/app/services/issues/move_service.rb
+++ b/app/services/issues/move_service.rb
@@ -23,11 +23,15 @@ module Issues
# to receive service desk emails on the new moved issue.
update_service_desk_sent_notifications
+ queue_copy_designs
+
new_entity
end
private
+ attr_reader :target_project
+
def update_service_desk_sent_notifications
return unless original_entity.from_service_desk?
@@ -46,9 +50,10 @@ module Issues
new_params = {
id: nil,
iid: nil,
- project: @target_project,
+ project: target_project,
author: original_entity.author,
- assignee_ids: original_entity.assignee_ids
+ assignee_ids: original_entity.assignee_ids,
+ moved_issue: true
}
new_params = original_entity.serializable_hash.symbolize_keys.merge(new_params)
@@ -58,6 +63,18 @@ module Issues
CreateService.new(@target_project, @current_user, new_params).execute(skip_system_notes: true)
end
+ def queue_copy_designs
+ return unless original_entity.designs.present?
+
+ response = DesignManagement::CopyDesignCollection::QueueService.new(
+ current_user,
+ original_entity,
+ new_entity
+ ).execute
+
+ log_error(response.message) if response.error?
+ end
+
def mark_as_moved
original_entity.update(moved_to: new_entity)
end
@@ -75,7 +92,7 @@ module Issues
end
def add_note_from
- SystemNoteService.noteable_moved(new_entity, @target_project,
+ SystemNoteService.noteable_moved(new_entity, target_project,
original_entity, current_user,
direction: :from)
end
diff --git a/app/services/issues/reopen_service.rb b/app/services/issues/reopen_service.rb
index e2b1b5400c7..12dbff57ec5 100644
--- a/app/services/issues/reopen_service.rb
+++ b/app/services/issues/reopen_service.rb
@@ -5,6 +5,8 @@ module Issues
def execute(issue)
return issue unless can?(current_user, :reopen_issue, issue)
+ before_reopen(issue)
+
if issue.reopen
event_service.reopen_issue(issue, current_user)
create_note(issue, 'reopened')
@@ -21,8 +23,14 @@ module Issues
private
+ def before_reopen(issue)
+ # Overriden in EE
+ end
+
def create_note(issue, state = issue.state)
SystemNoteService.change_status(issue, issue.project, current_user, state, nil)
end
end
end
+
+Issues::ReopenService.prepend_if_ee('EE::Issues::ReopenService')
diff --git a/app/services/jira/requests/base.rb b/app/services/jira/requests/base.rb
index 7c6db372257..4ed8df0f235 100644
--- a/app/services/jira/requests/base.rb
+++ b/app/services/jira/requests/base.rb
@@ -40,7 +40,12 @@ module Jira
build_service_response(response)
rescue Timeout::Error, Errno::EINVAL, Errno::ECONNRESET, Errno::ECONNREFUSED, URI::InvalidURIError, JIRA::HTTPError, OpenSSL::SSL::SSLError => error
error_message = "Jira request error: #{error.message}"
- log_error("Error sending message", client_url: client.options[:site], error: error_message)
+ log_error("Error sending message", client_url: client.options[:site],
+ error: {
+ exception_class: error.class.name,
+ exception_message: error.message,
+ exception_backtrace: Gitlab::BacktraceCleaner.clean_backtrace(error.backtrace)
+ })
ServiceResponse.error(message: error_message)
end
diff --git a/app/services/lfs/push_service.rb b/app/services/lfs/push_service.rb
index 6e1a11ebff8..9b947fbed07 100644
--- a/app/services/lfs/push_service.rb
+++ b/app/services/lfs/push_service.rb
@@ -12,7 +12,7 @@ module Lfs
def execute
lfs_objects_relation.each_batch(of: BATCH_SIZE) do |objects|
- push_objects(objects)
+ push_objects!(objects)
end
success
@@ -30,8 +30,8 @@ module Lfs
project.lfs_objects_for_repository_types(nil, :project)
end
- def push_objects(objects)
- rsp = lfs_client.batch('upload', objects)
+ def push_objects!(objects)
+ rsp = lfs_client.batch!('upload', objects)
objects = objects.index_by(&:oid)
rsp.fetch('objects', []).each do |spec|
@@ -53,14 +53,14 @@ module Lfs
return
end
- lfs_client.upload(object, upload, authenticated: authenticated)
+ lfs_client.upload!(object, upload, authenticated: authenticated)
end
def verify_object!(object, spec)
- # TODO: the remote has requested that we make another call to verify that
- # the object has been sent correctly.
- # https://gitlab.com/gitlab-org/gitlab/-/issues/250654
- log_error("LFS upload verification requested, but not supported for #{object.oid}")
+ authenticated = spec['authenticated']
+ verify = spec.dig('actions', 'verify')
+
+ lfs_client.verify!(object, verify, authenticated: authenticated)
end
def url
diff --git a/app/services/members/create_service.rb b/app/services/members/create_service.rb
index 610288c5e76..088e6f031c8 100644
--- a/app/services/members/create_service.rb
+++ b/app/services/members/create_service.rb
@@ -7,7 +7,7 @@ module Members
def execute(source)
return error(s_('AddMember|No users specified.')) if params[:user_ids].blank?
- user_ids = params[:user_ids].split(',').uniq
+ user_ids = params[:user_ids].split(',').uniq.flatten
return error(s_("AddMember|Too many users specified (limit is %{user_limit})") % { user_limit: user_limit }) if
user_limit && user_ids.size > user_limit
diff --git a/app/services/members/invitation_reminder_email_service.rb b/app/services/members/invitation_reminder_email_service.rb
new file mode 100644
index 00000000000..e589cdc2fa3
--- /dev/null
+++ b/app/services/members/invitation_reminder_email_service.rb
@@ -0,0 +1,54 @@
+# frozen_string_literal: true
+
+module Members
+ class InvitationReminderEmailService
+ include Gitlab::Utils::StrongMemoize
+
+ attr_reader :invitation
+
+ MAX_INVITATION_LIFESPAN = 14.0
+ REMINDER_RATIO = [2, 5, 10].freeze
+
+ def initialize(invitation)
+ @invitation = invitation
+ end
+
+ def execute
+ return unless experiment_enabled?
+
+ reminder_index = days_on_which_to_send_reminders.index(days_after_invitation_sent)
+ return unless reminder_index
+
+ invitation.send_invitation_reminder(reminder_index)
+ end
+
+ private
+
+ def experiment_enabled?
+ Gitlab::Experimentation.enabled_for_attribute?(:invitation_reminders, invitation.invite_email)
+ end
+
+ def days_after_invitation_sent
+ (Date.today - invitation.created_at.to_date).to_i
+ end
+
+ def days_on_which_to_send_reminders
+ # Don't send any reminders if the invitation has expired or expires today
+ return [] if invitation.expires_at && invitation.expires_at <= Date.today
+
+ # Calculate the number of days on which to send reminders based on the MAX_INVITATION_LIFESPAN and the REMINDER_RATIO
+ REMINDER_RATIO.map { |number_of_days| ((number_of_days * invitation_lifespan_in_days) / MAX_INVITATION_LIFESPAN).ceil }.uniq
+ end
+
+ def invitation_lifespan_in_days
+ # When the invitation lifespan is more than 14 days or does not expire, send the reminders within 14 days
+ strong_memoize(:invitation_lifespan_in_days) do
+ if invitation.expires_at
+ [(invitation.expires_at - invitation.created_at.to_date).to_i, MAX_INVITATION_LIFESPAN].min
+ else
+ MAX_INVITATION_LIFESPAN
+ end
+ end
+ end
+ end
+end
diff --git a/app/services/merge_requests/base_service.rb b/app/services/merge_requests/base_service.rb
index abc3f99797d..aa591312c6a 100644
--- a/app/services/merge_requests/base_service.rb
+++ b/app/services/merge_requests/base_service.rb
@@ -110,6 +110,10 @@ module MergeRequests
return
end
+ unless merge_request.allows_multiple_reviewers?
+ params[:reviewer_ids] = params[:reviewer_ids].first(1)
+ end
+
reviewer_ids = params[:reviewer_ids].select { |reviewer_id| user_can_read?(merge_request, reviewer_id) }
if params[:reviewer_ids].map(&:to_s) == [IssuableFinder::Params::NONE]
@@ -130,6 +134,11 @@ module MergeRequests
merge_request, merge_request.project, current_user, old_assignees)
end
+ def create_reviewer_note(merge_request, old_reviewers)
+ SystemNoteService.change_issuable_reviewers(
+ merge_request, merge_request.project, current_user, old_reviewers)
+ end
+
def create_pipeline_for(merge_request, user)
MergeRequests::CreatePipelineService.new(project, user).execute(merge_request)
end
diff --git a/app/services/merge_requests/cleanup_refs_service.rb b/app/services/merge_requests/cleanup_refs_service.rb
index 0f03f5f09b4..d003124a112 100644
--- a/app/services/merge_requests/cleanup_refs_service.rb
+++ b/app/services/merge_requests/cleanup_refs_service.rb
@@ -17,7 +17,7 @@ module MergeRequests
@repository = merge_request.project.repository
@ref_path = merge_request.ref_path
@merge_ref_path = merge_request.merge_ref_path
- @ref_head_sha = @repository.commit(merge_request.ref_path).id
+ @ref_head_sha = @repository.commit(merge_request.ref_path)&.id
@merge_ref_sha = merge_request.merge_ref_head&.id
end
diff --git a/app/services/merge_requests/export_csv_service.rb b/app/services/merge_requests/export_csv_service.rb
new file mode 100644
index 00000000000..1e7f0c8e722
--- /dev/null
+++ b/app/services/merge_requests/export_csv_service.rb
@@ -0,0 +1,55 @@
+# frozen_string_literal: true
+
+module MergeRequests
+ class ExportCsvService
+ include Gitlab::Routing.url_helpers
+ include GitlabRoutingHelper
+
+ # Target attachment size before base64 encoding
+ TARGET_FILESIZE = 15.megabytes
+
+ def initialize(merge_requests, project)
+ @project = project
+ @merge_requests = merge_requests
+ end
+
+ def csv_data
+ csv_builder.render(TARGET_FILESIZE)
+ end
+
+ def email(user)
+ Notify.merge_requests_csv_email(user, @project, csv_data, csv_builder.status).deliver_now
+ end
+
+ private
+
+ def csv_builder
+ @csv_builder ||= CsvBuilder.new(@merge_requests.with_csv_entity_associations, header_to_value_hash)
+ end
+
+ def header_to_value_hash
+ {
+ 'MR IID' => 'iid',
+ 'URL' => -> (merge_request) { merge_request_url(merge_request) },
+ 'Title' => 'title',
+ 'State' => 'state',
+ 'Description' => 'description',
+ 'Source Branch' => 'source_branch',
+ 'Target Branch' => 'target_branch',
+ 'Source Project ID' => 'source_project_id',
+ 'Target Project ID' => 'target_project_id',
+ 'Author' => -> (merge_request) { merge_request.author.name },
+ 'Author Username' => -> (merge_request) { merge_request.author.username },
+ 'Assignees' => -> (merge_request) { merge_request.assignees.map(&:name).join(', ') },
+ 'Assignee Usernames' => -> (merge_request) { merge_request.assignees.map(&:username).join(', ') },
+ 'Approvers' => -> (merge_request) { merge_request.approved_by_users.map(&:name).join(', ') },
+ 'Approver Usernames' => -> (merge_request) { merge_request.approved_by_users.map(&:username).join(', ') },
+ 'Merged User' => -> (merge_request) { merge_request.metrics&.merged_by&.name.to_s },
+ 'Merged Username' => -> (merge_request) { merge_request.metrics&.merged_by&.username.to_s },
+ 'Milestone ID' => -> (merge_request) { merge_request&.milestone&.id || '' },
+ 'Created At (UTC)' => -> (merge_request) { merge_request.created_at.utc },
+ 'Updated At (UTC)' => -> (merge_request) { merge_request.updated_at.utc }
+ }
+ end
+ end
+end
diff --git a/app/services/merge_requests/ff_merge_service.rb b/app/services/merge_requests/ff_merge_service.rb
index 79011094e88..c5640047899 100644
--- a/app/services/merge_requests/ff_merge_service.rb
+++ b/app/services/merge_requests/ff_merge_service.rb
@@ -27,7 +27,7 @@ module MergeRequests
rescue StandardError => e
raise MergeError, "Something went wrong during merge: #{e.message}"
ensure
- merge_request.update(in_progress_merge_commit_sha: nil)
+ merge_request.update_and_mark_in_progress_merge_commit_sha(nil)
end
end
end
diff --git a/app/services/merge_requests/merge_service.rb b/app/services/merge_requests/merge_service.rb
index 437e87dadf7..ba22b458777 100644
--- a/app/services/merge_requests/merge_service.rb
+++ b/app/services/merge_requests/merge_service.rb
@@ -84,7 +84,7 @@ module MergeRequests
merge_request.update!(merge_commit_sha: commit_id)
ensure
- merge_request.update_column(:in_progress_merge_commit_sha, nil)
+ merge_request.update_and_mark_in_progress_merge_commit_sha(nil)
end
def try_merge
diff --git a/app/services/merge_requests/merge_to_ref_service.rb b/app/services/merge_requests/merge_to_ref_service.rb
index 1876b1096fe..c0115e94903 100644
--- a/app/services/merge_requests/merge_to_ref_service.rb
+++ b/app/services/merge_requests/merge_to_ref_service.rb
@@ -58,8 +58,15 @@ module MergeRequests
params[:first_parent_ref] || merge_request.target_branch_ref
end
+ ##
+ # The parameter `allow_conflicts` is a flag whether merge conflicts should be merged into diff
+ # Default is false
+ def allow_conflicts
+ params[:allow_conflicts] || false
+ end
+
def commit
- repository.merge_to_ref(current_user, source, merge_request, target_ref, commit_message, first_parent_ref)
+ repository.merge_to_ref(current_user, source, merge_request, target_ref, commit_message, first_parent_ref, allow_conflicts)
rescue Gitlab::Git::PreReceiveError, Gitlab::Git::CommandError => error
raise MergeError, error.message
end
diff --git a/app/services/merge_requests/mergeability_check_service.rb b/app/services/merge_requests/mergeability_check_service.rb
index a3c39fa2e32..627c747203c 100644
--- a/app/services/merge_requests/mergeability_check_service.rb
+++ b/app/services/merge_requests/mergeability_check_service.rb
@@ -88,7 +88,7 @@ module MergeRequests
sleep_sec: retry_lease ? 1.second : 0
}
- in_lock(lease_key, lease_opts, &block)
+ in_lock(lease_key, **lease_opts, &block)
end
def payload
@@ -115,18 +115,20 @@ module MergeRequests
def update_merge_status
return unless merge_request.recheck_merge_status?
+ return merge_request.mark_as_unmergeable if merge_request.broken?
- if can_git_merge? && merge_to_ref
+ merge_to_ref_success = merge_to_ref
+
+ update_diff_discussion_positions! if merge_to_ref_success
+
+ if merge_to_ref_success && can_git_merge?
merge_request.mark_as_mergeable
- update_diff_discussion_positions!
else
merge_request.mark_as_unmergeable
end
end
def update_diff_discussion_positions!
- return if Feature.disabled?(:merge_ref_head_comments, merge_request.target_project, default_enabled: true)
-
Discussions::CaptureDiffNotePositionsService.new(merge_request).execute
end
@@ -151,13 +153,14 @@ module MergeRequests
end
def can_git_merge?
- !merge_request.broken? && repository.can_be_merged?(merge_request.diff_head_sha, merge_request.target_branch)
+ repository.can_be_merged?(merge_request.diff_head_sha, merge_request.target_branch)
end
def merge_to_ref
return true unless merge_ref_auto_sync_enabled?
- result = MergeRequests::MergeToRefService.new(project, merge_request.author).execute(merge_request)
+ params = { allow_conflicts: Feature.enabled?(:display_merge_conflicts_in_diff, project) }
+ result = MergeRequests::MergeToRefService.new(project, merge_request.author, params).execute(merge_request)
result[:status] == :success
end
diff --git a/app/services/merge_requests/refresh_service.rb b/app/services/merge_requests/refresh_service.rb
index 405b8fe9c9e..e5d0b216d6c 100644
--- a/app/services/merge_requests/refresh_service.rb
+++ b/app/services/merge_requests/refresh_service.rb
@@ -85,18 +85,13 @@ module MergeRequests
return if merge_requests.empty?
- commit_analyze_enabled = Feature.enabled?(:branch_push_merge_commit_analyze, @project, default_enabled: true)
- if commit_analyze_enabled
- analyzer = Gitlab::BranchPushMergeCommitAnalyzer.new(
- @commits.reverse,
- relevant_commit_ids: merge_requests.map(&:diff_head_sha)
- )
- end
+ analyzer = Gitlab::BranchPushMergeCommitAnalyzer.new(
+ @commits.reverse,
+ relevant_commit_ids: merge_requests.map(&:diff_head_sha)
+ )
merge_requests.each do |merge_request|
- if commit_analyze_enabled
- merge_request.merge_commit_sha = analyzer.get_merge_commit(merge_request.diff_head_sha)
- end
+ merge_request.merge_commit_sha = analyzer.get_merge_commit(merge_request.diff_head_sha)
MergeRequests::PostMergeService
.new(merge_request.target_project, @current_user)
@@ -184,7 +179,7 @@ module MergeRequests
def abort_auto_merge_with_todo(merge_request, reason)
response = abort_auto_merge(merge_request, reason)
- response = ServiceResponse.new(response)
+ response = ServiceResponse.new(**response)
return unless response.success?
todo_service.merge_request_became_unmergeable(merge_request)
diff --git a/app/services/merge_requests/update_service.rb b/app/services/merge_requests/update_service.rb
index 1468bfd6bb6..8c069ea5bb0 100644
--- a/app/services/merge_requests/update_service.rb
+++ b/app/services/merge_requests/update_service.rb
@@ -112,6 +112,8 @@ module MergeRequests
end
def handle_reviewers_change(merge_request, old_reviewers)
+ create_reviewer_note(merge_request, old_reviewers)
+ notification_service.async.changed_reviewer_of_merge_request(merge_request, current_user, old_reviewers)
todo_service.reassigned_reviewable(merge_request, current_user, old_reviewers)
end
diff --git a/app/services/metrics/dashboard/custom_dashboard_service.rb b/app/services/metrics/dashboard/custom_dashboard_service.rb
index f0f19bf2ba3..bde8e86851a 100644
--- a/app/services/metrics/dashboard/custom_dashboard_service.rb
+++ b/app/services/metrics/dashboard/custom_dashboard_service.rb
@@ -42,6 +42,12 @@ module Metrics
def cache_key
"project_#{project.id}_metrics_dashboard_#{dashboard_path}"
end
+
+ def sequence
+ [
+ ::Gitlab::Metrics::Dashboard::Stages::CustomDashboardMetricsInserter
+ ] + super
+ end
end
end
end
diff --git a/app/services/metrics/dashboard/dynamic_embed_service.rb b/app/services/metrics/dashboard/dynamic_embed_service.rb
index 0b198ecbbe9..a94538668c1 100644
--- a/app/services/metrics/dashboard/dynamic_embed_service.rb
+++ b/app/services/metrics/dashboard/dynamic_embed_service.rb
@@ -18,7 +18,7 @@ module Metrics
# Determines whether the provided params are sufficient
# to uniquely identify a panel from a yml-defined dashboard.
#
- # See https://docs.gitlab.com/ee/operations/metrics/dashboards/index.html#defining-custom-dashboards-per-project
+ # See https://docs.gitlab.com/ee/operations/metrics/dashboards/index.html
# for additional info on defining custom dashboards.
def valid_params?(params)
[
diff --git a/app/services/namespace_settings/update_service.rb b/app/services/namespace_settings/update_service.rb
new file mode 100644
index 00000000000..3c9b7b637ac
--- /dev/null
+++ b/app/services/namespace_settings/update_service.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+module NamespaceSettings
+ class UpdateService
+ include ::Gitlab::Allowable
+
+ attr_reader :current_user, :group, :settings_params
+
+ def initialize(current_user, group, settings)
+ @current_user = current_user
+ @group = group
+ @settings_params = settings
+ end
+
+ def execute
+ if group.namespace_settings
+ group.namespace_settings.attributes = settings_params
+ else
+ group.build_namespace_settings(settings_params)
+ end
+ end
+ end
+end
+
+NamespaceSettings::UpdateService.prepend_if_ee('EE::NamespaceSettings::UpdateService')
diff --git a/app/services/notes/create_service.rb b/app/services/notes/create_service.rb
index e26f662a697..48f44affb23 100644
--- a/app/services/notes/create_service.rb
+++ b/app/services/notes/create_service.rb
@@ -70,7 +70,7 @@ module Notes
Gitlab::Tracking.event('Notes::CreateService', 'execute', tracking_data_for(note))
end
- if Feature.enabled?(:merge_ref_head_comments, project, default_enabled: true) && note.for_merge_request? && note.diff_note? && note.start_of_discussion?
+ if note.for_merge_request? && note.diff_note? && note.start_of_discussion?
Discussions::CaptureDiffNotePositionService.new(note.noteable, note.diff_file&.paths).execute(note.discussion)
end
end
diff --git a/app/services/notification_recipients/build_service.rb b/app/services/notification_recipients/build_service.rb
index 0fe0d26d7b2..040ecc29d3a 100644
--- a/app/services/notification_recipients/build_service.rb
+++ b/app/services/notification_recipients/build_service.rb
@@ -13,8 +13,8 @@ module NotificationRecipients
NotificationRecipient.new(user, *args).notifiable?
end
- def self.build_recipients(*args)
- ::NotificationRecipients::Builder::Default.new(*args).notification_recipients
+ def self.build_recipients(target, current_user, **args)
+ ::NotificationRecipients::Builder::Default.new(target, current_user, **args).notification_recipients
end
def self.build_new_note_recipients(*args)
@@ -25,8 +25,8 @@ module NotificationRecipients
::NotificationRecipients::Builder::MergeRequestUnmergeable.new(*args).notification_recipients
end
- def self.build_project_maintainers_recipients(*args)
- ::NotificationRecipients::Builder::ProjectMaintainers.new(*args).notification_recipients
+ def self.build_project_maintainers_recipients(target, **args)
+ ::NotificationRecipients::Builder::ProjectMaintainers.new(target, **args).notification_recipients
end
def self.build_new_release_recipients(*args)
diff --git a/app/services/notification_recipients/builder/default.rb b/app/services/notification_recipients/builder/default.rb
index 790ce57452c..19527ba84e6 100644
--- a/app/services/notification_recipients/builder/default.rb
+++ b/app/services/notification_recipients/builder/default.rb
@@ -34,6 +34,9 @@ module NotificationRecipients
when :reassign_merge_request, :reassign_issue
add_recipients(previous_assignees, :mention, nil)
add_recipients(target.assignees, :mention, NotificationReason::ASSIGNED)
+ when :change_reviewer_merge_request
+ add_recipients(previous_assignees, :mention, nil)
+ add_recipients(target.reviewers, :mention, NotificationReason::REVIEW_REQUESTED)
end
add_subscribed_users
diff --git a/app/services/notification_service.rb b/app/services/notification_service.rb
index 731d72c41d4..7853ad11c64 100644
--- a/app/services/notification_service.rb
+++ b/app/services/notification_service.rb
@@ -238,6 +238,33 @@ class NotificationService
end
end
+ # When we change reviewer in a merge_request we should send an email to:
+ #
+ # * merge_request old reviewers if their notification level is not Disabled
+ # * merge_request new reviewers if their notification level is not Disabled
+ # * users with custom level checked with "change reviewer merge request"
+ #
+ def changed_reviewer_of_merge_request(merge_request, current_user, previous_reviewers = [])
+ recipients = NotificationRecipients::BuildService.build_recipients(
+ merge_request,
+ current_user,
+ action: "change_reviewer",
+ previous_assignees: previous_reviewers
+ )
+
+ previous_reviewer_ids = previous_reviewers.map(&:id)
+
+ recipients.each do |recipient|
+ mailer.changed_reviewer_of_merge_request_email(
+ recipient.user.id,
+ merge_request.id,
+ previous_reviewer_ids,
+ current_user.id,
+ recipient.reason
+ ).deliver_later
+ end
+ end
+
# When we add labels to a merge request we should send an email to:
#
# * watchers of the mr's labels
@@ -408,6 +435,10 @@ class NotificationService
mailer.member_invited_email(group_member.real_source_type, group_member.id, token).deliver_later
end
+ def invite_member_reminder(group_member, token, reminder_index)
+ mailer.member_invited_reminder_email(group_member.real_source_type, group_member.id, token, reminder_index).deliver_later
+ end
+
def accept_group_invite(group_member)
mailer.member_invite_accepted_email(group_member.real_source_type, group_member.id).deliver_later
end
diff --git a/app/services/packages/composer/composer_json_service.rb b/app/services/packages/composer/composer_json_service.rb
index 6ffb5a77da3..98aabd84d3d 100644
--- a/app/services/packages/composer/composer_json_service.rb
+++ b/app/services/packages/composer/composer_json_service.rb
@@ -3,6 +3,8 @@
module Packages
module Composer
class ComposerJsonService
+ InvalidJson = Class.new(StandardError)
+
def initialize(project, target)
@project, @target = project, target
end
@@ -20,11 +22,11 @@ module Packages
Gitlab::Json.parse(composer_file.data)
rescue JSON::ParserError
- raise 'Could not parse composer.json file. Invalid JSON.'
+ raise InvalidJson, 'Could not parse composer.json file. Invalid JSON.'
end
def composer_file_not_found!
- raise 'The file composer.json was not found.'
+ raise InvalidJson, 'The file composer.json was not found.'
end
end
end
diff --git a/app/services/packages/create_event_service.rb b/app/services/packages/create_event_service.rb
new file mode 100644
index 00000000000..d009cba2812
--- /dev/null
+++ b/app/services/packages/create_event_service.rb
@@ -0,0 +1,37 @@
+# frozen_string_literal: true
+
+module Packages
+ class CreateEventService < BaseService
+ def execute
+ event_scope = scope.is_a?(::Packages::Package) ? scope.package_type : scope
+
+ ::Packages::Event.create!(
+ event_type: event_name,
+ originator: current_user&.id,
+ originator_type: originator_type,
+ event_scope: event_scope
+ )
+ end
+
+ private
+
+ def scope
+ params[:scope]
+ end
+
+ def event_name
+ params[:event_name]
+ end
+
+ def originator_type
+ case current_user
+ when User
+ :user
+ when DeployToken
+ :deploy_token
+ else
+ :guest
+ end
+ end
+ end
+end
diff --git a/app/services/packages/create_package_service.rb b/app/services/packages/create_package_service.rb
index 397a5f74e0a..e3b0ad218e2 100644
--- a/app/services/packages/create_package_service.rb
+++ b/app/services/packages/create_package_service.rb
@@ -10,6 +10,7 @@ module Packages
.with_package_type(package_type)
.safe_find_or_create_by!(name: name, version: version) do |pkg|
pkg.creator = package_creator
+ yield pkg if block_given?
end
end
diff --git a/app/services/packages/generic/create_package_file_service.rb b/app/services/packages/generic/create_package_file_service.rb
new file mode 100644
index 00000000000..4d49c63799f
--- /dev/null
+++ b/app/services/packages/generic/create_package_file_service.rb
@@ -0,0 +1,38 @@
+# frozen_string_literal: true
+
+module Packages
+ module Generic
+ class CreatePackageFileService < BaseService
+ def execute
+ ::Packages::Package.transaction do
+ create_package_file(find_or_create_package)
+ end
+ end
+
+ private
+
+ def find_or_create_package
+ package_params = {
+ name: params[:package_name],
+ version: params[:package_version],
+ build: params[:build]
+ }
+
+ ::Packages::Generic::FindOrCreatePackageService
+ .new(project, current_user, package_params)
+ .execute
+ end
+
+ def create_package_file(package)
+ file_params = {
+ file: params[:file],
+ size: params[:file].size,
+ file_sha256: params[:file].sha256,
+ file_name: params[:file_name]
+ }
+
+ ::Packages::CreatePackageFileService.new(package, file_params).execute
+ end
+ end
+ end
+end
diff --git a/app/services/packages/generic/find_or_create_package_service.rb b/app/services/packages/generic/find_or_create_package_service.rb
new file mode 100644
index 00000000000..8a8459d167e
--- /dev/null
+++ b/app/services/packages/generic/find_or_create_package_service.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+module Packages
+ module Generic
+ class FindOrCreatePackageService < ::Packages::CreatePackageService
+ def execute
+ find_or_create_package!(::Packages::Package.package_types['generic']) do |package|
+ if params[:build].present?
+ package.build_info = Packages::BuildInfo.new(pipeline: params[:build].pipeline)
+ 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 16ba42bd317..17405002d8d 100644
--- a/app/services/personal_access_tokens/revoke_service.rb
+++ b/app/services/personal_access_tokens/revoke_service.rb
@@ -2,11 +2,12 @@
module PersonalAccessTokens
class RevokeService
- attr_reader :token, :current_user
+ attr_reader :token, :current_user, :group
- def initialize(current_user = nil, params = { token: nil })
+ def initialize(current_user = nil, params = { token: nil, group: nil })
@current_user = current_user
@token = params[:token]
+ @group = params[:group]
end
def execute
@@ -34,3 +35,5 @@ module PersonalAccessTokens
end
end
end
+
+PersonalAccessTokens::RevokeService.prepend_if_ee('EE::PersonalAccessTokens::RevokeService')
diff --git a/app/services/pod_logs/base_service.rb b/app/services/pod_logs/base_service.rb
index 8936f9b67a5..e4b6ad31e33 100644
--- a/app/services/pod_logs/base_service.rb
+++ b/app/services/pod_logs/base_service.rb
@@ -10,6 +10,8 @@ module PodLogs
CACHE_KEY_GET_POD_LOG = 'get_pod_log'
K8S_NAME_MAX_LENGTH = 253
+ self.reactive_cache_work_type = :external_dependency
+
def id
cluster.id
end
diff --git a/app/services/pod_logs/elasticsearch_service.rb b/app/services/pod_logs/elasticsearch_service.rb
index f79562c8ab3..58d1bfbf835 100644
--- a/app/services/pod_logs/elasticsearch_service.rb
+++ b/app/services/pod_logs/elasticsearch_service.rb
@@ -11,7 +11,6 @@ module PodLogs
:pod_logs,
:filter_return_keys
- self.reactive_cache_work_type = :external_dependency
self.reactive_cache_worker_finder = ->(id, _cache_key, namespace, params) { new(::Clusters::Cluster.find(id), namespace, params: params) }
private
diff --git a/app/services/pod_logs/kubernetes_service.rb b/app/services/pod_logs/kubernetes_service.rb
index b573ceae1aa..03b84f98973 100644
--- a/app/services/pod_logs/kubernetes_service.rb
+++ b/app/services/pod_logs/kubernetes_service.rb
@@ -17,7 +17,6 @@ module PodLogs
:split_logs,
:filter_return_keys
- self.reactive_cache_work_type = :external_dependency
self.reactive_cache_worker_finder = ->(id, _cache_key, namespace, params) { new(::Clusters::Cluster.find(id), namespace, params: params) }
private
diff --git a/app/services/projects/alerting/notify_service.rb b/app/services/projects/alerting/notify_service.rb
index bfce5f1ad63..affac45fc3d 100644
--- a/app/services/projects/alerting/notify_service.rb
+++ b/app/services/projects/alerting/notify_service.rb
@@ -7,43 +7,34 @@ module Projects
include ::IncidentManagement::Settings
def execute(token)
+ return bad_request unless valid_payload_size?
return forbidden unless alerts_service_activated?
return unauthorized unless valid_token?(token)
- alert = process_alert
+ process_alert
return bad_request unless alert.persisted?
- process_incident_issues(alert) if process_issues?
+ process_incident_issues if process_issues?
send_alert_email if send_email?
ServiceResponse.success
- rescue Gitlab::Alerting::NotificationPayloadParser::BadPayloadError
- bad_request
end
private
delegate :alerts_service, :alerts_service_activated?, to: :project
- def am_alert_params
- strong_memoize(:am_alert_params) do
- Gitlab::AlertManagement::AlertParams.from_generic_alert(project: project, payload: params.to_h)
- end
- end
-
def process_alert
- existing_alert = find_alert_by_fingerprint(am_alert_params[:fingerprint])
-
- if existing_alert
- process_existing_alert(existing_alert)
+ if alert.persisted?
+ process_existing_alert
else
create_alert
end
end
- def process_existing_alert(alert)
- if am_alert_params[:ended_at].present?
- process_resolved_alert(alert)
+ def process_existing_alert
+ if incoming_payload.ends_at.present?
+ process_resolved_alert
else
alert.register_new_event!
end
@@ -51,10 +42,10 @@ module Projects
alert
end
- def process_resolved_alert(alert)
+ def process_resolved_alert
return unless auto_close_incident?
- if alert.resolve(am_alert_params[:ended_at])
+ if alert.resolve(incoming_payload.ends_at)
close_issue(alert.issue)
end
@@ -72,20 +63,16 @@ module Projects
end
def create_alert
- alert = AlertManagement::Alert.create(am_alert_params.except(:ended_at))
- alert.execute_services if alert.persisted?
- SystemNoteService.create_new_alert(alert, 'Generic Alert Endpoint')
-
- alert
- end
-
- def find_alert_by_fingerprint(fingerprint)
- return unless fingerprint
+ return unless alert.save
- AlertManagement::Alert.not_resolved.for_fingerprint(project, fingerprint).first
+ alert.execute_services
+ SystemNoteService.create_new_alert(
+ alert,
+ alert.monitoring_tool || 'Generic Alert Endpoint'
+ )
end
- def process_incident_issues(alert)
+ def process_incident_issues
return if alert.issue
::IncidentManagement::ProcessAlertWorker.perform_async(nil, nil, alert.id)
@@ -94,11 +81,33 @@ module Projects
def send_alert_email
notification_service
.async
- .prometheus_alerts_fired(project, [parsed_payload])
+ .prometheus_alerts_fired(project, [alert.attributes])
+ end
+
+ def alert
+ strong_memoize(:alert) do
+ existing_alert || new_alert
+ end
+ end
+
+ def existing_alert
+ return unless incoming_payload.gitlab_fingerprint
+
+ AlertManagement::Alert.not_resolved.for_fingerprint(project, incoming_payload.gitlab_fingerprint).first
+ end
+
+ def new_alert
+ AlertManagement::Alert.new(**incoming_payload.alert_params, ended_at: nil)
+ end
+
+ def incoming_payload
+ strong_memoize(:incoming_payload) do
+ Gitlab::AlertManagement::Payload.parse(project, params.to_h)
+ end
end
- def parsed_payload
- Gitlab::Alerting::NotificationPayloadParser.call(params.to_h, project)
+ def valid_payload_size?
+ Gitlab::Utils::DeepSize.new(params).valid?
end
def valid_token?(token)
diff --git a/app/services/projects/container_repository/cleanup_tags_service.rb b/app/services/projects/container_repository/cleanup_tags_service.rb
index 31500043544..b8047a1ad71 100644
--- a/app/services/projects/container_repository/cleanup_tags_service.rb
+++ b/app/services/projects/container_repository/cleanup_tags_service.rb
@@ -4,7 +4,6 @@ module Projects
module ContainerRepository
class CleanupTagsService < BaseService
def execute(container_repository)
- return error('feature disabled') unless can_use?
return error('access denied') unless can_destroy?
return error('invalid regex') unless valid_regex?
@@ -74,10 +73,6 @@ module Projects
can?(current_user, :destroy_container_image, project)
end
- def can_use?
- Feature.enabled?(:container_registry_cleanup, project, default_enabled: true)
- end
-
def valid_regex?
%w(name_regex_delete name_regex name_regex_keep).each do |param_name|
regex = params[param_name]
diff --git a/app/services/projects/container_repository/delete_tags_service.rb b/app/services/projects/container_repository/delete_tags_service.rb
index fa3de4ae2ac..9fc3ec0aafb 100644
--- a/app/services/projects/container_repository/delete_tags_service.rb
+++ b/app/services/projects/container_repository/delete_tags_service.rb
@@ -26,9 +26,7 @@ module Projects
end
def delete_service
- fast_delete_enabled = Feature.enabled?(:container_registry_fast_tag_delete, default_enabled: true)
-
- if fast_delete_enabled && @container_repository.client.supports_tag_delete?
+ if @container_repository.client.supports_tag_delete?
::Projects::ContainerRepository::Gitlab::DeleteTagsService.new(@container_repository, @tag_names)
else
::Projects::ContainerRepository::ThirdParty::DeleteTagsService.new(@container_repository, @tag_names)
diff --git a/app/services/projects/create_from_template_service.rb b/app/services/projects/create_from_template_service.rb
index a207fd2c574..45b52a1861c 100644
--- a/app/services/projects/create_from_template_service.rb
+++ b/app/services/projects/create_from_template_service.rb
@@ -14,10 +14,16 @@ module Projects
def execute
return project unless validate_template!
- file = built_in_template&.file
+ file = built_in_template&.file || sample_data_template&.file
override_params = params.dup
- params[:file] = file
+
+ if built_in_template
+ params[:file] = built_in_template.file
+ elsif sample_data_template
+ params[:file] = sample_data_template.file
+ params[:sample_data] = true
+ end
GitlabProjectsImportService.new(current_user, params, override_params).execute
ensure
@@ -27,7 +33,7 @@ module Projects
private
def validate_template!
- return true if built_in_template
+ return true if built_in_template || sample_data_template
project.errors.add(:template_name, _("'%{template_name}' is unknown or invalid" % { template_name: template_name }))
false
@@ -39,6 +45,12 @@ module Projects
end
end
+ def sample_data_template
+ strong_memoize(:sample_data_template) do
+ Gitlab::SampleDataTemplate.find(template_name)
+ end
+ end
+
def project
@project ||= ::Project.new(namespace_id: params[:namespace_id])
end
diff --git a/app/services/projects/create_service.rb b/app/services/projects/create_service.rb
index 68b40fdd8f1..8f18a23aa0f 100644
--- a/app/services/projects/create_service.rb
+++ b/app/services/projects/create_service.rb
@@ -19,6 +19,10 @@ module Projects
@project = Project.new(params)
+ # If a project is newly created it should have shared runners settings
+ # based on its group having it enabled. This is like the "default value"
+ @project.shared_runners_enabled = false if !params.key?(:shared_runners_enabled) && @project.group && @project.group.shared_runners_setting != 'enabled'
+
# Make sure that the user is allowed to use the specified visibility level
if project_visibility.restricted?
deny_visibility_level(@project, project_visibility.visibility_level)
@@ -143,7 +147,7 @@ module Projects
def create_readme
commit_attrs = {
- branch_name: Gitlab::CurrentSettings.default_branch_name.presence || 'master',
+ branch_name: @project.default_branch || 'master',
commit_message: 'Initial commit',
file_path: 'README.md',
file_content: "# #{@project.name}\n\n#{@project.description}"
@@ -161,10 +165,9 @@ module Projects
@project.create_or_update_import_data(data: @import_data[:data], credentials: @import_data[:credentials]) if @import_data
if @project.save
- unless @project.gitlab_project_import?
- create_services_from_active_instances_or_templates(@project)
- @project.create_labels
- end
+ Service.create_from_active_default_integrations(@project, :project_id, with_templates: true)
+
+ @project.create_labels unless @project.gitlab_project_import?
unless @project.import?
raise 'Failed to create repository' unless @project.create_repository
@@ -228,15 +231,6 @@ module Projects
private
- # rubocop: disable CodeReuse/ActiveRecord
- def create_services_from_active_instances_or_templates(project)
- Service.active.where(instance: true).or(Service.active.where(template: true)).group_by(&:type).each do |type, records|
- service = records.find(&:instance?) || records.find(&:template?)
- Service.build_from_integration(project.id, service).save!
- end
- end
- # rubocop: enable CodeReuse/ActiveRecord
-
def project_namespace
@project_namespace ||= Namespace.find_by_id(@params[:namespace_id]) || current_user.namespace
end
diff --git a/app/services/projects/gitlab_projects_import_service.rb b/app/services/projects/gitlab_projects_import_service.rb
index 2e192942b9c..27cce15f97d 100644
--- a/app/services/projects/gitlab_projects_import_service.rb
+++ b/app/services/projects/gitlab_projects_import_service.rb
@@ -66,6 +66,7 @@ module Projects
end
if template_file
+ data[:sample_data] = params.delete(:sample_data) if params.key?(:sample_data)
params[:import_type] = 'gitlab_project'
end
diff --git a/app/services/projects/operations/update_service.rb b/app/services/projects/operations/update_service.rb
index 7af489c3751..7dfe7fffa1b 100644
--- a/app/services/projects/operations/update_service.rb
+++ b/app/services/projects/operations/update_service.rb
@@ -18,6 +18,7 @@ module Projects
.merge(grafana_integration_params)
.merge(prometheus_integration_params)
.merge(incident_management_setting_params)
+ .merge(tracing_setting_params)
end
def alerting_setting_params
@@ -121,6 +122,15 @@ module Projects
{ incident_management_setting_attributes: attrs }
end
+
+ def tracing_setting_params
+ attr = params[:tracing_setting_attributes]
+ return {} unless attr
+
+ destroy = attr[:external_url].blank?
+
+ { tracing_setting_attributes: attr.merge(_destroy: destroy) }
+ end
end
end
end
diff --git a/app/services/projects/overwrite_project_service.rb b/app/services/projects/overwrite_project_service.rb
index 958a00afbb8..e681b5643ee 100644
--- a/app/services/projects/overwrite_project_service.rb
+++ b/app/services/projects/overwrite_project_service.rb
@@ -32,12 +32,12 @@ module Projects
def move_before_destroy_relationships(source_project)
options = { remove_remaining_elements: false }
- ::Projects::MoveUsersStarProjectsService.new(@project, @current_user).execute(source_project, options)
- ::Projects::MoveAccessService.new(@project, @current_user).execute(source_project, options)
- ::Projects::MoveDeployKeysProjectsService.new(@project, @current_user).execute(source_project, options)
- ::Projects::MoveNotificationSettingsService.new(@project, @current_user).execute(source_project, options)
- ::Projects::MoveForksService.new(@project, @current_user).execute(source_project, options)
- ::Projects::MoveLfsObjectsProjectsService.new(@project, @current_user).execute(source_project, options)
+ ::Projects::MoveUsersStarProjectsService.new(@project, @current_user).execute(source_project, **options)
+ ::Projects::MoveAccessService.new(@project, @current_user).execute(source_project, **options)
+ ::Projects::MoveDeployKeysProjectsService.new(@project, @current_user).execute(source_project, **options)
+ ::Projects::MoveNotificationSettingsService.new(@project, @current_user).execute(source_project, **options)
+ ::Projects::MoveForksService.new(@project, @current_user).execute(source_project, **options)
+ ::Projects::MoveLfsObjectsProjectsService.new(@project, @current_user).execute(source_project, **options)
add_source_project_to_fork_network(source_project)
end
diff --git a/app/services/projects/prometheus/alerts/notify_service.rb b/app/services/projects/prometheus/alerts/notify_service.rb
index d32ead76d00..c002aca32db 100644
--- a/app/services/projects/prometheus/alerts/notify_service.rb
+++ b/app/services/projects/prometheus/alerts/notify_service.rb
@@ -125,7 +125,7 @@ module Projects
notification_service
.async
- .prometheus_alerts_fired(project, firings)
+ .prometheus_alerts_fired(project, alerts_attributes)
end
def process_prometheus_alerts
@@ -136,6 +136,18 @@ module Projects
end
end
+ def alerts_attributes
+ firings.map do |payload|
+ alert_params = Gitlab::AlertManagement::Payload.parse(
+ project,
+ payload,
+ monitoring_tool: Gitlab::AlertManagement::Payload::MONITORING_TOOLS[:prometheus]
+ ).alert_params
+
+ AlertManagement::Alert.new(alert_params).attributes
+ end
+ end
+
def bad_request
ServiceResponse.error(message: 'Bad Request', http_status: :bad_request)
end
diff --git a/app/services/projects/transfer_service.rb b/app/services/projects/transfer_service.rb
index dba5177718d..013861631a1 100644
--- a/app/services/projects/transfer_service.rb
+++ b/app/services/projects/transfer_service.rb
@@ -88,6 +88,10 @@ module Projects
# Move uploads
move_project_uploads(project)
+ # If a project is being transferred to another group it means it can already
+ # have shared runners enabled but we need to check whether the new group allows that.
+ project.shared_runners_enabled = false if project.group && project.group.shared_runners_setting == 'disabled_and_unoverridable'
+
project.old_path_with_namespace = @old_path
update_repository_configuration(@new_path)
diff --git a/app/services/projects/update_pages_service.rb b/app/services/projects/update_pages_service.rb
index ea37f2e4ec0..64b9eca9014 100644
--- a/app/services/projects/update_pages_service.rb
+++ b/app/services/projects/update_pages_service.rb
@@ -97,6 +97,7 @@ module Projects
build.artifacts_file.use_file do |artifacts_path|
SafeZip::Extract.new(artifacts_path)
.extract(directories: [PUBLIC_DIR], to: temp_path)
+ create_pages_deployment(artifacts_path)
end
rescue SafeZip::Extract::Error => e
raise FailedToExtractError, e.message
@@ -118,6 +119,21 @@ module Projects
FileUtils.rm_r(previous_public_path, force: true)
end
+ def create_pages_deployment(artifacts_path)
+ return unless Feature.enabled?(:zip_pages_deployments, project)
+
+ File.open(artifacts_path) do |file|
+ deployment = project.pages_deployments.create!(file: file)
+ project.pages_metadatum.update!(pages_deployment: deployment)
+ end
+
+ # TODO: schedule old deployment removal https://gitlab.com/gitlab-org/gitlab/-/issues/235730
+ rescue => e
+ # we don't want to break current pages deployment process if something goes wrong
+ # TODO: remove this rescue as part of https://gitlab.com/gitlab-org/gitlab/-/issues/245308
+ Gitlab::ErrorTracking.track_and_raise_for_dev_exception(e)
+ end
+
def latest?
# check if sha for the ref is still the most recent one
# this helps in case when multiple deployments happens
diff --git a/app/services/projects/update_remote_mirror_service.rb b/app/services/projects/update_remote_mirror_service.rb
index 5c41f00aac2..6115db54829 100644
--- a/app/services/projects/update_remote_mirror_service.rb
+++ b/app/services/projects/update_remote_mirror_service.rb
@@ -2,12 +2,14 @@
module Projects
class UpdateRemoteMirrorService < BaseService
+ include Gitlab::Utils::StrongMemoize
+
MAX_TRIES = 3
def execute(remote_mirror, tries)
return success unless remote_mirror.enabled?
- if Gitlab::UrlBlocker.blocked_url?(CGI.unescape(Gitlab::UrlSanitizer.sanitize(remote_mirror.url)))
+ if Gitlab::UrlBlocker.blocked_url?(normalized_url(remote_mirror.url))
return error("The remote mirror URL is invalid.")
end
@@ -27,6 +29,12 @@ module Projects
private
+ def normalized_url(url)
+ strong_memoize(:normalized_url) do
+ CGI.unescape(Gitlab::UrlSanitizer.sanitize(url))
+ end
+ end
+
def update_mirror(remote_mirror)
remote_mirror.update_start!
remote_mirror.ensure_remote!
@@ -47,7 +55,6 @@ module Projects
end
def send_lfs_objects!(remote_mirror)
- return unless Feature.enabled?(:push_mirror_syncs_lfs, project)
return unless project.lfs_enabled?
# TODO: Support LFS sync over SSH
diff --git a/app/services/quick_actions/target_service.rb b/app/services/quick_actions/target_service.rb
index 4273acfbf8b..a465632ccfb 100644
--- a/app/services/quick_actions/target_service.rb
+++ b/app/services/quick_actions/target_service.rb
@@ -17,12 +17,16 @@ module QuickActions
# rubocop: disable CodeReuse/ActiveRecord
def issue(type_id)
+ return project.issues.build if type_id.nil?
+
IssuesFinder.new(current_user, project_id: project.id).find_by(iid: type_id) || project.issues.build
end
# rubocop: enable CodeReuse/ActiveRecord
# rubocop: disable CodeReuse/ActiveRecord
def merge_request(type_id)
+ return project.merge_requests.build if type_id.nil?
+
MergeRequestsFinder.new(current_user, project_id: project.id).find_by(iid: type_id) || project.merge_requests.build
end
# rubocop: enable CodeReuse/ActiveRecord
diff --git a/app/services/releases/base_service.rb b/app/services/releases/base_service.rb
new file mode 100644
index 00000000000..15d040287a3
--- /dev/null
+++ b/app/services/releases/base_service.rb
@@ -0,0 +1,89 @@
+# frozen_string_literal: true
+
+module Releases
+ class BaseService
+ include BaseServiceUtility
+ include Gitlab::Utils::StrongMemoize
+
+ attr_accessor :project, :current_user, :params
+
+ def initialize(project, user = nil, params = {})
+ @project, @current_user, @params = project, user, params.dup
+ end
+
+ delegate :repository, to: :project
+
+ def tag_name
+ params[:tag]
+ end
+
+ def ref
+ params[:ref]
+ end
+
+ def name
+ params[:name] || tag_name
+ end
+
+ def description
+ params[:description]
+ end
+
+ def released_at
+ params[:released_at]
+ end
+
+ def release
+ strong_memoize(:release) do
+ project.releases.find_by_tag(tag_name)
+ end
+ end
+
+ def existing_tag
+ strong_memoize(:existing_tag) do
+ repository.find_tag(tag_name)
+ end
+ end
+
+ def tag_exist?
+ existing_tag.present?
+ end
+
+ def repository
+ strong_memoize(:repository) do
+ project.repository
+ end
+ end
+
+ def milestones
+ return [] unless param_for_milestone_titles_provided?
+
+ strong_memoize(:milestones) do
+ MilestonesFinder.new(
+ project: project,
+ current_user: current_user,
+ project_ids: Array(project.id),
+ group_ids: Array(project_group_id),
+ state: 'all',
+ title: params[:milestones]
+ ).execute
+ end
+ end
+
+ def inexistent_milestones
+ return [] unless param_for_milestone_titles_provided?
+
+ existing_milestone_titles = milestones.map(&:title)
+ Array(params[:milestones]) - existing_milestone_titles
+ end
+
+ def param_for_milestone_titles_provided?
+ params.key?(:milestones)
+ end
+
+ # overridden in EE
+ def project_group_id; end
+ end
+end
+
+Releases::BaseService.prepend_if_ee('EE::Releases::BaseService')
diff --git a/app/services/releases/concerns.rb b/app/services/releases/concerns.rb
deleted file mode 100644
index a0ebaea77c8..00000000000
--- a/app/services/releases/concerns.rb
+++ /dev/null
@@ -1,77 +0,0 @@
-# frozen_string_literal: true
-
-module Releases
- module Concerns
- extend ActiveSupport::Concern
- include Gitlab::Utils::StrongMemoize
-
- included do
- def tag_name
- params[:tag]
- end
-
- def ref
- params[:ref]
- end
-
- def name
- params[:name] || tag_name
- end
-
- def description
- params[:description]
- end
-
- def released_at
- params[:released_at]
- end
-
- def release
- strong_memoize(:release) do
- project.releases.find_by_tag(tag_name)
- end
- end
-
- def existing_tag
- strong_memoize(:existing_tag) do
- repository.find_tag(tag_name)
- end
- end
-
- def tag_exist?
- existing_tag.present?
- end
-
- def repository
- strong_memoize(:repository) do
- project.repository
- end
- end
-
- def milestones
- return [] unless param_for_milestone_titles_provided?
-
- strong_memoize(:milestones) do
- MilestonesFinder.new(
- project: project,
- current_user: current_user,
- project_ids: Array(project.id),
- state: 'all',
- title: params[:milestones]
- ).execute
- end
- end
-
- def inexistent_milestones
- return [] unless param_for_milestone_titles_provided?
-
- existing_milestone_titles = milestones.map(&:title)
- Array(params[:milestones]) - existing_milestone_titles
- end
-
- def param_for_milestone_titles_provided?
- params.key?(:milestones)
- end
- end
- end
-end
diff --git a/app/services/releases/create_evidence_service.rb b/app/services/releases/create_evidence_service.rb
index 9c370722d2c..78b6d77c2cb 100644
--- a/app/services/releases/create_evidence_service.rb
+++ b/app/services/releases/create_evidence_service.rb
@@ -12,7 +12,7 @@ module Releases
summary = ::Evidences::EvidenceSerializer.new.represent(evidence, evidence_options) # rubocop: disable CodeReuse/Serializer
evidence.summary = summary
- # TODO: fix the sha generating https://gitlab.com/gitlab-org/gitlab/-/issues/209000
+ # TODO: fix the sha generation https://gitlab.com/groups/gitlab-org/-/epics/3683
evidence.summary_sha = Gitlab::CryptoHelper.sha256(summary)
evidence.save!
diff --git a/app/services/releases/create_service.rb b/app/services/releases/create_service.rb
index 92a0b875dd4..887c2d355ee 100644
--- a/app/services/releases/create_service.rb
+++ b/app/services/releases/create_service.rb
@@ -1,9 +1,7 @@
# frozen_string_literal: true
module Releases
- class CreateService < BaseService
- include Releases::Concerns
-
+ class CreateService < Releases::BaseService
def execute
return error('Access Denied', 403) unless allowed?
return error('Release already exists', 409) if release
diff --git a/app/services/releases/destroy_service.rb b/app/services/releases/destroy_service.rb
index f9f6101abdd..8abf9308689 100644
--- a/app/services/releases/destroy_service.rb
+++ b/app/services/releases/destroy_service.rb
@@ -1,9 +1,7 @@
# frozen_string_literal: true
module Releases
- class DestroyService < BaseService
- include Releases::Concerns
-
+ class DestroyService < Releases::BaseService
def execute
return error('Release does not exist', 404) unless release
return error('Access Denied', 403) unless allowed?
diff --git a/app/services/releases/update_service.rb b/app/services/releases/update_service.rb
index a452f7aa17a..4786d35f31e 100644
--- a/app/services/releases/update_service.rb
+++ b/app/services/releases/update_service.rb
@@ -1,9 +1,7 @@
# frozen_string_literal: true
module Releases
- class UpdateService < BaseService
- include Releases::Concerns
-
+ class UpdateService < Releases::BaseService
def execute
return error('Tag does not exist', 404) unless existing_tag
return error('Release does not exist', 404) unless release
@@ -16,10 +14,18 @@ module Releases
params[:milestones] = milestones
end
- if release.update(params)
- success(tag: existing_tag, release: release, milestones_updated: milestones_updated?(previous_milestones))
- else
- error(release.errors.messages || '400 Bad request', 400)
+ # transaction needed as Rails applies `save!` to milestone_releases
+ # when it does assign_attributes instead of actual saving
+ # this leads to the validation error being raised
+ # see https://gitlab.com/gitlab-org/gitlab/-/merge_requests/43385
+ ActiveRecord::Base.transaction do
+ if release.update(params)
+ success(tag: existing_tag, release: release, milestones_updated: milestones_updated?(previous_milestones))
+ else
+ error(release.errors.messages || '400 Bad request', 400)
+ end
+ rescue ActiveRecord::RecordInvalid => e
+ error(e.message || '400 Bad request', 400)
end
end
diff --git a/app/services/repository_archive_clean_up_service.rb b/app/services/repository_archive_clean_up_service.rb
index 99a9c834352..0fb7dfdb85f 100644
--- a/app/services/repository_archive_clean_up_service.rb
+++ b/app/services/repository_archive_clean_up_service.rb
@@ -1,8 +1,23 @@
# frozen_string_literal: true
+# RepositoryArchiveCleanUpService removes cached repository archives
+# that are generated on-the-fly by Gitaly. These files are stored in the
+# following form (as defined in lib/gitlab/git/repository.rb) and served
+# by GitLab Workhorse:
+#
+# /path/to/repository/downloads/project-N/sha/@v2/archive.format
+#
+# Legacy paths omit the @v2 prefix.
+#
+# For example:
+#
+# /var/opt/gitlab/gitlab-rails/shared/cache/archive/project-1/master/@v2/archive.zip
class RepositoryArchiveCleanUpService
LAST_MODIFIED_TIME_IN_MINUTES = 120
+ # For `/path/project-N/sha/@v2/archive.zip`, `find /path -maxdepth 4` will find this file
+ MAX_ARCHIVE_DEPTH = 4
+
attr_reader :mmin, :path
def initialize(mmin = LAST_MODIFIED_TIME_IN_MINUTES)
@@ -22,12 +37,15 @@ class RepositoryArchiveCleanUpService
private
def clean_up_old_archives
- run(%W(find #{path} -mindepth 1 -maxdepth 3 -type f \( -name \*.tar -o -name \*.bz2 -o -name \*.tar.gz -o -name \*.zip \) -mmin +#{mmin} -delete))
+ run(%W(find #{path} -mindepth 1 -maxdepth #{MAX_ARCHIVE_DEPTH} -type f \( -name \*.tar -o -name \*.bz2 -o -name \*.tar.gz -o -name \*.zip \) -mmin +#{mmin} -delete))
end
def clean_up_empty_directories
- run(%W(find #{path} -mindepth 2 -maxdepth 2 -type d -empty -delete))
- run(%W(find #{path} -mindepth 1 -maxdepth 1 -type d -empty -delete))
+ (1...MAX_ARCHIVE_DEPTH).reverse_each { |depth| clean_up_empty_directories_with_depth(depth) }
+ end
+
+ def clean_up_empty_directories_with_depth(depth)
+ run(%W(find #{path} -mindepth #{depth} -maxdepth #{depth} -type d -empty -delete))
end
def run(cmd)
diff --git a/app/services/resource_access_tokens/create_service.rb b/app/services/resource_access_tokens/create_service.rb
index c253154c1b7..cdeb57627a8 100644
--- a/app/services/resource_access_tokens/create_service.rb
+++ b/app/services/resource_access_tokens/create_service.rb
@@ -10,7 +10,6 @@ module ResourceAccessTokens
end
def execute
- return unless feature_enabled?
return error("User does not have permission to create #{resource_type} Access Token") unless has_permission_to_create?
user = create_user
@@ -31,21 +30,8 @@ module ResourceAccessTokens
attr_reader :resource_type, :resource
- def feature_enabled?
- return false if ::Gitlab.com?
-
- ::Feature.enabled?(:resource_access_token, resource, default_enabled: true)
- end
-
def has_permission_to_create?
- case resource_type
- when 'project'
- can?(current_user, :admin_project, resource)
- when 'group'
- can?(current_user, :admin_group, resource)
- else
- false
- end
+ %w(project group).include?(resource_type) && can?(current_user, :admin_resource_access_tokens, resource)
end
def create_user
@@ -103,7 +89,7 @@ module ResourceAccessTokens
end
def provision_access(resource, user)
- resource.add_maintainer(user)
+ resource.add_user(user, :maintainer, expires_at: params[:expires_at])
end
def error(message)
diff --git a/app/services/resource_access_tokens/revoke_service.rb b/app/services/resource_access_tokens/revoke_service.rb
index efeb0bfb8d5..ece928dac31 100644
--- a/app/services/resource_access_tokens/revoke_service.rb
+++ b/app/services/resource_access_tokens/revoke_service.rb
@@ -14,18 +14,15 @@ module ResourceAccessTokens
end
def execute
+ return error("#{current_user.name} cannot delete #{bot_user.name}") unless can_destroy_bot_member?
return error("Failed to find bot user") unless find_member
- PersonalAccessToken.transaction do
- access_token.revoke!
+ access_token.revoke!
- raise RevokeAccessTokenError, "Failed to remove #{bot_user.name} member from: #{resource.name}" unless remove_member
+ destroy_bot_user
- raise RevokeAccessTokenError, "Migration to ghost user failed" unless migrate_to_ghost_user
- end
-
- success("Revoked access token: #{access_token.name}")
- rescue ActiveRecord::ActiveRecordError, RevokeAccessTokenError => error
+ success("Access token #{access_token.name} has been revoked and the bot user has been scheduled for deletion.")
+ rescue StandardError => error
log_error("Failed to revoke access token for #{bot_user.name}: #{error.message}")
error(error.message)
end
@@ -34,12 +31,18 @@ module ResourceAccessTokens
attr_reader :current_user, :access_token, :bot_user, :resource
- def remove_member
- ::Members::DestroyService.new(current_user).execute(find_member, destroy_bot: true)
+ def destroy_bot_user
+ DeleteUserWorker.perform_async(current_user.id, bot_user.id, skip_authorization: true)
end
- def migrate_to_ghost_user
- ::Users::MigrateToGhostUserService.new(bot_user).execute
+ def can_destroy_bot_member?
+ if resource.is_a?(Project)
+ can?(current_user, :admin_project_member, @resource)
+ elsif resource.is_a?(Group)
+ can?(current_user, :admin_group_member, @resource)
+ else
+ false
+ end
end
def find_member
diff --git a/app/services/search/global_service.rb b/app/services/search/global_service.rb
index fab02697cf0..5f80b07aa59 100644
--- a/app/services/search/global_service.rb
+++ b/app/services/search/global_service.rb
@@ -4,6 +4,8 @@ module Search
class GlobalService
include Gitlab::Utils::StrongMemoize
+ ALLOWED_SCOPES = %w(issues merge_requests milestones users).freeze
+
attr_accessor :current_user, :params
def initialize(user, params)
@@ -14,7 +16,8 @@ module Search
Gitlab::SearchResults.new(current_user,
params[:search],
projects,
- filters: { state: params[:state] })
+ sort: params[:sort],
+ filters: { state: params[:state], confidential: params[:confidential] })
end
def projects
@@ -22,10 +25,7 @@ module Search
end
def allowed_scopes
- strong_memoize(:allowed_scopes) do
- allowed_scopes = %w[issues merge_requests milestones]
- allowed_scopes << 'users' if Feature.enabled?(:users_search, default_enabled: true)
- end
+ ALLOWED_SCOPES
end
def scope
diff --git a/app/services/search/group_service.rb b/app/services/search/group_service.rb
index 68778aa2768..e17522dcd68 100644
--- a/app/services/search/group_service.rb
+++ b/app/services/search/group_service.rb
@@ -16,7 +16,8 @@ module Search
params[:search],
projects,
group: group,
- filters: { state: params[:state] }
+ sort: params[:sort],
+ filters: { state: params[:state], confidential: params[:confidential] }
)
end
diff --git a/app/services/search/project_service.rb b/app/services/search/project_service.rb
index 5eba909c23b..d32534303be 100644
--- a/app/services/search/project_service.rb
+++ b/app/services/search/project_service.rb
@@ -2,6 +2,10 @@
module Search
class ProjectService
+ include Gitlab::Utils::StrongMemoize
+
+ ALLOWED_SCOPES = %w(notes issues merge_requests milestones wiki_blobs commits users).freeze
+
attr_accessor :project, :current_user, :params
def initialize(project, user, params)
@@ -13,15 +17,18 @@ module Search
params[:search],
project: project,
repository_ref: params[:repository_ref],
- filters: { state: params[:state] })
+ sort: params[:sort],
+ filters: { confidential: params[:confidential], state: params[:state] }
+ )
end
- def scope
- @scope ||= begin
- allowed_scopes = %w[notes issues merge_requests milestones wiki_blobs commits]
- allowed_scopes << 'users' if Feature.enabled?(:users_search, default_enabled: true)
+ def allowed_scopes
+ ALLOWED_SCOPES
+ end
- allowed_scopes.delete(params[:scope]) { 'blobs' }
+ def scope
+ strong_memoize(:scope) do
+ allowed_scopes.include?(params[:scope]) ? params[:scope] : 'blobs'
end
end
end
diff --git a/app/services/search_service.rb b/app/services/search_service.rb
index 278cf389e07..3ccd67c8d30 100644
--- a/app/services/search_service.rb
+++ b/app/services/search_service.rb
@@ -65,6 +65,10 @@ class SearchService
@search_objects ||= redact_unauthorized_results(search_results.objects(scope, page: params[:page], per_page: per_page, preload_method: preload_method))
end
+ def search_highlight
+ search_results.highlight_map(scope)
+ end
+
private
def per_page
diff --git a/app/services/snippets/base_service.rb b/app/services/snippets/base_service.rb
index 53a04e5a398..278857b7933 100644
--- a/app/services/snippets/base_service.rb
+++ b/app/services/snippets/base_service.rb
@@ -4,6 +4,9 @@ module Snippets
class BaseService < ::BaseService
include SpamCheckMethods
+ UPDATE_COMMIT_MSG = 'Update snippet'
+ INITIAL_COMMIT_MSG = 'Initial commit'
+
CreateRepositoryError = Class.new(StandardError)
attr_reader :uploaded_assets, :snippet_actions
@@ -85,5 +88,20 @@ module Snippets
def restricted_files_actions
nil
end
+
+ def commit_attrs(snippet, msg)
+ {
+ branch_name: snippet.default_branch,
+ message: msg
+ }
+ end
+
+ def delete_repository(snippet)
+ snippet.repository.remove
+ snippet.snippet_repository&.delete
+
+ # Purge any existing value for repository_exists?
+ snippet.repository.expire_exists_cache
+ end
end
end
diff --git a/app/services/snippets/create_service.rb b/app/services/snippets/create_service.rb
index 5c9b2eb1aea..d7181883c39 100644
--- a/app/services/snippets/create_service.rb
+++ b/app/services/snippets/create_service.rb
@@ -59,7 +59,7 @@ module Snippets
log_error(e.message)
# If the commit action failed we need to remove the repository if exists
- @snippet.repository.remove if @snippet.repository_exists?
+ delete_repository(@snippet) if @snippet.repository_exists?
# If the snippet was created, we need to remove it as we
# would do like if it had had any validation error
@@ -81,12 +81,9 @@ module Snippets
end
def create_commit
- commit_attrs = {
- branch_name: @snippet.default_branch,
- message: 'Initial commit'
- }
+ attrs = commit_attrs(@snippet, INITIAL_COMMIT_MSG)
- @snippet.snippet_repository.multi_files_action(current_user, files_to_commit(@snippet), commit_attrs)
+ @snippet.snippet_repository.multi_files_action(current_user, files_to_commit(@snippet), **attrs)
end
def move_temporary_files
diff --git a/app/services/snippets/repository_validation_service.rb b/app/services/snippets/repository_validation_service.rb
index 5bf5e692ef4..7e9b2eded16 100644
--- a/app/services/snippets/repository_validation_service.rb
+++ b/app/services/snippets/repository_validation_service.rb
@@ -52,7 +52,7 @@ module Snippets
def check_file_count!
file_count = repository.ls_files(snippet.default_branch).size
- limit = Snippet.max_file_limit(current_user)
+ limit = Snippet.max_file_limit
if file_count > limit
raise RepositoryValidationError, _('Repository files count over the limit')
diff --git a/app/services/snippets/update_service.rb b/app/services/snippets/update_service.rb
index a0e9ab6ffda..0115cd19287 100644
--- a/app/services/snippets/update_service.rb
+++ b/app/services/snippets/update_service.rb
@@ -37,7 +37,10 @@ module Snippets
# is implemented.
# Once we can perform different operations through this service
# we won't need to keep track of the `content` and `file_name` fields
- if snippet_actions.any?
+ #
+ # If the repository does not exist we don't need to update `params`
+ # because we need to commit the information from the database
+ if snippet_actions.any? && snippet.repository_exists?
params[:content] = snippet_actions[0].content if snippet_actions[0].content
params[:file_name] = snippet_actions[0].file_path
end
@@ -52,7 +55,11 @@ module Snippets
# the repository we can just return
return true unless committable_attributes?
- create_repository_for(snippet)
+ unless snippet.repository_exists?
+ create_repository_for(snippet)
+ create_first_commit_using_db_data(snippet)
+ end
+
create_commit(snippet)
true
@@ -72,13 +79,7 @@ module Snippets
# If the commit action failed we remove it because
# we don't want to leave empty repositories
# around, to allow cloning them.
- if repository_empty?(snippet)
- snippet.repository.remove
- snippet.snippet_repository&.delete
- end
-
- # Purge any existing value for repository_exists?
- snippet.repository.expire_exists_cache
+ delete_repository(snippet) if repository_empty?(snippet)
false
end
@@ -89,15 +90,25 @@ module Snippets
raise CreateRepositoryError, 'Repository could not be created' unless snippet.repository_exists?
end
+ # If the user provides `snippet_actions` and the repository
+ # does not exist, we need to commit first the snippet info stored
+ # in the database. Mostly because the content inside `snippet_actions`
+ # would assume that the file is already in the repository.
+ def create_first_commit_using_db_data(snippet)
+ return if snippet_actions.empty?
+
+ attrs = commit_attrs(snippet, INITIAL_COMMIT_MSG)
+ actions = [{ file_path: snippet.file_name, content: snippet.content }]
+
+ snippet.snippet_repository.multi_files_action(current_user, actions, **attrs)
+ end
+
def create_commit(snippet)
raise UpdateError unless snippet.snippet_repository
- commit_attrs = {
- branch_name: snippet.default_branch,
- message: 'Update snippet'
- }
+ attrs = commit_attrs(snippet, UPDATE_COMMIT_MSG)
- snippet.snippet_repository.multi_files_action(current_user, files_to_commit(snippet), commit_attrs)
+ snippet.snippet_repository.multi_files_action(current_user, files_to_commit(snippet), **attrs)
end
# Because we are removing repositories we don't want to remove
diff --git a/app/services/spam/spam_action_service.rb b/app/services/spam/spam_action_service.rb
index b745b67f566..b3d617256ff 100644
--- a/app/services/spam/spam_action_service.rb
+++ b/app/services/spam/spam_action_service.rb
@@ -45,7 +45,7 @@ module Spam
attr_reader :user, :context
def allowlisted?(user)
- user.respond_to?(:gitlab_employee) && user.gitlab_employee?
+ user.try(:gitlab_employee?) || user.try(:gitlab_bot?) || user.try(:gitlab_service_user?)
end
def perform_spam_service_check(api)
diff --git a/app/services/static_site_editor/config_service.rb b/app/services/static_site_editor/config_service.rb
index 987ee071976..7b3115468a5 100644
--- a/app/services/static_site_editor/config_service.rb
+++ b/app/services/static_site_editor/config_service.rb
@@ -4,18 +4,38 @@ module StaticSiteEditor
class ConfigService < ::BaseContainerService
ValidationError = Class.new(StandardError)
- def execute
+ def initialize(container:, current_user: nil, params: {})
+ super
+
@project = container
+ @repository = project.repository
+ @ref = params.fetch(:ref)
+ end
+
+ def execute
check_access!
+ file_config = load_file_config!
+ file_data = file_config.to_hash_with_defaults
+ generated_data = load_generated_config.data
+
+ check_for_duplicate_keys!(generated_data, file_data)
+ data = merged_data(generated_data, file_data)
+
ServiceResponse.success(payload: data)
rescue ValidationError => e
ServiceResponse.error(message: e.message)
+ rescue => e
+ Gitlab::ErrorTracking.track_and_raise_exception(e)
end
private
- attr_reader :project
+ attr_reader :project, :repository, :ref
+
+ def static_site_editor_config_file
+ '.gitlab/static-site-editor.yml'
+ end
def check_access!
unless can?(current_user, :download_code, project)
@@ -23,27 +43,43 @@ module StaticSiteEditor
end
end
- def data
- check_for_duplicate_keys!
- generated_data.merge(file_data)
+ def load_file_config!
+ yaml = yaml_from_repo.presence || '{}'
+ file_config = Gitlab::StaticSiteEditor::Config::FileConfig.new(yaml)
+
+ unless file_config.valid?
+ raise ValidationError, file_config.errors.first
+ end
+
+ file_config
+ rescue Gitlab::StaticSiteEditor::Config::FileConfig::ConfigError => e
+ raise ValidationError, e.message
end
- def generated_data
- @generated_data ||= Gitlab::StaticSiteEditor::Config::GeneratedConfig.new(
- project.repository,
- params.fetch(:ref),
+ def load_generated_config
+ Gitlab::StaticSiteEditor::Config::GeneratedConfig.new(
+ repository,
+ ref,
params.fetch(:path),
params[:return_url]
- ).data
- end
-
- def file_data
- @file_data ||= Gitlab::StaticSiteEditor::Config::FileConfig.new.data
+ )
end
- def check_for_duplicate_keys!
+ def check_for_duplicate_keys!(generated_data, file_data)
duplicate_keys = generated_data.keys & file_data.keys
raise ValidationError.new("Duplicate key(s) '#{duplicate_keys}' found.") if duplicate_keys.present?
end
+
+ def merged_data(generated_data, file_data)
+ generated_data.merge(file_data)
+ end
+
+ def yaml_from_repo
+ repository.blob_data_at(ref, static_site_editor_config_file)
+ rescue GRPC::NotFound
+ # Return nil in the case of a GRPC::NotFound exception, so the default config will be used.
+ # Allow any other unexpected exception will be tracked and re-raised.
+ nil
+ end
end
end
diff --git a/app/services/system_note_service.rb b/app/services/system_note_service.rb
index df042fdc393..1a4374f2e94 100644
--- a/app/services/system_note_service.rb
+++ b/app/services/system_note_service.rb
@@ -41,6 +41,10 @@ module SystemNoteService
::SystemNotes::IssuablesService.new(noteable: issuable, project: project, author: author).change_issuable_assignees(old_assignees)
end
+ def change_issuable_reviewers(issuable, project, author, old_reviewers)
+ ::SystemNotes::IssuablesService.new(noteable: issuable, project: project, author: author).change_issuable_reviewers(old_reviewers)
+ end
+
def relate_issue(noteable, noteable_ref, user)
::SystemNotes::IssuablesService.new(noteable: noteable, project: noteable.project, author: user).relate_issue(noteable_ref)
end
@@ -308,6 +312,10 @@ module SystemNoteService
::SystemNotes::AlertManagementService.new(noteable: alert, project: alert.project).create_new_alert(monitoring_tool)
end
+ def change_incident_severity(incident, author)
+ ::SystemNotes::IncidentService.new(noteable: incident, project: incident.project, author: author).change_incident_severity
+ end
+
private
def merge_requests_service(noteable, project, author)
diff --git a/app/services/system_notes/incident_service.rb b/app/services/system_notes/incident_service.rb
new file mode 100644
index 00000000000..4628662f0e9
--- /dev/null
+++ b/app/services/system_notes/incident_service.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+module SystemNotes
+ class IncidentService < ::SystemNotes::BaseService
+ # Called when the severity of an Incident has changed
+ #
+ # Example Note text:
+ #
+ # "changed the severity to Medium - S3"
+ #
+ # Returns the created Note object
+ def change_incident_severity
+ severity = noteable.severity
+
+ if severity_label = IssuableSeverity::SEVERITY_LABELS[severity.to_sym]
+ body = "changed the severity to **#{severity_label}**"
+
+ create_note(NoteSummary.new(noteable, project, author, body, action: 'severity'))
+ else
+ Gitlab::AppLogger.error(
+ message: 'Cannot create a system note for severity change',
+ noteable_class: noteable.class.to_s,
+ noteable_id: noteable.id,
+ severity: severity
+ )
+ end
+ end
+ end
+end
diff --git a/app/services/system_notes/issuables_service.rb b/app/services/system_notes/issuables_service.rb
index 2252503d97e..7a73af0a81a 100644
--- a/app/services/system_notes/issuables_service.rb
+++ b/app/services/system_notes/issuables_service.rb
@@ -13,6 +13,8 @@ module SystemNotes
def relate_issue(noteable_ref)
body = "marked this issue as related to #{noteable_ref.to_reference(noteable.project)}"
+ issue_activity_counter.track_issue_related_action(author: author) if noteable.is_a?(Issue)
+
create_note(NoteSummary.new(noteable, project, author, body, action: 'relate'))
end
@@ -27,6 +29,8 @@ module SystemNotes
def unrelate_issue(noteable_ref)
body = "removed the relation with #{noteable_ref.to_reference(noteable.project)}"
+ issue_activity_counter.track_issue_unrelated_action(author: author) if noteable.is_a?(Issue)
+
create_note(NoteSummary.new(noteable, project, author, body, action: 'unrelate'))
end
@@ -81,6 +85,32 @@ module SystemNotes
create_note(NoteSummary.new(noteable, project, author, body, action: 'assignee'))
end
+ # Called when the reviewers of an issuable is changed or removed
+ #
+ # reviewers - Users being requested to review, or nil
+ #
+ # Example Note text:
+ #
+ # "requested review from @user1 and @user2"
+ #
+ # "requested review from @user1, @user2 and @user3 and removed review request for @user4 and @user5"
+ #
+ # Returns the created Note object
+ def change_issuable_reviewers(old_reviewers)
+ unassigned_users = old_reviewers - noteable.reviewers
+ added_users = noteable.reviewers - old_reviewers
+ text_parts = []
+
+ Gitlab::I18n.with_default_locale do
+ text_parts << "requested review from #{added_users.map(&:to_reference).to_sentence}" if added_users.any?
+ text_parts << "removed review request for #{unassigned_users.map(&:to_reference).to_sentence}" if unassigned_users.any?
+ end
+
+ body = text_parts.join(' and ')
+
+ create_note(NoteSummary.new(noteable, project, author, body, action: 'reviewer'))
+ end
+
# Called when the title of a Noteable is changed
#
# old_title - Previous String title
@@ -148,6 +178,8 @@ module SystemNotes
if noteable.is_a?(ExternalIssue)
noteable.project.external_issue_tracker.create_cross_reference_note(noteable, mentioner, author)
else
+ issue_activity_counter.track_issue_cross_referenced_action(author: author) if noteable.is_a?(Issue)
+
create_note(NoteSummary.new(noteable, noteable.project, author, body, action: 'cross_reference'))
end
end
@@ -182,6 +214,8 @@ module SystemNotes
status_label = new_task.complete? ? Taskable::COMPLETED : Taskable::INCOMPLETE
body = "marked the task **#{new_task.source}** as #{status_label}"
+ issue_activity_counter.track_issue_description_changed_action(author: author) if noteable.is_a?(Issue)
+
create_note(NoteSummary.new(noteable, project, author, body, action: 'task'))
end
@@ -203,6 +237,8 @@ module SystemNotes
cross_reference = noteable_ref.to_reference(project)
body = "moved #{direction} #{cross_reference}"
+ issue_activity_counter.track_issue_moved_action(author: author) if noteable.is_a?(Issue)
+
create_note(NoteSummary.new(noteable, project, author, body, action: 'moved'))
end
@@ -242,19 +278,7 @@ module SystemNotes
#
# Returns the created Note object
def change_status(status, source = nil)
- body = status.dup
- body << " via #{source.gfm_reference(project)}" if source
-
- action = status == 'reopened' ? 'opened' : status
-
- # A state event which results in a synthetic note will be
- # created by EventCreateService if change event tracking
- # is enabled.
- if state_change_tracking_enabled?
- create_resource_state_event(status: status, mentionable_source: source)
- else
- create_note(NoteSummary.new(noteable, project, author, body, action: action))
- end
+ create_resource_state_event(status: status, mentionable_source: source)
end
# Check if a cross reference to a noteable from a mentioner already exists
@@ -285,6 +309,9 @@ module SystemNotes
# Returns the created Note object
def mark_duplicate_issue(canonical_issue)
body = "marked this issue as a duplicate of #{canonical_issue.to_reference(project)}"
+
+ issue_activity_counter.track_issue_marked_as_duplicate_action(author: author) if noteable.is_a?(Issue)
+
create_note(NoteSummary.new(noteable, project, author, body, action: 'duplicate'))
end
@@ -308,27 +335,23 @@ module SystemNotes
action = noteable.discussion_locked? ? 'locked' : 'unlocked'
body = "#{action} this #{noteable.class.to_s.titleize.downcase}"
+ if noteable.is_a?(Issue)
+ if action == 'locked'
+ issue_activity_counter.track_issue_locked_action(author: author)
+ else
+ issue_activity_counter.track_issue_unlocked_action(author: author)
+ end
+ end
+
create_note(NoteSummary.new(noteable, project, author, body, action: action))
end
def close_after_error_tracking_resolve
- if state_change_tracking_enabled?
- create_resource_state_event(status: 'closed', close_after_error_tracking_resolve: true)
- else
- body = 'resolved the corresponding error and closed the issue.'
-
- create_note(NoteSummary.new(noteable, project, author, body, action: 'closed'))
- end
+ create_resource_state_event(status: 'closed', close_after_error_tracking_resolve: true)
end
def auto_resolve_prometheus_alert
- if state_change_tracking_enabled?
- create_resource_state_event(status: 'closed', close_auto_resolve_prometheus_alert: true)
- else
- body = 'automatically closed this issue because the alert resolved.'
-
- create_note(NoteSummary.new(noteable, project, author, body, action: 'closed'))
- end
+ create_resource_state_event(status: 'closed', close_auto_resolve_prometheus_alert: true)
end
private
@@ -361,11 +384,6 @@ module SystemNotes
.execute(params)
end
- def state_change_tracking_enabled?
- noteable.respond_to?(:resource_state_events) &&
- ::Feature.enabled?(:track_resource_state_change_events, noteable.project, default_enabled: true)
- end
-
def issue_activity_counter
Gitlab::UsageDataCounters::IssueActivityUniqueCounter
end
diff --git a/app/services/system_notes/time_tracking_service.rb b/app/services/system_notes/time_tracking_service.rb
index 8de42bd3225..650e40680b1 100644
--- a/app/services/system_notes/time_tracking_service.rb
+++ b/app/services/system_notes/time_tracking_service.rb
@@ -16,6 +16,8 @@ module SystemNotes
def change_due_date(due_date)
body = due_date ? "changed due date to #{due_date.to_s(:long)}" : 'removed due date'
+ issue_activity_counter.track_issue_due_date_changed_action(author: author) if noteable.is_a?(Issue)
+
create_note(NoteSummary.new(noteable, project, author, body, action: 'due_date'))
end
@@ -38,6 +40,8 @@ module SystemNotes
"changed time estimate to #{parsed_time}"
end
+ issue_activity_counter.track_issue_time_estimate_changed_action(author: author) if noteable.is_a?(Issue)
+
create_note(NoteSummary.new(noteable, project, author, body, action: 'time_tracking'))
end
@@ -67,7 +71,15 @@ module SystemNotes
body = text_parts.join(' ')
end
+ issue_activity_counter.track_issue_time_spent_changed_action(author: author) if noteable.is_a?(Issue)
+
create_note(NoteSummary.new(noteable, project, author, body, action: 'time_tracking'))
end
+
+ private
+
+ def issue_activity_counter
+ Gitlab::UsageDataCounters::IssueActivityUniqueCounter
+ end
end
end
diff --git a/app/services/todos/destroy/entity_leave_service.rb b/app/services/todos/destroy/entity_leave_service.rb
index 0c0548a17a1..97c56b84434 100644
--- a/app/services/todos/destroy/entity_leave_service.rb
+++ b/app/services/todos/destroy/entity_leave_service.rb
@@ -7,16 +7,14 @@ module Todos
attr_reader :user, :entity
- # rubocop: disable CodeReuse/ActiveRecord
def initialize(user_id, entity_id, entity_type)
unless %w(Group Project).include?(entity_type)
raise ArgumentError.new("#{entity_type} is not an entity user can leave")
end
- @user = User.find_by(id: user_id)
- @entity = entity_type.constantize.find_by(id: entity_id)
+ @user = UserFinder.new(user_id).find_by_id
+ @entity = entity_type.constantize.find_by(id: entity_id) # rubocop: disable CodeReuse/ActiveRecord
end
- # rubocop: enable CodeReuse/ActiveRecord
def execute
return unless entity && user
@@ -42,34 +40,37 @@ module Todos
end
end
- # rubocop: disable CodeReuse/ActiveRecord
def remove_confidential_issue_todos
- Todo.where(
- target_id: confidential_issues.select(:id), target_type: Issue.name, user_id: user.id
- ).delete_all
+ Todo
+ .for_target(confidential_issues.select(:id))
+ .for_type(Issue.name)
+ .for_user(user)
+ .delete_all
end
- # rubocop: enable CodeReuse/ActiveRecord
- # rubocop: disable CodeReuse/ActiveRecord
def remove_project_todos
# Issues are viewable by guests (even in private projects), so remove those todos
# from projects without guest access
- Todo.where(project_id: non_authorized_guest_projects, user_id: user.id)
+ Todo
+ .for_project(non_authorized_guest_projects)
+ .for_user(user)
.delete_all
# MRs require reporter access, so remove those todos that are not authorized
- Todo.where(project_id: non_authorized_reporter_projects, target_type: MergeRequest.name, user_id: user.id)
+ Todo
+ .for_project(non_authorized_reporter_projects)
+ .for_type(MergeRequest.name)
+ .for_user(user)
.delete_all
end
- # rubocop: enable CodeReuse/ActiveRecord
- # rubocop: disable CodeReuse/ActiveRecord
def remove_group_todos
- Todo.where(group_id: non_authorized_groups, user_id: user.id).delete_all
+ Todo
+ .for_group(non_authorized_groups)
+ .for_user(user)
+ .delete_all
end
- # rubocop: enable CodeReuse/ActiveRecord
- # rubocop: disable CodeReuse/ActiveRecord
def projects
condition = case entity
when Project
@@ -78,55 +79,40 @@ module Todos
{ namespace_id: non_authorized_reporter_groups }
end
- Project.where(condition)
+ Project.where(condition) # rubocop: disable CodeReuse/ActiveRecord
end
- # rubocop: enable CodeReuse/ActiveRecord
- # rubocop: disable CodeReuse/ActiveRecord
def authorized_reporter_projects
user.authorized_projects(Gitlab::Access::REPORTER).select(:id)
end
- # rubocop: enable CodeReuse/ActiveRecord
- # rubocop: disable CodeReuse/ActiveRecord
def authorized_guest_projects
user.authorized_projects(Gitlab::Access::GUEST).select(:id)
end
- # rubocop: enable CodeReuse/ActiveRecord
- # rubocop: disable CodeReuse/ActiveRecord
def non_authorized_reporter_projects
- projects.where('id NOT IN (?)', authorized_reporter_projects)
+ projects.id_not_in(authorized_reporter_projects)
end
- # rubocop: enable CodeReuse/ActiveRecord
- # rubocop: disable CodeReuse/ActiveRecord
def non_authorized_guest_projects
- projects.where('id NOT IN (?)', authorized_guest_projects)
+ projects.id_not_in(authorized_guest_projects)
end
- # rubocop: enable CodeReuse/ActiveRecord
- # rubocop: disable CodeReuse/ActiveRecord
def authorized_reporter_groups
GroupsFinder.new(user, min_access_level: Gitlab::Access::REPORTER).execute.select(:id)
end
- # rubocop: enable CodeReuse/ActiveRecord
- # rubocop: disable CodeReuse/ActiveRecord
def non_authorized_groups
return [] unless entity.is_a?(Namespace)
entity.self_and_descendants.select(:id)
- .where('id NOT IN (?)', GroupsFinder.new(user).execute.select(:id))
+ .id_not_in(GroupsFinder.new(user).execute.select(:id))
end
- # rubocop: enable CodeReuse/ActiveRecord
- # rubocop: disable CodeReuse/ActiveRecord
def non_authorized_reporter_groups
entity.self_and_descendants.select(:id)
- .where('id NOT IN (?)', authorized_reporter_groups)
+ .id_not_in(authorized_reporter_groups)
end
- # rubocop: enable CodeReuse/ActiveRecord
def user_has_reporter_access?
return unless entity.is_a?(Namespace)
@@ -134,16 +120,16 @@ module Todos
entity.member?(User.find(user.id), Gitlab::Access::REPORTER)
end
- # rubocop: disable CodeReuse/ActiveRecord
def confidential_issues
- assigned_ids = IssueAssignee.select(:issue_id).where(user_id: user.id)
+ assigned_ids = IssueAssignee.select(:issue_id).for_assignee(user)
- Issue.where(project_id: projects, confidential: true)
- .where('project_id NOT IN(?)', authorized_reporter_projects)
- .where('author_id != ?', user.id)
- .where('id NOT IN (?)', assigned_ids)
+ Issue
+ .in_projects(projects)
+ .confidential_only
+ .not_in_projects(authorized_reporter_projects)
+ .not_authored_by(user)
+ .id_not_in(assigned_ids)
end
- # rubocop: enable CodeReuse/ActiveRecord
end
end
end
diff --git a/app/services/users/approve_service.rb b/app/services/users/approve_service.rb
new file mode 100644
index 00000000000..228cfbd6947
--- /dev/null
+++ b/app/services/users/approve_service.rb
@@ -0,0 +1,37 @@
+# frozen_string_literal: true
+
+module Users
+ class ApproveService < BaseService
+ def initialize(current_user)
+ @current_user = current_user
+ end
+
+ def execute(user)
+ return error(_('You are not allowed to approve a user')) unless allowed?
+ return error(_('The user you are trying to approve is not pending an approval')) unless approval_required?(user)
+
+ if user.activate
+ # Resends confirmation email if the user isn't confirmed yet.
+ # Please see Devise's implementation of `resend_confirmation_instructions` for detail.
+ user.resend_confirmation_instructions
+ user.accept_pending_invitations! if user.active_for_authentication?
+
+ success
+ else
+ error(user.errors.full_messages.uniq.join('. '))
+ end
+ end
+
+ private
+
+ attr_reader :current_user
+
+ def allowed?
+ can?(current_user, :approve_user)
+ end
+
+ def approval_required?(user)
+ user.blocked_pending_approval?
+ end
+ end
+end
diff --git a/app/services/users/block_service.rb b/app/services/users/block_service.rb
index 041db731875..8513664ee85 100644
--- a/app/services/users/block_service.rb
+++ b/app/services/users/block_service.rb
@@ -7,6 +7,8 @@ module Users
end
def execute(user)
+ return error('An internal user cannot be blocked', 403) if user.internal?
+
if user.block
after_block_hook(user)
success
diff --git a/app/services/users/build_service.rb b/app/services/users/build_service.rb
index 2fc46f033dd..e3f02bf85f0 100644
--- a/app/services/users/build_service.rb
+++ b/app/services/users/build_service.rb
@@ -104,7 +104,6 @@ module Users
def build_user_params(skip_authorization:)
if current_user&.admin?
user_params = params.slice(*admin_create_params)
- user_params[:created_by_id] = current_user&.id
if params[:reset_password]
user_params.merge!(force_random_password: true, password_expires_at: nil)
@@ -125,6 +124,8 @@ module Users
end
end
+ user_params[:created_by_id] = current_user&.id
+
if user_default_internal_regex_enabled? && !user_params.key?(:external)
user_params[:external] = user_external?
end
diff --git a/app/services/users/destroy_service.rb b/app/services/users/destroy_service.rb
index 436d4fb3985..613d2e4ad82 100644
--- a/app/services/users/destroy_service.rb
+++ b/app/services/users/destroy_service.rb
@@ -26,7 +26,7 @@ module Users
def execute(user, options = {})
delete_solo_owned_groups = options.fetch(:delete_solo_owned_groups, options[:hard_delete])
- unless Ability.allowed?(current_user, :destroy_user, user)
+ unless Ability.allowed?(current_user, :destroy_user, user) || options[:skip_authorization]
raise Gitlab::Access::AccessDeniedError, "#{current_user} tried to destroy user #{user}!"
end
diff --git a/app/services/users/validate_otp_service.rb b/app/services/users/validate_otp_service.rb
new file mode 100644
index 00000000000..a9ce7959aea
--- /dev/null
+++ b/app/services/users/validate_otp_service.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+module Users
+ class ValidateOtpService < BaseService
+ def initialize(current_user)
+ @current_user = current_user
+ @strategy = if Feature.enabled?(:forti_authenticator, current_user)
+ ::Gitlab::Auth::Otp::Strategies::FortiAuthenticator.new(current_user)
+ else
+ ::Gitlab::Auth::Otp::Strategies::Devise.new(current_user)
+ end
+ end
+
+ def execute(otp_code)
+ strategy.validate(otp_code)
+ rescue StandardError => ex
+ Gitlab::ErrorTracking.log_exception(ex)
+ error(message: ex.message)
+ end
+
+ private
+
+ attr_reader :strategy
+ end
+end
diff --git a/app/services/web_hooks/destroy_service.rb b/app/services/web_hooks/destroy_service.rb
new file mode 100644
index 00000000000..58117985b56
--- /dev/null
+++ b/app/services/web_hooks/destroy_service.rb
@@ -0,0 +1,78 @@
+# frozen_string_literal: true
+
+module WebHooks
+ class DestroyService
+ include BaseServiceUtility
+
+ BATCH_SIZE = 1000
+ LOG_COUNT_THRESHOLD = 10000
+
+ DestroyError = Class.new(StandardError)
+
+ attr_accessor :current_user, :web_hook
+
+ def initialize(current_user)
+ @current_user = current_user
+ end
+
+ def execute(web_hook)
+ @web_hook = web_hook
+
+ async = false
+ # For a better user experience, it's better if the Web hook is
+ # destroyed right away without waiting for Sidekiq. However, if
+ # there are a lot of Web hook logs, we will need more time to
+ # clean them up, so schedule a Sidekiq job to do this.
+ if needs_async_destroy?
+ Gitlab::AppLogger.info("User #{current_user&.id} scheduled a deletion of hook ID #{web_hook.id}")
+ async_destroy(web_hook)
+ async = true
+ else
+ sync_destroy(web_hook)
+ end
+
+ success({ async: async })
+ end
+
+ def sync_destroy(web_hook)
+ @web_hook = web_hook
+
+ delete_web_hook_logs
+ result = web_hook.destroy
+
+ if result
+ success({ async: false })
+ else
+ error("Unable to destroy #{web_hook.model_name.human}")
+ end
+ end
+
+ private
+
+ def async_destroy(web_hook)
+ WebHooks::DestroyWorker.perform_async(current_user.id, web_hook.id)
+ end
+
+ # rubocop: disable CodeReuse/ActiveRecord
+ def needs_async_destroy?
+ web_hook.web_hook_logs.limit(LOG_COUNT_THRESHOLD).count == LOG_COUNT_THRESHOLD
+ end
+ # rubocop: enable CodeReuse/ActiveRecord
+
+ def delete_web_hook_logs
+ loop do
+ count = delete_web_hook_logs_in_batches
+ break if count < BATCH_SIZE
+ end
+ end
+
+ # rubocop: disable CodeReuse/ActiveRecord
+ def delete_web_hook_logs_in_batches
+ # We can't use EachBatch because that does an ORDER BY id, which can
+ # easily time out. We don't actually care about ordering when
+ # we are deleting these rows.
+ web_hook.web_hook_logs.limit(BATCH_SIZE).delete_all
+ end
+ # rubocop: enable CodeReuse/ActiveRecord
+ end
+end
diff --git a/app/services/webauthn/authenticate_service.rb b/app/services/webauthn/authenticate_service.rb
index a4513c62c2d..a575a853995 100644
--- a/app/services/webauthn/authenticate_service.rb
+++ b/app/services/webauthn/authenticate_service.rb
@@ -11,12 +11,6 @@ module Webauthn
def execute
parsed_device_response = Gitlab::Json.parse(@device_response)
- # appid is set for legacy U2F devices, will be used in a future iteration
- # rp_id = @app_id
- # unless parsed_device_response['clientExtensionResults'] && parsed_device_response['clientExtensionResults']['appid']
- # rp_id = URI(@app_id).host
- # end
-
webauthn_credential = WebAuthn::Credential.from_get(parsed_device_response)
encoded_raw_id = Base64.strict_encode64(webauthn_credential.raw_id)
stored_webauthn_credential = @user.webauthn_registrations.find_by_credential_xid(encoded_raw_id)
@@ -52,10 +46,14 @@ module Webauthn
# Verifies that webauthn_credential matches stored_credential with the given challenge
#
def verify_webauthn_credential(webauthn_credential, stored_credential, challenge, encoder)
+ # We need to adjust the relaying party id (RP id) we verify against if the registration in question
+ # is a migrated U2F registration. This is beacuse the appid of U2F and the rp id of WebAuthn differ.
+ rp_id = webauthn_credential.client_extension_outputs['appid'] ? WebAuthn.configuration.origin : URI(WebAuthn.configuration.origin).host
webauthn_credential.response.verify(
encoder.decode(challenge),
public_key: encoder.decode(stored_credential.public_key),
- sign_count: stored_credential.counter)
+ sign_count: stored_credential.counter,
+ rp_id: rp_id)
end
end
end
diff --git a/app/uploaders/deleted_object_uploader.rb b/app/uploaders/deleted_object_uploader.rb
new file mode 100644
index 00000000000..fc0f62b920c
--- /dev/null
+++ b/app/uploaders/deleted_object_uploader.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+class DeletedObjectUploader < GitlabUploader
+ include ObjectStorage::Concern
+
+ storage_options Gitlab.config.artifacts
+
+ def store_dir
+ model.store_dir
+ end
+end
diff --git a/app/uploaders/pages/deployment_uploader.rb b/app/uploaders/pages/deployment_uploader.rb
new file mode 100644
index 00000000000..e510025fc7d
--- /dev/null
+++ b/app/uploaders/pages/deployment_uploader.rb
@@ -0,0 +1,51 @@
+# frozen_string_literal: true
+
+module Pages
+ class DeploymentUploader < GitlabUploader
+ include ObjectStorage::Concern
+
+ storage_options Gitlab.config.pages
+
+ alias_method :upload, :model
+
+ private
+
+ def dynamic_segment
+ Gitlab::HashedPath.new('pages_deployments', model.id, root_hash: model.project_id)
+ end
+
+ # @hashed is chosen to avoid conflict with namespace name because we use the same directory for storage
+ # @ is not valid character for namespace
+ def base_dir
+ "@hashed"
+ end
+
+ # override GitlabUploader
+ # if set to true it erases the original file when uploading
+ # and we copy from the artifacts archive, so artifacts end up
+ # without the file
+ def move_to_cache
+ false
+ end
+
+ class << self
+ # we only upload this files from the rails background job
+ # so we don't need direct upload for pages deployments
+ # this method is here to ignore any user setting
+ def direct_upload_enabled?
+ false
+ end
+
+ # we don't need background uploads because we upload files
+ # to the right store right away, and we already do that in
+ # the background job
+ def background_upload_enabled?
+ false
+ end
+
+ def default_store
+ object_store_enabled? ? ObjectStorage::Store::REMOTE : ObjectStorage::Store::LOCAL
+ end
+ end
+ end
+end
diff --git a/app/uploaders/terraform/versioned_state_uploader.rb b/app/uploaders/terraform/versioned_state_uploader.rb
index be07993da0f..e50ab6c7dc6 100644
--- a/app/uploaders/terraform/versioned_state_uploader.rb
+++ b/app/uploaders/terraform/versioned_state_uploader.rb
@@ -2,12 +2,22 @@
module Terraform
class VersionedStateUploader < StateUploader
+ delegate :terraform_state, to: :model
+
def filename
- "#{model.version}.tfstate"
+ if terraform_state.versioning_enabled?
+ "#{model.version}.tfstate"
+ else
+ "#{model.uuid}.tfstate"
+ end
end
def store_dir
- Gitlab::HashedPath.new(model.uuid, root_hash: project_id)
+ if terraform_state.versioning_enabled?
+ Gitlab::HashedPath.new(model.uuid, root_hash: project_id)
+ else
+ project_id.to_s
+ end
end
end
end
diff --git a/app/validators/addressable_url_validator.rb b/app/validators/addressable_url_validator.rb
index 9fa99903e36..c6d9bd73566 100644
--- a/app/validators/addressable_url_validator.rb
+++ b/app/validators/addressable_url_validator.rb
@@ -80,7 +80,7 @@ class AddressableUrlValidator < ActiveModel::EachValidator
value = strip_value!(record, attribute, value)
- Gitlab::UrlBlocker.validate!(value, blocker_args)
+ Gitlab::UrlBlocker.validate!(value, **blocker_args)
rescue Gitlab::UrlBlocker::BlockedUrlError => e
record.errors.add(attribute, options.fetch(:blocked_message) % { exception_message: e.message })
end
diff --git a/app/validators/ip_address_validator.rb b/app/validators/ip_address_validator.rb
new file mode 100644
index 00000000000..0acf2bdf4fc
--- /dev/null
+++ b/app/validators/ip_address_validator.rb
@@ -0,0 +1,39 @@
+# frozen_string_literal: true
+
+# IpAddressValidator
+#
+# Validates that an IP address is a valid IPv4 or IPv6 address.
+# This should be coupled with a database column of type `inet`
+#
+# When using column type `inet` Rails will silently return the value
+# as `nil` when the value is not valid according to its type cast
+# using `IpAddr`. It's not very user friendly to return an error
+# "IP Address can't be blank" when a value was clearly given but
+# was not the right format. This validator will look at the value
+# before Rails type casts it when the value itself is `nil`.
+# This enables the validator to return a specific and useful error message.
+#
+# This validator allows `nil` values by default since the database
+# allows null values by default. To disallow `nil` values, use in conjunction
+# with `presence: true`.
+#
+# Do not use this validator with `allow_nil: true` or `allow_blank: true`.
+# Because of Rails type casting, when an invalid value is set the attribute
+# will return `nil` and Rails won't run this validator.
+#
+# Example:
+#
+# class Group < ActiveRecord::Base
+# validates :ip_address, presence: true, ip_address: true
+# end
+#
+class IpAddressValidator < ActiveModel::EachValidator
+ def validate_each(record, attribute, _)
+ value = record.public_send("#{attribute}_before_type_cast") # rubocop:disable GitlabSecurity/PublicSend
+ return if value.blank?
+
+ IPAddress.parse(value.to_s)
+ rescue ArgumentError
+ record.errors.add(attribute, _('must be a valid IPv4 or IPv6 address'))
+ 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 8fde92d6312..08442565931 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
@@ -6,8 +6,8 @@
"type": "string",
"default_value": "",
"value": "",
- "size": "MEDIUM",
- "description": "Analyzer image's registry prefix (or Name of the registry providing the analyzers' image)"
+ "size": "LARGE",
+ "description": "Analyzer image's registry prefix (or name of the registry providing the analyzers' image)"
},
{
"field" : "SAST_EXCLUDED_PATHS",
@@ -15,7 +15,7 @@
"type": "string",
"default_value": "",
"value": "",
- "size": "LARGE",
+ "size": "MEDIUM",
"description": "Comma-separated list of paths to be excluded from analyzer output. Patterns can be globs, file paths, or folder paths."
},
{
diff --git a/app/views/admin/abuse_reports/_abuse_report.html.haml b/app/views/admin/abuse_reports/_abuse_report.html.haml
index 5ed9a0d1adb..ae0da214fb7 100644
--- a/app/views/admin/abuse_reports/_abuse_report.html.haml
+++ b/app/views/admin/abuse_reports/_abuse_report.html.haml
@@ -1,7 +1,7 @@
- reporter = abuse_report.reporter
- user = abuse_report.user
%tr
- %th.d-block.d-sm-none.d-md-none
+ %th.d-block.d-sm-none
%strong= _('User')
%td
- if user
@@ -11,21 +11,22 @@
- else
= _('(removed)')
%td
- %strong.subheading.d-block.d-sm-none.d-md-none
+ %strong.subheading.d-block.d-sm-none
= _('Reported by %{reporter}') % { reporter: reporter ? link_to(reporter.name, reporter) : _('(removed)') }
.light.small
= time_ago_with_tooltip(abuse_report.created_at)
%td
- %strong.subheading.d-block.d-sm-none.d-md-none= _('Message')
+ %strong.subheading.d-block.d-sm-none
+ = _('Message')
.message
= markdown_field(abuse_report, :message)
%td
- if user
= link_to _('Remove user & report'), admin_abuse_report_path(abuse_report, remove_user: true),
- data: { confirm: _("USER %{user} WILL BE REMOVED! Are you sure?") % { user: user.name } }, remote: true, method: :delete, class: "btn btn-sm btn-block btn-remove js-remove-tr"
+ data: { confirm: _("USER %{user} WILL BE REMOVED! Are you sure?") % { user: user.name } }, remote: true, method: :delete, class: "gl-button btn btn-sm btn-block btn-danger js-remove-tr"
- if user && !user.blocked?
- = link_to _('Block user'), block_admin_user_path(user), data: {confirm: _('USER WILL BE BLOCKED! Are you sure?')}, method: :put, class: "btn btn-sm btn-block"
+ = link_to _('Block user'), block_admin_user_path(user), data: {confirm: _('USER WILL BE BLOCKED! Are you sure?')}, method: :put, class: "gl-button btn btn-sm btn-block"
- else
.btn.btn-sm.disabled.btn-block
= _('Already blocked')
- = link_to _('Remove report'), [:admin, abuse_report], remote: true, method: :delete, class: "btn btn-sm btn-block btn-close js-remove-tr"
+ = link_to _('Remove report'), [:admin, abuse_report], remote: true, method: :delete, class: "gl-button btn btn-sm btn-block btn-close js-remove-tr"
diff --git a/app/views/admin/abuse_reports/index.html.haml b/app/views/admin/abuse_reports/index.html.haml
index e3d78b3058f..daa766429e0 100644
--- a/app/views/admin/abuse_reports/index.html.haml
+++ b/app/views/admin/abuse_reports/index.html.haml
@@ -17,7 +17,7 @@
- if @abuse_reports.present?
.table-holder
%table.table.responsive-table
- %thead.d-none.d-sm-none.d-md-table-header-group
+ %thead.d-none.d-md-table-header-group
%tr
%th User
%th Reported by
diff --git a/app/views/admin/application_settings/_abuse.html.haml b/app/views/admin/application_settings/_abuse.html.haml
index ddffec32c41..c77615f9040 100644
--- a/app/views/admin/application_settings/_abuse.html.haml
+++ b/app/views/admin/application_settings/_abuse.html.haml
@@ -3,9 +3,9 @@
%fieldset
.form-group
- = f.label :admin_notification_email, 'Abuse reports notification email', class: 'label-bold'
- = f.text_field :admin_notification_email, class: 'form-control'
+ = f.label :abuse_notification_email, 'Abuse reports notification email', class: 'label-bold'
+ = f.text_field :abuse_notification_email, class: 'form-control'
.form-text.text-muted
Abuse reports will be sent to this address if it is set. Abuse reports are always available in the admin area.
- = f.submit 'Save changes', class: "btn btn-success"
+ = f.submit 'Save changes', class: "gl-button btn btn-success"
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 184249bcaba..f46eb84ce8e 100644
--- a/app/views/admin/application_settings/_account_and_limit.html.haml
+++ b/app/views/admin/application_settings/_account_and_limit.html.haml
@@ -60,5 +60,4 @@
= render_if_exists 'admin/application_settings/updating_name_disabled_for_users', form: f
= render_if_exists 'admin/application_settings/availability_on_namespace_setting', form: f
- .gl-display-flex.gl-justify-content-end
- = f.submit _('Save changes'), class: 'btn btn-success qa-save-changes-button'
+ = f.submit _('Save changes'), class: 'gl-button btn btn-success qa-save-changes-button'
diff --git a/app/views/admin/application_settings/_ci_cd.html.haml b/app/views/admin/application_settings/_ci_cd.html.haml
index b9cce6c8085..9f384519c3a 100644
--- a/app/views/admin/application_settings/_ci_cd.html.haml
+++ b/app/views/admin/application_settings/_ci_cd.html.haml
@@ -60,4 +60,4 @@
= _("The default CI configuration path for new projects.").html_safe
= link_to sprite_icon('question-o'), help_page_path('ci/pipelines/settings', anchor: 'custom-ci-configuration-path'), target: '_blank'
- = f.submit _('Save changes'), class: "btn btn-success"
+ = f.submit _('Save changes'), class: "gl-button btn btn-success"
diff --git a/app/views/admin/application_settings/_diff_limits.html.haml b/app/views/admin/application_settings/_diff_limits.html.haml
index 1bf25b6a558..6811c1e10d6 100644
--- a/app/views/admin/application_settings/_diff_limits.html.haml
+++ b/app/views/admin/application_settings/_diff_limits.html.haml
@@ -12,5 +12,4 @@
= link_to sprite_icon('question-o'),
help_page_path('user/admin_area/diff_limits',
anchor: 'maximum-diff-patch-size')
- .gl-display-flex.gl-justify-content-end
- = f.submit _('Save changes'), class: 'btn btn-success'
+ = f.submit _('Save changes'), class: 'gl-button btn btn-success'
diff --git a/app/views/admin/application_settings/_eks.html.haml b/app/views/admin/application_settings/_eks.html.haml
index d74afcd3e64..68324425ef9 100644
--- a/app/views/admin/application_settings/_eks.html.haml
+++ b/app/views/admin/application_settings/_eks.html.haml
@@ -28,4 +28,4 @@
= f.label :eks_secret_access_key, 'Secret access key', class: 'label-bold'
= f.password_field :eks_secret_access_key, autocomplete: 'off', class: 'form-control'
- = f.submit 'Save changes', class: "btn btn-success"
+ = f.submit 'Save changes', class: "gl-button btn btn-success"
diff --git a/app/views/admin/application_settings/_email.html.haml b/app/views/admin/application_settings/_email.html.haml
index 49747f2bfd4..dd1be876505 100644
--- a/app/views/admin/application_settings/_email.html.haml
+++ b/app/views/admin/application_settings/_email.html.haml
@@ -25,4 +25,4 @@
= render_if_exists 'admin/application_settings/email_additional_text_setting', form: f
- = f.submit _('Save changes'), class: "btn btn-success", data: { qa_selector: 'save_changes_button' }
+ = f.submit _('Save changes'), class: "gl-button btn btn-success", data: { qa_selector: 'save_changes_button' }
diff --git a/app/views/admin/application_settings/_external_authorization_service_form.html.haml b/app/views/admin/application_settings/_external_authorization_service_form.html.haml
index 179eb2d5f2e..c8c1f3e6214 100644
--- a/app/views/admin/application_settings/_external_authorization_service_form.html.haml
+++ b/app/views/admin/application_settings/_external_authorization_service_form.html.haml
@@ -47,5 +47,4 @@
.form-group
= f.label :external_authorization_service_default_label, _('Default classification label'), class: 'label-bold'
= f.text_field :external_authorization_service_default_label, class: 'form-control'
- .gl-display-flex.gl-justify-content-end
- = f.submit 'Save changes', class: "btn btn-success"
+ = f.submit 'Save changes', class: "gl-button btn btn-success"
diff --git a/app/views/admin/application_settings/_gitaly.html.haml b/app/views/admin/application_settings/_gitaly.html.haml
index fac2de8811f..a0cd70b4d7c 100644
--- a/app/views/admin/application_settings/_gitaly.html.haml
+++ b/app/views/admin/application_settings/_gitaly.html.haml
@@ -24,4 +24,4 @@
.form-text.text-muted
Medium operation timeout (in seconds). This should be a value between the Fast and the Default timeout.
- = f.submit 'Save changes', class: "btn btn-success"
+ = f.submit 'Save changes', class: "gl-button btn btn-success"
diff --git a/app/views/admin/application_settings/_gitpod.html.haml b/app/views/admin/application_settings/_gitpod.html.haml
index bbad5155ada..f0a1fd5e763 100644
--- a/app/views/admin/application_settings/_gitpod.html.haml
+++ b/app/views/admin/application_settings/_gitpod.html.haml
@@ -1,6 +1,5 @@
- return unless Gitlab::Gitpod.feature_available?
- expanded = integration_expanded?('gitpod_')
-- gitpod_link = link_to("Gitpod#{sprite_icon('external-link', size: 12, css_class: 'ml-1 vertical-align-center')}".html_safe, 'https://gitpod.io/', target: '_blank', rel: 'noopener noreferrer')
%section.settings.no-animate#js-gitpod-settings{ class: ('expanded' if expanded) }
.settings-header
@@ -9,7 +8,7 @@
%button.btn.btn-default.js-settings-toggle{ type: 'button' }
= expanded ? _('Collapse') : _('Expand')
%p
- = s_('Enable %{gitpod_link} integration to launch a development environment in your browser directly from GitLab.').html_safe % { gitpod_link: gitpod_link }
+ = gitpod_enable_description
= link_to sprite_icon('question-o'), help_page_path('integration/gitpod.md'), target: '_blank', class: 'has-tooltip', title: _('More information')
@@ -27,4 +26,4 @@
= f.text_field :gitpod_url, class: 'form-control', placeholder: s_('Gitpod|e.g. https://gitpod.example.com')
.form-text.text-muted
= s_('Gitpod|Add the URL to your Gitpod instance configured to read your GitLab projects.')
- = f.submit s_('Save changes'), class: 'btn btn-success'
+ = f.submit s_('Save changes'), class: 'gl-button btn btn-success'
diff --git a/app/views/admin/application_settings/_grafana.html.haml b/app/views/admin/application_settings/_grafana.html.haml
index 80ff5a298b4..bd2b2094311 100644
--- a/app/views/admin/application_settings/_grafana.html.haml
+++ b/app/views/admin/application_settings/_grafana.html.haml
@@ -14,4 +14,4 @@
= f.label :grafana_url, _('Grafana URL'), class: 'label-bold'
= f.text_field :grafana_url, class: 'form-control', placeholder: '/-/grafana'
- = f.submit _('Save changes'), class: "btn btn-success"
+ = f.submit _('Save changes'), class: "gl-button btn btn-success"
diff --git a/app/views/admin/application_settings/_help_page.html.haml b/app/views/admin/application_settings/_help_page.html.haml
index 5e5ab1e4269..fc31f612b8c 100644
--- a/app/views/admin/application_settings/_help_page.html.haml
+++ b/app/views/admin/application_settings/_help_page.html.haml
@@ -18,4 +18,9 @@
= f.text_field :help_page_support_url, class: 'form-control', placeholder: 'http://company.example.com/getting-help', :'aria-describedby' => 'support_help_block'
%span.form-text.text-muted#support_help_block= _('Alternate support URL for help page and help dropdown')
- = f.submit _('Save changes'), class: "btn btn-success"
+ - if show_documentation_base_url_field?
+ .form-group
+ = f.label :help_page_documentation_base_url, _('Documentation pages URL'), class: 'label-bold'
+ = f.text_field :help_page_documentation_base_url, class: 'form-control', placeholder: 'https://docs.gitlab.com'
+
+ = f.submit _('Save changes'), class: "gl-button btn btn-success"
diff --git a/app/views/admin/application_settings/_import_export_limits.html.haml b/app/views/admin/application_settings/_import_export_limits.html.haml
index d26c3376391..58218a41282 100644
--- a/app/views/admin/application_settings/_import_export_limits.html.haml
+++ b/app/views/admin/application_settings/_import_export_limits.html.haml
@@ -31,4 +31,4 @@
= f.label :group_download_export_limit, _('Max Group Export Download requests per minute per user'), class: 'label-bold'
= f.number_field :group_download_export_limit, class: 'form-control'
- = f.submit 'Save changes', class: "btn btn-success", data: { qa_selector: 'save_changes_button' }
+ = f.submit 'Save changes', class: "gl-button btn btn-success", data: { qa_selector: 'save_changes_button' }
diff --git a/app/views/admin/application_settings/_initial_branch_name.html.haml b/app/views/admin/application_settings/_initial_branch_name.html.haml
index acbf971e4b9..bab841fcade 100644
--- a/app/views/admin/application_settings/_initial_branch_name.html.haml
+++ b/app/views/admin/application_settings/_initial_branch_name.html.haml
@@ -10,5 +10,4 @@
%span.form-text.text-muted
= (_("Changes affect new repositories only. If not specified, Git's default name %{branch_name_default} will be used.") % { branch_name_default: fallback_branch_name } ).html_safe
- .gl-display-flex.gl-justify-content-end
- = f.submit _('Save changes'), class: 'gl-button btn-success'
+ = f.submit _('Save changes'), class: 'gl-button btn-success'
diff --git a/app/views/admin/application_settings/_ip_limits.html.haml b/app/views/admin/application_settings/_ip_limits.html.haml
index 9512c1837bf..c1565cf42e1 100644
--- a/app/views/admin/application_settings/_ip_limits.html.haml
+++ b/app/views/admin/application_settings/_ip_limits.html.haml
@@ -42,4 +42,4 @@
= f.label :throttle_authenticated_web_period_in_seconds, 'Rate limit period in seconds', class: 'label-bold'
= f.number_field :throttle_authenticated_web_period_in_seconds, class: 'form-control'
- = f.submit 'Save changes', class: "btn btn-success", data: { qa_selector: 'save_changes_button' }
+ = f.submit 'Save changes', class: "gl-button btn btn-success", data: { qa_selector: 'save_changes_button' }
diff --git a/app/views/admin/application_settings/_issue_limits.html.haml b/app/views/admin/application_settings/_issue_limits.html.haml
index b0bdc204f64..200ea3a8ec1 100644
--- a/app/views/admin/application_settings/_issue_limits.html.haml
+++ b/app/views/admin/application_settings/_issue_limits.html.haml
@@ -6,4 +6,4 @@
= f.label :issues_create_limit, 'Max requests per minute per user', class: 'label-bold'
= f.number_field :issues_create_limit, class: 'form-control'
- = f.submit 'Save changes', class: "btn btn-success", data: { qa_selector: 'save_changes_button' }
+ = f.submit 'Save changes', class: "gl-button btn btn-success", data: { qa_selector: 'save_changes_button' }
diff --git a/app/views/admin/application_settings/_localization.html.haml b/app/views/admin/application_settings/_localization.html.haml
index e01c123d1db..5ad7080b22b 100644
--- a/app/views/admin/application_settings/_localization.html.haml
+++ b/app/views/admin/application_settings/_localization.html.haml
@@ -15,4 +15,4 @@
= f.label :time_tracking_limit_to_hours, class: 'form-check-label' do
= _('Limit display of time tracking units to hours.')
- = f.submit _('Save changes'), class: "btn btn-success"
+ = f.submit _('Save changes'), class: "gl-button btn btn-success"
diff --git a/app/views/admin/application_settings/_outbound.html.haml b/app/views/admin/application_settings/_outbound.html.haml
index b0593b3bfa2..4f38ab3ab7a 100644
--- a/app/views/admin/application_settings/_outbound.html.haml
+++ b/app/views/admin/application_settings/_outbound.html.haml
@@ -27,4 +27,4 @@
%span.form-text.text-muted
= _('Resolves IP addresses once and uses them to submit requests')
- = f.submit 'Save changes', class: "btn btn-success", data: { qa_selector: 'save_changes_button' }
+ = f.submit 'Save changes', class: "gl-button btn btn-success", data: { qa_selector: 'save_changes_button' }
diff --git a/app/views/admin/application_settings/_pages.html.haml b/app/views/admin/application_settings/_pages.html.haml
index 2ee7f3edc97..d42987eb7d8 100644
--- a/app/views/admin/application_settings/_pages.html.haml
+++ b/app/views/admin/application_settings/_pages.html.haml
@@ -41,4 +41,4 @@
- terms_of_service_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: lets_encrypt_terms_of_service_admin_application_settings_path }
= _("I have read and agree to the Let's Encrypt %{link_start}Terms of Service%{link_end} (PDF)").html_safe % { link_start: terms_of_service_link_start, link_end: '</a>'.html_safe }
- = f.submit _('Save changes'), class: "btn btn-success"
+ = f.submit _('Save changes'), class: "gl-button btn btn-success"
diff --git a/app/views/admin/application_settings/_performance.html.haml b/app/views/admin/application_settings/_performance.html.haml
index 3473c185dbe..2d27bceef10 100644
--- a/app/views/admin/application_settings/_performance.html.haml
+++ b/app/views/admin/application_settings/_performance.html.haml
@@ -31,4 +31,4 @@
.form-text.text-muted
= _('Number of changes (branches or tags) in a single push to determine whether individual push events or bulk push event will be created. Bulk push event will be created if it surpasses that value.')
- = f.submit 'Save changes', class: "btn btn-success"
+ = f.submit 'Save changes', class: "gl-button btn btn-success"
diff --git a/app/views/admin/application_settings/_performance_bar.html.haml b/app/views/admin/application_settings/_performance_bar.html.haml
index f8bc29048f2..1036cc94bd0 100644
--- a/app/views/admin/application_settings/_performance_bar.html.haml
+++ b/app/views/admin/application_settings/_performance_bar.html.haml
@@ -11,4 +11,4 @@
= f.label :performance_bar_allowed_group_path, 'Allowed group', class: 'label-bold'
= f.text_field :performance_bar_allowed_group_path, class: 'form-control', placeholder: 'my-org/my-group', value: @application_setting.performance_bar_allowed_group&.full_path
- = f.submit 'Save changes', class: 'btn btn-success qa-save-changes-button'
+ = f.submit 'Save changes', class: 'gl-button btn btn-success qa-save-changes-button'
diff --git a/app/views/admin/application_settings/_plantuml.html.haml b/app/views/admin/application_settings/_plantuml.html.haml
index f2011257b8c..324f544a108 100644
--- a/app/views/admin/application_settings/_plantuml.html.haml
+++ b/app/views/admin/application_settings/_plantuml.html.haml
@@ -24,4 +24,4 @@
= link_to "PlantUML", "http://plantuml.com"
diagrams in Asciidoc documents using an external PlantUML service.
- = f.submit _('Save changes'), class: "btn btn-success"
+ = f.submit _('Save changes'), class: "gl-button btn btn-success"
diff --git a/app/views/admin/application_settings/_prometheus.html.haml b/app/views/admin/application_settings/_prometheus.html.haml
index 49f58449d29..c571ec1c1b0 100644
--- a/app/views/admin/application_settings/_prometheus.html.haml
+++ b/app/views/admin/application_settings/_prometheus.html.haml
@@ -30,4 +30,4 @@
A method call is only tracked when it takes longer to complete than
the given amount of milliseconds.
- = f.submit 'Save changes', class: "btn btn-success"
+ = f.submit 'Save changes', class: "gl-button btn btn-success"
diff --git a/app/views/admin/application_settings/_protected_paths.html.haml b/app/views/admin/application_settings/_protected_paths.html.haml
index 0220570daa9..fce64369f17 100644
--- a/app/views/admin/application_settings/_protected_paths.html.haml
+++ b/app/views/admin/application_settings/_protected_paths.html.haml
@@ -28,4 +28,4 @@
= _('All paths are relative to the GitLab URL. Do not include %{relative_url_link_start}relative URL%{relative_url_link_end}.').html_safe % { relative_url_link_start: relative_url_link_start, relative_url_link_end: '</a>'.html_safe }
= f.text_area :protected_paths_raw, placeholder: '/users/sign_in,/users/password', class: 'form-control', rows: 10
- = f.submit 'Save changes', class: 'btn btn-success'
+ = f.submit 'Save changes', class: 'gl-button btn btn-success'
diff --git a/app/views/admin/application_settings/_realtime.html.haml b/app/views/admin/application_settings/_realtime.html.haml
index 0e9731b1c70..cf0b2b53eff 100644
--- a/app/views/admin/application_settings/_realtime.html.haml
+++ b/app/views/admin/application_settings/_realtime.html.haml
@@ -14,4 +14,4 @@
installations. Set to 0 to completely disable polling.
= link_to sprite_icon('question-o'), help_page_path('administration/polling')
- = f.submit 'Save changes', class: "btn btn-success"
+ = f.submit 'Save changes', class: "gl-button btn btn-success"
diff --git a/app/views/admin/application_settings/_registry.html.haml b/app/views/admin/application_settings/_registry.html.haml
index 7ff2b6e841d..dd64d0ae419 100644
--- a/app/views/admin/application_settings/_registry.html.haml
+++ b/app/views/admin/application_settings/_registry.html.haml
@@ -21,4 +21,4 @@
.form-text.text-muted
= _("Tags are deleted until the timeout is reached. Any remaining tags are included the next time the policy runs. To remove the time limit, set it to 0.")
- = f.submit 'Save changes', class: "btn btn-success"
+ = f.submit 'Save changes', class: "gl-button btn btn-success"
diff --git a/app/views/admin/application_settings/_repository_check.html.haml b/app/views/admin/application_settings/_repository_check.html.haml
index 6f9d3a889cd..b9c2e406b78 100644
--- a/app/views/admin/application_settings/_repository_check.html.haml
+++ b/app/views/admin/application_settings/_repository_check.html.haml
@@ -18,8 +18,7 @@
If you got a lot of false alarms from repository checks you can choose to clear all repository check information from the database.
- clear_repository_checks_link = _('Clear all repository checks')
- clear_repository_checks_message = _('This will clear repository check states for ALL projects in the database. This cannot be undone. Are you sure?')
- .gl-display-flex.gl-justify-content-end
- = link_to clear_repository_checks_link, clear_repository_check_states_admin_application_settings_path, data: { confirm: clear_repository_checks_message }, method: :put, class: "btn btn-sm btn-remove"
+ = link_to clear_repository_checks_link, clear_repository_check_states_admin_application_settings_path, data: { confirm: clear_repository_checks_message }, method: :put, class: "gl-button btn btn-sm btn-danger"
.sub-section
%h4 Housekeeping
@@ -56,5 +55,4 @@
.form-text.text-muted
Number of Git pushes after which 'git gc' is run.
- .gl-display-flex.gl-justify-content-end
- = f.submit _('Save changes'), class: "btn btn-success"
+ = f.submit _('Save changes'), class: "gl-button btn btn-success"
diff --git a/app/views/admin/application_settings/_repository_mirrors_form.html.haml b/app/views/admin/application_settings/_repository_mirrors_form.html.haml
index d598f173ff3..125fa48bbc3 100644
--- a/app/views/admin/application_settings/_repository_mirrors_form.html.haml
+++ b/app/views/admin/application_settings/_repository_mirrors_form.html.haml
@@ -14,5 +14,4 @@
= render_if_exists 'admin/application_settings/mirror_settings', form: f
- .gl-display-flex.gl-justify-content-end
- = f.submit _('Save changes'), class: "btn btn-success"
+ = f.submit _('Save changes'), class: "gl-button btn btn-success"
diff --git a/app/views/admin/application_settings/_repository_static_objects.html.haml b/app/views/admin/application_settings/_repository_static_objects.html.haml
index 9bc751adc8b..00b9b4b8964 100644
--- a/app/views/admin/application_settings/_repository_static_objects.html.haml
+++ b/app/views/admin/application_settings/_repository_static_objects.html.haml
@@ -15,5 +15,4 @@
%span.form-text.text-muted#static_objects_external_storage_auth_token_help_block
= _('A secure token that identifies an external storage request.')
- .gl-display-flex.gl-justify-content-end
- = f.submit _('Save changes'), class: "btn btn-success"
+ = f.submit _('Save changes'), class: "gl-button btn btn-success"
diff --git a/app/views/admin/application_settings/_repository_storage.html.haml b/app/views/admin/application_settings/_repository_storage.html.haml
index 0dc8dc0740e..0862d1bf0b6 100644
--- a/app/views/admin/application_settings/_repository_storage.html.haml
+++ b/app/views/admin/application_settings/_repository_storage.html.haml
@@ -22,5 +22,4 @@
= f.text_field attribute[:name], class: 'form-text-input', value: attribute[:value]
= f.label attribute[:label], attribute[:label], class: 'label-bold form-check-label'
%br
- .gl-display-flex.gl-justify-content-end
- = f.submit _('Save changes'), class: "btn btn-success qa-save-changes-button"
+ = f.submit _('Save changes'), class: "gl-button btn btn-success qa-save-changes-button"
diff --git a/app/views/admin/application_settings/_signin.html.haml b/app/views/admin/application_settings/_signin.html.haml
index 2a26a0909fd..4a8616beff6 100644
--- a/app/views/admin/application_settings/_signin.html.haml
+++ b/app/views/admin/application_settings/_signin.html.haml
@@ -57,5 +57,4 @@
= f.label :sign_in_text, class: 'label-bold'
= f.text_area :sign_in_text, class: 'form-control', rows: 4
.form-text.text-muted Markdown enabled
- .gl-display-flex.gl-justify-content-end
- = f.submit 'Save changes', class: "btn btn-success"
+ = f.submit 'Save changes', class: "gl-button btn btn-success"
diff --git a/app/views/admin/application_settings/_signup.html.haml b/app/views/admin/application_settings/_signup.html.haml
index 3b88696dc51..98b49a236a3 100644
--- a/app/views/admin/application_settings/_signup.html.haml
+++ b/app/views/admin/application_settings/_signup.html.haml
@@ -9,6 +9,14 @@
Sign-up enabled
.form-text.text-muted
= _("When enabled, any user visiting %{host} will be able to create an account.") % { host: "#{new_user_session_url(host: Gitlab.config.gitlab.host)}" }
+ - if Feature.enabled?(:admin_approval_for_new_user_signups, default_enabled: true)
+ .form-group
+ .form-check
+ = f.check_box :require_admin_approval_after_user_signup, class: 'form-check-input'
+ = f.label :require_admin_approval_after_user_signup, class: 'form-check-label' do
+ = _('Require admin approval for new sign-ups')
+ .form-text.text-muted
+ = _("When enabled, any user visiting %{host} and creating an account will have to be explicitly approved by an admin before they can sign in. This setting is effective only if sign-ups are enabled.") % { host: "#{new_user_session_url(host: Gitlab.config.gitlab.host)}" }
.form-group
.form-check
= f.check_box :send_user_confirmation_email, class: 'form-check-input'
@@ -67,5 +75,4 @@
= f.label :after_sign_up_text, class: 'label-bold'
= f.text_area :after_sign_up_text, class: 'form-control', rows: 4
.form-text.text-muted Markdown enabled
- .gl-display-flex.gl-justify-content-end
- = f.submit 'Save changes', class: "btn btn-success"
+ = f.submit 'Save changes', class: "gl-button btn btn-success"
diff --git a/app/views/admin/application_settings/_snowplow.html.haml b/app/views/admin/application_settings/_snowplow.html.haml
index c339d6df363..7c2c5e0b3dc 100644
--- a/app/views/admin/application_settings/_snowplow.html.haml
+++ b/app/views/admin/application_settings/_snowplow.html.haml
@@ -26,4 +26,4 @@
= f.label :snowplow_cookie_domain, _('Cookie domain'), class: 'label-light'
= f.text_field :snowplow_cookie_domain, class: 'form-control'
- = f.submit _('Save changes'), class: 'btn btn-success'
+ = f.submit _('Save changes'), class: 'gl-button btn btn-success'
diff --git a/app/views/admin/application_settings/_sourcegraph.html.haml b/app/views/admin/application_settings/_sourcegraph.html.haml
index 7650526dfc0..2a4e8f87c31 100644
--- a/app/views/admin/application_settings/_sourcegraph.html.haml
+++ b/app/views/admin/application_settings/_sourcegraph.html.haml
@@ -35,4 +35,4 @@
= f.text_field :sourcegraph_url, class: 'form-control', placeholder: s_('SourcegraphAdmin|e.g. https://sourcegraph.example.com')
.form-text.text-muted
= s_('SourcegraphAdmin|Configure the URL to a Sourcegraph instance which can read your GitLab projects.')
- = f.submit s_('SourcegraphAdmin|Save changes'), class: 'btn btn-success'
+ = f.submit s_('SourcegraphAdmin|Save changes'), class: 'gl-button btn btn-success'
diff --git a/app/views/admin/application_settings/_spam.html.haml b/app/views/admin/application_settings/_spam.html.haml
index ab9368e723e..b54f1d7c829 100644
--- a/app/views/admin/application_settings/_spam.html.haml
+++ b/app/views/admin/application_settings/_spam.html.haml
@@ -71,4 +71,4 @@
= f.label :spam_check_endpoint_url, _('URL of the external Spam Check endpoint'), class: 'label-bold'
= f.text_field :spam_check_endpoint_url, class: 'form-control'
- = f.submit 'Save changes', class: "btn btn-success"
+ = f.submit 'Save changes', class: "gl-button btn btn-success"
diff --git a/app/views/admin/application_settings/_terminal.html.haml b/app/views/admin/application_settings/_terminal.html.haml
index 25d23ea7a84..7bc5b2405e8 100644
--- a/app/views/admin/application_settings/_terminal.html.haml
+++ b/app/views/admin/application_settings/_terminal.html.haml
@@ -8,5 +8,4 @@
.form-text.text-muted
Maximum time for web terminal websocket connection (in seconds).
0 for unlimited.
- .gl-display-flex.gl-justify-content-end
- = f.submit 'Save changes', class: "btn btn-success"
+ = f.submit 'Save changes', class: "gl-button btn btn-success"
diff --git a/app/views/admin/application_settings/_terms.html.haml b/app/views/admin/application_settings/_terms.html.haml
index a6d03ac1dde..10db1e23d7b 100644
--- a/app/views/admin/application_settings/_terms.html.haml
+++ b/app/views/admin/application_settings/_terms.html.haml
@@ -15,5 +15,4 @@
= f.text_area :terms, class: 'form-control', rows: 8
.form-text.text-muted
= _("Markdown enabled")
- .gl-display-flex.gl-justify-content-end
- = f.submit _("Save changes"), class: "btn btn-success"
+ = f.submit _("Save changes"), class: "gl-button btn btn-success"
diff --git a/app/views/admin/application_settings/_third_party_offers.html.haml b/app/views/admin/application_settings/_third_party_offers.html.haml
index 0ed7341986d..7e3e063118e 100644
--- a/app/views/admin/application_settings/_third_party_offers.html.haml
+++ b/app/views/admin/application_settings/_third_party_offers.html.haml
@@ -17,4 +17,4 @@
= f.check_box :hide_third_party_offers, class: 'form-check-input'
= f.label :hide_third_party_offers, _('Do not display offers from third parties within GitLab'), class: 'form-check-label'
- = f.submit _('Save changes'), class: "btn btn-success"
+ = f.submit _('Save changes'), class: "gl-button btn btn-success"
diff --git a/app/views/admin/application_settings/_usage.html.haml b/app/views/admin/application_settings/_usage.html.haml
index 4e45db1e10a..2ba7dcefd44 100644
--- a/app/views/admin/application_settings/_usage.html.haml
+++ b/app/views/admin/application_settings/_usage.html.haml
@@ -33,8 +33,8 @@
%pre.usage-data.js-syntax-highlight.code.highlight.mt-2.d-none{ class: payload_class, data: { endpoint: usage_data_admin_application_settings_path(format: :html) } }
- else
= _('The usage ping is disabled, and cannot be configured through this form.')
- - deactivating_usage_ping_path = help_page_path('development/telemetry/usage_ping', anchor: 'disable-usage-ping')
+ - deactivating_usage_ping_path = help_page_path('development/product_analytics/usage_ping', anchor: 'disable-usage-ping')
- deactivating_usage_ping_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: deactivating_usage_ping_path }
= s_('For more information, see the documentation on %{deactivating_usage_ping_link_start}deactivating the usage ping%{deactivating_usage_ping_link_end}.').html_safe % { deactivating_usage_ping_link_start: deactivating_usage_ping_link_start, deactivating_usage_ping_link_end: '</a>'.html_safe }
- = f.submit 'Save changes', class: "btn btn-success"
+ = f.submit 'Save changes', class: "gl-button btn btn-success"
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 28208d923db..46d8a8ac9c7 100644
--- a/app/views/admin/application_settings/_visibility_and_access.html.haml
+++ b/app/views/admin/application_settings/_visibility_and_access.html.haml
@@ -66,5 +66,4 @@
.form-group
= f.label field_name, "#{type.upcase} SSH keys", class: 'label-bold'
= f.select field_name, key_restriction_options_for_select(type), {}, class: 'form-control'
- .gl-display-flex.gl-justify-content-end
- = f.submit _('Save changes'), class: "btn btn-success"
+ = f.submit _('Save changes'), class: "gl-button btn btn-success"
diff --git a/app/views/admin/application_settings/general.html.haml b/app/views/admin/application_settings/general.html.haml
index 823cee09d4b..2d336bebc8d 100644
--- a/app/views/admin/application_settings/general.html.haml
+++ b/app/views/admin/application_settings/general.html.haml
@@ -101,8 +101,7 @@
= s_('IDE|Live Preview')
%span.form-text.text-muted
= s_('IDE|Allow live previews of JavaScript projects in the Web IDE using CodeSandbox Live Preview.')
- .gl-display-flex.gl-justify-content-end
- = f.submit _('Save changes'), class: "btn btn-success"
+ = f.submit _('Save changes'), class: "gl-button btn btn-success"
- if Feature.enabled?(:maintenance_mode)
%section.settings.no-animate#js-maintenance-mode-toggle{ class: ('expanded' if expanded_by_default?) }
diff --git a/app/views/admin/applications/_delete_form.html.haml b/app/views/admin/applications/_delete_form.html.haml
index 86f09bf1cb0..d348ad507c2 100644
--- a/app/views/admin/applications/_delete_form.html.haml
+++ b/app/views/admin/applications/_delete_form.html.haml
@@ -1,4 +1,4 @@
-- submit_btn_css ||= 'btn btn-link btn-remove btn-sm'
+- submit_btn_css ||= 'gl-button btn btn-danger btn-sm'
= form_tag admin_application_path(application) do
%input{ :name => "_method", :type => "hidden", :value => "delete" }/
= submit_tag 'Destroy', class: submit_btn_css, data: { confirm: _('Are you sure?') }
diff --git a/app/views/admin/applications/_form.html.haml b/app/views/admin/applications/_form.html.haml
index 0d01f1c57e0..0c3a4e73e30 100644
--- a/app/views/admin/applications/_form.html.haml
+++ b/app/views/admin/applications/_form.html.haml
@@ -40,5 +40,5 @@
= render 'shared/tokens/scopes_form', prefix: 'doorkeeper_application', token: application, scopes: @scopes
.form-actions
- = f.submit 'Submit', class: "btn btn-success wide"
- = link_to "Cancel", admin_applications_path, class: "btn btn-cancel"
+ = f.submit 'Submit', class: "gl-button btn btn-success wide"
+ = link_to "Cancel", admin_applications_path, class: "gl-button btn btn-cancel"
diff --git a/app/views/admin/applications/index.html.haml b/app/views/admin/applications/index.html.haml
index 0119cabf1ad..c1c1c2a4cfe 100644
--- a/app/views/admin/applications/index.html.haml
+++ b/app/views/admin/applications/index.html.haml
@@ -4,7 +4,7 @@
%p.light
System OAuth applications don't belong to any user and can only be managed by admins
%hr
-%p= link_to 'New application', new_admin_application_path, class: 'btn btn-success'
+%p= link_to 'New application', new_admin_application_path, class: 'gl-button btn btn-success'
%table.table
%thead
%tr
@@ -23,6 +23,6 @@
%td= @application_counts[application.id].to_i
%td= application.trusted? ? 'Y': 'N'
%td= application.confidential? ? 'Y': 'N'
- %td= link_to 'Edit', edit_admin_application_path(application), class: 'btn btn-link'
+ %td= link_to 'Edit', edit_admin_application_path(application), class: 'gl-button btn btn-link'
%td= render 'delete_form', application: application
= paginate @applications, theme: 'gitlab'
diff --git a/app/views/admin/applications/show.html.haml b/app/views/admin/applications/show.html.haml
index 5259dd56df5..f029da6b3af 100644
--- a/app/views/admin/applications/show.html.haml
+++ b/app/views/admin/applications/show.html.haml
@@ -13,7 +13,7 @@
.input-group
%input.label.label-monospace.monospace{ id: "application_id", type: "text", autocomplete: 'off', value: @application.uid, readonly: true }
.input-group-append
- = clipboard_button(target: '#application_id', title: _("Copy ID"), class: "btn btn btn-default")
+ = clipboard_button(target: '#application_id', title: _("Copy ID"), class: "gl-button btn btn-default")
%tr
%td
= _('Secret')
@@ -22,7 +22,7 @@
.input-group
%input.label.label-monospace.monospace{ id: "secret", type: "text", autocomplete: 'off', value: @application.secret, readonly: true }
.input-group-append
- = clipboard_button(target: '#secret', title: _("Copy secret"), class: "btn btn btn-default")
+ = clipboard_button(target: '#secret', title: _("Copy secret"), class: "gl-button btn btn-default")
%tr
%td
= _('Callback URL')
@@ -45,5 +45,5 @@
= render "shared/tokens/scopes_list", token: @application
.form-actions
- = link_to 'Edit', edit_admin_application_path(@application), class: 'btn btn-primary wide float-left'
+ = link_to 'Edit', edit_admin_application_path(@application), class: 'gl-button btn btn-primary wide float-left'
= render 'delete_form', application: @application, submit_btn_css: 'btn btn-danger gl-ml-3'
diff --git a/app/views/admin/broadcast_messages/_form.html.haml b/app/views/admin/broadcast_messages/_form.html.haml
index 8a937bd66cf..9693a97367f 100644
--- a/app/views/admin/broadcast_messages/_form.html.haml
+++ b/app/views/admin/broadcast_messages/_form.html.haml
@@ -1,4 +1,4 @@
-.broadcast-message.broadcast-banner-message.alert-warning.js-broadcast-banner-message-preview.mt-2{ style: broadcast_message_style(@broadcast_message), class: ('hidden' unless @broadcast_message.banner? ) }
+.broadcast-message.broadcast-banner-message.gl-alert-warning.js-broadcast-banner-message-preview.gl-mt-3{ style: broadcast_message_style(@broadcast_message), class: ('gl-display-none' unless @broadcast_message.banner? ) }
= sprite_icon('bullhorn', css_class:'vertical-align-text-top')
.js-broadcast-message-preview
- if @broadcast_message.message.present?
@@ -77,6 +77,6 @@
= f.datetime_select :ends_at, {}, class: 'form-control form-control-inline'
.form-actions
- if @broadcast_message.persisted?
- = f.submit "Update broadcast message", class: "btn btn-success"
+ = f.submit "Update broadcast message", class: "btn gl-button btn-success"
- else
- = f.submit "Add broadcast message", class: "btn btn-success"
+ = f.submit "Add broadcast message", class: "btn gl-button btn-success"
diff --git a/app/views/admin/dashboard/_billable_users_text.html.haml b/app/views/admin/dashboard/_billable_users_text.html.haml
new file mode 100644
index 00000000000..e9485d23228
--- /dev/null
+++ b/app/views/admin/dashboard/_billable_users_text.html.haml
@@ -0,0 +1 @@
+= s_('AdminArea|Active users')
diff --git a/app/views/admin/dashboard/index.html.haml b/app/views/admin/dashboard/index.html.haml
index 4acfc96caf2..b0d4a3fd8f5 100644
--- a/app/views/admin/dashboard/index.html.haml
+++ b/app/views/admin/dashboard/index.html.haml
@@ -19,7 +19,7 @@
%h3.text-center
= s_('AdminArea|Projects: %{number_of_projects}') % { number_of_projects: approximate_count_with_delimiters(@counts, Project) }
%hr
- = link_to(s_('AdminArea|New project'), new_project_path, class: "btn btn-success gl-w-full")
+ = link_to(s_('AdminArea|New project'), new_project_path, class: "btn gl-button btn-success gl-w-full")
.col-sm-4
.info-well.dark-well
.well-segment.well-centered
@@ -28,8 +28,8 @@
= s_('AdminArea|Users: %{number_of_users}') % { number_of_users: approximate_count_with_delimiters(@counts, User) }
%hr
.btn-group.d-flex{ role: 'group' }
- = link_to s_('AdminArea|New user'), new_admin_user_path, class: "btn btn-success gl-w-full"
- = link_to s_('AdminArea|Users statistics'), admin_dashboard_stats_path, class: 'btn btn-primary gl-w-full'
+ = link_to s_('AdminArea|New user'), new_admin_user_path, class: "btn gl-button btn-success gl-w-full"
+ = link_to s_('AdminArea|Users statistics'), admin_dashboard_stats_path, class: 'btn gl-button btn-info gl-w-full'
.col-sm-4
.info-well.dark-well
.well-segment.well-centered
@@ -37,7 +37,7 @@
%h3.text-center
= s_('AdminArea|Groups: %{number_of_groups}') % { number_of_groups: approximate_count_with_delimiters(@counts, Group) }
%hr
- = link_to s_('AdminArea|New group'), new_admin_group_path, class: "btn btn-success gl-w-full"
+ = link_to s_('AdminArea|New group'), new_admin_group_path, class: "btn gl-button btn-success gl-w-full"
.row
.col-md-4
#js-admin-statistics-container
@@ -51,7 +51,7 @@
= feature_entry(_('LDAP'),
enabled: Gitlab.config.ldap.enabled,
- doc_href: help_page_path('administration/auth/ldap'))
+ doc_href: help_page_path('administration/auth/ldap/index.md'))
= feature_entry(_('Gravatar'),
href: general_admin_application_settings_path(anchor: 'js-account-settings'),
diff --git a/app/views/admin/dashboard/stats.html.haml b/app/views/admin/dashboard/stats.html.haml
index 78707235cb5..9a89bf12365 100644
--- a/app/views/admin/dashboard/stats.html.haml
+++ b/app/views/admin/dashboard/stats.html.haml
@@ -50,11 +50,9 @@
= s_('AdminArea|Bots')
%td.p-3.text-right
= @users_statistics&.bots.to_i
-
%tr.bg-gray-light.gl-text-gray-900
%td.p-3
%strong
- = s_('AdminArea|Active users')
= render_if_exists 'admin/dashboard/billable_users_text'
%td.p-3.text-right
%strong
diff --git a/app/views/admin/deploy_keys/edit.html.haml b/app/views/admin/deploy_keys/edit.html.haml
index 99d8af65068..2a0177ab997 100644
--- a/app/views/admin/deploy_keys/edit.html.haml
+++ b/app/views/admin/deploy_keys/edit.html.haml
@@ -6,5 +6,5 @@
= form_for [:admin, @deploy_key], html: { class: 'deploy-key-form' } do |f|
= render partial: 'shared/deploy_keys/form', locals: { form: f, deploy_key: @deploy_key }
.form-actions
- = f.submit _('Save changes'), class: 'btn-success btn'
- = link_to _('Cancel'), admin_deploy_keys_path, class: 'btn btn-cancel'
+ = f.submit _('Save changes'), class: 'btn gl-button btn-success'
+ = link_to _('Cancel'), admin_deploy_keys_path, class: 'btn gl-button btn-cancel'
diff --git a/app/views/admin/deploy_keys/index.html.haml b/app/views/admin/deploy_keys/index.html.haml
index 3409e2ffc8a..9b6aa278906 100644
--- a/app/views/admin/deploy_keys/index.html.haml
+++ b/app/views/admin/deploy_keys/index.html.haml
@@ -2,7 +2,7 @@
- if @deploy_keys.any?
%h3.page-title.deploy-keys-title
= _('Public deploy keys (%{deploy_keys_count})') % { deploy_keys_count: @deploy_keys.load.size }
- = link_to _('New deploy key'), new_admin_deploy_key_path, class: 'float-right btn btn-success btn-md gl-button'
+ = link_to _('New deploy key'), new_admin_deploy_key_path, class: 'float-right btn gl-button btn-success btn-md gl-button'
.table-holder.deploy-keys-list
%table.table
%thead
@@ -27,7 +27,7 @@
= _('added %{created_at_timeago}').html_safe % { created_at_timeago: time_ago_with_tooltip(deploy_key.created_at) }
%td
.float-right
- = link_to _('Edit'), edit_admin_deploy_key_path(deploy_key), class: 'btn btn-sm'
- = link_to _('Remove'), admin_deploy_key_path(deploy_key), data: { confirm: _('Are you sure?') }, method: :delete, class: 'btn btn-sm btn-remove delete-key'
+ = link_to _('Edit'), edit_admin_deploy_key_path(deploy_key), class: 'btn gl-button btn-sm'
+ = link_to _('Remove'), admin_deploy_key_path(deploy_key), data: { confirm: _('Are you sure?') }, method: :delete, class: 'gl-button btn btn-sm btn-danger delete-key'
- else
= render 'shared/empty_states/deploy_keys'
diff --git a/app/views/admin/deploy_keys/new.html.haml b/app/views/admin/deploy_keys/new.html.haml
index f43c1447f09..5a3b880a596 100644
--- a/app/views/admin/deploy_keys/new.html.haml
+++ b/app/views/admin/deploy_keys/new.html.haml
@@ -6,5 +6,5 @@
= form_for [:admin, @deploy_key], html: { class: 'deploy-key-form' } do |f|
= render partial: 'shared/deploy_keys/form', locals: { form: f, deploy_key: @deploy_key }
.form-actions
- = f.submit 'Create', class: 'btn-success btn'
- = link_to 'Cancel', admin_deploy_keys_path, class: 'btn btn-cancel'
+ = f.submit 'Create', class: 'btn gl-button btn-success'
+ = link_to 'Cancel', admin_deploy_keys_path, class: 'btn gl-button btn-cancel'
diff --git a/app/views/admin/dev_ops_report/show.html.haml b/app/views/admin/dev_ops_report/show.html.haml
index 1892557d0d6..88105be70fb 100644
--- a/app/views/admin/dev_ops_report/show.html.haml
+++ b/app/views/admin/dev_ops_report/show.html.haml
@@ -1,5 +1,6 @@
- page_title _('DevOps Report')
- usage_ping_enabled = Gitlab::CurrentSettings.usage_ping_enabled
+- add_page_specific_style 'page_bundles/dev_ops_report'
.container
- if usage_ping_enabled && show_callout?('dev_ops_report_intro_callout_dismissed')
@@ -7,7 +8,7 @@
.gl-mt-3
- if !usage_ping_enabled
- #js-devops-empty-state{ data: { is_admin: current_user&.admin.to_s, empty_state_svg_path: image_path('illustrations/convdev/convdev_no_index.svg'), enable_usage_ping_link: metrics_and_profiling_admin_application_settings_path(anchor: 'js-usage-settings'), docs_link: help_page_path('development/telemetry/usage_ping') } }
+ #js-devops-empty-state{ data: { is_admin: current_user&.admin.to_s, empty_state_svg_path: image_path('illustrations/convdev/convdev_no_index.svg'), enable_usage_ping_link: metrics_and_profiling_admin_application_settings_path(anchor: 'js-usage-settings'), docs_link: help_page_path('development/product_analytics/usage_ping') } }
- elsif @metric.blank?
= render 'no_data'
- else
@@ -25,7 +26,7 @@
- @metric.cards.each do |card|
= render 'card', card: card
- .devops-steps.d-none.d-lg-block.d-xl-block
+ .devops-steps.d-none.d-lg-block
- @metric.idea_to_production_steps.each_with_index do |step, index|
.devops-step{ class: "devops-#{score_level(step.percentage_score)}-score" }
= custom_icon("i2p_step_#{index + 1}")
diff --git a/app/views/admin/groups/_form.html.haml b/app/views/admin/groups/_form.html.haml
index 041b0661d37..6174da14ac0 100644
--- a/app/views/admin/groups/_form.html.haml
+++ b/app/views/admin/groups/_form.html.haml
@@ -29,12 +29,10 @@
.gl-alert-body
= render 'shared/group_tips'
.form-actions
- = f.submit _('Create group'), class: "btn btn-success"
- = link_to _('Cancel'), admin_groups_path, class: "btn btn-cancel"
+ = f.submit _('Create group'), class: "gl-button btn btn-success"
+ = link_to _('Cancel'), admin_groups_path, class: "gl-button btn btn-cancel"
- else
.form-actions
- = f.submit _('Save changes'), class: "btn btn-success", data: { qa_selector: 'save_changes_button' }
- = link_to _('Cancel'), admin_group_path(@group), class: "btn btn-cancel"
-
-= render_if_exists 'ldap_group_links/ldap_syncrhonizations', group: @group
+ = f.submit _('Save changes'), class: "gl-button btn btn-success", data: { qa_selector: 'save_changes_button' }
+ = link_to _('Cancel'), admin_group_path(@group), class: "gl-button btn btn-cancel"
diff --git a/app/views/admin/groups/_group.html.haml b/app/views/admin/groups/_group.html.haml
index 3a82f3803bd..a667fc7ca04 100644
--- a/app/views/admin/groups/_group.html.haml
+++ b/app/views/admin/groups/_group.html.haml
@@ -34,4 +34,4 @@
.controls.gl-flex-shrink-0.gl-ml-5
= link_to _('Edit'), admin_group_edit_path(group), id: "edit_#{dom_id(group)}", class: 'btn'
- = link_to _('Delete'), [:admin, group], data: { confirm: _("Are you sure you want to remove %{group_name}?") % { group_name: group.name } }, method: :delete, class: 'btn btn-remove'
+ = link_to _('Delete'), [:admin, group], data: { confirm: _("Are you sure you want to remove %{group_name}?") % { group_name: group.name } }, method: :delete, class: 'gl-button btn btn-danger'
diff --git a/app/views/admin/groups/index.html.haml b/app/views/admin/groups/index.html.haml
index da2b2c60b15..bc4d4e489ce 100644
--- a/app/views/admin/groups/index.html.haml
+++ b/app/views/admin/groups/index.html.haml
@@ -8,9 +8,9 @@
- project_name = params[:name].present? ? params[:name] : nil
.search-field-holder
= search_field_tag :name, project_name, class: "form-control search-text-input js-search-input", autofocus: true, spellcheck: false, placeholder: 'Search by name', data: { qa_selector: 'group_search_field' }
- = icon("search", class: "search-icon")
+ = sprite_icon('search', css_class: 'search-icon')
= render "shared/groups/dropdown", options_hash: admin_groups_sort_options_hash
- = link_to new_admin_group_path, class: "btn btn-success" do
+ = link_to new_admin_group_path, class: "gl-button btn btn-success" do
= _('New group')
%ul.content-list
= render @groups
diff --git a/app/views/admin/groups/show.html.haml b/app/views/admin/groups/show.html.haml
index 6c2c0b3a488..424251f543e 100644
--- a/app/views/admin/groups/show.html.haml
+++ b/app/views/admin/groups/show.html.haml
@@ -113,9 +113,9 @@
%div
= users_select_tag(:user_ids, multiple: true, email_user: true, skip_ldap: @group.ldap_synced?, scope: :all)
.gl-mt-3
- = select_tag :access_level, options_for_select(GroupMember.access_level_roles), class: "project-access-select select2"
+ = select_tag :access_level, options_for_select(@group.access_level_roles), class: "project-access-select select2"
%hr
- = button_tag _('Add users to group'), class: "btn btn-success"
+ = button_tag _('Add users to group'), class: "gl-button btn btn-success"
= render 'shared/members/requests', membership_source: @group, requesters: @requesters, force_mobile_view: true
.card
diff --git a/app/views/admin/health_check/show.html.haml b/app/views/admin/health_check/show.html.haml
index 65d3c78ec11..76e4fa971a3 100644
--- a/app/views/admin/health_check/show.html.haml
+++ b/app/views/admin/health_check/show.html.haml
@@ -9,7 +9,7 @@
%code#health-check-token= Gitlab::CurrentSettings.health_check_access_token
.gl-mt-3
= button_to _("Reset health check access token"), reset_health_check_token_admin_application_settings_path,
- method: :put, class: 'btn btn-default',
+ method: :put, class: 'gl-button btn btn-default',
data: { confirm: _('Are you sure you want to reset the health check token?') }
%p.light
#{ _('Health information can be retrieved from the following endpoints. More information is available') }
diff --git a/app/views/admin/hook_logs/show.html.haml b/app/views/admin/hook_logs/show.html.haml
index a8ef19dcf46..ca2737ca56f 100644
--- a/app/views/admin/hook_logs/show.html.haml
+++ b/app/views/admin/hook_logs/show.html.haml
@@ -4,6 +4,6 @@
%hr
-= link_to _("Resend Request"), retry_admin_hook_hook_log_path(@hook, @hook_log), method: :post, class: "btn btn-default float-right gl-ml-3"
+= link_to _("Resend Request"), retry_admin_hook_hook_log_path(@hook, @hook_log), method: :post, class: "btn gl-button btn-default float-right gl-ml-3"
= render partial: 'shared/hook_logs/content', locals: { hook_log: @hook_log }
diff --git a/app/views/admin/hooks/edit.html.haml b/app/views/admin/hooks/edit.html.haml
index f9faf5b11fa..74f73b4972a 100644
--- a/app/views/admin/hooks/edit.html.haml
+++ b/app/views/admin/hooks/edit.html.haml
@@ -9,9 +9,9 @@
= form_for @hook, as: :hook, url: admin_hook_path do |f|
= render partial: 'form', locals: { form: f, hook: @hook }
.form-actions
- %span>= f.submit _('Save changes'), class: 'btn btn-success gl-mr-3'
+ %span>= f.submit _('Save changes'), class: 'btn gl-button btn-success gl-mr-3'
= render 'shared/web_hooks/test_button', hook: @hook
- = link_to _('Delete'), admin_hook_path(@hook), method: :delete, class: 'btn btn-remove float-right', data: { confirm: _('Are you sure?') }
+ = link_to _('Delete'), admin_hook_path(@hook), method: :delete, class: 'btn gl-button btn-danger float-right', data: { confirm: _('Are you sure?') }
%hr
diff --git a/app/views/admin/hooks/index.html.haml b/app/views/admin/hooks/index.html.haml
index d70baa592ea..c0bad6a0a63 100644
--- a/app/views/admin/hooks/index.html.haml
+++ b/app/views/admin/hooks/index.html.haml
@@ -7,7 +7,7 @@
.col-lg-8.gl-mb-3
= form_for @hook, as: :hook, url: admin_hooks_path do |f|
= render partial: 'form', locals: { form: f, hook: @hook }
- = f.submit _('Add system hook'), class: 'btn btn-success'
+ = f.submit _('Add system hook'), class: 'btn gl-button btn-success'
= render 'shared/web_hooks/index', hooks: @hooks, hook_class: @hook.class
diff --git a/app/views/admin/identities/_form.html.haml b/app/views/admin/identities/_form.html.haml
index 40a7014e143..5c62cff27c7 100644
--- a/app/views/admin/identities/_form.html.haml
+++ b/app/views/admin/identities/_form.html.haml
@@ -14,5 +14,5 @@
= f.text_field :extern_uid, class: 'form-control', required: true
.form-actions
- = f.submit _('Save changes'), class: "btn btn-success"
+ = f.submit _('Save changes'), class: "gl-button btn btn-success"
diff --git a/app/views/admin/identities/_identity.html.haml b/app/views/admin/identities/_identity.html.haml
index 5ed59809db5..d8facbb780a 100644
--- a/app/views/admin/identities/_identity.html.haml
+++ b/app/views/admin/identities/_identity.html.haml
@@ -4,9 +4,9 @@
%td
= identity.extern_uid
%td
- = link_to edit_admin_user_identity_path(@user, identity), class: 'btn btn-sm btn-grouped' do
+ = link_to edit_admin_user_identity_path(@user, identity), class: 'gl-button btn btn-sm btn-grouped' do
= _("Edit")
= link_to [:admin, @user, identity], method: :delete,
- class: 'btn btn-sm btn-danger',
+ class: 'gl-button btn btn-sm btn-danger',
data: { confirm: _("Are you sure you want to remove this identity?") } do
= _('Delete')
diff --git a/app/views/admin/identities/index.html.haml b/app/views/admin/identities/index.html.haml
index 9543bbcf977..a6d562dad31 100644
--- a/app/views/admin/identities/index.html.haml
+++ b/app/views/admin/identities/index.html.haml
@@ -3,7 +3,7 @@
- page_title _("Identities"), @user.name, _("Users")
= render 'admin/users/head'
-= link_to _('New identity'), new_admin_user_identity_path, class: 'float-right btn btn-success'
+= link_to _('New identity'), new_admin_user_identity_path, class: 'float-right gl-button btn btn-success'
- if @identities.present?
.table-holder
%table.table
diff --git a/app/views/admin/jobs/index.html.haml b/app/views/admin/jobs/index.html.haml
index 32c0a801a1d..d482ae04c08 100644
--- a/app/views/admin/jobs/index.html.haml
+++ b/app/views/admin/jobs/index.html.haml
@@ -8,7 +8,7 @@
- if @all_builds.running_or_pending.any?
#stop-jobs-modal
.nav-controls
- %button#stop-jobs-button.btn.btn-danger{ data: { toggle: 'modal',
+ %button#stop-jobs-button.btn.gl-button.btn-danger{ data: { toggle: 'modal',
target: '#stop-jobs-modal',
url: cancel_all_admin_jobs_path } }
= s_('AdminArea|Stop all jobs')
diff --git a/app/views/admin/labels/_form.html.haml b/app/views/admin/labels/_form.html.haml
index 299d0a12e6c..664081339f3 100644
--- a/app/views/admin/labels/_form.html.haml
+++ b/app/views/admin/labels/_form.html.haml
@@ -27,5 +27,5 @@
= render_suggested_colors
.form-actions
- = f.submit _('Save'), class: 'btn btn-success js-save-button'
- = link_to _("Cancel"), admin_labels_path, class: 'btn btn-cancel'
+ = f.submit _('Save'), class: 'btn gl-button btn-success js-save-button'
+ = link_to _("Cancel"), admin_labels_path, class: 'btn gl-button btn-cancel'
diff --git a/app/views/admin/labels/_label.html.haml b/app/views/admin/labels/_label.html.haml
index 6d934654c5d..b31b9bdab0a 100644
--- a/app/views/admin/labels/_label.html.haml
+++ b/app/views/admin/labels/_label.html.haml
@@ -1,7 +1,7 @@
%li.label-list-item{ id: dom_id(label) }
= render "shared/label_row", label: label.present(issuable_subject: nil)
.label-actions-list
- = link_to edit_admin_label_path(label), class: 'btn btn-transparent label-action has-tooltip', title: _('Edit'), data: { placement: 'bottom' }, aria_label: _('Edit') do
+ = link_to edit_admin_label_path(label), class: 'btn gl-button btn-transparent label-action has-tooltip', title: _('Edit'), data: { placement: 'bottom' }, aria_label: _('Edit') do
= sprite_icon('pencil')
- = link_to admin_label_path(label), class: 'btn btn-transparent remove-row label-action has-tooltip', title: _('Delete'), data: { placement: 'bottom', confirm: "Delete this label? Are you sure?" }, aria_label: _('Delete'), method: :delete, remote: true do
+ = link_to admin_label_path(label), class: 'btn gl-button btn-transparent remove-row label-action has-tooltip', title: _('Delete'), data: { placement: 'bottom', confirm: "Delete this label? Are you sure?" }, aria_label: _('Delete'), method: :delete, remote: true do
= sprite_icon('remove')
diff --git a/app/views/admin/labels/index.html.haml b/app/views/admin/labels/index.html.haml
index 38137f360fd..76d37626fff 100644
--- a/app/views/admin/labels/index.html.haml
+++ b/app/views/admin/labels/index.html.haml
@@ -1,7 +1,7 @@
- page_title _("Labels")
%div
- = link_to new_admin_label_path, class: "float-right btn btn-nr btn-success" do
+ = link_to new_admin_label_path, class: "float-right btn gl-button btn-nr btn-success" do
= _('New label')
%h3.page-title
= _('Labels')
diff --git a/app/views/admin/projects/index.html.haml b/app/views/admin/projects/index.html.haml
index 08e668e8623..bcf09dfc0d2 100644
--- a/app/views/admin/projects/index.html.haml
+++ b/app/views/admin/projects/index.html.haml
@@ -30,8 +30,8 @@
= dropdown_content
= dropdown_loading
= render 'shared/projects/dropdown'
- = link_to new_project_path, class: 'btn btn-success' do
+ = link_to new_project_path, class: 'gl-button btn btn-success' do
New Project
- = button_tag "Search", class: "btn btn-primary btn-search hide"
+ = button_tag "Search", class: "gl-button btn btn-primary btn-search hide"
= render 'projects'
diff --git a/app/views/admin/projects/show.html.haml b/app/views/admin/projects/show.html.haml
index d5af12fcd09..417fd1d60eb 100644
--- a/app/views/admin/projects/show.html.haml
+++ b/app/views/admin/projects/show.html.haml
@@ -13,8 +13,9 @@
- if @project.last_repository_check_failed?
.row
.col-md-12
- .card
- .card-header.alert.alert-danger
+ .gl-alert.gl-alert-danger.gl-mb-5
+ = sprite_icon('error', size: 16, css_class: 'gl-icon gl-alert-icon gl-alert-icon-no-title')
+ .gl-alert-body
- last_check_message = _("Last repository check (%{last_check_timestamp}) failed. See the 'repocheck.log' file for error messages.")
- last_check_message = last_check_message % { last_check_timestamp: time_ago_with_tooltip(@project.last_repository_check_at) }
= last_check_message.html_safe
@@ -148,7 +149,7 @@
.form-group.row
.offset-sm-3.col-sm-9
- = f.submit _('Transfer'), class: 'btn btn-primary'
+ = f.submit _('Transfer'), class: 'gl-button btn btn-primary'
.card.repository-check
.card-header
@@ -168,7 +169,7 @@
= link_to sprite_icon('question-o'), help_page_path('administration/repository_checks')
.form-group
- = f.submit _('Trigger repository check'), class: 'btn btn-primary'
+ = f.submit _('Trigger repository check'), class: 'gl-button btn btn-primary'
.col-md-6
- if @group
diff --git a/app/views/admin/runners/_runner.html.haml b/app/views/admin/runners/_runner.html.haml
index a2b736c332c..cc8ac6b0642 100644
--- a/app/views/admin/runners/_runner.html.haml
+++ b/app/views/admin/runners/_runner.html.haml
@@ -65,15 +65,15 @@
.table-section.table-button-footer.section-10
.btn-group.table-action-buttons
.btn-group
- = link_to admin_runner_path(runner), class: 'btn btn-default has-tooltip', title: _('Edit'), ref: 'tooltip', aria: { label: _('Edit') }, data: { placement: 'top', container: 'body'} do
+ = link_to admin_runner_path(runner), class: 'gl-button btn btn-default has-tooltip', title: _('Edit'), ref: 'tooltip', aria: { label: _('Edit') }, data: { placement: 'top', container: 'body'} do
= sprite_icon('pencil')
.btn-group
- if runner.active?
- = link_to [:pause, :admin, runner], method: :get, class: 'btn btn-default btn-svg has-tooltip', title: _('Pause'), ref: 'tooltip', aria: { label: _('Pause') }, data: { placement: 'top', container: 'body', confirm: _('Are you sure?') } do
+ = link_to [:pause, :admin, runner], method: :get, class: 'gl-button btn btn-default btn-svg has-tooltip', title: _('Pause'), ref: 'tooltip', aria: { label: _('Pause') }, data: { placement: 'top', container: 'body', confirm: _('Are you sure?') } do
= sprite_icon('pause')
- else
- = link_to [:resume, :admin, runner], method: :get, class: 'btn btn-default btn-svg has-tooltip gl-px-3', title: _('Resume'), ref: 'tooltip', aria: { label: _('Resume') }, data: { placement: 'top', container: 'body'} do
+ = link_to [:resume, :admin, runner], method: :get, class: 'gl-button btn btn-default btn-svg has-tooltip gl-px-3', title: _('Resume'), ref: 'tooltip', aria: { label: _('Resume') }, data: { placement: 'top', container: 'body'} do
= sprite_icon('play')
.btn-group
- = link_to [:admin, runner], method: :delete, class: 'btn btn-danger has-tooltip', title: _('Remove'), ref: 'tooltip', aria: { label: _('Remove') }, data: { placement: 'top', container: 'body', confirm: _('Are you sure?') } do
+ = link_to [:admin, runner], method: :delete, class: 'gl-button btn btn-danger has-tooltip', title: _('Remove'), ref: 'tooltip', aria: { label: _('Remove') }, data: { placement: 'top', container: 'body', confirm: _('Are you sure?') } do
= sprite_icon('close')
diff --git a/app/views/admin/runners/index.html.haml b/app/views/admin/runners/index.html.haml
index cc218aefdb7..3d3b8c28a17 100644
--- a/app/views/admin/runners/index.html.haml
+++ b/app/views/admin/runners/index.html.haml
@@ -48,7 +48,7 @@
.filtered-search-box
= dropdown_tag(_('Recent searches'),
options: { wrapper_class: 'filtered-search-history-dropdown-wrapper',
- toggle_class: 'btn filtered-search-history-dropdown-toggle-button',
+ toggle_class: 'gl-button btn filtered-search-history-dropdown-toggle-button',
dropdown_class: 'filtered-search-history-dropdown',
content_class: 'filtered-search-history-dropdown-content' }) do
.js-filtered-search-history-dropdown{ data: { full_path: admin_runners_path } }
@@ -60,7 +60,7 @@
#js-dropdown-hint.filtered-search-input-dropdown-menu.dropdown-menu.hint-dropdown
%ul.filter-dropdown{ data: { dynamic: true, dropdown: true } }
%li.filter-dropdown-item{ data: {hint: "#{'{{hint}}'}", tag: "#{'{{tag}}'}", action: "#{'{{hint === \'search\' ? \'submit\' : \'\' }}'}" } }
- = button_tag class: %w[btn btn-link] do
+ = button_tag class: %w[gl-button btn btn-link] do
-# Encapsulate static class name `{{icon}}` inside #{} to bypass
-# haml lint's ClassAttributeWithStaticValue
%svg
@@ -78,21 +78,21 @@
%ul{ data: { dropdown: true } }
- Ci::Runner::AVAILABLE_STATUSES.each do |status|
%li.filter-dropdown-item{ data: { value: status } }
- = button_tag class: %w[btn btn-link] do
+ = button_tag class: %w[gl-button btn btn-link] do
= status.titleize
#js-dropdown-admin-runner-type.filtered-search-input-dropdown-menu.dropdown-menu
%ul{ data: { dropdown: true } }
- Ci::Runner::AVAILABLE_TYPES.each do |runner_type|
%li.filter-dropdown-item{ data: { value: runner_type } }
- = button_tag class: %w[btn btn-link] do
+ = button_tag class: %w[gl-button btn btn-link] do
= runner_type.titleize
#js-dropdown-admin-runner-type.filtered-search-input-dropdown-menu.dropdown-menu
%ul{ data: { dropdown: true } }
- Ci::Runner::AVAILABLE_TYPES.each do |runner_type|
%li.filter-dropdown-item{ data: { value: runner_type } }
- = button_tag class: %w[btn btn-link] do
+ = button_tag class: %w[gl-button btn btn-link] do
= runner_type.titleize
#js-dropdown-runner-tag.filtered-search-input-dropdown-menu.dropdown-menu
diff --git a/app/views/admin/runners/show.html.haml b/app/views/admin/runners/show.html.haml
index cecf3f137ed..2c4befb1be2 100644
--- a/app/views/admin/runners/show.html.haml
+++ b/app/views/admin/runners/show.html.haml
@@ -49,7 +49,7 @@
= project.full_name
%td
.float-right
- = link_to 'Disable', admin_namespace_project_runner_project_path(project.namespace, project, runner_project), method: :delete, class: 'btn btn-danger btn-sm'
+ = link_to 'Disable', admin_namespace_project_runner_project_path(project.namespace, project, runner_project), method: :delete, class: 'gl-button btn btn-danger btn-sm'
%table.table.unassigned-projects
%thead
@@ -73,7 +73,7 @@
.float-right
= form_for project.runner_projects.new, url: admin_namespace_project_runner_projects_path(project.namespace, project), method: :post do |f|
= f.hidden_field :runner_id, value: @runner.id
- = f.submit 'Enable', class: 'btn btn-sm'
+ = f.submit 'Enable', class: 'gl-button btn btn-sm'
= paginate_without_count @projects
.col-md-6
diff --git a/app/views/admin/serverless/domains/_form.html.haml b/app/views/admin/serverless/domains/_form.html.haml
index 9e7990ef8ca..8f0dd0cab8e 100644
--- a/app/views/admin/serverless/domains/_form.html.haml
+++ b/app/views/admin/serverless/domains/_form.html.haml
@@ -16,7 +16,7 @@
- text, status = @domain.unverified? ? [_('Unverified'), 'badge-danger'] : [_('Verified'), 'badge-success']
.badge{ class: status }
= text
- = link_to sprite_icon("redo"), verify_admin_serverless_domain_path(@domain.id), method: :post, class: "btn has-tooltip", title: _("Retry verification")
+ = link_to sprite_icon("redo"), verify_admin_serverless_domain_path(@domain.id), method: :post, class: "gl-button btn has-tooltip", title: _("Retry verification")
.col-sm-6
= f.label :serverless_domain_dns, _('DNS'), class: 'label-bold'
@@ -50,7 +50,7 @@
.d-flex.justify-content-between.align-items-center.p-3
%span
= @domain.subject || _('missing')
- %button.btn.btn-remove.btn-sm.js-domain-cert-replace-btn{ type: 'button' }
+ %button.gl-button.btn.btn-danger.btn-sm.js-domain-cert-replace-btn{ type: 'button' }
= _('Replace')
.js-domain-cert-inputs{ class: ('hidden' if show_certificate_card) }
@@ -65,9 +65,9 @@
%span.form-text.text-muted
= _("Upload a private key for your certificate")
- = f.submit @domain.persisted? ? _('Save changes') : _('Add domain'), class: "btn btn-success js-serverless-domain-submit", disabled: @domain.persisted?
+ = f.submit @domain.persisted? ? _('Save changes') : _('Add domain'), class: "gl-button btn btn-success js-serverless-domain-submit", disabled: @domain.persisted?
- if @domain.persisted?
- %button.btn.btn-remove{ type: 'button', data: { toggle: 'modal', target: "#modal-delete-domain" } }
+ %button.gl-button.btn.btn-danger{ type: 'button', data: { toggle: 'modal', target: "#modal-delete-domain" } }
= _('Delete domain')
-# haml-lint:disable NoPlainNodes
@@ -88,12 +88,12 @@
= _("You are about to delete %{domain} from your instance. This domain will no longer be available to any Knative application.").html_safe % { domain: "<code>#{@domain.domain}</code>".html_safe }
.modal-footer
- %a{ href: '#', data: { dismiss: 'modal' }, class: 'btn btn-default' }
+ %a{ href: '#', data: { dismiss: 'modal' }, class: 'gl-button btn btn-default' }
= _('Cancel')
= link_to _('Delete domain'),
admin_serverless_domain_path(@domain.id),
title: _('Delete'),
method: :delete,
- class: "btn btn-remove",
+ class: "gl-button btn btn-danger",
disabled: domain_attached
diff --git a/app/views/admin/sessions/_new_base.html.haml b/app/views/admin/sessions/_new_base.html.haml
index 5be1c90d6aa..47ef4f26889 100644
--- a/app/views/admin/sessions/_new_base.html.haml
+++ b/app/views/admin/sessions/_new_base.html.haml
@@ -4,4 +4,4 @@
= password_field_tag 'user[password]', nil, class: 'form-control', required: true, title: _('This field is required.'), data: { qa_selector: 'password_field' }
.submit-container.move-submit-down
- = submit_tag _('Enter Admin Mode'), class: 'btn btn-success', data: { qa_selector: 'enter_admin_mode_button' }
+ = submit_tag _('Enter Admin Mode'), class: 'gl-button btn btn-success', data: { qa_selector: 'enter_admin_mode_button' }
diff --git a/app/views/admin/sessions/_two_factor_otp.html.haml b/app/views/admin/sessions/_two_factor_otp.html.haml
index 8d5588de06e..3fe6e20a367 100644
--- a/app/views/admin/sessions/_two_factor_otp.html.haml
+++ b/app/views/admin/sessions/_two_factor_otp.html.haml
@@ -6,4 +6,4 @@
= _("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.")
.submit-container.move-submit-down
- = submit_tag 'Verify code', class: 'btn btn-success'
+ = submit_tag 'Verify code', class: 'gl-button btn btn-success'
diff --git a/app/views/admin/spam_logs/_spam_log.html.haml b/app/views/admin/spam_logs/_spam_log.html.haml
index 9d47dc1cce5..2e7114ddab4 100644
--- a/app/views/admin/spam_logs/_spam_log.html.haml
+++ b/app/views/admin/spam_logs/_spam_log.html.haml
@@ -24,16 +24,16 @@
%td
- if user
= link_to 'Remove user', admin_spam_log_path(spam_log, remove_user: true),
- data: { confirm: "USER #{user.name} WILL BE REMOVED! Are you sure?" }, method: :delete, class: "btn btn-sm btn-remove"
+ data: { confirm: "USER #{user.name} WILL BE REMOVED! Are you sure?" }, method: :delete, class: "gl-button btn btn-sm btn-danger"
%td
- if spam_log.submitted_as_ham?
.btn.btn-sm.disabled
Submitted as ham
- else
- = link_to 'Submit as ham', mark_as_ham_admin_spam_log_path(spam_log), method: :post, class: 'btn btn-sm btn-warning'
+ = link_to 'Submit as ham', mark_as_ham_admin_spam_log_path(spam_log), method: :post, class: 'gl-button btn btn-sm btn-warning'
- if user && !user.blocked?
- = link_to 'Block user', block_admin_user_path(user), data: {confirm: 'USER WILL BE BLOCKED! Are you sure?'}, method: :put, class: "btn btn-sm"
+ = link_to 'Block user', block_admin_user_path(user), data: {confirm: 'USER WILL BE BLOCKED! Are you sure?'}, method: :put, class: "gl-button btn btn-sm"
- else
.btn.btn-sm.disabled
Already blocked
- = link_to 'Remove log', [:admin, spam_log], remote: true, method: :delete, class: "btn btn-sm btn-close js-remove-tr"
+ = link_to 'Remove log', [:admin, spam_log], remote: true, method: :delete, class: "gl-button btn btn-sm btn-close js-remove-tr"
diff --git a/app/views/admin/users/_approve_user.html.haml b/app/views/admin/users/_approve_user.html.haml
new file mode 100644
index 00000000000..b4d960d909c
--- /dev/null
+++ b/app/views/admin/users/_approve_user.html.haml
@@ -0,0 +1,7 @@
+.card.border-info
+ .card-header.gl-bg-blue-500.gl-text-white
+ = s_('AdminUsers|This user has requested access')
+ .card-body
+ = render partial: 'admin/users/user_approve_effects'
+ %br
+ = link_to s_('AdminUsers|Approve user'), approve_admin_user_path(user), method: :put, class: "btn gl-button btn-info", data: { confirm: s_('AdminUsers|Are you sure?') }
diff --git a/app/views/admin/users/_block_user.html.haml b/app/views/admin/users/_block_user.html.haml
new file mode 100644
index 00000000000..b07a72c3e28
--- /dev/null
+++ b/app/views/admin/users/_block_user.html.haml
@@ -0,0 +1,11 @@
+.card.border-warning
+ .card-header.bg-warning.text-white
+ = s_('AdminUsers|Block this user')
+ .card-body
+ = render partial: 'admin/users/user_block_effects'
+ %br
+ %button.btn.gl-button.btn-warning{ data: { 'gl-modal-action': 'block',
+ content: s_('AdminUsers|You can always unblock their account, their data will remain intact.'),
+ url: block_admin_user_path(user),
+ username: sanitize_name(user.name) } }
+ = s_('AdminUsers|Block user')
diff --git a/app/views/admin/users/_form.html.haml b/app/views/admin/users/_form.html.haml
index 9e31c8d2852..61c31d2d864 100644
--- a/app/views/admin/users/_form.html.haml
+++ b/app/views/admin/users/_form.html.haml
@@ -88,7 +88,7 @@
.form-actions
- if @user.new_record?
= f.submit 'Create user', class: "btn gl-button btn-success"
- = link_to 'Cancel', admin_users_path, class: "btn btn-cancel"
+ = link_to 'Cancel', admin_users_path, class: "gl-button btn btn-cancel"
- else
= f.submit 'Save changes', class: "btn gl-button btn-success"
= link_to 'Cancel', admin_user_path(@user), class: "btn gl-button btn-cancel"
diff --git a/app/views/admin/users/_head.html.haml b/app/views/admin/users/_head.html.haml
index a60dbd51935..4abcdef7e27 100644
--- a/app/views/admin/users/_head.html.haml
+++ b/app/views/admin/users/_head.html.haml
@@ -1,13 +1,20 @@
%h3.page-title
= @user.name
- - if @user.blocked?
- %span.cred (Blocked)
+ - if @user.blocked_pending_approval?
+ %span.cred
+ = s_('AdminUsers|(Pending approval)')
+ - elsif @user.blocked?
+ %span.cred
+ = s_('AdminUsers|(Blocked)')
- if @user.internal?
- %span.cred (Internal)
+ %span.cred
+ = s_('AdminUsers|(Internal)')
- if @user.admin
- %span.cred (Admin)
+ %span.cred
+ = s_('AdminUsers|(Admin)')
- if @user.deactivated?
- %span.cred (Deactivated)
+ %span.cred
+ = s_('AdminUsers|(Deactivated)')
= render_if_exists 'admin/users/audtior_user_badge'
.float-right
diff --git a/app/views/admin/users/_modals.html.haml b/app/views/admin/users/_modals.html.haml
index 6cf6dc116e3..a8e5d962e5b 100644
--- a/app/views/admin/users/_modals.html.haml
+++ b/app/views/admin/users/_modals.html.haml
@@ -25,6 +25,6 @@
'secondary-action': s_('AdminUsers|Block user') } }
= 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 %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end},
+ consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd},
it cannot be undone or recovered.')
diff --git a/app/views/admin/users/_user.html.haml b/app/views/admin/users/_user.html.haml
index 160303890f5..70ab95bfa61 100644
--- a/app/views/admin/users/_user.html.haml
+++ b/app/views/admin/users/_user.html.haml
@@ -4,7 +4,12 @@
= _('Name')
.table-mobile-content
= render 'user_detail', user: user
- .table-section.section-25
+ .table-section.section-10
+ .table-mobile-header{ role: 'rowheader' }
+ = _('Projects')
+ .table-mobile-content.gl-str-truncated{ data: { testid: "user-project-count-#{user.id}" } }
+ = user.authorized_projects.length
+ .table-section.section-15
.table-mobile-header{ role: 'rowheader' }
= _('Created on')
.table-mobile-content
@@ -30,15 +35,22 @@
%span.small
= s_('AdminUsers|Cannot unblock LDAP blocked users')
- elsif user.blocked?
- = link_to _('Unblock'), unblock_admin_user_path(user), method: :put
+ - if user.blocked_pending_approval?
+ = link_to s_('AdminUsers|Approve'), approve_admin_user_path(user), method: :put
+ %button.btn.btn-default-tertiary{ data: { 'gl-modal-action': 'block',
+ url: block_admin_user_path(user),
+ username: sanitize_name(user.name) } }
+ = s_('AdminUsers|Block')
+ - else
+ = link_to _('Unblock'), unblock_admin_user_path(user), method: :put
- else
- %button.btn.gl-button.btn-default-tertiary{ data: { 'gl-modal-action': 'block',
+ %button.btn.btn-default-tertiary{ data: { 'gl-modal-action': 'block',
url: block_admin_user_path(user),
username: sanitize_name(user.name) } }
= s_('AdminUsers|Block')
- if user.can_be_deactivated?
%li
- %button.btn.gl-button.btn-default-tertiary{ data: { 'gl-modal-action': 'deactivate',
+ %button.btn.btn-default-tertiary{ data: { 'gl-modal-action': 'deactivate',
url: deactivate_admin_user_path(user),
username: sanitize_name(user.name) } }
= s_('AdminUsers|Deactivate')
@@ -52,13 +64,13 @@
%li.divider
- if user.can_be_removed?
%li
- %button.delete-user-button.btn.gl-button.btn-default-tertiary.text-danger{ data: { 'gl-modal-action': 'delete',
+ %button.delete-user-button.btn.btn-default-tertiary.text-danger{ data: { 'gl-modal-action': 'delete',
delete_user_url: admin_user_path(user),
block_user_url: block_admin_user_path(user),
username: sanitize_name(user.name) } }
= s_('AdminUsers|Delete user')
%li
- %button.delete-user-button.btn.gl-button.btn-default-tertiary.text-danger{ data: { 'gl-modal-action': 'delete-with-contributions',
+ %button.delete-user-button.btn.btn-default-tertiary.text-danger{ data: { 'gl-modal-action': 'delete-with-contributions',
delete_user_url: admin_user_path(user, hard_delete: true),
block_user_url: block_admin_user_path(user),
username: sanitize_name(user.name) } }
diff --git a/app/views/admin/users/_user_approve_effects.html.haml b/app/views/admin/users/_user_approve_effects.html.haml
new file mode 100644
index 00000000000..54e51bf3467
--- /dev/null
+++ b/app/views/admin/users/_user_approve_effects.html.haml
@@ -0,0 +1,11 @@
+%p
+ = s_('AdminUsers|Approved users can:')
+%ul
+ %li
+ = s_('AdminUsers|Log in')
+ %li
+ = s_('AdminUsers|Access Git repositories')
+ %li
+ = s_('AdminUsers|Access the API')
+ %li
+ = s_('AdminUsers|Be added to groups and projects')
diff --git a/app/views/admin/users/_user_detail.html.haml b/app/views/admin/users/_user_detail.html.haml
index 3839231cb95..3bafd1cb396 100644
--- a/app/views/admin/users/_user_detail.html.haml
+++ b/app/views/admin/users/_user_detail.html.haml
@@ -15,3 +15,5 @@
.row-second-line.str-truncated-100
= mail_to user.email, user.email, class: 'text-secondary'
+ - unless Feature.disabled?(:security_auto_fix) || !user.internal? || user.website_url.blank?
+ = link_to "(#{_('more information')})", user.website_url
diff --git a/app/views/admin/users/index.html.haml b/app/views/admin/users/index.html.haml
index 118bdf7bb17..33faef92646 100644
--- a/app/views/admin/users/index.html.haml
+++ b/app/views/admin/users/index.html.haml
@@ -30,6 +30,11 @@
= link_to admin_users_path(filter: "blocked") do
= s_('AdminUsers|Blocked')
%small.badge.badge-pill= limited_counter_with_delimiter(User.blocked)
+ - if Feature.enabled?(:admin_approval_for_new_user_signups, default_enabled: true)
+ = nav_link(html_options: { class: "#{active_when(params[:filter] == 'blocked_pending_approval')} filter-blocked-pending-approval" }) do
+ = link_to admin_users_path(filter: "blocked_pending_approval") do
+ = s_('AdminUsers|Pending approval')
+ %small.badge.badge-pill= limited_counter_with_delimiter(User.blocked_pending_approval)
= nav_link(html_options: { class: active_when(params[:filter] == 'deactivated') }) do
= link_to admin_users_path(filter: "deactivated") do
= s_('AdminUsers|Deactivated')
@@ -51,7 +56,7 @@
= 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
- = icon("search", class: "search-icon")
+ = sprite_icon('search', css_class: 'search-icon')
= button_tag s_('AdminUsers|Search users') if Rails.env.test?
.dropdown.user-sort-dropdown
= label_tag 'Sort by', nil, class: 'label-bold'
@@ -72,7 +77,8 @@
.table-holder
.thead-white.text-nowrap.gl-responsive-table-row.table-row-header{ role: 'row' }
.table-section.section-40{ role: 'rowheader' }= _('Name')
- .table-section.section-25{ role: 'rowheader' }= _('Created on')
+ .table-section.section-10{ role: 'rowheader' }= _('Projects')
+ .table-section.section-15{ role: 'rowheader' }= _('Created on')
.table-section.section-15{ role: 'rowheader' }= _('Last activity')
= render partial: 'admin/users/user', collection: @users
diff --git a/app/views/admin/users/show.html.haml b/app/views/admin/users/show.html.haml
index a08c29714e0..9c6f151a6b1 100644
--- a/app/views/admin/users/show.html.haml
+++ b/app/views/admin/users/show.html.haml
@@ -54,7 +54,7 @@
%strong{ class: @user.two_factor_enabled? ? 'cgreen' : 'cred' }
- if @user.two_factor_enabled?
Enabled
- = link_to 'Disable', disable_two_factor_admin_user_path(@user), data: {confirm: 'Are you sure?'}, method: :patch, class: 'btn gl-button btn-sm btn-remove float-right', title: 'Disable Two-factor Authentication'
+ = link_to 'Disable', disable_two_factor_admin_user_path(@user), data: {confirm: 'Are you sure?'}, method: :patch, class: 'btn gl-button btn-sm btn-danger float-right', title: 'Disable Two-factor Authentication'
- else
Disabled
@@ -137,7 +137,7 @@
.col-md-6
- unless @user == current_user
- - unless @user.confirmed?
+ - if can_force_email_confirmation?(@user)
.card.border-info
.card-header.bg-info.text-white
Confirm user
@@ -150,50 +150,46 @@
= render 'admin/users/user_detail_note'
- - if @user.deactivated?
- .card.border-info
- .card-header.bg-info.text-white
- Reactivate this user
- .card-body
- = render partial: 'admin/users/user_activation_effects'
- %br
- = link_to 'Activate user', activate_admin_user_path(@user), method: :put, class: "btn gl-button btn-info", data: { confirm: 'Are you sure?' }
- - elsif @user.can_be_deactivated?
- .card.border-warning
- .card-header.bg-warning.text-white
- Deactivate this user
- .card-body
- = render partial: 'admin/users/user_deactivation_effects'
- %br
- %button.btn.gl-button.btn-warning{ data: { 'gl-modal-action': 'deactivate',
- content: 'You can always re-activate their account, their data will remain intact.',
- url: deactivate_admin_user_path(@user),
- username: sanitize_name(@user.name) } }
- = s_('AdminUsers|Deactivate user')
+ - unless @user.internal?
+ - if @user.deactivated?
+ .card.border-info
+ .card-header.bg-info.text-white
+ Reactivate this user
+ .card-body
+ = render partial: 'admin/users/user_activation_effects'
+ %br
+ = link_to 'Activate user', activate_admin_user_path(@user), method: :put, class: "btn gl-button btn-info", data: { confirm: 'Are you sure?' }
+ - elsif @user.can_be_deactivated?
+ .card.border-warning
+ .card-header.bg-warning.text-white
+ Deactivate this user
+ .card-body
+ = render partial: 'admin/users/user_deactivation_effects'
+ %br
+ %button.btn.gl-button.btn-warning{ data: { 'gl-modal-action': 'deactivate',
+ content: 'You can always re-activate their account, their data will remain intact.',
+ url: deactivate_admin_user_path(@user),
+ username: sanitize_name(@user.name) } }
+ = s_('AdminUsers|Deactivate user')
- if @user.blocked?
- .card.border-info
- .card-header.bg-info.text-white
- This user is blocked
- .card-body
- %p A blocked user cannot:
- %ul
- %li Log in
- %li Access Git repositories
- %br
- = link_to 'Unblock user', unblock_admin_user_path(@user), method: :put, class: "btn gl-button btn-info", data: { confirm: 'Are you sure?' }
- - else
- .card.border-warning
- .card-header.bg-warning.text-white
- Block this user
- .card-body
- = render partial: 'admin/users/user_block_effects'
- %br
- %button.btn.gl-button.btn-warning{ data: { 'gl-modal-action': 'block',
- content: 'You can always unblock their account, their data will remain intact.',
- url: block_admin_user_path(@user),
- username: sanitize_name(@user.name) } }
- = s_('AdminUsers|Block user')
+ - if @user.blocked_pending_approval?
+ = render 'admin/users/approve_user', user: @user
+ = render 'admin/users/block_user', user: @user
+ - else
+ .card.border-info
+ .card-header.gl-bg-blue-500.gl-text-white
+ This user is blocked
+ .card-body
+ %p A blocked user cannot:
+ %ul
+ %li Log in
+ %li Access Git repositories
+ %br
+ = link_to 'Unblock user', unblock_admin_user_path(@user), method: :put, class: "btn gl-button btn-info", data: { confirm: s_('AdminUsers|Are you sure?') }
+ - elsif !@user.internal?
+ = render 'admin/users/block_user', user: @user
+
- if @user.access_locked?
.card.border-info
.card-header.bg-info.text-white
diff --git a/app/views/ci/status/_dropdown_graph_badge.html.haml b/app/views/ci/status/_dropdown_graph_badge.html.haml
index 4c8bb84c9ef..5e9b02b5fe2 100644
--- a/app/views/ci/status/_dropdown_graph_badge.html.haml
+++ b/app/views/ci/status/_dropdown_graph_badge.html.haml
@@ -8,12 +8,12 @@
- if status.has_details?
= link_to status.details_path, class: 'mini-pipeline-graph-dropdown-item d-flex', data: { toggle: 'tooltip', title: tooltip, container: 'body' } do
%span{ class: klass }= sprite_icon(status.icon)
- %span.ci-build-text.text-truncate.mw-70p.gl-pl-2= subject.name
+ %span.gl-text-truncate.mw-70p.gl-pl-2= subject.name
- else
.menu-item.mini-pipeline-graph-dropdown-item.d-flex{ data: { toggle: 'tooltip', title: tooltip, container: 'body' } }
%span{ class: klass }= sprite_icon(status.icon)
- %span.ci-build-text.text-truncate.mw-70p.gl-pl-2= subject.name
+ %span.gl-text-truncate.mw-70p.gl-pl-2= subject.name
- if status.has_action?
= link_to status.action_path, class: "gl-button ci-action-icon-container ci-action-icon-wrapper js-ci-action-icon", method: status.action_method, data: { toggle: 'tooltip', title: status.action_title, container: 'body' } do
diff --git a/app/views/ci/variables/_index.html.haml b/app/views/ci/variables/_index.html.haml
index 8d379774719..b90e672cca9 100644
--- a/app/views/ci/variables/_index.html.haml
+++ b/app/views/ci/variables/_index.html.haml
@@ -24,7 +24,7 @@
- else
.row
.col-lg-12.js-ci-variable-list-section{ data: { save_endpoint: save_endpoint, maskable_regex: ci_variable_maskable_regex } }
- .hide.alert.alert-danger.js-ci-variable-error-box
+ .hide.gl-alert.gl-alert-danger.js-ci-variable-error-box
%ul.ci-variable-list
= render 'ci/variables/variable_header'
diff --git a/app/views/clusters/clusters/_advanced_settings.html.haml b/app/views/clusters/clusters/_advanced_settings.html.haml
index 117bdbc06a1..bbdbda40297 100644
--- a/app/views/clusters/clusters/_advanced_settings.html.haml
+++ b/app/views/clusters/clusters/_advanced_settings.html.haml
@@ -24,17 +24,18 @@
.text-muted
= html_escape(s_('ClusterIntegration|A cluster management project can be used to run deployment jobs with Kubernetes %{code_open}cluster-admin%{code_close} privileges.')) % { code_open: '<code>'.html_safe, code_close: '</code>'.html_safe }
= link_to _('More information'), help_page_path('user/clusters/management_project.md'), target: '_blank'
- .gl-display-flex.gl-justify-content-end
- = field.submit _('Save changes'), class: 'btn btn-success'
+ = field.submit _('Save changes'), class: 'btn gl-button btn-success'
- - if @cluster.managed?
- .sub-section.form-group
- %h4
- = s_('ClusterIntegration|Clear cluster cache')
- %p
- = s_("ClusterIntegration|Clear the local cache of namespace and service accounts. This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts.")
- .gl-display-flex.gl-justify-content-end
- = link_to(s_('ClusterIntegration|Clear cluster cache'), clusterable.clear_cluster_cache_path(@cluster), method: :delete, class: 'btn btn-primary')
+ .sub-section.form-group
+ %h4
+ = s_('ClusterIntegration|Clear cluster cache')
+ %p
+ = s_("ClusterIntegration|Clear the local cache of namespace and service accounts.")
+ - if @cluster.managed?
+ = s_("ClusterIntegration|This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts.")
+ - else
+ = s_("ClusterIntegration|This is necessary to clear existing environment-namespace associations from clusters previously managed by GitLab.")
+ = link_to(s_('ClusterIntegration|Clear cluster cache'), clusterable.clear_cluster_cache_path(@cluster), method: :delete, class: 'btn gl-button btn-info')
.sub-section.form-group
%h4.text-danger
diff --git a/app/views/clusters/clusters/_buttons.html.haml b/app/views/clusters/clusters/_buttons.html.haml
deleted file mode 100644
index c81d1d5b05a..00000000000
--- a/app/views/clusters/clusters/_buttons.html.haml
+++ /dev/null
@@ -1,6 +0,0 @@
-.nav-controls
- - if clusterable.can_add_cluster?
- = link_to s_('ClusterIntegration|Add Kubernetes cluster'), clusterable.new_path, class: 'btn btn-success js-add-cluster'
- - else
- %span.btn.btn-add-cluster.disabled.js-add-cluster
- = s_("ClusterIntegration|Add Kubernetes cluster")
diff --git a/app/views/clusters/clusters/_cluster.html.haml b/app/views/clusters/clusters/_cluster.html.haml
deleted file mode 100644
index f11117ea5c4..00000000000
--- a/app/views/clusters/clusters/_cluster.html.haml
+++ /dev/null
@@ -1,19 +0,0 @@
-.card
- .card-body.gl-responsive-table-row
- .table-section.section-60
- .table-mobile-header{ role: "rowheader" }= s_("ClusterIntegration|Kubernetes cluster")
- .table-mobile-content.gl-display-flex.gl-align-items-center.gl-justify-content-end.gl-justify-content-md-start
- .gl-w-6.gl-h-6.gl-mr-3.gl-display-flex.gl-align-items-center= provider_icon(cluster.provider_type)
- = cluster.item_link(clusterable, html_options: { data: { qa_selector: 'cluster', qa_cluster_name: cluster.name } })
- - if cluster.status_name == :creating
- .spinner.ml-2.align-middle.has-tooltip{ title: s_("ClusterIntegration|Cluster being created") }
- - unless cluster.enabled?
- %span.badge.badge-danger Connection disabled
- .table-section.section-25
- .table-mobile-header{ role: "rowheader" }= s_("ClusterIntegration|Environment scope")
- .table-mobile-content= cluster.environment_scope
- .table-section.section-15.text-right
- .table-mobile-header{ role: "rowheader" }
- .table-mobile-content
- %span.badge.badge-light
- = cluster.cluster_type_description
diff --git a/app/views/clusters/clusters/_cluster_list.html.haml b/app/views/clusters/clusters/_cluster_list.html.haml
new file mode 100644
index 00000000000..9627d940126
--- /dev/null
+++ b/app/views/clusters/clusters/_cluster_list.html.haml
@@ -0,0 +1,12 @@
+- if clusters.empty?
+ = render 'empty_state'
+- else
+ .top-area.adjust
+ .gl-display-block.gl-text-right.gl-my-4.gl-w-full
+ - if clusterable.can_add_cluster?
+ = link_to s_('ClusterIntegration|Connect cluster with certificate'), clusterable.new_path, class: 'btn gl-button btn-success js-add-cluster gl-py-2', qa_selector: :integrate_kubernetes_cluster_button
+ - else
+ %span.btn.gl-button.btn-success.js-add-cluster.disabled.gl-py-2
+ = s_("ClusterIntegration|Connect cluster with certificate")
+
+ #js-clusters-list-app{ data: js_clusters_list_data(clusterable.index_path(format: :json)) }
diff --git a/app/views/clusters/clusters/_empty_state.html.haml b/app/views/clusters/clusters/_empty_state.html.haml
index cfdbfe2dea1..1798ba81075 100644
--- a/app/views/clusters/clusters/_empty_state.html.haml
+++ b/app/views/clusters/clusters/_empty_state.html.haml
@@ -3,12 +3,12 @@
.svg-content= image_tag 'illustrations/clusters_empty.svg'
.col-12
.text-content
- %h4.text-center= s_('ClusterIntegration|Integrate Kubernetes cluster automation')
- %p
+ %h4.gl-text-center= s_('ClusterIntegration|Integrate Kubernetes with a cluster certificate')
+ %p.gl-text-center
= s_('ClusterIntegration|Kubernetes clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way.')
= clusterable.empty_state_help_text
= clusterable.learn_more_link
- if clusterable.can_add_cluster?
- .text-center
- = link_to s_('ClusterIntegration|Add Kubernetes cluster'), clusterable.new_path, class: 'btn btn-success'
+ .gl-text-center
+ = link_to s_('ClusterIntegration|Integrate with a cluster certificate'), clusterable.new_path, class: 'btn btn-success'
diff --git a/app/views/clusters/clusters/_gcp_signup_offer_banner.html.haml b/app/views/clusters/clusters/_gcp_signup_offer_banner.html.haml
index 54f6fa91cf1..8c23fc7c590 100644
--- a/app/views/clusters/clusters/_gcp_signup_offer_banner.html.haml
+++ b/app/views/clusters/clusters/_gcp_signup_offer_banner.html.haml
@@ -1,11 +1,9 @@
- link = link_to(s_('ClusterIntegration|sign up'), 'https://console.cloud.google.com/freetrial?utm_campaign=2018_cpanel&utm_source=gitlab&utm_medium=referral', target: '_blank', rel: 'noopener noreferrer')
-.bs-callout.gcp-signup-offer.alert.alert-block.alert-dismissable.gl-mt-3.gl-mb-3{ role: 'alert', data: { feature_id: UserCalloutsHelper::GCP_SIGNUP_OFFER, dismiss_endpoint: user_callouts_path } }
- %button.close.js-close{ type: "button" } &times;
- .gcp-signup-offer--content
- .gcp-signup-offer--icon.gl-mr-3
- = sprite_icon("information")
- .gcp-signup-offer--copy
- %h4= s_('ClusterIntegration|Did you know?')
- %p= s_('ClusterIntegration|Every new Google Cloud Platform (GCP) account receives $300 in credit upon %{sign_up_link}. In partnership with Google, GitLab is able to offer an additional $200 for both new and existing GCP accounts to get started with GitLab\'s Google Kubernetes Engine Integration.').html_safe % { sign_up_link: link }
- %a.btn.btn-default{ href: 'https://cloud.google.com/partners/partnercredit/?pcn_code=0014M00001h35gDQAQ#contact-form', target: '_blank', rel: 'noopener noreferrer' }
- = s_("ClusterIntegration|Apply for credit")
+.gcp-signup-offer.gl-alert.gl-alert-info.gl-my-3{ role: 'alert', data: { feature_id: UserCalloutsHelper::GCP_SIGNUP_OFFER, dismiss_endpoint: user_callouts_path } }
+ %button.js-close.gl-alert-dismiss{ type: 'button', 'aria-label' => _('Dismiss') }
+ = sprite_icon('close', size: 16, css_class: 'gl-icon')
+ = sprite_icon('information-o', size: 16, css_class: 'gl-icon gl-alert-icon gl-alert-icon-no-title')
+ %h4.gl-alert-title= s_('ClusterIntegration|Did you know?')
+ %p.gl-alert-body= s_('ClusterIntegration|Every new Google Cloud Platform (GCP) account receives $300 in credit upon %{sign_up_link}. In partnership with Google, GitLab is able to offer an additional $200 for both new and existing GCP accounts to get started with GitLab\'s Google Kubernetes Engine Integration.').html_safe % { sign_up_link: link }
+ %a.gl-button.btn-info{ href: 'https://cloud.google.com/partners/partnercredit/?pcn_code=0014M00001h35gDQAQ#contact-form', target: '_blank', rel: 'noopener noreferrer' }
+ = s_("ClusterIntegration|Apply for credit")
diff --git a/app/views/clusters/clusters/_provider_details_form.html.haml b/app/views/clusters/clusters/_provider_details_form.html.haml
index e211851b939..16891c7fc21 100644
--- a/app/views/clusters/clusters/_provider_details_form.html.haml
+++ b/app/views/clusters/clusters/_provider_details_form.html.haml
@@ -42,11 +42,17 @@
class: 'js-gl-managed',
label_class: 'label-bold' }
.form-text.text-muted
- = s_('ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster.')
+ = s_('ClusterIntegration|Allow GitLab to manage namespaces and service accounts for this cluster.')
= link_to _('More information'), help_page_path('user/project/clusters/index.md', anchor: 'gitlab-managed-clusters'), target: '_blank'
+ .form-group
+ = field.check_box :namespace_per_environment, { label: s_('ClusterIntegration|Namespace per environment'), label_class: 'label-bold' }
+ .form-text.text-muted
+ = s_('ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared.')
+ = link_to _('More information'), help_page_path('user/project/clusters/index.md', anchor: 'custom-namespace'), target: '_blank'
+
- if cluster.allow_user_defined_namespace?
- = render('clusters/clusters/namespace', platform_field: platform_field)
+ = render('clusters/clusters/namespace', platform_field: platform_field, field: field)
- .form-group.gl-display-flex.gl-justify-content-end
+ .form-group
= field.submit s_('ClusterIntegration|Save changes'), class: 'btn btn-success'
diff --git a/app/views/clusters/clusters/aws/_new.html.haml b/app/views/clusters/clusters/aws/_new.html.haml
index 3eab9b46fb3..b1a277faae9 100644
--- a/app/views/clusters/clusters/aws/_new.html.haml
+++ b/app/views/clusters/clusters/aws/_new.html.haml
@@ -4,6 +4,7 @@
= s_('Amazon authentication is not %{link_start}correctly configured%{link_end}. Ask your GitLab administrator if you want to use this service.').html_safe % { link_start: documentation_link_start, link_end: '<a/>'.html_safe }
- else
.js-create-eks-cluster-form-container{ data: { 'gitlab-managed-cluster-help-path' => help_page_path('user/project/clusters/index.md', anchor: 'gitlab-managed-clusters'),
+ 'namespace-per-environment-help-path' => help_page_path('user/project/clusters/index.md', anchor: 'custom-namespace'),
'create-role-path' => clusterable.authorize_aws_role_path,
'create-cluster-path' => clusterable.create_aws_clusters_path,
'account-id' => Gitlab::CurrentSettings.eks_account_id,
diff --git a/app/views/clusters/clusters/gcp/_form.html.haml b/app/views/clusters/clusters/gcp/_form.html.haml
index 434c02a5c41..ceb6e1d46b0 100644
--- a/app/views/clusters/clusters/gcp/_form.html.haml
+++ b/app/views/clusters/clusters/gcp/_form.html.haml
@@ -75,9 +75,15 @@
= field.check_box :managed, { label: s_('ClusterIntegration|GitLab-managed cluster'),
label_class: 'label-bold' }
.form-text.text-muted
- = s_('ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster.')
+ = s_('ClusterIntegration|Allow GitLab to manage namespaces and service accounts for this cluster.')
= link_to _('More information'), help_page_path('user/project/clusters/index.md', anchor: 'gitlab-managed-clusters'), target: '_blank'
+ .form-group
+ = field.check_box :namespace_per_environment, { label: s_('ClusterIntegration|Namespace per environment'), label_class: 'label-bold' }
+ .form-text.text-muted
+ = s_('ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared.')
+ = link_to _('More information'), help_page_path('user/project/clusters/index.md', anchor: 'custom-namespace'), target: '_blank'
+
.form-group.js-gke-cluster-creation-submit-container
= field.submit s_('ClusterIntegration|Create Kubernetes cluster'),
class: 'js-gke-cluster-creation-submit btn btn-success', disabled: true
diff --git a/app/views/clusters/clusters/index.html.haml b/app/views/clusters/clusters/index.html.haml
index 557ad1bf280..45287a01cc9 100644
--- a/app/views/clusters/clusters/index.html.haml
+++ b/app/views/clusters/clusters/index.html.haml
@@ -3,30 +3,24 @@
= render_gcp_signup_offer
-.clusters-container
- - if @clusters.empty?
- = render "empty_state"
- - else
- .top-area.adjust
- .nav-text
- = s_('ClusterIntegration|Kubernetes clusters can be used to deploy applications and to provide Review Apps for this project')
- = render 'clusters/clusters/buttons'
+.clusters-container.gl-my-2
+ - if display_cluster_agents?(clusterable)
+ .js-toggle-container
+ %ul.nav-links.nav-tabs.nav{ role: 'tablist' }
+ %li.nav-item{ role: 'presentation' }
+ %a.nav-link.active{ href: "#certificate-clusters-pane", id: "certificate-clusters-tab", data: { toggle: 'tab' }, role: 'tab' }
+ %span= s_('ClusterIntegration|Clusters connected with a certificate')
+
+ %li.nav-item{ role: 'presentation' }
+ %a.nav-link{ href: "#agent-clusters-pane", id: "agent-clusters-tab", data: { toggle: 'tab' }, role: 'tab' }
+ %span= s_('ClusterIntegration|GitLab Agent managed clusters')
+
+ .tab-content
+ .tab-pane.active{ id: 'certificate-clusters-pane', role: 'tabpanel' }
+ = render 'cluster_list', clusters: @clusters
- - if Feature.enabled?(:clusters_list_redesign)
- #js-clusters-list-app{ data: js_clusters_list_data(clusterable.index_path(format: :json)) }
- - else
- - if @has_ancestor_clusters
- .bs-callout.bs-callout-info
- = s_('ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters.')
- %strong
- = link_to _('More information'), help_page_path('user/group/clusters/index', anchor: 'cluster-precedence')
- .clusters-table.js-clusters-list
- .gl-responsive-table-row.table-row-header{ role: "row" }
- .table-section.section-60{ role: "rowheader" }
- = s_("ClusterIntegration|Kubernetes cluster")
- .table-section.section-30{ role: "rowheader" }
- = s_("ClusterIntegration|Environment scope")
- .table-section.section-10{ role: "rowheader" }
- - @clusters.each do |cluster|
- = render "cluster", cluster: cluster.present(current_user: current_user)
- = paginate @clusters, theme: "gitlab"
+ .tab-pane{ id: 'agent-clusters-pane', role: 'tabpanel' }
+ #js-cluster-agents-list{ data: js_cluster_agents_list_data(clusterable) }
+
+ - else
+ = render 'cluster_list', clusters: @clusters
diff --git a/app/views/clusters/clusters/user/_form.html.haml b/app/views/clusters/clusters/user/_form.html.haml
index 11772107135..a6097038b2e 100644
--- a/app/views/clusters/clusters/user/_form.html.haml
+++ b/app/views/clusters/clusters/user/_form.html.haml
@@ -46,9 +46,15 @@
class: 'js-gl-managed',
label_class: 'label-bold' }
.form-text.text-muted
- = s_('ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster.')
+ = s_('ClusterIntegration|Allow GitLab to manage namespaces and service accounts for this cluster.')
= link_to _('More information'), help_page_path('user/project/clusters/index.md', anchor: 'gitlab-managed-clusters'), target: '_blank'
+ .form-group
+ = field.check_box :namespace_per_environment, { label: s_('ClusterIntegration|Namespace per environment'), label_class: 'label-bold' }
+ .form-text.text-muted
+ = s_('ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared.')
+ = link_to _('More information'), help_page_path('user/project/clusters/index.md', anchor: 'custom-namespace'), target: '_blank'
+
= field.fields_for :platform_kubernetes, @user_cluster.platform_kubernetes do |platform_kubernetes_field|
- if @user_cluster.allow_user_defined_namespace?
= render('clusters/clusters/namespace', platform_field: platform_kubernetes_field)
diff --git a/app/views/dashboard/merge_requests.html.haml b/app/views/dashboard/merge_requests.html.haml
index dd9fd34f284..2111b66d26e 100644
--- a/app/views/dashboard/merge_requests.html.haml
+++ b/app/views/dashboard/merge_requests.html.haml
@@ -14,7 +14,7 @@
.top-area
= render 'shared/issuable/nav', type: :merge_requests, display_count: !@no_filters_set
-= render 'shared/issuable/search_bar', type: :merge_requests
+= render 'shared/issuable/search_bar', type: :merge_requests, disable_target_branch: true
- if current_user && @no_filters_set
= render 'shared/dashboard/no_filter_selected'
diff --git a/app/views/dashboard/milestones/index.html.haml b/app/views/dashboard/milestones/index.html.haml
index a0c1c314a85..923e78ad360 100644
--- a/app/views/dashboard/milestones/index.html.haml
+++ b/app/views/dashboard/milestones/index.html.haml
@@ -1,6 +1,7 @@
- @hide_top_links = true
- page_title _('Milestones')
- header_title _('Milestones'), dashboard_milestones_path
+- add_page_specific_style 'page_bundles/milestone'
.page-title-holder.d-flex.align-items-center
%h1.page-title= _('Milestones')
diff --git a/app/views/dashboard/todos/_todo.html.haml b/app/views/dashboard/todos/_todo.html.haml
index 82abb9b3b8a..6fb387ecca3 100644
--- a/app/views/dashboard/todos/_todo.html.haml
+++ b/app/views/dashboard/todos/_todo.html.haml
@@ -2,7 +2,7 @@
.todo-avatar
= author_avatar(todo, size: 40)
- .todo-item.todo-block.align-self-center
+ .todo-item.todo-block.align-self-center{ data: { qa_selector: "todo_item_container" } }
.todo-title
- if todo_author_display?(todo)
= todo_target_state_pill(todo)
@@ -13,7 +13,7 @@
- else
(removed)
- %span.title-item.action-name
+ %span.title-item.action-name{ data: { qa_selector: "todo_action_name_content" } }
= todo_action_name(todo)
%span.title-item.todo-label.todo-target-link
@@ -22,7 +22,7 @@
- else
= _("(removed)")
- %span.title-item.todo-target-title
+ %span.title-item.todo-target-title{ data: { qa_selector: "todo_target_title_content" } }
= todo_target_title(todo)
%span.title-item.todo-project.todo-label
@@ -31,7 +31,7 @@
- if todo.self_assigned?
%span.title-item.action-name
- to yourself
+ = todo_self_addressing(todo)
%span.title-item
&middot;
@@ -57,5 +57,5 @@
- else
.todo-actions
= link_to restore_dashboard_todo_path(todo), method: :patch, class: 'btn btn-loading d-flex align-items-center js-add-todo', data: { href: restore_dashboard_todo_path(todo) } do
- Add a To Do
+ Add a to do
%span.spinner.ml-1
diff --git a/app/views/dashboard/todos/index.html.haml b/app/views/dashboard/todos/index.html.haml
index 9c6a6be1bc3..56506370ee0 100644
--- a/app/views/dashboard/todos/index.html.haml
+++ b/app/views/dashboard/todos/index.html.haml
@@ -3,7 +3,7 @@
- header_title _("To-Do List"), dashboard_todos_path
= render_dashboard_gold_trial(current_user)
-= stylesheet_link_tag 'page_bundles/todos'
+- add_page_specific_style 'page_bundles/todos'
.page-title-holder.d-flex.align-items-center
%h1.page-title= _('To-Do List')
@@ -83,7 +83,7 @@
.todos-list-container.js-todos-all
- if @todos.any?
- .js-todos-list-container
+ .js-todos-list-container{ data: { qa_selector: "todos_list_container" } }
.js-todos-options{ data: { per_page: @todos.limit_value, current_page: @todos.current_page, total_pages: @todos.total_pages } }
.card.card-without-border.card-without-margin
%ul.content-list.todos-list
diff --git a/app/views/devise/mailer/confirmation_instructions.text.erb b/app/views/devise/mailer/confirmation_instructions.text.erb
index 05fddddf415..925ad9bd22e 100644
--- a/app/views/devise/mailer/confirmation_instructions.text.erb
+++ b/app/views/devise/mailer/confirmation_instructions.text.erb
@@ -1 +1 @@
-<%= render partial: "confirmation_instructions_#{@resource.is_a?(User) ? 'account' : 'secondary'}" %> \ No newline at end of file
+<%= render partial: "confirmation_instructions_#{@resource.is_a?(User) ? 'account' : 'secondary'}" %>
diff --git a/app/views/devise/shared/_experimental_separate_sign_up_flow_box.html.haml b/app/views/devise/shared/_experimental_separate_sign_up_flow_box.html.haml
index 5f7345f306d..621bbb32a13 100644
--- a/app/views/devise/shared/_experimental_separate_sign_up_flow_box.html.haml
+++ b/app/views/devise/shared/_experimental_separate_sign_up_flow_box.html.haml
@@ -11,10 +11,10 @@
.name.form-row
.col.form-group
= f.label :first_name, _('First name'), for: 'new_user_first_name', class: 'label-bold'
- = f.text_field :first_name, class: 'form-control top js-block-emoji js-validate-length', :data => { :max_length => max_first_name_length, :max_length_message => _("First Name is too long (maximum is %{max_length} characters).") % { max_length: max_first_name_length }, :qa_selector => 'new_user_firstname_field' }, required: true, title: _("This field is required.")
+ = f.text_field :first_name, class: 'form-control top js-block-emoji js-validate-length', :data => { :max_length => max_first_name_length, :max_length_message => _("First name is too long (maximum is %{max_length} characters).") % { max_length: max_first_name_length }, :qa_selector => 'new_user_firstname_field' }, required: true, title: _("This field is required.")
.col.form-group
= f.label :last_name, _('Last name'), for: 'new_user_last_name', class: 'label-bold'
- = f.text_field :last_name, class: "form-control top js-block-emoji js-validate-length", :data => { :max_length => max_last_name_length, :max_length_message => _("Last Name is too long (maximum is %{max_length} characters).") % { max_length: max_last_name_length }, :qa_selector => 'new_user_lastname_field' }, required: true, title: _("This field is required.")
+ = f.text_field :last_name, class: "form-control top js-block-emoji js-validate-length", :data => { :max_length => max_last_name_length, :max_length_message => _("Last name is too long (maximum is %{max_length} characters).") % { max_length: max_last_name_length }, :qa_selector => 'new_user_lastname_field' }, required: true, title: _("This field is required.")
.username.form-group
= f.label :username, class: 'label-bold'
= f.text_field :username, class: "form-control middle js-block-emoji js-validate-length js-validate-username", :data => { :min_length => min_username_length, :min_length_message => s_("SignUp|Username is too short (minimum is %{min_length} characters).") % { min_length: min_username_length }, :max_length => max_username_length, :max_length_message => _("Username is too long (maximum is %{max_length} characters).") % { max_length: max_username_length }, :qa_selector => 'new_user_username_field' }, pattern: Gitlab::PathRegex::NAMESPACE_FORMAT_REGEX_JS, required: true, title: _("Please create a username with only alphanumeric characters.")
@@ -28,21 +28,12 @@
= f.label :password, class: 'label-bold'
= f.password_field :password, class: "form-control bottom", data: { qa_selector: 'new_user_password_field' }, required: true, pattern: ".{#{@minimum_password_length},}", title: _("Minimum length is %{minimum_password_length} characters.") % { minimum_password_length: @minimum_password_length }
%p.gl-field-hint.text-secondary= _('Minimum length is %{minimum_password_length} characters') % { minimum_password_length: @minimum_password_length }
- - if Gitlab::CurrentSettings.current_application_settings.enforce_terms? && !experiment_enabled?(:terms_opt_in)
- .form-group
- = check_box_tag :terms_opt_in, '1', false, required: true, data: { qa_selector: 'new_user_accept_terms_checkbox' }
- = label_tag :terms_opt_in do
- - terms_link = link_to s_("I accept the|Terms of Service and Privacy Policy"), terms_path, target: "_blank"
- - accept_terms_label = _("I accept the %{terms_link}") % { terms_link: terms_link }
- = accept_terms_label.html_safe
= render_if_exists 'devise/shared/email_opted_in', f: f
%div
- if show_recaptcha_sign_up?
= recaptcha_tags
.submit-container.mt-3
= f.submit _("Register"), class: "btn-register btn btn-block btn-success mb-0 p-2", data: { qa_selector: 'new_user_register_button' }
- - if experiment_enabled?(:terms_opt_in)
- %p.gl-text-gray-500.gl-mt-5.gl-mb-0
- = html_escape(_("By clicking Register, I agree that I have read and accepted the GitLab %{linkStart}Terms of Use and Privacy Policy%{linkEnd}")) % { linkStart: "<a href='#{terms_path}' target='_blank' rel='noreferrer noopener'>".html_safe, linkEnd: '</a>'.html_safe }
+ = render 'devise/shared/terms_of_service_notice'
- if omniauth_enabled? && button_based_providers_enabled?
= render 'devise/shared/experimental_separate_sign_up_flow_omniauth_box'
diff --git a/app/views/devise/shared/_signup_box.html.haml b/app/views/devise/shared/_signup_box.html.haml
index 07ef9a7914a..f4ac9ad696b 100644
--- a/app/views/devise/shared/_signup_box.html.haml
+++ b/app/views/devise/shared/_signup_box.html.haml
@@ -1,4 +1,4 @@
-- max_name_length = 255
+- max_first_name_length = max_last_name_length = 127
- max_username_length = 255
- min_username_length = 2
#register-pane.tab-pane.login-box{ role: 'tabpanel' }
@@ -8,9 +8,13 @@
= render "devise/shared/error_messages", resource: resource
- if Feature.enabled?(:invisible_captcha)
= invisible_captcha
- .name.form-group
- = f.label :name, _('Full name'), class: 'label-bold'
- = f.text_field :name, class: "form-control top js-block-emoji js-validate-length", :data => { :max_length => max_name_length, :max_length_message => s_("SignUp|Name is too long (maximum is %{max_length} characters).") % { max_length: max_name_length }, :qa_selector => 'new_user_name_field' }, required: true, title: _("This field is required.")
+ .name.form-row
+ .col.form-group
+ = f.label :first_name, _('First name'), for: 'new_user_first_name', class: 'label-bold'
+ = f.text_field :first_name, class: 'form-control top js-block-emoji js-validate-length', :data => { :max_length => max_first_name_length, :max_length_message => _("First name is too long (maximum is %{max_length} characters).") % { max_length: max_first_name_length }, :qa_selector => 'new_user_first_name_field' }, required: true, title: _("This field is required.")
+ .col.form-group
+ = f.label :last_name, _('Last name'), for: 'new_user_last_name', class: 'label-bold'
+ = f.text_field :last_name, class: "form-control top js-block-emoji js-validate-length", :data => { :max_length => max_last_name_length, :max_length_message => _("Last name is too long (maximum is %{max_length} characters).") % { max_length: max_last_name_length }, :qa_selector => 'new_user_last_name_field' }, required: true, title: _("This field is required.")
.username.form-group
= f.label :username, class: 'label-bold'
= f.text_field :username, class: "form-control middle js-block-emoji js-validate-length js-validate-username", :data => { :min_length => min_username_length, :min_length_message => s_("SignUp|Username is too short (minimum is %{min_length} characters).") % { min_length: min_username_length }, :max_length => max_username_length, :max_length_message => s_("SignUp|Username is too long (maximum is %{max_length} characters).") % { max_length: max_username_length }, :qa_selector => 'new_user_username_field' }, pattern: Gitlab::PathRegex::NAMESPACE_FORMAT_REGEX_JS, required: true, title: _("Please create a username with only alphanumeric characters.")
@@ -24,16 +28,10 @@
= f.label :password, class: 'label-bold'
= f.password_field :password, class: "form-control bottom", data: { qa_selector: 'new_user_password_field' }, required: true, pattern: ".{#{@minimum_password_length},}", title: _("Minimum length is %{minimum_password_length} characters.") % { minimum_password_length: @minimum_password_length }
%p.gl-field-hint.text-secondary= _('Minimum length is %{minimum_password_length} characters') % { minimum_password_length: @minimum_password_length }
- - if Gitlab::CurrentSettings.current_application_settings.enforce_terms?
- .form-group
- = check_box_tag :terms_opt_in, '1', false, required: true, data: { qa_selector: 'new_user_accept_terms_checkbox' }
- = label_tag :terms_opt_in do
- - terms_link = link_to s_("I accept the|Terms of Service and Privacy Policy"), terms_path, target: "_blank"
- - accept_terms_label = _("I accept the %{terms_link}") % { terms_link: terms_link }
- = accept_terms_label.html_safe
= render_if_exists 'devise/shared/email_opted_in', f: f
%div
- if show_recaptcha_sign_up?
= recaptcha_tags
.submit-container
= f.submit _("Register"), class: "btn-register btn", data: { qa_selector: 'new_user_register_button' }
+ = render 'devise/shared/terms_of_service_notice'
diff --git a/app/views/devise/shared/_terms_of_service_notice.html.haml b/app/views/devise/shared/_terms_of_service_notice.html.haml
new file mode 100644
index 00000000000..46b043b2831
--- /dev/null
+++ b/app/views/devise/shared/_terms_of_service_notice.html.haml
@@ -0,0 +1,5 @@
+- company_name = Gitlab.com? ? 'GitLab' : ''
+
+- if Gitlab::CurrentSettings.current_application_settings.enforce_terms?
+ %p.gl-text-gray-500.gl-mt-5.gl-mb-0
+ = html_escape(_("By clicking Register, I agree that I have read and accepted the %{company_name} %{linkStart}Terms of Use and Privacy Policy%{linkEnd}")) % { linkStart: "<a href='#{terms_path}' target='_blank' rel='noreferrer noopener'>".html_safe, linkEnd: '</a>'.html_safe, company_name: company_name }
diff --git a/app/views/discussions/_diff_with_notes.html.haml b/app/views/discussions/_diff_with_notes.html.haml
index 8a3c841de0b..b34b6f09662 100644
--- a/app/views/discussions/_diff_with_notes.html.haml
+++ b/app/views/discussions/_diff_with_notes.html.haml
@@ -29,7 +29,7 @@
%td.line_content.js-success-lazy-load
.js-code-placeholder
%td.js-error-lazy-load-diff.hidden.diff-loading-error-block
- - button = button_tag(_("Try again"), class: "btn-link btn-link-retry btn-no-padding js-toggle-lazy-diff-retry-button")
+ - button = button_tag(_("Try again"), class: "btn-link gl-button btn-link-retry btn-no-padding js-toggle-lazy-diff-retry-button")
= _("Unable to load the diff. %{button_try_again}").html_safe % { button_try_again: button}
= render "discussions/diff_discussion", discussions: [discussion], expanded: true
- else
diff --git a/app/views/discussions/_jump_to_next.html.haml b/app/views/discussions/_jump_to_next.html.haml
deleted file mode 100644
index 3db509f24a5..00000000000
--- a/app/views/discussions/_jump_to_next.html.haml
+++ /dev/null
@@ -1,9 +0,0 @@
-- discussion = local_assigns.fetch(:discussion, nil)
-- if current_user
- %jump-to-discussion{ "inline-template" => true, ":discussion-id" => "'#{discussion.try(:id)}'" }
- .btn-group{ role: "group", "v-show" => "!allResolved", "v-if" => "showButton" }
- %button.btn.btn-default.discussion-next-btn.has-tooltip{ "@click" => "jumpToNextUnresolvedDiscussion",
- ":title" => "buttonText",
- ":aria-label" => "buttonText",
- data: { container: "body" } }
- = custom_icon("next_discussion")
diff --git a/app/views/discussions/_new_issue_for_all_discussions.html.haml b/app/views/discussions/_new_issue_for_all_discussions.html.haml
deleted file mode 100644
index 50dd5864195..00000000000
--- a/app/views/discussions/_new_issue_for_all_discussions.html.haml
+++ /dev/null
@@ -1,8 +0,0 @@
-- if merge_request.discussions_can_be_resolved_by?(current_user) && can?(current_user, :create_issue, @project)
- .btn-group{ role: "group", "v-if" => "unresolvedDiscussionCount > 0" }
- = link_to custom_icon('icon_mr_issue'),
- new_project_issue_path(@project, merge_request_to_resolve_discussions_of: merge_request.iid),
- title: 'Resolve all discussions in new issue',
- aria: { label: 'Resolve all discussions in new issue' },
- data: { container: 'body' },
- class: 'new-issue-for-discussion btn btn-default discussion-create-issue-btn has-tooltip'
diff --git a/app/views/discussions/_new_issue_for_discussion.html.haml b/app/views/discussions/_new_issue_for_discussion.html.haml
deleted file mode 100644
index 49d5378d62e..00000000000
--- a/app/views/discussions/_new_issue_for_discussion.html.haml
+++ /dev/null
@@ -1,10 +0,0 @@
-- if discussion.can_resolve?(current_user) && can?(current_user, :create_issue, @project)
- %new-issue-for-discussion-btn{ ":discussion-id" => "'#{discussion.id}'",
- "inline-template" => true }
- .btn-group{ role: "group", "v-if" => "showButton" }
- = link_to custom_icon('icon_mr_issue'),
- new_project_issue_path(@project, merge_request_to_resolve_discussions_of: merge_request.iid, discussion_to_resolve: discussion.id),
- title: 'Resolve this thread in a new issue',
- aria: { label: 'Resolve this thread in a new issue' },
- data: { container: 'body' },
- class: 'new-issue-for-discussion btn btn-default discussion-create-issue-btn has-tooltip'
diff --git a/app/views/discussions/_notes.html.haml b/app/views/discussions/_notes.html.haml
index 0a5541c3e82..7db318f83b1 100644
--- a/app/views/discussions/_notes.html.haml
+++ b/app/views/discussions/_notes.html.haml
@@ -9,9 +9,9 @@
-# to the first note position when we click on a badge diff discussion
%ul.notes{ id: "discussion_#{discussion.id}", data: { discussion_id: discussion.id, position: discussion.notes[0].position.to_json } }
- if discussion.try(:on_image?) && show_toggle
- %button.diff-notes-collapse.js-diff-notes-toggle{ type: 'button' }
+ %button.gl-button.diff-notes-collapse.js-diff-notes-toggle{ type: 'button' }
= sprite_icon('collapse', css_class: 'collapse-icon')
- %button.btn-transparent.badge.badge-pill.js-diff-notes-toggle{ type: 'button' }
+ %button.gl-button.btn-transparent.badge.badge-pill.js-diff-notes-toggle{ type: 'button' }
= badge_counter
= render partial: "shared/notes/note", collection: discussion.notes, as: :note, locals: { badge_counter: badge_counter, show_image_comment_badge: show_image_comment_badge }
@@ -21,22 +21,8 @@
- if can_create_note?
%a.user-avatar-link.d-none.d-sm-block{ href: user_path(current_user) }
= image_tag avatar_icon_for_user(current_user), alt: current_user.to_reference, class: 'avatar s40'
- - if discussion.potentially_resolvable?
- - line_type = local_assigns.fetch(:line_type, nil)
-
- .discussion-with-resolve-btn
- .btn-group.discussion-with-resolve-btn{ role: "group" }
- .btn-group{ role: "group" }
- = link_to_reply_discussion(discussion, line_type)
-
- = render "discussions/resolve_all", discussion: discussion
-
- .btn-group.discussion-actions
- = render "discussions/new_issue_for_discussion", discussion: discussion, merge_request: discussion.noteable
- = render "discussions/jump_to_next", discussion: discussion
- - else
- .discussion-with-resolve-btn
- = link_to_reply_discussion(discussion)
+ .discussion-with-resolve-btn
+ = link_to_reply_discussion(discussion)
- elsif !current_user
.disabled-comment.text-center
Please
diff --git a/app/views/doorkeeper/applications/_delete_form.html.haml b/app/views/doorkeeper/applications/_delete_form.html.haml
index 77b7a50338c..64b872b5610 100644
--- a/app/views/doorkeeper/applications/_delete_form.html.haml
+++ b/app/views/doorkeeper/applications/_delete_form.html.haml
@@ -1,4 +1,4 @@
-- submit_btn_css ||= 'btn btn-link btn-remove btn-sm'
+- submit_btn_css ||= 'gl-button btn btn-danger btn-sm'
= form_tag oauth_application_path(application) do
%input{ :name => "_method", :type => "hidden", :value => "delete" }/
- if defined? small
diff --git a/app/views/doorkeeper/authorized_applications/_delete_form.html.haml b/app/views/doorkeeper/authorized_applications/_delete_form.html.haml
index 9bc5e2ee42f..d73d171798e 100644
--- a/app/views/doorkeeper/authorized_applications/_delete_form.html.haml
+++ b/app/views/doorkeeper/authorized_applications/_delete_form.html.haml
@@ -5,4 +5,4 @@
= form_tag path do
%input{ :name => "_method", :type => "hidden", :value => "delete" }/
- = submit_tag _('Revoke'), class: 'btn btn-remove btn-sm', data: { confirm: _('Are you sure?') }
+ = submit_tag _('Revoke'), class: 'gl-button btn btn-danger btn-sm', data: { confirm: _('Are you sure?') }
diff --git a/app/views/events/event/_common.html.haml b/app/views/events/event/_common.html.haml
index a38d6dd3836..93c6efc9083 100644
--- a/app/views/events/event/_common.html.haml
+++ b/app/views/events/event/_common.html.haml
@@ -7,7 +7,7 @@
- if event.target
%span.event-type.d-inline-block.gl-mr-2{ class: event.action_name }
= event.action_name
- %span.event-target-type.gl-mr-2= event.target_type.titleize.downcase
+ %span.event-target-type.gl-mr-2= event.target_type_name
= link_to event.target_link_options, class: 'has-tooltip event-target-link gl-mr-2', title: event.target_title do
= event.target.reference_link_text
- unless event.milestone?
diff --git a/app/views/groups/_invite_members_modal.html.haml b/app/views/groups/_invite_members_modal.html.haml
new file mode 100644
index 00000000000..51f41d58029
--- /dev/null
+++ b/app/views/groups/_invite_members_modal.html.haml
@@ -0,0 +1,6 @@
+- if invite_members_allowed?(group)
+ .js-invite-members-modal{ data: { group_id: group.id,
+ group_name: group.name,
+ access_levels: GroupMember.access_level_roles.to_json,
+ default_access_level: Gitlab::Access::GUEST,
+ help_link: help_page_url('user/permissions') } }
diff --git a/app/views/groups/_invite_members_side_nav_link.html.haml b/app/views/groups/_invite_members_side_nav_link.html.haml
new file mode 100644
index 00000000000..1c90eaee992
--- /dev/null
+++ b/app/views/groups/_invite_members_side_nav_link.html.haml
@@ -0,0 +1,3 @@
+- if invite_members_allowed?(group) && body_data_page == 'groups:show'
+ %li
+ .js-invite-members-trigger{ data: { icon: 'plus', display_text: 'Invite team members' } }
diff --git a/app/views/groups/group_members/index.html.haml b/app/views/groups/group_members/index.html.haml
index ed7b201323a..d999f20ef91 100644
--- a/app/views/groups/group_members/index.html.haml
+++ b/app/views/groups/group_members/index.html.haml
@@ -4,7 +4,6 @@
- show_access_requests = can_manage_members && @requesters.exists?
- invited_active = params[:search_invited].present? || params[:invited_members_page].present?
- vue_members_list_enabled = Feature.enabled?(:vue_group_members_list, @group)
-- data_attributes = { group_id: @group.id }
- form_item_label_css_class = 'label-bold gl-mr-2 gl-mb-0 gl-py-2 align-self-md-center'
@@ -69,7 +68,7 @@
= label_tag :sort_by, _('Sort by'), class: form_item_label_css_class
= render 'shared/members/sort_dropdown'
- if vue_members_list_enabled
- .js-group-members-list{ data: { members: members_data_json(@group, @members), **data_attributes } }
+ .js-group-members-list{ data: group_members_list_data_attributes(@group, @members) }
- else
%ul.content-list.members-list{ data: { qa_selector: 'members_list' } }
= render partial: 'shared/members/member', collection: @members, as: :member
@@ -81,7 +80,7 @@
= render 'groups/group_members/tab_pane/title' do
= html_escape(_('Groups with access to %{strong_start}%{group_name}%{strong_end}')) % { group_name: @group.name, strong_start: '<strong>'.html_safe, strong_end: '</strong>'.html_safe }
- if vue_members_list_enabled
- .js-group-linked-list{ data: { members: linked_groups_data_json(@group.shared_with_group_links), **data_attributes } }
+ .js-group-linked-list{ data: linked_groups_list_data_attributes(@group) }
- else
%ul.content-list.members-list{ data: { qa_selector: 'groups_list' } }
- @group.shared_with_group_links.each do |group_link|
@@ -95,7 +94,7 @@
= form_tag group_group_members_path(@group), method: :get, class: 'user-search-form', data: { testid: 'user-search-form' } do
= render 'shared/members/search_field', name: 'search_invited'
- if vue_members_list_enabled
- .js-group-invited-members-list{ data: { members: members_data_json(@group, @invited_members), **data_attributes } }
+ .js-group-invited-members-list{ data: group_members_list_data_attributes(@group, @invited_members) }
- else
%ul.content-list.members-list
= render partial: 'shared/members/member', collection: @invited_members, as: :member
@@ -107,7 +106,7 @@
= render 'groups/group_members/tab_pane/title' do
= html_escape(_('Users requesting access to %{strong_start}%{group_name}%{strong_end}')) % { group_name: @group.name, strong_start: '<strong>'.html_safe, strong_end: '</strong>'.html_safe }
- if vue_members_list_enabled
- .js-group-access-requests-list{ data: { members: members_data_json(@group, @requesters), **data_attributes } }
+ .js-group-access-requests-list{ data: group_members_list_data_attributes(@group, @requesters) }
- else
%ul.content-list.members-list
= render partial: 'shared/members/member', collection: @requesters, as: :member
diff --git a/app/views/groups/issues.html.haml b/app/views/groups/issues.html.haml
index 1358e848154..33a9f423da6 100644
--- a/app/views/groups/issues.html.haml
+++ b/app/views/groups/issues.html.haml
@@ -1,6 +1,7 @@
- @can_bulk_update = can?(current_user, :admin_issue, @group) && @group.feature_available?(:group_bulk_edit)
- page_title _("Issues")
+- add_page_specific_style 'page_bundles/issues_list'
= content_for :meta_tags do
= auto_discovery_link_tag(:atom, safe_params.merge(rss_url_options).to_h, title: "#{@group.name} issues")
@@ -23,9 +24,12 @@
= render_if_exists 'shared/issuable/group_bulk_update_sidebar', group: @group, type: :issues
- if Feature.enabled?(:vue_issuables_list, @group)
+ - if use_startup_call?
+ - add_page_startup_api_call(api_v4_groups_issues_path(id: @group.id, params: startup_call_params))
.js-issuables-list{ data: { endpoint: expose_url(api_v4_groups_issues_path(id: @group.id)),
'can-bulk-edit': @can_bulk_update.to_json,
'empty-state-meta': { svg_path: image_path('illustrations/issues.svg') },
- 'sort-key': @sort } }
+ 'sort-key': @sort,
+ type: 'issues' } }
- else
= render 'shared/issues'
diff --git a/app/views/groups/labels/destroy.js.haml b/app/views/groups/labels/destroy.js.haml
deleted file mode 100644
index 3dfbfc77c0d..00000000000
--- a/app/views/groups/labels/destroy.js.haml
+++ /dev/null
@@ -1,2 +0,0 @@
-- if @group.labels.empty?
- $('.labels').load(document.URL + ' .nothing-here-block').hide().fadeIn(1000)
diff --git a/app/views/groups/labels/index.html.haml b/app/views/groups/labels/index.html.haml
index 3299d127222..debbe95d2aa 100644
--- a/app/views/groups/labels/index.html.haml
+++ b/app/views/groups/labels/index.html.haml
@@ -27,5 +27,5 @@
= render 'shared/empty_states/labels'
%template#js-badge-item-template
- %li.label-link-item.js-priority-badge.inline.gl-ml-3
- .label-badge.label-badge-blue= _('Prioritized label')
+ %li.js-priority-badge.inline.gl-ml-3
+ .label-badge.gl-bg-blue-50= _('Prioritized label')
diff --git a/app/views/groups/milestones/index.html.haml b/app/views/groups/milestones/index.html.haml
index 1685707d457..d20fa938a68 100644
--- a/app/views/groups/milestones/index.html.haml
+++ b/app/views/groups/milestones/index.html.haml
@@ -1,4 +1,5 @@
- page_title _("Milestones")
+- add_page_specific_style 'page_bundles/milestone'
.top-area
= render 'shared/milestones_filter', counts: @milestone_states
diff --git a/app/views/groups/milestones/show.html.haml b/app/views/groups/milestones/show.html.haml
index 33e68bc766e..5bbdd3a3b19 100644
--- a/app/views/groups/milestones/show.html.haml
+++ b/app/views/groups/milestones/show.html.haml
@@ -1,3 +1,4 @@
+- add_page_specific_style 'page_bundles/milestone'
= render "header_title"
= render 'shared/milestones/top', milestone: @milestone, group: @group
= render 'shared/milestones/tabs', milestone: @milestone, show_project_name: true
diff --git a/app/views/groups/projects.html.haml b/app/views/groups/projects.html.haml
index 555c4004a3f..4fa2fc6fd4d 100644
--- a/app/views/groups/projects.html.haml
+++ b/app/views/groups/projects.html.haml
@@ -15,7 +15,7 @@
.controls
= link_to _('Members'), project_project_members_path(project), id: "edit_#{dom_id(project)}", class: "btn"
= link_to _('Edit'), edit_project_path(project), id: "edit_#{dom_id(project)}", class: "btn"
- = link_to _('Delete'), project, data: { confirm: remove_project_message(project)}, method: :delete, class: "btn btn-remove"
+ = link_to _('Delete'), project, data: { confirm: remove_project_message(project)}, method: :delete, class: "gl-button btn btn-danger"
.stats
%span.badge.badge-pill
diff --git a/app/views/groups/registry/repositories/index.html.haml b/app/views/groups/registry/repositories/index.html.haml
index 2cac8e653e5..21882c3e3ce 100644
--- a/app/views/groups/registry/repositories/index.html.haml
+++ b/app/views/groups/registry/repositories/index.html.haml
@@ -12,6 +12,8 @@
"containers_error_image" => image_path('illustrations/docker-error-state.svg'),
"registry_host_url_with_port" => escape_once(registry_config.host_port),
"garbage_collection_help_page_path" => help_page_path('administration/packages/container_registry', anchor: 'container-registry-garbage-collection'),
+ "run_cleanup_policies_help_page_path" => help_page_path('administration/packages/container_registry', anchor: 'run-the-cleanup-policy-now'),
+ "cleanup_policies_help_page_path" => help_page_path('user/packages/container_registry/index', anchor: 'how-the-cleanup-policy-works'),
"is_admin": current_user&.admin.to_s,
is_group_page: "true",
character_error: @character_error.to_s } }
diff --git a/app/views/groups/runners/_index.html.haml b/app/views/groups/runners/_index.html.haml
index e885fcc08eb..b342b589d93 100644
--- a/app/views/groups/runners/_index.html.haml
+++ b/app/views/groups/runners/_index.html.haml
@@ -7,6 +7,8 @@
.row
.col-sm-6
= render 'groups/runners/group_runners'
+ .col-sm-6
+ = render 'groups/runners/shared_runners'
%h4.underlined-title
= _('Available Runners: %{runners}').html_safe % { runners: limited_counter_with_delimiter(@all_group_runners) }
diff --git a/app/views/groups/runners/_shared_runners.html.haml b/app/views/groups/runners/_shared_runners.html.haml
new file mode 100644
index 00000000000..15b1199b8c9
--- /dev/null
+++ b/app/views/groups/runners/_shared_runners.html.haml
@@ -0,0 +1,3 @@
+= render 'shared/runners/shared_runners_description'
+
+#update-shared-runners-form{ data: group_shared_runners_settings_data(@group) }
diff --git a/app/views/groups/settings/_advanced.html.haml b/app/views/groups/settings/_advanced.html.haml
index 98f4acaa5e3..c421a569a14 100644
--- a/app/views/groups/settings/_advanced.html.haml
+++ b/app/views/groups/settings/_advanced.html.haml
@@ -22,8 +22,7 @@
pattern: Gitlab::PathRegex::NAMESPACE_FORMAT_REGEX_JS,
title: s_('GroupSettings|Please choose a group URL with no special characters.'),
"data-bind-in" => "#{'create_chat_team' if Gitlab.config.mattermost.enabled}"
- .gl-display-flex.gl-justify-content-end
- = f.submit s_('GroupSettings|Change group URL'), class: 'btn btn-warning'
+ = f.submit s_('GroupSettings|Change group URL'), class: 'btn btn-warning'
.sub-section
%h4.warning-title= s_('GroupSettings|Transfer group')
@@ -33,14 +32,13 @@
= hidden_field_tag 'new_parent_group_id'
%ul
- - side_effects_link_start = '<a href="https://docs.gitlab.com/ce/user/project/index.html#redirects-when-changing-repository-paths" target="_blank">'
+ - side_effects_link_start = '<a href="https://docs.gitlab.com/ee/user/project/index.html#redirects-when-changing-repository-paths" target="_blank">'
- warning_text = s_("GroupSettings|Be careful. Changing a group's parent can have unintended %{side_effects_link_start}side effects%{side_effects_link_end}.") % { side_effects_link_start: side_effects_link_start, side_effects_link_end:'</a>' }
%li= warning_text.html_safe
%li= s_('GroupSettings|You can only transfer the group to a group you manage.')
%li= s_('GroupSettings|You will need to update your local repositories to point to the new location.')
%li= s_("GroupSettings|If the parent group's visibility is lower than the group current visibility, visibility levels for subgroups and projects will be changed to match the new parent group's visibility.")
- .gl-display-flex.gl-justify-content-end
- = f.submit s_('GroupSettings|Transfer group'), class: 'btn btn-warning'
+ = f.submit s_('GroupSettings|Transfer group'), class: 'btn btn-warning'
= render 'groups/settings/remove', group: @group
= render_if_exists 'groups/settings/restore', group: @group
diff --git a/app/views/groups/settings/_export.html.haml b/app/views/groups/settings/_export.html.haml
index af06cfff397..94466b76ac8 100644
--- a/app/views/groups/settings/_export.html.haml
+++ b/app/views/groups/settings/_export.html.haml
@@ -24,6 +24,5 @@
= link_to _('Download export'), download_export_group_path(group),
rel: 'nofollow', method: :get, class: 'btn btn-default', data: { qa_selector: 'download_export_link' }
- else
- .gl-display-flex.gl-justify-content-end
- = link_to _('Export group'), export_group_path(group),
- method: :post, class: 'btn btn-default', data: { qa_selector: 'export_group_link' }
+ = link_to _('Export group'), export_group_path(group),
+ method: :post, class: 'btn btn-default', data: { qa_selector: 'export_group_link' }
diff --git a/app/views/groups/settings/_general.html.haml b/app/views/groups/settings/_general.html.haml
index e43d49b229e..35d82084263 100644
--- a/app/views/groups/settings/_general.html.haml
+++ b/app/views/groups/settings/_general.html.haml
@@ -29,5 +29,4 @@
= link_to _('Remove avatar'), group_avatar_path(@group.to_param), data: { confirm: _('Avatar will be removed. Are you sure?')}, method: :delete, class: 'btn btn-link'
= render 'shared/visibility_level', f: f, visibility_level: @group.visibility_level, can_change_visibility_level: can_change_group_visibility_level?(@group), form_model: @group
- .gl-display-flex.gl-justify-content-end
- = f.submit _('Save changes'), class: 'btn btn-success mt-4 js-dirty-submit', data: { qa_selector: 'save_name_visibility_settings_button' }
+ = f.submit _('Save changes'), class: 'btn btn-success mt-4 js-dirty-submit', data: { qa_selector: 'save_name_visibility_settings_button' }
diff --git a/app/views/groups/settings/_permanent_deletion.html.haml b/app/views/groups/settings/_permanent_deletion.html.haml
index 063ff6dd132..14719200b45 100644
--- a/app/views/groups/settings/_permanent_deletion.html.haml
+++ b/app/views/groups/settings/_permanent_deletion.html.haml
@@ -5,5 +5,4 @@
= _('Removing this group also removes all child projects, including archived projects, and their resources.')
%br
%strong= _('Removed group can not be restored!')
- .gl-display-flex.gl-justify-content-end
- = button_to _('Remove group'), '#', class: 'btn btn-remove js-confirm-danger', data: { 'confirm-danger-message' => remove_group_message(group) }
+ = button_to _('Remove group'), '#', class: 'gl-button btn btn-danger js-confirm-danger', data: { 'confirm-danger-message' => remove_group_message(group) }
diff --git a/app/views/groups/settings/_permissions.html.haml b/app/views/groups/settings/_permissions.html.haml
index 86f49672d66..21d6a888d7b 100644
--- a/app/views/groups/settings/_permissions.html.haml
+++ b/app/views/groups/settings/_permissions.html.haml
@@ -38,8 +38,7 @@
= render 'groups/settings/project_creation_level', f: f, group: @group
= render 'groups/settings/subgroup_creation_level', f: f, group: @group
= render_if_exists 'groups/settings/prevent_forking', f: f, group: @group
- = render 'groups/settings/two_factor_auth', f: f
+ = render 'groups/settings/two_factor_auth', f: f, group: @group
= render_if_exists 'groups/personal_access_token_expiration_policy', f: f, group: @group
= render_if_exists 'groups/member_lock_setting', f: f, group: @group
- .gl-display-flex.gl-justify-content-end
- = f.submit _('Save changes'), class: 'btn btn-success gl-mt-3 js-dirty-submit', data: { qa_selector: 'save_permissions_changes_button' }
+ = f.submit _('Save changes'), class: 'btn btn-success gl-mt-3 js-dirty-submit', data: { qa_selector: 'save_permissions_changes_button' }
diff --git a/app/views/groups/settings/_two_factor_auth.html.haml b/app/views/groups/settings/_two_factor_auth.html.haml
index c49e61c8a31..d2d4c27c826 100644
--- a/app/views/groups/settings/_two_factor_auth.html.haml
+++ b/app/views/groups/settings/_two_factor_auth.html.haml
@@ -1,3 +1,4 @@
+- return unless group.parent_allows_two_factor_authentication?
- docs_link_url = help_page_path('security/two_factor_authentication', anchor: 'enforcing-2fa-for-all-users-in-a-group')
- docs_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: docs_link_url }
@@ -9,8 +10,14 @@
.form-check
= f.check_box :require_two_factor_authentication, class: 'form-check-input', data: { qa_selector: 'require_2fa_checkbox' }
= f.label :require_two_factor_authentication, class: 'form-check-label' do
- %span= _('Require all users in this group to setup Two-factor authentication')
+ %span= _('Require all users in this group to setup two-factor authentication')
.form-group
= f.label :two_factor_grace_period, _('Time before enforced'), class: 'label-bold'
= f.text_field :two_factor_grace_period, class: 'form-control form-control-sm w-auto'
.form-text.text-muted= _('Amount of time (in hours) that users are allowed to skip forced configuration of two-factor authentication')
+- unless group.has_parent?
+ .form-group
+ .form-check
+ = f.check_box :allow_mfa_for_subgroups, class: 'form-check-input', checked: group.namespace_settings.allow_mfa_for_subgroups
+ = f.label :allow_mfa_for_subgroups, class: 'form-check-label' do
+ = _('Allow subgroups to set up their own two-factor authentication rules')
diff --git a/app/views/groups/show.html.haml b/app/views/groups/show.html.haml
index ec4ab603d22..fa560942c5d 100644
--- a/app/views/groups/show.html.haml
+++ b/app/views/groups/show.html.haml
@@ -23,6 +23,8 @@
= render_if_exists 'groups/group_activity_analytics', group: @group
+= render_if_exists 'groups/invite_members_modal', group: @group
+
.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
diff --git a/app/views/ide/_show.html.haml b/app/views/ide/_show.html.haml
index d0384fd50bc..79cba2a54b0 100644
--- a/app/views/ide/_show.html.haml
+++ b/app/views/ide/_show.html.haml
@@ -1,8 +1,7 @@
- @body_class = 'ide-layout'
- page_title _('IDE')
-- content_for :page_specific_javascripts do
- = stylesheet_link_tag 'page_bundles/ide'
+- add_page_specific_style 'page_bundles/ide'
#ide.ide-loading{ data: ide_data }
.text-center
diff --git a/app/views/import/bitbucket/status.html.haml b/app/views/import/bitbucket/status.html.haml
index 9b54cbe577a..8946ab898e0 100644
--- a/app/views/import/bitbucket/status.html.haml
+++ b/app/views/import/bitbucket/status.html.haml
@@ -1,8 +1,9 @@
- page_title _('Bitbucket import')
- header_title _('Projects'), root_path
-%h3.page-title
- %i.fa.fa-bitbucket
+%h3.page-title.d-flex
+ .gl-display-flex.gl-align-items-center.gl-justify-content-center
+ = sprite_icon('bitbucket', css_class: 'gl-mr-2')
= _('Import projects from Bitbucket')
= render 'import/githubish_status', provider: 'bitbucket'
diff --git a/app/views/import/bitbucket_server/new.html.haml b/app/views/import/bitbucket_server/new.html.haml
index 735535ffc36..19c28d53087 100644
--- a/app/views/import/bitbucket_server/new.html.haml
+++ b/app/views/import/bitbucket_server/new.html.haml
@@ -3,8 +3,10 @@
- breadcrumb_title title
- header_title _("Projects"), root_path
-%h3.page-title
- = icon 'bitbucket-square', text: _('Import repositories from Bitbucket Server')
+%h3.page-title.d-flex
+ .gl-display-flex.gl-align-items-center.gl-justify-content-center
+ = sprite_icon('bitbucket', css_class: 'gl-mr-2')
+ = _('Import repositories from Bitbucket Server')
%p
= _('Enter in your Bitbucket Server URL and personal access token below')
diff --git a/app/views/import/bitbucket_server/status.html.haml b/app/views/import/bitbucket_server/status.html.haml
index b3ca1beb853..7c4e6913c53 100644
--- a/app/views/import/bitbucket_server/status.html.haml
+++ b/app/views/import/bitbucket_server/status.html.haml
@@ -1,8 +1,9 @@
- page_title _('Bitbucket Server import')
- header_title _('Projects'), root_path
-%h3.page-title
- %i.fa.fa-bitbucket-square
+%h3.page-title.d-flex
+ .gl-display-flex.gl-align-items-center.gl-justify-content-center
+ = sprite_icon('bitbucket', css_class: 'gl-mr-2')
= _('Import projects from Bitbucket Server')
= render 'import/githubish_status', provider: 'bitbucket_server', paginatable: true, extra_data: { reconfigure_path: configure_import_bitbucket_server_path }
diff --git a/app/views/import/bulk_imports/status.html.haml b/app/views/import/bulk_imports/status.html.haml
new file mode 100644
index 00000000000..d909f6a13f0
--- /dev/null
+++ b/app/views/import/bulk_imports/status.html.haml
@@ -0,0 +1 @@
+- page_title 'Bulk Import'
diff --git a/app/views/import/github/new.html.haml b/app/views/import/github/new.html.haml
index e86d4236be8..7e49cad7902 100644
--- a/app/views/import/github/new.html.haml
+++ b/app/views/import/github/new.html.haml
@@ -10,7 +10,9 @@
= import_github_authorize_message
- if github_import_configured? && !has_ci_cd_only_params?
- = link_to icon('github', text: title), status_import_github_path, class: 'btn btn-success'
+ = link_to status_import_github_path, class: 'btn btn-success gl-button' do
+ = sprite_icon('github', css_class: 'gl-mr-2')
+ = title
%hr
diff --git a/app/views/import/github/status.html.haml b/app/views/import/github/status.html.haml
index ee295e70cce..ba6a5657d12 100644
--- a/app/views/import/github/status.html.haml
+++ b/app/views/import/github/status.html.haml
@@ -2,7 +2,9 @@
- page_title title
- breadcrumb_title title
- header_title _("Projects"), root_path
-%h3.page-title.mb-0
- = icon 'github', class: 'fa-2x', text: _('Import repositories from GitHub')
+%h3.page-title.mb-0.gl-display-flex
+ .gl-display-flex.gl-align-items-center.gl-justify-content-center
+ = sprite_icon('github', css_class: 'gl-mr-2')
+ = _('Import repositories from GitHub')
= render 'import/githubish_status', provider: 'github'
diff --git a/app/views/import/google_code/new.html.haml b/app/views/import/google_code/new.html.haml
index 7dec67191b9..1edd224956c 100644
--- a/app/views/import/google_code/new.html.haml
+++ b/app/views/import/google_code/new.html.haml
@@ -1,7 +1,8 @@
- page_title _("Google Code import")
- header_title _("Projects"), root_path
-%h3.page-title
- %i.fa.fa-google
+%h3.page-title.gl-display-flex
+ .gl-display-flex.gl-align-items-center.gl-justify-content-center
+ = sprite_icon('google', css_class: 'gl-mr-2')
= _('Import projects from Google Code')
%hr
diff --git a/app/views/import/google_code/new_user_map.html.haml b/app/views/import/google_code/new_user_map.html.haml
index 1f1bfda7ee4..833987dea4e 100644
--- a/app/views/import/google_code/new_user_map.html.haml
+++ b/app/views/import/google_code/new_user_map.html.haml
@@ -1,7 +1,8 @@
- page_title _("User map"), _("Google Code import")
- header_title _("Projects"), root_path
-%h3.page-title
- %i.fa.fa-google
+%h3.page-title.gl-display-flex
+ .gl-display-flex.gl-align-items-center.gl-justify-content-center
+ = sprite_icon('google', css_class: 'gl-mr-2')
= _('Import projects from Google Code')
%hr
diff --git a/app/views/import/google_code/status.html.haml b/app/views/import/google_code/status.html.haml
index 22984d59afe..72112c128cb 100644
--- a/app/views/import/google_code/status.html.haml
+++ b/app/views/import/google_code/status.html.haml
@@ -1,7 +1,8 @@
- page_title _("Google Code import")
- header_title _("Projects"), root_path
-%h3.page-title
- %i.fa.fa-google
+%h3.page-title.gl-display-flex
+ .gl-display-flex.gl-align-items-center.gl-justify-content-center
+ = sprite_icon('google', css_class: 'gl-mr-2')
= _('Import projects from Google Code')
- if @repos.any?
diff --git a/app/views/import/shared/_errors.html.haml b/app/views/import/shared/_errors.html.haml
index de60c15351f..32b4a39924b 100644
--- a/app/views/import/shared/_errors.html.haml
+++ b/app/views/import/shared/_errors.html.haml
@@ -1,4 +1,6 @@
- if @errors.present?
- .alert.alert-danger
- - @errors.each do |error|
- = error
+ .gl-alert.gl-alert-danger.gl-mb-5
+ = sprite_icon('error', size: 16, css_class: 'gl-icon gl-alert-icon gl-alert-icon-no-title')
+ .gl-alert-body
+ - @errors.each do |error|
+ = error
diff --git a/app/views/invites/decline.html.haml b/app/views/invites/decline.html.haml
new file mode 100644
index 00000000000..4a57d70cb6e
--- /dev/null
+++ b/app/views/invites/decline.html.haml
@@ -0,0 +1,8 @@
+- page_title _('Invitation declined')
+.decline-page.gl-display-flex.gl-flex-direction-column.gl-mx-auto{ class: 'gl-xs-w-full!' }
+ .gl-align-self-center.gl-mb-4.gl-mt-7.gl-sm-mt-0= sprite_icon('check-circle', size: 48, css_class: 'gl-text-green-400')
+ %h2.gl-font-size-h2= _('You successfully declined the invitation')
+ %p
+ = html_escape(_('We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders.')) % { inviter: sanitize_name(@member.created_by.name) }
+ %p
+ = _('You can now close this window.')
diff --git a/app/views/invites/show.html.haml b/app/views/invites/show.html.haml
index 6b3996bee76..37143799132 100644
--- a/app/views/invites/show.html.haml
+++ b/app/views/invites/show.html.haml
@@ -25,5 +25,5 @@
- if !member?
.actions
- = link_to _("Accept invitation"), accept_invite_url(@token, new_user_invite: params[:new_user_invite]), method: :post, class: "btn btn-success"
- = link_to _("Decline"), decline_invite_url(@token), method: :post, class: "btn btn-danger gl-ml-3"
+ = link_to _("Accept invitation"), accept_invite_url(@token, new_user_invite: params[:new_user_invite]), method: :post, class: "btn gl-button btn-success"
+ = link_to _("Decline"), decline_invite_url(@token), method: :post, class: "btn gl-button btn-danger gl-ml-3"
diff --git a/app/views/jira_connect/subscriptions/index.html.haml b/app/views/jira_connect/subscriptions/index.html.haml
index f7ecfd09209..655c413f2a6 100644
--- a/app/views/jira_connect/subscriptions/index.html.haml
+++ b/app/views/jira_connect/subscriptions/index.html.haml
@@ -1,28 +1,61 @@
-%h1
- GitLab for Jira Configuration
-
-%form#add-subscription-form.subscription-form{ action: jira_connect_subscriptions_path }
- .ak-field-group
- %label
- Namespace
-
- .ak-field-group.field-group-input
- %input#namespace-input.ak-field-text{ type: 'text', required: true }
- %button.ak-button.ak-button__appearance-primary{ type: 'submit' }
- Link namespace to Jira
-
-%table.subscriptions
- %thead
- %tr
- %th Namespace
- %th Added
- %th
- %tbody
- - @subscriptions.each do |subscription|
- %tr
- %td= subscription.namespace.full_path
- %td= subscription.created_at
- %td= link_to 'Remove', jira_connect_subscription_path(subscription), class: 'remove-subscription'
+%header.jira-connect-header
+ = brand_header_logo
+
+.jira-connect-user
+ - if current_user
+ - user_link = link_to(current_user.to_reference, user_path(current_user), target: '_blank', rel: 'noopener noreferrer')
+ = _('Signed in to GitLab as %{user_link}').html_safe % { user_link: user_link }
+ - elsif @subscriptions.present?
+ = link_to _('Sign in to GitLab'), jira_connect_users_path, target: '_blank', rel: 'noopener noreferrer', class: 'js-jira-connect-sign-in'
+
+.jira-connect-app
+ %h1
+ GitLab for Jira Configuration
+
+ - if current_user.blank? && @subscriptions.empty?
+ %h2.heading-with-border Sign in to GitLab.com to get started.
+
+ .gl-mt-5
+ = external_link _('Sign in to GitLab'), jira_connect_users_path, class: 'ak-button ak-button__appearance-primary js-jira-connect-sign-in'
+
+ .gl-mt-5
+ %p Note: this integration only works with accounts on GitLab.com (SaaS).
+ - else
+ %form#add-subscription-form.subscription-form{ action: jira_connect_subscriptions_path }
+ .ak-field-group
+ %label
+ GitLab namespace
+
+ .ak-field-group.field-group-input
+ %input#namespace-input.ak-field-text{ type: 'text', required: true, placeholder: 'e.g. "MyCompany" or "MyCompany/GroupName"' }
+ %button.ak-button.ak-button__appearance-primary{ type: 'submit' }
+ Link namespace to Jira
+
+ - if @subscriptions.present?
+ %table.subscriptions
+ %thead
+ %tr
+ %th Namespace
+ %th Added
+ %th
+ %tbody
+ - @subscriptions.each do |subscription|
+ %tr
+ %td= subscription.namespace.full_path
+ %td= subscription.created_at
+ %td= link_to 'Remove', jira_connect_subscription_path(subscription), class: 'remove-subscription'
+ - else
+ %h4.empty-subscriptions
+ No linked namespaces
+
+ %p.browser-limitations-notice
+ %strong Browser limitations:
+ Adding a namespace currently works only in browsers that allow cross site cookies. Please make sure to use
+ %a{ href: 'https://www.mozilla.org/en-US/firefox/', target: '_blank', rel: 'noopener noreferrer' } Firefox
+ or
+ %a{ href: 'https://www.google.com/chrome/index.html', target: '_blank', rel: 'noopener noreferrer' } Google Chrome
+ or enable cross-site cookies in your browser when adding a namespace.
+ %a{ href: 'https://gitlab.com/gitlab-org/gitlab/-/issues/263509', target: '_blank', rel: 'noopener noreferrer' } Learn more
= page_specific_javascript_tag('jira_connect.js')
-= stylesheet_link_tag 'page_bundles/jira_connect'
+- add_page_specific_style 'page_bundles/jira_connect'
diff --git a/app/views/jira_connect/users/show.html.haml b/app/views/jira_connect/users/show.html.haml
new file mode 100644
index 00000000000..2ff92ab0dc8
--- /dev/null
+++ b/app/views/jira_connect/users/show.html.haml
@@ -0,0 +1,12 @@
+.jira-connect-users-container.gl-text-center
+ - user_link = link_to(current_user.to_reference, user_path(current_user), target: '_blank', rel: 'noopener noreferrer')
+ %h2= _('You are signed into GitLab as %{user_link}').html_safe % { user_link: user_link }
+
+ %p= s_('Integrations|You can now close this window and return to the GitLab for Jira application.')
+
+ - if @jira_app_link
+ %p= external_link s_('Integrations|Return to GitLab for Jira'), @jira_app_link, class: 'btn btn-success'
+
+ %p= link_to _('Sign out'), destroy_user_session_path, method: :post
+
+- add_page_specific_style 'page_bundles/jira_connect_users'
diff --git a/app/views/layouts/_head.html.haml b/app/views/layouts/_head.html.haml
index 1c87452f0a3..9d0c3ad5787 100644
--- a/app/views/layouts/_head.html.haml
+++ b/app/views/layouts/_head.html.haml
@@ -42,35 +42,40 @@
%title= page_title(site_name)
%meta{ name: "description", content: page_description }
+ - if page_canonical_link
+ %link{ rel: 'canonical', href: page_canonical_link }
+
= favicon_link_tag favicon, id: 'favicon', data: { original_href: favicon }, type: 'image/png'
= render 'layouts/startup_css'
- if user_application_theme == 'gl-dark'
= stylesheet_link_tag_defer "application_dark"
+ = yield :page_specific_styles
+ = stylesheet_link_tag_defer "application_utilities_dark"
- else
= stylesheet_link_tag_defer "application"
+ = yield :page_specific_styles
+ = stylesheet_link_tag_defer "application_utilities"
- unless use_startup_css?
- = stylesheet_link_tag_defer "themes/theme_#{user_application_theme_name}"
+ = stylesheet_link_tag_defer "themes/#{user_application_theme_css_filename}" if user_application_theme_css_filename
= stylesheet_link_tag "disable_animations", media: "all" if Rails.env.test? || Gitlab.config.gitlab['disable_animations']
- = stylesheet_link_tag_defer 'performance_bar' if performance_bar_enabled?
= stylesheet_link_tag_defer "highlight/themes/#{user_color_scheme}"
= render 'layouts/startup_css_activation'
- = Gon::Base.render_data(nonce: content_security_policy_nonce)
+ = stylesheet_link_tag 'performance_bar' if performance_bar_enabled?
- - if content_for?(:library_javascripts)
- = yield :library_javascripts
+ = Gon::Base.render_data(nonce: content_security_policy_nonce)
= javascript_include_tag locale_path unless I18n.locale == :en
- = webpack_bundle_tag "sentry" if Gitlab.config.sentry.enabled
+ -# Temporarily commented out to investigate performance: https://gitlab.com/gitlab-org/gitlab/-/issues/251179
+ -# = webpack_bundle_tag "sentry" if Gitlab.config.sentry.enabled
+ = webpack_bundle_tag 'performance_bar' if performance_bar_enabled?
- - if content_for?(:page_specific_javascripts)
- = yield :page_specific_javascripts
+ = yield :page_specific_javascripts
= webpack_controller_bundle_tags
- = webpack_bundle_tag 'performance_bar' if performance_bar_enabled?
= webpack_bundle_tag "chrome_84_icon_fix" if browser.chrome?([">=84", "<84.0.4147.125"]) || browser.edge?([">=84", "<84.0.522.59"])
= yield :project_javascripts
@@ -79,8 +84,6 @@
= csp_meta_tag
= action_cable_meta_tag
- - unless browser.safari?
- %meta{ name: 'referrer', content: 'origin-when-cross-origin' }
%meta{ name: 'viewport', content: 'width=device-width, initial-scale=1, maximum-scale=1' }
%meta{ name: 'theme-color', content: '#474D57' }
diff --git a/app/views/layouts/_loading_hints.html.haml b/app/views/layouts/_loading_hints.html.haml
index 0ef50d1b122..a75b602ff6b 100644
--- a/app/views/layouts/_loading_hints.html.haml
+++ b/app/views/layouts/_loading_hints.html.haml
@@ -6,5 +6,6 @@
- else
%link{ { rel: 'preload', href: stylesheet_url('application'), as: 'style' }, ActionController::Base.asset_host ? { crossorigin: 'anonymous' } : {} }
%link{ { rel: 'preload', href: stylesheet_url("highlight/themes/#{user_color_scheme}"), as: 'style' }, ActionController::Base.asset_host ? { crossorigin: 'anonymous' } : {} }
+%link{ { rel: 'preload', href: asset_url("fontawesome-webfont.woff2?v=4.7.0"), as: 'font', type: 'font/woff2' }, ActionController::Base.asset_host ? { crossorigin: 'anonymous' } : {} }
- if Gitlab::CurrentSettings.snowplow_enabled? && Gitlab::CurrentSettings.snowplow_collector_hostname
%link{ rel: 'preconnect', href: Gitlab::CurrentSettings.snowplow_collector_hostname, crossorigin: '' }
diff --git a/app/views/layouts/_page.html.haml b/app/views/layouts/_page.html.haml
index 5184bc93a81..9b925369660 100644
--- a/app/views/layouts/_page.html.haml
+++ b/app/views/layouts/_page.html.haml
@@ -19,7 +19,6 @@
= yield :customize_homepage_banner
- unless @hide_breadcrumbs
= render "layouts/nav/breadcrumbs"
- .d-flex
%div{ class: "#{(container_class unless @no_container)} #{@content_class}" }
.content{ id: "content-body" }
= render "layouts/flash", extra_flash_class: 'limit-container-width'
diff --git a/app/views/layouts/_startup_css.haml b/app/views/layouts/_startup_css.haml
index ea05157ed19..2f674f79b2f 100644
--- a/app/views/layouts/_startup_css.haml
+++ b/app/views/layouts/_startup_css.haml
@@ -3,5 +3,5 @@
- startup_filename = current_path?("sessions#new") ? 'signin' : user_application_theme == 'gl-dark' ? 'dark' : 'general'
%style{ type: "text/css" }
- = Rails.application.assets_manifest.find_sources("themes/theme_#{user_application_theme_name}.css").first.to_s.html_safe
+ = Rails.application.assets_manifest.find_sources("themes/#{user_application_theme_css_filename}.css").first.to_s.html_safe if user_application_theme_css_filename
= Rails.application.assets_manifest.find_sources("startup/startup-#{startup_filename}.css").first.to_s.html_safe
diff --git a/app/views/layouts/_startup_css_activation.haml b/app/views/layouts/_startup_css_activation.haml
index 022b9a695bc..a426d686c34 100644
--- a/app/views/layouts/_startup_css_activation.haml
+++ b/app/views/layouts/_startup_css_activation.haml
@@ -7,4 +7,3 @@
const startupLinkLoadedEvent = new CustomEvent('CSSStartupLinkLoaded');
linkTag.addEventListener('load',function(){this.media='all';this.setAttribute('data-startupcss', 'loaded');document.dispatchEvent(startupLinkLoadedEvent);},{once: true});
})
-- return unless use_startup_css?
diff --git a/app/views/layouts/_startup_js.html.haml b/app/views/layouts/_startup_js.html.haml
index 33c759b7a7c..f312e00c394 100644
--- a/app/views/layouts/_startup_js.html.haml
+++ b/app/views/layouts/_startup_js.html.haml
@@ -1,9 +1,11 @@
-- return unless page_startup_api_calls.present?
+- return unless page_startup_api_calls.present? || page_startup_graphql_calls.present?
= javascript_tag nonce: true do
:plain
var gl = window.gl || {};
gl.startup_calls = #{page_startup_api_calls.to_json};
+ gl.startup_graphql_calls = #{page_startup_graphql_calls.to_json};
+
if (gl.startup_calls && window.fetch) {
Object.keys(gl.startup_calls).forEach(apiCall => {
// fetch won’t send cookies in older browsers, unless you set the credentials init option.
@@ -14,3 +16,21 @@
};
});
}
+ if (gl.startup_graphql_calls && window.fetch) {
+ const url = `#{api_graphql_url}`
+
+ const opts = {
+ method: "POST",
+ headers: { "Content-Type": "application/json", 'X-CSRF-Token': "#{form_authenticity_token}" },
+ };
+
+ gl.startup_graphql_calls = gl.startup_graphql_calls.map(call => ({
+ operationName: call.query.match(/^query (.+)\(/)[1],
+ fetchCall: fetch(url, {
+ ...opts,
+ credentials: 'same-origin',
+ body: JSON.stringify(call)
+ })
+ }))
+ }
+
diff --git a/app/views/layouts/devise.html.haml b/app/views/layouts/devise.html.haml
index bbcb525ea4f..5daee24cb51 100644
--- a/app/views/layouts/devise.html.haml
+++ b/app/views/layouts/devise.html.haml
@@ -14,7 +14,7 @@
.row.mt-3
.col-sm-12
%h1.mb-3.font-weight-normal
- = brand_title
+ = current_appearance&.title.presence || "GitLab"
.row.mb-3
.col-sm-7.order-12.order-sm-1.brand-holder
= brand_image
@@ -27,6 +27,9 @@
%p
= _('GitLab is a single application for the entire software development lifecycle. From project planning and source code management to CI/CD, monitoring, and security.')
+ %p
+ = _('This is a self-managed instance of GitLab.')
+
- if Gitlab::CurrentSettings.sign_in_text.present?
= markdown_field(Gitlab::CurrentSettings.current_application_settings, :sign_in_text)
diff --git a/app/views/layouts/devise_experimental_onboarding_issues.html.haml b/app/views/layouts/devise_experimental_onboarding_issues.html.haml
index df2afbe60ae..ec9867f9e1f 100644
--- a/app/views/layouts/devise_experimental_onboarding_issues.html.haml
+++ b/app/views/layouts/devise_experimental_onboarding_issues.html.haml
@@ -1,5 +1,6 @@
!!! 5
%html.devise-layout-html.navless{ class: system_message_class }
+ - add_page_specific_style 'page_bundles/experimental_separate_sign_up'
= render "layouts/head"
%body.ui-indigo.signup-page{ class: "#{client_class_list}", data: { page: body_data_page, qa_selector: 'signup_page' } }
= render "layouts/header/logo_with_title"
diff --git a/app/views/layouts/devise_experimental_separate_sign_up_flow.html.haml b/app/views/layouts/devise_experimental_separate_sign_up_flow.html.haml
index fddfe14e05f..6be62645768 100644
--- a/app/views/layouts/devise_experimental_separate_sign_up_flow.html.haml
+++ b/app/views/layouts/devise_experimental_separate_sign_up_flow.html.haml
@@ -1,5 +1,6 @@
!!! 5
%html.devise-layout-html.navless{ class: system_message_class }
+ - add_page_specific_style 'page_bundles/experimental_separate_sign_up'
= render "layouts/head"
%body.ui-indigo.signup-page{ class: "#{client_class_list}", data: { page: body_data_page, qa_selector: 'signup_page' } }
= render "layouts/header/logo_with_title"
diff --git a/app/views/layouts/group.html.haml b/app/views/layouts/group.html.haml
index 8f4c89a9e77..6d2c5870e43 100644
--- a/app/views/layouts/group.html.haml
+++ b/app/views/layouts/group.html.haml
@@ -1,6 +1,6 @@
- page_title @group.name
-- page_description @group.description unless page_description
-- header_title group_title(@group) unless header_title
+- page_description @group.description_html unless page_description
+- header_title group_title(@group) unless header_title
- nav "group"
- display_subscription_banner!
- display_namespace_storage_limit_alert!
diff --git a/app/views/layouts/header/_current_user_dropdown.html.haml b/app/views/layouts/header/_current_user_dropdown.html.haml
index dcc6cba8444..4c6bfc0b33c 100644
--- a/app/views/layouts/header/_current_user_dropdown.html.haml
+++ b/app/views/layouts/header/_current_user_dropdown.html.haml
@@ -46,7 +46,7 @@
- if current_user_menu?(:help) || current_user_menu?(:settings) || current_user_menu?(:profile)
%li.d-md-none
= render 'shared/user_dropdown_contributing_link'
- = render_if_exists 'shared/user_dropdown_instance_review'
+ = render 'shared/user_dropdown_instance_review'
- if Gitlab.com_but_not_canary?
%li.d-md-none
= link_to _("Switch to GitLab Next"), "https://next.gitlab.com/"
diff --git a/app/views/layouts/header/_default.html.haml b/app/views/layouts/header/_default.html.haml
index 845231238f6..f6dc808aa55 100644
--- a/app/views/layouts/header/_default.html.haml
+++ b/app/views/layouts/header/_default.html.haml
@@ -14,7 +14,7 @@
%span.logo-text.d-none.d-lg-block.gl-ml-3
= logo_text
- if Gitlab.com_and_canary?
- = link_to 'https://next.gitlab.com', class: 'label-link canary-badge bg-transparent', target: :_blank do
+ = link_to 'https://next.gitlab.com', class: 'canary-badge bg-transparent', target: :_blank do
%span.color-label.has-tooltip.badge.badge-pill.green-badge
= _('Next')
@@ -73,7 +73,7 @@
%span.gl-sr-only
= s_('Nav|Help')
= sprite_icon('question')
- = sprite_icon('angle-down', css_class: 'caret-down')
+ = sprite_icon('chevron-down', css_class: 'caret-down')
.dropdown-menu.dropdown-menu-right
= render 'layouts/header/help_dropdown'
- if header_link?(:user_dropdown)
@@ -81,7 +81,7 @@
= link_to current_user, class: user_dropdown_class, data: { toggle: "dropdown" } do
= image_tag avatar_icon_for_user(current_user, 23), width: 23, height: 23, class: "header-user-avatar qa-user-avatar", alt: current_user.name
= render_if_exists 'layouts/header/user_notification_dot', project: project, namespace: group
- = sprite_icon('angle-down', css_class: 'caret-down')
+ = sprite_icon('chevron-down', css_class: 'caret-down')
.dropdown-menu.dropdown-menu-right
= render 'layouts/header/current_user_dropdown'
- if has_impersonation_link
@@ -99,8 +99,8 @@
= sprite_icon('ellipsis_h', size: 12, css_class: 'more-icon js-navbar-toggle-right')
= sprite_icon('close', size: 12, css_class: 'close-icon js-navbar-toggle-left')
-- if ::Feature.enabled?(:whats_new_drawer)
- #whats-new-app{ data: { features: whats_new_most_recent_release_items } }
+- if ::Feature.enabled?(:whats_new_drawer, current_user)
+ #whats-new-app{ data: { storage_key: whats_new_storage_key } }
- if can?(current_user, :update_user_status, current_user)
.js-set-status-modal-wrapper{ data: { current_emoji: current_user.status.present? ? current_user.status.emoji : '', current_message: current_user.status.present? ? current_user.status.message : '' } }
diff --git a/app/views/layouts/header/_help_dropdown.html.haml b/app/views/layouts/header/_help_dropdown.html.haml
index 2b6cbc1c0ef..40bf45db80d 100644
--- a/app/views/layouts/header/_help_dropdown.html.haml
+++ b/app/views/layouts/header/_help_dropdown.html.haml
@@ -17,7 +17,7 @@
- if current_user_menu?(:help) || current_user_menu?(:settings) || current_user_menu?(:profile)
%li
= render 'shared/user_dropdown_contributing_link'
- = render_if_exists 'shared/user_dropdown_instance_review'
+ = render 'shared/user_dropdown_instance_review'
- if Gitlab.com_but_not_canary?
%li
= link_to _("Switch to GitLab Next"), "https://next.gitlab.com/"
diff --git a/app/views/layouts/header/_new_dropdown.haml b/app/views/layouts/header/_new_dropdown.haml
index 0c989242194..2c5cd7e96c7 100644
--- a/app/views/layouts/header/_new_dropdown.haml
+++ b/app/views/layouts/header/_new_dropdown.haml
@@ -1,7 +1,7 @@
%li.header-new.dropdown{ data: { track_label: "new_dropdown", track_event: "click_dropdown", track_value: "" } }
= link_to new_project_path, class: "header-new-dropdown-toggle has-tooltip qa-new-menu-toggle", id: "js-onboarding-new-project-link", title: _("New..."), ref: 'tooltip', aria: { label: _("New...") }, data: { toggle: 'dropdown', placement: 'bottom', container: 'body', display: 'static' } do
= sprite_icon('plus-square')
- = sprite_icon('angle-down', css_class: 'caret-down')
+ = sprite_icon('chevron-down', css_class: 'caret-down')
.dropdown-menu.dropdown-menu-right
%ul
- if @group&.persisted?
diff --git a/app/views/layouts/jira_connect.html.haml b/app/views/layouts/jira_connect.html.haml
index fdeb3d3c9ac..17f6e9af61a 100644
--- a/app/views/layouts/jira_connect.html.haml
+++ b/app/views/layouts/jira_connect.html.haml
@@ -7,6 +7,7 @@
= stylesheet_link_tag 'https://unpkg.com/@atlaskit/reduced-ui-pack@10.5.5/dist/bundle.css'
= javascript_include_tag 'https://connect-cdn.atl-paas.net/all.js'
= javascript_include_tag 'https://unpkg.com/jquery@3.3.1/dist/jquery.min.js'
+ = yield :page_specific_styles
= yield :head
%body
.ac-content
diff --git a/app/views/layouts/nav/_classification_level_banner.html.haml b/app/views/layouts/nav/_classification_level_banner.html.haml
index cc4caf079b8..d76fb50aa0b 100644
--- a/app/views/layouts/nav/_classification_level_banner.html.haml
+++ b/app/views/layouts/nav/_classification_level_banner.html.haml
@@ -1,5 +1,5 @@
- if ::Gitlab::ExternalAuthorization.enabled? && @project
= content_for :header_content do
- %span.badge.color-label.classification-label.has-tooltip{ title: s_('ExternalAuthorizationService|Classification label') }
+ %span.badge.color-label.gl-bg-red-500.has-tooltip{ title: s_('ExternalAuthorizationService|Classification label') }
= sprite_icon('lock-open', size: 8, css_class: 'inline')
= @project.external_authorization_classification_label
diff --git a/app/views/layouts/nav/_dashboard.html.haml b/app/views/layouts/nav/_dashboard.html.haml
index 40ea42091bd..abaadc89a9e 100644
--- a/app/views/layouts/nav/_dashboard.html.haml
+++ b/app/views/layouts/nav/_dashboard.html.haml
@@ -3,17 +3,17 @@
%ul.list-unstyled.navbar-sub-nav
- if dashboard_nav_link?(:projects)
= nav_link(path: ['root#index', 'projects#trending', 'projects#starred', 'dashboard/projects#index'], html_options: { id: 'nav-projects-dropdown', class: "home dropdown header-projects qa-projects-dropdown", data: { track_label: "projects_dropdown", track_event: "click_dropdown", track_value: "" } }) do
- %button.btn{ type: 'button', data: { toggle: "dropdown" } }
+ %button{ type: 'button', data: { toggle: "dropdown" } }
= _('Projects')
- = sprite_icon('angle-down', css_class: 'caret-down')
+ = sprite_icon('chevron-down', css_class: 'caret-down')
.dropdown-menu.frequent-items-dropdown-menu
= render "layouts/nav/projects_dropdown/show"
- if dashboard_nav_link?(:groups)
= nav_link(controller: ['dashboard/groups', 'explore/groups'], html_options: { id: 'nav-groups-dropdown', class: "d-none d-md-block home dropdown header-groups qa-groups-dropdown", data: { track_label: "groups_dropdown", track_event: "click_dropdown", track_value: "" } }) do
- %button.btn{ type: 'button', data: { toggle: "dropdown" } }
+ %button{ type: 'button', data: { toggle: "dropdown" } }
= _('Groups')
- = sprite_icon('angle-down', css_class: 'caret-down')
+ = sprite_icon('chevron-down', css_class: 'caret-down')
.dropdown-menu.frequent-items-dropdown-menu
= render "layouts/nav/groups_dropdown/show"
@@ -21,7 +21,7 @@
%li.header-more.dropdown{ **tracking_attrs('main_navigation', 'click_more_link', 'navigation') }
%a{ href: "#", data: { toggle: "dropdown", qa_selector: 'more_dropdown' } }
= _('More')
- = sprite_icon('angle-down', css_class: 'caret-down')
+ = sprite_icon('chevron-down', css_class: 'caret-down')
.dropdown-menu
%ul
- if dashboard_nav_link?(:groups)
diff --git a/app/views/layouts/nav/sidebar/_admin.html.haml b/app/views/layouts/nav/sidebar/_admin.html.haml
index cb5277c02f0..0da4d4f7ddd 100644
--- a/app/views/layouts/nav/sidebar/_admin.html.haml
+++ b/app/views/layouts/nav/sidebar/_admin.html.haml
@@ -260,10 +260,11 @@
= link_to general_admin_application_settings_path, title: _('General'), class: 'qa-admin-settings-general-item' do
%span
= _('General')
- = nav_link(path: ['application_settings#integrations', 'integrations#edit']) do
- = link_to integrations_admin_application_settings_path, title: _('Integrations'), data: { qa_selector: 'integration_settings_link' } do
- %span
- = _('Integrations')
+ - if instance_level_integrations?
+ = nav_link(path: ['application_settings#integrations', 'integrations#edit']) do
+ = link_to integrations_admin_application_settings_path, title: _('Integrations'), data: { qa_selector: 'integration_settings_link' } do
+ %span
+ = _('Integrations')
= nav_link(path: 'application_settings#repository') do
= link_to repository_admin_application_settings_path, title: _('Repository'), class: 'qa-admin-settings-repository-item' do
%span
diff --git a/app/views/layouts/nav/sidebar/_group.html.haml b/app/views/layouts/nav/sidebar/_group.html.haml
index 9e9e6493e5b..5f4b1f8ad45 100644
--- a/app/views/layouts/nav/sidebar/_group.html.haml
+++ b/app/views/layouts/nav/sidebar/_group.html.haml
@@ -139,6 +139,8 @@
%strong.fly-out-top-item-name
= _('Members')
+ = render_if_exists 'groups/invite_members_side_nav_link', group: @group
+
- if group_sidebar_link?(:settings)
= nav_link(path: group_settings_nav_link_paths) do
= link_to edit_group_path(@group) do
diff --git a/app/views/layouts/nav/sidebar/_project.html.haml b/app/views/layouts/nav/sidebar/_project.html.haml
index 0eef587d7c7..d3d71f91176 100644
--- a/app/views/layouts/nav/sidebar/_project.html.haml
+++ b/app/views/layouts/nav/sidebar/_project.html.haml
@@ -229,25 +229,14 @@
%span
= _('Metrics')
- - if project_nav_tab?(:alert_management)
- = nav_link(controller: :alert_management) do
- = link_to project_alert_management_index_path(@project), title: _('Alerts') do
+ - if project_nav_tab?(:environments) && can?(current_user, :read_pod_logs, @project)
+ = nav_link(controller: :logs, action: [:index]) do
+ = link_to project_logs_path(@project), title: _('Logs') do
%span
- = _('Alerts')
-
- - if project_nav_tab?(:incidents)
- = nav_link(controller: :incidents) do
- = link_to project_incidents_path(@project), title: _('Incidents'), data: { qa_selector: 'operations_incidents_link' } do
- %span
- = _('Incidents')
+ = _('Logs')
- if project_nav_tab? :environments
- = render_if_exists "layouts/nav/sidebar/tracing_link"
-
- = nav_link(controller: :environments, action: [:index, :folder, :show, :new, :edit, :create, :update, :stop, :terminal]) do
- = link_to project_environments_path(@project), title: _('Environments'), class: 'shortcuts-environments qa-operations-environments-link' do
- %span
- = _('Environments')
+ = render "layouts/nav/sidebar/tracing_link"
- if project_nav_tab?(:error_tracking)
= nav_link(controller: :error_tracking) do
@@ -255,11 +244,17 @@
%span
= _('Error Tracking')
- - if project_nav_tab?(:product_analytics)
- = nav_link(controller: :product_analytics) do
- = link_to project_product_analytics_path(@project), title: _('Product Analytics') do
+ - if project_nav_tab?(:alert_management)
+ = nav_link(controller: :alert_management) do
+ = link_to project_alert_management_index_path(@project), title: _('Alerts') do
%span
- = _('Product Analytics')
+ = _('Alerts')
+
+ - if project_nav_tab?(:incidents)
+ = nav_link(controller: :incidents) do
+ = link_to project_incidents_path(@project), title: _('Incidents'), data: { qa_selector: 'operations_incidents_link' } do
+ %span
+ = _('Incidents')
- if project_nav_tab? :serverless
= nav_link(controller: :functions) do
@@ -267,12 +262,6 @@
%span
= _('Serverless')
- - if project_nav_tab?(:environments) && can?(current_user, :read_pod_logs, @project)
- = nav_link(controller: :logs, action: [:index]) do
- = link_to project_logs_path(@project), title: _('Logs') do
- %span
- = _('Logs')
-
- if project_nav_tab? :clusters
- show_cluster_hint = show_gke_cluster_integration_callout?(@project)
= nav_link(controller: [:clusters, :user, :gcp]) do
@@ -302,7 +291,23 @@
%span= _("Got it!")
= sprite_icon('thumb-up')
- = render_if_exists 'layouts/nav/sidebar/project_feature_flags_link'
+ - if project_nav_tab? :environments
+ = nav_link(controller: :environments, action: [:index, :folder, :show, :new, :edit, :create, :update, :stop, :terminal]) do
+ = link_to project_environments_path(@project), title: _('Environments'), class: 'shortcuts-environments qa-operations-environments-link' do
+ %span
+ = _('Environments')
+
+ - if project_nav_tab? :feature_flags
+ = nav_link(controller: :feature_flags) do
+ = link_to project_feature_flags_path(@project), title: _('Feature Flags'), class: 'shortcuts-feature-flags' do
+ %span
+ = _('Feature Flags')
+
+ - if project_nav_tab?(:product_analytics)
+ = nav_link(controller: :product_analytics) do
+ = link_to project_product_analytics_path(@project), title: _('Product Analytics') do
+ %span
+ = _('Product Analytics')
= render_if_exists 'layouts/nav/sidebar/project_packages_link'
diff --git a/app/views/layouts/nav/sidebar/_tracing_link.html.haml b/app/views/layouts/nav/sidebar/_tracing_link.html.haml
new file mode 100644
index 00000000000..7a31a20f5f0
--- /dev/null
+++ b/app/views/layouts/nav/sidebar/_tracing_link.html.haml
@@ -0,0 +1,7 @@
+- return unless can?(current_user, :read_environment, @project)
+
+- if project_nav_tab? :settings
+ = nav_link(controller: :tracings, action: [:show]) do
+ = link_to project_tracing_path(@project), title: _('Tracing') do
+ %span
+ = _('Tracing')
diff --git a/app/views/layouts/project.html.haml b/app/views/layouts/project.html.haml
index 222ca02b1df..a0c82380023 100644
--- a/app/views/layouts/project.html.haml
+++ b/app/views/layouts/project.html.haml
@@ -1,6 +1,6 @@
- page_title @project.full_name
-- page_description @project.description unless page_description
-- header_title project_title(@project) unless header_title
+- page_description @project.description_html unless page_description
+- header_title project_title(@project) unless header_title
- nav "project"
- display_subscription_banner!
- display_namespace_storage_limit_alert!
diff --git a/app/views/notify/_failed_builds.html.haml b/app/views/notify/_failed_builds.html.haml
index cde0ac21d6d..11cbd700258 100644
--- a/app/views/notify/_failed_builds.html.haml
+++ b/app/views/notify/_failed_builds.html.haml
@@ -6,7 +6,7 @@
#{'build'.pluralize(failed.size)}.
%tr.table-warning
%td{ style: "font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; border: 1px solid #ededed; border-bottom: 0; border-radius: 4px 4px 0 0; overflow: hidden; background-color: #fdf4f6; color: #d22852; font-size: 14px; line-height: 1.4; text-align: center; padding: 8px 16px;" }
- Logs may contain sensitive data. Please consider before forwarding this email.
+ Failed builds
%tr.section
%td{ style: "font-family: 'Helvetica Neue',Helvetica,Arial,sans-serif; padding: 0 16px; border: 1px solid #ededed; border-radius: 4px; overflow: hidden; border-top: 0; border-radius: 0 0 4px 4px;" }
%table.builds{ border: "0", cellpadding: "0", cellspacing: "0", style: "width: 100%; border-collapse: collapse;" }
diff --git a/app/views/notify/_issuable_csv_export.html.haml b/app/views/notify/_issuable_csv_export.html.haml
new file mode 100644
index 00000000000..239b5b14966
--- /dev/null
+++ b/app/views/notify/_issuable_csv_export.html.haml
@@ -0,0 +1,6 @@
+%p{ style: 'font-size:18px; text-align:center; line-height:30px;' }
+ - project_link = link_to(@project.full_name, project_url(@project), style: "color:#3777b0; text-decoration:none; display:block;")
+ = _('Your CSV export of %{count} from project %{project_link} has been added to this email as an attachment.').html_safe % { count: pluralize(@written_count, type.to_s), project_link: project_link }
+ - if @truncated
+ %p
+ = _('This attachment has been truncated to avoid exceeding the maximum allowed attachment size of 15MB. %{written_count} of %{count} issues have been included. Consider re-exporting with a narrower selection of issues.') % { written_count: @written_count, count: @count }
diff --git a/app/views/notify/autodevops_disabled_email.html.haml b/app/views/notify/autodevops_disabled_email.html.haml
index 65a2f75a3e2..72bcfbdf3af 100644
--- a/app/views/notify/autodevops_disabled_email.html.haml
+++ b/app/views/notify/autodevops_disabled_email.html.haml
@@ -46,4 +46,4 @@
%td{ style: "font-family: 'Menlo','Liberation Mono','Consolas','DejaVu Sans Mono','Ubuntu Mono','Courier New','andale mono','lucida console',monospace; font-size: 14px; line-height: 1.4; vertical-align: baseline; padding:0 8px;" }
API
-= render 'notify/failed_builds', pipeline: @pipeline, failed: @pipeline.statuses.latest.failed
+= render 'notify/failed_builds', pipeline: @pipeline, failed: @pipeline.latest_statuses.failed
diff --git a/app/views/notify/autodevops_disabled_email.text.erb b/app/views/notify/autodevops_disabled_email.text.erb
index f849c017265..c75857e96d7 100644
--- a/app/views/notify/autodevops_disabled_email.text.erb
+++ b/app/views/notify/autodevops_disabled_email.text.erb
@@ -7,7 +7,7 @@ The Auto DevOps pipeline failed for pipeline <%= @pipeline.iid %> (<%= pipeline_
<% else -%>
Pipeline #<%= @pipeline.id %> ( <%= pipeline_url(@pipeline) %> ) triggered by API
<% end -%>
-<% failed = @pipeline.statuses.latest.failed -%>
+<% failed = @pipeline.latest_statuses.failed -%>
had <%= failed.size %> failed <%= 'build'.pluralize(failed.size) %>.
<% failed.each do |build| -%>
diff --git a/app/views/notify/changed_reviewer_of_merge_request_email.html.haml b/app/views/notify/changed_reviewer_of_merge_request_email.html.haml
new file mode 100644
index 00000000000..ed7a3285f45
--- /dev/null
+++ b/app/views/notify/changed_reviewer_of_merge_request_email.html.haml
@@ -0,0 +1,2 @@
+%p
+ = change_reviewer_notification_text(@merge_request.reviewers, @previous_reviewers, :strong)
diff --git a/app/views/notify/changed_reviewer_of_merge_request_email.text.erb b/app/views/notify/changed_reviewer_of_merge_request_email.text.erb
new file mode 100644
index 00000000000..b6824966bb9
--- /dev/null
+++ b/app/views/notify/changed_reviewer_of_merge_request_email.text.erb
@@ -0,0 +1 @@
+<%= change_reviewer_notification_text(@merge_request.reviewers, @previous_reviewers) %>
diff --git a/app/views/notify/issue_status_changed_email.text.erb b/app/views/notify/issue_status_changed_email.text.erb
index f38b09e9820..f963e9b5c3d 100644
--- a/app/views/notify/issue_status_changed_email.text.erb
+++ b/app/views/notify/issue_status_changed_email.text.erb
@@ -1,4 +1,3 @@
Issue was <%= @issue_status %> by <%= sanitize_name(@updated_by.name) %>
Issue <%= @issue.iid %>: <%= url_for(project_issue_url(@issue.project, @issue)) %>
-
diff --git a/app/views/notify/issues_csv_email.html.haml b/app/views/notify/issues_csv_email.html.haml
index 77502a45f02..4cd47f12061 100644
--- a/app/views/notify/issues_csv_email.html.haml
+++ b/app/views/notify/issues_csv_email.html.haml
@@ -1,6 +1 @@
-%p{ style: 'font-size:18px; text-align:center; line-height:30px;' }
- - project_link = link_to(@project.full_name, project_url(@project), style: "color:#3777b0; text-decoration:none; display:block;")
- = _('Your CSV export of %{issues_count} from project %{project_link} has been added to this email as an attachment.').html_safe % { issues_count: pluralize(@written_count, 'issue'), project_link: project_link }
- - if @truncated
- %p
- = _('This attachment has been truncated to avoid exceeding the maximum allowed attachment size of 15MB. %{written_count} of %{issues_count} issues have been included. Consider re-exporting with a narrower selection of issues.') % { written_count: @written_count, issues_count: @issues_count }
+= render 'issuable_csv_export', type: :issue
diff --git a/app/views/notify/member_invited_reminder_email.html.haml b/app/views/notify/member_invited_reminder_email.html.haml
new file mode 100644
index 00000000000..720f3510722
--- /dev/null
+++ b/app/views/notify/member_invited_reminder_email.html.haml
@@ -0,0 +1,9 @@
+%tr
+ %td.text-content
+ %h2.invite-header
+ = invitation_reminder_salutation(@reminder_index, format: :html)
+ %p.invite-body
+ = invitation_reminder_body(member, @reminder_index, format: :html)
+ %p.invite-actions
+ = invitation_reminder_accept_link(@token, format: :html)
+ = invitation_reminder_decline_link(@token, format: :html)
diff --git a/app/views/notify/member_invited_reminder_email.text.erb b/app/views/notify/member_invited_reminder_email.text.erb
new file mode 100644
index 00000000000..97f34f01385
--- /dev/null
+++ b/app/views/notify/member_invited_reminder_email.text.erb
@@ -0,0 +1,6 @@
+<%= invitation_reminder_salutation(@reminder_index) %>
+
+<%= invitation_reminder_body(member, @reminder_index) %>
+
+<%= invitation_reminder_accept_link(@token) %>
+<%= invitation_reminder_decline_link(@token) %>
diff --git a/app/views/notify/merge_requests_csv_email.html.haml b/app/views/notify/merge_requests_csv_email.html.haml
new file mode 100644
index 00000000000..225c81117b3
--- /dev/null
+++ b/app/views/notify/merge_requests_csv_email.html.haml
@@ -0,0 +1 @@
+= render 'issuable_csv_export', type: :merge_request
diff --git a/app/views/notify/merge_requests_csv_email.text.erb b/app/views/notify/merge_requests_csv_email.text.erb
new file mode 100644
index 00000000000..9ed971bbe9c
--- /dev/null
+++ b/app/views/notify/merge_requests_csv_email.text.erb
@@ -0,0 +1,5 @@
+<%= _('Your CSV export of %{written_count} from project %{project_name} (%{project_url}) has been added to this email as an attachment.') % { written_count: pluralize(@written_count, 'merge request'), project_name: @project.full_name, project_url: project_url(@project) } %>
+
+<% if @truncated %>
+ <%= _('This attachment has been truncated to avoid exceeding the maximum allowed attachment size of 15MB. %{written_count} of %{merge_requests_count} issues have been included. Consider re-exporting with a narrower selection of issues.') % { written_count: @written_count, merge_requests_count: @merge_requests_count} %>
+<% end %>
diff --git a/app/views/notify/pipeline_failed_email.html.haml b/app/views/notify/pipeline_failed_email.html.haml
index f01181857ce..575ec8c488e 100644
--- a/app/views/notify/pipeline_failed_email.html.haml
+++ b/app/views/notify/pipeline_failed_email.html.haml
@@ -108,4 +108,4 @@
%td{ style: "font-family:'Menlo','Liberation Mono','Consolas','DejaVu Sans Mono','Ubuntu Mono','Courier New','andale mono','lucida console',monospace;font-size:14px;line-height:1.4;vertical-align:baseline;padding:0 5px;" }
API
-= render 'notify/failed_builds', pipeline: @pipeline, failed: @pipeline.statuses.latest.failed
+= render 'notify/failed_builds', pipeline: @pipeline, failed: @pipeline.latest_statuses.failed
diff --git a/app/views/notify/pipeline_failed_email.text.erb b/app/views/notify/pipeline_failed_email.text.erb
index b388aad7048..a30e331d892 100644
--- a/app/views/notify/pipeline_failed_email.text.erb
+++ b/app/views/notify/pipeline_failed_email.text.erb
@@ -27,7 +27,7 @@ Pipeline #<%= @pipeline.id %> ( <%= pipeline_url(@pipeline) %> ) triggered by <%
<% else -%>
Pipeline #<%= @pipeline.id %> ( <%= pipeline_url(@pipeline) %> ) triggered by API
<% end -%>
-<% failed = @pipeline.statuses.latest.failed -%>
+<% failed = @pipeline.latest_statuses.failed -%>
had <%= failed.size %> failed <%= 'build'.pluralize(failed.size) %>.
<% failed.each do |build| -%>
diff --git a/app/views/notify/prometheus_alert_fired_email.html.haml b/app/views/notify/prometheus_alert_fired_email.html.haml
index 17f9481d353..75ba66b44f9 100644
--- a/app/views/notify/prometheus_alert_fired_email.html.haml
+++ b/app/views/notify/prometheus_alert_fired_email.html.haml
@@ -1,17 +1,17 @@
%p
- = _('An alert has been triggered in %{project_path}.') % { project_path: @alert.project_full_path }
+ = _('An alert has been triggered in %{project_path}.') % { project_path: @alert.project.full_path }
- if description = @alert.description
%p
= _('Description:')
= description
-- if env_name = @alert.environment_name
+- if env_name = @alert.environment&.name
%p
= _('Environment:')
= env_name
-- if metric_query = @alert.metric_query
+- if metric_query = @alert.prometheus_alert&.full_query
%p
= _('Metric:')
@@ -25,4 +25,3 @@
- if @alert.show_performance_dashboard_link?
%p
= link_to(_('View performance dashboard.'), @alert.performance_dashboard_link)
-
diff --git a/app/views/notify/prometheus_alert_fired_email.text.erb b/app/views/notify/prometheus_alert_fired_email.text.erb
index c3f005cfb7e..8853f2a317b 100644
--- a/app/views/notify/prometheus_alert_fired_email.text.erb
+++ b/app/views/notify/prometheus_alert_fired_email.text.erb
@@ -1,14 +1,14 @@
-<%= _('An alert has been triggered in %{project_path}.') % { project_path: @alert.project_full_path } %>.
+<%= _('An alert has been triggered in %{project_path}.') % { project_path: @alert.project.full_path } %>.
<% if description = @alert.description %>
<%= _('Description:') %> <%= description %>
<% end %>
-<% if env_name = @alert.environment_name %>
+<% if env_name = @alert.environment&.name %>
<%= _('Environment:') %> <%= env_name %>
<% end %>
-<% if metric_query = @alert.metric_query %>
+<% if metric_query = @alert.prometheus_alert&.full_query %>
<%= _('Metric:') %> <%= metric_query %>
<% end %>
diff --git a/app/views/profiles/accounts/show.html.haml b/app/views/profiles/accounts/show.html.haml
index c875caca94a..fed40b7f119 100644
--- a/app/views/profiles/accounts/show.html.haml
+++ b/app/views/profiles/accounts/show.html.haml
@@ -2,8 +2,10 @@
- @content_class = "limit-container-width" unless fluid_layout
- if current_user.ldap_user?
- .alert.alert-info
- = s_('Profiles|Some options are unavailable for LDAP accounts')
+ .gl-alert.gl-alert-info.gl-my-5
+ = sprite_icon('information-o', size: 16, css_class: 'gl-icon gl-alert-icon gl-alert-icon-no-title')
+ .gl-alert-body
+ = s_('Profiles|Some options are unavailable for LDAP accounts')
.row.gl-mt-3
.col-lg-4.profile-settings-sidebar
@@ -15,10 +17,10 @@
%p
#{_('Status')}: #{current_user.two_factor_enabled? ? _('Enabled') : _('Disabled')}
- if current_user.two_factor_enabled?
- = link_to _('Manage two-factor authentication'), profile_two_factor_auth_path, class: 'btn btn-info'
+ = link_to _('Manage two-factor authentication'), profile_two_factor_auth_path, class: 'gl-button btn btn-info'
- else
.gl-mb-3
- = link_to _('Enable two-factor authentication'), profile_two_factor_auth_path, class: 'btn btn-success'
+ = link_to _('Enable two-factor authentication'), profile_two_factor_auth_path, class: 'gl-button btn btn-success', data: { qa_selector: 'enable_2fa_button' }
%hr
- if display_providers_on_profile?
diff --git a/app/views/profiles/active_sessions/_active_session.html.haml b/app/views/profiles/active_sessions/_active_session.html.haml
index 97f13a55dea..9ec8d694dac 100644
--- a/app/views/profiles/active_sessions/_active_session.html.haml
+++ b/app/views/profiles/active_sessions/_active_session.html.haml
@@ -30,6 +30,6 @@
= link_to(revoke_session_path(active_session),
{ data: { confirm: _('Are you sure? The device will be signed out of GitLab and all remember me tokens revoked.') },
method: :delete,
- class: "btn btn-danger gl-ml-3" }) do
+ class: "gl-button btn btn-danger gl-ml-3" }) do
%span.sr-only= _('Revoke')
= _('Revoke')
diff --git a/app/views/profiles/chat_names/_chat_name.html.haml b/app/views/profiles/chat_names/_chat_name.html.haml
index ff67f92ad07..6805824cebc 100644
--- a/app/views/profiles/chat_names/_chat_name.html.haml
+++ b/app/views/profiles/chat_names/_chat_name.html.haml
@@ -24,4 +24,4 @@
= _('Never')
%td
- = link_to _('Remove'), profile_chat_name_path(chat_name), method: :delete, class: 'btn btn-danger float-right', data: { confirm: _('Are you sure you want to revoke this nickname?') }
+ = link_to _('Remove'), profile_chat_name_path(chat_name), method: :delete, class: 'gl-button btn btn-danger float-right', data: { confirm: _('Are you sure you want to revoke this nickname?') }
diff --git a/app/views/profiles/chat_names/new.html.haml b/app/views/profiles/chat_names/new.html.haml
index 2134ab2bec6..4651854a551 100644
--- a/app/views/profiles/chat_names/new.html.haml
+++ b/app/views/profiles/chat_names/new.html.haml
@@ -8,7 +8,7 @@
.actions
= form_tag profile_chat_names_path, method: :post do
= hidden_field_tag :token, @chat_name_token.token
- = submit_tag _("Authorize"), class: "btn btn-success wide float-left"
+ = submit_tag _("Authorize"), class: "gl-button btn btn-success wide float-left"
= form_tag deny_profile_chat_names_path, method: :delete do
= hidden_field_tag :token, @chat_name_token.token
- = submit_tag _("Deny"), class: "btn btn-danger gl-ml-3"
+ = submit_tag _("Deny"), class: "gl-button btn btn-danger gl-ml-3"
diff --git a/app/views/profiles/emails/index.html.haml b/app/views/profiles/emails/index.html.haml
index a04ed87801a..0c6dc1a05d8 100644
--- a/app/views/profiles/emails/index.html.haml
+++ b/app/views/profiles/emails/index.html.haml
@@ -15,7 +15,7 @@
= f.label :email, _('Email'), class: 'label-bold'
= f.text_field :email, class: 'form-control', data: { qa_selector: 'email_address_field' }
.gl-mt-3
- = f.submit _('Add email address'), class: 'btn btn-success', data: { qa_selector: 'add_email_address_button' }
+ = f.submit _('Add email address'), class: 'gl-button btn btn-success', data: { qa_selector: 'add_email_address_button' }
%hr
%h4.gl-mt-0
= _('Linked emails (%{email_count})') % { email_count: @emails.load.size + 1 }
@@ -56,8 +56,8 @@
%span.badge.badge-info= s_('Profiles|Notification email')
- unless email.confirmed?
- confirm_title = "#{email.confirmation_sent_at ? _('Resend confirmation email') : _('Send confirmation email')}"
- = link_to confirm_title, resend_confirmation_instructions_profile_email_path(email), method: :put, class: 'btn btn-sm btn-warning gl-ml-3'
+ = link_to confirm_title, resend_confirmation_instructions_profile_email_path(email), method: :put, class: 'gl-button btn btn-sm btn-warning gl-ml-3'
- = link_to profile_email_path(email), data: { confirm: _('Are you sure?'), qa_selector: 'delete_email_link'}, method: :delete, class: 'btn btn-sm btn-danger gl-ml-3' do
+ = link_to profile_email_path(email), data: { confirm: _('Are you sure?'), qa_selector: 'delete_email_link'}, method: :delete, class: 'gl-button btn btn-sm btn-danger gl-ml-3' do
%span.sr-only= _('Remove')
= sprite_icon('remove')
diff --git a/app/views/profiles/gpg_keys/_form.html.haml b/app/views/profiles/gpg_keys/_form.html.haml
index 2fb07adc006..7a7b5802cd8 100644
--- a/app/views/profiles/gpg_keys/_form.html.haml
+++ b/app/views/profiles/gpg_keys/_form.html.haml
@@ -7,4 +7,4 @@
= f.text_area :key, class: "form-control", rows: 8, required: true, placeholder: _("Don't paste the private part of the GPG key. Paste the public part which begins with '-----BEGIN PGP PUBLIC KEY BLOCK-----'.")
.gl-mt-3
- = f.submit s_('Profiles|Add key'), class: "btn btn-success"
+ = f.submit s_('Profiles|Add key'), class: "gl-button btn btn-success"
diff --git a/app/views/profiles/gpg_keys/_key.html.haml b/app/views/profiles/gpg_keys/_key.html.haml
index f1abafa4149..c851601d4c3 100644
--- a/app/views/profiles/gpg_keys/_key.html.haml
+++ b/app/views/profiles/gpg_keys/_key.html.haml
@@ -19,9 +19,9 @@
.float-right
%span.key-created-at
= s_('Profiles|Created %{time_ago}'.html_safe) % { time_ago:time_ago_with_tooltip(key.created_at)}
- = link_to profile_gpg_key_path(key), data: { confirm: _('Are you sure? Removing this GPG key does not affect already signed commits.') }, method: :delete, class: "btn btn-danger gl-ml-3" do
+ = link_to profile_gpg_key_path(key), data: { confirm: _('Are you sure? Removing this GPG key does not affect already signed commits.') }, method: :delete, class: "gl-button btn btn-danger gl-ml-3" do
%span.sr-only= _('Remove')
= sprite_icon('remove')
- = link_to revoke_profile_gpg_key_path(key), data: { confirm: _('Are you sure? All commits that were signed with this GPG key will be unverified.') }, method: :put, class: "btn btn-danger gl-ml-3" do
+ = link_to revoke_profile_gpg_key_path(key), data: { confirm: _('Are you sure? All commits that were signed with this GPG key will be unverified.') }, method: :put, class: "gl-button btn btn-danger gl-ml-3" do
%span.sr-only= _('Revoke')
= _('Revoke')
diff --git a/app/views/profiles/keys/_form.html.haml b/app/views/profiles/keys/_form.html.haml
index 078b5907623..6a420d7996a 100644
--- a/app/views/profiles/keys/_form.html.haml
+++ b/app/views/profiles/keys/_form.html.haml
@@ -4,13 +4,13 @@
.form-group
= f.label :key, s_('Profiles|Key'), class: 'label-bold'
- %p= _("Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Don't use your private SSH key.")
+ %p= _("Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Do not paste your private SSH key, as that can compromise your identity.")
= f.text_area :key, class: "form-control js-add-ssh-key-validation-input qa-key-public-key-field", rows: 8, required: true, placeholder: s_('Profiles|Typically starts with "ssh-ed25519 …" or "ssh-rsa …"')
.form-row
.col.form-group
= f.label :title, _('Title'), class: 'label-bold'
= f.text_field :title, class: "form-control input-lg qa-key-title-field", required: true, placeholder: s_('Profiles|e.g. My MacBook key')
- %p.form-text.text-muted= s_('Profiles|Give your individual key a title. This will be publically visible.')
+ %p.form-text.text-muted= s_('Profiles|Give your individual key a title.')
.col.form-group
= f.label :expires_at, s_('Profiles|Expires at'), class: 'label-bold'
@@ -19,9 +19,9 @@
.js-add-ssh-key-validation-warning.hide
.bs-callout.bs-callout-warning{ role: 'alert', aria_live: 'assertive' }
%strong= _('Oops, are you sure?')
- %p= s_("Profiles|This doesn't look like a public SSH key, are you sure you want to add it?")
+ %p= s_("Profiles|This doesn't look like a public SSH key, are you sure you want to add it? It will be publicly visible.")
%button.btn.btn-success.js-add-ssh-key-validation-confirm-submit= _("Yes, add it")
.gl-mt-3
- = f.submit s_('Profiles|Add key'), class: "btn btn-success js-add-ssh-key-validation-original-submit qa-add-key-button"
+ = f.submit s_('Profiles|Add key'), class: "gl-button btn btn-success js-add-ssh-key-validation-original-submit qa-add-key-button"
diff --git a/app/views/profiles/keys/_key.html.haml b/app/views/profiles/keys/_key.html.haml
index 02b45853aa0..eaf00ce6709 100644
--- a/app/views/profiles/keys/_key.html.haml
+++ b/app/views/profiles/keys/_key.html.haml
@@ -23,9 +23,10 @@
%span.expires.gl-mr-3
= s_('Profiles|Expires:')
= key.expires_at ? key.expires_at.to_date : _('Never')
- %span.key-created-at
- = s_('Profiles|Created %{time_ago}'.html_safe) % { time_ago:time_ago_with_tooltip(key.created_at)}
+ %span.key-created-at.gl-display-flex.gl-align-items-center
+ = s_('Profiles|Created%{time_ago}'.html_safe) % { time_ago: time_ago_with_tooltip(key.created_at, html_class: 'gl-ml-2')}
- if key.can_delete?
- = link_to path_to_key(key, is_admin), data: { confirm: _('Are you sure?')}, method: :delete, class: "btn btn-transparent gl-ml-3 align-baseline" do
- %span.sr-only= _('Remove')
- = sprite_icon('remove')
+ .gl-ml-3
+ = button_to '#', class: "btn btn-default gl-button btn-default-tertiary js-confirm-modal-button", data: ssh_key_delete_modal_data(key, path_to_key(key, is_admin)) do
+ %span.sr-only= _('Delete')
+ = sprite_icon('remove')
diff --git a/app/views/profiles/keys/_key_details.html.haml b/app/views/profiles/keys/_key_details.html.haml
index 59d953678e7..22d795ca831 100644
--- a/app/views/profiles/keys/_key_details.html.haml
+++ b/app/views/profiles/keys/_key_details.html.haml
@@ -38,4 +38,4 @@
.col-md-12
.float-right
- if @key.can_delete?
- = link_to _('Remove'), path_to_key(@key, is_admin), data: {confirm: _('Are you sure?')}, method: :delete, class: "btn btn-remove delete-key qa-delete-key-button"
+ = button_to _('Delete'), '#', class: "btn btn-danger gl-button delete-key js-confirm-modal-button", data: ssh_key_delete_modal_data(@key, path_to_key(@key, is_admin))
diff --git a/app/views/profiles/notifications/show.html.haml b/app/views/profiles/notifications/show.html.haml
index da684c29372..9c5cfe35cda 100644
--- a/app/views/profiles/notifications/show.html.haml
+++ b/app/views/profiles/notifications/show.html.haml
@@ -3,7 +3,7 @@
%div
- if @user.errors.any?
- .alert.alert-danger
+ .gl-alert.gl-alert-danger
%ul
- @user.errors.full_messages.each do |msg|
%li= msg
diff --git a/app/views/profiles/passwords/edit.html.haml b/app/views/profiles/passwords/edit.html.haml
index fe16c2e2f28..1ee5f52e407 100644
--- a/app/views/profiles/passwords/edit.html.haml
+++ b/app/views/profiles/passwords/edit.html.haml
@@ -30,6 +30,6 @@
= f.label :password_confirmation, _('Password confirmation'), class: 'label-bold'
= f.password_field :password_confirmation, required: true, class: 'form-control', data: { qa_selector: 'confirm_password_field' }
.gl-mt-3.gl-mb-3
- = f.submit _('Save password'), class: "btn btn-success gl-mr-3", data: { qa_selector: 'save_password_button' }
+ = f.submit _('Save password'), class: "gl-button btn btn-success gl-mr-3", data: { qa_selector: 'save_password_button' }
- unless @user.password_automatically_set?
= link_to _('I forgot my password'), reset_profile_password_path, method: :put
diff --git a/app/views/profiles/passwords/new.html.haml b/app/views/profiles/passwords/new.html.haml
index ce60455ab89..f6783528243 100644
--- a/app/views/profiles/passwords/new.html.haml
+++ b/app/views/profiles/passwords/new.html.haml
@@ -28,4 +28,4 @@
.col-sm-10
= f.password_field :password_confirmation, required: true, class: 'form-control'
.form-actions
- = f.submit _('Set new password'), class: 'btn btn-success'
+ = f.submit _('Set new password'), class: 'gl-button btn btn-success'
diff --git a/app/views/profiles/preferences/_gitpod.html.haml b/app/views/profiles/preferences/_gitpod.html.haml
index 69c9443ebbb..589c3a27c18 100644
--- a/app/views/profiles/preferences/_gitpod.html.haml
+++ b/app/views/profiles/preferences/_gitpod.html.haml
@@ -1,5 +1,3 @@
-- gitpod_link = link_to("Gitpod#{sprite_icon('external-link', size: 12, css_class: 'ml-1 vertical-align-center')}".html_safe, 'https://gitpod.io/', target: '_blank', rel: 'noopener noreferrer')
-
%label.label-bold#gitpod
= s_('Gitpod')
= link_to sprite_icon('question-o'), help_page_path('integration/gitpod.md'), target: '_blank', class: 'has-tooltip', title: _('More information')
@@ -8,4 +6,4 @@
= f.label :gitpod_enabled, class: 'form-check-label' do
= s_('Gitpod|Enable Gitpod integration').html_safe
.form-text.text-muted
- = s_('Enable %{gitpod_link} integration to launch a development environment in your browser directly from GitLab.').html_safe % { gitpod_link: gitpod_link }
+ = gitpod_enable_description
diff --git a/app/views/profiles/preferences/show.html.haml b/app/views/profiles/preferences/show.html.haml
index 2c705886f47..b8d7e1af005 100644
--- a/app/views/profiles/preferences/show.html.haml
+++ b/app/views/profiles/preferences/show.html.haml
@@ -2,7 +2,7 @@
- @content_class = "limit-container-width" unless fluid_layout
- Gitlab::Themes.each do |theme|
- = stylesheet_link_tag "themes/theme_#{theme.css_class.gsub('ui-', '')}"
+ = stylesheet_link_tag "themes/#{theme.css_filename}" if theme.css_filename
= form_for @user, url: profile_preferences_path, remote: true, method: :put, html: { class: 'row gl-mt-3 js-preferences-form' } do |f|
.col-lg-4.application-theme#navigation-theme
@@ -143,4 +143,4 @@
.col-lg-4.profile-settings-sidebar
.col-lg-8
.form-group
- = f.submit _('Save changes'), class: 'btn btn-success'
+ = f.submit _('Save changes'), class: 'gl-button btn btn-success'
diff --git a/app/views/profiles/show.html.haml b/app/views/profiles/show.html.haml
index 1eb3a14525f..f5fab727a57 100644
--- a/app/views/profiles/show.html.haml
+++ b/app/views/profiles/show.html.haml
@@ -36,7 +36,7 @@
.form-text.text-muted= s_("Profiles|The maximum file size allowed is 200KB.")
- if @user.avatar?
%hr
- = link_to s_("Profiles|Remove avatar"), profile_avatar_path, data: { confirm: s_("Profiles|Avatar will be removed. Are you sure?") }, method: :delete, class: 'btn btn-danger btn-inverted'
+ = link_to s_("Profiles|Remove avatar"), profile_avatar_path, data: { confirm: s_("Profiles|Avatar will be removed. Are you sure?") }, method: :delete, class: 'gl-button btn btn-danger btn-inverted'
%hr
.row
@@ -46,7 +46,7 @@
.col-lg-8
= f.fields_for :status, @user.status do |status_form|
- emoji_button = button_tag type: :button,
- class: 'js-toggle-emoji-menu emoji-menu-toggle-button btn has-tooltip',
+ class: 'js-toggle-emoji-menu emoji-menu-toggle-button gl-button btn has-tooltip',
title: s_("Profiles|Add status emoji") do
- if @user.status
= emoji_icon @user.status.emoji
@@ -56,7 +56,7 @@
= sprite_icon('smile', css_class: 'award-control-icon-super-positive')
- reset_message_button = button_tag type: :button,
id: 'js-clear-user-status-button',
- class: 'clear-user-status btn has-tooltip',
+ class: 'clear-user-status gl-button btn has-tooltip',
title: s_("Profiles|Clear status") do
= sprite_icon("close")
@@ -78,7 +78,7 @@
-# TODO: might need an entry in user/profile.md to describe some of these settings
-# https://gitlab.com/gitlab-org/gitlab-foss/issues/60070
%h5= ("Time zone")
- = dropdown_tag(_("Select a timezone"), options: { toggle_class: 'btn js-timezone-dropdown input-lg', title: _("Select a timezone"), filter: true, placeholder: s_("OfSearchInADropdown|Filter"), data: { data: timezone_data } } )
+ = dropdown_tag(_("Select a timezone"), options: { toggle_class: 'gl-button btn js-timezone-dropdown input-lg', title: _("Select a timezone"), filter: true, placeholder: s_("OfSearchInADropdown|Filter"), data: { data: timezone_data } } )
%input.hidden{ :type => 'hidden', :id => 'user_timezone', :name => 'user[timezone]', value: @user.timezone }
%hr
@@ -119,10 +119,10 @@
.help-block
= s_("Profiles|Choose to show contributions of private projects on your public profile without any project, repository or organization information")
.gl-mt-3.gl-mb-3
- = f.submit s_("Profiles|Update profile settings"), class: 'btn btn-success'
- = link_to _("Cancel"), user_path(current_user), class: 'btn btn-cancel'
+ = f.submit s_("Profiles|Update profile settings"), class: 'gl-button btn btn-success'
+ = link_to _("Cancel"), user_path(current_user), class: 'gl-button btn btn-cancel'
-.modal.modal-profile-crop
+.modal.modal-profile-crop{ data: { cropper_css_path: ActionController::Base.helpers.stylesheet_path('lazy_bundles/cropper.css') } }
.modal-dialog
.modal-content
.modal-header
diff --git a/app/views/profiles/two_factor_auths/_codes.html.haml b/app/views/profiles/two_factor_auths/_codes.html.haml
index 40272b6354c..2cb7e022912 100644
--- a/app/views/profiles/two_factor_auths/_codes.html.haml
+++ b/app/views/profiles/two_factor_auths/_codes.html.haml
@@ -9,5 +9,5 @@
%span.monospace{ data: { qa_selector: 'code_content' } }= code
.d-flex
- = link_to _('Proceed'), profile_account_path, class: 'btn btn-success gl-mr-3', data: { qa_selector: 'proceed_button' }
- = link_to _('Download codes'), "data:text/plain;charset=utf-8,#{CGI.escape(@codes.join("\n"))}", download: "gitlab-recovery-codes.txt", class: 'btn btn-default'
+ = link_to _('Proceed'), profile_account_path, class: 'gl-button btn btn-success gl-mr-3', data: { qa_selector: 'proceed_button' }
+ = link_to _('Download codes'), "data:text/plain;charset=utf-8,#{CGI.escape(@codes.join("\n"))}", download: "gitlab-recovery-codes.txt", class: 'gl-button btn btn-default'
diff --git a/app/views/profiles/two_factor_auths/show.html.haml b/app/views/profiles/two_factor_auths/show.html.haml
index 82265938180..ff4ddd4ad69 100644
--- a/app/views/profiles/two_factor_auths/show.html.haml
+++ b/app/views/profiles/two_factor_auths/show.html.haml
@@ -20,7 +20,7 @@
= link_to _('Disable two-factor authentication'), profile_two_factor_auth_path,
method: :delete,
data: { confirm: webauthn_enabled ? _('Are you sure? This will invalidate your registered applications and U2F / WebAuthn devices.') : _('Are you sure? This will invalidate your registered applications and U2F devices.') },
- class: 'btn btn-danger gl-mr-3'
+ class: 'gl-button btn btn-danger gl-mr-3'
= form_tag codes_profile_two_factor_auth_path, {style: 'display: inline-block', method: :post} do |f|
= submit_tag _('Regenerate recovery codes'), class: 'btn'
@@ -52,7 +52,7 @@
= label_tag :pin_code, _('Pin code'), class: "label-bold"
= text_field_tag :pin_code, nil, class: "form-control", required: true, data: { qa_selector: 'pin_code_field' }
.gl-mt-3
- = submit_tag _('Register with two-factor app'), class: 'btn btn-success', data: { qa_selector: 'register_2fa_app_button' }
+ = submit_tag _('Register with two-factor app'), class: 'gl-button btn btn-success', data: { qa_selector: 'register_2fa_app_button' }
%hr
@@ -64,12 +64,12 @@
- else
= _('Register Universal Two-Factor (U2F) Device')
%p
- = _('Use a hardware device to add the second factor of authentication.')
+ = _('Set up a hardware device as a second factor to sign in.')
%p
- if webauthn_enabled
- = _("As WebAuthn devices are only supported by a few browsers, we require that you set up a two-factor authentication app before a WebAuthn device. That way you'll always be able to log in - even when you're using an unsupported browser.")
+ = _("Not all browsers support WebAuthn. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even from an unsupported browser.")
- else
- = _("As U2F devices are only supported by a few browsers, we require that you set up a two-factor authentication app before a U2F device. That way you'll always be able to log in - even when you're using an unsupported browser.")
+ = _("Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser.")
.col-lg-8
- registration = webauthn_enabled ? @webauthn_registration : @u2f_registration
- if registration.errors.present?
@@ -102,9 +102,14 @@
%tbody
- @registrations.each do |registration|
%tr
- %td= registration[:name].presence || html_escape_once(_("&lt;no name set&gt;")).html_safe
+ %td
+ - if registration[:name].present?
+ = registration[:name]
+ - else
+ %span.gl-text-gray-500
+ = _("no name set")
%td= registration[:created_at].to_date.to_s(:medium)
- %td= link_to _('Delete'), registration[:delete_path], method: :delete, class: "btn btn-danger float-right", data: { confirm: _('Are you sure you want to delete this device? This action cannot be undone.') }
+ %td= link_to _('Delete'), registration[:delete_path], method: :delete, class: "gl-button btn btn-danger float-right", data: { confirm: _('Are you sure you want to delete this device? This action cannot be undone.') }
- else
.settings-message.text-center
diff --git a/app/views/projects/_export.html.haml b/app/views/projects/_export.html.haml
index 41e13464b1e..5ec2dc57f96 100644
--- a/app/views/projects/_export.html.haml
+++ b/app/views/projects/_export.html.haml
@@ -26,6 +26,5 @@
= link_to _('Generate new export'), generate_new_export_project_path(project),
method: :post, class: "btn btn-default"
- else
- .gl-display-flex.gl-justify-content-end
- = link_to _('Export project'), export_project_path(project),
- method: :post, class: "btn btn-default", data: { qa_selector: 'export_project_link' }
+ = link_to _('Export project'), export_project_path(project),
+ method: :post, class: "btn btn-default", data: { qa_selector: 'export_project_link' }
diff --git a/app/views/projects/_files.html.haml b/app/views/projects/_files.html.haml
index 1562cc065f1..81c42de13f0 100644
--- a/app/views/projects/_files.html.haml
+++ b/app/views/projects/_files.html.haml
@@ -14,7 +14,7 @@
- if is_project_overview
.project-buttons.gl-mb-3.js-show-on-project-root
- = render 'stat_anchor_list', anchors: @project.statistics_buttons(show_auto_devops_callout: show_auto_devops_callout)
+ = render 'stat_anchor_list', anchors: @project.statistics_buttons(show_auto_devops_callout: show_auto_devops_callout), project_buttons: true
#js-tree-list{ data: vue_file_list_data(project, ref) }
- if can_edit_tree?
diff --git a/app/views/projects/_home_panel.html.haml b/app/views/projects/_home_panel.html.haml
index 94a2bdb3bcb..9f4496e7a13 100644
--- a/app/views/projects/_home_panel.html.haml
+++ b/app/views/projects/_home_panel.html.haml
@@ -3,19 +3,19 @@
- max_project_topic_length = 15
- emails_disabled = @project.emails_disabled?
-.project-home-panel.js-show-on-project-root{ class: [("empty-project" if empty_repo)] }
+.project-home-panel.js-show-on-project-root.gl-my-5{ class: [("empty-project" if empty_repo)] }
.row.gl-mb-3
.home-panel-title-row.col-md-12.col-lg-6.d-flex
- .avatar-container.rect-avatar.s64.home-panel-avatar.gl-mr-3.float-none
+ .avatar-container.rect-avatar.s64.home-panel-avatar.gl-flex-shrink-0.gl-w-11.gl-h-11.gl-mr-3.float-none
= project_icon(@project, alt: @project.name, class: 'avatar avatar-tile s64', width: 64, height: 64)
.d-flex.flex-column.flex-wrap.align-items-baseline
.d-inline-flex.align-items-baseline
- %h1.home-panel-title.gl-mt-3.gl-mb-2{ data: { qa_selector: 'project_name_content' } }
+ %h1.home-panel-title.gl-mt-3.gl-mb-2.gl-font-size-h1.gl-line-height-24.gl-font-weight-bold{ data: { qa_selector: 'project_name_content' } }
= @project.name
%span.visibility-icon.text-secondary.gl-ml-2.has-tooltip{ data: { container: 'body' }, title: visibility_icon_description(@project) }
= visibility_level_icon(@project.visibility_level, options: { class: 'icon' })
= render_if_exists 'compliance_management/compliance_framework/compliance_framework_badge', project: @project
- .home-panel-metadata.d-flex.flex-wrap.text-secondary
+ .home-panel-metadata.d-flex.flex-wrap.text-secondary.gl-font-base.gl-font-weight-normal.gl-line-height-normal
- if can?(current_user, :read_project, @project)
%span.text-secondary
= s_('ProjectPage|Project ID: %{project_id}') % { project_id: @project.id }
@@ -23,8 +23,8 @@
%span.access-request-links.gl-ml-3
= render 'shared/members/access_request_links', source: @project
- if @project.tag_list.present?
- %span.home-panel-topic-list.mt-2.w-100.d-inline-flex
- = sprite_icon('tag', css_class: 'icon gl-mr-2')
+ %span.home-panel-topic-list.mt-2.w-100.d-inline-flex.gl-font-base.gl-font-weight-normal
+ = sprite_icon('tag', css_class: 'icon gl-relative gl-mr-2')
- @project.topics_to_show.each do |topic|
- project_topics_classes = "badge badge-pill badge-secondary gl-mr-2"
diff --git a/app/views/projects/_import_project_pane.html.haml b/app/views/projects/_import_project_pane.html.haml
index fe3354aefbb..8b94133fd8a 100644
--- a/app/views/projects/_import_project_pane.html.haml
+++ b/app/views/projects/_import_project_pane.html.haml
@@ -4,7 +4,7 @@
.project-import
.form-group.import-btn-container.clearfix
%h5
- Import project from
+ = _("Import project from")
.import-buttons
- if gitlab_project_import_enabled?
.import_gitlab_project.has-tooltip{ data: { container: 'body' } }
@@ -15,19 +15,22 @@
- if github_import_enabled?
%div
= link_to new_import_github_path, class: 'btn js-import-github', **tracking_attrs(track_label, 'click_button', 'github') do
- = icon('github', text: 'GitHub')
+ = sprite_icon('github')
+ GitHub
- if bitbucket_import_enabled?
%div
= link_to status_import_bitbucket_path, class: "btn import_bitbucket #{'how_to_import_link' unless bitbucket_import_configured?}",
**tracking_attrs(track_label, 'click_button', 'bitbucket_cloud') do
- = icon('bitbucket', text: 'Bitbucket Cloud')
+ = sprite_icon('bitbucket')
+ Bitbucket Cloud
- unless bitbucket_import_configured?
= render 'projects/bitbucket_import_modal'
- if bitbucket_server_import_enabled?
%div
= link_to status_import_bitbucket_server_path, class: "btn import_bitbucket", **tracking_attrs(track_label, 'click_button', 'bitbucket_server') do
- = icon('bitbucket-square', text: 'Bitbucket Server')
+ = sprite_icon('bitbucket')
+ Bitbucket Server
%div
- if gitlab_import_enabled?
%div
@@ -41,7 +44,8 @@
- if google_code_import_enabled?
%div
= link_to new_import_google_code_path, class: 'btn import_google_code', **tracking_attrs(track_label, 'click_button', 'google_code') do
- = icon('google', text: 'Google Code')
+ = sprite_icon('google')
+ Google Code
- if fogbugz_import_enabled?
%div
@@ -64,7 +68,8 @@
- if manifest_import_enabled?
%div
= link_to new_import_manifest_path, class: 'btn import_manifest', **tracking_attrs(track_label, 'click_button', 'manifest_file') do
- = icon('file-text-o', text: 'Manifest file')
+ = sprite_icon('doc-text')
+ Manifest file
- if phabricator_import_enabled?
%div
diff --git a/app/views/projects/_project_templates.html.haml b/app/views/projects/_project_templates.html.haml
index 98fdb1d7a0b..79221c59ae4 100644
--- a/app/views/projects/_project_templates.html.haml
+++ b/app/views/projects/_project_templates.html.haml
@@ -1,7 +1,21 @@
- f ||= local_assigns[:f]
-.project-templates-buttons.import-buttons.col-sm-12
- = render 'projects/project_templates/built_in_templates'
+.project-templates-buttons.col-sm-12
+ %ul.nav-tabs.nav-links.nav.scrolling-tabs
+ %li.built-in-tab
+ %a.nav-link.active{ href: "#built-in", data: { toggle: 'tab'} }
+ = _('Built-in')
+ %span.badge.badge-pill= Gitlab::ProjectTemplate.all.count
+ %li.sample-data-templates-tab
+ %a.nav-link{ href: "#sample-data-templates", data: { toggle: 'tab'} }
+ = _('Sample Data')
+ %span.badge.badge-pill= Gitlab::SampleDataTemplate.all.count
+
+.tab-content
+ .project-templates-buttons.import-buttons.tab-pane.active#built-in
+ = render partial: 'projects/project_templates/template', collection: Gitlab::ProjectTemplate.all
+ .project-templates-buttons.import-buttons.tab-pane#sample-data-templates
+ = render partial: 'projects/project_templates/template', collection: Gitlab::SampleDataTemplate.all
.project-fields-form
= render 'projects/project_templates/project_fields_form'
diff --git a/app/views/projects/_stat_anchor_list.html.haml b/app/views/projects/_stat_anchor_list.html.haml
index 8e3d759b683..516790fb6d9 100644
--- a/app/views/projects/_stat_anchor_list.html.haml
+++ b/app/views/projects/_stat_anchor_list.html.haml
@@ -1,8 +1,9 @@
- anchors = local_assigns.fetch(:anchors, [])
+- project_buttons = local_assigns.fetch(:project_buttons, false)
- return unless anchors.any?
%ul.nav
- anchors.each do |anchor|
%li.nav-item
= link_to_if anchor.link, anchor.label, anchor.link, class: anchor.is_link ? 'nav-link stat-link d-flex align-items-center' : "nav-link btn btn-#{anchor.class_modifier || 'missing'} d-flex align-items-center" do
- .stat-text.d-flex.align-items-center= anchor.label
+ .stat-text.d-flex.align-items-center{ class: ('btn btn-default disabled' if project_buttons) }= anchor.label
diff --git a/app/views/projects/_visibility_modal.html.haml b/app/views/projects/_visibility_modal.html.haml
index 144f726572b..314211057f9 100644
--- a/app/views/projects/_visibility_modal.html.haml
+++ b/app/views/projects/_visibility_modal.html.haml
@@ -23,7 +23,7 @@
= ("To confirm, type %{phrase_code}").html_safe % { phrase_code: '<code class="js-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-confirm-danger-input qa-confirm-input'
- .form-actions.gl-display-flex.gl-justify-content-end
+ .form-actions
%button.btn.btn-default.gl-mr-4{ type: "button", "data-dismiss": "modal" }
= _('Cancel')
= submit_tag _('Reduce project visibility'), class: "btn btn-danger js-confirm-danger-submit qa-confirm-button", disabled: true
diff --git a/app/views/projects/artifacts/_artifact.html.haml b/app/views/projects/artifacts/_artifact.html.haml
index 36e149556e0..30f30fe922f 100644
--- a/app/views/projects/artifacts/_artifact.html.haml
+++ b/app/views/projects/artifacts/_artifact.html.haml
@@ -10,7 +10,7 @@
%span.build-link ##{artifact.job_id}
- if artifact.job.ref
- .icon-container{ "aria-label" => artifact.job.tag? ? _('Tag') : _('Branch') }
+ .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
@@ -30,7 +30,7 @@
.table-mobile-header{ role: 'rowheader' }= _('Creation date')
.table-mobile-content
%p.finished-at
- = icon("calendar")
+ = sprite_icon("calendar")
%span= time_ago_with_tooltip(artifact.created_at)
.table-section.section-20
@@ -38,7 +38,7 @@
.table-mobile-content
- if artifact.expire_at
%p.finished-at
- = icon("calendar")
+ = sprite_icon("calendar")
%span= time_ago_with_tooltip(artifact.expire_at)
.table-section.section-10
@@ -57,5 +57,5 @@
= sprite_icon('folder-open')
- 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?') }, method: :delete, title: _('Delete artifacts'), ref: 'tooltip', aria: { label: _('Delete artifacts') }, class: 'btn btn-remove has-tooltip' do
+ = link_to project_artifact_path(@project, artifact), data: { placement: 'top', container: 'body', confirm: _('Are you sure you want to delete these artifacts?') }, method: :delete, title: _('Delete artifacts'), ref: 'tooltip', aria: { label: _('Delete artifacts') }, class: 'gl-button btn btn-danger has-tooltip' do
= sprite_icon('remove')
diff --git a/app/views/projects/blob/_content.html.haml b/app/views/projects/blob/_content.html.haml
index 11946f22811..5b77e31eb00 100644
--- a/app/views/projects/blob/_content.html.haml
+++ b/app/views/projects/blob/_content.html.haml
@@ -2,9 +2,9 @@
- rich_viewer = blob.rich_viewer
- rich_viewer_active = rich_viewer && params[:viewer] != 'simple'
- blob_data = defined?(@blob) ? @blob.data : {}
-- filename = defined?(@blob) ? @blob.name : ''
+- is_ci_config_file = defined?(@blob) && defined?(@project) ? editing_ci_config?.to_s : 'false'
-#js-blob-toggle-graph-preview{ data: { blob_data: blob_data, filename: filename } }
+#js-blob-toggle-graph-preview{ data: { blob_data: blob_data, is_ci_config_file: is_ci_config_file } }
= render 'projects/blob/viewer', viewer: simple_viewer, hidden: rich_viewer_active
diff --git a/app/views/projects/blob/_editor.html.haml b/app/views/projects/blob/_editor.html.haml
index cea65bf9b4e..b0317d84cdc 100644
--- a/app/views/projects/blob/_editor.html.haml
+++ b/app/views/projects/blob/_editor.html.haml
@@ -20,8 +20,7 @@
required: true, class: 'form-control 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?
- .js-suggest-gitlab-ci-yml{ data: { toggle: 'popover',
- target: '#gitlab-ci-yml-selector',
+ .js-suggest-gitlab-ci-yml{ data: { target: '#gitlab-ci-yml-selector',
track_label: 'suggest_gitlab_ci_yml',
merge_request_path: params[:mr_path],
dismiss_key: @project.id,
@@ -30,7 +29,7 @@
.file-buttons
- if is_markdown
= render 'shared/blob/markdown_buttons', show_fullscreen_button: false
- = button_tag class: 'soft-wrap-toggle btn', type: 'button', tabindex: '-1' do
+ = button_tag class: 'soft-wrap-toggle btn gl-button', type: 'button', tabindex: '-1' do
%span.no-wrap
= custom_icon('icon_no_wrap')
No wrap
diff --git a/app/views/projects/blob/_header.html.haml b/app/views/projects/blob/_header.html.haml
index 2a1545e7db7..55ae9cded1c 100644
--- a/app/views/projects/blob/_header.html.haml
+++ b/app/views/projects/blob/_header.html.haml
@@ -4,8 +4,11 @@
.file-actions<
= render 'projects/blob/viewer_switcher', blob: blob unless blame
- = edit_blob_button(@project, @ref, @path, blob: blob)
- = ide_edit_button(@project, @ref, @path, blob: blob)
+ - if Feature.enabled?(:consolidated_edit_button)
+ = render 'shared/web_ide_button', blob: blob
+ - else
+ = edit_blob_button(@project, @ref, @path, blob: blob)
+ = ide_edit_button(@project, @ref, @path, blob: blob)
.btn-group.ml-2{ role: "group" }>
= render_if_exists 'projects/blob/header_file_locks_link'
- if current_user
diff --git a/app/views/projects/blob/_new_dir.html.haml b/app/views/projects/blob/_new_dir.html.haml
index e9010dc63fc..ca60827863a 100644
--- a/app/views/projects/blob/_new_dir.html.haml
+++ b/app/views/projects/blob/_new_dir.html.haml
@@ -15,7 +15,7 @@
= render 'shared/new_commit_form', placeholder: _("Add new directory")
.form-actions
- = submit_tag _("Create directory"), class: 'btn btn-success'
- = link_to "Cancel", '#', class: "btn btn-cancel", "data-dismiss" => "modal"
+ = submit_tag _("Create directory"), class: 'btn gl-button btn-success'
+ = link_to "Cancel", '#', class: "btn gl-button btn-cancel", "data-dismiss" => "modal"
= render 'shared/projects/edit_information'
diff --git a/app/views/projects/blob/_remove.html.haml b/app/views/projects/blob/_remove.html.haml
index f80bae5c88c..d3440ee41b5 100644
--- a/app/views/projects/blob/_remove.html.haml
+++ b/app/views/projects/blob/_remove.html.haml
@@ -12,5 +12,5 @@
.form-group.row
.offset-sm-2.col-sm-10
- = button_tag 'Delete file', class: 'btn btn-remove btn-remove-file'
- = link_to "Cancel", '#', class: "btn btn-cancel", "data-dismiss" => "modal"
+ = button_tag 'Delete file', class: 'btn gl-button btn-danger btn-remove-file'
+ = link_to "Cancel", '#', class: "btn gl-button btn-cancel", "data-dismiss" => "modal"
diff --git a/app/views/projects/blob/_upload.html.haml b/app/views/projects/blob/_upload.html.haml
index d2b3c8ef96b..4dbfa2b1e3c 100644
--- a/app/views/projects/blob/_upload.html.haml
+++ b/app/views/projects/blob/_upload.html.haml
@@ -15,14 +15,14 @@
#{ dropzone_text.html_safe }
%br
- .dropzone-alerts.alert.alert-danger.data{ style: "display:none" }
+ .dropzone-alerts.gl-alert.gl-alert-danger.gl-mb-5.data{ style: "display:none" }
= render 'shared/new_commit_form', placeholder: placeholder
.form-actions
- = button_tag class: 'btn btn-success btn-upload-file', id: 'submit-all', type: 'button' do
+ = button_tag class: 'btn gl-button btn-success btn-upload-file', id: 'submit-all', type: 'button' do
= icon('spin spinner', class: 'js-loading-icon hidden' )
= button_title
- = link_to _("Cancel"), '#', class: "btn btn-cancel", "data-dismiss" => "modal"
+ = link_to _("Cancel"), '#', class: "btn gl-button btn-cancel", "data-dismiss" => "modal"
= render 'shared/projects/edit_information'
diff --git a/app/views/projects/blob/_viewer_switcher.html.haml b/app/views/projects/blob/_viewer_switcher.html.haml
index df81e509c85..8e3cf607bbf 100644
--- a/app/views/projects/blob/_viewer_switcher.html.haml
+++ b/app/views/projects/blob/_viewer_switcher.html.haml
@@ -4,9 +4,9 @@
.btn-group.js-blob-viewer-switcher.ml-2{ role: "group" }>
- simple_label = "Display #{simple_viewer.switcher_title}"
- %button.btn.btn-default.btn-sm.js-blob-viewer-switch-btn.has-tooltip{ 'aria-label' => simple_label, title: simple_label, data: { viewer: 'simple', container: 'body' } }>
+ %button.btn.gl-button.btn-default.btn-sm.js-blob-viewer-switch-btn.has-tooltip{ 'aria-label' => simple_label, title: simple_label, data: { viewer: 'simple', container: 'body' } }>
= sprite_icon(simple_viewer.switcher_icon)
- rich_label = "Display #{rich_viewer.switcher_title}"
- %button.btn.btn-default.btn-sm.js-blob-viewer-switch-btn.has-tooltip{ 'aria-label' => rich_label, title: rich_label, data: { viewer: 'rich', container: 'body' } }>
+ %button.btn.gl-button.btn-default.btn-sm.js-blob-viewer-switch-btn.has-tooltip{ 'aria-label' => rich_label, title: rich_label, data: { viewer: 'rich', container: 'body' } }>
= sprite_icon(rich_viewer.switcher_icon)
diff --git a/app/views/projects/blob/edit.html.haml b/app/views/projects/blob/edit.html.haml
index 9bb4342ffb4..54c47e7af38 100644
--- a/app/views/projects/blob/edit.html.haml
+++ b/app/views/projects/blob/edit.html.haml
@@ -9,9 +9,6 @@
= link_to "the file", project_blob_path(@project, tree_join(@branch_name, @file_path)), target: "_blank", rel: 'noopener noreferrer', class: 'gl-link'
and make sure your changes will not unintentionally remove theirs.
-- if editing_ci_config? && show_web_ide_alert?
- #js-suggest-web-ide-ci{ data: { dismiss_endpoint: user_callouts_path, feature_id: UserCalloutsHelper::WEB_IDE_ALERT_DISMISSED, edit_path: ide_edit_path } }
-
.editor-title-row
%h3.page-title.blob-edit-page-title
Edit file
diff --git a/app/views/projects/blob/new.html.haml b/app/views/projects/blob/new.html.haml
index a939f43d5e2..2a33afabb7c 100644
--- a/app/views/projects/blob/new.html.haml
+++ b/app/views/projects/blob/new.html.haml
@@ -13,8 +13,7 @@
= render 'projects/commit_button', ref: @ref,
cancel_path: project_tree_path(@project, @id)
- if should_suggest_gitlab_ci_yml?
- .js-suggest-gitlab-ci-yml-commit-changes{ data: { toggle: 'popover',
- target: '#commit-changes',
+ .js-suggest-gitlab-ci-yml-commit-changes{ data: { target: '#commit-changes',
merge_request_path: params[:mr_path],
track_label: 'suggest_commit_first_project_gitlab_ci_yml',
dismiss_key: @project.id,
diff --git a/app/views/projects/blob/viewers/_markup.html.haml b/app/views/projects/blob/viewers/_markup.html.haml
index 8134adcbc32..703ffa8896e 100644
--- a/app/views/projects/blob/viewers/_markup.html.haml
+++ b/app/views/projects/blob/viewers/_markup.html.haml
@@ -1,4 +1,3 @@
- blob = viewer.blob
-- context = blob.respond_to?(:rendered_markup) ? { rendered: blob.rendered_markup } : {}
.file-content.md
- = markup(blob.name, blob.data, context)
+ = markup(blob.name, blob.data, viewer.banzai_render_context)
diff --git a/app/views/projects/branches/_branch.html.haml b/app/views/projects/branches/_branch.html.haml
index 020a4361203..30e710ead7f 100644
--- a/app/views/projects/branches/_branch.html.haml
+++ b/app/views/projects/branches/_branch.html.haml
@@ -50,13 +50,13 @@
- if can?(current_user, :push_code, @project)
- if branch.name == @project.repository.root_ref
- %button{ class: "btn btn-remove remove-row has-tooltip disabled",
+ %button{ class: "gl-button btn btn-danger remove-row has-tooltip disabled",
disabled: true,
title: s_('Branches|The default branch cannot be deleted') }
= sprite_icon("remove")
- elsif protected_branch?(@project, branch)
- if can?(current_user, :push_to_delete_protected_branch, @project)
- %button{ class: "btn btn-remove remove-row has-tooltip",
+ %button{ class: "gl-button btn btn-danger remove-row has-tooltip",
title: s_('Branches|Delete protected branch'),
data: { toggle: "modal",
target: "#modal-delete-branch",
@@ -65,13 +65,13 @@
is_merged: ("true" if merged) } }
= sprite_icon("remove")
- else
- %button{ class: "btn btn-remove remove-row has-tooltip disabled",
+ %button{ class: "gl-button btn btn-danger remove-row has-tooltip disabled",
disabled: true,
title: s_('Branches|Only a project maintainer or owner can delete a protected branch') }
= sprite_icon("remove")
- else
= link_to project_branch_path(@project, branch.name),
- class: "btn btn-remove remove-row qa-remove-btn js-ajax-loading-spinner has-tooltip",
+ class: "gl-button btn btn-danger remove-row qa-remove-btn js-ajax-loading-spinner has-tooltip",
title: s_('Branches|Delete branch'),
method: :delete,
data: { confirm: s_("Branches|Deleting the '%{branch_name}' branch cannot be undone. Are you sure?") % { branch_name: branch.name } },
diff --git a/app/views/projects/branches/index.html.haml b/app/views/projects/branches/index.html.haml
index ba42f43088f..f3561ed5078 100644
--- a/app/views/projects/branches/index.html.haml
+++ b/app/views/projects/branches/index.html.haml
@@ -34,7 +34,7 @@
- if can? current_user, :push_code, @project
= link_to project_merged_branches_path(@project),
- class: 'btn btn-inverted btn-remove has-tooltip qa-delete-merged-branches',
+ 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,
data: { confirm: s_('Branches|Deleting the merged branches cannot be undone. Are you sure?'),
diff --git a/app/views/projects/buttons/_fork.html.haml b/app/views/projects/buttons/_fork.html.haml
index 2d9c7f9848f..dbe0bf35b98 100644
--- a/app/views/projects/buttons/_fork.html.haml
+++ b/app/views/projects/buttons/_fork.html.haml
@@ -3,14 +3,14 @@
.count-badge.d-inline-flex.align-item-stretch.gl-mr-3
- if current_user.already_forked?(@project) && current_user.manageable_namespaces.size < 2
= link_to namespace_project_path(current_user, current_user.fork_of(@project)), title: s_('ProjectOverview|Go to your fork'), class: 'btn btn-default has-tooltip count-badge-button d-flex align-items-center fork-btn' do
- = sprite_icon('fork', { css_class: 'icon' })
+ = sprite_icon('fork', css_class: 'icon')
%span= s_('ProjectOverview|Fork')
- else
- can_create_fork = current_user.can?(:create_fork)
= link_to new_project_fork_path(@project),
class: "btn btn-default btn-xs has-tooltip count-badge-button d-flex align-items-center fork-btn #{'has-tooltip disabled' unless can_create_fork}",
title: (s_('ProjectOverview|You have reached your project limit') unless can_create_fork) do
- = sprite_icon('fork', { css_class: 'icon' })
+ = sprite_icon('fork', css_class: 'icon')
%span= s_('ProjectOverview|Fork')
%span.fork-count.count-badge-count.d-flex.align-items-center
= link_to project_forks_path(@project), title: n_(s_('ProjectOverview|Fork'), s_('ProjectOverview|Forks'), @project.forks_count), class: 'count' do
diff --git a/app/views/projects/buttons/_remove_tag.html.haml b/app/views/projects/buttons/_remove_tag.html.haml
new file mode 100644
index 00000000000..ae776e93203
--- /dev/null
+++ b/app/views/projects/buttons/_remove_tag.html.haml
@@ -0,0 +1,6 @@
+- project = local_assigns.fetch(:project, nil)
+- tag = local_assigns.fetch(:tag, nil)
+- return unless project && tag
+
+%button{ type: "button", class: "js-remove-tag js-confirm-modal-button gl-button btn btn-danger remove-row has-tooltip gl-ml-3 #{protected_tag?(project, tag) ? 'disabled' : ''}", title: s_('TagsPage|Delete tag'), data: { container: 'body', path: project_tag_path(@project, tag.name), modal_attributes: delete_tag_modal_attributes(tag.name) } }
+ = sprite_icon("remove")
diff --git a/app/views/projects/buttons/_star.html.haml b/app/views/projects/buttons/_star.html.haml
index 3dac38d1356..690f0fe10f7 100644
--- a/app/views/projects/buttons/_star.html.haml
+++ b/app/views/projects/buttons/_star.html.haml
@@ -2,10 +2,10 @@
.count-badge.d-inline-flex.align-item-stretch.gl-mr-3
%button.count-badge-button.btn.btn-default.btn-xs.d-flex.align-items-center.star-btn.toggle-star{ type: "button", data: { endpoint: toggle_star_project_path(@project, :json) } }
- if current_user.starred?(@project)
- = sprite_icon('star', { css_class: 'icon' })
+ = sprite_icon('star', css_class: 'icon')
%span.starred= s_('ProjectOverview|Unstar')
- else
- = sprite_icon('star-o', { css_class: 'icon' })
+ = sprite_icon('star-o', css_class: 'icon')
%span= s_('ProjectOverview|Star')
%span.star-count.count-badge-count.d-flex.align-items-center
= link_to project_starrers_path(@project), title: n_(s_('ProjectOverview|Starrer'), s_('ProjectOverview|Starrers'), @project.star_count), class: 'count' do
@@ -14,7 +14,7 @@
- else
.count-badge.d-inline-flex.align-item-stretch.gl-mr-3
= link_to new_user_session_path, class: 'btn btn-default btn-xs has-tooltip count-badge-button d-flex align-items-center star-btn', title: s_('ProjectOverview|You must sign in to star a project') do
- = sprite_icon('star-o', { css_class: 'icon' })
+ = sprite_icon('star-o', css_class: 'icon')
%span= s_('ProjectOverview|Star')
%span.star-count.count-badge-count.d-flex.align-items-center
= link_to project_starrers_path(@project), title: n_(s_('ProjectOverview|Starrer'), s_('ProjectOverview|Starrers'), @project.star_count), class: 'count' do
diff --git a/app/views/projects/ci/builds/_build.html.haml b/app/views/projects/ci/builds/_build.html.haml
index c7ab01a4ef7..138f5569218 100644
--- a/app/views/projects/ci/builds/_build.html.haml
+++ b/app/views/projects/ci/builds/_build.html.haml
@@ -21,8 +21,8 @@
- if ref
- if job.ref
- .icon-container
- = job.tag? ? icon('tag') : sprite_icon('fork', css_class: 'sprite')
+ .icon-container.gl-display-inline-block
+ = job.tag? ? sprite_icon('label', css_class: 'sprite') : sprite_icon('fork', css_class: 'sprite')
= link_to job.ref, project_ref_path(job.project, job.ref), class: "ref-name"
- else
.light= _('none')
@@ -33,10 +33,12 @@
= link_to job.short_sha, project_commit_path(job.project, job.sha), class: "commit-sha mr-0"
- if job.stuck?
- = icon('warning', class: 'text-warning has-tooltip', title: _('Job is stuck. Check runners.'))
+ %span.has-tooltip{ title: _('Job is stuck. Check runners.') }
+ = sprite_icon('warning', css_class: 'text-warning!')
- if retried
- = icon('refresh', class: 'text-warning has-tooltip', title: _('Job was retried'))
+ %span.has-tooltip{ title: _('Job was retried') }
+ = sprite_icon('retry', css_class: 'text-warning')
.label-container
- if job.tags.any?
@@ -87,7 +89,7 @@
- if job.finished_at
%p.finished-at
- = icon("calendar")
+ = sprite_icon("calendar")
%span= time_ago_with_tooltip(job.finished_at)
%td.coverage
@@ -101,11 +103,11 @@
= sprite_icon('download')
- if can?(current_user, :update_build, job)
- if job.active?
- = link_to cancel_project_job_path(job.project, job, continue: { to: request.fullpath }), method: :post, title: _('Cancel'), class: 'btn btn-build' do
+ = link_to cancel_project_job_path(job.project, job, continue: { to: request.fullpath }), method: :post, title: _('Cancel'), class: 'btn gl-button btn-build' do
= sprite_icon('close')
- elsif job.scheduled?
.btn-group
- .btn.btn-default{ disabled: true }
+ .btn.gl-button.btn-default{ disabled: true }
= sprite_icon('planning')
%time.js-remaining-time{ datetime: job.scheduled_at.utc.iso8601 }
= duration_in_numbers(job.execute_in)
@@ -113,17 +115,17 @@
= link_to play_project_job_path(job.project, job, return_to: request.original_url),
method: :post,
title: s_('DelayedJobs|Start now'),
- class: 'btn btn-default btn-build has-tooltip',
+ class: 'btn gl-button btn-default btn-build has-tooltip',
data: { confirm: confirmation_message } do
= sprite_icon('play')
= link_to unschedule_project_job_path(job.project, job, return_to: request.original_url),
method: :post,
title: s_('DelayedJobs|Unschedule'),
- class: 'btn btn-default btn-build has-tooltip' do
+ class: 'btn gl-button btn-default btn-build has-tooltip' do
= sprite_icon('time-out')
- elsif allow_retry
- if job.playable? && !admin && can?(current_user, :update_build, job)
- = link_to play_project_job_path(job.project, job, return_to: request.original_url), method: :post, title: _('Play'), class: 'btn btn-build' do
+ = link_to play_project_job_path(job.project, job, return_to: request.original_url), method: :post, title: _('Play'), class: 'btn gl-button btn-build' do
= custom_icon('icon_play')
- elsif job.retryable?
= link_to retry_project_job_path(job.project, job, return_to: request.original_url), method: :post, title: _('Retry'), class: 'btn btn-build gl-button btn-icon btn-default' do
diff --git a/app/views/projects/ci/lints/show.html.haml b/app/views/projects/ci/lints/show.html.haml
index 2e79852f4c9..64f250bd607 100644
--- a/app/views/projects/ci/lints/show.html.haml
+++ b/app/views/projects/ci/lints/show.html.haml
@@ -1,13 +1,10 @@
- page_title _("CI Lint")
- page_description _("Validate your GitLab CI configuration file")
-- unless Feature.enabled?(:monaco_ci)
- - content_for :library_javascripts do
- = page_specific_javascript_tag('lib/ace.js')
%h2.pt-3.pb-3= _("Validate your GitLab CI configuration")
- if Feature.enabled?(:ci_lint_vue, @project)
- #js-ci-lint{ data: { endpoint: project_ci_lint_path(@project) } }
+ #js-ci-lint{ data: { endpoint: project_ci_lint_path(@project), help_page_path: help_page_path('ci/lint', anchor: 'pipeline-simulation') } }
- else
.project-ci-linter
@@ -17,12 +14,9 @@
.file-holder
.js-file-title.file-title.clearfix
= _("Contents of .gitlab-ci.yml")
- - if Feature.enabled?(:monaco_ci)
- .file-editor.code
- .js-edit-mode-pane.qa-editor#editor{ data: { 'editor-loading': true } }<
- %pre.editor-loading-content= params[:content]
- - else
- #ci-editor.ci-editor= @content
+ .file-editor.code
+ .js-edit-mode-pane.qa-editor#editor{ data: { 'editor-loading': true } }<
+ %pre.editor-loading-content= params[:content]
= text_area_tag(:content, @content, class: 'hidden form-control span1', rows: 7, require: true)
.col-sm-12
.float-left.gl-mt-3
diff --git a/app/views/projects/cleanup/_show.html.haml b/app/views/projects/cleanup/_show.html.haml
index 019894ddbb4..02d35e690ca 100644
--- a/app/views/projects/cleanup/_show.html.haml
+++ b/app/views/projects/cleanup/_show.html.haml
@@ -26,5 +26,4 @@
.form-text.text-muted
= _("The maximum file size allowed is %{size}.") % { size: number_to_human_size(Gitlab::CurrentSettings.max_attachment_size.megabytes) }
- .gl-display-flex.gl-justify-content-end
- = f.submit _('Start cleanup'), class: 'btn btn-success'
+ = f.submit _('Start cleanup'), class: 'btn btn-success'
diff --git a/app/views/projects/commit/_commit_box.html.haml b/app/views/projects/commit/_commit_box.html.haml
index 29ee4a69e83..86c80f1a8ae 100644
--- a/app/views/projects/commit/_commit_box.html.haml
+++ b/app/views/projects/commit/_commit_box.html.haml
@@ -1,6 +1,6 @@
- can_collaborate = can_collaborate_with_project?(@project)
-.page-content-header.js-commit-box{ 'data-commit-path' => branches_project_commit_path(@project, @commit.id) }
+.page-content-header
.header-main-content
= render partial: 'signature', object: @commit.signature
%strong
@@ -22,17 +22,17 @@
.header-action-buttons
- if defined?(@notes_count) && @notes_count > 0
- %span.btn.disabled.btn-grouped.d-none.d-sm-block.gl-mr-3.has-tooltip{ title: n_("%d comment on this commit", "%d comments on this commit", @notes_count) % @notes_count }
+ %span.btn.disabled.gl-button.btn-icon.d-none.d-sm-inline.gl-mr-3.has-tooltip{ title: n_("%d comment on this commit", "%d comments on this commit", @notes_count) % @notes_count }
= sprite_icon('comment')
= @notes_count
- = link_to project_tree_path(@project, @commit), class: "btn btn-default gl-mr-3 d-none d-sm-none d-md-inline" do
+ = link_to project_tree_path(@project, @commit), class: "btn gl-button gl-mr-3 d-none d-md-inline" do
#{ _('Browse files') }
.dropdown.inline
- %a.btn.btn-default.dropdown-toggle.qa-options-button.d-md-inline{ data: { toggle: "dropdown" } }
+ %a.btn.gl-button.dropdown-toggle.qa-options-button.d-md-inline{ data: { toggle: "dropdown" } }
%span= _('Options')
= icon('caret-down')
%ul.dropdown-menu.dropdown-menu-right
- %li.d-block.d-sm-none.d-md-none
+ %li.d-block.d-sm-none
= link_to project_tree_path(@project, @commit) do
#{ _('Browse Files') }
- if can_collaborate && !@commit.has_been_reverted?(current_user)
@@ -58,7 +58,7 @@
%pre.commit-description<
= preserve(markdown_field(@commit, :description))
-.info-well
+.info-well.js-commit-box-info{ 'data-commit-path' => branches_project_commit_path(@project, @commit.id) }
.well-segment.branch-info
.icon-container.commit-icon
= custom_icon("icon_commit")
diff --git a/app/views/projects/commit/pipelines.html.haml b/app/views/projects/commit/pipelines.html.haml
index f8c27f4c026..0dbd6e53212 100644
--- a/app/views/projects/commit/pipelines.html.haml
+++ b/app/views/projects/commit/pipelines.html.haml
@@ -1,4 +1,5 @@
- page_title _('Pipelines'), "#{@commit.title} (#{@commit.short_id})", _('Commits')
+- add_page_specific_style 'page_bundles/pipelines'
= render 'commit_box'
= render 'ci_menu'
diff --git a/app/views/projects/commit/show.html.haml b/app/views/projects/commit/show.html.haml
index 40b96ca477e..003a27f4c9a 100644
--- a/app/views/projects/commit/show.html.haml
+++ b/app/views/projects/commit/show.html.haml
@@ -7,6 +7,7 @@
- @content_class = limited_container_width
- page_title "#{@commit.title} (#{@commit.short_id})", _('Commits')
- page_description @commit.description
+- add_page_specific_style 'page_bundles/pipelines'
.container-fluid{ class: [limited_container_width, container_class] }
= render "commit_box"
diff --git a/app/views/projects/commits/_commits.html.haml b/app/views/projects/commits/_commits.html.haml
index 293500a6c31..63cc96c2c05 100644
--- a/app/views/projects/commits/_commits.html.haml
+++ b/app/views/projects/commits/_commits.html.haml
@@ -28,7 +28,8 @@
= render partial: 'projects/commits/commit', collection: context_commits, locals: { project: project, ref: ref, merge_request: merge_request }
- if hidden > 0
- %li.alert.alert-warning
+ %li.gl-alert.gl-alert-warning
+ = sprite_icon('warning', size: 16, css_class: 'gl-icon gl-alert-icon gl-alert-icon-no-title')
= 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 project.context_commits_enabled? && can_update_merge_request && context_commits&.empty?
diff --git a/app/views/projects/commits/show.html.haml b/app/views/projects/commits/show.html.haml
index 28b5dc0cc67..40dd3a685d4 100644
--- a/app/views/projects/commits/show.html.haml
+++ b/app/views/projects/commits/show.html.haml
@@ -17,16 +17,16 @@
.tree-controls
- if @merge_request.present?
.control.d-none.d-md-block
- = link_to _("View open merge request"), project_merge_request_path(@project, @merge_request), class: 'btn'
+ = link_to _("View open merge request"), project_merge_request_path(@project, @merge_request), class: 'btn gl-button'
- elsif create_mr_button?(@repository.root_ref, @ref)
.control.d-none.d-md-block
- = link_to _("Create merge request"), create_mr_path(@repository.root_ref, @ref), class: 'btn btn-success'
+ = link_to _("Create merge request"), create_mr_path(@repository.root_ref, @ref), class: 'btn gl-button btn-success'
.control
= form_tag(project_commits_path(@project, @id), method: :get, class: 'commits-search-form js-signature-container', data: { 'signatures-path' => namespace_project_signatures_path }) do
= search_field_tag :search, params[:search], { placeholder: _('Search by message'), id: 'commits-search', class: 'form-control search-text-input input-short gl-mt-3 gl-sm-mt-0 gl-min-w-full', spellcheck: false }
.control.d-none.d-md-block
- = link_to project_commits_path(@project, @ref, rss_url_options), title: _("Commits feed"), class: 'btn btn-svg' do
+ = link_to project_commits_path(@project, @ref, rss_url_options), title: _("Commits feed"), class: 'btn gl-button btn-svg' do
= sprite_icon('rss', css_class: 'qa-rss-icon')
= render_if_exists 'projects/commits/mirror_status'
diff --git a/app/views/projects/compare/_form.html.haml b/app/views/projects/compare/_form.html.haml
index 768acac96c0..a257f2e9433 100644
--- a/app/views/projects/compare/_form.html.haml
+++ b/app/views/projects/compare/_form.html.haml
@@ -1,14 +1,14 @@
= form_tag project_compare_index_path(@project), method: :post, class: 'form-inline js-requires-input js-signature-container', data: { 'signatures-path' => signatures_namespace_project_compare_index_path } do
- if params[:to] && params[:from]
.compare-switch-container
- = link_to sprite_icon('substitute'), { from: params[:to], to: params[:from] }, class: 'commits-compare-switch has-tooltip btn btn-white', title: 'Swap revisions'
+ = link_to sprite_icon('substitute'), { from: params[:to], to: params[:from] }, class: 'commits-compare-switch has-tooltip btn gl-button btn-white', title: 'Swap revisions'
.form-group.dropdown.compare-form-group.to.js-compare-to-dropdown
.input-group.inline-input-group
%span.input-group-prepend
.input-group-text
= s_("CompareBranches|Source")
= hidden_field_tag :to, params[:to]
- = button_tag type: 'button', title: params[:to], class: "btn form-control compare-dropdown-toggle js-compare-dropdown has-tooltip", required: true, data: { refs_url: refs_project_path(@project), toggle: "dropdown", target: ".js-compare-to-dropdown", selected: params[:to], field_name: :to } do
+ = button_tag type: 'button', title: params[:to], class: "btn gl-button form-control compare-dropdown-toggle js-compare-dropdown has-tooltip", required: true, data: { refs_url: refs_project_path(@project), toggle: "dropdown", target: ".js-compare-to-dropdown", selected: params[:to], field_name: :to } do
.dropdown-toggle-text.str-truncated.monospace.float-left= params[:to] || _("Select branch/tag")
= sprite_icon('chevron-down', css_class: 'float-right')
= render 'shared/ref_dropdown'
@@ -19,12 +19,12 @@
.input-group-text
= s_("CompareBranches|Target")
= hidden_field_tag :from, params[:from]
- = button_tag type: 'button', title: params[:from], class: "btn form-control compare-dropdown-toggle js-compare-dropdown has-tooltip", required: true, data: { refs_url: refs_project_path(@project), toggle: "dropdown", target: ".js-compare-from-dropdown", selected: params[:from], field_name: :from } do
+ = button_tag type: 'button', title: params[:from], class: "btn gl-button form-control compare-dropdown-toggle js-compare-dropdown has-tooltip", required: true, data: { refs_url: refs_project_path(@project), toggle: "dropdown", target: ".js-compare-from-dropdown", selected: params[:from], field_name: :from } do
.dropdown-toggle-text.str-truncated.monospace.float-left= params[:from] || _("Select branch/tag")
= sprite_icon('chevron-down', css_class: 'float-right')
= render 'shared/ref_dropdown'
&nbsp;
- = button_tag s_("CompareBranches|Compare"), class: "btn btn-success commits-compare-btn"
+ = button_tag s_("CompareBranches|Compare"), class: "btn gl-button btn-success commits-compare-btn"
- if @merge_request.present?
= link_to _("View open merge request"), project_merge_request_path(@project, @merge_request), class: 'gl-ml-3 btn'
- elsif create_mr_button?
diff --git a/app/views/projects/confluences/show.html.haml b/app/views/projects/confluences/show.html.haml
index b87780db4cd..5814b7a00f5 100644
--- a/app/views/projects/confluences/show.html.haml
+++ b/app/views/projects/confluences/show.html.haml
@@ -1,5 +1,6 @@
- breadcrumb_title _('Confluence')
- page_title _('Confluence')
+- add_page_specific_style 'page_bundles/wiki'
= render layout: 'shared/empty_states/wikis_layout', locals: { image_path: 'illustrations/wiki_login_empty.svg' } do
%h4
= s_('WikiEmpty|Confluence is enabled')
diff --git a/app/views/projects/cycle_analytics/show.html.haml b/app/views/projects/cycle_analytics/show.html.haml
index d7e10efc3b1..d99579c25c0 100644
--- a/app/views/projects/cycle_analytics/show.html.haml
+++ b/app/views/projects/cycle_analytics/show.html.haml
@@ -1,4 +1,5 @@
- page_title _("Value Stream Analytics")
+- add_page_specific_style 'page_bundles/cycle_analytics'
#cycle-analytics{ "v-cloak" => "true", data: { request_path: project_cycle_analytics_path(@project) } }
- if @cycle_analytics_no_data
diff --git a/app/views/projects/default_branch/_show.html.haml b/app/views/projects/default_branch/_show.html.haml
index 46ee60949db..2ba12601c79 100644
--- a/app/views/projects/default_branch/_show.html.haml
+++ b/app/views/projects/default_branch/_show.html.haml
@@ -28,5 +28,4 @@
= _("Issues referenced by merge requests and commits within the default branch will be closed automatically")
= link_to sprite_icon('question-o'), help_page_path('user/project/issues/managing_issues.md', anchor: 'disabling-automatic-issue-closing'), target: '_blank'
- .gl-display-flex.gl-justify-content-end
- = f.submit _('Save changes'), class: "btn btn-success"
+ = f.submit _('Save changes'), class: "btn btn-success"
diff --git a/app/views/projects/deployments/_actions.haml b/app/views/projects/deployments/_actions.haml
index 5127d8b77d5..7f4b99f1a3f 100644
--- a/app/views/projects/deployments/_actions.haml
+++ b/app/views/projects/deployments/_actions.haml
@@ -3,7 +3,7 @@
- if actions.present?
.btn-group
.dropdown
- %button.dropdown.dropdown-new.btn.btn-default.has-tooltip{ type: 'button', 'data-toggle' => 'dropdown', title: s_('Environments|Deploy to...') }
+ %button.dropdown.dropdown-new.btn.gl-button.btn-default.has-tooltip{ type: 'button', 'data-toggle' => 'dropdown', title: s_('Environments|Deploy to...') }
= sprite_icon('play')
= icon('caret-down')
%ul.dropdown-menu.dropdown-menu-right
diff --git a/app/views/projects/deployments/_commit.html.haml b/app/views/projects/deployments/_commit.html.haml
index 743aa60b3ba..52e3e0fd997 100644
--- a/app/views/projects/deployments/_commit.html.haml
+++ b/app/views/projects/deployments/_commit.html.haml
@@ -1,7 +1,7 @@
.table-mobile-content
.branch-commit.cgray
- if deployment.ref
- %span.icon-container
+ %span.icon-container.gl-display-inline-block
= deployment.tag? ? icon('tag') : sprite_icon('fork', css_class: 'sprite')
= link_to deployment.ref, project_ref_path(@project, deployment.ref), class: "ref-name"
.icon-container.commit-icon
diff --git a/app/views/projects/deployments/_confirm_rollback_modal.html.haml b/app/views/projects/deployments/_confirm_rollback_modal.html.haml
index 3735ead1559..23729d6ebf9 100644
--- a/app/views/projects/deployments/_confirm_rollback_modal.html.haml
+++ b/app/views/projects/deployments/_confirm_rollback_modal.html.haml
@@ -15,8 +15,8 @@
%p
= s_('Environments|This action will run the job defined by %{environment_name} for commit %{commit_id}, putting the environment in a previous version. You can revert it by re-deploying the latest version of your application. Are you sure you want to continue?').html_safe % {commit_id: commit_sha, environment_name: @environment.name}
.modal-footer
- = button_tag _('Cancel'), type: 'button', class: 'btn btn-cancel', data: { dismiss: 'modal' }
- = link_to [:retry, @project, deployment.deployable], method: :post, class: 'btn btn-danger' do
+ = button_tag _('Cancel'), type: 'button', class: 'btn gl-button btn-danger', data: { dismiss: 'modal' }
+ = link_to [:retry, @project, deployment.deployable], method: :post, class: 'btn gl-button btn-danger' do
- if deployment.last?
= s_('Environments|Re-deploy')
- else
diff --git a/app/views/projects/deployments/_rollback.haml b/app/views/projects/deployments/_rollback.haml
index dffa5e4ba40..c5e884473ff 100644
--- a/app/views/projects/deployments/_rollback.haml
+++ b/app/views/projects/deployments/_rollback.haml
@@ -1,6 +1,6 @@
- if deployment.deployable && can?(current_user, :create_deployment, deployment)
- tooltip = deployment.last? ? s_('Environments|Re-deploy to environment') : s_('Environments|Rollback environment')
- = button_tag class: 'btn btn-default btn-build has-tooltip', type: 'button', data: { toggle: 'modal', target: "#confirm-rollback-modal-#{deployment.id}" }, title: tooltip do
+ = button_tag class: 'btn gl-button btn-default btn-build has-tooltip', type: 'button', data: { toggle: 'modal', target: "#confirm-rollback-modal-#{deployment.id}" }, title: tooltip do
- if deployment.last?
= sprite_icon('repeat')
- else
diff --git a/app/views/projects/diffs/_diffs.html.haml b/app/views/projects/diffs/_diffs.html.haml
index 6ba363e6555..43aaa7cb405 100644
--- a/app/views/projects/diffs/_diffs.html.haml
+++ b/app/views/projects/diffs/_diffs.html.haml
@@ -7,7 +7,7 @@
.content-block.oneline-block.files-changed.diff-files-changed.js-diff-files-changed
.files-changed-inner
- .inline-parallel-buttons.d-none.d-sm-none.d-md-block
+ .inline-parallel-buttons.d-none.d-md-block
- if !diffs_expanded? && diff_files.any? { |diff_file| diff_file.collapsed? }
= link_to _('Expand all'), url_for(safe_params.merge(expanded: 1, format: nil)), class: 'btn btn-default'
- if show_whitespace_toggle
diff --git a/app/views/projects/diffs/_file_header.html.haml b/app/views/projects/diffs/_file_header.html.haml
index f954b09abee..e9dfda4e927 100644
--- a/app/views/projects/diffs/_file_header.html.haml
+++ b/app/views/projects/diffs/_file_header.html.haml
@@ -6,7 +6,7 @@
- if diff_file.submodule?
- blob = diff_file.blob
%span
- = icon('archive fw')
+ = sprite_icon('archive')
%strong.file-title-name
= submodule_link(blob, diff_file.content_sha, diff_file.repository)
diff --git a/app/views/projects/diffs/_line.html.haml b/app/views/projects/diffs/_line.html.haml
index d35443cca1e..4d40071e07c 100644
--- a/app/views/projects/diffs/_line.html.haml
+++ b/app/views/projects/diffs/_line.html.haml
@@ -21,9 +21,6 @@
- else
= add_diff_note_button(line_code, diff_file.position(line), type)
%a{ href: "##{line_code}", data: { linenumber: link_text } }
- - discussion = line_discussions.try(:first)
- - if discussion && discussion.resolvable? && !plain
- %diff-note-avatars{ "discussion-id" => discussion.id }
%td.new_line.diff-line-num{ class: type, data: { linenumber: line.new_pos } }
- link_text = type == "old" ? " " : line.new_pos
- if plain
diff --git a/app/views/projects/diffs/_parallel_view.html.haml b/app/views/projects/diffs/_parallel_view.html.haml
index 9587ea4696b..ebe3aad064a 100644
--- a/app/views/projects/diffs/_parallel_view.html.haml
+++ b/app/views/projects/diffs/_parallel_view.html.haml
@@ -20,9 +20,6 @@
%td.old_line.diff-line-num.js-avatar-container{ class: left.type, data: { linenumber: left.old_pos } }
= add_diff_note_button(left_line_code, left_position, 'old')
%a{ href: "##{left_line_code}", data: { linenumber: left.old_pos } }
- - discussion_left = discussions_left.try(:first)
- - if discussion_left && discussion_left.resolvable?
- %diff-note-avatars{ "discussion-id" => discussion_left.id }
%td.line_content.parallel.left-side{ id: left_line_code, class: left.type }= diff_line_content(left.rich_text)
- else
%td.old_line.diff-line-num.empty-cell
@@ -41,9 +38,6 @@
%td.new_line.diff-line-num.js-avatar-container{ class: right.type, data: { linenumber: right.new_pos } }
= add_diff_note_button(right_line_code, right_position, 'new')
%a{ href: "##{right_line_code}", data: { linenumber: right.new_pos } }
- - discussion_right = discussions_right.try(:first)
- - if discussion_right && discussion_right.resolvable?
- %diff-note-avatars{ "discussion-id" => discussion_right.id }
%td.line_content.parallel.right-side{ id: right_line_code, class: right.type }= diff_line_content(right.rich_text)
- else
%td.old_line.diff-line-num.empty-cell
diff --git a/app/views/projects/diffs/_stats.html.haml b/app/views/projects/diffs/_stats.html.haml
index b438fbbf446..cee479aab0a 100644
--- a/app/views/projects/diffs/_stats.html.haml
+++ b/app/views/projects/diffs/_stats.html.haml
@@ -1,5 +1,5 @@
-- sum_added_lines = diff_files.sum(&:added_lines) # rubocop: disable CodeReuse/ActiveRecord
-- sum_removed_lines = diff_files.sum(&:removed_lines) # rubocop: disable CodeReuse/ActiveRecord
+- sum_added_lines = diff_files.sum(&:added_lines)
+- sum_removed_lines = diff_files.sum(&:removed_lines)
.commit-stat-summary.dropdown
Showing
%button.diff-stats-summary-toggler.js-diff-stats-dropdown{ type: "button", data: { toggle: "dropdown", display: "static" } }<
diff --git a/app/views/projects/diffs/_text_file.html.haml b/app/views/projects/diffs/_text_file.html.haml
index 641a0689c26..5a7830e306a 100644
--- a/app/views/projects/diffs/_text_file.html.haml
+++ b/app/views/projects/diffs/_text_file.html.haml
@@ -1,4 +1,4 @@
-- too_big = diff_file.diff_lines.count > Commit::DIFF_SAFE_LINES
+- too_big = diff_file.diff_lines.count > Commit.diff_safe_lines(project: @project)
- if too_big
.suppressed-container
%a.show-suppressed-diff.cursor-pointer.js-show-suppressed-diff= _("Changes suppressed. Click to show.")
diff --git a/app/views/projects/diffs/_warning.html.haml b/app/views/projects/diffs/_warning.html.haml
index 643d111fedd..30b0631b465 100644
--- a/app/views/projects/diffs/_warning.html.haml
+++ b/app/views/projects/diffs/_warning.html.haml
@@ -1,12 +1,15 @@
-.alert.alert-warning
- %h4
+.gl-alert.gl-alert-warning.gl-mb-5
+ %button.js-close.gl-alert-dismiss{ type: 'button', 'aria-label' => _('Dismiss') }
+ = sprite_icon('close', size: 16, css_class: 'gl-icon')
+ = sprite_icon('warning', size: 16, css_class: 'gl-icon gl-alert-icon')
+ %h4.gl-alert-title
= _("Too many changes to show.")
- .float-right
- - if current_controller?(:commit)
- = link_to _("Plain diff"), project_commit_path(@project, @commit, format: :diff), class: "btn btn-sm"
- = link_to _("Email patch"), project_commit_path(@project, @commit, format: :patch), class: "btn btn-sm"
- - elsif current_controller?('projects/merge_requests/diffs') && @merge_request&.persisted?
- = link_to _("Plain diff"), merge_request_path(@merge_request, format: :diff), class: "btn btn-sm"
- = link_to _("Email patch"), merge_request_path(@merge_request, format: :patch), class: "btn btn-sm"
- %p
+ .gl-alert-body
= html_escape(_("To preserve performance only %{strong_open}%{display_size} of %{real_size}%{strong_close} files are displayed.")) % { display_size: diff_files.size, real_size: diff_files.real_size, strong_open: '<strong>'.html_safe, strong_close: '</strong>'.html_safe }
+ .gl-alert-actions
+ - if current_controller?(:commit)
+ = link_to _("Plain diff"), project_commit_path(@project, @commit, format: :diff), class: "btn gl-alert-action btn-default gl-button btn-default-secondary"
+ = link_to _("Email patch"), project_commit_path(@project, @commit, format: :patch), class: "btn gl-alert-action btn-default gl-button btn-default-secondary"
+ - elsif current_controller?('projects/merge_requests/diffs') && @merge_request&.persisted?
+ = link_to _("Plain diff"), merge_request_path(@merge_request, format: :diff), class: "btn gl-alert-action btn-default gl-button btn-default-secondary"
+ = link_to _("Email patch"), merge_request_path(@merge_request, format: :patch), class: "btn gl-alert-action btn-default gl-button btn-default-secondary"
diff --git a/app/views/projects/edit.html.haml b/app/views/projects/edit.html.haml
index e5c4cfcbd72..63d571e718e 100644
--- a/app/views/projects/edit.html.haml
+++ b/app/views/projects/edit.html.haml
@@ -21,10 +21,9 @@
%input{ name: 'update_section', type: 'hidden', value: 'js-shared-permissions' }
%template.js-project-permissions-form-data{ type: "application/json" }= project_permissions_panel_data_json(@project)
.js-project-permissions-form
- .gl-display-flex.gl-justify-content-end
- - if show_visibility_confirm_modal?(@project)
- = render "visibility_modal"
- = f.submit _('Save changes'), class: "btn btn-success #{('js-confirm-danger' if show_visibility_confirm_modal?(@project))}", data: { qa_selector: 'visibility_features_permissions_save_button', check_field_name: ("project[visibility_level]" if show_visibility_confirm_modal?(@project)), check_compare_value: @project.visibility_level }
+ - if show_visibility_confirm_modal?(@project)
+ = render "visibility_modal"
+ = f.submit _('Save changes'), class: "btn btn-success #{('js-confirm-danger' if show_visibility_confirm_modal?(@project))}", data: { qa_selector: 'visibility_features_permissions_save_button', check_field_name: ("project[visibility_level]" if show_visibility_confirm_modal?(@project)), check_compare_value: @project.visibility_level }
%section.qa-merge-request-settings.rspec-merge-request-settings.settings.merge-requests-feature.no-animate#js-merge-request-settings{ class: [('expanded' if expanded), ('hidden' if @project.project_feature.send(:merge_requests_access_level) == 0)] }
.settings-header
@@ -38,8 +37,7 @@
= form_for @project, remote: true, html: { multipart: true, class: "merge-request-settings-form js-mr-settings-form" }, authenticity_token: true do |f|
%input{ name: 'update_section', type: 'hidden', value: 'js-merge-request-settings' }
= render 'projects/merge_request_settings', form: f
- .gl-display-flex.gl-justify-content-end
- = f.submit _('Save changes'), class: "btn btn-success qa-save-merge-request-changes rspec-save-merge-request-changes"
+ = f.submit _('Save changes'), class: "btn btn-succes qa-save-merge-request-changes rspec-save-merge-request-changes"
= render_if_exists 'projects/merge_request_approvals_settings', expanded: expanded
@@ -70,9 +68,8 @@
.sub-section
%h4= _('Housekeeping')
%p= _('Runs a number of housekeeping tasks within the current repository, such as compressing file revisions and removing unreachable objects.')
- .gl-display-flex.gl-justify-content-end
- = link_to _('Run housekeeping'), housekeeping_project_path(@project),
- method: :post, class: "btn btn-default"
+ = link_to _('Run housekeeping'), housekeeping_project_path(@project),
+ method: :post, class: "btn btn-default"
= render 'export', project: @project
@@ -94,8 +91,7 @@
%li= _('You will need to update your local repositories to point to the new location.')
- if @project.deployment_platform.present?
%li= _('Your deployment services will be broken, you will need to manually fix the services after renaming.')
- .gl-display-flex.gl-justify-content-end
- = f.submit _('Change path'), class: "btn btn-warning qa-change-path-button"
+ = f.submit _('Change path'), class: "btn btn-warning qa-change-path-button"
- if can?(current_user, :change_namespace, @project)
.sub-section
@@ -111,8 +107,7 @@
%li= _('You can only transfer the project to namespaces you manage.')
%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.')
- .gl-display-flex.gl-justify-content-end
- = f.submit 'Transfer project', class: "btn btn-remove js-confirm-danger qa-transfer-button", data: { "confirm-danger-message" => transfer_project_message(@project) }
+ = f.submit 'Transfer project', class: "gl-button btn btn-danger js-confirm-danger qa-transfer-button", data: { "confirm-danger-message" => transfer_project_message(@project) }
- if @project.forked? && can?(current_user, :remove_fork_project, @project)
.sub-section
@@ -122,7 +117,7 @@
= form_for @project, url: remove_fork_project_path(@project), method: :delete, remote: true, html: { class: 'transfer-project' } do |f|
%p
%strong= _('Once removed, the fork relationship cannot be restored and you will no longer be able to send merge requests to the source.')
- = button_to _('Remove fork relationship'), '#', class: "btn btn-remove js-confirm-danger", data: { "confirm-danger-message" => remove_fork_project_warning_message(@project) }
+ = button_to _('Remove fork relationship'), '#', class: "gl-button btn btn-danger js-confirm-danger", data: { "confirm-danger-message" => remove_fork_project_warning_message(@project) }
= render 'remove', project: @project
diff --git a/app/views/projects/empty.html.haml b/app/views/projects/empty.html.haml
index c9edc3c12ec..c6d39f5bba0 100644
--- a/app/views/projects/empty.html.haml
+++ b/app/views/projects/empty.html.haml
@@ -1,5 +1,5 @@
- @content_class = "limit-container-width" unless fluid_layout
-- default_branch_name = Gitlab::CurrentSettings.default_branch_name.presence || "master"
+- default_branch_name = @project.default_branch || "master"
- breadcrumb_title _("Details")
- page_title _("Details")
@@ -11,19 +11,19 @@
= _('The repository for this project is empty')
- if @project.can_current_user_push_code?
- %p.gl-mb-0
+ %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-clone-holder.d-block.d-md-none.mt-2.mr-2
= render "shared/mobile_clone_panel"
- .project-clone-holder.d-none.d-md-inline-block.mt-2.mr-2.float-left
+ .project-clone-holder.d-none.d-md-inline-block.mb-2.mr-2.float-left
= render "projects/buttons/clone"
- = render 'stat_anchor_list', anchors: @project.empty_repo_statistics_buttons
+ = render 'stat_anchor_list', anchors: @project.empty_repo_statistics_buttons, project_buttons: true
- if can?(current_user, :push_code, @project)
- .empty-wrapper.gl-mt-7
+ .empty-wrapper.gl-mt-4
%h3#repo-command-line-instructions.page-title-empty
= _('Command line instructions')
%p
diff --git a/app/views/projects/environments/edit.html.haml b/app/views/projects/environments/edit.html.haml
index 56af252d785..c4e2c1eb63d 100644
--- a/app/views/projects/environments/edit.html.haml
+++ b/app/views/projects/environments/edit.html.haml
@@ -1,4 +1,5 @@
- page_title _("Edit"), @environment.name, _("Environments")
+- add_page_specific_style 'page_bundles/environments'
%h3.page-title
= _('Edit environment')
diff --git a/app/views/projects/environments/folder.html.haml b/app/views/projects/environments/folder.html.haml
index 554cb4323f7..2b4d19a0e1d 100644
--- a/app/views/projects/environments/folder.html.haml
+++ b/app/views/projects/environments/folder.html.haml
@@ -1,5 +1,6 @@
- add_to_breadcrumbs _("Environments"), project_environments_path(@project)
- breadcrumb_title _("Folder/%{name}") % { name: @folder }
- page_title _("Environments in %{name}") % { name: @folder }
+- add_page_specific_style 'page_bundles/environments'
#environments-folder-list-view{ data: { environments_data: environments_folder_list_view_data, project_path: @project.full_path } }
diff --git a/app/views/projects/environments/index.html.haml b/app/views/projects/environments/index.html.haml
index 9abc1a5a925..067c987e721 100644
--- a/app/views/projects/environments/index.html.haml
+++ b/app/views/projects/environments/index.html.haml
@@ -1,4 +1,5 @@
- page_title _("Environments")
+- add_page_specific_style 'page_bundles/environments'
#environments-list-view{ data: { environments_data: environments_list_data,
"can-read-environment" => can?(current_user, :read_environment, @project).to_s,
diff --git a/app/views/projects/environments/new.html.haml b/app/views/projects/environments/new.html.haml
index 96edd3f0bd7..6b0ccc1dcc7 100644
--- a/app/views/projects/environments/new.html.haml
+++ b/app/views/projects/environments/new.html.haml
@@ -1,5 +1,6 @@
- breadcrumb_title _("Environments")
- page_title _("New Environment")
+- add_page_specific_style 'page_bundles/environments'
%h3.page-title
= _("New environment")
diff --git a/app/views/projects/environments/show.html.haml b/app/views/projects/environments/show.html.haml
index 929015023d2..5b1556c9f52 100644
--- a/app/views/projects/environments/show.html.haml
+++ b/app/views/projects/environments/show.html.haml
@@ -1,9 +1,8 @@
- add_to_breadcrumbs _("Environments"), project_environments_path(@project)
- breadcrumb_title @environment.name
- page_title _("Environments")
-
-- content_for :page_specific_javascripts do
- = stylesheet_link_tag 'page_bundles/xterm'
+- add_page_specific_style 'page_bundles/xterm'
+- add_page_specific_style 'page_bundles/environments'
#environments-detail-view{ data: { name: @environment.name, id: @environment.id, delete_path: environment_delete_path(@environment)} }
- if @environment.available? && can?(current_user, :stop_environment, @environment)
@@ -67,7 +66,7 @@
%p.blank-state-text
= html_escape(_("Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%{code_close} to track deployments here.")) % { code_open: '<code>'.html_safe, code_close: '</code>'.html_safe }
.text-center
- = link_to _("Read more"), help_page_path("ci/environments"), class: "btn btn-success"
+ = link_to _("Read more"), help_page_path("ci/environments/index.md"), class: "btn btn-success"
- else
.table-holder.gl-overflow-visible
.ci-table.environments{ role: 'grid' }
diff --git a/app/views/projects/environments/terminal.html.haml b/app/views/projects/environments/terminal.html.haml
index 3a705d736f3..ed0bc0680d7 100644
--- a/app/views/projects/environments/terminal.html.haml
+++ b/app/views/projects/environments/terminal.html.haml
@@ -1,5 +1,5 @@
- page_title _("Terminal for environment"), @environment.name
-
+- add_page_specific_style 'page_bundles/terminal'
- content_for :page_specific_javascripts do
= stylesheet_link_tag "xterm.css"
@@ -18,4 +18,4 @@
= render 'projects/deployments/actions', deployment: @environment.last_deployment
.terminal-container{ class: container_class }
- #terminal{ data: { project_path: "#{terminal_project_environment_path(@project, @environment)}.ws" } }
+ #terminal.gl-mt-4{ data: { project_path: "#{terminal_project_environment_path(@project, @environment)}.ws" } }
diff --git a/app/views/projects/error_tracking/details.html.haml b/app/views/projects/error_tracking/details.html.haml
index 7015dcdcb05..4a14e34cbf1 100644
--- a/app/views/projects/error_tracking/details.html.haml
+++ b/app/views/projects/error_tracking/details.html.haml
@@ -1,4 +1,5 @@
- page_title _('Error Details')
- add_to_breadcrumbs 'Errors', project_error_tracking_index_path(@project)
+- add_page_specific_style 'page_bundles/error_tracking_details'
#js-error_details{ data: error_details_data(@project, @issue_id) }
diff --git a/app/views/projects/error_tracking/index.html.haml b/app/views/projects/error_tracking/index.html.haml
index 96f61584a99..ffe0785d327 100644
--- a/app/views/projects/error_tracking/index.html.haml
+++ b/app/views/projects/error_tracking/index.html.haml
@@ -1,3 +1,4 @@
- page_title _('Errors')
+- add_page_specific_style 'page_bundles/error_tracking_index'
#js-error_tracking{ data: error_tracking_data(@current_user, @project) }
diff --git a/app/views/projects/feature_flags/_errors.html.haml b/app/views/projects/feature_flags/_errors.html.haml
deleted file mode 100644
index a32245640be..00000000000
--- a/app/views/projects/feature_flags/_errors.html.haml
+++ /dev/null
@@ -1,4 +0,0 @@
-#error_explanation
- .alert.alert-danger
- - @feature_flag.errors.full_messages.each do |message|
- %p= message
diff --git a/app/views/projects/feature_flags/edit.html.haml b/app/views/projects/feature_flags/edit.html.haml
index 4de41ca4080..028595aba0b 100644
--- a/app/views/projects/feature_flags/edit.html.haml
+++ b/app/views/projects/feature_flags/edit.html.haml
@@ -1,4 +1,4 @@
-- @gfm_form = Feature.enabled?(:feature_flags_issue_links, @project, default_enabled: true)
+- @gfm_form = true
- add_to_breadcrumbs s_('FeatureFlags|Feature Flags'), project_feature_flags_path(@project)
- breadcrumb_title @feature_flag.name
@@ -9,7 +9,7 @@
feature_flags_path: project_feature_flags_path(@project),
environments_endpoint: search_project_environments_path(@project, format: :json),
user_callouts_path: user_callouts_path,
- user_callout_id: UserCalloutsHelper::FEATURE_FLAGS_NEW_VERISION,
+ user_callout_id: UserCalloutsHelper::FEATURE_FLAGS_NEW_VERSION,
show_user_callout: show_feature_flags_new_version?.to_s,
strategy_type_docs_page_path: help_page_path('operations/feature_flags', anchor: 'feature-flag-strategies'),
environments_scope_docs_path: help_page_path('ci/environments', anchor: 'scoping-environments-with-specs'),
diff --git a/app/views/projects/feature_flags/index.html.haml b/app/views/projects/feature_flags/index.html.haml
index f425de91d12..7d48cba74d0 100644
--- a/app/views/projects/feature_flags/index.html.haml
+++ b/app/views/projects/feature_flags/index.html.haml
@@ -7,6 +7,8 @@
"feature-flags-help-page-path" => help_page_path("operations/feature_flags"),
"feature-flags-client-libraries-help-page-path" => help_page_path("operations/feature_flags", anchor: "choose-a-client-library"),
"feature-flags-client-example-help-page-path" => help_page_path("operations/feature_flags", anchor: "golang-application-example"),
+ "feature-flags-limit-exceeded" => @project.actual_limits.exceeded?(:project_feature_flags, @project.operations_feature_flags.count),
+ "feature-flags-limit" => @project.actual_limits.project_feature_flags,
"unleash-api-url" => (unleash_api_url(@project) if can?(current_user, :admin_feature_flag, @project)),
"unleash-api-instance-id" => (unleash_api_instance_id(@project) if can?(current_user, :admin_feature_flag, @project)),
"can-user-admin-feature-flag" => can?(current_user, :admin_feature_flag, @project),
diff --git a/app/views/projects/feature_flags/new.html.haml b/app/views/projects/feature_flags/new.html.haml
index a7388361da5..3bad1d9773c 100644
--- a/app/views/projects/feature_flags/new.html.haml
+++ b/app/views/projects/feature_flags/new.html.haml
@@ -7,7 +7,7 @@
feature_flags_path: project_feature_flags_path(@project),
environments_endpoint: search_project_environments_path(@project, format: :json),
user_callouts_path: user_callouts_path,
- user_callout_id: UserCalloutsHelper::FEATURE_FLAGS_NEW_VERISION,
+ user_callout_id: UserCalloutsHelper::FEATURE_FLAGS_NEW_VERSION,
show_user_callout: show_feature_flags_new_version?.to_s,
strategy_type_docs_page_path: help_page_path('operations/feature_flags', anchor: 'feature-flag-strategies'),
environments_scope_docs_path: help_page_path('ci/environments', anchor: 'scoping-environments-with-specs'),
diff --git a/app/views/projects/forks/_fork_button.html.haml b/app/views/projects/forks/_fork_button.html.haml
index dd49e8bdb4b..cfef2a19420 100644
--- a/app/views/projects/forks/_fork_button.html.haml
+++ b/app/views/projects/forks/_fork_button.html.haml
@@ -10,11 +10,11 @@
%h5.gl-mt-3
= namespace.human_name
- if forked_project = namespace.find_fork_of(@project)
- = link_to _("Go to project"), project_path(forked_project), class: "btn"
+ = link_to _("Go to project"), project_path(forked_project), class: "btn gl-button btn-default"
- else
%div{ class: ('has-tooltip' unless can_create_project),
title: (_('You have reached your project limit') unless can_create_project) }
= link_to _("Select"), project_forks_path(@project, namespace_key: namespace.id),
data: { qa_selector: 'fork_namespace_button', qa_name: namespace.human_name },
method: "POST",
- class: ["btn btn-success", ("disabled" unless can_create_project)]
+ class: ["btn gl-button btn-success", ("disabled" unless can_create_project)]
diff --git a/app/views/projects/forks/index.html.haml b/app/views/projects/forks/index.html.haml
index 8384561891a..67dc07fb785 100644
--- a/app/views/projects/forks/index.html.haml
+++ b/app/views/projects/forks/index.html.haml
@@ -30,11 +30,11 @@
- if current_user && can?(current_user, :fork_project, @project)
- if current_user.already_forked?(@project) && current_user.manageable_namespaces.size < 2
- = link_to namespace_project_path(current_user, current_user.fork_of(@project)), title: _('Go to your fork'), class: 'btn btn-success' do
+ = link_to namespace_project_path(current_user, current_user.fork_of(@project)), title: _('Go to your fork'), class: 'btn gl-button btn-success' do
= sprite_icon('fork', size: 12)
%span= _('Fork')
- else
- = link_to new_project_fork_path(@project), title: _("Fork project"), class: 'btn btn-success' do
+ = link_to new_project_fork_path(@project), title: _("Fork project"), class: 'btn gl-button btn-success' do
= sprite_icon('fork', size: 12)
%span= _('Fork')
diff --git a/app/views/projects/generic_commit_statuses/_generic_commit_status.html.haml b/app/views/projects/generic_commit_statuses/_generic_commit_status.html.haml
index 1118b44d7a2..e341831e17d 100644
--- a/app/views/projects/generic_commit_statuses/_generic_commit_status.html.haml
+++ b/app/views/projects/generic_commit_statuses/_generic_commit_status.html.haml
@@ -75,7 +75,7 @@
- if generic_commit_status.finished_at
%p.finished-at
- = icon("calendar")
+ = sprite_icon("calendar")
%span= time_ago_with_tooltip(generic_commit_status.finished_at)
%td.coverage
diff --git a/app/views/projects/group_links/update.js.haml b/app/views/projects/group_links/update.js.haml
deleted file mode 100644
index 55520fda494..00000000000
--- a/app/views/projects/group_links/update.js.haml
+++ /dev/null
@@ -1,4 +0,0 @@
-:plain
- var $listItem = $('#{escape_javascript(render('shared/members/group', group_link: @group_link))}');
- $("#group_member_#{@group_link.id} .list-item-name").replaceWith($listItem.find('.list-item-name'));
- gl.utils.localTimeAgo($('.js-timeago'), $("#group_member_#{@group_link.id}"));
diff --git a/app/views/projects/hook_logs/show.html.haml b/app/views/projects/hook_logs/show.html.haml
index 8a8c396a9e4..ebe179c3454 100644
--- a/app/views/projects/hook_logs/show.html.haml
+++ b/app/views/projects/hook_logs/show.html.haml
@@ -7,6 +7,6 @@
%h4.gl-mt-0
Request details
.col-lg-9
- = link_to 'Resend Request', @hook_log.present.retry_path, method: :post, class: "btn btn-default float-right gl-ml-3"
+ = link_to 'Resend Request', @hook_log.present.retry_path, method: :post, class: "btn gl-button btn-default float-right gl-ml-3"
= render partial: 'shared/hook_logs/content', locals: { hook_log: @hook_log }
diff --git a/app/views/projects/hooks/edit.html.haml b/app/views/projects/hooks/edit.html.haml
index f728ef5ac1a..fb19b251d41 100644
--- a/app/views/projects/hooks/edit.html.haml
+++ b/app/views/projects/hooks/edit.html.haml
@@ -10,9 +10,9 @@
= form_for [@project, @hook], as: :hook, url: project_hook_path(@project, @hook) do |f|
= render partial: 'shared/web_hooks/form', locals: { form: f, hook: @hook }
- %span>= f.submit 'Save changes', class: 'btn btn-success gl-mr-3'
+ = f.submit 'Save changes', class: 'btn gl-button btn-success gl-mr-3'
= render 'shared/web_hooks/test_button', hook: @hook
- = link_to _('Delete'), project_hook_path(@project, @hook), method: :delete, class: 'btn btn-remove float-right', data: { confirm: _('Are you sure?') }
+ = link_to _('Delete'), project_hook_path(@project, @hook), method: :delete, class: 'btn gl-button btn-danger float-right', data: { confirm: _('Are you sure?') }
%hr
diff --git a/app/views/projects/hooks/index.html.haml b/app/views/projects/hooks/index.html.haml
index 5c6a87ddb26..e40c36da29d 100644
--- a/app/views/projects/hooks/index.html.haml
+++ b/app/views/projects/hooks/index.html.haml
@@ -9,7 +9,6 @@
.col-lg-8.gl-mb-3
= form_for @hook, as: :hook, url: polymorphic_path([@project, :hooks]) do |f|
= render partial: 'shared/web_hooks/form', locals: { form: f, hook: @hook }
- .gl-display-flex.gl-justify-content-end
- = f.submit 'Add webhook', class: 'btn btn-success'
+ = f.submit 'Add webhook', class: 'btn btn-success'
= render 'shared/web_hooks/index', hooks: @hooks, hook_class: @hook.class
diff --git a/app/views/projects/incidents/_new_branch.html.haml b/app/views/projects/incidents/_new_branch.html.haml
new file mode 100644
index 00000000000..f250fbc4b8b
--- /dev/null
+++ b/app/views/projects/incidents/_new_branch.html.haml
@@ -0,0 +1 @@
+= render 'projects/issues/new_branch'
diff --git a/app/views/projects/incidents/index.html.haml b/app/views/projects/incidents/index.html.haml
index 3d66c254601..a89e93618bc 100644
--- a/app/views/projects/incidents/index.html.haml
+++ b/app/views/projects/incidents/index.html.haml
@@ -1,3 +1,3 @@
- page_title _('Incidents')
-#js-incidents{ data: incidents_data(@project) }
+#js-incidents{ data: incidents_data(@project, params) }
diff --git a/app/views/projects/incidents/show.html.haml b/app/views/projects/incidents/show.html.haml
new file mode 100644
index 00000000000..b0ddc85df5d
--- /dev/null
+++ b/app/views/projects/incidents/show.html.haml
@@ -0,0 +1 @@
+= render template: 'projects/issues/show'
diff --git a/app/views/projects/issues/_discussion.html.haml b/app/views/projects/issues/_discussion.html.haml
index 4273130bbc2..e1f1d8bb8f7 100644
--- a/app/views/projects/issues/_discussion.html.haml
+++ b/app/views/projects/issues/_discussion.html.haml
@@ -1,4 +1,5 @@
- add_page_startup_api_call discussions_path(@issue)
+- add_page_startup_api_call notes_url
- @gfm_form = true
diff --git a/app/views/projects/issues/_issue.html.haml b/app/views/projects/issues/_issue.html.haml
index ba9ab50cb3a..4f188ae273c 100644
--- a/app/views/projects/issues/_issue.html.haml
+++ b/app/views/projects/issues/_issue.html.haml
@@ -35,7 +35,7 @@
- if issue.due_date
%span.issuable-due-date.d-none.d-sm-inline-block.has-tooltip{ class: "#{'cred' if issue.overdue?}", title: _('Due date') }
&nbsp;
- = icon('calendar')
+ = sprite_icon('calendar')
= issue.due_date.to_s(:medium)
- if issue.labels.any?
&nbsp;
@@ -54,7 +54,7 @@
%li.issuable-status
= _('CLOSED')
- if issue.assignees.any?
- %li
+ %li.gl-display-flex
= render 'shared/issuable/assignees', project: @project, issuable: issue
= render 'shared/issuable_meta_data', issuable: issue
diff --git a/app/views/projects/issues/_issues.html.haml b/app/views/projects/issues/_issues.html.haml
index 1a557cce33c..fa08c39e407 100644
--- a/app/views/projects/issues/_issues.html.haml
+++ b/app/views/projects/issues/_issues.html.haml
@@ -4,12 +4,14 @@
- data_endpoint = local_assigns.fetch(:data_endpoint, expose_path(api_v4_projects_issues_path(id: @project.id)))
- default_empty_state_meta = { create_issue_path: new_project_issue_path(@project), svg_path: image_path('illustrations/issues.svg') }
- data_empty_state_meta = local_assigns.fetch(:data_empty_state_meta, default_empty_state_meta)
- - type = local_assigns.fetch(:type, '')
+ - type = local_assigns.fetch(:type, 'issues')
+ - if type == 'issues' && use_startup_call?
+ - add_page_startup_api_call(api_v4_projects_issues_path(id: @project.id, params: startup_call_params))
.js-issuables-list{ data: { endpoint: data_endpoint,
'empty-state-meta': data_empty_state_meta.to_json,
'can-bulk-edit': @can_bulk_update.to_json,
'sort-key': @sort,
- 'type': type } }
+ type: type } }
- else
- empty_state_path = local_assigns.fetch(:empty_state_path, 'shared/empty_states/issues')
%ul.content-list.issues-list.issuable-list{ class: ("manual-ordering" if @sort == 'relative_position') }
@@ -18,4 +20,4 @@
= render empty_state_path
- if @issues.present?
- = paginate @issues, theme: "gitlab", total_pages: @total_pages
+ = paginate_collection @issues, total_pages: @total_pages
diff --git a/app/views/projects/issues/_new_branch.html.haml b/app/views/projects/issues/_new_branch.html.haml
index 9bbab925f6a..aa95cecb5fe 100644
--- a/app/views/projects/issues/_new_branch.html.haml
+++ b/app/views/projects/issues/_new_branch.html.haml
@@ -43,7 +43,7 @@
%li.droplab-item-ignore.gl-ml-3.gl-mr-3.gl-mt-5
- if can_create_confidential_merge_request?
- #js-forked-project{ data: { namespace_path: @project.namespace.full_path, project_path: @project.full_path, new_fork_path: new_project_fork_path(@project), help_page_path: help_page_path('user/project/merge_requests') } }
+ #js-forked-project{ data: { namespace_path: @project.namespace.full_path, project_path: @project.full_path, new_fork_path: new_project_fork_path(@project), help_page_path: help_page_path('user/project/merge_requests/index.md') } }
.form-group
%label{ for: 'new-branch-name' }
= _('Branch name')
diff --git a/app/views/projects/issues/export_csv/_button.html.haml b/app/views/projects/issues/export_csv/_button.html.haml
index ef3fb438641..e5710fcdb60 100644
--- a/app/views/projects/issues/export_csv/_button.html.haml
+++ b/app/views/projects/issues/export_csv/_button.html.haml
@@ -1,4 +1,4 @@
- if current_user
- %button.csv_download_link.btn.has-tooltip{ title: _('Export as CSV'),
+ %button.csv_download_link.btn.gl-button.has-tooltip{ title: _('Export as CSV'),
data: { toggle: 'modal', target: '.issues-export-modal', qa_selector: 'export_as_csv_button' } }
= sprite_icon('export')
diff --git a/app/views/projects/issues/export_csv/_modal.html.haml b/app/views/projects/issues/export_csv/_modal.html.haml
index 793e43da935..6610af63445 100644
--- a/app/views/projects/issues/export_csv/_modal.html.haml
+++ b/app/views/projects/issues/export_csv/_modal.html.haml
@@ -10,12 +10,13 @@
%a.close{ href: '#', 'data-dismiss' => 'modal' }
= sprite_icon('close', css_class: 'gl-icon')
.modal-body
- .modal-subheader
- = icon('check', { class: 'checkmark' })
- %strong.gl-ml-3
- - issues_count = issuables_count_for_state(:issues, params[:state])
- = n_('%d issue selected', '%d issues selected', issues_count) % issues_count
+ - issues_count = issuables_count_for_state(:issues, params[:state])
+ - unless issues_count == -1 # The count timed out
+ .modal-subheader
+ = icon('check', { class: 'checkmark' })
+ %strong.gl-ml-3
+ = n_('%d issue selected', '%d issues selected', issues_count) % issues_count
.modal-text
= html_escape(_('The CSV export will be created in the background. Once finished, it will be sent to %{strong_open}%{email}%{strong_close} in an attachment.')) % { email: @current_user.notification_email, strong_open: '<strong>'.html_safe, strong_close: '</strong>'.html_safe }
.modal-footer
- = link_to _('Export issues'), export_csv_project_issues_path(@project, request.query_parameters), method: :post, class: 'btn btn-success float-left', title: _('Export issues'), data: { track_label: "export_issues_csv", track_event: "click_button", track_value: "", qa_selector: "export_issues_button" }
+ = link_to _('Export issues'), export_csv_project_issues_path(@project, request.query_parameters), method: :post, class: 'btn gl-button btn-success float-left', title: _('Export issues'), data: { track_label: "export_issues_csv", track_event: "click_button", track_value: "", qa_selector: "export_issues_button" }
diff --git a/app/views/projects/issues/index.html.haml b/app/views/projects/issues/index.html.haml
index cfc423da57a..842b3432991 100644
--- a/app/views/projects/issues/index.html.haml
+++ b/app/views/projects/issues/index.html.haml
@@ -2,6 +2,7 @@
- page_title _("Issues")
- new_issue_email = @project.new_issuable_address(current_user, 'issue')
+- add_page_specific_style 'page_bundles/issues_list'
= content_for :meta_tags do
= auto_discovery_link_tag(:atom, safe_params.merge(rss_url_options).to_h, title: "#{@project.name} issues")
diff --git a/app/views/projects/issues/service_desk.html.haml b/app/views/projects/issues/service_desk.html.haml
index 65580a94cd0..b0d8791c566 100644
--- a/app/views/projects/issues/service_desk.html.haml
+++ b/app/views/projects/issues/service_desk.html.haml
@@ -1,7 +1,7 @@
- @can_bulk_update = false
- page_title _("Service Desk")
-
+- add_page_specific_style 'page_bundles/issues_list'
- content_for :breadcrumbs_extra do
= render "projects/issues/nav_btns", show_export_button: false, show_rss_button: false
diff --git a/app/views/projects/issues/show.html.haml b/app/views/projects/issues/show.html.haml
index c762b044c3e..7785093466b 100644
--- a/app/views/projects/issues/show.html.haml
+++ b/app/views/projects/issues/show.html.haml
@@ -2,8 +2,12 @@
- add_to_breadcrumbs _("Issues"), project_issues_path(@project)
- breadcrumb_title @issue.to_reference
- page_title "#{@issue.title} (#{@issue.to_reference})", _("Issues")
-- page_description @issue.description
+- page_description @issue.description_html
- page_card_attributes @issue.card_attributes
+- if @issue.relocation_target
+ - page_canonical_link @issue.relocation_target.present(current_user: current_user).web_url
+- if @issue.sentry_issue.present?
+ - add_page_specific_style 'page_bundles/error_tracking_details'
- can_update_issue = can?(current_user, :update_issue, @issue)
- can_reopen_issue = can?(current_user, :reopen_issue, @issue)
@@ -61,15 +65,12 @@
.issue-details.issuable-details
.detail-page-description.content-block
- -# haml-lint:disable InlineJavaScript
- %script#js-issuable-app-initial-data{ type: "application/json" }= issuable_initial_data(@issue).to_json
- #js-issuable-app
+ #js-issuable-app{ data: { initial: issuable_initial_data(@issue).to_json} }
.title-container
%h2.title= markdown_field(@issue, :title)
- if @issue.description.present?
- .description{ class: can?(current_user, :update_issue, @issue) ? 'js-task-list-container' : '' }
+ .description
.md= markdown_field(@issue, :description)
- %textarea.hidden.js-task-list-field= @issue.description
= edited_time_ago_with_tooltip(@issue, placement: 'bottom', html_class: 'issue-edited-ago js-issue-edited-ago')
@@ -92,6 +93,7 @@
.js-noteable-awards
= render 'award_emoji/awards_block', awardable: @issue, inline: true
.new-branch-col
+ = render_if_exists "projects/issues/timeline_toggle", issue: @issue
#js-vue-sort-issue-discussions
#js-vue-discussion-filter{ data: { default_filter: current_user&.notes_filter_for(@issue), notes_filters: UserPreference.notes_filters.to_json } }
= render 'new_branch' if show_new_branch_button?
diff --git a/app/views/projects/jobs/show.html.haml b/app/views/projects/jobs/show.html.haml
index df98a1c7cce..d7a778088ee 100644
--- a/app/views/projects/jobs/show.html.haml
+++ b/app/views/projects/jobs/show.html.haml
@@ -1,9 +1,7 @@
- add_to_breadcrumbs _("Jobs"), project_jobs_path(@project)
- breadcrumb_title "##{@build.id}"
- page_title "#{@build.name} (##{@build.id})", _("Jobs")
-
-- content_for :page_specific_javascripts do
- = stylesheet_link_tag 'page_bundles/xterm'
+- add_page_specific_style 'page_bundles/xterm'
= render_if_exists "shared/shared_runners_minutes_limit_flash_message"
diff --git a/app/views/projects/jobs/terminal.html.haml b/app/views/projects/jobs/terminal.html.haml
index 01f40543926..95acbcae6d9 100644
--- a/app/views/projects/jobs/terminal.html.haml
+++ b/app/views/projects/jobs/terminal.html.haml
@@ -2,9 +2,10 @@
- add_to_breadcrumbs "##{@build.id}", project_job_path(@project, @build)
- breadcrumb_title _('Terminal')
- page_title _('Terminal'), "#{@build.name} (##{@build.id})", _('Jobs')
-
+- add_page_specific_style 'page_bundles/terminal'
- content_for :page_specific_javascripts do
= stylesheet_link_tag "xterm.css"
+
.terminal-container
- #terminal{ data: { project_path: terminal_project_job_path(@project, @build, format: :ws) } }
+ #terminal.gl-mt-4{ data: { project_path: terminal_project_job_path(@project, @build, format: :ws) } }
diff --git a/app/views/projects/labels/index.html.haml b/app/views/projects/labels/index.html.haml
index 8d8270847a3..2699192adc9 100644
--- a/app/views/projects/labels/index.html.haml
+++ b/app/views/projects/labels/index.html.haml
@@ -52,5 +52,5 @@
= render 'shared/empty_states/labels'
%template#js-badge-item-template
- %li.label-link-item.js-priority-badge.inline.gl-ml-3
- .label-badge.label-badge-blue= _('Prioritized label')
+ %li.js-priority-badge.inline.gl-ml-3
+ .label-badge.gl-bg-blue-50= _('Prioritized label')
diff --git a/app/views/projects/merge_requests/_description.html.haml b/app/views/projects/merge_requests/_description.html.haml
index 354a384b647..c20479662dd 100644
--- a/app/views/projects/merge_requests/_description.html.haml
+++ b/app/views/projects/merge_requests/_description.html.haml
@@ -3,7 +3,6 @@
.description.qa-description{ class: can?(current_user, :update_merge_request, @merge_request) ? 'js-task-list-container' : '' }
.md
= markdown_field(@merge_request, :description)
- %textarea.hidden.js-task-list-field
- = @merge_request.description
+ %textarea.hidden.js-task-list-field{ data: { value: @merge_request.description } }
= edited_time_ago_with_tooltip(@merge_request, placement: 'bottom')
diff --git a/app/views/projects/merge_requests/_discussion.html.haml b/app/views/projects/merge_requests/_discussion.html.haml
deleted file mode 100644
index ecb51aca847..00000000000
--- a/app/views/projects/merge_requests/_discussion.html.haml
+++ /dev/null
@@ -1,11 +0,0 @@
-- content_for :note_actions do
- - if can?(current_user, :update_merge_request, @merge_request)
- - if @merge_request.open?
- = link_to 'Close merge request', merge_request_path(@merge_request, merge_request: { state_event: :close }), method: :put, class: "btn btn-nr btn-comment btn-close close-mr-link js-note-target-close", title: "Close merge request", data: { original_text: "Close merge request", alternative_text: "Comment & close merge request"}
- - if @merge_request.reopenable?
- = link_to 'Reopen merge request', merge_request_path(@merge_request, merge_request: { state_event: :reopen }), method: :put, class: "btn btn-nr btn-comment btn-reopen reopen-mr-link js-note-target-close js-note-target-reopen", title: "Reopen merge request", data: { original_text: "Reopen merge request", alternative_text: "Comment & reopen merge request"}
- %comment-and-resolve-btn{ "inline-template" => true }
- %button.btn.btn-nr.btn-default.gl-mr-3.js-comment-resolve-button{ "v-if" => "showButton", type: "submit", data: { project_path: "#{project_path(@merge_request.project)}" } }
- {{ buttonText }}
-
-#notes= render "shared/notes/notes_with_form", :autocomplete => true
diff --git a/app/views/projects/merge_requests/_merge_request.html.haml b/app/views/projects/merge_requests/_merge_request.html.haml
index ad0f4d03f9a..092055a5f85 100644
--- a/app/views/projects/merge_requests/_merge_request.html.haml
+++ b/app/views/projects/merge_requests/_merge_request.html.haml
@@ -53,8 +53,11 @@
= link_to merge_request_path(merge_request), class: "has-tooltip", title: _('Cannot be merged automatically') do
= sprite_icon('warning-solid')
- if merge_request.assignees.any?
- %li.d-flex
+ %li.gl-display-flex.gl-align-items-center
= render 'shared/issuable/assignees', project: merge_request.project, issuable: merge_request
+ - if Feature.enabled?(:merge_request_reviewers, @project) && merge_request.reviewers.any?
+ %li.gl-display-flex.issuable-reviewers
+ = render 'shared/issuable/reviewers', project: merge_request.project, issuable: merge_request
= render 'projects/merge_requests/approvals_count', merge_request: merge_request
= render 'shared/issuable_meta_data', issuable: merge_request
diff --git a/app/views/projects/merge_requests/_merge_requests.html.haml b/app/views/projects/merge_requests/_merge_requests.html.haml
index 57fbd360d46..e2123e36e67 100644
--- a/app/views/projects/merge_requests/_merge_requests.html.haml
+++ b/app/views/projects/merge_requests/_merge_requests.html.haml
@@ -5,4 +5,4 @@
= render 'shared/empty_states/merge_requests'
- if @merge_requests.present?
- = paginate @merge_requests, theme: "gitlab", total_pages: @total_pages
+ = paginate_collection @merge_requests, total_pages: @total_pages
diff --git a/app/views/projects/merge_requests/_mr_title.html.haml b/app/views/projects/merge_requests/_mr_title.html.haml
index 454a0694355..b56e2c3f985 100644
--- a/app/views/projects/merge_requests/_mr_title.html.haml
+++ b/app/views/projects/merge_requests/_mr_title.html.haml
@@ -32,16 +32,19 @@
%ul
- if can_update_merge_request
%li= link_to 'Edit', edit_namespace_project_merge_request_path(@project.namespace, @project, @merge_request)
- - unless current_user == @merge_request.author
- %li= link_to 'Report abuse', new_abuse_report_path(user_id: @merge_request.author.id, ref_url: merge_request_url(@merge_request))
- if can_update_merge_request
+ - unless @merge_request.closed?
+ %li
+ = link_to @merge_request.work_in_progress? ? _('Mark as ready') : _('Mark as draft'), toggle_draft_issuable_path(@merge_request), method: :put, class: "js-draft-toggle-button"
%li{ class: [merge_request_button_visibility(@merge_request, true), 'js-close-item'] }
= link_to 'Close', merge_request_path(@merge_request, merge_request: { state_event: :close }), method: :put, title: 'Close merge request'
- if can_reopen_merge_request
%li{ class: merge_request_button_visibility(@merge_request, false) }
= link_to 'Reopen', merge_request_path(@merge_request, merge_request: { state_event: :reopen }), method: :put, class: 'reopen-mr-link', title: 'Reopen merge request'
+ - unless current_user == @merge_request.author
+ %li= link_to 'Report abuse', new_abuse_report_path(user_id: @merge_request.author.id, ref_url: merge_request_url(@merge_request))
- if can_update_merge_request
- = link_to 'Edit', edit_project_merge_request_path(@project, @merge_request), class: "d-none d-sm-none d-md-block btn btn-grouped js-issuable-edit qa-edit-button"
+ = link_to 'Edit', edit_project_merge_request_path(@project, @merge_request), class: "d-none d-sm-none d-md-block btn gl-button btn-grouped js-issuable-edit qa-edit-button"
= render 'shared/issuable/close_reopen_button', issuable: @merge_request, can_update: can_update_merge_request, can_reopen: can_reopen_merge_request
diff --git a/app/views/projects/merge_requests/conflicts/show.html.haml b/app/views/projects/merge_requests/conflicts/show.html.haml
index 28ba2b6ac75..a7ffe825139 100644
--- a/app/views/projects/merge_requests/conflicts/show.html.haml
+++ b/app/views/projects/merge_requests/conflicts/show.html.haml
@@ -1,4 +1,5 @@
- page_title _("Merge Conflicts"), "#{@merge_request.title} (#{@merge_request.to_reference}", _("Merge Requests")
+- add_page_specific_style 'page_bundles/merge_conflicts'
- content_for :page_specific_javascripts do
= page_specific_javascript_tag('lib/ace.js')
= render "projects/merge_requests/mr_title"
diff --git a/app/views/projects/merge_requests/creations/new.html.haml b/app/views/projects/merge_requests/creations/new.html.haml
index ad4980fa57f..4c968c8e8eb 100644
--- a/app/views/projects/merge_requests/creations/new.html.haml
+++ b/app/views/projects/merge_requests/creations/new.html.haml
@@ -1,6 +1,7 @@
- add_to_breadcrumbs _("Merge Requests"), project_merge_requests_path(@project)
- breadcrumb_title _("New")
- page_title _("New Merge Request")
+- add_page_specific_style 'page_bundles/pipelines'
- if @merge_request.can_be_created && !params[:change_branches]
= render 'new_submit'
diff --git a/app/views/projects/merge_requests/diffs/_commit_widget.html.haml b/app/views/projects/merge_requests/diffs/_commit_widget.html.haml
deleted file mode 100644
index c022d2c70d8..00000000000
--- a/app/views/projects/merge_requests/diffs/_commit_widget.html.haml
+++ /dev/null
@@ -1,11 +0,0 @@
--#-----------------------------------------------------------------
- WARNING: Please keep changes up-to-date with the following files:
- - `assets/javascripts/diffs/components/commit_widget.vue`
--#-----------------------------------------------------------------
-- collapsible = local_assigns.fetch(:collapsible, true)
-
-- if @commit
- .info-well.mw-100.mx-0
- .well-segment
- %ul.blob-commit-info
- = render 'projects/commits/commit', commit: @commit, merge_request: @merge_request, view_details: true, collapsible: collapsible
diff --git a/app/views/projects/merge_requests/diffs/_different_base.html.haml b/app/views/projects/merge_requests/diffs/_different_base.html.haml
deleted file mode 100644
index 06a15b96653..00000000000
--- a/app/views/projects/merge_requests/diffs/_different_base.html.haml
+++ /dev/null
@@ -1,11 +0,0 @@
-- if @merge_request_diff && different_base?(@start_version, @merge_request_diff)
- .mr-version-controls
- .content-block
- = sprite_icon('information-o')
- Selected versions have different base commits.
- Changes will include
- = link_to project_compare_path(@project, from: @start_version.base_commit_sha, to: @merge_request_diff.base_commit_sha) do
- new commits
- from
- = succeed '.' do
- %code.ref-name= @merge_request.target_branch
diff --git a/app/views/projects/merge_requests/diffs/_diffs.html.haml b/app/views/projects/merge_requests/diffs/_diffs.html.haml
deleted file mode 100644
index 9ebd91dea0b..00000000000
--- a/app/views/projects/merge_requests/diffs/_diffs.html.haml
+++ /dev/null
@@ -1,21 +0,0 @@
-= render 'projects/merge_requests/diffs/version_controls'
-= render 'projects/merge_requests/diffs/different_base'
-= render 'projects/merge_requests/diffs/not_all_comments_displayed'
-= render 'projects/merge_requests/diffs/commit_widget'
-
-- if @merge_request_diff&.empty?
- .row.empty-state.nothing-here-block
- .col-12
- .svg-content= image_tag 'illustrations/merge_request_changes_empty.svg'
- .col-12
- .text-content.text-center
- %p
- No changes between
- %span.ref-name= @merge_request.source_branch
- and
- %span.ref-name= @merge_request.target_branch
- .text-center= link_to 'Create commit', project_new_blob_path(@project, @merge_request.source_branch), class: 'btn btn-success'
-- else
- - diff_viewable = @merge_request_diff ? @merge_request_diff.viewable? : true
- - if diff_viewable
- = render "projects/diffs/diffs", diffs: @diffs, environment: @environment, merge_request: true
diff --git a/app/views/projects/merge_requests/diffs/_not_all_comments_displayed.html.haml b/app/views/projects/merge_requests/diffs/_not_all_comments_displayed.html.haml
deleted file mode 100644
index b9dc37c9b54..00000000000
--- a/app/views/projects/merge_requests/diffs/_not_all_comments_displayed.html.haml
+++ /dev/null
@@ -1,17 +0,0 @@
-- if @commit || @start_version || (@merge_request_diff && !@merge_request_diff.latest?)
- .mr-version-controls
- .content-block.comments-disabled-notif.clearfix
- = sprite_icon('information-o')
- = succeed '.' do
- - if @commit
- Only comments from the following commit are shown below
- - else
- Not all comments are displayed because you're
- - if @start_version
- comparing two versions of the diff
- - else
- viewing an old version of the diff
- .float-right
- = link_to diffs_project_merge_request_path(@merge_request.project, @merge_request), class: 'btn btn-sm' do
- Show latest version
- = "of the diff" if @commit
diff --git a/app/views/projects/merge_requests/diffs/_version_controls.html.haml b/app/views/projects/merge_requests/diffs/_version_controls.html.haml
deleted file mode 100644
index 52bf584d550..00000000000
--- a/app/views/projects/merge_requests/diffs/_version_controls.html.haml
+++ /dev/null
@@ -1,73 +0,0 @@
-- if @merge_request_diff && @merge_request_diffs.size > 1
- .mr-version-controls
- .mr-version-menus-container.content-block
- Changes between
- %span.dropdown.inline.mr-version-dropdown
- %a.dropdown-toggle.btn.btn-default{ data: { toggle: :dropdown, display: 'static' } }
- %span
- - if @merge_request_diff.latest?
- latest version
- - else
- version #{version_index(@merge_request_diff)}
- = icon('caret-down')
- .dropdown-menu.dropdown-select.dropdown-menu-selectable
- .dropdown-title
- %span Version:
- %button.dropdown-title-button.dropdown-menu-close{ aria: { label: "Close" } }
- = icon('times', class: 'dropdown-menu-close-icon')
- .dropdown-content
- %ul
- - @merge_request_diffs.each do |merge_request_diff|
- %li
- = link_to merge_request_version_path(@project, @merge_request, merge_request_diff, @start_sha), class: ('is-active' if merge_request_diff == @merge_request_diff) do
- %div
- %strong
- - if merge_request_diff.latest?
- latest version
- - else
- version #{version_index(merge_request_diff)}
- %div
- %small.commit-sha= short_sha(merge_request_diff.head_commit_sha)
- %div
- %small
- #{number_with_delimiter(merge_request_diff.commits_count)} #{'commit'.pluralize(merge_request_diff.commits_count)},
- = time_ago_with_tooltip(merge_request_diff.created_at)
-
- - if @merge_request_diff.base_commit_sha
- and
- %span.dropdown.inline.mr-version-compare-dropdown
- %a.btn.btn-default.dropdown-toggle{ data: { toggle: :dropdown, display: 'static' } }
- - if @start_version
- version #{version_index(@start_version)}
- - else
- %span.ref-name= @merge_request.target_branch
- = icon('caret-down')
- .dropdown-menu.dropdown-select.dropdown-menu-selectable
- .dropdown-title
- %span Compared with:
- %button.dropdown-title-button.dropdown-menu-close{ aria: { label: "Close" } }
- = icon('times', class: 'dropdown-menu-close-icon')
- .dropdown-content
- %ul
- - @comparable_diffs.each do |merge_request_diff|
- %li
- = link_to merge_request_version_path(@project, @merge_request, @merge_request_diff, merge_request_diff.head_commit_sha), class: ('is-active' if merge_request_diff == @start_version) do
- %div
- %strong
- - if merge_request_diff.latest?
- latest version
- - else
- version #{version_index(merge_request_diff)}
- %div
- %small.commit-sha= short_sha(merge_request_diff.head_commit_sha)
- %div
- %small
- = time_ago_with_tooltip(merge_request_diff.created_at)
- %li
- = link_to merge_request_version_path(@project, @merge_request, @merge_request_diff), class: ('is-active' unless @start_version) do
- %div
- %strong
- %span.ref-name= @merge_request.target_branch
- (base)
- %div
- %strong.commit-sha= short_sha(@merge_request_diff.base_commit_sha)
diff --git a/app/views/projects/merge_requests/invalid.html.haml b/app/views/projects/merge_requests/invalid.html.haml
index 7b831aa2d01..df942c11883 100644
--- a/app/views/projects/merge_requests/invalid.html.haml
+++ b/app/views/projects/merge_requests/invalid.html.haml
@@ -1,25 +1,28 @@
- page_title "#{@merge_request.title} (#{@merge_request.to_reference}", _("Merge Requests")
+- badge_css_classes = "badge gl-text-white"
+- badge_info_css_classes = "#{badge_css_classes} badge-info"
+- badge_inverse_css_classes = "#{badge_css_classes} badge-inverse"
.merge-request
= render "projects/merge_requests/mr_title"
= render "projects/merge_requests/mr_box"
- .alert.alert-danger
+ .gl-alert.gl-alert-danger
+ = sprite_icon('error', size: 16, css_class: 'gl-icon gl-alert-icon gl-alert-icon-no-title')
%p
We cannot render this merge request properly because
- if @merge_request.for_fork? && !@merge_request.source_project
fork project was removed
- elsif !@merge_request.source_branch_exists?
- %span.badge.badge-inverse= @merge_request.source_branch
+ %span{ class: badge_inverse_css_classes }= @merge_request.source_branch
does not exist in
- %span.badge.badge-info= @merge_request.source_project_path
+ %span{ class: badge_info_css_classes }= @merge_request.source_project_path
- elsif !@merge_request.target_branch_exists?
- %span.badge.badge-inverse= @merge_request.target_branch
+ %span{ class: badge_inverse_css_classes }= @merge_request.target_branch
does not exist in
- %span.badge.badge-info= @merge_request.target_project_path
+ %span{ class: badge_info_css_classes }= @merge_request.target_project_path
- else
of internal error
%strong
Please close Merge Request or change branches with existing one
-
diff --git a/app/views/projects/merge_requests/show.html.haml b/app/views/projects/merge_requests/show.html.haml
index b579f7510f9..1dbcd613ceb 100644
--- a/app/views/projects/merge_requests/show.html.haml
+++ b/app/views/projects/merge_requests/show.html.haml
@@ -3,11 +3,14 @@
- add_to_breadcrumbs _("Merge Requests"), project_merge_requests_path(@project)
- breadcrumb_title @merge_request.to_reference
- page_title "#{@merge_request.title} (#{@merge_request.to_reference})", _("Merge Requests")
-- page_description @merge_request.description
+- page_description @merge_request.description_html
- page_card_attributes @merge_request.card_attributes
- suggest_changes_help_path = help_page_path('user/discussions/index.md', anchor: 'suggest-changes')
- number_of_pipelines = @pipelines.size
- mr_action = j(params[:tab].presence || 'show')
+- add_page_specific_style 'page_bundles/merge_requests'
+- add_page_specific_style 'page_bundles/pipelines'
+- add_page_specific_style 'page_bundles/reports'
.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 } }
= render "projects/merge_requests/mr_title"
@@ -43,7 +46,6 @@
.tab-content#diff-notes-app
#js-diff-file-finder
- - if native_code_navigation_enabled?(@project)
#js-code-navigation
= render "projects/merge_requests/tabs/pane", id: "notes", class: "notes voting_notes" do
.row
@@ -92,7 +94,7 @@
.loading.hide
.spinner.spinner-md
-= render 'shared/issuable/sidebar', issuable_sidebar: @issuable_sidebar, assignees: @merge_request.assignees, source_branch: @merge_request.source_branch
+= render 'shared/issuable/sidebar', issuable_sidebar: @issuable_sidebar, assignees: @merge_request.assignees, reviewers: @merge_request.reviewers, source_branch: @merge_request.source_branch
- if @merge_request.can_be_reverted?(current_user)
= render "projects/commit/change", type: 'revert', commit: @merge_request.merge_commit, title: @merge_request.title
diff --git a/app/views/projects/milestones/index.html.haml b/app/views/projects/milestones/index.html.haml
index 2bab2a0fb03..2c52d2a5fbc 100644
--- a/app/views/projects/milestones/index.html.haml
+++ b/app/views/projects/milestones/index.html.haml
@@ -1,4 +1,5 @@
- page_title _('Milestones')
+- add_page_specific_style 'page_bundles/milestone'
.top-area
= render 'shared/milestones_filter', counts: milestone_counts(@project.milestones)
@@ -11,7 +12,7 @@
= _('New milestone')
.milestones
- #delete-milestone-modal
+ #js-delete-milestone-modal
#promote-milestone-modal
%ul.content-list
diff --git a/app/views/projects/milestones/show.html.haml b/app/views/projects/milestones/show.html.haml
index 99e626161c4..2185df3a994 100644
--- a/app/views/projects/milestones/show.html.haml
+++ b/app/views/projects/milestones/show.html.haml
@@ -1,7 +1,8 @@
- add_to_breadcrumbs _('Milestones'), project_milestones_path(@project)
- breadcrumb_title @milestone.title
- page_title @milestone.title, _('Milestones')
-- page_description @milestone.description
+- page_description @milestone.description_html
+- add_page_specific_style 'page_bundles/milestone'
= render 'shared/milestones/header', milestone: @milestone
= render 'shared/milestones/description', milestone: @milestone
@@ -9,11 +10,15 @@
= render_if_exists 'shared/milestones/burndown', milestone: @milestone, project: @project
- if can?(current_user, :read_issue, @project) && @milestone.total_issues_count == 0
- .alert.alert-success.gl-mt-3
- %span= _('Assign some issues to this milestone.')
+ .gl-alert.gl-alert-info.gl-mt-3.gl-mb-5{ data: { testid: 'no-issues-alert' } }
+ = sprite_icon('information-o', size: 16, css_class: 'gl-icon gl-alert-icon gl-alert-icon-no-title')
+ .gl-alert-body
+ %span= _('Assign some issues to this milestone.')
- elsif @milestone.complete? && @milestone.active?
- .alert.alert-success.gl-mt-3
- %span= _('All issues for this milestone are closed. You may close this milestone now.')
+ .gl-alert.gl-alert-success.gl-mt-3.gl-mb-5{ data: { testid: 'all-issues-closed-alert' } }
+ = sprite_icon('check-circle', size: 16, css_class: 'gl-icon gl-alert-icon gl-alert-icon-no-title')
+ .gl-alert-body
+ %span= _('All issues for this milestone are closed. You may close this milestone now.')
= render 'shared/milestones/tabs', milestone: @milestone
= render 'shared/milestones/sidebar', milestone: @milestone, project: @project, affix_offset: 153
diff --git a/app/views/projects/milestones/update.js.haml b/app/views/projects/milestones/update.js.haml
deleted file mode 100644
index 3ff84915e97..00000000000
--- a/app/views/projects/milestones/update.js.haml
+++ /dev/null
@@ -1,2 +0,0 @@
-:plain
- $('##{dom_id(@milestone)}').fadeOut();
diff --git a/app/views/projects/mirrors/_mirror_repos.html.haml b/app/views/projects/mirrors/_mirror_repos.html.haml
index d7098bbb69d..d2847de6ece 100644
--- a/app/views/projects/mirrors/_mirror_repos.html.haml
+++ b/app/views/projects/mirrors/_mirror_repos.html.haml
@@ -6,7 +6,7 @@
%section.settings.project-mirror-settings.no-animate#js-push-remote-settings{ class: mirror_settings_class, data: { qa_selector: 'mirroring_repositories_settings_content' } }
.settings-header
%h4= _('Mirroring repositories')
- %button.btn.js-settings-toggle
+ %button.btn.gl-button.js-settings-toggle
= expanded ? _('Collapse') : _('Expand')
%p
= _('Set up your project to automatically push and/or pull changes to/from another repository. Branches, tags, and commits will be synced automatically.')
@@ -32,7 +32,7 @@
= label_tag :only_protected_branches, _('Only mirror protected branches'), class: 'form-check-label'
= link_to sprite_icon('question-o'), help_page_path('user/project/protected_branches'), target: '_blank'
- .panel-footer.gl-display-flex.gl-justify-content-end
+ .panel-footer
= f.submit _('Mirror repository'), class: 'btn btn-success js-mirror-submit qa-mirror-repository-button', name: :update_remote_mirror
- else
.gl-alert.gl-alert-info{ role: 'alert' }
@@ -74,4 +74,4 @@
- if mirror.ssh_key_auth?
= clipboard_button(text: mirror.ssh_public_key, class: 'btn btn-default', title: _('Copy SSH public key'), qa_selector: 'copy_public_key_button')
= render 'shared/remote_mirror_update_button', remote_mirror: mirror
- %button.js-delete-mirror.qa-delete-mirror.rspec-delete-mirror.btn.btn-danger{ type: 'button', data: { mirror_id: mirror.id, toggle: 'tooltip', container: 'body' }, title: _('Remove') }= sprite_icon('remove')
+ %button.js-delete-mirror.qa-delete-mirror.rspec-delete-mirror.btn.gl-button.btn-danger{ type: 'button', data: { mirror_id: mirror.id, toggle: 'tooltip', container: 'body' }, title: _('Remove') }= sprite_icon('remove')
diff --git a/app/views/projects/mirrors/_regenerate_public_ssh_key_confirm_modal.html.haml b/app/views/projects/mirrors/_regenerate_public_ssh_key_confirm_modal.html.haml
index 327552c9b2c..e6f3060af3e 100644
--- a/app/views/projects/mirrors/_regenerate_public_ssh_key_confirm_modal.html.haml
+++ b/app/views/projects/mirrors/_regenerate_public_ssh_key_confirm_modal.html.haml
@@ -9,5 +9,5 @@
.modal-body
%p= _('Are you sure you want to regenerate the public key? You will have to update the public key on the remote server before mirroring will work again.')
.form-actions.modal-footer
- = button_tag _('Cancel'), type: 'button', class: 'btn js-cancel'
- = button_tag _('Regenerate key'), type: 'button', class: 'btn btn-inverted btn-warning js-confirm'
+ = button_tag _('Cancel'), type: 'button', class: 'btn gl-button js-cancel'
+ = button_tag _('Regenerate key'), type: 'button', class: 'btn gl-button btn-inverted btn-warning js-confirm'
diff --git a/app/views/projects/mirrors/_ssh_host_keys.html.haml b/app/views/projects/mirrors/_ssh_host_keys.html.haml
index 786918c4970..1690188f07a 100644
--- a/app/views/projects/mirrors/_ssh_host_keys.html.haml
+++ b/app/views/projects/mirrors/_ssh_host_keys.html.haml
@@ -3,7 +3,7 @@
- verified_at = mirror.ssh_known_hosts_verified_at
.form-group.js-ssh-host-keys-section{ class: ('collapse' unless mirror.ssh_mirror_url?) }
- %button.btn.btn-inverted.btn-secondary.inline.js-detect-host-keys.gl-mr-3{ type: 'button', data: { qa_selector: 'detect_host_keys' } }
+ %button.btn.gl-button.btn-inverted.btn-secondary.inline.js-detect-host-keys.gl-mr-3{ type: 'button', data: { qa_selector: 'detect_host_keys' } }
.js-spinner.d-none.spinner.mr-1
= _('Detect host keys')
.fingerprint-ssh-info.js-fingerprint-ssh-info.gl-mt-3.gl-mb-3{ class: ('collapse' unless mirror.ssh_mirror_url?) }
@@ -23,7 +23,7 @@
#{time_ago_in_words(verified_at)} ago
.js-ssh-hosts-advanced.inline
- %button.btn.btn-default.btn-show-advanced.show-advanced{ type: 'button' }
+ %button.btn.gl-button.btn-default.btn-show-advanced.show-advanced{ type: 'button' }
%span.label-show
= _('Input host keys manually')
%span.label-hide
diff --git a/app/views/projects/network/show.html.haml b/app/views/projects/network/show.html.haml
index d134bfb488e..4366676bd45 100644
--- a/app/views/projects/network/show.html.haml
+++ b/app/views/projects/network/show.html.haml
@@ -2,12 +2,12 @@
- page_title _("Graph"), @ref
= render "head"
%div{ class: container_class }
- .project-network
- .controls
+ .project-network.gl-border-1.gl-border-solid.gl-border-gray-300
+ .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 input-mx-250 search-sha'
= button_tag class: 'btn btn-success' do
- = icon('search')
+ = sprite_icon('search')
.inline.prepend-left-20
.form-check.light
= check_box_tag :filter_ref, 1, @options[:filter_ref], class: 'form-check-input'
@@ -15,6 +15,6 @@
%span= _("Begin with the selected commit")
- if @commit
- .network-graph{ data: { url: @url, commit_url: @commit_url, ref: @ref, commit_id: @commit.id } }
+ .network-graph.gl-bg-white.gl-overflow-scroll.gl-overflow-x-hidden{ data: { url: @url, commit_url: @commit_url, ref: @ref, commit_id: @commit.id } }
.text-center.gl-mt-3
.spinner.spinner-md
diff --git a/app/views/projects/no_repo.html.haml b/app/views/projects/no_repo.html.haml
index 0ab9d9c4005..c44d3da23bb 100644
--- a/app/views/projects/no_repo.html.haml
+++ b/app/views/projects/no_repo.html.haml
@@ -22,4 +22,4 @@
- if can? current_user, :remove_project, @project
.prepend-top-20
- = link_to _('Delete project'), project_path(@project), data: { confirm: remove_project_message(@project)}, method: :delete, class: "btn btn-inverted btn-remove float-right"
+ = link_to _('Delete project'), project_path(@project), data: { confirm: remove_project_message(@project)}, method: :delete, class: "gl-button btn btn-danger btn-danger-secondary float-right"
diff --git a/app/views/projects/notes/_actions.html.haml b/app/views/projects/notes/_actions.html.haml
index 058366eb75d..a785e36fad5 100644
--- a/app/views/projects/notes/_actions.html.haml
+++ b/app/views/projects/notes/_actions.html.haml
@@ -2,7 +2,7 @@
- if note.noteable_author?(@noteable)
%span{ class: 'note-role user-access-role has-tooltip d-none d-md-inline-block', title: _("This user is the author of this %{noteable}.") % { noteable: @noteable.human_class_name } }= _("Author")
- if access
- %span{ class: 'note-role user-access-role has-tooltip', title: _("This user is a %{access} of the %{name} project.") % { access: access.downcase, name: note.project_name } }= access
+ %span{ class: 'note-role user-access-role has-tooltip', title: _("This user has the %{access} role in the %{name} project.") % { access: access.downcase, name: note.project_name } }= access
- elsif note.contributor?
%span{ class: 'note-role user-access-role has-tooltip', title: _("This user has previously committed to the %{name} project.") % { name: note.project_name } }= _("Contributor")
diff --git a/app/views/projects/packages/packages/show.html.haml b/app/views/projects/packages/packages/show.html.haml
index 97a3c6e7092..aeca3f5b3e3 100644
--- a/app/views/projects/packages/packages/show.html.haml
+++ b/app/views/projects/packages/packages/show.html.haml
@@ -24,4 +24,5 @@
composer_help_path: help_page_path('user/packages/composer_repository/index'),
project_name: @project.name,
project_list_url: project_packages_path(@project),
- group_list_url: @project.group ? group_packages_path(@project.group) : ''} }
+ group_list_url: @project.group ? group_packages_path(@project.group) : '',
+ composer_config_repository_name: composer_config_repository_name(@project.group&.id)} }
diff --git a/app/views/projects/pages/_destroy.haml b/app/views/projects/pages/_destroy.haml
index 58dbbb5bcfc..2714b5f221a 100644
--- a/app/views/projects/pages/_destroy.haml
+++ b/app/views/projects/pages/_destroy.haml
@@ -8,7 +8,7 @@
%p
= s_('GitLabPages|Removing pages will prevent them from being exposed to the outside world.')
.form-actions
- = link_to s_('GitLabPages|Remove pages'), project_pages_path(@project), data: { confirm: s_('GitLabPages|Are you sure?')}, method: :delete, class: "btn btn-remove"
+ = link_to s_('GitLabPages|Remove pages'), project_pages_path(@project), data: { confirm: s_('GitLabPages|Are you sure?')}, method: :delete, class: "btn gl-button btn-danger"
- else
.nothing-here-block
= s_('GitLabPages|Only project maintainers can remove pages')
diff --git a/app/views/projects/pages/_list.html.haml b/app/views/projects/pages/_list.html.haml
index af6de10b2a0..84c8ab0ceba 100644
--- a/app/views/projects/pages/_list.html.haml
+++ b/app/views/projects/pages/_list.html.haml
@@ -21,8 +21,8 @@
%span.badge.badge-danger
= s_('GitLabPages|Expired')
%div
- = link_to s_('GitLabPages|Edit'), project_pages_domain_path(@project, domain), class: "btn btn-sm btn-grouped btn-success btn-inverted"
- = link_to s_('GitLabPages|Remove'), project_pages_domain_path(@project, domain), data: { confirm: s_('GitLabPages|Are you sure?')}, method: :delete, class: "btn btn-remove btn-sm btn-grouped"
+ = link_to s_('GitLabPages|Edit'), project_pages_domain_path(@project, domain), class: "btn gl-button btn-sm btn-grouped btn-success btn-inverted"
+ = link_to s_('GitLabPages|Remove'), project_pages_domain_path(@project, domain), data: { confirm: s_('GitLabPages|Are you sure?')}, method: :delete, class: "btn gl-button btn-danger btn-sm btn-grouped"
- if domain.needs_verification?
%li.list-group-item.bs-callout-warning
- details_link_start = "<a href='#{project_pages_domain_path(@project, domain)}'>".html_safe
diff --git a/app/views/projects/pages/_pages_settings.html.haml b/app/views/projects/pages/_pages_settings.html.haml
index 8aa02074205..51483176d6f 100644
--- a/app/views/projects/pages/_pages_settings.html.haml
+++ b/app/views/projects/pages/_pages_settings.html.haml
@@ -1,6 +1,7 @@
= form_for @project, url: project_pages_path(@project), html: { class: 'inline', title: pages_https_only_title } do |f|
+ = render_if_exists 'shared/pages/max_pages_size_input', form: f
+
- if Gitlab.config.pages.external_http || Gitlab.config.pages.external_https
- = render_if_exists 'shared/pages/max_pages_size_input', form: f
.form-group
.form-check
@@ -9,5 +10,5 @@
%strong
= s_('GitLabPages|Force HTTPS (requires valid certificates)')
- .gl-mt-3
- = f.submit s_('GitLabPages|Save'), class: 'btn btn-success'
+ .gl-mt-3
+ = f.submit s_('GitLabPages|Save'), class: 'btn btn-success gl-button'
diff --git a/app/views/projects/pages/show.html.haml b/app/views/projects/pages/show.html.haml
index 8a01945ffac..4347cbdbd9b 100644
--- a/app/views/projects/pages/show.html.haml
+++ b/app/views/projects/pages/show.html.haml
@@ -5,7 +5,7 @@
= s_('GitLabPages|Pages')
- if can?(current_user, :update_pages, @project) && (Gitlab.config.pages.external_http || Gitlab.config.pages.external_https)
- = link_to new_project_pages_domain_path(@project), class: 'btn btn-success float-right', title: s_('GitLabPages|New Domain') do
+ = link_to new_project_pages_domain_path(@project), class: 'btn gl-button btn-success float-right', title: s_('GitLabPages|New Domain') do
= s_('GitLabPages|New Domain')
%p.light
diff --git a/app/views/projects/pages_domains/_certificate.html.haml b/app/views/projects/pages_domains/_certificate.html.haml
index 16d949c416b..33db7896065 100644
--- a/app/views/projects/pages_domains/_certificate.html.haml
+++ b/app/views/projects/pages_domains/_certificate.html.haml
@@ -40,7 +40,7 @@
= link_to _('Remove'),
clean_certificate_project_pages_domain_path(@project, domain_presenter),
data: { confirm: _('Are you sure?') },
- class: 'btn btn-remove btn-sm',
+ class: 'gl-button btn btn-danger btn-sm',
method: :delete
- else
.row
diff --git a/app/views/projects/pages_domains/_form.html.haml b/app/views/projects/pages_domains/_form.html.haml
index 9e9f60a6f09..453134ce5ab 100644
--- a/app/views/projects/pages_domains/_form.html.haml
+++ b/app/views/projects/pages_domains/_form.html.haml
@@ -1,5 +1,6 @@
- if domain_presenter.errors.any?
- .alert.alert-danger
+ .gl-alert.gl-alert-danger
+ = sprite_icon('error', size: 16, css_class: 'gl-icon gl-alert-icon gl-alert-icon-no-title')
- domain_presenter.errors.full_messages.each do |msg|
= msg
diff --git a/app/views/projects/pipeline_schedules/_pipeline_schedule.html.haml b/app/views/projects/pipeline_schedules/_pipeline_schedule.html.haml
index ca71aa8a24d..45aaf2b64bf 100644
--- a/app/views/projects/pipeline_schedules/_pipeline_schedule.html.haml
+++ b/app/views/projects/pipeline_schedules/_pipeline_schedule.html.haml
@@ -36,5 +36,5 @@
= link_to edit_pipeline_schedule_path(pipeline_schedule), title: _('Edit'), class: 'btn gl-display-flex' do
= sprite_icon('pencil')
- if can?(current_user, :admin_pipeline_schedule, pipeline_schedule)
- = link_to pipeline_schedule_path(pipeline_schedule), title: _('Delete'), method: :delete, class: 'btn btn-remove', data: { confirm: _("Are you sure you want to delete this pipeline schedule?") } do
+ = link_to pipeline_schedule_path(pipeline_schedule), title: _('Delete'), method: :delete, class: 'gl-button btn btn-danger', data: { confirm: _("Are you sure you want to delete this pipeline schedule?") } do
= sprite_icon('remove')
diff --git a/app/views/projects/pipeline_schedules/index.html.haml b/app/views/projects/pipeline_schedules/index.html.haml
index 2b2b79d886b..91083cc0768 100644
--- a/app/views/projects/pipeline_schedules/index.html.haml
+++ b/app/views/projects/pipeline_schedules/index.html.haml
@@ -2,7 +2,7 @@
- page_title _("Pipeline Schedules")
-#pipeline-schedules-callout{ data: { docs_url: help_page_path('ci/pipelines/schedules') } }
+#pipeline-schedules-callout{ data: { docs_url: help_page_path('ci/pipelines/schedules'), image_url: image_path('illustrations/pipeline_schedule_callout.svg') } }
.top-area
- schedule_path_proc = ->(scope) { pipeline_schedules_path(@project, scope: scope) }
= render "tabs", schedule_path_proc: schedule_path_proc, all_schedules: @all_schedules, scope: @scope
diff --git a/app/views/projects/pipelines/_info.html.haml b/app/views/projects/pipelines/_info.html.haml
index c54a19b8f61..6d3b3f815e4 100644
--- a/app/views/projects/pipelines/_info.html.haml
+++ b/app/views/projects/pipelines/_info.html.haml
@@ -43,8 +43,8 @@
placement: "top",
html: "true",
trigger: "focus",
- title: "<div class='autodevops-title'>#{popover_title_text}</div>",
- content: "<a class='autodevops-link' href='#{popover_content_url}' target='_blank' rel='noopener noreferrer nofollow'>#{popover_content_text}</a>",
+ title: "<div class='gl-font-weight-normal gl-line-height-normal'>#{popover_title_text}</div>",
+ content: "<a href='#{popover_content_url}' target='_blank' rel='noopener noreferrer nofollow'>#{popover_content_text}</a>",
} }
Auto DevOps
- if @pipeline.detached_merge_request_pipeline?
@@ -58,7 +58,7 @@
.icon-container.commit-icon
= custom_icon("icon_commit")
= link_to commit.short_id, project_commit_path(@project, @pipeline.sha), class: "commit-sha js-details-short"
- = link_to("#", class: "js-details-expand d-none d-sm-none d-md-inline") do
+ = link_to("#", class: "js-details-expand d-none d-md-inline") do
%span.text-expander
= sprite_icon('ellipsis_h', size: 12)
%span.js-details-content.hide
diff --git a/app/views/projects/pipelines/_with_tabs.html.haml b/app/views/projects/pipelines/_with_tabs.html.haml
index f1ed67f8f82..40a52f76641 100644
--- a/app/views/projects/pipelines/_with_tabs.html.haml
+++ b/app/views/projects/pipelines/_with_tabs.html.haml
@@ -68,7 +68,7 @@
%td.responsive-table-cell.build-failure{ data: { column: _('Failure')} }
= build.present.callout_failure_message
%td.responsive-table-cell.build-actions
- - if can?(current_user, :update_build, job)
+ - if can?(current_user, :update_build, job) && job.retryable?
= link_to retry_project_job_path(build.project, build, return_to: request.original_url), method: :post, title: _('Retry'), class: 'btn btn-build gl-button btn-icon btn-default' do
= sprite_icon('repeat', css_class: 'gl-icon')
- if can?(current_user, :read_build, job)
diff --git a/app/views/projects/pipelines/index.html.haml b/app/views/projects/pipelines/index.html.haml
index 05f8a126a02..ca07f33136b 100644
--- a/app/views/projects/pipelines/index.html.haml
+++ b/app/views/projects/pipelines/index.html.haml
@@ -1,4 +1,5 @@
- page_title _('Pipelines')
+- add_page_specific_style 'page_bundles/pipelines'
= render_if_exists "shared/shared_runners_minutes_limit_flash_message"
diff --git a/app/views/projects/pipelines/new.html.haml b/app/views/projects/pipelines/new.html.haml
index 2be75106000..cb5401cd329 100644
--- a/app/views/projects/pipelines/new.html.haml
+++ b/app/views/projects/pipelines/new.html.haml
@@ -6,8 +6,16 @@
= s_('Pipeline|Run Pipeline')
%hr
-- if Feature.enabled?(:new_pipeline_form)
- #js-new-pipeline{ data: { project_id: @project.id, pipelines_path: project_pipelines_path(@project), ref_param: params[:ref] || @project.default_branch, var_param: params[:var].to_json, file_param: params[:file_var].to_json, ref_names: @project.repository.ref_names.to_json.html_safe, settings_link: project_settings_ci_cd_path(@project), max_warnings: ::Gitlab::Ci::Warnings::MAX_LIMIT } }
+- if Feature.enabled?(:new_pipeline_form, @project)
+ #js-new-pipeline{ data: { project_id: @project.id,
+ pipelines_path: project_pipelines_path(@project),
+ config_variables_path: config_variables_namespace_project_pipelines_path(@project.namespace, @project),
+ ref_param: params[:ref] || @project.default_branch,
+ var_param: params[:var].to_json,
+ file_param: params[:file_var].to_json,
+ ref_names: @project.repository.ref_names.to_json.html_safe,
+ settings_link: project_settings_ci_cd_path(@project),
+ max_warnings: ::Gitlab::Ci::Warnings::MAX_LIMIT } }
- else
= form_for @pipeline, as: :pipeline, url: project_pipelines_path(@project), html: { id: "new-pipeline-form", class: "js-new-pipeline-form js-requires-input" } do |f|
diff --git a/app/views/projects/pipelines/show.html.haml b/app/views/projects/pipelines/show.html.haml
index a9c140aee5f..34f7744f825 100644
--- a/app/views/projects/pipelines/show.html.haml
+++ b/app/views/projects/pipelines/show.html.haml
@@ -2,10 +2,11 @@
- breadcrumb_title "##{@pipeline.id}"
- page_title _('Pipeline')
- pipeline_has_errors = @pipeline.builds.empty? && @pipeline.yaml_errors.present?
+- add_page_specific_style 'page_bundles/pipeline'
+- add_page_specific_style 'page_bundles/reports'
.js-pipeline-container{ data: { controller_action: "#{controller.action_name}" } }
- #js-pipeline-header-vue.pipeline-header-container
-
+ #js-pipeline-header-vue.pipeline-header-container{ data: {full_path: @project.full_path, retry_path: retry_project_pipeline_path(@pipeline.project, @pipeline), cancel_path: cancel_project_pipeline_path(@pipeline.project, @pipeline), delete_path: project_pipeline_path(@pipeline.project, @pipeline), pipeline_iid: @pipeline.iid, pipeline_id: @pipeline.id} }
- if @pipeline.commit.present?
= render "projects/pipelines/info", commit: @pipeline.commit
diff --git a/app/views/projects/project_members/_team.html.haml b/app/views/projects/project_members/_team.html.haml
index 4b3fdf8d0b1..4d4705c4ed5 100644
--- a/app/views/projects/project_members/_team.html.haml
+++ b/app/views/projects/project_members/_team.html.haml
@@ -11,7 +11,7 @@
.position-relative
= search_field_tag :search, params[:search], { placeholder: _('Find existing members by name'), class: 'form-control', spellcheck: false }
%button.user-search-btn{ type: "submit", "aria-label" => _("Submit search") }
- = icon("search")
+ = sprite_icon('search', css_class: 'gl-vertical-align-middle!')
= label_tag :sort_by, _('Sort by'), class: 'col-form-label label-bold px-2'
= render 'shared/members/sort_dropdown'
%ul.content-list.members-list{ data: { qa_selector: 'members_list' } }
diff --git a/app/views/projects/project_members/import.html.haml b/app/views/projects/project_members/import.html.haml
index bcca943de6a..2f953db0d65 100644
--- a/app/views/projects/project_members/import.html.haml
+++ b/app/views/projects/project_members/import.html.haml
@@ -11,5 +11,5 @@
.col-sm-10= select_tag(:source_project_id, options_from_collection_for_select(@projects, :id, :name_with_namespace), prompt: "Select project", class: "select2 lg", required: true)
.form-actions
- = button_tag _('Import project members'), class: "btn btn-success"
- = link_to _("Cancel"), project_project_members_path(@project), class: "btn btn-cancel"
+ = button_tag _('Import project members'), class: "btn gl-button btn-success"
+ = link_to _("Cancel"), project_project_members_path(@project), class: "btn gl-button btn-cancel"
diff --git a/app/views/projects/project_templates/_built_in_templates.html.haml b/app/views/projects/project_templates/_built_in_templates.html.haml
deleted file mode 100644
index 43352952b37..00000000000
--- a/app/views/projects/project_templates/_built_in_templates.html.haml
+++ /dev/null
@@ -1,17 +0,0 @@
-- Gitlab::ProjectTemplate.all.each do |template|
- .template-option.d-flex.align-items-center{ data: { qa_selector: 'template_option_row' } }
- .logo.gl-mr-3.px-1
- = image_tag template.logo, size: 32, class: "btn-template-icon icon-#{template.name}"
- .description
- %strong
- = template.title
- %br
- .text-muted
- = template.description
- .controls.d-flex.align-items-center
- %a.btn.btn-default.gl-mr-3{ href: template.preview, rel: 'noopener noreferrer', target: '_blank', data: { track_label: "template_preview", track_property: template.name, track_event: "click_button", track_value: "" } }
- = _("Preview")
- %label.btn.btn-success.template-button.choose-template.gl-mb-0{ for: template.name }
- %input{ type: "radio", autocomplete: "off", name: "project[template_name]", id: template.name, value: template.name, data: { track_label: "template_use", track_property: template.name, track_event: "click_button", track_value: "" } }
- %span{ data: { qa_selector: 'use_template_button' } }
- = _("Use template")
diff --git a/app/views/projects/project_templates/_template.html.haml b/app/views/projects/project_templates/_template.html.haml
new file mode 100644
index 00000000000..e2bfd0881b5
--- /dev/null
+++ b/app/views/projects/project_templates/_template.html.haml
@@ -0,0 +1,16 @@
+.template-option.d-flex.align-items-center{ data: { qa_selector: 'template_option_row' } }
+ .logo.gl-mr-3.px-1
+ = image_tag template.logo, size: 32, class: "btn-template-icon icon-#{template.name}"
+ .description
+ %strong
+ = template.title
+ %br
+ .text-muted
+ = template.description
+ .controls.d-flex.align-items-center
+ %a.btn.gl-button.btn-default.gl-mr-3{ href: template.preview, rel: 'noopener noreferrer', target: '_blank', data: { track_label: "template_preview", track_property: template.name, track_event: "click_button", track_value: "" } }
+ = _("Preview")
+ %label.btn.gl-button.btn-success.template-button.choose-template.gl-mb-0{ for: template.name }
+ %input{ type: "radio", autocomplete: "off", name: "project[template_name]", id: template.name, value: template.name, data: { track_label: "template_use", track_property: template.name, track_event: "click_button", track_value: "" } }
+ %span{ data: { qa_selector: 'use_template_button' } }
+ = _("Use template")
diff --git a/app/views/projects/protected_branches/_create_protected_branch.html.haml b/app/views/projects/protected_branches/_create_protected_branch.html.haml
index ee359a01e74..33be875d9a6 100644
--- a/app/views/projects/protected_branches/_create_protected_branch.html.haml
+++ b/app/views/projects/protected_branches/_create_protected_branch.html.haml
@@ -1,3 +1,5 @@
+- select_mode_for_dropdown = Feature.enabled?(:deploy_keys_on_protected_branches, @project) ? 'js-multiselect' : ''
+
- content_for :merge_access_levels do
.merge_access_levels-container
= dropdown_tag('Select',
@@ -7,7 +9,7 @@
- content_for :push_access_levels do
.push_access_levels-container
= dropdown_tag('Select',
- options: { toggle_class: 'js-allowed-to-push qa-allowed-to-push-select wide',
+ options: { toggle_class: "js-allowed-to-push qa-allowed-to-push-select #{select_mode_for_dropdown} wide",
dropdown_class: 'dropdown-menu-selectable qa-allowed-to-push-dropdown rspec-allowed-to-push-dropdown capitalize-header',
data: { field_name: 'protected_branch[push_access_levels_attributes][0][access_level]', input_id: 'push_access_levels_attributes' }})
diff --git a/app/views/projects/protected_tags/shared/_create_protected_tag.html.haml b/app/views/projects/protected_tags/shared/_create_protected_tag.html.haml
index dc7514badb6..c4bf2d20ecf 100644
--- a/app/views/projects/protected_tags/shared/_create_protected_tag.html.haml
+++ b/app/views/projects/protected_tags/shared/_create_protected_tag.html.haml
@@ -24,5 +24,5 @@
.create_access_levels-container
= yield :create_access_levels
- .card-footer.gl-display-flex.gl-justify-content-end
+ .card-footer
= f.submit _('Protect'), class: 'btn-success btn', disabled: true, data: { qa_selector: 'protect_tag_button' }
diff --git a/app/views/projects/registry/repositories/index.html.haml b/app/views/projects/registry/repositories/index.html.haml
index 8540ce30060..9ac1fda169f 100644
--- a/app/views/projects/registry/repositories/index.html.haml
+++ b/app/views/projects/registry/repositories/index.html.haml
@@ -15,5 +15,8 @@
"registry_host_url_with_port" => escape_once(registry_config.host_port),
"expiration_policy_help_page_path" => help_page_path('user/packages/container_registry/index', anchor: 'expiration-policy'),
"garbage_collection_help_page_path" => help_page_path('administration/packages/container_registry', anchor: 'container-registry-garbage-collection'),
+ "run_cleanup_policies_help_page_path" => help_page_path('administration/packages/container_registry', anchor: 'run-the-cleanup-policy-now'),
+ "cleanup_policies_help_page_path" => help_page_path('user/packages/container_registry/index', anchor: 'how-the-cleanup-policy-works'),
+
"is_admin": current_user&.admin.to_s,
character_error: @character_error.to_s } }
diff --git a/app/views/projects/registry/settings/_index.haml b/app/views/projects/registry/settings/_index.haml
index c0cef8503e0..c6fae2cc7a1 100644
--- a/app/views/projects/registry/settings/_index.haml
+++ b/app/views/projects/registry/settings/_index.haml
@@ -1,7 +1,8 @@
#js-registry-settings{ data: { project_id: @project.id,
+ project_path: @project.full_path,
cadence_options: cadence_options.to_json,
keep_n_options: keep_n_options.to_json,
older_than_options: older_than_options.to_json,
is_admin: current_user&.admin.to_s,
admin_settings_path: ci_cd_admin_application_settings_path(anchor: 'js-registry-settings'),
- enable_historic_entries: Gitlab::CurrentSettings.try(:container_expiration_policies_enable_historic_entries).to_s} }
+ enable_historic_entries: container_expiration_policies_historic_entry_enabled?(@project).to_s} }
diff --git a/app/views/projects/releases/show.html.haml b/app/views/projects/releases/show.html.haml
index 188262fb34c..91ee9ad70a3 100644
--- a/app/views/projects/releases/show.html.haml
+++ b/app/views/projects/releases/show.html.haml
@@ -1,4 +1,5 @@
- add_to_breadcrumbs _("Releases"), project_releases_path(@project)
- page_title @release.name
+- page_description @release.description_html
-#js-show-release-page{ data: { project_id: @project.id, tag_name: @release.tag } }
+#js-show-release-page{ data: data_for_show_page }
diff --git a/app/views/projects/runners/_shared_runners.html.haml b/app/views/projects/runners/_shared_runners.html.haml
index 8a17ca3c670..c567b453bf2 100644
--- a/app/views/projects/runners/_shared_runners.html.haml
+++ b/app/views/projects/runners/_shared_runners.html.haml
@@ -1,19 +1,16 @@
-%h3
- = _('Shared Runners')
-
-.bs-callout.shared-runners-description
- - if Gitlab::CurrentSettings.shared_runners_text.present?
- = markdown_field(Gitlab::CurrentSettings.current_application_settings, :shared_runners_text)
- - else
- = _('GitLab Shared Runners execute code of different projects on the same Runner unless you configure GitLab Runner Autoscale with MaxBuilds 1 (which it is on GitLab.com).')
+= render layout: 'shared/runners/shared_runners_description' do
%hr
- - if @project.shared_runners_enabled?
- = link_to toggle_shared_runners_project_runners_path(@project), class: 'btn btn-close', method: :post do
- = _('Disable shared Runners')
+ - if @project.group&.shared_runners_setting == 'disabled_and_unoverridable'
+ %h5.gl-text-red-500
+ = _('Shared runners disabled on group level')
- else
- = link_to toggle_shared_runners_project_runners_path(@project), class: 'btn btn-success', method: :post do
- = _('Enable shared Runners')
- &nbsp; for this project
+ - if @project.shared_runners_enabled?
+ = link_to toggle_shared_runners_project_runners_path(@project), class: 'btn btn-close', method: :post do
+ = _('Disable shared runners')
+ - else
+ = link_to toggle_shared_runners_project_runners_path(@project), class: 'btn btn-success', method: :post do
+ = _('Enable shared runners')
+ &nbsp; for this project
- if @shared_runners_count == 0
= _('This GitLab instance does not provide any shared Runners yet. Instance administrators can register shared Runners in the admin area.')
diff --git a/app/views/projects/services/mattermost_slash_commands/_installation_info.html.haml b/app/views/projects/services/mattermost_slash_commands/_installation_info.html.haml
index aee81ea744a..53ee363de53 100644
--- a/app/views/projects/services/mattermost_slash_commands/_installation_info.html.haml
+++ b/app/views/projects/services/mattermost_slash_commands/_installation_info.html.haml
@@ -2,6 +2,6 @@
- unless @service.activated?
.row
.col-sm-9.offset-sm-3
- = link_to new_project_mattermost_path(@project), class: 'btn btn-lg' do
+ = link_to new_project_mattermost_path(@project), class: 'btn gl-button btn-lg' do
= custom_icon('mattermost_logo', size: 15)
= s_("MattermostService|Add to Mattermost")
diff --git a/app/views/projects/services/prometheus/_configuration_banner.html.haml b/app/views/projects/services/prometheus/_configuration_banner.html.haml
index b4e8458d8b9..717df405fa7 100644
--- a/app/views/projects/services/prometheus/_configuration_banner.html.haml
+++ b/app/views/projects/services/prometheus/_configuration_banner.html.haml
@@ -14,13 +14,13 @@
.col-sm-10
%p.text-success.gl-mt-3
= s_('PrometheusService|Prometheus is being automatically managed on your clusters')
- = link_to s_('PrometheusService|Manage clusters'), project_clusters_path(project), class: 'btn'
+ = link_to s_('PrometheusService|Manage clusters'), project_clusters_path(project), class: 'btn gl-button'
- else
.col-sm-2
= image_tag 'illustrations/monitoring/loading.svg'
.col-sm-10
%p.gl-mt-3
= s_('PrometheusService|Automatically deploy and configure Prometheus on your clusters to monitor your project’s environments')
- = link_to s_('PrometheusService|Install Prometheus on clusters'), project_clusters_path(project), class: 'btn btn-success'
+ = link_to s_('PrometheusService|Install Prometheus on clusters'), project_clusters_path(project), class: 'btn gl-button btn-success'
%hr
diff --git a/app/views/projects/services/prometheus/_custom_metrics.html.haml b/app/views/projects/services/prometheus/_custom_metrics.html.haml
index 57100282c34..70685a8a9eb 100644
--- a/app/views/projects/services/prometheus/_custom_metrics.html.haml
+++ b/app/views/projects/services/prometheus/_custom_metrics.html.haml
@@ -13,7 +13,7 @@
-# haml-lint:disable NoPlainNodes
%span.badge.badge-pill.js-custom-monitored-count 0
-# haml-lint:enable NoPlainNodes
- = link_to s_('PrometheusService|New metric'), new_project_prometheus_metric_path(project), class: 'btn btn-success js-new-metric-button hidden', data: { qa_selector: 'new_metric_button' }
+ = link_to s_('PrometheusService|New metric'), new_project_prometheus_metric_path(project), class: 'btn gl-button btn-success js-new-metric-button hidden', data: { qa_selector: 'new_metric_button' }
.card-body
.flash-container.hidden
.flash-warning
diff --git a/app/views/projects/settings/_archive.html.haml b/app/views/projects/settings/_archive.html.haml
index cbeedbd080c..4133129fde2 100644
--- a/app/views/projects/settings/_archive.html.haml
+++ b/app/views/projects/settings/_archive.html.haml
@@ -13,7 +13,6 @@
method: :post, class: "btn btn-success"
- else
%p= _("Archiving the project will make it entirely read only. It is hidden from the dashboard and doesn't show up in searches. %{strong_start}The repository cannot be committed to, and no issues, comments, or other entities can be created.%{strong_end}").html_safe % { strong_start: '<strong>'.html_safe, strong_end: '</strong>'.html_safe }
- .gl-display-flex.gl-justify-content-end
- = link_to _('Archive project'), archive_project_path(@project),
- data: { confirm: _("Are you sure that you want to archive this project?"), qa_selector: 'archive_project_link' },
- method: :post, class: "btn btn-warning"
+ = link_to _('Archive project'), archive_project_path(@project),
+ data: { confirm: _("Are you sure that you want to archive this project?"), qa_selector: 'archive_project_link' },
+ method: :post, class: "btn btn-warning"
diff --git a/app/views/projects/settings/_general.html.haml b/app/views/projects/settings/_general.html.haml
index 50f80fd1e2f..5d5f1d54439 100644
--- a/app/views/projects/settings/_general.html.haml
+++ b/app/views/projects/settings/_general.html.haml
@@ -40,5 +40,4 @@
%hr
= link_to _('Remove avatar'), project_avatar_path(@project), data: { confirm: _('Avatar will be removed. Are you sure?')}, method: :delete, class: 'btn btn-link'
- .gl-display-flex.gl-justify-content-end
- = f.submit _('Save changes'), class: "btn btn-success mt-4 qa-save-naming-topics-avatar-button"
+ = f.submit _('Save changes'), class: "btn btn-success mt-4 qa-save-naming-topics-avatar-button"
diff --git a/app/views/projects/settings/ci_cd/_badge.html.haml b/app/views/projects/settings/ci_cd/_badge.html.haml
index 82c8ec088e5..2c3e6387972 100644
--- a/app/views/projects/settings/ci_cd/_badge.html.haml
+++ b/app/views/projects/settings/ci_cd/_badge.html.haml
@@ -15,18 +15,18 @@
.col-md-2.text-center
Markdown
.col-md-10.code.js-syntax-highlight
- = highlight('.md', badge.to_markdown, language: 'markdown')
+ = highlight_badge('.md', badge.to_markdown, language: 'markdown')
.row
%hr
.row
.col-md-2.text-center
HTML
.col-md-10.code.js-syntax-highlight
- = highlight('.html', badge.to_html, language: 'html')
+ = highlight_badge('.html', badge.to_html, language: 'html')
.row
%hr
.row
.col-md-2.text-center
AsciiDoc
.col-md-10.code.js-syntax-highlight
- = highlight('.adoc', badge.to_asciidoc)
+ = highlight_badge('.adoc', badge.to_asciidoc)
diff --git a/app/views/projects/settings/ci_cd/_form.html.haml b/app/views/projects/settings/ci_cd/_form.html.haml
index 414a5f264bd..4793e685163 100644
--- a/app/views/projects/settings/ci_cd/_form.html.haml
+++ b/app/views/projects/settings/ci_cd/_form.html.haml
@@ -90,12 +90,13 @@
.form-group
.form-check
- = f.check_box :forward_deployment_enabled, { class: 'form-check-input' }
- = f.label :forward_deployment_enabled, class: 'form-check-label' do
- %strong= _("Skip outdated deployment jobs")
- .form-text.text-muted
- = _("When a deployment job is successful, skip older deployment jobs that are still pending")
- = link_to sprite_icon('question-o'), help_page_path('ci/pipelines/settings', anchor: 'skip-outdated-deployment-jobs'), target: '_blank'
+ = f.fields_for :ci_cd_settings_attributes, @project.ci_cd_settings do |form|
+ = form.check_box :forward_deployment_enabled, { class: 'form-check-input' }
+ = form.label :forward_deployment_enabled, class: 'form-check-label' do
+ %strong= _("Skip outdated deployment jobs")
+ .form-text.text-muted
+ = _("When a deployment job is successful, skip older deployment jobs that are still pending")
+ = link_to sprite_icon('question-o'), help_page_path('ci/pipelines/settings', anchor: 'skip-outdated-deployment-jobs'), target: '_blank'
%hr
.form-group
diff --git a/app/views/projects/settings/operations/_alert_management.html.haml b/app/views/projects/settings/operations/_alert_management.html.haml
index f8f3ecb6273..5c16a5e2758 100644
--- a/app/views/projects/settings/operations/_alert_management.html.haml
+++ b/app/views/projects/settings/operations/_alert_management.html.haml
@@ -9,6 +9,6 @@
= _('Expand')
%p
= _('Display alerts from all your monitoring tools directly within GitLab.')
- = link_to _('More information'), help_page_path('user/project/operations/alert_management'), target: '_blank', rel: 'noopener noreferrer'
+ = link_to _('More information'), help_page_path('operations/incident_management/index.md'), target: '_blank', rel: 'noopener noreferrer'
.settings-content
.js-alerts-settings{ data: alerts_settings_data }
diff --git a/app/views/projects/settings/operations/_tracing.html.haml b/app/views/projects/settings/operations/_tracing.html.haml
new file mode 100644
index 00000000000..f654c723e36
--- /dev/null
+++ b/app/views/projects/settings/operations/_tracing.html.haml
@@ -0,0 +1,33 @@
+- setting = tracing_setting
+- has_jaeger_url = setting.external_url.present?
+
+%section.settings.border-0.no-animate
+ .settings-header{ :class => "border-top" }
+ %h3{ :class => "h4" }
+ = _("Jaeger tracing")
+ %button.btn.gl-button.js-settings-toggle{ type: 'button' }
+ = _('Expand')
+ %p
+ - if has_jaeger_url
+ - tracing_link = link_to sanitize(setting.external_url, scrubber: Rails::Html::TextOnlyScrubber.new), target: "_blank", rel: 'noopener noreferrer' do
+ %span
+ = _('Tracing')
+ = sprite_icon('external-link', css_class: 'ml-1 vertical-align-middle')
+ - else
+ - tracing_link = link_to project_tracing_path(@project) do
+ %span
+ = _('Tracing')
+ = _("To open Jaeger and easily view tracing from GitLab, link the %{link} page to your server").html_safe % { link: tracing_link }
+ .settings-content
+ = form_for @project, url: project_settings_operations_path(@project), method: :patch do |f|
+ = form_errors(@project)
+ .form-group
+ = f.fields_for :tracing_setting_attributes, setting do |form|
+ = form.label :external_url, _('Jaeger URL'), class: 'label-bold'
+ = form.url_field :external_url, class: 'form-control', placeholder: 'e.g. https://jaeger.mycompany.com'
+ %p.form-text.text-muted
+ - jaeger_help_url = "https://www.jaegertracing.io/docs/1.7/getting-started/"
+ - link_start_tag = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: jaeger_help_url }
+ - link_end_tag = "#{sprite_icon('external-link', css_class: 'ml-1 vertical-align-middle')}</a>".html_safe
+ = _("For more information, please review %{link_start_tag}Jaeger's configuration doc%{link_end_tag}").html_safe % { link_start_tag: link_start_tag, link_end_tag: link_end_tag }
+ = f.submit _('Save changes'), class: 'btn btn-success'
diff --git a/app/views/projects/settings/operations/show.html.haml b/app/views/projects/settings/operations/show.html.haml
index 103828ee0a0..e5d34ff0fc9 100644
--- a/app/views/projects/settings/operations/show.html.haml
+++ b/app/views/projects/settings/operations/show.html.haml
@@ -8,5 +8,5 @@
= render 'projects/settings/operations/prometheus', service: prometheus_service if Feature.enabled?(:settings_operations_prometheus_service)
= render 'projects/settings/operations/metrics_dashboard'
= render 'projects/settings/operations/grafana_integration'
-= render_if_exists 'projects/settings/operations/tracing'
+= render 'projects/settings/operations/tracing'
= render_if_exists 'projects/settings/operations/status_page'
diff --git a/app/views/projects/snippets/_actions.html.haml b/app/views/projects/snippets/_actions.html.haml
deleted file mode 100644
index e4645101765..00000000000
--- a/app/views/projects/snippets/_actions.html.haml
+++ /dev/null
@@ -1,36 +0,0 @@
-- return unless current_user
-
-.d-none.d-sm-block
- - if can?(current_user, :update_snippet, @snippet)
- = link_to edit_project_snippet_path(@project, @snippet), class: "btn btn-grouped" do
- = _('Edit')
- - if can?(current_user, :admin_snippet, @snippet)
- = link_to project_snippet_path(@project, @snippet), method: :delete, data: { confirm: _("Are you sure?") }, class: "btn btn-grouped btn-inverted btn-remove", title: _('Delete Snippet') do
- = _('Delete')
- - if can?(current_user, :create_snippet, @project)
- = link_to new_project_snippet_path(@project), class: 'btn btn-grouped btn-inverted btn-success', title: _("New snippet") do
- = _('New snippet')
- - if @snippet.submittable_as_spam_by?(current_user)
- = link_to _('Submit as spam'), mark_as_spam_project_snippet_path(@project, @snippet), method: :post, class: 'btn btn-grouped btn-spam', title: _('Submit as spam')
-- if can?(current_user, :create_snippet, @project) || can?(current_user, :update_snippet, @snippet)
- .d-block.d-sm-none.dropdown
- %button.btn.btn-default.btn-block.gl-mb-0.gl-mt-2{ data: { toggle: "dropdown" } }
- = _('Options')
- = icon('caret-down')
- .dropdown-menu.dropdown-menu-full-width
- %ul
- - if can?(current_user, :create_snippet, @project)
- %li
- = link_to new_project_snippet_path(@project), title: _("New snippet") do
- = _('New snippet')
- - if can?(current_user, :admin_snippet, @snippet)
- %li
- = link_to project_snippet_path(@project, @snippet), method: :delete, data: { confirm: _("Are you sure?") }, title: _('Delete Snippet') do
- = _('Delete')
- - if can?(current_user, :update_snippet, @snippet)
- %li
- = link_to edit_project_snippet_path(@project, @snippet) do
- = _('Edit')
- - if @snippet.submittable_as_spam_by?(current_user)
- %li
- = link_to _('Submit as spam'), mark_as_spam_project_snippet_path(@project, @snippet), method: :post
diff --git a/app/views/projects/snippets/show.html.haml b/app/views/projects/snippets/show.html.haml
index 7cf5de8947c..726ab7d2372 100644
--- a/app/views/projects/snippets/show.html.haml
+++ b/app/views/projects/snippets/show.html.haml
@@ -3,13 +3,7 @@
- breadcrumb_title @snippet.to_reference
- page_title "#{@snippet.title} (#{@snippet.to_reference})", _("Snippets")
-- if Feature.enabled?(:snippets_vue, default_enabled: true)
- #js-snippet-view{ data: {'qa-selector': 'snippet_view', 'snippet-gid': @snippet.to_global_id} }
-- else
- = render 'shared/snippets/header'
-
- .project-snippets
- = render 'shared/snippets/blob', blob: @blob
+#js-snippet-view{ data: {'qa-selector': 'snippet_view', 'snippet-gid': @snippet.to_global_id} }
.row-content-block.top-block.content-component-block
= render 'award_emoji/awards_block', awardable: @snippet, inline: true
diff --git a/app/views/projects/starrers/index.html.haml b/app/views/projects/starrers/index.html.haml
index 97996562e2c..7c8314c157d 100644
--- a/app/views/projects/starrers/index.html.haml
+++ b/app/views/projects/starrers/index.html.haml
@@ -11,7 +11,7 @@
.position-relative
= search_field_tag :search, params[:search], { placeholder: _('Search'), class: 'form-control', spellcheck: false }
%button.user-search-btn{ type: "submit", "aria-label" => _("Submit search") }
- = icon("search")
+ = sprite_icon('search')
.dropdown.inline.user-sort-dropdown
= dropdown_toggle(starrers_sort_options_hash[@sort], { toggle: 'dropdown' })
%ul.dropdown-menu.dropdown-menu-right.dropdown-menu-selectable
diff --git a/app/views/projects/tags/_tag.html.haml b/app/views/projects/tags/_tag.html.haml
index dba9b20fcff..d7231e758c7 100644
--- a/app/views/projects/tags/_tag.html.haml
+++ b/app/views/projects/tags/_tag.html.haml
@@ -1,6 +1,7 @@
- commit = @repository.commit(tag.dereferenced_target)
- release = @releases.find { |release| release.tag == tag.name }
-%li.flex-row.allow-wrap
+
+%li.flex-row.allow-wrap.js-tag-list
.row-main-content
= sprite_icon('tag')
= link_to tag.name, project_tag_path(@project, tag.name), class: 'item-title ref-name'
@@ -24,7 +25,7 @@
.text-secondary
= sprite_icon("rocket", size: 12)
= _("Release")
- = link_to release.name, project_releases_path(@project, anchor: release.tag), class: 'tag-release-link'
+ = link_to release.name, project_releases_path(@project, anchor: release.tag), class: 'gl-text-blue-600!'
- if release.description.present?
.md.gl-mt-3
= markdown_field(release, :description)
@@ -38,5 +39,4 @@
- if can?(current_user, :admin_tag, @project)
= link_to edit_project_tag_release_path(@project, tag.name), class: 'btn btn-edit has-tooltip', title: s_('TagsPage|Edit release notes'), data: { container: "body" } do
= sprite_icon("pencil")
- = link_to project_tag_path(@project, tag.name), class: "btn btn-remove remove-row has-tooltip gl-ml-3 #{protected_tag?(@project, tag) ? 'disabled' : ''}", title: s_('TagsPage|Delete tag'), method: :delete, data: { confirm: s_('TagsPage|Deleting the %{tag_name} tag cannot be undone. Are you sure?') % { tag_name: tag.name }, container: 'body' }, remote: true do
- = sprite_icon("remove")
+ = render 'projects/buttons/remove_tag', project: @project, tag: tag
diff --git a/app/views/projects/tags/destroy.js.haml b/app/views/projects/tags/destroy.js.haml
deleted file mode 100644
index 59d359bbf10..00000000000
--- a/app/views/projects/tags/destroy.js.haml
+++ /dev/null
@@ -1,4 +0,0 @@
-- if @error.present?
- new Flash({ message: '#{escape_javascript(@error)}', type: 'alert' });
-- elsif @repository.tags.empty?
- $('.tags').load(document.URL + ' .nothing-here-block').hide().fadeIn(1000)
diff --git a/app/views/projects/tags/show.html.haml b/app/views/projects/tags/show.html.haml
index 25a560da5c6..d726d2ab233 100644
--- a/app/views/projects/tags/show.html.haml
+++ b/app/views/projects/tags/show.html.haml
@@ -52,8 +52,7 @@
= render 'projects/buttons/download', project: @project, ref: @tag.name
- if can?(current_user, :admin_tag, @project)
.btn-container.controls-item-full
- = link_to project_tag_path(@project, @tag.name), class: "btn btn-icon btn-danger gl-button remove-row has-tooltip #{protected_tag?(@project, @tag) ? 'disabled' : ''}", title: s_('TagsPage|Delete tag'), method: :delete, data: { confirm: s_('TagsPage|Deleting the %{tag_name} tag cannot be undone. Are you sure?') % { tag_name: @tag.name } } do
- = sprite_icon('remove', css_class: 'gl-icon')
+ = render 'projects/buttons/remove_tag', project: @project, tag: @tag
- if @tag.message.present?
%pre.wrap{ data: { qa_selector: 'tag_message_content' } }
diff --git a/app/views/projects/tracings/_tracing_button.html.haml b/app/views/projects/tracings/_tracing_button.html.haml
new file mode 100644
index 00000000000..c9a6afd3761
--- /dev/null
+++ b/app/views/projects/tracings/_tracing_button.html.haml
@@ -0,0 +1,2 @@
+= link_to project_settings_operations_path(@project), title: _('Configure Tracing'), class: 'btn btn-success' do
+ = _('Add Jaeger URL')
diff --git a/app/views/projects/tracings/show.html.haml b/app/views/projects/tracings/show.html.haml
new file mode 100644
index 00000000000..8c9bffc81bf
--- /dev/null
+++ b/app/views/projects/tracings/show.html.haml
@@ -0,0 +1,33 @@
+- @content_class = "limit-container-width" unless fluid_layout
+- page_title _("Tracing")
+
+- if @project.tracing_external_url.present?
+ %h3.page-title= _('Tracing')
+ .gl-alert.gl-alert-info.alert.flex-alert
+ = sprite_icon('information-o', css_class: 'gl-icon gl-alert-icon gl-alert-icon-no-title')
+ .alert-message
+ = _("Your password isn't required to view this page. If a password or any other personal details are requested, please contact your administrator to report abuse.")
+ - jaeger_link = link_to('Jaeger tracing', 'https://www.jaegertracing.io/', target: "_blank", rel: "noreferrer")
+ %p.light= _("GitLab uses %{jaeger_link} to monitor distributed systems.").html_safe % { jaeger_link: jaeger_link }
+
+
+ .card
+ - iframe_permissions = "allow-forms allow-scripts allow-same-origin allow-popups"
+ %iframe.border-0{ src: sanitize(@project.tracing_external_url, scrubber: Rails::Html::TextOnlyScrubber.new), width: '100%', height: 970, sandbox: iframe_permissions }
+- else
+ .row.empty-state
+ .col-12
+ .svg-content
+ = image_tag 'illustrations/monitoring/tracing.svg'
+
+ .col-12
+ .text-content
+ %h4.text-left= _('Troubleshoot and monitor your application with tracing')
+ %p
+ - jaeger_help_url = "https://www.jaegertracing.io/docs/1.7/getting-started/"
+ - link_start_tag = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: jaeger_help_url }
+ - link_end_tag = "#{sprite_icon('external-link', css_class: 'ml-1 vertical-align-middle')}</a>".html_safe
+ = _('To get started, link this page to your Jaeger server, or find out how to %{link_start_tag}install Jaeger%{link_end_tag}').html_safe % { link_start_tag: link_start_tag, link_end_tag: link_end_tag }
+
+ .text-center
+ = render 'tracing_button'
diff --git a/app/views/projects/tree/_tree_header.html.haml b/app/views/projects/tree/_tree_header.html.haml
index 268858f8ff8..dc9fb9e7792 100644
--- a/app/views/projects/tree/_tree_header.html.haml
+++ b/app/views/projects/tree/_tree_header.html.haml
@@ -1,7 +1,3 @@
-- can_collaborate = can_collaborate_with_project?(@project)
-- can_create_mr_from_fork = can?(current_user, :fork_project, @project) && can?(current_user, :create_merge_request_in, @project)
-- can_visit_ide = can_collaborate || current_user&.already_forked?(@project)
-
.tree-ref-container
.tree-ref-holder
= render 'shared/ref_switcher', destination: 'tree', path: @path, show_create: true
@@ -14,13 +10,7 @@
#js-tree-history-link.d-inline-block{ data: { history_link: project_commits_path(@project, @ref) } }
= render 'projects/find_file_link'
-
- - if can_visit_ide || can_create_mr_from_fork
- #js-tree-web-ide-link.d-inline-block{ data: { options: vue_ide_link_data(@project, @ref).to_json } }
- - if !can_visit_ide
- = render 'shared/confirm_fork_modal', fork_path: ide_fork_and_edit_path(@project, @ref, @path)
- - unless current_user&.gitpod_enabled
- = render 'shared/gitpod/enable_gitpod_modal'
+ = render 'shared/web_ide_button', blob: nil
- if show_xcode_link?(@project)
.project-action-button.project-xcode.inline<
diff --git a/app/views/projects/tree/show.html.haml b/app/views/projects/tree/show.html.haml
index 3dd12a7b641..4d8c357cee1 100644
--- a/app/views/projects/tree/show.html.haml
+++ b/app/views/projects/tree/show.html.haml
@@ -1,3 +1,5 @@
+- current_route_path = request.fullpath.match(/-\/tree\/[^\/]+\/(.+$)/).to_a[1]
+- add_page_startup_graphql_call('repository/path_last_commit', { projectPath: @project.full_path, ref: current_ref, path: current_route_path })
- breadcrumb_title _("Repository")
- @content_class = "limit-container-width" unless fluid_layout
diff --git a/app/views/projects/triggers/_index.html.haml b/app/views/projects/triggers/_index.html.haml
index 4e097f345c2..4f39c839630 100644
--- a/app/views/projects/triggers/_index.html.haml
+++ b/app/views/projects/triggers/_index.html.haml
@@ -6,23 +6,26 @@
.card-body
= render "projects/triggers/form", btn_text: "Add trigger"
%hr
- - if @triggers.any?
- .table-responsive.triggers-list
- %table.table
- %thead
- %th
- %strong Token
- %th
- %strong Description
- %th
- %strong Owner
- %th
- %strong Last used
- %th
- = render partial: 'projects/triggers/trigger', collection: @triggers, as: :trigger
+ - if Feature.enabled?(:ci_pipeline_triggers_settings_vue_ui, @project)
+ #js-ci-pipeline-triggers-list.triggers-list{ data: { triggers: @triggers_json } }
- else
- %p.settings-message.text-center.gl-mb-3
- No triggers have been created yet. Add one using the form above.
+ - if @triggers.any?
+ .table-responsive.triggers-list
+ %table.table
+ %thead
+ %th
+ %strong Token
+ %th
+ %strong Description
+ %th
+ %strong Owner
+ %th
+ %strong Last used
+ %th
+ = render partial: 'projects/triggers/trigger', collection: @triggers, as: :trigger
+ - else
+ %p.settings-message.text-center.gl-mb-3{ data: { testid: 'no_triggers_content' } }
+ No triggers have been created yet. Add one using the form above.
.card-footer
diff --git a/app/views/projects/triggers/_trigger.html.haml b/app/views/projects/triggers/_trigger.html.haml
index 579b8ba2766..b25199b405a 100644
--- a/app/views/projects/triggers/_trigger.html.haml
+++ b/app/views/projects/triggers/_trigger.html.haml
@@ -2,7 +2,7 @@
%td
- if trigger.has_token_exposed?
%span= trigger.token
- = clipboard_button(text: trigger.token, title: _("Copy trigger token"))
+ = clipboard_button(text: trigger.token, title: _("Copy trigger token"), testid: 'clipboard-btn')
- else
%span= trigger.short_token
@@ -33,5 +33,5 @@
= link_to edit_project_trigger_path(@project, trigger), method: :get, title: "Edit", class: "btn btn-default btn-sm" do
= sprite_icon('pencil')
- if can?(current_user, :manage_trigger, trigger)
- = link_to project_trigger_path(@project, trigger), data: { confirm: revoke_trigger_confirmation }, method: :delete, title: "Revoke", class: "btn btn-default btn-warning btn-sm btn-trigger-revoke" do
+ = link_to project_trigger_path(@project, trigger), data: { confirm: revoke_trigger_confirmation, testid: 'trigger_revoke_button' }, method: :delete, title: "Revoke", class: "btn btn-default btn-warning btn-sm btn-trigger-revoke" do
= sprite_icon('remove')
diff --git a/app/views/projects/wikis/git_access.html.haml b/app/views/projects/wikis/git_access.html.haml
index 1db4554541d..c166642bae2 100644
--- a/app/views/projects/wikis/git_access.html.haml
+++ b/app/views/projects/wikis/git_access.html.haml
@@ -1,5 +1,6 @@
- @content_class = "limit-container-width" unless fluid_layout
- page_title s_("WikiClone|Git Access"), _("Wiki")
+- add_page_specific_style 'page_bundles/wiki'
.wiki-page-header.top-area.has-sidebar-toggle.py-3.flex-column.flex-lg-row
= wiki_sidebar_toggle_button
diff --git a/app/views/registrations/welcome.html.haml b/app/views/registrations/welcome.html.haml
index 5ad0fbf8fbc..bebcc2152af 100644
--- a/app/views/registrations/welcome.html.haml
+++ b/app/views/registrations/welcome.html.haml
@@ -22,4 +22,4 @@
- if partial_exists? "registrations/welcome/button"
= render "registrations/welcome/button"
- else
- = f.submit _('Get started!'), class: 'btn-register btn btn-block gl-mb-0 gl-p-3', data: { qa_selector: 'get_started_button' }
+ = f.submit _('Get started!'), class: 'btn-register gl-button btn btn-block gl-mb-0 gl-p-3', data: { qa_selector: 'get_started_button' }
diff --git a/app/views/search/_category.html.haml b/app/views/search/_category.html.haml
index d6e38ddd5c6..f094a6f5e3b 100644
--- a/app/views/search/_category.html.haml
+++ b/app/views/search/_category.html.haml
@@ -30,5 +30,6 @@
= search_filter_link 'issues', _("Issues")
= search_filter_link 'merge_requests', _("Merge requests")
= search_filter_link 'milestones', _("Milestones")
+ = render_if_exists 'search/epics_filter_link'
= render_if_exists 'search/category_elasticsearch'
= users
diff --git a/app/views/search/_filter.html.haml b/app/views/search/_filter.html.haml
index bee4aff605f..e7febd4638b 100644
--- a/app/views/search/_filter.html.haml
+++ b/app/views/search/_filter.html.haml
@@ -2,15 +2,14 @@
= hidden_field_tag :group_id, params[:group_id]
- if params[:project_id].present?
= hidden_field_tag :project_id, params[:project_id]
-.dropdown.form-group.mb-lg-0.mx-lg-1
+.dropdown.form-group.mb-lg-0.mx-lg-1{ data: { testid: "group-filter" } }
%label.d-block{ for: "dashboard_search_group" }
= _("Group")
- %button.dropdown-menu-toggle.js-search-group-dropdown.mt-0{ type: "button", id: "dashboard_search_group", data: { toggle: "dropdown", group_id: params[:group_id] } }
- %span.dropdown-toggle-text
- - if @group.present?
- = @group.name
- - else
- = _("Any")
+ %button.dropdown-menu-toggle.gl-display-inline-flex.js-search-group-dropdown.gl-mt-0{ type: "button", id: "dashboard_search_group", data: { toggle: "dropdown", group_id: params[:group_id] } }
+ %span.dropdown-toggle-text.gl-flex-grow-1.str-truncated-100
+ = @group&.name || _("Any")
+ - if @group.present?
+ = link_to sprite_icon("clear"), url_for(safe_params.except(:project_id, :group_id)), class: 'search-clear js-search-clear has-tooltip', title: _('Clear')
= icon("chevron-down")
.dropdown-menu.dropdown-select.dropdown-menu-selectable.dropdown-menu-right
= dropdown_title(_("Filter results by group"))
@@ -21,12 +20,11 @@
.dropdown.project-filter.form-group.mb-lg-0.mx-lg-1
%label.d-block{ for: "dashboard_search_project" }
= _("Project")
- %button.dropdown-menu-toggle.js-search-project-dropdown.mt-0{ type: "button", id: "dashboard_search_project", data: { toggle: "dropdown"} }
- %span.dropdown-toggle-text
- - if @project.present?
- = @project.full_name
- - else
- = _("Any")
+ %button.dropdown-menu-toggle.gl-display-inline-flex.js-search-project-dropdown.gl-mt-0{ type: "button", id: "dashboard_search_project", data: { toggle: "dropdown", target: '.project-filter' } }
+ %span.dropdown-toggle-text.gl-flex-grow-1.str-truncated-100
+ = @project&.full_name || _("Any")
+ - if @project.present?
+ = link_to sprite_icon("clear"), url_for(safe_params.except(:project_id)), class: 'search-clear js-search-clear has-tooltip', title: _('Clear')
= icon("chevron-down")
.dropdown-menu.dropdown-select.dropdown-menu-selectable.dropdown-menu-right
= dropdown_title(_("Filter results by project"))
diff --git a/app/views/search/_form.html.haml b/app/views/search/_form.html.haml
index b29707d391d..c8fa016662f 100644
--- a/app/views/search/_form.html.haml
+++ b/app/views/search/_form.html.haml
@@ -9,8 +9,8 @@
= _("What are you searching for?")
.position-relative
= search_field_tag :search, params[:search], placeholder: _("Search for projects, issues, etc."), class: "form-control search-text-input js-search-input", id: "dashboard_search", autofocus: true, spellcheck: false
- = icon("search", class: "search-icon")
- %button.search-clear.js-search-clear{ class: ("hidden" if !params[:search].present?), type: "button", tabindex: "-1" }
+ = sprite_icon('search', css_class: 'search-icon')
+ %button.search-clear.js-search-clear{ class: [("hidden" if params[:search].blank?), "has-tooltip"], type: "button", tabindex: "-1", title: _('Clear') }
= sprite_icon('clear')
%span.sr-only
= _("Clear search")
diff --git a/app/views/search/_results.html.haml b/app/views/search/_results.html.haml
index e0dbb5135e9..95c378bff7c 100644
--- a/app/views/search/_results.html.haml
+++ b/app/views/search/_results.html.haml
@@ -1,7 +1,7 @@
- if @search_objects.to_a.empty?
+ = render partial: "search/results/filters"
= render partial: "search/results/empty"
= render_if_exists 'shared/promotions/promote_advanced_search'
- = render_if_exists 'search/form_revert_to_basic'
- else
.row-content-block.d-md-flex.text-left.align-items-center
- unless @search_objects.is_a?(Kaminari::PaginatableWithoutCount)
@@ -10,10 +10,9 @@
- if @project
- link_to_project = link_to(@project.full_name, @project, class: 'ml-md-1')
- if @scope == 'blobs'
- - repository_ref = params[:repository_ref].to_s.presence || @project.default_branch
= s_("SearchCodeResults|in")
.mx-md-1
- = render partial: "shared/ref_switcher", locals: { ref: repository_ref, form_path: request.fullpath, field_name: 'repository_ref' }
+ = render partial: "shared/ref_switcher", locals: { ref: repository_ref(@project), form_path: request.fullpath, field_name: 'repository_ref' }
= s_('SearchCodeResults|of %{link_to_project}').html_safe % { link_to_project: link_to_project }
- else
= _("in project %{link_to_project}").html_safe % { link_to_project: link_to_project }
@@ -21,8 +20,7 @@
- link_to_group = link_to(@group.name, @group, class: 'ml-md-1')
= _("in group %{link_to_group}").html_safe % { link_to_group: link_to_group }
= render_if_exists 'shared/promotions/promote_advanced_search'
-
- #js-search-filter-by-state{ 'v-cloak': true, data: { scope: @scope, state: params[:state] } }
+ = render partial: "search/results/filters"
.results.gl-mt-3
- if @scope == 'commits'
@@ -34,7 +32,7 @@
.term
= render 'shared/projects/list', projects: @search_objects, pipeline_status: false
- else
- = render partial: "search/results/#{@scope.singularize}", collection: @search_objects
+ = render_if_exists partial: "search/results/#{@scope.singularize}", collection: @search_objects
- if @scope != 'projects'
= paginate_collection(@search_objects)
diff --git a/app/views/search/results/_blob.html.haml b/app/views/search/results/_blob.html.haml
index 6e17a25c713..aeb37022f99 100644
--- a/app/views/search/results/_blob.html.haml
+++ b/app/views/search/results/_blob.html.haml
@@ -1,5 +1,5 @@
- project = blob.project
- return unless project
-- blob_link = project_blob_path(project, tree_join(blob.ref, blob.path))
+- blob_link = project_blob_path(project, tree_join(repository_ref(project), blob.path))
= render partial: 'search/results/blob_data', locals: { blob: blob, project: project, path: blob.path, blob_link: blob_link }
diff --git a/app/views/search/results/_blob_data.html.haml b/app/views/search/results/_blob_data.html.haml
index 27d4dbe1085..d873a15d051 100644
--- a/app/views/search/results/_blob_data.html.haml
+++ b/app/views/search/results/_blob_data.html.haml
@@ -2,7 +2,7 @@
.file-holder
.js-file-title.file-title{ data: { qa_selector: 'file_title_content' } }
= link_to blob_link, data: {track_event: 'click_text', track_label: 'blob_path', track_property: 'search_result'} do
- %i.fa.fa-file
+ = sprite_icon('document')
%strong
= search_blob_title(project, path)
- if blob.data
diff --git a/app/views/search/results/_empty.html.haml b/app/views/search/results/_empty.html.haml
index 6c7c6de1178..3cd1c901f8e 100644
--- a/app/views/search/results/_empty.html.haml
+++ b/app/views/search/results/_empty.html.haml
@@ -1,5 +1,5 @@
.search_box
.search_glyph
%h4
- = icon('search')
+ = sprite_icon('search', size: 24, css_class: 'gl-vertical-align-text-bottom')
= search_entries_empty_message(@scope, @search_term)
diff --git a/app/views/search/results/_filters.html.haml b/app/views/search/results/_filters.html.haml
new file mode 100644
index 00000000000..632d3dfd58c
--- /dev/null
+++ b/app/views/search/results/_filters.html.haml
@@ -0,0 +1,7 @@
+.d-lg-flex.align-items-end
+ #js-search-filter-by-state{ 'v-cloak': true }
+ - if Feature.enabled?(:search_filter_by_confidential, @group)
+ #js-search-filter-by-confidential{ 'v-cloak': true }
+
+ - if %w(issues merge_requests).include?(@scope)
+ %hr.gl-mt-4.gl-mb-4
diff --git a/app/views/search/results/_issue.html.haml b/app/views/search/results/_issue.html.haml
index e0336d98f04..a101e60f297 100644
--- a/app/views/search/results/_issue.html.haml
+++ b/app/views/search/results/_issue.html.haml
@@ -9,6 +9,5 @@
%span.term.str-truncated.gl-font-weight-bold.gl-ml-2= issue.title
.gl-text-gray-500.gl-my-3
= sprintf(s_(' %{project_name}#%{issue_iid} &middot; opened %{issue_created} by %{author}'), { project_name: issue.project.full_name, issue_iid: issue.iid, issue_created: time_ago_with_tooltip(issue.created_at, placement: 'bottom'), author: link_to_member(@project, issue.author, avatar: false) }).html_safe
- - if issue.description.present?
- .description.term.col-sm-10.gl-px-0
- = truncate(issue.description, length: 200)
+ .description.term.col-sm-10.gl-px-0
+ = highlight_and_truncate_issue(issue, @search_term, @search_highlight)
diff --git a/app/views/search/show.html.haml b/app/views/search/show.html.haml
index 18eaccb46b2..3fb91428c56 100644
--- a/app/views/search/show.html.haml
+++ b/app/views/search/show.html.haml
@@ -6,10 +6,9 @@
- page_description(_("%{count} %{scope} for term '%{term}'") % { count: @search_results.formatted_count(@scope), scope: @scope, term: @search_term })
- page_card_attributes("Namespace" => @group&.full_path, "Project" => @project&.full_path)
-.page-title-holder.d-sm-flex.align-items-sm-center
- %h1.page-title<
- = _('Search')
- = render_if_exists 'search/form_elasticsearch', attrs: { class: 'ml-sm-auto' }
+.page-title-holder.d-flex.flex-wrap.justify-content-between
+ %h1.page-title.mr-3= _('Search')
+ = render_if_exists 'search/form_elasticsearch', attrs: { class: 'mb-2 mb-sm-0 align-self-center' }
.gl-mt-3
= render 'search/form'
diff --git a/app/views/shared/_auto_devops_implicitly_enabled_banner.html.haml b/app/views/shared/_auto_devops_implicitly_enabled_banner.html.haml
index d378e6cb22c..6f70c927147 100644
--- a/app/views/shared/_auto_devops_implicitly_enabled_banner.html.haml
+++ b/app/views/shared/_auto_devops_implicitly_enabled_banner.html.haml
@@ -1,13 +1,13 @@
- if show_auto_devops_implicitly_enabled_banner?(project, current_user)
- .qa-auto-devops-banner.auto-devops-implicitly-enabled-banner.alert.alert-info
- - more_information_link = link_to _('More information'), help_page_path('topics/autodevops/index.md'), target: '_blank', class: 'alert-link'
- - auto_devops_message = s_("AutoDevOps|The Auto DevOps pipeline has been enabled and will be used if no alternative CI configuration file is found. %{more_information_link}") % { more_information_link: more_information_link }
- = auto_devops_message.html_safe
- .alert-link-group
- = link_to _('Settings'), project_settings_ci_cd_path(project), class: 'alert-link'
- |
- = link_to _('Dismiss'), '#', class: 'hide-auto-devops-implicitly-enabled-banner alert-link', data: { project_id: project.id }
+ .qa-auto-devops-banner.auto-devops-implicitly-enabled-banner.gl-alert.gl-alert-info
+ = sprite_icon('information-o', css_class: 'gl-icon gl-alert-icon gl-alert-icon-no-title')
+ %button.js-close.gl-alert-dismiss{ type: 'button', 'aria-label' => _('Dismiss'), class: 'hide-auto-devops-implicitly-enabled-banner alert-link', data: { project_id: project.id } }
+ = sprite_icon('close', css_class: 'gl-icon')
+ .gl-alert-body
+ = s_("AutoDevOps|The Auto DevOps pipeline has been enabled and will be used if no alternative CI configuration file is found.")
- unless Gitlab.config.registry.enabled
%div
- = icon('exclamation-triangle')
= _('Container registry is not enabled on this GitLab instance. Ask an administrator to enable it in order for Auto DevOps to work.')
+ .gl-alert-actions.gl-mt-3
+ = link_to _('Settings'), project_settings_ci_cd_path(project), class: 'alert-link btn gl-button btn-info'
+ = link_to _('More information'), help_page_path('topics/autodevops/index.md'), target: '_blank', class: 'alert-link btn gl-button btn-default gl-ml-2'
diff --git a/app/views/shared/_confirm_fork_modal.html.haml b/app/views/shared/_confirm_fork_modal.html.haml
index f2a193e0bbc..1390d821899 100644
--- a/app/views/shared/_confirm_fork_modal.html.haml
+++ b/app/views/shared/_confirm_fork_modal.html.haml
@@ -1,4 +1,4 @@
-#modal-confirm-fork.modal{ data: { qa_selector: 'confirm_fork_modal' } }
+.modal{ data: { qa_selector: 'confirm_fork_modal'}, id: "modal-confirm-fork-#{type}" }
.modal-dialog
.modal-content
.modal-header
diff --git a/app/views/shared/_confirm_modal.html.haml b/app/views/shared/_confirm_modal.html.haml
index dc95bcdc756..ecb462205b0 100644
--- a/app/views/shared/_confirm_modal.html.haml
+++ b/app/views/shared/_confirm_modal.html.haml
@@ -17,5 +17,5 @@
.form-group
= text_field_tag 'confirm_name_input', '', class: 'form-control js-confirm-danger-input qa-confirm-input'
- .form-actions.gl-display-flex.gl-justify-content-end
+ .form-actions
= submit_tag _('Confirm'), class: "btn btn-danger js-confirm-danger-submit qa-confirm-button"
diff --git a/app/views/shared/_delete_label_modal.html.haml b/app/views/shared/_delete_label_modal.html.haml
index ffc34ff34c3..8d761e3b9c4 100644
--- a/app/views/shared/_delete_label_modal.html.haml
+++ b/app/views/shared/_delete_label_modal.html.haml
@@ -17,4 +17,4 @@
label.destroy_path,
title: _('Delete'),
method: :delete,
- class: 'btn btn-remove'
+ class: 'gl-button btn btn-danger'
diff --git a/app/views/shared/_issuable_meta_data.html.haml b/app/views/shared/_issuable_meta_data.html.haml
index 3eb27f002ef..f21ec45eefb 100644
--- a/app/views/shared/_issuable_meta_data.html.haml
+++ b/app/views/shared/_issuable_meta_data.html.haml
@@ -5,21 +5,23 @@
- issuable_mr = @issuable_meta_data[issuable.id].merge_requests_count
- if issuable_mr > 0
- %li.issuable-mr.d-none.d-sm-block.has-tooltip{ title: _('Related merge requests') }
+ %li.issuable-mr.gl-display-none.gl-display-sm-block.has-tooltip{ title: _('Related merge requests') }
= image_tag('icon-merge-request-unmerged.svg', class: 'icon-merge-request-unmerged')
= issuable_mr
- if upvotes > 0
- %li.issuable-upvotes.d-none.d-sm-block.has-tooltip{ title: _('Upvotes') }
- = sprite_icon('thumb-up', css_class: "vertical-align-middle")
+ %li.issuable-upvotes.gl-display-none.gl-display-sm-block.has-tooltip{ title: _('Upvotes') }
+ = sprite_icon('thumb-up', css_class: "gl-vertical-align-middle")
= upvotes
- if downvotes > 0
- %li.issuable-downvotes.d-none.d-sm-block.has-tooltip{ title: _('Downvotes') }
- = sprite_icon('thumb-down', css_class: "vertical-align-middle")
+ %li.issuable-downvotes.gl-display-none.gl-display-sm-block.has-tooltip{ title: _('Downvotes') }
+ = sprite_icon('thumb-down', css_class: "gl-vertical-align-middle")
= downvotes
-%li.issuable-comments.d-none.d-sm-block
+= render_if_exists 'shared/issuable/blocking_issues_count', issuable: issuable
+
+%li.issuable-comments.gl-display-none.gl-display-sm-block
= link_to issuable_path, class: ['has-tooltip', ('no-comments' if note_count == 0)], title: _('Comments') do
= sprite_icon('comments', css_class: 'gl-vertical-align-text-bottom')
= note_count
diff --git a/app/views/shared/_label.html.haml b/app/views/shared/_label.html.haml
index c4b7ef481fd..1dadb4384b9 100644
--- a/app/views/shared/_label.html.haml
+++ b/app/views/shared/_label.html.haml
@@ -9,9 +9,6 @@
%li.label-list-item{ id: label_css_id, data: { id: label.id } }
= render "shared/label_row", label: label, force_priority: force_priority
%ul.label-actions-list
- - if @project
- %li.inline
- .label-badge.label-badge-gray= label.model_name.human.capitalize
- if can?(current_user, :admin_label, @project)
%li.inline.js-toggle-priority{ data: { url: remove_priority_project_label_path(@project, label),
dom_id: dom_id(label), type: label.type } }
diff --git a/app/views/shared/_label_full_path.html.haml b/app/views/shared/_label_full_path.html.haml
new file mode 100644
index 00000000000..fd67bbbbd10
--- /dev/null
+++ b/app/views/shared/_label_full_path.html.haml
@@ -0,0 +1,4 @@
+- full_path = label.subject_full_name
+
+.label-badge.gl-bg-gray-50.gl-max-w-full.gl-text-truncate{ title: full_path }
+ = full_path
diff --git a/app/views/shared/_label_row.html.haml b/app/views/shared/_label_row.html.haml
index 3d2ae772135..9c9ac5f7b2c 100644
--- a/app/views/shared/_label_row.html.haml
+++ b/app/views/shared/_label_row.html.haml
@@ -3,23 +3,28 @@
- show_label_issues_link = subject_or_group_defined && show_label_issuables_link?(label, :issues)
- show_label_merge_requests_link = subject_or_group_defined && show_label_issuables_link?(label, :merge_requests)
-.label-name
+.label-name.gl-flex-shrink-0.gl-mt-2.gl-mr-3
= render_label(label, tooltip: false)
-.label-description
- .label-description-wrapper
- - if label.description.present?
- .description-text
+.label-description.gl-flex-grow-1.gl-overflow-hidden
+ .gl-display-flex.gl-align-items-center.gl-flex-wrap.gl-mt-2
+ .description-text.gl-flex-grow-1.gl-overflow-hidden
+ - if label.description.present?
= markdown_field(label, :description)
- %ul.label-links
+ - elsif show_labels_full_path?(@project, @group)
+ = render 'shared/label_full_path', label: label
+ %ul.label-links.gl-m-0.gl-p-0.gl-white-space-nowrap
- if show_label_issues_link
- %li.label-link-item.inline
- = link_to_label(label) { _('Issues') }
+ %li.inline
+ = link_to_label(label, css_class: 'gl-text-blue-600!') { _('Issues') }
- if show_label_merge_requests_link
&middot;
- %li.label-link-item.inline
- = link_to_label(label, type: :merge_request) { _('Merge requests') }
+ %li.inline
+ = link_to_label(label, type: :merge_request, css_class: 'gl-text-blue-600!') { _('Merge requests') }
+ = render_if_exists 'shared/label_row_epics_link', label: label
- if force_priority
&middot;
- %li.label-link-item.priority-badge.js-priority-badge.inline.gl-ml-3
- .label-badge.label-badge-blue= _('Prioritized label')
- = render_if_exists 'shared/label_row_epics_link', label: label
+ %li.js-priority-badge.inline.gl-ml-3
+ .label-badge.gl-bg-blue-50= _('Prioritized label')
+ - if label.description.present? && show_labels_full_path?(@project, @group)
+ .gl-mt-3
+ = render 'shared/label_full_path', label: label
diff --git a/app/views/shared/_new_project_item_select.html.haml b/app/views/shared/_new_project_item_select.html.haml
index 47fb38d979d..4340a34dc26 100644
--- a/app/views/shared/_new_project_item_select.html.haml
+++ b/app/views/shared/_new_project_item_select.html.haml
@@ -1,7 +1,7 @@
- if any_projects?(@projects)
- .project-item-select-holder.btn-group
- %a.btn.btn-success.new-project-item-link.qa-new-project-item-link{ href: '', data: { label: local_assigns[:label], type: local_assigns[:type] } }
+ .project-item-select-holder.btn-group.gl-ml-auto.gl-mr-auto.gl-py-3.gl-relative.gl-display-flex.gl-overflow-hidden
+ %a.btn.gl-button.btn-success.new-project-item-link.block-truncated.qa-new-project-item-link{ href: '', data: { label: local_assigns[:label], type: local_assigns[:type] }, class: "gl-m-0!" }
= loading_icon(color: 'light')
- = project_select_tag :project_path, class: "project-item-select", data: { include_groups: local_assigns[:include_groups], order_by: 'last_activity_at', relative_path: local_assigns[:path], with_shared: local_assigns[:with_shared], include_projects_in_subgroups: local_assigns[:include_projects_in_subgroups] }, with_feature_enabled: local_assigns[:with_feature_enabled]
- %button.btn.btn-success.new-project-item-select-button.qa-new-project-item-select-button.gl-p-0
+ = project_select_tag :project_path, class: "project-item-select gl-absolute gl-visibility-hidden", data: { include_groups: local_assigns[:include_groups], order_by: 'last_activity_at', relative_path: local_assigns[:path], with_shared: local_assigns[:with_shared], include_projects_in_subgroups: local_assigns[:include_projects_in_subgroups] }, with_feature_enabled: local_assigns[:with_feature_enabled]
+ %button.btn.dropdown-toggle.btn-success.btn-md.gl-button.gl-dropdown-toggle.dropdown-toggle-split.new-project-item-select-button.qa-new-project-item-select-button.gl-p-0.gl-w-100{ class: "gl-m-0!", 'aria-label': _('Toggle project select') }
= sprite_icon('chevron-down')
diff --git a/app/views/shared/_user_dropdown_instance_review.html.haml b/app/views/shared/_user_dropdown_instance_review.html.haml
new file mode 100644
index 00000000000..18bfb5d7e3e
--- /dev/null
+++ b/app/views/shared/_user_dropdown_instance_review.html.haml
@@ -0,0 +1,6 @@
+- return unless instance_review_permitted?
+
+%li.divider
+%li
+ = link_to admin_instance_review_path, target: '_blank', class: 'text-nowrap' do
+ = _("Get a free instance review")
diff --git a/app/views/shared/_web_ide_button.html.haml b/app/views/shared/_web_ide_button.html.haml
new file mode 100644
index 00000000000..75f5b8647f2
--- /dev/null
+++ b/app/views/shared/_web_ide_button.html.haml
@@ -0,0 +1,10 @@
+- type = blob ? 'blob' : 'tree'
+
+.d-inline-block{ data: { options: web_ide_button_data(blob: blob).to_json }, id: "js-#{type}-web-ide-link" }
+
+- if show_edit_button?
+ = render 'shared/confirm_fork_modal', fork_path: fork_and_edit_path(@project, @ref, @path), type: 'edit'
+- if show_web_ide_button?
+ = render 'shared/confirm_fork_modal', fork_path: ide_fork_and_edit_path(@project, @ref, @path), type: 'webide'
+- if show_gitpod_button?
+ = render 'shared/gitpod/enable_gitpod_modal'
diff --git a/app/views/shared/boards/_show.html.haml b/app/views/shared/boards/_show.html.haml
index e5808bfe878..c3137120034 100644
--- a/app/views/shared/boards/_show.html.haml
+++ b/app/views/shared/boards/_show.html.haml
@@ -8,6 +8,7 @@
- @content_class = "issue-boards-content js-focus-mode-board"
- breadcrumb_title _("Issue Boards")
- page_title("#{board.name}", _("Boards"))
+- add_page_specific_style 'page_bundles/boards'
- content_for :page_specific_javascripts do
@@ -35,7 +36,7 @@
":disabled" => "disabled",
":key" => "list.id" }
= render "shared/boards/components/sidebar", group: group
- = render_if_exists 'shared/boards/components/board_settings_sidebar'
+ %board-settings-sidebar{ ":can-admin-list" => can_admin_list }
- if @project
%board-add-issues-modal{ "new-issue-path" => new_project_issue_path(@project),
"milestone-path" => milestones_filter_dropdown_path,
diff --git a/app/views/shared/deploy_keys/_project_group_form.html.haml b/app/views/shared/deploy_keys/_project_group_form.html.haml
index 815967b0372..179ec33ee65 100644
--- a/app/views/shared/deploy_keys/_project_group_form.html.haml
+++ b/app/views/shared/deploy_keys/_project_group_form.html.haml
@@ -20,5 +20,5 @@
%p.light.gl-mb-0
= _('Allow this key to push to repository as well? (Default only allows pull access.)')
- .form-group.row.gl-display-flex.gl-justify-content-end
+ .form-group.row
= f.submit _("Add key"), class: "btn-success btn"
diff --git a/app/views/shared/deploy_tokens/_form.html.haml b/app/views/shared/deploy_tokens/_form.html.haml
index cc5addaa3a0..da634d37c55 100644
--- a/app/views/shared/deploy_tokens/_form.html.haml
+++ b/app/views/shared/deploy_tokens/_form.html.haml
@@ -46,5 +46,5 @@
= label_tag ("deploy_token_write_package_registry"), 'write_package_registry', class: 'label-bold form-check-label'
.text-secondary= s_('DeployTokens|Allows write access to the package registry')
- .gl-mt-3.gl-display-flex.gl-justify-content-end
+ .gl-mt-3
= f.submit s_('DeployTokens|Create deploy token'), class: 'btn btn-success qa-create-deploy-token'
diff --git a/app/views/shared/icons/_next_discussion.svg b/app/views/shared/icons/_next_discussion.svg
deleted file mode 100644
index 43559a60cb0..00000000000
--- a/app/views/shared/icons/_next_discussion.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg viewBox="0 0 20 19" ><path d="M15.21 7.783h-3.317c-.268 0-.472.218-.472.486v.953c0 .28.212.486.473.486h3.318v1.575c0 .36.233.452.52.23l3.06-2.37c.274-.213.286-.582 0-.804l-3.06-2.37c-.275-.213-.52-.12-.52.23v1.583zm.57-3.66c-1.558-1.22-3.783-1.98-6.254-1.98C4.816 2.143 1 4.91 1 8.333c0 1.964 1.256 3.715 3.216 4.846-.447 1.615-1.132 2.195-1.732 2.882-.142.174-.304.32-.256.56v.01c.047.213.218.368.41.368h.046c.37-.048.743-.116 1.085-.213 1.645-.425 3.13-1.22 4.377-2.34.447.048.913.077 1.38.077 2.092 0 4.01-.546 5.492-1.454-.416-.208-.798-.475-1.134-.792-1.227.63-2.743 1.008-4.36 1.008-.41 0-.828-.03-1.237-.078l-.543-.058-.41.368c-.78.696-1.655 1.248-2.616 1.654.248-.445.486-.977.667-1.664l.257-.928-.828-.484c-1.646-.948-2.598-2.32-2.598-3.763 0-2.69 3.35-4.952 7.308-4.952 1.893 0 3.647.518 4.962 1.353.393-.266.827-.473 1.29-.61z" /></svg>
diff --git a/app/views/shared/issuable/_approved_by_dropdown.html.haml b/app/views/shared/issuable/_approved_by_dropdown.html.haml
new file mode 100644
index 00000000000..8014545ab85
--- /dev/null
+++ b/app/views/shared/issuable/_approved_by_dropdown.html.haml
@@ -0,0 +1,16 @@
+#js-dropdown-approved-by.filtered-search-input-dropdown-menu.dropdown-menu
+ %ul{ data: { dropdown: true } }
+ %li.filter-dropdown-item{ data: { value: 'None' } }
+ %button.btn.btn-link{ type: 'button' }
+ = _('None')
+ %li.filter-dropdown-item{ data: { value: 'Any' } }
+ %button.btn.btn-link{ type: 'button' }
+ = _('Any')
+ %li.divider.droplab-item-ignore
+ - if current_user
+ = render 'shared/issuable/user_dropdown_item',
+ user: current_user
+ %ul.filter-dropdown{ data: { dynamic: true, dropdown: true } }
+ = render 'shared/issuable/user_dropdown_item',
+ user: User.new(username: '{{username}}', name: '{{name}}'),
+ avatar: { lazy: true, url: '{{avatar_url}}' }
diff --git a/app/views/shared/issuable/_assignees.html.haml b/app/views/shared/issuable/_assignees.html.haml
index 8e46db6dea2..196d0417fb8 100644
--- a/app/views/shared/issuable/_assignees.html.haml
+++ b/app/views/shared/issuable/_assignees.html.haml
@@ -4,7 +4,8 @@
- more_assignees_count = issuable.assignees.size - render_count
- issuable.assignees.take(render_count).each do |assignee| # rubocop: disable CodeReuse/ActiveRecord
- = link_to_member(@project, assignee, name: false, title: "Assigned to :name")
+ = link_to_member(@project, assignee, name: false, title: _("Assigned to %{name}") % { name: assignee.name})
- if more_assignees_count > 0
- %span{ class: 'avatar-counter has-tooltip', data: { container: 'body', placement: 'bottom', 'line-type' => 'old', 'original-title' => "+#{more_assignees_count} more assignees", qa_selector: 'avatar_counter_content' } } +#{more_assignees_count}
+ %span{ class: 'avatar-counter has-tooltip', data: { container: 'body', placement: 'bottom', 'line-type' => 'old', qa_selector: 'avatar_counter_content' }, title: _("+%{more_assignees_count} more assignees") % { more_assignees_count: more_assignees_count} }
+ = _("+%{more_assignees_count}") % { more_assignees_count: more_assignees_count}
diff --git a/app/views/shared/issuable/_close_reopen_button.html.haml b/app/views/shared/issuable/_close_reopen_button.html.haml
index 59d0c46b92f..8365bc6f863 100644
--- a/app/views/shared/issuable/_close_reopen_button.html.haml
+++ b/app/views/shared/issuable/_close_reopen_button.html.haml
@@ -5,18 +5,21 @@
- if defined? warn_before_close
- add_blocked_class = warn_before_close
-- if is_current_user
+- if is_current_user && !issuable.is_a?(MergeRequest)
- if can_update
- %button{ class: "d-none d-sm-none d-md-block btn btn-grouped btn-close js-btn-issue-action #{issuable_button_visibility(issuable, true)} #{(add_blocked_class ? 'btn-issue-blocked' : '')}",
+ %button{ class: "d-none d-md-block btn btn-grouped btn-close js-btn-issue-action #{issuable_button_visibility(issuable, true)} #{(add_blocked_class ? 'btn-issue-blocked' : '')}",
data: { remote: 'true', endpoint: close_issuable_path(issuable), qa_selector: 'close_issue_button' } }
= _("Close %{display_issuable_type}") % { display_issuable_type: display_issuable_type }
- if can_reopen
- %button{ class: "d-none d-sm-none d-md-block btn btn-grouped btn-reopen js-btn-issue-action #{issuable_button_visibility(issuable, false)}",
+ %button{ class: "d-none d-md-block btn btn-grouped btn-reopen js-btn-issue-action #{issuable_button_visibility(issuable, false)}",
data: { remote: 'true', endpoint: reopen_issuable_path(issuable), qa_selector: 'reopen_issue_button' } }
= _("Reopen %{display_issuable_type}") % { display_issuable_type: display_issuable_type }
- else
- if can_update && !are_close_and_open_buttons_hidden
- = render 'shared/issuable/close_reopen_report_toggle', issuable: issuable, warn_before_close: add_blocked_class
+ - if issuable.is_a?(MergeRequest)
+ = render 'shared/issuable/close_reopen_draft_report_toggle', issuable: issuable
+ - else
+ = render 'shared/issuable/close_reopen_report_toggle', issuable: issuable, warn_before_close: add_blocked_class
- else
= link_to _('Report abuse'), new_abuse_report_path(user_id: issuable.author.id, ref_url: issuable_url(issuable)),
- class: 'd-none d-sm-none d-md-block btn btn-grouped btn-close-color', title: _('Report abuse')
+ class: 'd-none d-md-block btn btn-grouped btn-close-color', title: _('Report abuse')
diff --git a/app/views/shared/issuable/_close_reopen_draft_report_toggle.html.haml b/app/views/shared/issuable/_close_reopen_draft_report_toggle.html.haml
new file mode 100644
index 00000000000..bdb53dfe323
--- /dev/null
+++ b/app/views/shared/issuable/_close_reopen_draft_report_toggle.html.haml
@@ -0,0 +1,37 @@
+- display_issuable_type = issuable_display_type(issuable)
+- button_action_class = issuable.closed? ? 'btn-default' : 'btn-warning btn-warning-secondary'
+- button_class = "btn gl-button #{!issuable.closed? && 'js-draft-toggle-button'}"
+- toggle_class = "btn gl-button dropdown-toggle"
+
+.float-left.btn-group.gl-ml-3.issuable-close-dropdown.d-none.d-md-inline-flex.js-issuable-close-dropdown
+ = link_to issuable.closed? ? reopen_issuable_path(issuable) : toggle_draft_issuable_path(issuable), method: :put, class: "#{button_class} #{button_action_class}" do
+ - if issuable.closed?
+ = _('Reopen')
+ = display_issuable_type
+ - else
+ = issuable.work_in_progress? ? _('Mark as ready') : _('Mark as draft')
+
+ - if !issuable.closed? || !issuable_author_is_current_user(issuable)
+ = button_tag type: 'button', class: "#{toggle_class} #{button_action_class}", data: { 'toggle' => 'dropdown' } do
+ %span.sr-only= _('Toggle dropdown')
+ = sprite_icon "angle-down", size: 12
+
+ %ul.js-issuable-close-menu.dropdown-menu.dropdown-menu-right
+ - if issuable.open?
+ %li
+ = link_to close_issuable_path(issuable), method: :put do
+ .description
+ %strong.title
+ = _('Close')
+ = display_issuable_type
+
+ - unless issuable_author_is_current_user(issuable)
+ - unless issuable.closed?
+ %li.divider.droplab-item-ignore
+
+ %li.report-item
+ %a.report-abuse-link{ href: new_abuse_report_path(user_id: issuable.author.id, ref_url: issuable_url(issuable)) }
+ .description
+ %strong.title= _('Report abuse')
+ %p.text
+ = _('Report %{display_issuable_type} that are abusive, inappropriate or spam.') % { display_issuable_type: display_issuable_type.pluralize }
diff --git a/app/views/shared/issuable/_close_reopen_report_toggle.html.haml b/app/views/shared/issuable/_close_reopen_report_toggle.html.haml
index 4c7aee09406..df441e6d0af 100644
--- a/app/views/shared/issuable/_close_reopen_report_toggle.html.haml
+++ b/app/views/shared/issuable/_close_reopen_report_toggle.html.haml
@@ -1,7 +1,7 @@
- display_issuable_type = issuable_display_type(issuable)
- button_action = issuable.closed? ? 'reopen' : 'close'
- display_button_action = button_action.capitalize
-- button_responsive_class = 'd-none d-sm-none d-md-block'
+- button_responsive_class = 'd-none d-md-block'
- button_class = "#{button_responsive_class} btn btn-grouped js-issuable-close-button js-btn-issue-action issuable-close-button"
- toggle_class = "#{button_responsive_class} btn btn-nr dropdown-toggle js-issuable-close-toggle"
- add_blocked_class = false
diff --git a/app/views/shared/issuable/_reviewers.html.haml b/app/views/shared/issuable/_reviewers.html.haml
new file mode 100644
index 00000000000..8e66135a20b
--- /dev/null
+++ b/app/views/shared/issuable/_reviewers.html.haml
@@ -0,0 +1,11 @@
+- max_render = 4
+- reviewers_rendering_overflow = issuable.reviewers.size > max_render
+- render_count = reviewers_rendering_overflow ? max_render - 1 : max_render
+- more_reviewers_count = issuable.reviewers.size - render_count
+
+- issuable.reviewers.take(render_count).each do |reviewer| # rubocop: disable CodeReuse/ActiveRecord
+ = link_to_member(@project, reviewer, name: false, title: _("Review requested from %{name}") % { name: reviewer.name})
+
+- if more_reviewers_count > 0
+ %span{ class: 'avatar-counter has-tooltip', data: { container: 'body', placement: 'bottom', 'line-type' => 'old' }, title: _("+%{more_reviewers_count} more reviewers") % { more_reviewers_count: more_reviewers_count} }
+ = _("+%{more_reviewers_count}") % { more_reviewers_count: more_reviewers_count}
diff --git a/app/views/shared/issuable/_search_bar.html.haml b/app/views/shared/issuable/_search_bar.html.haml
index cd7d792738d..ae79d5e3c3e 100644
--- a/app/views/shared/issuable/_search_bar.html.haml
+++ b/app/views/shared/issuable/_search_bar.html.haml
@@ -1,6 +1,7 @@
- type = local_assigns.fetch(:type)
- board = local_assigns.fetch(:board, nil)
- show_sorting_dropdown = local_assigns.fetch(:show_sorting_dropdown, true)
+- disable_target_branch = local_assigns.fetch(:disable_target_branch, false)
- placeholder = local_assigns[:placeholder] || _('Search or filter results...')
- is_not_boards_modal_or_productivity_analytics = type != :boards_modal && type != :productivity_analytics
- block_css_class = is_not_boards_modal_or_productivity_analytics ? 'row-content-block second-block' : ''
@@ -154,10 +155,16 @@
%li.filter-dropdown-item{ data: { value: 'no', capitalize: true } }
%button.btn.btn-link{ type: 'button' }
= _('No')
- #js-dropdown-target-branch.filtered-search-input-dropdown-menu.dropdown-menu
+ - unless disable_target_branch
+ #js-dropdown-target-branch.filtered-search-input-dropdown-menu.dropdown-menu
+ %ul.filter-dropdown{ data: { dynamic: true, dropdown: true } }
+ %li.filter-dropdown-item
+ %button.btn.btn-link.js-data-value.monospace
+ {{title}}
+ #js-dropdown-environment.filtered-search-input-dropdown-menu.dropdown-menu
%ul.filter-dropdown{ data: { dynamic: true, dropdown: true } }
%li.filter-dropdown-item
- %button.btn.btn-link.js-data-value.monospace
+ %button.btn.btn-link.js-data-value{ type: 'button' }
{{title}}
= render_if_exists 'shared/issuable/filter_weight', type: type
diff --git a/app/views/shared/issuable/_sidebar.html.haml b/app/views/shared/issuable/_sidebar.html.haml
index 620e9b5ea31..458703ebc5f 100644
--- a/app/views/shared/issuable/_sidebar.html.haml
+++ b/app/views/shared/issuable/_sidebar.html.haml
@@ -5,204 +5,173 @@
- signed_in = !!issuable_sidebar.dig(:current_user, :id)
- can_edit_issuable = issuable_sidebar.dig(:current_user, :can_edit)
- add_page_startup_api_call "#{issuable_sidebar[:issuable_json_path]}?serializer=sidebar_extras"
-
-- if Feature.enabled?(:vue_issuable_sidebar, @project.group)
- %aside#js-vue-issuable-sidebar{ data: { signed_in: signed_in,
- sidebar_status_class: sidebar_gutter_collapsed_class } }
-- else
- %aside.right-sidebar.js-right-sidebar.js-issuable-sidebar{ data: { signed: { in: signed_in } }, class: sidebar_gutter_collapsed_class, 'aria-live' => 'polite' }
- .issuable-sidebar
- .block.issuable-sidebar-header
- - if signed_in
- %span.issuable-header-text.hide-collapsed.float-left
- = _('To Do')
- %a.gutter-toggle.float-right.js-sidebar-toggle.has-tooltip{ role: "button", href: "#", "aria-label" => _('Toggle sidebar'), title: sidebar_gutter_tooltip_text, data: { container: 'body', placement: 'left', boundary: 'viewport' } }
- = sidebar_gutter_toggle_icon
- - if signed_in
- = render "shared/issuable/sidebar_todo", issuable_sidebar: issuable_sidebar
-
- = form_for issuable_type, url: issuable_sidebar[:issuable_json_path], remote: true, html: { class: 'issuable-context-form inline-update js-issuable-update' } do |f|
- - if signed_in
- .block.todo.hide-expanded
- = render "shared/issuable/sidebar_todo", issuable_sidebar: issuable_sidebar, is_collapsed: true
- .block.assignee.qa-assignee-block
- = render "shared/issuable/sidebar_assignees", issuable_sidebar: issuable_sidebar, assignees: assignees
-
- = render_if_exists 'shared/issuable/sidebar_item_epic', issuable_sidebar: issuable_sidebar
-
- - if issuable_sidebar[:supports_milestone]
- - milestone = issuable_sidebar[:milestone] || {}
- .block.milestone{ data: { qa_selector: 'milestone_block' } }
- .sidebar-collapsed-icon.has-tooltip{ title: sidebar_milestone_tooltip_label(milestone), data: { container: 'body', html: 'true', placement: 'left', boundary: 'viewport' } }
- = sprite_icon('clock')
- %span.milestone-title.collapse-truncated-title
- - if milestone.present?
- = milestone[:title]
- - else
- = _('None')
- .title.hide-collapsed
- = _('Milestone')
- = loading_icon(css_class: 'gl-vertical-align-text-bottom hidden block-loading')
- - if can_edit_issuable
- = link_to _('Edit'), '#', class: 'js-sidebar-dropdown-toggle edit-link float-right', data: { qa_selector: "edit_milestone_link", track_label: "right_sidebar", track_property: "milestone", track_event: "click_edit_button", track_value: "" }
- .value.hide-collapsed
+- reviewers = local_assigns.fetch(:reviewers, nil)
+
+%aside.right-sidebar.js-right-sidebar.js-issuable-sidebar{ data: { signed: { in: signed_in }, issuable_type: issuable_type }, class: sidebar_gutter_collapsed_class, 'aria-live' => 'polite' }
+ .issuable-sidebar
+ .block.issuable-sidebar-header
+ - if signed_in
+ %span.issuable-header-text.hide-collapsed.float-left
+ = _('To Do')
+ %a.gutter-toggle.float-right.js-sidebar-toggle.has-tooltip{ role: "button", href: "#", "aria-label" => _('Toggle sidebar'), title: sidebar_gutter_tooltip_text, data: { container: 'body', placement: 'left', boundary: 'viewport' } }
+ = sidebar_gutter_toggle_icon
+ - if signed_in
+ = render "shared/issuable/sidebar_todo", issuable_sidebar: issuable_sidebar
+
+ = form_for issuable_type, url: issuable_sidebar[:issuable_json_path], remote: true, html: { class: 'issuable-context-form inline-update js-issuable-update' } do |f|
+ - if signed_in
+ .block.todo.hide-expanded
+ = render "shared/issuable/sidebar_todo", issuable_sidebar: issuable_sidebar, is_collapsed: true
+ .block.assignee.qa-assignee-block
+ = render "shared/issuable/sidebar_assignees", issuable_sidebar: issuable_sidebar, assignees: assignees, signed_in: signed_in
+
+ - if Feature.enabled?(:merge_request_reviewers, @project) && reviewers
+ .block.reviewer.qa-reviewer-block
+ = render "shared/issuable/sidebar_reviewers", issuable_sidebar: issuable_sidebar, reviewers: reviewers, signed_in: signed_in
+
+ = render_if_exists 'shared/issuable/sidebar_item_epic', issuable_sidebar: issuable_sidebar
+
+ - if issuable_sidebar[:supports_milestone]
+ - milestone = issuable_sidebar[:milestone] || {}
+ .block.milestone{ data: { qa_selector: 'milestone_block' } }
+ .sidebar-collapsed-icon.has-tooltip{ title: sidebar_milestone_tooltip_label(milestone), data: { container: 'body', html: 'true', placement: 'left', boundary: 'viewport' } }
+ = sprite_icon('clock')
+ %span.milestone-title.collapse-truncated-title
- if milestone.present?
- - milestone_title = milestone[:expired] ? _("%{milestone_name} (Past due)").html_safe % { milestone_name: milestone[:title] } : milestone[:title]
- = link_to milestone_title, milestone[:web_url], class: "bold has-tooltip", title: sidebar_milestone_remaining_days(milestone), data: { container: "body", html: 'true', boundary: 'viewport', qa_selector: 'milestone_link', qa_title: milestone[:title] }
+ = milestone[:title]
- else
- %span.no-value
- = _('None')
-
- .selectbox.hide-collapsed
- = f.hidden_field 'milestone_id', value: milestone[:id], id: nil
- = dropdown_tag('Milestone', options: { title: _('Assign milestone'), toggle_class: 'js-milestone-select js-extra-options', filter: true, dropdown_class: 'dropdown-menu-selectable', placeholder: _('Search milestones'), data: { show_no: true, field_name: "#{issuable_type}[milestone_id]", project_id: issuable_sidebar[:project_id], issuable_id: issuable_sidebar[:id], ability_name: issuable_type, issue_update: issuable_sidebar[:issuable_json_path], use_id: true, default_no: true, selected: milestone[:title], null_default: true, display: 'static' }})
- - if @project.group.present?
- = render_if_exists 'shared/issuable/iteration_select', { can_edit: can_edit_issuable, group_path: @project.group.full_path, project_path: issuable_sidebar[:project_full_path], issue_iid: issuable_sidebar[:iid], issuable_type: issuable_type }
-
- - if issuable_sidebar[:supports_time_tracking]
- #issuable-time-tracker.block
- // Fallback while content is loading
- .title.hide-collapsed
- = _('Time tracking')
- = loading_icon
- - if issuable_sidebar.has_key?(:due_date)
- .block.due_date
- .sidebar-collapsed-icon.has-tooltip{ data: { placement: 'left', container: 'body', html: 'true', boundary: 'viewport' }, title: sidebar_due_date_tooltip_label(issuable_sidebar[:due_date]) }
- = sprite_icon('calendar')
- %span.js-due-date-sidebar-value
- = issuable_sidebar[:due_date].try(:to_s, :medium) || _('None')
- .title.hide-collapsed
- = _('Due date')
- = loading_icon(css_class: 'gl-vertical-align-text-bottom hidden block-loading')
- - if can_edit_issuable
- = link_to _('Edit'), '#', class: 'js-sidebar-dropdown-toggle edit-link float-right', data: { track_label: "right_sidebar", track_property: "due_date", track_event: "click_edit_button", track_value: "" }
- .value.hide-collapsed
- %span.value-content
- - if issuable_sidebar[:due_date]
- %span.bold= issuable_sidebar[:due_date].to_s(:medium)
- - else
- %span.no-value
- = _('None')
- - if can_edit_issuable
- %span.no-value.js-remove-due-date-holder{ class: ("hidden" if issuable_sidebar[:due_date].nil?) }
- \-
- %a.js-remove-due-date{ href: "#", role: "button" }
- = _('remove due date')
+ = _('None')
+ .title.hide-collapsed
+ = _('Milestone')
+ = loading_icon(css_class: 'gl-vertical-align-text-bottom hidden block-loading')
- if can_edit_issuable
- .selectbox.hide-collapsed
- = f.hidden_field :due_date, value: issuable_sidebar[:due_date].try(:strftime, 'yy-mm-dd')
- .dropdown
- %button.dropdown-menu-toggle.js-due-date-select{ type: 'button', data: { toggle: 'dropdown', field_name: "#{issuable_type}[due_date]", ability_name: issuable_type, issue_update: issuable_sidebar[:issuable_json_path], display: 'static' } }
- %span.dropdown-toggle-text
- = _('Due date')
- = icon('chevron-down', 'aria-hidden': 'true')
- .dropdown-menu.dropdown-menu-due-date
- = dropdown_title(_('Due date'))
- = dropdown_content do
- .js-due-date-calendar
-
-
- - if Feature.enabled?(:vue_sidebar_labels, @project)
- .js-sidebar-labels{ data: { allow_label_create: issuable_sidebar.dig(:current_user, :can_admin_label).to_s,
- allow_scoped_labels: issuable_sidebar[:scoped_labels_available].to_s,
- can_edit: can_edit_issuable.to_s,
- iid: issuable_sidebar[:iid],
- issuable_type: issuable_type,
- labels_fetch_path: issuable_sidebar[:project_labels_path],
- labels_manage_path: project_labels_path(@project),
- labels_update_path: issuable_sidebar[:issuable_json_path],
- project_issues_path: issuable_sidebar[:project_issuables_path],
- project_path: @project.full_path,
- selected_labels: issuable_sidebar[:labels].to_json } }
- - else
- - selected_labels = issuable_sidebar[:labels]
- .block.labels
- .sidebar-collapsed-icon.js-sidebar-labels-tooltip{ title: issuable_labels_tooltip(selected_labels), data: { placement: "left", container: "body", boundary: 'viewport' } }
- = sprite_icon('labels')
- %span
- = selected_labels.size
- .title.hide-collapsed
- = _('Labels')
- = loading_icon(css_class: 'gl-vertical-align-text-bottom hidden block-loading')
- - if can_edit_issuable
- = link_to _('Edit'), '#', class: 'js-sidebar-dropdown-toggle edit-link float-right', data: { qa_selector: "edit_labels_link", track_label: "right_sidebar", track_property: "labels", track_event: "click_edit_button", track_value: "" }
- .value.issuable-show-labels.dont-hide.hide-collapsed{ class: ("has-labels" if selected_labels.any?), data: { qa_selector: 'labels_block' } }
- - if selected_labels.any?
- - selected_labels.each do |label_hash|
- = render_label(label_from_hash(label_hash).present(issuable_subject: nil), link: sidebar_label_filter_path(issuable_sidebar[:project_issuables_path], label_hash[:title]), dataset: { qa_selector: 'label', qa_label_name: label_hash[:title] })
+ = link_to _('Edit'), '#', class: 'js-sidebar-dropdown-toggle edit-link float-right', data: { qa_selector: "edit_milestone_link", track_label: "right_sidebar", track_property: "milestone", track_event: "click_edit_button", track_value: "" }
+ .value.hide-collapsed
+ - if milestone.present?
+ - milestone_title = milestone[:expired] ? _("%{milestone_name} (Past due)").html_safe % { milestone_name: milestone[:title] } : milestone[:title]
+ = link_to milestone_title, milestone[:web_url], class: "bold has-tooltip", title: sidebar_milestone_remaining_days(milestone), data: { container: "body", html: 'true', boundary: 'viewport', qa_selector: 'milestone_link', qa_title: milestone[:title] }
+ - else
+ %span.no-value
+ = _('None')
+
+ .selectbox.hide-collapsed
+ = f.hidden_field 'milestone_id', value: milestone[:id], id: nil
+ = dropdown_tag('Milestone', options: { title: _('Assign milestone'), toggle_class: 'js-milestone-select js-extra-options', filter: true, dropdown_class: 'dropdown-menu-selectable', placeholder: _('Search milestones'), data: { show_no: true, field_name: "#{issuable_type}[milestone_id]", project_id: issuable_sidebar[:project_id], issuable_id: issuable_sidebar[:id], ability_name: issuable_type, issue_update: issuable_sidebar[:issuable_json_path], use_id: true, default_no: true, selected: milestone[:title], null_default: true, display: 'static' }})
+ - if @project.group.present?
+ = render_if_exists 'shared/issuable/iteration_select', { can_edit: can_edit_issuable, group_path: @project.group.full_path, project_path: issuable_sidebar[:project_full_path], issue_iid: issuable_sidebar[:iid], issuable_type: issuable_type }
+
+ - if issuable_sidebar[:supports_time_tracking]
+ #issuable-time-tracker.block
+ // Fallback while content is loading
+ .title.hide-collapsed
+ = _('Time tracking')
+ = loading_icon
+ - if issuable_sidebar.has_key?(:due_date)
+ .block.due_date
+ .sidebar-collapsed-icon.has-tooltip{ data: { placement: 'left', container: 'body', html: 'true', boundary: 'viewport' }, title: sidebar_due_date_tooltip_label(issuable_sidebar[:due_date]) }
+ = sprite_icon('calendar')
+ %span.js-due-date-sidebar-value
+ = issuable_sidebar[:due_date].try(:to_s, :medium) || _('None')
+ .title.hide-collapsed
+ = _('Due date')
+ = loading_icon(css_class: 'gl-vertical-align-text-bottom hidden block-loading')
+ - if can_edit_issuable
+ = link_to _('Edit'), '#', class: 'js-sidebar-dropdown-toggle edit-link float-right', data: { track_label: "right_sidebar", track_property: "due_date", track_event: "click_edit_button", track_value: "" }
+ .value.hide-collapsed
+ %span.value-content
+ - if issuable_sidebar[:due_date]
+ %span.bold= issuable_sidebar[:due_date].to_s(:medium)
- else
%span.no-value
= _('None')
+ - if can_edit_issuable
+ %span.no-value.js-remove-due-date-holder{ class: ("hidden" if issuable_sidebar[:due_date].nil?) }
+ \-
+ %a.js-remove-due-date{ href: "#", role: "button" }
+ = _('remove due date')
+ - if can_edit_issuable
.selectbox.hide-collapsed
- - selected_labels.each do |label|
- = hidden_field_tag "#{issuable_type}[label_names][]", label[:id], id: nil
+ = f.hidden_field :due_date, value: issuable_sidebar[:due_date].try(:strftime, 'yy-mm-dd')
.dropdown
- %button.dropdown-menu-toggle.js-label-select.js-multiselect.js-label-sidebar-dropdown{ type: "button", data: sidebar_label_dropdown_data(issuable_type, issuable_sidebar) }
- %span.dropdown-toggle-text{ class: ("is-default" if selected_labels.empty?) }
- = multi_label_name(selected_labels, "Labels")
+ %button.dropdown-menu-toggle.js-due-date-select{ type: 'button', data: { toggle: 'dropdown', field_name: "#{issuable_type}[due_date]", ability_name: issuable_type, issue_update: issuable_sidebar[:issuable_json_path], display: 'static' } }
+ %span.dropdown-toggle-text
+ = _('Due date')
= icon('chevron-down', 'aria-hidden': 'true')
- .dropdown-menu.dropdown-select.dropdown-menu-paging.qa-dropdown-menu-labels.dropdown-menu-labels.dropdown-menu-selectable.dropdown-extended-height
- = render partial: "shared/issuable/label_page_default"
- - if issuable_sidebar.dig(:current_user, :can_admin_label)
- = render partial: "shared/issuable/label_page_create"
-
- = render_if_exists 'shared/issuable/sidebar_weight', issuable_sidebar: issuable_sidebar
-
- - if issuable_sidebar[:supports_severity]
- #js-severity
-
- - if issuable_sidebar.dig(:features_available, :health_status)
- .js-sidebar-status-entry-point
-
- - if issuable_sidebar.has_key?(:confidential)
- %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
-
- %script#js-lock-issue-data{ type: "application/json" }= { is_locked: !!issuable_sidebar[:discussion_locked], is_editable: can_edit_issuable }.to_json.html_safe
- #js-lock-entry-point
-
- .js-sidebar-participants-entry-point
-
- - if signed_in
- .js-sidebar-subscriptions-entry-point
-
- - project_ref = issuable_sidebar[:reference]
- .block.with-sub-blocks
- .project-reference.sub-block
+ .dropdown-menu.dropdown-menu-due-date
+ = dropdown_title(_('Due date'))
+ = dropdown_content do
+ .js-due-date-calendar
+
+
+ .js-sidebar-labels{ data: { allow_label_create: issuable_sidebar.dig(:current_user, :can_admin_label).to_s,
+ allow_scoped_labels: issuable_sidebar[:scoped_labels_available].to_s,
+ can_edit: can_edit_issuable.to_s,
+ iid: issuable_sidebar[:iid],
+ issuable_type: issuable_type,
+ labels_fetch_path: issuable_sidebar[:project_labels_path],
+ labels_manage_path: project_labels_path(@project),
+ labels_update_path: issuable_sidebar[:issuable_json_path],
+ project_issues_path: issuable_sidebar[:project_issuables_path],
+ project_path: @project.full_path,
+ selected_labels: issuable_sidebar[:labels].to_json } }
+
+ = render_if_exists 'shared/issuable/sidebar_weight', issuable_sidebar: issuable_sidebar
+
+ - if issuable_sidebar[:supports_severity]
+ #js-severity
+
+ - if issuable_sidebar.dig(:features_available, :health_status)
+ .js-sidebar-status-entry-point
+
+ - if issuable_sidebar.has_key?(:confidential)
+ %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
+
+ %script#js-lock-issue-data{ type: "application/json" }= { is_locked: !!issuable_sidebar[:discussion_locked], is_editable: can_edit_issuable }.to_json.html_safe
+ #js-lock-entry-point
+
+ .js-sidebar-participants-entry-point
+
+ - if signed_in
+ .js-sidebar-subscriptions-entry-point
+
+ - project_ref = issuable_sidebar[:reference]
+ .block.with-sub-blocks
+ .project-reference.sub-block
+ .sidebar-collapsed-icon.dont-change-state
+ = clipboard_button(text: project_ref, title: _('Copy reference'), placement: "left", boundary: 'viewport')
+ .cross-project-reference.hide-collapsed
+ %span
+ = _('Reference:')
+ %cite{ title: project_ref }
+ = project_ref
+ = clipboard_button(text: project_ref, title: _('Copy reference'), placement: "left", boundary: 'viewport')
+ - if issuable_type == 'merge_request'
+ .sidebar-source-branch.sub-block
.sidebar-collapsed-icon.dont-change-state
- = clipboard_button(text: project_ref, title: _('Copy reference'), placement: "left", boundary: 'viewport')
- .cross-project-reference.hide-collapsed
+ = clipboard_button(text: source_branch, title: _('Copy branch name'), placement: "left", boundary: 'viewport')
+ .sidebar-mr-source-branch.hide-collapsed
%span
- = _('Reference:')
- %cite{ title: project_ref }
- = project_ref
- = clipboard_button(text: project_ref, title: _('Copy reference'), placement: "left", boundary: 'viewport')
- - if issuable_type == 'merge_request'
- .sidebar-source-branch.sub-block
- .sidebar-collapsed-icon.dont-change-state
- = clipboard_button(text: source_branch, title: _('Copy branch name'), placement: "left", boundary: 'viewport')
- .sidebar-mr-source-branch.hide-collapsed
- %span
- = _('Source branch: %{source_branch_open}%{source_branch}%{source_branch_close}').html_safe % { source_branch_open: "<cite class='ref-name' title='#{source_branch}'>".html_safe, source_branch_close: "</cite>".html_safe, source_branch: source_branch }
- = clipboard_button(text: source_branch, title: _('Copy branch name'), placement: "left", boundary: 'viewport')
-
- - 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') }
- = custom_icon('icon_arrow_right')
- .dropdown.sidebar-move-issue-dropdown.hide-collapsed
- %button.btn.btn-default.btn-block.js-sidebar-dropdown-toggle.js-move-issue{ type: 'button',
- data: { toggle: 'dropdown', display: 'static', track_label: "right_sidebar", track_property: "move_issue", track_event: "click_button", track_value: "" } }
- = _('Move issue')
- .dropdown-menu.dropdown-menu-selectable.dropdown-extended-height
- = dropdown_title(_('Move issue'))
- = dropdown_filter(_('Search project'), search_id: 'sidebar-move-issue-dropdown-search')
- = dropdown_content
- = dropdown_loading
- = dropdown_footer add_content_class: true do
- %button.btn.btn-success.sidebar-move-issue-confirmation-button.js-move-issue-confirmation-button{ type: 'button', disabled: true }
- = _('Move')
- = loading_icon(css_class: 'gl-vertical-align-text-bottom sidebar-move-issue-confirmation-loading-icon')
-
- -# haml-lint:disable InlineJavaScript
- %script.js-sidebar-options{ type: "application/json" }= issuable_sidebar_options(issuable_sidebar).to_json.html_safe
+ = _('Source branch: %{source_branch_open}%{source_branch}%{source_branch_close}').html_safe % { source_branch_open: "<cite class='ref-name' title='#{source_branch}'>".html_safe, source_branch_close: "</cite>".html_safe, source_branch: source_branch }
+ = clipboard_button(text: source_branch, title: _('Copy branch name'), placement: "left", boundary: 'viewport')
+
+ - 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') }
+ = custom_icon('icon_arrow_right')
+ .dropdown.sidebar-move-issue-dropdown.hide-collapsed
+ %button.btn.btn-default.btn-block.js-sidebar-dropdown-toggle.js-move-issue{ type: 'button',
+ data: { toggle: 'dropdown', display: 'static', track_label: "right_sidebar", track_property: "move_issue", track_event: "click_button", track_value: "" } }
+ = _('Move issue')
+ .dropdown-menu.dropdown-menu-selectable.dropdown-extended-height
+ = dropdown_title(_('Move issue'))
+ = dropdown_filter(_('Search project'), search_id: 'sidebar-move-issue-dropdown-search')
+ = dropdown_content
+ = dropdown_loading
+ = dropdown_footer add_content_class: true do
+ %button.btn.btn-success.sidebar-move-issue-confirmation-button.js-move-issue-confirmation-button{ type: 'button', disabled: true }
+ = _('Move')
+ = loading_icon(css_class: 'gl-vertical-align-text-bottom sidebar-move-issue-confirmation-loading-icon')
+
+ -# haml-lint:disable InlineJavaScript
+ %script.js-sidebar-options{ type: "application/json" }= issuable_sidebar_options(issuable_sidebar).to_json.html_safe
diff --git a/app/views/shared/issuable/_sidebar_assignees.html.haml b/app/views/shared/issuable/_sidebar_assignees.html.haml
index 175713751ef..a7f435edb90 100644
--- a/app/views/shared/issuable/_sidebar_assignees.html.haml
+++ b/app/views/shared/issuable/_sidebar_assignees.html.haml
@@ -1,5 +1,4 @@
- issuable_type = issuable_sidebar[:type]
-- signed_in = !!issuable_sidebar.dig(:current_user, :id)
#js-vue-sidebar-assignees{ data: { field: issuable_type, signed_in: signed_in } }
.title.hide-collapsed
@@ -40,17 +39,25 @@
- data['max-select'] = dropdown_options[:data][:'max-select'] if dropdown_options[:data][:'max-select']
- options[:data].merge!(data)
- - if experiment_enabled?(:invite_members_version_a) && can_import_members?
+ - if directly_invite_members? || indirectly_invite_members?
- options[:dropdown_class] += ' dropdown-extended-height'
- options[:footer_content] = true
- options[:wrapper_class] = 'js-sidebar-assignee-dropdown'
+ - invite_text = _('Invite Members')
+ - track_label = 'edit_assignee'
= dropdown_tag(title, options: options) do
%ul.dropdown-footer-list
%li
- = link_to _('Invite Members'),
- project_project_members_path(@project),
- title: _('Invite Members'),
- data: { 'is-link': true, 'track-event': 'click_invite_members', 'track-label': 'edit_assignee' }
+ - if directly_invite_members?
+ = link_to invite_text,
+ project_project_members_path(@project),
+ title: invite_text,
+ data: { 'is-link': true, 'track-event': 'click_invite_members', 'track-label': track_label }
+ - else
+ .js-invite-member-trigger{ data: { display_text: invite_text, event: 'click_invite_members_version_b', label: track_label } }
- else
= dropdown_tag(title, options: options)
+
+- if indirectly_invite_members?
+ .js-invite-member-modal{ data: { members_path: project_project_members_path(@project, sort: :access_level_desc) } }
diff --git a/app/views/shared/issuable/_sidebar_reviewers.html.haml b/app/views/shared/issuable/_sidebar_reviewers.html.haml
new file mode 100644
index 00000000000..0142c87aeb0
--- /dev/null
+++ b/app/views/shared/issuable/_sidebar_reviewers.html.haml
@@ -0,0 +1,55 @@
+- issuable_type = issuable_sidebar[:type]
+
+#js-vue-sidebar-reviewers{ data: { field: issuable_type, signed_in: signed_in } }
+ .title.hide-collapsed
+ = _('Reviewer')
+ = loading_icon(css_class: 'gl-vertical-align-text-bottom')
+
+.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)
+
+ - options = { toggle_class: 'js-reviewer-search js-author-search',
+ title: _('Request review from'),
+ filter: true,
+ dropdown_class: 'dropdown-menu-user dropdown-menu-selectable dropdown-menu-author',
+ placeholder: _('Search users'),
+ data: { first_user: issuable_sidebar.dig(:current_user, :username),
+ current_user: true,
+ iid: issuable_sidebar[:iid],
+ issuable_type: issuable_type,
+ project_id: issuable_sidebar[:project_id],
+ author_id: issuable_sidebar[:author_id],
+ field_name: "#{issuable_type}[reviewer_ids][]",
+ issue_update: issuable_sidebar[:issuable_json_path],
+ ability_name: issuable_type,
+ null_user: true,
+ display: 'static' } }
+
+ - 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['dropdown-title'] = title
+ - data['dropdown-header'] = dropdown_options[:data][:'dropdown-header']
+ - data['max-select'] = dropdown_options[:data][:'max-select'] if dropdown_options[:data][:'max-select']
+ - options[:data].merge!(data)
+
+ - if experiment_enabled?(:invite_members_version_a) && can_import_members?
+ - options[:dropdown_class] += ' dropdown-extended-height'
+ - options[:footer_content] = true
+ - options[:wrapper_class] = 'js-sidebar-reviewer-dropdown'
+
+ = dropdown_tag(title, options: options) do
+ %ul.dropdown-footer-list
+ %li
+ = link_to _('Invite Members'),
+ project_project_members_path(@project),
+ title: _('Invite Members'),
+ data: { 'is-link': true, 'track-event': 'click_invite_members', 'track-label': 'edit_reviewer' }
+ - else
+ = dropdown_tag(title, options: options)
diff --git a/app/views/shared/issuable/form/_type_selector.html.haml b/app/views/shared/issuable/form/_type_selector.html.haml
index 7a8120d2d02..3347966f39a 100644
--- a/app/views/shared/issuable/form/_type_selector.html.haml
+++ b/app/views/shared/issuable/form/_type_selector.html.haml
@@ -1,4 +1,4 @@
-- return unless issuable.supports_issue_type? && can?(current_user, :admin_issue, @project)
+- return unless issuable.supports_issue_type? && can?(current_user, :create_issue, @project)
.form-group.row.gl-mb-0
= form.label :type, 'Type', class: 'col-form-label col-sm-2'
@@ -20,11 +20,11 @@
%li.js-filter-issuable-type
= link_to new_project_issue_path(@project), class: ("is-active" if issuable.issue?) do
= _("Issue")
- %li.js-filter-issuable-type
+ %li.js-filter-issuable-type{ data: { track: { event: "select_issue_type_incident", label: "select_issue_type_incident_dropdown_option" } } }
= link_to new_project_issue_path(@project, { issuable_template: 'incident', issue: { issue_type: 'incident' } }), class: ("is-active" if issuable.incident?) do
= _("Incident")
- if issuable.incident?
%p.form-text.text-muted
- - incident_docs_url = help_page_path('operations/incident_management/incidents.md', anchor: 'create-and-manage-incidents-in-gitlab')
+ - incident_docs_url = help_page_path('operations/incident_management/incidents.md')
- incident_docs_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: incident_docs_url }
= _('A %{incident_docs_start}modified issue%{incident_docs_end} to guide the resolution of incidents.').html_safe % { incident_docs_start: incident_docs_start, incident_docs_end: '</a>'.html_safe }
diff --git a/app/views/shared/labels/_form.html.haml b/app/views/shared/labels/_form.html.haml
index 78ff225daad..2df6c3a6afd 100644
--- a/app/views/shared/labels/_form.html.haml
+++ b/app/views/shared/labels/_form.html.haml
@@ -28,7 +28,7 @@
= render_suggested_colors
.form-actions
- if @label.persisted?
- = f.submit 'Save changes', class: 'btn btn-success js-save-button'
+ = f.submit 'Save changes', class: 'btn gl-button btn-success js-save-button'
- else
- = f.submit 'Create label', class: 'btn btn-success js-save-button qa-label-create-button'
- = link_to 'Cancel', back_path, class: 'btn btn-cancel'
+ = f.submit 'Create label', class: 'btn gl-button btn-success js-save-button qa-label-create-button'
+ = link_to 'Cancel', back_path, class: 'btn gl-button btn-cancel'
diff --git a/app/views/shared/labels/_nav.html.haml b/app/views/shared/labels/_nav.html.haml
index d613ea466fa..6d1d422f227 100644
--- a/app/views/shared/labels/_nav.html.haml
+++ b/app/views/shared/labels/_nav.html.haml
@@ -15,10 +15,10 @@
.input-group
= search_field_tag :search, params[:search], { placeholder: _('Filter'), id: 'label-search', class: 'form-control search-text-input input-short', spellcheck: false, autofocus: true }
%span.input-group-append
- %button.btn.btn-default{ type: "submit", "aria-label" => _('Submit search') }
- = icon("search")
+ %button.btn.gl-button.btn-default{ type: "submit", "aria-label" => _('Submit search') }
+ = sprite_icon('search')
= render 'shared/labels/sort_dropdown'
- if labels_or_filters && can_admin_label && @project
- = link_to _('New label'), new_project_label_path(@project), class: "btn btn-success qa-label-create-new"
+ = link_to _('New label'), new_project_label_path(@project), class: "btn gl-button btn-success qa-label-create-new"
- if labels_or_filters && can_admin_label && @group
- = link_to _('New label'), new_group_label_path(@group), class: "btn btn-success qa-label-create-new"
+ = link_to _('New label'), new_group_label_path(@group), class: "btn gl-button btn-success qa-label-create-new"
diff --git a/app/views/shared/members/_access_request_links.html.haml b/app/views/shared/members/_access_request_links.html.haml
index b4b06640bd9..a983a736a1e 100644
--- a/app/views/shared/members/_access_request_links.html.haml
+++ b/app/views/shared/members/_access_request_links.html.haml
@@ -5,13 +5,13 @@
= link_to link_text, polymorphic_path([:leave, source, :members]),
method: :delete,
data: { confirm: leave_confirmation_message(source), qa_selector: 'leave_group_link' },
- class: 'access-request-link js-leave-link'
+ class: '.gl-pl-3.gl-border-l-1.gl-border-l-solid.gl-border-l-gray-500 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) },
- class: 'access-request-link'
+ class: '.gl-pl-3.gl-border-l-1.gl-border-l-solid.gl-border-l-gray-500'
- elsif source.request_access_enabled && can?(current_user, :request_access, source)
= link_to _('Request Access'), polymorphic_path([:request_access, source, :members]),
method: :post,
- class: 'access-request-link'
+ class: '.gl-pl-3.gl-border-l-1.gl-border-l-solid.gl-border-l-gray-500'
diff --git a/app/views/shared/members/_group.html.haml b/app/views/shared/members/_group.html.haml
index 8e5763842d9..42e12d92a7d 100644
--- a/app/views/shared/members/_group.html.haml
+++ b/app/views/shared/members/_group.html.haml
@@ -6,17 +6,18 @@
-# Note this is just for groups. For individual members please see shared/members/_member
-%li.member.group_member.py-2.px-3.d-flex.flex-column.flex-md-row{ id: dom_id, data: { qa_selector: 'group_row' } }
+%li.member.js-member.group_member.py-2.px-3.d-flex.flex-column.flex-md-row{ id: dom_id, data: { qa_selector: 'group_row' } }
%span.list-item-name.mb-2.m-md-0
= group_icon(group, class: "avatar s40 flex-shrink-0 flex-grow-0", alt: '')
.user-info
= link_to group.full_name, group_path(group), class: 'member'
.cgray
Given access #{time_ago_with_tooltip(group_link.created_at)}
- - if group_link.expires?
- ·
- %span{ class: ('text-warning' if group_link.expires_soon?) }
- = _("Expires in %{expires_at}").html_safe % { expires_at: distance_of_time_in_words_to_now(group_link.expires_at) }
+ %span.js-expires-in{ class: ('gl-display-none' unless group_link.expires?) }
+ &middot;
+ %span.js-expires-in-text{ class: ('text-warning' if group_link.expires_soon?) }
+ - if group_link.expires?
+ = _("Expires in %{expires_at}").html_safe % { expires_at: distance_of_time_in_words_to_now(group_link.expires_at) }
.controls.member-controls.align-items-center
= form_tag group_link_path, method: :put, remote: true, class: 'js-edit-member-form form-group d-sm-flex' do
= hidden_field_tag "group_link[group_access]", group_link.group_access
@@ -43,7 +44,7 @@
= link_to group_link_path,
method: :delete,
data: { confirm: _("Are you sure you want to remove %{group_name}?") % { group_name: group.name }, qa_selector: 'delete_group_access_link' },
- class: 'btn btn-remove m-0 ml-sm-2 align-self-center' do
+ class: 'gl-button btn btn-danger m-0 ml-sm-2 align-self-center' do
%span.d-block.d-sm-none
= _("Delete")
= sprite_icon('remove', css_class: 'd-none d-sm-block')
diff --git a/app/views/shared/members/_member.html.haml b/app/views/shared/members/_member.html.haml
index 7573c2f6d56..164d38986ec 100644
--- a/app/views/shared/members/_member.html.haml
+++ b/app/views/shared/members/_member.html.haml
@@ -8,7 +8,7 @@
-# Note this is just for individual members. For groups please see shared/members/_group
-%li.member.py-2.px-3.d-flex.flex-column{ class: [dom_class(member), ("is-overridden" if override), ("flex-md-row" unless force_mobile_view)], id: dom_id(member), data: { qa_selector: 'member_row' } }
+%li.member.js-member.py-2.px-3.d-flex.flex-column{ class: [dom_class(member), ("is-overridden" if override), ("flex-md-row" unless force_mobile_view)], id: dom_id(member), data: { qa_selector: 'member_row' } }
%span.list-item-name.mb-2.m-md-0
- if user
= image_tag avatar_icon_for_user(user, 40), class: "avatar s40 flex-shrink-0 flex-grow-0", alt: ''
@@ -40,10 +40,11 @@
= _("Requested %{time_ago}").html_safe % { time_ago: time_ago_with_tooltip(member.requested_at) }
- else
= _("Given access %{time_ago}").html_safe % { time_ago: time_ago_with_tooltip(member.created_at) }
- - if member.expires?
- ·
- %span{ class: "#{"text-warning" if member.expires_soon?} has-tooltip", title: member.expires_at.to_time.in_time_zone.to_s(:medium) }
- = _("Expires in %{expires_at}").html_safe % { expires_at: distance_of_time_in_words_to_now(member.expires_at) }
+ %span.js-expires-in{ class: ('gl-display-none' unless member.expires?) }
+ &middot;
+ %span.js-expires-in-text{ class: "has-tooltip#{' text-warning' if member.expires_soon?}", title: (member.expires_at.to_time.in_time_zone.to_s(:medium) if member.expires?) }
+ - if member.expires?
+ = _("Expires in %{expires_at}").html_safe % { expires_at: distance_of_time_in_words_to_now(member.expires_at) }
- else
= image_tag avatar_icon_for_email(member.invite_email, 40), class: "avatar s40 flex-shrink-0 flex-grow-0", alt: ''
diff --git a/app/views/shared/members/update.js.haml b/app/views/shared/members/update.js.haml
deleted file mode 100644
index 55050bd8a15..00000000000
--- a/app/views/shared/members/update.js.haml
+++ /dev/null
@@ -1,6 +0,0 @@
-- member = local_assigns.fetch(:member)
-
-:plain
- var $listItem = $('#{escape_javascript(render('shared/members/member', member: member))}');
- $("##{dom_id(member)} .list-item-name").replaceWith($listItem.find('.list-item-name'));
- gl.utils.localTimeAgo($('.js-timeago'), $("##{dom_id(member)}"));
diff --git a/app/views/shared/milestones/_delete_button.html.haml b/app/views/shared/milestones/_delete_button.html.haml
index e00a10398d3..7a813e110c4 100644
--- a/app/views/shared/milestones/_delete_button.html.haml
+++ b/app/views/shared/milestones/_delete_button.html.haml
@@ -1,8 +1,6 @@
- milestone_url = @milestone.project_milestone? ? project_milestone_path(@project, @milestone) : group_milestone_path(@group, @milestone)
-%button.js-delete-milestone-button.btn.btn-grouped.btn-danger{ data: { toggle: 'modal',
- target: '#delete-milestone-modal',
- milestone_id: @milestone.id,
+%button.js-delete-milestone-button.btn.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,
@@ -11,4 +9,4 @@
= _('Delete')
.spinner.js-loading-icon.hidden
-#delete-milestone-modal
+#js-delete-milestone-modal
diff --git a/app/views/shared/milestones/_issuable.html.haml b/app/views/shared/milestones/_issuable.html.haml
index f8bf3e7ad6a..a62ed009552 100644
--- a/app/views/shared/milestones/_issuable.html.haml
+++ b/app/views/shared/milestones/_issuable.html.haml
@@ -10,8 +10,6 @@
%span
- if show_project_name
%strong #{project.name} &middot;
- - elsif show_full_project_name
- %strong #{project.full_name} &middot;
- if issuable.is_a?(Issue)
= confidential_icon(issuable)
= link_to issuable.title, issuable_url_args, title: issuable.title
diff --git a/app/views/shared/milestones/_issuables.html.haml b/app/views/shared/milestones/_issuables.html.haml
index ee97f0172da..9147e1c50e3 100644
--- a/app/views/shared/milestones/_issuables.html.haml
+++ b/app/views/shared/milestones/_issuables.html.haml
@@ -15,4 +15,4 @@
= render partial: 'shared/milestones/issuable',
collection: issuables,
as: :issuable,
- locals: { show_project_name: show_project_name, show_full_project_name: show_full_project_name }
+ locals: { show_project_name: show_project_name }
diff --git a/app/views/shared/milestones/_issues_tab.html.haml b/app/views/shared/milestones/_issues_tab.html.haml
index dc54eefbaa9..76ef636ec96 100644
--- a/app/views/shared/milestones/_issues_tab.html.haml
+++ b/app/views/shared/milestones/_issues_tab.html.haml
@@ -1,5 +1,4 @@
-- args = { show_project_name: local_assigns.fetch(:show_project_name, false),
- show_full_project_name: local_assigns.fetch(:show_full_project_name, false) }
+- args = { show_project_name: local_assigns.fetch(:show_project_name, false) }
- if display_issues_count_warning?(@milestone)
.flash-container
diff --git a/app/views/shared/milestones/_merge_requests_tab.haml b/app/views/shared/milestones/_merge_requests_tab.haml
index 0dbf2b27c8d..a78440600ad 100644
--- a/app/views/shared/milestones/_merge_requests_tab.haml
+++ b/app/views/shared/milestones/_merge_requests_tab.haml
@@ -1,5 +1,4 @@
-- args = { show_project_name: local_assigns.fetch(:show_project_name, false),
- show_full_project_name: local_assigns.fetch(:show_full_project_name, false) }
+- args = { show_project_name: local_assigns.fetch(:show_project_name, false) }
.row.gl-mt-3
.col-md-3
diff --git a/app/views/shared/milestones/_milestone.html.haml b/app/views/shared/milestones/_milestone.html.haml
index 27b771b281b..f28aa406784 100644
--- a/app/views/shared/milestones/_milestone.html.haml
+++ b/app/views/shared/milestones/_milestone.html.haml
@@ -29,10 +29,10 @@
%div
= render('shared/milestone_expired', milestone: milestone)
- if milestone.group_milestone?
- .label-badge.label-badge-blue.d-inline-block
+ .label-badge.gl-bg-blue-50.d-inline-block
= milestone.group.full_name
- if milestone.project_milestone?
- .label-badge.label-badge-gray.d-inline-block
+ .label-badge.gl-bg-gray-50.d-inline-block
= milestone.project.full_name
.col-sm-4.milestone-progress
diff --git a/app/views/shared/milestones/_sidebar.html.haml b/app/views/shared/milestones/_sidebar.html.haml
index bdacdb23141..d9d7d18c732 100644
--- a/app/views/shared/milestones/_sidebar.html.haml
+++ b/app/views/shared/milestones/_sidebar.html.haml
@@ -32,7 +32,8 @@
.block.due_date
.sidebar-collapsed-icon
- = icon('calendar', 'aria-hidden': 'true')
+ %span{ 'aria-hidden': 'true' }
+ = sprite_icon('calendar')
%span.collapsed-milestone-date
- if milestone.start_date && milestone.due_date
- if milestone.start_date.year == milestone.due_date.year
diff --git a/app/views/shared/milestones/_tabs.html.haml b/app/views/shared/milestones/_tabs.html.haml
index 34f476241c6..33e634c3e7b 100644
--- a/app/views/shared/milestones/_tabs.html.haml
+++ b/app/views/shared/milestones/_tabs.html.haml
@@ -1,14 +1,16 @@
+- show_project_name = local_assigns.fetch(:show_project_name, false)
+
.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)
%ul.nav-links.scrolling-tabs.js-milestone-tabs.nav.nav-tabs
%li.nav-item
- = link_to '#tab-issues', class: 'nav-link active', data: { toggle: 'tab', show: '.tab-issues-buttons' } do
+ = link_to '#tab-issues', class: 'nav-link active', data: { toggle: 'tab', endpoint: milestone_tab_path(milestone, 'issues', show_project_name: show_project_name) } do
= _('Issues')
%span.badge.badge-pill= milestone.issues_visible_to_user(current_user).size
- if milestone.merge_requests_enabled?
%li.nav-item
- = link_to '#tab-merge-requests', class: 'nav-link', data: { toggle: 'tab', endpoint: milestone_tab_path(milestone, 'merge_requests') } do
+ = link_to '#tab-merge-requests', class: 'nav-link', data: { toggle: 'tab', endpoint: milestone_tab_path(milestone, 'merge_requests', show_project_name: show_project_name) } do
= _('Merge Requests')
%span.badge.badge-pill= milestone.merge_requests_visible_to_user(current_user).size
%li.nav-item
@@ -20,20 +22,13 @@
= _('Labels')
%span.badge.badge-pill= milestone.issue_labels_visible_by_user(current_user).count
-- issues = milestone.sorted_issues(current_user)
-- show_project_name = local_assigns.fetch(:show_project_name, false)
-- show_full_project_name = local_assigns.fetch(:show_full_project_name, false)
-
.tab-content.milestone-content
- .tab-pane.active#tab-issues{ data: { sort_endpoint: (sort_issues_project_milestone_path(@project, @milestone) if @project && current_user) } }
- = render 'shared/milestones/issues_tab', issues: issues, show_project_name: show_project_name, show_full_project_name: show_full_project_name
+ .tab-pane.active#tab-issues
+ = render "shared/milestones/tab_loading"
- if milestone.merge_requests_enabled?
.tab-pane#tab-merge-requests
- -# loaded async
= render "shared/milestones/tab_loading"
.tab-pane#tab-participants
- -# loaded async
= render "shared/milestones/tab_loading"
.tab-pane#tab-labels
- -# loaded async
= render "shared/milestones/tab_loading"
diff --git a/app/views/shared/milestones/_top.html.haml b/app/views/shared/milestones/_top.html.haml
index 4d209c30e7b..c37fdf0c98f 100644
--- a/app/views/shared/milestones/_top.html.haml
+++ b/app/views/shared/milestones/_top.html.haml
@@ -7,7 +7,7 @@
= render 'shared/milestones/description', milestone: milestone
- if milestone.complete? && milestone.active?
- .alert.alert-success.gl-mt-3
+ .gl-alert.gl-alert-success.gl-mt-3
%span
= _('All issues for this milestone are closed.')
= group ? _('You may close the milestone now.') : _('Navigate to the project to close the milestone.')
diff --git a/app/views/shared/notes/_edit.html.haml b/app/views/shared/notes/_edit.html.haml
index 84a3ef9d8fe..9cfb3f3b576 100644
--- a/app/views/shared/notes/_edit.html.haml
+++ b/app/views/shared/notes/_edit.html.haml
@@ -1 +1 @@
-%textarea.hidden.js-task-list-field.original-task-list{ data: { update_url: note_url(note) } }= note.note
+%textarea.hidden.js-task-list-field.original-task-list{ data: { update_url: note_url(note), value: note.note } }
diff --git a/app/views/shared/notes/_notes_with_form.html.haml b/app/views/shared/notes/_notes_with_form.html.haml
index 5b7a0b99598..9baa340376b 100644
--- a/app/views/shared/notes/_notes_with_form.html.haml
+++ b/app/views/shared/notes/_notes_with_form.html.haml
@@ -12,7 +12,7 @@
.timeline-entry-inner
.flash-container.timeline-content
- .timeline-icon.d-none.d-sm-none.d-md-block
+ .timeline-icon.d-none.d-md-block
%a.author-link{ href: user_path(current_user) }
= image_tag avatar_icon_for_user(current_user), alt: current_user.to_reference, class: 'avatar s40'
.timeline-content.timeline-content-form
diff --git a/app/views/shared/notifications/_button.html.haml b/app/views/shared/notifications/_button.html.haml
index f2c7ab648c0..d7b53810f76 100644
--- a/app/views/shared/notifications/_button.html.haml
+++ b/app/views/shared/notifications/_button.html.haml
@@ -17,7 +17,7 @@
.js-notification-toggle-btns
%div{ class: ("btn-group" if notification_setting.custom?) }
- if notification_setting.custom?
- %button.dropdown-new.btn.btn-defaul.btn-icon.gl-button.has-tooltip.notifications-btn.text-left#notifications-button{ type: "button", title: button_title, class: "#{btn_class}", "aria-label" => aria_label, data: { container: "body", toggle: "modal", target: "#" + notifications_menu_identifier("modal", notification_setting), display: 'static' } }
+ %button.dropdown-new.btn.btn-default.btn-icon.gl-button.has-tooltip.notifications-btn.text-left#notifications-button{ type: "button", title: button_title, class: "#{btn_class}", "aria-label" => aria_label, data: { container: "body", toggle: "modal", target: "#" + notifications_menu_identifier("modal", notification_setting), display: 'static' } }
= sprite_icon("notifications", css_class: "js-notification-loading")
= notification_title(notification_setting.level)
%button.btn.dropdown-toggle.d-flex{ data: { toggle: "dropdown", target: notifications_menu_identifier("dropdown", notification_setting), flip: "false" } }
diff --git a/app/views/shared/projects/_search_form.html.haml b/app/views/shared/projects/_search_form.html.haml
index 4365e3f6877..7b76d6d789b 100644
--- a/app/views/shared/projects/_search_form.html.haml
+++ b/app/views/shared/projects/_search_form.html.haml
@@ -11,7 +11,7 @@
autofocus: local_assigns[:autofocus]
- if local_assigns[:icon]
- = icon("search", class: "search-icon")
+ = sprite_icon('search', css_class: 'search-icon')
- if params[:sort].present?
= hidden_field_tag :sort, params[:sort]
diff --git a/app/views/shared/runners/_shared_runners_description.html.haml b/app/views/shared/runners/_shared_runners_description.html.haml
new file mode 100644
index 00000000000..b9fb518b1aa
--- /dev/null
+++ b/app/views/shared/runners/_shared_runners_description.html.haml
@@ -0,0 +1,11 @@
+- link = link_to _('MaxBuilds'), 'https://docs.gitlab.com/runner/configuration/advanced-configuration.html#the-runnersmachine-section', target: '_blank'
+
+%h3
+ = _('Shared runners')
+
+.bs-callout.shared-runners-description
+ - if Gitlab::CurrentSettings.shared_runners_text.present?
+ = markdown_field(Gitlab::CurrentSettings.current_application_settings, :shared_runners_text)
+ - else
+ = _('The same shared runner executes code from multiple projects, unless you configure autoscaling with %{link} set to 1 (which it is on GitLab.com).').html_safe % { link: link }
+ = yield
diff --git a/app/views/shared/snippets/_blob.html.haml b/app/views/shared/snippets/_blob.html.haml
deleted file mode 100644
index a2169deb592..00000000000
--- a/app/views/shared/snippets/_blob.html.haml
+++ /dev/null
@@ -1,13 +0,0 @@
-%article.file-holder.snippet-file-content
- .js-file-title.file-title-flex-parent
- = render 'projects/blob/header_content', blob: blob
-
- .file-actions.d-none.d-sm-block
- = render 'projects/blob/viewer_switcher', blob: blob
-
- .btn-group{ role: "group" }<
- = copy_blob_source_button(blob)
- = open_raw_blob_button(blob)
- = download_raw_snippet_button(@snippet)
-
- = render 'projects/blob/content', blob: blob
diff --git a/app/views/shared/snippets/_form.html.haml b/app/views/shared/snippets/_form.html.haml
index 198735df5ee..5f511b35b61 100644
--- a/app/views/shared/snippets/_form.html.haml
+++ b/app/views/shared/snippets/_form.html.haml
@@ -1,56 +1,2 @@
-- if Feature.enabled?(:snippets_edit_vue, default_enabled: true)
- - available_visibility_levels = available_visibility_levels(@snippet)
- #js-snippet-edit.snippet-form{ data: {'project_path': @snippet.project&.full_path, 'snippet-gid': @snippet.new_record? ? '' : @snippet.to_global_id, 'markdown-preview-path': preview_markdown_path(parent), 'markdown-docs-path': help_page_path('user/markdown'), 'visibility-help-link': help_page_path("public_access/public_access"), 'visibility_levels': available_visibility_levels, 'selected_level': snippets_selected_visibility_level(available_visibility_levels, @snippet.visibility_level), 'multiple_levels_restricted': multiple_visibility_levels_restricted? } }
-- else
- .snippet-form-holder
- = form_for @snippet, url: url,
- html: { class: "snippet-form js-requires-input js-quick-submit common-note-form" },
- data: { "snippet-type": @snippet.project_id ? 'project' : 'personal'} do |f|
- = form_errors(@snippet)
-
- .form-group
- = f.label :title, class: 'label-bold'
- = f.text_field :title, class: 'form-control', required: true, autofocus: true, data: { qa_selector: 'snippet_title_field' }
-
- .form-group.js-description-input
- - description_placeholder = s_('Snippets|Optionally add a description about what your snippet does or how to use it...')
- - is_expanded = @snippet.description && !@snippet.description.empty?
- = f.label :description, s_("Snippets|Description (optional)"), class: 'label-bold'
- .js-collapsible-input
- .js-collapsed{ class: ('d-none' if is_expanded) }
- = text_field_tag nil, nil, class: 'form-control', placeholder: description_placeholder, data: { qa_selector: 'description_placeholder' }
- .js-expanded{ class: ('d-none' if !is_expanded) }
- = render layout: 'shared/md_preview', locals: { url: preview_markdown_path(@project), referenced_users: true } do
- = render 'shared/zen', f: f, attr: :description, classes: 'note-textarea', placeholder: description_placeholder, qa_selector: 'snippet_description_field'
- = render 'shared/notes/hints'
-
- .form-group.file-editor
- = f.label :file_name, s_('Snippets|File')
- .file-holder.snippet
- .js-file-title.file-title-flex-parent
- = f.text_field :file_name, placeholder: s_("Snippets|Give your file a name to add code highlighting, e.g. example.rb for Ruby"), class: 'form-control js-snippet-file-name', data: { qa_selector: 'file_name_field' }
- .file-content.code
- #editor{ data: { 'editor-loading': true } }<
- %pre.editor-loading-content= @snippet.content
- = f.hidden_field :content, class: 'snippet-file-content'
-
- .form-group
- .font-weight-bold
- = _('Visibility level')
- = link_to sprite_icon('question-o'), help_page_path('public_access/public_access'), target: '_blank'
- = render 'shared/visibility_level', f: f, visibility_level: @snippet.visibility_level, can_change_visibility_level: true, form_model: @snippet, with_label: false
-
- - if params[:files]
- - params[:files].each_with_index do |file, index|
- = hidden_field_tag "files[]", file, id: "files_#{index}"
-
- .form-actions
- - if @snippet.new_record?
- = f.submit 'Create snippet', class: "btn-success btn", data: { qa_selector: 'submit_button' }
- - else
- = f.submit 'Save changes', class: "btn-success btn", data: { qa_selector: 'submit_button' }
-
- - if @snippet.project_id
- = link_to "Cancel", project_snippets_path(@project), class: "btn btn-cancel"
- - else
- = link_to "Cancel", snippets_path(@project), class: "btn btn-cancel"
+- available_visibility_levels = available_visibility_levels(@snippet)
+#js-snippet-edit.snippet-form{ data: {'project_path': @snippet.project&.full_path, 'snippet-gid': @snippet.new_record? ? '' : @snippet.to_global_id, 'markdown-preview-path': preview_markdown_path(parent), 'markdown-docs-path': help_page_path('user/markdown'), 'visibility-help-link': help_page_path("public_access/public_access"), 'visibility_levels': available_visibility_levels, 'selected_level': snippets_selected_visibility_level(available_visibility_levels, @snippet.visibility_level), 'multiple_levels_restricted': multiple_visibility_levels_restricted? } }
diff --git a/app/views/shared/snippets/_header.html.haml b/app/views/shared/snippets/_header.html.haml
deleted file mode 100644
index a9226117727..00000000000
--- a/app/views/shared/snippets/_header.html.haml
+++ /dev/null
@@ -1,47 +0,0 @@
-.detail-page-header
- .detail-page-header-body
- .snippet-box.has-tooltip.inline.gl-mr-2{ title: snippet_visibility_level_description(@snippet.visibility_level, @snippet), data: { container: "body" } }
- %span.sr-only
- = visibility_level_label(@snippet.visibility_level)
- = visibility_level_icon(@snippet.visibility_level)
- %span.creator
- = s_('Snippets|Authored %{time_ago} by %{author}').html_safe % { time_ago: time_ago_with_tooltip(@snippet.created_at, placement: 'bottom', html_class: 'snippet_updated_ago'), author: link_to_member(@project, @snippet.author, size: 24, author_class: "author item-title", avatar_class: "d-none d-sm-inline") + user_status(@snippet.author) }
-
- .detail-page-header-actions
- - if @snippet.project_id?
- = render "projects/snippets/actions"
- - else
- = render "snippets/actions"
-
-.snippet-header.limited-header-width
- %h2.snippet-title.gl-mt-0.mb-3
- = markdown_field(@snippet, :title)
-
- - if @snippet.description.present?
- .description
- .md
- = markdown_field(@snippet, :description)
- %textarea.hidden.js-task-list-field
- = @snippet.description
-
- - if @snippet.updated_at != @snippet.created_at
- = edited_time_ago_with_tooltip(@snippet, placement: 'bottom', exclude_author: true)
-
- - if @snippet.embeddable?
- .embed-snippet
- .input-group
- .input-group-prepend
- %button.btn.btn-svg.embed-toggle.input-group-text{ 'data-toggle': 'dropdown', type: 'button' }
- %span.js-embed-action= _("Embed")
- = sprite_icon('angle-down', size: 12, css_class: 'caret-down')
- %ul.dropdown-menu.dropdown-menu-selectable.embed-toggle-list
- %li
- %button.js-embed-btn.btn.btn-transparent.is-active{ type: 'button' }
- %strong.embed-toggle-list-item= _("Embed")
- %li
- %button.js-share-btn.btn.btn-transparent{ type: 'button' }
- %strong.embed-toggle-list-item= _("Share")
- = snippet_embed_input(@snippet)
- .input-group-append
- = clipboard_button(title: _('Copy'), class: 'js-clipboard-btn snippet-clipboard-btn btn btn-default', target: '.js-snippet-url-area')
- .clearfix
diff --git a/app/views/shared/snippets/_snippet.html.haml b/app/views/shared/snippets/_snippet.html.haml
index 25e31fd519b..5f0ecb2ee79 100644
--- a/app/views/shared/snippets/_snippet.html.haml
+++ b/app/views/shared/snippets/_snippet.html.haml
@@ -1,7 +1,7 @@
- link_project = local_assigns.fetch(:link_project, false)
- notes_count = @noteable_meta_data[snippet.id].user_notes_count
-%li.snippet-row.py-3
+%li.snippet-row.py-3{ data: { qa_selector: 'snippet_link', qa_snippet_title: snippet.title } }
= image_tag avatar_icon_for_user(snippet.author), class: "avatar s40 d-none d-sm-block", alt: ''
.title
diff --git a/app/views/shared/web_hooks/_form.html.haml b/app/views/shared/web_hooks/_form.html.haml
index 96da5136908..9c60201412c 100644
--- a/app/views/shared/web_hooks/_form.html.haml
+++ b/app/views/shared/web_hooks/_form.html.haml
@@ -77,7 +77,7 @@
= form.label :deployment_events, class: 'list-label form-check-label ml-1' do
%strong= s_('Webhooks|Deployment events')
%p.text-muted.ml-1
- = s_('Webhooks|This URL will be triggered when a deployment is finished/failed/canceled')
+ = s_('Webhooks|This URL is triggered when a deployment starts, finishes, fails, or is canceled')
.form-group
= form.label :enable_ssl_verification, s_('Webhooks|SSL verification'), class: 'label-bold checkbox'
.form-check
diff --git a/app/views/shared/wikis/_form.html.haml b/app/views/shared/wikis/_form.html.haml
index 66c0f64c32c..dde1b3afa2d 100644
--- a/app/views/shared/wikis/_form.html.haml
+++ b/app/views/shared/wikis/_form.html.haml
@@ -17,10 +17,10 @@
= f.hidden_field :last_commit_sha, value: @page.last_commit_sha
.form-group.row
- .col-sm-12= f.label :title, class: 'control-label-full-width'
- .col-sm-12
+ .col-sm-2.col-form-label= f.label :title, class: 'control-label-full-width'
+ .col-sm-10
= f.text_field :title, class: 'form-control qa-wiki-title-textbox', value: @page.title, required: true, autofocus: !@page.persisted?, placeholder: s_('Wiki|Page title')
- %span.d-inline-block.mw-100.gl-mt-2
+ %span.gl-display-inline-block.gl-max-w-full.gl-mt-2.gl-text-gray-600
= sprite_icon('bulb', size: 12, css_class: 'gl-mr-n1')
- if @page.persisted?
= s_("WikiEditPageTip|Tip: You can move this page by adding the path to the beginning of the title.")
@@ -29,18 +29,18 @@
- else
= s_("WikiNewPageTip|Tip: You can specify the full path for the new file. We will automatically create any missing directories.")
= succeed '.' do
- = link_to _('Learn more'), help_page_path('user/project/wiki/index', anchor: 'creating-a-new-wiki-page'),
+ = link_to _('More information'), help_page_path('user/project/wiki/index', anchor: 'creating-a-new-wiki-page'),
target: '_blank', rel: 'noopener noreferrer'
.form-group.row
- .col-sm-12= f.label :format, class: 'control-label-full-width'
- .col-sm-12
+ .col-sm-2.col-form-label= f.label :format, class: 'control-label-full-width'
+ .col-sm-10
.select-wrapper
= f.select :format, options_for_select(Wiki::MARKUPS, {selected: @page.format}), {}, class: 'form-control select-control'
= icon('chevron-down')
.form-group.row
- .col-sm-12= f.label :content, class: 'control-label-full-width'
- .col-sm-12
+ .col-sm-2.col-form-label= f.label :content, class: 'control-label-full-width'
+ .col-sm-10
= render layout: 'shared/md_preview', locals: { url: wiki_page_path(@wiki, @page, action: :preview_markdown) } do
= render 'shared/zen', f: f, attr: :content, classes: 'note-textarea qa-wiki-content-textarea', placeholder: s_("WikiPage|Write your content or drag files here…")
= render 'shared/notes/hints'
@@ -48,7 +48,7 @@
.clearfix
.error-alert
- .form-text.text-muted
+ .form-text.gl-text-gray-600
= succeed '.' do
- case @page.format.to_s
- when 'rdoc'
@@ -65,15 +65,15 @@
= (s_("WikiMarkdownDocs|More examples are in the %{docs_link}") % { docs_link: markdown_link }).html_safe
.form-group.row
- .col-sm-12= f.label :commit_message, class: 'control-label-full-width'
- .col-sm-12= f.text_field :message, class: 'form-control qa-wiki-message-textbox', rows: 18, value: nil
+ .col-sm-2.col-form-label= f.label :commit_message, class: 'control-label-full-width'
+ .col-sm-10= f.text_field :message, class: 'form-control qa-wiki-message-textbox', rows: 18, value: nil
.form-actions
- if @page && @page.persisted?
= f.submit _("Save changes"), class: 'btn-success btn qa-save-changes-button'
.float-right
- = link_to _("Cancel"), wiki_page_path(@wiki, @page), class: 'btn btn-cancel btn-grouped'
+ = link_to _("Cancel"), wiki_page_path(@wiki, @page), class: 'btn gl-button btn-cancel btn-grouped'
- else
= f.submit s_("Wiki|Create page"), class: 'btn-success btn qa-create-page-button rspec-create-page-button'
.float-right
- = link_to _("Cancel"), wiki_path(@wiki), class: 'btn btn-cancel'
+ = link_to _("Cancel"), wiki_path(@wiki), class: 'btn gl-button btn-cancel'
diff --git a/app/views/shared/wikis/_main_links.html.haml b/app/views/shared/wikis/_main_links.html.haml
index e173ef72d11..8568c36559a 100644
--- a/app/views/shared/wikis/_main_links.html.haml
+++ b/app/views/shared/wikis/_main_links.html.haml
@@ -1,9 +1,6 @@
- if @page&.persisted?
+ = link_to wiki_page_path(@wiki, @page, action: :history), class: "btn gl-button", role: "button", data: { qa_selector: 'page_history_button' } do
+ = s_("Wiki|Page history")
- if can?(current_user, :create_wiki, @wiki.container)
- = link_to wiki_path(@wiki, action: :new), class: "btn btn-success", role: "button", data: { qa_selector: 'new_page_button' } do
+ = link_to wiki_path(@wiki, action: :new), class: "btn gl-button btn-success btn-inverted", role: "button", data: { qa_selector: 'new_page_button' } do
= s_("Wiki|New page")
- = link_to wiki_page_path(@wiki, @page, action: :history), class: "btn", role: "button", data: { qa_selector: 'page_history_button' } do
- = s_("Wiki|Page history")
- - if can?(current_user, :create_wiki, @wiki.container) && @page.latest? && @valid_encoding
- = link_to wiki_page_path(@wiki, @page, action: :edit), class: "btn js-wiki-edit", role: "button", data: { qa_selector: 'edit_page_button' } do
- = _("Edit")
diff --git a/app/views/shared/wikis/_pages_wiki_page.html.haml b/app/views/shared/wikis/_pages_wiki_page.html.haml
index b56ae2bf9b1..fb6f58d044d 100644
--- a/app/views/shared/wikis/_pages_wiki_page.html.haml
+++ b/app/views/shared/wikis/_pages_wiki_page.html.haml
@@ -1,5 +1,5 @@
%li
- = link_to wiki_page.title, wiki_page_path(@wiki, wiki_page), data: { qa_selector: 'wiki_page_link', qa_page_name: wiki_page.slug }
+ = link_to wiki_page.human_title, wiki_page_path(@wiki, wiki_page), data: { qa_selector: 'wiki_page_link', qa_page_name: wiki_page.slug }
%small (#{wiki_page.format})
.float-right
- if wiki_page.last_version
diff --git a/app/views/shared/wikis/_sidebar.html.haml b/app/views/shared/wikis/_sidebar.html.haml
index 54f285671a1..893661755ab 100644
--- a/app/views/shared/wikis/_sidebar.html.haml
+++ b/app/views/shared/wikis/_sidebar.html.haml
@@ -4,10 +4,11 @@
%a.gutter-toggle.float-right.d-block.d-sm-block.d-md-none.js-sidebar-wiki-toggle{ href: "#" }
= sprite_icon('chevron-double-lg-right', css_class: 'gl-icon')
- - git_access_url = wiki_path(@wiki, action: :git_access)
- = link_to git_access_url, class: active_nav_link?(path: 'wikis#git_access') ? 'active' : '', data: { qa_selector: 'clone_repository_link' } do
- = sprite_icon('download', css_class: 'gl-mr-2')
- %span= _("Clone repository")
+ - if @wiki.container.is_a?(Project)
+ - git_access_url = wiki_path(@wiki, action: :git_access)
+ = link_to git_access_url, class: active_nav_link?(path: 'wikis#git_access') ? 'active' : '', data: { qa_selector: 'clone_repository_link' } do
+ = sprite_icon('download', css_class: 'gl-mr-2')
+ %span= _("Clone repository")
.blocks-container
.block.block-first.w-100
@@ -18,5 +19,5 @@
= render @sidebar_wiki_entries, context: 'sidebar'
.block.w-100
- if @sidebar_limited
- = link_to wiki_path(@wiki, action: :pages), class: 'btn btn-block', data: { qa_selector: 'view_all_pages_button' } do
+ = link_to wiki_path(@wiki, action: :pages), class: 'btn gl-button btn-block', data: { qa_selector: 'view_all_pages_button' } do
= s_("Wiki|View All Pages")
diff --git a/app/views/shared/wikis/_wiki_directory.html.haml b/app/views/shared/wikis/_wiki_directory.html.haml
index 21e829d86a6..a492d1e5aa0 100644
--- a/app/views/shared/wikis/_wiki_directory.html.haml
+++ b/app/views/shared/wikis/_wiki_directory.html.haml
@@ -1,4 +1,4 @@
%li{ data: { qa_selector: 'wiki_directory_content' } }
- = wiki_directory.slug
+ = wiki_directory.title
%ul
- = render wiki_directory.pages, context: context
+ = render wiki_directory.entries, context: context
diff --git a/app/views/shared/wikis/diff.html.haml b/app/views/shared/wikis/diff.html.haml
index 6fce3f5894e..68bbbd66f4a 100644
--- a/app/views/shared/wikis/diff.html.haml
+++ b/app/views/shared/wikis/diff.html.haml
@@ -1,4 +1,5 @@
- wiki_page_title @page, _('Changes')
+- add_page_specific_style 'page_bundles/wiki'
- commit = @diffs.diffable
.wiki-page-header.top-area.has-sidebar-toggle.flex-column.flex-lg-row
@@ -12,7 +13,7 @@
= _('Changes')
.nav-controls.pb-md-3.pb-lg-0
- = link_to wiki_page_path(@wiki, @page, action: :history), class: 'btn', role: 'button', data: { qa_selector: 'page_history_button' } do
+ = link_to wiki_page_path(@wiki, @page, action: :history), class: 'btn gl-button', role: 'button', data: { qa_selector: 'page_history_button' } do
= s_('Wiki|Page history')
.page-content-header
diff --git a/app/views/shared/wikis/edit.html.haml b/app/views/shared/wikis/edit.html.haml
index 64a4816def6..834749caaba 100644
--- a/app/views/shared/wikis/edit.html.haml
+++ b/app/views/shared/wikis/edit.html.haml
@@ -1,4 +1,5 @@
- wiki_page_title @page, @page.persisted? ? _('Edit') : _('New')
+- add_page_specific_style 'page_bundles/wiki'
= wiki_page_errors(@error)
@@ -17,8 +18,6 @@
.nav-controls.pb-md-3.pb-lg-0
- if @page.persisted?
- = link_to wiki_page_path(@wiki, @page, action: :history), class: "btn" do
- = s_("Wiki|Page history")
- if can?(current_user, :admin_wiki, @wiki.container)
#delete-wiki-modal-wrapper{ data: { delete_wiki_url: wiki_page_path(@wiki, @page), page_title: @page.human_title } }
diff --git a/app/views/shared/wikis/empty.html.haml b/app/views/shared/wikis/empty.html.haml
index 62fa6e1907b..c52ead74b4c 100644
--- a/app/views/shared/wikis/empty.html.haml
+++ b/app/views/shared/wikis/empty.html.haml
@@ -1,4 +1,5 @@
- page_title _("Wiki")
- @right_sidebar = false
+- add_page_specific_style 'page_bundles/wiki'
= render 'shared/empty_states/wikis'
diff --git a/app/views/shared/wikis/history.html.haml b/app/views/shared/wikis/history.html.haml
index f9d21c8fb57..50ccfdeabd5 100644
--- a/app/views/shared/wikis/history.html.haml
+++ b/app/views/shared/wikis/history.html.haml
@@ -1,4 +1,5 @@
- wiki_page_title @page, _('History')
+- add_page_specific_style 'page_bundles/wiki'
.wiki-page-header.top-area.has-sidebar-toggle.flex-column.flex-lg-row
= wiki_sidebar_toggle_button
diff --git a/app/views/shared/wikis/pages.html.haml b/app/views/shared/wikis/pages.html.haml
index 35a62ec2bb4..76fc9510740 100644
--- a/app/views/shared/wikis/pages.html.haml
+++ b/app/views/shared/wikis/pages.html.haml
@@ -2,6 +2,7 @@
- breadcrumb_title s_("Wiki|Pages")
- page_title s_("Wiki|Pages"), _("Wiki")
- sort_title = wiki_sort_title(params[:sort])
+- add_page_specific_style 'page_bundles/wiki'
.wiki-page-header.top-area.flex-column.flex-lg-row
@@ -10,14 +11,14 @@
= s_("Wiki|Wiki Pages")
.nav-controls.pb-md-3.pb-lg-0
- = link_to wiki_path(@wiki, action: :git_access), class: 'btn' do
+ = link_to wiki_path(@wiki, action: :git_access), class: 'btn gl-button' do
= sprite_icon('download')
= _("Clone repository")
.dropdown.inline.wiki-sort-dropdown
.btn-group{ role: 'group' }
.btn-group{ role: 'group' }
- %button.dropdown-toggle{ type: 'button', data: { toggle: 'dropdown', display: 'static' }, class: 'btn btn-default' }
+ %button.dropdown-toggle{ type: 'button', data: { toggle: 'dropdown', display: 'static' }, class: 'btn gl-button btn-default' }
= sort_title
= sprite_icon('chevron-down')
%ul.dropdown-menu.dropdown-menu-right.dropdown-menu-selectable.dropdown-menu-sort
diff --git a/app/views/shared/wikis/show.html.haml b/app/views/shared/wikis/show.html.haml
index a7c734f5af4..6f1c1a3a801 100644
--- a/app/views/shared/wikis/show.html.haml
+++ b/app/views/shared/wikis/show.html.haml
@@ -1,10 +1,10 @@
- wiki_page_title @page
+- add_page_specific_style 'page_bundles/wiki'
.wiki-page-header.top-area.has-sidebar-toggle.flex-column.flex-lg-row
= wiki_sidebar_toggle_button
.nav-text.flex-fill
- %h2.wiki-page-title{ data: { qa_selector: 'wiki_page_title' } }= @page.human_title
%span.wiki-last-edit-by
- if @page.last_version
= (_("Last edited by %{name}") % { name: "<strong>#{@page.last_version.author_name}</strong>" }).html_safe
@@ -20,8 +20,13 @@
- history_link = link_to s_("WikiHistoricalPage|history"), wiki_page_path(@wiki, @page, action: :history)
= (s_("WikiHistoricalPage|You can view the %{most_recent_link} or browse the %{history_link}.") % { most_recent_link: most_recent_link, history_link: history_link }).html_safe
-.gl-mt-3.gl-mb-3
- .js-wiki-page-content.md{ data: { qa_selector: 'wiki_page_content', tracking_context: wiki_page_tracking_context(@page).to_json } }
+.gl-mt-5.gl-mb-3
+ .gl-display-flex.gl-justify-content-space-between
+ %h2.gl-mt-0.gl-mb-5{ data: { qa_selector: 'wiki_page_title', testid: 'wiki_page_title' } }= @page.human_title
+ %div
+ - if can?(current_user, :create_wiki, @wiki.container) && @page.latest? && @valid_encoding
+ = link_to sprite_icon('pencil', css_class: 'gl-icon'), wiki_page_path(@wiki, @page, action: :edit), title: 'Edit', role: "button", class: 'btn gl-button btn-icon btn-default js-wiki-edit', data: { qa_selector: 'edit_page_button', testid: 'wiki_edit_button' }
+ .js-wiki-page-content.md.gl-pt-2{ data: { qa_selector: 'wiki_page_content', testid: 'wiki_page_content', tracking_context: wiki_page_tracking_context(@page).to_json } }
= render_wiki_content(@page)
= render 'shared/wikis/sidebar'
diff --git a/app/views/sherlock/file_samples/show.html.haml b/app/views/sherlock/file_samples/show.html.haml
index 5fef56f7fc3..b7e6f883667 100644
--- a/app/views/sherlock/file_samples/show.html.haml
+++ b/app/views/sherlock/file_samples/show.html.haml
@@ -5,7 +5,7 @@
.row-content-block
.float-right
- = link_to(sherlock_transaction_path(@transaction), class: 'btn') do
+ = link_to(sherlock_transaction_path(@transaction), class: 'btn gl-button') do
= sprite_icon('arrow-left')
= t('sherlock.transaction')
.oneline
@@ -27,7 +27,7 @@
%article.file-holder
.js-file-title.file-title
- %i.fa.fa-file-text-o.fa-fw
+ = sprite_icon("doc-text")
%strong
= @file_sample.file
.code.file-content.js-syntax-highlight
diff --git a/app/views/snippets/_actions.html.haml b/app/views/snippets/_actions.html.haml
deleted file mode 100644
index 566395133a1..00000000000
--- a/app/views/snippets/_actions.html.haml
+++ /dev/null
@@ -1,35 +0,0 @@
-- return unless current_user
-
-.d-none.d-sm-block
- - if can?(current_user, :update_snippet, @snippet)
- = link_to edit_snippet_path(@snippet), class: "btn btn-grouped" do
- = _("Edit")
- - if can?(current_user, :admin_snippet, @snippet)
- = link_to gitlab_snippet_path(@snippet), method: :delete, data: { confirm: _("Are you sure?") }, class: "btn btn-grouped btn-inverted btn-remove", title: _('Delete Snippet') do
- = _("Delete")
- - if can?(current_user, :create_snippet)
- = link_to new_snippet_path, class: "btn btn-grouped btn-success btn-inverted", title: _("New snippet") do
- = _("New snippet")
- - if @snippet.submittable_as_spam_by?(current_user)
- = link_to _('Submit as spam'), mark_as_spam_snippet_path(@snippet), method: :post, class: 'btn btn-grouped btn-spam', title: _('Submit as spam')
-.d-block.d-sm-none.dropdown
- %button.btn.btn-default.btn-block.gl-mb-0.gl-mt-2{ data: { toggle: "dropdown" } }
- = _("Options")
- = icon('caret-down')
- .dropdown-menu.dropdown-menu-full-width
- %ul
- - if can?(current_user, :create_snippet)
- %li
- = link_to new_snippet_path, title: _("New snippet") do
- = _("New snippet")
- - if can?(current_user, :admin_snippet, @snippet)
- %li
- = link_to gitlab_snippet_path(@snippet), method: :delete, data: { confirm: _("Are you sure?") }, title: _('Delete Snippet') do
- = _("Delete")
- - if can?(current_user, :update_snippet, @snippet)
- %li
- = link_to edit_snippet_path(@snippet) do
- = _("Edit")
- - if @snippet.submittable_as_spam_by?(current_user)
- %li
- = link_to _('Submit as spam'), mark_as_spam_snippet_path(@snippet), method: :post
diff --git a/app/views/snippets/show.html.haml b/app/views/snippets/show.html.haml
index 819f02b78fe..77a6ff5455e 100644
--- a/app/views/snippets/show.html.haml
+++ b/app/views/snippets/show.html.haml
@@ -4,13 +4,7 @@
- breadcrumb_title @snippet.to_reference
- page_title "#{@snippet.title} (#{@snippet.to_reference})", _("Snippets")
-- if Feature.enabled?(:snippets_vue, default_enabled: true)
- #js-snippet-view{ data: {'qa-selector': 'snippet_view', 'snippet-gid': @snippet.to_global_id} }
-- else
- = render 'shared/snippets/header'
-
- .personal-snippets
- = render 'shared/snippets/blob', blob: @blob
+#js-snippet-view{ data: {'qa-selector': 'snippet_view', 'snippet-gid': @snippet.to_global_id} }
.row-content-block.top-block.content-component-block
= render 'award_emoji/awards_block', awardable: @snippet, inline: true
diff --git a/app/views/users/_overview.html.haml b/app/views/users/_overview.html.haml
index 5b6d1169b4b..294af53e35b 100644
--- a/app/views/users/_overview.html.haml
+++ b/app/views/users/_overview.html.haml
@@ -1,3 +1,5 @@
+- activity_pane_class = Feature.enabled?(:security_auto_fix) && @user.bot? ? "col-12" : "col-md-12 col-lg-6"
+
.row
.col-12
.calendar-block.gl-mt-3.gl-mb-3
@@ -6,25 +8,26 @@
.spinner.spinner-md
.user-calendar-activities.d-none.d-sm-block
.row
- .col-md-12.col-lg-6
+ %div{ class: activity_pane_class }
- if can?(current_user, :read_cross_project)
.activities-block
.gl-mt-5
- .d-flex.align-items-center.border-bottom
- %h4.flex-grow
- = s_('UserProfile|Activity')
+ .gl-display-flex.gl-align-items-center.gl-border-b-1.gl-border-b-gray-100.gl-border-b-solid
+ %h4.gl-flex-grow-1
+ = Feature.enabled?(:security_auto_fix) && @user.bot? ? s_('UserProfile|Bot activity') : s_('UserProfile|Activity')
= link_to s_('UserProfile|View all'), user_activity_path, class: "hide js-view-all"
.overview-content-list{ data: { href: user_path } }
.center.light.loading
.spinner.spinner-md
- .col-md-12.col-lg-6
- .projects-block
- .gl-mt-5
- .d-flex.align-items-center.border-bottom
- %h4.flex-grow
- = s_('UserProfile|Personal projects')
- = link_to s_('UserProfile|View all'), user_projects_path, class: "hide js-view-all"
- .overview-content-list{ data: { href: user_projects_path } }
- .center.light.loading
- .spinner.spinner-md
+ - unless Feature.enabled?(:security_auto_fix) && @user.bot?
+ .col-md-12.col-lg-6
+ .projects-block
+ .gl-mt-5
+ .gl-display-flex.gl-align-items-center.gl-border-b-1.gl-border-b-gray-100.gl-border-b-solid
+ %h4.gl-flex-grow-1
+ = s_('UserProfile|Personal projects')
+ = link_to s_('UserProfile|View all'), user_projects_path, class: "hide js-view-all"
+ .overview-content-list{ data: { href: user_projects_path } }
+ .center.light.loading
+ .spinner.spinner-md
diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml
index fbda9b79e82..2746a139dd0 100644
--- a/app/views/users/show.html.haml
+++ b/app/views/users/show.html.haml
@@ -2,7 +2,7 @@
- @hide_breadcrumbs = true
- @no_container = true
- page_title @user.blocked? ? s_('UserProfile|Blocked user') : @user.name
-- page_description @user.bio
+- page_description @user.bio_html
- header_title @user.name, user_path(@user)
- link_classes = "flex-grow-1 mx-1 "
@@ -67,17 +67,19 @@
- unless @user.skype.blank?
.profile-link-holder.middle-dot-divider
= link_to "skype:#{@user.skype}", title: "Skype" do
- = icon('skype')
+ = sprite_icon('skype')
- unless @user.linkedin.blank?
.profile-link-holder.middle-dot-divider
= link_to linkedin_url(@user), title: "LinkedIn", target: '_blank', rel: 'noopener noreferrer nofollow' do
- = icon('linkedin-square')
+ = sprite_icon('linkedin')
- unless @user.twitter.blank?
.profile-link-holder.middle-dot-divider-sm
= link_to twitter_url(@user), title: "Twitter", target: '_blank', rel: 'noopener noreferrer nofollow' do
- = icon('twitter-square')
+ = sprite_icon('twitter')
- unless @user.website_url.blank?
.profile-link-holder.middle-dot-divider-sm.d-block.d-sm-inline.mt-1.mt-sm-0
+ - if Feature.enabled?(:security_auto_fix) && @user.bot?
+ = sprite_icon('question', css_class: 'gl-text-blue-600')
= link_to @user.short_website_url, @user.full_website_url, class: 'text-link', target: '_blank', rel: 'me noopener noreferrer nofollow'
- unless @user.public_email.blank?
.profile-link-holder.middle-dot-divider-sm.d-block.d-sm-inline.mt-1.mt-sm-0
@@ -101,26 +103,27 @@
%li.js-activity-tab
= link_to user_activity_path, data: { target: 'div#activity', action: 'activity', toggle: 'tab' } do
= s_('UserProfile|Activity')
- - if profile_tab?(:groups)
- %li.js-groups-tab
- = link_to user_groups_path, data: { target: 'div#groups', action: 'groups', toggle: 'tab', endpoint: user_groups_path(format: :json) } do
- = s_('UserProfile|Groups')
- - if profile_tab?(:contributed)
- %li.js-contributed-tab
- = link_to user_contributed_projects_path, data: { target: 'div#contributed', action: 'contributed', toggle: 'tab', endpoint: user_contributed_projects_path(format: :json) } do
- = s_('UserProfile|Contributed projects')
- - if profile_tab?(:projects)
- %li.js-projects-tab
- = link_to user_projects_path, data: { target: 'div#projects', action: 'projects', toggle: 'tab', endpoint: user_projects_path(format: :json) } do
- = s_('UserProfile|Personal projects')
- - if profile_tab?(:starred)
- %li.js-starred-tab
- = link_to user_starred_projects_path, data: { target: 'div#starred', action: 'starred', toggle: 'tab', endpoint: user_starred_projects_path(format: :json) } do
- = s_('UserProfile|Starred projects')
- - if profile_tab?(:snippets)
- %li.js-snippets-tab
- = link_to user_snippets_path, data: { target: 'div#snippets', action: 'snippets', toggle: 'tab', endpoint: user_snippets_path(format: :json) } do
- = s_('UserProfile|Snippets')
+ - unless Feature.enabled?(:security_auto_fix) && @user.bot?
+ - if profile_tab?(:groups)
+ %li.js-groups-tab
+ = link_to user_groups_path, data: { target: 'div#groups', action: 'groups', toggle: 'tab', endpoint: user_groups_path(format: :json) } do
+ = s_('UserProfile|Groups')
+ - if profile_tab?(:contributed)
+ %li.js-contributed-tab
+ = link_to user_contributed_projects_path, data: { target: 'div#contributed', action: 'contributed', toggle: 'tab', endpoint: user_contributed_projects_path(format: :json) } do
+ = s_('UserProfile|Contributed projects')
+ - if profile_tab?(:projects)
+ %li.js-projects-tab
+ = link_to user_projects_path, data: { target: 'div#projects', action: 'projects', toggle: 'tab', endpoint: user_projects_path(format: :json) } do
+ = s_('UserProfile|Personal projects')
+ - if profile_tab?(:starred)
+ %li.js-starred-tab
+ = link_to user_starred_projects_path, data: { target: 'div#starred', action: 'starred', toggle: 'tab', endpoint: user_starred_projects_path(format: :json) } do
+ = s_('UserProfile|Starred projects')
+ - if profile_tab?(:snippets)
+ %li.js-snippets-tab
+ = link_to user_snippets_path, data: { target: 'div#snippets', action: 'snippets', toggle: 'tab', endpoint: user_snippets_path(format: :json) } do
+ = s_('UserProfile|Snippets')
%div{ class: container_class }
.tab-content
@@ -136,26 +139,26 @@
.content_list{ data: { href: user_path } }
.loading
.spinner.spinner-md
-
- - if profile_tab?(:groups)
- #groups.tab-pane
- -# This tab is always loaded via AJAX
-
- - if profile_tab?(:contributed)
- #contributed.tab-pane
- -# This tab is always loaded via AJAX
-
- - if profile_tab?(:projects)
- #projects.tab-pane
- -# This tab is always loaded via AJAX
-
- - if profile_tab?(:starred)
- #starred.tab-pane
- -# This tab is always loaded via AJAX
-
- - if profile_tab?(:snippets)
- #snippets.tab-pane
- -# This tab is always loaded via AJAX
+ - unless @user.bot?
+ - if profile_tab?(:groups)
+ #groups.tab-pane
+ -# This tab is always loaded via AJAX
+
+ - if profile_tab?(:contributed)
+ #contributed.tab-pane
+ -# This tab is always loaded via AJAX
+
+ - if profile_tab?(:projects)
+ #projects.tab-pane
+ -# This tab is always loaded via AJAX
+
+ - if profile_tab?(:starred)
+ #starred.tab-pane
+ -# This tab is always loaded via AJAX
+
+ - if profile_tab?(:snippets)
+ #snippets.tab-pane
+ -# This tab is always loaded via AJAX
.loading.hide
.spinner.spinner-md
diff --git a/app/workers/all_queues.yml b/app/workers/all_queues.yml
index 11bf797fb90..30b89f37562 100644
--- a/app/workers/all_queues.yml
+++ b/app/workers/all_queues.yml
@@ -147,6 +147,14 @@
:weight: 1
:idempotent:
:tags: []
+- :name: cronjob:ci_schedule_delete_objects_cron
+ :feature_category: :continuous_integration
+ :has_external_dependencies:
+ :urgency: :low
+ :resource_boundary: :unknown
+ :weight: 1
+ :idempotent: true
+ :tags: []
- :name: cronjob:container_expiration_policy
:feature_category: :container_registry
:has_external_dependencies:
@@ -211,6 +219,14 @@
:weight: 1
:idempotent:
:tags: []
+- :name: cronjob:member_invitation_reminder_emails
+ :feature_category: :subgroups
+ :has_external_dependencies:
+ :urgency: :low
+ :resource_boundary: :unknown
+ :weight: 1
+ :idempotent:
+ :tags: []
- :name: cronjob:metrics_dashboard_schedule_annotations_prune
:feature_category: :metrics
:has_external_dependencies:
@@ -419,6 +435,22 @@
:weight: 1
:idempotent: true
:tags: []
+- :name: deployment:deployments_drop_older_deployments
+ :feature_category: :continuous_delivery
+ :has_external_dependencies:
+ :urgency: :low
+ :resource_boundary: :unknown
+ :weight: 3
+ :idempotent:
+ :tags: []
+- :name: deployment:deployments_execute_hooks
+ :feature_category: :continuous_delivery
+ :has_external_dependencies:
+ :urgency: :low
+ :resource_boundary: :cpu
+ :weight: 3
+ :idempotent:
+ :tags: []
- :name: deployment:deployments_finished
:feature_category: :continuous_delivery
:has_external_dependencies:
@@ -435,6 +467,14 @@
:weight: 3
:idempotent:
:tags: []
+- :name: deployment:deployments_link_merge_request
+ :feature_category: :continuous_delivery
+ :has_external_dependencies:
+ :urgency: :low
+ :resource_boundary: :cpu
+ :weight: 3
+ :idempotent: true
+ :tags: []
- :name: deployment:deployments_success
:feature_category: :continuous_delivery
:has_external_dependencies:
@@ -443,6 +483,14 @@
:weight: 3
:idempotent:
:tags: []
+- :name: deployment:deployments_update_environment
+ :feature_category: :continuous_delivery
+ :has_external_dependencies:
+ :urgency: :low
+ :resource_boundary: :cpu
+ :weight: 3
+ :idempotent: true
+ :tags: []
- :name: gcp_cluster:cluster_configure_istio
:feature_category: :kubernetes_management
:has_external_dependencies: true
@@ -723,6 +771,14 @@
:weight: 2
:idempotent: true
:tags: []
+- :name: incident_management:incident_management_add_severity_system_note
+ :feature_category: :incident_management
+ :has_external_dependencies:
+ :urgency: :low
+ :resource_boundary: :unknown
+ :weight: 2
+ :idempotent:
+ :tags: []
- :name: incident_management:incident_management_pager_duty_process_incident
:feature_category: :incident_management
:has_external_dependencies:
@@ -906,7 +962,8 @@
:resource_boundary: :unknown
:weight: 1
:idempotent:
- :tags: []
+ :tags:
+ - :requires_disk_io
- :name: pipeline_background:ci_build_report_result
:feature_category: :continuous_integration
:has_external_dependencies:
@@ -914,7 +971,8 @@
:resource_boundary: :unknown
:weight: 1
:idempotent: true
- :tags: []
+ :tags:
+ - :requires_disk_io
- :name: pipeline_background:ci_build_trace_chunk_flush
:feature_category: :continuous_integration
:has_external_dependencies:
@@ -994,7 +1052,8 @@
:resource_boundary: :unknown
:weight: 3
:idempotent:
- :tags: []
+ :tags:
+ - :requires_disk_io
- :name: pipeline_default:build_trace_sections
:feature_category: :continuous_integration
:has_external_dependencies:
@@ -1002,7 +1061,8 @@
:resource_boundary: :unknown
:weight: 3
:idempotent:
- :tags: []
+ :tags:
+ - :requires_disk_io
- :name: pipeline_default:ci_create_cross_project_pipeline
:feature_category: :continuous_integration
:has_external_dependencies:
@@ -1259,6 +1319,15 @@
:resource_boundary: :unknown
:weight: 2
:idempotent:
+ :tags:
+ - :requires_disk_io
+- :name: ci_delete_objects
+ :feature_category: :continuous_integration
+ :has_external_dependencies:
+ :urgency: :low
+ :resource_boundary: :unknown
+ :weight: 1
+ :idempotent: true
:tags: []
- :name: create_commit_signature
:feature_category: :source_code_management
@@ -1324,6 +1393,14 @@
:weight: 1
:idempotent:
:tags: []
+- :name: design_management_copy_design_collection
+ :feature_category: :design_management
+ :has_external_dependencies:
+ :urgency: :low
+ :resource_boundary: :unknown
+ :weight: 1
+ :idempotent: true
+ :tags: []
- :name: design_management_new_version
:feature_category: :design_management
:has_external_dependencies:
@@ -1340,6 +1417,22 @@
:weight: 1
:idempotent:
:tags: []
+- :name: disallow_two_factor_for_group
+ :feature_category: :subgroups
+ :has_external_dependencies:
+ :urgency: :low
+ :resource_boundary: :unknown
+ :weight: 1
+ :idempotent: true
+ :tags: []
+- :name: disallow_two_factor_for_subgroups
+ :feature_category: :subgroups
+ :has_external_dependencies:
+ :urgency: :low
+ :resource_boundary: :unknown
+ :weight: 1
+ :idempotent: true
+ :tags: []
- :name: email_receiver
:feature_category: :issue_tracking
:has_external_dependencies:
@@ -1371,7 +1464,8 @@
:resource_boundary: :unknown
:weight: 1
:idempotent:
- :tags: []
+ :tags:
+ - :requires_disk_io
- :name: export_csv
:feature_category: :issue_tracking
:has_external_dependencies:
@@ -1435,7 +1529,8 @@
:resource_boundary: :unknown
:weight: 1
:idempotent:
- :tags: []
+ :tags:
+ - :requires_disk_io
- :name: group_export
:feature_category: :importers
:has_external_dependencies:
@@ -1476,6 +1571,14 @@
:weight: 1
:idempotent:
:tags: []
+- :name: issuable_export_csv
+ :feature_category: :issue_tracking
+ :has_external_dependencies:
+ :urgency: :low
+ :resource_boundary: :cpu
+ :weight: 1
+ :idempotent:
+ :tags: []
- :name: issue_placement
:feature_category: :issue_tracking
:has_external_dependencies:
@@ -1532,6 +1635,14 @@
:weight: 1
:idempotent: true
:tags: []
+- :name: metrics_dashboard_sync_dashboards
+ :feature_category: :metrics
+ :has_external_dependencies:
+ :urgency: :low
+ :resource_boundary: :unknown
+ :weight: 1
+ :idempotent: true
+ :tags: []
- :name: migrate_external_diffs
:feature_category: :source_code_management
:has_external_dependencies:
@@ -1579,7 +1690,8 @@
:resource_boundary: :unknown
:weight: 1
:idempotent:
- :tags: []
+ :tags:
+ - :requires_disk_io
- :name: pages_domain_ssl_renewal
:feature_category: :pages
:has_external_dependencies:
@@ -1587,7 +1699,8 @@
:resource_boundary: :unknown
:weight: 1
:idempotent:
- :tags: []
+ :tags:
+ - :requires_disk_io
- :name: pages_domain_verification
:feature_category: :pages
:has_external_dependencies:
@@ -1595,7 +1708,8 @@
:resource_boundary: :unknown
:weight: 1
:idempotent:
- :tags: []
+ :tags:
+ - :requires_disk_io
- :name: pages_remove
:feature_category: :pages
:has_external_dependencies:
@@ -1667,7 +1781,8 @@
:resource_boundary: :unknown
:weight: 1
:idempotent:
- :tags: []
+ :tags:
+ - :requires_disk_io
- :name: project_export
:feature_category: :importers
:has_external_dependencies:
@@ -1708,6 +1823,30 @@
:weight: 1
:idempotent: true
:tags: []
+- :name: propagate_integration_group
+ :feature_category: :integrations
+ :has_external_dependencies:
+ :urgency: :low
+ :resource_boundary: :unknown
+ :weight: 1
+ :idempotent: true
+ :tags: []
+- :name: propagate_integration_inherit
+ :feature_category: :integrations
+ :has_external_dependencies:
+ :urgency: :low
+ :resource_boundary: :unknown
+ :weight: 1
+ :idempotent: true
+ :tags: []
+- :name: propagate_integration_project
+ :feature_category: :integrations
+ :has_external_dependencies:
+ :urgency: :low
+ :resource_boundary: :unknown
+ :weight: 1
+ :idempotent: true
+ :tags: []
- :name: propagate_service_template
:feature_category: :integrations
:has_external_dependencies:
@@ -1860,6 +1999,14 @@
:weight: 1
:idempotent:
:tags: []
+- :name: web_hooks_destroy
+ :feature_category: :integrations
+ :has_external_dependencies:
+ :urgency: :low
+ :resource_boundary: :unknown
+ :weight: 1
+ :idempotent: true
+ :tags: []
- :name: x509_certificate_revoke
:feature_category: :source_code_management
:has_external_dependencies:
diff --git a/app/workers/analytics/instance_statistics/count_job_trigger_worker.rb b/app/workers/analytics/instance_statistics/count_job_trigger_worker.rb
index a9976c6e5cb..bf57619fc6e 100644
--- a/app/workers/analytics/instance_statistics/count_job_trigger_worker.rb
+++ b/app/workers/analytics/instance_statistics/count_job_trigger_worker.rb
@@ -14,13 +14,10 @@ module Analytics
idempotent!
def perform
- return if Feature.disabled?(:store_instance_statistics_measurements, default_enabled: true)
-
recorded_at = Time.zone.now
- measurement_identifiers = Analytics::InstanceStatistics::Measurement.identifiers
worker_arguments = Gitlab::Analytics::InstanceStatistics::WorkersArgumentBuilder.new(
- measurement_identifiers: measurement_identifiers.values,
+ measurement_identifiers: ::Analytics::InstanceStatistics::Measurement.measurement_identifier_values,
recorded_at: recorded_at
).execute
diff --git a/app/workers/archive_trace_worker.rb b/app/workers/archive_trace_worker.rb
index 3ddb5686bf2..b0c5bef336a 100644
--- a/app/workers/archive_trace_worker.rb
+++ b/app/workers/archive_trace_worker.rb
@@ -4,6 +4,8 @@ class ArchiveTraceWorker # rubocop:disable Scalability/IdempotentWorker
include ApplicationWorker
include PipelineBackgroundQueue
+ tags :requires_disk_io
+
# rubocop: disable CodeReuse/ActiveRecord
def perform(job_id)
Ci::Build.without_archived_trace.find_by(id: job_id).try do |job|
diff --git a/app/workers/authorized_project_update/periodic_recalculate_worker.rb b/app/workers/authorized_project_update/periodic_recalculate_worker.rb
index 0d1ad67d7bb..78ffdbca4d6 100644
--- a/app/workers/authorized_project_update/periodic_recalculate_worker.rb
+++ b/app/workers/authorized_project_update/periodic_recalculate_worker.rb
@@ -12,9 +12,7 @@ module AuthorizedProjectUpdate
idempotent!
def perform
- if ::Feature.enabled?(:periodic_project_authorization_recalculation, default_enabled: true)
- AuthorizedProjectUpdate::PeriodicRecalculateService.new.execute
- end
+ AuthorizedProjectUpdate::PeriodicRecalculateService.new.execute
end
end
end
diff --git a/app/workers/authorized_project_update/user_refresh_over_user_range_worker.rb b/app/workers/authorized_project_update/user_refresh_over_user_range_worker.rb
index 336b1c5443e..9bd1ad2ed30 100644
--- a/app/workers/authorized_project_update/user_refresh_over_user_range_worker.rb
+++ b/app/workers/authorized_project_update/user_refresh_over_user_range_worker.rb
@@ -12,9 +12,7 @@ module AuthorizedProjectUpdate
idempotent!
def perform(start_user_id, end_user_id)
- if ::Feature.enabled?(:periodic_project_authorization_recalculation, default_enabled: true)
- AuthorizedProjectUpdate::RecalculateForUserRangeService.new(start_user_id, end_user_id).execute
- end
+ AuthorizedProjectUpdate::RecalculateForUserRangeService.new(start_user_id, end_user_id).execute
end
end
end
diff --git a/app/workers/background_migration_worker.rb b/app/workers/background_migration_worker.rb
index bff864ba420..74a12dbff77 100644
--- a/app/workers/background_migration_worker.rb
+++ b/app/workers/background_migration_worker.rb
@@ -23,7 +23,9 @@ class BackgroundMigrationWorker # rubocop:disable Scalability/IdempotentWorker
#
# class_name - The class name of the background migration to run.
# arguments - The arguments to pass to the migration class.
- def perform(class_name, arguments = [])
+ # lease_attempts - The number of times we will try to obtain an exclusive
+ # lease on the class before running anyway. Pass 0 to always run.
+ def perform(class_name, arguments = [], lease_attempts = 5)
with_context(caller_id: class_name.to_s) do
should_perform, ttl = perform_and_ttl(class_name)
diff --git a/app/workers/build_coverage_worker.rb b/app/workers/build_coverage_worker.rb
index 7d893024abc..d63d8549f09 100644
--- a/app/workers/build_coverage_worker.rb
+++ b/app/workers/build_coverage_worker.rb
@@ -4,6 +4,8 @@ class BuildCoverageWorker # rubocop:disable Scalability/IdempotentWorker
include ApplicationWorker
include PipelineQueue
+ tags :requires_disk_io
+
# rubocop: disable CodeReuse/ActiveRecord
def perform(build_id)
Ci::Build.find_by(id: build_id)&.update_coverage
diff --git a/app/workers/build_finished_worker.rb b/app/workers/build_finished_worker.rb
index d0f7d65aed6..d7a5fcf4f18 100644
--- a/app/workers/build_finished_worker.rb
+++ b/app/workers/build_finished_worker.rb
@@ -9,6 +9,8 @@ class BuildFinishedWorker # rubocop:disable Scalability/IdempotentWorker
worker_resource_boundary :cpu
tags :requires_disk_io
+ ARCHIVE_TRACES_IN = 2.minutes.freeze
+
# rubocop: disable CodeReuse/ActiveRecord
def perform(build_id)
Ci::Build.find_by(id: build_id).try do |build|
@@ -33,9 +35,22 @@ class BuildFinishedWorker # rubocop:disable Scalability/IdempotentWorker
# We execute these async as these are independent operations.
BuildHooksWorker.perform_async(build.id)
- ArchiveTraceWorker.perform_async(build.id)
ExpirePipelineCacheWorker.perform_async(build.pipeline_id) if build.pipeline.cacheable?
ChatNotificationWorker.perform_async(build.id) if build.pipeline.chat?
+
+ ##
+ # We want to delay sending a build trace to object storage operation to
+ # validate that this fixes a race condition between this and flushing live
+ # trace chunks and chunks being removed after consolidation and putting
+ # them into object storage archive.
+ #
+ # TODO This is temporary fix we should improve later, after we validate
+ # that this is indeed the culprit.
+ #
+ # See https://gitlab.com/gitlab-org/gitlab/-/issues/267112 for more
+ # details.
+ #
+ ArchiveTraceWorker.perform_in(ARCHIVE_TRACES_IN, build.id)
end
end
diff --git a/app/workers/build_trace_sections_worker.rb b/app/workers/build_trace_sections_worker.rb
index c25f77974e9..59f019b827e 100644
--- a/app/workers/build_trace_sections_worker.rb
+++ b/app/workers/build_trace_sections_worker.rb
@@ -4,6 +4,8 @@ class BuildTraceSectionsWorker # rubocop:disable Scalability/IdempotentWorker
include ApplicationWorker
include PipelineQueue
+ tags :requires_disk_io
+
# rubocop: disable CodeReuse/ActiveRecord
def perform(build_id)
Ci::Build.find_by(id: build_id)&.parse_trace_sections!
diff --git a/app/workers/chat_notification_worker.rb b/app/workers/chat_notification_worker.rb
index 5fab437f49f..94a0197b862 100644
--- a/app/workers/chat_notification_worker.rb
+++ b/app/workers/chat_notification_worker.rb
@@ -7,6 +7,7 @@ class ChatNotificationWorker # rubocop:disable Scalability/IdempotentWorker
sidekiq_options retry: false
feature_category :chatops
+ tags :requires_disk_io
urgency :low # Can't be high as it has external dependencies
weight 2
worker_has_external_dependencies!
diff --git a/app/workers/ci/build_report_result_worker.rb b/app/workers/ci/build_report_result_worker.rb
index 60387936d0b..01a45490541 100644
--- a/app/workers/ci/build_report_result_worker.rb
+++ b/app/workers/ci/build_report_result_worker.rb
@@ -5,6 +5,8 @@ module Ci
include ApplicationWorker
include PipelineBackgroundQueue
+ tags :requires_disk_io
+
idempotent!
def perform(build_id)
diff --git a/app/workers/ci/build_trace_chunk_flush_worker.rb b/app/workers/ci/build_trace_chunk_flush_worker.rb
index 2908c7c2d0b..89400247a7b 100644
--- a/app/workers/ci/build_trace_chunk_flush_worker.rb
+++ b/app/workers/ci/build_trace_chunk_flush_worker.rb
@@ -8,8 +8,8 @@ module Ci
idempotent!
# rubocop: disable CodeReuse/ActiveRecord
- def perform(chunk_id)
- ::Ci::BuildTraceChunk.find_by(id: chunk_id).try do |chunk|
+ def perform(id)
+ ::Ci::BuildTraceChunk.find_by(id: id).try do |chunk|
chunk.persist_data!
end
end
diff --git a/app/workers/ci/delete_objects_worker.rb b/app/workers/ci/delete_objects_worker.rb
new file mode 100644
index 00000000000..e34be33b438
--- /dev/null
+++ b/app/workers/ci/delete_objects_worker.rb
@@ -0,0 +1,38 @@
+# frozen_string_literal: true
+
+module Ci
+ class DeleteObjectsWorker
+ include ApplicationWorker
+ include LimitedCapacity::Worker
+
+ feature_category :continuous_integration
+ idempotent!
+
+ def perform_work(*args)
+ service.execute
+ end
+
+ def remaining_work_count(*args)
+ @remaining_work_count ||= service
+ .remaining_batches_count(max_batch_count: remaining_capacity)
+ end
+
+ def max_running_jobs
+ if ::Feature.enabled?(:ci_delete_objects_low_concurrency)
+ 2
+ elsif ::Feature.enabled?(:ci_delete_objects_medium_concurrency)
+ 20
+ elsif ::Feature.enabled?(:ci_delete_objects_high_concurrency)
+ 50
+ else
+ 0
+ end
+ end
+
+ private
+
+ def service
+ @service ||= DeleteObjectsService.new
+ end
+ end
+end
diff --git a/app/workers/ci/schedule_delete_objects_cron_worker.rb b/app/workers/ci/schedule_delete_objects_cron_worker.rb
new file mode 100644
index 00000000000..fa0b15deb56
--- /dev/null
+++ b/app/workers/ci/schedule_delete_objects_cron_worker.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+module Ci
+ class ScheduleDeleteObjectsCronWorker
+ include ApplicationWorker
+ # rubocop:disable Scalability/CronWorkerContext
+ # This worker does not perform work scoped to a context
+ include CronjobQueue
+ # rubocop:enable Scalability/CronWorkerContext
+
+ feature_category :continuous_integration
+ idempotent!
+
+ def perform(*args)
+ Ci::DeleteObjectsWorker.perform_with_capacity(*args)
+ end
+ end
+end
diff --git a/app/workers/cleanup_container_repository_worker.rb b/app/workers/cleanup_container_repository_worker.rb
index 4469ea8cff9..80cc296fff5 100644
--- a/app/workers/cleanup_container_repository_worker.rb
+++ b/app/workers/cleanup_container_repository_worker.rb
@@ -16,9 +16,17 @@ class CleanupContainerRepositoryWorker # rubocop:disable Scalability/IdempotentW
return unless valid?
- Projects::ContainerRepository::CleanupTagsService
+ if run_by_container_expiration_policy?
+ container_repository.start_expiration_policy!
+ end
+
+ result = Projects::ContainerRepository::CleanupTagsService
.new(project, current_user, params)
.execute(container_repository)
+
+ if run_by_container_expiration_policy? && result[:status] == :success
+ container_repository.reset_expiration_policy_started_at!
+ end
end
private
@@ -30,7 +38,7 @@ class CleanupContainerRepositoryWorker # rubocop:disable Scalability/IdempotentW
end
def run_by_container_expiration_policy?
- @params['container_expiration_policy'] && container_repository && project
+ @params['container_expiration_policy'] && container_repository.present? && project.present?
end
def project
diff --git a/app/workers/concerns/limited_capacity/job_tracker.rb b/app/workers/concerns/limited_capacity/job_tracker.rb
new file mode 100644
index 00000000000..96b6e1a2024
--- /dev/null
+++ b/app/workers/concerns/limited_capacity/job_tracker.rb
@@ -0,0 +1,74 @@
+# frozen_string_literal: true
+module LimitedCapacity
+ class JobTracker # rubocop:disable Scalability/IdempotentWorker
+ include Gitlab::Utils::StrongMemoize
+
+ def initialize(namespace)
+ @namespace = namespace
+ end
+
+ def register(jid)
+ _added, @count = with_redis_pipeline do |redis|
+ register_job_keys(redis, jid)
+ get_job_count(redis)
+ end
+ end
+
+ def remove(jid)
+ _removed, @count = with_redis_pipeline do |redis|
+ remove_job_keys(redis, jid)
+ get_job_count(redis)
+ end
+ end
+
+ def clean_up
+ completed_jids = Gitlab::SidekiqStatus.completed_jids(running_jids)
+ return unless completed_jids.any?
+
+ _removed, @count = with_redis_pipeline do |redis|
+ remove_job_keys(redis, completed_jids)
+ get_job_count(redis)
+ end
+ end
+
+ def count
+ @count ||= with_redis { |redis| get_job_count(redis) }
+ end
+
+ def running_jids
+ with_redis do |redis|
+ redis.smembers(counter_key)
+ end
+ end
+
+ private
+
+ attr_reader :namespace
+
+ def counter_key
+ "worker:#{namespace.to_s.underscore}:running"
+ end
+
+ def get_job_count(redis)
+ redis.scard(counter_key)
+ end
+
+ def register_job_keys(redis, keys)
+ redis.sadd(counter_key, keys)
+ end
+
+ def remove_job_keys(redis, keys)
+ redis.srem(counter_key, keys)
+ end
+
+ def with_redis(&block)
+ Gitlab::Redis::Queues.with(&block) # rubocop: disable CodeReuse/ActiveRecord
+ end
+
+ def with_redis_pipeline(&block)
+ with_redis do |redis|
+ redis.pipelined(&block)
+ end
+ end
+ end
+end
diff --git a/app/workers/concerns/limited_capacity/worker.rb b/app/workers/concerns/limited_capacity/worker.rb
new file mode 100644
index 00000000000..c0d6bfff2f5
--- /dev/null
+++ b/app/workers/concerns/limited_capacity/worker.rb
@@ -0,0 +1,164 @@
+# frozen_string_literal: true
+
+# Usage:
+#
+# Worker that performs the tasks:
+#
+# class DummyWorker
+# include ApplicationWorker
+# include LimitedCapacity::Worker
+#
+# # For each job that raises any error, a worker instance will be disabled
+# # until the next schedule-run.
+# # If you wish to get around this, exceptions must by handled by the implementer.
+# #
+# def perform_work(*args)
+# end
+#
+# def remaining_work_count(*args)
+# 5
+# end
+#
+# def max_running_jobs
+# 25
+# end
+# end
+#
+# Cron worker to fill the pool of regular workers:
+#
+# class ScheduleDummyCronWorker
+# include ApplicationWorker
+# include CronjobQueue
+#
+# def perform(*args)
+# DummyWorker.perform_with_capacity(*args)
+# end
+# end
+#
+
+module LimitedCapacity
+ module Worker
+ extend ActiveSupport::Concern
+ include Gitlab::Utils::StrongMemoize
+
+ included do
+ # Disable Sidekiq retries, log the error, and send the job to the dead queue.
+ # This is done to have only one source that produces jobs and because the slot
+ # would be occupied by a job that will be performed in the distant future.
+ # We let the cron worker enqueue new jobs, this could be seen as our retry and
+ # back off mechanism because the job might fail again if executed immediately.
+ sidekiq_options retry: 0
+ deduplicate :none
+ end
+
+ class_methods do
+ def perform_with_capacity(*args)
+ worker = self.new
+ worker.remove_failed_jobs
+ worker.report_prometheus_metrics(*args)
+ required_jobs_count = worker.required_jobs_count(*args)
+
+ arguments = Array.new(required_jobs_count) { args }
+ self.bulk_perform_async(arguments) # rubocop:disable Scalability/BulkPerformWithContext
+ end
+ end
+
+ def perform(*args)
+ return unless has_capacity?
+
+ job_tracker.register(jid)
+ perform_work(*args)
+ rescue => exception
+ raise
+ ensure
+ job_tracker.remove(jid)
+ report_prometheus_metrics
+ re_enqueue(*args) unless exception
+ end
+
+ def perform_work(*args)
+ raise NotImplementedError
+ end
+
+ def remaining_work_count(*args)
+ raise NotImplementedError
+ end
+
+ def max_running_jobs
+ raise NotImplementedError
+ end
+
+ def has_capacity?
+ remaining_capacity > 0
+ end
+
+ def remaining_capacity
+ [
+ max_running_jobs - running_jobs_count - self.class.queue_size,
+ 0
+ ].max
+ end
+
+ def has_work?(*args)
+ remaining_work_count(*args) > 0
+ end
+
+ def remove_failed_jobs
+ job_tracker.clean_up
+ end
+
+ def report_prometheus_metrics(*args)
+ running_jobs_gauge.set(prometheus_labels, running_jobs_count)
+ remaining_work_gauge.set(prometheus_labels, remaining_work_count(*args))
+ max_running_jobs_gauge.set(prometheus_labels, max_running_jobs)
+ end
+
+ def required_jobs_count(*args)
+ [
+ remaining_work_count(*args),
+ remaining_capacity
+ ].min
+ end
+
+ private
+
+ def running_jobs_count
+ job_tracker.count
+ end
+
+ def job_tracker
+ strong_memoize(:job_tracker) do
+ JobTracker.new(self.class.name)
+ end
+ end
+
+ def re_enqueue(*args)
+ return unless has_capacity?
+ return unless has_work?(*args)
+
+ self.class.perform_async(*args)
+ end
+
+ def running_jobs_gauge
+ strong_memoize(:running_jobs_gauge) do
+ Gitlab::Metrics.gauge(:limited_capacity_worker_running_jobs, 'Number of running jobs')
+ end
+ end
+
+ def max_running_jobs_gauge
+ strong_memoize(:max_running_jobs_gauge) do
+ Gitlab::Metrics.gauge(:limited_capacity_worker_max_running_jobs, 'Maximum number of running jobs')
+ end
+ end
+
+ def remaining_work_gauge
+ strong_memoize(:remaining_work_gauge) do
+ Gitlab::Metrics.gauge(:limited_capacity_worker_remaining_work_count, 'Number of jobs waiting to be enqueued')
+ end
+ end
+
+ def prometheus_labels
+ { worker: self.class.name }
+ end
+ end
+end
diff --git a/app/workers/container_expiration_policy_worker.rb b/app/workers/container_expiration_policy_worker.rb
index 96590e165ae..61ba27f00d2 100644
--- a/app/workers/container_expiration_policy_worker.rb
+++ b/app/workers/container_expiration_policy_worker.rb
@@ -7,13 +7,15 @@ class ContainerExpirationPolicyWorker # rubocop:disable Scalability/IdempotentWo
feature_category :container_registry
def perform
- ContainerExpirationPolicy.runnable_schedules.preloaded.find_each do |container_expiration_policy|
- with_context(project: container_expiration_policy.project,
- user: container_expiration_policy.project.owner) do |project:, user:|
- ContainerExpirationPolicyService.new(project, user)
- .execute(container_expiration_policy)
- rescue ContainerExpirationPolicyService::InvalidPolicyError => e
- Gitlab::ErrorTracking.log_exception(e, container_expiration_policy_id: container_expiration_policy.id)
+ ContainerExpirationPolicy.executable.preloaded.each_batch do |relation|
+ relation.each do |container_expiration_policy|
+ with_context(project: container_expiration_policy.project,
+ user: container_expiration_policy.project.owner) do |project:, user:|
+ ContainerExpirationPolicyService.new(project, user)
+ .execute(container_expiration_policy)
+ rescue ContainerExpirationPolicyService::InvalidPolicyError => e
+ Gitlab::ErrorTracking.log_exception(e, container_expiration_policy_id: container_expiration_policy.id)
+ end
end
end
end
diff --git a/app/workers/deployments/drop_older_deployments_worker.rb b/app/workers/deployments/drop_older_deployments_worker.rb
new file mode 100644
index 00000000000..d6cd92c1da4
--- /dev/null
+++ b/app/workers/deployments/drop_older_deployments_worker.rb
@@ -0,0 +1,14 @@
+# frozen_string_literal: true
+
+module Deployments
+ class DropOlderDeploymentsWorker # rubocop:disable Scalability/IdempotentWorker
+ include ApplicationWorker
+
+ queue_namespace :deployment
+ feature_category :continuous_delivery
+
+ def perform(deployment_id)
+ Deployments::OlderDeploymentsDropService.new(deployment_id).execute
+ end
+ end
+end
diff --git a/app/workers/deployments/execute_hooks_worker.rb b/app/workers/deployments/execute_hooks_worker.rb
new file mode 100644
index 00000000000..6be05232321
--- /dev/null
+++ b/app/workers/deployments/execute_hooks_worker.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+module Deployments
+ class ExecuteHooksWorker # rubocop:disable Scalability/IdempotentWorker
+ include ApplicationWorker
+
+ queue_namespace :deployment
+ feature_category :continuous_delivery
+ worker_resource_boundary :cpu
+
+ def perform(deployment_id)
+ if (deploy = Deployment.find_by_id(deployment_id))
+ deploy.execute_hooks
+ end
+ end
+ end
+end
diff --git a/app/workers/deployments/finished_worker.rb b/app/workers/deployments/finished_worker.rb
index 0be420af718..62c886010a3 100644
--- a/app/workers/deployments/finished_worker.rb
+++ b/app/workers/deployments/finished_worker.rb
@@ -1,5 +1,7 @@
# frozen_string_literal: true
+# This worker is deprecated and will be removed in 14.0
+# See: https://gitlab.com/gitlab-org/gitlab/-/issues/266381
module Deployments
class FinishedWorker # rubocop:disable Scalability/IdempotentWorker
include ApplicationWorker
diff --git a/app/workers/deployments/forward_deployment_worker.rb b/app/workers/deployments/forward_deployment_worker.rb
index a6f246dbbbd..dd01fcbbafe 100644
--- a/app/workers/deployments/forward_deployment_worker.rb
+++ b/app/workers/deployments/forward_deployment_worker.rb
@@ -1,5 +1,7 @@
# frozen_string_literal: true
+# This worker is deprecated and will be removed in 14.0
+# See: https://gitlab.com/gitlab-org/gitlab/-/issues/266381
module Deployments
class ForwardDeploymentWorker # rubocop:disable Scalability/IdempotentWorker
include ApplicationWorker
diff --git a/app/workers/deployments/link_merge_request_worker.rb b/app/workers/deployments/link_merge_request_worker.rb
new file mode 100644
index 00000000000..4723691a0bb
--- /dev/null
+++ b/app/workers/deployments/link_merge_request_worker.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+module Deployments
+ class LinkMergeRequestWorker
+ include ApplicationWorker
+
+ queue_namespace :deployment
+ idempotent!
+ feature_category :continuous_delivery
+ worker_resource_boundary :cpu
+
+ def perform(deployment_id)
+ if (deploy = Deployment.find_by_id(deployment_id))
+ LinkMergeRequestsService.new(deploy).execute
+ end
+ end
+ end
+end
diff --git a/app/workers/deployments/success_worker.rb b/app/workers/deployments/success_worker.rb
index 17f790d2f6f..b72b107985b 100644
--- a/app/workers/deployments/success_worker.rb
+++ b/app/workers/deployments/success_worker.rb
@@ -1,5 +1,7 @@
# frozen_string_literal: true
+# This worker is deprecated and will be removed in 14.0
+# See: https://gitlab.com/gitlab-org/gitlab/-/issues/266381
module Deployments
class SuccessWorker # rubocop:disable Scalability/IdempotentWorker
include ApplicationWorker
@@ -12,7 +14,7 @@ module Deployments
Deployment.find_by_id(deployment_id).try do |deployment|
break unless deployment.success?
- Deployments::AfterCreateService.new(deployment).execute
+ Deployments::UpdateEnvironmentService.new(deployment).execute
end
end
end
diff --git a/app/workers/deployments/update_environment_worker.rb b/app/workers/deployments/update_environment_worker.rb
new file mode 100644
index 00000000000..2381f9926bc
--- /dev/null
+++ b/app/workers/deployments/update_environment_worker.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+module Deployments
+ class UpdateEnvironmentWorker
+ include ApplicationWorker
+
+ queue_namespace :deployment
+ idempotent!
+ feature_category :continuous_delivery
+ worker_resource_boundary :cpu
+
+ def perform(deployment_id)
+ Deployment.find_by_id(deployment_id).try do |deployment|
+ break unless deployment.success?
+
+ Deployments::UpdateEnvironmentService.new(deployment).execute
+ end
+ end
+ end
+end
diff --git a/app/workers/design_management/copy_design_collection_worker.rb b/app/workers/design_management/copy_design_collection_worker.rb
new file mode 100644
index 00000000000..0a6e23fe9da
--- /dev/null
+++ b/app/workers/design_management/copy_design_collection_worker.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+module DesignManagement
+ class CopyDesignCollectionWorker
+ include ApplicationWorker
+
+ feature_category :design_management
+ idempotent!
+ urgency :low
+
+ def perform(user_id, issue_id, target_issue_id)
+ user = User.find(user_id)
+ issue = Issue.find(issue_id)
+ target_issue = Issue.find(target_issue_id)
+
+ response = DesignManagement::CopyDesignCollection::CopyService.new(
+ target_issue.project,
+ user,
+ issue: issue,
+ target_issue: target_issue
+ ).execute
+
+ Gitlab::AppLogger.warn(response.message) if response.error?
+ end
+ end
+end
diff --git a/app/workers/design_management/new_version_worker.rb b/app/workers/design_management/new_version_worker.rb
index 3634dcbcebd..4fbf2067be4 100644
--- a/app/workers/design_management/new_version_worker.rb
+++ b/app/workers/design_management/new_version_worker.rb
@@ -9,10 +9,10 @@ module DesignManagement
# `GenerateImageVersionsService` resizing designs
worker_resource_boundary :memory
- def perform(version_id)
+ def perform(version_id, skip_system_notes = false)
version = DesignManagement::Version.find(version_id)
- add_system_note(version)
+ add_system_note(version) unless skip_system_notes
generate_image_versions(version)
rescue ActiveRecord::RecordNotFound => e
Sidekiq.logger.warn(e)
diff --git a/app/workers/disallow_two_factor_for_group_worker.rb b/app/workers/disallow_two_factor_for_group_worker.rb
new file mode 100644
index 00000000000..b3cc7a44672
--- /dev/null
+++ b/app/workers/disallow_two_factor_for_group_worker.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+class DisallowTwoFactorForGroupWorker
+ include ApplicationWorker
+ include ExceptionBacktrace
+
+ feature_category :subgroups
+ idempotent!
+
+ def perform(group_id)
+ begin
+ group = Group.find(group_id)
+ rescue ActiveRecord::RecordNotFound
+ return
+ end
+
+ group.update!(require_two_factor_authentication: false)
+ end
+end
diff --git a/app/workers/disallow_two_factor_for_subgroups_worker.rb b/app/workers/disallow_two_factor_for_subgroups_worker.rb
new file mode 100644
index 00000000000..1ca227030e2
--- /dev/null
+++ b/app/workers/disallow_two_factor_for_subgroups_worker.rb
@@ -0,0 +1,30 @@
+# frozen_string_literal: true
+
+class DisallowTwoFactorForSubgroupsWorker
+ include ApplicationWorker
+ include ExceptionBacktrace
+
+ INTERVAL = 2.seconds.to_i
+
+ feature_category :subgroups
+ idempotent!
+
+ def perform(group_id)
+ begin
+ group = Group.find(group_id)
+ rescue ActiveRecord::RecordNotFound
+ return
+ end
+
+ # rubocop: disable CodeReuse/ActiveRecord
+ subgroups = group.descendants.where(require_two_factor_authentication: true) # rubocop: disable CodeReuse/ActiveRecord
+ subgroups.find_each(batch_size: 100).with_index do |subgroup, index|
+ delay = index * INTERVAL
+
+ with_context(namespace: subgroup) do
+ DisallowTwoFactorForGroupWorker.perform_in(delay, subgroup.id)
+ end
+ end
+ # rubocop: enable CodeReuse/ActiveRecord
+ end
+end
diff --git a/app/workers/expire_build_instance_artifacts_worker.rb b/app/workers/expire_build_instance_artifacts_worker.rb
index e6cd60a3e47..a5571473b43 100644
--- a/app/workers/expire_build_instance_artifacts_worker.rb
+++ b/app/workers/expire_build_instance_artifacts_worker.rb
@@ -4,6 +4,7 @@ class ExpireBuildInstanceArtifactsWorker # rubocop:disable Scalability/Idempoten
include ApplicationWorker
feature_category :continuous_integration
+ tags :requires_disk_io
# rubocop: disable CodeReuse/ActiveRecord
def perform(build_id)
diff --git a/app/workers/export_csv_worker.rb b/app/workers/export_csv_worker.rb
index e7baaf40a41..f2da381a34a 100644
--- a/app/workers/export_csv_worker.rb
+++ b/app/workers/export_csv_worker.rb
@@ -15,8 +15,6 @@ class ExportCsvWorker # rubocop:disable Scalability/IdempotentWorker
params[:project_id] = project_id
params.delete(:sort)
- issues = IssuesFinder.new(@current_user, params).execute
-
- Issues::ExportCsvService.new(issues, @project).email(@current_user)
+ IssuableExportCsvWorker.perform_async(:issue, @current_user.id, @project.id, params)
end
end
diff --git a/app/workers/git_garbage_collect_worker.rb b/app/workers/git_garbage_collect_worker.rb
index b0307571448..9071e4b8a1b 100644
--- a/app/workers/git_garbage_collect_worker.rb
+++ b/app/workers/git_garbage_collect_worker.rb
@@ -91,14 +91,16 @@ class GitGarbageCollectWorker # rubocop:disable Scalability/IdempotentWorker
end
def cleanup_orphan_lfs_file_references(project)
- return unless Feature.enabled?(:cleanup_lfs_during_gc, project)
return if Gitlab::Database.read_only? # GitGarbageCollectWorker may be run on a Geo secondary
::Gitlab::Cleanup::OrphanLfsFileReferences.new(project, dry_run: false, logger: logger).run!
+ rescue => err
+ Gitlab::GitLogger.warn(message: "Cleaning up orphan LFS objects files failed", error: err.message)
+ Gitlab::ErrorTracking.track_and_raise_for_dev_exception(err)
end
def flush_ref_caches(project)
- project.repository.after_create_branch
+ project.repository.expire_branches_cache
project.repository.branch_names
project.repository.has_visible_content?
end
diff --git a/app/workers/group_destroy_worker.rb b/app/workers/group_destroy_worker.rb
index d80a2dad7d9..901785f462b 100644
--- a/app/workers/group_destroy_worker.rb
+++ b/app/workers/group_destroy_worker.rb
@@ -5,6 +5,7 @@ class GroupDestroyWorker # rubocop:disable Scalability/IdempotentWorker
include ExceptionBacktrace
feature_category :subgroups
+ tags :requires_disk_io
def perform(group_id, user_id)
begin
diff --git a/app/workers/group_export_worker.rb b/app/workers/group_export_worker.rb
index e22b691d35e..a212147d8fd 100644
--- a/app/workers/group_export_worker.rb
+++ b/app/workers/group_export_worker.rb
@@ -6,7 +6,7 @@ class GroupExportWorker # rubocop:disable Scalability/IdempotentWorker
feature_category :importers
loggable_arguments 2
- sidekiq_options retry: false
+ sidekiq_options retry: false, dead: false
def perform(current_user_id, group_id, params = {})
current_user = User.find(current_user_id)
diff --git a/app/workers/group_import_worker.rb b/app/workers/group_import_worker.rb
index 36d81468d55..b8b596f459b 100644
--- a/app/workers/group_import_worker.rb
+++ b/app/workers/group_import_worker.rb
@@ -3,13 +3,13 @@
class GroupImportWorker # rubocop:disable Scalability/IdempotentWorker
include ApplicationWorker
- sidekiq_options retry: false
+ sidekiq_options retry: false, dead: false
feature_category :importers
def perform(user_id, group_id)
current_user = User.find(user_id)
group = Group.find(group_id)
- group_import_state = group.import_state || group.build_import_state
+ group_import_state = group.import_state
group_import_state.jid = self.jid
group_import_state.start!
diff --git a/app/workers/incident_management/add_severity_system_note_worker.rb b/app/workers/incident_management/add_severity_system_note_worker.rb
new file mode 100644
index 00000000000..9f132531562
--- /dev/null
+++ b/app/workers/incident_management/add_severity_system_note_worker.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+module IncidentManagement
+ class AddSeveritySystemNoteWorker # rubocop:disable Scalability/IdempotentWorker
+ include ApplicationWorker
+
+ queue_namespace :incident_management
+ feature_category :incident_management
+
+ def perform(incident_id, user_id)
+ return if incident_id.blank? || user_id.blank?
+
+ incident = Issue.with_issue_type(:incident).find_by_id(incident_id)
+ return unless incident
+
+ user = User.find_by_id(user_id)
+ return unless user
+
+ SystemNoteService.change_incident_severity(incident, user)
+ end
+ end
+end
diff --git a/app/workers/issuable_export_csv_worker.rb b/app/workers/issuable_export_csv_worker.rb
new file mode 100644
index 00000000000..d91ba77287f
--- /dev/null
+++ b/app/workers/issuable_export_csv_worker.rb
@@ -0,0 +1,53 @@
+# frozen_string_literal: true
+
+class IssuableExportCsvWorker # rubocop:disable Scalability/IdempotentWorker
+ include ApplicationWorker
+
+ feature_category :issue_tracking
+ worker_resource_boundary :cpu
+ loggable_arguments 2
+
+ PERMITTED_TYPES = [:merge_request, :issue].freeze
+
+ def perform(type, current_user_id, project_id, params)
+ @type = type.to_sym
+ check_permitted_type!
+ process_params!(params, project_id)
+
+ @current_user = User.find(current_user_id)
+ @project = Project.find(project_id)
+ @service = service(find_objects(params))
+
+ @service.email(@current_user)
+ end
+
+ private
+
+ def find_objects(params)
+ case @type
+ when :issue
+ IssuesFinder.new(@current_user, params).execute
+ when :merge_request
+ MergeRequestsFinder.new(@current_user, params).execute
+ end
+ end
+
+ def service(issuables)
+ case @type
+ when :issue
+ Issues::ExportCsvService.new(issuables, @project)
+ when :merge_request
+ MergeRequests::ExportCsvService.new(issuables, @project)
+ end
+ end
+
+ def process_params!(params, project_id)
+ params.symbolize_keys!
+ params[:project_id] = project_id
+ params.delete(:sort)
+ end
+
+ def check_permitted_type!
+ raise ArgumentError, "type parameter must be :issue or :merge_request, it was #{@type}" unless PERMITTED_TYPES.include?(@type)
+ end
+end
diff --git a/app/workers/issue_placement_worker.rb b/app/workers/issue_placement_worker.rb
index a8d59e9125c..5b547ab0c8d 100644
--- a/app/workers/issue_placement_worker.rb
+++ b/app/workers/issue_placement_worker.rb
@@ -36,14 +36,14 @@ class IssuePlacementWorker
Gitlab::ErrorTracking.log_exception(e, issue_id: issue_id, project_id: project_id)
IssueRebalancingWorker.perform_async(nil, project_id.presence || issue.project_id)
end
- # rubocop: enable CodeReuse/ActiveRecord
def find_issue(issue_id, project_id)
- return Issue.id_in(issue_id).first if issue_id
+ return Issue.id_in(issue_id).take if issue_id
- project = Project.id_in(project_id).first
+ project = Project.id_in(project_id).take
return unless project
- project.issues.first
+ project.issues.take
end
+ # rubocop: enable CodeReuse/ActiveRecord
end
diff --git a/app/workers/issue_rebalancing_worker.rb b/app/workers/issue_rebalancing_worker.rb
index 032ba5534e6..a9ad66198f3 100644
--- a/app/workers/issue_rebalancing_worker.rb
+++ b/app/workers/issue_rebalancing_worker.rb
@@ -11,7 +11,8 @@ class IssueRebalancingWorker
return if project_id.nil?
project = Project.find(project_id)
- issue = project.issues.first # All issues are equivalent as far as we are concerned
+ # All issues are equivalent as far as we are concerned
+ issue = project.issues.take # rubocop: disable CodeReuse/ActiveRecord
IssueRebalancingService.new(issue).execute
rescue ActiveRecord::RecordNotFound, IssueRebalancingService::TooManyIssues => e
diff --git a/app/workers/member_invitation_reminder_emails_worker.rb b/app/workers/member_invitation_reminder_emails_worker.rb
new file mode 100644
index 00000000000..50f583005c0
--- /dev/null
+++ b/app/workers/member_invitation_reminder_emails_worker.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+class MemberInvitationReminderEmailsWorker # rubocop:disable Scalability/IdempotentWorker
+ include ApplicationWorker
+ include CronjobQueue # rubocop:disable Scalability/CronWorkerContext
+
+ feature_category :subgroups
+ urgency :low
+
+ def perform
+ return unless Gitlab::Experimentation.enabled?(:invitation_reminders)
+
+ Member.not_accepted_invitations.not_expired.last_ten_days_excluding_today.find_in_batches do |invitations|
+ invitations.each do |invitation|
+ Members::InvitationReminderEmailService.new(invitation).execute
+ end
+ end
+ end
+end
diff --git a/app/workers/metrics/dashboard/sync_dashboards_worker.rb b/app/workers/metrics/dashboard/sync_dashboards_worker.rb
new file mode 100644
index 00000000000..7a124a33f9e
--- /dev/null
+++ b/app/workers/metrics/dashboard/sync_dashboards_worker.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+module Metrics
+ module Dashboard
+ class SyncDashboardsWorker
+ include ApplicationWorker
+
+ feature_category :metrics
+
+ idempotent!
+
+ def perform(project_id)
+ project = Project.find(project_id)
+ dashboard_paths = ::Gitlab::Metrics::Dashboard::RepoDashboardFinder.list_dashboards(project)
+
+ dashboard_paths.each do |dashboard_path|
+ ::Gitlab::Metrics::Dashboard::Importer.new(dashboard_path, project).execute!
+ end
+ end
+ end
+ end
+end
diff --git a/app/workers/pages_domain_ssl_renewal_worker.rb b/app/workers/pages_domain_ssl_renewal_worker.rb
index 561fd59d471..125ba343948 100644
--- a/app/workers/pages_domain_ssl_renewal_worker.rb
+++ b/app/workers/pages_domain_ssl_renewal_worker.rb
@@ -4,6 +4,7 @@ class PagesDomainSslRenewalWorker # rubocop:disable Scalability/IdempotentWorker
include ApplicationWorker
feature_category :pages
+ tags :requires_disk_io
def perform(domain_id)
domain = PagesDomain.find_by_id(domain_id)
diff --git a/app/workers/pages_domain_verification_worker.rb b/app/workers/pages_domain_verification_worker.rb
index 1b4d9d3994c..ff0463481cd 100644
--- a/app/workers/pages_domain_verification_worker.rb
+++ b/app/workers/pages_domain_verification_worker.rb
@@ -4,6 +4,7 @@ class PagesDomainVerificationWorker # rubocop:disable Scalability/IdempotentWork
include ApplicationWorker
feature_category :pages
+ tags :requires_disk_io
# rubocop: disable CodeReuse/ActiveRecord
def perform(domain_id)
diff --git a/app/workers/pages_worker.rb b/app/workers/pages_worker.rb
index aefa4bc4223..0c561626f8c 100644
--- a/app/workers/pages_worker.rb
+++ b/app/workers/pages_worker.rb
@@ -6,6 +6,7 @@ class PagesWorker # rubocop:disable Scalability/IdempotentWorker
sidekiq_options retry: 3
feature_category :pages
loggable_arguments 0, 1
+ tags :requires_disk_io
def perform(action, *arg)
send(action, *arg) # rubocop:disable GitlabSecurity/PublicSend
diff --git a/app/workers/post_receive.rb b/app/workers/post_receive.rb
index 4a93b1af166..0b224b88e4d 100644
--- a/app/workers/post_receive.rb
+++ b/app/workers/post_receive.rb
@@ -24,7 +24,7 @@ class PostReceive # rubocop:disable Scalability/IdempotentWorker
post_received = Gitlab::GitPostReceive.new(container, identifier, changes, push_options)
if repo_type.wiki?
- process_wiki_changes(post_received, container.wiki)
+ process_wiki_changes(post_received, container)
elsif repo_type.project?
process_project_changes(post_received, container)
elsif repo_type.snippet?
diff --git a/app/workers/project_destroy_worker.rb b/app/workers/project_destroy_worker.rb
index b3e7996f4a4..99d51fc5c2e 100644
--- a/app/workers/project_destroy_worker.rb
+++ b/app/workers/project_destroy_worker.rb
@@ -5,6 +5,7 @@ class ProjectDestroyWorker # rubocop:disable Scalability/IdempotentWorker
include ExceptionBacktrace
feature_category :source_code_management
+ tags :requires_disk_io
def perform(project_id, user_id, params)
project = Project.find(project_id)
diff --git a/app/workers/project_export_worker.rb b/app/workers/project_export_worker.rb
index 6c8640138a1..1c4aa3f7e49 100644
--- a/app/workers/project_export_worker.rb
+++ b/app/workers/project_export_worker.rb
@@ -8,7 +8,7 @@ class ProjectExportWorker # rubocop:disable Scalability/IdempotentWorker
worker_resource_boundary :memory
urgency :throttled
loggable_arguments 2, 3
- sidekiq_options retry: false
+ sidekiq_options retry: false, dead: false
sidekiq_options status_expiration: StuckExportJobsWorker::EXPORT_JOBS_EXPIRATION
def perform(current_user_id, project_id, after_export_strategy = {}, params = {})
diff --git a/app/workers/propagate_integration_group_worker.rb b/app/workers/propagate_integration_group_worker.rb
new file mode 100644
index 00000000000..01155753877
--- /dev/null
+++ b/app/workers/propagate_integration_group_worker.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+class PropagateIntegrationGroupWorker
+ include ApplicationWorker
+
+ feature_category :integrations
+ idempotent!
+
+ # rubocop: disable CodeReuse/ActiveRecord
+ def perform(integration_id, min_id, max_id)
+ integration = Service.find_by_id(integration_id)
+ return unless integration
+
+ batch = if integration.instance?
+ Group.where(id: min_id..max_id).without_integration(integration)
+ else
+ integration.group.descendants.where(id: min_id..max_id).without_integration(integration)
+ end
+
+ return if batch.empty?
+
+ BulkCreateIntegrationService.new(integration, batch, 'group').execute
+ end
+ # rubocop: enable CodeReuse/ActiveRecord
+end
diff --git a/app/workers/propagate_integration_inherit_worker.rb b/app/workers/propagate_integration_inherit_worker.rb
new file mode 100644
index 00000000000..ef3132202f6
--- /dev/null
+++ b/app/workers/propagate_integration_inherit_worker.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+class PropagateIntegrationInheritWorker
+ include ApplicationWorker
+
+ feature_category :integrations
+ idempotent!
+
+ # rubocop: disable CodeReuse/ActiveRecord
+ def perform(integration_id, min_id, max_id)
+ integration = Service.find_by_id(integration_id)
+ return unless integration
+
+ services = Service.where(id: min_id..max_id).by_type(integration.type).inherit_from_id(integration.id)
+
+ BulkUpdateIntegrationService.new(integration, services).execute
+ end
+ # rubocop: enable CodeReuse/ActiveRecord
+end
diff --git a/app/workers/propagate_integration_project_worker.rb b/app/workers/propagate_integration_project_worker.rb
new file mode 100644
index 00000000000..188d81e5fc1
--- /dev/null
+++ b/app/workers/propagate_integration_project_worker.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+class PropagateIntegrationProjectWorker
+ include ApplicationWorker
+
+ feature_category :integrations
+ idempotent!
+
+ # rubocop: disable CodeReuse/ActiveRecord
+ def perform(integration_id, min_id, max_id)
+ integration = Service.find_by_id(integration_id)
+ return unless integration
+
+ batch = Project.where(id: min_id..max_id).without_integration(integration)
+ batch = batch.in_namespace(integration.group.self_and_descendants) if integration.group_id
+
+ return if batch.empty?
+
+ BulkCreateIntegrationService.new(integration, batch, 'project').execute
+ end
+ # rubocop: enable CodeReuse/ActiveRecord
+end
diff --git a/app/workers/propagate_integration_worker.rb b/app/workers/propagate_integration_worker.rb
index 68e38386372..bb954b12a25 100644
--- a/app/workers/propagate_integration_worker.rb
+++ b/app/workers/propagate_integration_worker.rb
@@ -7,7 +7,8 @@ class PropagateIntegrationWorker
idempotent!
loggable_arguments 1
- # Keep overwrite parameter for backwards compatibility.
+ # TODO: Keep overwrite parameter for backwards compatibility. Remove after >= 14.0
+ # https://gitlab.com/gitlab-org/gitlab/-/issues/255382
def perform(integration_id, overwrite = nil)
Admin::PropagateIntegrationService.propagate(Service.find(integration_id))
end
diff --git a/app/workers/repository_import_worker.rb b/app/workers/repository_import_worker.rb
index 54052bda675..51fe60e25fc 100644
--- a/app/workers/repository_import_worker.rb
+++ b/app/workers/repository_import_worker.rb
@@ -7,7 +7,8 @@ class RepositoryImportWorker # rubocop:disable Scalability/IdempotentWorker
feature_category :importers
worker_has_external_dependencies!
- sidekiq_options retry: false
+ # Do not retry on Import/Export until https://gitlab.com/gitlab-org/gitlab/-/issues/16812 is solved.
+ sidekiq_options retry: false, dead: false
sidekiq_options status_expiration: Gitlab::Import::StuckImportJob::IMPORT_JOBS_EXPIRATION
# technical debt: https://gitlab.com/gitlab-org/gitlab/issues/33991
diff --git a/app/workers/stuck_ci_jobs_worker.rb b/app/workers/stuck_ci_jobs_worker.rb
index f8209ae5e63..eca0a248a37 100644
--- a/app/workers/stuck_ci_jobs_worker.rb
+++ b/app/workers/stuck_ci_jobs_worker.rb
@@ -17,7 +17,7 @@ class StuckCiJobsWorker # rubocop:disable Scalability/IdempotentWorker
def perform
return unless try_obtain_lease
- Gitlab::AppLogger.info "#{self.class}: Cleaning stuck builds" # rubocop:disable Gitlab/RailsLogger
+ Gitlab::AppLogger.info "#{self.class}: Cleaning stuck builds"
drop :running, BUILD_RUNNING_OUTDATED_TIMEOUT, 'ci_builds.updated_at < ?', :stuck_or_timeout_failure
drop :pending, BUILD_PENDING_OUTDATED_TIMEOUT, 'ci_builds.updated_at < ?', :stuck_or_timeout_failure
diff --git a/app/workers/web_hooks/destroy_worker.rb b/app/workers/web_hooks/destroy_worker.rb
new file mode 100644
index 00000000000..13a5a7bf1e6
--- /dev/null
+++ b/app/workers/web_hooks/destroy_worker.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+module WebHooks
+ class DestroyWorker
+ include ApplicationWorker
+
+ feature_category :integrations
+ urgency :low
+ idempotent!
+
+ def perform(user_id, web_hook_id)
+ user = User.find_by_id(user_id)
+ hook = WebHook.find_by_id(web_hook_id)
+
+ return unless user && hook
+
+ result = ::WebHooks::DestroyService.new(user).sync_destroy(hook)
+
+ return result if result[:status] == :success
+
+ e = ::WebHooks::DestroyService::DestroyError.new(result[:message])
+ Gitlab::ErrorTracking.track_exception(e, web_hook_id: hook.id)
+
+ raise e
+ end
+ end
+end
diff --git a/bin/feature-flag b/bin/feature-flag
index 9a550dc8884..b5e7889be1d 100755
--- a/bin/feature-flag
+++ b/bin/feature-flag
@@ -153,6 +153,10 @@ class FeatureFlagOptionParser
end
end
+ def read_ee_only(options)
+ TYPES.dig(options.type, :ee_only)
+ end
+
def read_rollout_issue_url(options)
return unless TYPES.dig(options.type, :rollout_issue)
@@ -204,6 +208,7 @@ class FeatureFlagCreator
# Read type from $stdin unless is already set
options.type ||= FeatureFlagOptionParser.read_type
+ options.ee ||= FeatureFlagOptionParser.read_ee_only(options)
options.group ||= FeatureFlagOptionParser.read_group
options.introduced_by_url ||= FeatureFlagOptionParser.read_introduced_by_url
options.rollout_issue_url ||= FeatureFlagOptionParser.read_rollout_issue_url(options)
@@ -224,14 +229,22 @@ class FeatureFlagCreator
private
def contents
- YAML.dump(
+ # Slice is used to ensure that YAML keys
+ # are always ordered in a predictable way
+ config_hash.slice(
+ *::Feature::Shared::PARAMS.map(&:to_s)
+ ).to_yaml
+ end
+
+ def config_hash
+ {
'name' => options.name,
'introduced_by_url' => options.introduced_by_url,
'rollout_issue_url' => options.rollout_issue_url,
- 'group' => options.group.to_s,
+ 'group' => options.group,
'type' => options.type.to_s,
'default_enabled' => FeatureFlagOptionParser.read_default_enabled(options)
- ).strip
+ }
end
def write
diff --git a/changelogs/unreleased/-231183-invites.yml b/changelogs/unreleased/-231183-invites.yml
new file mode 100644
index 00000000000..3dae27472fc
--- /dev/null
+++ b/changelogs/unreleased/-231183-invites.yml
@@ -0,0 +1,5 @@
+---
+title: Apply GitLab UI button styles to buttons in app/views/invites directory
+merge_request: 44289
+author: Lakshit
+type: other
diff --git a/changelogs/unreleased/-231185-admin-jobs.yml b/changelogs/unreleased/-231185-admin-jobs.yml
new file mode 100644
index 00000000000..5f2e1279d00
--- /dev/null
+++ b/changelogs/unreleased/-231185-admin-jobs.yml
@@ -0,0 +1,5 @@
+---
+title: Apply GitLab UI button styles to buttons in app/views/admin/jobs directory
+merge_request: 44291
+author: Lakshit
+type: other
diff --git a/changelogs/unreleased/-231191-projects-services-mattermost_slash_commands.yml b/changelogs/unreleased/-231191-projects-services-mattermost_slash_commands.yml
new file mode 100644
index 00000000000..48470ae1d4e
--- /dev/null
+++ b/changelogs/unreleased/-231191-projects-services-mattermost_slash_commands.yml
@@ -0,0 +1,5 @@
+---
+title: Apply GitLab UI button styles to buttons in app/views/projects/services/mattermost_slash_commands
+merge_request: 44293
+author: Lakshit
+type: other
diff --git a/changelogs/unreleased/-231200-projects-issues-export_csv.yml b/changelogs/unreleased/-231200-projects-issues-export_csv.yml
new file mode 100644
index 00000000000..90f30207926
--- /dev/null
+++ b/changelogs/unreleased/-231200-projects-issues-export_csv.yml
@@ -0,0 +1,5 @@
+---
+title: Apply gl-button class to projects/issues/export_csv directory
+merge_request: 44106
+author: Lakshit
+type: other
diff --git a/changelogs/unreleased/-231206-projects-commits.yml b/changelogs/unreleased/-231206-projects-commits.yml
new file mode 100644
index 00000000000..981dc5b6da1
--- /dev/null
+++ b/changelogs/unreleased/-231206-projects-commits.yml
@@ -0,0 +1,5 @@
+---
+title: Apply GitLab UI button styles to buttons in app/views/projects/commits directory
+merge_request: 44331
+author: Lakshit
+type: other
diff --git a/changelogs/unreleased/-231207-projects-compare.yml b/changelogs/unreleased/-231207-projects-compare.yml
new file mode 100644
index 00000000000..37ebf5e7e4f
--- /dev/null
+++ b/changelogs/unreleased/-231207-projects-compare.yml
@@ -0,0 +1,5 @@
+---
+title: Apply GitLab UI button styles to buttons in app/views/projects/compare directory
+merge_request: 44342
+author: Lakshit
+type: other
diff --git a/changelogs/unreleased/-231208-sherlock-file_samples.yml b/changelogs/unreleased/-231208-sherlock-file_samples.yml
new file mode 100644
index 00000000000..69402e37ae0
--- /dev/null
+++ b/changelogs/unreleased/-231208-sherlock-file_samples.yml
@@ -0,0 +1,5 @@
+---
+title: Apply GitLab UI button styles to buttons in app/views/sherlock/file_samples
+merge_request: 44109
+author: Lakshit
+type: other
diff --git a/changelogs/unreleased/-231217-shared-wikis.yml b/changelogs/unreleased/-231217-shared-wikis.yml
new file mode 100644
index 00000000000..7d565965941
--- /dev/null
+++ b/changelogs/unreleased/-231217-shared-wikis.yml
@@ -0,0 +1,5 @@
+---
+title: Apply GitLab UI button styles to buttons in app/views/shared/wikis directory
+merge_request: 44338
+author: Lakshit
+type: other
diff --git a/changelogs/unreleased/-231225-projects-deployments.yml b/changelogs/unreleased/-231225-projects-deployments.yml
new file mode 100644
index 00000000000..140f1e9672c
--- /dev/null
+++ b/changelogs/unreleased/-231225-projects-deployments.yml
@@ -0,0 +1,5 @@
+---
+title: Add gl-button class to app/views/projects/deployments
+merge_request: 44203
+author: Lakshit
+type: other
diff --git a/changelogs/unreleased/10io-return-empty-string-for-md5-maven-upload-requests.yml b/changelogs/unreleased/10io-return-empty-string-for-md5-maven-upload-requests.yml
new file mode 100644
index 00000000000..e938bb50de1
--- /dev/null
+++ b/changelogs/unreleased/10io-return-empty-string-for-md5-maven-upload-requests.yml
@@ -0,0 +1,5 @@
+---
+title: Fix the maven md5 upload endpoint
+merge_request: 45271
+author:
+type: fixed
diff --git a/changelogs/unreleased/119032-add-filename-to-unit-test-report.yml b/changelogs/unreleased/119032-add-filename-to-unit-test-report.yml
new file mode 100644
index 00000000000..51b8b3b9287
--- /dev/null
+++ b/changelogs/unreleased/119032-add-filename-to-unit-test-report.yml
@@ -0,0 +1,5 @@
+---
+title: Add file name column to CI unit test report
+merge_request: 43338
+author:
+type: added
diff --git a/changelogs/unreleased/13426-bugfix-copyState-and-padding.yml b/changelogs/unreleased/13426-bugfix-copyState-and-padding.yml
new file mode 100644
index 00000000000..9be2b78ed70
--- /dev/null
+++ b/changelogs/unreleased/13426-bugfix-copyState-and-padding.yml
@@ -0,0 +1,5 @@
+---
+title: Fix displaying a message when design copying is in progress
+merge_request: 43749
+author:
+type: fixed
diff --git a/changelogs/unreleased/13426-copy-designs.yml b/changelogs/unreleased/13426-copy-designs.yml
new file mode 100644
index 00000000000..aabdd709bd7
--- /dev/null
+++ b/changelogs/unreleased/13426-copy-designs.yml
@@ -0,0 +1,5 @@
+---
+title: Copy designs to new issue when issue is moved
+merge_request: 41714
+author:
+type: added
diff --git a/changelogs/unreleased/13426-graphql-fe.yml b/changelogs/unreleased/13426-graphql-fe.yml
new file mode 100644
index 00000000000..8058a6925df
--- /dev/null
+++ b/changelogs/unreleased/13426-graphql-fe.yml
@@ -0,0 +1,5 @@
+---
+title: Copy designs to issue when an issue with designs is moved
+merge_request: 42548
+author:
+type: fixed
diff --git a/changelogs/unreleased/13426-graphql.yml b/changelogs/unreleased/13426-graphql.yml
new file mode 100644
index 00000000000..b3a86f8bd5c
--- /dev/null
+++ b/changelogs/unreleased/13426-graphql.yml
@@ -0,0 +1,5 @@
+---
+title: Add DesignCollection copyState GraphQL field
+merge_request: 42919
+author:
+type: added
diff --git a/changelogs/unreleased/13426-remove-feature-flag.yml b/changelogs/unreleased/13426-remove-feature-flag.yml
new file mode 100644
index 00000000000..3666a7a7119
--- /dev/null
+++ b/changelogs/unreleased/13426-remove-feature-flag.yml
@@ -0,0 +1,5 @@
+---
+title: Designs are moved with an Issue that is moved
+merge_request: 44524
+author:
+type: fixed
diff --git a/changelogs/unreleased/17673-wiki-pages-tree-structure.yml b/changelogs/unreleased/17673-wiki-pages-tree-structure.yml
new file mode 100644
index 00000000000..e946a267dd9
--- /dev/null
+++ b/changelogs/unreleased/17673-wiki-pages-tree-structure.yml
@@ -0,0 +1,5 @@
+---
+title: Show wiki tree structure in sidebar and pages overview
+merge_request: 42867
+author:
+type: changed
diff --git a/changelogs/unreleased/18324-add-links-to-urls-in-job-logs.yml b/changelogs/unreleased/18324-add-links-to-urls-in-job-logs.yml
new file mode 100644
index 00000000000..884022e7f86
--- /dev/null
+++ b/changelogs/unreleased/18324-add-links-to-urls-in-job-logs.yml
@@ -0,0 +1,5 @@
+---
+title: Make URL links in job logs clickable
+merge_request: 40175
+author: Åukasz Groszkowski @falxcerebri
+type: added
diff --git a/changelogs/unreleased/18969-allow-optional-caching-in-failed-builds.yml b/changelogs/unreleased/18969-allow-optional-caching-in-failed-builds.yml
new file mode 100644
index 00000000000..7b55ecc75d8
--- /dev/null
+++ b/changelogs/unreleased/18969-allow-optional-caching-in-failed-builds.yml
@@ -0,0 +1,5 @@
+---
+title: Add cache:when keyword for ci yml config
+merge_request: 41822
+author:
+type: added
diff --git a/changelogs/unreleased/197227-load-milestone-issues-tab-async.yml b/changelogs/unreleased/197227-load-milestone-issues-tab-async.yml
new file mode 100644
index 00000000000..b3f427ddbdd
--- /dev/null
+++ b/changelogs/unreleased/197227-load-milestone-issues-tab-async.yml
@@ -0,0 +1,5 @@
+---
+title: Load issues tab in the milestone page asynchronously
+merge_request: 42473
+author:
+type: performance
diff --git a/changelogs/unreleased/198-add-automation-friendly-migration-rake-tasks.yml b/changelogs/unreleased/198-add-automation-friendly-migration-rake-tasks.yml
new file mode 100644
index 00000000000..77a51de52b2
--- /dev/null
+++ b/changelogs/unreleased/198-add-automation-friendly-migration-rake-tasks.yml
@@ -0,0 +1,5 @@
+---
+title: Add unattended database migration option
+merge_request: 44392
+author:
+type: added
diff --git a/changelogs/unreleased/198413-CI-Pre-Collapsed-Sections.yml b/changelogs/unreleased/198413-CI-Pre-Collapsed-Sections.yml
new file mode 100644
index 00000000000..d31052a11a1
--- /dev/null
+++ b/changelogs/unreleased/198413-CI-Pre-Collapsed-Sections.yml
@@ -0,0 +1,5 @@
+---
+title: Pre-Collapsed Sections in CI Job Logs
+merge_request: 42231
+author: Kev @KevSlashNull
+type: added
diff --git a/changelogs/unreleased/198612-monaco-ci-default.yml b/changelogs/unreleased/198612-monaco-ci-default.yml
new file mode 100644
index 00000000000..3fbef70f629
--- /dev/null
+++ b/changelogs/unreleased/198612-monaco-ci-default.yml
@@ -0,0 +1,5 @@
+---
+title: Replaced ACE with Editor Lite for CI linting
+merge_request: 42814
+author:
+type: added
diff --git a/changelogs/unreleased/202264-migrate-fa-spinner-to-spinner-for-app-assets-javascripts-vue_share.yml b/changelogs/unreleased/202264-migrate-fa-spinner-to-spinner-for-app-assets-javascripts-vue_share.yml
new file mode 100644
index 00000000000..0d8801a3880
--- /dev/null
+++ b/changelogs/unreleased/202264-migrate-fa-spinner-to-spinner-for-app-assets-javascripts-vue_share.yml
@@ -0,0 +1,5 @@
+---
+title: Migrate '.fa-spinner' to '.spinner' for 'awards_list.vue'
+merge_request: 45393
+author:
+type: changed
diff --git a/changelogs/unreleased/205157-cannot-include-downstream-pipeline-with-include-file.yml b/changelogs/unreleased/205157-cannot-include-downstream-pipeline-with-include-file.yml
new file mode 100644
index 00000000000..fea95fa43e1
--- /dev/null
+++ b/changelogs/unreleased/205157-cannot-include-downstream-pipeline-with-include-file.yml
@@ -0,0 +1,5 @@
+---
+title: Allow to include project files in parent-child pipelines
+merge_request: 43404
+author:
+type: fixed
diff --git a/changelogs/unreleased/207347-terraform-versions-api.yml b/changelogs/unreleased/207347-terraform-versions-api.yml
new file mode 100644
index 00000000000..e20b754ceac
--- /dev/null
+++ b/changelogs/unreleased/207347-terraform-versions-api.yml
@@ -0,0 +1,5 @@
+---
+title: Add API endpoints to manage individual Terraform state versions
+merge_request: 42415
+author:
+type: added
diff --git a/changelogs/unreleased/208193-add-expiration-started-at-to-container-repositories.yml b/changelogs/unreleased/208193-add-expiration-started-at-to-container-repositories.yml
new file mode 100644
index 00000000000..27f46240a5c
--- /dev/null
+++ b/changelogs/unreleased/208193-add-expiration-started-at-to-container-repositories.yml
@@ -0,0 +1,5 @@
+---
+title: Add expiration policy started at support in container repositories
+merge_request: 42598
+author:
+type: added
diff --git a/changelogs/unreleased/208260-fix-mr-task-lists-starting-with-new-line.yml b/changelogs/unreleased/208260-fix-mr-task-lists-starting-with-new-line.yml
new file mode 100644
index 00000000000..3f9efc17abc
--- /dev/null
+++ b/changelogs/unreleased/208260-fix-mr-task-lists-starting-with-new-line.yml
@@ -0,0 +1,5 @@
+---
+title: Fix checking of task lists when MR description starts with a blank line
+merge_request: 43125
+author:
+type: fixed
diff --git a/changelogs/unreleased/209831-propagate-integrations-using-batching-and-queues.yml b/changelogs/unreleased/209831-propagate-integrations-using-batching-and-queues.yml
new file mode 100644
index 00000000000..d46b05c5e92
--- /dev/null
+++ b/changelogs/unreleased/209831-propagate-integrations-using-batching-and-queues.yml
@@ -0,0 +1,5 @@
+---
+title: Update database index on namespaces for type and id
+merge_request: 42128
+author:
+type: other
diff --git a/changelogs/unreleased/212373-249588-enable-ci_new_artifact_file_reader.yml b/changelogs/unreleased/212373-249588-enable-ci_new_artifact_file_reader.yml
new file mode 100644
index 00000000000..c5b485e9951
--- /dev/null
+++ b/changelogs/unreleased/212373-249588-enable-ci_new_artifact_file_reader.yml
@@ -0,0 +1,5 @@
+---
+title: Fix triggering multiple children pipeline with the same artifact
+merge_request: 42595
+author:
+type: fixed
diff --git a/changelogs/unreleased/215669-create-auto-fix-bot.yml b/changelogs/unreleased/215669-create-auto-fix-bot.yml
new file mode 100644
index 00000000000..11c59ea3aee
--- /dev/null
+++ b/changelogs/unreleased/215669-create-auto-fix-bot.yml
@@ -0,0 +1,5 @@
+---
+title: Add security bot
+merge_request: 43147
+author:
+type: added
diff --git a/changelogs/unreleased/215697-allow-groups-to-disable-2fa-requirement-for-subgroups-migration.yml b/changelogs/unreleased/215697-allow-groups-to-disable-2fa-requirement-for-subgroups-migration.yml
new file mode 100644
index 00000000000..e6a5e68ffc6
--- /dev/null
+++ b/changelogs/unreleased/215697-allow-groups-to-disable-2fa-requirement-for-subgroups-migration.yml
@@ -0,0 +1,6 @@
+---
+title: Add namespace setting to allow to mark if parent group allow subgroups to require
+ 2FA
+merge_request: 41760
+author:
+type: added
diff --git a/changelogs/unreleased/215697-allow-groups-to-disable-2fa-requirement-for-subgroups-ui.yml b/changelogs/unreleased/215697-allow-groups-to-disable-2fa-requirement-for-subgroups-ui.yml
new file mode 100644
index 00000000000..12c2636c35e
--- /dev/null
+++ b/changelogs/unreleased/215697-allow-groups-to-disable-2fa-requirement-for-subgroups-ui.yml
@@ -0,0 +1,5 @@
+---
+title: Allow groups to disable 2FA requirement for subgroups
+merge_request: 44712
+author:
+type: added
diff --git a/changelogs/unreleased/216438-add-lsif-to-go-auto-devops-gitlab-ci-yml.yml b/changelogs/unreleased/216438-add-lsif-to-go-auto-devops-gitlab-ci-yml.yml
new file mode 100644
index 00000000000..08df708e2da
--- /dev/null
+++ b/changelogs/unreleased/216438-add-lsif-to-go-auto-devops-gitlab-ci-yml.yml
@@ -0,0 +1,5 @@
+---
+title: Add LSIF to Go Auto DevOps gitlab-ci.yml
+merge_request: 40072
+author:
+type: added
diff --git a/changelogs/unreleased/21654-ide-button-in-mr-diff-files.yml b/changelogs/unreleased/21654-ide-button-in-mr-diff-files.yml
new file mode 100644
index 00000000000..6c56b39bc0f
--- /dev/null
+++ b/changelogs/unreleased/21654-ide-button-in-mr-diff-files.yml
@@ -0,0 +1,5 @@
+---
+title: Add Web IDE as dropdown item to diff file edit
+merge_request: 42275
+author:
+type: changed
diff --git a/changelogs/unreleased/216571-terraform-states-graphql-endpoint.yml b/changelogs/unreleased/216571-terraform-states-graphql-endpoint.yml
new file mode 100644
index 00000000000..6b3c0dd0875
--- /dev/null
+++ b/changelogs/unreleased/216571-terraform-states-graphql-endpoint.yml
@@ -0,0 +1,5 @@
+---
+title: Add GraphQL endpoint for Terraform state metadata
+merge_request: 43375
+author:
+type: added
diff --git a/changelogs/unreleased/216642-display-youtube-iframes.yml b/changelogs/unreleased/216642-display-youtube-iframes.yml
new file mode 100644
index 00000000000..7dbb1d3ff35
--- /dev/null
+++ b/changelogs/unreleased/216642-display-youtube-iframes.yml
@@ -0,0 +1,5 @@
+---
+title: Display youtube videos on the Static Site Editor
+merge_request: 39756
+author:
+type: added
diff --git a/changelogs/unreleased/216642-embed-youtube-video.yml b/changelogs/unreleased/216642-embed-youtube-video.yml
new file mode 100644
index 00000000000..cdfa02670eb
--- /dev/null
+++ b/changelogs/unreleased/216642-embed-youtube-video.yml
@@ -0,0 +1,5 @@
+---
+title: Add the ability to insert a YouTube video
+merge_request: 44102
+author:
+type: added
diff --git a/changelogs/unreleased/216861-autosave.yml b/changelogs/unreleased/216861-autosave.yml
new file mode 100644
index 00000000000..235075927a6
--- /dev/null
+++ b/changelogs/unreleased/216861-autosave.yml
@@ -0,0 +1,5 @@
+---
+title: Preserve the merge request title and description in the static site editor upon modal close
+merge_request: 44512
+author:
+type: added
diff --git a/changelogs/unreleased/216861-ui-for-mr-title-description.yml b/changelogs/unreleased/216861-ui-for-mr-title-description.yml
new file mode 100644
index 00000000000..0fb500f1fdb
--- /dev/null
+++ b/changelogs/unreleased/216861-ui-for-mr-title-description.yml
@@ -0,0 +1,5 @@
+---
+title: Add merge request title and description UI to Static Site Editor submission flow
+merge_request: 44071
+author:
+type: added
diff --git a/changelogs/unreleased/216881-add-close-button-to-sidebar-labels-to-remove.yml b/changelogs/unreleased/216881-add-close-button-to-sidebar-labels-to-remove.yml
new file mode 100644
index 00000000000..12599aeec42
--- /dev/null
+++ b/changelogs/unreleased/216881-add-close-button-to-sidebar-labels-to-remove.yml
@@ -0,0 +1,5 @@
+---
+title: Add close button to issue, MR, and epic sidebar labels
+merge_request: 42703
+author:
+type: added
diff --git a/changelogs/unreleased/216881-remove-vue_sidebar_labels-feature-flag.yml b/changelogs/unreleased/216881-remove-vue_sidebar_labels-feature-flag.yml
new file mode 100644
index 00000000000..703ca9bfe26
--- /dev/null
+++ b/changelogs/unreleased/216881-remove-vue_sidebar_labels-feature-flag.yml
@@ -0,0 +1,5 @@
+---
+title: Update issue and MR sidebar labels to use Vue instead of Haml
+merge_request: 44942
+author:
+type: changed
diff --git a/changelogs/unreleased/217115-assign-epic-to-a-group-when-creating-within-another-epic.yml b/changelogs/unreleased/217115-assign-epic-to-a-group-when-creating-within-another-epic.yml
new file mode 100644
index 00000000000..71e7cf38426
--- /dev/null
+++ b/changelogs/unreleased/217115-assign-epic-to-a-group-when-creating-within-another-epic.yml
@@ -0,0 +1,5 @@
+---
+title: Add a REST API endpoint to list group's descendants
+merge_request: 42620
+author:
+type: added
diff --git a/changelogs/unreleased/217157-nuget-version-regex.yml b/changelogs/unreleased/217157-nuget-version-regex.yml
new file mode 100644
index 00000000000..53248d1837a
--- /dev/null
+++ b/changelogs/unreleased/217157-nuget-version-regex.yml
@@ -0,0 +1,5 @@
+---
+title: Update NuGet version validation to allow for extended versions
+merge_request: 44335
+author:
+type: fixed
diff --git a/changelogs/unreleased/217722-fj-add-spam-mechanism-to-snippet-mutations.yml b/changelogs/unreleased/217722-fj-add-spam-mechanism-to-snippet-mutations.yml
new file mode 100644
index 00000000000..70e1099e7d8
--- /dev/null
+++ b/changelogs/unreleased/217722-fj-add-spam-mechanism-to-snippet-mutations.yml
@@ -0,0 +1,5 @@
+---
+title: Add spam flag to snippet create/update mutations
+merge_request: 44010
+author:
+type: changed
diff --git a/changelogs/unreleased/217809-fj-remove-snippet-multiple-files-ff.yml b/changelogs/unreleased/217809-fj-remove-snippet-multiple-files-ff.yml
new file mode 100644
index 00000000000..1ce966770a1
--- /dev/null
+++ b/changelogs/unreleased/217809-fj-remove-snippet-multiple-files-ff.yml
@@ -0,0 +1,5 @@
+---
+title: Enable snippet multiple files
+merge_request: 43246
+author:
+type: added
diff --git a/changelogs/unreleased/217882-allow-designs-to-be-added-to-moved-issues.yml b/changelogs/unreleased/217882-allow-designs-to-be-added-to-moved-issues.yml
new file mode 100644
index 00000000000..0237ad2d3e2
--- /dev/null
+++ b/changelogs/unreleased/217882-allow-designs-to-be-added-to-moved-issues.yml
@@ -0,0 +1,5 @@
+---
+title: Allow designs to be added, changed, or destroyed on locked and moved issues
+merge_request: 42935
+author:
+type: changed
diff --git a/changelogs/unreleased/219915-cleanup-policy-not-working.yml b/changelogs/unreleased/219915-cleanup-policy-not-working.yml
new file mode 100644
index 00000000000..7dfe0edeb7e
--- /dev/null
+++ b/changelogs/unreleased/219915-cleanup-policy-not-working.yml
@@ -0,0 +1,5 @@
+---
+title: Fix bug to allow container cleanup policies to properly run
+merge_request: 43359
+author:
+type: fixed
diff --git a/changelogs/unreleased/219951-improve-styling-of-design-pins.yml b/changelogs/unreleased/219951-improve-styling-of-design-pins.yml
new file mode 100644
index 00000000000..e81e2e7409b
--- /dev/null
+++ b/changelogs/unreleased/219951-improve-styling-of-design-pins.yml
@@ -0,0 +1,5 @@
+---
+title: Update styling of design comment pins
+merge_request: 39797
+author:
+type: changed
diff --git a/changelogs/unreleased/220182-remove-feature-flag.yml b/changelogs/unreleased/220182-remove-feature-flag.yml
new file mode 100644
index 00000000000..90eeff08826
--- /dev/null
+++ b/changelogs/unreleased/220182-remove-feature-flag.yml
@@ -0,0 +1,5 @@
+---
+title: Display cluster list node information
+merge_request: 42396
+author:
+type: added
diff --git a/changelogs/unreleased/220203-gitlab-com-sso-create-no-access-role-fe-changes.yml b/changelogs/unreleased/220203-gitlab-com-sso-create-no-access-role-fe-changes.yml
new file mode 100644
index 00000000000..d8b42d0bebc
--- /dev/null
+++ b/changelogs/unreleased/220203-gitlab-com-sso-create-no-access-role-fe-changes.yml
@@ -0,0 +1,5 @@
+---
+title: Add No Access Role for top group members
+merge_request: 40942
+author:
+type: added
diff --git a/changelogs/unreleased/220388-project-access-tokens-bot-not-deleted-when-token-expires.yml b/changelogs/unreleased/220388-project-access-tokens-bot-not-deleted-when-token-expires.yml
new file mode 100644
index 00000000000..cdd843101f5
--- /dev/null
+++ b/changelogs/unreleased/220388-project-access-tokens-bot-not-deleted-when-token-expires.yml
@@ -0,0 +1,5 @@
+---
+title: Remove project bot user membership when project access token expires
+merge_request: 43605
+author:
+type: fixed
diff --git a/changelogs/unreleased/220420-migration-validate-designs-filename-text-limit.yml b/changelogs/unreleased/220420-migration-validate-designs-filename-text-limit.yml
new file mode 100644
index 00000000000..c3b2abfcc0a
--- /dev/null
+++ b/changelogs/unreleased/220420-migration-validate-designs-filename-text-limit.yml
@@ -0,0 +1,5 @@
+---
+title: Add migration to validate design_management_designs.filename text limit constraint
+merge_request: 43952
+author:
+type: other
diff --git a/changelogs/unreleased/220503_bug_add_branches_to_be_notified_to_hangouts_service_api.yml b/changelogs/unreleased/220503_bug_add_branches_to_be_notified_to_hangouts_service_api.yml
new file mode 100644
index 00000000000..22f81687cef
--- /dev/null
+++ b/changelogs/unreleased/220503_bug_add_branches_to_be_notified_to_hangouts_service_api.yml
@@ -0,0 +1,5 @@
+---
+title: Fix branches_to_be_notified API param for hangouts chat service
+merge_request: 35599
+author:
+type: fixed
diff --git a/changelogs/unreleased/220561-fix-invalid-project-path-response-in-go-middleware.yml b/changelogs/unreleased/220561-fix-invalid-project-path-response-in-go-middleware.yml
new file mode 100644
index 00000000000..8c72e60250b
--- /dev/null
+++ b/changelogs/unreleased/220561-fix-invalid-project-path-response-in-go-middleware.yml
@@ -0,0 +1,5 @@
+---
+title: Handle the blacklisted ip error in the Go middleware
+merge_request: 44614
+author:
+type: changed
diff --git a/changelogs/unreleased/220795-remove-snippets-vue-feature-flag.yml b/changelogs/unreleased/220795-remove-snippets-vue-feature-flag.yml
new file mode 100644
index 00000000000..da85070cdc6
--- /dev/null
+++ b/changelogs/unreleased/220795-remove-snippets-vue-feature-flag.yml
@@ -0,0 +1,5 @@
+---
+title: Fix full screen comment button on snippets
+merge_request: 44083
+author:
+type: fixed
diff --git a/changelogs/unreleased/222511-missing-tooltip-for-redeploy.yml b/changelogs/unreleased/222511-missing-tooltip-for-redeploy.yml
new file mode 100644
index 00000000000..bc409fe1b27
--- /dev/null
+++ b/changelogs/unreleased/222511-missing-tooltip-for-redeploy.yml
@@ -0,0 +1,5 @@
+---
+title: Add tooltip for pipeline actions
+merge_request: 44317
+author:
+type: fixed
diff --git a/changelogs/unreleased/222699-wiki-find-page-empty-title.yml b/changelogs/unreleased/222699-wiki-find-page-empty-title.yml
new file mode 100644
index 00000000000..87388938b80
--- /dev/null
+++ b/changelogs/unreleased/222699-wiki-find-page-empty-title.yml
@@ -0,0 +1,5 @@
+---
+title: Return nil when fetching a wiki page with invalid arguments
+merge_request: 44302
+author:
+type: fixed
diff --git a/changelogs/unreleased/223101-follow-up-from-replace-double-angle-icons-with-chevron.yml b/changelogs/unreleased/223101-follow-up-from-replace-double-angle-icons-with-chevron.yml
new file mode 100644
index 00000000000..743e4621767
--- /dev/null
+++ b/changelogs/unreleased/223101-follow-up-from-replace-double-angle-icons-with-chevron.yml
@@ -0,0 +1,5 @@
+---
+title: Replace double angle icons with GitLab SVG in issuables sidebar
+merge_request: 43655
+author:
+type: changed
diff --git a/changelogs/unreleased/223236_update_middleman_logo.yml b/changelogs/unreleased/223236_update_middleman_logo.yml
new file mode 100644
index 00000000000..9a8a95fbdb0
--- /dev/null
+++ b/changelogs/unreleased/223236_update_middleman_logo.yml
@@ -0,0 +1,5 @@
+---
+title: Add Middleman Logo for Project Templates
+merge_request: 44617
+author:
+type: added
diff --git a/changelogs/unreleased/224143-suggestion-button-not-work-for-numbers.yml b/changelogs/unreleased/224143-suggestion-button-not-work-for-numbers.yml
new file mode 100644
index 00000000000..3a7e88b2ef1
--- /dev/null
+++ b/changelogs/unreleased/224143-suggestion-button-not-work-for-numbers.yml
@@ -0,0 +1,5 @@
+---
+title: Ensure suggestion works for number text
+merge_request: 44332
+author:
+type: fixed
diff --git a/changelogs/unreleased/224527-replace-fa-search-with-gitlab-svg-search-icon.yml b/changelogs/unreleased/224527-replace-fa-search-with-gitlab-svg-search-icon.yml
new file mode 100644
index 00000000000..d52f4289d78
--- /dev/null
+++ b/changelogs/unreleased/224527-replace-fa-search-with-gitlab-svg-search-icon.yml
@@ -0,0 +1,5 @@
+---
+title: Replace fa-search with GitLab SVG search icon
+merge_request: 43110
+author:
+type: changed
diff --git a/changelogs/unreleased/225164-add-a-title-section-to-the-package-registry-ui.yml b/changelogs/unreleased/225164-add-a-title-section-to-the-package-registry-ui.yml
new file mode 100644
index 00000000000..866b99a4e61
--- /dev/null
+++ b/changelogs/unreleased/225164-add-a-title-section-to-the-package-registry-ui.yml
@@ -0,0 +1,5 @@
+---
+title: Add a title section to the Package Registry UI
+merge_request: 42963
+author:
+type: changed
diff --git a/changelogs/unreleased/225175-change-the-default-order-for-packages-in-the-package-registry-list.yml b/changelogs/unreleased/225175-change-the-default-order-for-packages-in-the-package-registry-list.yml
new file mode 100644
index 00000000000..63c800ee990
--- /dev/null
+++ b/changelogs/unreleased/225175-change-the-default-order-for-packages-in-the-package-registry-list.yml
@@ -0,0 +1,5 @@
+---
+title: Rename Created to Published in package sort dropdown
+merge_request: 42677
+author:
+type: changed
diff --git a/changelogs/unreleased/225293-emaill-participants.yml b/changelogs/unreleased/225293-emaill-participants.yml
new file mode 100644
index 00000000000..78a4853dc6f
--- /dev/null
+++ b/changelogs/unreleased/225293-emaill-participants.yml
@@ -0,0 +1,5 @@
+---
+title: Add issue_email_participants table and related model
+merge_request: 42943
+author:
+type: other
diff --git a/changelogs/unreleased/225644-package-registry-in-the-group-registry-view-make-the-project-ui-mo.yml b/changelogs/unreleased/225644-package-registry-in-the-group-registry-view-make-the-project-ui-mo.yml
new file mode 100644
index 00000000000..cce1d360787
--- /dev/null
+++ b/changelogs/unreleased/225644-package-registry-in-the-group-registry-view-make-the-project-ui-mo.yml
@@ -0,0 +1,5 @@
+---
+title: Breadcrumb like UI for project path in packages list
+merge_request: 42684
+author:
+type: changed
diff --git a/changelogs/unreleased/225655-alert-new-page.yml b/changelogs/unreleased/225655-alert-new-page.yml
new file mode 100644
index 00000000000..baae40eccfb
--- /dev/null
+++ b/changelogs/unreleased/225655-alert-new-page.yml
@@ -0,0 +1,5 @@
+---
+title: Allow alerts to open on new tab
+merge_request: 42691
+author:
+type: changed
diff --git a/changelogs/unreleased/225930-replace-fa-file-icons-with-gitlab-svg-document-icon.yml b/changelogs/unreleased/225930-replace-fa-file-icons-with-gitlab-svg-document-icon.yml
new file mode 100644
index 00000000000..3ff8962d738
--- /dev/null
+++ b/changelogs/unreleased/225930-replace-fa-file-icons-with-gitlab-svg-document-icon.yml
@@ -0,0 +1,5 @@
+---
+title: Replace fa-file icons with GitLab SVG document icon
+merge_request: 45380
+author:
+type: changed
diff --git a/changelogs/unreleased/225941-replace-fa-file-text-o-icons-with-gitlab-svg-doc-text-icon.yml b/changelogs/unreleased/225941-replace-fa-file-text-o-icons-with-gitlab-svg-doc-text-icon.yml
new file mode 100644
index 00000000000..c4b83fa4adb
--- /dev/null
+++ b/changelogs/unreleased/225941-replace-fa-file-text-o-icons-with-gitlab-svg-doc-text-icon.yml
@@ -0,0 +1,5 @@
+---
+title: Replace fa-file-text-o icons with GitLab SVG doc-text icon
+merge_request: 44706
+author:
+type: changed
diff --git a/changelogs/unreleased/225952-replace-fa-calendar-icons-with-gitlab-svg-calendar-icon.yml b/changelogs/unreleased/225952-replace-fa-calendar-icons-with-gitlab-svg-calendar-icon.yml
new file mode 100644
index 00000000000..969332b6881
--- /dev/null
+++ b/changelogs/unreleased/225952-replace-fa-calendar-icons-with-gitlab-svg-calendar-icon.yml
@@ -0,0 +1,5 @@
+---
+title: Replace fa-calendar icon with GitLab SVG
+merge_request: 45175
+author:
+type: changed
diff --git a/changelogs/unreleased/227668-boards_resolver_id_required.yml b/changelogs/unreleased/227668-boards_resolver_id_required.yml
new file mode 100644
index 00000000000..4253258055b
--- /dev/null
+++ b/changelogs/unreleased/227668-boards_resolver_id_required.yml
@@ -0,0 +1,5 @@
+---
+title: 'GraphQL: No longer allows to omit ID when querying for a single board.'
+merge_request: 43627
+author:
+type: fixed
diff --git a/changelogs/unreleased/227836-incidents-comments-timeline-view.yml b/changelogs/unreleased/227836-incidents-comments-timeline-view.yml
new file mode 100644
index 00000000000..d061466d39f
--- /dev/null
+++ b/changelogs/unreleased/227836-incidents-comments-timeline-view.yml
@@ -0,0 +1,5 @@
+---
+title: Add timeline toggle button for incidents comments
+merge_request: 43302
+author:
+type: added
diff --git a/changelogs/unreleased/228674-no-dependencies-on-deploy-ecs.yml b/changelogs/unreleased/228674-no-dependencies-on-deploy-ecs.yml
new file mode 100644
index 00000000000..6a308ae5de4
--- /dev/null
+++ b/changelogs/unreleased/228674-no-dependencies-on-deploy-ecs.yml
@@ -0,0 +1,5 @@
+---
+title: Add empty dependencies value to ECS Deploy job
+merge_request: 36862
+author:
+type: fixed
diff --git a/changelogs/unreleased/229023-migrate-sidebar-epic-tooltip.yml b/changelogs/unreleased/229023-migrate-sidebar-epic-tooltip.yml
new file mode 100644
index 00000000000..cf13a49aa84
--- /dev/null
+++ b/changelogs/unreleased/229023-migrate-sidebar-epic-tooltip.yml
@@ -0,0 +1,5 @@
+---
+title: Replace tooltip with GLTooltip in epic sidebar datepicker
+merge_request: 45392
+author:
+type: other
diff --git a/changelogs/unreleased/229038-delete-environment-tooltip.yml b/changelogs/unreleased/229038-delete-environment-tooltip.yml
new file mode 100644
index 00000000000..3fb050fd43b
--- /dev/null
+++ b/changelogs/unreleased/229038-delete-environment-tooltip.yml
@@ -0,0 +1,5 @@
+---
+title: Remove jquery tooltip API call from delete environment button
+merge_request: 44191
+author:
+type: other
diff --git a/changelogs/unreleased/229039-environment-stop-tooltip.yml b/changelogs/unreleased/229039-environment-stop-tooltip.yml
new file mode 100644
index 00000000000..24837315786
--- /dev/null
+++ b/changelogs/unreleased/229039-environment-stop-tooltip.yml
@@ -0,0 +1,5 @@
+---
+title: Remove jquery tooltip API call from stop environment button
+merge_request: 44199
+author:
+type: changed
diff --git a/changelogs/unreleased/229040-activity-bar-tooltip.yml b/changelogs/unreleased/229040-activity-bar-tooltip.yml
new file mode 100644
index 00000000000..22083ba622e
--- /dev/null
+++ b/changelogs/unreleased/229040-activity-bar-tooltip.yml
@@ -0,0 +1,5 @@
+---
+title: Remove jquery tooltip from IDE activity bar
+merge_request: 44526
+author:
+type: changed
diff --git a/changelogs/unreleased/229114-jira-connect-install-webhook-for-updates.yml b/changelogs/unreleased/229114-jira-connect-install-webhook-for-updates.yml
new file mode 100644
index 00000000000..d86468981bc
--- /dev/null
+++ b/changelogs/unreleased/229114-jira-connect-install-webhook-for-updates.yml
@@ -0,0 +1,5 @@
+---
+title: Fix Jira Connect App update webhooks
+merge_request: 45151
+author:
+type: fixed
diff --git a/changelogs/unreleased/229223-store-jira-server-type-post-migration.yml b/changelogs/unreleased/229223-store-jira-server-type-post-migration.yml
new file mode 100644
index 00000000000..dbf2a1dbfbc
--- /dev/null
+++ b/changelogs/unreleased/229223-store-jira-server-type-post-migration.yml
@@ -0,0 +1,5 @@
+---
+title: Background migration for setting Jira tracker data deployment type
+merge_request: 37002
+author:
+type: changed
diff --git a/changelogs/unreleased/229284-migrate-bootstrap-button-to-gitlab-ui-glbutton-in-app-assets-javas.yml b/changelogs/unreleased/229284-migrate-bootstrap-button-to-gitlab-ui-glbutton-in-app-assets-javas.yml
new file mode 100644
index 00000000000..0e05ddd0a8a
--- /dev/null
+++ b/changelogs/unreleased/229284-migrate-bootstrap-button-to-gitlab-ui-glbutton-in-app-assets-javas.yml
@@ -0,0 +1,5 @@
+---
+title: Update IDE compare changes view button to link style
+merge_request: 43403
+author:
+type: other
diff --git a/changelogs/unreleased/229303-migrate-bootstrap-button-to-gitlab-ui-glbutton-in-app-assets-javas.yml b/changelogs/unreleased/229303-migrate-bootstrap-button-to-gitlab-ui-glbutton-in-app-assets-javas.yml
new file mode 100644
index 00000000000..7f8fa21c28f
--- /dev/null
+++ b/changelogs/unreleased/229303-migrate-bootstrap-button-to-gitlab-ui-glbutton-in-app-assets-javas.yml
@@ -0,0 +1,6 @@
+---
+title: Migrating deprecated buttons to GlButtons for modals that have not yet been
+ migrated to the new GlModal component
+merge_request: 44611
+author:
+type: other
diff --git a/changelogs/unreleased/229327-migrate-bootstrap-button-to-gitlab-ui-glbutton-in-ee-app-assets-ja.yml b/changelogs/unreleased/229327-migrate-bootstrap-button-to-gitlab-ui-glbutton-in-ee-app-assets-ja.yml
new file mode 100644
index 00000000000..52666825ae1
--- /dev/null
+++ b/changelogs/unreleased/229327-migrate-bootstrap-button-to-gitlab-ui-glbutton-in-ee-app-assets-ja.yml
@@ -0,0 +1,5 @@
+---
+title: Replace button component
+merge_request: 42716
+author:
+type: changed
diff --git a/changelogs/unreleased/229330-update-discard-changes-button.yml b/changelogs/unreleased/229330-update-discard-changes-button.yml
new file mode 100644
index 00000000000..58e60d4a12c
--- /dev/null
+++ b/changelogs/unreleased/229330-update-discard-changes-button.yml
@@ -0,0 +1,5 @@
+---
+title: Updated Discard Changes button in WebIDE
+merge_request: 41899
+author:
+type: changed
diff --git a/changelogs/unreleased/229343-update-lock-form-buttons.yml b/changelogs/unreleased/229343-update-lock-form-buttons.yml
new file mode 100644
index 00000000000..d19c738b5c3
--- /dev/null
+++ b/changelogs/unreleased/229343-update-lock-form-buttons.yml
@@ -0,0 +1,5 @@
+---
+title: Update lock form buttons to gl-button
+merge_request: 41454
+author:
+type: changed
diff --git a/changelogs/unreleased/229344-update-confidential-form-buttons.yml b/changelogs/unreleased/229344-update-confidential-form-buttons.yml
new file mode 100644
index 00000000000..0b6f687530d
--- /dev/null
+++ b/changelogs/unreleased/229344-update-confidential-form-buttons.yml
@@ -0,0 +1,5 @@
+---
+title: Update confidential form buttons to gl-button
+merge_request: 40893
+author:
+type: changed
diff --git a/changelogs/unreleased/229404-filter-capabilities.yml b/changelogs/unreleased/229404-filter-capabilities.yml
new file mode 100644
index 00000000000..ae415d6446a
--- /dev/null
+++ b/changelogs/unreleased/229404-filter-capabilities.yml
@@ -0,0 +1,5 @@
+---
+title: Resolve Add filter capabilities to Incident list
+merge_request: 42377
+author:
+type: changed
diff --git a/changelogs/unreleased/229534-incident-sorting-backend.yml b/changelogs/unreleased/229534-incident-sorting-backend.yml
new file mode 100644
index 00000000000..0732f2868f9
--- /dev/null
+++ b/changelogs/unreleased/229534-incident-sorting-backend.yml
@@ -0,0 +1,5 @@
+---
+title: Add severity and published sorting for incident issues
+merge_request: 42800
+author:
+type: added
diff --git a/changelogs/unreleased/229534-incidents-sorting.yml b/changelogs/unreleased/229534-incidents-sorting.yml
new file mode 100644
index 00000000000..1a33227c3d0
--- /dev/null
+++ b/changelogs/unreleased/229534-incidents-sorting.yml
@@ -0,0 +1,5 @@
+---
+title: Sort incidents list by severity and published columns
+merge_request: 43121
+author:
+type: added
diff --git a/changelogs/unreleased/229672-update-badge-list-row-modal.yml b/changelogs/unreleased/229672-update-badge-list-row-modal.yml
new file mode 100644
index 00000000000..0479b426a6b
--- /dev/null
+++ b/changelogs/unreleased/229672-update-badge-list-row-modal.yml
@@ -0,0 +1,5 @@
+---
+title: Update delete badge modal to gl-modal
+merge_request: 44495
+author:
+type: changed
diff --git a/changelogs/unreleased/229727-drop-type-on-audit-events.yml b/changelogs/unreleased/229727-drop-type-on-audit-events.yml
new file mode 100644
index 00000000000..0abfc00444b
--- /dev/null
+++ b/changelogs/unreleased/229727-drop-type-on-audit-events.yml
@@ -0,0 +1,5 @@
+---
+title: Remove type column on audit_events table
+merge_request: 43703
+author:
+type: other
diff --git a/changelogs/unreleased/229834-destroy-board-list-graphql.yml b/changelogs/unreleased/229834-destroy-board-list-graphql.yml
new file mode 100644
index 00000000000..79f63b07eb7
--- /dev/null
+++ b/changelogs/unreleased/229834-destroy-board-list-graphql.yml
@@ -0,0 +1,5 @@
+---
+title: Destroy issue board list via GraphQL
+merge_request: 43081
+author:
+type: added
diff --git a/changelogs/unreleased/229838-create-issue-graphql.yml b/changelogs/unreleased/229838-create-issue-graphql.yml
new file mode 100644
index 00000000000..fb3e1976cc8
--- /dev/null
+++ b/changelogs/unreleased/229838-create-issue-graphql.yml
@@ -0,0 +1,5 @@
+---
+title: Add GraphQL mutation to create an issue
+merge_request: 43735
+author:
+type: added
diff --git a/changelogs/unreleased/229918-issue_data_designs.yml b/changelogs/unreleased/229918-issue_data_designs.yml
new file mode 100644
index 00000000000..3e89ae61ae3
--- /dev/null
+++ b/changelogs/unreleased/229918-issue_data_designs.yml
@@ -0,0 +1,5 @@
+---
+title: Added UsageData metrics for Issue designs' usage
+merge_request: 44373
+author:
+type: added
diff --git a/changelogs/unreleased/229918-issue_data_epics.yml b/changelogs/unreleased/229918-issue_data_epics.yml
new file mode 100644
index 00000000000..692edbf54d2
--- /dev/null
+++ b/changelogs/unreleased/229918-issue_data_epics.yml
@@ -0,0 +1,5 @@
+---
+title: Added UsageData metrics for issues added/removed from Epics
+merge_request: 44371
+author:
+type: added
diff --git a/changelogs/unreleased/229918-track-additional-issue-change-events.yml b/changelogs/unreleased/229918-track-additional-issue-change-events.yml
new file mode 100644
index 00000000000..0e34439be06
--- /dev/null
+++ b/changelogs/unreleased/229918-track-additional-issue-change-events.yml
@@ -0,0 +1,5 @@
+---
+title: Add more issue change events to usage ping
+merge_request: 43828
+author:
+type: other
diff --git a/changelogs/unreleased/229918-track-time-tracking-events.yml b/changelogs/unreleased/229918-track-time-tracking-events.yml
new file mode 100644
index 00000000000..e4bdf8b57fc
--- /dev/null
+++ b/changelogs/unreleased/229918-track-time-tracking-events.yml
@@ -0,0 +1,5 @@
+---
+title: Track issue time tracking events in usage ping
+merge_request: 44404
+author:
+type: other
diff --git a/changelogs/unreleased/230438-usage-data-optimize-usage_activity_by_stage-counters.yml b/changelogs/unreleased/230438-usage-data-optimize-usage_activity_by_stage-counters.yml
new file mode 100644
index 00000000000..c7a834d605f
--- /dev/null
+++ b/changelogs/unreleased/230438-usage-data-optimize-usage_activity_by_stage-counters.yml
@@ -0,0 +1,5 @@
+---
+title: Add index on ci_builds relation to improve Usage Ping metrics collection performance.
+merge_request: 37581
+author:
+type: added
diff --git a/changelogs/unreleased/230719-tabs-vue-migrate-app-assets-javascripts-environments-components-en.yml b/changelogs/unreleased/230719-tabs-vue-migrate-app-assets-javascripts-environments-components-en.yml
new file mode 100644
index 00000000000..8cdd77718f8
--- /dev/null
+++ b/changelogs/unreleased/230719-tabs-vue-migrate-app-assets-javascripts-environments-components-en.yml
@@ -0,0 +1,5 @@
+---
+title: Migrate custom Tabs to GlTabs
+merge_request: 42236
+author:
+type: changed
diff --git a/changelogs/unreleased/230720-tabs-vue-migrate-app-assets-javascripts-environments-folder-enviro.yml b/changelogs/unreleased/230720-tabs-vue-migrate-app-assets-javascripts-environments-folder-enviro.yml
new file mode 100644
index 00000000000..f27930f26e5
--- /dev/null
+++ b/changelogs/unreleased/230720-tabs-vue-migrate-app-assets-javascripts-environments-folder-enviro.yml
@@ -0,0 +1,5 @@
+---
+title: Migrate environments folder tabs to GlTabs
+merge_request: 42894
+author:
+type: changed
diff --git a/changelogs/unreleased/230725-update-boards-modal-tabs.yml b/changelogs/unreleased/230725-update-boards-modal-tabs.yml
new file mode 100644
index 00000000000..87e1e0b4f54
--- /dev/null
+++ b/changelogs/unreleased/230725-update-boards-modal-tabs.yml
@@ -0,0 +1,5 @@
+---
+title: Update issue boards modal to gl-tabs
+merge_request: 43740
+author:
+type: changed
diff --git a/changelogs/unreleased/230827-fix-epics-filter.yml b/changelogs/unreleased/230827-fix-epics-filter.yml
new file mode 100644
index 00000000000..898b5ce913e
--- /dev/null
+++ b/changelogs/unreleased/230827-fix-epics-filter.yml
@@ -0,0 +1,5 @@
+---
+title: Fix filtering epics when sorting by dates
+merge_request: 42827
+author:
+type: fixed
diff --git a/changelogs/unreleased/230841-update-alert-gfm-like-reference.yml b/changelogs/unreleased/230841-update-alert-gfm-like-reference.yml
new file mode 100644
index 00000000000..9f6a0e7b2dc
--- /dev/null
+++ b/changelogs/unreleased/230841-update-alert-gfm-like-reference.yml
@@ -0,0 +1,5 @@
+---
+title: Update alert GFM reference in highlight bar
+merge_request: 43104
+author:
+type: changed
diff --git a/changelogs/unreleased/231072-project-members-import-button.yml b/changelogs/unreleased/231072-project-members-import-button.yml
new file mode 100644
index 00000000000..26bdd048726
--- /dev/null
+++ b/changelogs/unreleased/231072-project-members-import-button.yml
@@ -0,0 +1,5 @@
+---
+title: Add gl-button class to import and cancel buttons for project member import page
+merge_request: 43620
+author: Gary Bell @garybell
+type: other
diff --git a/changelogs/unreleased/231180-ui-button-proj-hook_logs.yml b/changelogs/unreleased/231180-ui-button-proj-hook_logs.yml
new file mode 100644
index 00000000000..5e26bbc3f97
--- /dev/null
+++ b/changelogs/unreleased/231180-ui-button-proj-hook_logs.yml
@@ -0,0 +1,5 @@
+---
+title: Set hook_log css to gl-button
+merge_request: 42730
+author: Mike Terhar @mterhar
+type: other
diff --git a/changelogs/unreleased/231209-labels-buttons.yml b/changelogs/unreleased/231209-labels-buttons.yml
new file mode 100644
index 00000000000..51de12ff2e8
--- /dev/null
+++ b/changelogs/unreleased/231209-labels-buttons.yml
@@ -0,0 +1,5 @@
+---
+title: Apply GitLab UI styles to buttons in app/views/shared/labels directory
+merge_request: 43346
+author: Gary Bell @garybell
+type: other
diff --git a/changelogs/unreleased/231214-admin-deploy-key-buttons.yml b/changelogs/unreleased/231214-admin-deploy-key-buttons.yml
new file mode 100644
index 00000000000..c67666dd1c5
--- /dev/null
+++ b/changelogs/unreleased/231214-admin-deploy-key-buttons.yml
@@ -0,0 +1,5 @@
+---
+title: Update buttons to use GitLab button class gl-button
+merge_request: 44361
+author: Gary Bell @garybell
+type: other
diff --git a/changelogs/unreleased/231306-approve-activity-in-core.yml b/changelogs/unreleased/231306-approve-activity-in-core.yml
new file mode 100644
index 00000000000..41e921821b5
--- /dev/null
+++ b/changelogs/unreleased/231306-approve-activity-in-core.yml
@@ -0,0 +1,5 @@
+---
+title: Fix issues with optional merge requests approval in CE
+author: Pavel Kuznetsov
+merge_request: 42119
+type: fixed
diff --git a/changelogs/unreleased/231467-reduce-cached-query-jobscontroller-show.yml b/changelogs/unreleased/231467-reduce-cached-query-jobscontroller-show.yml
new file mode 100644
index 00000000000..8a6e84f3a0b
--- /dev/null
+++ b/changelogs/unreleased/231467-reduce-cached-query-jobscontroller-show.yml
@@ -0,0 +1,5 @@
+---
+title: Reduce cached SQL for JobsController#show
+merge_request: 43559
+author:
+type: performance
diff --git a/changelogs/unreleased/232503-editor-lite-extensions-on-instance.yml b/changelogs/unreleased/232503-editor-lite-extensions-on-instance.yml
new file mode 100644
index 00000000000..785e3b2fce3
--- /dev/null
+++ b/changelogs/unreleased/232503-editor-lite-extensions-on-instance.yml
@@ -0,0 +1,5 @@
+---
+title: Editor Lite to saupport extensions in instance constructor
+merge_request: 44723
+author:
+type: added
diff --git a/changelogs/unreleased/232503-editor-lite-to-snippet.yml b/changelogs/unreleased/232503-editor-lite-to-snippet.yml
new file mode 100644
index 00000000000..904640b369b
--- /dev/null
+++ b/changelogs/unreleased/232503-editor-lite-to-snippet.yml
@@ -0,0 +1,5 @@
+---
+title: Replaced blob-content-edit with editor-lite compoennt for Snippet edit form
+merge_request: 44994
+author:
+type: changed
diff --git a/changelogs/unreleased/232503-editor-lite-vue-component.yml b/changelogs/unreleased/232503-editor-lite-vue-component.yml
new file mode 100644
index 00000000000..ccccfe2b427
--- /dev/null
+++ b/changelogs/unreleased/232503-editor-lite-vue-component.yml
@@ -0,0 +1,5 @@
+---
+title: Added new editor-lite Vue component
+merge_request: 44577
+author:
+type: added
diff --git a/changelogs/unreleased/232670-webauthn-background-migration.yml b/changelogs/unreleased/232670-webauthn-background-migration.yml
new file mode 100644
index 00000000000..ad2ff74ad3a
--- /dev/null
+++ b/changelogs/unreleased/232670-webauthn-background-migration.yml
@@ -0,0 +1,5 @@
+---
+title: Migrate u2f registrations to webauthn registrations
+merge_request: 42159
+author: Jan Beckmann
+type: added
diff --git a/changelogs/unreleased/232798-alrt-graphql.yml b/changelogs/unreleased/232798-alrt-graphql.yml
new file mode 100644
index 00000000000..5af2732885f
--- /dev/null
+++ b/changelogs/unreleased/232798-alrt-graphql.yml
@@ -0,0 +1,5 @@
+---
+title: Make alerts searchable by assignee username in GraphQL API
+merge_request: 44911
+author:
+type: added
diff --git a/changelogs/unreleased/233016_fix_jira_dvcs_user_avatars.yml b/changelogs/unreleased/233016_fix_jira_dvcs_user_avatars.yml
new file mode 100644
index 00000000000..695de5d40b0
--- /dev/null
+++ b/changelogs/unreleased/233016_fix_jira_dvcs_user_avatars.yml
@@ -0,0 +1,5 @@
+---
+title: Fix broken user avatars in Jira Development Panel
+merge_request: 43563
+author:
+type: fixed
diff --git a/changelogs/unreleased/233430-design-repo-in-backup.yml b/changelogs/unreleased/233430-design-repo-in-backup.yml
new file mode 100644
index 00000000000..e8bbd3cfb94
--- /dev/null
+++ b/changelogs/unreleased/233430-design-repo-in-backup.yml
@@ -0,0 +1,5 @@
+---
+title: Include Design Management git repositories in GitLab Backup
+merge_request: 43947
+author:
+type: fixed
diff --git a/changelogs/unreleased/233433-create-board-graphql.yml b/changelogs/unreleased/233433-create-board-graphql.yml
new file mode 100644
index 00000000000..f8db2d62d6f
--- /dev/null
+++ b/changelogs/unreleased/233433-create-board-graphql.yml
@@ -0,0 +1,5 @@
+---
+title: Create an issue board via GraphQL mutation
+merge_request: 44298
+author:
+type: added
diff --git a/changelogs/unreleased/233626-fj-add-snippets-to-backups.yml b/changelogs/unreleased/233626-fj-add-snippets-to-backups.yml
new file mode 100644
index 00000000000..8fc61ab1c2c
--- /dev/null
+++ b/changelogs/unreleased/233626-fj-add-snippets-to-backups.yml
@@ -0,0 +1,5 @@
+---
+title: Add snippets to GitLab backups
+merge_request: 43694
+author:
+type: changed
diff --git a/changelogs/unreleased/233627-fj-restore-snippets-in-backups.yml b/changelogs/unreleased/233627-fj-restore-snippets-in-backups.yml
new file mode 100644
index 00000000000..0737cec3d89
--- /dev/null
+++ b/changelogs/unreleased/233627-fj-restore-snippets-in-backups.yml
@@ -0,0 +1,5 @@
+---
+title: Restore snippet repositories from backups
+merge_request: 43696
+author:
+type: changed
diff --git a/changelogs/unreleased/233647-replace-bootstrap-alerts-to-gitlab-ui.yml b/changelogs/unreleased/233647-replace-bootstrap-alerts-to-gitlab-ui.yml
new file mode 100644
index 00000000000..c8316653765
--- /dev/null
+++ b/changelogs/unreleased/233647-replace-bootstrap-alerts-to-gitlab-ui.yml
@@ -0,0 +1,5 @@
+---
+title: Replace bootstrap alerts in app/views/admin/broadcast_messages/_form.html.haml
+merge_request: 41271
+author: Gilang Gumilar
+type: changed
diff --git a/changelogs/unreleased/233660-remove-bootstrap-alert-gcp.yml b/changelogs/unreleased/233660-remove-bootstrap-alert-gcp.yml
new file mode 100644
index 00000000000..a0cf820cb4e
--- /dev/null
+++ b/changelogs/unreleased/233660-remove-bootstrap-alert-gcp.yml
@@ -0,0 +1,5 @@
+---
+title: Remove bootrap alert from gcp offer
+merge_request: 41814
+author:
+type: other
diff --git a/changelogs/unreleased/233664-bootstrap-alert-auto-devops.yml b/changelogs/unreleased/233664-bootstrap-alert-auto-devops.yml
new file mode 100644
index 00000000000..c32ac9522a2
--- /dev/null
+++ b/changelogs/unreleased/233664-bootstrap-alert-auto-devops.yml
@@ -0,0 +1,5 @@
+---
+title: Migrate auto devops message from bootstrap
+merge_request: 45221
+author:
+type: other
diff --git a/changelogs/unreleased/233674-remove-bootstrap-usage-invalid.yml b/changelogs/unreleased/233674-remove-bootstrap-usage-invalid.yml
new file mode 100644
index 00000000000..ec86067a9b1
--- /dev/null
+++ b/changelogs/unreleased/233674-remove-bootstrap-usage-invalid.yml
@@ -0,0 +1,5 @@
+---
+title: Remove bootstrap usage from merge_requests/invalid
+merge_request: 43439
+author:
+type: changed
diff --git a/changelogs/unreleased/233680-replace-bootstrap-alerts-in-app-views-profiles-accounts-show-html-.yml b/changelogs/unreleased/233680-replace-bootstrap-alerts-in-app-views-profiles-accounts-show-html-.yml
new file mode 100644
index 00000000000..b5ff847e4e9
--- /dev/null
+++ b/changelogs/unreleased/233680-replace-bootstrap-alerts-in-app-views-profiles-accounts-show-html-.yml
@@ -0,0 +1,5 @@
+---
+title: Replace bootstrap alerts in app/views/profiles/accounts/show.html.haml
+merge_request: 41299
+author: Gilang Gumilar
+type: changed
diff --git a/changelogs/unreleased/233681-replace-bootstrap-alerts-in-app-views-projects-milestones-show-htm.yml b/changelogs/unreleased/233681-replace-bootstrap-alerts-in-app-views-projects-milestones-show-htm.yml
new file mode 100644
index 00000000000..7fd61417d26
--- /dev/null
+++ b/changelogs/unreleased/233681-replace-bootstrap-alerts-in-app-views-projects-milestones-show-htm.yml
@@ -0,0 +1,5 @@
+---
+title: Replace bootstrap alerts in app/views/projects/milestones/show.html.haml
+merge_request: 41396
+author: Gilang Gumilar
+type: changed
diff --git a/changelogs/unreleased/233686-replace-bootstrap-alerts-in-app-views-admin-projects-show-html-ham.yml b/changelogs/unreleased/233686-replace-bootstrap-alerts-in-app-views-admin-projects-show-html-ham.yml
new file mode 100644
index 00000000000..6ded0ab3b3d
--- /dev/null
+++ b/changelogs/unreleased/233686-replace-bootstrap-alerts-in-app-views-admin-projects-show-html-ham.yml
@@ -0,0 +1,5 @@
+---
+title: Replace bootstrap alerts in app/views/admin/projects/show.html.haml
+merge_request: 41389
+author: Gilang Gumilar
+type: changed
diff --git a/changelogs/unreleased/233693-remove-bootstrap-pages.yml b/changelogs/unreleased/233693-remove-bootstrap-pages.yml
new file mode 100644
index 00000000000..dce56a28d86
--- /dev/null
+++ b/changelogs/unreleased/233693-remove-bootstrap-pages.yml
@@ -0,0 +1,5 @@
+---
+title: Remove bootstrap from pages/form
+merge_request: 43442
+author:
+type: other
diff --git a/changelogs/unreleased/233694-replace-bootstrap-alerts-in-app-views-projects-diffs-_warning-html.yml b/changelogs/unreleased/233694-replace-bootstrap-alerts-in-app-views-projects-diffs-_warning-html.yml
new file mode 100644
index 00000000000..ec4537484fe
--- /dev/null
+++ b/changelogs/unreleased/233694-replace-bootstrap-alerts-in-app-views-projects-diffs-_warning-html.yml
@@ -0,0 +1,5 @@
+---
+title: Replace bootstrap alerts in app/views/projects/diffs/_warning.html.haml
+merge_request: 41295
+author: Gilang Gumilar
+type: changed
diff --git a/changelogs/unreleased/233703-replace-bootstrap-alerts-in-app-views-import-shared-_errors-html-h.yml b/changelogs/unreleased/233703-replace-bootstrap-alerts-in-app-views-import-shared-_errors-html-h.yml
new file mode 100644
index 00000000000..37ce9481f51
--- /dev/null
+++ b/changelogs/unreleased/233703-replace-bootstrap-alerts-in-app-views-import-shared-_errors-html-h.yml
@@ -0,0 +1,5 @@
+---
+title: Replace bootstrap alerts in app/views/import/shared/_errors.html.haml
+merge_request: 41288
+author: Gilang Gumilar
+type: changed
diff --git a/changelogs/unreleased/233719-project-creating-incidents-usage-ping.yml b/changelogs/unreleased/233719-project-creating-incidents-usage-ping.yml
new file mode 100644
index 00000000000..d6e5dadb688
--- /dev/null
+++ b/changelogs/unreleased/233719-project-creating-incidents-usage-ping.yml
@@ -0,0 +1,5 @@
+---
+title: Add projects_creating_incidents to usage ping counts
+merge_request: 42934
+author:
+type: added
diff --git a/changelogs/unreleased/233722-snowplow-incidents-list-details-views.yml b/changelogs/unreleased/233722-snowplow-incidents-list-details-views.yml
new file mode 100644
index 00000000000..24bab5312cc
--- /dev/null
+++ b/changelogs/unreleased/233722-snowplow-incidents-list-details-views.yml
@@ -0,0 +1,5 @@
+---
+title: Snowplow tracking of Incident details views
+merge_request: 45011
+author:
+type: added
diff --git a/changelogs/unreleased/233785-track-audit-event-searches.yml b/changelogs/unreleased/233785-track-audit-event-searches.yml
new file mode 100644
index 00000000000..b6464a6d6e2
--- /dev/null
+++ b/changelogs/unreleased/233785-track-audit-event-searches.yml
@@ -0,0 +1,5 @@
+---
+title: Track audit event searches via Snowplow
+merge_request: 44888
+author:
+type: other
diff --git a/changelogs/unreleased/233940-product-analytics-for-group-level-integrations.yml b/changelogs/unreleased/233940-product-analytics-for-group-level-integrations.yml
new file mode 100644
index 00000000000..4dfcc8e37e6
--- /dev/null
+++ b/changelogs/unreleased/233940-product-analytics-for-group-level-integrations.yml
@@ -0,0 +1,5 @@
+---
+title: Add product analytics for group-level integrations
+merge_request: 44726
+author:
+type: other
diff --git a/changelogs/unreleased/233994_sse_usage_ping.yml b/changelogs/unreleased/233994_sse_usage_ping.yml
new file mode 100644
index 00000000000..767f1f0fe2e
--- /dev/null
+++ b/changelogs/unreleased/233994_sse_usage_ping.yml
@@ -0,0 +1,5 @@
+---
+title: Add usage ping to count Static Site Editor views
+merge_request: 44573
+author:
+type: added
diff --git a/changelogs/unreleased/235108-migrate-terraform-states-to-versioniong.yml b/changelogs/unreleased/235108-migrate-terraform-states-to-versioniong.yml
new file mode 100644
index 00000000000..90f89077c0c
--- /dev/null
+++ b/changelogs/unreleased/235108-migrate-terraform-states-to-versioniong.yml
@@ -0,0 +1,5 @@
+---
+title: Seed initial version for non-versioned terraform states
+merge_request: 43665
+author:
+type: added
diff --git a/changelogs/unreleased/235676-prioritize-exact-matches.yml b/changelogs/unreleased/235676-prioritize-exact-matches.yml
new file mode 100644
index 00000000000..88ee99fd839
--- /dev/null
+++ b/changelogs/unreleased/235676-prioritize-exact-matches.yml
@@ -0,0 +1,5 @@
+---
+title: Add sort by similarity to getProjects GraphQL call
+merge_request: 43136
+author:
+type: changed
diff --git a/changelogs/unreleased/235765-enable-project-access-tokens-gitlab-com.yml b/changelogs/unreleased/235765-enable-project-access-tokens-gitlab-com.yml
new file mode 100644
index 00000000000..e56a865721f
--- /dev/null
+++ b/changelogs/unreleased/235765-enable-project-access-tokens-gitlab-com.yml
@@ -0,0 +1,5 @@
+---
+title: Enable project access tokens on GitLab.com
+merge_request: 43190
+author:
+type: changed
diff --git a/changelogs/unreleased/235822-group-package-permissions.yml b/changelogs/unreleased/235822-group-package-permissions.yml
new file mode 100644
index 00000000000..4faa4c40747
--- /dev/null
+++ b/changelogs/unreleased/235822-group-package-permissions.yml
@@ -0,0 +1,5 @@
+---
+title: Fix group deploy tokens permissions for package access
+merge_request: 43007
+author:
+type: fixed
diff --git a/changelogs/unreleased/235822-maven-group-token.yml b/changelogs/unreleased/235822-maven-group-token.yml
new file mode 100644
index 00000000000..4ad0bbc8fa2
--- /dev/null
+++ b/changelogs/unreleased/235822-maven-group-token.yml
@@ -0,0 +1,6 @@
+---
+title: Fix group deploy tokens to return all projects and work with the Maven group
+ endpoint
+merge_request: 43628
+author:
+type: fixed
diff --git a/changelogs/unreleased/235857-sentryerrortype-project_id-returns-a-project-global-id.yml b/changelogs/unreleased/235857-sentryerrortype-project_id-returns-a-project-global-id.yml
new file mode 100644
index 00000000000..574d83e8a85
--- /dev/null
+++ b/changelogs/unreleased/235857-sentryerrortype-project_id-returns-a-project-global-id.yml
@@ -0,0 +1,5 @@
+---
+title: Fix type of SentryErrorType global ID
+merge_request: 42185
+author:
+type: fixed
diff --git a/changelogs/unreleased/235888-gitlab-for-jira-app-should-display-who-is-logged-in.yml b/changelogs/unreleased/235888-gitlab-for-jira-app-should-display-who-is-logged-in.yml
new file mode 100644
index 00000000000..bdcd4905d71
--- /dev/null
+++ b/changelogs/unreleased/235888-gitlab-for-jira-app-should-display-who-is-logged-in.yml
@@ -0,0 +1,5 @@
+---
+title: Add user sign in indicator to Jira connect app
+merge_request: 42628
+author:
+type: changed
diff --git a/changelogs/unreleased/235945-replace-the-delete-ssh-confirmation-dialog-with-a-pajamas-modal.yml b/changelogs/unreleased/235945-replace-the-delete-ssh-confirmation-dialog-with-a-pajamas-modal.yml
new file mode 100644
index 00000000000..2fddc52c957
--- /dev/null
+++ b/changelogs/unreleased/235945-replace-the-delete-ssh-confirmation-dialog-with-a-pajamas-modal.yml
@@ -0,0 +1,5 @@
+---
+title: Updated the admin and user SSH key delete confirmation to use GlModal
+merge_request: 42824
+author:
+type: changed
diff --git a/changelogs/unreleased/237923-error-when-quickly-reordering-designs.yml b/changelogs/unreleased/237923-error-when-quickly-reordering-designs.yml
new file mode 100644
index 00000000000..63ffd426228
--- /dev/null
+++ b/changelogs/unreleased/237923-error-when-quickly-reordering-designs.yml
@@ -0,0 +1,5 @@
+---
+title: Resolve Error when quickly reordering designs
+merge_request: 42818
+author:
+type: fixed
diff --git a/changelogs/unreleased/238570-hide-instance-level-integrations-on-gitlab-com.yml b/changelogs/unreleased/238570-hide-instance-level-integrations-on-gitlab-com.yml
new file mode 100644
index 00000000000..3a68c265a86
--- /dev/null
+++ b/changelogs/unreleased/238570-hide-instance-level-integrations-on-gitlab-com.yml
@@ -0,0 +1,5 @@
+---
+title: Hide instance-level integrations on GitLab.com
+merge_request: 42808
+author:
+type: changed
diff --git a/changelogs/unreleased/238605-optimise-lfs-cleanup.yml b/changelogs/unreleased/238605-optimise-lfs-cleanup.yml
new file mode 100644
index 00000000000..e1533b8fba2
--- /dev/null
+++ b/changelogs/unreleased/238605-optimise-lfs-cleanup.yml
@@ -0,0 +1,5 @@
+---
+title: Optimise cleaning up LFS objects
+merge_request: 42830
+author:
+type: performance
diff --git a/changelogs/unreleased/238605-remove-cleanup-lfs-during-gc-feature-flag.yml b/changelogs/unreleased/238605-remove-cleanup-lfs-during-gc-feature-flag.yml
new file mode 100644
index 00000000000..107417c01e3
--- /dev/null
+++ b/changelogs/unreleased/238605-remove-cleanup-lfs-during-gc-feature-flag.yml
@@ -0,0 +1,5 @@
+---
+title: Clean up unused LFS objects during repository housekeeping
+merge_request: 40979
+author:
+type: added
diff --git a/changelogs/unreleased/238628-design-specs-for-confirmation-modal.yml b/changelogs/unreleased/238628-design-specs-for-confirmation-modal.yml
new file mode 100644
index 00000000000..03eb155e53c
--- /dev/null
+++ b/changelogs/unreleased/238628-design-specs-for-confirmation-modal.yml
@@ -0,0 +1,5 @@
+---
+title: Add confirmation modal on instance-level integration form
+merge_request: 42840
+author:
+type: changed
diff --git a/changelogs/unreleased/238931-improve-responsive-state-of-board-filtering-bar-when-group-by-drop.yml b/changelogs/unreleased/238931-improve-responsive-state-of-board-filtering-bar-when-group-by-drop.yml
new file mode 100644
index 00000000000..b5736d84fdf
--- /dev/null
+++ b/changelogs/unreleased/238931-improve-responsive-state-of-board-filtering-bar-when-group-by-drop.yml
@@ -0,0 +1,5 @@
+---
+title: Fix mobile view of filtering bar
+merge_request: 45226
+author:
+type: fixed
diff --git a/changelogs/unreleased/239090-fix-throughput-chart.yml b/changelogs/unreleased/239090-fix-throughput-chart.yml
new file mode 100644
index 00000000000..cf3259ebacb
--- /dev/null
+++ b/changelogs/unreleased/239090-fix-throughput-chart.yml
@@ -0,0 +1,6 @@
+---
+title: Optionally use merge request metrics association for merge request diff stats
+ in GraphQL
+merge_request: 44613
+author:
+type: performance
diff --git a/changelogs/unreleased/239130-conan-recipe-display-be.yml b/changelogs/unreleased/239130-conan-recipe-display-be.yml
new file mode 100644
index 00000000000..81077644bd8
--- /dev/null
+++ b/changelogs/unreleased/239130-conan-recipe-display-be.yml
@@ -0,0 +1,5 @@
+---
+title: Use Conan recipe as package name in package API
+merge_request: 42860
+author:
+type: changed
diff --git a/changelogs/unreleased/239130-package-presenter-conan.yml b/changelogs/unreleased/239130-package-presenter-conan.yml
new file mode 100644
index 00000000000..8f8ad152966
--- /dev/null
+++ b/changelogs/unreleased/239130-package-presenter-conan.yml
@@ -0,0 +1,5 @@
+---
+title: Display conan recipe as package name on package detail page
+merge_request: 44294
+author:
+type: changed
diff --git a/changelogs/unreleased/239327-fj-fix-snippet-update-edge-case.yml b/changelogs/unreleased/239327-fj-fix-snippet-update-edge-case.yml
new file mode 100644
index 00000000000..ed4721cd1a6
--- /dev/null
+++ b/changelogs/unreleased/239327-fj-fix-snippet-update-edge-case.yml
@@ -0,0 +1,5 @@
+---
+title: Fix edge case when updating snippet with no repo
+merge_request: 42964
+author:
+type: fixed
diff --git a/changelogs/unreleased/239852-move-merge-conflicts-to-page-bundle.yml b/changelogs/unreleased/239852-move-merge-conflicts-to-page-bundle.yml
new file mode 100644
index 00000000000..33b46be5035
--- /dev/null
+++ b/changelogs/unreleased/239852-move-merge-conflicts-to-page-bundle.yml
@@ -0,0 +1,5 @@
+---
+title: Add darkmode support for merge conflict page
+merge_request: 44168
+author:
+type: other
diff --git a/changelogs/unreleased/239861-pipeline-light-text-normal.yml b/changelogs/unreleased/239861-pipeline-light-text-normal.yml
new file mode 100644
index 00000000000..a569e4bb85a
--- /dev/null
+++ b/changelogs/unreleased/239861-pipeline-light-text-normal.yml
@@ -0,0 +1,5 @@
+---
+title: Remove CSS that ligthens texts in the pipeline
+merge_request: 45253
+author:
+type: changed
diff --git a/changelogs/unreleased/241165-sse-config-image-upload-path.yml b/changelogs/unreleased/241165-sse-config-image-upload-path.yml
new file mode 100644
index 00000000000..a42520031b3
--- /dev/null
+++ b/changelogs/unreleased/241165-sse-config-image-upload-path.yml
@@ -0,0 +1,5 @@
+---
+title: Introduce 'image_upload_path' entry support for '.gitlab/static-site-editor.yml' config file.
+merge_request: 43481
+author:
+type: added
diff --git a/changelogs/unreleased/241166-sse-config-mounts.yml b/changelogs/unreleased/241166-sse-config-mounts.yml
new file mode 100644
index 00000000000..272cfec3ae0
--- /dev/null
+++ b/changelogs/unreleased/241166-sse-config-mounts.yml
@@ -0,0 +1,5 @@
+---
+title: Introduce 'mounts' entry support for '.gitlab/static-site-editor.yml' config file.
+merge_request: 43485
+author:
+type: added
diff --git a/changelogs/unreleased/241663-incident-sla-cron-job.yml b/changelogs/unreleased/241663-incident-sla-cron-job.yml
new file mode 100644
index 00000000000..1c94d76a104
--- /dev/null
+++ b/changelogs/unreleased/241663-incident-sla-cron-job.yml
@@ -0,0 +1,5 @@
+---
+title: Schedule adding "Missed SLA" label to issues
+merge_request: 44546
+author:
+type: added
diff --git a/changelogs/unreleased/241663-incident-sla-logic.yml b/changelogs/unreleased/241663-incident-sla-logic.yml
new file mode 100644
index 00000000000..5b06e8e751f
--- /dev/null
+++ b/changelogs/unreleased/241663-incident-sla-logic.yml
@@ -0,0 +1,5 @@
+---
+title: Add Issuable Service Level Agreement (SLA) table
+merge_request: 44253
+author:
+type: added
diff --git a/changelogs/unreleased/241678-python-name-normalization.yml b/changelogs/unreleased/241678-python-name-normalization.yml
new file mode 100644
index 00000000000..b6d405a5dc9
--- /dev/null
+++ b/changelogs/unreleased/241678-python-name-normalization.yml
@@ -0,0 +1,6 @@
+---
+title: Search for python packages with normalized name to allow installs of packages
+ with periods and underscores
+merge_request: 44807
+author:
+type: changed
diff --git a/changelogs/unreleased/241831-null-bytes.yml b/changelogs/unreleased/241831-null-bytes.yml
new file mode 100644
index 00000000000..6371d4dd7c7
--- /dev/null
+++ b/changelogs/unreleased/241831-null-bytes.yml
@@ -0,0 +1,5 @@
+---
+title: Disallow NULL Bytes (U+0000) in requests
+merge_request: 45223
+author:
+type: added
diff --git a/changelogs/unreleased/241990-default-show_inherited_labels-feature-flag-to-true.yml b/changelogs/unreleased/241990-default-show_inherited_labels-feature-flag-to-true.yml
new file mode 100644
index 00000000000..ad1775cf2cd
--- /dev/null
+++ b/changelogs/unreleased/241990-default-show_inherited_labels-feature-flag-to-true.yml
@@ -0,0 +1,5 @@
+---
+title: Show all inherited labels in projects and subgroups
+merge_request: 45161
+author:
+type: added
diff --git a/changelogs/unreleased/241990-show-all-inherited-labels-in-subgroups.yml b/changelogs/unreleased/241990-show-all-inherited-labels-in-subgroups.yml
new file mode 100644
index 00000000000..079a9b2a458
--- /dev/null
+++ b/changelogs/unreleased/241990-show-all-inherited-labels-in-subgroups.yml
@@ -0,0 +1,5 @@
+---
+title: Show origin path of labels on subgroup labels page
+merge_request: 45040
+author:
+type: added
diff --git a/changelogs/unreleased/241990-show-full-path-where-labels-come-from.yml b/changelogs/unreleased/241990-show-full-path-where-labels-come-from.yml
new file mode 100644
index 00000000000..3a2ac5a0465
--- /dev/null
+++ b/changelogs/unreleased/241990-show-full-path-where-labels-come-from.yml
@@ -0,0 +1,5 @@
+---
+title: Show labels origin path on project labels page
+merge_request: 43858
+author:
+type: added
diff --git a/changelogs/unreleased/242016-fj-add-instance-gitpod-enabled-to-usage-data.yml b/changelogs/unreleased/242016-fj-add-instance-gitpod-enabled-to-usage-data.yml
new file mode 100644
index 00000000000..7c109a090e5
--- /dev/null
+++ b/changelogs/unreleased/242016-fj-add-instance-gitpod-enabled-to-usage-data.yml
@@ -0,0 +1,5 @@
+---
+title: Add Gitpod enabled instance setting to Usage Data
+merge_request: 42563
+author:
+type: changed
diff --git a/changelogs/unreleased/242016-fj-add-user-preferences-gitpod-enabled-to-usage-data.yml b/changelogs/unreleased/242016-fj-add-user-preferences-gitpod-enabled-to-usage-data.yml
new file mode 100644
index 00000000000..780c98d46f6
--- /dev/null
+++ b/changelogs/unreleased/242016-fj-add-user-preferences-gitpod-enabled-to-usage-data.yml
@@ -0,0 +1,5 @@
+---
+title: Add Gitpod enabled user setting to Usage Data
+merge_request: 42570
+author:
+type: changed
diff --git a/changelogs/unreleased/242285-approve-graphql-ce.yml b/changelogs/unreleased/242285-approve-graphql-ce.yml
new file mode 100644
index 00000000000..12415795839
--- /dev/null
+++ b/changelogs/unreleased/242285-approve-graphql-ce.yml
@@ -0,0 +1,5 @@
+---
+title: Allow get approvals on merge request by GraphQL in CE
+author: Pavel Kuznetsov
+merge_request: 43325
+type: add
diff --git a/changelogs/unreleased/243563-move-approval-code-to-ce.yml b/changelogs/unreleased/243563-move-approval-code-to-ce.yml
new file mode 100644
index 00000000000..1e96465e3c2
--- /dev/null
+++ b/changelogs/unreleased/243563-move-approval-code-to-ce.yml
@@ -0,0 +1,5 @@
+---
+title: Move approval MR filter and quick actions to CE
+author: Pavel Kuznetsov
+merge_request: 43326
+type: changed
diff --git a/changelogs/unreleased/243750-display-messages-and-warning-for-partially-executed-cleanup-polici.yml b/changelogs/unreleased/243750-display-messages-and-warning-for-partially-executed-cleanup-polici.yml
new file mode 100644
index 00000000000..e3f090109cf
--- /dev/null
+++ b/changelogs/unreleased/243750-display-messages-and-warning-for-partially-executed-cleanup-polici.yml
@@ -0,0 +1,5 @@
+---
+title: Display alert for partially executed cleanup policies
+merge_request: 43831
+author:
+type: changed
diff --git a/changelogs/unreleased/243776-reorder-nav-item.yml b/changelogs/unreleased/243776-reorder-nav-item.yml
new file mode 100644
index 00000000000..ca08daa800b
--- /dev/null
+++ b/changelogs/unreleased/243776-reorder-nav-item.yml
@@ -0,0 +1,5 @@
+---
+title: Update sidebar operations order
+merge_request: 42493
+author:
+type: changed
diff --git a/changelogs/unreleased/244050-feature-flag-to-allow-old-projects-to-have-a-cleanup-policy.yml b/changelogs/unreleased/244050-feature-flag-to-allow-old-projects-to-have-a-cleanup-policy.yml
new file mode 100644
index 00000000000..1a66f602e54
--- /dev/null
+++ b/changelogs/unreleased/244050-feature-flag-to-allow-old-projects-to-have-a-cleanup-policy.yml
@@ -0,0 +1,5 @@
+---
+title: Add feature flag for a phased rollout of cleanup policies
+merge_request: 44444
+author:
+type: added
diff --git a/changelogs/unreleased/244355-add-javascript-example-on-how-we-could-track-ui-events-using-usage.yml b/changelogs/unreleased/244355-add-javascript-example-on-how-we-could-track-ui-events-using-usage.yml
new file mode 100644
index 00000000000..8320e4159ae
--- /dev/null
+++ b/changelogs/unreleased/244355-add-javascript-example-on-how-we-could-track-ui-events-using-usage.yml
@@ -0,0 +1,5 @@
+---
+title: JS client for increment_unique_users API
+merge_request: 43084
+author:
+type: added
diff --git a/changelogs/unreleased/244427-bold-search-term-issues.yml b/changelogs/unreleased/244427-bold-search-term-issues.yml
new file mode 100644
index 00000000000..5e960541990
--- /dev/null
+++ b/changelogs/unreleased/244427-bold-search-term-issues.yml
@@ -0,0 +1,5 @@
+---
+title: Global Search - Bold Issue's Search Term
+merge_request: 43124
+author:
+type: changed
diff --git a/changelogs/unreleased/244484-remove-redundant-cluster-agents-index.yml b/changelogs/unreleased/244484-remove-redundant-cluster-agents-index.yml
new file mode 100644
index 00000000000..5286361142c
--- /dev/null
+++ b/changelogs/unreleased/244484-remove-redundant-cluster-agents-index.yml
@@ -0,0 +1,5 @@
+---
+title: Remove duplicate index on cluster_agents
+merge_request: 42902
+author:
+type: other
diff --git a/changelogs/unreleased/244828-drop-iglu-registry-url-column.yml b/changelogs/unreleased/244828-drop-iglu-registry-url-column.yml
new file mode 100644
index 00000000000..ee87d496276
--- /dev/null
+++ b/changelogs/unreleased/244828-drop-iglu-registry-url-column.yml
@@ -0,0 +1,5 @@
+---
+title: Drop Iglu registry URL column
+merge_request: 42939
+author:
+type: removed
diff --git a/changelogs/unreleased/244873-perceived-ux-success-screen.yml b/changelogs/unreleased/244873-perceived-ux-success-screen.yml
new file mode 100644
index 00000000000..13722416404
--- /dev/null
+++ b/changelogs/unreleased/244873-perceived-ux-success-screen.yml
@@ -0,0 +1,5 @@
+---
+title: Update user feedback to a dedicated page as opposed to solely a button with a loader
+merge_request: 43189
+author:
+type: changed
diff --git a/changelogs/unreleased/245304-reference-pages_deployments-in-pages_metadata.yml b/changelogs/unreleased/245304-reference-pages_deployments-in-pages_metadata.yml
new file mode 100644
index 00000000000..948e9e9bd5b
--- /dev/null
+++ b/changelogs/unreleased/245304-reference-pages_deployments-in-pages_metadata.yml
@@ -0,0 +1,5 @@
+---
+title: Reference pages_deployments in pages_metadata
+merge_request: 42834
+author:
+type: added
diff --git a/changelogs/unreleased/245325-refactor-the-invites-controller-member-method.yml b/changelogs/unreleased/245325-refactor-the-invites-controller-member-method.yml
new file mode 100644
index 00000000000..2998a787691
--- /dev/null
+++ b/changelogs/unreleased/245325-refactor-the-invites-controller-member-method.yml
@@ -0,0 +1,5 @@
+---
+title: Refactor the invites controller member method
+merge_request: 42727
+author:
+type: other
diff --git a/changelogs/unreleased/245331-alert-integrations-list.yml b/changelogs/unreleased/245331-alert-integrations-list.yml
new file mode 100644
index 00000000000..f46aceb94ca
--- /dev/null
+++ b/changelogs/unreleased/245331-alert-integrations-list.yml
@@ -0,0 +1,5 @@
+---
+title: Add the Alerts integrations table to Alert integrations settings in the Operations section
+merge_request: 44181
+author:
+type: added
diff --git a/changelogs/unreleased/245337-integrations-list-icons.yml b/changelogs/unreleased/245337-integrations-list-icons.yml
new file mode 100644
index 00000000000..72ef2d7514c
--- /dev/null
+++ b/changelogs/unreleased/245337-integrations-list-icons.yml
@@ -0,0 +1,5 @@
+---
+title: Status icons for alerts integratiosn list
+merge_request: 44318
+author:
+type: added
diff --git a/changelogs/unreleased/246619-add-package-events.yml b/changelogs/unreleased/246619-add-package-events.yml
new file mode 100644
index 00000000000..26465bc4aaa
--- /dev/null
+++ b/changelogs/unreleased/246619-add-package-events.yml
@@ -0,0 +1,5 @@
+---
+title: Adds package event tracking
+merge_request: 41846
+author:
+type: added
diff --git a/changelogs/unreleased/246739-use-gitlab-svg-icons-in-file_type_icon_class-helper.yml b/changelogs/unreleased/246739-use-gitlab-svg-icons-in-file_type_icon_class-helper.yml
new file mode 100644
index 00000000000..0c007f8a864
--- /dev/null
+++ b/changelogs/unreleased/246739-use-gitlab-svg-icons-in-file_type_icon_class-helper.yml
@@ -0,0 +1,5 @@
+---
+title: Use GitLab SVG icons in file_type_icon_class helper
+merge_request: 44580
+author:
+type: changed
diff --git a/changelogs/unreleased/246783-setting-button-position.yml b/changelogs/unreleased/246783-setting-button-position.yml
new file mode 100644
index 00000000000..2f703479857
--- /dev/null
+++ b/changelogs/unreleased/246783-setting-button-position.yml
@@ -0,0 +1,5 @@
+---
+title: Revert justified-content-end settings buttons
+merge_request: 42273
+author:
+type: changed
diff --git a/changelogs/unreleased/246793-mr-coverage-only-latest-build.yml b/changelogs/unreleased/246793-mr-coverage-only-latest-build.yml
new file mode 100644
index 00000000000..5bd6ef4739a
--- /dev/null
+++ b/changelogs/unreleased/246793-mr-coverage-only-latest-build.yml
@@ -0,0 +1,5 @@
+---
+title: Do not show retried builds in the MR code coverage
+merge_request: 42402
+author: Simon Lenz @koala7
+type: fixed
diff --git a/changelogs/unreleased/246847-store-pipeline-counts-by-status.yml b/changelogs/unreleased/246847-store-pipeline-counts-by-status.yml
new file mode 100644
index 00000000000..8cd1de665dd
--- /dev/null
+++ b/changelogs/unreleased/246847-store-pipeline-counts-by-status.yml
@@ -0,0 +1,5 @@
+---
+title: Store pipeline counts by status for instance statistics
+merge_request: 43027
+author:
+type: changed
diff --git a/changelogs/unreleased/247449_auto-purchased-storage-allocation.yml b/changelogs/unreleased/247449_auto-purchased-storage-allocation.yml
new file mode 100644
index 00000000000..5c87ea2fb22
--- /dev/null
+++ b/changelogs/unreleased/247449_auto-purchased-storage-allocation.yml
@@ -0,0 +1,5 @@
+---
+title: Enable automatic allocation of purchased storage
+merge_request: 44376
+author:
+type: changed
diff --git a/changelogs/unreleased/247476-standardise-usage-of-angle-brackets.yml b/changelogs/unreleased/247476-standardise-usage-of-angle-brackets.yml
new file mode 100644
index 00000000000..eec8ad098a1
--- /dev/null
+++ b/changelogs/unreleased/247476-standardise-usage-of-angle-brackets.yml
@@ -0,0 +1,5 @@
+---
+title: Remove angle brackets from empty name in U2F device settings
+merge_request: 42440
+author:
+type: changed
diff --git a/changelogs/unreleased/247489-update-create-column-from-to-also-copy-constraints-take-2.yml b/changelogs/unreleased/247489-update-create-column-from-to-also-copy-constraints-take-2.yml
new file mode 100644
index 00000000000..d1e0bccd923
--- /dev/null
+++ b/changelogs/unreleased/247489-update-create-column-from-to-also-copy-constraints-take-2.yml
@@ -0,0 +1,5 @@
+---
+title: Add migration helpers for copying check constraints
+merge_request: 44777
+author:
+type: other
diff --git a/changelogs/unreleased/247496-add-rollback-migration-helpers-for-change-column-type-concurrently.yml b/changelogs/unreleased/247496-add-rollback-migration-helpers-for-change-column-type-concurrently.yml
new file mode 100644
index 00000000000..c060c044050
--- /dev/null
+++ b/changelogs/unreleased/247496-add-rollback-migration-helpers-for-change-column-type-concurrently.yml
@@ -0,0 +1,5 @@
+---
+title: Add undo helpers for change_column_type_concurrently and cleanup_concurrent_column_type_change
+merge_request: 44155
+author:
+type: other
diff --git a/changelogs/unreleased/247634-add-healthcheck-to-ce.yml b/changelogs/unreleased/247634-add-healthcheck-to-ce.yml
new file mode 100644
index 00000000000..06e571e8166
--- /dev/null
+++ b/changelogs/unreleased/247634-add-healthcheck-to-ce.yml
@@ -0,0 +1,6 @@
+---
+title: Back-port free instance review for instances with 50+ users from EE Core to
+ CE
+merge_request: 44770
+author:
+type: changed
diff --git a/changelogs/unreleased/247895-search-results-filters-should-have-a-clear-behavior.yml b/changelogs/unreleased/247895-search-results-filters-should-have-a-clear-behavior.yml
new file mode 100644
index 00000000000..b113ed96e18
--- /dev/null
+++ b/changelogs/unreleased/247895-search-results-filters-should-have-a-clear-behavior.yml
@@ -0,0 +1,5 @@
+---
+title: Add buttons in the Search page to clear Group and Project filters
+merge_request: 42897
+author:
+type: added
diff --git a/changelogs/unreleased/248564-remove-web-ide-suggestion-banner-on-blob-edit.yml b/changelogs/unreleased/248564-remove-web-ide-suggestion-banner-on-blob-edit.yml
new file mode 100644
index 00000000000..7977c4f6c46
--- /dev/null
+++ b/changelogs/unreleased/248564-remove-web-ide-suggestion-banner-on-blob-edit.yml
@@ -0,0 +1,5 @@
+---
+title: Remove banner that suggests Web IDE for editing gitlab-ci.yml
+merge_request: 42815
+author:
+type: changed
diff --git a/changelogs/unreleased/249180-add-time-limit-on-counts.yml b/changelogs/unreleased/249180-add-time-limit-on-counts.yml
new file mode 100644
index 00000000000..e11962c5a43
--- /dev/null
+++ b/changelogs/unreleased/249180-add-time-limit-on-counts.yml
@@ -0,0 +1,5 @@
+---
+title: Recover gracefully when issuable counts are too expensive
+merge_request: 44184
+author:
+type: fixed
diff --git a/changelogs/unreleased/249368-unit-test-report-test-cases-with-errored-status-show-skipped-icon.yml b/changelogs/unreleased/249368-unit-test-report-test-cases-with-errored-status-show-skipped-icon.yml
new file mode 100644
index 00000000000..5767b241881
--- /dev/null
+++ b/changelogs/unreleased/249368-unit-test-report-test-cases-with-errored-status-show-skipped-icon.yml
@@ -0,0 +1,5 @@
+---
+title: 'Unit Test Report: Fix icon for errored status'
+merge_request: 42540
+author:
+type: fixed
diff --git a/changelogs/unreleased/249550-remove-feature-flag-for-core-mr-widget.yml b/changelogs/unreleased/249550-remove-feature-flag-for-core-mr-widget.yml
new file mode 100644
index 00000000000..ee2059bbcda
--- /dev/null
+++ b/changelogs/unreleased/249550-remove-feature-flag-for-core-mr-widget.yml
@@ -0,0 +1,5 @@
+---
+title: Enable core_security_mr_widget feature flag by default
+merge_request: 44764
+author:
+type: added
diff --git a/changelogs/unreleased/249561-update-workhorse.yml b/changelogs/unreleased/249561-update-workhorse.yml
new file mode 100644
index 00000000000..21bd979f4a2
--- /dev/null
+++ b/changelogs/unreleased/249561-update-workhorse.yml
@@ -0,0 +1,5 @@
+---
+title: Update GitLab Workhorse to v8.47.0
+merge_request: 42855
+author:
+type: other
diff --git a/changelogs/unreleased/249590-project-count-admin-view.yml b/changelogs/unreleased/249590-project-count-admin-view.yml
new file mode 100644
index 00000000000..5e9d9473f43
--- /dev/null
+++ b/changelogs/unreleased/249590-project-count-admin-view.yml
@@ -0,0 +1,5 @@
+---
+title: Display user project count on Admin Dashboard
+merge_request: 42871
+author:
+type: added
diff --git a/changelogs/unreleased/249811-remove-coverage-report-view-feature-flag.yml b/changelogs/unreleased/249811-remove-coverage-report-view-feature-flag.yml
new file mode 100644
index 00000000000..5c6933ebe02
--- /dev/null
+++ b/changelogs/unreleased/249811-remove-coverage-report-view-feature-flag.yml
@@ -0,0 +1,5 @@
+---
+title: Remove coverage_report_view feature flag
+merge_request: 43711
+author: David Barr @davebarr
+type: removed
diff --git a/changelogs/unreleased/249819-ide-improve-errors.yml b/changelogs/unreleased/249819-ide-improve-errors.yml
new file mode 100644
index 00000000000..925f7e5f647
--- /dev/null
+++ b/changelogs/unreleased/249819-ide-improve-errors.yml
@@ -0,0 +1,5 @@
+---
+title: Improve WebIDE error messages on committing
+merge_request: 43408
+author:
+type: changed
diff --git a/changelogs/unreleased/250041-does-not-refresh-project-snippet-statistics-on-a-read-only-instanc.yml b/changelogs/unreleased/250041-does-not-refresh-project-snippet-statistics-on-a-read-only-instanc.yml
new file mode 100644
index 00000000000..f85da860bcd
--- /dev/null
+++ b/changelogs/unreleased/250041-does-not-refresh-project-snippet-statistics-on-a-read-only-instanc.yml
@@ -0,0 +1,5 @@
+---
+title: Does not refresh project/snippet statistics on a read-only instance
+merge_request: 42417
+author:
+type: fixed
diff --git a/changelogs/unreleased/250355-iterations-overlap-validation-bug.yml b/changelogs/unreleased/250355-iterations-overlap-validation-bug.yml
new file mode 100644
index 00000000000..a2c23138144
--- /dev/null
+++ b/changelogs/unreleased/250355-iterations-overlap-validation-bug.yml
@@ -0,0 +1,5 @@
+---
+title: Fix iteration validation not checking parent groups
+merge_request: 43234
+author:
+type: fixed
diff --git a/changelogs/unreleased/250571-jumping-button-on-the-environments-page.yml b/changelogs/unreleased/250571-jumping-button-on-the-environments-page.yml
new file mode 100644
index 00000000000..73d01d0f620
--- /dev/null
+++ b/changelogs/unreleased/250571-jumping-button-on-the-environments-page.yml
@@ -0,0 +1,5 @@
+---
+title: Avoid New Environment button glitching when changing tabs
+merge_request: 44603
+author:
+type: fixed
diff --git a/changelogs/unreleased/250580-fix-graphql-api-token-authentication.yml b/changelogs/unreleased/250580-fix-graphql-api-token-authentication.yml
new file mode 100644
index 00000000000..8beebf53a02
--- /dev/null
+++ b/changelogs/unreleased/250580-fix-graphql-api-token-authentication.yml
@@ -0,0 +1,5 @@
+---
+title: Fix GraphQL token authentication when installed under a relative URL
+merge_request: 42706
+author:
+type: fixed
diff --git a/changelogs/unreleased/250654-get-lfs-push-mirror-working-for-github.yml b/changelogs/unreleased/250654-get-lfs-push-mirror-working-for-github.yml
new file mode 100644
index 00000000000..1bc0f738692
--- /dev/null
+++ b/changelogs/unreleased/250654-get-lfs-push-mirror-working-for-github.yml
@@ -0,0 +1,5 @@
+---
+title: Make git lfs for push mirrors work to GitHub.com
+merge_request: 43321
+author:
+type: fixed
diff --git a/changelogs/unreleased/250671-don-t-init-http-metrics-in-sidekiq.yml b/changelogs/unreleased/250671-don-t-init-http-metrics-in-sidekiq.yml
new file mode 100644
index 00000000000..4f1ce2a10ca
--- /dev/null
+++ b/changelogs/unreleased/250671-don-t-init-http-metrics-in-sidekiq.yml
@@ -0,0 +1,5 @@
+---
+title: Don't expose http_request_duration_seconds metrics in sidekiq exporter
+merge_request: 43941
+author:
+type: performance
diff --git a/changelogs/unreleased/250685-fix-carets.yml b/changelogs/unreleased/250685-fix-carets.yml
new file mode 100644
index 00000000000..52885668f88
--- /dev/null
+++ b/changelogs/unreleased/250685-fix-carets.yml
@@ -0,0 +1,5 @@
+---
+title: Fix caret sizes in navigation
+merge_request: 42605
+author:
+type: fixed
diff --git a/changelogs/unreleased/250727-use-fuzzaldrinplus-search-for-labels.yml b/changelogs/unreleased/250727-use-fuzzaldrinplus-search-for-labels.yml
new file mode 100644
index 00000000000..2513161075c
--- /dev/null
+++ b/changelogs/unreleased/250727-use-fuzzaldrinplus-search-for-labels.yml
@@ -0,0 +1,5 @@
+---
+title: Add fuzzy search support to labels dropdown
+merge_request: 43969
+author:
+type: fixed
diff --git a/changelogs/unreleased/251048-modify-time-period-for-batch-counting-performance-of-the-last-port.yml b/changelogs/unreleased/251048-modify-time-period-for-batch-counting-performance-of-the-last-port.yml
new file mode 100644
index 00000000000..00f5c9b0f04
--- /dev/null
+++ b/changelogs/unreleased/251048-modify-time-period-for-batch-counting-performance-of-the-last-port.yml
@@ -0,0 +1,5 @@
+---
+title: Modify time_period for last 28 days to improve batch counting performance
+merge_request: 42972
+author:
+type: performance
diff --git a/changelogs/unreleased/251113-create_framework_model.yml b/changelogs/unreleased/251113-create_framework_model.yml
new file mode 100644
index 00000000000..7db07459e9e
--- /dev/null
+++ b/changelogs/unreleased/251113-create_framework_model.yml
@@ -0,0 +1,5 @@
+---
+title: Create ComplianceManagement::Framework Model
+merge_request: 43301
+author:
+type: changed
diff --git a/changelogs/unreleased/251179-spike-investigate-value-of-sentry-vs-performance-implications.yml b/changelogs/unreleased/251179-spike-investigate-value-of-sentry-vs-performance-implications.yml
new file mode 100644
index 00000000000..876083b0fe1
--- /dev/null
+++ b/changelogs/unreleased/251179-spike-investigate-value-of-sentry-vs-performance-implications.yml
@@ -0,0 +1,5 @@
+---
+title: Remove Sentry implementation to investigate performance impact
+merge_request: 44643
+author:
+type: performance
diff --git a/changelogs/unreleased/251214-remove-release-evidence-collection-feature-flag.yml b/changelogs/unreleased/251214-remove-release-evidence-collection-feature-flag.yml
new file mode 100644
index 00000000000..31b147cc23c
--- /dev/null
+++ b/changelogs/unreleased/251214-remove-release-evidence-collection-feature-flag.yml
@@ -0,0 +1,5 @@
+---
+title: Remove release_evidence_collection feature flag
+merge_request: 44234
+author: David Barr @davebarr
+type: removed
diff --git a/changelogs/unreleased/251935-add-default_branch_name-column-to-namespace_settings-table.yml b/changelogs/unreleased/251935-add-default_branch_name-column-to-namespace_settings-table.yml
new file mode 100644
index 00000000000..6a6139c3c45
--- /dev/null
+++ b/changelogs/unreleased/251935-add-default_branch_name-column-to-namespace_settings-table.yml
@@ -0,0 +1,5 @@
+---
+title: Add :default_branch_name column to namespace_settings
+merge_request: 42778
+author:
+type: added
diff --git a/changelogs/unreleased/251963-respect-group-s-default-branch-name-when-present.yml b/changelogs/unreleased/251963-respect-group-s-default-branch-name-when-present.yml
new file mode 100644
index 00000000000..593be2d1450
--- /dev/null
+++ b/changelogs/unreleased/251963-respect-group-s-default-branch-name-when-present.yml
@@ -0,0 +1,5 @@
+---
+title: Respect Group's default branch name when present
+merge_request: 44370
+author:
+type: changed
diff --git a/changelogs/unreleased/254197-merge-request-diff-has-an-extra-spacing-on-mobile.yml b/changelogs/unreleased/254197-merge-request-diff-has-an-extra-spacing-on-mobile.yml
new file mode 100644
index 00000000000..02cf7dbea49
--- /dev/null
+++ b/changelogs/unreleased/254197-merge-request-diff-has-an-extra-spacing-on-mobile.yml
@@ -0,0 +1,5 @@
+---
+title: Eliminate extra spacing on MR diffs from mobile/tablet screen
+merge_request: 42821
+author: Takuya Noguchi
+type: fixed
diff --git a/changelogs/unreleased/254224-notification-icons-missing-icon-for-custom.yml b/changelogs/unreleased/254224-notification-icons-missing-icon-for-custom.yml
new file mode 100644
index 00000000000..1250aa860dc
--- /dev/null
+++ b/changelogs/unreleased/254224-notification-icons-missing-icon-for-custom.yml
@@ -0,0 +1,5 @@
+---
+title: 'Notifications icon: Render empty string for custom setting'
+merge_request: 42848
+author:
+type: other
diff --git a/changelogs/unreleased/254250-add-time-tracking-to-incidents.yml b/changelogs/unreleased/254250-add-time-tracking-to-incidents.yml
new file mode 100644
index 00000000000..0f183f66e82
--- /dev/null
+++ b/changelogs/unreleased/254250-add-time-tracking-to-incidents.yml
@@ -0,0 +1,5 @@
+---
+title: Allow time tracking in incidents
+merge_request: 42965
+author:
+type: changed
diff --git a/changelogs/unreleased/254281-add-user-agent-to-git-lfs-client.yml b/changelogs/unreleased/254281-add-user-agent-to-git-lfs-client.yml
new file mode 100644
index 00000000000..7f9f2d58fc2
--- /dev/null
+++ b/changelogs/unreleased/254281-add-user-agent-to-git-lfs-client.yml
@@ -0,0 +1,5 @@
+---
+title: Fix verifying LFS uploads with GitHub
+merge_request: 43852
+author:
+type: fixed
diff --git a/changelogs/unreleased/254281-lfs-push-mirror-prefers-server-authorization-header.yml b/changelogs/unreleased/254281-lfs-push-mirror-prefers-server-authorization-header.yml
new file mode 100644
index 00000000000..771047b908a
--- /dev/null
+++ b/changelogs/unreleased/254281-lfs-push-mirror-prefers-server-authorization-header.yml
@@ -0,0 +1,5 @@
+---
+title: Prefer server-provided authentication for LFS push mirroring
+merge_request: 44284
+author:
+type: fixed
diff --git a/changelogs/unreleased/254281-remove-push-mirror-syncs-lfs-feature-flag.yml b/changelogs/unreleased/254281-remove-push-mirror-syncs-lfs-feature-flag.yml
new file mode 100644
index 00000000000..6272ae1b995
--- /dev/null
+++ b/changelogs/unreleased/254281-remove-push-mirror-syncs-lfs-feature-flag.yml
@@ -0,0 +1,5 @@
+---
+title: Sync LFS objects when push mirroring over HTTPS
+merge_request: 44457
+author:
+type: added
diff --git a/changelogs/unreleased/254673-replace-cycle_analytics-icon_branch-svg-with-commit-svg-in-gitlab-.yml b/changelogs/unreleased/254673-replace-cycle_analytics-icon_branch-svg-with-commit-svg-in-gitlab-.yml
new file mode 100644
index 00000000000..ae176f0c1fd
--- /dev/null
+++ b/changelogs/unreleased/254673-replace-cycle_analytics-icon_branch-svg-with-commit-svg-in-gitlab-.yml
@@ -0,0 +1,5 @@
+---
+title: Replace in-repo SVGs with @gitlab/svgs in Cycle Analytics
+merge_request: 43823
+author: Takuya Noguchi
+type: other
diff --git a/changelogs/unreleased/254706-fix-commit-item-layout-on-mrs.yml b/changelogs/unreleased/254706-fix-commit-item-layout-on-mrs.yml
new file mode 100644
index 00000000000..bfa48ad3d93
--- /dev/null
+++ b/changelogs/unreleased/254706-fix-commit-item-layout-on-mrs.yml
@@ -0,0 +1,5 @@
+---
+title: Improve the Commit box on the Merge Request Changs tab when browsing per commit
+merge_request: 43613
+author:
+type: fixed
diff --git a/changelogs/unreleased/254721-enable-store_ci_pipeline_counts_by_status-ff-by-default.yml b/changelogs/unreleased/254721-enable-store_ci_pipeline_counts_by_status-ff-by-default.yml
new file mode 100644
index 00000000000..e0491b10620
--- /dev/null
+++ b/changelogs/unreleased/254721-enable-store_ci_pipeline_counts_by_status-ff-by-default.yml
@@ -0,0 +1,5 @@
+---
+title: Store pipeline counts by status for instance statistics
+merge_request: 43857
+author:
+type: added
diff --git a/changelogs/unreleased/254823-automatically-expand-file-on-merge-request-with-changes-to-single-.yml b/changelogs/unreleased/254823-automatically-expand-file-on-merge-request-with-changes-to-single-.yml
new file mode 100644
index 00000000000..42a1d7c6847
--- /dev/null
+++ b/changelogs/unreleased/254823-automatically-expand-file-on-merge-request-with-changes-to-single-.yml
@@ -0,0 +1,5 @@
+---
+title: Automatically expand diffs for merge requests with changes to a single file
+merge_request: 44629
+author:
+type: changed
diff --git a/changelogs/unreleased/254903-add-multiple-assignee-filter-graphql.yml b/changelogs/unreleased/254903-add-multiple-assignee-filter-graphql.yml
new file mode 100644
index 00000000000..54d482d0c9f
--- /dev/null
+++ b/changelogs/unreleased/254903-add-multiple-assignee-filter-graphql.yml
@@ -0,0 +1,5 @@
+---
+title: Add assignee usernames to issue resolver
+merge_request: 43294
+author:
+type: changed
diff --git a/changelogs/unreleased/254932-fix-search-results-blob-link-to-branch.yml b/changelogs/unreleased/254932-fix-search-results-blob-link-to-branch.yml
new file mode 100644
index 00000000000..7e3e2d05ac1
--- /dev/null
+++ b/changelogs/unreleased/254932-fix-search-results-blob-link-to-branch.yml
@@ -0,0 +1,5 @@
+---
+title: Ensure code search results link to searched ref
+merge_request: 43510
+author:
+type: fixed
diff --git a/changelogs/unreleased/254946-add-missing-fa-icons-for-file_type_icon_class.yml b/changelogs/unreleased/254946-add-missing-fa-icons-for-file_type_icon_class.yml
new file mode 100644
index 00000000000..8ad7010c0ee
--- /dev/null
+++ b/changelogs/unreleased/254946-add-missing-fa-icons-for-file_type_icon_class.yml
@@ -0,0 +1,5 @@
+---
+title: Add missing fontawesome file icon classes
+merge_request: 43091
+author:
+type: added
diff --git a/changelogs/unreleased/255322-search-sort-issues-and-mrs.yml b/changelogs/unreleased/255322-search-sort-issues-and-mrs.yml
new file mode 100644
index 00000000000..6808844dd9b
--- /dev/null
+++ b/changelogs/unreleased/255322-search-sort-issues-and-mrs.yml
@@ -0,0 +1,5 @@
+---
+title: Add sort parameter to Issue and Merge Request scopes
+merge_request: 43295
+author:
+type: added
diff --git a/changelogs/unreleased/255347-add-a-project-configured-with-gitpod-to-project-templates.yml b/changelogs/unreleased/255347-add-a-project-configured-with-gitpod-to-project-templates.yml
new file mode 100644
index 00000000000..21ea90a7be7
--- /dev/null
+++ b/changelogs/unreleased/255347-add-a-project-configured-with-gitpod-to-project-templates.yml
@@ -0,0 +1,5 @@
+---
+title: "Add Gitpod Spring Petclinic to Project Templates"
+merge_request: 43319
+author:
+type: added
diff --git a/changelogs/unreleased/255938-delete-user-dialog-text-contains-formatting-strings.yml b/changelogs/unreleased/255938-delete-user-dialog-text-contains-formatting-strings.yml
new file mode 100644
index 00000000000..7842acf3d85
--- /dev/null
+++ b/changelogs/unreleased/255938-delete-user-dialog-text-contains-formatting-strings.yml
@@ -0,0 +1,5 @@
+---
+title: Fix Delete User dialog formatted strings
+merge_request: 43871
+author:
+type: fixed
diff --git a/changelogs/unreleased/255985-snowplow-count-timeline-toggle.yml b/changelogs/unreleased/255985-snowplow-count-timeline-toggle.yml
new file mode 100644
index 00000000000..ea33491efcd
--- /dev/null
+++ b/changelogs/unreleased/255985-snowplow-count-timeline-toggle.yml
@@ -0,0 +1,5 @@
+---
+title: Snowplow count of clicks on timeline toggle for incident comments
+merge_request: 44487
+author:
+type: added
diff --git a/changelogs/unreleased/256094-fix-copy-indexes-migration-helper-opclass-replication.yml b/changelogs/unreleased/256094-fix-copy-indexes-migration-helper-opclass-replication.yml
new file mode 100644
index 00000000000..45b182503e8
--- /dev/null
+++ b/changelogs/unreleased/256094-fix-copy-indexes-migration-helper-opclass-replication.yml
@@ -0,0 +1,6 @@
+---
+title: Fix copy_indexes migration helper skipping the opclass for indexes
+ with operator classes defined for them
+merge_request: 43471
+author:
+type: fixed
diff --git a/changelogs/unreleased/256121-add-schema-to-migration-helpers-that-query-the-pg-catalog.yml b/changelogs/unreleased/256121-add-schema-to-migration-helpers-that-query-the-pg-catalog.yml
new file mode 100644
index 00000000000..7fa4750c445
--- /dev/null
+++ b/changelogs/unreleased/256121-add-schema-to-migration-helpers-that-query-the-pg-catalog.yml
@@ -0,0 +1,5 @@
+---
+title: Update database helpers to set the current_schema
+merge_request: 43568
+author:
+type: fixed
diff --git a/changelogs/unreleased/257198-align-recognized-markdown-extensions-with-file-icon.yml b/changelogs/unreleased/257198-align-recognized-markdown-extensions-with-file-icon.yml
new file mode 100644
index 00000000000..5ba79e464aa
--- /dev/null
+++ b/changelogs/unreleased/257198-align-recognized-markdown-extensions-with-file-icon.yml
@@ -0,0 +1,5 @@
+---
+title: Add markdown icon to more file extensions
+merge_request: 43479
+author:
+type: fixed
diff --git a/changelogs/unreleased/257762-boards-page-broken-on-dark-mode.yml b/changelogs/unreleased/257762-boards-page-broken-on-dark-mode.yml
new file mode 100644
index 00000000000..44dda08d5b0
--- /dev/null
+++ b/changelogs/unreleased/257762-boards-page-broken-on-dark-mode.yml
@@ -0,0 +1,5 @@
+---
+title: Fix dark mode for boards and swimlanes
+merge_request: 44951
+author:
+type: fixed
diff --git a/changelogs/unreleased/257764-milestones-page-broken-on-dark-mode.yml b/changelogs/unreleased/257764-milestones-page-broken-on-dark-mode.yml
new file mode 100644
index 00000000000..40a552d2d25
--- /dev/null
+++ b/changelogs/unreleased/257764-milestones-page-broken-on-dark-mode.yml
@@ -0,0 +1,5 @@
+---
+title: Fix dark mode for milestones
+merge_request: 44952
+author:
+type: fixed
diff --git a/changelogs/unreleased/257842-issue-incident-feature-flag-removal.yml b/changelogs/unreleased/257842-issue-incident-feature-flag-removal.yml
new file mode 100644
index 00000000000..e56812d8713
--- /dev/null
+++ b/changelogs/unreleased/257842-issue-incident-feature-flag-removal.yml
@@ -0,0 +1,5 @@
+---
+title: Allow users to navigate to the incidents show details page wrapper through `/issues/incidents/:id` from the Incident list
+merge_request: 44438
+author:
+type: changed
diff --git a/changelogs/unreleased/257881-migration-user-admin-approval-toggle.yml b/changelogs/unreleased/257881-migration-user-admin-approval-toggle.yml
new file mode 100644
index 00000000000..a995bfe7a7f
--- /dev/null
+++ b/changelogs/unreleased/257881-migration-user-admin-approval-toggle.yml
@@ -0,0 +1,6 @@
+---
+title: Add a database column to enable or disable the setting that puts newly registered
+ users in a pending state, requiring admin approval for their activation
+merge_request: 43661
+author:
+type: added
diff --git a/changelogs/unreleased/258203-add-api-fuzzing-plan-limits-db.yml b/changelogs/unreleased/258203-add-api-fuzzing-plan-limits-db.yml
new file mode 100644
index 00000000000..19695b5c384
--- /dev/null
+++ b/changelogs/unreleased/258203-add-api-fuzzing-plan-limits-db.yml
@@ -0,0 +1,5 @@
+---
+title: Add API Fuzzing plan limits db column
+merge_request: 43934
+author:
+type: added
diff --git a/changelogs/unreleased/258206-enable-gitpod-flag-by-default.yml b/changelogs/unreleased/258206-enable-gitpod-flag-by-default.yml
new file mode 100644
index 00000000000..a55fac23c32
--- /dev/null
+++ b/changelogs/unreleased/258206-enable-gitpod-flag-by-default.yml
@@ -0,0 +1,5 @@
+---
+title: Enable Gitpod button on file tree view
+merge_request: 43961
+author:
+type: added
diff --git a/changelogs/unreleased/258668-update-icons-in-nav.yml b/changelogs/unreleased/258668-update-icons-in-nav.yml
new file mode 100644
index 00000000000..ec630bb34a3
--- /dev/null
+++ b/changelogs/unreleased/258668-update-icons-in-nav.yml
@@ -0,0 +1,5 @@
+---
+title: Update nav icons to chevron-down
+merge_request: 43767
+author:
+type: changed
diff --git a/changelogs/unreleased/258677-center-toggle-focus-mode-icon.yml b/changelogs/unreleased/258677-center-toggle-focus-mode-icon.yml
new file mode 100644
index 00000000000..3e0886a9d47
--- /dev/null
+++ b/changelogs/unreleased/258677-center-toggle-focus-mode-icon.yml
@@ -0,0 +1,5 @@
+---
+title: Update toggle focus mode icon to gl-icon
+merge_request: 43888
+author:
+type: changed
diff --git a/changelogs/unreleased/258964-update-node-sass-from-4-12-to-4-14.yml b/changelogs/unreleased/258964-update-node-sass-from-4-12-to-4-14.yml
new file mode 100644
index 00000000000..1e4b6f97122
--- /dev/null
+++ b/changelogs/unreleased/258964-update-node-sass-from-4-12-to-4-14.yml
@@ -0,0 +1,5 @@
+---
+title: Update node-sass from 4.12.0 to 4.14.1
+merge_request: 43808
+author: Takuya Noguchi
+type: other
diff --git a/changelogs/unreleased/258980-enable-feature-flag-by-default-of-admin-approval-for-new-user-sign.yml b/changelogs/unreleased/258980-enable-feature-flag-by-default-of-admin-approval-for-new-user-sign.yml
new file mode 100644
index 00000000000..fa3abd7d356
--- /dev/null
+++ b/changelogs/unreleased/258980-enable-feature-flag-by-default-of-admin-approval-for-new-user-sign.yml
@@ -0,0 +1,5 @@
+---
+title: Introduce 'admin approvals for new user signups' feature
+merge_request: 45233
+author:
+type: added
diff --git a/changelogs/unreleased/259005-add-cached-queries-to-performance-bar.yml b/changelogs/unreleased/259005-add-cached-queries-to-performance-bar.yml
new file mode 100644
index 00000000000..0d2796a301f
--- /dev/null
+++ b/changelogs/unreleased/259005-add-cached-queries-to-performance-bar.yml
@@ -0,0 +1,5 @@
+---
+title: Include cached sql calls in performance bar
+merge_request: 44022
+author:
+type: changed
diff --git a/changelogs/unreleased/259060-align-badge-in-mr-list.yml b/changelogs/unreleased/259060-align-badge-in-mr-list.yml
new file mode 100644
index 00000000000..e99194b4b51
--- /dev/null
+++ b/changelogs/unreleased/259060-align-badge-in-mr-list.yml
@@ -0,0 +1,5 @@
+---
+title: Align badge with avatar in MR List
+merge_request: 44671
+author:
+type: fixed
diff --git a/changelogs/unreleased/260323-handle-malformed-composer-json.yml b/changelogs/unreleased/260323-handle-malformed-composer-json.yml
new file mode 100644
index 00000000000..347493786c6
--- /dev/null
+++ b/changelogs/unreleased/260323-handle-malformed-composer-json.yml
@@ -0,0 +1,5 @@
+---
+title: Return 422 error rather than 500 when composer.json is missing or malformed
+merge_request: 44587
+author: David Barr @davebarr
+type: fixed
diff --git a/changelogs/unreleased/262051-design-thumbnail-image-is-not-updated-after-uploading-an-image-wit.yml b/changelogs/unreleased/262051-design-thumbnail-image-is-not-updated-after-uploading-an-image-wit.yml
new file mode 100644
index 00000000000..b6e597bfc97
--- /dev/null
+++ b/changelogs/unreleased/262051-design-thumbnail-image-is-not-updated-after-uploading-an-image-wit.yml
@@ -0,0 +1,5 @@
+---
+title: Update Design thumbnail after uploading an image with the same filename
+merge_request: 44305
+author:
+type: fixed
diff --git a/changelogs/unreleased/262073-fix-merge-conflict-button-text-none.yml b/changelogs/unreleased/262073-fix-merge-conflict-button-text-none.yml
new file mode 100644
index 00000000000..2c819d7485d
--- /dev/null
+++ b/changelogs/unreleased/262073-fix-merge-conflict-button-text-none.yml
@@ -0,0 +1,5 @@
+---
+title: Fix merge conflict button text if "None" code style selected
+merge_request: 44427
+author: David Barr @davebarr
+type: fixed
diff --git a/changelogs/unreleased/262633-integrations-form-cleanup.yml b/changelogs/unreleased/262633-integrations-form-cleanup.yml
new file mode 100644
index 00000000000..af28c721e7b
--- /dev/null
+++ b/changelogs/unreleased/262633-integrations-form-cleanup.yml
@@ -0,0 +1,5 @@
+---
+title: Fix documentation link, spacing, and error handling in alert integrations list
+merge_request: 45304
+author:
+type: other
diff --git a/changelogs/unreleased/262686-track-unique-wiki-page-views.yml b/changelogs/unreleased/262686-track-unique-wiki-page-views.yml
new file mode 100644
index 00000000000..3b40651c42b
--- /dev/null
+++ b/changelogs/unreleased/262686-track-unique-wiki-page-views.yml
@@ -0,0 +1,5 @@
+---
+title: Track unique wiki page views in Usage Ping
+merge_request: 44622
+author:
+type: changed
diff --git a/changelogs/unreleased/262730-fix-incident-table-hover.yml b/changelogs/unreleased/262730-fix-incident-table-hover.yml
new file mode 100644
index 00000000000..c24db9e9d81
--- /dev/null
+++ b/changelogs/unreleased/262730-fix-incident-table-hover.yml
@@ -0,0 +1,5 @@
+---
+title: Fix table border hover for incidents and alerts
+merge_request: 45117
+author:
+type: fixed
diff --git a/changelogs/unreleased/262851-minimal-access-role-resending-member-invite-causes-404.yml b/changelogs/unreleased/262851-minimal-access-role-resending-member-invite-causes-404.yml
new file mode 100644
index 00000000000..5d3c321c2d8
--- /dev/null
+++ b/changelogs/unreleased/262851-minimal-access-role-resending-member-invite-causes-404.yml
@@ -0,0 +1,5 @@
+---
+title: Allow re-sending invite to minimal access user
+merge_request: 44936
+author:
+type: fixed
diff --git a/changelogs/unreleased/263102-bugfix-use-project-owner-to-perform-git-actions-during-design-copy.yml b/changelogs/unreleased/263102-bugfix-use-project-owner-to-perform-git-actions-during-design-copy.yml
new file mode 100644
index 00000000000..1513e876841
--- /dev/null
+++ b/changelogs/unreleased/263102-bugfix-use-project-owner-to-perform-git-actions-during-design-copy.yml
@@ -0,0 +1,6 @@
+---
+title: Perform git actions with a user with elevated git permissions during a design
+ copy
+merge_request: 44662
+author:
+type: fixed
diff --git a/changelogs/unreleased/263110-improve-cleanup-policies-selection-during-their-execution.yml b/changelogs/unreleased/263110-improve-cleanup-policies-selection-during-their-execution.yml
new file mode 100644
index 00000000000..bff321cd5b9
--- /dev/null
+++ b/changelogs/unreleased/263110-improve-cleanup-policies-selection-during-their-execution.yml
@@ -0,0 +1,5 @@
+---
+title: Exclude policies with no container repositories when executing them
+merge_request: 44748
+author:
+type: fixed
diff --git a/changelogs/unreleased/263221-clone-button-misaligned-on-empty-repository.yml b/changelogs/unreleased/263221-clone-button-misaligned-on-empty-repository.yml
new file mode 100644
index 00000000000..0d46d50092d
--- /dev/null
+++ b/changelogs/unreleased/263221-clone-button-misaligned-on-empty-repository.yml
@@ -0,0 +1,5 @@
+---
+title: Fix button row margin on empty project
+merge_request: 44860
+author:
+type: fixed
diff --git a/changelogs/unreleased/263237-replace-font-awesome-icons-in-user-profile.yml b/changelogs/unreleased/263237-replace-font-awesome-icons-in-user-profile.yml
new file mode 100644
index 00000000000..1a54c38161c
--- /dev/null
+++ b/changelogs/unreleased/263237-replace-font-awesome-icons-in-user-profile.yml
@@ -0,0 +1,5 @@
+---
+title: Replace Font Awesome social icons with GitLab SVGs on user profile page
+merge_request: 44599
+author:
+type: other
diff --git a/changelogs/unreleased/263402-enable-review-app-button-opens-twice-the-popup.yml b/changelogs/unreleased/263402-enable-review-app-button-opens-twice-the-popup.yml
new file mode 100644
index 00000000000..e790a3fd228
--- /dev/null
+++ b/changelogs/unreleased/263402-enable-review-app-button-opens-twice-the-popup.yml
@@ -0,0 +1,5 @@
+---
+title: Avooid opening 2 modals for enabling review app
+merge_request: 45361
+author:
+type: fixed
diff --git a/changelogs/unreleased/263406-enable-cached-markdown-blob-default.yml b/changelogs/unreleased/263406-enable-cached-markdown-blob-default.yml
new file mode 100644
index 00000000000..8bafc2abd89
--- /dev/null
+++ b/changelogs/unreleased/263406-enable-cached-markdown-blob-default.yml
@@ -0,0 +1,5 @@
+---
+title: Enable caching of markdown when viewing blob
+merge_request: 45367
+author:
+type: performance
diff --git a/changelogs/unreleased/263412-enable-ci_manual_bridges-by-default.yml b/changelogs/unreleased/263412-enable-ci_manual_bridges-by-default.yml
new file mode 100644
index 00000000000..201c6e277e1
--- /dev/null
+++ b/changelogs/unreleased/263412-enable-ci_manual_bridges-by-default.yml
@@ -0,0 +1,5 @@
+---
+title: Add support for manual bridges for CI pipelines
+merge_request: 45368
+author:
+type: added
diff --git a/changelogs/unreleased/263484-integration-descriptions-should-be-less-project-level-specific.yml b/changelogs/unreleased/263484-integration-descriptions-should-be-less-project-level-specific.yml
new file mode 100644
index 00000000000..1a804edec88
--- /dev/null
+++ b/changelogs/unreleased/263484-integration-descriptions-should-be-less-project-level-specific.yml
@@ -0,0 +1,5 @@
+---
+title: Update integration descriptions to not be project-specific
+merge_request: 44893
+author:
+type: changed
diff --git a/changelogs/unreleased/263509_add_cross_site_cookies_browser_limitaion_message.yml b/changelogs/unreleased/263509_add_cross_site_cookies_browser_limitaion_message.yml
new file mode 100644
index 00000000000..9ce503a8c9d
--- /dev/null
+++ b/changelogs/unreleased/263509_add_cross_site_cookies_browser_limitaion_message.yml
@@ -0,0 +1,5 @@
+---
+title: Add note about cross site cookies browser limitaion to Jira App page
+merge_request: 44898
+author:
+type: fixed
diff --git a/changelogs/unreleased/264790-bs4-optimization-admin-abuse-reports.yml b/changelogs/unreleased/264790-bs4-optimization-admin-abuse-reports.yml
new file mode 100644
index 00000000000..fb7c68358a2
--- /dev/null
+++ b/changelogs/unreleased/264790-bs4-optimization-admin-abuse-reports.yml
@@ -0,0 +1,5 @@
+---
+title: Remove d-md-none/d-sm-none when d-sm-none/d-none exists
+merge_request: 44845
+author: Takuya Noguchi
+type: other
diff --git a/changelogs/unreleased/264790-bs4-optimization-admin-devops-report.yml b/changelogs/unreleased/264790-bs4-optimization-admin-devops-report.yml
new file mode 100644
index 00000000000..cd3f178a3ef
--- /dev/null
+++ b/changelogs/unreleased/264790-bs4-optimization-admin-devops-report.yml
@@ -0,0 +1,5 @@
+---
+title: Remove duplicated BS display properties from Admin DevOps report' HAML
+merge_request: 44846
+author: Takuya Noguchi
+type: other
diff --git a/changelogs/unreleased/264790-bs4-optimization-commit-2.yml b/changelogs/unreleased/264790-bs4-optimization-commit-2.yml
new file mode 100644
index 00000000000..ff9ccf25716
--- /dev/null
+++ b/changelogs/unreleased/264790-bs4-optimization-commit-2.yml
@@ -0,0 +1,5 @@
+---
+title: Remove duplicated BS display property from Commit/Snippet's HAML
+merge_request: 44917
+author: Takuya Noguchi
+type: other
diff --git a/changelogs/unreleased/264790-bs4-optimization-commit.yml b/changelogs/unreleased/264790-bs4-optimization-commit.yml
new file mode 100644
index 00000000000..4cf199eaba1
--- /dev/null
+++ b/changelogs/unreleased/264790-bs4-optimization-commit.yml
@@ -0,0 +1,5 @@
+---
+title: Remove duplicated BS display properties from Commit's HAML
+merge_request: 44847
+author: Takuya Noguchi
+type: other
diff --git a/changelogs/unreleased/264790-bs4-optimization-diff.yml b/changelogs/unreleased/264790-bs4-optimization-diff.yml
new file mode 100644
index 00000000000..13a795d2568
--- /dev/null
+++ b/changelogs/unreleased/264790-bs4-optimization-diff.yml
@@ -0,0 +1,5 @@
+---
+title: Remove duplicated BS display properties from Diff's HAML
+merge_request: 44848
+author: Takuya Noguchi
+type: other
diff --git a/changelogs/unreleased/264790-bs4-optimization-environments.yml b/changelogs/unreleased/264790-bs4-optimization-environments.yml
new file mode 100644
index 00000000000..2845eb68c7b
--- /dev/null
+++ b/changelogs/unreleased/264790-bs4-optimization-environments.yml
@@ -0,0 +1,5 @@
+---
+title: Remove duplicated BS display properties from Environments
+merge_request: 45167
+author: Takuya Noguchi
+type: other
diff --git a/changelogs/unreleased/264790-bs4-optimization-issuable-header.yml b/changelogs/unreleased/264790-bs4-optimization-issuable-header.yml
new file mode 100644
index 00000000000..9e80b566d03
--- /dev/null
+++ b/changelogs/unreleased/264790-bs4-optimization-issuable-header.yml
@@ -0,0 +1,5 @@
+---
+title: Remove duplicated BS display properties from Issuables
+merge_request: 45177
+author: Takuya Noguchi
+type: other
diff --git a/changelogs/unreleased/264790-bs4-optimization-pipelines.yml b/changelogs/unreleased/264790-bs4-optimization-pipelines.yml
new file mode 100644
index 00000000000..cf25b681843
--- /dev/null
+++ b/changelogs/unreleased/264790-bs4-optimization-pipelines.yml
@@ -0,0 +1,5 @@
+---
+title: Remove duplicated BS display properties from Pipelines
+merge_request: 45171
+author: Takuya Noguchi
+type: other
diff --git a/changelogs/unreleased/267000-create-from-template-inherit-integrations.yml b/changelogs/unreleased/267000-create-from-template-inherit-integrations.yml
new file mode 100644
index 00000000000..e2e8f47b745
--- /dev/null
+++ b/changelogs/unreleased/267000-create-from-template-inherit-integrations.yml
@@ -0,0 +1,5 @@
+---
+title: Projects created from templates inherits integrations.
+merge_request: 44932
+author:
+type: changed
diff --git a/changelogs/unreleased/267011-accept-alternative-names-for-production-env.yml b/changelogs/unreleased/267011-accept-alternative-names-for-production-env.yml
new file mode 100644
index 00000000000..b557d19448e
--- /dev/null
+++ b/changelogs/unreleased/267011-accept-alternative-names-for-production-env.yml
@@ -0,0 +1,5 @@
+---
+title: Allow more naming conventions for VSA production environment
+merge_request: 45069
+author:
+type: changed
diff --git a/changelogs/unreleased/267114-enable-usage_data_api-by-default-feature.yml b/changelogs/unreleased/267114-enable-usage_data_api-by-default-feature.yml
new file mode 100644
index 00000000000..df38561eb1a
--- /dev/null
+++ b/changelogs/unreleased/267114-enable-usage_data_api-by-default-feature.yml
@@ -0,0 +1,5 @@
+---
+title: Enable usage_data_api feature flag by default
+merge_request: 45004
+author:
+type: other
diff --git a/changelogs/unreleased/267498-failed-test-qa-specs-features-browser_ui-1_manage-login-register_s.yml b/changelogs/unreleased/267498-failed-test-qa-specs-features-browser_ui-1_manage-login-register_s.yml
new file mode 100644
index 00000000000..bcdf1cae2af
--- /dev/null
+++ b/changelogs/unreleased/267498-failed-test-qa-specs-features-browser_ui-1_manage-login-register_s.yml
@@ -0,0 +1,5 @@
+---
+title: Redirect when no user is signed in when updating registration
+merge_request: 45276
+author:
+type: fixed
diff --git a/changelogs/unreleased/267505-mobile-empty-screen-svg-overlap.yml b/changelogs/unreleased/267505-mobile-empty-screen-svg-overlap.yml
new file mode 100644
index 00000000000..2c07ee33e8b
--- /dev/null
+++ b/changelogs/unreleased/267505-mobile-empty-screen-svg-overlap.yml
@@ -0,0 +1,5 @@
+---
+title: Class and markup cleanup to prevent SVG header bar overlap in Static Site Editor
+merge_request: 45334
+author:
+type: fixed
diff --git a/changelogs/unreleased/267583-fix-storing-of-issue-json-for-redirect.yml b/changelogs/unreleased/267583-fix-storing-of-issue-json-for-redirect.yml
new file mode 100644
index 00000000000..c7f2dfbf9b6
--- /dev/null
+++ b/changelogs/unreleased/267583-fix-storing-of-issue-json-for-redirect.yml
@@ -0,0 +1,5 @@
+---
+title: Fix redirects to issue sidebar JSON when visiting the login page
+merge_request: 45194
+author:
+type: fixed
diff --git a/changelogs/unreleased/267973-replace-fa-angle-double-left-with-gitlab-svg-chevron-double-lg-lef.yml b/changelogs/unreleased/267973-replace-fa-angle-double-left-with-gitlab-svg-chevron-double-lg-lef.yml
new file mode 100644
index 00000000000..e3b56c5dbd9
--- /dev/null
+++ b/changelogs/unreleased/267973-replace-fa-angle-double-left-with-gitlab-svg-chevron-double-lg-lef.yml
@@ -0,0 +1,5 @@
+---
+title: Replace fa-angle-double-left and fa-angle-double-right icons with GitLab SVG
+merge_request: 45251
+author:
+type: changed
diff --git a/changelogs/unreleased/268042-graphql-use-new-global_id-for-discussion-mutations.yml b/changelogs/unreleased/268042-graphql-use-new-global_id-for-discussion-mutations.yml
new file mode 100644
index 00000000000..45cace04adc
--- /dev/null
+++ b/changelogs/unreleased/268042-graphql-use-new-global_id-for-discussion-mutations.yml
@@ -0,0 +1,5 @@
+---
+title: Update GraphQL discussionToggleResolve mutation input id to be more type-specific
+merge_request: 45346
+author:
+type: changed
diff --git a/changelogs/unreleased/268144-mr-widget-copy-branch-name-button-tooltip-occasionally-shows-undef.yml b/changelogs/unreleased/268144-mr-widget-copy-branch-name-button-tooltip-occasionally-shows-undef.yml
new file mode 100644
index 00000000000..412c62c7ce4
--- /dev/null
+++ b/changelogs/unreleased/268144-mr-widget-copy-branch-name-button-tooltip-occasionally-shows-undef.yml
@@ -0,0 +1,5 @@
+---
+title: Fix undefined tooltip text flashing on clipboard icon
+merge_request: 45482
+author:
+type: fixed
diff --git a/changelogs/unreleased/270054-fix-no-method-error.yml b/changelogs/unreleased/270054-fix-no-method-error.yml
new file mode 100644
index 00000000000..ae3706062f2
--- /dev/null
+++ b/changelogs/unreleased/270054-fix-no-method-error.yml
@@ -0,0 +1,5 @@
+---
+title: Fix error when cleaning up MR with no head ref
+merge_request: 45504
+author:
+type: fixed
diff --git a/changelogs/unreleased/27535-new-project-ide.yml b/changelogs/unreleased/27535-new-project-ide.yml
new file mode 100644
index 00000000000..ce06f1c0380
--- /dev/null
+++ b/changelogs/unreleased/27535-new-project-ide.yml
@@ -0,0 +1,5 @@
+---
+title: Use Web IDE to create new files in empty repos
+merge_request: 44287
+author:
+type: added
diff --git a/changelogs/unreleased/32328_add_help_page_documentation_url_column.yml b/changelogs/unreleased/32328_add_help_page_documentation_url_column.yml
new file mode 100644
index 00000000000..bf09578aa54
--- /dev/null
+++ b/changelogs/unreleased/32328_add_help_page_documentation_url_column.yml
@@ -0,0 +1,5 @@
+---
+title: Add Documentation URL to Admin Area
+merge_request: 42702
+author:
+type: added
diff --git a/changelogs/unreleased/32328_use_documentation_url_to_configure_path_to_help_pages.yml b/changelogs/unreleased/32328_use_documentation_url_to_configure_path_to_help_pages.yml
new file mode 100644
index 00000000000..0ddf35eebb5
--- /dev/null
+++ b/changelogs/unreleased/32328_use_documentation_url_to_configure_path_to_help_pages.yml
@@ -0,0 +1,5 @@
+---
+title: Redirect to documentation pages URL when configuration option is set
+merge_request: 43157
+author:
+type: added
diff --git a/changelogs/unreleased/35223-drop-unused-user-id-column-on-cluster-providers-aws.yml b/changelogs/unreleased/35223-drop-unused-user-id-column-on-cluster-providers-aws.yml
new file mode 100644
index 00000000000..dd27d6778fc
--- /dev/null
+++ b/changelogs/unreleased/35223-drop-unused-user-id-column-on-cluster-providers-aws.yml
@@ -0,0 +1,5 @@
+---
+title: Remove unused cluster_providers_aws.created_by_user_id column
+merge_request: 43064
+author:
+type: other
diff --git a/changelogs/unreleased/40174-snowflake-npm-forward.yml b/changelogs/unreleased/40174-snowflake-npm-forward.yml
new file mode 100644
index 00000000000..d0ed22870db
--- /dev/null
+++ b/changelogs/unreleased/40174-snowflake-npm-forward.yml
@@ -0,0 +1,5 @@
+---
+title: Measure npm request forwarding usage
+merge_request: 40174
+author:
+type: added
diff --git a/changelogs/unreleased/42426-migrate-slack-button.yml b/changelogs/unreleased/42426-migrate-slack-button.yml
new file mode 100644
index 00000000000..6599b8bb591
--- /dev/null
+++ b/changelogs/unreleased/42426-migrate-slack-button.yml
@@ -0,0 +1,5 @@
+---
+title: Update button to gl-button on GitLab for Slack page
+merge_request: 42426
+author:
+type: other
diff --git a/changelogs/unreleased/42782-move-beforescript-into-script.yml b/changelogs/unreleased/42782-move-beforescript-into-script.yml
new file mode 100644
index 00000000000..5d649838a8c
--- /dev/null
+++ b/changelogs/unreleased/42782-move-beforescript-into-script.yml
@@ -0,0 +1,5 @@
+---
+title: Move before_script into script for CQ template
+merge_request: 42782
+author: Vicken Simonian @vicken.papaya
+type: fixed
diff --git a/changelogs/unreleased/42916-pypi-install-command.yml b/changelogs/unreleased/42916-pypi-install-command.yml
new file mode 100644
index 00000000000..cad4d355c8c
--- /dev/null
+++ b/changelogs/unreleased/42916-pypi-install-command.yml
@@ -0,0 +1,5 @@
+---
+title: Update pypi install command to work with external dependencies
+merge_request: 42916
+author:
+type: changed
diff --git a/changelogs/unreleased/42917_golang_vendor_templates.yml b/changelogs/unreleased/42917_golang_vendor_templates.yml
new file mode 100644
index 00000000000..928bb628e1c
--- /dev/null
+++ b/changelogs/unreleased/42917_golang_vendor_templates.yml
@@ -0,0 +1,5 @@
+---
+title: Update golang version in vendored Dockerfile template
+merge_request: 42917
+author:
+type: added
diff --git a/changelogs/unreleased/42989-update-deactivation-threshold-to-90-days.yml b/changelogs/unreleased/42989-update-deactivation-threshold-to-90-days.yml
new file mode 100644
index 00000000000..3cf2bac918b
--- /dev/null
+++ b/changelogs/unreleased/42989-update-deactivation-threshold-to-90-days.yml
@@ -0,0 +1,5 @@
+---
+title: Adjusted deactivation threshold from 180 to 90 days
+merge_request: 42989
+author:
+type: changed
diff --git a/changelogs/unreleased/43009-update-docs-link-packages.yml b/changelogs/unreleased/43009-update-docs-link-packages.yml
new file mode 100644
index 00000000000..1722e866e4d
--- /dev/null
+++ b/changelogs/unreleased/43009-update-docs-link-packages.yml
@@ -0,0 +1,5 @@
+---
+title: Empty state Packages UI links to user docs
+merge_request: 43009
+author:
+type: fixed
diff --git a/changelogs/unreleased/43499-update-commit-message-popover.yml b/changelogs/unreleased/43499-update-commit-message-popover.yml
new file mode 100644
index 00000000000..3f4b4a222b7
--- /dev/null
+++ b/changelogs/unreleased/43499-update-commit-message-popover.yml
@@ -0,0 +1,5 @@
+---
+title: Update popover to gl-popover on WebIDE commit message
+merge_request: 43499
+author:
+type: other
diff --git a/changelogs/unreleased/44949-update-copy-insert-modal.yml b/changelogs/unreleased/44949-update-copy-insert-modal.yml
new file mode 100644
index 00000000000..6d936b414bc
--- /dev/null
+++ b/changelogs/unreleased/44949-update-copy-insert-modal.yml
@@ -0,0 +1,5 @@
+---
+title: Update the copy in the insert image modal to align with copy guidelines
+merge_request: 44949
+author:
+type: other
diff --git a/changelogs/unreleased/Add-Issue-Link-to-Open-Message.yml b/changelogs/unreleased/Add-Issue-Link-to-Open-Message.yml
new file mode 100644
index 00000000000..a31210519c8
--- /dev/null
+++ b/changelogs/unreleased/Add-Issue-Link-to-Open-Message.yml
@@ -0,0 +1,5 @@
+---
+title: Add Issue Link to "Issue opened by" Integration Chat Message
+merge_request: 42785
+author: Kev @KevSlashNull
+type: changed
diff --git a/changelogs/unreleased/Migrate-deprecated-delete-milestone-modal-ab.yml b/changelogs/unreleased/Migrate-deprecated-delete-milestone-modal-ab.yml
new file mode 100644
index 00000000000..2bc425b2e12
--- /dev/null
+++ b/changelogs/unreleased/Migrate-deprecated-delete-milestone-modal-ab.yml
@@ -0,0 +1,5 @@
+---
+title: Migrate DeprecatedModal to GitLab UI Modal
+merge_request: 42113
+author:
+type: changed
diff --git a/changelogs/unreleased/Replace-GIDeprecatedDropdown-in-app-assets-javascripts-alert_management.yml b/changelogs/unreleased/Replace-GIDeprecatedDropdown-in-app-assets-javascripts-alert_management.yml
new file mode 100644
index 00000000000..983bfb84325
--- /dev/null
+++ b/changelogs/unreleased/Replace-GIDeprecatedDropdown-in-app-assets-javascripts-alert_management.yml
@@ -0,0 +1,5 @@
+---
+title: Replace-GIDeprecatedDropdown-in-app/assets/javascripts/alert_management
+merge_request: 41409
+author: nuwe1
+type: other
diff --git a/changelogs/unreleased/Replace-GlDeprecatedDropdown-with-GlDropdown-in-app-assets-javascripts-ci.yml b/changelogs/unreleased/Replace-GlDeprecatedDropdown-with-GlDropdown-in-app-assets-javascripts-ci.yml
new file mode 100644
index 00000000000..97a63301c56
--- /dev/null
+++ b/changelogs/unreleased/Replace-GlDeprecatedDropdown-with-GlDropdown-in-app-assets-javascripts-ci.yml
@@ -0,0 +1,5 @@
+---
+title: Replace-GlDeprecatedDropdown-with-GlDropdown-in-app/assets/javascripts/ci_variable_list
+merge_request: 41413
+author: nuwe1
+type: other
diff --git a/changelogs/unreleased/Replace-GlDeprecatedDropdown-with-GlDropdown-in-app-assets-javascripts-cl.yml b/changelogs/unreleased/Replace-GlDeprecatedDropdown-with-GlDropdown-in-app-assets-javascripts-cl.yml
new file mode 100644
index 00000000000..f3f2cb3ae58
--- /dev/null
+++ b/changelogs/unreleased/Replace-GlDeprecatedDropdown-with-GlDropdown-in-app-assets-javascripts-cl.yml
@@ -0,0 +1,5 @@
+---
+title: Replace deprecated cluster dropdowns with updated dropdowns
+merge_request: 41414
+author: nuwe1
+type: other
diff --git a/changelogs/unreleased/Replace-GlDeprecatedDropdown-with-GlDropdown-in-app-assets-javascripts-co.yml b/changelogs/unreleased/Replace-GlDeprecatedDropdown-with-GlDropdown-in-app-assets-javascripts-co.yml
new file mode 100644
index 00000000000..6babaa9a740
--- /dev/null
+++ b/changelogs/unreleased/Replace-GlDeprecatedDropdown-with-GlDropdown-in-app-assets-javascripts-co.yml
@@ -0,0 +1,5 @@
+---
+title: Replace-GlDeprecatedDropdown-with-GlDropdown-in-app/assets/javascripts/confidential_merge_request/components/dropdown.vue
+merge_request: 41416
+author: nuwe1
+type: other
diff --git a/changelogs/unreleased/Replace-GlDeprecatedDropdown-with-GlDropdown-in-app-assets-javascripts-lo.yml b/changelogs/unreleased/Replace-GlDeprecatedDropdown-with-GlDropdown-in-app-assets-javascripts-lo.yml
new file mode 100644
index 00000000000..ccac03b006f
--- /dev/null
+++ b/changelogs/unreleased/Replace-GlDeprecatedDropdown-with-GlDropdown-in-app-assets-javascripts-lo.yml
@@ -0,0 +1,5 @@
+---
+title: Replace-GlDeprecatedDropdown-with-GlDropdown-in-app/assets/javascripts/logs
+merge_request: 41421
+author: nuwe1
+type: other
diff --git a/changelogs/unreleased/Replace-GlDeprecatedDropdown-with-GlDropdown-in-app-assets-javascripts-pa.yml b/changelogs/unreleased/Replace-GlDeprecatedDropdown-with-GlDropdown-in-app-assets-javascripts-pa.yml
new file mode 100644
index 00000000000..8638d578605
--- /dev/null
+++ b/changelogs/unreleased/Replace-GlDeprecatedDropdown-with-GlDropdown-in-app-assets-javascripts-pa.yml
@@ -0,0 +1,5 @@
+---
+title: Replace-GlDeprecatedDropdown-with-GlDropdown-in-app/assets/javascripts/pages/projects/graphs/components/code_coverage.vue
+merge_request: 41423
+author: nuwe1
+type: other
diff --git a/changelogs/unreleased/Replace-GlDeprecatedDropdown-with-GlDropdown-in-app-assets-javascripts-pi.yml b/changelogs/unreleased/Replace-GlDeprecatedDropdown-with-GlDropdown-in-app-assets-javascripts-pi.yml
new file mode 100644
index 00000000000..21834cbdf35
--- /dev/null
+++ b/changelogs/unreleased/Replace-GlDeprecatedDropdown-with-GlDropdown-in-app-assets-javascripts-pi.yml
@@ -0,0 +1,5 @@
+---
+title: Replace-GlDeprecatedDropdown-with-GlDropdown-in-app/assets/javascripts/pipelines/components/pipelines_list/tokens/pipeline_trigger_author_token.vue
+merge_request: 41424
+author: nuwe1
+type: other
diff --git a/changelogs/unreleased/Replace-GlDeprecatedDropdown-with-GlDropdown-in-app-assets-javascripts-re.yml b/changelogs/unreleased/Replace-GlDeprecatedDropdown-with-GlDropdown-in-app-assets-javascripts-re.yml
new file mode 100644
index 00000000000..3c7fa2f2e5f
--- /dev/null
+++ b/changelogs/unreleased/Replace-GlDeprecatedDropdown-with-GlDropdown-in-app-assets-javascripts-re.yml
@@ -0,0 +1,5 @@
+---
+title: Replace `GlDeprecatedDropdown` with `GlDropdown` in `app/assets/javascripts/repository/components/breadcrumbs.vue`
+merge_request: 41427
+author: nuwe1
+type: other
diff --git a/changelogs/unreleased/Replace-GlDeprecatedDropdown-with-GlDropdown-in-app-assets-javascripts-vu.yml b/changelogs/unreleased/Replace-GlDeprecatedDropdown-with-GlDropdown-in-app-assets-javascripts-vu.yml
new file mode 100644
index 00000000000..e2ba6e3c553
--- /dev/null
+++ b/changelogs/unreleased/Replace-GlDeprecatedDropdown-with-GlDropdown-in-app-assets-javascripts-vu.yml
@@ -0,0 +1,5 @@
+---
+title: Replace `GlDeprecatedDropdown` with `GlDropdown` in app/assets/javascripts/vue_shared/components/split_button.vue
+merge_request: 41433
+author: nuwe1
+type: other
diff --git a/changelogs/unreleased/Replace-GlDeprecatedDropdown-with-GlDropdown-in-ee-app-assets-javascripts.yml b/changelogs/unreleased/Replace-GlDeprecatedDropdown-with-GlDropdown-in-ee-app-assets-javascripts.yml
new file mode 100644
index 00000000000..092f8e82580
--- /dev/null
+++ b/changelogs/unreleased/Replace-GlDeprecatedDropdown-with-GlDropdown-in-ee-app-assets-javascripts.yml
@@ -0,0 +1,5 @@
+---
+title: Replace-GlDeprecatedDropdown-with-GlDropdown-in-ee/app/assets/javascripts/geo_node_form-and-ee/app/assets/javascripts/geo_replicable
+merge_request: 41438
+author: nuwe1
+type: other
diff --git a/changelogs/unreleased/Replace-GlDeprecatedDropdown-with-GlDropdown-timezone-dropdown.yml b/changelogs/unreleased/Replace-GlDeprecatedDropdown-with-GlDropdown-timezone-dropdown.yml
new file mode 100644
index 00000000000..e29de3daa8d
--- /dev/null
+++ b/changelogs/unreleased/Replace-GlDeprecatedDropdown-with-GlDropdown-timezone-dropdown.yml
@@ -0,0 +1,5 @@
+---
+title: Replace GlDeprecatedDropdown with GlDropDown in timezone-dropdown.vue
+merge_request: 41434
+author: nuwe1
+type: other
diff --git a/changelogs/unreleased/Replace-calendar-icon-tooltip-sidebar-ab.yml b/changelogs/unreleased/Replace-calendar-icon-tooltip-sidebar-ab.yml
new file mode 100644
index 00000000000..994652aacb7
--- /dev/null
+++ b/changelogs/unreleased/Replace-calendar-icon-tooltip-sidebar-ab.yml
@@ -0,0 +1,5 @@
+---
+title: Replacing vue shared tooltip on calendar icon
+merge_request: 45059
+author:
+type: other
diff --git a/changelogs/unreleased/ab-reindexing-actiontracking.yml b/changelogs/unreleased/ab-reindexing-actiontracking.yml
new file mode 100644
index 00000000000..210e6d984ed
--- /dev/null
+++ b/changelogs/unreleased/ab-reindexing-actiontracking.yml
@@ -0,0 +1,5 @@
+---
+title: Track statistics for index rebuilds
+merge_request: 43156
+author:
+type: other
diff --git a/changelogs/unreleased/ab-reindexing-index-model.yml b/changelogs/unreleased/ab-reindexing-index-model.yml
new file mode 100644
index 00000000000..abff32e0004
--- /dev/null
+++ b/changelogs/unreleased/ab-reindexing-index-model.yml
@@ -0,0 +1,5 @@
+---
+title: 'Add database view for postgres indexes'
+merge_request: 42967
+author:
+type: other
diff --git a/changelogs/unreleased/ab-reindexing-limit-schema.yml b/changelogs/unreleased/ab-reindexing-limit-schema.yml
new file mode 100644
index 00000000000..c7ac33f6dc7
--- /dev/null
+++ b/changelogs/unreleased/ab-reindexing-limit-schema.yml
@@ -0,0 +1,5 @@
+---
+title: Limit postgres_indexes to owned schemas
+merge_request: 43834
+author:
+type: other
diff --git a/changelogs/unreleased/add-abuse-notification-email.yml b/changelogs/unreleased/add-abuse-notification-email.yml
new file mode 100644
index 00000000000..1d8312d9cf7
--- /dev/null
+++ b/changelogs/unreleased/add-abuse-notification-email.yml
@@ -0,0 +1,5 @@
+---
+title: Set abuse_notification_email instead of admin_notification_email.
+merge_request: 41319
+author: Hiromi Nozawa
+type: deprecated
diff --git a/changelogs/unreleased/add-ci-deleted-objects-table.yml b/changelogs/unreleased/add-ci-deleted-objects-table.yml
new file mode 100644
index 00000000000..7576fe52d70
--- /dev/null
+++ b/changelogs/unreleased/add-ci-deleted-objects-table.yml
@@ -0,0 +1,5 @@
+---
+title: Parallelize removal of expired artifacts
+merge_request: 39464
+author:
+type: changed
diff --git a/changelogs/unreleased/add-dast-site-validation-worker-245209.yml b/changelogs/unreleased/add-dast-site-validation-worker-245209.yml
new file mode 100644
index 00000000000..ba38313f47f
--- /dev/null
+++ b/changelogs/unreleased/add-dast-site-validation-worker-245209.yml
@@ -0,0 +1,5 @@
+---
+title: Add state field to DastSiteValidation
+merge_request: 42198
+author:
+type: added
diff --git a/changelogs/unreleased/add-golang-to-packages.yml b/changelogs/unreleased/add-golang-to-packages.yml
new file mode 100644
index 00000000000..601c7996206
--- /dev/null
+++ b/changelogs/unreleased/add-golang-to-packages.yml
@@ -0,0 +1,5 @@
+---
+title: Add Go(lang) to Packages
+merge_request: 41712
+author: Ethan Reesor (@firelizzard)
+type: added
diff --git a/changelogs/unreleased/add-notification-setting-for-merge-request-reviewers.yml b/changelogs/unreleased/add-notification-setting-for-merge-request-reviewers.yml
new file mode 100644
index 00000000000..6163f5e5f03
--- /dev/null
+++ b/changelogs/unreleased/add-notification-setting-for-merge-request-reviewers.yml
@@ -0,0 +1,5 @@
+---
+title: Add notification setting for merge request reviewers
+merge_request: 41851
+author:
+type: added
diff --git a/changelogs/unreleased/add-sorting-to-releases.yml b/changelogs/unreleased/add-sorting-to-releases.yml
new file mode 100644
index 00000000000..e2ce398856f
--- /dev/null
+++ b/changelogs/unreleased/add-sorting-to-releases.yml
@@ -0,0 +1,5 @@
+---
+title: Add sorting parameters to Releases API
+merge_request: 44118
+author:
+type: added
diff --git a/changelogs/unreleased/add-sse-config-file-3.yml b/changelogs/unreleased/add-sse-config-file-3.yml
new file mode 100644
index 00000000000..b942b1224f2
--- /dev/null
+++ b/changelogs/unreleased/add-sse-config-file-3.yml
@@ -0,0 +1,6 @@
+---
+title: Introduce '.gitlab/static-site-editor.yml' config file, with support for 'static_site_generator'
+ entry.
+merge_request: 41957
+author:
+type: added
diff --git a/changelogs/unreleased/add-vuex-store-for-milestone-combobox.yml b/changelogs/unreleased/add-vuex-store-for-milestone-combobox.yml
new file mode 100644
index 00000000000..88610c6ec29
--- /dev/null
+++ b/changelogs/unreleased/add-vuex-store-for-milestone-combobox.yml
@@ -0,0 +1,5 @@
+---
+title: Add vuex stores for milestone comboxbox
+merge_request: 45287
+author:
+type: added
diff --git a/changelogs/unreleased/add_index_for_sha_to_deployments.yml b/changelogs/unreleased/add_index_for_sha_to_deployments.yml
new file mode 100644
index 00000000000..612665427fd
--- /dev/null
+++ b/changelogs/unreleased/add_index_for_sha_to_deployments.yml
@@ -0,0 +1,5 @@
+---
+title: Add index for project_id and sha to deployments table
+merge_request: 43836
+author:
+type: performance
diff --git a/changelogs/unreleased/add_options_to_dast_scanner_profile_254626.yml b/changelogs/unreleased/add_options_to_dast_scanner_profile_254626.yml
new file mode 100644
index 00000000000..207fe49525a
--- /dev/null
+++ b/changelogs/unreleased/add_options_to_dast_scanner_profile_254626.yml
@@ -0,0 +1,6 @@
+---
+title: Add on-demand DAST scan options (scanType, showDebugMessages, useAjaxSpider)
+ ajax spider and set the scan type
+merge_request: 43240
+author:
+type: added
diff --git a/changelogs/unreleased/adding-hcl.yml b/changelogs/unreleased/adding-hcl.yml
new file mode 100644
index 00000000000..4b0d750474f
--- /dev/null
+++ b/changelogs/unreleased/adding-hcl.yml
@@ -0,0 +1,5 @@
+---
+title: IDE editor - Adding syntax highlighting for terraform / hcl
+merge_request: 44056
+author:
+type: added
diff --git a/changelogs/unreleased/ajk-219380-fix-design-type-formatting-in-activity-streams.yml b/changelogs/unreleased/ajk-219380-fix-design-type-formatting-in-activity-streams.yml
new file mode 100644
index 00000000000..d12834e93b1
--- /dev/null
+++ b/changelogs/unreleased/ajk-219380-fix-design-type-formatting-in-activity-streams.yml
@@ -0,0 +1,5 @@
+---
+title: Customize value of note_target_type for designs
+merge_request: 43727
+author:
+type: fixed
diff --git a/changelogs/unreleased/ajk-graphql-group-mrs.yml b/changelogs/unreleased/ajk-graphql-group-mrs.yml
new file mode 100644
index 00000000000..b20313752ae
--- /dev/null
+++ b/changelogs/unreleased/ajk-graphql-group-mrs.yml
@@ -0,0 +1,5 @@
+---
+title: Enable querying for merge requests within a group
+merge_request: 43863
+author:
+type: added
diff --git a/changelogs/unreleased/ajk-graphql-milestone-filters.yml b/changelogs/unreleased/ajk-graphql-milestone-filters.yml
new file mode 100644
index 00000000000..872cc180fd5
--- /dev/null
+++ b/changelogs/unreleased/ajk-graphql-milestone-filters.yml
@@ -0,0 +1,5 @@
+---
+title: Add filters on Milestone title in the GraphQL API
+merge_request: 44208
+author:
+type: changed
diff --git a/changelogs/unreleased/ajk-issue-reposition-take.yml b/changelogs/unreleased/ajk-issue-reposition-take.yml
new file mode 100644
index 00000000000..d3e00184cfb
--- /dev/null
+++ b/changelogs/unreleased/ajk-issue-reposition-take.yml
@@ -0,0 +1,5 @@
+---
+title: Performance fix for issue placement
+merge_request: 43315
+author:
+type: performance
diff --git a/changelogs/unreleased/ajk-remove-design_management_reference_filter_gfm_pipeline-ff.yml b/changelogs/unreleased/ajk-remove-design_management_reference_filter_gfm_pipeline-ff.yml
new file mode 100644
index 00000000000..af5900d538c
--- /dev/null
+++ b/changelogs/unreleased/ajk-remove-design_management_reference_filter_gfm_pipeline-ff.yml
@@ -0,0 +1,5 @@
+---
+title: Enable design management reference filter
+merge_request: 43731
+author:
+type: added
diff --git a/changelogs/unreleased/ajk-remove-graphql_lookahead_support.yml b/changelogs/unreleased/ajk-remove-graphql_lookahead_support.yml
new file mode 100644
index 00000000000..f4140b1d9a3
--- /dev/null
+++ b/changelogs/unreleased/ajk-remove-graphql_lookahead_support.yml
@@ -0,0 +1,5 @@
+---
+title: Remove graphql_lookahead_support feature flag
+merge_request: 43438
+author:
+type: added
diff --git a/changelogs/unreleased/ajk-remove-wiki_events_on_git_push-ff.yml b/changelogs/unreleased/ajk-remove-wiki_events_on_git_push-ff.yml
new file mode 100644
index 00000000000..37342ac2146
--- /dev/null
+++ b/changelogs/unreleased/ajk-remove-wiki_events_on_git_push-ff.yml
@@ -0,0 +1,5 @@
+---
+title: Enable wiki events on git push
+merge_request: 43738
+author:
+type: added
diff --git a/changelogs/unreleased/alipniagov-update-wh-to-8-49.yml b/changelogs/unreleased/alipniagov-update-wh-to-8-49.yml
new file mode 100644
index 00000000000..8eff6983c67
--- /dev/null
+++ b/changelogs/unreleased/alipniagov-update-wh-to-8-49.yml
@@ -0,0 +1,5 @@
+---
+title: Update GitLab Workhorse to v8.49.0
+merge_request: 43999
+author:
+type: other
diff --git a/changelogs/unreleased/alipniagov-update-wh-version.yml b/changelogs/unreleased/alipniagov-update-wh-version.yml
new file mode 100644
index 00000000000..a5e7d55af7a
--- /dev/null
+++ b/changelogs/unreleased/alipniagov-update-wh-version.yml
@@ -0,0 +1,5 @@
+---
+title: Update GitLab Workhorse to v8.48.0
+merge_request: 43586
+author:
+type: other
diff --git a/changelogs/unreleased/alipniagov-update-workhorse-to-8-51.yml b/changelogs/unreleased/alipniagov-update-workhorse-to-8-51.yml
new file mode 100644
index 00000000000..22c00c97892
--- /dev/null
+++ b/changelogs/unreleased/alipniagov-update-workhorse-to-8-51.yml
@@ -0,0 +1,5 @@
+---
+title: Update GitLab Workhorse to v8.51.0
+merge_request: 45256
+author:
+type: other
diff --git a/changelogs/unreleased/always-show-clear-cluster-cache-button.yml b/changelogs/unreleased/always-show-clear-cluster-cache-button.yml
new file mode 100644
index 00000000000..744e226e50b
--- /dev/null
+++ b/changelogs/unreleased/always-show-clear-cluster-cache-button.yml
@@ -0,0 +1,5 @@
+---
+title: Always show the "Clear cluster cache" button among the advanced Kubernetes cluster configuration options
+merge_request: 43619
+author:
+type: changed
diff --git a/changelogs/unreleased/api-expose-gpg.yml b/changelogs/unreleased/api-expose-gpg.yml
new file mode 100644
index 00000000000..0508b95a524
--- /dev/null
+++ b/changelogs/unreleased/api-expose-gpg.yml
@@ -0,0 +1,5 @@
+---
+title: Allow a users public GPG Keys to be API accessible
+merge_request: 43332
+author:
+type: added
diff --git a/changelogs/unreleased/automatic_move_storage.yml b/changelogs/unreleased/automatic_move_storage.yml
new file mode 100644
index 00000000000..7909d587601
--- /dev/null
+++ b/changelogs/unreleased/automatic_move_storage.yml
@@ -0,0 +1,5 @@
+---
+title: Allow automatically selecting repository storage on move
+merge_request: 45338
+author:
+type: changed
diff --git a/changelogs/unreleased/batch-load-user-notes-count.yml b/changelogs/unreleased/batch-load-user-notes-count.yml
new file mode 100644
index 00000000000..66f1222c8ea
--- /dev/null
+++ b/changelogs/unreleased/batch-load-user-notes-count.yml
@@ -0,0 +1,5 @@
+---
+title: Preload `user_notes_count` in MergeRequest GraphQL API
+merge_request: 44894
+author:
+type: performance
diff --git a/changelogs/unreleased/bjk-rack_metric_methods.yml b/changelogs/unreleased/bjk-rack_metric_methods.yml
new file mode 100644
index 00000000000..cd86dfd5c69
--- /dev/null
+++ b/changelogs/unreleased/bjk-rack_metric_methods.yml
@@ -0,0 +1,5 @@
+---
+title: Cleanup request http method/code metrics
+merge_request: 42618
+author:
+type: performance
diff --git a/changelogs/unreleased/bugfix_coverage_fuzzing_linux_arch.yml b/changelogs/unreleased/bugfix_coverage_fuzzing_linux_arch.yml
new file mode 100644
index 00000000000..69f97bc9e08
--- /dev/null
+++ b/changelogs/unreleased/bugfix_coverage_fuzzing_linux_arch.yml
@@ -0,0 +1,5 @@
+---
+title: Remove linux arch only rule for coverage fuzzing
+merge_request: 42316
+author:
+type: fixed
diff --git a/changelogs/unreleased/bump-deploy-image-for-fixing-scale-bug.yml b/changelogs/unreleased/bump-deploy-image-for-fixing-scale-bug.yml
new file mode 100644
index 00000000000..a08824cb687
--- /dev/null
+++ b/changelogs/unreleased/bump-deploy-image-for-fixing-scale-bug.yml
@@ -0,0 +1,5 @@
+---
+title: Fix Auto Deploy scale subcommand unintentionally recreates legacy PostgreSQL
+merge_request: 44535
+author:
+type: fixed
diff --git a/changelogs/unreleased/bvl-remove-ff-commits-count.yml b/changelogs/unreleased/bvl-remove-ff-commits-count.yml
new file mode 100644
index 00000000000..4077a8bb1c1
--- /dev/null
+++ b/changelogs/unreleased/bvl-remove-ff-commits-count.yml
@@ -0,0 +1,5 @@
+---
+title: Remove the commit count from the commits API
+merge_request: 44934
+author:
+type: performance
diff --git a/changelogs/unreleased/bw-delete-jira-tracker-data-jobs.yml b/changelogs/unreleased/bw-delete-jira-tracker-data-jobs.yml
new file mode 100644
index 00000000000..a7ce3533df2
--- /dev/null
+++ b/changelogs/unreleased/bw-delete-jira-tracker-data-jobs.yml
@@ -0,0 +1,5 @@
+---
+title: Delete any outstanding BackfillJiraTrackerDeploymentType
+merge_request: 45219
+author:
+type: fixed
diff --git a/changelogs/unreleased/bw_update_global_id_checks.yml b/changelogs/unreleased/bw_update_global_id_checks.yml
new file mode 100644
index 00000000000..2c3d9e81755
--- /dev/null
+++ b/changelogs/unreleased/bw_update_global_id_checks.yml
@@ -0,0 +1,5 @@
+---
+title: Updated GraphQL mutation input ids to be more type specific
+merge_request: 44073
+author:
+type: changed
diff --git a/changelogs/unreleased/change-transfer-update-create-services.yml b/changelogs/unreleased/change-transfer-update-create-services.yml
new file mode 100644
index 00000000000..a35016d229c
--- /dev/null
+++ b/changelogs/unreleased/change-transfer-update-create-services.yml
@@ -0,0 +1,5 @@
+---
+title: Change transfer, update and create services for groups and projects to take in consideration shared runners settings
+merge_request: 36080
+author: Arthur de Lapertosa Lisboa
+type: added
diff --git a/changelogs/unreleased/cngo-clear-label-select-on-enter.yml b/changelogs/unreleased/cngo-clear-label-select-on-enter.yml
new file mode 100644
index 00000000000..afcaca6a876
--- /dev/null
+++ b/changelogs/unreleased/cngo-clear-label-select-on-enter.yml
@@ -0,0 +1,5 @@
+---
+title: Reset labels select search text on Enter
+merge_request: 43285
+author:
+type: fixed
diff --git a/changelogs/unreleased/cngo-fix-scoped-label-markdown-padding.yml b/changelogs/unreleased/cngo-fix-scoped-label-markdown-padding.yml
new file mode 100644
index 00000000000..0aa6a468e3f
--- /dev/null
+++ b/changelogs/unreleased/cngo-fix-scoped-label-markdown-padding.yml
@@ -0,0 +1,5 @@
+---
+title: Fix scoped label markdown padding
+merge_request: 45153
+author:
+type: fixed
diff --git a/changelogs/unreleased/copy-project-homepage-default-view-for-anonoymous-users.yml b/changelogs/unreleased/copy-project-homepage-default-view-for-anonoymous-users.yml
new file mode 100644
index 00000000000..cc4bba49c42
--- /dev/null
+++ b/changelogs/unreleased/copy-project-homepage-default-view-for-anonoymous-users.yml
@@ -0,0 +1,5 @@
+---
+title: Copy project homepage default view for anonymous users
+merge_request: 44606
+author: George Tsiolis
+type: changed
diff --git a/changelogs/unreleased/cycle-analytics-to-value-stream-analytics-in-university.yml b/changelogs/unreleased/cycle-analytics-to-value-stream-analytics-in-university.yml
new file mode 100644
index 00000000000..a090ac909ef
--- /dev/null
+++ b/changelogs/unreleased/cycle-analytics-to-value-stream-analytics-in-university.yml
@@ -0,0 +1,5 @@
+---
+title: Update Cycle Analytics with Value Stream Analytics in University
+merge_request: 44244
+author: Takuya Noguchi
+type: other
diff --git a/changelogs/unreleased/dblessing-auth-events-usage-ping.yml b/changelogs/unreleased/dblessing-auth-events-usage-ping.yml
new file mode 100644
index 00000000000..26117006f1c
--- /dev/null
+++ b/changelogs/unreleased/dblessing-auth-events-usage-ping.yml
@@ -0,0 +1,5 @@
+---
+title: Report auth events in manage stage usage ping
+merge_request: 39747
+author:
+type: added
diff --git a/changelogs/unreleased/dblessing-ip-address-validator.yml b/changelogs/unreleased/dblessing-ip-address-validator.yml
new file mode 100644
index 00000000000..cd20210d950
--- /dev/null
+++ b/changelogs/unreleased/dblessing-ip-address-validator.yml
@@ -0,0 +1,5 @@
+---
+title: Add validator for IP address/inet columns
+merge_request: 42893
+author:
+type: added
diff --git a/changelogs/unreleased/dblessing_user_created_by_id.yml b/changelogs/unreleased/dblessing_user_created_by_id.yml
new file mode 100644
index 00000000000..686b1834136
--- /dev/null
+++ b/changelogs/unreleased/dblessing_user_created_by_id.yml
@@ -0,0 +1,5 @@
+---
+title: Always set created_by_id when creating a user
+merge_request: 43342
+author:
+type: changed
diff --git a/changelogs/unreleased/debian_packages.yml b/changelogs/unreleased/debian_packages.yml
new file mode 100644
index 00000000000..2504018a6f9
--- /dev/null
+++ b/changelogs/unreleased/debian_packages.yml
@@ -0,0 +1,5 @@
+---
+title: Add Debian API skeleton
+merge_request: 42670
+author: Mathieu Parent
+type: added
diff --git a/changelogs/unreleased/debian_regexp.yml b/changelogs/unreleased/debian_regexp.yml
new file mode 100644
index 00000000000..fe8e06c9291
--- /dev/null
+++ b/changelogs/unreleased/debian_regexp.yml
@@ -0,0 +1,5 @@
+---
+title: Add Debian regexps
+merge_request: 43259
+author: Mathieu Parent
+type: added
diff --git a/changelogs/unreleased/design-tracking-create-update.yml b/changelogs/unreleased/design-tracking-create-update.yml
new file mode 100644
index 00000000000..e55684ebf64
--- /dev/null
+++ b/changelogs/unreleased/design-tracking-create-update.yml
@@ -0,0 +1,5 @@
+---
+title: Add product analytics for design created and modified events
+merge_request: 44129
+author:
+type: added
diff --git a/changelogs/unreleased/disable-shared-runners-ui.yml b/changelogs/unreleased/disable-shared-runners-ui.yml
new file mode 100644
index 00000000000..a36213f1448
--- /dev/null
+++ b/changelogs/unreleased/disable-shared-runners-ui.yml
@@ -0,0 +1,5 @@
+---
+title: UI to disable shared runners by group
+merge_request: 39249
+author:
+type: added
diff --git a/changelogs/unreleased/disabled-scoped-issue-board-assigns-labels.yml b/changelogs/unreleased/disabled-scoped-issue-board-assigns-labels.yml
new file mode 100644
index 00000000000..19c4208ad34
--- /dev/null
+++ b/changelogs/unreleased/disabled-scoped-issue-board-assigns-labels.yml
@@ -0,0 +1,5 @@
+---
+title: Fix the ability to assign labels based on license feature availability.
+merge_request: 44171
+author:
+type: fixed
diff --git a/changelogs/unreleased/display-contributor-and-author-badges-on-notes.yml b/changelogs/unreleased/display-contributor-and-author-badges-on-notes.yml
new file mode 100644
index 00000000000..163053c1b70
--- /dev/null
+++ b/changelogs/unreleased/display-contributor-and-author-badges-on-notes.yml
@@ -0,0 +1,5 @@
+---
+title: Display Contributor badges on notes
+merge_request: 42576
+author: Mycroft Kang @TaehyeokKang
+type: added
diff --git a/changelogs/unreleased/docs-test-hardcoded-docs-links.yml b/changelogs/unreleased/docs-test-hardcoded-docs-links.yml
new file mode 100644
index 00000000000..14ab10fd0f3
--- /dev/null
+++ b/changelogs/unreleased/docs-test-hardcoded-docs-links.yml
@@ -0,0 +1,5 @@
+---
+title: Update doc links in app
+merge_request: 44134
+author:
+type: other
diff --git a/changelogs/unreleased/drop-an-element.yml b/changelogs/unreleased/drop-an-element.yml
new file mode 100644
index 00000000000..958d7a47678
--- /dev/null
+++ b/changelogs/unreleased/drop-an-element.yml
@@ -0,0 +1,5 @@
+---
+title: Remove an unnecessary element from every page
+merge_request: 42769
+author: Takuya Noguchi
+type: other
diff --git a/changelogs/unreleased/drop-instance-statistics-visibility-private-column.yml b/changelogs/unreleased/drop-instance-statistics-visibility-private-column.yml
new file mode 100644
index 00000000000..10885375093
--- /dev/null
+++ b/changelogs/unreleased/drop-instance-statistics-visibility-private-column.yml
@@ -0,0 +1,5 @@
+---
+title: Drop column instance_statistics_visibility_private
+merge_request: 42969
+author:
+type: deprecated
diff --git a/changelogs/unreleased/dz-scope-profile-routes.yml b/changelogs/unreleased/dz-scope-profile-routes.yml
new file mode 100644
index 00000000000..6557ce8da95
--- /dev/null
+++ b/changelogs/unreleased/dz-scope-profile-routes.yml
@@ -0,0 +1,5 @@
+---
+title: Copy profile route under - scope
+merge_request: 45045
+author:
+type: other
diff --git a/changelogs/unreleased/eb-limit-test-cases-parsed.yml b/changelogs/unreleased/eb-limit-test-cases-parsed.yml
new file mode 100644
index 00000000000..59a9e611d4b
--- /dev/null
+++ b/changelogs/unreleased/eb-limit-test-cases-parsed.yml
@@ -0,0 +1,5 @@
+---
+title: Add limit to number of test cases parsed by JUnit parser
+merge_request: 44615
+author:
+type: changed
diff --git a/changelogs/unreleased/eb-unit-tests-parsed-usage-ping.yml b/changelogs/unreleased/eb-unit-tests-parsed-usage-ping.yml
new file mode 100644
index 00000000000..0ac94f0cafb
--- /dev/null
+++ b/changelogs/unreleased/eb-unit-tests-parsed-usage-ping.yml
@@ -0,0 +1,5 @@
+---
+title: Track unique number of test cases parsed
+merge_request: 41918
+author:
+type: added
diff --git a/changelogs/unreleased/enable-track-unique-visits-ff-by-default.yml b/changelogs/unreleased/enable-track-unique-visits-ff-by-default.yml
new file mode 100644
index 00000000000..0c321e6b58b
--- /dev/null
+++ b/changelogs/unreleased/enable-track-unique-visits-ff-by-default.yml
@@ -0,0 +1,5 @@
+---
+title: Enable track_unique_visits feature flag by default
+merge_request: 43989
+author:
+type: other
diff --git a/changelogs/unreleased/eread-migrate-badge-list-row-buttons-to-new-buttons.yml b/changelogs/unreleased/eread-migrate-badge-list-row-buttons-to-new-buttons.yml
new file mode 100644
index 00000000000..82b5eff2ec5
--- /dev/null
+++ b/changelogs/unreleased/eread-migrate-badge-list-row-buttons-to-new-buttons.yml
@@ -0,0 +1,5 @@
+---
+title: Migrate badge list row buttons to new buttons
+merge_request: 43072
+author:
+type: other
diff --git a/changelogs/unreleased/eread-migrate-tooltip-time-track-collapsed.yml b/changelogs/unreleased/eread-migrate-tooltip-time-track-collapsed.yml
new file mode 100644
index 00000000000..e519f650ef3
--- /dev/null
+++ b/changelogs/unreleased/eread-migrate-tooltip-time-track-collapsed.yml
@@ -0,0 +1,5 @@
+---
+title: Migrate collapsed time tracking tooltip
+merge_request: 44874
+author:
+type: other
diff --git a/changelogs/unreleased/expose-clusters-namespace-per-environment-flag.yml b/changelogs/unreleased/expose-clusters-namespace-per-environment-flag.yml
new file mode 100644
index 00000000000..99c630b5904
--- /dev/null
+++ b/changelogs/unreleased/expose-clusters-namespace-per-environment-flag.yml
@@ -0,0 +1,6 @@
+---
+title: Expose the option to use namespace-per-project instead of namespace-per-environment
+ for Kubernetes clusters
+merge_request: 42309
+author:
+type: changed
diff --git a/changelogs/unreleased/expose-created-at.yml b/changelogs/unreleased/expose-created-at.yml
new file mode 100644
index 00000000000..b87acba405c
--- /dev/null
+++ b/changelogs/unreleased/expose-created-at.yml
@@ -0,0 +1,5 @@
+---
+title: Expose `created_at` in Group and Project members API response
+merge_request: 45156
+author: Rajendra Kadam
+type: added
diff --git a/changelogs/unreleased/expose-junit-spec-file-path.yml b/changelogs/unreleased/expose-junit-spec-file-path.yml
new file mode 100644
index 00000000000..de15bae28b9
--- /dev/null
+++ b/changelogs/unreleased/expose-junit-spec-file-path.yml
@@ -0,0 +1,5 @@
+---
+title: Expose file path from XML Test Report artifact
+merge_request: 43594
+author:
+type: changed
diff --git a/changelogs/unreleased/feat-jcunha-adds-terraform-ci-latest-template.yml b/changelogs/unreleased/feat-jcunha-adds-terraform-ci-latest-template.yml
new file mode 100644
index 00000000000..563b7d65650
--- /dev/null
+++ b/changelogs/unreleased/feat-jcunha-adds-terraform-ci-latest-template.yml
@@ -0,0 +1,6 @@
+---
+title: Adds a Terraform.latest.gitlab-ci.yml to support quick development of Terraform
+ related features
+merge_request: 43802
+author:
+type: added
diff --git a/changelogs/unreleased/feature-flag-limits-ux.yml b/changelogs/unreleased/feature-flag-limits-ux.yml
new file mode 100644
index 00000000000..7b1fa628ea9
--- /dev/null
+++ b/changelogs/unreleased/feature-flag-limits-ux.yml
@@ -0,0 +1,5 @@
+---
+title: Feature Flags limits UX and documentation
+merge_request: 44089
+author:
+type: added
diff --git a/changelogs/unreleased/feature-flags-flexible-rollout-ux.yml b/changelogs/unreleased/feature-flags-flexible-rollout-ux.yml
new file mode 100644
index 00000000000..0f92f7f3d3c
--- /dev/null
+++ b/changelogs/unreleased/feature-flags-flexible-rollout-ux.yml
@@ -0,0 +1,5 @@
+---
+title: Adds flexible rollout strategy UX and documentation
+merge_request: 43611
+author:
+type: added
diff --git a/changelogs/unreleased/feature-gb-validate-build-traces.yml b/changelogs/unreleased/feature-gb-validate-build-traces.yml
new file mode 100644
index 00000000000..7d7e49d20d4
--- /dev/null
+++ b/changelogs/unreleased/feature-gb-validate-build-traces.yml
@@ -0,0 +1,5 @@
+---
+title: Validate build traces using CRC32 checksums
+merge_request: 42829
+author:
+type: added
diff --git a/changelogs/unreleased/fix-backward-keyset-pagination-for-merged-at.yml b/changelogs/unreleased/fix-backward-keyset-pagination-for-merged-at.yml
new file mode 100644
index 00000000000..a1657e81517
--- /dev/null
+++ b/changelogs/unreleased/fix-backward-keyset-pagination-for-merged-at.yml
@@ -0,0 +1,5 @@
+---
+title: Fix GraphQL backward pagination when merge requests are ordered by merged_at
+merge_request: 43701
+author:
+type: fixed
diff --git a/changelogs/unreleased/fix-design-zoom.yml b/changelogs/unreleased/fix-design-zoom.yml
new file mode 100644
index 00000000000..e73ec45491c
--- /dev/null
+++ b/changelogs/unreleased/fix-design-zoom.yml
@@ -0,0 +1,5 @@
+---
+title: Fix design scale bug when navigating to a design after zooming
+merge_request: 44262
+author:
+type: fixed
diff --git a/changelogs/unreleased/fix-encoding-for-nil-diff-files.yml b/changelogs/unreleased/fix-encoding-for-nil-diff-files.yml
new file mode 100644
index 00000000000..470cb8ff324
--- /dev/null
+++ b/changelogs/unreleased/fix-encoding-for-nil-diff-files.yml
@@ -0,0 +1,5 @@
+---
+title: Fix migrating some empty diffs
+merge_request: 42825
+author:
+type: fixed
diff --git a/changelogs/unreleased/fix-gb-fix-chunks-migration-race.yml b/changelogs/unreleased/fix-gb-fix-chunks-migration-race.yml
new file mode 100644
index 00000000000..6b796a0263f
--- /dev/null
+++ b/changelogs/unreleased/fix-gb-fix-chunks-migration-race.yml
@@ -0,0 +1,5 @@
+---
+title: Use optimistic locking to safely migrate a build trace chunk
+merge_request: 44588
+author:
+type: fixed
diff --git a/changelogs/unreleased/fix-gl-emoji-race-condition.yml b/changelogs/unreleased/fix-gl-emoji-race-condition.yml
new file mode 100644
index 00000000000..6df766b5afc
--- /dev/null
+++ b/changelogs/unreleased/fix-gl-emoji-race-condition.yml
@@ -0,0 +1,5 @@
+---
+title: Fix emoji rendering in certain edge cases
+merge_request: 44542
+author:
+type: fixed
diff --git a/changelogs/unreleased/fix-pipeline-stage-action-alignment.yml b/changelogs/unreleased/fix-pipeline-stage-action-alignment.yml
new file mode 100644
index 00000000000..ad0293c00aa
--- /dev/null
+++ b/changelogs/unreleased/fix-pipeline-stage-action-alignment.yml
@@ -0,0 +1,5 @@
+---
+title: Fix button placement on pipeline graph
+merge_request: 43419
+author:
+type: fixed
diff --git a/changelogs/unreleased/fix-retry-job-button-422.yml b/changelogs/unreleased/fix-retry-job-button-422.yml
new file mode 100644
index 00000000000..7415d881da3
--- /dev/null
+++ b/changelogs/unreleased/fix-retry-job-button-422.yml
@@ -0,0 +1,5 @@
+---
+title: Remove retry icon on failed job if merge pipeline
+merge_request: 42495
+author:
+type: fixed
diff --git a/changelogs/unreleased/fix-spelling-of-pypi.yml b/changelogs/unreleased/fix-spelling-of-pypi.yml
new file mode 100644
index 00000000000..3101367cbc6
--- /dev/null
+++ b/changelogs/unreleased/fix-spelling-of-pypi.yml
@@ -0,0 +1,5 @@
+---
+title: Fix spelling of PyPI
+merge_request: 44058
+author: Peter Bittner (@bittner)
+type: other
diff --git a/changelogs/unreleased/fix-theme-switcher.yml b/changelogs/unreleased/fix-theme-switcher.yml
new file mode 100644
index 00000000000..39c8dff2df9
--- /dev/null
+++ b/changelogs/unreleased/fix-theme-switcher.yml
@@ -0,0 +1,5 @@
+---
+title: Fix theme selector not working immediately for some themes
+merge_request: 43239
+author:
+type: fixed
diff --git a/changelogs/unreleased/fix-unresolved-value-error-in-instance-statistics-graphql-api.yml b/changelogs/unreleased/fix-unresolved-value-error-in-instance-statistics-graphql-api.yml
new file mode 100644
index 00000000000..2f9a417e0bc
--- /dev/null
+++ b/changelogs/unreleased/fix-unresolved-value-error-in-instance-statistics-graphql-api.yml
@@ -0,0 +1,5 @@
+---
+title: Fix instance statistics GraphQL query with identifier
+merge_request: 44475
+author:
+type: fixed
diff --git a/changelogs/unreleased/fix-wrong-scope-in-approved-by.yml b/changelogs/unreleased/fix-wrong-scope-in-approved-by.yml
new file mode 100644
index 00000000000..b2d9106737c
--- /dev/null
+++ b/changelogs/unreleased/fix-wrong-scope-in-approved-by.yml
@@ -0,0 +1,5 @@
+---
+title: Fix approvedBy filed in MR GraphQL API
+merge_request: 43705
+author:
+type: fixed
diff --git a/changelogs/unreleased/forward_deployment_enabled-api.yml b/changelogs/unreleased/forward_deployment_enabled-api.yml
new file mode 100644
index 00000000000..5da83dd8036
--- /dev/null
+++ b/changelogs/unreleased/forward_deployment_enabled-api.yml
@@ -0,0 +1,5 @@
+---
+title: Support ci_forward_deployment_enabled in edit API
+merge_request: 44510
+author:
+type: added
diff --git a/changelogs/unreleased/gaga5lala-227175-carrierwave-error-handle.yml b/changelogs/unreleased/gaga5lala-227175-carrierwave-error-handle.yml
new file mode 100644
index 00000000000..8e134642cb0
--- /dev/null
+++ b/changelogs/unreleased/gaga5lala-227175-carrierwave-error-handle.yml
@@ -0,0 +1,5 @@
+---
+title: Log CarrierWave::IntegrityError without sending exception
+merge_request: 43750
+author: gaga5lala
+type: other
diff --git a/changelogs/unreleased/generic-packages-enable-by-default.yml b/changelogs/unreleased/generic-packages-enable-by-default.yml
new file mode 100644
index 00000000000..f3c7bd5a67d
--- /dev/null
+++ b/changelogs/unreleased/generic-packages-enable-by-default.yml
@@ -0,0 +1,5 @@
+---
+title: Add support for Generic packages
+merge_request: 45102
+author:
+type: added
diff --git a/changelogs/unreleased/georgekoltsov-add-group-import-usage-ping.yml b/changelogs/unreleased/georgekoltsov-add-group-import-usage-ping.yml
new file mode 100644
index 00000000000..5aa5a587275
--- /dev/null
+++ b/changelogs/unreleased/georgekoltsov-add-group-import-usage-ping.yml
@@ -0,0 +1,5 @@
+---
+title: Add Group Import usage ping
+merge_request: 41663
+author:
+type: added
diff --git a/changelogs/unreleased/gitlab_buttons_ci_builds.yml b/changelogs/unreleased/gitlab_buttons_ci_builds.yml
new file mode 100644
index 00000000000..ce5f78e1e46
--- /dev/null
+++ b/changelogs/unreleased/gitlab_buttons_ci_builds.yml
@@ -0,0 +1,5 @@
+---
+title: Apply GitLab UI button styles to HAML buttons app/views/projects/ci/builds
+merge_request: 43728
+author: Andrei Kyrnich @kyrnich
+type: other
diff --git a/changelogs/unreleased/gitlab_buttons_projects_blob.yml b/changelogs/unreleased/gitlab_buttons_projects_blob.yml
new file mode 100644
index 00000000000..eef9af0a46b
--- /dev/null
+++ b/changelogs/unreleased/gitlab_buttons_projects_blob.yml
@@ -0,0 +1,5 @@
+---
+title: Apply GitLab UI button styles to HAML buttons app/views/projects/blob
+merge_request: 42991
+author: Andrei Kyrnich @kyrnich
+type: other
diff --git a/changelogs/unreleased/gitlab_buttons_projects_forks.yml b/changelogs/unreleased/gitlab_buttons_projects_forks.yml
new file mode 100644
index 00000000000..0cb67451146
--- /dev/null
+++ b/changelogs/unreleased/gitlab_buttons_projects_forks.yml
@@ -0,0 +1,5 @@
+---
+title: Apply GitLab UI button styles to HAML buttons app/views/projects/forks
+merge_request: 43101
+author: Andrei Kyrnich @kyrnich
+type: other
diff --git a/changelogs/unreleased/gy-add-demo-templates.yml b/changelogs/unreleased/gy-add-demo-templates.yml
new file mode 100644
index 00000000000..7e11468f5c3
--- /dev/null
+++ b/changelogs/unreleased/gy-add-demo-templates.yml
@@ -0,0 +1,5 @@
+---
+title: Add Sample Data
+merge_request: 41699
+author:
+type: added
diff --git a/changelogs/unreleased/himkp-webide-binary-regression.yml b/changelogs/unreleased/himkp-webide-binary-regression.yml
new file mode 100644
index 00000000000..1b19bfbca87
--- /dev/null
+++ b/changelogs/unreleased/himkp-webide-binary-regression.yml
@@ -0,0 +1,5 @@
+---
+title: Fix regression when uploading / viewing binary files in the Web IDE
+merge_request: 44699
+author:
+type: fixed
diff --git a/changelogs/unreleased/id-add-approval-rules-approvers-usage-ping.yml b/changelogs/unreleased/id-add-approval-rules-approvers-usage-ping.yml
new file mode 100644
index 00000000000..3977e5763d2
--- /dev/null
+++ b/changelogs/unreleased/id-add-approval-rules-approvers-usage-ping.yml
@@ -0,0 +1,5 @@
+---
+title: Add approval rules with approvers to usage ping
+merge_request: 36737
+author:
+type: added
diff --git a/changelogs/unreleased/id-fix-squash-messages.yml b/changelogs/unreleased/id-fix-squash-messages.yml
new file mode 100644
index 00000000000..6acbbbee9d7
--- /dev/null
+++ b/changelogs/unreleased/id-fix-squash-messages.yml
@@ -0,0 +1,5 @@
+---
+title: Fix suggested squashed messages for MR
+merge_request: 43508
+author:
+type: fixed
diff --git a/changelogs/unreleased/id-required-sections.yml b/changelogs/unreleased/id-required-sections.yml
new file mode 100644
index 00000000000..b24baa719c0
--- /dev/null
+++ b/changelogs/unreleased/id-required-sections.yml
@@ -0,0 +1,5 @@
+---
+title: Introduce required_code_owners_sections table
+merge_request: 43573
+author:
+type: added
diff --git a/changelogs/unreleased/id-update-mini-magick.yml b/changelogs/unreleased/id-update-mini-magick.yml
new file mode 100644
index 00000000000..71d2503478b
--- /dev/null
+++ b/changelogs/unreleased/id-update-mini-magick.yml
@@ -0,0 +1,5 @@
+---
+title: Bump mini_magick gem version
+merge_request: 44450
+author:
+type: other
diff --git a/changelogs/unreleased/improve-emoji-support.yml b/changelogs/unreleased/improve-emoji-support.yml
new file mode 100644
index 00000000000..9660c02c5f7
--- /dev/null
+++ b/changelogs/unreleased/improve-emoji-support.yml
@@ -0,0 +1,5 @@
+---
+title: Improve issuable reaction search
+merge_request: 42321
+author: Ethan Reesor (@firelizzard)
+type: added
diff --git a/changelogs/unreleased/improve-gfm-ac-emoji.yml b/changelogs/unreleased/improve-gfm-ac-emoji.yml
new file mode 100644
index 00000000000..c8eaea58005
--- /dev/null
+++ b/changelogs/unreleased/improve-gfm-ac-emoji.yml
@@ -0,0 +1,5 @@
+---
+title: Match against description and unicode character when autocompleting GFM emoji
+merge_request: 42669
+author: Ethan Reesor (@firelizzard)
+type: added
diff --git a/changelogs/unreleased/incident-settings-sla.yml b/changelogs/unreleased/incident-settings-sla.yml
new file mode 100644
index 00000000000..a42a96bf4be
--- /dev/null
+++ b/changelogs/unreleased/incident-settings-sla.yml
@@ -0,0 +1,5 @@
+---
+title: Add Incident Sla timer columns to DB
+merge_request: 44099
+author:
+type: added
diff --git a/changelogs/unreleased/isolate-mentions-migration.yml b/changelogs/unreleased/isolate-mentions-migration.yml
new file mode 100644
index 00000000000..ae12901ce90
--- /dev/null
+++ b/changelogs/unreleased/isolate-mentions-migration.yml
@@ -0,0 +1,5 @@
+---
+title: Store user mentions to DB
+merge_request: 43393
+author:
+type: added
diff --git a/changelogs/unreleased/issuable-award-fuzzy-search.yml b/changelogs/unreleased/issuable-award-fuzzy-search.yml
new file mode 100644
index 00000000000..b3671d861e2
--- /dev/null
+++ b/changelogs/unreleased/issuable-award-fuzzy-search.yml
@@ -0,0 +1,5 @@
+---
+title: Use fuzzy matching for issuable awards
+merge_request: 42674
+author: Ethan Reesor (@firelizzard)
+type: added
diff --git a/changelogs/unreleased/issue-233479-Allow_move_issues_on_graphql.yml b/changelogs/unreleased/issue-233479-Allow_move_issues_on_graphql.yml
new file mode 100644
index 00000000000..21def475bb2
--- /dev/null
+++ b/changelogs/unreleased/issue-233479-Allow_move_issues_on_graphql.yml
@@ -0,0 +1,5 @@
+---
+title: Allow to move issues between projects on GraphQL
+merge_request: 44491
+author:
+type: added
diff --git a/changelogs/unreleased/issue_205151.yml b/changelogs/unreleased/issue_205151.yml
new file mode 100644
index 00000000000..c687a736d20
--- /dev/null
+++ b/changelogs/unreleased/issue_205151.yml
@@ -0,0 +1,4 @@
+title: 'Rendering trailing slash in reference links (issue 205151)'
+merge_request: 42484
+author:
+type: fixed
diff --git a/changelogs/unreleased/issue_233479-allow-graphql-to-update-issue-state.yml b/changelogs/unreleased/issue_233479-allow-graphql-to-update-issue-state.yml
new file mode 100644
index 00000000000..43bf32ce87f
--- /dev/null
+++ b/changelogs/unreleased/issue_233479-allow-graphql-to-update-issue-state.yml
@@ -0,0 +1,5 @@
+---
+title: Allow to update issue state on GraphQL
+merge_request: 44061
+author:
+type: added
diff --git a/changelogs/unreleased/issue_237977-2.yml b/changelogs/unreleased/issue_237977-2.yml
new file mode 100644
index 00000000000..6e61ea9c405
--- /dev/null
+++ b/changelogs/unreleased/issue_237977-2.yml
@@ -0,0 +1,5 @@
+---
+title: Populate blocking issues count
+merge_request: 45176
+author:
+type: other
diff --git a/changelogs/unreleased/issue_237977.yml b/changelogs/unreleased/issue_237977.yml
new file mode 100644
index 00000000000..97ba5a982a8
--- /dev/null
+++ b/changelogs/unreleased/issue_237977.yml
@@ -0,0 +1,5 @@
+---
+title: Populate issues blocking_issues_count
+merge_request: 42277
+author:
+type: other
diff --git a/changelogs/unreleased/jdb-refactor-diff-rows-utils.yml b/changelogs/unreleased/jdb-refactor-diff-rows-utils.yml
new file mode 100644
index 00000000000..eadc3ef0e94
--- /dev/null
+++ b/changelogs/unreleased/jdb-refactor-diff-rows-utils.yml
@@ -0,0 +1,5 @@
+---
+title: Move shared logic into utils
+merge_request: 42407
+author:
+type: other
diff --git a/changelogs/unreleased/jh-store_temp_import_data.yml b/changelogs/unreleased/jh-store_temp_import_data.yml
new file mode 100644
index 00000000000..d9df05be415
--- /dev/null
+++ b/changelogs/unreleased/jh-store_temp_import_data.yml
@@ -0,0 +1,5 @@
+---
+title: Create a set of models to store the temporary data needed for a bulk import
+merge_request: 42978
+author:
+type: changed
diff --git a/changelogs/unreleased/jivanvl-runner-guided-install-backend.yml b/changelogs/unreleased/jivanvl-runner-guided-install-backend.yml
new file mode 100644
index 00000000000..9c68363867d
--- /dev/null
+++ b/changelogs/unreleased/jivanvl-runner-guided-install-backend.yml
@@ -0,0 +1,5 @@
+---
+title: Add runner setup methods
+merge_request: 42878
+author:
+type: added
diff --git a/changelogs/unreleased/jl-update-signin-page.yml b/changelogs/unreleased/jl-update-signin-page.yml
new file mode 100644
index 00000000000..27e145828ba
--- /dev/null
+++ b/changelogs/unreleased/jl-update-signin-page.yml
@@ -0,0 +1,5 @@
+---
+title: Indicate on signin page instance is self-managed
+merge_request: 44681
+author:
+type: changed
diff --git a/changelogs/unreleased/john_long-update_project_pages_settings.yml b/changelogs/unreleased/john_long-update_project_pages_settings.yml
new file mode 100644
index 00000000000..45fde761968
--- /dev/null
+++ b/changelogs/unreleased/john_long-update_project_pages_settings.yml
@@ -0,0 +1,5 @@
+---
+title: Allow size limit to be available by default in the project pages settings form
+merge_request: 45054
+author:
+type: fixed
diff --git a/changelogs/unreleased/jv-cleanup-job-waiter.yml b/changelogs/unreleased/jv-cleanup-job-waiter.yml
new file mode 100644
index 00000000000..be8ff470dc2
--- /dev/null
+++ b/changelogs/unreleased/jv-cleanup-job-waiter.yml
@@ -0,0 +1,5 @@
+---
+title: Add cleanup migration for JobWaiter Redis keys
+merge_request: 43882
+author:
+type: fixed
diff --git a/changelogs/unreleased/jv-job-waiter-key-leak.yml b/changelogs/unreleased/jv-job-waiter-key-leak.yml
new file mode 100644
index 00000000000..8e1bde87fdb
--- /dev/null
+++ b/changelogs/unreleased/jv-job-waiter-key-leak.yml
@@ -0,0 +1,5 @@
+---
+title: Ensure JobWaiter keys always expire
+merge_request: 43320
+author:
+type: fixed
diff --git a/changelogs/unreleased/jyavorska-master-patch-96769.yml b/changelogs/unreleased/jyavorska-master-patch-96769.yml
new file mode 100644
index 00000000000..6cf4808e368
--- /dev/null
+++ b/changelogs/unreleased/jyavorska-master-patch-96769.yml
@@ -0,0 +1,5 @@
+---
+title: Add canonical links for moved/duplicated issues
+merge_request: 34604
+author:
+type: added
diff --git a/changelogs/unreleased/kassio-do-not-add-missing-not-if-importer-user-is-mapped.yml b/changelogs/unreleased/kassio-do-not-add-missing-not-if-importer-user-is-mapped.yml
new file mode 100644
index 00000000000..b878cc1311b
--- /dev/null
+++ b/changelogs/unreleased/kassio-do-not-add-missing-not-if-importer-user-is-mapped.yml
@@ -0,0 +1,5 @@
+---
+title: Allow member mapping to map importer user on Group/Project Import
+merge_request: 42882
+author:
+type: changed
diff --git a/changelogs/unreleased/kassio-fix-missing-author-notes-on-importers.yml b/changelogs/unreleased/kassio-fix-missing-author-notes-on-importers.yml
new file mode 100644
index 00000000000..7f7e2322f10
--- /dev/null
+++ b/changelogs/unreleased/kassio-fix-missing-author-notes-on-importers.yml
@@ -0,0 +1,5 @@
+---
+title: Fixed a bug causing 'Missing author note' to be added to notes for mapped users when importing project using GitLab Import.
+merge_request: 42648
+author:
+type: fixed
diff --git a/changelogs/unreleased/khanchi-designs-patch.yml b/changelogs/unreleased/khanchi-designs-patch.yml
new file mode 100644
index 00000000000..9f675685c30
--- /dev/null
+++ b/changelogs/unreleased/khanchi-designs-patch.yml
@@ -0,0 +1,5 @@
+---
+title: 'Designs: return an error if uploading designs with duplicate names'
+merge_request: 42514
+author: Sushil Khanchi
+type: fixed
diff --git a/changelogs/unreleased/kubeclient_491.yml b/changelogs/unreleased/kubeclient_491.yml
new file mode 100644
index 00000000000..56f3c1403ed
--- /dev/null
+++ b/changelogs/unreleased/kubeclient_491.yml
@@ -0,0 +1,6 @@
+---
+title: Bump kubeclient to 4.9.1 which includes ability to integrate Kubernetes clusters
+ where their API url is on a sub-path
+merge_request: 44856
+author:
+type: other
diff --git a/changelogs/unreleased/latest-successful-build-including-child-pipelines.yml b/changelogs/unreleased/latest-successful-build-including-child-pipelines.yml
new file mode 100644
index 00000000000..386795ba14d
--- /dev/null
+++ b/changelogs/unreleased/latest-successful-build-including-child-pipelines.yml
@@ -0,0 +1,5 @@
+---
+title: Include builds from child pipelines in latest sucessful build for ref/sha
+merge_request: 29710
+author:
+type: fixed
diff --git a/changelogs/unreleased/ld-graphql-use-new-global_id-for-note-mutations.yml b/changelogs/unreleased/ld-graphql-use-new-global_id-for-note-mutations.yml
new file mode 100644
index 00000000000..d3bb4709f32
--- /dev/null
+++ b/changelogs/unreleased/ld-graphql-use-new-global_id-for-note-mutations.yml
@@ -0,0 +1,5 @@
+---
+title: Updated GraphQL note mutation input ids to be more type-specific
+merge_request: 45341
+author:
+type: changed
diff --git a/changelogs/unreleased/list_issue_filters.yml b/changelogs/unreleased/list_issue_filters.yml
new file mode 100644
index 00000000000..8c1787ea5fe
--- /dev/null
+++ b/changelogs/unreleased/list_issue_filters.yml
@@ -0,0 +1,5 @@
+---
+title: Accept issue filters when getting board lists in GraphQL
+merge_request: 43968
+author:
+type: added
diff --git a/changelogs/unreleased/lm-add-action-to-detailed-status.yml b/changelogs/unreleased/lm-add-action-to-detailed-status.yml
new file mode 100644
index 00000000000..90523847d7f
--- /dev/null
+++ b/changelogs/unreleased/lm-add-action-to-detailed-status.yml
@@ -0,0 +1,5 @@
+---
+title: 'GraphQL: Adds action to DetailedStatusType and StatusActioType'
+merge_request: 44088
+author:
+type: added
diff --git a/changelogs/unreleased/lm-add-scheduled-jobs.yml b/changelogs/unreleased/lm-add-scheduled-jobs.yml
new file mode 100644
index 00000000000..a48cffe4617
--- /dev/null
+++ b/changelogs/unreleased/lm-add-scheduled-jobs.yml
@@ -0,0 +1,5 @@
+---
+title: 'GraphQL: Adds scheduledAt to CiJob'
+merge_request: 44054
+author:
+type: added
diff --git a/changelogs/unreleased/lm-add-status-graphql.yml b/changelogs/unreleased/lm-add-status-graphql.yml
new file mode 100644
index 00000000000..52297c8d0a9
--- /dev/null
+++ b/changelogs/unreleased/lm-add-status-graphql.yml
@@ -0,0 +1,5 @@
+---
+title: 'GrahphQL: Adds status to jobs, stages, and groups'
+merge_request: 43069
+author:
+type: added
diff --git a/changelogs/unreleased/lm-enable-one-d-matrix-by-default.yml b/changelogs/unreleased/lm-enable-one-d-matrix-by-default.yml
new file mode 100644
index 00000000000..0a3266d2747
--- /dev/null
+++ b/changelogs/unreleased/lm-enable-one-d-matrix-by-default.yml
@@ -0,0 +1,5 @@
+---
+title: Enable one_dimensional_matrix feature flag by default
+merge_request: 45086
+author:
+type: added
diff --git a/changelogs/unreleased/lm-improve-n-1-pl-serializer.yml b/changelogs/unreleased/lm-improve-n-1-pl-serializer.yml
new file mode 100644
index 00000000000..d919ab72ef4
--- /dev/null
+++ b/changelogs/unreleased/lm-improve-n-1-pl-serializer.yml
@@ -0,0 +1,5 @@
+---
+title: Improve n+1 in pipeline serializer for triggered pipelines
+merge_request: 42421
+author:
+type: performance
diff --git a/changelogs/unreleased/lm-update-status-null-fields.yml b/changelogs/unreleased/lm-update-status-null-fields.yml
new file mode 100644
index 00000000000..998f6a02213
--- /dev/null
+++ b/changelogs/unreleased/lm-update-status-null-fields.yml
@@ -0,0 +1,5 @@
+---
+title: 'GraphQL: Changes fields in detailedStatus to be nullable'
+merge_request: 45072
+author:
+type: changed
diff --git a/changelogs/unreleased/mb-rails-save-bang-rubcop.yml b/changelogs/unreleased/mb-rails-save-bang-rubcop.yml
new file mode 100644
index 00000000000..4be9dd4113a
--- /dev/null
+++ b/changelogs/unreleased/mb-rails-save-bang-rubcop.yml
@@ -0,0 +1,5 @@
+---
+title: Fix Rails/SaveBang offenses for spec files in spec/support/shared_example/*
+merge_request: 44424
+author: matthewbried
+type: other
diff --git a/changelogs/unreleased/mb_rails_save_bang_fix2.yml b/changelogs/unreleased/mb_rails_save_bang_fix2.yml
new file mode 100644
index 00000000000..33e175c55ea
--- /dev/null
+++ b/changelogs/unreleased/mb_rails_save_bang_fix2.yml
@@ -0,0 +1,5 @@
+---
+title: Fix Rails/SaveBang offenses in spec/uploaders/* and spec/tasks/
+merge_request: 44820
+author: matthewbried
+type: other
diff --git a/changelogs/unreleased/mb_rails_save_bang_fix3.yml b/changelogs/unreleased/mb_rails_save_bang_fix3.yml
new file mode 100644
index 00000000000..af25c188ead
--- /dev/null
+++ b/changelogs/unreleased/mb_rails_save_bang_fix3.yml
@@ -0,0 +1,5 @@
+---
+title: Fix Rails/SaveBang offenses in spec/support/*
+merge_request: 44884
+author: matthewbried
+type: other
diff --git a/changelogs/unreleased/mb_rails_save_bang_fix4.yml b/changelogs/unreleased/mb_rails_save_bang_fix4.yml
new file mode 100644
index 00000000000..e4e48e26361
--- /dev/null
+++ b/changelogs/unreleased/mb_rails_save_bang_fix4.yml
@@ -0,0 +1,5 @@
+---
+title: Fix Rails/SaveBang offenses in spec/services/projects/*
+merge_request: 44980
+author: matthewbried
+type: other
diff --git a/changelogs/unreleased/mc-feature-ci-config-render-api-endpoint.yml b/changelogs/unreleased/mc-feature-ci-config-render-api-endpoint.yml
new file mode 100644
index 00000000000..5c8bc732f73
--- /dev/null
+++ b/changelogs/unreleased/mc-feature-ci-config-render-api-endpoint.yml
@@ -0,0 +1,5 @@
+---
+title: Show expanded CI config in CI lint API endpoint.
+merge_request: 42380
+author:
+type: added
diff --git a/changelogs/unreleased/mc-feature-fix-keep-path-artifact-locking.yml b/changelogs/unreleased/mc-feature-fix-keep-path-artifact-locking.yml
new file mode 100644
index 00000000000..bdd19afb0b7
--- /dev/null
+++ b/changelogs/unreleased/mc-feature-fix-keep-path-artifact-locking.yml
@@ -0,0 +1,5 @@
+---
+title: Show keep path for expired locked artifacts.
+merge_request: 43866
+author:
+type: changed
diff --git a/changelogs/unreleased/mc-feature-project-ci-lint-api.yml b/changelogs/unreleased/mc-feature-project-ci-lint-api.yml
new file mode 100644
index 00000000000..db24843e65f
--- /dev/null
+++ b/changelogs/unreleased/mc-feature-project-ci-lint-api.yml
@@ -0,0 +1,5 @@
+---
+title: Add project scoped CI lint API endpoint.
+merge_request: 42998
+author:
+type: added
diff --git a/changelogs/unreleased/mgill-user-gpg.yml b/changelogs/unreleased/mgill-user-gpg.yml
new file mode 100644
index 00000000000..ffcf5a0c3fb
--- /dev/null
+++ b/changelogs/unreleased/mgill-user-gpg.yml
@@ -0,0 +1,5 @@
+---
+title: API support for a specific GPG Key for given user
+merge_request: 43693
+author:
+type: added
diff --git a/changelogs/unreleased/migrate-recover-hidden-stage.yml b/changelogs/unreleased/migrate-recover-hidden-stage.yml
new file mode 100644
index 00000000000..e4cf4992a94
--- /dev/null
+++ b/changelogs/unreleased/migrate-recover-hidden-stage.yml
@@ -0,0 +1,5 @@
+---
+title: Migrate Recover hidden stage dropdown
+merge_request: 43032
+author:
+type: other
diff --git a/changelogs/unreleased/migrate_blocked_by.yml b/changelogs/unreleased/migrate_blocked_by.yml
new file mode 100644
index 00000000000..04f40b17159
--- /dev/null
+++ b/changelogs/unreleased/migrate_blocked_by.yml
@@ -0,0 +1,5 @@
+---
+title: Migrate blocked_by issue links to blocks type by swapping source and target
+merge_request: 45262
+author:
+type: other
diff --git a/changelogs/unreleased/mk-add-missing-avatar-size.yml b/changelogs/unreleased/mk-add-missing-avatar-size.yml
new file mode 100644
index 00000000000..8b587ee0004
--- /dev/null
+++ b/changelogs/unreleased/mk-add-missing-avatar-size.yml
@@ -0,0 +1,5 @@
+---
+title: Add missing 90x avatar size for image scaling
+merge_request: 45025
+author:
+type: fixed
diff --git a/changelogs/unreleased/mk-enforce-not-null-file-store-on-package-files.yml b/changelogs/unreleased/mk-enforce-not-null-file-store-on-package-files.yml
new file mode 100644
index 00000000000..34d2c443232
--- /dev/null
+++ b/changelogs/unreleased/mk-enforce-not-null-file-store-on-package-files.yml
@@ -0,0 +1,6 @@
+---
+title: Validate not null file_store field on packages_package_files to maintain data
+ integrity
+merge_request: 42400
+author:
+type: added
diff --git a/changelogs/unreleased/mk-stackprof-object-support.yml b/changelogs/unreleased/mk-stackprof-object-support.yml
new file mode 100644
index 00000000000..7b3b3cc7024
--- /dev/null
+++ b/changelogs/unreleased/mk-stackprof-object-support.yml
@@ -0,0 +1,5 @@
+---
+title: Support all stackprof profiling modes
+merge_request: 45277
+author:
+type: changed
diff --git a/changelogs/unreleased/mo-pipeline-artifacts-size-graphql.yml b/changelogs/unreleased/mo-pipeline-artifacts-size-graphql.yml
new file mode 100644
index 00000000000..cc629714895
--- /dev/null
+++ b/changelogs/unreleased/mo-pipeline-artifacts-size-graphql.yml
@@ -0,0 +1,5 @@
+---
+title: Add pipeline_artifacts_size to RootStorageStatisticsType
+merge_request: 44595
+author:
+type: changed
diff --git a/changelogs/unreleased/move-ff-menu-doc-to-core.yml b/changelogs/unreleased/move-ff-menu-doc-to-core.yml
new file mode 100644
index 00000000000..10939c306c4
--- /dev/null
+++ b/changelogs/unreleased/move-ff-menu-doc-to-core.yml
@@ -0,0 +1,5 @@
+---
+title: Move feature flags to core
+merge_request: 44642
+author:
+type: changed
diff --git a/changelogs/unreleased/move-referrer-policy-to-header.yml b/changelogs/unreleased/move-referrer-policy-to-header.yml
new file mode 100644
index 00000000000..e80bcee4a23
--- /dev/null
+++ b/changelogs/unreleased/move-referrer-policy-to-header.yml
@@ -0,0 +1,5 @@
+---
+title: Set default Referrer-Policy to strict-origin-when-cross-origin and set it in a header rather than HTML
+merge_request: 26065
+author: nhirokinet
+type: changed
diff --git a/changelogs/unreleased/mr-state-index.yml b/changelogs/unreleased/mr-state-index.yml
new file mode 100644
index 00000000000..80344515863
--- /dev/null
+++ b/changelogs/unreleased/mr-state-index.yml
@@ -0,0 +1,5 @@
+---
+title: Add state_id index for merge_requests list
+merge_request: 42481
+author:
+type: performance
diff --git a/changelogs/unreleased/mw-description-template-replace-fa-icons.yml b/changelogs/unreleased/mw-description-template-replace-fa-icons.yml
new file mode 100644
index 00000000000..99a0f095d15
--- /dev/null
+++ b/changelogs/unreleased/mw-description-template-replace-fa-icons.yml
@@ -0,0 +1,5 @@
+---
+title: "Description Templates: Replace fontawesome icons with GitLab SVGs"
+merge_request: 43379
+author:
+type: changed
diff --git a/changelogs/unreleased/mw-feature-flags-replace-chevron-fa-icon.yml b/changelogs/unreleased/mw-feature-flags-replace-chevron-fa-icon.yml
new file mode 100644
index 00000000000..72ec90332f4
--- /dev/null
+++ b/changelogs/unreleased/mw-feature-flags-replace-chevron-fa-icon.yml
@@ -0,0 +1,5 @@
+---
+title: 'Feature flags form: Replace fa-chevron-down with GitLab SVG'
+merge_request: 42968
+author:
+type: changed
diff --git a/changelogs/unreleased/mw-project-settings-icon-replacements.yml b/changelogs/unreleased/mw-project-settings-icon-replacements.yml
new file mode 100644
index 00000000000..d7478f3386f
--- /dev/null
+++ b/changelogs/unreleased/mw-project-settings-icon-replacements.yml
@@ -0,0 +1,5 @@
+---
+title: Replace fa-chevron-down with GitLab SVG in project visibility settings
+merge_request: 45021
+author:
+type: changed
diff --git a/changelogs/unreleased/mw-replace-external-link-icon-group-folder.yml b/changelogs/unreleased/mw-replace-external-link-icon-group-folder.yml
new file mode 100644
index 00000000000..d7cae88883e
--- /dev/null
+++ b/changelogs/unreleased/mw-replace-external-link-icon-group-folder.yml
@@ -0,0 +1,5 @@
+---
+title: Replace fa-external-link with GitLab SVG in group folder
+merge_request: 43128
+author:
+type: changed
diff --git a/changelogs/unreleased/mw-replace-fa-bitbucket-icons.yml b/changelogs/unreleased/mw-replace-fa-bitbucket-icons.yml
new file mode 100644
index 00000000000..1f13ef5bbdc
--- /dev/null
+++ b/changelogs/unreleased/mw-replace-fa-bitbucket-icons.yml
@@ -0,0 +1,5 @@
+---
+title: Replace fa-bitbucket-* icons with GitLab SVG
+merge_request: 45437
+author:
+type: changed
diff --git a/changelogs/unreleased/mw-replace-fa-github-icons.yml b/changelogs/unreleased/mw-replace-fa-github-icons.yml
new file mode 100644
index 00000000000..4959d502263
--- /dev/null
+++ b/changelogs/unreleased/mw-replace-fa-github-icons.yml
@@ -0,0 +1,5 @@
+---
+title: Replace fa-github with GitLab SVG MERGE_REQUEST_ID
+merge_request: 45533
+author:
+type: changed
diff --git a/changelogs/unreleased/mw-replace-fa-google-icons.yml b/changelogs/unreleased/mw-replace-fa-google-icons.yml
new file mode 100644
index 00000000000..72480752391
--- /dev/null
+++ b/changelogs/unreleased/mw-replace-fa-google-icons.yml
@@ -0,0 +1,5 @@
+---
+title: Replace fa-google with GitLab SVG
+merge_request: 45506
+author:
+type: changed
diff --git a/changelogs/unreleased/mw-replace-fa-icon-in-repo-preview.yml b/changelogs/unreleased/mw-replace-fa-icon-in-repo-preview.yml
new file mode 100644
index 00000000000..e9fd0c66f89
--- /dev/null
+++ b/changelogs/unreleased/mw-replace-fa-icon-in-repo-preview.yml
@@ -0,0 +1,5 @@
+---
+title: Replace fa icon with GitLab SVG in repository preview
+merge_request: 44696
+author:
+type: changed
diff --git a/changelogs/unreleased/mw-replace-fa-refresh.yml b/changelogs/unreleased/mw-replace-fa-refresh.yml
new file mode 100644
index 00000000000..2b26631d981
--- /dev/null
+++ b/changelogs/unreleased/mw-replace-fa-refresh.yml
@@ -0,0 +1,5 @@
+---
+title: Replace fa icons in CI build table
+merge_request: 45123
+author:
+type: changed
diff --git a/changelogs/unreleased/mw-replace-fa-search-icons.yml b/changelogs/unreleased/mw-replace-fa-search-icons.yml
new file mode 100644
index 00000000000..777098ef490
--- /dev/null
+++ b/changelogs/unreleased/mw-replace-fa-search-icons.yml
@@ -0,0 +1,5 @@
+---
+title: Replace fa-search fontawesome icons with GitLab SVG in Vue components
+merge_request: 43879
+author:
+type: changed
diff --git a/changelogs/unreleased/mw-replace-fa-warning-in-limit-warning-component.yml b/changelogs/unreleased/mw-replace-fa-warning-in-limit-warning-component.yml
new file mode 100644
index 00000000000..03c226d7673
--- /dev/null
+++ b/changelogs/unreleased/mw-replace-fa-warning-in-limit-warning-component.yml
@@ -0,0 +1,5 @@
+---
+title: 'VSA: Replace fa-warning with GitLab SVG icon'
+merge_request: 43994
+author:
+type: changed
diff --git a/changelogs/unreleased/mw-replace-switcher-icons.yml b/changelogs/unreleased/mw-replace-switcher-icons.yml
new file mode 100644
index 00000000000..d09bf1abc98
--- /dev/null
+++ b/changelogs/unreleased/mw-replace-switcher-icons.yml
@@ -0,0 +1,5 @@
+---
+title: Replace switcher fa- icons in blob viewer models
+merge_request: 45124
+author:
+type: changed
diff --git a/changelogs/unreleased/mw-vsa-limit-warnings-icon-refactor.yml b/changelogs/unreleased/mw-vsa-limit-warnings-icon-refactor.yml
new file mode 100644
index 00000000000..0d4051dae79
--- /dev/null
+++ b/changelogs/unreleased/mw-vsa-limit-warnings-icon-refactor.yml
@@ -0,0 +1,5 @@
+---
+title: 'VSA: Replace fa-warning with GitLab SVG'
+merge_request: 43262
+author:
+type: changed
diff --git a/changelogs/unreleased/mwaw-230438-log-usage-data-failed-queries.yml b/changelogs/unreleased/mwaw-230438-log-usage-data-failed-queries.yml
new file mode 100644
index 00000000000..72033578f4d
--- /dev/null
+++ b/changelogs/unreleased/mwaw-230438-log-usage-data-failed-queries.yml
@@ -0,0 +1,5 @@
+---
+title: Log failed BatchCount queries
+merge_request: 41552
+author:
+type: added
diff --git a/changelogs/unreleased/nfriend-add-release-og-description.yml b/changelogs/unreleased/nfriend-add-release-og-description.yml
new file mode 100644
index 00000000000..0a8d6372b6f
--- /dev/null
+++ b/changelogs/unreleased/nfriend-add-release-og-description.yml
@@ -0,0 +1,5 @@
+---
+title: Add og:description meta tag to individual "Release" page
+merge_request: 42889
+author:
+type: added
diff --git a/changelogs/unreleased/nfriend-fix-markdown-preview-on-new-release-page.yml b/changelogs/unreleased/nfriend-fix-markdown-preview-on-new-release-page.yml
new file mode 100644
index 00000000000..b6854e68776
--- /dev/null
+++ b/changelogs/unreleased/nfriend-fix-markdown-preview-on-new-release-page.yml
@@ -0,0 +1,5 @@
+---
+title: Fix Markdown "Preview" tab on New/Edit Release and New Snippet pages
+merge_request: 42640
+author:
+type: fixed
diff --git a/changelogs/unreleased/nfriend-fix-release-asset-link-length.yml b/changelogs/unreleased/nfriend-fix-release-asset-link-length.yml
new file mode 100644
index 00000000000..435929e247c
--- /dev/null
+++ b/changelogs/unreleased/nfriend-fix-release-asset-link-length.yml
@@ -0,0 +1,5 @@
+---
+title: Fix clickable width of release asset links
+merge_request: 42757
+author:
+type: fixed
diff --git a/changelogs/unreleased/nfriend-fix-release-edit-button-size.yml b/changelogs/unreleased/nfriend-fix-release-edit-button-size.yml
new file mode 100644
index 00000000000..9ccb16bd852
--- /dev/null
+++ b/changelogs/unreleased/nfriend-fix-release-edit-button-size.yml
@@ -0,0 +1,5 @@
+---
+title: Fix size of edit button on releases page
+merge_request: 42779
+author:
+type: fixed
diff --git a/changelogs/unreleased/nfriend-strip-markdown-from-og-description.yml b/changelogs/unreleased/nfriend-strip-markdown-from-og-description.yml
new file mode 100644
index 00000000000..75d53bf26ed
--- /dev/null
+++ b/changelogs/unreleased/nfriend-strip-markdown-from-og-description.yml
@@ -0,0 +1,5 @@
+---
+title: Strip markdown from og:description meta tags
+merge_request: 42918
+author:
+type: added
diff --git a/changelogs/unreleased/nfriend-update-releases-page-skeleton-loader-shape.yml b/changelogs/unreleased/nfriend-update-releases-page-skeleton-loader-shape.yml
new file mode 100644
index 00000000000..2e21a11a233
--- /dev/null
+++ b/changelogs/unreleased/nfriend-update-releases-page-skeleton-loader-shape.yml
@@ -0,0 +1,5 @@
+---
+title: Update skeleton loader shape on releases pages
+merge_request: 43138
+author:
+type: added
diff --git a/changelogs/unreleased/nicolasdular-remove-tos-checkobx.yml b/changelogs/unreleased/nicolasdular-remove-tos-checkobx.yml
new file mode 100644
index 00000000000..704bc965ff4
--- /dev/null
+++ b/changelogs/unreleased/nicolasdular-remove-tos-checkobx.yml
@@ -0,0 +1,5 @@
+---
+title: Remove accept terms checkbox for signup
+merge_request: 42581
+author:
+type: changed
diff --git a/changelogs/unreleased/nicolasdular-respect-dnt.yml b/changelogs/unreleased/nicolasdular-respect-dnt.yml
new file mode 100644
index 00000000000..1b7f2db8094
--- /dev/null
+++ b/changelogs/unreleased/nicolasdular-respect-dnt.yml
@@ -0,0 +1,5 @@
+---
+title: Respect DNT when tracking experiments
+merge_request: 44420
+author:
+type: fixed
diff --git a/changelogs/unreleased/nicolasdular-split-first-last-name.yml b/changelogs/unreleased/nicolasdular-split-first-last-name.yml
new file mode 100644
index 00000000000..57eb59647e6
--- /dev/null
+++ b/changelogs/unreleased/nicolasdular-split-first-last-name.yml
@@ -0,0 +1,5 @@
+---
+title: Split name to first and last name for signup
+merge_request: 42346
+author:
+type: changed
diff --git a/changelogs/unreleased/nix-comment.yml b/changelogs/unreleased/nix-comment.yml
new file mode 100644
index 00000000000..2d07f434289
--- /dev/null
+++ b/changelogs/unreleased/nix-comment.yml
@@ -0,0 +1,5 @@
+---
+title: Remove an outdated comment
+merge_request: 44861
+author: Robin Dupret
+type: other
diff --git a/changelogs/unreleased/notificaion-button-class.yml b/changelogs/unreleased/notificaion-button-class.yml
new file mode 100644
index 00000000000..367edc1d3a8
--- /dev/null
+++ b/changelogs/unreleased/notificaion-button-class.yml
@@ -0,0 +1,5 @@
+---
+title: Fix broken button default class
+merge_request: 43977
+author:
+type: fixed
diff --git a/changelogs/unreleased/ntepluhina-fix-incorrect-parameter.yml b/changelogs/unreleased/ntepluhina-fix-incorrect-parameter.yml
new file mode 100644
index 00000000000..3764efeeb8b
--- /dev/null
+++ b/changelogs/unreleased/ntepluhina-fix-incorrect-parameter.yml
@@ -0,0 +1,5 @@
+---
+title: Fixed incorrect parameter in GraphQL startup call
+merge_request: 45115
+author:
+type: fixed
diff --git a/changelogs/unreleased/ntepluhina-refactor-toolbar-to-gitlab-ui.yml b/changelogs/unreleased/ntepluhina-refactor-toolbar-to-gitlab-ui.yml
new file mode 100644
index 00000000000..7f3fc367d6e
--- /dev/null
+++ b/changelogs/unreleased/ntepluhina-refactor-toolbar-to-gitlab-ui.yml
@@ -0,0 +1,5 @@
+---
+title: Update Design Management toolbar to use GitLab UI classes
+merge_request: 43682
+author:
+type: other
diff --git a/changelogs/unreleased/okr-alert-widget-form.yml b/changelogs/unreleased/okr-alert-widget-form.yml
new file mode 100644
index 00000000000..138c428403a
--- /dev/null
+++ b/changelogs/unreleased/okr-alert-widget-form.yml
@@ -0,0 +1,5 @@
+---
+title: Migrate button in alert_widget_form.vue
+merge_request: 43720
+author:
+type: other
diff --git a/changelogs/unreleased/okr-fluentd-output-settings.yml b/changelogs/unreleased/okr-fluentd-output-settings.yml
new file mode 100644
index 00000000000..b966d1dca42
--- /dev/null
+++ b/changelogs/unreleased/okr-fluentd-output-settings.yml
@@ -0,0 +1,5 @@
+---
+title: Migrate button in fluentd_output_settings.vue
+merge_request: 43724
+author:
+type: other
diff --git a/changelogs/unreleased/okr-ingress-modsecurity-settings.yml b/changelogs/unreleased/okr-ingress-modsecurity-settings.yml
new file mode 100644
index 00000000000..b5b22d25a0a
--- /dev/null
+++ b/changelogs/unreleased/okr-ingress-modsecurity-settings.yml
@@ -0,0 +1,5 @@
+---
+title: Migrate deprecated button to GlButton in ingress_modsecurity_settings.vue
+merge_request: 43717
+author:
+type: other
diff --git a/changelogs/unreleased/okr-modal-copy-button.yml b/changelogs/unreleased/okr-modal-copy-button.yml
new file mode 100644
index 00000000000..390da8d4b73
--- /dev/null
+++ b/changelogs/unreleased/okr-modal-copy-button.yml
@@ -0,0 +1,5 @@
+---
+title: Update button in modal_copy_button.vue to use GlButton from GitLab UI
+merge_request: 43714
+author:
+type: other
diff --git a/changelogs/unreleased/pages-1-26-0.yml b/changelogs/unreleased/pages-1-26-0.yml
new file mode 100644
index 00000000000..704059c7049
--- /dev/null
+++ b/changelogs/unreleased/pages-1-26-0.yml
@@ -0,0 +1,5 @@
+---
+title: Upgrade GitLab Pages to 1.26.0
+merge_request: 43416
+author:
+type: added
diff --git a/changelogs/unreleased/pages-1-27-0.yml b/changelogs/unreleased/pages-1-27-0.yml
new file mode 100644
index 00000000000..5b6e80d2f1a
--- /dev/null
+++ b/changelogs/unreleased/pages-1-27-0.yml
@@ -0,0 +1,5 @@
+---
+title: Upgrade GitLab Pages to 1.27.0
+merge_request: 44162
+author:
+type: added
diff --git a/changelogs/unreleased/pat-bot-terms.yml b/changelogs/unreleased/pat-bot-terms.yml
new file mode 100644
index 00000000000..dceb285e5e0
--- /dev/null
+++ b/changelogs/unreleased/pat-bot-terms.yml
@@ -0,0 +1,5 @@
+---
+title: Auto-accept TOS if project bot
+merge_request: 43067
+author:
+type: fixed
diff --git a/changelogs/unreleased/ph-199725-diffHeaderActionDropdown.yml b/changelogs/unreleased/ph-199725-diffHeaderActionDropdown.yml
new file mode 100644
index 00000000000..89ed558ea8f
--- /dev/null
+++ b/changelogs/unreleased/ph-199725-diffHeaderActionDropdown.yml
@@ -0,0 +1,5 @@
+---
+title: Move diff header actions into dropdown menu
+merge_request:
+author:
+type: changed
diff --git a/changelogs/unreleased/ph-207481-targetBranchFilterDashboard.yml b/changelogs/unreleased/ph-207481-targetBranchFilterDashboard.yml
new file mode 100644
index 00000000000..e1eed671357
--- /dev/null
+++ b/changelogs/unreleased/ph-207481-targetBranchFilterDashboard.yml
@@ -0,0 +1,5 @@
+---
+title: Disable target branch filter option on merge requests dashboard
+merge_request:
+author:
+type: fixed
diff --git a/changelogs/unreleased/ph-212334-fixTwoButtonReviewSubmit.yml b/changelogs/unreleased/ph-212334-fixTwoButtonReviewSubmit.yml
new file mode 100644
index 00000000000..90c20a6b97b
--- /dev/null
+++ b/changelogs/unreleased/ph-212334-fixTwoButtonReviewSubmit.yml
@@ -0,0 +1,5 @@
+---
+title: Improve two button review submit in merge requests
+merge_request: 43149
+author:
+type: changed
diff --git a/changelogs/unreleased/ph-218300-fixedSystemHeaderOnDiffs.yml b/changelogs/unreleased/ph-218300-fixedSystemHeaderOnDiffs.yml
new file mode 100644
index 00000000000..01c7d14e600
--- /dev/null
+++ b/changelogs/unreleased/ph-218300-fixedSystemHeaderOnDiffs.yml
@@ -0,0 +1,5 @@
+---
+title: Fixed merge request tabs overlapping with system header
+merge_request:
+author:
+type: fixed
diff --git a/changelogs/unreleased/ph-224141-hideBatchSuggestionsWithOnlyOneSuggestion.yml b/changelogs/unreleased/ph-224141-hideBatchSuggestionsWithOnlyOneSuggestion.yml
new file mode 100644
index 00000000000..bdd30e0e946
--- /dev/null
+++ b/changelogs/unreleased/ph-224141-hideBatchSuggestionsWithOnlyOneSuggestion.yml
@@ -0,0 +1,5 @@
+---
+title: Hides batch suggestions button if there is only 1 suggestion
+merge_request: 42681
+author:
+type: fixed
diff --git a/changelogs/unreleased/ph-227421-changeMROptionsDropdownToIncludeDraft.yml b/changelogs/unreleased/ph-227421-changeMROptionsDropdownToIncludeDraft.yml
new file mode 100644
index 00000000000..9fdd604b19b
--- /dev/null
+++ b/changelogs/unreleased/ph-227421-changeMROptionsDropdownToIncludeDraft.yml
@@ -0,0 +1,5 @@
+---
+title: Adds button to update merge request draft status on merge request show page
+merge_request: 43098
+author:
+type: added
diff --git a/changelogs/unreleased/pl-tracing-core-2-usage-data.yml b/changelogs/unreleased/pl-tracing-core-2-usage-data.yml
new file mode 100644
index 00000000000..0dab5f6bb68
--- /dev/null
+++ b/changelogs/unreleased/pl-tracing-core-2-usage-data.yml
@@ -0,0 +1,5 @@
+---
+title: Move Tracing usage data ping to Core
+merge_request: 44006
+author:
+type: added
diff --git a/changelogs/unreleased/pl-tracing-core-5-settings-haml.yml b/changelogs/unreleased/pl-tracing-core-5-settings-haml.yml
new file mode 100644
index 00000000000..35a0cb50d6f
--- /dev/null
+++ b/changelogs/unreleased/pl-tracing-core-5-settings-haml.yml
@@ -0,0 +1,5 @@
+---
+title: Move Tracing feature to Core
+merge_request: 44574
+author:
+type: added
diff --git a/changelogs/unreleased/preload-merge-request-diffs-for-throughtput-table.yml b/changelogs/unreleased/preload-merge-request-diffs-for-throughtput-table.yml
new file mode 100644
index 00000000000..80fc9d090c6
--- /dev/null
+++ b/changelogs/unreleased/preload-merge-request-diffs-for-throughtput-table.yml
@@ -0,0 +1,5 @@
+---
+title: Optimize the loading of diffStats in merge request GraphQL API
+merge_request: 44752
+author:
+type: performance
diff --git a/changelogs/unreleased/ps-fix-attach-a-file.yml b/changelogs/unreleased/ps-fix-attach-a-file.yml
new file mode 100644
index 00000000000..beec21a2b70
--- /dev/null
+++ b/changelogs/unreleased/ps-fix-attach-a-file.yml
@@ -0,0 +1,5 @@
+---
+title: Fix attach file button not working in description fields
+merge_request: 44216
+author:
+type: fixed
diff --git a/changelogs/unreleased/psi-board-remove-list-to-sidebar.yml b/changelogs/unreleased/psi-board-remove-list-to-sidebar.yml
new file mode 100644
index 00000000000..6b890920c9e
--- /dev/null
+++ b/changelogs/unreleased/psi-board-remove-list-to-sidebar.yml
@@ -0,0 +1,5 @@
+---
+title: Move remove board column button to sidebar
+merge_request: 44380
+author:
+type: changed
diff --git a/changelogs/unreleased/psi-do-not-extend-2.yml b/changelogs/unreleased/psi-do-not-extend-2.yml
new file mode 100644
index 00000000000..45cd1038392
--- /dev/null
+++ b/changelogs/unreleased/psi-do-not-extend-2.yml
@@ -0,0 +1,5 @@
+---
+title: Less inconsistent Edit links in sidebar
+merge_request: 43106
+author:
+type: performance
diff --git a/changelogs/unreleased/put_extra_graphql_logs.yml b/changelogs/unreleased/put_extra_graphql_logs.yml
new file mode 100644
index 00000000000..1ffbbea181f
--- /dev/null
+++ b/changelogs/unreleased/put_extra_graphql_logs.yml
@@ -0,0 +1,5 @@
+---
+title: Include `used_fields` and `used_deprecated_fields` in GraphQL logs
+merge_request: 42820
+author:
+type: added
diff --git a/changelogs/unreleased/rails-save-bang-33.yml b/changelogs/unreleased/rails-save-bang-33.yml
new file mode 100644
index 00000000000..ed001e647ba
--- /dev/null
+++ b/changelogs/unreleased/rails-save-bang-33.yml
@@ -0,0 +1,5 @@
+---
+title: Fix Rails/SaveBang offenses for spec files in spec/services/milestones/*
+merge_request: 42775
+author: Rajendra Kadam
+type: other
diff --git a/changelogs/unreleased/rails-save-bang-34.yml b/changelogs/unreleased/rails-save-bang-34.yml
new file mode 100644
index 00000000000..db0fba9c15e
--- /dev/null
+++ b/changelogs/unreleased/rails-save-bang-34.yml
@@ -0,0 +1,5 @@
+---
+title: Fix Rails/SaveBang offenses for spec files in spec/services/issuable/*
+merge_request: 42780
+author: Rajendra Kadam
+type: other
diff --git a/changelogs/unreleased/rails-save-bang-35.yml b/changelogs/unreleased/rails-save-bang-35.yml
new file mode 100644
index 00000000000..580b0cb1bf8
--- /dev/null
+++ b/changelogs/unreleased/rails-save-bang-35.yml
@@ -0,0 +1,5 @@
+---
+title: Fixes Rails/SaveBang cop for spec files in ee/spec/models/concerns/*
+merge_request: 42839
+author: Rajendra Kadam
+type: other
diff --git a/changelogs/unreleased/rails-save-bang-36.yml b/changelogs/unreleased/rails-save-bang-36.yml
new file mode 100644
index 00000000000..e3262aa413e
--- /dev/null
+++ b/changelogs/unreleased/rails-save-bang-36.yml
@@ -0,0 +1,5 @@
+---
+title: Fixes Rails/SaveBang cop for spec files in spec/models/concerns/*
+merge_request: 42942
+author: Rajendra Kadam
+type: other
diff --git a/changelogs/unreleased/rails-save-bang-37.yml b/changelogs/unreleased/rails-save-bang-37.yml
new file mode 100644
index 00000000000..167162dbac6
--- /dev/null
+++ b/changelogs/unreleased/rails-save-bang-37.yml
@@ -0,0 +1,5 @@
+---
+title: Fixes Rails/SaveBang cop for spec files in spec/lib/gitlab/git/*
+merge_request: 43013
+author: Rajendra Kadam
+type: other
diff --git a/changelogs/unreleased/rate-limit-docs.yml b/changelogs/unreleased/rate-limit-docs.yml
new file mode 100644
index 00000000000..c1c745ef757
--- /dev/null
+++ b/changelogs/unreleased/rate-limit-docs.yml
@@ -0,0 +1,5 @@
+---
+title: Rate limit documentation for non-configurable limits
+merge_request: 44003
+author:
+type: other
diff --git a/changelogs/unreleased/reminder-emails-invitation-declined-screen.yml b/changelogs/unreleased/reminder-emails-invitation-declined-screen.yml
new file mode 100644
index 00000000000..35d3013f3c1
--- /dev/null
+++ b/changelogs/unreleased/reminder-emails-invitation-declined-screen.yml
@@ -0,0 +1,5 @@
+---
+title: Add invitation declined page
+merge_request: 43305
+author:
+type: changed
diff --git a/changelogs/unreleased/remove-add_severity_system_note-feature-flag.yml b/changelogs/unreleased/remove-add_severity_system_note-feature-flag.yml
new file mode 100644
index 00000000000..117d7511d8b
--- /dev/null
+++ b/changelogs/unreleased/remove-add_severity_system_note-feature-flag.yml
@@ -0,0 +1,5 @@
+---
+title: Add system note on incident severity change
+merge_request: 43998
+author:
+type: added
diff --git a/changelogs/unreleased/remove-index-on-issues-relative-position.yml b/changelogs/unreleased/remove-index-on-issues-relative-position.yml
new file mode 100644
index 00000000000..690e358dbce
--- /dev/null
+++ b/changelogs/unreleased/remove-index-on-issues-relative-position.yml
@@ -0,0 +1,5 @@
+---
+title: Remove index on issues.relative_position
+merge_request: 43991
+author:
+type: performance
diff --git a/changelogs/unreleased/remove-project-id-and-id-index-on-vulnerabilities-table.yml b/changelogs/unreleased/remove-project-id-and-id-index-on-vulnerabilities-table.yml
new file mode 100644
index 00000000000..9e863970235
--- /dev/null
+++ b/changelogs/unreleased/remove-project-id-and-id-index-on-vulnerabilities-table.yml
@@ -0,0 +1,5 @@
+---
+title: Remove duplicate index from the Vulnerabilities table
+merge_request: 44422
+author: Borivoje Tasovac @borivojetasovac
+type: performance
diff --git a/changelogs/unreleased/remove-tmp-index.yml b/changelogs/unreleased/remove-tmp-index.yml
new file mode 100644
index 00000000000..8c2820cc7cd
--- /dev/null
+++ b/changelogs/unreleased/remove-tmp-index.yml
@@ -0,0 +1,5 @@
+---
+title: Remove temporary index for fixing broken CS fingerprints
+merge_request: 43126
+author:
+type: other
diff --git a/changelogs/unreleased/remove-unused-index-for-cs-reports.yml b/changelogs/unreleased/remove-unused-index-for-cs-reports.yml
new file mode 100644
index 00000000000..509c0451f96
--- /dev/null
+++ b/changelogs/unreleased/remove-unused-index-for-cs-reports.yml
@@ -0,0 +1,5 @@
+---
+title: Remove temporary index for container scanning findings
+merge_request: 44131
+author:
+type: other
diff --git a/changelogs/unreleased/remove-wiki-history-button-editing-view.yml b/changelogs/unreleased/remove-wiki-history-button-editing-view.yml
new file mode 100644
index 00000000000..d5195257f42
--- /dev/null
+++ b/changelogs/unreleased/remove-wiki-history-button-editing-view.yml
@@ -0,0 +1,5 @@
+---
+title: Minor UI improvements to Wiki edit page
+merge_request: 45247
+author:
+type: changed
diff --git a/changelogs/unreleased/remove_store_instance_statistics_measurements_ff.yml b/changelogs/unreleased/remove_store_instance_statistics_measurements_ff.yml
new file mode 100644
index 00000000000..43354cdcb3c
--- /dev/null
+++ b/changelogs/unreleased/remove_store_instance_statistics_measurements_ff.yml
@@ -0,0 +1,5 @@
+---
+title: Remove the `store_instance_statistics_measurements` feature flag
+merge_request: 44566
+author:
+type: changed
diff --git a/changelogs/unreleased/replace-alert-milestones.yml b/changelogs/unreleased/replace-alert-milestones.yml
new file mode 100644
index 00000000000..f90863a209a
--- /dev/null
+++ b/changelogs/unreleased/replace-alert-milestones.yml
@@ -0,0 +1,5 @@
+---
+title: Replace bootstrap alert in app/views/shared/milestones/_top.html.haml
+merge_request: 44731
+author:
+type: changed
diff --git a/changelogs/unreleased/revert-42465-and-42343.yml b/changelogs/unreleased/revert-42465-and-42343.yml
deleted file mode 100644
index 4c7342c9d0d..00000000000
--- a/changelogs/unreleased/revert-42465-and-42343.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: 'Revert 42465 and 42343: Expanded collapsed diff files'
-merge_request: 43361
-author:
-type: other
diff --git a/changelogs/unreleased/revert-a6875e5f.yml b/changelogs/unreleased/revert-a6875e5f.yml
new file mode 100644
index 00000000000..ea8135346f2
--- /dev/null
+++ b/changelogs/unreleased/revert-a6875e5f.yml
@@ -0,0 +1,5 @@
+---
+title: Revert required encryption on CI runner tokens
+merge_request: 42623
+author:
+type: fixed
diff --git a/changelogs/unreleased/revert-aa19ce96.yml b/changelogs/unreleased/revert-aa19ce96.yml
new file mode 100644
index 00000000000..c814da0d016
--- /dev/null
+++ b/changelogs/unreleased/revert-aa19ce96.yml
@@ -0,0 +1,5 @@
+---
+title: Revert of Background migration for setting Jira tracker data deployment type
+merge_request: 45205
+author:
+type: fixed
diff --git a/changelogs/unreleased/revise-tooltip-text-of-note-role-badge.yml b/changelogs/unreleased/revise-tooltip-text-of-note-role-badge.yml
new file mode 100644
index 00000000000..4362c2fcc9e
--- /dev/null
+++ b/changelogs/unreleased/revise-tooltip-text-of-note-role-badge.yml
@@ -0,0 +1,5 @@
+---
+title: Revise tooltip text of note role badge
+merge_request: 42771
+author: Mycroft Kang @TaehyeokKang
+type: Bug fix
diff --git a/changelogs/unreleased/revoke-token-delete-project-bot.yml b/changelogs/unreleased/revoke-token-delete-project-bot.yml
new file mode 100644
index 00000000000..0cbe419f925
--- /dev/null
+++ b/changelogs/unreleased/revoke-token-delete-project-bot.yml
@@ -0,0 +1,5 @@
+---
+title: Delete project bot when token is revoked
+merge_request: 43373
+author:
+type: fixed
diff --git a/changelogs/unreleased/sarnold-deprecate-lowercase-enums.yml b/changelogs/unreleased/sarnold-deprecate-lowercase-enums.yml
new file mode 100644
index 00000000000..aee4f1137e3
--- /dev/null
+++ b/changelogs/unreleased/sarnold-deprecate-lowercase-enums.yml
@@ -0,0 +1,5 @@
+---
+title: Deprecate lowercase values for sort enums in GraphQL
+merge_request: 43650
+author:
+type: changed
diff --git a/changelogs/unreleased/scoped-label-dashboard.yml b/changelogs/unreleased/scoped-label-dashboard.yml
new file mode 100644
index 00000000000..b564fd4cd8e
--- /dev/null
+++ b/changelogs/unreleased/scoped-label-dashboard.yml
@@ -0,0 +1,5 @@
+---
+title: Fix profile scoped label CSS
+merge_request: 43005
+author:
+type: changed
diff --git a/changelogs/unreleased/security-update-runner-version.yml b/changelogs/unreleased/security-update-runner-version.yml
new file mode 100644
index 00000000000..46dd2163a14
--- /dev/null
+++ b/changelogs/unreleased/security-update-runner-version.yml
@@ -0,0 +1,5 @@
+---
+title: Update GitLab Runner Helm Chart to 0.21.1
+merge_request:
+author:
+type: security
diff --git a/changelogs/unreleased/send-chat-notification-when-deployment-starts.yml b/changelogs/unreleased/send-chat-notification-when-deployment-starts.yml
new file mode 100644
index 00000000000..d9330677a85
--- /dev/null
+++ b/changelogs/unreleased/send-chat-notification-when-deployment-starts.yml
@@ -0,0 +1,5 @@
+---
+title: Send chat notification when deployment starts
+merge_request: 41214
+author: Sashi Kumar
+type: added
diff --git a/changelogs/unreleased/set-performance-bar-cookie-expiry.yml b/changelogs/unreleased/set-performance-bar-cookie-expiry.yml
new file mode 100644
index 00000000000..bfeccc075d2
--- /dev/null
+++ b/changelogs/unreleased/set-performance-bar-cookie-expiry.yml
@@ -0,0 +1,5 @@
+---
+title: Set performance cookie to last for a year
+merge_request: 43692
+author:
+type: changed
diff --git a/changelogs/unreleased/sh-active-include-lfs-in-archives.yml b/changelogs/unreleased/sh-active-include-lfs-in-archives.yml
new file mode 100644
index 00000000000..b04f362d130
--- /dev/null
+++ b/changelogs/unreleased/sh-active-include-lfs-in-archives.yml
@@ -0,0 +1,5 @@
+---
+title: Include LFS blobs in archives
+merge_request: 44116
+author:
+type: added
diff --git a/changelogs/unreleased/sh-destroy-hook-logs-in-batches.yml b/changelogs/unreleased/sh-destroy-hook-logs-in-batches.yml
new file mode 100644
index 00000000000..eb0a9174fe4
--- /dev/null
+++ b/changelogs/unreleased/sh-destroy-hook-logs-in-batches.yml
@@ -0,0 +1,5 @@
+---
+title: Fix Web hook deletion not working when many hook logs are present
+merge_request: 43464
+author:
+type: fixed
diff --git a/changelogs/unreleased/sh-fix-pipeline-notification-email-warning.yml b/changelogs/unreleased/sh-fix-pipeline-notification-email-warning.yml
new file mode 100644
index 00000000000..a9f5ddcef33
--- /dev/null
+++ b/changelogs/unreleased/sh-fix-pipeline-notification-email-warning.yml
@@ -0,0 +1,5 @@
+---
+title: Update pipeline failed notification e-mail warning
+merge_request: 42736
+author:
+type: fixed
diff --git a/changelogs/unreleased/sh-improve-merge-error-display.yml b/changelogs/unreleased/sh-improve-merge-error-display.yml
new file mode 100644
index 00000000000..dd008563b04
--- /dev/null
+++ b/changelogs/unreleased/sh-improve-merge-error-display.yml
@@ -0,0 +1,5 @@
+---
+title: Fix unnecessarily escaped merge error text
+merge_request: 44844
+author:
+type: fixed
diff --git a/changelogs/unreleased/sh-lfs-smudge-api.yml b/changelogs/unreleased/sh-lfs-smudge-api.yml
new file mode 100644
index 00000000000..cab857aabbc
--- /dev/null
+++ b/changelogs/unreleased/sh-lfs-smudge-api.yml
@@ -0,0 +1,5 @@
+---
+title: Add internal API to download LFS objects
+merge_request: 42161
+author:
+type: added
diff --git a/changelogs/unreleased/sh-update-gitlab-shell-13-10.yml b/changelogs/unreleased/sh-update-gitlab-shell-13-10.yml
new file mode 100644
index 00000000000..ac086f5d6a1
--- /dev/null
+++ b/changelogs/unreleased/sh-update-gitlab-shell-13-10.yml
@@ -0,0 +1,5 @@
+---
+title: Update gitlab-shell to v13.10.0
+merge_request: 45408
+author:
+type: changed
diff --git a/changelogs/unreleased/sh-update-puma-memory-limits.yml b/changelogs/unreleased/sh-update-puma-memory-limits.yml
new file mode 100644
index 00000000000..65161fda80b
--- /dev/null
+++ b/changelogs/unreleased/sh-update-puma-memory-limits.yml
@@ -0,0 +1,5 @@
+---
+title: Raise Puma Worker Killer RAM limits
+merge_request: 45116
+author:
+type: changed
diff --git a/changelogs/unreleased/sh-update-rack-2-1-4.yml b/changelogs/unreleased/sh-update-rack-2-1-4.yml
new file mode 100644
index 00000000000..4be62c3b017
--- /dev/null
+++ b/changelogs/unreleased/sh-update-rack-2-1-4.yml
@@ -0,0 +1,5 @@
+---
+title: Update to Rack v2.1.4
+merge_request: 45340
+author:
+type: fixed
diff --git a/changelogs/unreleased/sh-upgrade-gitlab-shell-13-8.yml b/changelogs/unreleased/sh-upgrade-gitlab-shell-13-8.yml
new file mode 100644
index 00000000000..3c05570343f
--- /dev/null
+++ b/changelogs/unreleased/sh-upgrade-gitlab-shell-13-8.yml
@@ -0,0 +1,5 @@
+---
+title: Upgrade gitlab-shell to v13.8.0
+merge_request: 44852
+author:
+type: other
diff --git a/changelogs/unreleased/sh-usage-data-pg-system-id.yml b/changelogs/unreleased/sh-usage-data-pg-system-id.yml
new file mode 100644
index 00000000000..e8cf62e902d
--- /dev/null
+++ b/changelogs/unreleased/sh-usage-data-pg-system-id.yml
@@ -0,0 +1,5 @@
+---
+title: Include PostgreSQL system identifier in usage ping
+merge_request: 44972
+author:
+type: added
diff --git a/changelogs/unreleased/sk-250667-fix-block-user-api.yml b/changelogs/unreleased/sk-250667-fix-block-user-api.yml
new file mode 100644
index 00000000000..7259027c684
--- /dev/null
+++ b/changelogs/unreleased/sk-250667-fix-block-user-api.yml
@@ -0,0 +1,5 @@
+---
+title: Fix 500 error in block user API for internal user
+merge_request: 43461
+author: Sashi Kumar
+type: fixed
diff --git a/changelogs/unreleased/sk-250679-fix-deactivate-user-api.yml b/changelogs/unreleased/sk-250679-fix-deactivate-user-api.yml
new file mode 100644
index 00000000000..6ecd19d877c
--- /dev/null
+++ b/changelogs/unreleased/sk-250679-fix-deactivate-user-api.yml
@@ -0,0 +1,5 @@
+---
+title: Fix incorrect HTTP response in deactivate user API for internal user
+merge_request: 43356
+author: Sashi Kumar
+type: fixed
diff --git a/changelogs/unreleased/spec_job_token.yml b/changelogs/unreleased/spec_job_token.yml
new file mode 100644
index 00000000000..bf7f32eaab5
--- /dev/null
+++ b/changelogs/unreleased/spec_job_token.yml
@@ -0,0 +1,5 @@
+---
+title: Move job token specs to core
+merge_request: 42374
+author: Mathieu Parent
+type: changed
diff --git a/changelogs/unreleased/ss-add-apply-to-assignees.yml b/changelogs/unreleased/ss-add-apply-to-assignees.yml
new file mode 100644
index 00000000000..ed370175363
--- /dev/null
+++ b/changelogs/unreleased/ss-add-apply-to-assignees.yml
@@ -0,0 +1,5 @@
+---
+title: Add apply button when user changes assignees
+merge_request: 44812
+author:
+type: added
diff --git a/changelogs/unreleased/sy-alert-integrations-table.yml b/changelogs/unreleased/sy-alert-integrations-table.yml
new file mode 100644
index 00000000000..70fe1b19159
--- /dev/null
+++ b/changelogs/unreleased/sy-alert-integrations-table.yml
@@ -0,0 +1,5 @@
+---
+title: Add table for alert http integrations for project
+merge_request: 43634
+author:
+type: added
diff --git a/changelogs/unreleased/sy-allow-guests-to-view-incidents.yml b/changelogs/unreleased/sy-allow-guests-to-view-incidents.yml
new file mode 100644
index 00000000000..5b7fdc80389
--- /dev/null
+++ b/changelogs/unreleased/sy-allow-guests-to-view-incidents.yml
@@ -0,0 +1,5 @@
+---
+title: Show incident list for users who can read issues
+merge_request: 43060
+author:
+type: fixed
diff --git a/changelogs/unreleased/sy-improve-generic-alert-system-note.yml b/changelogs/unreleased/sy-improve-generic-alert-system-note.yml
new file mode 100644
index 00000000000..e12f408753f
--- /dev/null
+++ b/changelogs/unreleased/sy-improve-generic-alert-system-note.yml
@@ -0,0 +1,5 @@
+---
+title: Include monitoring tool from payload in system note for alert creation
+merge_request: 42631
+author:
+type: changed
diff --git a/changelogs/unreleased/sy-truncate-alert-fields.yml b/changelogs/unreleased/sy-truncate-alert-fields.yml
new file mode 100644
index 00000000000..e929cde65f9
--- /dev/null
+++ b/changelogs/unreleased/sy-truncate-alert-fields.yml
@@ -0,0 +1,5 @@
+---
+title: Truncate over-long alert fields instead of return error response
+merge_request: 45099
+author:
+type: changed
diff --git a/changelogs/unreleased/tr-add-detail-fields-to-table.yml b/changelogs/unreleased/tr-add-detail-fields-to-table.yml
new file mode 100644
index 00000000000..f4992b7a0f6
--- /dev/null
+++ b/changelogs/unreleased/tr-add-detail-fields-to-table.yml
@@ -0,0 +1,5 @@
+---
+title: Add hosts field to alert detail table
+merge_request: 43087
+author:
+type: changed
diff --git a/changelogs/unreleased/tr-filter-internal-strings.yml b/changelogs/unreleased/tr-filter-internal-strings.yml
new file mode 100644
index 00000000000..e761c5d54cd
--- /dev/null
+++ b/changelogs/unreleased/tr-filter-internal-strings.yml
@@ -0,0 +1,5 @@
+---
+title: Remove internal fields from alert details table
+merge_request: 43076
+author:
+type: changed
diff --git a/changelogs/unreleased/tz-lazy-load-cropper.yml b/changelogs/unreleased/tz-lazy-load-cropper.yml
new file mode 100644
index 00000000000..41f9e01940a
--- /dev/null
+++ b/changelogs/unreleased/tz-lazy-load-cropper.yml
@@ -0,0 +1,5 @@
+---
+title: Loads cropper css only when needed
+merge_request: 44137
+author:
+type: performance
diff --git a/changelogs/unreleased/tz-preload-iconfont.yml b/changelogs/unreleased/tz-preload-iconfont.yml
new file mode 100644
index 00000000000..12c7fd914af
--- /dev/null
+++ b/changelogs/unreleased/tz-preload-iconfont.yml
@@ -0,0 +1,5 @@
+---
+title: Preloading of Fontawesome Icon Font
+merge_request: 44282
+author:
+type: performance
diff --git a/changelogs/unreleased/unleash-api-with-private-repo.yml b/changelogs/unreleased/unleash-api-with-private-repo.yml
new file mode 100644
index 00000000000..3dcdfcdd899
--- /dev/null
+++ b/changelogs/unreleased/unleash-api-with-private-repo.yml
@@ -0,0 +1,5 @@
+---
+title: Allow Unleash clients to request feature flags when repository is private
+merge_request: 43059
+author:
+type: fixed
diff --git a/changelogs/unreleased/update-clipboard-button.yml b/changelogs/unreleased/update-clipboard-button.yml
new file mode 100644
index 00000000000..03eff85ab32
--- /dev/null
+++ b/changelogs/unreleased/update-clipboard-button.yml
@@ -0,0 +1,5 @@
+---
+title: Update clipboard button to use Pajamas
+merge_request: 38421
+author:
+type: changed
diff --git a/changelogs/unreleased/update-cluster-applications-34.yml b/changelogs/unreleased/update-cluster-applications-34.yml
new file mode 100644
index 00000000000..5a7a17c2fae
--- /dev/null
+++ b/changelogs/unreleased/update-cluster-applications-34.yml
@@ -0,0 +1,5 @@
+---
+title: Bump cluster applications CI template
+merge_request: 45472
+author:
+type: other
diff --git a/changelogs/unreleased/update-gitlab-runner-helm-chart-to-0-21-0.yml b/changelogs/unreleased/update-gitlab-runner-helm-chart-to-0-21-0.yml
new file mode 100644
index 00000000000..0b4b92717e7
--- /dev/null
+++ b/changelogs/unreleased/update-gitlab-runner-helm-chart-to-0-21-0.yml
@@ -0,0 +1,5 @@
+---
+title: Update GitLab Runner Helm Chart to 0.21.0
+merge_request: 42844
+author:
+type: other
diff --git a/changelogs/unreleased/update-members-api-for-multiple-user_ids.yml b/changelogs/unreleased/update-members-api-for-multiple-user_ids.yml
new file mode 100644
index 00000000000..49c3c97c5c1
--- /dev/null
+++ b/changelogs/unreleased/update-members-api-for-multiple-user_ids.yml
@@ -0,0 +1,5 @@
+---
+title: Update Add Members API to accept user_id array
+merge_request: 44051
+author:
+type: added
diff --git a/changelogs/unreleased/upgrade-rouge-to-3-24.yml b/changelogs/unreleased/upgrade-rouge-to-3-24.yml
new file mode 100644
index 00000000000..3e20dfde007
--- /dev/null
+++ b/changelogs/unreleased/upgrade-rouge-to-3-24.yml
@@ -0,0 +1,5 @@
+---
+title: Update Rouge to v3.24
+merge_request: 45225
+author:
+type: other
diff --git a/changelogs/unreleased/upgrate-gitlab-pages-to-1-28-0.yml b/changelogs/unreleased/upgrate-gitlab-pages-to-1-28-0.yml
new file mode 100644
index 00000000000..ab5258051ae
--- /dev/null
+++ b/changelogs/unreleased/upgrate-gitlab-pages-to-1-28-0.yml
@@ -0,0 +1,5 @@
+---
+title: Upgrade GitLab Pages to 1.28.0
+merge_request: 45257
+author:
+type: added
diff --git a/changelogs/unreleased/use_mirror_of_helm_stable_repo.yml b/changelogs/unreleased/use_mirror_of_helm_stable_repo.yml
new file mode 100644
index 00000000000..479ed48ce89
--- /dev/null
+++ b/changelogs/unreleased/use_mirror_of_helm_stable_repo.yml
@@ -0,0 +1,5 @@
+---
+title: "GitLab-managed apps: Use GitLab's repo as replacement for the Helm stable repo"
+merge_request: 44875
+author:
+type: other
diff --git a/changelogs/unreleased/vij-public-project-snippets.yml b/changelogs/unreleased/vij-public-project-snippets.yml
new file mode 100644
index 00000000000..2cbc97cb469
--- /dev/null
+++ b/changelogs/unreleased/vij-public-project-snippets.yml
@@ -0,0 +1,5 @@
+---
+title: Allow unauthenticated users access to public Project Snippets via the REST API
+merge_request: 44446
+author:
+type: fixed
diff --git a/changelogs/unreleased/vij-public-snippet-access.yml b/changelogs/unreleased/vij-public-snippet-access.yml
new file mode 100644
index 00000000000..8a6bb324e75
--- /dev/null
+++ b/changelogs/unreleased/vij-public-snippet-access.yml
@@ -0,0 +1,5 @@
+---
+title: Allow unauthenticated users access to public Personal Snippets via the REST API
+merge_request: 44135
+author:
+type: fixed
diff --git a/changelogs/unreleased/wiki-editor-ux-debt-1.yml b/changelogs/unreleased/wiki-editor-ux-debt-1.yml
new file mode 100644
index 00000000000..60f16c315bb
--- /dev/null
+++ b/changelogs/unreleased/wiki-editor-ux-debt-1.yml
@@ -0,0 +1,5 @@
+---
+title: Move wiki edit button inline with wiki title
+merge_request: 44391
+author:
+type: changed
diff --git a/changelogs/unreleased/wiki-editor-ux-debt-2.yml b/changelogs/unreleased/wiki-editor-ux-debt-2.yml
new file mode 100644
index 00000000000..93a4c2609cc
--- /dev/null
+++ b/changelogs/unreleased/wiki-editor-ux-debt-2.yml
@@ -0,0 +1,5 @@
+---
+title: Reposition wiki title on wiki pages
+merge_request: 44390
+author:
+type: changed
diff --git a/changelogs/unreleased/zj-bump-shell.yml b/changelogs/unreleased/zj-bump-shell.yml
new file mode 100644
index 00000000000..61e808e7071
--- /dev/null
+++ b/changelogs/unreleased/zj-bump-shell.yml
@@ -0,0 +1,5 @@
+---
+title: Update GitLab-Shell to v13.9.0
+merge_request: 45358
+author:
+type: changed
diff --git a/changelogs/unreleased/zj-update-lang-colors.yml b/changelogs/unreleased/zj-update-lang-colors.yml
new file mode 100644
index 00000000000..72b2bc01b08
--- /dev/null
+++ b/changelogs/unreleased/zj-update-lang-colors.yml
@@ -0,0 +1,5 @@
+---
+title: Update programming language colors and metadata
+merge_request: 43111
+author:
+type: changed
diff --git a/config/application.rb b/config/application.rb
index 4d2f3745b52..75befc8a248 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -1,3 +1,4 @@
+# frozen_string_literal: true
require_relative 'boot'
# Based on https://github.com/rails/rails/blob/v6.0.1/railties/lib/rails/all.rb
@@ -27,6 +28,7 @@ module Gitlab
require_dependency Rails.root.join('lib/gitlab/middleware/basic_health_check')
require_dependency Rails.root.join('lib/gitlab/middleware/same_site_cookies')
require_dependency Rails.root.join('lib/gitlab/middleware/handle_ip_spoof_attack_error')
+ require_dependency Rails.root.join('lib/gitlab/middleware/handle_null_bytes')
require_dependency Rails.root.join('lib/gitlab/runtime')
# Settings in config/environments/* take precedence over those specified here.
@@ -127,12 +129,12 @@ module Gitlab
/^description$/,
/^note$/,
/^text$/,
- /^title$/
+ /^title$/,
+ /^hook$/
]
config.filter_parameters += %i(
certificate
encrypted_key
- hook
import_url
elasticsearch_url
otp_attempt
@@ -151,14 +153,6 @@ module Gitlab
# like if you have constraints or database-specific column types
config.active_record.schema_format = :sql
- # Configure webpack
- config.webpack.config_file = "config/webpack.config.js"
- config.webpack.output_dir = "public/assets/webpack"
- config.webpack.public_path = "assets/webpack"
-
- # Webpack dev server configuration is handled in initializers/static_files.rb
- config.webpack.dev_server.enabled = false
-
config.action_mailer.delivery_job = "ActionMailer::MailDeliveryJob"
# Enable the asset pipeline
@@ -168,6 +162,8 @@ module Gitlab
config.assets.paths << Gemojione.images_path
config.assets.paths << "#{config.root}/vendor/assets/fonts"
+ config.assets.precompile << "application_utilities.css"
+ config.assets.precompile << "application_utilities_dark.css"
config.assets.precompile << "application_dark.css"
config.assets.precompile << "startup/*.css"
@@ -178,10 +174,29 @@ module Gitlab
config.assets.precompile << "notify.css"
config.assets.precompile << "mailers/*.css"
config.assets.precompile << "page_bundles/_mixins_and_variables_and_functions.css"
+ config.assets.precompile << "page_bundles/boards.css"
+ config.assets.precompile << "page_bundles/cycle_analytics.css"
+ config.assets.precompile << "page_bundles/dev_ops_report.css"
+ config.assets.precompile << "page_bundles/environments.css"
+ config.assets.precompile << "page_bundles/error_tracking_details.css"
+ config.assets.precompile << "page_bundles/error_tracking_index.css"
+ config.assets.precompile << "page_bundles/experimental_separate_sign_up.css"
config.assets.precompile << "page_bundles/ide.css"
+ config.assets.precompile << "page_bundles/issues_list.css"
config.assets.precompile << "page_bundles/jira_connect.css"
+ config.assets.precompile << "page_bundles/jira_connect_users.css"
+ config.assets.precompile << "page_bundles/merge_conflicts.css"
+ config.assets.precompile << "page_bundles/merge_requests.css"
+ config.assets.precompile << "page_bundles/milestone.css"
+ config.assets.precompile << "page_bundles/pipeline.css"
+ config.assets.precompile << "page_bundles/pipelines.css"
+ config.assets.precompile << "page_bundles/productivity_analytics.css"
+ config.assets.precompile << "page_bundles/terminal.css"
config.assets.precompile << "page_bundles/todos.css"
+ config.assets.precompile << "page_bundles/reports.css"
config.assets.precompile << "page_bundles/xterm.css"
+ config.assets.precompile << "page_bundles/wiki.css"
+ config.assets.precompile << "lazy_bundles/cropper.css"
config.assets.precompile << "performance_bar.css"
config.assets.precompile << "lib/ace.js"
config.assets.precompile << "disable_animations.css"
@@ -210,13 +225,6 @@ module Gitlab
config.assets.paths << "#{config.root}/node_modules/xterm/src/"
config.assets.precompile << "xterm.css"
- # Add EE assets
- if Gitlab.ee?
- %w[images javascripts stylesheets].each do |path|
- config.assets.paths << "#{config.root}/ee/app/assets/#{path}"
- end
- end
-
# Import path for EE specific SCSS entry point
# In CE it will import a noop file, in EE a functioning file
# Order is important, so that the ee file takes precedence:
@@ -230,16 +238,6 @@ module Gitlab
# See https://gitlab.com/gitlab-org/gitlab-foss/issues/64091#note_194512508
config.assets.paths << "#{config.root}/node_modules"
- if Gitlab.ee?
- # Compile non-JS/CSS assets in the ee/app/assets folder by default
- # Mimic sprockets-rails default: https://github.com/rails/sprockets-rails/blob/v3.2.1/lib/sprockets/railtie.rb#L84-L87
- LOOSE_EE_APP_ASSETS = lambda do |logical_path, filename|
- filename.start_with?(config.root.join("ee/app/assets").to_s) &&
- !['.js', '.css', ''].include?(File.extname(logical_path))
- end
- config.assets.precompile << LOOSE_EE_APP_ASSETS
- end
-
# Version of your assets, change this if you want to expire all your assets
config.assets.version = '1.0'
@@ -256,6 +254,8 @@ module Gitlab
config.middleware.insert_before ActionDispatch::RemoteIp, ::Gitlab::Middleware::HandleIpSpoofAttackError
+ config.middleware.use ::Gitlab::Middleware::HandleNullBytes
+
# Allow access to GitLab API from other domains
config.middleware.insert_before Warden::Manager, Rack::Cors do
headers_to_expose = %w[Link X-Total X-Total-Pages X-Per-Page X-Page X-Next-Page X-Prev-Page X-Gitlab-Blob-Id X-Gitlab-Commit-Id X-Gitlab-Content-Sha256 X-Gitlab-Encoding X-Gitlab-File-Name X-Gitlab-File-Path X-Gitlab-Last-Commit-Id X-Gitlab-Ref X-Gitlab-Size]
@@ -304,6 +304,34 @@ module Gitlab
g.factory_bot false
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.
+ #
+ # In our case this copies for example: Vue, Markdown and Graphql, which we do not need
+ # for production.
+ #
+ # We remove this default behavior and then reimplement it in order to consider ee/ as well
+ # and remove those other files we do not need.
+ #
+ # For reference: https://github.com/rails/sprockets-rails/blob/v3.2.1/lib/sprockets/railtie.rb#L84-L87
+ initializer :correct_precompile_targets, after: :set_default_precompile do |app|
+ app.config.assets.precompile.reject! { |entry| entry == Sprockets::Railtie::LOOSE_APP_ASSETS }
+
+ asset_roots = [config.root.join("app/assets").to_s]
+
+ if Gitlab.ee?
+ asset_roots << config.root.join("ee/app/assets").to_s
+ end
+
+ LOOSE_APP_ASSETS = lambda do |logical_path, filename|
+ filename.start_with?(*asset_roots) &&
+ !['.js', '.css', '.md', '.vue', '.graphql', ''].include?(File.extname(logical_path))
+ end
+
+ app.config.assets.precompile << LOOSE_APP_ASSETS
+ end
+
# This empty initializer forces the :let_zeitwerk_take_over initializer to run before we load
# initializers in config/initializers. This is done because autoloading before Zeitwerk takes
# over is deprecated but our initializers do a lot of autoloading.
@@ -318,6 +346,20 @@ module Gitlab
end
end
+ # Add EE assets. They should take precedence over CE. This means if two files exist, e.g.:
+ #
+ # ee/app/assets/stylesheets/example.scss
+ # app/assets/stylesheets/example.scss
+ #
+ # The ee/ version will be preferred.
+ initializer :prefer_ee_assets, after: :append_assets_path do |app|
+ if Gitlab.ee?
+ %w[images javascripts stylesheets].each do |path|
+ app.config.assets.paths.unshift("#{config.root}/ee/app/assets/#{path}")
+ end
+ end
+ end
+
config.after_initialize do
# Devise (see initializers/8_devise.rb) already reloads routes if
# eager loading is enabled, so don't do this twice since it's
diff --git a/config/database.yml.postgresql b/config/database.yml.postgresql
index 37c69ad326b..ca1ff4db1b4 100644
--- a/config/database.yml.postgresql
+++ b/config/database.yml.postgresql
@@ -28,6 +28,8 @@ development:
username: postgres
password: "secure password"
host: localhost
+ variables:
+ statement_timeout: 15s
#
# Staging specific
@@ -51,3 +53,5 @@ test: &test
password:
host: localhost
prepared_statements: false
+ variables:
+ statement_timeout: 15s
diff --git a/config/dependency_decisions.yml b/config/dependency_decisions.yml
index 2f0d9066a7a..c12ede63fba 100644
--- a/config/dependency_decisions.yml
+++ b/config/dependency_decisions.yml
@@ -18,85 +18,85 @@
:why: Bundler is MIT licensed but will sometimes fail in CI.
:versions: []
:when: 2016-05-02 06:42:08.045090000 Z
-- - :whitelist
+- - :permit
- MIT
- :who: Connor Shea
:why: http://choosealicense.com/licenses/mit/
:versions: []
:when: 2016-04-17 21:12:24.558441000 Z
-- - :whitelist
+- - :permit
- Apache 2.0
- :who: Connor Shea
:why: http://choosealicense.com/licenses/apache-2.0/
:versions: []
:when: 2016-05-02 05:27:43.762702000 Z
-- - :whitelist
+- - :permit
- ruby
- :who: Connor Shea
:why: https://github.com/ruby/ruby/blob/ruby_2_1/COPYING
:versions: []
:when: 2016-05-02 05:31:54.498490000 Z
-- - :whitelist
+- - :permit
- LGPL
- :who: Connor Shea
:why: http://www.gnu.org/licenses/license-list.html#LGPLv2.1
:versions: []
:when: 2016-05-02 05:32:48.645841000 Z
-- - :whitelist
+- - :permit
- ISC
- :who: Connor Shea
:why: http://www.gnu.org/licenses/license-list.html#ISC
:versions: []
:when: 2016-05-02 05:42:01.894452000 Z
-- - :whitelist
+- - :permit
- New BSD
- :who: Connor Shea
:why: https://opensource.org/licenses/BSD-3-Clause
:versions: []
:when: 2016-05-02 05:44:38.246021000 Z
-- - :whitelist
+- - :permit
- LGPL-2.1+
- :who: Connor Shea
:why: Equivalent to LGPL.
:versions: []
:when: 2016-05-02 05:52:56.303239000 Z
-- - :whitelist
+- - :permit
- BSD
- :who: Connor Shea
:why: https://opensource.org/licenses/BSD-2-Clause
:versions: []
:when: 2016-05-02 05:55:09.796363000 Z
-- - :whitelist
+- - :permit
- LGPLv2+
- :who: Stan Hu
:why: Equivalent to LGPLv2
:versions: []
:when: 2016-06-07 17:14:10.907682000 Z
-- - :whitelist
+- - :permit
- Artistic 2.0
- :who: Josh Frye
:why: Disk/mount information display on Admin pages
:versions: []
:when: 2016-06-29 16:32:45.432113000 Z
-- - :whitelist
+- - :permit
- Simplified BSD
- :who: Douwe Maan
:why: https://opensource.org/licenses/BSD-2-Clause
:versions: []
:when: 2016-07-26 21:24:07.248480000 Z
-- - :blacklist
+- - :restrict
- GPLv2
- :who: Connor Shea
:why: GPL-licensed libraries cannot be linked to from non-GPL projects.
:versions: []
:when: 2016-05-02 05:29:27.637336000 Z
-- - :blacklist
+- - :restrict
- GPLv3
- :who: Connor Shea
:why: GPL-licensed libraries cannot be linked to from non-GPL projects.
:versions: []
:when: 2016-05-02 05:29:43.904715000 Z
-- - :blacklist
+- - :restrict
- OSL-3.0
- :who: Sean McGivern
:why: The OSL license is a copyleft license
@@ -188,13 +188,13 @@
:why: https://github.com/nodeca/pako/blob/master/LICENSE
:versions: []
:when: 2017-04-05 10:43:45.897720000 Z
-- - :whitelist
+- - :permit
- Unlicense
- :who: Nick Thomas <nick@gitlab.com>
:why: https://gitlab.com/gitlab-com/organization/issues/116
:versions: []
:when: 2017-09-01 17:17:51.996511844 Z
-- - :blacklist
+- - :restrict
- Facebook BSD+PATENTS
- :who: Nick Thomas <nick@gitlab.com>
:why: https://gitlab.com/gitlab-com/organization/issues/117
@@ -281,19 +281,19 @@
:why: https://github.com/hexorx/countries/blob/master/LICENSE
:versions: []
:when: 2019-09-11 13:08:28.431132000 Z
-- - :whitelist
+- - :permit
- "(MIT OR CC0-1.0)"
- :who:
:why:
:versions: []
:when: 2019-11-08 10:03:31.787226000 Z
-- - :whitelist
+- - :permit
- CC0-1.0
- :who: Thomas Randolph
:why: This license is public domain
:versions: []
:when: 2020-06-03 05:04:44.632875345 Z
-- - :whitelist
+- - :permit
- 0BSD
- :who: Natalia Tepluhina
:why: This license is public domain
@@ -313,9 +313,15 @@
:why: "https://github.com/cure53/DOMPurify/blob/main/LICENSE and https://gitlab.com/gitlab-org/gitlab/-/merge_requests/31928#note_346604841"
:versions: []
:when: 2020-08-13 13:42:46.508082000 Z
-- - :whitelist
+- - :permit
- Apache-2.0 WITH LLVM-exception
- :who: Nathan Friend
:why: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/40670#note_403946372
:versions: []
:when: 2020-08-28 15:01:59.329048917 Z
+- - :approve
+ - docutils
+ - :who: Mo Khan
+ :why: Used to generate documentation. https://pypi.org/project/docutils/0.13.1/
+ :versions: []
+ :when: 2020-10-05 20:22:55.955189491 Z
diff --git a/config/environments/production.rb b/config/environments/production.rb
index 393a274606e..d9b3ee354b0 100644
--- a/config/environments/production.rb
+++ b/config/environments/production.rb
@@ -12,7 +12,7 @@ Rails.application.configure do
config.public_file_server.enabled = false
# Compress JavaScripts and CSS.
- config.assets.js_compressor = :uglifier
+ config.assets.js_compressor = :terser
# config.assets.css_compressor = :sass
# Don't fallback to assets pipeline if a precompiled asset is missed
diff --git a/config/feature_categories.yml b/config/feature_categories.yml
index 7b85f910d85..edf7bba27a3 100644
--- a/config/feature_categories.yml
+++ b/config/feature_categories.yml
@@ -19,7 +19,7 @@
- auto_devops
- backup_restore
- behavior_analytics
-- billing
+- boards
- chatops
- cloud_native_installation
- cluster_cost_optimization
@@ -49,7 +49,7 @@
- error_tracking
- feature_flags
- foundations
-- fuzz-testing
+- fuzz_testing
- gdk
- geo_replication
- git_lfs
@@ -62,15 +62,15 @@
- importers
- incident_management
- infrastructure_as_code
+- insights
+- instance_statistics
- integrations
- interactive_application_security_testing
- internationalization
-- instance_statistics
- issue_tracking
- jenkins_importer
- jira_importer
- jupyter_notebooks
-- kanban_boards
- kubernetes_management
- license_compliance
- live_preview
@@ -83,10 +83,13 @@
- omnibus_package
- package_registry
- pages
+- pipeline_authoring
- pki_management
- planning_analytics
- product_analytics
- projects
+- provision
+- purchase
- quality_management
- release_evidence
- release_orchestration
diff --git a/config/feature_flags/development/additional_snowplow_tracking.yml b/config/feature_flags/development/additional_snowplow_tracking.yml
index f4f73a0bbd0..3e2b542b1a8 100644
--- a/config/feature_flags/development/additional_snowplow_tracking.yml
+++ b/config/feature_flags/development/additional_snowplow_tracking.yml
@@ -1,7 +1,6 @@
----
name: additional_snowplow_tracking
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/12088
+rollout_issue_url:
+group: group::product analytics
type: development
default_enabled: false
diff --git a/config/feature_flags/development/admin_approval_for_new_user_signups.yml b/config/feature_flags/development/admin_approval_for_new_user_signups.yml
new file mode 100644
index 00000000000..0cde210e6a0
--- /dev/null
+++ b/config/feature_flags/development/admin_approval_for_new_user_signups.yml
@@ -0,0 +1,7 @@
+---
+name: admin_approval_for_new_user_signups
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/43827
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/258980
+type: development
+group: group::access
+default_enabled: true
diff --git a/config/feature_flags/development/ajax_new_deploy_token.yml b/config/feature_flags/development/ajax_new_deploy_token.yml
index cffd589b32b..336e3004d52 100644
--- a/config/feature_flags/development/ajax_new_deploy_token.yml
+++ b/config/feature_flags/development/ajax_new_deploy_token.yml
@@ -1,7 +1,7 @@
---
name: ajax_new_deploy_token
-introduced_by_url:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/27141
rollout_issue_url:
-group:
+group: group::progressive delivery
type: development
default_enabled: false
diff --git a/config/feature_flags/development/allow_group_deploy_token.yml b/config/feature_flags/development/allow_group_deploy_token.yml
index f08614b45e9..06a8659292d 100644
--- a/config/feature_flags/development/allow_group_deploy_token.yml
+++ b/config/feature_flags/development/allow_group_deploy_token.yml
@@ -1,7 +1,7 @@
---
name: allow_group_deploy_token
-introduced_by_url:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/23460
rollout_issue_url:
-group:
+group: group::progressive delivery
type: development
default_enabled: true
diff --git a/config/feature_flags/development/allow_possible_spam.yml b/config/feature_flags/development/allow_possible_spam.yml
index 658e775af91..2e121519628 100644
--- a/config/feature_flags/development/allow_possible_spam.yml
+++ b/config/feature_flags/development/allow_possible_spam.yml
@@ -1,7 +1,7 @@
---
name: allow_possible_spam
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/17604
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/29830
+group: group::portfolio management
type: development
default_enabled: false
diff --git a/config/feature_flags/development/allow_unsafe_ruby_regexp.yml b/config/feature_flags/development/allow_unsafe_ruby_regexp.yml
index 4d3b13deda2..272e9f5ffa2 100644
--- a/config/feature_flags/development/allow_unsafe_ruby_regexp.yml
+++ b/config/feature_flags/development/allow_unsafe_ruby_regexp.yml
@@ -1,7 +1,7 @@
---
name: allow_unsafe_ruby_regexp
introduced_by_url:
-rollout_issue_url:
-group:
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/257849
type: development
+group: group::continuous integration
default_enabled: false
diff --git a/config/feature_flags/development/api_kaminari_count_with_limit.yml b/config/feature_flags/development/api_kaminari_count_with_limit.yml
deleted file mode 100644
index 0224d606df1..00000000000
--- a/config/feature_flags/development/api_kaminari_count_with_limit.yml
+++ /dev/null
@@ -1,7 +0,0 @@
----
-name: api_kaminari_count_with_limit
-introduced_by_url:
-rollout_issue_url:
-group:
-type: development
-default_enabled: false
diff --git a/config/feature_flags/development/artifacts_management_page.yml b/config/feature_flags/development/artifacts_management_page.yml
index 94d99974859..78659422a39 100644
--- a/config/feature_flags/development/artifacts_management_page.yml
+++ b/config/feature_flags/development/artifacts_management_page.yml
@@ -1,7 +1,7 @@
---
name: artifacts_management_page
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/16654
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/254938
+group: group::continuous integration
type: development
default_enabled: false
diff --git a/config/feature_flags/development/auto_create_cluster_management_project.yml b/config/feature_flags/development/auto_create_cluster_management_project.yml
index ca87e401d4a..d3b88f056ec 100644
--- a/config/feature_flags/development/auto_create_cluster_management_project.yml
+++ b/config/feature_flags/development/auto_create_cluster_management_project.yml
@@ -1,7 +1,7 @@
---
name: auto_create_cluster_management_project
-introduced_by_url:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/23946
rollout_issue_url:
-group:
+group: group::configure
type: development
default_enabled: false
diff --git a/config/feature_flags/development/backfill_partitioned_audit_events.yml b/config/feature_flags/development/backfill_partitioned_audit_events.yml
deleted file mode 100644
index ae986c941cb..00000000000
--- a/config/feature_flags/development/backfill_partitioned_audit_events.yml
+++ /dev/null
@@ -1,7 +0,0 @@
----
-name: backfill_partitioned_audit_events
-introduced_by_url:
-rollout_issue_url:
-group:
-type: development
-default_enabled: true
diff --git a/config/feature_flags/development/boards_with_swimlanes.yml b/config/feature_flags/development/boards_with_swimlanes.yml
index e2db136b45c..19e5ab24206 100644
--- a/config/feature_flags/development/boards_with_swimlanes.yml
+++ b/config/feature_flags/development/boards_with_swimlanes.yml
@@ -1,7 +1,7 @@
---
name: boards_with_swimlanes
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url:
+rollout_issue_url:
+group: group::project management
type: development
default_enabled: false
diff --git a/config/feature_flags/development/branch_push_merge_commit_analyze.yml b/config/feature_flags/development/branch_push_merge_commit_analyze.yml
deleted file mode 100644
index f5a695a9ce9..00000000000
--- a/config/feature_flags/development/branch_push_merge_commit_analyze.yml
+++ /dev/null
@@ -1,7 +0,0 @@
----
-name: branch_push_merge_commit_analyze
-introduced_by_url:
-rollout_issue_url:
-group:
-type: development
-default_enabled: true
diff --git a/config/feature_flags/development/broadcast_issue_updates.yml b/config/feature_flags/development/broadcast_issue_updates.yml
index 2db27dfb2ed..435678f869d 100644
--- a/config/feature_flags/development/broadcast_issue_updates.yml
+++ b/config/feature_flags/development/broadcast_issue_updates.yml
@@ -1,7 +1,7 @@
---
name: broadcast_issue_updates
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/30732
+rollout_issue_url: https://gitlab.com/gitlab-com/gl-infra/delivery/-/issues/1210
+group: group::project management
type: development
default_enabled: false
diff --git a/config/feature_flags/development/build_service_proxy.yml b/config/feature_flags/development/build_service_proxy.yml
index 165e3c15f81..0c0aaa8aca9 100644
--- a/config/feature_flags/development/build_service_proxy.yml
+++ b/config/feature_flags/development/build_service_proxy.yml
@@ -1,7 +1,7 @@
---
name: build_service_proxy
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/9723
+rollout_issue_url:
+group: group::editor
type: development
default_enabled: false
diff --git a/config/feature_flags/development/bulk_import.yml b/config/feature_flags/development/bulk_import.yml
new file mode 100644
index 00000000000..0a5a1e5654e
--- /dev/null
+++ b/config/feature_flags/development/bulk_import.yml
@@ -0,0 +1,7 @@
+---
+name: bulk_import
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/42704
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/255310
+group: group::import
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/bulk_update_health_status.yml b/config/feature_flags/development/bulk_update_health_status.yml
index 5553f2e077f..fa06adfd60a 100644
--- a/config/feature_flags/development/bulk_update_health_status.yml
+++ b/config/feature_flags/development/bulk_update_health_status.yml
@@ -1,7 +1,7 @@
---
name: bulk_update_health_status
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url:
+rollout_issue_url:
+group: group::portfolio management
type: development
default_enabled: true
diff --git a/config/feature_flags/development/burnup_charts.yml b/config/feature_flags/development/burnup_charts.yml
index 9484af49530..5ead8362d90 100644
--- a/config/feature_flags/development/burnup_charts.yml
+++ b/config/feature_flags/development/burnup_charts.yml
@@ -1,7 +1,7 @@
---
name: burnup_charts
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url:
+rollout_issue_url:
+group: group::project management
type: development
default_enabled: false
diff --git a/config/feature_flags/development/cached_markdown_blob.yml b/config/feature_flags/development/cached_markdown_blob.yml
new file mode 100644
index 00000000000..de7a7c52b66
--- /dev/null
+++ b/config/feature_flags/development/cached_markdown_blob.yml
@@ -0,0 +1,7 @@
+---
+name: cached_markdown_blob
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/44300
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/263406
+type: development
+group: group::source code
+default_enabled: true
diff --git a/config/feature_flags/development/canary_ingress_weight_control.yml b/config/feature_flags/development/canary_ingress_weight_control.yml
new file mode 100644
index 00000000000..681ffc98cb5
--- /dev/null
+++ b/config/feature_flags/development/canary_ingress_weight_control.yml
@@ -0,0 +1,7 @@
+---
+name: canary_ingress_weight_control
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/43816
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/260295
+type: development
+group: group::progressive delivery
+default_enabled: false
diff --git a/config/feature_flags/development/ci_always_refresh_merge_requests_from_beginning.yml b/config/feature_flags/development/ci_always_refresh_merge_requests_from_beginning.yml
new file mode 100644
index 00000000000..9e5cae4e4a0
--- /dev/null
+++ b/config/feature_flags/development/ci_always_refresh_merge_requests_from_beginning.yml
@@ -0,0 +1,7 @@
+---
+name: ci_always_refresh_merge_requests_from_beginning
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/45232
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/268215
+type: development
+group: group::continuous integration
+default_enabled: false
diff --git a/config/feature_flags/development/ci_artifacts_exclude.yml b/config/feature_flags/development/ci_artifacts_exclude.yml
index 6e9d27efe42..86398f085d8 100644
--- a/config/feature_flags/development/ci_artifacts_exclude.yml
+++ b/config/feature_flags/development/ci_artifacts_exclude.yml
@@ -1,7 +1,7 @@
---
name: ci_artifacts_exclude
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/30708
+rollout_issue_url:
+group: group::continuous integration
type: development
default_enabled: true
diff --git a/config/feature_flags/development/ci_bridge_pipeline_details.yml b/config/feature_flags/development/ci_bridge_pipeline_details.yml
deleted file mode 100644
index 59c5d978eb0..00000000000
--- a/config/feature_flags/development/ci_bridge_pipeline_details.yml
+++ /dev/null
@@ -1,7 +0,0 @@
----
-name: ci_bridge_pipeline_details
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/41263
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/250683
-group: group::memory
-type: development
-default_enabled: true
diff --git a/config/feature_flags/development/ci_build_metadata_config.yml b/config/feature_flags/development/ci_build_metadata_config.yml
index add7c963272..176abbfd387 100644
--- a/config/feature_flags/development/ci_build_metadata_config.yml
+++ b/config/feature_flags/development/ci_build_metadata_config.yml
@@ -1,7 +1,7 @@
---
name: ci_build_metadata_config
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/7238
+rollout_issue_url:
+group: group::continuous integration
type: development
default_enabled: false
diff --git a/config/feature_flags/development/ci_bulk_insert_on_create.yml b/config/feature_flags/development/ci_bulk_insert_on_create.yml
deleted file mode 100644
index 3227497ecfc..00000000000
--- a/config/feature_flags/development/ci_bulk_insert_on_create.yml
+++ /dev/null
@@ -1,7 +0,0 @@
----
-name: ci_bulk_insert_on_create
-introduced_by_url:
-rollout_issue_url:
-group:
-type: development
-default_enabled: true
diff --git a/config/feature_flags/development/ci_child_of_child_pipeline.yml b/config/feature_flags/development/ci_child_of_child_pipeline.yml
deleted file mode 100644
index 02122076434..00000000000
--- a/config/feature_flags/development/ci_child_of_child_pipeline.yml
+++ /dev/null
@@ -1,7 +0,0 @@
----
-name: ci_child_of_child_pipeline
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/41102
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/243747
-group: 'group::continuous integration'
-type: development
-default_enabled: true
diff --git a/config/feature_flags/development/ci_daily_code_coverage.yml b/config/feature_flags/development/ci_daily_code_coverage.yml
deleted file mode 100644
index c9add1bf460..00000000000
--- a/config/feature_flags/development/ci_daily_code_coverage.yml
+++ /dev/null
@@ -1,7 +0,0 @@
----
-name: ci_daily_code_coverage
-introduced_by_url:
-rollout_issue_url:
-group:
-type: development
-default_enabled: true
diff --git a/config/feature_flags/development/ci_delete_objects_high_concurrency.yml b/config/feature_flags/development/ci_delete_objects_high_concurrency.yml
new file mode 100644
index 00000000000..c2b391f8b8f
--- /dev/null
+++ b/config/feature_flags/development/ci_delete_objects_high_concurrency.yml
@@ -0,0 +1,7 @@
+---
+name: ci_delete_objects_high_concurrency
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/39464
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/247103
+group: group::continuous integration
+type: development
+default_enabled: false \ No newline at end of file
diff --git a/config/feature_flags/development/ci_delete_objects_low_concurrency.yml b/config/feature_flags/development/ci_delete_objects_low_concurrency.yml
new file mode 100644
index 00000000000..cc59e0e3f6f
--- /dev/null
+++ b/config/feature_flags/development/ci_delete_objects_low_concurrency.yml
@@ -0,0 +1,7 @@
+---
+name: ci_delete_objects_low_concurrency
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/39464
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/247103
+group: group::continuous integration
+type: development
+default_enabled: false \ No newline at end of file
diff --git a/config/feature_flags/development/ci_delete_objects_medium_concurrency.yml b/config/feature_flags/development/ci_delete_objects_medium_concurrency.yml
new file mode 100644
index 00000000000..4b72980945c
--- /dev/null
+++ b/config/feature_flags/development/ci_delete_objects_medium_concurrency.yml
@@ -0,0 +1,7 @@
+---
+name: ci_delete_objects_medium_concurrency
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/39464
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/247103
+group: group::continuous integration
+type: development
+default_enabled: false \ No newline at end of file
diff --git a/config/feature_flags/development/ci_disable_validates_dependencies.yml b/config/feature_flags/development/ci_disable_validates_dependencies.yml
index 65358a04340..ccd529d0a09 100644
--- a/config/feature_flags/development/ci_disable_validates_dependencies.yml
+++ b/config/feature_flags/development/ci_disable_validates_dependencies.yml
@@ -1,7 +1,7 @@
---
name: ci_disable_validates_dependencies
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/14009
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/257847
+group: group::continuous integration
type: development
default_enabled: false
diff --git a/config/feature_flags/development/ci_download_daily_code_coverage.yml b/config/feature_flags/development/ci_download_daily_code_coverage.yml
deleted file mode 100644
index d209f2bf9ad..00000000000
--- a/config/feature_flags/development/ci_download_daily_code_coverage.yml
+++ /dev/null
@@ -1,7 +0,0 @@
----
-name: ci_download_daily_code_coverage
-introduced_by_url:
-rollout_issue_url:
-group:
-type: development
-default_enabled: true
diff --git a/config/feature_flags/development/ci_dynamic_child_pipeline.yml b/config/feature_flags/development/ci_dynamic_child_pipeline.yml
index ac2afe77743..c568e9392b2 100644
--- a/config/feature_flags/development/ci_dynamic_child_pipeline.yml
+++ b/config/feature_flags/development/ci_dynamic_child_pipeline.yml
@@ -1,7 +1,7 @@
---
name: ci_dynamic_child_pipeline
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/23790
+rollout_issue_url:
+group: group::continuous integration
type: development
default_enabled: true
diff --git a/config/feature_flags/development/ci_enable_live_trace.yml b/config/feature_flags/development/ci_enable_live_trace.yml
index e9fd998f6df..7ae59946330 100644
--- a/config/feature_flags/development/ci_enable_live_trace.yml
+++ b/config/feature_flags/development/ci_enable_live_trace.yml
@@ -1,7 +1,7 @@
---
name: ci_enable_live_trace
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/5255
+rollout_issue_url:
+group: group::continuous integration
type: development
default_enabled: false
diff --git a/config/feature_flags/development/ci_instance_variables_ui.yml b/config/feature_flags/development/ci_instance_variables_ui.yml
index 0671d1a1a7c..481e0150600 100644
--- a/config/feature_flags/development/ci_instance_variables_ui.yml
+++ b/config/feature_flags/development/ci_instance_variables_ui.yml
@@ -1,7 +1,7 @@
---
name: ci_instance_variables_ui
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/33510
+rollout_issue_url:
+group: group::continuous integration
type: development
default_enabled: true
diff --git a/config/feature_flags/development/ci_job_heartbeats_runner.yml b/config/feature_flags/development/ci_job_heartbeats_runner.yml
deleted file mode 100644
index dcccd1512ed..00000000000
--- a/config/feature_flags/development/ci_job_heartbeats_runner.yml
+++ /dev/null
@@ -1,7 +0,0 @@
----
-name: ci_job_heartbeats_runner
-introduced_by_url:
-rollout_issue_url:
-group:
-type: development
-default_enabled: true
diff --git a/config/feature_flags/development/ci_job_jwt.yml b/config/feature_flags/development/ci_job_jwt.yml
index 3d18472add4..b0ad0790ebc 100644
--- a/config/feature_flags/development/ci_job_jwt.yml
+++ b/config/feature_flags/development/ci_job_jwt.yml
@@ -1,7 +1,7 @@
---
name: ci_job_jwt
-introduced_by_url:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/issues/207125
rollout_issue_url:
-group:
+group: group::release management
type: development
default_enabled: true
diff --git a/config/feature_flags/development/ci_jobs_finder_refactor.yml b/config/feature_flags/development/ci_jobs_finder_refactor.yml
index 13b8fa03477..f43db747e0a 100644
--- a/config/feature_flags/development/ci_jobs_finder_refactor.yml
+++ b/config/feature_flags/development/ci_jobs_finder_refactor.yml
@@ -4,4 +4,4 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/36622
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/245183
group: group::continuous integration
type: development
-default_enabled: false
+default_enabled: true
diff --git a/config/feature_flags/development/ci_key_autocomplete.yml b/config/feature_flags/development/ci_key_autocomplete.yml
deleted file mode 100644
index 1c6bfa90a9d..00000000000
--- a/config/feature_flags/development/ci_key_autocomplete.yml
+++ /dev/null
@@ -1,7 +0,0 @@
----
-name: ci_key_autocomplete
-introduced_by_url:
-rollout_issue_url:
-group:
-type: development
-default_enabled: true
diff --git a/config/feature_flags/development/ci_lint_creates_pipeline_with_dry_run.yml b/config/feature_flags/development/ci_lint_creates_pipeline_with_dry_run.yml
index 8abb52486b6..5f23d038998 100644
--- a/config/feature_flags/development/ci_lint_creates_pipeline_with_dry_run.yml
+++ b/config/feature_flags/development/ci_lint_creates_pipeline_with_dry_run.yml
@@ -1,7 +1,7 @@
---
name: ci_lint_creates_pipeline_with_dry_run
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/37828
+rollout_issue_url:
+group: group::continuous integration
type: development
default_enabled: true
diff --git a/config/feature_flags/development/ci_lint_vue.yml b/config/feature_flags/development/ci_lint_vue.yml
index 832f543ba3d..a72e97909be 100644
--- a/config/feature_flags/development/ci_lint_vue.yml
+++ b/config/feature_flags/development/ci_lint_vue.yml
@@ -2,6 +2,6 @@
name: ci_lint_vue
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/42401
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/249661
-group: group::continuous intergration
+group: group::continuous integration
type: development
default_enabled: false \ No newline at end of file
diff --git a/config/feature_flags/development/ci_manual_bridges.yml b/config/feature_flags/development/ci_manual_bridges.yml
new file mode 100644
index 00000000000..fa3f323722d
--- /dev/null
+++ b/config/feature_flags/development/ci_manual_bridges.yml
@@ -0,0 +1,7 @@
+---
+name: ci_manual_bridges
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/44011
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/263412
+type: development
+group: group::pipeline authoring
+default_enabled: true
diff --git a/config/feature_flags/development/ci_new_artifact_file_reader.yml b/config/feature_flags/development/ci_new_artifact_file_reader.yml
deleted file mode 100644
index a6e9c67bd7e..00000000000
--- a/config/feature_flags/development/ci_new_artifact_file_reader.yml
+++ /dev/null
@@ -1,7 +0,0 @@
----
-name: ci_new_artifact_file_reader
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/40268
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/249588
-group: group::pipeline authoring
-type: development
-default_enabled: false
diff --git a/config/feature_flags/development/ci_pipeline_latest.yml b/config/feature_flags/development/ci_pipeline_latest.yml
index 661d0714e53..87b064043a3 100644
--- a/config/feature_flags/development/ci_pipeline_latest.yml
+++ b/config/feature_flags/development/ci_pipeline_latest.yml
@@ -1,7 +1,7 @@
---
name: ci_pipeline_latest
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/34160
+rollout_issue_url:
+group: group::continuous integration
type: development
default_enabled: true
diff --git a/config/feature_flags/development/ci_pipeline_rewind_iid.yml b/config/feature_flags/development/ci_pipeline_rewind_iid.yml
deleted file mode 100644
index 8b6bb378a0a..00000000000
--- a/config/feature_flags/development/ci_pipeline_rewind_iid.yml
+++ /dev/null
@@ -1,7 +0,0 @@
----
-name: ci_pipeline_rewind_iid
-introduced_by_url:
-rollout_issue_url:
-group:
-type: development
-default_enabled: true
diff --git a/config/feature_flags/development/ci_pipeline_status_omit_commit_sha_in_cache_key.yml b/config/feature_flags/development/ci_pipeline_status_omit_commit_sha_in_cache_key.yml
index eda5ab00ef1..911eab84b28 100644
--- a/config/feature_flags/development/ci_pipeline_status_omit_commit_sha_in_cache_key.yml
+++ b/config/feature_flags/development/ci_pipeline_status_omit_commit_sha_in_cache_key.yml
@@ -1,7 +1,7 @@
---
name: ci_pipeline_status_omit_commit_sha_in_cache_key
-introduced_by_url:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/33712
rollout_issue_url:
-group:
+group: group::continuous integration
type: development
default_enabled: true
diff --git a/config/feature_flags/development/ci_pipeline_triggers_settings_vue_ui.yml b/config/feature_flags/development/ci_pipeline_triggers_settings_vue_ui.yml
new file mode 100644
index 00000000000..0a5c214308a
--- /dev/null
+++ b/config/feature_flags/development/ci_pipeline_triggers_settings_vue_ui.yml
@@ -0,0 +1,7 @@
+---
+name: ci_pipeline_triggers_settings_vue_ui
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/41864
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/247486
+group: group::continuous integration
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/ci_raise_job_rules_without_workflow_rules_warning.yml b/config/feature_flags/development/ci_raise_job_rules_without_workflow_rules_warning.yml
index d2e25e7bf11..c2cd1d62734 100644
--- a/config/feature_flags/development/ci_raise_job_rules_without_workflow_rules_warning.yml
+++ b/config/feature_flags/development/ci_raise_job_rules_without_workflow_rules_warning.yml
@@ -1,7 +1,7 @@
---
name: ci_raise_job_rules_without_workflow_rules_warning
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/38387
+rollout_issue_url:
+group: group::continuous integration
type: development
default_enabled: true
diff --git a/config/feature_flags/development/ci_send_deployment_hook_when_start.yml b/config/feature_flags/development/ci_send_deployment_hook_when_start.yml
new file mode 100644
index 00000000000..41f8e719b63
--- /dev/null
+++ b/config/feature_flags/development/ci_send_deployment_hook_when_start.yml
@@ -0,0 +1,7 @@
+---
+name: ci_send_deployment_hook_when_start
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/41214
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/247137
+group: group::progressive delivery
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/ci_skip_persistent_ref_existence_check.yml b/config/feature_flags/development/ci_skip_persistent_ref_existence_check.yml
index a9a79f80512..60c626295ab 100644
--- a/config/feature_flags/development/ci_skip_persistent_ref_existence_check.yml
+++ b/config/feature_flags/development/ci_skip_persistent_ref_existence_check.yml
@@ -1,7 +1,7 @@
---
name: ci_skip_persistent_ref_existence_check
-introduced_by_url:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/32391
rollout_issue_url:
-group:
+group: group::continuous integration
type: development
default_enabled: false
diff --git a/config/feature_flags/development/ci_store_pipeline_messages.yml b/config/feature_flags/development/ci_store_pipeline_messages.yml
index c7235ab2196..35cbfad0efa 100644
--- a/config/feature_flags/development/ci_store_pipeline_messages.yml
+++ b/config/feature_flags/development/ci_store_pipeline_messages.yml
@@ -1,7 +1,7 @@
---
name: ci_store_pipeline_messages
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url:
+rollout_issue_url:
+group: group::continuous integration
type: development
default_enabled: true
diff --git a/config/feature_flags/development/ci_synchronous_artifact_parsing.yml b/config/feature_flags/development/ci_synchronous_artifact_parsing.yml
index c5d1a44b61f..795ac08c7e9 100644
--- a/config/feature_flags/development/ci_synchronous_artifact_parsing.yml
+++ b/config/feature_flags/development/ci_synchronous_artifact_parsing.yml
@@ -1,7 +1,7 @@
---
name: ci_synchronous_artifact_parsing
-introduced_by_url:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/26247
rollout_issue_url:
-group:
+group: group::progressive delivery
type: development
default_enabled: true
diff --git a/config/feature_flags/development/ci_update_queues_for_online_runners.yml b/config/feature_flags/development/ci_update_queues_for_online_runners.yml
deleted file mode 100644
index f2bce6e14b5..00000000000
--- a/config/feature_flags/development/ci_update_queues_for_online_runners.yml
+++ /dev/null
@@ -1,7 +0,0 @@
----
-name: ci_update_queues_for_online_runners
-introduced_by_url:
-rollout_issue_url:
-group:
-type: development
-default_enabled: true
diff --git a/config/feature_flags/development/ci_yaml_limit_size.yml b/config/feature_flags/development/ci_yaml_limit_size.yml
index 06229c08af5..0ebd29d0ba5 100644
--- a/config/feature_flags/development/ci_yaml_limit_size.yml
+++ b/config/feature_flags/development/ci_yaml_limit_size.yml
@@ -1,7 +1,7 @@
---
name: ci_yaml_limit_size
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url:
+rollout_issue_url:
+group: group::continuous integration
type: development
default_enabled: true
diff --git a/config/feature_flags/development/cleanup_lfs_during_gc.yml b/config/feature_flags/development/cleanup_lfs_during_gc.yml
deleted file mode 100644
index 836784b1d9c..00000000000
--- a/config/feature_flags/development/cleanup_lfs_during_gc.yml
+++ /dev/null
@@ -1,7 +0,0 @@
----
-name: cleanup_lfs_during_gc
-introduced_by_url:
-rollout_issue_url:
-group:
-type: development
-default_enabled: false
diff --git a/config/feature_flags/development/cluster_agent_list.yml b/config/feature_flags/development/cluster_agent_list.yml
new file mode 100644
index 00000000000..a4468b662ae
--- /dev/null
+++ b/config/feature_flags/development/cluster_agent_list.yml
@@ -0,0 +1,7 @@
+---
+name: cluster_agent_list
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/issues/228845
+rollout_issue_url: https://gitlab.com/groups/gitlab-org/-/epics/3834
+group: group::configure
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/cluster_management_project.yml b/config/feature_flags/development/cluster_management_project.yml
index 9d58efd5194..922b7e6cad3 100644
--- a/config/feature_flags/development/cluster_management_project.yml
+++ b/config/feature_flags/development/cluster_management_project.yml
@@ -1,7 +1,7 @@
---
name: cluster_management_project
-introduced_by_url:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/17866
rollout_issue_url:
-group:
+group: group::configure
type: development
default_enabled: true
diff --git a/config/feature_flags/development/clusters_list_redesign.yml b/config/feature_flags/development/clusters_list_redesign.yml
deleted file mode 100644
index 1a9ad73eb79..00000000000
--- a/config/feature_flags/development/clusters_list_redesign.yml
+++ /dev/null
@@ -1,7 +0,0 @@
----
-name: clusters_list_redesign
-introduced_by_url:
-rollout_issue_url:
-group:
-type: development
-default_enabled: false
diff --git a/config/feature_flags/development/consolidated_edit_button.yml b/config/feature_flags/development/consolidated_edit_button.yml
new file mode 100644
index 00000000000..eecb426c1aa
--- /dev/null
+++ b/config/feature_flags/development/consolidated_edit_button.yml
@@ -0,0 +1,7 @@
+---
+name: consolidated_edit_button
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/44311
+rollout_issue_url:
+group: group::editor
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/container_expiration_policies_historic_entry.yml b/config/feature_flags/development/container_expiration_policies_historic_entry.yml
new file mode 100644
index 00000000000..0525f77eacf
--- /dev/null
+++ b/config/feature_flags/development/container_expiration_policies_historic_entry.yml
@@ -0,0 +1,7 @@
+---
+name: container_expiration_policies_historic_entry
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/44444
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/262639
+type: development
+group: group::package
+default_enabled: false
diff --git a/config/feature_flags/development/container_registry_api.yml b/config/feature_flags/development/container_registry_api.yml
deleted file mode 100644
index b0e128f1c3d..00000000000
--- a/config/feature_flags/development/container_registry_api.yml
+++ /dev/null
@@ -1,7 +0,0 @@
----
-name: container_registry_api
-introduced_by_url:
-rollout_issue_url:
-group:
-type: development
-default_enabled: true
diff --git a/config/feature_flags/development/container_registry_cleanup.yml b/config/feature_flags/development/container_registry_cleanup.yml
deleted file mode 100644
index a03f530b339..00000000000
--- a/config/feature_flags/development/container_registry_cleanup.yml
+++ /dev/null
@@ -1,7 +0,0 @@
----
-name: container_registry_cleanup
-introduced_by_url:
-rollout_issue_url:
-group:
-type: development
-default_enabled: true
diff --git a/config/feature_flags/development/container_registry_fast_tag_delete.yml b/config/feature_flags/development/container_registry_fast_tag_delete.yml
deleted file mode 100644
index dddac070355..00000000000
--- a/config/feature_flags/development/container_registry_fast_tag_delete.yml
+++ /dev/null
@@ -1,7 +0,0 @@
----
-name: container_registry_fast_tag_delete
-introduced_by_url:
-rollout_issue_url:
-group:
-type: development
-default_enabled: true
diff --git a/config/feature_flags/development/core_security_mr_widget.yml b/config/feature_flags/development/core_security_mr_widget.yml
new file mode 100644
index 00000000000..343bd238ae8
--- /dev/null
+++ b/config/feature_flags/development/core_security_mr_widget.yml
@@ -0,0 +1,7 @@
+---
+name: core_security_mr_widget
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/44639
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/249543
+type: development
+group: group::static analysis
+default_enabled: true
diff --git a/config/feature_flags/development/create_cloud_run_clusters.yml b/config/feature_flags/development/create_cloud_run_clusters.yml
index 30894fd2df1..6c479a3dd6c 100644
--- a/config/feature_flags/development/create_cloud_run_clusters.yml
+++ b/config/feature_flags/development/create_cloud_run_clusters.yml
@@ -1,7 +1,7 @@
---
name: create_cloud_run_clusters
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/19063
+rollout_issue_url:
+group: group::configure
type: development
default_enabled: true
diff --git a/config/feature_flags/development/dag_pipeline_tab.yml b/config/feature_flags/development/dag_pipeline_tab.yml
new file mode 100644
index 00000000000..f4261b51e05
--- /dev/null
+++ b/config/feature_flags/development/dag_pipeline_tab.yml
@@ -0,0 +1,7 @@
+---
+name: dag_pipeline_tab
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/30310
+rollout_issue_url:
+group: group::pipeline authoring
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/dashboard_pipeline_status.yml b/config/feature_flags/development/dashboard_pipeline_status.yml
index 241f5fea64f..8034177ee1e 100644
--- a/config/feature_flags/development/dashboard_pipeline_status.yml
+++ b/config/feature_flags/development/dashboard_pipeline_status.yml
@@ -1,7 +1,7 @@
---
name: dashboard_pipeline_status
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/22029
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/209061
+group: group::continuous integration
type: development
default_enabled: true
diff --git a/config/feature_flags/development/debian_packages.yml b/config/feature_flags/development/debian_packages.yml
new file mode 100644
index 00000000000..8f706e81b6a
--- /dev/null
+++ b/config/feature_flags/development/debian_packages.yml
@@ -0,0 +1,7 @@
+---
+name: debian_packages
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/42670
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/5835
+group: group::package
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/default_merge_ref_for_diffs.yml b/config/feature_flags/development/default_merge_ref_for_diffs.yml
new file mode 100644
index 00000000000..b982185c1fd
--- /dev/null
+++ b/config/feature_flags/development/default_merge_ref_for_diffs.yml
@@ -0,0 +1,7 @@
+---
+name: default_merge_ref_for_diffs
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/34472
+rollout_issue_url:
+type: development
+group: group::source code
+default_enabled: false
diff --git a/config/feature_flags/development/deploy_boards_dedupe_instances.yml b/config/feature_flags/development/deploy_boards_dedupe_instances.yml
new file mode 100644
index 00000000000..d407e11babd
--- /dev/null
+++ b/config/feature_flags/development/deploy_boards_dedupe_instances.yml
@@ -0,0 +1,7 @@
+---
+name: deploy_boards_dedupe_instances
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/40768
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/258214
+type: development
+group: group::progressive delivery
+default_enabled: false
diff --git a/config/feature_flags/development/deploy_from_footer.yml b/config/feature_flags/development/deploy_from_footer.yml
deleted file mode 100644
index 8e31ab511b6..00000000000
--- a/config/feature_flags/development/deploy_from_footer.yml
+++ /dev/null
@@ -1,7 +0,0 @@
----
-name: deploy_from_footer
-introduced_by_url:
-rollout_issue_url:
-group:
-type: development
-default_enabled: true
diff --git a/config/feature_flags/development/deploy_keys_on_protected_branches.yml b/config/feature_flags/development/deploy_keys_on_protected_branches.yml
new file mode 100644
index 00000000000..ec5c13082ec
--- /dev/null
+++ b/config/feature_flags/development/deploy_keys_on_protected_branches.yml
@@ -0,0 +1,7 @@
+---
+name: deploy_keys_on_protected_branches
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/35638
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/247866
+group: group::progressive delivery
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/deploy_tokens_api.yml b/config/feature_flags/development/deploy_tokens_api.yml
index d8691842822..27c583e760b 100644
--- a/config/feature_flags/development/deploy_tokens_api.yml
+++ b/config/feature_flags/development/deploy_tokens_api.yml
@@ -1,7 +1,7 @@
---
name: deploy_tokens_api
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/25219
+rollout_issue_url:
+group: group::package
type: development
default_enabled: true
diff --git a/config/feature_flags/development/deployment_filters.yml b/config/feature_flags/development/deployment_filters.yml
new file mode 100644
index 00000000000..8c265f253fc
--- /dev/null
+++ b/config/feature_flags/development/deployment_filters.yml
@@ -0,0 +1,7 @@
+---
+name: deployment_filters
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/44041
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/267561
+type: development
+group: group::source code
+default_enabled: false
diff --git a/config/feature_flags/development/design_management_allow_dangerous_images.yml b/config/feature_flags/development/design_management_allow_dangerous_images.yml
index d1d09f154a4..73c348a69ca 100644
--- a/config/feature_flags/development/design_management_allow_dangerous_images.yml
+++ b/config/feature_flags/development/design_management_allow_dangerous_images.yml
@@ -1,7 +1,7 @@
---
name: design_management_allow_dangerous_images
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/16160
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/34279
+group: group::knowledge
type: development
default_enabled: false
diff --git a/config/feature_flags/development/design_management_reference_filter_gfm_pipeline.yml b/config/feature_flags/development/design_management_reference_filter_gfm_pipeline.yml
deleted file mode 100644
index e07b621ed23..00000000000
--- a/config/feature_flags/development/design_management_reference_filter_gfm_pipeline.yml
+++ /dev/null
@@ -1,7 +0,0 @@
----
-name: design_management_reference_filter_gfm_pipeline
-introduced_by_url:
-rollout_issue_url:
-group:
-type: development
-default_enabled: true
diff --git a/config/feature_flags/development/design_management_todo_button.yml b/config/feature_flags/development/design_management_todo_button.yml
deleted file mode 100644
index 218ddf9f65c..00000000000
--- a/config/feature_flags/development/design_management_todo_button.yml
+++ /dev/null
@@ -1,7 +0,0 @@
----
-name: design_management_todo_button
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/39935
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/245074
-group: group::knowledge
-type: development
-default_enabled: true
diff --git a/config/feature_flags/development/disable_metric_dashboard_refresh_rate.yml b/config/feature_flags/development/disable_metric_dashboard_refresh_rate.yml
index 193579cd11b..d0e549a465d 100644
--- a/config/feature_flags/development/disable_metric_dashboard_refresh_rate.yml
+++ b/config/feature_flags/development/disable_metric_dashboard_refresh_rate.yml
@@ -1,7 +1,7 @@
---
name: disable_metric_dashboard_refresh_rate
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/issues/229831
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/229841
+group: group::health
type: development
default_enabled: false
diff --git a/config/feature_flags/development/disable_shared_runners_on_group.yml b/config/feature_flags/development/disable_shared_runners_on_group.yml
new file mode 100644
index 00000000000..86ccf59c8a0
--- /dev/null
+++ b/config/feature_flags/development/disable_shared_runners_on_group.yml
@@ -0,0 +1,7 @@
+---
+name: disable_shared_runners_on_group
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/36080
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/258991
+type: development
+group: group::runner
+default_enabled: true
diff --git a/config/feature_flags/development/display_merge_conflicts_in_diff.yml b/config/feature_flags/development/display_merge_conflicts_in_diff.yml
new file mode 100644
index 00000000000..678037fa366
--- /dev/null
+++ b/config/feature_flags/development/display_merge_conflicts_in_diff.yml
@@ -0,0 +1,7 @@
+---
+name: display_merge_conflicts_in_diff
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/45008
+rollout_issue_url:
+type: development
+group: group::source code
+default_enabled: false
diff --git a/config/feature_flags/development/drop_license_management_artifact.yml b/config/feature_flags/development/drop_license_management_artifact.yml
index 59d749154b5..34e10fa7ae6 100644
--- a/config/feature_flags/development/drop_license_management_artifact.yml
+++ b/config/feature_flags/development/drop_license_management_artifact.yml
@@ -1,7 +1,7 @@
---
name: drop_license_management_artifact
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url:
+rollout_issue_url:
+group: group::composition analysis
type: development
default_enabled: true
diff --git a/config/feature_flags/development/efficient_counter_attribute.yml b/config/feature_flags/development/efficient_counter_attribute.yml
index a1b16be7ce8..1b12c166c53 100644
--- a/config/feature_flags/development/efficient_counter_attribute.yml
+++ b/config/feature_flags/development/efficient_counter_attribute.yml
@@ -1,7 +1,7 @@
---
name: efficient_counter_attribute
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/35878
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/238535
+group: group::continuous integration
type: development
default_enabled: false
diff --git a/config/feature_flags/development/export_lfs_objects_projects.yml b/config/feature_flags/development/export_lfs_objects_projects.yml
deleted file mode 100644
index 6ef3317de8d..00000000000
--- a/config/feature_flags/development/export_lfs_objects_projects.yml
+++ /dev/null
@@ -1,7 +0,0 @@
----
-name: export_lfs_objects_projects
-introduced_by_url:
-rollout_issue_url:
-group:
-type: development
-default_enabled: true
diff --git a/config/feature_flags/development/export_reduce_relation_batch_size.yml b/config/feature_flags/development/export_reduce_relation_batch_size.yml
index b32e2232933..d077079b586 100644
--- a/config/feature_flags/development/export_reduce_relation_batch_size.yml
+++ b/config/feature_flags/development/export_reduce_relation_batch_size.yml
@@ -1,7 +1,7 @@
---
name: export_reduce_relation_batch_size
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url:
+rollout_issue_url:
+group: group::import
type: development
default_enabled: false
diff --git a/config/feature_flags/development/expose_environment_path_in_alert_details.yml b/config/feature_flags/development/expose_environment_path_in_alert_details.yml
new file mode 100644
index 00000000000..f1e35cffbe0
--- /dev/null
+++ b/config/feature_flags/development/expose_environment_path_in_alert_details.yml
@@ -0,0 +1,7 @@
+---
+name: expose_environment_path_in_alert_details
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/43414
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/258638
+type: development
+group: group::progressive delivery
+default_enabled: false
diff --git a/config/feature_flags/development/feature_flag_api.yml b/config/feature_flags/development/feature_flag_api.yml
new file mode 100644
index 00000000000..326cfa83433
--- /dev/null
+++ b/config/feature_flags/development/feature_flag_api.yml
@@ -0,0 +1,7 @@
+---
+name: feature_flag_api
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/18198
+rollout_issue_url:
+group: group::progressive delivery
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/feature_flag_permissions.yml b/config/feature_flags/development/feature_flag_permissions.yml
new file mode 100644
index 00000000000..2eb5b513743
--- /dev/null
+++ b/config/feature_flags/development/feature_flag_permissions.yml
@@ -0,0 +1,7 @@
+---
+name: feature_flag_permissions
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/10096
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/254981
+group: group::progressive delivery
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/feature_flags_legacy_read_only.yml b/config/feature_flags/development/feature_flags_legacy_read_only.yml
new file mode 100644
index 00000000000..b790e466093
--- /dev/null
+++ b/config/feature_flags/development/feature_flags_legacy_read_only.yml
@@ -0,0 +1,7 @@
+---
+name: feature_flags_legacy_read_only
+introduced_by_url:
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/240985
+group: group::progressive delivery
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/feature_flags_legacy_read_only_override.yml b/config/feature_flags/development/feature_flags_legacy_read_only_override.yml
new file mode 100644
index 00000000000..14acde1b8fc
--- /dev/null
+++ b/config/feature_flags/development/feature_flags_legacy_read_only_override.yml
@@ -0,0 +1,7 @@
+---
+name: feature_flags_legacy_read_only_override
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/40431
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/240985
+group: group::progressive delivery
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/feature_flags_new_version.yml b/config/feature_flags/development/feature_flags_new_version.yml
new file mode 100644
index 00000000000..3a89816c482
--- /dev/null
+++ b/config/feature_flags/development/feature_flags_new_version.yml
@@ -0,0 +1,7 @@
+---
+name: feature_flags_new_version
+introduced_by_url:
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/258831
+group: group::progressive delivery
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/forti_authenticator.yml b/config/feature_flags/development/forti_authenticator.yml
new file mode 100644
index 00000000000..31f5256753f
--- /dev/null
+++ b/config/feature_flags/development/forti_authenticator.yml
@@ -0,0 +1,7 @@
+---
+name: forti_authenticator
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/45055
+rollout_issue_url:
+type: development
+group: group::access
+default_enabled: false
diff --git a/config/feature_flags/development/forward_deployment_enabled.yml b/config/feature_flags/development/forward_deployment_enabled.yml
index 51cc99e39ae..f9aed1a0568 100644
--- a/config/feature_flags/development/forward_deployment_enabled.yml
+++ b/config/feature_flags/development/forward_deployment_enabled.yml
@@ -1,7 +1,7 @@
---
name: forward_deployment_enabled
-introduced_by_url:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/24412
rollout_issue_url:
-group:
+group: group::progressive delivery
type: development
default_enabled: true
diff --git a/config/feature_flags/development/g_compliance_dashboard_feature.yml b/config/feature_flags/development/g_compliance_dashboard_feature.yml
deleted file mode 100644
index 3390bc18810..00000000000
--- a/config/feature_flags/development/g_compliance_dashboard_feature.yml
+++ /dev/null
@@ -1,7 +0,0 @@
----
-name: g_compliance_dashboard_feature
-introduced_by_url:
-rollout_issue_url:
-group:
-type: development
-default_enabled: true
diff --git a/config/feature_flags/development/generic_packages.yml b/config/feature_flags/development/generic_packages.yml
index 99b89b196ea..7b80e50d372 100644
--- a/config/feature_flags/development/generic_packages.yml
+++ b/config/feature_flags/development/generic_packages.yml
@@ -4,4 +4,4 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/40045
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/239133
group: group::release management
type: development
-default_enabled: false
+default_enabled: true
diff --git a/config/feature_flags/development/git_push_create_all_pipelines.yml b/config/feature_flags/development/git_push_create_all_pipelines.yml
index 62dbe9bb02f..a205307d5fa 100644
--- a/config/feature_flags/development/git_push_create_all_pipelines.yml
+++ b/config/feature_flags/development/git_push_create_all_pipelines.yml
@@ -1,7 +1,7 @@
---
name: git_push_create_all_pipelines
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/27205
+rollout_issue_url:
+group: group::continuous integration
type: development
default_enabled: false
diff --git a/config/feature_flags/development/gitpod.yml b/config/feature_flags/development/gitpod.yml
index 148ea7294ba..d1d9f35d4d4 100644
--- a/config/feature_flags/development/gitpod.yml
+++ b/config/feature_flags/development/gitpod.yml
@@ -1,7 +1,7 @@
---
name: gitpod
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/37985
-rollout_issue_url:
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/258206
group: group::editor
type: development
-default_enabled: false \ No newline at end of file
+default_enabled: true
diff --git a/config/feature_flags/development/global_default_branch_name.yml b/config/feature_flags/development/global_default_branch_name.yml
index 57b324a6da2..2954ed74062 100644
--- a/config/feature_flags/development/global_default_branch_name.yml
+++ b/config/feature_flags/development/global_default_branch_name.yml
@@ -1,7 +1,7 @@
---
name: global_default_branch_name
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/35269
+rollout_issue_url:
+group: group::source code
type: development
default_enabled: true
diff --git a/config/feature_flags/development/go_proxy.yml b/config/feature_flags/development/go_proxy.yml
index bde614dd84d..bd0c58faee5 100644
--- a/config/feature_flags/development/go_proxy.yml
+++ b/config/feature_flags/development/go_proxy.yml
@@ -1,7 +1,7 @@
---
name: go_proxy
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/27746
+rollout_issue_url:
+group: group::package
type: development
default_enabled: false
diff --git a/config/feature_flags/development/go_proxy_disable_gomod_validation.yml b/config/feature_flags/development/go_proxy_disable_gomod_validation.yml
index 5e9671c66d5..336a88bb7ff 100644
--- a/config/feature_flags/development/go_proxy_disable_gomod_validation.yml
+++ b/config/feature_flags/development/go_proxy_disable_gomod_validation.yml
@@ -1,7 +1,7 @@
---
name: go_proxy_disable_gomod_validation
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/34338
+rollout_issue_url:
+group: group::package
type: development
default_enabled: false
diff --git a/config/feature_flags/development/graphql_board_lists.yml b/config/feature_flags/development/graphql_board_lists.yml
index 4e6bf000a8f..7e2696a06c8 100644
--- a/config/feature_flags/development/graphql_board_lists.yml
+++ b/config/feature_flags/development/graphql_board_lists.yml
@@ -1,7 +1,7 @@
---
name: graphql_board_lists
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url:
+rollout_issue_url:
+group: group::project management
type: development
default_enabled: false
diff --git a/config/feature_flags/development/graphql_individual_release_page.yml b/config/feature_flags/development/graphql_individual_release_page.yml
new file mode 100644
index 00000000000..29c9692eaec
--- /dev/null
+++ b/config/feature_flags/development/graphql_individual_release_page.yml
@@ -0,0 +1,7 @@
+---
+name: graphql_individual_release_page
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/44779
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/263522
+type: development
+group: group::release management
+default_enabled: true
diff --git a/config/feature_flags/development/graphql_lookahead_support.yml b/config/feature_flags/development/graphql_lookahead_support.yml
deleted file mode 100644
index 2c8825f309e..00000000000
--- a/config/feature_flags/development/graphql_lookahead_support.yml
+++ /dev/null
@@ -1,7 +0,0 @@
----
-name: graphql_lookahead_support
-introduced_by_url:
-rollout_issue_url:
-group:
-type: development
-default_enabled: false
diff --git a/config/feature_flags/development/graphql_milestone_stats.yml b/config/feature_flags/development/graphql_milestone_stats.yml
index daa72031879..a3ff14d3245 100644
--- a/config/feature_flags/development/graphql_milestone_stats.yml
+++ b/config/feature_flags/development/graphql_milestone_stats.yml
@@ -1,7 +1,7 @@
---
name: graphql_milestone_stats
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/35066
+rollout_issue_url:
+group: group::release management
type: development
default_enabled: true
diff --git a/config/feature_flags/development/graphql_pipeline_header.yml b/config/feature_flags/development/graphql_pipeline_header.yml
new file mode 100644
index 00000000000..99019d4c849
--- /dev/null
+++ b/config/feature_flags/development/graphql_pipeline_header.yml
@@ -0,0 +1,7 @@
+---
+name: graphql_pipeline_header
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/39494
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/254235
+group: group::pipeline authoring
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/graphql_release_data.yml b/config/feature_flags/development/graphql_release_data.yml
index c30fbf7fe13..609c0dc634a 100644
--- a/config/feature_flags/development/graphql_release_data.yml
+++ b/config/feature_flags/development/graphql_release_data.yml
@@ -1,7 +1,7 @@
---
name: graphql_release_data
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/30753
+rollout_issue_url:
+group: group::release management
type: development
default_enabled: true
diff --git a/config/feature_flags/development/graphql_releases_page.yml b/config/feature_flags/development/graphql_releases_page.yml
new file mode 100644
index 00000000000..607fc7027b5
--- /dev/null
+++ b/config/feature_flags/development/graphql_releases_page.yml
@@ -0,0 +1,7 @@
+---
+name: graphql_releases_page
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/33095
+rollout_issue_url:
+group: group::release management
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/group_export_ndjson.yml b/config/feature_flags/development/group_export_ndjson.yml
index af495df2e48..3f7f61672f4 100644
--- a/config/feature_flags/development/group_export_ndjson.yml
+++ b/config/feature_flags/development/group_export_ndjson.yml
@@ -1,7 +1,7 @@
---
name: group_export_ndjson
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/29590
+rollout_issue_url:
+group: group::import
type: development
default_enabled: true
diff --git a/config/feature_flags/development/group_import_export.yml b/config/feature_flags/development/group_import_export.yml
index 8a49fb29e45..0e88c45684f 100644
--- a/config/feature_flags/development/group_import_export.yml
+++ b/config/feature_flags/development/group_import_export.yml
@@ -1,7 +1,7 @@
---
name: group_import_export
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url:
+rollout_issue_url:
+group: group::import
type: development
default_enabled: true
diff --git a/config/feature_flags/development/group_import_ndjson.yml b/config/feature_flags/development/group_import_ndjson.yml
index cf438abe8cb..98f0d4722e4 100644
--- a/config/feature_flags/development/group_import_ndjson.yml
+++ b/config/feature_flags/development/group_import_ndjson.yml
@@ -1,7 +1,7 @@
---
name: group_import_ndjson
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/29716
+rollout_issue_url:
+group: group::import
type: development
default_enabled: true
diff --git a/config/feature_flags/development/group_level_integrations.yml b/config/feature_flags/development/group_level_integrations.yml
index 8fc7da47ba1..c089333f72a 100644
--- a/config/feature_flags/development/group_level_integrations.yml
+++ b/config/feature_flags/development/group_level_integrations.yml
@@ -1,6 +1,6 @@
---
name: group_level_integrations
-introduced_by_url:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/27557
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/238575
group: group::ecosystem
type: development
diff --git a/config/feature_flags/development/help_page_documentation_redirect.yml b/config/feature_flags/development/help_page_documentation_redirect.yml
new file mode 100644
index 00000000000..bf30101a199
--- /dev/null
+++ b/config/feature_flags/development/help_page_documentation_redirect.yml
@@ -0,0 +1,7 @@
+---
+name: help_page_documentation_redirect
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/42702
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/255328
+group: group::static site editor
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/improved_mr_merged_at_queries.yml b/config/feature_flags/development/improved_mr_merged_at_queries.yml
deleted file mode 100644
index bf4c8814540..00000000000
--- a/config/feature_flags/development/improved_mr_merged_at_queries.yml
+++ /dev/null
@@ -1,7 +0,0 @@
----
-name: improved_mr_merged_at_queries
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/39329
-rollout_issue_url:
-group: group::analytics
-type: development
-default_enabled: true
diff --git a/config/feature_flags/development/inactive_policy_condition.yml b/config/feature_flags/development/inactive_policy_condition.yml
deleted file mode 100644
index bf577fb3123..00000000000
--- a/config/feature_flags/development/inactive_policy_condition.yml
+++ /dev/null
@@ -1,7 +0,0 @@
----
-name: inactive_policy_condition
-introduced_by_url:
-rollout_issue_url:
-group:
-type: development
-default_enabled: true
diff --git a/config/feature_flags/development/include_lfs_blobs_in_archive.yml b/config/feature_flags/development/include_lfs_blobs_in_archive.yml
new file mode 100644
index 00000000000..fcbefa3d072
--- /dev/null
+++ b/config/feature_flags/development/include_lfs_blobs_in_archive.yml
@@ -0,0 +1,7 @@
+---
+name: include_lfs_blobs_in_archive
+introduced_by_url: '44116'
+rollout_issue_url:
+type: development
+group: group::source code
+default_enabled: false
diff --git a/config/feature_flags/development/increased_diff_limits.yml b/config/feature_flags/development/increased_diff_limits.yml
new file mode 100644
index 00000000000..351e6926161
--- /dev/null
+++ b/config/feature_flags/development/increased_diff_limits.yml
@@ -0,0 +1,7 @@
+---
+name: increased_diff_limits
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/40357
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/241185
+group: group::source code
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/ingress_modsecurity.yml b/config/feature_flags/development/ingress_modsecurity.yml
index cf289bb3d45..7ed1d089476 100644
--- a/config/feature_flags/development/ingress_modsecurity.yml
+++ b/config/feature_flags/development/ingress_modsecurity.yml
@@ -1,7 +1,7 @@
---
name: ingress_modsecurity
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/20194
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/258554
+group: group::container security
type: development
default_enabled: false
diff --git a/config/feature_flags/development/invisible_captcha.yml b/config/feature_flags/development/invisible_captcha.yml
index ee38a9c657a..e44e5a47947 100644
--- a/config/feature_flags/development/invisible_captcha.yml
+++ b/config/feature_flags/development/invisible_captcha.yml
@@ -1,7 +1,7 @@
---
name: invisible_captcha
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/31625
+rollout_issue_url:
+group: group::acquisition
type: development
default_enabled: false
diff --git a/config/feature_flags/development/invite_email_experiment.yml b/config/feature_flags/development/invite_email_experiment.yml
index 3797090724e..496f096f7c7 100644
--- a/config/feature_flags/development/invite_email_experiment.yml
+++ b/config/feature_flags/development/invite_email_experiment.yml
@@ -1,7 +1,7 @@
---
name: invite_email_experiment
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/39628
+rollout_issue_url:
+group: group::acquisition
type: development
default_enabled: false
diff --git a/config/feature_flags/development/invite_members_group_modal.yml b/config/feature_flags/development/invite_members_group_modal.yml
new file mode 100644
index 00000000000..faa905f6557
--- /dev/null
+++ b/config/feature_flags/development/invite_members_group_modal.yml
@@ -0,0 +1,7 @@
+---
+name: invite_members_group_modal
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/37906
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/247208
+group: group::expansion
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/json_limited_encoder.yml b/config/feature_flags/development/json_limited_encoder.yml
index 3afed64b4cc..d20b5412233 100644
--- a/config/feature_flags/development/json_limited_encoder.yml
+++ b/config/feature_flags/development/json_limited_encoder.yml
@@ -1,7 +1,7 @@
---
name: json_limited_encoder
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/38687
+rollout_issue_url:
+group: group::source code
type: development
default_enabled: false
diff --git a/config/feature_flags/development/junit_pipeline_screenshots_view.yml b/config/feature_flags/development/junit_pipeline_screenshots_view.yml
index d9f61b572be..273e0ed450e 100644
--- a/config/feature_flags/development/junit_pipeline_screenshots_view.yml
+++ b/config/feature_flags/development/junit_pipeline_screenshots_view.yml
@@ -1,7 +1,7 @@
---
name: junit_pipeline_screenshots_view
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/issues/202114
+rollout_issue_url:
+group: group::verify testing
type: development
default_enabled: false
diff --git a/config/feature_flags/development/kubernetes_cluster_namespace_role_admin.yml b/config/feature_flags/development/kubernetes_cluster_namespace_role_admin.yml
new file mode 100644
index 00000000000..7fb9a3d6921
--- /dev/null
+++ b/config/feature_flags/development/kubernetes_cluster_namespace_role_admin.yml
@@ -0,0 +1,7 @@
+---
+name: kubernetes_cluster_namespace_role_admin
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/45479
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/270030
+type: development
+group: group::configure
+default_enabled: false
diff --git a/config/feature_flags/development/limit_projects_in_groups_api.yml b/config/feature_flags/development/limit_projects_in_groups_api.yml
index 571c02578d3..efa763944ec 100644
--- a/config/feature_flags/development/limit_projects_in_groups_api.yml
+++ b/config/feature_flags/development/limit_projects_in_groups_api.yml
@@ -1,7 +1,7 @@
---
name: limit_projects_in_groups_api
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/20023
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/257829
+group: group::access
type: development
default_enabled: true
diff --git a/config/feature_flags/development/log_import_export_relation_creation.yml b/config/feature_flags/development/log_import_export_relation_creation.yml
index bfd4b27752b..4ab84c2193c 100644
--- a/config/feature_flags/development/log_import_export_relation_creation.yml
+++ b/config/feature_flags/development/log_import_export_relation_creation.yml
@@ -1,7 +1,7 @@
---
name: log_import_export_relation_creation
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url:
+rollout_issue_url:
+group: group::import
type: development
default_enabled: false
diff --git a/config/feature_flags/development/maintenance_mode.yml b/config/feature_flags/development/maintenance_mode.yml
index 8fba1216834..429e70b64a2 100644
--- a/config/feature_flags/development/maintenance_mode.yml
+++ b/config/feature_flags/development/maintenance_mode.yml
@@ -1,7 +1,7 @@
---
name: maintenance_mode
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/28158
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/217895
+group: group::geo
type: development
default_enabled: false
diff --git a/config/feature_flags/development/marginalia.yml b/config/feature_flags/development/marginalia.yml
deleted file mode 100644
index 9fcfa061bff..00000000000
--- a/config/feature_flags/development/marginalia.yml
+++ /dev/null
@@ -1,7 +0,0 @@
----
-name: marginalia
-introduced_by_url:
-rollout_issue_url:
-group:
-type: development
-default_enabled: false
diff --git a/config/feature_flags/development/merge_base_pipelines.yml b/config/feature_flags/development/merge_base_pipelines.yml
new file mode 100644
index 00000000000..4f57ca556f1
--- /dev/null
+++ b/config/feature_flags/development/merge_base_pipelines.yml
@@ -0,0 +1,7 @@
+---
+name: merge_base_pipelines
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/44648
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/263724
+type: development
+group: group::testing
+default_enabled: false
diff --git a/config/feature_flags/development/merge_orchestration_service.yml b/config/feature_flags/development/merge_orchestration_service.yml
index 134553e7344..2bdfe9b52a4 100644
--- a/config/feature_flags/development/merge_orchestration_service.yml
+++ b/config/feature_flags/development/merge_orchestration_service.yml
@@ -1,7 +1,7 @@
---
name: merge_orchestration_service
-introduced_by_url:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/28532
rollout_issue_url:
-group:
+group: group::continuous integration
type: development
default_enabled: true
diff --git a/config/feature_flags/development/merge_request_cached_pipeline_serializer.yml b/config/feature_flags/development/merge_request_cached_pipeline_serializer.yml
new file mode 100644
index 00000000000..1141d1f82a4
--- /dev/null
+++ b/config/feature_flags/development/merge_request_cached_pipeline_serializer.yml
@@ -0,0 +1,7 @@
+---
+name: merge_request_cached_pipeline_serializer
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/38273
+rollout_issue_url:
+type: development
+group: group::source code
+default_enabled: false
diff --git a/config/feature_flags/development/merge_request_draft_filter.yml b/config/feature_flags/development/merge_request_draft_filter.yml
index 113194c2a18..6bf3e12d817 100644
--- a/config/feature_flags/development/merge_request_draft_filter.yml
+++ b/config/feature_flags/development/merge_request_draft_filter.yml
@@ -1,7 +1,7 @@
---
name: merge_request_draft_filter
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/35942
+rollout_issue_url:
+group: group::source code
type: development
default_enabled: true
diff --git a/config/feature_flags/development/merge_request_short_pipeline_serializer.yml b/config/feature_flags/development/merge_request_short_pipeline_serializer.yml
deleted file mode 100644
index c24dd106547..00000000000
--- a/config/feature_flags/development/merge_request_short_pipeline_serializer.yml
+++ /dev/null
@@ -1,7 +0,0 @@
----
-name: merge_request_short_pipeline_serializer
-introduced_by_url:
-rollout_issue_url:
-group:
-type: development
-default_enabled: true
diff --git a/config/feature_flags/development/merge_request_widget_graphql.yml b/config/feature_flags/development/merge_request_widget_graphql.yml
index 028553a47f8..cbe76a61fa5 100644
--- a/config/feature_flags/development/merge_request_widget_graphql.yml
+++ b/config/feature_flags/development/merge_request_widget_graphql.yml
@@ -1,7 +1,7 @@
---
name: merge_request_widget_graphql
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/38311
+rollout_issue_url:
+group: group::source code
type: development
default_enabled: false
diff --git a/config/feature_flags/development/metrics_dashboard.yml b/config/feature_flags/development/metrics_dashboard.yml
index a252068aa9a..04a64b632ba 100644
--- a/config/feature_flags/development/metrics_dashboard.yml
+++ b/config/feature_flags/development/metrics_dashboard.yml
@@ -1,7 +1,7 @@
---
name: metrics_dashboard
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/29634
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/257902
+group: group::health
type: development
default_enabled: true
diff --git a/config/feature_flags/development/migrate_bio_to_user_details.yml b/config/feature_flags/development/migrate_bio_to_user_details.yml
deleted file mode 100644
index f54e45f9bd3..00000000000
--- a/config/feature_flags/development/migrate_bio_to_user_details.yml
+++ /dev/null
@@ -1,7 +0,0 @@
----
-name: migrate_bio_to_user_details
-introduced_by_url:
-rollout_issue_url:
-group:
-type: development
-default_enabled: true
diff --git a/config/feature_flags/development/migrate_user_mentions.yml b/config/feature_flags/development/migrate_user_mentions.yml
index 3388fb020ad..5dd5667dfae 100644
--- a/config/feature_flags/development/migrate_user_mentions.yml
+++ b/config/feature_flags/development/migrate_user_mentions.yml
@@ -1,7 +1,7 @@
---
name: migrate_user_mentions
-introduced_by_url:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/34378
rollout_issue_url:
-group:
+group: group::project management
type: development
default_enabled: true
diff --git a/config/feature_flags/development/modifed_path_ci_variables.yml b/config/feature_flags/development/modifed_path_ci_variables.yml
deleted file mode 100644
index a72a5ae56e1..00000000000
--- a/config/feature_flags/development/modifed_path_ci_variables.yml
+++ /dev/null
@@ -1,7 +0,0 @@
----
-name: modifed_path_ci_variables
-introduced_by_url:
-rollout_issue_url:
-group:
-type: development
-default_enabled: false
diff --git a/config/feature_flags/development/monaco_blobs.yml b/config/feature_flags/development/monaco_blobs.yml
deleted file mode 100644
index bb1215493d5..00000000000
--- a/config/feature_flags/development/monaco_blobs.yml
+++ /dev/null
@@ -1,7 +0,0 @@
----
-name: monaco_blobs
-introduced_by_url:
-rollout_issue_url:
-group:
-type: development
-default_enabled: true
diff --git a/config/feature_flags/development/monaco_ci.yml b/config/feature_flags/development/monaco_ci.yml
deleted file mode 100644
index 5d6ace8d8ad..00000000000
--- a/config/feature_flags/development/monaco_ci.yml
+++ /dev/null
@@ -1,7 +0,0 @@
----
-name: monaco_ci
-introduced_by_url:
-rollout_issue_url:
-group:
-type: development
-default_enabled: false
diff --git a/config/feature_flags/development/mr_commit_neighbor_nav.yml b/config/feature_flags/development/mr_commit_neighbor_nav.yml
index 5fcacbdd3fe..7b540e14464 100644
--- a/config/feature_flags/development/mr_commit_neighbor_nav.yml
+++ b/config/feature_flags/development/mr_commit_neighbor_nav.yml
@@ -1,7 +1,7 @@
---
name: mr_commit_neighbor_nav
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/28596
+rollout_issue_url:
+group: group::source code
type: development
default_enabled: true
diff --git a/config/feature_flags/development/multi_select_board.yml b/config/feature_flags/development/multi_select_board.yml
index 35718606d62..3849fb0e12b 100644
--- a/config/feature_flags/development/multi_select_board.yml
+++ b/config/feature_flags/development/multi_select_board.yml
@@ -1,7 +1,7 @@
---
name: multi_select_board
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url:
+rollout_issue_url:
+group: group::project management
type: development
default_enabled: true
diff --git a/config/feature_flags/development/multiline_comments.yml b/config/feature_flags/development/multiline_comments.yml
index cb80d381e18..135e5be1dc5 100644
--- a/config/feature_flags/development/multiline_comments.yml
+++ b/config/feature_flags/development/multiline_comments.yml
@@ -1,7 +1,7 @@
---
name: multiline_comments
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/issues/211255
+rollout_issue_url:
+group: group::source code
type: development
default_enabled: true
diff --git a/config/feature_flags/development/new_pipeline_form.yml b/config/feature_flags/development/new_pipeline_form.yml
index 96c7268ded0..3c1079a5f5c 100644
--- a/config/feature_flags/development/new_pipeline_form.yml
+++ b/config/feature_flags/development/new_pipeline_form.yml
@@ -1,7 +1,7 @@
---
name: new_pipeline_form
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/35674
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/229632
+group: group::continuous integration
type: development
default_enabled: false
diff --git a/config/feature_flags/development/new_pipeline_form_prefilled_vars.yml b/config/feature_flags/development/new_pipeline_form_prefilled_vars.yml
new file mode 100644
index 00000000000..6b821e7fd9e
--- /dev/null
+++ b/config/feature_flags/development/new_pipeline_form_prefilled_vars.yml
@@ -0,0 +1,7 @@
+---
+name: new_pipeline_form_prefilled_vars
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/44120
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/263276
+type: development
+group: group::continuous integration
+default_enabled: false
diff --git a/config/feature_flags/development/new_release_page.yml b/config/feature_flags/development/new_release_page.yml
index a17438ba949..b2890b9ebf9 100644
--- a/config/feature_flags/development/new_release_page.yml
+++ b/config/feature_flags/development/new_release_page.yml
@@ -1,7 +1,7 @@
---
name: new_release_page
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/35367
+rollout_issue_url:
+group: group::release management
type: development
default_enabled: true
diff --git a/config/feature_flags/development/new_variables_ui.yml b/config/feature_flags/development/new_variables_ui.yml
index 7621b356f5d..091c6e51013 100644
--- a/config/feature_flags/development/new_variables_ui.yml
+++ b/config/feature_flags/development/new_variables_ui.yml
@@ -1,7 +1,7 @@
---
name: new_variables_ui
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/25260
+rollout_issue_url:
+group: group::continuous integration
type: development
default_enabled: true
diff --git a/config/feature_flags/development/not_issuable_queries.yml b/config/feature_flags/development/not_issuable_queries.yml
index f6bbceff505..a5cfba7980d 100644
--- a/config/feature_flags/development/not_issuable_queries.yml
+++ b/config/feature_flags/development/not_issuable_queries.yml
@@ -1,7 +1,7 @@
---
name: not_issuable_queries
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/27639
+rollout_issue_url:
+group: group::project management
type: development
default_enabled: true
diff --git a/config/feature_flags/development/one_dimensional_matrix.yml b/config/feature_flags/development/one_dimensional_matrix.yml
new file mode 100644
index 00000000000..1db16474d38
--- /dev/null
+++ b/config/feature_flags/development/one_dimensional_matrix.yml
@@ -0,0 +1,7 @@
+---
+name: one_dimensional_matrix
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/42170
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/256062
+type: development
+group: group::pipeline authoring
+default_enabled: true
diff --git a/config/feature_flags/development/packages_coming_soon.yml b/config/feature_flags/development/packages_coming_soon.yml
deleted file mode 100644
index 0a0d1f989dc..00000000000
--- a/config/feature_flags/development/packages_coming_soon.yml
+++ /dev/null
@@ -1,7 +0,0 @@
----
-name: packages_coming_soon
-introduced_by_url:
-rollout_issue_url:
-group:
-type: development
-default_enabled: false
diff --git a/config/feature_flags/development/paginated_notes.yml b/config/feature_flags/development/paginated_notes.yml
index cd98b3b1bbf..a9209fbe4ae 100644
--- a/config/feature_flags/development/paginated_notes.yml
+++ b/config/feature_flags/development/paginated_notes.yml
@@ -1,7 +1,7 @@
---
name: paginated_notes
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/34628
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/254987
+group: group::source code
type: development
default_enabled: false
diff --git a/config/feature_flags/development/periodic_project_authorization_recalculation.yml b/config/feature_flags/development/periodic_project_authorization_recalculation.yml
deleted file mode 100644
index 90b9babcfca..00000000000
--- a/config/feature_flags/development/periodic_project_authorization_recalculation.yml
+++ /dev/null
@@ -1,7 +0,0 @@
----
-name: periodic_project_authorization_recalculation
-introduced_by_url:
-rollout_issue_url:
-group:
-type: development
-default_enabled: true
diff --git a/config/feature_flags/development/phabricator_import.yml b/config/feature_flags/development/phabricator_import.yml
index 32ccfed557e..1bce39b65f6 100644
--- a/config/feature_flags/development/phabricator_import.yml
+++ b/config/feature_flags/development/phabricator_import.yml
@@ -1,7 +1,7 @@
---
name: phabricator_import
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/13569
+rollout_issue_url: https://gitlab.com/groups/gitlab-org/-/epics/1197
+group: group::import
type: development
default_enabled: false
diff --git a/config/feature_flags/development/pipelines_security_report_summary.yml b/config/feature_flags/development/pipelines_security_report_summary.yml
index 943997f1a4f..b9e83bc0795 100644
--- a/config/feature_flags/development/pipelines_security_report_summary.yml
+++ b/config/feature_flags/development/pipelines_security_report_summary.yml
@@ -1,7 +1,7 @@
---
name: pipelines_security_report_summary
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/31136
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/235943
+group: group::dynamic analysis
type: development
default_enabled: false
diff --git a/config/feature_flags/development/product_analytics.yml b/config/feature_flags/development/product_analytics.yml
index 85bef678251..02840f3212b 100644
--- a/config/feature_flags/development/product_analytics.yml
+++ b/config/feature_flags/development/product_analytics.yml
@@ -1,7 +1,7 @@
---
name: product_analytics
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/36443
+rollout_issue_url:
+group: group::product analytics
type: development
default_enabled: false
diff --git a/config/feature_flags/development/project_export_as_ndjson.yml b/config/feature_flags/development/project_export_as_ndjson.yml
index eee61f4ce26..f39b892f18a 100644
--- a/config/feature_flags/development/project_export_as_ndjson.yml
+++ b/config/feature_flags/development/project_export_as_ndjson.yml
@@ -1,7 +1,7 @@
---
name: project_export_as_ndjson
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/26995
+rollout_issue_url:
+group: group::import
type: development
default_enabled: true
diff --git a/config/feature_flags/development/project_finder_similarity_sort.yml b/config/feature_flags/development/project_finder_similarity_sort.yml
new file mode 100644
index 00000000000..2d29bed82c4
--- /dev/null
+++ b/config/feature_flags/development/project_finder_similarity_sort.yml
@@ -0,0 +1,7 @@
+---
+name: project_finder_similarity_sort
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/43136
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/263249
+type: development
+group: group::threat insights
+default_enabled: false
diff --git a/config/feature_flags/development/project_import_ndjson.yml b/config/feature_flags/development/project_import_ndjson.yml
index a7971d462fe..8dc924a97c2 100644
--- a/config/feature_flags/development/project_import_ndjson.yml
+++ b/config/feature_flags/development/project_import_ndjson.yml
@@ -1,7 +1,7 @@
---
name: project_import_ndjson
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/27206
+rollout_issue_url:
+group: group::import
type: development
default_enabled: true
diff --git a/config/feature_flags/development/project_transactionless_destroy.yml b/config/feature_flags/development/project_transactionless_destroy.yml
index 07018632e7a..726875655e9 100644
--- a/config/feature_flags/development/project_transactionless_destroy.yml
+++ b/config/feature_flags/development/project_transactionless_destroy.yml
@@ -1,7 +1,7 @@
---
name: project_transactionless_destroy
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/39367
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/255972
+group: group::continuous integration
type: development
default_enabled: false
diff --git a/config/feature_flags/development/prometheus_computed_alerts.yml b/config/feature_flags/development/prometheus_computed_alerts.yml
index ddba72b2f46..576894df589 100644
--- a/config/feature_flags/development/prometheus_computed_alerts.yml
+++ b/config/feature_flags/development/prometheus_computed_alerts.yml
@@ -1,7 +1,7 @@
---
name: prometheus_computed_alerts
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/13443
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/255304
+group: group::health
type: development
default_enabled: false
diff --git a/config/feature_flags/development/push_mirror_syncs_lfs.yml b/config/feature_flags/development/push_mirror_syncs_lfs.yml
deleted file mode 100644
index d78fe679baa..00000000000
--- a/config/feature_flags/development/push_mirror_syncs_lfs.yml
+++ /dev/null
@@ -1,7 +0,0 @@
----
-name: push_mirror_syncs_lfs
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/40137
-rollout_issue_url:
-group: group::source code
-type: development
-default_enabled: false
diff --git a/config/feature_flags/development/reactive_caching_limit_environment.yml b/config/feature_flags/development/reactive_caching_limit_environment.yml
index 84db37d1d34..8aa66c9d293 100644
--- a/config/feature_flags/development/reactive_caching_limit_environment.yml
+++ b/config/feature_flags/development/reactive_caching_limit_environment.yml
@@ -1,7 +1,7 @@
---
name: reactive_caching_limit_environment
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/34202
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/202633
+group: group::configure
type: development
default_enabled: false
diff --git a/config/feature_flags/development/real_time_issue_sidebar.yml b/config/feature_flags/development/real_time_issue_sidebar.yml
index 7cbaabe643f..37284b2642c 100644
--- a/config/feature_flags/development/real_time_issue_sidebar.yml
+++ b/config/feature_flags/development/real_time_issue_sidebar.yml
@@ -1,7 +1,7 @@
---
name: real_time_issue_sidebar
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/30239
+rollout_issue_url: https://gitlab.com/gitlab-com/gl-infra/delivery/-/issues/1210
+group: group::project management
type: development
default_enabled: false
diff --git a/config/feature_flags/development/rebalance_issues.yml b/config/feature_flags/development/rebalance_issues.yml
index 4c14824a35d..df04da8c8d3 100644
--- a/config/feature_flags/development/rebalance_issues.yml
+++ b/config/feature_flags/development/rebalance_issues.yml
@@ -2,6 +2,6 @@
name: rebalance_issues
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/40124
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/239344
-group: 'group::project management'
+group: group::project management
type: development
default_enabled: false
diff --git a/config/feature_flags/development/recursive_approach_for_all_projects.yml b/config/feature_flags/development/recursive_approach_for_all_projects.yml
new file mode 100644
index 00000000000..10c51419d6a
--- /dev/null
+++ b/config/feature_flags/development/recursive_approach_for_all_projects.yml
@@ -0,0 +1,7 @@
+---
+name: recursive_approach_for_all_projects
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/44740
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/263442
+type: development
+group: group::fulfillment
+default_enabled: false
diff --git a/config/feature_flags/development/release_asset_link_editing.yml b/config/feature_flags/development/release_asset_link_editing.yml
deleted file mode 100644
index 6e6cce2c343..00000000000
--- a/config/feature_flags/development/release_asset_link_editing.yml
+++ /dev/null
@@ -1,7 +0,0 @@
----
-name: release_asset_link_editing
-introduced_by_url:
-rollout_issue_url:
-group:
-type: development
-default_enabled: true
diff --git a/config/feature_flags/development/release_asset_link_type.yml b/config/feature_flags/development/release_asset_link_type.yml
deleted file mode 100644
index baeb2e59f82..00000000000
--- a/config/feature_flags/development/release_asset_link_type.yml
+++ /dev/null
@@ -1,7 +0,0 @@
----
-name: release_asset_link_type
-introduced_by_url:
-rollout_issue_url:
-group:
-type: development
-default_enabled: true
diff --git a/config/feature_flags/development/release_evidence.yml b/config/feature_flags/development/release_evidence.yml
index a19994d51a7..c2f7ab16332 100644
--- a/config/feature_flags/development/release_evidence.yml
+++ b/config/feature_flags/development/release_evidence.yml
@@ -1,7 +1,7 @@
---
name: release_evidence
-introduced_by_url:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/26509
rollout_issue_url:
-group:
+group: group::release management
type: development
default_enabled: true
diff --git a/config/feature_flags/development/release_evidence_collection.yml b/config/feature_flags/development/release_evidence_collection.yml
deleted file mode 100644
index c5ab8f8e5c0..00000000000
--- a/config/feature_flags/development/release_evidence_collection.yml
+++ /dev/null
@@ -1,7 +0,0 @@
----
-name: release_evidence_collection
-introduced_by_url:
-rollout_issue_url:
-group:
-type: development
-default_enabled: true
diff --git a/config/feature_flags/development/release_issue_summary.yml b/config/feature_flags/development/release_issue_summary.yml
deleted file mode 100644
index ebd8ef2e4d0..00000000000
--- a/config/feature_flags/development/release_issue_summary.yml
+++ /dev/null
@@ -1,7 +0,0 @@
----
-name: release_issue_summary
-introduced_by_url:
-rollout_issue_url:
-group:
-type: development
-default_enabled: true
diff --git a/config/feature_flags/development/release_mr_issue_urls.yml b/config/feature_flags/development/release_mr_issue_urls.yml
index f6abf50f535..3f9c81b8fe9 100644
--- a/config/feature_flags/development/release_mr_issue_urls.yml
+++ b/config/feature_flags/development/release_mr_issue_urls.yml
@@ -1,7 +1,7 @@
---
name: release_mr_issue_urls
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/18727
+rollout_issue_url:
+group: group::release management
type: development
default_enabled: false
diff --git a/config/feature_flags/development/release_show_page.yml b/config/feature_flags/development/release_show_page.yml
deleted file mode 100644
index 5a3f1709452..00000000000
--- a/config/feature_flags/development/release_show_page.yml
+++ /dev/null
@@ -1,7 +0,0 @@
----
-name: release_show_page
-introduced_by_url:
-rollout_issue_url:
-group:
-type: development
-default_enabled: true
diff --git a/config/feature_flags/development/remove_legacy_github_client.yml b/config/feature_flags/development/remove_legacy_github_client.yml
index adb0c7b5d03..ecb8e103949 100644
--- a/config/feature_flags/development/remove_legacy_github_client.yml
+++ b/config/feature_flags/development/remove_legacy_github_client.yml
@@ -1,7 +1,7 @@
---
name: remove_legacy_github_client
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url:
+rollout_issue_url:
+group: group::import
type: development
default_enabled: false
diff --git a/config/feature_flags/development/repack_after_shard_migration.yml b/config/feature_flags/development/repack_after_shard_migration.yml
index addfcf66537..18663a4e7af 100644
--- a/config/feature_flags/development/repack_after_shard_migration.yml
+++ b/config/feature_flags/development/repack_after_shard_migration.yml
@@ -1,7 +1,7 @@
---
name: repack_after_shard_migration
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/21502
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/195597
+group: group::source code
type: development
default_enabled: false
diff --git a/config/feature_flags/development/resource_access_token.yml b/config/feature_flags/development/resource_access_token.yml
deleted file mode 100644
index 80c5b2a5eb4..00000000000
--- a/config/feature_flags/development/resource_access_token.yml
+++ /dev/null
@@ -1,7 +0,0 @@
----
-name: resource_access_token
-introduced_by_url:
-rollout_issue_url:
-group:
-type: development
-default_enabled: true
diff --git a/config/feature_flags/development/safezip_use_rubyzip.yml b/config/feature_flags/development/safezip_use_rubyzip.yml
deleted file mode 100644
index 139283d93d2..00000000000
--- a/config/feature_flags/development/safezip_use_rubyzip.yml
+++ /dev/null
@@ -1,7 +0,0 @@
----
-name: safezip_use_rubyzip
-introduced_by_url:
-rollout_issue_url:
-group:
-type: development
-default_enabled: true
diff --git a/config/feature_flags/development/save_raw_usage_data.yml b/config/feature_flags/development/save_raw_usage_data.yml
index 9556f699b9b..b3c65c12e2d 100644
--- a/config/feature_flags/development/save_raw_usage_data.yml
+++ b/config/feature_flags/development/save_raw_usage_data.yml
@@ -1,7 +1,7 @@
---
name: save_raw_usage_data
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/38457
+rollout_issue_url:
+group: group::product analytics
type: development
default_enabled: false
diff --git a/config/feature_flags/development/schema_linting.yml b/config/feature_flags/development/schema_linting.yml
index 1220b02be0d..3722f1dd97f 100644
--- a/config/feature_flags/development/schema_linting.yml
+++ b/config/feature_flags/development/schema_linting.yml
@@ -1,7 +1,7 @@
---
name: schema_linting
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/35838
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/255919
+group: group::editor
type: development
default_enabled: false
diff --git a/config/feature_flags/development/search_filter_by_confidential.yml b/config/feature_flags/development/search_filter_by_confidential.yml
new file mode 100644
index 00000000000..0a952a4d25e
--- /dev/null
+++ b/config/feature_flags/development/search_filter_by_confidential.yml
@@ -0,0 +1,7 @@
+---
+name: search_filter_by_confidential
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/40793
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/244923
+group: group::global search
+type: development
+default_enabled: false \ No newline at end of file
diff --git a/config/feature_flags/development/security_auto_fix.yml b/config/feature_flags/development/security_auto_fix.yml
new file mode 100644
index 00000000000..b97220a1059
--- /dev/null
+++ b/config/feature_flags/development/security_auto_fix.yml
@@ -0,0 +1,7 @@
+---
+name: security_auto_fix
+introduced_by_url:
+rollout_issue_url:
+group: group::composition analysis
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/serverless_domain.yml b/config/feature_flags/development/serverless_domain.yml
index 160730117d6..f4821e5a14c 100644
--- a/config/feature_flags/development/serverless_domain.yml
+++ b/config/feature_flags/development/serverless_domain.yml
@@ -1,7 +1,7 @@
---
name: serverless_domain
-introduced_by_url:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/21222
rollout_issue_url:
-group:
+group: group::configure
type: development
default_enabled: false
diff --git a/config/feature_flags/development/service_desk_custom_address.yml b/config/feature_flags/development/service_desk_custom_address.yml
index 25cab0059c7..13a9ef6f37a 100644
--- a/config/feature_flags/development/service_desk_custom_address.yml
+++ b/config/feature_flags/development/service_desk_custom_address.yml
@@ -2,6 +2,6 @@
name: service_desk_custom_address
introduced_by_url:
rollout_issue_url:
-group:
+group: group::certify
type: development
default_enabled: false
diff --git a/config/feature_flags/development/settings_operations_prometheus_service.yml b/config/feature_flags/development/settings_operations_prometheus_service.yml
index de2df4b219d..1a4815a3fb9 100644
--- a/config/feature_flags/development/settings_operations_prometheus_service.yml
+++ b/config/feature_flags/development/settings_operations_prometheus_service.yml
@@ -1,7 +1,7 @@
---
name: settings_operations_prometheus_service
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/24296
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/258560
+group: group::health
type: development
default_enabled: false
diff --git a/config/feature_flags/development/show_contributor_on_note.yml b/config/feature_flags/development/show_contributor_on_note.yml
deleted file mode 100644
index 89533037244..00000000000
--- a/config/feature_flags/development/show_contributor_on_note.yml
+++ /dev/null
@@ -1,7 +0,0 @@
----
-name: show_contributor_on_note
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/40198
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/249179
-group: group::project management
-type: development
-default_enabled: false \ No newline at end of file
diff --git a/config/feature_flags/development/show_inherited_labels.yml b/config/feature_flags/development/show_inherited_labels.yml
new file mode 100644
index 00000000000..73ceb07002c
--- /dev/null
+++ b/config/feature_flags/development/show_inherited_labels.yml
@@ -0,0 +1,7 @@
+---
+name: show_inherited_labels
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/42960
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/267547
+group: group::project management
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/similarity_search.yml b/config/feature_flags/development/similarity_search.yml
index b7d48c5b986..f99e80b5cc7 100644
--- a/config/feature_flags/development/similarity_search.yml
+++ b/config/feature_flags/development/similarity_search.yml
@@ -1,7 +1,7 @@
---
name: similarity_search
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/37300/
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/38675
+group: group::analytics
type: development
default_enabled: true
diff --git a/config/feature_flags/development/snippet_multiple_files.yml b/config/feature_flags/development/snippet_multiple_files.yml
deleted file mode 100644
index 28520cea19c..00000000000
--- a/config/feature_flags/development/snippet_multiple_files.yml
+++ /dev/null
@@ -1,7 +0,0 @@
----
-name: snippet_multiple_files
-introduced_by_url:
-rollout_issue_url:
-group:
-type: development
-default_enabled: false
diff --git a/config/feature_flags/development/snippet_spam.yml b/config/feature_flags/development/snippet_spam.yml
new file mode 100644
index 00000000000..8215766fd3f
--- /dev/null
+++ b/config/feature_flags/development/snippet_spam.yml
@@ -0,0 +1,7 @@
+---
+name: snippet_spam
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/44010
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/262013
+type: development
+group: group::editor
+default_enabled: false
diff --git a/config/feature_flags/development/snippets_binary_blob.yml b/config/feature_flags/development/snippets_binary_blob.yml
index c8d1b5d6ba2..6ab05b096ba 100644
--- a/config/feature_flags/development/snippets_binary_blob.yml
+++ b/config/feature_flags/development/snippets_binary_blob.yml
@@ -1,7 +1,7 @@
---
name: snippets_binary_blob
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url:
+rollout_issue_url:
+group: group::editor
type: development
default_enabled: false
diff --git a/config/feature_flags/development/snippets_edit_vue.yml b/config/feature_flags/development/snippets_edit_vue.yml
deleted file mode 100644
index d62926a8337..00000000000
--- a/config/feature_flags/development/snippets_edit_vue.yml
+++ /dev/null
@@ -1,7 +0,0 @@
----
-name: snippets_edit_vue
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/25667
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/207239
-group: group::editor
-type: development
-default_enabled: true
diff --git a/config/feature_flags/development/snippets_vue.yml b/config/feature_flags/development/snippets_vue.yml
deleted file mode 100644
index b3b7e525a6e..00000000000
--- a/config/feature_flags/development/snippets_vue.yml
+++ /dev/null
@@ -1,7 +0,0 @@
----
-name: snippets_vue
-introduced_by_url:
-rollout_issue_url:
-group:
-type: development
-default_enabled: true
diff --git a/config/feature_flags/development/soft_email_confirmation.yml b/config/feature_flags/development/soft_email_confirmation.yml
index d471cf442de..ee951d84ed8 100644
--- a/config/feature_flags/development/soft_email_confirmation.yml
+++ b/config/feature_flags/development/soft_email_confirmation.yml
@@ -1,7 +1,7 @@
---
name: soft_email_confirmation
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/31245
+rollout_issue_url:
+group: group::acquisition
type: development
default_enabled: false
diff --git a/config/feature_flags/development/soft_fail_count_by_state.yml b/config/feature_flags/development/soft_fail_count_by_state.yml
new file mode 100644
index 00000000000..a8cd1a35e44
--- /dev/null
+++ b/config/feature_flags/development/soft_fail_count_by_state.yml
@@ -0,0 +1,7 @@
+---
+name: soft_fail_count_by_state
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/44184
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/263222
+type: development
+group: group::source code
+default_enabled: false
diff --git a/config/feature_flags/development/specialized_project_authorization_project_share_worker.yml b/config/feature_flags/development/specialized_project_authorization_project_share_worker.yml
index c09c5ad519b..951ea4b315f 100644
--- a/config/feature_flags/development/specialized_project_authorization_project_share_worker.yml
+++ b/config/feature_flags/development/specialized_project_authorization_project_share_worker.yml
@@ -1,7 +1,7 @@
---
name: specialized_project_authorization_project_share_worker
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/32864
+rollout_issue_url:
+group: group::access
type: development
default_enabled: false
diff --git a/config/feature_flags/development/specialized_project_authorization_workers.yml b/config/feature_flags/development/specialized_project_authorization_workers.yml
index 7fceff532f3..48372cac765 100644
--- a/config/feature_flags/development/specialized_project_authorization_workers.yml
+++ b/config/feature_flags/development/specialized_project_authorization_workers.yml
@@ -1,7 +1,7 @@
---
name: specialized_project_authorization_workers
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/31377
+rollout_issue_url:
+group: group::access
type: development
default_enabled: false
diff --git a/config/feature_flags/development/sql-set-operators.yml b/config/feature_flags/development/sql-set-operators.yml
deleted file mode 100644
index cefe2a83782..00000000000
--- a/config/feature_flags/development/sql-set-operators.yml
+++ /dev/null
@@ -1,7 +0,0 @@
----
-name: sql-set-operators
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/39786
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/39786
-group: group::access
-type: development
-default_enabled: false
diff --git a/config/feature_flags/development/sql_set_operators.yml b/config/feature_flags/development/sql_set_operators.yml
index b8a838a13f1..2098a19a24a 100644
--- a/config/feature_flags/development/sql_set_operators.yml
+++ b/config/feature_flags/development/sql_set_operators.yml
@@ -1,7 +1,7 @@
---
name: sql_set_operators
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/39786
+rollout_issue_url:
+group: group::access
type: development
default_enabled: false
diff --git a/config/feature_flags/development/store_ci_pipeline_counts_by_status.yml b/config/feature_flags/development/store_ci_pipeline_counts_by_status.yml
new file mode 100644
index 00000000000..62044bf855a
--- /dev/null
+++ b/config/feature_flags/development/store_ci_pipeline_counts_by_status.yml
@@ -0,0 +1,7 @@
+---
+name: store_ci_pipeline_counts_by_status
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/43027
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/254721
+type: development
+group: group::analytics
+default_enabled: true
diff --git a/config/feature_flags/development/store_instance_statistics_measurements.yml b/config/feature_flags/development/store_instance_statistics_measurements.yml
deleted file mode 100644
index 9483b9005df..00000000000
--- a/config/feature_flags/development/store_instance_statistics_measurements.yml
+++ /dev/null
@@ -1,7 +0,0 @@
----
-name: store_instance_statistics_measurements
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/41300
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/247871
-group: group::analytics
-type: development
-default_enabled: true
diff --git a/config/feature_flags/development/store_mentioned_users_to_db.yml b/config/feature_flags/development/store_mentioned_users_to_db.yml
deleted file mode 100644
index e19076f2b84..00000000000
--- a/config/feature_flags/development/store_mentioned_users_to_db.yml
+++ /dev/null
@@ -1,7 +0,0 @@
----
-name: store_mentioned_users_to_db
-introduced_by_url:
-rollout_issue_url:
-group:
-type: development
-default_enabled: true
diff --git a/config/feature_flags/development/suggest_pipeline.yml b/config/feature_flags/development/suggest_pipeline.yml
deleted file mode 100644
index bd467f4bcca..00000000000
--- a/config/feature_flags/development/suggest_pipeline.yml
+++ /dev/null
@@ -1,7 +0,0 @@
----
-name: suggest_pipeline
-introduced_by_url:
-rollout_issue_url:
-group:
-type: development
-default_enabled: false
diff --git a/config/feature_flags/development/sync_metrics_dashboards.yml b/config/feature_flags/development/sync_metrics_dashboards.yml
new file mode 100644
index 00000000000..2dd8964121a
--- /dev/null
+++ b/config/feature_flags/development/sync_metrics_dashboards.yml
@@ -0,0 +1,7 @@
+---
+name: sync_metrics_dashboards
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/39658
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/241793
+group: group::apm
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/track_issue_activity_actions.yml b/config/feature_flags/development/track_issue_activity_actions.yml
index 034b697ab52..f80831e1b35 100644
--- a/config/feature_flags/development/track_issue_activity_actions.yml
+++ b/config/feature_flags/development/track_issue_activity_actions.yml
@@ -2,6 +2,6 @@
name: track_issue_activity_actions
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/40904
rollout_issue_url:
-group: group::project_management
+group: group::project management
type: development
-default_enabled: false \ No newline at end of file
+default_enabled: true
diff --git a/config/feature_flags/development/track_resource_state_change_events.yml b/config/feature_flags/development/track_resource_state_change_events.yml
deleted file mode 100644
index 3bfde5cf05e..00000000000
--- a/config/feature_flags/development/track_resource_state_change_events.yml
+++ /dev/null
@@ -1,7 +0,0 @@
----
-name: track_resource_state_change_events
-introduced_by_url:
-rollout_issue_url:
-group:
-type: development
-default_enabled: true
diff --git a/config/feature_flags/development/track_unique_test_cases_parsed.yml b/config/feature_flags/development/track_unique_test_cases_parsed.yml
new file mode 100644
index 00000000000..98ae38e1cb0
--- /dev/null
+++ b/config/feature_flags/development/track_unique_test_cases_parsed.yml
@@ -0,0 +1,7 @@
+---
+name: track_unique_test_cases_parsed
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/41918
+rollout_issue_url:
+group: group::testing
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/track_unique_visits.yml b/config/feature_flags/development/track_unique_visits.yml
index 6a60d327e87..10f78a32492 100644
--- a/config/feature_flags/development/track_unique_visits.yml
+++ b/config/feature_flags/development/track_unique_visits.yml
@@ -1,7 +1,7 @@
---
name: track_unique_visits
-introduced_by_url:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/33146
rollout_issue_url:
-group:
+group: group::analytics
type: development
-default_enabled: false
+default_enabled: true
diff --git a/config/feature_flags/development/track_unique_wiki_page_views.yml b/config/feature_flags/development/track_unique_wiki_page_views.yml
new file mode 100644
index 00000000000..0e8120635ab
--- /dev/null
+++ b/config/feature_flags/development/track_unique_wiki_page_views.yml
@@ -0,0 +1,7 @@
+---
+name: track_unique_wiki_page_views
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/44622
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/267162
+type: development
+group: group::knowledge
+default_enabled: true
diff --git a/config/feature_flags/development/tribute_autocomplete.yml b/config/feature_flags/development/tribute_autocomplete.yml
index 31ee1b932d3..94cfc00c467 100644
--- a/config/feature_flags/development/tribute_autocomplete.yml
+++ b/config/feature_flags/development/tribute_autocomplete.yml
@@ -1,7 +1,7 @@
---
name: tribute_autocomplete
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/32671
+rollout_issue_url:
+group: group::project management
type: development
default_enabled: false
diff --git a/config/feature_flags/development/two_factor_for_cli.yml b/config/feature_flags/development/two_factor_for_cli.yml
new file mode 100644
index 00000000000..f75264451e0
--- /dev/null
+++ b/config/feature_flags/development/two_factor_for_cli.yml
@@ -0,0 +1,7 @@
+---
+name: two_factor_for_cli
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/39703
+rollout_issue_url:
+type: development
+group: group::access
+default_enabled: false
diff --git a/config/feature_flags/development/unified_diff_lines.yml b/config/feature_flags/development/unified_diff_lines.yml
index a676f0732dd..d580ef65104 100644
--- a/config/feature_flags/development/unified_diff_lines.yml
+++ b/config/feature_flags/development/unified_diff_lines.yml
@@ -4,4 +4,4 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/40131
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/241188
group: group::source code
type: development
-default_enabled: false
+default_enabled: true
diff --git a/config/feature_flags/development/upload_middleware_jwt_params_handler.yml b/config/feature_flags/development/upload_middleware_jwt_params_handler.yml
index b467ade8609..1c3545cb728 100644
--- a/config/feature_flags/development/upload_middleware_jwt_params_handler.yml
+++ b/config/feature_flags/development/upload_middleware_jwt_params_handler.yml
@@ -4,4 +4,4 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/33277
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/233895
group: group::package
type: development
-default_enabled: false
+default_enabled: true
diff --git a/config/feature_flags/development/usage_data_a_compliance_audit_events_api.yml b/config/feature_flags/development/usage_data_a_compliance_audit_events_api.yml
new file mode 100644
index 00000000000..8b2e8063164
--- /dev/null
+++ b/config/feature_flags/development/usage_data_a_compliance_audit_events_api.yml
@@ -0,0 +1,7 @@
+---
+name: usage_data_a_compliance_audit_events_api
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/41689
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/233786
+group: group::compliance
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/usage_data_api.yml b/config/feature_flags/development/usage_data_api.yml
index 0976b27d417..5c8e918521d 100644
--- a/config/feature_flags/development/usage_data_api.yml
+++ b/config/feature_flags/development/usage_data_api.yml
@@ -1,7 +1,7 @@
---
name: usage_data_api
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/41301
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/235459
-group: group::telemetry
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/267114
+group: group::product analytics
type: development
-default_enabled: false
+default_enabled: true
diff --git a/config/feature_flags/development/usage_data_g_compliance_dashboard.yml b/config/feature_flags/development/usage_data_g_compliance_dashboard.yml
index 6f971788d88..24d6f81740b 100644
--- a/config/feature_flags/development/usage_data_g_compliance_dashboard.yml
+++ b/config/feature_flags/development/usage_data_g_compliance_dashboard.yml
@@ -1,7 +1,7 @@
---
name: usage_data_g_compliance_dashboard
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url:
+rollout_issue_url:
+group: group::compliance
type: development
default_enabled: false
diff --git a/config/feature_flags/development/usage_data_i_source_code_code_intelligence.yml b/config/feature_flags/development/usage_data_i_source_code_code_intelligence.yml
new file mode 100644
index 00000000000..15ce7194264
--- /dev/null
+++ b/config/feature_flags/development/usage_data_i_source_code_code_intelligence.yml
@@ -0,0 +1,7 @@
+---
+name: usage_data_i_source_code_code_intelligence
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/41881
+rollout_issue_url:
+group: group::source code
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/usage_data_i_testing_test_case_parsed.yml b/config/feature_flags/development/usage_data_i_testing_test_case_parsed.yml
new file mode 100644
index 00000000000..095010da56b
--- /dev/null
+++ b/config/feature_flags/development/usage_data_i_testing_test_case_parsed.yml
@@ -0,0 +1,7 @@
+---
+name: usage_data_i_testing_test_case_parsed
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/41918
+rollout_issue_url:
+group: group::testing
+type: development
+default_enabled: true
diff --git a/config/feature_flags/development/usage_data_incident_management_alert_assigned.yml b/config/feature_flags/development/usage_data_incident_management_alert_assigned.yml
index 22589d00ae0..a50a3eafa1a 100644
--- a/config/feature_flags/development/usage_data_incident_management_alert_assigned.yml
+++ b/config/feature_flags/development/usage_data_incident_management_alert_assigned.yml
@@ -1,7 +1,7 @@
---
name: usage_data_incident_management_alert_assigned
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/40475
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/229918
+group: group::health
type: development
default_enabled: true
diff --git a/config/feature_flags/development/usage_data_incident_management_alert_status_changed.yml b/config/feature_flags/development/usage_data_incident_management_alert_status_changed.yml
index 10f987ecd65..957e316e153 100644
--- a/config/feature_flags/development/usage_data_incident_management_alert_status_changed.yml
+++ b/config/feature_flags/development/usage_data_incident_management_alert_status_changed.yml
@@ -1,7 +1,7 @@
---
name: usage_data_incident_management_alert_status_changed
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/40475
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/229918
+group: group::health
type: development
default_enabled: true
diff --git a/config/feature_flags/development/usage_data_incident_management_alert_todo.yml b/config/feature_flags/development/usage_data_incident_management_alert_todo.yml
index 67d18480a56..5e64899978a 100644
--- a/config/feature_flags/development/usage_data_incident_management_alert_todo.yml
+++ b/config/feature_flags/development/usage_data_incident_management_alert_todo.yml
@@ -1,7 +1,7 @@
---
name: usage_data_incident_management_alert_todo
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/40475
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/229918
+group: group::health
type: development
default_enabled: true
diff --git a/config/feature_flags/development/usage_data_incident_management_incident_assigned.yml b/config/feature_flags/development/usage_data_incident_management_incident_assigned.yml
index 1b48fe4ac9c..a582a44a3e2 100644
--- a/config/feature_flags/development/usage_data_incident_management_incident_assigned.yml
+++ b/config/feature_flags/development/usage_data_incident_management_incident_assigned.yml
@@ -1,7 +1,7 @@
---
name: usage_data_incident_management_incident_assigned
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/40475
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/229918
+group: group::health
type: development
default_enabled: true
diff --git a/config/feature_flags/development/usage_data_incident_management_incident_change_confidential.yml b/config/feature_flags/development/usage_data_incident_management_incident_change_confidential.yml
index 6235382fd59..ad482676132 100644
--- a/config/feature_flags/development/usage_data_incident_management_incident_change_confidential.yml
+++ b/config/feature_flags/development/usage_data_incident_management_incident_change_confidential.yml
@@ -1,7 +1,7 @@
---
name: usage_data_incident_management_incident_change_confidential
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/40475
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/229918
+group: group::health
type: development
default_enabled: true
diff --git a/config/feature_flags/development/usage_data_incident_management_incident_closed.yml b/config/feature_flags/development/usage_data_incident_management_incident_closed.yml
index 4f8f9b951ed..943b7a83e5e 100644
--- a/config/feature_flags/development/usage_data_incident_management_incident_closed.yml
+++ b/config/feature_flags/development/usage_data_incident_management_incident_closed.yml
@@ -1,7 +1,7 @@
---
name: usage_data_incident_management_incident_closed
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/40475
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/229918
+group: group::health
type: development
default_enabled: true
diff --git a/config/feature_flags/development/usage_data_incident_management_incident_comment.yml b/config/feature_flags/development/usage_data_incident_management_incident_comment.yml
index b41c96d3b04..5d173e1e869 100644
--- a/config/feature_flags/development/usage_data_incident_management_incident_comment.yml
+++ b/config/feature_flags/development/usage_data_incident_management_incident_comment.yml
@@ -1,7 +1,7 @@
---
name: usage_data_incident_management_incident_comment
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/40475
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/229918
+group: group::health
type: development
default_enabled: true
diff --git a/config/feature_flags/development/usage_data_incident_management_incident_created.yml b/config/feature_flags/development/usage_data_incident_management_incident_created.yml
index 693cc23dc3b..86e47d54d18 100644
--- a/config/feature_flags/development/usage_data_incident_management_incident_created.yml
+++ b/config/feature_flags/development/usage_data_incident_management_incident_created.yml
@@ -1,7 +1,7 @@
---
name: usage_data_incident_management_incident_created
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/40475
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/229918
+group: group::health
type: development
default_enabled: true
diff --git a/config/feature_flags/development/usage_data_incident_management_incident_relate.yml b/config/feature_flags/development/usage_data_incident_management_incident_relate.yml
index 70b4c5c3f65..84ba0d34cc7 100644
--- a/config/feature_flags/development/usage_data_incident_management_incident_relate.yml
+++ b/config/feature_flags/development/usage_data_incident_management_incident_relate.yml
@@ -1,7 +1,7 @@
---
name: usage_data_incident_management_incident_relate
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/40475
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/229918
+group: group::health
type: development
default_enabled: true
diff --git a/config/feature_flags/development/usage_data_incident_management_incident_reopened.yml b/config/feature_flags/development/usage_data_incident_management_incident_reopened.yml
index ccb108a4a28..ed71d353cfe 100644
--- a/config/feature_flags/development/usage_data_incident_management_incident_reopened.yml
+++ b/config/feature_flags/development/usage_data_incident_management_incident_reopened.yml
@@ -1,7 +1,7 @@
---
name: usage_data_incident_management_incident_reopened
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/40475
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/229918
+group: group::health
type: development
default_enabled: true
diff --git a/config/feature_flags/development/usage_data_incident_management_incident_todo.yml b/config/feature_flags/development/usage_data_incident_management_incident_todo.yml
index c517a66a151..aa400fb4455 100644
--- a/config/feature_flags/development/usage_data_incident_management_incident_todo.yml
+++ b/config/feature_flags/development/usage_data_incident_management_incident_todo.yml
@@ -1,7 +1,7 @@
---
name: usage_data_incident_management_incident_todo
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/40475
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/229918
+group: group::health
type: development
default_enabled: true
diff --git a/config/feature_flags/development/usage_data_incident_management_incident_unrelate.yml b/config/feature_flags/development/usage_data_incident_management_incident_unrelate.yml
index da418eb79a4..5798331175e 100644
--- a/config/feature_flags/development/usage_data_incident_management_incident_unrelate.yml
+++ b/config/feature_flags/development/usage_data_incident_management_incident_unrelate.yml
@@ -1,7 +1,7 @@
---
name: usage_data_incident_management_incident_unrelate
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/40475
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/229918
+group: group::health
type: development
default_enabled: true
diff --git a/config/feature_flags/development/usage_data_incident_management_incident_zoom_meeting.yml b/config/feature_flags/development/usage_data_incident_management_incident_zoom_meeting.yml
index bbe81fdf3ed..921c466a167 100644
--- a/config/feature_flags/development/usage_data_incident_management_incident_zoom_meeting.yml
+++ b/config/feature_flags/development/usage_data_incident_management_incident_zoom_meeting.yml
@@ -1,7 +1,7 @@
---
name: usage_data_incident_management_incident_zoom_meeting
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/40475
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/229918
+group: group::health
type: development
default_enabled: true
diff --git a/config/feature_flags/development/users_search.yml b/config/feature_flags/development/users_search.yml
deleted file mode 100644
index 0397ee60225..00000000000
--- a/config/feature_flags/development/users_search.yml
+++ /dev/null
@@ -1,7 +0,0 @@
----
-name: users_search
-introduced_by_url:
-rollout_issue_url:
-group:
-type: development
-default_enabled: true
diff --git a/config/feature_flags/development/validate_import_decompressed_archive_size.yml b/config/feature_flags/development/validate_import_decompressed_archive_size.yml
index 28876f5180f..3e575657a78 100644
--- a/config/feature_flags/development/validate_import_decompressed_archive_size.yml
+++ b/config/feature_flags/development/validate_import_decompressed_archive_size.yml
@@ -1,7 +1,7 @@
---
name: validate_import_decompressed_archive_size
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url:
+rollout_issue_url:
+group: group::import
type: development
default_enabled: false
diff --git a/config/feature_flags/development/view_diffs_file_by_file.yml b/config/feature_flags/development/view_diffs_file_by_file.yml
index 4df755943ab..2ac8a7c3087 100644
--- a/config/feature_flags/development/view_diffs_file_by_file.yml
+++ b/config/feature_flags/development/view_diffs_file_by_file.yml
@@ -1,7 +1,7 @@
---
name: view_diffs_file_by_file
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/35223
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/229848
+group: group::source code
type: development
default_enabled: true
diff --git a/config/feature_flags/development/vue_issuable_sidebar.yml b/config/feature_flags/development/vue_issuable_sidebar.yml
index d57852c9491..01c8bc3460b 100644
--- a/config/feature_flags/development/vue_issuable_sidebar.yml
+++ b/config/feature_flags/development/vue_issuable_sidebar.yml
@@ -1,7 +1,7 @@
---
name: vue_issuable_sidebar
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/18199
+rollout_issue_url:
+group: group::project management
type: development
default_enabled: false
diff --git a/config/feature_flags/development/vue_issuables_list.yml b/config/feature_flags/development/vue_issuables_list.yml
index 79ade237824..5fe5c7e3e9f 100644
--- a/config/feature_flags/development/vue_issuables_list.yml
+++ b/config/feature_flags/development/vue_issuables_list.yml
@@ -1,7 +1,7 @@
---
name: vue_issuables_list
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/15091
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/208093
+group: group::project management
type: development
default_enabled: false
diff --git a/config/feature_flags/development/web_ide_primary_edit.yml b/config/feature_flags/development/web_ide_primary_edit.yml
index 8bea7fd94e7..33e3db0322b 100644
--- a/config/feature_flags/development/web_ide_primary_edit.yml
+++ b/config/feature_flags/development/web_ide_primary_edit.yml
@@ -1,7 +1,7 @@
---
name: web_ide_primary_edit
-introduced_by_url:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/35957
rollout_issue_url:
-group:
+group: group::editor
type: development
default_enabled: false
diff --git a/config/feature_flags/development/webperf_experiment.yml b/config/feature_flags/development/webperf_experiment.yml
index 02c2a12cfaf..16f1f0ac773 100644
--- a/config/feature_flags/development/webperf_experiment.yml
+++ b/config/feature_flags/development/webperf_experiment.yml
@@ -1,7 +1,7 @@
---
name: webperf_experiment
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url:
+rollout_issue_url:
+group: group::editor
type: development
default_enabled: false
diff --git a/config/feature_flags/development/whats_new_drawer.yml b/config/feature_flags/development/whats_new_drawer.yml
index 6e31b17e05a..d6b7ffbbb57 100644
--- a/config/feature_flags/development/whats_new_drawer.yml
+++ b/config/feature_flags/development/whats_new_drawer.yml
@@ -1,7 +1,7 @@
---
name: whats_new_drawer
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/38975
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/254186
+group: group::retention
type: development
default_enabled: false
diff --git a/config/feature_flags/development/widget_visibility_polling.yml b/config/feature_flags/development/widget_visibility_polling.yml
index c0c6962a46d..711d4be2fd1 100644
--- a/config/feature_flags/development/widget_visibility_polling.yml
+++ b/config/feature_flags/development/widget_visibility_polling.yml
@@ -1,7 +1,7 @@
---
name: widget_visibility_polling
-introduced_by_url:
-rollout_issue_url:
-group:
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/29318
+rollout_issue_url:
+group: group::source code
type: development
default_enabled: true
diff --git a/config/feature_flags/development/wiki_events_on_git_push.yml b/config/feature_flags/development/wiki_events_on_git_push.yml
deleted file mode 100644
index abab9029bae..00000000000
--- a/config/feature_flags/development/wiki_events_on_git_push.yml
+++ /dev/null
@@ -1,7 +0,0 @@
----
-name: wiki_events_on_git_push
-introduced_by_url:
-rollout_issue_url:
-group:
-type: development
-default_enabled: false
diff --git a/config/feature_flags/development/zip_pages_deployments.yml b/config/feature_flags/development/zip_pages_deployments.yml
new file mode 100644
index 00000000000..3bafc2aae14
--- /dev/null
+++ b/config/feature_flags/development/zip_pages_deployments.yml
@@ -0,0 +1,7 @@
+---
+name: zip_pages_deployments
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/42834
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/245308
+group: group::release management
+type: development
+default_enabled: false \ No newline at end of file
diff --git a/config/feature_flags/licensed/incident_sla.yml b/config/feature_flags/licensed/incident_sla.yml
new file mode 100644
index 00000000000..e59251dd82f
--- /dev/null
+++ b/config/feature_flags/licensed/incident_sla.yml
@@ -0,0 +1,7 @@
+---
+name: incident_sla
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/43648
+rollout_issue_url:
+group: group::health
+type: licensed
+default_enabled: true
diff --git a/config/feature_flags/licensed/minimal_access_role.yml b/config/feature_flags/licensed/minimal_access_role.yml
new file mode 100644
index 00000000000..ca27b86d35f
--- /dev/null
+++ b/config/feature_flags/licensed/minimal_access_role.yml
@@ -0,0 +1,7 @@
+---
+name: minimal_access_role
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/40942
+rollout_issue_url:
+group: group::access
+type: licensed
+default_enabled: true
diff --git a/config/feature_flags/licensed/resource_access_token.yml b/config/feature_flags/licensed/resource_access_token.yml
new file mode 100644
index 00000000000..c236851881d
--- /dev/null
+++ b/config/feature_flags/licensed/resource_access_token.yml
@@ -0,0 +1,7 @@
+---
+name: resource_access_token
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/29622
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/235765
+group: group::access
+type: licensed
+default_enabled: true
diff --git a/config/feature_flags/ops/api_kaminari_count_with_limit.yml b/config/feature_flags/ops/api_kaminari_count_with_limit.yml
new file mode 100644
index 00000000000..1fdeaa53b83
--- /dev/null
+++ b/config/feature_flags/ops/api_kaminari_count_with_limit.yml
@@ -0,0 +1,7 @@
+---
+name: api_kaminari_count_with_limit
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/23931
+rollout_issue_url:
+group: group::ecosystem
+type: ops
+default_enabled: false
diff --git a/config/feature_flags/ops/ci_accept_trace.yml b/config/feature_flags/ops/ci_accept_trace.yml
index e32a3819844..8671f42c3c1 100644
--- a/config/feature_flags/ops/ci_accept_trace.yml
+++ b/config/feature_flags/ops/ci_accept_trace.yml
@@ -1,7 +1,7 @@
---
name: ci_accept_trace
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/41304
-rollout_issue_url:
+rollout_issue_url:
group: group::continuous integration
type: ops
-default_enabled: false \ No newline at end of file
+default_enabled: true
diff --git a/config/feature_flags/ops/ci_trace_log_invalid_chunks.yml b/config/feature_flags/ops/ci_trace_log_invalid_chunks.yml
new file mode 100644
index 00000000000..f5e8bbae258
--- /dev/null
+++ b/config/feature_flags/ops/ci_trace_log_invalid_chunks.yml
@@ -0,0 +1,7 @@
+---
+name: ci_trace_log_invalid_chunks
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/44409
+rollout_issue_url:
+type: ops
+group: group::continuous integration
+default_enabled: false
diff --git a/config/feature_flags/ops/database_reindexing.yml b/config/feature_flags/ops/database_reindexing.yml
new file mode 100644
index 00000000000..ea000a052db
--- /dev/null
+++ b/config/feature_flags/ops/database_reindexing.yml
@@ -0,0 +1,7 @@
+---
+name: database_reindexing
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/42705
+rollout_issue_url:
+group: group::database
+type: ops
+default_enabled: false \ No newline at end of file
diff --git a/config/feature_flags/ops/gitlab_sidekiq_enable_semi_reliable_fetcher.yml b/config/feature_flags/ops/gitlab_sidekiq_enable_semi_reliable_fetcher.yml
new file mode 100644
index 00000000000..680f8201d27
--- /dev/null
+++ b/config/feature_flags/ops/gitlab_sidekiq_enable_semi_reliable_fetcher.yml
@@ -0,0 +1,7 @@
+---
+name: gitlab_sidekiq_enable_semi_reliable_fetcher
+introduced_by_url:
+rollout_issue_url:
+group:
+type: ops
+default_enabled: true
diff --git a/config/feature_flags/ops/gitlab_sidekiq_reliable_fetcher.yml b/config/feature_flags/ops/gitlab_sidekiq_reliable_fetcher.yml
new file mode 100644
index 00000000000..ae395e19384
--- /dev/null
+++ b/config/feature_flags/ops/gitlab_sidekiq_reliable_fetcher.yml
@@ -0,0 +1,7 @@
+---
+name: gitlab_sidekiq_reliable_fetcher
+introduced_by_url:
+rollout_issue_url:
+group:
+type: ops
+default_enabled: true
diff --git a/config/feature_flags/ops/marginalia.yml b/config/feature_flags/ops/marginalia.yml
new file mode 100644
index 00000000000..a5d64c48b27
--- /dev/null
+++ b/config/feature_flags/ops/marginalia.yml
@@ -0,0 +1,7 @@
+---
+name: marginalia
+introduced_by_url:
+rollout_issue_url:
+group:
+type: ops
+default_enabled: false
diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example
index 605729a1435..de389514cce 100644
--- a/config/gitlab.yml.example
+++ b/config/gitlab.yml.example
@@ -394,6 +394,14 @@ production: &base
# File that contains the shared secret key for verifying access for gitlab-pages.
# Default is '.gitlab_pages_secret' relative to Rails.root (i.e. root of the GitLab app).
# secret_file: /home/git/gitlab/.gitlab_pages_secret
+ object_store:
+ enabled: false
+ remote_directory: pages # The bucket name
+ connection:
+ provider: AWS
+ aws_access_key_id: AWS_ACCESS_KEY_ID
+ aws_secret_access_key: AWS_SECRET_ACCESS_KEY
+ region: us-east-1
## Mattermost
## For enabling Add to Mattermost button
@@ -427,6 +435,9 @@ production: &base
# Remove expired build artifacts
expire_build_artifacts_worker:
cron: "50 * * * *"
+ # Remove files from object storage
+ ci_schedule_delete_objects_worker:
+ cron: "*/16 * * * *"
# Stop expired environments
environments_auto_stop_cron_worker:
cron: "24 * * * *"
@@ -846,6 +857,12 @@ production: &base
# (default: accept any service name in keytab file)
# service_principal_name: HTTP/gitlab.example.com@EXAMPLE.COM
+ # Kerberos realms/domains that are allowed to automatically link LDAP identities.
+ # By default, GitLab accepts a realm that matches the domain derived from the
+ # LDAP `base` DN. For example, `ou=users,dc=example,dc=com` would allow users
+ # with a realm matching `example.com`.
+ # simple_ldap_linking_allowed_realms: ['example.com','kerberos.example.com']
+
# Dedicated port: Git before 2.4 does not fall back to Basic authentication if Negotiate fails.
# To support both Basic and Negotiate methods with older versions of Git, configure
# nginx to proxy GitLab on an extra port (e.g. 8443) and uncomment the following lines
@@ -1005,6 +1022,21 @@ production: &base
# cas3:
# session_duration: 28800
+ # FortiAuthenticator settings
+ forti_authenticator:
+ # Allow using FortiAuthenticator as OTP provider
+ enabled: false
+
+ # Host and port of FortiAuthenticator instance
+ # host: forti_authenticator.example.com
+ # port: 443
+
+ # Username for accessing FortiAuthenticator API
+ # username: john
+
+ # Access token for FortiAuthenticator API
+ # access_token: 123s3cr3t456
+
# Shared file storage settings
shared:
# path: /mnt/gitlab # Default: shared
@@ -1318,6 +1350,14 @@ test:
# user: YOUR_USERNAME
pages:
path: tmp/tests/pages
+ object_store:
+ enabled: false
+ remote_directory: pages # The bucket name
+ connection:
+ provider: AWS
+ aws_access_key_id: AWS_ACCESS_KEY_ID
+ aws_secret_access_key: AWS_SECRET_ACCESS_KEY
+ region: us-east-1
repositories:
storages:
default:
diff --git a/config/initializers/0_license.rb b/config/initializers/0_license.rb
index e7b46a14630..ce3103be2e4 100644
--- a/config/initializers/0_license.rb
+++ b/config/initializers/0_license.rb
@@ -1,7 +1,8 @@
# frozen_string_literal: true
Gitlab.ee do
- public_key_file = File.read(Rails.root.join(".license_encryption_key.pub"))
+ prefix = ENV['GITLAB_LICENSE_MODE'] == 'test' ? 'test_' : ''
+ public_key_file = File.read(Rails.root.join(".#{prefix}license_encryption_key.pub"))
public_key = OpenSSL::PKey::RSA.new(public_key_file)
Gitlab::License.encryption_key = public_key
rescue
diff --git a/config/initializers/0_marginalia.rb b/config/initializers/0_marginalia.rb
index a697f67dbf2..5c6cf7752c4 100644
--- a/config/initializers/0_marginalia.rb
+++ b/config/initializers/0_marginalia.rb
@@ -21,4 +21,4 @@ Gitlab::Marginalia.set_application_name
Gitlab::Marginalia.enable_sidekiq_instrumentation
-Gitlab::Marginalia.set_feature_cache
+Gitlab::Marginalia.set_enabled_from_feature_flag
diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb
index 15c9fd427ff..affbc85d5a9 100644
--- a/config/initializers/1_settings.rb
+++ b/config/initializers/1_settings.rb
@@ -297,6 +297,10 @@ Settings.pages['external_http'] ||= false unless Settings.pages['external_http']
Settings.pages['external_https'] ||= false unless Settings.pages['external_https'].present?
Settings.pages['artifacts_server'] ||= Settings.pages['enabled'] if Settings.pages['artifacts_server'].nil?
Settings.pages['secret_file'] ||= Rails.root.join('.gitlab_pages_secret')
+# We want pages zip archives to be stored on the same directory as old pages hierarchical structure
+# this will allow us to easier migrate existing instances with NFS
+Settings.pages['storage_path'] = Settings.pages['path']
+Settings.pages['object_store'] = ObjectStoreSettings.legacy_parse(Settings.pages['object_store'])
#
# Geo
@@ -412,6 +416,9 @@ Settings.cron_jobs['pipeline_schedule_worker']['job_class'] = 'PipelineScheduleW
Settings.cron_jobs['expire_build_artifacts_worker'] ||= Settingslogic.new({})
Settings.cron_jobs['expire_build_artifacts_worker']['cron'] ||= '50 * * * *'
Settings.cron_jobs['expire_build_artifacts_worker']['job_class'] = 'ExpireBuildArtifactsWorker'
+Settings.cron_jobs['ci_schedule_delete_objects_worker'] ||= Settingslogic.new({})
+Settings.cron_jobs['ci_schedule_delete_objects_worker']['cron'] ||= '*/16 * * * *'
+Settings.cron_jobs['ci_schedule_delete_objects_worker']['job_class'] = 'Ci::ScheduleDeleteObjectsCronWorker'
Settings.cron_jobs['environments_auto_stop_cron_worker'] ||= Settingslogic.new({})
Settings.cron_jobs['environments_auto_stop_cron_worker']['cron'] ||= '24 * * * *'
Settings.cron_jobs['environments_auto_stop_cron_worker']['job_class'] = 'Environments::AutoStopCronWorker'
@@ -520,8 +527,14 @@ Settings.cron_jobs['ci_platform_metrics_update_cron_worker']['job_class'] = 'CiP
Settings.cron_jobs['analytics_instance_statistics_count_job_trigger_worker'] ||= Settingslogic.new({})
Settings.cron_jobs['analytics_instance_statistics_count_job_trigger_worker']['cron'] ||= '50 23 */1 * *'
Settings.cron_jobs['analytics_instance_statistics_count_job_trigger_worker']['job_class'] ||= 'Analytics::InstanceStatistics::CountJobTriggerWorker'
+Settings.cron_jobs['member_invitation_reminder_emails_worker'] ||= Settingslogic.new({})
+Settings.cron_jobs['member_invitation_reminder_emails_worker']['cron'] ||= '0 0 * * *'
+Settings.cron_jobs['member_invitation_reminder_emails_worker']['job_class'] = 'MemberInvitationReminderEmailsWorker'
Gitlab.ee do
+ Settings.cron_jobs['active_user_count_threshold_worker'] ||= Settingslogic.new({})
+ Settings.cron_jobs['active_user_count_threshold_worker']['cron'] ||= '0 12 * * *'
+ Settings.cron_jobs['active_user_count_threshold_worker']['job_class'] = 'ActiveUserCountThresholdWorker'
Settings.cron_jobs['adjourned_group_deletion_worker'] ||= Settingslogic.new({})
Settings.cron_jobs['adjourned_group_deletion_worker']['cron'] ||= '0 3 * * *'
Settings.cron_jobs['adjourned_group_deletion_worker']['job_class'] = 'AdjournedGroupDeletionWorker'
@@ -561,6 +574,9 @@ Gitlab.ee do
Settings.cron_jobs['historical_data_worker'] ||= Settingslogic.new({})
Settings.cron_jobs['historical_data_worker']['cron'] ||= '0 12 * * *'
Settings.cron_jobs['historical_data_worker']['job_class'] = 'HistoricalDataWorker'
+ Settings.cron_jobs['incident_sla_exceeded_check_worker'] ||= Settingslogic.new({})
+ Settings.cron_jobs['incident_sla_exceeded_check_worker']['cron'] ||= '*/2 * * * *'
+ Settings.cron_jobs['incident_sla_exceeded_check_worker']['job_class'] = 'IncidentManagement::IncidentSlaExceededCheckWorker'
Settings.cron_jobs['import_software_licenses_worker'] ||= Settingslogic.new({})
Settings.cron_jobs['import_software_licenses_worker']['cron'] ||= '0 3 * * 0'
Settings.cron_jobs['import_software_licenses_worker']['job_class'] = 'ImportSoftwareLicensesWorker'
@@ -727,6 +743,7 @@ Gitlab.ee do
Settings['kerberos'] ||= Settingslogic.new({})
Settings.kerberos['enabled'] = false if Settings.kerberos['enabled'].nil?
Settings.kerberos['keytab'] = nil if Settings.kerberos['keytab'].blank? # nil means use default keytab
+ Settings.kerberos['simple_ldap_linking_allowed_realms'] = [] if Settings.kerberos['simple_ldap_linking_allowed_realms'].blank?
Settings.kerberos['service_principal_name'] = nil if Settings.kerberos['service_principal_name'].blank? # nil means any SPN in keytab
Settings.kerberos['use_dedicated_port'] = false if Settings.kerberos['use_dedicated_port'].nil?
Settings.kerberos['https'] = Settings.gitlab.https if Settings.kerberos['https'].nil?
@@ -750,6 +767,13 @@ Gitlab.ee do
end
#
+# FortiAuthenticator
+#
+Settings['forti_authenticator'] ||= Settingslogic.new({})
+Settings.forti_authenticator['enabled'] = false if Settings.forti_authenticator['enabled'].nil?
+Settings.forti_authenticator['port'] = 443 if Settings.forti_authenticator['port'].to_i == 0
+
+#
# Extra customization
#
Settings['extra'] ||= Settingslogic.new({})
@@ -774,10 +798,15 @@ Settings['gitaly'] ||= Settingslogic.new({})
# Webpack settings
#
Settings['webpack'] ||= Settingslogic.new({})
+Settings.webpack['config_file'] ||= 'config/webpack.config.js'
+Settings.webpack['output_dir'] ||= 'public/assets/webpack'
+Settings.webpack['public_path'] ||= 'assets/webpack'
+Settings.webpack['manifest_filename'] ||= 'manifest.json'
Settings.webpack['dev_server'] ||= Settingslogic.new({})
Settings.webpack.dev_server['enabled'] ||= false
Settings.webpack.dev_server['host'] ||= 'localhost'
Settings.webpack.dev_server['port'] ||= 3808
+Settings.webpack.dev_server['https'] ||= false
#
# Monitoring settings
diff --git a/config/initializers/7_prometheus_metrics.rb b/config/initializers/7_prometheus_metrics.rb
index d5d8587f1c8..dbaebc83658 100644
--- a/config/initializers/7_prometheus_metrics.rb
+++ b/config/initializers/7_prometheus_metrics.rb
@@ -69,7 +69,9 @@ if !Rails.env.test? && Gitlab::Metrics.prometheus_metrics_enabled?
Gitlab::Metrics.gauge(:deployments, 'GitLab Version', {}, :max).set({ version: Gitlab::VERSION }, 1)
- Gitlab::Metrics::RequestsRackMiddleware.initialize_http_request_duration_seconds
+ unless Gitlab::Runtime.sidekiq?
+ Gitlab::Metrics::RequestsRackMiddleware.initialize_http_request_duration_seconds
+ end
rescue IOError => e
Gitlab::ErrorTracking.track_exception(e)
Gitlab::Metrics.error_detected!
diff --git a/config/initializers/database_config.rb b/config/initializers/database_config.rb
index cccd4335a7d..a91f67224d7 100644
--- a/config/initializers/database_config.rb
+++ b/config/initializers/database_config.rb
@@ -20,21 +20,12 @@ Gitlab.ee do
end
end
-# Because of the way Ruby on Rails manages database connections, it is
-# important that we have at least as many connections as we have
-# threads. While there is a 'pool' setting in database.yml, it is not
-# very practical because you need to maintain it in tandem with the
-# number of application threads. Because of this we override the number
-# of allowed connections in the database connection pool based on the
-# configured number of application threads.
+# We configure the database connection pool size automatically based on the
+# configured concurrency. We also add some headroom, to make sure we don't run
+# out of connections when more threads besides the 'user-facing' ones are
+# running.
#
-# Gitlab::Runtime.max_threads is the number of "user facing" application
-# threads the process has been configured with. We also have auxiliary
-# threads that use database connections. Because it is not practical to
-# keep an accurate count of the number auxiliary threads as the
-# application evolves over time, we just add a fixed headroom to the
-# number of user-facing threads. It is OK if this number is too large
-# because connections are instantiated lazily.
+# Read more about this in doc/development/database/client_side_connection_pool.md
headroom = (ENV["DB_POOL_HEADROOM"].presence || 10).to_i
calculated_pool_size = Gitlab::Runtime.max_threads + headroom
diff --git a/config/initializers/forbid_sidekiq_in_transactions.rb b/config/initializers/forbid_sidekiq_in_transactions.rb
index 6bcd4dbd52f..f505fb5843a 100644
--- a/config/initializers/forbid_sidekiq_in_transactions.rb
+++ b/config/initializers/forbid_sidekiq_in_transactions.rb
@@ -46,7 +46,7 @@ end
module ActiveRecord
class Base
module SkipTransactionCheckAfterCommit
- def committed!(*)
+ def committed!(*args, **kwargs)
Sidekiq::Worker.skipping_transaction_check { super }
end
end
diff --git a/config/initializers/lograge.rb b/config/initializers/lograge.rb
index e3601a9538e..0ea0adf86bc 100644
--- a/config/initializers/lograge.rb
+++ b/config/initializers/lograge.rb
@@ -1,30 +1,40 @@
# Only use Lograge for Rails
unless Gitlab::Runtime.sidekiq?
- filename = File.join(Rails.root, 'log', "#{Rails.env}_json.log")
+ Rails.application.reloader.to_prepare do
+ filename = File.join(Rails.root, 'log', "#{Rails.env}_json.log")
+ db_counter = Gitlab::Metrics::Subscribers::ActiveRecord
- Rails.application.configure do
- config.lograge.enabled = true
- # Store the lograge JSON files in a separate file
- config.lograge.keep_original_rails_log = Gitlab::Utils.to_boolean(ENV.fetch('UNSTRUCTURED_RAILS_LOG', 'true'))
- # Don't use the Logstash formatter since this requires logstash-event, an
- # unmaintained gem that monkey patches `Time`
- config.lograge.formatter = Lograge::Formatters::Json.new
- config.lograge.logger = ActiveSupport::Logger.new(filename)
- config.lograge.before_format = lambda do |data, payload|
- data.delete(:error)
- data[:db_duration_s] = Gitlab::Utils.ms_to_round_sec(data.delete(:db)) if data[:db]
- data[:view_duration_s] = Gitlab::Utils.ms_to_round_sec(data.delete(:view)) if data[:view]
- data[:duration_s] = Gitlab::Utils.ms_to_round_sec(data.delete(:duration)) if data[:duration]
- data.merge!(::Gitlab::Metrics::Subscribers::ActiveRecord.db_counter_payload)
+ Rails.application.configure do
+ config.lograge.enabled = true
+ # Store the lograge JSON files in a separate file
+ config.lograge.keep_original_rails_log = Gitlab::Utils.to_boolean(ENV.fetch('UNSTRUCTURED_RAILS_LOG', 'true'))
+ # Don't use the Logstash formatter since this requires logstash-event, an
+ # unmaintained gem that monkey patches `Time`
+ config.lograge.formatter = Lograge::Formatters::Json.new
+ config.lograge.logger = ActiveSupport::Logger.new(filename)
+ config.lograge.before_format = lambda do |data, payload|
+ data.delete(:error)
+ data[:db_duration_s] = Gitlab::Utils.ms_to_round_sec(data.delete(:db)) if data[:db]
+ data[:view_duration_s] = Gitlab::Utils.ms_to_round_sec(data.delete(:view)) if data[:view]
+ data[:duration_s] = Gitlab::Utils.ms_to_round_sec(data.delete(:duration)) if data[:duration]
+ data.merge!(db_counter.db_counter_payload)
- data
- end
+ # Remove empty hashes to prevent type mismatches
+ # These are set to empty hashes in Lograge's ActionCable subscriber
+ # https://github.com/roidrage/lograge/blob/v0.11.2/lib/lograge/log_subscribers/action_cable.rb#L14-L16
+ %i(method path format).each do |key|
+ data[key] = nil if data[key] == {}
+ end
+
+ data
+ end
- # This isn't a user-reachable controller; we use it to check for a
- # valid CSRF token in the API
- config.lograge.ignore_actions = ['Gitlab::RequestForgeryProtection::Controller#index']
+ # This isn't a user-reachable controller; we use it to check for a
+ # valid CSRF token in the API
+ config.lograge.ignore_actions = ['Gitlab::RequestForgeryProtection::Controller#index']
- # Add request parameters to log output
- config.lograge.custom_options = Gitlab::Lograge::CustomOptions
+ # Add request parameters to log output
+ config.lograge.custom_options = Gitlab::Lograge::CustomOptions
+ end
end
end
diff --git a/config/initializers/rails_host_authorization_gitpod.rb b/config/initializers/rails_host_authorization_gitpod.rb
new file mode 100644
index 00000000000..0c1822bc91a
--- /dev/null
+++ b/config/initializers/rails_host_authorization_gitpod.rb
@@ -0,0 +1,6 @@
+# frozen_string_literal: true
+
+if Rails.env.development? && ENV['GITPOD_WORKSPACE_ID'].present?
+ gitpod_host = URI(`gp url 3000`.strip).host
+ Rails.application.config.hosts += [gitpod_host]
+end
diff --git a/config/initializers/sidekiq.rb b/config/initializers/sidekiq.rb
index a33c28090e2..72e2b94fe07 100644
--- a/config/initializers/sidekiq.rb
+++ b/config/initializers/sidekiq.rb
@@ -3,13 +3,13 @@
def enable_reliable_fetch?
return true unless Feature::FlipperFeature.table_exists?
- Feature.enabled?(:gitlab_sidekiq_reliable_fetcher, default_enabled: true)
+ Feature.enabled?(:gitlab_sidekiq_reliable_fetcher, type: :ops, default_enabled: true)
end
def enable_semi_reliable_fetch_mode?
return true unless Feature::FlipperFeature.table_exists?
- Feature.enabled?(:gitlab_sidekiq_enable_semi_reliable_fetcher, default_enabled: true)
+ Feature.enabled?(:gitlab_sidekiq_enable_semi_reliable_fetcher, type: :ops, default_enabled: true)
end
# Custom Queues configuration
diff --git a/config/initializers/sprockets.rb b/config/initializers/sprockets.rb
new file mode 100644
index 00000000000..a20b7dc75e9
--- /dev/null
+++ b/config/initializers/sprockets.rb
@@ -0,0 +1 @@
+Sprockets.register_compressor 'application/javascript', :terser, Terser::Compressor
diff --git a/config/initializers/stackprof.rb b/config/initializers/stackprof.rb
index 797efdb9bbd..4c4d241f065 100644
--- a/config/initializers/stackprof.rb
+++ b/config/initializers/stackprof.rb
@@ -2,14 +2,18 @@
# trigger stackprof by sending a SIGUSR2 signal
#
-# default settings:
-# * collect raw samples
-# * sample at 100hz (every 10k microseconds)
-# * timeout profile after 30 seconds
-# * write to $TMPDIR/stackprof.$PID.$RAND.profile
+# Docs: https://docs.gitlab.com/ee/development/performance.html#production
module Gitlab
class StackProf
+ DEFAULT_FILE_PREFIX = Dir.tmpdir
+ DEFAULT_TIMEOUT_SEC = 30
+ DEFAULT_MODE = :cpu
+ # Sample interval as a frequency in microseconds (~100hz); appropriate for CPU profiles
+ DEFAULT_INTERVAL_US = 10_000
+ # Sample interval in event occurrences (n = every nth event); appropriate for allocation profiles
+ DEFAULT_INTERVAL_EVENTS = 1_000
+
# this is a workaround for sidekiq, which defines its own SIGUSR2 handler.
# by defering to the sidekiq startup event, we get to set up our own
# handler late enough.
@@ -32,11 +36,7 @@ module Gitlab
end
def self.on_worker_start
- Gitlab::AppJsonLogger.info(
- event: "stackprof",
- message: "listening on SIGUSR2 signal",
- pid: Process.pid
- )
+ log_event('listening for SIGUSR2 signal')
# create a pipe in order to propagate signal out of the signal handler
# see also: https://cr.yp.to/docs/selfpipe.html
@@ -55,43 +55,46 @@ module Gitlab
# a given interval (by default 30 seconds), avoiding unbounded memory
# growth from a profile that was started and never stopped.
t = Thread.new do
- timeout_s = ENV['STACKPROF_TIMEOUT_S']&.to_i || 30
+ timeout_s = ENV['STACKPROF_TIMEOUT_S']&.to_i || DEFAULT_TIMEOUT_SEC
current_timeout_s = nil
loop do
- got_value = IO.select([read], nil, nil, current_timeout_s)
- read.getbyte if got_value
+ read.getbyte if IO.select([read], nil, nil, current_timeout_s)
if ::StackProf.running?
- stackprof_file_prefix = ENV['STACKPROF_FILE_PREFIX'] || Dir.tmpdir
+ stackprof_file_prefix = ENV['STACKPROF_FILE_PREFIX'] || DEFAULT_FILE_PREFIX
stackprof_out_file = "#{stackprof_file_prefix}/stackprof.#{Process.pid}.#{SecureRandom.hex(6)}.profile"
- Gitlab::AppJsonLogger.info(
- event: "stackprof",
- message: "stopping profile",
- output_filename: stackprof_out_file,
- pid: Process.pid,
- timeout_s: timeout_s,
- timed_out: got_value.nil?
+ log_event(
+ 'stopping profile',
+ profile_filename: stackprof_out_file,
+ profile_timeout_s: timeout_s
)
::StackProf.stop
::StackProf.results(stackprof_out_file)
current_timeout_s = nil
else
- Gitlab::AppJsonLogger.info(
- event: "stackprof",
- message: "starting profile",
- pid: Process.pid
+ mode = ENV['STACKPROF_MODE']&.to_sym || DEFAULT_MODE
+ interval = ENV['STACKPROF_INTERVAL']&.to_i
+ interval ||= (mode == :object ? DEFAULT_INTERVAL_EVENTS : DEFAULT_INTERVAL_US)
+
+ log_event(
+ 'starting profile',
+ profile_mode: mode,
+ profile_interval: interval,
+ profile_timeout: timeout_s
)
::StackProf.start(
- mode: :cpu,
+ mode: mode,
raw: Gitlab::Utils.to_boolean(ENV['STACKPROF_RAW'] || 'true'),
- interval: ENV['STACKPROF_INTERVAL_US']&.to_i || 10_000
+ interval: interval
)
current_timeout_s = timeout_s
end
end
+ rescue => e
+ log_event("stackprof failed: #{e}")
end
t.abort_on_exception = true
@@ -121,6 +124,14 @@ module Gitlab
write.write('.')
end
end
+
+ def self.log_event(event, labels = {})
+ Gitlab::AppJsonLogger.info({
+ event: 'stackprof',
+ message: event,
+ pid: Process.pid
+ }.merge(labels.compact))
+ end
end
end
diff --git a/config/initializers/static_files.rb b/config/initializers/static_files.rb
index e02f0868e9f..4e19fec084a 100644
--- a/config/initializers/static_files.rb
+++ b/config/initializers/static_files.rb
@@ -15,32 +15,14 @@ if app.config.public_file_server.enabled
# If webpack-dev-server is configured, proxy webpack's public directory
# instead of looking for static assets
- dev_server = Gitlab.config.webpack.dev_server
-
- if dev_server.enabled
- settings = {
- enabled: true,
- host: dev_server.host,
- port: dev_server.port,
- manifest_host: dev_server.host,
- manifest_port: dev_server.port
- }
-
- if Rails.env.development?
- settings.merge!(
- host: Gitlab.config.gitlab.host,
- port: Gitlab.config.gitlab.port,
- https: false
- )
- app.config.middleware.insert_before(
- Gitlab::Middleware::Static,
- Gitlab::Webpack::DevServerMiddleware,
- proxy_path: app.config.webpack.public_path,
- proxy_host: dev_server.host,
- proxy_port: dev_server.port
- )
- end
-
- app.config.webpack.dev_server.merge!(settings)
+ if Gitlab.config.webpack.dev_server.enabled && Rails.env.development?
+ app.config.middleware.insert_before(
+ Gitlab::Middleware::Static,
+ Gitlab::Webpack::DevServerMiddleware,
+ proxy_path: Gitlab.config.webpack.public_path,
+ proxy_host: Gitlab.config.webpack.dev_server.host,
+ proxy_port: Gitlab.config.webpack.dev_server.port,
+ proxy_https: Gitlab.config.webpack.dev_server.https
+ )
end
end
diff --git a/config/initializers/webauthn.rb b/config/initializers/webauthn.rb
index 8dc5dfd56ed..1f37e7c84c3 100644
--- a/config/initializers/webauthn.rb
+++ b/config/initializers/webauthn.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
WebAuthn.configure do |config|
# This value needs to match `window.location.origin` evaluated by
# the User Agent during registration and authentication ceremonies.
diff --git a/config/initializers_before_autoloader/000_inflections.rb b/config/initializers_before_autoloader/000_inflections.rb
index a34b75d0382..85c53ab4320 100644
--- a/config/initializers_before_autoloader/000_inflections.rb
+++ b/config/initializers_before_autoloader/000_inflections.rb
@@ -24,11 +24,11 @@ ActiveSupport::Inflector.inflections do |inflect|
project_auto_devops
project_registry
project_statistics
+ snippet_repository_registry
system_note_metadata
- terraform_state_registry
+ terraform_state_version_registry
vulnerabilities_feedback
vulnerability_feedback
- snippet_repository_registry
)
inflect.acronym 'EE'
inflect.acronym 'CSP'
diff --git a/config/locales/devise.en.yml b/config/locales/devise.en.yml
index e4a46be9bf3..6c6a5f7b1a1 100644
--- a/config/locales/devise.en.yml
+++ b/config/locales/devise.en.yml
@@ -16,6 +16,9 @@ en:
timeout: "Your session expired. Please sign in again to continue."
unauthenticated: "You need to sign in or sign up before continuing."
unconfirmed: "You have to confirm your email address before continuing. Please check your email for the link we sent you, or click 'Resend confirmation email'."
+ blocked: "Your account has been blocked. Please contact your GitLab administrator if you think this is an error."
+ forbidden: "Your account does not have the required permission to login. Please contact your GitLab administrator if you think this is an error."
+ blocked_pending_approval: "Your account is pending approval from your GitLab administrator and hence blocked. Please contact your GitLab administrator if you think this is an error."
mailer:
confirmation_instructions:
subject: "Confirmation instructions"
@@ -42,6 +45,7 @@ en:
signed_up_but_inactive: "You have signed up successfully. However, we could not sign you in because your account is not yet activated."
signed_up_but_locked: "You have signed up successfully. However, we could not sign you in because your account is locked."
signed_up_but_unconfirmed: "A message with a confirmation link has been sent to your email address. Please follow the link to activate your account."
+ signed_up_but_blocked_pending_approval: "You have signed up successfully. However, we could not sign you in because your account is awaiting approval from your GitLab administrator."
update_needs_confirmation: "You updated your account successfully, but we need to verify your new email address. Please check your email and follow the confirm link to confirm your new email address."
updated: "Your account has been updated successfully."
sessions:
diff --git a/config/locales/en.yml b/config/locales/en.yml
index 7ff4e3bf7da..fb024b7ba2a 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -20,6 +20,8 @@ en:
token: "Grafana HTTP API Token"
grafana_url: "Grafana API URL"
grafana_enabled: "Grafana integration enabled"
+ service_desk_setting:
+ project_key: "Project name suffix"
user/user_detail:
job_title: 'Job title'
user/user_detail:
diff --git a/config/object_store_settings.rb b/config/object_store_settings.rb
index 0d346135463..767fcd7579c 100644
--- a/config/object_store_settings.rb
+++ b/config/object_store_settings.rb
@@ -1,8 +1,12 @@
# Set default values for object_store settings
class ObjectStoreSettings
- SUPPORTED_TYPES = %w(artifacts external_diffs lfs uploads packages dependency_proxy terraform_state).freeze
+ SUPPORTED_TYPES = %w(artifacts external_diffs lfs uploads packages dependency_proxy terraform_state pages).freeze
ALLOWED_OBJECT_STORE_OVERRIDES = %w(bucket enabled proxy_download).freeze
+ # pages may be enabled but use legacy disk storage
+ # we don't need to raise an error in that case
+ ALLOWED_INCOMPLETE_TYPES = %w(pages).freeze
+
attr_accessor :settings
# Legacy parser
@@ -115,7 +119,9 @@ class ObjectStoreSettings
next unless section
- raise "Object storage for #{store_type} must have a bucket specified" if section['enabled'] && target_config['bucket'].blank?
+ if section['enabled'] && target_config['bucket'].blank?
+ missing_bucket_for(store_type)
+ end
# Map bucket (external name) -> remote_directory (internal representation)
target_config['remote_directory'] = target_config.delete('bucket')
@@ -152,4 +158,14 @@ class ObjectStoreSettings
true
end
+
+ def missing_bucket_for(store_type)
+ message = "Object storage for #{store_type} must have a bucket specified"
+
+ if ALLOWED_INCOMPLETE_TYPES.include?(store_type)
+ warn "[WARNING] #{message}"
+ else
+ raise message
+ end
+ end
end
diff --git a/config/redis.cache.yml.example b/config/redis.cache.yml.example
index b20f1dd2122..fb92c205ce1 100644
--- a/config/redis.cache.yml.example
+++ b/config/redis.cache.yml.example
@@ -26,7 +26,7 @@ production:
# http://redis.io/topics/sentinel
#
# You must specify a list of a few sentinels that will handle client connection
- # please read here for more information: https://docs.gitlab.com/ce/administration/high_availability/redis.html
+ # please read here for more information: https://docs.gitlab.com/ee/administration/redis/index.html
##
# url: redis://master:6380
# sentinels:
diff --git a/config/redis.queues.yml.example b/config/redis.queues.yml.example
index 46ab39729c4..dd6c10e0e06 100644
--- a/config/redis.queues.yml.example
+++ b/config/redis.queues.yml.example
@@ -26,7 +26,7 @@ production:
# http://redis.io/topics/sentinel
#
# You must specify a list of a few sentinels that will handle client connection
- # please read here for more information: https://docs.gitlab.com/ce/administration/high_availability/redis.html
+ # please read here for more information: https://docs.gitlab.com/ee/administration/redis/index.html
##
# url: redis://master:6381
# sentinels:
diff --git a/config/redis.shared_state.yml.example b/config/redis.shared_state.yml.example
index 05fed947f52..98f6f330bc7 100644
--- a/config/redis.shared_state.yml.example
+++ b/config/redis.shared_state.yml.example
@@ -26,7 +26,7 @@ production:
# http://redis.io/topics/sentinel
#
# You must specify a list of a few sentinels that will handle client connection
- # please read here for more information: https://docs.gitlab.com/ce/administration/high_availability/redis.html
+ # please read here for more information: https://docs.gitlab.com/ee/administration/redis/index.html
##
# url: redis://master:6382
# sentinels:
diff --git a/config/resque.yml.example b/config/resque.yml.example
index 932c1553dfb..0f629a5229c 100644
--- a/config/resque.yml.example
+++ b/config/resque.yml.example
@@ -22,7 +22,7 @@ production:
# http://redis.io/topics/sentinel
#
# You must specify a list of a few sentinels that will handle client connection
- # please read here for more information: https://docs.gitlab.com/ce/administration/high_availability/redis.html
+ # please read here for more information: https://docs.gitlab.com/ee/administration/redis/index.html
##
# url: redis://master:6379
# sentinels:
diff --git a/config/routes.rb b/config/routes.rb
index 9bd68bfeef6..87d32e3d89a 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -69,10 +69,6 @@ Rails.application.routes.draw do
# Begin of the /-/ scope.
# Use this scope for all new global routes.
scope path: '-' do
- # remove in 13.5
- get '/instance_statistics', to: redirect('admin/dev_ops_report')
- get '/instance_statistics/dev_ops_score', to: redirect('admin/dev_ops_report')
- get '/instance_statistics/cohorts', to: redirect('admin/cohorts')
# Autocomplete
get '/autocomplete/users' => 'autocomplete#users'
get '/autocomplete/users/:id' => 'autocomplete#user'
@@ -87,12 +83,16 @@ Rails.application.routes.draw do
get '/autocomplete/namespace_routes' => 'autocomplete#namespace_routes'
end
+ get '/whats_new' => 'whats_new#index'
+
# '/-/health' implemented by BasicHealthCheck middleware
get 'liveness' => 'health#liveness'
get 'readiness' => 'health#readiness'
resources :metrics, only: [:index]
mount Peek::Railtie => '/peek', as: 'peek_routes'
+ get 'runner_setup/platforms' => 'runner_setup#platforms'
+
# Boards resources shared between group and projects
resources :boards, only: [] do
resources :lists, module: :boards, only: [:index, :create, :update, :destroy] do
@@ -122,6 +122,7 @@ Rails.application.routes.draw do
get 'ide' => 'ide#index'
get 'ide/*vueroute' => 'ide#index', format: false
+ get 'ide/project/:namespace/:project/merge_requests/:id' => 'ide#index', format: false, as: :ide_merge_request
draw :operations
draw :jira_connect
@@ -275,6 +276,14 @@ Rails.application.routes.draw do
draw :snippets
end
+ # Serve profile routes under /-/ scope.
+ # To ensure an old unscoped routing is used for the UI we need to
+ # add prefix 'as' to the scope routing and place it below original routing.
+ # Issue https://gitlab.com/gitlab-org/gitlab/-/issues/210024
+ scope '-', as: :scoped do
+ draw :profile
+ end
+
root to: "root#index"
get '*unmatched_route', to: 'application#route_not_found'
diff --git a/config/routes/admin.rb b/config/routes/admin.rb
index bac8247de2e..84b9829dacf 100644
--- a/config/routes/admin.rb
+++ b/config/routes/admin.rb
@@ -17,6 +17,7 @@ namespace :admin do
put :activate
put :unlock
put :confirm
+ put :approve
post :impersonate
patch :disable_two_factor
delete 'remove/:email_id', action: 'remove_email', as: 'remove_email'
@@ -81,6 +82,8 @@ namespace :admin do
post :preview, on: :collection
end
+ get :instance_review, to: 'instance_review#index'
+
resource :health_check, controller: 'health_check', only: [:show]
resource :background_jobs, controller: 'background_jobs', only: [:show]
@@ -91,8 +94,6 @@ namespace :admin do
resources :instance_statistics, only: :index
resource :dev_ops_report, controller: 'dev_ops_report', only: :show
- # remove in 13.5
- get '/dev_ops_score', to: redirect('admin/dev_ops_report')
resources :cohorts, only: :index
scope(path: 'projects/*namespace_id',
@@ -153,6 +154,7 @@ namespace :admin do
collection do
get :tag_list, format: :json
+ get :runner_setup_scripts, format: :json
end
end
diff --git a/config/routes/group.rb b/config/routes/group.rb
index e5bbfdf7548..33464cf3b55 100644
--- a/config/routes/group.rb
+++ b/config/routes/group.rb
@@ -17,6 +17,7 @@ constraints(::Constraints::GroupUrlConstrainer.new) do
put :transfer, as: :transfer_group # rubocop:disable Cop/PutGroupRoutesUnderScope
post :export, as: :export_group # rubocop:disable Cop/PutGroupRoutesUnderScope
get :download_export, as: :download_export_group # rubocop:disable Cop/PutGroupRoutesUnderScope
+ get :unfoldered_environment_names, as: :unfoldered_environment_names_group # rubocop:disable Cop/PutGroupRoutesUnderScope
# TODO: Remove as part of refactor in https://gitlab.com/gitlab-org/gitlab-foss/issues/49693
get 'shared', action: :show, as: :group_shared # rubocop:disable Cop/PutGroupRoutesUnderScope
@@ -35,6 +36,7 @@ constraints(::Constraints::GroupUrlConstrainer.new) do
put :reset_registration_token
patch :update_auto_devops
post :create_deploy_token, path: 'deploy_token/create', to: 'repository#create_deploy_token'
+ get :runner_setup_scripts, format: :json
end
resource :repository, only: [:show], controller: 'repository' do
@@ -61,6 +63,7 @@ constraints(::Constraints::GroupUrlConstrainer.new) do
resources :milestones, constraints: { id: %r{[^/]+} } do
member do
+ get :issues
get :merge_requests
get :participants
get :labels
@@ -85,7 +88,7 @@ constraints(::Constraints::GroupUrlConstrainer.new) do
delete :leave, on: :collection
end
- resources :group_links, only: [:create, :update, :destroy], constraints: { id: /\d+/ }
+ resources :group_links, only: [:create, :update, :destroy], constraints: { id: /\d+|:id/ }
resources :uploads, only: [:create] do
collection do
diff --git a/config/routes/import.rb b/config/routes/import.rb
index 0d3f202ba55..3ee44aa8659 100644
--- a/config/routes/import.rb
+++ b/config/routes/import.rb
@@ -69,6 +69,11 @@ namespace :import do
post :authorize
end
+ resource :bulk_import, only: [:create] do
+ post :configure
+ get :status
+ end
+
resource :manifest, only: [:create, :new], controller: :manifest do
get :status
get :realtime_changes
diff --git a/config/routes/jira_connect.rb b/config/routes/jira_connect.rb
index a3b786b60f0..72b3f04f5e5 100644
--- a/config/routes/jira_connect.rb
+++ b/config/routes/jira_connect.rb
@@ -5,6 +5,7 @@ namespace :jira_connect do
root to: proc { [404, {}, ['']] }, as: 'base'
get 'app_descriptor' => 'app_descriptor#show'
+ get :users, to: 'users#show'
namespace :events do
post 'installed'
diff --git a/config/routes/pipelines.rb b/config/routes/pipelines.rb
index 605e82af23a..0fc308b5e65 100644
--- a/config/routes/pipelines.rb
+++ b/config/routes/pipelines.rb
@@ -7,6 +7,7 @@ resources :pipelines, only: [:index, :new, :create, :show, :destroy] do
scope '(*ref)', constraints: { ref: Gitlab::PathRegex.git_reference_regex } do
get :latest, action: :show, defaults: { latest: true }
end
+ get :config_variables
end
member do
diff --git a/config/routes/project.rb b/config/routes/project.rb
index 24b44646d95..eae217de1ac 100644
--- a/config/routes/project.rb
+++ b/config/routes/project.rb
@@ -93,6 +93,7 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
post :reset_cache
put :reset_registration_token
post :create_deploy_token, path: 'deploy_token/create', to: 'repository#create_deploy_token'
+ get :runner_setup_scripts, format: :json
end
resource :operations, only: [:show, :update] do
@@ -161,8 +162,7 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
resources :milestones, constraints: { id: /\d+/ } do
member do
post :promote
- put :sort_issues
- put :sort_merge_requests
+ get :issues
get :merge_requests
get :participants
get :labels
@@ -307,10 +307,14 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
get 'details', on: :member
end
+ resource :tracing, only: [:show]
+
post 'incidents/integrations/pagerduty', to: 'incident_management/pager_duty_incidents#create'
resources :incidents, only: [:index]
+ get 'issues/incident/:id' => 'incidents#show', as: :issues_incident
+
namespace :error_tracking do
resources :projects, only: :index
end
@@ -364,16 +368,14 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
resource :jira, only: [:show], controller: :jira
end
- resources :snippets, concerns: :awardable, constraints: { id: /\d+/ } do
+ resources :snippets, except: [:create, :update, :destroy], concerns: :awardable, constraints: { id: /\d+/ } do
member do
get :raw
post :mark_as_spam
end
end
- resources :feature_flags, param: :iid do
- resources :feature_flag_issues, only: [:index, :create, :destroy], as: 'issues', path: 'issues'
- end
+ resources :feature_flags, param: :iid
resource :feature_flags_client, only: [] do
post :reset_token
end
@@ -551,6 +553,7 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
Gitlab::Routing.redirect_legacy_paths(self, :mirror, :tags,
:cycle_analytics, :mattermost, :variables, :triggers,
:environments, :protected_environments, :error_tracking, :alert_management,
+ :tracing,
:serverless, :clusters, :audit_events, :wikis, :merge_requests,
:vulnerability_feedback, :security, :dependencies, :issues)
end
@@ -575,6 +578,7 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
get :activity
get :refs
put :new_issuable_address
+ get :unfoldered_environment_names
end
end
# rubocop: enable Cop/PutProjectRoutesUnderScope
diff --git a/config/routes/snippets.rb b/config/routes/snippets.rb
index 7bb82da4910..9e0c42fa07d 100644
--- a/config/routes/snippets.rb
+++ b/config/routes/snippets.rb
@@ -1,4 +1,4 @@
-resources :snippets, concerns: :awardable do
+resources :snippets, except: [:create, :update, :destroy], concerns: :awardable, constraints: { id: /\d+/ } do
member do
get :raw
post :mark_as_spam
diff --git a/config/sidekiq_queues.yml b/config/sidekiq_queues.yml
index 823ec2eddb3..f061efeb427 100644
--- a/config/sidekiq_queues.yml
+++ b/config/sidekiq_queues.yml
@@ -50,6 +50,8 @@
- 2
- - ci_batch_reset_minutes
- 1
+- - ci_delete_objects
+ - 1
- - container_repository
- 1
- - create_commit_signature
@@ -62,6 +64,8 @@
- 1
- - cronjob
- 1
+- - dast_site_validation
+ - 1
- - default
- 1
- - delete_diff_files
@@ -76,10 +80,16 @@
- 1
- - deployment
- 3
+- - design_management_copy_design_collection
+ - 1
- - design_management_new_version
- 1
- - detect_repository_languages
- 1
+- - disallow_two_factor_for_group
+ - 1
+- - disallow_two_factor_for_subgroups
+ - 1
- - elastic_commit_indexer
- 1
- - elastic_delete_project
@@ -136,10 +146,14 @@
- 2
- - incident_management
- 2
+- - incident_management_apply_incident_sla_exceeded_label
+ - 1
- - invalid_gpg_signature_update
- 2
- - irker
- 1
+- - issuable_export_csv
+ - 1
- - issue_placement
- 2
- - issue_rebalancing
@@ -164,6 +178,8 @@
- 1
- - metrics_dashboard_prune_old_annotations
- 1
+- - metrics_dashboard_sync_dashboards
+ - 1
- - migrate_external_diffs
- 1
- - namespaceless_project_destroy
@@ -232,6 +248,12 @@
- 1
- - propagate_integration
- 1
+- - propagate_integration_group
+ - 1
+- - propagate_integration_inherit
+ - 1
+- - propagate_integration_project
+ - 1
- - propagate_service_template
- 1
- - reactive_caching
@@ -298,5 +320,7 @@
- 1
- - web_hook
- 1
+- - web_hooks_destroy
+ - 1
- - x509_certificate_revoke
- 1
diff --git a/config/webpack.config.js b/config/webpack.config.js
index 652ada1d832..821ddc84e1a 100644
--- a/config/webpack.config.js
+++ b/config/webpack.config.js
@@ -18,6 +18,7 @@ const IS_DEV_SERVER = process.env.WEBPACK_DEV_SERVER === 'true';
const IS_EE = require('./helpers/is_ee_env');
const DEV_SERVER_HOST = process.env.DEV_SERVER_HOST || 'localhost';
const DEV_SERVER_PORT = parseInt(process.env.DEV_SERVER_PORT, 10) || 3808;
+const DEV_SERVER_HTTPS = process.env.DEV_SERVER_HTTPS && process.env.DEV_SERVER_HTTPS !== 'false';
const DEV_SERVER_LIVERELOAD = IS_DEV_SERVER && process.env.DEV_SERVER_LIVERELOAD !== 'false';
const WEBPACK_REPORT = process.env.WEBPACK_REPORT && process.env.WEBPACK_REPORT !== 'false';
const WEBPACK_MEMORY_TEST =
@@ -78,7 +79,7 @@ function generateEntries() {
const manualEntries = {
default: defaultEntries,
- sentry: './sentry/index.js',
+ // sentry: './sentry/index.js', Temporarily commented out to investigate performance: https://gitlab.com/gitlab-org/gitlab/-/issues/251179
performance_bar: './performance_bar/index.js',
chrome_84_icon_fix: './lib/chrome_84_icon_fix.js',
};
@@ -96,6 +97,7 @@ const alias = {
vue$: 'vue/dist/vue.esm.js',
spec: path.join(ROOT_PATH, 'spec/javascripts'),
jest: path.join(ROOT_PATH, 'spec/frontend'),
+ shared_queries: path.join(ROOT_PATH, 'app/graphql/queries'),
// the following resolves files which are different between CE and EE
ee_else_ce: path.join(ROOT_PATH, 'app/assets/javascripts'),
@@ -278,6 +280,14 @@ module.exports = {
chunks: 'initial',
minChunks: autoEntriesCount * 0.9,
}),
+ graphql: {
+ priority: 16,
+ name: 'graphql',
+ chunks: 'all',
+ test: /[\\/]node_modules[\\/][^\\/]*(immer|apollo|graphql|zen-observable)[^\\/]*[\\/]/,
+ minChunks: 2,
+ reuseExistingChunk: true,
+ },
monaco: {
priority: 15,
name: 'monaco',
@@ -543,6 +553,7 @@ module.exports = {
devServer: {
host: DEV_SERVER_HOST,
port: DEV_SERVER_PORT,
+ https: DEV_SERVER_HTTPS,
disableHostCheck: true,
headers: {
'Access-Control-Allow-Origin': '*',
diff --git a/danger/ci_templates/Dangerfile b/danger/ci_templates/Dangerfile
new file mode 100644
index 00000000000..34b4bbff7a5
--- /dev/null
+++ b/danger/ci_templates/Dangerfile
@@ -0,0 +1,30 @@
+# frozen_string_literal: true
+
+gitlab_danger = GitlabDanger.new(helper.gitlab_helper)
+
+TEMPLATE_MESSAGE = <<~MSG
+This merge request requires a CI/CD Template review. To make sure these
+changes are reviewed, take the following steps:
+
+1. Ensure the merge request has the ~"ci::templates" label.
+ If the merge request modifies CI/CD Template files, Danger will do this for you.
+1. Prepare your MR for a CI/CD Template review according to the
+ [template development guide](https://docs.gitlab.com/ee/development/cicd/templates.html).
+1. Assign and `@` mention the CI/CD Template reviewer suggested by Reviewer Roulette.
+MSG
+
+TEMPLATE_FILES_MESSAGE = <<~MSG
+The following files require a review from the CI/CD Templates maintainers:
+MSG
+
+return unless gitlab_danger.ci?
+
+template_paths_to_review = helper.changes_by_category[:ci_template]
+
+if gitlab.mr_labels.include?('ci::templates') || template_paths_to_review.any?
+ message 'This merge request adds or changes files that require a ' \
+ 'review from the CI/CD Templates maintainers.'
+
+ markdown(TEMPLATE_MESSAGE)
+ markdown(TEMPLATE_FILES_MESSAGE + helper.markdown_list(template_paths_to_review)) if template_paths_to_review.any?
+end
diff --git a/danger/documentation/Dangerfile b/danger/documentation/Dangerfile
index 16d22969fbd..dc43e9d1843 100644
--- a/danger/documentation/Dangerfile
+++ b/danger/documentation/Dangerfile
@@ -8,8 +8,7 @@ docs_paths_to_review = helper.changes_by_category[:docs]
return if docs_paths_to_review.empty?
-message 'This merge request adds or changes files that require a review ' \
- 'from the Technical Writing team.'
+message 'This merge request adds or changes documentation files. A review from the Technical Writing team before you merge is **recommended**. Reviews can happen after you merge.'
return unless gitlab_danger.ci?
diff --git a/danger/metadata/Dangerfile b/danger/metadata/Dangerfile
index 1d7f863c201..b98d10d0654 100644
--- a/danger/metadata/Dangerfile
+++ b/danger/metadata/Dangerfile
@@ -40,10 +40,3 @@ has_pick_into_stable_label = gitlab.mr_labels.find { |label| label.start_with?('
if gitlab.branch_for_base != "master" && !has_pick_into_stable_label && !helper.security_mr?
warn "Most of the time, merge requests should target `master`. Otherwise, please set the relevant `Pick into X.Y` label."
end
-
-if gitlab.mr_json['title'].length > 72
- warn 'The title of this merge request is longer than 72 characters and ' \
- 'would violate our commit message rules when using the Squash on Merge ' \
- 'feature. Please consider adjusting the title, or rebase the ' \
- "commits manually and don't use Squash on Merge."
-end
diff --git a/danger/pajamas/Dangerfile b/danger/pajamas/Dangerfile
index 34dcbc21941..36bf7672cbf 100644
--- a/danger/pajamas/Dangerfile
+++ b/danger/pajamas/Dangerfile
@@ -1,15 +1,43 @@
# frozen_string_literal: true
+# rubocop:disable Style/SignalException
PATTERNS = %w[
+ %a.btn.btn-
+ %button.btn.btn-
+ .alert
+ .alert-danger
+ .alert-dismissible
+ .alert-info
+ .alert-link
+ .alert-primary
+ .alert-success
+ .alert-warning
+ .nav-tabs
+ .toolbar-button-icon
+ .tooltip
+ .tooltip-inner
+ <button
+ <tabs
+ bs-callout
createFlash
+ deprecated-modal
gl-deprecated-button
- loading-button
- pagination-button
gl-deprecated-dropdown
gl-deprecated-dropdown-divider
gl-deprecated-dropdown-header
gl-deprecated-dropdown-item
+ has-tooltip
+ has_tooltip
initDeprecatedJQueryDropdown
+ loading-button
+ v-popover
+ v-tooltip
+ with_tooltip
+].freeze
+
+BLOCKING_PATTERNS = %w[
+ pagination-button
+ graphql_pagination
].freeze
def get_added_lines(files)
@@ -25,19 +53,34 @@ changed_vue_haml_files = helper.changed_files(/.vue$|.haml$/)
return if changed_vue_haml_files.empty?
changed_lines_in_mr = get_added_lines(changed_vue_haml_files)
-has_deprecated_components = changed_lines_in_mr.select { |i| i[/#{PATTERNS.join("|")}/] }
-deprecated_components_in_mr = PATTERNS.select { |s| has_deprecated_components.join(" ")[s] }
-
-return if deprecated_components_in_mr.empty?
+deprecated_components_in_mr = PATTERNS.select { |pattern| changed_lines_in_mr.any? { |line| line[pattern] } }
+blocking_components_in_mr = BLOCKING_PATTERNS.select { |pattern| changed_lines_in_mr.any? { |line| line[pattern] } }
-warn "This merge request contains deprecated components. Please consider using Pajamas components instead."
+return if (deprecated_components_in_mr + blocking_components_in_mr).empty?
markdown(<<~MARKDOWN)
## Deprecated components
- The following components are deprecated:
+MARKDOWN
- * #{deprecated_components_in_mr.join("\n* ")}
+if blocking_components_in_mr.any?
+ markdown(<<~MARKDOWN)
+ These deprecated components have already been migrated and can no longer be used. Please use [Pajamas components](https://design.gitlab.com/components/status/) instead.
- Please consider using [Pajamas components](https://design.gitlab.com/components/status/) instead.
-MARKDOWN
+ * #{blocking_components_in_mr.join("\n* ")}
+
+ MARKDOWN
+
+ fail "This merge request contains deprecated components that have been migrated and can no longer be used. Please use Pajamas components instead."
+end
+
+if deprecated_components_in_mr.any?
+ markdown(<<~MARKDOWN)
+ These deprecated components are in the process of being migrated. Please consider using [Pajamas components](https://design.gitlab.com/components/status/) instead.
+
+ * #{deprecated_components_in_mr.join("\n* ")}
+
+ MARKDOWN
+
+ warn "This merge request contains deprecated components. Please consider using Pajamas components instead."
+end
diff --git a/danger/product_analytics/Dangerfile b/danger/product_analytics/Dangerfile
new file mode 100644
index 00000000000..fb441d6e467
--- /dev/null
+++ b/danger/product_analytics/Dangerfile
@@ -0,0 +1,48 @@
+# frozen_string_literal: true
+
+PRODUCT_ANALYTICS_CHANGED_FILES_MESSAGE = <<~MSG
+For the following files, a review from the [Data team and Product Analytics team](https://gitlab.com/groups/gitlab-org/growth/product_analytics/engineers/-/group_members?with_inherited_permissions=exclude) is recommended
+Please check the ~"product analytics(telemetry)" [guide](https://docs.gitlab.com/ee/development/product_analytics/usage_ping.html) and reach out to %<product_analytics_engineers_group>s group for a review.
+
+
+%<changed_files>s
+
+MSG
+
+UPDATE_METRICS_DEFINITIONS_MESSAGE = <<~MSG
+ When adding, changing, or updating metrics, please update the [Event dictionary Usage Ping table](https://docs.gitlab.com/ee/development/product_analytics/event_dictionary.html#usage-ping).
+
+MSG
+
+PRODUCT_ANALYTICS_ENGINEERS_GROUP = '@gitlab-org/growth/product_analytics/engineers'
+
+tracking_files = [
+ 'lib/gitlab/tracking.rb',
+ 'spec/lib/gitlab/tracking_spec.rb',
+ 'app/helpers/tracking_helper.rb',
+ 'spec/helpers/tracking_helper_spec.rb',
+ 'app/assets/javascripts/tracking.js',
+ 'spec/frontend/tracking_spec.js'
+]
+
+usage_data_changed_files = helper.changed_files(/usage_data/)
+snowplow_events_changed_files = git.modified_files & tracking_files
+
+changed_files = (usage_data_changed_files + snowplow_events_changed_files)
+
+if changed_files.any?
+
+ mention = if helper.draft_mr?
+ "`#{PRODUCT_ANALYTICS_ENGINEERS_GROUP}`"
+ else
+ PRODUCT_ANALYTICS_ENGINEERS_GROUP
+ end
+
+ warn format(PRODUCT_ANALYTICS_CHANGED_FILES_MESSAGE, changed_files: helper.markdown_list(changed_files), product_analytics_engineers_group: mention)
+ warn format(UPDATE_METRICS_DEFINITIONS_MESSAGE) unless helper.changed_files(/usage_ping\.md/).any?
+
+ product_analytics_labels = ['product analytics(telemetry)']
+ product_analytics_labels << 'product analytics(telemetry)::review pending' unless helper.mr_has_labels?('product analytics(telemetry)::reviewed')
+
+ markdown(helper.prepare_labels_for_mr(product_analytics_labels))
+end
diff --git a/danger/specialization_labels/Dangerfile b/danger/specialization_labels/Dangerfile
index 919f7313b49..ac93eb4c3e1 100644
--- a/danger/specialization_labels/Dangerfile
+++ b/danger/specialization_labels/Dangerfile
@@ -10,7 +10,8 @@ SPECIALIZATIONS = {
frontend: 'frontend',
docs: 'documentation',
qa: 'QA',
- engineering_productivity: 'Engineering Productivity'
+ engineering_productivity: 'Engineering Productivity',
+ ci_template: 'ci::templates'
}.freeze
labels_to_add = helper.changes_by_category.each_with_object([]) do |(category, _changes), memo|
diff --git a/danger/telemetry/Dangerfile b/danger/telemetry/Dangerfile
deleted file mode 100644
index 6cfc1a005c3..00000000000
--- a/danger/telemetry/Dangerfile
+++ /dev/null
@@ -1,38 +0,0 @@
-# frozen_string_literal: true
-
-TELEMETRY_CHANGED_FILES_MESSAGE = <<~MSG
-For the following files, a review from the [Data team and Telemetry team](https://gitlab.com/groups/gitlab-org/growth/telemetry/engineers/-/group_members?with_inherited_permissions=exclude) is recommended
-Please check the ~telemetry [guide](https://docs.gitlab.com/ee/development/telemetry/usage_ping.html) and reach out to @gitlab-org/growth/telemetry/engineers group for a review.
-
-%<changed_files>s
-
-MSG
-
-UPDATE_METRICS_DEFINITIONS_MESSAGE = <<~MSG
- When adding, changing, or updating metrics, please update the [Event dictionary Usage Ping table](https://docs.gitlab.com/ee/development/telemetry/event_dictionary.html#usage-ping).
-
-MSG
-
-tracking_files = [
- 'lib/gitlab/tracking.rb',
- 'spec/lib/gitlab/tracking_spec.rb',
- 'app/helpers/tracking_helper.rb',
- 'spec/helpers/tracking_helper_spec.rb',
- 'app/assets/javascripts/tracking.js',
- 'spec/frontend/tracking_spec.js'
-]
-
-usage_data_changed_files = helper.changed_files(/usage_data/)
-snowplow_events_changed_files = git.modified_files & tracking_files
-
-changed_files = (usage_data_changed_files + snowplow_events_changed_files)
-
-if changed_files.any?
- warn format(TELEMETRY_CHANGED_FILES_MESSAGE, changed_files: helper.markdown_list(changed_files))
- warn format(UPDATE_METRICS_DEFINITIONS_MESSAGE) unless helper.changed_files(/usage_ping\.md/).any?
-
- telemetry_labels = ['telemetry']
- telemetry_labels << 'telemetry::review pending' unless helper.mr_has_labels?('telemetry::reviewed')
-
- markdown(helper.prepare_labels_for_mr(telemetry_labels))
-end
diff --git a/data/whats_new/202008180001_12_10.yml b/data/whats_new/202008180001_12_10.yml
index 9acabbb76e6..66267bfcace 100644
--- a/data/whats_new/202008180001_12_10.yml
+++ b/data/whats_new/202008180001_12_10.yml
@@ -7,8 +7,8 @@
packages: [Ultimate, Gold]
url: https://docs.gitlab.com/ee/user/project/requirements/index.html
image_url:
- published_at: 2020-04-22
- release: 12.10
+ published_at: 2020-04-22
+ release: 12.10
- title: Retrieve CI/CD secrets from HashiCorp Vault
body: In this release, GitLab adds support for lightweight JSON Web Token (JWT) authentication to integrate with your existing HashiCorp Vault. Now, you can seamlessly provide secrets to CI/CD jobs by taking advantage of HashiCorp's JWT authentication method rather than manually having to provide secrets as a variable in GitLab.
stage: Release
diff --git a/data/whats_new/202009300001_13_04.yml b/data/whats_new/202009300001_13_04.yml
new file mode 100644
index 00000000000..cda0cf15170
--- /dev/null
+++ b/data/whats_new/202009300001_13_04.yml
@@ -0,0 +1,61 @@
+---
+- title: Use HashiCorp Vault secrets in CI jobs
+ body: In GitLab 12.10, GitLab introduced functionality for GitLab Runner to fetch and inject secrets into CI jobs. GitLab is now expanding the JWT Vault Authentication method by building a new secrets syntax in the .gitlab-ci.yml file. This makes it easier for you to configure and use HashiCorp Vault with GitLab.
+ stage: Release
+ self-managed: true
+ gitlab-com: true
+ packages: [Premium, Ultimate]
+ url: https://docs.gitlab.com/ee/ci/secrets
+ image_url: https://about.gitlab.com/images/13_4/vault_ci.png
+ published_at: 2020-09-22
+ release: 13.4
+- title: Introducing the GitLab Kubernetes Agent
+ body: "GitLab's Kubernetes integration has long enabled deployment to Kubernetes clusters without manual setup. Many users have enjoyed the ease-of-use, while others have run into some challenges. The current integration requires your cluster to be open to the Internet for GitLab to access it. For many organizations, this isn't possible, because they must lock down their cluster access for security, compliance, or regulatory purposes. To work around these restrictions, users needed to create custom tooling on top of GitLab, or they couldn't use the feature. Today, we're announcing the GitLab Kubernetes Agent: a new way to deploy to Kubernetes clusters. The Agent runs inside of your cluster, so you don't need to open it to the internet. The Agent orchestrates deployments by pulling new changes from GitLab, rather than GitLab pushing updates to the cluster. No matter what method of GitOps you use, GitLab has you covered."
+ stage: Configure
+ self-managed: true
+ gitlab-com: false
+ packages: [Premium, Ultimate]
+ url: https://docs.gitlab.com/ee/user/clusters/agent
+ image_url: https://about.gitlab.com/images/13_4/gitops-header.png
+ published_at: 2020-09-22
+ release: 13.4
+- title: Grant users deployment permissions without code access
+ body: If your team needs to maintain separation of duties between team members who own development, and team members who own deployments, the permissions paradigm in GitLab has made this challenging. In GitLab 13.4, you can give non-code contributors permission to approve merge requests for deployment, and actually deploy code, without also granting them maintainer access.
+ stage: Release
+ self-managed: true
+ gitlab-com: true
+ packages: [Premium, Ultimate]
+ url: https://docs.gitlab.com/ee/ci/environments/protected_environments.html#environment-access-by-group-membership
+ image_url: https://about.gitlab.com/images/13_4/deployer-role.png
+ published_at: 2020-09-22
+ release: 13.4
+- title: Security Center
+ body: We've made a foundational change to security visibility and management in GitLab. The Instance Security Dashboard has been transformed into a Security Center. The biggest change is introducing a new menu structure. Rather than a single page, you can now find a Security Dashboard, Vulnerability Report, and Settings area. While the functionality hasn't changed, breaking things apart enables future enhancements that would have been difficult otherwise. This also creates a top-level framework for including other security-related functionality in the future. The dedicated Vulnerability Report now has more room to display important details and inherits those currently found on the Project vulnerability list. Separating the vulnerability metrics widgets into their own area creates a true Security Dashboard.
+ stage: Secure
+ self-managed: true
+ gitlab-com: true
+ packages: [Ultimate]
+ url: https://docs.gitlab.com/ee/user/application_security/security_dashboard/#instance-security-center
+ image_url: https://about.gitlab.com/images/13_4/instance_vulnerability_report.png
+ published_at: 2020-09-22
+ release: 13.4
+- title: Feature Flags made available in GitLab Starter
+ body: Earlier this year, GitLab committed to moving 18 features to our open source core product. With this release of GitLab we've finished moving Feature Flags to Starter, and we are continuing to migrate our Feature Flag service to Core in GitLab 13.5. We're excited about bringing these features to more users and seeing what use cases and workflows you use them for.
+ stage: Release
+ self-managed: true
+ gitlab-com: true
+ packages: [starter, premium, ultimate]
+ url: https://www.youtube.com/embed/1FBRaBQTQZk
+ image_url: http://i3.ytimg.com/vi/1FBRaBQTQZk/maxresdefault.jpg
+ published_at: 2020-09-22
+ release: 13.4
+- title: Quick navigation using the Search bar
+ body: When navigating through GitLab, sometimes you just want to go to a specific project and not a search result page. Using the Global search bar, you can now quickly jump to recent issues, groups, projects, settings, and help topics. You can even use the `/` keyboard shortcut to move the cursor to the search bar, to navigate GitLab even more efficiently!
+ stage: Enablement
+ self-managed: true
+ gitlab-com: true
+ packages: [core, starter, premium, ultimate]
+ url: https://docs.gitlab.com/ee/user/search/#autocomplete-suggestions
+ image_url: https://about.gitlab.com/images/13_4/enablement_global_search.gif
+ published_at: 2020-09-22
+ release: 13.4
diff --git a/db/fixtures/development/29_instance_statistics.rb b/db/fixtures/development/29_instance_statistics.rb
index c4af13d0f4d..02afdc61339 100644
--- a/db/fixtures/development/29_instance_statistics.rb
+++ b/db/fixtures/development/29_instance_statistics.rb
@@ -3,17 +3,31 @@
require './spec/support/sidekiq_middleware'
Gitlab::Seeder.quiet do
+ chance_for_decrement = 0.1 # 10% chance that we'll generate smaller count than the previous count
+ max_increase = 10000
+ max_decrease = 1000
+
model_class = Analytics::InstanceStatistics::Measurement
- recorded_at = Date.today
- # Insert random counts for the last 10 weeks
- measurements = 10.times.flat_map do
- recorded_at = (recorded_at - 1.week).end_of_week.end_of_day - 5.minutes
+ measurements = model_class.identifiers.flat_map do |_, id|
+ recorded_at = 60.days.ago
+ current_count = rand(1_000_000)
+
+ # Insert random counts for the last 60 days
+ Array.new(60) do
+ recorded_at = (recorded_at + 1.day).end_of_day - 5.minutes
+
+ # Normally our counts should slowly increase as the gitlab instance grows.
+ # Small chance (10%) to have a slight decrease (simulating cleanups, bulk delete)
+ if rand < chance_for_decrement
+ current_count -= rand(max_decrease)
+ else
+ current_count += rand(max_increase)
+ end
- model_class.identifiers.map do |_, id|
{
recorded_at: recorded_at,
- count: rand(1_000_000),
+ count: current_count,
identifier: id
}
end
diff --git a/db/migrate/20200123090839_remove_analytics_repository_table_fks_on_projects.rb b/db/migrate/20200123090839_remove_analytics_repository_table_fks_on_projects.rb
index 94fafe214c2..18fd349df2a 100644
--- a/db/migrate/20200123090839_remove_analytics_repository_table_fks_on_projects.rb
+++ b/db/migrate/20200123090839_remove_analytics_repository_table_fks_on_projects.rb
@@ -5,22 +5,26 @@ class RemoveAnalyticsRepositoryTableFksOnProjects < ActiveRecord::Migration[5.2]
DOWNTIME = false
+ disable_ddl_transaction!
+
def up
+ # Requires ExclusiveLock on all tables. analytics_* tables are empty
with_lock_retries do
- # Requires ExclusiveLock on all tables. analytics_* tables are empty
- remove_foreign_key :analytics_repository_files, :projects
- remove_foreign_key :analytics_repository_file_edits, :projects if table_exists?(:analytics_repository_file_edits) # this table might be already dropped on development environment
- remove_foreign_key :analytics_repository_file_commits, :projects
+ remove_foreign_key_if_exists(:analytics_repository_files, :projects)
end
- end
- def down
with_lock_retries do
- # rubocop:disable Migration/AddConcurrentForeignKey
- add_foreign_key :analytics_repository_files, :projects, on_delete: :cascade
- add_foreign_key :analytics_repository_file_edits, :projects, on_delete: :cascade
- add_foreign_key :analytics_repository_file_commits, :projects, on_delete: :cascade
- # rubocop:enable Migration/AddConcurrentForeignKey
+ remove_foreign_key_if_exists(:analytics_repository_file_edits, :projects) if table_exists?(:analytics_repository_file_edits) # this table might be already dropped on development environment
end
+
+ with_lock_retries do
+ remove_foreign_key_if_exists(:analytics_repository_file_commits, :projects)
+ end
+ end
+
+ def down
+ add_concurrent_foreign_key(:analytics_repository_files, :projects, column: :project_id, on_delete: :cascade)
+ add_concurrent_foreign_key(:analytics_repository_file_edits, :projects, column: :project_id, on_delete: :cascade)
+ add_concurrent_foreign_key(:analytics_repository_file_commits, :projects, column: :project_id, on_delete: :cascade)
end
end
diff --git a/db/migrate/20200123091422_remove_analytics_repository_files_fk_on_other_analytics_tables.rb b/db/migrate/20200123091422_remove_analytics_repository_files_fk_on_other_analytics_tables.rb
index e3e415dd0ad..a436ad8d529 100644
--- a/db/migrate/20200123091422_remove_analytics_repository_files_fk_on_other_analytics_tables.rb
+++ b/db/migrate/20200123091422_remove_analytics_repository_files_fk_on_other_analytics_tables.rb
@@ -5,20 +5,21 @@ class RemoveAnalyticsRepositoryFilesFkOnOtherAnalyticsTables < ActiveRecord::Mig
DOWNTIME = false
+ disable_ddl_transaction!
+
def up
+ # Requires ExclusiveLock on all tables. analytics_* tables are empty
with_lock_retries do
- # Requires ExclusiveLock on all tables. analytics_* tables are empty
- remove_foreign_key :analytics_repository_file_edits, :analytics_repository_files if table_exists?(:analytics_repository_file_edits) # this table might be already dropped on development environment
- remove_foreign_key :analytics_repository_file_commits, :analytics_repository_files
+ remove_foreign_key_if_exists(:analytics_repository_file_edits, :analytics_repository_files) if table_exists?(:analytics_repository_file_edits) # this table might be already dropped on development environment
end
- end
- def down
with_lock_retries do
- # rubocop:disable Migration/AddConcurrentForeignKey
- add_foreign_key :analytics_repository_file_edits, :analytics_repository_files, on_delete: :cascade
- add_foreign_key :analytics_repository_file_commits, :analytics_repository_files, on_delete: :cascade
- # rubocop:enable Migration/AddConcurrentForeignKey
+ remove_foreign_key_if_exists(:analytics_repository_file_commits, :analytics_repository_files)
end
end
+
+ def down
+ add_concurrent_foreign_key(:analytics_repository_file_edits, :analytics_repository_files, column: :analytics_repository_file_id, on_delete: :cascade)
+ add_concurrent_foreign_key(:analytics_repository_file_commits, :analytics_repository_files, column: :analytics_repository_file_id, on_delete: :cascade)
+ end
end
diff --git a/db/migrate/20200226100624_requirements_add_project_fk.rb b/db/migrate/20200226100624_requirements_add_project_fk.rb
index 7c133e820f3..b44ce1d34ec 100644
--- a/db/migrate/20200226100624_requirements_add_project_fk.rb
+++ b/db/migrate/20200226100624_requirements_add_project_fk.rb
@@ -7,7 +7,7 @@ class RequirementsAddProjectFk < ActiveRecord::Migration[6.0]
def up
with_lock_retries do
- add_foreign_key(:requirements, :projects, column: :project_id, on_delete: :cascade) # rubocop: disable Migration/AddConcurrentForeignKey
+ add_foreign_key(:requirements, :projects, column: :project_id, on_delete: :cascade)
end
end
diff --git a/db/migrate/20200226100634_requirements_add_author_fk.rb b/db/migrate/20200226100634_requirements_add_author_fk.rb
index 8e1a726bb76..b458657827f 100644
--- a/db/migrate/20200226100634_requirements_add_author_fk.rb
+++ b/db/migrate/20200226100634_requirements_add_author_fk.rb
@@ -7,7 +7,7 @@ class RequirementsAddAuthorFk < ActiveRecord::Migration[6.0]
def up
with_lock_retries do
- add_foreign_key(:requirements, :users, column: :author_id, on_delete: :nullify) # rubocop: disable Migration/AddConcurrentForeignKey
+ add_foreign_key(:requirements, :users, column: :author_id, on_delete: :nullify)
end
end
diff --git a/db/migrate/20200304121828_add_ci_sources_project_pipeline_foreign_key.rb b/db/migrate/20200304121828_add_ci_sources_project_pipeline_foreign_key.rb
index d5b0af41d4a..ed244a7d308 100644
--- a/db/migrate/20200304121828_add_ci_sources_project_pipeline_foreign_key.rb
+++ b/db/migrate/20200304121828_add_ci_sources_project_pipeline_foreign_key.rb
@@ -7,7 +7,7 @@ class AddCiSourcesProjectPipelineForeignKey < ActiveRecord::Migration[6.0]
def up
with_lock_retries do
- add_foreign_key :ci_sources_projects, :ci_pipelines, column: :pipeline_id, on_delete: :cascade # rubocop:disable Migration/AddConcurrentForeignKey
+ add_foreign_key :ci_sources_projects, :ci_pipelines, column: :pipeline_id, on_delete: :cascade
end
end
diff --git a/db/migrate/20200304121844_add_ci_sources_project_source_project_foreign_key.rb b/db/migrate/20200304121844_add_ci_sources_project_source_project_foreign_key.rb
index 4f679bef85e..56ae2106644 100644
--- a/db/migrate/20200304121844_add_ci_sources_project_source_project_foreign_key.rb
+++ b/db/migrate/20200304121844_add_ci_sources_project_source_project_foreign_key.rb
@@ -7,7 +7,7 @@ class AddCiSourcesProjectSourceProjectForeignKey < ActiveRecord::Migration[6.0]
def up
with_lock_retries do
- add_foreign_key :ci_sources_projects, :projects, column: :source_project_id, on_delete: :cascade # rubocop:disable Migration/AddConcurrentForeignKey
+ add_foreign_key :ci_sources_projects, :projects, column: :source_project_id, on_delete: :cascade
end
end
diff --git a/db/migrate/20200316173312_add_vulnerability_export_project_foreign_key.rb b/db/migrate/20200316173312_add_vulnerability_export_project_foreign_key.rb
index 23837f559d2..84b96c64658 100644
--- a/db/migrate/20200316173312_add_vulnerability_export_project_foreign_key.rb
+++ b/db/migrate/20200316173312_add_vulnerability_export_project_foreign_key.rb
@@ -7,7 +7,7 @@ class AddVulnerabilityExportProjectForeignKey < ActiveRecord::Migration[6.0]
def up
with_lock_retries do
- add_foreign_key :vulnerability_exports, :projects, column: :project_id, on_delete: :cascade, index: false # rubocop:disable Migration/AddConcurrentForeignKey
+ add_foreign_key :vulnerability_exports, :projects, column: :project_id, on_delete: :cascade, index: false
end
end
diff --git a/db/migrate/20200317142110_add_vulnerability_export_user_foreign_key.rb b/db/migrate/20200317142110_add_vulnerability_export_user_foreign_key.rb
index 032577f2f2a..c4f685701b9 100644
--- a/db/migrate/20200317142110_add_vulnerability_export_user_foreign_key.rb
+++ b/db/migrate/20200317142110_add_vulnerability_export_user_foreign_key.rb
@@ -7,7 +7,7 @@ class AddVulnerabilityExportUserForeignKey < ActiveRecord::Migration[6.0]
def up
with_lock_retries do
- add_foreign_key :vulnerability_exports, :users, column: :author_id, on_delete: :cascade, index: false # rubocop:disable Migration/AddConcurrentForeignKey
+ add_foreign_key :vulnerability_exports, :users, column: :author_id, on_delete: :cascade, index: false
end
end
diff --git a/db/migrate/20200326124443_add_projects_fk_to_jira_imports_table.rb b/db/migrate/20200326124443_add_projects_fk_to_jira_imports_table.rb
index 6410f530b30..654d35619e3 100644
--- a/db/migrate/20200326124443_add_projects_fk_to_jira_imports_table.rb
+++ b/db/migrate/20200326124443_add_projects_fk_to_jira_imports_table.rb
@@ -7,7 +7,7 @@ class AddProjectsFkToJiraImportsTable < ActiveRecord::Migration[6.0]
def up
with_lock_retries do
- add_foreign_key :jira_imports, :projects, on_delete: :cascade # rubocop:disable Migration/AddConcurrentForeignKey
+ add_foreign_key :jira_imports, :projects, on_delete: :cascade
end
end
diff --git a/db/migrate/20200326134443_add_users_fk_to_jira_imports_table.rb b/db/migrate/20200326134443_add_users_fk_to_jira_imports_table.rb
index 0956a8e814b..429f72628e2 100644
--- a/db/migrate/20200326134443_add_users_fk_to_jira_imports_table.rb
+++ b/db/migrate/20200326134443_add_users_fk_to_jira_imports_table.rb
@@ -7,7 +7,7 @@ class AddUsersFkToJiraImportsTable < ActiveRecord::Migration[6.0]
def up
with_lock_retries do
- add_foreign_key :jira_imports, :users, on_delete: :nullify # rubocop:disable Migration/AddConcurrentForeignKey
+ add_foreign_key :jira_imports, :users, on_delete: :nullify
end
end
diff --git a/db/migrate/20200326144443_add_labels_fk_to_jira_imports_table.rb b/db/migrate/20200326144443_add_labels_fk_to_jira_imports_table.rb
index ead04100a96..9bcadcb61c1 100644
--- a/db/migrate/20200326144443_add_labels_fk_to_jira_imports_table.rb
+++ b/db/migrate/20200326144443_add_labels_fk_to_jira_imports_table.rb
@@ -7,7 +7,7 @@ class AddLabelsFkToJiraImportsTable < ActiveRecord::Migration[6.0]
def up
with_lock_retries do
- add_foreign_key :jira_imports, :labels, on_delete: :nullify # rubocop:disable Migration/AddConcurrentForeignKey
+ add_foreign_key :jira_imports, :labels, on_delete: :nullify
end
end
diff --git a/db/migrate/20200416120354_add_locked_by_user_id_foreign_key_to_terraform_state.rb b/db/migrate/20200416120354_add_locked_by_user_id_foreign_key_to_terraform_state.rb
index ecee028351a..144291d94be 100644
--- a/db/migrate/20200416120354_add_locked_by_user_id_foreign_key_to_terraform_state.rb
+++ b/db/migrate/20200416120354_add_locked_by_user_id_foreign_key_to_terraform_state.rb
@@ -7,7 +7,7 @@ class AddLockedByUserIdForeignKeyToTerraformState < ActiveRecord::Migration[6.0]
def up
with_lock_retries do
- add_foreign_key :terraform_states, :users, column: :locked_by_user_id # rubocop:disable Migration/AddConcurrentForeignKey
+ add_foreign_key :terraform_states, :users, column: :locked_by_user_id
end
end
diff --git a/db/migrate/20200423075720_add_user_id_foreign_key_to_resource_state_events.rb b/db/migrate/20200423075720_add_user_id_foreign_key_to_resource_state_events.rb
index 702347e5d43..91a6dbe4214 100644
--- a/db/migrate/20200423075720_add_user_id_foreign_key_to_resource_state_events.rb
+++ b/db/migrate/20200423075720_add_user_id_foreign_key_to_resource_state_events.rb
@@ -7,7 +7,7 @@ class AddUserIdForeignKeyToResourceStateEvents < ActiveRecord::Migration[6.0]
def up
with_lock_retries do
- add_foreign_key :resource_state_events, :users, column: :user_id, on_delete: :nullify # rubocop:disable Migration/AddConcurrentForeignKey
+ add_foreign_key :resource_state_events, :users, column: :user_id, on_delete: :nullify
end
end
diff --git a/db/migrate/20200423080334_add_issue_id_foreign_key_to_resource_state_events.rb b/db/migrate/20200423080334_add_issue_id_foreign_key_to_resource_state_events.rb
index 660c51eb3a6..b9f0fdeaa16 100644
--- a/db/migrate/20200423080334_add_issue_id_foreign_key_to_resource_state_events.rb
+++ b/db/migrate/20200423080334_add_issue_id_foreign_key_to_resource_state_events.rb
@@ -7,7 +7,7 @@ class AddIssueIdForeignKeyToResourceStateEvents < ActiveRecord::Migration[6.0]
def up
with_lock_retries do
- add_foreign_key :resource_state_events, :issues, column: :issue_id, on_delete: :cascade # rubocop:disable Migration/AddConcurrentForeignKey
+ add_foreign_key :resource_state_events, :issues, column: :issue_id, on_delete: :cascade
end
end
diff --git a/db/migrate/20200423080607_add_merge_request_id_foreign_key_to_resource_state_events.rb b/db/migrate/20200423080607_add_merge_request_id_foreign_key_to_resource_state_events.rb
index 4f0a689a992..3c070984f9e 100644
--- a/db/migrate/20200423080607_add_merge_request_id_foreign_key_to_resource_state_events.rb
+++ b/db/migrate/20200423080607_add_merge_request_id_foreign_key_to_resource_state_events.rb
@@ -7,7 +7,7 @@ class AddMergeRequestIdForeignKeyToResourceStateEvents < ActiveRecord::Migration
def up
with_lock_retries do
- add_foreign_key :resource_state_events, :merge_requests, column: :merge_request_id, on_delete: :cascade # rubocop:disable Migration/AddConcurrentForeignKey
+ add_foreign_key :resource_state_events, :merge_requests, column: :merge_request_id, on_delete: :cascade
end
end
diff --git a/db/migrate/20200429015603_add_fk_to_project_repository_storage_moves.rb b/db/migrate/20200429015603_add_fk_to_project_repository_storage_moves.rb
index a68ce66e4a6..166ce320a23 100644
--- a/db/migrate/20200429015603_add_fk_to_project_repository_storage_moves.rb
+++ b/db/migrate/20200429015603_add_fk_to_project_repository_storage_moves.rb
@@ -7,7 +7,7 @@ class AddFkToProjectRepositoryStorageMoves < ActiveRecord::Migration[6.0]
def up
with_lock_retries do
- add_foreign_key :project_repository_storage_moves, :projects, on_delete: :cascade # rubocop:disable Migration/AddConcurrentForeignKey
+ add_foreign_key :project_repository_storage_moves, :projects, on_delete: :cascade
end
end
diff --git a/db/migrate/20200510183128_add_foreign_key_from_webauthn_registrations_to_users.rb b/db/migrate/20200510183128_add_foreign_key_from_webauthn_registrations_to_users.rb
index f71a5276dee..9071e3e17e3 100644
--- a/db/migrate/20200510183128_add_foreign_key_from_webauthn_registrations_to_users.rb
+++ b/db/migrate/20200510183128_add_foreign_key_from_webauthn_registrations_to_users.rb
@@ -9,7 +9,7 @@ class AddForeignKeyFromWebauthnRegistrationsToUsers < ActiveRecord::Migration[6.
def up
with_lock_retries do
- add_foreign_key :webauthn_registrations, :users, column: :user_id, on_delete: :cascade # rubocop:disable Migration/AddConcurrentForeignKey
+ add_foreign_key :webauthn_registrations, :users, column: :user_id, on_delete: :cascade
end
end
diff --git a/db/migrate/20200511092505_add_foreign_key_to_epic_id_on_resource_state_events.rb b/db/migrate/20200511092505_add_foreign_key_to_epic_id_on_resource_state_events.rb
index 8072fe81c4a..1daa620501a 100644
--- a/db/migrate/20200511092505_add_foreign_key_to_epic_id_on_resource_state_events.rb
+++ b/db/migrate/20200511092505_add_foreign_key_to_epic_id_on_resource_state_events.rb
@@ -7,7 +7,7 @@ class AddForeignKeyToEpicIdOnResourceStateEvents < ActiveRecord::Migration[6.0]
def up
with_lock_retries do
- add_foreign_key :resource_state_events, :epics, column: :epic_id, on_delete: :cascade # rubocop:disable Migration/AddConcurrentForeignKey
+ add_foreign_key :resource_state_events, :epics, column: :epic_id, on_delete: :cascade
end
end
diff --git a/db/migrate/20200511121549_add_group_wiki_repositories_shard_id_foreign_key.rb b/db/migrate/20200511121549_add_group_wiki_repositories_shard_id_foreign_key.rb
index c2606dfb0d5..d1bb3fcc6ea 100644
--- a/db/migrate/20200511121549_add_group_wiki_repositories_shard_id_foreign_key.rb
+++ b/db/migrate/20200511121549_add_group_wiki_repositories_shard_id_foreign_key.rb
@@ -7,7 +7,7 @@ class AddGroupWikiRepositoriesShardIdForeignKey < ActiveRecord::Migration[6.0]
def up
with_lock_retries do
- add_foreign_key :group_wiki_repositories, :shards, on_delete: :restrict # rubocop:disable Migration/AddConcurrentForeignKey
+ add_foreign_key :group_wiki_repositories, :shards, on_delete: :restrict
end
end
diff --git a/db/migrate/20200511121610_add_group_wiki_repositories_group_id_foreign_key.rb b/db/migrate/20200511121610_add_group_wiki_repositories_group_id_foreign_key.rb
index 3a4c75be3b9..40f272cc0e7 100644
--- a/db/migrate/20200511121610_add_group_wiki_repositories_group_id_foreign_key.rb
+++ b/db/migrate/20200511121610_add_group_wiki_repositories_group_id_foreign_key.rb
@@ -7,7 +7,7 @@ class AddGroupWikiRepositoriesGroupIdForeignKey < ActiveRecord::Migration[6.0]
def up
with_lock_retries do
- add_foreign_key :group_wiki_repositories, :namespaces, column: :group_id, on_delete: :cascade # rubocop:disable Migration/AddConcurrentForeignKey
+ add_foreign_key :group_wiki_repositories, :namespaces, column: :group_id, on_delete: :cascade
end
end
diff --git a/db/migrate/20200511191027_add_author_foreign_key_to_test_reports.rb b/db/migrate/20200511191027_add_author_foreign_key_to_test_reports.rb
index a9fbee388c5..532133fe7f9 100644
--- a/db/migrate/20200511191027_add_author_foreign_key_to_test_reports.rb
+++ b/db/migrate/20200511191027_add_author_foreign_key_to_test_reports.rb
@@ -7,7 +7,7 @@ class AddAuthorForeignKeyToTestReports < ActiveRecord::Migration[6.0]
def up
with_lock_retries do
- add_foreign_key :requirements_management_test_reports, :users, column: :author_id, on_delete: :nullify # rubocop:disable Migration/AddConcurrentForeignKey
+ add_foreign_key :requirements_management_test_reports, :users, column: :author_id, on_delete: :nullify
end
end
diff --git a/db/migrate/20200511208012_add_pipeline_foreign_key_to_test_reports.rb b/db/migrate/20200511208012_add_pipeline_foreign_key_to_test_reports.rb
index 2b9b3464580..46657f9af6d 100644
--- a/db/migrate/20200511208012_add_pipeline_foreign_key_to_test_reports.rb
+++ b/db/migrate/20200511208012_add_pipeline_foreign_key_to_test_reports.rb
@@ -7,7 +7,7 @@ class AddPipelineForeignKeyToTestReports < ActiveRecord::Migration[6.0]
def up
with_lock_retries do
- add_foreign_key :requirements_management_test_reports, :ci_pipelines, column: :pipeline_id, on_delete: :nullify # rubocop:disable Migration/AddConcurrentForeignKey
+ add_foreign_key :requirements_management_test_reports, :ci_pipelines, column: :pipeline_id, on_delete: :nullify
end
end
diff --git a/db/migrate/20200521225337_add_foreign_key_to_user_id_on_alert_management_alert_assignees.rb b/db/migrate/20200521225337_add_foreign_key_to_user_id_on_alert_management_alert_assignees.rb
index 9d97c68f78f..4a6a25a8472 100644
--- a/db/migrate/20200521225337_add_foreign_key_to_user_id_on_alert_management_alert_assignees.rb
+++ b/db/migrate/20200521225337_add_foreign_key_to_user_id_on_alert_management_alert_assignees.rb
@@ -7,7 +7,7 @@ class AddForeignKeyToUserIdOnAlertManagementAlertAssignees < ActiveRecord::Migra
def up
with_lock_retries do
- add_foreign_key :alert_management_alert_assignees, :users, column: :user_id, on_delete: :cascade # rubocop:disable Migration/AddConcurrentForeignKey
+ add_foreign_key :alert_management_alert_assignees, :users, column: :user_id, on_delete: :cascade
end
end
diff --git a/db/migrate/20200521225346_add_foreign_key_to_alert_id_on_alert_mangagement_alert_assignees.rb b/db/migrate/20200521225346_add_foreign_key_to_alert_id_on_alert_mangagement_alert_assignees.rb
index 1d6197edef9..77d374f08fa 100644
--- a/db/migrate/20200521225346_add_foreign_key_to_alert_id_on_alert_mangagement_alert_assignees.rb
+++ b/db/migrate/20200521225346_add_foreign_key_to_alert_id_on_alert_mangagement_alert_assignees.rb
@@ -7,7 +7,7 @@ class AddForeignKeyToAlertIdOnAlertMangagementAlertAssignees < ActiveRecord::Mig
def up
with_lock_retries do
- add_foreign_key :alert_management_alert_assignees, :alert_management_alerts, column: :alert_id, on_delete: :cascade # rubocop:disable Migration/AddConcurrentForeignKey
+ add_foreign_key :alert_management_alert_assignees, :alert_management_alerts, column: :alert_id, on_delete: :cascade
end
end
diff --git a/db/migrate/20200526164947_add_foreign_key_to_ops_feature_flags_issues.rb b/db/migrate/20200526164947_add_foreign_key_to_ops_feature_flags_issues.rb
index 1cad53cb371..a11a8094823 100644
--- a/db/migrate/20200526164947_add_foreign_key_to_ops_feature_flags_issues.rb
+++ b/db/migrate/20200526164947_add_foreign_key_to_ops_feature_flags_issues.rb
@@ -7,7 +7,7 @@ class AddForeignKeyToOpsFeatureFlagsIssues < ActiveRecord::Migration[6.0]
def up
with_lock_retries do
- add_foreign_key :operations_feature_flags_issues, :issues, column: :issue_id, on_delete: :cascade # rubocop:disable Migration/AddConcurrentForeignKey
+ add_foreign_key :operations_feature_flags_issues, :issues, column: :issue_id, on_delete: :cascade
end
end
diff --git a/db/migrate/20200527135313_add_requirements_build_reference.rb b/db/migrate/20200527135313_add_requirements_build_reference.rb
index 3385243fbdd..b492871a19b 100644
--- a/db/migrate/20200527135313_add_requirements_build_reference.rb
+++ b/db/migrate/20200527135313_add_requirements_build_reference.rb
@@ -11,7 +11,7 @@ class AddRequirementsBuildReference < ActiveRecord::Migration[6.0]
add_index :requirements_management_test_reports, :build_id, name: INDEX_NAME # rubocop:disable Migration/AddIndex
with_lock_retries do
- add_foreign_key :requirements_management_test_reports, :ci_builds, column: :build_id, on_delete: :nullify # rubocop:disable Migration/AddConcurrentForeignKey
+ add_foreign_key :requirements_management_test_reports, :ci_builds, column: :build_id, on_delete: :nullify
end
end
diff --git a/db/migrate/20200527152116_add_foreign_key_to_build_id_on_build_report_results.rb b/db/migrate/20200527152116_add_foreign_key_to_build_id_on_build_report_results.rb
index 1c41389b15b..1809fed551a 100644
--- a/db/migrate/20200527152116_add_foreign_key_to_build_id_on_build_report_results.rb
+++ b/db/migrate/20200527152116_add_foreign_key_to_build_id_on_build_report_results.rb
@@ -7,7 +7,7 @@ class AddForeignKeyToBuildIdOnBuildReportResults < ActiveRecord::Migration[6.0]
def up
with_lock_retries do
- add_foreign_key :ci_build_report_results, :ci_builds, column: :build_id, on_delete: :cascade # rubocop:disable Migration/AddConcurrentForeignKey
+ add_foreign_key :ci_build_report_results, :ci_builds, column: :build_id, on_delete: :cascade
end
end
diff --git a/db/migrate/20200527152657_add_foreign_key_to_project_id_on_build_report_results.rb b/db/migrate/20200527152657_add_foreign_key_to_project_id_on_build_report_results.rb
index da870722bc3..1857cb07b06 100644
--- a/db/migrate/20200527152657_add_foreign_key_to_project_id_on_build_report_results.rb
+++ b/db/migrate/20200527152657_add_foreign_key_to_project_id_on_build_report_results.rb
@@ -7,7 +7,7 @@ class AddForeignKeyToProjectIdOnBuildReportResults < ActiveRecord::Migration[6.0
def up
with_lock_retries do
- add_foreign_key :ci_build_report_results, :projects, column: :project_id, on_delete: :cascade # rubocop:disable Migration/AddConcurrentForeignKey
+ add_foreign_key :ci_build_report_results, :projects, column: :project_id, on_delete: :cascade
end
end
diff --git a/db/migrate/20200604174544_add_users_foreign_key_to_board_user_preferences.rb b/db/migrate/20200604174544_add_users_foreign_key_to_board_user_preferences.rb
index 8f60c41a9c7..cc613e0261e 100644
--- a/db/migrate/20200604174544_add_users_foreign_key_to_board_user_preferences.rb
+++ b/db/migrate/20200604174544_add_users_foreign_key_to_board_user_preferences.rb
@@ -7,7 +7,7 @@ class AddUsersForeignKeyToBoardUserPreferences < ActiveRecord::Migration[6.0]
def up
with_lock_retries do
- add_foreign_key :board_user_preferences, :users, column: :user_id, on_delete: :cascade # rubocop:disable Migration/AddConcurrentForeignKey
+ add_foreign_key :board_user_preferences, :users, column: :user_id, on_delete: :cascade
end
end
diff --git a/db/migrate/20200604174558_add_boards_foreign_key_to_board_user_preferences.rb b/db/migrate/20200604174558_add_boards_foreign_key_to_board_user_preferences.rb
index a18f0eac505..4ac978d3741 100644
--- a/db/migrate/20200604174558_add_boards_foreign_key_to_board_user_preferences.rb
+++ b/db/migrate/20200604174558_add_boards_foreign_key_to_board_user_preferences.rb
@@ -7,7 +7,7 @@ class AddBoardsForeignKeyToBoardUserPreferences < ActiveRecord::Migration[6.0]
def up
with_lock_retries do
- add_foreign_key :board_user_preferences, :boards, column: :board_id, on_delete: :cascade # rubocop:disable Migration/AddConcurrentForeignKey
+ add_foreign_key :board_user_preferences, :boards, column: :board_id, on_delete: :cascade
end
end
diff --git a/db/migrate/20200605003204_add_foreign_key_to_alert_management_alert_user_mentions.rb b/db/migrate/20200605003204_add_foreign_key_to_alert_management_alert_user_mentions.rb
index 35a250521a6..3198544d3a9 100644
--- a/db/migrate/20200605003204_add_foreign_key_to_alert_management_alert_user_mentions.rb
+++ b/db/migrate/20200605003204_add_foreign_key_to_alert_management_alert_user_mentions.rb
@@ -7,7 +7,7 @@ class AddForeignKeyToAlertManagementAlertUserMentions < ActiveRecord::Migration[
def up
with_lock_retries do
- add_foreign_key :alert_management_alert_user_mentions, :notes, column: :note_id, on_delete: :cascade # rubocop:disable Migration/AddConcurrentForeignKey
+ add_foreign_key :alert_management_alert_user_mentions, :notes, column: :note_id, on_delete: :cascade
end
end
diff --git a/db/migrate/20200623073431_add_source_merge_request_id_to_resource_state_events.rb b/db/migrate/20200623073431_add_source_merge_request_id_to_resource_state_events.rb
index 8970797d3c0..01d0d8ce1d4 100644
--- a/db/migrate/20200623073431_add_source_merge_request_id_to_resource_state_events.rb
+++ b/db/migrate/20200623073431_add_source_merge_request_id_to_resource_state_events.rb
@@ -20,7 +20,7 @@ class AddSourceMergeRequestIdToResourceStateEvents < ActiveRecord::Migration[6.0
unless foreign_key_exists?(:resource_state_events, :merge_requests, column: :source_merge_request_id)
with_lock_retries do
- add_foreign_key :resource_state_events, :merge_requests, column: :source_merge_request_id, on_delete: :nullify # rubocop:disable Migration/AddConcurrentForeignKey
+ add_foreign_key :resource_state_events, :merge_requests, column: :source_merge_request_id, on_delete: :nullify
end
end
end
diff --git a/db/migrate/20200722132040_add_users_fk_to_resource_iteration_events_table.rb b/db/migrate/20200722132040_add_users_fk_to_resource_iteration_events_table.rb
index e28405be53d..c3d95c9dfc2 100644
--- a/db/migrate/20200722132040_add_users_fk_to_resource_iteration_events_table.rb
+++ b/db/migrate/20200722132040_add_users_fk_to_resource_iteration_events_table.rb
@@ -7,7 +7,7 @@ class AddUsersFkToResourceIterationEventsTable < ActiveRecord::Migration[6.0]
def up
with_lock_retries do
- add_foreign_key :resource_iteration_events, :users, column: :user_id, on_delete: :nullify # rubocop:disable Migration/AddConcurrentForeignKey
+ add_foreign_key :resource_iteration_events, :users, column: :user_id, on_delete: :nullify
end
end
diff --git a/db/migrate/20200722132540_add_issues_fk_to_resource_iteration_events_table.rb b/db/migrate/20200722132540_add_issues_fk_to_resource_iteration_events_table.rb
index adb10aaa707..b603f14f62b 100644
--- a/db/migrate/20200722132540_add_issues_fk_to_resource_iteration_events_table.rb
+++ b/db/migrate/20200722132540_add_issues_fk_to_resource_iteration_events_table.rb
@@ -7,7 +7,7 @@ class AddIssuesFkToResourceIterationEventsTable < ActiveRecord::Migration[6.0]
def up
with_lock_retries do
- add_foreign_key :resource_iteration_events, :issues, column: :issue_id, on_delete: :cascade # rubocop:disable Migration/AddConcurrentForeignKey
+ add_foreign_key :resource_iteration_events, :issues, column: :issue_id, on_delete: :cascade
end
end
diff --git a/db/migrate/20200722133040_add_merge_requests_fk_to_resource_iteration_events_table.rb b/db/migrate/20200722133040_add_merge_requests_fk_to_resource_iteration_events_table.rb
index 8b1859bb253..e047b157a53 100644
--- a/db/migrate/20200722133040_add_merge_requests_fk_to_resource_iteration_events_table.rb
+++ b/db/migrate/20200722133040_add_merge_requests_fk_to_resource_iteration_events_table.rb
@@ -7,7 +7,7 @@ class AddMergeRequestsFkToResourceIterationEventsTable < ActiveRecord::Migration
def up
with_lock_retries do
- add_foreign_key :resource_iteration_events, :merge_requests, column: :merge_request_id, on_delete: :cascade # rubocop:disable Migration/AddConcurrentForeignKey
+ add_foreign_key :resource_iteration_events, :merge_requests, column: :merge_request_id, on_delete: :cascade
end
end
diff --git a/db/migrate/20200722133540_add_iterations_fk_to_resource_iteration_events_table.rb b/db/migrate/20200722133540_add_iterations_fk_to_resource_iteration_events_table.rb
index b42c29a0634..1bb3ac7c8bd 100644
--- a/db/migrate/20200722133540_add_iterations_fk_to_resource_iteration_events_table.rb
+++ b/db/migrate/20200722133540_add_iterations_fk_to_resource_iteration_events_table.rb
@@ -7,7 +7,7 @@ class AddIterationsFkToResourceIterationEventsTable < ActiveRecord::Migration[6.
def up
with_lock_retries do
- add_foreign_key :resource_iteration_events, :sprints, column: :iteration_id, on_delete: :cascade # rubocop:disable Migration/AddConcurrentForeignKey
+ add_foreign_key :resource_iteration_events, :sprints, column: :iteration_id, on_delete: :cascade
end
end
diff --git a/db/migrate/20200731201408_add_foreign_key_to_experiment_on_experiment_users.rb b/db/migrate/20200731201408_add_foreign_key_to_experiment_on_experiment_users.rb
index 3961803bf52..c1a6dae242b 100644
--- a/db/migrate/20200731201408_add_foreign_key_to_experiment_on_experiment_users.rb
+++ b/db/migrate/20200731201408_add_foreign_key_to_experiment_on_experiment_users.rb
@@ -8,7 +8,7 @@ class AddForeignKeyToExperimentOnExperimentUsers < ActiveRecord::Migration[6.0]
def up
with_lock_retries do
# There is no need to use add_concurrent_foreign_key since it's an empty table
- add_foreign_key :experiment_users, :experiments, column: :experiment_id, on_delete: :cascade # rubocop:disable Migration/AddConcurrentForeignKey
+ add_foreign_key :experiment_users, :experiments, column: :experiment_id, on_delete: :cascade
end
end
diff --git a/db/migrate/20200731201834_add_foreign_key_to_user_on_experiment_users.rb b/db/migrate/20200731201834_add_foreign_key_to_user_on_experiment_users.rb
index 42c337fecff..673a0bde0b1 100644
--- a/db/migrate/20200731201834_add_foreign_key_to_user_on_experiment_users.rb
+++ b/db/migrate/20200731201834_add_foreign_key_to_user_on_experiment_users.rb
@@ -8,7 +8,7 @@ class AddForeignKeyToUserOnExperimentUsers < ActiveRecord::Migration[6.0]
def up
with_lock_retries do
# There is no need to use add_concurrent_foreign_key since it's an empty table
- add_foreign_key :experiment_users, :users, column: :user_id, on_delete: :cascade # rubocop:disable Migration/AddConcurrentForeignKey
+ add_foreign_key :experiment_users, :users, column: :user_id, on_delete: :cascade
end
end
diff --git a/db/migrate/20200805151001_add_foreign_key_to_pipeline_id_on_pipeline_artifact.rb b/db/migrate/20200805151001_add_foreign_key_to_pipeline_id_on_pipeline_artifact.rb
index d6c3a4fe742..5cfe0496b8d 100644
--- a/db/migrate/20200805151001_add_foreign_key_to_pipeline_id_on_pipeline_artifact.rb
+++ b/db/migrate/20200805151001_add_foreign_key_to_pipeline_id_on_pipeline_artifact.rb
@@ -7,7 +7,7 @@ class AddForeignKeyToPipelineIdOnPipelineArtifact < ActiveRecord::Migration[6.0]
def up
with_lock_retries do
- add_foreign_key :ci_pipeline_artifacts, :ci_pipelines, column: :pipeline_id, on_delete: :cascade # rubocop:disable Migration/AddConcurrentForeignKey
+ add_foreign_key :ci_pipeline_artifacts, :ci_pipelines, column: :pipeline_id, on_delete: :cascade
end
end
diff --git a/db/migrate/20200805151726_add_foreign_key_to_project_id_on_pipeline_artifact.rb b/db/migrate/20200805151726_add_foreign_key_to_project_id_on_pipeline_artifact.rb
index 367a2774d62..fe418f4c5af 100644
--- a/db/migrate/20200805151726_add_foreign_key_to_project_id_on_pipeline_artifact.rb
+++ b/db/migrate/20200805151726_add_foreign_key_to_project_id_on_pipeline_artifact.rb
@@ -7,7 +7,7 @@ class AddForeignKeyToProjectIdOnPipelineArtifact < ActiveRecord::Migration[6.0]
def up
with_lock_retries do
- add_foreign_key :ci_pipeline_artifacts, :projects, column: :project_id, on_delete: :cascade # rubocop:disable Migration/AddConcurrentForeignKey
+ add_foreign_key :ci_pipeline_artifacts, :projects, column: :project_id, on_delete: :cascade
end
end
diff --git a/db/migrate/20200813135558_create_ci_deleted_objects.rb b/db/migrate/20200813135558_create_ci_deleted_objects.rb
new file mode 100644
index 00000000000..5364b7fc0ce
--- /dev/null
+++ b/db/migrate/20200813135558_create_ci_deleted_objects.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+class CreateCiDeletedObjects < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ create_table :ci_deleted_objects, if_not_exists: true do |t|
+ t.integer :file_store, limit: 2, default: 1, null: false
+ t.datetime_with_timezone :pick_up_at, null: false, default: -> { 'now()' }, index: true
+ t.text :store_dir, null: false
+
+ # rubocop:disable Migration/AddLimitToTextColumns
+ # This column depends on the `file` column from `ci_job_artifacts` table
+ # which doesn't have a constraint limit on it.
+ t.text :file, null: false
+ # rubocop:enable Migration/AddLimitToTextColumns
+ end
+
+ add_text_limit(:ci_deleted_objects, :store_dir, 1024)
+ end
+
+ def down
+ drop_table :ci_deleted_objects
+ end
+end
diff --git a/db/migrate/20200817195628_add_modified_to_approval_merge_request_rule.rb b/db/migrate/20200817195628_add_modified_to_approval_merge_request_rule.rb
new file mode 100644
index 00000000000..71a29ae9bc5
--- /dev/null
+++ b/db/migrate/20200817195628_add_modified_to_approval_merge_request_rule.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+class AddModifiedToApprovalMergeRequestRule < ActiveRecord::Migration[6.0]
+ DOWNTIME = false
+
+ def change
+ add_column :approval_merge_request_rules, :modified_from_project_rule, :boolean, default: false, null: false
+ end
+end
diff --git a/db/migrate/20200825081035_boards_epic_user_preferences_fk_board.rb b/db/migrate/20200825081035_boards_epic_user_preferences_fk_board.rb
index eb52cadaecf..1c014573fb4 100644
--- a/db/migrate/20200825081035_boards_epic_user_preferences_fk_board.rb
+++ b/db/migrate/20200825081035_boards_epic_user_preferences_fk_board.rb
@@ -7,7 +7,7 @@ class BoardsEpicUserPreferencesFkBoard < ActiveRecord::Migration[6.0]
def up
with_lock_retries do
- add_foreign_key :boards_epic_user_preferences, :boards, column: :board_id, on_delete: :cascade # rubocop: disable Migration/AddConcurrentForeignKey
+ add_foreign_key :boards_epic_user_preferences, :boards, column: :board_id, on_delete: :cascade
end
end
diff --git a/db/migrate/20200825081045_boards_epic_user_preferences_fk_user.rb b/db/migrate/20200825081045_boards_epic_user_preferences_fk_user.rb
index 98d0a5b64f6..3edc3bc0ded 100644
--- a/db/migrate/20200825081045_boards_epic_user_preferences_fk_user.rb
+++ b/db/migrate/20200825081045_boards_epic_user_preferences_fk_user.rb
@@ -7,7 +7,7 @@ class BoardsEpicUserPreferencesFkUser < ActiveRecord::Migration[6.0]
def up
with_lock_retries do
- add_foreign_key :boards_epic_user_preferences, :users, column: :user_id, on_delete: :cascade # rubocop: disable Migration/AddConcurrentForeignKey
+ add_foreign_key :boards_epic_user_preferences, :users, column: :user_id, on_delete: :cascade
end
end
diff --git a/db/migrate/20200825081055_boards_epic_user_preferences_fk_epic.rb b/db/migrate/20200825081055_boards_epic_user_preferences_fk_epic.rb
index 46498f186c4..0354060b7c1 100644
--- a/db/migrate/20200825081055_boards_epic_user_preferences_fk_epic.rb
+++ b/db/migrate/20200825081055_boards_epic_user_preferences_fk_epic.rb
@@ -7,7 +7,7 @@ class BoardsEpicUserPreferencesFkEpic < ActiveRecord::Migration[6.0]
def up
with_lock_retries do
- add_foreign_key :boards_epic_user_preferences, :epics, column: :epic_id, on_delete: :cascade # rubocop: disable Migration/AddConcurrentForeignKey
+ add_foreign_key :boards_epic_user_preferences, :epics, column: :epic_id, on_delete: :cascade
end
end
diff --git a/db/migrate/20200827060911_add_merge_request_foreign_key_to_merge_request_reviewers.rb b/db/migrate/20200827060911_add_merge_request_foreign_key_to_merge_request_reviewers.rb
index dc3356375fd..73d0eea9819 100644
--- a/db/migrate/20200827060911_add_merge_request_foreign_key_to_merge_request_reviewers.rb
+++ b/db/migrate/20200827060911_add_merge_request_foreign_key_to_merge_request_reviewers.rb
@@ -10,7 +10,7 @@ class AddMergeRequestForeignKeyToMergeRequestReviewers < ActiveRecord::Migration
def up
with_lock_retries do
- add_foreign_key :merge_request_reviewers, :merge_requests, column: :merge_request_id, on_delete: :cascade # rubocop:disable Migration/AddConcurrentForeignKey
+ add_foreign_key :merge_request_reviewers, :merge_requests, column: :merge_request_id, on_delete: :cascade
end
end
diff --git a/db/migrate/20200827060932_add_user_foreign_key_to_merge_request_reviewers.rb b/db/migrate/20200827060932_add_user_foreign_key_to_merge_request_reviewers.rb
index d6c6985a668..5463c3d9846 100644
--- a/db/migrate/20200827060932_add_user_foreign_key_to_merge_request_reviewers.rb
+++ b/db/migrate/20200827060932_add_user_foreign_key_to_merge_request_reviewers.rb
@@ -10,7 +10,7 @@ class AddUserForeignKeyToMergeRequestReviewers < ActiveRecord::Migration[6.0]
def up
with_lock_retries do
- add_foreign_key :merge_request_reviewers, :users, column: :user_id, on_delete: :cascade # rubocop:disable Migration/AddConcurrentForeignKey
+ add_foreign_key :merge_request_reviewers, :users, column: :user_id, on_delete: :cascade
end
end
diff --git a/db/migrate/20200828155134_add_foreign_key_on_scan_id_to_security_scans.rb b/db/migrate/20200828155134_add_foreign_key_on_scan_id_to_security_scans.rb
index 612bd79a282..9d815cc75dc 100644
--- a/db/migrate/20200828155134_add_foreign_key_on_scan_id_to_security_scans.rb
+++ b/db/migrate/20200828155134_add_foreign_key_on_scan_id_to_security_scans.rb
@@ -7,7 +7,7 @@ class AddForeignKeyOnScanIdToSecurityScans < ActiveRecord::Migration[6.0]
def up
with_lock_retries do
- add_foreign_key :security_findings, :security_scans, column: :scan_id, on_delete: :cascade # rubocop:disable Migration/AddConcurrentForeignKey
+ add_foreign_key :security_findings, :security_scans, column: :scan_id, on_delete: :cascade
end
end
diff --git a/db/migrate/20200828155205_add_foreign_key_on_scanner_id_to_vulnerability_scanners.rb b/db/migrate/20200828155205_add_foreign_key_on_scanner_id_to_vulnerability_scanners.rb
index eb3e878c8be..015e83b59b1 100644
--- a/db/migrate/20200828155205_add_foreign_key_on_scanner_id_to_vulnerability_scanners.rb
+++ b/db/migrate/20200828155205_add_foreign_key_on_scanner_id_to_vulnerability_scanners.rb
@@ -7,7 +7,7 @@ class AddForeignKeyOnScannerIdToVulnerabilityScanners < ActiveRecord::Migration[
def up
with_lock_retries do
- add_foreign_key :security_findings, :vulnerability_scanners, column: :scanner_id, on_delete: :cascade # rubocop:disable Migration/AddConcurrentForeignKey
+ add_foreign_key :security_findings, :vulnerability_scanners, column: :scanner_id, on_delete: :cascade
end
end
diff --git a/db/migrate/20200905013247_add_golang_package_max_file_size_to_plan_limits.rb b/db/migrate/20200905013247_add_golang_package_max_file_size_to_plan_limits.rb
new file mode 100644
index 00000000000..0a6d0ce7339
--- /dev/null
+++ b/db/migrate/20200905013247_add_golang_package_max_file_size_to_plan_limits.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+class AddGolangPackageMaxFileSizeToPlanLimits < ActiveRecord::Migration[6.0]
+ DOWNTIME = false
+
+ def change
+ add_column(:plan_limits, :golang_max_file_size, :bigint, default: 100.megabytes, null: false)
+ end
+end
diff --git a/db/migrate/20200907092610_add_user_id_to_group_import_states.rb b/db/migrate/20200907092610_add_user_id_to_group_import_states.rb
new file mode 100644
index 00000000000..231bafeabdb
--- /dev/null
+++ b/db/migrate/20200907092610_add_user_id_to_group_import_states.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+class AddUserIdToGroupImportStates < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ unless column_exists?(:group_import_states, :user_id)
+ with_lock_retries do
+ add_column :group_import_states, :user_id, :bigint
+ end
+ end
+
+ add_concurrent_foreign_key :group_import_states, :users, column: :user_id, on_delete: :cascade
+ add_concurrent_index :group_import_states, :user_id, where: 'user_id IS NOT NULL', name: 'index_group_import_states_on_user_id'
+ end
+
+ def down
+ with_lock_retries do
+ remove_column :group_import_states, :user_id
+ end
+ end
+end
diff --git a/db/migrate/20200908094810_add_new_setting_to_namespace_setting.rb b/db/migrate/20200908094810_add_new_setting_to_namespace_setting.rb
new file mode 100644
index 00000000000..27fc93a2c53
--- /dev/null
+++ b/db/migrate/20200908094810_add_new_setting_to_namespace_setting.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+class AddNewSettingToNamespaceSetting < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ def up
+ with_lock_retries do
+ add_column :namespace_settings, :allow_mfa_for_subgroups, :boolean, default: true, null: false
+ end
+ end
+
+ def down
+ with_lock_retries do
+ remove_column :namespace_settings, :allow_mfa_for_subgroups
+ end
+ end
+end
diff --git a/db/migrate/20200909040555_create_package_events.rb b/db/migrate/20200909040555_create_package_events.rb
new file mode 100644
index 00000000000..000ff051a7c
--- /dev/null
+++ b/db/migrate/20200909040555_create_package_events.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+class CreatePackageEvents < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ def change
+ create_table :packages_events do |t|
+ t.integer :event_type, null: false, limit: 2
+ t.integer :event_scope, null: false, limit: 2
+ t.integer :originator_type, null: false, limit: 2
+ t.bigint :originator
+ t.datetime_with_timezone :created_at, null: false
+
+ t.references :package, primary_key: false, default: nil, index: true, foreign_key: { to_table: :packages_packages, on_delete: :nullify }, type: :bigint
+ end
+ end
+end
diff --git a/db/migrate/20200909083339_add_change_reviewer_merge_request_to_notification_settings.rb b/db/migrate/20200909083339_add_change_reviewer_merge_request_to_notification_settings.rb
new file mode 100644
index 00000000000..7024cc4a263
--- /dev/null
+++ b/db/migrate/20200909083339_add_change_reviewer_merge_request_to_notification_settings.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+class AddChangeReviewerMergeRequestToNotificationSettings < ActiveRecord::Migration[6.0]
+ DOWNTIME = false
+
+ def change
+ add_column :notification_settings, :change_reviewer_merge_request, :boolean
+ end
+end
diff --git a/db/migrate/20200911121027_add_pages_deployment_project_foreign_key.rb b/db/migrate/20200911121027_add_pages_deployment_project_foreign_key.rb
index 70418881c4f..665b9de9230 100644
--- a/db/migrate/20200911121027_add_pages_deployment_project_foreign_key.rb
+++ b/db/migrate/20200911121027_add_pages_deployment_project_foreign_key.rb
@@ -7,7 +7,7 @@ class AddPagesDeploymentProjectForeignKey < ActiveRecord::Migration[6.0]
def up
with_lock_retries do
- add_foreign_key :pages_deployments, :projects, column: :project_id, on_delete: :cascade # rubocop:disable Migration/AddConcurrentForeignKey
+ add_foreign_key :pages_deployments, :projects, column: :project_id, on_delete: :cascade
end
end
diff --git a/db/migrate/20200911121048_add_pages_deployment_ci_build_foreign_key.rb b/db/migrate/20200911121048_add_pages_deployment_ci_build_foreign_key.rb
index ece721d88d5..83f38b2fae3 100644
--- a/db/migrate/20200911121048_add_pages_deployment_ci_build_foreign_key.rb
+++ b/db/migrate/20200911121048_add_pages_deployment_ci_build_foreign_key.rb
@@ -7,7 +7,7 @@ class AddPagesDeploymentCiBuildForeignKey < ActiveRecord::Migration[6.0]
def up
with_lock_retries do
- add_foreign_key :pages_deployments, :ci_builds, column: :ci_build_id, on_delete: :nullify # rubocop:disable Migration/AddConcurrentForeignKey
+ add_foreign_key :pages_deployments, :ci_builds, column: :ci_build_id, on_delete: :nullify
end
end
diff --git a/db/migrate/20200912152943_rename_admin_notification_email_application_setting.rb b/db/migrate/20200912152943_rename_admin_notification_email_application_setting.rb
new file mode 100644
index 00000000000..b469099014d
--- /dev/null
+++ b/db/migrate/20200912152943_rename_admin_notification_email_application_setting.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+class RenameAdminNotificationEmailApplicationSetting < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ rename_column_concurrently :application_settings, :admin_notification_email, :abuse_notification_email
+ end
+
+ def down
+ undo_rename_column_concurrently :application_settings, :admin_notification_email, :abuse_notification_email
+ end
+end
diff --git a/db/migrate/20200912193210_add_scheduling_issues_temp_indexes.rb b/db/migrate/20200912193210_add_scheduling_issues_temp_indexes.rb
new file mode 100644
index 00000000000..bc2b8d4ce97
--- /dev/null
+++ b/db/migrate/20200912193210_add_scheduling_issues_temp_indexes.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+class AddSchedulingIssuesTempIndexes < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index :issue_links, [:source_id], where: 'link_type = 1', name: 'tmp_idx_blocking_type_links'
+ add_concurrent_index :issue_links, [:target_id], where: 'link_type = 2', name: 'tmp_idx_blocked_by_type_links'
+ add_concurrent_index :issues, :id, where: '(state_id = 1 AND blocking_issues_count = 0)', name: 'tmp_idx_index_issues_with_outdate_blocking_count'
+ end
+
+ def down
+ remove_concurrent_index_by_name(:issue_links, 'tmp_idx_blocking_type_links')
+ remove_concurrent_index_by_name(:issue_links, 'tmp_idx_blocked_by_type_links')
+ remove_concurrent_index_by_name(:issues, 'tmp_idx_index_issues_with_outdate_blocking_count')
+ end
+end
diff --git a/db/migrate/20200914070140_add_expiration_policy_started_at_to_container_repositories.rb b/db/migrate/20200914070140_add_expiration_policy_started_at_to_container_repositories.rb
new file mode 100644
index 00000000000..fa787fe98b0
--- /dev/null
+++ b/db/migrate/20200914070140_add_expiration_policy_started_at_to_container_repositories.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+class AddExpirationPolicyStartedAtToContainerRepositories < ActiveRecord::Migration[6.0]
+ DOWNTIME = false
+
+ def up
+ add_column(:container_repositories, :expiration_policy_started_at, :datetime_with_timezone)
+ end
+
+ def down
+ remove_column(:container_repositories, :expiration_policy_started_at)
+ end
+end
diff --git a/db/migrate/20200915134004_add_indices_to_approval_project_rules.rb b/db/migrate/20200915134004_add_indices_to_approval_project_rules.rb
new file mode 100644
index 00000000000..b7b0e1da2cb
--- /dev/null
+++ b/db/migrate/20200915134004_add_indices_to_approval_project_rules.rb
@@ -0,0 +1,25 @@
+# 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 AddIndicesToApprovalProjectRules < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ RULE_TYPE_INDEX_NAME = 'index_approval_project_rules_on_id_with_regular_type'
+ RULE_ID_INDEX_NAME = 'index_approval_project_rules_users_on_approval_project_rule_id'
+
+ def up
+ add_concurrent_index :approval_project_rules, :id, where: 'rule_type = 0', name: RULE_TYPE_INDEX_NAME
+ add_concurrent_index :approval_project_rules_users, :approval_project_rule_id, name: RULE_ID_INDEX_NAME
+ end
+
+ def down
+ remove_concurrent_index :approval_project_rules, :id, where: 'rule_type = 0', name: RULE_TYPE_INDEX_NAME
+ remove_concurrent_index :approval_project_rules_users, :approval_project_rule_id, name: RULE_ID_INDEX_NAME
+ end
+end
diff --git a/db/migrate/20200916135044_add_state_id_index_to_merge_requests.rb b/db/migrate/20200916135044_add_state_id_index_to_merge_requests.rb
new file mode 100644
index 00000000000..bec162ff888
--- /dev/null
+++ b/db/migrate/20200916135044_add_state_id_index_to_merge_requests.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+class AddStateIdIndexToMergeRequests < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index :merge_requests, [:target_project_id, :iid, :state_id], name: :index_merge_requests_on_target_project_id_and_iid_and_state_id
+ end
+
+ def down
+ remove_concurrent_index :merge_requests, [:target_project_id, :iid, :state_id], name: :index_merge_requests_on_target_project_id_and_iid_and_state_id
+ end
+end
diff --git a/db/migrate/20200916151442_add_result_index_to_authentication_events.rb b/db/migrate/20200916151442_add_result_index_to_authentication_events.rb
new file mode 100644
index 00000000000..13b0521038e
--- /dev/null
+++ b/db/migrate/20200916151442_add_result_index_to_authentication_events.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+class AddResultIndexToAuthenticationEvents < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+ INDEX_NAME = 'index_authentication_events_on_provider_user_id_created_at'
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index :authentication_events, [:provider, :user_id, :created_at], where: 'result = 1', name: INDEX_NAME
+ end
+
+ def down
+ remove_concurrent_index_by_name :authentication_events, INDEX_NAME
+ end
+end
diff --git a/db/migrate/20200916165232_add_debian_max_file_size_to_plan_limits.rb b/db/migrate/20200916165232_add_debian_max_file_size_to_plan_limits.rb
new file mode 100644
index 00000000000..9a91a5d2195
--- /dev/null
+++ b/db/migrate/20200916165232_add_debian_max_file_size_to_plan_limits.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+class AddDebianMaxFileSizeToPlanLimits < ActiveRecord::Migration[6.0]
+ DOWNTIME = false
+
+ def change
+ add_column :plan_limits, :debian_max_file_size, :bigint, default: 3.gigabytes, null: false
+ end
+end
diff --git a/db/migrate/20200917121650_add_help_page_documentation_url_to_application_settings.rb b/db/migrate/20200917121650_add_help_page_documentation_url_to_application_settings.rb
new file mode 100644
index 00000000000..21259b633b1
--- /dev/null
+++ b/db/migrate/20200917121650_add_help_page_documentation_url_to_application_settings.rb
@@ -0,0 +1,12 @@
+# frozen_string_literal: true
+
+class AddHelpPageDocumentationUrlToApplicationSettings < ActiveRecord::Migration[6.0]
+ DOWNTIME = false
+
+ # rubocop:disable Migration/AddLimitToTextColumns
+ # limit is added in 20200921113722_add_text_limit_to_help_page_documentation_url.rb
+ def change
+ add_column :application_settings, :help_page_documentation_base_url, :text
+ end
+ # rubocop:enable Migration/AddLimitToTextColumns
+end
diff --git a/db/migrate/20200919200318_add_default_branch_name_to_namespace_settings.rb b/db/migrate/20200919200318_add_default_branch_name_to_namespace_settings.rb
new file mode 100644
index 00000000000..c8c856c7533
--- /dev/null
+++ b/db/migrate/20200919200318_add_default_branch_name_to_namespace_settings.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class AddDefaultBranchNameToNamespaceSettings < ActiveRecord::Migration[6.0]
+ DOWNTIME = false
+
+ # rubocop:disable Migration/AddLimitToTextColumns
+
+ # limit is added in 20200919204155_add_text_limit_to_namespace_settings_default_branch_name
+ #
+ def change
+ add_column :namespace_settings, :default_branch_name, :text
+ end
+
+ # rubocop:enable Migration/AddLimitToTextColumns
+end
diff --git a/db/migrate/20200919204155_add_text_limit_to_namespace_settings_default_branch_name.rb b/db/migrate/20200919204155_add_text_limit_to_namespace_settings_default_branch_name.rb
new file mode 100644
index 00000000000..174a1a9c556
--- /dev/null
+++ b/db/migrate/20200919204155_add_text_limit_to_namespace_settings_default_branch_name.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+class AddTextLimitToNamespaceSettingsDefaultBranchName < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ add_text_limit :namespace_settings, :default_branch_name, 255
+ end
+
+ def down
+ # Down is required as `add_text_limit` is not reversible
+ #
+ remove_text_limit :namespace_settings, :default_branch_name
+ end
+end
diff --git a/db/migrate/20200921093826_add_index_to_user_preferences.rb b/db/migrate/20200921093826_add_index_to_user_preferences.rb
new file mode 100644
index 00000000000..78b04eb7a83
--- /dev/null
+++ b/db/migrate/20200921093826_add_index_to_user_preferences.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+class AddIndexToUserPreferences < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index :user_preferences, :gitpod_enabled, name: :index_user_preferences_on_gitpod_enabled
+ end
+
+ def down
+ remove_concurrent_index :user_preferences, :gitpod_enabled, name: :index_user_preferences_on_gitpod_enabled
+ end
+end
diff --git a/db/migrate/20200921113722_add_text_limit_to_help_page_documentation_url.rb b/db/migrate/20200921113722_add_text_limit_to_help_page_documentation_url.rb
new file mode 100644
index 00000000000..a262ea559a5
--- /dev/null
+++ b/db/migrate/20200921113722_add_text_limit_to_help_page_documentation_url.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+class AddTextLimitToHelpPageDocumentationUrl < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ add_text_limit :application_settings, :help_page_documentation_base_url, 255
+ end
+
+ def down
+ remove_text_limit :application_settings, :help_page_documentation_base_url
+ end
+end
diff --git a/db/migrate/20200921130028_add_pages_deployment_id_to_pages_metadata.rb b/db/migrate/20200921130028_add_pages_deployment_id_to_pages_metadata.rb
new file mode 100644
index 00000000000..395ce43d8ac
--- /dev/null
+++ b/db/migrate/20200921130028_add_pages_deployment_id_to_pages_metadata.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+class AddPagesDeploymentIdToPagesMetadata < ActiveRecord::Migration[6.0]
+ DOWNTIME = false
+
+ def change
+ add_column :project_pages_metadata, :pages_deployment_id, :bigint
+ end
+end
diff --git a/db/migrate/20200921131313_add_foreign_key_to_pages_deployment_id_in_project_pages_metadata.rb b/db/migrate/20200921131313_add_foreign_key_to_pages_deployment_id_in_project_pages_metadata.rb
new file mode 100644
index 00000000000..8611f3ab943
--- /dev/null
+++ b/db/migrate/20200921131313_add_foreign_key_to_pages_deployment_id_in_project_pages_metadata.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+class AddForeignKeyToPagesDeploymentIdInProjectPagesMetadata < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+ INDEX_NAME = 'index_project_pages_metadata_on_pages_deployment_id'
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index(:project_pages_metadata, :pages_deployment_id, name: INDEX_NAME)
+ add_concurrent_foreign_key :project_pages_metadata, :pages_deployments, column: :pages_deployment_id, on_delete: :nullify
+ end
+
+ def down
+ remove_foreign_key_if_exists :project_pages_metadata, column: :pages_deployment_id
+ remove_concurrent_index_by_name(:project_pages_metadata, INDEX_NAME)
+ end
+end
diff --git a/db/migrate/20200921203231_remove_duplicate_cluster_agents_index.rb b/db/migrate/20200921203231_remove_duplicate_cluster_agents_index.rb
new file mode 100644
index 00000000000..3f073e32d84
--- /dev/null
+++ b/db/migrate/20200921203231_remove_duplicate_cluster_agents_index.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+class RemoveDuplicateClusterAgentsIndex < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+ INDEX = 'index_cluster_agents_on_project_id'
+
+ disable_ddl_transaction!
+
+ def up
+ remove_concurrent_index_by_name :cluster_agents, INDEX
+ end
+
+ def down
+ add_concurrent_index :cluster_agents, :project_id, name: INDEX
+ end
+end
diff --git a/db/migrate/20200922052316_create_issue_email_participants.rb b/db/migrate/20200922052316_create_issue_email_participants.rb
new file mode 100644
index 00000000000..a8aeb9d9a5a
--- /dev/null
+++ b/db/migrate/20200922052316_create_issue_email_participants.rb
@@ -0,0 +1,32 @@
+# frozen_string_literal: true
+
+class CreateIssueEmailParticipants < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ unless table_exists?(:issue_email_participants)
+ with_lock_retries do
+ create_table :issue_email_participants do |t|
+ t.references :issue, index: false, null: false, foreign_key: { on_delete: :cascade }
+ t.datetime_with_timezone :created_at, null: false
+ t.datetime_with_timezone :updated_at, null: false
+ t.text :email, null: false
+
+ t.index [:issue_id, :email], unique: true
+ end
+ end
+
+ add_text_limit(:issue_email_participants, :email, 255)
+ end
+ end
+
+ def down
+ with_lock_retries do
+ drop_table :issue_email_participants
+ end
+ end
+end
diff --git a/db/migrate/20200922075244_add_compliance_framework_model.rb b/db/migrate/20200922075244_add_compliance_framework_model.rb
new file mode 100644
index 00000000000..376482d9005
--- /dev/null
+++ b/db/migrate/20200922075244_add_compliance_framework_model.rb
@@ -0,0 +1,32 @@
+# frozen_string_literal: true
+
+class AddComplianceFrameworkModel < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ unless table_exists?(:compliance_management_frameworks)
+ with_lock_retries do
+ create_table :compliance_management_frameworks do |t|
+ t.references :group, foreign_key: { to_table: :namespaces, on_delete: :cascade }, null: false, index: false
+ t.text :name, null: false
+ t.text :description, null: false
+ t.text :color, null: false
+ t.index [:group_id, :name], unique: true
+ end
+ end
+ end
+
+ add_text_limit :compliance_management_frameworks, :name, 255
+ add_text_limit :compliance_management_frameworks, :description, 255
+ add_text_limit :compliance_management_frameworks, :color, 10
+ end
+
+ def down
+ with_lock_retries do
+ drop_table :compliance_management_frameworks
+ end
+ end
+end
diff --git a/db/migrate/20200922093004_add_postgres_index_view.rb b/db/migrate/20200922093004_add_postgres_index_view.rb
new file mode 100644
index 00000000000..c16eae4dd0b
--- /dev/null
+++ b/db/migrate/20200922093004_add_postgres_index_view.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+class AddPostgresIndexView < ActiveRecord::Migration[6.0]
+ DOWNTIME = false
+
+ def up
+ execute(<<~SQL)
+ CREATE VIEW postgres_indexes AS
+ SELECT
+ pg_namespace.nspname || '.' || pg_class.relname as identifier,
+ pg_index.indexrelid,
+ pg_namespace.nspname as schema,
+ pg_class.relname as name,
+ pg_index.indisunique as unique,
+ pg_index.indisvalid as valid_index,
+ pg_class.relispartition as partitioned,
+ pg_index.indisexclusion as exclusion,
+ pg_indexes.indexdef as definition,
+ pg_relation_size(pg_class.oid) as ondisk_size_bytes
+ FROM pg_index
+ INNER JOIN pg_class ON pg_class.oid = pg_index.indexrelid
+ INNER JOIN pg_namespace ON pg_class.relnamespace = pg_namespace.oid
+ INNER JOIN pg_indexes ON pg_class.relname = pg_indexes.indexname
+ WHERE pg_namespace.nspname <> 'pg_catalog'
+ SQL
+ end
+
+ def down
+ execute(<<~SQL)
+ DROP VIEW postgres_indexes
+ SQL
+ end
+end
diff --git a/db/migrate/20200922133949_create_bulk_import.rb b/db/migrate/20200922133949_create_bulk_import.rb
new file mode 100644
index 00000000000..29d770d13ff
--- /dev/null
+++ b/db/migrate/20200922133949_create_bulk_import.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+class CreateBulkImport < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ def up
+ with_lock_retries do
+ create_table :bulk_imports do |t|
+ t.references :user, type: :integer, index: true, null: false, foreign_key: { on_delete: :cascade }
+
+ t.integer :source_type, null: false, limit: 2
+ t.integer :status, null: false, limit: 2
+
+ t.timestamps_with_timezone
+ end
+ end
+ end
+
+ def down
+ with_lock_retries do
+ drop_table :bulk_imports
+ end
+ end
+end
diff --git a/db/migrate/20200923071622_add_description_to_requirements.rb b/db/migrate/20200923071622_add_description_to_requirements.rb
new file mode 100644
index 00000000000..b4b1250c10a
--- /dev/null
+++ b/db/migrate/20200923071622_add_description_to_requirements.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class AddDescriptionToRequirements < ActiveRecord::Migration[6.0]
+ DOWNTIME = false
+
+ # rubocop:disable Migration/AddLimitToTextColumns
+ # limit for description is added in 20200923071644_add_text_limit_to_requirements_description
+ # for description_html limit is not set because it's for caching purposes and
+ # its value is generated from `description`
+ def change
+ add_column :requirements, :description, :text
+ add_column :requirements, :description_html, :text
+ end
+ # rubocop:enable Migration/AddLimitToTextColumns
+end
diff --git a/db/migrate/20200923071644_add_text_limit_to_requirements_description.rb b/db/migrate/20200923071644_add_text_limit_to_requirements_description.rb
new file mode 100644
index 00000000000..0172d6bbba3
--- /dev/null
+++ b/db/migrate/20200923071644_add_text_limit_to_requirements_description.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+class AddTextLimitToRequirementsDescription < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ add_text_limit :requirements, :description, 10_000
+ end
+
+ def down
+ remove_text_limit :requirements, :description
+ end
+end
diff --git a/db/migrate/20200923102312_update_programming_language_colors.rb b/db/migrate/20200923102312_update_programming_language_colors.rb
new file mode 100644
index 00000000000..37233bd3148
--- /dev/null
+++ b/db/migrate/20200923102312_update_programming_language_colors.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+require 'yaml'
+
+class UpdateProgrammingLanguageColors < ActiveRecord::Migration[6.0]
+ DOWNTIME = false
+
+ class ProgrammingLanguage < ActiveRecord::Base; end
+
+ def up
+ YAML.load_file("vendor/languages.yml").each do |name, metadata|
+ color = metadata["color"]
+ next unless color.present?
+
+ ProgrammingLanguage.where(name: name).update(color: color)
+ end
+ end
+
+ def down
+ # noop
+ end
+end
diff --git a/db/migrate/20200923130057_remove_tmp_container_scanning_index.rb b/db/migrate/20200923130057_remove_tmp_container_scanning_index.rb
new file mode 100644
index 00000000000..e9ab6f9ff15
--- /dev/null
+++ b/db/migrate/20200923130057_remove_tmp_container_scanning_index.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+class RemoveTmpContainerScanningIndex < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+ INDEX_NAME = 'tmp_index_for_fixing_inconsistent_vulnerability_occurrences'
+ disable_ddl_transaction!
+
+ def up
+ remove_concurrent_index_by_name(:vulnerability_occurrences, INDEX_NAME)
+ end
+
+ def down
+ # report_type: 2 container scanning
+ add_concurrent_index(:vulnerability_occurrences, :id,
+ where: "LENGTH(location_fingerprint) = 40 AND report_type = 2",
+ name: INDEX_NAME)
+ end
+end
diff --git a/db/migrate/20200923140404_add_postgres_reindex_actions_table.rb b/db/migrate/20200923140404_add_postgres_reindex_actions_table.rb
new file mode 100644
index 00000000000..ed37e44e201
--- /dev/null
+++ b/db/migrate/20200923140404_add_postgres_reindex_actions_table.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+class AddPostgresReindexActionsTable < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ create_table :postgres_reindex_actions, if_not_exists: true do |t|
+ t.datetime_with_timezone :action_start, null: false
+ t.datetime_with_timezone :action_end
+ t.bigint :ondisk_size_bytes_start, null: false
+ t.bigint :ondisk_size_bytes_end
+ t.integer :state, limit: 2, null: false, default: 0
+ t.text :index_identifier, null: false, index: true
+ end
+
+ add_text_limit(:postgres_reindex_actions, :index_identifier, 255)
+ end
+
+ def down
+ drop_table :postgres_reindex_actions
+ end
+end
diff --git a/db/migrate/20200924035825_add_options_to_dast_scanner_profile.rb b/db/migrate/20200924035825_add_options_to_dast_scanner_profile.rb
new file mode 100644
index 00000000000..588ce8fada7
--- /dev/null
+++ b/db/migrate/20200924035825_add_options_to_dast_scanner_profile.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+class AddOptionsToDastScannerProfile < ActiveRecord::Migration[6.0]
+ DOWNTIME = false
+
+ PASSIVE_SCAN_ENUM_VALUE = 1
+
+ def change
+ add_column :dast_scanner_profiles, :scan_type, :integer, limit: 2, default: PASSIVE_SCAN_ENUM_VALUE, null: false
+ add_column :dast_scanner_profiles, :use_ajax_spider, :boolean, default: false, null: false
+ add_column :dast_scanner_profiles, :show_debug_messages, :boolean, default: false, null: false
+ end
+end
diff --git a/db/migrate/20200925112104_create_bulk_import_configurations.rb b/db/migrate/20200925112104_create_bulk_import_configurations.rb
new file mode 100644
index 00000000000..b894cdeefbc
--- /dev/null
+++ b/db/migrate/20200925112104_create_bulk_import_configurations.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+class CreateBulkImportConfigurations < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ create_table :bulk_import_configurations, if_not_exists: true do |t|
+ t.references :bulk_import, type: :integer, index: true, null: false, foreign_key: { on_delete: :cascade }
+
+ t.text :encrypted_url # rubocop: disable Migration/AddLimitToTextColumns
+ t.text :encrypted_url_iv # rubocop: disable Migration/AddLimitToTextColumns
+
+ t.text :encrypted_access_token # rubocop: disable Migration/AddLimitToTextColumns
+ t.text :encrypted_access_token_iv # rubocop: disable Migration/AddLimitToTextColumns
+
+ t.timestamps_with_timezone
+ end
+ end
+
+ def down
+ drop_table :bulk_import_configurations
+ end
+end
diff --git a/db/migrate/20200925114522_create_bulk_import_entities.rb b/db/migrate/20200925114522_create_bulk_import_entities.rb
new file mode 100644
index 00000000000..c78c4aee9ae
--- /dev/null
+++ b/db/migrate/20200925114522_create_bulk_import_entities.rb
@@ -0,0 +1,38 @@
+# frozen_string_literal: true
+
+class CreateBulkImportEntities < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ create_table :bulk_import_entities, if_not_exists: true do |t|
+ t.bigint :bulk_import_id, index: true, null: false
+ t.bigint :parent_id, index: true
+ t.bigint :namespace_id, index: true
+ t.bigint :project_id, index: true
+
+ t.integer :source_type, null: false, limit: 2
+ t.text :source_full_path, null: false
+
+ t.text :destination_name, null: false
+ t.text :destination_namespace, null: false
+
+ t.integer :status, null: false, limit: 2
+ t.text :jid
+
+ t.timestamps_with_timezone
+ end
+
+ add_text_limit(:bulk_import_entities, :source_full_path, 255)
+ add_text_limit(:bulk_import_entities, :destination_name, 255)
+ add_text_limit(:bulk_import_entities, :destination_namespace, 255)
+ add_text_limit(:bulk_import_entities, :jid, 255)
+ end
+
+ def down
+ drop_table :bulk_import_entities
+ end
+end
diff --git a/db/migrate/20200925125321_add_u2f_id_to_webauthn_registration.rb b/db/migrate/20200925125321_add_u2f_id_to_webauthn_registration.rb
new file mode 100644
index 00000000000..8a352fc6e9f
--- /dev/null
+++ b/db/migrate/20200925125321_add_u2f_id_to_webauthn_registration.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+class AddU2fIdToWebauthnRegistration < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ def change
+ add_column :webauthn_registrations, :u2f_registration_id, :integer
+ end
+end
diff --git a/db/migrate/20200925153423_add_bulk_import_foreign_key_to_bulk_import_entities.rb b/db/migrate/20200925153423_add_bulk_import_foreign_key_to_bulk_import_entities.rb
new file mode 100644
index 00000000000..fca4070d990
--- /dev/null
+++ b/db/migrate/20200925153423_add_bulk_import_foreign_key_to_bulk_import_entities.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+class AddBulkImportForeignKeyToBulkImportEntities < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_foreign_key :bulk_import_entities, :bulk_imports, column: :bulk_import_id, on_delete: :cascade
+ end
+
+ def down
+ remove_foreign_key :bulk_import_entities, column: :bulk_import_id
+ end
+end
diff --git a/db/migrate/20200925193815_add_parent_foreign_key_to_bulk_import_entities.rb b/db/migrate/20200925193815_add_parent_foreign_key_to_bulk_import_entities.rb
new file mode 100644
index 00000000000..37e38c384b8
--- /dev/null
+++ b/db/migrate/20200925193815_add_parent_foreign_key_to_bulk_import_entities.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+class AddParentForeignKeyToBulkImportEntities < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_foreign_key :bulk_import_entities, :bulk_import_entities, column: :parent_id, on_delete: :cascade
+ end
+
+ def down
+ remove_foreign_key :bulk_import_entities, column: :parent_id
+ end
+end
diff --git a/db/migrate/20200925193906_add_namespace_foreign_key_to_bulk_import_entities.rb b/db/migrate/20200925193906_add_namespace_foreign_key_to_bulk_import_entities.rb
new file mode 100644
index 00000000000..13212395488
--- /dev/null
+++ b/db/migrate/20200925193906_add_namespace_foreign_key_to_bulk_import_entities.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+class AddNamespaceForeignKeyToBulkImportEntities < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_foreign_key :bulk_import_entities, :namespaces, column: :namespace_id
+ end
+
+ def down
+ with_lock_retries do
+ remove_foreign_key :bulk_import_entities, column: :namespace_id
+ end
+ end
+end
diff --git a/db/migrate/20200925194006_add_project_foreign_key_to_bulk_import_entities.rb b/db/migrate/20200925194006_add_project_foreign_key_to_bulk_import_entities.rb
new file mode 100644
index 00000000000..975f2b1ef4a
--- /dev/null
+++ b/db/migrate/20200925194006_add_project_foreign_key_to_bulk_import_entities.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+class AddProjectForeignKeyToBulkImportEntities < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_foreign_key :bulk_import_entities, :projects, column: :project_id
+ end
+
+ def down
+ with_lock_retries do
+ remove_foreign_key :bulk_import_entities, column: :project_id
+ end
+ end
+end
diff --git a/db/migrate/20200927224750_add_incident_issue_type_index_to_issues.rb b/db/migrate/20200927224750_add_incident_issue_type_index_to_issues.rb
new file mode 100644
index 00000000000..ed4dd5b9cc1
--- /dev/null
+++ b/db/migrate/20200927224750_add_incident_issue_type_index_to_issues.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+class AddIncidentIssueTypeIndexToIssues < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ INCIDENT_ISSUE_TYPE = 1
+ INDEX_NAME = 'index_issues_project_id_issue_type_incident'
+
+ def up
+ add_concurrent_index :issues, :project_id, where: "issue_type = #{INCIDENT_ISSUE_TYPE}", name: INDEX_NAME
+ end
+
+ def down
+ remove_concurrent_index_by_name(:issues, INDEX_NAME)
+ end
+end
diff --git a/db/migrate/20200928095732_add_state_to_dast_site_validation.rb b/db/migrate/20200928095732_add_state_to_dast_site_validation.rb
new file mode 100644
index 00000000000..7adeef54d71
--- /dev/null
+++ b/db/migrate/20200928095732_add_state_to_dast_site_validation.rb
@@ -0,0 +1,12 @@
+# frozen_string_literal: true
+
+class AddStateToDastSiteValidation < ActiveRecord::Migration[6.0]
+ DOWNTIME = false
+
+ # rubocop:disable Migration/AddLimitToTextColumns
+ # limit is added in 20200928100408_add_text_limit_to_dast_site_validation_state.rb
+ def change
+ add_column :dast_site_validations, :state, :text, default: :pending, null: false
+ end
+ # rubocop:enable Migration/AddLimitToTextColumns
+end
diff --git a/db/migrate/20200928100408_add_text_limit_to_dast_site_validation_state.rb b/db/migrate/20200928100408_add_text_limit_to_dast_site_validation_state.rb
new file mode 100644
index 00000000000..18bf7ee4bdc
--- /dev/null
+++ b/db/migrate/20200928100408_add_text_limit_to_dast_site_validation_state.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+class AddTextLimitToDastSiteValidationState < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ add_text_limit :dast_site_validations, :state, 255
+ end
+
+ def down
+ remove_text_limit :dast_site_validations, :state
+ end
+end
diff --git a/db/migrate/20200928125258_add_foreign_key_to_u2f_reg_id_in_webauthn_regs.rb b/db/migrate/20200928125258_add_foreign_key_to_u2f_reg_id_in_webauthn_regs.rb
new file mode 100644
index 00000000000..b76b826658e
--- /dev/null
+++ b/db/migrate/20200928125258_add_foreign_key_to_u2f_reg_id_in_webauthn_regs.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+class AddForeignKeyToU2fRegIdInWebauthnRegs < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+ INDEX_NAME = 'index_webauthn_registrations_on_u2f_registration_id'
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index :webauthn_registrations, :u2f_registration_id, where: 'u2f_registration_id IS NOT NULL', name: INDEX_NAME
+ add_concurrent_foreign_key :webauthn_registrations, :u2f_registrations, column: :u2f_registration_id, on_delete: :cascade
+ end
+
+ def down
+ remove_foreign_key_if_exists :webauthn_registrations, column: :u2f_registration_id
+ remove_concurrent_index_by_name(:webauthn_registrations, INDEX_NAME)
+ end
+end
diff --git a/db/migrate/20200928131934_create_required_code_owners_sections.rb b/db/migrate/20200928131934_create_required_code_owners_sections.rb
new file mode 100644
index 00000000000..f2dfd4007e5
--- /dev/null
+++ b/db/migrate/20200928131934_create_required_code_owners_sections.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+class CreateRequiredCodeOwnersSections < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ with_lock_retries do
+ create_table :required_code_owners_sections, if_not_exists: true do |t|
+ t.references :protected_branch, null: false, foreign_key: { on_delete: :cascade }
+ t.text :name, null: false
+ end
+ end
+
+ add_text_limit :required_code_owners_sections, :name, 1024
+ end
+
+ def down
+ with_lock_retries do
+ drop_table :required_code_owners_sections, if_exists: true
+ end
+ end
+end
diff --git a/db/migrate/20200928164807_add_index_on_vulnerabilities_state_case.rb b/db/migrate/20200928164807_add_index_on_vulnerabilities_state_case.rb
new file mode 100644
index 00000000000..7bfae7377d7
--- /dev/null
+++ b/db/migrate/20200928164807_add_index_on_vulnerabilities_state_case.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+class AddIndexOnVulnerabilitiesStateCase < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+ INDEX_NAME = 'index_vulnerabilities_on_state_case_id'
+ STATE_ORDER_ARRAY_POSITION = 'ARRAY_POSITION(ARRAY[1, 4, 3, 2]::smallint[], state)'
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index :vulnerabilities, "#{STATE_ORDER_ARRAY_POSITION}, id DESC", name: INDEX_NAME
+ add_concurrent_index :vulnerabilities, "#{STATE_ORDER_ARRAY_POSITION} DESC, id DESC", name: "#{INDEX_NAME}_desc"
+ end
+
+ def down
+ remove_concurrent_index_by_name :vulnerabilities, "#{INDEX_NAME}_desc"
+ remove_concurrent_index_by_name :vulnerabilities, INDEX_NAME
+ end
+end
diff --git a/db/migrate/20200928203531_create_alert_management_http_integrations.rb b/db/migrate/20200928203531_create_alert_management_http_integrations.rb
new file mode 100644
index 00000000000..fe13fe400e3
--- /dev/null
+++ b/db/migrate/20200928203531_create_alert_management_http_integrations.rb
@@ -0,0 +1,37 @@
+# frozen_string_literal: true
+
+class CreateAlertManagementHttpIntegrations < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+ UNIQUE_INDEX = 'index_http_integrations_on_active_and_project_and_endpoint'
+
+ disable_ddl_transaction!
+
+ def up
+ create_table :alert_management_http_integrations, if_not_exists: true do |t|
+ t.timestamps_with_timezone
+ t.bigint :project_id, index: true, null: false
+ t.boolean :active, null: false, default: false
+ t.text :encrypted_token, null: false
+ t.text :encrypted_token_iv, null: false
+ t.text :endpoint_identifier, null: false
+ t.text :name, null: false
+ end
+
+ add_text_limit :alert_management_http_integrations, :encrypted_token, 255
+ add_text_limit :alert_management_http_integrations, :encrypted_token_iv, 255
+ add_text_limit :alert_management_http_integrations, :endpoint_identifier, 255
+ add_text_limit :alert_management_http_integrations, :name, 255
+
+ add_index :alert_management_http_integrations,
+ [:active, :project_id, :endpoint_identifier],
+ unique: true,
+ name: UNIQUE_INDEX,
+ where: 'active'
+ end
+
+ def down
+ drop_table :alert_management_http_integrations
+ end
+end
diff --git a/db/migrate/20200928210524_add_http_integrations_project_foreign_key.rb b/db/migrate/20200928210524_add_http_integrations_project_foreign_key.rb
new file mode 100644
index 00000000000..f59a5a0b5bb
--- /dev/null
+++ b/db/migrate/20200928210524_add_http_integrations_project_foreign_key.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+class AddHttpIntegrationsProjectForeignKey < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ def up
+ with_lock_retries do
+ add_foreign_key :alert_management_http_integrations, :projects, column: :project_id, on_delete: :cascade # rubocop:disable Migration/AddConcurrentForeignKey
+ end
+ end
+
+ def down
+ with_lock_retries do
+ remove_foreign_key :alert_management_http_integrations, column: :project_id
+ end
+ end
+end
diff --git a/db/migrate/20200928233632_remove_terraform_state_verification_indexes.rb b/db/migrate/20200928233632_remove_terraform_state_verification_indexes.rb
new file mode 100644
index 00000000000..0256d580cd6
--- /dev/null
+++ b/db/migrate/20200928233632_remove_terraform_state_verification_indexes.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+class RemoveTerraformStateVerificationIndexes < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+ CHECKSUM_INDEX_NAME = "terraform_states_verification_checksum_partial".freeze
+ FAILURE_INDEX_NAME = "terraform_states_verification_failure_partial".freeze
+
+ disable_ddl_transaction!
+
+ def up
+ remove_concurrent_index :terraform_states, :verification_failure, name: FAILURE_INDEX_NAME
+ remove_concurrent_index :terraform_states, :verification_checksum, name: CHECKSUM_INDEX_NAME
+ end
+
+ def down
+ add_concurrent_index :terraform_states, :verification_failure, where: "(verification_failure IS NOT NULL)", name: FAILURE_INDEX_NAME
+ add_concurrent_index :terraform_states, :verification_checksum, where: "(verification_checksum IS NOT NULL)", name: CHECKSUM_INDEX_NAME
+ end
+end
diff --git a/db/migrate/20200929032729_add_sla_minutes_to_project_incident_management_settings.rb b/db/migrate/20200929032729_add_sla_minutes_to_project_incident_management_settings.rb
new file mode 100644
index 00000000000..2848cdf8fcd
--- /dev/null
+++ b/db/migrate/20200929032729_add_sla_minutes_to_project_incident_management_settings.rb
@@ -0,0 +1,10 @@
+# frozen_string_literal: true
+
+class AddSlaMinutesToProjectIncidentManagementSettings < ActiveRecord::Migration[6.0]
+ DOWNTIME = false
+
+ def change
+ add_column :project_incident_management_settings, :sla_timer, :boolean, default: false
+ add_column :project_incident_management_settings, :sla_timer_minutes, :integer
+ end
+end
diff --git a/db/migrate/20200929063159_add_require_admin_approval_after_user_signup_to_application_settings.rb b/db/migrate/20200929063159_add_require_admin_approval_after_user_signup_to_application_settings.rb
new file mode 100644
index 00000000000..92d82757b79
--- /dev/null
+++ b/db/migrate/20200929063159_add_require_admin_approval_after_user_signup_to_application_settings.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+class AddRequireAdminApprovalAfterUserSignupToApplicationSettings < ActiveRecord::Migration[6.0]
+ DOWNTIME = false
+
+ def change
+ add_column :application_settings, :require_admin_approval_after_user_signup, :boolean, default: false, null: false
+ end
+end
diff --git a/db/migrate/20200930094812_update_postgres_indexes_view.rb b/db/migrate/20200930094812_update_postgres_indexes_view.rb
new file mode 100644
index 00000000000..b36ea362e6f
--- /dev/null
+++ b/db/migrate/20200930094812_update_postgres_indexes_view.rb
@@ -0,0 +1,54 @@
+# frozen_string_literal: true
+
+class UpdatePostgresIndexesView < ActiveRecord::Migration[6.0]
+ DOWNTIME = false
+
+ def up
+ execute(<<~SQL)
+ CREATE OR REPLACE VIEW postgres_indexes AS
+ SELECT
+ pg_namespace.nspname || '.' || pg_class.relname as identifier,
+ pg_index.indexrelid,
+ pg_namespace.nspname as schema,
+ pg_class.relname as name,
+ pg_index.indisunique as unique,
+ pg_index.indisvalid as valid_index,
+ pg_class.relispartition as partitioned,
+ pg_index.indisexclusion as exclusion,
+ pg_indexes.indexdef as definition,
+ pg_relation_size(pg_class.oid) as ondisk_size_bytes
+ FROM pg_index
+ INNER JOIN pg_class ON pg_class.oid = pg_index.indexrelid
+ INNER JOIN pg_namespace ON pg_class.relnamespace = pg_namespace.oid
+ INNER JOIN pg_indexes ON pg_class.relname = pg_indexes.indexname
+ WHERE pg_namespace.nspname <> 'pg_catalog'
+ AND pg_namespace.nspname IN (
+ current_schema(),
+ 'gitlab_partitions_dynamic',
+ 'gitlab_partitions_static'
+ )
+ SQL
+ end
+
+ def down
+ execute(<<~SQL)
+ CREATE OR REPLACE VIEW postgres_indexes AS
+ SELECT
+ pg_namespace.nspname || '.' || pg_class.relname as identifier,
+ pg_index.indexrelid,
+ pg_namespace.nspname as schema,
+ pg_class.relname as name,
+ pg_index.indisunique as unique,
+ pg_index.indisvalid as valid_index,
+ pg_class.relispartition as partitioned,
+ pg_index.indisexclusion as exclusion,
+ pg_indexes.indexdef as definition,
+ pg_relation_size(pg_class.oid) as ondisk_size_bytes
+ FROM pg_index
+ INNER JOIN pg_class ON pg_class.oid = pg_index.indexrelid
+ INNER JOIN pg_namespace ON pg_class.relnamespace = pg_namespace.oid
+ INNER JOIN pg_indexes ON pg_class.relname = pg_indexes.indexname
+ WHERE pg_namespace.nspname <> 'pg_catalog'
+ SQL
+ end
+end
diff --git a/db/migrate/20200930131343_add_index_on_project_id_and_sha_to_deployments.rb b/db/migrate/20200930131343_add_index_on_project_id_and_sha_to_deployments.rb
new file mode 100644
index 00000000000..19a536f8f6e
--- /dev/null
+++ b/db/migrate/20200930131343_add_index_on_project_id_and_sha_to_deployments.rb
@@ -0,0 +1,20 @@
+# 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 AddIndexOnProjectIdAndShaToDeployments < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+ DOWNTIME = false
+ INDEX_NAME = 'index_deployments_on_project_id_sha'
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index :deployments, [:project_id, :sha], name: INDEX_NAME
+ end
+
+ def down
+ remove_concurrent_index_by_name(:deployments, INDEX_NAME)
+ end
+end
diff --git a/db/migrate/20200930132319_add_api_fuzzing_to_plan_limits.rb b/db/migrate/20200930132319_add_api_fuzzing_to_plan_limits.rb
new file mode 100644
index 00000000000..9be79974ee4
--- /dev/null
+++ b/db/migrate/20200930132319_add_api_fuzzing_to_plan_limits.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+class AddApiFuzzingToPlanLimits < ActiveRecord::Migration[6.0]
+ DOWNTIME = false
+
+ def change
+ add_column :plan_limits, "ci_max_artifact_size_api_fuzzing", :integer, default: 0, null: false
+ end
+end
diff --git a/db/migrate/20201002012659_add_issuable_sla_table.rb b/db/migrate/20201002012659_add_issuable_sla_table.rb
new file mode 100644
index 00000000000..c43187bf93a
--- /dev/null
+++ b/db/migrate/20201002012659_add_issuable_sla_table.rb
@@ -0,0 +1,12 @@
+# frozen_string_literal: true
+
+class AddIssuableSlaTable < ActiveRecord::Migration[6.0]
+ DOWNTIME = false
+
+ def change
+ create_table :issuable_slas do |t|
+ t.references :issue, null: false, index: { unique: true }, foreign_key: { on_delete: :cascade }
+ t.datetime_with_timezone :due_at, null: false
+ end
+ end
+end
diff --git a/db/migrate/20201004163918_remove_project_id_and_id_index_from_vulnerabilities_table.rb b/db/migrate/20201004163918_remove_project_id_and_id_index_from_vulnerabilities_table.rb
new file mode 100644
index 00000000000..7a59e706bf3
--- /dev/null
+++ b/db/migrate/20201004163918_remove_project_id_and_id_index_from_vulnerabilities_table.rb
@@ -0,0 +1,17 @@
+class RemoveProjectIdAndIdIndexFromVulnerabilitiesTable < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+ INDEX_NAME = 'index_vulnerabilities_on_project_id_and_id'
+
+ disable_ddl_transaction!
+
+ def up
+ Gitlab::BackgroundMigration.steal('PopulateResolvedOnDefaultBranchColumn')
+ remove_concurrent_index_by_name :vulnerabilities, INDEX_NAME
+ end
+
+ def down
+ add_concurrent_index :vulnerabilities, [:project_id, :id], name: INDEX_NAME
+ end
+end
diff --git a/db/migrate/20201005092703_add_namespace_column_to_frameworks.rb b/db/migrate/20201005092703_add_namespace_column_to_frameworks.rb
new file mode 100644
index 00000000000..b7a9866e50b
--- /dev/null
+++ b/db/migrate/20201005092703_add_namespace_column_to_frameworks.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+class AddNamespaceColumnToFrameworks < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+ INDEX_NAME = 'idx_on_compliance_management_frameworks_namespace_id_name'
+
+ disable_ddl_transaction!
+
+ def up
+ unless column_exists?(:compliance_management_frameworks, :namespace_id)
+ add_column(:compliance_management_frameworks, :namespace_id, :integer)
+ end
+
+ add_concurrent_foreign_key(:compliance_management_frameworks, :namespaces, column: :namespace_id, on_delete: :cascade)
+ add_concurrent_index(:compliance_management_frameworks, [:namespace_id, :name], unique: true, name: INDEX_NAME)
+ end
+
+ def down
+ remove_concurrent_index_by_name(:compliance_management_frameworks, INDEX_NAME)
+ remove_foreign_key_if_exists(:compliance_management_frameworks, :namespaces, column: :namespace_id)
+
+ remove_column(:compliance_management_frameworks, :namespace_id)
+ end
+end
diff --git a/db/migrate/20201005092709_remove_compliance_frameworks_group_id_fk.rb b/db/migrate/20201005092709_remove_compliance_frameworks_group_id_fk.rb
new file mode 100644
index 00000000000..88c019c849e
--- /dev/null
+++ b/db/migrate/20201005092709_remove_compliance_frameworks_group_id_fk.rb
@@ -0,0 +1,39 @@
+# frozen_string_literal: true
+
+class RemoveComplianceFrameworksGroupIdFk < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+ INDEX_NAME = 'index_compliance_management_frameworks_on_group_id_and_name'.freeze
+
+ class TmpComplianceFramework < ActiveRecord::Base
+ self.table_name = 'compliance_management_frameworks'
+
+ include EachBatch
+ end
+
+ disable_ddl_transaction!
+
+ def up
+ TmpComplianceFramework.each_batch(of: 100) do |query|
+ query.update_all('namespace_id = group_id') # Copy data in case we rolled back before...
+ end
+
+ change_column_null(:compliance_management_frameworks, :group_id, true)
+
+ remove_foreign_key_if_exists(:compliance_management_frameworks, :namespaces, column: :group_id)
+ remove_concurrent_index_by_name(:compliance_management_frameworks, INDEX_NAME)
+ end
+
+ def down
+ # This is just to make the rollback possible
+ TmpComplianceFramework.each_batch(of: 100) do |query|
+ query.update_all('group_id = namespace_id') # The group_id column is not in used at all
+ end
+
+ change_column_null(:compliance_management_frameworks, :group_id, false)
+
+ add_concurrent_foreign_key(:compliance_management_frameworks, :namespaces, column: :group_id, on_delete: :cascade)
+ add_concurrent_index(:compliance_management_frameworks, [:group_id, :name], unique: true, name: INDEX_NAME)
+ end
+end
diff --git a/db/migrate/20201005092753_add_framework_id_to_project_framework_settings.rb b/db/migrate/20201005092753_add_framework_id_to_project_framework_settings.rb
new file mode 100644
index 00000000000..f9ac12dcfd2
--- /dev/null
+++ b/db/migrate/20201005092753_add_framework_id_to_project_framework_settings.rb
@@ -0,0 +1,34 @@
+# frozen_string_literal: true
+
+class AddFrameworkIdToProjectFrameworkSettings < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ unless column_exists?(:project_compliance_framework_settings, :framework_id)
+ with_lock_retries do
+ add_column(:project_compliance_framework_settings, :framework_id, :bigint)
+ end
+ end
+
+ add_concurrent_index(:project_compliance_framework_settings, :framework_id)
+
+ add_concurrent_foreign_key(
+ :project_compliance_framework_settings,
+ :compliance_management_frameworks,
+ column: :framework_id,
+ on_delete: :cascade
+ )
+ end
+
+ def down
+ remove_foreign_key_if_exists(:project_compliance_framework_settings, :compliance_management_frameworks, column: :framework_id)
+
+ with_lock_retries do
+ remove_column(:project_compliance_framework_settings, :framework_id)
+ end
+ end
+end
diff --git a/db/migrate/20201006014605_add_automatic_purchased_storage_allocation_to_application_settings.rb b/db/migrate/20201006014605_add_automatic_purchased_storage_allocation_to_application_settings.rb
new file mode 100644
index 00000000000..f88bd177b98
--- /dev/null
+++ b/db/migrate/20201006014605_add_automatic_purchased_storage_allocation_to_application_settings.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+class AddAutomaticPurchasedStorageAllocationToApplicationSettings < ActiveRecord::Migration[6.0]
+ DOWNTIME = false
+
+ def change
+ add_column :application_settings, :automatic_purchased_storage_allocation, :boolean, default: false, null: false
+ end
+end
diff --git a/db/migrate/20201007115209_add_lock_version_to_ci_build_trace_chunk.rb b/db/migrate/20201007115209_add_lock_version_to_ci_build_trace_chunk.rb
new file mode 100644
index 00000000000..fdef5e2f52a
--- /dev/null
+++ b/db/migrate/20201007115209_add_lock_version_to_ci_build_trace_chunk.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+class AddLockVersionToCiBuildTraceChunk < ActiveRecord::Migration[6.0]
+ DOWNTIME = false
+
+ def change
+ add_column :ci_build_trace_chunks, :lock_version, :integer, default: 0, null: false
+ end
+end
diff --git a/db/migrate/20201009090954_add_index_with_project_id_to_container_expiration_policies.rb b/db/migrate/20201009090954_add_index_with_project_id_to_container_expiration_policies.rb
new file mode 100644
index 00000000000..ec44d5ddcef
--- /dev/null
+++ b/db/migrate/20201009090954_add_index_with_project_id_to_container_expiration_policies.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+class AddIndexWithProjectIdToContainerExpirationPolicies < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ INDEX_NAME = 'idx_container_exp_policies_on_project_id_next_run_at_enabled'
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index :container_expiration_policies, [:project_id, :next_run_at, :enabled], name: INDEX_NAME
+ end
+
+ def down
+ remove_concurrent_index_by_name :container_expiration_policies, INDEX_NAME
+ end
+end
diff --git a/db/migrate/20201012194936_create_saml_group_links.rb b/db/migrate/20201012194936_create_saml_group_links.rb
new file mode 100644
index 00000000000..d47c383afef
--- /dev/null
+++ b/db/migrate/20201012194936_create_saml_group_links.rb
@@ -0,0 +1,30 @@
+# frozen_string_literal: true
+
+class CreateSamlGroupLinks < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ with_lock_retries do
+ create_table :saml_group_links, if_not_exists: true do |t|
+ t.integer :access_level, null: false, limit: 2
+ t.references :group, index: false, foreign_key: { to_table: :namespaces, on_delete: :cascade }, null: false
+ t.timestamps_with_timezone
+ t.text :saml_group_name, null: false
+
+ t.index [:group_id, :saml_group_name], unique: true
+ end
+ end
+
+ add_text_limit :saml_group_links, :saml_group_name, 255
+ end
+
+ def down
+ with_lock_retries do
+ drop_table :saml_group_links
+ end
+ end
+end
diff --git a/db/migrate/20201014205300_drop_backfill_jira_tracker_deployment_type_jobs.rb b/db/migrate/20201014205300_drop_backfill_jira_tracker_deployment_type_jobs.rb
new file mode 100644
index 00000000000..ea45e82dcc4
--- /dev/null
+++ b/db/migrate/20201014205300_drop_backfill_jira_tracker_deployment_type_jobs.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+class DropBackfillJiraTrackerDeploymentTypeJobs < ActiveRecord::Migration[6.0]
+ DOWNTIME = false
+ DROPPED_JOB_CLASS = 'BackfillJiraTrackerDeploymentType'.freeze
+ QUEUE = 'background_migration'.freeze
+
+ def up
+ sidekiq_queues.each do |queue|
+ queue.each do |job|
+ next unless job.args.first == DROPPED_JOB_CLASS
+
+ job.delete
+ end
+ end
+ end
+
+ def down
+ # no-op
+ end
+
+ def sidekiq_queues
+ [Sidekiq::ScheduledSet.new, Sidekiq::RetrySet.new, Sidekiq::Queue.new(QUEUE)]
+ end
+end
diff --git a/db/post_migrate/20190926180443_schedule_epic_issues_after_epics_move.rb b/db/post_migrate/20190926180443_schedule_epic_issues_after_epics_move.rb
index 86fe0f26681..113b7104209 100644
--- a/db/post_migrate/20190926180443_schedule_epic_issues_after_epics_move.rb
+++ b/db/post_migrate/20190926180443_schedule_epic_issues_after_epics_move.rb
@@ -25,7 +25,7 @@ class ScheduleEpicIssuesAfterEpicsMove < ActiveRecord::Migration[5.2]
Epic.each_batch(of: BATCH_SIZE) do |batch, index|
range = batch.pluck('MIN(id)', 'MAX(id)').first
delay = index * INTERVAL
- BackgroundMigrationWorker.perform_in(delay, MIGRATION, *range)
+ BackgroundMigrationWorker.perform_in(delay, MIGRATION, range)
end
end
diff --git a/db/post_migrate/20200511083541_cleanup_projects_with_missing_namespace.rb b/db/post_migrate/20200511083541_cleanup_projects_with_missing_namespace.rb
index 1ead10a4de6..9e606b2264b 100644
--- a/db/post_migrate/20200511083541_cleanup_projects_with_missing_namespace.rb
+++ b/db/post_migrate/20200511083541_cleanup_projects_with_missing_namespace.rb
@@ -66,8 +66,6 @@ class CleanupProjectsWithMissingNamespace < ActiveRecord::Migration[6.0]
end
def ensure_bio_is_assigned_to_user_details
- return if Feature.disabled?(:migrate_bio_to_user_details, default_enabled: true)
-
user_detail.bio = bio.to_s[0...255]
end
diff --git a/db/post_migrate/20200810191256_remove_pipeline_id_from_test_reports.rb b/db/post_migrate/20200810191256_remove_pipeline_id_from_test_reports.rb
index 4a5e6942371..f99629a921e 100644
--- a/db/post_migrate/20200810191256_remove_pipeline_id_from_test_reports.rb
+++ b/db/post_migrate/20200810191256_remove_pipeline_id_from_test_reports.rb
@@ -13,9 +13,7 @@ class RemovePipelineIdFromTestReports < ActiveRecord::Migration[6.0]
add_column :requirements_management_test_reports, :pipeline_id, :integer
with_lock_retries do
- # rubocop:disable Migration/AddConcurrentForeignKey
add_foreign_key :requirements_management_test_reports, :ci_pipelines, column: :pipeline_id, on_delete: :nullify
- # rubocop:enable Migration/AddConcurrentForeignKey
end
end
end
diff --git a/db/post_migrate/20200901170135_backfill_modified_column_for_approval_merge_request_rules.rb b/db/post_migrate/20200901170135_backfill_modified_column_for_approval_merge_request_rules.rb
new file mode 100644
index 00000000000..9a9866f38ec
--- /dev/null
+++ b/db/post_migrate/20200901170135_backfill_modified_column_for_approval_merge_request_rules.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+class BackfillModifiedColumnForApprovalMergeRequestRules < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::Migrations::BackgroundMigrationHelpers
+
+ disable_ddl_transaction!
+
+ class ApprovalMergeRequestRule < ActiveRecord::Base
+ include ::EachBatch
+
+ self.table_name = 'approval_merge_request_rules'
+ end
+
+ def change
+ queue_background_migration_jobs_by_range_at_intervals(ApprovalMergeRequestRule, 'AddModifiedToApprovalMergeRequestRule', 2.minutes, batch_size: 10_000)
+ end
+end
diff --git a/db/post_migrate/20200907092715_add_not_null_constraint_to_user_on_group_import_states.rb b/db/post_migrate/20200907092715_add_not_null_constraint_to_user_on_group_import_states.rb
new file mode 100644
index 00000000000..4f2edad43d8
--- /dev/null
+++ b/db/post_migrate/20200907092715_add_not_null_constraint_to_user_on_group_import_states.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+class AddNotNullConstraintToUserOnGroupImportStates < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ add_not_null_constraint :group_import_states, :user_id, validate: false
+ end
+
+ def down
+ remove_not_null_constraint :group_import_states, :user_id
+ end
+end
diff --git a/db/post_migrate/20200908064229_add_partial_index_to_ci_builds_table_on_user_id_name.rb b/db/post_migrate/20200908064229_add_partial_index_to_ci_builds_table_on_user_id_name.rb
new file mode 100644
index 00000000000..433fa957c38
--- /dev/null
+++ b/db/post_migrate/20200908064229_add_partial_index_to_ci_builds_table_on_user_id_name.rb
@@ -0,0 +1,37 @@
+# frozen_string_literal: true
+
+class AddPartialIndexToCiBuildsTableOnUserIdName < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+ disable_ddl_transaction!
+
+ INDEX_NAME = 'index_partial_ci_builds_on_user_id_name_parser_features'
+ FILTER_CONDITION = <<~SQL
+ (((type)::text = 'Ci::Build'::text) AND
+ ((name)::text = ANY (
+ ARRAY[
+ ('container_scanning'::character varying)::text,
+ ('dast'::character varying)::text,
+ ('dependency_scanning'::character varying)::text,
+ ('license_management'::character varying)::text,
+ ('license_scanning'::character varying)::text,
+ ('sast'::character varying)::text,
+ ('coverage_fuzzing'::character varying)::text,
+ ('secret_detection'::character varying)::text
+ ]
+ ))
+ )
+ SQL
+
+ def up
+ add_concurrent_index(:ci_builds,
+ [:user_id, :name],
+ where: FILTER_CONDITION,
+ name: INDEX_NAME)
+ end
+
+ def down
+ remove_concurrent_index_by_name :ci_builds, INDEX_NAME
+ end
+end
diff --git a/db/post_migrate/20200909161624_cleanup_group_import_states_with_null_user_id.rb b/db/post_migrate/20200909161624_cleanup_group_import_states_with_null_user_id.rb
new file mode 100644
index 00000000000..861d9e40e77
--- /dev/null
+++ b/db/post_migrate/20200909161624_cleanup_group_import_states_with_null_user_id.rb
@@ -0,0 +1,80 @@
+# frozen_string_literal: true
+
+class CleanupGroupImportStatesWithNullUserId < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ # With BATCH_SIZE=1000 and group_import_states.count=600 on GitLab.com
+ # - 1 iteration will be run
+ # - each batch requires on average ~2500ms
+ # - 600 rows require on average ~1500ms
+ # Expected total run time: ~2500ms
+ BATCH_SIZE = 1000
+
+ disable_ddl_transaction!
+
+ class User < ActiveRecord::Base
+ self.table_name = 'users'
+ end
+
+ class Namespace < ActiveRecord::Base
+ self.table_name = 'namespaces'
+
+ belongs_to :owner, class_name: 'CleanupGroupImportStatesWithNullUserId::User'
+ end
+
+ class Member < ActiveRecord::Base
+ self.table_name = 'members'
+ self.inheritance_column = :_type_disabled
+
+ belongs_to :user, class_name: 'CleanupGroupImportStatesWithNullUserId::User'
+ end
+
+ class Group < Namespace
+ OWNER = 50
+
+ self.inheritance_column = :_type_disabled
+
+ def default_owner
+ owners.first || parent&.default_owner || owner
+ end
+
+ def parent
+ Group.find_by_id(parent_id)
+ end
+
+ def owners
+ Member.where(type: 'GroupMember', source_type: 'Namespace', source_id: id, requested_at: nil, access_level: OWNER).map(&:user)
+ end
+ end
+
+ class GroupImportState < ActiveRecord::Base
+ include ::EachBatch
+
+ self.table_name = 'group_import_states'
+
+ belongs_to :group, class_name: 'CleanupGroupImportStatesWithNullUserId::Group'
+ belongs_to :user, class_name: 'CleanupGroupImportStatesWithNullUserId::User'
+ end
+
+ def up
+ User.reset_column_information
+ Namespace.reset_column_information
+ Member.reset_column_information
+ Group.reset_column_information
+ GroupImportState.reset_column_information
+
+ GroupImportState.each_batch(of: BATCH_SIZE) do |batch|
+ batch.each do |group_import_state|
+ owner_id = Group.find_by_id(group_import_state.group_id)&.default_owner&.id
+
+ group_import_state.update!(user_id: owner_id) if owner_id
+ end
+ end
+
+ GroupImportState.where('user_id IS NULL').delete_all
+ end
+
+ def down
+ # no-op : can't go back to `NULL` without first dropping the `NOT NULL` constraint
+ end
+end
diff --git a/db/post_migrate/20200910155617_backfill_jira_tracker_deployment_type.rb b/db/post_migrate/20200910155617_backfill_jira_tracker_deployment_type.rb
new file mode 100644
index 00000000000..9c978a20d25
--- /dev/null
+++ b/db/post_migrate/20200910155617_backfill_jira_tracker_deployment_type.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+class BackfillJiraTrackerDeploymentType < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ def up
+ # no-op
+ # this migration was reverted
+ # in https://gitlab.com/gitlab-org/gitlab/-/merge_requests/45205
+ # due to https://gitlab.com/gitlab-com/gl-infra/production/-/issues/2820
+ end
+
+ def down
+ # no-op
+ # intentionally blank
+ end
+end
diff --git a/db/post_migrate/20200912153218_cleanup_admin_notification_email_application_setting_rename.rb b/db/post_migrate/20200912153218_cleanup_admin_notification_email_application_setting_rename.rb
new file mode 100644
index 00000000000..35c54b64ddf
--- /dev/null
+++ b/db/post_migrate/20200912153218_cleanup_admin_notification_email_application_setting_rename.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+class CleanupAdminNotificationEmailApplicationSettingRename < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ cleanup_concurrent_column_rename :application_settings, :admin_notification_email, :abuse_notification_email
+ end
+
+ def down
+ undo_cleanup_concurrent_column_rename :application_settings, :admin_notification_email, :abuse_notification_email
+ end
+end
diff --git a/db/post_migrate/20200915185707_ensure_filled_file_store_on_package_files.rb b/db/post_migrate/20200915185707_ensure_filled_file_store_on_package_files.rb
new file mode 100644
index 00000000000..ec6f6df27bc
--- /dev/null
+++ b/db/post_migrate/20200915185707_ensure_filled_file_store_on_package_files.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+class EnsureFilledFileStoreOnPackageFiles < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ BACKGROUND_MIGRATION_CLASS = 'SetNullPackageFilesFileStoreToLocalValue'
+ BATCH_SIZE = 5_000
+ LOCAL_STORE = 1 # equal to ObjectStorage::Store::LOCAL
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ module Packages
+ class PackageFile < ActiveRecord::Base
+ self.table_name = 'packages_package_files'
+
+ include ::EachBatch
+ end
+ end
+
+ def up
+ Gitlab::BackgroundMigration.steal(BACKGROUND_MIGRATION_CLASS)
+
+ # Do a manual update in case we lost BG jobs. The expected record count should be 0 or very low.
+ Packages::PackageFile.where(file_store: nil).each_batch(of: BATCH_SIZE) do |batch, index|
+ batch.update_all(file_store: LOCAL_STORE)
+ end
+ end
+
+ def down
+ # no-op
+ end
+end
diff --git a/db/post_migrate/20200915191156_validate_not_null_file_store_on_package_files.rb b/db/post_migrate/20200915191156_validate_not_null_file_store_on_package_files.rb
new file mode 100644
index 00000000000..5e6db9cec3f
--- /dev/null
+++ b/db/post_migrate/20200915191156_validate_not_null_file_store_on_package_files.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+class ValidateNotNullFileStoreOnPackageFiles < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ # Remove index which was only added to fill file_store
+ INDEX_NAME = 'index_packages_package_files_file_store_is_null'
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ validate_not_null_constraint :packages_package_files, :file_store
+
+ remove_concurrent_index_by_name :packages_package_files, INDEX_NAME
+ end
+
+ def down
+ add_concurrent_index :packages_package_files, :id, where: 'file_store IS NULL', name: INDEX_NAME
+ end
+end
diff --git a/db/post_migrate/20200917135802_remove_duplicated_cs_findings_without_vulnerability_id.rb b/db/post_migrate/20200917135802_remove_duplicated_cs_findings_without_vulnerability_id.rb
new file mode 100644
index 00000000000..0e161b5de78
--- /dev/null
+++ b/db/post_migrate/20200917135802_remove_duplicated_cs_findings_without_vulnerability_id.rb
@@ -0,0 +1,30 @@
+# frozen_string_literal: true
+
+class RemoveDuplicatedCsFindingsWithoutVulnerabilityId < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ BATCH_SIZE = 1_000
+
+ INTERVAL = 2.minutes
+
+ # 1_500 records will be deleted
+ def up
+ return unless Gitlab.com?
+
+ migration = Gitlab::BackgroundMigration::RemoveDuplicatedCsFindingsWithoutVulnerabilityId
+ migration_name = migration.to_s.demodulize
+ relation = migration::Finding.container_scanning.with_broken_fingerprint.where(vulnerability_id: nil)
+ queue_background_migration_jobs_by_range_at_intervals(relation,
+ migration_name,
+ INTERVAL,
+ batch_size: BATCH_SIZE)
+ end
+
+ def down
+ # no-op
+ end
+end
diff --git a/db/post_migrate/20200917165525_update_index_on_namespaces_for_type_and_id.rb b/db/post_migrate/20200917165525_update_index_on_namespaces_for_type_and_id.rb
new file mode 100644
index 00000000000..35b72b4f160
--- /dev/null
+++ b/db/post_migrate/20200917165525_update_index_on_namespaces_for_type_and_id.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+class UpdateIndexOnNamespacesForTypeAndId < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+ disable_ddl_transaction!
+
+ OLD_INDEX_NAME = 'index_namespaces_on_type_partial'
+ NEW_INDEX_NAME = 'index_namespaces_on_type_and_id_partial'
+
+ def up
+ add_concurrent_index(:namespaces, [:type, :id], where: 'type IS NOT NULL', name: NEW_INDEX_NAME)
+
+ remove_concurrent_index_by_name(:namespaces, OLD_INDEX_NAME)
+ end
+
+ def down
+ add_concurrent_index(:namespaces, :type, where: 'type IS NOT NULL', name: OLD_INDEX_NAME)
+
+ remove_concurrent_index_by_name(:namespaces, NEW_INDEX_NAME)
+ end
+end
diff --git a/db/post_migrate/20200922054642_drop_snowplow_iglu_registry_url_from_application_settings.rb b/db/post_migrate/20200922054642_drop_snowplow_iglu_registry_url_from_application_settings.rb
new file mode 100644
index 00000000000..d3e64f1f4c2
--- /dev/null
+++ b/db/post_migrate/20200922054642_drop_snowplow_iglu_registry_url_from_application_settings.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+class DropSnowplowIgluRegistryUrlFromApplicationSettings < ActiveRecord::Migration[6.0]
+ DOWNTIME = false
+
+ def change
+ remove_column :application_settings, :snowplow_iglu_registry_url, :string, limit: 255
+ end
+end
diff --git a/db/post_migrate/20200922095954_remove_instance_statistics_visibility_private_from_application_settings.rb b/db/post_migrate/20200922095954_remove_instance_statistics_visibility_private_from_application_settings.rb
new file mode 100644
index 00000000000..1d01e54013d
--- /dev/null
+++ b/db/post_migrate/20200922095954_remove_instance_statistics_visibility_private_from_application_settings.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+class RemoveInstanceStatisticsVisibilityPrivateFromApplicationSettings < ActiveRecord::Migration[6.0]
+ DOWNTIME = false
+
+ def up
+ remove_column :application_settings, :instance_statistics_visibility_private
+ end
+
+ def down
+ add_column :application_settings, :instance_statistics_visibility_private, :boolean, default: false, null: false
+ end
+end
diff --git a/db/post_migrate/20200922170907_change_index_on_pipeline_status.rb b/db/post_migrate/20200922170907_change_index_on_pipeline_status.rb
new file mode 100644
index 00000000000..61648788d7f
--- /dev/null
+++ b/db/post_migrate/20200922170907_change_index_on_pipeline_status.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+class ChangeIndexOnPipelineStatus < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+ OLD_INDEX_NAME = 'index_ci_pipelines_on_status'
+ NEW_INDEX_NAME = 'index_ci_pipelines_on_status_and_id'
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index :ci_pipelines, [:status, :id], name: NEW_INDEX_NAME
+ remove_concurrent_index_by_name :ci_pipelines, name: OLD_INDEX_NAME
+ end
+
+ def down
+ add_concurrent_index :ci_pipelines, :status, name: OLD_INDEX_NAME
+ remove_concurrent_index_by_name :ci_pipelines, name: NEW_INDEX_NAME
+ end
+end
diff --git a/db/post_migrate/20200922231755_remove_created_by_user_id_from_cluster_providers_aws.rb b/db/post_migrate/20200922231755_remove_created_by_user_id_from_cluster_providers_aws.rb
new file mode 100644
index 00000000000..02cc9676202
--- /dev/null
+++ b/db/post_migrate/20200922231755_remove_created_by_user_id_from_cluster_providers_aws.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+class RemoveCreatedByUserIdFromClusterProvidersAws < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+ INDEX_NAME = 'index_cluster_providers_aws_on_created_by_user_id'
+
+ disable_ddl_transaction!
+
+ def up
+ with_lock_retries do
+ remove_column :cluster_providers_aws, :created_by_user_id
+ end
+ end
+
+ def down
+ unless column_exists?(:cluster_providers_aws, :created_by_user_id)
+ add_column :cluster_providers_aws, :created_by_user_id, :integer
+ end
+
+ add_concurrent_index :cluster_providers_aws, :created_by_user_id, name: INDEX_NAME
+
+ add_concurrent_foreign_key :cluster_providers_aws, :users, column: :created_by_user_id, on_delete: :nullify
+ end
+end
diff --git a/db/post_migrate/20200929052138_create_initial_versions_for_pre_versioning_terraform_states.rb b/db/post_migrate/20200929052138_create_initial_versions_for_pre_versioning_terraform_states.rb
new file mode 100644
index 00000000000..eff6ebfe5b4
--- /dev/null
+++ b/db/post_migrate/20200929052138_create_initial_versions_for_pre_versioning_terraform_states.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+class CreateInitialVersionsForPreVersioningTerraformStates < ActiveRecord::Migration[6.0]
+ DOWNTIME = false
+
+ def up
+ execute <<-SQL
+ INSERT INTO terraform_state_versions (terraform_state_id, created_at, updated_at, version, file_store, file)
+ SELECT id, NOW(), NOW(), 0, file_store, file
+ FROM terraform_states
+ WHERE versioning_enabled = FALSE
+ ON CONFLICT (terraform_state_id, version) DO NOTHING
+ SQL
+ end
+
+ def down
+ end
+end
diff --git a/db/post_migrate/20200929113254_remove_type_from_audit_events.rb b/db/post_migrate/20200929113254_remove_type_from_audit_events.rb
new file mode 100644
index 00000000000..000dc0d2865
--- /dev/null
+++ b/db/post_migrate/20200929113254_remove_type_from_audit_events.rb
@@ -0,0 +1,125 @@
+# frozen_string_literal: true
+
+class RemoveTypeFromAuditEvents < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::SchemaHelpers
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+ SOURCE_TABLE_NAME = 'audit_events'
+ PARTITIONED_TABLE_NAME = 'audit_events_part_5fc467ac26'
+ TRIGGER_FUNCTION_NAME = 'table_sync_function_2be879775d'
+
+ def up
+ with_lock_retries do
+ remove_column SOURCE_TABLE_NAME, :type
+
+ create_trigger_function(TRIGGER_FUNCTION_NAME, replace: true) do
+ <<~SQL
+ IF (TG_OP = 'DELETE') THEN
+ DELETE FROM #{PARTITIONED_TABLE_NAME} where id = OLD.id;
+ ELSIF (TG_OP = 'UPDATE') THEN
+ UPDATE #{PARTITIONED_TABLE_NAME}
+ SET author_id = NEW.author_id,
+ entity_id = NEW.entity_id,
+ entity_type = NEW.entity_type,
+ details = NEW.details,
+ ip_address = NEW.ip_address,
+ author_name = NEW.author_name,
+ entity_path = NEW.entity_path,
+ target_details = NEW.target_details,
+ target_type = NEW.target_type,
+ target_id = NEW.target_id,
+ created_at = NEW.created_at
+ WHERE #{PARTITIONED_TABLE_NAME}.id = NEW.id;
+ ELSIF (TG_OP = 'INSERT') THEN
+ INSERT INTO #{PARTITIONED_TABLE_NAME} (id,
+ author_id,
+ entity_id,
+ entity_type,
+ details,
+ ip_address,
+ author_name,
+ entity_path,
+ target_details,
+ target_type,
+ target_id,
+ created_at)
+ VALUES (NEW.id,
+ NEW.author_id,
+ NEW.entity_id,
+ NEW.entity_type,
+ NEW.details,
+ NEW.ip_address,
+ NEW.author_name,
+ NEW.entity_path,
+ NEW.target_details,
+ NEW.target_type,
+ NEW.target_id,
+ NEW.created_at);
+ END IF;
+ RETURN NULL;
+ SQL
+ end
+
+ remove_column PARTITIONED_TABLE_NAME, :type
+ end
+ end
+
+ def down
+ with_lock_retries do
+ add_column SOURCE_TABLE_NAME, :type, :string
+ add_column PARTITIONED_TABLE_NAME, :type, :string
+
+ create_trigger_function(TRIGGER_FUNCTION_NAME, replace: true) do
+ <<~SQL
+ IF (TG_OP = 'DELETE') THEN
+ DELETE FROM #{PARTITIONED_TABLE_NAME} where id = OLD.id;
+ ELSIF (TG_OP = 'UPDATE') THEN
+ UPDATE #{PARTITIONED_TABLE_NAME}
+ SET author_id = NEW.author_id,
+ type = NEW.type,
+ entity_id = NEW.entity_id,
+ entity_type = NEW.entity_type,
+ details = NEW.details,
+ ip_address = NEW.ip_address,
+ author_name = NEW.author_name,
+ entity_path = NEW.entity_path,
+ target_details = NEW.target_details,
+ target_type = NEW.target_type,
+ target_id = NEW.target_id,
+ created_at = NEW.created_at
+ WHERE #{PARTITIONED_TABLE_NAME}.id = NEW.id;
+ ELSIF (TG_OP = 'INSERT') THEN
+ INSERT INTO #{PARTITIONED_TABLE_NAME} (id,
+ author_id,
+ type,
+ entity_id,
+ entity_type,
+ details,
+ ip_address,
+ author_name,
+ entity_path,
+ target_details,
+ target_type,
+ target_id,
+ created_at)
+ VALUES (NEW.id,
+ NEW.author_id,
+ NEW.type,
+ NEW.entity_id,
+ NEW.entity_type,
+ NEW.details,
+ NEW.ip_address,
+ NEW.author_name,
+ NEW.entity_path,
+ NEW.target_details,
+ NEW.target_type,
+ NEW.target_id,
+ NEW.created_at);
+ END IF;
+ RETURN NULL;
+ SQL
+ end
+ end
+ end
+end
diff --git a/db/post_migrate/20200929114107_schedule_migrate_u2f_webauthn.rb b/db/post_migrate/20200929114107_schedule_migrate_u2f_webauthn.rb
new file mode 100644
index 00000000000..b118ed271a2
--- /dev/null
+++ b/db/post_migrate/20200929114107_schedule_migrate_u2f_webauthn.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+class ScheduleMigrateU2fWebauthn < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ INTERVAL = 2.minutes.to_i
+ DOWNTIME = false
+ MIGRATION = 'MigrateU2fWebauthn'
+ BATCH_SIZE = 1_000
+
+ disable_ddl_transaction!
+
+ class U2fRegistration < ActiveRecord::Base
+ include EachBatch
+
+ self.table_name = 'u2f_registrations'
+ end
+
+ def up
+ say "Scheduling #{MIGRATION} background migration jobs"
+
+ queue_background_migration_jobs_by_range_at_intervals(U2fRegistration, MIGRATION, INTERVAL, batch_size: BATCH_SIZE)
+ end
+
+ def down
+ # no-op
+ # There is no real way back here, because
+ # a) The U2fMigrator of webauthn_ruby gem only works in one way
+ # b) This migration only pushes jobs to Sidekiq
+ end
+end
diff --git a/db/post_migrate/20200930144340_set_job_waiter_ttl.rb b/db/post_migrate/20200930144340_set_job_waiter_ttl.rb
new file mode 100644
index 00000000000..b15faa61dea
--- /dev/null
+++ b/db/post_migrate/20200930144340_set_job_waiter_ttl.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+class SetJobWaiterTtl < ActiveRecord::Migration[6.0]
+ DOWNTIME = false
+
+ SCRIPT = <<~LUA.freeze
+ if redis.call("ttl", KEYS[1]) < 0 then
+ redis.call("expire", KEYS[1], 21600)
+ end
+ LUA
+
+ def up
+ Gitlab::Redis::SharedState.with do |redis|
+ cursor_init = '0'
+ cursor = cursor_init
+
+ loop do
+ cursor, keys = redis.scan(cursor, match: 'gitlab:job_waiter:*')
+
+ redis.pipelined do |redis|
+ keys.each { |k| redis.eval(SCRIPT, keys: [k]) }
+ end
+
+ break if cursor == cursor_init
+ end
+ end
+ end
+
+ def down
+ end
+end
diff --git a/db/post_migrate/20201001022100_validate_designs_filename_text_limit.rb b/db/post_migrate/20201001022100_validate_designs_filename_text_limit.rb
new file mode 100644
index 00000000000..35ed8c20671
--- /dev/null
+++ b/db/post_migrate/20201001022100_validate_designs_filename_text_limit.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+class ValidateDesignsFilenameTextLimit < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ validate_text_limit :design_management_designs, :filename
+ end
+
+ def down
+ # no-op
+ end
+end
diff --git a/db/post_migrate/20201001101136_remove_index_on_issues_relative_position.rb b/db/post_migrate/20201001101136_remove_index_on_issues_relative_position.rb
new file mode 100644
index 00000000000..605a167c0d5
--- /dev/null
+++ b/db/post_migrate/20201001101136_remove_index_on_issues_relative_position.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+class RemoveIndexOnIssuesRelativePosition < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ INDEX_NAME = 'index_issues_on_relative_position'
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ remove_concurrent_index_by_name(:issues, INDEX_NAME)
+ end
+
+ def down
+ add_concurrent_index(:issues, :relative_position, name: INDEX_NAME)
+ end
+end
diff --git a/db/post_migrate/20201002094617_remove_container_scanning_report_type_index.rb b/db/post_migrate/20201002094617_remove_container_scanning_report_type_index.rb
new file mode 100644
index 00000000000..a591fc185c4
--- /dev/null
+++ b/db/post_migrate/20201002094617_remove_container_scanning_report_type_index.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+class RemoveContainerScanningReportTypeIndex < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+ INDEX_NAME = 'idx_container_scanning_findings'
+
+ disable_ddl_transaction!
+
+ def up
+ remove_concurrent_index_by_name(:vulnerability_occurrences, INDEX_NAME)
+ end
+
+ def down
+ # report_type: 2 container scanning
+ add_concurrent_index(
+ :vulnerability_occurrences,
+ :id,
+ where: 'report_type = 2',
+ name: INDEX_NAME
+ )
+ end
+end
diff --git a/db/post_migrate/20201002175953_add_index_for_merged_merge_requests.rb b/db/post_migrate/20201002175953_add_index_for_merged_merge_requests.rb
new file mode 100644
index 00000000000..cd663f3da89
--- /dev/null
+++ b/db/post_migrate/20201002175953_add_index_for_merged_merge_requests.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+class AddIndexForMergedMergeRequests < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+ INDEX_NAME = 'idx_merge_requests_on_merged_state'
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index :merge_requests,
+ :id,
+ where: 'state_id = 3',
+ name: INDEX_NAME
+ end
+
+ def down
+ remove_concurrent_index_by_name :merge_requests, INDEX_NAME
+ end
+end
diff --git a/db/post_migrate/20201005094331_migrate_compliance_framework_enum_to_database_framework_record.rb b/db/post_migrate/20201005094331_migrate_compliance_framework_enum_to_database_framework_record.rb
new file mode 100644
index 00000000000..5e261637d46
--- /dev/null
+++ b/db/post_migrate/20201005094331_migrate_compliance_framework_enum_to_database_framework_record.rb
@@ -0,0 +1,104 @@
+# frozen_string_literal: true
+
+class MigrateComplianceFrameworkEnumToDatabaseFrameworkRecord < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ class TmpComplianceFramework < ActiveRecord::Base
+ self.table_name = 'compliance_management_frameworks'
+ end
+
+ class TmpProjectSettings < ActiveRecord::Base
+ # Maps data between ComplianceManagement::ComplianceFramework::FRAMEWORKS(enum) and new ComplianceManagement::Framework model
+ ENUM_FRAMEWORK_MAPPING = {
+ 1 => {
+ name: 'GDPR',
+ description: 'General Data Protection Regulation',
+ color: '#1aaa55'
+ }.freeze,
+ 2 => {
+ name: 'HIPAA',
+ description: 'Health Insurance Portability and Accountability Act',
+ color: '#1f75cb'
+ }.freeze,
+ 3 => {
+ name: 'PCI-DSS',
+ description: 'Payment Card Industry-Data Security Standard',
+ color: '#6666c4'
+ }.freeze,
+ 4 => {
+ name: 'SOC 2',
+ description: 'Service Organization Control 2',
+ color: '#dd2b0e'
+ }.freeze,
+ 5 => {
+ name: 'SOX',
+ description: 'Sarbanes-Oxley',
+ color: '#fc9403'
+ }.freeze
+ }.freeze
+
+ self.table_name = 'project_compliance_framework_settings'
+
+ include EachBatch
+
+ def raw_compliance_framework
+ # Because we have an `enum` definition in ComplianceManagement::ComplianceFramework::ProjectSettings, this is very unlikely to fail.
+ ENUM_FRAMEWORK_MAPPING.fetch(framework).merge(namespace_id: root_namespace_id)
+ end
+ end
+
+ def up
+ return unless Gitlab.ee?
+
+ TmpComplianceFramework.reset_column_information
+ TmpProjectSettings.reset_column_information
+
+ # This is our standard recursive namespace query, we use it to determine the root_namespace_id in the same query.
+ lateral_join = <<~SQL
+ INNER JOIN LATERAL (
+ WITH RECURSIVE "base_and_ancestors" AS (
+ (
+ SELECT "ns".* FROM "namespaces" as ns WHERE "ns"."id" = projects.namespace_id
+ ) UNION
+ (
+ SELECT "ns".* FROM "namespaces" as ns, "base_and_ancestors" WHERE "ns"."id" = "base_and_ancestors"."parent_id"
+ )
+ ) SELECT "namespaces".* FROM "base_and_ancestors" AS "namespaces" WHERE parent_id IS NULL LIMIT 1) AS root_namespaces ON TRUE
+ SQL
+
+ TmpProjectSettings.each_batch(of: 100) do |query|
+ project_settings_with_root_group = query
+ .select(:project_id, :framework, 'root_namespaces.id as root_namespace_id')
+ .from("(SELECT * FROM project_compliance_framework_settings) as project_compliance_framework_settings") # this is needed for the LATERAL JOIN
+ .joins("INNER JOIN projects on projects.id = project_compliance_framework_settings.project_id")
+ .joins(lateral_join)
+ .to_a
+
+ ActiveRecord::Base.transaction do
+ raw_frameworks = project_settings_with_root_group.map(&:raw_compliance_framework)
+ TmpComplianceFramework.insert_all(raw_frameworks.uniq) # Create compliance frameworks per group
+
+ unique_namespace_ids = project_settings_with_root_group.map(&:root_namespace_id).uniq
+
+ framework_records = TmpComplianceFramework.select(:id, :namespace_id, :name).where(namespace_id: unique_namespace_ids)
+
+ project_settings_with_root_group.each do |project_setting|
+ framework = framework_records.find do |record|
+ # name is unique within a group
+ record.name == project_setting.raw_compliance_framework[:name] && record[:namespace_id] == project_setting.raw_compliance_framework[:namespace_id]
+ end
+
+ project_setting.update_column(:framework_id, framework.id)
+ end
+ end
+ end
+ end
+
+ def down
+ # data migration, no-op
+ end
+end
diff --git a/db/post_migrate/20201005153955_add_not_null_constraint_to_compliance_project_settings.rb b/db/post_migrate/20201005153955_add_not_null_constraint_to_compliance_project_settings.rb
new file mode 100644
index 00000000000..6d47cbe9f08
--- /dev/null
+++ b/db/post_migrate/20201005153955_add_not_null_constraint_to_compliance_project_settings.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+class AddNotNullConstraintToComplianceProjectSettings < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ add_not_null_constraint(:project_compliance_framework_settings, :framework_id)
+
+ change_column_null(:compliance_management_frameworks, :namespace_id, false)
+ end
+
+ def down
+ change_column_null(:compliance_management_frameworks, :namespace_id, true)
+
+ remove_not_null_constraint(:project_compliance_framework_settings, :framework_id)
+ end
+end
diff --git a/db/post_migrate/20201014142521_schedule_sync_blocking_issues_count.rb b/db/post_migrate/20201014142521_schedule_sync_blocking_issues_count.rb
new file mode 100644
index 00000000000..61b2b2aaad5
--- /dev/null
+++ b/db/post_migrate/20201014142521_schedule_sync_blocking_issues_count.rb
@@ -0,0 +1,46 @@
+# frozen_string_literal: true
+
+require 'set'
+
+class ScheduleSyncBlockingIssuesCount < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ BATCH_SIZE = 50
+ DELAY_INTERVAL = 120.seconds.to_i
+ MIGRATION = 'SyncBlockingIssuesCount'.freeze
+
+ disable_ddl_transaction!
+
+ class TmpIssueLink < ActiveRecord::Base
+ self.table_name = 'issue_links'
+
+ include EachBatch
+ end
+
+ def up
+ return unless Gitlab.ee?
+
+ issue_link_ids = SortedSet.new
+
+ TmpIssueLink.distinct.select(:source_id).where(link_type: 1).each_batch(of: 1000, column: :source_id) do |query|
+ issue_link_ids.merge(query.pluck(:source_id))
+ end
+
+ TmpIssueLink.distinct.select(:target_id).where(link_type: 2).each_batch(of: 1000, column: :target_id) do |query|
+ issue_link_ids.merge(query.pluck(:target_id))
+ end
+
+ issue_link_ids.each_slice(BATCH_SIZE).with_index do |items, index|
+ start_id, *, end_id = items
+
+ arguments = [start_id, end_id]
+
+ final_delay = DELAY_INTERVAL * (index + 1)
+ migrate_in(final_delay, MIGRATION, arguments)
+ end
+ end
+
+ def down
+ # NO OP
+ end
+end
diff --git a/db/post_migrate/20201015073808_schedule_blocked_by_links_replacement.rb b/db/post_migrate/20201015073808_schedule_blocked_by_links_replacement.rb
new file mode 100644
index 00000000000..7833d7c4c04
--- /dev/null
+++ b/db/post_migrate/20201015073808_schedule_blocked_by_links_replacement.rb
@@ -0,0 +1,30 @@
+# frozen_string_literal: true
+
+class ScheduleBlockedByLinksReplacement < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+ INTERVAL = 2.minutes
+ # at the time of writing there were 47600 blocked_by issues:
+ # estimated time is 48 batches * 2 minutes -> 100 minutes
+ BATCH_SIZE = 1000
+ MIGRATION = 'ReplaceBlockedByLinks'
+
+ disable_ddl_transaction!
+
+ class IssueLink < ActiveRecord::Base
+ include EachBatch
+
+ self.table_name = 'issue_links'
+ end
+
+ def up
+ relation = IssueLink.where(link_type: 2)
+
+ queue_background_migration_jobs_by_range_at_intervals(
+ relation, MIGRATION, INTERVAL, batch_size: BATCH_SIZE)
+ end
+
+ def down
+ end
+end
diff --git a/db/post_migrate/20201015154527_add_index_on_services_for_usage_data.rb b/db/post_migrate/20201015154527_add_index_on_services_for_usage_data.rb
new file mode 100644
index 00000000000..f85ab97420b
--- /dev/null
+++ b/db/post_migrate/20201015154527_add_index_on_services_for_usage_data.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+class AddIndexOnServicesForUsageData < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+ INDEX_NAME = 'index_services_on_type_id_when_active_and_project_id_not_null'
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index :services, [:type, :id], where: 'active = TRUE AND project_id IS NOT NULL', name: INDEX_NAME
+ end
+
+ def down
+ remove_concurrent_index_by_name :services, INDEX_NAME
+ end
+end
diff --git a/db/schema_migrations/20200813135558 b/db/schema_migrations/20200813135558
new file mode 100644
index 00000000000..319f0a0b604
--- /dev/null
+++ b/db/schema_migrations/20200813135558
@@ -0,0 +1 @@
+5f7a5fa697d769f5ccc9f0a6f19a91c8935f2559e019d50895574819494baf7e \ No newline at end of file
diff --git a/db/schema_migrations/20200817195628 b/db/schema_migrations/20200817195628
new file mode 100644
index 00000000000..7d919242d89
--- /dev/null
+++ b/db/schema_migrations/20200817195628
@@ -0,0 +1 @@
+4da25ee40eabd81765b562929c819da1fc2b0f8afe1f4eefe6b769fcd8f0d4cd \ No newline at end of file
diff --git a/db/schema_migrations/20200901170135 b/db/schema_migrations/20200901170135
new file mode 100644
index 00000000000..4f0f5213a98
--- /dev/null
+++ b/db/schema_migrations/20200901170135
@@ -0,0 +1 @@
+fca99780272ca4ceb42fd38d16f67cd4a0a675ecdaf91e51c4c0728205212ed0 \ No newline at end of file
diff --git a/db/schema_migrations/20200905013247 b/db/schema_migrations/20200905013247
new file mode 100644
index 00000000000..b0926ca1d99
--- /dev/null
+++ b/db/schema_migrations/20200905013247
@@ -0,0 +1 @@
+860c45fd6293f2f8f10d7351cb5a2fbab2cc9147e56b538cb62d75469b039ef0 \ No newline at end of file
diff --git a/db/schema_migrations/20200907092610 b/db/schema_migrations/20200907092610
new file mode 100644
index 00000000000..63eecc83a3c
--- /dev/null
+++ b/db/schema_migrations/20200907092610
@@ -0,0 +1 @@
+de1051e8f2d9f042ac923686b8c61e743c695736e8c7ebfdf6f87ab1ed09a11f \ No newline at end of file
diff --git a/db/schema_migrations/20200907092715 b/db/schema_migrations/20200907092715
new file mode 100644
index 00000000000..700db177075
--- /dev/null
+++ b/db/schema_migrations/20200907092715
@@ -0,0 +1 @@
+2610104c89134b94d460a714f17c23e5e35d76147c1f25be6c02804a39725d6c \ No newline at end of file
diff --git a/db/schema_migrations/20200908064229 b/db/schema_migrations/20200908064229
new file mode 100644
index 00000000000..37958f04de8
--- /dev/null
+++ b/db/schema_migrations/20200908064229
@@ -0,0 +1 @@
+e73076f6d7540372ee16fe26dcb44e8b84dde69e27c46483ee26883e81059501 \ No newline at end of file
diff --git a/db/schema_migrations/20200908094810 b/db/schema_migrations/20200908094810
new file mode 100644
index 00000000000..a047e64107b
--- /dev/null
+++ b/db/schema_migrations/20200908094810
@@ -0,0 +1 @@
+327cd19cd6c0f273aea61ffebf10046fb7229516bc4ed28f3c0290bb3ad04755 \ No newline at end of file
diff --git a/db/schema_migrations/20200909040555 b/db/schema_migrations/20200909040555
new file mode 100644
index 00000000000..27855514146
--- /dev/null
+++ b/db/schema_migrations/20200909040555
@@ -0,0 +1 @@
+f68d29be164299e5ccf73347841d27b17f028941e37e3510d3da9d513762a17f \ No newline at end of file
diff --git a/db/schema_migrations/20200909083339 b/db/schema_migrations/20200909083339
new file mode 100644
index 00000000000..179a683412c
--- /dev/null
+++ b/db/schema_migrations/20200909083339
@@ -0,0 +1 @@
+8b2090e953e6205b65555408a88d3da7f6bce28b0baa52d1a43a3a3e8001b7e1 \ No newline at end of file
diff --git a/db/schema_migrations/20200909161624 b/db/schema_migrations/20200909161624
new file mode 100644
index 00000000000..941af468398
--- /dev/null
+++ b/db/schema_migrations/20200909161624
@@ -0,0 +1 @@
+2d7f514429e9a08ce13995feff43e221b3e2e74737ed48f81e104008d8ec24b9 \ No newline at end of file
diff --git a/db/schema_migrations/20200910155617 b/db/schema_migrations/20200910155617
new file mode 100644
index 00000000000..901b6c0545c
--- /dev/null
+++ b/db/schema_migrations/20200910155617
@@ -0,0 +1 @@
+6cba0aecae495458b3b161999417cb9d790e60b4edfb10bb26b9684d466e3fd2 \ No newline at end of file
diff --git a/db/schema_migrations/20200912152943 b/db/schema_migrations/20200912152943
new file mode 100644
index 00000000000..4dd1ae708cd
--- /dev/null
+++ b/db/schema_migrations/20200912152943
@@ -0,0 +1 @@
+b8d7a2ec9ecf51fd7cb9346e1484b45d5b472a85d90ad270d08c1cca1b44f039 \ No newline at end of file
diff --git a/db/schema_migrations/20200912153218 b/db/schema_migrations/20200912153218
new file mode 100644
index 00000000000..9c013281ea2
--- /dev/null
+++ b/db/schema_migrations/20200912153218
@@ -0,0 +1 @@
+fd632247f1588c537e83574edd7936c530e154091e3101d0404da3b7ef8b4bef \ No newline at end of file
diff --git a/db/schema_migrations/20200912193210 b/db/schema_migrations/20200912193210
new file mode 100644
index 00000000000..a6ce007630a
--- /dev/null
+++ b/db/schema_migrations/20200912193210
@@ -0,0 +1 @@
+bcc84e89e4e9772d3209aa8df1368c188b1c6334114bcf339870cae74e724d01 \ No newline at end of file
diff --git a/db/schema_migrations/20200914070140 b/db/schema_migrations/20200914070140
new file mode 100644
index 00000000000..b9cac3a3726
--- /dev/null
+++ b/db/schema_migrations/20200914070140
@@ -0,0 +1 @@
+8cabe224e89ef77fe4a2bc1f8bf7381faaa10d1cab4907a26aeb2162a126af52 \ No newline at end of file
diff --git a/db/schema_migrations/20200915134004 b/db/schema_migrations/20200915134004
new file mode 100644
index 00000000000..a8857de0ada
--- /dev/null
+++ b/db/schema_migrations/20200915134004
@@ -0,0 +1 @@
+dd630c76819641ad64a5f6ae40ad4f49e7fbe1c783398d97886dc7e9852a245e \ No newline at end of file
diff --git a/db/schema_migrations/20200915185707 b/db/schema_migrations/20200915185707
new file mode 100644
index 00000000000..2161aa5acf8
--- /dev/null
+++ b/db/schema_migrations/20200915185707
@@ -0,0 +1 @@
+e1ae80d6f0a6372bb329d45257d9a0a8ca5b6a83718d2a10ee295b8c4c97f60e \ No newline at end of file
diff --git a/db/schema_migrations/20200915191156 b/db/schema_migrations/20200915191156
new file mode 100644
index 00000000000..5005ee15989
--- /dev/null
+++ b/db/schema_migrations/20200915191156
@@ -0,0 +1 @@
+d8ddec6b234d59b3b85705dfa7b724d3be4974bfa57fae70aa5c2dbdd2e73cfa \ No newline at end of file
diff --git a/db/schema_migrations/20200916135044 b/db/schema_migrations/20200916135044
new file mode 100644
index 00000000000..8bb10fbb1e3
--- /dev/null
+++ b/db/schema_migrations/20200916135044
@@ -0,0 +1 @@
+299e6fb38da303f06ab006a25701ff1c58ce2abfa8cf93c3c8b866ee0b2bd1cc \ No newline at end of file
diff --git a/db/schema_migrations/20200916151442 b/db/schema_migrations/20200916151442
new file mode 100644
index 00000000000..36b2a4e9962
--- /dev/null
+++ b/db/schema_migrations/20200916151442
@@ -0,0 +1 @@
+aef52404e6ce83d5d4b3de65ad00b665334f5ff2e5b7b6c3c622f79313657f26 \ No newline at end of file
diff --git a/db/schema_migrations/20200916165232 b/db/schema_migrations/20200916165232
new file mode 100644
index 00000000000..8e97fcf3efa
--- /dev/null
+++ b/db/schema_migrations/20200916165232
@@ -0,0 +1 @@
+18a3981a3becefe6700dd5fea87e8ba9478c0e83ddc80de1b3ee2ed77c221ce6 \ No newline at end of file
diff --git a/db/schema_migrations/20200917121650 b/db/schema_migrations/20200917121650
new file mode 100644
index 00000000000..d0f26d40466
--- /dev/null
+++ b/db/schema_migrations/20200917121650
@@ -0,0 +1 @@
+3343b646d0c0ca2d92982740abe4372fb80931cb4bb4386229959d5d61c86587 \ No newline at end of file
diff --git a/db/schema_migrations/20200917135802 b/db/schema_migrations/20200917135802
new file mode 100644
index 00000000000..7b948de646b
--- /dev/null
+++ b/db/schema_migrations/20200917135802
@@ -0,0 +1 @@
+8d9e75f7c6344b03cb740fa691fcbb5bea1751802741229158701bc1af975897 \ No newline at end of file
diff --git a/db/schema_migrations/20200917165525 b/db/schema_migrations/20200917165525
new file mode 100644
index 00000000000..bf01a95ad14
--- /dev/null
+++ b/db/schema_migrations/20200917165525
@@ -0,0 +1 @@
+0080b9192ba5b4ea3853cfd930d58e10b9619f3d9a54016b574712e5ec2084f6 \ No newline at end of file
diff --git a/db/schema_migrations/20200919200318 b/db/schema_migrations/20200919200318
new file mode 100644
index 00000000000..29721a3ef2b
--- /dev/null
+++ b/db/schema_migrations/20200919200318
@@ -0,0 +1 @@
+f33c66297ca7848c576778dc275e42801f5f9d7cdcf8c4d2fb205d4eb9770937 \ No newline at end of file
diff --git a/db/schema_migrations/20200919204155 b/db/schema_migrations/20200919204155
new file mode 100644
index 00000000000..39b608deed4
--- /dev/null
+++ b/db/schema_migrations/20200919204155
@@ -0,0 +1 @@
+097cb7a36fdc831045f3a33a047f8bda6474b8165ef5fc95dbdeea45d0ac04a3 \ No newline at end of file
diff --git a/db/schema_migrations/20200921093826 b/db/schema_migrations/20200921093826
new file mode 100644
index 00000000000..4a405de5215
--- /dev/null
+++ b/db/schema_migrations/20200921093826
@@ -0,0 +1 @@
+8d14013bcb4d8302c91e331f619fb6f621ab79907aebc421d99c9484ecd7a5d8 \ No newline at end of file
diff --git a/db/schema_migrations/20200921113722 b/db/schema_migrations/20200921113722
new file mode 100644
index 00000000000..96dc1683f72
--- /dev/null
+++ b/db/schema_migrations/20200921113722
@@ -0,0 +1 @@
+723812a28afbabb6b7884fd76dcaf658c5e35a33a46e90a9a94aef12e735e604 \ No newline at end of file
diff --git a/db/schema_migrations/20200921130028 b/db/schema_migrations/20200921130028
new file mode 100644
index 00000000000..b718f21c156
--- /dev/null
+++ b/db/schema_migrations/20200921130028
@@ -0,0 +1 @@
+60835078e0a0bd191e9b1f0316f894c5223d6849277992b5034ed4ff9a798fe4 \ No newline at end of file
diff --git a/db/schema_migrations/20200921131313 b/db/schema_migrations/20200921131313
new file mode 100644
index 00000000000..559701acf69
--- /dev/null
+++ b/db/schema_migrations/20200921131313
@@ -0,0 +1 @@
+e4f9e918c86705409555cde065f30ba0c0c405dfd1918f47a169a5dc5c244a8d \ No newline at end of file
diff --git a/db/schema_migrations/20200921203231 b/db/schema_migrations/20200921203231
new file mode 100644
index 00000000000..544b7146ebf
--- /dev/null
+++ b/db/schema_migrations/20200921203231
@@ -0,0 +1 @@
+7f62ce5117a16213bad6537dfeae2af4016262c533f8fa6b7a19572077bcf8d7 \ No newline at end of file
diff --git a/db/schema_migrations/20200922052316 b/db/schema_migrations/20200922052316
new file mode 100644
index 00000000000..31bd12178ef
--- /dev/null
+++ b/db/schema_migrations/20200922052316
@@ -0,0 +1 @@
+384d022662437de21b4b3b97bf2f1dec2925be6afe4b62828c97dc9b3b3fc77c \ No newline at end of file
diff --git a/db/schema_migrations/20200922054642 b/db/schema_migrations/20200922054642
new file mode 100644
index 00000000000..443c13c256e
--- /dev/null
+++ b/db/schema_migrations/20200922054642
@@ -0,0 +1 @@
+ad63096e49440f7f2a15ea2747689ca39f52fdcebc1949a1feed82a22f432e9e \ No newline at end of file
diff --git a/db/schema_migrations/20200922075244 b/db/schema_migrations/20200922075244
new file mode 100644
index 00000000000..82a2fc5f304
--- /dev/null
+++ b/db/schema_migrations/20200922075244
@@ -0,0 +1 @@
+a8450c6c21b1182afd06c88af18c0d9be92b0e7fdc73505c07d4ab3fddd39abf \ No newline at end of file
diff --git a/db/schema_migrations/20200922093004 b/db/schema_migrations/20200922093004
new file mode 100644
index 00000000000..04dd5dbfcf6
--- /dev/null
+++ b/db/schema_migrations/20200922093004
@@ -0,0 +1 @@
+705d010620b1aa95e86c8fb5fb9175fe77778376d228003e9fd2c8d0bb20a347 \ No newline at end of file
diff --git a/db/schema_migrations/20200922095954 b/db/schema_migrations/20200922095954
new file mode 100644
index 00000000000..2282da76380
--- /dev/null
+++ b/db/schema_migrations/20200922095954
@@ -0,0 +1 @@
+c55f27f817afc60462e5dc43755a4ddd76f1399f5e461bab4b36bf5e5b26ce0a \ No newline at end of file
diff --git a/db/schema_migrations/20200922133949 b/db/schema_migrations/20200922133949
new file mode 100644
index 00000000000..8c1874198bb
--- /dev/null
+++ b/db/schema_migrations/20200922133949
@@ -0,0 +1 @@
+8196e28f6fe8cdb4cf710922b5cd218030ba587c629de7ee75dc061d05c7e1a9 \ No newline at end of file
diff --git a/db/schema_migrations/20200922170907 b/db/schema_migrations/20200922170907
new file mode 100644
index 00000000000..66ff701973d
--- /dev/null
+++ b/db/schema_migrations/20200922170907
@@ -0,0 +1 @@
+ab044b609a29e9a179813de79dab9770665917a8ed78db907755a64f2d4aa47c \ No newline at end of file
diff --git a/db/schema_migrations/20200922231755 b/db/schema_migrations/20200922231755
new file mode 100644
index 00000000000..504df45b957
--- /dev/null
+++ b/db/schema_migrations/20200922231755
@@ -0,0 +1 @@
+0019105cd2112e138b9926dc000b0c54b41fca6dfb2c4f658900040e0ecb3b70 \ No newline at end of file
diff --git a/db/schema_migrations/20200923071622 b/db/schema_migrations/20200923071622
new file mode 100644
index 00000000000..629b241ce0a
--- /dev/null
+++ b/db/schema_migrations/20200923071622
@@ -0,0 +1 @@
+1751fa6522a88582cb6a580acc95665f4e3f3a879f2365d5fd0a824ad1b4806d \ No newline at end of file
diff --git a/db/schema_migrations/20200923071644 b/db/schema_migrations/20200923071644
new file mode 100644
index 00000000000..431ed5af1f0
--- /dev/null
+++ b/db/schema_migrations/20200923071644
@@ -0,0 +1 @@
+0df2b1e65ef0dc563c55e575968e4fd768cec2e713e3b1c999cf584ef62b629d \ No newline at end of file
diff --git a/db/schema_migrations/20200923102312 b/db/schema_migrations/20200923102312
new file mode 100644
index 00000000000..52ed07034fc
--- /dev/null
+++ b/db/schema_migrations/20200923102312
@@ -0,0 +1 @@
+f19e61e3863905885c8b5b2129be2586d912d616a5b3b54e99a72c5760082059 \ No newline at end of file
diff --git a/db/schema_migrations/20200923130057 b/db/schema_migrations/20200923130057
new file mode 100644
index 00000000000..e95c2da0a1d
--- /dev/null
+++ b/db/schema_migrations/20200923130057
@@ -0,0 +1 @@
+84b272d61f6ab6e9f9f8eb059ba139a3fa0d2f1bbeb337f2e4e7cd4034822b44 \ No newline at end of file
diff --git a/db/schema_migrations/20200923140404 b/db/schema_migrations/20200923140404
new file mode 100644
index 00000000000..9c1bfd59b4c
--- /dev/null
+++ b/db/schema_migrations/20200923140404
@@ -0,0 +1 @@
+8a1898f62a47575c7ea428198163e04ff427e7ab6cd04eb9897930a6b7753681 \ No newline at end of file
diff --git a/db/schema_migrations/20200924035825 b/db/schema_migrations/20200924035825
new file mode 100644
index 00000000000..0c27ed47732
--- /dev/null
+++ b/db/schema_migrations/20200924035825
@@ -0,0 +1 @@
+d413e19c8ddaba4556cf36a38e03b1c7c46ee7edf7e56692028e066f97605784 \ No newline at end of file
diff --git a/db/schema_migrations/20200925112104 b/db/schema_migrations/20200925112104
new file mode 100644
index 00000000000..bb0f8032a84
--- /dev/null
+++ b/db/schema_migrations/20200925112104
@@ -0,0 +1 @@
+a14df9e9a115d39636b29bfe73fb175bb1e8d4510bee26e3e0c6c979949b13c4 \ No newline at end of file
diff --git a/db/schema_migrations/20200925114522 b/db/schema_migrations/20200925114522
new file mode 100644
index 00000000000..4b8d893833d
--- /dev/null
+++ b/db/schema_migrations/20200925114522
@@ -0,0 +1 @@
+7d43d2fa91e27eaf9399cf0ce9e4375e849deb71b12d4891455bc51392bce14a \ No newline at end of file
diff --git a/db/schema_migrations/20200925125321 b/db/schema_migrations/20200925125321
new file mode 100644
index 00000000000..103cd02c5e1
--- /dev/null
+++ b/db/schema_migrations/20200925125321
@@ -0,0 +1 @@
+d1d2f7d5f70e912b1d0a77417a96b9e16ffc620eb8c941ed4aa9a8c166ba26e0 \ No newline at end of file
diff --git a/db/schema_migrations/20200925153423 b/db/schema_migrations/20200925153423
new file mode 100644
index 00000000000..ffbdc2c81c2
--- /dev/null
+++ b/db/schema_migrations/20200925153423
@@ -0,0 +1 @@
+f445704e51dad2369719d8c0931c3314793fa90ba6b5a383df503ea4f6dafd20 \ No newline at end of file
diff --git a/db/schema_migrations/20200925193815 b/db/schema_migrations/20200925193815
new file mode 100644
index 00000000000..fdfa07c5a99
--- /dev/null
+++ b/db/schema_migrations/20200925193815
@@ -0,0 +1 @@
+a814b745b4911fc6c80971e6c0c19e6d64ca30cb94fa87a94bc1adf8c07b1c87 \ No newline at end of file
diff --git a/db/schema_migrations/20200925193906 b/db/schema_migrations/20200925193906
new file mode 100644
index 00000000000..dd9c1e4cd3b
--- /dev/null
+++ b/db/schema_migrations/20200925193906
@@ -0,0 +1 @@
+a915ccf5df0ec803286205916ffcd34b1410d1cc4da84f8299b63b3665d69e09 \ No newline at end of file
diff --git a/db/schema_migrations/20200925194006 b/db/schema_migrations/20200925194006
new file mode 100644
index 00000000000..fc89ebb9f7b
--- /dev/null
+++ b/db/schema_migrations/20200925194006
@@ -0,0 +1 @@
+28a71a380be0ef08389defac604c351f0a7f31b6c03a7c40aabe47bf09e6a485 \ No newline at end of file
diff --git a/db/schema_migrations/20200927224750 b/db/schema_migrations/20200927224750
new file mode 100644
index 00000000000..9454bec58c5
--- /dev/null
+++ b/db/schema_migrations/20200927224750
@@ -0,0 +1 @@
+8e0c5be3d6fe2d0d718c7b7a99d84b14dfc6006f780ec0622eb5aae937e6b367 \ No newline at end of file
diff --git a/db/schema_migrations/20200928095732 b/db/schema_migrations/20200928095732
new file mode 100644
index 00000000000..15f0d5e3eae
--- /dev/null
+++ b/db/schema_migrations/20200928095732
@@ -0,0 +1 @@
+5ff9bf6c542f686729abf18f282351d9bb5b895070c6f06c5fc8d125be4a38f7 \ No newline at end of file
diff --git a/db/schema_migrations/20200928100408 b/db/schema_migrations/20200928100408
new file mode 100644
index 00000000000..e49c397924d
--- /dev/null
+++ b/db/schema_migrations/20200928100408
@@ -0,0 +1 @@
+56984f720cfde6ad28b8612e092809252f948797fecb64dfc3b82d5b3b74f7ec \ No newline at end of file
diff --git a/db/schema_migrations/20200928125258 b/db/schema_migrations/20200928125258
new file mode 100644
index 00000000000..d9756bd6ee6
--- /dev/null
+++ b/db/schema_migrations/20200928125258
@@ -0,0 +1 @@
+46579fd0313068f3c9c1631f1da4a0b20513759a54dad4841bcea7d6c727646a \ No newline at end of file
diff --git a/db/schema_migrations/20200928131934 b/db/schema_migrations/20200928131934
new file mode 100644
index 00000000000..952e2121d35
--- /dev/null
+++ b/db/schema_migrations/20200928131934
@@ -0,0 +1 @@
+106757b0f30d3c89fcafa13be92271090fa107831fd538ee087d7ce212842492 \ No newline at end of file
diff --git a/db/schema_migrations/20200928164807 b/db/schema_migrations/20200928164807
new file mode 100644
index 00000000000..3efd3c56402
--- /dev/null
+++ b/db/schema_migrations/20200928164807
@@ -0,0 +1 @@
+346d0e913212d6e84528d47228ba7e6d0cf4a396e7fc921f7c684acfaaeeedb8 \ No newline at end of file
diff --git a/db/schema_migrations/20200928203531 b/db/schema_migrations/20200928203531
new file mode 100644
index 00000000000..229e2dc9b1f
--- /dev/null
+++ b/db/schema_migrations/20200928203531
@@ -0,0 +1 @@
+fc9719e0822d17eacb375b4adb2eac35afba04cafc2bd429c82c502d2fe5f12e \ No newline at end of file
diff --git a/db/schema_migrations/20200928210524 b/db/schema_migrations/20200928210524
new file mode 100644
index 00000000000..41905703d01
--- /dev/null
+++ b/db/schema_migrations/20200928210524
@@ -0,0 +1 @@
+788fd828a7aa8fb8741f13596f54fc4d9f4f5caeaf34d08aed47bbefe363ae75 \ No newline at end of file
diff --git a/db/schema_migrations/20200928233632 b/db/schema_migrations/20200928233632
new file mode 100644
index 00000000000..d66fc8310f2
--- /dev/null
+++ b/db/schema_migrations/20200928233632
@@ -0,0 +1 @@
+c390843c8a93ca429d1442d7b54f5f9dc01e0343c71ed1a046f11968cc10810d \ No newline at end of file
diff --git a/db/schema_migrations/20200929032729 b/db/schema_migrations/20200929032729
new file mode 100644
index 00000000000..cd38d67c78a
--- /dev/null
+++ b/db/schema_migrations/20200929032729
@@ -0,0 +1 @@
+77fa26f97216c1fa3d0b046dfabac92a5afa2a0eaf33439117b29ac81e740e4a \ No newline at end of file
diff --git a/db/schema_migrations/20200929052138 b/db/schema_migrations/20200929052138
new file mode 100644
index 00000000000..05c56a31270
--- /dev/null
+++ b/db/schema_migrations/20200929052138
@@ -0,0 +1 @@
+30b84d137fcb17eaca86f1bec52d6e20c972f7083d4c983e2bb397c9126b5f0c \ No newline at end of file
diff --git a/db/schema_migrations/20200929063159 b/db/schema_migrations/20200929063159
new file mode 100644
index 00000000000..b7815e9bb39
--- /dev/null
+++ b/db/schema_migrations/20200929063159
@@ -0,0 +1 @@
+9ef08404b964ccae3e12332340f16c6b8bb2bbdb2c04ba105fe1c0c7e6bf84f2 \ No newline at end of file
diff --git a/db/schema_migrations/20200929113254 b/db/schema_migrations/20200929113254
new file mode 100644
index 00000000000..172a6eabd66
--- /dev/null
+++ b/db/schema_migrations/20200929113254
@@ -0,0 +1 @@
+260f392c3ff257960dc7b198473056e7bf9b9a668403d2f05391d2b7989cf83c \ No newline at end of file
diff --git a/db/schema_migrations/20200929114107 b/db/schema_migrations/20200929114107
new file mode 100644
index 00000000000..f3b7a7a3bad
--- /dev/null
+++ b/db/schema_migrations/20200929114107
@@ -0,0 +1 @@
+f5d4b534c230f9ac7f285bccd096a7d51bf5c9e7a73f293fafaff89bb1ee12e1 \ No newline at end of file
diff --git a/db/schema_migrations/20200930094812 b/db/schema_migrations/20200930094812
new file mode 100644
index 00000000000..ad03614e47d
--- /dev/null
+++ b/db/schema_migrations/20200930094812
@@ -0,0 +1 @@
+b92b48a17bfd350a70017bfee99bcfb3dbc5ae9e33c8f23ab593666e5c3900aa \ No newline at end of file
diff --git a/db/schema_migrations/20200930131343 b/db/schema_migrations/20200930131343
new file mode 100644
index 00000000000..a872607f241
--- /dev/null
+++ b/db/schema_migrations/20200930131343
@@ -0,0 +1 @@
+45530bb3090d9e8df3a79f42a06b042e0c40f6e185078c6d79d7ec334175c7d5 \ No newline at end of file
diff --git a/db/schema_migrations/20200930132319 b/db/schema_migrations/20200930132319
new file mode 100644
index 00000000000..7bffd187de2
--- /dev/null
+++ b/db/schema_migrations/20200930132319
@@ -0,0 +1 @@
+1ded640c70d5e569f0f26729c96d2dc27c528bcb045e28f073ed8fce9f918d95 \ No newline at end of file
diff --git a/db/schema_migrations/20200930144340 b/db/schema_migrations/20200930144340
new file mode 100644
index 00000000000..4ac1bae7537
--- /dev/null
+++ b/db/schema_migrations/20200930144340
@@ -0,0 +1 @@
+febc66dbb48fbd281223ab9466cc5d94e945e8164fa9db0ee149c29e653b3eb2 \ No newline at end of file
diff --git a/db/schema_migrations/20201001022100 b/db/schema_migrations/20201001022100
new file mode 100644
index 00000000000..9c11e9e6094
--- /dev/null
+++ b/db/schema_migrations/20201001022100
@@ -0,0 +1 @@
+a581071767c5484e8286951854b0effe04d4b8951f208f10ceb4812940363959 \ No newline at end of file
diff --git a/db/schema_migrations/20201001101136 b/db/schema_migrations/20201001101136
new file mode 100644
index 00000000000..ecfc37cdfc5
--- /dev/null
+++ b/db/schema_migrations/20201001101136
@@ -0,0 +1 @@
+f3f9dd503d2c2695d5cd32ea87ff11e45832b1650df3186c7f71c984fc59ad24 \ No newline at end of file
diff --git a/db/schema_migrations/20201002012659 b/db/schema_migrations/20201002012659
new file mode 100644
index 00000000000..6a6d33389f9
--- /dev/null
+++ b/db/schema_migrations/20201002012659
@@ -0,0 +1 @@
+8a12c3c4f674d2a36df56a89bfd32e0f3945e73605460bdf2a8b0aa1308f5b19 \ No newline at end of file
diff --git a/db/schema_migrations/20201002094617 b/db/schema_migrations/20201002094617
new file mode 100644
index 00000000000..9c4d6155700
--- /dev/null
+++ b/db/schema_migrations/20201002094617
@@ -0,0 +1 @@
+823c72852eeb17eaf43c58e936ac25effdacb335f76562c68a4f90d5b1a32021 \ No newline at end of file
diff --git a/db/schema_migrations/20201002175953 b/db/schema_migrations/20201002175953
new file mode 100644
index 00000000000..df5f64c0deb
--- /dev/null
+++ b/db/schema_migrations/20201002175953
@@ -0,0 +1 @@
+619e788f8868a2ff602a06e0025154b0b10b17cd69edcce70378e11750d5e686 \ No newline at end of file
diff --git a/db/schema_migrations/20201004163918 b/db/schema_migrations/20201004163918
new file mode 100644
index 00000000000..e77e000bac8
--- /dev/null
+++ b/db/schema_migrations/20201004163918
@@ -0,0 +1 @@
+e25da3da50ed2396afe3bcb1ff441b5f1f0a43c0e23d66140a160d42f1b66a1a \ No newline at end of file
diff --git a/db/schema_migrations/20201005092703 b/db/schema_migrations/20201005092703
new file mode 100644
index 00000000000..54969553788
--- /dev/null
+++ b/db/schema_migrations/20201005092703
@@ -0,0 +1 @@
+550fb12fe5e180ab52bd6d012cf1869544130049e83ccbefd4b132831a074f71 \ No newline at end of file
diff --git a/db/schema_migrations/20201005092709 b/db/schema_migrations/20201005092709
new file mode 100644
index 00000000000..e0a7ecad91f
--- /dev/null
+++ b/db/schema_migrations/20201005092709
@@ -0,0 +1 @@
+5d9dbae8074627c41170e70849a3e6b71e20da473f312227df462c894c194efb \ No newline at end of file
diff --git a/db/schema_migrations/20201005092753 b/db/schema_migrations/20201005092753
new file mode 100644
index 00000000000..a519b6b3f1e
--- /dev/null
+++ b/db/schema_migrations/20201005092753
@@ -0,0 +1 @@
+b59670c031a146e7a1a8277ba51080a6c120724a00c7612933ff1ed44bc8dd60 \ No newline at end of file
diff --git a/db/schema_migrations/20201005094331 b/db/schema_migrations/20201005094331
new file mode 100644
index 00000000000..63b48d9fdaf
--- /dev/null
+++ b/db/schema_migrations/20201005094331
@@ -0,0 +1 @@
+b024bc44406810a30a3aebb33dd1355468448b4ebf9c76fe7811148044241551 \ No newline at end of file
diff --git a/db/schema_migrations/20201005153955 b/db/schema_migrations/20201005153955
new file mode 100644
index 00000000000..19d8b921ceb
--- /dev/null
+++ b/db/schema_migrations/20201005153955
@@ -0,0 +1 @@
+563f76e0635b54c2a5cb78cf5e87ea217acf3b6c853518588fcdeadef9dcc951 \ No newline at end of file
diff --git a/db/schema_migrations/20201006014605 b/db/schema_migrations/20201006014605
new file mode 100644
index 00000000000..92209fcd127
--- /dev/null
+++ b/db/schema_migrations/20201006014605
@@ -0,0 +1 @@
+d1a636c0b0c7f11bf5d6e882970a5286a28c3f060f89df3ac51df2e7c86f042e \ No newline at end of file
diff --git a/db/schema_migrations/20201007115209 b/db/schema_migrations/20201007115209
new file mode 100644
index 00000000000..acd0a056bbd
--- /dev/null
+++ b/db/schema_migrations/20201007115209
@@ -0,0 +1 @@
+761cad9a584d98e3086e716f7a5c1d9b4aba87b084efcfcee7272cfdf1179372 \ No newline at end of file
diff --git a/db/schema_migrations/20201009090954 b/db/schema_migrations/20201009090954
new file mode 100644
index 00000000000..5d5ca8ff29b
--- /dev/null
+++ b/db/schema_migrations/20201009090954
@@ -0,0 +1 @@
+d0944a864a1a89e9339eb1f8ffab683df1a5bb90f7b7a16cabd4871f34d1cd48 \ No newline at end of file
diff --git a/db/schema_migrations/20201012194936 b/db/schema_migrations/20201012194936
new file mode 100644
index 00000000000..c626e091e5e
--- /dev/null
+++ b/db/schema_migrations/20201012194936
@@ -0,0 +1 @@
+823d23d8ce8959762a7cadb883ed6d36a46fedaf238ea955d93136277d55cad5 \ No newline at end of file
diff --git a/db/schema_migrations/20201014142521 b/db/schema_migrations/20201014142521
new file mode 100644
index 00000000000..d87f01628c3
--- /dev/null
+++ b/db/schema_migrations/20201014142521
@@ -0,0 +1 @@
+aed103bb25b70eb8f6387d84225a8e51672a83c4586ccc65da3011ef010da4b1 \ No newline at end of file
diff --git a/db/schema_migrations/20201014205300 b/db/schema_migrations/20201014205300
new file mode 100644
index 00000000000..7d183f22624
--- /dev/null
+++ b/db/schema_migrations/20201014205300
@@ -0,0 +1 @@
+05352623a59d56c1633317ba7dbaba7d75bb8e529a748a90512dcf3641b8d3cb \ No newline at end of file
diff --git a/db/schema_migrations/20201015073808 b/db/schema_migrations/20201015073808
new file mode 100644
index 00000000000..c14d0b7a528
--- /dev/null
+++ b/db/schema_migrations/20201015073808
@@ -0,0 +1 @@
+e44ab2a7b3014b44d7d84de1f7e618d2fc89f98b8d59f5f6fa331544e206355f \ No newline at end of file
diff --git a/db/schema_migrations/20201015154527 b/db/schema_migrations/20201015154527
new file mode 100644
index 00000000000..995483bef49
--- /dev/null
+++ b/db/schema_migrations/20201015154527
@@ -0,0 +1 @@
+319502924c38f5e78e40226a55ad99db53b246aa0d35eb945ac9a96f9e55f584 \ No newline at end of file
diff --git a/db/structure.sql b/db/structure.sql
index 6e921810cfb..4e6fc7e9260 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -19,7 +19,6 @@ IF (TG_OP = 'DELETE') THEN
ELSIF (TG_OP = 'UPDATE') THEN
UPDATE audit_events_part_5fc467ac26
SET author_id = NEW.author_id,
- type = NEW.type,
entity_id = NEW.entity_id,
entity_type = NEW.entity_type,
details = NEW.details,
@@ -34,7 +33,6 @@ ELSIF (TG_OP = 'UPDATE') THEN
ELSIF (TG_OP = 'INSERT') THEN
INSERT INTO audit_events_part_5fc467ac26 (id,
author_id,
- type,
entity_id,
entity_type,
details,
@@ -47,7 +45,6 @@ ELSIF (TG_OP = 'INSERT') THEN
created_at)
VALUES (NEW.id,
NEW.author_id,
- NEW.type,
NEW.entity_id,
NEW.entity_type,
NEW.details,
@@ -69,7 +66,6 @@ COMMENT ON FUNCTION table_sync_function_2be879775d() IS 'Partitioning migration:
CREATE TABLE audit_events_part_5fc467ac26 (
id bigint NOT NULL,
author_id integer NOT NULL,
- type character varying,
entity_id integer NOT NULL,
entity_type character varying NOT NULL,
details text,
@@ -8830,6 +8826,31 @@ CREATE SEQUENCE alert_management_alerts_id_seq
ALTER SEQUENCE alert_management_alerts_id_seq OWNED BY alert_management_alerts.id;
+CREATE TABLE alert_management_http_integrations (
+ id bigint NOT NULL,
+ created_at timestamp with time zone NOT NULL,
+ updated_at timestamp with time zone NOT NULL,
+ project_id bigint NOT NULL,
+ active boolean DEFAULT false NOT NULL,
+ encrypted_token text NOT NULL,
+ encrypted_token_iv text NOT NULL,
+ endpoint_identifier text NOT NULL,
+ name text NOT NULL,
+ CONSTRAINT check_286943b636 CHECK ((char_length(encrypted_token_iv) <= 255)),
+ CONSTRAINT check_392143ccf4 CHECK ((char_length(name) <= 255)),
+ CONSTRAINT check_e270820180 CHECK ((char_length(endpoint_identifier) <= 255)),
+ CONSTRAINT check_f68577c4af CHECK ((char_length(encrypted_token) <= 255))
+);
+
+CREATE SEQUENCE alert_management_http_integrations_id_seq
+ START WITH 1
+ INCREMENT BY 1
+ NO MINVALUE
+ NO MAXVALUE
+ CACHE 1;
+
+ALTER SEQUENCE alert_management_http_integrations_id_seq OWNED BY alert_management_http_integrations.id;
+
CREATE TABLE alerts_service_data (
id bigint NOT NULL,
service_id integer NOT NULL,
@@ -9031,7 +9052,6 @@ CREATE TABLE application_settings (
session_expire_delay integer DEFAULT 10080 NOT NULL,
import_sources text,
help_page_text text,
- admin_notification_email character varying,
shared_runners_enabled boolean DEFAULT true NOT NULL,
max_artifacts_size integer DEFAULT 100 NOT NULL,
runners_registration_token character varying,
@@ -9146,7 +9166,6 @@ CREATE TABLE application_settings (
snowplow_enabled boolean DEFAULT false NOT NULL,
snowplow_collector_hostname character varying,
snowplow_cookie_domain character varying,
- instance_statistics_visibility_private boolean DEFAULT false NOT NULL,
web_ide_clientside_preview_enabled boolean DEFAULT false NOT NULL,
user_show_add_ssh_key_message boolean DEFAULT true NOT NULL,
custom_project_templates_group_id integer,
@@ -9196,7 +9215,6 @@ CREATE TABLE application_settings (
throttle_incident_management_notification_enabled boolean DEFAULT false NOT NULL,
throttle_incident_management_notification_period_in_seconds integer DEFAULT 3600,
throttle_incident_management_notification_per_period integer DEFAULT 3600,
- snowplow_iglu_registry_url character varying(255),
push_event_hooks_limit integer DEFAULT 3 NOT NULL,
push_event_activities_limit integer DEFAULT 3 NOT NULL,
custom_http_clone_url_root character varying(511),
@@ -9272,8 +9290,13 @@ CREATE TABLE application_settings (
elasticsearch_client_request_timeout integer DEFAULT 0 NOT NULL,
gitpod_enabled boolean DEFAULT false NOT NULL,
gitpod_url text DEFAULT 'https://gitpod.io/'::text,
+ abuse_notification_email character varying,
+ require_admin_approval_after_user_signup boolean DEFAULT false NOT NULL,
+ help_page_documentation_base_url text,
+ automatic_purchased_storage_allocation boolean DEFAULT false NOT NULL,
CONSTRAINT check_2dba05b802 CHECK ((char_length(gitpod_url) <= 255)),
CONSTRAINT check_51700b31b5 CHECK ((char_length(default_branch_name) <= 255)),
+ CONSTRAINT check_57123c9593 CHECK ((char_length(help_page_documentation_base_url) <= 255)),
CONSTRAINT check_9c6c447a13 CHECK ((char_length(maintenance_mode_message) <= 255)),
CONSTRAINT check_d03919528d CHECK ((char_length(container_registry_vendor) <= 255)),
CONSTRAINT check_d820146492 CHECK ((char_length(spam_check_endpoint_url) <= 255)),
@@ -9314,6 +9337,7 @@ CREATE TABLE approval_merge_request_rules (
rule_type smallint DEFAULT 1 NOT NULL,
report_type smallint,
section text,
+ modified_from_project_rule boolean DEFAULT false NOT NULL,
CONSTRAINT check_6fca5928b2 CHECK ((char_length(section) <= 255))
);
@@ -9514,7 +9538,6 @@ ALTER SEQUENCE atlassian_identities_user_id_seq OWNED BY atlassian_identities.us
CREATE TABLE audit_events (
id integer NOT NULL,
author_id integer NOT NULL,
- type character varying,
entity_id integer NOT NULL,
entity_type character varying NOT NULL,
details text,
@@ -9793,6 +9816,73 @@ CREATE SEQUENCE broadcast_messages_id_seq
ALTER SEQUENCE broadcast_messages_id_seq OWNED BY broadcast_messages.id;
+CREATE TABLE bulk_import_configurations (
+ id bigint NOT NULL,
+ bulk_import_id integer NOT NULL,
+ encrypted_url text,
+ encrypted_url_iv text,
+ encrypted_access_token text,
+ encrypted_access_token_iv text,
+ created_at timestamp with time zone NOT NULL,
+ updated_at timestamp with time zone NOT NULL
+);
+
+CREATE SEQUENCE bulk_import_configurations_id_seq
+ START WITH 1
+ INCREMENT BY 1
+ NO MINVALUE
+ NO MAXVALUE
+ CACHE 1;
+
+ALTER SEQUENCE bulk_import_configurations_id_seq OWNED BY bulk_import_configurations.id;
+
+CREATE TABLE bulk_import_entities (
+ id bigint NOT NULL,
+ bulk_import_id bigint NOT NULL,
+ parent_id bigint,
+ namespace_id bigint,
+ project_id bigint,
+ source_type smallint NOT NULL,
+ source_full_path text NOT NULL,
+ destination_name text NOT NULL,
+ destination_namespace text NOT NULL,
+ status smallint NOT NULL,
+ jid text,
+ created_at timestamp with time zone NOT NULL,
+ updated_at timestamp with time zone NOT NULL,
+ CONSTRAINT check_13f279f7da CHECK ((char_length(source_full_path) <= 255)),
+ CONSTRAINT check_715d725ea2 CHECK ((char_length(destination_name) <= 255)),
+ CONSTRAINT check_796a4d9cc6 CHECK ((char_length(jid) <= 255)),
+ CONSTRAINT check_b834fff4d9 CHECK ((char_length(destination_namespace) <= 255))
+);
+
+CREATE SEQUENCE bulk_import_entities_id_seq
+ START WITH 1
+ INCREMENT BY 1
+ NO MINVALUE
+ NO MAXVALUE
+ CACHE 1;
+
+ALTER SEQUENCE bulk_import_entities_id_seq OWNED BY bulk_import_entities.id;
+
+CREATE TABLE bulk_imports (
+ id bigint NOT NULL,
+ user_id integer NOT NULL,
+ source_type smallint NOT NULL,
+ status smallint NOT NULL,
+ created_at timestamp with time zone NOT NULL,
+ updated_at timestamp with time zone NOT NULL
+);
+
+CREATE SEQUENCE bulk_imports_id_seq
+ START WITH 1
+ INCREMENT BY 1
+ NO MINVALUE
+ NO MAXVALUE
+ CACHE 1;
+
+ALTER SEQUENCE bulk_imports_id_seq OWNED BY bulk_imports.id;
+
CREATE TABLE chat_names (
id integer NOT NULL,
user_id integer NOT NULL,
@@ -9889,7 +9979,8 @@ CREATE TABLE ci_build_trace_chunks (
chunk_index integer NOT NULL,
data_store integer NOT NULL,
raw_data bytea,
- checksum bytea
+ checksum bytea,
+ lock_version integer DEFAULT 0 NOT NULL
);
CREATE SEQUENCE ci_build_trace_chunks_id_seq
@@ -10050,6 +10141,24 @@ CREATE SEQUENCE ci_daily_build_group_report_results_id_seq
ALTER SEQUENCE ci_daily_build_group_report_results_id_seq OWNED BY ci_daily_build_group_report_results.id;
+CREATE TABLE ci_deleted_objects (
+ id bigint NOT NULL,
+ file_store smallint DEFAULT 1 NOT NULL,
+ pick_up_at timestamp with time zone DEFAULT now() NOT NULL,
+ store_dir text NOT NULL,
+ file text NOT NULL,
+ CONSTRAINT check_5e151d6912 CHECK ((char_length(store_dir) <= 1024))
+);
+
+CREATE SEQUENCE ci_deleted_objects_id_seq
+ START WITH 1
+ INCREMENT BY 1
+ NO MINVALUE
+ NO MAXVALUE
+ CACHE 1;
+
+ALTER SEQUENCE ci_deleted_objects_id_seq OWNED BY ci_deleted_objects.id;
+
CREATE TABLE ci_freeze_periods (
id bigint NOT NULL,
project_id bigint NOT NULL,
@@ -10701,7 +10810,6 @@ ALTER SEQUENCE cluster_projects_id_seq OWNED BY cluster_projects.id;
CREATE TABLE cluster_providers_aws (
id bigint NOT NULL,
cluster_id bigint NOT NULL,
- created_by_user_id integer,
num_nodes integer NOT NULL,
status integer NOT NULL,
created_at timestamp with time zone NOT NULL,
@@ -11063,6 +11171,27 @@ CREATE SEQUENCE commit_user_mentions_id_seq
ALTER SEQUENCE commit_user_mentions_id_seq OWNED BY commit_user_mentions.id;
+CREATE TABLE compliance_management_frameworks (
+ id bigint NOT NULL,
+ group_id bigint,
+ name text NOT NULL,
+ description text NOT NULL,
+ color text NOT NULL,
+ namespace_id integer NOT NULL,
+ CONSTRAINT check_08cd34b2c2 CHECK ((char_length(color) <= 10)),
+ CONSTRAINT check_1617e0b87e CHECK ((char_length(description) <= 255)),
+ CONSTRAINT check_ab00bc2193 CHECK ((char_length(name) <= 255))
+);
+
+CREATE SEQUENCE compliance_management_frameworks_id_seq
+ START WITH 1
+ INCREMENT BY 1
+ NO MINVALUE
+ NO MAXVALUE
+ CACHE 1;
+
+ALTER SEQUENCE compliance_management_frameworks_id_seq OWNED BY compliance_management_frameworks.id;
+
CREATE TABLE container_expiration_policies (
project_id bigint NOT NULL,
created_at timestamp with time zone NOT NULL,
@@ -11083,7 +11212,8 @@ CREATE TABLE container_repositories (
name character varying NOT NULL,
created_at timestamp without time zone NOT NULL,
updated_at timestamp without time zone NOT NULL,
- status smallint
+ status smallint,
+ expiration_policy_started_at timestamp with time zone
);
CREATE SEQUENCE container_repositories_id_seq
@@ -11169,6 +11299,9 @@ CREATE TABLE dast_scanner_profiles (
spider_timeout smallint,
target_timeout smallint,
name text NOT NULL,
+ scan_type smallint DEFAULT 1 NOT NULL,
+ use_ajax_spider boolean DEFAULT false NOT NULL,
+ show_debug_messages boolean DEFAULT false NOT NULL,
CONSTRAINT check_568568fabf CHECK ((char_length(name) <= 255))
);
@@ -11233,7 +11366,9 @@ CREATE TABLE dast_site_validations (
validation_strategy smallint NOT NULL,
url_base text NOT NULL,
url_path text NOT NULL,
+ state text DEFAULT 'pending'::text NOT NULL,
CONSTRAINT check_13b34efe4b CHECK ((char_length(url_path) <= 255)),
+ CONSTRAINT check_283be72e9b CHECK ((char_length(state) <= 255)),
CONSTRAINT check_cd3b538210 CHECK ((char_length(url_base) <= 255))
);
@@ -11411,7 +11546,8 @@ CREATE TABLE design_management_designs (
project_id integer NOT NULL,
issue_id integer,
filename character varying NOT NULL,
- relative_position integer
+ relative_position integer,
+ CONSTRAINT check_07155e2715 CHECK ((char_length((filename)::text) <= 255))
);
CREATE SEQUENCE design_management_designs_id_seq
@@ -12488,6 +12624,7 @@ CREATE TABLE group_import_states (
status smallint DEFAULT 0 NOT NULL,
jid text,
last_error text,
+ user_id bigint,
CONSTRAINT check_87b58f6b30 CHECK ((char_length(last_error) <= 255)),
CONSTRAINT check_96558fff96 CHECK ((char_length(jid) <= 100))
);
@@ -12669,11 +12806,44 @@ CREATE SEQUENCE issuable_severities_id_seq
ALTER SEQUENCE issuable_severities_id_seq OWNED BY issuable_severities.id;
+CREATE TABLE issuable_slas (
+ id bigint NOT NULL,
+ issue_id bigint NOT NULL,
+ due_at timestamp with time zone NOT NULL
+);
+
+CREATE SEQUENCE issuable_slas_id_seq
+ START WITH 1
+ INCREMENT BY 1
+ NO MINVALUE
+ NO MAXVALUE
+ CACHE 1;
+
+ALTER SEQUENCE issuable_slas_id_seq OWNED BY issuable_slas.id;
+
CREATE TABLE issue_assignees (
user_id integer NOT NULL,
issue_id integer NOT NULL
);
+CREATE TABLE issue_email_participants (
+ id bigint NOT NULL,
+ issue_id bigint NOT NULL,
+ created_at timestamp with time zone NOT NULL,
+ updated_at timestamp with time zone NOT NULL,
+ email text NOT NULL,
+ CONSTRAINT check_2c321d408d CHECK ((char_length(email) <= 255))
+);
+
+CREATE SEQUENCE issue_email_participants_id_seq
+ START WITH 1
+ INCREMENT BY 1
+ NO MINVALUE
+ NO MAXVALUE
+ CACHE 1;
+
+ALTER SEQUENCE issue_email_participants_id_seq OWNED BY issue_email_participants.id;
+
CREATE TABLE issue_links (
id integer NOT NULL,
source_id integer NOT NULL,
@@ -13561,7 +13731,10 @@ CREATE TABLE namespace_settings (
created_at timestamp with time zone NOT NULL,
updated_at timestamp with time zone NOT NULL,
namespace_id integer NOT NULL,
- prevent_forking_outside_group boolean DEFAULT false NOT NULL
+ prevent_forking_outside_group boolean DEFAULT false NOT NULL,
+ allow_mfa_for_subgroups boolean DEFAULT true NOT NULL,
+ default_branch_name text,
+ CONSTRAINT check_0ba93c78c7 CHECK ((char_length(default_branch_name) <= 255))
);
CREATE TABLE namespace_statistics (
@@ -13727,7 +13900,8 @@ CREATE TABLE notification_settings (
notification_email character varying,
fixed_pipeline boolean,
new_release boolean,
- moved_project boolean DEFAULT true NOT NULL
+ moved_project boolean DEFAULT true NOT NULL,
+ change_reviewer_merge_request boolean
);
CREATE SEQUENCE notification_settings_id_seq
@@ -14069,6 +14243,25 @@ CREATE SEQUENCE packages_dependency_links_id_seq
ALTER SEQUENCE packages_dependency_links_id_seq OWNED BY packages_dependency_links.id;
+CREATE TABLE packages_events (
+ id bigint NOT NULL,
+ event_type smallint NOT NULL,
+ event_scope smallint NOT NULL,
+ originator_type smallint NOT NULL,
+ originator bigint,
+ created_at timestamp with time zone NOT NULL,
+ package_id bigint
+);
+
+CREATE SEQUENCE packages_events_id_seq
+ START WITH 1
+ INCREMENT BY 1
+ NO MINVALUE
+ NO MAXVALUE
+ CACHE 1;
+
+ALTER SEQUENCE packages_events_id_seq OWNED BY packages_events.id;
+
CREATE TABLE packages_maven_metadata (
id bigint NOT NULL,
package_id bigint NOT NULL,
@@ -14121,7 +14314,8 @@ CREATE TABLE packages_package_files (
verified_at timestamp with time zone,
verification_failure character varying(255),
verification_retry_count integer,
- verification_checksum bytea
+ verification_checksum bytea,
+ CONSTRAINT check_4c5e6bb0b3 CHECK ((file_store IS NOT NULL))
);
CREATE SEQUENCE packages_package_files_id_seq
@@ -14363,7 +14557,10 @@ CREATE TABLE plan_limits (
nuget_max_file_size bigint DEFAULT 524288000 NOT NULL,
pypi_max_file_size bigint DEFAULT '3221225472'::bigint NOT NULL,
generic_packages_max_file_size bigint DEFAULT '5368709120'::bigint NOT NULL,
- project_feature_flags integer DEFAULT 200 NOT NULL
+ golang_max_file_size bigint DEFAULT 104857600 NOT NULL,
+ debian_max_file_size bigint DEFAULT '3221225472'::bigint NOT NULL,
+ project_feature_flags integer DEFAULT 200 NOT NULL,
+ ci_max_artifact_size_api_fuzzing integer DEFAULT 0 NOT NULL
);
CREATE SEQUENCE plan_limits_id_seq
@@ -14409,6 +14606,43 @@ CREATE SEQUENCE pool_repositories_id_seq
ALTER SEQUENCE pool_repositories_id_seq OWNED BY pool_repositories.id;
+CREATE VIEW postgres_indexes AS
+ SELECT (((pg_namespace.nspname)::text || '.'::text) || (pg_class.relname)::text) AS identifier,
+ pg_index.indexrelid,
+ pg_namespace.nspname AS schema,
+ pg_class.relname AS name,
+ pg_index.indisunique AS "unique",
+ pg_index.indisvalid AS valid_index,
+ pg_class.relispartition AS partitioned,
+ pg_index.indisexclusion AS exclusion,
+ pg_indexes.indexdef AS definition,
+ pg_relation_size((pg_class.oid)::regclass) AS ondisk_size_bytes
+ FROM (((pg_index
+ JOIN pg_class ON ((pg_class.oid = pg_index.indexrelid)))
+ JOIN pg_namespace ON ((pg_class.relnamespace = pg_namespace.oid)))
+ JOIN pg_indexes ON ((pg_class.relname = pg_indexes.indexname)))
+ WHERE ((pg_namespace.nspname <> 'pg_catalog'::name) AND (pg_namespace.nspname = ANY (ARRAY["current_schema"(), 'gitlab_partitions_dynamic'::name, 'gitlab_partitions_static'::name])));
+
+CREATE TABLE postgres_reindex_actions (
+ id bigint NOT NULL,
+ action_start timestamp with time zone NOT NULL,
+ action_end timestamp with time zone,
+ ondisk_size_bytes_start bigint NOT NULL,
+ ondisk_size_bytes_end bigint,
+ state smallint DEFAULT 0 NOT NULL,
+ index_identifier text NOT NULL,
+ CONSTRAINT check_f12527622c CHECK ((char_length(index_identifier) <= 255))
+);
+
+CREATE SEQUENCE postgres_reindex_actions_id_seq
+ START WITH 1
+ INCREMENT BY 1
+ NO MINVALUE
+ NO MAXVALUE
+ CACHE 1;
+
+ALTER SEQUENCE postgres_reindex_actions_id_seq OWNED BY postgres_reindex_actions.id;
+
CREATE TABLE programming_languages (
id integer NOT NULL,
name character varying NOT NULL,
@@ -14497,7 +14731,9 @@ ALTER SEQUENCE project_ci_cd_settings_id_seq OWNED BY project_ci_cd_settings.id;
CREATE TABLE project_compliance_framework_settings (
project_id bigint NOT NULL,
- framework smallint NOT NULL
+ framework smallint NOT NULL,
+ framework_id bigint,
+ CONSTRAINT check_d348de9e2d CHECK ((framework_id IS NOT NULL))
);
CREATE SEQUENCE project_compliance_framework_settings_project_id_seq
@@ -14664,6 +14900,8 @@ CREATE TABLE project_incident_management_settings (
encrypted_pagerduty_token bytea,
encrypted_pagerduty_token_iv bytea,
auto_close_incident boolean DEFAULT true NOT NULL,
+ sla_timer boolean DEFAULT false,
+ sla_timer_minutes integer,
CONSTRAINT pagerduty_token_iv_length_constraint CHECK ((octet_length(encrypted_pagerduty_token_iv) <= 12)),
CONSTRAINT pagerduty_token_length_constraint CHECK ((octet_length(encrypted_pagerduty_token) <= 255))
);
@@ -14710,7 +14948,8 @@ ALTER SEQUENCE project_mirror_data_id_seq OWNED BY project_mirror_data.id;
CREATE TABLE project_pages_metadata (
project_id bigint NOT NULL,
deployed boolean DEFAULT false NOT NULL,
- artifacts_archive_id bigint
+ artifacts_archive_id bigint,
+ pages_deployment_id bigint
);
CREATE TABLE project_repositories (
@@ -15314,6 +15553,22 @@ CREATE TABLE repository_languages (
share double precision NOT NULL
);
+CREATE TABLE required_code_owners_sections (
+ id bigint NOT NULL,
+ protected_branch_id bigint NOT NULL,
+ name text NOT NULL,
+ CONSTRAINT check_e58d53741e CHECK ((char_length(name) <= 1024))
+);
+
+CREATE SEQUENCE required_code_owners_sections_id_seq
+ START WITH 1
+ INCREMENT BY 1
+ NO MINVALUE
+ NO MAXVALUE
+ CACHE 1;
+
+ALTER SEQUENCE required_code_owners_sections_id_seq OWNED BY required_code_owners_sections.id;
+
CREATE TABLE requirements (
id bigint NOT NULL,
created_at timestamp with time zone NOT NULL,
@@ -15324,7 +15579,10 @@ CREATE TABLE requirements (
cached_markdown_version integer,
state smallint DEFAULT 1 NOT NULL,
title character varying(255) NOT NULL,
- title_html text
+ title_html text,
+ description text,
+ description_html text,
+ CONSTRAINT check_785ae25b9d CHECK ((char_length(description) <= 10000))
);
CREATE SEQUENCE requirements_id_seq
@@ -15494,6 +15752,25 @@ CREATE SEQUENCE routes_id_seq
ALTER SEQUENCE routes_id_seq OWNED BY routes.id;
+CREATE TABLE saml_group_links (
+ id bigint NOT NULL,
+ access_level smallint NOT NULL,
+ group_id bigint NOT NULL,
+ created_at timestamp with time zone NOT NULL,
+ updated_at timestamp with time zone NOT NULL,
+ saml_group_name text NOT NULL,
+ CONSTRAINT check_1b3fc49d1e CHECK ((char_length(saml_group_name) <= 255))
+);
+
+CREATE SEQUENCE saml_group_links_id_seq
+ START WITH 1
+ INCREMENT BY 1
+ NO MINVALUE
+ NO MAXVALUE
+ CACHE 1;
+
+ALTER SEQUENCE saml_group_links_id_seq OWNED BY saml_group_links.id;
+
CREATE TABLE saml_providers (
id integer NOT NULL,
group_id integer NOT NULL,
@@ -16910,6 +17187,7 @@ CREATE TABLE webauthn_registrations (
credential_xid text NOT NULL,
name text NOT NULL,
public_key text NOT NULL,
+ u2f_registration_id integer,
CONSTRAINT check_242f0cc65c CHECK ((char_length(credential_xid) <= 255)),
CONSTRAINT check_2f02e74321 CHECK ((char_length(name) <= 255))
);
@@ -17043,6 +17321,8 @@ ALTER TABLE ONLY alert_management_alert_user_mentions ALTER COLUMN id SET DEFAUL
ALTER TABLE ONLY alert_management_alerts ALTER COLUMN id SET DEFAULT nextval('alert_management_alerts_id_seq'::regclass);
+ALTER TABLE ONLY alert_management_http_integrations ALTER COLUMN id SET DEFAULT nextval('alert_management_http_integrations_id_seq'::regclass);
+
ALTER TABLE ONLY alerts_service_data ALTER COLUMN id SET DEFAULT nextval('alerts_service_data_id_seq'::regclass);
ALTER TABLE ONLY allowed_email_domains ALTER COLUMN id SET DEFAULT nextval('allowed_email_domains_id_seq'::regclass);
@@ -17111,6 +17391,12 @@ ALTER TABLE ONLY boards_epic_user_preferences ALTER COLUMN id SET DEFAULT nextva
ALTER TABLE ONLY broadcast_messages ALTER COLUMN id SET DEFAULT nextval('broadcast_messages_id_seq'::regclass);
+ALTER TABLE ONLY bulk_import_configurations ALTER COLUMN id SET DEFAULT nextval('bulk_import_configurations_id_seq'::regclass);
+
+ALTER TABLE ONLY bulk_import_entities ALTER COLUMN id SET DEFAULT nextval('bulk_import_entities_id_seq'::regclass);
+
+ALTER TABLE ONLY bulk_imports ALTER COLUMN id SET DEFAULT nextval('bulk_imports_id_seq'::regclass);
+
ALTER TABLE ONLY chat_names ALTER COLUMN id SET DEFAULT nextval('chat_names_id_seq'::regclass);
ALTER TABLE ONLY chat_teams ALTER COLUMN id SET DEFAULT nextval('chat_teams_id_seq'::regclass);
@@ -17133,6 +17419,8 @@ ALTER TABLE ONLY ci_builds_runner_session ALTER COLUMN id SET DEFAULT nextval('c
ALTER TABLE ONLY ci_daily_build_group_report_results ALTER COLUMN id SET DEFAULT nextval('ci_daily_build_group_report_results_id_seq'::regclass);
+ALTER TABLE ONLY ci_deleted_objects ALTER COLUMN id SET DEFAULT nextval('ci_deleted_objects_id_seq'::regclass);
+
ALTER TABLE ONLY ci_freeze_periods ALTER COLUMN id SET DEFAULT nextval('ci_freeze_periods_id_seq'::regclass);
ALTER TABLE ONLY ci_group_variables ALTER COLUMN id SET DEFAULT nextval('ci_group_variables_id_seq'::regclass);
@@ -17229,6 +17517,8 @@ ALTER TABLE ONLY clusters_kubernetes_namespaces ALTER COLUMN id SET DEFAULT next
ALTER TABLE ONLY commit_user_mentions ALTER COLUMN id SET DEFAULT nextval('commit_user_mentions_id_seq'::regclass);
+ALTER TABLE ONLY compliance_management_frameworks ALTER COLUMN id SET DEFAULT nextval('compliance_management_frameworks_id_seq'::regclass);
+
ALTER TABLE ONLY container_repositories ALTER COLUMN id SET DEFAULT nextval('container_repositories_id_seq'::regclass);
ALTER TABLE ONLY conversational_development_index_metrics ALTER COLUMN id SET DEFAULT nextval('conversational_development_index_metrics_id_seq'::regclass);
@@ -17379,6 +17669,10 @@ ALTER TABLE ONLY ip_restrictions ALTER COLUMN id SET DEFAULT nextval('ip_restric
ALTER TABLE ONLY issuable_severities ALTER COLUMN id SET DEFAULT nextval('issuable_severities_id_seq'::regclass);
+ALTER TABLE ONLY issuable_slas ALTER COLUMN id SET DEFAULT nextval('issuable_slas_id_seq'::regclass);
+
+ALTER TABLE ONLY issue_email_participants ALTER COLUMN id SET DEFAULT nextval('issue_email_participants_id_seq'::regclass);
+
ALTER TABLE ONLY issue_links ALTER COLUMN id SET DEFAULT nextval('issue_links_id_seq'::regclass);
ALTER TABLE ONLY issue_metrics ALTER COLUMN id SET DEFAULT nextval('issue_metrics_id_seq'::regclass);
@@ -17495,6 +17789,8 @@ ALTER TABLE ONLY packages_dependencies ALTER COLUMN id SET DEFAULT nextval('pack
ALTER TABLE ONLY packages_dependency_links ALTER COLUMN id SET DEFAULT nextval('packages_dependency_links_id_seq'::regclass);
+ALTER TABLE ONLY packages_events ALTER COLUMN id SET DEFAULT nextval('packages_events_id_seq'::regclass);
+
ALTER TABLE ONLY packages_maven_metadata ALTER COLUMN id SET DEFAULT nextval('packages_maven_metadata_id_seq'::regclass);
ALTER TABLE ONLY packages_package_files ALTER COLUMN id SET DEFAULT nextval('packages_package_files_id_seq'::regclass);
@@ -17521,6 +17817,8 @@ ALTER TABLE ONLY plans ALTER COLUMN id SET DEFAULT nextval('plans_id_seq'::regcl
ALTER TABLE ONLY pool_repositories ALTER COLUMN id SET DEFAULT nextval('pool_repositories_id_seq'::regclass);
+ALTER TABLE ONLY postgres_reindex_actions ALTER COLUMN id SET DEFAULT nextval('postgres_reindex_actions_id_seq'::regclass);
+
ALTER TABLE ONLY product_analytics_events_experimental ALTER COLUMN id SET DEFAULT nextval('product_analytics_events_experimental_id_seq'::regclass);
ALTER TABLE ONLY programming_languages ALTER COLUMN id SET DEFAULT nextval('programming_languages_id_seq'::regclass);
@@ -17599,6 +17897,8 @@ ALTER TABLE ONLY releases ALTER COLUMN id SET DEFAULT nextval('releases_id_seq':
ALTER TABLE ONLY remote_mirrors ALTER COLUMN id SET DEFAULT nextval('remote_mirrors_id_seq'::regclass);
+ALTER TABLE ONLY required_code_owners_sections ALTER COLUMN id SET DEFAULT nextval('required_code_owners_sections_id_seq'::regclass);
+
ALTER TABLE ONLY requirements ALTER COLUMN id SET DEFAULT nextval('requirements_id_seq'::regclass);
ALTER TABLE ONLY requirements_management_test_reports ALTER COLUMN id SET DEFAULT nextval('requirements_management_test_reports_id_seq'::regclass);
@@ -17617,6 +17917,8 @@ ALTER TABLE ONLY reviews ALTER COLUMN id SET DEFAULT nextval('reviews_id_seq'::r
ALTER TABLE ONLY routes ALTER COLUMN id SET DEFAULT nextval('routes_id_seq'::regclass);
+ALTER TABLE ONLY saml_group_links ALTER COLUMN id SET DEFAULT nextval('saml_group_links_id_seq'::regclass);
+
ALTER TABLE ONLY saml_providers ALTER COLUMN id SET DEFAULT nextval('saml_providers_id_seq'::regclass);
ALTER TABLE ONLY scim_identities ALTER COLUMN id SET DEFAULT nextval('scim_identities_id_seq'::regclass);
@@ -17956,6 +18258,9 @@ ALTER TABLE ONLY alert_management_alert_user_mentions
ALTER TABLE ONLY alert_management_alerts
ADD CONSTRAINT alert_management_alerts_pkey PRIMARY KEY (id);
+ALTER TABLE ONLY alert_management_http_integrations
+ ADD CONSTRAINT alert_management_http_integrations_pkey PRIMARY KEY (id);
+
ALTER TABLE ONLY alerts_service_data
ADD CONSTRAINT alerts_service_data_pkey PRIMARY KEY (id);
@@ -18070,20 +18375,26 @@ ALTER TABLE ONLY boards
ALTER TABLE ONLY broadcast_messages
ADD CONSTRAINT broadcast_messages_pkey PRIMARY KEY (id);
+ALTER TABLE ONLY bulk_import_configurations
+ ADD CONSTRAINT bulk_import_configurations_pkey PRIMARY KEY (id);
+
+ALTER TABLE ONLY bulk_import_entities
+ ADD CONSTRAINT bulk_import_entities_pkey PRIMARY KEY (id);
+
+ALTER TABLE ONLY bulk_imports
+ ADD CONSTRAINT bulk_imports_pkey PRIMARY KEY (id);
+
ALTER TABLE ONLY chat_names
ADD CONSTRAINT chat_names_pkey PRIMARY KEY (id);
ALTER TABLE ONLY chat_teams
ADD CONSTRAINT chat_teams_pkey PRIMARY KEY (id);
-ALTER TABLE design_management_designs
- ADD CONSTRAINT check_07155e2715 CHECK ((char_length((filename)::text) <= 255)) NOT VALID;
-
ALTER TABLE vulnerability_scanners
ADD CONSTRAINT check_37608c9db5 CHECK ((char_length(vendor) <= 255)) NOT VALID;
-ALTER TABLE packages_package_files
- ADD CONSTRAINT check_4c5e6bb0b3 CHECK ((file_store IS NOT NULL)) NOT VALID;
+ALTER TABLE group_import_states
+ ADD CONSTRAINT check_cda75c7c3f CHECK ((user_id IS NOT NULL)) NOT VALID;
ALTER TABLE ONLY ci_build_needs
ADD CONSTRAINT ci_build_needs_pkey PRIMARY KEY (id);
@@ -18112,6 +18423,9 @@ ALTER TABLE ONLY ci_builds_runner_session
ALTER TABLE ONLY ci_daily_build_group_report_results
ADD CONSTRAINT ci_daily_build_group_report_results_pkey PRIMARY KEY (id);
+ALTER TABLE ONLY ci_deleted_objects
+ ADD CONSTRAINT ci_deleted_objects_pkey PRIMARY KEY (id);
+
ALTER TABLE ONLY ci_freeze_periods
ADD CONSTRAINT ci_freeze_periods_pkey PRIMARY KEY (id);
@@ -18256,6 +18570,9 @@ ALTER TABLE ONLY clusters
ALTER TABLE ONLY commit_user_mentions
ADD CONSTRAINT commit_user_mentions_pkey PRIMARY KEY (id);
+ALTER TABLE ONLY compliance_management_frameworks
+ ADD CONSTRAINT compliance_management_frameworks_pkey PRIMARY KEY (id);
+
ALTER TABLE ONLY container_expiration_policies
ADD CONSTRAINT container_expiration_policies_pkey PRIMARY KEY (project_id);
@@ -18493,6 +18810,12 @@ ALTER TABLE ONLY ip_restrictions
ALTER TABLE ONLY issuable_severities
ADD CONSTRAINT issuable_severities_pkey PRIMARY KEY (id);
+ALTER TABLE ONLY issuable_slas
+ ADD CONSTRAINT issuable_slas_pkey PRIMARY KEY (id);
+
+ALTER TABLE ONLY issue_email_participants
+ ADD CONSTRAINT issue_email_participants_pkey PRIMARY KEY (id);
+
ALTER TABLE ONLY issue_links
ADD CONSTRAINT issue_links_pkey PRIMARY KEY (id);
@@ -18688,6 +19011,9 @@ ALTER TABLE ONLY packages_dependencies
ALTER TABLE ONLY packages_dependency_links
ADD CONSTRAINT packages_dependency_links_pkey PRIMARY KEY (id);
+ALTER TABLE ONLY packages_events
+ ADD CONSTRAINT packages_events_pkey PRIMARY KEY (id);
+
ALTER TABLE ONLY packages_maven_metadata
ADD CONSTRAINT packages_maven_metadata_pkey PRIMARY KEY (id);
@@ -18736,6 +19062,9 @@ ALTER TABLE ONLY plans
ALTER TABLE ONLY pool_repositories
ADD CONSTRAINT pool_repositories_pkey PRIMARY KEY (id);
+ALTER TABLE ONLY postgres_reindex_actions
+ ADD CONSTRAINT postgres_reindex_actions_pkey PRIMARY KEY (id);
+
ALTER TABLE ONLY programming_languages
ADD CONSTRAINT programming_languages_pkey PRIMARY KEY (id);
@@ -18868,6 +19197,9 @@ ALTER TABLE ONLY releases
ALTER TABLE ONLY remote_mirrors
ADD CONSTRAINT remote_mirrors_pkey PRIMARY KEY (id);
+ALTER TABLE ONLY required_code_owners_sections
+ ADD CONSTRAINT required_code_owners_sections_pkey PRIMARY KEY (id);
+
ALTER TABLE ONLY requirements_management_test_reports
ADD CONSTRAINT requirements_management_test_reports_pkey PRIMARY KEY (id);
@@ -18895,6 +19227,9 @@ ALTER TABLE ONLY reviews
ALTER TABLE ONLY routes
ADD CONSTRAINT routes_pkey PRIMARY KEY (id);
+ALTER TABLE ONLY saml_group_links
+ ADD CONSTRAINT saml_group_links_pkey PRIMARY KEY (id);
+
ALTER TABLE ONLY saml_providers
ADD CONSTRAINT saml_providers_pkey PRIMARY KEY (id);
@@ -19287,7 +19622,7 @@ CREATE INDEX idx_audit_events_on_entity_id_desc_author_id_created_at ON audit_ev
CREATE INDEX idx_ci_pipelines_artifacts_locked ON ci_pipelines USING btree (ci_ref_id, id) WHERE (locked = 1);
-CREATE INDEX idx_container_scanning_findings ON vulnerability_occurrences USING btree (id) WHERE (report_type = 2);
+CREATE INDEX idx_container_exp_policies_on_project_id_next_run_at_enabled ON container_expiration_policies USING btree (project_id, next_run_at, enabled);
CREATE INDEX idx_deployment_clusters_on_cluster_id_and_kubernetes_namespace ON deployment_clusters USING btree (cluster_id, kubernetes_namespace);
@@ -19317,6 +19652,8 @@ CREATE INDEX idx_members_created_at_user_id_invite_token ON members USING btree
CREATE INDEX idx_merge_requests_on_id_and_merge_jid ON merge_requests USING btree (id, merge_jid) WHERE ((merge_jid IS NOT NULL) AND (state_id = 4));
+CREATE INDEX idx_merge_requests_on_merged_state ON merge_requests USING btree (id) WHERE (state_id = 3);
+
CREATE INDEX idx_merge_requests_on_source_project_and_branch_state_opened ON merge_requests USING btree (source_project_id, source_branch) WHERE (state_id = 1);
CREATE INDEX idx_merge_requests_on_state_id_and_merge_status ON merge_requests USING btree (state_id, merge_status) WHERE ((state_id = 1) AND ((merge_status)::text = 'can_be_merged'::text));
@@ -19329,6 +19666,8 @@ CREATE UNIQUE INDEX idx_metrics_users_starred_dashboard_on_user_project_dashboar
CREATE INDEX idx_mr_cc_diff_files_on_mr_cc_id_and_sha ON merge_request_context_commit_diff_files USING btree (merge_request_context_commit_id, sha);
+CREATE UNIQUE INDEX idx_on_compliance_management_frameworks_namespace_id_name ON compliance_management_frameworks USING btree (namespace_id, name);
+
CREATE INDEX idx_packages_packages_on_project_id_name_version_package_type ON packages_packages USING btree (project_id, name, version, package_type);
CREATE UNIQUE INDEX idx_pkgs_dep_links_on_pkg_id_dependency_id_dependency_type ON packages_dependency_links USING btree (package_id, dependency_id, dependency_type);
@@ -19381,6 +19720,8 @@ CREATE UNIQUE INDEX index_alert_management_alerts_on_project_id_and_iid ON alert
CREATE INDEX index_alert_management_alerts_on_prometheus_alert_id ON alert_management_alerts USING btree (prometheus_alert_id) WHERE (prometheus_alert_id IS NOT NULL);
+CREATE INDEX index_alert_management_http_integrations_on_project_id ON alert_management_http_integrations USING btree (project_id);
+
CREATE UNIQUE INDEX index_alert_user_mentions_on_alert_id ON alert_management_alert_user_mentions USING btree (alert_management_alert_id) WHERE (note_id IS NULL);
CREATE UNIQUE INDEX index_alert_user_mentions_on_alert_id_and_note_id ON alert_management_alert_user_mentions USING btree (alert_management_alert_id, note_id);
@@ -19447,6 +19788,8 @@ CREATE UNIQUE INDEX index_approval_project_rules_groups_1 ON approval_project_ru
CREATE INDEX index_approval_project_rules_groups_2 ON approval_project_rules_groups USING btree (group_id);
+CREATE INDEX index_approval_project_rules_on_id_with_regular_type ON approval_project_rules USING btree (id) WHERE (rule_type = 0);
+
CREATE INDEX index_approval_project_rules_on_project_id ON approval_project_rules USING btree (project_id);
CREATE INDEX index_approval_project_rules_on_rule_type ON approval_project_rules USING btree (rule_type);
@@ -19459,6 +19802,8 @@ CREATE UNIQUE INDEX index_approval_project_rules_users_1 ON approval_project_rul
CREATE INDEX index_approval_project_rules_users_2 ON approval_project_rules_users USING btree (user_id);
+CREATE INDEX index_approval_project_rules_users_on_approval_project_rule_id ON approval_project_rules_users USING btree (approval_project_rule_id);
+
CREATE UNIQUE INDEX index_approval_rule_name_for_code_owners_rule_type ON approval_merge_request_rules USING btree (merge_request_id, name) WHERE ((rule_type = 2) AND (section IS NULL));
CREATE UNIQUE INDEX index_approval_rule_name_for_sectional_code_owners_rule_type ON approval_merge_request_rules USING btree (merge_request_id, name, section) WHERE (rule_type = 2);
@@ -19481,6 +19826,8 @@ CREATE UNIQUE INDEX index_atlassian_identities_on_extern_uid ON atlassian_identi
CREATE INDEX index_authentication_events_on_provider ON authentication_events USING btree (provider);
+CREATE INDEX index_authentication_events_on_provider_user_id_created_at ON authentication_events USING btree (provider, user_id, created_at) WHERE (result = 1);
+
CREATE INDEX index_authentication_events_on_user_id ON authentication_events USING btree (user_id);
CREATE INDEX index_award_emoji_on_awardable_type_and_awardable_id ON award_emoji USING btree (awardable_type, awardable_id);
@@ -19547,6 +19894,18 @@ CREATE INDEX index_boards_on_project_id ON boards USING btree (project_id);
CREATE INDEX index_broadcast_message_on_ends_at_and_broadcast_type_and_id ON broadcast_messages USING btree (ends_at, broadcast_type, id);
+CREATE INDEX index_bulk_import_configurations_on_bulk_import_id ON bulk_import_configurations USING btree (bulk_import_id);
+
+CREATE INDEX index_bulk_import_entities_on_bulk_import_id ON bulk_import_entities USING btree (bulk_import_id);
+
+CREATE INDEX index_bulk_import_entities_on_namespace_id ON bulk_import_entities USING btree (namespace_id);
+
+CREATE INDEX index_bulk_import_entities_on_parent_id ON bulk_import_entities USING btree (parent_id);
+
+CREATE INDEX index_bulk_import_entities_on_project_id ON bulk_import_entities USING btree (project_id);
+
+CREATE INDEX index_bulk_imports_on_user_id ON bulk_imports USING btree (user_id);
+
CREATE UNIQUE INDEX index_chat_names_on_service_id_and_team_id_and_chat_id ON chat_names USING btree (service_id, team_id, chat_id);
CREATE UNIQUE INDEX index_chat_names_on_user_id_and_service_id ON chat_names USING btree (user_id, service_id);
@@ -19625,6 +19984,8 @@ CREATE UNIQUE INDEX index_ci_builds_runner_session_on_build_id ON ci_builds_runn
CREATE INDEX index_ci_daily_build_group_report_results_on_last_pipeline_id ON ci_daily_build_group_report_results USING btree (last_pipeline_id);
+CREATE INDEX index_ci_deleted_objects_on_pick_up_at ON ci_deleted_objects USING btree (pick_up_at);
+
CREATE INDEX index_ci_freeze_periods_on_project_id ON ci_freeze_periods USING btree (project_id);
CREATE UNIQUE INDEX index_ci_group_variables_on_group_id_and_key ON ci_group_variables USING btree (group_id, key);
@@ -19709,7 +20070,7 @@ CREATE INDEX index_ci_pipelines_on_project_id_and_user_id_and_status_and_ref ON
CREATE INDEX index_ci_pipelines_on_project_idandrefandiddesc ON ci_pipelines USING btree (project_id, ref, id DESC);
-CREATE INDEX index_ci_pipelines_on_status ON ci_pipelines USING btree (status);
+CREATE INDEX index_ci_pipelines_on_status_and_id ON ci_pipelines USING btree (status, id);
CREATE INDEX index_ci_pipelines_on_user_id_and_created_at_and_config_source ON ci_pipelines USING btree (user_id, created_at, config_source);
@@ -19785,8 +20146,6 @@ CREATE INDEX index_cluster_agent_tokens_on_agent_id ON cluster_agent_tokens USIN
CREATE UNIQUE INDEX index_cluster_agent_tokens_on_token_encrypted ON cluster_agent_tokens USING btree (token_encrypted);
-CREATE INDEX index_cluster_agents_on_project_id ON cluster_agents USING btree (project_id);
-
CREATE UNIQUE INDEX index_cluster_agents_on_project_id_and_name ON cluster_agents USING btree (project_id, name);
CREATE UNIQUE INDEX index_cluster_groups_on_cluster_id_and_group_id ON cluster_groups USING btree (cluster_id, group_id);
@@ -19803,8 +20162,6 @@ CREATE UNIQUE INDEX index_cluster_providers_aws_on_cluster_id ON cluster_provide
CREATE INDEX index_cluster_providers_aws_on_cluster_id_and_status ON cluster_providers_aws USING btree (cluster_id, status);
-CREATE INDEX index_cluster_providers_aws_on_created_by_user_id ON cluster_providers_aws USING btree (created_by_user_id);
-
CREATE INDEX index_cluster_providers_gcp_on_cloud_run ON cluster_providers_gcp USING btree (cloud_run);
CREATE UNIQUE INDEX index_cluster_providers_gcp_on_cluster_id ON cluster_providers_gcp USING btree (cluster_id);
@@ -19933,6 +20290,8 @@ CREATE INDEX index_deployments_on_project_id_and_status_and_created_at ON deploy
CREATE INDEX index_deployments_on_project_id_and_updated_at_and_id ON deployments USING btree (project_id, updated_at DESC, id DESC);
+CREATE INDEX index_deployments_on_project_id_sha ON deployments USING btree (project_id, sha);
+
CREATE INDEX index_deployments_on_user_id_and_status_and_created_at ON deployments USING btree (user_id, status, created_at);
CREATE INDEX index_description_versions_on_epic_id ON description_versions USING btree (epic_id) WHERE (epic_id IS NOT NULL);
@@ -20219,12 +20578,16 @@ CREATE INDEX index_group_group_links_on_shared_with_group_id ON group_group_link
CREATE INDEX index_group_import_states_on_group_id ON group_import_states USING btree (group_id);
+CREATE INDEX index_group_import_states_on_user_id ON group_import_states USING btree (user_id) WHERE (user_id IS NOT NULL);
+
CREATE UNIQUE INDEX index_group_stages_on_group_id_group_value_stream_id_and_name ON analytics_cycle_analytics_group_stages USING btree (group_id, group_value_stream_id, name);
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);
+CREATE UNIQUE INDEX index_http_integrations_on_active_and_project_and_endpoint ON alert_management_http_integrations USING btree (active, project_id, endpoint_identifier) WHERE active;
+
CREATE INDEX index_identities_on_saml_provider_id ON identities USING btree (saml_provider_id) WHERE (saml_provider_id IS NOT NULL);
CREATE INDEX index_identities_on_user_id ON identities USING btree (user_id);
@@ -20263,10 +20626,14 @@ CREATE INDEX index_ip_restrictions_on_group_id ON ip_restrictions USING btree (g
CREATE UNIQUE INDEX index_issuable_severities_on_issue_id ON issuable_severities USING btree (issue_id);
+CREATE UNIQUE INDEX index_issuable_slas_on_issue_id ON issuable_slas USING btree (issue_id);
+
CREATE UNIQUE INDEX index_issue_assignees_on_issue_id_and_user_id ON issue_assignees USING btree (issue_id, user_id);
CREATE INDEX index_issue_assignees_on_user_id ON issue_assignees USING btree (user_id);
+CREATE UNIQUE INDEX index_issue_email_participants_on_issue_id_and_email ON issue_email_participants USING btree (issue_id, email);
+
CREATE INDEX index_issue_links_on_source_id ON issue_links USING btree (source_id);
CREATE UNIQUE INDEX index_issue_links_on_source_id_and_target_id ON issue_links USING btree (source_id, target_id);
@@ -20309,8 +20676,6 @@ CREATE UNIQUE INDEX index_issues_on_project_id_and_iid ON issues USING btree (pr
CREATE INDEX index_issues_on_promoted_to_epic_id ON issues USING btree (promoted_to_epic_id) WHERE (promoted_to_epic_id IS NOT NULL);
-CREATE INDEX index_issues_on_relative_position ON issues USING btree (relative_position);
-
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);
@@ -20319,6 +20684,8 @@ CREATE INDEX index_issues_on_updated_at ON issues USING btree (updated_at);
CREATE INDEX index_issues_on_updated_by_id ON issues USING btree (updated_by_id) WHERE (updated_by_id IS NOT NULL);
+CREATE INDEX index_issues_project_id_issue_type_incident ON issues USING btree (project_id) WHERE (issue_type = 1);
+
CREATE UNIQUE INDEX index_jira_connect_installations_on_client_key ON jira_connect_installations USING btree (client_key);
CREATE INDEX index_jira_connect_subscriptions_on_namespace_id ON jira_connect_subscriptions USING btree (namespace_id);
@@ -20489,6 +20856,8 @@ CREATE INDEX index_merge_requests_on_target_project_id_and_created_at_and_id ON
CREATE UNIQUE INDEX index_merge_requests_on_target_project_id_and_iid ON merge_requests USING btree (target_project_id, iid);
+CREATE INDEX index_merge_requests_on_target_project_id_and_iid_and_state_id ON merge_requests USING btree (target_project_id, iid, state_id);
+
CREATE INDEX index_merge_requests_on_target_project_id_and_target_branch ON merge_requests USING btree (target_project_id, target_branch) WHERE ((state_id = 1) AND (merge_when_pipeline_succeeds = true));
CREATE INDEX index_merge_requests_on_title ON merge_requests USING btree (title);
@@ -20573,7 +20942,7 @@ CREATE UNIQUE INDEX index_namespaces_on_runners_token_encrypted ON namespaces US
CREATE INDEX index_namespaces_on_shared_and_extra_runners_minutes_limit ON namespaces USING btree (shared_runners_minutes_limit, extra_shared_runners_minutes_limit);
-CREATE INDEX index_namespaces_on_type_partial ON namespaces USING btree (type) WHERE (type IS NOT NULL);
+CREATE INDEX index_namespaces_on_type_and_id_partial ON namespaces USING btree (type, id) WHERE (type IS NOT NULL);
CREATE INDEX index_non_requested_project_members_on_source_id_and_type ON members USING btree (source_id, source_type) WHERE ((requested_at IS NULL) AND ((type)::text = 'ProjectMember'::text));
@@ -20669,14 +21038,14 @@ CREATE UNIQUE INDEX index_packages_dependencies_on_name_and_version_pattern ON p
CREATE INDEX index_packages_dependency_links_on_dependency_id ON packages_dependency_links USING btree (dependency_id);
+CREATE INDEX index_packages_events_on_package_id ON packages_events USING btree (package_id);
+
CREATE INDEX index_packages_maven_metadata_on_package_id_and_path ON packages_maven_metadata USING btree (package_id, path);
CREATE INDEX index_packages_nuget_dl_metadata_on_dependency_link_id ON packages_nuget_dependency_link_metadata USING btree (dependency_link_id);
CREATE UNIQUE INDEX index_packages_on_project_id_name_version_unique_when_generic ON packages_packages USING btree (project_id, name, version) WHERE (package_type = 7);
-CREATE INDEX index_packages_package_files_file_store_is_null ON packages_package_files USING btree (id) WHERE (file_store IS NULL);
-
CREATE INDEX index_packages_package_files_on_file_store ON packages_package_files USING btree (file_store);
CREATE INDEX index_packages_package_files_on_package_id_and_file_name ON packages_package_files USING btree (package_id, file_name);
@@ -20733,6 +21102,8 @@ CREATE INDEX index_pages_domains_on_wildcard ON pages_domains USING btree (wildc
CREATE UNIQUE INDEX index_partial_am_alerts_on_project_id_and_fingerprint ON alert_management_alerts USING btree (project_id, fingerprint) WHERE (status <> 2);
+CREATE INDEX index_partial_ci_builds_on_user_id_name_parser_features ON ci_builds USING btree (user_id, name) WHERE (((type)::text = 'Ci::Build'::text) AND ((name)::text = ANY (ARRAY[('container_scanning'::character varying)::text, ('dast'::character varying)::text, ('dependency_scanning'::character varying)::text, ('license_management'::character varying)::text, ('license_scanning'::character varying)::text, ('sast'::character varying)::text, ('coverage_fuzzing'::character varying)::text, ('secret_detection'::character varying)::text])));
+
CREATE UNIQUE INDEX index_partitioned_foreign_keys_unique_index ON partitioned_foreign_keys USING btree (to_table, from_table, from_column);
CREATE INDEX index_pat_on_user_id_and_expires_at ON personal_access_tokens USING btree (user_id, expires_at);
@@ -20757,6 +21128,8 @@ CREATE INDEX index_pool_repositories_on_shard_id ON pool_repositories USING btre
CREATE UNIQUE INDEX index_pool_repositories_on_source_project_id_and_shard_id ON pool_repositories USING btree (source_project_id, shard_id);
+CREATE INDEX index_postgres_reindex_actions_on_index_identifier ON postgres_reindex_actions USING btree (index_identifier);
+
CREATE UNIQUE INDEX index_programming_languages_on_name ON programming_languages USING btree (name);
CREATE INDEX index_project_access_tokens_on_project_id ON project_access_tokens USING btree (project_id);
@@ -20773,6 +21146,8 @@ CREATE UNIQUE INDEX index_project_auto_devops_on_project_id ON project_auto_devo
CREATE UNIQUE INDEX index_project_ci_cd_settings_on_project_id ON project_ci_cd_settings USING btree (project_id);
+CREATE INDEX index_project_compliance_framework_settings_on_framework_id ON project_compliance_framework_settings USING btree (framework_id);
+
CREATE INDEX index_project_compliance_framework_settings_on_project_id ON project_compliance_framework_settings USING btree (project_id);
CREATE INDEX index_project_custom_attributes_on_key_and_value ON project_custom_attributes USING btree (key, value);
@@ -20817,6 +21192,8 @@ CREATE INDEX index_project_mirror_data_on_status ON project_mirror_data USING bt
CREATE INDEX index_project_pages_metadata_on_artifacts_archive_id ON project_pages_metadata USING btree (artifacts_archive_id);
+CREATE INDEX index_project_pages_metadata_on_pages_deployment_id ON project_pages_metadata USING btree (pages_deployment_id);
+
CREATE UNIQUE INDEX index_project_pages_metadata_on_project_id ON project_pages_metadata USING btree (project_id);
CREATE INDEX index_project_pages_metadata_on_project_id_and_deployed_is_true ON project_pages_metadata USING btree (project_id) WHERE (deployed = true);
@@ -21019,6 +21396,8 @@ CREATE INDEX index_remote_mirrors_on_project_id ON remote_mirrors USING btree (p
CREATE UNIQUE INDEX index_repository_languages_on_project_and_languages_id ON repository_languages USING btree (project_id, programming_language_id);
+CREATE INDEX index_required_code_owners_sections_on_protected_branch_id ON required_code_owners_sections USING btree (protected_branch_id);
+
CREATE INDEX index_requirements_management_test_reports_on_author_id ON requirements_management_test_reports USING btree (author_id);
CREATE INDEX index_requirements_management_test_reports_on_build_id ON requirements_management_test_reports USING btree (build_id);
@@ -21101,6 +21480,8 @@ CREATE INDEX index_routes_on_path_trigram ON routes USING gin (path gin_trgm_ops
CREATE UNIQUE INDEX index_routes_on_source_type_and_source_id ON routes USING btree (source_type, source_id);
+CREATE UNIQUE INDEX index_saml_group_links_on_group_id_and_saml_group_name ON saml_group_links USING btree (group_id, saml_group_name);
+
CREATE INDEX index_saml_providers_on_group_id ON saml_providers USING btree (group_id);
CREATE INDEX index_scim_identities_on_group_id ON scim_identities USING btree (group_id);
@@ -21153,6 +21534,8 @@ CREATE UNIQUE INDEX index_services_on_type_and_instance_partial ON services USIN
CREATE UNIQUE INDEX index_services_on_type_and_template_partial ON services USING btree (type, template) WHERE (template = true);
+CREATE INDEX index_services_on_type_id_when_active_and_project_id_not_null ON services USING btree (type, id) WHERE ((active = true) AND (project_id IS NOT NULL));
+
CREATE INDEX index_services_on_type_id_when_active_not_instance_not_template ON services USING btree (type, id) WHERE ((active = true) AND (instance = false) AND (template = false));
CREATE UNIQUE INDEX index_services_on_unique_group_id_and_type ON services USING btree (group_id, type);
@@ -21329,6 +21712,8 @@ CREATE UNIQUE INDEX index_user_interacted_projects_on_project_id_and_user_id ON
CREATE INDEX index_user_interacted_projects_on_user_id ON user_interacted_projects USING btree (user_id);
+CREATE INDEX index_user_preferences_on_gitpod_enabled ON user_preferences USING btree (gitpod_enabled);
+
CREATE UNIQUE INDEX index_user_preferences_on_user_id ON user_preferences USING btree (user_id);
CREATE INDEX index_user_statuses_on_user_id ON user_statuses USING btree (user_id);
@@ -21407,12 +21792,14 @@ CREATE INDEX index_vulnerabilities_on_milestone_id ON vulnerabilities USING btre
CREATE INDEX index_vulnerabilities_on_project_id ON vulnerabilities USING btree (project_id);
-CREATE INDEX index_vulnerabilities_on_project_id_and_id ON vulnerabilities USING btree (project_id, id);
-
CREATE INDEX index_vulnerabilities_on_resolved_by_id ON vulnerabilities USING btree (resolved_by_id);
CREATE INDEX index_vulnerabilities_on_start_date_sourcing_milestone_id ON vulnerabilities USING btree (start_date_sourcing_milestone_id);
+CREATE INDEX index_vulnerabilities_on_state_case_id ON vulnerabilities USING btree (array_position(ARRAY[(1)::smallint, (4)::smallint, (3)::smallint, (2)::smallint], state), id DESC);
+
+CREATE INDEX index_vulnerabilities_on_state_case_id_desc ON vulnerabilities USING btree (array_position(ARRAY[(1)::smallint, (4)::smallint, (3)::smallint, (2)::smallint], state) DESC, id DESC);
+
CREATE INDEX index_vulnerabilities_on_updated_by_id ON vulnerabilities USING btree (updated_by_id);
CREATE INDEX index_vulnerability_exports_on_author_id ON vulnerability_exports USING btree (author_id);
@@ -21483,6 +21870,8 @@ CREATE INDEX index_web_hooks_on_type ON web_hooks USING btree (type);
CREATE UNIQUE INDEX index_webauthn_registrations_on_credential_xid ON webauthn_registrations USING btree (credential_xid);
+CREATE INDEX index_webauthn_registrations_on_u2f_registration_id ON webauthn_registrations USING btree (u2f_registration_id) WHERE (u2f_registration_id IS NOT NULL);
+
CREATE INDEX index_webauthn_registrations_on_user_id ON webauthn_registrations USING btree (user_id);
CREATE INDEX index_wiki_page_meta_on_project_id ON wiki_page_meta USING btree (project_id);
@@ -21563,15 +21952,15 @@ CREATE INDEX terraform_state_versions_verification_checksum_partial ON terraform
CREATE INDEX terraform_state_versions_verification_failure_partial ON terraform_state_versions USING btree (verification_failure) WHERE (verification_failure IS NOT NULL);
-CREATE INDEX terraform_states_verification_checksum_partial ON terraform_states USING btree (verification_checksum) WHERE (verification_checksum IS NOT NULL);
+CREATE INDEX tmp_build_stage_position_index ON ci_builds USING btree (stage_id, stage_idx) WHERE (stage_idx IS NOT NULL);
-CREATE INDEX terraform_states_verification_failure_partial ON terraform_states USING btree (verification_failure) WHERE (verification_failure IS NOT NULL);
+CREATE INDEX tmp_idx_blocked_by_type_links ON issue_links USING btree (target_id) WHERE (link_type = 2);
-CREATE INDEX tmp_build_stage_position_index ON ci_builds USING btree (stage_id, stage_idx) WHERE (stage_idx IS NOT NULL);
+CREATE INDEX tmp_idx_blocking_type_links ON issue_links USING btree (source_id) WHERE (link_type = 1);
-CREATE INDEX tmp_index_for_email_unconfirmation_migration ON emails USING btree (id) WHERE (confirmed_at IS NOT NULL);
+CREATE INDEX tmp_idx_index_issues_with_outdate_blocking_count ON issues USING btree (id) WHERE ((state_id = 1) AND (blocking_issues_count = 0));
-CREATE INDEX tmp_index_for_fixing_inconsistent_vulnerability_occurrences ON vulnerability_occurrences USING btree (id) WHERE ((length(location_fingerprint) = 40) AND (report_type = 2));
+CREATE INDEX tmp_index_for_email_unconfirmation_migration ON emails USING btree (id) WHERE (confirmed_at IS NOT NULL);
CREATE UNIQUE INDEX unique_merge_request_metrics_by_merge_request_id ON merge_request_metrics USING btree (merge_request_id);
@@ -21872,6 +22261,9 @@ ALTER TABLE ONLY notification_settings
ALTER TABLE ONLY lists
ADD CONSTRAINT fk_0d3f677137 FOREIGN KEY (board_id) REFERENCES boards(id) ON DELETE CASCADE;
+ALTER TABLE ONLY project_pages_metadata
+ ADD CONSTRAINT fk_0fd5b22688 FOREIGN KEY (pages_deployment_id) REFERENCES pages_deployments(id) ON DELETE SET NULL;
+
ALTER TABLE ONLY group_deletion_schedules
ADD CONSTRAINT fk_11e3ebfcdd FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE;
@@ -21881,6 +22273,9 @@ ALTER TABLE ONLY vulnerabilities
ALTER TABLE ONLY vulnerabilities
ADD CONSTRAINT fk_131d289c65 FOREIGN KEY (milestone_id) REFERENCES milestones(id) ON DELETE SET NULL;
+ALTER TABLE ONLY webauthn_registrations
+ ADD CONSTRAINT fk_13e04d719a FOREIGN KEY (u2f_registration_id) REFERENCES u2f_registrations(id) ON DELETE CASCADE;
+
ALTER TABLE ONLY protected_branch_push_access_levels
ADD CONSTRAINT fk_15d2a7a4ae FOREIGN KEY (deploy_key_id) REFERENCES keys(id) ON DELETE CASCADE;
@@ -22115,6 +22510,9 @@ ALTER TABLE ONLY merge_requests
ALTER TABLE ONLY merge_request_metrics
ADD CONSTRAINT fk_7f28d925f3 FOREIGN KEY (merged_by_id) REFERENCES users(id) ON DELETE SET NULL;
+ALTER TABLE ONLY group_import_states
+ ADD CONSTRAINT fk_8053b3ebd6 FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE;
+
ALTER TABLE ONLY sprints
ADD CONSTRAINT fk_80aa8a1f95 FOREIGN KEY (group_id) REFERENCES namespaces(id) ON DELETE CASCADE;
@@ -22145,6 +22543,9 @@ ALTER TABLE ONLY ci_builds
ALTER TABLE ONLY vulnerabilities
ADD CONSTRAINT fk_88b4d546ef FOREIGN KEY (start_date_sourcing_milestone_id) REFERENCES milestones(id) ON DELETE SET NULL;
+ALTER TABLE ONLY bulk_import_entities
+ ADD CONSTRAINT fk_88c725229f FOREIGN KEY (namespace_id) REFERENCES namespaces(id) ON DELETE CASCADE;
+
ALTER TABLE ONLY issues
ADD CONSTRAINT fk_899c8f3231 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
@@ -22223,6 +22624,9 @@ ALTER TABLE ONLY ci_builds
ALTER TABLE ONLY ci_pipelines
ADD CONSTRAINT fk_a23be95014 FOREIGN KEY (merge_request_id) REFERENCES merge_requests(id) ON DELETE CASCADE;
+ALTER TABLE ONLY bulk_import_entities
+ ADD CONSTRAINT fk_a44ff95be5 FOREIGN KEY (parent_id) REFERENCES bulk_import_entities(id) ON DELETE CASCADE;
+
ALTER TABLE ONLY users
ADD CONSTRAINT fk_a4b8fefe3e FOREIGN KEY (managing_group_id) REFERENCES namespaces(id) ON DELETE SET NULL;
@@ -22265,6 +22669,12 @@ ALTER TABLE ONLY project_access_tokens
ALTER TABLE ONLY protected_tag_create_access_levels
ADD CONSTRAINT fk_b4eb82fe3c FOREIGN KEY (group_id) REFERENCES namespaces(id) ON DELETE CASCADE;
+ALTER TABLE ONLY bulk_import_entities
+ ADD CONSTRAINT fk_b69fa2b2df FOREIGN KEY (bulk_import_id) REFERENCES bulk_imports(id) ON DELETE CASCADE;
+
+ALTER TABLE ONLY compliance_management_frameworks
+ ADD CONSTRAINT fk_b74c45b71f FOREIGN KEY (namespace_id) REFERENCES namespaces(id) ON DELETE CASCADE;
+
ALTER TABLE ONLY issue_assignees
ADD CONSTRAINT fk_b7d881734a FOREIGN KEY (issue_id) REFERENCES issues(id) ON DELETE CASCADE;
@@ -22280,6 +22690,9 @@ ALTER TABLE ONLY gitlab_subscriptions
ALTER TABLE ONLY metrics_users_starred_dashboards
ADD CONSTRAINT fk_bd6ae32fac FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE;
+ALTER TABLE ONLY project_compliance_framework_settings
+ ADD CONSTRAINT fk_be413374a9 FOREIGN KEY (framework_id) REFERENCES compliance_management_frameworks(id) ON DELETE CASCADE;
+
ALTER TABLE ONLY snippets
ADD CONSTRAINT fk_be41fd4bb7 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
@@ -22319,6 +22732,9 @@ ALTER TABLE ONLY todos
ALTER TABLE ONLY geo_event_log
ADD CONSTRAINT fk_cff7185ad2 FOREIGN KEY (reset_checksum_event_id) REFERENCES geo_reset_checksum_events(id) ON DELETE CASCADE;
+ALTER TABLE ONLY bulk_import_entities
+ ADD CONSTRAINT fk_d06d023c30 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
+
ALTER TABLE ONLY project_mirror_data
ADD CONSTRAINT fk_d1aad367d7 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
@@ -22523,6 +22939,9 @@ ALTER TABLE ONLY user_synced_attributes_metadata
ALTER TABLE ONLY project_authorizations
ADD CONSTRAINT fk_rails_0f84bb11f3 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
+ALTER TABLE ONLY issue_email_participants
+ ADD CONSTRAINT fk_rails_0fdfd8b811 FOREIGN KEY (issue_id) REFERENCES issues(id) ON DELETE CASCADE;
+
ALTER TABLE ONLY merge_request_context_commits
ADD CONSTRAINT fk_rails_0fe0039f60 FOREIGN KEY (merge_request_id) REFERENCES merge_requests(id) ON DELETE CASCADE;
@@ -22556,6 +22975,9 @@ ALTER TABLE ONLY project_statistics
ALTER TABLE ONLY user_details
ADD CONSTRAINT fk_rails_12e0b3043d FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE;
+ALTER TABLE ONLY bulk_imports
+ ADD CONSTRAINT fk_rails_130a09357d FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE;
+
ALTER TABLE ONLY diff_note_positions
ADD CONSTRAINT fk_rails_13c7212859 FOREIGN KEY (note_id) REFERENCES notes(id) ON DELETE CASCADE;
@@ -22595,6 +23017,9 @@ ALTER TABLE ONLY gpg_signatures
ALTER TABLE ONLY vulnerability_user_mentions
ADD CONSTRAINT fk_rails_1a41c485cd FOREIGN KEY (vulnerability_id) REFERENCES vulnerabilities(id) ON DELETE CASCADE;
+ALTER TABLE ONLY issuable_slas
+ ADD CONSTRAINT fk_rails_1b8768cd63 FOREIGN KEY (issue_id) REFERENCES issues(id) ON DELETE CASCADE;
+
ALTER TABLE ONLY board_assignees
ADD CONSTRAINT fk_rails_1c0ff59e82 FOREIGN KEY (assignee_id) REFERENCES users(id) ON DELETE CASCADE;
@@ -22628,6 +23053,9 @@ ALTER TABLE ONLY clusters_applications_runners
ALTER TABLE ONLY service_desk_settings
ADD CONSTRAINT fk_rails_223a296a85 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
+ALTER TABLE ONLY saml_group_links
+ ADD CONSTRAINT fk_rails_22e312c530 FOREIGN KEY (group_id) REFERENCES namespaces(id) ON DELETE CASCADE;
+
ALTER TABLE ONLY group_custom_attributes
ADD CONSTRAINT fk_rails_246e0db83a FOREIGN KEY (group_id) REFERENCES namespaces(id) ON DELETE CASCADE;
@@ -22865,6 +23293,9 @@ ALTER TABLE ONLY status_page_settings
ALTER TABLE ONLY project_repository_storage_moves
ADD CONSTRAINT fk_rails_5106dbd44a FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
+ALTER TABLE ONLY bulk_import_configurations
+ ADD CONSTRAINT fk_rails_536b96bff1 FOREIGN KEY (bulk_import_id) REFERENCES bulk_imports(id) ON DELETE CASCADE;
+
ALTER TABLE ONLY x509_commit_signatures
ADD CONSTRAINT fk_rails_53fe41188f FOREIGN KEY (x509_certificate_id) REFERENCES x509_certificates(id) ON DELETE CASCADE;
@@ -23111,6 +23542,9 @@ ALTER TABLE ONLY clusters_kubernetes_namespaces
ALTER TABLE ONLY approval_merge_request_rules_users
ADD CONSTRAINT fk_rails_80e6801803 FOREIGN KEY (approval_merge_request_rule_id) REFERENCES approval_merge_request_rules(id) ON DELETE CASCADE;
+ALTER TABLE ONLY required_code_owners_sections
+ ADD CONSTRAINT fk_rails_817708cf2d FOREIGN KEY (protected_branch_id) REFERENCES protected_branches(id) ON DELETE CASCADE;
+
ALTER TABLE ONLY dast_site_profiles
ADD CONSTRAINT fk_rails_83e309d69e FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
@@ -23399,6 +23833,9 @@ ALTER TABLE ONLY elasticsearch_indexed_namespaces
ALTER TABLE ONLY vulnerability_occurrence_identifiers
ADD CONSTRAINT fk_rails_be2e49e1d0 FOREIGN KEY (identifier_id) REFERENCES vulnerability_identifiers(id) ON DELETE CASCADE;
+ALTER TABLE ONLY alert_management_http_integrations
+ ADD CONSTRAINT fk_rails_bec49f52cc FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
+
ALTER TABLE ONLY vulnerability_occurrences
ADD CONSTRAINT fk_rails_bf5b788ca7 FOREIGN KEY (scanner_id) REFERENCES vulnerability_scanners(id) ON DELETE CASCADE;
@@ -23444,6 +23881,9 @@ ALTER TABLE ONLY merge_request_user_mentions
ALTER TABLE ONLY ci_job_artifacts
ADD CONSTRAINT fk_rails_c5137cb2c1 FOREIGN KEY (job_id) REFERENCES ci_builds(id) ON DELETE CASCADE;
+ALTER TABLE ONLY packages_events
+ ADD CONSTRAINT fk_rails_c6c20d0094 FOREIGN KEY (package_id) REFERENCES packages_packages(id) ON DELETE SET NULL;
+
ALTER TABLE ONLY project_settings
ADD CONSTRAINT fk_rails_c6df6e6328 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
@@ -23606,9 +24046,6 @@ ALTER TABLE ONLY alert_management_alert_user_mentions
ALTER TABLE ONLY snippet_statistics
ADD CONSTRAINT fk_rails_ebc283ccf1 FOREIGN KEY (snippet_id) REFERENCES snippets(id) ON DELETE CASCADE;
-ALTER TABLE ONLY cluster_providers_aws
- ADD CONSTRAINT fk_rails_ed1fdfaeb2 FOREIGN KEY (created_by_user_id) REFERENCES users(id) ON DELETE SET NULL;
-
ALTER TABLE ONLY project_security_settings
ADD CONSTRAINT fk_rails_ed4abe1338 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
diff --git a/doc/.vale/gitlab/Acronyms.yml b/doc/.vale/gitlab/Acronyms.yml
index d26ce9810d7..53690138300 100644
--- a/doc/.vale/gitlab/Acronyms.yml
+++ b/doc/.vale/gitlab/Acronyms.yml
@@ -44,6 +44,7 @@ exceptions:
- IBM
- IDE
- IID
+ - IMAP
- IRC
- ISO
- JSON
@@ -65,6 +66,7 @@ exceptions:
- POST
- PUT
- RAM
+ - REST
- RPC
- RSA
- RSS
diff --git a/doc/.vale/gitlab/Admin.yml b/doc/.vale/gitlab/Admin.yml
new file mode 100644
index 00000000000..27a703c30c3
--- /dev/null
+++ b/doc/.vale/gitlab/Admin.yml
@@ -0,0 +1,13 @@
+---
+# Warning: gitlab.Admin
+#
+# You should not use "admin", but "Admin Area" is OK.
+#
+# For a list of all options, see https://errata-ai.gitbook.io/vale/getting-started/styles
+extends: substitution
+message: 'Use "administration", "administrator", "administer", or "Admin Area" instead of "admin" or "admin area".'
+link: https://docs.gitlab.com/ee/development/documentation/styleguide.html
+level: warning
+ignorecase: true
+swap:
+ 'admin ?\w*': '(?:Admin Area|[Aa]dminist(ration|rator|er))'
diff --git a/doc/.vale/gitlab/InclusionAbleism.yml b/doc/.vale/gitlab/InclusionAbleism.yml
new file mode 100644
index 00000000000..29b26547130
--- /dev/null
+++ b/doc/.vale/gitlab/InclusionAbleism.yml
@@ -0,0 +1,14 @@
+---
+# Suggestion: gitlab.InclusionAbleism
+#
+# Suggests alternatives for words that foster ableism.
+#
+# For a list of all options, see https://errata-ai.gitbook.io/vale/getting-started/styles
+extends: substitution
+message: 'Use inclusive language. Consider "%s" instead of "%s".'
+link: https://docs.gitlab.com/ee/development/documentation/styleguide.html#inclusive-language
+level: suggestion
+ignorecase: true
+swap:
+ sanity (?:check|test): check for completeness
+ dummy: placeholder, sample, fake
diff --git a/doc/.vale/gitlab/InclusionCultural.yml b/doc/.vale/gitlab/InclusionCultural.yml
new file mode 100644
index 00000000000..5bfad84f100
--- /dev/null
+++ b/doc/.vale/gitlab/InclusionCultural.yml
@@ -0,0 +1,16 @@
+---
+# Warning: gitlab.InclusionCultural
+#
+# Suggests alternatives for words that are culturally inappropriate.
+#
+# For a list of all options, see https://errata-ai.gitbook.io/vale/getting-started/styles
+extends: substitution
+message: 'Use inclusive language. Consider "%s" instead of "%s".'
+link: https://docs.gitlab.com/ee/development/documentation/styleguide.html#inclusive-language
+level: warning
+ignorecase: true
+swap:
+ blacklist(?:ed|ing|s)?: denylist
+ whitelist(?:ed|ing|s)?: allowlist
+ master: primary, main
+ slave: secondary
diff --git a/doc/.vale/gitlab/InclusionGender.yml b/doc/.vale/gitlab/InclusionGender.yml
new file mode 100644
index 00000000000..389d76d7a24
--- /dev/null
+++ b/doc/.vale/gitlab/InclusionGender.yml
@@ -0,0 +1,18 @@
+---
+# Suggestion: gitlab.InclusionGender
+#
+# Suggests alternatives for words that are gender-specific.
+#
+# For a list of all options, see https://errata-ai.gitbook.io/vale/getting-started/styles
+extends: substitution
+message: 'Use inclusive language. Consider "%s" instead of "%s".'
+link: https://docs.gitlab.com/ee/development/documentation/styleguide.html#inclusive-language
+level: suggestion
+ignorecase: true
+swap:
+ mankind: humanity, people
+ manpower: GitLab team members
+ he: they
+ his: their
+ she: they
+ hers: their
diff --git a/doc/.vale/gitlab/OutdatedVersions.yml b/doc/.vale/gitlab/OutdatedVersions.yml
index 1bc0bf58f90..2ce61ee5798 100644
--- a/doc/.vale/gitlab/OutdatedVersions.yml
+++ b/doc/.vale/gitlab/OutdatedVersions.yml
@@ -7,7 +7,7 @@
extends: existence
message: 'Can this reference to "%s" be refactored?'
link: https://docs.gitlab.com/ee/development/documentation/styleguide.html#importance-of-referencing-gitlab-versions-and-tiers
-level: warning
+level: suggestion
nonword: true
ignorecase: true
tokens:
diff --git a/doc/.vale/gitlab/SubstitutionWarning.yml b/doc/.vale/gitlab/SubstitutionWarning.yml
index 5324a48e38c..68313a37e7d 100644
--- a/doc/.vale/gitlab/SubstitutionWarning.yml
+++ b/doc/.vale/gitlab/SubstitutionWarning.yml
@@ -11,8 +11,6 @@ link: https://about.gitlab.com/handbook/communication/#top-misused-terms
level: warning
ignorecase: true
swap:
- admin: administrator
- blacklist(ed|ing)?: denylist
code base: codebase
config: configuration
distro: distribution
@@ -20,4 +18,3 @@ swap:
filesystem: file system
info: information
repo: repository
- whitelist(ed|ing)?: allowlist
diff --git a/doc/.vale/gitlab/Substitutions.yml b/doc/.vale/gitlab/Substitutions.yml
index 77536ea0b33..704c64f1fbd 100644
--- a/doc/.vale/gitlab/Substitutions.yml
+++ b/doc/.vale/gitlab/Substitutions.yml
@@ -13,6 +13,7 @@ ignorecase: true
swap:
frontmatter: front matter
GitLabber: GitLab team member
+ GitLab-shell: GitLab Shell
gitlab omnibus: Omnibus GitLab
param: parameter
params: parameters
diff --git a/doc/.vale/gitlab/spelling-exceptions.txt b/doc/.vale/gitlab/spelling-exceptions.txt
index bf816afdfab..c0a85fc6b70 100644
--- a/doc/.vale/gitlab/spelling-exceptions.txt
+++ b/doc/.vale/gitlab/spelling-exceptions.txt
@@ -61,6 +61,7 @@ buildpacks
bundler
bundlers
burndown
+burnup
cacheable
CAS
CentOS
@@ -142,8 +143,10 @@ Facebook
failover
failovers
failsafe
+Falco
fastlane
favicon
+Figma
Filebeat
Fio
firewalled
@@ -166,6 +169,7 @@ Gitleaks
Gitter
globals
Gmail
+Gollum
Google
Gosec
Gradle
@@ -220,6 +224,7 @@ Kibana
Kinesis
Knative
Kramdown
+Kubecost
kubectl
Kubernetes
Kubesec
@@ -253,6 +258,7 @@ memoize
memoized
memoizing
Memorystore
+mergeability
mergeable
Microsoft
middleware
@@ -275,6 +281,7 @@ mockups
ModSecurity
monorepo
monorepos
+multiline
mutex
nameserver
nameservers
@@ -298,6 +305,7 @@ OmniAuth
onboarding
OpenID
OpenShift
+Opsgenie
Packagist
parallelization
parallelizations
@@ -305,6 +313,7 @@ passwordless
Patroni
performant
PgBouncer
+Phabricator
phaser
phasers
Pipfile
@@ -345,6 +354,7 @@ Python
Qualys
Rackspace
Raspbian
+Rdoc
reachability
rebase
rebased
@@ -365,6 +375,8 @@ reindex
reindexed
reindexes
reindexing
+reinitialize
+reinitializing
relicensing
remediations
repmgr
@@ -382,6 +394,7 @@ reusability
reverified
reverifies
reverify
+RHEL
rollout
rollouts
rsync
@@ -423,7 +436,10 @@ smartcard
smartcards
SMTP
Sobelow
+Solarized
Sourcegraph
+sparkline
+sparklines
spidering
Splunk
SpotBugs
@@ -439,6 +455,8 @@ subfolder
subfolders
subgraph
subgraphs
+subkey
+subkeys
sublicense
sublicensed
sublicenses
@@ -455,8 +473,10 @@ substring
substrings
subtree
subtrees
+sudo
syslog
tcpdump
+Thanos
Tiller
timecop
todos
@@ -479,6 +499,7 @@ unarchived
unarchives
unarchiving
unassign
+unassigning
unassigns
uncheck
unchecked
@@ -510,6 +531,9 @@ unprioritized
unprotect
unprotected
unprotects
+unprovision
+unprovisioned
+unprovisions
unpublish
unpublished
unpublishes
diff --git a/doc/README.md b/doc/README.md
index efae2cdd3ff..09638bb4ce8 100644
--- a/doc/README.md
+++ b/doc/README.md
@@ -85,14 +85,14 @@ The following sections provide links to documentation for each DevOps stage:
### Manage
-GitLab provides statistics and insight into ways you can maximize the value of GitLab in your organization.
+GitLab provides statistics and insights into ways you can maximize the value of GitLab in your organization.
The following documentation relates to the DevOps **Manage** stage:
| Manage topics | Description |
|:--------------------------------------------------------------------------------------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| [Authentication and<br/>Authorization](administration/auth/README.md) **(CORE ONLY)** | Supported authentication and authorization providers. |
-| [GitLab Value Stream Analytics](user/project/cycle_analytics.md) | Measure the time it takes to go from an [idea to production](https://about.gitlab.com/blog/2016/08/05/continuous-integration-delivery-and-deployment-with-gitlab/#from-idea-to-production-with-gitlab) for each project you have. |
+| [GitLab Value Stream Analytics](user/analytics/value_stream_analytics.md) | Measure the time it takes to go from an [idea to production](https://about.gitlab.com/blog/2016/08/05/continuous-integration-delivery-and-deployment-with-gitlab/#from-idea-to-production-with-gitlab) for each project you have. |
| [Instance-level Analytics](user/admin_area/analytics/index.md) | Discover statistics on how many GitLab features you use and user activity. |
<div align="right">
@@ -121,7 +121,7 @@ The following documentation relates to the DevOps **Plan** stage:
| [Milestones](user/project/milestones/index.md) | Set milestones for delivery of issues and merge requests, with optional due date. |
| [Project Issue Board](user/project/issue_board.md) | Display issues on a Scrum or Kanban board. |
| [Quick Actions](user/project/quick_actions.md) | Shortcuts for common actions on issues or merge requests, replacing the need to click buttons or use dropdowns in GitLab's UI. |
-| [Related Issues](user/project/issues/related_issues.md) **(STARTER)** | Create a relationship between issues. |
+| [Related Issues](user/project/issues/related_issues.md) | Create a relationship between issues. |
| [Requirements Management](user/project/requirements/index.md) **(ULTIMATE)** | Check your products against a set of criteria. |
| [Roadmap](user/group/roadmap/index.md) **(ULTIMATE)** | Visualize epic timelines. |
| [Service Desk](user/project/service_desk.md) | A simple way to allow people to create issues in your GitLab instance without needing their own user account. |
@@ -218,7 +218,7 @@ The following documentation relates to the DevOps **Create** stage:
| [GitLab GraphQL API](api/graphql/index.md) | Integrate with GitLab using our GraphQL API. |
| [GitLab Integration](integration/README.md) | Integrate with multiple third-party services with GitLab to allow external issue trackers and external authentication. |
| [GitLab Webhooks](user/project/integrations/webhooks.md) | Let GitLab notify you when new code has been pushed to your project. |
-| [Jira Development Panel](integration/jira_development_panel.md) **(PREMIUM)** | See GitLab information in the Jira Development Panel. |
+| [Jira Development Panel](integration/jira_development_panel.md) | See GitLab information in the Jira Development Panel. |
| [Integrations](user/project/integrations/overview.md) | Integrate a project with external services, such as CI and chat. |
| [Trello Power-Up](integration/trello_power_up.md) | Integrate with GitLab's Trello Power-Up. |
@@ -267,9 +267,7 @@ The following documentation relates to the DevOps **Package** stage:
|:----------------------------------------------------------------|:-------------------------------------------------------|
| [Container Registry](user/packages/container_registry/index.md) | The GitLab Container Registry enables every project in GitLab to have its own space to store [Docker](https://www.docker.com/) images. |
| [Dependency Proxy](user/packages/dependency_proxy/index.md) **(PREMIUM)** | The GitLab Dependency Proxy sets up a local proxy for frequently used upstream images/packages. |
-| [Conan Repository](user/packages/conan_repository/index.md) | The GitLab Conan Repository enables every project in GitLab to have its own space to store [Conan](https://conan.io/) packages. |
-| [Maven Repository](user/packages/maven_repository/index.md) | The GitLab Maven Repository enables every project in GitLab to have its own space to store [Maven](https://maven.apache.org/) packages. |
-| [NPM Registry](user/packages/npm_registry/index.md) | The GitLab NPM Registry enables every project in GitLab to have its own space to store [NPM](https://www.npmjs.com/) packages. |
+| [Package Registry](user/packages/package_registry/index.md) | Use GitLab as a private or public registry for a variety of common package managers, including [NPM](user/packages/npm_registry/index.md), [Maven](user/packages/maven_repository/index.md), [PyPI](user/packages/pypi_repository/index.md), and others. You can also store generic files. |
<div align="right">
<a type="button" class="btn btn-default" href="#overview">
@@ -295,7 +293,7 @@ The following documentation relates to the DevOps **Secure** stage:
| [Dependency Scanning](user/application_security/dependency_scanning/index.md) **(ULTIMATE)** | Analyze your dependencies for known vulnerabilities. |
| [Dynamic Application Security Testing (DAST)](user/application_security/dast/index.md) **(ULTIMATE)** | Analyze running web applications for known vulnerabilities. |
| [Group Security Dashboard](user/application_security/security_dashboard/index.md#group-security-dashboard) **(ULTIMATE)** | View vulnerabilities in all the projects in a group and its subgroups. |
-| [Instance Security Dashboard](user/application_security/security_dashboard/index.md#instance-security-dashboard) **(ULTIMATE)** | View vulnerabilities in all the projects you're interested in. |
+| [Instance Security Center](user/application_security/security_dashboard/index.md#instance-security-center) **(ULTIMATE)** | View vulnerabilities in all the projects you're interested in. |
| [License Compliance](user/compliance/license_compliance/index.md) **(ULTIMATE)** | Search your project's dependencies for their licenses. |
| [Pipeline Security](user/application_security/security_dashboard/index.md#pipeline-security) **(ULTIMATE)** | View the security reports for your project's pipelines. |
| [Project Security Dashboard](user/application_security/security_dashboard/index.md#project-security-dashboard) **(ULTIMATE)** | View the latest security reports for your project. |
diff --git a/doc/administration/audit_events.md b/doc/administration/audit_events.md
index 099346b2b0b..ac972e2e33e 100644
--- a/doc/administration/audit_events.md
+++ b/doc/administration/audit_events.md
@@ -9,7 +9,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
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/).
GitLab system administrators can also take advantage of the logs located on the
-filesystem. See [the logs system documentation](logs.md) for more details.
+file system. See [the logs system documentation](logs.md) for more details.
## Overview
@@ -108,7 +108,7 @@ Server-wide audit logging introduces the ability to observe user actions across
the entire instance of your GitLab server, making it easy to understand who
changed what and when for audit purposes.
-To view the server-wide admin log, visit **Admin Area > Monitoring > Audit Log**.
+To view the server-wide administrator log, visit **Admin Area > Monitoring > Audit Log**.
In addition to the group and project events, the following user actions are also
recorded:
@@ -126,6 +126,7 @@ recorded:
- User was added ([introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/251) in GitLab 12.8)
- User was blocked via Admin Area ([introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/251) in GitLab 12.8)
- User was blocked via API ([introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/25872) in GitLab 12.9)
+- Failed second-factor authentication attempt ([introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/16826) in GitLab 13.5)
It's possible to filter particular actions by choosing an audit data type from
the filter dropdown box. You can further filter by specific group, project, or user
@@ -151,7 +152,7 @@ on adding these events into GitLab:
The current architecture of audit events is not prepared to receive a very high amount of records.
It may make the user interface for your project or audit logs very busy, and the disk space consumed by the
-`audit_events` PostgreSQL table will increase considerably. It's disabled by default
+`audit_events` PostgreSQL table may increase considerably. It's disabled by default
to prevent performance degradations on GitLab instances with very high Git write traffic.
In an upcoming release, Audit Logs for Git push events will be enabled
@@ -172,6 +173,7 @@ the steps bellow.
```ruby
Feature.enable(:repository_push_audit_event)
+ ```
## Export to CSV **(PREMIUM ONLY)**
@@ -183,6 +185,7 @@ the steps bellow.
CAUTION: **Warning:**
This feature might not be available to you. Check the **version history** note above for details.
+If available, you can enable it with a [feature flag](#enable-or-disable-audit-log-export-to-csv).
Export to CSV allows customers to export the current filter view of your audit log as a
CSV file,
diff --git a/doc/administration/auditor_users.md b/doc/administration/auditor_users.md
index ace210183b2..c41065abd17 100644
--- a/doc/administration/auditor_users.md
+++ b/doc/administration/auditor_users.md
@@ -1,34 +1,39 @@
-# Auditor users **(PREMIUM ONLY)**
+---
+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/engineering/ux/technical-writing/#designated-technical-writers
+---
->[Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/998) in [GitLab Premium](https://about.gitlab.com/pricing/) 8.17.
+# Auditor users **(PREMIUM ONLY)**
Auditor users are given read-only access to all projects, groups, and other
resources on the GitLab instance.
## Overview
-Auditor users can have full access to their own resources (projects, groups,
-snippets, etc.), and read-only access to **all** other resources, except the
-Admin Area. To put another way, they are just regular users (who can be added
-to projects, create personal snippets, create milestones on their groups, etc.)
-who also happen to have read-only access to all projects on the system that
-they haven't been explicitly [given access](../user/permissions.md) to.
+Auditor users are able to have both full access to their own resources
+(including projects, groups, and snippets) and read-only access to _all_ other
+resources, except the [Admin Area](../user/admin_area/index.md). These user
+accounts are regular users who can be added to projects, create personal
+snippets, and create milestones on their groups, while also having read-only
+access to all projects on the server to which they haven't been explicitly
+[given access](../user/permissions.md).
The Auditor role is _not_ a read-only version of the Admin role. Auditor users
-will not be able to access the project/group settings pages, or the Admin Area.
+can't access the project or group settings pages, or the Admin Area.
-To sum up, assuming you have logged-in as an Auditor user:
+Assuming you have signed in as an Auditor user:
- For a project the Auditor is not member of, the Auditor should have
- read-only access. If the project is public or internal, they would have the
- same access as the users that are not members of that project/group.
+ read-only access. If the project is public or internal, they have the same
+ access as users that aren't members of that project or group.
- For a project the Auditor owns, the Auditor should have full access to
everything.
-- For a project the Auditor has been added to as a member, the Auditor should
- have the same access as the [permissions](../user/permissions.md) they were given to. For example, if
- they were added as a Developer, they could then push commits or comment on
- issues.
-- The Auditor cannot view the Admin Area, or perform any admin actions.
+- For a project to which the Auditor is added as a member, the Auditor should
+ have the same access as their given [permissions](../user/permissions.md).
+ For example, if they were added as a Developer, they can push commits or
+ comment on issues.
+- The Auditor can't view the Admin Area, or perform any admin actions.
For more information about what an Auditor can or can't do, see the
[Permissions and restrictions of an Auditor user](#permissions-and-restrictions-of-an-auditor-user)
@@ -36,33 +41,37 @@ section.
## Use cases
-1. Your compliance department wants to run tests against the entire GitLab base
- to ensure users are complying with password, credit card, and other sensitive
- data policies. With Auditor users, this can be achieved very easily without
- resulting to tactics like giving a user admin rights or having to use the API
- to add them to all projects.
-1. If particular users need visibility or access to most of all projects in
- your GitLab instance, instead of manually adding the user to all projects,
- you can simply create an Auditor user and share the credentials with those
- that you want to grant access to.
+The following use cases describe some situations where Auditor users could be
+helpful:
+
+- Your compliance department wants to run tests against the entire GitLab base
+ to ensure users are complying with password, credit card, and other sensitive
+ data policies. With Auditor users, this can be achieved very without having
+ to give them user admin rights or using the API to add them to all projects.
+- If particular users need visibility or access to most of all projects in
+ your GitLab instance, instead of manually adding the user to all projects,
+ you can create an Auditor user and then share the credentials with those users
+ to which you want to grant access.
## Adding an Auditor user
+To create a new Auditor user:
+
1. Create a new user or edit an existing one by navigating to
- **Admin Area > Users**. You will find the option of the access level under
+ **Admin Area > Users**. You will find the option of the access level in
the 'Access' section.
![Admin Area Form](img/auditor_access_form.png)
-1. Click **Save changes** or **Create user** for the changes to take effect.
+1. Select **Save changes** or **Create user** for the changes to take effect.
-To revoke the Auditor permissions from a user, simply make them a Regular user
-following the same steps as above.
+To revoke Auditor permissions from a user, make them a regular user by
+following the previous steps.
## Permissions and restrictions of an Auditor user
An Auditor user should be able to access all projects and groups of a GitLab
-instance, with the following permissions/restrictions:
+instance, with the following permissions and restrictions:
- Has read-only access to the API
- Can access projects that are:
@@ -70,15 +79,15 @@ instance, with the following permissions/restrictions:
- Public
- Internal
- Can read all files in a repository
-- Can read issues / MRs
+- Can read issues and MRs
- Can read project snippets
- Cannot be Admin and Auditor at the same time
- Cannot access the Admin Area
-- In a group / project they're not a member of:
+- In a group or project they're not a member of:
- Cannot access project settings
- Cannot access group settings
- Cannot commit to repository
- - Cannot create / comment on issues / MRs
- - Cannot create/modify files from the Web UI
+ - Cannot create or comment on issues and MRs
+ - Cannot create or modify files from the Web UI
- Cannot merge a merge request
- Cannot create project snippets
diff --git a/doc/administration/auth/README.md b/doc/administration/auth/README.md
index 926a4abab7d..cf82454cfd2 100644
--- a/doc/administration/auth/README.md
+++ b/doc/administration/auth/README.md
@@ -18,7 +18,7 @@ providers:
- [Azure](../../integration/azure.md)
- [Bitbucket Cloud](../../integration/bitbucket.md)
- [CAS](../../integration/cas.md)
-- [Crowd](../../integration/crowd.md)
+- [Crowd](crowd.md)
- [Facebook](../../integration/facebook.md)
- [GitHub](../../integration/github.md)
- [GitLab.com](../../integration/gitlab.md)
diff --git a/doc/administration/auth/ldap/index.md b/doc/administration/auth/ldap/index.md
index 1dac098ec0c..3df85babc94 100644
--- a/doc/administration/auth/ldap/index.md
+++ b/doc/administration/auth/ldap/index.md
@@ -12,6 +12,7 @@ GitLab integrates with LDAP to support user authentication.
This integration works with most LDAP-compliant directory servers, including:
- Microsoft Active Directory
+ - [Microsoft Active Directory Trusts](https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2008-R2-and-2008/cc771568(v=ws.10)) are not supported.
- Apple Open Directory
- Open LDAP
- 389 Server
@@ -21,9 +22,6 @@ Users added through LDAP take a [licensed seat](../../../subscriptions/self_mana
GitLab Enterprise Editions (EE) include enhanced integration,
including group membership syncing as well as multiple LDAP servers support.
-NOTE: **Note:**
-[Microsoft Active Directory Trusts](https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2008-R2-and-2008/cc771568(v=ws.10)) are not supported.
-
## Overview
[LDAP](https://en.wikipedia.org/wiki/Lightweight_Directory_Access_Protocol)
@@ -55,9 +53,8 @@ are already logged in or are using Git over SSH will still be able to access
GitLab for up to one hour. Manually block the user in the GitLab Admin Area to
immediately block all access.
-NOTE: **Note:**
GitLab Enterprise Edition Starter supports a
-[configurable sync time](#adjusting-ldap-user-sync-schedule).
+[configurable sync time](#adjusting-ldap-user-sync-schedule). **(STARTER)**
## Git password authentication **(CORE ONLY)**
@@ -100,7 +97,6 @@ library. `start_tls` corresponds to StartTLS, not to be confused with regular TL
Normally, if you specify `simple_tls` it will be on port 636, while `start_tls` (StartTLS)
would be on port 389. `plain` also operates on port 389. Removed values: `tls` was replaced with `start_tls` and `ssl` was replaced with `simple_tls`.
-NOTE: **Note:**
LDAP users must have an email address set, regardless of whether it is used to sign-in.
### Example Configurations **(CORE ONLY)**
@@ -120,7 +116,6 @@ gitlab_rails['ldap_servers'] = {
'verify_certificates' => true,
'bind_dn' => '_the_full_dn_of_the_user_you_will_bind_with',
'password' => '_the_password_of_the_bind_user',
- 'encryption' => 'plain',
'verify_certificates' => true,
'tls_options' => {
'ca_file' => '',
@@ -430,8 +425,7 @@ gitlab_rails['ldap_servers'] = {
}
```
-NOTE: **Note:**
-Any number of LDAP servers can be configured. However, make sure to use a unique naming convention for the `label` section of each entry as this will be the display name of the tab shown on the sign-in page.
+If you configure multiple LDAP servers, use a unique naming convention for the `label` section of each entry. That label is used as the display name of the tab shown on the sign-in page.
## User sync **(STARTER ONLY)**
@@ -445,11 +439,10 @@ The process executes the following access checks:
blocked/disabled state). This will only be checked if
`active_directory: true` is set in the LDAP configuration.
-NOTE: **Note:**
In Active Directory, a user is marked as disabled/blocked if the user
account control attribute (`userAccountControl:1.2.840.113556.1.4.803`)
-has bit 2 set. See <https://ctovswild.com/2009/09/03/bitmask-searches-in-ldap/>
-for more information.
+has bit 2 set.
+For more information, see <https://ctovswild.com/2009/09/03/bitmask-searches-in-ldap/>
The user will be set to `ldap_blocked` state in GitLab if the above conditions
fail. This means the user will not be able to sign-in or push/pull code.
@@ -460,8 +453,10 @@ The process will also update the following user information:
- If `sync_ssh_keys` is set, SSH public keys.
- If Kerberos is enabled, Kerberos identity.
-NOTE: **Note:**
-The LDAP sync process updates existing users while new users are created on first sign in.
+The LDAP sync process:
+
+- Updates existing users.
+- Creates new users on first sign in.
### Adjusting LDAP user sync schedule **(STARTER ONLY)**
@@ -469,11 +464,13 @@ NOTE: **Note:**
These are cron formatted values. You can use a crontab generator to create
these values, for example <http://www.crontabgenerator.com/>.
-By default, GitLab will run a worker once per day at 01:30 a.m. server time to
+By default, GitLab runs a worker once per day at 01:30 a.m. server time to
check and update GitLab users against LDAP.
You can manually configure LDAP user sync times by setting the
-following configuration values. The example below shows how to set LDAP user
+following configuration values, in cron format. If needed, you can
+use a [crontab generator](http://crontabgenerator.com).
+The example below shows how to set LDAP user
sync to run once every 12 hours at the top of the hour.
**Omnibus installations**
@@ -512,7 +509,7 @@ GitLab group membership to be automatically updated based on LDAP group members.
The `group_base` configuration should be a base LDAP 'container', such as an
'organization' or 'organizational unit', that contains LDAP groups that should
be available to GitLab. For example, `group_base` could be
-`ou=groups,dc=example,dc=com`. In the config file it will look like the
+`ou=groups,dc=example,dc=com`. In the configuration file it will look like the
following.
**Omnibus configuration**
@@ -617,14 +614,12 @@ To enable it you need to:
### Adjusting LDAP group sync schedule **(STARTER ONLY)**
-NOTE: **Note:**
-These are cron formatted values. You can use a crontab generator to create
-these values, for example [Crontab Generator](http://www.crontabgenerator.com/).
-
By default, GitLab runs a group sync process every hour, on the hour.
+The values shown are in cron format. If needed, you can use a
+[Crontab Generator](http://www.crontabgenerator.com).
CAUTION: **Important:**
-It's recommended that you do not start the sync process too frequently as this
+Do not start the sync process too frequently as this
could lead to multiple syncs running concurrently. This is primarily a concern
for installations with a large number of LDAP users. Please review the
[LDAP group sync benchmark metrics](#benchmarks) to see how
@@ -727,7 +722,8 @@ Other LDAP servers should work, too.
Active Directory also supports nested groups. Group sync will recursively
resolve membership if `active_directory: true` is set in the configuration file.
-NOTE: **Note:**
+##### Nested group memberships
+
Nested group memberships are resolved only if the nested group
is found within the configured `group_base`. For example, if GitLab sees a
nested group with DN `cn=nested_group,ou=special_groups,dc=example,dc=com` but
diff --git a/doc/administration/auth/ldap/ldap-troubleshooting.md b/doc/administration/auth/ldap/ldap-troubleshooting.md
index 3d3ac124ac4..c6558bf1791 100644
--- a/doc/administration/auth/ldap/ldap-troubleshooting.md
+++ b/doc/administration/auth/ldap/ldap-troubleshooting.md
@@ -682,7 +682,7 @@ The rails console is a valuable tool to help debug LDAP problems. It allows you
directly interact with the application by running commands and seeing how GitLab
responds to them.
-Please refer to [this guide](../../troubleshooting/debug.md#starting-a-rails-console-session)
+Please refer to [this guide](../../operations/rails_console.md#starting-a-rails-console-session)
for instructions on how to use the rails console.
#### Enable debug output
diff --git a/doc/administration/auth/smartcard.md b/doc/administration/auth/smartcard.md
index 0ecf3ca090d..a696d0499a4 100644
--- a/doc/administration/auth/smartcard.md
+++ b/doc/administration/auth/smartcard.md
@@ -1,4 +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/engineering/ux/technical-writing/#designated-technical-writers
type: reference
---
diff --git a/doc/administration/compliance.md b/doc/administration/compliance.md
index 237261f2567..44270283308 100644
--- a/doc/administration/compliance.md
+++ b/doc/administration/compliance.md
@@ -1,3 +1,9 @@
+---
+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/engineering/ux/technical-writing/#designated-technical-writers
+---
+
# Compliance features
You can configure the following GitLab features to help ensure that your GitLab instance meets common compliance standards. Click a feature name for further documentation.
diff --git a/doc/administration/consul.md b/doc/administration/consul.md
index ae22d8bd4d0..4eed020c284 100644
--- a/doc/administration/consul.md
+++ b/doc/administration/consul.md
@@ -1,4 +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/engineering/ux/technical-writing/#designated-technical-writers
type: reference
---
diff --git a/doc/administration/database_load_balancing.md b/doc/administration/database_load_balancing.md
index 36ef905fd90..e88f88a0427 100644
--- a/doc/administration/database_load_balancing.md
+++ b/doc/administration/database_load_balancing.md
@@ -1,3 +1,9 @@
+---
+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/engineering/ux/technical-writing/#designated-technical-writers
+---
+
# Database Load Balancing **(PREMIUM ONLY)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/1283) in [GitLab Premium](https://about.gitlab.com/pricing/) 9.0.
@@ -128,7 +134,7 @@ production:
disconnect_timeout: 120
```
-Here the `discover:` section specifies the configuration details to use for
+Here, the `discover:` section specifies the configuration details to use for
service discovery.
### Configuration
@@ -139,7 +145,7 @@ The following options can be set:
|----------------------|---------------------------------------------------------------------------------------------------|-----------|
| `nameserver` | The nameserver to use for looking up the DNS record. | localhost |
| `record` | The record to look up. This option is required for service discovery to work. | |
-| `record_type` | Optional record type to look up, this can be either A or SRV (since GitLab 12.3) | A |
+| `record_type` | Optional record type to look up, this can be either A or SRV (GitLab 12.3 and later) | A |
| `port` | The port of the nameserver. | 8600 |
| `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 |
diff --git a/doc/administration/environment_variables.md b/doc/administration/environment_variables.md
index d48a47e9645..25bfc3c132d 100644
--- a/doc/administration/environment_variables.md
+++ b/doc/administration/environment_variables.md
@@ -1,77 +1,75 @@
---
-stage: Verify
-group: Continuous Integration
+stage: Enablement
+group: Distribution
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/#designated-technical-writers
type: reference
---
-# Environment Variables
+# Environment variables
GitLab exposes certain environment variables which can be used to override
their defaults values.
-People usually configure GitLab via `/etc/gitlab/gitlab.rb` for Omnibus
+People usually configure GitLab with `/etc/gitlab/gitlab.rb` for Omnibus
installations, or `gitlab.yml` for installations from source.
-Below you will find the supported environment variables which you can use to
-override certain values.
+You can use the following environment variables to override certain values:
## Supported environment variables
-Variable | Type | Description
--------- | ---- | -----------
-`ENABLE_BOOTSNAP` | string | Enables Bootsnap for speeding up initial Rails boot (`1` to enable)
-`GITLAB_CDN_HOST` | string | Sets the base URL for a CDN to serve static assets (e.g. `//mycdnsubdomain.fictional-cdn.com`)
-`GITLAB_ROOT_PASSWORD` | string | Sets the password for the `root` user on installation
-`GITLAB_HOST` | string | The full URL of the GitLab server (including `http://` or `https://`)
-`RAILS_ENV` | string | The Rails environment; can be one of `production`, `development`, `staging` or `test`
-`DATABASE_URL` | string | The database URL; is of the form: `postgresql://localhost/blog_development`
-`GITLAB_EMAIL_FROM` | string | The e-mail address used in the "From" field in e-mails sent by GitLab
-`GITLAB_EMAIL_DISPLAY_NAME` | string | The name used in the "From" field in e-mails sent by GitLab
-`GITLAB_EMAIL_REPLY_TO` | string | The e-mail address used in the "Reply-To" field in e-mails sent by GitLab
-`GITLAB_EMAIL_SUBJECT_SUFFIX` | string | The e-mail subject suffix used in e-mails sent by GitLab
-`GITLAB_UNICORN_MEMORY_MIN` | integer | The minimum memory threshold (in bytes) for the Unicorn worker killer
-`GITLAB_UNICORN_MEMORY_MAX` | integer | The maximum memory threshold (in bytes) for the Unicorn worker killer
-`GITLAB_SHARED_RUNNERS_REGISTRATION_TOKEN` | string | Sets the initial registration token used for runners
-`UNSTRUCTURED_RAILS_LOG` | string | Enables the unstructured log in addition to JSON logs (defaults to `true`)
+| Variable | Type | Description |
+|--------------------------------------------|---------|---------------------------------------------------------------------------------------------------------|
+| `DATABASE_URL` | string | The database URL; is of the form: `postgresql://localhost/blog_development`. |
+| `ENABLE_BOOTSNAP` | string | Enables Bootsnap for speeding up initial Rails boot (`1` to enable). |
+| `GITLAB_CDN_HOST` | string | Sets the base URL for a CDN to serve static assets (for example, `//mycdnsubdomain.fictional-cdn.com`). |
+| `GITLAB_EMAIL_DISPLAY_NAME` | string | The name used in the **From** field in emails sent by GitLab. |
+| `GITLAB_EMAIL_FROM` | string | The email address used in the **From** field in emails sent by GitLab. |
+| `GITLAB_EMAIL_REPLY_TO` | string | The email address used in the **Reply-To** field in emails sent by GitLab. |
+| `GITLAB_EMAIL_SUBJECT_SUFFIX` | string | The email subject suffix used in emails sent by GitLab. |
+| `GITLAB_HOST` | string | The full URL of the GitLab server (including `http://` or `https://`). |
+| `GITLAB_ROOT_PASSWORD` | string | Sets the password for the `root` user on installation. |
+| `GITLAB_SHARED_RUNNERS_REGISTRATION_TOKEN` | string | Sets the initial registration token used for runners. |
+| `GITLAB_UNICORN_MEMORY_MAX` | integer | The maximum memory threshold (in bytes) for the [unicorn-worker-killer](operations/unicorn.md#unicorn-worker-killer). |
+| `GITLAB_UNICORN_MEMORY_MIN` | integer | The minimum memory threshold (in bytes) for the [unicorn-worker-killer](operations/unicorn.md#unicorn-worker-killer). |
+| `RAILS_ENV` | string | The Rails environment; can be one of `production`, `development`, `staging`, or `test`. |
+| `UNSTRUCTURED_RAILS_LOG` | string | Enables the unstructured log in addition to JSON logs (defaults to `true`). |
## Complete database variables
-The recommended way of specifying your database connection information is to set
-the `DATABASE_URL` environment variable. This variable only holds connection
-information (`adapter`, `database`, `username`, `password`, `host` and `port`),
-but not behavior information (`encoding`, `pool`). If you don't want to use
-`DATABASE_URL` and/or want to set database behavior information, you will have
-to either:
+The recommended method for specifying your database connection information is
+to set the `DATABASE_URL` environment variable. This variable contains
+connection information (`adapter`, `database`, `username`, `password`, `host`,
+and `port`), but no behavior information (`encoding` or `pool`). If you don't
+want to use `DATABASE_URL`, or want to set database behavior information,
+either:
-- copy our template file: `cp config/database.yml.env config/database.yml`, or
-- set a value for some `GITLAB_DATABASE_XXX` variables
+- Copy the template file, `cp config/database.yml.env config/database.yml`.
+- Set a value for some `GITLAB_DATABASE_XXX` variables.
The list of `GITLAB_DATABASE_XXX` variables that you can set is:
-Variable | Default value | Overridden by `DATABASE_URL`?
--------- | ------------- | -----------------------------
-`GITLAB_DATABASE_ADAPTER` | `postgresql` | Yes
-`GITLAB_DATABASE_DATABASE` | `gitlab_#{ENV['RAILS_ENV']` | Yes
-`GITLAB_DATABASE_USERNAME` | `root` | Yes
-`GITLAB_DATABASE_PASSWORD` | None | Yes
-`GITLAB_DATABASE_HOST` | `localhost` | Yes
-`GITLAB_DATABASE_PORT` | `5432` | Yes
-`GITLAB_DATABASE_ENCODING` | `unicode` | No
-`GITLAB_DATABASE_POOL` | `10` | No
+| Variable | Default value | Overridden by `DATABASE_URL`? |
+|-----------------------------|--------------------------------|-------------------------------|
+| `GITLAB_DATABASE_ADAPTER` | `postgresql` | **{check-circle}** Yes |
+| `GITLAB_DATABASE_DATABASE` | `gitlab_#{ENV['RAILS_ENV']` | **{check-circle}** Yes |
+| `GITLAB_DATABASE_ENCODING` | `unicode` | **{dotted-circle}** No |
+| `GITLAB_DATABASE_HOST` | `localhost` | **{check-circle}** Yes |
+| `GITLAB_DATABASE_PASSWORD` | _none_ | **{check-circle}** Yes |
+| `GITLAB_DATABASE_POOL` | `10` | **{dotted-circle}** No |
+| `GITLAB_DATABASE_PORT` | `5432` | **{check-circle}** Yes |
+| `GITLAB_DATABASE_USERNAME` | `root` | **{check-circle}** Yes |
## Adding more variables
-We welcome merge requests to make more settings configurable via variables.
-Please make changes in the `config/initializers/1_settings.rb` file and stick
-to the naming scheme `GITLAB_#{name in 1_settings.rb in upper case}`.
+We welcome merge requests to make more settings configurable by using variables.
+Make changes to the `config/initializers/1_settings.rb` file, and use the
+naming scheme `GITLAB_#{name in 1_settings.rb in upper case}`.
## Omnibus configuration
-To set environment variables, follow [these
-instructions](https://docs.gitlab.com/omnibus/settings/environment-variables.html).
+To set environment variables, follow [these instructions](https://docs.gitlab.com/omnibus/settings/environment-variables.html).
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)
-section in the Omnibus documentation.
+For more information, see the [Pre-configure Docker container](https://docs.gitlab.com/omnibus/docker/#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 a8a14063f26..4129677f134 100644
--- a/doc/administration/feature_flags.md
+++ b/doc/administration/feature_flags.md
@@ -65,7 +65,7 @@ For installations from the source:
sudo -u git -H bundle exec rails console -e production
```
-For details, see [starting a Rails console session](troubleshooting/debug.md#starting-a-rails-console-session).
+For details, see [starting a Rails console session](operations/rails_console.md#starting-a-rails-console-session).
### Enable or disable the feature
@@ -79,10 +79,10 @@ To enable a feature, run:
Feature.enable(:<feature flag>)
```
-Example, to enable Evidence Collection:
+Example, to enable a fictional feature flag named `my_awesome_feature`:
```ruby
-Feature.enable(:release_evidence_collection)
+Feature.enable(:my_awesome_feature)
```
To disable a feature, run:
@@ -91,10 +91,10 @@ To disable a feature, run:
Feature.disable(:<feature flag>)
```
-Example, to disable Evidence Collection:
+Example, to disable a fictional feature flag named `my_awesome_feature`:
```ruby
-Feature.disable(:release_evidence_collection)
+Feature.disable(:my_awesome_feature)
```
Some feature flags can be enabled or disabled on a per project basis:
@@ -112,18 +112,18 @@ Feature.enable(:product_analytics, Project.find(1234))
`Feature.enable` and `Feature.disable` always return `nil`, this is not an indication that the command failed:
```ruby
-irb(main):001:0> Feature.enable(:release_evidence_collection)
+irb(main):001:0> Feature.enable(:my_awesome_feature)
=> nil
```
-To check if a flag is enabled or disabled you can use `Feature.enabled?` or `Feature.disabled?`:
+To check if a flag is enabled or disabled you can use `Feature.enabled?` or `Feature.disabled?`. For example, for a fictional feature flag named `my_awesome_feature`:
```ruby
-Feature.enable(:release_evidence_collection)
+Feature.enable(:my_awesome_feature)
=> nil
-Feature.enabled?(:release_evidence_collection)
+Feature.enabled?(:my_awesome_feature)
=> true
-Feature.disabled?(:release_evidence_collection)
+Feature.disabled?(:my_awesome_feature)
=> false
```
diff --git a/doc/administration/geo/disaster_recovery/index.md b/doc/administration/geo/disaster_recovery/index.md
index 8862776ee1b..32b3558a51f 100644
--- a/doc/administration/geo/disaster_recovery/index.md
+++ b/doc/administration/geo/disaster_recovery/index.md
@@ -11,11 +11,11 @@ Geo replicates your database, your Git repositories, and few other assets.
We will support and replicate more data in the future, that will enable you to
failover with minimal effort, in a disaster situation.
-See [Geo current limitations](../index.md#current-limitations) for more information.
+See [Geo limitations](../index.md#limitations) for more information.
CAUTION: **Warning:**
Disaster recovery for multi-secondary configurations is in **Alpha**.
-For the latest updates, check the [Disaster Recovery epic for complete maturity](https://gitlab.com/groups/gitlab-org/-/epics/590).
+For the latest updates, check the [Disaster Recovery epic for complete maturity](https://gitlab.com/groups/gitlab-org/-/epics/590).
Multi-secondary configurations require the complete re-synchronization and re-configuration of all non-promoted secondaries and
will cause downtime.
@@ -84,8 +84,8 @@ must disable the **primary** node.
single recommendation. You may need to:
- Reconfigure the load balancers.
- - Change DNS records (for example, point the primary DNS record to the **secondary**
- node in order to stop usage of the **primary** node).
+ - Change DNS records (for example, point the primary DNS record to the
+ **secondary** node to stop usage of the **primary** node).
- Stop the virtual servers.
- Block traffic through a firewall.
- Revoke object storage permissions from the **primary** node.
@@ -98,16 +98,16 @@ must disable the **primary** node.
Note the following when promoting a secondary:
-- If replication was paused on the secondary node, for example as a part of upgrading,
- while you were running a version of GitLab lower than 13.4, you _must_
- [enable the node via the database](../replication/troubleshooting.md#while-promoting-the-secondary-i-got-an-error-activerecordrecordinvalid)
+- If replication was paused on the secondary node (for example as a part of
+ upgrading, while you were running a version of GitLab earlier than 13.4), you
+ _must_ [enable the node by using the database](../replication/troubleshooting.md#message-activerecordrecordinvalid-validation-failed-enabled-geo-primary-node-cannot-be-disabled)
before proceeding.
- A new **secondary** should not be added at this time. If you want to add a new
**secondary**, do this after you have completed the entire process of promoting
the **secondary** to the **primary**.
- If you encounter an `ActiveRecord::RecordInvalid: Validation failed: Name has already been taken`
- error during this process, please read
- [the troubleshooting advice](../replication/troubleshooting.md#fixing-errors-during-a-failover-or-when-promoting-a-secondary-to-a-primary-node).
+ error message during this process, for more information, see this
+ [troubleshooting advice](../replication/troubleshooting.md#fixing-errors-during-a-failover-or-when-promoting-a-secondary-to-a-primary-node).
#### Promoting a **secondary** node running on a single machine
@@ -120,6 +120,10 @@ Note the following when promoting a secondary:
1. Edit `/etc/gitlab/gitlab.rb` to reflect its new status as **primary** by
removing any lines that enabled the `geo_secondary_role`:
+ Users of GitLab 13.5 or later can skip this step, due to the appropriate
+ roles being enabled or disabled during the promotion in the following
+ step.
+
```ruby
## In pre-11.5 documentation, the role was enabled as follows. Remove this line.
geo_secondary_role['enable'] = true
@@ -129,7 +133,10 @@ Note the following when promoting a secondary:
```
1. Promote the **secondary** node to the **primary** node.
-
+
+DANGER: **Danger:**
+In GitLab 13.2 and later versions, promoting a secondary node to a primary while the secondary is paused fails. We are [investigating the issue](https://gitlab.com/gitlab-org/gitlab/-/issues/225173). Do not pause replication before promoting a secondary. If the node is paused, please resume before promoting.
+
To promote the secondary node to primary along with preflight checks:
```shell
@@ -139,7 +146,7 @@ Note the following when promoting a secondary:
If you have already run the [preflight checks](planned_failover.md#preflight-checks) separately or don't want to run them, you can skip preflight checks with:
```shell
- gitlab-ctl promote-to-primary-node --skip-preflight-check
+ gitlab-ctl promote-to-primary-node --skip-preflight-checks
```
You can also promote the secondary node to primary **without any further confirmation**, even when preflight checks fail:
@@ -159,6 +166,9 @@ conjunction with multiple servers, as it can only
perform changes on a **secondary** with only a single machine. Instead, you must
do this manually.
+DANGER: **Danger:**
+In GitLab 13.2 and later versions, promoting a secondary node to a primary while the secondary is paused fails. We are [investigating the issue](https://gitlab.com/gitlab-org/gitlab/-/issues/225173). Do not pause replication before promoting a secondary. If the node is paused, please resume before promoting.
+
1. SSH in to the database node in the **secondary** and trigger PostgreSQL to
promote to read-write:
@@ -201,6 +211,9 @@ an external PostgreSQL database, as it can only perform changes on a **secondary
node with GitLab and the database on the same machine. As a result, a manual process is
required:
+DANGER: **Danger:**
+In GitLab 13.2 and later versions, promoting a secondary node to a primary while the secondary is paused fails. We are [investigating the issue](https://gitlab.com/gitlab-org/gitlab/-/issues/225173). Do not pause replication before promoting a secondary. If the node is paused, please resume before promoting.
+
1. Promote the replica database associated with the **secondary** site. This will
set the database to read-write:
- Amazon RDS - [Promoting a Read Replica to Be a Standalone DB Instance](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_ReadRepl.html#USER_ReadRepl.Promote)
diff --git a/doc/administration/geo/disaster_recovery/planned_failover.md b/doc/administration/geo/disaster_recovery/planned_failover.md
index 9b9c386652c..1238c4d8e2a 100644
--- a/doc/administration/geo/disaster_recovery/planned_failover.md
+++ b/doc/administration/geo/disaster_recovery/planned_failover.md
@@ -27,7 +27,7 @@ have a high degree of confidence in being able to perform them accurately.
## Not all data is automatically replicated
-If you are using any GitLab features that Geo [doesn't support](../index.md#current-limitations),
+If you are using any GitLab features that Geo [doesn't support](../index.md#limitations),
you must make separate provisions to ensure that the **secondary** node has an
up-to-date copy of any data associated with that feature. This may extend the
required scheduled maintenance period significantly.
diff --git a/doc/administration/geo/disaster_recovery/promotion_runbook.md b/doc/administration/geo/disaster_recovery/promotion_runbook.md
index fb2353513df..7eb6ef01aee 100644
--- a/doc/administration/geo/disaster_recovery/promotion_runbook.md
+++ b/doc/administration/geo/disaster_recovery/promotion_runbook.md
@@ -1,269 +1,5 @@
---
-stage: Enablement
-group: Geo
-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/#designated-technical-writers
-type: howto
+redirect_to: runbooks/planned_failover_single_node.md
---
-CAUTION: **Caution:**
-This runbook is in **alpha**. For complete, production-ready documentation, see the
-[disaster recovery documentation](index.md).
-
-# Disaster Recovery (Geo) promotion runbooks **(PREMIUM ONLY)**
-
-## Geo planned failover runbook 1
-
-| Component | Configuration |
-| ----------- | --------------- |
-| PostgreSQL | Omnibus-managed |
-| Geo site | Single-node |
-| Secondaries | One |
-
-This runbook will guide you through a planned failover of a single-node Geo site
-with one secondary. The following general architecture is assumed:
-
-```mermaid
-graph TD
- subgraph main[Geo deployment]
- subgraph Primary[Primary site]
- Node_1[(GitLab node)]
- end
- subgraph Secondary1[Secondary site]
- Node_2[(GitLab node)]
- end
- end
-```
-
-This guide will result in the following:
-
-1. An offline primary.
-1. A promoted secondary that is now the new primary.
-
-What is not covered:
-
-1. Re-adding the old **primary** as a secondary.
-1. Adding a new secondary.
-
-### Preparation
-
-NOTE: **Note:**
-Before following any of those steps, make sure you have `root` access to the
-**secondary** to promote it, since there isn't provided an automated way to
-promote a Geo replica and perform a failover.
-
-On the **secondary** node, navigate to the **Admin Area > Geo** dashboard to
-review its status. Replicated objects (shown in green) should be close to 100%,
-and there should be no failures (shown in red). If a large proportion of
-objects aren't yet replicated (shown in gray), consider giving the node more
-time to complete.
-
-![Replication status](img/replication-status.png)
-
-If any objects are failing to replicate, this should be investigated before
-scheduling the maintenance window. After a planned failover, anything that
-failed to replicate will be **lost**.
-
-You can use the
-[Geo status API](../../../api/geo_nodes.md#retrieve-project-sync-or-verification-failures-that-occurred-on-the-current-node)
-to review failed objects and the reasons for failure.
-A common cause of replication failures is the data being missing on the
-**primary** node - you can resolve these failures by restoring the data from backup,
-or removing references to the missing data.
-
-The maintenance window won't end until Geo replication and verification is
-completely finished. To keep the window as short as possible, you should
-ensure these processes are close to 100% as possible during active use.
-
-If the **secondary** node is still replicating data from the **primary** node,
-follow these steps to avoid unnecessary data loss:
-
-1. Until a [read-only mode](https://gitlab.com/gitlab-org/gitlab/-/issues/14609)
- is implemented, updates must be prevented from happening manually to the
- **primary**. Note that your **secondary** node still needs read-only
- access to the **primary** node during the maintenance window:
-
- 1. At the scheduled time, using your cloud provider or your node's firewall, block
- all HTTP, HTTPS and SSH traffic to/from the **primary** node, **except** for your IP and
- the **secondary** node's IP.
-
- For instance, you can run the following commands on the **primary** node:
-
- ```shell
- sudo iptables -A INPUT -p tcp -s <secondary_node_ip> --destination-port 22 -j ACCEPT
- sudo iptables -A INPUT -p tcp -s <your_ip> --destination-port 22 -j ACCEPT
- sudo iptables -A INPUT --destination-port 22 -j REJECT
-
- sudo iptables -A INPUT -p tcp -s <secondary_node_ip> --destination-port 80 -j ACCEPT
- sudo iptables -A INPUT -p tcp -s <your_ip> --destination-port 80 -j ACCEPT
- sudo iptables -A INPUT --tcp-dport 80 -j REJECT
-
- sudo iptables -A INPUT -p tcp -s <secondary_node_ip> --destination-port 443 -j ACCEPT
- sudo iptables -A INPUT -p tcp -s <your_ip> --destination-port 443 -j ACCEPT
- sudo iptables -A INPUT --tcp-dport 443 -j REJECT
- ```
-
- From this point, users will be unable to view their data or make changes on the
- **primary** node. They will also be unable to log in to the **secondary** node.
- However, existing sessions will work for the remainder of the maintenance period, and
- public data will be accessible throughout.
-
- 1. Verify the **primary** node is blocked to HTTP traffic by visiting it in browser via
- another IP. The server should refuse connection.
-
- 1. Verify the **primary** node is blocked to Git over SSH traffic by attempting to pull an
- existing Git repository with an SSH remote URL. The server should refuse
- connection.
-
- 1. On the **primary** node, disable non-Geo periodic background jobs by navigating
- to **Admin Area > Monitoring > Background Jobs > Cron**, clicking `Disable All`,
- and then clicking `Enable` for the `geo_sidekiq_cron_config_worker` cron job.
- This job will re-enable several other cron jobs that are essential for planned
- failover to complete successfully.
-
-1. Finish replicating and verifying all data:
-
- CAUTION: **Caution:**
- Not all data is automatically replicated. Read more about
- [what is excluded](planned_failover.md#not-all-data-is-automatically-replicated).
-
- 1. If you are manually replicating any
- [data not managed by Geo](../replication/datatypes.md#limitations-on-replicationverification),
- trigger the final replication process now.
- 1. On the **primary** node, navigate to **Admin Area > Monitoring > Background Jobs > Queues**
- and wait for all queues except those with `geo` in the name to drop to 0.
- These queues contain work that has been submitted by your users; failing over
- before it is completed will cause the work to be lost.
- 1. On the **primary** node, navigate to **Admin Area > Geo** and wait for the
- following conditions to be true of the **secondary** node you are failing over to:
- - All replication meters to each 100% replicated, 0% failures.
- - All verification meters reach 100% verified, 0% failures.
- - Database replication lag is 0ms.
- - The Geo log cursor is up to date (0 events behind).
-
- 1. On the **secondary** node, navigate to **Admin Area > Monitoring > Background Jobs > Queues**
- and wait for all the `geo` queues to drop to 0 queued and 0 running jobs.
- 1. On the **secondary** node, use [these instructions](../../raketasks/check.md)
- to verify the integrity of CI artifacts, LFS objects, and uploads in file
- storage.
-
- At this point, your **secondary** node will contain an up-to-date copy of everything the
- **primary** node has, meaning nothing will be lost when you fail over.
-
-1. In this final step, you need to permanently disable the **primary** node.
-
- CAUTION: **Caution:**
- When the **primary** node goes offline, there may be data saved on the **primary** node
- that has not been replicated to the **secondary** node. This data should be treated
- as lost if you proceed.
-
- TIP: **Tip:**
- If you plan to [update the **primary** domain DNS record](index.md#step-4-optional-updating-the-primary-domain-dns-record),
- you may wish to lower the TTL now to speed up propagation.
-
- When performing a failover, we want to avoid a split-brain situation where
- writes can occur in two different GitLab instances. So to prepare for the
- failover, you must disable the **primary** node:
-
- - If you have SSH access to the **primary** node, stop and disable GitLab:
-
- ```shell
- sudo gitlab-ctl stop
- ```
-
- Prevent GitLab from starting up again if the server unexpectedly reboots:
-
- ```shell
- sudo systemctl disable gitlab-runsvdir
- ```
-
- NOTE: **Note:**
- (**CentOS only**) In CentOS 6 or older, there is no easy way to prevent GitLab from being
- started if the machine reboots isn't available (see [Omnibus GitLab issue #3058](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/3058)).
- It may be safest to uninstall the GitLab package completely with `sudo yum remove gitlab-ee`.
-
- NOTE: **Note:**
- (**Ubuntu 14.04 LTS**) If you are using an older version of Ubuntu
- or any other distribution based on the Upstart init system, you can prevent GitLab
- from starting if the machine reboots as `root` with
- `initctl stop gitlab-runsvvdir && echo 'manual' > /etc/init/gitlab-runsvdir.override && initctl reload-configuration`.
-
- - If you do not have SSH access to the **primary** node, take the machine offline and
- prevent it from rebooting. Since there are many ways you may prefer to accomplish
- this, we will avoid a single recommendation. You may need to:
-
- - Reconfigure the load balancers.
- - Change DNS records (for example, point the **primary** DNS record to the **secondary**
- node in order to stop usage of the **primary** node).
- - Stop the virtual servers.
- - Block traffic through a firewall.
- - Revoke object storage permissions from the **primary** node.
- - Physically disconnect a machine.
-
-### Promoting the **secondary** node
-
-Note the following when promoting a secondary:
-
-- A new **secondary** should not be added at this time. If you want to add a new
- **secondary**, do this after you have completed the entire process of promoting
- the **secondary** to the **primary**.
-- If you encounter an `ActiveRecord::RecordInvalid: Validation failed: Name has already been taken`
- error during this process, read
- [the troubleshooting advice](../replication/troubleshooting.md#fixing-errors-during-a-failover-or-when-promoting-a-secondary-to-a-primary-node).
-
-To promote the secondary node:
-
-1. SSH in to your **secondary** node and login as root:
-
- ```shell
- sudo -i
- ```
-
-1. Edit `/etc/gitlab/gitlab.rb` to reflect its new status as **primary** by
- removing any lines that enabled the `geo_secondary_role`:
-
- ```ruby
- ## In pre-11.5 documentation, the role was enabled as follows. Remove this line.
- geo_secondary_role['enable'] = true
-
- ## In 11.5+ documentation, the role was enabled as follows. Remove this line.
- roles ['geo_secondary_role']
- ```
-
-1. Run the following command to list out all preflight checks and automatically
- check if replication and verification are complete before scheduling a planned
- failover to ensure the process will go smoothly:
-
- ```shell
- gitlab-ctl promotion-preflight-checks
- ```
-
-1. Promote the **secondary**:
-
- ```shell
- gitlab-ctl promote-to-primary-node
- ```
-
- If you have already run the [preflight checks](planned_failover.md#preflight-checks)
- or don't want to run them, you can skip them:
-
- ```shell
- gitlab-ctl promote-to-primary-node --skip-preflight-check
- ```
-
- You can also promote the secondary node to primary **without any further confirmation**, even when preflight checks fail:
-
- ```shell
- sudo gitlab-ctl promote-to-primary-node --force
- ```
-
-1. Verify you can connect to the newly promoted **primary** node using the URL used
- previously for the **secondary** node.
-
- If successful, the **secondary** node has now been promoted to the **primary** node.
-
-### Next steps
-
-To regain geographic redundancy as quickly as possible, you should
-[add a new **secondary** node](../setup/index.md). To
-do that, you can re-add the old **primary** as a new secondary and bring it back
-online.
+This document was moved to [another location](runbooks/planned_failover_single_node.md).
diff --git a/doc/administration/geo/disaster_recovery/runbooks/planned_failover_multi_node.md b/doc/administration/geo/disaster_recovery/runbooks/planned_failover_multi_node.md
new file mode 100644
index 00000000000..1e3bac0b354
--- /dev/null
+++ b/doc/administration/geo/disaster_recovery/runbooks/planned_failover_multi_node.md
@@ -0,0 +1,274 @@
+---
+stage: Enablement
+group: Geo
+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/#designated-technical-writers
+type: howto
+---
+
+CAUTION: **Caution:**
+This runbook is in **alpha**. For complete, production-ready documentation, see the
+[disaster recovery documentation](../index.md).
+
+# Disaster Recovery (Geo) promotion runbooks **(PREMIUM ONLY)**
+
+## Geo planned failover for a multi-node configuration
+
+| Component | Configuration |
+|-------------|-----------------|
+| PostgreSQL | Omnibus-managed |
+| Geo site | Multi-node |
+| Secondaries | One |
+
+This runbook will guide you through a planned failover of a multi-node Geo site
+with one secondary. The following [2000 user reference architecture](../../../../administration/reference_architectures/2k_users.md) is assumed:
+
+```mermaid
+graph TD
+ subgraph main[Geo deployment]
+ subgraph Primary[Primary site, multi-node]
+ Node_1[Rails node 1]
+ Node_2[Rails node 2]
+ Node_3[PostgreSQL node]
+ Node_4[Gitaly node]
+ Node_5[Redis node]
+ Node_6[Monitoring node]
+ end
+ subgraph Secondary[Secondary site, multi-node]
+ Node_7[Rails node 1]
+ Node_8[Rails node 2]
+ Node_9[PostgreSQL node]
+ Node_10[Gitaly node]
+ Node_11[Redis node]
+ Node_12[Monitoring node]
+ end
+ end
+```
+
+The load balancer node and optional NFS server are omitted for clarity.
+
+This guide will result in the following:
+
+1. An offline primary.
+1. A promoted secondary that is now the new primary.
+
+What is not covered:
+
+1. Re-adding the old **primary** as a secondary.
+1. Adding a new secondary.
+
+### Preparation
+
+NOTE: **Note:**
+Before following any of those steps, make sure you have `root` access to the
+**secondary** to promote it, since there isn't provided an automated way to
+promote a Geo replica and perform a failover.
+
+On the **secondary** node, navigate to the **Admin Area > Geo** dashboard to
+review its status. Replicated objects (shown in green) should be close to 100%,
+and there should be no failures (shown in red). If a large proportion of
+objects aren't yet replicated (shown in gray), consider giving the node more
+time to complete.
+
+![Replication status](../img/replication-status.png)
+
+If any objects are failing to replicate, this should be investigated before
+scheduling the maintenance window. After a planned failover, anything that
+failed to replicate will be **lost**.
+
+You can use the
+[Geo status API](../../../../api/geo_nodes.md#retrieve-project-sync-or-verification-failures-that-occurred-on-the-current-node)
+to review failed objects and the reasons for failure.
+A common cause of replication failures is the data being missing on the
+**primary** node - you can resolve these failures by restoring the data from backup,
+or removing references to the missing data.
+
+The maintenance window won't end until Geo replication and verification is
+completely finished. To keep the window as short as possible, you should
+ensure these processes are close to 100% as possible during active use.
+
+If the **secondary** node is still replicating data from the **primary** node,
+follow these steps to avoid unnecessary data loss:
+
+1. Until a [read-only mode](https://gitlab.com/gitlab-org/gitlab/-/issues/14609)
+ is implemented, updates must be prevented from happening manually to the
+ **primary**. Note that your **secondary** node still needs read-only
+ access to the **primary** node during the maintenance window:
+
+ 1. At the scheduled time, using your cloud provider or your node's firewall, block
+ all HTTP, HTTPS and SSH traffic to/from the **primary** node, **except** for your IP and
+ the **secondary** node's IP.
+
+ For instance, you can run the following commands on the **primary** node:
+
+ ```shell
+ sudo iptables -A INPUT -p tcp -s <secondary_node_ip> --destination-port 22 -j ACCEPT
+ sudo iptables -A INPUT -p tcp -s <your_ip> --destination-port 22 -j ACCEPT
+ sudo iptables -A INPUT --destination-port 22 -j REJECT
+
+ sudo iptables -A INPUT -p tcp -s <secondary_node_ip> --destination-port 80 -j ACCEPT
+ sudo iptables -A INPUT -p tcp -s <your_ip> --destination-port 80 -j ACCEPT
+ sudo iptables -A INPUT --tcp-dport 80 -j REJECT
+
+ sudo iptables -A INPUT -p tcp -s <secondary_node_ip> --destination-port 443 -j ACCEPT
+ sudo iptables -A INPUT -p tcp -s <your_ip> --destination-port 443 -j ACCEPT
+ sudo iptables -A INPUT --tcp-dport 443 -j REJECT
+ ```
+
+ From this point, users will be unable to view their data or make changes on the
+ **primary** node. They will also be unable to log in to the **secondary** node.
+ However, existing sessions will work for the remainder of the maintenance period, and
+ public data will be accessible throughout.
+
+ 1. Verify the **primary** node is blocked to HTTP traffic by visiting it in browser via
+ another IP. The server should refuse connection.
+
+ 1. Verify the **primary** node is blocked to Git over SSH traffic by attempting to pull an
+ existing Git repository with an SSH remote URL. The server should refuse
+ connection.
+
+ 1. On the **primary** node, disable non-Geo periodic background jobs by navigating
+ to **Admin Area > Monitoring > Background Jobs > Cron**, clicking `Disable All`,
+ and then clicking `Enable` for the `geo_sidekiq_cron_config_worker` cron job.
+ This job will re-enable several other cron jobs that are essential for planned
+ failover to complete successfully.
+
+1. Finish replicating and verifying all data:
+
+ CAUTION: **Caution:**
+ Not all data is automatically replicated. Read more about
+ [what is excluded](../planned_failover.md#not-all-data-is-automatically-replicated).
+
+ 1. If you are manually replicating any
+ [data not managed by Geo](../../replication/datatypes.md#limitations-on-replicationverification),
+ trigger the final replication process now.
+ 1. On the **primary** node, navigate to **Admin Area > Monitoring > Background Jobs > Queues**
+ and wait for all queues except those with `geo` in the name to drop to 0.
+ These queues contain work that has been submitted by your users; failing over
+ before it is completed will cause the work to be lost.
+ 1. On the **primary** node, navigate to **Admin Area > Geo** and wait for the
+ following conditions to be true of the **secondary** node you are failing over to:
+ - All replication meters to each 100% replicated, 0% failures.
+ - All verification meters reach 100% verified, 0% failures.
+ - Database replication lag is 0ms.
+ - The Geo log cursor is up to date (0 events behind).
+
+ 1. On the **secondary** node, navigate to **Admin Area > Monitoring > Background Jobs > Queues**
+ and wait for all the `geo` queues to drop to 0 queued and 0 running jobs.
+ 1. On the **secondary** node, use [these instructions](../../../raketasks/check.md)
+ to verify the integrity of CI artifacts, LFS objects, and uploads in file
+ storage.
+
+ At this point, your **secondary** node will contain an up-to-date copy of everything the
+ **primary** node has, meaning nothing will be lost when you fail over.
+
+1. In this final step, you need to permanently disable the **primary** node.
+
+ CAUTION: **Caution:**
+ When the **primary** node goes offline, there may be data saved on the **primary** node
+ that has not been replicated to the **secondary** node. This data should be treated
+ as lost if you proceed.
+
+ TIP: **Tip:**
+ If you plan to [update the **primary** domain DNS record](../index.md#step-4-optional-updating-the-primary-domain-dns-record),
+ you may wish to lower the TTL now to speed up propagation.
+
+ When performing a failover, we want to avoid a split-brain situation where
+ writes can occur in two different GitLab instances. So to prepare for the
+ failover, you must disable the **primary** node:
+
+ - If you have SSH access to the **primary** node, stop and disable GitLab:
+
+ ```shell
+ sudo gitlab-ctl stop
+ ```
+
+ Prevent GitLab from starting up again if the server unexpectedly reboots:
+
+ ```shell
+ sudo systemctl disable gitlab-runsvdir
+ ```
+
+ NOTE: **Note:**
+ (**CentOS only**) In CentOS 6 or older, there is no easy way to prevent GitLab from being
+ started if the machine reboots isn't available (see [Omnibus GitLab issue #3058](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/3058)).
+ It may be safest to uninstall the GitLab package completely with `sudo yum remove gitlab-ee`.
+
+ NOTE: **Note:**
+ (**Ubuntu 14.04 LTS**) If you are using an older version of Ubuntu
+ or any other distribution based on the Upstart init system, you can prevent GitLab
+ from starting if the machine reboots as `root` with
+ `initctl stop gitlab-runsvvdir && echo 'manual' > /etc/init/gitlab-runsvdir.override && initctl reload-configuration`.
+
+ - If you do not have SSH access to the **primary** node, take the machine offline and
+ prevent it from rebooting. Since there are many ways you may prefer to accomplish
+ this, we will avoid a single recommendation. You may need to:
+
+ - Reconfigure the load balancers.
+ - Change DNS records (for example, point the **primary** DNS record to the
+ **secondary** node to stop using the **primary** node).
+ - Stop the virtual servers.
+ - Block traffic through a firewall.
+ - Revoke object storage permissions from the **primary** node.
+ - Physically disconnect a machine.
+
+### Promoting the **secondary** node
+
+NOTE: **Note:**
+A new **secondary** should not be added at this time. If you want to add a new
+**secondary**, do this after you have completed the entire process of promoting
+the **secondary** to the **primary**.
+
+CAUTION: **Caution:**
+If you encounter an `ActiveRecord::RecordInvalid: Validation failed: Name has already been taken` error during this process, read
+[the troubleshooting advice](../../replication/troubleshooting.md#fixing-errors-during-a-failover-or-when-promoting-a-secondary-to-a-primary-node).
+
+The `gitlab-ctl promote-to-primary-node` command cannot be used yet in
+conjunction with multiple servers, as it can only
+perform changes on a **secondary** with only a single machine. Instead, you must
+do this manually.
+
+DANGER: **Danger:**
+In GitLab 13.2 and later versions, promoting a secondary node to a primary while the secondary is paused fails. We are [investigating the issue](https://gitlab.com/gitlab-org/gitlab/-/issues/225173). Do not pause replication before promoting a secondary. If the node is paused, please resume before promoting.
+
+1. SSH in to the PostgreSQL node in the **secondary** and trigger PostgreSQL to
+ promote to read-write:
+
+ ```shell
+ sudo gitlab-pg-ctl promote
+ ```
+
+ In GitLab 12.8 and earlier, see [Message: `sudo: gitlab-pg-ctl: command not found`](../../replication/troubleshooting.md#message-sudo-gitlab-pg-ctl-command-not-found).
+
+1. Edit `/etc/gitlab/gitlab.rb` on every machine in the **secondary** to
+ reflect its new status as **primary** by removing any lines that enabled the
+ `geo_secondary_role`:
+
+ ```ruby
+ ## In pre-11.5 documentation, the role was enabled as follows. Remove this line.
+ geo_secondary_role['enable'] = true
+
+ ## In 11.5+ documentation, the role was enabled as follows. Remove this line.
+ roles ['geo_secondary_role']
+ ```
+
+ After making these changes [Reconfigure GitLab](../../../restart_gitlab.md#omnibus-gitlab-reconfigure) each
+ machine so the changes take effect.
+
+1. Promote the **secondary** to **primary**. SSH into a single Rails node
+ server and execute:
+
+ ```shell
+ sudo gitlab-rake geo:set_secondary_as_primary
+ ```
+
+1. Verify you can connect to the newly promoted **primary** using the URL used
+ previously for the **secondary**.
+
+1. Success! The **secondary** has now been promoted to **primary**.
+
+### Next steps
+
+To regain geographic redundancy as quickly as possible, you should
+[add a new **secondary** node](../../setup/index.md). To
+do that, you can re-add the old **primary** as a new secondary and bring it back
+online.
diff --git a/doc/administration/geo/disaster_recovery/runbooks/planned_failover_single_node.md b/doc/administration/geo/disaster_recovery/runbooks/planned_failover_single_node.md
new file mode 100644
index 00000000000..5e847030077
--- /dev/null
+++ b/doc/administration/geo/disaster_recovery/runbooks/planned_failover_single_node.md
@@ -0,0 +1,269 @@
+---
+stage: Enablement
+group: Geo
+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/#designated-technical-writers
+type: howto
+---
+
+CAUTION: **Caution:**
+This runbook is in **alpha**. For complete, production-ready documentation, see the
+[disaster recovery documentation](../index.md).
+
+# Disaster Recovery (Geo) promotion runbooks **(PREMIUM ONLY)**
+
+## Geo planned failover for a single-node configuration
+
+| Component | Configuration |
+|-------------|-----------------|
+| PostgreSQL | Omnibus-managed |
+| Geo site | Single-node |
+| Secondaries | One |
+
+This runbook will guide you through a planned failover of a single-node Geo site
+with one secondary. The following general architecture is assumed:
+
+```mermaid
+graph TD
+ subgraph main[Geo deployment]
+ subgraph Primary[Primary site]
+ Node_1[(GitLab node)]
+ end
+ subgraph Secondary1[Secondary site]
+ Node_2[(GitLab node)]
+ end
+ end
+```
+
+This guide will result in the following:
+
+1. An offline primary.
+1. A promoted secondary that is now the new primary.
+
+What is not covered:
+
+1. Re-adding the old **primary** as a secondary.
+1. Adding a new secondary.
+
+### Preparation
+
+NOTE: **Note:**
+Before following any of those steps, make sure you have `root` access to the
+**secondary** to promote it, since there isn't provided an automated way to
+promote a Geo replica and perform a failover.
+
+On the **secondary** node, navigate to the **Admin Area > Geo** dashboard to
+review its status. Replicated objects (shown in green) should be close to 100%,
+and there should be no failures (shown in red). If a large proportion of
+objects aren't yet replicated (shown in gray), consider giving the node more
+time to complete.
+
+![Replication status](../img/replication-status.png)
+
+If any objects are failing to replicate, this should be investigated before
+scheduling the maintenance window. After a planned failover, anything that
+failed to replicate will be **lost**.
+
+You can use the
+[Geo status API](../../../../api/geo_nodes.md#retrieve-project-sync-or-verification-failures-that-occurred-on-the-current-node)
+to review failed objects and the reasons for failure.
+A common cause of replication failures is the data being missing on the
+**primary** node - you can resolve these failures by restoring the data from backup,
+or removing references to the missing data.
+
+The maintenance window won't end until Geo replication and verification is
+completely finished. To keep the window as short as possible, you should
+ensure these processes are close to 100% as possible during active use.
+
+If the **secondary** node is still replicating data from the **primary** node,
+follow these steps to avoid unnecessary data loss:
+
+1. Until a [read-only mode](https://gitlab.com/gitlab-org/gitlab/-/issues/14609)
+ is implemented, updates must be prevented from happening manually to the
+ **primary**. Note that your **secondary** node still needs read-only
+ access to the **primary** node during the maintenance window:
+
+ 1. At the scheduled time, using your cloud provider or your node's firewall, block
+ all HTTP, HTTPS and SSH traffic to/from the **primary** node, **except** for your IP and
+ the **secondary** node's IP.
+
+ For instance, you can run the following commands on the **primary** node:
+
+ ```shell
+ sudo iptables -A INPUT -p tcp -s <secondary_node_ip> --destination-port 22 -j ACCEPT
+ sudo iptables -A INPUT -p tcp -s <your_ip> --destination-port 22 -j ACCEPT
+ sudo iptables -A INPUT --destination-port 22 -j REJECT
+
+ sudo iptables -A INPUT -p tcp -s <secondary_node_ip> --destination-port 80 -j ACCEPT
+ sudo iptables -A INPUT -p tcp -s <your_ip> --destination-port 80 -j ACCEPT
+ sudo iptables -A INPUT --tcp-dport 80 -j REJECT
+
+ sudo iptables -A INPUT -p tcp -s <secondary_node_ip> --destination-port 443 -j ACCEPT
+ sudo iptables -A INPUT -p tcp -s <your_ip> --destination-port 443 -j ACCEPT
+ sudo iptables -A INPUT --tcp-dport 443 -j REJECT
+ ```
+
+ From this point, users will be unable to view their data or make changes on the
+ **primary** node. They will also be unable to log in to the **secondary** node.
+ However, existing sessions will work for the remainder of the maintenance period, and
+ public data will be accessible throughout.
+
+ 1. Verify the **primary** node is blocked to HTTP traffic by visiting it in browser via
+ another IP. The server should refuse connection.
+
+ 1. Verify the **primary** node is blocked to Git over SSH traffic by attempting to pull an
+ existing Git repository with an SSH remote URL. The server should refuse
+ connection.
+
+ 1. On the **primary** node, disable non-Geo periodic background jobs by navigating
+ to **Admin Area > Monitoring > Background Jobs > Cron**, clicking `Disable All`,
+ and then clicking `Enable` for the `geo_sidekiq_cron_config_worker` cron job.
+ This job will re-enable several other cron jobs that are essential for planned
+ failover to complete successfully.
+
+1. Finish replicating and verifying all data:
+
+ CAUTION: **Caution:**
+ Not all data is automatically replicated. Read more about
+ [what is excluded](../planned_failover.md#not-all-data-is-automatically-replicated).
+
+ 1. If you are manually replicating any
+ [data not managed by Geo](../../replication/datatypes.md#limitations-on-replicationverification),
+ trigger the final replication process now.
+ 1. On the **primary** node, navigate to **Admin Area > Monitoring > Background Jobs > Queues**
+ and wait for all queues except those with `geo` in the name to drop to 0.
+ These queues contain work that has been submitted by your users; failing over
+ before it is completed will cause the work to be lost.
+ 1. On the **primary** node, navigate to **Admin Area > Geo** and wait for the
+ following conditions to be true of the **secondary** node you are failing over to:
+ - All replication meters to each 100% replicated, 0% failures.
+ - All verification meters reach 100% verified, 0% failures.
+ - Database replication lag is 0ms.
+ - The Geo log cursor is up to date (0 events behind).
+
+ 1. On the **secondary** node, navigate to **Admin Area > Monitoring > Background Jobs > Queues**
+ and wait for all the `geo` queues to drop to 0 queued and 0 running jobs.
+ 1. On the **secondary** node, use [these instructions](../../../raketasks/check.md)
+ to verify the integrity of CI artifacts, LFS objects, and uploads in file
+ storage.
+
+ At this point, your **secondary** node will contain an up-to-date copy of everything the
+ **primary** node has, meaning nothing will be lost when you fail over.
+
+1. In this final step, you need to permanently disable the **primary** node.
+
+ CAUTION: **Caution:**
+ When the **primary** node goes offline, there may be data saved on the **primary** node
+ that has not been replicated to the **secondary** node. This data should be treated
+ as lost if you proceed.
+
+ TIP: **Tip:**
+ If you plan to [update the **primary** domain DNS record](../index.md#step-4-optional-updating-the-primary-domain-dns-record),
+ you may wish to lower the TTL now to speed up propagation.
+
+ When performing a failover, we want to avoid a split-brain situation where
+ writes can occur in two different GitLab instances. So to prepare for the
+ failover, you must disable the **primary** node:
+
+ - If you have SSH access to the **primary** node, stop and disable GitLab:
+
+ ```shell
+ sudo gitlab-ctl stop
+ ```
+
+ Prevent GitLab from starting up again if the server unexpectedly reboots:
+
+ ```shell
+ sudo systemctl disable gitlab-runsvdir
+ ```
+
+ NOTE: **Note:**
+ (**CentOS only**) In CentOS 6 or older, there is no easy way to prevent GitLab from being
+ started if the machine reboots isn't available (see [Omnibus GitLab issue #3058](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/3058)).
+ It may be safest to uninstall the GitLab package completely with `sudo yum remove gitlab-ee`.
+
+ NOTE: **Note:**
+ (**Ubuntu 14.04 LTS**) If you are using an older version of Ubuntu
+ or any other distribution based on the Upstart init system, you can prevent GitLab
+ from starting if the machine reboots as `root` with
+ `initctl stop gitlab-runsvvdir && echo 'manual' > /etc/init/gitlab-runsvdir.override && initctl reload-configuration`.
+
+ - If you do not have SSH access to the **primary** node, take the machine offline and
+ prevent it from rebooting. Since there are many ways you may prefer to accomplish
+ this, we will avoid a single recommendation. You may need to:
+
+ - Reconfigure the load balancers.
+ - Change DNS records (for example, point the **primary** DNS record to the
+ **secondary** node to stop using the **primary** node).
+ - Stop the virtual servers.
+ - Block traffic through a firewall.
+ - Revoke object storage permissions from the **primary** node.
+ - Physically disconnect a machine.
+
+### Promoting the **secondary** node
+
+Note the following when promoting a secondary:
+
+- A new **secondary** should not be added at this time. If you want to add a new
+ **secondary**, do this after you have completed the entire process of promoting
+ the **secondary** to the **primary**.
+- If you encounter an `ActiveRecord::RecordInvalid: Validation failed: Name has already been taken`
+ error during this process, read
+ [the troubleshooting advice](../../replication/troubleshooting.md#fixing-errors-during-a-failover-or-when-promoting-a-secondary-to-a-primary-node).
+
+To promote the secondary node:
+
+1. SSH in to your **secondary** node and login as root:
+
+ ```shell
+ sudo -i
+ ```
+
+1. Edit `/etc/gitlab/gitlab.rb` to reflect its new status as **primary** by
+ removing any lines that enabled the `geo_secondary_role`:
+
+ ```ruby
+ ## In pre-11.5 documentation, the role was enabled as follows. Remove this line.
+ geo_secondary_role['enable'] = true
+
+ ## In 11.5+ documentation, the role was enabled as follows. Remove this line.
+ roles ['geo_secondary_role']
+ ```
+
+1. Run the following command to list out all preflight checks and automatically
+ check if replication and verification are complete before scheduling a planned
+ failover to ensure the process will go smoothly:
+
+ ```shell
+ gitlab-ctl promotion-preflight-checks
+ ```
+
+1. Promote the **secondary**:
+
+ ```shell
+ gitlab-ctl promote-to-primary-node
+ ```
+
+ If you have already run the [preflight checks](../planned_failover.md#preflight-checks)
+ or don't want to run them, you can skip them:
+
+ ```shell
+ gitlab-ctl promote-to-primary-node --skip-preflight-check
+ ```
+
+ You can also promote the secondary node to primary **without any further confirmation**, even when preflight checks fail:
+
+ ```shell
+ sudo gitlab-ctl promote-to-primary-node --force
+ ```
+
+1. Verify you can connect to the newly promoted **primary** node using the URL used
+ previously for the **secondary** node.
+
+ If successful, the **secondary** node has now been promoted to the **primary** node.
+
+### Next steps
+
+To regain geographic redundancy as quickly as possible, you should
+[add a new **secondary** node](../../setup/index.md). To
+do that, you can re-add the old **primary** as a new secondary and bring it back
+online.
diff --git a/doc/administration/geo/index.md b/doc/administration/geo/index.md
index 6fdf213ac78..8767940816b 100644
--- a/doc/administration/geo/index.md
+++ b/doc/administration/geo/index.md
@@ -39,7 +39,7 @@ Implementing Geo provides the following benefits:
In addition, it:
-- Can be used for cloning and fetching projects, in addition to reading any data available in the GitLab web interface (see [current limitations](#current-limitations)).
+- Can be used for cloning and fetching projects, in addition to reading any data available in the GitLab web interface (see [limitations](#limitations)).
- Overcomes slow connections between distant offices, saving time by improving speed for distributed teams.
- Helps reducing the loading time for automated tasks, custom integrations, and internal workflows.
- Can quickly fail over to a **secondary** node in a [disaster recovery](disaster_recovery/index.md) scenario.
@@ -67,9 +67,9 @@ Keep in mind that:
- **Secondary** nodes talk to the **primary** node to:
- Get user data for logins (API).
- Replicate repositories, LFS Objects, and Attachments (HTTPS + JWT).
-- Since GitLab Premium 10.0, the **primary** node no longer talks to **secondary** nodes to notify for changes (API).
+- In GitLab Premium 10.0 and later, the **primary** node no longer talks to **secondary** nodes to notify for changes (API).
- Pushing directly to a **secondary** node (for both HTTP and SSH, including Git LFS) was [introduced](https://about.gitlab.com/releases/2018/09/22/gitlab-11-3-released/) in [GitLab Premium](https://about.gitlab.com/pricing/#self-managed) 11.3.
-- There are [limitations](#current-limitations) in the current implementation.
+- There are [limitations](#limitations) when using Geo.
### Architecture
@@ -195,6 +195,9 @@ For information on how to update your Geo nodes to the latest GitLab version, se
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/35913) in [GitLab Premium](https://about.gitlab.com/pricing/) 13.2.
+DANGER: **Danger:**
+In GitLab 13.2 and later versions, promoting a secondary node to a primary while the secondary is paused fails. We are [investigating the issue](https://gitlab.com/gitlab-org/gitlab/-/issues/225173). Do not pause replication before promoting a secondary. If the node is paused, please resume before promoting.
+
In some circumstances, like during [upgrades](replication/updating_the_geo_nodes.md) or a [planned failover](disaster_recovery/planned_failover.md), it is desirable to pause replication between the primary and secondary.
Pausing and resuming replication is done via a command line tool from the secondary node.
@@ -247,7 +250,7 @@ For more information on removing a Geo node, see [Removing **secondary** Geo nod
To find out how to disable Geo, see [Disabling Geo](replication/disable_geo.md).
-## Current limitations
+## Limitations
CAUTION: **Caution:**
This list of limitations only reflects the latest version of GitLab. If you are using an older version, extra limitations may be in place.
@@ -261,6 +264,7 @@ This list of limitations only reflects the latest version of GitLab. If you are
- Object pools for forked project deduplication work only on the **primary** node, and are duplicated on the **secondary** node.
- [External merge request diffs](../merge_request_diffs.md) will not be replicated if they are on-disk, and viewing merge requests will fail. However, external MR diffs in object storage **are** supported. The default configuration (in-database) does work.
- GitLab Runners cannot register with a **secondary** node. Support for this is [planned for the future](https://gitlab.com/gitlab-org/gitlab/-/issues/3294).
+- Geo **secondary** nodes can not be configured to [use high-availability configurations of PostgreSQL](https://gitlab.com/groups/gitlab-org/-/epics/2536).
### Limitations on replication/verification
@@ -278,7 +282,7 @@ For answers to common questions, see the [Geo FAQ](replication/faq.md).
## Log files
-Since GitLab 9.5, Geo stores structured log messages in a `geo.log` file. For Omnibus installations, this file is at `/var/log/gitlab/gitlab-rails/geo.log`.
+In GitLab 9.5 and later, Geo stores structured log messages in a `geo.log` file. For Omnibus installations, this file is at `/var/log/gitlab/gitlab-rails/geo.log`.
This file contains information about when Geo attempts to sync repositories and files. Each line in the file contains a separate JSON entry that can be ingested into. For example, Elasticsearch or Splunk.
diff --git a/doc/administration/geo/replication/datatypes.md b/doc/administration/geo/replication/datatypes.md
index 166a724f9c1..d1fa2d503be 100644
--- a/doc/administration/geo/replication/datatypes.md
+++ b/doc/administration/geo/replication/datatypes.md
@@ -23,30 +23,34 @@ We currently distinguish between three different data types:
See the list below of each feature or component we replicate, its corresponding data type, replication, and
verification methods:
-| Type | Feature / component | Replication method | Verification method |
-|:---------|:----------------------------------------------|:--------------------------------------|:-----------------------|
-| Database | Application data in PostgreSQL | Native | Native |
-| Database | Redis | _N/A_ (*1*) | _N/A_ |
-| Database | Elasticsearch | Native | Native |
-| Database | Personal snippets | PostgreSQL Replication | PostgreSQL Replication |
-| Database | Project snippets | PostgreSQL Replication | PostgreSQL Replication |
-| Database | SSH public keys | PostgreSQL Replication | PostgreSQL Replication |
-| Git | Project repository | Geo with Gitaly | Gitaly Checksum |
-| Git | Project wiki repository | Geo with Gitaly | Gitaly Checksum |
-| Git | Project designs repository | Geo with Gitaly | Gitaly Checksum |
-| Git | Object pools for forked project deduplication | Geo with Gitaly | _Not implemented_ |
-| Blobs | User uploads _(filesystem)_ | Geo with API | _Not implemented_ |
-| Blobs | User uploads _(object storage)_ | Geo with API/Managed (*2*) | _Not implemented_ |
-| Blobs | LFS objects _(filesystem)_ | Geo with API | _Not implemented_ |
-| Blobs | LFS objects _(object storage)_ | Geo with API/Managed (*2*) | _Not implemented_ |
-| Blobs | CI job artifacts _(filesystem)_ | Geo with API | _Not implemented_ |
-| Blobs | CI job artifacts _(object storage)_ | Geo with API/Managed (*2*) | _Not implemented_ |
-| Blobs | Archived CI build traces _(filesystem)_ | Geo with API | _Not implemented_ |
-| Blobs | Archived CI build traces _(object storage)_ | Geo with API/Managed (*2*) | _Not implemented_ |
-| Blobs | Container registry _(filesystem)_ | Geo with API/Docker API | _Not implemented_ |
-| Blobs | Container registry _(object storage)_ | Geo with API/Managed/Docker API (*2*) | _Not implemented_ |
-| Blobs | Package registry _(filesystem)_ | Geo with API | _Not implemented_ |
-| Blobs | Package registry _(object storage)_ | Geo with API/Managed (*2*) | _Not implemented_ |
+| Type | Feature / component | Replication method | Verification method |
+|:---------|:------------------------------------------------|:--------------------------------------|:-----------------------|
+| Database | Application data in PostgreSQL | Native | Native |
+| Database | Redis | _N/A_ (*1*) | _N/A_ |
+| Database | Elasticsearch | Native | Native |
+| Database | Personal snippets | PostgreSQL Replication | PostgreSQL Replication |
+| Database | Project snippets | PostgreSQL Replication | PostgreSQL Replication |
+| Database | SSH public keys | PostgreSQL Replication | PostgreSQL Replication |
+| Git | Project repository | Geo with Gitaly | Gitaly Checksum |
+| Git | Project wiki repository | Geo with Gitaly | Gitaly Checksum |
+| Git | Project designs repository | Geo with Gitaly | Gitaly Checksum |
+| Git | Object pools for forked project deduplication | Geo with Gitaly | _Not implemented_ |
+| Blobs | User uploads _(filesystem)_ | Geo with API | _Not implemented_ |
+| Blobs | User uploads _(object storage)_ | Geo with API/Managed (*2*) | _Not implemented_ |
+| Blobs | LFS objects _(filesystem)_ | Geo with API | _Not implemented_ |
+| Blobs | LFS objects _(object storage)_ | Geo with API/Managed (*2*) | _Not implemented_ |
+| Blobs | CI job artifacts _(filesystem)_ | Geo with API | _Not implemented_ |
+| Blobs | CI job artifacts _(object storage)_ | Geo with API/Managed (*2*) | _Not implemented_ |
+| Blobs | Archived CI build traces _(filesystem)_ | Geo with API | _Not implemented_ |
+| Blobs | Archived CI build traces _(object storage)_ | Geo with API/Managed (*2*) | _Not implemented_ |
+| Blobs | Container registry _(filesystem)_ | Geo with API/Docker API | _Not implemented_ |
+| Blobs | Container registry _(object storage)_ | Geo with API/Managed/Docker API (*2*) | _Not implemented_ |
+| Blobs | Package registry _(filesystem)_ | Geo with API | _Not implemented_ |
+| Blobs | Package registry _(object storage)_ | Geo with API/Managed (*2*) | _Not implemented_ |
+| Blobs | Versioned Terraform State _(filesystem)_ | Geo with API | _Not implemented_ |
+| Blobs | Versioned Terraform State _(object storage)_ | Geo with API/Managed (*2*) | _Not implemented_ |
+| Blobs | External Merge Request Diffs _(filesystem)_ | Geo with API | _Not implemented_ |
+| Blobs | External Merge Request Diffs _(object storage)_ | Geo with API/Managed (*2*) | _Not implemented_ |
- (*1*): Redis replication can be used as part of HA with Redis sentinel. It's not used between Geo nodes.
- (*2*): Object storage replication can be performed by Geo or by your object storage provider/appliance
@@ -160,39 +164,34 @@ replicating data from those features will cause the data to be **lost**.
If you wish to use those features on a **secondary** node, or to execute a failover
successfully, you must replicate their data using some other means.
-| Feature | Replicated (added in GitLab version) | Verified (added in GitLab version) | Notes |
-|:------------------------------------------------------------------------------------------------------|:-------------------------------------------------------------|:----------------------------------------------------------|:-----------------------------------------------------------------------------------------------------------|
-| Application data in PostgreSQL | **Yes** (10.2) | **Yes** (10.2) | |
-| Project repository | **Yes** (10.2) | **Yes** (10.7) | |
-| Project wiki repository | **Yes** (10.2) | **Yes** (10.7) | |
-| Project designs repository | **Yes** (12.7) | [No](https://gitlab.com/gitlab-org/gitlab/-/issues/32467) | |
-| Uploads | **Yes** (10.2) | [No](https://gitlab.com/groups/gitlab-org/-/epics/1817) | Verified only on transfer, or manually (*1*) |
-| LFS objects | **Yes** (10.2) | [No](https://gitlab.com/gitlab-org/gitlab/-/issues/8922) | Verified only on transfer, or manually (*1*). Unavailable for new LFS objects in 11.11.x and 12.0.x (*2*). |
-| CI job artifacts (other than traces) | **Yes** (10.4) | [No](https://gitlab.com/gitlab-org/gitlab/-/issues/8923) | Verified only manually (*1*) |
-| Archived traces | **Yes** (10.4) | [No](https://gitlab.com/gitlab-org/gitlab/-/issues/8923) | Verified only on transfer, or manually (*1*) |
-| Personal snippets | **Yes** (10.2) | **Yes** (10.2) | |
-| [Versioned snippets](../../../user/snippets.md#versioned-snippets) | [No](https://gitlab.com/groups/gitlab-org/-/epics/2809) | [No](https://gitlab.com/groups/gitlab-org/-/epics/2810) | |
-| Project snippets | **Yes** (10.2) | **Yes** (10.2) | |
-| Object pools for forked project deduplication | **Yes** | No | |
-| [Server-side Git hooks](../../server_hooks.md) | No | No | |
-| [Elasticsearch integration](../../../integration/elasticsearch.md) | [No](https://gitlab.com/gitlab-org/gitlab/-/issues/1186) | No | |
-| [GitLab Pages](../../pages/index.md) | [No](https://gitlab.com/groups/gitlab-org/-/epics/589) | No | |
-| [Container Registry](../../packages/container_registry.md) | **Yes** (12.3) | No | |
-| [NPM Registry](../../../user/packages/npm_registry/index.md) | **Yes** (13.2) | No | Behind feature flag `geo_package_file_replication`, enabled by default |
-| [Maven Repository](../../../user/packages/maven_repository/index.md) | **Yes** (13.2) | No | Behind feature flag `geo_package_file_replication`, enabled by default |
-| [Conan Repository](../../../user/packages/conan_repository/index.md) | **Yes** (13.2) | No | Behind feature flag `geo_package_file_replication`, enabled by default |
-| [NuGet Repository](../../../user/packages/nuget_repository/index.md) | **Yes** (13.2) | No | Behind feature flag `geo_package_file_replication`, enabled by default |
-| [PyPi Repository](../../../user/packages/pypi_repository/index.md) | **Yes** (13.2) | No | Behind feature flag `geo_package_file_replication`, enabled by default |
-| [Composer Repository](../../../user/packages/composer_repository/index.md) | **Yes** (13.2) | No | Behind feature flag `geo_package_file_replication`, enabled by default |
-| [External merge request diffs](../../merge_request_diffs.md) | [No](https://gitlab.com/gitlab-org/gitlab/-/issues/33817) | No | |
-| [Terraform State](../../terraform_state.md) | [No](https://gitlab.com/groups/gitlab-org/-/epics/3112)(*3*) | No | |
-| [Vulnerability Export](../../../user/application_security/security_dashboard/#export-vulnerabilities) | [No](https://gitlab.com/groups/gitlab-org/-/epics/3111)(*3*) | No | |
-| Content in object storage | **Yes** (12.4) | No | |
-
-- (*1*): The integrity can be verified manually using
- [Integrity Check Rake Task](../../raketasks/check.md) on both nodes and comparing
- the output between them.
-- (*2*): GitLab versions 11.11.x and 12.0.x are affected by [a bug that prevents any new
- LFS objects from replicating](https://gitlab.com/gitlab-org/gitlab/-/issues/32696).
-- (*3*): If you are using Object Storage, the replication can be performed by the
- Object Storage provider if supported. Please see [Geo with Object Storage](object_storage.md)
+| Feature | Replicated (added in GitLab version) | Verified (added in GitLab version) | Object Storage replication (please see [Geo with Object Storage](object_storage.md)) | Notes |
+|:---------------------------------------------------------------------------------------------------------------|:-----------------------------------------------------------------------------------|:----------------------------------------------------------|:-------------------------------------------------------------------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| [Application data in PostgreSQL](../../postgresql/index.md) | **Yes** (10.2) | **Yes** (10.2) | No | |
+| [Project repository](../../..//user/project/repository/) | **Yes** (10.2) | **Yes** (10.7) | No | |
+| [Project wiki repository](../../../user/project/wiki/) | **Yes** (10.2) | **Yes** (10.7) | No | |
+| [Uploads](../../uploads.md) | **Yes** (10.2) | [No](https://gitlab.com/groups/gitlab-org/-/epics/1817) | No | Verified only on transfer or manually using [Integrity Check Rake Task](../../raketasks/check.md) on both nodes and comparing the output between them. |
+| [LFS objects](../../lfs/index.md) | **Yes** (10.2) | [No](https://gitlab.com/gitlab-org/gitlab/-/issues/8922) | Via Object Storage provider if supported. Native Geo support (Beta). | Verified only on transfer or manually using [Integrity Check Rake Task](../../raketasks/check.md) on both nodes and comparing the output between them. GitLab versions 11.11.x and 12.0.x are affected by [a bug that prevents any new LFS objects from replicating](https://gitlab.com/gitlab-org/gitlab/-/issues/32696). |
+| [Personal snippets](../../../user/snippets.md#personal-snippets) | **Yes** (10.2) | **Yes** (10.2) | No | |
+| [Project snippets](../../../user/snippets.md#project-snippets) | **Yes** (10.2) | **Yes** (10.2) | No | |
+| [CI job artifacts (other than Job Logs)](../../../ci/pipelines/job_artifacts.md) | **Yes** (10.4) | [No](https://gitlab.com/gitlab-org/gitlab/-/issues/8923) | Via Object Storage provider if supported. Native Geo support (Beta) . | Verified only manually using [Integrity Check Rake Task](../../raketasks/check.md) on both nodes and comparing the output between them |
+| [Job logs](../../job_logs.md) | **Yes** (10.4) | [No](https://gitlab.com/gitlab-org/gitlab/-/issues/8923) | Via Object Storage provider if supported. Native Geo support (Beta). | Verified only on transfer or manually using [Integrity Check Rake Task](../../raketasks/check.md) on both nodes and comparing the output between them |
+| [Object pools for forked project deduplication](../../../development/git_object_deduplication.md) | **Yes** | No | No | |
+| [Container Registry](../../packages/container_registry.md) | **Yes** (12.3) | No | No | Disabled by default. See [instructions](./docker_registry.md) to enable. |
+| [Content in object storage (beta)](object_storage.md) | **Yes** (12.4) | [No](https://gitlab.com/gitlab-org/gitlab/-/issues/13845) | No | |
+| [Project designs repository](../../../user/project/issues/design_management.md) | **Yes** (12.7) | [No](https://gitlab.com/gitlab-org/gitlab/-/issues/32467) | Via Object Storage provider if supported. Native Geo support (Beta). | |
+| [NPM Registry](../../../user/packages/npm_registry/index.md) | **Yes** (13.2) | [No](https://gitlab.com/groups/gitlab-org/-/epics/1817) | Via Object Storage provider if supported. Native Geo support (Beta). | Behind feature flag `geo_package_file_replication`, enabled by default |
+| [Maven Repository](../../../user/packages/maven_repository/index.md) | **Yes** (13.2) | [No](https://gitlab.com/groups/gitlab-org/-/epics/1817) | Via Object Storage provider if supported. Native Geo support (Beta). | Behind feature flag `geo_package_file_replication`, enabled by default |
+| [Conan Repository](../../../user/packages/conan_repository/index.md) | **Yes** (13.2) | [No](https://gitlab.com/groups/gitlab-org/-/epics/1817) | Via Object Storage provider if supported. Native Geo support (Beta). | Behind feature flag `geo_package_file_replication`, enabled by default |
+| [NuGet Repository](../../../user/packages/nuget_repository/index.md) | **Yes** (13.2) | [No](https://gitlab.com/groups/gitlab-org/-/epics/1817) | Via Object Storage provider if supported. Native Geo support (Beta). | Behind feature flag `geo_package_file_replication`, enabled by default |
+| [PyPI Repository](../../../user/packages/pypi_repository/index.md) | **Yes** (13.2) | [No](https://gitlab.com/groups/gitlab-org/-/epics/1817) | Via Object Storage provider if supported. Native Geo support (Beta). | Behind feature flag `geo_package_file_replication`, enabled by default |
+| [Composer Repository](../../../user/packages/composer_repository/index.md) | **Yes** (13.2) | [No](https://gitlab.com/groups/gitlab-org/-/epics/1817) | Via Object Storage provider if supported. Native Geo support (Beta). | Behind feature flag `geo_package_file_replication`, enabled by default |
+| [Generic packages](../../../user/packages/generic_packages/index.md) | **Yes** (13.5) | [No](https://gitlab.com/groups/gitlab-org/-/epics/1817) | Via Object Storage provider if supported. Native Geo support (Beta). | Behind feature flag `geo_package_file_replication`, enabled by default |
+| [Versioned Terraform State](../../terraform_state.md) | **Yes** (13.5) | No | Via Object Storage provider if supported. Native Geo support (Beta). | Behind feature flag `geo_terraform_state_version_replication`, enabled by default |
+| [External merge request diffs](../../merge_request_diffs.md) | **Yes** (13.5) | No | Behind feature flag `geo_merge_request_diff_replication`, enabled by default | |
+| [Versioned snippets](../../../user/snippets.md#versioned-snippets) | [No](https://gitlab.com/groups/gitlab-org/-/epics/2809) | [No](https://gitlab.com/groups/gitlab-org/-/epics/2810) | No | |
+| [Server-side Git hooks](../../server_hooks.md) | [No](https://gitlab.com/groups/gitlab-org/-/epics/1867) | No | No | |
+| [Elasticsearch integration](../../../integration/elasticsearch.md) | [No](https://gitlab.com/gitlab-org/gitlab/-/issues/1186) | No | No | |
+| [GitLab Pages](../../pages/index.md) | [No](https://gitlab.com/groups/gitlab-org/-/epics/589) | No | No | |
+| [CI Pipeline Artifacts](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/models/ci/pipeline_artifact.rb) | [No](https://gitlab.com/gitlab-org/gitlab/-/issues/238464) | No | Via Object Storage provider if supported. Native Geo support (Beta). | Persists additional artifacts after a pipeline completes |
+| [Dependency proxy images](../../../user/packages/dependency_proxy/index.md) | [No](https://gitlab.com/gitlab-org/gitlab/-/issues/259694) | No | No | Blocked on [Geo: Secondary Mimicry](https://gitlab.com/groups/gitlab-org/-/epics/1528). Note that replication of this cache is not needed for Disaster Recovery purposes because it can be recreated from external sources. |
+| [Vulnerability Export](../../../user/application_security/security_dashboard/#export-vulnerabilities) | [Not planned](https://gitlab.com/groups/gitlab-org/-/epics/3111) | No | Via Object Storage provider if supported. Native Geo support (Beta). | Not planned because they are ephemeral and sensitive. They can be regenerated on demand. |
diff --git a/doc/administration/geo/replication/disable_geo.md b/doc/administration/geo/replication/disable_geo.md
index aed8e5fc3bc..14a11d9c1e3 100644
--- a/doc/administration/geo/replication/disable_geo.md
+++ b/doc/administration/geo/replication/disable_geo.md
@@ -29,7 +29,7 @@ anymore on these nodes. You can follow our docs to [remove your secondary Geo no
If the current node that you want to keep using is a secondary node, you need to first promote it to primary.
You can use our steps on [how to promote a secondary node](../disaster_recovery/#step-3-promoting-a-secondary-node)
-in order to do that.
+to do that.
## Remove the primary node from the UI
diff --git a/doc/administration/geo/replication/faq.md b/doc/administration/geo/replication/faq.md
index 3892d73b465..f7f391b360e 100644
--- a/doc/administration/geo/replication/faq.md
+++ b/doc/administration/geo/replication/faq.md
@@ -67,3 +67,7 @@ That's totally fine. We use HTTP(s) to fetch repository changes from the **prima
## Is this possible to set up a Docker Registry for a **secondary** node that mirrors the one on the **primary** node?
Yes. See [Docker Registry for a **secondary** node](docker_registry.md).
+
+## Can I login to a secondary node?
+
+Yes, but secondary nodes receive all authentication data (like user accounts and logins) from the primary instance. This means you will be re-directed to the primary for authentication and routed back afterwards.
diff --git a/doc/administration/geo/replication/geo_validation_tests.md b/doc/administration/geo/replication/geo_validation_tests.md
index 8247b8c6336..c28688930b5 100644
--- a/doc/administration/geo/replication/geo_validation_tests.md
+++ b/doc/administration/geo/replication/geo_validation_tests.md
@@ -114,6 +114,22 @@ The following are GitLab upgrade validation tests we performed.
The following are PostgreSQL upgrade validation tests we performed.
+### September 2020
+
+[Verify PostgreSQL 12 upgrade for Geo installations](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/5454):
+
+- Description: With PostgreSQL 12 available as an opt-in version in GitLab 13.3, we tested upgrading
+ existing Geo installations from PostgreSQL 11 to 12. We also re-tested fresh installations of GitLab
+ with Geo after fixes were made to support PostgreSQL 12. These tests were done using a
+ [nightly build](https://packages.gitlab.com/gitlab/nightly-builds/packages/ubuntu/bionic/gitlab-ee_13.3.6+rnightly.169516.d5209202-0_amd64.deb)
+ of GitLab 13.4.
+- Outcome: Tests were successful for Geo deployments with a single database node on the primary and secondary.
+ We encountered known issues with repmgr and Patroni managed PostgreSQL clusters on the Geo primary. Using
+ PostgreSQL 12 with a database cluster on the primary is not recommended until the issues are resolved.
+- Known issues for PostgreSQL clusters:
+ - [Ensure Patroni detects PostgreSQL update](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/5423)
+ - [Allow configuring permanent replication slots in patroni](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/5628)
+
### August 2020
[Verify Geo installation with PostgreSQL 12](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/5453):
@@ -168,5 +184,4 @@ The following are additional validation tests we performed.
[Test Gitaly Cluster on a Geo Deployment](https://gitlab.com/gitlab-org/gitlab/-/issues/223210):
- Description: Tested a Geo deployment with Gitaly clusters configured on both the primary and secondary Geo sites. Triggered automatic Gitaly cluster failover on the primary Geo site, and ran end-to-end Geo tests. Then triggered Gitaly cluster failover on the secondary Geo site, and re-ran the end-to-end Geo tests.
-
- Outcome: Successful end-to-end tests before and after Gitaly cluster failover on the primary site, and before and after Gitaly cluster failover on the secondary site.
diff --git a/doc/administration/high_availability/img/geo-ha-diagram.png b/doc/administration/geo/replication/img/geo-ha-diagram.png
index da5d612827c..da5d612827c 100644
--- a/doc/administration/high_availability/img/geo-ha-diagram.png
+++ b/doc/administration/geo/replication/img/geo-ha-diagram.png
Binary files differ
diff --git a/doc/administration/geo/replication/multiple_servers.md b/doc/administration/geo/replication/multiple_servers.md
index cba41c375a3..7d65d2165c5 100644
--- a/doc/administration/geo/replication/multiple_servers.md
+++ b/doc/administration/geo/replication/multiple_servers.md
@@ -13,7 +13,7 @@ described, it is possible to adapt these instructions to your needs.
## Architecture overview
-![Geo multi-node diagram](../../high_availability/img/geo-ha-diagram.png)
+![Geo multi-node diagram](img/geo-ha-diagram.png)
_[diagram source - GitLab employees only](https://docs.google.com/drawings/d/1z0VlizKiLNXVVVaERFwgsIOuEgjcUqDTWPdQYsE7Z4c/edit)_
@@ -133,7 +133,7 @@ Configure the following services, again using the non-Geo multi-node
documentation:
- [Configuring Redis for GitLab](../../redis/replication_and_failover.md#example-configuration-for-the-gitlab-application) for multiple nodes.
-- [Gitaly](../../high_availability/gitaly.md), which will store data that is
+- [Gitaly](../../gitaly/index.md), which will store data that is
synchronized from the **primary** node.
NOTE: **Note:**
@@ -422,7 +422,6 @@ application servers above, with some changes to run only the `sidekiq` service:
##
alertmanager['enable'] = false
consul['enable'] = false
- geo_logcursor['enable'] = false
gitaly['enable'] = false
gitlab_exporter['enable'] = false
gitlab_workhorse['enable'] = false
diff --git a/doc/administration/geo/replication/troubleshooting.md b/doc/administration/geo/replication/troubleshooting.md
index f6d6f39fb19..b62c5c6f460 100644
--- a/doc/administration/geo/replication/troubleshooting.md
+++ b/doc/administration/geo/replication/troubleshooting.md
@@ -386,6 +386,15 @@ This happens when you have added IP addresses without a subnet mask in `postgres
To fix this, add the subnet mask in `/etc/gitlab/gitlab.rb` under `postgresql['md5_auth_cidr_addresses']`
to respect the CIDR format (i.e. `1.2.3.4/32`).
+### Message: `Found data in the gitlabhq_production database!` when running `gitlab-ctl replicate-geo-database`
+
+This happens if data is detected in the `projects` table. When one or more projects are detected, the operation
+is aborted to prevent accidental data loss. To bypass this message, pass the `--force` option to the command.
+
+In GitLab 13.4, a seed project is added when GitLab is first installed. This makes it necessary to pass `--force` even
+on a new Geo secondary node. There is an [issue to account for seed projects](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/5618)
+when checking the database.
+
### Very large repositories never successfully synchronize on the **secondary** node
GitLab places a timeout on all repository clones, including project imports
@@ -483,8 +492,8 @@ to start again from scratch, there are a few steps that can help you:
gitlab-ctl start geo-postgresql
```
- Reconfigure in order to recreate the folders and make sure permissions and ownership
- are correctly
+ Reconfigure to recreate the folders and make sure permissions and ownership
+ are correct:
```shell
gitlab-ctl reconfigure
@@ -605,46 +614,18 @@ or `gitlab-ctl promote-to-primary-node`, either:
### Message: ActiveRecord::RecordInvalid: Validation failed: Enabled Geo primary node cannot be disabled
-This error may occur if you have paused replication from the original primary node before attempting to promote this node.
-To double check this, you can do the following:
-
-- Get the current secondary node's ID using:
-
- ```shell
- sudo gitlab-rails runner 'puts GeoNode.current_node.id'
- ```
-
-- Double check that the node is active through the database by running the following
- on the secondary node, replacing `ID_FROM_ABOVE`:
-
- ```shell
- sudo gitlab-rails dbconsole
-
- SELECT enabled FROM geo_nodes WHERE id = ID_FROM_ABOVE;
- ```
-
-- If the above returned `f` it means that the replication was paused.
- You can re-enable it through an `UPDATE` statement in the database:
-
- ```shell
- sudo gitlab-rails dbconsole
-
- UPDATE geo_nodes SET enabled = 't' WHERE id = ID_FROM_ABOVE;
- ```
-
-### While Promoting the secondary, I got an error `ActiveRecord::RecordInvalid`
-
If you disabled a secondary node, either with the [replication pause task](../index.md#pausing-and-resuming-replication)
-(13.2) or via the UI (13.1 and earlier), you must first re-enable the
-node before you can continue. This is fixed in 13.4.
+(13.2) or by using the user interface (13.1 and earlier), you must first
+re-enable the node before you can continue. This is fixed in 13.4.
-From `gitlab-psql`, execute the following, replacing `<your secondary url>`
-with the URL for your secondary server starting with `http` or `https` and ending with a `/`.
+Run the following command, replacing `https://<secondary url>/` with the URL
+for your secondary server, using either `http` or `https`, and ensuring that you
+end the URL with a slash (`/`):
```shell
-SECONDARY_URL="https://<secondary url>/"
-DATABASE_NAME="gitlabhq_production"
-sudo gitlab-psql -d "$DATABASE_NAME" -c "UPDATE geo_nodes SET enabled = true WHERE url = '$SECONDARY_URL';"
+sudo gitlab-rails dbconsole
+
+UPDATE geo_nodes SET enabled = true WHERE url = 'https://<secondary url>/' AND enabled = false;"
```
This should update 1 row.
diff --git a/doc/administration/geo/replication/updating_the_geo_nodes.md b/doc/administration/geo/replication/updating_the_geo_nodes.md
index b78aeb06ebf..1af2b8d0b88 100644
--- a/doc/administration/geo/replication/updating_the_geo_nodes.md
+++ b/doc/administration/geo/replication/updating_the_geo_nodes.md
@@ -21,14 +21,17 @@ Updating Geo nodes involves performing:
NOTE: **Note:**
These general update steps are not intended for [high-availability deployments](https://docs.gitlab.com/omnibus/update/README.html#multi-node--ha-deployment), and will cause downtime. If you want to avoid downtime, consider using [zero downtime updates](https://docs.gitlab.com/omnibus/update/README.html#zero-downtime-updates).
+DANGER: **Danger:**
+In GitLab 13.2 and later versions, promoting a secondary node to a primary while the secondary is paused fails. We are [investigating the issue](https://gitlab.com/gitlab-org/gitlab/-/issues/225173). Do not pause replication before promoting a secondary. If the node is paused, please resume before promoting.
+
To update the Geo nodes when a new GitLab version is released, update **primary**
and all **secondary** nodes:
1. **Optional:** [Pause replication on each **secondary** node.](../index.md#pausing-and-resuming-replication)
1. Log into the **primary** node.
-1. [Update GitLab on the **primary** node using Omnibus](https://docs.gitlab.com/omnibus/update/README.html).
+1. [Update GitLab on the **primary** node using Omnibus's Geo-specific steps](https://docs.gitlab.com/omnibus/update/README.html#geo-deployment).
1. Log into each **secondary** node.
-1. [Update GitLab on each **secondary** node using Omnibus](https://docs.gitlab.com/omnibus/update/README.html).
+1. [Update GitLab on each **secondary** node using Omnibus's Geo-specific steps](https://docs.gitlab.com/omnibus/update/README.html#geo-deployment).
1. If you paused replication in step 1, [resume replication on each **secondary**](../index.md#pausing-and-resuming-replication)
1. [Test](#check-status-after-updating) **primary** and **secondary** nodes, and check version in each.
diff --git a/doc/administration/geo/replication/version_specific_updates.md b/doc/administration/geo/replication/version_specific_updates.md
index 1ae246e3e61..85c869eff92 100644
--- a/doc/administration/geo/replication/version_specific_updates.md
+++ b/doc/administration/geo/replication/version_specific_updates.md
@@ -397,7 +397,7 @@ existing repositories was added in GitLab 10.1.
## Updating to GitLab 10.0
-Since GitLab 10.0, we require all **Geo** systems to [use SSH key lookups via
+In GitLab 10.0 and later, we require all **Geo** systems to [use SSH key lookups via
the database](../../operations/fast_ssh_key_lookup.md) to avoid having to maintain consistency of the
`authorized_keys` file for SSH access. Failing to do this will prevent users
from being able to clone via SSH.
@@ -447,8 +447,8 @@ Omnibus is the following:
> **IMPORTANT**:
With GitLab 9.0, the PostgreSQL version is updated to 9.6 and manual steps are
-required in order to update the **secondary** nodes and keep the Streaming
-Replication working. Downtime is required, so plan ahead.
+required to update the **secondary** nodes and keep the Streaming Replication
+working. Downtime is required, so plan ahead.
The following steps apply only if you update from a 8.17 GitLab version to
9.0+. For previous versions, update to GitLab 8.17 first before attempting to
@@ -611,9 +611,9 @@ is prepended with the relevant node for better clarity:
### Update tracking database on **secondary** node
-After updating a **secondary** node, you might need to run migrations on
-the tracking database. The tracking database was added in GitLab 9.1,
-and it is required since 10.0.
+After updating a **secondary** node, you might need to run migrations on the
+tracking database. The tracking database was added in GitLab 9.1, and is
+required in GitLab 10.0 and later.
1. Run database migrations on tracking database:
diff --git a/doc/administration/geo/setup/database.md b/doc/administration/geo/setup/database.md
index aefa8a0e399..09b9c71aeb7 100644
--- a/doc/administration/geo/setup/database.md
+++ b/doc/administration/geo/setup/database.md
@@ -17,9 +17,10 @@ NOTE: **Note:**
The stages of the setup process must be completed in the documented order.
Before attempting the steps in this stage, [complete all prior stages](../setup/index.md#using-omnibus-gitlab).
-This document describes the minimal steps you have to take in order to
-replicate your **primary** GitLab database to a **secondary** node's database. You may
-have to change some values according to your database setup, how big it is, etc.
+This document describes the minimal steps you have to take to replicate your
+**primary** GitLab database to a **secondary** node's database. You may have to
+change some values, based on attributes including your database's setup and
+size.
You are encouraged to first read through all the steps before executing them
in your testing/production environment.
@@ -433,6 +434,11 @@ data before running `pg_basebackup`.
NOTE: **Note:**
Replication slot names must only contain lowercase letters, numbers, and the underscore character.
+ NOTE: **Note:**
+ In GitLab 13.4, a seed project is added when GitLab is first installed. This makes it necessary to pass `--force` even
+ on a new Geo secondary node. There is an [issue to account for seed projects](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/5618)
+ when checking the database.
+
When prompted, enter the _plaintext_ password you set up for the `gitlab_replicator`
user in the first step.
diff --git a/doc/administration/gitaly/index.md b/doc/administration/gitaly/index.md
index e6b137bac29..59a6f2596da 100644
--- a/doc/administration/gitaly/index.md
+++ b/doc/administration/gitaly/index.md
@@ -90,10 +90,10 @@ When running Gitaly on its own server, note the following regarding GitLab versi
leveraged for redundancy on block-level Git data, but only has to be mounted 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. In order to use Elasticsearch in these versions, the
+ NFS. To use Elasticsearch in these versions, the
[repository indexer](../../integration/elasticsearch.md#elasticsearch-repository-indexer)
must be enabled in your GitLab configuration.
-- [Since GitLab 12.3](https://gitlab.com/gitlab-org/gitlab/-/issues/6481), the new indexer is
+- [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
@@ -317,7 +317,7 @@ disable enforcement. For more information, see the documentation on configuring
```
1. Save the file and [reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure).
-1. Run `sudo /opt/gitlab/embedded/service/gitlab-shell/bin/check -config /opt/gitlab/embedded/service/gitlab-shell/config.yml`
+1. Run `sudo /opt/gitlab/embedded/bin/gitaly-hooks check /var/opt/gitlab/gitaly/config.toml`
to confirm that Gitaly can perform callbacks to the GitLab internal API.
**For installations from source**
@@ -364,7 +364,7 @@ disable enforcement. For more information, see the documentation on configuring
```
1. Save the files and [restart GitLab](../restart_gitlab.md#installations-from-source).
-1. Run `sudo -u git /home/git/gitlab-shell/bin/check -config /home/git/gitlab-shell/config.yml`
+1. Run `sudo -u git /home/git/gitaly/gitaly-hooks check /home/git/gitaly/config.toml`
to confirm that Gitaly can perform callbacks to the GitLab internal API.
### Configure Gitaly clients
@@ -382,10 +382,10 @@ if previously enabled manually.
Gitaly makes the following assumptions:
- Your `gitaly1.internal` Gitaly server can be reached at `gitaly1.internal:8075` from your Gitaly
- clients, and that Gitaly server can read and write to `/mnt/gitlab/default` and
+ clients, and that Gitaly server can read, write, and set permissions on `/mnt/gitlab/default` and
`/mnt/gitlab/storage1`.
- Your `gitaly2.internal` Gitaly server can be reached at `gitaly2.internal:8075` from your Gitaly
- clients, and that Gitaly server can read and write to `/mnt/gitlab/storage2`.
+ clients, and that Gitaly server can read, write, and set permissions on `/mnt/gitlab/storage2`.
- Your `gitaly1.internal` and `gitaly2.internal` Gitaly servers can reach each other.
You can't define Gitaly servers with some as a local Gitaly server
@@ -406,8 +406,8 @@ server (with `gitaly_address`) unless you setup with special
```
1. Save the file and [reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure).
-1. Run `sudo gitlab-rake gitlab:gitaly:check` to confirm the Gitaly client can connect to Gitaly
- servers.
+1. Run `sudo gitlab-rake gitlab:gitaly:check` on the Gitaly client (for example, the
+ Rails application) to confirm it can connect to Gitaly servers.
1. Tail the logs to see the requests:
```shell
@@ -424,17 +424,17 @@ server (with `gitaly_address`) unless you setup with special
storages:
default:
gitaly_address: tcp://gitaly1.internal:8075
- path: /some/dummy/path
+ path: /some/local/path
storage1:
gitaly_address: tcp://gitaly1.internal:8075
- path: /some/dummy/path
+ path: /some/local/path
storage2:
gitaly_address: tcp://gitaly2.internal:8075
- path: /some/dummy/path
+ path: /some/local/path
```
NOTE: **Note:**
- `/some/dummy/path` should be set to a local folder that exists, however no data will be stored in
+ `/some/local/path` should be set to a local folder that exists, however no data will be stored in
this folder. This will no longer be necessary after
[this issue](https://gitlab.com/gitlab-org/gitaly/-/issues/1282) is resolved.
@@ -482,6 +482,14 @@ git_data_dirs({
'storage1' => { 'gitaly_address' => 'tcp://gitlab.internal:8075', 'path' => '/mnt/gitlab/git-data' },
'storage2' => { 'gitaly_address' => 'tcp://gitaly2.internal:8075' },
})
+
+# Make Gitaly accept connections on all network interfaces
+gitaly['listen_addr'] = "0.0.0.0:8075"
+
+# Or for TLS
+gitaly['tls_listen_addr'] = "0.0.0.0:9999"
+gitaly['certificate_path'] = "/etc/gitlab/ssl/cert.pem"
+gitaly['key_path'] = "/etc/gitlab/ssl/key.pem"
```
`path` can only be included for storage shards on the local Gitaly server.
@@ -532,20 +540,12 @@ corresponding to each Gitaly server must be installed on that Gitaly server.
Additionally, the certificate (or its certificate authority) must be installed on all:
-- Gitaly servers, including the Gitaly server using the certificate.
+- Gitaly servers.
- Gitaly clients that communicate with it.
-The process is documented in the
-[GitLab custom certificate configuration](https://docs.gitlab.com/omnibus/settings/ssl.html#install-custom-public-certificates)
-and repeated below.
-
Note the following:
-- The certificate must specify the address you use to access the Gitaly server. If you are:
- - Addressing the Gitaly server by a hostname, you can either use the Common Name field for this,
- or add it as a Subject Alternative Name.
- - Addressing the Gitaly server by its IP address, you must add it as a Subject Alternative Name to
- the certificate. [gRPC does not support using an IP address as Common Name in a certificate](https://github.com/grpc/grpc/issues/2691).
+- The certificate must specify the address you use to access the Gitaly server. You must add the hostname or IP address as a Subject Alternative Name to the certificate.
- You can configure Gitaly servers with both an unencrypted listening address `listen_addr` and an
encrypted listening address `tls_listen_addr` at the same time. This allows you to gradually
transition from unencrypted to encrypted traffic if necessary.
@@ -631,17 +631,17 @@ To configure Gitaly with TLS:
storages:
default:
gitaly_address: tls://gitaly1.internal:9999
- path: /some/dummy/path
+ path: /some/local/path
storage1:
gitaly_address: tls://gitaly1.internal:9999
- path: /some/dummy/path
+ path: /some/local/path
storage2:
gitaly_address: tls://gitaly2.internal:9999
- path: /some/dummy/path
+ path: /some/local/path
```
NOTE: **Note:**
- `/some/dummy/path` should be set to a local folder that exists, however no data will be stored
+ `/some/local/path` should be set to a local folder that exists, however no data will be stored
in this folder. This will no longer be necessary after
[Gitaly issue #1282](https://gitlab.com/gitlab-org/gitaly/-/issues/1282) is resolved.
@@ -711,6 +711,15 @@ Gitaly Go process. Some examples of things that are implemented in `gitaly-ruby`
- RPCs that deal with wikis.
- RPCs that create commits on behalf of a user, such as merge commits.
+We recommend:
+
+- At least 300MB memory per worker.
+- No more than one worker per core.
+
+NOTE: **Note:**
+`gitaly-ruby` is planned to be eventually removed. To track progress, see the
+[Remove the Gitaly-Ruby sidecar](https://gitlab.com/groups/gitlab-org/-/epics/2862) epic.
+
### Configure number of `gitaly-ruby` workers
`gitaly-ruby` has much less capacity than Gitaly implemented in Go. If your Gitaly server has to handle lots of
@@ -1021,6 +1030,9 @@ The second facet presents the only real solution. For this, we developed
## Troubleshooting Gitaly
+Check [Gitaly timeouts](../../user/admin_area/settings/gitaly_timeouts.md) when troubleshooting
+Gitaly.
+
### Checking versions when using standalone Gitaly servers
When using standalone Gitaly servers, you must make sure they are the same version
@@ -1242,13 +1254,6 @@ unset http_proxy
unset https_proxy
```
-### Gitaly not listening on new address after reconfiguring
-
-When updating the `gitaly['listen_addr']` or `gitaly['prometheus_listen_addr']`
-values, Gitaly may continue to listen on the old address after a `sudo gitlab-ctl reconfigure`.
-
-When this occurs, performing a `sudo gitlab-ctl restart` will resolve the issue. This will no longer be necessary after [this issue](https://gitlab.com/gitlab-org/gitaly/-/issues/2521) is resolved.
-
### Permission denied errors appearing in Gitaly logs when accessing repositories from a standalone Gitaly server
If this error occurs even though file permissions are correct, it's likely that
diff --git a/doc/administration/gitaly/praefect.md b/doc/administration/gitaly/praefect.md
index 876904a2093..d091ae5895a 100644
--- a/doc/administration/gitaly/praefect.md
+++ b/doc/administration/gitaly/praefect.md
@@ -182,7 +182,7 @@ failure. For greater fault tolerance, the following options are available:
- For Geo instances, either:
- Set up a separate [PostgreSQL instance](https://www.postgresql.org/docs/11/high-availability.html).
- Use a cloud-managed PostgreSQL service. AWS
- [Relational Database Service](https://aws.amazon.com/rds/)) is recommended.
+ [Relational Database Service](https://aws.amazon.com/rds/) is recommended.
To complete this section you will need:
@@ -356,7 +356,7 @@ application server, or a Gitaly node.
If you want to use a TLS client certificate, the options below can be used:
```ruby
- # Connect to PostreSQL using a TLS client certificate
+ # Connect to PostgreSQL using a TLS client certificate
# praefect['database_sslcert'] = '/path/to/client-cert'
# praefect['database_sslkey'] = '/path/to/client-key'
@@ -547,14 +547,14 @@ To configure Praefect with TLS:
storages:
default:
gitaly_address: tls://praefect1.internal:3305
- path: /some/dummy/path
+ path: /some/local/path
storage1:
gitaly_address: tls://praefect2.internal:3305
- path: /some/dummy/path
+ path: /some/local/path
```
NOTE: **Note:**
- `/some/dummy/path` should be set to a local folder that exists, however no
+ `/some/local/path` should be set to a local folder that exists, however no
data will be stored in this folder. This will no longer be necessary after
[this issue](https://gitlab.com/gitlab-org/gitaly/-/issues/1282) is resolved.
@@ -873,10 +873,10 @@ Particular attention should be shown to:
gitlab-ctl reconfigure
```
-1. Verify each `gitlab-shell` on each Gitaly node can reach GitLab. On each Gitaly node run:
+1. Verify on each Gitaly node the Git Hooks can reach GitLab. On each Gitaly node run:
```shell
- /opt/gitlab/embedded/service/gitlab-shell/bin/check -config /opt/gitlab/embedded/service/gitlab-shell/config.yml
+ /opt/gitlab/embedded/bin/gitaly-hooks check /var/opt/gitlab/gitaly/config.toml
```
1. Verify that GitLab can reach Praefect:
@@ -943,16 +943,17 @@ cluster.
## Distributed reads
> - Introduced in GitLab 13.1 in [beta](https://about.gitlab.com/handbook/product/gitlab-the-product/#alpha-beta-ga) with feature flag `gitaly_distributed_reads` set to disabled.
-> - [Made generally available](https://gitlab.com/gitlab-org/gitaly/-/issues/2951) in GitLab 13.3.
+> - [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.
Praefect supports distribution of read operations across Gitaly nodes that are
configured for the virtual node.
-The feature is enabled by default. To disable distributed reads, the `gitaly_distributed_reads`
-[feature flag](../feature_flags.md) must be disabled in a Ruby console:
+The feature is disabled by default. To enable distributed reads, the `gitaly_distributed_reads`
+[feature flag](../feature_flags.md) must be enabled in a Ruby console:
```ruby
-Feature.disable(:gitaly_distributed_reads)
+Feature.enable(:gitaly_distributed_reads)
```
If enabled, all RPCs marked with `ACCESSOR` option like
@@ -993,6 +994,8 @@ information, see the [strong consistency epic](https://gitlab.com/groups/gitlab-
To enable strong consistency:
+- In GitLab 13.5, you must use Git v2.28.0 or higher on Gitaly nodes to enable
+ strong consistency.
- In GitLab 13.4 and later, the strong consistency voting strategy has been
improved. Instead of requiring all nodes to agree, only the primary and half
of the secondaries need to agree. This strategy is enabled by default. To
diff --git a/doc/administration/gitaly/reference.md b/doc/administration/gitaly/reference.md
index 0c211c220d7..53001b946d8 100644
--- a/doc/administration/gitaly/reference.md
+++ b/doc/administration/gitaly/reference.md
@@ -138,8 +138,8 @@ Most of the time we use `git cat-file --batch` processes for that. For
better performance, Gitaly can re-use these `git cat-file` processes
across RPC calls. Previously used processes are kept around in a
["Git cat-file cache"](https://about.gitlab.com/blog/2019/07/08/git-performance-on-nfs/#enter-cat-file-cache).
-In order to control how much system resources this uses, we have a maximum number
-of cat-file processes that can go into the cache.
+To control how much system resources this uses, we have a maximum number of
+cat-file processes that can go into the cache.
The default limit is 100 `cat-file`s, which constitute a pair of
`git cat-file --batch` and `git cat-file --batch-check` processes. If
diff --git a/doc/administration/high_availability/README.md b/doc/administration/high_availability/README.md
deleted file mode 100644
index d36b029cbb3..00000000000
--- a/doc/administration/high_availability/README.md
+++ /dev/null
@@ -1,7 +0,0 @@
----
-redirect_to: ../reference_architectures/index.md
----
-
-# Reference Architectures
-
-This document was moved to [another location](../reference_architectures/index.md).
diff --git a/doc/administration/high_availability/alpha_database.md b/doc/administration/high_availability/alpha_database.md
deleted file mode 100644
index 99c28e5c7a6..00000000000
--- a/doc/administration/high_availability/alpha_database.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: 'database.md'
----
-
-This document was moved to [another location](../postgresql/index.md).
diff --git a/doc/administration/high_availability/consul.md b/doc/administration/high_availability/consul.md
deleted file mode 100644
index 362d6ee8ba7..00000000000
--- a/doc/administration/high_availability/consul.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: ../consul.md
----
-
-This document was moved to [another location](../consul.md).
diff --git a/doc/administration/high_availability/database.md b/doc/administration/high_availability/database.md
deleted file mode 100644
index 784e496d10e..00000000000
--- a/doc/administration/high_availability/database.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../postgresql/index.md'
----
-
-This document was moved to [another location](../postgresql/index.md).
diff --git a/doc/administration/high_availability/gitaly.md b/doc/administration/high_availability/gitaly.md
deleted file mode 100644
index a1e8fe3b488..00000000000
--- a/doc/administration/high_availability/gitaly.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: ../gitaly/index.md
----
-
-This document was moved to [another location](../gitaly/index.md).
diff --git a/doc/administration/high_availability/gitlab.md b/doc/administration/high_availability/gitlab.md
deleted file mode 100644
index 748373c8941..00000000000
--- a/doc/administration/high_availability/gitlab.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: ../reference_architectures/index.md
----
-
-This document was moved to [another location](../reference_architectures/index.md).
diff --git a/doc/administration/high_availability/img/fully-distributed.png b/doc/administration/high_availability/img/fully-distributed.png
deleted file mode 100644
index c3cd2bf24f0..00000000000
--- a/doc/administration/high_availability/img/fully-distributed.png
+++ /dev/null
Binary files differ
diff --git a/doc/administration/high_availability/img/horizontal.png b/doc/administration/high_availability/img/horizontal.png
deleted file mode 100644
index 75d08e1097a..00000000000
--- a/doc/administration/high_availability/img/horizontal.png
+++ /dev/null
Binary files differ
diff --git a/doc/administration/high_availability/img/hybrid.png b/doc/administration/high_availability/img/hybrid.png
deleted file mode 100644
index 8dd9923e597..00000000000
--- a/doc/administration/high_availability/img/hybrid.png
+++ /dev/null
Binary files differ
diff --git a/doc/administration/high_availability/load_balancer.md b/doc/administration/high_availability/load_balancer.md
deleted file mode 100644
index 5cedc4e11ae..00000000000
--- a/doc/administration/high_availability/load_balancer.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: ../load_balancer.md
----
-
-This document was moved to [another location](../load_balancer.md).
diff --git a/doc/administration/high_availability/monitoring_node.md b/doc/administration/high_availability/monitoring_node.md
deleted file mode 100644
index 76bcf6d0d40..00000000000
--- a/doc/administration/high_availability/monitoring_node.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: ../monitoring/prometheus/index.md
----
-
-This document was moved to [another location](../monitoring/prometheus/index.md).
diff --git a/doc/administration/high_availability/nfs.md b/doc/administration/high_availability/nfs.md
deleted file mode 100644
index e3342fa0813..00000000000
--- a/doc/administration/high_availability/nfs.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: ../nfs.md
----
-
-This document was moved to [another location](../nfs.md).
diff --git a/doc/administration/high_availability/nfs_host_client_setup.md b/doc/administration/high_availability/nfs_host_client_setup.md
deleted file mode 100644
index e3342fa0813..00000000000
--- a/doc/administration/high_availability/nfs_host_client_setup.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: ../nfs.md
----
-
-This document was moved to [another location](../nfs.md).
diff --git a/doc/administration/high_availability/object_storage.md b/doc/administration/high_availability/object_storage.md
deleted file mode 100644
index eeb730d3cc7..00000000000
--- a/doc/administration/high_availability/object_storage.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../object_storage.md'
----
-
-This document was moved to [another location](../object_storage.md).
diff --git a/doc/administration/high_availability/pgbouncer.md b/doc/administration/high_availability/pgbouncer.md
deleted file mode 100644
index 44f4aa37651..00000000000
--- a/doc/administration/high_availability/pgbouncer.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: ../postgresql/pgbouncer.md
----
-
-This document was moved to [another location](../postgresql/pgbouncer.md).
diff --git a/doc/administration/high_availability/redis.md b/doc/administration/high_availability/redis.md
deleted file mode 100644
index 2b5771f49f2..00000000000
--- a/doc/administration/high_availability/redis.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: ../redis/index.md
----
-
-This document was moved to [another location](../redis/index.md).
diff --git a/doc/administration/high_availability/redis_source.md b/doc/administration/high_availability/redis_source.md
deleted file mode 100644
index 75496638979..00000000000
--- a/doc/administration/high_availability/redis_source.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: ../redis/replication_and_failover_external.md
----
-
-This document was moved to [another location](../redis/replication_and_failover_external.md).
diff --git a/doc/administration/high_availability/sidekiq.md b/doc/administration/high_availability/sidekiq.md
deleted file mode 100644
index ac92ae2eaaa..00000000000
--- a/doc/administration/high_availability/sidekiq.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: ../sidekiq.md
----
-
-This document was moved to [another location](../sidekiq.md).
diff --git a/doc/administration/housekeeping.md b/doc/administration/housekeeping.md
index 4110f8b7646..c784c788b31 100644
--- a/doc/administration/housekeeping.md
+++ b/doc/administration/housekeeping.md
@@ -1,3 +1,9 @@
+---
+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/engineering/ux/technical-writing/#designated-technical-writers
+---
+
# Housekeeping
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/3041) in GitLab 8.4.
@@ -28,6 +34,9 @@ the `pushes_since_gc` value is 200 a `git gc` will be run.
`git add`.
- `git repack` ([man page](https://mirrors.edge.kernel.org/pub/software/scm/git/docs/git-repack.html)) re-organize existing packs into a single, more efficient pack.
+Housekeeping will also [remove unreferenced LFS files](../raketasks/cleanup.md#remove-unreferenced-lfs-files)
+from your project on the same schedule as the `git gc` operation, freeing up storage space for your project.
+
You can find this option under your project's **Settings > General > Advanced**.
![Housekeeping settings](img/housekeeping_settings.png)
diff --git a/doc/administration/img/export_audit_log_v13_4.png b/doc/administration/img/export_audit_log_v13_4.png
index 1b404b5742c..e4ba330b8a9 100644
--- a/doc/administration/img/export_audit_log_v13_4.png
+++ b/doc/administration/img/export_audit_log_v13_4.png
Binary files differ
diff --git a/doc/administration/incoming_email.md b/doc/administration/incoming_email.md
index c0c03044225..bd075e86a15 100644
--- a/doc/administration/incoming_email.md
+++ b/doc/administration/incoming_email.md
@@ -82,15 +82,15 @@ instead of the regular password for the mailbox.
To set up a basic Postfix mail server with IMAP access on Ubuntu, follow the
[Postfix setup documentation](reply_by_email_postfix_setup.md).
-### Security Concerns
+### Security concerns
-WARNING: **WARNING:**
+CAUTION: **Caution:**
Be careful when choosing the domain used for receiving incoming email.
-For the sake of example, suppose your top-level company domain is `hooli.com`.
+For example, suppose your top-level company domain is `hooli.com`.
All employees in your company have an email address at that domain via Google
Apps, and your company's private Slack instance requires a valid `@hooli.com`
-email address in order to sign up.
+email address to sign up.
If you also host a public-facing GitLab instance at `hooli.com` and set your
incoming email domain to `hooli.com`, an attacker could abuse the "Create new
@@ -112,7 +112,7 @@ See GitLab issue [#30366](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/303
for a real-world example of this exploit.
CAUTION: **Caution:**
-Be sure to use a mail server that has been configured to reduce
+Use a mail server that has been configured to reduce
spam.
A Postfix mail server that is running on a default configuration, for example,
can result in abuse. All messages received on the configured mailbox will be processed
diff --git a/doc/administration/index.md b/doc/administration/index.md
index a6448fcf64f..07aa3b50bc6 100644
--- a/doc/administration/index.md
+++ b/doc/administration/index.md
@@ -1,8 +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/engineering/ux/technical-writing/#designated-technical-writers
description: 'Learn how to install, configure, update, and maintain your GitLab instance.'
---
-# Administrator Docs **(CORE ONLY)**
+# Administrator documentation **(CORE ONLY)**
Learn how to administer your self-managed GitLab instance.
@@ -12,18 +15,16 @@ GitLab has two product distributions available through [different subscriptions]
- The open core [GitLab Enterprise Edition (EE)](https://gitlab.com/gitlab-org/gitlab).
You can [install either GitLab CE or GitLab EE](https://about.gitlab.com/install/ce-or-ee/).
-However, the features you'll have access to depend on the subscription you choose
-(Core, Starter, Premium, or Ultimate).
+However, the features you have access to depend on your chosen [subscription](https://about.gitlab.com/pricing/).
-NOTE: **Note:**
-GitLab Community Edition installations only have access to Core features.
+GitLab Community Edition installations have access only to Core features.
-GitLab.com is administered by GitLab, Inc., therefore, only GitLab team members have
-access to its admin configurations. If you're a GitLab.com user, please check the
-[user documentation](../user/index.md).
+Non-administrator users can't access GitLab administration tools and settings.
-NOTE: **Note:**
-Non-administrator users don’t have access to GitLab administration tools and settings.
+GitLab.com is administered by GitLab, Inc., and only GitLab team members have
+access to its administration tools and settings. Users of GitLab.com should
+instead refer to the [User documentation](../user/index.md) for GitLab
+configuration and usage documentation.
## Installing and maintaining GitLab
@@ -52,8 +53,10 @@ Learn how to install, configure, update, and maintain your GitLab instance.
- [GitLab Pages configuration](pages/index.md): Enable and configure GitLab Pages.
- [GitLab Pages configuration for GitLab source installations](pages/source.md): Enable and configure GitLab Pages on [source installations](../install/installation.md#installation-from-source).
- [Uploads administration](uploads.md): Configure GitLab uploads storage.
-- [Environment variables](environment_variables.md): Supported environment variables that can be used to override their defaults values in order to configure GitLab.
-- [Plugins](plugins.md): With custom plugins, GitLab administrators can introduce custom integrations without modifying GitLab's source code.
+- [Environment variables](environment_variables.md): Supported environment
+ variables that can be used to override their default values to configure
+ GitLab.
+- [Plugins](file_hooks.md): With custom plugins, GitLab administrators can introduce custom integrations without modifying GitLab's source code.
- [Enforcing Terms of Service](../user/admin_area/settings/terms.md)
- [Third party offers](../user/admin_area/settings/third_party_offers.md)
- [Compliance](compliance.md): A collection of features from across the application that you may configure to help ensure that your GitLab instance and DevOps workflow meet compliance standards.
@@ -82,6 +85,7 @@ Learn how to install, configure, update, and maintain your GitLab instance.
- [Operations](operations/index.md): Keeping GitLab up and running (clean up Redis sessions, moving repositories, Sidekiq MemoryKiller, Puma).
- [Restart GitLab](restart_gitlab.md): Learn how to restart GitLab and its components.
- [Invalidate Markdown cache](invalidate_markdown_cache.md): Invalidate any cached Markdown.
+- [Instance review](instance_review.md): Request a free review of your GitLab instance.
#### Updating GitLab
@@ -113,7 +117,7 @@ Learn how to install, configure, update, and maintain your GitLab instance.
- [Kerberos authentication](../integration/kerberos.md) **(STARTER ONLY)**
- See also other [authentication](../topics/authentication/index.md#gitlab-administrators) topics (for example, enforcing 2FA).
- [Email users](../tools/email.md): Email GitLab users from within GitLab. **(STARTER ONLY)**
-- [User Cohorts](../user/admin_area/user_cohorts.md): Display the monthly cohorts of new users and their activities over time.
+- [User Cohorts](../user/admin_area/analytics/user_cohorts.md): Display the monthly cohorts of new users and their activities over time.
- [Audit logs and events](audit_events.md): View the changes made within the GitLab server for:
- Groups and projects. **(STARTER)**
- Instances. **(PREMIUM ONLY)**
diff --git a/doc/administration/instance_limits.md b/doc/administration/instance_limits.md
index abd98002934..cb37be8d9dd 100644
--- a/doc/administration/instance_limits.md
+++ b/doc/administration/instance_limits.md
@@ -1,4 +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/engineering/ux/technical-writing/#designated-technical-writers
type: reference
---
@@ -163,7 +166,7 @@ There is a limit when embedding metrics in GFM for performance reasons.
On GitLab.com, the [maximum number of webhooks and their size](../user/gitlab_com/index.md#webhooks) per project, and per group, is limited.
To set this limit on a self-managed installation, run the following in the
-[GitLab Rails console](troubleshooting/debug.md#starting-a-rails-console-session):
+[GitLab Rails console](operations/rails_console.md#starting-a-rails-console-session):
```ruby
# If limits don't exist for the default plan, you can create one with:
@@ -203,7 +206,7 @@ support keyset-based pagination. More information about pagination options can b
found in the [API docs section on pagination](../api/README.md#pagination).
To set this limit on a self-managed installation, run the following in the
-[GitLab Rails console](troubleshooting/debug.md#starting-a-rails-console-session):
+[GitLab Rails console](operations/rails_console.md#starting-a-rails-console-session):
```ruby
# If limits don't exist for the default plan, you can create one with:
@@ -238,7 +241,7 @@ will fail with a `job_activity_limit_exceeded` error.
This limit is disabled by default.
To set this limit on a self-managed installation, run the following in the
-[GitLab Rails console](troubleshooting/debug.md#starting-a-rails-console-session):
+[GitLab Rails console](operations/rails_console.md#starting-a-rails-console-session):
```ruby
# If limits don't exist for the default plan, you can create one with:
@@ -264,7 +267,7 @@ limit, the subscription will be considered invalid.
- On [GitLab Starter](https://about.gitlab.com/pricing/#self-managed) tier or higher self-managed installations, this limit is defined for the `default` plan that affects all projects.
To set this limit on a self-managed installation, run the following in the
-[GitLab Rails console](troubleshooting/debug.md#starting-a-rails-console-session):
+[GitLab Rails console](operations/rails_console.md#starting-a-rails-console-session):
```ruby
Plan.default.actual_limits.update!(ci_project_subscriptions: 500)
@@ -290,7 +293,7 @@ or higher tiers), this limit is defined for the `default` plan that affects all
projects. By default, there is no limit.
To set this limit on a self-managed installation, run the following in the
-[GitLab Rails console](troubleshooting/debug.md#starting-a-rails-console-session):
+[GitLab Rails console](operations/rails_console.md#starting-a-rails-console-session):
```ruby
Plan.default.actual_limits.update!(ci_pipeline_schedules: 100)
@@ -308,7 +311,7 @@ On self-managed instances this limit is defined for the `default` plan. By defau
this limit is set to `25`.
To update this limit to a new value on a self-managed installation, run the following in the
-[GitLab Rails console](troubleshooting/debug.md#starting-a-rails-console-session):
+[GitLab Rails console](operations/rails_console.md#starting-a-rails-console-session):
```ruby
Plan.default.actual_limits.update!(ci_instance_level_variables: 30)
@@ -333,6 +336,7 @@ setting is used:
| Artifact limit name | Default value |
|---------------------------------------------|---------------|
| `ci_max_artifact_size_accessibility` | 0 |
+| `ci_max_artifact_size_api_fuzzing` | 0 |
| `ci_max_artifact_size_archive` | 0 |
| `ci_max_artifact_size_browser_performance` | 0 |
| `ci_max_artifact_size_cluster_applications` | 0 |
@@ -360,7 +364,7 @@ setting is used:
| `ci_max_artifact_size_trace` | 0 |
For example, to set the `ci_max_artifact_size_junit` limit to 10MB on a self-managed
-installation, run the following in the [GitLab Rails console](troubleshooting/debug.md#starting-a-rails-console-session):
+installation, run the following in the [GitLab Rails console](operations/rails_console.md#starting-a-rails-console-session):
```ruby
Plan.default.actual_limits.update!(ci_max_artifact_size_junit: 10)
@@ -480,7 +484,7 @@ indexed](#maximum-file-size-indexed)).
- For self-managed installations it is unlimited by default
This limit can be configured for self-managed installations when [enabling
-Elasticsearch](../integration/elasticsearch.md#enabling-elasticsearch).
+Elasticsearch](../integration/elasticsearch.md#enabling-advanced-search).
NOTE: **Note:**
Set the limit to `0` to disable it.
@@ -527,13 +531,17 @@ More information can be found in the [Push event activities limit and bulk push
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/218017) in GitLab 13.4.
-On GitLab.com, the maximum file size for a package that's uploaded to the [GitLab Package Registry](../user/packages/package_registry/index.md)
-is 5 gigabytes.
+On GitLab.com, the maximum file size for a package that's uploaded to the [GitLab Package Registry](../user/packages/package_registry/index.md) varies by format:
-Limits are set per package type.
+- Conan: 3GB
+- Generic: 5GB
+- Maven: 3GB
+- NPM: 500MB
+- NuGet: 500MB
+- PyPI: 3GB
To set this limit on a self-managed installation, run the following in the
-[GitLab Rails console](troubleshooting/debug.md#starting-a-rails-console-session):
+[GitLab Rails console](operations/rails_console.md#starting-a-rails-console-session):
```ruby
# File size limit is stored in bytes
@@ -552,6 +560,12 @@ Plan.default.actual_limits.update!(maven_max_file_size: 100.megabytes)
# For PyPI Packages
Plan.default.actual_limits.update!(pypi_max_file_size: 100.megabytes)
+
+# For Debian Packages
+Plan.default.actual_limits.update!(debian_max_file_size: 100.megabytes)
+
+# For Generic Packages
+Plan.default.actual_limits.update!(generic_packages_max_file_size: 100.megabytes)
```
Set the limit to `0` to allow any file size.
diff --git a/doc/administration/instance_review.md b/doc/administration/instance_review.md
index 8ea4bff252e..7eadb54804b 100644
--- a/doc/administration/instance_review.md
+++ b/doc/administration/instance_review.md
@@ -1,13 +1,25 @@
+---
+stage: Growth
+group: Conversion
+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/#designated-technical-writers
+---
+
# Instance Review **(CORE ONLY)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/6995) in [GitLab Core](https://about.gitlab.com/pricing/) 11.3.
-If you are running a medium size instance of GitLab Core edition you are qualified for a free Instance Review. You can find the button in the User menu.
+If you are running a medium size instance (50+ users) of
+[GitLab Core](https://about.gitlab.com/pricing/) edition, you are qualified for a
+free Instance Review.
-![Instance Review button](img/instance_review_button.png)
+1. Sign in as a user with Admin [permissions](../user/permissions.md).
+1. In the top menu, click your user icon, and select
+ **Get a free instance review**:
-When you click the button you will be redirected to a form with prefilled data obtained from your instance.
+ ![Instance Review button](img/instance_review_button.png)
-Once you submit the data to GitLab Inc. you can see the initial report.
+1. GitLab redirects you to a form with prefilled data obtained from your instance.
+1. Click **Submit** to see the initial report.
-Additionally you will be contacted by our team for further review which should help you to improve your usage of GitLab.
+A GitLab team member will contact you for further review, to provide suggestions
+that will help you improve your usage of GitLab.
diff --git a/doc/administration/integration/plantuml.md b/doc/administration/integration/plantuml.md
index 49ea59d239c..5bdea9d8843 100644
--- a/doc/administration/integration/plantuml.md
+++ b/doc/administration/integration/plantuml.md
@@ -132,7 +132,7 @@ stop;
You need to enable PlantUML integration from Settings under Admin Area. To do
that, login with an Admin account and do following:
-- In GitLab, go to **Admin Area > Settings > Integrations**.
+- In GitLab, go to **Admin Area > Settings > General**.
- Expand the **PlantUML** section.
- Check **Enable PlantUML** checkbox.
- Set the PlantUML instance as `https://gitlab.example.com/-/plantuml/`.
diff --git a/doc/administration/integration/terminal.md b/doc/administration/integration/terminal.md
index c363bd30543..3c53535d856 100644
--- a/doc/administration/integration/terminal.md
+++ b/doc/administration/integration/terminal.md
@@ -1,3 +1,9 @@
+---
+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/engineering/ux/technical-writing/#designated-technical-writers
+---
+
# Web terminals
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/7690) in GitLab 8.15.
diff --git a/doc/administration/job_artifacts.md b/doc/administration/job_artifacts.md
index 2a79923b793..8069b12e0b9 100644
--- a/doc/administration/job_artifacts.md
+++ b/doc/administration/job_artifacts.md
@@ -99,8 +99,13 @@ artifacts, you can use an object storage like AWS S3 instead.
This configuration relies on valid AWS credentials to be configured already.
Use an object storage option like AWS S3 to store job artifacts.
+If you configure GitLab to store artifacts on object storage, you may also want to
+[eliminate local disk usage for job logs](job_logs.md#prevent-local-disk-usage).
+In both cases, job logs are archived and moved to object storage when the job completes.
+
DANGER: **Danger:**
-If you configure GitLab to store CI logs and artifacts on object storage, you must also enable [incremental logging](job_logs.md#new-incremental-logging-architecture). Otherwise, job logs will disappear or not be saved.
+In a multi-server setup you must use one of the options to
+[eliminate local disk usage for job logs](job_logs.md#prevent-local-disk-usage), or job logs could be lost.
[Read more about using object storage with GitLab](object_storage.md).
@@ -117,9 +122,9 @@ For source installations the following settings are nested under `artifacts:` an
|---------|-------------|---------|
| `enabled` | Enable/disable object storage | `false` |
| `remote_directory` | The bucket name where Artifacts will be stored| |
-| `direct_upload` | Set to true to enable direct upload of Artifacts without the need of local shared storage. Option may be removed once we decide to support only single storage for all files. | `false` |
-| `background_upload` | Set to false to disable automatic upload. Option may be removed once upload is direct to S3 | `true` |
-| `proxy_download` | Set to true to enable proxying all files served. Option allows to reduce egress traffic as this allows clients to download directly from remote storage instead of proxying all data | `false` |
+| `direct_upload` | Set to `true` to enable direct upload of Artifacts without the need of local shared storage. Option may be removed once we decide to support only single storage for all files. | `false` |
+| `background_upload` | Set to `false` to disable automatic upload. Option may be removed once upload is direct to S3 | `true` |
+| `proxy_download` | Set to `true` to enable proxying all files served. Option allows to reduce egress traffic as this allows clients to download directly from remote storage instead of proxying all data | `false` |
| `connection` | Various connection options described below | |
#### Connection settings
@@ -203,9 +208,9 @@ _The artifacts are stored by default in
enabled: true
object_store:
enabled: true
- remote_directory: "artifacts" # The bucket name
+ remote_directory: "artifacts" # The bucket name
connection:
- provider: AWS # Only AWS supported at the moment
+ provider: AWS # Only AWS supported at the moment
aws_access_key_id: AWS_ACCESS_KEY_ID
aws_secret_access_key: AWS_SECRET_ACCESS_KEY
region: eu-central-1
@@ -316,9 +321,9 @@ _The uploads are stored by default in
**In Omnibus installations:**
-In order to migrate back to local storage:
+To migrate back to local storage:
-1. Set both `direct_upload` and `background_upload` to false in `gitlab.rb`, under the artifacts object storage settings.
+1. Set both `direct_upload` and `background_upload` to `false` in `gitlab.rb`, under the artifacts object storage settings.
1. [Reconfigure GitLab](restart_gitlab.md#omnibus-gitlab-reconfigure).
1. Run `gitlab-rake gitlab:artifacts:migrate_to_local`.
1. Disable object_storage for artifacts in `gitlab.rb`:
@@ -369,7 +374,7 @@ default artifacts expiration setting, which you can find in the [CI/CD Admin set
> Introduced in GitLab 10.3.
-To disable [the dependencies validation](../ci/yaml/README.md#when-a-dependent-job-will-fail),
+To disable [the dependencies validation](../ci/yaml/README.md#when-a-dependent-job-fails),
you can enable the `ci_disable_validates_dependencies` feature flag from a Rails console.
**In Omnibus installations:**
@@ -419,10 +424,10 @@ generated by [GitLab Workhorse](https://gitlab.com/gitlab-org/gitlab-workhorse).
that are located in the artifacts archive itself.
The metadata file is in a binary format, with additional Gzip compression.
-GitLab does not extract the artifacts archive in order to save space, memory
-and disk 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.
+GitLab doesn't extract the artifacts archive to save space, memory, and disk
+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
from the archive and the download begins. This implementation saves space,
diff --git a/doc/administration/job_logs.md b/doc/administration/job_logs.md
index c34035e3c0c..c89ffb8da8b 100644
--- a/doc/administration/job_logs.md
+++ b/doc/administration/job_logs.md
@@ -65,6 +65,15 @@ job logs are automatically migrated to it along with the other job artifacts.
See "Phase 4: uploading" in [Data flow](#data-flow) to learn about the process.
+## Prevent local disk usage
+
+If you want to avoid any local disk usage for job logs,
+you can do so using one of the following options:
+
+- Enable the [beta incremental logging](#new-incremental-logging-architecture) feature.
+- Set the [job logs location](#changing-the-job-logs-local-location)
+ to an NFS drive.
+
## How to remove job logs
There isn't a way to automatically expire old job logs, but it's safe to remove
diff --git a/doc/administration/lfs/index.md b/doc/administration/lfs/index.md
index 5c1a9519a35..a360542ac44 100644
--- a/doc/administration/lfs/index.md
+++ b/doc/administration/lfs/index.md
@@ -6,14 +6,16 @@ type: reference, howto
disqus_identifier: 'https://docs.gitlab.com/ee/workflow/lfs/lfs_administration.html'
---
-# GitLab Git Large File Storage (LFS) Administration
+# GitLab Git Large File Storage (LFS) Administration **(CORE ONLY)**
+
+> - Git LFS is supported in GitLab starting with version 8.2.
+> - Support for object storage, such as AWS S3, was introduced in 10.0.
+> - LFS is enabled in GitLab self-managed instances by default.
Documentation on how to use Git LFS are under [Managing large binary files with Git LFS doc](../../topics/git/lfs/index.md).
## Requirements
-- Git LFS is supported in GitLab starting with version 8.2.
-- Support for object storage, such as AWS S3, was introduced in 10.0.
- Users need to install [Git LFS client](https://git-lfs.github.com) version 1.0.1 and up.
## Configuration
@@ -41,6 +43,8 @@ gitlab_rails['lfs_enabled'] = false
gitlab_rails['lfs_storage_path'] = "/mnt/storage/lfs-objects"
```
+After you update settings in `/etc/gitlab/gitlab.rb`, make sure to run [Omnibus GitLab reconfigure](../restart_gitlab.md#omnibus-gitlab-reconfigure).
+
### Configuration for installations from source
In `config/gitlab.yml`:
diff --git a/doc/administration/libravatar.md b/doc/administration/libravatar.md
index beecd9e4783..a92e6fade03 100644
--- a/doc/administration/libravatar.md
+++ b/doc/administration/libravatar.md
@@ -1,4 +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/engineering/ux/technical-writing/#designated-technical-writers
type: howto
---
@@ -72,10 +75,9 @@ Then run `sudo gitlab-ctl reconfigure` for the changes to take effect.
missing images for user email addresses that are not found on the Libravatar
service.
-In order to use a set other than `identicon`, replace the `&d=identicon`
-portion of the URL with another supported set.
-For example, you can use the `retro` set, in which case the URL would look like:
-`plain_url: "http://cdn.libravatar.org/avatar/%{hash}?s=%{size}&d=retro"`
+To use a set other than `identicon`, replace the `&d=identicon` portion of the
+URL with another supported set. For example, you can use the `retro` set, in
+which case the URL would look like: `plain_url: "http://cdn.libravatar.org/avatar/%{hash}?s=%{size}&d=retro"`
## Usage examples for Microsoft Office 365
@@ -84,8 +86,8 @@ Note that this service requires a login, so this use case is most useful in a
corporate installation where all users have access to Office 365.
```ruby
-gitlab_rails['gravatar_plain_url'] = 'http://outlook.office365.com/owa/service.svc/s/GetPersonaPhoto?email=%{email}&size=HR120x120'
-gitlab_rails['gravatar_ssl_url'] = 'https://outlook.office365.com/owa/service.svc/s/GetPersonaPhoto?email=%{email}&size=HR120x120'
+gitlab_rails['gravatar_plain_url'] = 'http://outlook.office.com/owa/service.svc/s/GetPersonaPhoto?email=%{email}&size=HR120x120'
+gitlab_rails['gravatar_ssl_url'] = 'https://outlook.office.com/owa/service.svc/s/GetPersonaPhoto?email=%{email}&size=HR120x120'
```
<!-- ## Troubleshooting
diff --git a/doc/administration/load_balancer.md b/doc/administration/load_balancer.md
index fe534f30f66..ae4fa83662a 100644
--- a/doc/administration/load_balancer.md
+++ b/doc/administration/load_balancer.md
@@ -1,4 +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/engineering/ux/technical-writing/#designated-technical-writers
type: reference
---
diff --git a/doc/administration/logs.md b/doc/administration/logs.md
index fcd6264dafd..c9e0cca807e 100644
--- a/doc/administration/logs.md
+++ b/doc/administration/logs.md
@@ -1,6 +1,6 @@
---
stage: Monitor
-group: APM
+group: Health
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/#designated-technical-writers
---
@@ -100,9 +100,9 @@ The ActionCable connection or channel class is used as the `controller`.
```json
{
- "method":{},
- "path":{},
- "format":{},
+ "method":null,
+ "path":null,
+ "format":null,
"controller":"IssuesChannel",
"action":"subscribe",
"status":200,
@@ -363,8 +363,7 @@ This file lives in `/var/log/gitlab/gitlab-rails/git_json.log` for
Omnibus GitLab packages or in `/home/git/gitlab/log/git_json.log` for
installations from source.
-NOTE: **Note:**
-After 12.2, this file was renamed from `githost.log` to
+After GitLab version 12.2, this file was renamed from `githost.log` to
`git_json.log` and stored in JSON format.
GitLab has to interact with Git repositories, but in some rare cases
@@ -599,7 +598,6 @@ installations from source.
## Unicorn Logs
-NOTE: **Note:**
Starting with GitLab 13.0, Puma is the default web server used in GitLab
all-in-one package based installations as well as GitLab Helm chart deployments.
@@ -674,10 +672,8 @@ This log records:
- Information whenever [Rack Attack](../security/rack_attack.md) registers an abusive request.
- Requests over the [Rate Limit](../user/admin_area/settings/rate_limits_on_raw_endpoints.md) on raw endpoints.
- [Protected paths](../user/admin_area/settings/protected_paths.md) abusive requests.
-
-NOTE: **Note:**
-In GitLab versions [12.3](https://gitlab.com/gitlab-org/gitlab/-/issues/29239) and greater, user ID and username are also
-recorded on this log, if available.
+- In GitLab versions [12.3](https://gitlab.com/gitlab-org/gitlab/-/issues/29239) and greater,
+ user ID and username, if available.
## `graphql_json.log`
@@ -967,19 +963,9 @@ When [troubleshooting](troubleshooting/index.md) issues that aren't localized to
previously listed components, it's helpful to simultaneously gather multiple logs and statistics
from a GitLab instance.
-### GitLabSOS
-
-If performance degradations or cascading errors occur that can't readily be attributed to one
-of the previously listed GitLab components, [GitLabSOS](https://gitlab.com/gitlab-com/support/toolbox/gitlabsos/)
-can provide a perspective spanning all of Omnibus GitLab. For more details and instructions
-to run it, see [the GitLabSOS documentation](https://gitlab.com/gitlab-com/support/toolbox/gitlabsos/#gitlabsos).
-
-NOTE: **Note:**
-GitLab Support likes to use this custom-made tool.
-
### Briefly tail the main logs
-If the bug or error is readily reproducible bug or error, save the main GitLab logs
+If the bug or error is readily reproducible, save the main GitLab logs
[to a file](troubleshooting/linux_cheat_sheet.md#files--dirs) while reproducing the
problem once or more times:
@@ -989,6 +975,16 @@ sudo gitlab-ctl tail | tee /tmp/<case-ID-and-keywords>.log
Conclude the log gathering with <kbd>Ctrl</kbd> + <kbd>C</kbd>.
+### GitLabSOS
+
+If performance degradations or cascading errors occur that can't readily be attributed to one
+of the previously listed GitLab components, [GitLabSOS](https://gitlab.com/gitlab-com/support/toolbox/gitlabsos/)
+can provide a perspective spanning all of Omnibus GitLab. For more details and instructions
+to run it, see [the GitLabSOS documentation](https://gitlab.com/gitlab-com/support/toolbox/gitlabsos/#gitlabsos).
+
+NOTE: **Note:**
+GitLab Support likes to use this custom-made tool.
+
### Fast-stats
[Fast-stats](https://gitlab.com/gitlab-com/support/toolbox/fast-stats) is a tool
diff --git a/doc/administration/merge_request_diffs.md b/doc/administration/merge_request_diffs.md
index 3f4cd6e2751..3c093d44780 100644
--- a/doc/administration/merge_request_diffs.md
+++ b/doc/administration/merge_request_diffs.md
@@ -17,12 +17,11 @@ By default, merge request diffs are stored in the database, in a table named
`merge_request_diff_files`. Larger installations may find this table grows too
large, in which case, switching to external storage is recommended.
-## Using external storage
-
Merge request diffs can be stored on disk, or in object storage. In general, it
-is better to store the diffs in the database than on disk.
+is better to store the diffs in the database than on disk. A compromise is available
+that only [stores outdated diffs](#alternative-in-database-storage) outside of database.
-To enable external storage of merge request diffs, follow the instructions below.
+## Using external storage
**In Omnibus installations:**
@@ -68,16 +67,40 @@ To enable external storage of merge request diffs, follow the instructions below
## Using object storage
-CAUTION: **WARNING:**
- Currently migrating to object storage is **non-reversible**
+CAUTION: **Warning:**
+Currently migrating to object storage is **non-reversible**
Instead of storing the external diffs on disk, we recommended the use of an object
store like AWS S3 instead. This configuration relies on valid AWS credentials to
be configured already.
+**In Omnibus installations:**
+
+1. Edit `/etc/gitlab/gitlab.rb` and add the following line:
+
+ ```ruby
+ gitlab_rails['external_diffs_enabled'] = true
+ ```
+
+1. Set [object storage settings](#object-storage-settings).
+1. Save the file and [reconfigure GitLab](restart_gitlab.md#omnibus-gitlab-reconfigure) for the changes to take effect.
+
+**In installations from source:**
+
+1. Edit `/home/git/gitlab/config/gitlab.yml` and add or amend the following
+ lines:
+
+ ```yaml
+ external_diffs:
+ enabled: true
+ ```
+
+1. Set [object storage settings](#object-storage-settings).
+1. Save the file and [restart GitLab](restart_gitlab.md#installations-from-source) for the changes to take effect.
+
[Read more about using object storage with GitLab](object_storage.md).
-## Object Storage Settings
+### Object Storage Settings
NOTE: **Note:**
In GitLab 13.2 and later, we recommend using the
@@ -92,12 +115,12 @@ then `object_store:`. On Omnibus installations, they are prefixed by
|---------|-------------|---------|
| `enabled` | Enable/disable object storage | `false` |
| `remote_directory` | The bucket name where external diffs will be stored| |
-| `direct_upload` | Set to true to enable direct upload of external diffs without the need of local shared storage. Option may be removed once we decide to support only single storage for all files. | `false` |
-| `background_upload` | Set to false to disable automatic upload. Option may be removed once upload is direct to S3 | `true` |
-| `proxy_download` | Set to true to enable proxying all files served. Option allows to reduce egress traffic as this allows clients to download directly from remote storage instead of proxying all data | `false` |
+| `direct_upload` | Set to `true` to enable direct upload of external diffs without the need of local shared storage. Option may be removed once we decide to support only single storage for all files. | `false` |
+| `background_upload` | Set to `false` to disable automatic upload. Option may be removed once upload is direct to S3 | `true` |
+| `proxy_download` | Set to `true` to enable proxying all files served. Option allows to reduce egress traffic as this allows clients to download directly from remote storage instead of proxying all data | `false` |
| `connection` | Various connection options described below | |
-### S3 compatible connection settings
+#### S3 compatible connection settings
See [the available connection settings for different providers](object_storage.md#connection-settings).
diff --git a/doc/administration/monitoring/github_imports.md b/doc/administration/monitoring/github_imports.md
index 0d79684c951..64f45001438 100644
--- a/doc/administration/monitoring/github_imports.md
+++ b/doc/administration/monitoring/github_imports.md
@@ -1,6 +1,6 @@
---
stage: Monitor
-group: APM
+group: Health
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/#designated-technical-writers
---
diff --git a/doc/administration/monitoring/gitlab_self_monitoring_project/index.md b/doc/administration/monitoring/gitlab_self_monitoring_project/index.md
index efe31997b25..fcaf9aaaaee 100644
--- a/doc/administration/monitoring/gitlab_self_monitoring_project/index.md
+++ b/doc/administration/monitoring/gitlab_self_monitoring_project/index.md
@@ -1,6 +1,6 @@
---
stage: Monitor
-group: APM
+group: Health
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/#designated-technical-writers
---
@@ -9,17 +9,18 @@ info: To determine the technical writer assigned to the Stage/Group associated w
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/32351) in GitLab 12.7, behind a disabled feature flag (`self_monitoring_project`).
> - The feature flag was removed and the Self Monitoring Project was [made generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/198511) in GitLab 12.8.
-GitLab has been adding the ability for administrators to see insights into the health of
-their GitLab instance. In order to surface this experience in a native way, similar to how
-you would interact with an application deployed via GitLab, a base project called
-"GitLab self monitoring" with
-[internal visibility](../../../public_access/public_access.md#internal-projects) will be
-added under a group called "GitLab Instance Administrators" specifically created for
-visualizing and configuring the monitoring of your GitLab instance.
+GitLab has been adding the ability for administrators to see insights into the
+health of their GitLab instance. To surface this experience in a native way
+(similar to how you would interact with an application deployed using GitLab),
+a base project called "GitLab self monitoring" with
+[internal visibility](../../../public_access/public_access.md#internal-projects)
+will be added under a group called "GitLab Instance Administrators"
+specifically created for visualizing and configuring the monitoring of your
+GitLab instance.
-All administrators at the time of creation of the project and group will be added
-as maintainers of the group and project, and as an admin, you'll be able to add new
-members to the group in order to give them maintainer access to the project.
+All administrators at the time of creation of the project and group will be
+added as maintainers of the group and project, and as an admin, you'll be able
+to add new members to the group to give them maintainer access to the project.
This project is used to self monitor your GitLab instance. The metrics dashboard
of the project shows some basic resource usage charts, such as CPU and memory usage
@@ -74,7 +75,8 @@ you should
## Taking action on Prometheus alerts **(ULTIMATE)**
You can [add a webhook](../../../operations/metrics/alerts.md#external-prometheus-instances)
-to the Prometheus configuration in order for GitLab to receive notifications of any alerts.
+to the Prometheus configuration for GitLab to receive notifications of any
+alerts.
Once the webhook is setup, you can
[take action on incoming alerts](../../../operations/metrics/alerts.md#trigger-actions-from-alerts).
diff --git a/doc/administration/monitoring/index.md b/doc/administration/monitoring/index.md
index a54c25450c6..fbd4c1aa3dd 100644
--- a/doc/administration/monitoring/index.md
+++ b/doc/administration/monitoring/index.md
@@ -1,6 +1,6 @@
---
stage: Monitor
-group: APM
+group: Health
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/#designated-technical-writers
---
diff --git a/doc/administration/monitoring/ip_whitelist.md b/doc/administration/monitoring/ip_whitelist.md
index 862a9368be8..480a4ea3598 100644
--- a/doc/administration/monitoring/ip_whitelist.md
+++ b/doc/administration/monitoring/ip_whitelist.md
@@ -1,6 +1,6 @@
---
stage: Monitor
-group: APM
+group: Health
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/#designated-technical-writers
---
diff --git a/doc/administration/monitoring/performance/gitlab_configuration.md b/doc/administration/monitoring/performance/gitlab_configuration.md
index d09dabab40d..6677eb73664 100644
--- a/doc/administration/monitoring/performance/gitlab_configuration.md
+++ b/doc/administration/monitoring/performance/gitlab_configuration.md
@@ -1,6 +1,6 @@
---
stage: Monitor
-group: APM
+group: Health
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/#designated-technical-writers
---
diff --git a/doc/administration/monitoring/performance/grafana_configuration.md b/doc/administration/monitoring/performance/grafana_configuration.md
index 136a2749e80..77ed5d442e6 100644
--- a/doc/administration/monitoring/performance/grafana_configuration.md
+++ b/doc/administration/monitoring/performance/grafana_configuration.md
@@ -1,6 +1,6 @@
---
stage: Monitor
-group: APM
+group: Health
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/#designated-technical-writers
---
@@ -17,7 +17,6 @@ or Grafana supplies package repositories (Yum/Apt) for easy installation.
See [Grafana installation documentation](https://grafana.com/docs/grafana/latest/installation/)
for detailed steps.
-NOTE: **Note:**
Before starting Grafana for the first time, set the admin user
and password in `/etc/grafana/grafana.ini`. If you don't, the default password
is `admin`.
@@ -50,7 +49,6 @@ JSON file individually:
1. After the dashboard is imported, click the **Save dashboard** icon in the top bar:
![Grafana save icon](img/grafana_save_icon.png)
- NOTE: **Note:**
If you don't save the dashboard after importing it, the dashboard is removed
when you navigate away from the page.
diff --git a/doc/administration/monitoring/performance/img/performance_bar.png b/doc/administration/monitoring/performance/img/performance_bar.png
index be06e0b2f94..380e2060b24 100644
--- a/doc/administration/monitoring/performance/img/performance_bar.png
+++ b/doc/administration/monitoring/performance/img/performance_bar.png
Binary files differ
diff --git a/doc/administration/monitoring/performance/img/performance_bar_sql_queries.png b/doc/administration/monitoring/performance/img/performance_bar_sql_queries.png
index 6b571f4e85c..ef74e0a3b6e 100644
--- a/doc/administration/monitoring/performance/img/performance_bar_sql_queries.png
+++ b/doc/administration/monitoring/performance/img/performance_bar_sql_queries.png
Binary files differ
diff --git a/doc/administration/monitoring/performance/index.md b/doc/administration/monitoring/performance/index.md
index 6f22327e499..68b89b837ac 100644
--- a/doc/administration/monitoring/performance/index.md
+++ b/doc/administration/monitoring/performance/index.md
@@ -1,6 +1,6 @@
---
stage: Monitor
-group: APM
+group: Health
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/#designated-technical-writers
---
@@ -11,7 +11,7 @@ GitLab comes with its own application performance measuring system as of GitLab
Community and Enterprise editions.
Apart from this introduction, you are advised to read through the following
-documents in order to understand and properly configure GitLab Performance Monitoring:
+documents to understand and properly configure GitLab Performance Monitoring:
- [GitLab Configuration](gitlab_configuration.md)
- [Prometheus documentation](../prometheus/index.md)
diff --git a/doc/administration/monitoring/performance/performance_bar.md b/doc/administration/monitoring/performance/performance_bar.md
index e247ec3708c..45dc4730cab 100644
--- a/doc/administration/monitoring/performance/performance_bar.md
+++ b/doc/administration/monitoring/performance/performance_bar.md
@@ -1,6 +1,6 @@
---
stage: Monitor
-group: APM
+group: Health
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/#designated-technical-writers
---
@@ -15,7 +15,7 @@ From left to right, it displays:
- **Current Host**: the current host serving the page.
- **Database queries**: the time taken (in milliseconds) and the total number
- of database queries, displayed in the format `00ms / 00pg`. Click to display
+ of database queries, displayed in the format `00ms / 00 (00 cached) pg`. Click to display
a modal window with more details:
![SQL profiling using the Performance Bar](img/performance_bar_sql_queries.png)
- **Gitaly calls**: the time taken (in milliseconds) and the total number of
diff --git a/doc/administration/monitoring/performance/request_profiling.md b/doc/administration/monitoring/performance/request_profiling.md
index 5746b95eb44..6e03404fd26 100644
--- a/doc/administration/monitoring/performance/request_profiling.md
+++ b/doc/administration/monitoring/performance/request_profiling.md
@@ -1,6 +1,6 @@
---
stage: Monitor
-group: APM
+group: Health
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/#designated-technical-writers
---
@@ -25,7 +25,6 @@ To profile a request:
curl --header 'X-Profile-Token: <token>' --header 'X-Profile-Mode: <mode>' "https://gitlab.example.com/group/project"
```
- NOTE: **Note:**
Profiled requests can take longer than usual.
After the request completes, you can view the profiling output from the
diff --git a/doc/administration/monitoring/prometheus/gitlab_exporter.md b/doc/administration/monitoring/prometheus/gitlab_exporter.md
index 686ed14ba42..971dafb4ba2 100644
--- a/doc/administration/monitoring/prometheus/gitlab_exporter.md
+++ b/doc/administration/monitoring/prometheus/gitlab_exporter.md
@@ -1,6 +1,6 @@
---
stage: Monitor
-group: APM
+group: Health
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/#designated-technical-writers
---
diff --git a/doc/administration/monitoring/prometheus/gitlab_metrics.md b/doc/administration/monitoring/prometheus/gitlab_metrics.md
index ae31a3db023..adb1f719f3c 100644
--- a/doc/administration/monitoring/prometheus/gitlab_metrics.md
+++ b/doc/administration/monitoring/prometheus/gitlab_metrics.md
@@ -1,6 +1,6 @@
---
stage: Monitor
-group: APM
+group: Health
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/#designated-technical-writers
---
@@ -91,8 +91,8 @@ The following metrics are available:
| `gitlab_transaction_rails_queue_duration_total` | Counter | 9.4 | Measures latency between GitLab Workhorse forwarding a request to Rails | `controller`, `action` |
| `gitlab_transaction_view_duration_total` | Counter | 9.4 | Duration for views | `controller`, `action`, `view` |
| `gitlab_view_rendering_duration_seconds` | Histogram | 10.2 | Duration for views (histogram) | `controller`, `action`, `view` |
-| `http_requests_total` | Counter | 9.4 | Rack request count | `method` |
-| `http_request_duration_seconds` | Histogram | 9.4 | HTTP response time from rack middleware | `method`, `status` |
+| `http_requests_total` | Counter | 9.4 | Rack request count | `method`, `status` |
+| `http_request_duration_seconds` | Histogram | 9.4 | HTTP response time from rack middleware | `method` |
| `gitlab_transaction_db_count_total` | Counter | 13.1 | Counter for total number of SQL calls | `controller`, `action` |
| `gitlab_transaction_db_write_count_total` | Counter | 13.1 | Counter for total number of write SQL calls | `controller`, `action` |
| `gitlab_transaction_db_cached_count_total` | Counter | 13.1 | Counter for total number of cached SQL calls | `controller`, `action` |
@@ -113,6 +113,8 @@ The following metrics are available:
| `action_cable_pool_largest_size` | Gauge | 13.4 | Largest number of worker threads observed so far in ActionCable thread pool | `server_mode` |
| `action_cable_pool_pending_tasks` | Gauge | 13.4 | Number of tasks waiting to be executed in ActionCable thread pool | `server_mode` |
| `action_cable_pool_tasks_total` | Gauge | 13.4 | Total number of tasks executed in ActionCable thread pool | `server_mode` |
+| `gitlab_issuable_fast_count_by_state_total` | Counter | 13.5 | Total number of row count operations on issue/merge request list pages | |
+| `gitlab_issuable_fast_count_by_state_failures_total` | Counter | 13.5 | Number of soft-failed row count operations on issue/merge request list pages | |
## Metrics controlled by a feature flag
@@ -122,6 +124,8 @@ The following metrics can be controlled by feature flags:
|:---------------------------------------------------------------|:-------------------------------------------------------------------|
| `gitlab_method_call_duration_seconds` | `prometheus_metrics_method_instrumentation` |
| `gitlab_view_rendering_duration_seconds` | `prometheus_metrics_view_instrumentation` |
+| `gitlab_issuable_fast_count_by_state_total` | `soft_fail_count_by_state` |
+| `gitlab_issuable_fast_count_by_state_failures_total` | `soft_fail_count_by_state` |
## Sidekiq metrics
@@ -184,12 +188,12 @@ configuration option in `gitlab.yml`. These metrics are served from the
| `geo_package_files_synced` | Gauge | 13.3 | Number of syncable package files synced on secondary | `url` |
| `geo_package_files_failed` | Gauge | 13.3 | Number of syncable package files failed to sync on secondary | `url` |
| `geo_package_files_registry` | Gauge | 13.3 | Number of package files in the registry | `url` |
-| `geo_terraform_states` | Gauge | 13.3 | Number of terraform states on primary | `url` |
-| `geo_terraform_states_checksummed` | Gauge | 13.3 | Number of terraform states checksummed on primary | `url` |
-| `geo_terraform_states_checksum_failed` | Gauge | 13.3 | Number of terraform states failed to calculate the checksum on primary | `url` |
-| `geo_terraform_states_synced` | Gauge | 13.3 | Number of syncable terraform states synced on secondary | `url` |
-| `geo_terraform_states_failed` | Gauge | 13.3 | Number of syncable terraform states failed to sync on secondary | `url` |
-| `geo_terraform_states_registry` | Gauge | 13.3 | Number of terraform states in the registry | `url` |
+| `geo_terraform_state_versions` | Gauge | 13.5 | Number of terraform state versions on primary | `url` |
+| `geo_terraform_state_versions_checksummed` | Gauge | 13.5 | Number of terraform state versions checksummed on primary | `url` |
+| `geo_terraform_state_versions_checksum_failed` | Gauge | 13.5 | Number of terraform state versions failed to calculate the checksum on primary | `url` |
+| `geo_terraform_state_versions_synced` | Gauge | 13.5 | Number of syncable terraform state versions synced on secondary | `url` |
+| `geo_terraform_state_versions_failed` | Gauge | 13.5 | Number of syncable terraform state versions failed to sync on secondary | `url` |
+| `geo_terraform_state_versions_registry` | Gauge | 13.5 | Number of terraform state versions in the registry | `url` |
| `global_search_bulk_cron_queue_size` | Gauge | 12.10 | Number of database records waiting to be synchronized to Elasticsearch | |
| `global_search_awaiting_indexing_queue_size` | Gauge | 13.2 | Number of database updates waiting to be synchronized to Elasticsearch while indexing is paused | |
| `geo_merge_request_diffs` | Gauge | 13.4 | Number of merge request diffs on primary | `url` |
@@ -204,6 +208,9 @@ configuration option in `gitlab.yml`. These metrics are served from the
| `geo_snippet_repositories_synced` | Gauge | 13.4 | Number of syncable snippets synced on secondary | `url` |
| `geo_snippet_repositories_failed` | Gauge | 13.4 | Number of syncable snippets failed on secondary | `url` |
| `geo_snippet_repositories_registry` | Gauge | 13.4 | Number of syncable snippets in the registry | `url` |
+| `limited_capacity_worker_running_jobs` | Gauge | 13.5 | Number of running jobs | `worker` |
+| `limited_capacity_worker_max_running_jobs` | Gauge | 13.5 | Maximum number of running jobs | `worker` |
+| `limited_capacity_worker_remaining_work_count` | Gauge | 13.5 | Number of jobs waiting to be enqueued | `worker` |
## Database load balancing metrics **(PREMIUM ONLY)**
diff --git a/doc/administration/monitoring/prometheus/index.md b/doc/administration/monitoring/prometheus/index.md
index 7d93e9797be..63231996dcc 100644
--- a/doc/administration/monitoring/prometheus/index.md
+++ b/doc/administration/monitoring/prometheus/index.md
@@ -1,6 +1,6 @@
---
stage: Monitor
-group: APM
+group: Health
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/#designated-technical-writers
---
@@ -32,7 +32,7 @@ dashboard tool like [Grafana](https://grafana.com).
## Configuring Prometheus
NOTE: **Note:**
-For installations from source, you'll have to install and configure it yourself.
+For installations from source, you must install and configure it yourself.
Prometheus and its exporters are on by default, starting with GitLab 9.0.
Prometheus will run as the `gitlab-prometheus` user and listen on
@@ -60,9 +60,9 @@ it's not recommended to change the port Prometheus listens
on, as this might affect or conflict with other services running on the GitLab
server. Proceed at your own risk.
-In order to access Prometheus from outside the GitLab server you will need to
-set a FQDN or IP in `prometheus['listen_address']`.
-To change the address/port that Prometheus listens on:
+To access Prometheus from outside the GitLab server, set an FQDN or IP in
+`prometheus['listen_address']`. To change the address/port that Prometheus
+listens on:
1. Edit `/etc/gitlab/gitlab.rb`
1. Add or find and uncomment the following line:
@@ -179,7 +179,7 @@ The next step is to tell all the other nodes where the monitoring node is:
take effect.
NOTE: **Note:**
-Once monitoring using Service Discovery is enabled with `consul['monitoring_service_discovery'] = true`,
+After monitoring using Service Discovery is enabled with `consul['monitoring_service_discovery'] = true`,
ensure that `prometheus['scrape_configs']` is not set in `/etc/gitlab/gitlab.rb`. Setting both
`consul['monitoring_service_discovery'] = true` and `prometheus['scrape_configs']` in `/etc/gitlab/gitlab.rb`
will result in errors.
@@ -312,7 +312,6 @@ To use an external Prometheus server:
You can visit `http://localhost:9090` for the dashboard that Prometheus offers by default.
-NOTE: **Note:**
If SSL has been enabled on your GitLab instance, you may not be able to access
Prometheus on the same browser as GitLab if using the same FQDN due to [HSTS](https://en.wikipedia.org/wiki/HTTP_Strict_Transport_Security). We plan to
[provide access via GitLab](https://gitlab.com/gitlab-org/multi-user-prometheus), but in the interim there are
diff --git a/doc/administration/monitoring/prometheus/node_exporter.md b/doc/administration/monitoring/prometheus/node_exporter.md
index 07f6b8b8e1e..dae1f02b196 100644
--- a/doc/administration/monitoring/prometheus/node_exporter.md
+++ b/doc/administration/monitoring/prometheus/node_exporter.md
@@ -1,6 +1,6 @@
---
stage: Monitor
-group: APM
+group: Health
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/#designated-technical-writers
---
@@ -10,7 +10,7 @@ The [node exporter](https://github.com/prometheus/node_exporter) enables you to
various machine resources such as memory, disk and CPU utilization.
NOTE: **Note:**
-For installations from source you'll have to install and configure it yourself.
+For installations from source you must install and configure it yourself.
To enable the node exporter:
diff --git a/doc/administration/monitoring/prometheus/pgbouncer_exporter.md b/doc/administration/monitoring/prometheus/pgbouncer_exporter.md
index 62d0bf684b6..4554bc06401 100644
--- a/doc/administration/monitoring/prometheus/pgbouncer_exporter.md
+++ b/doc/administration/monitoring/prometheus/pgbouncer_exporter.md
@@ -1,6 +1,6 @@
---
stage: Monitor
-group: APM
+group: Health
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/#designated-technical-writers
---
@@ -12,7 +12,7 @@ The [PgBouncer exporter](https://github.com/prometheus-community/pgbouncer_expor
you to measure various [PgBouncer](https://www.pgbouncer.org/) metrics.
NOTE: **Note:**
-For installations from source you'll have to install and configure it yourself.
+For installations from source you must install and configure it yourself.
To enable the PgBouncer exporter:
diff --git a/doc/administration/monitoring/prometheus/postgres_exporter.md b/doc/administration/monitoring/prometheus/postgres_exporter.md
index e3fff45fce3..9eb9ba3c59f 100644
--- a/doc/administration/monitoring/prometheus/postgres_exporter.md
+++ b/doc/administration/monitoring/prometheus/postgres_exporter.md
@@ -1,6 +1,6 @@
---
stage: Monitor
-group: APM
+group: Health
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/#designated-technical-writers
---
@@ -9,7 +9,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
The [PostgreSQL Server Exporter](https://github.com/wrouesnel/postgres_exporter) allows you to export various PostgreSQL metrics.
NOTE: **Note:**
-For installations from source you will have to install and configure it yourself.
+For installations from source you must install and configure it yourself.
To enable the PostgreSQL Server Exporter:
@@ -20,7 +20,6 @@ To enable the PostgreSQL Server Exporter:
postgres_exporter['enable'] = true
```
- NOTE: **Note:**
If PostgreSQL Server Exporter is configured on a separate node, make sure that the local
address is [listed in `trust_auth_cidr_addresses`](../../postgresql/replication_and_failover.md#network-information) or the
exporter will not be able to connect to the database.
diff --git a/doc/administration/monitoring/prometheus/redis_exporter.md b/doc/administration/monitoring/prometheus/redis_exporter.md
index b7c66959349..16a758c9804 100644
--- a/doc/administration/monitoring/prometheus/redis_exporter.md
+++ b/doc/administration/monitoring/prometheus/redis_exporter.md
@@ -1,6 +1,6 @@
---
stage: Monitor
-group: APM
+group: Health
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/#designated-technical-writers
---
@@ -11,7 +11,7 @@ various [Redis](https://redis.io) metrics. For more information on what is expor
[read the upstream documentation](https://github.com/oliver006/redis_exporter/blob/master/README.md#whats-exported).
NOTE: **Note:**
-For installations from source you'll have to install and configure it yourself.
+For installations from source you must install and configure it yourself.
To enable the Redis exporter:
diff --git a/doc/administration/monitoring/prometheus/registry_exporter.md b/doc/administration/monitoring/prometheus/registry_exporter.md
index 3d28b26b685..3bf4db8a665 100644
--- a/doc/administration/monitoring/prometheus/registry_exporter.md
+++ b/doc/administration/monitoring/prometheus/registry_exporter.md
@@ -1,6 +1,6 @@
---
stage: Monitor
-group: APM
+group: Health
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/#designated-technical-writers
---
diff --git a/doc/administration/nfs.md b/doc/administration/nfs.md
index b54f05ad536..fabbfb2552e 100644
--- a/doc/administration/nfs.md
+++ b/doc/administration/nfs.md
@@ -1,4 +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/engineering/ux/technical-writing/#designated-technical-writers
type: reference
---
@@ -296,6 +299,25 @@ Having multiple NFS mounts will require manually making sure the data directorie
are empty before attempting a restore. Read more about the
[restore prerequisites](../raketasks/backup_restore.md).
+## Testing NFS
+
+Once you've set up the NFS server and client, you can verify NFS is configured correctly
+by testing the following commands:
+
+```shell
+sudo mkdir /gitlab-nfs/test-dir
+sudo chown git /gitlab-nfs/test-dir
+sudo chgrp gitlab-www /gitlab-nfs/test-dir
+sudo chgrp root /gitlab-nfs/test-dir
+sudo chmod 2755 /gitlab-nfs/test-dir
+sudo -u git mkdir /gitlab-nfs/test-dir/test2
+sudo -u git chmod 2755 /gitlab-nfs/test-dir/test2
+sudo ls -lah /gitlab-nfs/test-dir/test2
+sudo -u git rm -r /gitlab-nfs/test-dir
+```
+
+Any `Operation not permitted` errors means you should investigate your NFS server export options.
+
## NFS in a Firewalled Environment
If the traffic between your NFS server and NFS client(s) is subject to port filtering
@@ -317,6 +339,28 @@ sudo ufw allow from <client_ip_address> to any port nfs
## Known issues
+### Upgrade to Gitaly Cluster or disable caching if experiencing data loss
+
+CAUTION: **Caution:**
+From GitLab 13.0, using NFS for Git repositories is deprecated. In GitLab 14.0,
+support for NFS for Git repositories is scheduled to be removed. Upgrade to
+[Gitaly Cluster](gitaly/praefect.md) as soon as possible.
+
+Customers and users have reported data loss on high-traffic repositories when using NFS for Git repositories.
+For example, we have seen [inconsistent updates after a push](https://gitlab.com/gitlab-org/gitaly/-/issues/2589). The problem may be partially mitigated by adjusting caching using the following NFS client mount options:
+
+| Setting | Description |
+| ------- | ----------- |
+| `lookupcache=positive` | Tells the NFS client to honor `positive` cache results but invalidates any `negative` cache results. Negative cache results cause problems with Git. Specifically, a `git push` can fail to register uniformly across all NFS clients. The negative cache causes the clients to 'remember' that the files did not exist previously.
+| `actimeo=0` | Sets the time to zero that the NFS client caches files and directories before requesting fresh information from a server. |
+| `noac` | Tells the NFS client not to cache file attributes and forces application writes to become synchronous so that local changes to a file become visible on the server immediately. |
+
+CAUTION: **Caution:**
+The `actimeo=0` and `noac` options both result in a significant reduction in performance, possibly leading to timeouts.
+You may be able to avoid timeouts and data loss using `actimeo=0` and `lookupcache=positive` _without_ `noac`, however
+we expect the performance reduction will still be significant. As noted above, we strongly recommend upgrading to
+[Gitaly Cluster](gitaly/praefect.md) as soon as possible.
+
### Avoid using AWS's Elastic File System (EFS)
GitLab strongly recommends against using AWS Elastic File System (EFS).
diff --git a/doc/administration/object_storage.md b/doc/administration/object_storage.md
index 39365ffe404..8b788e6d91d 100644
--- a/doc/administration/object_storage.md
+++ b/doc/administration/object_storage.md
@@ -1,4 +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/engineering/ux/technical-writing/#designated-technical-writers
type: reference
---
@@ -17,7 +20,7 @@ GitLab has been tested on a number of object storage providers:
- [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)
-- [Openstack Swift](https://docs.openstack.org/swift/latest/s3_compat.html)
+- [OpenStack Swift](https://docs.openstack.org/swift/latest/s3_compat.html)
- [Azure Blob storage](https://docs.microsoft.com/en-us/azure/storage/blobs/storage-blobs-introduction)
- On-premises hardware and appliances from various storage vendors.
- MinIO. We have [a guide to deploying this](https://docs.gitlab.com/charts/advanced/external-object-storage/minio.html) within our Helm Chart documentation.
@@ -369,7 +372,7 @@ Here are the valid connection parameters for Rackspace Cloud, provided by
| `rackspace_username` | The username of the Rackspace account with access to the container | `joe.smith` |
| `rackspace_api_key` | The API key of the Rackspace account with access to the container | `ABC123DEF456ABC123DEF456ABC123DE` |
| `rackspace_region` | The Rackspace storage region to use, a three letter code from the [list of service access endpoints](https://developer.rackspace.com/docs/cloud-files/v1/general-api-info/service-access/) | `iad` |
-| `rackspace_temp_url_key` | The private key you have set in the Rackspace API for temporary URLs. Read more [here](https://developer.rackspace.com/docs/cloud-files/v1/use-cases/public-access-to-your-cloud-files-account/#tempurl) | `ABC123DEF456ABC123DEF456ABC123DE` |
+| `rackspace_temp_url_key` | The private key you have set in the Rackspace API for [temporary URLs](https://developer.rackspace.com/docs/cloud-files/v1/use-cases/public-access-to-your-cloud-files-account/#tempurl). | `ABC123DEF456ABC123DEF456ABC123DE` |
NOTE: **Note:**
Regardless of whether the container has public access enabled or disabled, Fog will
@@ -383,7 +386,7 @@ and comparing the output of the returned headers.
The following YAML shows how the `object_store` section defines
object-specific configuration block and how the `enabled` and
-`proxy_download` flags can be overriden. The `bucket` is the only
+`proxy_download` flags can be overridden. The `bucket` is the only
required parameter within each type:
```yaml
@@ -503,13 +506,13 @@ supported by consolidated configuration form, refer to the following guides:
|Object storage type|Supported by consolidated configuration?|
|-------------------|----------------------------------------|
| [Backups](../raketasks/backup_restore.md#uploading-backups-to-a-remote-cloud-storage)|No|
-| [Job artifacts](job_artifacts.md#using-object-storage) and [incremental logging](job_logs.md#new-incremental-logging-architecture) | Yes |
+| [Job artifacts](job_artifacts.md#using-object-storage) including archived job logs | Yes |
| [LFS objects](lfs/index.md#storing-lfs-objects-in-remote-object-storage) | Yes |
| [Uploads](uploads.md#using-object-storage) | Yes |
| [Container Registry](packages/container_registry.md#use-object-storage) (optional feature) | No |
| [Merge request diffs](merge_request_diffs.md#using-object-storage) | Yes |
| [Mattermost](https://docs.mattermost.com/administration/config-settings.html#file-storage)| No |
-| [Packages](packages/index.md#using-object-storage) (optional feature) **(PREMIUM ONLY)** | Yes |
+| [Packages](packages/index.md#using-object-storage) (optional feature) | Yes |
| [Dependency Proxy](packages/dependency_proxy.md#using-object-storage) (optional feature) **(PREMIUM ONLY)** | Yes |
| [Pseudonymizer](pseudonymizer.md#configuration) (optional feature) **(ULTIMATE ONLY)** | No |
| [Autoscale runner caching](https://docs.gitlab.com/runner/configuration/autoscale.html#distributed-runners-caching) (optional for improved performance) | No |
@@ -520,12 +523,13 @@ supported by consolidated configuration form, refer to the following guides:
If you're working to [scale out](reference_architectures/index.md) your GitLab implementation,
or add fault tolerance and redundancy, you may be
looking at removing dependencies on block or network filesystems.
-See the following guides and
+See the following additional guides and
[note that Pages requires disk storage](#gitlab-pages-requires-nfs):
1. Make sure the [`git` user home directory](https://docs.gitlab.com/omnibus/settings/configuration.html#moving-the-home-directory-for-a-user) is on local disk.
1. Configure [database lookup of SSH keys](operations/fast_ssh_key_lookup.md)
to eliminate the need for a shared `authorized_keys` file.
+1. [Prevent local disk usage for job logs](job_logs.md#prevent-local-disk-usage).
## Warnings, limitations, and known issues
@@ -569,7 +573,8 @@ The dependency on disk storage also prevents Pages being deployed using the
### Incremental logging is required for CI to use object storage
If you configure GitLab to use object storage for CI logs and artifacts,
-[you must also enable incremental logging](job_artifacts.md#using-object-storage).
+you can avoid [local disk usage for job logs](job_logs.md#data-flow) by enabling
+[beta incremental logging](job_logs.md#new-incremental-logging-architecture).
### Proxy Download
@@ -685,7 +690,7 @@ in the `storage_options` configuration section:
| Setting | Description |
|-------------------------------------|-------------|
-| `server_side_encryption` | Encryption mode (AES256 or aws:kms) |
+| `server_side_encryption` | Encryption mode (`AES256` or `aws:kms`) |
| `server_side_encryption_kms_key_id` | Amazon Resource Name. Only needed when `aws:kms` is used in `server_side_encryption`. See the [Amazon documentation on using KMS encryption](https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingKMSEncryption.html) |
As with the case for default encryption, these options only work when
diff --git a/doc/administration/operations/cleaning_up_redis_sessions.md b/doc/administration/operations/cleaning_up_redis_sessions.md
index d2aec2f7c47..a94f88439f2 100644
--- a/doc/administration/operations/cleaning_up_redis_sessions.md
+++ b/doc/administration/operations/cleaning_up_redis_sessions.md
@@ -1,3 +1,9 @@
+---
+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/engineering/ux/technical-writing/#designated-technical-writers
+---
+
# Cleaning up stale Redis sessions
Since version 6.2, GitLab stores web user sessions as key-value pairs in Redis.
diff --git a/doc/administration/operations/extra_sidekiq_processes.md b/doc/administration/operations/extra_sidekiq_processes.md
index e589ecc4216..76dc9bf5510 100644
--- a/doc/administration/operations/extra_sidekiq_processes.md
+++ b/doc/administration/operations/extra_sidekiq_processes.md
@@ -1,3 +1,9 @@
+---
+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/engineering/ux/technical-writing/#designated-technical-writers
+---
+
# Run multiple Sidekiq processes **(CORE ONLY)**
GitLab allows you to start multiple Sidekiq processes.
diff --git a/doc/administration/operations/fast_ssh_key_lookup.md b/doc/administration/operations/fast_ssh_key_lookup.md
index 6cd393be330..88ef69b29f2 100644
--- a/doc/administration/operations/fast_ssh_key_lookup.md
+++ b/doc/administration/operations/fast_ssh_key_lookup.md
@@ -1,3 +1,9 @@
+---
+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/engineering/ux/technical-writing/#designated-technical-writers
+---
+
# Fast lookup of authorized SSH keys in the database
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/1631) in [GitLab Starter](https://about.gitlab.com/pricing/) 9.3.
@@ -114,7 +120,6 @@ This is a brief overview. Please refer to the above instructions for more contex
1. Enable writes to the `authorized_keys` file in Application Settings
1. Remove the `AuthorizedKeysCommand` lines from `/etc/ssh/sshd_config` or from `/assets/sshd_config` if you are using Omnibus Docker.
1. Reload `sshd`: `sudo service sshd reload`
-1. Remove the `/opt/gitlab-shell/authorized_keys` file
## Compiling a custom version of OpenSSH for CentOS 6
diff --git a/doc/administration/operations/filesystem_benchmarking.md b/doc/administration/operations/filesystem_benchmarking.md
index 64afd1b44f3..c55f253b772 100644
--- a/doc/administration/operations/filesystem_benchmarking.md
+++ b/doc/administration/operations/filesystem_benchmarking.md
@@ -1,3 +1,9 @@
+---
+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/engineering/ux/technical-writing/#designated-technical-writers
+---
+
# Filesystem Performance Benchmarking
Filesystem performance has a big impact on overall GitLab performance,
diff --git a/doc/administration/operations/index.md b/doc/administration/operations/index.md
index 45b8e5ad448..aaeb8c723d0 100644
--- a/doc/administration/operations/index.md
+++ b/doc/administration/operations/index.md
@@ -1,3 +1,9 @@
+---
+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/engineering/ux/technical-writing/#designated-technical-writers
+---
+
# Performing Operations in GitLab
Keep your GitLab instance up and running smoothly.
diff --git a/doc/administration/operations/moving_repositories.md b/doc/administration/operations/moving_repositories.md
index 4763c012538..94eea1e25b8 100644
--- a/doc/administration/operations/moving_repositories.md
+++ b/doc/administration/operations/moving_repositories.md
@@ -1,3 +1,9 @@
+---
+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/engineering/ux/technical-writing/#designated-technical-writers
+---
+
# Moving repositories managed by GitLab
Sometimes you need to move all repositories managed by GitLab to
diff --git a/doc/administration/operations/puma.md b/doc/administration/operations/puma.md
index f5b09d7a978..2d53a790428 100644
--- a/doc/administration/operations/puma.md
+++ b/doc/administration/operations/puma.md
@@ -1,3 +1,9 @@
+---
+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/engineering/ux/technical-writing/#designated-technical-writers
+---
+
# Switching to Puma
As of GitLab 12.9, [Puma](https://github.com/puma/puma) has replaced [Unicorn](https://yhbt.net/unicorn/)
diff --git a/doc/administration/operations/rails_console.md b/doc/administration/operations/rails_console.md
new file mode 100644
index 00000000000..9db9a885baf
--- /dev/null
+++ b/doc/administration/operations/rails_console.md
@@ -0,0 +1,144 @@
+# The Rails Console
+
+The [Rails console](https://guides.rubyonrails.org/command_line.html#rails-console).
+provides a way to interact with your GitLab instance from the command line.
+
+CAUTION: **Caution:**
+The Rails console interacts directly with GitLab. In many cases,
+there are no handrails to prevent you from permanently modifying, corrupting
+or destroying production data. If you would like to explore the Rails console
+with no consequences, you are strongly advised to do so in a test environment.
+
+The Rails console is for GitLab system administrators who are troubleshooting
+a problem or need to retrieve some data that can only be done through direct
+access of the GitLab application.
+
+## Starting a Rails console session
+
+**For Omnibus installations**
+
+```shell
+sudo gitlab-rails console
+```
+
+**For installations from source**
+
+```shell
+sudo -u git -H bundle exec rails console -e production
+```
+
+**For Kubernetes deployments**
+
+The console is in the task-runner pod. Refer to our [Kubernetes cheat sheet](../troubleshooting/kubernetes_cheat_sheet.md#gitlab-specific-kubernetes-information) for details.
+
+To exit the console, type: `quit`.
+
+## Output Rails console session history
+
+Enter the following command on the rails console to display
+your command history.
+
+```ruby
+puts Readline::HISTORY.to_a
+```
+
+You can then copy it to your clipboard and save for future reference.
+
+## Using the Rails Runner
+
+If you need to run some Ruby code in the context of your GitLab production
+environment, you can do so using the [Rails Runner](https://guides.rubyonrails.org/command_line.html#rails-runner).
+When executing a script file, the script must be accessible by the `git` user.
+
+When the command or script completes, the Rails Runner process finishes.
+It is useful for running within other scripts or cron jobs for example.
+
+**For Omnibus installations**
+
+```shell
+sudo gitlab-rails runner "RAILS_COMMAND"
+
+# Example with a two-line Ruby script
+sudo gitlab-rails runner "user = User.first; puts user.username"
+
+# Example with a ruby script file (make sure to use the full path)
+sudo gitlab-rails runner /path/to/script.rb
+```
+
+**For installations from source**
+
+```shell
+sudo -u git -H bundle exec rails runner -e production "RAILS_COMMAND"
+
+# Example with a two-line Ruby script
+sudo -u git -H bundle exec rails runner -e production "user = User.first; puts user.username"
+
+# Example with a ruby script file (make sure to use the full path)
+sudo -u git -H bundle exec rails runner -e production /path/to/script.rb
+```
+
+Rails Runner does not produce the same output as the console.
+
+If you set a variable on the console, the console will generate useful debug output
+such as the variable contents or properties of referenced entity:
+
+```ruby
+irb(main):001:0> user = User.first
+=> #<User id:1 @root>
+```
+
+Rails Runner does not do this: you have to be explicit about generating
+output:
+
+```shell
+$ sudo gitlab-rails runner "user = User.first"
+$ sudo gitlab-rails runner "user = User.first; puts user.username ; puts user.id"
+root
+1
+```
+
+Some basic knowledge of Ruby will be very useful. Try [this
+30-minute tutorial](https://try.ruby-lang.org/) for a quick introduction.
+Rails experience is helpful but not essential.
+
+### Troubleshooting Rails Runner
+
+The `gitlab-rails` command executes Rails Runner using a non-root account and group, by default: `git:git`.
+
+If the non-root account cannot find the Ruby script filename passed to `gitlab-rails runner`
+you may get a syntax error, not an error that the file couldn't be accessed.
+
+A common reason for this is that the script has been put in the root account's home directory.
+
+`runner` tries to parse the path and file parameter as Ruby code.
+
+For example:
+
+```plaintext
+[root ~]# echo 'puts "hello world"' > ./helloworld.rb
+[root ~]# sudo gitlab-rails runner ./helloworld.rb
+Please specify a valid ruby command or the path of a script to run.
+Run 'rails runner -h' for help.
+
+/opt/gitlab/..../runner_command.rb:45: syntax error, unexpected '.'
+./helloworld.rb
+^
+[root ~]# sudo gitlab-rails runner /root/helloworld.rb
+Please specify a valid ruby command or the path of a script to run.
+Run 'rails runner -h' for help.
+
+/opt/gitlab/..../runner_command.rb:45: unknown regexp options - hllwrld
+[root ~]# mv ~/helloworld.rb /tmp
+[root ~]# sudo gitlab-rails runner /tmp/helloworld.rb
+hello world
+```
+
+A meaningful error should be generated if the directory can be accessed, but the file cannot:
+
+```plaintext
+[root ~]# chmod 400 /tmp/helloworld.rb
+[root ~]# sudo gitlab-rails runner /tmp/helloworld.rb
+Traceback (most recent call last):
+ [traceback removed]
+/opt/gitlab/..../runner_command.rb:42:in `load': cannot load such file -- /tmp/helloworld.rb (LoadError)
+```
diff --git a/doc/administration/operations/sidekiq_memory_killer.md b/doc/administration/operations/sidekiq_memory_killer.md
index d1ff98a0079..d99468411e3 100644
--- a/doc/administration/operations/sidekiq_memory_killer.md
+++ b/doc/administration/operations/sidekiq_memory_killer.md
@@ -1,3 +1,9 @@
+---
+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/engineering/ux/technical-writing/#designated-technical-writers
+---
+
# Sidekiq MemoryKiller
The GitLab Rails application code suffers from memory leaks. For web requests
@@ -8,7 +14,7 @@ MemoryKiller applies the same approach to the Sidekiq processes used by GitLab
to process background jobs.
Unlike puma-worker-killer, which is enabled by default for all GitLab
-installations since GitLab 13.0, the Sidekiq MemoryKiller is enabled by default
+installations of GitLab 13.0 and later, the Sidekiq MemoryKiller is enabled by default
_only_ for Omnibus packages. The reason for this is that the MemoryKiller
relies on runit to restart Sidekiq after a memory-induced shutdown and GitLab
installations from source do not all use runit or an equivalent.
diff --git a/doc/administration/operations/ssh_certificates.md b/doc/administration/operations/ssh_certificates.md
index c81eb15955d..7cbd8c74f90 100644
--- a/doc/administration/operations/ssh_certificates.md
+++ b/doc/administration/operations/ssh_certificates.md
@@ -1,3 +1,9 @@
+---
+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/engineering/ux/technical-writing/#designated-technical-writers
+---
+
# User lookup via OpenSSH's AuthorizedPrincipalsCommand
> [Available in](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/19911) GitLab
diff --git a/doc/administration/operations/unicorn.md b/doc/administration/operations/unicorn.md
index a1593c3a6c3..80dafde14aa 100644
--- a/doc/administration/operations/unicorn.md
+++ b/doc/administration/operations/unicorn.md
@@ -1,3 +1,9 @@
+---
+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/engineering/ux/technical-writing/#designated-technical-writers
+---
+
# Understanding Unicorn and unicorn-worker-killer
NOTE: **Note:**
diff --git a/doc/administration/packages/container_registry.md b/doc/administration/packages/container_registry.md
index 74af5c8149b..56b7f01e1ad 100644
--- a/doc/administration/packages/container_registry.md
+++ b/doc/administration/packages/container_registry.md
@@ -10,15 +10,13 @@ info: To determine the technical writer assigned to the Stage/Group associated w
> - Container Registry manifest `v1` support was added in GitLab 8.9 to support
> Docker versions earlier than 1.10.
-NOTE: **Note:**
-This document is the administrator's guide. To learn how to use GitLab Container
-Registry, see the [user documentation](../../user/packages/container_registry/index.md).
+With the GitLab Container Registry, every project can have its
+own space to store Docker images.
-With the Container Registry integrated into GitLab, every project can have its
-own space to store its Docker images.
+Read more about the Docker Registry in [the Docker documentation](https://docs.docker.com/registry/introduction/).
-You can read more about the Docker Registry at
-<https://docs.docker.com/registry/introduction/>.
+This document is the administrator's guide. To learn how to use the GitLab Container
+Registry, see the [user documentation](../../user/packages/container_registry/index.md).
## Enable the Container Registry
@@ -37,9 +35,8 @@ Otherwise, the Container Registry is not enabled. To enable it:
- You can configure it for your [GitLab domain](#configure-container-registry-under-an-existing-gitlab-domain), or
- You can configure it for [a different domain](#configure-container-registry-under-its-own-domain).
-NOTE: **Note:**
The Container Registry works under HTTPS by default. You can use HTTP
-but it's not recommended and is out of the scope of this document.
+but it's not recommended and is beyond the scope of this document.
Read the [insecure Registry documentation](https://docs.docker.com/registry/insecure/)
if you want to implement this.
@@ -47,12 +44,12 @@ if you want to implement this.
If you have installed GitLab from source:
-1. You will have to [install Registry](https://docs.docker.com/registry/deploying/) by yourself.
-1. After the installation is complete, you will have to configure the Registry's
- settings in `gitlab.yml` in order to enable it.
-1. Use the sample NGINX configuration file that is found under
+1. You must [install Registry](https://docs.docker.com/registry/deploying/) by yourself.
+1. After the installation is complete, to enable it, you must configure the Registry's
+ settings in `gitlab.yml`.
+1. Use the sample NGINX configuration file from under
[`lib/support/nginx/registry-ssl`](https://gitlab.com/gitlab-org/gitlab/blob/master/lib/support/nginx/registry-ssl) and edit it to match the
- `host`, `port` and TLS certs paths.
+ `host`, `port`, and TLS certificate paths.
The contents of `gitlab.yml` are:
@@ -67,21 +64,20 @@ registry:
issuer: gitlab-issuer
```
-where:
+Where:
| Parameter | Description |
| --------- | ----------- |
| `enabled` | `true` or `false`. Enables the Registry in GitLab. By default this is `false`. |
-| `host` | The host URL under which the Registry will run and the users will be able to use. |
-| `port` | The port under which the external Registry domain will listen on. |
-| `api_url` | The internal API URL under which the Registry is exposed to. It defaults to `http://localhost:5000`. |
+| `host` | The host URL under which the Registry runs and users can use. |
+| `port` | The port the external Registry domain listens on. |
+| `api_url` | The internal API URL under which the Registry is exposed. It defaults to `http://localhost:5000`. |
| `key` | The private key location that is a pair of Registry's `rootcertbundle`. Read the [token auth configuration documentation](https://docs.docker.com/registry/configuration/#token). |
| `path` | This should be the same directory like specified in Registry's `rootdirectory`. Read the [storage configuration documentation](https://docs.docker.com/registry/configuration/#storage). This path needs to be readable by the GitLab user, the web-server user and the Registry user. Read more in [#configure-storage-for-the-container-registry](#configure-storage-for-the-container-registry). |
| `issuer` | This should be the same value as configured in Registry's `issuer`. Read the [token auth configuration documentation](https://docs.docker.com/registry/configuration/#token). |
-NOTE: **Note:**
A Registry init file is not shipped with GitLab if you install it from source.
-Hence, [restarting GitLab](../restart_gitlab.md#installations-from-source) will not restart the Registry should
+Hence, [restarting GitLab](../restart_gitlab.md#installations-from-source) does not restart the Registry should
you modify its settings. Read the upstream documentation on how to achieve that.
At the **absolute** minimum, make sure your [Registry configuration](https://docs.docker.com/registry/configuration/#auth)
@@ -98,37 +94,34 @@ auth:
```
CAUTION: **Caution:**
-If `auth` is not set up, users will be able to pull Docker images without authentication.
+If `auth` is not set up, users can pull Docker images without authentication.
## Container Registry domain configuration
There are two ways you can configure the Registry's external domain. Either:
-- [Use the existing GitLab domain](#configure-container-registry-under-an-existing-gitlab-domain) where in that case
- the Registry will have to listen on a port and reuse GitLab's TLS certificate,
+- [Use the existing GitLab domain](#configure-container-registry-under-an-existing-gitlab-domain).
+ The Registry listens on a port and reuses GitLab's TLS certificate.
- [Use a completely separate domain](#configure-container-registry-under-its-own-domain) with a new TLS certificate
for that domain.
-Since the container Registry requires a TLS certificate, in the end it all boils
-down to how easy or pricey it is to get a new one.
+Because the Container Registry requires a TLS certificate, cost may be a factor.
-Please take this into consideration before configuring the Container Registry
+Take this into consideration before configuring the Container Registry
for the first time.
### Configure Container Registry under an existing GitLab domain
If the Registry is configured to use the existing GitLab domain, you can
-expose the Registry on a port so that you can reuse the existing GitLab TLS
+expose the Registry on a port. This way you can reuse the existing GitLab TLS
certificate.
-Assuming that the GitLab domain is `https://gitlab.example.com` and the port the
-Registry is exposed to the outside world is `5050`, here is what you need to set
+If the GitLab domain is `https://gitlab.example.com` and the port to the outside world is `5050`, here is what you need to set
in `gitlab.rb` or `gitlab.yml` if you are using Omnibus GitLab or installed
GitLab from source respectively.
-NOTE: **Note:**
-Be careful to choose a port different than the one that Registry listens to (`5000` by default),
-otherwise you will run into conflicts.
+Ensure you choose a port different than the one that Registry listens to (`5000` by default),
+otherwise conflicts occur.
**Omnibus GitLab installations**
@@ -139,7 +132,7 @@ otherwise you will run into conflicts.
registry_external_url 'https://gitlab.example.com:5050'
```
- Note how the `registry_external_url` is listening on HTTPS under the
+ The `registry_external_url` is listening on HTTPS under the
existing GitLab URL, but on a different port.
If your TLS certificate is not in `/etc/gitlab/ssl/gitlab.example.com.crt`
@@ -160,7 +153,6 @@ otherwise you will run into conflicts.
openssl s_client -showcerts -servername gitlab.example.com -connect gitlab.example.com:5050 > cacert.pem
```
-NOTE: **Note:**
If your certificate provider provides the CA Bundle certificates, append them to the TLS certificate file.
**Installations from source**
@@ -187,12 +179,11 @@ docker login gitlab.example.com:5050
### Configure Container Registry under its own domain
-If the Registry is configured to use its own domain, you will need a TLS
-certificate for that specific domain (e.g., `registry.example.com`) or maybe
+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 (e.g., `registry.gitlab.example.com`).
+domain, for example, `registry.gitlab.example.com`.
-NOTE: **Note:**
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#host-services).
@@ -210,19 +201,19 @@ Let's assume that you want the container Registry to be accessible at
chmod 600 /etc/gitlab/ssl/registry.gitlab.example.com.*
```
-1. Once the TLS certificate is in place, edit `/etc/gitlab/gitlab.rb` with:
+1. After the TLS certificate is in place, edit `/etc/gitlab/gitlab.rb` with:
```ruby
registry_external_url 'https://registry.gitlab.example.com'
```
- Note how the `registry_external_url` is listening on HTTPS.
+ The `registry_external_url` is listening on HTTPS.
1. Save the file and [reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure) for the changes to take effect.
-If you have a [wildcard certificate](https://en.wikipedia.org/wiki/Wildcard_certificate), you need to specify the path to the
-certificate in addition to the URL, in this case `/etc/gitlab/gitlab.rb` will
-look like:
+If you have a [wildcard certificate](https://en.wikipedia.org/wiki/Wildcard_certificate), you must specify the path to the
+certificate in addition to the URL, in this case `/etc/gitlab/gitlab.rb`
+looks like:
```ruby
registry_nginx['ssl_certificate'] = "/etc/gitlab/ssl/certificate.pem"
@@ -252,9 +243,8 @@ docker login registry.gitlab.example.com
## Disable Container Registry site-wide
-NOTE: **Note:**
-Disabling the Registry in the Rails GitLab application as set by the following
-steps, will not remove any existing Docker images. This is handled by the
+When you disable the Registry by following these steps, you do not
+remove any existing Docker images. This is handled by the
Registry application itself.
**Omnibus GitLab**
@@ -281,7 +271,7 @@ Registry application itself.
## Disable Container Registry for new projects site-wide
-If the Container Registry is enabled, then it will be available on all new
+If the Container Registry is enabled, then it should be available on all new
projects. To disable this function and let the owners of a project to enable
the Container Registry by themselves, follow the steps below.
@@ -317,7 +307,7 @@ the Container Registry by themselves, follow the steps below.
You can configure the Container Registry to use various storage backends by
configuring a storage driver. By default the GitLab Container Registry
-is configured to use the [filesystem driver](#use-filesystem)
+is configured to use the [file system driver](#use-file-system)
configuration.
The different supported drivers are:
@@ -331,15 +321,14 @@ The different supported drivers are:
| swift | OpenStack Swift Object Storage |
| oss | Aliyun OSS |
-NOTE: **Note:**
-Although most S3 compatible services (like [MinIO](https://min.io/)) should work with the registry, we only guarantee support for AWS S3. Because we cannot assert the correctness of third-party S3 implementations, we can debug issues, but we cannot patch the registry unless an issue is reproducible against an AWS S3 bucket.
+Although most S3 compatible services (like [MinIO](https://min.io/)) should work with the Container Registry, we only guarantee support for AWS S3. Because we cannot assert the correctness of third-party S3 implementations, we can debug issues, but we cannot patch the registry unless an issue is reproducible against an AWS S3 bucket.
Read more about the individual driver's configuration options in the
[Docker Registry docs](https://docs.docker.com/registry/configuration/#storage).
-### Use filesystem
+### Use file system
-If you want to store your images on the filesystem, you can change the storage
+If you want to store your images on the file system, you can change the storage
path for the Container Registry, follow the steps below.
This path is accessible to:
@@ -347,8 +336,7 @@ This path is accessible to:
- The user running the Container Registry daemon.
- The user running GitLab.
-CAUTION: **Warning:**
-You should confirm that all GitLab, Registry and web server users
+All GitLab, Registry, and web server users must
have access to this directory.
**Omnibus GitLab installations**
@@ -387,13 +375,10 @@ driver for the Container Registry.
[Read more about using object storage with GitLab](../object_storage.md).
CAUTION: **Warning:**
-GitLab will not backup Docker images that are not stored on the
-filesystem. Remember to enable backups with your object storage provider if
+GitLab does not back up Docker images that are not stored on the
+file system. Enable backups with your object storage provider if
desired.
-NOTE: **Note:**
-`regionendpoint` is only required when configuring an S3 compatible service such as MinIO. It takes a URL such as `http://127.0.0.1:9000`.
-
**Omnibus GitLab installations**
To configure the `s3` storage driver in Omnibus:
@@ -412,14 +397,14 @@ To configure the `s3` storage driver in Omnibus:
}
```
-1. Save the file and [reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure) for the changes to take effect.
+ - `regionendpoint` is only required when configuring an S3 compatible service such as MinIO. It takes a URL such as `http://127.0.0.1:9000`.
+ - `your-s3-bucket` should be the name of a bucket that exists, and can't include subdirectories.
-NOTE: **Note:**
-`your-s3-bucket` should only be the name of a bucket that exists, and can't include subdirectories.
+1. Save the file and [reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure) for the changes to take effect.
**Installations from source**
-Configuring the storage driver is done in your registry configuration YML file created
+Configuring the storage driver is done in the registry configuration YML file created
when you [deployed your Docker registry](https://docs.docker.com/registry/deploying/).
`s3` storage driver example:
@@ -438,8 +423,7 @@ storage:
enabled: true
```
-NOTE: **Note:**
-`your-s3-bucket` should only be the name of a bucket that exists, and can't include subdirectories.
+`your-s3-bucket` should be the name of a bucket that exists, and can't include subdirectories.
#### Migrate to object storage without downtime
@@ -451,7 +435,7 @@ you can pull from the Container Registry, but you cannot push.
1. Optional: To reduce the amount of data to be migrated, run the [garbage collection tool without downtime](#performing-garbage-collection-without-downtime).
1. This example uses the `aws` CLI. If you haven't configured the
CLI before, you have to configure your credentials by running `sudo aws configure`.
- Because a non-admin user likely can't access the Container Registry folder,
+ Because a non-administrator user likely can't access the Container Registry folder,
ensure you use `sudo`. To check your credential configuration, run
[`ls`](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/s3/ls.html) to list
all buckets.
@@ -483,14 +467,14 @@ you can pull from the Container Registry, but you cannot push.
sudo aws --endpoint-url https://your-object-storage-backend.com s3 sync registry s3://mybucket --delete --dryrun
```
- After verifying the command is going to perform as expected, remove the
+ After verifying the command performs as expected, remove the
[`--dryrun`](https://docs.aws.amazon.com/cli/latest/reference/s3/sync.html)
flag and run the command.
DANGER: **Danger:**
The [`--delete`](https://docs.aws.amazon.com/cli/latest/reference/s3/sync.html)
- flag will delete files that exist in the destination but not in the source.
- Make sure not to swap the source and destination, or you will delete all data in the Registry.
+ flag deletes files that exist in the destination but not in the source.
+ If you swap the source and destination, all data in the Registry is deleted.
1. Verify all Container Registry files have been uploaded to object storage
by looking at the file count returned by these two commands:
@@ -560,15 +544,11 @@ However, this behavior is undesirable for registries used by internal hosts that
### Storage limitations
Currently, there is no storage limitation, which means a user can upload an
-infinite amount of Docker images with arbitrary sizes. This setting will be
+infinite amount of Docker images with arbitrary sizes. This setting should be
configurable in future releases.
## Change the registry's internal port
-NOTE: **Note:**
-This is not to be confused with the port that GitLab itself uses to expose
-the Registry to the world.
-
The Registry server listens on localhost at port `5000` by default,
which is the address for which the Registry server should accept connections.
In the examples below we set the Registry's port to `5001`.
@@ -589,7 +569,7 @@ In the examples below we set the Registry's port to `5001`.
[`http:addr`](https://docs.docker.com/registry/configuration/#http) value:
```yaml
- http
+ http:
addr: localhost:5001
```
@@ -603,9 +583,8 @@ on how to achieve that.
## Use an external container registry with GitLab as an auth endpoint
-NOTE: **Note:**
-In using an external container registry, some features associated with the
-container registry may be unavailable or have [inherent risks](./../../user/packages/container_registry/index.md#use-with-external-container-registries)
+If you use an external container registry, some features associated with the
+container registry may be unavailable or have [inherent risks](./../../user/packages/container_registry/index.md#use-with-external-container-registries).
**Omnibus GitLab**
@@ -619,13 +598,12 @@ You can use GitLab as an auth endpoint with an external container registry.
gitlab_rails['registry_issuer'] = "omnibus-gitlab-issuer"
```
- NOTE: **Note:**
`gitlab_rails['registry_enabled'] = true` is needed to enable GitLab's
Container Registry features and authentication endpoint. GitLab's bundled
- Container Registry service will not be started even with this enabled.
+ Container Registry service does not start, even with this enabled.
1. A certificate-key pair is required for GitLab and the external container
- registry to communicate securely. You will need to create a certificate-key
+ registry to communicate securely. You need to create a certificate-key
pair, configuring the external container registry with the public
certificate and configuring GitLab with the private key. To do that, add
the following to `/etc/gitlab/gitlab.rb`:
@@ -641,11 +619,10 @@ You can use GitLab as an auth endpoint with an external container registry.
gitlab_rails['registry_key_path'] = "/custom/path/to/registry-key.key"
```
- NOTE: **Note:**
- The file specified at `registry_key_path` gets populated with the
- content specified by `internal_key`, each time reconfigure is executed. If
- no file is specified, Omnibus GitLab will default it to
- `/var/opt/gitlab/gitlab-rails/etc/gitlab-registry.key` and will populate
+ Each time reconfigure is executed, the file specified at `registry_key_path`
+ gets populated with the content specified by `internal_key`. If
+ no file is specified, Omnibus GitLab defaults it to
+ `/var/opt/gitlab/gitlab-rails/etc/gitlab-registry.key` and populates
it.
1. To change the container registry URL displayed in the GitLab Container
@@ -686,8 +663,7 @@ response to events happening within the registry.
Read more about the Container Registry notifications configuration options in the
[Docker Registry notifications documentation](https://docs.docker.com/registry/notifications/).
-NOTE: **Note:**
-Multiple endpoints can be configured for the Container Registry.
+You can configure multiple endpoints for the Container Registry.
**Omnibus GitLab installations**
@@ -761,28 +737,16 @@ project.container_repositories.find_each do |repo|
end
```
-NOTE: **Note:**
You can also [run cleanup on a schedule](../../user/packages/container_registry/index.md#cleanup-policy).
## Container Registry garbage collection
-NOTE: **Note:**
-The garbage collection tools are only available when you've installed GitLab
-via an Omnibus package or the [cloud native chart](https://docs.gitlab.com/charts/charts/registry/#garbage-collection).
-
-DANGER: **Danger:**
-By running the built-in garbage collection command, it will cause downtime to
-the Container Registry. If you run this command on an instance in an environment
-where one of your other instances is still writing to the Registry storage,
-referenced manifests will be removed. To avoid that, make sure Registry is set to
-[read-only mode](#performing-garbage-collection-without-downtime) before proceeding.
-
Container Registry can use considerable amounts of disk space. To clear up
some unused layers, the registry includes a garbage collect command.
GitLab offers a set of APIs to manipulate the Container Registry and aid the process
of removing unused tags. Currently, this is exposed using the API, but in the future,
-these controls will be migrated to the GitLab interface.
+these controls should migrate to the GitLab interface.
Project maintainers can
[delete Container Registry tags in bulk](../../api/container_registry.md#delete-registry-repository-tags-in-bulk)
@@ -791,6 +755,15 @@ it only unlinks tags from manifests and image blobs. To recycle the Container
Registry data in the whole GitLab instance, you can use the built-in command
provided by `gitlab-ctl`.
+Prerequisites:
+
+- You must have installed GitLab by using an Omnibus package or the
+ [cloud native chart](https://docs.gitlab.com/charts/charts/registry/#garbage-collection).
+- You must set the Registry to [read-only mode](#performing-garbage-collection-without-downtime).
+ Running garbage collection causes downtime for the Container Registry. When you run this command
+ on an instance in an environment where another instances is still writing to the Registry storage,
+ referenced manifests are removed.
+
### Understanding the content-addressable layers
Consider the following example, where you first build the image:
@@ -818,15 +791,14 @@ no longer directly accessible via the `:latest` tag.
> [Introduced](https://gitlab.com/gitlab-org/omnibus-gitlab/-/merge_requests/987) in Omnibus GitLab 8.12.
-There are a couple of considerations you need to note before running the
-built-in command:
+Before you run the built-in command, note the following:
-- The built-in command will stop the registry before it starts the garbage collection.
+- The built-in command stops the registry before it starts the garbage collection.
- The garbage collect command takes some time to complete, depending on the
amount of data that exists.
-- If you changed the location of registry configuration file, you will need to
+- If you changed the location of registry configuration file, you must
specify its path.
-- After the garbage collection is done, the registry should start up automatically.
+- After the garbage collection is done, the registry should start automatically.
If you did not change the default location of the configuration file, run:
@@ -882,7 +854,6 @@ During this time,
you will be able to pull from the Container Registry, but you will not be able to
push.
-NOTE: **Note:**
By default, the [registry storage path](#configure-storage-for-the-container-registry)
is `/var/opt/gitlab/gitlab-rails/shared/registry`.
@@ -1065,7 +1036,7 @@ Start with a value between `25000000` (25MB) and `50000000` (50MB).
s3:
accesskey: 'AKIAKIAKI'
secretkey: 'secret123'
- bucket: 'gitlab-registry-bucket-AKIAKIAKI'
+ bucket: 'gitlab-registry-bucket-AKIAKIAKI'
chunksize: 25000000
```
@@ -1166,12 +1137,7 @@ curl localhost:5001/debug/vars
### Advanced Troubleshooting
-NOTE: **Note:**
-The following section is only recommended for experts.
-
-Sometimes it's not obvious what is wrong, and you may need to dive deeper into
-the communication between the Docker client and the Registry to find out
-what's wrong. We will use a concrete example in the past to illustrate how to
+We will use a concrete example in the past to illustrate how to
diagnose a problem with the S3 setup.
#### Unexpected 403 error during push
diff --git a/doc/administration/packages/dependency_proxy.md b/doc/administration/packages/dependency_proxy.md
index 2f9cfecc9d4..fba3d51f741 100644
--- a/doc/administration/packages/dependency_proxy.md
+++ b/doc/administration/packages/dependency_proxy.md
@@ -11,7 +11,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
GitLab can be utilized as a dependency proxy for a variety of common package managers.
This is the administration documentation. If you want to learn how to use the
-dependency proxies, see the [user guide](../../user/group/dependency_proxy/index.md).
+dependency proxies, see the [user guide](../../user/packages/dependency_proxy/index.md).
## Enabling the Dependency Proxy feature
@@ -135,28 +135,28 @@ This section describes the earlier configuration format.
##
## The location where build dependency_proxy are stored (default: shared/dependency_proxy).
##
- #storage_path: shared/dependency_proxy
+ # storage_path: shared/dependency_proxy
object_store:
enabled: false
- remote_directory: dependency_proxy # The bucket name.
- #direct_upload: false # Use Object Storage directly for uploads instead of background uploads if enabled (Default: false).
- #background_upload: true # Temporary option to limit automatic upload (Default: true).
- #proxy_download: false # Passthrough all downloads via GitLab instead of using Redirects to Object Storage.
+ remote_directory: dependency_proxy # The bucket name.
+ # direct_upload: false # Use Object Storage directly for uploads instead of background uploads if enabled (Default: false).
+ # background_upload: true # Temporary option to limit automatic upload (Default: true).
+ # proxy_download: false # Passthrough all downloads via GitLab instead of using Redirects to Object Storage.
connection:
+ ##
+ ## If the provider is AWS S3, use the following
+ ##
+ provider: AWS
+ region: us-east-1
+ aws_access_key_id: AWS_ACCESS_KEY_ID
+ aws_secret_access_key: AWS_SECRET_ACCESS_KEY
##
- ## If the provider is AWS S3, uncomment the following
+ ## If the provider is other than AWS (an S3-compatible one), comment out the previous 4 lines and use the following instead:
##
- #provider: AWS
- #region: us-east-1
- #aws_access_key_id: AWS_ACCESS_KEY_ID
- #aws_secret_access_key: AWS_SECRET_ACCESS_KEY
- ##
- ## If the provider is other than AWS (an S3-compatible one), uncomment the following
- ##
- #host: 's3.amazonaws.com' # default: s3.amazonaws.com.
- #aws_signature_version: 4 # For creation of signed URLs. Set to 2 if provider does not support v4.
- #endpoint: 'https://s3.amazonaws.com' # Useful for S3-compliant services such as DigitalOcean Spaces.
- #path_style: false # If true, use 'host/bucket_name/object' instead of 'bucket_name.host/object'.
+ # host: 's3.amazonaws.com' # default: s3.amazonaws.com.
+ # aws_signature_version: 4 # For creation of signed URLs. Set to 2 if provider does not support v4.
+ # endpoint: 'https://s3.amazonaws.com' # Useful for S3-compliant services such as DigitalOcean Spaces.
+ # path_style: false # If true, use 'host/bucket_name/object' instead of 'bucket_name.host/object'.
```
1. [Restart GitLab](../restart_gitlab.md#installations-from-source "How to restart GitLab") for the changes to take effect.
diff --git a/doc/administration/packages/index.md b/doc/administration/packages/index.md
index 1061f3c33db..0b3a7ae9fa5 100644
--- a/doc/administration/packages/index.md
+++ b/doc/administration/packages/index.md
@@ -14,13 +14,14 @@ The Packages feature allows GitLab to act as a repository for the following:
| Software repository | Description | Available in GitLab version |
| ------------------- | ----------- | --------------------------- |
-| [PyPi Repository](../../user/packages/pypi_repository/index.md) | The GitLab PyPi Repository enables every project in GitLab to have its own space to store [PyPi](https://pypi.org/) packages. | 12.10+ |
+| [PyPI Repository](../../user/packages/pypi_repository/index.md) | The GitLab PyPI Repository enables every project in GitLab to have its own space to store [PyPI](https://pypi.org/) packages. | 12.10+ |
| [Composer Repository](../../user/packages/composer_repository/index.md) | The GitLab Composer Repository enables every project in GitLab to have its own space to store [Composer](https://getcomposer.org/) packages. | 13.1+ |
| [NuGet Repository](../../user/packages/nuget_repository/index.md) | The GitLab NuGet Repository enables every project in GitLab to have its own space to store [NuGet](https://www.nuget.org/) packages. | 12.8+ |
| [Conan Repository](../../user/packages/conan_repository/index.md) | The GitLab Conan Repository enables every project in GitLab to have its own space to store [Conan](https://conan.io/) packages. | 12.4+ |
| [Maven Repository](../../user/packages/maven_repository/index.md) | The GitLab Maven Repository enables every project in GitLab to have its own space to store [Maven](https://maven.apache.org/) packages. | 11.3+ |
| [NPM Registry](../../user/packages/npm_registry/index.md) | The GitLab NPM Registry enables every project in GitLab to have its own space to store [NPM](https://www.npmjs.com/) packages. | 11.7+ |
| [Go Proxy](../../user/packages/go_proxy/index.md) | The Go proxy for GitLab enables every project in GitLab to be fetched with the [Go proxy protocol](https://proxy.golang.org/). | 13.1+ |
+| [Generic packages](../../user/packages/generic_packages/index.md) | Store arbitrary files, like release binaries. | 13.5+ |
Don't you see your package management system supported yet?
Please consider contributing
@@ -142,33 +143,33 @@ We recommend using the [consolidated object storage settings](../object_storage.
1. Edit the `packages` section in `config/gitlab.yml` (uncomment where necessary):
```yaml
- packages:
- enabled: true
+ packages:
+ enabled: true
+ ##
+ ## The location where build packages are stored (default: shared/packages).
+ ##
+ # storage_path: shared/packages
+ object_store:
+ enabled: false
+ remote_directory: packages # The bucket name.
+ # direct_upload: false # Use Object Storage directly for uploads instead of background uploads if enabled (Default: false).
+ # background_upload: true # Temporary option to limit automatic upload (Default: true).
+ # proxy_download: false # Passthrough all downloads via GitLab instead of using Redirects to Object Storage.
+ connection:
##
- ## The location where build packages are stored (default: shared/packages).
+ ## If the provider is AWS S3, use the following:
##
- #storage_path: shared/packages
- object_store:
- enabled: false
- remote_directory: packages # The bucket name.
- #direct_upload: false # Use Object Storage directly for uploads instead of background uploads if enabled (Default: false).
- #background_upload: true # Temporary option to limit automatic upload (Default: true).
- #proxy_download: false # Passthrough all downloads via GitLab instead of using Redirects to Object Storage.
- connection:
- ##
- ## If the provider is AWS S3, uncomment the following
- ##
- #provider: AWS
- #region: us-east-1
- #aws_access_key_id: AWS_ACCESS_KEY_ID
- #aws_secret_access_key: AWS_SECRET_ACCESS_KEY
- ##
- ## If the provider is other than AWS (an S3-compatible one), uncomment the following
- ##
- #host: 's3.amazonaws.com' # default: s3.amazonaws.com.
- #aws_signature_version: 4 # For creation of signed URLs. Set to 2 if provider does not support v4.
- #endpoint: 'https://s3.amazonaws.com' # Useful for S3-compliant services such as DigitalOcean Spaces.
- #path_style: false # If true, use 'host/bucket_name/object' instead of 'bucket_name.host/object'.
+ provider: AWS
+ region: us-east-1
+ aws_access_key_id: AWS_ACCESS_KEY_ID
+ aws_secret_access_key: AWS_SECRET_ACCESS_KEY
+ ##
+ ## If the provider is other than AWS (an S3-compatible one), comment out the previous 4 lines and use the following instead:
+ ##
+ # host: 's3.amazonaws.com' # default: s3.amazonaws.com.
+ # aws_signature_version: 4 # For creation of signed URLs. Set to 2 if provider does not support v4.
+ # endpoint: 'https://s3.amazonaws.com' # Useful for S3-compliant services such as DigitalOcean Spaces.
+ # path_style: false # If true, use 'host/bucket_name/object' instead of 'bucket_name.host/object'.
```
1. Save the file and [restart GitLab](../restart_gitlab.md#installations-from-source) for the changes to take effect.
diff --git a/doc/administration/pages/index.md b/doc/administration/pages/index.md
index 3c0030be629..9f72293a730 100644
--- a/doc/administration/pages/index.md
+++ b/doc/administration/pages/index.md
@@ -53,8 +53,14 @@ supporting custom domains a secondary IP is not needed.
Before proceeding with the Pages configuration, you will need to:
-1. Have an exclusive root domain for serving GitLab Pages. Note that you cannot
- use a subdomain of your GitLab's instance domain.
+1. Have a domain for Pages that is not a subdomain of your GitLab's instance domain.
+
+ | GitLab domain | Pages domain | Does it work? |
+ | :---: | :---: | :---: |
+ | `example.com` | `example.io` | **{check-circle}** Yes |
+ | `example.com` | `pages.example.com` | **{dotted-circle}** No |
+ | `gitlab.example.com` | `pages.example.com` | **{check-circle}** Yes |
+
1. Configure a **wildcard DNS record**.
1. (Optional) Have a **wildcard certificate** for that domain if you decide to
serve Pages under HTTPS.
@@ -235,7 +241,7 @@ control over how the Pages daemon runs and serves content in your environment.
| `pages_path` | The directory on disk where pages are stored, defaults to `GITLAB-RAILS/shared/pages`.
| `pages_nginx[]` | |
| `enable` | Include a virtual host `server{}` block for Pages inside NGINX. Needed for NGINX to proxy traffic back to the Pages daemon. Set to `false` if the Pages daemon should directly receive all requests, for example, when using [custom domains](index.md#custom-domains).
-| `FF_ENABLE_REDIRECTS` | Feature flag to enable redirects. See the [redirects documentation](../../user/project/pages/redirects.md#enable-or-disable-redirects) for more info. |
+| `FF_ENABLE_REDIRECTS` | Feature flag to disable redirects (enabled by default). Read the [redirects documentation](../../user/project/pages/redirects.md#disable-redirects) for more info. |
---
@@ -370,8 +376,8 @@ Pages access control is disabled by default. To enable it:
1. Users can now configure it in their [projects' settings](../../user/project/pages/pages_access_control.md).
NOTE: **Important:**
-For multi-node setups, in order for this setting to be effective, it has to be applied
-to all the App nodes as well as the Sidekiq nodes.
+For this setting to be effective with multi-node setups, it has to be applied to
+all the App nodes and Sidekiq nodes.
#### Disabling public access to all Pages websites
@@ -397,8 +403,7 @@ redeployed. This issue will be resolved by
### Running behind a proxy
Like the rest of GitLab, Pages can be used in those environments where external
-internet connectivity is gated by a proxy. In order to use a proxy for GitLab
-pages:
+internet connectivity is gated by a proxy. To use a proxy for GitLab Pages:
1. Configure in `/etc/gitlab/gitlab.rb`:
@@ -425,10 +430,6 @@ Authority (CA) in the system certificate store.
For Omnibus, this is fixed by [installing a custom CA in Omnibus GitLab](https://docs.gitlab.com/omnibus/settings/ssl.html#install-custom-public-certificates).
-## Enable redirects
-
-In GitLab Pages, you can [enable the redirects feature](../../user/project/pages/redirects.md#enable-or-disable-redirects) to configure rules to forward one URL to another using HTTP redirects.
-
## Activate verbose logging for daemon
Verbose logging was [introduced](https://gitlab.com/gitlab-org/omnibus-gitlab/-/merge_requests/2533) in
@@ -508,7 +509,8 @@ To override the global maximum pages size for a specific group:
## Running GitLab Pages on a separate server
-You can run the GitLab Pages daemon on a separate server in order to decrease the load on your main application server.
+You can run the GitLab Pages daemon on a separate server to decrease the load on
+your main application server.
To configure GitLab Pages on a separate server:
@@ -595,7 +597,7 @@ database encryption. Proceed with caution.
```ruby
pages_external_url "http://<pages_server_URL>"
gitlab_pages['enable'] = false
- gitlab_rails['pages_enabled']=false
+ pages_nginx['enable'] = false
gitlab_rails['pages_path'] = "/mnt/pages"
```
@@ -779,3 +781,16 @@ For example, if there is a connection timeout:
```plaintext
error="failed to connect to internal Pages API: Get \"https://gitlab.example.com:3000/api/v4/internal/pages/status\": net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers)"
```
+
+### 500 error with `securecookie: failed to generate random iv` and `Failed to save the session`
+
+This problem most likely results from an [out-dated operating system](https://docs.gitlab.com/omnibus/package-information/deprecated_os.html).
+The [Pages daemon uses the `securecookie` library](https://gitlab.com/search?group_id=9970&project_id=734943&repository_ref=master&scope=blobs&search=securecookie&snippets=false) to get random strings via [crypto/rand in Go](https://golang.org/pkg/crypto/rand/#pkg-variables).
+This requires the `getrandom` syscall or `/dev/urandom` to be available on the host OS.
+Upgrading to an [officially supported operating system](https://about.gitlab.com/install/) is recommended.
+
+### The requested scope is invalid, malformed, or unknown
+
+This problem comes from the permissions of the GitLab Pages OAuth application. To fix it, go to
+**Admin > Applications > GitLab Pages** and edit the application. Under **Scopes**, ensure that the
+`api` scope is selected and save your changes.
diff --git a/doc/administration/pages/source.md b/doc/administration/pages/source.md
index 662817e7411..87217b141a4 100644
--- a/doc/administration/pages/source.md
+++ b/doc/administration/pages/source.md
@@ -347,10 +347,6 @@ world. Custom domains and TLS are supported.
1. Restart NGINX
1. [Restart GitLab](../restart_gitlab.md#installations-from-source)
-## Enable redirects
-
-In GitLab Pages, you can [enable the redirects feature](../../user/project/pages/redirects.md#enable-or-disable-redirects) to configure rules to forward one URL to another using HTTP redirects.
-
## NGINX caveats
NOTE: **Note:**
diff --git a/doc/administration/postgresql/external.md b/doc/administration/postgresql/external.md
index 632b68fb014..4a164c66578 100644
--- a/doc/administration/postgresql/external.md
+++ b/doc/administration/postgresql/external.md
@@ -1,3 +1,9 @@
+---
+stage: Enablement
+group: Database
+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/#designated-technical-writers
+---
+
# Configure GitLab using an external PostgreSQL service
If you're hosting GitLab on a cloud provider, you can optionally use a
diff --git a/doc/administration/postgresql/index.md b/doc/administration/postgresql/index.md
index 2720d8e696b..c7ec46db654 100644
--- a/doc/administration/postgresql/index.md
+++ b/doc/administration/postgresql/index.md
@@ -1,11 +1,14 @@
---
+stage: Enablement
+group: Database
+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/#designated-technical-writers
type: reference
---
# Configuring PostgreSQL for scaling
In this section, you'll be guided through configuring a PostgreSQL database to
-be used with GitLab in one of our [Scalable and Highly Available Setups](../reference_architectures/index.md).
+be used with GitLab in one of our [reference architectures](../reference_architectures/index.md).
There are essentially three setups to choose from.
## PostgreSQL replication and failover with Omnibus GitLab **(PREMIUM ONLY)**
diff --git a/doc/administration/postgresql/pgbouncer.md b/doc/administration/postgresql/pgbouncer.md
index 9db3e017359..7760b197267 100644
--- a/doc/administration/postgresql/pgbouncer.md
+++ b/doc/administration/postgresql/pgbouncer.md
@@ -1,4 +1,7 @@
---
+stage: Enablement
+group: Database
+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/#designated-technical-writers
type: reference
---
@@ -145,6 +148,35 @@ ote_pid | tls
(1 row)
```
+## Procedure for bypassing PgBouncer
+
+Some database changes have to be done directly, and not through PgBouncer. This includes database restores and GitLab upgrades (because of the database migrations).
+
+1. To find the primary node, run the following on a database node:
+
+ ```shell
+ sudo gitlab-ctl repmgr cluster show
+ ```
+
+1. Edit `/etc/gitlab/gitlab.rb` on the application node you're performing the task on, and update
+ `gitlab_rails['db_host']` and `gitlab_rails['db_port']` with the database
+ primary's host and port.
+
+1. Run reconfigure:
+
+ ```shell
+ sudo gitlab-ctl reconfigure
+ ```
+
+Once you've performed the tasks or procedure, switch back to using PgBouncer:
+
+1. Change back `/etc/gitlab/gitlab.rb` to point to PgBouncer.
+1. Run reconfigure:
+
+ ```shell
+ sudo gitlab-ctl reconfigure
+ ```
+
## Troubleshooting
In case you are experiencing any issues connecting through PgBouncer, the first
diff --git a/doc/administration/postgresql/replication_and_failover.md b/doc/administration/postgresql/replication_and_failover.md
index bc2af167e6c..0a40b61fd3c 100644
--- a/doc/administration/postgresql/replication_and_failover.md
+++ b/doc/administration/postgresql/replication_and_failover.md
@@ -1,10 +1,16 @@
+---
+stage: Enablement
+group: Database
+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/#designated-technical-writers
+---
+
# PostgreSQL replication and failover with Omnibus GitLab **(PREMIUM ONLY)**
-This document will focus only on configuration supported with [GitLab Premium](https://about.gitlab.com/pricing/), using the Omnibus GitLab package.
-If you are a Community Edition or Starter user, consider using a cloud hosted solution.
-This document will not cover installations from source.
+This document focuses on configuration supported with [GitLab Premium](https://about.gitlab.com/pricing/), using the Omnibus GitLab package.
+If you're a Community Edition or Starter user, consider using a cloud hosted solution.
+This document doesn't cover installations from source.
-If a setup with replication and failover is not what you were looking for, see
+If a setup with replication and failover isn't what you were looking for, see
the [database configuration document](https://docs.gitlab.com/omnibus/settings/database.html)
for the Omnibus GitLab packages.
@@ -87,9 +93,9 @@ information.
#### Network information
-PostgreSQL does not listen on any network interface by default. It needs to know
-which IP address to listen on in order to be accessible to other services.
-Similarly, PostgreSQL access is controlled based on the network source.
+PostgreSQL doesn't listen on any network interface by default. It needs to know
+which IP address to listen on to be accessible to other services. Similarly,
+PostgreSQL access is controlled based on the network source.
This is why you will need:
@@ -419,7 +425,7 @@ Check the [Troubleshooting section](#troubleshooting) before proceeding.
1. Make sure you collect [`CONSUL_SERVER_NODES`](#consul-information), [`CONSUL_PASSWORD_HASH`](#consul-information), and [`PGBOUNCER_PASSWORD_HASH`](#pgbouncer-information) before executing the next step.
-1. One each node, edit the `/etc/gitlab/gitlab.rb` config file and replace values noted in the `# START user configuration` section as below:
+1. One each node, edit the `/etc/gitlab/gitlab.rb` configuration file and replace values noted in the `# START user configuration` section as below:
```ruby
# Disable all components except PgBouncer and Consul agent
@@ -1263,6 +1269,11 @@ with:
sudo gitlab-ctl stop patroni
```
+Note that stopping or restarting Patroni service on the leader node will trigger the automatic failover. If you
+want to signal Patroni to reload its configuration or restart PostgreSQL process without triggering the failover, you
+must use the `reload` or `restart` sub-commands of `gitlab-ctl patroni` instead. These two sub-commands are wrappers of
+the same `patronictl` commands.
+
### Manual failover procedure for Patroni
While Patroni supports automatic failover, you also have the ability to perform
@@ -1348,3 +1359,93 @@ You can switch an exiting database cluster to use Patroni instead of repmgr with
1. Repeat the last two steps for all replica nodes. `gitlab.rb` should look the same on all nodes.
1. Optional: You can remove `gitlab_repmgr` database and role on the primary.
+
+### Upgrading PostgreSQL major version in a Patroni cluster
+
+As of GitLab 13.3, PostgreSQL 11.7 and 12.3 are both shipped with Omnibus GitLab. GitLab still
+uses PostgreSQL 11 by default. Therefore `gitlab-ctl pg-upgrade` does not automatically upgrade
+to PostgreSQL 12. If you want to upgrade to PostgreSQL 12, you must ask for it explicitly.
+
+CAUTION: **Warning:**
+The procedure for upgrading PostgreSQL in a Patroni cluster is different than when upgrading using repmgr.
+The following outlines the key differences and important considerations that need to be accounted for when
+upgrading PostgreSQL.
+
+Here are a few key facts that you must consider before upgrading PostgreSQL:
+
+- The main point is that you will have to **shut down the Patroni cluster**. This means that your
+ GitLab deployment will be down for the duration of database upgrade or, at least, as long as your leader
+ node is upgraded. This can be **a significant downtime depending on the size of your database**.
+
+- Upgrading PostgreSQL creates a new data directory with a new control data. From Patroni's perspective
+ this is a new cluster that needs to be bootstrapped again. Therefore, as part of the upgrade procedure,
+ the cluster state, which is stored in Consul, will be wiped out. Once the upgrade is completed, Patroni
+ will be instructed to bootstrap a new cluster. **Note that this will change your _cluster ID_**.
+
+- The procedures for upgrading leader and replicas are not the same. That is why it is important to use the
+ right procedure on each node.
+
+- Upgrading a replica node **deletes the data directory and resynchronizes it** from the leader using the
+ configured replication method (currently `pg_basebackup` is the only available option). It might take some
+ time for replica to catch up with the leader, depending on the size of your database.
+
+- An overview of the upgrade procedure is outlined in [Patoni's documentation](https://patroni.readthedocs.io/en/latest/existing_data.html#major-upgrade-of-postgresql-version).
+ You can still use `gitlab-ctl pg-upgrade` which implements this procedure with a few adjustments.
+
+Considering these, you should carefully plan your PostgreSQL upgrade:
+
+1. Find out which node is the leader and which node is a replica:
+
+ ```shell
+ gitlab-ctl patroni members
+ ```
+
+ NOTE: **Note:**
+ `gitlab-ctl pg-upgrade` tries to detect the role of the node. If for any reason the auto-detection
+ does not work or you believe it did not detect the role correctly, you can use the `--leader` or `--replica`
+ arguments to manually override it.
+
+1. Stop Patroni **only on replicas**.
+
+ ```shell
+ sudo gitlab-ctl stop patroni
+ ```
+
+1. Enable the maintenance mode on the **application node**:
+
+ ```shell
+ sudo gitlab-ctl deploy-page up
+ ```
+
+1. Upgrade PostgreSQL on **the leader node** and make sure that the upgrade is completed successfully:
+
+ ```shell
+ sudo gitlab-ctl pg-upgrade -V 12
+ ```
+
+1. Check the status of the leader and cluster. You can only proceed if you have a healthy leader:
+
+ ```shell
+ gitlab-ctl patroni check-leader
+
+ # OR
+
+ gitlab-ctl patroni members
+ ```
+
+1. You can now disable the maintenance mode on the **application node**:
+
+ ```shell
+ sudo gitlab-ctl deploy-page down
+ ```
+
+1. Upgrade PostgreSQL **on replicas** (you can do this in parallel on all of them):
+
+ ```shell
+ sudo gitlab-ctl pg-upgrade -V 12
+ ```
+
+NOTE: **Note:**
+Reverting PostgreSQL upgrade with `gitlab-ctl revert-pg-upgrade` has the same considerations as
+`gitlab-ctl pg-upgrade`. You should follow the same procedure by first stopping the replicas,
+then reverting the leader, and finally reverting the replicas.
diff --git a/doc/administration/postgresql/standalone.md b/doc/administration/postgresql/standalone.md
index 2747749066e..2ac74e8a4a0 100644
--- a/doc/administration/postgresql/standalone.md
+++ b/doc/administration/postgresql/standalone.md
@@ -1,15 +1,21 @@
+---
+stage: Enablement
+group: Database
+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/#designated-technical-writers
+---
+
# Standalone PostgreSQL using Omnibus GitLab **(CORE ONLY)**
If you wish to have your database service hosted separately from your GitLab
-application server(s), you can do this using the PostgreSQL binaries packaged
+application servers, you can do this using the PostgreSQL binaries packaged
together with Omnibus GitLab. This is recommended as part of our
[reference architecture for up to 2,000 users](../reference_architectures/2k_users.md).
## Setting it up
-1. SSH into the PostgreSQL server.
-1. [Download/install](https://about.gitlab.com/install/) the Omnibus GitLab
- package you want using **steps 1 and 2** from the GitLab downloads page.
+1. SSH in to the PostgreSQL server.
+1. [Download and install](https://about.gitlab.com/install/) the Omnibus GitLab
+ package you want using *steps 1 and 2* from the GitLab downloads page.
- Do not complete any other steps on the download page.
1. Generate a password hash for PostgreSQL. This assumes you will use the default
username of `gitlab` (recommended). The command will request a password
diff --git a/doc/administration/raketasks/check.md b/doc/administration/raketasks/check.md
index 15014fffd01..bdccd6d5fe9 100644
--- a/doc/administration/raketasks/check.md
+++ b/doc/administration/raketasks/check.md
@@ -148,9 +148,38 @@ above.
for the affected project(s).
If the issue persists, try triggering `gc` via the
-[Rails Console](../troubleshooting/navigating_gitlab_via_rails_console.md#starting-a-rails-console-session):
+[Rails Console](../operations/rails_console.md#starting-a-rails-console-session):
```ruby
p = Project.find_by_path("project-name")
Projects::HousekeepingService.new(p, :gc).execute
```
+
+### Delete references to missing remote uploads
+
+`gitlab-rake gitlab:uploads:check VERBOSE=1` detects remote objects that do not exist because they were
+deleted externally but their references still exist in the GitLab database.
+
+Example output with error message:
+
+```shell
+$ sudo gitlab-rake gitlab:uploads:check VERBOSE=1
+Checking integrity of Uploads
+- 100..434: Failures: 2
+- Upload: 100: Remote object does not exist
+- Upload: 101: Remote object does not exist
+Done!
+```
+
+To delete these references to remote uploads that were deleted externally, open the [GitLab Rails Console](../operations/rails_console.md#starting-a-rails-console-session) and run:
+
+```ruby
+uploads_deleted=0
+Upload.find_each do |upload|
+ next if upload.retrieve_uploader.file.exists?
+ uploads_deleted=uploads_deleted + 1
+ p upload ### allow verification before destroy
+ # p upload.destroy! ### uncomment to actually destroy
+end
+p "#{uploads_deleted} remote objects were destroyed."
+```
diff --git a/doc/administration/raketasks/doctor.md b/doc/administration/raketasks/doctor.md
index 62d0af70706..c97aa5a4de1 100644
--- a/doc/administration/raketasks/doctor.md
+++ b/doc/administration/raketasks/doctor.md
@@ -47,9 +47,8 @@ I, [2020-06-11T17:18:15.575711 #27148] INFO -- : Done!
### Verbose mode
-In order to get more detailed information about which
-rows and columns cannot be decrypted, you can pass a VERBOSE
-environment variable:
+To get more detailed information about which rows and columns can't be
+decrypted, you can pass a `VERBOSE` environment variable:
**Omnibus Installation**
diff --git a/doc/administration/raketasks/github_import.md b/doc/administration/raketasks/github_import.md
index a46a2b34687..7f673a2c850 100644
--- a/doc/administration/raketasks/github_import.md
+++ b/doc/administration/raketasks/github_import.md
@@ -2,9 +2,8 @@
> [Introduced]( https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/10308) in GitLab 9.1.
-In order to retrieve and import GitHub repositories, you will need a
-[GitHub personal access token](https://github.com/settings/tokens).
-A username should be passed as the second argument to the Rake task
+To retrieve and import GitHub repositories, you need a [GitHub personal access token](https://github.com/settings/tokens).
+A username should be passed as the second argument to the Rake task,
which will become the owner of the project. You can resume an import
with the same command.
diff --git a/doc/administration/raketasks/uploads/sanitize.md b/doc/administration/raketasks/uploads/sanitize.md
index 9586ab2c6f4..54aa62059cf 100644
--- a/doc/administration/raketasks/uploads/sanitize.md
+++ b/doc/administration/raketasks/uploads/sanitize.md
@@ -1,6 +1,6 @@
# Uploads sanitize Rake tasks **(CORE ONLY)**
-Since GitLab 11.9, EXIF data is automatically stripped from JPG or TIFF image uploads.
+In GitLab 11.9 and later, EXIF data is automatically stripped from JPG or TIFF image uploads.
EXIF data may contain sensitive information (for example, GPS location), so you
can remove EXIF data from existing images that were uploaded to an earlier version of GitLab.
diff --git a/doc/administration/read_only_gitlab.md b/doc/administration/read_only_gitlab.md
new file mode 100644
index 00000000000..681102a8c39
--- /dev/null
+++ b/doc/administration/read_only_gitlab.md
@@ -0,0 +1,125 @@
+---
+stage: Enablement
+group: Distribution
+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/#designated-technical-writers
+---
+
+# Place GitLab into a read-only state **(CORE ONLY)**
+
+CAUTION: **Warning:**
+This document should be used as a temporary solution.
+There's work in progress to make this
+[possible with Geo](https://gitlab.com/groups/gitlab-org/-/epics/2149).
+
+In some cases, you might want to place GitLab under a read-only state.
+The configuration for doing so depends on your desired outcome.
+
+## Make the repositories read-only
+
+The first thing you'll want to accomplish is to ensure that no changes can be
+made to your repositories. There's two ways you can accomplish that:
+
+- Either stop Unicorn/Puma to make the internal API unreachable:
+
+ ```shell
+ sudo gitlab-ctl stop puma # or unicorn
+ ```
+
+- Or, open up a Rails console:
+
+ ```shell
+ sudo gitlab-rails console
+ ```
+
+ And set the repositories for all projects read-only:
+
+ ```ruby
+ Project.all.find_each { |project| project.update!(repository_read_only: true) }
+ ```
+
+ When you're ready to revert this, you can do so with the following command:
+
+ ```ruby
+ Project.all.find_each { |project| project.update!(repository_read_only: false) }
+ ```
+
+## Shut down the GitLab UI
+
+If you don't mind shutting down the GitLab UI, then the easiest approach is to
+stop `sidekiq` and `puma`/`unicorn`, and you'll effectively ensure that no
+changes can be made to GitLab:
+
+```shell
+sudo gitlab-ctl stop sidekiq
+sudo gitlab-ctl stop puma # or unicorn
+```
+
+When you're ready to revert this:
+
+```shell
+sudo gitlab-ctl start sidekiq
+sudo gitlab-ctl start puma # or unicorn
+```
+
+## Make the database read-only
+
+If you want to allow users to use the GitLab UI, then you'll need to ensure that
+the database is read-only:
+
+1. Take a [GitLab backup](../raketasks/backup_restore.md#back-up-gitlab)
+ in case things don't go as expected.
+1. Enter PostgreSQL on the console as an admin user:
+
+ ```shell
+ sudo \
+ -u gitlab-psql /opt/gitlab/embedded/bin/psql \
+ -h /var/opt/gitlab/postgresql gitlabhq_production
+ ```
+
+1. Create the `gitlab_read_only` user. Note that the password is set to `mypassword`,
+ change that to your liking:
+
+ ```sql
+ -- NOTE: Use the password defined earlier
+ CREATE USER gitlab_read_only WITH password 'mypassword';
+ GRANT CONNECT ON DATABASE gitlabhq_production to gitlab_read_only;
+ GRANT USAGE ON SCHEMA public TO gitlab_read_only;
+ GRANT SELECT ON ALL TABLES IN SCHEMA public TO gitlab_read_only;
+ GRANT SELECT ON ALL SEQUENCES IN SCHEMA public TO gitlab_read_only;
+
+ -- Tables created by "gitlab" should be made read-only for "gitlab_read_only"
+ -- automatically.
+ ALTER DEFAULT PRIVILEGES FOR USER gitlab IN SCHEMA public GRANT SELECT ON TABLES TO gitlab_read_only;
+ ALTER DEFAULT PRIVILEGES FOR USER gitlab IN SCHEMA public GRANT SELECT ON SEQUENCES TO gitlab_read_only;
+ ```
+
+1. Get the hashed password of the `gitlab_read_only` user and copy the result:
+
+ ```shell
+ sudo gitlab-ctl pg-password-md5 gitlab_read_only
+ ```
+
+1. Edit `/etc/gitlab/gitlab.rb` and add the password from the previous step:
+
+ ```ruby
+ postgresql['sql_user_password'] = 'a2e20f823772650f039284619ab6f239'
+ postgresql['sql_user'] = "gitlab_read_only"
+ ```
+
+1. Reconfigure GitLab and restart PostgreSQL:
+
+ ```shell
+ sudo gitlab-ctl reconfigure
+ sudo gitlab-ctl restart postgresql
+ ```
+
+When you're ready to revert the read-only state, you'll need to remove the added
+lines in `/etc/gitlab/gitlab.rb`, and reconfigure GitLab and restart PostgreSQL:
+
+```shell
+sudo gitlab-ctl reconfigure
+sudo gitlab-ctl restart postgresql
+```
+
+Once you verify all works as expected, you can remove the `gitlab_read_only`
+user from the database.
diff --git a/doc/administration/redis/replication_and_failover.md b/doc/administration/redis/replication_and_failover.md
index ca041adb1d8..72a52ba0a1f 100644
--- a/doc/administration/redis/replication_and_failover.md
+++ b/doc/administration/redis/replication_and_failover.md
@@ -124,9 +124,9 @@ each other over the network.
### Sentinel setup overview
Sentinels watch both other Sentinels and Redis nodes. Whenever a Sentinel
-detects that a Redis node is not responding, it will announce that to the
-other Sentinels. They have to reach the **quorum**, that is the minimum amount
-of Sentinels that agrees a node is down, in order to be able to start a failover.
+detects that a Redis node isn't responding, it announces the node's status to
+the other Sentinels. The Sentinels have to reach a _quorum_ (the minimum amount
+of Sentinels agreeing a node is down) to be able to start a failover.
Whenever the **quorum** is met, the **majority** of all known Sentinel nodes
need to be available and reachable, so that they can elect the Sentinel **leader**
diff --git a/doc/administration/redis/replication_and_failover_external.md b/doc/administration/redis/replication_and_failover_external.md
index ce452d30fc2..7561f1c0fbf 100644
--- a/doc/administration/redis/replication_and_failover_external.md
+++ b/doc/administration/redis/replication_and_failover_external.md
@@ -71,7 +71,7 @@ requirements:
- All Redis servers in this guide must be configured to use a TCP connection
instead of a socket. To configure Redis to use TCP connections you need to
- define both `bind` and `port` in the Redis config file. You can bind to all
+ define both `bind` and `port` in the Redis configuration file. You can bind to all
interfaces (`0.0.0.0`) or specify the IP of the desired interface
(e.g., one from an internal network).
- Since Redis 3.2, you must define a password to receive external connections
@@ -228,13 +228,13 @@ which ideally should not have Redis or Sentinels in the same machine:
sentinels:
-
host: 10.0.0.1
- port: 26379 # point to sentinel, not to redis port
+ port: 26379 # point to sentinel, not to redis port
-
host: 10.0.0.2
- port: 26379 # point to sentinel, not to redis port
+ port: 26379 # point to sentinel, not to redis port
-
host: 10.0.0.3
- port: 26379 # point to sentinel, not to redis port
+ port: 26379 # point to sentinel, not to redis port
```
1. [Restart GitLab](../restart_gitlab.md#installations-from-source) for the changes to take effect.
@@ -353,13 +353,13 @@ or a failover promotes a different **Primary** node.
sentinels:
-
host: 10.0.0.1
- port: 26379 # point to sentinel, not to redis port
+ port: 26379 # point to sentinel, not to redis port
-
host: 10.0.0.2
- port: 26379 # point to sentinel, not to redis port
+ port: 26379 # point to sentinel, not to redis port
-
host: 10.0.0.3
- port: 26379 # point to sentinel, not to redis port
+ port: 26379 # point to sentinel, not to redis port
```
1. [Restart GitLab](../restart_gitlab.md#installations-from-source) for the changes to take effect.
diff --git a/doc/administration/redis/troubleshooting.md b/doc/administration/redis/troubleshooting.md
index 402b60e5b7b..c9976ac791d 100644
--- a/doc/administration/redis/troubleshooting.md
+++ b/doc/administration/redis/troubleshooting.md
@@ -146,13 +146,13 @@ production:
sentinels:
-
host: 10.0.0.1
- port: 26379 # point to sentinel, not to redis port
+ port: 26379 # point to sentinel, not to redis port
-
host: 10.0.0.2
- port: 26379 # point to sentinel, not to redis port
+ port: 26379 # point to sentinel, not to redis port
-
host: 10.0.0.3
- port: 26379 # point to sentinel, not to redis port
+ port: 26379 # point to sentinel, not to redis port
```
When in doubt, read the [Redis Sentinel documentation](https://redis.io/topics/sentinel).
diff --git a/doc/administration/reference_architectures/10k_users.md b/doc/administration/reference_architectures/10k_users.md
index 5f8ab6683a9..7910905ce54 100644
--- a/doc/administration/reference_architectures/10k_users.md
+++ b/doc/administration/reference_architectures/10k_users.md
@@ -17,21 +17,21 @@ full list of reference architectures, see
| Service | Nodes | Configuration | GCP | AWS | Azure |
|--------------------------------------------|-------------|-------------------------|-----------------|-------------|----------|
-| External load balancing node | 1 | 2 vCPU, 1.8GB memory | n1-highcpu-2 | c5.large | F2s v2 |
-| Consul | 3 | 2 vCPU, 1.8GB memory | n1-highcpu-2 | c5.large | F2s v2 |
-| PostgreSQL | 3 | 4 vCPU, 15GB memory | n1-standard-4 | m5.xlarge | D4s v3 |
-| PgBouncer | 3 | 2 vCPU, 1.8GB memory | n1-highcpu-2 | c5.large | F2s v2 |
-| Internal load balancing node | 1 | 2 vCPU, 1.8GB memory | n1-highcpu-2 | c5.large | F2s v2 |
-| Redis - Cache | 3 | 4 vCPU, 15GB memory | n1-standard-4 | m5.xlarge | D4s v3 |
-| Redis - Queues / Shared State | 3 | 4 vCPU, 15GB memory | n1-standard-4 | m5.xlarge | D4s v3 |
-| Redis Sentinel - Cache | 3 | 1 vCPU, 1.7GB memory | g1-small | t2.small | B1MS |
-| Redis Sentinel - Queues / Shared State | 3 | 1 vCPU, 1.7GB memory | g1-small | t2.small | B1MS |
-| Gitaly | 2 (minimum) | 16 vCPU, 60GB memory | n1-standard-16 | m5.4xlarge | D16s v3 |
-| Sidekiq | 4 | 4 vCPU, 15GB memory | n1-standard-4 | m5.xlarge | D4s v3 |
-| GitLab Rails | 3 | 32 vCPU, 28.8GB memory | n1-highcpu-32 | c5.9xlarge | F32s v2 |
-| Monitoring node | 1 | 4 vCPU, 3.6GB memory | n1-highcpu-4 | c5.xlarge | F4s v2 |
-| Object Storage | n/a | n/a | n/a | n/a | n/a |
-| NFS Server | 1 | 4 vCPU, 3.6GB memory | n1-highcpu-4 | c5.xlarge | F4s v2 |
+| External load balancing node | 1 | 2 vCPU, 1.8 GB memory | n1-highcpu-2 | c5.large | F2s v2 |
+| Consul | 3 | 2 vCPU, 1.8 GB memory | n1-highcpu-2 | c5.large | F2s v2 |
+| PostgreSQL | 3 | 4 vCPU, 15 GB memory | n1-standard-4 | m5.xlarge | D4s v3 |
+| PgBouncer | 3 | 2 vCPU, 1.8 GB memory | n1-highcpu-2 | c5.large | F2s v2 |
+| Internal load balancing node | 1 | 2 vCPU, 1.8 GB memory | n1-highcpu-2 | c5.large | F2s v2 |
+| Redis - Cache | 3 | 4 vCPU, 15 GB memory | n1-standard-4 | m5.xlarge | D4s v3 |
+| Redis - Queues / Shared State | 3 | 4 vCPU, 15 GB memory | n1-standard-4 | m5.xlarge | D4s v3 |
+| Redis Sentinel - Cache | 3 | 1 vCPU, 1.7 GB memory | g1-small | t2.small | B1MS |
+| Redis Sentinel - Queues / Shared State | 3 | 1 vCPU, 1.7 GB memory | g1-small | t2.small | B1MS |
+| Gitaly | 2 (minimum) | 16 vCPU, 60 GB memory | n1-standard-16 | m5.4xlarge | D16s v3 |
+| Sidekiq | 4 | 4 vCPU, 15 GB memory | n1-standard-4 | m5.xlarge | D4s v3 |
+| GitLab Rails | 3 | 32 vCPU, 28.8 GB memory | n1-highcpu-32 | c5.9xlarge | F32s v2 |
+| Monitoring node | 1 | 4 vCPU, 3.6 GB memory | n1-highcpu-4 | c5.xlarge | F4s v2 |
+| Object storage | n/a | n/a | n/a | n/a | n/a |
+| NFS server | 1 | 4 vCPU, 3.6 GB memory | n1-highcpu-4 | c5.xlarge | F4s v2 |
The Google Cloud Platform (GCP) architectures were built and tested using the
[Intel Xeon E5 v3 (Haswell)](https://cloud.google.com/compute/docs/cpu-platforms)
@@ -40,41 +40,43 @@ or higher, are required for your CPU or node counts. For more information, see
our [Sysbench](https://github.com/akopytov/sysbench)-based
[CPU benchmark](https://gitlab.com/gitlab-org/quality/performance/-/wikis/Reference-Architectures/GCP-CPU-Benchmarks).
-For data objects (such as LFS, Uploads, or Artifacts), an
-[object storage service](#configure-the-object-storage) is recommended instead
-of NFS where possible, due to better performance and availability. Since this
-doesn't require a node to be set up, *Object Storage* is noted as not
-applicable (n/a) in the previous table.
+Due to better performance and availability, for data objects (such as LFS,
+uploads, or artifacts), using an [object storage service](#configure-the-object-storage)
+is recommended instead of using NFS. Using an object storage service also
+doesn't require you to provision and maintain a node.
## Setup components
To set up GitLab and its components to accommodate up to 10,000 users:
1. [Configure the external load balancing node](#configure-the-external-load-balancer)
- that will handle the load balancing of the three GitLab application services nodes.
+ to handle the load balancing of the GitLab application services nodes.
1. [Configure Consul](#configure-consul).
1. [Configure PostgreSQL](#configure-postgresql), the database for GitLab.
1. [Configure PgBouncer](#configure-pgbouncer).
-1. [Configure the internal load balancing node](#configure-the-internal-load-balancer)
+1. [Configure the internal load balancing node](#configure-the-internal-load-balancer).
1. [Configure Redis](#configure-redis).
1. [Configure Gitaly](#configure-gitaly),
which provides access to the Git repositories.
1. [Configure Sidekiq](#configure-sidekiq).
1. [Configure the main GitLab Rails application](#configure-gitlab-rails)
- to run Puma/Unicorn, Workhorse, GitLab Shell, and to serve all frontend requests (UI, API, Git
- over HTTP/SSH).
-1. [Configure Prometheus](#configure-prometheus) to monitor your GitLab environment.
-1. [Configure the Object Storage](#configure-the-object-storage)
+ to run Puma/Unicorn, Workhorse, GitLab Shell, and to serve all frontend
+ requests (which include UI, API, and Git over HTTP/SSH).
+1. [Configure Prometheus](#configure-prometheus) to monitor your GitLab
+ environment.
+1. [Configure the object storage](#configure-the-object-storage)
used for shared data objects.
-1. [Configure NFS (Optional)](#configure-nfs-optional)
- to have shared disk storage service as an alternative to Gitaly and/or Object Storage (although
- not recommended). NFS is required for GitLab Pages, you can skip this step if you're not using
- that feature.
+1. [Configure Advanced Search](#configure-advanced-search) (optional) for faster,
+ more advanced code search across your entire GitLab instance.
+1. [Configure NFS](#configure-nfs-optional) (optional, and not recommended)
+ to have shared disk storage service as an alternative to Gitaly or object
+ storage. You can skip this step if you're not using GitLab Pages (which
+ requires NFS).
-We start with all servers on the same 10.6.0.0/24 private network range, they
-can connect to each other freely on those addresses.
+The servers start on the same 10.6.0.0/24 private network range, and can
+connect to each other freely on these addresses.
-Here is a list and description of each machine and the assigned IP:
+The following list includes descriptions of each server and its assigned IP:
- `10.6.0.10`: External Load Balancer
- `10.6.0.11`: Consul 1
@@ -112,19 +114,18 @@ Here is a list and description of each machine and the assigned IP:
## Configure the external load balancer
-NOTE: **Note:**
+In an active/active 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 hope
+that if you're managing multi-node systems like GitLab, you already have a load
+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.
+
This architecture has been tested and validated with [HAProxy](https://www.haproxy.org/)
as the load balancer. Although other load balancers with similar feature sets
could also be used, those load balancers have not been validated.
-In an active/active GitLab configuration, you will need a load balancer to route
-traffic to the application servers. The specifics on which load balancer to use
-or the exact configuration is beyond the scope of GitLab documentation. We hope
-that if you're managing multi-node systems like GitLab you have a load balancer of
-choice already. Some examples including HAProxy (open-source), F5 Big-IP LTM,
-and Citrix Net Scaler. This documentation will outline what ports and protocols
-you need to use with GitLab.
-
The next question is how you will handle SSL in your environment.
There are several different options:
@@ -247,14 +248,11 @@ with the other servers.
To configure Consul:
-1. SSH into the server that will host Consul.
-1. [Download/install](https://about.gitlab.com/install/) the
- Omnibus GitLab Enterprise Edition package using **steps 1 and 2** from the
- GitLab downloads page.
- - Make sure you select the correct Omnibus package, with the same version
- the GitLab application is running.
- - Do not complete any other steps on the download page.
-
+1. SSH in to the server that will host Consul.
+1. [Download and install](https://about.gitlab.com/install/) the Omnibus GitLab
+ package of your choice. Be sure to both follow _only_ installation steps 1 and 2
+ on the page, and to select the correct Omnibus GitLab package, with the same version
+ and type (Community or Enterprise editions) as your current install.
1. Edit `/etc/gitlab/gitlab.rb` and add the contents:
```ruby
@@ -282,10 +280,9 @@ To configure Consul:
1. Go through the steps again for all the other Consul nodes, and
make sure you set up the correct IPs.
-NOTE: **Note:**
-A Consul leader will be elected when the provisioning of the third Consul server is completed.
-Viewing the Consul logs `sudo gitlab-ctl tail consul` will display
-`...[INFO] consul: New leader elected: ...`
+A Consul leader is _elected_ when the provisioning of the third Consul server is
+complete. Viewing the Consul logs `sudo gitlab-ctl tail consul` displays
+`...[INFO] consul: New leader elected: ...`.
You can list the current Consul members (server, client):
@@ -352,7 +349,7 @@ in the second step, do not supply the `EXTERNAL_URL` value.
#### PostgreSQL primary node
-1. SSH into the PostgreSQL primary node.
+1. SSH in to the PostgreSQL primary node.
1. Generate a password hash for the PostgreSQL username/password pair. This assumes you will use the default
username of `gitlab` (recommended). The command will request a password
and confirmation. Use the value that is output by this command in the next
@@ -513,7 +510,7 @@ are supported and can be added if needed.
#### PostgreSQL post-configuration
-SSH into the **primary node**:
+SSH in to the **primary node**:
1. Open a database prompt:
@@ -548,7 +545,7 @@ SSH into the **primary node**:
is not an IP address, it will need to be a resolvable name (via DNS or
`/etc/hosts`)
-SSH into the **secondary node**:
+SSH in to the **secondary node**:
1. Set up the repmgr standby:
@@ -662,7 +659,6 @@ The following IPs will be used as an example:
1. [Reconfigure Omnibus GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure) for the changes to take effect.
- NOTE: **Note:**
If an error `execute[generate databases.ini]` occurs, this is due to an existing
[known issue](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/4713).
It will be resolved when you run a second `reconfigure` after the next step.
@@ -796,35 +792,31 @@ to be used with GitLab. The following IPs will be used as an example:
- `10.6.0.82`: Sentinel - Queues 2
- `10.6.0.83`: Sentinel - Queues 3
-NOTE: **Providing your own Redis instance:**
-Managed Redis from cloud providers such as AWS ElastiCache will work. If these
-services support high availability, be sure it is **not** the Redis Cluster type.
-Redis version 5.0 or higher is required, as this is what ships with
-Omnibus GitLab packages starting with GitLab 13.0. Older Redis versions
-do not support an optional count argument to SPOP which is now required for
-[Merge Trains](../../ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/index.md).
+### Providing your own Redis instance
+
+Managed Redis from cloud providers (such as AWS ElastiCache) will work. If these
+services support high availability, be sure it _isn't_ of the Redis Cluster type.
+Redis version 5.0 or higher is required, which is included with Omnibus GitLab
+packages starting with GitLab 13.0. Older Redis versions don't support an
+optional count argument to SPOP, which is required for [Merge Trains](../../ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/index.md).
Note the Redis node's IP address or hostname, port, and password (if required).
-These will be necessary when configuring the
-[GitLab application servers](#configure-gitlab-rails) later.
+These will be necessary later when configuring the [GitLab application servers](#configure-gitlab-rails).
### Configure the Redis and Sentinel Cache cluster
This is the section where we install and set up the new Redis Cache instances.
-NOTE: **Note:**
-Redis nodes (both primary and replica) will need the same password defined in
-`redis['password']`. At any time during a failover the Sentinels can
-reconfigure a node and change its status from primary to replica and vice versa.
+Both the primary and replica Redis nodes need the same password defined in
+`redis['password']`. At any time during a failover, the Sentinels can reconfigure
+a node and change its status from primary to replica (and vice versa).
#### Configure the primary Redis Cache node
-1. SSH into the **Primary** Redis server.
-1. [Download/install](https://about.gitlab.com/install/) the Omnibus GitLab
- package you want using **steps 1 and 2** from the GitLab downloads page.
- - Make sure you select the correct Omnibus package, with the same version
- and type (Community, Enterprise editions) of your current install.
- - Do not complete any other steps on the download page.
-
+1. SSH in to the **Primary** Redis server.
+1. [Download and install](https://about.gitlab.com/install/) the Omnibus GitLab
+ package of your choice. Be sure to both follow _only_ installation steps 1 and 2
+ on the page, and to select the correct Omnibus GitLab package, with the same version
+ and type (Community or Enterprise editions) as your current install.
1. Edit `/etc/gitlab/gitlab.rb` and add the contents:
```ruby
@@ -868,20 +860,17 @@ reconfigure a node and change its status from primary to replica and vice versa.
1. [Reconfigure Omnibus GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure) for the changes to take effect.
-NOTE: **Note:**
-You can specify multiple roles like sentinel and Redis as:
-`roles ['redis_sentinel_role', 'redis_master_role']`.
-Read more about [roles](https://docs.gitlab.com/omnibus/roles/).
+You can specify multiple roles, like sentinel and Redis, as:
+`roles ['redis_sentinel_role', 'redis_master_role']`. Read more about
+[roles](https://docs.gitlab.com/omnibus/roles/).
#### Configure the replica Redis Cache nodes
-1. SSH into the **replica** Redis server.
-1. [Download/install](https://about.gitlab.com/install/) the Omnibus GitLab
- package you want using **steps 1 and 2** from the GitLab downloads page.
- - Make sure you select the correct Omnibus package, with the same version
- and type (Community, Enterprise editions) of your current install.
- - Do not complete any other steps on the download page.
-
+1. SSH in to the **replica** Redis server.
+1. [Download and install](https://about.gitlab.com/install/) the Omnibus GitLab
+ package of your choice. Be sure to both follow _only_ installation steps 1 and 2
+ on the page, and to select the correct Omnibus GitLab package, with the same version
+ and type (Community or Enterprise editions) as your current install.
1. Edit `/etc/gitlab/gitlab.rb` and add the contents:
```ruby
@@ -934,10 +923,9 @@ Read more about [roles](https://docs.gitlab.com/omnibus/roles/).
1. Go through the steps again for all the other replica nodes, and
make sure to set up the IPs correctly.
-NOTE: **Note:**
-You can specify multiple roles like sentinel and Redis as:
-`roles ['redis_sentinel_role', 'redis_master_role']`.
-Read more about [roles](https://docs.gitlab.com/omnibus/roles/).
+You can specify multiple roles, like sentinel and Redis, as:
+`roles ['redis_sentinel_role', 'redis_master_role']`. Read more about
+[roles](https://docs.gitlab.com/omnibus/roles/).
These values don't have to be changed again in `/etc/gitlab/gitlab.rb` after
a failover, as the nodes will be managed by the [Sentinels](#configure-the-sentinel-cache-nodes), and even after a
@@ -955,13 +943,6 @@ are supported and can be added if needed.
#### Configure the Sentinel Cache nodes
-NOTE: **Note:**
-If you are using an external Redis Sentinel instance, be sure
-to exclude the `requirepass` parameter from the Sentinel
-configuration. This parameter will cause clients to report `NOAUTH
-Authentication required.`. [Redis Sentinel 3.2.x does not support
-password authentication](https://github.com/antirez/redis/issues/3279).
-
Now that the Redis servers are all set up, let's configure the Sentinel
servers. The following IPs will be used as an example:
@@ -969,16 +950,19 @@ servers. The following IPs will be used as an example:
- `10.6.0.72`: Sentinel - Cache 2
- `10.6.0.73`: Sentinel - Cache 3
-To configure the Sentinel Cache server:
+NOTE: **Note:**
+If you're using an external Redis Sentinel instance, be sure to exclude the
+`requirepass` parameter from the Sentinel configuration. This parameter causes
+clients to report `NOAUTH Authentication required.`.
+[Redis Sentinel 3.2.x doesn't support password authentication](https://github.com/antirez/redis/issues/3279).
-1. SSH into the server that will host Consul/Sentinel.
-1. [Download/install](https://about.gitlab.com/install/) the
- Omnibus GitLab Enterprise Edition package using **steps 1 and 2** from the
- GitLab downloads page.
- - Make sure you select the correct Omnibus package, with the same version
- the GitLab application is running.
- - Do not complete any other steps on the download page.
+To configure the Sentinel Cache server:
+1. SSH in to the server that will host Consul/Sentinel.
+1. [Download and install](https://about.gitlab.com/install/) the Omnibus GitLab
+ package of your choice. Be sure to both follow _only_ installation steps 1 and 2
+ on the page, and to select the correct Omnibus GitLab package, with the same version
+ and type (Community or Enterprise editions) as your current install.
1. Edit `/etc/gitlab/gitlab.rb` and add the contents:
```ruby
@@ -1081,20 +1065,17 @@ To configure the Sentinel Cache server:
This is the section where we install and set up the new Redis Queues instances.
-NOTE: **Note:**
-Redis nodes (both primary and replica) will need the same password defined in
-`redis['password']`. At any time during a failover the Sentinels can
-reconfigure a node and change its status from primary to replica and vice versa.
+Both the primary and replica Redis nodes need the same password defined in
+`redis['password']`. At any time during a failover, the Sentinels can reconfigure
+a node and change its status from primary to replica (and vice versa).
#### Configure the primary Redis Queues node
-1. SSH into the **Primary** Redis server.
-1. [Download/install](https://about.gitlab.com/install/) the Omnibus GitLab
- package you want using **steps 1 and 2** from the GitLab downloads page.
- - Make sure you select the correct Omnibus package, with the same version
- and type (Community, Enterprise editions) of your current install.
- - Do not complete any other steps on the download page.
-
+1. SSH in to the **Primary** Redis server.
+1. [Download and install](https://about.gitlab.com/install/) the Omnibus GitLab
+ package of your choice. Be sure to both follow _only_ installation steps 1 and 2
+ on the page, and to select the correct Omnibus GitLab package, with the same version
+ and type (Community or Enterprise editions) as your current install.
1. Edit `/etc/gitlab/gitlab.rb` and add the contents:
```ruby
@@ -1143,20 +1124,17 @@ reconfigure a node and change its status from primary to replica and vice versa.
1. [Reconfigure Omnibus GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure) for the changes to take effect.
-NOTE: **Note:**
-You can specify multiple roles like sentinel and Redis as:
-`roles ['redis_sentinel_role', 'redis_master_role']`.
-Read more about [roles](https://docs.gitlab.com/omnibus/roles/).
+You can specify multiple roles, like sentinel and Redis, as:
+`roles ['redis_sentinel_role', 'redis_master_role']`. Read more about
+[roles](https://docs.gitlab.com/omnibus/roles/).
#### Configure the replica Redis Queues nodes
-1. SSH into the **replica** Redis Queue server.
-1. [Download/install](https://about.gitlab.com/install/) the Omnibus GitLab
- package you want using **steps 1 and 2** from the GitLab downloads page.
- - Make sure you select the correct Omnibus package, with the same version
- and type (Community, Enterprise editions) of your current install.
- - Do not complete any other steps on the download page.
-
+1. SSH in to the **replica** Redis Queue server.
+1. [Download and install](https://about.gitlab.com/install/) the Omnibus GitLab
+ package of your choice. Be sure to both follow _only_ installation steps 1 and 2
+ on the page, and to select the correct Omnibus GitLab package, with the same version
+ and type (Community or Enterprise editions) as your current install.
1. Edit `/etc/gitlab/gitlab.rb` and add the contents:
```ruby
@@ -1209,10 +1187,9 @@ Read more about [roles](https://docs.gitlab.com/omnibus/roles/).
1. Go through the steps again for all the other replica nodes, and
make sure to set up the IPs correctly.
-NOTE: **Note:**
-You can specify multiple roles like sentinel and Redis as:
-`roles ['redis_sentinel_role', 'redis_master_role']`.
-Read more about [roles](https://docs.gitlab.com/omnibus/roles/).
+You can specify multiple roles, like sentinel and Redis, as:
+`roles ['redis_sentinel_role', 'redis_master_role']`. Read more about
+[roles](https://docs.gitlab.com/omnibus/roles/).
These values don't have to be changed again in `/etc/gitlab/gitlab.rb` after
a failover, as the nodes will be managed by the [Sentinels](#configure-the-sentinel-queues-nodes), and even after a
@@ -1230,13 +1207,6 @@ are supported and can be added if needed.
#### Configure the Sentinel Queues nodes
-NOTE: **Note:**
-If you are using an external Redis Sentinel instance, be sure
-to exclude the `requirepass` parameter from the Sentinel
-configuration. This parameter will cause clients to report `NOAUTH
-Authentication required.`. [Redis Sentinel 3.2.x does not support
-password authentication](https://github.com/antirez/redis/issues/3279).
-
Now that the Redis servers are all set up, let's configure the Sentinel
servers. The following IPs will be used as an example:
@@ -1244,16 +1214,19 @@ servers. The following IPs will be used as an example:
- `10.6.0.82`: Sentinel - Queues 2
- `10.6.0.83`: Sentinel - Queues 3
-To configure the Sentinel Queues server:
+NOTE: **Note:**
+If you're using an external Redis Sentinel instance, be sure to exclude the
+`requirepass` parameter from the Sentinel configuration. This parameter causes
+clients to report `NOAUTH Authentication required.`.
+[Redis Sentinel 3.2.x doesn't support password authentication](https://github.com/antirez/redis/issues/3279).
-1. SSH into the server that will host Sentinel.
-1. [Download/install](https://about.gitlab.com/install/) the
- Omnibus GitLab Enterprise Edition package using **steps 1 and 2** from the
- GitLab downloads page.
- - Make sure you select the correct Omnibus package, with the same version
- the GitLab application is running.
- - Do not complete any other steps on the download page.
+To configure the Sentinel Queues server:
+1. SSH in to the server that will host Sentinel.
+1. [Download and install](https://about.gitlab.com/install/) the Omnibus GitLab
+ package of your choice. Be sure to both follow _only_ installation steps 1 and 2
+ on the page, and to select the correct Omnibus GitLab package, with the same version
+ and type (Community or Enterprise editions) as your current install.
1. Edit `/etc/gitlab/gitlab.rb` and add the contents:
```ruby
@@ -1362,52 +1335,48 @@ To configure the Sentinel Queues server:
## Configure Gitaly
-Deploying Gitaly in its own server can benefit GitLab installations that are
-larger than a single machine.
-
-The Gitaly node requirements are dependent on customer data, specifically the number of
-projects and their repository sizes. Two nodes are recommended as an absolute minimum.
-Each Gitaly node should store no more than 5TB of data and have the number of
-[`gitaly-ruby` workers](../gitaly/index.md#gitaly-ruby) set to 20% of available CPUs.
-Additional nodes should be considered in conjunction with a review of expected
-data size and spread based on the recommendations above.
-
-It is also strongly recommended that all Gitaly nodes be set up with SSD disks with
-a throughput of at least 8,000 IOPS for read operations and 2,000 IOPS for write,
-as Gitaly has heavy I/O. These IOPS values are recommended only as a starter as with
-time they may be adjusted higher or lower depending on the scale of your environment's workload.
-If you're running the environment on a Cloud provider, you may need to refer to
-their documentation on how to configure IOPS correctly.
-
-Some things to note:
-
-- The GitLab Rails application shards repositories into [repository storages](../repository_storage_paths.md).
-- A Gitaly server can host one or more storages.
-- A GitLab server can use one or more Gitaly servers.
-- Gitaly addresses must be specified in such a way that they resolve
- correctly for ALL Gitaly clients.
+[Gitaly](../gitaly/index.md) server node requirements are dependent on data,
+specifically the number of projects and those projects' sizes. It's recommended
+that a Gitaly server node stores no more than 5 TB of data. Although this
+reference architecture includes a recommendation for the number of Gitaly server
+nodes to use, depending on your storage requirements, you may require additional
+Gitaly server nodes.
+
+Due to Gitaly having notable input and output requirements, we strongly
+recommend that all Gitaly nodes use solid-state drives (SSDs). These SSDs should
+have a throughput of at least 8,000 input/output operations per second (IOPS)
+for read operations and 2,000 IOPS for write operations. These IOPS values are
+initial recommendations, and may be adjusted to greater or lesser values
+depending on the scale of your environment's workload. If you're running the
+environment on a Cloud provider, refer to their documentation about how to
+configure IOPS correctly.
+
+Be sure to note the following items:
+
+- The GitLab Rails application shards repositories into
+ [repository storage paths](../repository_storage_paths.md).
+- A Gitaly server can host one or more storage paths.
+- A GitLab server can use one or more Gitaly server nodes.
+- Gitaly addresses must be specified to be correctly resolvable for _all_
+ Gitaly clients.
- Gitaly servers must not be exposed to the public internet, as Gitaly's network
traffic is unencrypted by default. The use of a firewall is highly recommended
to restrict access to the Gitaly server. Another option is to
[use TLS](#gitaly-tls-support).
-TIP: **Tip:**
-For more information about Gitaly's history and network architecture see the
-[standalone Gitaly documentation](../gitaly/index.md).
-
-Note: **Note:**
-The token referred to throughout the Gitaly documentation is
-just an arbitrary password selected by the administrator. It is unrelated to
-tokens created for the GitLab API or other similar web API tokens.
+NOTE: **Note:**
+The token referred to throughout the Gitaly documentation is an arbitrary
+password selected by the administrator. This token is unrelated to tokens
+created for the GitLab API or other similar web API tokens.
-Below we describe how to configure two Gitaly servers, with IPs and
-domain names:
+This section describes how to configure two Gitaly servers, with the following
+IPs and domain names:
- `10.6.0.91`: Gitaly 1 (`gitaly1.internal`)
- `10.6.0.92`: Gitaly 2 (`gitaly2.internal`)
-The secret token is assumed to be `gitalysecret` and that
-your GitLab installation has three repository storages:
+Assumptions about your servers include having the secret token be `gitalysecret`,
+and that your GitLab installation has three repository storages:
- `default` on Gitaly 1
- `storage1` on Gitaly 1
@@ -1415,11 +1384,11 @@ your GitLab installation has three repository storages:
On each node:
-1. [Download/Install](https://about.gitlab.com/install/) the Omnibus GitLab
- package you want using **steps 1 and 2** from the GitLab downloads page but
- **without** providing the `EXTERNAL_URL` value.
-1. Edit `/etc/gitlab/gitlab.rb` to configure storage paths, enable
- the network listener and configure the token:
+1. [Download and install](https://about.gitlab.com/install/) the Omnibus GitLab
+ package of your choice. Be sure to follow _only_ installation steps 1 and 2
+ on the page, and _do not_ provide the `EXTERNAL_URL` value.
+1. Edit `/etc/gitlab/gitlab.rb` to configure the storage paths, enable
+ the network listener, and configure the token:
<!--
updates to following example must also be made at
@@ -1467,39 +1436,39 @@ On each node:
```
1. Append the following to `/etc/gitlab/gitlab.rb` for each respective server:
- 1. On `gitaly1.internal`:
-
- ```ruby
- git_data_dirs({
- 'default' => {
- 'path' => '/var/opt/gitlab/git-data'
- },
- 'storage1' => {
- 'path' => '/mnt/gitlab/git-data'
- },
- })
- ```
-
- 1. On `gitaly2.internal`:
-
- ```ruby
- git_data_dirs({
- 'storage2' => {
- 'path' => '/mnt/gitlab/git-data'
- },
- })
- ```
+ - On `gitaly1.internal`:
+
+ ```ruby
+ git_data_dirs({
+ 'default' => {
+ 'path' => '/var/opt/gitlab/git-data'
+ },
+ 'storage1' => {
+ 'path' => '/mnt/gitlab/git-data'
+ },
+ })
+ ```
+
+ - On `gitaly2.internal`:
+
+ ```ruby
+ git_data_dirs({
+ 'storage2' => {
+ 'path' => '/mnt/gitlab/git-data'
+ },
+ })
+ ```
<!--
updates to following example must also be made at
https://gitlab.com/gitlab-org/charts/gitlab/blob/master/doc/advanced/external-gitaly/external-omnibus-gitaly.md#configure-omnibus-gitlab
-->
-1. Copy the `/etc/gitlab/gitlab-secrets.json` file from your Consul server, and replace
- the file of the same name on this server. If that file is not on this server,
- add the file from your Consul server to this server.
+1. Copy the `/etc/gitlab/gitlab-secrets.json` file from your Consul server, and
+ then replace the file of the same name on this server. If that file isn't on
+ this server, add the file from your Consul server to this server.
-1. Save the file and [reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure).
+1. Save the file, and then [reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure).
### Gitaly TLS support
@@ -1521,11 +1490,10 @@ Name. If you are addressing the Gitaly server by its IP address, you must add it
as a Subject Alternative Name to the certificate.
[gRPC does not support using an IP address as Common Name in a certificate](https://github.com/grpc/grpc/issues/2691).
-NOTE: **Note:**
-It is possible to configure Gitaly servers with both an
-unencrypted listening address `listen_addr` and an encrypted listening
-address `tls_listen_addr` at the same time. This allows you to do a
-gradual transition from unencrypted to encrypted traffic, if necessary.
+It's possible to configure Gitaly servers with both an unencrypted listening
+address (`listen_addr`) and an encrypted listening address (`tls_listen_addr`)
+at the same time. This allows you to do a gradual transition from unencrypted to
+encrypted traffic, if necessary.
To configure Gitaly with TLS:
@@ -1580,10 +1548,10 @@ The following IPs will be used as an example:
To configure the Sidekiq nodes, on each one:
-1. SSH into the Sidekiq server.
-1. [Download/install](https://about.gitlab.com/install/) the Omnibus GitLab package
-you want using steps 1 and 2 from the GitLab downloads page.
-**Do not complete any other steps on the download page.**
+1. SSH in to the Sidekiq server.
+1. [Download and install](https://about.gitlab.com/install/) the Omnibus GitLab
+ package of your choice. Be sure to follow _only_ installation steps 1 and 2
+ on the page.
1. Open `/etc/gitlab/gitlab.rb` with your editor:
```ruby
@@ -1701,15 +1669,14 @@ You can also run [multiple Sidekiq processes](../operations/extra_sidekiq_proces
## Configure GitLab Rails
-NOTE: **Note:**
-In our architectures we run each GitLab Rails node using the Puma webserver
-and have its number of workers set to 90% of available CPUs along with four threads. For
-nodes that are running Rails with other components the worker value should be reduced
-accordingly where we've found 50% achieves a good balance but this is dependent
-on workload.
-
This section describes how to configure the GitLab application (Rails) component.
+In our architecture, we run each GitLab Rails node using the Puma webserver, and
+have its number of workers set to 90% of available CPUs, with four threads. For
+nodes running Rails with other components, the worker value should be reduced
+accordingly. We've determined that a worker value of 50% achieves a good balance,
+but this is dependent on workload.
+
The following IPs will be used as an example:
- `10.6.0.111`: GitLab application 1
@@ -1718,10 +1685,9 @@ The following IPs will be used as an example:
On each node perform the following:
-1. Download/install Omnibus GitLab using **steps 1 and 2** from
- [GitLab downloads](https://about.gitlab.com/install/). Do not complete other
- steps on the download page.
-
+1. [Download and install](https://about.gitlab.com/install/) the Omnibus GitLab
+ package of your choice. Be sure to follow _only_ installation steps 1 and 2
+ on the page.
1. Copy the `/etc/gitlab/gitlab-secrets.json` file from your Consul server, and replace
the file of the same name on this server. If that file is not on this server,
add the file from your Consul server to this server.
@@ -1752,6 +1718,7 @@ On each node perform the following:
roles ['application_role']
gitaly['enable'] = false
nginx['enable'] = true
+ sidekiq['enable'] = false
## PostgreSQL connection details
# Disable PostgreSQL on the application node
@@ -1795,7 +1762,6 @@ On each node perform the following:
# Set the network addresses that the exporters used for monitoring will listen on
node_exporter['listen_address'] = '0.0.0.0:9100'
gitlab_workhorse['prometheus_listen_addr'] = '0.0.0.0:9229'
- sidekiq['listen_address'] = "0.0.0.0"
puma['listen'] = '0.0.0.0'
# Add the monitoring node's IP address to the monitoring whitelist and allow it to
@@ -1836,7 +1802,7 @@ On each node perform the following:
1. Specify the necessary NFS mounts in `/etc/fstab`.
The exact contents of `/etc/fstab` will depend on how you chose
- to configure your NFS server. See the [NFS documentation](../high_availability/nfs.md)
+ to configure your NFS server. See the [NFS documentation](../nfs.md)
for examples and the various options.
1. Create the shared directories. These may be different depending on your NFS
@@ -1877,30 +1843,31 @@ On each node perform the following:
1. Optionally, from the Gitaly servers, confirm that Gitaly can perform callbacks to the internal API:
```shell
- sudo /opt/gitlab/embedded/service/gitlab-shell/bin/check -config /opt/gitlab/embedded/service/gitlab-shell/config.yml
+ sudo /opt/gitlab/embedded/bin/gitaly-hooks check /var/opt/gitlab/gitaly/config.toml
```
-NOTE: **Note:**
-When you specify `https` in the `external_url`, as in the example
-above, GitLab assumes you have SSL certificates in `/etc/gitlab/ssl/`. If
-certificates are not present, NGINX will fail to start. See the
-[NGINX documentation](https://docs.gitlab.com/omnibus/settings/nginx.html#enable-https)
-for more information.
+When you specify `https` in the `external_url`, as in the previous example,
+GitLab expects that the SSL certificates are in `/etc/gitlab/ssl/`. If the
+certificates aren't present, NGINX will fail to start. For more information, see
+the [NGINX documentation](https://docs.gitlab.com/omnibus/settings/nginx.html#enable-https).
### GitLab Rails post-configuration
-Initialize the GitLab database, by running the following in one of the Rails nodes:
+1. Designate one application node for running database migrations during
+ installation and updates. Initialize the GitLab database and ensure all
+ migrations ran:
-```shell
-sudo gitlab-rake gitlab:db:configure
-```
+ ```shell
+ sudo gitlab-rake gitlab:db:configure
+ ```
-NOTE: **Note:**
-If you encounter a `rake aborted!` error stating that PgBouncer is failing to connect to
-PostgreSQL it may be that your PgBouncer node's IP address is missing from
-PostgreSQL's `trust_auth_cidr_addresses` in `gitlab.rb` on your database nodes. See
-[PgBouncer error `ERROR: pgbouncer cannot connect to server`](troubleshooting.md#pgbouncer-error-error-pgbouncer-cannot-connect-to-server)
-in the Troubleshooting section before proceeding.
+ If you encounter a `rake aborted!` error message stating that PgBouncer is
+ failing to connect to PostgreSQL, it may be that your PgBouncer node's IP
+ address is missing from PostgreSQL's `trust_auth_cidr_addresses` in `gitlab.rb`
+ on your database nodes. Before proceeding, see
+ [PgBouncer error `ERROR: pgbouncer cannot connect to server`](troubleshooting.md#pgbouncer-error-error-pgbouncer-cannot-connect-to-server).
+
+1. [Configure fast lookup of authorized SSH keys in the database](../operations/fast_ssh_key_lookup.md).
<div align="right">
<a type="button" class="btn btn-default" href="#setup-components">
@@ -1920,11 +1887,10 @@ The following IP will be used as an example:
To configure the Monitoring node:
-1. SSH into the Monitoring node.
-1. [Download/install](https://about.gitlab.com/install/) the Omnibus GitLab
- package you want using **steps 1 and 2** from the GitLab downloads page.
- Do not complete any other steps on the download page.
-
+1. SSH in to the Monitoring node.
+1. [Download and install](https://about.gitlab.com/install/) the Omnibus GitLab
+ package of your choice. Be sure to follow _only_ installation steps 1 and 2
+ on the page.
1. Copy the `/etc/gitlab/gitlab-secrets.json` file from your Consul server, and replace
the file of the same name on this server. If that file is not on this server,
add the file from your Consul server to this server.
@@ -1988,28 +1954,44 @@ It's recommended over [NFS](#configure-nfs-optional) and in general it's better
in larger setups as object storage is typically much more performant, reliable,
and scalable.
-Object storage options that GitLab has tested, or is aware of customers using include:
+GitLab has been tested on a number of object storage providers:
-- SaaS/Cloud solutions such as [Amazon S3](https://aws.amazon.com/s3/), [Google cloud storage](https://cloud.google.com/storage).
+- [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)
+- [Openstack Swift](https://docs.openstack.org/swift/latest/s3_compat.html)
+- [Azure Blob storage](https://docs.microsoft.com/en-us/azure/storage/blobs/storage-blobs-introduction)
- On-premises hardware and appliances from various storage vendors.
-- MinIO. There is [a guide to deploying this](https://docs.gitlab.com/charts/advanced/external-object-storage/minio.html) within our Helm Chart documentation.
-
-For configuring GitLab to use Object Storage refer to the following guides
-based on what features you intend to use:
-
-1. Configure [object storage for backups](../../raketasks/backup_restore.md#uploading-backups-to-a-remote-cloud-storage).
-1. Configure [object storage for job artifacts](../job_artifacts.md#using-object-storage)
- including [incremental logging](../job_logs.md#new-incremental-logging-architecture).
-1. Configure [object storage for LFS objects](../lfs/index.md#storing-lfs-objects-in-remote-object-storage).
-1. Configure [object storage for uploads](../uploads.md#using-object-storage).
-1. Configure [object storage for merge request diffs](../merge_request_diffs.md#using-object-storage).
-1. Configure [object storage for Container Registry](../packages/container_registry.md#use-object-storage) (optional feature).
-1. Configure [object storage for Mattermost](https://docs.mattermost.com/administration/config-settings.html#file-storage) (optional feature).
-1. Configure [object storage for packages](../packages/index.md#using-object-storage) (optional feature). **(PREMIUM ONLY)**
-1. Configure [object storage for Dependency Proxy](../packages/dependency_proxy.md#using-object-storage) (optional feature). **(PREMIUM ONLY)**
-1. Configure [object storage for Pseudonymizer](../pseudonymizer.md#configuration) (optional feature). **(ULTIMATE ONLY)**
-1. Configure [object storage for autoscale runner caching](https://docs.gitlab.com/runner/configuration/autoscale.html#distributed-runners-caching) (optional - for improved performance).
-1. Configure [object storage for Terraform state files](../terraform_state.md#using-object-storage).
+- MinIO. We have [a guide to deploying this](https://docs.gitlab.com/charts/advanced/external-object-storage/minio.html) within our Helm Chart documentation.
+
+There are two ways of specifying object storage configuration in GitLab:
+
+- [Consolidated form](../object_storage.md#consolidated-object-storage-configuration): A single credential is
+ shared by all supported object types.
+- [Storage-specific form](../object_storage.md#storage-specific-configuration): Every object defines its
+ own object storage [connection and configuration](../object_storage.md#connection-settings).
+
+Starting with GitLab 13.2, consolidated object storage configuration is available. It simplifies your GitLab configuration since the connection details are shared across object types. Refer to [Consolidated object storage configuration](../object_storage.md#consolidated-object-storage-configuration) guide for instructions on how to set it up.
+
+For configuring object storage in GitLab 13.1 and earlier, or for storage types not
+supported by consolidated configuration form, refer to the following guides based
+on what features you intend to use:
+
+|Object storage type|Supported by consolidated configuration?|
+|-------------------|----------------------------------------|
+| [Backups](../../raketasks/backup_restore.md#uploading-backups-to-a-remote-cloud-storage)|No|
+| [Job artifacts](../job_artifacts.md#using-object-storage) including archived job logs | Yes |
+| [LFS objects](../lfs/index.md#storing-lfs-objects-in-remote-object-storage) | Yes |
+| [Uploads](../uploads.md#using-object-storage) | Yes |
+| [Container Registry](../packages/container_registry.md#use-object-storage) (optional feature) | No |
+| [Merge request diffs](../merge_request_diffs.md#using-object-storage) | Yes |
+| [Mattermost](https://docs.mattermost.com/administration/config-settings.html#file-storage)| No |
+| [Packages](../packages/index.md#using-object-storage) (optional feature) | Yes |
+| [Dependency Proxy](../packages/dependency_proxy.md#using-object-storage) (optional feature) **(PREMIUM ONLY)** | Yes |
+| [Pseudonymizer](../pseudonymizer.md#configuration) (optional feature) **(ULTIMATE ONLY)** | No |
+| [Autoscale runner caching](https://docs.gitlab.com/runner/configuration/autoscale.html#distributed-runners-caching) (optional for improved performance) | No |
+| [Terraform state files](../terraform_state.md#using-object-storage) | Yes |
Using separate buckets for each data type is the recommended approach for GitLab.
@@ -2033,13 +2015,29 @@ work.
</a>
</div>
+## Configure Advanced Search **(STARTER ONLY)**
+
+You can leverage Elasticsearch and [enable Advanced Search](../../integration/elasticsearch.md)
+for faster, more advanced code search across your entire GitLab instance.
+
+Elasticsearch cluster design and requirements are dependent on your specific
+data. For recommended best practices about how to set up your Elasticsearch
+cluster alongside your instance, read how to
+[choose the optimal cluster configuration](../../integration/elasticsearch.md#guidance-on-choosing-optimal-cluster-configuration).
+
+<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>
+
## Configure NFS (optional)
[Object storage](#configure-the-object-storage), along with [Gitaly](#configure-gitaly)
are recommended over NFS wherever possible for improved performance. If you intend
to use GitLab Pages, this currently [requires NFS](troubleshooting.md#gitlab-pages-requires-nfs).
-See how to [configure NFS](../high_availability/nfs.md).
+See how to [configure NFS](../nfs.md).
<div align="right">
<a type="button" class="btn btn-default" href="#setup-components">
diff --git a/doc/administration/reference_architectures/1k_users.md b/doc/administration/reference_architectures/1k_users.md
index d376c1b7575..0cb7b8868c3 100644
--- a/doc/administration/reference_architectures/1k_users.md
+++ b/doc/administration/reference_architectures/1k_users.md
@@ -20,8 +20,8 @@ many organizations .
| Users | Configuration | GCP | AWS | Azure |
|--------------|-------------------------|----------------|-----------------|----------------|
-| Up to 500 | 4 vCPU, 3.6GB memory | n1-highcpu-4 | c5.xlarge | F4s v2 |
-| Up to 1,000 | 8 vCPU, 7.2GB memory | n1-highcpu-8 | c5.2xlarge | F8s v2 |
+| Up to 500 | 4 vCPU, 3.6 GB memory | n1-highcpu-4 | c5.xlarge | F4s v2 |
+| Up to 1,000 | 8 vCPU, 7.2 GB memory | n1-highcpu-8 | c5.2xlarge | F8s v2 |
The Google Cloud Platform (GCP) architectures were built and tested using the
[Intel Xeon E5 v3 (Haswell)](https://cloud.google.com/compute/docs/cpu-platforms)
@@ -30,20 +30,28 @@ or higher, are required for your CPU or node counts. For more information, see
our [Sysbench](https://github.com/akopytov/sysbench)-based
[CPU benchmark](https://gitlab.com/gitlab-org/quality/performance/-/wikis/Reference-Architectures/GCP-CPU-Benchmarks).
-In addition to the stated configurations, we recommend having at least 2GB of
+In addition to the stated configurations, we recommend having at least 2 GB of
swap on your server, even if you currently have enough available memory. Having
-swap will help reduce the chance of errors occurring if your available memory
+swap helps to reduce the chance of errors occurring if your available memory
changes. We also recommend configuring the kernel's swappiness setting to a
lower value (such as `10`) to make the most of your memory, while still having
the swap available when needed.
## Setup instructions
-For this default reference architecture, to install GitLab use the standard
+To install GitLab for this default reference architecture, use the standard
[installation instructions](../../install/README.md).
-NOTE: **Note:**
-You can also optionally configure GitLab to use an
-[external PostgreSQL service](../postgresql/external.md) or an
-[external object storage service](../high_availability/object_storage.md) for
-added performance and reliability at a reduced complexity cost.
+You can also optionally configure GitLab to use an [external PostgreSQL service](../postgresql/external.md)
+or an [external object storage service](../object_storage.md) for added
+performance and reliability at a reduced complexity cost.
+
+## Configure Advanced Search **(STARTER ONLY)**
+
+You can leverage Elasticsearch and [enable Advanced Search](../../integration/elasticsearch.md)
+for faster, more advanced code search across your entire GitLab instance.
+
+Elasticsearch cluster design and requirements are dependent on your specific
+data. For recommended best practices about how to set up your Elasticsearch
+cluster alongside your instance, read how to
+[choose the optimal cluster configuration](../../integration/elasticsearch.md#guidance-on-choosing-optimal-cluster-configuration).
diff --git a/doc/administration/reference_architectures/25k_users.md b/doc/administration/reference_architectures/25k_users.md
index 2ef555bff29..bb6e2eb4376 100644
--- a/doc/administration/reference_architectures/25k_users.md
+++ b/doc/administration/reference_architectures/25k_users.md
@@ -17,21 +17,21 @@ full list of reference architectures, see
| Service | Nodes | Configuration | GCP | AWS | Azure |
|-----------------------------------------|-------------|-------------------------|-----------------|-------------|----------|
-| External load balancing node | 1 | 4 vCPU, 3.6GB memory | n1-highcpu-4 | c5.xlarge | F4s v2 |
-| Consul | 3 | 2 vCPU, 1.8GB memory | n1-highcpu-2 | c5.large | F2s v2 |
-| PostgreSQL | 3 | 8 vCPU, 30GB memory | n1-standard-8 | m5.2xlarge | D8s v3 |
-| PgBouncer | 3 | 2 vCPU, 1.8GB memory | n1-highcpu-2 | c5.large | F2s v2 |
-| Internal load balancing node | 1 | 2 vCPU, 1.8GB memory | n1-highcpu-2 | c5.large | F2s v2 |
-| Redis - Cache | 3 | 4 vCPU, 15GB memory | n1-standard-4 | m5.xlarge | D4s v3 |
-| Redis - Queues / Shared State | 3 | 4 vCPU, 15GB memory | n1-standard-4 | m5.xlarge | D4s v3 |
-| Redis Sentinel - Cache | 3 | 1 vCPU, 1.7GB memory | g1-small | t2.small | B1MS |
-| Redis Sentinel - Queues / Shared State | 3 | 1 vCPU, 1.7GB memory | g1-small | t2.small | B1MS |
-| Gitaly | 2 (minimum) | 32 vCPU, 120GB memory | n1-standard-32 | m5.8xlarge | D32s v3 |
-| Sidekiq | 4 | 4 vCPU, 15GB memory | n1-standard-4 | m5.xlarge | D4s v3 |
-| GitLab Rails | 5 | 32 vCPU, 28.8GB memory | n1-highcpu-32 | c5.9xlarge | F32s v2 |
-| Monitoring node | 1 | 4 vCPU, 3.6GB memory | n1-highcpu-4 | c5.xlarge | F4s v2 |
-| Object Storage | n/a | n/a | n/a | n/a | n/a |
-| NFS Server | 1 | 4 vCPU, 3.6GB memory | n1-highcpu-4 | c5.xlarge | F4s v2 |
+| External load balancing node | 1 | 4 vCPU, 3.6 GB memory | n1-highcpu-4 | c5.xlarge | F4s v2 |
+| Consul | 3 | 2 vCPU, 1.8 GB memory | n1-highcpu-2 | c5.large | F2s v2 |
+| PostgreSQL | 3 | 8 vCPU, 30 GB memory | n1-standard-8 | m5.2xlarge | D8s v3 |
+| PgBouncer | 3 | 2 vCPU, 1.8 GB memory | n1-highcpu-2 | c5.large | F2s v2 |
+| Internal load balancing node | 1 | 4 vCPU, 3.6GB memory | n1-highcpu-4 | c5.large | F2s v2 |
+| Redis - Cache | 3 | 4 vCPU, 15 GB memory | n1-standard-4 | m5.xlarge | D4s v3 |
+| Redis - Queues / Shared State | 3 | 4 vCPU, 15 GB memory | n1-standard-4 | m5.xlarge | D4s v3 |
+| Redis Sentinel - Cache | 3 | 1 vCPU, 1.7 GB memory | g1-small | t2.small | B1MS |
+| Redis Sentinel - Queues / Shared State | 3 | 1 vCPU, 1.7 GB memory | g1-small | t2.small | B1MS |
+| Gitaly | 2 (minimum) | 32 vCPU, 120 GB memory | n1-standard-32 | m5.8xlarge | D32s v3 |
+| Sidekiq | 4 | 4 vCPU, 15 GB memory | n1-standard-4 | m5.xlarge | D4s v3 |
+| GitLab Rails | 5 | 32 vCPU, 28.8 GB memory | n1-highcpu-32 | c5.9xlarge | F32s v2 |
+| Monitoring node | 1 | 4 vCPU, 3.6 GB memory | n1-highcpu-4 | c5.xlarge | F4s v2 |
+| Object storage | n/a | n/a | n/a | n/a | n/a |
+| NFS server | 1 | 4 vCPU, 3.6 GB memory | n1-highcpu-4 | c5.xlarge | F4s v2 |
The Google Cloud Platform (GCP) architectures were built and tested using the
[Intel Xeon E5 v3 (Haswell)](https://cloud.google.com/compute/docs/cpu-platforms)
@@ -40,41 +40,43 @@ or higher, are required for your CPU or node counts. For more information, see
our [Sysbench](https://github.com/akopytov/sysbench)-based
[CPU benchmark](https://gitlab.com/gitlab-org/quality/performance/-/wikis/Reference-Architectures/GCP-CPU-Benchmarks).
-For data objects (such as LFS, Uploads, or Artifacts), an
-[object storage service](#configure-the-object-storage) is recommended instead
-of NFS where possible, due to better performance and availability. Since this
-doesn't require a node to be set up, *Object Storage* is noted as not
-applicable (n/a) in the previous table.
+Due to better performance and availability, for data objects (such as LFS,
+uploads, or artifacts), using an [object storage service](#configure-the-object-storage)
+is recommended instead of using NFS. Using an object storage service also
+doesn't require you to provision and maintain a node.
## Setup components
To set up GitLab and its components to accommodate up to 25,000 users:
1. [Configure the external load balancing node](#configure-the-external-load-balancer)
- that will handle the load balancing of the three GitLab application services nodes.
+ to handle the load balancing of the GitLab application services nodes.
1. [Configure Consul](#configure-consul).
1. [Configure PostgreSQL](#configure-postgresql), the database for GitLab.
1. [Configure PgBouncer](#configure-pgbouncer).
-1. [Configure the internal load balancing node](#configure-the-internal-load-balancer)
+1. [Configure the internal load balancing node](#configure-the-internal-load-balancer).
1. [Configure Redis](#configure-redis).
1. [Configure Gitaly](#configure-gitaly),
which provides access to the Git repositories.
1. [Configure Sidekiq](#configure-sidekiq).
1. [Configure the main GitLab Rails application](#configure-gitlab-rails)
- to run Puma/Unicorn, Workhorse, GitLab Shell, and to serve all frontend requests (UI, API, Git
- over HTTP/SSH).
-1. [Configure Prometheus](#configure-prometheus) to monitor your GitLab environment.
-1. [Configure the Object Storage](#configure-the-object-storage)
+ to run Puma/Unicorn, Workhorse, GitLab Shell, and to serve all frontend
+ requests (which include UI, API, and Git over HTTP/SSH).
+1. [Configure Prometheus](#configure-prometheus) to monitor your GitLab
+ environment.
+1. [Configure the object storage](#configure-the-object-storage)
used for shared data objects.
-1. [Configure NFS (Optional)](#configure-nfs-optional)
- to have shared disk storage service as an alternative to Gitaly and/or Object Storage (although
- not recommended). NFS is required for GitLab Pages, you can skip this step if you're not using
- that feature.
+1. [Configure Advanced Search](#configure-advanced-search) (optional) for faster,
+ more advanced code search across your entire GitLab instance.
+1. [Configure NFS](#configure-nfs-optional) (optional, and not recommended)
+ to have shared disk storage service as an alternative to Gitaly or object
+ storage. You can skip this step if you're not using GitLab Pages (which
+ requires NFS).
-We start with all servers on the same 10.6.0.0/24 private network range, they
-can connect to each other freely on those addresses.
+The servers start on the same 10.6.0.0/24 private network range, and can
+connect to each other freely on these addresses.
-Here is a list and description of each machine and the assigned IP:
+The following list includes descriptions of each server and its assigned IP:
- `10.6.0.10`: External Load Balancer
- `10.6.0.11`: Consul 1
@@ -112,19 +114,18 @@ Here is a list and description of each machine and the assigned IP:
## Configure the external load balancer
-NOTE: **Note:**
+In an active/active 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 hope
+that if you're managing multi-node systems like GitLab, you already have a load
+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.
+
This architecture has been tested and validated with [HAProxy](https://www.haproxy.org/)
as the load balancer. Although other load balancers with similar feature sets
could also be used, those load balancers have not been validated.
-In an active/active GitLab configuration, you will need a load balancer to route
-traffic to the application servers. The specifics on which load balancer to use
-or the exact configuration is beyond the scope of GitLab documentation. We hope
-that if you're managing multi-node systems like GitLab you have a load balancer of
-choice already. Some examples including HAProxy (open-source), F5 Big-IP LTM,
-and Citrix Net Scaler. This documentation will outline what ports and protocols
-you need to use with GitLab.
-
The next question is how you will handle SSL in your environment.
There are several different options:
@@ -247,14 +248,11 @@ with the other servers.
To configure Consul:
-1. SSH into the server that will host Consul.
-1. [Download/install](https://about.gitlab.com/install/) the
- Omnibus GitLab Enterprise Edition package using **steps 1 and 2** from the
- GitLab downloads page.
- - Make sure you select the correct Omnibus package, with the same version
- the GitLab application is running.
- - Do not complete any other steps on the download page.
-
+1. SSH in to the server that will host Consul.
+1. [Download and install](https://about.gitlab.com/install/) the Omnibus GitLab
+ package of your choice. Be sure to both follow _only_ installation steps 1 and 2
+ on the page, and to select the correct Omnibus GitLab package, with the same version
+ and type (Community or Enterprise editions) as your current install.
1. Edit `/etc/gitlab/gitlab.rb` and add the contents:
```ruby
@@ -282,10 +280,9 @@ To configure Consul:
1. Go through the steps again for all the other Consul nodes, and
make sure you set up the correct IPs.
-NOTE: **Note:**
-A Consul leader will be elected when the provisioning of the third Consul server is completed.
-Viewing the Consul logs `sudo gitlab-ctl tail consul` will display
-`...[INFO] consul: New leader elected: ...`
+A Consul leader is _elected_ when the provisioning of the third Consul server is
+complete. Viewing the Consul logs `sudo gitlab-ctl tail consul` displays
+`...[INFO] consul: New leader elected: ...`.
You can list the current Consul members (server, client):
@@ -352,7 +349,7 @@ in the second step, do not supply the `EXTERNAL_URL` value.
#### PostgreSQL primary node
-1. SSH into the PostgreSQL primary node.
+1. SSH in to the PostgreSQL primary node.
1. Generate a password hash for the PostgreSQL username/password pair. This assumes you will use the default
username of `gitlab` (recommended). The command will request a password
and confirmation. Use the value that is output by this command in the next
@@ -513,7 +510,7 @@ are supported and can be added if needed.
#### PostgreSQL post-configuration
-SSH into the **primary node**:
+SSH in to the **primary node**:
1. Open a database prompt:
@@ -548,7 +545,7 @@ SSH into the **primary node**:
is not an IP address, it will need to be a resolvable name (via DNS or
`/etc/hosts`)
-SSH into the **secondary node**:
+SSH in to the **secondary node**:
1. Set up the repmgr standby:
@@ -662,7 +659,6 @@ The following IPs will be used as an example:
1. [Reconfigure Omnibus GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure) for the changes to take effect.
- NOTE: **Note:**
If an error `execute[generate databases.ini]` occurs, this is due to an existing
[known issue](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/4713).
It will be resolved when you run a second `reconfigure` after the next step.
@@ -796,35 +792,31 @@ to be used with GitLab. The following IPs will be used as an example:
- `10.6.0.82`: Sentinel - Queues 2
- `10.6.0.83`: Sentinel - Queues 3
-NOTE: **Providing your own Redis instance:**
-Managed Redis from cloud providers such as AWS ElastiCache will work. If these
-services support high availability, be sure it is **not** the Redis Cluster type.
-Redis version 5.0 or higher is required, as this is what ships with
-Omnibus GitLab packages starting with GitLab 13.0. Older Redis versions
-do not support an optional count argument to SPOP which is now required for
-[Merge Trains](../../ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/index.md).
+### Providing your own Redis instance
+
+Managed Redis from cloud providers (such as AWS ElastiCache) will work. If these
+services support high availability, be sure it _isn't_ of the Redis Cluster type.
+Redis version 5.0 or higher is required, which is included with Omnibus GitLab
+packages starting with GitLab 13.0. Older Redis versions don't support an
+optional count argument to SPOP, which is required for [Merge Trains](../../ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/index.md).
Note the Redis node's IP address or hostname, port, and password (if required).
-These will be necessary when configuring the
-[GitLab application servers](#configure-gitlab-rails) later.
+These will be necessary later when configuring the [GitLab application servers](#configure-gitlab-rails).
### Configure the Redis and Sentinel Cache cluster
This is the section where we install and set up the new Redis Cache instances.
-NOTE: **Note:**
-Redis nodes (both primary and replica) will need the same password defined in
-`redis['password']`. At any time during a failover the Sentinels can
-reconfigure a node and change its status from primary to replica and vice versa.
+Both the primary and replica Redis nodes need the same password defined in
+`redis['password']`. At any time during a failover, the Sentinels can reconfigure
+a node and change its status from primary to replica (and vice versa).
#### Configure the primary Redis Cache node
-1. SSH into the **Primary** Redis server.
-1. [Download/install](https://about.gitlab.com/install/) the Omnibus GitLab
- package you want using **steps 1 and 2** from the GitLab downloads page.
- - Make sure you select the correct Omnibus package, with the same version
- and type (Community, Enterprise editions) of your current install.
- - Do not complete any other steps on the download page.
-
+1. SSH in to the **Primary** Redis server.
+1. [Download and install](https://about.gitlab.com/install/) the Omnibus GitLab
+ package of your choice. Be sure to both follow _only_ installation steps 1 and 2
+ on the page, and to select the correct Omnibus GitLab package, with the same version
+ and type (Community or Enterprise editions) as your current install.
1. Edit `/etc/gitlab/gitlab.rb` and add the contents:
```ruby
@@ -868,20 +860,17 @@ reconfigure a node and change its status from primary to replica and vice versa.
1. [Reconfigure Omnibus GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure) for the changes to take effect.
-NOTE: **Note:**
-You can specify multiple roles like sentinel and Redis as:
-`roles ['redis_sentinel_role', 'redis_master_role']`.
-Read more about [roles](https://docs.gitlab.com/omnibus/roles/).
+You can specify multiple roles, like sentinel and Redis, as:
+`roles ['redis_sentinel_role', 'redis_master_role']`. Read more about
+[roles](https://docs.gitlab.com/omnibus/roles/).
#### Configure the replica Redis Cache nodes
-1. SSH into the **replica** Redis server.
-1. [Download/install](https://about.gitlab.com/install/) the Omnibus GitLab
- package you want using **steps 1 and 2** from the GitLab downloads page.
- - Make sure you select the correct Omnibus package, with the same version
- and type (Community, Enterprise editions) of your current install.
- - Do not complete any other steps on the download page.
-
+1. SSH in to the **replica** Redis server.
+1. [Download and install](https://about.gitlab.com/install/) the Omnibus GitLab
+ package of your choice. Be sure to both follow _only_ installation steps 1 and 2
+ on the page, and to select the correct Omnibus GitLab package, with the same version
+ and type (Community or Enterprise editions) as your current install.
1. Edit `/etc/gitlab/gitlab.rb` and add the contents:
```ruby
@@ -934,10 +923,9 @@ Read more about [roles](https://docs.gitlab.com/omnibus/roles/).
1. Go through the steps again for all the other replica nodes, and
make sure to set up the IPs correctly.
-NOTE: **Note:**
-You can specify multiple roles like sentinel and Redis as:
-`roles ['redis_sentinel_role', 'redis_master_role']`.
-Read more about [roles](https://docs.gitlab.com/omnibus/roles/).
+You can specify multiple roles, like sentinel and Redis, as:
+`roles ['redis_sentinel_role', 'redis_master_role']`. Read more about
+[roles](https://docs.gitlab.com/omnibus/roles/).
These values don't have to be changed again in `/etc/gitlab/gitlab.rb` after
a failover, as the nodes will be managed by the [Sentinels](#configure-the-sentinel-cache-nodes), and even after a
@@ -955,13 +943,6 @@ are supported and can be added if needed.
#### Configure the Sentinel Cache nodes
-NOTE: **Note:**
-If you are using an external Redis Sentinel instance, be sure
-to exclude the `requirepass` parameter from the Sentinel
-configuration. This parameter will cause clients to report `NOAUTH
-Authentication required.`. [Redis Sentinel 3.2.x does not support
-password authentication](https://github.com/antirez/redis/issues/3279).
-
Now that the Redis servers are all set up, let's configure the Sentinel
servers. The following IPs will be used as an example:
@@ -969,16 +950,19 @@ servers. The following IPs will be used as an example:
- `10.6.0.72`: Sentinel - Cache 2
- `10.6.0.73`: Sentinel - Cache 3
-To configure the Sentinel Cache server:
+NOTE: **Note:**
+If you're using an external Redis Sentinel instance, be sure to exclude the
+`requirepass` parameter from the Sentinel configuration. This parameter causes
+clients to report `NOAUTH Authentication required.`.
+[Redis Sentinel 3.2.x doesn't support password authentication](https://github.com/antirez/redis/issues/3279).
-1. SSH into the server that will host Consul/Sentinel.
-1. [Download/install](https://about.gitlab.com/install/) the
- Omnibus GitLab Enterprise Edition package using **steps 1 and 2** from the
- GitLab downloads page.
- - Make sure you select the correct Omnibus package, with the same version
- the GitLab application is running.
- - Do not complete any other steps on the download page.
+To configure the Sentinel Cache server:
+1. SSH in to the server that will host Consul/Sentinel.
+1. [Download and install](https://about.gitlab.com/install/) the Omnibus GitLab
+ package of your choice. Be sure to both follow _only_ installation steps 1 and 2
+ on the page, and to select the correct Omnibus GitLab package, with the same version
+ and type (Community or Enterprise editions) as your current install.
1. Edit `/etc/gitlab/gitlab.rb` and add the contents:
```ruby
@@ -1081,20 +1065,17 @@ To configure the Sentinel Cache server:
This is the section where we install and set up the new Redis Queues instances.
-NOTE: **Note:**
-Redis nodes (both primary and replica) will need the same password defined in
-`redis['password']`. At any time during a failover the Sentinels can
-reconfigure a node and change its status from primary to replica and vice versa.
+Both the primary and replica Redis nodes need the same password defined in
+`redis['password']`. At any time during a failover, the Sentinels can reconfigure
+a node and change its status from primary to replica (and vice versa).
#### Configure the primary Redis Queues node
-1. SSH into the **Primary** Redis server.
-1. [Download/install](https://about.gitlab.com/install/) the Omnibus GitLab
- package you want using **steps 1 and 2** from the GitLab downloads page.
- - Make sure you select the correct Omnibus package, with the same version
- and type (Community, Enterprise editions) of your current install.
- - Do not complete any other steps on the download page.
-
+1. SSH in to the **Primary** Redis server.
+1. [Download and install](https://about.gitlab.com/install/) the Omnibus GitLab
+ package of your choice. Be sure to both follow _only_ installation steps 1 and 2
+ on the page, and to select the correct Omnibus GitLab package, with the same version
+ and type (Community or Enterprise editions) as your current install.
1. Edit `/etc/gitlab/gitlab.rb` and add the contents:
```ruby
@@ -1143,20 +1124,17 @@ reconfigure a node and change its status from primary to replica and vice versa.
1. [Reconfigure Omnibus GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure) for the changes to take effect.
-NOTE: **Note:**
-You can specify multiple roles like sentinel and Redis as:
-`roles ['redis_sentinel_role', 'redis_master_role']`.
-Read more about [roles](https://docs.gitlab.com/omnibus/roles/).
+You can specify multiple roles, like sentinel and Redis, as:
+`roles ['redis_sentinel_role', 'redis_master_role']`. Read more about
+[roles](https://docs.gitlab.com/omnibus/roles/).
#### Configure the replica Redis Queues nodes
-1. SSH into the **replica** Redis Queue server.
-1. [Download/install](https://about.gitlab.com/install/) the Omnibus GitLab
- package you want using **steps 1 and 2** from the GitLab downloads page.
- - Make sure you select the correct Omnibus package, with the same version
- and type (Community, Enterprise editions) of your current install.
- - Do not complete any other steps on the download page.
-
+1. SSH in to the **replica** Redis Queue server.
+1. [Download and install](https://about.gitlab.com/install/) the Omnibus GitLab
+ package of your choice. Be sure to both follow _only_ installation steps 1 and 2
+ on the page, and to select the correct Omnibus GitLab package, with the same version
+ and type (Community or Enterprise editions) as your current install.
1. Edit `/etc/gitlab/gitlab.rb` and add the contents:
```ruby
@@ -1209,10 +1187,9 @@ Read more about [roles](https://docs.gitlab.com/omnibus/roles/).
1. Go through the steps again for all the other replica nodes, and
make sure to set up the IPs correctly.
-NOTE: **Note:**
-You can specify multiple roles like sentinel and Redis as:
-`roles ['redis_sentinel_role', 'redis_master_role']`.
-Read more about [roles](https://docs.gitlab.com/omnibus/roles/).
+You can specify multiple roles, like sentinel and Redis, as:
+`roles ['redis_sentinel_role', 'redis_master_role']`. Read more about
+[roles](https://docs.gitlab.com/omnibus/roles/).
These values don't have to be changed again in `/etc/gitlab/gitlab.rb` after
a failover, as the nodes will be managed by the [Sentinels](#configure-the-sentinel-queues-nodes), and even after a
@@ -1230,13 +1207,6 @@ are supported and can be added if needed.
#### Configure the Sentinel Queues nodes
-NOTE: **Note:**
-If you are using an external Redis Sentinel instance, be sure
-to exclude the `requirepass` parameter from the Sentinel
-configuration. This parameter will cause clients to report `NOAUTH
-Authentication required.`. [Redis Sentinel 3.2.x does not support
-password authentication](https://github.com/antirez/redis/issues/3279).
-
Now that the Redis servers are all set up, let's configure the Sentinel
servers. The following IPs will be used as an example:
@@ -1244,16 +1214,19 @@ servers. The following IPs will be used as an example:
- `10.6.0.82`: Sentinel - Queues 2
- `10.6.0.83`: Sentinel - Queues 3
-To configure the Sentinel Queues server:
+NOTE: **Note:**
+If you're using an external Redis Sentinel instance, be sure to exclude the
+`requirepass` parameter from the Sentinel configuration. This parameter causes
+clients to report `NOAUTH Authentication required.`.
+[Redis Sentinel 3.2.x doesn't support password authentication](https://github.com/antirez/redis/issues/3279).
-1. SSH into the server that will host Sentinel.
-1. [Download/install](https://about.gitlab.com/install/) the
- Omnibus GitLab Enterprise Edition package using **steps 1 and 2** from the
- GitLab downloads page.
- - Make sure you select the correct Omnibus package, with the same version
- the GitLab application is running.
- - Do not complete any other steps on the download page.
+To configure the Sentinel Queues server:
+1. SSH in to the server that will host Sentinel.
+1. [Download and install](https://about.gitlab.com/install/) the Omnibus GitLab
+ package of your choice. Be sure to both follow _only_ installation steps 1 and 2
+ on the page, and to select the correct Omnibus package, with the same version
+ and type (Community or Enterprise editions) as your current install.
1. Edit `/etc/gitlab/gitlab.rb` and add the contents:
```ruby
@@ -1362,52 +1335,48 @@ To configure the Sentinel Queues server:
## Configure Gitaly
-Deploying Gitaly in its own server can benefit GitLab installations that are
-larger than a single machine.
-
-The Gitaly node requirements are dependent on customer data, specifically the number of
-projects and their repository sizes. Two nodes are recommended as an absolute minimum.
-Each Gitaly node should store no more than 5TB of data and have the number of
-[`gitaly-ruby` workers](../gitaly/index.md#gitaly-ruby) set to 20% of available CPUs.
-Additional nodes should be considered in conjunction with a review of expected
-data size and spread based on the recommendations above.
-
-It is also strongly recommended that all Gitaly nodes be set up with SSD disks with
-a throughput of at least 8,000 IOPS for read operations and 2,000 IOPS for write,
-as Gitaly has heavy I/O. These IOPS values are recommended only as a starter as with
-time they may be adjusted higher or lower depending on the scale of your environment's workload.
-If you're running the environment on a Cloud provider, you may need to refer to
-their documentation on how to configure IOPS correctly.
-
-Some things to note:
-
-- The GitLab Rails application shards repositories into [repository storages](../repository_storage_paths.md).
-- A Gitaly server can host one or more storages.
-- A GitLab server can use one or more Gitaly servers.
-- Gitaly addresses must be specified in such a way that they resolve
- correctly for ALL Gitaly clients.
+[Gitaly](../gitaly/index.md) server node requirements are dependent on data,
+specifically the number of projects and those projects' sizes. It's recommended
+that a Gitaly server node stores no more than 5 TB of data. Although this
+reference architecture includes a recommendation for the number of Gitaly server
+nodes to use, depending on your storage requirements, you may require additional
+Gitaly server nodes.
+
+Due to Gitaly having notable input and output requirements, we strongly
+recommend that all Gitaly nodes use solid-state drives (SSDs). These SSDs should
+have a throughput of at least 8,000 input/output operations per second (IOPS)
+for read operations and 2,000 IOPS for write operations. These IOPS values are
+initial recommendations, and may be adjusted to greater or lesser values
+depending on the scale of your environment's workload. If you're running the
+environment on a Cloud provider, refer to their documentation about how to
+configure IOPS correctly.
+
+Be sure to note the following items:
+
+- The GitLab Rails application shards repositories into
+ [repository storage paths](../repository_storage_paths.md).
+- A Gitaly server can host one or more storage paths.
+- A GitLab server can use one or more Gitaly server nodes.
+- Gitaly addresses must be specified to be correctly resolvable for _all_
+ Gitaly clients.
- Gitaly servers must not be exposed to the public internet, as Gitaly's network
traffic is unencrypted by default. The use of a firewall is highly recommended
to restrict access to the Gitaly server. Another option is to
[use TLS](#gitaly-tls-support).
-TIP: **Tip:**
-For more information about Gitaly's history and network architecture see the
-[standalone Gitaly documentation](../gitaly/index.md).
-
-Note: **Note:**
-The token referred to throughout the Gitaly documentation is
-just an arbitrary password selected by the administrator. It is unrelated to
-tokens created for the GitLab API or other similar web API tokens.
+NOTE: **Note:**
+The token referred to throughout the Gitaly documentation is an arbitrary
+password selected by the administrator. This token is unrelated to tokens
+created for the GitLab API or other similar web API tokens.
-Below we describe how to configure two Gitaly servers, with IPs and
-domain names:
+This section describes how to configure two Gitaly servers, with the following
+IPs and domain names:
- `10.6.0.91`: Gitaly 1 (`gitaly1.internal`)
- `10.6.0.92`: Gitaly 2 (`gitaly2.internal`)
-The secret token is assumed to be `gitalysecret` and that
-your GitLab installation has three repository storages:
+Assumptions about your servers include having the secret token be `gitalysecret`,
+and that your GitLab installation has three repository storages:
- `default` on Gitaly 1
- `storage1` on Gitaly 1
@@ -1415,11 +1384,11 @@ your GitLab installation has three repository storages:
On each node:
-1. [Download/Install](https://about.gitlab.com/install/) the Omnibus GitLab
- package you want using **steps 1 and 2** from the GitLab downloads page but
- **without** providing the `EXTERNAL_URL` value.
-1. Edit `/etc/gitlab/gitlab.rb` to configure storage paths, enable
- the network listener and configure the token:
+1. [Download and install](https://about.gitlab.com/install/) the Omnibus GitLab
+ package of your choice. Be sure to follow _only_ installation steps 1 and 2
+ on the page, and _do not_ provide the `EXTERNAL_URL` value.
+1. Edit `/etc/gitlab/gitlab.rb` to configure the storage paths, enable
+ the network listener, and configure the token:
<!--
updates to following example must also be made at
@@ -1467,39 +1436,39 @@ On each node:
```
1. Append the following to `/etc/gitlab/gitlab.rb` for each respective server:
- 1. On `gitaly1.internal`:
-
- ```ruby
- git_data_dirs({
- 'default' => {
- 'path' => '/var/opt/gitlab/git-data'
- },
- 'storage1' => {
- 'path' => '/mnt/gitlab/git-data'
- },
- })
- ```
-
- 1. On `gitaly2.internal`:
-
- ```ruby
- git_data_dirs({
- 'storage2' => {
- 'path' => '/mnt/gitlab/git-data'
- },
- })
- ```
+ - On `gitaly1.internal`:
+
+ ```ruby
+ git_data_dirs({
+ 'default' => {
+ 'path' => '/var/opt/gitlab/git-data'
+ },
+ 'storage1' => {
+ 'path' => '/mnt/gitlab/git-data'
+ },
+ })
+ ```
+
+ - On `gitaly2.internal`:
+
+ ```ruby
+ git_data_dirs({
+ 'storage2' => {
+ 'path' => '/mnt/gitlab/git-data'
+ },
+ })
+ ```
<!--
updates to following example must also be made at
https://gitlab.com/gitlab-org/charts/gitlab/blob/master/doc/advanced/external-gitaly/external-omnibus-gitaly.md#configure-omnibus-gitlab
-->
-1. Copy the `/etc/gitlab/gitlab-secrets.json` file from your Consul server, and replace
- the file of the same name on this server. If that file is not on this server,
- add the file from your Consul server to this server.
+1. Copy the `/etc/gitlab/gitlab-secrets.json` file from your Consul server, and
+ then replace the file of the same name on this server. If that file isn't on
+ this server, add the file from your Consul server to this server.
-1. Save the file and [reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure).
+1. Save the file, and then [reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure).
### Gitaly TLS support
@@ -1521,11 +1490,10 @@ Name. If you are addressing the Gitaly server by its IP address, you must add it
as a Subject Alternative Name to the certificate.
[gRPC does not support using an IP address as Common Name in a certificate](https://github.com/grpc/grpc/issues/2691).
-NOTE: **Note:**
-It is possible to configure Gitaly servers with both an
-unencrypted listening address `listen_addr` and an encrypted listening
-address `tls_listen_addr` at the same time. This allows you to do a
-gradual transition from unencrypted to encrypted traffic, if necessary.
+It's possible to configure Gitaly servers with both an unencrypted listening
+address (`listen_addr`) and an encrypted listening address (`tls_listen_addr`)
+at the same time. This allows you to do a gradual transition from unencrypted to
+encrypted traffic, if necessary.
To configure Gitaly with TLS:
@@ -1580,10 +1548,10 @@ The following IPs will be used as an example:
To configure the Sidekiq nodes, on each one:
-1. SSH into the Sidekiq server.
-1. [Download/install](https://about.gitlab.com/install/) the Omnibus GitLab package
-you want using steps 1 and 2 from the GitLab downloads page.
-**Do not complete any other steps on the download page.**
+1. SSH in to the Sidekiq server.
+1. [Download and install](https://about.gitlab.com/install/) the Omnibus GitLab
+ package of your choice. Be sure to follow _only_ installation steps 1 and 2
+ on the page.
1. Open `/etc/gitlab/gitlab.rb` with your editor:
```ruby
@@ -1701,15 +1669,14 @@ You can also run [multiple Sidekiq processes](../operations/extra_sidekiq_proces
## Configure GitLab Rails
-NOTE: **Note:**
-In our architectures we run each GitLab Rails node using the Puma webserver
-and have its number of workers set to 90% of available CPUs along with four threads. For
-nodes that are running Rails with other components the worker value should be reduced
-accordingly where we've found 50% achieves a good balance but this is dependent
-on workload.
-
This section describes how to configure the GitLab application (Rails) component.
+In our architecture, we run each GitLab Rails node using the Puma webserver, and
+have its number of workers set to 90% of available CPUs, with four threads. For
+nodes running Rails with other components, the worker value should be reduced
+accordingly. We've determined that a worker value of 50% achieves a good balance,
+but this is dependent on workload.
+
The following IPs will be used as an example:
- `10.6.0.111`: GitLab application 1
@@ -1718,10 +1685,9 @@ The following IPs will be used as an example:
On each node perform the following:
-1. Download/install Omnibus GitLab using **steps 1 and 2** from
- [GitLab downloads](https://about.gitlab.com/install/). Do not complete other
- steps on the download page.
-
+1. [Download and install](https://about.gitlab.com/install/) the Omnibus GitLab
+ package of your choice. Be sure to follow _only_ installation steps 1 and 2
+ on the page.
1. Copy the `/etc/gitlab/gitlab-secrets.json` file from your Consul server, and replace
the file of the same name on this server. If that file is not on this server,
add the file from your Consul server to this server.
@@ -1752,6 +1718,7 @@ On each node perform the following:
roles ['application_role']
gitaly['enable'] = false
nginx['enable'] = true
+ sidekiq['enable'] = false
## PostgreSQL connection details
# Disable PostgreSQL on the application node
@@ -1795,7 +1762,6 @@ On each node perform the following:
# Set the network addresses that the exporters used for monitoring will listen on
node_exporter['listen_address'] = '0.0.0.0:9100'
gitlab_workhorse['prometheus_listen_addr'] = '0.0.0.0:9229'
- sidekiq['listen_address'] = "0.0.0.0"
puma['listen'] = '0.0.0.0'
# Add the monitoring node's IP address to the monitoring whitelist and allow it to
@@ -1836,7 +1802,7 @@ On each node perform the following:
1. Specify the necessary NFS mounts in `/etc/fstab`.
The exact contents of `/etc/fstab` will depend on how you chose
- to configure your NFS server. See the [NFS documentation](../high_availability/nfs.md)
+ to configure your NFS server. See the [NFS documentation](../nfs.md)
for examples and the various options.
1. Create the shared directories. These may be different depending on your NFS
@@ -1877,30 +1843,31 @@ On each node perform the following:
1. Optionally, from the Gitaly servers, confirm that Gitaly can perform callbacks to the internal API:
```shell
- sudo /opt/gitlab/embedded/service/gitlab-shell/bin/check -config /opt/gitlab/embedded/service/gitlab-shell/config.yml
+ sudo /opt/gitlab/embedded/bin/gitaly-hooks check /var/opt/gitlab/gitaly/config.toml
```
-NOTE: **Note:**
-When you specify `https` in the `external_url`, as in the example
-above, GitLab assumes you have SSL certificates in `/etc/gitlab/ssl/`. If
-certificates are not present, NGINX will fail to start. See the
-[NGINX documentation](https://docs.gitlab.com/omnibus/settings/nginx.html#enable-https)
-for more information.
+When you specify `https` in the `external_url`, as in the previous example,
+GitLab expects that the SSL certificates are in `/etc/gitlab/ssl/`. If the
+certificates aren't present, NGINX will fail to start. For more information, see
+the [NGINX documentation](https://docs.gitlab.com/omnibus/settings/nginx.html#enable-https).
### GitLab Rails post-configuration
-Initialize the GitLab database, by running the following in one of the Rails nodes:
+1. Designate one application node for running database migrations during
+ installation and updates. Initialize the GitLab database and ensure all
+ migrations ran:
-```shell
-sudo gitlab-rake gitlab:db:configure
-```
+ ```shell
+ sudo gitlab-rake gitlab:db:configure
+ ```
-NOTE: **Note:**
-If you encounter a `rake aborted!` error stating that PgBouncer is failing to connect to
-PostgreSQL it may be that your PgBouncer node's IP address is missing from
-PostgreSQL's `trust_auth_cidr_addresses` in `gitlab.rb` on your database nodes. See
-[PgBouncer error `ERROR: pgbouncer cannot connect to server`](troubleshooting.md#pgbouncer-error-error-pgbouncer-cannot-connect-to-server)
-in the Troubleshooting section before proceeding.
+ If you encounter a `rake aborted!` error message stating that PgBouncer is
+ failing to connect to PostgreSQL, it may be that your PgBouncer node's IP
+ address is missing from PostgreSQL's `trust_auth_cidr_addresses` in `gitlab.rb`
+ on your database nodes. Before proceeding, see
+ [PgBouncer error `ERROR: pgbouncer cannot connect to server`](troubleshooting.md#pgbouncer-error-error-pgbouncer-cannot-connect-to-server).
+
+1. [Configure fast lookup of authorized SSH keys in the database](../operations/fast_ssh_key_lookup.md).
<div align="right">
<a type="button" class="btn btn-default" href="#setup-components">
@@ -1920,11 +1887,10 @@ The following IP will be used as an example:
To configure the Monitoring node:
-1. SSH into the Monitoring node.
-1. [Download/install](https://about.gitlab.com/install/) the Omnibus GitLab
- package you want using **steps 1 and 2** from the GitLab downloads page.
- Do not complete any other steps on the download page.
-
+1. SSH in to the Monitoring node.
+1. [Download and install](https://about.gitlab.com/install/) the Omnibus GitLab
+ package of your choice. Be sure to follow _only_ installation steps 1 and 2
+ on the page.
1. Copy the `/etc/gitlab/gitlab-secrets.json` file from your Consul server, and replace
the file of the same name on this server. If that file is not on this server,
add the file from your Consul server to this server.
@@ -1988,28 +1954,44 @@ It's recommended over [NFS](#configure-nfs-optional) and in general it's better
in larger setups as object storage is typically much more performant, reliable,
and scalable.
-Object storage options that GitLab has tested, or is aware of customers using include:
+GitLab has been tested on a number of object storage providers:
-- SaaS/Cloud solutions such as [Amazon S3](https://aws.amazon.com/s3/), [Google cloud storage](https://cloud.google.com/storage).
+- [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)
+- [Openstack Swift](https://docs.openstack.org/swift/latest/s3_compat.html)
+- [Azure Blob storage](https://docs.microsoft.com/en-us/azure/storage/blobs/storage-blobs-introduction)
- On-premises hardware and appliances from various storage vendors.
-- MinIO. There is [a guide to deploying this](https://docs.gitlab.com/charts/advanced/external-object-storage/minio.html) within our Helm Chart documentation.
-
-For configuring GitLab to use Object Storage refer to the following guides
-based on what features you intend to use:
-
-1. Configure [object storage for backups](../../raketasks/backup_restore.md#uploading-backups-to-a-remote-cloud-storage).
-1. Configure [object storage for job artifacts](../job_artifacts.md#using-object-storage)
- including [incremental logging](../job_logs.md#new-incremental-logging-architecture).
-1. Configure [object storage for LFS objects](../lfs/index.md#storing-lfs-objects-in-remote-object-storage).
-1. Configure [object storage for uploads](../uploads.md#using-object-storage).
-1. Configure [object storage for merge request diffs](../merge_request_diffs.md#using-object-storage).
-1. Configure [object storage for Container Registry](../packages/container_registry.md#use-object-storage) (optional feature).
-1. Configure [object storage for Mattermost](https://docs.mattermost.com/administration/config-settings.html#file-storage) (optional feature).
-1. Configure [object storage for packages](../packages/index.md#using-object-storage) (optional feature). **(PREMIUM ONLY)**
-1. Configure [object storage for Dependency Proxy](../packages/dependency_proxy.md#using-object-storage) (optional feature). **(PREMIUM ONLY)**
-1. Configure [object storage for Pseudonymizer](../pseudonymizer.md#configuration) (optional feature). **(ULTIMATE ONLY)**
-1. Configure [object storage for autoscale runner caching](https://docs.gitlab.com/runner/configuration/autoscale.html#distributed-runners-caching) (optional - for improved performance).
-1. Configure [object storage for Terraform state files](../terraform_state.md#using-object-storage).
+- MinIO. We have [a guide to deploying this](https://docs.gitlab.com/charts/advanced/external-object-storage/minio.html) within our Helm Chart documentation.
+
+There are two ways of specifying object storage configuration in GitLab:
+
+- [Consolidated form](../object_storage.md#consolidated-object-storage-configuration): A single credential is
+ shared by all supported object types.
+- [Storage-specific form](../object_storage.md#storage-specific-configuration): Every object defines its
+ own object storage [connection and configuration](../object_storage.md#connection-settings).
+
+Starting with GitLab 13.2, consolidated object storage configuration is available. It simplifies your GitLab configuration since the connection details are shared across object types. Refer to [Consolidated object storage configuration](../object_storage.md#consolidated-object-storage-configuration) guide for instructions on how to set it up.
+
+For configuring object storage in GitLab 13.1 and earlier, or for storage types not
+supported by consolidated configuration form, refer to the following guides based
+on what features you intend to use:
+
+|Object storage type|Supported by consolidated configuration?|
+|-------------------|----------------------------------------|
+| [Backups](../../raketasks/backup_restore.md#uploading-backups-to-a-remote-cloud-storage)|No|
+| [Job artifacts](../job_artifacts.md#using-object-storage) including archived job logs | Yes |
+| [LFS objects](../lfs/index.md#storing-lfs-objects-in-remote-object-storage) | Yes |
+| [Uploads](../uploads.md#using-object-storage) | Yes |
+| [Container Registry](../packages/container_registry.md#use-object-storage) (optional feature) | No |
+| [Merge request diffs](../merge_request_diffs.md#using-object-storage) | Yes |
+| [Mattermost](https://docs.mattermost.com/administration/config-settings.html#file-storage)| No |
+| [Packages](../packages/index.md#using-object-storage) (optional feature) | Yes |
+| [Dependency Proxy](../packages/dependency_proxy.md#using-object-storage) (optional feature) **(PREMIUM ONLY)** | Yes |
+| [Pseudonymizer](../pseudonymizer.md#configuration) (optional feature) **(ULTIMATE ONLY)** | No |
+| [Autoscale runner caching](https://docs.gitlab.com/runner/configuration/autoscale.html#distributed-runners-caching) (optional for improved performance) | No |
+| [Terraform state files](../terraform_state.md#using-object-storage) | Yes |
Using separate buckets for each data type is the recommended approach for GitLab.
@@ -2033,13 +2015,29 @@ work.
</a>
</div>
+## Configure Advanced Search **(STARTER ONLY)**
+
+You can leverage Elasticsearch and [enable Advanced Search](../../integration/elasticsearch.md)
+for faster, more advanced code search across your entire GitLab instance.
+
+Elasticsearch cluster design and requirements are dependent on your specific
+data. For recommended best practices about how to set up your Elasticsearch
+cluster alongside your instance, read how to
+[choose the optimal cluster configuration](../../integration/elasticsearch.md#guidance-on-choosing-optimal-cluster-configuration).
+
+<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>
+
## Configure NFS (optional)
[Object storage](#configure-the-object-storage), along with [Gitaly](#configure-gitaly)
are recommended over NFS wherever possible for improved performance. If you intend
to use GitLab Pages, this currently [requires NFS](troubleshooting.md#gitlab-pages-requires-nfs).
-See how to [configure NFS](../high_availability/nfs.md).
+See how to [configure NFS](../nfs.md).
<div align="right">
<a type="button" class="btn btn-default" href="#setup-components">
diff --git a/doc/administration/reference_architectures/2k_users.md b/doc/administration/reference_architectures/2k_users.md
index 34b90964fbf..4863329b695 100644
--- a/doc/administration/reference_architectures/2k_users.md
+++ b/doc/administration/reference_architectures/2k_users.md
@@ -17,14 +17,14 @@ For a full list of reference architectures, see
| Service | Nodes | Configuration | GCP | AWS | Azure |
|------------------------------------------|--------|-------------------------|----------------|--------------|---------|
-| Load balancer | 1 | 2 vCPU, 1.8GB memory | n1-highcpu-2 | c5.large | F2s v2 |
-| PostgreSQL | 1 | 2 vCPU, 7.5GB memory | n1-standard-2 | m5.large | D2s v3 |
-| Redis | 1 | 1 vCPU, 3.75GB memory | n1-standard-1 | m5.large | D2s v3 |
-| Gitaly | 1 | 4 vCPU, 15GB memory | n1-standard-4 | m5.xlarge | D4s v3 |
-| GitLab Rails | 2 | 8 vCPU, 7.2GB memory | n1-highcpu-8 | c5.2xlarge | F8s v2 |
-| Monitoring node | 1 | 2 vCPU, 1.8GB memory | n1-highcpu-2 | c5.large | F2s v2 |
+| Load balancer | 1 | 2 vCPU, 1.8 GB memory | n1-highcpu-2 | c5.large | F2s v2 |
+| PostgreSQL | 1 | 2 vCPU, 7.5 GB memory | n1-standard-2 | m5.large | D2s v3 |
+| Redis | 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 |
+| 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 | n/a | n/a | n/a | n/a | n/a |
-| NFS server (optional, not recommended) | 1 | 4 vCPU, 3.6GB memory | n1-highcpu-4 | c5.xlarge | F4s v2 |
+| NFS server (optional, not recommended) | 1 | 4 vCPU, 3.6 GB memory | n1-highcpu-4 | c5.xlarge | F4s v2 |
The Google Cloud Platform (GCP) architectures were built and tested using the
[Intel Xeon E5 v3 (Haswell)](https://cloud.google.com/compute/docs/cpu-platforms)
@@ -43,7 +43,7 @@ doesn't require you to provision and maintain a node.
To set up GitLab and its components to accommodate up to 2,000 users:
1. [Configure the external load balancing node](#configure-the-external-load-balancer)
- to handle the load balancing of the two GitLab application services nodes.
+ to handle the load balancing of the GitLab application services nodes.
1. [Configure PostgreSQL](#configure-postgresql), the database for GitLab.
1. [Configure Redis](#configure-redis).
1. [Configure Gitaly](#configure-gitaly), which provides access to the Git
@@ -55,6 +55,8 @@ To set up GitLab and its components to accommodate up to 2,000 users:
environment.
1. [Configure the object storage](#configure-the-object-storage) used for
shared data objects.
+1. [Configure Advanced Search](#configure-advanced-search) (optional) for faster,
+ more advanced code search across your entire GitLab instance.
1. [Configure NFS](#configure-nfs-optional) (optional, and not recommended)
to have shared disk storage service as an alternative to Gitaly or object
storage. You can skip this step if you're not using GitLab Pages (which
@@ -62,18 +64,17 @@ To set up GitLab and its components to accommodate up to 2,000 users:
## Configure the external load balancer
-NOTE: **Note:**
-This architecture has been tested and validated with [HAProxy](https://www.haproxy.org/).
-Although you can use a load balancer with a similar set of features, GitLab
-hasn't validated other load balancers.
-
In an active/active GitLab configuration, you'll need a load balancer to route
-traffic to the application servers. The specifics for which load balancer to
-use or its exact configuration is out of scope for the GitLab documentation.
-If you're managing multi-node systems (including GitLab) you'll probably
-already have a load balancer of choice. Some examples including HAProxy
-(open-source), F5 Big-IP LTM, and Citrix Net Scaler. This documentation
-includes the ports and protocols for use with GitLab.
+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 hope
+that if you're managing multi-node systems like GitLab, you already have a load
+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.
+
+This architecture has been tested and validated with [HAProxy](https://www.haproxy.org/)
+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:
@@ -206,10 +207,10 @@ further configuration steps.
### Standalone PostgreSQL using Omnibus GitLab
-1. SSH into the PostgreSQL server.
-1. [Download/install](https://about.gitlab.com/install/) the Omnibus GitLab
- package you want using **steps 1 and 2** from the GitLab downloads page.
- - Do not complete any other steps on the download page.
+1. SSH in to the PostgreSQL server.
+1. [Download and install](https://about.gitlab.com/install/) the Omnibus GitLab
+ package of your choice. Be sure to follow _only_ installation steps 1 and 2
+ on the page.
1. Generate a password hash for PostgreSQL. This assumes you will use the default
username of `gitlab` (recommended). The command will request a password
and confirmation. Use the value that is output by this command in the next
@@ -300,11 +301,10 @@ The Omnibus GitLab package can be used to configure a standalone Redis server.
The steps below are the minimum necessary to configure a Redis server with
Omnibus:
-1. SSH into the Redis server.
-1. [Download/install](https://about.gitlab.com/install/) the Omnibus GitLab
- package you want using **steps 1 and 2** from the GitLab downloads page.
- - Do not complete any other steps on the download page.
-
+1. SSH in to the Redis server.
+1. [Download and install](https://about.gitlab.com/install/) the Omnibus GitLab
+ package of your choice. Be sure to follow _only_ installation steps 1 and 2
+ on the page.
1. Edit `/etc/gitlab/gitlab.rb` and add the contents:
```ruby
@@ -393,12 +393,11 @@ The following procedure describes how to configure a single Gitaly server named
`gitaly1.internal` with the secret token `gitalysecret`. We assume your GitLab
installation has two repository storages: `default` and `storage1`.
-To configure the Gitaly server:
+To configure the Gitaly server, on the server node you want to use for Gitaly:
-1. On the server node you want to use for Gitaly,
- [download and install](https://about.gitlab.com/install/) your selected
- Omnibus GitLab package using *steps 1 and 2* from the GitLab downloads page,
- but *without* providing the `EXTERNAL_URL` value.
+1. [Download and install](https://about.gitlab.com/install/) the Omnibus GitLab
+ package of your choice. Be sure to follow _only_ installation steps 1 and 2
+ on the page, and _do not_ provide the `EXTERNAL_URL` value.
1. Edit the Gitaly server node's `/etc/gitlab/gitlab.rb` file to configure
storage paths, enable the network listener, and to configure the token:
@@ -464,7 +463,7 @@ To configure the Gitaly server:
1. Confirm that Gitaly can perform callbacks to the internal API:
```shell
- sudo /opt/gitlab/embedded/service/gitlab-shell/bin/check -config /opt/gitlab/embedded/service/gitlab-shell/config.yml
+ sudo /opt/gitlab/embedded/bin/gitaly-hooks check /var/opt/gitlab/gitaly/config.toml
```
### Gitaly TLS support
@@ -487,11 +486,10 @@ Name. If you are addressing the Gitaly server by its IP address, you must add it
as a Subject Alternative Name to the certificate.
[gRPC does not support using an IP address as Common Name in a certificate](https://github.com/grpc/grpc/issues/2691).
-NOTE: **Note:**
-It is possible to configure Gitaly servers with both an
-unencrypted listening address `listen_addr` and an encrypted listening
-address `tls_listen_addr` at the same time. This allows you to do a
-gradual transition from unencrypted to encrypted traffic, if necessary.
+It's possible to configure Gitaly servers with both an unencrypted listening
+address (`listen_addr`) and an encrypted listening address (`tls_listen_addr`)
+at the same time. This allows you to do a gradual transition from unencrypted to
+encrypted traffic, if necessary.
To configure Gitaly with TLS:
@@ -535,14 +533,14 @@ To configure Gitaly with TLS:
## Configure GitLab Rails
-NOTE: **Note:**
-In our architectures we run each GitLab Rails node using the Puma webserver
-and have its number of workers set to 90% of available CPUs along with four threads. For
-nodes that are running Rails with other components the worker value should be reduced
-accordingly where we've found 50% achieves a good balance but this is dependent
-on workload.
-
This section describes how to configure the GitLab application (Rails) component.
+
+In our architecture, we run each GitLab Rails node using the Puma webserver, and
+have its number of workers set to 90% of available CPUs, with four threads. For
+nodes running Rails with other components, the worker value should be reduced
+accordingly. We've determined that a worker value of 50% achieves a good balance,
+but this is dependent on workload.
+
On each node perform the following:
1. If you're [using NFS](#configure-nfs-optional):
@@ -570,10 +568,10 @@ On each node perform the following:
mkdir -p /var/opt/gitlab/.ssh /var/opt/gitlab/gitlab-rails/uploads /var/opt/gitlab/gitlab-rails/shared /var/opt/gitlab/gitlab-ci/builds /var/opt/gitlab/git-data
```
-1. Download/install Omnibus GitLab using **steps 1 and 2** from
- [GitLab downloads](https://about.gitlab.com/install/). Do not complete other
- steps on the download page.
-1. Create/edit `/etc/gitlab/gitlab.rb` and use the following configuration.
+1. [Download and install](https://about.gitlab.com/install/) the Omnibus GitLab
+ package of your choice. Be sure to follow _only_ installation steps 1 and 2
+ on the page.
+1. Create or edit `/etc/gitlab/gitlab.rb` and use the following configuration.
To maintain uniformity of links across nodes, the `external_url`
on the application server should point to the external URL that users will use
to access GitLab. This would be the URL of the [load balancer](#configure-the-external-load-balancer)
@@ -664,12 +662,33 @@ On each node perform the following:
sudo gitlab-ctl tail gitaly
```
-NOTE: **Note:**
-When you specify `https` in the `external_url`, as in the example
-above, GitLab assumes you have SSL certificates in `/etc/gitlab/ssl/`. If
-certificates are not present, NGINX will fail to start. See the
-[NGINX documentation](https://docs.gitlab.com/omnibus/settings/nginx.html#enable-https)
-for more information.
+1. Save the `/etc/gitlab/gitlab-secrets.json` file from one of the two
+ application nodes and install it on the other application node and the
+ [Gitaly node](#configure-gitaly) and
+ [reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure).
+
+When you specify `https` in the `external_url`, as in the previous example,
+GitLab expects that the SSL certificates are in `/etc/gitlab/ssl/`. If the
+certificates aren't present, NGINX will fail to start. For more information, see
+the [NGINX documentation](https://docs.gitlab.com/omnibus/settings/nginx.html#enable-https).
+
+### GitLab Rails post-configuration
+
+1. Designate one application node for running database migrations during
+ installation and updates. Initialize the GitLab database and ensure all
+ migrations ran:
+
+ ```shell
+ sudo gitlab-rake gitlab:db:configure
+ ```
+
+ If you encounter a `rake aborted!` error message stating that PgBouncer is
+ failing to connect to PostgreSQL, it may be that your PgBouncer node's IP
+ address is missing from PostgreSQL's `trust_auth_cidr_addresses` in `gitlab.rb`
+ on your database nodes. Before proceeding, see
+ [PgBouncer error `ERROR: pgbouncer cannot connect to server`](troubleshooting.md#pgbouncer-error-error-pgbouncer-cannot-connect-to-server).
+
+1. [Configure fast lookup of authorized SSH keys in the database](../operations/fast_ssh_key_lookup.md).
<div align="right">
<a type="button" class="btn btn-default" href="#setup-components">
@@ -683,10 +702,10 @@ The Omnibus GitLab package can be used to configure a standalone Monitoring node
running [Prometheus](../monitoring/prometheus/index.md) and
[Grafana](../monitoring/performance/grafana_configuration.md):
-1. SSH into the Monitoring node.
-1. [Download/install](https://about.gitlab.com/install/) the Omnibus GitLab
- package you want using **steps 1 and 2** from the GitLab downloads page.
- Do not complete any other steps on the download page.
+1. SSH in to the Monitoring node.
+1. [Download and install](https://about.gitlab.com/install/) the Omnibus GitLab
+ package of your choice. Be sure to follow _only_ installation steps 1 and 2
+ on the page.
1. Edit `/etc/gitlab/gitlab.rb` and add the contents:
```ruby
@@ -806,30 +825,44 @@ data, and is recommended over [NFS](#configure-nfs-optional). In general,
object storage services are better for larger environments, as object storage
is typically much more performant, reliable, and scalable.
-Object storage options that GitLab has either tested or is aware of customers
-using, includes:
-
-- SaaS/Cloud solutions (such as [Amazon S3](https://aws.amazon.com/s3/) or
- [Google Cloud Storage](https://cloud.google.com/storage)).
-- On-premises hardware and appliances, from various storage vendors.
-- MinIO ([Deployment guide](https://docs.gitlab.com/charts/advanced/external-object-storage/minio.html)).
-
-To configure GitLab to use object storage, refer to the following guides based
-on the features you intend to use:
-
-1. [Object storage for backups](../../raketasks/backup_restore.md#uploading-backups-to-a-remote-cloud-storage).
-1. [Object storage for job artifacts](../job_artifacts.md#using-object-storage)
- including [incremental logging](../job_logs.md#new-incremental-logging-architecture).
-1. [Object storage for LFS objects](../lfs/index.md#storing-lfs-objects-in-remote-object-storage).
-1. [Object storage for uploads](../uploads.md#using-object-storage).
-1. [Object storage for merge request diffs](../merge_request_diffs.md#using-object-storage).
-1. [Object storage for Container Registry](../packages/container_registry.md#use-object-storage) (optional feature).
-1. [Object storage for Mattermost](https://docs.mattermost.com/administration/config-settings.html#file-storage) (optional feature).
-1. [Object storage for packages](../packages/index.md#using-object-storage) (optional feature). **(PREMIUM ONLY)**
-1. [Object storage for Dependency Proxy](../packages/dependency_proxy.md#using-object-storage) (optional feature). **(PREMIUM ONLY)**
-1. [Object storage for Pseudonymizer](../pseudonymizer.md#configuration) (optional feature). **(ULTIMATE ONLY)**
-1. [Object storage for autoscale runner caching](https://docs.gitlab.com/runner/configuration/autoscale.html#distributed-runners-caching) (optional, for improved performance).
-1. [Object storage for Terraform state files](../terraform_state.md#using-object-storage).
+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)
+- [Openstack Swift](https://docs.openstack.org/swift/latest/s3_compat.html)
+- [Azure Blob storage](https://docs.microsoft.com/en-us/azure/storage/blobs/storage-blobs-introduction)
+- On-premises hardware and appliances from various storage vendors.
+- MinIO. We have [a guide to deploying this](https://docs.gitlab.com/charts/advanced/external-object-storage/minio.html) within our Helm Chart documentation.
+
+There are two ways of specifying object storage configuration in GitLab:
+
+- [Consolidated form](../object_storage.md#consolidated-object-storage-configuration): A single credential is
+ shared by all supported object types.
+- [Storage-specific form](../object_storage.md#storage-specific-configuration): Every object defines its
+ own object storage [connection and configuration](../object_storage.md#connection-settings).
+
+Starting with GitLab 13.2, consolidated object storage configuration is available. It simplifies your GitLab configuration since the connection details are shared across object types. Refer to [Consolidated object storage configuration](../object_storage.md#consolidated-object-storage-configuration) guide for instructions on how to set it up.
+
+For configuring object storage in GitLab 13.1 and earlier, or for storage types not
+supported by consolidated configuration form, refer to the following guides based
+on what features you intend to use:
+
+|Object storage type|Supported by consolidated configuration?|
+|-------------------|----------------------------------------|
+| [Backups](../../raketasks/backup_restore.md#uploading-backups-to-a-remote-cloud-storage)|No|
+| [Job artifacts](../job_artifacts.md#using-object-storage) including archived job logs | Yes |
+| [LFS objects](../lfs/index.md#storing-lfs-objects-in-remote-object-storage) | Yes |
+| [Uploads](../uploads.md#using-object-storage) | Yes |
+| [Container Registry](../packages/container_registry.md#use-object-storage) (optional feature) | No |
+| [Merge request diffs](../merge_request_diffs.md#using-object-storage) | Yes |
+| [Mattermost](https://docs.mattermost.com/administration/config-settings.html#file-storage)| No |
+| [Packages](../packages/index.md#using-object-storage) (optional feature) | Yes |
+| [Dependency Proxy](../packages/dependency_proxy.md#using-object-storage) (optional feature) **(PREMIUM ONLY)** | Yes |
+| [Pseudonymizer](../pseudonymizer.md#configuration) (optional feature) **(ULTIMATE ONLY)** | No |
+| [Autoscale runner caching](https://docs.gitlab.com/runner/configuration/autoscale.html#distributed-runners-caching) (optional for improved performance) | No |
+| [Terraform state files](../terraform_state.md#using-object-storage) | Yes |
Using separate buckets for each data type is the recommended approach for GitLab.
@@ -851,6 +884,22 @@ functioning backups is encountered.
</a>
</div>
+## Configure Advanced Search **(STARTER ONLY)**
+
+You can leverage Elasticsearch and [enable Advanced Search](../../integration/elasticsearch.md)
+for faster, more advanced code search across your entire GitLab instance.
+
+Elasticsearch cluster design and requirements are dependent on your specific
+data. For recommended best practices about how to set up your Elasticsearch
+cluster alongside your instance, read how to
+[choose the optimal cluster configuration](../../integration/elasticsearch.md#guidance-on-choosing-optimal-cluster-configuration).
+
+<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>
+
## Configure NFS (optional)
For improved performance, [object storage](#configure-the-object-storage),
diff --git a/doc/administration/reference_architectures/3k_users.md b/doc/administration/reference_architectures/3k_users.md
index be944586e43..70d0cae6dfd 100644
--- a/doc/administration/reference_architectures/3k_users.md
+++ b/doc/administration/reference_architectures/3k_users.md
@@ -24,18 +24,18 @@ costly-to-operate environment by using the
| Service | Nodes | Configuration | GCP | AWS | Azure |
|--------------------------------------------|-------------|-----------------------|----------------|-------------|---------|
-| External load balancing node | 1 | 2 vCPU, 1.8GB memory | n1-highcpu-2 | c5.large | F2s v2 |
-| Redis | 3 | 2 vCPU, 7.5GB memory | n1-standard-2 | m5.large | D2s v3 |
-| Consul + Sentinel | 3 | 2 vCPU, 1.8GB memory | n1-highcpu-2 | c5.large | F2s v2 |
-| PostgreSQL | 3 | 2 vCPU, 7.5GB memory | n1-standard-2 | m5.large | D2s v3 |
-| PgBouncer | 3 | 2 vCPU, 1.8GB memory | n1-highcpu-2 | c5.large | F2s v2 |
-| Internal load balancing node | 1 | 2 vCPU, 1.8GB memory | n1-highcpu-2 | c5.large | F2s v2 |
-| Gitaly | 2 (minimum) | 4 vCPU, 15GB memory | n1-standard-4 | m5.xlarge | D4s v3 |
-| Sidekiq | 4 | 2 vCPU, 7.5GB memory | n1-standard-2 | m5.large | D2s v3 |
-| GitLab Rails | 3 | 8 vCPU, 7.2GB memory | n1-highcpu-8 | c5.2xlarge | F8s v2 |
-| Monitoring node | 1 | 2 vCPU, 1.8GB memory | n1-highcpu-2 | c5.large | F2s v2 |
-| Object Storage | n/a | n/a | n/a | n/a | n/a |
-| NFS Server (optional, not recommended) | 1 | 4 vCPU, 3.6GB memory | n1-highcpu-4 | c5.xlarge | F4s v2 |
+| External load balancing node | 1 | 2 vCPU, 1.8 GB memory | n1-highcpu-2 | c5.large | F2s v2 |
+| Redis | 3 | 2 vCPU, 7.5 GB memory | n1-standard-2 | m5.large | D2s v3 |
+| Consul + Sentinel | 3 | 2 vCPU, 1.8 GB memory | n1-highcpu-2 | c5.large | F2s v2 |
+| PostgreSQL | 3 | 2 vCPU, 7.5 GB memory | n1-standard-2 | m5.large | D2s v3 |
+| PgBouncer | 3 | 2 vCPU, 1.8 GB memory | n1-highcpu-2 | c5.large | F2s v2 |
+| Internal load balancing node | 1 | 2 vCPU, 1.8 GB memory | n1-highcpu-2 | c5.large | F2s v2 |
+| Gitaly | 2 (minimum) | 4 vCPU, 15 GB memory | n1-standard-4 | m5.xlarge | D4s v3 |
+| Sidekiq | 4 | 2 vCPU, 7.5 GB memory | n1-standard-2 | m5.large | D2s v3 |
+| GitLab Rails | 3 | 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 | n/a | n/a | n/a | n/a | n/a |
+| NFS server (optional, not recommended) | 1 | 4 vCPU, 3.6 GB memory | n1-highcpu-4 | c5.xlarge | F4s v2 |
The Google Cloud Platform (GCP) architectures were built and tested using the
[Intel Xeon E5 v3 (Haswell)](https://cloud.google.com/compute/docs/cpu-platforms)
@@ -44,41 +44,43 @@ or higher, are required for your CPU or node counts. For more information, see
our [Sysbench](https://github.com/akopytov/sysbench)-based
[CPU benchmark](https://gitlab.com/gitlab-org/quality/performance/-/wikis/Reference-Architectures/GCP-CPU-Benchmarks).
-For data objects (such as LFS, Uploads, or Artifacts), an
-[object storage service](#configure-the-object-storage) is recommended instead
-of NFS where possible, due to better performance and availability. Since this
-doesn't require a node to be set up, *Object Storage* is noted as not
-applicable (n/a) in the previous table.
+Due to better performance and availability, for data objects (such as LFS,
+uploads, or artifacts), using an [object storage service](#configure-the-object-storage)
+is recommended instead of using NFS. Using an object storage service also
+doesn't require you to provision and maintain a node.
## Setup components
To set up GitLab and its components to accommodate up to 3,000 users:
1. [Configure the external load balancing node](#configure-the-external-load-balancer)
- that will handle the load balancing of the two GitLab application services nodes.
+ to handle the load balancing of the GitLab application services nodes.
1. [Configure Redis](#configure-redis).
1. [Configure Consul and Sentinel](#configure-consul-and-sentinel).
1. [Configure PostgreSQL](#configure-postgresql), the database for GitLab.
1. [Configure PgBouncer](#configure-pgbouncer).
-1. [Configure the internal load balancing node](#configure-the-internal-load-balancer)
+1. [Configure the internal load balancing node](#configure-the-internal-load-balancer).
1. [Configure Gitaly](#configure-gitaly),
which provides access to the Git repositories.
1. [Configure Sidekiq](#configure-sidekiq).
1. [Configure the main GitLab Rails application](#configure-gitlab-rails)
- to run Puma/Unicorn, Workhorse, GitLab Shell, and to serve all frontend requests (UI, API, Git
- over HTTP/SSH).
-1. [Configure Prometheus](#configure-prometheus) to monitor your GitLab environment.
-1. [Configure the Object Storage](#configure-the-object-storage)
+ to run Puma/Unicorn, Workhorse, GitLab Shell, and to serve all frontend
+ requests (which include UI, API, and Git over HTTP/SSH).
+1. [Configure Prometheus](#configure-prometheus) to monitor your GitLab
+ environment.
+1. [Configure the object storage](#configure-the-object-storage)
used for shared data objects.
-1. [Configure NFS (Optional)](#configure-nfs-optional)
- to have shared disk storage service as an alternative to Gitaly and/or Object Storage (although
- not recommended). NFS is required for GitLab Pages, you can skip this step if you're not using
- that feature.
+1. [Configure Advanced Search](#configure-advanced-search) (optional) for faster,
+ more advanced code search across your entire GitLab instance.
+1. [Configure NFS](#configure-nfs-optional) (optional, and not recommended)
+ to have shared disk storage service as an alternative to Gitaly or object
+ storage. You can skip this step if you're not using GitLab Pages (which
+ requires NFS).
-We start with all servers on the same 10.6.0.0/16 private network range, they
-can connect to each other freely on those addresses.
+The servers start on the same 10.6.0.0/24 private network range, and can
+connect to each other freely on these addresses.
-Here is a list and description of each machine and the assigned IP:
+The following list includes descriptions of each server and its assigned IP:
- `10.6.0.10`: External Load Balancer
- `10.6.0.61`: Redis Primary
@@ -107,19 +109,18 @@ Here is a list and description of each machine and the assigned IP:
## Configure the external load balancer
-NOTE: **Note:**
+In an active/active 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 hope
+that if you're managing multi-node systems like GitLab, you already have a load
+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.
+
This architecture has been tested and validated with [HAProxy](https://www.haproxy.org/)
as the load balancer. Although other load balancers with similar feature sets
could also be used, those load balancers have not been validated.
-In an active/active GitLab configuration, you will need a load balancer to route
-traffic to the application servers. The specifics on which load balancer to use
-or the exact configuration is beyond the scope of GitLab documentation. We hope
-that if you're managing multi-node systems like GitLab you have a load balancer of
-choice already. Some examples including HAProxy (open-source), F5 Big-IP LTM,
-and Citrix Net Scaler. This documentation will outline what ports and protocols
-you need to use with GitLab.
-
The next question is how you will handle SSL in your environment.
There are several different options:
@@ -277,20 +278,17 @@ The requirements for a Redis setup are the following:
([Internet](https://gitlab.com/gitlab-org/gitlab-foss/uploads/c4cc8cd353604bd80315f9384035ff9e/The_Internet_IT_Crowd.png)),
using a firewall.
-NOTE: **Note:**
-Redis nodes (both primary and replica) will need the same password defined in
-`redis['password']`. At any time during a failover the Sentinels can
-reconfigure a node and change its status from primary to replica and vice versa.
+Both the primary and replica Redis nodes need the same password defined in
+`redis['password']`. At any time during a failover, the Sentinels can reconfigure
+a node and change its status from primary to replica (and vice versa).
#### Configuring the primary Redis instance
-1. SSH into the **Primary** Redis server.
-1. [Download/install](https://about.gitlab.com/install/) the Omnibus GitLab
- package you want using **steps 1 and 2** from the GitLab downloads page.
- - Make sure you select the correct Omnibus package, with the same version
- and type (Community, Enterprise editions) of your current install.
- - Do not complete any other steps on the download page.
-
+1. SSH in to the **Primary** Redis server.
+1. [Download and install](https://about.gitlab.com/install/) the Omnibus GitLab
+ package of your choice. Be sure to both follow _only_ installation steps 1 and 2
+ on the page, and to select the correct Omnibus GitLab package, with the same version
+ and type (Community or Enterprise editions) as your current install.
1. Edit `/etc/gitlab/gitlab.rb` and add the contents:
```ruby
@@ -334,18 +332,17 @@ reconfigure a node and change its status from primary to replica and vice versa.
1. [Reconfigure Omnibus GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure) for the changes to take effect.
-NOTE: **Note:**
-You can specify multiple roles like sentinel and Redis as:
-`roles ['redis_sentinel_role', 'redis_master_role']`.
-Read more about [roles](https://docs.gitlab.com/omnibus/roles/).
+You can specify multiple roles, like sentinel and Redis, as:
+`roles ['redis_sentinel_role', 'redis_master_role']`. Read more about
+[roles](https://docs.gitlab.com/omnibus/roles/).
-You can list the current Redis Primary, Replica status via:
+You can list the current Redis Primary, Replica status by using:
```shell
/opt/gitlab/embedded/bin/redis-cli -h <host> -a 'redis-password-goes-here' info replication
```
-Show running GitLab services via:
+Show running GitLab services by using:
```shell
gitlab-ctl status
@@ -363,13 +360,11 @@ run: redis-exporter: (pid 30075) 76861s; run: log: (pid 29674) 76896s
#### Configuring the replica Redis instances
-1. SSH into the **replica** Redis server.
-1. [Download/install](https://about.gitlab.com/install/) the Omnibus GitLab
- package you want using **steps 1 and 2** from the GitLab downloads page.
- - Make sure you select the correct Omnibus package, with the same version
- and type (Community, Enterprise editions) of your current install.
- - Do not complete any other steps on the download page.
-
+1. SSH in to the **replica** Redis server.
+1. [Download and install](https://about.gitlab.com/install/) the Omnibus GitLab
+ package of your choice. Be sure to both follow _only_ installation steps 1 and 2
+ on the page, and to select the correct Omnibus GitLab package, with the same version
+ and type (Community or Enterprise editions) as your current install.
1. Edit `/etc/gitlab/gitlab.rb` and add the contents:
```ruby
@@ -422,10 +417,9 @@ run: redis-exporter: (pid 30075) 76861s; run: log: (pid 29674) 76896s
1. Go through the steps again for all the other replica nodes, and
make sure to set up the IPs correctly.
-NOTE: **Note:**
-You can specify multiple roles like sentinel and Redis as:
-`roles ['redis_sentinel_role', 'redis_master_role']`.
-Read more about [roles](https://docs.gitlab.com/omnibus/roles/).
+You can specify multiple roles, like sentinel and Redis, as:
+`roles ['redis_sentinel_role', 'redis_master_role']`. Read more about
+[roles](https://docs.gitlab.com/omnibus/roles/).
These values don't have to be changed again in `/etc/gitlab/gitlab.rb` after
a failover, as the nodes will be managed by the [Sentinels](#configure-consul-and-sentinel), and even after a
@@ -443,13 +437,6 @@ are supported and can be added if needed.
## Configure Consul and Sentinel
-NOTE: **Note:**
-If you are using an external Redis Sentinel instance, be sure
-to exclude the `requirepass` parameter from the Sentinel
-configuration. This parameter will cause clients to report `NOAUTH
-Authentication required.`. [Redis Sentinel 3.2.x does not support
-password authentication](https://github.com/antirez/redis/issues/3279).
-
Now that the Redis servers are all set up, let's configure the Sentinel
servers. The following IPs will be used as an example:
@@ -457,16 +444,19 @@ servers. The following IPs will be used as an example:
- `10.6.0.12`: Consul/Sentinel 2
- `10.6.0.13`: Consul/Sentinel 3
-To configure the Sentinel:
+NOTE: **Note:**
+If you're using an external Redis Sentinel instance, be sure to exclude the
+`requirepass` parameter from the Sentinel configuration. This parameter causes
+clients to report `NOAUTH Authentication required.`.
+[Redis Sentinel 3.2.x doesn't support password authentication](https://github.com/antirez/redis/issues/3279).
-1. SSH into the server that will host Consul/Sentinel.
-1. [Download/install](https://about.gitlab.com/install/) the
- Omnibus GitLab Enterprise Edition package using **steps 1 and 2** from the
- GitLab downloads page.
- - Make sure you select the correct Omnibus package, with the same version
- the GitLab application is running.
- - Do not complete any other steps on the download page.
+To configure the Sentinel:
+1. SSH in to the server that will host Consul/Sentinel.
+1. [Download and install](https://about.gitlab.com/install/) the Omnibus GitLab
+ package of your choice. Be sure to both follow _only_ installation steps 1 and 2
+ on the page, and to select the correct Omnibus GitLab package, with the same version
+ and type (Community or Enterprise editions) as your current install.
1. Edit `/etc/gitlab/gitlab.rb` and add the contents:
```ruby
@@ -556,10 +546,9 @@ To configure the Sentinel:
1. Go through the steps again for all the other Consul/Sentinel nodes, and
make sure you set up the correct IPs.
-NOTE: **Note:**
-A Consul leader will be elected when the provisioning of the third Consul server is completed.
-Viewing the Consul logs `sudo gitlab-ctl tail consul` will display
-`...[INFO] consul: New leader elected: ...`
+A Consul leader is _elected_ when the provisioning of the third Consul server is
+complete. Viewing the Consul logs `sudo gitlab-ctl tail consul` displays
+`...[INFO] consul: New leader elected: ...`.
You can list the current Consul members (server, client):
@@ -627,7 +616,7 @@ in the second step, do not supply the `EXTERNAL_URL` value.
#### PostgreSQL primary node
-1. SSH into the PostgreSQL primary node.
+1. SSH in to the PostgreSQL primary node.
1. Generate a password hash for the PostgreSQL username/password pair. This assumes you will use the default
username of `gitlab` (recommended). The command will request a password
and confirmation. Use the value that is output by this command in the next
@@ -812,7 +801,7 @@ are supported and can be added if needed.
#### PostgreSQL post-configuration
-SSH into the **primary node**:
+SSH in to the **primary node**:
1. Open a database prompt:
@@ -848,7 +837,7 @@ SSH into the **primary node**:
is not an IP address, it will need to be a resolvable name (via DNS or
`/etc/hosts`)
-SSH into the **secondary node**:
+SSH in to the **secondary node**:
1. Set up the repmgr standby:
@@ -1069,51 +1058,48 @@ Refer to your preferred Load Balancer's documentation for further guidance.
## Configure Gitaly
-Deploying Gitaly in its own server can benefit GitLab installations that are
-larger than a single machine.
-
-The Gitaly node requirements are dependent on customer data, specifically the number of
-projects and their repository sizes. Two nodes are recommended as an absolute minimum.
-Each Gitaly node should store no more than 5TB of data and have the number of
-[`gitaly-ruby` workers](../gitaly/index.md#gitaly-ruby) set to 20% of available CPUs.
-Additional nodes should be considered in conjunction with a review of expected
-data size and spread based on the recommendations above.
-
-It is also strongly recommended that all Gitaly nodes be set up with SSD disks with
-a throughput of at least 8,000 IOPS for read operations and 2,000 IOPS for write,
-as Gitaly has heavy I/O. These IOPS values are recommended only as a starter as with
-time they may be adjusted higher or lower depending on the scale of your environment's workload.
-If you're running the environment on a Cloud provider, you may need to refer to
-their documentation on how to configure IOPS correctly.
-
-Some things to note:
-
-- The GitLab Rails application shards repositories into [repository storages](../repository_storage_paths.md).
-- A Gitaly server can host one or more storages.
-- A GitLab server can use one or more Gitaly servers.
-- Gitaly addresses must be specified in such a way that they resolve
- correctly for ALL Gitaly clients.
+[Gitaly](../gitaly/index.md) server node requirements are dependent on data,
+specifically the number of projects and those projects' sizes. It's recommended
+that a Gitaly server node stores no more than 5 TB of data. Although this
+reference architecture includes a recommendation for the number of Gitaly server
+nodes to use, depending on your storage requirements, you may require additional
+Gitaly server nodes.
+
+Due to Gitaly having notable input and output requirements, we strongly
+recommend that all Gitaly nodes use solid-state drives (SSDs). These SSDs should
+have a throughput of at least 8,000 input/output operations per second (IOPS)
+for read operations and 2,000 IOPS for write operations. These IOPS values are
+initial recommendations, and may be adjusted to greater or lesser values
+depending on the scale of your environment's workload. If you're running the
+environment on a Cloud provider, refer to their documentation about how to
+configure IOPS correctly.
+
+Be sure to note the following items:
+
+- The GitLab Rails application shards repositories into
+ [repository storage paths](../repository_storage_paths.md).
+- A Gitaly server can host one or more storage paths.
+- A GitLab server can use one or more Gitaly server nodes.
+- Gitaly addresses must be specified to be correctly resolvable for _all_
+ Gitaly clients.
- Gitaly servers must not be exposed to the public internet, as Gitaly's network
traffic is unencrypted by default. The use of a firewall is highly recommended
to restrict access to the Gitaly server. Another option is to
[use TLS](#gitaly-tls-support).
-TIP: **Tip:**
-For more information about Gitaly's history and network architecture see the
-[standalone Gitaly documentation](../gitaly/index.md).
-
-Note: **Note:** The token referred to throughout the Gitaly documentation is
-just an arbitrary password selected by the administrator. It is unrelated to
-tokens created for the GitLab API or other similar web API tokens.
+NOTE: **Note:**
+The token referred to throughout the Gitaly documentation is an arbitrary
+password selected by the administrator. This token is unrelated to tokens
+created for the GitLab API or other similar web API tokens.
-Below we describe how to configure two Gitaly servers, with IPs and
-domain names:
+This section describes how to configure two Gitaly servers, with the following
+IPs and domain names:
- `10.6.0.51`: Gitaly 1 (`gitaly1.internal`)
- `10.6.0.52`: Gitaly 2 (`gitaly2.internal`)
-The secret token is assumed to be `gitalysecret` and that
-your GitLab installation has three repository storages:
+Assumptions about your servers include having the secret token be `gitalysecret`,
+and that your GitLab installation has three repository storages:
- `default` on Gitaly 1
- `storage1` on Gitaly 1
@@ -1121,11 +1107,11 @@ your GitLab installation has three repository storages:
On each node:
-1. [Download/Install](https://about.gitlab.com/install/) the Omnibus GitLab
- package you want using **steps 1 and 2** from the GitLab downloads page but
- **without** providing the `EXTERNAL_URL` value.
-1. Edit `/etc/gitlab/gitlab.rb` to configure storage paths, enable
- the network listener and configure the token:
+1. [Download and install](https://about.gitlab.com/install/) the Omnibus GitLab
+ package of your choice. Be sure to follow _only_ installation steps 1 and 2
+ on the page, and _do not_ provide the `EXTERNAL_URL` value.
+1. Edit `/etc/gitlab/gitlab.rb` to configure the storage paths, enable
+ the network listener, and configure the token:
<!--
updates to following example must also be made at
@@ -1189,39 +1175,39 @@ On each node:
```
1. Append the following to `/etc/gitlab/gitlab.rb` for each respective server:
- 1. On `gitaly1.internal`:
-
- ```ruby
- git_data_dirs({
- 'default' => {
- 'path' => '/var/opt/gitlab/git-data'
- },
- 'storage1' => {
- 'path' => '/mnt/gitlab/git-data'
- },
- })
- ```
-
- 1. On `gitaly2.internal`:
-
- ```ruby
- git_data_dirs({
- 'storage2' => {
- 'path' => '/mnt/gitlab/git-data'
- },
- })
- ```
+ - On `gitaly1.internal`:
+
+ ```ruby
+ git_data_dirs({
+ 'default' => {
+ 'path' => '/var/opt/gitlab/git-data'
+ },
+ 'storage1' => {
+ 'path' => '/mnt/gitlab/git-data'
+ },
+ })
+ ```
+
+ - On `gitaly2.internal`:
+
+ ```ruby
+ git_data_dirs({
+ 'storage2' => {
+ 'path' => '/mnt/gitlab/git-data'
+ },
+ })
+ ```
<!--
updates to following example must also be made at
https://gitlab.com/gitlab-org/charts/gitlab/blob/master/doc/advanced/external-gitaly/external-omnibus-gitaly.md#configure-omnibus-gitlab
-->
-1. Save the file and [reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure).
+1. Save the file, and then [reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure).
1. Confirm that Gitaly can perform callbacks to the internal API:
```shell
- sudo /opt/gitlab/embedded/service/gitlab-shell/bin/check -config /opt/gitlab/embedded/service/gitlab-shell/config.yml
+ sudo /opt/gitlab/embedded/bin/gitaly-hooks check /var/opt/gitlab/gitaly/config.toml
```
1. Verify the GitLab services are running:
@@ -1259,11 +1245,10 @@ Name. If you are addressing the Gitaly server by its IP address, you must add it
as a Subject Alternative Name to the certificate.
[gRPC does not support using an IP address as Common Name in a certificate](https://github.com/grpc/grpc/issues/2691).
-NOTE: **Note:**
-It is possible to configure Gitaly servers with both an
-unencrypted listening address `listen_addr` and an encrypted listening
-address `tls_listen_addr` at the same time. This allows you to do a
-gradual transition from unencrypted to encrypted traffic, if necessary.
+It's possible to configure Gitaly servers with both an unencrypted listening
+address (`listen_addr`) and an encrypted listening address (`tls_listen_addr`)
+at the same time. This allows you to do a gradual transition from unencrypted to
+encrypted traffic, if necessary.
To configure Gitaly with TLS:
@@ -1317,10 +1302,10 @@ The following IPs will be used as an example:
To configure the Sidekiq nodes, one each one:
-1. SSH into the Sidekiq server.
-1. [Download/install](https://about.gitlab.com/install/) the Omnibus GitLab package
-you want using steps 1 and 2 from the GitLab downloads page.
-**Do not complete any other steps on the download page.**
+1. SSH in to the Sidekiq server.
+1. [Download and install](https://about.gitlab.com/install/) the Omnibus GitLab
+ package of your choice. Be sure to follow _only_ installation steps 1 and 2
+ on the page.
1. Open `/etc/gitlab/gitlab.rb` with your editor:
```ruby
@@ -1431,14 +1416,14 @@ You can also run [multiple Sidekiq processes](../operations/extra_sidekiq_proces
## Configure GitLab Rails
-NOTE: **Note:**
-In our architectures we run each GitLab Rails node using the Puma webserver
-and have its number of workers set to 90% of available CPUs along with four threads. For
-nodes that are running Rails with other components the worker value should be reduced
-accordingly where we've found 50% achieves a good balance but this is dependent
-on workload.
-
This section describes how to configure the GitLab application (Rails) component.
+
+In our architecture, we run each GitLab Rails node using the Puma webserver, and
+have its number of workers set to 90% of available CPUs, with four threads. For
+nodes running Rails with other components, the worker value should be reduced
+accordingly. We've determined that a worker value of 50% achieves a good balance,
+but this is dependent on workload.
+
On each node perform the following:
1. If you're [using NFS](#configure-nfs-optional):
@@ -1466,10 +1451,10 @@ On each node perform the following:
mkdir -p /var/opt/gitlab/.ssh /var/opt/gitlab/gitlab-rails/uploads /var/opt/gitlab/gitlab-rails/shared /var/opt/gitlab/gitlab-ci/builds /var/opt/gitlab/git-data
```
-1. Download/install Omnibus GitLab using **steps 1 and 2** from
- [GitLab downloads](https://about.gitlab.com/install/). Do not complete other
- steps on the download page.
-1. Create/edit `/etc/gitlab/gitlab.rb` and use the following configuration.
+1. [Download and install](https://about.gitlab.com/install/) the Omnibus GitLab
+ package of your choice. Be sure to follow _only_ installation steps 1 and 2
+ on the page.
+1. Create or edit `/etc/gitlab/gitlab.rb` and use the following configuration.
To maintain uniformity of links across nodes, the `external_url`
on the application server should point to the external URL that users will use
to access GitLab. This would be the URL of the [external load balancer](#configure-the-external-load-balancer)
@@ -1582,6 +1567,11 @@ On each node perform the following:
sudo gitlab-ctl tail gitaly
```
+1. Save the `/etc/gitlab/gitlab-secrets.json` file from one of the two
+ application nodes and install it on the other application node, the
+ [Gitaly node](#configure-gitaly) and the [Sidekiq node](#configure-sidekiq) and
+ [reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure).
+
1. Verify the GitLab services are running:
```shell
@@ -1600,12 +1590,10 @@ On each node perform the following:
run: puma: (pid 4936) 8645s; run: log: (pid 29656) 79161s
```
-NOTE: **Note:**
-When you specify `https` in the `external_url`, as in the example
-above, GitLab assumes you have SSL certificates in `/etc/gitlab/ssl/`. If
-certificates are not present, NGINX will fail to start. See the
-[NGINX documentation](https://docs.gitlab.com/omnibus/settings/nginx.html#enable-https)
-for more information.
+When you specify `https` in the `external_url`, as in the previous example,
+GitLab expects that the SSL certificates are in `/etc/gitlab/ssl/`. If the
+certificates aren't present, NGINX will fail to start. For more information, see
+the [NGINX documentation](https://docs.gitlab.com/omnibus/settings/nginx.html#enable-https).
### GitLab Rails post-configuration
@@ -1615,12 +1603,11 @@ for more information.
gitlab-rake gitlab:db:configure
```
- NOTE: **Note:**
- If you encounter a `rake aborted!` error stating that PgBouncer is failing to connect to
- PostgreSQL it may be that your PgBouncer node's IP address is missing from
- PostgreSQL's `trust_auth_cidr_addresses` in `gitlab.rb` on your database nodes. See
- [PgBouncer error `ERROR: pgbouncer cannot connect to server`](troubleshooting.md#pgbouncer-error-error-pgbouncer-cannot-connect-to-server)
- in the Troubleshooting section before proceeding.
+ If you encounter a `rake aborted!` error message stating that PgBouncer is
+ failing to connect to PostgreSQL, it may be that your PgBouncer node's IP
+ address is missing from PostgreSQL's `trust_auth_cidr_addresses` in `gitlab.rb`
+ on your database nodes. Before proceeding, see
+ [PgBouncer error `ERROR: pgbouncer cannot connect to server`](troubleshooting.md#pgbouncer-error-error-pgbouncer-cannot-connect-to-server).
1. [Configure fast lookup of authorized SSH keys in the database](../operations/fast_ssh_key_lookup.md).
@@ -1636,10 +1623,10 @@ The Omnibus GitLab package can be used to configure a standalone Monitoring node
running [Prometheus](../monitoring/prometheus/index.md) and
[Grafana](../monitoring/performance/grafana_configuration.md):
-1. SSH into the Monitoring node.
-1. [Download/install](https://about.gitlab.com/install/) the Omnibus GitLab
- package you want using **steps 1 and 2** from the GitLab downloads page.
- Do not complete any other steps on the download page.
+1. SSH in to the Monitoring node.
+1. [Download and install](https://about.gitlab.com/install/) the Omnibus GitLab
+ package of your choice. Be sure to follow _only_ installation steps 1 and 2
+ on the page.
1. Edit `/etc/gitlab/gitlab.rb` and add the contents:
```ruby
@@ -1714,28 +1701,44 @@ It's recommended over [NFS](#configure-nfs-optional) and in general it's better
in larger setups as object storage is typically much more performant, reliable,
and scalable.
-Object storage options that GitLab has tested, or is aware of customers using include:
+GitLab has been tested on a number of object storage providers:
-- SaaS/Cloud solutions such as [Amazon S3](https://aws.amazon.com/s3/), [Google cloud storage](https://cloud.google.com/storage).
+- [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)
+- [Openstack Swift](https://docs.openstack.org/swift/latest/s3_compat.html)
+- [Azure Blob storage](https://docs.microsoft.com/en-us/azure/storage/blobs/storage-blobs-introduction)
- On-premises hardware and appliances from various storage vendors.
-- MinIO. There is [a guide to deploying this](https://docs.gitlab.com/charts/advanced/external-object-storage/minio.html) within our Helm Chart documentation.
-
-For configuring GitLab to use Object Storage refer to the following guides
-based on what features you intend to use:
-
-1. Configure [object storage for backups](../../raketasks/backup_restore.md#uploading-backups-to-a-remote-cloud-storage).
-1. Configure [object storage for job artifacts](../job_artifacts.md#using-object-storage)
- including [incremental logging](../job_logs.md#new-incremental-logging-architecture).
-1. Configure [object storage for LFS objects](../lfs/index.md#storing-lfs-objects-in-remote-object-storage).
-1. Configure [object storage for uploads](../uploads.md#using-object-storage).
-1. Configure [object storage for merge request diffs](../merge_request_diffs.md#using-object-storage).
-1. Configure [object storage for Container Registry](../packages/container_registry.md#use-object-storage) (optional feature).
-1. Configure [object storage for Mattermost](https://docs.mattermost.com/administration/config-settings.html#file-storage) (optional feature).
-1. Configure [object storage for packages](../packages/index.md#using-object-storage) (optional feature). **(PREMIUM ONLY)**
-1. Configure [object storage for Dependency Proxy](../packages/dependency_proxy.md#using-object-storage) (optional feature). **(PREMIUM ONLY)**
-1. Configure [object storage for Pseudonymizer](../pseudonymizer.md#configuration) (optional feature). **(ULTIMATE ONLY)**
-1. Configure [object storage for autoscale runner caching](https://docs.gitlab.com/runner/configuration/autoscale.html#distributed-runners-caching) (optional - for improved performance).
-1. Configure [object storage for Terraform state files](../terraform_state.md#using-object-storage).
+- MinIO. We have [a guide to deploying this](https://docs.gitlab.com/charts/advanced/external-object-storage/minio.html) within our Helm Chart documentation.
+
+There are two ways of specifying object storage configuration in GitLab:
+
+- [Consolidated form](../object_storage.md#consolidated-object-storage-configuration): A single credential is
+ shared by all supported object types.
+- [Storage-specific form](../object_storage.md#storage-specific-configuration): Every object defines its
+ own object storage [connection and configuration](../object_storage.md#connection-settings).
+
+Starting with GitLab 13.2, consolidated object storage configuration is available. It simplifies your GitLab configuration since the connection details are shared across object types. Refer to [Consolidated object storage configuration](../object_storage.md#consolidated-object-storage-configuration) guide for instructions on how to set it up.
+
+For configuring object storage in GitLab 13.1 and earlier, or for storage types not
+supported by consolidated configuration form, refer to the following guides based
+on what features you intend to use:
+
+|Object storage type|Supported by consolidated configuration?|
+|-------------------|----------------------------------------|
+| [Backups](../../raketasks/backup_restore.md#uploading-backups-to-a-remote-cloud-storage)|No|
+| [Job artifacts](../job_artifacts.md#using-object-storage) including archived job logs | Yes |
+| [LFS objects](../lfs/index.md#storing-lfs-objects-in-remote-object-storage) | Yes |
+| [Uploads](../uploads.md#using-object-storage) | Yes |
+| [Container Registry](../packages/container_registry.md#use-object-storage) (optional feature) | No |
+| [Merge request diffs](../merge_request_diffs.md#using-object-storage) | Yes |
+| [Mattermost](https://docs.mattermost.com/administration/config-settings.html#file-storage)| No |
+| [Packages](../packages/index.md#using-object-storage) (optional feature) | Yes |
+| [Dependency Proxy](../packages/dependency_proxy.md#using-object-storage) (optional feature) **(PREMIUM ONLY)** | Yes |
+| [Pseudonymizer](../pseudonymizer.md#configuration) (optional feature) **(ULTIMATE ONLY)** | No |
+| [Autoscale runner caching](https://docs.gitlab.com/runner/configuration/autoscale.html#distributed-runners-caching) (optional for improved performance) | No |
+| [Terraform state files](../terraform_state.md#using-object-storage) | Yes |
Using separate buckets for each data type is the recommended approach for GitLab.
@@ -1759,6 +1762,22 @@ work.
</a>
</div>
+## Configure Advanced Search **(STARTER ONLY)**
+
+You can leverage Elasticsearch and [enable Advanced Search](../../integration/elasticsearch.md)
+for faster, more advanced code search across your entire GitLab instance.
+
+Elasticsearch cluster design and requirements are dependent on your specific
+data. For recommended best practices about how to set up your Elasticsearch
+cluster alongside your instance, read how to
+[choose the optimal cluster configuration](../../integration/elasticsearch.md#guidance-on-choosing-optimal-cluster-configuration).
+
+<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>
+
## Configure NFS (optional)
[Object storage](#configure-the-object-storage), along with [Gitaly](#configure-gitaly)
diff --git a/doc/administration/reference_architectures/50k_users.md b/doc/administration/reference_architectures/50k_users.md
index e812eed0227..44fbe2db504 100644
--- a/doc/administration/reference_architectures/50k_users.md
+++ b/doc/administration/reference_architectures/50k_users.md
@@ -17,21 +17,21 @@ full list of reference architectures, see
| Service | Nodes | Configuration | GCP | AWS | Azure |
|-----------------------------------------|-------------|-------------------------|-----------------|--------------|----------|
-| External load balancing node | 1 | 8 vCPU, 7.2GB memory | n1-highcpu-8 | c5.2xlarge | F8s v2 |
-| Consul | 3 | 2 vCPU, 1.8GB memory | n1-highcpu-2 | c5.large | F2s v2 |
-| PostgreSQL | 3 | 16 vCPU, 60GB memory | n1-standard-16 | m5.4xlarge | D16s v3 |
-| PgBouncer | 3 | 2 vCPU, 1.8GB memory | n1-highcpu-2 | c5.large | F2s v2 |
-| Internal load balancing node | 1 | 8 vCPU, 7.2GB memory | n1-highcpu-8 | c5.2xlarge | F8s v2 |
-| Redis - Cache | 3 | 4 vCPU, 15GB memory | n1-standard-4 | m5.xlarge | D4s v3 |
-| Redis - Queues / Shared State | 3 | 4 vCPU, 15GB memory | n1-standard-4 | m5.xlarge | D4s v3 |
-| Redis Sentinel - Cache | 3 | 1 vCPU, 1.7GB memory | g1-small | t2.small | B1MS |
-| Redis Sentinel - Queues / Shared State | 3 | 1 vCPU, 1.7GB memory | g1-small | t2.small | B1MS |
-| Gitaly | 2 (minimum) | 64 vCPU, 240GB memory | n1-standard-64 | m5.16xlarge | D64s v3 |
-| Sidekiq | 4 | 4 vCPU, 15GB memory | n1-standard-4 | m5.xlarge | D4s v3 |
-| GitLab Rails | 12 | 32 vCPU, 28.8GB memory | n1-highcpu-32 | c5.9xlarge | F32s v2 |
-| Monitoring node | 1 | 4 vCPU, 3.6GB memory | n1-highcpu-4 | c5.xlarge | F4s v2 |
-| Object Storage | n/a | n/a | n/a | n/a | n/a |
-| NFS Server | 1 | 4 vCPU, 3.6GB memory | n1-highcpu-4 | c5.xlarge | F4s v2 |
+| External load balancing node | 1 | 8 vCPU, 7.2 GB memory | n1-highcpu-8 | c5.2xlarge | F8s v2 |
+| Consul | 3 | 2 vCPU, 1.8 GB memory | n1-highcpu-2 | c5.large | F2s v2 |
+| PostgreSQL | 3 | 16 vCPU, 60 GB memory | n1-standard-16 | m5.4xlarge | D16s v3 |
+| PgBouncer | 3 | 2 vCPU, 1.8 GB memory | n1-highcpu-2 | c5.large | F2s v2 |
+| Internal load balancing node | 1 | 8 vCPU, 7.2 GB memory | n1-highcpu-8 | c5.2xlarge | F8s v2 |
+| Redis - Cache | 3 | 4 vCPU, 15 GB memory | n1-standard-4 | m5.xlarge | D4s v3 |
+| Redis - Queues / Shared State | 3 | 4 vCPU, 15 GB memory | n1-standard-4 | m5.xlarge | D4s v3 |
+| Redis Sentinel - Cache | 3 | 1 vCPU, 1.7 GB memory | g1-small | t2.small | B1MS |
+| Redis Sentinel - Queues / Shared State | 3 | 1 vCPU, 1.7 GB memory | g1-small | t2.small | B1MS |
+| Gitaly | 2 (minimum) | 64 vCPU, 240 GB memory | n1-standard-64 | m5.16xlarge | D64s v3 |
+| Sidekiq | 4 | 4 vCPU, 15 GB memory | n1-standard-4 | m5.xlarge | D4s v3 |
+| GitLab Rails | 12 | 32 vCPU, 28.8 GB memory | n1-highcpu-32 | c5.9xlarge | F32s v2 |
+| Monitoring node | 1 | 4 vCPU, 3.6 GB memory | n1-highcpu-4 | c5.xlarge | F4s v2 |
+| Object storage | n/a | n/a | n/a | n/a | n/a |
+| NFS server | 1 | 4 vCPU, 3.6 GB memory | n1-highcpu-4 | c5.xlarge | F4s v2 |
The Google Cloud Platform (GCP) architectures were built and tested using the
[Intel Xeon E5 v3 (Haswell)](https://cloud.google.com/compute/docs/cpu-platforms)
@@ -40,41 +40,43 @@ or higher, are required for your CPU or node counts. For more information, see
our [Sysbench](https://github.com/akopytov/sysbench)-based
[CPU benchmark](https://gitlab.com/gitlab-org/quality/performance/-/wikis/Reference-Architectures/GCP-CPU-Benchmarks).
-For data objects (such as LFS, Uploads, or Artifacts), an
-[object storage service](#configure-the-object-storage) is recommended instead
-of NFS where possible, due to better performance and availability. Since this
-doesn't require a node to be set up, *Object Storage* is noted as not
-applicable (n/a) in the previous table.
+Due to better performance and availability, for data objects (such as LFS,
+uploads, or artifacts), using an [object storage service](#configure-the-object-storage)
+is recommended instead of using NFS. Using an object storage service also
+doesn't require you to provision and maintain a node.
## Setup components
To set up GitLab and its components to accommodate up to 50,000 users:
1. [Configure the external load balancing node](#configure-the-external-load-balancer)
- that will handle the load balancing of the three GitLab application services nodes.
+ to handle the load balancing of the GitLab application services nodes.
1. [Configure Consul](#configure-consul).
1. [Configure PostgreSQL](#configure-postgresql), the database for GitLab.
1. [Configure PgBouncer](#configure-pgbouncer).
-1. [Configure the internal load balancing node](#configure-the-internal-load-balancer)
+1. [Configure the internal load balancing node](#configure-the-internal-load-balancer).
1. [Configure Redis](#configure-redis).
1. [Configure Gitaly](#configure-gitaly),
which provides access to the Git repositories.
1. [Configure Sidekiq](#configure-sidekiq).
1. [Configure the main GitLab Rails application](#configure-gitlab-rails)
- to run Puma/Unicorn, Workhorse, GitLab Shell, and to serve all frontend requests (UI, API, Git
- over HTTP/SSH).
-1. [Configure Prometheus](#configure-prometheus) to monitor your GitLab environment.
-1. [Configure the Object Storage](#configure-the-object-storage)
+ to run Puma/Unicorn, Workhorse, GitLab Shell, and to serve all frontend
+ requests (which include UI, API, and Git over HTTP/SSH).
+1. [Configure Prometheus](#configure-prometheus) to monitor your GitLab
+ environment.
+1. [Configure the object storage](#configure-the-object-storage)
used for shared data objects.
-1. [Configure NFS (Optional)](#configure-nfs-optional)
- to have shared disk storage service as an alternative to Gitaly and/or Object Storage (although
- not recommended). NFS is required for GitLab Pages, you can skip this step if you're not using
- that feature.
+1. [Configure Advanced Search](#configure-advanced-search) (optional) for faster,
+ more advanced code search across your entire GitLab instance.
+1. [Configure NFS](#configure-nfs-optional) (optional, and not recommended)
+ to have shared disk storage service as an alternative to Gitaly or object
+ storage. You can skip this step if you're not using GitLab Pages (which
+ requires NFS).
-We start with all servers on the same 10.6.0.0/24 private network range, they
-can connect to each other freely on those addresses.
+The servers start on the same 10.6.0.0/24 private network range, and can
+connect to each other freely on these addresses.
-Here is a list and description of each machine and the assigned IP:
+The following list includes descriptions of each server and its assigned IP:
- `10.6.0.10`: External Load Balancer
- `10.6.0.11`: Consul 1
@@ -112,19 +114,18 @@ Here is a list and description of each machine and the assigned IP:
## Configure the external load balancer
-NOTE: **Note:**
+In an active/active 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 hope
+that if you're managing multi-node systems like GitLab, you already have a load
+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.
+
This architecture has been tested and validated with [HAProxy](https://www.haproxy.org/)
as the load balancer. Although other load balancers with similar feature sets
could also be used, those load balancers have not been validated.
-In an active/active GitLab configuration, you will need a load balancer to route
-traffic to the application servers. The specifics on which load balancer to use
-or the exact configuration is beyond the scope of GitLab documentation. We hope
-that if you're managing multi-node systems like GitLab you have a load balancer of
-choice already. Some examples including HAProxy (open-source), F5 Big-IP LTM,
-and Citrix Net Scaler. This documentation will outline what ports and protocols
-you need to use with GitLab.
-
The next question is how you will handle SSL in your environment.
There are several different options:
@@ -247,14 +248,11 @@ with the other servers.
To configure Consul:
-1. SSH into the server that will host Consul.
-1. [Download/install](https://about.gitlab.com/install/) the
- Omnibus GitLab Enterprise Edition package using **steps 1 and 2** from the
- GitLab downloads page.
- - Make sure you select the correct Omnibus package, with the same version
- the GitLab application is running.
- - Do not complete any other steps on the download page.
-
+1. SSH in to the server that will host Consul.
+1. [Download and install](https://about.gitlab.com/install/) the Omnibus GitLab
+ package of your choice. Be sure to both follow _only_ installation steps 1 and 2
+ on the page, and to select the correct Omnibus GitLab package, with the same version
+ and type (Community or Enterprise editions) as your current install.
1. Edit `/etc/gitlab/gitlab.rb` and add the contents:
```ruby
@@ -282,10 +280,9 @@ To configure Consul:
1. Go through the steps again for all the other Consul nodes, and
make sure you set up the correct IPs.
-NOTE: **Note:**
-A Consul leader will be elected when the provisioning of the third Consul server is completed.
-Viewing the Consul logs `sudo gitlab-ctl tail consul` will display
-`...[INFO] consul: New leader elected: ...`
+A Consul leader is _elected_ when the provisioning of the third Consul server is
+complete. Viewing the Consul logs `sudo gitlab-ctl tail consul` displays
+`...[INFO] consul: New leader elected: ...`.
You can list the current Consul members (server, client):
@@ -352,7 +349,7 @@ in the second step, do not supply the `EXTERNAL_URL` value.
#### PostgreSQL primary node
-1. SSH into the PostgreSQL primary node.
+1. SSH in to the PostgreSQL primary node.
1. Generate a password hash for the PostgreSQL username/password pair. This assumes you will use the default
username of `gitlab` (recommended). The command will request a password
and confirmation. Use the value that is output by this command in the next
@@ -513,7 +510,7 @@ are supported and can be added if needed.
#### PostgreSQL post-configuration
-SSH into the **primary node**:
+SSH in to the **primary node**:
1. Open a database prompt:
@@ -548,7 +545,7 @@ SSH into the **primary node**:
is not an IP address, it will need to be a resolvable name (via DNS or
`/etc/hosts`)
-SSH into the **secondary node**:
+SSH in to the **secondary node**:
1. Set up the repmgr standby:
@@ -662,7 +659,6 @@ The following IPs will be used as an example:
1. [Reconfigure Omnibus GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure) for the changes to take effect.
- NOTE: **Note:**
If an error `execute[generate databases.ini]` occurs, this is due to an existing
[known issue](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/4713).
It will be resolved when you run a second `reconfigure` after the next step.
@@ -796,35 +792,31 @@ to be used with GitLab. The following IPs will be used as an example:
- `10.6.0.82`: Sentinel - Queues 2
- `10.6.0.83`: Sentinel - Queues 3
-NOTE: **Providing your own Redis instance:**
-Managed Redis from cloud providers such as AWS ElastiCache will work. If these
-services support high availability, be sure it is **not** the Redis Cluster type.
-Redis version 5.0 or higher is required, as this is what ships with
-Omnibus GitLab packages starting with GitLab 13.0. Older Redis versions
-do not support an optional count argument to SPOP which is now required for
-[Merge Trains](../../ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/index.md).
+### Providing your own Redis instance
+
+Managed Redis from cloud providers (such as AWS ElastiCache) will work. If these
+services support high availability, be sure it _isn't_ of the Redis Cluster type.
+Redis version 5.0 or higher is required, which is included with Omnibus GitLab
+packages starting with GitLab 13.0. Older Redis versions don't support an
+optional count argument to SPOP, which is required for [Merge Trains](../../ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/index.md).
Note the Redis node's IP address or hostname, port, and password (if required).
-These will be necessary when configuring the
-[GitLab application servers](#configure-gitlab-rails) later.
+These will be necessary later when configuring the [GitLab application servers](#configure-gitlab-rails).
### Configure the Redis and Sentinel Cache cluster
This is the section where we install and set up the new Redis Cache instances.
-NOTE: **Note:**
-Redis nodes (both primary and replica) will need the same password defined in
-`redis['password']`. At any time during a failover the Sentinels can
-reconfigure a node and change its status from primary to replica and vice versa.
+Both the primary and replica Redis nodes need the same password defined in
+`redis['password']`. At any time during a failover, the Sentinels can reconfigure
+a node and change its status from primary to replica (and vice versa).
#### Configure the primary Redis Cache node
-1. SSH into the **Primary** Redis server.
-1. [Download/install](https://about.gitlab.com/install/) the Omnibus GitLab
- package you want using **steps 1 and 2** from the GitLab downloads page.
- - Make sure you select the correct Omnibus package, with the same version
- and type (Community, Enterprise editions) of your current install.
- - Do not complete any other steps on the download page.
-
+1. SSH in to the **Primary** Redis server.
+1. [Download and install](https://about.gitlab.com/install/) the Omnibus GitLab
+ package of your choice. Be sure to both follow _only_ installation steps 1 and 2
+ on the page, and to select the correct Omnibus GitLab package, with the same version
+ and type (Community or Enterprise editions) as your current install.
1. Edit `/etc/gitlab/gitlab.rb` and add the contents:
```ruby
@@ -868,20 +860,17 @@ reconfigure a node and change its status from primary to replica and vice versa.
1. [Reconfigure Omnibus GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure) for the changes to take effect.
-NOTE: **Note:**
-You can specify multiple roles like sentinel and Redis as:
-`roles ['redis_sentinel_role', 'redis_master_role']`.
-Read more about [roles](https://docs.gitlab.com/omnibus/roles/).
+You can specify multiple roles, like sentinel and Redis, as:
+`roles ['redis_sentinel_role', 'redis_master_role']`. Read more about
+[roles](https://docs.gitlab.com/omnibus/roles/).
#### Configure the replica Redis Cache nodes
-1. SSH into the **replica** Redis server.
-1. [Download/install](https://about.gitlab.com/install/) the Omnibus GitLab
- package you want using **steps 1 and 2** from the GitLab downloads page.
- - Make sure you select the correct Omnibus package, with the same version
- and type (Community, Enterprise editions) of your current install.
- - Do not complete any other steps on the download page.
-
+1. SSH in to the **replica** Redis server.
+1. [Download and install](https://about.gitlab.com/install/) the Omnibus GitLab
+ package of your choice. Be sure to both follow _only_ installation steps 1 and 2
+ on the page, and to select the correct Omnibus GitLab package, with the same version
+ and type (Community or Enterprise editions) as your current install.
1. Edit `/etc/gitlab/gitlab.rb` and add the contents:
```ruby
@@ -934,10 +923,9 @@ Read more about [roles](https://docs.gitlab.com/omnibus/roles/).
1. Go through the steps again for all the other replica nodes, and
make sure to set up the IPs correctly.
-NOTE: **Note:**
-You can specify multiple roles like sentinel and Redis as:
-`roles ['redis_sentinel_role', 'redis_master_role']`.
-Read more about [roles](https://docs.gitlab.com/omnibus/roles/).
+You can specify multiple roles, like sentinel and Redis, as:
+`roles ['redis_sentinel_role', 'redis_master_role']`. Read more about
+[roles](https://docs.gitlab.com/omnibus/roles/).
These values don't have to be changed again in `/etc/gitlab/gitlab.rb` after
a failover, as the nodes will be managed by the [Sentinels](#configure-the-sentinel-cache-nodes), and even after a
@@ -955,13 +943,6 @@ are supported and can be added if needed.
#### Configure the Sentinel Cache nodes
-NOTE: **Note:**
-If you are using an external Redis Sentinel instance, be sure
-to exclude the `requirepass` parameter from the Sentinel
-configuration. This parameter will cause clients to report `NOAUTH
-Authentication required.`. [Redis Sentinel 3.2.x does not support
-password authentication](https://github.com/antirez/redis/issues/3279).
-
Now that the Redis servers are all set up, let's configure the Sentinel
servers. The following IPs will be used as an example:
@@ -969,16 +950,19 @@ servers. The following IPs will be used as an example:
- `10.6.0.72`: Sentinel - Cache 2
- `10.6.0.73`: Sentinel - Cache 3
-To configure the Sentinel Cache server:
+NOTE: **Note:**
+If you're using an external Redis Sentinel instance, be sure to exclude the
+`requirepass` parameter from the Sentinel configuration. This parameter causes
+clients to report `NOAUTH Authentication required.`.
+[Redis Sentinel 3.2.x doesn't support password authentication](https://github.com/antirez/redis/issues/3279).
-1. SSH into the server that will host Consul/Sentinel.
-1. [Download/install](https://about.gitlab.com/install/) the
- Omnibus GitLab Enterprise Edition package using **steps 1 and 2** from the
- GitLab downloads page.
- - Make sure you select the correct Omnibus package, with the same version
- the GitLab application is running.
- - Do not complete any other steps on the download page.
+To configure the Sentinel Cache server:
+1. SSH in to the server that will host Consul/Sentinel.
+1. [Download and install](https://about.gitlab.com/install/) the Omnibus GitLab
+ package of your choice. Be sure to both follow _only_ installation steps 1 and 2
+ on the page, and to select the correct Omnibus GitLab package, with the same version
+ and type (Community or Enterprise editions) as your current install.
1. Edit `/etc/gitlab/gitlab.rb` and add the contents:
```ruby
@@ -1081,20 +1065,17 @@ To configure the Sentinel Cache server:
This is the section where we install and set up the new Redis Queues instances.
-NOTE: **Note:**
-Redis nodes (both primary and replica) will need the same password defined in
-`redis['password']`. At any time during a failover the Sentinels can
-reconfigure a node and change its status from primary to replica and vice versa.
+Both the primary and replica Redis nodes need the same password defined in
+`redis['password']`. At any time during a failover, the Sentinels can reconfigure
+a node and change its status from primary to replica (and vice versa).
#### Configure the primary Redis Queues node
-1. SSH into the **Primary** Redis server.
-1. [Download/install](https://about.gitlab.com/install/) the Omnibus GitLab
- package you want using **steps 1 and 2** from the GitLab downloads page.
- - Make sure you select the correct Omnibus package, with the same version
- and type (Community, Enterprise editions) of your current install.
- - Do not complete any other steps on the download page.
-
+1. SSH in to the **Primary** Redis server.
+1. [Download and install](https://about.gitlab.com/install/) the Omnibus GitLab
+ package of your choice. Be sure to both follow _only_ installation steps 1 and 2
+ on the page, and to select the correct Omnibus GitLab package, with the same version
+ and type (Community or Enterprise editions) as your current install.
1. Edit `/etc/gitlab/gitlab.rb` and add the contents:
```ruby
@@ -1143,20 +1124,17 @@ reconfigure a node and change its status from primary to replica and vice versa.
1. [Reconfigure Omnibus GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure) for the changes to take effect.
-NOTE: **Note:**
-You can specify multiple roles like sentinel and Redis as:
-`roles ['redis_sentinel_role', 'redis_master_role']`.
-Read more about [roles](https://docs.gitlab.com/omnibus/roles/).
+You can specify multiple roles, like sentinel and Redis, as:
+`roles ['redis_sentinel_role', 'redis_master_role']`. Read more about
+[roles](https://docs.gitlab.com/omnibus/roles/).
#### Configure the replica Redis Queues nodes
-1. SSH into the **replica** Redis Queue server.
-1. [Download/install](https://about.gitlab.com/install/) the Omnibus GitLab
- package you want using **steps 1 and 2** from the GitLab downloads page.
- - Make sure you select the correct Omnibus package, with the same version
- and type (Community, Enterprise editions) of your current install.
- - Do not complete any other steps on the download page.
-
+1. SSH in to the **replica** Redis Queue server.
+1. [Download and install](https://about.gitlab.com/install/) the Omnibus GitLab
+ package of your choice. Be sure to both follow _only_ installation steps 1 and 2
+ on the page, and to select the correct Omnibus GitLab package, with the same version
+ and type (Community or Enterprise editions) as your current install.
1. Edit `/etc/gitlab/gitlab.rb` and add the contents:
```ruby
@@ -1209,10 +1187,9 @@ Read more about [roles](https://docs.gitlab.com/omnibus/roles/).
1. Go through the steps again for all the other replica nodes, and
make sure to set up the IPs correctly.
-NOTE: **Note:**
-You can specify multiple roles like sentinel and Redis as:
-`roles ['redis_sentinel_role', 'redis_master_role']`.
-Read more about [roles](https://docs.gitlab.com/omnibus/roles/).
+You can specify multiple roles, like sentinel and Redis, as:
+`roles ['redis_sentinel_role', 'redis_master_role']`. Read more about
+[roles](https://docs.gitlab.com/omnibus/roles/).
These values don't have to be changed again in `/etc/gitlab/gitlab.rb` after
a failover, as the nodes will be managed by the [Sentinels](#configure-the-sentinel-queues-nodes), and even after a
@@ -1230,13 +1207,6 @@ are supported and can be added if needed.
#### Configure the Sentinel Queues nodes
-NOTE: **Note:**
-If you are using an external Redis Sentinel instance, be sure
-to exclude the `requirepass` parameter from the Sentinel
-configuration. This parameter will cause clients to report `NOAUTH
-Authentication required.`. [Redis Sentinel 3.2.x does not support
-password authentication](https://github.com/antirez/redis/issues/3279).
-
Now that the Redis servers are all set up, let's configure the Sentinel
servers. The following IPs will be used as an example:
@@ -1244,16 +1214,19 @@ servers. The following IPs will be used as an example:
- `10.6.0.82`: Sentinel - Queues 2
- `10.6.0.83`: Sentinel - Queues 3
-To configure the Sentinel Queues server:
+NOTE: **Note:**
+If you're using an external Redis Sentinel instance, be sure to exclude the
+`requirepass` parameter from the Sentinel configuration. This parameter causes
+clients to report `NOAUTH Authentication required.`.
+[Redis Sentinel 3.2.x doesn't support password authentication](https://github.com/antirez/redis/issues/3279).
-1. SSH into the server that will host Sentinel.
-1. [Download/install](https://about.gitlab.com/install/) the
- Omnibus GitLab Enterprise Edition package using **steps 1 and 2** from the
- GitLab downloads page.
- - Make sure you select the correct Omnibus package, with the same version
- the GitLab application is running.
- - Do not complete any other steps on the download page.
+To configure the Sentinel Queues server:
+1. SSH in to the server that will host Sentinel.
+1. [Download and install](https://about.gitlab.com/install/) the Omnibus GitLab
+ package of your choice. Be sure to both follow _only_ installation steps 1 and 2
+ on the page, and to select the correct Omnibus GitLab package, with the same version
+ and type (Community or Enterprise editions) as your current install.
1. Edit `/etc/gitlab/gitlab.rb` and add the contents:
```ruby
@@ -1362,52 +1335,48 @@ To configure the Sentinel Queues server:
## Configure Gitaly
-Deploying Gitaly in its own server can benefit GitLab installations that are
-larger than a single machine.
-
-The Gitaly node requirements are dependent on customer data, specifically the number of
-projects and their repository sizes. Two nodes are recommended as an absolute minimum.
-Each Gitaly node should store no more than 5TB of data and have the number of
-[`gitaly-ruby` workers](../gitaly/index.md#gitaly-ruby) set to 20% of available CPUs.
-Additional nodes should be considered in conjunction with a review of expected
-data size and spread based on the recommendations above.
-
-It is also strongly recommended that all Gitaly nodes be set up with SSD disks with
-a throughput of at least 8,000 IOPS for read operations and 2,000 IOPS for write,
-as Gitaly has heavy I/O. These IOPS values are recommended only as a starter as with
-time they may be adjusted higher or lower depending on the scale of your environment's workload.
-If you're running the environment on a Cloud provider, you may need to refer to
-their documentation on how to configure IOPS correctly.
-
-Some things to note:
-
-- The GitLab Rails application shards repositories into [repository storages](../repository_storage_paths.md).
-- A Gitaly server can host one or more storages.
-- A GitLab server can use one or more Gitaly servers.
-- Gitaly addresses must be specified in such a way that they resolve
- correctly for ALL Gitaly clients.
+[Gitaly](../gitaly/index.md) server node requirements are dependent on data,
+specifically the number of projects and those projects' sizes. It's recommended
+that a Gitaly server node stores no more than 5 TB of data. Although this
+reference architecture includes a recommendation for the number of Gitaly server
+nodes to use, depending on your storage requirements, you may require additional
+Gitaly server nodes.
+
+Due to Gitaly having notable input and output requirements, we strongly
+recommend that all Gitaly nodes use solid-state drives (SSDs). These SSDs should
+have a throughput of at least 8,000 input/output operations per second (IOPS)
+for read operations and 2,000 IOPS for write operations. These IOPS values are
+initial recommendations, and may be adjusted to greater or lesser values
+depending on the scale of your environment's workload. If you're running the
+environment on a Cloud provider, refer to their documentation about how to
+configure IOPS correctly.
+
+Be sure to note the following items:
+
+- The GitLab Rails application shards repositories into
+ [repository storage paths](../repository_storage_paths.md).
+- A Gitaly server can host one or more storage paths.
+- A GitLab server can use one or more Gitaly server nodes.
+- Gitaly addresses must be specified to be correctly resolvable for _all_
+ Gitaly clients.
- Gitaly servers must not be exposed to the public internet, as Gitaly's network
traffic is unencrypted by default. The use of a firewall is highly recommended
to restrict access to the Gitaly server. Another option is to
[use TLS](#gitaly-tls-support).
-TIP: **Tip:**
-For more information about Gitaly's history and network architecture see the
-[standalone Gitaly documentation](../gitaly/index.md).
-
-Note: **Note:**
-The token referred to throughout the Gitaly documentation is
-just an arbitrary password selected by the administrator. It is unrelated to
-tokens created for the GitLab API or other similar web API tokens.
+NOTE: **Note:**
+The token referred to throughout the Gitaly documentation is an arbitrary
+password selected by the administrator. This token is unrelated to tokens
+created for the GitLab API or other similar web API tokens.
-Below we describe how to configure two Gitaly servers, with IPs and
-domain names:
+This section describes how to configure two Gitaly servers, with the following
+IPs and domain names:
- `10.6.0.91`: Gitaly 1 (`gitaly1.internal`)
- `10.6.0.92`: Gitaly 2 (`gitaly2.internal`)
-The secret token is assumed to be `gitalysecret` and that
-your GitLab installation has three repository storages:
+Assumptions about your servers include having the secret token be `gitalysecret`,
+and that your GitLab installation has three repository storages:
- `default` on Gitaly 1
- `storage1` on Gitaly 1
@@ -1415,11 +1384,11 @@ your GitLab installation has three repository storages:
On each node:
-1. [Download/Install](https://about.gitlab.com/install/) the Omnibus GitLab
- package you want using **steps 1 and 2** from the GitLab downloads page but
- **without** providing the `EXTERNAL_URL` value.
-1. Edit `/etc/gitlab/gitlab.rb` to configure storage paths, enable
- the network listener and configure the token:
+1. [Download and install](https://about.gitlab.com/install/) the Omnibus GitLab
+ package of your choice. Be sure to follow _only_ installation steps 1 and 2
+ on the page, and _do not_ provide the `EXTERNAL_URL` value.
+1. Edit `/etc/gitlab/gitlab.rb` to configure the storage paths, enable
+ the network listener, and configure the token:
<!--
updates to following example must also be made at
@@ -1467,39 +1436,39 @@ On each node:
```
1. Append the following to `/etc/gitlab/gitlab.rb` for each respective server:
- 1. On `gitaly1.internal`:
-
- ```ruby
- git_data_dirs({
- 'default' => {
- 'path' => '/var/opt/gitlab/git-data'
- },
- 'storage1' => {
- 'path' => '/mnt/gitlab/git-data'
- },
- })
- ```
-
- 1. On `gitaly2.internal`:
-
- ```ruby
- git_data_dirs({
- 'storage2' => {
- 'path' => '/mnt/gitlab/git-data'
- },
- })
- ```
+ - On `gitaly1.internal`:
+
+ ```ruby
+ git_data_dirs({
+ 'default' => {
+ 'path' => '/var/opt/gitlab/git-data'
+ },
+ 'storage1' => {
+ 'path' => '/mnt/gitlab/git-data'
+ },
+ })
+ ```
+
+ - On `gitaly2.internal`:
+
+ ```ruby
+ git_data_dirs({
+ 'storage2' => {
+ 'path' => '/mnt/gitlab/git-data'
+ },
+ })
+ ```
<!--
updates to following example must also be made at
https://gitlab.com/gitlab-org/charts/gitlab/blob/master/doc/advanced/external-gitaly/external-omnibus-gitaly.md#configure-omnibus-gitlab
-->
-1. Copy the `/etc/gitlab/gitlab-secrets.json` file from your Consul server, and replace
- the file of the same name on this server. If that file is not on this server,
- add the file from your Consul server to this server.
+1. Copy the `/etc/gitlab/gitlab-secrets.json` file from your Consul server, and
+ then replace the file of the same name on this server. If that file isn't on
+ this server, add the file from your Consul server to this server.
-1. Save the file and [reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure).
+1. Save the file, and then [reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure).
### Gitaly TLS support
@@ -1521,11 +1490,10 @@ Name. If you are addressing the Gitaly server by its IP address, you must add it
as a Subject Alternative Name to the certificate.
[gRPC does not support using an IP address as Common Name in a certificate](https://github.com/grpc/grpc/issues/2691).
-NOTE: **Note:**
-It is possible to configure Gitaly servers with both an
-unencrypted listening address `listen_addr` and an encrypted listening
-address `tls_listen_addr` at the same time. This allows you to do a
-gradual transition from unencrypted to encrypted traffic, if necessary.
+It's possible to configure Gitaly servers with both an unencrypted listening
+address (`listen_addr`) and an encrypted listening address (`tls_listen_addr`)
+at the same time. This allows you to do a gradual transition from unencrypted to
+encrypted traffic, if necessary.
To configure Gitaly with TLS:
@@ -1580,10 +1548,10 @@ The following IPs will be used as an example:
To configure the Sidekiq nodes, on each one:
-1. SSH into the Sidekiq server.
-1. [Download/install](https://about.gitlab.com/install/) the Omnibus GitLab package
-you want using steps 1 and 2 from the GitLab downloads page.
-**Do not complete any other steps on the download page.**
+1. SSH in to the Sidekiq server.
+1. [Download and install](https://about.gitlab.com/install/) the Omnibus GitLab
+ package of your choice. Be sure to follow _only_ installation steps 1 and 2
+ on the page.
1. Open `/etc/gitlab/gitlab.rb` with your editor:
```ruby
@@ -1701,15 +1669,14 @@ You can also run [multiple Sidekiq processes](../operations/extra_sidekiq_proces
## Configure GitLab Rails
-NOTE: **Note:**
-In our architectures we run each GitLab Rails node using the Puma webserver
-and have its number of workers set to 90% of available CPUs along with four threads. For
-nodes that are running Rails with other components the worker value should be reduced
-accordingly where we've found 50% achieves a good balance but this is dependent
-on workload.
-
This section describes how to configure the GitLab application (Rails) component.
+In our architecture, we run each GitLab Rails node using the Puma webserver, and
+have its number of workers set to 90% of available CPUs, with four threads. For
+nodes running Rails with other components, the worker value should be reduced
+accordingly. We've determined that a worker value of 50% achieves a good balance,
+but this is dependent on workload.
+
The following IPs will be used as an example:
- `10.6.0.111`: GitLab application 1
@@ -1718,10 +1685,9 @@ The following IPs will be used as an example:
On each node perform the following:
-1. Download/install Omnibus GitLab using **steps 1 and 2** from
- [GitLab downloads](https://about.gitlab.com/install/). Do not complete other
- steps on the download page.
-
+1. [Download and install](https://about.gitlab.com/install/) the Omnibus GitLab
+ package of your choice. Be sure to follow _only_ installation steps 1 and 2
+ on the page.
1. Copy the `/etc/gitlab/gitlab-secrets.json` file from your Consul server, and replace
the file of the same name on this server. If that file is not on this server,
add the file from your Consul server to this server.
@@ -1752,6 +1718,7 @@ On each node perform the following:
roles ['application_role']
gitaly['enable'] = false
nginx['enable'] = true
+ sidekiq['enable'] = false
## PostgreSQL connection details
# Disable PostgreSQL on the application node
@@ -1795,7 +1762,6 @@ On each node perform the following:
# Set the network addresses that the exporters used for monitoring will listen on
node_exporter['listen_address'] = '0.0.0.0:9100'
gitlab_workhorse['prometheus_listen_addr'] = '0.0.0.0:9229'
- sidekiq['listen_address'] = "0.0.0.0"
puma['listen'] = '0.0.0.0'
# Add the monitoring node's IP address to the monitoring whitelist and allow it to
@@ -1836,7 +1802,7 @@ On each node perform the following:
1. Specify the necessary NFS mounts in `/etc/fstab`.
The exact contents of `/etc/fstab` will depend on how you chose
- to configure your NFS server. See the [NFS documentation](../high_availability/nfs.md)
+ to configure your NFS server. See the [NFS documentation](../nfs.md)
for examples and the various options.
1. Create the shared directories. These may be different depending on your NFS
@@ -1877,30 +1843,31 @@ On each node perform the following:
1. Optionally, from the Gitaly servers, confirm that Gitaly can perform callbacks to the internal API:
```shell
- sudo /opt/gitlab/embedded/service/gitlab-shell/bin/check -config /opt/gitlab/embedded/service/gitlab-shell/config.yml
+ sudo /opt/gitlab/embedded/bin/gitaly-hooks check /var/opt/gitlab/gitaly/config.toml
```
-NOTE: **Note:**
-When you specify `https` in the `external_url`, as in the example
-above, GitLab assumes you have SSL certificates in `/etc/gitlab/ssl/`. If
-certificates are not present, NGINX will fail to start. See the
-[NGINX documentation](https://docs.gitlab.com/omnibus/settings/nginx.html#enable-https)
-for more information.
+When you specify `https` in the `external_url`, as in the previous example,
+GitLab expects that the SSL certificates are in `/etc/gitlab/ssl/`. If the
+certificates aren't present, NGINX will fail to start. For more information, see
+the [NGINX documentation](https://docs.gitlab.com/omnibus/settings/nginx.html#enable-https).
### GitLab Rails post-configuration
-Initialize the GitLab database, by running the following in one of the Rails nodes:
+1. Designate one application node for running database migrations during
+ installation and updates. Initialize the GitLab database and ensure all
+ migrations ran:
-```shell
-sudo gitlab-rake gitlab:db:configure
-```
+ ```shell
+ sudo gitlab-rake gitlab:db:configure
+ ```
-NOTE: **Note:**
-If you encounter a `rake aborted!` error stating that PgBouncer is failing to connect to
-PostgreSQL it may be that your PgBouncer node's IP address is missing from
-PostgreSQL's `trust_auth_cidr_addresses` in `gitlab.rb` on your database nodes. See
-[PgBouncer error `ERROR: pgbouncer cannot connect to server`](troubleshooting.md#pgbouncer-error-error-pgbouncer-cannot-connect-to-server)
-in the Troubleshooting section before proceeding.
+ If you encounter a `rake aborted!` error message stating that PgBouncer is
+ failing to connect to PostgreSQL, it may be that your PgBouncer node's IP
+ address is missing from PostgreSQL's `trust_auth_cidr_addresses` in `gitlab.rb`
+ on your database nodes. Before proceeding, see
+ [PgBouncer error `ERROR: pgbouncer cannot connect to server`](troubleshooting.md#pgbouncer-error-error-pgbouncer-cannot-connect-to-server).
+
+1. [Configure fast lookup of authorized SSH keys in the database](../operations/fast_ssh_key_lookup.md).
<div align="right">
<a type="button" class="btn btn-default" href="#setup-components">
@@ -1920,11 +1887,10 @@ The following IP will be used as an example:
To configure the Monitoring node:
-1. SSH into the Monitoring node.
-1. [Download/install](https://about.gitlab.com/install/) the Omnibus GitLab
- package you want using **steps 1 and 2** from the GitLab downloads page.
- Do not complete any other steps on the download page.
-
+1. SSH in to the Monitoring node.
+1. [Download and install](https://about.gitlab.com/install/) the Omnibus GitLab
+ package of your choice. Be sure to follow _only_ installation steps 1 and 2
+ on the page.
1. Copy the `/etc/gitlab/gitlab-secrets.json` file from your Consul server, and replace
the file of the same name on this server. If that file is not on this server,
add the file from your Consul server to this server.
@@ -1988,28 +1954,44 @@ It's recommended over [NFS](#configure-nfs-optional) and in general it's better
in larger setups as object storage is typically much more performant, reliable,
and scalable.
-Object storage options that GitLab has tested, or is aware of customers using include:
+GitLab has been tested on a number of object storage providers:
-- SaaS/Cloud solutions such as [Amazon S3](https://aws.amazon.com/s3/), [Google cloud storage](https://cloud.google.com/storage).
+- [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)
+- [Openstack Swift](https://docs.openstack.org/swift/latest/s3_compat.html)
+- [Azure Blob storage](https://docs.microsoft.com/en-us/azure/storage/blobs/storage-blobs-introduction)
- On-premises hardware and appliances from various storage vendors.
-- MinIO. There is [a guide to deploying this](https://docs.gitlab.com/charts/advanced/external-object-storage/minio.html) within our Helm Chart documentation.
-
-For configuring GitLab to use Object Storage refer to the following guides
-based on what features you intend to use:
-
-1. Configure [object storage for backups](../../raketasks/backup_restore.md#uploading-backups-to-a-remote-cloud-storage).
-1. Configure [object storage for job artifacts](../job_artifacts.md#using-object-storage)
- including [incremental logging](../job_logs.md#new-incremental-logging-architecture).
-1. Configure [object storage for LFS objects](../lfs/index.md#storing-lfs-objects-in-remote-object-storage).
-1. Configure [object storage for uploads](../uploads.md#using-object-storage).
-1. Configure [object storage for merge request diffs](../merge_request_diffs.md#using-object-storage).
-1. Configure [object storage for Container Registry](../packages/container_registry.md#use-object-storage) (optional feature).
-1. Configure [object storage for Mattermost](https://docs.mattermost.com/administration/config-settings.html#file-storage) (optional feature).
-1. Configure [object storage for packages](../packages/index.md#using-object-storage) (optional feature). **(PREMIUM ONLY)**
-1. Configure [object storage for Dependency Proxy](../packages/dependency_proxy.md#using-object-storage) (optional feature). **(PREMIUM ONLY)**
-1. Configure [object storage for Pseudonymizer](../pseudonymizer.md#configuration) (optional feature). **(ULTIMATE ONLY)**
-1. Configure [object storage for autoscale runner caching](https://docs.gitlab.com/runner/configuration/autoscale.html#distributed-runners-caching) (optional - for improved performance).
-1. Configure [object storage for Terraform state files](../terraform_state.md#using-object-storage).
+- MinIO. We have [a guide to deploying this](https://docs.gitlab.com/charts/advanced/external-object-storage/minio.html) within our Helm Chart documentation.
+
+There are two ways of specifying object storage configuration in GitLab:
+
+- [Consolidated form](../object_storage.md#consolidated-object-storage-configuration): A single credential is
+ shared by all supported object types.
+- [Storage-specific form](../object_storage.md#storage-specific-configuration): Every object defines its
+ own object storage [connection and configuration](../object_storage.md#connection-settings).
+
+Starting with GitLab 13.2, consolidated object storage configuration is available. It simplifies your GitLab configuration since the connection details are shared across object types. Refer to [Consolidated object storage configuration](../object_storage.md#consolidated-object-storage-configuration) guide for instructions on how to set it up.
+
+For configuring object storage in GitLab 13.1 and earlier, or for storage types not
+supported by consolidated configuration form, refer to the following guides based
+on what features you intend to use:
+
+|Object storage type|Supported by consolidated configuration?|
+|-------------------|----------------------------------------|
+| [Backups](../../raketasks/backup_restore.md#uploading-backups-to-a-remote-cloud-storage)|No|
+| [Job artifacts](../job_artifacts.md#using-object-storage) including archived job logs | Yes |
+| [LFS objects](../lfs/index.md#storing-lfs-objects-in-remote-object-storage) | Yes |
+| [Uploads](../uploads.md#using-object-storage) | Yes |
+| [Container Registry](../packages/container_registry.md#use-object-storage) (optional feature) | No |
+| [Merge request diffs](../merge_request_diffs.md#using-object-storage) | Yes |
+| [Mattermost](https://docs.mattermost.com/administration/config-settings.html#file-storage)| No |
+| [Packages](../packages/index.md#using-object-storage) (optional feature) | Yes |
+| [Dependency Proxy](../packages/dependency_proxy.md#using-object-storage) (optional feature) **(PREMIUM ONLY)** | Yes |
+| [Pseudonymizer](../pseudonymizer.md#configuration) (optional feature) **(ULTIMATE ONLY)** | No |
+| [Autoscale runner caching](https://docs.gitlab.com/runner/configuration/autoscale.html#distributed-runners-caching) (optional for improved performance) | No |
+| [Terraform state files](../terraform_state.md#using-object-storage) | Yes |
Using separate buckets for each data type is the recommended approach for GitLab.
@@ -2033,13 +2015,29 @@ work.
</a>
</div>
+## Configure Advanced Search **(STARTER ONLY)**
+
+You can leverage Elasticsearch and [enable Advanced Search](../../integration/elasticsearch.md)
+for faster, more advanced code search across your entire GitLab instance.
+
+Elasticsearch cluster design and requirements are dependent on your specific
+data. For recommended best practices about how to set up your Elasticsearch
+cluster alongside your instance, read how to
+[choose the optimal cluster configuration](../../integration/elasticsearch.md#guidance-on-choosing-optimal-cluster-configuration).
+
+<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>
+
## Configure NFS (optional)
[Object storage](#configure-the-object-storage), along with [Gitaly](#configure-gitaly)
are recommended over NFS wherever possible for improved performance. If you intend
to use GitLab Pages, this currently [requires NFS](troubleshooting.md#gitlab-pages-requires-nfs).
-See how to [configure NFS](../high_availability/nfs.md).
+See how to [configure NFS](../nfs.md).
<div align="right">
<a type="button" class="btn btn-default" href="#setup-components">
diff --git a/doc/administration/reference_architectures/5k_users.md b/doc/administration/reference_architectures/5k_users.md
index 6dfa588b092..9f83950a927 100644
--- a/doc/administration/reference_architectures/5k_users.md
+++ b/doc/administration/reference_architectures/5k_users.md
@@ -24,18 +24,18 @@ costly-to-operate environment by using the
| Service | Nodes | Configuration | GCP | AWS | Azure |
|--------------------------------------------|-------------|-------------------------|----------------|-------------|----------|
-| External load balancing node | 1 | 2 vCPU, 1.8GB memory | n1-highcpu-2 | c5.large | F2s v2 |
-| Redis | 3 | 2 vCPU, 7.5GB memory | n1-standard-2 | m5.large | D2s v3 |
-| Consul + Sentinel | 3 | 2 vCPU, 1.8GB memory | n1-highcpu-2 | c5.large | F2s v2 |
-| PostgreSQL | 3 | 2 vCPU, 7.5GB memory | n1-standard-2 | m5.large | D2s v3 |
-| PgBouncer | 3 | 2 vCPU, 1.8GB memory | n1-highcpu-2 | c5.large | F2s v2 |
-| Internal load balancing node | 1 | 2 vCPU, 1.8GB memory | n1-highcpu-2 | c5.large | F2s v2 |
-| Gitaly | 2 (minimum) | 8 vCPU, 30GB memory | n1-standard-8 | m5.2xlarge | D8s v3 |
-| Sidekiq | 4 | 2 vCPU, 7.5GB memory | n1-standard-2 | m5.large | D2s v3 |
-| GitLab Rails | 3 | 16 vCPU, 14.4GB memory | n1-highcpu-16 | c5.4xlarge | F16s v2 |
-| Monitoring node | 1 | 2 vCPU, 1.8GB memory | n1-highcpu-2 | c5.large | F2s v2 |
-| Object Storage | n/a | n/a | n/a | n/a | n/a |
-| NFS Server (optional, not recommended) | 1 | 4 vCPU, 3.6GB memory | n1-highcpu-4 | c5.xlarge | F4s v2 |
+| External load balancing node | 1 | 2 vCPU, 1.8 GB memory | n1-highcpu-2 | c5.large | F2s v2 |
+| Redis | 3 | 2 vCPU, 7.5 GB memory | n1-standard-2 | m5.large | D2s v3 |
+| Consul + Sentinel | 3 | 2 vCPU, 1.8 GB memory | n1-highcpu-2 | c5.large | F2s v2 |
+| PostgreSQL | 3 | 2 vCPU, 7.5 GB memory | n1-standard-2 | m5.large | D2s v3 |
+| PgBouncer | 3 | 2 vCPU, 1.8 GB memory | n1-highcpu-2 | c5.large | F2s v2 |
+| Internal load balancing node | 1 | 2 vCPU, 1.8 GB memory | n1-highcpu-2 | c5.large | F2s v2 |
+| Gitaly | 2 (minimum) | 8 vCPU, 30 GB memory | n1-standard-8 | m5.2xlarge | D8s v3 |
+| Sidekiq | 4 | 2 vCPU, 7.5 GB memory | n1-standard-2 | m5.large | D2s v3 |
+| GitLab Rails | 3 | 16 vCPU, 14.4 GB memory | n1-highcpu-16 | c5.4xlarge | F16s v2 |
+| Monitoring node | 1 | 2 vCPU, 1.8 GB memory | n1-highcpu-2 | c5.large | F2s v2 |
+| Object storage | n/a | n/a | n/a | n/a | n/a |
+| NFS server (optional, not recommended) | 1 | 4 vCPU, 3.6 GB memory | n1-highcpu-4 | c5.xlarge | F4s v2 |
The Google Cloud Platform (GCP) architectures were built and tested using the
[Intel Xeon E5 v3 (Haswell)](https://cloud.google.com/compute/docs/cpu-platforms)
@@ -44,41 +44,43 @@ or higher, are required for your CPU or node counts. For more information, see
our [Sysbench](https://github.com/akopytov/sysbench)-based
[CPU benchmark](https://gitlab.com/gitlab-org/quality/performance/-/wikis/Reference-Architectures/GCP-CPU-Benchmarks).
-For data objects (such as LFS, Uploads, or Artifacts), an
-[object storage service](#configure-the-object-storage) is recommended instead
-of NFS where possible, due to better performance and availability. Since this
-doesn't require a node to be set up, *Object Storage* is noted as not
-applicable (n/a) in the previous table.
+Due to better performance and availability, for data objects (such as LFS,
+uploads, or artifacts), using an [object storage service](#configure-the-object-storage)
+is recommended instead of using NFS. Using an object storage service also
+doesn't require you to provision and maintain a node.
## Setup components
To set up GitLab and its components to accommodate up to 5,000 users:
1. [Configure the external load balancing node](#configure-the-external-load-balancer)
- that will handle the load balancing of the two GitLab application services nodes.
+ to handle the load balancing of the GitLab application services nodes.
1. [Configure Redis](#configure-redis).
1. [Configure Consul and Sentinel](#configure-consul-and-sentinel).
1. [Configure PostgreSQL](#configure-postgresql), the database for GitLab.
1. [Configure PgBouncer](#configure-pgbouncer).
-1. [Configure the internal load balancing node](#configure-the-internal-load-balancer)
+1. [Configure the internal load balancing node](#configure-the-internal-load-balancer).
1. [Configure Gitaly](#configure-gitaly),
which provides access to the Git repositories.
1. [Configure Sidekiq](#configure-sidekiq).
1. [Configure the main GitLab Rails application](#configure-gitlab-rails)
- to run Puma/Unicorn, Workhorse, GitLab Shell, and to serve all frontend requests (UI, API, Git
- over HTTP/SSH).
-1. [Configure Prometheus](#configure-prometheus) to monitor your GitLab environment.
-1. [Configure the Object Storage](#configure-the-object-storage)
+ to run Puma/Unicorn, Workhorse, GitLab Shell, and to serve all frontend
+ requests (which include UI, API, and Git over HTTP/SSH).
+1. [Configure Prometheus](#configure-prometheus) to monitor your GitLab
+ environment.
+1. [Configure the object storage](#configure-the-object-storage)
used for shared data objects.
-1. [Configure NFS (Optional)](#configure-nfs-optional)
- to have shared disk storage service as an alternative to Gitaly and/or Object Storage (although
- not recommended). NFS is required for GitLab Pages, you can skip this step if you're not using
- that feature.
+1. [Configure Advanced Search](#configure-advanced-search) (optional) for faster,
+ more advanced code search across your entire GitLab instance.
+1. [Configure NFS](#configure-nfs-optional) (optional, and not recommended)
+ to have shared disk storage service as an alternative to Gitaly or object
+ storage. You can skip this step if you're not using GitLab Pages (which
+ requires NFS).
-We start with all servers on the same 10.6.0.0/16 private network range, they
-can connect to each other freely on those addresses.
+The servers start on the same 10.6.0.0/24 private network range, and can
+connect to each other freely on these addresses.
-Here is a list and description of each machine and the assigned IP:
+The following list includes descriptions of each server and its assigned IP:
- `10.6.0.10`: External Load Balancer
- `10.6.0.61`: Redis Primary
@@ -107,19 +109,18 @@ Here is a list and description of each machine and the assigned IP:
## Configure the external load balancer
-NOTE: **Note:**
+In an active/active 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 hope
+that if you're managing multi-node systems like GitLab, you already have a load
+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.
+
This architecture has been tested and validated with [HAProxy](https://www.haproxy.org/)
as the load balancer. Although other load balancers with similar feature sets
could also be used, those load balancers have not been validated.
-In an active/active GitLab configuration, you will need a load balancer to route
-traffic to the application servers. The specifics on which load balancer to use
-or the exact configuration is beyond the scope of GitLab documentation. We hope
-that if you're managing multi-node systems like GitLab you have a load balancer of
-choice already. Some examples including HAProxy (open-source), F5 Big-IP LTM,
-and Citrix Net Scaler. This documentation will outline what ports and protocols
-you need to use with GitLab.
-
The next question is how you will handle SSL in your environment.
There are several different options:
@@ -277,20 +278,17 @@ The requirements for a Redis setup are the following:
([Internet](https://gitlab.com/gitlab-org/gitlab-foss/uploads/c4cc8cd353604bd80315f9384035ff9e/The_Internet_IT_Crowd.png)),
using a firewall.
-NOTE: **Note:**
-Redis nodes (both primary and replica) will need the same password defined in
-`redis['password']`. At any time during a failover the Sentinels can
-reconfigure a node and change its status from primary to replica and vice versa.
+Both the primary and replica Redis nodes need the same password defined in
+`redis['password']`. At any time during a failover, the Sentinels can reconfigure
+a node and change its status from primary to replica (and vice versa).
#### Configuring the primary Redis instance
-1. SSH into the **Primary** Redis server.
-1. [Download/install](https://about.gitlab.com/install/) the Omnibus GitLab
- package you want using **steps 1 and 2** from the GitLab downloads page.
- - Make sure you select the correct Omnibus package, with the same version
- and type (Community, Enterprise editions) of your current install.
- - Do not complete any other steps on the download page.
-
+1. SSH in to the **Primary** Redis server.
+1. [Download and install](https://about.gitlab.com/install/) the Omnibus GitLab
+ package of your choice. Be sure to both follow _only_ installation steps 1 and 2
+ on the page, and to select the correct Omnibus GitLab package, with the same version
+ and type (Community or Enterprise editions) as your current install.
1. Edit `/etc/gitlab/gitlab.rb` and add the contents:
```ruby
@@ -334,10 +332,9 @@ reconfigure a node and change its status from primary to replica and vice versa.
1. [Reconfigure Omnibus GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure) for the changes to take effect.
-NOTE: **Note:**
-You can specify multiple roles like sentinel and Redis as:
-`roles ['redis_sentinel_role', 'redis_master_role']`.
-Read more about [roles](https://docs.gitlab.com/omnibus/roles/).
+You can specify multiple roles, like sentinel and Redis, as:
+`roles ['redis_sentinel_role', 'redis_master_role']`. Read more about
+[roles](https://docs.gitlab.com/omnibus/roles/).
You can list the current Redis Primary, Replica status via:
@@ -363,13 +360,11 @@ run: redis-exporter: (pid 30075) 76861s; run: log: (pid 29674) 76896s
#### Configuring the replica Redis instances
-1. SSH into the **replica** Redis server.
-1. [Download/install](https://about.gitlab.com/install/) the Omnibus GitLab
- package you want using **steps 1 and 2** from the GitLab downloads page.
- - Make sure you select the correct Omnibus package, with the same version
- and type (Community, Enterprise editions) of your current install.
- - Do not complete any other steps on the download page.
-
+1. SSH in to the **replica** Redis server.
+1. [Download and install](https://about.gitlab.com/install/) the Omnibus GitLab
+ package of your choice. Be sure to both follow _only_ installation steps 1 and 2
+ on the page, and to select the correct Omnibus GitLab package, with the same version
+ and type (Community or Enterprise editions) as your current install.
1. Edit `/etc/gitlab/gitlab.rb` and add the contents:
```ruby
@@ -422,10 +417,9 @@ run: redis-exporter: (pid 30075) 76861s; run: log: (pid 29674) 76896s
1. Go through the steps again for all the other replica nodes, and
make sure to set up the IPs correctly.
-NOTE: **Note:**
-You can specify multiple roles like sentinel and Redis as:
-`roles ['redis_sentinel_role', 'redis_master_role']`.
-Read more about [roles](https://docs.gitlab.com/omnibus/roles/).
+You can specify multiple roles, like sentinel and Redis, as:
+`roles ['redis_sentinel_role', 'redis_master_role']`. Read more about
+[roles](https://docs.gitlab.com/omnibus/roles/).
These values don't have to be changed again in `/etc/gitlab/gitlab.rb` after
a failover, as the nodes will be managed by the [Sentinels](#configure-consul-and-sentinel), and even after a
@@ -443,13 +437,6 @@ are supported and can be added if needed.
## Configure Consul and Sentinel
-NOTE: **Note:**
-If you are using an external Redis Sentinel instance, be sure
-to exclude the `requirepass` parameter from the Sentinel
-configuration. This parameter will cause clients to report `NOAUTH
-Authentication required.`. [Redis Sentinel 3.2.x does not support
-password authentication](https://github.com/antirez/redis/issues/3279).
-
Now that the Redis servers are all set up, let's configure the Sentinel
servers. The following IPs will be used as an example:
@@ -457,16 +444,19 @@ servers. The following IPs will be used as an example:
- `10.6.0.12`: Consul/Sentinel 2
- `10.6.0.13`: Consul/Sentinel 3
-To configure the Sentinel:
+NOTE: **Note:**
+If you're using an external Redis Sentinel instance, be sure to exclude the
+`requirepass` parameter from the Sentinel configuration. This parameter causes
+clients to report `NOAUTH Authentication required.`.
+[Redis Sentinel 3.2.x doesn't support password authentication](https://github.com/antirez/redis/issues/3279).
-1. SSH into the server that will host Consul/Sentinel.
-1. [Download/install](https://about.gitlab.com/install/) the
- Omnibus GitLab Enterprise Edition package using **steps 1 and 2** from the
- GitLab downloads page.
- - Make sure you select the correct Omnibus package, with the same version
- the GitLab application is running.
- - Do not complete any other steps on the download page.
+To configure the Sentinel:
+1. SSH in to the server that will host Consul/Sentinel.
+1. [Download and install](https://about.gitlab.com/install/) the Omnibus GitLab
+ package of your choice. Be sure to both follow _only_ installation steps 1 and 2
+ on the page, and to select the correct Omnibus GitLab package, with the same version
+ and type (Community or Enterprise editions) as your current install.
1. Edit `/etc/gitlab/gitlab.rb` and add the contents:
```ruby
@@ -556,10 +546,9 @@ To configure the Sentinel:
1. Go through the steps again for all the other Consul/Sentinel nodes, and
make sure you set up the correct IPs.
-NOTE: **Note:**
-A Consul leader will be elected when the provisioning of the third Consul server is completed.
-Viewing the Consul logs `sudo gitlab-ctl tail consul` will display
-`...[INFO] consul: New leader elected: ...`
+A Consul leader is _elected_ when the provisioning of the third Consul server is
+complete. Viewing the Consul logs `sudo gitlab-ctl tail consul` displays
+`...[INFO] consul: New leader elected: ...`.
You can list the current Consul members (server, client):
@@ -627,7 +616,7 @@ in the second step, do not supply the `EXTERNAL_URL` value.
#### PostgreSQL primary node
-1. SSH into the PostgreSQL primary node.
+1. SSH in to the PostgreSQL primary node.
1. Generate a password hash for the PostgreSQL username/password pair. This assumes you will use the default
username of `gitlab` (recommended). The command will request a password
and confirmation. Use the value that is output by this command in the next
@@ -812,7 +801,7 @@ are supported and can be added if needed.
#### PostgreSQL post-configuration
-SSH into the **primary node**:
+SSH in to the **primary node**:
1. Open a database prompt:
@@ -847,7 +836,7 @@ SSH into the **primary node**:
is not an IP address, it will need to be a resolvable name (via DNS or
`/etc/hosts`)
-SSH into the **secondary node**:
+SSH in to the **secondary node**:
1. Set up the repmgr standby:
@@ -1068,51 +1057,48 @@ Refer to your preferred Load Balancer's documentation for further guidance.
## Configure Gitaly
-Deploying Gitaly in its own server can benefit GitLab installations that are
-larger than a single machine.
-
-The Gitaly node requirements are dependent on customer data, specifically the number of
-projects and their repository sizes. Two nodes are recommended as an absolute minimum.
-Each Gitaly node should store no more than 5TB of data and have the number of
-[`gitaly-ruby` workers](../gitaly/index.md#gitaly-ruby) set to 20% of available CPUs.
-Additional nodes should be considered in conjunction with a review of expected
-data size and spread based on the recommendations above.
-
-It is also strongly recommended that all Gitaly nodes be set up with SSD disks with
-a throughput of at least 8,000 IOPS for read operations and 2,000 IOPS for write,
-as Gitaly has heavy I/O. These IOPS values are recommended only as a starter as with
-time they may be adjusted higher or lower depending on the scale of your environment's workload.
-If you're running the environment on a Cloud provider, you may need to refer to
-their documentation on how to configure IOPS correctly.
-
-Some things to note:
-
-- The GitLab Rails application shards repositories into [repository storages](../repository_storage_paths.md).
-- A Gitaly server can host one or more storages.
-- A GitLab server can use one or more Gitaly servers.
-- Gitaly addresses must be specified in such a way that they resolve
- correctly for ALL Gitaly clients.
+[Gitaly](../gitaly/index.md) server node requirements are dependent on data,
+specifically the number of projects and those projects' sizes. It's recommended
+that a Gitaly server node stores no more than 5 TB of data. Although this
+reference architecture includes a recommendation for the number of Gitaly server
+nodes to use, depending on your storage requirements, you may require additional
+Gitaly server nodes.
+
+Due to Gitaly having notable input and output requirements, we strongly
+recommend that all Gitaly nodes use solid-state drives (SSDs). These SSDs should
+have a throughput of at least 8,000 input/output operations per second (IOPS)
+for read operations and 2,000 IOPS for write operations. These IOPS values are
+initial recommendations, and may be adjusted to greater or lesser values
+depending on the scale of your environment's workload. If you're running the
+environment on a Cloud provider, refer to their documentation about how to
+configure IOPS correctly.
+
+Be sure to note the following items:
+
+- The GitLab Rails application shards repositories into
+ [repository storage paths](../repository_storage_paths.md).
+- A Gitaly server can host one or more storage paths.
+- A GitLab server can use one or more Gitaly server nodes.
+- Gitaly addresses must be specified to be correctly resolvable for _all_
+ Gitaly clients.
- Gitaly servers must not be exposed to the public internet, as Gitaly's network
traffic is unencrypted by default. The use of a firewall is highly recommended
to restrict access to the Gitaly server. Another option is to
[use TLS](#gitaly-tls-support).
-TIP: **Tip:**
-For more information about Gitaly's history and network architecture see the
-[standalone Gitaly documentation](../gitaly/index.md).
-
-Note: **Note:** The token referred to throughout the Gitaly documentation is
-just an arbitrary password selected by the administrator. It is unrelated to
-tokens created for the GitLab API or other similar web API tokens.
+NOTE: **Note:**
+The token referred to throughout the Gitaly documentation is an arbitrary
+password selected by the administrator. This token is unrelated to tokens
+created for the GitLab API or other similar web API tokens.
-Below we describe how to configure two Gitaly servers, with IPs and
-domain names:
+This section describes how to configure two Gitaly servers, with the following
+IPs and domain names:
- `10.6.0.51`: Gitaly 1 (`gitaly1.internal`)
- `10.6.0.52`: Gitaly 2 (`gitaly2.internal`)
-The secret token is assumed to be `gitalysecret` and that
-your GitLab installation has three repository storages:
+Assumptions about your servers include having the secret token be `gitalysecret`,
+and that your GitLab installation has three repository storages:
- `default` on Gitaly 1
- `storage1` on Gitaly 1
@@ -1120,11 +1106,11 @@ your GitLab installation has three repository storages:
On each node:
-1. [Download/Install](https://about.gitlab.com/install/) the Omnibus GitLab
- package you want using **steps 1 and 2** from the GitLab downloads page but
- **without** providing the `EXTERNAL_URL` value.
-1. Edit `/etc/gitlab/gitlab.rb` to configure storage paths, enable
- the network listener and configure the token:
+1. [Download and install](https://about.gitlab.com/install/) the Omnibus GitLab
+ package of your choice. Be sure to follow _only_ installation steps 1 and 2
+ on the page, and _do not_ provide the `EXTERNAL_URL` value.
+1. Edit `/etc/gitlab/gitlab.rb` to configure the storage paths, enable
+ the network listener, and configure the token:
<!--
updates to following example must also be made at
@@ -1188,39 +1174,39 @@ On each node:
```
1. Append the following to `/etc/gitlab/gitlab.rb` for each respective server:
- 1. On `gitaly1.internal`:
-
- ```ruby
- git_data_dirs({
- 'default' => {
- 'path' => '/var/opt/gitlab/git-data'
- },
- 'storage1' => {
- 'path' => '/mnt/gitlab/git-data'
- },
- })
- ```
-
- 1. On `gitaly2.internal`:
-
- ```ruby
- git_data_dirs({
- 'storage2' => {
- 'path' => '/mnt/gitlab/git-data'
- },
- })
- ```
+ - On `gitaly1.internal`:
+
+ ```ruby
+ git_data_dirs({
+ 'default' => {
+ 'path' => '/var/opt/gitlab/git-data'
+ },
+ 'storage1' => {
+ 'path' => '/mnt/gitlab/git-data'
+ },
+ })
+ ```
+
+ - On `gitaly2.internal`:
+
+ ```ruby
+ git_data_dirs({
+ 'storage2' => {
+ 'path' => '/mnt/gitlab/git-data'
+ },
+ })
+ ```
<!--
updates to following example must also be made at
https://gitlab.com/gitlab-org/charts/gitlab/blob/master/doc/advanced/external-gitaly/external-omnibus-gitaly.md#configure-omnibus-gitlab
-->
-1. Save the file and [reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure).
+1. Save the file, and then [reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure).
1. Confirm that Gitaly can perform callbacks to the internal API:
```shell
- sudo /opt/gitlab/embedded/service/gitlab-shell/bin/check -config /opt/gitlab/embedded/service/gitlab-shell/config.yml
+ sudo /opt/gitlab/embedded/bin/gitaly-hooks check /var/opt/gitlab/gitaly/config.toml
```
1. Verify the GitLab services are running:
@@ -1258,11 +1244,10 @@ Name. If you are addressing the Gitaly server by its IP address, you must add it
as a Subject Alternative Name to the certificate.
[gRPC does not support using an IP address as Common Name in a certificate](https://github.com/grpc/grpc/issues/2691).
-NOTE: **Note:**
-It is possible to configure Gitaly servers with both an
-unencrypted listening address `listen_addr` and an encrypted listening
-address `tls_listen_addr` at the same time. This allows you to do a
-gradual transition from unencrypted to encrypted traffic, if necessary.
+It's possible to configure Gitaly servers with both an unencrypted listening
+address (`listen_addr`) and an encrypted listening address (`tls_listen_addr`)
+at the same time. This allows you to do a gradual transition from unencrypted to
+encrypted traffic, if necessary.
To configure Gitaly with TLS:
@@ -1316,10 +1301,10 @@ The following IPs will be used as an example:
To configure the Sidekiq nodes, one each one:
-1. SSH into the Sidekiq server.
-1. [Download/install](https://about.gitlab.com/install/) the Omnibus GitLab package
-you want using steps 1 and 2 from the GitLab downloads page.
-**Do not complete any other steps on the download page.**
+1. SSH in to the Sidekiq server.
+1. [Download and install](https://about.gitlab.com/install/) the Omnibus GitLab
+ package of your choice. Be sure to follow _only_ installation steps 1 and 2
+ on the page.
1. Open `/etc/gitlab/gitlab.rb` with your editor:
```ruby
@@ -1430,14 +1415,14 @@ You can also run [multiple Sidekiq processes](../operations/extra_sidekiq_proces
## Configure GitLab Rails
-NOTE: **Note:**
-In our architectures we run each GitLab Rails node using the Puma webserver
-and have its number of workers set to 90% of available CPUs along with four threads. For
-nodes that are running Rails with other components the worker value should be reduced
-accordingly where we've found 50% achieves a good balance but this is dependent
-on workload.
-
This section describes how to configure the GitLab application (Rails) component.
+
+In our architecture, we run each GitLab Rails node using the Puma webserver, and
+have its number of workers set to 90% of available CPUs, with four threads. For
+nodes running Rails with other components, the worker value should be reduced
+accordingly. We've determined that a worker value of 50% achieves a good balance,
+but this is dependent on workload.
+
On each node perform the following:
1. If you're [using NFS](#configure-nfs-optional):
@@ -1465,10 +1450,10 @@ On each node perform the following:
mkdir -p /var/opt/gitlab/.ssh /var/opt/gitlab/gitlab-rails/uploads /var/opt/gitlab/gitlab-rails/shared /var/opt/gitlab/gitlab-ci/builds /var/opt/gitlab/git-data
```
-1. Download/install Omnibus GitLab using **steps 1 and 2** from
- [GitLab downloads](https://about.gitlab.com/install/). Do not complete other
- steps on the download page.
-1. Create/edit `/etc/gitlab/gitlab.rb` and use the following configuration.
+1. [Download and install](https://about.gitlab.com/install/) the Omnibus GitLab
+ package of your choice. Be sure to follow _only_ installation steps 1 and 2
+ on the page.
+1. Create or edit `/etc/gitlab/gitlab.rb` and use the following configuration.
To maintain uniformity of links across nodes, the `external_url`
on the application server should point to the external URL that users will use
to access GitLab. This would be the URL of the [external load balancer](#configure-the-external-load-balancer)
@@ -1581,6 +1566,11 @@ On each node perform the following:
sudo gitlab-ctl tail gitaly
```
+1. Save the `/etc/gitlab/gitlab-secrets.json` file from one of the two
+ application nodes and install it on the other application node, the
+ [Gitaly node](#configure-gitaly) and the [Sidekiq node](#configure-sidekiq) and
+ [reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure).
+
1. Verify the GitLab services are running:
```shell
@@ -1599,12 +1589,10 @@ On each node perform the following:
run: puma: (pid 4936) 8645s; run: log: (pid 29656) 79161s
```
-NOTE: **Note:**
-When you specify `https` in the `external_url`, as in the example
-above, GitLab assumes you have SSL certificates in `/etc/gitlab/ssl/`. If
-certificates are not present, NGINX will fail to start. See the
-[NGINX documentation](https://docs.gitlab.com/omnibus/settings/nginx.html#enable-https)
-for more information.
+When you specify `https` in the `external_url`, as in the previous example,
+GitLab expects that the SSL certificates are in `/etc/gitlab/ssl/`. If the
+certificates aren't present, NGINX will fail to start. For more information, see
+the [NGINX documentation](https://docs.gitlab.com/omnibus/settings/nginx.html#enable-https).
### GitLab Rails post-configuration
@@ -1614,12 +1602,11 @@ for more information.
gitlab-rake gitlab:db:configure
```
- NOTE: **Note:**
- If you encounter a `rake aborted!` error stating that PgBouncer is failing to connect to
- PostgreSQL it may be that your PgBouncer node's IP address is missing from
- PostgreSQL's `trust_auth_cidr_addresses` in `gitlab.rb` on your database nodes. See
- [PgBouncer error `ERROR: pgbouncer cannot connect to server`](troubleshooting.md#pgbouncer-error-error-pgbouncer-cannot-connect-to-server)
- in the Troubleshooting section before proceeding.
+ If you encounter a `rake aborted!` error message stating that PgBouncer is
+ failing to connect to PostgreSQL, it may be that your PgBouncer node's IP
+ address is missing from PostgreSQL's `trust_auth_cidr_addresses` in `gitlab.rb`
+ on your database nodes. Before proceeding, see
+ [PgBouncer error `ERROR: pgbouncer cannot connect to server`](troubleshooting.md#pgbouncer-error-error-pgbouncer-cannot-connect-to-server).
1. [Configure fast lookup of authorized SSH keys in the database](../operations/fast_ssh_key_lookup.md).
@@ -1635,10 +1622,10 @@ The Omnibus GitLab package can be used to configure a standalone Monitoring node
running [Prometheus](../monitoring/prometheus/index.md) and
[Grafana](../monitoring/performance/grafana_configuration.md):
-1. SSH into the Monitoring node.
-1. [Download/install](https://about.gitlab.com/install/) the Omnibus GitLab
- package you want using **steps 1 and 2** from the GitLab downloads page.
- Do not complete any other steps on the download page.
+1. SSH in to the Monitoring node.
+1. [Download and install](https://about.gitlab.com/install/) the Omnibus GitLab
+ package of your choice. Be sure to follow _only_ installation steps 1 and 2
+ on the page.
1. Edit `/etc/gitlab/gitlab.rb` and add the contents:
```ruby
@@ -1713,28 +1700,44 @@ It's recommended over [NFS](#configure-nfs-optional) and in general it's better
in larger setups as object storage is typically much more performant, reliable,
and scalable.
-Object storage options that GitLab has tested, or is aware of customers using include:
+GitLab has been tested on a number of object storage providers:
-- SaaS/Cloud solutions such as [Amazon S3](https://aws.amazon.com/s3/), [Google cloud storage](https://cloud.google.com/storage).
+- [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)
+- [Openstack Swift](https://docs.openstack.org/swift/latest/s3_compat.html)
+- [Azure Blob storage](https://docs.microsoft.com/en-us/azure/storage/blobs/storage-blobs-introduction)
- On-premises hardware and appliances from various storage vendors.
-- MinIO. There is [a guide to deploying this](https://docs.gitlab.com/charts/advanced/external-object-storage/minio.html) within our Helm Chart documentation.
-
-For configuring GitLab to use Object Storage refer to the following guides
-based on what features you intend to use:
-
-1. Configure [object storage for backups](../../raketasks/backup_restore.md#uploading-backups-to-a-remote-cloud-storage).
-1. Configure [object storage for job artifacts](../job_artifacts.md#using-object-storage)
- including [incremental logging](../job_logs.md#new-incremental-logging-architecture).
-1. Configure [object storage for LFS objects](../lfs/index.md#storing-lfs-objects-in-remote-object-storage).
-1. Configure [object storage for uploads](../uploads.md#using-object-storage).
-1. Configure [object storage for merge request diffs](../merge_request_diffs.md#using-object-storage).
-1. Configure [object storage for Container Registry](../packages/container_registry.md#use-object-storage) (optional feature).
-1. Configure [object storage for Mattermost](https://docs.mattermost.com/administration/config-settings.html#file-storage) (optional feature).
-1. Configure [object storage for packages](../packages/index.md#using-object-storage) (optional feature). **(PREMIUM ONLY)**
-1. Configure [object storage for Dependency Proxy](../packages/dependency_proxy.md#using-object-storage) (optional feature). **(PREMIUM ONLY)**
-1. Configure [object storage for Pseudonymizer](../pseudonymizer.md#configuration) (optional feature). **(ULTIMATE ONLY)**
-1. Configure [object storage for autoscale runner caching](https://docs.gitlab.com/runner/configuration/autoscale.html#distributed-runners-caching) (optional - for improved performance).
-1. Configure [object storage for Terraform state files](../terraform_state.md#using-object-storage).
+- MinIO. We have [a guide to deploying this](https://docs.gitlab.com/charts/advanced/external-object-storage/minio.html) within our Helm Chart documentation.
+
+There are two ways of specifying object storage configuration in GitLab:
+
+- [Consolidated form](../object_storage.md#consolidated-object-storage-configuration): A single credential is
+ shared by all supported object types.
+- [Storage-specific form](../object_storage.md#storage-specific-configuration): Every object defines its
+ own object storage [connection and configuration](../object_storage.md#connection-settings).
+
+Starting with GitLab 13.2, consolidated object storage configuration is available. It simplifies your GitLab configuration since the connection details are shared across object types. Refer to [Consolidated object storage configuration](../object_storage.md#consolidated-object-storage-configuration) guide for instructions on how to set it up.
+
+For configuring object storage in GitLab 13.1 and earlier, or for storage types not
+supported by consolidated configuration form, refer to the following guides based
+on what features you intend to use:
+
+|Object storage type|Supported by consolidated configuration?|
+|-------------------|----------------------------------------|
+| [Backups](../../raketasks/backup_restore.md#uploading-backups-to-a-remote-cloud-storage)|No|
+| [Job artifacts](../job_artifacts.md#using-object-storage) including archived job logs | Yes |
+| [LFS objects](../lfs/index.md#storing-lfs-objects-in-remote-object-storage) | Yes |
+| [Uploads](../uploads.md#using-object-storage) | Yes |
+| [Container Registry](../packages/container_registry.md#use-object-storage) (optional feature) | No |
+| [Merge request diffs](../merge_request_diffs.md#using-object-storage) | Yes |
+| [Mattermost](https://docs.mattermost.com/administration/config-settings.html#file-storage)| No |
+| [Packages](../packages/index.md#using-object-storage) (optional feature) | Yes |
+| [Dependency Proxy](../packages/dependency_proxy.md#using-object-storage) (optional feature) **(PREMIUM ONLY)** | Yes |
+| [Pseudonymizer](../pseudonymizer.md#configuration) (optional feature) **(ULTIMATE ONLY)** | No |
+| [Autoscale runner caching](https://docs.gitlab.com/runner/configuration/autoscale.html#distributed-runners-caching) (optional for improved performance) | No |
+| [Terraform state files](../terraform_state.md#using-object-storage) | Yes |
Using separate buckets for each data type is the recommended approach for GitLab.
@@ -1758,6 +1761,22 @@ work.
</a>
</div>
+## Configure Advanced Search **(STARTER ONLY)**
+
+You can leverage Elasticsearch and [enable Advanced Search](../../integration/elasticsearch.md)
+for faster, more advanced code search across your entire GitLab instance.
+
+Elasticsearch cluster design and requirements are dependent on your specific
+data. For recommended best practices about how to set up your Elasticsearch
+cluster alongside your instance, read how to
+[choose the optimal cluster configuration](../../integration/elasticsearch.md#guidance-on-choosing-optimal-cluster-configuration).
+
+<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>
+
## Configure NFS (optional)
[Object storage](#configure-the-object-storage), along with [Gitaly](#configure-gitaly)
diff --git a/doc/administration/reference_architectures/index.md b/doc/administration/reference_architectures/index.md
index 3964b8daeb7..8816d0eecf4 100644
--- a/doc/administration/reference_architectures/index.md
+++ b/doc/administration/reference_architectures/index.md
@@ -105,7 +105,7 @@ is the least complex to setup. This provides a point-in-time recovery of a prede
> - Supported tiers: [GitLab Starter, Premium, and Ultimate](https://about.gitlab.com/pricing/)
This requires separating out GitLab into multiple application nodes with an added
-[load balancer](../high_availability/load_balancer.md). The load balancer will distribute traffic
+[load balancer](../load_balancer.md). The load balancer will distribute traffic
across GitLab application nodes. Meanwhile, each application node connects to a
shared file server and database systems on the back end. This way, if one of the
application servers fails, the workflow is not interrupted.
diff --git a/doc/administration/reply_by_email_postfix_setup.md b/doc/administration/reply_by_email_postfix_setup.md
index f950134889d..f4fcbefa403 100644
--- a/doc/administration/reply_by_email_postfix_setup.md
+++ b/doc/administration/reply_by_email_postfix_setup.md
@@ -71,7 +71,7 @@ The instructions make the assumption that you will be using the email address `i
sudo postfix start
```
-1. Send the new `incoming` user a dummy email to test SMTP, by entering the following into the SMTP prompt:
+1. Send the new `incoming` user an email to test SMTP, by entering the following into the SMTP prompt:
```plaintext
ehlo localhost
@@ -112,7 +112,7 @@ The instructions make the assumption that you will be using the email address `i
q
```
-1. Log out of the `incoming` account and go back to being `root`:
+1. Sign out of the `incoming` account, and go back to being `root`:
```shell
logout
@@ -164,7 +164,7 @@ Courier, which we will install later to add IMAP authentication, requires mailbo
try the above steps again, substituting `heirloom-mailx` for the `mail`
command._
-1. Log out of the `incoming` account and go back to being `root`:
+1. Sign out of the `incoming` account, and go back to being `root`:
```shell
logout
@@ -251,7 +251,7 @@ Courier, which we will install later to add IMAP authentication, requires mailbo
If you get a `Connection refused` error instead, make sure your firewall is set up to allow inbound traffic on port 25.
- 1. Send the `incoming` user a dummy email to test SMTP, by entering the following into the SMTP prompt:
+ 1. Send the `incoming` user an email to test SMTP, by entering the following into the SMTP prompt:
```plaintext
ehlo gitlab.example.com
@@ -288,7 +288,7 @@ Courier, which we will install later to add IMAP authentication, requires mailbo
q
```
- 1. Log out of the `incoming` account and go back to being `root`:
+ 1. Sign out of the `incoming` account, and go back to being `root`:
```shell
logout
diff --git a/doc/administration/repository_storage_types.md b/doc/administration/repository_storage_types.md
index 1c036cfe2ac..b272c4b463e 100644
--- a/doc/administration/repository_storage_types.md
+++ b/doc/administration/repository_storage_types.md
@@ -83,7 +83,7 @@ The "Gitaly relative path" is shown there, for example:
This is the path under `/var/opt/gitlab/git-data/repositories/` on a
default Omnibus installation.
-In a [Rails console](troubleshooting/debug.md#starting-a-rails-console-session),
+In a [Rails console](operations/rails_console.md#starting-a-rails-console-session),
get this information using either the numeric project ID or the full path:
```ruby
@@ -95,7 +95,7 @@ Project.find_by_full_path('group/project').disk_path
To translate from a hashed storage path to a project name:
-1. Start a [Rails console](troubleshooting/debug.md#starting-a-rails-console-session).
+1. Start a [Rails console](operations/rails_console.md#starting-a-rails-console-session).
1. Run the following:
```ruby
diff --git a/doc/administration/server_hooks.md b/doc/administration/server_hooks.md
index 54b2cd43265..b5e975d397f 100644
--- a/doc/administration/server_hooks.md
+++ b/doc/administration/server_hooks.md
@@ -156,22 +156,6 @@ NOTE: **Note:**
While other environment variables can be passed to server hooks, your application should not rely on
them as they can change.
-## Transition to Go
-
-> - Introduced in GitLab 13.2 using feature flags.
-> - In GitLab 13.4, `update` Ruby [implementation removed](https://gitlab.com/gitlab-org/gitaly/-/merge_requests/2501).
-> - In GitLab 13.4, `post-receive` Go implementation [made default](https://gitlab.com/gitlab-org/gitaly/-/merge_requests/2502).
-
-The following server hooks have been re-implemented in Go:
-
-- `pre-receive`, with the Go implementation used by default. To use the Ruby implementation instead,
- [disable](feature_flags.md#enable-or-disable-the-feature) the `:gitaly_go_preceive_hook` feature
- flag.
-- `update`, with Go implementation always used. No Ruby implementation is available.
-- `post-receive`, with the Go implementation used by default. To use the Ruby implementation
- instead, [disable](feature_flags.md#enable-or-disable-the-feature) the
- `:gitaly_go_postreceive_hook` feature flag.
-
## Custom error messages
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/5073) in GitLab 8.10.
diff --git a/doc/administration/smime_signing_email.md b/doc/administration/smime_signing_email.md
index b1e7e349978..6ded7fdd7d0 100644
--- a/doc/administration/smime_signing_email.md
+++ b/doc/administration/smime_signing_email.md
@@ -75,8 +75,8 @@ extensions), which contain the following in a single encrypted file:
- Intermediate certificates (if any)
- Private key
-In order to export the required files in PEM encoding from the PKCS#12 file,
-the `openssl` command can be used:
+To export the required files in PEM encoding from the PKCS#12 file, the
+`openssl` command can be used:
```shell
#-- Extract private key in PEM encoding (no password, unencrypted)
diff --git a/doc/administration/snippets/index.md b/doc/administration/snippets/index.md
index 95de3b8c183..5e61d20c683 100644
--- a/doc/administration/snippets/index.md
+++ b/doc/administration/snippets/index.md
@@ -20,8 +20,8 @@ abuse of the feature. The default value is **52428800 Bytes** (50 MB).
The content size limit will be applied when a snippet is created or updated.
-In order not to break any existing snippets, the limit doesn't have any
-effect on them until a snippet is edited again and the content changes.
+This limit doesn't affect existing snippets until they're updated and their
+content changes.
### Snippets size limit configuration
diff --git a/doc/administration/terraform_state.md b/doc/administration/terraform_state.md
index 76e54acce16..55e166d2bf7 100644
--- a/doc/administration/terraform_state.md
+++ b/doc/administration/terraform_state.md
@@ -1,3 +1,9 @@
+---
+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/engineering/ux/technical-writing/#designated-technical-writers
+---
+
# Terraform state administration (alpha)
> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/2673) in GitLab 12.10.
diff --git a/doc/administration/troubleshooting/debug.md b/doc/administration/troubleshooting/debug.md
index a1b4df9b94e..ef95bdc8602 100644
--- a/doc/administration/troubleshooting/debug.md
+++ b/doc/administration/troubleshooting/debug.md
@@ -5,27 +5,15 @@ in production.
## Starting a Rails console session
-Troubleshooting and debugging your GitLab instance often requires a
-[Rails console](https://guides.rubyonrails.org/command_line.html#rails-console).
+Troubleshooting and debugging your GitLab instance often requires a Rails console.
+
+Your type of GitLab installation determines how
+[to start a rails console](../operations/rails_console.md).
See also:
- [GitLab Rails Console Cheat Sheet](gitlab_rails_cheat_sheet.md).
- [Navigating GitLab via Rails console](navigating_gitlab_via_rails_console.md).
-**For Omnibus installations**
-
-```shell
-sudo gitlab-rails console
-```
-
-**For installations from source**
-
-```shell
-sudo -u git -H bundle exec rails console -e production
-```
-
-Kubernetes: the console is in the task-runner pod, refer to our [Kubernetes cheat sheet](kubernetes_cheat_sheet.md#gitlab-specific-kubernetes-information) for details.
-
### Enabling Active Record logging
You can enable output of Active Record debug logging in the Rails console
@@ -98,7 +86,7 @@ sudo -u git -H bundle exec rails runner -e production /path/to/script.rb
A common problem is that mails are not being sent for some reason. Suppose you configured
an SMTP server, but you're not seeing mail delivered. Here's how to check the settings:
-1. Run a [Rails console](#starting-a-rails-console-session).
+1. Run a [Rails console](../operations/rails_console.md#starting-a-rails-console-session).
1. Look at the ActionMailer `delivery_method` to make sure it matches what you
intended. If you configured SMTP, it should say `:smtp`. If you're using
@@ -238,7 +226,7 @@ separate Rails process to debug the issue:
1. Log in to your GitLab account.
1. Copy the URL that is causing problems (e.g. `https://gitlab.com/ABC`).
1. Create a Personal Access Token for your user (Profile Settings -> Access Tokens).
-1. Bring up the [GitLab Rails console.](#starting-a-rails-console-session)
+1. Bring up the [GitLab Rails console.](../operations/rails_console.md#starting-a-rails-console-session)
1. At the Rails console, run:
```ruby
diff --git a/doc/administration/troubleshooting/elasticsearch.md b/doc/administration/troubleshooting/elasticsearch.md
index e13261e3074..6de5bb71d75 100644
--- a/doc/administration/troubleshooting/elasticsearch.md
+++ b/doc/administration/troubleshooting/elasticsearch.md
@@ -164,7 +164,7 @@ Troubleshooting search result issues is rather straight forward on Elasticsearch
The first step is to confirm GitLab is using Elasticsearch for the search function.
To do this:
-1. Confirm the integration is enabled in **Admin Area > Settings > Integrations**.
+1. Confirm the integration is enabled in **Admin Area > Settings > General**.
1. Confirm searches utilize Elasticsearch by accessing the rails console
(`sudo gitlab-rails console`) and running the following commands:
@@ -206,7 +206,7 @@ The best place to start is to determine if the issue is with creating an empty i
If it is, check on the Elasticsearch side to determine if the `gitlab-production` (the
name for the GitLab index) exists. If it exists, manually delete it on the Elasticsearch
side and attempt to recreate it from the
-[`recreate_index`](../../integration/elasticsearch.md#gitlab-elasticsearch-rake-tasks)
+[`recreate_index`](../../integration/elasticsearch.md#gitlab-advanced-search-rake-tasks)
Rake task.
If you still encounter issues, try creating an index manually on the Elasticsearch
@@ -225,8 +225,8 @@ during the indexing of projects. If errors do occur, they will either stem from
If the indexing process does not present errors, you will want to check the status of the indexed projects. You can do this via the following Rake tasks:
-- [`sudo gitlab-rake gitlab:elastic:index_projects_status`](../../integration/elasticsearch.md#gitlab-elasticsearch-rake-tasks) (shows the overall status)
-- [`sudo gitlab-rake gitlab:elastic:projects_not_indexed`](../../integration/elasticsearch.md#gitlab-elasticsearch-rake-tasks) (shows specific projects that are not indexed)
+- [`sudo gitlab-rake gitlab:elastic:index_projects_status`](../../integration/elasticsearch.md#gitlab-advanced-search-rake-tasks) (shows the overall status)
+- [`sudo gitlab-rake gitlab:elastic:projects_not_indexed`](../../integration/elasticsearch.md#gitlab-advanced-search-rake-tasks) (shows specific projects that are not indexed)
If:
diff --git a/doc/administration/troubleshooting/gitlab_rails_cheat_sheet.md b/doc/administration/troubleshooting/gitlab_rails_cheat_sheet.md
index 9a23a115765..dbda889d370 100644
--- a/doc/administration/troubleshooting/gitlab_rails_cheat_sheet.md
+++ b/doc/administration/troubleshooting/gitlab_rails_cheat_sheet.md
@@ -222,11 +222,12 @@ namespace = Namespace.find_by_full_path("")
```ruby
# ID will be the webhook_id
-WebHookLog.where(web_hook_id: ID).each_slice(ID) do |slice|
- slice.each(&:destroy)
-end
+hook=WebHook.find(ID)
+
+WebHooks::DestroyService.new(current_user).execute(hook)
-WebHook.find(ID).destroy
+#In case the service gets timeout consider removing webhook_logs
+hook.web_hook_logs.limit(BATCH_SIZE).delete_all
```
### Bulk update service integration password for _all_ projects
@@ -285,6 +286,16 @@ GitlabShellWorker.perform_in(0, :remove_repository, p.repository_storage, p.wiki
p.create_wiki ### creates the wiki project on the filesystem
```
+## Issue boards
+
+### In case of issue boards not loading properly and it's getting time out. We need to call the Issue Rebalancing service to fix this
+
+```ruby
+p=Project.find_by_full_path('PROJECT PATH')
+
+IssueRebalancingService.new(p.issues.take).execute
+```
+
## Imports / Exports
```ruby
@@ -411,6 +422,9 @@ user.skip_reconfirmation!
# Active users on the instance, now
User.active.count
+# Users taking a seat on the instance
+License.current.current_active_users_count
+
# The historical max on the instance as of the past year
::HistoricalData.max_historical_user_count
```
@@ -506,6 +520,54 @@ group = Group.find_by_path_or_name('group-name')
group.project_creation_level=0
```
+## SCIM
+
+### Fixing bad SCIM identities
+
+```ruby
+def delete_bad_scim(email, group_path)
+ output = ""
+ u = User.find_by_email(email)
+ uid = u.id
+ g = Group.find_by_full_path(group_path)
+ saml_prov_id = SamlProvider.find_by(group_id: g.id).id
+ saml = Identity.where(user_id: uid, saml_provider_id: saml_prov_id)
+ scim = ScimIdentity.where(user_id: uid , group_id: g.id)
+ if saml[0]
+ saml_eid = saml[0].extern_uid
+ output += "%s," % [email]
+ output += "SAML: %s," % [saml_eid]
+ if scim[0]
+ scim_eid = scim[0].extern_uid
+ output += "SCIM: %s" % [scim_eid]
+ if saml_eid == scim_eid
+ output += " Identities matched, not deleted \n"
+ else
+ scim[0].destroy
+ output += " Deleted \n"
+ end
+ else
+ output = "ERROR No SCIM identify found for: [%s]\n" % [email]
+ puts output
+ return 1
+ end
+ else
+ output = "ERROR No SAML identify found for: [%s]\n" % [email]
+ puts output
+ return 1
+ end
+ puts output
+ return 0
+end
+
+# In case of multiple emails
+emails = [email1, email2]
+
+emails.each do |e|
+ delete_bad_scim(e,'GROUPPATH')
+end
+```
+
## Routes
### Remove redirecting routes
@@ -525,8 +587,8 @@ conflicting_permanent_redirects.destroy_all
### Close a merge request properly (if merged but still marked as open)
```ruby
-p = Project.find_by_full_path('')
-m = project.merge_requests.find_by(iid: )
+p = Project.find_by_full_path('<full/path/to/project>')
+m = p.merge_requests.find_by(iid: <iid>)
u = User.find_by_username('')
MergeRequests::PostMergeService.new(p, u).execute(m)
```
diff --git a/doc/administration/troubleshooting/kubernetes_cheat_sheet.md b/doc/administration/troubleshooting/kubernetes_cheat_sheet.md
index 01532032b49..7c5a9e0d79f 100644
--- a/doc/administration/troubleshooting/kubernetes_cheat_sheet.md
+++ b/doc/administration/troubleshooting/kubernetes_cheat_sheet.md
@@ -84,8 +84,7 @@ and they will assist you with any issues you are having.
## GitLab-specific Kubernetes information
-- Minimal config that can be used to test a Kubernetes Helm chart can be found
- [here](https://gitlab.com/gitlab-org/charts/gitlab/-/issues/620).
+- Minimal configuration that can be used to [test a Kubernetes Helm chart](https://gitlab.com/gitlab-org/charts/gitlab/-/issues/620).
- Tailing logs of a separate pod. An example for a Webservice pod:
@@ -190,7 +189,7 @@ and they will assist you with any issues you are having.
be possible to use [Updating GitLab using the Helm Chart](https://docs.gitlab.com/charts/index.html#updating-gitlab-using-the-helm-chart)
for upgrades.
-- How to apply changes to GitLab config:
+- How to apply changes to GitLab configuration:
- Modify the `gitlab.yaml` file.
- Run the following command to apply changes:
@@ -255,7 +254,7 @@ to those documents for details.
helm install gitlab -f <path-to-yaml-file> gitlab/gitlab
```
- If you want to modify some GitLab settings, you can use the above-mentioned config
+ If you want to modify some GitLab settings, you can use the above-mentioned configuration
as a base and create your own YAML file.
- Monitor the installation progress via `helm status gitlab` and `minikube dashboard`.
diff --git a/doc/administration/troubleshooting/log_parsing.md b/doc/administration/troubleshooting/log_parsing.md
index dcd1df2f423..7914628a756 100644
--- a/doc/administration/troubleshooting/log_parsing.md
+++ b/doc/administration/troubleshooting/log_parsing.md
@@ -3,11 +3,11 @@
We recommend using log aggregation and search tools like Kibana and Splunk whenever possible,
but if they are not available you can still quickly parse
[GitLab logs](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/26311) in JSON format
-(the default since GitLab 12.0) using [`jq`](https://stedolan.github.io/jq/).
+(the default in GitLab 12.0 and later) using [`jq`](https://stedolan.github.io/jq/).
## What is JQ?
-As noted in its [manual](https://stedolan.github.io/jq/manual/), jq is a command-line JSON processor. The following examples
+As noted in its [manual](https://stedolan.github.io/jq/manual/), `jq` is a command-line JSON processor. The following examples
include use cases targeted for parsing GitLab log files.
## Parsing Logs
diff --git a/doc/administration/troubleshooting/navigating_gitlab_via_rails_console.md b/doc/administration/troubleshooting/navigating_gitlab_via_rails_console.md
index 571973c12d9..a1485249b0e 100644
--- a/doc/administration/troubleshooting/navigating_gitlab_via_rails_console.md
+++ b/doc/administration/troubleshooting/navigating_gitlab_via_rails_console.md
@@ -3,7 +3,7 @@
At the heart of GitLab is a web application [built using the Ruby on Rails
framework](https://about.gitlab.com/blog/2018/10/29/why-we-use-rails-to-build-gitlab/).
Thanks to this, we also get access to the amazing tools built right into Rails.
-In this guide, we'll introduce the [Rails console](debug.md#starting-a-rails-console-session)
+In this guide, we'll introduce the [Rails console](../operations/rails_console.md#starting-a-rails-console-session)
and the basics of interacting with your GitLab instance from the command line.
CAUTION: **Caution:**
@@ -20,20 +20,10 @@ Rails experience is helpful to have but not a must.
## Starting a Rails console session
-Omnibus GitLab comes with a convenient wrapper command which automatically loads
-the production GitLab environment:
+Your type of GitLab installation determines how
+[to start a rails console](../operations/rails_console.md).
-```shell
-sudo gitlab-rails console
-```
-
-For source installations, you'll have to instead run:
-
-```shell
-sudo -u git -H bundle exec rails console -e production
-```
-
-Further code examples will all take place inside the Rails console and also
+The following code examples will all take place inside the Rails console and also
assume an Omnibus GitLab installation.
## Active Record objects
diff --git a/doc/administration/troubleshooting/sidekiq.md b/doc/administration/troubleshooting/sidekiq.md
index 404e806c5d9..b7762f8ac3e 100644
--- a/doc/administration/troubleshooting/sidekiq.md
+++ b/doc/administration/troubleshooting/sidekiq.md
@@ -7,7 +7,7 @@ may be filling up. Users will notice when this happens because new branches
may not show up and merge requests may not be updated. The following are some
troubleshooting steps that will help you diagnose the bottleneck.
-NOTE **Note:**
+NOTE: **Note:**
GitLab administrators/users should consider working through these
debug steps with GitLab Support so the backtraces can be analyzed by our team.
It may reveal a bug or necessary improvement in GitLab.
diff --git a/doc/administration/troubleshooting/ssl.md b/doc/administration/troubleshooting/ssl.md
index e6c081e1eea..4d4b9755fa9 100644
--- a/doc/administration/troubleshooting/ssl.md
+++ b/doc/administration/troubleshooting/ssl.md
@@ -23,7 +23,7 @@ After configuring a GitLab instance with an internal CA certificate, you might n
More details here: https://curl.haxx.se/docs/sslcerts.html
```
-- Testing via the [rails console](debug.md#starting-a-rails-console-session) also fails:
+- Testing via the [rails console](../operations/rails_console.md#starting-a-rails-console-session) also fails:
```ruby
uri = URI.parse("https://gitlab.domain.tld")
@@ -205,6 +205,6 @@ Some of these errors come from the Excon Ruby gem, and could be generated in cir
where GitLab is configured to initiate an HTTPS session to a remote server
that is serving just HTTP.
-One scenario is that you're using [object storage](../high_availability/object_storage.md)
+One scenario is that you're using [object storage](../object_storage.md)
which is not served under HTTPS. GitLab is misconfigured and attempts a TLS handshake,
but the object storage will respond with plain HTTP.
diff --git a/doc/administration/troubleshooting/tracing_correlation_id.md b/doc/administration/troubleshooting/tracing_correlation_id.md
index 03c342595a3..ae9ebd90951 100644
--- a/doc/administration/troubleshooting/tracing_correlation_id.md
+++ b/doc/administration/troubleshooting/tracing_correlation_id.md
@@ -4,7 +4,7 @@ type: reference
# Finding relevant log entries with a correlation ID
-Since GitLab 11.6, a unique request tracking ID, known as the "correlation ID" has been
+In GitLab 11.6 and later, a unique request tracking ID, known as the "correlation ID" has been
logged by the GitLab instance for most requests. Each individual request to GitLab gets
its own correlation ID, which then gets logged in each GitLab component's logs for that
request. This makes it easier to trace behavior in a
@@ -122,5 +122,5 @@ If you have done some horizontal scaling in your GitLab infrastructure, then
you will need to search across _all_ of your GitLab nodes. You can do this with
some sort of log aggregation software like Loki, ELK, Splunk, or others.
-You can use a tool like Ansible or PSSH (parellel SSH) that can execute identical commands across your servers in
+You can use a tool like Ansible or PSSH (parallel SSH) that can execute identical commands across your servers in
parallel, or craft your own solution.
diff --git a/doc/administration/uploads.md b/doc/administration/uploads.md
index 71a41719003..91de089c45e 100644
--- a/doc/administration/uploads.md
+++ b/doc/administration/uploads.md
@@ -2,6 +2,35 @@
Uploads represent all user data that may be sent to GitLab as a single file. As an example, avatars and notes' attachments are uploads. Uploads are integral to GitLab functionality, and therefore cannot be disabled.
+## Upload parameters
+
+> - [Changed](https://gitlab.com/gitlab-org/gitlab/-/issues/214785) in GitLab 13.5.
+> - It's [deployed behind a feature flag](../user/feature_flags.md), enabled by default.
+> - It's enabled on GitLab.com.
+> - It's recommended for production use.
+> - For GitLab self-managed instances, GitLab administrators can opt to disable it. **(CORE ONLY)**
+
+In 13.5 and later, upload parameters are passed [between Workhorse and GitLab Rails](../development/architecture.md#simplified-component-overview) differently than they
+were before.
+
+This change is deployed behind a feature flag that is **enabled by default**.
+
+If you experience any issues with upload,
+[GitLab administrators with access to the GitLab Rails console](./feature_flags.md)
+can opt to disable it.
+
+To enable it:
+
+```ruby
+Feature.enable(:upload_middleware_jwt_params_handler)
+```
+
+To disable it:
+
+```ruby
+Feature.disable(:upload_middleware_jwt_params_handler)
+```
+
## Using local storage
NOTE: **Note:**
@@ -58,7 +87,7 @@ This configuration relies on valid AWS credentials to be configured already.
[Read more about using object storage with GitLab](object_storage.md).
NOTE: **Note:**
-We recommend using the [consolidated object storage settings](object_storage.md#consolidated-object-storage-configuration). The following instructions apply to the original config format.
+We recommend using the [consolidated object storage settings](object_storage.md#consolidated-object-storage-configuration). The following instructions apply to the original configuration format.
## Object Storage Settings
@@ -68,9 +97,9 @@ For source installations the following settings are nested under `uploads:` and
|---------|-------------|---------|
| `enabled` | Enable/disable object storage | `false` |
| `remote_directory` | The bucket name where Uploads will be stored| |
-| `direct_upload` | Set to true to remove Puma from the Upload path. Workhorse handles the actual Artifact Upload to Object Storage while Puma does minimal processing to keep track of the upload. There is no need for local shared storage. The option may be removed if support for a single storage type for all files is introduced. Read more on [direct upload](../development/uploads.md#direct-upload). | `false` |
-| `background_upload` | Set to false to disable automatic upload. Option may be removed once upload is direct to S3 (if `direct_upload` is set to `true` it will override `background_upload`) | `true` |
-| `proxy_download` | Set to true to enable proxying all files served. Option allows to reduce egress traffic as this allows clients to download directly from remote storage instead of proxying all data | `false` |
+| `direct_upload` | Set to `true` to remove Puma from the Upload path. Workhorse handles the actual Artifact Upload to Object Storage while Puma does minimal processing to keep track of the upload. There is no need for local shared storage. The option may be removed if support for a single storage type for all files is introduced. Read more on [direct upload](../development/uploads.md#direct-upload). | `false` |
+| `background_upload` | Set to `false` to disable automatic upload. Option may be removed once upload is direct to S3 (if `direct_upload` is set to `true` it will override `background_upload`) | `true` |
+| `proxy_download` | Set to `true` to enable proxying all files served. Option allows to reduce egress traffic as this allows clients to download directly from remote storage instead of proxying all data | `false` |
| `connection` | Various connection options described below | |
### Connection settings
diff --git a/doc/api/README.md b/doc/api/README.md
index 53df4114a71..3f7dae055e2 100644
--- a/doc/api/README.md
+++ b/doc/api/README.md
@@ -83,7 +83,11 @@ There are several ways to authenticate with the GitLab API:
1. [OAuth2 tokens](#oauth2-tokens)
1. [Personal access tokens](../user/profile/personal_access_tokens.md)
-1. [Project access tokens](../user/project/settings/project_access_tokens.md) **(CORE ONLY)**
+1. [Project access tokens](../user/project/settings/project_access_tokens.md)
+
+NOTE: **Note:**
+Project access tokens are supported for self-managed instances on Core and above. They are also supported on GitLab.com Bronze and above.
+
1. [Session cookie](#session-cookie)
1. [GitLab CI/CD job token](#gitlab-ci-job-token) **(Specific endpoints only)**
@@ -158,9 +162,22 @@ for example, without needing to explicitly pass an access token.
With a few API endpoints you can use a [GitLab CI/CD job token](../user/project/new_ci_build_permissions_model.md#job-token)
to authenticate with the API:
+- Packages:
+ - [Composer Repository](../user/packages/composer_repository/index.md)
+ - [Conan Repository](../user/packages/conan_repository/index.md)
+ - [Container Registry](../user/packages/container_registry/index.md) (`$CI_REGISTRY_PASSWORD` is actually `$CI_JOB_TOKEN`, but this may change in the future)
+ - [Go Proxy](../user/packages/go_proxy/index.md)
+ - [Maven Repository](../user/packages/maven_repository/index.md#authenticate-with-a-ci-job-token)
+ - [NPM Repository](../user/packages/npm_registry/index.md#authenticating-with-a-ci-job-token)
+ - [Nuget Repository](../user/packages/nuget_repository/index.md)
+ - [PyPI Repository](../user/packages/pypi_repository/index.md#using-gitlab-ci-with-pypi-packages)
+ - [Generic packages](../user/packages/generic_packages/index.md#publish-a-generic-package-by-using-cicd)
- [Get job artifacts](job_artifacts.md#get-job-artifacts)
-- [Pipeline triggers](pipeline_triggers.md)
+- [Pipeline triggers](pipeline_triggers.md) (via `token=` parameter)
- [Release creation](releases/index.md#create-a-release)
+- [Terraform plan](../user/infrastructure/index.md)
+
+The token is valid as long as the job is running.
### Impersonation tokens
@@ -297,21 +314,22 @@ The following table gives an overview of how the API functions generally behave.
The following table shows the possible return codes for API requests.
-| Return values | Description |
-| ------------- | ----------- |
-| `200 OK` | The `GET`, `PUT` or `DELETE` request was successful, the resource(s) itself is returned as JSON. |
-| `204 No Content` | The server has successfully fulfilled the request and that there is no additional content to send in the response payload body. |
-| `201 Created` | The `POST` request was successful and the resource is returned as JSON. |
-| `304 Not Modified` | Indicates that the resource has not been modified since the last request. |
-| `400 Bad Request` | A required attribute of the API request is missing, e.g., the title of an issue is not given. |
-| `401 Unauthorized` | The user is not authenticated, a valid [user token](#authentication) is necessary. |
-| `403 Forbidden` | The request is not allowed, e.g., the user is not allowed to delete a project. |
-| `404 Not Found` | A resource could not be accessed, e.g., an ID for a resource could not be found. |
+| Return values | Description |
+| ------------------------ | ----------- |
+| `200 OK` | The `GET`, `PUT` or `DELETE` request was successful, the resource(s) itself is returned as JSON. |
+| `204 No Content` | The server has successfully fulfilled the request and that there is no additional content to send in the response payload body. |
+| `201 Created` | The `POST` request was successful and the resource is returned as JSON. |
+| `304 Not Modified` | Indicates that the resource has not been modified since the last request. |
+| `400 Bad Request` | A required attribute of the API request is missing, e.g., the title of an issue is not given. |
+| `401 Unauthorized` | The user is not authenticated, a valid [user token](#authentication) is necessary. |
+| `403 Forbidden` | The request is not allowed, e.g., the user is not allowed to delete a project. |
+| `404 Not Found` | A resource could not be accessed, e.g., an ID for a resource could not be found. |
| `405 Method Not Allowed` | The request is not supported. |
-| `409 Conflict` | A conflicting resource already exists, e.g., creating a project with a name that already exists. |
-| `412` | Indicates the request was denied. May happen if the `If-Unmodified-Since` header is provided when trying to delete a resource, which was modified in between. |
-| `422 Unprocessable` | The entity could not be processed. |
-| `500 Server Error` | While handling the request something went wrong server-side. |
+| `409 Conflict` | A conflicting resource already exists, e.g., creating a project with a name that already exists. |
+| `412` | Indicates the request was denied. May happen if the `If-Unmodified-Since` header is provided when trying to delete a resource, which was modified in between. |
+| `422 Unprocessable` | The entity could not be processed. |
+| `429 Too Many Requests` | The user exceeded the [application rate limits](../administration/instance_limits.md#rate-limits). |
+| `500 Server Error` | While handling the request, something went wrong server-side. |
## Pagination
@@ -360,22 +378,22 @@ curl --head --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.exampl
The response will then be:
```http
-HTTP/1.1 200 OK
-Cache-Control: no-cache
-Content-Length: 1103
-Content-Type: application/json
-Date: Mon, 18 Jan 2016 09:43:18 GMT
-Link: <https://gitlab.example.com/api/v4/projects/8/issues/8/notes?page=1&per_page=3>; rel="prev", <https://gitlab.example.com/api/v4/projects/8/issues/8/notes?page=3&per_page=3>; rel="next", <https://gitlab.example.com/api/v4/projects/8/issues/8/notes?page=1&per_page=3>; rel="first", <https://gitlab.example.com/api/v4/projects/8/issues/8/notes?page=3&per_page=3>; rel="last"
-Status: 200 OK
-Vary: Origin
-X-Next-Page: 3
-X-Page: 2
-X-Per-Page: 3
-X-Prev-Page: 1
-X-Request-Id: 732ad4ee-9870-4866-a199-a9db0cde3c86
-X-Runtime: 0.108688
-X-Total: 8
-X-Total-Pages: 3
+HTTP/2 200 OK
+cache-control: no-cache
+content-length: 1103
+content-type: application/json
+date: Mon, 18 Jan 2016 09:43:18 GMT
+link: <https://gitlab.example.com/api/v4/projects/8/issues/8/notes?page=1&per_page=3>; rel="prev", <https://gitlab.example.com/api/v4/projects/8/issues/8/notes?page=3&per_page=3>; rel="next", <https://gitlab.example.com/api/v4/projects/8/issues/8/notes?page=1&per_page=3>; rel="first", <https://gitlab.example.com/api/v4/projects/8/issues/8/notes?page=3&per_page=3>; rel="last"
+status: 200 OK
+vary: Origin
+x-next-page: 3
+x-page: 2
+x-per-page: 3
+x-prev-page: 1
+x-request-id: 732ad4ee-9870-4866-a199-a9db0cde3c86
+x-runtime: 0.108688
+x-total: 8
+x-total-pages: 3
```
#### Other pagination headers
@@ -384,12 +402,12 @@ GitLab also returns the following additional pagination headers:
| Header | Description |
| --------------- | --------------------------------------------- |
-| `X-Total` | The total number of items |
-| `X-Total-Pages` | The total number of pages |
-| `X-Per-Page` | The number of items per page |
-| `X-Page` | The index of the current page (starting at 1) |
-| `X-Next-Page` | The index of the next page |
-| `X-Prev-Page` | The index of the previous page |
+| `x-total` | The total number of items |
+| `x-total-pages` | The total number of pages |
+| `x-per-page` | The number of items per page |
+| `x-page` | The index of the current page (starting at 1) |
+| `x-next-page` | The index of the next page |
+| `X-prev-page` | The index of the previous page |
NOTE: **Note:**
For GitLab.com users, [some pagination headers may not be returned](../user/gitlab_com/index.md#pagination-response-headers).
@@ -588,7 +606,7 @@ Such errors appear in two cases:
- A required attribute of the API request is missing, e.g., the title of an
issue is not given
-- An attribute did not pass the validation, e.g., user bio is too long
+- An attribute did not pass the validation, e.g., the user bio is too long
When an attribute is missing, you will get something like:
diff --git a/doc/api/admin_sidekiq_queues.md b/doc/api/admin_sidekiq_queues.md
index 4a2456d6f4a..22488d053b4 100644
--- a/doc/api/admin_sidekiq_queues.md
+++ b/doc/api/admin_sidekiq_queues.md
@@ -29,6 +29,7 @@ DELETE /admin/sidekiq/queues/:queue_name
| `root_namespace` | string | no | The root namespace of the project |
| `subscription_plan` | string | no | The subscription plan of the root namespace (GitLab.com only) |
| `caller_id` | string | no | The endpoint or background job that schedule the job (for example: `ProjectsController#create`, `/api/:version/projects/:id`, `PostReceive`) |
+| `feature_category` | string | no | The feature category of the background job (for example: `issue_tracking` or `code_review`) |
At least one attribute, other than `queue_name`, is required.
diff --git a/doc/api/api_resources.md b/doc/api/api_resources.md
index 898aa713331..199b244b2c3 100644
--- a/doc/api/api_resources.md
+++ b/doc/api/api_resources.md
@@ -9,7 +9,7 @@ Available resources for the [GitLab API](README.md) can be grouped in the follow
See also:
- [V3 to V4](v3_to_v4.md).
-- Adding [deploy keys for multiple projects](deploy_key_multiple_projects.md).
+- Adding [deploy keys for multiple projects](deploy_keys.md#adding-deploy-keys-to-multiple-projects).
- [API Resources for various templates](#templates-api-resources).
## Project resources
@@ -38,6 +38,7 @@ The following API resources are available in the project context:
| [Issues Statistics](issues_statistics.md) | `/projects/:id/issues_statistics` (also available for groups and standalone) |
| [Issue boards](boards.md) | `/projects/:id/boards` |
| [Issue links](issue_links.md) **(STARTER)** | `/projects/:id/issues/.../links` |
+| [Iterations](iterations.md) **(STARTER)** | `/projects/:id/iterations` (also available for groups) |
| [Jobs](jobs.md) | `/projects/:id/jobs`, `/projects/:id/pipelines/.../jobs` |
| [Labels](labels.md) | `/projects/:id/labels` |
| [Managed licenses](managed_licenses.md) **(ULTIMATE)** | `/projects/:id/managed_licenses` |
@@ -80,7 +81,7 @@ The following API resources are available in the project context:
| [Vulnerability exports](vulnerability_exports.md) **(ULTIMATE)** | `/projects/:id/vulnerability_exports` |
| [Project vulnerabilities](project_vulnerabilities.md) **(ULTIMATE)** | `/projects/:id/vulnerabilities` |
| [Vulnerability findings](vulnerability_findings.md) **(ULTIMATE)** | `/projects/:id/vulnerability_findings` |
-| [Wikis](wikis.md) | `/projects/:id/wikis` |
+| [Project wikis](wikis.md) | `/projects/:id/wikis` |
## Group resources
@@ -97,6 +98,7 @@ The following API resources are available in the group context:
| [Groups](groups.md) | `/groups`, `/groups/.../subgroups` |
| [Group badges](group_badges.md) | `/groups/:id/badges` |
| [Group issue boards](group_boards.md) | `/groups/:id/boards` |
+| [Group iterations](group_iterations.md) **(STARTER)** | `/groups/:id/iterations` (also available for projects) |
| [Group labels](group_labels.md) | `/groups/:id/labels` |
| [Group-level variables](group_level_variables.md) | `/groups/:id/variables` |
| [Group milestones](group_milestones.md) | `/groups/:id/milestones` |
@@ -108,6 +110,7 @@ The following API resources are available in the group context:
| [Notification settings](notification_settings.md) | `/groups/:id/notification_settings` (also available for projects and standalone) |
| [Resource label events](resource_label_events.md) | `/groups/:id/epics/.../resource_label_events` (also available for projects) |
| [Search](search.md) | `/groups/:id/search` (also available for projects and standalone) |
+| [Group wikis](group_wikis.md) **(PREMIUM)** | `/groups/:id/wikis` |
## Standalone resources
diff --git a/doc/api/commits.md b/doc/api/commits.md
index da95e9a943f..66b34d4bc75 100644
--- a/doc/api/commits.md
+++ b/doc/api/commits.md
@@ -614,7 +614,7 @@ Example response:
## Commit status
-Since GitLab 8.1, this is the new commit status API.
+In GitLab 8.1 and later, this is the new commit status API.
### List the statuses of a commit
diff --git a/doc/api/container_registry.md b/doc/api/container_registry.md
index e4687994017..3a7ebf9a2aa 100644
--- a/doc/api/container_registry.md
+++ b/doc/api/container_registry.md
@@ -23,9 +23,8 @@ GET /projects/:id/registry/repositories
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) accessible by the authenticated user. |
-| `tags` | boolean | no | If the parameter is included as true, each repository will include an array of `"tags"` in the response. |
-| `name` | string | no | Returns a list of repositories with a name that matches the value. ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/29763) in GitLab 13.0). |
-| `tags_count` | boolean | no | If the parameter is included as true, each repository will include `"tags_count"` in the response ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/32141) in GitLab 13.1). |
+| `tags` | boolean | no | If the parameter is included as true, each repository includes an array of `"tags"` in the response. |
+| `tags_count` | boolean | no | If the parameter is included as true, each repository includes `"tags_count"` in the response ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/32141) in GitLab 13.1). |
```shell
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/5/registry/repositories"
@@ -41,7 +40,8 @@ Example response:
"path": "group/project",
"project_id": 9,
"location": "gitlab.example.com:5000/group/project",
- "created_at": "2019-01-10T13:38:57.391Z"
+ "created_at": "2019-01-10T13:38:57.391Z",
+ "cleanup_policy_started_at": "2020-01-10T15:40:57.391Z"
},
{
"id": 2,
@@ -49,7 +49,8 @@ Example response:
"path": "group/project/releases",
"project_id": 9,
"location": "gitlab.example.com:5000/group/project/releases",
- "created_at": "2019-01-10T13:39:08.229Z"
+ "created_at": "2019-01-10T13:39:08.229Z",
+ "cleanup_policy_started_at": "2020-08-17T03:12:35.489Z"
}
]
```
@@ -65,9 +66,8 @@ GET /groups/:id/registry/repositories
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) accessible by the authenticated user. |
-| `tags` | boolean | no | If the parameter is included as true, each repository will include an array of `"tags"` in the response. |
-| `name` | string | no | Returns a list of repositories with a name that matches the value. ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/29763) in GitLab 13.0). |
-| `tags_count` | boolean | no | If the parameter is included as true, each repository will include `"tags_count"` in the response ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/32141) in GitLab 13.1). |
+| `tags` | boolean | no | If the parameter is included as true, each repository includes an array of `"tags"` in the response. |
+| `tags_count` | boolean | no | If the parameter is included as true, each repository includes `"tags_count"` in the response ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/32141) in GitLab 13.1). |
```shell
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/groups/2/registry/repositories?tags=1&tags_count=true"
@@ -84,6 +84,7 @@ Example response:
"project_id": 9,
"location": "gitlab.example.com:5000/group/project",
"created_at": "2019-01-10T13:38:57.391Z",
+ "cleanup_policy_started_at": "2020-08-17T03:12:35.489Z",
"tags_count": 1,
"tags": [
{
@@ -100,6 +101,7 @@ Example response:
"project_id": 11,
"location": "gitlab.example.com:5000/group/other_project",
"created_at": "2019-01-10T13:39:08.229Z",
+ "cleanup_policy_started_at": "2020-01-10T15:40:57.391Z",
"tags_count": 3,
"tags": [
{
@@ -228,7 +230,7 @@ DELETE /projects/:id/registry/repositories/:repository_id/tags/:tag_name
curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/5/registry/repositories/2/tags/v10.0.0"
```
-This action does not delete blobs. In order to delete them and recycle disk space,
+This action doesn't delete blobs. To delete them and recycle disk space,
[run the garbage collection](https://docs.gitlab.com/omnibus/maintenance/README.html#removing-unused-layers-not-referenced-by-manifests).
## Delete registry repository tags in bulk
@@ -248,28 +250,29 @@ DELETE /projects/:id/registry/repositories/:repository_id/tags
| `repository_id` | integer | yes | The ID of registry repository. |
| `name_regex` | string | no | The [re2](https://github.com/google/re2/wiki/Syntax) regex of the name to delete. To delete all tags specify `.*`. **Note:** `name_regex` is deprecated in favor of `name_regex_delete`. This field is validated. |
| `name_regex_delete` | string | yes | The [re2](https://github.com/google/re2/wiki/Syntax) regex of the name to delete. To delete all tags specify `.*`. This field is validated. |
-| `name_regex_keep` | string | no | The [re2](https://github.com/google/re2/wiki/Syntax) regex of the name to keep. This value will override any matches from `name_regex_delete`. This field is validated. Note: setting to `.*` will result in a no-op. |
+| `name_regex_keep` | string | no | The [re2](https://github.com/google/re2/wiki/Syntax) regex of the name to keep. This value overrides any matches from `name_regex_delete`. This field is validated. Note: setting to `.*` results in a no-op. |
| `keep_n` | integer | no | The amount of latest tags of given name to keep. |
| `older_than` | string | no | Tags to delete that are older than the given time, written in human readable form `1h`, `1d`, `1month`. |
This API call performs the following operations:
-1. It orders all tags by creation date. The creation date is the time of the
- manifest creation, not the time of tag push.
-1. It removes only the tags matching the given `name_regex_delete` (or deprecated `name_regex`), keeping any that match `name_regex_keep`.
-1. It never removes the tag named `latest`.
-1. It keeps N latest matching tags (if `keep_n` is specified).
-1. It only removes tags that are older than X amount of time (if `older_than` is specified).
-1. It schedules the asynchronous job to be executed in the background.
-
-These operations are executed asynchronously and it might
-take time to get executed. You can run this at most
-once an hour for a given container repository.
-This action does not delete blobs. In order to delete them and recycle disk space,
+- It orders all tags by creation date. The creation date is the time of the
+ manifest creation, not the time of tag push.
+- It removes only the tags matching the given `name_regex_delete` (or deprecated
+ `name_regex`), keeping any that match `name_regex_keep`.
+- It never removes the tag named `latest`.
+- It keeps N latest matching tags (if `keep_n` is specified).
+- It only removes tags that are older than X amount of time (if `older_than` is
+ specified).
+- It schedules the asynchronous job to be executed in the background.
+
+These operations are executed asynchronously and can take time to get executed.
+You can run this at most once an hour for a given container repository. This
+action doesn't delete blobs. To delete them and recycle disk space,
[run the garbage collection](https://docs.gitlab.com/omnibus/maintenance/README.html#removing-unused-layers-not-referenced-by-manifests).
NOTE: **Note:**
-Since GitLab 12.4, individual tags are deleted.
+In GitLab 12.4 and later, individual tags are deleted.
For more details, see the [discussion](https://gitlab.com/gitlab-org/gitlab/-/issues/15737).
Examples:
diff --git a/doc/api/epics.md b/doc/api/epics.md
index 91ea92c8589..5c7366c8457 100644
--- a/doc/api/epics.md
+++ b/doc/api/epics.md
@@ -267,6 +267,7 @@ POST /groups/:id/epics
| `labels` | string | no | The comma separated list of labels |
| `description` | string | no | The description of the epic. Limited to 1,048,576 characters. |
| `confidential` | boolean | no | Whether the epic should be confidential |
+| `created_at` | string | no | When the epic was created. Date time string, ISO 8601 formatted, for example `2016-03-11T03:45:40Z` . Requires administrator or project/group owner privileges ([introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/255309) in GitLab 13.5) |
| `start_date_is_fixed` | boolean | no | Whether start date should be sourced from `start_date_fixed` or from milestones (since 11.3) |
| `start_date_fixed` | string | no | The fixed start date of an epic (since 11.3) |
| `due_date_is_fixed` | boolean | no | Whether due date should be sourced from `due_date_fixed` or from milestones (since 11.3) |
@@ -349,6 +350,7 @@ PUT /groups/:id/epics/:epic_iid
| `description` | string | no | The description of an epic. Limited to 1,048,576 characters. |
| `confidential` | boolean | no | Whether the epic should be confidential |
| `labels` | string | no | The comma separated list of labels |
+| `updated_at` | string | no | When the epic was updated. Date time string, ISO 8601 formatted, for example `2016-03-11T03:45:40Z` . Requires administrator or project/group owner privileges ([introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/255309) in GitLab 13.5) |
| `start_date_is_fixed` | boolean | no | Whether start date should be sourced from `start_date_fixed` or from milestones (since 11.3) |
| `start_date_fixed` | string | no | The fixed start date of an epic (since 11.3) |
| `due_date_is_fixed` | boolean | no | Whether due date should be sourced from `due_date_fixed` or from milestones (since 11.3) |
@@ -422,10 +424,10 @@ DELETE /groups/:id/epics/:epic_iid
curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/groups/1/epics/5"
```
-## Create a to-do
+## Create a to do
-Manually creates a to-do for the current user on an epic. If
-there already exists a to-do for the user on that epic, status code `304` is
+Manually creates a to do for the current user on an epic. If
+there already exists a to do for the user on that epic, status code `304` is
returned.
```plaintext
diff --git a/doc/api/experiments.md b/doc/api/experiments.md
new file mode 100644
index 00000000000..66c444e54ce
--- /dev/null
+++ b/doc/api/experiments.md
@@ -0,0 +1,40 @@
+---
+stage: Growth
+group: Expansion
+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/#designated-technical-writers
+---
+
+# Experiments API
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/262725) in GitLab 13.5.
+
+This API is for listing Experiments [experiment use in development of GitLab](../development/experiment_guide/index.md).
+
+All methods require user be a [GitLab team member](https://gitlab.com/groups/gitlab-com/-/group_members) for authorization.
+
+## List all experiments
+
+Get a list of all experiments, with its enabled status.
+
+```plaintext
+GET /experiments
+```
+
+```shell
+curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/experiments"
+```
+
+Example response:
+
+```json
+[
+ {
+ "key": "experiment_1",
+ "enabled": true
+ },
+ {
+ "key": "experiment_2",
+ "enabled": false
+ }
+]
+```
diff --git a/doc/api/feature_flag_user_lists.md b/doc/api/feature_flag_user_lists.md
index 460f3727819..b44cb1fb9f2 100644
--- a/doc/api/feature_flag_user_lists.md
+++ b/doc/api/feature_flag_user_lists.md
@@ -4,9 +4,10 @@ group: Progressive Delivery
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/#designated-technical-writers
---
-# Feature flag user lists API **(PREMIUM)**
+# Feature flag user lists API **(CORE)**
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/205409) in [GitLab Premium](https://about.gitlab.com/pricing/) 12.10.
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/205409) in [GitLab Premium](https://about.gitlab.com/pricing/) 12.10.
+> - [Moved](https://gitlab.com/gitlab-org/gitlab/-/issues/212318) to GitLab Core in 13.5.
API for accessing GitLab Feature Flag User Lists.
diff --git a/doc/api/feature_flags.md b/doc/api/feature_flags.md
index 1088154b599..fbda873f866 100644
--- a/doc/api/feature_flags.md
+++ b/doc/api/feature_flags.md
@@ -4,9 +4,11 @@ group: Progressive Delivery
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/#designated-technical-writers
---
-# Feature Flags API **(PREMIUM)**
+# Feature Flags API **(CORE)**
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/9566) in [GitLab Premium](https://about.gitlab.com/pricing/) 12.5.
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/9566) in [GitLab Premium](https://about.gitlab.com/pricing/) 12.5.
+> - [Moved](https://gitlab.com/gitlab-org/gitlab/-/issues/212318) to [GitLab Starter](https://about.gitlab.com/pricing/) in 13.4.
+> - [Moved](https://gitlab.com/gitlab-org/gitlab/-/issues/212318) to [GitLab Core](https://about.gitlab.com/pricing/) in 13.5.
NOTE: **Note:**
This API is behind a [feature flag](../operations/feature_flags.md#enable-or-disable-feature-flag-strategies).
@@ -151,7 +153,7 @@ POST /projects/:id/feature_flags
| `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. |
+| `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://unleash.github.io/docs/activation_strategy#flexiblerollout). |
| `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. |
diff --git a/doc/api/feature_flags_legacy.md b/doc/api/feature_flags_legacy.md
index 175261b3a7b..a7c139a02ba 100644
--- a/doc/api/feature_flags_legacy.md
+++ b/doc/api/feature_flags_legacy.md
@@ -4,9 +4,11 @@ group: Progressive Delivery
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/#designated-technical-writers
---
-# Legacy Feature Flags API **(PREMIUM)**
+# Legacy Feature Flags API **(CORE)**
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/9566) in [GitLab Premium](https://about.gitlab.com/pricing/) 12.5.
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/9566) in [GitLab Premium](https://about.gitlab.com/pricing/) 12.5.
+> - [Moved](https://gitlab.com/gitlab-org/gitlab/-/issues/212318) to [GitLab Starter](https://about.gitlab.com/pricing/) in 13.4.
+> - [Moved](https://gitlab.com/gitlab-org/gitlab/-/issues/212318) to [GitLab Core](https://about.gitlab.com/pricing/) in 13.5.
CAUTION: **Deprecation:**
This API is deprecated and [scheduled for removal in GitLab 14.0](https://gitlab.com/gitlab-org/gitlab/-/issues/213369). Use [this API](feature_flags.md) instead.
diff --git a/doc/api/geo_nodes.md b/doc/api/geo_nodes.md
index 8d2052f7373..064bd26ee72 100644
--- a/doc/api/geo_nodes.md
+++ b/doc/api/geo_nodes.md
@@ -1,7 +1,7 @@
# Geo Nodes API **(PREMIUM ONLY)**
-In order to interact with Geo node endpoints, you need to authenticate yourself
-as an admin.
+To interact with Geo node endpoints, you need to authenticate yourself as an
+admin.
## Create a new Geo node
@@ -460,12 +460,12 @@ Example response:
"package_files_registry_count": 10,
"package_files_synced_count": 6,
"package_files_failed_count": 3,
- "terraform_states_count": 10,
- "terraform_states_checksummed_count": 10,
- "terraform_states_checksum_failed_count": 0,
- "terraform_states_registry_count": 10,
- "terraform_states_synced_count": 6,
- "terraform_states_failed_count": 3
+ "terraform_state_versions_count": 10,
+ "terraform_state_versions_checksummed_count": 10,
+ "terraform_state_versions_checksum_failed_count": 0,
+ "terraform_state_versions_registry_count": 10,
+ "terraform_state_versions_synced_count": 6,
+ "terraform_state_versions_failed_count": 3,
"snippet_repositories_count": 10,
"snippet_repositories_checksummed_count": 10,
"snippet_repositories_checksum_failed_count": 0,
diff --git a/doc/api/graphql/reference/gitlab_schema.graphql b/doc/api/graphql/reference/gitlab_schema.graphql
index 7f5ff04bcee..a44f8f70311 100644
--- a/doc/api/graphql/reference/gitlab_schema.graphql
+++ b/doc/api/graphql/reference/gitlab_schema.graphql
@@ -32,7 +32,7 @@ input AddAwardEmojiInput {
"""
The global id of the awardable resource
"""
- awardableId: ID!
+ awardableId: AwardableID!
"""
A unique identifier for the client performing the mutation.
@@ -77,7 +77,7 @@ input AddProjectToSecurityDashboardInput {
"""
ID of the project to be added to Instance Security Dashboard
"""
- id: ID!
+ id: ProjectID!
}
"""
@@ -115,6 +115,11 @@ input AdminSidekiqQueuesDeleteJobsInput {
clientMutationId: String
"""
+ Delete jobs matching feature_category in the context metadata
+ """
+ featureCategory: String
+
+ """
Delete jobs matching project in the context metadata
"""
project: String
@@ -245,6 +250,11 @@ type AlertManagementAlert implements Noteable {
endedAt: Time
"""
+ Environment for the alert
+ """
+ environment: Environment
+
+ """
Number of events of this alert
"""
eventCount: Int
@@ -435,6 +445,16 @@ Values for sorting alerts
"""
enum AlertManagementAlertSort {
"""
+ Created at ascending order
+ """
+ CREATED_ASC
+
+ """
+ Created at descending order
+ """
+ CREATED_DESC
+
+ """
Created time by ascending order
"""
CREATED_TIME_ASC
@@ -495,6 +515,16 @@ enum AlertManagementAlertSort {
STATUS_DESC
"""
+ Updated at ascending order
+ """
+ UPDATED_ASC
+
+ """
+ Updated at descending order
+ """
+ UPDATED_DESC
+
+ """
Created time by ascending order
"""
UPDATED_TIME_ASC
@@ -507,22 +537,22 @@ enum AlertManagementAlertSort {
"""
Created at ascending order
"""
- created_asc
+ created_asc @deprecated(reason: "Use CREATED_ASC. Deprecated in 13.5")
"""
Created at descending order
"""
- created_desc
+ created_desc @deprecated(reason: "Use CREATED_DESC. Deprecated in 13.5")
"""
Updated at ascending order
"""
- updated_asc
+ updated_asc @deprecated(reason: "Use UPDATED_ASC. Deprecated in 13.5")
"""
Updated at descending order
"""
- updated_desc
+ updated_desc @deprecated(reason: "Use UPDATED_DESC. Deprecated in 13.5")
}
"""
@@ -772,7 +802,7 @@ input AwardEmojiAddInput {
"""
The global id of the awardable resource
"""
- awardableId: ID!
+ awardableId: AwardableID!
"""
A unique identifier for the client performing the mutation.
@@ -812,7 +842,7 @@ input AwardEmojiRemoveInput {
"""
The global id of the awardable resource
"""
- awardableId: ID!
+ awardableId: AwardableID!
"""
A unique identifier for the client performing the mutation.
@@ -852,7 +882,7 @@ input AwardEmojiToggleInput {
"""
The global id of the awardable resource
"""
- awardableId: ID!
+ awardableId: AwardableID!
"""
A unique identifier for the client performing the mutation.
@@ -890,6 +920,11 @@ type AwardEmojiTogglePayload {
toggledOn: Boolean!
}
+"""
+Identifier of Awardable
+"""
+scalar AwardableID
+
type BaseService implements Service {
"""
Indicates if the service is active
@@ -1035,7 +1070,7 @@ type Board {
Returns the last _n_ elements from the list.
"""
last: Int
- ): EpicConnection
+ ): BoardEpicConnection
"""
Whether or not backlog list is hidden.
@@ -1053,6 +1088,31 @@ type Board {
id: ID!
"""
+ Labels of the board
+ """
+ labels(
+ """
+ Returns the elements in the list that come after the specified cursor.
+ """
+ after: String
+
+ """
+ Returns the elements in the list that come before the specified cursor.
+ """
+ before: String
+
+ """
+ Returns the first _n_ elements from the list.
+ """
+ first: Int
+
+ """
+ Returns the last _n_ elements from the list.
+ """
+ last: Int
+ ): LabelConnection
+
+ """
Lists of the board
"""
lists(
@@ -1077,6 +1137,11 @@ type Board {
id: ID
"""
+ Filters applied when getting issue metadata in the board list
+ """
+ issueFilters: BoardIssueInput
+
+ """
Returns the last _n_ elements from the list.
"""
last: Int
@@ -1134,6 +1199,484 @@ type BoardEdge {
}
"""
+Represents an epic on an issue board
+"""
+type BoardEpic implements CurrentUserTodos & Noteable {
+ """
+ Author of the epic
+ """
+ author: User!
+
+ """
+ Children (sub-epics) of the epic
+ """
+ children(
+ """
+ Returns the elements in the list that come after the specified cursor.
+ """
+ after: String
+
+ """
+ Filter epics by author
+ """
+ authorUsername: String
+
+ """
+ Returns the elements in the list that come before the specified cursor.
+ """
+ before: String
+
+ """
+ List items overlapping a time frame defined by startDate..endDate (if one
+ date is provided, both must be present). Deprecated in 13.5: Use timeframe.end
+ """
+ endDate: Time
+
+ """
+ Returns the first _n_ elements from the list.
+ """
+ first: Int
+
+ """
+ IID of the epic, e.g., "1"
+ """
+ iid: ID
+
+ """
+ Filter epics by iid for autocomplete
+ """
+ iidStartsWith: String
+
+ """
+ List of IIDs of epics, e.g., [1, 2]
+ """
+ iids: [ID!]
+
+ """
+ Filter epics by labels
+ """
+ labelName: [String!]
+
+ """
+ Returns the last _n_ elements from the list.
+ """
+ last: Int
+
+ """
+ Filter epics by milestone title, computed from epic's issues
+ """
+ milestoneTitle: String
+
+ """
+ Search query for epic title or description
+ """
+ search: String
+
+ """
+ List epics by sort order
+ """
+ sort: EpicSort
+
+ """
+ List items overlapping a time frame defined by startDate..endDate (if one
+ date is provided, both must be present). Deprecated in 13.5: Use
+ timeframe.start
+ """
+ startDate: Time
+
+ """
+ Filter epics by state
+ """
+ state: EpicState
+
+ """
+ List items overlapping the given timeframe
+ """
+ timeframe: Timeframe
+ ): EpicConnection
+
+ """
+ Timestamp of when the epic was closed
+ """
+ closedAt: Time
+
+ """
+ Indicates if the epic is confidential
+ """
+ confidential: Boolean
+
+ """
+ Timestamp of when the epic was created
+ """
+ createdAt: Time
+
+ """
+ Todos for the current user
+ """
+ currentUserTodos(
+ """
+ Returns the elements in the list that come after the specified cursor.
+ """
+ after: String
+
+ """
+ Returns the elements in the list that come before the specified cursor.
+ """
+ before: String
+
+ """
+ Returns the first _n_ elements from the list.
+ """
+ first: Int
+
+ """
+ Returns the last _n_ elements from the list.
+ """
+ last: Int
+
+ """
+ State of the todos
+ """
+ state: TodoStateEnum
+ ): TodoConnection!
+
+ """
+ Number of open and closed descendant epics and issues
+ """
+ descendantCounts: EpicDescendantCount
+
+ """
+ Total weight of open and closed issues in the epic and its descendants
+ """
+ descendantWeightSum: EpicDescendantWeights
+
+ """
+ Description of the epic
+ """
+ description: String
+
+ """
+ All discussions on this noteable
+ """
+ discussions(
+ """
+ Returns the elements in the list that come after the specified cursor.
+ """
+ after: String
+
+ """
+ Returns the elements in the list that come before the specified cursor.
+ """
+ before: String
+
+ """
+ Returns the first _n_ elements from the list.
+ """
+ first: Int
+
+ """
+ Returns the last _n_ elements from the list.
+ """
+ last: Int
+ ): DiscussionConnection!
+
+ """
+ Number of downvotes the epic has received
+ """
+ downvotes: Int!
+
+ """
+ Due date of the epic
+ """
+ dueDate: Time
+
+ """
+ Fixed due date of the epic
+ """
+ dueDateFixed: Time
+
+ """
+ Inherited due date of the epic from milestones
+ """
+ dueDateFromMilestones: Time
+
+ """
+ Indicates if the due date has been manually set
+ """
+ dueDateIsFixed: Boolean
+
+ """
+ Group to which the epic belongs
+ """
+ group: Group!
+
+ """
+ Indicates if the epic has children
+ """
+ hasChildren: Boolean!
+
+ """
+ Indicates if the epic has direct issues
+ """
+ hasIssues: Boolean!
+
+ """
+ Indicates if the epic has a parent epic
+ """
+ hasParent: Boolean!
+
+ """
+ Current health status of the epic
+ """
+ healthStatus: EpicHealthStatus
+
+ """
+ ID of the epic
+ """
+ id: ID!
+
+ """
+ Internal ID of the epic
+ """
+ iid: ID!
+
+ """
+ A list of issues associated with the epic
+ """
+ issues(
+ """
+ Returns the elements in the list that come after the specified cursor.
+ """
+ after: String
+
+ """
+ Returns the elements in the list that come before the specified cursor.
+ """
+ before: String
+
+ """
+ Returns the first _n_ elements from the list.
+ """
+ first: Int
+
+ """
+ Returns the last _n_ elements from the list.
+ """
+ last: Int
+ ): EpicIssueConnection
+
+ """
+ Labels assigned to the epic
+ """
+ labels(
+ """
+ Returns the elements in the list that come after the specified cursor.
+ """
+ after: String
+
+ """
+ Returns the elements in the list that come before the specified cursor.
+ """
+ before: String
+
+ """
+ Returns the first _n_ elements from the list.
+ """
+ first: Int
+
+ """
+ Returns the last _n_ elements from the list.
+ """
+ last: Int
+ ): LabelConnection
+
+ """
+ All notes on this noteable
+ """
+ notes(
+ """
+ Returns the elements in the list that come after the specified cursor.
+ """
+ after: String
+
+ """
+ Returns the elements in the list that come before the specified cursor.
+ """
+ before: String
+
+ """
+ Returns the first _n_ elements from the list.
+ """
+ first: Int
+
+ """
+ Returns the last _n_ elements from the list.
+ """
+ last: Int
+ ): NoteConnection!
+
+ """
+ Parent epic of the epic
+ """
+ parent: Epic
+
+ """
+ List of participants for the epic
+ """
+ participants(
+ """
+ Returns the elements in the list that come after the specified cursor.
+ """
+ after: String
+
+ """
+ Returns the elements in the list that come before the specified cursor.
+ """
+ before: String
+
+ """
+ Returns the first _n_ elements from the list.
+ """
+ first: Int
+
+ """
+ Returns the last _n_ elements from the list.
+ """
+ last: Int
+ ): UserConnection
+
+ """
+ Internal reference of the epic. Returned in shortened format by default
+ """
+ reference(
+ """
+ Indicates if the reference should be returned in full
+ """
+ full: Boolean = false
+ ): String!
+
+ """
+ URI path of the epic-issue relationship
+ """
+ relationPath: String
+
+ """
+ The relative position of the epic in the epic tree
+ """
+ relativePosition: Int
+
+ """
+ Start date of the epic
+ """
+ startDate: Time
+
+ """
+ Fixed start date of the epic
+ """
+ startDateFixed: Time
+
+ """
+ Inherited start date of the epic from milestones
+ """
+ startDateFromMilestones: Time
+
+ """
+ Indicates if the start date has been manually set
+ """
+ startDateIsFixed: Boolean
+
+ """
+ State of the epic
+ """
+ state: EpicState!
+
+ """
+ Indicates the currently logged in user is subscribed to the epic
+ """
+ subscribed: Boolean!
+
+ """
+ Title of the epic
+ """
+ title: String
+
+ """
+ Timestamp of when the epic was updated
+ """
+ updatedAt: Time
+
+ """
+ Number of upvotes the epic has received
+ """
+ upvotes: Int!
+
+ """
+ Permissions for the current user on the resource
+ """
+ userPermissions: EpicPermissions!
+
+ """
+ User preferences for the epic on the issue board
+ """
+ userPreferences: BoardEpicUserPreferences
+
+ """
+ Web path of the epic
+ """
+ webPath: String!
+
+ """
+ Web URL of the epic
+ """
+ webUrl: String!
+}
+
+"""
+The connection type for BoardEpic.
+"""
+type BoardEpicConnection {
+ """
+ A list of edges.
+ """
+ edges: [BoardEpicEdge]
+
+ """
+ A list of nodes.
+ """
+ nodes: [BoardEpic]
+
+ """
+ Information to aid in pagination.
+ """
+ pageInfo: PageInfo!
+}
+
+"""
+An edge in a connection.
+"""
+type BoardEpicEdge {
+ """
+ A cursor for use in pagination.
+ """
+ cursor: String!
+
+ """
+ The item at the end of the edge.
+ """
+ node: BoardEpic
+}
+
+"""
+Represents user preferences for a board epic
+"""
+type BoardEpicUserPreferences {
+ """
+ Indicates epic should be displayed as collapsed
+ """
+ collapsed: Boolean!
+}
+
+"""
Identifier of Board
"""
scalar BoardID
@@ -1402,7 +1945,7 @@ input BoardListUpdateLimitMetricsInput {
"""
The global ID of the list.
"""
- listId: ID!
+ listId: ListID!
"""
The new maximum issue count limit.
@@ -1479,6 +2022,11 @@ type BurnupChartDailyTotals {
type CiGroup {
"""
+ Detailed status of the group
+ """
+ detailedStatus: DetailedStatus
+
+ """
Jobs in group
"""
jobs(
@@ -1551,6 +2099,11 @@ type CiGroupEdge {
type CiJob {
"""
+ Detailed status of the job
+ """
+ detailedStatus: DetailedStatus
+
+ """
Name of the job
"""
name: String
@@ -1579,6 +2132,11 @@ type CiJob {
"""
last: Int
): CiJobConnection
+
+ """
+ Schedule for the build
+ """
+ scheduledAt: Time
}
"""
@@ -1623,6 +2181,11 @@ scalar CiPipelineID
type CiStage {
"""
+ Detailed status of the stage
+ """
+ detailedStatus: DetailedStatus
+
+ """
Group of jobs for the stage
"""
groups(
@@ -1937,6 +2500,11 @@ Identifier of Clusters::AgentToken
"""
scalar ClustersAgentTokenID
+"""
+Identifier of Clusters::Cluster
+"""
+scalar ClustersClusterID
+
type Commit {
"""
Author of the commit
@@ -2481,7 +3049,7 @@ input CreateAnnotationInput {
"""
The global id of the cluster to add an annotation to
"""
- clusterId: ID
+ clusterId: ClustersClusterID
"""
The path to a file defining the dashboard on which the annotation should be added
@@ -2501,7 +3069,7 @@ input CreateAnnotationInput {
"""
The global id of the environment to add an annotation to
"""
- environmentId: ID
+ environmentId: EnvironmentID
"""
Timestamp indicating starting moment to which the annotation relates
@@ -2530,6 +3098,71 @@ type CreateAnnotationPayload {
}
"""
+Autogenerated input type of CreateBoard
+"""
+input CreateBoardInput {
+ """
+ The ID of the user to be assigned to the board.
+ """
+ assigneeId: String
+
+ """
+ A unique identifier for the client performing the mutation.
+ """
+ clientMutationId: String
+
+ """
+ The group full path the board is associated with.
+ """
+ groupPath: ID
+
+ """
+ The IDs of labels to be added to the board.
+ """
+ labelIds: [ID!]
+
+ """
+ The ID of the milestone to be assigned to the board.
+ """
+ milestoneId: ID
+
+ """
+ The board name.
+ """
+ name: String
+
+ """
+ The project full path the board is associated with.
+ """
+ projectPath: ID
+
+ """
+ The weight of the board.
+ """
+ weight: Boolean
+}
+
+"""
+Autogenerated return type of CreateBoard
+"""
+type CreateBoardPayload {
+ """
+ The board after mutation.
+ """
+ board: Board
+
+ """
+ A unique identifier for the client performing the mutation.
+ """
+ clientMutationId: String
+
+ """
+ Errors encountered during execution of the mutation.
+ """
+ errors: [String!]!
+}
+
+"""
Autogenerated input type of CreateBranch
"""
input CreateBranchInput {
@@ -2636,7 +3269,7 @@ input CreateDiffNoteInput {
"""
The global id of the resource to add a note to
"""
- noteableId: ID!
+ noteableId: NoteableID!
"""
The position of this note on a diff
@@ -2766,7 +3399,7 @@ input CreateImageDiffNoteInput {
"""
The global id of the resource to add a note to
"""
- noteableId: ID!
+ noteableId: NoteableID!
"""
The position of this note on a diff
@@ -2795,6 +3428,121 @@ type CreateImageDiffNotePayload {
}
"""
+Autogenerated input type of CreateIssue
+"""
+input CreateIssueInput {
+ """
+ The array of user IDs to assign to the issue
+ """
+ assigneeIds: [UserID!]
+
+ """
+ A unique identifier for the client performing the mutation.
+ """
+ clientMutationId: String
+
+ """
+ Indicates the issue is confidential
+ """
+ confidential: Boolean
+
+ """
+ Timestamp when the issue was created. Available only for admins and project owners
+ """
+ createdAt: Time
+
+ """
+ Description of the issue
+ """
+ description: String
+
+ """
+ The ID of a discussion to resolve. Also pass `merge_request_to_resolve_discussions_of`
+ """
+ discussionToResolve: String
+
+ """
+ Due date of the issue
+ """
+ dueDate: ISO8601Date
+
+ """
+ The ID of an epic to associate the issue with
+ """
+ epicId: EpicID
+
+ """
+ The desired health status
+ """
+ healthStatus: HealthStatus
+
+ """
+ The IID (internal ID) of a project issue. Only admins and project owners can modify
+ """
+ iid: Int
+
+ """
+ The IDs of labels to be added to the issue
+ """
+ labelIds: [LabelID!]
+
+ """
+ Labels of the issue
+ """
+ labels: [String!]
+
+ """
+ Indicates discussion is locked on the issue
+ """
+ locked: Boolean
+
+ """
+ The IID of a merge request for which to resolve discussions
+ """
+ mergeRequestToResolveDiscussionsOf: MergeRequestID
+
+ """
+ The ID of the milestone to assign to the issue. On update milestone will be removed if set to null
+ """
+ milestoneId: MilestoneID
+
+ """
+ Project full path the issue is associated with
+ """
+ projectPath: ID!
+
+ """
+ Title of the issue
+ """
+ title: String!
+
+ """
+ The weight of the issue
+ """
+ weight: Int
+}
+
+"""
+Autogenerated return type of CreateIssue
+"""
+type CreateIssuePayload {
+ """
+ A unique identifier for the client performing the mutation.
+ """
+ clientMutationId: String
+
+ """
+ Errors encountered during execution of the mutation.
+ """
+ errors: [String!]!
+
+ """
+ The issue after mutation
+ """
+ issue: Issue
+}
+
+"""
Autogenerated input type of CreateIteration
"""
input CreateIterationInput {
@@ -2876,12 +3624,12 @@ input CreateNoteInput {
"""
The global id of the discussion this note is in reply to
"""
- discussionId: ID
+ discussionId: DiscussionID
"""
The global id of the resource to add a note to
"""
- noteableId: ID!
+ noteableId: NoteableID!
}
"""
@@ -2914,14 +3662,19 @@ input CreateRequirementInput {
clientMutationId: String
"""
- The project full path the requirement is associated with
+ Description of the requirement
+ """
+ description: String
+
+ """
+ Full project path the requirement is associated with
"""
projectPath: ID!
"""
Title of the requirement
"""
- title: String!
+ title: String
}
"""
@@ -2939,7 +3692,7 @@ type CreateRequirementPayload {
errors: [String!]!
"""
- The requirement after mutation
+ Requirement after mutation
"""
requirement: Requirement
}
@@ -3002,6 +3755,11 @@ type CreateSnippetPayload {
The snippet after mutation
"""
snippet: Snippet
+
+ """
+ Indicates whether the operation returns a record detected as spam
+ """
+ spam: Boolean
}
"""
@@ -3133,6 +3891,11 @@ type DastOnDemandScanCreatePayload {
enum DastScanTypeEnum {
"""
+ Active DAST scan. This scan will make active attacks against the target site.
+ """
+ ACTIVE
+
+ """
Passive DAST scan. This scan will not make active attacks against the target site.
"""
PASSIVE
@@ -3163,6 +3926,16 @@ type DastScannerProfile {
profileName: String
"""
+ Indicates the type of DAST scan that will run. Either a Passive Scan or an Active Scan.
+ """
+ scanType: DastScanTypeEnum
+
+ """
+ Indicates if debug messages should be included in DAST console output. True to include the debug messages.
+ """
+ showDebugMessages: Boolean!
+
+ """
The maximum number of minutes allowed for the spider to traverse the site
"""
spiderTimeout: Int
@@ -3171,6 +3944,13 @@ type DastScannerProfile {
The maximum number of seconds allowed for the site under test to respond to a request
"""
targetTimeout: Int
+
+ """
+ Indicates if the AJAX spider should be used to crawl the target site. True to
+ run the AJAX spider in addition to the traditional spider, and false to run
+ only the traditional spider.
+ """
+ useAjaxSpider: Boolean!
}
"""
@@ -3213,6 +3993,16 @@ input DastScannerProfileCreateInput {
profileName: String!
"""
+ Indicates the type of DAST scan that will run. Either a Passive Scan or an Active Scan.
+ """
+ scanType: DastScanTypeEnum = PASSIVE
+
+ """
+ Indicates if debug messages should be included in DAST console output. True to include the debug messages.
+ """
+ showDebugMessages: Boolean = false
+
+ """
The maximum number of minutes allowed for the spider to traverse the site.
"""
spiderTimeout: Int
@@ -3221,6 +4011,13 @@ input DastScannerProfileCreateInput {
The maximum number of seconds allowed for the site under test to respond to a request.
"""
targetTimeout: Int
+
+ """
+ Indicates if the AJAX spider should be used to crawl the target site. True to
+ run the AJAX spider in addition to the traditional spider, and false to run
+ only the traditional spider.
+ """
+ useAjaxSpider: Boolean = false
}
"""
@@ -3328,6 +4125,16 @@ input DastScannerProfileUpdateInput {
profileName: String!
"""
+ Indicates the type of DAST scan that will run. Either a Passive Scan or an Active Scan.
+ """
+ scanType: DastScanTypeEnum
+
+ """
+ Indicates if debug messages should be included in DAST console output. True to include the debug messages.
+ """
+ showDebugMessages: Boolean
+
+ """
The maximum number of minutes allowed for the spider to traverse the site.
"""
spiderTimeout: Int!
@@ -3336,6 +4143,13 @@ input DastScannerProfileUpdateInput {
The maximum number of seconds allowed for the site under test to respond to a request.
"""
targetTimeout: Int!
+
+ """
+ Indicates if the AJAX spider should be used to crawl the target site. True to
+ run the AJAX spider in addition to the traditional spider, and false to run
+ only the traditional spider.
+ """
+ useAjaxSpider: Boolean
}
"""
@@ -3596,6 +4410,66 @@ enum DastSiteProfileValidationStatusEnum {
}
"""
+Autogenerated input type of DastSiteTokenCreate
+"""
+input DastSiteTokenCreateInput {
+ """
+ A unique identifier for the client performing the mutation.
+ """
+ clientMutationId: String
+
+ """
+ The project the site token belongs to.
+ """
+ fullPath: ID!
+
+ """
+ The URL of the target to be validated.
+ """
+ targetUrl: String
+}
+
+"""
+Autogenerated return type of DastSiteTokenCreate
+"""
+type DastSiteTokenCreatePayload {
+ """
+ A unique identifier for the client performing the mutation.
+ """
+ clientMutationId: String
+
+ """
+ Errors encountered during execution of the mutation.
+ """
+ errors: [String!]!
+
+ """
+ ID of the site token.
+ """
+ id: DastSiteTokenID
+
+ """
+ The current validation status of the target.
+ """
+ status: DastSiteProfileValidationStatusEnum
+
+ """
+ Token string.
+ """
+ token: String
+}
+
+"""
+Identifier of DastSiteToken
+"""
+scalar DastSiteTokenID
+
+"""
+Date represented in ISO 8601
+"""
+scalar Date
+
+"""
Autogenerated input type of DeleteAnnotation
"""
input DeleteAnnotationInput {
@@ -3920,6 +4794,11 @@ A collection of designs
"""
type DesignCollection {
"""
+ Copy state of the design collection
+ """
+ copyState: DesignCollectionCopyState
+
+ """
Find a specific design
"""
design(
@@ -4047,6 +4926,26 @@ type DesignCollection {
}
"""
+Copy state of a DesignCollection
+"""
+enum DesignCollectionCopyState {
+ """
+ The DesignCollection encountered an error during a copy
+ """
+ ERROR
+
+ """
+ The DesignCollection is being copied
+ """
+ IN_PROGRESS
+
+ """
+ The DesignCollection has no copy in progress
+ """
+ READY
+}
+
+"""
The connection type for Design.
"""
type DesignConnection {
@@ -4471,6 +5370,41 @@ input DestroyBoardInput {
}
"""
+Autogenerated input type of DestroyBoardList
+"""
+input DestroyBoardListInput {
+ """
+ A unique identifier for the client performing the mutation.
+ """
+ clientMutationId: String
+
+ """
+ Global ID of the list to destroy. Only label lists are accepted.
+ """
+ listId: ListID!
+}
+
+"""
+Autogenerated return type of DestroyBoardList
+"""
+type DestroyBoardListPayload {
+ """
+ A unique identifier for the client performing the mutation.
+ """
+ clientMutationId: String
+
+ """
+ Errors encountered during execution of the mutation.
+ """
+ errors: [String!]!
+
+ """
+ The list after mutation.
+ """
+ list: BoardList
+}
+
+"""
Autogenerated return type of DestroyBoard
"""
type DestroyBoardPayload {
@@ -4502,7 +5436,7 @@ input DestroyNoteInput {
"""
The global id of the note to destroy
"""
- id: ID!
+ id: NoteID!
}
"""
@@ -4562,44 +5496,49 @@ type DestroySnippetPayload {
type DetailedStatus {
"""
- Path of the details for the pipeline status
+ Action information for the status. This includes method, button title, icon, path, and title
+ """
+ action: StatusAction
+
+ """
+ Path of the details for the status
"""
- detailsPath: String!
+ detailsPath: String
"""
- Favicon of the pipeline status
+ Favicon of the status
"""
- favicon: String!
+ favicon: String
"""
- Group of the pipeline status
+ Group of the status
"""
- group: String!
+ group: String
"""
- Indicates if the pipeline status has further details
+ Indicates if the status has further details
"""
- hasDetails: Boolean!
+ hasDetails: Boolean
"""
- Icon of the pipeline status
+ Icon of the status
"""
- icon: String!
+ icon: String
"""
- Label of the pipeline status
+ Label of the status
"""
- label: String!
+ label: String
"""
- Text of the pipeline status
+ Text of the status
"""
- text: String!
+ text: String
"""
- Tooltip associated with the pipeline status
+ Tooltip associated with the status
"""
- tooltip: String!
+ tooltip: String
}
input DiffImagePositionInput {
@@ -4915,6 +5854,11 @@ type DiscussionEdge {
}
"""
+Identifier of Discussion
+"""
+scalar DiscussionID
+
+"""
Autogenerated input type of DiscussionToggleResolve
"""
input DiscussionToggleResolveInput {
@@ -4926,7 +5870,7 @@ input DiscussionToggleResolveInput {
"""
The global id of the discussion
"""
- id: ID!
+ id: DiscussionID!
"""
Will resolve the discussion when true, and unresolve the discussion when false
@@ -4971,7 +5915,7 @@ input DismissVulnerabilityInput {
"""
ID of the vulnerability to be dismissed
"""
- id: ID!
+ id: VulnerabilityID!
}
"""
@@ -5045,7 +5989,7 @@ type Environment {
id: ID!
"""
- The most severe open alert for the environment. If multiple alerts have equal severity, the most recent is returned.
+ The most severe open alert for the environment. If multiple alerts have equal severity, the most recent is returned
"""
latestOpenedMostSevereAlert: AlertManagementAlert
@@ -5065,6 +6009,12 @@ type Environment {
name: String!
"""
+ The path to the environment. Will always return null if
+ `expose_environment_path_in_alert_details` feature flag is disabled
+ """
+ path: String
+
+ """
State of the environment, for example: available/stopped
"""
state: String!
@@ -5106,6 +6056,11 @@ type EnvironmentEdge {
}
"""
+Identifier of Environment
+"""
+scalar EnvironmentID
+
+"""
Represents an epic
"""
type Epic implements CurrentUserTodos & Noteable {
@@ -5134,8 +6089,8 @@ type Epic implements CurrentUserTodos & Noteable {
before: String
"""
- List items within a time frame where items.end_date is between startDate and
- endDate parameters (startDate parameter must be present)
+ List items overlapping a time frame defined by startDate..endDate (if one
+ date is provided, both must be present). Deprecated in 13.5: Use timeframe.end
"""
endDate: Time
@@ -5185,8 +6140,9 @@ type Epic implements CurrentUserTodos & Noteable {
sort: EpicSort
"""
- List items within a time frame where items.start_date is between startDate
- and endDate parameters (endDate parameter must be present)
+ List items overlapping a time frame defined by startDate..endDate (if one
+ date is provided, both must be present). Deprecated in 13.5: Use
+ timeframe.start
"""
startDate: Time
@@ -5194,10 +6150,15 @@ type Epic implements CurrentUserTodos & Noteable {
Filter epics by state
"""
state: EpicState
+
+ """
+ List items overlapping the given timeframe
+ """
+ timeframe: Timeframe
): EpicConnection
"""
- Timestamp of the epic's closure
+ Timestamp of when the epic was closed
"""
closedAt: Time
@@ -5207,7 +6168,7 @@ type Epic implements CurrentUserTodos & Noteable {
confidential: Boolean
"""
- Timestamp of the epic's creation
+ Timestamp of when the epic was created
"""
createdAt: Time
@@ -5502,7 +6463,7 @@ type Epic implements CurrentUserTodos & Noteable {
title: String
"""
- Timestamp of the epic's last activity
+ Timestamp of when the epic was updated
"""
updatedAt: Time
@@ -5967,6 +6928,11 @@ type EpicIssue implements CurrentUserTodos & Noteable {
severity: IssuableSeverity
"""
+ Timestamp of when the issue SLA expires.
+ """
+ slaDueAt: Time
+
+ """
State of the issue
"""
state: IssueState!
@@ -6233,17 +7199,17 @@ input EpicTreeNodeFieldsInputType {
"""
The id of the epic_issue or issue that the actual epic or issue is switched with
"""
- adjacentReferenceId: ID
+ adjacentReferenceId: EpicTreeSortingID
"""
The id of the epic_issue or epic that is being moved
"""
- id: ID!
+ id: EpicTreeSortingID!
"""
ID of the new parent epic
"""
- newParentId: ID
+ newParentId: EpicID
"""
The type of the switch, after or before allowed
@@ -6258,7 +7224,7 @@ input EpicTreeReorderInput {
"""
The id of the base epic of the tree
"""
- baseEpicId: ID!
+ baseEpicId: EpicID!
"""
A unique identifier for the client performing the mutation.
@@ -6287,6 +7253,11 @@ type EpicTreeReorderPayload {
}
"""
+Identifier of EpicTreeSorting
+"""
+scalar EpicTreeSortingID
+
+"""
Epic ID wildcard values
"""
enum EpicWildcardId {
@@ -6328,6 +7299,36 @@ type GeoNode {
internalUrl: String
"""
+ Find merge request diff registries on this Geo node
+ """
+ mergeRequestDiffRegistries(
+ """
+ Returns the elements in the list that come after the specified cursor.
+ """
+ after: String
+
+ """
+ Returns the elements in the list that come before the specified cursor.
+ """
+ before: String
+
+ """
+ Returns the first _n_ elements from the list.
+ """
+ first: Int
+
+ """
+ Filters registries by their ID
+ """
+ ids: [ID!]
+
+ """
+ Returns the last _n_ elements from the list.
+ """
+ last: Int
+ ): MergeRequestDiffRegistryConnection
+
+ """
The interval (in days) in which the repository verification is valid. Once expired, it will be reverified
"""
minimumReverificationInterval: Int
@@ -6418,10 +7419,9 @@ type GeoNode {
syncObjectStorage: Boolean
"""
- Find terraform state registries on this Geo node. Available only when feature
- flag `geo_terraform_state_replication` is enabled
+ Find terraform state version registries on this Geo node
"""
- terraformStateRegistries(
+ terraformStateVersionRegistries(
"""
Returns the elements in the list that come after the specified cursor.
"""
@@ -6446,7 +7446,7 @@ type GeoNode {
Returns the last _n_ elements from the list.
"""
last: Int
- ): TerraformStateRegistryConnection
+ ): TerraformStateVersionRegistryConnection
"""
The user-facing URL for this Geo node
@@ -6493,6 +7493,16 @@ type GrafanaIntegration {
type Group {
"""
+ Size limit for repositories in the namespace in bytes
+ """
+ actualRepositorySizeLimit: Float
+
+ """
+ Additional storage purchased for the root namespace in bytes
+ """
+ additionalPurchasedStorageSize: Float
+
+ """
Indicates whether Auto DevOps is enabled for all projects within this group
"""
autoDevopsEnabled: Boolean
@@ -6507,9 +7517,9 @@ type Group {
"""
board(
"""
- Find a board by its ID
+ The board's ID
"""
- id: ID
+ id: BoardID!
): Board
"""
@@ -6543,6 +7553,11 @@ type Group {
): BoardConnection
"""
+ Includes at least one project where the repository size exceeds the limit
+ """
+ containsLockedProjects: Boolean!
+
+ """
Description of the namespace
"""
description: String
@@ -6567,8 +7582,8 @@ type Group {
authorUsername: String
"""
- List items within a time frame where items.end_date is between startDate and
- endDate parameters (startDate parameter must be present)
+ List items overlapping a time frame defined by startDate..endDate (if one
+ date is provided, both must be present). Deprecated in 13.5: Use timeframe.end
"""
endDate: Time
@@ -6608,8 +7623,9 @@ type Group {
sort: EpicSort
"""
- List items within a time frame where items.start_date is between startDate
- and endDate parameters (endDate parameter must be present)
+ List items overlapping a time frame defined by startDate..endDate (if one
+ date is provided, both must be present). Deprecated in 13.5: Use
+ timeframe.start
"""
startDate: Time
@@ -6617,6 +7633,11 @@ type Group {
Filter epics by state
"""
state: EpicState
+
+ """
+ List items overlapping the given timeframe
+ """
+ timeframe: Timeframe
): Epic
"""
@@ -6639,8 +7660,8 @@ type Group {
before: String
"""
- List items within a time frame where items.end_date is between startDate and
- endDate parameters (startDate parameter must be present)
+ List items overlapping a time frame defined by startDate..endDate (if one
+ date is provided, both must be present). Deprecated in 13.5: Use timeframe.end
"""
endDate: Time
@@ -6690,8 +7711,9 @@ type Group {
sort: EpicSort
"""
- List items within a time frame where items.start_date is between startDate
- and endDate parameters (endDate parameter must be present)
+ List items overlapping a time frame defined by startDate..endDate (if one
+ date is provided, both must be present). Deprecated in 13.5: Use
+ timeframe.start
"""
startDate: Time
@@ -6699,6 +7721,11 @@ type Group {
Filter epics by state
"""
state: EpicState
+
+ """
+ List items overlapping the given timeframe
+ """
+ timeframe: Timeframe
): EpicConnection
"""
@@ -6762,7 +7789,7 @@ type Group {
isTemporaryStorageIncreaseEnabled: Boolean!
"""
- Issues of the group
+ Issues for projects in this group
"""
issues(
"""
@@ -6781,6 +7808,16 @@ type Group {
assigneeUsername: String
"""
+ Usernames of users assigned to the issue
+ """
+ assigneeUsernames: [String!]
+
+ """
+ Username of the author of the issue
+ """
+ authorUsername: String
+
+ """
Returns the elements in the list that come before the specified cursor.
"""
before: String
@@ -6821,7 +7858,7 @@ type Group {
iids: [String!]
"""
- Include issues belonging to subgroups.
+ Include issues belonging to subgroups
"""
includeSubgroups: Boolean = false
@@ -6891,8 +7928,8 @@ type Group {
before: String
"""
- List items within a time frame where items.end_date is between startDate and
- endDate parameters (startDate parameter must be present)
+ List items overlapping a time frame defined by startDate..endDate (if one
+ date is provided, both must be present). Deprecated in 13.5: Use timeframe.end
"""
endDate: Time
@@ -6922,8 +7959,9 @@ type Group {
last: Int
"""
- List items within a time frame where items.start_date is between startDate
- and endDate parameters (endDate parameter must be present)
+ List items overlapping a time frame defined by startDate..endDate (if one
+ date is provided, both must be present). Deprecated in 13.5: Use
+ timeframe.start
"""
startDate: Time
@@ -6933,6 +7971,11 @@ type Group {
state: IterationState
"""
+ List items overlapping the given timeframe
+ """
+ timeframe: Timeframe
+
+ """
Fuzzy search by title
"""
title: String
@@ -6989,6 +8032,91 @@ type Group {
mentionsDisabled: Boolean
"""
+ Merge requests for projects in this group
+ """
+ mergeRequests(
+ """
+ Returns the elements in the list that come after the specified cursor.
+ """
+ after: String
+
+ """
+ Username of the assignee
+ """
+ assigneeUsername: String
+
+ """
+ Username of the author
+ """
+ authorUsername: String
+
+ """
+ Returns the elements in the list that come before the specified cursor.
+ """
+ before: String
+
+ """
+ Returns the first _n_ elements from the list.
+ """
+ first: Int
+
+ """
+ Array of IIDs of merge requests, for example `[1, 2]`
+ """
+ iids: [String!]
+
+ """
+ Include merge requests belonging to subgroups
+ """
+ includeSubgroups: Boolean = false
+
+ """
+ Array of label names. All resolved merge requests will have all of these labels.
+ """
+ labels: [String!]
+
+ """
+ Returns the last _n_ elements from the list.
+ """
+ last: Int
+
+ """
+ Merge requests merged after this date
+ """
+ mergedAfter: Time
+
+ """
+ Merge requests merged before this date
+ """
+ mergedBefore: Time
+
+ """
+ Title of the milestone
+ """
+ milestoneTitle: String
+
+ """
+ Sort merge requests by this criteria
+ """
+ sort: MergeRequestSort = created_desc
+
+ """
+ Array of source branch names. All resolved merge requests will have one of these branches as their source.
+ """
+ sourceBranches: [String!]
+
+ """
+ A merge request state. If provided, all resolved merge requests will have this state.
+ """
+ state: MergeRequestState
+
+ """
+ Array of target branch names. All resolved merge requests will have one of these branches as their target.
+ """
+ targetBranches: [String!]
+ ): MergeRequestConnection
+
+ """
Milestones of the group
"""
milestones(
@@ -7003,8 +8131,13 @@ type Group {
before: String
"""
- List items within a time frame where items.end_date is between startDate and
- endDate parameters (startDate parameter must be present)
+ A date that the milestone contains
+ """
+ containingDate: Time
+
+ """
+ List items overlapping a time frame defined by startDate..endDate (if one
+ date is provided, both must be present). Deprecated in 13.5: Use timeframe.end
"""
endDate: Time
@@ -7029,8 +8162,14 @@ type Group {
last: Int
"""
- List items within a time frame where items.start_date is between startDate
- and endDate parameters (endDate parameter must be present)
+ A search string for the title
+ """
+ searchTitle: String
+
+ """
+ List items overlapping a time frame defined by startDate..endDate (if one
+ date is provided, both must be present). Deprecated in 13.5: Use
+ timeframe.start
"""
startDate: Time
@@ -7038,6 +8177,16 @@ type Group {
Filter milestones by state
"""
state: MilestoneStateEnum
+
+ """
+ List items overlapping the given timeframe
+ """
+ timeframe: Timeframe
+
+ """
+ The title of the milestone
+ """
+ title: String
): MilestoneConnection
"""
@@ -7106,6 +8255,11 @@ type Group {
): ProjectConnection!
"""
+ Number of projects in the root namespace where the repository size exceeds the limit
+ """
+ repositorySizeExcessProjectCount: Int!
+
+ """
Indicates if users can request access to namespace
"""
requestAccessEnabled: Boolean
@@ -7186,6 +8340,16 @@ type Group {
): TimelogConnection!
"""
+ Total repository size of all projects in the root namespace in bytes
+ """
+ totalRepositorySize: Float
+
+ """
+ Total excess repository size of all projects in the root namespace in bytes
+ """
+ totalRepositorySizeExcess: Float
+
+ """
Time before two-factor authentication is enforced
"""
twoFactorGracePeriod: Int
@@ -7962,6 +9126,11 @@ type Issue implements CurrentUserTodos & Noteable {
severity: IssuableSeverity
"""
+ Timestamp of when the issue SLA expires.
+ """
+ slaDueAt: Time
+
+ """
State of the issue
"""
state: IssueState!
@@ -8088,6 +9257,31 @@ Identifier of Issue
scalar IssueID
"""
+Autogenerated input type of IssueMove
+"""
+input IssueMoveInput {
+ """
+ A unique identifier for the client performing the mutation.
+ """
+ clientMutationId: String
+
+ """
+ The IID of the issue to mutate
+ """
+ iid: String!
+
+ """
+ The project the issue to mutate is in
+ """
+ projectPath: ID!
+
+ """
+ The project to move the issue to
+ """
+ targetProjectPath: ID!
+}
+
+"""
Autogenerated input type of IssueMoveList
"""
input IssueMoveListInput {
@@ -8158,6 +9352,26 @@ type IssueMoveListPayload {
}
"""
+Autogenerated return type of IssueMove
+"""
+type IssueMovePayload {
+ """
+ A unique identifier for the client performing the mutation.
+ """
+ clientMutationId: String
+
+ """
+ Errors encountered during execution of the mutation.
+ """
+ errors: [String!]!
+
+ """
+ The issue after mutation
+ """
+ issue: Issue
+}
+
+"""
Check permissions for the current user on a issue
"""
type IssuePermissions {
@@ -8404,7 +9618,7 @@ input IssueSetIterationInput {
"""
The iteration to assign to the issue.
"""
- iterationId: ID
+ iterationId: IterationID
"""
The project the issue to mutate is in
@@ -8617,6 +9831,16 @@ Values for sorting issues
"""
enum IssueSort {
"""
+ Created at ascending order
+ """
+ CREATED_ASC
+
+ """
+ Created at descending order
+ """
+ CREATED_DESC
+
+ """
Due date by ascending order
"""
DUE_DATE_ASC
@@ -8657,11 +9881,41 @@ enum IssueSort {
PRIORITY_DESC
"""
+ Published issues shown last
+ """
+ PUBLISHED_ASC
+
+ """
+ Published issues shown first
+ """
+ PUBLISHED_DESC
+
+ """
Relative position by ascending order
"""
RELATIVE_POSITION_ASC
"""
+ Severity from less critical to more critical
+ """
+ SEVERITY_ASC
+
+ """
+ Severity from more critical to less critical
+ """
+ SEVERITY_DESC
+
+ """
+ Updated at ascending order
+ """
+ UPDATED_ASC
+
+ """
+ Updated at descending order
+ """
+ UPDATED_DESC
+
+ """
Weight by ascending order
"""
WEIGHT_ASC
@@ -8674,22 +9928,22 @@ enum IssueSort {
"""
Created at ascending order
"""
- created_asc
+ created_asc @deprecated(reason: "Use CREATED_ASC. Deprecated in 13.5")
"""
Created at descending order
"""
- created_desc
+ created_desc @deprecated(reason: "Use CREATED_DESC. Deprecated in 13.5")
"""
Updated at ascending order
"""
- updated_asc
+ updated_asc @deprecated(reason: "Use UPDATED_ASC. Deprecated in 13.5")
"""
Updated at descending order
"""
- updated_desc
+ updated_desc @deprecated(reason: "Use UPDATED_DESC. Deprecated in 13.5")
}
"""
@@ -8703,6 +9957,21 @@ enum IssueState {
}
"""
+Values for issue state events
+"""
+enum IssueStateEvent {
+ """
+ Closes the issue
+ """
+ CLOSE
+
+ """
+ Reopens the issue
+ """
+ REOPEN
+}
+
+"""
Represents total number of issues for the represented statuses
"""
type IssueStatusCountsType {
@@ -9215,6 +10484,11 @@ The connection type for Label.
"""
type LabelConnection {
"""
+ Total count of collection
+ """
+ count: Int!
+
+ """
A list of edges.
"""
edges: [LabelEdge]
@@ -9251,6 +10525,11 @@ Identifier of Label
scalar LabelID
"""
+Identifier of List
+"""
+scalar ListID
+
+"""
List limit metric setting
"""
enum ListLimitMetric {
@@ -9319,6 +10598,26 @@ enum MeasurementIdentifier {
PIPELINES
"""
+ Pipeline count with canceled status
+ """
+ PIPELINES_CANCELED
+
+ """
+ Pipeline count with failed status
+ """
+ PIPELINES_FAILED
+
+ """
+ Pipeline count with skipped status
+ """
+ PIPELINES_SKIPPED
+
+ """
+ Pipeline count with success status
+ """
+ PIPELINES_SUCCEEDED
+
+ """
Project count
"""
PROJECTS
@@ -10019,6 +11318,86 @@ type MergeRequestCreatePayload {
}
"""
+Represents the Geo sync and verification state of a Merge Request diff
+"""
+type MergeRequestDiffRegistry {
+ """
+ Timestamp when the MergeRequestDiffRegistry was created
+ """
+ createdAt: Time
+
+ """
+ ID of the MergeRequestDiffRegistry
+ """
+ id: ID!
+
+ """
+ Error message during sync of the MergeRequestDiffRegistry
+ """
+ lastSyncFailure: String
+
+ """
+ Timestamp of the most recent successful sync of the MergeRequestDiffRegistry
+ """
+ lastSyncedAt: Time
+
+ """
+ ID of the Merge Request diff
+ """
+ mergeRequestDiffId: ID!
+
+ """
+ Timestamp after which the MergeRequestDiffRegistry should be resynced
+ """
+ retryAt: Time
+
+ """
+ Number of consecutive failed sync attempts of the MergeRequestDiffRegistry
+ """
+ retryCount: Int
+
+ """
+ Sync state of the MergeRequestDiffRegistry
+ """
+ state: RegistryState
+}
+
+"""
+The connection type for MergeRequestDiffRegistry.
+"""
+type MergeRequestDiffRegistryConnection {
+ """
+ A list of edges.
+ """
+ edges: [MergeRequestDiffRegistryEdge]
+
+ """
+ A list of nodes.
+ """
+ nodes: [MergeRequestDiffRegistry]
+
+ """
+ Information to aid in pagination.
+ """
+ pageInfo: PageInfo!
+}
+
+"""
+An edge in a connection.
+"""
+type MergeRequestDiffRegistryEdge {
+ """
+ A cursor for use in pagination.
+ """
+ cursor: String!
+
+ """
+ The item at the end of the edge.
+ """
+ node: MergeRequestDiffRegistry
+}
+
+"""
An edge in a connection.
"""
type MergeRequestEdge {
@@ -10034,6 +11413,11 @@ type MergeRequestEdge {
}
"""
+Identifier of MergeRequest
+"""
+scalar MergeRequestID
+
+"""
Check permissions for the current user on a merge request
"""
type MergeRequestPermissions {
@@ -10245,7 +11629,7 @@ input MergeRequestSetMilestoneInput {
"""
The milestone to assign to the merge request.
"""
- milestoneId: ID
+ milestoneId: MilestoneID
"""
The project the merge request to mutate is in
@@ -10368,6 +11752,16 @@ Values for sorting merge requests
"""
enum MergeRequestSort {
"""
+ Created at ascending order
+ """
+ CREATED_ASC
+
+ """
+ Created at descending order
+ """
+ CREATED_DESC
+
+ """
Label priority by ascending order
"""
LABEL_PRIORITY_ASC
@@ -10408,24 +11802,34 @@ enum MergeRequestSort {
PRIORITY_DESC
"""
+ Updated at ascending order
+ """
+ UPDATED_ASC
+
+ """
+ Updated at descending order
+ """
+ UPDATED_DESC
+
+ """
Created at ascending order
"""
- created_asc
+ created_asc @deprecated(reason: "Use CREATED_ASC. Deprecated in 13.5")
"""
Created at descending order
"""
- created_desc
+ created_desc @deprecated(reason: "Use CREATED_DESC. Deprecated in 13.5")
"""
Updated at ascending order
"""
- updated_asc
+ updated_asc @deprecated(reason: "Use UPDATED_ASC. Deprecated in 13.5")
"""
Updated at descending order
"""
- updated_desc
+ updated_desc @deprecated(reason: "Use UPDATED_DESC. Deprecated in 13.5")
}
"""
@@ -10783,11 +12187,13 @@ type Mutation {
configureSast(input: ConfigureSastInput!): ConfigureSastPayload
createAlertIssue(input: CreateAlertIssueInput!): CreateAlertIssuePayload
createAnnotation(input: CreateAnnotationInput!): CreateAnnotationPayload
+ createBoard(input: CreateBoardInput!): CreateBoardPayload
createBranch(input: CreateBranchInput!): CreateBranchPayload
createClusterAgent(input: CreateClusterAgentInput!): CreateClusterAgentPayload
createDiffNote(input: CreateDiffNoteInput!): CreateDiffNotePayload
createEpic(input: CreateEpicInput!): CreateEpicPayload
createImageDiffNote(input: CreateImageDiffNoteInput!): CreateImageDiffNotePayload
+ createIssue(input: CreateIssueInput!): CreateIssuePayload
createIteration(input: CreateIterationInput!): CreateIterationPayload
createNote(input: CreateNoteInput!): CreateNotePayload
createRequirement(input: CreateRequirementInput!): CreateRequirementPayload
@@ -10800,11 +12206,13 @@ type Mutation {
dastSiteProfileCreate(input: DastSiteProfileCreateInput!): DastSiteProfileCreatePayload
dastSiteProfileDelete(input: DastSiteProfileDeleteInput!): DastSiteProfileDeletePayload
dastSiteProfileUpdate(input: DastSiteProfileUpdateInput!): DastSiteProfileUpdatePayload
+ dastSiteTokenCreate(input: DastSiteTokenCreateInput!): DastSiteTokenCreatePayload
deleteAnnotation(input: DeleteAnnotationInput!): DeleteAnnotationPayload
designManagementDelete(input: DesignManagementDeleteInput!): DesignManagementDeletePayload
designManagementMove(input: DesignManagementMoveInput!): DesignManagementMovePayload
designManagementUpload(input: DesignManagementUploadInput!): DesignManagementUploadPayload
destroyBoard(input: DestroyBoardInput!): DestroyBoardPayload
+ destroyBoardList(input: DestroyBoardListInput!): DestroyBoardListPayload
destroyNote(input: DestroyNoteInput!): DestroyNotePayload
destroySnippet(input: DestroySnippetInput!): DestroySnippetPayload
@@ -10812,10 +12220,11 @@ type Mutation {
Toggles the resolved state of a discussion
"""
discussionToggleResolve(input: DiscussionToggleResolveInput!): DiscussionToggleResolvePayload
- dismissVulnerability(input: DismissVulnerabilityInput!): DismissVulnerabilityPayload
+ dismissVulnerability(input: DismissVulnerabilityInput!): DismissVulnerabilityPayload @deprecated(reason: "Use vulnerabilityDismiss. Deprecated in 13.5")
epicAddIssue(input: EpicAddIssueInput!): EpicAddIssuePayload
epicSetSubscription(input: EpicSetSubscriptionInput!): EpicSetSubscriptionPayload
epicTreeReorder(input: EpicTreeReorderInput!): EpicTreeReorderPayload
+ issueMove(input: IssueMoveInput!): IssueMovePayload
issueMoveList(input: IssueMoveListInput!): IssueMoveListPayload
issueSetAssignees(input: IssueSetAssigneesInput!): IssueSetAssigneesPayload
issueSetConfidential(input: IssueSetConfidentialInput!): IssueSetConfidentialPayload
@@ -10847,6 +12256,7 @@ type Mutation {
pipelineRetry(input: PipelineRetryInput!): PipelineRetryPayload
removeAwardEmoji(input: RemoveAwardEmojiInput!): RemoveAwardEmojiPayload @deprecated(reason: "Use awardEmojiRemove. Deprecated in 13.2")
removeProjectFromSecurityDashboard(input: RemoveProjectFromSecurityDashboardInput!): RemoveProjectFromSecurityDashboardPayload
+ revertVulnerabilityToDetected(input: RevertVulnerabilityToDetectedInput!): RevertVulnerabilityToDetectedPayload @deprecated(reason: "Use vulnerabilityRevertToDetected. Deprecated in 13.5")
runDastScan(input: RunDASTScanInput!): RunDASTScanPayload @deprecated(reason: "Use DastOnDemandScanCreate. Deprecated in 13.4")
todoMarkDone(input: TodoMarkDoneInput!): TodoMarkDonePayload
todoRestore(input: TodoRestoreInput!): TodoRestorePayload
@@ -10855,6 +12265,7 @@ type Mutation {
toggleAwardEmoji(input: ToggleAwardEmojiInput!): ToggleAwardEmojiPayload @deprecated(reason: "Use awardEmojiToggle. Deprecated in 13.2")
updateAlertStatus(input: UpdateAlertStatusInput!): UpdateAlertStatusPayload
updateBoard(input: UpdateBoardInput!): UpdateBoardPayload
+ updateBoardEpicUserPreferences(input: UpdateBoardEpicUserPreferencesInput!): UpdateBoardEpicUserPreferencesPayload
updateBoardList(input: UpdateBoardListInput!): UpdateBoardListPayload
updateContainerExpirationPolicy(input: UpdateContainerExpirationPolicyInput!): UpdateContainerExpirationPolicyPayload
updateEpic(input: UpdateEpicInput!): UpdateEpicPayload
@@ -10875,7 +12286,10 @@ type Mutation {
updateNote(input: UpdateNoteInput!): UpdateNotePayload
updateRequirement(input: UpdateRequirementInput!): UpdateRequirementPayload
updateSnippet(input: UpdateSnippetInput!): UpdateSnippetPayload
+ vulnerabilityConfirm(input: VulnerabilityConfirmInput!): VulnerabilityConfirmPayload
+ vulnerabilityDismiss(input: VulnerabilityDismissInput!): VulnerabilityDismissPayload
vulnerabilityResolve(input: VulnerabilityResolveInput!): VulnerabilityResolvePayload
+ vulnerabilityRevertToDetected(input: VulnerabilityRevertToDetectedInput!): VulnerabilityRevertToDetectedPayload
}
"""
@@ -10900,6 +12314,21 @@ enum MutationOperationMode {
type Namespace {
"""
+ Size limit for repositories in the namespace in bytes
+ """
+ actualRepositorySizeLimit: Float
+
+ """
+ Additional storage purchased for the root namespace in bytes
+ """
+ additionalPurchasedStorageSize: Float
+
+ """
+ Includes at least one project where the repository size exceeds the limit
+ """
+ containsLockedProjects: Boolean!
+
+ """
Description of the namespace
"""
description: String
@@ -10990,6 +12419,11 @@ type Namespace {
): ProjectConnection!
"""
+ Number of projects in the root namespace where the repository size exceeds the limit
+ """
+ repositorySizeExcessProjectCount: Int!
+
+ """
Indicates if users can request access to namespace
"""
requestAccessEnabled: Boolean
@@ -11010,6 +12444,16 @@ type Namespace {
temporaryStorageIncreaseEndsOn: Time
"""
+ Total repository size of all projects in the root namespace in bytes
+ """
+ totalRepositorySize: Float
+
+ """
+ Total excess repository size of all projects in the root namespace in bytes
+ """
+ totalRepositorySizeExcess: Float
+
+ """
Visibility of the namespace
"""
visibility: String
@@ -11051,6 +12495,11 @@ type NamespaceEdge {
}
"""
+Identifier of Namespace
+"""
+scalar NamespaceID
+
+"""
Autogenerated input type of NamespaceIncreaseStorageTemporarily
"""
input NamespaceIncreaseStorageTemporarilyInput {
@@ -11062,7 +12511,7 @@ input NamespaceIncreaseStorageTemporarilyInput {
"""
The global id of the namespace to mutate
"""
- id: ID!
+ id: NamespaceID!
}
"""
@@ -11259,6 +12708,11 @@ type NoteEdge {
node: Note
}
+"""
+Identifier of Note
+"""
+scalar NoteID
+
type NotePermissions {
"""
Indicates the user can perform `admin_note` on this resource
@@ -11339,6 +12793,11 @@ interface Noteable {
}
"""
+Identifier of Noteable
+"""
+scalar NoteableID
+
+"""
Represents a package
"""
type Package {
@@ -11409,7 +12868,7 @@ type PackageEdge {
}
"""
-Represents the sync and verification state of a package file
+Represents the Geo sync and verification state of a package file
"""
type PackageFileRegistry {
"""
@@ -11490,37 +12949,47 @@ type PackageFileRegistryEdge {
enum PackageTypeEnum {
"""
- Packages from the composer package manager
+ Packages from the Composer package manager
"""
COMPOSER
"""
- Packages from the conan package manager
+ Packages from the Conan package manager
"""
CONAN
"""
- Packages from the generic package manager
+ Packages from the Debian package manager
+ """
+ DEBIAN
+
+ """
+ Packages from the Generic package manager
"""
GENERIC
"""
- Packages from the maven package manager
+ Packages from the Golang package manager
+ """
+ GOLANG
+
+ """
+ Packages from the Maven package manager
"""
MAVEN
"""
- Packages from the npm package manager
+ Packages from the NPM package manager
"""
NPM
"""
- Packages from the nuget package manager
+ Packages from the Nuget package manager
"""
NUGET
"""
- Packages from the pypi package manager
+ Packages from the PyPI package manager
"""
PYPI
}
@@ -11854,10 +13323,20 @@ enum PipelineStatusEnum {
type Project {
"""
+ Size limit for the repository in bytes
+ """
+ actualRepositorySizeLimit: Float
+
+ """
A single Alert Management alert of the project
"""
alertManagementAlert(
"""
+ Username of a user assigned to the issue
+ """
+ assigneeUsername: String
+
+ """
IID of the alert. For example, "1"
"""
iid: String
@@ -11883,6 +13362,11 @@ type Project {
"""
alertManagementAlertStatusCounts(
"""
+ Username of a user assigned to the issue
+ """
+ assigneeUsername: String
+
+ """
Search criteria for filtering alerts. This will search on title, description, service, monitoring_tool.
"""
search: String
@@ -11898,6 +13382,11 @@ type Project {
after: String
"""
+ Username of a user assigned to the issue
+ """
+ assigneeUsername: String
+
+ """
Returns the elements in the list that come before the specified cursor.
"""
before: String
@@ -11959,9 +13448,9 @@ type Project {
"""
board(
"""
- Find a board by its ID
+ The board's ID
"""
- id: ID
+ id: BoardID!
): Board
"""
@@ -12249,6 +13738,16 @@ type Project {
assigneeUsername: String
"""
+ Usernames of users assigned to the issue
+ """
+ assigneeUsernames: [String!]
+
+ """
+ Username of the author of the issue
+ """
+ authorUsername: String
+
+ """
Issues closed after this date
"""
closedAfter: Time
@@ -12339,6 +13838,16 @@ type Project {
assigneeUsername: String
"""
+ Usernames of users assigned to the issue
+ """
+ assigneeUsernames: [String!]
+
+ """
+ Username of the author of the issue
+ """
+ authorUsername: String
+
+ """
Issues closed after this date
"""
closedAfter: Time
@@ -12419,6 +13928,16 @@ type Project {
assigneeUsername: String
"""
+ Usernames of users assigned to the issue
+ """
+ assigneeUsernames: [String!]
+
+ """
+ Username of the author of the issue
+ """
+ authorUsername: String
+
+ """
Returns the elements in the list that come before the specified cursor.
"""
before: String
@@ -12529,8 +14048,8 @@ type Project {
before: String
"""
- List items within a time frame where items.end_date is between startDate and
- endDate parameters (startDate parameter must be present)
+ List items overlapping a time frame defined by startDate..endDate (if one
+ date is provided, both must be present). Deprecated in 13.5: Use timeframe.end
"""
endDate: Time
@@ -12560,8 +14079,9 @@ type Project {
last: Int
"""
- List items within a time frame where items.start_date is between startDate
- and endDate parameters (endDate parameter must be present)
+ List items overlapping a time frame defined by startDate..endDate (if one
+ date is provided, both must be present). Deprecated in 13.5: Use
+ timeframe.start
"""
startDate: Time
@@ -12571,6 +14091,11 @@ type Project {
state: IterationState
"""
+ List items overlapping the given timeframe
+ """
+ timeframe: Timeframe
+
+ """
Fuzzy search by title
"""
title: String
@@ -12778,8 +14303,13 @@ type Project {
before: String
"""
- List items within a time frame where items.end_date is between startDate and
- endDate parameters (startDate parameter must be present)
+ A date that the milestone contains
+ """
+ containingDate: Time
+
+ """
+ List items overlapping a time frame defined by startDate..endDate (if one
+ date is provided, both must be present). Deprecated in 13.5: Use timeframe.end
"""
endDate: Time
@@ -12804,8 +14334,14 @@ type Project {
last: Int
"""
- List items within a time frame where items.start_date is between startDate
- and endDate parameters (endDate parameter must be present)
+ A search string for the title
+ """
+ searchTitle: String
+
+ """
+ List items overlapping a time frame defined by startDate..endDate (if one
+ date is provided, both must be present). Deprecated in 13.5: Use
+ timeframe.start
"""
startDate: Time
@@ -12813,6 +14349,16 @@ type Project {
Filter milestones by state
"""
state: MilestoneStateEnum
+
+ """
+ List items overlapping the given timeframe
+ """
+ timeframe: Timeframe
+
+ """
+ The title of the milestone
+ """
+ title: String
): MilestoneConnection
"""
@@ -13012,12 +14558,17 @@ type Project {
repository: Repository
"""
+ Size of repository that exceeds the limit in bytes
+ """
+ repositorySizeExcess: Float
+
+ """
Indicates if users can request member access to the project
"""
requestAccessEnabled: Boolean
"""
- Find a single requirement. Available only when feature flag `requirements_management` is enabled.
+ Find a single requirement
"""
requirement(
"""
@@ -13057,7 +14608,7 @@ type Project {
requirementStatesCount: RequirementStatesCount
"""
- Find requirements. Available only when feature flag `requirements_management` is enabled.
+ Find requirements
"""
requirements(
"""
@@ -13257,6 +14808,31 @@ type Project {
tagList: String
"""
+ Terraform states associated with the project
+ """
+ terraformStates(
+ """
+ Returns the elements in the list that come after the specified cursor.
+ """
+ after: String
+
+ """
+ Returns the elements in the list that come before the specified cursor.
+ """
+ before: String
+
+ """
+ Returns the first _n_ elements from the list.
+ """
+ first: Int
+
+ """
+ Returns the last _n_ elements from the list.
+ """
+ last: Int
+ ): TerraformStateConnection
+
+ """
Permissions for the current user on the resource
"""
userPermissions: ProjectPermissions!
@@ -13468,6 +15044,11 @@ type ProjectEdge {
}
"""
+Identifier of Project
+"""
+scalar ProjectID
+
+"""
Represents a Project Membership
"""
type ProjectMember implements MemberInterface {
@@ -14001,9 +15582,44 @@ type Query {
Search query for project name, path, or description
"""
search: String
+
+ """
+ Include namespace in project search
+ """
+ searchNamespaces: Boolean
+
+ """
+ Sort order of results
+ """
+ sort: String
): ProjectConnection
"""
+ Supported runner platforms
+ """
+ runnerPlatforms(
+ """
+ Returns the elements in the list that come after the specified cursor.
+ """
+ after: String
+
+ """
+ Returns the elements in the list that come before the specified cursor.
+ """
+ before: String
+
+ """
+ Returns the first _n_ elements from the list.
+ """
+ first: Int
+
+ """
+ Returns the last _n_ elements from the list.
+ """
+ last: Int
+ ): RunnerPlatformConnection
+
+ """
Find Snippets visible to the current user
"""
snippets(
@@ -14249,6 +15865,16 @@ type Query {
"""
startDate: ISO8601Date!
): VulnerabilitiesCountByDayAndSeverityConnection @deprecated(reason: "Use `vulnerabilitiesCountByDay`. Deprecated in 13.3")
+
+ """
+ Find a vulnerability
+ """
+ vulnerability(
+ """
+ The Global ID of the Vulnerability
+ """
+ id: VulnerabilityID!
+ ): Vulnerability
}
"""
@@ -14725,7 +16351,7 @@ input RemoveAwardEmojiInput {
"""
The global id of the awardable resource
"""
- awardableId: ID!
+ awardableId: AwardableID!
"""
A unique identifier for the client performing the mutation.
@@ -14770,7 +16396,7 @@ input RemoveProjectFromSecurityDashboardInput {
"""
ID of the project to remove from the Instance Security Dashboard
"""
- id: ID!
+ id: ProjectID!
}
"""
@@ -14840,6 +16466,16 @@ type Requirement {
createdAt: Time!
"""
+ Description of the requirement
+ """
+ description: String
+
+ """
+ The GitLab Flavored Markdown rendering of `description`
+ """
+ descriptionHtml: String
+
+ """
ID of the requirement
"""
id: ID!
@@ -14850,6 +16486,11 @@ type Requirement {
iid: ID!
"""
+ Indicates if latest test report was created by user
+ """
+ lastTestReportManuallyCreated: Boolean
+
+ """
Latest requirement test report state
"""
lastTestReportState: TestReportState
@@ -14900,6 +16541,11 @@ type Requirement {
title: String
"""
+ The GitLab Flavored Markdown rendering of `title`
+ """
+ titleHtml: String
+
+ """
Timestamp of when the requirement was last updated
"""
updatedAt: Time!
@@ -15020,6 +16666,41 @@ interface ResolvableInterface {
resolvedBy: User
}
+"""
+Autogenerated input type of RevertVulnerabilityToDetected
+"""
+input RevertVulnerabilityToDetectedInput {
+ """
+ A unique identifier for the client performing the mutation.
+ """
+ clientMutationId: String
+
+ """
+ ID of the vulnerability to be reverted
+ """
+ id: VulnerabilityID!
+}
+
+"""
+Autogenerated return type of RevertVulnerabilityToDetected
+"""
+type RevertVulnerabilityToDetectedPayload {
+ """
+ A unique identifier for the client performing the mutation.
+ """
+ clientMutationId: String
+
+ """
+ Errors encountered during execution of the mutation.
+ """
+ errors: [String!]!
+
+ """
+ The vulnerability after revert
+ """
+ vulnerability: Vulnerability
+}
+
type RootStorageStatistics {
"""
The CI artifacts size in bytes
@@ -15037,6 +16718,11 @@ type RootStorageStatistics {
packagesSize: Float!
"""
+ The CI pipeline artifacts size in bytes
+ """
+ pipelineArtifactsSize: Float!
+
+ """
The Git repository size in bytes
"""
repositorySize: Float!
@@ -15107,6 +16793,125 @@ type RunDASTScanPayload {
pipelineUrl: String
}
+type RunnerArchitecture {
+ """
+ Download location for the runner for the platform architecture
+ """
+ downloadLocation: String!
+
+ """
+ Name of the runner platform architecture
+ """
+ name: String!
+}
+
+"""
+The connection type for RunnerArchitecture.
+"""
+type RunnerArchitectureConnection {
+ """
+ A list of edges.
+ """
+ edges: [RunnerArchitectureEdge]
+
+ """
+ A list of nodes.
+ """
+ nodes: [RunnerArchitecture]
+
+ """
+ Information to aid in pagination.
+ """
+ pageInfo: PageInfo!
+}
+
+"""
+An edge in a connection.
+"""
+type RunnerArchitectureEdge {
+ """
+ A cursor for use in pagination.
+ """
+ cursor: String!
+
+ """
+ The item at the end of the edge.
+ """
+ node: RunnerArchitecture
+}
+
+type RunnerPlatform {
+ """
+ Runner architectures supported for the platform
+ """
+ architectures(
+ """
+ Returns the elements in the list that come after the specified cursor.
+ """
+ after: String
+
+ """
+ Returns the elements in the list that come before the specified cursor.
+ """
+ before: String
+
+ """
+ Returns the first _n_ elements from the list.
+ """
+ first: Int
+
+ """
+ Returns the last _n_ elements from the list.
+ """
+ last: Int
+ ): RunnerArchitectureConnection
+
+ """
+ Human readable name of the runner platform
+ """
+ humanReadableName: String!
+
+ """
+ Name slug of the runner platform
+ """
+ name: String!
+}
+
+"""
+The connection type for RunnerPlatform.
+"""
+type RunnerPlatformConnection {
+ """
+ A list of edges.
+ """
+ edges: [RunnerPlatformEdge]
+
+ """
+ A list of nodes.
+ """
+ nodes: [RunnerPlatform]
+
+ """
+ Information to aid in pagination.
+ """
+ pageInfo: PageInfo!
+}
+
+"""
+An edge in a connection.
+"""
+type RunnerPlatformEdge {
+ """
+ A cursor for use in pagination.
+ """
+ cursor: String!
+
+ """
+ The item at the end of the edge.
+ """
+ node: RunnerPlatform
+}
+
"""
Represents a CI configuration of SAST
"""
@@ -15273,6 +17078,26 @@ type SastCiConfigurationAnalyzersEntityEdge {
}
"""
+Represents the analyzers entity in SAST CI configuration
+"""
+input SastCiConfigurationAnalyzersEntityInput {
+ """
+ State of the analyzer
+ """
+ enabled: Boolean!
+
+ """
+ Name of analyzer
+ """
+ name: String!
+
+ """
+ List of variables for the analyzer
+ """
+ variables: [SastCiConfigurationEntityInput!]
+}
+
+"""
Represents an entity in SAST CI configuration
"""
type SastCiConfigurationEntity {
@@ -15397,6 +17222,11 @@ Represents a CI configuration of SAST
"""
input SastCiConfigurationInput {
"""
+ List of analyzers and related variables for the SAST configuration
+ """
+ analyzers: [SastCiConfigurationAnalyzersEntityInput!]
+
+ """
List of global entities related to SAST configuration
"""
global: [SastCiConfigurationEntityInput!]
@@ -15521,6 +17351,11 @@ Represents summary of a security report
"""
type SecurityReportSummary {
"""
+ Aggregated counts for the api_fuzzing scan
+ """
+ apiFuzzing: SecurityReportSummarySection
+
+ """
Aggregated counts for the container_scanning scan
"""
containerScanning: SecurityReportSummarySection
@@ -15600,6 +17435,7 @@ type SecurityReportSummarySection {
The type of the security scanner
"""
enum SecurityScannerType {
+ API_FUZZING
CONTAINER_SCANNING
COVERAGE_FUZZING
DAST
@@ -16183,7 +18019,32 @@ type Snippet implements Noteable {
"""
Snippet blobs
"""
- blobs: [SnippetBlob!]!
+ blobs(
+ """
+ Returns the elements in the list that come after the specified cursor.
+ """
+ after: String
+
+ """
+ Returns the elements in the list that come before the specified cursor.
+ """
+ before: String
+
+ """
+ Returns the first _n_ elements from the list.
+ """
+ first: Int
+
+ """
+ Returns the last _n_ elements from the list.
+ """
+ last: Int
+
+ """
+ Paths of the blobs
+ """
+ paths: [String!]
+ ): SnippetBlobConnection
"""
Timestamp this snippet was created
@@ -16407,6 +18268,41 @@ input SnippetBlobActionInputType {
}
"""
+The connection type for SnippetBlob.
+"""
+type SnippetBlobConnection {
+ """
+ A list of edges.
+ """
+ edges: [SnippetBlobEdge]
+
+ """
+ A list of nodes.
+ """
+ nodes: [SnippetBlob]
+
+ """
+ Information to aid in pagination.
+ """
+ pageInfo: PageInfo!
+}
+
+"""
+An edge in a connection.
+"""
+type SnippetBlobEdge {
+ """
+ A cursor for use in pagination.
+ """
+ cursor: String!
+
+ """
+ The item at the end of the edge.
+ """
+ node: SnippetBlob
+}
+
+"""
Represents how the blob content should be displayed
"""
type SnippetBlobViewer {
@@ -16520,22 +18416,69 @@ enum Sort {
"""
Created at ascending order
"""
- created_asc
+ CREATED_ASC
+
+ """
+ Created at descending order
+ """
+ CREATED_DESC
+
+ """
+ Updated at ascending order
+ """
+ UPDATED_ASC
+
+ """
+ Updated at descending order
+ """
+ UPDATED_DESC
+
+ """
+ Created at ascending order
+ """
+ created_asc @deprecated(reason: "Use CREATED_ASC. Deprecated in 13.5")
"""
Created at descending order
"""
- created_desc
+ created_desc @deprecated(reason: "Use CREATED_DESC. Deprecated in 13.5")
"""
Updated at ascending order
"""
- updated_asc
+ updated_asc @deprecated(reason: "Use UPDATED_ASC. Deprecated in 13.5")
"""
Updated at descending order
"""
- updated_desc
+ updated_desc @deprecated(reason: "Use UPDATED_DESC. Deprecated in 13.5")
+}
+
+type StatusAction {
+ """
+ Title for the button, for example: Retry this job
+ """
+ buttonTitle: String
+
+ """
+ Icon used in the action button
+ """
+ icon: String
+
+ """
+ Method for the action, for example: :post
+ """
+ method: String
+
+ """
+ Path for the action
+ """
+ path: String
+
+ """
+ Title for the action, for example: Retry
+ """
+ title: String
}
type Submodule implements Entry {
@@ -16630,64 +18573,131 @@ type TaskCompletionStatus {
count: Int!
}
+type TerraformState {
+ """
+ Timestamp the Terraform state was created
+ """
+ createdAt: Time!
+
+ """
+ ID of the Terraform state
+ """
+ id: ID!
+
+ """
+ Timestamp the Terraform state was locked
+ """
+ lockedAt: Time
+
+ """
+ The user currently holding a lock on the Terraform state
+ """
+ lockedByUser: User
+
+ """
+ Name of the Terraform state
+ """
+ name: String!
+
+ """
+ Timestamp the Terraform state was updated
+ """
+ updatedAt: Time!
+}
+
+"""
+The connection type for TerraformState.
+"""
+type TerraformStateConnection {
+ """
+ A list of edges.
+ """
+ edges: [TerraformStateEdge]
+
+ """
+ A list of nodes.
+ """
+ nodes: [TerraformState]
+
+ """
+ Information to aid in pagination.
+ """
+ pageInfo: PageInfo!
+}
+
"""
-Represents the sync and verification state of a terraform state
+An edge in a connection.
"""
-type TerraformStateRegistry {
+type TerraformStateEdge {
"""
- Timestamp when the TerraformStateRegistry was created
+ A cursor for use in pagination.
+ """
+ cursor: String!
+
+ """
+ The item at the end of the edge.
+ """
+ node: TerraformState
+}
+
+"""
+Represents the Geo sync and verification state of a terraform state version
+"""
+type TerraformStateVersionRegistry {
+ """
+ Timestamp when the TerraformStateVersionRegistry was created
"""
createdAt: Time
"""
- ID of the TerraformStateRegistry
+ ID of the TerraformStateVersionRegistry
"""
id: ID!
"""
- Error message during sync of the TerraformStateRegistry
+ Error message during sync of the TerraformStateVersionRegistry
"""
lastSyncFailure: String
"""
- Timestamp of the most recent successful sync of the TerraformStateRegistry
+ Timestamp of the most recent successful sync of the TerraformStateVersionRegistry
"""
lastSyncedAt: Time
"""
- Timestamp after which the TerraformStateRegistry should be resynced
+ Timestamp after which the TerraformStateVersionRegistry should be resynced
"""
retryAt: Time
"""
- Number of consecutive failed sync attempts of the TerraformStateRegistry
+ Number of consecutive failed sync attempts of the TerraformStateVersionRegistry
"""
retryCount: Int
"""
- Sync state of the TerraformStateRegistry
+ Sync state of the TerraformStateVersionRegistry
"""
state: RegistryState
"""
- ID of the TerraformState
+ ID of the terraform state version
"""
- terraformStateId: ID!
+ terraformStateVersionId: ID!
}
"""
-The connection type for TerraformStateRegistry.
+The connection type for TerraformStateVersionRegistry.
"""
-type TerraformStateRegistryConnection {
+type TerraformStateVersionRegistryConnection {
"""
A list of edges.
"""
- edges: [TerraformStateRegistryEdge]
+ edges: [TerraformStateVersionRegistryEdge]
"""
A list of nodes.
"""
- nodes: [TerraformStateRegistry]
+ nodes: [TerraformStateVersionRegistry]
"""
Information to aid in pagination.
@@ -16698,7 +18708,7 @@ type TerraformStateRegistryConnection {
"""
An edge in a connection.
"""
-type TerraformStateRegistryEdge {
+type TerraformStateVersionRegistryEdge {
"""
A cursor for use in pagination.
"""
@@ -16707,7 +18717,7 @@ type TerraformStateRegistryEdge {
"""
The item at the end of the edge.
"""
- node: TerraformStateRegistry
+ node: TerraformStateVersionRegistry
}
"""
@@ -16790,6 +18800,21 @@ interface TimeboxBurnupTimeSeriesInterface {
burnupTimeSeries: [BurnupChartDailyTotals!]
}
+"""
+A time-frame defined as a closed inclusive range of two dates
+"""
+input Timeframe {
+ """
+ The end of the range
+ """
+ end: Date!
+
+ """
+ The start of the range
+ """
+ start: Date!
+}
+
type Timelog {
"""
Timestamp of when the time tracked was spent at. Deprecated in 12.10: Use `spentAt`
@@ -16953,6 +18978,11 @@ type TodoEdge {
}
"""
+Identifier of Todo
+"""
+scalar TodoID
+
+"""
Autogenerated input type of TodoMarkDone
"""
input TodoMarkDoneInput {
@@ -16964,7 +18994,7 @@ input TodoMarkDoneInput {
"""
The global id of the todo to mark as done
"""
- id: ID!
+ id: TodoID!
}
"""
@@ -16999,7 +19029,7 @@ input TodoRestoreInput {
"""
The global id of the todo to restore
"""
- id: ID!
+ id: TodoID!
}
"""
@@ -17014,7 +19044,7 @@ input TodoRestoreManyInput {
"""
The global ids of the todos to restore (a maximum of 50 is supported at once)
"""
- ids: [ID!]!
+ ids: [TodoID!]!
}
"""
@@ -17141,7 +19171,7 @@ input ToggleAwardEmojiInput {
"""
The global id of the awardable resource
"""
- awardableId: ID!
+ awardableId: AwardableID!
"""
A unique identifier for the client performing the mutation.
@@ -17407,13 +19437,58 @@ type UpdateAlertStatusPayload {
}
"""
+Autogenerated input type of UpdateBoardEpicUserPreferences
+"""
+input UpdateBoardEpicUserPreferencesInput {
+ """
+ The board global ID
+ """
+ boardId: BoardID!
+
+ """
+ A unique identifier for the client performing the mutation.
+ """
+ clientMutationId: String
+
+ """
+ Whether the epic should be collapsed in the board
+ """
+ collapsed: Boolean!
+
+ """
+ ID of an epic to set preferences for
+ """
+ epicId: EpicID!
+}
+
+"""
+Autogenerated return type of UpdateBoardEpicUserPreferences
+"""
+type UpdateBoardEpicUserPreferencesPayload {
+ """
+ A unique identifier for the client performing the mutation.
+ """
+ clientMutationId: String
+
+ """
+ User preferences for the epic in the board after mutation
+ """
+ epicUserPreferences: BoardEpicUserPreferences
+
+ """
+ Errors encountered during execution of the mutation.
+ """
+ errors: [String!]!
+}
+
+"""
Autogenerated input type of UpdateBoard
"""
input UpdateBoardInput {
"""
The id of user to be assigned to the board.
"""
- assigneeId: ID
+ assigneeId: UserID
"""
A unique identifier for the client performing the mutation.
@@ -17433,12 +19508,22 @@ input UpdateBoardInput {
"""
The board global id.
"""
- id: ID!
+ id: BoardID!
+
+ """
+ The IDs of labels to be added to the board.
+ """
+ labelIds: [LabelID!]
+
+ """
+ Labels of the issue
+ """
+ labels: [String!]
"""
The id of milestone to be assigned to the board.
"""
- milestoneId: ID
+ milestoneId: MilestoneID
"""
Name of the board
@@ -17710,7 +19795,7 @@ input UpdateImageDiffNoteInput {
"""
The global id of the note to update
"""
- id: ID!
+ id: NoteID!
"""
The position of this note on a diff
@@ -17743,7 +19828,7 @@ Autogenerated input type of UpdateIssue
"""
input UpdateIssueInput {
"""
- The IDs of labels to be added to the issue.
+ The IDs of labels to be added to the issue
"""
addLabelIds: [ID!]
@@ -17765,7 +19850,7 @@ input UpdateIssueInput {
"""
Due date of the issue
"""
- dueDate: Time
+ dueDate: ISO8601Date
"""
The ID of the parent epic. NULL when removing the association
@@ -17788,7 +19873,7 @@ input UpdateIssueInput {
locked: Boolean
"""
- The ID of the milestone to be assigned, milestone will be removed if set to null.
+ The ID of the milestone to assign to the issue. On update milestone will be removed if set to null
"""
milestoneId: ID
@@ -17798,14 +19883,24 @@ input UpdateIssueInput {
projectPath: ID!
"""
- The IDs of labels to be removed from the issue.
+ The IDs of labels to be removed from the issue
"""
removeLabelIds: [ID!]
"""
+ Close or reopen an issue
+ """
+ stateEvent: IssueStateEvent
+
+ """
Title of the issue
"""
title: String
+
+ """
+ The weight of the issue
+ """
+ weight: Int
}
"""
@@ -17910,7 +20005,7 @@ input UpdateNoteInput {
"""
The global id of the note to update
"""
- id: ID!
+ id: NoteID!
}
"""
@@ -17943,6 +20038,11 @@ input UpdateRequirementInput {
clientMutationId: String
"""
+ Description of the requirement
+ """
+ description: String
+
+ """
The iid of the requirement to update
"""
iid: String!
@@ -17953,7 +20053,7 @@ input UpdateRequirementInput {
lastTestReportState: TestReportState
"""
- The project full path the requirement is associated with
+ Full project path the requirement is associated with
"""
projectPath: ID!
@@ -17983,7 +20083,7 @@ type UpdateRequirementPayload {
errors: [String!]!
"""
- The requirement after mutation
+ Requirement after mutation
"""
requirement: Requirement
}
@@ -18041,6 +20141,11 @@ type UpdateSnippetPayload {
The snippet after mutation
"""
snippet: Snippet
+
+ """
+ Indicates whether the operation returns a record detected as spam
+ """
+ spam: Boolean
}
scalar Upload
@@ -18056,6 +20161,11 @@ type User {
after: String
"""
+ Username of the author
+ """
+ authorUsername: String
+
+ """
Returns the elements in the list that come before the specified cursor.
"""
before: String
@@ -18136,6 +20246,11 @@ type User {
after: String
"""
+ Username of the assignee
+ """
+ assigneeUsername: String
+
+ """
Returns the elements in the list that come before the specified cursor.
"""
before: String
@@ -18666,7 +20781,7 @@ type VulnerabilitiesCountByDayEdge {
"""
Represents a vulnerability
"""
-type Vulnerability {
+type Vulnerability implements Noteable {
"""
Description of the vulnerability
"""
@@ -18678,6 +20793,31 @@ type Vulnerability {
detectedAt: Time!
"""
+ All discussions on this noteable
+ """
+ discussions(
+ """
+ Returns the elements in the list that come after the specified cursor.
+ """
+ after: String
+
+ """
+ Returns the elements in the list that come before the specified cursor.
+ """
+ before: String
+
+ """
+ Returns the first _n_ elements from the list.
+ """
+ first: Int
+
+ """
+ Returns the last _n_ elements from the list.
+ """
+ last: Int
+ ): DiscussionConnection!
+
+ """
GraphQL ID of the vulnerability
"""
id: ID!
@@ -18723,6 +20863,31 @@ type Vulnerability {
location: VulnerabilityLocation
"""
+ All notes on this noteable
+ """
+ notes(
+ """
+ Returns the elements in the list that come after the specified cursor.
+ """
+ after: String
+
+ """
+ Returns the elements in the list that come before the specified cursor.
+ """
+ before: String
+
+ """
+ Returns the first _n_ elements from the list.
+ """
+ first: Int
+
+ """
+ Returns the last _n_ elements from the list.
+ """
+ last: Int
+ ): NoteConnection!
+
+ """
Primary identifier of the vulnerability.
"""
primaryIdentifier: VulnerabilityIdentifier
@@ -18735,7 +20900,7 @@ type Vulnerability {
"""
Type of the security report that found the vulnerability (SAST,
DEPENDENCY_SCANNING, CONTAINER_SCANNING, DAST, SECRET_DETECTION,
- COVERAGE_FUZZING)
+ COVERAGE_FUZZING, API_FUZZING)
"""
reportType: VulnerabilityReportType
@@ -18755,7 +20920,7 @@ type Vulnerability {
severity: VulnerabilitySeverity
"""
- State of the vulnerability (DETECTED, DISMISSED, RESOLVED, CONFIRMED)
+ State of the vulnerability (DETECTED, CONFIRMED, RESOLVED, DISMISSED)
"""
state: VulnerabilityState
@@ -18781,6 +20946,41 @@ type Vulnerability {
}
"""
+Autogenerated input type of VulnerabilityConfirm
+"""
+input VulnerabilityConfirmInput {
+ """
+ A unique identifier for the client performing the mutation.
+ """
+ clientMutationId: String
+
+ """
+ ID of the vulnerability to be confirmed
+ """
+ id: VulnerabilityID!
+}
+
+"""
+Autogenerated return type of VulnerabilityConfirm
+"""
+type VulnerabilityConfirmPayload {
+ """
+ A unique identifier for the client performing the mutation.
+ """
+ clientMutationId: String
+
+ """
+ Errors encountered during execution of the mutation.
+ """
+ errors: [String!]!
+
+ """
+ The vulnerability after state change
+ """
+ vulnerability: Vulnerability
+}
+
+"""
The connection type for Vulnerability.
"""
type VulnerabilityConnection {
@@ -18801,6 +21001,46 @@ type VulnerabilityConnection {
}
"""
+Autogenerated input type of VulnerabilityDismiss
+"""
+input VulnerabilityDismissInput {
+ """
+ A unique identifier for the client performing the mutation.
+ """
+ clientMutationId: String
+
+ """
+ Reason why vulnerability should be dismissed
+ """
+ comment: String
+
+ """
+ ID of the vulnerability to be dismissed
+ """
+ id: VulnerabilityID!
+}
+
+"""
+Autogenerated return type of VulnerabilityDismiss
+"""
+type VulnerabilityDismissPayload {
+ """
+ A unique identifier for the client performing the mutation.
+ """
+ clientMutationId: String
+
+ """
+ Errors encountered during execution of the mutation.
+ """
+ errors: [String!]!
+
+ """
+ The vulnerability after dismissal
+ """
+ vulnerability: Vulnerability
+}
+
+"""
An edge in a connection.
"""
type VulnerabilityEdge {
@@ -19123,6 +21363,7 @@ type VulnerabilityPermissions {
The type of the security scan that found the vulnerability
"""
enum VulnerabilityReportType {
+ API_FUZZING
CONTAINER_SCANNING
COVERAGE_FUZZING
DAST
@@ -19141,7 +21382,7 @@ input VulnerabilityResolveInput {
clientMutationId: String
"""
- ID of the vulnerability to be resolveed
+ ID of the vulnerability to be resolved
"""
id: VulnerabilityID!
}
@@ -19167,6 +21408,41 @@ type VulnerabilityResolvePayload {
}
"""
+Autogenerated input type of VulnerabilityRevertToDetected
+"""
+input VulnerabilityRevertToDetectedInput {
+ """
+ A unique identifier for the client performing the mutation.
+ """
+ clientMutationId: String
+
+ """
+ ID of the vulnerability to be reverted
+ """
+ id: VulnerabilityID!
+}
+
+"""
+Autogenerated return type of VulnerabilityRevertToDetected
+"""
+type VulnerabilityRevertToDetectedPayload {
+ """
+ A unique identifier for the client performing the mutation.
+ """
+ clientMutationId: String
+
+ """
+ Errors encountered during execution of the mutation.
+ """
+ errors: [String!]!
+
+ """
+ The vulnerability after revert
+ """
+ vulnerability: Vulnerability
+}
+
+"""
Represents a vulnerability scanner
"""
type VulnerabilityScanner {
@@ -19278,6 +21554,26 @@ Vulnerability sort values
"""
enum VulnerabilitySort {
"""
+ Detection timestamp in ascending order
+ """
+ detected_asc
+
+ """
+ Detection timestamp in descending order
+ """
+ detected_desc
+
+ """
+ Report Type in ascending order
+ """
+ report_type_asc
+
+ """
+ Report Type in descending order
+ """
+ report_type_desc
+
+ """
Severity in ascending order
"""
severity_asc
@@ -19286,6 +21582,26 @@ enum VulnerabilitySort {
Severity in descending order
"""
severity_desc
+
+ """
+ State in ascending order
+ """
+ state_asc
+
+ """
+ State in descending order
+ """
+ state_desc
+
+ """
+ Title in ascending order
+ """
+ title_asc
+
+ """
+ Title in descending order
+ """
+ title_desc
}
"""
diff --git a/doc/api/graphql/reference/gitlab_schema.json b/doc/api/graphql/reference/gitlab_schema.json
index 173415ca164..6914ba29c57 100644
--- a/doc/api/graphql/reference/gitlab_schema.json
+++ b/doc/api/graphql/reference/gitlab_schema.json
@@ -111,7 +111,7 @@
"name": null,
"ofType": {
"kind": "SCALAR",
- "name": "ID",
+ "name": "AwardableID",
"ofType": null
}
},
@@ -227,7 +227,7 @@
"name": null,
"ofType": {
"kind": "SCALAR",
- "name": "ID",
+ "name": "ProjectID",
"ofType": null
}
},
@@ -382,6 +382,16 @@
"defaultValue": null
},
{
+ "name": "featureCategory",
+ "description": "Delete jobs matching feature_category in the context metadata",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
"name": "queueName",
"description": "The name of the queue to delete jobs from",
"type": {
@@ -667,6 +677,20 @@
"deprecationReason": null
},
{
+ "name": "environment",
+ "description": "Environment for the alert",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "Environment",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
"name": "eventCount",
"description": "Number of events of this alert",
"args": [
@@ -1227,23 +1251,47 @@
{
"name": "updated_desc",
"description": "Updated at descending order",
+ "isDeprecated": true,
+ "deprecationReason": "Use UPDATED_DESC. Deprecated in 13.5"
+ },
+ {
+ "name": "updated_asc",
+ "description": "Updated at ascending order",
+ "isDeprecated": true,
+ "deprecationReason": "Use UPDATED_ASC. Deprecated in 13.5"
+ },
+ {
+ "name": "created_desc",
+ "description": "Created at descending order",
+ "isDeprecated": true,
+ "deprecationReason": "Use CREATED_DESC. Deprecated in 13.5"
+ },
+ {
+ "name": "created_asc",
+ "description": "Created at ascending order",
+ "isDeprecated": true,
+ "deprecationReason": "Use CREATED_ASC. Deprecated in 13.5"
+ },
+ {
+ "name": "UPDATED_DESC",
+ "description": "Updated at descending order",
"isDeprecated": false,
"deprecationReason": null
},
{
- "name": "updated_asc",
+ "name": "UPDATED_ASC",
"description": "Updated at ascending order",
"isDeprecated": false,
"deprecationReason": null
},
{
- "name": "created_desc",
+ "name": "CREATED_DESC",
"description": "Created at descending order",
"isDeprecated": false,
"deprecationReason": null
},
{
- "name": "created_asc",
+ "name": "CREATED_ASC",
"description": "Created at ascending order",
"isDeprecated": false,
"deprecationReason": null
@@ -1969,7 +2017,7 @@
"name": null,
"ofType": {
"kind": "SCALAR",
- "name": "ID",
+ "name": "AwardableID",
"ofType": null
}
},
@@ -2085,7 +2133,7 @@
"name": null,
"ofType": {
"kind": "SCALAR",
- "name": "ID",
+ "name": "AwardableID",
"ofType": null
}
},
@@ -2201,7 +2249,7 @@
"name": null,
"ofType": {
"kind": "SCALAR",
- "name": "ID",
+ "name": "AwardableID",
"ofType": null
}
},
@@ -2322,6 +2370,16 @@
"possibleTypes": null
},
{
+ "kind": "SCALAR",
+ "name": "AwardableID",
+ "description": "Identifier of Awardable",
+ "fields": null,
+ "inputFields": null,
+ "interfaces": null,
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
"kind": "OBJECT",
"name": "BaseService",
"description": null,
@@ -2764,7 +2822,7 @@
],
"type": {
"kind": "OBJECT",
- "name": "EpicConnection",
+ "name": "BoardEpicConnection",
"ofType": null
},
"isDeprecated": false,
@@ -2817,6 +2875,59 @@
"deprecationReason": null
},
{
+ "name": "labels",
+ "description": "Labels of the board",
+ "args": [
+ {
+ "name": "after",
+ "description": "Returns the elements in the list that come after the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "before",
+ "description": "Returns the elements in the list that come before the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "first",
+ "description": "Returns the first _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "last",
+ "description": "Returns the last _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "LabelConnection",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
"name": "lists",
"description": "Lists of the board",
"args": [
@@ -2831,6 +2942,16 @@
"defaultValue": null
},
{
+ "name": "issueFilters",
+ "description": "Filters applied when getting issue metadata in the board list",
+ "type": {
+ "kind": "INPUT_OBJECT",
+ "name": "BoardIssueInput",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
"name": "after",
"description": "Returns the elements in the list that come after the specified cursor.",
"type": {
@@ -3042,6 +3163,1273 @@
"possibleTypes": null
},
{
+ "kind": "OBJECT",
+ "name": "BoardEpic",
+ "description": "Represents an epic on an issue board",
+ "fields": [
+ {
+ "name": "author",
+ "description": "Author of the epic",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "User",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "children",
+ "description": "Children (sub-epics) of the epic",
+ "args": [
+ {
+ "name": "startDate",
+ "description": "List items overlapping a time frame defined by startDate..endDate (if one date is provided, both must be present). Deprecated in 13.5: Use timeframe.start",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "endDate",
+ "description": "List items overlapping a time frame defined by startDate..endDate (if one date is provided, both must be present). Deprecated in 13.5: Use timeframe.end",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "timeframe",
+ "description": "List items overlapping the given timeframe",
+ "type": {
+ "kind": "INPUT_OBJECT",
+ "name": "Timeframe",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "iid",
+ "description": "IID of the epic, e.g., \"1\"",
+ "type": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "iids",
+ "description": "List of IIDs of epics, e.g., [1, 2]",
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "state",
+ "description": "Filter epics by state",
+ "type": {
+ "kind": "ENUM",
+ "name": "EpicState",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "search",
+ "description": "Search query for epic title or description",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "sort",
+ "description": "List epics by sort order",
+ "type": {
+ "kind": "ENUM",
+ "name": "EpicSort",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "authorUsername",
+ "description": "Filter epics by author",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "labelName",
+ "description": "Filter epics by labels",
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "milestoneTitle",
+ "description": "Filter epics by milestone title, computed from epic's issues",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "iidStartsWith",
+ "description": "Filter epics by iid for autocomplete",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "after",
+ "description": "Returns the elements in the list that come after the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "before",
+ "description": "Returns the elements in the list that come before the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "first",
+ "description": "Returns the first _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "last",
+ "description": "Returns the last _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "EpicConnection",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "closedAt",
+ "description": "Timestamp of when the epic was closed",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "confidential",
+ "description": "Indicates if the epic is confidential",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "createdAt",
+ "description": "Timestamp of when the epic was created",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "currentUserTodos",
+ "description": "Todos for the current user",
+ "args": [
+ {
+ "name": "after",
+ "description": "Returns the elements in the list that come after the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "before",
+ "description": "Returns the elements in the list that come before the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "first",
+ "description": "Returns the first _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "last",
+ "description": "Returns the last _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "state",
+ "description": "State of the todos",
+ "type": {
+ "kind": "ENUM",
+ "name": "TodoStateEnum",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "TodoConnection",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "descendantCounts",
+ "description": "Number of open and closed descendant epics and issues",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "EpicDescendantCount",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "descendantWeightSum",
+ "description": "Total weight of open and closed issues in the epic and its descendants",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "EpicDescendantWeights",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "description",
+ "description": "Description of the epic",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "discussions",
+ "description": "All discussions on this noteable",
+ "args": [
+ {
+ "name": "after",
+ "description": "Returns the elements in the list that come after the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "before",
+ "description": "Returns the elements in the list that come before the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "first",
+ "description": "Returns the first _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "last",
+ "description": "Returns the last _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "DiscussionConnection",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "downvotes",
+ "description": "Number of downvotes the epic has received",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "dueDate",
+ "description": "Due date of the epic",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "dueDateFixed",
+ "description": "Fixed due date of the epic",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "dueDateFromMilestones",
+ "description": "Inherited due date of the epic from milestones",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "dueDateIsFixed",
+ "description": "Indicates if the due date has been manually set",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "group",
+ "description": "Group to which the epic belongs",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "Group",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "hasChildren",
+ "description": "Indicates if the epic has children",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "hasIssues",
+ "description": "Indicates if the epic has direct issues",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "hasParent",
+ "description": "Indicates if the epic has a parent epic",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "healthStatus",
+ "description": "Current health status of the epic",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "EpicHealthStatus",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "id",
+ "description": "ID of the epic",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "iid",
+ "description": "Internal ID of the epic",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "issues",
+ "description": "A list of issues associated with the epic",
+ "args": [
+ {
+ "name": "after",
+ "description": "Returns the elements in the list that come after the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "before",
+ "description": "Returns the elements in the list that come before the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "first",
+ "description": "Returns the first _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "last",
+ "description": "Returns the last _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "EpicIssueConnection",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "labels",
+ "description": "Labels assigned to the epic",
+ "args": [
+ {
+ "name": "after",
+ "description": "Returns the elements in the list that come after the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "before",
+ "description": "Returns the elements in the list that come before the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "first",
+ "description": "Returns the first _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "last",
+ "description": "Returns the last _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "LabelConnection",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "notes",
+ "description": "All notes on this noteable",
+ "args": [
+ {
+ "name": "after",
+ "description": "Returns the elements in the list that come after the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "before",
+ "description": "Returns the elements in the list that come before the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "first",
+ "description": "Returns the first _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "last",
+ "description": "Returns the last _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "NoteConnection",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "parent",
+ "description": "Parent epic of the epic",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "Epic",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "participants",
+ "description": "List of participants for the epic",
+ "args": [
+ {
+ "name": "after",
+ "description": "Returns the elements in the list that come after the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "before",
+ "description": "Returns the elements in the list that come before the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "first",
+ "description": "Returns the first _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "last",
+ "description": "Returns the last _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "UserConnection",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "reference",
+ "description": "Internal reference of the epic. Returned in shortened format by default",
+ "args": [
+ {
+ "name": "full",
+ "description": "Indicates if the reference should be returned in full",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ },
+ "defaultValue": "false"
+ }
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "relationPath",
+ "description": "URI path of the epic-issue relationship",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "relativePosition",
+ "description": "The relative position of the epic in the epic tree",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "startDate",
+ "description": "Start date of the epic",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "startDateFixed",
+ "description": "Fixed start date of the epic",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "startDateFromMilestones",
+ "description": "Inherited start date of the epic from milestones",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "startDateIsFixed",
+ "description": "Indicates if the start date has been manually set",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "state",
+ "description": "State of the epic",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "ENUM",
+ "name": "EpicState",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "subscribed",
+ "description": "Indicates the currently logged in user is subscribed to the epic",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "title",
+ "description": "Title of the epic",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "updatedAt",
+ "description": "Timestamp of when the epic was updated",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "upvotes",
+ "description": "Number of upvotes the epic has received",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "userPermissions",
+ "description": "Permissions for the current user on the resource",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "EpicPermissions",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "userPreferences",
+ "description": "User preferences for the epic on the issue board",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "BoardEpicUserPreferences",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "webPath",
+ "description": "Web path of the epic",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "webUrl",
+ "description": "Web URL of the epic",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+ {
+ "kind": "INTERFACE",
+ "name": "Noteable",
+ "ofType": null
+ },
+ {
+ "kind": "INTERFACE",
+ "name": "CurrentUserTodos",
+ "ofType": null
+ }
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "BoardEpicConnection",
+ "description": "The connection type for BoardEpic.",
+ "fields": [
+ {
+ "name": "edges",
+ "description": "A list of edges.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "BoardEpicEdge",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "nodes",
+ "description": "A list of nodes.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "BoardEpic",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "pageInfo",
+ "description": "Information to aid in pagination.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "PageInfo",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "BoardEpicEdge",
+ "description": "An edge in a connection.",
+ "fields": [
+ {
+ "name": "cursor",
+ "description": "A cursor for use in pagination.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "node",
+ "description": "The item at the end of the edge.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "BoardEpic",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "BoardEpicUserPreferences",
+ "description": "Represents user preferences for a board epic",
+ "fields": [
+ {
+ "name": "collapsed",
+ "description": "Indicates epic should be displayed as collapsed",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
"kind": "SCALAR",
"name": "BoardID",
"description": "Identifier of Board",
@@ -3718,7 +5106,7 @@
"name": null,
"ofType": {
"kind": "SCALAR",
- "name": "ID",
+ "name": "ListID",
"ofType": null
}
},
@@ -4000,6 +5388,20 @@
"description": null,
"fields": [
{
+ "name": "detailedStatus",
+ "description": "Detailed status of the group",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "DetailedStatus",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
"name": "jobs",
"description": "Jobs in group",
"args": [
@@ -4206,6 +5608,20 @@
"description": null,
"fields": [
{
+ "name": "detailedStatus",
+ "description": "Detailed status of the job",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "DetailedStatus",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
"name": "name",
"description": "Name of the job",
"args": [
@@ -4271,6 +5687,20 @@
},
"isDeprecated": false,
"deprecationReason": null
+ },
+ {
+ "name": "scheduledAt",
+ "description": "Schedule for the build",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
}
],
"inputFields": null,
@@ -4408,6 +5838,20 @@
"description": null,
"fields": [
{
+ "name": "detailedStatus",
+ "description": "Detailed status of the stage",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "DetailedStatus",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
"name": "groups",
"description": "Group of jobs for the stage",
"args": [
@@ -5330,6 +6774,16 @@
"possibleTypes": null
},
{
+ "kind": "SCALAR",
+ "name": "ClustersClusterID",
+ "description": "Identifier of Clusters::Cluster",
+ "fields": null,
+ "inputFields": null,
+ "interfaces": null,
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
"kind": "OBJECT",
"name": "Commit",
"description": null,
@@ -6695,7 +8149,7 @@
"description": "The global id of the environment to add an annotation to",
"type": {
"kind": "SCALAR",
- "name": "ID",
+ "name": "EnvironmentID",
"ofType": null
},
"defaultValue": null
@@ -6705,7 +8159,7 @@
"description": "The global id of the cluster to add an annotation to",
"type": {
"kind": "SCALAR",
- "name": "ID",
+ "name": "ClustersClusterID",
"ofType": null
},
"defaultValue": null
@@ -6846,6 +8300,172 @@
},
{
"kind": "INPUT_OBJECT",
+ "name": "CreateBoardInput",
+ "description": "Autogenerated input type of CreateBoard",
+ "fields": null,
+ "inputFields": [
+ {
+ "name": "projectPath",
+ "description": "The project full path the board is associated with.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "groupPath",
+ "description": "The group full path the board is associated with.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "name",
+ "description": "The board name.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "assigneeId",
+ "description": "The ID of the user to be assigned to the board.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "milestoneId",
+ "description": "The ID of the milestone to be assigned to the board.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "weight",
+ "description": "The weight of the board.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "labelIds",
+ "description": "The IDs of labels to be added to the board.",
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "clientMutationId",
+ "description": "A unique identifier for the client performing the mutation.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "interfaces": null,
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "CreateBoardPayload",
+ "description": "Autogenerated return type of CreateBoard",
+ "fields": [
+ {
+ "name": "board",
+ "description": "The board after mutation.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "Board",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "clientMutationId",
+ "description": "A unique identifier for the client performing the mutation.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "errors",
+ "description": "Errors encountered during execution of the mutation.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ }
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "INPUT_OBJECT",
"name": "CreateBranchInput",
"description": "Autogenerated input type of CreateBranch",
"fields": null,
@@ -7104,7 +8724,7 @@
"name": null,
"ofType": {
"kind": "SCALAR",
- "name": "ID",
+ "name": "NoteableID",
"ofType": null
}
},
@@ -7452,7 +9072,7 @@
"name": null,
"ofType": {
"kind": "SCALAR",
- "name": "ID",
+ "name": "NoteableID",
"ofType": null
}
},
@@ -7580,6 +9200,296 @@
},
{
"kind": "INPUT_OBJECT",
+ "name": "CreateIssueInput",
+ "description": "Autogenerated input type of CreateIssue",
+ "fields": null,
+ "inputFields": [
+ {
+ "name": "description",
+ "description": "Description of the issue",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "dueDate",
+ "description": "Due date of the issue",
+ "type": {
+ "kind": "SCALAR",
+ "name": "ISO8601Date",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "confidential",
+ "description": "Indicates the issue is confidential",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "locked",
+ "description": "Indicates discussion is locked on the issue",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "projectPath",
+ "description": "Project full path the issue is associated with",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "iid",
+ "description": "The IID (internal ID) of a project issue. Only admins and project owners can modify",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "title",
+ "description": "Title of the issue",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "milestoneId",
+ "description": "The ID of the milestone to assign to the issue. On update milestone will be removed if set to null",
+ "type": {
+ "kind": "SCALAR",
+ "name": "MilestoneID",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "labels",
+ "description": "Labels of the issue",
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "labelIds",
+ "description": "The IDs of labels to be added to the issue",
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "LabelID",
+ "ofType": null
+ }
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "createdAt",
+ "description": "Timestamp when the issue was created. Available only for admins and project owners",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "mergeRequestToResolveDiscussionsOf",
+ "description": "The IID of a merge request for which to resolve discussions",
+ "type": {
+ "kind": "SCALAR",
+ "name": "MergeRequestID",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "discussionToResolve",
+ "description": "The ID of a discussion to resolve. Also pass `merge_request_to_resolve_discussions_of`",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "assigneeIds",
+ "description": "The array of user IDs to assign to the issue",
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "UserID",
+ "ofType": null
+ }
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "healthStatus",
+ "description": "The desired health status",
+ "type": {
+ "kind": "ENUM",
+ "name": "HealthStatus",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "weight",
+ "description": "The weight of the issue",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "epicId",
+ "description": "The ID of an epic to associate the issue with",
+ "type": {
+ "kind": "SCALAR",
+ "name": "EpicID",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "clientMutationId",
+ "description": "A unique identifier for the client performing the mutation.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "interfaces": null,
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "CreateIssuePayload",
+ "description": "Autogenerated return type of CreateIssue",
+ "fields": [
+ {
+ "name": "clientMutationId",
+ "description": "A unique identifier for the client performing the mutation.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "errors",
+ "description": "Errors encountered during execution of the mutation.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ }
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "issue",
+ "description": "The issue after mutation",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "Issue",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "INPUT_OBJECT",
"name": "CreateIterationInput",
"description": "Autogenerated input type of CreateIteration",
"fields": null,
@@ -7740,7 +9650,7 @@
"name": null,
"ofType": {
"kind": "SCALAR",
- "name": "ID",
+ "name": "NoteableID",
"ofType": null
}
},
@@ -7775,7 +9685,7 @@
"description": "The global id of the discussion this note is in reply to",
"type": {
"kind": "SCALAR",
- "name": "ID",
+ "name": "DiscussionID",
"ofType": null
},
"defaultValue": null
@@ -7872,19 +9782,25 @@
"name": "title",
"description": "Title of the requirement",
"type": {
- "kind": "NON_NULL",
- "name": null,
- "ofType": {
- "kind": "SCALAR",
- "name": "String",
- "ofType": null
- }
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "description",
+ "description": "Description of the requirement",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
},
"defaultValue": null
},
{
"name": "projectPath",
- "description": "The project full path the requirement is associated with",
+ "description": "Full project path the requirement is associated with",
"type": {
"kind": "NON_NULL",
"name": null,
@@ -7958,7 +9874,7 @@
},
{
"name": "requirement",
- "description": "The requirement after mutation",
+ "description": "Requirement after mutation",
"args": [
],
@@ -8141,6 +10057,20 @@
},
"isDeprecated": false,
"deprecationReason": null
+ },
+ {
+ "name": "spam",
+ "description": "Indicates whether the operation returns a record detected as spam",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
}
],
"inputFields": null,
@@ -8373,6 +10303,11 @@
"possibleTypes": [
{
"kind": "OBJECT",
+ "name": "BoardEpic",
+ "ofType": null
+ },
+ {
+ "kind": "OBJECT",
"name": "Design",
"ofType": null
},
@@ -8537,6 +10472,12 @@
"description": "Passive DAST scan. This scan will not make active attacks against the target site.",
"isDeprecated": false,
"deprecationReason": null
+ },
+ {
+ "name": "ACTIVE",
+ "description": "Active DAST scan. This scan will make active attacks against the target site.",
+ "isDeprecated": false,
+ "deprecationReason": null
}
],
"possibleTypes": null
@@ -8611,6 +10552,38 @@
"deprecationReason": null
},
{
+ "name": "scanType",
+ "description": "Indicates the type of DAST scan that will run. Either a Passive Scan or an Active Scan.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "ENUM",
+ "name": "DastScanTypeEnum",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "showDebugMessages",
+ "description": "Indicates if debug messages should be included in DAST console output. True to include the debug messages.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
"name": "spiderTimeout",
"description": "The maximum number of minutes allowed for the spider to traverse the site",
"args": [
@@ -8637,6 +10610,24 @@
},
"isDeprecated": false,
"deprecationReason": null
+ },
+ {
+ "name": "useAjaxSpider",
+ "description": "Indicates if the AJAX spider should be used to crawl the target site. True to run the AJAX spider in addition to the traditional spider, and false to run only the traditional spider.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
}
],
"inputFields": null,
@@ -8768,6 +10759,36 @@
"defaultValue": null
},
{
+ "name": "scanType",
+ "description": "Indicates the type of DAST scan that will run. Either a Passive Scan or an Active Scan.",
+ "type": {
+ "kind": "ENUM",
+ "name": "DastScanTypeEnum",
+ "ofType": null
+ },
+ "defaultValue": "PASSIVE"
+ },
+ {
+ "name": "useAjaxSpider",
+ "description": "Indicates if the AJAX spider should be used to crawl the target site. True to run the AJAX spider in addition to the traditional spider, and false to run only the traditional spider.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ },
+ "defaultValue": "false"
+ },
+ {
+ "name": "showDebugMessages",
+ "description": "Indicates if debug messages should be included in DAST console output. True to include the debug messages.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ },
+ "defaultValue": "false"
+ },
+ {
"name": "clientMutationId",
"description": "A unique identifier for the client performing the mutation.",
"type": {
@@ -9097,6 +11118,36 @@
"defaultValue": null
},
{
+ "name": "scanType",
+ "description": "Indicates the type of DAST scan that will run. Either a Passive Scan or an Active Scan.",
+ "type": {
+ "kind": "ENUM",
+ "name": "DastScanTypeEnum",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "useAjaxSpider",
+ "description": "Indicates if the AJAX spider should be used to crawl the target site. True to run the AJAX spider in addition to the traditional spider, and false to run only the traditional spider.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "showDebugMessages",
+ "description": "Indicates if debug messages should be included in DAST console output. True to include the debug messages.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
"name": "clientMutationId",
"description": "A unique identifier for the client performing the mutation.",
"type": {
@@ -9841,6 +11892,166 @@
},
{
"kind": "INPUT_OBJECT",
+ "name": "DastSiteTokenCreateInput",
+ "description": "Autogenerated input type of DastSiteTokenCreate",
+ "fields": null,
+ "inputFields": [
+ {
+ "name": "fullPath",
+ "description": "The project the site token belongs to.",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "targetUrl",
+ "description": "The URL of the target to be validated.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "clientMutationId",
+ "description": "A unique identifier for the client performing the mutation.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "interfaces": null,
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "DastSiteTokenCreatePayload",
+ "description": "Autogenerated return type of DastSiteTokenCreate",
+ "fields": [
+ {
+ "name": "clientMutationId",
+ "description": "A unique identifier for the client performing the mutation.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "errors",
+ "description": "Errors encountered during execution of the mutation.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ }
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "id",
+ "description": "ID of the site token.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "DastSiteTokenID",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "status",
+ "description": "The current validation status of the target.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "ENUM",
+ "name": "DastSiteProfileValidationStatusEnum",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "token",
+ "description": "Token string.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "SCALAR",
+ "name": "DastSiteTokenID",
+ "description": "Identifier of DastSiteToken",
+ "fields": null,
+ "inputFields": null,
+ "interfaces": null,
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "SCALAR",
+ "name": "Date",
+ "description": "Date represented in ISO 8601",
+ "fields": null,
+ "inputFields": null,
+ "interfaces": null,
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "INPUT_OBJECT",
"name": "DeleteAnnotationInput",
"description": "Autogenerated input type of DeleteAnnotation",
"fields": null,
@@ -10790,6 +13001,20 @@
"description": "A collection of designs",
"fields": [
{
+ "name": "copyState",
+ "description": "Copy state of the design collection",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "ENUM",
+ "name": "DesignCollectionCopyState",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
"name": "design",
"description": "Find a specific design",
"args": [
@@ -11107,6 +13332,35 @@
"possibleTypes": null
},
{
+ "kind": "ENUM",
+ "name": "DesignCollectionCopyState",
+ "description": "Copy state of a DesignCollection",
+ "fields": null,
+ "inputFields": null,
+ "interfaces": null,
+ "enumValues": [
+ {
+ "name": "READY",
+ "description": "The DesignCollection has no copy in progress",
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "IN_PROGRESS",
+ "description": "The DesignCollection is being copied",
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "ERROR",
+ "description": "The DesignCollection encountered an error during a copy",
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "possibleTypes": null
+ },
+ {
"kind": "OBJECT",
"name": "DesignConnection",
"description": "The connection type for Design.",
@@ -12358,6 +14612,108 @@
"possibleTypes": null
},
{
+ "kind": "INPUT_OBJECT",
+ "name": "DestroyBoardListInput",
+ "description": "Autogenerated input type of DestroyBoardList",
+ "fields": null,
+ "inputFields": [
+ {
+ "name": "listId",
+ "description": "Global ID of the list to destroy. Only label lists are accepted.",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ListID",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "clientMutationId",
+ "description": "A unique identifier for the client performing the mutation.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "interfaces": null,
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "DestroyBoardListPayload",
+ "description": "Autogenerated return type of DestroyBoardList",
+ "fields": [
+ {
+ "name": "clientMutationId",
+ "description": "A unique identifier for the client performing the mutation.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "errors",
+ "description": "Errors encountered during execution of the mutation.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ }
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "list",
+ "description": "The list after mutation.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "BoardList",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
"kind": "OBJECT",
"name": "DestroyBoardPayload",
"description": "Autogenerated return type of DestroyBoard",
@@ -12438,7 +14794,7 @@
"name": null,
"ofType": {
"kind": "SCALAR",
- "name": "ID",
+ "name": "NoteID",
"ofType": null
}
},
@@ -12634,145 +14990,127 @@
"description": null,
"fields": [
{
+ "name": "action",
+ "description": "Action information for the status. This includes method, button title, icon, path, and title",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "StatusAction",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
"name": "detailsPath",
- "description": "Path of the details for the pipeline status",
+ "description": "Path of the details for the status",
"args": [
],
"type": {
- "kind": "NON_NULL",
- "name": null,
- "ofType": {
- "kind": "SCALAR",
- "name": "String",
- "ofType": null
- }
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "favicon",
- "description": "Favicon of the pipeline status",
+ "description": "Favicon of the status",
"args": [
],
"type": {
- "kind": "NON_NULL",
- "name": null,
- "ofType": {
- "kind": "SCALAR",
- "name": "String",
- "ofType": null
- }
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "group",
- "description": "Group of the pipeline status",
+ "description": "Group of the status",
"args": [
],
"type": {
- "kind": "NON_NULL",
- "name": null,
- "ofType": {
- "kind": "SCALAR",
- "name": "String",
- "ofType": null
- }
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "hasDetails",
- "description": "Indicates if the pipeline status has further details",
+ "description": "Indicates if the status has further details",
"args": [
],
"type": {
- "kind": "NON_NULL",
- "name": null,
- "ofType": {
- "kind": "SCALAR",
- "name": "Boolean",
- "ofType": null
- }
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "icon",
- "description": "Icon of the pipeline status",
+ "description": "Icon of the status",
"args": [
],
"type": {
- "kind": "NON_NULL",
- "name": null,
- "ofType": {
- "kind": "SCALAR",
- "name": "String",
- "ofType": null
- }
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "label",
- "description": "Label of the pipeline status",
+ "description": "Label of the status",
"args": [
],
"type": {
- "kind": "NON_NULL",
- "name": null,
- "ofType": {
- "kind": "SCALAR",
- "name": "String",
- "ofType": null
- }
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "text",
- "description": "Text of the pipeline status",
+ "description": "Text of the status",
"args": [
],
"type": {
- "kind": "NON_NULL",
- "name": null,
- "ofType": {
- "kind": "SCALAR",
- "name": "String",
- "ofType": null
- }
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "tooltip",
- "description": "Tooltip associated with the pipeline status",
+ "description": "Tooltip associated with the status",
"args": [
],
"type": {
- "kind": "NON_NULL",
- "name": null,
- "ofType": {
- "kind": "SCALAR",
- "name": "String",
- "ofType": null
- }
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
},
"isDeprecated": false,
"deprecationReason": null
@@ -13744,6 +16082,16 @@
"possibleTypes": null
},
{
+ "kind": "SCALAR",
+ "name": "DiscussionID",
+ "description": "Identifier of Discussion",
+ "fields": null,
+ "inputFields": null,
+ "interfaces": null,
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
"kind": "INPUT_OBJECT",
"name": "DiscussionToggleResolveInput",
"description": "Autogenerated input type of DiscussionToggleResolve",
@@ -13757,7 +16105,7 @@
"name": null,
"ofType": {
"kind": "SCALAR",
- "name": "ID",
+ "name": "DiscussionID",
"ofType": null
}
},
@@ -13873,7 +16221,7 @@
"name": null,
"ofType": {
"kind": "SCALAR",
- "name": "ID",
+ "name": "VulnerabilityID",
"ofType": null
}
},
@@ -14160,7 +16508,7 @@
},
{
"name": "latestOpenedMostSevereAlert",
- "description": "The most severe open alert for the environment. If multiple alerts have equal severity, the most recent is returned.",
+ "description": "The most severe open alert for the environment. If multiple alerts have equal severity, the most recent is returned",
"args": [
],
@@ -14218,6 +16566,20 @@
"deprecationReason": null
},
{
+ "name": "path",
+ "description": "The path to the environment. Will always return null if `expose_environment_path_in_alert_details` feature flag is disabled",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
"name": "state",
"description": "State of the environment, for example: available/stopped",
"args": [
@@ -14356,6 +16718,16 @@
"possibleTypes": null
},
{
+ "kind": "SCALAR",
+ "name": "EnvironmentID",
+ "description": "Identifier of Environment",
+ "fields": null,
+ "inputFields": null,
+ "interfaces": null,
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
"kind": "OBJECT",
"name": "Epic",
"description": "Represents an epic",
@@ -14384,7 +16756,7 @@
"args": [
{
"name": "startDate",
- "description": "List items within a time frame where items.start_date is between startDate and endDate parameters (endDate parameter must be present)",
+ "description": "List items overlapping a time frame defined by startDate..endDate (if one date is provided, both must be present). Deprecated in 13.5: Use timeframe.start",
"type": {
"kind": "SCALAR",
"name": "Time",
@@ -14394,7 +16766,7 @@
},
{
"name": "endDate",
- "description": "List items within a time frame where items.end_date is between startDate and endDate parameters (startDate parameter must be present)",
+ "description": "List items overlapping a time frame defined by startDate..endDate (if one date is provided, both must be present). Deprecated in 13.5: Use timeframe.end",
"type": {
"kind": "SCALAR",
"name": "Time",
@@ -14403,6 +16775,16 @@
"defaultValue": null
},
{
+ "name": "timeframe",
+ "description": "List items overlapping the given timeframe",
+ "type": {
+ "kind": "INPUT_OBJECT",
+ "name": "Timeframe",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
"name": "iid",
"description": "IID of the epic, e.g., \"1\"",
"type": {
@@ -14559,7 +16941,7 @@
},
{
"name": "closedAt",
- "description": "Timestamp of the epic's closure",
+ "description": "Timestamp of when the epic was closed",
"args": [
],
@@ -14587,7 +16969,7 @@
},
{
"name": "createdAt",
- "description": "Timestamp of the epic's creation",
+ "description": "Timestamp of when the epic was created",
"args": [
],
@@ -15354,7 +17736,7 @@
},
{
"name": "updatedAt",
- "description": "Timestamp of the epic's last activity",
+ "description": "Timestamp of when the epic was updated",
"args": [
],
@@ -16627,6 +19009,20 @@
"deprecationReason": null
},
{
+ "name": "slaDueAt",
+ "description": "Timestamp of when the issue SLA expires.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
"name": "state",
"description": "State of the issue",
"args": [
@@ -17433,7 +19829,7 @@
"name": null,
"ofType": {
"kind": "SCALAR",
- "name": "ID",
+ "name": "EpicTreeSortingID",
"ofType": null
}
},
@@ -17444,7 +19840,7 @@
"description": "The id of the epic_issue or issue that the actual epic or issue is switched with",
"type": {
"kind": "SCALAR",
- "name": "ID",
+ "name": "EpicTreeSortingID",
"ofType": null
},
"defaultValue": null
@@ -17464,7 +19860,7 @@
"description": "ID of the new parent epic",
"type": {
"kind": "SCALAR",
- "name": "ID",
+ "name": "EpicID",
"ofType": null
},
"defaultValue": null
@@ -17488,7 +19884,7 @@
"name": null,
"ofType": {
"kind": "SCALAR",
- "name": "ID",
+ "name": "EpicID",
"ofType": null
}
},
@@ -17577,6 +19973,16 @@
"possibleTypes": null
},
{
+ "kind": "SCALAR",
+ "name": "EpicTreeSortingID",
+ "description": "Identifier of EpicTreeSorting",
+ "fields": null,
+ "inputFields": null,
+ "interfaces": null,
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
"kind": "ENUM",
"name": "EpicWildcardId",
"description": "Epic ID wildcard values",
@@ -17689,6 +20095,77 @@
"deprecationReason": null
},
{
+ "name": "mergeRequestDiffRegistries",
+ "description": "Find merge request diff registries on this Geo node",
+ "args": [
+ {
+ "name": "ids",
+ "description": "Filters registries by their ID",
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "after",
+ "description": "Returns the elements in the list that come after the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "before",
+ "description": "Returns the elements in the list that come before the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "first",
+ "description": "Returns the first _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "last",
+ "description": "Returns the last _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "MergeRequestDiffRegistryConnection",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
"name": "minimumReverificationInterval",
"description": "The interval (in days) in which the repository verification is valid. Once expired, it will be reverified",
"args": [
@@ -17919,8 +20396,8 @@
"deprecationReason": null
},
{
- "name": "terraformStateRegistries",
- "description": "Find terraform state registries on this Geo node. Available only when feature flag `geo_terraform_state_replication` is enabled",
+ "name": "terraformStateVersionRegistries",
+ "description": "Find terraform state version registries on this Geo node",
"args": [
{
"name": "ids",
@@ -17983,7 +20460,7 @@
],
"type": {
"kind": "OBJECT",
- "name": "TerraformStateRegistryConnection",
+ "name": "TerraformStateVersionRegistryConnection",
"ofType": null
},
"isDeprecated": false,
@@ -18152,6 +20629,34 @@
"description": null,
"fields": [
{
+ "name": "actualRepositorySizeLimit",
+ "description": "Size limit for repositories in the namespace in bytes",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Float",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "additionalPurchasedStorageSize",
+ "description": "Additional storage purchased for the root namespace in bytes",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Float",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
"name": "autoDevopsEnabled",
"description": "Indicates whether Auto DevOps is enabled for all projects within this group",
"args": [
@@ -18185,11 +20690,15 @@
"args": [
{
"name": "id",
- "description": "Find a board by its ID",
+ "description": "The board's ID",
"type": {
- "kind": "SCALAR",
- "name": "ID",
- "ofType": null
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "BoardID",
+ "ofType": null
+ }
},
"defaultValue": null
}
@@ -18266,6 +20775,24 @@
"deprecationReason": null
},
{
+ "name": "containsLockedProjects",
+ "description": "Includes at least one project where the repository size exceeds the limit",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
"name": "description",
"description": "Description of the namespace",
"args": [
@@ -18313,7 +20840,7 @@
"args": [
{
"name": "startDate",
- "description": "List items within a time frame where items.start_date is between startDate and endDate parameters (endDate parameter must be present)",
+ "description": "List items overlapping a time frame defined by startDate..endDate (if one date is provided, both must be present). Deprecated in 13.5: Use timeframe.start",
"type": {
"kind": "SCALAR",
"name": "Time",
@@ -18323,7 +20850,7 @@
},
{
"name": "endDate",
- "description": "List items within a time frame where items.end_date is between startDate and endDate parameters (startDate parameter must be present)",
+ "description": "List items overlapping a time frame defined by startDate..endDate (if one date is provided, both must be present). Deprecated in 13.5: Use timeframe.end",
"type": {
"kind": "SCALAR",
"name": "Time",
@@ -18332,6 +20859,16 @@
"defaultValue": null
},
{
+ "name": "timeframe",
+ "description": "List items overlapping the given timeframe",
+ "type": {
+ "kind": "INPUT_OBJECT",
+ "name": "Timeframe",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
"name": "iid",
"description": "IID of the epic, e.g., \"1\"",
"type": {
@@ -18452,7 +20989,7 @@
"args": [
{
"name": "startDate",
- "description": "List items within a time frame where items.start_date is between startDate and endDate parameters (endDate parameter must be present)",
+ "description": "List items overlapping a time frame defined by startDate..endDate (if one date is provided, both must be present). Deprecated in 13.5: Use timeframe.start",
"type": {
"kind": "SCALAR",
"name": "Time",
@@ -18462,7 +20999,7 @@
},
{
"name": "endDate",
- "description": "List items within a time frame where items.end_date is between startDate and endDate parameters (startDate parameter must be present)",
+ "description": "List items overlapping a time frame defined by startDate..endDate (if one date is provided, both must be present). Deprecated in 13.5: Use timeframe.end",
"type": {
"kind": "SCALAR",
"name": "Time",
@@ -18471,6 +21008,16 @@
"defaultValue": null
},
{
+ "name": "timeframe",
+ "description": "List items overlapping the given timeframe",
+ "type": {
+ "kind": "INPUT_OBJECT",
+ "name": "Timeframe",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
"name": "iid",
"description": "IID of the epic, e.g., \"1\"",
"type": {
@@ -18790,7 +21337,7 @@
},
{
"name": "issues",
- "description": "Issues of the group",
+ "description": "Issues for projects in this group",
"args": [
{
"name": "iid",
@@ -18849,6 +21396,16 @@
"defaultValue": null
},
{
+ "name": "authorUsername",
+ "description": "Username of the author of the issue",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
"name": "assigneeUsername",
"description": "Username of a user assigned to the issue",
"type": {
@@ -18859,6 +21416,24 @@
"defaultValue": null
},
{
+ "name": "assigneeUsernames",
+ "description": "Usernames of users assigned to the issue",
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ }
+ },
+ "defaultValue": null
+ },
+ {
"name": "assigneeId",
"description": "ID of a user assigned to the issues, \"none\" and \"any\" values supported",
"type": {
@@ -18992,7 +21567,7 @@
},
{
"name": "includeSubgroups",
- "description": "Include issues belonging to subgroups.",
+ "description": "Include issues belonging to subgroups",
"type": {
"kind": "SCALAR",
"name": "Boolean",
@@ -19055,7 +21630,7 @@
"args": [
{
"name": "startDate",
- "description": "List items within a time frame where items.start_date is between startDate and endDate parameters (endDate parameter must be present)",
+ "description": "List items overlapping a time frame defined by startDate..endDate (if one date is provided, both must be present). Deprecated in 13.5: Use timeframe.start",
"type": {
"kind": "SCALAR",
"name": "Time",
@@ -19065,7 +21640,7 @@
},
{
"name": "endDate",
- "description": "List items within a time frame where items.end_date is between startDate and endDate parameters (startDate parameter must be present)",
+ "description": "List items overlapping a time frame defined by startDate..endDate (if one date is provided, both must be present). Deprecated in 13.5: Use timeframe.end",
"type": {
"kind": "SCALAR",
"name": "Time",
@@ -19074,6 +21649,16 @@
"defaultValue": null
},
{
+ "name": "timeframe",
+ "description": "List items overlapping the given timeframe",
+ "type": {
+ "kind": "INPUT_OBJECT",
+ "name": "Timeframe",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
"name": "state",
"description": "Filter iterations by state",
"type": {
@@ -19291,12 +21876,217 @@
"deprecationReason": null
},
{
+ "name": "mergeRequests",
+ "description": "Merge requests for projects in this group",
+ "args": [
+ {
+ "name": "iids",
+ "description": "Array of IIDs of merge requests, for example `[1, 2]`",
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "sourceBranches",
+ "description": "Array of source branch names. All resolved merge requests will have one of these branches as their source.",
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "targetBranches",
+ "description": "Array of target branch names. All resolved merge requests will have one of these branches as their target.",
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "state",
+ "description": "A merge request state. If provided, all resolved merge requests will have this state.",
+ "type": {
+ "kind": "ENUM",
+ "name": "MergeRequestState",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "labels",
+ "description": "Array of label names. All resolved merge requests will have all of these labels.",
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "mergedAfter",
+ "description": "Merge requests merged after this date",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "mergedBefore",
+ "description": "Merge requests merged before this date",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "milestoneTitle",
+ "description": "Title of the milestone",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "sort",
+ "description": "Sort merge requests by this criteria",
+ "type": {
+ "kind": "ENUM",
+ "name": "MergeRequestSort",
+ "ofType": null
+ },
+ "defaultValue": "created_desc"
+ },
+ {
+ "name": "includeSubgroups",
+ "description": "Include merge requests belonging to subgroups",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ },
+ "defaultValue": "false"
+ },
+ {
+ "name": "assigneeUsername",
+ "description": "Username of the assignee",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "authorUsername",
+ "description": "Username of the author",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "after",
+ "description": "Returns the elements in the list that come after the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "before",
+ "description": "Returns the elements in the list that come before the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "first",
+ "description": "Returns the first _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "last",
+ "description": "Returns the last _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "MergeRequestConnection",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
"name": "milestones",
"description": "Milestones of the group",
"args": [
{
"name": "startDate",
- "description": "List items within a time frame where items.start_date is between startDate and endDate parameters (endDate parameter must be present)",
+ "description": "List items overlapping a time frame defined by startDate..endDate (if one date is provided, both must be present). Deprecated in 13.5: Use timeframe.start",
"type": {
"kind": "SCALAR",
"name": "Time",
@@ -19306,7 +22096,7 @@
},
{
"name": "endDate",
- "description": "List items within a time frame where items.end_date is between startDate and endDate parameters (startDate parameter must be present)",
+ "description": "List items overlapping a time frame defined by startDate..endDate (if one date is provided, both must be present). Deprecated in 13.5: Use timeframe.end",
"type": {
"kind": "SCALAR",
"name": "Time",
@@ -19315,6 +22105,16 @@
"defaultValue": null
},
{
+ "name": "timeframe",
+ "description": "List items overlapping the given timeframe",
+ "type": {
+ "kind": "INPUT_OBJECT",
+ "name": "Timeframe",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
"name": "ids",
"description": "Array of global milestone IDs, e.g., \"gid://gitlab/Milestone/1\"",
"type": {
@@ -19343,6 +22143,36 @@
"defaultValue": null
},
{
+ "name": "title",
+ "description": "The title of the milestone",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "searchTitle",
+ "description": "A search string for the title",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "containingDate",
+ "description": "A date that the milestone contains",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
"name": "includeDescendants",
"description": "Also return milestones in all subgroups and subprojects",
"type": {
@@ -19563,6 +22393,24 @@
"deprecationReason": null
},
{
+ "name": "repositorySizeExcessProjectCount",
+ "description": "Number of projects in the root namespace where the repository size exceeds the limit",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
"name": "requestAccessEnabled",
"description": "Indicates if users can request access to namespace",
"args": [
@@ -19758,6 +22606,34 @@
"deprecationReason": null
},
{
+ "name": "totalRepositorySize",
+ "description": "Total repository size of all projects in the root namespace in bytes",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Float",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "totalRepositorySizeExcess",
+ "description": "Total excess repository size of all projects in the root namespace in bytes",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Float",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
"name": "twoFactorGracePeriod",
"description": "Time before two-factor authentication is enforced",
"args": [
@@ -21905,6 +24781,20 @@
"deprecationReason": null
},
{
+ "name": "slaDueAt",
+ "description": "Timestamp of when the issue SLA expires.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
"name": "state",
"description": "State of the issue",
"args": [
@@ -22335,6 +25225,69 @@
},
{
"kind": "INPUT_OBJECT",
+ "name": "IssueMoveInput",
+ "description": "Autogenerated input type of IssueMove",
+ "fields": null,
+ "inputFields": [
+ {
+ "name": "projectPath",
+ "description": "The project the issue to mutate is in",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "iid",
+ "description": "The IID of the issue to mutate",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "targetProjectPath",
+ "description": "The project to move the issue to",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "clientMutationId",
+ "description": "A unique identifier for the client performing the mutation.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "interfaces": null,
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "INPUT_OBJECT",
"name": "IssueMoveListInput",
"description": "Autogenerated input type of IssueMoveList",
"fields": null,
@@ -22515,6 +25468,73 @@
},
{
"kind": "OBJECT",
+ "name": "IssueMovePayload",
+ "description": "Autogenerated return type of IssueMove",
+ "fields": [
+ {
+ "name": "clientMutationId",
+ "description": "A unique identifier for the client performing the mutation.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "errors",
+ "description": "Errors encountered during execution of the mutation.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ }
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "issue",
+ "description": "The issue after mutation",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "Issue",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
"name": "IssuePermissions",
"description": "Check permissions for the current user on a issue",
"fields": [
@@ -23243,7 +26263,7 @@
"description": "The iteration to assign to the issue.\n",
"type": {
"kind": "SCALAR",
- "name": "ID",
+ "name": "IterationID",
"ofType": null
},
"defaultValue": null
@@ -23861,23 +26881,47 @@
{
"name": "updated_desc",
"description": "Updated at descending order",
+ "isDeprecated": true,
+ "deprecationReason": "Use UPDATED_DESC. Deprecated in 13.5"
+ },
+ {
+ "name": "updated_asc",
+ "description": "Updated at ascending order",
+ "isDeprecated": true,
+ "deprecationReason": "Use UPDATED_ASC. Deprecated in 13.5"
+ },
+ {
+ "name": "created_desc",
+ "description": "Created at descending order",
+ "isDeprecated": true,
+ "deprecationReason": "Use CREATED_DESC. Deprecated in 13.5"
+ },
+ {
+ "name": "created_asc",
+ "description": "Created at ascending order",
+ "isDeprecated": true,
+ "deprecationReason": "Use CREATED_ASC. Deprecated in 13.5"
+ },
+ {
+ "name": "UPDATED_DESC",
+ "description": "Updated at descending order",
"isDeprecated": false,
"deprecationReason": null
},
{
- "name": "updated_asc",
+ "name": "UPDATED_ASC",
"description": "Updated at ascending order",
"isDeprecated": false,
"deprecationReason": null
},
{
- "name": "created_desc",
+ "name": "CREATED_DESC",
"description": "Created at descending order",
"isDeprecated": false,
"deprecationReason": null
},
{
- "name": "created_asc",
+ "name": "CREATED_ASC",
"description": "Created at ascending order",
"isDeprecated": false,
"deprecationReason": null
@@ -23937,6 +26981,18 @@
"deprecationReason": null
},
{
+ "name": "SEVERITY_ASC",
+ "description": "Severity from less critical to more critical",
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "SEVERITY_DESC",
+ "description": "Severity from more critical to less critical",
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
"name": "WEIGHT_ASC",
"description": "Weight by ascending order",
"isDeprecated": false,
@@ -23947,6 +27003,18 @@
"description": "Weight by descending order",
"isDeprecated": false,
"deprecationReason": null
+ },
+ {
+ "name": "PUBLISHED_ASC",
+ "description": "Published issues shown last",
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "PUBLISHED_DESC",
+ "description": "Published issues shown first",
+ "isDeprecated": false,
+ "deprecationReason": null
}
],
"possibleTypes": null
@@ -23987,6 +27055,29 @@
"possibleTypes": null
},
{
+ "kind": "ENUM",
+ "name": "IssueStateEvent",
+ "description": "Values for issue state events",
+ "fields": null,
+ "inputFields": null,
+ "interfaces": null,
+ "enumValues": [
+ {
+ "name": "REOPEN",
+ "description": "Reopens the issue",
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "CLOSE",
+ "description": "Closes the issue",
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "possibleTypes": null
+ },
+ {
"kind": "OBJECT",
"name": "IssueStatusCountsType",
"description": "Represents total number of issues for the represented statuses",
@@ -25555,6 +28646,24 @@
"description": "The connection type for Label.",
"fields": [
{
+ "name": "count",
+ "description": "Total count of collection",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
"name": "edges",
"description": "A list of edges.",
"args": [
@@ -25672,6 +28781,16 @@
"possibleTypes": null
},
{
+ "kind": "SCALAR",
+ "name": "ListID",
+ "description": "Identifier of List",
+ "fields": null,
+ "inputFields": null,
+ "interfaces": null,
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
"kind": "ENUM",
"name": "ListLimitMetric",
"description": "List limit metric setting",
@@ -25845,6 +28964,30 @@
"description": "Pipeline count",
"isDeprecated": false,
"deprecationReason": null
+ },
+ {
+ "name": "PIPELINES_SUCCEEDED",
+ "description": "Pipeline count with success status",
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "PIPELINES_FAILED",
+ "description": "Pipeline count with failed status",
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "PIPELINES_CANCELED",
+ "description": "Pipeline count with canceled status",
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "PIPELINES_SKIPPED",
+ "description": "Pipeline count with skipped status",
+ "isDeprecated": false,
+ "deprecationReason": null
}
],
"possibleTypes": null
@@ -27832,6 +30975,251 @@
},
{
"kind": "OBJECT",
+ "name": "MergeRequestDiffRegistry",
+ "description": "Represents the Geo sync and verification state of a Merge Request diff",
+ "fields": [
+ {
+ "name": "createdAt",
+ "description": "Timestamp when the MergeRequestDiffRegistry was created",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "id",
+ "description": "ID of the MergeRequestDiffRegistry",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "lastSyncFailure",
+ "description": "Error message during sync of the MergeRequestDiffRegistry",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "lastSyncedAt",
+ "description": "Timestamp of the most recent successful sync of the MergeRequestDiffRegistry",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "mergeRequestDiffId",
+ "description": "ID of the Merge Request diff",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "retryAt",
+ "description": "Timestamp after which the MergeRequestDiffRegistry should be resynced",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "retryCount",
+ "description": "Number of consecutive failed sync attempts of the MergeRequestDiffRegistry",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "state",
+ "description": "Sync state of the MergeRequestDiffRegistry",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "ENUM",
+ "name": "RegistryState",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "MergeRequestDiffRegistryConnection",
+ "description": "The connection type for MergeRequestDiffRegistry.",
+ "fields": [
+ {
+ "name": "edges",
+ "description": "A list of edges.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "MergeRequestDiffRegistryEdge",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "nodes",
+ "description": "A list of nodes.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "MergeRequestDiffRegistry",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "pageInfo",
+ "description": "Information to aid in pagination.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "PageInfo",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "MergeRequestDiffRegistryEdge",
+ "description": "An edge in a connection.",
+ "fields": [
+ {
+ "name": "cursor",
+ "description": "A cursor for use in pagination.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "node",
+ "description": "The item at the end of the edge.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "MergeRequestDiffRegistry",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
"name": "MergeRequestEdge",
"description": "An edge in a connection.",
"fields": [
@@ -27876,6 +31264,16 @@
"possibleTypes": null
},
{
+ "kind": "SCALAR",
+ "name": "MergeRequestID",
+ "description": "Identifier of MergeRequest",
+ "fields": null,
+ "inputFields": null,
+ "interfaces": null,
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
"kind": "OBJECT",
"name": "MergeRequestPermissions",
"description": "Check permissions for the current user on a merge request",
@@ -28515,7 +31913,7 @@
"description": "The milestone to assign to the merge request.\n",
"type": {
"kind": "SCALAR",
- "name": "ID",
+ "name": "MilestoneID",
"ofType": null
},
"defaultValue": null
@@ -28873,23 +32271,47 @@
{
"name": "updated_desc",
"description": "Updated at descending order",
+ "isDeprecated": true,
+ "deprecationReason": "Use UPDATED_DESC. Deprecated in 13.5"
+ },
+ {
+ "name": "updated_asc",
+ "description": "Updated at ascending order",
+ "isDeprecated": true,
+ "deprecationReason": "Use UPDATED_ASC. Deprecated in 13.5"
+ },
+ {
+ "name": "created_desc",
+ "description": "Created at descending order",
+ "isDeprecated": true,
+ "deprecationReason": "Use CREATED_DESC. Deprecated in 13.5"
+ },
+ {
+ "name": "created_asc",
+ "description": "Created at ascending order",
+ "isDeprecated": true,
+ "deprecationReason": "Use CREATED_ASC. Deprecated in 13.5"
+ },
+ {
+ "name": "UPDATED_DESC",
+ "description": "Updated at descending order",
"isDeprecated": false,
"deprecationReason": null
},
{
- "name": "updated_asc",
+ "name": "UPDATED_ASC",
"description": "Updated at ascending order",
"isDeprecated": false,
"deprecationReason": null
},
{
- "name": "created_desc",
+ "name": "CREATED_DESC",
"description": "Created at descending order",
"isDeprecated": false,
"deprecationReason": null
},
{
- "name": "created_asc",
+ "name": "CREATED_ASC",
"description": "Created at ascending order",
"isDeprecated": false,
"deprecationReason": null
@@ -30437,6 +33859,33 @@
"deprecationReason": null
},
{
+ "name": "createBoard",
+ "description": null,
+ "args": [
+ {
+ "name": "input",
+ "description": null,
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "INPUT_OBJECT",
+ "name": "CreateBoardInput",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "CreateBoardPayload",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
"name": "createBranch",
"description": null,
"args": [
@@ -30572,6 +34021,33 @@
"deprecationReason": null
},
{
+ "name": "createIssue",
+ "description": null,
+ "args": [
+ {
+ "name": "input",
+ "description": null,
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "INPUT_OBJECT",
+ "name": "CreateIssueInput",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "CreateIssuePayload",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
"name": "createIteration",
"description": null,
"args": [
@@ -30896,6 +34372,33 @@
"deprecationReason": null
},
{
+ "name": "dastSiteTokenCreate",
+ "description": null,
+ "args": [
+ {
+ "name": "input",
+ "description": null,
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "INPUT_OBJECT",
+ "name": "DastSiteTokenCreateInput",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "DastSiteTokenCreatePayload",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
"name": "deleteAnnotation",
"description": null,
"args": [
@@ -31031,6 +34534,33 @@
"deprecationReason": null
},
{
+ "name": "destroyBoardList",
+ "description": null,
+ "args": [
+ {
+ "name": "input",
+ "description": null,
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "INPUT_OBJECT",
+ "name": "DestroyBoardListInput",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "DestroyBoardListPayload",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
"name": "destroyNote",
"description": null,
"args": [
@@ -31135,8 +34665,8 @@
"name": "DismissVulnerabilityPayload",
"ofType": null
},
- "isDeprecated": false,
- "deprecationReason": null
+ "isDeprecated": true,
+ "deprecationReason": "Use vulnerabilityDismiss. Deprecated in 13.5"
},
{
"name": "epicAddIssue",
@@ -31220,6 +34750,33 @@
"deprecationReason": null
},
{
+ "name": "issueMove",
+ "description": null,
+ "args": [
+ {
+ "name": "input",
+ "description": null,
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "INPUT_OBJECT",
+ "name": "IssueMoveInput",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "IssueMovePayload",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
"name": "issueMoveList",
"description": null,
"args": [
@@ -31949,6 +35506,33 @@
"deprecationReason": null
},
{
+ "name": "revertVulnerabilityToDetected",
+ "description": null,
+ "args": [
+ {
+ "name": "input",
+ "description": null,
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "INPUT_OBJECT",
+ "name": "RevertVulnerabilityToDetectedInput",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "RevertVulnerabilityToDetectedPayload",
+ "ofType": null
+ },
+ "isDeprecated": true,
+ "deprecationReason": "Use vulnerabilityRevertToDetected. Deprecated in 13.5"
+ },
+ {
"name": "runDastScan",
"description": null,
"args": [
@@ -32165,6 +35749,33 @@
"deprecationReason": null
},
{
+ "name": "updateBoardEpicUserPreferences",
+ "description": null,
+ "args": [
+ {
+ "name": "input",
+ "description": null,
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "INPUT_OBJECT",
+ "name": "UpdateBoardEpicUserPreferencesInput",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "UpdateBoardEpicUserPreferencesPayload",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
"name": "updateBoardList",
"description": null,
"args": [
@@ -32408,6 +36019,60 @@
"deprecationReason": null
},
{
+ "name": "vulnerabilityConfirm",
+ "description": null,
+ "args": [
+ {
+ "name": "input",
+ "description": null,
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "INPUT_OBJECT",
+ "name": "VulnerabilityConfirmInput",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "VulnerabilityConfirmPayload",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "vulnerabilityDismiss",
+ "description": null,
+ "args": [
+ {
+ "name": "input",
+ "description": null,
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "INPUT_OBJECT",
+ "name": "VulnerabilityDismissInput",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "VulnerabilityDismissPayload",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
"name": "vulnerabilityResolve",
"description": null,
"args": [
@@ -32433,6 +36098,33 @@
},
"isDeprecated": false,
"deprecationReason": null
+ },
+ {
+ "name": "vulnerabilityRevertToDetected",
+ "description": null,
+ "args": [
+ {
+ "name": "input",
+ "description": null,
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "INPUT_OBJECT",
+ "name": "VulnerabilityRevertToDetectedInput",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "VulnerabilityRevertToDetectedPayload",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
}
],
"inputFields": null,
@@ -32477,6 +36169,52 @@
"description": null,
"fields": [
{
+ "name": "actualRepositorySizeLimit",
+ "description": "Size limit for repositories in the namespace in bytes",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Float",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "additionalPurchasedStorageSize",
+ "description": "Additional storage purchased for the root namespace in bytes",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Float",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "containsLockedProjects",
+ "description": "Includes at least one project where the repository size exceeds the limit",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
"name": "description",
"description": "Description of the namespace",
"args": [
@@ -32724,6 +36462,24 @@
"deprecationReason": null
},
{
+ "name": "repositorySizeExcessProjectCount",
+ "description": "Number of projects in the root namespace where the repository size exceeds the limit",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
"name": "requestAccessEnabled",
"description": "Indicates if users can request access to namespace",
"args": [
@@ -32780,6 +36536,34 @@
"deprecationReason": null
},
{
+ "name": "totalRepositorySize",
+ "description": "Total repository size of all projects in the root namespace in bytes",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Float",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "totalRepositorySizeExcess",
+ "description": "Total excess repository size of all projects in the root namespace in bytes",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Float",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
"name": "visibility",
"description": "Visibility of the namespace",
"args": [
@@ -32914,6 +36698,16 @@
"possibleTypes": null
},
{
+ "kind": "SCALAR",
+ "name": "NamespaceID",
+ "description": "Identifier of Namespace",
+ "fields": null,
+ "inputFields": null,
+ "interfaces": null,
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
"kind": "INPUT_OBJECT",
"name": "NamespaceIncreaseStorageTemporarilyInput",
"description": "Autogenerated input type of NamespaceIncreaseStorageTemporarily",
@@ -32927,7 +36721,7 @@
"name": null,
"ofType": {
"kind": "SCALAR",
- "name": "ID",
+ "name": "NamespaceID",
"ofType": null
}
},
@@ -33535,6 +37329,16 @@
"possibleTypes": null
},
{
+ "kind": "SCALAR",
+ "name": "NoteID",
+ "description": "Identifier of Note",
+ "fields": null,
+ "inputFields": null,
+ "interfaces": null,
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
"kind": "OBJECT",
"name": "NotePermissions",
"description": null,
@@ -33768,6 +37572,11 @@
},
{
"kind": "OBJECT",
+ "name": "BoardEpic",
+ "ofType": null
+ },
+ {
+ "kind": "OBJECT",
"name": "Design",
"ofType": null
},
@@ -33795,10 +37604,25 @@
"kind": "OBJECT",
"name": "Snippet",
"ofType": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "Vulnerability",
+ "ofType": null
}
]
},
{
+ "kind": "SCALAR",
+ "name": "NoteableID",
+ "description": "Identifier of Noteable",
+ "fields": null,
+ "inputFields": null,
+ "interfaces": null,
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
"kind": "OBJECT",
"name": "Package",
"description": "Represents a package",
@@ -34030,7 +37854,7 @@
{
"kind": "OBJECT",
"name": "PackageFileRegistry",
- "description": "Represents the sync and verification state of a package file",
+ "description": "Represents the Geo sync and verification state of a package file",
"fields": [
{
"name": "createdAt",
@@ -34282,43 +38106,55 @@
"enumValues": [
{
"name": "MAVEN",
- "description": "Packages from the maven package manager",
+ "description": "Packages from the Maven package manager",
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "NPM",
- "description": "Packages from the npm package manager",
+ "description": "Packages from the NPM package manager",
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "CONAN",
- "description": "Packages from the conan package manager",
+ "description": "Packages from the Conan package manager",
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "NUGET",
- "description": "Packages from the nuget package manager",
+ "description": "Packages from the Nuget package manager",
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "PYPI",
- "description": "Packages from the pypi package manager",
+ "description": "Packages from the PyPI package manager",
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "COMPOSER",
- "description": "Packages from the composer package manager",
+ "description": "Packages from the Composer package manager",
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "GENERIC",
- "description": "Packages from the generic package manager",
+ "description": "Packages from the Generic package manager",
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "GOLANG",
+ "description": "Packages from the Golang package manager",
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "DEBIAN",
+ "description": "Packages from the Debian package manager",
"isDeprecated": false,
"deprecationReason": null
}
@@ -35391,6 +39227,20 @@
"description": null,
"fields": [
{
+ "name": "actualRepositorySizeLimit",
+ "description": "Size limit for the repository in bytes",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Float",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
"name": "alertManagementAlert",
"description": "A single Alert Management alert of the project",
"args": [
@@ -35441,6 +39291,16 @@
"ofType": null
},
"defaultValue": null
+ },
+ {
+ "name": "assigneeUsername",
+ "description": "Username of a user assigned to the issue",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
}
],
"type": {
@@ -35464,6 +39324,16 @@
"ofType": null
},
"defaultValue": null
+ },
+ {
+ "name": "assigneeUsername",
+ "description": "Username of a user assigned to the issue",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
}
],
"type": {
@@ -35527,6 +39397,16 @@
"defaultValue": null
},
{
+ "name": "assigneeUsername",
+ "description": "Username of a user assigned to the issue",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
"name": "after",
"description": "Returns the elements in the list that come after the specified cursor.",
"type": {
@@ -35637,11 +39517,15 @@
"args": [
{
"name": "id",
- "description": "Find a board by its ID",
+ "description": "The board's ID",
"type": {
- "kind": "SCALAR",
- "name": "ID",
- "ofType": null
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "BoardID",
+ "ofType": null
+ }
},
"defaultValue": null
}
@@ -36366,6 +40250,16 @@
"defaultValue": null
},
{
+ "name": "authorUsername",
+ "description": "Username of the author of the issue",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
"name": "assigneeUsername",
"description": "Username of a user assigned to the issue",
"type": {
@@ -36376,6 +40270,24 @@
"defaultValue": null
},
{
+ "name": "assigneeUsernames",
+ "description": "Usernames of users assigned to the issue",
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ }
+ },
+ "defaultValue": null
+ },
+ {
"name": "assigneeId",
"description": "ID of a user assigned to the issues, \"none\" and \"any\" values supported",
"type": {
@@ -36577,6 +40489,16 @@
"defaultValue": null
},
{
+ "name": "authorUsername",
+ "description": "Username of the author of the issue",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
"name": "assigneeUsername",
"description": "Username of a user assigned to the issue",
"type": {
@@ -36587,6 +40509,24 @@
"defaultValue": null
},
{
+ "name": "assigneeUsernames",
+ "description": "Usernames of users assigned to the issue",
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ }
+ },
+ "defaultValue": null
+ },
+ {
"name": "assigneeId",
"description": "ID of a user assigned to the issues, \"none\" and \"any\" values supported",
"type": {
@@ -36754,6 +40694,16 @@
"defaultValue": null
},
{
+ "name": "authorUsername",
+ "description": "Username of the author of the issue",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
"name": "assigneeUsername",
"description": "Username of a user assigned to the issue",
"type": {
@@ -36764,6 +40714,24 @@
"defaultValue": null
},
{
+ "name": "assigneeUsernames",
+ "description": "Usernames of users assigned to the issue",
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ }
+ },
+ "defaultValue": null
+ },
+ {
"name": "assigneeId",
"description": "ID of a user assigned to the issues, \"none\" and \"any\" values supported",
"type": {
@@ -36964,7 +40932,7 @@
"args": [
{
"name": "startDate",
- "description": "List items within a time frame where items.start_date is between startDate and endDate parameters (endDate parameter must be present)",
+ "description": "List items overlapping a time frame defined by startDate..endDate (if one date is provided, both must be present). Deprecated in 13.5: Use timeframe.start",
"type": {
"kind": "SCALAR",
"name": "Time",
@@ -36974,7 +40942,7 @@
},
{
"name": "endDate",
- "description": "List items within a time frame where items.end_date is between startDate and endDate parameters (startDate parameter must be present)",
+ "description": "List items overlapping a time frame defined by startDate..endDate (if one date is provided, both must be present). Deprecated in 13.5: Use timeframe.end",
"type": {
"kind": "SCALAR",
"name": "Time",
@@ -36983,6 +40951,16 @@
"defaultValue": null
},
{
+ "name": "timeframe",
+ "description": "List items overlapping the given timeframe",
+ "type": {
+ "kind": "INPUT_OBJECT",
+ "name": "Timeframe",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
"name": "state",
"description": "Filter iterations by state",
"type": {
@@ -37536,7 +41514,7 @@
"args": [
{
"name": "startDate",
- "description": "List items within a time frame where items.start_date is between startDate and endDate parameters (endDate parameter must be present)",
+ "description": "List items overlapping a time frame defined by startDate..endDate (if one date is provided, both must be present). Deprecated in 13.5: Use timeframe.start",
"type": {
"kind": "SCALAR",
"name": "Time",
@@ -37546,7 +41524,7 @@
},
{
"name": "endDate",
- "description": "List items within a time frame where items.end_date is between startDate and endDate parameters (startDate parameter must be present)",
+ "description": "List items overlapping a time frame defined by startDate..endDate (if one date is provided, both must be present). Deprecated in 13.5: Use timeframe.end",
"type": {
"kind": "SCALAR",
"name": "Time",
@@ -37555,6 +41533,16 @@
"defaultValue": null
},
{
+ "name": "timeframe",
+ "description": "List items overlapping the given timeframe",
+ "type": {
+ "kind": "INPUT_OBJECT",
+ "name": "Timeframe",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
"name": "ids",
"description": "Array of global milestone IDs, e.g., \"gid://gitlab/Milestone/1\"",
"type": {
@@ -37583,6 +41571,36 @@
"defaultValue": null
},
{
+ "name": "title",
+ "description": "The title of the milestone",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "searchTitle",
+ "description": "A search string for the title",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "containingDate",
+ "description": "A date that the milestone contains",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
"name": "includeAncestors",
"description": "Also return milestones in the project's parent group and its ancestors",
"type": {
@@ -38114,6 +42132,20 @@
"deprecationReason": null
},
{
+ "name": "repositorySizeExcess",
+ "description": "Size of repository that exceeds the limit in bytes",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Float",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
"name": "requestAccessEnabled",
"description": "Indicates if users can request member access to the project",
"args": [
@@ -38129,7 +42161,7 @@
},
{
"name": "requirement",
- "description": "Find a single requirement. Available only when feature flag `requirements_management` is enabled.",
+ "description": "Find a single requirement",
"args": [
{
"name": "iid",
@@ -38232,7 +42264,7 @@
},
{
"name": "requirements",
- "description": "Find requirements. Available only when feature flag `requirements_management` is enabled.",
+ "description": "Find requirements",
"args": [
{
"name": "iid",
@@ -38727,6 +42759,59 @@
"deprecationReason": null
},
{
+ "name": "terraformStates",
+ "description": "Terraform states associated with the project",
+ "args": [
+ {
+ "name": "after",
+ "description": "Returns the elements in the list that come after the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "before",
+ "description": "Returns the elements in the list that come before the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "first",
+ "description": "Returns the first _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "last",
+ "description": "Returns the last _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "TerraformStateConnection",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
"name": "userPermissions",
"description": "Permissions for the current user on the resource",
"args": [
@@ -39317,6 +43402,16 @@
"possibleTypes": null
},
{
+ "kind": "SCALAR",
+ "name": "ProjectID",
+ "description": "Identifier of Project",
+ "fields": null,
+ "inputFields": null,
+ "interfaces": null,
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
"kind": "OBJECT",
"name": "ProjectMember",
"description": "Represents a Project Membership",
@@ -40982,6 +45077,26 @@
"defaultValue": null
},
{
+ "name": "searchNamespaces",
+ "description": "Include namespace in project search",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "sort",
+ "description": "Sort order of results",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
"name": "after",
"description": "Returns the elements in the list that come after the specified cursor.",
"type": {
@@ -41031,6 +45146,59 @@
"deprecationReason": null
},
{
+ "name": "runnerPlatforms",
+ "description": "Supported runner platforms",
+ "args": [
+ {
+ "name": "after",
+ "description": "Returns the elements in the list that come after the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "before",
+ "description": "Returns the elements in the list that come before the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "first",
+ "description": "Returns the first _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "last",
+ "description": "Returns the last _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "RunnerPlatformConnection",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
"name": "snippets",
"description": "Find Snippets visible to the current user",
"args": [
@@ -41617,6 +45785,33 @@
},
"isDeprecated": true,
"deprecationReason": "Use `vulnerabilitiesCountByDay`. Deprecated in 13.3"
+ },
+ {
+ "name": "vulnerability",
+ "description": "Find a vulnerability",
+ "args": [
+ {
+ "name": "id",
+ "description": "The Global ID of the Vulnerability",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "VulnerabilityID",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "Vulnerability",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
}
],
"inputFields": null,
@@ -42880,7 +47075,7 @@
"name": null,
"ofType": {
"kind": "SCALAR",
- "name": "ID",
+ "name": "AwardableID",
"ofType": null
}
},
@@ -42996,7 +47191,7 @@
"name": null,
"ofType": {
"kind": "SCALAR",
- "name": "ID",
+ "name": "ProjectID",
"ofType": null
}
},
@@ -43218,6 +47413,34 @@
"deprecationReason": null
},
{
+ "name": "description",
+ "description": "Description of the requirement",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "descriptionHtml",
+ "description": "The GitLab Flavored Markdown rendering of `description`",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
"name": "id",
"description": "ID of the requirement",
"args": [
@@ -43254,6 +47477,20 @@
"deprecationReason": null
},
{
+ "name": "lastTestReportManuallyCreated",
+ "description": "Indicates if latest test report was created by user",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
"name": "lastTestReportState",
"description": "Latest requirement test report state",
"args": [
@@ -43381,6 +47618,20 @@
"deprecationReason": null
},
{
+ "name": "titleHtml",
+ "description": "The GitLab Flavored Markdown rendering of `title`",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
"name": "updatedAt",
"description": "Timestamp of when the requirement was last updated",
"args": [
@@ -43790,6 +48041,108 @@
]
},
{
+ "kind": "INPUT_OBJECT",
+ "name": "RevertVulnerabilityToDetectedInput",
+ "description": "Autogenerated input type of RevertVulnerabilityToDetected",
+ "fields": null,
+ "inputFields": [
+ {
+ "name": "id",
+ "description": "ID of the vulnerability to be reverted",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "VulnerabilityID",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "clientMutationId",
+ "description": "A unique identifier for the client performing the mutation.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "interfaces": null,
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "RevertVulnerabilityToDetectedPayload",
+ "description": "Autogenerated return type of RevertVulnerabilityToDetected",
+ "fields": [
+ {
+ "name": "clientMutationId",
+ "description": "A unique identifier for the client performing the mutation.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "errors",
+ "description": "Errors encountered during execution of the mutation.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ }
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "vulnerability",
+ "description": "The vulnerability after revert",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "Vulnerability",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
"kind": "OBJECT",
"name": "RootStorageStatistics",
"description": null,
@@ -43849,6 +48202,24 @@
"deprecationReason": null
},
{
+ "name": "pipelineArtifactsSize",
+ "description": "The CI pipeline artifacts size in bytes",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Float",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
"name": "repositorySize",
"description": "The Git repository size in bytes",
"args": [
@@ -44074,6 +48445,381 @@
},
{
"kind": "OBJECT",
+ "name": "RunnerArchitecture",
+ "description": null,
+ "fields": [
+ {
+ "name": "downloadLocation",
+ "description": "Download location for the runner for the platform architecture",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "name",
+ "description": "Name of the runner platform architecture",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "RunnerArchitectureConnection",
+ "description": "The connection type for RunnerArchitecture.",
+ "fields": [
+ {
+ "name": "edges",
+ "description": "A list of edges.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "RunnerArchitectureEdge",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "nodes",
+ "description": "A list of nodes.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "RunnerArchitecture",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "pageInfo",
+ "description": "Information to aid in pagination.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "PageInfo",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "RunnerArchitectureEdge",
+ "description": "An edge in a connection.",
+ "fields": [
+ {
+ "name": "cursor",
+ "description": "A cursor for use in pagination.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "node",
+ "description": "The item at the end of the edge.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "RunnerArchitecture",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "RunnerPlatform",
+ "description": null,
+ "fields": [
+ {
+ "name": "architectures",
+ "description": "Runner architectures supported for the platform",
+ "args": [
+ {
+ "name": "after",
+ "description": "Returns the elements in the list that come after the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "before",
+ "description": "Returns the elements in the list that come before the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "first",
+ "description": "Returns the first _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "last",
+ "description": "Returns the last _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "RunnerArchitectureConnection",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "humanReadableName",
+ "description": "Human readable name of the runner platform",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "name",
+ "description": "Name slug of the runner platform",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "RunnerPlatformConnection",
+ "description": "The connection type for RunnerPlatform.",
+ "fields": [
+ {
+ "name": "edges",
+ "description": "A list of edges.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "RunnerPlatformEdge",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "nodes",
+ "description": "A list of nodes.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "RunnerPlatform",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "pageInfo",
+ "description": "Information to aid in pagination.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "PageInfo",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "RunnerPlatformEdge",
+ "description": "An edge in a connection.",
+ "fields": [
+ {
+ "name": "cursor",
+ "description": "A cursor for use in pagination.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "node",
+ "description": "The item at the end of the edge.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "RunnerPlatform",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
"name": "SastCiConfiguration",
"description": "Represents a CI configuration of SAST",
"fields": [
@@ -44479,6 +49225,63 @@
"possibleTypes": null
},
{
+ "kind": "INPUT_OBJECT",
+ "name": "SastCiConfigurationAnalyzersEntityInput",
+ "description": "Represents the analyzers entity in SAST CI configuration",
+ "fields": null,
+ "inputFields": [
+ {
+ "name": "name",
+ "description": "Name of analyzer",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "enabled",
+ "description": "State of the analyzer",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "variables",
+ "description": "List of variables for the analyzer",
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "INPUT_OBJECT",
+ "name": "SastCiConfigurationEntityInput",
+ "ofType": null
+ }
+ }
+ },
+ "defaultValue": null
+ }
+ ],
+ "interfaces": null,
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
"kind": "OBJECT",
"name": "SastCiConfigurationEntity",
"description": "Represents an entity in SAST CI configuration",
@@ -44848,6 +49651,24 @@
}
},
"defaultValue": null
+ },
+ {
+ "name": "analyzers",
+ "description": "List of analyzers and related variables for the SAST configuration",
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "INPUT_OBJECT",
+ "name": "SastCiConfigurationAnalyzersEntityInput",
+ "ofType": null
+ }
+ }
+ },
+ "defaultValue": null
}
],
"interfaces": null,
@@ -45195,6 +50016,20 @@
"description": "Represents summary of a security report",
"fields": [
{
+ "name": "apiFuzzing",
+ "description": "Aggregated counts for the api_fuzzing scan",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "SecurityReportSummarySection",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
"name": "containerScanning",
"description": "Aggregated counts for the container_scanning scan",
"args": [
@@ -45437,6 +50272,12 @@
"description": null,
"isDeprecated": false,
"deprecationReason": null
+ },
+ {
+ "name": "API_FUZZING",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
}
],
"possibleTypes": null
@@ -47364,24 +52205,69 @@
"name": "blobs",
"description": "Snippet blobs",
"args": [
-
- ],
- "type": {
- "kind": "NON_NULL",
- "name": null,
- "ofType": {
- "kind": "LIST",
- "name": null,
- "ofType": {
- "kind": "NON_NULL",
+ {
+ "name": "paths",
+ "description": "Paths of the blobs",
+ "type": {
+ "kind": "LIST",
"name": null,
"ofType": {
- "kind": "OBJECT",
- "name": "SnippetBlob",
- "ofType": null
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
}
- }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "after",
+ "description": "Returns the elements in the list that come after the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "before",
+ "description": "Returns the elements in the list that come before the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "first",
+ "description": "Returns the first _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "last",
+ "description": "Returns the last _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
}
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "SnippetBlobConnection",
+ "ofType": null
},
"isDeprecated": false,
"deprecationReason": null
@@ -48037,6 +52923,118 @@
},
{
"kind": "OBJECT",
+ "name": "SnippetBlobConnection",
+ "description": "The connection type for SnippetBlob.",
+ "fields": [
+ {
+ "name": "edges",
+ "description": "A list of edges.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "SnippetBlobEdge",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "nodes",
+ "description": "A list of nodes.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "SnippetBlob",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "pageInfo",
+ "description": "Information to aid in pagination.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "PageInfo",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "SnippetBlobEdge",
+ "description": "An edge in a connection.",
+ "fields": [
+ {
+ "name": "cursor",
+ "description": "A cursor for use in pagination.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "node",
+ "description": "The item at the end of the edge.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "SnippetBlob",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
"name": "SnippetBlobViewer",
"description": "Represents how the blob content should be displayed",
"fields": [
@@ -48414,23 +53412,47 @@
{
"name": "updated_desc",
"description": "Updated at descending order",
+ "isDeprecated": true,
+ "deprecationReason": "Use UPDATED_DESC. Deprecated in 13.5"
+ },
+ {
+ "name": "updated_asc",
+ "description": "Updated at ascending order",
+ "isDeprecated": true,
+ "deprecationReason": "Use UPDATED_ASC. Deprecated in 13.5"
+ },
+ {
+ "name": "created_desc",
+ "description": "Created at descending order",
+ "isDeprecated": true,
+ "deprecationReason": "Use CREATED_DESC. Deprecated in 13.5"
+ },
+ {
+ "name": "created_asc",
+ "description": "Created at ascending order",
+ "isDeprecated": true,
+ "deprecationReason": "Use CREATED_ASC. Deprecated in 13.5"
+ },
+ {
+ "name": "UPDATED_DESC",
+ "description": "Updated at descending order",
"isDeprecated": false,
"deprecationReason": null
},
{
- "name": "updated_asc",
+ "name": "UPDATED_ASC",
"description": "Updated at ascending order",
"isDeprecated": false,
"deprecationReason": null
},
{
- "name": "created_desc",
+ "name": "CREATED_DESC",
"description": "Created at descending order",
"isDeprecated": false,
"deprecationReason": null
},
{
- "name": "created_asc",
+ "name": "CREATED_ASC",
"description": "Created at ascending order",
"isDeprecated": false,
"deprecationReason": null
@@ -48439,6 +53461,89 @@
"possibleTypes": null
},
{
+ "kind": "OBJECT",
+ "name": "StatusAction",
+ "description": null,
+ "fields": [
+ {
+ "name": "buttonTitle",
+ "description": "Title for the button, for example: Retry this job",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "icon",
+ "description": "Icon used in the action button",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "method",
+ "description": "Method for the action, for example: :post",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "path",
+ "description": "Path for the action",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "title",
+ "description": "Title for the action, for example: Retry",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
"kind": "SCALAR",
"name": "String",
"description": "Represents textual data as UTF-8 character sequences. This type is most often used by GraphQL to represent free-form human-readable text.",
@@ -48764,12 +53869,237 @@
},
{
"kind": "OBJECT",
- "name": "TerraformStateRegistry",
- "description": "Represents the sync and verification state of a terraform state",
+ "name": "TerraformState",
+ "description": null,
+ "fields": [
+ {
+ "name": "createdAt",
+ "description": "Timestamp the Terraform state was created",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "id",
+ "description": "ID of the Terraform state",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "lockedAt",
+ "description": "Timestamp the Terraform state was locked",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "lockedByUser",
+ "description": "The user currently holding a lock on the Terraform state",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "User",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "name",
+ "description": "Name of the Terraform state",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "updatedAt",
+ "description": "Timestamp the Terraform state was updated",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "TerraformStateConnection",
+ "description": "The connection type for TerraformState.",
+ "fields": [
+ {
+ "name": "edges",
+ "description": "A list of edges.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "TerraformStateEdge",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "nodes",
+ "description": "A list of nodes.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "TerraformState",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "pageInfo",
+ "description": "Information to aid in pagination.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "PageInfo",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "TerraformStateEdge",
+ "description": "An edge in a connection.",
+ "fields": [
+ {
+ "name": "cursor",
+ "description": "A cursor for use in pagination.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "node",
+ "description": "The item at the end of the edge.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "TerraformState",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "TerraformStateVersionRegistry",
+ "description": "Represents the Geo sync and verification state of a terraform state version",
"fields": [
{
"name": "createdAt",
- "description": "Timestamp when the TerraformStateRegistry was created",
+ "description": "Timestamp when the TerraformStateVersionRegistry was created",
"args": [
],
@@ -48783,7 +54113,7 @@
},
{
"name": "id",
- "description": "ID of the TerraformStateRegistry",
+ "description": "ID of the TerraformStateVersionRegistry",
"args": [
],
@@ -48801,7 +54131,7 @@
},
{
"name": "lastSyncFailure",
- "description": "Error message during sync of the TerraformStateRegistry",
+ "description": "Error message during sync of the TerraformStateVersionRegistry",
"args": [
],
@@ -48815,7 +54145,7 @@
},
{
"name": "lastSyncedAt",
- "description": "Timestamp of the most recent successful sync of the TerraformStateRegistry",
+ "description": "Timestamp of the most recent successful sync of the TerraformStateVersionRegistry",
"args": [
],
@@ -48829,7 +54159,7 @@
},
{
"name": "retryAt",
- "description": "Timestamp after which the TerraformStateRegistry should be resynced",
+ "description": "Timestamp after which the TerraformStateVersionRegistry should be resynced",
"args": [
],
@@ -48843,7 +54173,7 @@
},
{
"name": "retryCount",
- "description": "Number of consecutive failed sync attempts of the TerraformStateRegistry",
+ "description": "Number of consecutive failed sync attempts of the TerraformStateVersionRegistry",
"args": [
],
@@ -48857,7 +54187,7 @@
},
{
"name": "state",
- "description": "Sync state of the TerraformStateRegistry",
+ "description": "Sync state of the TerraformStateVersionRegistry",
"args": [
],
@@ -48870,8 +54200,8 @@
"deprecationReason": null
},
{
- "name": "terraformStateId",
- "description": "ID of the TerraformState",
+ "name": "terraformStateVersionId",
+ "description": "ID of the terraform state version",
"args": [
],
@@ -48897,8 +54227,8 @@
},
{
"kind": "OBJECT",
- "name": "TerraformStateRegistryConnection",
- "description": "The connection type for TerraformStateRegistry.",
+ "name": "TerraformStateVersionRegistryConnection",
+ "description": "The connection type for TerraformStateVersionRegistry.",
"fields": [
{
"name": "edges",
@@ -48911,7 +54241,7 @@
"name": null,
"ofType": {
"kind": "OBJECT",
- "name": "TerraformStateRegistryEdge",
+ "name": "TerraformStateVersionRegistryEdge",
"ofType": null
}
},
@@ -48929,7 +54259,7 @@
"name": null,
"ofType": {
"kind": "OBJECT",
- "name": "TerraformStateRegistry",
+ "name": "TerraformStateVersionRegistry",
"ofType": null
}
},
@@ -48964,7 +54294,7 @@
},
{
"kind": "OBJECT",
- "name": "TerraformStateRegistryEdge",
+ "name": "TerraformStateVersionRegistryEdge",
"description": "An edge in a connection.",
"fields": [
{
@@ -48993,7 +54323,7 @@
],
"type": {
"kind": "OBJECT",
- "name": "TerraformStateRegistry",
+ "name": "TerraformStateVersionRegistry",
"ofType": null
},
"isDeprecated": false,
@@ -49278,6 +54608,45 @@
]
},
{
+ "kind": "INPUT_OBJECT",
+ "name": "Timeframe",
+ "description": "A time-frame defined as a closed inclusive range of two dates",
+ "fields": null,
+ "inputFields": [
+ {
+ "name": "start",
+ "description": "The start of the range",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Date",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "end",
+ "description": "The end of the range",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Date",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ }
+ ],
+ "interfaces": null,
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
"kind": "OBJECT",
"name": "Timelog",
"description": null,
@@ -49831,6 +55200,16 @@
"possibleTypes": null
},
{
+ "kind": "SCALAR",
+ "name": "TodoID",
+ "description": "Identifier of Todo",
+ "fields": null,
+ "inputFields": null,
+ "interfaces": null,
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
"kind": "INPUT_OBJECT",
"name": "TodoMarkDoneInput",
"description": "Autogenerated input type of TodoMarkDone",
@@ -49844,7 +55223,7 @@
"name": null,
"ofType": {
"kind": "SCALAR",
- "name": "ID",
+ "name": "TodoID",
"ofType": null
}
},
@@ -49950,7 +55329,7 @@
"name": null,
"ofType": {
"kind": "SCALAR",
- "name": "ID",
+ "name": "TodoID",
"ofType": null
}
},
@@ -49991,7 +55370,7 @@
"name": null,
"ofType": {
"kind": "SCALAR",
- "name": "ID",
+ "name": "TodoID",
"ofType": null
}
}
@@ -50400,7 +55779,7 @@
"name": null,
"ofType": {
"kind": "SCALAR",
- "name": "ID",
+ "name": "AwardableID",
"ofType": null
}
},
@@ -51176,6 +56555,136 @@
},
{
"kind": "INPUT_OBJECT",
+ "name": "UpdateBoardEpicUserPreferencesInput",
+ "description": "Autogenerated input type of UpdateBoardEpicUserPreferences",
+ "fields": null,
+ "inputFields": [
+ {
+ "name": "boardId",
+ "description": "The board global ID",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "BoardID",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "epicId",
+ "description": "ID of an epic to set preferences for",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "EpicID",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "collapsed",
+ "description": "Whether the epic should be collapsed in the board",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "clientMutationId",
+ "description": "A unique identifier for the client performing the mutation.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "interfaces": null,
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "UpdateBoardEpicUserPreferencesPayload",
+ "description": "Autogenerated return type of UpdateBoardEpicUserPreferences",
+ "fields": [
+ {
+ "name": "clientMutationId",
+ "description": "A unique identifier for the client performing the mutation.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "epicUserPreferences",
+ "description": "User preferences for the epic in the board after mutation",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "BoardEpicUserPreferences",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "errors",
+ "description": "Errors encountered during execution of the mutation.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ }
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "INPUT_OBJECT",
"name": "UpdateBoardInput",
"description": "Autogenerated input type of UpdateBoard",
"fields": null,
@@ -51188,7 +56697,7 @@
"name": null,
"ofType": {
"kind": "SCALAR",
- "name": "ID",
+ "name": "BoardID",
"ofType": null
}
},
@@ -51229,7 +56738,7 @@
"description": "The id of user to be assigned to the board.",
"type": {
"kind": "SCALAR",
- "name": "ID",
+ "name": "UserID",
"ofType": null
},
"defaultValue": null
@@ -51239,7 +56748,7 @@
"description": "The id of milestone to be assigned to the board.",
"type": {
"kind": "SCALAR",
- "name": "ID",
+ "name": "MilestoneID",
"ofType": null
},
"defaultValue": null
@@ -51255,6 +56764,42 @@
"defaultValue": null
},
{
+ "name": "labels",
+ "description": "Labels of the issue",
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "labelIds",
+ "description": "The IDs of labels to be added to the board.",
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "LabelID",
+ "ofType": null
+ }
+ }
+ },
+ "defaultValue": null
+ },
+ {
"name": "clientMutationId",
"description": "A unique identifier for the client performing the mutation.",
"type": {
@@ -51917,7 +57462,7 @@
"name": null,
"ofType": {
"kind": "SCALAR",
- "name": "ID",
+ "name": "NoteID",
"ofType": null
}
},
@@ -52060,16 +57605,6 @@
"defaultValue": null
},
{
- "name": "title",
- "description": "Title of the issue",
- "type": {
- "kind": "SCALAR",
- "name": "String",
- "ofType": null
- },
- "defaultValue": null
- },
- {
"name": "description",
"description": "Description of the issue",
"type": {
@@ -52084,7 +57619,7 @@
"description": "Due date of the issue",
"type": {
"kind": "SCALAR",
- "name": "Time",
+ "name": "ISO8601Date",
"ofType": null
},
"defaultValue": null
@@ -52110,8 +57645,28 @@
"defaultValue": null
},
{
+ "name": "title",
+ "description": "Title of the issue",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "milestoneId",
+ "description": "The ID of the milestone to assign to the issue. On update milestone will be removed if set to null",
+ "type": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
"name": "addLabelIds",
- "description": "The IDs of labels to be added to the issue.",
+ "description": "The IDs of labels to be added to the issue",
"type": {
"kind": "LIST",
"name": null,
@@ -52129,7 +57684,7 @@
},
{
"name": "removeLabelIds",
- "description": "The IDs of labels to be removed from the issue.",
+ "description": "The IDs of labels to be removed from the issue",
"type": {
"kind": "LIST",
"name": null,
@@ -52146,11 +57701,11 @@
"defaultValue": null
},
{
- "name": "milestoneId",
- "description": "The ID of the milestone to be assigned, milestone will be removed if set to null.",
+ "name": "stateEvent",
+ "description": "Close or reopen an issue",
"type": {
- "kind": "SCALAR",
- "name": "ID",
+ "kind": "ENUM",
+ "name": "IssueStateEvent",
"ofType": null
},
"defaultValue": null
@@ -52166,6 +57721,16 @@
"defaultValue": null
},
{
+ "name": "weight",
+ "description": "The weight of the issue",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
"name": "epicId",
"description": "The ID of the parent epic. NULL when removing the association",
"type": {
@@ -52427,7 +57992,7 @@
"name": null,
"ofType": {
"kind": "SCALAR",
- "name": "ID",
+ "name": "NoteID",
"ofType": null
}
},
@@ -52552,38 +58117,48 @@
"defaultValue": null
},
{
- "name": "state",
- "description": "State of the requirement",
+ "name": "description",
+ "description": "Description of the requirement",
"type": {
- "kind": "ENUM",
- "name": "RequirementState",
+ "kind": "SCALAR",
+ "name": "String",
"ofType": null
},
"defaultValue": null
},
{
- "name": "iid",
- "description": "The iid of the requirement to update",
+ "name": "projectPath",
+ "description": "Full project path the requirement is associated with",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
- "name": "String",
+ "name": "ID",
"ofType": null
}
},
"defaultValue": null
},
{
- "name": "projectPath",
- "description": "The project full path the requirement is associated with",
+ "name": "state",
+ "description": "State of the requirement",
+ "type": {
+ "kind": "ENUM",
+ "name": "RequirementState",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "iid",
+ "description": "The iid of the requirement to update",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
- "name": "ID",
+ "name": "String",
"ofType": null
}
},
@@ -52661,7 +58236,7 @@
},
{
"name": "requirement",
- "description": "The requirement after mutation",
+ "description": "Requirement after mutation",
"args": [
],
@@ -52822,6 +58397,20 @@
},
"isDeprecated": false,
"deprecationReason": null
+ },
+ {
+ "name": "spam",
+ "description": "Indicates whether the operation returns a record detected as spam",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
}
],
"inputFields": null,
@@ -52993,6 +58582,16 @@
"defaultValue": null
},
{
+ "name": "authorUsername",
+ "description": "Username of the author",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
"name": "after",
"description": "Returns the elements in the list that come after the specified cursor.",
"type": {
@@ -53188,6 +58787,16 @@
"defaultValue": null
},
{
+ "name": "assigneeUsername",
+ "description": "Username of the assignee",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
"name": "after",
"description": "Returns the elements in the list that come after the specified cursor.",
"type": {
@@ -54606,6 +60215,63 @@
"deprecationReason": null
},
{
+ "name": "discussions",
+ "description": "All discussions on this noteable",
+ "args": [
+ {
+ "name": "after",
+ "description": "Returns the elements in the list that come after the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "before",
+ "description": "Returns the elements in the list that come before the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "first",
+ "description": "Returns the first _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "last",
+ "description": "Returns the last _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "DiscussionConnection",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
"name": "id",
"description": "GraphQL ID of the vulnerability",
"args": [
@@ -54731,6 +60397,63 @@
"deprecationReason": null
},
{
+ "name": "notes",
+ "description": "All notes on this noteable",
+ "args": [
+ {
+ "name": "after",
+ "description": "Returns the elements in the list that come after the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "before",
+ "description": "Returns the elements in the list that come before the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "first",
+ "description": "Returns the first _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "last",
+ "description": "Returns the last _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "NoteConnection",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
"name": "primaryIdentifier",
"description": "Primary identifier of the vulnerability.",
"args": [
@@ -54760,7 +60483,7 @@
},
{
"name": "reportType",
- "description": "Type of the security report that found the vulnerability (SAST, DEPENDENCY_SCANNING, CONTAINER_SCANNING, DAST, SECRET_DETECTION, COVERAGE_FUZZING)",
+ "description": "Type of the security report that found the vulnerability (SAST, DEPENDENCY_SCANNING, CONTAINER_SCANNING, DAST, SECRET_DETECTION, COVERAGE_FUZZING, API_FUZZING)",
"args": [
],
@@ -54820,7 +60543,7 @@
},
{
"name": "state",
- "description": "State of the vulnerability (DETECTED, DISMISSED, RESOLVED, CONFIRMED)",
+ "description": "State of the vulnerability (DETECTED, CONFIRMED, RESOLVED, DISMISSED)",
"args": [
],
@@ -54899,6 +60622,112 @@
],
"inputFields": null,
"interfaces": [
+ {
+ "kind": "INTERFACE",
+ "name": "Noteable",
+ "ofType": null
+ }
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "INPUT_OBJECT",
+ "name": "VulnerabilityConfirmInput",
+ "description": "Autogenerated input type of VulnerabilityConfirm",
+ "fields": null,
+ "inputFields": [
+ {
+ "name": "id",
+ "description": "ID of the vulnerability to be confirmed",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "VulnerabilityID",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "clientMutationId",
+ "description": "A unique identifier for the client performing the mutation.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "interfaces": null,
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "VulnerabilityConfirmPayload",
+ "description": "Autogenerated return type of VulnerabilityConfirm",
+ "fields": [
+ {
+ "name": "clientMutationId",
+ "description": "A unique identifier for the client performing the mutation.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "errors",
+ "description": "Errors encountered during execution of the mutation.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ }
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "vulnerability",
+ "description": "The vulnerability after state change",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "Vulnerability",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
],
"enumValues": null,
@@ -54972,6 +60801,118 @@
"possibleTypes": null
},
{
+ "kind": "INPUT_OBJECT",
+ "name": "VulnerabilityDismissInput",
+ "description": "Autogenerated input type of VulnerabilityDismiss",
+ "fields": null,
+ "inputFields": [
+ {
+ "name": "id",
+ "description": "ID of the vulnerability to be dismissed",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "VulnerabilityID",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "comment",
+ "description": "Reason why vulnerability should be dismissed",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "clientMutationId",
+ "description": "A unique identifier for the client performing the mutation.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "interfaces": null,
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "VulnerabilityDismissPayload",
+ "description": "Autogenerated return type of VulnerabilityDismiss",
+ "fields": [
+ {
+ "name": "clientMutationId",
+ "description": "A unique identifier for the client performing the mutation.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "errors",
+ "description": "Errors encountered during execution of the mutation.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ }
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "vulnerability",
+ "description": "The vulnerability after dismissal",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "Vulnerability",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
"kind": "OBJECT",
"name": "VulnerabilityEdge",
"description": "An edge in a connection.",
@@ -55993,6 +61934,12 @@
"description": null,
"isDeprecated": false,
"deprecationReason": null
+ },
+ {
+ "name": "API_FUZZING",
+ "description": null,
+ "isDeprecated": false,
+ "deprecationReason": null
}
],
"possibleTypes": null
@@ -56005,7 +61952,7 @@
"inputFields": [
{
"name": "id",
- "description": "ID of the vulnerability to be resolveed",
+ "description": "ID of the vulnerability to be resolved",
"type": {
"kind": "NON_NULL",
"name": null,
@@ -56100,6 +62047,108 @@
"possibleTypes": null
},
{
+ "kind": "INPUT_OBJECT",
+ "name": "VulnerabilityRevertToDetectedInput",
+ "description": "Autogenerated input type of VulnerabilityRevertToDetected",
+ "fields": null,
+ "inputFields": [
+ {
+ "name": "id",
+ "description": "ID of the vulnerability to be reverted",
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "VulnerabilityID",
+ "ofType": null
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "clientMutationId",
+ "description": "A unique identifier for the client performing the mutation.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "interfaces": null,
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "VulnerabilityRevertToDetectedPayload",
+ "description": "Autogenerated return type of VulnerabilityRevertToDetected",
+ "fields": [
+ {
+ "name": "clientMutationId",
+ "description": "A unique identifier for the client performing the mutation.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "errors",
+ "description": "Errors encountered during execution of the mutation.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ }
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "vulnerability",
+ "description": "The vulnerability after revert",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "Vulnerability",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
"kind": "OBJECT",
"name": "VulnerabilityScanner",
"description": "Represents a vulnerability scanner",
@@ -56443,6 +62492,54 @@
"description": "Severity in ascending order",
"isDeprecated": false,
"deprecationReason": null
+ },
+ {
+ "name": "title_desc",
+ "description": "Title in descending order",
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "title_asc",
+ "description": "Title in ascending order",
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "detected_desc",
+ "description": "Detection timestamp in descending order",
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "detected_asc",
+ "description": "Detection timestamp in ascending order",
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "report_type_desc",
+ "description": "Report Type in descending order",
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "report_type_asc",
+ "description": "Report Type in ascending order",
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "state_desc",
+ "description": "State in descending order",
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "state_asc",
+ "description": "State in ascending order",
+ "isDeprecated": false,
+ "deprecationReason": null
}
],
"possibleTypes": null
@@ -56462,7 +62559,7 @@
"deprecationReason": null
},
{
- "name": "DISMISSED",
+ "name": "CONFIRMED",
"description": null,
"isDeprecated": false,
"deprecationReason": null
@@ -56474,7 +62571,7 @@
"deprecationReason": null
},
{
- "name": "CONFIRMED",
+ "name": "DISMISSED",
"description": null,
"isDeprecated": false,
"deprecationReason": null
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index fc27298aff2..dca00fc1286 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -77,6 +77,7 @@ Describes an alert from the project's Alert Management.
| `details` | JSON | Alert details |
| `detailsUrl` | String! | The URL of the alert detail page |
| `endedAt` | Time | Timestamp the alert ended |
+| `environment` | Environment | Environment for the alert |
| `eventCount` | Int | Number of events of this alert |
| `hosts` | String! => Array | List of hosts the alert came from |
| `iid` | ID! | Internal ID of the alert |
@@ -209,6 +210,57 @@ Represents a project or group board.
| `name` | String | Name of the board |
| `weight` | Int | Weight of the board. |
+### BoardEpic
+
+Represents an epic on an issue board.
+
+| Field | Type | Description |
+| ----- | ---- | ----------- |
+| `author` | User! | Author of the epic |
+| `closedAt` | Time | Timestamp of when the epic was closed |
+| `confidential` | Boolean | Indicates if the epic is confidential |
+| `createdAt` | Time | Timestamp of when the epic was created |
+| `descendantCounts` | EpicDescendantCount | Number of open and closed descendant epics and issues |
+| `descendantWeightSum` | EpicDescendantWeights | Total weight of open and closed issues in the epic and its descendants |
+| `description` | String | Description of the epic |
+| `downvotes` | Int! | Number of downvotes the epic has received |
+| `dueDate` | Time | Due date of the epic |
+| `dueDateFixed` | Time | Fixed due date of the epic |
+| `dueDateFromMilestones` | Time | Inherited due date of the epic from milestones |
+| `dueDateIsFixed` | Boolean | Indicates if the due date has been manually set |
+| `group` | Group! | Group to which the epic belongs |
+| `hasChildren` | Boolean! | Indicates if the epic has children |
+| `hasIssues` | Boolean! | Indicates if the epic has direct issues |
+| `hasParent` | Boolean! | Indicates if the epic has a parent epic |
+| `healthStatus` | EpicHealthStatus | Current health status of the epic |
+| `id` | ID! | ID of the epic |
+| `iid` | ID! | Internal ID of the epic |
+| `parent` | Epic | Parent epic of the epic |
+| `reference` | String! | Internal reference of the epic. Returned in shortened format by default |
+| `relationPath` | String | URI path of the epic-issue relationship |
+| `relativePosition` | Int | The relative position of the epic in the epic tree |
+| `startDate` | Time | Start date of the epic |
+| `startDateFixed` | Time | Fixed start date of the epic |
+| `startDateFromMilestones` | Time | Inherited start date of the epic from milestones |
+| `startDateIsFixed` | Boolean | Indicates if the start date has been manually set |
+| `state` | EpicState! | State of the epic |
+| `subscribed` | Boolean! | Indicates the currently logged in user is subscribed to the epic |
+| `title` | String | Title of the epic |
+| `updatedAt` | Time | Timestamp of when the epic was updated |
+| `upvotes` | Int! | Number of upvotes the epic has received |
+| `userPermissions` | EpicPermissions! | Permissions for the current user on the resource |
+| `userPreferences` | BoardEpicUserPreferences | User preferences for the epic on the issue board |
+| `webPath` | String! | Web path of the epic |
+| `webUrl` | String! | Web URL of the epic |
+
+### BoardEpicUserPreferences
+
+Represents user preferences for a board epic.
+
+| Field | Type | Description |
+| ----- | ---- | ----------- |
+| `collapsed` | Boolean! | Indicates epic should be displayed as collapsed |
+
### BoardList
Represents a list for an issue board.
@@ -272,6 +324,7 @@ Represents the total number of issues and their weights for a particular day.
| Field | Type | Description |
| ----- | ---- | ----------- |
+| `detailedStatus` | DetailedStatus | Detailed status of the group |
| `name` | String | Name of the job group |
| `size` | Int | Size of the group |
@@ -279,12 +332,15 @@ Represents the total number of issues and their weights for a particular day.
| Field | Type | Description |
| ----- | ---- | ----------- |
+| `detailedStatus` | DetailedStatus | Detailed status of the job |
| `name` | String | Name of the job |
+| `scheduledAt` | Time | Schedule for the build |
### CiStage
| Field | Type | Description |
| ----- | ---- | ----------- |
+| `detailedStatus` | DetailedStatus | Detailed status of the stage |
| `name` | String | Name of the stage |
### ClusterAgent
@@ -421,6 +477,16 @@ Autogenerated return type of CreateAnnotation.
| `clientMutationId` | String | A unique identifier for the client performing the mutation. |
| `errors` | String! => Array | Errors encountered during execution of the mutation. |
+### CreateBoardPayload
+
+Autogenerated return type of CreateBoard.
+
+| Field | Type | Description |
+| ----- | ---- | ----------- |
+| `board` | Board | The board after mutation. |
+| `clientMutationId` | String | A unique identifier for the client performing the mutation. |
+| `errors` | String! => Array | Errors encountered during execution of the mutation. |
+
### CreateBranchPayload
Autogenerated return type of CreateBranch.
@@ -471,6 +537,16 @@ Autogenerated return type of CreateImageDiffNote.
| `errors` | String! => Array | Errors encountered during execution of the mutation. |
| `note` | Note | The note after mutation |
+### CreateIssuePayload
+
+Autogenerated return type of CreateIssue.
+
+| Field | Type | Description |
+| ----- | ---- | ----------- |
+| `clientMutationId` | String | A unique identifier for the client performing the mutation. |
+| `errors` | String! => Array | Errors encountered during execution of the mutation. |
+| `issue` | Issue | The issue after mutation |
+
### CreateIterationPayload
Autogenerated return type of CreateIteration.
@@ -499,7 +575,7 @@ Autogenerated return type of CreateRequirement.
| ----- | ---- | ----------- |
| `clientMutationId` | String | A unique identifier for the client performing the mutation. |
| `errors` | String! => Array | Errors encountered during execution of the mutation. |
-| `requirement` | Requirement | The requirement after mutation |
+| `requirement` | Requirement | Requirement after mutation |
### CreateSnippetPayload
@@ -510,6 +586,7 @@ Autogenerated return type of CreateSnippet.
| `clientMutationId` | String | A unique identifier for the client performing the mutation. |
| `errors` | String! => Array | Errors encountered during execution of the mutation. |
| `snippet` | Snippet | The snippet after mutation |
+| `spam` | Boolean | Indicates whether the operation returns a record detected as spam |
### CreateTestCasePayload
@@ -541,8 +618,11 @@ Represents a DAST scanner profile.
| `globalId` | DastScannerProfileID! | ID of the DAST scanner profile |
| `id` **{warning-solid}** | ID! | **Deprecated:** Use `global_id`. Deprecated in 13.4 |
| `profileName` | String | Name of the DAST scanner profile |
+| `scanType` | DastScanTypeEnum | Indicates the type of DAST scan that will run. Either a Passive Scan or an Active Scan. |
+| `showDebugMessages` | Boolean! | Indicates if debug messages should be included in DAST console output. True to include the debug messages. |
| `spiderTimeout` | Int | The maximum number of minutes allowed for the spider to traverse the site |
| `targetTimeout` | Int | The maximum number of seconds allowed for the site under test to respond to a request |
+| `useAjaxSpider` | Boolean! | Indicates if the AJAX spider should be used to crawl the target site. True to run the AJAX spider in addition to the traditional spider, and false to run only the traditional spider. |
### DastScannerProfileCreatePayload
@@ -624,6 +704,18 @@ Autogenerated return type of DastSiteProfileUpdate.
| `errors` | String! => Array | Errors encountered during execution of the mutation. |
| `id` | DastSiteProfileID | ID of the site profile. |
+### DastSiteTokenCreatePayload
+
+Autogenerated return type of DastSiteTokenCreate.
+
+| Field | Type | Description |
+| ----- | ---- | ----------- |
+| `clientMutationId` | String | A unique identifier for the client performing the mutation. |
+| `errors` | String! => Array | Errors encountered during execution of the mutation. |
+| `id` | DastSiteTokenID | ID of the site token. |
+| `status` | DastSiteProfileValidationStatusEnum | The current validation status of the target. |
+| `token` | String | Token string. |
+
### DeleteAnnotationPayload
Autogenerated return type of DeleteAnnotation.
@@ -685,6 +777,7 @@ A collection of designs.
| Field | Type | Description |
| ----- | ---- | ----------- |
+| `copyState` | DesignCollectionCopyState | Copy state of the design collection |
| `design` | Design | Find a specific design |
| `designAtVersion` | DesignAtVersion | Find a design as of a version |
| `issue` | Issue! | Issue associated with the design collection |
@@ -739,6 +832,16 @@ A specific version in which designs were added, modified or deleted.
| `id` | ID! | ID of the design version |
| `sha` | ID! | SHA of the design version |
+### DestroyBoardListPayload
+
+Autogenerated return type of DestroyBoardList.
+
+| Field | Type | Description |
+| ----- | ---- | ----------- |
+| `clientMutationId` | String | A unique identifier for the client performing the mutation. |
+| `errors` | String! => Array | Errors encountered during execution of the mutation. |
+| `list` | BoardList | The list after mutation. |
+
### DestroyBoardPayload
Autogenerated return type of DestroyBoard.
@@ -773,14 +876,15 @@ Autogenerated return type of DestroySnippet.
| Field | Type | Description |
| ----- | ---- | ----------- |
-| `detailsPath` | String! | Path of the details for the pipeline status |
-| `favicon` | String! | Favicon of the pipeline status |
-| `group` | String! | Group of the pipeline status |
-| `hasDetails` | Boolean! | Indicates if the pipeline status has further details |
-| `icon` | String! | Icon of the pipeline status |
-| `label` | String! | Label of the pipeline status |
-| `text` | String! | Text of the pipeline status |
-| `tooltip` | String! | Tooltip associated with the pipeline status |
+| `action` | StatusAction | Action information for the status. This includes method, button title, icon, path, and title |
+| `detailsPath` | String | Path of the details for the status |
+| `favicon` | String | Favicon of the status |
+| `group` | String | Group of the status |
+| `hasDetails` | Boolean | Indicates if the status has further details |
+| `icon` | String | Icon of the status |
+| `label` | String | Label of the status |
+| `text` | String | Text of the status |
+| `tooltip` | String | Tooltip associated with the status |
### DiffPosition
@@ -866,9 +970,10 @@ Describes where code is deployed for a project.
| Field | Type | Description |
| ----- | ---- | ----------- |
| `id` | ID! | ID of the environment |
-| `latestOpenedMostSevereAlert` | AlertManagementAlert | The most severe open alert for the environment. If multiple alerts have equal severity, the most recent is returned. |
+| `latestOpenedMostSevereAlert` | AlertManagementAlert | The most severe open alert for the environment. If multiple alerts have equal severity, the most recent is returned |
| `metricsDashboard` | MetricsDashboard | Metrics dashboard schema for the environment |
| `name` | String! | Human-readable name of the environment |
+| `path` | String | The path to the environment. Will always return null if `expose_environment_path_in_alert_details` feature flag is disabled |
| `state` | String! | State of the environment, for example: available/stopped |
### Epic
@@ -878,9 +983,9 @@ Represents an epic.
| Field | Type | Description |
| ----- | ---- | ----------- |
| `author` | User! | Author of the epic |
-| `closedAt` | Time | Timestamp of the epic's closure |
+| `closedAt` | Time | Timestamp of when the epic was closed |
| `confidential` | Boolean | Indicates if the epic is confidential |
-| `createdAt` | Time | Timestamp of the epic's creation |
+| `createdAt` | Time | Timestamp of when the epic was created |
| `descendantCounts` | EpicDescendantCount | Number of open and closed descendant epics and issues |
| `descendantWeightSum` | EpicDescendantWeights | Total weight of open and closed issues in the epic and its descendants |
| `description` | String | Description of the epic |
@@ -907,7 +1012,7 @@ Represents an epic.
| `state` | EpicState! | State of the epic |
| `subscribed` | Boolean! | Indicates the currently logged in user is subscribed to the epic |
| `title` | String | Title of the epic |
-| `updatedAt` | Time | Timestamp of the epic's last activity |
+| `updatedAt` | Time | Timestamp of when the epic was updated |
| `upvotes` | Int! | Number of upvotes the epic has received |
| `userPermissions` | EpicPermissions! | Permissions for the current user on the resource |
| `webPath` | String! | Web path of the epic |
@@ -984,6 +1089,7 @@ Relationship between an epic and an issue.
| `relationPath` | String | URI path of the epic-issue relation |
| `relativePosition` | Int | Relative position of the issue (used for positioning in epic tree and issue boards) |
| `severity` | IssuableSeverity | Severity level of the incident |
+| `slaDueAt` | Time | Timestamp of when the issue SLA expires. |
| `state` | IssueState! | State of the issue |
| `statusPagePublishedIncident` | Boolean | Indicates whether an issue is published to the status page |
| `subscribed` | Boolean! | Indicates the currently logged in user is subscribed to the issue |
@@ -1069,9 +1175,12 @@ Autogenerated return type of EpicTreeReorder.
| Field | Type | Description |
| ----- | ---- | ----------- |
+| `actualRepositorySizeLimit` | Float | Size limit for repositories in the namespace in bytes |
+| `additionalPurchasedStorageSize` | Float | Additional storage purchased for the root namespace in bytes |
| `autoDevopsEnabled` | Boolean | Indicates whether Auto DevOps is enabled for all projects within this group |
| `avatarUrl` | String | Avatar URL of the group |
| `board` | Board | A single board of the group |
+| `containsLockedProjects` | Boolean! | Includes at least one project where the repository size exceeds the limit |
| `description` | String | Description of the namespace |
| `descriptionHtml` | String | The GitLab Flavored Markdown rendering of `description` |
| `emailsDisabled` | Boolean | Indicates if a group has email notifications disabled |
@@ -1089,6 +1198,7 @@ Autogenerated return type of EpicTreeReorder.
| `parent` | Group | Parent group |
| `path` | String! | Path of the namespace |
| `projectCreationLevel` | String | The permission level required to create projects in the group |
+| `repositorySizeExcessProjectCount` | Int! | Number of projects in the root namespace where the repository size exceeds the limit |
| `requestAccessEnabled` | Boolean | Indicates if users can request access to namespace |
| `requireTwoFactorAuthentication` | Boolean | Indicates if all users in this group are required to set up two-factor authentication |
| `rootStorageStatistics` | RootStorageStatistics | Aggregated storage statistics of the namespace. Only available for root namespaces |
@@ -1096,6 +1206,8 @@ Autogenerated return type of EpicTreeReorder.
| `storageSizeLimit` | Float | Total storage limit of the root namespace in bytes |
| `subgroupCreationLevel` | String | The permission level required to create subgroups within the group |
| `temporaryStorageIncreaseEndsOn` | Time | Date until the temporary storage increase is active |
+| `totalRepositorySize` | Float | Total repository size of all projects in the root namespace in bytes |
+| `totalRepositorySizeExcess` | Float | Total excess repository size of all projects in the root namespace in bytes |
| `twoFactorGracePeriod` | Int | Time before two-factor authentication is enforced |
| `userPermissions` | GroupPermissions! | Permissions for the current user on the resource |
| `visibility` | String | Visibility of the namespace |
@@ -1168,6 +1280,7 @@ Represents a recorded measurement (object count) for the Admins.
| `reference` | String! | Internal reference of the issue. Returned in shortened format by default |
| `relativePosition` | Int | Relative position of the issue (used for positioning in epic tree and issue boards) |
| `severity` | IssuableSeverity | Severity level of the incident |
+| `slaDueAt` | Time | Timestamp of when the issue SLA expires. |
| `state` | IssueState! | State of the issue |
| `statusPagePublishedIncident` | Boolean | Indicates whether an issue is published to the status page |
| `subscribed` | Boolean! | Indicates the currently logged in user is subscribed to the issue |
@@ -1195,6 +1308,16 @@ Autogenerated return type of IssueMoveList.
| `errors` | String! => Array | Errors encountered during execution of the mutation. |
| `issue` | Issue | The issue after mutation |
+### IssueMovePayload
+
+Autogenerated return type of IssueMove.
+
+| Field | Type | Description |
+| ----- | ---- | ----------- |
+| `clientMutationId` | String | A unique identifier for the client performing the mutation. |
+| `errors` | String! => Array | Errors encountered during execution of the mutation. |
+| `issue` | Issue | The issue after mutation |
+
### IssuePermissions
Check permissions for the current user on a issue.
@@ -1486,6 +1609,21 @@ Autogenerated return type of MergeRequestCreate.
| `errors` | String! => Array | Errors encountered during execution of the mutation. |
| `mergeRequest` | MergeRequest | The merge request after mutation |
+### MergeRequestDiffRegistry
+
+Represents the Geo sync and verification state of a Merge Request diff.
+
+| Field | Type | Description |
+| ----- | ---- | ----------- |
+| `createdAt` | Time | Timestamp when the MergeRequestDiffRegistry was created |
+| `id` | ID! | ID of the MergeRequestDiffRegistry |
+| `lastSyncFailure` | String | Error message during sync of the MergeRequestDiffRegistry |
+| `lastSyncedAt` | Time | Timestamp of the most recent successful sync of the MergeRequestDiffRegistry |
+| `mergeRequestDiffId` | ID! | ID of the Merge Request diff |
+| `retryAt` | Time | Timestamp after which the MergeRequestDiffRegistry should be resynced |
+| `retryCount` | Int | Number of consecutive failed sync attempts of the MergeRequestDiffRegistry |
+| `state` | RegistryState | Sync state of the MergeRequestDiffRegistry |
+
### MergeRequestPermissions
Check permissions for the current user on a merge request.
@@ -1630,6 +1768,9 @@ Contains statistics about a milestone.
| Field | Type | Description |
| ----- | ---- | ----------- |
+| `actualRepositorySizeLimit` | Float | Size limit for repositories in the namespace in bytes |
+| `additionalPurchasedStorageSize` | Float | Additional storage purchased for the root namespace in bytes |
+| `containsLockedProjects` | Boolean! | Includes at least one project where the repository size exceeds the limit |
| `description` | String | Description of the namespace |
| `descriptionHtml` | String | The GitLab Flavored Markdown rendering of `description` |
| `fullName` | String! | Full name of the namespace |
@@ -1639,10 +1780,13 @@ Contains statistics about a milestone.
| `lfsEnabled` | Boolean | Indicates if Large File Storage (LFS) is enabled for namespace |
| `name` | String! | Name of the namespace |
| `path` | String! | Path of the namespace |
+| `repositorySizeExcessProjectCount` | Int! | Number of projects in the root namespace where the repository size exceeds the limit |
| `requestAccessEnabled` | Boolean | Indicates if users can request access to namespace |
| `rootStorageStatistics` | RootStorageStatistics | Aggregated storage statistics of the namespace. Only available for root namespaces |
| `storageSizeLimit` | Float | Total storage limit of the root namespace in bytes |
| `temporaryStorageIncreaseEndsOn` | Time | Date until the temporary storage increase is active |
+| `totalRepositorySize` | Float | Total repository size of all projects in the root namespace in bytes |
+| `totalRepositorySizeExcess` | Float | Total excess repository size of all projects in the root namespace in bytes |
| `visibility` | String | Visibility of the namespace |
### NamespaceIncreaseStorageTemporarilyPayload
@@ -1702,7 +1846,7 @@ Represents a package.
### PackageFileRegistry
-Represents the sync and verification state of a package file.
+Represents the Geo sync and verification state of a package file.
| Field | Type | Description |
| ----- | ---- | ----------- |
@@ -1790,6 +1934,7 @@ Autogenerated return type of PipelineRetry.
| Field | Type | Description |
| ----- | ---- | ----------- |
+| `actualRepositorySizeLimit` | Float | Size limit for the repository in bytes |
| `alertManagementAlert` | AlertManagementAlert | A single Alert Management alert of the project |
| `alertManagementAlertStatusCounts` | AlertManagementAlertStatusCountsType | Counts of alerts by status for the project |
| `allowMergeOnSkippedPipeline` | Boolean | If `only_allow_merge_if_pipeline_succeeds` is true, indicates if merge requests of the project can also be merged with skipped jobs |
@@ -1836,8 +1981,9 @@ Autogenerated return type of PipelineRetry.
| `release` | Release | A single release of the project |
| `removeSourceBranchAfterMerge` | Boolean | Indicates if `Delete source branch` option should be enabled by default for all new merge requests of the project |
| `repository` | Repository | Git repository of the project |
+| `repositorySizeExcess` | Float | Size of repository that exceeds the limit in bytes |
| `requestAccessEnabled` | Boolean | Indicates if users can request member access to the project |
-| `requirement` | Requirement | Find a single requirement. Available only when feature flag `requirements_management` is enabled. |
+| `requirement` | Requirement | Find a single requirement |
| `requirementStatesCount` | RequirementStatesCount | Number of requirements for the project by their state |
| `sastCiConfiguration` | SastCiConfiguration | SAST CI configuration for the project |
| `securityDashboardPath` | String | Path to project's security dashboard |
@@ -2049,12 +2195,16 @@ Represents a requirement.
| ----- | ---- | ----------- |
| `author` | User! | Author of the requirement |
| `createdAt` | Time! | Timestamp of when the requirement was created |
+| `description` | String | Description of the requirement |
+| `descriptionHtml` | String | The GitLab Flavored Markdown rendering of `description` |
| `id` | ID! | ID of the requirement |
| `iid` | ID! | Internal ID of the requirement |
+| `lastTestReportManuallyCreated` | Boolean | Indicates if latest test report was created by user |
| `lastTestReportState` | TestReportState | Latest requirement test report state |
| `project` | Project! | Project to which the requirement belongs |
| `state` | RequirementState! | State of the requirement |
| `title` | String | Title of the requirement |
+| `titleHtml` | String | The GitLab Flavored Markdown rendering of `title` |
| `updatedAt` | Time! | Timestamp of when the requirement was last updated |
| `userPermissions` | RequirementPermissions! | Permissions for the current user on the resource |
@@ -2079,6 +2229,16 @@ Counts of requirements by their state.
| `archived` | Int | Number of archived requirements |
| `opened` | Int | Number of opened requirements |
+### RevertVulnerabilityToDetectedPayload
+
+Autogenerated return type of RevertVulnerabilityToDetected.
+
+| Field | Type | Description |
+| ----- | ---- | ----------- |
+| `clientMutationId` | String | A unique identifier for the client performing the mutation. |
+| `errors` | String! => Array | Errors encountered during execution of the mutation. |
+| `vulnerability` | Vulnerability | The vulnerability after revert |
+
### RootStorageStatistics
| Field | Type | Description |
@@ -2086,6 +2246,7 @@ Counts of requirements by their state.
| `buildArtifactsSize` | Float! | The CI artifacts size in bytes |
| `lfsObjectsSize` | Float! | The LFS objects size in bytes |
| `packagesSize` | Float! | The packages size in bytes |
+| `pipelineArtifactsSize` | Float! | The CI pipeline artifacts size in bytes |
| `repositorySize` | Float! | The Git repository size in bytes |
| `snippetsSize` | Float! | The snippets size in bytes |
| `storageSize` | Float! | The total storage in bytes |
@@ -2101,6 +2262,20 @@ Autogenerated return type of RunDASTScan.
| `errors` | String! => Array | Errors encountered during execution of the mutation. |
| `pipelineUrl` | String | URL of the pipeline that was created. |
+### RunnerArchitecture
+
+| Field | Type | Description |
+| ----- | ---- | ----------- |
+| `downloadLocation` | String! | Download location for the runner for the platform architecture |
+| `name` | String! | Name of the runner platform architecture |
+
+### RunnerPlatform
+
+| Field | Type | Description |
+| ----- | ---- | ----------- |
+| `humanReadableName` | String! | Human readable name of the runner platform |
+| `name` | String! | Name slug of the runner platform |
+
### SastCiConfigurationAnalyzersEntity
Represents an analyzer entity in SAST CI configuration.
@@ -2150,6 +2325,7 @@ Represents summary of a security report.
| Field | Type | Description |
| ----- | ---- | ----------- |
+| `apiFuzzing` | SecurityReportSummarySection | Aggregated counts for the api_fuzzing scan |
| `containerScanning` | SecurityReportSummarySection | Aggregated counts for the container_scanning scan |
| `coverageFuzzing` | SecurityReportSummarySection | Aggregated counts for the coverage_fuzzing scan |
| `dast` | SecurityReportSummarySection | Aggregated counts for the dast scan |
@@ -2302,7 +2478,6 @@ Represents a snippet entry.
| ----- | ---- | ----------- |
| `author` | User | The owner of the snippet |
| `blob` **{warning-solid}** | SnippetBlob! | **Deprecated:** Use `blobs`. Deprecated in 13.3 |
-| `blobs` | SnippetBlob! => Array | Snippet blobs |
| `createdAt` | Time! | Timestamp this snippet was created |
| `description` | String | Description of the snippet |
| `descriptionHtml` | String | The GitLab Flavored Markdown rendering of `description` |
@@ -2362,6 +2537,16 @@ Represents how the blob content should be displayed.
| `reportSnippet` | Boolean! | Indicates the user can perform `report_snippet` on this resource |
| `updateSnippet` | Boolean! | Indicates the user can perform `update_snippet` on this resource |
+### StatusAction
+
+| Field | Type | Description |
+| ----- | ---- | ----------- |
+| `buttonTitle` | String | Title for the button, for example: Retry this job |
+| `icon` | String | Icon used in the action button |
+| `method` | String | Method for the action, for example: :post |
+| `path` | String | Path for the action |
+| `title` | String | Title for the action, for example: Retry |
+
### Submodule
| Field | Type | Description |
@@ -2384,20 +2569,31 @@ Completion status of tasks.
| `completedCount` | Int! | Number of completed tasks |
| `count` | Int! | Number of total tasks |
-### TerraformStateRegistry
+### TerraformState
+
+| Field | Type | Description |
+| ----- | ---- | ----------- |
+| `createdAt` | Time! | Timestamp the Terraform state was created |
+| `id` | ID! | ID of the Terraform state |
+| `lockedAt` | Time | Timestamp the Terraform state was locked |
+| `lockedByUser` | User | The user currently holding a lock on the Terraform state |
+| `name` | String! | Name of the Terraform state |
+| `updatedAt` | Time! | Timestamp the Terraform state was updated |
+
+### TerraformStateVersionRegistry
-Represents the sync and verification state of a terraform state.
+Represents the Geo sync and verification state of a terraform state version.
| Field | Type | Description |
| ----- | ---- | ----------- |
-| `createdAt` | Time | Timestamp when the TerraformStateRegistry was created |
-| `id` | ID! | ID of the TerraformStateRegistry |
-| `lastSyncFailure` | String | Error message during sync of the TerraformStateRegistry |
-| `lastSyncedAt` | Time | Timestamp of the most recent successful sync of the TerraformStateRegistry |
-| `retryAt` | Time | Timestamp after which the TerraformStateRegistry should be resynced |
-| `retryCount` | Int | Number of consecutive failed sync attempts of the TerraformStateRegistry |
-| `state` | RegistryState | Sync state of the TerraformStateRegistry |
-| `terraformStateId` | ID! | ID of the TerraformState |
+| `createdAt` | Time | Timestamp when the TerraformStateVersionRegistry was created |
+| `id` | ID! | ID of the TerraformStateVersionRegistry |
+| `lastSyncFailure` | String | Error message during sync of the TerraformStateVersionRegistry |
+| `lastSyncedAt` | Time | Timestamp of the most recent successful sync of the TerraformStateVersionRegistry |
+| `retryAt` | Time | Timestamp after which the TerraformStateVersionRegistry should be resynced |
+| `retryCount` | Int | Number of consecutive failed sync attempts of the TerraformStateVersionRegistry |
+| `state` | RegistryState | Sync state of the TerraformStateVersionRegistry |
+| `terraformStateVersionId` | ID! | ID of the terraform state version |
### TestReport
@@ -2523,6 +2719,16 @@ Autogenerated return type of UpdateAlertStatus.
| `issue` | Issue | The issue created after mutation |
| `todo` | Todo | The todo after mutation |
+### UpdateBoardEpicUserPreferencesPayload
+
+Autogenerated return type of UpdateBoardEpicUserPreferences.
+
+| Field | Type | Description |
+| ----- | ---- | ----------- |
+| `clientMutationId` | String | A unique identifier for the client performing the mutation. |
+| `epicUserPreferences` | BoardEpicUserPreferences | User preferences for the epic in the board after mutation |
+| `errors` | String! => Array | Errors encountered during execution of the mutation. |
+
### UpdateBoardListPayload
Autogenerated return type of UpdateBoardList.
@@ -2611,7 +2817,7 @@ Autogenerated return type of UpdateRequirement.
| ----- | ---- | ----------- |
| `clientMutationId` | String | A unique identifier for the client performing the mutation. |
| `errors` | String! => Array | Errors encountered during execution of the mutation. |
-| `requirement` | Requirement | The requirement after mutation |
+| `requirement` | Requirement | Requirement after mutation |
### UpdateSnippetPayload
@@ -2622,6 +2828,7 @@ Autogenerated return type of UpdateSnippet.
| `clientMutationId` | String | A unique identifier for the client performing the mutation. |
| `errors` | String! => Array | Errors encountered during execution of the mutation. |
| `snippet` | Snippet | The snippet after mutation |
+| `spam` | Boolean | Indicates whether the operation returns a record detected as spam |
### User
@@ -2690,16 +2897,36 @@ Represents a vulnerability.
| `location` | VulnerabilityLocation | Location metadata for the vulnerability. Its fields depend on the type of security scan that found the vulnerability |
| `primaryIdentifier` | VulnerabilityIdentifier | Primary identifier of the vulnerability. |
| `project` | Project | The project on which the vulnerability was found |
-| `reportType` | VulnerabilityReportType | Type of the security report that found the vulnerability (SAST, DEPENDENCY_SCANNING, CONTAINER_SCANNING, DAST, SECRET_DETECTION, COVERAGE_FUZZING) |
+| `reportType` | VulnerabilityReportType | Type of the security report that found the vulnerability (SAST, DEPENDENCY_SCANNING, CONTAINER_SCANNING, DAST, SECRET_DETECTION, COVERAGE_FUZZING, API_FUZZING) |
| `resolvedOnDefaultBranch` | Boolean! | Indicates whether the vulnerability is fixed on the default branch or not |
| `scanner` | VulnerabilityScanner | Scanner metadata for the vulnerability. |
| `severity` | VulnerabilitySeverity | Severity of the vulnerability (INFO, UNKNOWN, LOW, MEDIUM, HIGH, CRITICAL) |
-| `state` | VulnerabilityState | State of the vulnerability (DETECTED, DISMISSED, RESOLVED, CONFIRMED) |
+| `state` | VulnerabilityState | State of the vulnerability (DETECTED, CONFIRMED, RESOLVED, DISMISSED) |
| `title` | String | Title of the vulnerability |
| `userNotesCount` | Int! | Number of user notes attached to the vulnerability |
| `userPermissions` | VulnerabilityPermissions! | Permissions for the current user on the resource |
| `vulnerabilityPath` | String | URL to the vulnerability's details page |
+### VulnerabilityConfirmPayload
+
+Autogenerated return type of VulnerabilityConfirm.
+
+| Field | Type | Description |
+| ----- | ---- | ----------- |
+| `clientMutationId` | String | A unique identifier for the client performing the mutation. |
+| `errors` | String! => Array | Errors encountered during execution of the mutation. |
+| `vulnerability` | Vulnerability | The vulnerability after state change |
+
+### VulnerabilityDismissPayload
+
+Autogenerated return type of VulnerabilityDismiss.
+
+| Field | Type | Description |
+| ----- | ---- | ----------- |
+| `clientMutationId` | String | A unique identifier for the client performing the mutation. |
+| `errors` | String! => Array | Errors encountered during execution of the mutation. |
+| `vulnerability` | Vulnerability | The vulnerability after dismissal |
+
### VulnerabilityIdentifier
Represents a vulnerability identifier.
@@ -2812,6 +3039,16 @@ Autogenerated return type of VulnerabilityResolve.
| `errors` | String! => Array | Errors encountered during execution of the mutation. |
| `vulnerability` | Vulnerability | The vulnerability after state change |
+### VulnerabilityRevertToDetectedPayload
+
+Autogenerated return type of VulnerabilityRevertToDetected.
+
+| Field | Type | Description |
+| ----- | ---- | ----------- |
+| `clientMutationId` | String | A unique identifier for the client performing the mutation. |
+| `errors` | String! => Array | Errors encountered during execution of the mutation. |
+| `vulnerability` | Vulnerability | The vulnerability after revert |
+
### VulnerabilityScanner
Represents a vulnerability scanner.
@@ -2890,6 +3127,8 @@ Values for sorting alerts.
| Value | Description |
| ----- | ----------- |
+| `CREATED_ASC` | Created at ascending order |
+| `CREATED_DESC` | Created at descending order |
| `CREATED_TIME_ASC` | Created time by ascending order |
| `CREATED_TIME_DESC` | Created time by descending order |
| `ENDED_AT_ASC` | End time by ascending order |
@@ -2902,12 +3141,14 @@ Values for sorting alerts.
| `STARTED_AT_DESC` | Start time by descending order |
| `STATUS_ASC` | Status by order: Ignored > Resolved > Acknowledged > Triggered |
| `STATUS_DESC` | Status by order: Triggered > Acknowledged > Resolved > Ignored |
+| `UPDATED_ASC` | Updated at ascending order |
+| `UPDATED_DESC` | Updated at descending order |
| `UPDATED_TIME_ASC` | Created time by ascending order |
| `UPDATED_TIME_DESC` | Created time by descending order |
-| `created_asc` | Created at ascending order |
-| `created_desc` | Created at descending order |
-| `updated_asc` | Updated at ascending order |
-| `updated_desc` | Updated at descending order |
+| `created_asc` **{warning-solid}** | **Deprecated:** Use CREATED_ASC. Deprecated in 13.5 |
+| `created_desc` **{warning-solid}** | **Deprecated:** Use CREATED_DESC. Deprecated in 13.5 |
+| `updated_asc` **{warning-solid}** | **Deprecated:** Use UPDATED_ASC. Deprecated in 13.5 |
+| `updated_desc` **{warning-solid}** | **Deprecated:** Use UPDATED_DESC. Deprecated in 13.5 |
### AlertManagementSeverity
@@ -2996,6 +3237,7 @@ Mode of a commit action.
| Value | Description |
| ----- | ----------- |
+| `ACTIVE` | Active DAST scan. This scan will make active attacks against the target site. |
| `PASSIVE` | Passive DAST scan. This scan will not make active attacks against the target site. |
### DastSiteProfileValidationStatusEnum
@@ -3007,6 +3249,16 @@ Mode of a commit action.
| `PASSED_VALIDATION` | Site validation process finished successfully |
| `PENDING_VALIDATION` | Site validation process has not started |
+### DesignCollectionCopyState
+
+Copy state of a DesignCollection.
+
+| Value | Description |
+| ----- | ----------- |
+| `ERROR` | The DesignCollection encountered an error during a copy |
+| `IN_PROGRESS` | The DesignCollection is being copied |
+| `READY` | The DesignCollection has no copy in progress |
+
### DesignVersionEvent
Mutation event of a design within a version.
@@ -3115,6 +3367,8 @@ Values for sorting issues.
| Value | Description |
| ----- | ----------- |
+| `CREATED_ASC` | Created at ascending order |
+| `CREATED_DESC` | Created at descending order |
| `DUE_DATE_ASC` | Due date by ascending order |
| `DUE_DATE_DESC` | Due date by descending order |
| `LABEL_PRIORITY_ASC` | Label priority by ascending order |
@@ -3123,13 +3377,19 @@ Values for sorting issues.
| `MILESTONE_DUE_DESC` | Milestone due date by descending order |
| `PRIORITY_ASC` | Priority by ascending order |
| `PRIORITY_DESC` | Priority by descending order |
+| `PUBLISHED_ASC` | Published issues shown last |
+| `PUBLISHED_DESC` | Published issues shown first |
| `RELATIVE_POSITION_ASC` | Relative position by ascending order |
+| `SEVERITY_ASC` | Severity from less critical to more critical |
+| `SEVERITY_DESC` | Severity from more critical to less critical |
+| `UPDATED_ASC` | Updated at ascending order |
+| `UPDATED_DESC` | Updated at descending order |
| `WEIGHT_ASC` | Weight by ascending order |
| `WEIGHT_DESC` | Weight by descending order |
-| `created_asc` | Created at ascending order |
-| `created_desc` | Created at descending order |
-| `updated_asc` | Updated at ascending order |
-| `updated_desc` | Updated at descending order |
+| `created_asc` **{warning-solid}** | **Deprecated:** Use CREATED_ASC. Deprecated in 13.5 |
+| `created_desc` **{warning-solid}** | **Deprecated:** Use CREATED_DESC. Deprecated in 13.5 |
+| `updated_asc` **{warning-solid}** | **Deprecated:** Use UPDATED_ASC. Deprecated in 13.5 |
+| `updated_desc` **{warning-solid}** | **Deprecated:** Use UPDATED_DESC. Deprecated in 13.5 |
### IssueState
@@ -3142,6 +3402,15 @@ State of a GitLab issue.
| `locked` | |
| `opened` | |
+### IssueStateEvent
+
+Values for issue state events.
+
+| Value | Description |
+| ----- | ----------- |
+| `CLOSE` | Closes the issue |
+| `REOPEN` | Reopens the issue |
+
### IssueType
Issue type.
@@ -3184,6 +3453,10 @@ Possible identifier types for a measurement.
| `ISSUES` | Issue count |
| `MERGE_REQUESTS` | Merge request count |
| `PIPELINES` | Pipeline count |
+| `PIPELINES_CANCELED` | Pipeline count with canceled status |
+| `PIPELINES_FAILED` | Pipeline count with failed status |
+| `PIPELINES_SKIPPED` | Pipeline count with skipped status |
+| `PIPELINES_SUCCEEDED` | Pipeline count with success status |
| `PROJECTS` | Project count |
| `USERS` | User count |
@@ -3193,6 +3466,8 @@ Values for sorting merge requests.
| Value | Description |
| ----- | ----------- |
+| `CREATED_ASC` | Created at ascending order |
+| `CREATED_DESC` | Created at descending order |
| `LABEL_PRIORITY_ASC` | Label priority by ascending order |
| `LABEL_PRIORITY_DESC` | Label priority by descending order |
| `MERGED_AT_ASC` | Merge time by ascending order |
@@ -3201,10 +3476,12 @@ Values for sorting merge requests.
| `MILESTONE_DUE_DESC` | Milestone due date by descending order |
| `PRIORITY_ASC` | Priority by ascending order |
| `PRIORITY_DESC` | Priority by descending order |
-| `created_asc` | Created at ascending order |
-| `created_desc` | Created at descending order |
-| `updated_asc` | Updated at ascending order |
-| `updated_desc` | Updated at descending order |
+| `UPDATED_ASC` | Updated at ascending order |
+| `UPDATED_DESC` | Updated at descending order |
+| `created_asc` **{warning-solid}** | **Deprecated:** Use CREATED_ASC. Deprecated in 13.5 |
+| `created_desc` **{warning-solid}** | **Deprecated:** Use CREATED_DESC. Deprecated in 13.5 |
+| `updated_asc` **{warning-solid}** | **Deprecated:** Use UPDATED_ASC. Deprecated in 13.5 |
+| `updated_desc` **{warning-solid}** | **Deprecated:** Use UPDATED_DESC. Deprecated in 13.5 |
### MergeRequestState
@@ -3256,13 +3533,15 @@ Values for sorting projects.
| Value | Description |
| ----- | ----------- |
-| `COMPOSER` | Packages from the composer package manager |
-| `CONAN` | Packages from the conan package manager |
-| `GENERIC` | Packages from the generic package manager |
-| `MAVEN` | Packages from the maven package manager |
-| `NPM` | Packages from the npm package manager |
-| `NUGET` | Packages from the nuget package manager |
-| `PYPI` | Packages from the pypi package manager |
+| `COMPOSER` | Packages from the Composer package manager |
+| `CONAN` | Packages from the Conan package manager |
+| `DEBIAN` | Packages from the Debian package manager |
+| `GENERIC` | Packages from the Generic package manager |
+| `GOLANG` | Packages from the Golang package manager |
+| `MAVEN` | Packages from the Maven package manager |
+| `NPM` | Packages from the NPM package manager |
+| `NUGET` | Packages from the Nuget package manager |
+| `PYPI` | Packages from the PyPI package manager |
### PipelineConfigSourceEnum
@@ -3352,6 +3631,7 @@ The type of the security scanner.
| Value | Description |
| ----- | ----------- |
+| `API_FUZZING` | |
| `CONTAINER_SCANNING` | |
| `COVERAGE_FUZZING` | |
| `DAST` | |
@@ -3428,10 +3708,14 @@ Common sort values.
| Value | Description |
| ----- | ----------- |
-| `created_asc` | Created at ascending order |
-| `created_desc` | Created at descending order |
-| `updated_asc` | Updated at ascending order |
-| `updated_desc` | Updated at descending order |
+| `CREATED_ASC` | Created at ascending order |
+| `CREATED_DESC` | Created at descending order |
+| `UPDATED_ASC` | Updated at ascending order |
+| `UPDATED_DESC` | Updated at descending order |
+| `created_asc` **{warning-solid}** | **Deprecated:** Use CREATED_ASC. Deprecated in 13.5 |
+| `created_desc` **{warning-solid}** | **Deprecated:** Use CREATED_DESC. Deprecated in 13.5 |
+| `updated_asc` **{warning-solid}** | **Deprecated:** Use UPDATED_ASC. Deprecated in 13.5 |
+| `updated_desc` **{warning-solid}** | **Deprecated:** Use UPDATED_DESC. Deprecated in 13.5 |
### TestReportState
@@ -3532,6 +3816,7 @@ The type of the security scan that found the vulnerability.
| Value | Description |
| ----- | ----------- |
+| `API_FUZZING` | |
| `CONTAINER_SCANNING` | |
| `COVERAGE_FUZZING` | |
| `DAST` | |
@@ -3558,8 +3843,16 @@ Vulnerability sort values.
| Value | Description |
| ----- | ----------- |
+| `detected_asc` | Detection timestamp in ascending order |
+| `detected_desc` | Detection timestamp in descending order |
+| `report_type_asc` | Report Type in ascending order |
+| `report_type_desc` | Report Type in descending order |
| `severity_asc` | Severity in ascending order |
| `severity_desc` | Severity in descending order |
+| `state_asc` | State in ascending order |
+| `state_desc` | State in descending order |
+| `title_asc` | Title in ascending order |
+| `title_desc` | Title in descending order |
### VulnerabilityState
diff --git a/doc/api/group_clusters.md b/doc/api/group_clusters.md
index 17413ea2a3b..27b76d1f0c0 100644
--- a/doc/api/group_clusters.md
+++ b/doc/api/group_clusters.md
@@ -8,8 +8,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/30213) in GitLab 12.1.
-NOTE: **Note:**
-User will need at least maintainer access for the group to use these endpoints.
+Users need at least [Maintainer](../user/permissions.md) access for the group to use these endpoints.
## List group clusters
diff --git a/doc/api/group_iterations.md b/doc/api/group_iterations.md
new file mode 100644
index 00000000000..62431244d78
--- /dev/null
+++ b/doc/api/group_iterations.md
@@ -0,0 +1,55 @@
+---
+stage: Plan
+group: Project Management
+info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers
+---
+
+# Group iterations API **(STARTER)**
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/118742) in [GitLab Starter](https://about.gitlab.com/pricing/) 13.5.
+
+This page describes the group iterations API.
+There's a separate [project iterations API](./iterations.md) page.
+
+## List group iterations
+
+Returns a list of group iterations.
+
+```plaintext
+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
+```
+
+| Attribute | Type | Required | Description |
+| ------------------- | ------- | -------- | ----------- |
+| `state` | string | no | Return only `opened`, `upcoming`, `started`, `closed`, or `all` iterations. Defaults to `all`. |
+| `search` | string | no | Return only iterations with a title matching the provided string. |
+| `include_ancestors` | boolean | no | Include iterations from parent group and its ancestors. Defaults to `true`. |
+
+Example request:
+
+```shell
+curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/groups/5/iterations"
+```
+
+Example response:
+
+```json
+[
+ {
+ "id": 53,
+ "iid": 13,
+ "group_id": 5,
+ "title": "Iteration II",
+ "description": "Ipsum Lorem ipsum",
+ "state": 2,
+ "created_at": "2020-01-27T05:07:12.573Z",
+ "updated_at": "2020-01-27T05:07:12.573Z",
+ "due_date": "2020-02-01",
+ "start_date": "2020-02-14"
+ }
+]
+```
diff --git a/doc/api/group_milestones.md b/doc/api/group_milestones.md
index 47350442b3e..3220707e9e3 100644
--- a/doc/api/group_milestones.md
+++ b/doc/api/group_milestones.md
@@ -9,7 +9,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/12819) in GitLab 9.5.
This page describes the group milestones API.
-There's a separate [project milestones API](./group_milestones.md) page.
+There's a separate [project milestones API](./milestones.md) page.
## List group milestones
diff --git a/doc/api/group_wikis.md b/doc/api/group_wikis.md
index 414c795e092..c61a557fcc6 100644
--- a/doc/api/group_wikis.md
+++ b/doc/api/group_wikis.md
@@ -5,9 +5,9 @@ info: "To determine the technical writer assigned to the Stage/Group associated
type: reference, api
---
-# Wikis API
+# Group wikis API **(PREMIUM)**
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/212199) in GitLab 13.2.
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/212199) in [GitLab Premium](https://about.gitlab.com/pricing/) 13.5.
Available only in APIv4.
diff --git a/doc/api/groups.md b/doc/api/groups.md
index ae3300e24fb..53c92cf85ec 100644
--- a/doc/api/groups.md
+++ b/doc/api/groups.md
@@ -167,6 +167,89 @@ GET /groups/:id/subgroups
]
```
+## List a group's descendant groups
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/217115) in GitLab 13.5
+
+Get a list of visible descendant groups of this group.
+When accessed without authentication, only public groups are returned.
+
+By default, this request returns 20 results at a time because the API results [are paginated](README.md#pagination).
+
+Parameters:
+
+| Attribute | Type | Required | Description |
+| ------------------------ | ----------------- | -------- | ----------- |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) of the immediate parent group |
+| `skip_groups` | array of integers | no | Skip the group IDs passed |
+| `all_available` | boolean | no | Show all the groups you have access to (defaults to `false` for authenticated users, `true` for admin). Attributes `owned` and `min_access_level` have precedence |
+| `search` | string | no | Return the list of authorized groups matching the search criteria |
+| `order_by` | string | no | Order groups by `name`, `path`, or `id`. Default is `name` |
+| `sort` | string | no | Order groups in `asc` or `desc` order. Default is `asc` |
+| `statistics` | boolean | no | Include group statistics (admins only) |
+| `with_custom_attributes` | boolean | no | Include [custom attributes](custom_attributes.md) in response (admins only) |
+| `owned` | boolean | no | Limit to groups explicitly owned by the current user |
+| `min_access_level` | integer | no | Limit to groups where current user has at least this [access level](members.md#valid-access-levels) |
+
+```plaintext
+GET /groups/:id/descendant_groups
+```
+
+```json
+[
+ {
+ "id": 2,
+ "name": "Bar Group",
+ "path": "foo/bar",
+ "description": "A subgroup of Foo Group",
+ "visibility": "public",
+ "share_with_group_lock": false,
+ "require_two_factor_authentication": false,
+ "two_factor_grace_period": 48,
+ "project_creation_level": "developer",
+ "auto_devops_enabled": null,
+ "subgroup_creation_level": "owner",
+ "emails_disabled": null,
+ "mentions_disabled": null,
+ "lfs_enabled": true,
+ "default_branch_protection": 2,
+ "avatar_url": "http://gitlab.example.com/uploads/group/avatar/1/bar.jpg",
+ "web_url": "http://gitlab.example.com/groups/foo/bar",
+ "request_access_enabled": false,
+ "full_name": "Bar Group",
+ "full_path": "foo/bar",
+ "file_template_project_id": 1,
+ "parent_id": 123,
+ "created_at": "2020-01-15T12:36:29.590Z"
+ },
+ {
+ "id": 3,
+ "name": "Baz Group",
+ "path": "foo/bar/baz",
+ "description": "A subgroup of Bar Group",
+ "visibility": "public",
+ "share_with_group_lock": false,
+ "require_two_factor_authentication": false,
+ "two_factor_grace_period": 48,
+ "project_creation_level": "developer",
+ "auto_devops_enabled": null,
+ "subgroup_creation_level": "owner",
+ "emails_disabled": null,
+ "mentions_disabled": null,
+ "lfs_enabled": true,
+ "default_branch_protection": 2,
+ "avatar_url": "http://gitlab.example.com/uploads/group/avatar/1/baz.jpg",
+ "web_url": "http://gitlab.example.com/groups/foo/bar/baz",
+ "request_access_enabled": false,
+ "full_name": "Baz Group",
+ "full_path": "foo/bar/baz",
+ "file_template_project_id": 1,
+ "parent_id": 123,
+ "created_at": "2020-01-15T12:36:29.590Z"
+ }
+]
+```
+
## List a group's projects
Get a list of projects in this group. When accessed without authentication, only public projects are returned.
@@ -357,6 +440,7 @@ Example response:
"import_status":"failed",
"open_issues_count":10,
"ci_default_git_depth":50,
+ "ci_forward_deployment_enabled":true,
"public_jobs":true,
"build_timeout":3600,
"auto_cancel_pending_pipelines":"enabled",
@@ -676,6 +760,7 @@ Parameters:
| `default_branch_protection` | integer | no | See [Options for `default_branch_protection`](#options-for-default_branch_protection). Default to the global level default branch protection setting. |
| `shared_runners_minutes_limit` | integer | no | **(STARTER ONLY)** Pipeline minutes quota for this group (included in plan). Can be `nil` (default; inherit system default), `0` (unlimited) or `> 0` |
| `extra_shared_runners_minutes_limit` | integer | no | **(STARTER ONLY)** Extra pipeline minutes quota for this group (purchased in addition to the minutes included in the plan). |
+| `shared_runners_setting` | string | no | See [Options for `shared_runners_setting`](#options-for-shared_runners_setting). Enable or disable shared runners for a group's subgroups and projects. |
### Options for `default_branch_protection`
@@ -687,6 +772,16 @@ The `default_branch_protection` attribute determines whether developers and main
| `1` | Partial protection. Developers and maintainers can: <br>- Push new commits |
| `2` | Full protection. Only maintainers can: <br>- Push new commits |
+### Options for `shared_runners_setting`
+
+The `shared_runners_setting` attribute determines whether shared runners are enabled for a group's subgroups and projects.
+
+| Value | Description |
+|-------|-------------------------------------------------------------------------------------------------------------|
+| `enabled` | Enables shared runners for all projects and subgroups in this group. |
+| `disabled_with_override` | Disables shared runners for all projects and subgroups in this group, but allows subgroups to override this setting. |
+| `disabled_and_unoverridable` | Disables shared runners for all projects and subgroups in this group, and prevents subgroups from overriding this setting. |
+
## New Subgroup
This is similar to creating a [New group](#new-group). You'll need the `parent_id` from the [List groups](#list-groups) call. You can then enter the desired:
@@ -696,7 +791,7 @@ This is similar to creating a [New group](#new-group). You'll need the `parent_i
```shell
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" --header "Content-Type: application/json" \
- --data '{"path": "<subgroup_path>", "name": "<subgroup_name>", "parent_id": <parent_group_id> } \
+ --data '{"path": "<subgroup_path>", "name": "<subgroup_name>", "parent_id": <parent_group_id> }' \
"https://gitlab.example.com/api/v4/groups/"
```
diff --git a/doc/api/import.md b/doc/api/import.md
index 54e7eb12ed1..e377853ade0 100644
--- a/doc/api/import.md
+++ b/doc/api/import.md
@@ -50,8 +50,8 @@ POST /import/bitbucket_server
| `personal_access_token` | string | yes | Bitbucket Server personal access token/password |
| `bitbucket_server_project` | string | yes | Bitbucket Project Key |
| `bitbucket_server_repo` | string | yes | Bitbucket Repository Name |
-| `new_name` | string | no | New repo name |
-| `target_namespace` | string | no | Namespace to import repo into |
+| `new_name` | string | no | New repository name |
+| `target_namespace` | string | no | Namespace to import repository into |
```shell
curl --request POST \
diff --git a/doc/api/instance_level_ci_variables.md b/doc/api/instance_level_ci_variables.md
index d8f306a822c..e8550d41c44 100644
--- a/doc/api/instance_level_ci_variables.md
+++ b/doc/api/instance_level_ci_variables.md
@@ -70,7 +70,7 @@ curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/a
Create a new instance-level variable.
-[Since GitLab 13.1](https://gitlab.com/gitlab-org/gitlab/-/issues/216097), the maximum number of allowed instance-level variables can be changed.
+[In GitLab 13.1 and later](https://gitlab.com/gitlab-org/gitlab/-/issues/216097), the maximum number of allowed instance-level variables can be changed.
```plaintext
POST /admin/ci/variables
@@ -79,7 +79,7 @@ POST /admin/ci/variables
| Attribute | Type | required | Description |
|-----------------|---------|----------|-----------------------|
| `key` | string | yes | The `key` of a variable. Max 255 characters, only `A-Z`, `a-z`, `0-9`, and `_` are allowed. |
-| `value` | string | yes | The `value` of a variable. 10,000 characters allowed. [Since GitLab 13.3](https://gitlab.com/gitlab-org/gitlab/-/issues/220028) |
+| `value` | string | yes | The `value` of a variable. 10,000 characters allowed ([GitLab 13.3 and later](https://gitlab.com/gitlab-org/gitlab/-/issues/220028)). |
| `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. |
@@ -109,7 +109,7 @@ PUT /admin/ci/variables/:key
| Attribute | Type | required | Description |
|-----------------|---------|----------|-------------------------|
| `key` | string | yes | The `key` of a variable. |
-| `value` | string | yes | The `value` of a variable. [Since GitLab 13.3](https://gitlab.com/gitlab-org/gitlab/-/issues/220028), around 10,000 characters allowed. Previously 700 characters. |
+| `value` | string | yes | The `value` of a variable. 10,000 characters allowed ([GitLab 13.3 and later](https://gitlab.com/gitlab-org/gitlab/-/issues/220028)). |
| `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. |
diff --git a/doc/api/issue_links.md b/doc/api/issue_links.md
index b6502bf099c..757910d0946 100644
--- a/doc/api/issue_links.md
+++ b/doc/api/issue_links.md
@@ -1,8 +1,11 @@
-# Issue links API **(STARTER)**
+# Issue links API **(CORE)**
+
+> The simple "relates to" relationship [moved](https://gitlab.com/gitlab-org/gitlab/-/issues/212329) to [GitLab Core](https://about.gitlab.com/pricing/) in 13.4.
## List issue relations
-Get a list of related issues of a given issue, sorted by the relationship creation datetime (ascending).
+Get a list of a given issue's [related issues](../user/project/issues/related_issues.md),
+sorted by the relationship creation datetime (ascending).
Issues will be filtered according to the user authorizations.
```plaintext
@@ -55,19 +58,20 @@ Parameters:
## Create an issue link
-Creates a two-way relation between two issues. User must be allowed to update both issues in order to succeed.
+Creates a two-way relation between two issues. The user must be allowed to
+update both issues to succeed.
```plaintext
POST /projects/:id/issues/:issue_iid/links
```
-| Attribute | Type | Required | Description |
-|-------------|---------|----------|--------------------------------------|
-| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
-| `issue_iid` | integer | yes | The internal ID of a project's issue |
+| Attribute | Type | Required | Description |
+|---------------------|----------------|----------|--------------------------------------|
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
+| `issue_iid` | integer | yes | The internal ID of a project's issue |
| `target_project_id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) of a target project |
-| `target_issue_iid` | integer/string | yes | The internal ID of a target project's issue |
-| `link_type` | string | no | The type of the relation ("relates_to", "blocks", "is_blocked_by"), defaults to "relates_to"). |
+| `target_issue_iid` | integer/string | yes | The internal ID of a target project's issue |
+| `link_type` | string | no | The type of the relation ("relates_to", "blocks", "is_blocked_by"), defaults to "relates_to"). |
```shell
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/4/issues/1/links?target_project_id=5&target_issue_iid=1"
diff --git a/doc/api/issues.md b/doc/api/issues.md
index d8249869cab..b50ea7b42be 100644
--- a/doc/api/issues.md
+++ b/doc/api/issues.md
@@ -16,7 +16,7 @@ are paginated.
Read more on [pagination](README.md#pagination).
-CAUTION: **Deprecation:**
+DANGER: **Deprecated:**
The `reference` attribute in responses is deprecated in favor of `references`.
Introduced in [GitLab 12.6](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/20354).
@@ -33,19 +33,19 @@ use parameter `scope=all`.
```plaintext
GET /issues
-GET /issues?state=opened
-GET /issues?state=closed
+GET /issues?assignee_id=5
+GET /issues?author_id=5
+GET /issues?confidential=true
+GET /issues?iids[]=42&iids[]=43
GET /issues?labels=foo
GET /issues?labels=foo,bar
GET /issues?labels=foo,bar&state=opened
GET /issues?milestone=1.0.0
GET /issues?milestone=1.0.0&state=opened
-GET /issues?iids[]=42&iids[]=43
-GET /issues?author_id=5
-GET /issues?assignee_id=5
GET /issues?my_reaction_emoji=star
GET /issues?search=foo&in=title
-GET /issues?confidential=true
+GET /issues?state=closed
+GET /issues?state=opened
```
| Attribute | Type | Required | Description |
@@ -194,7 +194,7 @@ the `health_status` parameter:
]
```
-NOTE: **Note:**
+DANGER: **Deprecated:**
The `assignee` column is deprecated. We now show it as a single-sized array `assignees` to conform
to the GitLab EE API.
@@ -212,19 +212,19 @@ The preferred way to do this, is by using [personal access tokens](../user/profi
```plaintext
GET /groups/:id/issues
-GET /groups/:id/issues?state=opened
-GET /groups/:id/issues?state=closed
+GET /groups/:id/issues?assignee_id=5
+GET /groups/:id/issues?author_id=5
+GET /groups/:id/issues?confidential=true
+GET /groups/:id/issues?iids[]=42&iids[]=43
GET /groups/:id/issues?labels=foo
GET /groups/:id/issues?labels=foo,bar
GET /groups/:id/issues?labels=foo,bar&state=opened
GET /groups/:id/issues?milestone=1.0.0
GET /groups/:id/issues?milestone=1.0.0&state=opened
-GET /groups/:id/issues?iids[]=42&iids[]=43
-GET /groups/:id/issues?search=issue+title+or+description
-GET /groups/:id/issues?author_id=5
-GET /groups/:id/issues?assignee_id=5
GET /groups/:id/issues?my_reaction_emoji=star
-GET /groups/:id/issues?confidential=true
+GET /groups/:id/issues?search=issue+title+or+description
+GET /groups/:id/issues?state=closed
+GET /groups/:id/issues?state=opened
```
| Attribute | Type | Required | Description |
@@ -372,7 +372,7 @@ the `health_status` parameter:
]
```
-NOTE: **Note:**
+DANGER: **Deprecated:**
The `assignee` column is deprecated. We now show it as a single-sized array `assignees` to conform to the GitLab EE API.
NOTE: **Note:**
@@ -389,19 +389,19 @@ The preferred way to do this, is by using [personal access tokens](../user/profi
```plaintext
GET /projects/:id/issues
-GET /projects/:id/issues?state=opened
-GET /projects/:id/issues?state=closed
+GET /projects/:id/issues?assignee_id=5
+GET /projects/:id/issues?author_id=5
+GET /projects/:id/issues?confidential=true
+GET /projects/:id/issues?iids[]=42&iids[]=43
GET /projects/:id/issues?labels=foo
GET /projects/:id/issues?labels=foo,bar
GET /projects/:id/issues?labels=foo,bar&state=opened
GET /projects/:id/issues?milestone=1.0.0
GET /projects/:id/issues?milestone=1.0.0&state=opened
-GET /projects/:id/issues?iids[]=42&iids[]=43
-GET /projects/:id/issues?search=issue+title+or+description
-GET /projects/:id/issues?author_id=5
-GET /projects/:id/issues?assignee_id=5
GET /projects/:id/issues?my_reaction_emoji=star
-GET /projects/:id/issues?confidential=true
+GET /projects/:id/issues?search=issue+title+or+description
+GET /projects/:id/issues?state=closed
+GET /projects/:id/issues?state=opened
```
| Attribute | Type | Required | Description |
@@ -555,7 +555,7 @@ the `health_status` parameter:
]
```
-NOTE: **Note:**
+DANGER: **Deprecated:**
The `assignee` column is deprecated. We now show it as a single-sized array `assignees` to conform to the GitLab EE API.
NOTE: **Note:**
@@ -574,7 +574,7 @@ GET /issues/:id
| Attribute | Type | Required | Description |
|-------------|---------|----------|--------------------------------------|
-| `id` | integer | yes | The ID of the issue |
+| `id` | integer | yes | The ID of the issue |
```shell
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/issues/41"
@@ -663,10 +663,10 @@ Example response:
"weight": null,
"has_tasks": false,
"_links": {
- "self": "http://gitlab.dummy:3000/api/v4/projects/1/issues/1",
- "notes": "http://gitlab.dummy:3000/api/v4/projects/1/issues/1/notes",
- "award_emoji": "http://gitlab.dummy:3000/api/v4/projects/1/issues/1/award_emoji",
- "project": "http://gitlab.dummy:3000/api/v4/projects/1"
+ "self": "http://gitlab.example:3000/api/v4/projects/1/issues/1",
+ "notes": "http://gitlab.example:3000/api/v4/projects/1/issues/1/notes",
+ "award_emoji": "http://gitlab.example:3000/api/v4/projects/1/issues/1/award_emoji",
+ "project": "http://gitlab.example:3000/api/v4/projects/1"
},
"references": {
"short": "#1",
@@ -712,19 +712,19 @@ the `epic` property:
}
```
-NOTE: **Note:**
+DANGER: **Deprecated:**
The `assignee` column is deprecated. We now show it as a single-sized array `assignees` to conform
to the GitLab EE API.
+DANGER: **Deprecated:**
+The `epic_iid` attribute is deprecated, and [will be removed in version 5](https://gitlab.com/gitlab-org/gitlab/-/issues/35157).
+Please use `iid` of the `epic` attribute instead.
+
NOTE: **Note:**
The `closed_by` attribute was [introduced in GitLab 10.6](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/17042).
This value is only present for issues closed after GitLab 10.6 and if the user account
that closed the issue still exists.
-NOTE: **Note:**
-The `epic_iid` attribute is deprecated, and [will be removed in version 5](https://gitlab.com/gitlab-org/gitlab/-/issues/35157).
-Please use `iid` of the `epic` attribute instead.
-
## Single project issue
Get a single project issue.
@@ -874,17 +874,17 @@ property:
]
```
-NOTE: **Note:**
+DANGER: **Deprecated:**
The `assignee` column is deprecated. We now show it as a single-sized array `assignees` to conform to the GitLab EE API.
+DANGER: **Deprecated:**
+The `epic_iid` attribute is deprecated and [will be removed in version 5](https://gitlab.com/gitlab-org/gitlab/-/issues/35157).
+Please use `iid` of the `epic` attribute instead.
+
NOTE: **Note:**
The `closed_by` attribute was [introduced in GitLab 10.6](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/17042). This value is only present for issues closed after GitLab 10.6 and if the user account that closed
the issue still exists.
-NOTE: **Note:**
-The `epic_iid` attribute is deprecated and [will be removed in version 5](https://gitlab.com/gitlab-org/gitlab/-/issues/35157).
-Please use `iid` of the `epic` attribute instead.
-
## New issue
Creates a new project issue.
@@ -895,21 +895,21 @@ POST /projects/:id/issues
| Attribute | Type | Required | Description |
|-------------------------------------------|----------------|----------|--------------|
+| `assignee_ids` | integer array | no | The ID of the user(s) to assign the issue to. |
+| `confidential` | boolean | no | Set an issue to be confidential. Default is `false`. |
+| `created_at` | string | no | When the issue was created. Date time string, ISO 8601 formatted, for example `2016-03-11T03:45:40Z`. Requires administrator or project/group owner rights. |
+| `description` | string | no | The description of an issue. Limited to 1,048,576 characters. |
+| `discussion_to_resolve` | string | no | The ID of a discussion to resolve. This fills out the issue with a default description and mark the discussion as resolved. Use in combination with `merge_request_to_resolve_discussions_of`. |
+| `due_date` | string | no | The due date. Date time string in the format YEAR-MONTH-DAY, for example `2016-03-11` |
+| `epic_id` **(PREMIUM)** | integer | no | ID of the epic to add the issue to. Valid values are greater than or equal to 0. |
+| `epic_iid` **(PREMIUM)** | integer | no | IID of the epic to add the issue to. Valid values are greater than or equal to 0. (deprecated, [will be removed in version 5](https://gitlab.com/gitlab-org/gitlab/-/issues/35157)) |
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
| `iid` | integer/string | no | The internal ID of the project's issue (requires administrator or project owner rights) |
-| `title` | string | yes | The title of an issue |
-| `description` | string | no | The description of an issue. Limited to 1,048,576 characters. |
-| `confidential` | boolean | no | Set an issue to be confidential. Default is `false`. |
-| `assignee_ids` | integer array | no | The ID of the user(s) to assign the issue to. |
-| `milestone_id` | integer | no | The global ID of a milestone to assign issue |
| `labels` | string | no | Comma-separated label names for an issue |
-| `created_at` | string | no | Date time string, ISO 8601 formatted, for example `2016-03-11T03:45:40Z` (requires administrator or project/group owner rights) |
-| `due_date` | string | no | Date time string in the format YEAR-MONTH-DAY, for example `2016-03-11` |
| `merge_request_to_resolve_discussions_of` | integer | no | The IID of a merge request in which to resolve all issues. This fills out the issue with a default description and mark all discussions as resolved. When passing a description or title, these values take precedence over the default values.|
-| `discussion_to_resolve` | string | no | The ID of a discussion to resolve. This fills out the issue with a default description and mark the discussion as resolved. Use in combination with `merge_request_to_resolve_discussions_of`. |
+| `milestone_id` | integer | no | The global ID of a milestone to assign issue |
+| `title` | string | yes | The title of an issue |
| `weight` **(STARTER)** | integer | no | The weight of the issue. Valid values are greater than or equal to 0. |
-| `epic_id` **(PREMIUM)** | integer | no | ID of the epic to add the issue to. Valid values are greater than or equal to 0. |
-| `epic_iid` **(PREMIUM)** | integer | no | IID of the epic to add the issue to. Valid values are greater than or equal to 0. (deprecated, [will be removed in version 5](https://gitlab.com/gitlab-org/gitlab/-/issues/35157)) |
```shell
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/4/issues?title=Issues%20with%20auth&labels=bug"
@@ -1002,7 +1002,7 @@ the `health_status` parameter:
]
```
-NOTE: **Note:**
+DANGER: **Deprecated:**
The `assignee` column is deprecated. We now show it as a single-sized array `assignees` to conform to the GitLab EE API.
NOTE: **Note:**
@@ -1019,29 +1019,43 @@ See [Issues rate limits](../user/admin_area/settings/rate_limit_on_issues_creati
Updates an existing project issue. This call is also used to mark an issue as
closed.
+At least one of the following parameters is required for the request to be successful:
+
+- `:assignee_id`
+- `:assignee_ids`
+- `:confidential`
+- `:created_at`
+- `:description`
+- `:discussion_locked`
+- `:due_date`
+- `:labels`
+- `:milestone_id`
+- `:state_event`
+- `:title`
+
```plaintext
PUT /projects/:id/issues/:issue_iid
```
| Attribute | Type | Required | Description |
|----------------|---------|----------|------------------------------------------------------------------------------------------------------------|
+| `add_labels` | string | no | Comma-separated label names to add to an issue. |
+| `assignee_ids` | integer array | no | The ID of the user(s) to assign the issue to. Set to `0` or provide an empty value to unassign all assignees. |
+| `confidential` | boolean | no | Updates an issue to be confidential |
+| `description` | string | no | The description of an issue. Limited to 1,048,576 characters. |
+| `discussion_locked` | boolean | no | Flag indicating if the issue's discussion is locked. If the discussion is locked only project members can add or edit comments. |
+| `due_date` | string | no | The due date. Date time string in the format YEAR-MONTH-DAY, for example `2016-03-11` |
+| `epic_id` **(PREMIUM)** | integer | no | ID of the epic to add the issue to. Valid values are greater than or equal to 0. |
+| `epic_iid` **(PREMIUM)** | integer | no | IID of the epic to add the issue to. Valid values are greater than or equal to 0. (deprecated, [will be removed in version 5](https://gitlab.com/gitlab-org/gitlab/-/issues/35157)) |
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
| `issue_iid` | integer | yes | The internal ID of a project's issue |
-| `title` | string | no | The title of an issue |
-| `description` | string | no | The description of an issue. Limited to 1,048,576 characters. |
-| `confidential` | boolean | no | Updates an issue to be confidential |
-| `assignee_ids` | integer array | no | The ID of the user(s) to assign the issue to. Set to `0` or provide an empty value to unassign all assignees. |
-| `milestone_id` | integer | no | The global ID of a milestone to assign the issue to. Set to `0` or provide an empty value to unassign a milestone.|
| `labels` | string | no | Comma-separated label names for an issue. Set to an empty string to unassign all labels. |
-| `add_labels` | string | no | Comma-separated label names to add to an issue. |
+| `milestone_id` | integer | no | The global ID of a milestone to assign the issue to. Set to `0` or provide an empty value to unassign a milestone.|
| `remove_labels`| string | no | Comma-separated label names to remove from an issue. |
| `state_event` | string | no | The state event of an issue. Set `close` to close the issue and `reopen` to reopen it |
-| `updated_at` | string | no | Date time string, ISO 8601 formatted, for example `2016-03-11T03:45:40Z` (requires administrator or project owner rights). Empty string or null values are not accepted.|
-| `due_date` | string | no | Date time string in the format YEAR-MONTH-DAY, for example `2016-03-11` |
+| `title` | string | no | The title of an issue |
+| `updated_at` | string | no | When the issue was updated. Date time string, ISO 8601 formatted, for example `2016-03-11T03:45:40Z` (requires administrator or project owner rights). Empty string or null values are not accepted.|
| `weight` **(STARTER)** | integer | no | The weight of the issue. Valid values are greater than or equal to 0. 0 |
-| `discussion_locked` | boolean | no | Flag indicating if the issue's discussion is locked. If the discussion is locked only project members can add or edit comments. |
-| `epic_id` **(PREMIUM)** | integer | no | ID of the epic to add the issue to. Valid values are greater than or equal to 0. |
-| `epic_iid` **(PREMIUM)** | integer | no | IID of the epic to add the issue to. Valid values are greater than or equal to 0. (deprecated, [will be removed in version 5](https://gitlab.com/gitlab-org/gitlab/-/issues/35157)) |
```shell
curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/4/issues/85?state_event=close"
@@ -1142,15 +1156,12 @@ the `health_status` parameter:
```
NOTE: **Note:**
-At least one of following parameters is required to be passed for the request to be successful: `:assignee_id`, `:assignee_ids`, `:confidential`, `:created_at`, `:description`, `:discussion_locked`, `:due_date`, `:labels`, `:milestone_id`, `:state_event`, or `:title`.
-
-NOTE: **Note:**
-`assignee` column is deprecated. We now show it as a single-sized array `assignees` to conform to the GitLab EE API.
-
-NOTE: **Note:**
The `closed_by` attribute was [introduced in GitLab 10.6](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/17042). This value is only present for issues closed after GitLab 10.6 and if the user account that closed
the issue still exists.
+DANGER: **Deprecated:**
+`assignee` column is deprecated. We now show it as a single-sized array `assignees` to conform to the GitLab EE API.
+
## Delete an issue
Only for admins and project owners. Deletes the issue in question.
@@ -1309,7 +1320,7 @@ the `health_status` parameter:
]
```
-NOTE: **Note:**
+DANGER: **Deprecated:**
The `assignee` column is deprecated. We now show it as a single-sized array `assignees` to conform to the GitLab EE API.
NOTE: **Note:**
@@ -1418,7 +1429,7 @@ the `weight` parameter:
}
```
-NOTE: **Note:**
+DANGER: **Deprecated:**
The `assignee` column is deprecated. We now show it as a single-sized array `assignees` to conform to the GitLab EE API.
NOTE: **Note:**
@@ -1496,10 +1507,10 @@ Example response:
}
```
-## Create a to-do
+## Create a to do
-Manually creates a to-do for the current user on an issue. If
-there already exists a to-do for the user on that issue, status code `304` is
+Manually creates a to do for the current user on an issue. If
+there already exists a to do for the user on that issue, status code `304` is
returned.
```plaintext
@@ -1608,7 +1619,7 @@ Example response:
}
```
-NOTE: **Note:**
+DANGER: **Deprecated:**
The `assignee` column is deprecated. We now show it as a single-sized array `assignees` to conform to the GitLab EE API.
NOTE: **Note:**
@@ -1625,9 +1636,9 @@ POST /projects/:id/issues/:issue_iid/time_estimate
| Attribute | Type | Required | Description |
|-------------|---------|----------|------------------------------------------|
+| `duration` | string | yes | The duration in human format. e.g: 3h30m |
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
| `issue_iid` | integer | yes | The internal ID of a project's issue |
-| `duration` | string | yes | The duration in human format. e.g: 3h30m |
```shell
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/5/issues/93/time_estimate?duration=3h30m"
@@ -1682,9 +1693,9 @@ POST /projects/:id/issues/:issue_iid/add_spent_time
| Attribute | Type | Required | Description |
|-------------|---------|----------|------------------------------------------|
+| `duration` | string | yes | The duration in human format. e.g: 3h30m |
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
| `issue_iid` | integer | yes | The internal ID of a project's issue |
-| `duration` | string | yes | The duration in human format. e.g: 3h30m |
```shell
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/5/issues/93/add_spent_time?duration=1h"
diff --git a/doc/api/iterations.md b/doc/api/iterations.md
new file mode 100644
index 00000000000..53a6bb00f23
--- /dev/null
+++ b/doc/api/iterations.md
@@ -0,0 +1,57 @@
+---
+stage: Plan
+group: Project Management
+info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers
+---
+
+# Project iterations API **(STARTER)**
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/118742) in [GitLab Starter](https://about.gitlab.com/pricing/) 13.5.
+
+This page describes the project iterations API.
+There's a separate [group iterations API](./group_iterations.md) page.
+
+As of GitLab 13.5, we don't have project-level iterations, but you can use this endpoint to fetch the iterations of the project's ancestor groups.
+
+## List project iterations
+
+Returns a list of project iterations.
+
+```plaintext
+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
+```
+
+| Attribute | Type | Required | Description |
+| ------------------- | ------- | -------- | ----------- |
+| `state` | string | no | Return only `opened`, `upcoming`, `started`, `closed`, or `all` iterations. Defaults to `all`. |
+| `search` | string | no | Return only iterations with a title matching the provided string. |
+| `include_ancestors` | boolean | no | Include iterations from parent group and its ancestors. Defaults to `true`. |
+
+Example request:
+
+```shell
+curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/5/iterations"
+```
+
+Example response:
+
+```json
+[
+ {
+ "id": 53,
+ "iid": 13,
+ "group_id": 5,
+ "title": "Iteration II",
+ "description": "Ipsum Lorem ipsum",
+ "state": 2,
+ "created_at": "2020-01-27T05:07:12.573Z",
+ "updated_at": "2020-01-27T05:07:12.573Z",
+ "due_date": "2020-02-01",
+ "start_date": "2020-02-14"
+ }
+]
+```
diff --git a/doc/api/job_artifacts.md b/doc/api/job_artifacts.md
index 458877d6548..f5510f6ee91 100644
--- a/doc/api/job_artifacts.md
+++ b/doc/api/job_artifacts.md
@@ -63,6 +63,11 @@ the given reference name and job, provided the job finished successfully. This
is the same as [getting the job's artifacts](#get-job-artifacts), but by
defining the job's name instead of its ID.
+NOTE: **Note:**
+If a pipeline is [parent of other child pipelines](../ci/parent_child_pipelines.md), artifacts
+are searched in hierarchical order from parent to child. For example, if both parent and
+child pipelines have a job with the same name, the artifact from the parent pipeline will be returned.
+
```plaintext
GET /projects/:id/jobs/artifacts/:ref_name/download?job=name
```
@@ -157,6 +162,11 @@ Download a single artifact file for a specific job of the latest successful
pipeline for the given reference name from within the job's artifacts archive.
The file is extracted from the archive and streamed to the client.
+In [GitLab 13.5](https://gitlab.com/gitlab-org/gitlab/-/issues/201784) and later, artifacts
+for [parent and child pipelines](../ci/parent_child_pipelines.md) are searched in hierarchical
+order from parent to child. For example, if both parent and child pipelines have a
+job with the same name, the artifact from the parent pipeline is returned.
+
```plaintext
GET /projects/:id/jobs/artifacts/:ref_name/raw/*artifact_path?job=name
```
diff --git a/doc/api/license.md b/doc/api/license.md
index 71e95fc3202..dcdf019059b 100644
--- a/doc/api/license.md
+++ b/doc/api/license.md
@@ -1,7 +1,7 @@
# License **(CORE ONLY)**
-In order to interact with license endpoints, you need to authenticate yourself
-as an admin.
+To interact with license endpoints, you need to authenticate yourself as an
+admin.
## Retrieve information about the current license
diff --git a/doc/api/lint.md b/doc/api/lint.md
index f4d8a0bc011..c82e0845f99 100644
--- a/doc/api/lint.md
+++ b/doc/api/lint.md
@@ -4,11 +4,14 @@ group: Continuous Integration
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/#designated-technical-writers
---
-# Validate the `.gitlab-ci.yml` (API)
+# CI Lint API
+
+## Validate the CI YAML configuration
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/5953) in GitLab 8.12.
-Checks if your `.gitlab-ci.yml` file is valid.
+Checks if CI/CD YAML configuration is valid. This endpoint validates basic CI/CD
+configuration syntax. It doesn't have any namespace specific context.
```plaintext
POST /ci/lint
@@ -16,13 +19,15 @@ POST /ci/lint
| Attribute | Type | Required | Description |
| ---------- | ------- | -------- | -------- |
-| `content` | string | yes | the `.gitlab-ci.yaml` content|
+| `content` | string | yes | The CI/CD configuration content. |
+| `include_merged_yaml` | boolean | no | If the [expanded CI/CD configuration](#yaml-expansion) should be included in the response. |
```shell
curl --header "Content-Type: application/json" "https://gitlab.example.com/api/v4/ci/lint" --data '{"content": "{ \"image\": \"ruby:2.6\", \"services\": [\"postgres\"], \"before_script\": [\"bundle install\", \"bundle exec rake db:create\"], \"variables\": {\"DB_NAME\": \"postgres\"}, \"types\": [\"test\", \"deploy\", \"notify\"], \"rspec\": { \"script\": \"rake spec\", \"tags\": [\"ruby\", \"postgres\"], \"only\": [\"branches\"]}}"}'
```
-Be sure to copy paste the exact contents of `.gitlab-ci.yml` as YAML is very picky about indentation and spaces.
+Be sure to paste the exact contents of your GitLab CI/CD YAML configuration because YAML
+is very sensitive about indentation and spacing.
Example responses:
@@ -53,3 +58,180 @@ Example responses:
"error": "content is missing"
}
```
+
+### YAML expansion
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/29568) in GitLab 13.5.
+
+The CI lint returns an expanded version of the configuration. The expansion does not
+work for CI configuration added with [`include: local`](../ci/yaml/README.md#includelocal),
+or with [`extends:`](../ci/yaml/README.md#extends).
+
+Example contents of a `.gitlab-ci.yml` passed to the CI Lint API with
+`include_merged_yaml` set as true:
+
+```yaml
+include:
+ remote: 'https://example.com/remote.yaml'
+
+test:
+ stage: test
+ script:
+ - echo 1
+```
+
+Example contents of `https://example.com/remote.yaml`:
+
+```yaml
+another_test:
+ stage: test
+ script:
+ - echo 2
+```
+
+Example response:
+
+```json
+{
+ "status": "valid",
+ "errors": [],
+ "merged_config": "---\n:another_test:\n :stage: test\n :script: echo 2\n:test:\n :stage: test\n :script: echo 1\n"
+}
+```
+
+## Validate a project's CI configuration
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/231352) in GitLab 13.5.
+
+Checks if a project's latest (`HEAD` of the project's default branch)
+`.gitlab-ci.yml` configuration is valid. This endpoint uses all namespace
+specific data available, including variables, local includes, and so on.
+
+```plaintext
+GET /projects/:id/ci/lint
+```
+
+| Attribute | Type | Required | Description |
+| ---------- | ------- | -------- | -------- |
+| `dry_run` | boolean | no | Run pipeline creation simulation, or only do static check. |
+
+Example request:
+
+```shell
+curl "https://gitlab.example.com/api/v4/projects/:id/ci/lint"
+```
+
+Example responses:
+
+- Valid configuration:
+
+```json
+{
+ "valid": true,
+ "merged_yaml": "---\n:test_job:\n :script: echo 1\n",
+ "errors": [],
+ "warnings": []
+}
+```
+
+- Invalid configuration:
+
+```json
+{
+ "valid": false,
+ "merged_yaml": "---\n:test_job:\n :script: echo 1\n",
+ "errors": [
+ "jobs config should contain at least one visible job"
+ ],
+ "warnings": []
+}
+```
+
+## Use jq to create and process YAML & JSON payloads
+
+To `POST` a YAML configuration to the CI Lint endpoint, it must be properly escaped and JSON encoded.
+You can use `jq` and `curl` to escape and upload YAML to the GitLab API.
+
+### Escape YAML for JSON encoding
+
+To escape quotes and encode your YAML in a format suitable for embedding within
+a JSON payload, you can use `jq`. For example, create a file named `example-gitlab-ci.yml`:
+
+```yaml
+.api_test:
+ rules:
+ - if: '$CI_PIPELINE_SOURCE=="merge_request_event"'
+ changes:
+ - src/api/*
+deploy:
+ extends:
+ - .api_test
+ rules:
+ - when: manual
+ allow_failure: true
+ script:
+ - echo "hello world"
+```
+
+Next, use `jq` to escape and encode the YAML file into JSON:
+
+```shell
+jq --raw-input --slurp < example-gitlab-ci.yml
+```
+
+To escape and encode an input YAML file (`example-gitlab-ci.yml`), and `POST` it to the
+GitLab API using `curl` and `jq` in a one-line command:
+
+```shell
+jq --null-input --arg yaml "$(<example-gitlab-ci.yml)" '.content=$yaml' \
+| curl 'https://gitlab.com/api/v4/ci/lint?include_merged_yaml=true' \
+--header 'Content-Type: application/json' \
+--data @-
+```
+
+### Parse a CI Lint response
+
+To reformat the CI Lint response, you can use `jq`. You can pipe the CI Lint response to `jq`,
+or store the API response as a text file and provide it as an argument:
+
+```shell
+jq --raw-output '.merged_yaml | fromjson' <your_input_here>
+```
+
+Example input:
+
+```json
+{"status":"valid","errors":[],"merged_yaml":"---\n:.api_test:\n :rules:\n - :if: $CI_PIPELINE_SOURCE==\"merge_request_event\"\n :changes:\n - src/api/*\n:deploy:\n :rules:\n - :when: manual\n :allow_failure: true\n :extends:\n - \".api_test\"\n :script:\n - echo \"hello world\"\n"}
+```
+
+Becomes:
+
+```yaml
+:.api_test:
+ :rules:
+ - :if: $CI_PIPELINE_SOURCE=="merge_request_event"
+ :changes:
+ - src/api/*
+:deploy:
+ :rules:
+ - :when: manual
+ :allow_failure: true
+ :extends:
+ - ".api_test"
+ :script:
+ - echo "hello world"
+```
+
+With a one-line command, you can:
+
+1. Escape the YAML
+1. Encode it in JSON
+1. POST it to the API with curl
+1. Format the response
+
+```shell
+jq --null-input --arg yaml "$(<example-gitlab-ci.yml)" '.content=$yaml' \
+| curl 'https://gitlab.com/api/v4/ci/lint?include_merged_yaml=true' \
+--header 'Content-Type: application/json' --data @- \
+| jq --raw-output '.merged_yaml | fromjson'
+```
diff --git a/doc/api/members.md b/doc/api/members.md
index 76d63b277c4..4440b70c512 100644
--- a/doc/api/members.md
+++ b/doc/api/members.md
@@ -180,6 +180,7 @@ Example response:
"web_url": "http://192.168.1.8:3000/root",
"access_level": 30,
"email": "john@example.com",
+ "created_at": "2012-10-22T14:13:35Z",
"expires_at": null,
"group_saml_identity": null
}
@@ -223,6 +224,61 @@ Example response:
}
```
+## List all billable members of a group
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/217384) in GitLab 13.5.
+
+Gets a list of group members that count as billable. The list includes members in the subgroup or subproject.
+
+NOTE:
+Unlike other API endpoints, billable members is updated once per day at 12:00 UTC.
+
+This function takes [pagination](README.md#pagination) parameters `page` and `per_page` to restrict the list of users.
+
+```plaintext
+GET /groups/:id/billable_members
+```
+
+| Attribute | Type | Required | Description |
+| --------- | ---- | -------- | ----------- |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) owned by the authenticated user |
+
+```shell
+curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/groups/:id/billable_members"
+```
+
+Example response:
+
+```json
+[
+ {
+ "id": 1,
+ "username": "raymond_smith",
+ "name": "Raymond Smith",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/c2525a7f58ae3776070e44c106c48e15?s=80&d=identicon",
+ "web_url": "http://192.168.1.8:3000/root",
+ },
+ {
+ "id": 2,
+ "username": "john_doe",
+ "name": "John Doe",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/c2525a7f58ae3776070e44c106c48e15?s=80&d=identicon",
+ "web_url": "http://192.168.1.8:3000/root",
+ "email": "john@example.com"
+ },
+ {
+ "id": 3,
+ "username": "foo_bar",
+ "name": "Foo bar",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/c2525a7f58ae3776070e44c106c48e15?s=80&d=identicon",
+ "web_url": "http://192.168.1.8:3000/root"
+ }
+]
+```
+
## Add a member to a group or project
Adds a member to a group or project.
@@ -235,7 +291,7 @@ POST /projects/:id/members
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the project or group](README.md#namespaced-path-encoding) owned by the authenticated user |
-| `user_id` | integer | yes | The user ID of the new member |
+| `user_id` | integer/string | yes | The user ID of the new member or multiple IDs separated by commas |
| `access_level` | integer | yes | A valid access level |
| `expires_at` | string | no | A date string in the format YEAR-MONTH-DAY |
diff --git a/doc/api/merge_request_approvals.md b/doc/api/merge_request_approvals.md
index 643d03b6fb8..89e4224c735 100644
--- a/doc/api/merge_request_approvals.md
+++ b/doc/api/merge_request_approvals.md
@@ -60,7 +60,7 @@ POST /projects/:id/approvals
| `disable_overriding_approvers_per_merge_request` | boolean | no | Allow/Disallow overriding approvers per MR |
| `merge_requests_author_approval` | boolean | no | Allow/Disallow authors from self approving merge requests; `true` means authors can self approve |
| `merge_requests_disable_committers_approval` | boolean | no | Allow/Disallow committers from self approving merge requests |
-| `require_password_to_approve` | boolean | no | Require approver to enter a password in order to authenticate before adding the approval |
+| `require_password_to_approve` | boolean | no | Require approver to enter a password to authenticate before adding the approval |
```json
{
diff --git a/doc/api/merge_requests.md b/doc/api/merge_requests.md
index faefc445210..194f48c6e84 100644
--- a/doc/api/merge_requests.md
+++ b/doc/api/merge_requests.md
@@ -72,6 +72,9 @@ Parameters:
| `in` | string | no | Modify the scope of the `search` attribute. `title`, `description`, or a string joining them with comma. Default is `title,description` |
| `wip` | string | no | Filter merge requests against their `wip` status. `yes` to return *only* WIP merge requests, `no` to return *non* WIP merge requests |
| `not` | Hash | no | Return merge requests that do not match the parameters supplied. Accepts: `labels`, `milestone`, `author_id`, `author_username`, `assignee_id`, `assignee_username`, `my_reaction_emoji` |
+| `environment` | string | no | Returns merge requests deployed to the given environment
+| `deployed_before` | datetime | no | Return merge requests deployed before the given date/time
+| `deployed_after` | datetime | no | Return merge requests deployed after the given date/time
NOTE: **Note:**
[Starting in GitLab 13.0](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/31890),
@@ -1004,6 +1007,7 @@ order for it to take effect:
value of zero disables approvals for that project.
1. The provided value of `approvals_before_merge` must be greater than the
target project's `approvals_before_merge`.
+1. This API returns 201 (created) for a successful response.
```json
{
@@ -1310,7 +1314,7 @@ curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" "https://git
Merge changes submitted with MR using this API.
-If merge request is unable to be accepted (ie: Draft, Closed, Pipeline Pending Completion, or Failed while requiring Success) - you'll get a `405` and the error message 'Method Not Allowed'
+If merge request is unable to be accepted (such as Draft, Closed, Pipeline Pending Completion, or Failed while requiring Success) - you'll get a `405` and the error message 'Method Not Allowed'
If it has some conflicts and can not be merged - you'll get a `406` and the error message 'Branch cannot be merged'
@@ -2085,10 +2089,10 @@ the `approvals_before_merge` parameter:
}
```
-## Create a to-do
+## Create a to do
-Manually creates a to-do for the current user on a merge request.
-If there already exists a to-do for the user on that merge request,
+Manually creates a to do for the current user on a merge request.
+If there already exists a to do for the user on that merge request,
status code `304` is returned.
```plaintext
diff --git a/doc/api/metrics_dashboard_annotations.md b/doc/api/metrics_dashboard_annotations.md
index 10dfd3d1c3b..c23ed657583 100644
--- a/doc/api/metrics_dashboard_annotations.md
+++ b/doc/api/metrics_dashboard_annotations.md
@@ -1,6 +1,6 @@
---
stage: Monitor
-group: APM
+group: Health
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/#designated-technical-writers
type: concepts, howto
---
@@ -18,14 +18,11 @@ POST /environments/:id/metrics_dashboard/annotations/
POST /clusters/:id/metrics_dashboard/annotations/
```
-NOTE: **Note:**
-The value of `dashboard_path` will be treated as a CGI-escaped path, and automatically un-escaped.
-
Parameters:
| Attribute | Type | Required | Description |
|:---------------|:---------------|:---------|:-----------------------------------------------------------------------------|
-| `dashboard_path` | string | yes | ID of the dashboard which needs to be annotated. |
+| `dashboard_path` | string | yes | ID of the dashboard which needs to be annotated. Treated as a CGI-escaped path, and automatically un-escaped. |
| `starting_at` | string | yes | Date time string, ISO 8601 formatted, such as `2016-03-11T03:45:40Z`. Timestamp marking start point of annotation. |
| `ending_at` | string | no | Date time string, ISO 8601 formatted, such as `2016-03-11T03:45:40Z`. Timestamp marking end point of annotation. When not supplied annotation will be displayed as single event at start point. |
| `description` | string | yes | Description of the annotation. |
diff --git a/doc/api/metrics_user_starred_dashboards.md b/doc/api/metrics_user_starred_dashboards.md
index df9cdd3b0e4..8c2894293ba 100644
--- a/doc/api/metrics_user_starred_dashboards.md
+++ b/doc/api/metrics_user_starred_dashboards.md
@@ -1,6 +1,6 @@
---
stage: Monitor
-group: APM
+group: Health
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/#designated-technical-writers
type: concepts, howto
---
diff --git a/doc/api/namespaces.md b/doc/api/namespaces.md
index ba59d467bc8..0792c6d4a3b 100644
--- a/doc/api/namespaces.md
+++ b/doc/api/namespaces.md
@@ -87,6 +87,26 @@ the `plan` parameter associated with a namespace:
]
```
+Users on GitLab.com will also see `max_seats_used` and `seats_in_use` parameters.
+`max_seats_used` is the highest number of users the group had. `seats_in_use` is
+the number of license seats currently being used. Both values are updated
+once a day.
+
+`max_seats_used` and `seats_in_use` will be non-zero only for namespaces on paid plans.
+
+```json
+[
+ {
+ "id": 1,
+ "name": "user1",
+ "billable_members_count": 2,
+ "max_seats_used": 3,
+ "seats_in_use": 2,
+ ...
+ }
+]
+```
+
NOTE: **Note:**
Only group maintainers/owners are presented with `members_count_with_descendants`, as well as `plan` **(BRONZE ONLY)**.
@@ -123,6 +143,8 @@ Example response:
"web_url": "https://gitlab.example.com/groups/twitter",
"members_count_with_descendants": 2,
"billable_members_count": 2,
+ "max_seats_used": 0,
+ "seats_in_use": 0,
"plan": "default",
"trial_ends_on": null,
"trial": false
@@ -162,6 +184,8 @@ Example response:
"web_url": "https://gitlab.example.com/groups/group1",
"members_count_with_descendants": 2,
"billable_members_count": 2,
+ "max_seats_used": 0,
+ "seats_in_use": 0,
"plan": "default",
"trial_ends_on": null,
"trial": false
@@ -188,6 +212,8 @@ Example response:
"web_url": "https://gitlab.example.com/groups/group1",
"members_count_with_descendants": 2,
"billable_members_count": 2,
+ "max_seats_used": 0,
+ "seats_in_use": 0,
"plan": "default",
"trial_ends_on": null,
"trial": false
diff --git a/doc/api/openapi/openapi.yaml b/doc/api/openapi/openapi.yaml
index 8aa4de62501..8c46804d86f 100644
--- a/doc/api/openapi/openapi.yaml
+++ b/doc/api/openapi/openapi.yaml
@@ -9,9 +9,9 @@ info:
When viewing this on gitlab.com, you can test API calls directly from the browser
against the `gitlab.com` instance, if you are logged in.
The feature uses the current [GitLab session cookie](https://docs.gitlab.com/ee/api/README.html#session-cookie),
- so each request is made using your account.
+ so each request is made using your account.
- Read more at <https://docs.gitlab.com/ee/development/documentation/styleguide.html#restful-api>.
+ Read more at <https://docs.gitlab.com/ee/development/documentation/restful_api_styleguide.html>.
version: "v4"
title: "GitLab API"
termsOfService: "https://about.gitlab.com/terms/"
diff --git a/doc/api/packages.md b/doc/api/packages.md
index cf65b518844..d4e69b9bc66 100644
--- a/doc/api/packages.md
+++ b/doc/api/packages.md
@@ -26,7 +26,7 @@ GET /projects/:id/packages
| `id` | integer/string | yes | ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
| `order_by`| string | no | The field to use as order. One of `created_at` (default), `name`, `version`, or `type`. |
| `sort` | string | no | The direction of the order, either `asc` (default) for ascending order or `desc` for descending order. |
-| `package_type` | string | no | Filter the returned packages by type. One of `conan`, `maven`, `npm`, `pypi`, `composer`, or `nuget`. (_Introduced in GitLab 12.9_)
+| `package_type` | string | no | Filter the returned packages by type. One of `conan`, `maven`, `npm`, `pypi`, `composer`, `nuget`, or `golang`. (_Introduced in GitLab 12.9_)
| `package_name` | string | no | Filter the project packages with a fuzzy search by name. (_Introduced in GitLab 12.9_)
```shell
@@ -50,6 +50,19 @@ Example response:
"version": "1.0.3",
"package_type": "npm",
"created_at": "2019-11-27T03:37:38.711Z"
+ },
+ {
+ "id": 3,
+ "name": "Hello/0.1@mycompany/stable",
+ "conan_package_name": "Hello",
+ "version": "0.1",
+ "package_type": "conan",
+ "_links": {
+ "web_path": "/foo/bar/-/packages/3",
+ "delete_api_path": "https://gitlab.example.com/api/v4/projects/1/packages/3"
+ },
+ "created_at": "2029-12-16T20:33:34.316Z",
+ "tags": []
}
]
```
@@ -73,7 +86,7 @@ GET /groups/:id/packages
| `exclude_subgroups` | boolean | false | If the parameter is included as true, packages from projects from subgroups are not listed. Default is `false`. |
| `order_by`| string | no | The field to use as order. One of `created_at` (default), `name`, `version`, `type`, or `project_path`. |
| `sort` | string | no | The direction of the order, either `asc` (default) for ascending order or `desc` for descending order. |
-| `package_type` | string | no | Filter the returned packages by type. One of `conan`, `maven`, `npm`, `pypi`, `composer`, or `nuget`. (_Introduced in GitLab 12.9_) |
+| `package_type` | string | no | Filter the returned packages by type. One of `conan`, `maven`, `npm`, `pypi`, `composer`, `nuget`, or `golang`. (_Introduced in GitLab 12.9_) |
| `package_name` | string | no | Filter the project packages with a fuzzy search by name. (_[Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/30980) in GitLab 13.0_)
```shell
diff --git a/doc/api/personal_access_tokens.md b/doc/api/personal_access_tokens.md
index 517e26f3d85..43310570fe8 100644
--- a/doc/api/personal_access_tokens.md
+++ b/doc/api/personal_access_tokens.md
@@ -24,7 +24,7 @@ curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/a
```
```json
-[
+[
{
"id": 4,
"name": "Test Token",
@@ -45,7 +45,7 @@ curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/a
```
```json
-[
+[
{
"id": 4,
"name": "Test Token",
diff --git a/doc/api/project_badges.md b/doc/api/project_badges.md
index 936bd40d1ee..b8ea55ab72f 100644
--- a/doc/api/project_badges.md
+++ b/doc/api/project_badges.md
@@ -16,7 +16,7 @@ Badges support placeholders that will be replaced in real time in both the link
- **%{project_path}**: will be replaced by the project path.
- **%{project_id}**: will be replaced by the project ID.
- **%{default_branch}**: will be replaced by the project default branch.
-- **%{commit_sha}**: will be replaced by the last project's commit sha.
+- **%{commit_sha}**: will be replaced by the last project's commit SHA.
## List all badges of a project
diff --git a/doc/api/project_clusters.md b/doc/api/project_clusters.md
index 04694157561..ce175184179 100644
--- a/doc/api/project_clusters.md
+++ b/doc/api/project_clusters.md
@@ -8,8 +8,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/23922) in GitLab 11.7.
-NOTE: **Note:**
-User will need at least maintainer access to use these endpoints.
+Users need at least [Maintainer](../user/permissions.md) access to use these endpoints.
## List project clusters
diff --git a/doc/api/project_repository_storage_moves.md b/doc/api/project_repository_storage_moves.md
index 2010fccc624..b490b6235b1 100644
--- a/doc/api/project_repository_storage_moves.md
+++ b/doc/api/project_repository_storage_moves.md
@@ -194,7 +194,7 @@ Parameters:
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `project_id` | integer | yes | ID of the project |
-| `destination_storage_name` | string | yes | Name of the destination storage shard |
+| `destination_storage_name` | string | no | Name of the destination storage shard. If not provided the storage will be selected automatically. |
Example request:
diff --git a/doc/api/project_snippets.md b/doc/api/project_snippets.md
index eccc8b4212d..cc8bb20b003 100644
--- a/doc/api/project_snippets.md
+++ b/doc/api/project_snippets.md
@@ -83,12 +83,17 @@ POST /projects/:id/snippets
Parameters:
-- `id` (required) - The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user
-- `title` (required) - The title of a snippet
-- `file_name` (required) - The name of a snippet file
-- `description` (optional) - The description of a snippet
-- `content` (required) - The content of a snippet
-- `visibility` (required) - The snippet's visibility
+| Attribute | Type | Required | Description |
+|:------------------|:----------------|:---------|:----------------------------------------------------------------------------------------------------------------|
+| `id` | integer | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
+| `title` | string | yes | Title of a snippet |
+| `file_name` | string | no | Deprecated: Use `files` instead. Name of a snippet file |
+| `content` | string | no | Deprecated: Use `files` instead. Content of a snippet |
+| `description` | string | no | Description of a snippet |
+| `visibility` | string | no | Snippet's [visibility](#snippet-visibility-level) |
+| `files` | array of hashes | no | An array of snippet files |
+| `files:file_path` | string | yes | File path of the snippet file |
+| `files:content` | string | yes | Content of the snippet file |
Example request:
@@ -105,9 +110,13 @@ curl --request POST "https://gitlab.com/api/v4/projects/:id/snippets" \
{
"title" : "Example Snippet Title",
"description" : "More verbose snippet description",
- "file_name" : "example.txt",
- "content" : "source code \n with multiple lines\n",
- "visibility" : "private"
+ "visibility" : "private",
+ "files": [
+ {
+ "file_path": "example.txt",
+ "content" : "source code \n with multiple lines\n",
+ }
+ ]
}
```
@@ -121,13 +130,22 @@ PUT /projects/:id/snippets/:snippet_id
Parameters:
-- `id` (required) - The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user
-- `snippet_id` (required) - The ID of a project's snippet
-- `title` (optional) - The title of a snippet
-- `file_name` (optional) - The name of a snippet file
-- `description` (optional) - The description of a snippet
-- `content` (optional) - The content of a snippet
-- `visibility` (optional) - The snippet's visibility
+| Attribute | Type | Required | Description |
+|:----------------------|:----------------|:---------|:----------------------------------------------------------------------------------------------------------------|
+| `id` | integer | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
+| `snippet_id` | integer | yes | The ID of a project's snippet |
+| `title` | string | no | Title of a snippet |
+| `file_name` | string | no | Deprecated: Use `files` instead. Name of a snippet file |
+| `content` | string | no | Deprecated: Use `files` instead. Content of a snippet |
+| `description` | string | no | Description of a snippet |
+| `visibility` | string | no | Snippet's [visibility](#snippet-visibility-level) |
+| `files` | array of hashes | no | An array of snippet files |
+| `files:action` | string | yes | Type of action to perform on the file, one of: 'create', 'update', 'delete', 'move' |
+| `files:file_path` | string | no | File path of the snippet file |
+| `files:previous_path` | string | no | Previous path of the snippet file |
+| `files:content` | string | no | Content of the snippet file |
+
+Updates to snippets with multiple files *must* use the `files` attribute.
Example request:
@@ -144,9 +162,14 @@ curl --request PUT "https://gitlab.com/api/v4/projects/:id/snippets/:snippet_id"
{
"title" : "Updated Snippet Title",
"description" : "More verbose snippet description",
- "file_name" : "new_filename.txt",
- "content" : "updated source code \n with multiple lines\n",
- "visibility" : "private"
+ "visibility" : "private",
+ "files": [
+ {
+ "action": "update",
+ "file_path": "example.txt",
+ "content" : "updated source code \n with multiple lines\n"
+ }
+ ]
}
```
diff --git a/doc/api/projects.md b/doc/api/projects.md
index ad26457ad99..f6ed905cda1 100644
--- a/doc/api/projects.md
+++ b/doc/api/projects.md
@@ -156,6 +156,7 @@ When the user is authenticated and `simple` is not set this returns something li
"star_count": 0,
"runners_token": "b8547b1dc37721d05889db52fa2f02",
"ci_default_git_depth": 50,
+ "ci_forward_deployment_enabled": true,
"public_jobs": true,
"shared_with_groups": [],
"only_allow_merge_if_pipeline_succeeds": false,
@@ -248,6 +249,7 @@ When the user is authenticated and `simple` is not set this returns something li
"star_count": 0,
"runners_token": "b8547b1dc37721d05889db52fa2f02",
"ci_default_git_depth": 0,
+ "ci_forward_deployment_enabled": true,
"public_jobs": true,
"shared_with_groups": [],
"only_allow_merge_if_pipeline_succeeds": false,
@@ -410,6 +412,7 @@ This endpoint supports [keyset pagination](README.md#keyset-based-pagination) fo
"star_count": 0,
"runners_token": "b8547b1dc37721d05889db52fa2f02",
"ci_default_git_depth": 50,
+ "ci_forward_deployment_enabled": true,
"public_jobs": true,
"shared_with_groups": [],
"only_allow_merge_if_pipeline_succeeds": false,
@@ -502,6 +505,7 @@ This endpoint supports [keyset pagination](README.md#keyset-based-pagination) fo
"star_count": 0,
"runners_token": "b8547b1dc37721d05889db52fa2f02",
"ci_default_git_depth": 0,
+ "ci_forward_deployment_enabled": true,
"public_jobs": true,
"shared_with_groups": [],
"only_allow_merge_if_pipeline_succeeds": false,
@@ -856,6 +860,7 @@ GET /projects/:id
"star_count": 0,
"runners_token": "b8bc4a7a29eb76ea83cf79e4908c2b",
"ci_default_git_depth": 50,
+ "ci_forward_deployment_enabled": true,
"public_jobs": true,
"shared_with_groups": [
{
@@ -1218,6 +1223,7 @@ PUT /projects/:id
| `build_coverage_regex` | string | no | Test coverage parsing |
| `ci_config_path` | string | no | The path to CI configuration file |
| `ci_default_git_depth` | integer | no | Default number of revisions for [shallow cloning](../ci/pipelines/settings.md#git-shallow-clone) |
+| `ci_forward_deployment_enabled` | boolean | no | When a new deployment job starts, [skip older deployment jobs](../ci/pipelines/settings.md#skip-outdated-deployment-jobs) that are still pending |
| `auto_devops_enabled` | boolean | no | Enable Auto DevOps for this project |
| `auto_devops_deploy_strategy` | string | no | Auto Deploy strategy (`continuous`, `manual` or `timed_incremental`) |
| `repository_storage` | string | no | Which storage shard the repository is on. Available only to admins |
@@ -1701,6 +1707,7 @@ Example response:
"star_count": 0,
"runners_token": "b8bc4a7a29eb76ea83cf79e4908c2b",
"ci_default_git_depth": 50,
+ "ci_forward_deployment_enabled": true,
"public_jobs": true,
"shared_with_groups": [],
"only_allow_merge_if_pipeline_succeeds": false,
@@ -1811,6 +1818,7 @@ Example response:
"star_count": 0,
"runners_token": "b8bc4a7a29eb76ea83cf79e4908c2b",
"ci_default_git_depth": 50,
+ "ci_forward_deployment_enabled": true,
"public_jobs": true,
"shared_with_groups": [],
"only_allow_merge_if_pipeline_succeeds": false,
@@ -2241,6 +2249,113 @@ PUT /projects/:id/transfer
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
| `namespace` | integer/string | yes | The ID or path of the namespace to transfer to project to |
+Example request:
+
+```shell
+curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/5/transfer?namespace=14"
+```
+
+Example response:
+
+```json
+ {
+ "id": 7,
+ "description": "",
+ "name": "hello-world",
+ "name_with_namespace": "cute-cats / hello-world",
+ "path": "hello-world",
+ "path_with_namespace": "cute-cats/hello-world",
+ "created_at": "2020-10-15T16:25:22.415Z",
+ "default_branch": "master",
+ "tag_list": [],
+ "ssh_url_to_repo": "git@gitlab.example.com:cute-cats/hello-world.git",
+ "http_url_to_repo": "https://gitlab.example.com/cute-cats/hello-world.git",
+ "web_url": "https://gitlab.example.com/cute-cats/hello-world",
+ "readme_url": "https://gitlab.example.com/cute-cats/hello-world/-/blob/master/README.md",
+ "avatar_url": null,
+ "forks_count": 0,
+ "star_count": 0,
+ "last_activity_at": "2020-10-15T16:25:22.415Z",
+ "namespace": {
+ "id": 18,
+ "name": "cute-cats",
+ "path": "cute-cats",
+ "kind": "group",
+ "full_path": "cute-cats",
+ "parent_id": null,
+ "avatar_url": null,
+ "web_url": "https://gitlab.example.com/groups/cute-cats"
+ },
+ "_links": {
+ "self": "https://gitlab.example.com/api/v4/projects/7",
+ "issues": "https://gitlab.example.com/api/v4/projects/7/issues",
+ "merge_requests": "https://gitlab.example.com/api/v4/projects/7/merge_requests",
+ "repo_branches": "https://gitlab.example.com/api/v4/projects/7/repository/branches",
+ "labels": "https://gitlab.example.com/api/v4/projects/7/labels",
+ "events": "https://gitlab.example.com/api/v4/projects/7/events",
+ "members": "https://gitlab.example.com/api/v4/projects/7/members"
+ },
+ "packages_enabled": true,
+ "empty_repo": false,
+ "archived": false,
+ "visibility": "private",
+ "resolve_outdated_diff_discussions": false,
+ "container_registry_enabled": true,
+ "container_expiration_policy": {
+ "cadence": "7d",
+ "enabled": false,
+ "keep_n": null,
+ "older_than": null,
+ "name_regex": null,
+ "name_regex_keep": null,
+ "next_run_at": "2020-10-22T16:25:22.746Z"
+ },
+ "issues_enabled": true,
+ "merge_requests_enabled": true,
+ "wiki_enabled": true,
+ "jobs_enabled": true,
+ "snippets_enabled": true,
+ "service_desk_enabled": false,
+ "service_desk_address": null,
+ "can_create_merge_request_in": true,
+ "issues_access_level": "enabled",
+ "repository_access_level": "enabled",
+ "merge_requests_access_level": "enabled",
+ "forking_access_level": "enabled",
+ "wiki_access_level": "enabled",
+ "builds_access_level": "enabled",
+ "snippets_access_level": "enabled",
+ "pages_access_level": "enabled",
+ "emails_disabled": null,
+ "shared_runners_enabled": true,
+ "lfs_enabled": true,
+ "creator_id": 2,
+ "import_status": "none",
+ "open_issues_count": 0,
+ "ci_default_git_depth": 50,
+ "public_jobs": true,
+ "build_timeout": 3600,
+ "auto_cancel_pending_pipelines": "enabled",
+ "build_coverage_regex": null,
+ "ci_config_path": null,
+ "shared_with_groups": [],
+ "only_allow_merge_if_pipeline_succeeds": false,
+ "allow_merge_on_skipped_pipeline": null,
+ "request_access_enabled": true,
+ "only_allow_merge_if_all_discussions_are_resolved": false,
+ "remove_source_branch_after_merge": true,
+ "printing_merge_request_link_enabled": true,
+ "merge_method": "merge",
+ "suggestion_commit_message": null,
+ "auto_devops_enabled": true,
+ "auto_devops_deploy_strategy": "continuous",
+ "autoclose_referenced_issues": true,
+ "approvals_before_merge": 0,
+ "mirror": false,
+ "compliance_frameworks": []
+}
+```
+
## Branches
Read more in the [Branches](branches.md) documentation.
diff --git a/doc/api/protected_branches.md b/doc/api/protected_branches.md
index 05d586738d0..79b848bdf15 100644
--- a/doc/api/protected_branches.md
+++ b/doc/api/protected_branches.md
@@ -295,6 +295,67 @@ Example response:
}
```
+### Example with allow to push and allow to merge access **(STARTER)**
+
+Example request:
+
+```shell
+curl --request POST \
+ --header "PRIVATE-TOKEN: <your_access_token>" \
+ --header "Content-Type: application/json" \
+ --data '{
+ "id": 5,
+ "name": "master",
+ "allowed_to_push": [{"access_level": 30}],
+ "allowed_to_merge": [{
+ "access_level": 30
+ },{
+ "access_level": 40
+ }
+ ]}'
+ "https://gitlab.example.com/api/v4/projects/5/protected_branches"
+```
+
+Example response:
+
+```json
+{
+ "id": 5,
+ "name": "master",
+ "push_access_levels": [
+ {
+ "access_level": 30,
+ "access_level_description": "Developers + Maintainers",
+ "user_id": null,
+ "group_id": null
+ }
+ ],
+ "merge_access_levels": [
+ {
+ "access_level": 30,
+ "access_level_description": "Developers + Maintainers",
+ "user_id": null,
+ "group_id": null
+ },
+ {
+ "access_level": 40,
+ "access_level_description": "Maintainers",
+ "user_id": null,
+ "group_id": null
+ }
+ ],
+ "unprotect_access_levels": [
+ {
+ "access_level": 40,
+ "access_level_description": "Maintainers",
+ "user_id": null,
+ "group_id": null
+ }
+ ],
+ "code_owner_approval_required": false
+}
+```
+
## Unprotect repository branches
Unprotects the given protected branch or wildcard protected branch.
diff --git a/doc/api/releases/index.md b/doc/api/releases/index.md
index 357f7e7a125..4dac9f61469 100644
--- a/doc/api/releases/index.md
+++ b/doc/api/releases/index.md
@@ -22,6 +22,8 @@ GET /projects/:id/releases
| Attribute | Type | Required | Description |
| ------------- | -------------- | -------- | ----------------------------------------------------------------------------------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](../README.md#namespaced-path-encoding). |
+| `order_by` | string | no | The field to use as order. Either `released_at` (default) or `created_at`. |
+| `sort` | string | no | The direction of the order. Either `desc` (default) for descending order or `asc` for ascending order. |
Example request:
@@ -361,11 +363,11 @@ POST /projects/:id/releases
| `tag_name` | string | yes | The tag where the release will be created from. |
| `description` | string | no | The description of the release. You can use [Markdown](../../user/markdown.md). |
| `ref` | string | yes, if `tag_name` doesn't exist | If a tag specified in `tag_name` doesn't exist, the release will be created from `ref` and tagged with `tag_name`. It can be a commit SHA, another tag name, or a branch name. |
-| `milestones` | array of string | no | The title of each milestone the release is associated with. |
+| `milestones` | array of string | no | The title of each milestone the release is associated with. [GitLab Premium](https://about.gitlab.com/pricing/) customers can specify group milestones. |
| `assets:links` | array of hash | no | An array of assets links. |
| `assets:links:name`| string | required by: `assets:links` | The name of the link. |
| `assets:links:url` | string | required by: `assets:links` | The URL of the link. |
-| `assets:links:filepath` | string | no | Optional path for a [Direct Asset link](../../user/project/releases.md).
+| `assets:links:filepath` | string | no | Optional path for a [Direct Asset link](../../user/project/releases/index.md).
| `assets:links:link_type` | string | no | The type of the link: `other`, `runbook`, `image`, `package`. Defaults to `other`.
| `released_at` | datetime | no | The date when the release will be/was ready. Defaults to the current time. Expected in ISO 8601 format (`2019-03-15T08:00:00Z`). |
@@ -484,6 +486,15 @@ Example response:
}
```
+### Group milestones **(PREMIUM ONLY)**
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/235391) in [GitLab Premium](https://about.gitlab.com/pricing/) 13.5.
+
+Group milestones associated with the project may be specified in the `milestones`
+array for [Create a release](#create-a-release) and [Update a release](#update-a-release)
+API calls. Only milestones associated with the project's group may be specified, and
+adding milestones for ancestor groups will raise an error.
+
## Collect release evidence **(PREMIUM ONLY)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/199065) in [GitLab Premium](https://about.gitlab.com/pricing/) 12.10.
@@ -525,7 +536,7 @@ PUT /projects/:id/releases/:tag_name
| `tag_name` | string | yes | The tag where the release will be created from. |
| `name` | string | no | The release name. |
| `description` | string | no | The description of the release. You can use [Markdown](../../user/markdown.md). |
-| `milestones` | array of string | no | The title of each milestone to associate with the release (`[]` to remove all milestones from the release). |
+| `milestones` | array of string | no | The title of each milestone to associate with the release. [GitLab Premium](https://about.gitlab.com/pricing/) customers can specify group milestones. To remove all milestones from the release, specify `[]`. |
| `released_at` | datetime | no | The date when the release will be/was ready. Expected in ISO 8601 format (`2019-03-15T08:00:00Z`). |
Example request:
diff --git a/doc/api/repositories.md b/doc/api/repositories.md
index 305216f853a..7e94ff7b7f2 100644
--- a/doc/api/repositories.md
+++ b/doc/api/repositories.md
@@ -24,7 +24,8 @@ Parameters:
- `path` (optional) - The path inside repository. Used to get content of subdirectories
- `ref` (optional) - The name of a repository branch or tag or if not given the default branch
- `recursive` (optional) - Boolean value used to get a recursive tree (false by default)
-- `per_page` (optional) - Number of results to show per page. If not specified, defaults to `20`
+- `per_page` (optional) - Number of results to show per page. If not specified, defaults to `20`.
+ Read more on [pagination](README.md#pagination).
```json
[
diff --git a/doc/api/resource_iteration_events.md b/doc/api/resource_iteration_events.md
index f774cdfe9c7..47f4d70fdf1 100644
--- a/doc/api/resource_iteration_events.md
+++ b/doc/api/resource_iteration_events.md
@@ -6,14 +6,8 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Resource iteration events API **(STARTER)**
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/40850) in [GitLab Starter](https://about.gitlab.com/pricing/) 13.4
-> - It's [deployed behind a feature flag](../user/feature_flags.md), enabled by default.
-> - It's enabled on GitLab.com.
-> - It's recommended for production use.
-> - For GitLab self-managed instances, GitLab administrators can opt to [disable it](#enable-or-disable-iterations-events-tracking).
-
-NOTE: **Note:**
-This feature might not be available to you. Check the **version history** note above for details.
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/229463) in [GitLab Starter](https://about.gitlab.com/pricing/) 13.4.
+> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/229463) in [GitLab Starter](https://about.gitlab.com/pricing/) 13.5.
Resource iteration events keep track of what happens to GitLab [issues](../user/project/issues/).
@@ -154,22 +148,3 @@ Example response:
"action": "remove"
}
```
-
-### Enable or disable iterations events tracking **(STARTER)**
-
-Iterations events tracking is under development but ready for production use.
-It is deployed behind a feature flag that is **enabled by default**.
-[GitLab administrators with access to the GitLab Rails console](../administration/feature_flags.md)
-can opt to disable it.
-
-To enable it:
-
-```ruby
-Feature.enable(:track_iteration_change_events)
-```
-
-To disable it:
-
-```ruby
-Feature.disable(:track_iteration_change_events)
-```
diff --git a/doc/api/runners.md b/doc/api/runners.md
index 436abe0a706..16ecdebcd4f 100644
--- a/doc/api/runners.md
+++ b/doc/api/runners.md
@@ -271,20 +271,20 @@ Example response:
}
```
-## Remove a runner
+### Pause a runner
-Remove a runner.
+Pause a specific runner.
```plaintext
-DELETE /runners/:id
+PUT --form "active=false" /runners/:runner_id
```
-| Attribute | Type | Required | Description |
-|-----------|---------|----------|---------------------|
-| `id` | integer | yes | The ID of a runner |
+| Attribute | Type | Required | Description |
+|-------------|---------|----------|---------------------|
+| `runner_id` | integer | yes | The ID of a runner |
```shell
-curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/runners/6"
+curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" --form "active=false" "https://gitlab.example.com/api/v4/runners/6"
```
## List runner's jobs
@@ -466,7 +466,7 @@ Example response:
Disable a specific runner from the project. It works only if the project isn't
the only project associated with the specified runner. If so, an error is
-returned. Use the [Remove a runner](#remove-a-runner) call instead.
+returned. Use the call to [delete a runner](#delete-a-runner) instead.
```plaintext
DELETE /projects/:id/runners/:runner_id
@@ -553,7 +553,7 @@ POST /runners
|--------------|---------|----------|---------------------|
| `token` | string | yes | [Registration token](#registration-and-authentication-tokens). |
| `description`| string | no | Runner's description|
-| `info` | hash | no | Runner's metadata |
+| `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 | Whether the runner is active |
| `locked` | boolean | no | Whether the runner should be locked for current project |
| `run_untagged` | boolean | no | Whether the runner should handle untagged jobs |
@@ -580,9 +580,32 @@ Example response:
}
```
-## Delete a registered runner
+## Delete a runner
+
+There are two ways to delete a runner:
+
+- By specifying the runner ID.
+- By specifying the runner's authentication token.
-Deletes a registered runner.
+### Delete a runner by ID
+
+To delete the runner by ID, use your access token with the runner's ID:
+
+```plaintext
+DELETE /runners/:id
+```
+
+| Attribute | Type | Required | Description |
+|-------------|---------|----------|---------------------|
+| `id` | integer | yes | The ID of a runner. The ID is visible in the UI under **Settings > CI/CD**. Expand **Runners**, and below the **Remove Runner** button is an ID preceded by the pound sign, for example, `#6`. |
+
+```shell
+curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/runners/6"
+```
+
+### Delete a runner by authentication token
+
+To delete the runner by using its authentication token:
```plaintext
DELETE /runners
@@ -590,7 +613,7 @@ DELETE /runners
| Attribute | Type | Required | Description |
|-------------|---------|----------|---------------------|
-| `token` | string | yes | Runner's [authentication token](#registration-and-authentication-tokens). |
+| `token` | string | yes | The runner's [authentication token](#registration-and-authentication-tokens). |
```shell
curl --request DELETE "https://gitlab.example.com/api/v4/runners" --form "token=<authentication_token>"
diff --git a/doc/api/search.md b/doc/api/search.md
index cb90b9a064c..bdf5bdd4924 100644
--- a/doc/api/search.md
+++ b/doc/api/search.md
@@ -24,10 +24,11 @@ GET /search
| `scope` | string | yes | The scope to search in |
| `search` | string | yes | The search query |
| `state` | string | no | Filter by state. Issues and merge requests are supported; it is ignored for other scopes. |
+| `confidential` | boolean | no | Filter by confidentiality. Issues scope is supported; it is ignored for other scopes. This parameter is behind a [feature flag (`search_filter_by_confidential`)](../administration/feature_flags.md). |
Search the expression within the specified scope. Currently these scopes are supported: projects, issues, merge_requests, milestones, snippet_titles, users.
-If Elasticsearch is enabled additional scopes available are blobs, wiki_blobs and commits. Find more about [the feature](../integration/elasticsearch.md). **(STARTER)**
+If Elasticsearch is enabled additional scopes available are blobs, wiki_blobs, notes, and commits. Find more about [the feature](../integration/elasticsearch.md). **(STARTER)**
The response depends on the requested scope.
@@ -362,6 +363,40 @@ Example response:
NOTE: **Note:**
`filename` is deprecated in favor of `path`. Both return the full path of the file inside the repository, but in the future `filename` will be only the file name and not the full path. For details, see [issue 34521](https://gitlab.com/gitlab-org/gitlab/-/issues/34521).
+### Scope: notes **(STARTER)**
+
+This scope is available only if [Elasticsearch](../integration/elasticsearch.md) is enabled.
+
+```shell
+curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/6/search?scope=notes&search=maxime"
+```
+
+Example response:
+
+```json
+[
+ {
+ "id": 191,
+ "body": "Harum maxime consequuntur et et deleniti assumenda facilis.",
+ "attachment": null,
+ "author": {
+ "id": 23,
+ "name": "User 1",
+ "username": "user1",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/111d68d06e2d317b5a59c2c6c5bad808?s=80&d=identicon",
+ "web_url": "http://localhost:3000/user1"
+ },
+ "created_at": "2017-09-05T08:01:32.068Z",
+ "updated_at": "2017-09-05T08:01:32.068Z",
+ "system": false,
+ "noteable_id": 22,
+ "noteable_type": "Issue",
+ "noteable_iid": 2
+ }
+]
+```
+
### Scope: users
```shell
@@ -399,10 +434,11 @@ GET /groups/:id/search
| `scope` | string | yes | The scope to search in |
| `search` | string | yes | The search query |
| `state` | string | no | Filter by state. Issues and merge requests are supported; it is ignored for other scopes. |
+| `confidential` | boolean | no | Filter by confidentiality. Issues scope is supported; it is ignored for other scopes. This parameter is behind a [feature flag (`search_filter_by_confidential`)](../administration/feature_flags.md). |
Search the expression within the specified scope. Currently these scopes are supported: projects, issues, merge_requests, milestones, users.
-If Elasticsearch is enabled additional scopes available are blobs, wiki_blobs and commits. Find more about [the feature](../integration/elasticsearch.md). **(STARTER)**
+If Elasticsearch is enabled additional scopes available are blobs, wiki_blobs, notes, and commits. Find more about [the feature](../integration/elasticsearch.md). **(STARTER)**
The response depends on the requested scope.
@@ -706,6 +742,40 @@ Example response:
NOTE **Note:**
`filename` is deprecated in favor of `path`. Both return the full path of the file inside the repository, but in the future `filename` will be only the file name and not the full path. For details, see [issue 34521](https://gitlab.com/gitlab-org/gitlab/-/issues/34521).
+### Scope: notes **(STARTER)**
+
+This scope is available only if [Elasticsearch](../integration/elasticsearch.md) is enabled.
+
+```shell
+curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/6/search?scope=notes&search=maxime"
+```
+
+Example response:
+
+```json
+[
+ {
+ "id": 191,
+ "body": "Harum maxime consequuntur et et deleniti assumenda facilis.",
+ "attachment": null,
+ "author": {
+ "id": 23,
+ "name": "User 1",
+ "username": "user1",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/111d68d06e2d317b5a59c2c6c5bad808?s=80&d=identicon",
+ "web_url": "http://localhost:3000/user1"
+ },
+ "created_at": "2017-09-05T08:01:32.068Z",
+ "updated_at": "2017-09-05T08:01:32.068Z",
+ "system": false,
+ "noteable_id": 22,
+ "noteable_type": "Issue",
+ "noteable_iid": 2
+ }
+]
+```
+
### Scope: users
```shell
@@ -744,6 +814,7 @@ GET /projects/:id/search
| `search` | string | yes | The search query |
| `ref` | string | no | The name of a repository branch or tag to search on. The project's default branch is used by default. This is only applicable for scopes: commits, blobs, and wiki_blobs. |
| `state` | string | no | Filter by state. Issues and merge requests are supported; it is ignored for other scopes. |
+| `confidential` | boolean | no | Filter by confidentiality. Issues scope is supported; it is ignored for other scopes. This parameter is behind a [feature flag (`search_filter_by_confidential`)](../administration/feature_flags.md). |
Search the expression within the specified scope. Currently these scopes are supported: issues, merge_requests, milestones, notes, wiki_blobs, commits, blobs, users.
diff --git a/doc/api/services.md b/doc/api/services.md
index 405047a433d..7c01e43a4d8 100644
--- a/doc/api/services.md
+++ b/doc/api/services.md
@@ -659,7 +659,7 @@ Parameters:
| `webhook` | string | true | The Hangouts Chat webhook. For example, `https://chat.googleapis.com/v1/spaces...`. |
| `notify_only_broken_pipelines` | boolean | false | Send notifications for broken pipelines |
| `notify_only_default_branch` | boolean | false | DEPRECATED: This parameter has been replaced with `branches_to_be_notified` |
-| `branches_to_be_notified` | string | all | Branches to send notifications for. Valid options are "all", "default", "protected", and "default_and_protected" |
+| `branches_to_be_notified` | string | false | Branches to send notifications for. Valid options are "all", "default", "protected", and "default_and_protected" |
| `push_events` | boolean | false | Enable notifications for push events |
| `issues_events` | boolean | false | Enable notifications for issue events |
| `confidential_issues_events` | boolean | false | Enable notifications for confidential issue events |
@@ -714,7 +714,7 @@ Parameters:
| `merge_requests_events` | boolean | false | Enable notifications for merge request events |
| `tag_push_events` | boolean | false | Enable notifications for tag push events |
| `note_events` | boolean | false | Enable notifications for note events |
-| `confidental_note_events` | boolean | false | Enable notifications for confidential note events |
+| `confidential_note_events` | boolean | false | Enable notifications for confidential note events |
| `pipeline_events` | boolean | false | Enable notifications for pipeline events |
### Delete HipChat service
diff --git a/doc/api/settings.md b/doc/api/settings.md
index c8a466d1fcd..236cd10a30e 100644
--- a/doc/api/settings.md
+++ b/doc/api/settings.md
@@ -2,8 +2,8 @@
These API calls allow you to read and modify GitLab instance
[application settings](#list-of-settings-that-can-be-accessed-via-api-calls)
-as appear in `/admin/application_settings/general`. You have to be an
-administrator in order to perform this action.
+as they appear in `/admin/application_settings/general`. You must be an
+administrator to perform this action.
## Get current application settings
@@ -185,13 +185,14 @@ Example responses: **(PREMIUM ONLY)**
## List of settings that can be accessed via API calls
-In general, all settings are optional. Certain settings though, if enabled, will
-require other settings to be set in order to function properly. These requirements
-are listed in the descriptions of the relevant settings.
+In general, all settings are optional. Certain settings though, if enabled,
+require other settings to be set to function properly. These requirements are
+listed in the descriptions of the relevant settings.
-| Attribute | Type | Required | Description |
-| --------- | ---- | :------: | ----------- |
-| `admin_notification_email` | string | no | Abuse reports will be sent to this address if it is set. Abuse reports are always available in the Admin Area. |
+| Attribute | Type | Required | Description |
+|------------------------------------------|------------------|:------------------------------------:|-------------|
+| `admin_notification_email` | string | no | Deprecated: Use `abuse_notification_email` instead. If set, [abuse reports](../user/admin_area/abuse_reports.md) are sent to this address. Abuse reports are always available in the Admin Area. |
+| `abuse_notification_email` | string | no | If set, [abuse reports](../user/admin_area/abuse_reports.md) are sent to this address. Abuse reports are always available in the Admin Area. |
| `after_sign_out_path` | string | no | Where to redirect users after logout. |
| `after_sign_up_text` | string | no | Text shown to the user after signing up |
| `akismet_api_key` | string | required by: `akismet_enabled` | API key for Akismet spam protection. |
@@ -208,6 +209,7 @@ are listed in the descriptions of the relevant settings.
| `authorized_keys_enabled` | boolean | no | By default, we write to the `authorized_keys` file to support Git over SSH without additional configuration. GitLab can be optimized to authenticate SSH keys via the database file. Only disable this if you have configured your OpenSSH server to use the AuthorizedKeysCommand. |
| `auto_devops_domain` | string | no | Specify a domain to use by default for every project's Auto Review Apps and Auto Deploy stages. |
| `auto_devops_enabled` | boolean | no | Enable Auto DevOps for projects by default. It will automatically build, test, and deploy applications based on a predefined CI/CD configuration. |
+| `automatic_purchased_storage_allocation` | boolean | no | Enabling this permits automatic allocation of purchased storage within a namespace. |
| `check_namespace_plan` | boolean | no | **(PREMIUM)** Enabling this will make only licensed EE features available to projects if the project namespace's plan includes the feature or if the project is public. |
| `commit_email_hostname` | string | no | Custom hostname (for private commit emails). |
| `container_registry_token_expire_delay` | integer | no | Container Registry token duration in minutes. |
@@ -255,10 +257,10 @@ are listed in the descriptions of the relevant settings.
| `external_auth_client_cert` | string | no | (**If enabled, requires:** `external_auth_client_key`) The certificate to use to authenticate with the external authorization service |
| `external_auth_client_key_pass` | string | no | Passphrase to use for the private key when authenticating with the external service this is encrypted when stored |
| `external_auth_client_key` | string | required by: `external_auth_client_cert` | Private key for the certificate when authentication is required for the external authorization service, this is encrypted when stored |
-| `external_authorization_service_default_label` | string | required by: `external_authorization_service_enabled` | The default classification label to use when requesting authorization and no classification label has been specified on the project |
+| `external_authorization_service_default_label` | string | required by:<br>`external_authorization_service_enabled` | The default classification label to use when requesting authorization and no classification label has been specified on the project. |
| `external_authorization_service_enabled` | boolean | no | (**If enabled, requires:** `external_authorization_service_default_label`, `external_authorization_service_timeout` and `external_authorization_service_url`) Enable using an external authorization service for accessing projects |
-| `external_authorization_service_timeout` | float | required by: `external_authorization_service_enabled` | The timeout after which an authorization request is aborted, in seconds. When a request times out, access is denied to the user. (min: 0.001, max: 10, step: 0.001) |
-| `external_authorization_service_url` | string | required by: `external_authorization_service_enabled` | URL to which authorization requests will be directed |
+| `external_authorization_service_timeout` | float | required by:<br>`external_authorization_service_enabled` | The timeout after which an authorization request is aborted, in seconds. When a request times out, access is denied to the user. (min: 0.001, max: 10, step: 0.001). |
+| `external_authorization_service_url` | string | required by:<br>`external_authorization_service_enabled` | URL to which authorization requests are directed. |
| `file_template_project_id` | integer | no | **(PREMIUM)** The ID of a project to load custom file templates from |
| `first_day_of_week` | integer | no | Start day of the week for calendar views and date pickers. Valid values are `0` (default) for Sunday, `1` for Monday, and `6` for Saturday. |
| `geo_node_allowed_ips` | string | yes | **(PREMIUM)** Comma-separated list of IPs and CIDRs of allowed secondary nodes. For example, `1.1.1.1, 2.2.2.0/24`. |
@@ -298,7 +300,7 @@ are listed in the descriptions of the relevant settings.
| `mirror_max_capacity` | integer | no | **(PREMIUM)** Maximum number of mirrors that can be synchronizing at the same time. |
| `mirror_max_delay` | integer | no | **(PREMIUM)** Maximum time (in minutes) between updates that a mirror can have when scheduled to synchronize. |
| `npm_package_requests_forwarding` | boolean | no | **(PREMIUM)** Use npmjs.org as a default remote repository when the package is not found in the GitLab NPM Registry |
-| `outbound_local_requests_whitelist` | array of strings | no | Define a list of trusted domains or ip addresses to which local requests are allowed when local requests for hooks and services are disabled.
+| `outbound_local_requests_whitelist` | array of strings | no | Define a list of trusted domains or IP addresses to which local requests are allowed when local requests for hooks and services are disabled.
| `pages_domain_verification_enabled` | boolean | no | Require users to prove ownership of custom domains. Domain verification is an essential security measure for public GitLab sites. Users are required to demonstrate they control a domain before it is enabled. |
| `password_authentication_enabled_for_git` | boolean | no | Enable authentication for Git over HTTP(S) via a GitLab account password. Default is `true`. |
| `password_authentication_enabled_for_web` | boolean | no | Enable authentication for the web interface via a GitLab account password. Default is `true`. |
@@ -321,7 +323,7 @@ are listed in the descriptions of the relevant settings.
| `receive_max_input_size` | integer | no | Maximum push size (MB). |
| `repository_checks_enabled` | boolean | no | GitLab will periodically run `git fsck` in all project and wiki repositories to look for silent disk corruption issues. |
| `repository_size_limit` | integer | no | **(PREMIUM)** Size limit per repository (MB) |
-| `repository_storages_weighted` | hash of strings to integers | no | (GitLab 13.1 and later) Hash of names of taken from `gitlab.yml` to weights. New projects are created in one of these stores, chosen by a weighted random selection. |
+| `repository_storages_weighted` | hash of strings to integers | no | (GitLab 13.1 and later) Hash of names of taken from `gitlab.yml` to [weights](../administration/repository_storage_paths.md#choose-where-new-repositories-will-be-stored). New projects are created in one of these stores, chosen by a weighted random selection. |
| `repository_storages` | array of strings | no | (GitLab 13.0 and earlier) List of names of enabled storage paths, taken from `gitlab.yml`. New projects are created in one of these stores, chosen at random. |
| `require_two_factor_authentication` | boolean | no | (**If enabled, requires:** `two_factor_grace_period`) Require all users to set up Two-factor authentication. |
| `restricted_visibility_levels` | array of strings | no | Selected levels cannot be used by non-admin users for groups, projects or snippets. Can take `private`, `internal` and `public` as a parameter. Default is `null` which means there is no restriction. |
@@ -351,17 +353,17 @@ are listed in the descriptions of the relevant settings.
| `terminal_max_session_time` | integer | no | Maximum time for web terminal websocket connection (in seconds). Set to `0` for unlimited time. |
| `terms` | text | required by: `enforce_terms` | (**Required by:** `enforce_terms`) Markdown content for the ToS. |
| `throttle_authenticated_api_enabled` | boolean | no | (**If enabled, requires:** `throttle_authenticated_api_period_in_seconds` and `throttle_authenticated_api_requests_per_period`) Enable authenticated API request rate limit. Helps reduce request volume (for example, from crawlers or abusive bots). |
-| `throttle_authenticated_api_period_in_seconds` | integer | required by: `throttle_authenticated_api_enabled` | Rate limit period in seconds. |
-| `throttle_authenticated_api_requests_per_period` | integer | required by: `throttle_authenticated_api_enabled` | Max requests per period per user. |
+| `throttle_authenticated_api_period_in_seconds` | integer | required by:<br>`throttle_authenticated_api_enabled` | Rate limit period in seconds. |
+| `throttle_authenticated_api_requests_per_period` | integer | required by:<br>`throttle_authenticated_api_enabled` | Max requests per period per user. |
| `throttle_authenticated_web_enabled` | boolean | no | (**If enabled, requires:** `throttle_authenticated_web_period_in_seconds` and `throttle_authenticated_web_requests_per_period`) Enable authenticated web request rate limit. Helps reduce request volume (for example, from crawlers or abusive bots). |
-| `throttle_authenticated_web_period_in_seconds` | integer | required by: `throttle_authenticated_web_enabled` | Rate limit period in seconds. |
-| `throttle_authenticated_web_requests_per_period` | integer | required by: `throttle_authenticated_web_enabled` | Max requests per period per user. |
+| `throttle_authenticated_web_period_in_seconds` | integer | required by:<br>`throttle_authenticated_web_enabled` | Rate limit period in seconds. |
+| `throttle_authenticated_web_requests_per_period` | integer | required by:<br>`throttle_authenticated_web_enabled` | Max requests per period per user. |
| `throttle_unauthenticated_enabled` | boolean | no | (**If enabled, requires:** `throttle_unauthenticated_period_in_seconds` and `throttle_unauthenticated_requests_per_period`) Enable unauthenticated request rate limit. Helps reduce request volume (for example, from crawlers or abusive bots). |
-| `throttle_unauthenticated_period_in_seconds` | integer | required by: `throttle_unauthenticated_enabled` | Rate limit period in seconds. |
-| `throttle_unauthenticated_requests_per_period` | integer | required by: `throttle_unauthenticated_enabled` | Max requests per period per IP. |
+| `throttle_unauthenticated_period_in_seconds` | integer | required by:<br>`throttle_unauthenticated_enabled` | Rate limit period in seconds. |
+| `throttle_unauthenticated_requests_per_period` | integer | required by:<br>`throttle_unauthenticated_enabled` | Max requests per period per IP. |
| `time_tracking_limit_to_hours` | boolean | no | Limit display of time tracking units to hours. Default is `false`. |
| `two_factor_grace_period` | integer | required by: `require_two_factor_authentication` | Amount of time (in hours) that users are allowed to skip forced configuration of two-factor authentication. |
-| `unique_ips_limit_enabled` | boolean | no | (**If enabled, requires:** `unique_ips_limit_per_user` and `unique_ips_limit_time_window`) Limit sign in from multiple ips. |
+| `unique_ips_limit_enabled` | boolean | no | (**If enabled, requires:** `unique_ips_limit_per_user` and `unique_ips_limit_time_window`) Limit sign in from multiple IPs. |
| `unique_ips_limit_per_user` | integer | required by: `unique_ips_limit_enabled` | Maximum number of IPs per user. |
| `unique_ips_limit_time_window` | integer | required by: `unique_ips_limit_enabled` | How many seconds an IP will be counted towards the limit. |
| `usage_ping_enabled` | boolean | no | Every week GitLab will report license usage back to GitLab, Inc. |
diff --git a/doc/api/snippets.md b/doc/api/snippets.md
index 6863763ff24..431d745ac84 100644
--- a/doc/api/snippets.md
+++ b/doc/api/snippets.md
@@ -198,22 +198,40 @@ POST /snippets
Parameters:
-| Attribute | Type | Required | Description |
-|:--------------|:-------|:---------|:---------------------------------------------------|
-| `title` | string | yes | Title of a snippet. |
-| `file_name` | string | yes | Name of a snippet file. |
-| `content` | string | yes | Content of a snippet. |
-| `description` | string | no | Description of a snippet. |
-| `visibility` | string | no | Snippet's [visibility](#snippet-visibility-level). |
+| Attribute | Type | Required | Description |
+|:------------------|:----------------|:---------|:--------------------------------------------------------|
+| `title` | string | yes | Title of a snippet |
+| `file_name` | string | no | Deprecated: Use `files` instead. Name of a snippet file |
+| `content` | string | no | Deprecated: Use `files` instead. Content of a snippet |
+| `description` | string | no | Description of a snippet |
+| `visibility` | string | no | Snippet's [visibility](#snippet-visibility-level) |
+| `files` | array of hashes | no | An array of snippet files |
+| `files:file_path` | string | yes | File path of the snippet file |
+| `files:content` | string | yes | Content of the snippet file |
Example request:
```shell
-curl --request POST \
- --data '{"title": "This is a snippet", "content": "Hello world", "description": "Hello World snippet", "file_name": "test.txt", "visibility": "internal" }' \
+curl --request POST "https://gitlab.example.com/api/v4/snippets" \
--header 'Content-Type: application/json' \
--header "PRIVATE-TOKEN: <your_access_token>" \
- "https://gitlab.example.com/api/v4/snippets"
+ -d @snippet.json
+```
+
+`snippet.json` used in the above example request:
+
+```json
+{
+ "title": "This is a snippet",
+ "description": "Hello World snippet",
+ "visibility": "internal",
+ "files": [
+ {
+ "content": "Hello world",
+ "file_path": "test.txt"
+ }
+ ]
+}
```
Example response:
@@ -222,7 +240,6 @@ Example response:
{
"id": 1,
"title": "This is a snippet",
- "file_name": "test.txt",
"description": "Hello World snippet",
"visibility": "internal",
"author": {
@@ -238,7 +255,16 @@ Example response:
"created_at": "2012-06-28T10:52:04Z",
"project_id": null,
"web_url": "http://example.com/snippets/1",
- "raw_url": "http://example.com/snippets/1/raw"
+ "raw_url": "http://example.com/snippets/1/raw",
+ "ssh_url_to_repo": "ssh://git@gitlab.example.com:snippets/1.git",
+ "http_url_to_repo": "https://gitlab.example.com/snippets/1.git",
+ "file_name": "test.txt",
+ "files": [
+ {
+ "path": "text.txt",
+ "raw_url": "https://gitlab.example.com/-/snippets/1/raw/master/renamed.md"
+ }
+ ]
}
```
@@ -255,23 +281,44 @@ PUT /snippets/:id
Parameters:
-| Attribute | Type | Required | Description |
-|:--------------|:--------|:---------|:---------------------------------------------------|
-| `id` | integer | yes | ID of snippet to update. |
-| `title` | string | no | Title of a snippet. |
-| `file_name` | string | no | Name of a snippet file. |
-| `description` | string | no | Description of a snippet. |
-| `content` | string | no | Content of a snippet. |
-| `visibility` | string | no | Snippet's [visibility](#snippet-visibility-level). |
+| Attribute | Type | Required | Description |
+|:----------------------|:----------------|:---------|:------------------------------------------------------------------------------------|
+| `id` | integer | yes | ID of snippet to update |
+| `title` | string | no | Title of a snippet |
+| `file_name` | string | no | Deprecated: Use `files` instead. Name of a snippet file |
+| `content` | string | no | Deprecated: Use `files` instead. Content of a snippet |
+| `description` | string | no | Description of a snippet |
+| `visibility` | string | no | Snippet's [visibility](#snippet-visibility-level) |
+| `files` | array of hashes | no | An array of snippet files |
+| `files:action` | string | yes | Type of action to perform on the file, one of: 'create', 'update', 'delete', 'move' |
+| `files:file_path` | string | no | File path of the snippet file |
+| `files:previous_path` | string | no | Previous path of the snippet file |
+| `files:content` | string | no | Content of the snippet file |
+
+Updates to snippets with multiple files *must* use the `files` attribute.
Example request:
```shell
-curl --request PUT \
- --data '{"title": "foo", "content": "bar"}' \
+curl --request PUT "https://gitlab.example.com/api/v4/snippets/1" \
--header 'Content-Type: application/json' \
--header "PRIVATE-TOKEN: <your_access_token>" \
- "https://gitlab.example.com/api/v4/snippets/1"
+ -d @snippet.json
+```
+
+`snippet.json` used in the above example request:
+
+```json
+{
+ "title": "foo",
+ "files": [
+ {
+ "action": "move",
+ "previous_path": "test.txt",
+ "file_path": "renamed.md"
+ }
+ ]
+}
```
Example response:
@@ -280,7 +327,6 @@ Example response:
{
"id": 1,
"title": "test",
- "file_name": "add.rb",
"description": "description of snippet",
"visibility": "internal",
"author": {
@@ -296,7 +342,16 @@ Example response:
"created_at": "2012-06-28T10:52:04Z",
"project_id": null,
"web_url": "http://example.com/snippets/1",
- "raw_url": "http://example.com/snippets/1/raw"
+ "raw_url": "http://example.com/snippets/1/raw",
+ "ssh_url_to_repo": "ssh://git@gitlab.example.com:snippets/1.git",
+ "http_url_to_repo": "https://gitlab.example.com/snippets/1.git",
+ "file_name": "renamed.md",
+ "files": [
+ {
+ "path": "renamed.md",
+ "raw_url": "https://gitlab.example.com/-/snippets/1/raw/master/renamed.md"
+ }
+ ]
}
```
diff --git a/doc/api/templates/gitlab_ci_ymls.md b/doc/api/templates/gitlab_ci_ymls.md
index dfe22fc453e..45bc0f55095 100644
--- a/doc/api/templates/gitlab_ci_ymls.md
+++ b/doc/api/templates/gitlab_ci_ymls.md
@@ -135,7 +135,7 @@ Example response:
```json
{
"name": "Ruby",
- "content": "# This file is a template, and might need editing before it works on your project.\n# Official language image. Look for the different tagged releases at:\n# https://hub.docker.com/r/library/ruby/tags/\nimage: \"ruby:2.5\"\n\n# Pick zero or more services to be used on all builds.\n# Only needed when using a docker container to run your tests in.\n# Check out: http://docs.gitlab.com/ce/ci/docker/using_docker_images.html#what-is-a-service\nservices:\n - mysql:latest\n - redis:latest\n - postgres:latest\n\nvariables:\n POSTGRES_DB: database_name\n\n# Cache gems in between builds\ncache:\n paths:\n - vendor/ruby\n\n# This is a basic example for a gem or script which doesn't use\n# services such as redis or postgres\nbefore_script:\n - ruby -v # Print out ruby version for debugging\n # Uncomment next line if your rails app needs a JS runtime:\n # - apt-get update -q && apt-get install nodejs -yqq\n - bundle install -j $(nproc) --path vendor # Install dependencies into ./vendor/ruby\n\n# Optional - Delete if not using `rubocop`\nrubocop:\n script:\n - rubocop\n\nrspec:\n script:\n - rspec spec\n\nrails:\n variables:\n DATABASE_URL: \"postgresql://postgres:postgres@postgres:5432/$POSTGRES_DB\"\n script:\n - rails db:migrate\n - rails db:seed\n - rails test\n\n# This deploy job uses a simple deploy flow to Heroku, other providers, e.g. AWS Elastic Beanstalk\n# are supported too: https://github.com/travis-ci/dpl\ndeploy:\n type: deploy\n environment: production\n script:\n - gem install dpl\n - dpl --provider=heroku --app=$HEROKU_APP_NAME --api-key=$HEROKU_PRODUCTION_KEY\n"
+ "content": "# This file is a template, and might need editing before it works on your project.\n# Official language image. Look for the different tagged releases at:\n# https://hub.docker.com/r/library/ruby/tags/\nimage: \"ruby:2.5\"\n\n# Pick zero or more services to be used on all builds.\n# Only needed when using a docker container to run your tests in.\n# Check out: http://docs.gitlab.com/ee/ci/docker/using_docker_images.html#what-is-a-service\nservices:\n - mysql:latest\n - redis:latest\n - postgres:latest\n\nvariables:\n POSTGRES_DB: database_name\n\n# Cache gems in between builds\ncache:\n paths:\n - vendor/ruby\n\n# This is a basic example for a gem or script which doesn't use\n# services such as redis or postgres\nbefore_script:\n - ruby -v # Print out ruby version for debugging\n # Uncomment next line if your rails app needs a JS runtime:\n # - apt-get update -q && apt-get install nodejs -yqq\n - bundle install -j $(nproc) --path vendor # Install dependencies into ./vendor/ruby\n\n# Optional - Delete if not using `rubocop`\nrubocop:\n script:\n - rubocop\n\nrspec:\n script:\n - rspec spec\n\nrails:\n variables:\n DATABASE_URL: \"postgresql://postgres:postgres@postgres:5432/$POSTGRES_DB\"\n script:\n - rails db:migrate\n - rails db:seed\n - rails test\n\n# This deploy job uses a simple deploy flow to Heroku, other providers, e.g. AWS Elastic Beanstalk\n# are supported too: https://github.com/travis-ci/dpl\ndeploy:\n type: deploy\n environment: production\n script:\n - gem install dpl\n - dpl --provider=heroku --app=$HEROKU_APP_NAME --api-key=$HEROKU_PRODUCTION_KEY\n"
}
```
diff --git a/doc/api/todos.md b/doc/api/todos.md
index ebe10ecbd49..ab36021d694 100644
--- a/doc/api/todos.md
+++ b/doc/api/todos.md
@@ -4,13 +4,13 @@ group: Project Management
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/#designated-technical-writers
---
-# To-dos API
+# To dos API
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/3188) in GitLab 8.10.
-## Get a list of to-dos
+## Get a list of to dos
-Returns a list of to-dos. When no filter is applied, it returns all pending to-dos
+Returns a list of to dos. When no filter is applied, it returns all pending to dos
for the current user. Different filters allow the user to precise the request.
```plaintext
@@ -25,8 +25,8 @@ Parameters:
| `author_id` | integer | no | The ID of an author |
| `project_id` | integer | no | The ID of a project |
| `group_id` | integer | no | The ID of a group |
-| `state` | string | no | The state of the to-do. Can be either `pending` or `done` |
-| `type` | string | no | The type of a to-do. Can be either `Issue`, `MergeRequest`, `DesignManagement::Design` or `AlertManagement::Alert` |
+| `state` | string | no | The state of the to do. Can be either `pending` or `done` |
+| `type` | string | no | The type of a to do. Can be either `Issue`, `MergeRequest`, `DesignManagement::Design` or `AlertManagement::Alert` |
```shell
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/todos"
@@ -187,10 +187,10 @@ Example Response:
]
```
-## Mark a to-do as done
+## Mark a to do as done
-Marks a single pending to-do given by its ID for the current user as done. The
-to-do marked as done is returned in the response.
+Marks a single pending to do given by its ID for the current user as done. The
+to do marked as done is returned in the response.
```plaintext
POST /todos/:id/mark_as_done
@@ -200,7 +200,7 @@ Parameters:
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
-| `id` | integer | yes | The ID of a to-do |
+| `id` | integer | yes | The ID of a to do |
```shell
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/todos/130/mark_as_done"
@@ -285,9 +285,9 @@ Example Response:
}
```
-## Mark all to-dos as done
+## Mark all to dos as done
-Marks all pending to-dos for the current user as done. It returns the HTTP status code `204` with an empty response.
+Marks all pending to dos for the current user as done. It returns the HTTP status code `204` with an empty response.
```plaintext
POST /todos/mark_as_done
diff --git a/doc/api/users.md b/doc/api/users.md
index 634e0bd0842..beaea689fb7 100644
--- a/doc/api/users.md
+++ b/doc/api/users.md
@@ -950,7 +950,7 @@ Returns `204 No Content` on success, or `404 Not found` if the key cannot be fou
## List all GPG keys for given user
-Get a list of a specified user's GPG keys. Available only for admins.
+Get a list of a specified user's GPG keys. This endpoint can be accessed without authentication.
```plaintext
GET /users/:id/gpg_keys
@@ -980,7 +980,8 @@ Example response:
## Get a specific GPG key for a given user
-Get a specific GPG key for a given user. Available only for admins.
+Get a specific GPG key for a given user. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/43693)
+in GitLab 13.5, this endpoint can be accessed without admin authentication.
```plaintext
GET /users/:id/gpg_keys/:key_id
@@ -1209,7 +1210,9 @@ Returns:
- `201 OK` on success.
- `404 User Not Found` if user cannot be found.
-- `403 Forbidden` when trying to block an already blocked user by LDAP synchronization.
+- `403 Forbidden` when trying to block:
+ - A user that is blocked through LDAP.
+ - An internal user.
## Unblock user
@@ -1246,7 +1249,8 @@ Returns:
- `404 User Not Found` if user cannot be found.
- `403 Forbidden` when trying to deactivate a user:
- Blocked by admin or by LDAP synchronization.
- - That has any activity in past 180 days. These users cannot be deactivated.
+ - That has any activity in past 90 days. These users cannot be deactivated.
+ - That is internal.
## Activate user
diff --git a/doc/api/v3_to_v4.md b/doc/api/v3_to_v4.md
index 4139438bea0..c351c14e24c 100644
--- a/doc/api/v3_to_v4.md
+++ b/doc/api/v3_to_v4.md
@@ -1,6 +1,6 @@
# API V3 to API V4
-Since GitLab 9.0, API V4 is the preferred version to be used.
+In GitLab 9.0 and later, API V4 is the preferred version to be used.
API V3 was unsupported from GitLab 9.5, released on August
22, 2017. API v3 was removed in [GitLab 11.0](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/36819).
diff --git a/doc/api/vulnerabilities.md b/doc/api/vulnerabilities.md
index 73c765e2ccc..f89f2bda2eb 100644
--- a/doc/api/vulnerabilities.md
+++ b/doc/api/vulnerabilities.md
@@ -220,3 +220,53 @@ Example response:
"closed_at": null
}
```
+
+## Revert vulnerability to detected state
+
+Reverts a given vulnerability to detected state. Returns status code `304` if the vulnerability is already in detected state.
+
+If an authenticated user does not have permission to
+[revert vulnerability to detected state](../user/permissions.md#project-members-permissions),
+this request will result in a `403` status code.
+
+```plaintext
+POST /vulnerabilities/:id/revert
+```
+
+| Attribute | Type | Required | Description |
+| --------- | ---- | -------- | ----------- |
+| `id` | integer or string | yes | The ID of a vulnerability to revert to detected state |
+
+```shell
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/vulnerabilities/5/dismiss"
+```
+
+Example response:
+
+```json
+{
+ "id": 2,
+ "title": "Predictable pseudorandom number generator",
+ "description": null,
+ "state": "detected",
+ "severity": "medium",
+ "confidence": "medium",
+ "report_type": "sast",
+ "project": {
+ "id": 32,
+ "name": "security-reports",
+ "full_path": "/gitlab-examples/security/security-reports",
+ "full_name": "gitlab-examples / security / security-reports"
+ },
+ "author_id": 1,
+ "updated_by_id": null,
+ "last_edited_by_id": null,
+ "closed_by_id": null,
+ "start_date": null,
+ "due_date": null,
+ "created_at": "2019-10-13T15:08:40.219Z",
+ "updated_at": "2019-10-13T15:09:40.382Z",
+ "last_edited_at": null,
+ "closed_at": null
+}
+```
diff --git a/doc/api/vulnerability_exports.md b/doc/api/vulnerability_exports.md
index d19d41b647e..0ee8a18a46a 100644
--- a/doc/api/vulnerability_exports.md
+++ b/doc/api/vulnerability_exports.md
@@ -198,18 +198,18 @@ The response will be `404 Not Found` if the vulnerability export is not finished
Example response:
```csv
-Group Name,Project Name,Scanner Type,Scanner Name,Status,Vulnerability,Details,Additional Info,Severity,CVE
-Gitlab.org,Defend,container_scanning,Clair,confirmed,CVE-2017-16997 in glibc,,CVE-2017-16997 in glibc,critical,CVE-2017-16997
+Group Name,Project Name,Scanner Type,Scanner Name,Status,Vulnerability,Details,Additional Info,Severity,CVE,CWE,Other Identifiers
+Gitlab.org,Defend,container_scanning,Clair,detected,CVE-2017-16997 in glibc,,CVE-2017-16997 in glibc,critical,CVE-2017-16997
Gitlab.org,Defend,container_scanning,Clair,detected,CVE-2017-18269 in glibc,,CVE-2017-18269 in glibc,critical,CVE-2017-18269
Gitlab.org,Defend,container_scanning,Clair,detected,CVE-2018-1000001 in glibc,,CVE-2018-1000001 in glibc,high,CVE-2018-1000001
Gitlab.org,Defend,container_scanning,Clair,detected,CVE-2016-10228 in glibc,,CVE-2016-10228 in glibc,medium,CVE-2016-10228
-Gitlab.org,Defend,container_scanning,Clair,confirmed,CVE-2010-4052 in glibc,,CVE-2010-4052 in glibc,low,CVE-2010-4052
+Gitlab.org,Defend,container_scanning,Clair,detected,CVE-2010-4052 in glibc,,CVE-2010-4052 in glibc,low,CVE-2010-4052
Gitlab.org,Defend,container_scanning,Clair,detected,CVE-2018-18520 in elfutils,,CVE-2018-18520 in elfutils,low,CVE-2018-18520
-Gitlab.org,Defend,container_scanning,Clair,detected,CVE-2018-16869 in nettle,,CVE-2018-16869 in nettle,unknown,CVE-2018-16869
-Gitlab.org,Defend,dependency_scanning,Gemnasium,detected,Regular Expression Denial of Service in debug,,Regular Expression Denial of Service in debug,unknown,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,confirmed,ECB mode is insecure 2,,ECB mode is insecure,medium,ea0f905fc76f2739d5f10a1fd1e37a10:ECB_MODE:src/main/java/com/gitlab/security_products/tests/App.java:29
-Gitlab.org,Defend,```
+Gitlab.org,Defend,container_scanning,Clair,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"""
+```
diff --git a/doc/api/wikis.md b/doc/api/wikis.md
index 7d16a5a38ee..a8c002d4fac 100644
--- a/doc/api/wikis.md
+++ b/doc/api/wikis.md
@@ -5,7 +5,7 @@ info: "To determine the technical writer assigned to the Stage/Group associated
type: reference, api
---
-# Wikis API
+# Project wikis API
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/13372) in GitLab 10.0.
diff --git a/doc/architecture/blueprints/cloud_native_build_logs/index.md b/doc/architecture/blueprints/cloud_native_build_logs/index.md
new file mode 100644
index 00000000000..25abfe36e88
--- /dev/null
+++ b/doc/architecture/blueprints/cloud_native_build_logs/index.md
@@ -0,0 +1,141 @@
+---
+comments: false
+description: 'Next iteration of build logs architecture at GitLab'
+---
+
+# Cloud Native Build Logs
+
+Cloud native and the adoption of Kubernetes has been recognised by GitLab to be
+one of the top two biggest tailwinds that are helping us grow faster as a
+company behind the project.
+
+This effort is described in a more details [in the infrastructure team
+handbook](https://about.gitlab.com/handbook/engineering/infrastructure/production/kubernetes/gitlab-com/).
+
+## Traditional build logs
+
+Traditional job logs depend a lot on availability of a local shared storage.
+
+Every time a GitLab Runner sends a new partial build output, we write this
+output to a file on a disk. This is simple, but this mechanism depends on
+shared local storage - the same file needs to be available on every GitLab web
+node machine, because GitLab Runner might connect to a different one every time
+it performs an API request. Sidekiq also needs access to the file because when
+a job is complete, a trace file contents will be sent to the object store.
+
+## New architecture
+
+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
+I/O mechanism - we store data in Redis in chunks, and migrate them to an object
+store once we reach a desired chunk size.
+
+Simplified sequence diagram is available below.
+
+```mermaid
+sequenceDiagram
+ autonumber
+ participant U as User
+ participant R as Runner
+ participant G as GitLab (rails)
+ participant I as Redis
+ participant D as Database
+ participant O as Object store
+
+ loop incremental trace update sent by a runner
+ Note right of R: Runner appends a build trace
+ R->>+G: PATCH trace [build.id, offset, data]
+ G->>+D: find or create chunk [chunk.index]
+ D-->>-G: chunk [id, index]
+ G->>I: append chunk data [chunk.index, data]
+ G-->>-R: 200 OK
+ end
+
+ Note right of R: User retrieves a trace
+ U->>+G: GET build trace
+ loop every trace chunk
+ G->>+D: find chunk [index]
+ D-->>-G: chunk [id]
+ G->>+I: read chunk data [chunk.index]
+ I-->>-G: chunk data [data, size]
+ end
+ G-->>-U: build trace
+
+ Note right of R: Trace chunk is full
+ R->>+G: PATCH trace [build.id, offset, data]
+ G->>+D: find or create chunk [chunk.index]
+ D-->>-G: chunk [id, index]
+ G->>I: append chunk data [chunk.index, data]
+ G->>G: chunk full [index]
+ G-->>-R: 200 OK
+ G->>+I: read chunk data [chunk.index]
+ I-->>-G: chunk data [data, size]
+ G->>O: send chunk data [data, size]
+ G->>+D: update data store type [chunk.id]
+ G->>+I: delete chunk data [chunk.index]
+```
+
+## NFS coupling
+
+In 2017, we experienced serious problems of scaling our NFS infrastructure. We
+even tried to replace NFS with
+[CephFS](https://docs.ceph.com/docs/master/cephfs/) - unsuccessfully.
+
+Since that time it has become apparent that the cost of operations and
+maintenance of a NFS cluster is significant and that if we ever decide to
+migrate to Kubernetes [we need to decouple GitLab from a shared local storage
+and
+NFS](https://gitlab.com/gitlab-org/gitlab-pages/-/issues/426#note_375646396).
+
+1. NFS might be a single point of failure
+1. NFS can only be reliably scaled vertically
+1. Moving to Kubernetes means increasing the number of mount points by an order
+ of magnitude
+1. NFS depends on extremely reliable network which can be difficult to provide
+ in Kubernetes environment
+1. Storing customer data on NFS involves additional security risks
+
+Moving GitLab to Kubernetes without NFS decoupling would result in an explosion
+of complexity, maintenance cost and enormous, negative impact on availability.
+
+## Iterations
+
+1. ✓ Implement the new architecture in way that it does not depend on shared local storage
+1. ✓ Evaluate performance and edge-cases, iterate to improve the new architecture
+1. ✓ Design cloud native build logs correctness verification mechanisms
+1. ✓ Build observability mechanisms around performance and correctness
+1. Rollout the feature into production environment incrementally
+
+The work needed to make the new architecture production ready and enabled on
+GitLab.com is being tracked in [Cloud Native Build Logs on
+GitLab.com](https://gitlab.com/groups/gitlab-org/-/epics/4275) epic.
+
+Enabling this feature on GitLab.com is a subtask of [making the new
+architecture generally
+available](https://gitlab.com/groups/gitlab-org/-/epics/3791) for everyone.
+
+## 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 | Jason Yavorska |
+| 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
new file mode 100644
index 00000000000..37e69d46ae1
--- /dev/null
+++ b/doc/architecture/blueprints/cloud_native_gitlab_pages/index.md
@@ -0,0 +1,135 @@
+---
+comments: false
+description: 'Making GitLab Pages a Cloud Native application - architecture blueprint.'
+---
+
+# GitLab Pages New Architecture
+
+GitLab Pages is an important component of the GitLab product. It is mostly
+being used to serve static content, and has a limited set of well defined
+responsibilities. That being said, unfortunately it has become a blocker for
+GitLab.com Kubernetes migration.
+
+Cloud Native and the adoption of Kubernetes has been recognised by GitLab to be
+one of the top two biggest tailwinds that are helping us grow faster as a
+company behind the project.
+
+This effort is described in more detail [in the infrastructure team handbook
+page](https://about.gitlab.com/handbook/engineering/infrastructure/production/kubernetes/gitlab-com/).
+
+GitLab Pages is tightly coupled with NFS and in order to unblock Kubernetes
+migration a significant change to GitLab Pages' architecture is required. This
+is an ongoing work that we have started more than a year ago. This blueprint
+might be useful to understand why it is important, and what is the roadmap.
+
+## How GitLab Pages Works
+
+GitLab Pages is a daemon designed to serve static content, written in
+[Go](https://golang.org/).
+
+Initially, GitLab Pages has been designed to store static content on a local
+shared block storage (NFS) in a hierarchical group > project directory
+structure. Each directory, representing a project, was supposed to contain a
+configuration file and static content that GitLab Pages daemon was supposed to
+read and serve.
+
+```mermaid
+graph LR
+ A(GitLab Rails) -- Writes new pages deployment --> B[(NFS)]
+ C(GitLab Pages) -. Reads static content .-> B
+```
+
+This initial design has become outdated because of a few reasons - NFS coupling
+being one of them - and we decided to replace it with more "decoupled
+service"-like architecture. The new architecture, that we are working on, is
+described in this blueprint.
+
+## NFS coupling
+
+In 2017, we experienced serious problems of scaling our NFS infrastructure. We
+even tried to replace NFS with
+[CephFS](https://docs.ceph.com/docs/master/cephfs/) - unsuccessfully.
+
+Since that time it has become apparent that the cost of operations and
+maintenance of a NFS cluster is significant and that if we ever decide to
+migrate to Kubernetes [we need to decouple GitLab from a shared local storage
+and
+NFS](https://gitlab.com/gitlab-org/gitlab-pages/-/issues/426#note_375646396).
+
+1. NFS might be a single point of failure
+1. NFS can only be reliably scaled vertically
+1. Moving to Kubernetes means increasing the number of mount points by an order
+ of magnitude
+1. NFS depends on extremely reliable network which can be difficult to provide
+ in Kubernetes environment
+1. Storing customer data on NFS involves additional security risks
+
+Moving GitLab to Kubernetes without NFS decoupling would result in an explosion
+of complexity, maintenance cost and enormous, negative impact on availability.
+
+## New GitLab Pages Architecture
+
+- GitLab Pages is going to source domains' configuration from GitLab's internal
+ API, instead of reading `config.json` files from a local shared storage.
+- GitLab Pages is going to serve static content from Object Storage.
+
+```mermaid
+graph TD
+ A(User) -- Pushes pages deployment --> B{GitLab}
+ C((GitLab Pages)) -. Reads configuration from API .-> B
+ C -. Reads static content .-> D[(Object Storage)]
+ C -- Serves static content --> E(Visitors)
+```
+
+This new architecture has been briefly described in [the blog
+post](https://about.gitlab.com/blog/2020/08/03/how-gitlab-pages-uses-the-gitlab-api-to-serve-content/)
+too.
+
+## Iterations
+
+1. ✓ Redesign GitLab Pages configuration source to use GitLab's API
+1. ✓ Evaluate performance and build reliable caching mechanisms
+1. ✓ Incrementally rollout the new source on GitLab.com
+1. ✓ Make GitLab Pages API domains config source enabled by default
+1. Enable experimentation with different servings through feature flags
+1. Triangulate object store serving design through meaningful experiments
+1. Design pages migration mechanisms that can work incrementally
+1. Gradually migrate towards object storage serving on GitLab.com
+
+[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 | Jackie Porter |
+| Leadership | Daniel Croft |
+| Engineering | Kamil Trzciński |
+
+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/feature_flags_development/index.md b/doc/architecture/blueprints/feature_flags_development/index.md
new file mode 100644
index 00000000000..0aeb2b51b39
--- /dev/null
+++ b/doc/architecture/blueprints/feature_flags_development/index.md
@@ -0,0 +1,140 @@
+---
+comments: false
+description: 'Internal usage of Feature Flags for GitLab development'
+---
+
+# Usage of Feature Flags for GitLab development
+
+Usage of feature flags become crucial for the development of GitLab. The
+feature flags are a convenient way to ship changes early, and safely rollout
+them to wide audience ensuring that feature is stable and performant.
+
+Since the presence of feature is controlled with a dedicated condition, a
+developer can decide for a best time for testing the feature, ensuring that
+feature is not enable prematurely.
+
+## Challenges
+
+The extensive usage of feature flags poses a few challenges
+
+- Each feature flag that we add to codebase is a ~"technical debt" as it adds a
+ matrix of configurations.
+- Testing each combination of feature flags is close to impossible, so we
+ instead try to optimise our testing of feature flags to the most common
+ scenarios.
+- There's a growing challenge of maintaining a growing number of feature flags.
+ We sometimes forget how our feature flags are configured or why we haven't
+ yet removed the feature flag.
+- The usage of feature flags can also be confusing to people outside of
+ development that might not fully understand dependence of ~feature or ~bug
+ fix on feature flag and how this feature flag is configured. Or if the feature
+ should be announced as part of release post.
+- Maintaining feature flags poses additional challenge of having to manage
+ different configurations across different environments/target. We have
+ different configuration of feature flags for testing, for development, for
+ staging, for production and what is being shipped to our customers as part of
+ on-premise offering.
+
+## Goals
+
+The biggest challenge today with our feature flags usage is their implicit
+nature. Feature flags are part of the codebase, making them hard to understand
+outside of development function.
+
+We should aim to make our feature flag based development to be accessible to
+any interested party.
+
+- developer / engineer
+ - can easily add a new feature flag, and configure it's state
+ - can quickly find who to reach if touches another feature flag
+ - can quickly find stale feature flags
+- engineering manager
+ - can understand what feature flags her/his group manages
+- engineering manager and director
+ - can understand how much ~"technical debt" is inflicted due to amount of feature flags that we have to manage
+ - can understand how many feature flags are added and removed in each release
+- product manager and documentation writer
+ - can understand what features are gated by what feature flags
+ - can understand if feature and thus feature flag is generally available on GitLab.com
+ - can understand if feature and thus feature flag is enabled by default for on-premise installations
+- delivery engineer
+ - can understand what feature flags are introduced and changed between subsequent deployments
+- support and reliability engineer
+ - can understand how feature flags changed between releases: what feature flags become enabled, what removed
+ - can quickly find relevant information about feature flag to know individuals which might help with an ongoing support request or incident
+
+## Proposal
+
+To help with above goals we should aim to make our feature flags usage explicit
+and understood by all involved parties.
+
+Introduce a YAML-described `feature-flags/<name-of-feature.yml>` that would
+allow us to have:
+
+1. A central place where all feature flags are documented,
+1. A description of why the given feature flag was introduced,
+1. A what relevant issue and merge request it was introduced by,
+1. Build automated documentation with all feature flags in the codebase,
+1. Track how many feature flags are per given group
+1. Track how many feature flags are added and removed between releases
+1. Make this information easily accessible for all
+1. Allow our customers to easily discover how to enable features and quickly
+ find out information what did change between different releases
+
+### The `YAML`
+
+```yaml
+---
+name: ci_disallow_to_create_merge_request_pipelines_in_target_project
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/40724
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/235119
+group: group::progressive delivery
+type: development
+default_enabled: false
+```
+
+## Reasons
+
+These are reason why these changes are needed:
+
+- we have around 500 different feature flags today
+- we have hard time tracking their usage
+- we have ambiguous usage of feature flag with different `default_enabled:` and
+ different `actors` used
+- we lack a clear indication who owns what feature flag and where to find
+ relevant informations
+- we do not emphasise the desire to create feature flag rollout issue to
+ indicate that feature flag is in fact a ~"technical debt"
+- we don't know exactly what feature flags we have in our codebase
+- we don't know exactly how our feature flags are configured for different
+ environments: what is being used for `test`, what we ship for `on-premise`,
+ what is our settings for `staging`, `qa` and `production`
+
+## Iterations
+
+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/index.md b/doc/architecture/index.md
new file mode 100644
index 00000000000..0a2ade6b7b0
--- /dev/null
+++ b/doc/architecture/index.md
@@ -0,0 +1,9 @@
+---
+comments: false
+description: 'Architecture Practice at GitLab'
+---
+
+# Architecture at GitLab
+
+- [Architecture at GitLab](https://about.gitlab.com/handbook/engineering/architecture/)
+- [Architecture Workflow](https://about.gitlab.com/handbook/engineering/architecture/workflow/)
diff --git a/doc/articles/artifactory_and_gitlab/index.md b/doc/articles/artifactory_and_gitlab/index.md
deleted file mode 100644
index ed9fd135e7c..00000000000
--- a/doc/articles/artifactory_and_gitlab/index.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../../ci/examples/artifactory_and_gitlab/index.md'
----
-
-This document was moved to [another location](../../ci/examples/artifactory_and_gitlab/index.md)
diff --git a/doc/articles/how_to_configure_ldap_gitlab_ce/index.md b/doc/articles/how_to_configure_ldap_gitlab_ce/index.md
deleted file mode 100644
index 2fbeb6f2506..00000000000
--- a/doc/articles/how_to_configure_ldap_gitlab_ce/index.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../../administration/auth/ldap/index.md'
----
-
-This document was moved to [another location](../../administration/auth/ldap/index.md).
diff --git a/doc/articles/how_to_configure_ldap_gitlab_ee/index.md b/doc/articles/how_to_configure_ldap_gitlab_ee/index.md
deleted file mode 100644
index 2fbeb6f2506..00000000000
--- a/doc/articles/how_to_configure_ldap_gitlab_ee/index.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../../administration/auth/ldap/index.md'
----
-
-This document was moved to [another location](../../administration/auth/ldap/index.md).
diff --git a/doc/articles/how_to_install_git/index.md b/doc/articles/how_to_install_git/index.md
deleted file mode 100644
index 62598101895..00000000000
--- a/doc/articles/how_to_install_git/index.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../../topics/git/how_to_install_git/index.md'
----
-
-This document was moved to [another location](../../topics/git/how_to_install_git/index.md).
diff --git a/doc/articles/index.md b/doc/articles/index.md
deleted file mode 100644
index 4b965b0256f..00000000000
--- a/doc/articles/index.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../topics/index.md'
----
-
-This document was moved to [another location](../topics/index.md)
diff --git a/doc/articles/laravel_with_gitlab_and_envoy/index.md b/doc/articles/laravel_with_gitlab_and_envoy/index.md
deleted file mode 100644
index fa4f6243410..00000000000
--- a/doc/articles/laravel_with_gitlab_and_envoy/index.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../../ci/examples/laravel_with_gitlab_and_envoy/index.md'
----
-
-This document was moved to [another location](../../ci/examples/laravel_with_gitlab_and_envoy/index.md).
diff --git a/doc/articles/numerous_undo_possibilities_in_git/index.md b/doc/articles/numerous_undo_possibilities_in_git/index.md
deleted file mode 100644
index 83aac82db4e..00000000000
--- a/doc/articles/numerous_undo_possibilities_in_git/index.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../../topics/git/numerous_undo_possibilities_in_git/index.md'
----
-
-This document was moved to [another location](../../topics/git/numerous_undo_possibilities_in_git/index.md).
diff --git a/doc/articles/openshift_and_gitlab/index.md b/doc/articles/openshift_and_gitlab/index.md
deleted file mode 100644
index 822d012aa3d..00000000000
--- a/doc/articles/openshift_and_gitlab/index.md
+++ /dev/null
@@ -1,3 +0,0 @@
----
-redirect_to: '../../install/openshift_and_gitlab/index.html'
----
diff --git a/doc/articles/runner_autoscale_aws/index.md b/doc/articles/runner_autoscale_aws/index.md
deleted file mode 100644
index fb769731256..00000000000
--- a/doc/articles/runner_autoscale_aws/index.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: 'https://docs.gitlab.com/runner/configuration/runner_autoscale_aws/index.html'
----
-
-This document was moved to [another location](https://docs.gitlab.com/runner/configuration/runner_autoscale_aws/index.html).
diff --git a/doc/ci/README.md b/doc/ci/README.md
index 9d3f7f2a8f2..dca6d8baa79 100644
--- a/doc/ci/README.md
+++ b/doc/ci/README.md
@@ -16,7 +16,7 @@ through the [continuous methodologies](introduction/index.md#introduction-to-cic
- Continuous Delivery (CD)
- Continuous Deployment (CD)
-NOTE: **Note:**
+TIP: **Tip:**
Out-of-the-box management systems can decrease hours spent on maintaining toolchains by 10% or more.
Watch our ["Mastering continuous software development"](https://about.gitlab.com/webcast/mastering-ci-cd/)
webcast to learn about continuous methods and how GitLab’s built-in CI can help you simplify and scale software development.
@@ -24,7 +24,7 @@ webcast to learn about continuous methods and how GitLab’s built-in CI can hel
## Overview
Continuous Integration works by pushing small code chunks to your
-application's code base hosted in a Git repository, and, to every
+application's codebase hosted in a Git repository, and to every
push, run a pipeline of scripts to build, test, and validate the
code changes before merging them into the main branch.
@@ -73,13 +73,14 @@ to your needs:
![Use a `.gitlab-ci.yml` template](img/add_file_template_11_10.png)
+While building your `.gitlab-ci.yml`, you can use the [CI/CD configuration visualization](yaml/visualization.md) to facilate your writing experience.
+
For a broader overview, see the [CI/CD getting started](quick_start/README.md) guide.
Once you're familiar with how GitLab CI/CD works, see the
[`.gitlab-ci.yml` full reference](yaml/README.md)
for all the attributes you can set and use.
-NOTE: **Note:**
GitLab CI/CD and [shared runners](runners/README.md#shared-runners) are enabled on GitLab.com and available for all users, limited only by the [pipeline quota](../user/gitlab_com/index.md#shared-runners).
## Concepts
@@ -94,7 +95,7 @@ GitLab CI/CD uses a number of concepts to describe and run your build and deploy
| [Job artifacts](pipelines/job_artifacts.md) | Output, use, and reuse job artifacts. |
| [Cache dependencies](caching/index.md) | Cache your dependencies for a faster execution. |
| [GitLab Runner](https://docs.gitlab.com/runner/) | Configure your own runners to execute your scripts. |
-| [Pipeline efficiency](pipelines/pipeline_efficiency.md) | Configure your pipelines to run quickly and effienctly. |
+| [Pipeline efficiency](pipelines/pipeline_efficiency.md) | Configure your pipelines to run quickly and efficiently. |
## Configuration
diff --git a/doc/ci/caching/index.md b/doc/ci/caching/index.md
index 50f7d5252d8..df41f7da2d9 100644
--- a/doc/ci/caching/index.md
+++ b/doc/ci/caching/index.md
@@ -24,7 +24,6 @@ how it is defined in `.gitlab-ci.yml`.
## Cache vs artifacts
-NOTE: **Note:**
Be careful if you use cache and artifacts to store the same path in your jobs
as **caches are restored before artifacts** and the content could be overwritten.
@@ -73,7 +72,6 @@ Artifacts:
- Are always uploaded to GitLab (known as coordinator).
- Can have an expiration value for controlling disk usage (30 days by default).
-NOTE: **Note:**
Both artifacts and caches define their paths relative to the project directory, and
can't link to files outside it.
@@ -204,9 +202,7 @@ runs of jobs for things like dependencies and commonly used libraries
(Node.js packages, PHP packages, rubygems, Python libraries, etc.),
so they don't have to be re-fetched from the public internet.
-NOTE: **Note:**
-For more examples, check out our [GitLab CI/CD
-templates](https://gitlab.com/gitlab-org/gitlab/tree/master/lib/gitlab/ci/templates).
+For more examples, check out our [GitLab CI/CD templates](https://gitlab.com/gitlab-org/gitlab/tree/master/lib/gitlab/ci/templates).
### Caching Node.js dependencies
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 74c48f087b2..f8e2a2b7eb0 100644
--- a/doc/ci/ci_cd_for_external_repos/bitbucket_integration.md
+++ b/doc/ci/ci_cd_for_external_repos/bitbucket_integration.md
@@ -9,7 +9,7 @@ type: howto
GitLab CI/CD can be used with Bitbucket Cloud by:
-1. Creating a [CI/CD project](../../user/project/ci_cd_for_external_repo.md).
+1. Creating a [CI/CD project](index.md).
1. Connecting your Git repository via URL.
To use GitLab CI/CD with a Bitbucket Cloud repository:
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 661d935fc1d..7ee9f98bd39 100644
--- a/doc/ci/ci_cd_for_external_repos/github_integration.md
+++ b/doc/ci/ci_cd_for_external_repos/github_integration.md
@@ -21,7 +21,6 @@ cannot be used to authenticate with GitHub as an external CI/CD repository.
## Connect with Personal Access Token
-NOTE: **Note:**
Personal access tokens can only be used to connect GitHub.com
repositories to GitLab, and the GitHub user must have the [owner role](https://docs.github.com/en/github/getting-started-with-github/access-permissions-on-github).
@@ -53,7 +52,6 @@ GitLab will:
## Connect manually
-NOTE: **Note:**
To use **GitHub Enterprise** with **GitLab.com**, use this method.
To manually enable GitLab CI/CD for your repository:
diff --git a/doc/ci/ci_cd_for_external_repos/index.md b/doc/ci/ci_cd_for_external_repos/index.md
index 78988e8a057..c6590599849 100644
--- a/doc/ci/ci_cd_for_external_repos/index.md
+++ b/doc/ci/ci_cd_for_external_repos/index.md
@@ -74,7 +74,6 @@ If changes are pushed to the branch referenced by the Pull Request and the
Pull Request is still open, a pipeline for the external pull request is
created.
-NOTE: **Note:**
GitLab CI/CD will create 2 pipelines in this case. One for the
branch push and one for the external pull request.
diff --git a/doc/ci/cloud_deployment/index.md b/doc/ci/cloud_deployment/index.md
index 6fa0e6d9475..af7df0e1153 100644
--- a/doc/ci/cloud_deployment/index.md
+++ b/doc/ci/cloud_deployment/index.md
@@ -8,7 +8,10 @@ type: howto
# Cloud deployment
Interacting with a major cloud provider may have become a much needed task that's
-part of your delivery process. GitLab is making this process less painful by providing Docker images
+part of your delivery process. With GitLab you can
+[deploy your application anywhere](https://about.gitlab.com/stages-devops-lifecycle/deploy-targets/).
+
+For some specific deployment targets, GitLab makes this process less painful by providing Docker images
that come with the needed libraries and tools pre-installed.
By referencing them in your CI/CD pipeline, you'll be able to interact with your chosen
cloud provider more easily.
@@ -200,3 +203,81 @@ deploy:
script:
- aws ecs register-task-definition ...
```
+
+### Provision and deploy to your AWS Elastic Compute Cloud (EC2)
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/201742) in GitLab 13.5.
+
+You can use the `AWS/CF-Provision-and-Deploy-EC2` CI template to perform the
+following actions within the same pipeline:
+
+1. **Create stack**: Provision your own infrastructure by leveraging the [AWS CloudFormation](https://aws.amazon.com/cloudformation/) API.
+1. **Push to S3**: Push your previously-built artifact to an [AWS S3](https://aws.amazon.com/s3/) bucket.
+1. **Deploy to EC2**: Deploy this pushed content onto an [AWS EC2](https://aws.amazon.com/ec2/) instance.
+
+![CF-Provision-and-Deploy-EC2 diagram](../img/cf_ec2_diagram_v13_5.png)
+
+#### Run the `AWS/CF-Provision-and-Deploy-EC2.gitlab-ci.yml` template
+
+To run the `AWS/CF-Provision-and-Deploy-EC2.gitlab-ci.yml` template, you must
+pass three JSON input objects, based on existing templates:
+
+1. The AWS documentation provides templates for the _Create stack_ and _Deploy to EC2_ steps (links
+ below). We provide the template for the remaining step, _Push to S3_:
+
+ - [Template for the _Create stack_ step on AWS](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-anatomy.html).
+ - Template for the _Push to S3_ step. Note that `source` is where a preceding `build` job built
+ your application, exporting the build through [`artifacts:paths`](../yaml/README.md#artifactspaths):
+
+ ```json
+ {
+ "applicationName": "string",
+ "source": "string",
+ "s3Location": "s3://your/bucket/project_built_file...]"
+ }
+ ```
+
+ - [Template for the _Deploy to EC2_ step on AWS](https://docs.aws.amazon.com/codedeploy/latest/APIReference/API_CreateDeployment.html).
+
+1. Once you have completed these three templates based on your requirements, you
+ have two ways to pass in these JSON objects:
+
+ - They can be three actual files located in your project. You must specify their path relative to
+ your project root in your `.gitlab-ci.yml` file, using the following variables. For example, if
+ your files are in a `<project_root>/aws` folder:
+
+ ```yaml
+ variables:
+ CI_AWS_CF_CREATE_STACK_FILE: 'aws/cf_create_stack.json'
+ CI_AWS_S3_PUSH_FILE: 'aws/s3_push.json'
+ CI_AWS_EC2_DEPLOYMENT_FILE: 'aws/create_deployment.json'
+ ```
+
+ - Alternatively, you can provide these JSON objects as [file-typed environment variables](../variables/README.md#custom-environment-variables-of-type-file).
+ In your project, go to **Settings > CI / CD > Variables** and add
+ the three variables listed above as file-typed environment variables.
+ For each variable, set the value to its corresponding JSON object.
+
+1. Provide the name of the stack you're creating and/or targeting, as an environment variable:
+
+ ```yaml
+ variables:
+ CI_AWS_CF_STACK_NAME: 'YourStackName'
+ ```
+
+1. Add this CI template to your `.gitlab-ci.yml`:
+
+ ```yaml
+ include:
+ - template: AWS/CF-Provision-and-Deploy-EC2.gitlab-ci.yml
+ ```
+
+When running your project pipeline at this point:
+
+- Your AWS CloudFormation stack is created based on the content of your
+ `CI_AWS_CF_CREATE_STACK_FILE` file/variable.
+ If your stack already exists, this step is skipped, but the `provision` job it belongs to still
+ runs.
+- Your built application is pushed to your S3 bucket then and deployed to your EC2 instance, based
+ on the related JSON object's content. The deployment job finishes whenever the deployment to EC2
+ is done or has failed.
diff --git a/doc/ci/docker/using_docker_build.md b/doc/ci/docker/using_docker_build.md
index 045fcd39c4d..e3123cde1cd 100644
--- a/doc/ci/docker/using_docker_build.md
+++ b/doc/ci/docker/using_docker_build.md
@@ -48,7 +48,6 @@ The simplest approach is to install GitLab Runner in `shell` execution mode.
GitLab Runner then executes job scripts as the `gitlab-runner` user.
1. Install [GitLab Runner](https://gitlab.com/gitlab-org/gitlab-runner/#installation).
-
1. During GitLab Runner installation select `shell` as method of executing job scripts or use command:
```shell
@@ -90,7 +89,6 @@ GitLab Runner then executes job scripts as the `gitlab-runner` user.
1. You can now use `docker` command (and **install** `docker-compose` if needed).
-NOTE: **Note:**
By adding `gitlab-runner` to the `docker` group you are effectively granting `gitlab-runner` full root permissions.
For more information please read [On Docker security: `docker` group considered harmful](https://www.andreas-jung.com/contents/on-docker-security-docker-group-considered-harmful).
@@ -101,7 +99,6 @@ The second approach is to use the special Docker-in-Docker (dind)
(`docker`) and run the job script in context of that
image in privileged mode.
-NOTE: **Note:**
`docker-compose` is not part of Docker-in-Docker (dind). To use `docker-compose` in your
CI builds, follow the `docker-compose`
[installation instructions](https://docs.docker.com/compose/install/).
@@ -149,22 +146,17 @@ released.
#### TLS enabled
-NOTE: **Note:**
-Requires GitLab Runner 11.11 or later, but is not supported if GitLab
-Runner is installed using the [Helm
-chart](https://docs.gitlab.com/runner/install/kubernetes.html). See the
-[related
-issue](https://gitlab.com/gitlab-org/charts/gitlab-runner/-/issues/83) for
-details.
-
The Docker daemon supports connection over TLS and it's done by default
for Docker 19.03.12 or higher. This is the **suggested** way to use the
Docker-in-Docker service and
[GitLab.com shared runners](../../user/gitlab_com/index.md#shared-runners)
support this.
-1. Install [GitLab Runner](https://docs.gitlab.com/runner/install/).
+GitLab Runner 11.11 or later is required, but it is not supported if GitLab
+Runner is installed using the [Helm chart](https://docs.gitlab.com/runner/install/kubernetes.html).
+See the [related issue](https://gitlab.com/gitlab-org/charts/gitlab-runner/-/issues/83) for details.
+1. Install [GitLab Runner](https://docs.gitlab.com/runner/install/).
1. Register GitLab Runner from the command line to use `docker` and `privileged`
mode:
@@ -225,7 +217,7 @@ support this.
# The 'docker' hostname is the alias of the service container as described at
# https://docs.gitlab.com/ee/ci/docker/using_docker_images.html#accessing-the-services.
#
- # Note that if you're using GitLab Runner 12.7 or earlier with the Kubernetes executor and Kubernetes 1.6 or earlier,
+ # If you're using GitLab Runner 12.7 or earlier with the Kubernetes executor and Kubernetes 1.6 or earlier,
# the variable must be set to tcp://localhost:2376 because of how the
# Kubernetes executor connects services to the job container
# DOCKER_HOST: tcp://localhost:2376
@@ -287,7 +279,7 @@ variables:
# The 'docker' hostname is the alias of the service container as described at
# https://docs.gitlab.com/ee/ci/docker/using_docker_images.html#accessing-the-services
#
- # Note that if you're using GitLab Runner 12.7 or earlier with the Kubernetes executor and Kubernetes 1.6 or earlier,
+ # If you're using GitLab Runner 12.7 or earlier with the Kubernetes executor and Kubernetes 1.6 or earlier,
# the variable must be set to tcp://localhost:2375 because of how the
# Kubernetes executor connects services to the job container
# DOCKER_HOST: tcp://localhost:2375
@@ -324,7 +316,6 @@ are done to the services as well, making these incompatible.
In order to do that, follow the steps:
1. Install [GitLab Runner](https://docs.gitlab.com/runner/install/).
-
1. Register GitLab Runner from the command line to use `docker` and share `/var/run/docker.sock`:
```shell
@@ -506,14 +497,13 @@ environment = ["DOCKER_DRIVER=overlay2"]
If you're running multiple runners, you have to modify all configuration files.
-NOTE: **Note:**
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/).
## Using the GitLab Container Registry
Once you've built a Docker image, you can push it up to the built-in
-[GitLab Container Registry](../../user/packages/container_registry/index.md#build-and-push-images-using-gitlab-cicd).
+[GitLab Container Registry](../../user/packages/container_registry/index.md#build-and-push-by-using-gitlab-cicd).
## Troubleshooting
diff --git a/doc/ci/docker/using_docker_images.md b/doc/ci/docker/using_docker_images.md
index 0fcd95c41ed..f7d54aa7d78 100644
--- a/doc/ci/docker/using_docker_images.md
+++ b/doc/ci/docker/using_docker_images.md
@@ -138,7 +138,6 @@ still succeeds even if that warning was printed. For example:
As it was mentioned before, this feature is designed to provide **network accessible**
services. A database is the simplest example of such a service.
-NOTE: **Note:**
The services feature is not designed to, and does not add any software from the
defined `services` image(s) to the job's container.
@@ -186,7 +185,6 @@ access to it from your build container under two hostnames to choose from:
- `tutum-wordpress`
- `tutum__wordpress`
-NOTE: **Note:**
Hostnames with underscores are not RFC valid and may cause problems in 3rd party
applications.
@@ -364,10 +362,9 @@ For example, the following two definitions are equal:
| `name` | yes, when used with any other option | 9.4 | Full name of the image that should be used. It should contain the Registry part if needed. |
| `entrypoint` | no | 9.4 |Command or script that should be executed as the container's entrypoint. It's translated to Docker's `--entrypoint` option while creating the container. The syntax is similar to [`Dockerfile`'s `ENTRYPOINT`](https://docs.docker.com/engine/reference/builder/#entrypoint) directive, where each shell token is a separate string in the array. |
| `command` | no | 9.4 |Command or script that should be used as the container's command. It's translated to arguments passed to Docker after the image's name. The syntax is similar to [`Dockerfile`'s `CMD`](https://docs.docker.com/engine/reference/builder/#cmd) directive, where each shell token is a separate string in the array. |
-| `alias` | no | 9.4 |Additional alias that can be used to access the service from the job's container. Read [Accessing the services](#accessing-the-services) for more information. |
+| `alias` (1) | no | 9.4 |Additional alias that can be used to access the service from the job's container. Read [Accessing the services](#accessing-the-services) for more information. |
-NOTE: **Note:**
-Alias support for the Kubernetes executor was [introduced](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/2229) in GitLab Runner 12.8, and is only available for Kubernetes version 1.7 or later.
+(1) Alias support for the Kubernetes executor was [introduced](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/2229) in GitLab Runner 12.8, and is only available for Kubernetes version 1.7 or later.
### Starting multiple services from the same image
@@ -532,7 +529,6 @@ To define which should be used, the GitLab Runner process reads the configuratio
If the `--user` flag is provided to run the GitLab Runner child processes as unprivileged user,
the home directory of the main GitLab Runner process user is used.
-NOTE: **Note:**
GitLab Runner reads this configuration **only** from `config.toml` and ignores it if
it's provided as an environment variable. This is because GitLab Runner uses **only**
`config.toml` configuration and does not interpolate **ANY** environment variables at
@@ -547,6 +543,7 @@ runtime.
at least version **1.8** if you want to use private registries.
- Available for [Kubernetes executor](https://docs.gitlab.com/runner/executors/kubernetes.html)
in GitLab Runner 13.1 and later.
+- [Credentials Store](#using-credentials-store) and [Credential Helpers](#using-credential-helpers) require binaries to be added to the GitLab Runner's `$PATH`, and require access to do so. Therefore, these features are not available on shared runners or any other runner where the user does not have access to the environment where the runner is installed.
### Using statically-defined credentials
@@ -600,7 +597,7 @@ There are two ways to determine the value of `DOCKER_AUTH_CONFIG`:
Open a terminal and execute the following command:
```shell
- # Note the use of "-n" - it prevents encoding a newline in the password.
+ # The use of "-n" - prevents encoding a newline in the password.
echo -n "my_username:my_password" | base64
# Example output to copy
@@ -650,7 +647,6 @@ follow these steps:
You can add configuration for as many registries as you want, adding more
registries to the `"auths"` hash as described above.
-NOTE: **Note:**
The full `hostname:port` combination is required everywhere
for the runner to match the `DOCKER_AUTH_CONFIG`. For example, if
`registry.example.com:5000/namespace/image:tag` is specified in `.gitlab-ci.yml`,
@@ -679,17 +675,14 @@ To add `DOCKER_AUTH_CONFIG` to a runner:
environment = ["DOCKER_AUTH_CONFIG={\"auths\":{\"registry.example.com:5000\":{\"auth\":\"bXlfdXNlcm5hbWU6bXlfcGFzc3dvcmQ=\"}}}"]
```
-1. Restart the runner service.
-
-NOTE: **Note:**
-The double quotes included in the `DOCKER_AUTH_CONFIG`
-data must be escaped with backslashes. This prevents them from being
-interpreted as TOML.
+ - The double quotes included in the `DOCKER_AUTH_CONFIG`
+ data must be escaped with backslashes. This prevents them from being
+ interpreted as TOML.
+ - The `environment` option is a list. Your runner may
+ have existing entries and you should add this to the list, not replace
+ it.
-NOTE: **Note:**
-The `environment` option is a list. So your runner may
-have existing entries and you should add this to the list, not replace
-it.
+1. Restart the runner service.
### Using Credentials Store
@@ -717,10 +710,9 @@ To configure credentials store, follow these steps:
`${GITLAB_RUNNER_HOME}/.docker/config.json`. GitLab Runner reads this configuration file
and uses the needed helper for this specific repository.
-NOTE: **Note:**
`credsStore` is used to access ALL the registries.
-If you want to use both images from private registry and public images from DockerHub,
-pulling from DockerHub would fail, because Docker daemon tries to use the same credentials for **ALL** the registries.
+If you want to use both images from private registry and public images from Docker Hub,
+pulling from Docker Hub would fail, because Docker daemon tries to use the same credentials for **ALL** the registries.
### Using Credential Helpers
@@ -732,10 +724,8 @@ image which is private and requires you to log in into a private container regis
To configure access for `aws_account_id.dkr.ecr.region.amazonaws.com`, follow these steps:
1. Make sure `docker-credential-ecr-login` is available in GitLab Runner's `$PATH`.
-
1. Have any of the following [AWS credentials setup](https://github.com/awslabs/amazon-ecr-credential-helper#aws-credentials).
Make sure that GitLab Runner can access the credentials.
-
1. Make GitLab Runner use it. There are two ways to accomplish this. Either:
- Create a [variable](../variables/README.md#gitlab-cicd-environment-variables)
@@ -791,7 +781,6 @@ service containers.
For all possible configuration variables check the documentation of each image
provided in their corresponding Docker hub page.
-NOTE: **Note:**
All variables are passed to all services containers. It's not
designed to distinguish which variable should go where.
@@ -823,7 +812,6 @@ time.
## How to debug a job locally
-NOTE: **Note:**
The following commands are run without root privileges. You should be
able to run Docker with your regular user account.
diff --git a/doc/ci/docker/using_kaniko.md b/doc/ci/docker/using_kaniko.md
index a62f4db4fe4..f9b09bada14 100644
--- a/doc/ci/docker/using_kaniko.md
+++ b/doc/ci/docker/using_kaniko.md
@@ -17,13 +17,13 @@ kaniko solves two problems with using the
build](using_docker_build.md#use-docker-in-docker-workflow-with-docker-executor) method:
- Docker-in-Docker requires [privileged mode](https://docs.docker.com/engine/reference/run/#runtime-privilege-and-linux-capabilities)
- in order to function, which is a significant security concern.
+ to function, which is a significant security concern.
- Docker-in-Docker generally incurs a performance penalty and can be quite slow.
## Requirements
-In order to utilize kaniko with GitLab, [a runner](https://docs.gitlab.com/runner/)
-with one of the following executors is required:
+To use kaniko with GitLab, [a runner](https://docs.gitlab.com/runner/) with one
+of the following executors is required:
- [Kubernetes](https://docs.gitlab.com/runner/executors/kubernetes.html).
- [Docker](https://docs.gitlab.com/runner/executors/docker.html).
diff --git a/doc/ci/enable_or_disable_ci.md b/doc/ci/enable_or_disable_ci.md
index 46cf76637a4..8b88ec509e7 100644
--- a/doc/ci/enable_or_disable_ci.md
+++ b/doc/ci/enable_or_disable_ci.md
@@ -31,7 +31,6 @@ either:
- Site-wide by modifying the settings in `gitlab.yml` and `gitlab.rb` for source
and Omnibus installations respectively.
-NOTE: **Note:**
This only applies to pipelines run as part of GitLab CI/CD. This will not enable or disable
pipelines that are run from an [external integration](../user/project/integrations/overview.md#integrations-listing).
diff --git a/doc/ci/environments/index.md b/doc/ci/environments/index.md
index 07d0dac6163..baf2156e64a 100644
--- a/doc/ci/environments/index.md
+++ b/doc/ci/environments/index.md
@@ -118,11 +118,9 @@ With this configuration, we:
- Ensure that our app is able to be built successfully.
- Lastly we deploy to the staging server.
-NOTE: **Note:**
-The `environment` keyword defines where the app is deployed.
-The environment `name` and `url` is exposed in various places
-within GitLab. Each time a job that has an environment specified
-succeeds, a deployment is recorded, along with the Git SHA, and environment name.
+Note that the `environment` keyword defines where the app is deployed. The environment `name` and
+`url` is exposed in various places within GitLab. Each time a job that has an environment specified
+succeeds, a deployment is recorded along with the Git SHA and environment name.
CAUTION: **Caution:**
Some characters are not allowed in environment names. Use only letters,
@@ -288,12 +286,11 @@ You can find the "play" button in the pipelines, environments, deployments, and
| Deployments | ![Deployments manual action](../img/environments_manual_action_deployments.png) |
| Jobs | ![Builds manual action](../img/environments_manual_action_jobs.png) |
-Clicking on the play button in any view will trigger the `deploy_prod` job, and the
-deployment will be recorded as a new environment named `production`.
+Clicking the play button in any view triggers the `deploy_prod` job. The deployment is recorded as a
+new environment named `production`.
-NOTE: **Note:**
-If your environment's name is `production` (all lowercase),
-it will get recorded in [Value Stream Analytics](../../user/project/cycle_analytics.md).
+If your environment's name is `production` (all lowercase), it's recorded in
+[Value Stream Analytics](../../user/analytics/value_stream_analytics.md).
### Configuring dynamic environments
@@ -371,9 +368,8 @@ For the value of:
the example above: `https://$CI_COMMIT_REF_NAME.example.com`, which would give a URL
of `https://100-do-the-thing.example.com`.
-NOTE: **Note:**
-You are not required to use the same prefix or only slashes (`/`) in the dynamic environments'
-names. However, using this format will enable the [grouping similar environments](#grouping-similar-environments)
+You aren't required to use the same prefix or only slashes (`/`) in the dynamic environments' names.
+However, using this format enables the [grouping similar environments](#grouping-similar-environments)
feature.
### Configuring Kubernetes deployments
@@ -384,6 +380,12 @@ If you are deploying to a [Kubernetes cluster](../../user/project/clusters/index
associated with your project, you can configure these deployments from your
`gitlab-ci.yml` file.
+NOTE: **Note:**
+Kubernetes configuration isn't supported for Kubernetes clusters that are
+[managed by GitLab](../../user/project/clusters/index.md#gitlab-managed-clusters).
+To follow progress on support for GitLab-managed clusters, see the
+[relevant issue](https://gitlab.com/gitlab-org/gitlab/-/issues/38054).
+
The following configuration options are supported:
- [`namespace`](https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/)
@@ -411,12 +413,6 @@ trace on the deployment job page:
![Deployment cluster information](../img/environments_deployment_cluster_v12_8.png)
-NOTE: **Note:**
-Kubernetes configuration is not supported for Kubernetes clusters
-that are [managed by GitLab](../../user/project/clusters/index.md#gitlab-managed-clusters).
-To follow progress on support for GitLab-managed clusters, see the
-[relevant issue](https://gitlab.com/gitlab-org/gitlab/-/issues/38054).
-
#### Configuring incremental rollouts
Learn how to release production changes to only a portion of your Kubernetes pods with
@@ -514,9 +510,8 @@ review_app:
This example requires that NGINX and GitLab Runner are set up on the server this job will run on.
-NOTE: **Note:**
-See the [limitations](#limitations) section for some edge cases regarding the naming of
-your branches and Review Apps.
+See the [limitations](#limitations) section for some edge cases regarding the naming of your
+branches and Review Apps.
The complete example provides the following workflow to developers:
@@ -617,13 +612,12 @@ To retry or rollback a deployment:
#### What to expect with a rollback
-Pressing the **Rollback** button on a specific commit will trigger a _new_ deployment with its
-own unique job ID.
-
-This means that you will see a new deployment that points to the commit you are rolling back to.
+Pressing the **Rollback** button on a specific commit triggers a _new_ deployment with its own
+unique job ID. This means that you will see a new deployment that points to the commit you're
+rolling back to.
-NOTE: **Note:**
-The defined deployment process in the job's `script` determines whether the rollback succeeds or not.
+Note that the defined deployment process in the job's `script` determines whether the rollback
+succeeds.
### Using the environment URL
@@ -662,9 +656,8 @@ Stopping an environment:
This is often used when multiple developers are working on a project at the same time,
each of them pushing to their own branches, causing many dynamic environments to be created.
-NOTE: **Note:**
-Starting with GitLab 8.14, dynamic environments are stopped automatically
-when their associated branch is deleted.
+Starting with GitLab 8.14, dynamic environments stop automatically when their associated branch is
+deleted.
#### Automatically stopping an environment
@@ -721,29 +714,25 @@ You can read more in the [`.gitlab-ci.yml` reference](../yaml/README.md#environm
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/20956) in GitLab 12.8.
-You can set a expiry time to environments and stop them automatically after a certain period.
+You can set an expiry time for environments and stop them automatically after a certain period.
-For example, consider the use of this feature with Review Apps environments.
-When you set up Review Apps, sometimes they keep running for a long time
-because some merge requests are left as open. An example for this situation is when the author of the merge
-request is not actively working on it, due to priority changes or a different approach was decided on, and the merge requests was simply forgotten.
-Idle environments waste resources, therefore they
-should be terminated as soon as possible.
+For example, consider the use of this feature with Review App environments. When you set up Review
+Apps, sometimes they keep running for a long time because some merge requests are left open and
+forgotten. Such idle environments waste resources and should be terminated as soon as possible.
-To address this problem, you can specify an optional expiration date for
-Review Apps environments. When the expiry time is reached, GitLab will automatically trigger a job
-to stop the environment, eliminating the need of manually doing so. In case an environment is updated, the expiration is renewed
-ensuring that only active merge requests keep running Review Apps.
+To address this problem, you can specify an optional expiration date for Review App environments.
+When the expiry time is reached, GitLab automatically triggers a job to stop the environment,
+eliminating the need of manually doing so. In case an environment is updated, the expiration is
+renewed ensuring that only active merge requests keep running Review Apps.
-To enable this feature, you need to specify the [`environment:auto_stop_in`](../yaml/README.md#environmentauto_stop_in) keyword in `.gitlab-ci.yml`.
-You can specify a human-friendly date as the value, such as `1 hour and 30 minutes` or `1 day`.
-`auto_stop_in` uses the same format of [`artifacts:expire_in` docs](../yaml/README.md#artifactsexpire_in).
+To enable this feature, you must specify the [`environment:auto_stop_in`](../yaml/README.md#environmentauto_stop_in)
+keyword in `.gitlab-ci.yml`. You can specify a human-friendly date as the value, such as
+`1 hour and 30 minutes` or `1 day`. `auto_stop_in` uses the same format of
+[`artifacts:expire_in` docs](../yaml/README.md#artifactsexpire_in).
-NOTE: **Note:**
-Due to the resource limitation, a background worker for stopping environments only
-runs once every hour. This means environments will not be stopped at the exact
-timestamp as the specified period, but will be stopped when the hourly cron worker
-detects expired environments.
+Note that due to resource limitation, a background worker for stopping environments only runs once
+every hour. This means that environments aren't stopped at the exact timestamp specified, but are
+instead stopped when the hourly cron worker detects expired environments.
##### Auto-stop example
@@ -866,7 +855,7 @@ exist, you should see something like:
### Environment incident management
-You have successfuly setup a Continous Delivery/Deployment workflow in your project.
+You have successfully setup a Continuous Delivery/Deployment workflow in your project.
Production environments can go down unexpectedly, including for reasons outside
of your own control. For example, issues with external dependencies, infrastructure,
or human error can cause major issues with an environment. This could include:
@@ -903,8 +892,7 @@ you can monitor the behavior of your app running in each environment. For the mo
dashboard to appear, you need to Configure Prometheus to collect at least one
[supported metric](../../user/project/integrations/prometheus_library/index.md).
-NOTE: **Note:**
-Since GitLab 9.2, all deployments to an environment are shown directly on the monitoring dashboard.
+In GitLab 9.2 and later, all deployments to an environment are shown directly on the monitoring dashboard.
Once configured, GitLab will attempt to retrieve [supported performance metrics](../../user/project/integrations/prometheus_library/index.md)
for any environment that has had a successful deployment. If monitoring data was
@@ -938,6 +926,11 @@ This is a powerful feature that allows you to debug issues without leaving the c
of your web browser. To enable it, just follow the instructions given in the service integration
documentation.
+NOTE: **Note:**
+Container-based deployments often lack basic tools (like an editor), and may
+be stopped or restarted at any time. If this happens, you will lose all your
+changes. Treat this as a debugging tool, not a comprehensive online IDE.
+
Once enabled, your environments will gain a "terminal" button:
![Terminal button on environment index](../img/environments_terminal_button_on_index.png)
@@ -961,14 +954,9 @@ by your deployment so you can:
You can open multiple terminals to the same environment, they each get their own shell
session and even a multiplexer like `screen` or `tmux`.
-NOTE: **Note:**
-Container-based deployments often lack basic tools (like an editor), and may
-be stopped or restarted at any time. If this happens, you will lose all your
-changes. Treat this as a debugging tool, not a comprehensive online IDE.
-
### Check out deployments locally
-Since GitLab 8.13, a reference in the Git repository is saved for each deployment, so
+In GitLab 8.13 and later, a reference in the Git repository is saved for each deployment, so
knowing the state of your current environments is only a `git fetch` away.
In your Git configuration, append the `[remote "<your-remote>"]` block with an extra
@@ -1024,9 +1012,8 @@ As you can see, you can use specific matching for selecting a particular environ
and also use wildcard matching (`*`) for selecting a particular environment group,
such as [Review Apps](../review_apps/index.md) (`review/*`).
-NOTE: **Note:**
-The most _specific_ spec takes precedence over the other wildcard matching.
-In this case, `review/feature-1` spec takes precedence over `review/*` and `*` specs.
+Note that the most _specific_ spec takes precedence over the other wildcard matching. In this case,
+the `review/feature-1` spec takes precedence over `review/*` and `*` specs.
### Environments Dashboard **(PREMIUM)**
diff --git a/doc/ci/environments/protected_environments.md b/doc/ci/environments/protected_environments.md
index 5dda0cc81f6..87bced29906 100644
--- a/doc/ci/environments/protected_environments.md
+++ b/doc/ci/environments/protected_environments.md
@@ -9,8 +9,6 @@ type: concepts, howto
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/6303) in [GitLab Premium](https://about.gitlab.com/pricing/) 11.3.
-## Overview
-
[Environments](../environments/index.md) can be used for different reasons:
- Some of them are just for testing.
diff --git a/doc/ci/examples/artifactory_and_gitlab/index.md b/doc/ci/examples/artifactory_and_gitlab/index.md
index 2abb2cc1b0d..e2ee05923cd 100644
--- a/doc/ci/examples/artifactory_and_gitlab/index.md
+++ b/doc/ci/examples/artifactory_and_gitlab/index.md
@@ -23,10 +23,10 @@ We also assume that an Artifactory instance is available and reachable from the
## Create the simple Maven dependency
-First of all, you need an application to work with: in this specific case we will
-use a simple one, but it could be any Maven application. This will be the
-dependency you want to package and deploy to Artifactory, in order to be
-available to other projects.
+First, you need an application to work with: in this specific case we'll use a
+simple one, but it could be any Maven application. This will be the dependency
+you want to package and deploy to Artifactory, to be available to other
+projects.
### Prepare the dependency application
@@ -58,7 +58,7 @@ The application is ready to use, but you need some additional steps to deploy it
1. Log in to Artifactory with your user's credentials.
1. From the main screen, click on the `libs-release-local` item in the **Set Me Up** panel.
1. Copy to clipboard the configuration snippet under the **Deploy** paragraph.
-1. Change the `url` value in order to have it configurable via variables.
+1. Change the `url` value to have it configurable by using variables.
1. Copy the snippet in the `pom.xml` file for your project, just after the
`dependencies` section. The snippet should look like this:
@@ -146,8 +146,9 @@ deploy:
- master
```
-The runner will use the latest [Maven Docker image](https://hub.docker.com/_/maven/), which already contains all the tools and the dependencies you need to manage the project,
-in order to run the jobs.
+The runner uses the latest [Maven Docker image](https://hub.docker.com/_/maven/),
+which contains all of the tools and dependencies needed to manage the project
+and to run the jobs.
Environment variables are set to instruct Maven to use the `homedir` of the repository instead of the user's home when searching for configuration and dependencies.
diff --git a/doc/ci/examples/authenticating-with-hashicorp-vault/index.md b/doc/ci/examples/authenticating-with-hashicorp-vault/index.md
index 73896547675..4a0ff2fa6ac 100644
--- a/doc/ci/examples/authenticating-with-hashicorp-vault/index.md
+++ b/doc/ci/examples/authenticating-with-hashicorp-vault/index.md
@@ -41,15 +41,14 @@ The JWT's payload looks like this:
"nbf": 1585798372, # Not valid before
"exp": 1585713886, # Expire at
"sub": "job_1212", # Subject (job id)
- "namespace_id": "1",
- "namespace_path": "mygroup",
- "project_id": "22",
- "project_path": "mygroup/myproject",
- "user_id": "42",
- "user_login": "myuser",
- "user_email": "myuser@example.com",
- "pipeline_id": "1212",
- "job_id": "1212",
+ "namespace_id": "1", # Use this to scope to group or user level namespace by id
+ "namespace_path": "mygroup", # Use this to scope to group or user level namespace by path
+ "project_id": "22", #
+ "project_path": "mygroup/myproject", #
+ "user_id": "42", # Id of the user executing the job
+ "user_email": "myuser@example.com", # Email of the user executing the job
+ "pipeline_id": "1212", #
+ "job_id": "1212", #
"ref": "auto-deploy-2020-04-01", # Git ref for this job
"ref_type": "branch", # Git ref type, branch or tag
"ref_protected": "true" # true if this git ref is protected, false otherwise
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 1f6c81a68aa..aa6e6f73a0d 100644
--- a/doc/ci/examples/end_to_end_testing_webdriverio/index.md
+++ b/doc/ci/examples/end_to_end_testing_webdriverio/index.md
@@ -9,7 +9,7 @@ type: tutorial
[Review Apps](../../review_apps/index.md) are great: for every merge request
(or branch, for that matter), the new code can be copied and deployed to a fresh production-like live
-environment, making it incredibly low-effort to assess the impact of the changes. Thus, when we use a dependency manager like
+environment, reducing the effort to assess the impact of changes. Thus, when we use a dependency manager like
[Dependencies.io](https://www.dependencies.io/), it can submit a merge request with an updated dependency,
and it will immediately be clear that the application can still be properly built and deployed. After all, you can _see_ it
running!
@@ -95,9 +95,10 @@ dependency upgrade did not break anything without even having to look at your we
## Running locally
-We'll get to running the above test in CI/CD in a moment. When writing tests, however, it helps if
-you do not have to wait for your pipelines to succeed in order to check whether they do what you
-expect them to do. In other words, let's get it to run locally.
+We'll get to running the above test in CI/CD in a moment. When writing tests,
+however, it helps if you don't have to wait for your pipelines to succeed to
+determine whether they do what you expect them to do. In other words, let's get
+it to run locally.
Make sure that your app is running locally. If you use Webpack,
you can use [the Webpack Dev Server WebdriverIO plugin](https://www.npmjs.com/package/wdio-webpack-dev-server-service)
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 8927c5c3480..aaa34afeddf 100644
--- a/doc/ci/examples/laravel_with_gitlab_and_envoy/index.md
+++ b/doc/ci/examples/laravel_with_gitlab_and_envoy/index.md
@@ -143,7 +143,6 @@ Now, let's clone our repository on the server just to make sure the `deployer` u
git clone git@gitlab.example.com:<USERNAME>/laravel-sample.git
```
-NOTE: **Note:**
Answer **yes** if asked `Are you sure you want to continue connecting (yes/no)?`.
It adds GitLab.com to the known hosts.
@@ -167,7 +166,6 @@ server {
}
```
-NOTE: **Note:**
You may replace the app's name in `/var/www/app/current/public` with the folder name of your application.
## Setting up Envoy
@@ -397,8 +395,6 @@ To be able to build, test, and deploy our app with GitLab CI/CD, we need to prep
To do that, we'll use a Docker image which has the minimum requirements that a Laravel app needs to run.
[There are other ways](../php.md#test-php-projects-using-the-docker-executor) to do that as well, but they may lead our builds run slowly, which is not what we want when there are faster options to use.
-With Docker images our builds run incredibly faster!
-
### Create a Container Image
Let's create a [Dockerfile](https://gitlab.com/mehranrasulian/laravel-sample/blob/master/Dockerfile) in the root directory of our app with the following content:
@@ -441,9 +437,11 @@ On your GitLab project repository navigate to the **Registry** tab.
![container registry page empty image](img/container_registry_page_empty_image.png)
-You may need to [enable Container Registry](../../../user/packages/container_registry/index.md#enable-the-container-registry-for-your-project) to your project to see this tab. You'll find it under your project's **Settings > General > Visibility, project features, permissions**.
+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 login to the GitLab registry using our GitLab username and password:
+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,
+then run the following commands:
```shell
docker login registry.gitlab.com
@@ -457,14 +455,10 @@ docker build -t registry.gitlab.com/<USERNAME>/laravel-sample .
docker push registry.gitlab.com/<USERNAME>/laravel-sample
```
-NOTE: **Note:**
-To run the above commands, we first need to have [Docker](https://docs.docker.com/engine/installation/) installed on our machine.
-
Congratulations! You just pushed the first Docker image to the GitLab Registry, and if you refresh the page you should be able to see it:
![container registry page with image](img/container_registry_page_with_image.jpg)
-NOTE: **Note:**
You can also [use GitLab CI/CD](https://about.gitlab.com/blog/2016/05/23/gitlab-container-registry/#use-with-gitlab-ci) to build and push your Docker images, rather than doing that on your machine.
We'll use this image further down in the `.gitlab-ci.yml` configuration file to handle the process of testing and deploying our app.
@@ -544,7 +538,6 @@ services:
...
```
-NOTE: **Note:**
If you wish to test your app with different PHP versions and [database management systems](../../services/README.md), you can define different `image` and `services` keywords for each test job.
#### Variables
diff --git a/doc/ci/examples/php.md b/doc/ci/examples/php.md
index ab6ff1dc177..699d04f632c 100644
--- a/doc/ci/examples/php.md
+++ b/doc/ci/examples/php.md
@@ -141,12 +141,11 @@ Of course, `my_php.ini` must be present in the root directory of your repository
## Test PHP projects using the Shell executor
-The shell executor runs your job in a terminal session on your server.
-Thus, in order to test your projects you first need to make sure that all
-dependencies are installed.
+The shell executor runs your job in a terminal session on your server. To test
+your projects, you must first ensure that all dependencies are installed.
-For example, in a VM running Debian 8 we first update the cache, then we
-install `phpunit` and `php5-mysql`:
+For example, in a VM running Debian 8, first update the cache, and then install
+`phpunit` and `php5-mysql`:
```shell
sudo apt-get update -y
@@ -219,8 +218,8 @@ test:atoum:
### Using Composer
The majority of the PHP projects use Composer for managing their PHP packages.
-In order to execute Composer before running your tests, simply add the
-following in your `.gitlab-ci.yml`:
+To execute Composer before running your tests, add the following to your
+`.gitlab-ci.yml`:
```yaml
# Composer stores all downloaded packages in the vendor/ directory.
@@ -243,14 +242,14 @@ before_script:
## Access private packages or dependencies
If your test suite needs to access a private repository, you need to configure
-[the SSH keys](../ssh_keys/README.md) in order to be able to clone it.
+the [SSH keys](../ssh_keys/README.md) to be able to clone it.
## Use databases or other services
-Most of the time you will need a running database in order for your tests to
-run. If you are using the Docker executor you can leverage Docker's ability to
-link to other containers. With GitLab Runner, this can be achieved by
-defining a `service`.
+Most of the time, you need a running database for your tests to be able to
+run. If you're using the Docker executor, you can leverage Docker's ability to
+link to other containers. With GitLab Runner, this can be achieved by defining
+a `service`.
This functionality is covered in [the CI services](../services/README.md)
documentation.
diff --git a/doc/ci/examples/test-and-deploy-ruby-application-to-heroku.md b/doc/ci/examples/test-and-deploy-ruby-application-to-heroku.md
index 066c0cf214f..86c979c489c 100644
--- a/doc/ci/examples/test-and-deploy-ruby-application-to-heroku.md
+++ b/doc/ci/examples/test-and-deploy-ruby-application-to-heroku.md
@@ -68,7 +68,7 @@ First install [Docker Engine](https://docs.docker.com/installation/).
To build this project you also need to have [GitLab Runner](https://docs.gitlab.com/runner/).
You can use public runners available on `gitlab.com` or register your own. Start by
-creating a template configuration file in order to pass complex configuration:
+creating a template configuration file to pass complex configuration:
```shell
cat > /tmp/test-config.template.toml << EOF
diff --git a/doc/ci/examples/test_phoenix_app_with_gitlab_ci_cd/index.md b/doc/ci/examples/test_phoenix_app_with_gitlab_ci_cd/index.md
index ab6a4d3f507..c62f0dec598 100644
--- a/doc/ci/examples/test_phoenix_app_with_gitlab_ci_cd/index.md
+++ b/doc/ci/examples/test_phoenix_app_with_gitlab_ci_cd/index.md
@@ -117,7 +117,6 @@ Generated hello_gitlab_ci app
The database for HelloGitlabCi.Repo has been created
```
-NOTE: **Note:**
Phoenix assumes that our PostgreSQL database will have a `postgres` user account with the correct
permissions and a password of `postgres`. If it's not your case, check
[Ecto's instructions](https://hexdocs.pm/ecto/Ecto.html#module-repositories).
@@ -205,7 +204,6 @@ when running our Phoenix in our `localhost`.
Without `.gitkeep`, Git will not upload this empty directory and we'll got an error when running our
test on GitLab.
- NOTE: **Note:**
If we add a folder via the GitLab UI, GitLab itself will add the `.gitkeep` to that new dir.
Now, let's run a local test and see if everything we did didn't break anything.
diff --git a/doc/ci/img/cf_ec2_diagram_v13_5.png b/doc/ci/img/cf_ec2_diagram_v13_5.png
new file mode 100644
index 00000000000..1d49790c7b9
--- /dev/null
+++ b/doc/ci/img/cf_ec2_diagram_v13_5.png
Binary files differ
diff --git a/doc/ci/img/ci_lint.png b/doc/ci/img/ci_lint.png
index e62de011293..fdc3868cdce 100644
--- a/doc/ci/img/ci_lint.png
+++ b/doc/ci/img/ci_lint.png
Binary files differ
diff --git a/doc/ci/img/ci_lint_dry_run.png b/doc/ci/img/ci_lint_dry_run.png
index 4092b66d534..61d6379f70e 100644
--- a/doc/ci/img/ci_lint_dry_run.png
+++ b/doc/ci/img/ci_lint_dry_run.png
Binary files differ
diff --git a/doc/ci/img/gitlab_vault_workflow_v13_4.png b/doc/ci/img/gitlab_vault_workflow_v13_4.png
new file mode 100644
index 00000000000..80d07362bf4
--- /dev/null
+++ b/doc/ci/img/gitlab_vault_workflow_v13_4.png
Binary files differ
diff --git a/doc/ci/introduction/index.md b/doc/ci/introduction/index.md
index db2749233e8..d1f3e449e5b 100644
--- a/doc/ci/introduction/index.md
+++ b/doc/ci/introduction/index.md
@@ -12,7 +12,7 @@ In this document, we'll present an overview of the concepts of Continuous Integr
Continuous Delivery, and Continuous Deployment, as well as an introduction to
GitLab CI/CD.
-NOTE: **Note:**
+TIP: **Tip:**
Out-of-the-box management systems can decrease hours spent on maintaining toolchains by 10% or more.
Watch our ["Mastering continuous software development"](https://about.gitlab.com/webcast/mastering-ci-cd/)
webcast to learn about continuous methods and how GitLab’s built-in CI can help you simplify and scale software development.
@@ -154,7 +154,7 @@ commits to a feature branch in a remote repository in GitLab,
the CI/CD pipeline set for your project is triggered. By doing
so, GitLab CI/CD:
-- Runs automated scripts (sequential or parallel) to:
+- Runs automated scripts (sequentially or in parallel) to:
- Build and test your app.
- Preview the changes per merge request with Review Apps, as you
would see in your `localhost`.
diff --git a/doc/ci/merge_request_pipelines/index.md b/doc/ci/merge_request_pipelines/index.md
index 3ce62936168..cc0b4ac1f86 100644
--- a/doc/ci/merge_request_pipelines/index.md
+++ b/doc/ci/merge_request_pipelines/index.md
@@ -24,7 +24,6 @@ can run a pipeline for merge requests.
![Merge request page](img/merge_request.png)
-NOTE: **Note:**
If you use this feature with [merge when pipeline succeeds](../../user/project/merge_requests/merge_when_pipeline_succeeds.md),
pipelines for merge requests take precedence over the other regular pipelines.
@@ -125,8 +124,9 @@ Therefore:
- Since `C` specifies that it should only run for merge requests, it will not run for any pipeline
except a merge request pipeline.
-This helps you avoid having to add the `only:` rule to all of your jobs
-in order to make them always run. You can use this format to set up a Review App, helping to save resources.
+This helps you avoid having to add the `only:` rule to all of your jobs to make
+them always run. You can use this format to set up a Review App, helping to
+save resources.
#### Excluding certain branches
diff --git a/doc/ci/merge_request_pipelines/pipelines_for_merged_results/index.md b/doc/ci/merge_request_pipelines/pipelines_for_merged_results/index.md
index dd08f9248f6..2330bdb4c7c 100644
--- a/doc/ci/merge_request_pipelines/pipelines_for_merged_results/index.md
+++ b/doc/ci/merge_request_pipelines/pipelines_for_merged_results/index.md
@@ -80,8 +80,8 @@ For more information, read the [documentation on Merge Trains](merge_trains/inde
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/12996) in [GitLab Premium](https://about.gitlab.com/pricing/) 12.3.
-GitLab CI/CD can detect the presence of redundant pipelines,
-and will cancel them automatically in order to conserve CI resources.
+GitLab CI/CD can detect the presence of redundant pipelines, and cancels them
+to conserve CI resources.
When a user merges a merge request immediately within an ongoing merge
train, the train will be reconstructed, as it will recreate the expected
diff --git a/doc/ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/index.md b/doc/ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/index.md
index 1f88e8f832f..45cae49377f 100644
--- a/doc/ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/index.md
+++ b/doc/ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/index.md
@@ -37,7 +37,6 @@ run.
To add a merge request to a merge train, you need [permissions](../../../../user/permissions.md) to push to the target branch.
-NOTE: **Note:**
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
will be queued until a slot in the merge train is free. There is no limit to the
diff --git a/doc/ci/metrics_reports.md b/doc/ci/metrics_reports.md
index 4f4471225a0..53e097760e6 100644
--- a/doc/ci/metrics_reports.md
+++ b/doc/ci/metrics_reports.md
@@ -9,8 +9,6 @@ type: reference
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/9788) in [GitLab Premium](https://about.gitlab.com/pricing/) 11.10. Requires GitLab Runner 11.10 and above.
-## Overview
-
GitLab provides a lot of great reporting tools for [merge requests](../user/project/merge_requests/index.md) - [Unit test reports](unit_test_reports.md), [code quality](../user/project/merge_requests/code_quality.md), performance tests, etc. While JUnit is a great open framework for tests that "pass" or "fail", it is also important to see other types of metrics from a given change.
You can configure your job to use custom Metrics Reports, and GitLab will display a report on the merge request so that it's easier and faster to identify changes without having to check the entire log.
diff --git a/doc/ci/migration/jenkins.md b/doc/ci/migration/jenkins.md
index 8dff99f7244..1130c11f472 100644
--- a/doc/ci/migration/jenkins.md
+++ b/doc/ci/migration/jenkins.md
@@ -23,7 +23,7 @@ that were able to quickly complete this migration:
1. Use the [Jenkins Wrapper](#jenkinsfile-wrapper) to temporarily maintain fragile Jenkins jobs.
1. Migrate the build and CI jobs and configure them to show results directly in your merge requests. They can use [Auto DevOps](../../topics/autodevops/index.md) as a starting point, and [customize](../../topics/autodevops/customize.md) or [decompose](../../topics/autodevops/customize.md#using-components-of-auto-devops) the configuration as needed.
1. Add [Review Apps](../review_apps/index.md).
- 1. Migrate the deployment jobs using [cloud deployment templates](../cloud_deployment/index.md), adding [environments](../environments/index.md), and [deploy boards](../..//user/project/deploy_boards.md).
+ 1. Migrate the deployment jobs using [cloud deployment templates](../cloud_deployment/index.md), adding [environments](../environments/index.md), and [deploy boards](../../user/project/deploy_boards.md).
1. Work to unwrap any jobs still running with the use of the Jenkins wrapper.
1. Take stock of any common CI/CD job definitions then create and share [templates](#templates) for them.
1. Check the [pipeline efficiency documentation](../pipelines/pipeline_efficiency.md)
@@ -83,7 +83,7 @@ There are some high level differences between the products worth mentioning:
- You can control which jobs run in which cases, depending on how they are triggered,
with the [`rules` syntax](../yaml/README.md#rules).
-- GitLab [pipeline scheduling concepts](../pipelines/schedules.md) are also different than with Jenkins.
+- GitLab [pipeline scheduling concepts](../pipelines/schedules.md) are also different from Jenkins.
- You can reuse pipeline configurations using the [`include` keyword](../yaml/README.md#include)
and [templates](#templates). Your templates can be kept in a central repository (with different
permissions), and then any project can use them. This central project could also
diff --git a/doc/ci/multi_project_pipelines.md b/doc/ci/multi_project_pipelines.md
index 3f9a00b6cc8..378adcd35e9 100644
--- a/doc/ci/multi_project_pipelines.md
+++ b/doc/ci/multi_project_pipelines.md
@@ -163,6 +163,8 @@ have permission to run CI/CD pipelines against the protected branch, the pipelin
### Passing variables to a downstream pipeline
+#### With the `variables` keyword
+
Sometimes you might want to pass variables to a downstream pipeline.
You can do that using the `variables` keyword, just like you would when
defining a regular job.
@@ -211,10 +213,49 @@ In this scenario, the `UPSTREAM_BRANCH` variable with a value related to the
upstream pipeline will be passed to the `downstream-job` job, and will be available
within the context of all downstream builds.
-NOTE: **Tip:**
Upstream pipelines take precedence over downstream ones. If there are two
variables with the same name defined in both upstream and downstream projects,
-the ones defined in the upstream project will take precedence.
+the ones defined in the upstream project take precedence.
+
+#### With variable inheritance
+
+You can pass variables to a downstream pipeline with [`dotenv` variable inheritance](variables/README.md#inherit-environment-variables) and [cross project artifact downloads](yaml/README.md#cross-project-artifact-downloads-with-needs).
+
+In the upstream pipeline:
+
+1. Save the variables in a `.env` file.
+1. Save the `.env` file as a `dotenv` report.
+1. Trigger the downstream pipeline.
+
+```yaml
+build_vars:
+ stage: build
+ script:
+ - echo "BUILD_VERSION=hello" >> build.env
+ artifacts:
+ reports:
+ dotenv: build.env
+
+deploy:
+ stage: deploy
+ trigger: my/downstream_project
+```
+
+Set the `test` job in the downstream pipeline to inherit the variables from the `build_vars`
+job in the upstream project with `needs:`. The `test` job inherits the variables in the
+`dotenv` report and it can access `BUILD_VERSION` in the script:
+
+```yaml
+test:
+ stage: test
+ script:
+ - echo $BUILD_VERSION
+ needs:
+ - project: my/upstream_project
+ job: build_vars
+ ref: master
+ artifacts: true
+```
### Mirroring status from triggered pipeline
@@ -280,3 +321,11 @@ Any pipelines that complete successfully for new tags in the subscribed project
will now trigger a pipeline on the current project's default branch. The maximum
number of upstream pipeline subscriptions is 2 by default, for both the upstream and
downstream projects. This [application limit](../administration/instance_limits.md#number-of-cicd-subscriptions-to-a-project) can be changed on self-managed instances by a GitLab administrator.
+
+## Downstream private projects confidentiality concern
+
+If you trigger a pipeline in a downstream private project, the name of the project
+and the status of the pipeline is visible in the upstream project's pipelines page.
+
+If you have a public project that can trigger downstream pipelines in a private
+project, make sure to check that there are no confidentiality problems.
diff --git a/doc/ci/parent_child_pipelines.md b/doc/ci/parent_child_pipelines.md
index 83fa1d355e6..a0965643970 100644
--- a/doc/ci/parent_child_pipelines.md
+++ b/doc/ci/parent_child_pipelines.md
@@ -68,11 +68,22 @@ microservice_a:
trigger:
include:
- local: path/to/microservice_a.yml
- - template: SAST.gitlab-ci.yml
+ - template: Security/SAST.gitlab-ci.yml
```
-NOTE: **Note:**
-The max number of entries that are accepted for `trigger:include:` is three.
+In [GitLab 13.5](https://gitlab.com/gitlab-org/gitlab/-/issues/205157) and later,
+you can use [`include:file`](yaml/README.md#includefile) to trigger child pipelines
+with a configuration file in a different project:
+
+```yaml
+microservice_a:
+ trigger:
+ include:
+ - project: 'my-group/my-pipeline-library'
+ file: 'path/to/ci-config.yml'
+```
+
+The maximum number of entries that are accepted for `trigger:include:` is three.
Similar to [multi-project pipelines](multi_project_pipelines.md#mirroring-status-from-triggered-pipeline),
we can set the parent pipeline to depend on the status of the child pipeline upon completion:
@@ -82,7 +93,7 @@ microservice_a:
trigger:
include:
- local: path/to/microservice_a.yml
- - template: SAST.gitlab-ci.yml
+ - template: Security/SAST.gitlab-ci.yml
strategy: depend
```
@@ -153,32 +164,13 @@ This is [resolved in GitLab 12.10](https://gitlab.com/gitlab-org/gitlab/-/issues
## Nested child pipelines
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/29651) in GitLab 13.4.
-> - It's [deployed behind a feature flag](../user/feature_flags.md), enabled by default.
-> - It's enabled on GitLab.com.
-> - It's recommended for production use.
-> - For GitLab self-managed instances, GitLab administrators can opt to [disable it](#enable-or-disable-nested-child-pipelines). **(CORE ONLY)**
+> - [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.
-### Enable or disable nested child pipelines **(CORE ONLY)**
+## Pass variables to a child pipeline
-Nested child pipelines with a depth of two are under development but ready for
-production use. This feature is deployed behind a feature flag that is **enabled by default**.
-
-[GitLab administrators with access to the GitLab Rails console](../administration/feature_flags.md)
-can opt to disable it.
-
-To enable it:
-
-```ruby
-Feature.enable(:ci_child_of_child_pipeline)
-```
-
-To disable it:
-
-```ruby
-Feature.disable(:ci_child_of_child_pipeline)
-```
+You can [pass variables to a downstream pipeline](multi_project_pipelines.md#passing-variables-to-a-downstream-pipeline).
diff --git a/doc/ci/pipelines/img/ci_efficiency_pipeline_dag_critical_path.png b/doc/ci/pipelines/img/ci_efficiency_pipeline_dag_critical_path.png
index 1715e8224ab..421fddaf38d 100644
--- a/doc/ci/pipelines/img/ci_efficiency_pipeline_dag_critical_path.png
+++ b/doc/ci/pipelines/img/ci_efficiency_pipeline_dag_critical_path.png
Binary files differ
diff --git a/doc/ci/pipelines/img/ci_efficiency_pipeline_health_grafana_dashboard.png b/doc/ci/pipelines/img/ci_efficiency_pipeline_health_grafana_dashboard.png
index 0956e76804e..59276bda727 100644
--- a/doc/ci/pipelines/img/ci_efficiency_pipeline_health_grafana_dashboard.png
+++ b/doc/ci/pipelines/img/ci_efficiency_pipeline_health_grafana_dashboard.png
Binary files differ
diff --git a/doc/ci/pipelines/index.md b/doc/ci/pipelines/index.md
index 1b9048089bd..f7e3698b6d4 100644
--- a/doc/ci/pipelines/index.md
+++ b/doc/ci/pipelines/index.md
@@ -10,7 +10,7 @@ type: reference
> Introduced in GitLab 8.8.
-NOTE: **Tip:**
+TIP: **Tip:**
Watch the
["Mastering continuous software development"](https://about.gitlab.com/webcast/mastering-ci-cd/)
webcast to see a comprehensive demo of a GitLab CI/CD pipeline.
@@ -101,8 +101,8 @@ you can filter the pipeline list by:
- Trigger author
- Branch name
-- Status ([since GitLab 13.1](https://gitlab.com/gitlab-org/gitlab/-/issues/217617))
-- Tag ([since GitLab 13.1](https://gitlab.com/gitlab-org/gitlab/-/issues/217617))
+- Status ([GitLab 13.1 and later](https://gitlab.com/gitlab-org/gitlab/-/issues/217617))
+- Tag ([GitLab 13.1 and later](https://gitlab.com/gitlab-org/gitlab/-/issues/217617))
### Run a pipeline manually
@@ -114,7 +114,7 @@ operation of the pipeline.
To execute a pipeline manually:
1. Navigate to your project's **CI/CD > Pipelines**.
-1. Click on the **Run Pipeline** button.
+1. Select the **Run Pipeline** button.
1. On the **Run Pipeline** page:
1. Select the branch to run the pipeline for in the **Create for** field.
1. Enter any [environment variables](../variables/README.md) required for the pipeline run.
@@ -461,6 +461,28 @@ this line should be hidden when collapsed
section_end:1560896353:my_first_section\r\e[0K
```
+#### Pre-collapse sections
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/198413) in GitLab 13.5.
+
+You can make the job log automatically collapse collapsible sections by adding the `collapsed` option to the section start.
+Add `[collapsed=true]` after the section name and before the `\r`. The section end marker
+remains unchanged:
+
+- Section start marker with `[collapsed=true]`: `section_start:UNIX_TIMESTAMP:SECTION_NAME[collapsed=true]\r\e[0K` + `TEXT_OF_SECTION_HEADER`
+- Section end marker: `section_end:UNIX_TIMESTAMP:SECTION_NAME\r\e[0K`
+
+Add the updated section start text to the CI configuration. For example,
+using `echo`:
+
+```yaml
+job1:
+ script:
+ - echo -e "section_start:`date +%s`:my_first_section[collapsed=true]\r\e[0KHeader of the 1st collapsible section"
+ - echo 'this line should be hidden automatically after loading the job log'
+ - echo -e "section_end:`date +%s`:my_first_section\r\e[0K"
+```
+
## Visualize pipelines
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/5742) in GitLab 8.11.
@@ -473,7 +495,6 @@ and their statuses.
Pipeline graphs can be displayed in two different ways, depending on the page you
access the graph from.
-NOTE: **Note:**
GitLab capitalizes the stages' names in the pipeline graphs.
### Regular pipeline graphs
diff --git a/doc/ci/pipelines/job_artifacts.md b/doc/ci/pipelines/job_artifacts.md
index 750a76bfaa0..d904452a011 100644
--- a/doc/ci/pipelines/job_artifacts.md
+++ b/doc/ci/pipelines/job_artifacts.md
@@ -37,8 +37,8 @@ pdf:
expire_in: 1 week
```
-A job named `pdf` calls the `xelatex` command in order to build a PDF file from
-the latex source file `mycv.tex`. We then define the `artifacts` paths which in
+A job named `pdf` calls the `xelatex` command to build a PDF file from the
+latex source file `mycv.tex`. We then define the `artifacts` paths which in
turn are defined with the `paths` keyword. All paths to files and directories
are relative to the repository that was cloned during the build.
@@ -61,12 +61,10 @@ The `artifacts:reports` keyword is used for collecting test reports, code qualit
reports, and security reports from jobs. It also exposes these reports in GitLab's
UI (merge requests, pipeline views, and security dashboards).
-NOTE: **Note:**
The test reports are collected regardless of the job results (success or failure).
You can use [`artifacts:expire_in`](../yaml/README.md#artifactsexpire_in) to set up an expiration
date for their artifacts.
-NOTE: **Note:**
If you also want the ability to browse the report output files, include the
[`artifacts:paths`](../yaml/README.md#artifactspaths) keyword.
@@ -96,7 +94,6 @@ rspec:
The collected Unit test reports upload to GitLab as an artifact and display in merge requests.
-NOTE: **Note:**
If the JUnit tool you use exports to multiple XML files, specify
multiple test report paths within a single job to
concatenate them into a single file. Use a filename pattern (`junit: rspec-*.xml`),
@@ -343,6 +340,11 @@ The latest artifacts are created by jobs in the **most recent** successful pipel
for the specific ref. If you run two types of pipelines for the same ref, timing determines the latest
artifact. For example, if a merge request creates a branch pipeline at the same time as a scheduled pipeline, the pipeline that completed most recently creates the latest artifact.
+In [GitLab 13.5](https://gitlab.com/gitlab-org/gitlab/-/issues/201784) and later, artifacts
+for [parent and child pipelines](../parent_child_pipelines.md) are searched in hierarchical
+order from parent to child. For example, if both parent and child pipelines have a
+job with the same name, the artifact from the parent pipeline is returned.
+
Artifacts for other pipelines can be accessed with direct access to them.
The structure of the URL to download the whole artifacts archive is the following:
@@ -429,7 +431,20 @@ To erase a job:
## Retrieve artifacts of private projects when using GitLab CI
-In order to retrieve a job artifact of a different project, you might need to use a private token in order to [authenticate and download](../../api/job_artifacts.md#get-job-artifacts) the artifacts.
+To retrieve a job artifact from a different project, you might need to use a
+private token to [authenticate and download](../../api/job_artifacts.md#get-job-artifacts)
+the artifact.
+
+## Troubleshooting
+
+### Error message `No files to upload`
+
+This is often preceded by other errors or warnings that specify the filename and why it wasn't
+generated in the first place. Please check the entire job log for such messages.
+
+If you find no helpful messages, please retry the failed job after activating
+[CI debug logging](../variables/README.md#debug-logging).
+This provides useful information to investigate further.
<!-- ## Troubleshooting
diff --git a/doc/ci/pipelines/pipeline_artifacts.md b/doc/ci/pipelines/pipeline_artifacts.md
new file mode 100644
index 00000000000..8d70fff4e03
--- /dev/null
+++ b/doc/ci/pipelines/pipeline_artifacts.md
@@ -0,0 +1,18 @@
+---
+stage: Verify
+group: Continuous Integration
+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/#designated-technical-writers
+type: reference, howto
+---
+
+# Pipeline artifacts
+
+Pipeline artifacts are files created by GitLab after a pipeline finishes. These are different than [job artifacts](job_artifacts.md) because they are not explicitly managed by the `.gitlab-ci.yml` definitions.
+
+Pipeline artifacts are used by the [test coverage visualization feature](../../user/project/merge_requests/test_coverage_visualization.md) to collect coverage information. It uses the [`artifacts: reports`](../yaml/README.md#artifactsreports) CI/CD keyword.
+
+## Storage
+
+Pipeline artifacts are saved to disk or object storage. They count towards a project's [storage usage quota](../../user/group/index.md#storage-usage-quota). The **Artifacts** on the usage quote page is the sum of all job artifacts and pipeline artifacts.
+
+Pipeline artifacts are erased after one week.
diff --git a/doc/ci/pipelines/schedules.md b/doc/ci/pipelines/schedules.md
index e488179ffee..bcdb7c4c8b6 100644
--- a/doc/ci/pipelines/schedules.md
+++ b/doc/ci/pipelines/schedules.md
@@ -11,9 +11,6 @@ type: reference, howto
> - Introduced in GitLab 9.1 as [Trigger Schedule](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/10533).
> - [Renamed to Pipeline Schedule](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/10853) in GitLab 9.2.
-NOTE: **Note:**
-Cron notation is parsed by [Fugit](https://github.com/floraison/fugit).
-
Pipelines are normally run based on certain conditions being met. For example, when a branch is pushed to repository.
Pipeline schedules can be used to also run [pipelines](index.md) at specific intervals. For example:
@@ -24,6 +21,8 @@ Pipeline schedules can be used to also run [pipelines](index.md) at specific int
In addition to using the GitLab UI, pipeline schedules can be maintained using the
[Pipeline schedules API](../../api/pipeline_schedules.md).
+Schedule timing is configured with cron notation, parsed by [Fugit](https://github.com/floraison/fugit).
+
## Prerequisites
In order for a scheduled pipeline to be created successfully:
diff --git a/doc/ci/pipelines/settings.md b/doc/ci/pipelines/settings.md
index 849eb66d07f..143a5346e88 100644
--- a/doc/ci/pipelines/settings.md
+++ b/doc/ci/pipelines/settings.md
@@ -36,13 +36,11 @@ in `.gitlab-ci.yml`.
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/28919) in GitLab 12.0.
-NOTE: **Note:**
-As of GitLab 12.0, newly created projects will automatically have a default
-`git depth` value of `50`.
+It is possible to limit the number of changes that GitLab CI/CD fetches when cloning
+a repository. Setting a limit to `git depth` can speed up Pipelines execution.
-It is possible to limit the number of changes that GitLab CI/CD will fetch when cloning
-a repository. Setting a limit to `git depth` can speed up Pipelines execution. Maximum
-allowed value is `1000`.
+In GitLab 12.0 and later, newly created projects automatically have a default
+`git depth` value of `50`. The maximum allowed value is `1000`.
To disable shallow clone and make GitLab CI/CD fetch all branches and tags each time,
keep the value empty or set to `0`.
@@ -75,7 +73,7 @@ For information about setting a maximum artifact size for a project, see
> - [Support for external `.gitlab-ci.yml` locations](https://gitlab.com/gitlab-org/gitlab/-/issues/14376) introduced in GitLab 12.6.
By default we look for the `.gitlab-ci.yml` file in the project's root
-directory. If needed, you can specify an alternate path and file name, including locations outside the project.
+directory. If needed, you can specify an alternate path and filename, including locations outside the project.
To customize the path:
@@ -93,12 +91,12 @@ paths and file names include:
- `my/path/.gitlab-ci.yml`
- `my/path/.my-custom-file.yml`
-If the CI configuration will be hosted on an external site, the URL link must end with `.yml`:
+If hosting the CI configuration on an external site, the URL link must end with `.yml`:
- `http://example.com/generate/ci/config.yml`
-If the CI configuration will be hosted in a different project within GitLab, the path must be relative
-to the root directory in the other project, with the group and project name added to the end:
+If hosting the CI configuration in a different project within GitLab, the path must be relative
+to the root directory in the other project. Include the group and project name at the end:
- `.gitlab-ci.yml@mygroup/another-project`
- `my/path/.my-custom-file.yml@mygroup/another-project`
@@ -109,7 +107,7 @@ configuration file. For example:
- Create a public project to host the configuration file.
- Give write permissions on the project only to users who are allowed to edit the file.
-Other users and projects will be able to access the configuration file without being
+Other users and projects can access the configuration file without being
able to edit it.
## Test coverage parsing
@@ -125,8 +123,8 @@ can use <https://rubular.com> to test your regex. The regex returns the **last**
match found in the output.
If the pipeline succeeds, the coverage is shown in the merge request widget and
-in the jobs table. If multiple jobs in the pipeline have coverage reports, they will
-be averaged.
+in the jobs table. If multiple jobs in the pipeline have coverage reports, they are
+averaged.
![MR widget coverage](img/pipelines_test_coverage_mr_widget.png)
@@ -140,7 +138,7 @@ in the pipelines settings page.
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/209121) the ability to download a `.csv` in GitLab 12.10.
> - [Graph introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/33743) in GitLab 13.1.
-If you want to see the evolution of your project code coverage over time,
+To see the evolution of your project code coverage over time,
you can view a graph or download a CSV file with this data. From your project:
1. Go to **{chart}** **Project Analytics > Repository** to see the historic data for each job listed in the dropdown above the graph.
@@ -150,13 +148,13 @@ you can view a graph or download a CSV file with this data. From your project:
### Removing color codes
-Some test coverage tools output with ANSI color codes that won't be
-parsed correctly by the regular expression and will cause coverage
+Some test coverage tools output with ANSI color codes that aren't
+parsed correctly by the regular expression. This causes coverage
parsing to fail.
-If your coverage tool doesn't provide an option to disable color
-codes in the output, you can pipe the output of the coverage tool through a
-small one line script that will strip the color codes off.
+Some coverage tools don't provide an option to disable color
+codes in the output. If so, pipe the output of the coverage tool through a
+small one line script that strips the color codes off.
For example:
@@ -172,7 +170,7 @@ Pipeline visibility is determined by:
- The **Public pipelines** project setting under your project's **Settings > CI/CD > General pipelines**.
NOTE: **Note:**
-If the project visibility is set to **Private**, the [**Public pipelines** setting will have no effect](../enable_or_disable_ci.md#per-project-user-setting).
+If the project visibility is set to **Private**, the [**Public pipelines** setting has no effect](../enable_or_disable_ci.md#per-project-user-setting).
This also determines the visibility of these related features:
@@ -180,8 +178,7 @@ This also determines the visibility of these related features:
- Job artifacts
- The [pipeline security dashboard](../../user/application_security/security_dashboard/index.md#pipeline-security) **(ULTIMATE)**
-NOTE: **Note:**
-Currently, job logs and artifacts are [not yet visible for guest users and non-project members](https://gitlab.com/gitlab-org/gitlab/-/issues/25649).
+Job logs and artifacts are [not visible for guest users and non-project members](https://gitlab.com/gitlab-org/gitlab/-/issues/25649).
If **Public pipelines** is enabled (default):
@@ -204,16 +201,14 @@ If **Public pipelines** is disabled:
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/9362) in GitLab 9.1.
-If you want all pending non-HEAD pipelines on branches to auto-cancel each time
-a new pipeline is created, such as after a Git push or manually from the UI,
-you can enable this in the project settings:
+You can set pending or running pipelines to cancel automatically when a new pipeline runs on the same branch. You can enable this in the project settings:
1. Go to **Settings > CI / CD**.
1. Expand **General Pipelines**.
1. Check the **Auto-cancel redundant, pending pipelines** checkbox.
1. Click **Save changes**.
-Note that only jobs with [interruptible](../yaml/README.md#interruptible) set to `true` will be cancelled.
+Note that only jobs with [interruptible](../yaml/README.md#interruptible) set to `true` are cancelled.
## Skip outdated deployment jobs
@@ -232,18 +227,18 @@ To avoid this scenario:
1. Check the **Skip outdated deployment jobs** checkbox.
1. Click **Save changes**.
-The pending deployment jobs will be skipped.
+When enabled, any older deployments job are skipped when a new deployment starts.
For more information, see [Deployment safety](../environments/deployment_safety.md).
## Pipeline Badges
In the pipelines settings page you can find pipeline status and test coverage
-badges for your project. The latest successful pipeline will be used to read
+badges for your project. The latest successful pipeline is used to read
the pipeline status and test coverage values.
Visit the pipelines settings page in your project to see the exact link to
-your badges, as well as ways to embed the badge image in your HTML or Markdown
+your badges. You can also see ways to embed the badge image in your HTML or Markdown
pages.
![Pipelines badges](img/pipelines_settings_badges.png)
@@ -276,8 +271,8 @@ https://gitlab.example.com/<namespace>/<project>/badges/<branch>/pipeline.svg?ig
### Test coverage report badge
-GitLab makes it possible to define the regular expression for [coverage report](#test-coverage-parsing),
-that each job log will be matched against. This means that each job in the
+GitLab makes it possible to define the regular expression for the [coverage report](#test-coverage-parsing),
+that each job log is matched against. This means that each job in the
pipeline can have the test coverage percentage value defined.
The test coverage badge can be accessed using following link:
@@ -288,7 +283,7 @@ https://gitlab.example.com/<namespace>/<project>/badges/<branch>/coverage.svg
If you would like to get the coverage report from a specific job, you can add
the `job=coverage_job_name` parameter to the URL. For example, the following
-Markdown code will embed the test coverage report badge of the `coverage` job
+Markdown code embeds the test coverage report badge of the `coverage` job
into your `README.md`:
```markdown
@@ -297,7 +292,7 @@ into your `README.md`:
### Badge styles
-Pipeline badges can be rendered in different styles by adding the `style=style_name` parameter to the URL. Currently two styles are available:
+Pipeline badges can be rendered in different styles by adding the `style=style_name` parameter to the URL. Two styles are available:
#### Flat (default)
@@ -324,10 +319,10 @@ https://gitlab.example.com/<namespace>/<project>/badges/<branch>/coverage.svg?st
The text for a badge can be customized. This can be useful to differentiate between multiple coverage jobs that run in the same pipeline. Customize the badge text and width by adding the `key_text=custom_text` and `key_width=custom_key_width` parameters to the URL:
```plaintext
-https://gitlab.com/gitlab-org/gitlab/badges/master/coverage.svg?job=karma&key_text=Frontend+Coverage&key_width=100
+https://gitlab.com/gitlab-org/gitlab/badges/master/coverage.svg?job=karma&key_text=Frontend+Coverage&key_width=130
```
-![Badge with custom text and width](https://gitlab.com/gitlab-org/gitlab/badges/master/coverage.svg?job=karma&key_text=Frontend+Coverage&key_width=100)
+![Badge with custom text and width](https://gitlab.com/gitlab-org/gitlab/badges/master/coverage.svg?job=karma&key_text=Frontend+Coverage&key_width=130)
## Environment Variables
diff --git a/doc/ci/quick_start/README.md b/doc/ci/quick_start/README.md
index fa16614b0e0..246430a6458 100644
--- a/doc/ci/quick_start/README.md
+++ b/doc/ci/quick_start/README.md
@@ -68,11 +68,6 @@ blog about it](https://about.gitlab.com/blog/2015/05/06/why-were-replacing-gitla
### Creating a simple `.gitlab-ci.yml` file
-NOTE: **Note:**
-A GitLab team member has made an [unofficial visual pipeline editor](https://unofficial.gitlab.tools/visual-pipelines/).
-There is a [plan to make it an official part of GitLab](https://gitlab.com/groups/gitlab-org/-/epics/4069)
-in the future, but it's available for anyone who wants to try it at the above link.
-
You need to create a file named `.gitlab-ci.yml` in the root directory of your
repository. This is a [YAML](https://en.wikipedia.org/wiki/YAML) file
so you have to pay extra attention to indentation. Always use spaces, not tabs.
@@ -117,9 +112,17 @@ What is important is that each job is run independently from each other.
If you want to check whether the `.gitlab-ci.yml` of your project is valid, there is a
[CI Lint tool](../lint.md) available in every project.
+You can use the [CI/CD configuration visualization](../yaml/visualization.md) to
+see a graphical representation of your `.gitlab-ci.yml`.
+
For more information and a complete `.gitlab-ci.yml` syntax, please read
[the reference documentation on `.gitlab-ci.yml`](../yaml/README.md).
+TIP: **Tip:**
+A GitLab team member has made an [unofficial visual pipeline editor](https://unofficial.gitlab.tools/visual-pipelines/).
+There is a [plan to make it an official part of GitLab](https://gitlab.com/groups/gitlab-org/-/epics/4069)
+in the future, but it's available for anyone who wants to try it at the above link.
+
### Push `.gitlab-ci.yml` to GitLab
Once you've created `.gitlab-ci.yml`, you should add it to your Git repository
diff --git a/doc/ci/review_apps/img/toolbar_feeback_form.png b/doc/ci/review_apps/img/toolbar_feeback_form.png
deleted file mode 100644
index fe1c7e6e611..00000000000
--- a/doc/ci/review_apps/img/toolbar_feeback_form.png
+++ /dev/null
Binary files differ
diff --git a/doc/ci/review_apps/img/toolbar_feedback_form_v13_5.png b/doc/ci/review_apps/img/toolbar_feedback_form_v13_5.png
new file mode 100644
index 00000000000..dc4a13b2152
--- /dev/null
+++ b/doc/ci/review_apps/img/toolbar_feedback_form_v13_5.png
Binary files differ
diff --git a/doc/ci/review_apps/index.md b/doc/ci/review_apps/index.md
index e2d5cbcbea4..7110117709f 100644
--- a/doc/ci/review_apps/index.md
+++ b/doc/ci/review_apps/index.md
@@ -33,7 +33,7 @@ In the above example:
## 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.md) relevant to the branch.
+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.
@@ -188,20 +188,35 @@ Once you have the route mapping set up, it will take effect in the following loc
## Visual Reviews **(STARTER)**
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/10761) in GitLab Starter 12.0.
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/10761) in GitLab Starter 12.0.
+> - It's [deployed behind a feature flag](../../user/feature_flags.md), enabled by default.
+> - It's enabled on GitLab.com.
+> - For GitLab self-managed instances, GitLab administrators can opt to [disable it](#enable-or-disable-visual-reviews). **(STARTER ONLY)**
-With Visual Reviews, you can provide a feedback form to your Review Apps so
-that reviewers can post comments directly from the app back to the merge request
-that spawned the Review App.
+With Visual Reviews, members of any team (Product, Design, Quality, and so on) can provide feedback comments through a form in your review apps. The comments are added to the merge request that triggered the review app.
-### Configuring Visual Reviews
+### Using Visual Reviews
-Ensure that the `anonymous_visual_review_feedback` feature flag is enabled.
-Administrators can enable with a Rails console as follows:
+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.
-```ruby
-Feature.enable(:anonymous_visual_review_feedback)
-```
+![Visual review feedback form](img/toolbar_feedback_form_v13_5.png)
+
+To use the feedback form to make a comment in the merge request:
+
+1. Click the **Review** tab on the right side of a page.
+1. Make a comment on the visual review. You can make use of all the
+ [Markdown annotations](../../user/markdown.md) that are also available in
+ merge request comments.
+1. Enter your personal information:
+ - If [`data-require-auth`](#authentication-for-visual-reviews) is `true`, you must enter your [personal access token](../../user/profile/personal_access_tokens.md).
+ - Otherwise, enter your name, and optionally your email.
+1. Click **Send feedback**.
+
+<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
The feedback form is served through a script you add to pages in your Review App.
If you have [Developer permissions](../../user/permissions.md) to the project,
@@ -212,18 +227,18 @@ if [route maps](#route-maps) are configured in the project.
![review button](img/review_button.png)
The provided script should be added to the `<head>` of your application and
-consists of some project and merge request specific values. Here's what it
-looks like:
+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:
```html
<script
data-project-id='11790219'
data-merge-request-id='1'
- data-mr-url='https://gitlab.example.com'
+ data-mr-url='https://gitlab.com'
data-project-path='sarah/review-app-tester'
data-require-auth='true'
id='review-app-toolbar-script'
- src='https://gitlab.example.com/assets/webpack/visual_review_toolbar.js'>
+ src='https://gitlab.com/assets/webpack/visual_review_toolbar.js'>
</script>
```
@@ -239,21 +254,21 @@ to replace those values at runtime when each review app is created:
- `data-mr-url` is the URL of the GitLab instance and will be the same for all
review apps.
- `data-project-path` is the project's path, which can be found by `CI_PROJECT_PATH`.
-- `data-require-auth` is optional for public projects but required for [private and internal ones](#visual-reviews-in-private-or-internal-projects). If this is set to `true`, the user will be required to enter their [personal access token](../../user/profile/personal_access_tokens.md) instead of their name and email.
+- `data-require-auth` is optional for public projects but required for [private and internal ones](#authentication-for-visual-reviews). If this is set to `true`, the user will be required to enter their [personal access token](../../user/profile/personal_access_tokens.md) instead of their name and email.
- `id` is always `review-app-toolbar-script`, you don't need to change that.
- `src` is the source of the review toolbar script, which resides in the
respective GitLab instance and will be the same for all review apps.
-For example, in a Ruby application, you would need to have this script:
+For example, in a Ruby application with code hosted on in a project GitLab.com, you would need to have this script:
```html
<script
data-project-id="ENV['CI_PROJECT_ID']"
data-merge-request-id="ENV['CI_MERGE_REQUEST_IID']"
- data-mr-url='https://gitlab.example.com'
+ data-mr-url='https://gitlab.com'
data-project-path="ENV['CI_PROJECT_PATH']"
id='review-app-toolbar-script'
- src='https://gitlab.example.com/assets/webpack/visual_review_toolbar.js'>
+ src='https://gitlab.com/assets/webpack/visual_review_toolbar.js'>
</script>
```
@@ -273,33 +288,34 @@ can supply the ID by either:​​
- Dynamically adding the `data-merge-request-id` value during the build of the app.
- Supplying it manually through the visual review form in the app.
-### Visual Reviews in private or internal projects
+### Enable or disable Visual Reviews **(STARTER ONLY)**
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/42750#note_317271120) in GitLab 12.10.
+Visual Reviews is deployed behind a feature flag that is **enabled by default**.
+[GitLab administrators with access to the GitLab Rails console](../../administration/feature_flags.md)
+can opt to disable it.
-To enable visual reviews for private and internal projects, set the
-[`data-require-auth` variable](#configuring-visual-reviews) to `true`. When enabled,
-the user must enter a [personal access token](../../user/profile/personal_access_tokens.md)
-with `api` scope before submitting feedback.
+To disable it:
-### Using Visual Reviews
+```ruby
+Feature.disable(:anonymous_visual_review_feedback)
+```
-After Visual Reviews has been [enabled](#configuring-visual-reviews) for the
-Review App, the Visual Reviews feedback form is overlaid on the app's pages at
-the bottom-right corner.
+To enable it:
-![Visual review feedback form](img/toolbar_feeback_form.png)
+```ruby
+Feature.enable(:anonymous_visual_review_feedback)
+```
-To use the feedback form:
+### Authentication for Visual Reviews
-1. Make a comment on the visual review. You can make use of all the
- [Markdown annotations](../../user/markdown.md) that are also available in
- merge request comments.
-1. If `data-require-auth` is `true`, you must enter your [personal access token](../../user/profile/personal_access_tokens.md). Otherwise, you must enter your name, and optionally, your email.
-1. Finally, click **Send feedback**.
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/42750#note_317271120) in GitLab 12.10.
+
+To enable visual reviews for private and internal projects, set the
+[`data-require-auth` variable](#enable-or-disable-visual-reviews) to `true`. When enabled,
+the user must enter a [personal access token](../../user/profile/personal_access_tokens.md)
+with `api` scope before submitting feedback.
-After you make and submit a comment in the visual review box, it will appear
-automatically in the respective merge request.
+This same method can be used to require authentication for any public projects.
## Limitations
diff --git a/doc/ci/runners/README.md b/doc/ci/runners/README.md
index 32561e6b98c..a3cc46f59bf 100644
--- a/doc/ci/runners/README.md
+++ b/doc/ci/runners/README.md
@@ -18,16 +18,12 @@ Runners can be specific to certain projects or available to all projects.
## Types of runners
-There are three types of runners:
+In the GitLab UI there are three types of runners, based on who you want to have access:
-- [Shared](#shared-runners) (for all projects)
-- [Group](#group-runners) (for all projects in a group)
-- [Specific](#specific-runners) (for specific projects)
-
-If you are running self-managed GitLab, you can create your own runners.
-
-If you are using GitLab.com, you can use the shared runners provided by GitLab or
-create your own group or specific runners.
+- [Shared runners](#shared-runners) are available to all groups and projects in a GitLab instance.
+- [Group runners](#group-runners) are available to all projects and subgroups in a group.
+- [Specific runners](#specific-runners) are associated with specific projects.
+ Typically, specific runners are used for one project at a time.
### Shared runners
@@ -39,11 +35,10 @@ multiple projects.
If you are using a self-managed instance of GitLab:
-- Your administrator can install and register shared runners by viewing the instructions
- [here](https://docs.gitlab.com/runner/install/index.html).
+- Your administrator can install and register shared runners by [following the documentation](https://docs.gitlab.com/runner/install/index.html).
<!-- going to your project's
<!-- **Settings > CI / CD**, expanding the **Runners** section, and clicking **Show runner installation instructions**.-->
- <!-- These instructions are also available [here](https://docs.gitlab.com/runner/install/index.html).-->
+ <!-- These instructions are also available [in the documentation](https://docs.gitlab.com/runner/install/index.html).-->
- The administrator can also configure a maximum number of shared runner [pipeline minutes for
each group](../../user/admin_area/settings/continuous_integration.md#shared-runners-pipeline-minutes-quota).
@@ -123,21 +118,20 @@ To enable shared runners:
#### Disable shared runners
-You can disable shared runners for individual projects<!-- or for groups-->.
-You must have Owner permissions for the project<!-- or group-->.
+You can disable shared runners for individual projects or for groups.
+You must have Owner permissions for the project or group.
To disable shared runners for a project:
1. Go to the project's **Settings > CI/CD** and expand the **Runners** section.
1. In the **Shared runners** area, click **Disable shared runners**.
-<!--To disable shared runners for a group:
+To disable shared runners for a group:
1. Go to the group's **Settings > CI/CD** and expand the **Runners** section.
-1. In the **Shared runners** area, click **Disable shared runners globally**.
+1. In the **Shared runners** area, click **Enable shared runners for this group**.
1. Optionally, to allow shared runners to be enabled for individual projects or subgroups,
- click **Allow projects/subgroups to override the global setting**.
--->
+ click **Allow projects and subgroups to override the group setting**.
### Group runners
diff --git a/doc/ci/secrets/index.md b/doc/ci/secrets/index.md
index 6d561fe00a3..fb1183cd68b 100644
--- a/doc/ci/secrets/index.md
+++ b/doc/ci/secrets/index.md
@@ -17,23 +17,36 @@ Unlike CI variables, which are always presented to a job, secrets must be explic
required by a job. Read [GitLab CI/CD pipeline configuration reference](../yaml/README.md#secrets)
for more information about the syntax.
-GitLab has selected [Vault by Hashicorp](https://www.vaultproject.io) as the
+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)
as the first supported secrets engine.
GitLab authenticates using Vault's
-[JWT Auth method](https://www.vaultproject.io/docs/auth/jwt#jwt-authentication), using
+[JSON Web Token (JWT) authentication method](https://www.vaultproject.io/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.
You must [configure your Vault server](#configure-your-vault-server) before you
can use [use Vault secrets in a CI job](#use-vault-secrets-in-a-ci-job).
+The flow for using GitLab with HashiCorp Vault
+is summarized by this diagram:
+
+![Flow between GitLab and HashiCorp](../img/gitlab_vault_workflow_v13_4.png "How GitLab CI_JOB_JWT works with HashiCorp Vault")
+
+1. Configure your vault and secrets.
+1. Generate your JWT and provide it to your CI job.
+1. Runner contacts HashiCorp Vault and authenticates using the JWT.
+1. HashiCorp Vault verifies the JWT.
+1. HashiCorp Vault checks the bounded claims and attaches policies.
+1. HashiCorp Vault returns the token.
+1. Runner reads secrets from the HashiCorp Vault.
+
NOTE: **Note:**
-Read the [Authenticating and Reading Secrets With Hashicorp Vault](../examples/authenticating-with-hashicorp-vault/index.md)
-tutorial for a version of this feature that is available to all
+Read the [Authenticating and Reading Secrets With HashiCorp Vault](../examples/authenticating-with-hashicorp-vault/index.md)
+tutorial for a version of this feature. It's available to all
subscription levels, supports writing secrets to and deleting secrets from Vault,
-and multiple secrets engines.
+and supports multiple secrets engines.
## Configure your Vault server
@@ -90,7 +103,7 @@ the secrets stored in Vault by defining them with the `vault` keyword:
```yaml
secrets:
DATABASE_PASSWORD:
- vault: production/db/password@ops # translates to secret `ops/data/production/db`, field `password`
+ vault: production/db/password@ops # translates to secret `ops/data/production/db`, field `password`
```
In this example:
@@ -149,7 +162,7 @@ generated by this GitLab instance may be allowed to authenticate using this role
For a full list of `CI_JOB_JWT` claims, read the
[How it works](../examples/authenticating-with-hashicorp-vault/index.md#how-it-works) section of the
-[Authenticating and Reading Secrets With Hashicorp Vault](../examples/authenticating-with-hashicorp-vault/index.md) tutorial.
+[Authenticating and Reading Secrets With HashiCorp Vault](../examples/authenticating-with-hashicorp-vault/index.md) tutorial.
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
diff --git a/doc/ci/services/postgres.md b/doc/ci/services/postgres.md
index aadbce5a50a..96552ab1245 100644
--- a/doc/ci/services/postgres.md
+++ b/doc/ci/services/postgres.md
@@ -13,7 +13,7 @@ do this with the Docker and Shell executors of GitLab Runner.
## Use PostgreSQL with the Docker executor
-If you are using [GitLab Runner](../runners/README.md) with the Docker executor
+If you're using [GitLab Runner](../runners/README.md) with the Docker executor,
you basically have everything set up already.
First, in your `.gitlab-ci.yml` add:
@@ -29,12 +29,11 @@ variables:
POSTGRES_HOST_AUTH_METHOD: trust
```
-NOTE: **Note:**
-The `POSTGRES_DB`, `POSTGRES_USER`, `POSTGRES_PASSWORD` and `POSTGRES_HOST_AUTH_METHOD`
-variables can't be set in the GitLab UI. To set them, assign them to a variable
-[in the UI](../variables/README.md#create-a-custom-variable-in-the-ui), and then assign that
-variable to the `POSTGRES_DB`, `POSTGRES_USER`, `POSTGRES_PASSWORD` and `POSTGRES_HOST_AUTH_METHOD`
-variables in your `.gitlab-ci.yml`.
+To set values for the `POSTGRES_DB`, `POSTGRES_USER`,
+`POSTGRES_PASSWORD` and `POSTGRES_HOST_AUTH_METHOD`,
+[assign them to a variable in the user interface](../variables/README.md#create-a-custom-variable-in-the-ui),
+then assign that variable to the corresponding variable in your
+`.gitlab-ci.yml` file.
And then configure your application to use the database, for example:
@@ -45,14 +44,14 @@ Password: ''
Database: nice_marmot
```
-If you are wondering why we used `postgres` for the `Host`, read more at
+If you're wondering why we used `postgres` for the `Host`, read more at
[How services are linked to the job](../docker/using_docker_images.md#how-services-are-linked-to-the-job).
You can also use any other Docker image available on [Docker Hub](https://hub.docker.com/_/postgres).
-For example, to use PostgreSQL 9.3 the service becomes `postgres:9.3`.
+For example, to use PostgreSQL 9.3, the service becomes `postgres:9.3`.
-The `postgres` image can accept some environment variables. For more details
-check the documentation on [Docker Hub](https://hub.docker.com/_/postgres).
+The `postgres` image can accept some environment variables. For more details,
+see the documentation on [Docker Hub](https://hub.docker.com/_/postgres).
## Use PostgreSQL with the Shell executor
@@ -65,7 +64,7 @@ First install the PostgreSQL server:
sudo apt-get install -y postgresql postgresql-client libpq-dev
```
-The next step is to create a user, so login to PostgreSQL:
+The next step is to create a user, so sign in to PostgreSQL:
```shell
sudo -u postgres psql -d template1
@@ -74,24 +73,26 @@ sudo -u postgres psql -d template1
Then create a user (in our case `runner`) which will be used by your
application. Change `$password` in the command below to a real strong password.
-*__Note:__ Do not type `template1=#`, this is part of the PostgreSQL prompt.*
+NOTE: **Note:**
+Be sure to not enter `template1=#` in the following commands, as that's part of
+the PostgreSQL prompt.
```shell
template1=# CREATE USER runner WITH PASSWORD '$password' CREATEDB;
```
-*__Note:__ Notice that we created the user with the privilege to be able to
-create databases (`CREATEDB`). In the following steps we will create a database
-explicitly for that user but having that privilege can be useful if in your
-testing framework you have tools that drop and create databases.*
+The created user has the privilege to create databases (`CREATEDB`). The
+following steps describe how to create a database explicitly for that user, but
+having that privilege can be useful if in your testing framework you have tools
+that drop and create databases.
-Create the database and grant all privileges on it for the user `runner`:
+Create the database and grant all privileges to it for the user `runner`:
```shell
template1=# CREATE DATABASE nice_marmot OWNER runner;
```
-If all went well you can now quit the database session:
+If all went well, you can now quit the database session:
```shell
template1=# \q
@@ -104,8 +105,8 @@ check that everything is in place.
psql -U runner -h localhost -d nice_marmot -W
```
-*__Note:__ We are explicitly telling `psql` to connect to localhost in order
-to use the md5 authentication. If you omit this step you will be denied access.*
+This command explicitly directs `psql` to connect to localhost to use the md5
+authentication. If you omit this step, you'll be denied access.
Finally, configure your application to use the database, for example:
@@ -122,5 +123,5 @@ We have set up an [Example PostgreSQL Project](https://gitlab.com/gitlab-example
convenience that runs on [GitLab.com](https://gitlab.com) using our publicly
available [shared runners](../runners/README.md).
-Want to hack on it? Simply fork it, commit and push your changes. Within a few
+Want to hack on it? Fork it, commit, and push your changes. Within a few
moments the changes will be picked by a public runner and the job will begin.
diff --git a/doc/ci/ssh_keys/README.md b/doc/ci/ssh_keys/README.md
index d8280316f19..12478000a0a 100644
--- a/doc/ci/ssh_keys/README.md
+++ b/doc/ci/ssh_keys/README.md
@@ -36,7 +36,6 @@ with any type of [executor](https://docs.gitlab.com/runner/executors/)
`~/.ssh/authorized_keys`) or add it as a [deploy key](../../ssh/README.md#deploy-keys)
if you are accessing a private GitLab repository.
-NOTE: **Note:**
The private key will not be displayed in the job log, unless you enable
[debug logging](../variables/README.md#debug-logging). You might also want to
check the [visibility of your pipelines](../pipelines/settings.md#visibility-of-pipelines).
@@ -94,7 +93,6 @@ to access it. This is where an SSH key pair comes in handy.
# - git config --global user.name "User name"
```
- NOTE: **Note:**
The [`before_script`](../yaml/README.md#before_script-and-after_script) can be set globally
or per-job.
@@ -134,7 +132,8 @@ on, and use that key for all projects that are run on this machine.
If you are accessing a private GitLab repository you need to add it as a
[deploy key](../../ssh/README.md#deploy-keys).
-Once done, try to log in to the remote server in order to accept the fingerprint:
+After generating the key, try to sign in to the remote server to accept the
+fingerprint:
```shell
ssh example.com
@@ -163,7 +162,6 @@ ssh-keyscan 1.2.3.4
Create a new [variable](../variables/README.md#gitlab-cicd-environment-variables) with
`SSH_KNOWN_HOSTS` as "Key", and as a "Value" add the output of `ssh-keyscan`.
-NOTE: **Note:**
If you need to connect to multiple servers, all the server host keys
need to be collected in the **Value** of the variable, one key per line.
diff --git a/doc/ci/triggers/README.md b/doc/ci/triggers/README.md
index 2b006b8779b..bcd19f0de6f 100644
--- a/doc/ci/triggers/README.md
+++ b/doc/ci/triggers/README.md
@@ -95,9 +95,9 @@ Read more about the [jobs API](../../api/job_artifacts.md#download-the-artifacts
## Adding a new trigger
-You can add a new trigger by going to your project's
-**Settings âž” CI/CD** under **Triggers**. The **Add trigger** button will
-create a new token which you can then use to trigger a rerun of this
+Go to your
+**Settings âž” CI/CD** under **Triggers** to add a new trigger. The **Add trigger** button creates
+a new token which you can then use to trigger a rerun of this
particular project's pipeline.
Every new trigger you create, gets assigned a different token which you can
@@ -121,7 +121,7 @@ POST /projects/:id/trigger/pipeline
```
The required parameters are the [trigger's `token`](#authentication-tokens)
-and the Git `ref` on which the trigger will be performed. Valid refs are
+and the Git `ref` on which the trigger is performed. Valid refs are
branches or tags. The `:id` of a project can be found by
[querying the API](../../api/projects.md) or by visiting the **CI/CD**
settings page which provides self-explanatory examples.
@@ -146,7 +146,7 @@ curl --request POST \
https://gitlab.example.com/api/v4/projects/9/trigger/pipeline
```
-In this case, the project with ID `9` will get rebuilt on `master` branch.
+In this case, the project with ID `9` gets rebuilt on `master` branch.
Alternatively, you can pass the `token` and `ref` arguments in the query string:
@@ -169,9 +169,9 @@ build_docs:
- tags
```
-This means that whenever a new tag is pushed on project A, the job will run and the
-`build_docs` job will be executed, triggering a rebuild of project B. The
-`stage: deploy` ensures that this job will run only after all jobs with
+This means that whenever a new tag is pushed on project A, the job runs and the
+`build_docs` job is executed, triggering a rebuild of project B. The
+`stage: deploy` ensures that this job runs only after all jobs with
`stage: test` complete successfully.
## Triggering a pipeline from a webhook
@@ -183,14 +183,14 @@ webhook URL for Push and Tag events (change the project ID, ref and token):
https://gitlab.example.com/api/v4/projects/9/ref/master/trigger/pipeline?token=TOKEN
```
-`ref` should be passed as part of the URL in order to take precedence over
-`ref` from the webhook body that designates the branch ref that fired the
-trigger in the source repository. `ref` should be URL-encoded if it contains slashes.
+You should pass `ref` as part of the URL, to take precedence over `ref` from
+the webhook body that designates the branch ref that fired the trigger in the
+source repository. Be sure to URL-encode `ref` if it contains slashes.
## Making use of trigger variables
You can pass any number of arbitrary variables in the trigger API call and they
-will be available in GitLab CI/CD so that they can be used in your `.gitlab-ci.yml`
+are available in GitLab CI/CD so that they can be used in your `.gitlab-ci.yml`
file. The parameter is of the form:
```plaintext
@@ -237,7 +237,7 @@ upload_package:
```
You can then trigger a rebuild while you pass the `UPLOAD_TO_S3` variable
-and the script of the `upload_package` job will run:
+and the script of the `upload_package` job is run:
```shell
curl --request POST \
@@ -252,10 +252,6 @@ of all types of variables.
## Using cron to trigger nightly pipelines
-NOTE: **Note:**
-The following behavior can also be achieved through GitLab's UI with
-[pipeline schedules](../pipelines/schedules.md).
-
Whether you craft a script or just run cURL directly, you can trigger jobs
in conjunction with cron. The example below triggers a job on the `master`
branch of project with ID `9` every night at `00:30`:
@@ -264,9 +260,12 @@ branch of project with ID `9` every night at `00:30`:
30 0 * * * curl --request POST --form token=TOKEN --form ref=master https://gitlab.example.com/api/v4/projects/9/trigger/pipeline
```
+This behavior can also be achieved through GitLab's UI with
+[pipeline schedules](../pipelines/schedules.md).
+
## Legacy triggers
-Old triggers, created before GitLab 9.0 will be marked as legacy.
+Old triggers, created before GitLab 9.0 are marked as legacy.
Triggers with the legacy label do not have an associated user and only have
access to the current project. They are considered deprecated and will be
diff --git a/doc/ci/unit_test_reports.md b/doc/ci/unit_test_reports.md
index 5a59a175a89..b9c1809bf0d 100644
--- a/doc/ci/unit_test_reports.md
+++ b/doc/ci/unit_test_reports.md
@@ -10,8 +10,6 @@ type: reference
> - [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/45318) in GitLab 11.2. Requires GitLab Runner 11.2 and above.
> - [Renamed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/39737) from JUnit test reports to Unit test reports in GitLab 13.4.
-## Overview
-
It is very common that a [CI/CD pipeline](pipelines/index.md) contains a
test job that will verify your code.
If the tests fail, the pipeline fails and users get notified. The person that
@@ -20,12 +18,12 @@ tests failed so that they can fix them.
You can configure your job to use Unit test reports, and GitLab will display a
report on the merge request so that it's easier and faster to identify the
-failure without having to check the entire log. Unit test reports currently
+failure without having to check the entire log. Unit test reports currently
only support test reports in the JUnit report format.
-If you don't use Merge Requests but still want to see the unit test report
-output without searching through job logs, the full
-[Unit test reports](#viewing-unit-test-reports-on-gitlab) are available
+If you don't use Merge Requests but still want to see the unit test report
+output without searching through job logs, the full
+[Unit test reports](#viewing-unit-test-reports-on-gitlab) are available
in the pipeline detail view.
Consider the following workflow:
@@ -84,7 +82,6 @@ To make the Unit test report output files browsable, include them with the
To upload the report even if the job fails (for example if the tests do not pass), use the [`artifacts:when:always`](yaml/README.md#artifactswhen)
keyword.
-NOTE: **Note:**
You cannot have multiple tests with the same name and class in your JUnit report format XML file.
### Ruby example
@@ -146,8 +143,8 @@ java:
junit: build/test-results/test/**/TEST-*.xml
```
-NOTE: **Note:**
-Support for `**` was added in [GitLab Runner 13.0](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/2620).
+In [GitLab Runner 13.0](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/2620)
+and later, you can use `**`.
#### Maven
diff --git a/doc/ci/variables/README.md b/doc/ci/variables/README.md
index 1a982fa4e19..9c8fb994bf7 100644
--- a/doc/ci/variables/README.md
+++ b/doc/ci/variables/README.md
@@ -12,10 +12,11 @@ affect the way running processes behave on an operating
system.
Environment variables are part of the environment in which a process runs.
-For example, a running process can query the value of the
-`TEMP` environment variable to discover a suitable location
-to store temporary files, or to define a `URL` for a database
-that can be reused in different scripts.
+For example, a running process could:
+
+- Use the value of a `TEMP` environment variable to know the correct location
+ to store temporary files.
+- Use a `DATABASE_URL` variable for the URL to a database that can be reused in different scripts.
Variables are useful for customizing your jobs in GitLab CI/CD.
When you use variables, you don't have to hard-code values.
@@ -62,22 +63,6 @@ job `test_variable`, which is `test`:
![Output `$CI_JOB_STAGE`](img/ci_job_stage_output_example.png)
-As another example, let's say you're using your own GitLab
-instance and you want to know what domain your GitLab Pages are
-served under. You can call it by using the predefined
-variable `$CI_PAGES_DOMAIN` in your script:
-
-```yaml
-pages:
- script:
- - ...
- - echo $CI_PAGES_DOMAIN
-```
-
-For GitLab.com users, the output is `gitlab.io`. For your
-private instance, the output is whatever your sysadmin has
-defined.
-
## Custom environment variables
When you need a specific custom environment variable, you can
@@ -103,8 +88,8 @@ variables:
You can then call its value in your script:
```yaml
- script:
- - echo "$TEST"
+script:
+ - echo "$TEST"
```
For more details, see [`.gitlab-ci.yml` defined variables](#gitlab-ciyml-defined-variables).
@@ -181,8 +166,8 @@ You can use tools like [the AWS CLI](https://docs.aws.amazon.com/cli/latest/user
and [`kubectl`](https://kubernetes.io/docs/concepts/configuration/organize-cluster-access-kubeconfig/#the-kubeconfig-environment-variable)
to customize your configuration by using **File** type variables.
-In the past, a common pattern was to read the value of a CI variable, save it in a file, and then
-use the newly created file in your script:
+Previously, a common pattern was to read the value of a CI variable, save it in a file, and then
+use that file in your script:
```shell
# Read certificate stored in $KUBE_CA_PEM variable and save it in a new file
@@ -258,7 +243,7 @@ Some variables are listed in the UI so you can choose them more quickly.
| `AWS_DEFAULT_REGION` | Any | 12.10 |
| `AWS_SECRET_ACCESS_KEY` | Any | 12.10 |
-NOTE: **Note:**
+CAUTION: **Caution:**
When you store credentials, there are security implications. If you are using AWS keys,
for example, follow their [best practices](https://docs.aws.amazon.com/general/latest/gr/aws-access-keys-best-practices.html).
@@ -288,11 +273,11 @@ job_name:
### PowerShell
-To access environment variables in a **Windows PowerShell** environment, prefix
-the variable name with (`$env:`). For environment variables set by GitLab CI, including those set by [`variables`](https://gitlab.com/gitlab-org/gitlab/blob/master/doc/ci/yaml/README.md#variables)
-parameter, they can also be accessed by prefixing the variable name with (`$`)
-as of [GitLab Runner 1.0.0](https://gitlab.com/gitlab-org/gitlab-runner/-/commit/abc44bb158008cd3a49c0d8173717c38dadb29ae#47afd7e8f12afdb8f0246262488f24e6dd071a22).
-System set environment variables however must be accessed using (`$env:`).
+To access variables in a **Windows PowerShell** environment, including system set
+environment variables, prefix the variable name with (`$env:`). Environment variables
+set by GitLab CI can also be accessed by prefixing the variable name with (`$`) with
+[GitLab Runner 1.0.0](https://gitlab.com/gitlab-org/gitlab-runner/-/merge_requests/68)
+and later.
```yaml
job_name:
@@ -386,9 +371,6 @@ export GITLAB_USER_ID="42"
## `.gitlab-ci.yml` defined variables
-NOTE: **Note:**
-This feature requires GitLab Runner 0.5.0 or higher and GitLab 7.14 or higher.
-
You can add variables that are set in the build environment to `.gitlab-ci.yml`.
These variables are saved in the repository, and they
are meant to store non-sensitive project configuration, like `RAILS_ENV` or
@@ -428,10 +410,12 @@ script:
> Introduced in GitLab 9.4.
-You can define per-project or per-group variables
-that are set in the pipeline environment. Group-level variables are stored out of
-the repository (not in `.gitlab-ci.yml`) and are securely passed to GitLab Runner,
-which makes them available during a pipeline run. For Premium users who do **not** use an external key store or who use GitLab's [integration with HashiCorp Vault](../secrets/index.md), we recommend using group environment variables to store secrets like passwords, SSH keys, and credentials.
+You can define per-project or per-group variables that are set in the pipeline environment. Group-level variables are stored out of the repository (not in `.gitlab-ci.yml`). They are securely passed to GitLab Runner, which makes them available during a pipeline run.
+
+We recommend using group environment variables to store secrets (like passwords, SSH keys, and credentials) for Premium users who:
+
+- Do **not** use an external key store.
+- Use GitLab's [integration with HashiCorp Vault](../secrets/index.md).
Group-level variables can be added by:
@@ -452,8 +436,7 @@ Once you set them, they are available for all subsequent pipelines. Any group-le
Instance variables are useful for no longer needing to manually enter the same credentials repeatedly for all your projects. Instance-level variables are available to all projects and groups on the instance.
-NOTE: **Note:**
-The maximum number of instance-level variables is [planned to be 25](https://gitlab.com/gitlab-org/gitlab/-/issues/216097).
+In GitLab 13.1 and later, the [maximum number of instance-level variables is 25](https://gitlab.com/gitlab-org/gitlab/-/issues/216097).
You can define instance-level variables via the UI or [API](../../api/instance_level_ci_variables.md).
@@ -463,7 +446,7 @@ To add an instance-level variable:
1. Click the **Add variable** button, and fill in the details:
- **Key**: Must be one line, using only letters, numbers, or `_` (underscore), with no spaces.
- - **Value**: [Since GitLab 13.3](https://gitlab.com/gitlab-org/gitlab/-/issues/220028), 10,000 characters allowed. This is also bounded by the limits of the selected runner operating system. In GitLab 13.0 to 13.2, 700 characters allowed.
+ - **Value**: [In GitLab 13.3 and later](https://gitlab.com/gitlab-org/gitlab/-/issues/220028), 10,000 characters allowed. This is also bounded by the limits of the selected runner operating system. In GitLab 13.0 to 13.2, 700 characters allowed.
- **Type**: `File` or `Variable`.
- **Protect variable** (Optional): If selected, the variable is only available in pipelines that run on protected branches or tags.
- **Mask variable** (Optional): If selected, the variable's **Value** is not shown in job logs. The variable is not saved if the value does not meet the [masking requirements](#masked-variable-requirements).
@@ -566,12 +549,11 @@ variables take precedence over those defined in `.gitlab-ci.yml`.
Variable names are limited by the underlying shell used to execute scripts (see [available shells](https://docs.gitlab.com/runner/shells/index.html).
Each shell has its own unique set of reserved variable names.
-You also want to keep in mind the [scope of environment variables](where_variables_can_be_used.md) to ensure a variable is defined in the scope
-in which you wish to use it.
+Keep in mind the [scope of environment variables](where_variables_can_be_used.md) to ensure a variable is defined in the scope in which you wish to use it.
## Where variables can be used
-Click [here](where_variables_can_be_used.md) for a section that describes where and how the different types of variables can be used.
+[This section](where_variables_can_be_used.md) describes where and how the different types of variables can be used.
## Advanced use
@@ -609,8 +591,8 @@ then available as environment variables on the running application
container.
CAUTION: **Caution:**
-Variables with multi-line values are not currently supported due to
-limitations with the current Auto DevOps scripting environment.
+Variables with multi-line values are not supported due to
+limitations with the Auto DevOps scripting environment.
### Override a variable by manually running a pipeline
@@ -701,9 +683,10 @@ Examples:
- `$VARIABLE == ""`
- `$VARIABLE != ""` (introduced in GitLab 11.11)
-If you want to check whether a variable is defined, but is empty, you can
-simply compare it against an empty string, like `$VAR == ''` or non-empty
-string `$VARIABLE != ""`.
+To check if a variable is defined but empty, compare it to:
+
+- An empty string: `$VARIABLE == ''`
+- A non-empty string: `$VARIABLE != ""`
#### Comparing two variables
@@ -719,9 +702,8 @@ of these variables.
Example: `$STAGING`
-If you only want to create a job when there is some variable present,
-which means that it is defined and non-empty, you can simply use
-variable name as an expression, like `$STAGING`. If `$STAGING` variable
+To create a job when there is some variable present, meaning it is defined and non-empty,
+use the variable name as an expression, like `$STAGING`. If the `$STAGING` variable
is defined, and is non empty, expression evaluates to `true`.
`$STAGING` value needs to be a string, with length higher than zero.
Variable that contains only whitespace characters is not an empty variable.
@@ -785,7 +767,7 @@ Examples:
##### Enable or disable parenthesis support for variables **(CORE ONLY)**
-The feature is currently deployed behind a feature flag that is **enabled by default**.
+The feature is deployed behind a feature flag that is **enabled by default**.
[GitLab administrators with access to the GitLab Rails console](../../administration/feature_flags.md)
can opt to disable it for your instance.
@@ -820,8 +802,7 @@ NOTE: **Note:**
The available regular expression syntax is limited. See [related issue](https://gitlab.com/gitlab-org/gitlab/-/issues/35438)
for more details.
-If needed, you can use a test pipeline to determine whether a regular expression will
-work in a variable. The example below tests the `^mast.*` regular expression directly,
+If needed, you can use a test pipeline to determine whether a regular expression works in a variable. The example below tests the `^mast.*` regular expression directly,
as well as from within a variable:
```yaml
@@ -856,9 +837,7 @@ from being leaked into the log unless your script writes them to the screen.
If a job isn't working as expected, this can make the problem difficult to
investigate; in these cases, you can enable debug tracing in `.gitlab-ci.yml`.
-Available on GitLab Runner v1.7+, this feature enables the shell's execution
-log, resulting in a verbose job log listing all commands that were run,
-variables that were set, and so on.
+Available on GitLab Runner v1.7+, this feature enables the shell's execution log. This results in a verbose job log listing all commands that were run, variables that were set, and so on.
Before enabling this, you should ensure jobs are visible to
[team members only](../../user/permissions.md#project-features). You should
diff --git a/doc/ci/variables/deprecated_variables.md b/doc/ci/variables/deprecated_variables.md
index 94ec8439605..71e2b5b2e44 100644
--- a/doc/ci/variables/deprecated_variables.md
+++ b/doc/ci/variables/deprecated_variables.md
@@ -16,7 +16,6 @@ To follow conventions of naming across GitLab, and to further move away from the
`build` term and toward `job`, some [CI/CD environment variables](README.md#predefined-environment-variables) were renamed for GitLab 9.0
release.
-NOTE: **Note:**
Starting with GitLab 9.0, we have deprecated the `$CI_BUILD_*` variables. **You are
strongly advised to use the new variables as we will remove the old ones in
future GitLab releases.**
diff --git a/doc/ci/variables/predefined_variables.md b/doc/ci/variables/predefined_variables.md
index 915041b71a6..08aaacd2620 100644
--- a/doc/ci/variables/predefined_variables.md
+++ b/doc/ci/variables/predefined_variables.md
@@ -69,7 +69,8 @@ Kubernetes-specific environment variables are detailed in the
| `CI_JOB_MANUAL` | 8.12 | all | The flag to indicate that job was manually started |
| `CI_JOB_NAME` | 9.0 | 0.5 | The name of the job as defined in `.gitlab-ci.yml` |
| `CI_JOB_STAGE` | 9.0 | 0.5 | The name of the stage as defined in `.gitlab-ci.yml` |
-| `CI_JOB_TOKEN` | 9.0 | 1.2 | Token used for authenticating with the [GitLab Container Registry](../../user/packages/container_registry/index.md), downloading [dependent repositories](../../user/project/new_ci_build_permissions_model.md#dependent-repositories), and accessing [GitLab-managed Terraform state](../../user/infrastructure/index.md#gitlab-managed-terraform-state). |
+| `CI_JOB_STATUS` | all | 13.5 | The state of the job as each runner stage is executed. Use with [`after_script`](../yaml/README.md#before_script-and-after_script) where `CI_JOB_STATUS` can be either: `success`, `failed` or `canceled`. |
+| `CI_JOB_TOKEN` | 9.0 | 1.2 | Token used for authenticating with [a few API endpoints](../../api/README.md#gitlab-ci-job-token) and downloading [dependent repositories](../../user/project/new_ci_build_permissions_model.md#dependent-repositories). The token is valid as long as the job is running. |
| `CI_JOB_JWT` | 12.10 | all | RS256 JSON web token that can be used for authenticating with third party systems that support JWT authentication, for example [HashiCorp's Vault](../secrets/index.md). |
| `CI_JOB_URL` | 11.1 | 0.5 | Job details URL |
| `CI_KUBERNETES_ACTIVE` | 13.0 | all | Included with the value `true` only if the pipeline has a Kubernetes cluster available for deployments. Not included if no cluster is available. Can be used as an alternative to [`only:kubernetes`/`except:kubernetes`](../yaml/README.md#onlykubernetesexceptkubernetes) with [`rules:if`](../yaml/README.md#rulesif) |
@@ -104,7 +105,7 @@ Kubernetes-specific environment variables are detailed in the
| `CI_PROJECT_ID` | all | all | The unique ID of the current project that GitLab CI/CD uses internally |
| `CI_PROJECT_NAME` | 8.10 | 0.5 | The name of the directory for the project that is currently being built. For example, if the project URL is `gitlab.example.com/group-name/project-1`, the `CI_PROJECT_NAME` would be `project-1`. |
| `CI_PROJECT_NAMESPACE` | 8.10 | 0.5 | The project namespace (username or group name) that is currently being built |
-| `CI_PROJECT_ROOT_NAMESPACE` | 13.2 | 0.5 | The **root** project namespace (username or group name) that is currently being built. For example, if `CI_PROJECT_NAME` is `root-group/child-group/grandchild-group`, `CI_PROJECT_ROOT_NAMESPACE` would be `root-group`. |
+| `CI_PROJECT_ROOT_NAMESPACE` | 13.2 | 0.5 | The **root** project namespace (username or group name) that is currently being built. For example, if `CI_PROJECT_NAMESPACE` is `root-group/child-group/grandchild-group`, `CI_PROJECT_ROOT_NAMESPACE` would be `root-group`. |
| `CI_PROJECT_PATH` | 8.10 | 0.5 | The namespace with project name |
| `CI_PROJECT_PATH_SLUG` | 9.3 | all | `$CI_PROJECT_PATH` lowercased and with everything except `0-9` and `a-z` replaced with `-`. Use in URLs and domain names. |
| `CI_PROJECT_REPOSITORY_LANGUAGES` | 12.3 | all | Comma-separated, lowercased list of the languages used in the repository (e.g. `ruby,javascript,html,css`) |
diff --git a/doc/ci/variables/where_variables_can_be_used.md b/doc/ci/variables/where_variables_can_be_used.md
index 330b960ca9a..b4236ca34c2 100644
--- a/doc/ci/variables/where_variables_can_be_used.md
+++ b/doc/ci/variables/where_variables_can_be_used.md
@@ -38,15 +38,14 @@ There are two places defined variables can be used. On the:
### `config.toml` file
-NOTE: **Note:**
-You can read more about `config.toml` in the [GitLab Runner docs](https://docs.gitlab.com/runner/configuration/advanced-configuration.html).
-
| Definition | Can be expanded? | Description |
|:-------------------------------------|:-----------------|:---------------------------------------------------------------------------------------------------------------------------------------------|
| `runners.environment` | yes | The variable expansion is made by GitLab Runner's [internal variable expansion mechanism](#gitlab-runner-internal-variable-expansion-mechanism) |
| `runners.kubernetes.pod_labels` | yes | The Variable expansion is made by GitLab Runner's [internal variable expansion mechanism](#gitlab-runner-internal-variable-expansion-mechanism) |
| `runners.kubernetes.pod_annotations` | yes | The Variable expansion is made by GitLab Runner's [internal variable expansion mechanism](#gitlab-runner-internal-variable-expansion-mechanism) |
+You can read more about `config.toml` in the [GitLab Runner docs](https://docs.gitlab.com/runner/configuration/advanced-configuration.html).
+
## Expansion mechanisms
There are three expansion mechanisms:
@@ -104,10 +103,6 @@ These restrictions are because `after_script` scripts are executed in a
## Persisted variables
-NOTE: **Note:**
-Some of the persisted variables contain tokens and cannot be used by some definitions
-due to security reasons.
-
The following variables are known as "persisted":
- `CI_PIPELINE_ID`
@@ -130,6 +125,9 @@ They are:
- For definitions where the ["Expansion place"](#gitlab-ciyml-file) is GitLab.
- In the `only` and `except` [variables expressions](README.md#environment-variables-expressions).
+Some of the persisted variables contain tokens and cannot be used by some definitions
+due to security reasons.
+
## Variables with an environment scope
Variables defined with an environment scope are supported. Given that
diff --git a/doc/ci/yaml/README.md b/doc/ci/yaml/README.md
index 40df9c7c986..2e4ab68a0e8 100644
--- a/doc/ci/yaml/README.md
+++ b/doc/ci/yaml/README.md
@@ -33,11 +33,8 @@ We have complete examples of configuring pipelines:
> - <i class="fa fa-youtube-play youtube" aria-hidden="true"></i>&nbsp;Learn how [Verizon reduced rebuilds](https://about.gitlab.com/blog/2019/02/14/verizon-customer-story/)
> from 30 days to under 8 hours with GitLab.
-NOTE: **Note:**
If you have a [mirrored repository that GitLab pulls from](../../user/project/repository/repository_mirroring.md#pulling-from-a-remote-repository),
-you may need to enable pipeline triggering. Go to your project's
-
-**Settings > Repository > Pull from a remote repository > Trigger pipelines for mirror updates**.
+you may need to enable pipeline triggering. Go to your project's **Settings > Repository > Pull from a remote repository > Trigger pipelines for mirror updates**.
## Introduction
@@ -107,12 +104,12 @@ The following table lists available parameters for jobs:
| [`script`](#script) | Shell script that is executed by a runner. |
| [`after_script`](#before_script-and-after_script) | Override a set of commands that are executed after job. |
| [`allow_failure`](#allow_failure) | Allow job to fail. Failed job does not contribute to commit status. |
-| [`artifacts`](#artifacts) | List of files and directories to attach to a job on success. Also available: `artifacts:paths`, `artifacts:exclude`, `artifacts:expose_as`, `artifacts:name`, `artifacts:untracked`, `artifacts:when`, `artifacts:expire_in`, `artifacts:reports`. |
+| [`artifacts`](#artifacts) | List of files and directories to attach to a job on success. Also available: `artifacts:paths`, `artifacts:exclude`, `artifacts:expose_as`, `artifacts:name`, `artifacts:untracked`, `artifacts:when`, `artifacts:expire_in`, and `artifacts:reports`. |
| [`before_script`](#before_script-and-after_script) | Override a set of commands that are executed before job. |
-| [`cache`](#cache) | List of files that should be cached between subsequent runs. Also available: `cache:paths`, `cache:key`, `cache:untracked`, and `cache:policy`. |
+| [`cache`](#cache) | List of files that should be cached between subsequent runs. Also available: `cache:paths`, `cache:key`, `cache:untracked`, `cache:when`, and `cache:policy`. |
| [`coverage`](#coverage) | Code coverage settings for a given job. |
| [`dependencies`](#dependencies) | Restrict which artifacts are passed to a specific job by providing a list of jobs to fetch artifacts from. |
-| [`environment`](#environment) | Name of an environment to which the job deploys. Also available: `environment:name`, `environment:url`, `environment:on_stop`, `environment:auto_stop_in` and `environment:action`. |
+| [`environment`](#environment) | Name of an environment to which the job deploys. Also available: `environment:name`, `environment:url`, `environment:on_stop`, `environment:auto_stop_in`, and `environment:action`. |
| [`except`](#onlyexcept-basic) | Limit when jobs are not created. Also available: [`except:refs`, `except:kubernetes`, `except:variables`, and `except:changes`](#onlyexcept-advanced). |
| [`extends`](#extends) | Configuration entries that this job inherits from. |
| [`image`](#image) | Use Docker images. Also available: `image:name` and `image:entrypoint`. |
@@ -184,7 +181,7 @@ To enable or disable the inheritance of all `variables:` or `default:` parameter
- `variables: true` or `variables: false`
To inherit only a subset of `default:` parameters or `variables:`, specify what
-you wish to inherit, and any not listed will **not** be inherited. Use
+you wish to inherit. Anything not listed is **not** inherited. Use
one of the following formats:
```yaml
@@ -208,16 +205,16 @@ inherit:
In the example below:
- `rubocop`:
- - **will** inherit: Nothing.
+ - inherits: Nothing.
- `rspec`:
- - **will** inherit: the default `image` and the `WEBHOOK_URL` variable.
- - will **not** inherit: the default `before_script` and the `DOMAIN` variable.
+ - inherits: the default `image` and the `WEBHOOK_URL` variable.
+ - does **not** inherit: the default `before_script` and the `DOMAIN` variable.
- `capybara`:
- - **will** inherit: the default `before_script` and `image`.
- - will **not** inherit: the `DOMAIN` and `WEBHOOK_URL` variables.
+ - inherits: the default `before_script` and `image`.
+ - does **not** inherit: the `DOMAIN` and `WEBHOOK_URL` variables.
- `karma`:
- - **will** inherit: the default `image` and `before_script`, and the `DOMAIN` variable.
- - will **not** inherit: `WEBHOOK_URL` variable.
+ - inherits: the default `image` and `before_script`, and the `DOMAIN` variable.
+ - does **not** inherit: `WEBHOOK_URL` variable.
```yaml
default:
@@ -347,23 +344,23 @@ workflow:
This example never allows pipelines for schedules or `push` (branches and tags) pipelines,
but does allow pipelines in **all** other cases, *including* merge request pipelines.
-As with `rules` defined in jobs, be careful not to use a configuration that allows
-merge request pipelines and branch pipelines to run at the same time, or you could
-have [duplicate pipelines](#prevent-duplicate-pipelines).
+Be careful not to use a configuration that might run
+merge request pipelines and branch pipelines at the same time. As with `rules` defined in jobs,
+it can cause [duplicate pipelines](#prevent-duplicate-pipelines).
#### `workflow:rules` templates
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/217732) in GitLab 13.0.
-We provide pre-made templates for use with your pipelines that set up `workflow: rules`
-for common scenarios. Usage of these will make things easier and prevent duplicate pipelines from running.
+We provide templates that set up `workflow: rules`
+for common scenarios. These templates help prevent duplicate pipelines.
The [`Branch-Pipelines` template](https://gitlab.com/gitlab-org/gitlab/-/tree/master/lib/gitlab/ci/templates/Workflows/Branch-Pipelines.gitlab-ci.yml)
makes your pipelines run for branches and tags.
-Branch pipeline status will be displayed within merge requests that use that branch
-as a source, but this pipeline type does not support any features offered by
-[Merge Request Pipelines](../merge_request_pipelines/) like
+Branch pipeline status is displayed within merge requests that use the branch
+as a source. However, this pipeline type does not support any features offered by
+[Merge Request Pipelines](../merge_request_pipelines/), like
[Pipelines for Merge Results](../merge_request_pipelines/#pipelines-for-merged-results)
or [Merge Trains](../merge_request_pipelines/pipelines_for_merged_results/merge_trains/).
Use this template if you are intentionally avoiding those features.
@@ -391,7 +388,7 @@ include:
### `include`
> - Introduced in [GitLab Premium](https://about.gitlab.com/pricing/) 10.5.
-> - Available for Starter, Premium and Ultimate since 10.6.
+> - Available for Starter, Premium, and Ultimate in GitLab 10.6 and later.
> - [Moved](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/42861) to GitLab Core in 11.4.
Using the `include` keyword allows the inclusion of external YAML files. This helps
@@ -402,6 +399,10 @@ configuration files. This helps avoid duplicated configuration, for example, glo
`include` requires the external YAML file to have the extensions `.yml` or `.yaml`,
otherwise the external file is not included.
+Using [YAML anchors](#anchors) across different YAML files sourced by `include` is not
+supported. You must only refer to anchors in the same file. Instead
+of using YAML anchors, you can use the [`extends` keyword](#extends).
+
`include` supports the following inclusion methods:
| Method | Description |
@@ -413,7 +414,6 @@ otherwise the external file is not included.
The `include` methods do not support [variable expansion](../variables/where_variables_can_be_used.md#variables-usage).
-NOTE: **Note:**
`.gitlab-ci.yml` configuration included by all methods is evaluated at pipeline creation.
The configuration is a snapshot in time and persisted in the database. Any changes to
referenced `.gitlab-ci.yml` configuration is not reflected in GitLab until the next pipeline is created.
@@ -428,11 +428,6 @@ TIP: **Tip:**
Use merging to customize and override included CI/CD configurations with local
definitions. Local definitions in `.gitlab-ci.yml` override included definitions.
-NOTE: **Note:**
-Using [YAML anchors](#anchors) across different YAML files sourced by `include` is not
-supported. You must only refer to anchors in the same file. Instead
-of using YAML anchors, you can use the [`extends` keyword](#extends).
-
#### `include:local`
`include:local` includes a file from the same repository as `.gitlab-ci.yml`.
@@ -442,12 +437,11 @@ You can only use files that are tracked by Git on the same branch
your configuration file is on. In other words, when using a `include:local`, make
sure that both `.gitlab-ci.yml` and the local file are on the same branch.
+Including local files through Git submodules paths is not supported.
+
All [nested includes](#nested-includes) are executed in the scope of the same project,
so it's possible to use local, project, remote, or template includes.
-NOTE: **Note:**
-Including local files through Git submodules paths is not supported.
-
Example:
```yaml
@@ -455,7 +449,6 @@ include:
- local: '/templates/.gitlab-ci-template.yml'
```
-TIP: **Tip:**
Local includes can be used as a replacement for symbolic links that are not followed.
This can be defined as a short local include:
@@ -495,8 +488,8 @@ include:
file: '/templates/.gitlab-ci-template.yml'
```
-All [nested includes](#nested-includes) are executed in the scope of the target project,
-so it's possible to use local (relative to target project), project, remote
+All [nested includes](#nested-includes) are executed in the scope of the target project.
+This means you can use local (relative to target project), project, remote,
or template includes.
#### `include:remote`
@@ -548,7 +541,7 @@ Nested includes allow you to compose a set of includes.
A total of 100 includes is allowed, but duplicate includes are considered a configuration error.
-Since [GitLab 12.4](https://gitlab.com/gitlab-org/gitlab/-/issues/28212), the time limit
+In [GitLab 12.4](https://gitlab.com/gitlab-org/gitlab/-/issues/28212) and later, the time limit
for resolving all files is 30 seconds.
#### Additional `includes` examples
@@ -635,10 +628,9 @@ job:
- bundle exec rspec
```
-NOTE: **Note:**
Sometimes, `script` commands must be wrapped in single or double quotes.
-For example, commands that contain a colon (`:`) must be wrapped in quotes so
-that the YAML parser knows to interpret the whole thing as a string rather than
+For example, commands that contain a colon (`:`) must be wrapped in quotes.
+The YAML parser needs to interpret the text as a string rather than
a "key: value" pair. Be careful when using special characters:
`:`, `{`, `}`, `[`, `]`, `,`, `&`, `*`, `#`, `?`, `|`, `-`, `<`, `>`, `=`, `!`, `%`, `@`, `` ` ``.
@@ -657,15 +649,18 @@ job:
> Introduced in GitLab 8.7 and requires GitLab Runner v1.2.
-`before_script` is used to define a command that should be run before each
+`before_script` is used to define commands that should be run before each
job, including deploy jobs, but after the restoration of any [artifacts](#artifacts).
This must be an array.
Scripts specified in `before_script` are concatenated with any scripts specified
in the main [`script`](#script), and executed together in a single shell.
-`after_script` is used to define the command that runs after each
-job, including failed ones. This must be an array.
+`after_script` is used to define commands that run after each
+job, including failed jobs. This must be an array. If a job times out or is cancelled,
+the `after_script` commands are not executed. Support for executing `after_script`
+commands for timed-out or cancelled jobs
+[is planned](https://gitlab.com/gitlab-org/gitlab/-/issues/15603).
Scripts specified in `after_script` are executed in a new shell, separate from any
`before_script` or `script` scripts. As a result, they:
@@ -744,11 +739,11 @@ using [`|` (literal) and `>` (folded) YAML multi-line block scalar indicators](h
CAUTION: **Warning:**
If multiple commands are combined into one command string, only the last command's
-failure or success is reported,
-[incorrectly ignoring failures from earlier commands due to a bug](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/25394).
-If the success of the job depends on the success or failure of these commands,
-you can run the commands as separate `script:` items, or add `exit 1` commands
-as appropriate to the command string where needed.
+failure or success is reported.
+[Failures from earlier commands are ignored due to a bug](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/25394).
+To work around this,
+run each command as a separate `script:` item, or add an `exit 1` command
+to each command string.
You can use the `|` (literal) YAML multiline block scalar indicator to write
commands over multiple lines in the `script` section of a job description.
@@ -808,7 +803,7 @@ Second command line.
```
When you omit the `>` or `|` block scalar indicators, GitLab forms the command
-by concatenating non-empty lines, so make sure the lines can run when concatenated.
+by concatenating non-empty lines. Make sure the lines can run when concatenated.
Shell [here documents](https://en.wikipedia.org/wiki/Here_document) work with the
`|` and `>` operators as well. The example below transliterates the lower case letters
@@ -895,6 +890,8 @@ The following stages are available to every pipeline:
User-defined stages are executed after `.pre` and before `.post`.
+A pipeline is not created if all jobs are in `.pre` or `.post` stages.
+
The order of `.pre` and `.post` can't be changed, even if defined out of order in `.gitlab-ci.yml`.
For example, the following are equivalent configuration:
@@ -926,9 +923,6 @@ For example, the following are equivalent configuration:
- b
```
-NOTE: **Note:**
-A pipeline is not created if all jobs are in `.pre` or `.post` stages.
-
### `extends`
> Introduced in GitLab 11.3.
@@ -961,7 +955,7 @@ GitLab performs a reverse deep merge based on the keys. GitLab:
- Merges the `rspec` contents into `.tests` recursively.
- Doesn't merge the values of the keys.
-The result is this `rspec` job:
+The result is this `rspec` job, where `script: rake test` is overwritten by `script: rake rspec`:
```yaml
rspec:
@@ -974,9 +968,6 @@ rspec:
- $RSPEC
```
-NOTE: **Note:**
-Note that `script: rake test` has been overwritten by `script: rake rspec`.
-
If you do want to include the `rake test`, see [`before_script` and `after_script`](#before_script-and-after_script).
`.tests` in this example is a [hidden job](#hide-jobs), but it's
@@ -1113,7 +1104,6 @@ is either included or excluded from the pipeline, depending on the configuration
If included, the job also has [certain attributes](#rules-attributes)
added to it.
-CAUTION: **Caution:**
`rules` replaces [`only/except`](#onlyexcept-basic) and can't be used in conjunction with it.
If you attempt to use both keywords in the same job, the linter returns a
`key may not be used with rules` error.
@@ -1500,9 +1490,8 @@ job:
- spec/**.rb
```
-NOTE: **Note:**
-For performance reasons, using `exists` with patterns is limited to 10000
-checks. After the 10000th check, rules with patterned globs always match.
+For performance reasons, using `exists` with patterns is limited to 10,000
+checks. After the 10,000th check, rules with patterned globs always match.
#### `rules:allow_failure`
@@ -1543,15 +1532,15 @@ docker build:
script: docker build -t my-image:$CI_COMMIT_REF_SLUG .
rules:
- if: '$VAR == "string value"'
- changes: # Will include the job and set to when:manual if any of the follow paths match a modified file.
+ changes: # Include the job and set to when:manual if any of the follow paths match a modified file.
- Dockerfile
- docker/scripts/*
when: manual
- # - when: never would be redundant here, this is implied any time rules are listed.
+ # - when: never would be redundant here, this is implied any time rules are listed.
```
-Keywords such as `branches` or `refs` that are currently available for
-`only`/`except` are not yet available in `rules` as they are being individually
+Keywords such as `branches` or `refs` that are available for
+`only`/`except` are not available in `rules`. They are being individually
considered for their usage and behavior in this context. Future keyword improvements
are being discussed in our [epic for improving `rules`](https://gitlab.com/groups/gitlab-org/-/epics/2783),
where anyone can add suggestions or requests.
@@ -1567,10 +1556,9 @@ job1:
if: ($CI_COMMIT_BRANCH == "master" || $CI_COMMIT_BRANCH == "develop") && $MY_VARIABLE
```
-NOTE: **Note:**
-In GitLab 13.2 and older, the order of operations when mixing `||` and `&&` in a single rule may not have executed
-in the expected order. This is [fixed](https://gitlab.com/gitlab-org/gitlab/-/issues/230938)
-in GitLab 13.3.
+CAUTION: **Caution:**
+[Before GitLab 13.3](https://gitlab.com/gitlab-org/gitlab/-/issues/230938),
+rules that use both `||` and `&&` may evaluate with an unexpected order of operations.
### `only`/`except` (basic)
@@ -1611,8 +1599,8 @@ In addition, `only` and `except` allow the use of special keywords:
| `triggers` | For pipelines created by using a [trigger token](../triggers/README.md#trigger-token). |
| `web` | For pipelines created by using **Run pipeline** button in the GitLab UI, from the project's **CI/CD > Pipelines** section. |
-In the example below, `job` will run only for refs that start with `issue-`,
-whereas all branches will be skipped:
+In the example below, `job` runs only for refs that start with `issue-`,
+whereas all branches are skipped:
```yaml
job:
@@ -1637,8 +1625,8 @@ job:
- branches
```
-In this example, `job` will run only for refs that are tagged, or if a build is
-explicitly requested via an API trigger or a [Pipeline Schedule](../pipelines/schedules.md):
+In this example, `job` runs only for refs that are tagged, or if a build is
+explicitly requested by an API trigger or a [Pipeline Schedule](../pipelines/schedules.md):
```yaml
job:
@@ -1684,19 +1672,19 @@ job:
#### Regular expressions
-Because `@` is used to denote the beginning of a ref's repository path,
-matching a ref name containing the `@` character in a regular expression
-requires the use of the hex character code match `\x40`.
+The `@` symbol denotes the beginning of a ref's repository path.
+To match a ref name that contains the `@` character in a regular expression,
+you must use the hex character code match `\x40`.
Only the tag or branch name can be matched by a regular expression.
The repository path, if given, is always matched literally.
-If a regular expression shall be used to match the tag or branch name,
-the entire ref name part of the pattern has to be a regular expression,
-and must be surrounded by `/`.
-(With regular expression flags appended after the closing `/`.)
-So `issue-/.*/` won't work to match all tag names or branch names
-that begin with `issue-`.
+To match the tag or branch name,
+the entire ref name part of the pattern must be a regular expression surrounded by `/`.
+For example, you can't use `issue-/.*/` to match all tag names or branch names
+that begin with `issue-`, but you can use `/issue-.*/`.
+
+Regular expression flags must be appended after the closing `/`.
TIP: **Tip:**
Use anchors `^` and `$` to avoid the regular expression
@@ -1706,20 +1694,17 @@ while just `/issue/` would also match a branch called `severe-issues`.
#### Supported `only`/`except` regexp syntax
-CAUTION: **Warning:**
-This is a breaking change that was introduced with GitLab 11.9.4.
-
-In GitLab 11.9.4, GitLab begun internally converting regexp used
+In GitLab 11.9.4, GitLab began internally converting the regexp used
in `only` and `except` parameters to [RE2](https://github.com/google/re2/wiki/Syntax).
-This means that only subset of features provided by [Ruby Regexp](https://ruby-doc.org/core/Regexp.html)
-is supported. [RE2](https://github.com/google/re2/wiki/Syntax) limits the set of features
-provided due to computational complexity, which means some features became unavailable in GitLab 11.9.4.
-For example, negative lookaheads.
+[RE2](https://github.com/google/re2/wiki/Syntax) limits the set of available features
+due to computational complexity, and some features, like negative lookaheads, became unavailable.
+Only a subset of features provided by [Ruby Regexp](https://ruby-doc.org/core/Regexp.html)
+are now supported.
-For GitLab versions from 11.9.7 and up to GitLab 12.0, GitLab provides a feature flag that can be
-enabled by administrators that allows users to use unsafe regexp syntax. This brings compatibility
-with previously allowed syntax version and allows users to gracefully migrate to the new syntax.
+From GitLab 11.9.7 to GitLab 12.0, GitLab provided a feature flag to
+let you use the unsafe regexp syntax. This flag allowed
+compatibility with the previous syntax version so you could gracefully migrate to the new syntax.
```ruby
Feature.enable(:allow_unsafe_ruby_regexp)
@@ -1727,10 +1712,6 @@ Feature.enable(:allow_unsafe_ruby_regexp)
### `only`/`except` (advanced)
-CAUTION: **Warning:**
-This is an _alpha_ feature, and is subject to change at any time without
-prior notice!
-
GitLab supports both simple and complex strategies, so it's possible to use an
array and a hash configuration scheme.
@@ -1741,7 +1722,7 @@ Four keys are available:
- `changes`
- `kubernetes`
-If you use multiple keys under `only` or `except`, the keys will be evaluated as a
+If you use multiple keys under `only` or `except`, the keys are evaluated as a
single conjoined expression. That is:
- `only:` includes the job if **all** of the keys have at least one condition that matches.
@@ -1752,9 +1733,9 @@ the pipeline if the following is true:
- `(any listed refs are true) AND (any listed variables are true) AND (any listed changes are true) AND (any chosen Kubernetes status matches)`
-In the example below, the `test` job will `only` be created when **all** of the following are true:
+In the example below, the `test` job is `only` created when **all** of the following are true:
-- The pipeline has been [scheduled](../../user/project/pipelines/schedules.md) **or** runs for `master`.
+- The pipeline has been [scheduled](../pipelines/schedules.md) **or** runs for `master`.
- The `variables` keyword matches.
- The `kubernetes` service is active on the project.
@@ -1775,7 +1756,7 @@ added if the following is true:
- `(any listed refs are true) OR (any listed variables are true) OR (any listed changes are true) OR (a chosen Kubernetes status matches)`
-In the example below, the `test` job will **not** be created when **any** of the following are true:
+In the example below, the `test` job is **not** created when **any** of the following are true:
- The pipeline runs for the `master` branch.
- There are changes to the `README.md` file in the root directory of the repository.
@@ -1797,8 +1778,8 @@ test:
The `refs` strategy can take the same values as the
[simplified only/except configuration](#onlyexcept-basic).
-In the example below, the `deploy` job is going to be created only when the
-pipeline has been [scheduled](../pipelines/schedules.md) or runs for the `master` branch:
+In the example below, the `deploy` job is created only when the
+pipeline is [scheduled](../pipelines/schedules.md) or runs for the `master` branch:
```yaml
deploy:
@@ -1814,7 +1795,7 @@ deploy:
The `kubernetes` strategy accepts only the `active` keyword.
-In the example below, the `deploy` job is going to be created only when the
+In the example below, the `deploy` job is created only when the
Kubernetes service is active in the project:
```yaml
@@ -1827,12 +1808,11 @@ deploy:
> `variables` policy introduced in GitLab 10.7.
-The `variables` keyword is used to define variables expressions. In other words,
-you can use predefined variables / project / group or
-environment-scoped variables to define an expression GitLab is going to
-evaluate in order to decide whether a job should be created or not.
+The `variables` keyword defines variable expressions.
+
+These expressions determine whether or not a job should be created.
-Examples of using variables expressions:
+Examples of using variable expressions:
```yaml
deploy:
@@ -1902,22 +1882,21 @@ docker build:
- more_scripts/*.{rb,py,sh}
```
-In the scenario above, when pushing commits to an existing branch in GitLab,
-it creates and triggers the `docker build` job, provided that one of the
-commits contains changes to any of the following:
+When you push commits to an existing branch,
+the `docker build` job is created, but only if changes were made to any of the following:
- The `Dockerfile` file.
-- Any of the files inside `docker/scripts/` directory.
-- Any of the files and subdirectories inside the `dockerfiles` directory.
-- Any of the files with `rb`, `py`, `sh` extensions inside the `more_scripts` directory.
+- Any of the files in the `docker/scripts/` directory.
+- Any of the files and subdirectories in the `dockerfiles` directory.
+- Any of the files with `rb`, `py`, `sh` extensions in the `more_scripts` directory.
CAUTION: **Warning:**
-If using `only:changes` with [only allow merge requests to be merged if the pipeline succeeds](../../user/project/merge_requests/merge_when_pipeline_succeeds.md#only-allow-merge-requests-to-be-merged-if-the-pipeline-succeeds),
-undesired behavior could result if you don't [also use `only:merge_requests`](#using-onlychanges-with-pipelines-for-merge-requests).
+If you use `only:changes` with [only allow merge requests to be merged if the pipeline succeeds](../../user/project/merge_requests/merge_when_pipeline_succeeds.md#only-allow-merge-requests-to-be-merged-if-the-pipeline-succeeds),
+you should [also use `only:merge_requests`](#using-onlychanges-with-pipelines-for-merge-requests). Otherwise it may not work as expected.
You can also use glob patterns to match multiple files in either the root directory
-of the repository, or in _any_ directory within the repository, but they must be wrapped
-in double quotes or GitLab will fail to parse the `.gitlab-ci.yml`. For example:
+of the repository, or in _any_ directory within the repository. However, they must be wrapped
+in double quotes or GitLab can't parse them. For example:
```yaml
test:
@@ -1930,10 +1909,8 @@ test:
- "**/*.sql"
```
-The following example will skip the `build` job if a change is detected in any file
-in the root directory of the repository with a `.md` extension. This mean that if you change multiple files,
-but only one file is a `.md` file, the `build` job will still be skipped and will
-not run for the other files.
+You can skip a job if a change is detected in any file with a
+`.md` extension in the root directory of the repository:
```yaml
build:
@@ -1943,13 +1920,13 @@ build:
- "*.md"
```
-CAUTION: **Warning:**
-There are some points to be aware of when
-[using this feature with new branches or tags *without* pipelines for merge requests](#using-onlychanges-without-pipelines-for-merge-requests).
+If you change multiple files, but only one file ends in `.md`,
+the `build` job is still skipped. The job does not run for any of the files.
-CAUTION: **Warning:**
-There are some points to be aware of when
-[using this feature with scheduled pipelines](#using-onlychanges-with-scheduled-pipelines).
+Read more about how to use this feature with:
+
+- [New branches or tags *without* pipelines for merge requests](#using-onlychanges-without-pipelines-for-merge-requests).
+- [Scheduled pipelines](#using-onlychanges-with-scheduled-pipelines).
##### Using `only:changes` with pipelines for merge requests
@@ -1957,7 +1934,7 @@ With [pipelines for merge requests](../merge_request_pipelines/index.md),
it's possible to define a job to be created based on files modified
in a merge request.
-In order to deduce the correct base SHA of the source branch, we recommend combining
+To deduce the correct base SHA of the source branch, we recommend combining
this keyword with `only: [merge_requests]`. This way, file differences are correctly
calculated from any further commits, thus all changes in the merge requests are properly
tested in pipelines.
@@ -1975,13 +1952,9 @@ docker build service one:
- service-one/**/*
```
-In the scenario above, if a merge request is created or updated that changes
-either files in `service-one` directory or the `Dockerfile`, GitLab creates
-and triggers the `docker build service one` job.
-
-Note that if [pipelines for merge requests](../merge_request_pipelines/index.md) is
-combined with `only: [change]`, but `only: [merge_requests]` is omitted, there could be
-unwanted behavior.
+In this scenario, if a merge request changes
+files in the `service-one` directory or the `Dockerfile`, GitLab creates
+the `docker build service one` job.
For example:
@@ -1994,15 +1967,17 @@ docker build service one:
- service-one/**/*
```
-In the example above, a pipeline could fail due to changes to a file in `service-one/**/*`.
-A later commit could then be pushed that does not include any changes to this file,
-but includes changes to the `Dockerfile`, and this pipeline could pass because it's only
-testing the changes to the `Dockerfile`. GitLab checks the **most recent pipeline**,
-that **passed**, and will show the merge request as mergeable, despite the earlier
-failed pipeline caused by a change that was not yet corrected.
+In the example above, the pipeline might fail because of changes to a file in `service-one/**/*`.
+
+A later commit that doesn't have changes in `service-one/**/*`
+but does have changes to the `Dockerfile` can pass. The job
+only tests the changes to the `Dockerfile`.
-With this configuration, care must be taken to check that the most recent pipeline
-properly corrected any failures from previous pipelines.
+GitLab checks the **most recent pipeline** that **passed**. If the merge request is mergeable,
+it doesn't matter that an earlier pipeline failed because of a change that has not been corrected.
+
+When you use this configuration, ensure that the most recent pipeline
+properly corrects any failures from previous pipelines.
##### Using `only:changes` without pipelines for merge requests
@@ -2068,15 +2043,15 @@ production:
This example creates four paths of execution:
-- Linter: the `lint` job will run immediately without waiting for the `build` stage to complete because it has no needs (`needs: []`).
+- Linter: the `lint` job runs immediately without waiting for the `build` stage to complete because it has no needs (`needs: []`).
-- Linux path: the `linux:rspec` and `linux:rubocop` jobs will be run as soon
+- Linux path: the `linux:rspec` and `linux:rubocop` jobs runs as soon
as the `linux:build` job finishes without waiting for `mac:build` to finish.
-- macOS path: the `mac:rspec` and `mac:rubocop` jobs will be run as soon
+- macOS path: the `mac:rspec` and `mac:rubocop` jobs runs as soon
as the `mac:build` job finishes, without waiting for `linux:build` to finish.
-- The `production` job will be executed as soon as all previous jobs
+- The `production` job runs as soon as all previous jobs
finish; in this case: `linux:build`, `linux:rspec`, `linux:rubocop`,
`mac:build`, `mac:rspec`, `mac:rubocop`.
@@ -2084,14 +2059,14 @@ This example creates four paths of execution:
- If `needs:` is set to point to a job that is not instantiated
because of `only/except` rules or otherwise does not exist, the
- pipeline will be created with YAML error.
+ pipeline is not created and a YAML error is shown.
- The maximum number of jobs that a single job can need in the `needs:` array is limited:
- For GitLab.com, the limit is 50. For more information, see our
[infrastructure issue](https://gitlab.com/gitlab-com/gl-infra/infrastructure/-/issues/7541).
- For self-managed instances, the limit is: 50. This limit [can be changed](#changing-the-needs-job-limit).
- If `needs:` refers to a job that is marked as `parallel:`.
- the current job will depend on all parallel jobs created.
-- `needs:` is similar to `dependencies:` in that it needs to use jobs from prior stages,
+ the current job depends on all parallel jobs being created.
+- `needs:` is similar to `dependencies:` in that it must use jobs from prior stages,
meaning it's impossible to create circular dependencies. Depending on jobs in the
current stage is not possible either, but support [is planned](https://gitlab.com/gitlab-org/gitlab/-/issues/30632).
- Related to the above, stages must be explicitly defined for all jobs
@@ -2108,8 +2083,7 @@ can choose a custom limit. For example, to set the limit to 100:
Plan.default.actual_limits.update!(ci_needs_size_limit: 100)
```
-NOTE: **Note:**
-To disable the ability to use DAG, set the limit to `0`.
+To disable directed acyclic graphs (DAG), set the limit to `0`.
#### Artifact downloads with `needs`
@@ -2117,12 +2091,12 @@ To disable the ability to use DAG, set the limit to `0`.
When using `needs`, artifact downloads are controlled with `artifacts: true` (default) or `artifacts: false`.
-Since GitLab 12.6, you can't combine the [`dependencies`](#dependencies) keyword
+In GitLab 12.6 and later, you can't combine the [`dependencies`](#dependencies) keyword
with `needs` to control artifact downloads in jobs. `dependencies` is still valid
in jobs that do not use `needs`.
-In the example below, the `rspec` job will download the `build_job` artifacts, while the
-`rubocop` job won't:
+In the example below, the `rspec` job downloads the `build_job` artifacts, while the
+`rubocop` job doesn't:
```yaml
build_job:
@@ -2144,9 +2118,9 @@ rubocop:
artifacts: false
```
-Additionally, in the three syntax examples below, the `rspec` job will download the artifacts
-from all three `build_jobs`, as `artifacts` is true for `build_job_1`, and will
-**default** to true for both `build_job_2` and `build_job_3`.
+Additionally, in the three syntax examples below, the `rspec` job downloads the artifacts
+from all three `build_jobs`. `artifacts` is true for `build_job_1` and
+**defaults** to true for both `build_job_2` and `build_job_3`.
```yaml
rspec:
@@ -2161,9 +2135,10 @@ rspec:
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/14311) in GitLab v12.7.
-`needs` can be used to download artifacts from up to five jobs in pipelines on
-[other refs in the same project](#artifact-downloads-between-pipelines-in-the-same-project),
-or pipelines in different projects, groups and namespaces:
+Use `needs` to download artifacts from up to five jobs in pipelines:
+
+- [On other refs in the same project](#artifact-downloads-between-pipelines-in-the-same-project).
+- In different projects, groups and namespaces.
```yaml
build_job:
@@ -2177,7 +2152,7 @@ build_job:
artifacts: true
```
-`build_job` will download the artifacts from the latest successful `build-1` job
+`build_job` downloads the artifacts from the latest successful `build-1` job
on the `master` branch in the `group/project-name` project. If the project is in the
same group or namespace, you can omit them from the `project:` key. For example,
`project: group/project-name` or `project: project-name`.
@@ -2186,9 +2161,10 @@ The user running the pipeline must have at least `reporter` access to the group
##### Artifact downloads between pipelines in the same project
-`needs` can be used to download artifacts from different pipelines in the current project
-by setting the `project` keyword as the current project's name, and specifying a ref.
-In the example below, `build_job` will download the artifacts for the latest successful
+Use `needs` to download artifacts from different pipelines in the current project.
+Set the `project` keyword as the current project's name, and specify a ref.
+
+In this example, `build_job` downloads the artifacts for the latest successful
`build-1` job with the `other-ref` ref:
```yaml
@@ -2220,7 +2196,6 @@ build_job:
artifacts: true
```
-NOTE: **Note:**
Downloading artifacts from jobs that are run in [`parallel:`](#parallel) is not supported.
### `tags`
@@ -2232,7 +2207,7 @@ When you register a runner, you can specify the runner's tags, for
example `ruby`, `postgres`, `development`.
In this example, the job is run by a runner that
-has both `ruby` AND `postgres` tags defined.
+has both `ruby` and `postgres` tags defined.
```yaml
job:
@@ -2271,16 +2246,16 @@ The default value is `false`, except for [manual](#whenmanual) jobs using the
`when: manual` syntax, unless using [`rules:`](#rules) syntax, where all jobs
default to false, *including* `when: manual` jobs.
-When enabled and the job fails, the job will show an orange warning in the UI.
-However, the logical flow of the pipeline will consider the job a
+When `allow_failure` is enabled and the job fails, the job shows an orange warning in the UI.
+However, the logical flow of the pipeline considers the job a
success/passed, and is not blocked.
-Assuming all other jobs are successful, the job's stage and its pipeline will
-show the same orange warning. However, the associated commit will be marked
+Assuming all other jobs are successful, the job's stage and its pipeline
+show the same orange warning. However, the associated commit is marked as
"passed", without warnings.
-In the example below, `job1` and `job2` will run in parallel, but if `job1`
-fails, it won't stop the next stage from running, since it's marked with
+In the example below, `job1` and `job2` run in parallel, but if `job1`
+fails, it doesn't stop the next stage from running, because it's marked with
`allow_failure: true`:
```yaml
@@ -2309,15 +2284,15 @@ failure.
`when` can be set to one of the following values:
1. `on_success` - execute job only when all jobs from prior stages
- succeed (or are considered succeeding because they are marked
- `allow_failure`). This is the default.
+ succeed (or are considered succeeding because they have `allow_failure: true`).
+ This is the default.
1. `on_failure` - execute job only when at least one job from prior stages
fails.
1. `always` - execute job regardless of the status of jobs from prior stages.
1. `manual` - execute job manually (added in GitLab 8.10). Read about
- [manual actions](#whenmanual) below.
+ [manual jobs](#whenmanual) below.
1. `delayed` - execute job after a certain period (added in GitLab 11.14).
- Read about [delayed actions](#whendelayed) below.
+ Read about [delayed jobs](#whendelayed) below.
1. `never`:
- With [`rules`](#rules), don't execute job.
- With [`workflow:rules`](#workflowrules), don't run pipeline.
@@ -2371,45 +2346,44 @@ The above script:
#### `when:manual`
> - Introduced in GitLab 8.10.
-> - Blocking manual actions were introduced in GitLab 9.0.
+> - Blocking manual jobs were introduced in GitLab 9.0.
> - Protected actions were introduced in GitLab 9.2.
-Manual actions are a special type of job that are not executed automatically,
-they need to be explicitly started by a user. An example usage of manual actions
-would be a deployment to a production environment. Manual actions can be started
-from the pipeline, job, environment, and deployment views. Read more at the
-[environments documentation](../environments/index.md#configuring-manual-deployments).
+A manual job is a type of job that is not executed automatically and must be explicitly
+started by a user. You might want to use manual jobs for things like deploying to production.
-Manual actions can be either optional or blocking. Blocking manual actions will
-block the execution of the pipeline at the stage this action is defined in. It's
-possible to resume execution of the pipeline when someone executes a blocking
-manual action by clicking a _play_ button.
+To make a job manual, add `when: manual` to its configuration.
-When a pipeline is blocked, it won't be merged if Merge When Pipeline Succeeds
-is set. Blocked pipelines also do have a special status, called _manual_.
-When the `when:manual` syntax is used, manual actions are non-blocking by
-default. If you want to make manual action blocking, it's necessary to add
-`allow_failure: false` to the job's definition in `.gitlab-ci.yml`.
+Manual jobs can be started from the pipeline, job, [environment](../environments/index.md#configuring-manual-deployments),
+and deployment views.
-Optional manual actions have `allow_failure: true` set by default and their
-Statuses don't contribute to the overall pipeline status. So, if a manual
-action fails, the pipeline will eventually succeed.
+Manual jobs can be either optional or blocking:
-NOTE: **Note:**
-When using [`rules:`](#rules), `allow_failure` defaults to `false`, including for manual jobs.
+- **Optional**: Manual jobs have [`allow_failure: true](#allow_failure) set by default
+ and are considered optional. The status of an optional manual job does not contribute
+ to the overall pipeline status. A pipeline can succeed even if all its manual jobs fail.
-Manual actions are considered to be write actions, so permissions for
-[protected branches](../../user/project/protected_branches.md) are used when
-a user wants to trigger an action. In other words, in order to trigger a manual
-action assigned to a branch that the pipeline is running for, the user needs to
-have the ability to merge to this branch. It's possible to use protected environments
-to more strictly [protect manual deployments](#protecting-manual-jobs) from being
-run by unauthorized users.
+- **Blocking**: To make a blocking manual job, add `allow_failure: false` to its configuration.
+ Blocking manual jobs stop further execution of the pipeline at the stage where the
+ job is defined. To let the pipeline continue running, click **{play}** (play) on
+ the blocking manual job.
-NOTE: **Note:**
-Using `when:manual` and `trigger` together results in the error `jobs:#{job-name} when
-should be on_success, on_failure or always`, because `when:manual` prevents triggers
-being used.
+ Merge requests in projects with [merge when pipeline succeeds](../../user/project/merge_requests/merge_when_pipeline_succeeds.md)
+ enabled can't be merged with a blocked pipeline. Blocked pipelines show a status
+ of **blocked**.
+
+When you use [`rules:`](#rules), `allow_failure` defaults to `false`, including for manual jobs.
+
+To trigger a manual job, a user must have permission to merge to the assigned branch.
+You can use [protected branches](../../user/project/protected_branches.md) to more strictly
+[protect manual deployments](#protecting-manual-jobs) from being run by unauthorized users.
+
+In [GitLab 13.5](https://gitlab.com/gitlab-org/gitlab/-/issues/201938) and later, you
+can use `when:manual` in the same job as [`trigger`](#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`.
+It is deployed behind the `:ci_manual_bridges` [feature flag](../../user/feature_flags.md), which is **enabled by default**.
+[GitLab administrators with access to the Rails console](../../administration/feature_flags.md)
+can opt to disable it.
##### Protecting manual jobs **(PREMIUM)**
@@ -2441,12 +2415,12 @@ To do this, you must:
1. In the [protected environments settings](../environments/protected_environments.md#protecting-environments),
select the environment (`production` in the example above) and add the users, roles or groups
that are authorized to trigger the manual job to the **Allowed to Deploy** list. Only those in
- this list will be able to trigger this manual job, as well as GitLab administrators
+ this list can trigger this manual job, as well as GitLab administrators
who are always able to use protected environments.
-Additionally, if a manual job is defined as blocking by adding `allow_failure: false`,
-the next stages of the pipeline won't run until the manual job is triggered. This
-can be used as a way to have a defined list of users allowed to "approve" later pipeline
+Additionally, if you define a manual job as blocking by adding `allow_failure: false`,
+the pipeline's next stages don't run until the manual job is triggered. You can use this
+to define a list of users allowed to "approve" later pipeline
stages by triggering the blocking manual job.
#### `when:delayed`
@@ -2465,11 +2439,11 @@ provided. `start_in` key must be less than or equal to one week. Examples of val
- `1 day`
- `1 week`
-When there is a delayed job in a stage, the pipeline won't progress until the delayed job has finished.
+When there is a delayed job in a stage, the pipeline doesn't progress until the delayed job has finished.
This means this keyword can also be used for inserting delays between different stages.
The timer of a delayed job starts immediately after the previous stage has completed.
-Similar to other types of jobs, a delayed job's timer won't start unless the previous stage passed.
+Similar to other types of jobs, a delayed job's timer doesn't start unless the previous stage passed.
The following example creates a job named `timed rollout 10%` that is executed 30 minutes after the previous stage has completed:
@@ -2482,7 +2456,7 @@ timed rollout 10%:
```
You can stop the active timer of a delayed job by clicking the **{time-out}** (**Unschedule**) button.
-This job will never be executed in the future unless you execute the job manually.
+This job can no longer be scheduled to run automatically. You can, however, execute the job manually.
To start a delayed job immediately, click the **Play** button.
Soon GitLab Runner picks up and starts the job.
@@ -2495,7 +2469,7 @@ Soon GitLab Runner picks up and starts the job.
`environment` is used to define that a job deploys to a specific environment.
If `environment` is specified and no environment under that name exists, a new
-one will be created automatically.
+one is created automatically.
In its simplest form, the `environment` keyword can be defined like:
@@ -2506,7 +2480,7 @@ deploy to production:
environment: production
```
-In the above example, the `deploy to production` job will be marked as doing a
+In the above example, the `deploy to production` job is marked as doing a
deployment to the `production` environment.
#### `environment:name`
@@ -2574,12 +2548,12 @@ deploy to production:
> - [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/22191) in GitLab 8.13.
> - Starting with GitLab 8.14, when you have an environment that has a stop action
-> defined, GitLab will automatically trigger a stop action when the associated
+> defined, GitLab automatically triggers a stop action when the associated
> branch is deleted.
-Closing (stopping) environments can be achieved with the `on_stop` keyword defined under
-`environment`. It declares a different job that runs in order to close
-the environment.
+Closing (stopping) environments can be achieved with the `on_stop` keyword
+defined under `environment`. It declares a different job that runs to close the
+environment.
Read the `environment:action` section for an example.
@@ -2591,7 +2565,7 @@ The `action` keyword can be used to specify jobs that prepare, start, or stop en
| **Value** | **Description** |
|-----------|---------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| start | Default value. Indicates that job starts the environment. Deployment will be created after job starts. |
+| start | Default value. Indicates that job starts the environment. The deployment is created after the job starts. |
| prepare | Indicates that job is only preparing the environment. Does not affect deployments. [Read more about environments](../environments/index.md#prepare-an-environment) |
| stop | Indicates that job stops deployment. See the example below. |
@@ -2617,21 +2591,20 @@ stop_review_app:
action: stop
```
-In the above example we set up the `review_app` job to deploy to the `review`
-environment, and we also defined a new `stop_review_app` job under `on_stop`.
-Once the `review_app` job is successfully finished, it will trigger the
-`stop_review_app` job based on what is defined under `when`. In this case we
-set it up to `manual` so it will need a [manual action](#whenmanual) via
-GitLab's web interface in order to run.
+In the above example, the `review_app` job deploys to the `review`
+environment. A new `stop_review_app` job is listed under `on_stop`.
+After the `review_app` job is finished, it triggers the
+`stop_review_app` job based on what is defined under `when`. In this case,
+it is set to `manual`, so it needs a [manual action](#whenmanual) from
+GitLab's user interface to run.
-Also in the example, `GIT_STRATEGY` is set to `none` so that GitLab Runner won’t
-try to check out the code after the branch is deleted when the `stop_review_app`
-job is [automatically triggered](../environments/index.md#automatically-stopping-an-environment).
+Also in the example, `GIT_STRATEGY` is set to `none`. If the
+`stop_review_app` job is [automatically triggered](../environments/index.md#automatically-stopping-an-environment),
+the runner won’t try to check out the code after the branch is deleted.
-NOTE: **Note:**
-The above example overwrites global variables. If your stop environment job depends
-on global variables, you can use [anchor variables](#yaml-anchors-for-variables) when setting the `GIT_STRATEGY`
-to change it without overriding the global variables.
+The example also overwrites global variables. If your `stop` `environment` job depends
+on global variables, you can use [anchor variables](#yaml-anchors-for-variables) when you set the `GIT_STRATEGY`.
+This changes the job without overriding the global variables.
The `stop_review_app` job is **required** to have the following keywords defined:
@@ -2640,10 +2613,12 @@ The `stop_review_app` job is **required** to have the following keywords defined
- `environment:action`
Additionally, both jobs should have matching [`rules`](../yaml/README.md#onlyexcept-basic)
-or [`only/except`](../yaml/README.md#onlyexcept-basic) configuration. In the example
-above, if the configuration is not identical, the `stop_review_app` job might not be
-included in all pipelines that include the `review_app` job, and it will not be
-possible to trigger the `action: stop` to stop the environment automatically.
+or [`only/except`](../yaml/README.md#onlyexcept-basic) configuration.
+
+In the example above, if the configuration is not identical:
+
+- The `stop_review_app` job might not be included in all pipelines that include the `review_app` job.
+- It is not possible to trigger the `action: stop` to stop the environment automatically.
#### `environment:auto_stop_in`
@@ -2687,7 +2662,7 @@ deploy:
namespace: production
```
-This will set up the `deploy` job to deploy to the `production`
+This configuration sets up the `deploy` job to deploy to the `production`
environment, using the `production`
[Kubernetes namespace](https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/).
@@ -2719,11 +2694,11 @@ deploy as review app:
url: https://$CI_ENVIRONMENT_SLUG.example.com/
```
-The `deploy as review app` job will be marked as deployment to dynamically
+The `deploy as review app` job is marked as deployment to dynamically
create the `review/$CI_COMMIT_REF_NAME` environment, where `$CI_COMMIT_REF_NAME`
is an [environment variable](../variables/README.md) set by the runner. The
`$CI_ENVIRONMENT_SLUG` variable is based on the environment name, but suitable
-for inclusion in URLs. In this case, if the `deploy as review app` job was run
+for inclusion in URLs. In this case, if the `deploy as review app` job is run
in a branch named `pow`, this environment would be accessible with an URL like
`https://review-pow.example.com/`.
@@ -2742,16 +2717,15 @@ as Review Apps. You can see a simple example using Review Apps at
> by default.
> - From GitLab 9.2, caches are restored before [artifacts](#artifacts).
-TIP: **Learn more:**
-Read how caching works and find out some good practices in the
-[caching dependencies documentation](../caching/index.md).
-
`cache` is used to specify a list of files and directories that should be
cached between jobs. You can only use paths that are within the local working
copy.
If `cache` is defined outside the scope of jobs, it means it's set
-globally and all jobs will use that definition.
+globally and all jobs use that definition.
+
+Read how caching works and find out some good practices in the
+[caching dependencies documentation](../caching/index.md).
#### `cache:paths`
@@ -2777,7 +2751,7 @@ rspec:
```
Locally defined cache overrides globally defined options. The following `rspec`
-job will cache only `binaries/`:
+job caches only `binaries/`:
```yaml
cache:
@@ -2792,20 +2766,20 @@ rspec:
- binaries/
```
-Note that since cache is shared between jobs, if you're using different
-paths for different jobs, you should also set a different **cache:key**
-otherwise cache content can be overwritten.
+The cache is shared between jobs, so if you're using different
+paths for different jobs, you should also set a different `cache:key`.
+Otherwise cache content can be overwritten.
#### `cache:key`
> Introduced in GitLab Runner v1.0.0.
-Since the cache is shared between jobs, if you're using different
-paths for different jobs, you should also set a different `cache:key`
-otherwise cache content can be overwritten.
+The cache is shared between jobs, so if you're using different
+paths for different jobs, you should also set a different `cache:key`.
+Otherwise cache content can be overwritten.
-The `key` parameter defines the affinity of caching between jobs,
-to have a single cache for all jobs, cache per-job, cache per-branch
+The `key` parameter defines the affinity of caching between jobs.
+You can have a single cache for all jobs, cache per-job, cache per-branch,
or any other way that fits your workflow. This way, you can fine tune caching,
including caching data between different jobs or even different branches.
@@ -2814,10 +2788,6 @@ The `cache:key` variable can use any of the
set, is just literal `default`, which means everything is shared between
pipelines and jobs by default, starting from GitLab 9.0.
-NOTE: **Note:**
-The `cache:key` variable can't contain the `/` character, or the equivalent
-URI-encoded `%2F`; a value made only of dots (`.`, `%2E`) is also forbidden.
-
For example, to enable per-branch caching:
```yaml
@@ -2837,18 +2807,23 @@ cache:
- binaries/
```
+The `cache:key` variable can't contain the `/` character, or the equivalent
+URI-encoded `%2F`. A value made only of dots (`.`, `%2E`) is also forbidden.
+
+You can specify a [fallback cache key](#fallback-cache-key) to use if the specified `cache:key` is not found.
+
##### `cache:key:files`
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/18986) in GitLab v12.5.
The `cache:key:files` keyword extends the `cache:key` functionality by making it easier
-to reuse some caches, and rebuild them less often, which will speed up subsequent pipeline
+to reuse some caches, and rebuild them less often, which speeds up subsequent pipeline
runs.
-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)
+When you include `cache:key:files`, you must also list the project files that are used to generate the key, up to a maximum of two files.
+The cache `key` is a SHA checksum computed from the most recent commits (up to two, if two files are listed)
that changed the given files. If neither file was changed in any commits,
-the fallback key will be `default`.
+the fallback key is `default`.
```yaml
cache:
@@ -2864,7 +2839,7 @@ cache:
In this example we're creating a cache for Ruby and Node.js dependencies that
is tied to current versions of the `Gemfile.lock` and `package.json` files. Whenever one of
these files changes, a new cache key is computed and a new cache is created. Any future
-job runs using the same `Gemfile.lock` and `package.json` with `cache:key:files` will
+job runs that use the same `Gemfile.lock` and `package.json` with `cache:key:files`
use the new cache, instead of rebuilding the dependencies.
##### `cache:key:prefix`
@@ -2897,11 +2872,11 @@ rspec:
- bundle exec rspec
```
-For example, adding a `prefix` of `$CI_JOB_NAME` will
-cause the key to look like: `rspec-feef9576d21ee9b6a32e30c5c79d0a0ceb68d1e5` and
+For example, adding a `prefix` of `$CI_JOB_NAME`
+causes the key to look like: `rspec-feef9576d21ee9b6a32e30c5c79d0a0ceb68d1e5` and
the job cache is shared across different branches. If a branch changes
-`Gemfile.lock`, that branch will have a new SHA checksum for `cache:key:files`. A new cache key
-will be generated, and a new cache will be created for that key.
+`Gemfile.lock`, that branch has a new SHA checksum for `cache:key:files`. A new cache key
+is generated, and a new cache is created for that key.
If `Gemfile.lock` is not found, the prefix is added to
`default`, so the key in the example would be `rspec-default`.
@@ -2928,6 +2903,28 @@ rspec:
- binaries/
```
+#### `cache:when`
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/18969) in GitLab 13.5 and GitLab Runner v13.5.0.
+
+`cache:when` defines when to save the cache, based on the status of the job. You can
+set `cache:when` to:
+
+- `on_success` - save the cache only when the job succeeds. This is the default.
+- `on_failure` - save the cache only when the job fails.
+- `always` - save the cache regardless of the job status.
+
+For example, to store a cache whether or not the job fails or succeeds:
+
+```yaml
+rspec:
+ script: rspec
+ cache:
+ paths:
+ - rspec/
+ when: 'always'
+```
+
#### `cache:policy`
> Introduced in GitLab 9.4.
@@ -2967,13 +2964,13 @@ rspec:
- bundle exec rspec ...
```
-This helps to speed up job execution and reduce load on the cache server,
-especially when you have a large number of cache-using jobs executing in
+This helps to speed up job execution and reduce load on the cache server.
+It is especially helpful when you have a large number of cache-using jobs executing in
parallel.
-Additionally, if you have a job that unconditionally recreates the cache without
-reference to its previous contents, you can use `policy: push` in that job to
-skip the download step.
+If you have a job that unconditionally recreates the cache without
+referring to its previous contents, you can skip the download step.
+To do so, add `policy: push` to the job.
### `artifacts`
@@ -2986,8 +2983,8 @@ skip the download step.
`artifacts` is used to specify a list of files and directories that are
attached to the job when it [succeeds, fails, or always](#artifactswhen).
-The artifacts will be sent to GitLab after the job finishes and will
-be available for download in the GitLab UI provided that the size is not
+The artifacts are sent to GitLab after the job finishes. They are
+available for download in the GitLab UI if the size is not
larger than the [maximum artifact size](../../user/gitlab_com/index.md#gitlab-cicd).
[Read more about artifacts](../pipelines/job_artifacts.md).
@@ -3003,7 +3000,7 @@ patterns and:
- In GitLab Runner 12.10 and earlier,
[`filepath.Match`](https://pkg.go.dev/path/filepath/#Match).
-To restrict which jobs a specific job will fetch artifacts from, see [dependencies](#dependencies).
+To restrict which jobs a specific job fetches artifacts from, see [dependencies](#dependencies).
Send all files in `binaries` and `.config`:
@@ -3026,7 +3023,7 @@ job:
You may want to create artifacts only for tagged releases to avoid filling the
build server storage with temporary build artifacts.
-Create artifacts only for tags (`default-job` won't create artifacts):
+Create artifacts only for tags (`default-job` doesn't create artifacts):
```yaml
default-job:
@@ -3098,10 +3095,10 @@ test:
paths: ['file.txt']
```
-With this configuration, GitLab will add a link **artifact 1** to the relevant merge request
+With this configuration, GitLab adds a link **artifact 1** to the relevant merge request
that points to `file1.txt`.
-An example that will match an entire directory:
+An example that matches an entire directory:
```yaml
test:
@@ -3116,12 +3113,12 @@ Note the following:
- Artifacts do not display in the merge request UI when using variables to define the `artifacts:paths`.
- A maximum of 10 job artifacts per merge request can be exposed.
- Glob patterns are unsupported.
-- If a directory is specified, the link will be to the job [artifacts browser](../pipelines/job_artifacts.md#browsing-artifacts) if there is more than
+- If a directory is specified, the link is to the job [artifacts browser](../pipelines/job_artifacts.md#browsing-artifacts) if there is more than
one file in the directory.
- For exposed single file artifacts with `.html`, `.htm`, `.txt`, `.json`, `.xml`,
and `.log` extensions, if [GitLab Pages](../../administration/pages/index.md) is:
- - Enabled, GitLab will automatically render the artifact.
- - Not enabled, you will see the file in the artifacts browser.
+ - Enabled, GitLab automatically renders the artifact.
+ - Not enabled, the file is displayed in the artifacts browser.
#### `artifacts:name`
@@ -3133,11 +3130,6 @@ useful when you want to download the archive from GitLab. The `artifacts:name`
variable can make use of any of the [predefined variables](../variables/README.md).
The default name is `artifacts`, which becomes `artifacts.zip` when you download it.
-NOTE: **Note:**
-If your branch-name contains forward slashes
-(for example `feature/my-feature`) it's advised to use `$CI_COMMIT_REF_SLUG`
-instead of `$CI_COMMIT_REF_NAME` for proper naming of the artifact.
-
To create an archive with a name of the current job:
```yaml
@@ -3159,6 +3151,10 @@ job:
- binaries/
```
+If your branch-name contains forward slashes
+(for example `feature/my-feature`) it's advised to use `$CI_COMMIT_REF_SLUG`
+instead of `$CI_COMMIT_REF_NAME` for proper naming of the artifact.
+
To create an archive with a name of the current job and the current branch or
tag including only the binaries directory:
@@ -3207,10 +3203,8 @@ job:
#### `artifacts:untracked`
`artifacts:untracked` is used to add all Git untracked files as artifacts (along
-to the paths defined in `artifacts:paths`).
-
-NOTE: **Note:**
-`artifacts:untracked` ignores configuration in the repository's `.gitignore` file.
+to the paths defined in `artifacts:paths`). `artifacts:untracked` ignores configuration
+in the repository's `.gitignore` file.
Send all Git untracked files:
@@ -3250,7 +3244,7 @@ failure.
1. `on_failure` - upload artifacts only when the job fails.
1. `always` - upload artifacts regardless of the job status.
-To upload artifacts only when job fails:
+For example, to upload artifacts only when a job fails:
```yaml
job:
@@ -3300,7 +3294,6 @@ job:
expire_in: 1 week
```
-NOTE: **Note:**
The latest artifacts for refs are locked against deletion, and kept regardless of
the expiry time. [Introduced in](https://gitlab.com/gitlab-org/gitlab/-/issues/16267)
GitLab 13.0 behind a disabled feature flag, and [made the default behavior](https://gitlab.com/gitlab-org/gitlab/-/issues/229936)
@@ -3335,24 +3328,27 @@ These are the available report types:
> Introduced in GitLab 8.6 and GitLab Runner v1.1.1.
-By default, all [`artifacts`](#artifacts) from all previous [stages](#stages)
-are passed, but you can use the `dependencies` parameter to define a limited
-list of jobs (or no jobs) to fetch artifacts from.
+By default, all [`artifacts`](#artifacts) from previous [stages](#stages)
+are passed to each job. However, you can use the `dependencies` parameter to
+define a limited list of jobs to fetch artifacts from. You can also set a job to download no artifacts at all.
To use this feature, define `dependencies` in context of the job and pass
a list of all previous jobs the artifacts should be downloaded from.
-You can only define jobs from stages that are executed before the current one.
-An error will be shown if you define jobs from the current stage or next ones.
-Defining an empty array will skip downloading any artifacts for that job.
-The status of the previous job is not considered when using `dependencies`, so
-if it failed or it's a manual job that was not run, no error occurs.
-In the following example, we define two jobs with artifacts, `build:osx` and
+You can define jobs from stages that were executed before the current one.
+An error occurs if you define jobs from the current or an upcoming stage.
+
+To prevent a job from downloading artifacts, define an empty array.
+
+When you use `dependencies`, the status of the previous job is not considered.
+If a job fails or it's a manual job that was not run, no error occurs.
+
+The following example defines two jobs with artifacts: `build:osx` and
`build:linux`. When the `test:osx` is executed, the artifacts from `build:osx`
-will be downloaded and extracted in the context of the build. The same happens
+are downloaded and extracted in the context of the build. The same happens
for `test:linux` and artifacts from `build:linux`.
-The job `deploy` will download artifacts from all previous jobs because of
+The job `deploy` downloads artifacts from all previous jobs because of
the [stage](#stages) precedence:
```yaml
@@ -3387,16 +3383,15 @@ deploy:
script: make deploy
```
-##### When a dependent job will fail
+##### When a dependent job fails
> Introduced in GitLab 10.3.
If the artifacts of the job that is set as a dependency have been
[expired](#artifactsexpire_in) or
[erased](../pipelines/job_artifacts.md#erasing-artifacts), then
-the dependent job will fail.
+the dependent job fails.
-NOTE: **Note:**
You can ask your administrator to
[flip this switch](../../administration/job_artifacts.md#validation-for-dependencies)
and bring back the old behavior.
@@ -3409,7 +3404,7 @@ Use `coverage` to configure how code coverage is extracted from the
job output.
Regular expressions are the only valid kind of value expected here. So, using
-surrounding `/` is mandatory in order to consistently and explicitly represent
+surrounding `/` is mandatory to consistently and explicitly represent
a regular expression string. You must escape special characters if you want to
match them literally.
@@ -3426,17 +3421,17 @@ job1:
> - [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/3442) in GitLab 9.5.
> - [Behavior expanded](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/3515) in GitLab 11.5 to control which failures to retry on.
-Use `retry` to configure how many times a job is going to be retried in
+Use `retry` to configure how many times a job is retried in
case of a failure.
-When a job fails and has `retry` configured, it's going to be processed again
-up to the amount of times specified by the `retry` keyword.
+When a job fails, the job is processed again,
+until the limit specified by the `retry` keyword is reached.
-If `retry` is set to 2, and a job succeeds in a second run (first retry), it won't be retried
-again. `retry` value has to be a positive integer, equal or larger than 0, but
-lower or equal to 2 (two retries maximum, three runs in total).
+If `retry` is set to `2`, and a job succeeds in a second run (first retry), it is not retried.
+The `retry` value must be a positive integer, from `0` to `2`
+(two retries maximum, three runs in total).
-A simple example to retry in all failure cases:
+This example retries all failure cases:
```yaml
test:
@@ -3444,7 +3439,7 @@ test:
retry: 2
```
-By default, a job will be retried on all failure cases. To have a better control
+By default, a job is retried on all failure cases. To have better control
over which failures to retry, `retry` can be a hash with the following keys:
- `max`: The maximum number of retries.
@@ -3460,8 +3455,8 @@ test:
when: runner_system_failure
```
-If there is another failure, other than a runner system failure, the job will
-not be retried.
+If there is another failure, other than a runner system failure, the job
+is not retried.
To retry on multiple failure cases, `when` can also be an array of failures:
@@ -3478,10 +3473,10 @@ test:
Possible values for `when` are:
<!--
- Please make sure to update `RETRY_WHEN_IN_DOCUMENTATION` array in
- `spec/lib/gitlab/ci/config/entry/retry_spec.rb` if you change any of
- the documented values below. The test there makes sure that all documented
- values are really valid as a configuration option and therefore should always
+ If you change any of the values below, make sure to update the `RETRY_WHEN_IN_DOCUMENTATION`
+ array in `spec/lib/gitlab/ci/config/entry/retry_spec.rb`.
+ The test there makes sure that all documented
+ values are valid as a configuration option and therefore should always
stay in sync with this documentation.
-->
@@ -3543,7 +3538,6 @@ test:
parallel: 5
```
-TIP: **Tip:**
Parallelize tests suites across parallel jobs.
Different languages have different tools to facilitate this.
@@ -3578,6 +3572,12 @@ job split into three separate jobs.
Use `matrix:` to configure different variables for jobs that are running in parallel.
There can be from 2 to 50 jobs.
+[In GitLab 13.5](https://gitlab.com/gitlab-org/gitlab/-/issues/26362) and later,
+you can have one-dimensional matrices with a single job.
+The ability to have one-dimensional matrices is [deployed behind a feature flag](../../user/feature_flags.md),
+enabled by default. It's enabled on GitLab.com. For self-managed GitLab instances,
+administrators can opt to disable it by [disabling the `one_dimensional_matrix:` feature flag](../../administration/feature_flags.md). **(CORE ONLY)**
+
Every job gets the same `CI_NODE_TOTAL` [environment variable](../variables/README.md#predefined-environment-variables) value, and a unique `CI_NODE_INDEX` value.
```yaml
@@ -3623,19 +3623,25 @@ Job naming style [was improved](https://gitlab.com/gitlab-org/gitlab/-/issues/23
Use `trigger` to define a downstream pipeline trigger. When GitLab starts a job created
with a `trigger` definition, a downstream pipeline is created.
+Jobs with `trigger` can only use a [limited set of keywords](../multi_project_pipelines.md#limitations).
+For example, you can't run commands with [`script`](#script), [`before_script`](#before_script-and-after_script),
+or [`after_script`](#before_script-and-after_script).
+
You can use this keyword to create two different types of downstream pipelines:
- [Multi-project pipelines](../multi_project_pipelines.md#creating-multi-project-pipelines-from-gitlab-ciyml)
- [Child pipelines](../parent_child_pipelines.md)
-[Since GitLab 13.2](https://gitlab.com/gitlab-org/gitlab/-/issues/197140/), you can
-see which job triggered a downstream pipeline by hovering your mouse cursor over
-the downstream pipeline job in the [pipeline graph](../pipelines/index.md#visualize-pipelines).
+[In GitLab 13.2](https://gitlab.com/gitlab-org/gitlab/-/issues/197140/) and later, you can
+view which job triggered a downstream pipeline. In the [pipeline graph](../pipelines/index.md#visualize-pipelines),
+hover over the downstream pipeline job.
-NOTE: **Note:**
-Using a `trigger` with `when:manual` together results in the error `jobs:#{job-name}
-when should be on_success, on_failure or always`, because `when:manual` prevents
-triggers being used.
+In [GitLab 13.5](https://gitlab.com/gitlab-org/gitlab/-/issues/201938) and later, you
+can use [`when:manual`](#whenmanual) 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`.
+It is deployed behind the `:ci_manual_bridges` [feature flag](../../user/feature_flags.md), which is **enabled by default**.
+[GitLab administrators with access to the Rails console](../../administration/feature_flags.md)
+can opt to disable it.
#### Simple `trigger` syntax for multi-project pipelines
@@ -3654,7 +3660,7 @@ staging:
#### Complex `trigger` syntax for multi-project pipelines
-It's possible to configure a branch name that GitLab will use to create
+You can configure a branch name that GitLab uses to create
a downstream pipeline with:
```yaml
@@ -3669,7 +3675,7 @@ staging:
branch: stable
```
-It's possible to mirror the status from a triggered pipeline:
+To mirror the status from a triggered pipeline:
```yaml
trigger_job:
@@ -3678,7 +3684,7 @@ trigger_job:
strategy: depend
```
-It's possible to mirror the status from an upstream pipeline:
+To mirror the status from an upstream pipeline:
```yaml
upstream_bridge:
@@ -3736,14 +3742,30 @@ child-pipeline:
The `generated-config.yml` is extracted from the artifacts and used as the configuration
for triggering the child pipeline.
+##### Trigger child pipeline with files from another project
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/205157) in GitLab 13.5.
+
+To trigger child pipelines with files from another private project under the same
+GitLab instance, use [`include:file`](#includefile):
+
+```yaml
+child-pipeline:
+ trigger:
+ include:
+ - project: 'my-group/my-pipeline-library'
+ ref: 'master'
+ file: '/path/to/child-pipeline.yml'
+```
+
#### Linking pipelines with `trigger:strategy`
By default, the `trigger` job completes with the `success` status
as soon as the downstream pipeline is created.
To force the `trigger` job to wait for the downstream (multi-project or child) pipeline to complete, use
-`strategy: depend`. This will make the trigger job wait with a "running" status until the triggered
-pipeline completes. At that point, the `trigger` job will complete and display the same status as
+`strategy: depend`. This setting makes the trigger job wait with a "running" status until the triggered
+pipeline completes. At that point, the `trigger` job completes and displays the same status as
the downstream job.
```yaml
@@ -3753,16 +3775,16 @@ trigger_job:
strategy: depend
```
-This can help keep your pipeline execution linear. In the example above, jobs from
-subsequent stages will wait for the triggered pipeline to successfully complete before
-starting, at the cost of reduced parallelization.
+This setting can help keep your pipeline execution linear. In the example above, jobs from
+subsequent stages wait for the triggered pipeline to successfully complete before
+starting, which reduces parallelization.
#### Trigger a pipeline by API call
-Triggers can be used to force a rebuild of a specific branch, tag or commit,
-with an API call when a pipeline gets created using a trigger token.
+To force a rebuild of a specific branch, tag, or commit, you can use an API call
+with a trigger token.
-Not to be confused with the [`trigger`](#trigger) parameter.
+The trigger token is different than the [`trigger`](#trigger) parameter.
[Read more in the triggers documentation.](../triggers/README.md)
@@ -3771,19 +3793,18 @@ Not to be confused with the [`trigger`](#trigger) parameter.
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/32022) in GitLab 12.3.
`interruptible` is used to indicate that a job should be canceled if made redundant by a newer pipeline run. Defaults to `false`.
-This value will only be used if the [automatic cancellation of redundant pipelines feature](../pipelines/settings.md#auto-cancel-pending-pipelines)
+This value is used only if the [automatic cancellation of redundant pipelines feature](../pipelines/settings.md#auto-cancel-pending-pipelines)
is enabled.
-When enabled, a pipeline on the same branch will be canceled when:
+When enabled, a pipeline on the same branch is canceled when:
- It's made redundant by a newer pipeline run.
- Either all jobs are set as interruptible, or any uninterruptible jobs haven't started.
-Pending jobs are always considered interruptible.
-
-TIP: **Tip:**
Set jobs as interruptible that can be safely canceled once started (for instance, a build job).
+Pending jobs are always considered interruptible.
+
Here is a simple example:
```yaml
@@ -3806,17 +3827,16 @@ step-2:
step-3:
stage: stage3
script:
- - echo "Because step-2 can not be canceled, this step will never be canceled, even though set as interruptible."
+ - echo "Because step-2 can not be canceled, this step can never be canceled, even though it's set as interruptible."
interruptible: true
```
-In the example above, a new pipeline run will cause an existing running pipeline to be:
+In the example above, a new pipeline run causes an existing running pipeline to be:
- Canceled, if only `step-1` is running or pending.
- Not canceled, once `step-2` starts running.
-NOTE: **Note:**
-Once an uninterruptible job is running, the pipeline will never be canceled, regardless of the final job's state.
+When an uninterruptible job is running, the pipeline can never be canceled, regardless of the final job's state.
### `resource_group`
@@ -3826,12 +3846,13 @@ Sometimes running multiple jobs or pipelines at the same time in an environment
can lead to errors during the deployment.
To avoid these errors, the `resource_group` attribute can be used to ensure that
-the runner doesn't run certain jobs simultaneously.
+the runner doesn't run certain jobs simultaneously. Resource groups behave similar
+to semaphores in other programming languages.
When the `resource_group` key is defined for a job in `.gitlab-ci.yml`,
job executions are mutually exclusive across different pipelines for the same project.
If multiple jobs belonging to the same resource group are enqueued simultaneously,
-only one of the jobs is picked by the runner, and the other jobs wait until the
+only one of the jobs is picked by the runner. The other jobs wait until the
`resource_group` is free.
Here is a simple example:
@@ -3842,17 +3863,14 @@ deploy-to-production:
resource_group: production
```
-In this case, if a `deploy-to-production` job is running in a pipeline, and a new
-`deploy-to-production` job is created in a different pipeline, it won't run until
-the currently running/pending `deploy-to-production` job is finished. As a result,
-you can ensure that concurrent deployments will never happen to the production environment.
+In this case, two `deploy-to-production` jobs in two separate pipelines can never run at the same time. As a result,
+you can ensure that concurrent deployments never happen to the production environment.
There can be multiple `resource_group`s defined per environment. A good use case for this
-is when deploying to physical devices. You may have more than one physical device, and each
-one can be deployed to, but there can be only one deployment per device at any given time.
+is when deploying to physical devices. You may have multiple physical devices that
+can be deployed to, but there can be only one deployment per device at any given time.
-NOTE: **Note:**
-This key can only contain letters, digits, `-`, `_`, `/`, `$`, `{`, `}`, `.`, and spaces.
+The `resource_group` value can only contain letters, digits, `-`, `_`, `/`, `$`, `{`, `}`, `.`, and spaces.
It can't start or end with `/`.
For more information, see [Deployments Safety](../environments/deployment_safety.md).
@@ -3962,7 +3980,11 @@ The title of each milestone the release is associated with.
#### `release:released_at`
The date and time when the release is ready. Defaults to the current date and time if not
-defined. Expected in ISO 8601 format (2019-03-15T08:00:00Z).
+defined. Should be enclosed in quotes and expressed in ISO 8601 format.
+
+```json
+released_at: '2021-03-15T08:00:00Z'
+```
#### Complete example for `release`
@@ -3990,7 +4012,7 @@ tags. These options cannot be used together, so choose one:
- 'm1'
- 'm2'
- 'm3'
- released_at: '2020-07-15T08:00:00Z' # Optional, will auto generate if not defined, or can use a variable.
+ released_at: '2020-07-15T08:00:00Z' # Optional, is auto generated if not defined, or can use a variable.
```
- To create a release automatically when commits are pushed or merged to the default branch,
@@ -4036,9 +4058,14 @@ tags. These options cannot be used together, so choose one:
- 'm1'
- 'm2'
- 'm3'
- released_at: '2020-07-15T08:00:00Z' # Optional, will auto generate if not defined, or can use a variable.
+ released_at: '2020-07-15T08:00:00Z' # Optional, is auto generated if not defined, or can use a variable.
```
+#### Release assets as Generic packages
+
+You can use [Generic packages](../../user/packages/generic_packages/) to host your release assets.
+For a complete example of how to do this, see the [example in the repository](https://gitlab.com/gitlab-org/release-cli/-/tree/master/docs/examples/release-assets-as-generic-package/).
+
#### `releaser-cli` command line
The entries under the `:release` node are transformed into a `bash` command line and sent
@@ -4056,14 +4083,16 @@ release-cli create --name "Release $CI_COMMIT_SHA" --description "Created using
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/33014) in GitLab 13.4.
`secrets` indicates the [CI Secrets](../secrets/index.md) this job needs. It should be a hash,
-and the keys should be the names of the environment variables the job needs to access the secrets.
+and the keys should be the names of the environment variables that are made available to the job.
+The value of each secret is saved in a temporary file. This file's path is stored in these
+environment variables.
#### `secrets:vault` **(PREMIUM)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/28321) in GitLab 13.4.
`vault` keyword specifies secrets provided by [Hashicorp's Vault](https://www.vaultproject.io/).
-This syntax has multiple forms. The shortest form asssumes the use of the
+This syntax has multiple forms. The shortest form assumes the use of the
[KV-V2](https://www.vaultproject.io/docs/secrets/kv/kv-v2) secrets engine,
mounted at the default path `kv-v2`. The last part of the secret's path is the
field to fetch the value for:
@@ -4072,7 +4101,7 @@ field to fetch the value for:
job:
secrets:
DATABASE_PASSWORD:
- vault: production/db/password # translates to secret `kv-v2/data/production/db`, field `password`
+ vault: production/db/password # translates to secret `kv-v2/data/production/db`, field `password`
```
You can specify a custom secrets engine path by adding a suffix starting with `@`:
@@ -4081,7 +4110,7 @@ You can specify a custom secrets engine path by adding a suffix starting with `@
job:
secrets:
DATABASE_PASSWORD:
- vault: production/db/password@ops # translates to secret `ops/data/production/db`, field `password`
+ vault: production/db/password@ops # translates to secret `ops/data/production/db`, field `password`
```
In the detailed form of the syntax, you can specify all details explicitly:
@@ -4131,34 +4160,40 @@ Read more on [GitLab Pages user documentation](../../user/project/pages/index.md
> Introduced in GitLab Runner v0.5.0.
-NOTE: **Note:**
-Integers (as well as strings) are legal both for variable's name and value.
-Floats are not legal and can't be used.
+Variables are configurable values that are passed to jobs. They can be set
+globally and per-job.
+
+There are two types of variables.
+
+- [Custom variables](../variables/README.md#custom-environment-variables):
+ You can define their values in the `.gitlab-ci.yml` file, in the GitLab UI,
+ or by using the API.
+- [Predefined variables](../variables/predefined_variables.md):
+ These values are set by the runner itself.
+ One example is `CI_COMMIT_REF_NAME`, which is the branch or tag the project is built for.
-Variables are configurable values in `.gitlab-ci.yml` that are passed to jobs.
-They can be set globally and per-job.
-When you use the `variables` keyword in jobs, it overrides the global
-YAML variables and predefined ones of the same name.
+After you define a variable, you can use it in all executed commands and scripts.
-Variables are stored in the Git repository and are meant for non-sensitive
-project configuration, for example:
+Variables are meant for non-sensitive project configuration, for example:
```yaml
variables:
DATABASE_URL: "postgres://postgres@postgres/my_database"
```
-You can use these variables later in all executed commands and scripts.
-The YAML-defined variables are also set to all created service containers,
-so that you can fine tune them.
+You can use integers and strings for the variable's name and value.
+You cannot use floats.
+
+If you define a variable at the top level of the `gitlab-ci.yml` file, it is global,
+meaning it applies to all jobs.
+
+If you define a variable within a job, it's available to that job only.
-Except for the user-defined variables, there are also variables [set up by the
-runner itself](../variables/README.md#predefined-environment-variables).
-One example would be `CI_COMMIT_REF_NAME`, which has the value of
-the branch or tag name the project is built for. Apart from the variables
-you can set in `.gitlab-ci.yml`, there are also environment
-[variables](../variables/README.md#gitlab-cicd-environment-variables),
-which can be set in the GitLab UI.
+If a variable of the same name is defined globally and for a specific job, the
+[job-specific variable is used](../variables/README.md#priority-of-environment-variables).
+
+All YAML-defined variables are also set to any linked
+[service containers](../docker/using_docker_images.md#what-is-a-service).
[YAML anchors for variables](#yaml-anchors-for-variables) are available.
@@ -4169,12 +4204,9 @@ Learn more about [variables and their priority](../variables/README.md).
> - Introduced in GitLab 8.9 as an experimental feature.
> - `GIT_STRATEGY=none` requires GitLab Runner v1.7+.
-CAUTION: **Caution:**
-May change or be removed completely in future releases.
-
You can set the `GIT_STRATEGY` used for getting recent application code, either
globally or per-job in the [`variables`](#variables) section. If left
-unspecified, the default from project settings will be used.
+unspecified, the default from the project settings is used.
There are three possible values: `clone`, `fetch`, and `none`.
@@ -4195,10 +4227,11 @@ variables:
GIT_STRATEGY: fetch
```
-`none` also re-uses the local working copy, but skips all Git operations
-(including GitLab Runner's pre-clone script, if present). It's mostly useful
-for jobs that operate exclusively on artifacts (for example, `deploy`). Git repository
-data may be present, but it's certain to be out of date, so you should only
+`none` also re-uses the local working copy. However, it skips all Git operations,
+including GitLab Runner's pre-clone script, if present.
+
+It's useful for jobs that operate exclusively on artifacts, like a deployment job.
+Git repository data may be present, but it's likely out-of-date. You should only
rely on files brought into the local working copy from cache or artifacts.
```yaml
@@ -4222,10 +4255,10 @@ globally or per-job in the [`variables`](#variables) section.
There are three possible values: `none`, `normal`, and `recursive`:
-- `none` means that submodules won't be included when fetching the project
+- `none` means that submodules are not included when fetching the project
code. This is the default, which matches the pre-v1.10 behavior.
-- `normal` means that only the top-level submodules will be included. It's
+- `normal` means that only the top-level submodules are included. It's
equivalent to:
```shell
@@ -4234,7 +4267,7 @@ There are three possible values: `none`, `normal`, and `recursive`:
```
- `recursive` means that all submodules (including submodules of submodules)
- will be included. This feature needs Git v1.8.1 and later. When using a
+ are included. This feature needs Git v1.8.1 and later. When using a
GitLab Runner with an executor not based on Docker, make sure the Git version
meets that requirement. It's equivalent to:
@@ -4243,7 +4276,7 @@ There are three possible values: `none`, `normal`, and `recursive`:
git submodule update --init --recursive
```
-Note that for this feature to work correctly, the submodules must be configured
+For this feature to work correctly, the submodules must be configured
(in `.gitmodules`) with either:
- the HTTP(S) URL of a publicly-accessible repository, or
@@ -4259,15 +4292,15 @@ The `GIT_CHECKOUT` variable can be used when the `GIT_STRATEGY` is set to either
specified, it defaults to true. You can set them globally or per-job in the
[`variables`](#variables) section.
-If set to `false`, the runner will:
+If set to `false`, the runner:
-- when doing `fetch` - update the repository and leave working copy on
+- when doing `fetch` - updates the repository and leaves the working copy on
the current revision,
-- when doing `clone` - clone the repository and leave working copy on the
+- when doing `clone` - clones the repository and leaves the working copy on the
default branch.
-Having this setting set to `true` will mean that for both `clone` and `fetch`
-strategies the runner will checkout the working copy to a revision related
+If `GIT_CHECKOUT` is set to `true`, both `clone` and `fetch` work the same way.
+The runner checks out the working copy of a revision related
to the CI pipeline:
```yaml
@@ -4313,7 +4346,7 @@ script:
The `GIT_FETCH_EXTRA_FLAGS` variable is used to control the behavior of
`git fetch`. You can set it globally or per-job in the [`variables`](#variables) section.
-`GIT_FETCH_EXTRA_FLAGS` accepts all possible options of the [`git fetch`](https://git-scm.com/docs/git-fetch) command, but please note that `GIT_FETCH_EXTRA_FLAGS` flags will be appended after the default flags that can't be modified.
+`GIT_FETCH_EXTRA_FLAGS` accepts all options of the [`git fetch`](https://git-scm.com/docs/git-fetch) command. However, `GIT_FETCH_EXTRA_FLAGS` flags are appended after the default flags that can't be modified.
The default flags are:
@@ -4335,7 +4368,7 @@ script:
- ls -al cache/
```
-The configuration above will result in `git fetch` being called this way:
+The configuration above results in `git fetch` being called this way:
```shell
git fetch origin $REFSPECS --depth 50 --prune
@@ -4347,13 +4380,13 @@ Where `$REFSPECS` is a value provided to the runner internally by GitLab.
> Introduced in GitLab, it requires GitLab Runner v1.9+.
-You can set the number for attempts the running job will try to execute each
-of the following stages:
+You can set the number of attempts that the running job tries to execute
+the following stages:
| Variable | Description |
|-----------------------------------|--------------------------------------------------------|
| **ARTIFACT_DOWNLOAD_ATTEMPTS** | Number of attempts to download artifacts running a job |
-| **EXECUTOR_JOB_SECTION_ATTEMPTS** | [Since GitLab 12.10](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/4450), the number of attempts to run a section in a job after a [`No Such Container`](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/4450) error ([Docker executor](https://docs.gitlab.com/runner/executors/docker.html) only). |
+| **EXECUTOR_JOB_SECTION_ATTEMPTS** | [In GitLab 12.10](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/4450) and later, the number of attempts to run a section in a job after a [`No Such Container`](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/4450) error ([Docker executor](https://docs.gitlab.com/runner/executors/docker.html) only). |
| **GET_SOURCES_ATTEMPTS** | Number of attempts to fetch sources running a job |
| **RESTORE_CACHE_ATTEMPTS** | Number of attempts to restore the cache running a job |
@@ -4368,27 +4401,52 @@ variables:
You can set them globally or per-job in the [`variables`](#variables) section.
+### Fallback cache key
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-runner/-/merge_requests/1534) in GitLab Runner 13.4.
+
+You can use the `$CI_COMMIT_REF_SLUG` variable to specify your [`cache:key`](#cachekey).
+For example, if your `$CI_COMMIT_REF_SLUG` is `test` you can set a job
+to download cache that's tagged with `test`.
+
+If a cache with this tag is not found, you can use `CACHE_FALLBACK_KEY` to
+specify a cache to use when none exists.
+
+For example:
+
+```yaml
+variables:
+ CACHE_FALLBACK_KEY: fallback-key
+
+cache:
+ key: "$CI_COMMIT_REF_SLUG"
+ paths:
+ - binaries/
+```
+
+In this example, if the `$CI_COMMIT_REF_SLUG` is not found, the job uses the key defined
+by the `CACHE_FALLBACK_KEY` variable.
+
### Shallow cloning
> Introduced in GitLab 8.9 as an experimental feature.
-NOTE: **Note:**
-As of GitLab 12.0, newly created projects will automatically have a [default `git depth` value of `50`](../pipelines/settings.md#git-shallow-clone).
-
-You can specify the depth of fetching and cloning using `GIT_DEPTH`. This does a
-shallow clone of the repository and can significantly speed up cloning for
-repositories with a large number of commits or old, large binaries. The value is
+You can specify the depth of fetching and cloning using `GIT_DEPTH`.
+`GIT_DEPTH` does a shallow clone of the repository and can significantly speed up cloning.
+It can be helpful for repositories with a large number of commits or old, large binaries. The value is
passed to `git fetch` and `git clone`.
-NOTE: **Note:**
-If you use a depth of 1 and have a queue of jobs or retry
+In GitLab 12.0 and later, newly-created projects automatically have a
+[default `git depth` value of `50`](../pipelines/settings.md#git-shallow-clone).
+
+If you use a depth of `1` and have a queue of jobs or retry
jobs, jobs may fail.
-Since Git fetching and cloning is based on a ref, such as a branch name, runners
-can't clone a specific commit SHA. If there are multiple jobs in the queue, or
-you're retrying an old job, the commit to be tested needs to be within the
+Git fetching and cloning is based on a ref, such as a branch name, so runners
+can't clone a specific commit SHA. If multiple jobs are in the queue, or
+you're retrying an old job, the commit to be tested must be within the
Git history that is cloned. Setting too small a value for `GIT_DEPTH` can make
-it impossible to run these old commits. You will see `unresolved reference` in
+it impossible to run these old commits and `unresolved reference` is displayed in
job logs. You should then reconsider changing `GIT_DEPTH` to a higher value.
Jobs that rely on `git describe` may not work correctly when `GIT_DEPTH` is
@@ -4407,11 +4465,6 @@ You can set it globally or per-job in the [`variables`](#variables) section.
> [Introduced](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/2211) in GitLab Runner 11.10.
-NOTE: **Note:**
-This can only be used when `custom_build_dir` is enabled in the [runner's
-configuration](https://docs.gitlab.com/runner/configuration/advanced-configuration.html#the-runnerscustom_build_dir-section).
-This is the default configuration for `docker` and `kubernetes` executor.
-
By default, GitLab Runner clones the repository in a unique subpath of the
`$CI_BUILDS_DIR` directory. However, your project might require the code in a
specific directory (Go projects, for example). In that case, you can specify
@@ -4431,12 +4484,17 @@ The `GIT_CLONE_PATH` has to always be within `$CI_BUILDS_DIR`. The directory set
is dependent on executor and configuration of [runners.builds_dir](https://docs.gitlab.com/runner/configuration/advanced-configuration.html#the-runners-section)
setting.
+This can only be used when `custom_build_dir` is enabled in the
+[runner's configuration](https://docs.gitlab.com/runner/configuration/advanced-configuration.html#the-runnerscustom_build_dir-section).
+This is the default configuration for the `docker` and `kubernetes` executors.
+
#### Handling concurrency
-An executor using a concurrency greater than `1` might lead
-to failures because multiple jobs might be working on the same directory if the `builds_dir`
+An executor that uses a concurrency greater than `1` might lead
+to failures. Multiple jobs might be working on the same directory if the `builds_dir`
is shared between jobs.
-GitLab Runner does not try to prevent this situation. It's up to the administrator
+
+The runner does not try to prevent this situation. It's up to the administrator
and developers to comply with the requirements of runner configuration.
To avoid this scenario, you can use a unique path within `$CI_BUILDS_DIR`, because runner
@@ -4503,15 +4561,20 @@ need to be used to merge arrays.
> Introduced in GitLab 8.6 and GitLab Runner v1.1.1.
-YAML has a handy feature called 'anchors', which lets you easily duplicate
-content across your document. Anchors can be used to duplicate/inherit
-properties, and is a perfect example to be used with [hidden jobs](#hide-jobs)
-to provide templates for your jobs. When there is duplicate keys, GitLab will
-perform a reverse deep merge based on the keys.
+YAML has a feature called 'anchors' that you can use to duplicate
+content across your document.
+
+Use anchors to duplicate or inherit properties. Use anchors with [hidden jobs](#hide-jobs)
+to provide templates for your jobs. When there are duplicate keys, GitLab
+performs a reverse deep merge based on the keys.
+
+You can't use YAML anchors across multiple files when leveraging the [`include`](#include)
+feature. Anchors are only valid within the file they were defined in. Instead
+of using YAML anchors, you can use the [`extends` keyword](#extends).
-The following example uses anchors and map merging. It will create two jobs,
-`test1` and `test2`, that will inherit the parameters of `.job_template`, each
-having their own custom `script` defined:
+The following example uses anchors and map merging. It creates two jobs,
+`test1` and `test2`, that inherit the parameters of `.job_template`, each
+with their own custom `script` defined:
```yaml
.job_template: &job_definition # Hidden key that defines an anchor named 'job_definition'
@@ -4559,9 +4622,9 @@ test2:
- test2 project
```
-Let's see another one example. This time we will use anchors to define two sets
-of services. This will create two jobs, `test:postgres` and `test:mysql`, that
-will share the `script` directive defined in `.job_template`, and the `services`
+Let's see another example. This time we use anchors to define two sets
+of services. This configuration creates two jobs, `test:postgres` and `test:mysql`, that
+share the `script` directive defined in `.job_template`, and the `services`
directive defined in `.postgres_services` and `.mysql_services` respectively:
```yaml
@@ -4630,15 +4693,8 @@ test:mysql:
- dev
```
-You can see that the hidden jobs are conveniently used as templates.
-
-NOTE: **Note:**
-Note that `tags: [dev]` has been overwritten by `tags: [postgres]`.
-
-NOTE: **Note:**
-You can't use YAML anchors across multiple files when leveraging the [`include`](#include)
-feature. Anchors are only valid within the file they were defined in. Instead
-of using YAML anchors, you can use the [`extends` keyword](#extends).
+You can see that the hidden jobs are conveniently used as templates, and
+`tags: [dev]` has been overwritten by `tags: [postgres]`.
#### YAML anchors for `before_script` and `after_script`
@@ -4692,7 +4748,7 @@ job_name:
of variables across multiple jobs. It can also enable more flexibility when a job
requires a specific `variables` block that would otherwise override the global variables.
-In the example below, we will override the `GIT_STRATEGY` variable without affecting
+In the example below, we override the `GIT_STRATEGY` variable without affecting
the use of the `SAMPLE_VARIABLE` variable:
```yaml
@@ -4701,7 +4757,7 @@ variables: &global-variables
SAMPLE_VARIABLE: sample_variable_value
ANOTHER_SAMPLE_VARIABLE: another_sample_variable_value
-# a job that needs to set the GIT_STRATEGY variable, yet depend on global variables
+# a job that must set the GIT_STRATEGY variable, yet depend on global variables
job_no_git_strategy:
stage: cleanup
variables:
@@ -4723,8 +4779,8 @@ lines where the job is defined:
# - run test
```
-You can instead start its name with a dot (`.`) and it won't be processed by
-GitLab CI/CD. In the following example, `.hidden_job` will be ignored:
+Instead, you can start its name with a dot (`.`) and it is not processed by
+GitLab CI/CD. In the following example, `.hidden_job` is ignored:
```yaml
.hidden_job:
@@ -4739,18 +4795,18 @@ into templates.
## Skip Pipeline
If your commit message contains `[ci skip]` or `[skip ci]`, using any
-capitalization, the commit will be created but the pipeline will be skipped.
+capitalization, the commit is created but the pipeline is skipped.
Alternatively, one can pass the `ci.skip` [Git push option](../../user/project/push_options.md#push-options-for-gitlab-cicd)
if using Git 2.10 or newer.
## Processing Git pushes
-GitLab will create at most 4 branch and tag pipelines when
-pushing multiple changes in single `git push` invocation.
+GitLab creates at most four branch and tag pipelines when
+pushing multiple changes in a single `git push` invocation.
-This limitation does not affect any of the updated Merge Request pipelines.
-All updated Merge Requests will have a pipeline created when using
+This limitation does not affect any of the updated merge request pipelines.
+All updated merge requests have a pipeline created when using
[pipelines for merge requests](../merge_request_pipelines/index.md).
## Deprecated parameters
diff --git a/doc/ci/yaml/img/ci_config_visualization_hover_v13_5.png b/doc/ci/yaml/img/ci_config_visualization_hover_v13_5.png
new file mode 100644
index 00000000000..e6c85bd39e4
--- /dev/null
+++ b/doc/ci/yaml/img/ci_config_visualization_hover_v13_5.png
Binary files differ
diff --git a/doc/ci/yaml/img/ci_config_visualization_v13_5.png b/doc/ci/yaml/img/ci_config_visualization_v13_5.png
new file mode 100644
index 00000000000..0aee5cff7be
--- /dev/null
+++ b/doc/ci/yaml/img/ci_config_visualization_v13_5.png
Binary files differ
diff --git a/doc/ci/yaml/includes.md b/doc/ci/yaml/includes.md
index f7ed7248dc4..d7945617dc9 100644
--- a/doc/ci/yaml/includes.md
+++ b/doc/ci/yaml/includes.md
@@ -73,10 +73,11 @@ automatically fetched and evaluated along with the content of `.gitlab-ci.yml`.
Content of `https://gitlab.com/awesome-project/raw/master/.before-script-template.yml`:
```yaml
-before_script:
- - apt-get update -qq && apt-get install -y -qq sqlite3 libsqlite3-dev nodejs
- - gem install bundler --no-document
- - bundle install --jobs $(nproc) "${FLAGS[@]}"
+default:
+ before_script:
+ - apt-get update -qq && apt-get install -y -qq sqlite3 libsqlite3-dev nodejs
+ - gem install bundler --no-document
+ - bundle install --jobs $(nproc) "${FLAGS[@]}"
```
Content of `.gitlab-ci.yml`:
diff --git a/doc/ci/yaml/visualization.md b/doc/ci/yaml/visualization.md
new file mode 100644
index 00000000000..ac5f5c8fd14
--- /dev/null
+++ b/doc/ci/yaml/visualization.md
@@ -0,0 +1,46 @@
+# Visualize your CI/CD configuration
+
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/241722) in GitLab 13.5.
+> - It's [deployed behind a feature flag](../../user/feature_flags.md), disabled by default.
+> - It's disabled on GitLab.com.
+> - It's not recommended for production use.
+> - To use it in GitLab self-managed instances, ask a GitLab administrator to [enable it](#enable-or-disable-cicd-configuration-visualization). **(CORE ONLY)**
+
+CAUTION: **Warning:**
+This feature might not be available to you. Check the **version history** note above for details.
+
+To see a visualization of your `gitlab-ci.yml` configuration, navigate to any CI/CD
+configuration file and click on the `Visualization` tab. The visualization shows
+all stages and jobs. [`needs`](README.md#needs) relationships are displayed as lines
+connecting jobs together, showing the hierarchy of execution:
+
+![CI Config Visualization](img/ci_config_visualization_v13_5.png)
+
+Hovering on a job highlights its `needs` relationships:
+
+![CI Config Visualization on hover](img/ci_config_visualization_hover_v13_5.png)
+
+If the configuration does not have any `needs` relationships, then no lines are drawn because
+each job depends only on the previous stage being completed successfully.
+
+You can only preview one `gitlab-ci.yml` file at a time. Configuration imported with
+[`includes`](README.md#include) is ignored and not included in the visualization.
+
+## Enable or disable CI/CD configuration visualization **(CORE ONLY)**
+
+CI/CD configuration visualization is under development and not 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(:gitlab_ci_yml_preview)
+```
+
+To disable it:
+
+```ruby
+Feature.disable(:gitlab_ci_yml_preview)
+```
diff --git a/doc/container_registry/README.md b/doc/container_registry/README.md
deleted file mode 100644
index b98d1b51999..00000000000
--- a/doc/container_registry/README.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../user/packages/container_registry/index.md'
----
-
-This document was moved to [another location](../user/packages/container_registry/index.md).
diff --git a/doc/container_registry/troubleshooting.md b/doc/container_registry/troubleshooting.md
deleted file mode 100644
index 092d7831e35..00000000000
--- a/doc/container_registry/troubleshooting.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../user/packages/container_registry/index.md#troubleshooting-the-gitlab-container-registry'
----
-
-This document was moved to [user/project/container_registry](../user/packages/container_registry/index.md#troubleshooting-the-gitlab-container-registry).
diff --git a/doc/customization/welcome_message.md b/doc/customization/welcome_message.md
index 45f1fed355e..9667e5e380a 100644
--- a/doc/customization/welcome_message.md
+++ b/doc/customization/welcome_message.md
@@ -1,5 +1,5 @@
---
-redirect_to: 'branded_login_page.md'
+redirect_to: '../user/admin_area/appearance.md#sign-in--sign-up-pages'
---
-This document was moved to [another location](branded_login_page.md).
+This document was moved to [another location](../user/admin_area/appearance.md#sign-in--sign-up-pages).
diff --git a/doc/development/README.md b/doc/development/README.md
index abdd5c662f3..7b8a5cd5f75 100644
--- a/doc/development/README.md
+++ b/doc/development/README.md
@@ -43,6 +43,7 @@ For information on how to install, configure, update, and upgrade your own GitLa
**Must-reads:**
+- [Guide on adapting existing and introducing new components](architecture.md#adapting-existing-and-introducing-new-components)
- [Code review guidelines](code_review.md) for reviewing code and having code reviewed
- [Database review guidelines](database_review.md) for reviewing database-related changes and complex SQL queries, and having them reviewed
- [Secure coding guidelines](secure_coding_guidelines.md)
@@ -115,6 +116,7 @@ Complementary reads:
- [Code Intelligence](code_intelligence/index.md)
- [Approval Rules](approval_rules.md)
- [Feature categorization](feature_categorization/index.md)
+- [Wikis development guide](wikis.md)
## Performance guides
@@ -163,11 +165,11 @@ See [database guidelines](database/index.md).
- [Externalization](i18n/externalization.md)
- [Translation](i18n/translation.md)
-## Telemetry guides
+## Product Analytics guides
-- [Telemetry guide](telemetry/index.md)
-- [Usage Ping guide](telemetry/usage_ping.md)
-- [Snowplow guide](telemetry/snowplow.md)
+- [Product Analytics guide](product_analytics/index.md)
+- [Usage Ping guide](product_analytics/usage_ping.md)
+- [Snowplow guide](product_analytics/snowplow.md)
## Experiment guide
diff --git a/doc/development/adding_database_indexes.md b/doc/development/adding_database_indexes.md
index 03557491e68..d2526d6c4f2 100644
--- a/doc/development/adding_database_indexes.md
+++ b/doc/development/adding_database_indexes.md
@@ -1,3 +1,9 @@
+---
+stage: Enablement
+group: Database
+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/#designated-technical-writers
+---
+
# Adding Database Indexes
Indexes can be used to speed up database queries, but when should you add a new
diff --git a/doc/development/adding_service_component.md b/doc/development/adding_service_component.md
index 2801e27145d..bb5af286c1d 100644
--- a/doc/development/adding_service_component.md
+++ b/doc/development/adding_service_component.md
@@ -46,7 +46,7 @@ TIP: **Tip:**
**For services that depend on the existing GitLab codebase:**
-The first iteration should be opt-in, either through the `gitlab.yml` configuration or through [feature flags](feature_flags.md). For these types of services it is often necessary to [bundle the service and its dependencies with GitLab](#bundling-a-service-with-gitlab) as part of the initial integration.
+The first iteration should be opt-in, either through the `gitlab.yml` configuration or through [feature flags](feature_flags/index.md). For these types of services it is often necessary to [bundle the service and its dependencies with GitLab](#bundling-a-service-with-gitlab) as part of the initial integration.
TIP: **Tip:**
[ActionCable](https://docs.gitlab.com/omnibus/settings/actioncable.html) is an example of a service that has been added this way.
diff --git a/doc/development/api_graphql_styleguide.md b/doc/development/api_graphql_styleguide.md
index 18fc0fb7d33..3d4c033e676 100644
--- a/doc/development/api_graphql_styleguide.md
+++ b/doc/development/api_graphql_styleguide.md
@@ -49,6 +49,20 @@ See also:
- [Exposing Global IDs](#exposing-global-ids).
- [Mutation arguments](#object-identifier-arguments).
+We have a custom scalar type (`Types::GlobalIDType`) which should be used as the
+type of input and output arguments when the value is a `GlobalID`. The benefits
+of using this type instead of `ID` are:
+
+- it validates that the value is a `GlobalID`
+- it parses it into a `GlobalID` before passing it to user code
+- it can be parameterized on the type of the object (e.g.
+ `GlobalIDType[Project]`) which offers even better validation and security.
+
+Consider using this type for all new arguments and result types. Remember that
+it is perfectly possible to parameterize this type with a concern or a
+supertype, if you want to accept a wider range of objects (e.g.
+`GlobalIDType[Issuable]` vs `GlobalIDType[Issue]`).
+
## Types
We use a code-first schema, and we declare what type everything is in Ruby.
@@ -371,8 +385,8 @@ end
GitLab's GraphQL API is versionless, which means we maintain backwards
compatibility with older versions of the API with every change. Rather
than removing a field or [enum value](#enums), we need to _deprecate_ it instead.
-In future, GitLab
-[may remove deprecated parts of the schema](https://gitlab.com/gitlab-org/gitlab/-/issues/32292).
+The deprecated parts of the schema can then be removed in a future release
+in accordance with [GitLab's deprecation process](../api/graphql/index.md#deprecation-process).
Fields and enum values are deprecated using the `deprecated` property.
The value of the property is a `Hash` of:
@@ -472,6 +486,28 @@ end
Enum values can be deprecated using the
[`deprecated` keyword](#deprecating-fields-and-enum-values).
+### Defining GraphQL enums dynamically from Rails enums
+
+If your GraphQL enum is backed by a [Rails enum](creating_enums.md), then consider
+using the Rails enum to dynamically define the GraphQL enum values. Doing so
+binds the GraphQL enum values to the Rails enum definition, so if values are
+ever added to the Rails enum then the GraphQL enum automatically reflects the change.
+
+Example:
+
+```ruby
+module Types
+ class IssuableSeverityEnum < BaseEnum
+ graphql_name 'IssuableSeverity'
+ description 'Incident severity'
+
+ ::IssuableSeverity.severities.keys.each do |severity|
+ value severity.upcase, value: severity, description: "#{severity.titleize} severity"
+ end
+ end
+end
+```
+
## JSON
When data to be returned by GraphQL is stored as
@@ -780,6 +816,25 @@ to advertise the need for lookahead:
For an example of real world use, please
see [`ResolvesMergeRequests`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/graphql/resolvers/concerns/resolves_merge_requests.rb).
+### Negated arguments
+
+Negated filters can filter some resources (for example, find all issues that
+have the `bug` label, but don't have the `bug2` label assigned). The `not`
+argument is the preferred syntax to pass negated arguments:
+
+```graphql
+issues(labelName: "bug", not: {labelName: "bug2"}) {
+ nodes {
+ id
+ title
+ }
+}
+```
+
+To avoid duplicated argument definitions, you can place these arguments in a reusable module (or
+class, if the arguments are nested). Alternatively, you can consider to add a
+[helper resolver method](https://gitlab.com/gitlab-org/gitlab/-/issues/258969).
+
## Pass a parent object into a child Presenter
Sometimes you need to access the resolved query parent in a child context to compute fields. Usually the parent is only
@@ -827,10 +882,39 @@ mutation.
### Building Mutations
-Mutations live in `app/graphql/mutations` ideally grouped per
+Mutations are stored in `app/graphql/mutations`, ideally grouped per
resources they are mutating, similar to our services. They should
inherit `Mutations::BaseMutation`. The fields defined on the mutation
-will be returned as the result of the mutation.
+are returned as the result of the mutation.
+
+#### Update mutation granularity
+
+GitLab's service-oriented architecture means that most mutations call a Create, Delete, or Update
+service, for example `UpdateMergeRequestService`.
+For Update mutations, a you might want to only update one aspect of an object, and thus only need a
+_fine-grained_ mutation, for example `MergeRequest::SetWip`.
+
+It's acceptable to have both fine-grained mutations and coarse-grained mutations, but be aware
+that too many fine-grained mutations can lead to organizational challenges in maintainability, code
+comprehensibility, and testing.
+Each mutation requires a new class, which can lead to technical debt.
+It also means the schema becomes very big, and we want users to easily navigate our schema.
+As each new mutation also needs tests (including slower request integration tests), adding mutations
+slows down the test suite.
+
+To minimize changes:
+
+- Use existing mutations, such as `MergeRequest::Update`, when available.
+- Expose existing services as a coarse-grained mutation.
+
+When a fine-grained mutation might be more appropriate:
+
+- Modifying a property that requires specific permissions or other specialized logic.
+- Exposing a state-machine-like transition (locking issues, merging MRs, closing epics, etc).
+- Accepting nested properties (where we accept properties for a child object).
+- The semantics of the mutation can be expressed clearly and concisely.
+
+See [issue #233063](https://gitlab.com/gitlab-org/gitlab/-/issues/233063) for further context.
### Naming conventions
@@ -1361,5 +1445,4 @@ For information on generating GraphQL documentation and schema files, see
[updating the schema documentation](rake_tasks.md#update-graphql-documentation-and-schema-definitions).
To help our readers, you should also add a new page to our [GraphQL API](../api/graphql/index.md) documentation.
-For guidance, see the [GraphQL API](documentation/styleguide.md#graphql-api) section
-of our documentation style guide.
+For guidance, see the [GraphQL API](documentation/graphql_styleguide.md) page.
diff --git a/doc/development/api_styleguide.md b/doc/development/api_styleguide.md
index 400752c69e9..47c06377d88 100644
--- a/doc/development/api_styleguide.md
+++ b/doc/development/api_styleguide.md
@@ -17,7 +17,7 @@ Each new or updated API endpoint must come with documentation, unless it is inte
The docs should be in the same merge request, or, if strictly necessary,
in a follow-up with the same milestone as the original merge request.
-See the [Documentation Style Guide RESTful API section](documentation/styleguide.md#restful-api) for details on documenting API resources in Markdown as well as in OpenAPI definition files.
+See the [Documentation Style Guide RESTful API page](documentation/restful_api_styleguide.md) for details on documenting API resources in Markdown as well as in OpenAPI definition files.
## Methods and parameters description
diff --git a/doc/development/architecture.md b/doc/development/architecture.md
index f6b1c8cd914..513af491576 100644
--- a/doc/development/architecture.md
+++ b/doc/development/architecture.md
@@ -1,32 +1,91 @@
-# GitLab Architecture Overview
+# GitLab architecture overview
## Software delivery
-There are two software distributions of GitLab: the open source [Community Edition](https://gitlab.com/gitlab-org/gitlab-foss/) (CE), and the open core [Enterprise Edition](https://gitlab.com/gitlab-org/gitlab/) (EE). GitLab is available under [different subscriptions](https://about.gitlab.com/pricing/).
+There are two software distributions of GitLab:
-New versions of GitLab are released in stable branches and the master branch is for bleeding edge development.
+- The open source [Community Edition](https://gitlab.com/gitlab-org/gitlab-foss/) (CE).
+- The open core [Enterprise Edition](https://gitlab.com/gitlab-org/gitlab/) (EE).
-For information, see the [GitLab Release Process](https://gitlab.com/gitlab-org/release/docs/-/tree/master#gitlab-release-process).
+GitLab is available under [different subscriptions](https://about.gitlab.com/pricing/).
-Both EE and CE require some add-on components called GitLab Shell and Gitaly. These components are available from the [GitLab Shell](https://gitlab.com/gitlab-org/gitlab-shell/-/tree/master) and [Gitaly](https://gitlab.com/gitlab-org/gitaly/-/tree/master) repositories respectively. New versions are usually tags but staying on the master branch will give you the latest stable version. New releases are generally around the same time as GitLab CE releases with the exception of informal security updates deemed critical.
+New versions of GitLab are released from stable branches, and the `master` branch is used for
+bleeding-edge development.
+
+For more information, visit the [GitLab Release Process](https://about.gitlab.com/handbook/engineering/releases/).
+
+Both distributions require additional components. These components are described in the
+[Component details](#components) section, and all have their own repositories.
+New versions of each dependent component are usually tags, but staying on the `master` branch of the
+GitLab codebase gives you the latest stable version of those components. New versions are
+generally released around the same time as GitLab releases, with the exception of informal security
+updates deemed critical.
## Components
-A typical install of GitLab will be on GNU/Linux. It uses NGINX or Apache as a web front end to proxypass the Unicorn web server. By default, communication between Unicorn and the front end is via a Unix domain socket but forwarding requests via TCP is also supported. The web front end accesses `/home/git/gitlab/public` bypassing the Unicorn server to serve static pages, uploads (e.g. avatar images or attachments), and pre-compiled assets. GitLab serves web pages and the [GitLab API](../api/README.md) using the Unicorn web server. It uses Sidekiq as a job queue which, in turn, uses Redis as a non-persistent database backend for job information, meta data, and incoming jobs.
+A typical install of GitLab is on GNU/Linux, but growing number of deployments also use the
+Kubernetes platform. The largest known GitLab instance is on GitLab.com, which is deployed using our
+[official GitLab Helm chart](https://docs.gitlab.com/charts/) and the [official Linux package](https://about.gitlab.com/install/).
-We also support deploying GitLab on Kubernetes using our [GitLab Helm chart](https://docs.gitlab.com/charts/).
+A typical installation uses NGINX or Apache as a web server to proxy through
+[GitLab Workhorse](https://gitlab.com/gitlab-org/gitlab-workhorse) and into the [Puma](https://puma.io)
+application server. GitLab serves web pages and the [GitLab API](../api/README.md) using the Puma
+application server. It uses Sidekiq as a job queue which, in turn, uses Redis as a non-persistent
+database backend for job information, metadata, and incoming jobs.
-The GitLab web app uses PostgreSQL for persistent database information (e.g. users, permissions, issues, other meta data). GitLab stores the bare Git repositories it serves in `/home/git/repositories` by default. It also keeps default branch and hook information with the bare repository.
+By default, communication between Puma and Workhorse is via a Unix domain socket, but forwarding
+requests via TCP is also supported. Workhorse accesses the `gitlab/public` directory, bypassing the
+Puma application server to serve static pages, uploads (for example, avatar images or attachments),
+and pre-compiled assets.
-When serving repositories over HTTP/HTTPS GitLab utilizes the GitLab API to resolve authorization and access as well as serving Git objects.
+The GitLab application uses PostgreSQL for persistent database information (for example, users,
+permissions, issues, or other metadata). GitLab stores the bare Git repositories in the location
+defined in [the configuration file, `repositories:` section](https://gitlab.com/gitlab-org/gitlab/blob/master/config/gitlab.yml.example).
+It also keeps default branch and hook information with the bare repository.
-The add-on component GitLab Shell serves repositories over SSH. It manages the SSH keys within `/home/git/.ssh/authorized_keys` which should not be manually edited. GitLab Shell accesses the bare repositories through Gitaly to serve Git objects and communicates with Redis to submit jobs to Sidekiq for GitLab to process. GitLab Shell queries the GitLab API to determine authorization and access.
+When serving repositories over HTTP/HTTPS GitLab uses the GitLab API to resolve authorization and
+access and to serve Git objects.
-Gitaly executes Git operations from GitLab Shell and the GitLab web app, and provides an API to the GitLab web app to get attributes from Git (e.g. title, branches, tags, other meta data), and to get blobs (e.g. diffs, commits, files).
+The add-on component GitLab Shell serves repositories over SSH. It manages the SSH keys within the
+location defined in [the configuration file, `GitLab Shell` section](https://gitlab.com/gitlab-org/gitlab/blob/master/config/gitlab.yml.example).
+The file in that location should never be manually edited. GitLab Shell accesses the bare
+repositories through Gitaly to serve Git objects, and communicates with Redis to submit jobs to
+Sidekiq for GitLab to process. GitLab Shell queries the GitLab API to determine authorization and access.
+
+Gitaly executes Git operations from GitLab Shell and the GitLab web app, and provides an API to the
+GitLab web app to get attributes from Git (for example, title, branches, tags, or other metadata),
+and to get blobs (for example, diffs, commits, or files).
You may also be interested in the [production architecture of GitLab.com](https://about.gitlab.com/handbook/engineering/infrastructure/production/architecture/).
-### Simplified Component Overview
+## Adapting existing and introducing new components
+
+There are fundamental differences in how the application behaves when it is installed on a
+traditional Linux machine compared to a containerized platform, such as Kubernetes.
+
+Compared to [our official installation methods](https://about.gitlab.com/install/), some of the
+notable differences are:
+
+- Official Linux packages can access files on the same file system with different services.
+ [Shared files](shared_files.md) are not an option for the application running on the Kubernetes
+ platform.
+- Official Linux packages by default have services that have access to the shared configuration and
+ network. This is not the case for services running in Kubernetes, where services might be running
+ in complete isolation, or only accessible through specific ports.
+
+In other words, the shared state between services needs to be carefully considered when
+architecting new features and adding new components. Services that need to have access to the same
+files, need to be able to exchange information through the appropriate APIs. Whenever possible,
+this should not be done with files.
+
+Since components written with the API-first philosophy in mind are compatible with both methods, all
+new features and services must be written to consider Kubernetes compatibility **first**.
+
+The simplest way to ensure this, is to add support for your feature or service to
+[the official GitLab Helm chart](https://docs.gitlab.com/charts/) or reach out to
+[the Distribution team](https://about.gitlab.com/handbook/engineering/development/enablement/distribution/#how-to-work-with-distribution).
+
+### Simplified component overview
This is a simplified architecture diagram that can be used to
understand GitLab's architecture.
@@ -51,23 +110,25 @@ SSH -- TCP 22 --> GitLabShell[GitLab Shell]
SMTP[SMTP Gateway]
Geo[GitLab Geo Node] -- TCP 22, 80, 443 --> NGINX
-GitLabShell --TCP 8080 -->Unicorn["Unicorn (GitLab Rails)"]
+GitLabShell --TCP 8080 -->Puma["Puma (GitLab Rails)"]
GitLabShell --> Praefect
-Unicorn --> PgBouncer[PgBouncer]
-Unicorn --> Redis
-Unicorn --> Praefect
+Puma --> PgBouncer[PgBouncer]
+Puma --> Redis
+Puma --> Praefect
Sidekiq --> Redis
Sidekiq --> PgBouncer
Sidekiq --> Praefect
-GitLabWorkhorse[GitLab Workhorse] --> Unicorn
+GitLabWorkhorse[GitLab Workhorse] --> Puma
GitLabWorkhorse --> Redis
GitLabWorkhorse --> Praefect
Praefect --> Gitaly
NGINX --> GitLabWorkhorse
NGINX -- TCP 8090 --> GitLabPages[GitLab Pages]
NGINX --> Grafana[Grafana]
+NGINX -- TCP 8150 --> GitLabKas[GitLab Kubernetes Agent Server]
+GitLabKas --> Praefect
Grafana -- TCP 9090 --> Prometheus[Prometheus]
-Prometheus -- TCP 80, 443 --> Unicorn
+Prometheus -- TCP 80, 443 --> Puma
RedisExporter[Redis Exporter] --> Redis
Prometheus -- TCP 9121 --> RedisExporter
PostgreSQLExporter[PostgreSQL Exporter] --> PostgreSQL
@@ -83,27 +144,27 @@ PgBouncer --> Consul
PostgreSQL --> Consul
PgBouncer --> PostgreSQL
NGINX --> Registry
-Unicorn --> Registry
+Puma --> Registry
NGINX --> Mattermost
-Mattermost --- Unicorn
+Mattermost --- Puma
Prometheus --> Alertmanager
Migrations --> PostgreSQL
Runner -- TCP 443 --> NGINX
-Unicorn -- TCP 9200 --> Elasticsearch
+Puma -- TCP 9200 --> Elasticsearch
Sidekiq -- TCP 9200 --> Elasticsearch
Sidekiq -- TCP 80, 443 --> Sentry
-Unicorn -- TCP 80, 443 --> Sentry
+Puma -- TCP 80, 443 --> Sentry
Sidekiq -- UDP 6831 --> Jaeger
-Unicorn -- UDP 6831 --> Jaeger
+Puma -- UDP 6831 --> Jaeger
Gitaly -- UDP 6831 --> Jaeger
GitLabShell -- UDP 6831 --> Jaeger
GitLabWorkhorse -- UDP 6831 --> Jaeger
Alertmanager -- TCP 25 --> SMTP
Sidekiq -- TCP 25 --> SMTP
-Unicorn -- TCP 25 --> SMTP
-Unicorn -- TCP 369 --> LDAP
+Puma -- TCP 25 --> SMTP
+Puma -- TCP 369 --> LDAP
Sidekiq -- TCP 369 --> LDAP
-Unicorn -- TCP 443 --> ObjectStorage["Object Storage"]
+Puma -- TCP 443 --> ObjectStorage["Object Storage"]
Sidekiq -- TCP 443 --> ObjectStorage
GitLabWorkhorse -- TCP 443 --> ObjectStorage
Registry -- TCP 443 --> ObjectStorage
@@ -121,7 +182,7 @@ click Gitaly "./architecture.html#gitaly"
click Jaeger "./architecture.html#jaeger"
click GitLabWorkhorse "./architecture.html#gitlab-workhorse"
click LDAP "./architecture.html#ldap-authentication"
-click Unicorn "./architecture.html#unicorn"
+click Puma "./architecture.html#puma"
click GitLabShell "./architecture.html#gitlab-shell"
click SSH "./architecture.html#ssh-request-22"
click Sidekiq "./architecture.html#sidekiq"
@@ -175,6 +236,7 @@ Table description links:
| [GitLab Geo Node](#gitlab-geo) | Geographically distributed GitLab nodes | ⚙ | ⚙ | ⌠| ✅ | ⌠| ⚙ | EE Only |
| [GitLab Managed Apps](#gitlab-managed-apps) | Deploy Helm, Ingress, Cert-Manager, Prometheus, GitLab Runner, JupyterHub, or Knative to a cluster | ⤓ | ⤓ | ⤓ | ⤓ | ⤓ | ⤓ | CE & EE |
| [GitLab Pages](#gitlab-pages) | Hosts static websites | ⚙ | ⌠| ⌠| ✅ | ⚙ | ⚙ | CE & EE |
+| [GitLab Kubernetes Agent](#gitlab-kubernetes-agent) | Integrate Kubernetes clusters in a cloud-native way | ⚙ | ⚙ | ⌠| ⌠| ⤓ | ⚙ | EE Only |
| [GitLab self-monitoring: Alertmanager](#alertmanager) | Deduplicates, groups, and routes alerts from Prometheus | ⚙ | ✅ | ⚙ | ✅ | ⌠| ⌠| CE & EE |
| [GitLab self-monitoring: Grafana](#grafana) | Metrics dashboard | ✅ | ⚙ | ⤓ | ✅ | ⌠| ⌠| CE & EE |
| [GitLab self-monitoring: Jaeger](#jaeger) | View traces generated by the GitLab instance | ⌠| ⚙ | ⌠| ⌠| ⤓ | ⚙ | CE & EE |
@@ -201,7 +263,7 @@ Table description links:
| [Runner](#gitlab-runner) | Executes GitLab CI/CD jobs | ⤓ | ✅ | ⚙ | ✅ | ⚙ | ⚙ | CE & EE |
| [Sentry integration](#sentry) | Error tracking for deployed apps | ⤓ | ⤓ | ⤓ | ⤓ | ⤓ | ⤓ | CE & EE |
| [Sidekiq](#sidekiq) | Background jobs processor | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | CE & EE |
-| [Unicorn (GitLab Rails)](#unicorn) | Handles requests for the web interface and API | ✅ | ✅ | ✅ | ✅ | ⚙ | ✅ | CE & EE |
+| [Puma (GitLab Rails)](#puma) | Handles requests for the web interface and API | ✅ | ✅ | ✅ | ✅ | ⚙ | ✅ | CE & EE |
### Component details
@@ -271,7 +333,7 @@ Consul is a tool for service discovery and configuration. Consul is distributed,
- [Source](../integration/elasticsearch.md)
- [GDK](https://gitlab.com/gitlab-org/gitlab-development-kit/blob/master/doc/howto/elasticsearch.md)
- Layer: Core Service (Data)
-- GitLab.com: [Get Advanced Global Search working on GitLab.com](https://gitlab.com/groups/gitlab-org/-/epics/153) epic.
+- GitLab.com: [Get Advanced Search working on GitLab.com](https://gitlab.com/groups/gitlab-org/-/epics/153) epic.
Elasticsearch is a distributed RESTful search engine built for the cloud.
@@ -321,6 +383,19 @@ repository updates to secondary nodes.
GitLab Exporter is a process designed in house that allows us to export metrics about GitLab application internals to Prometheus. You can read more [in the project's README](https://gitlab.com/gitlab-org/gitlab-exporter).
+#### GitLab Kubernetes Agent
+
+- [Project page](https://gitlab.com/gitlab-org/cluster-integration/gitlab-agent)
+- Configuration:
+ - [Omnibus](https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/files/gitlab-config-template/gitlab.rb.template)
+ - [Charts](https://docs.gitlab.com/charts/charts/gitlab/kas/index.html)
+
+[GitLab Kubernetes Agent](../user/clusters/agent/index.md) is an active in-cluster
+component for solving GitLab and Kubernetes integration tasks in a secure and
+cloud-native way.
+
+You can use it to sync deployments onto your Kubernetes cluster.
+
#### GitLab Pages
- Configuration:
@@ -368,13 +443,13 @@ GitLab CI/CD is the open-source continuous integration service included with Git
- [Project page](https://gitlab.com/gitlab-org/gitlab-workhorse/blob/master/README.md)
- Configuration:
- [Omnibus](https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/files/gitlab-config-template/gitlab.rb.template)
- - [Charts](https://docs.gitlab.com/charts/charts/gitlab/unicorn/)
+ - [Charts](https://docs.gitlab.com/charts/charts/gitlab/webservice/)
- [Source](../install/installation.md#install-gitlab-workhorse)
- Layer: Core Service (Processor)
- Process: `gitlab-workhorse`
- GitLab.com: [Service Architecture](https://about.gitlab.com/handbook/engineering/infrastructure/production/architecture/#service-architecture)
-[GitLab Workhorse](https://gitlab.com/gitlab-org/gitlab-workhorse) is a program designed at GitLab to help alleviate pressure from Unicorn. You can read more about the [historical reasons for developing](https://about.gitlab.com/blog/2016/04/12/a-brief-history-of-gitlab-workhorse/). It's designed to act as a smart reverse proxy to help speed up GitLab as a whole.
+[GitLab Workhorse](https://gitlab.com/gitlab-org/gitlab-workhorse) is a program designed at GitLab to help alleviate pressure from Puma. You can read more about the [historical reasons for developing](https://about.gitlab.com/blog/2016/04/12/a-brief-history-of-gitlab-workhorse/). It's designed to act as a smart reverse proxy to help speed up GitLab as a whole.
#### Grafana
@@ -411,7 +486,8 @@ For monitoring deployed apps, see [Jaeger tracing documentation](../operations/t
- Layer: Core Service
- Process: `logrotate`
-GitLab is comprised of a large number of services that all log. We started bundling our own logrotate as of 7.4 to make sure we were logging responsibly. This is just a packaged version of the common open source offering.
+GitLab is comprised of a large number of services that all log. We started bundling our own Logrotate
+as of GitLab 7.4 to make sure we were logging responsibly. This is just a packaged version of the common open source offering.
#### Mattermost
@@ -560,7 +636,7 @@ Redis is packaged to provide a place to store:
- [Source](../administration/packages/container_registry.md#enable-the-container-registry)
- [GDK](https://gitlab.com/gitlab-org/gitlab-development-kit/blob/master/doc/howto/registry.md)
- Layer: Core Service (Processor)
-- GitLab.com: [GitLab Container Registry](../user/packages/container_registry/index.md#build-and-push-images-using-gitlab-cicd)
+- GitLab.com: [GitLab Container Registry](../user/packages/container_registry/index.md#build-and-push-by-using-gitlab-cicd)
The registry is what users use to store their own Docker images. The bundled
registry uses NGINX as a load balancer and GitLab as an authentication manager.
@@ -603,8 +679,30 @@ For monitoring deployed apps, see the [Sentry integration docs](../operations/er
Sidekiq is a Ruby background job processor that pulls jobs from the Redis queue and processes them. Background jobs allow GitLab to provide a faster request/response cycle by moving work into the background.
+#### Puma
+
+NOTE: **Note:**
+Starting with GitLab 13.0, Puma is the default web server and Unicorn has been
+disabled by default.
+
+- [Project page](https://gitlab.com/gitlab-org/gitlab/blob/master/README.md)
+- Configuration:
+ - [Omnibus](https://docs.gitlab.com/omnibus/settings/puma.html)
+ - [Charts](https://docs.gitlab.com/charts/charts/gitlab/webservice/)
+ - [Source](../install/installation.md#configure-it)
+ - [GDK](https://gitlab.com/gitlab-org/gitlab/blob/master/config/gitlab.yml.example)
+- Layer: Core Service (Processor)
+- Process: `puma`
+- GitLab.com: [Puma](../user/gitlab_com/index.md#puma)
+
+[Puma](https://puma.io/) is a Ruby application server that is used to run the core Rails Application that provides the user facing features in GitLab. Often process output you will see this as `bundle` or `config.ru` depending on the GitLab version.
+
#### Unicorn
+NOTE: **Note:**
+Starting with GitLab 13.0, Puma is the default web server and Unicorn has been
+disabled by default.
+
- [Project page](https://gitlab.com/gitlab-org/gitlab/blob/master/README.md)
- Configuration:
- [Omnibus](https://docs.gitlab.com/omnibus/settings/unicorn.html)
@@ -669,7 +767,7 @@ You can install them after you create a cluster. This includes:
- [JupyterHub](https://jupyter.org)
- [Knative](https://cloud.google.com/knative/)
-## GitLab by Request Type
+## GitLab by request type
GitLab provides two "interfaces" for end users to access the service:
@@ -678,20 +776,20 @@ GitLab provides two "interfaces" for end users to access the service:
It's important to understand the distinction as some processes are used in both and others are exclusive to a specific request type.
-### GitLab Web HTTP Request Cycle
+### GitLab Web HTTP request cycle
When making a request to an HTTP Endpoint (think `/users/sign_in`) the request will take the following path through the GitLab Service:
- NGINX - Acts as our first line reverse proxy.
-- GitLab Workhorse - This determines if it needs to go to the Rails application or somewhere else to reduce load on Unicorn.
-- Unicorn - Since this is a web request, and it needs to access the application it will go to Unicorn.
+- GitLab Workhorse - This determines if it needs to go to the Rails application or somewhere else to reduce load on Puma.
+- Puma - Since this is a web request, and it needs to access the application it will go to Puma.
- PostgreSQL/Gitaly/Redis - Depending on the type of request, it may hit these services to store or retrieve data.
-### GitLab Git Request Cycle
+### GitLab Git request cycle
Below we describe the different paths that HTTP vs. SSH Git requests will take. There is some overlap with the Web Request Cycle but also some differences.
-### Web Request (80/443)
+### Web request (80/443)
Git operations over HTTP use the stateless "smart" protocol described in the
[Git documentation](https://git-scm.com/docs/http-protocol), but responsibility
@@ -736,7 +834,7 @@ sequenceDiagram
The sequence is similar for `git push`, except `git-receive-pack` is used
instead of `git-upload-pack`.
-### SSH Request (22)
+### SSH request (22)
Git operations over SSH can use the stateful protocol described in the
[Git documentation](https://git-scm.com/docs/pack-protocol#_ssh_transport), but
@@ -801,7 +899,7 @@ except there is no round-trip into Gitaly - Rails performs the action as part
of the [internal API](internal_api.md) call, and GitLab Shell streams the
response back to the user directly.
-## System Layout
+## System layout
When referring to `~git` in the pictures it means the home directory of the Git user which is typically `/home/git`.
@@ -811,9 +909,9 @@ The bare repositories are located in `/home/git/repositories`. GitLab is a Ruby
To serve repositories over SSH there's an add-on application called GitLab Shell which is installed in `/home/git/gitlab-shell`.
-### Installation Folder Summary
+### Installation folder summary
-To summarize here's the [directory structure of the `git` user home directory](../install/structure.md).
+To summarize here's the [directory structure of the `git` user home directory](../install/installation.md#gitlab-directory-structure).
### Processes
@@ -823,12 +921,12 @@ ps aux | grep '^git'
GitLab has several components to operate. It requires a persistent database
(PostgreSQL) and Redis database, and uses Apache `httpd` or NGINX to proxypass
-Unicorn. All these components should run as different system users to GitLab
-(e.g., `postgres`, `redis` and `www-data`, instead of `git`).
+Puma. All these components should run as different system users to GitLab
+(for example, `postgres`, `redis`, and `www-data`, instead of `git`).
-As the `git` user it starts Sidekiq and Unicorn (a simple Ruby HTTP server
+As the `git` user it starts Sidekiq and Puma (a simple Ruby HTTP server
running on port `8080` by default). Under the GitLab user there are normally 4
-processes: `unicorn_rails master` (1 process), `unicorn_rails worker`
+processes: `puma master` (1 process), `puma cluster worker`
(2 processes), `sidekiq` (1 process).
### Repository access
@@ -841,7 +939,7 @@ See the README for more information.
### Init scripts of the services
-The GitLab init script starts and stops Unicorn and Sidekiq:
+The GitLab init script starts and stops Puma and Sidekiq:
```plaintext
/etc/init.d/gitlab
@@ -881,9 +979,9 @@ Usage: /etc/init.d/postgresql {start|stop|restart|reload|force-reload|status} [v
### Log locations of the services
-GitLab (includes Unicorn and Sidekiq logs):
+GitLab (includes Puma and Sidekiq logs):
-- `/home/git/gitlab/log/` contains `application.log`, `production.log`, `sidekiq.log`, `unicorn.stdout.log`, `git_json.log` and `unicorn.stderr.log` normally.
+- `/home/git/gitlab/log/` contains `application.log`, `production.log`, `sidekiq.log`, `puma.stdout.log`, `git_json.log` and `puma.stderr.log` normally.
GitLab Shell:
@@ -914,17 +1012,18 @@ PostgreSQL:
### GitLab specific configuration files
-GitLab has configuration files located in `/home/git/gitlab/config/*`. Commonly referenced config files include:
+GitLab has configuration files located in `/home/git/gitlab/config/*`. Commonly referenced
+configuration files include:
-- `gitlab.yml` - GitLab configuration.
-- `unicorn.rb` - Unicorn web server settings.
-- `database.yml` - Database connection settings.
+- `gitlab.yml` - GitLab configuration
+- `puma.rb` - Puma web server settings
+- `database.yml` - Database connection settings
GitLab Shell has a configuration file at `/home/git/gitlab-shell/config.yml`.
-### Maintenance Tasks
+### Maintenance tasks
-[GitLab](https://gitlab.com/gitlab-org/gitlab/tree/master) provides Rake tasks with which you see version information and run a quick check on your configuration to ensure it is configured properly within the application. See [maintenance Rake tasks](../raketasks/maintenance.md).
+[GitLab](https://gitlab.com/gitlab-org/gitlab/tree/master) provides Rake tasks with which you see version information and run a quick check on your configuration to ensure it is configured properly within the application. See [maintenance Rake tasks](../administration/raketasks/maintenance.md).
In a nutshell, do the following:
```shell
@@ -934,7 +1033,8 @@ bundle exec rake gitlab:env:info RAILS_ENV=production
bundle exec rake gitlab:check RAILS_ENV=production
```
-Note: It is recommended to log into the `git` user using `sudo -i -u git` or `sudo su - git`. While the sudo commands provided by GitLab work in Ubuntu they do not always work in RHEL.
+Note: It is recommended to log into the `git` user using `sudo -i -u git` or `sudo su - git`. While
+the `sudo` commands provided by GitLab work in Ubuntu they do not always work in RHEL.
## GitLab.com
diff --git a/doc/development/background_migrations.md b/doc/development/background_migrations.md
index 4b58758b5c7..e5cc2ae4d1d 100644
--- a/doc/development/background_migrations.md
+++ b/doc/development/background_migrations.md
@@ -1,4 +1,11 @@
-# Background Migrations
+---
+type: reference, dev
+stage: none
+group: Development
+info: "See the Technical Writers assigned to Development Guidelines: https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments-to-development-guidelines"
+---
+
+# Background migrations
Background migrations can be used to perform data migrations that would
otherwise take a very long time (hours, days, years, etc) to complete. For
@@ -92,6 +99,20 @@ bulk_migrate_async(
)
```
+Note that this will queue a Sidekiq job immediately: if you have a large number
+of records, this may not be what you want. You can use the function
+`queue_background_migration_jobs_by_range_at_intervals` to split the job into
+batches:
+
+```ruby
+queue_background_migration_jobs_by_range_at_intervals(
+ ClassName,
+ BackgroundMigrationClassName,
+ 2.minutes,
+ batch_size: 10_000
+ )
+```
+
You'll also need to make sure that newly created data is either migrated, or
saved in both the old and new version upon creation. For complex and time
consuming migrations it's best to schedule a background job using an
diff --git a/doc/development/changelog.md b/doc/development/changelog.md
index f57e666540c..922c4814d91 100644
--- a/doc/development/changelog.md
+++ b/doc/development/changelog.md
@@ -31,14 +31,16 @@ the `author` field. GitLab team members **should not**.
- Any change that introduces a database migration, whether it's regular, post,
or data migration, **must** have a changelog entry, even if it is behind a
- disabled feature flag.
+ disabled feature flag. Since the migration is executed on [GitLab FOSS](https://gitlab.com/gitlab-org/gitlab-foss/),
+ the changelog for database schema changes should be written to the
+ `changelogs/unreleased/` directory, even when other elements of that change affect only GitLab EE.
+
- [Security fixes](https://gitlab.com/gitlab-org/release/docs/blob/master/general/security/developer.md)
**must** have a changelog entry, without `merge_request` value
and with `type` set to `security`.
-- Any user-facing change **should** have a changelog entry. Example: "GitLab now
- uses system fonts for all text."
+- Any user-facing change **should** have a changelog entry. This includes both visual changes (regardless of how minor), and changes to the rendered DOM which impact how a screen reader may announce the content.
- Performance improvements **should** have a changelog entry.
-- Changes that need to be documented in the Telemetry [Event Dictionary](telemetry/event_dictionary.md)
+- Changes that need to be documented in the Product Analytics [Event Dictionary](product_analytics/event_dictionary.md)
also require a changelog entry.
- _Any_ contribution from a community member, no matter how small, **may** have
a changelog entry regardless of these guidelines if the contributor wants one.
@@ -46,6 +48,7 @@ the `author` field. GitLab team members **should not**.
- Any docs-only changes **should not** have a changelog entry.
- Any change behind a disabled feature flag **should not** have a changelog entry.
- Any change behind an enabled feature flag **should** have a changelog entry.
+- Any change that adds new usage data metrics and changes that needs to be documented in Product Analytics [Event Dictionary](telemetry/event_dictionary.md) **should** have a changelog entry.
- A change that [removes a feature flag](feature_flags/development.md) **should** have a changelog entry -
only if the feature flag did not default to true already.
- A fix for a regression introduced and then fixed in the same release (i.e.,
diff --git a/doc/development/chatops_on_gitlabcom.md b/doc/development/chatops_on_gitlabcom.md
index 3c1c7750842..c64766af589 100644
--- a/doc/development/chatops_on_gitlabcom.md
+++ b/doc/development/chatops_on_gitlabcom.md
@@ -22,9 +22,7 @@ To request access to Chatops on GitLab.com:
1. Log into <https://ops.gitlab.net/users/sign_in> **using the same username** as for GitLab.com (you may have to rename it).
1. You could also use the "Sign in with" Google button to sign in, with your GitLab.com email address.
1. Ask one of your team members to add you to the `chatops` project in Ops. They can do it by running `/chatops run member add <username> gitlab-com/chatops --ops` command in the `#chat-ops-test` Slack channel.
-
-NOTE: **Note:**
-If you had to change your username for GitLab.com on the first step, make sure [to reflect this information](https://gitlab.com/gitlab-com/www-gitlab-com#adding-yourself-to-the-team-page) on [the team page](https://about.gitlab.com/company/team/).
+1. If you had to change your username for GitLab.com on the first step, make sure [to reflect this information](https://gitlab.com/gitlab-com/www-gitlab-com#adding-yourself-to-the-team-page) on [the team page](https://about.gitlab.com/company/team/).
## See also
diff --git a/doc/development/cicd/templates.md b/doc/development/cicd/templates.md
index 77cedc9814e..7d522a55559 100644
--- a/doc/development/cicd/templates.md
+++ b/doc/development/cicd/templates.md
@@ -13,15 +13,16 @@ This document explains how to develop [GitLab CI/CD templates](../../ci/examples
All template files reside in the `lib/gitlab/ci/templates` directory, and are categorized by the following sub-directories:
-| Sub-directory | Content | [Selectable in UI](#make-sure-the-new-template-can-be-selected-in-ui) |
-|----------------|--------------------------------------------------------------|-----------------------------------------------------------------------|
-| `/AWS/*` | Cloud Deployment (AWS) related jobs | No |
-| `/Jobs/*` | Auto DevOps related jobs | No |
-| `/Pages/*` | Static site generators for GitLab Pages (for example Jekyll) | Yes |
-| `/Security/*` | Security related jobs | Yes |
-| `/Verify/*` | Verify/testing related jobs | Yes |
-| `/Workflows/*` | Common uses of the `workflow:` keyword | No |
-| `/*` (root) | General templates | Yes |
+| Sub-directory | Content | [Selectable in UI](#make-sure-the-new-template-can-be-selected-in-ui) |
+|----------------|----------------------------------------------------|-----------------------------------------------------------------------|
+| `/AWS/*` | Cloud Deployment (AWS) related jobs | No |
+| `/Jobs/*` | Auto DevOps related jobs | No |
+| `/Pages/*` | Static site generators for GitLab Pages (for example Jekyll) | Yes |
+| `/Security/*` | Security related jobs | Yes |
+| `/Terraform/*` | Infrastructure as Code related templates | No |
+| `/Verify/*` | Verify/testing related jobs | Yes |
+| `/Workflows/*` | Common uses of the `workflow:` keyword | No |
+| `/*` (root) | General templates | Yes |
## Criteria
@@ -110,7 +111,7 @@ to include older template versions. If other templates are included with `includ
they can be combined with the `include: remote`:
```yaml
-# To use the v13 stable template, which is not included in v14, fetch the specifc
+# To use the v13 stable template, which is not included in v14, fetch the specific
# template from the remote template repository with the `include:remote:` keyword.
# If you fetch from the GitLab canonical project, use the following URL format:
# https://gitlab.com/gitlab-org/gitlab/-/raw/<version>/lib/gitlab/ci/templates/<template-name>
diff --git a/doc/development/code_review.md b/doc/development/code_review.md
index 2e319efa5f3..3ff802d3b23 100644
--- a/doc/development/code_review.md
+++ b/doc/development/code_review.md
@@ -67,6 +67,10 @@ page, with these behaviors:
contains the string 'OOO', or the emoji is `:palm_tree:` or `:beach:`.
1. [Trainee maintainers](https://about.gitlab.com/handbook/engineering/workflow/code-review/#trainee-maintainer)
are three times as likely to be picked as other reviewers.
+1. People whose [GitLab status](../user/profile/index.md#current-status) emoji
+ is `:large_blue_circle:` are more likely to be picked. This applies to both reviewers and trainee maintainers.
+ - Reviewers with `:large_blue_circle:` are two times as likely to be picked as other reviewers.
+ - Trainee maintainers with `:large_blue_circle:` are four times as likely to be picked as other reviewers.
1. It always picks the same reviewers and maintainers for the same
branch name (unless their OOO status changes, as in point 1). It
removes leading `ce-` and `ee-`, and trailing `-ce` and `-ee`, so
@@ -100,6 +104,7 @@ with [domain expertise](#domain-experts).
by a [Software Engineer in Test](https://about.gitlab.com/handbook/engineering/quality/#individual-contributors)**.
1. If your merge request only includes end-to-end changes (*3*) **or** if the MR author is a [Software Engineer in Test](https://about.gitlab.com/handbook/engineering/quality/#individual-contributors), it must be **approved by a [Quality maintainer](https://about.gitlab.com/handbook/engineering/projects/#gitlab_maintainers_qa)**
1. If your merge request includes a new or updated [application limit](https://about.gitlab.com/handbook/product/product-processes/#introducing-application-limits), it must be **approved by a [product manager](https://about.gitlab.com/company/team/)**.
+1. If your merge request includes Product Analytics (telemetry) changes, it should be reviewed and approved by a [Product analytics engineer](https://gitlab.com/gitlab-org/growth/product-analytics/engineers).
- (*1*): Please note that specs other than JavaScript specs are considered backend code.
- (*2*): We encourage you to seek guidance from a database maintainer if your merge
diff --git a/doc/development/contributing/community_roles.md b/doc/development/contributing/community_roles.md
index 7d2d1b77a0e..d880361e3aa 100644
--- a/doc/development/contributing/community_roles.md
+++ b/doc/development/contributing/community_roles.md
@@ -1,3 +1,9 @@
+---
+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/engineering/ux/technical-writing/#designated-technical-writers
+---
+
# Community members & roles
GitLab community members and their privileges/responsibilities.
diff --git a/doc/development/contributing/design.md b/doc/development/contributing/design.md
index 352392931c0..891c764f07f 100644
--- a/doc/development/contributing/design.md
+++ b/doc/development/contributing/design.md
@@ -1,3 +1,10 @@
+---
+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/engineering/ux/technical-writing/#designated-technical-writers
+---
+
# Implement design & UI elements
For guidance on UX implementation at GitLab, please refer to our [Design System](https://design.gitlab.com/).
diff --git a/doc/development/contributing/index.md b/doc/development/contributing/index.md
index 7550fe69546..6cbe57bf926 100644
--- a/doc/development/contributing/index.md
+++ b/doc/development/contributing/index.md
@@ -1,3 +1,10 @@
+---
+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/engineering/ux/technical-writing/#designated-technical-writers
+---
+
# Contribute to GitLab
Thank you for your interest in contributing to GitLab. This guide details how
diff --git a/doc/development/contributing/issue_workflow.md b/doc/development/contributing/issue_workflow.md
index bb7b4713a5e..b7c05a369f0 100644
--- a/doc/development/contributing/issue_workflow.md
+++ b/doc/development/contributing/issue_workflow.md
@@ -1,3 +1,10 @@
+---
+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/engineering/ux/technical-writing/#designated-technical-writers
+---
+
# Issues workflow
## Issue tracker guidelines
@@ -320,6 +327,11 @@ look for issues labeled `~"Accepting merge requests"` with a [weight of 1](https
More experienced contributors are very welcome to tackle
[any of them](https://gitlab.com/groups/gitlab-org/-/issues?state=opened&label_name[]=Accepting+merge+requests&assignee_id=None).
+For more complex features that have a weight of 2 or more and clear scope, we recommend looking at issues
+with the [label `~"Community Challenge"`](https://gitlab.com/gitlab-org/gitlab/-/issues?scope=all&utf8=%E2%9C%93&state=opened&label_name[]=Accepting%20merge%20requests&label_name[]=Community%20challenge).
+If your MR for the `~"Community Challenge"` issue gets merged, you will also have a chance to win a custom
+GitLab merchandise.
+
If you've decided that you would like to work on an issue, please @-mention
the [appropriate product manager](https://about.gitlab.com/handbook/product/#who-to-talk-to-for-what)
as soon as possible. The product manager will then pull in appropriate GitLab team
diff --git a/doc/development/contributing/merge_request_workflow.md b/doc/development/contributing/merge_request_workflow.md
index d88b159b666..31f59ad875c 100644
--- a/doc/development/contributing/merge_request_workflow.md
+++ b/doc/development/contributing/merge_request_workflow.md
@@ -1,3 +1,10 @@
+---
+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/engineering/ux/technical-writing/#designated-technical-writers
+---
+
# Merge requests workflow
We welcome merge requests from everyone, with fixes and improvements
@@ -218,7 +225,7 @@ requirements.
1. [Secure coding guidelines](https://gitlab.com/gitlab-com/gl-security/security-guidelines) have been followed.
1. [Documented](../documentation/index.md) in the `/doc` directory.
1. [Changelog entry added](../changelog.md), if necessary.
-1. Reviewed by relevant (UX/FE/BE/tech writing) reviewers and all concerns are addressed.
+1. Reviewed by relevant reviewers and all concerns are addressed for Availability, Regressions, Security. Documentation reviews should take place as soon as possible, but they should not block a merge request.
1. Merged by a project maintainer.
1. Create an issue in the [infrastructure issue tracker](https://gitlab.com/gitlab-com/gl-infra/infrastructure/-/issues) to inform the Infrastructure department when your contribution is changing default settings or introduces a new setting, if relevant.
1. Confirmed to be working in the [Canary stage](https://about.gitlab.com/handbook/engineering/#canary-testing) or on GitLab.com once the contribution is deployed.
diff --git a/doc/development/contributing/style_guides.md b/doc/development/contributing/style_guides.md
index f6e64c1f1e6..773c1a771cd 100644
--- a/doc/development/contributing/style_guides.md
+++ b/doc/development/contributing/style_guides.md
@@ -1,3 +1,10 @@
+---
+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/engineering/ux/technical-writing/#designated-technical-writers
+---
+
# Style guides
## Editor/IDE styling standardization
diff --git a/doc/development/database/add_foreign_key_to_existing_column.md b/doc/development/database/add_foreign_key_to_existing_column.md
index 1b41a52c95e..85411ff9aa7 100644
--- a/doc/development/database/add_foreign_key_to_existing_column.md
+++ b/doc/development/database/add_foreign_key_to_existing_column.md
@@ -1,3 +1,9 @@
+---
+stage: Enablement
+group: Database
+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/#designated-technical-writers
+---
+
# Adding foreign key constraint to an existing column
Foreign keys help ensure consistency between related database tables. The current database review process **always** encourages you to add [foreign keys](../foreign_keys.md) when creating tables that reference records from other tables.
@@ -103,7 +109,7 @@ class RemoveRecordsWithoutUserFromEmailsTable < ActiveRecord::Migration[5.2]
end
def down
- # Can be a no-op when data inconsistency is not affecting the pre and post deploymnet version of the application.
+ # Can be a no-op when data inconsistency is not affecting the pre and post deployment version of the application.
# In this case we might have records in the `emails` table where the associated record in the `users` table is not there anymore.
end
end
diff --git a/doc/development/database/client_side_connection_pool.md b/doc/development/database/client_side_connection_pool.md
new file mode 100644
index 00000000000..1a30d2d73a3
--- /dev/null
+++ b/doc/development/database/client_side_connection_pool.md
@@ -0,0 +1,63 @@
+---
+type: dev, reference
+stage: none
+group: Development
+info: "See the Technical Writers assigned to Development Guidelines: https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments-to-development-guidelines"
+---
+
+# Client-side connection-pool
+
+Ruby processes accessing the database through
+ActiveRecord, automatically calculate the connection-pool size for the
+process based on the concurrency.
+
+Because of the way [Ruby on Rails manages database
+connections](#connection-lifecycle), it is important that we have at
+least as many connections as we have threads. While there is a 'pool'
+setting in [`database.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/config/database.yml.postgresql), it is not very practical because you need to
+maintain it in tandem with the number of application threads. For this
+reason, we override the number of allowed connections in the database
+connection-pool based on the configured number of application threads.
+
+`Gitlab::Runtime.max_threads` is the number of user-facing
+application threads the process has been configured with. We also have
+auxiliary threads that use database connections. As it isn't
+straightforward to keep an accurate count of the number of auxiliary threads as
+the application evolves over time, we just add a fixed headroom to the
+number of user-facing threads. It is OK if this number is too large
+because connections are instantiated lazily.
+
+## Troubleshooting connection-pool issues
+
+The connection-pool usage can be seen per environment in the [connection-pool
+saturation
+dashboard](https://dashboards.gitlab.net/d/alerts-sat_rails_db_connection_pool/alerts-rails_db_connection_pool-saturation-detail?orgId=1).
+
+If the connection-pool is too small, this would manifest in
+`ActiveRecord::ConnectionTimeoutError`s from the application. Because we alert
+when almost all connections are used, we should know this before
+timeouts occur. If this happens we can remediate by setting the
+`DB_POOL_HEADROOM` environment variable to something bigger than the
+hardcoded value (10).
+
+At this point, we need to investigate what is using more connections
+than we anticipated. To do that, we can use the
+`gitlab_ruby_threads_running_threads` metric. For example, [this
+graph](https://thanos-query.ops.gitlab.net/graph?g0.range_input=1h&g0.max_source_resolution=0s&g0.expr=sum%20by%20(thread_name)%20(%20gitlab_ruby_threads_running_threads%7Buses_db_connection%3D%22yes%22%7D%20)&g0.tab=0)
+shows all running threads that connect to the database by their
+name. Threads labeled `puma worker` or `sidekiq_worker_thread` are
+the threads that define `Gitlab::Runtime.max_threads` so those are
+accounted for. If there's more than 10 other threads running, we could
+consider raising the default headroom.
+
+## Connection lifecycle
+
+For web requests, a connection is obtained from the pool at the first
+time a database query is made. The connection is returned to the pool
+after the request completes.
+
+For background jobs, the behavior is very similar. The thread obtains
+a connection for the first query, and returns it after the job is
+finished.
+
+This is managed by Rails internally.
diff --git a/doc/development/database/database_reviewer_guidelines.md b/doc/development/database/database_reviewer_guidelines.md
index 6cb061f9959..3345df8b46b 100644
--- a/doc/development/database/database_reviewer_guidelines.md
+++ b/doc/development/database/database_reviewer_guidelines.md
@@ -1,3 +1,9 @@
+---
+stage: Enablement
+group: Database
+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/#designated-technical-writers
+---
+
# Database Reviewer Guidelines
This page includes introductory material for new database reviewers.
diff --git a/doc/development/database/index.md b/doc/development/database/index.md
index 9ea5b6fcaac..4bcefefe7a7 100644
--- a/doc/development/database/index.md
+++ b/doc/development/database/index.md
@@ -1,3 +1,9 @@
+---
+stage: Enablement
+group: Database
+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/#designated-technical-writers
+---
+
# Database guides
## Database Reviews
@@ -24,6 +30,7 @@
- [Background migrations](../background_migrations.md)
- [Swapping tables](../swapping_tables.md)
- [Deleting migrations](../deleting_migrations.md)
+- [Partitioning tables](table_partitioning.md)
## Debugging
@@ -49,6 +56,8 @@
- [Database Debugging and Troubleshooting](../database_debugging.md)
- [Query Count Limits](../query_count_limits.md)
- [Creating enums](../creating_enums.md)
+- [Client-side connection-pool](client_side_connection_pool.md)
+- [Updating multiple values](./setting_multiple_values.md)
## Case studies
diff --git a/doc/development/database/not_null_constraints.md b/doc/development/database/not_null_constraints.md
index e4dec2afa10..96271863d94 100644
--- a/doc/development/database/not_null_constraints.md
+++ b/doc/development/database/not_null_constraints.md
@@ -1,3 +1,9 @@
+---
+stage: Enablement
+group: Database
+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/#designated-technical-writers
+---
+
# `NOT NULL` constraints
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/38358) in GitLab 13.0.
@@ -33,7 +39,7 @@ end
## Add a `NOT NULL` column to an existing table
-With PostgreSQL 11 being the minimum version since GitLab 13.0, adding columns with `NULL` and/or
+With PostgreSQL 11 being the minimum version in GitLab 13.0 and later, adding columns with `NULL` and/or
default values has become much easier and the standard `add_column` helper should be used in all cases.
For example, consider a migration that adds a new `NOT NULL` column `active` to table `db_guides`,
diff --git a/doc/development/database/setting_multiple_values.md b/doc/development/database/setting_multiple_values.md
new file mode 100644
index 00000000000..5569a0e10b7
--- /dev/null
+++ b/doc/development/database/setting_multiple_values.md
@@ -0,0 +1,103 @@
+# Setting Multiple Values
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/32921) in GitLab 13.5.
+
+Frequently, we will want to update multiple objects with new values for one
+or more columns. The obvious way to do this is using `Relation#update_all`:
+
+```ruby
+user.issues.open.update_all(due_date: 7.days.from_now) # (1)
+user.issues.update_all('relative_position = relative_position + 1') # (2)
+```
+
+But what do you do if you cannot express the update as either a static value (1)
+or as a calculation (2)?
+
+Thankfully we can use `UPDATE FROM` to express the need to update multiple rows
+with distinct values in a single query. One can either use a temporary table, or
+a Common Table Expression (CTE), and then use that as the source of the updates:
+
+```sql
+with updates(obj_id, new_title, new_weight) as (
+ values (1 :: integer, 'Very difficult issue' :: text, 8 :: integer),
+ (2, 'Very easy issue', 1)
+)
+update issues
+ set title = new_title, weight = new_weight
+ from updates
+ where id = obj_id
+```
+
+The bad news: There is no way to express this in ActiveRecord or even dropping
+down to ARel - the `UpdateManager` just does not support `update from`, so this
+is not expressible.
+
+The good news: We supply an abstraction to help you generate these kinds of
+updates, called `Gitlab::Database::BulkUpdate`. This constructs queries such as the
+above, and uses binding parameters to avoid SQL injection.
+
+## Usage
+
+To use this, we need:
+
+- the list of columns to update
+- a mapping from object/ID to the new values to set for that object
+- a way to determine the table for each object
+
+So for example, we can express the query above as:
+
+```ruby
+issue_a = Issue.find(..)
+issue_b = Issue.find(..)
+
+# Issues a single query:
+::Gitlab::Database::BulkUpdate.execute(%i[title weight], {
+ issue_a => { title: 'Very difficult issue', weight: 8 },
+ issue_b => { title: 'Very easy issue', weight: 1 }
+})
+```
+
+Here the table can be determined automatically, from calling
+`object.class.table_name`, so we don't need to provide anything.
+
+We can even pass heterogeneous sets of objects, if the updates all make sense
+for them:
+
+```ruby
+issue_a = Issue.find(..)
+issue_b = Issue.find(..)
+merge_request = MergeRequest.find(..)
+
+# Issues two queries
+::Gitlab::Database::BulkUpdate.execute(%i[title], {
+ issue_a => { title: 'A' },
+ issue_b => { title: 'B' },
+ merge_request => { title: 'B' }
+})
+```
+
+If your objects do not return the correct model class (perhaps because they are
+part of a union), then we need to specify this explicitly in a block:
+
+```ruby
+bazzes = params
+objects = Foo.from_union([
+ Foo.select("id, 'foo' as object_type").where(quux: true),
+ Bar.select("id, 'bar' as object_type").where(wibble: true)
+ ])
+# At this point, all the objects are instances of Foo, even the ones from the
+# Bar table
+mapping = objects.to_h { |obj| [obj, bazzes[obj.id] }
+
+# Issues at most 2 queries
+::Gitlab::Database::BulkUpdate.execute(%i[baz], mapping) do |obj|
+ obj.object_type.constantize
+end
+```
+
+## Caveats
+
+Note that this is a **very low level** tool, and operates on the raw column
+values. Enumerations and state fields must be translated into their underlying
+representations, for example, and nested associations are not supported. No
+validations or hooks will be called.
diff --git a/doc/development/database/strings_and_the_text_data_type.md b/doc/development/database/strings_and_the_text_data_type.md
index b73dfa859fb..fe8cfa5cd22 100644
--- a/doc/development/database/strings_and_the_text_data_type.md
+++ b/doc/development/database/strings_and_the_text_data_type.md
@@ -1,3 +1,9 @@
+---
+stage: Enablement
+group: Database
+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/#designated-technical-writers
+---
+
# Strings and the Text data type
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/30453) in GitLab 13.0.
diff --git a/doc/development/database/table_partitioning.md b/doc/development/database/table_partitioning.md
new file mode 100644
index 00000000000..30d0b0a2f5b
--- /dev/null
+++ b/doc/development/database/table_partitioning.md
@@ -0,0 +1,259 @@
+---
+stage: Enablement
+group: Database
+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/#designated-technical-writers
+---
+
+# Database table partitioning
+
+Table partitioning is a powerful database feature that allows a table's
+data to be split into smaller physical tables that act as a single large
+table. If the application is designed to work with partitioning in mind,
+there can be multiple benefits, such as:
+
+- Query performance can be improved greatly, because the database can
+cheaply eliminate much of the data from the search space, while still
+providing full SQL capabilities.
+
+- Bulk deletes can be achieved with minimal impact on the database by
+dropping entire partitions. This is a natural fit for features that need
+to periodically delete data that falls outside the retention window.
+
+- Administrative tasks like `VACUUM` and index rebuilds can operate on
+individual partitions, rather than across a single massive table.
+
+Unfortunately, not all models fit a partitioning scheme, and there are
+significant drawbacks if implemented incorrectly. Additionally, tables
+can only be partitioned at their creation, making it nontrivial to apply
+partitioning to a busy database. A suite of migration tools are available
+to enable backend developers to partition existing tables, but the
+migration process is rather heavy, taking multiple steps split across
+several releases. Due to the limitations of partitioning and the related
+migrations, you should understand how partitioning fits your use case
+before attempting to leverage this feature.
+
+## Determining when to use partitioning
+
+While partitioning can be very useful when properly applied, it's
+imperative to identify if the data and workload of a table naturally fit a
+partitioning scheme. There are a few details you'll have to understand
+in order to decide if partitioning is a good fit for your particular
+problem.
+
+First, a table is partitioned on a partition key, which is a column or
+set of columns which determine how the data will be split across the
+partitions. The partition key is used by the database when reading or
+writing data, to decide which partition(s) need to be accessed. The
+partition key should be a column that would be included in a `WHERE`
+clause on almost all queries accessing that table.
+
+Second, it's necessary to understand the strategy the database will
+use to split the data across the partitions. The scheme supported by the
+GitLab migration helpers is date-range partitioning, where each partition
+in the table contains data for a single month. In this case, the partitioning
+key would need to be a timestamp or date column. In order for this type of
+partitioning to work well, most queries would need to access data within a
+certain date range.
+
+For a more concrete example, the `audit_events` table can be used, which
+was the first table to be partitioned in the application database
+(scheduled for deployment with the GitLab 13.5 release). This
+table tracks audit entries of security events that happen in the
+application. In almost all cases, users want to see audit activity that
+occurs in a certain timeframe. As a result, date-range partitioning
+was a natural fit for how the data would be accessed.
+
+To look at this in more detail, imagine a simplified `audit_events` schema:
+
+```sql
+CREATE TABLE audit_events (
+ id SERIAL NOT NULL PRIMARY KEY,
+ author_id INT NOT NULL,
+ details jsonb NOT NULL,
+ created_at timestamptz NOT NULL);
+```
+
+Now imagine typical queries in the UI would display the data within a
+certain date range, like a single week:
+
+```sql
+SELECT *
+FROM audit_events
+WHERE created_at >= '2020-01-01 00:00:00'
+ AND created_at < '2020-01-08 00:00:00'
+ORDER BY created_at DESC
+LIMIT 100
+```
+
+If the table is partitioned on the `created_at` column the base table would
+look like:
+
+```sql
+CREATE TABLE audit_events (
+ id SERIAL NOT NULL,
+ author_id INT NOT NULL,
+ details jsonb NOT NULL,
+ created_at timestamptz NOT NULL,
+ PRIMARY KEY (id, created_at))
+PARTITION BY RANGE(created_at);
+```
+
+NOTE: **Note:**
+The primary key of a partitioned table must include the partition key as
+part of the primary key definition.
+
+And we might have a list of partitions for the table, such as:
+
+```sql
+audit_events_202001 FOR VALUES FROM ('2020-01-01') TO ('2020-02-01')
+audit_events_202002 FOR VALUES FROM ('2020-02-01') TO ('2020-03-01')
+audit_events_202003 FOR VALUES FROM ('2020-03-01') TO ('2020-04-01')
+```
+
+Each partition is a separate physical table, with the same structure as
+the base `audit_events` table, but contains only data for rows where the
+partition key falls in the specified range. For example, the partition
+`audit_events_202001` contains rows where the `created_at` column is
+greater than or equal to `2020-01-01` and less than `2020-02-01`.
+
+Now, if we look at the previous example query again, the database can
+use the `WHERE` to recognize that all matching rows will be in the
+`audit_events_202001` partition. Rather than searching all of the data
+in all of the partitions, it can search only the single month's worth
+of data in the appropriate partition. In a large table, this can
+dramatically reduce the amount of data the database needs to access.
+However, imagine a query that does not filter based on the partitioning
+key, such as:
+
+```sql
+SELECT *
+FROM audit_events
+WHERE author_id = 123
+ORDER BY created_at DESC
+LIMIT 100
+```
+
+In this example, the database can't prune any partitions from the search,
+because matching data could exist in any of them. As a result, it has to
+query each partition individually, and aggregate the rows into a single result
+set. Since `author_id` would be indexed, the performance impact could
+likely be acceptable, but on more complex queries the overhead can be
+substantial. Partitioning should only be leveraged if the access patterns
+of the data support the partitioning strategy, otherwise performance will
+suffer.
+
+## Partitioning a table
+
+Unfortunately, tables can only be partitioned at their creation, making
+it nontrivial to apply to a busy database. A suite of migration
+tools have been developed to enable backend developers to partition
+existing tables. This migration process takes multiple steps which must
+be split across several releases.
+
+### Caveats
+
+The partitioning migration helpers work by creating a partitioned duplicate
+of the original table and using a combination of a trigger and a background
+migration to copy data into the new table. Changes to the original table
+schema can be made in parallel with the partitioning migration, but they
+must take care to not break the underlying mechanism that makes the migration
+work. For example, if a column is added to the table that is being
+partitioned, both the partitioned table and the trigger definition need to
+be updated to match.
+
+### Step 1: Creating the partitioned copy (Release N)
+
+The first step is to add a migration to create the partitioned copy of
+the original table. This migration will also create the appropriate
+partitions based on the data in the original table, and install a
+trigger that will sync writes from the original table into the
+partitioned copy.
+
+An example migration of partitioning the `audit_events` table by its
+`created_at` column would look like:
+
+```ruby
+class PartitionAuditEvents < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::PartitioningMigrationHelpers
+
+ def up
+ partition_table_by_date :audit_events, :created_at
+ end
+
+ def down
+ drop_partitioned_table_for :audit_events
+ end
+end
+```
+
+Once this has executed, any inserts, updates or deletes in the
+original table will also be duplicated in the new table. For updates and
+deletes, the operation will only have an effect if the corresponding row
+exists in the partitioned table.
+
+### Step 2: Backfill the partitioned copy (Release N)
+
+The second step is to add a post-deployment migration that will schedule
+the background jobs that will backfill existing data from the original table
+into the partitioned copy.
+
+Continuing the above example, the migration would look like:
+
+```ruby
+class BackfillPartitionAuditEvents < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::PartitioningMigrationHelpers
+
+ def up
+ enqueue_partitioning_data_migration :audit_events
+ end
+
+ def down
+ cleanup_partitioning_data_migration :audit_events
+ end
+end
+```
+
+This step uses the same mechanism as any background migration, so you
+may want to read the [Background Migration](../background_migrations.md)
+guide for details on that process. Background jobs are scheduled every
+2 minutes and copy `50_000` records at a time, which can be used to
+estimate the timing of the background migration portion of the
+partitioning migration.
+
+### Step 3: Post-backfill cleanup (Release N+1)
+
+The third step must occur at least one release after the release that
+includes the background migration. This gives time for the background
+migration to execute properly in self-managed installations. In this step,
+add another post-deployment migration that will cleanup after the
+background migration. This includes forcing any remaining jobs to
+execute, and copying data that may have been missed, due to dropped or
+failed jobs.
+
+Once again, continuing the example, this migration would look like:
+
+```ruby
+class CleanupPartitionedAuditEventsBackfill < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::PartitioningMigrationHelpers
+
+ def up
+ finalize_backfilling_partitioned_table :audit_events
+ end
+
+ def down
+ # no op
+ end
+end
+```
+
+After this migration has completed, the original table and partitioned
+table should contain identical data. The trigger installed on the
+original table guarantees that the data will remain in sync going
+forward.
+
+### Step 4: Swap the partitioned and non-partitioned tables (Release N+1)
+
+The final step of the migration will make the partitioned table ready
+for use by the application. This section will be updated when the
+migration helper is ready, for now development can be followed in the
+[Tracking Issue](https://gitlab.com/gitlab-org/gitlab/-/issues/241267).
diff --git a/doc/development/database_debugging.md b/doc/development/database_debugging.md
index 61e8ac60bfe..ebd57df498e 100644
--- a/doc/development/database_debugging.md
+++ b/doc/development/database_debugging.md
@@ -1,3 +1,9 @@
+---
+stage: Enablement
+group: Database
+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/#designated-technical-writers
+---
+
# Troubleshooting and Debugging Database
This section is to help give some copy-pasta you can use as a reference when you
@@ -19,7 +25,7 @@ If you just want to delete everything and start over with an empty DB (approxima
bundle exec rake db:reset RAILS_ENV=development
```
-If you just want to delete everything and start over with dummy data (approximately 4 minutes). This
+If you just want to delete everything and start over with sample data (approximately 4 minutes). This
also does `db:reset` and runs DB-specific migrations:
```shell
diff --git a/doc/development/database_query_comments.md b/doc/development/database_query_comments.md
index 77943f2b261..ccaaadef4f4 100644
--- a/doc/development/database_query_comments.md
+++ b/doc/development/database_query_comments.md
@@ -1,3 +1,9 @@
+---
+stage: Enablement
+group: Database
+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/#designated-technical-writers
+---
+
# Database query comments with Marginalia
The [Marginalia gem](https://github.com/basecamp/marginalia) is used to add
diff --git a/doc/development/database_review.md b/doc/development/database_review.md
index f56ffdbad21..3f5f36b0b6e 100644
--- a/doc/development/database_review.md
+++ b/doc/development/database_review.md
@@ -1,3 +1,9 @@
+---
+stage: Enablement
+group: Database
+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/#designated-technical-writers
+---
+
# Database Review Guidelines
This page is specific to database reviews. Please refer to our
@@ -21,7 +27,7 @@ A database review is required for:
database review.
- Changes in usage data metrics that use `count` and `distinct_count`.
These metrics could have complex queries over large tables.
- See the [Telemetry Guide](telemetry/usage_ping.md#implementing-usage-ping)
+ See the [Product Analytics Guide](product_analytics/usage_ping.md#implementing-usage-ping)
for implementation details.
A database reviewer is expected to look out for obviously complex
@@ -184,10 +190,6 @@ test its execution using `CREATE INDEX CONCURRENTLY` in the `#database-lab` Slac
- [Check query plans](understanding_explain_plans.md) and suggest improvements
to queries (changing the query, schema or adding indexes and similar)
- General guideline is for queries to come in below 100ms execution time
- - If queries rely on prior migrations that are not present yet on production
- (eg indexes, columns), you can use a [one-off instance from the restore
- pipeline](https://ops.gitlab.net/gitlab-com/gl-infra/gitlab-restore/postgres-gprd)
- in order to establish a proper testing environment. If you don't have access to this project, reach out to #database on Slack to get advice on how to proceed.
- Avoid N+1 problems and minimalize the [query count](merge_request_performance_guidelines.md#query-counts).
### Timing guidelines for migrations
diff --git a/doc/development/db_dump.md b/doc/development/db_dump.md
index 4095932e44c..b16cd4b08d1 100644
--- a/doc/development/db_dump.md
+++ b/doc/development/db_dump.md
@@ -1,3 +1,9 @@
+---
+stage: Enablement
+group: Database
+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/#designated-technical-writers
+---
+
# Importing a database dump into a staging environment
Sometimes it is useful to import the database from a production environment
diff --git a/doc/development/distributed_tracing.md b/doc/development/distributed_tracing.md
index 9a4c15c5c19..952435150d6 100644
--- a/doc/development/distributed_tracing.md
+++ b/doc/development/distributed_tracing.md
@@ -1,15 +1,12 @@
---
stage: Monitor
-group: APM
+group: Health
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/#designated-technical-writers
---
# Distributed Tracing - development guidelines
-NOTE: **Note:**
-Distributed Tracing in GitLab is currently considered **experimental**, as it has not yet been tested at scale on GitLab.com.
-
-GitLab is instrumented for distributed tracing.
+GitLab is instrumented for distributed tracing. Distributed Tracing in GitLab is currently considered **experimental**, as it has not yet been tested at scale on GitLab.com.
According to [Open Tracing](https://opentracing.io/docs/overview/what-is-tracing/):
diff --git a/doc/development/documentation/feature_flags.md b/doc/development/documentation/feature_flags.md
index a4a6ee2fa0f..0f03ceeb4b5 100644
--- a/doc/development/documentation/feature_flags.md
+++ b/doc/development/documentation/feature_flags.md
@@ -52,7 +52,7 @@ For feature flags disabled by default, if they can be used by end users:
do not say anything about it.
- Say whether it's recommended for production use.
- Document how to enable and disable it.
-- Add a warning to the user saying that the feature is disabled.
+- Add a warning to the user saying that the feature might be disabled.
For example, for a feature disabled by default, disabled on GitLab.com, cannot
be enabled for a single project, and is not ready for production use:
@@ -250,7 +250,7 @@ be enabled by project, and is ready for production use:
> - [Introduced](link-to-issue) in GitLab 12.0.
> - It's [deployed behind a feature flag](<replace with path to>/user/feature_flags.md), enabled by default.
> - It's enabled on GitLab.com.
-> - It can be enabled or disable for a single project.
+> - It can be enabled or disabled for a single project.
> - It's recommended for production use.
> - For GitLab self-managed instances, GitLab administrators can opt to [disable it](#anchor-to-section). **(CORE ONLY)**
diff --git a/doc/development/documentation/graphql_styleguide.md b/doc/development/documentation/graphql_styleguide.md
new file mode 100644
index 00000000000..11e6b159359
--- /dev/null
+++ b/doc/development/documentation/graphql_styleguide.md
@@ -0,0 +1,92 @@
+---
+type: reference, dev
+stage: none
+group: Development
+info: "See the Technical Writers assigned to Development Guidelines: https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments-to-development-guidelines"
+description: "Writing styles, markup, formatting, and other standards for GraphQL API's GitLab Documentation."
+---
+
+# GraphQL API
+
+GraphQL APIs are different from [RESTful APIs](restful_api_styleguide.md). Reference
+information is generated in our [GraphQL reference](../../api/graphql/reference/index.md).
+
+However, it's helpful to include examples on how to use GraphQL for different
+*use cases*, with samples that readers can use directly in the
+[GraphiQL explorer](../api_graphql_styleguide.md#graphiql).
+
+This section describes the steps required to add your GraphQL examples to
+GitLab documentation.
+
+## Add a dedicated GraphQL page
+
+To create a dedicated GraphQL page, create a new `.md` file in the
+`doc/api/graphql/` directory. Give that file a functional name, such as
+`import_from_specific_location.md`.
+
+## Start the page with an explanation
+
+Include a page title that describes the GraphQL functionality in a few words,
+such as:
+
+```markdown
+# Search for [substitute kind of data]
+```
+
+Describe the search. One sentence may be all you need. More information may
+help readers learn how to use the example for their GitLab deployments.
+
+## Include a procedure using the GraphiQL explorer
+
+The GraphiQL explorer can help readers test queries with working deployments.
+Set up the section with the following:
+
+- Use the following title:
+
+ ```markdown
+ ## Set up the GraphiQL explorer
+ ```
+
+- Include a code block with the query that anyone can include in their
+ instance of the GraphiQL explorer:
+
+ ````markdown
+ ```graphql
+ query {
+ <insert queries here>
+ }
+ ```
+ ````
+
+- Tell the user what to do:
+
+ ```markdown
+ 1. Open the GraphiQL explorer tool in the following URL: `https://gitlab.com/-/graphql-explorer`.
+ 1. Paste the `query` listed above into the left window of your GraphiQL explorer tool.
+ 1. Select **Play** to get the result shown here:
+ ```
+
+- Include a screenshot of the result in the GraphiQL explorer. Follow the naming
+ convention described in the [Save the image](styleguide.md#save-the-image) section of the Documentation style guide.
+- Follow up with an example of what you can do with the output. Make sure the
+ example is something that readers can do on their own deployments.
+- Include a link to the [GraphQL API resources](../../api/graphql/reference/index.md).
+
+## Add the GraphQL example to the global navigation
+
+You should include a link for your new document in the global navigation (the list on the
+left side of the documentation website). To do so, open a second MR, against the
+[GitLab documentation repository](https://gitlab.com/gitlab-org/gitlab-docs/).
+
+We store our global navigation in the [`default-nav.yaml`](https://gitlab.com/gitlab-org/gitlab-docs/-/blob/master/content/_data/default-nav.yaml) file, in the
+`content/_data` subdirectory. You can find the GraphQL section under the
+following line:
+
+```yaml
+- category_title: GraphQL
+```
+
+Be aware that CI tests for that second MR will fail with a bad link until the
+main MR that adds the new GraphQL page is merged. Therefore, only merge the MR against the
+[`gitlab-docs`](https://gitlab.com/gitlab-org/gitlab-docs) repository after the content has
+been merged and live on `docs.gitlab.com`.
diff --git a/doc/development/documentation/index.md b/doc/development/documentation/index.md
index d6f24d6374d..e51f966ee6e 100644
--- a/doc/development/documentation/index.md
+++ b/doc/development/documentation/index.md
@@ -1,4 +1,7 @@
---
+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/engineering/ux/technical-writing/#designated-technical-writers
description: Learn how to contribute to GitLab Documentation.
---
@@ -52,9 +55,9 @@ docs-only merge requests using the following guide:
[Contributions to GitLab docs](workflow.md) are welcome from the entire GitLab community.
-To ensure that GitLab docs are current, there are special processes and responsibilities for all [feature changes](feature-change-workflow.md), that is development work that impacts the appearance, usage, or administration of a feature.
+To ensure that GitLab docs are current, there are special processes and responsibilities for all [feature changes](workflow.md), that is development work that impacts the appearance, usage, or administration of a feature.
-However, anyone can contribute [documentation improvements](improvement-workflow.md) that are not associated with a feature change. For example, adding a new doc on how to accomplish a use case that's already possible with GitLab or with third-party tools and GitLab.
+However, anyone can contribute [documentation improvements](workflow.md) that are not associated with a feature change. For example, adding a new doc on how to accomplish a use case that's already possible with GitLab or with third-party tools and GitLab.
## Markdown and styles
@@ -128,7 +131,7 @@ The following metadata should be added when a page is moved to another location:
- `redirect_to`: The relative path and filename (with an `.md` extension) of the
location to which visitors should be redirected for a moved page.
- [Learn more](#changing-document-location).
+ [Learn more](#move-or-rename-a-page).
- `disqus_identifier`: Identifier for Disqus commenting system. Used to keep
comments with a page that's been moved to a new URL.
[Learn more](#redirections-for-pages-with-disqus-comments).
@@ -156,17 +159,18 @@ Nanoc layout), which will be displayed at the top of the page if defined:
[algorithm](https://gitlab.com/gitlab-org/gitlab-docs/-/blob/master/lib/helpers/reading_time.rb)
to calculate the reading time based on the number of words.
-## Changing document location
+## Move or rename a page
+
+Moving or renaming a document is the same as changing its location. This process
+requires specific steps to ensure that visitors can find the new
+documentation page, whether they're using `/help` from a GitLab instance or by
+visiting <https://docs.gitlab.com>.
-Changing a document's location requires specific steps to ensure that
-users can seamlessly access the new doc page, whether they are accessing content
-on a GitLab instance domain at `/help` or at <https://docs.gitlab.com>. Be sure to assign a
-technical writer if you have any questions during the process (such as
-whether the move is necessary), and ensure that a technical writer reviews this
-change prior to merging.
+Be sure to assign a technical writer to a page move or rename MR. Technical
+Writers can help with any questions and can review your change.
-If you indeed need to change a document's location, do not remove the old
-document, but instead replace all of its content with the following:
+To change a document's location, don't remove the old document, but instead
+replace all of its content with the following:
```markdown
---
@@ -176,14 +180,18 @@ redirect_to: '../path/to/file/index.md'
This document was moved to [another location](../path/to/file/index.md).
```
-Where `../path/to/file/index.md` is usually the relative path to the old document.
+Replace `../path/to/file/index.md` with the relative path to the old document.
+
+The `redirect_to` variable supports both full and relative URLs; for example:
-The `redirect_to` variable supports both full and relative URLs, for example
-`https://docs.gitlab.com/ee/path/to/file.html`, `../path/to/file.html`, `path/to/file.md`.
-It ensures that the redirect will work for <https://docs.gitlab.com> and any `*.md` paths
-will be compiled to `*.html`.
-The new line underneath the front matter informs the user that the document
-changed location and is useful for someone that browses that file from the repository.
+- `https://docs.gitlab.com/ee/path/to/file.html`
+- `../path/to/file.html`
+- `path/to/file.md`
+
+The redirect works for <https://docs.gitlab.com>, and any `*.md` paths are
+changed to `*.html`. The description line following the `redirect_to` code
+informs the visitor that the document changed location if the redirect process
+doesn't complete successfully.
For example, if you move `doc/workflow/lfs/index.md` to
`doc/administration/lfs.md`, then the steps would be:
@@ -208,9 +216,8 @@ For example, if you move `doc/workflow/lfs/index.md` to
git grep -n "lfs/lfs_administration"
```
-NOTE: **Note:**
-If the document being moved has any Disqus comments on it, there are extra steps
-to follow documented just [below](#redirections-for-pages-with-disqus-comments).
+1. If the document being moved has any Disqus comments on it, follow the steps
+ described in [Redirections for pages with Disqus comments](#redirections-for-pages-with-disqus-comments).
Things to note:
@@ -241,7 +248,8 @@ using the old URL as value. For example, let's say we moved the document
available under `https://docs.gitlab.com/my-old-location/README.html` to a new location,
`https://docs.gitlab.com/my-new-location/index.html`.
-Into the **new document** front matter, we add the following:
+Into the **new document** front matter, we add the following information. You must
+include the file name in the `disqus_identifier` URL, even if it's `index.html` or `README.html`.
```yaml
---
@@ -249,9 +257,6 @@ disqus_identifier: 'https://docs.gitlab.com/my-old-location/README.html'
---
```
-Note: it is necessary to include the file name in the `disqus_identifier` URL,
-even if it's `index.html` or `README.html`.
-
## Merge requests for GitLab documentation
Before getting started, make sure you read the introductory section
@@ -267,9 +272,8 @@ represents a good-faith effort to follow the template and style standards,
and is believed to be accurate.
Further needs for what would make the doc even better should be immediately addressed
-in a follow-up MR or issue.
+in a follow-up merge request or issue.
-NOTE: **Note:**
If the release version you want to add the documentation to has already been
frozen or released, use the label `~"Pick into X.Y"` to get it merged into
the correct release. Avoid picking into a past release as much as you can, as
@@ -392,8 +396,7 @@ You will need at least Maintainer permissions to be able to run it.
![Manual trigger a docs build](img/manual_build_docs.png)
-NOTE: **Note:**
-You will need to push a branch to those repositories, it doesn't work for forks.
+You must push a branch to those repositories, as it doesn't work for forks.
The `review-docs-deploy*` job will:
@@ -410,17 +413,16 @@ minutes and it should appear online, otherwise you can check the status of the
remote pipeline from the link in the merge request's job output.
If the pipeline failed or got stuck, drop a line in the `#docs` chat channel.
-TIP: **Tip:**
-Someone with no merge rights to the GitLab projects (think of forks from
-contributors) cannot run the manual job. In that case, you can
-ask someone from the GitLab team who has the permissions to do that for you.
-
-NOTE: **Note:**
Make sure that you always delete the branch of the merge request you were
working on. If you don't, the remote docs branch won't be removed either,
and the server where the Review Apps are hosted will eventually be out of
disk space.
+TIP: **Tip:**
+Someone with no merge rights to the GitLab projects (think of forks from
+contributors) cannot run the manual job. In that case, you can
+ask someone from the GitLab team who has the permissions to do that for you.
+
### Troubleshooting review apps
In case the review app URL returns 404, follow these steps to debug:
@@ -462,7 +464,7 @@ If you want to know the in-depth details, here's what's really happening:
The following GitLab features are used among others:
- [Manual actions](../../ci/yaml/README.md#whenmanual)
-- [Multi project pipelines](../../ci/multi_project_pipeline_graphs.md)
+- [Multi project pipelines](../../ci/multi_project_pipelines.md)
- [Review Apps](../../ci/review_apps/index.md)
- [Artifacts](../../ci/yaml/README.md#artifacts)
- [Specific runner](../../ci/runners/README.md#prevent-a-specific-runner-from-being-enabled-for-other-projects)
@@ -668,7 +670,7 @@ build pipelines:
```
We recommend installing the version of `markdownlint-cli` currently used in the documentation
- linting [Docker image](https://gitlab.com/gitlab-org/gitlab-docs/-/blob/master/dockerfiles/Dockerfile.gitlab-docs-lint#L38).
+ linting [Docker image](https://gitlab.com/gitlab-org/gitlab-docs/-/blob/master/.gitlab-ci.yml#L420).
1. Install [`vale`](https://github.com/errata-ai/vale/releases). For example, to install using
`brew` for macOS, run:
@@ -678,7 +680,7 @@ build pipelines:
```
We recommend installing the version of Vale currently used in the documentation linting
- [Docker image](https://gitlab.com/gitlab-org/gitlab-docs/-/blob/master/dockerfiles/Dockerfile.gitlab-docs-lint#L16).
+ [Docker image](https://gitlab.com/gitlab-org/gitlab-docs/-/blob/master/.gitlab-ci.yml#L419).
In addition to using markdownlint and Vale at the command line, these tools can be
[integrated with your code editor](#configure-editors).
diff --git a/doc/development/documentation/restful_api_styleguide.md b/doc/development/documentation/restful_api_styleguide.md
new file mode 100644
index 00000000000..b12578b5d98
--- /dev/null
+++ b/doc/development/documentation/restful_api_styleguide.md
@@ -0,0 +1,180 @@
+---
+type: reference, dev
+stage: none
+group: Development
+info: "See the Technical Writers assigned to Development Guidelines: https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments-to-development-guidelines"
+description: "Writing styles, markup, formatting, and other standards for GitLab's RESTful APIs."
+---
+
+# RESTful API
+
+REST API resources are documented in Markdown under
+[`/doc/api`](https://gitlab.com/gitlab-org/gitlab/-/tree/master/doc/api). Each
+resource has its own Markdown file, which is linked from `api_resources.md`.
+
+When modifying the Markdown, also update the corresponding
+[OpenAPI definition](https://gitlab.com/gitlab-org/gitlab/-/tree/master/doc/api/openapi)
+if one exists for the resource. If not, consider creating one. Match the latest
+[OpenAPI 3.0.x specification](https://swagger.io/specification/). (For more
+information, see the discussion in this
+[issue](https://gitlab.com/gitlab-org/gitlab/-/issues/16023#note_370901810).)
+
+In the Markdown doc for a resource (AKA endpoint):
+
+- Every method must have the REST API request. For example:
+
+ ```plaintext
+ GET /projects/:id/repository/branches
+ ```
+
+- Every method must have a detailed [description of the parameters](#method-description).
+- Every method must have a cURL example.
+- Every method must have a response body (in JSON format).
+
+## API topic template
+
+The following can be used as a template to get started:
+
+````markdown
+## Descriptive title
+
+One or two sentence description of what endpoint does.
+
+```plaintext
+METHOD /endpoint
+```
+
+| Attribute | Type | Required | Description |
+|:------------|:---------|:---------|:----------------------|
+| `attribute` | datatype | yes/no | Detailed description. |
+| `attribute` | datatype | yes/no | Detailed description. |
+
+Example request:
+
+```shell
+curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/endpoint?parameters"
+```
+
+Example response:
+
+```json
+[
+ {
+ }
+]
+```
+````
+
+## Method description
+
+Use the following table headers to describe the methods. Attributes should
+always be in code blocks using backticks (`` ` ``).
+
+```markdown
+| Attribute | Type | Required | Description |
+|:----------|:-----|:---------|:------------|
+```
+
+Rendered example:
+
+| Attribute | Type | Required | Description |
+|:----------|:-------|:---------|:--------------------|
+| `user` | string | yes | The GitLab username. |
+
+## cURL commands
+
+- Use `https://gitlab.example.com/api/v4/` as an endpoint.
+- Wherever needed use this personal access token: `<your_access_token>`.
+- Always put the request first. `GET` is the default so you don't have to
+ include it.
+- Wrap the URL in double quotes (`"`).
+- Prefer to use examples using the personal access token and don't pass data of
+ username and password.
+
+| Methods | Description |
+|:------------------------------------------- |:------------------------------------------------------|
+| `--header "PRIVATE-TOKEN: <your_access_token>"` | Use this method as is, whenever authentication needed. |
+| `--request POST` | Use this method when creating new objects |
+| `--request PUT` | Use this method when updating existing objects |
+| `--request DELETE` | Use this method when removing existing objects |
+
+## cURL Examples
+
+The following sections include a set of [cURL](https://curl.haxx.se) examples
+you can use in the API documentation.
+
+CAUTION: **Caution:**
+Do not use information for real users, URLs, or tokens. For documentation, refer to our
+relevant style guide sections on [Fake user information](styleguide.md#fake-user-information),
+[Fake URLs](styleguide.md#fake-urls), and [Fake tokens](styleguide.md#fake-tokens).
+
+### Simple cURL command
+
+Get the details of a group:
+
+```shell
+curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/groups/gitlab-org"
+```
+
+### cURL example with parameters passed in the URL
+
+Create a new project under the authenticated user's namespace:
+
+```shell
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects?name=foo"
+```
+
+### Post data using cURL's `--data`
+
+Instead of using `--request POST` and appending the parameters to the URI, you
+can use cURL's `--data` option. The example below will create a new project
+`foo` under the authenticated user's namespace.
+
+```shell
+curl --data "name=foo" --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects"
+```
+
+### Post data using JSON content
+
+NOTE: **Note:**
+In this example we create a new group. Watch carefully the single and double
+quotes.
+
+```shell
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" --header "Content-Type: application/json" --data '{"path": "my-group", "name": "My group"}' "https://gitlab.example.com/api/v4/groups"
+```
+
+### Post data using form-data
+
+Instead of using JSON or urlencode you can use multipart/form-data which
+properly handles data encoding:
+
+```shell
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" --form "title=ssh-key" --form "key=ssh-rsa AAAAB3NzaC1yc2EA..." "https://gitlab.example.com/api/v4/users/25/keys"
+```
+
+The above example is run by and administrator and will add an SSH public key
+titled `ssh-key` to user's account which has an ID of 25.
+
+### Escape special characters
+
+Spaces or slashes (`/`) may sometimes result to errors, thus it is recommended
+to escape them when possible. In the example below we create a new issue which
+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"
+```
+
+Use `%2F` for slashes (`/`).
+
+### Pass arrays to API calls
+
+The GitLab API sometimes accepts arrays of strings or integers. For example, to
+exclude specific users when requesting a list of users for a project, you would
+do something like this:
+
+```shell
+curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" --data "skip_users[]=<user_id>" --data "skip_users[]=<user_id>" "https://gitlab.example.com/api/v4/projects/<project_id>/users"
+```
diff --git a/doc/development/documentation/site_architecture/global_nav.md b/doc/development/documentation/site_architecture/global_nav.md
index 22d97a9e2cf..9fce9b4e4b3 100644
--- a/doc/development/documentation/site_architecture/global_nav.md
+++ b/doc/development/documentation/site_architecture/global_nav.md
@@ -324,7 +324,6 @@ There are three main considerations on the logic built for the nav:
- `https://docs.gitlab.com/ee/`
- `https://docs.gitlab.com/omnibus/`
- `https://docs.gitlab.com/runner/`
- - `https://docs.gitlab.com/debug/`
- `https://docs.gitlab.com/*`
- [EE-only](#ee-only-docs): documentation only available in `/ee/`, not on `/ce/`, e.g.:
- `https://docs.gitlab.com/ee/user/group/epics/`
@@ -342,8 +341,8 @@ all the nav links to other pages:
<% dir = @item.identifier.to_s[%r{(?<=/)[^/]+}] %>
```
-For instance, for `https://docs.gitlab.com/ce/user/index.html`,
-`dir` == `ce`, and for `https://docs.gitlab.com/omnibus/README.html`,
+For instance, for `https://docs.gitlab.com/ee/user/index.html`,
+`dir` == `ee`, and for `https://docs.gitlab.com/omnibus/README.html`,
`dir` == `omnibus`.
#### Default URL
diff --git a/doc/development/documentation/site_architecture/release_process.md b/doc/development/documentation/site_architecture/release_process.md
index 98bb116aba6..d04d34ff786 100644
--- a/doc/development/documentation/site_architecture/release_process.md
+++ b/doc/development/documentation/site_architecture/release_process.md
@@ -121,10 +121,11 @@ versions (stable branches `X.Y` of the `gitlab-docs` project):
pipelines succeed:
NOTE: **Note:**
- The `release-X-Y` branch needs to be present locally, otherwise the Rake
- task will abort.
+ The `release-X-Y` branch needs to be present locally,
+ and you need to have switched to it, otherwise the Rake task will fail.
```shell
+ git checkout release-X-Y
./bin/rake release:dropdowns
```
diff --git a/doc/development/documentation/styleguide.md b/doc/development/documentation/styleguide.md
index 984c64b9e9e..6075124ef40 100644
--- a/doc/development/documentation/styleguide.md
+++ b/doc/development/documentation/styleguide.md
@@ -251,7 +251,7 @@ The table below shows what kind of documentation goes where.
| `doc/legal/` | Legal documents about contributing to GitLab. |
| `doc/install/` | Contains instructions for installing GitLab. |
| `doc/update/` | Contains instructions for updating GitLab. |
-| `doc/topics/` | Indexes per topic (`doc/topics/topic-name/index.md`): all resources for that topic. |
+| `doc/topics/` | Indexes per topic (`doc/topics/topic_name/index.md`): all resources for that topic. |
### Work with directories and files
@@ -287,9 +287,8 @@ The table below shows what kind of documentation goes where.
1. The `doc/topics/` directory holds topic-related technical content. Create
`doc/topics/topic_name/subtopic_name/index.md` when subtopics become necessary.
General user- and admin- related documentation, should be placed accordingly.
-1. The directories `/workflow/`, `/university/`, and `/articles/` have been
- *deprecated* and the majority their documentation has been moved to their
- correct location in small iterations.
+1. The `/university/` directory is *deprecated* and the majority of its documentation
+ has been moved.
If you are unsure where to place a document or a content addition, this should
not stop you from authoring and contributing. You can use your best judgment and
@@ -369,7 +368,7 @@ create an issue or an MR to propose a change to the user interface text.
- milestones
- reorder issues
- runner, runners, shared runners
- - a to-do, to-dos
+ - a to-do item, to dos
- *Some features are capitalized*, typically nouns naming GitLab-specific
capabilities or tools. For example:
- GitLab CI/CD
@@ -410,7 +409,7 @@ Use forms of *sign in*, instead of *log in* or *login*. For example:
Exceptions to this rule include the concept of *single sign-on* and
references to user interface elements. For example:
-- To sign in to product X, enter your credentials, and then click **Log in**.
+- To sign in to product X, enter your credentials, and then select **Log in**.
### Inclusive language
@@ -418,8 +417,11 @@ We strive to create documentation that is inclusive. This section includes
guidance and examples in the following categories:
- [Gender-specific wording](#avoid-gender-specific-wording).
+ (Tested in [`InclusionGender.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/.vale/gitlab/InclusionGender.yml).)
- [Ableist language](#avoid-ableist-language).
+ (Tested in [`InclusionAbleism.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/.vale/gitlab/InclusionAbleism.yml).)
- [Cultural sensitivity](#culturally-sensitive-language).
+ (Tested in [`InclusionCultural.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/.vale/gitlab/InclusionCultural.yml).)
We write our developer documentation with inclusivity and diversity in mind. This
page is not an exhaustive reference, but describes some general guidelines and
@@ -433,12 +435,16 @@ a gender-neutral pronoun.
Avoid the use of gender-specific pronouns, unless referring to a specific person.
+<!-- vale gitlab.InclusionGender = NO -->
+
| Use | Avoid |
|-----------------------------------|---------------------------------|
| People, humanity | Mankind |
| GitLab Team Members | Manpower |
| You can install; They can install | He can install; She can install |
+<!-- vale gitlab.InclusionGender = YES -->
+
If you need to set up [Fake user information](#fake-user-information), use
diverse or non-gendered names with common surnames.
@@ -446,6 +452,8 @@ diverse or non-gendered names with common surnames.
Avoid terms that are also used in negative stereotypes for different groups.
+<!-- vale gitlab.InclusionAbleism = NO -->
+
| Use | Avoid |
|------------------------|----------------------|
| Check for completeness | Sanity check |
@@ -455,6 +463,8 @@ Avoid terms that are also used in negative stereotypes for different groups.
| Active/Inactive | Enabled/Disabled |
| On/Off | Enabled/Disabled |
+<!-- vale gitlab.InclusionAbleism = YES -->
+
Credit: [Avoid ableist language](https://developers.google.com/style/inclusive-documentation#ableist-language)
in the Google Developer Style Guide.
@@ -464,13 +474,57 @@ Avoid terms that reflect negative cultural stereotypes and history. In most
cases, you can replace terms such as `master` and `slave` with terms that are
more precise and functional, such as `primary` and `secondary`.
+<!-- vale gitlab.InclusionCultural = NO -->
+
| Use | Avoid |
|----------------------|-----------------------|
| Primary / secondary | Master / slave |
| Allowlist / denylist | Blacklist / whitelist |
+<!-- vale gitlab.InclusionCultural = YES -->
+
For more information see the following [Internet Draft specification](https://tools.ietf.org/html/draft-knodel-terminology-02).
+### Fake user information
+
+You may need to include user information in entries such as a REST call or user profile.
+**Do not** use real user information or email addresses in GitLab documentation. For email
+addresses and names, do use:
+
+- **Email addresses**: Use an email address ending in `example.com`.
+- **Names**: Use strings like `example_username`. Alternatively, use diverse or
+ non-gendered names with common surnames, such as `Sidney Jones`, `Zhang Wei`,
+ or `Alex Garcia`.
+
+### Fake URLs
+
+When including sample URLs in the documentation, use:
+
+- `example.com` when the domain name is generic.
+- `gitlab.example.com` when referring to self-managed instances of GitLab.
+
+### Fake tokens
+
+There may be times where a token is needed to demonstrate an API call using
+cURL or a variable used in CI. It is strongly advised not to use real tokens in
+documentation even if the probability of a token being exploited is low.
+
+You can use the following fake tokens as examples:
+
+| Token type | Token value |
+|:----------------------|:-------------------------------------------------------------------|
+| Private user token | `<your_access_token>` |
+| Personal access token | `n671WNGecHugsdEDPsyo` |
+| Application ID | `2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6` |
+| Application secret | `04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df` |
+| CI/CD variable | `Li8j-mLUVA3eZYjPfd_H` |
+| Specific runner token | `yrnZW46BrtBFqM7xDzE7dddd` |
+| Shared runner token | `6Vk7ZsosqQyfreAxXTZr` |
+| Trigger token | `be20d8dcc028677c931e04f3871a9b` |
+| Webhook secret token | `6XhDroRcYPM5by_h-HLY` |
+| Health check token | `Tu7BgjR9qeZTEyRzGG2P` |
+| Request profile token | `7VgpS4Ax5utVD2esNstz` |
+
### Language to avoid
When creating documentation, limit or avoid the use of the following verb
@@ -529,6 +583,7 @@ tenses, words, and phrases:
- Avoid the use of [racially-insensitive terminology or phrases](https://www.marketplace.org/2020/06/17/tech-companies-update-language-to-avoid-offensive-terms/). For example:
- Use *primary* and *secondary* for database and server relationships.
- Use *allowlist* and *denylist* to describe access control lists.
+- Avoid the word *please*. For details, see [the Microsoft style guide](https://docs.microsoft.com/en-us/style-guide/a-z-word-list-term-collections/p/please).
### Word usage clarifications
@@ -832,8 +887,10 @@ When creating tables of lists of features (such as whether or not features are
available to certain roles on the [Permissions](../../user/permissions.md#project-members-permissions)
page), use the following phrases (based on the SVG icons):
-- *No*: **{dotted-circle}** No
-- *Yes*: **{check-circle}** Yes
+| Option | Markdown | Displayed result |
+|--------|--------------------------|------------------------|
+| No | `**{dotted-circle}** No` | **{dotted-circle}** No |
+| Yes | `**{check-circle}** Yes` | **{check-circle}** Yes |
## Quotes
@@ -890,8 +947,8 @@ search engine optimization (SEO), use the imperative, where possible.
For guidelines on capitalizing headings, see the section on [capitalization](#capitalization).
NOTE: **Note:**
-If you change an existing title, be careful. Any such changes may affect not
-only [links](#anchor-links) within the page, but may also affect links to the
+If you change an existing title, be careful. These changes might affect not
+only [links](#anchor-links) within the page, but might also affect links to the
GitLab documentation from both the GitLab application and external sites.
### Anchor links
@@ -1095,14 +1152,26 @@ document to ensure it links to the most recent version of the file.
## Navigation
-To indicate the steps of navigation through the user interface:
+When documenting navigation through the user interface:
-- Use the exact word as shown in the UI, including any capital letters as-is.
+- Use the exact wording as shown in the UI, including any capital letters as-is.
- Use bold text for navigation items and the char "greater than" (`>`) as a
- separator (for example, `Navigate to your project's **Settings > CI/CD**` ).
+ separator. For example: `Navigate to your project's **Settings > CI/CD**`.
- If there are any expandable menus, make sure to mention that the user needs to
- expand the tab to find the settings you're referring to (for example,
- `Navigate to your project's **Settings > CI/CD** and expand **General pipelines**`).
+ expand the tab to find the settings you're referring to. For example:
+ `Navigate to your project's **Settings > CI/CD** and expand **General pipelines**`.
+
+### Navigational elements
+
+Use the following terms when referring to the main GitLab user interface
+elements:
+
+- **Top menu**: This is the top menu that spans the width of the user interface.
+ It includes the GitLab logo, search field, counters, and the user's avatar.
+- **Left sidebar**: This is the navigation sidebar on the left of the user
+ interface, specific to the project or group.
+- **Right sidebar**: This is the navigation sidebar on the right of the user
+ interface, specific to the open issue, merge request, or epic.
## Images
@@ -1162,9 +1231,6 @@ that:
- Are accurate, succinct, and unique.
- Don't use *image of …* or *graphic of…* to describe the image.
-Also, if a heading immediately follows an image, be sure to add three dashes
-(`---`) between the image and the heading.
-
### Remove image shadow
All images displayed on the [GitLab documentation site](https://docs.gitlab.com)
@@ -1249,7 +1315,7 @@ reviewed and approved by a technical writer.
1. In YouTube, visit the video URL you want to display. Copy the regular URL
from your browser (`https://www.youtube.com/watch?v=VIDEO-ID`) and replace
the video title and link in the line under `<div class="video-fallback">`.
-1. In YouTube, click **Share**, and then click **Embed**.
+1. In YouTube, select **Share**, and then select **Embed**.
1. Copy the `<iframe>` source (`src`) **URL only**
(`https://www.youtube.com/embed/VIDEO-ID`),
and paste it, replacing the content of the `src` field in the
@@ -1292,6 +1358,9 @@ the documentation site, but will be displayed on GitLab's `/help`.
added to code blocks. To make things easier for the user, always add a full
code block for things that can be useful to copy and paste, as they can easily
do it with the button on code blocks.
+- HTTP methods (`HTTP POST`) and HTTP status codes, both full (`404 File Not Found`)
+ and abbreviated (`404`), should be wrapped in inline code blocks when used in sentences.
+ For example: Send a `DELETE` request to delete the runner. Send a `POST` request to create one.
- Add a blank line above and below code blocks.
- When providing a shell command and its output, prefix the shell command with `$`
and leave a blank line between the command and the output.
@@ -1416,17 +1485,17 @@ interface:
Use an icon when you find yourself having to describe an interface element. For
example:
-- Do: Click the Admin Area icon ( **{admin}** ).
-- Don't: Click the Admin Area icon (the wrench icon).
+- Do: Select the Admin Area icon ( **{admin}** ).
+- Don't: Select the Admin Area icon (the wrench icon).
## Alert boxes
When you need to call special attention to particular sentences, use the
following markup to create highlighted alert boxes.
-Note that the alert boxes only work for one paragraph only. Multiple paragraphs,
-lists, headers and so on, will not render correctly. For multiple lines, use
-[blockquotes](#blockquotes) instead.
+Alert boxes work for one paragraph only. Multiple paragraphs, lists, and headers
+won't render correctly. For multiple lines, use [blockquotes](#blockquotes)
+instead.
Alert boxes render only on the GitLab documentation site (<https://docs.gitlab.com>).
Within GitLab itself, they will appear as plain Markdown text (like the examples
@@ -1444,23 +1513,20 @@ guidelines, but for consistency you should try to use these values:
### Note
-Notes catch the eye of most readers, and therefore should be used very sparingly.
-In most cases, content considered for a note should be included:
+Notes indicate additional information that is of special use to the reader.
+Notes are most effective when used _sparingly_.
-- As just another sentence in the previous paragraph or the most-relevant
- paragraph.
-- As its own standalone paragraph.
-- As content under a new subheading that introduces the topic, making it more
- visible or findable.
+Try to avoid them. Too many notes can impact the scannability of a topic and
+create an overly busy page.
-#### When to use
+Instead of adding a note, try one of these alternatives:
-Use a note when there is a reason that most or all readers who browse the
-section should see the content. That is, if missed, it’s likely to cause major
-trouble for a minority of users or significant trouble for a majority of users.
+- Re-write the sentence as part of the most-relevant paragraph.
+- Put the information into its own standalone paragraph.
+- Put the content under a new subheading that introduces the topic, which makes
+ it more visible.
-Weigh the costs of distracting users to whom the content is not relevant against
-the cost of users missing the content if it were not expressed as a note.
+If you must use a note, use the following formatting:
```markdown
NOTE: **Note:**
@@ -1582,12 +1648,11 @@ application:
The following are recommended verbs for specific uses with user interface
elements:
-| Recommended | Used for | Replaces |
-|:--------------------|:---------------------------|:---------------------------|
-| *click* | buttons, links, menu items | "hit", "press", "select" |
-| *select* or *clear* | checkboxes | "enable", "click", "press" |
-| *select* | dropdowns | "pick" |
-| *expand* | expandable sections | "open" |
+| Recommended | Used for | Replaces |
+|:--------------------|:--------------------------------------|:---------------------------|
+| *select* | buttons, links, menu items, dropdowns | "click, "press," "hit" |
+| *select* or *clear* | checkboxes | "enable", "click", "press" |
+| *expand* | expandable sections | "open" |
### Other Verbs
@@ -1614,6 +1679,15 @@ heading level.
### Text for documentation requiring version text
+When a feature is new or updated, you can add version information as a bulleted
+item in the **Version history**, or as an inline reference with related text.
+
+#### Version text in the **Version History**
+
+If all content in a section is related, add version text in a bulleted list
+following the heading for the section. To render correctly, it must be on its
+own line and surrounded by blank lines.
+
- For features that need to declare the GitLab version that the feature was
introduced. Text similar to the following should be added immediately below
the heading as a blockquote:
@@ -1663,9 +1737,20 @@ heading level.
and replaced by [Feature name](link-to-feature-documentation).
```
-NOTE: **Note:**
-Version text must be on its own line and surrounded by blank lines to render
-correctly.
+#### Inline version text
+
+If you're adding content to an existing topic, you can add version information
+inline with the existing text.
+
+In this case, add `([introduced/deprecated](<link-to-issue>) in GitLab X.X)`.
+If applicable, include the paid tier: `([introduced/deprecated](<link-to-issue>) in [GitLab Premium](https://about.gitlab.com/pricing/) 12.4)`
+
+Including the issue link is encouraged, but isn't a requirement. For example:
+
+```markdown
+The voting strategy (introduced in GitLab 13.4) requires
+the primary and secondary voters to agree.
+```
### Versions in the past or future
@@ -1807,7 +1892,7 @@ for the changes to take effect.
If the document you are editing resides in a place other than the GitLab CE/EE
`doc/` directory, instead of the relative link, use the full path:
-`https://docs.gitlab.com/ce/administration/restart_gitlab.html`. Replace
+`https://docs.gitlab.com/ee/administration/restart_gitlab.html`. Replace
`reconfigure` with `restart` where appropriate.
### Installation guide
@@ -1894,216 +1979,9 @@ steps aren't required, consider setting up a [table](#tables) with headers of
Learn how to [document features deployed behind flags](feature_flags.md). For
guidance on developing GitLab with feature flags, see [Feature flags in development of GitLab](../feature_flags/index.md).
-## RESTful API
-
-REST API resources are documented in Markdown under
-[`/doc/api`](https://gitlab.com/gitlab-org/gitlab/-/tree/master/doc/api). Each
-resource has its own Markdown file, which is linked from `api_resources.md`.
-
-When modifying the Markdown, also update the corresponding
-[OpenAPI definition](https://gitlab.com/gitlab-org/gitlab/-/tree/master/doc/api/openapi)
-if one exists for the resource. If not, consider creating one. Match the latest
-[OpenAPI 3.0.x specification](https://swagger.io/specification/). (For more
-information, see the discussion in this
-[issue](https://gitlab.com/gitlab-org/gitlab/-/issues/16023#note_370901810).)
-
-In the Markdown doc for a resource (AKA endpoint):
-
-- Every method must have the REST API request. For example:
-
- ```plaintext
- GET /projects/:id/repository/branches
- ```
-
-- Every method must have a detailed [description of the parameters](#method-description).
-- Every method must have a cURL example.
-- Every method must have a response body (in JSON format).
-
-### API topic template
-
-The following can be used as a template to get started:
-
-````markdown
-## Descriptive title
-
-One or two sentence description of what endpoint does.
-
-```plaintext
-METHOD /endpoint
-```
-
-| Attribute | Type | Required | Description |
-|:------------|:---------|:---------|:----------------------|
-| `attribute` | datatype | yes/no | Detailed description. |
-| `attribute` | datatype | yes/no | Detailed description. |
-
-Example request:
-
-```shell
-curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/endpoint?parameters"
-```
-
-Example response:
-
-```json
-[
- {
- }
-]
-```
-````
-
-### Fake user information
-
-You may need to demonstrate an API call or a cURL command that includes the name
-and email address of a user. Don't use real user information in API calls:
-
-- **Email addresses**: Use an email address ending in `example.com`.
-- **Names**: Use strings like `Example Username`. Alternatively, use diverse or
- non-gendered names with common surnames, such as `Sidney Jones`, `Zhang Wei`,
- or `Maria Garcia`.
-
-### Fake URLs
-
-When including sample URLs in the documentation, use:
-
-- `example.com` when the domain name is generic.
-- `gitlab.example.com` when referring to self-managed instances of GitLab.
-
-### Fake tokens
-
-There may be times where a token is needed to demonstrate an API call using
-cURL or a variable used in CI. It is strongly advised not to use real tokens in
-documentation even if the probability of a token being exploited is low.
-
-You can use the following fake tokens as examples:
-
-| Token type | Token value |
-|:----------------------|:-------------------------------------------------------------------|
-| Private user token | `<your_access_token>` |
-| Personal access token | `n671WNGecHugsdEDPsyo` |
-| Application ID | `2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6` |
-| Application secret | `04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df` |
-| CI/CD variable | `Li8j-mLUVA3eZYjPfd_H` |
-| Specific runner token | `yrnZW46BrtBFqM7xDzE7dddd` |
-| Shared runner token | `6Vk7ZsosqQyfreAxXTZr` |
-| Trigger token | `be20d8dcc028677c931e04f3871a9b` |
-| Webhook secret token | `6XhDroRcYPM5by_h-HLY` |
-| Health check token | `Tu7BgjR9qeZTEyRzGG2P` |
-| Request profile token | `7VgpS4Ax5utVD2esNstz` |
-
-### Method description
-
-Use the following table headers to describe the methods. Attributes should
-always be in code blocks using backticks (`` ` ``).
-
-```markdown
-| Attribute | Type | Required | Description |
-|:----------|:-----|:---------|:------------|
-```
-
-Rendered example:
-
-| Attribute | Type | Required | Description |
-|:----------|:-------|:---------|:--------------------|
-| `user` | string | yes | The GitLab username |
-
-### cURL commands
-
-- Use `https://gitlab.example.com/api/v4/` as an endpoint.
-- Wherever needed use this personal access token: `<your_access_token>`.
-- Always put the request first. `GET` is the default so you don't have to
- include it.
-- Wrap the URL in double quotes (`"`).
-- Prefer to use examples using the personal access token and don't pass data of
- username and password.
-
-| Methods | Description |
-|:------------------------------------------- |:------------------------------------------------------|
-| `--header "PRIVATE-TOKEN: <your_access_token>"` | Use this method as is, whenever authentication needed |
-| `--request POST` | Use this method when creating new objects |
-| `--request PUT` | Use this method when updating existing objects |
-| `--request DELETE` | Use this method when removing existing objects |
-
-### cURL Examples
-
-The following sections include a set of [cURL](https://curl.haxx.se) examples
-you can use in the API documentation.
-
-#### Simple cURL command
-
-Get the details of a group:
-
-```shell
-curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/groups/gitlab-org"
-```
-
-#### cURL example with parameters passed in the URL
-
-Create a new project under the authenticated user's namespace:
-
-```shell
-curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects?name=foo"
-```
-
-#### Post data using cURL's `--data`
-
-Instead of using `--request POST` and appending the parameters to the URI, you
-can use cURL's `--data` option. The example below will create a new project
-`foo` under the authenticated user's namespace.
-
-```shell
-curl --data "name=foo" --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects"
-```
-
-#### Post data using JSON content
-
-NOTE: **Note:**
-In this example we create a new group. Watch carefully the single and double
-quotes.
-
-```shell
-curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" --header "Content-Type: application/json" --data '{"path": "my-group", "name": "My group"}' "https://gitlab.example.com/api/v4/groups"
-```
-
-#### Post data using form-data
-
-Instead of using JSON or urlencode you can use multipart/form-data which
-properly handles data encoding:
-
-```shell
-curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" --form "title=ssh-key" --form "key=ssh-rsa AAAAB3NzaC1yc2EA..." "https://gitlab.example.com/api/v4/users/25/keys"
-```
-
-The above example is run by and administrator and will add an SSH public key
-titled `ssh-key` to user's account which has an ID of 25.
-
-#### Escape special characters
-
-Spaces or slashes (`/`) may sometimes result to errors, thus it is recommended
-to escape them when possible. In the example below we create a new issue which
-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"
-```
-
-Use `%2F` for slashes (`/`).
-
-#### Pass arrays to API calls
-
-The GitLab API sometimes accepts arrays of strings or integers. For example, to
-exclude specific users when requesting a list of users for a project, you would
-do something like this:
-
-```shell
-curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" --data "skip_users[]=<user_id>" --data "skip_users[]=<user_id>" "https://gitlab.example.com/api/v4/projects/<project_id>/users"
-```
-
## GraphQL API
-GraphQL APIs are different from [RESTful APIs](#restful-api). Reference
+GraphQL APIs are different from [RESTful APIs](restful_api_styleguide.md). Reference
information is generated in our [GraphQL reference](../../api/graphql/reference/index.md).
However, it's helpful to include examples on how to use GraphQL for different
@@ -2158,7 +2036,7 @@ Set up the section with the following:
```markdown
1. Open the GraphiQL explorer tool in the following URL: `https://gitlab.com/-/graphql-explorer`.
1. Paste the `query` listed above into the left window of your GraphiQL explorer tool.
- 1. Click Play to get the result shown here:
+ 1. Select Play to get the result shown here:
```
- Include a screenshot of the result in the GraphiQL explorer. Follow the naming
diff --git a/doc/development/elasticsearch.md b/doc/development/elasticsearch.md
index e70cf456101..639759e5014 100644
--- a/doc/development/elasticsearch.md
+++ b/doc/development/elasticsearch.md
@@ -9,7 +9,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
This area is to maintain a compendium of useful information when working with Elasticsearch.
Information on how to enable Elasticsearch and perform the initial indexing is in
-the [Elasticsearch integration documentation](../integration/elasticsearch.md#enabling-elasticsearch).
+the [Elasticsearch integration documentation](../integration/elasticsearch.md#enabling-advanced-search).
## Deep Dive
diff --git a/doc/development/emails.md b/doc/development/emails.md
index cf7f49ee834..de9607fef64 100644
--- a/doc/development/emails.md
+++ b/doc/development/emails.md
@@ -27,7 +27,7 @@ Please note that [S/MIME signed](../administration/smime_signing_email.md) email
## Mailer previews
Rails provides a way to preview our mailer templates in HTML and plaintext using
-dummy data.
+sample data.
The previews live in [`app/mailers/previews`](https://gitlab.com/gitlab-org/gitlab-foss/tree/master/app/mailers/previews) and can be viewed at
[`/rails/mailers`](http://localhost:3000/rails/mailers).
diff --git a/doc/development/event_tracking/backend.md b/doc/development/event_tracking/backend.md
index 93e135772ef..79ea80a52ea 100644
--- a/doc/development/event_tracking/backend.md
+++ b/doc/development/event_tracking/backend.md
@@ -1,5 +1,5 @@
---
-redirect_to: '../telemetry/index.md'
+redirect_to: '../product_analytics/index.md'
---
-This document was moved to [another location](../telemetry/index.md).
+This document was moved to [another location](../product_analytics/index.md).
diff --git a/doc/development/event_tracking/frontend.md b/doc/development/event_tracking/frontend.md
index 93e135772ef..79ea80a52ea 100644
--- a/doc/development/event_tracking/frontend.md
+++ b/doc/development/event_tracking/frontend.md
@@ -1,5 +1,5 @@
---
-redirect_to: '../telemetry/index.md'
+redirect_to: '../product_analytics/index.md'
---
-This document was moved to [another location](../telemetry/index.md).
+This document was moved to [another location](../product_analytics/index.md).
diff --git a/doc/development/event_tracking/index.md b/doc/development/event_tracking/index.md
index 93e135772ef..79ea80a52ea 100644
--- a/doc/development/event_tracking/index.md
+++ b/doc/development/event_tracking/index.md
@@ -1,5 +1,5 @@
---
-redirect_to: '../telemetry/index.md'
+redirect_to: '../product_analytics/index.md'
---
-This document was moved to [another location](../telemetry/index.md).
+This document was moved to [another location](../product_analytics/index.md).
diff --git a/doc/development/experiment_guide/index.md b/doc/development/experiment_guide/index.md
index 07b803603a5..18b606450c2 100644
--- a/doc/development/experiment_guide/index.md
+++ b/doc/development/experiment_guide/index.md
@@ -16,46 +16,97 @@ In either case, an outcome of the experiment should be posted to the issue with
## Code reviews
-Since the code of experiments will not be part of the codebase for a long time and we want to iterate fast to retrieve data, the code quality of experiments might sometimes not fulfill our standards but should not negatively impact the availability of GitLab whether the experiment is running or not.
-Initially experiments will only be deployed to a fraction of users but we still want a flawless experience for those users. Therefore, experiments still require tests.
-
-For reviewers and maintainers: if you find code that would usually not make it through the review, but is temporarily acceptable, please mention your concerns but note that it's not necessary to change.
-The author then adds a comment to this piece of code and adds a link to the issue that resolves the experiment. If the experiment is successful and becomes part of the product these follow up issues should be addressed.
+Experiments' code quality can fail our standards for several reasons. These
+reasons can include not being added to the codebase for a long time, or because
+of fast iteration to retrieve data. However, having the experiment run (or not
+run) shouldn't impact GitLab's availability. To avoid or identify issues,
+experiments are initially deployed to a small number of users. Regardless,
+experiments still need tests.
+
+If, as a reviewer or maintainer, you find code that would usually fail review
+but is acceptable for now, mention your concerns with a note that there's no
+need to change the code. The author can then add a comment to this piece of code
+and link to the issue that resolves the experiment. If the experiment is
+successful and becomes part of the product, any follow up issues should be
+addressed.
## How to create an A/B test
-- Add the experiment to the `Gitlab::Experimentation::EXPERIMENTS` hash in [`experimentation.rb`](https://gitlab.com/gitlab-org/gitlab/blob/master/lib%2Fgitlab%2Fexperimentation.rb):
-
- ```ruby
- EXPERIMENTS = {
- other_experiment: {
- #...
- },
- # Add your experiment here:
- signup_flow: {
- environment: ::Gitlab.dev_env_or_com?, # Target environment, defaults to enabled for development and GitLab.com
- tracking_category: 'Growth::Acquisition::Experiment::SignUpFlow' # Used for providing the category when setting up tracking data
- }
- }.freeze
- ```
-
-- Use the experiment in a controller:
-
- ```ruby
- class RegistrationController < ApplicationController
- def show
- # experiment_enabled?(:feature_name) is also available in views and helpers
- if experiment_enabled?(:signup_flow)
- # render the experiment
- else
- # render the original version
- end
- end
- end
- ```
-
-- Track necessary events. See the [telemetry guide](../telemetry/index.md) for details.
-- After the merge request is merged, use [`chatops`](../../ci/chatops/README.md) in the
+### Implementation
+
+1. Add the experiment to the `Gitlab::Experimentation::EXPERIMENTS` hash in [`experimentation.rb`](https://gitlab.com/gitlab-org/gitlab/blob/master/lib%2Fgitlab%2Fexperimentation.rb):
+
+ ```ruby
+ EXPERIMENTS = {
+ other_experiment: {
+ #...
+ },
+ # Add your experiment here:
+ signup_flow: {
+ environment: ::Gitlab.dev_env_or_com?, # Target environment, defaults to enabled for development and GitLab.com
+ tracking_category: 'Growth::Acquisition::Experiment::SignUpFlow' # Used for providing the category when setting up tracking data
+ }
+ }.freeze
+ ```
+
+1. Use the experiment in the code.
+
+ - Use this standard for the experiment in a controller:
+
+ ```ruby
+ class RegistrationController < ApplicationController
+ def show
+ # experiment_enabled?(:experiment_key) is also available in views and helpers
+ if experiment_enabled?(:signup_flow)
+ # render the experiment
+ else
+ # render the original version
+ end
+ end
+ end
+ ```
+
+ - Make the experiment available to the frontend in a controller:
+
+ ```ruby
+ before_action do
+ push_frontend_experiment(:signup_flow)
+ end
+ ```
+
+ The above will check whether the experiment is enabled and push the result to the frontend.
+
+ You can check the state of the feature flag in JavaScript:
+
+ ```javascript
+ import { isExperimentEnabled } from '~/experimentation';
+
+ if ( isExperimentEnabled('signupFlow') ) {
+ // ...
+ }
+ ```
+
+ - It is also possible to run an experiment outside of the controller scope, for example in a worker:
+
+ ```ruby
+ class SomeWorker
+ def perform
+ # Check if the experiment is enabled at all (the percentage_of_time_value > 0)
+ return unless Gitlab::Experimentation.enabled?(:experiment_key)
+
+ # Since we cannot access cookies in a worker, we need to bucket models based on a unique, unchanging attribute instead.
+ # Use the following method to check if the experiment is enabled for a certain attribute, for example a username or email address:
+ if Gitlab::Experimentation.enabled_for_attribute?(:experiment_key, some_attribute)
+ # execute experimental code
+ else
+ # execute control code
+ end
+ end
+ end
+ ```
+
+1. Track necessary events. See the [product analytics guide](../product_analytics/index.md) for details.
+1. After the merge request is merged, use [`chatops`](../../ci/chatops/README.md) in the
[appropriate channel](../feature_flags/controls.md#communicate-the-change) to start the experiment for 10% of the users.
The feature flag should have the name of the experiment with the `_experiment_percentage` suffix appended.
For visibility, please also share any commands run against production in the `#s_growth` channel:
@@ -69,3 +120,19 @@ For visibility, please also share any commands run against production in the `#s
```shell
/chatops run feature delete signup_flow_experiment_percentage
```
+
+### Tests and test helpers
+
+Use the following in Jest to test the experiment is enabled.
+
+```javascript
+import { withGonExperiment } from 'helpers/experimentation_helper';
+
+describe('given experiment is enabled', () => {
+ withGonExperiment('signupFlow');
+
+ it('should do the experimental thing', () => {
+ expect(wrapper.find('.js-some-experiment-triggered-element')).toEqual(expect.any(Element));
+ });
+});
+```
diff --git a/doc/development/fe_guide/architecture.md b/doc/development/fe_guide/architecture.md
index 3d27f67a8a6..c7e1ba59f23 100644
--- a/doc/development/fe_guide/architecture.md
+++ b/doc/development/fe_guide/architecture.md
@@ -15,5 +15,5 @@ You can find the Frontend Architecture experts on the [team page](https://about.
## Examples
-You can find documentation about the desired architecture for a new feature
-built with Vue.js [here](vue.md).
+You can find [documentation about the desired architecture](vue.md) for a new
+feature built with Vue.js.
diff --git a/doc/development/fe_guide/dependencies.md b/doc/development/fe_guide/dependencies.md
index 7f078df887d..ba97e7e39be 100644
--- a/doc/development/fe_guide/dependencies.md
+++ b/doc/development/fe_guide/dependencies.md
@@ -18,9 +18,9 @@ automatically create merge requests for updating dependencies of several project
up-to-date list of projects managed by the renovate bot in the project’s README. Some key dependencies
updated using renovate are:
-- [`@gitlab/ui`](https://gitlab.com/gitlab-org/gitlab-ui/)
-- [`@gitlab/svgs`](https://gitlab.com/gitlab-org/gitlab-svgs/)
-- [`@gitlab/eslint-config`](https://gitlab.com/gitlab-org/gitlab-eslint-config)
+- [`@gitlab/ui`](https://gitlab.com/gitlab-org/gitlab-ui)
+- [`@gitlab/svgs`](https://gitlab.com/gitlab-org/gitlab-svgs)
+- [`@gitlab/eslint-plugin`](https://gitlab.com/gitlab-org/frontend/eslint-plugin)
### Blocked dependencies
diff --git a/doc/development/fe_guide/event_tracking.md b/doc/development/fe_guide/event_tracking.md
index 93e135772ef..79ea80a52ea 100644
--- a/doc/development/fe_guide/event_tracking.md
+++ b/doc/development/fe_guide/event_tracking.md
@@ -1,5 +1,5 @@
---
-redirect_to: '../telemetry/index.md'
+redirect_to: '../product_analytics/index.md'
---
-This document was moved to [another location](../telemetry/index.md).
+This document was moved to [another location](../product_analytics/index.md).
diff --git a/doc/development/fe_guide/graphql.md b/doc/development/fe_guide/graphql.md
index 82cd19dce4f..ad3958d4496 100644
--- a/doc/development/fe_guide/graphql.md
+++ b/doc/development/fe_guide/graphql.md
@@ -187,7 +187,7 @@ As shown in the code example by using `produce`, we can perform any kind of dire
`draftState`. Besides, `immer` guarantees that a new state which includes the changes to `draftState` will be generated.
Finally, to verify whether the immutable cache update is working properly, we need to change
-`assumeImmutableResults` to `true` in the `default client config` (see [Apollo Client](#apollo-client) for more info).
+`assumeImmutableResults` to `true` in the `default client config` (see [Apollo Client](#apollo-client) for more info).
If everything is working properly `assumeImmutableResults` should remain set to `true`.
@@ -308,7 +308,7 @@ const resolvers = {
export default resolvers;
```
-We need to pass resolvers object to our existing Apollo Client:
+We need to pass a resolvers object to our existing Apollo Client:
```javascript
// graphql.js
@@ -319,13 +319,13 @@ import resolvers from './graphql/resolvers';
const defaultClient = createDefaultClient(resolvers);
```
-Now every single time on attempt to fetch a version, our client will fetch `id` and `sha` from the remote API endpoint and will assign our hardcoded values to `author` and `createdAt` version properties. With this data, frontend developers are able to work on UI part without being blocked by backend. When actual response is added to the API, a custom local resolver can be removed fast and the only change to query/fragment is `@client` directive removal.
+For each attempt to fetch a version, our client will fetch `id` and `sha` from the remote API endpoint and will assign our hardcoded values to the `author` and `createdAt` version properties. With this data, frontend developers are able to work on their UI without being blocked by backend. When the actual response is added to the API, our custom local resolver can be removed and the only change to the query/fragment is to remove the `@client` directive.
Read more about local state management with Apollo in the [Vue Apollo documentation](https://vue-apollo.netlify.app/guide/local-state.html#local-state).
### Using with Vuex
-When Apollo Client is used within Vuex and fetched data is stored in the Vuex store, there is no need in keeping Apollo Client cache enabled. Otherwise we would have data from the API stored in two places - Vuex store and Apollo Client cache. More to say, with Apollo's default settings, a subsequent fetch from the GraphQL API could result in fetching data from Apollo cache (in the case where we have the same query and variables). To prevent this behavior, we need to disable Apollo Client cache passing a valid `fetchPolicy` option to its constructor:
+When Apollo Client is used within Vuex and fetched data is stored in the Vuex store, there is no need to keep Apollo Client cache enabled. Otherwise we would have data from the API stored in two places - Vuex store and Apollo Client cache. With Apollo's default settings, a subsequent fetch from the GraphQL API could result in fetching data from Apollo cache (in the case where we have the same query and variables). To prevent this behavior, we need to disable Apollo Client cache by passing a valid `fetchPolicy` option to its constructor:
```javascript
import fetchPolicies from '~/graphql_shared/fetch_policy_constants';
diff --git a/doc/development/fe_guide/icons.md b/doc/development/fe_guide/icons.md
index b539293e9cf..67add5709d9 100644
--- a/doc/development/fe_guide/icons.md
+++ b/doc/development/fe_guide/icons.md
@@ -1,9 +1,10 @@
# Icons and SVG Illustrations
-We manage our own Icon and Illustration library in the [`gitlab-svgs`](https://gitlab.com/gitlab-org/gitlab-svgs) repository.
-This repository is published on [npm](https://www.npmjs.com/package/@gitlab/svgs) and managed as a dependency via yarn.
-You can browse all available Icons and Illustrations [here](https://gitlab-org.gitlab.io/gitlab-svgs).
-To upgrade to a new version run `yarn upgrade @gitlab/svgs`.
+We manage our own icon and illustration library in the [`gitlab-svgs`](https://gitlab.com/gitlab-org/gitlab-svgs)
+repository. This repository is published on [npm](https://www.npmjs.com/package/@gitlab/svgs),
+and is managed as a dependency with yarn. You can browse all available
+[icons and illustrations](https://gitlab-org.gitlab.io/gitlab-svgs). To upgrade
+to a new version run `yarn upgrade @gitlab/svgs`.
## Icons
@@ -21,10 +22,11 @@ To use a sprite Icon in HAML or Rails we use a specific helper function :
sprite_icon(icon_name, size: nil, css_class: '')
```
-- **icon_name** Use the icon_name that you can find in the SVG Sprite
- ([Overview is available here](https://gitlab-org.gitlab.io/gitlab-svgs)).
-- **size (optional)** Use one of the following sizes : 16, 24, 32, 48, 72 (this will be translated into a `s16` class)
-- **css_class (optional)** If you want to add additional CSS classes
+- **icon_name**: Use the icon_name for the SVG sprite in the list of
+ ([GitLab SVGs](https://gitlab-org.gitlab.io/gitlab-svgs)).
+- **size (optional)**: Use one of the following sizes : 16, 24, 32, 48, 72 (this
+ will be translated into a `s16` class)
+- **css_class (optional)**: If you want to add additional CSS classes.
**Example**
@@ -66,10 +68,12 @@ export default {
</template>
```
-- **name** Name of the Icon in the SVG Sprite ([Overview is available here](https://gitlab-org.gitlab.io/gitlab-svgs)).
-- **size (optional)** Number value for the size which is then mapped to a specific CSS class
- (Available Sizes: 8, 12, 16, 18, 24, 32, 48, 72 are mapped to `sXX` CSS classes)
-- **class (optional)** Additional CSS Classes to add to the SVG tag.
+- **name**: Name of the icon of the SVG sprite, as listed in the
+ ([GitLab SVG Previewer](https://gitlab-org.gitlab.io/gitlab-svgs)).
+- **size: (optional)** Number value for the size which is then mapped to a
+ specific CSS class (Available sizes: 8, 12, 16, 18, 24, 32, 48, 72 are mapped
+ to `sXX` CSS classes)
+- **class (optional)**: Additional CSS classes to add to the SVG tag.
### Usage in HTML/JS
diff --git a/doc/development/fe_guide/index.md b/doc/development/fe_guide/index.md
index ef23b6c4ed2..f909866d44e 100644
--- a/doc/development/fe_guide/index.md
+++ b/doc/development/fe_guide/index.md
@@ -76,6 +76,10 @@ How we use SVG for our [Icons and Illustrations](icons.md).
General information about frontend [dependencies](dependencies.md) and how we manage them.
+## Keyboard Shortcuts
+
+How we implement [keyboard shortcuts](keyboard_shortcuts.md) that can be customized and disabled.
+
## Frontend FAQ
Read the [frontend's FAQ](frontend_faq.md) for common small pieces of helpful information.
diff --git a/doc/development/fe_guide/keyboard_shortcuts.md b/doc/development/fe_guide/keyboard_shortcuts.md
new file mode 100644
index 00000000000..da9b3702a8d
--- /dev/null
+++ b/doc/development/fe_guide/keyboard_shortcuts.md
@@ -0,0 +1,98 @@
+# Implementing keyboard shortcuts
+
+We use [Mousetrap](https://craig.is/killing/mice) to implement keyboard
+shortcuts in GitLab.
+
+Mousetrap provides an API that allows keyboard shortcut strings (like
+`mod+shift+p` or `p b`) to be bound to a JavaScript handler:
+
+```javascript
+// Don't do this; see note below
+Mousetrap.bind('p b', togglePerformanceBar)
+```
+
+However, associating a hard-coded key sequence to a handler (as shown above)
+prevents these keyboard shortcuts from being customized or disabled by users.
+
+To allow keyboard shortcuts to be customized, commands are defined in
+`~/behaviors/shortcuts/keybindings.js`. The `keysFor` method is responsible for
+returning the correct key sequence for the provided command:
+
+```javascript
+import { keysFor, TOGGLE_PERFORMANCE_BAR } from '~/behaviors/shortcuts/keybindings'
+
+Mousetrap.bind(keysFor(TOGGLE_PERFORMANCE_BAR), togglePerformanceBar);
+```
+
+## Shortcut customization
+
+`keybindings.js` stores keyboard shortcut customizations as a JSON string in
+`localStorage`. When `keybindings.js` is first imported, it fetches any
+customizations from `localStorage` and merges these customizations into the
+default set of keybindings. There is no UI to edit these customizations.
+
+## Adding new shortcuts
+
+Because keyboard shortcuts can be customized or disabled by end users,
+developers are encouraged to build _lots_ of keyboard shortcuts into GitLab.
+Shortcuts that are less likely to be used should be
+[disabled](#disabling-shortcuts) by default.
+
+To add a new shortcut, define and export a new command string in
+`keybindings.js`:
+
+```javascript
+export const MAKE_COFFEE = 'foodAndBeverage.makeCoffee';
+```
+
+Next, add a new command definition under the appropriate group in the
+`keybindingGroups` array:
+
+```javascript
+{
+ description: s__('KeyboardShortcuts|Make coffee'),
+ command: MAKE_COFFEE,
+ defaultKeys: ['mod+shift+c'],
+ customKeys: customizations[MAKE_COFFEE],
+}
+```
+
+Finally, in the application code, import the `keysFor` function and the new
+command and bind the shortcut to the handler using Mousetrap:
+
+```javascript
+import { keysFor, MAKE_COFFEE } from '~/behaviors/shortcuts/keybindings'
+
+Mousetrap.bind(keysFor(MAKE_COFFEE), makeCoffee);
+```
+
+See the existing the command definitions in `keybindings.js` for more examples.
+
+## Disabling shortcuts
+
+A shortcut can be disabled, also known as _unassigned_, by assigning the
+shortcut to an empty array `[]`. For example, to introduce a new shortcut that
+is disabled by default, a command can be defined like this:
+
+```javascript
+export const MAKE_MOCHA = 'foodAndBeverage.makeMocha';
+
+{
+ description: s__('KeyboardShortcuts|Make a mocha'),
+ command: MAKE_MOCHA,
+ defaultKeys: [],
+ customKeys: customizations[MAKE_MOCHA],
+}
+```
+
+## Make cross-platform shortcuts
+
+It's difficult to make shortcuts that work well in all platforms and browsers.
+This is one of the reasons that being able to customize and disable shortcuts is
+so important.
+
+One important way to make keyboard shortcuts more portable is to use the `mod`
+shortcut string, which resolves to `command` on Mac and `ctrl` otherwise.
+
+See [Mousetrap's documentation](https://craig.is/killing/mice#api.bind.combo)
+for more information.
diff --git a/doc/development/fe_guide/tooling.md b/doc/development/fe_guide/tooling.md
index 5685ac5abcd..b93c0a9736b 100644
--- a/doc/development/fe_guide/tooling.md
+++ b/doc/development/fe_guide/tooling.md
@@ -101,7 +101,10 @@ Our code is automatically formatted with [Prettier](https://prettier.io) to foll
### Editor
-The easiest way to include prettier in your workflow is by setting up your preferred editor (all major editors are supported) accordingly. We suggest setting up prettier to run automatically when each file is saved. Find [here](https://prettier.io/docs/en/editors.html) the best way to set it up in your preferred editor.
+The recommended method to include Prettier in your workflow is to set up your
+preferred editor (all major editors are supported) accordingly. We suggest
+setting up Prettier to run when each file is saved. For instructions about using
+Prettier in your preferred editor, see the [Prettier documentation](https://prettier.io/docs/en/editors.html).
Please take care that you only let Prettier format the same file types as the global Yarn script does (`.js`, `.vue`, `.graphql`, and `.scss`). In VSCode by example you can easily exclude file formats in your settings file:
diff --git a/doc/development/fe_guide/vuex.md b/doc/development/fe_guide/vuex.md
index 4badf3f0845..528dcb3b7f4 100644
--- a/doc/development/fe_guide/vuex.md
+++ b/doc/development/fe_guide/vuex.md
@@ -32,8 +32,9 @@ When using Vuex at GitLab, separate these concerns into different files to impro
└── mutation_types.js # mutation types
```
-The following example shows an application that lists and adds users to the state.
-(For a more complex example implementation take a look at the security applications store in [here](https://gitlab.com/gitlab-org/gitlab/tree/master/ee/app/assets/javascripts/vue_shared/security_reports/store))
+The following example shows an application that lists and adds users to the
+state. (For a more complex example implementation, review the security
+applications stored in this [repository](https://gitlab.com/gitlab-org/gitlab/tree/master/ee/app/assets/javascripts/vue_shared/security_reports/store)).
### `index.js`
diff --git a/doc/development/feature_categorization/index.md b/doc/development/feature_categorization/index.md
index 3fd402ebe84..57e0ad8b772 100644
--- a/doc/development/feature_categorization/index.md
+++ b/doc/development/feature_categorization/index.md
@@ -23,9 +23,9 @@ product categories. When this occurs, you can automatically update
and generate a new version of the file, which needs to be committed to
the repository.
-The [Scalabilitity
+The [Scalability
team](https://about.gitlab.com/handbook/engineering/infrastructure/team/scalability/)
-currently maintains the `stages.yml` file. They will automatically be
+currently maintains the `feature_categories.yml` file. They will automatically be
notified on Slack when the file becomes outdated.
## Sidekiq workers
@@ -75,38 +75,23 @@ A feature category can be specified on an entire controller
using:
```ruby
-class Projects::MergeRequestsController < ApplicationController
- feature_category :source_code_management
+class Boards::ListsController < ApplicationController
+ feature_category :kanban_boards
end
```
The feature category can be limited to a list of actions using the
-`only` argument, actions can be excluded using the `except` argument.
+second argument:
```ruby
-class Projects::MergeRequestsController < ApplicationController
- feature_category :code_testing, only: [:metrics_reports]
- feature_category :source_code_management, except: [:test_reports, :coverage_reports]
+class DashboardController < ApplicationController
+ feature_category :issue_tracking, [:issues, :issues_calendar]
+ feature_category :code_review, [:merge_requests]
end
```
-`except` and `only` arguments can not be combined.
-
-When specifying `except` all other actions will get the specified
-category assigned.
-
-The assignment can also be scoped using `if` and `unless` procs:
-
-```ruby
-class Projects::MergeRequestsController < ApplicationController
- feature_category :source_code_management,
- unless: -> (action) { action.include?("reports") }
- if: -> (action) { action.include?("widget") }
-end
-```
-
-In this case, both procs need to be satisfied for the action to get
-the category assigned.
+These forms cannot be mixed: if a controller has more than one category,
+every single action must be listed.
### Excluding controller actions from feature categorization
@@ -125,6 +110,5 @@ The `spec/controllers/every_controller_spec.rb` will iterate over all
defined routes, and check the controller to see if a category is
assigned to all actions.
-The spec also validates if the used feature categories are known. And
-if the actions used in `only` and `except` configuration still exist
-as routes.
+The spec also validates if the used feature categories are known. And if
+the actions used in configuration still exist as routes.
diff --git a/doc/development/feature_flags/controls.md b/doc/development/feature_flags/controls.md
index 605b5919e0b..ef38a85bec0 100644
--- a/doc/development/feature_flags/controls.md
+++ b/doc/development/feature_flags/controls.md
@@ -88,15 +88,13 @@ parts of the company. The developer responsible needs to determine
whether this is necessary and the appropriate level of communication.
This depends on the feature and what sort of impact it might have.
-As a guideline:
+Guidelines:
-- For simple features that are low-risk, and easily rolled back, then
- just proceed to [enabling the feature in `#production`](#process).
-- For features that will impact user experience consider notifying
+1. If the feature meets the requirements for creating a [Change Management](https://about.gitlab.com/handbook/engineering/infrastructure/change-management/#feature-flags-and-the-change-management-process) issue, create a Change Management issue per [criticality guidelines](https://about.gitlab.com/handbook/engineering/infrastructure/change-management/#change-request-workflows).
+1. For simple, low-risk, easily reverted features, proceed and [enable the feature in `#production`](#process).
+1. For features that impact the user experience, consider notifying
+ `#support_gitlab-com` first.
`#support_gitlab-com` beforehand.
-- For features with significant downstream effects (e.g.: turning on/off
- Elasticsearch indexing) consider coordinating with `#production`
- beforehand.
#### Process
@@ -250,13 +248,26 @@ Changes to the issue format can be submitted in the
## Cleaning up
-Once the change is deemed stable, submit a new merge request to remove the
-feature flag. This ensures the change is available to all users and self-managed
-instances. Make sure to add the ~"feature flag" label to this merge request so
-release managers are aware the changes are hidden behind a feature flag. If the
-merge request has to be picked into a stable branch, make sure to also add the
-appropriate `~"Pick into X.Y"` label (e.g. `~"Pick into 13.0"`).
-See [the process document](process.md#including-a-feature-behind-feature-flag-in-the-final-release) for further details.
+A feature flag should be removed as soon as it is no longer needed. Each additional
+feature flag in the codebase increases the complexity of the application
+and reduces confidence in our testing suite covering all possible combinations.
+Additionally, a feature flag overwritten in some of the environments can result
+in undefined and untested system behavior.
+
+To remove a feature flag:
+
+1. Open a new merge request with the ~"feature flag" label so
+ release managers are aware the changes are hidden behind a feature flag.
+1. If the merge request has to be picked into a stable branch, add the
+ appropriate `~"Pick into X.Y"` label, for example `~"Pick into 13.0"`.
+ See [the feature flag process](process.md#including-a-feature-behind-feature-flag-in-the-final-release)
+ for further details.
+1. Remove all references to the feature flag from the codebase.
+1. Remove the YAML definition for the feature from the repository.
+1. Clean up the feature flag from all environments with `/chatops run feature delete some_feature`.
+1. Close the rollout issue for the feature flag after the feature flag is removed from the codebase.
+
+### Cleanup ChatOps
When a feature gate has been removed from the code base, the feature
record still exists in the database that the flag was deployed too.
diff --git a/doc/development/feature_flags/development.md b/doc/development/feature_flags/development.md
index 29bd0ca0a7e..067e480f6f8 100644
--- a/doc/development/feature_flags/development.md
+++ b/doc/development/feature_flags/development.md
@@ -52,10 +52,10 @@ invocations:
```ruby
# Check if feature flag is enabled
-Feature.enabled?(:my_ops_flag, project, type: ops)
+Feature.enabled?(:my_ops_flag, project, type: :ops)
# Check if feature flag is disabled
-Feature.disabled?(:my_ops_flag, project, type: ops)
+Feature.disabled?(:my_ops_flag, project, type: :ops)
# Push feature flag to Frontend
push_frontend_feature_flag(:my_ops_flag, project, type: :ops)
@@ -153,6 +153,11 @@ default_enabled: false
TIP: **Tip:**
To create a feature flag that is only used in EE, add the `--ee` flag: `bin/feature-flag --ee`
+## Delete a feature flag
+
+See [cleaning up feature flags](controls.md#cleaning-up) for more information about
+deleting feature flags.
+
## Develop with a feature flag
There are two main ways of using Feature Flags in the GitLab codebase:
@@ -440,6 +445,21 @@ Feature.enabled?(:my_feature2) # => false
Feature.enabled?(:my_feature2, project1) # => true
```
+### `have_pushed_frontend_feature_flags`
+
+Use `have_pushed_frontend_feature_flags` to test if [`push_frontend_feature_flag`](#frontend)
+has added the feature flag to the HTML.
+
+For example,
+
+```ruby
+stub_feature_flags(value_stream_analytics_path_navigation: false)
+
+visit group_analytics_cycle_analytics_path(group)
+
+expect(page).to have_pushed_frontend_feature_flags(valueStreamAnalyticsPathNavigation: false)
+```
+
### `stub_feature_flags` vs `Feature.enable*`
It is preferred to use `stub_feature_flags` to enable feature flags
@@ -496,6 +516,14 @@ Feature.enabled?(:ci_live_trace) # => false
Feature.enabled?(:ci_live_trace, gate) # => true
```
+You can also disable a feature flag for a specific actor:
+
+```ruby
+gate = stub_feature_flag_gate('CustomActor')
+
+stub_feature_flags(ci_live_trace: false, thing: gate)
+```
+
### Controlling feature flags engine in tests
Our Flipper engine in the test environment works in a memory mode `Flipper::Adapters::Memory`.
diff --git a/doc/development/frontend.md b/doc/development/frontend.md
index f46cc377f95..8bb5cf7af62 100644
--- a/doc/development/frontend.md
+++ b/doc/development/frontend.md
@@ -1,4 +1,5 @@
+---
+redirect_to: 'fe_guide/index.md'
+---
-# Frontend Development Guidelines
-
-This page has moved [here](fe_guide/index.md).
+This document was moved to [another location](fe_guide/index.md).
diff --git a/doc/development/geo.md b/doc/development/geo.md
index 5b4af1c9931..06b032a8f66 100644
--- a/doc/development/geo.md
+++ b/doc/development/geo.md
@@ -1,3 +1,9 @@
+---
+stage: Enablement
+group: Geo
+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/#designated-technical-writers
+---
+
# Geo (development) **(PREMIUM ONLY)**
Geo connects GitLab instances together. One GitLab instance is
@@ -420,7 +426,7 @@ We switch and filter from each event by the `event_name` field.
### Geo Log Cursor (GitLab 10.0 and up)
-Since GitLab 10.0, [System Webhooks](#system-hooks-gitlab-87-to-95) are no longer
+In GitLab 10.0 and later, [System Webhooks](#system-hooks-gitlab-87-to-95) are no longer
used and Geo Log Cursor is used instead. The Log Cursor traverses the
`Geo::EventLog` rows to see if there are changes since the last time
the log was checked and will handle repository updates, deletes,
diff --git a/doc/development/geo/framework.md b/doc/development/geo/framework.md
index b720a6ca47e..55f4be07bb4 100644
--- a/doc/development/geo/framework.md
+++ b/doc/development/geo/framework.md
@@ -1,3 +1,9 @@
+---
+stage: Enablement
+group: Geo
+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/#designated-technical-writers
+---
+
# Geo self-service framework (alpha)
NOTE: **Note:**
@@ -91,8 +97,6 @@ module Geo
::Packages::PackageFile
end
- # Change this to `true` to release replication of this model. Then remove
- # this override in the next release.
# The feature flag follows the format `geo_#{replicable_name}_replication`,
# so here it would be `geo_package_file_replication`
def self.replication_enabled_by_default?
@@ -193,7 +197,9 @@ For example, to add support for files referenced by a `Widget` model with a
file_store == ObjectStorage::Store::LOCAL
end
- def self.replicables_for_geo_node
+ # @param primary_key_in [Range, Widget] arg to pass to primary_key_in scope
+ # @return [ActiveRecord::Relation<Widget>] everything that should be synced to this node, restricted by primary key
+ def self.replicables_for_current_secondary(primary_key_in)
# Should be implemented. The idea of the method is to restrict
# the set of synced items depending on synchronization settings
end
@@ -220,8 +226,6 @@ For example, to add support for files referenced by a `Widget` model with a
model_record.file
end
- # Change this to `true` to release replication of this model. Then remove
- # this override in the next release.
# The feature flag follows the format `geo_#{replicable_name}_replication`,
# so here it would be `geo_widget_replication`
def self.replication_enabled_by_default?
@@ -637,7 +641,7 @@ the Admin Area UI, and Prometheus!
include ::Types::Geo::RegistryType
graphql_name 'WidgetRegistry'
- description 'Represents the sync and verification state of a widget'
+ description 'Represents the Geo sync and verification state of a widget'
field :widget_id, GraphQL::ID_TYPE, null: false, description: 'ID of the Widget'
end
@@ -676,6 +680,12 @@ the Admin Area UI, and Prometheus!
}
```
+1. Update the GraphQL reference documentation:
+
+ ```shell
+ bundle exec rake gitlab:graphql:compile_docs
+ ```
+
Individual widget synchronization and verification data should now be available
via the GraphQL API!
@@ -693,3 +703,33 @@ To do: This should be done as part of
Widget sync and verification data (aggregate and individual) should now be
available in the Admin UI!
+
+#### Releasing the feature
+
+1. In `ee/app/replicators/geo/widget_replicator.rb`, delete the `self.replication_enabled_by_default?` method:
+
+ ```ruby
+ module Geo
+ class WidgetReplicator < Gitlab::Geo::Replicator
+ ...
+
+ # REMOVE THIS METHOD
+ def self.replication_enabled_by_default?
+ false
+ end
+ # REMOVE THIS METHOD
+
+ ...
+ end
+ end
+ ```
+
+1. In `ee/app/graphql/types/geo/geo_node_type.rb`, remove the `feature_flag` option for the released type:
+
+ ```ruby
+ field :widget_registries, ::Types::Geo::WidgetRegistryType.connection_type,
+ null: true,
+ resolver: ::Resolvers::Geo::WidgetRegistriesResolver,
+ description: 'Find widget registries on this Geo node',
+ feature_flag: :geo_widget_replication # REMOVE THIS LINE
+ ```
diff --git a/doc/development/go_guide/index.md b/doc/development/go_guide/index.md
index 6954b2bd6dc..15d25d2d1ed 100644
--- a/doc/development/go_guide/index.md
+++ b/doc/development/go_guide/index.md
@@ -130,7 +130,7 @@ become available, you will be able to share job templates like this
Dependencies should be kept to the minimum. The introduction of a new
dependency should be argued in the merge request, as per our [Approval
Guidelines](../code_review.md#approval-guidelines). Both [License
-Management](../../user/compliance/license_compliance/index.md)
+Scanning](../../user/compliance/license_compliance/index.md)
**(ULTIMATE)** and [Dependency
Scanning](../../user/application_security/dependency_scanning/index.md)
**(ULTIMATE)** should be activated on all projects to ensure new dependencies
@@ -138,7 +138,7 @@ security status and license compatibility.
### Modules
-Since Go 1.11, a standard dependency system is available behind the name [Go
+In Go 1.11 and later, a standard dependency system is available behind the name [Go
Modules](https://github.com/golang/go/wiki/Modules). It provides a way to
define and lock dependencies for reproducible builds. It should be used
whenever possible.
@@ -472,7 +472,7 @@ In case we want to drop support for `go 1.11` in GitLab `12.10`, we need to veri
We will not consider the active milestone, `12.10`, because a backport for `12.7` will be required in case of a critical security release.
-1. If both [Omnibus and CNG](#updating-go-version) were using Go `1.12` since GitLab `12.7`, then we safely drop support for `1.11`.
+1. If both [Omnibus and CNG](#updating-go-version) were using Go `1.12` in GitLab `12.7` and later, then we safely drop support for `1.11`.
1. If Omnibus or CNG were using `1.11` in GitLab `12.7`, then we still need to keep support for Go `1.11` for easier backporting of security fixes.
## Secure Team standards and style guidelines
diff --git a/doc/development/gotchas.md b/doc/development/gotchas.md
index f7b44e74c17..cc3db267d53 100644
--- a/doc/development/gotchas.md
+++ b/doc/development/gotchas.md
@@ -3,6 +3,21 @@
The purpose of this guide is to document potential "gotchas" that contributors
might encounter or should avoid during development of GitLab CE and EE.
+## Do not read files from app/assets directory
+
+In GitLab 10.8 and later, Omnibus has [dropped the `app/assets` directory](https://gitlab.com/gitlab-org/omnibus-gitlab/-/merge_requests/2456),
+after asset compilation. The `ee/app/assets`, `vendor/assets` directories are dropped as well.
+
+This means that reading files from that directory will fail in Omnibus-installed GitLab instances:
+
+```ruby
+file = Rails.root.join('app/assets/images/logo.svg')
+
+# This file does not exist, read will fail with:
+# Errno::ENOENT: No such file or directory @ rb_sysopen
+File.read(file)
+```
+
## Do not assert against the absolute value of a sequence-generated attribute
Consider the following factory:
diff --git a/doc/development/graphql_guide/index.md b/doc/development/graphql_guide/index.md
index 62650f7cd3f..9d7fb5ba0a8 100644
--- a/doc/development/graphql_guide/index.md
+++ b/doc/development/graphql_guide/index.md
@@ -8,6 +8,6 @@ feedback, and suggestions.
- [GraphQL API development style guide](../api_graphql_styleguide.md): development style guide for
GraphQL.
-- [GraphQL API documentation style guide](../documentation/styleguide.md#graphql-api): documentation
+- [GraphQL API documentation style guide](../documentation/graphql_styleguide.md): documentation
style guide for GraphQL.
- [GraphQL API](../../api/graphql/index.md): user documentation for the GitLab GraphQL API.
diff --git a/doc/development/i18n/externalization.md b/doc/development/i18n/externalization.md
index b5c5a199b1e..59399e54c3e 100644
--- a/doc/development/i18n/externalization.md
+++ b/doc/development/i18n/externalization.md
@@ -205,7 +205,7 @@ For the static text strings we suggest two patterns for using these translations
When possible, you should opt for this pattern, as this allows you to import these strings directly into your component specs for re-use during testing.
-- Internal component `$options` object `:
+- Internal component `$options` object:
```javascript
<script>
@@ -432,7 +432,7 @@ To avoid this error, use the applicable HTML entity code (`&lt;` or `&gt;`) inst
- In JavaScript:
```javascript
- import { sanitize } from 'dompurify';
+ import { sanitize } from '~/lib/dompurify';
const i18n = { LESS_THAN_ONE_HOUR: sanitize(__('In &lt; 1 hour'), { ALLOWED_TAGS: [] }) };
diff --git a/doc/development/i18n/index.md b/doc/development/i18n/index.md
index 929eded3f8e..2d84fe4536f 100644
--- a/doc/development/i18n/index.md
+++ b/doc/development/i18n/index.md
@@ -38,10 +38,10 @@ Voting for translations is also valuable, helping to confirm good and flag inacc
See [Translation guidelines](translation.md).
-### Proof reading
+### Proofreading
-Proof reading helps ensure the accuracy and consistency of translations. All
-translations are proof read before being accepted. If a translations requires
+Proofreading helps ensure the accuracy and consistency of translations. All
+translations are proofread before being accepted. If a translations requires
changes, you will be notified with a comment explaining why.
See [Proofreading Translations](proofreader.md) for more information on who's
diff --git a/doc/development/img/architecture_simplified.png b/doc/development/img/architecture_simplified.png
index 46ae2b3c055..72d00b91129 100644
--- a/doc/development/img/architecture_simplified.png
+++ b/doc/development/img/architecture_simplified.png
Binary files differ
diff --git a/doc/development/instrumentation.md b/doc/development/instrumentation.md
index e420ae0c54f..bdbcd52eb61 100644
--- a/doc/development/instrumentation.md
+++ b/doc/development/instrumentation.md
@@ -1,6 +1,6 @@
---
stage: Monitor
-group: APM
+group: Health
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/#designated-technical-writers
---
@@ -11,7 +11,7 @@ blocks of Ruby code. Method instrumentation is the primary form of
instrumentation with block-based instrumentation only being used when we want to
drill down to specific regions of code within a method.
-Please refer to [Telemetry](telemetry/index.md) if you are tracking product usage patterns.
+Please refer to [Product Analytics](product_analytics/index.md) if you are tracking product usage patterns.
## Instrumenting Methods
diff --git a/doc/development/integrations/secure.md b/doc/development/integrations/secure.md
index dcfd0f40bf0..1094074cab6 100644
--- a/doc/development/integrations/secure.md
+++ b/doc/development/integrations/secure.md
@@ -374,12 +374,19 @@ which is shared by the analyzers that GitLab maintains. You can [contribute](htt
new generic identifiers to if needed. Analyzers may also produce vendor-specific or product-specific
identifiers, which don't belong in the [common library](https://gitlab.com/gitlab-org/security-products/analyzers/common).
-The first item of the `identifiers` array is called the primary identifier.
+The first item of the `identifiers` array is called the [primary
+identifier](../../user/application_security/terminology/#primary-identifier).
The primary identifier is particularly important, because it is used to
[track vulnerabilities](#tracking-and-merging-vulnerabilities) as new commits are pushed to the repository.
Identifiers are also used to [merge duplicate vulnerabilities](#tracking-and-merging-vulnerabilities)
reported for the same commit, except for `CWE` and `WASC`.
+Not all vulnerabilities have CVEs, and a CVE can be identified multiple times. As a result, a CVE
+isn't a stable identifier and you shouldn't assume it as such when tracking vulnerabilities.
+
+The maximum number of identifiers for a vulnerability is set as 20. If a vulnerability has more than 20 identifiers,
+the system will save only the first 20 of them.
+
### Location
The `location` indicates where the vulnerability has been detected.
diff --git a/doc/development/integrations/secure_partner_integration.md b/doc/development/integrations/secure_partner_integration.md
index 830cb84e257..19fd86f4bf6 100644
--- a/doc/development/integrations/secure_partner_integration.md
+++ b/doc/development/integrations/secure_partner_integration.md
@@ -36,7 +36,7 @@ best place to integrate your own product and its results into GitLab.
- Pipeline jobs serve a variety of purposes. Jobs can do scanning for and have
implications for app security, corporate policy, or compliance. When complete,
the job reports back on its status and creates a
- [job artifact](../../user/project/pipelines/job_artifacts.md) as a result.
+ [job artifact](../../ci/pipelines/job_artifacts.md) as a result.
- The [Merge Request Security Widget](../../user/project/merge_requests/testing_and_reports_in_merge_requests.md#security-reports)
displays the results of the pipeline's security checks and the developer can
review them. The developer can review both a summary and a detailed version
@@ -44,7 +44,7 @@ best place to integrate your own product and its results into GitLab.
- If certain policies (such as [merge request approvals](../../user/project/merge_requests/merge_request_approvals.md))
are in place for a project, developers must resolve specific findings or get
an approval from a specific list of people.
-- The [security dashboard](../../user/application_security/security_dashboard/index.md#gitlab-security-dashboard)
+- The [security dashboard](../../user/application_security/security_dashboard/index.md)
also shows results which can developers can use to quickly see all the
vulnerabilities that need to be addressed in the code.
- When the developer reads the details about a vulnerability, they are
@@ -78,7 +78,7 @@ and complete an integration with the Secure stage.
to successfully display your own product's results with the rest of GitLab.
- See detailed [technical directions](secure.md) for this step.
- Read more about [job report artifacts](../../ci/pipelines/job_artifacts.md#artifactsreports).
- - Read about [job artifacts](../../user/project/pipelines/job_artifacts.md).
+ - Read about [job artifacts](../../ci/pipelines/job_artifacts.md).
- Your report artifact must be in one of our currently supported formats.
For more information, see the [documentation on reports](secure.md#report).
- Documentation for [SAST reports](../../user/application_security/sast/index.md#reports-json-format).
@@ -89,7 +89,7 @@ and complete an integration with the Secure stage.
and add the label `devops::secure`.
- Once the job is completed, the data can be seen:
- In the [Merge Request Security Report](../../user/project/merge_requests/testing_and_reports_in_merge_requests.md#security-reports) ([MR Security Report data flow](https://gitlab.com/snippets/1910005#merge-request-view)).
- - While [browsing a Job Artifact](../../user/project/pipelines/job_artifacts.md).
+ - While [browsing a Job Artifact](../../ci/pipelines/job_artifacts.md).
- In the [Security Dashboard](../../user/application_security/security_dashboard/index.md) ([Dashboard data flow](https://gitlab.com/snippets/1910005#project-and-group-dashboards)).
1. Optional: Provide a way to interact with results as Vulnerabilities:
- Users can interact with the findings from your artifact within their workflow. They can dismiss the findings or accept them and create a backlog issue.
diff --git a/doc/development/internal_api.md b/doc/development/internal_api.md
index 4b46787c2c3..e25feda356d 100644
--- a/doc/development/internal_api.md
+++ b/doc/development/internal_api.md
@@ -52,7 +52,7 @@ POST /internal/allowed
| `username` | string | no | Username from the certificate used to connect to GitLab Shell |
| `project` | string | no (if `gl_repository` is passed) | Path to the project |
| `gl_repository` | string | no (if `project` is passed) | Repository identifier (e.g. `project-7`) |
-| `protocol` | string | yes | SSH when called from GitLab-shell, HTTP or SSH when called from Gitaly |
+| `protocol` | string | yes | SSH when called from GitLab Shell, HTTP or SSH when called from Gitaly |
| `action` | string | yes | Git command being run (`git-upload-pack`, `git-receive-pack`, `git-upload-archive`) |
| `changes` | string | yes | `<oldrev> <newrev> <refname>` when called from Gitaly, the magic string `_any` when called from GitLab Shell |
| `check_ip` | string | no | IP address from which call to GitLab Shell was made |
@@ -223,6 +223,7 @@ Example response:
- GitLab Geo
- GitLab Shell's `bin/check`
+- Gitaly
## Get new 2FA recovery codes using an SSH key
diff --git a/doc/development/kubernetes.md b/doc/development/kubernetes.md
index 64089d51c7b..a54798b4c35 100644
--- a/doc/development/kubernetes.md
+++ b/doc/development/kubernetes.md
@@ -15,14 +15,14 @@ This document provides various guidelines when developing for GitLab's
Some Kubernetes operations, such as creating restricted project
namespaces are performed on the GitLab Rails application. These
-operations are performed using a [client library](#client-library).
-These operations will carry an element of risk as the operations will be
-run as the same user running the GitLab Rails application, see the
-[security](#security) section below.
+operations are performed using a [client library](#client-library),
+and carry an element of risk. The operations are
+run as the same user running the GitLab Rails application. For more information,
+read the [security](#security) section below.
Some Kubernetes operations, such as installing cluster applications are
performed on one-off pods on the Kubernetes cluster itself. These
-installation pods are currently named `install-<application_name>` and
+installation pods are named `install-<application_name>` and
are created within the `gitlab-managed-apps` namespace.
In terms of code organization, we generally add objects that represent
@@ -33,33 +33,32 @@ Kubernetes resources in
We use the [`kubeclient`](https://rubygems.org/gems/kubeclient) gem to
perform Kubernetes API calls. As the `kubeclient` gem does not support
-different API Groups (e.g. `apis/rbac.authorization.k8s.io`) from a
+different API Groups (such as `apis/rbac.authorization.k8s.io`) from a
single client, we have created a wrapper class,
[`Gitlab::Kubernetes::KubeClient`](https://gitlab.com/gitlab-org/gitlab/blob/master/lib/gitlab/kubernetes/kube_client.rb)
-that will enable you to achieve this.
+that enable you to achieve this.
-Selected Kubernetes API groups are currently supported. Do add support
+Selected Kubernetes API groups are supported. Do add support
for new API groups or methods to
[`Gitlab::Kubernetes::KubeClient`](https://gitlab.com/gitlab-org/gitlab/blob/master/lib/gitlab/kubernetes/kube_client.rb)
if you need to use them. New API groups or API group versions can be
-added to `SUPPORTED_API_GROUPS` - internally, this will create an
+added to `SUPPORTED_API_GROUPS` - internally, this creates an
internal client for that group. New methods can be added as a delegation
to the relevant internal client.
### Performance considerations
-All calls to the Kubernetes API must be in a background process. Do not
-perform Kubernetes API calls within a web request as this will block
-Unicorn and can easily lead to a Denial Of Service (DoS) attack in GitLab as
+All calls to the Kubernetes API must be in a background process. Don't
+perform Kubernetes API calls within a web request. This blocks
+Unicorn, and can lead to a denial-of-service (DoS) attack in GitLab as
the Kubernetes cluster response times are outside of our control.
The easiest way to ensure your calls happen a background process is to
delegate any such work to happen in a [Sidekiq worker](sidekiq_style_guide.md).
-There are instances where you would like to make calls to Kubernetes and
-return the response and as such a background worker does not seem to be
-a good fit. For such cases you should make use of [reactive
-caching](https://gitlab.com/gitlab-org/gitlab/blob/master/app/models/concerns/reactive_caching.rb).
+You may want to make calls to Kubernetes and return the response, but a background
+worker isn't a good fit. Consider using
+[reactive caching](https://gitlab.com/gitlab-org/gitlab/blob/master/app/models/concerns/reactive_caching.rb).
For example:
```ruby
@@ -76,7 +75,7 @@ For example:
### Testing
-We have some Webmock stubs in
+We have some WebMock stubs in
[`KubernetesHelpers`](https://gitlab.com/gitlab-org/gitlab/blob/master/spec/support/helpers/kubernetes_helpers.rb)
which can help with mocking out calls to Kubernetes API in your tests.
@@ -86,8 +85,8 @@ This section outlines the process for allowing a GitLab instance to create EKS c
The following prerequisites are required:
-A `Customer` AWS account. This is the account in which the
-EKS cluster will be created. The following resources must be present:
+A `Customer` AWS account. The EKS cluster is created in this account. The following
+resources must be present:
- A provisioning role that has permissions to create the cluster
and associated resources. It must list the `GitLab` AWS account
@@ -114,7 +113,7 @@ The process for creating a cluster is as follows:
which takes somewhere between 10 and 15 minutes in most cases.
1. When the stack is ready, GitLab stores the cluster details and generates
another set of temporary credentials, this time to allow connecting to
- the cluster via Kubeclient. These credentials are valid for one minute.
+ the cluster via `kubeclient`. These credentials are valid for one minute.
1. GitLab configures the worker nodes so that they are able to authenticate
to the cluster, and creates a service account for itself for future operations.
1. Credentials that are no longer required are removed. This deletes the following
@@ -126,7 +125,7 @@ The process for creating a cluster is as follows:
## Security
-### SSRF
+### Server Side Request Forgery (SSRF) attacks
As URLs for Kubernetes clusters are user controlled it is easily
susceptible to Server Side Request Forgery (SSRF) attacks. You should
@@ -153,11 +152,11 @@ Mitigation strategies include:
app.make_errored!("Kubernetes error: #{e.error_code}")
```
-## Debugging
+## Debugging Kubernetes integrations
Logs related to the Kubernetes integration can be found in
[`kubernetes.log`](../administration/logs.md#kuberneteslog). On a local
-GDK install, this will be present in `log/kubernetes.log`.
+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)
@@ -176,7 +175,9 @@ kubectl logs <pod_name> --follow -n gitlab-managed-apps
## GitLab Managed Apps
-GitLab provides [GitLab Managed Apps](../user/clusters/applications.md), a one-click install for various applications which can be added directly to your configured cluster.
+GitLab provides [GitLab Managed Apps](../user/clusters/applications.md), a one-click
+install for various applications which can be added directly to your configured cluster.
**<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
-For an overview of how to add a new GitLab-managed app, see [How to add GitLab-managed-apps to Kubernetes integration](https://youtu.be/mKm-jkranEk).**
+For an overview of how to add a new GitLab-managed app, see
+[How to add GitLab-managed-apps to Kubernetes integration](https://youtu.be/mKm-jkranEk).**
diff --git a/doc/development/logging.md b/doc/development/logging.md
index 474a500da61..14812978f2d 100644
--- a/doc/development/logging.md
+++ b/doc/development/logging.md
@@ -1,6 +1,6 @@
---
stage: Monitor
-group: APM
+group: Health
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/#designated-technical-writers
---
@@ -287,7 +287,6 @@ method or variable shouldn't be evaluated right away)
See our [HOWTO: Use Sidekiq metadata logs](https://www.youtube.com/watch?v=_wDllvO_IY0) for further knowledge on
creating visualizations in Kibana.
-NOTE: **Note:**
The fields of the context are currently only logged for Sidekiq jobs triggered
through web requests. See the
[follow-up work](https://gitlab.com/gitlab-com/gl-infra/scalability/-/issues/68)
diff --git a/doc/development/migration_style_guide.md b/doc/development/migration_style_guide.md
index 207dd02d258..71191d1d871 100644
--- a/doc/development/migration_style_guide.md
+++ b/doc/development/migration_style_guide.md
@@ -295,13 +295,16 @@ end
Adding foreign key to `projects`:
+We can use the `add_concurrenct_foreign_key` method in this case, as this helper method
+has the lock retries built into it.
+
```ruby
include Gitlab::Database::MigrationHelpers
+disable_ddl_transaction!
+
def up
- with_lock_retries do
- add_foreign_key :imports, :projects, column: :project_id, on_delete: :cascade # rubocop:disable Migration/AddConcurrentForeignKey
- end
+ add_concurrent_foreign_key :imports, :projects, column: :project_id, on_delete: :cascade
end
def down
@@ -316,10 +319,10 @@ Adding foreign key to `users`:
```ruby
include Gitlab::Database::MigrationHelpers
+disable_ddl_transaction!
+
def up
- with_lock_retries do
- add_foreign_key :imports, :users, column: :user_id, on_delete: :cascade # rubocop:disable Migration/AddConcurrentForeignKey
- end
+ add_concurrent_foreign_key :imports, :users, column: :user_id, on_delete: :cascade
end
def down
@@ -331,7 +334,7 @@ end
**Usage with `disable_ddl_transaction!`**
-Generally the `with_lock_retries` helper should work with `disabled_ddl_transaction!`. A custom RuboCop rule ensures that only allowed methods can be placed within the lock retries block.
+Generally the `with_lock_retries` helper should work with `disable_ddl_transaction!`. A custom RuboCop rule ensures that only allowed methods can be placed within the lock retries block.
```ruby
disable_ddl_transaction!
@@ -348,7 +351,7 @@ end
The RuboCop rule generally allows standard Rails migration methods, listed below. This example will cause a Rubocop offense:
```ruby
-disabled_ddl_transaction!
+disable_ddl_transaction!
def up
with_lock_retries do
@@ -364,17 +367,7 @@ standard Rails migration helper methods. Calling more than one migration
helper is not a problem if they're executed on the same table.
Using the `with_lock_retries` helper method is advised when a database
-migration involves one of the high-traffic tables:
-
-- `users`
-- `projects`
-- `namespaces`
-- `gitlab_subscriptions`
-- `issues`
-- `merge_requests`
-- `ci_pipelines`
-- `ci_builds`
-- `notes`
+migration involves one of the [high-traffic tables](https://gitlab.com/gitlab-org/gitlab/-/blob/master/rubocop/rubocop-migrations.yml#L3).
Example changes:
@@ -612,7 +605,7 @@ See the style guide on [`NOT NULL` constraints](database/not_null_constraints.md
## Adding Columns With Default Values
-With PostgreSQL 11 being the minimum version since GitLab 13.0, adding columns with default values has become much easier and
+With PostgreSQL 11 being the minimum version in GitLab 13.0 and later, adding columns with default values has become much easier and
the standard `add_column` helper should be used in all cases.
Before PostgreSQL 11, adding a column with a default was problematic as it would
@@ -647,7 +640,7 @@ tables: `namespaces`. This can be translated to:
```sql
ALTER TABLE namespaces
ALTER COLUMN request_access_enabled
-DEFAULT false
+SET DEFAULT false
```
In this particular case, the default value exists and we're just changing the metadata for
diff --git a/doc/development/multi_version_compatibility.md b/doc/development/multi_version_compatibility.md
index 5ca43b9b818..714be296b40 100644
--- a/doc/development/multi_version_compatibility.md
+++ b/doc/development/multi_version_compatibility.md
@@ -122,7 +122,7 @@ If we look at this schema from a database point of view, we can see two deployme
And these deployments align perfectly with application changes.
1. At the beginning we have `Version N` on `Schema A`.
-1. Then we have a _long_ transition periond with both `Version N` and `Version N+1` on `Schema B`.
+1. Then we have a _long_ transition period with both `Version N` and `Version N+1` on `Schema B`.
1. When we only have `Version N+1` on `Schema B` the schema changes again.
1. Finally we have `Version N+1` on `Schema C`.
diff --git a/doc/development/new_fe_guide/development/accessibility.md b/doc/development/new_fe_guide/development/accessibility.md
index b9ee5c3a549..9c63ccad6e1 100644
--- a/doc/development/new_fe_guide/development/accessibility.md
+++ b/doc/development/new_fe_guide/development/accessibility.md
@@ -12,7 +12,7 @@ WAI-ARIA (the Accessible Rich Internet Applications specification) defines a way
The `role` attribute describes the role the element plays in the context of the document.
-Check the list of WAI-ARIA roles [here](https://www.w3.org/TR/wai-aria-1.1/#landmark_roles)
+Review the list of [WAI-ARIA roles](https://www.w3.org/TR/wai-aria-1.1/#landmark_roles).
## Icons
diff --git a/doc/development/new_fe_guide/development/index.md b/doc/development/new_fe_guide/development/index.md
index 5dced3dc466..119dbc58012 100644
--- a/doc/development/new_fe_guide/development/index.md
+++ b/doc/development/new_fe_guide/development/index.md
@@ -12,6 +12,6 @@ Learn how to implement an accessible frontend.
Learn how to keep our frontend performant.
-## [Testing](testing.md)
+## [Testing](../../testing_guide/frontend_testing.md)
Learn how to keep our frontend tested.
diff --git a/doc/development/packages.md b/doc/development/packages.md
index 55e22d4bb5f..9eae99ff890 100644
--- a/doc/development/packages.md
+++ b/doc/development/packages.md
@@ -64,15 +64,16 @@ will have to be managed. Using instance level endpoints requires [stricter namin
The current state of existing package registries availability is:
-| Repository Type | Project Level | Group Level | Instance Level |
-|-----------------|---------------|-------------|----------------|
-| Maven | Yes | Yes | Yes |
-| Conan | Yes | No - [open issue](https://gitlab.com/gitlab-org/gitlab/-/issues/11679) | Yes |
-| NPM | No - [open issue](https://gitlab.com/gitlab-org/gitlab/-/issues/36853) | Yes | No - [open issue](https://gitlab.com/gitlab-org/gitlab/-/issues/36853) |
-| NuGet | Yes | No - [open issue](https://gitlab.com/gitlab-org/gitlab/-/issues/36423) | No |
-| PyPI | Yes | No | No |
-| Go | Yes | No - [open issue](https://gitlab.com/gitlab-org/gitlab/-/issues/213900) | No - [open-issue](https://gitlab.com/gitlab-org/gitlab/-/issues/213902) |
-| Composer | Yes | Yes | No |
+| Repository Type | Project Level | Group Level | Instance Level |
+|------------------|---------------|-------------|----------------|
+| Maven | Yes | Yes | Yes |
+| Conan | Yes | No - [open issue](https://gitlab.com/gitlab-org/gitlab/-/issues/11679) | Yes |
+| NPM | No - [open issue](https://gitlab.com/gitlab-org/gitlab/-/issues/36853) | Yes | No - [open issue](https://gitlab.com/gitlab-org/gitlab/-/issues/36853) |
+| NuGet | Yes | No - [open issue](https://gitlab.com/gitlab-org/gitlab/-/issues/36423) | No |
+| PyPI | Yes | No | No |
+| Go | Yes | No - [open issue](https://gitlab.com/gitlab-org/gitlab/-/issues/213900) | No - [open-issue](https://gitlab.com/gitlab-org/gitlab/-/issues/213902) |
+| Composer | Yes | Yes | No |
+| Generic | Yes | No | No |
NOTE: **Note:**
NPM is currently a hybrid of the instance level and group level.
@@ -87,7 +88,7 @@ Composer package naming scope is Instance Level.
To avoid name conflict for instance-level endpoints you will need to define a package naming convention
that gives a way to identify the project that the package belongs to. This generally involves using the project
ID or full project path in the package name. See
-[Conan's naming convention](../user/packages/conan_repository/index.md#package-recipe-naming-convention-for-instance-level-remote) as an example.
+[Conan's naming convention](../user/packages/conan_repository/index.md#package-recipe-naming-convention-for-instance-remotes) as an example.
For group and project-level endpoints, naming can be less constrained and it will be up to the group and project
members to be certain that there is no conflict between two package names. However, the system should prevent
diff --git a/doc/development/performance.md b/doc/development/performance.md
index 1dc7538c55b..3b59393bae6 100644
--- a/doc/development/performance.md
+++ b/doc/development/performance.md
@@ -247,8 +247,12 @@ The following configuration options can be configured:
- `STACKPROF_ENABLED`: Enables stackprof signal handler on SIGUSR2 signal.
Defaults to `false`.
-- `STACKPROF_INTERVAL_US`: Sampling interval in microseconds. Defaults to
- `10000` μs (100hz).
+- `STACKPROF_MODE`: See [sampling modes](https://github.com/tmm1/stackprof#sampling).
+ Defaults to `cpu`.
+- `STACKPROF_INTERVAL`: Sampling interval. Unit semantics depend on `STACKPROF_MODE`.
+ For `object` mode this is a per-event interval (every `n`th event will be sampled)
+ and defaults to `1000`.
+ For other modes such as `cpu` this is a frequency and defaults to `10000` μs (100hz).
- `STACKPROF_FILE_PREFIX`: File path prefix where profiles are stored. Defaults
to `$TMPDIR` (often corresponds to `/tmp`).
- `STACKPROF_TIMEOUT_S`: Profiling timeout in seconds. Profiling will
diff --git a/doc/development/pipelines.md b/doc/development/pipelines.md
index 7756ef376fc..d12220d8c95 100644
--- a/doc/development/pipelines.md
+++ b/doc/development/pipelines.md
@@ -122,7 +122,6 @@ graph RL;
click 2_2-5 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=8404303&udv=0"
subgraph "Needs `setup-test-env` & `compile-test-assets`";
2_2-2 & 2_2-4 & 2_2-5 --> 1-6 & 1-3;
- 2_2-3 --> 1-6 & 1-4;
end
2_3-1["build-assets-image (2.5 minutes)"];
@@ -228,7 +227,6 @@ graph RL;
click 2_2-5 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=8404303&udv=0"
subgraph "Needs `setup-test-env` & `compile-test-assets`";
2_2-2 & 2_2-4 & 2_2-5 --> 1-6 & 1-3;
- 2_2-3 --> 1-6 & 1-4;
end
2_3-1["build-assets-image (2.5 minutes)"];
diff --git a/doc/development/policies.md b/doc/development/policies.md
index 8f05948cb41..8dfd4763551 100644
--- a/doc/development/policies.md
+++ b/doc/development/policies.md
@@ -171,7 +171,7 @@ class ParentPolicy < BasePolicy
condition(:speaks_spanish) { @subject.spoken_languages.include?(:es) }
condition(:has_license) { @subject.driving_license.present? }
condition(:enjoys_broccoli) { @subject.enjoyment_of(:broccoli) > 0 }
-
+
rule { speaks_spanish }.enable :read_spanish
rule { has_license }.enable :drive_car
rule { enjoys_broccoli }.enable :eat_broccoli
@@ -190,7 +190,7 @@ child policy, for example:
```ruby
class ChildPolicy < BasePolicy
delegate { @subject.parent }
-
+
rule { default }.prevent :drive_car
end
```
@@ -211,11 +211,11 @@ The solution it to override the `:eat_broccoli` ability in the child policy:
```ruby
class ChildPolicy < BasePolicy
delegate { @subject.parent }
-
+
overrides :eat_broccoli
-
+
condition(:good_kid) { @subject.behavior_level >= Child::GOOD }
-
+
rule { good_kid }.enable :eat_broccoli
end
```
diff --git a/doc/development/product_analytics/event_dictionary.md b/doc/development/product_analytics/event_dictionary.md
new file mode 100644
index 00000000000..b049db21c30
--- /dev/null
+++ b/doc/development/product_analytics/event_dictionary.md
@@ -0,0 +1,32 @@
+---
+stage: Growth
+group: Product Analytics
+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/#designated-technical-writers
+---
+
+# Event Dictionary
+
+**Note: We've temporarily moved the Event Dictionary to a [Google Sheet](https://docs.google.com/spreadsheets/d/1VzE8R72Px_Y_LlE3Z05LxUlG_dumWe3vl-HeUo70TPw/edit?usp=sharing)**. The previous Markdown table exceeded 600 rows making it difficult to manage. In the future, our intention is to move this back into our docs using a [YAML file](https://gitlab.com/gitlab-org/gitlab-docs/-/issues/823).
+
+The event dictionary is a single source of truth for the metrics and events we collect for product usage data. The Event Dictionary lists all the metrics and events we track, why we're tracking them, and where they are tracked.
+
+This is a living document that is updated any time a new event is planned or implemented. It includes the following information.
+
+- Section, stage, or group
+- Description
+- Implementation status
+- Availability by plan type
+- Code path
+
+We're currently focusing our Event Dictionary on [Usage Ping](usage_ping.md). In the future, we will also include [Snowplow](snowplow.md). We currently have an initiative across the entire product organization to complete the [Event Dictionary for Usage Ping](https://gitlab.com/groups/gitlab-org/-/epics/4174).
+
+## Instructions
+
+1. Open the Event Dictionary and fill in all the **PM to edit** columns highlighted in yellow.
+1. Check that all the metrics and events are assigned to the correct section, stage, or group. If a metric is used across many groups, assign it to the stage. If a metric is used across many stages, assign it to the section. If a metric is incorrectly assigned to another section, stage, or group, let the PM know you have reassigned it. If your group has no assigned metrics and events, check that your metrics and events are not incorrectly assigned to another PM.
+1. Add descriptions of what your metrics and events are tracking. Work with your Engineering team or the Product Analytics team if you need help understanding this.
+1. Add what plans this metric is available on. Work with your Engineering team or the Product Analytics team if you need help understanding this.
+
+## Planned metrics and events
+
+For future metrics and events you plan to track, please add them to the Event Dictionary and note the status as `Planned`, `In Progress`, or `Implemented`. Once you have confirmed the metric has been implemented and have confirmed the metric data is in our data warehouse, change the status to **Data Available**.
diff --git a/doc/development/product_analytics/index.md b/doc/development/product_analytics/index.md
new file mode 100644
index 00000000000..ab76d6f0561
--- /dev/null
+++ b/doc/development/product_analytics/index.md
@@ -0,0 +1,182 @@
+---
+stage: Growth
+group: Product Analytics
+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/#designated-technical-writers
+---
+
+# Product Analytics Guide
+
+At GitLab, we collect product usage data for the purpose of helping us build a better product. Data helps GitLab understand which parts of the product need improvement and which features we should build next. Product usage data also helps our team better understand the reasons why people use GitLab. With this knowledge we are able to make better product decisions.
+
+We encourage users to enable tracking, and we embrace full transparency with our tracking approach so it can be easily understood and trusted.
+
+By enabling tracking, users can:
+
+- Contribute back to the wider community.
+- Help GitLab improve on the product.
+
+## Our tracking tools
+
+We use three methods to gather product usage data:
+
+- [Snowplow](#snowplow)
+- [Usage Ping](#usage-ping)
+- [Database import](#database-import)
+
+### Snowplow
+
+Snowplow is an enterprise-grade marketing and product analytics platform which helps track the way
+users engage with our website and application.
+
+Snowplow consists of two components:
+
+- [Snowplow JS](https://github.com/snowplow/snowplow/wiki/javascript-tracker) tracks client-side
+ events.
+- [Snowplow Ruby](https://github.com/snowplow/snowplow/wiki/ruby-tracker) tracks server-side events.
+
+For more details, read the [Snowplow](snowplow.md) guide.
+
+### Usage Ping
+
+Usage Ping is a method for GitLab Inc to collect usage data on a GitLab instance. Usage Ping is primarily composed of row counts for different tables in the instance’s database. By comparing these counts month over month (or week over week), we can get a rough sense for how an instance is using the different features within the product. This high-level data is used to help our product, support, and sales teams.
+
+For more details, read the [Usage Ping](usage_ping.md) guide.
+
+### Database import
+
+Database imports are full imports of data into GitLab's data warehouse. For GitLab.com, the PostgreSQL database is loaded into Snowflake data warehouse every 6 hours. For more details, see the [data team handbook](https://about.gitlab.com/handbook/business-ops/data-team/platform/#extract-and-load).
+
+## What data can be tracked
+
+Our different tracking tools allows us to track different types of events. The event types and examples of what data can be tracked are outlined below.
+
+The availability of event types and their tracking tools varies by segment. For example, on Self-Managed Users, we only have reporting using Database records via Usage Ping.
+
+| Event Types | SaaS Instance | SaaS Plan | SaaS Group | SaaS Session | SaaS User | SM Instance | SM Plan | SM Group | SM Session | SM User |
+|----------------------------------------|---------------|-----------|------------|--------------|-----------|-------------|---------|----------|------------|---------|
+| Snowplow (JS Pageview events) | ✅ | 📅 | 📅 | ✅ | 📅 | 📅 | 📅 | 📅 | 📅 | 📅 |
+| Snowplow (JS UI events) | ✅ | 📅 | 📅 | ✅ | 📅 | 📅 | 📅 | 📅 | 📅 | 📅 |
+| Snowplow (Ruby Pageview events) | ✅ | 📅 | 📅 | ✅ | 📅 | 📅 | 📅 | 📅 | 📅 | 📅 |
+| Snowplow (Ruby CRUD / API events) | ✅ | 📅 | 📅 | ✅ | 📅 | 📅 | 📅 | 📅 | 📅 | 📅 |
+| Usage Ping (Redis UI counters) | 🔄 | 🔄 | 🔄 | âœ–ï¸ | 🔄 | 🔄 | 🔄 | 🔄 | âœ–ï¸ | 🔄 |
+| Usage Ping (Redis Pageview counters) | 🔄 | 🔄 | 🔄 | âœ–ï¸ | 🔄 | 🔄 | 🔄 | 🔄 | âœ–ï¸ | 🔄 |
+| Usage Ping (Redis CRUD / API counters) | 🔄 | 🔄 | 🔄 | âœ–ï¸ | 🔄 | 🔄 | 🔄 | 🔄 | âœ–ï¸ | 🔄 |
+| Usage Ping (Database counters) | ✅ | 🔄 | 📅 | âœ–ï¸ | ✅ | ✅ | ✅ | ✅ | âœ–ï¸ | ✅ |
+| Usage Ping (Instance settings) | ✅ | 🔄 | 📅 | âœ–ï¸ | ✅ | ✅ | ✅ | ✅ | âœ–ï¸ | ✅ |
+| Usage Ping (Integration settings) | ✅ | 🔄 | 📅 | âœ–ï¸ | ✅ | ✅ | ✅ | ✅ | âœ–ï¸ | ✅ |
+| Database import (Database records) | ✅ | ✅ | ✅ | âœ–ï¸ | ✅ | âœ–ï¸ | âœ–ï¸ | âœ–ï¸ | âœ–ï¸ | âœ–ï¸ |
+
+[Source file](https://docs.google.com/spreadsheets/d/1e8Afo41Ar8x3JxAXJF3nL83UxVZ3hPIyXdt243VnNuE/edit?usp=sharing)
+
+**Legend**
+
+✅ Available, 🔄 In Progress, 📅 Planned, âœ–ï¸ Not Possible
+
+SaaS = GitLab.com. SM = Self-Managed instance
+
+### Pageview events
+
+- Number of sessions that visited the /dashboard/groups page
+
+### UI events
+
+- Number of sessions that clicked on a button or link
+- Number of sessions that closed a modal
+
+UI events are any interface-driven actions from the browser including click data.
+
+### CRUD or API events
+
+- Number of Git pushes
+- Number of GraphQL queries
+- Number of requests to a Rails action or controller
+
+These are backend events that include the creation, read, update, deletion of records, and other events that might be triggered from layers other than those available in the interface.
+
+### Database records
+
+These are raw database records which can be explored using business intelligence tools like Sisense. The full list of available tables can be found in [structure.sql](https://gitlab.com/gitlab-org/gitlab/-/blob/master/db/structure.sql).
+
+### Instance settings
+
+These are settings of your instance such as the instance's Git version and if certain features are enabled such as `container_registry_enabled`.
+
+### Integration settings
+
+These are integrations your GitLab instance interacts with such as an [external storage provider](../../administration/static_objects_external_storage.md) or an [external container registry](../../administration/packages/container_registry.md#use-an-external-container-registry-with-gitlab-as-an-auth-endpoint). These services must be able to send data back into a GitLab instance for data to be tracked.
+
+## Reporting level
+
+Our reporting levels of aggregate or individual reporting varies by segment. For example, on Self-Managed Users, we can report at an aggregate user level using Usage Ping but not on an Individual user level.
+
+| Aggregated Reporting | SaaS Instance | SaaS Plan | SaaS Group | SaaS Session | SaaS User | SM Instance | SM Plan | SM Group | SM Session | SM User |
+|----------------------|---------------|-----------|------------|--------------|-----------|-------------|---------|----------|------------|---------|
+| Snowplow | ✅ | 📅 | 📅 | ✅ | 📅 | ✅ | 📅 | 📅 | ✅ | 📅 |
+| Usage Ping | ✅ | 🔄 | 📅 | 📅 | ✅ | ✅ | ✅ | ✅ | 📅 | ✅ |
+| Database import | ✅ | ✅ | ✅ | âœ–ï¸ | ✅ | âœ–ï¸ | âœ–ï¸ | âœ–ï¸ | âœ–ï¸ | âœ–ï¸ |
+
+| Identifiable Reporting | SaaS Instance | SaaS Plan | SaaS Group | SaaS Session | SaaS User | SM Instance | SM Plan | SM Group | SM Session | SM User |
+|------------------------|---------------|-----------|------------|--------------|-----------|-------------|---------|----------|------------|---------|
+| Snowplow | ✅ | 📅 | 📅 | ✅ | 📅 | âœ–ï¸ | âœ–ï¸ | âœ–ï¸ | âœ–ï¸ | âœ–ï¸ |
+| Usage Ping | ✅ | 🔄 | 📅 | âœ–ï¸ | âœ–ï¸ | ✅ | ✅ | âœ–ï¸ | âœ–ï¸ | âœ–ï¸ |
+| Database import | ✅ | ✅ | ✅ | âœ–ï¸ | ✅ | âœ–ï¸ | âœ–ï¸ | âœ–ï¸ | âœ–ï¸ | âœ–ï¸ |
+
+**Legend**
+
+✅ Available, 🔄 In Progress, 📅 Planned, âœ–ï¸ Not Possible
+
+SaaS = GitLab.com. SM = Self-Managed instance
+
+## Reporting time period
+
+Our reporting time periods varies by segment. For example, on Self-Managed Users, we can report all time counts and 28 day counts in Usage Ping.
+
+| Reporting Time Period | All Time | 28 Days | 7 Days | Daily |
+|-----------------------|----------|---------|--------|-------|
+| Snowplow | ✅ | ✅ | ✅ | ✅ |
+| Usage Ping | ✅ | ✅ | 📅 | âœ–ï¸ |
+| Database import | ✅ | ✅ | ✅ | ✅ |
+
+**Legend**
+
+✅ Available, 🔄 In Progress, 📅 Planned, âœ–ï¸ Not Possible
+
+## Systems overview
+
+The systems overview is a simplified diagram showing the interactions between GitLab Inc and self-managed instances.
+
+![Product Analytics Overview](../img/telemetry_system_overview.png)
+
+[Source file](https://app.diagrams.net/#G13DVpN-XnhWGz9tqReIj8pp1UE4ehk_EC)
+
+### GitLab Inc
+
+For Product Analytics purposes, GitLab Inc has three major components:
+
+1. [Data Infrastructure](https://about.gitlab.com/handbook/business-ops/data-team/platform/infrastructure/): This contains everything managed by our data team including Sisense Dashboards for visualization, Snowflake for Data Warehousing, incoming data sources such as PostgreSQL Pipeline and S3 Bucket, and lastly our data collectors [GitLab.com's Snowplow Collector](https://gitlab.com/gitlab-com/gl-infra/readiness/-/tree/master/library/snowplow/) and GitLab's Versions Application.
+1. GitLab.com: This is the production GitLab application which is made up of a Client and Server. On the Client or browser side, a Snowplow JS Tracker (Frontend) is used to track client-side events. On the Server or application side, a Snowplow Ruby Tracker (Backend) is used to track server-side events. The server also contains Usage Ping which leverages a PostgreSQL database and a Redis in-memory data store to report on usage data. Lastly, the server also contains System Logs which are generated from running the GitLab application.
+1. [Monitoring infrastructure](https://about.gitlab.com/handbook/engineering/monitoring/): This is the infrastructure used to ensure GitLab.com is operating smoothly. System Logs are sent from GitLab.com to our monitoring infrastructure and collected by a FluentD collector. From FluentD, logs are either sent to long term Google Cloud Services cold storage via Stackdriver, or, they are sent to our Elastic Cluster via Cloud Pub/Sub which can be explored in real-time using Kibana.
+
+### Self-managed
+
+For Product Analytics purposes, self-managed instances have two major components:
+
+1. Data infrastructure: Having a data infrastructure setup is optional on self-managed instances. If you'd like to collect Snowplow tracking events for your self-managed instance, you can setup your own self-managed Snowplow collector and configure your Snowplow events to point to your own collector.
+1. GitLab: A self-managed GitLab instance contains all of the same components as GitLab.com mentioned above.
+
+### Differences between GitLab Inc and Self-managed
+
+As shown by the orange lines, on GitLab.com Snowplow JS, Snowplow Ruby, Usage Ping, and PostgreSQL database imports all flow into GitLab Inc's data infrastructure. However, on self-managed, only Usage Ping flows into GitLab Inc's data infrastructure.
+
+As shown by the green lines, on GitLab.com system logs flow into GitLab Inc's monitoring infrastructure. On self-managed, there are no logs sent to GitLab Inc's monitoring infrastructure.
+
+Note (1): Snowplow JS and Snowplow Ruby are available on self-managed, however, the Snowplow Collector endpoint is set to a self-managed Snowplow Collector which GitLab Inc does not have access to.
+
+## Additional information
+
+More useful links:
+
+- [Product Analytics Direction](https://about.gitlab.com/direction/product-analytics/)
+- [Data Analysis Process](https://about.gitlab.com/handbook/business-ops/data-team/#data-analysis-process/)
+- [Data for Product Managers](https://about.gitlab.com/handbook/business-ops/data-team/programs/data-for-product-managers/)
+- [Data Infrastructure](https://about.gitlab.com/handbook/business-ops/data-team/platform/infrastructure/)
diff --git a/doc/development/product_analytics/snowplow.md b/doc/development/product_analytics/snowplow.md
new file mode 100644
index 00000000000..21d92566ffd
--- /dev/null
+++ b/doc/development/product_analytics/snowplow.md
@@ -0,0 +1,429 @@
+---
+stage: Growth
+group: Product Analytics
+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/#designated-technical-writers
+---
+
+# Snowplow Guide
+
+This guide provides an overview of how Snowplow works, and implementation details.
+
+For more information about Product Analytics, see:
+
+- [Product Analytics Guide](index.md)
+- [Usage Ping Guide](usage_ping.md)
+
+More useful links:
+
+- [Product Analytics Direction](https://about.gitlab.com/direction/product-analytics/)
+- [Data Analysis Process](https://about.gitlab.com/handbook/business-ops/data-team/#data-analysis-process/)
+- [Data for Product Managers](https://about.gitlab.com/handbook/business-ops/data-team/programs/data-for-product-managers/)
+- [Data Infrastructure](https://about.gitlab.com/handbook/business-ops/data-team/platform/infrastructure/)
+
+## What is Snowplow
+
+Snowplow is an enterprise-grade marketing and product analytics platform which helps track the way users engage with our website and application.
+
+[Snowplow](https://github.com/snowplow/snowplow) consists of the following loosely-coupled sub-systems:
+
+- **Trackers** fire Snowplow events. Snowplow has 12 trackers, covering web, mobile, desktop, server, and IoT.
+- **Collectors** receive Snowplow events from trackers. We have three different event collectors, synchronizing events either to Amazon S3, Apache Kafka, or Amazon Kinesis.
+- **Enrich** cleans up the raw Snowplow events, enriches them and puts them into storage. We have an Hadoop-based enrichment process, and a Kinesis-based or Kafka-based process.
+- **Storage** is where the Snowplow events live. We store the Snowplow events in a flat file structure on S3, and in the Redshift and PostgreSQL databases.
+- **Data modeling** is where event-level data is joined with other data sets and aggregated into smaller data sets, and business logic is applied. This produces a clean set of tables which make it easier to perform analysis on the data. We have data models for Redshift and Looker.
+- **Analytics** are performed on the Snowplow events or on the aggregate tables.
+
+![snowplow_flow](../img/snowplow_flow.png)
+
+## Snowplow schema
+
+We have many definitions of Snowplow's schema. We have an active issue to [standardize this schema](https://gitlab.com/gitlab-org/gitlab/-/issues/207930) including the following definitions:
+
+- Frontend and backend taxonomy as listed below
+- [Structured event taxonomy](#structured-event-taxonomy)
+- [Self describing events](https://github.com/snowplow/snowplow/wiki/Custom-events#self-describing-events)
+- [Iglu schema](https://gitlab.com/gitlab-org/iglu/)
+- [Snowplow authored events](https://github.com/snowplow/snowplow/wiki/Snowplow-authored-events)
+
+## Enabling Snowplow
+
+Tracking can be enabled at:
+
+- The instance level, which enables tracking on both the frontend and backend layers.
+- User level, though user tracking can be disabled on a per-user basis. GitLab tracking respects the [Do Not Track](https://www.eff.org/issues/do-not-track) standard, so any user who has enabled the Do Not Track option in their browser is not tracked at a user level.
+
+We utilize Snowplow for the majority of our tracking strategy and it is enabled on GitLab.com. On a self-managed instance, Snowplow can be enabled by navigating to:
+
+- **Admin Area > Settings > General** in the UI.
+- `admin/application_settings/integrations` in your browser.
+
+The following configuration is required:
+
+| Name | Value |
+|---------------|---------------------------|
+| Collector | `snowplow.trx.gitlab.net` |
+| Site ID | `gitlab` |
+| Cookie domain | `.gitlab.com` |
+
+## Snowplow request flow
+
+The following example shows a basic request/response flow between the following components:
+
+- Snowplow JS / Ruby Trackers on GitLab.com
+- [GitLab.com Snowplow Collector](https://gitlab.com/gitlab-com/gl-infra/readiness/-/blob/master/library/snowplow/index.md)
+- GitLab's S3 Bucket
+- GitLab's Snowflake Data Warehouse
+- Sisense:
+
+```mermaid
+sequenceDiagram
+ participant Snowplow JS (Frontend)
+ participant Snowplow Ruby (Backend)
+ participant GitLab.com Snowplow Collector
+ participant S3 Bucket
+ participant Snowflake DW
+ participant Sisense Dashboards
+ Snowplow JS (Frontend) ->> GitLab.com Snowplow Collector: FE Tracking event
+ Snowplow Ruby (Backend) ->> GitLab.com Snowplow Collector: BE Tracking event
+ loop Process using Kinesis Stream
+ GitLab.com Snowplow Collector ->> GitLab.com Snowplow Collector: Log raw events
+ GitLab.com Snowplow Collector ->> GitLab.com Snowplow Collector: Enrich events
+ GitLab.com Snowplow Collector ->> GitLab.com Snowplow Collector: Write to disk
+ end
+ GitLab.com Snowplow Collector ->> S3 Bucket: Kinesis Firehose
+ S3 Bucket->>Snowflake DW: Import data
+ Snowflake DW->>Snowflake DW: Transform data using dbt
+ Snowflake DW->>Sisense Dashboards: Data available for querying
+```
+
+## Structured event taxonomy
+
+When adding new click events, we should add them in a way that's internally consistent. If we don't, it'll be very painful to perform analysis across features since each feature will be capturing events differently.
+
+The current method provides several attributes that are sent on each click event. Please try to follow these guidelines when specifying events to capture:
+
+| attribute | type | required | description |
+| --------- | ------- | -------- | ----------- |
+| category | text | true | The page or backend area of the application. Unless infeasible, please use the Rails page attribute by default in the frontend, and namespace + classname on the backend. |
+| action | text | true | The action the user is taking, or aspect that's being instrumented. The first word should always describe the action or aspect: clicks should be `click`, activations should be `activate`, creations should be `create`, etc. Use underscores to describe what was acted on; for example, activating a form field would be `activate_form_input`. An interface action like clicking on a dropdown would be `click_dropdown`, while a behavior like creating a project record from the backend would be `create_project` |
+| label | text | false | The specific element, or object that's being acted on. This is either the label of the element (e.g. a tab labeled 'Create from template' may be `create_from_template`) or a unique identifier if no text is available (e.g. closing the Groups dropdown in the top navbar might be `groups_dropdown_close`), or it could be the name or title attribute of a record being created. |
+| property | text | false | Any additional property of the element, or object being acted on. |
+| value | decimal | false | Describes a numeric value or something directly related to the event. This could be the value of an input (e.g. `10` when clicking `internal` visibility). |
+
+## Implementing Snowplow JS (Frontend) tracking
+
+GitLab provides `Tracking`, an interface that wraps the [Snowplow JavaScript Tracker](https://github.com/snowplow/snowplow/wiki/javascript-tracker) for tracking custom events. There are a few ways to utilize tracking, but each generally requires at minimum, a `category` and an `action`. Additional data can be provided that adheres to our [Structured event taxonomy](#structured-event-taxonomy).
+
+| field | type | default value | description |
+|:-----------|:-------|:---------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| `category` | string | document.body.dataset.page | Page or subsection of a page that events are being captured within. |
+| `action` | string | 'generic' | Action the user is taking. Clicks should be `click` and activations should be `activate`, so for example, focusing a form field would be `activate_form_input`, and clicking a button would be `click_button`. |
+| `data` | object | {} | Additional data such as `label`, `property`, `value`, and `context` as described in our [Structured event taxonomy](#structured-event-taxonomy). |
+
+### Tracking in HAML (or Vue Templates)
+
+When working within HAML (or Vue templates) we can add `data-track-*` attributes to elements of interest. All elements that have a `data-track-event` attribute automatically have event tracking bound on clicks.
+
+Below is an example of `data-track-*` attributes assigned to a button:
+
+```haml
+%button.btn{ data: { track: { event: "click_button", label: "template_preview", property: "my-template" } } }
+```
+
+```html
+<button class="btn"
+ data-track-event="click_button"
+ data-track-label="template_preview"
+ data-track-property="my-template"
+/>
+```
+
+Event listeners are bound at the document level to handle click events on or within elements with these data attributes. This allows them to be properly handled on re-rendering and changes to the DOM. Note that because of the way these events are bound, click events should not be stopped from propagating up the DOM tree. If for any reason click events are being stopped from propagating, you need to implement your own listeners and follow the instructions in [Tracking in raw JavaScript](#tracking-in-raw-javascript).
+
+Below is a list of supported `data-track-*` attributes:
+
+| attribute | required | description |
+|:----------------------|:---------|:------------|
+| `data-track-event` | 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 would be `activate_form_input` and clicking a button would be `click_button`. |
+| `data-track-label` | false | The `label` as described in our [Structured event taxonomy](#structured-event-taxonomy). |
+| `data-track-property` | false | The `property` as described in our [Structured event taxonomy](#structured-event-taxonomy). |
+| `data-track-value` | false | The `value` as described in our [Structured event taxonomy](#structured-event-taxonomy). If omitted, this is the element's `value` property or an empty string. For checkboxes, the default value is the element's checked attribute or `false` when unchecked. |
+| `data-track-context` | false | The `context` as described in our [Structured event taxonomy](#structured-event-taxonomy). |
+
+### Tracking within Vue components
+
+There's a tracking Vue mixin that can be used in components if more complex tracking is required. To use it, first import the `Tracking` library and request a mixin.
+
+```javascript
+import Tracking from '~/tracking';
+const trackingMixin = Tracking.mixin({ label: 'right_sidebar' });
+```
+
+You can provide default options that are passed along whenever an event is tracked from within your component. For instance, if all events within a component should be tracked with a given `label`, you can provide one at this time. Available defaults are `category`, `label`, `property`, and `value`. If no category is specified, `document.body.dataset.page` is used as the default.
+
+You can then use the mixin normally in your component with the `mixin` Vue declaration. The mixin also provides the ability to specify tracking options in `data` or `computed`. These override any defaults and allow the values to be dynamic from props, or based on state.
+
+```javascript
+export default {
+ mixins: [trackingMixin],
+ // ...[component implementation]...
+ data() {
+ return {
+ expanded: false,
+ tracking: {
+ label: 'left_sidebar'
+ }
+ };
+ },
+}
+```
+
+The mixin provides a `track` method that can be called within the template, or from component methods. An example of the whole implementation might look like the following.
+
+```javascript
+export default {
+ mixins: [Tracking.mixin({ label: 'right_sidebar' })],
+ data() {
+ return {
+ expanded: false,
+ };
+ },
+ methods: {
+ toggle() {
+ this.expanded = !this.expanded;
+ this.track('click_toggle', { value: this.expanded })
+ }
+ }
+};
+```
+
+And if needed within the template, you can use the `track` method directly as well.
+
+```html
+<template>
+ <div>
+ <a class="toggle" @click.prevent="toggle">Toggle</a>
+ <div v-if="expanded">
+ <p>Hello world!</p>
+ <a @click.prevent="track('click_action')">Track an event</a>
+ </div>
+ </div>
+</template>
+```
+
+### Tracking in raw JavaScript
+
+Custom event tracking and instrumentation can be added by directly calling the `Tracking.event` static function. The following example demonstrates tracking a click on a button by calling `Tracking.event` manually.
+
+```javascript
+import Tracking from '~/tracking';
+
+const button = document.getElementById('create_from_template_button');
+button.addEventListener('click', () => {
+ Tracking.event('dashboard:projects:index', 'click_button', {
+ label: 'create_from_template',
+ property: 'template_preview',
+ value: 'rails',
+ });
+})
+```
+
+### Tests and test helpers
+
+In Jest particularly in Vue tests, you can use the following:
+
+```javascript
+import { mockTracking } from 'helpers/tracking_helper';
+
+describe('MyTracking', () => {
+ let spy;
+
+ beforeEach(() => {
+ spy = mockTracking('_category_', wrapper.element, jest.spyOn);
+ });
+
+ it('tracks an event when clicked on feedback', () => {
+ wrapper.find('.discover-feedback-icon').trigger('click');
+
+ expect(spy).toHaveBeenCalledWith('_category_', 'click_button', {
+ label: 'security-discover-feedback-cta',
+ property: '0',
+ });
+ });
+});
+```
+
+In obsolete Karma tests it's used as below:
+
+```javascript
+import { mockTracking, triggerEvent } from 'spec/helpers/tracking_helper';
+
+describe('my component', () => {
+ let trackingSpy;
+
+ beforeEach(() => {
+ trackingSpy = mockTracking('_category_', vm.$el, spyOn);
+ });
+
+ const triggerEvent = () => {
+ // action which should trigger a event
+ };
+
+ it('tracks an event when toggled', () => {
+ expect(trackingSpy).not.toHaveBeenCalled();
+
+ triggerEvent('a.toggle');
+
+ expect(trackingSpy).toHaveBeenCalledWith('_category_', 'click_edit_button', {
+ label: 'right_sidebar',
+ property: 'confidentiality',
+ });
+ });
+});
+```
+
+## Implementing Snowplow Ruby (Backend) tracking
+
+GitLab provides `Gitlab::Tracking`, an interface that wraps the [Snowplow Ruby Tracker](https://github.com/snowplow/snowplow/wiki/ruby-tracker) for tracking custom events.
+
+Custom event tracking and instrumentation can be added by directly calling the `GitLab::Tracking.event` class method, which accepts the following arguments:
+
+| argument | type | default value | description |
+|:-----------|:-------|:--------------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| `category` | string | 'application' | Area or aspect of the application. This could be `HealthCheckController` or `Lfs::FileTransformer` for instance. |
+| `action` | string | 'generic' | The action being taken, which can be anything from a controller action like `create` to something like an Active Record callback. |
+| `data` | object | {} | Additional data such as `label`, `property`, `value`, and `context` as described in [Structured event taxonomy](#structured-event-taxonomy). These are set as empty strings if you don't provide them. |
+
+Tracking can be viewed as either tracking user behavior, or can be utilized for instrumentation to monitor and visualize performance over time in an area or aspect of code.
+
+For example:
+
+```ruby
+class Projects::CreateService < BaseService
+ def execute
+ project = Project.create(params)
+
+ Gitlab::Tracking.event('Projects::CreateService', 'create_project',
+ label: project.errors.full_messages.to_sentence,
+ value: project.valid?
+ )
+ end
+end
+```
+
+### Unit testing
+
+Use the `expect_snowplow_event` helper when testing backend Snowplow events. See [testing best practices](
+https://docs.gitlab.com/ee/development/testing_guide/best_practices.html#test-snowplow-events) for details.
+
+### Performance
+
+We use the [AsyncEmitter](https://github.com/snowplow/snowplow/wiki/Ruby-Tracker#52-the-asyncemitter-class) when tracking events, which allows for instrumentation calls to be run in a background thread. This is still an active area of development.
+
+## Developing and testing Snowplow
+
+There are several tools for developing and testing Snowplow Event
+
+| Testing Tool | Frontend Tracking | Backend Tracking | Local Development Environment | Production Environment | Production Environment |
+|----------------------------------------------|--------------------|---------------------|-------------------------------|------------------------|------------------------|
+| Snowplow Analytics Debugger Chrome Extension | **{check-circle}** | **{dotted-circle}** | **{check-circle}** | **{check-circle}** | **{check-circle}** |
+| Snowplow Inspector Chrome Extension | **{check-circle}** | **{dotted-circle}** | **{check-circle}** | **{check-circle}** | **{check-circle}** |
+| Snowplow Micro | **{check-circle}** | **{check-circle}** | **{check-circle}** | **{dotted-circle}** | **{dotted-circle}** |
+| Snowplow Mini | **{check-circle}** | **{check-circle}** | **{dotted-circle}** | **{status_preparing}** | **{status_preparing}** |
+
+**Legend**
+
+**{check-circle}** Available, **{status_preparing}** In progress, **{dotted-circle}** Not Planned
+
+### Preparing your MR for Review
+
+1. For frontend events, in the MR description section, add a screenshot of the event's relevant section using the [Snowplow Analytics Debugger](https://chrome.google.com/webstore/detail/snowplow-analytics-debugg/jbnlcgeengmijcghameodeaenefieedm) Chrome browser extension.
+1. For backend events, please use Snowplow Micro and add the output of the Snowplow Micro good events `GET http://localhost:9090/micro/good`.
+
+### Snowplow Analytics Debugger Chrome Extension
+
+Snowplow Analytics Debugger is a browser extension for testing frontend events. This works on production, staging and local development environments.
+
+1. Install the [Snowplow Analytics Debugger](https://chrome.google.com/webstore/detail/snowplow-analytics-debugg/jbnlcgeengmijcghameodeaenefieedm) Chrome browser extension.
+1. Open Chrome DevTools to the Snowplow Analytics Debugger tab.
+1. Learn more at [Igloo Analytics](https://www.iglooanalytics.com/blog/snowplow-analytics-debugger-chrome-extension.html).
+
+### Snowplow Inspector Chrome Extension
+
+Snowplow Inspector Chrome Extension is a browser extension for testing frontend events. This works on production, staging and local development environments.
+
+1. Install [Snowplow Inspector](https://chrome.google.com/webstore/detail/snowplow-inspector/maplkdomeamdlngconidoefjpogkmljm?hl=en).
+1. Open the Chrome extension by pressing the Snowplow Inspector icon beside the address bar.
+1. Click around on a webpage with Snowplow and you should see JavaScript events firing in the inspector window.
+
+### Snowplow Micro
+
+Snowplow Micro is a very small version of a full Snowplow data collection pipeline: small enough that it can be launched by a test suite. Events can be recorded into Snowplow Micro just as they can a full Snowplow pipeline. Micro then exposes an API that can be queried.
+
+Snowplow Micro is a Docker-based solution for testing frontend and backend events in a local development environment. You need to modify GDK using the instructions below to set this up.
+
+- Read [Introducing Snowplow Micro](https://snowplowanalytics.com/blog/2019/07/17/introducing-snowplow-micro/)
+- Look at the [Snowplow Micro repository](https://github.com/snowplow-incubator/snowplow-micro)
+- Watch our [installation guide recording](https://www.youtube.com/watch?v=OX46fo_A0Ag)
+
+1. Install [Snowplow Micro](https://github.com/snowplow-incubator/snowplow-micro):
+
+ ```shell
+ docker run --mount type=bind,source=$(pwd)/example,destination=/config -p 9090:9090 snowplow/snowplow-micro:latest --collector-config /config/micro.conf --iglu /config/iglu.json
+ ```
+
+1. Install Snowplow Micro by cloning the settings in [this project](https://gitlab.com/gitlab-org/snowplow-micro-configuration):
+
+ ```shell
+ git clone git@gitlab.com:gitlab-org/snowplow-micro-configuration.git
+ ./snowplow-micro.sh
+ ```
+
+1. Update port in SQL to set `9090`:
+
+ ```shell
+ gdk psql -d gitlabhq_development
+ update application_settings set snowplow_collector_hostname='localhost:9090', snowplow_enabled=true, snowplow_cookie_domain='.gitlab.com';
+ ```
+
+1. Update `app/assets/javascripts/tracking.js` to [remove this line](https://gitlab.com/snippets/1918635):
+
+ ```javascript
+ forceSecureTracker: true
+ ```
+
+1. Update `lib/gitlab/tracking.rb` to [add these lines](https://gitlab.com/snippets/1918635):
+
+ ```ruby
+ protocol: 'http',
+ port: 9090,
+ ```
+
+1. Update `lib/gitlab/tracking.rb` to [change async emitter from https to http](https://gitlab.com/snippets/1918635):
+
+ ```ruby
+ SnowplowTracker::AsyncEmitter.new(Gitlab::CurrentSettings.snowplow_collector_hostname, protocol: 'http'),
+ ```
+
+1. Enable Snowplow in the admin area, Settings::Integrations::Snowplow to point to:
+ `http://localhost:3000/admin/application_settings/integrations#js-snowplow-settings`.
+
+1. Restart GDK:
+
+ ```shell
+ `gdk restart`
+ ```
+
+1. Send a test Snowplow event from the Rails console:
+
+ ```ruby
+ Gitlab::Tracking.self_describing_event('iglu:com.gitlab/pageview_context/jsonschema/1-0-0', { page_type: 'MY_TYPE' }, context: nil )
+ ```
+
+### Snowplow Mini
+
+[Snowplow Mini](https://github.com/snowplow/snowplow-mini) is an easily-deployable, single-instance version of Snowplow.
+
+Snowplow Mini can be used for testing frontend and backend events on a production, staging and local development environment.
+
+For GitLab.com, we're setting up a [QA and Testing environment](https://gitlab.com/gitlab-org/telemetry/-/issues/266) using Snowplow Mini.
diff --git a/doc/development/product_analytics/usage_ping.md b/doc/development/product_analytics/usage_ping.md
new file mode 100644
index 00000000000..d482af77d8a
--- /dev/null
+++ b/doc/development/product_analytics/usage_ping.md
@@ -0,0 +1,937 @@
+---
+stage: Growth
+group: Product Analytics
+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/#designated-technical-writers
+---
+
+# Usage Ping Guide
+
+> - Introduced in GitLab Enterprise Edition 8.10.
+> - More statistics were added in GitLab Enterprise Edition 8.12.
+> - Moved to GitLab Core in 9.1.
+> - More statistics were added in GitLab Ultimate 11.2.
+
+This guide describes Usage Ping's purpose and how it's implemented.
+
+For more information about Product Analytics, see:
+
+- [Product Analytics Guide](index.md)
+- [Snowplow Guide](snowplow.md)
+
+More useful links:
+
+- [Product Analytics Direction](https://about.gitlab.com/direction/product-analytics/)
+- [Data Analysis Process](https://about.gitlab.com/handbook/business-ops/data-team/#data-analysis-process/)
+- [Data for Product Managers](https://about.gitlab.com/handbook/business-ops/data-team/programs/data-for-product-managers/)
+- [Data Infrastructure](https://about.gitlab.com/handbook/business-ops/data-team/platform/infrastructure/)
+
+## What is Usage Ping?
+
+- GitLab sends a weekly payload containing usage data to GitLab Inc. Usage Ping provides high-level data to help our product, support, and sales teams. It does not send any project names, usernames, or any other specific data. The information from the usage ping is not anonymous, it is linked to the hostname of the instance. Sending usage ping is optional, and any instance can disable analytics.
+- The usage data is primarily composed of row counts for different tables in the instance’s database. By comparing these counts month over month (or week over week), we can get a rough sense for how an instance is using the different features within the product. In addition to counts, other facts
+ that help us classify and understand GitLab installations are collected.
+- Usage ping is important to GitLab as we use it to calculate our Stage Monthly Active Users (SMAU) which helps us measure the success of our stages and features.
+- While usage ping is enabled, GitLab will gather data from the other instances and will be able to show usage statistics of your instance to your users.
+
+### Why should we enable Usage Ping?
+
+- The main purpose of Usage Ping is to build a better GitLab. Data about how GitLab is used is collected to better understand feature/stage adoption and usage, which helps us understand how GitLab is adding value and helps our team better understand the reasons why people use GitLab and with this knowledge we're able to make better product decisions.
+- As a benefit of having the usage ping active, GitLab lets you analyze the users’ activities over time of your GitLab installation.
+- As a benefit of having the usage ping active, GitLab provides you with The DevOps Report,which gives you an overview of your entire instance’s adoption of Concurrent DevOps from planning to monitoring.
+- You will get better, more proactive support. (assuming that our TAMs and support organization used the data to deliver more value)
+- You will get insight and advice into how to get the most value out of your investment in GitLab. Wouldn't you want to know that a number of features or values are not being adopted in your organization?
+- You get a report that illustrates how you compare against other similar organizations (anonymized), with specific advice and recommendations on how to improve your DevOps processes.
+- Usage Ping is enabled by default. To disable it, see [Disable Usage Ping](#disable-usage-ping).
+
+### Limitations
+
+- Usage Ping does not track frontend events things like page views, link clicks, or user sessions, and only focuses on aggregated backend events.
+- Because of these limitations we recommend instrumenting your products with Snowplow for more detailed analytics on GitLab.com and use Usage Ping to track aggregated backend events on self-managed.
+
+## Usage Ping payload
+
+You can view the exact JSON payload sent to GitLab Inc. in the administration panel. To view the payload:
+
+1. Navigate to **Admin Area > Settings > Metrics and profiling**.
+1. Expand the **Usage statistics** section.
+1. Click the **Preview payload** button.
+
+For an example payload, see [Example Usage Ping payload](#example-usage-ping-payload).
+
+## Disable Usage Ping
+
+To disable Usage Ping in the GitLab UI, go to the **Settings** page of your administration panel and uncheck the **Usage Ping** checkbox.
+
+To disable Usage Ping and prevent it from being configured in the future through the administration panel, Omnibus installs can set the following in [`gitlab.rb`](https://docs.gitlab.com/omnibus/settings/configuration.html#configuration-options):
+
+```ruby
+gitlab_rails['usage_ping_enabled'] = false
+```
+
+Source installations can set the following in `gitlab.yml`:
+
+```yaml
+production: &base
+ # ...
+ gitlab:
+ # ...
+ usage_ping_enabled: false
+```
+
+## Usage Ping request flow
+
+The following example shows a basic request/response flow between a GitLab instance, the Versions Application, the License Application, Salesforce, GitLab's S3 Bucket, GitLab's Snowflake Data Warehouse, and Sisense:
+
+```mermaid
+sequenceDiagram
+ participant GitLab Instance
+ participant Versions Application
+ participant Licenses Application
+ participant Salesforce
+ participant S3 Bucket
+ participant Snowflake DW
+ participant Sisense Dashboards
+ GitLab Instance->>Versions Application: Send Usage Ping
+ loop Process usage data
+ Versions Application->>Versions Application: Parse usage data
+ Versions Application->>Versions Application: Write to database
+ Versions Application->>Versions Application: Update license ping time
+ end
+ loop Process data for Salesforce
+ Versions Application-xLicenses Application: Request Zuora subscription id
+ Licenses Application-xVersions Application: Zuora subscription id
+ Versions Application-xSalesforce: Request Zuora account id by Zuora subscription id
+ Salesforce-xVersions Application: Zuora account id
+ Versions Application-xSalesforce: Usage data for the Zuora account
+ end
+ Versions Application->>S3 Bucket: Export Versions database
+ S3 Bucket->>Snowflake DW: Import data
+ Snowflake DW->>Snowflake DW: Transform data using dbt
+ Snowflake DW->>Sisense Dashboards: Data available for querying
+ Versions Application->>GitLab Instance: DevOps Report (Conversational Development Index)
+```
+
+## How Usage Ping works
+
+1. The Usage Ping [cron job](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/workers/gitlab_usage_ping_worker.rb#L30) is set in Sidekiq to run weekly.
+1. When the cron job runs, it calls [`GitLab::UsageData.to_json`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/services/submit_usage_ping_service.rb#L22).
+1. `GitLab::UsageData.to_json` [cascades down](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/usage_data.rb#L22) to ~400+ other counter method calls.
+1. The response of all methods calls are [merged together](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/usage_data.rb#L14) into a single JSON payload in `GitLab::UsageData.to_json`.
+1. The JSON payload is then [posted to the Versions application]( https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/services/submit_usage_ping_service.rb#L20).
+
+## Implementing Usage Ping
+
+Usage Ping consists of two kinds of data, counters and observations. Counters track how often a certain event
+happened over time, such as how many CI pipelines have run. They are monotonic and always trend up.
+Observations are facts collected from one or more GitLab instances and can carry arbitrary data. There are no
+general guidelines around how to collect those, due to the individual nature of that data.
+
+There are several types of counters which are all found in `usage_data.rb`:
+
+- **Ordinary Batch Counters:** Simple count of a given ActiveRecord_Relation
+- **Distinct Batch Counters:** Distinct count of a given ActiveRecord_Relation on given column
+- **Sum Batch Counters:** Sum the values of a given ActiveRecord_Relation on given column
+- **Alternative Counters:** Used for settings and configurations
+- **Redis Counters:** Used for in-memory counts.
+
+NOTE: **Note:**
+Only use the provided counter methods. Each counter method contains a built in fail safe to isolate each counter to avoid breaking the entire Usage Ping.
+
+### Why batch counting
+
+For large tables, PostgreSQL can take a long time to count rows due to MVCC [(Multi-version Concurrency Control)](https://en.wikipedia.org/wiki/Multiversion_concurrency_control). Batch counting is a counting method where a single large query is broken into multiple smaller queries. For example, instead of a single query querying 1,000,000 records, with batch counting, you can execute 100 queries of 10,000 records each. Batch counting is useful for avoiding database timeouts as each batch query is significantly shorter than one single long running query.
+
+For GitLab.com, there are extremely large tables with 15 second query timeouts, so we use batch counting to avoid encountering timeouts. Here are the sizes of some GitLab.com tables:
+
+| Table | Row counts in millions |
+|------------------------------|------------------------|
+| `merge_request_diff_commits` | 2280 |
+| `ci_build_trace_sections` | 1764 |
+| `merge_request_diff_files` | 1082 |
+| `events` | 514 |
+
+There are two batch counting methods provided, `Ordinary Batch Counters` and `Distinct Batch Counters`. Batch counting requires indexes on columns to calculate max, min, and range queries. In some cases, a specialized index may need to be added on the columns involved in a counter.
+
+### Ordinary Batch Counters
+
+Handles `ActiveRecord::StatementInvalid` error
+
+Simple count of a given ActiveRecord_Relation, does a non-distinct batch count, smartly reduces batch_size and handles errors.
+
+Method: `count(relation, column = nil, batch: true, start: nil, finish: nil)`
+
+Arguments:
+
+- `relation` the ActiveRecord_Relation to perform the count
+- `column` the column to perform the count on, by default is the primary key
+- `batch`: default `true` in order to use batch counting
+- `start`: custom start of the batch counting in order to avoid complex min calculations
+- `end`: custom end of the batch counting in order to avoid complex min calculations
+
+Examples:
+
+```ruby
+count(User.active)
+count(::Clusters::Cluster.aws_installed.enabled, :cluster_id)
+count(::Clusters::Cluster.aws_installed.enabled, :cluster_id, start: ::Clusters::Cluster.minimum(:id), finish: ::Clusters::Cluster.maximum(:id))
+```
+
+### Distinct Batch Counters
+
+Handles `ActiveRecord::StatementInvalid` error
+
+Distinct count of a given ActiveRecord_Relation on given column, a distinct batch count, smartly reduces batch_size and handles errors.
+
+Method: `distinct_count(relation, column = nil, batch: true, batch_size: nil, start: nil, finish: nil)`
+
+Arguments:
+
+- `relation` the ActiveRecord_Relation to perform the count
+- `column` the column to perform the distinct count, by default is the primary key
+- `batch`: default `true` in order to use batch counting
+- `batch_size`: if none set it will use default value 10000 from `Gitlab::Database::BatchCounter`
+- `start`: custom start of the batch counting in order to avoid complex min calculations
+- `end`: custom end of the batch counting in order to avoid complex min calculations
+
+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')
+```
+
+### Sum Batch Counters
+
+Handles `ActiveRecord::StatementInvalid` error
+
+Sum the values of a given ActiveRecord_Relation on given column and handles errors.
+
+Method: `sum(relation, column, batch_size: nil, start: nil, finish: nil)`
+
+Arguments:
+
+- `relation` the ActiveRecord_Relation to perform the operation
+- `column` the column to sum on
+- `batch_size`: if none set it will use default value 1000 from `Gitlab::Database::BatchCounter`
+- `start`: custom start of the batch counting in order to avoid complex min calculations
+- `end`: custom end of the batch counting in order to avoid complex min calculations
+
+Examples:
+
+```ruby
+sum(JiraImportState.finished, :imported_issues_count)
+```
+
+### Grouping & Batch Operations
+
+The `count`, `distinct_count`, and `sum` batch counters can accept an `ActiveRecord::Relation`
+object, which groups by a specified column. With a grouped relation, the methods do batch counting,
+handle errors, and returns a hash table of key-value pairs.
+
+Examples:
+
+```ruby
+count(Namespace.group(:type))
+# returns => {nil=>179, "Group"=>54}
+
+distinct_count(Project.group(:visibility_level), :creator_id)
+# returns => {0=>1, 10=>1, 20=>11}
+
+sum(Issue.group(:state_id), :weight))
+# returns => {1=>3542, 2=>6820}
+```
+
+### Redis Counters
+
+Handles `::Redis::CommandError` and `Gitlab::UsageDataCounters::BaseCounter::UnknownEvent`
+returns -1 when a block is sent or hash with all values -1 when a `counter(Gitlab::UsageDataCounters)` is sent
+different behavior due to 2 different implementations of Redis counter
+
+Method: `redis_usage_data(counter, &block)`
+
+Arguments:
+
+- `counter`: a counter from `Gitlab::UsageDataCounters`, that has `fallback_totals` method implemented
+- or a `block`: which is evaluated
+
+#### Ordinary Redis Counters
+
+Examples of implementation:
+
+- Using Redis methods [`INCR`](https://redis.io/commands/incr), [`GET`](https://redis.io/commands/get), and [`Gitlab::UsageDataCounters::WikiPageCounter`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/usage_data_counters/wiki_page_counter.rb)
+- Using Redis methods [`HINCRBY`](https://redis.io/commands/hincrby), [`HGETALL`](https://redis.io/commands/hgetall), and [`Gitlab::UsageCounters::PodLogs`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/usage_counters/pod_logs.rb)
+
+#### Redis HLL Counters
+
+With `Gitlab::UsageDataCounters::HLLRedisCounter` we have available data structures used to count unique values.
+
+Implemented using Redis methods [PFADD](https://redis.io/commands/pfadd) and [PFCOUNT](https://redis.io/commands/pfcount).
+
+##### Adding new events
+
+1. Define events in [`known_events.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/usage_data_counters/known_events.yml).
+
+ Example event:
+
+ ```yaml
+ - name: i_compliance_credential_inventory
+ category: compliance
+ redis_slot: compliance
+ expiry: 42 # 6 weeks
+ aggregation: weekly
+ ```
+
+ Keys:
+
+ - `name`: unique event name.
+
+ Name format `<prefix>_<redis_slot>_name`.
+
+ Use one of the following prefixes for the event's name:
+
+ - `g_` for group, as an event which is tracked for group.
+ - `p_` for project, as an event which is tracked for project.
+ - `i_` for instance, as an event which is tracked for instance.
+ - `a_` for events encompassing all `g_`, `p_`, `i_`.
+ - `o_` for other.
+
+ Consider including in the event's name the Redis slot in order to be able to count totals for a specific category.
+
+ Example names: `i_compliance_credential_inventory`, `g_analytics_contribution`.
+
+ - `category`: event category. Used for getting total counts for events in a category, for easier
+ access to a group of events.
+ - `redis_slot`: optional Redis slot; default value: event name. Used if needed to calculate totals
+ for a group of metrics. Ensure keys are in the same slot. For example:
+ `i_compliance_credential_inventory` with `redis_slot: 'compliance'` will build Redis key
+ `i_{compliance}_credential_inventory-2020-34`. If `redis_slot` is not defined the Redis key will
+ be `{i_compliance_credential_inventory}-2020-34`.
+ - `expiry`: expiry time in days. Default: 29 days for daily aggregation and 6 weeks for weekly
+ aggregation.
+ - `aggregation`: aggregation `:daily` or `:weekly`. The argument defines how we build the Redis
+ keys for data storage. For `daily` we keep a key for metric per day of the year, for `weekly` we
+ keep a key for metric per week of the year.
+
+1. Track event in controller using `RedisTracking` module with `track_redis_hll_event(*controller_actions, name:, feature:, feature_default_enabled: false)`.
+
+ Arguments:
+
+ - `controller_actions`: controller actions we want to track.
+ - `name`: event name.
+ - `feature`: feature name, all metrics we track should be under feature flag.
+ - `feature_default_enabled`: feature flag is disabled by default, set to `true` for it to be enabled by default.
+
+ Example usage:
+
+ ```ruby
+ # controller
+ class ProjectsController < Projects::ApplicationController
+ include RedisTracking
+
+ skip_before_action :authenticate_user!, only: :show
+ track_redis_hll_event :index, :show, name: 'g_compliance_example_feature_visitors', feature: :compliance_example_feature, feature_default_enabled: true
+
+ def index
+ render html: 'index'
+ end
+
+ def new
+ render html: 'new'
+ end
+
+ def show
+ render html: 'show'
+ end
+ end
+ ```
+
+1. Track event in API using `increment_unique_values(event_name, values)` helper method.
+
+ In order to be able to track the event, Usage Ping must be enabled and the event feature `usage_data_<event_name>` must be enabled.
+
+ Arguments:
+
+ - `event_name`: event name.
+ - `values`: values counted, one value or array of values.
+
+ Example usage:
+
+ ```ruby
+ get ':id/registry/repositories' do
+ repositories = ContainerRepositoriesFinder.new(
+ user: current_user, subject: user_group
+ ).execute
+
+ increment_unique_values('i_list_repositories', current_user.id)
+
+ present paginate(repositories), with: Entities::ContainerRegistry::Repository, tags: params[:tags], tags_count: params[:tags_count]
+ end
+ ```
+
+1. Track event using `track_usage_event(event_name, values) in services and graphql
+
+ Increment unique values count using Redis HLL, for given event name.
+
+ Example:
+
+ [Track usage event for incident created in service](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/services/issues/update_service.rb)
+
+ [Track usage event for incident created in graphql](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/graphql/mutations/alert_management/update_alert_status.rb)
+
+ ```ruby
+ track_usage_event(:incident_management_incident_created, current_user.id)
+ ```
+
+1. Track event using `UsageData` API
+
+ Increment unique users count using Redis HLL, for given event name.
+
+ Tracking events using the `UsageData` API requires the `usage_data_api` feature flag to be enabled, which is enabled by default.
+
+ API requests are protected by checking for a valid CSRF token.
+
+ In order to be able to increment the values the related feature `usage_data<event_name>` should be enabled.
+
+ ```plaintext
+ POST /usage_data/increment_unique_users
+ ```
+
+ | Attribute | Type | Required | Description |
+ | :-------- | :--- | :------- | :---------- |
+ | `event` | string | yes | The event name it should be tracked |
+
+ Response
+w
+ Return 200 if tracking failed for any reason.
+
+ - `200` if event was tracked or any errors
+ - `400 Bad request` if event parameter is missing
+ - `401 Unauthorized` if user is not authenticated
+ - `403 Forbidden` for invalid CSRF token provided
+
+1. Track events using JavaScript/Vue API helper which calls the API above
+
+ Example usage for an existing event already defined in [known events](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/usage_data_counters/known_events.yml):
+
+ Note that `usage_data_api` and `usage_data_#{event_name}` should be enabled in order to be able to track events
+
+ ```javascript
+ import api from '~/api';
+
+ api.trackRedisHllUserEvent('my_already_defined_event_name'),
+ ```
+
+1. Track event using base module `Gitlab::UsageDataCounters::HLLRedisCounter.track_event(entity_id, event_name)`.
+
+ Arguments:
+
+ - `entity_id`: value we count. For example: user_id, visitor_id.
+ - `event_name`: event name.
+
+1. Get event data using `Gitlab::UsageDataCounters::HLLRedisCounter.unique_events(event_names:, start_date:, end_date)`.
+
+ Arguments:
+
+ - `event_names`: the list of event names.
+ - `start_date`: start date of the period for which we want to get event data.
+ - `end_date`: end date of the period for which we want to get event data.
+
+Recommendations:
+
+- Key should expire in 29 days for daily and 42 days for weekly.
+- If possible, data granularity should be a week. For example a key could be composed from the
+ metric's name and week of the year, `2020-33-{metric_name}`.
+- Use a [feature flag](../../operations/feature_flags.md) to have a control over the impact when
+ adding new metrics.
+
+##### Known events in usage data payload
+
+All events added in [`known_events.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/usage_data_counters/known_events.yml) are automatically added to usage data generation under the `redis_hll_counters` key. This column is stored in [version-app as a JSON](https://gitlab.com/gitlab-services/version-gitlab-com/-/blob/master/db/schema.rb#L209).
+For each event we add metrics for the weekly and monthly time frames, and totals for each where applicable:
+
+- `#{event_name}_weekly`: Data for 7 days for daily [aggregation](#adding-new-events) events and data for the last complete week for weekly [aggregation](#adding-new-events) events.
+- `#{event_name}_monthly`: Data for 28 days for daily [aggregation](#adding-new-events) events and data for the last 4 complete weeks for weekly [aggregation](#adding-new-events) events.
+- `#{category}_total_unique_counts_weekly`: Total unique counts for events in the same category for the last 7 days or the last complete week, if events are in the same Redis slot and we have more than one metric.
+- `#{category}_total_unique_counts_monthly`: Total unique counts for events in same category for the last 28 days or the last 4 complete weeks, if events are in the same Redis slot and we have more than one metric.
+
+Example of `redis_hll_counters` data:
+
+```ruby
+{:redis_hll_counters=>
+ {"compliance"=>
+ {"g_compliance_dashboard_weekly"=>0,
+ "g_compliance_dashboard_monthly"=>0,
+ "g_compliance_audit_events_weekly"=>0,
+ "g_compliance_audit_events_monthly"=>0,
+ "compliance_total_unique_counts_weekly"=>0,
+ "compliance_total_unique_counts_monthly"=>0},
+ "analytics"=>
+ {"g_analytics_contribution_weekly"=>0,
+ "g_analytics_contribution_monthly"=>0,
+ "g_analytics_insights_weekly"=>0,
+ "g_analytics_insights_monthly"=>0,
+ "analytics_total_unique_counts_weekly"=>0,
+ "analytics_total_unique_counts_monthly"=>0},
+ "ide_edit"=>
+ {"g_edit_by_web_ide_weekly"=>0,
+ "g_edit_by_web_ide_monthly"=>0,
+ "g_edit_by_sfe_weekly"=>0,
+ "g_edit_by_sfe_monthly"=>0,
+ "ide_edit_total_unique_counts_weekly"=>0,
+ "ide_edit_total_unique_counts_monthly"=>0},
+ "search"=>
+ {"i_search_total_weekly"=>0, "i_search_total_monthly"=>0, "i_search_advanced_weekly"=>0, "i_search_advanced_monthly"=>0, "i_search_paid_weekly"=>0, "i_search_paid_monthly"=>0, "search_total_unique_counts_weekly"=>0, "search_total_unique_counts_monthly"=>0},
+ "source_code"=>{"wiki_action_weekly"=>0, "wiki_action_monthly"=>0}
+ }
+```
+
+Example usage:
+
+```ruby
+# Redis Counters
+redis_usage_data(Gitlab::UsageDataCounters::WikiPageCounter)
+redis_usage_data { ::Gitlab::UsageCounters::PodLogs.usage_totals[:total] }
+
+# Define events in known_events.yml https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/usage_data_counters/known_events.yml
+
+# Tracking events
+Gitlab::UsageDataCounters::HLLRedisCounter.track_event(visitor_id, 'expand_vulnerabilities')
+
+# Get unique events for metric
+redis_usage_data { Gitlab::UsageDataCounters::HLLRedisCounter.unique_events(event_names: 'expand_vulnerabilities', start_date: 28.days.ago, end_date: Date.current) }
+```
+
+### Alternative Counters
+
+Handles `StandardError` and fallbacks into -1 this way not all measures fail if we encounter one exception.
+Mainly used for settings and configurations.
+
+Method: `alt_usage_data(value = nil, fallback: -1, &block)`
+
+Arguments:
+
+- `value`: a simple static value in which case the value is simply returned.
+- or a `block`: which is evaluated
+- `fallback: -1`: the common value used for any metrics that are failing.
+
+Example of usage:
+
+```ruby
+alt_usage_data { Gitlab::VERSION }
+alt_usage_data { Gitlab::CurrentSettings.uuid }
+alt_usage_data(999)
+```
+
+### Prometheus Queries
+
+In those cases where operational metrics should be part of Usage Ping, a database or Redis query is unlikely
+to provide useful data. Instead, Prometheus might be more appropriate, since most of GitLab's architectural
+components publish metrics to it that can be queried back, aggregated, and included as usage data.
+
+NOTE: **Note:**
+Prometheus as a data source for Usage Ping is currently only available for single-node Omnibus installations
+that are running the [bundled Prometheus](../../administration/monitoring/prometheus/index.md) instance.
+
+In order to query Prometheus for metrics, a helper method is available that will `yield` a fully configured
+`PrometheusClient`, given it is available as per the note above:
+
+```ruby
+with_prometheus_client do |client|
+ response = client.query('<your query>')
+ ...
+end
+```
+
+Please refer to [the `PrometheusClient` definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/prometheus_client.rb)
+for how to use its API to query for data.
+
+## Developing and testing Usage Ping
+
+### 1. Use your Rails console to manually test counters
+
+```ruby
+# count
+Gitlab::UsageData.count(User.active)
+Gitlab::UsageData.count(::Clusters::Cluster.aws_installed.enabled, :cluster_id)
+
+# count distinct
+Gitlab::UsageData.distinct_count(::Project, :creator_id)
+Gitlab::UsageData.distinct_count(::Note.with_suggestions.where(time_period), :author_id, start: ::User.minimum(:id), finish: ::User.maximum(:id))
+```
+
+### 2. Generate the SQL query
+
+Your Rails console will return the generated SQL queries.
+
+Example:
+
+```ruby
+pry(main)> Gitlab::UsageData.count(User.active)
+ (2.6ms) SELECT "features"."key" FROM "features"
+ (15.3ms) SELECT MIN("users"."id") FROM "users" WHERE ("users"."state" IN ('active')) AND ("users"."user_type" IS NULL OR "users"."user_type" IN (6, 4))
+ (2.4ms) SELECT MAX("users"."id") FROM "users" WHERE ("users"."state" IN ('active')) AND ("users"."user_type" IS NULL OR "users"."user_type" IN (6, 4))
+ (1.9ms) SELECT COUNT("users"."id") FROM "users" WHERE ("users"."state" IN ('active')) AND ("users"."user_type" IS NULL OR "users"."user_type" IN (6, 4)) AND "users"."id" BETWEEN 1 AND 100000
+```
+
+### 3. Optimize queries with #database-lab
+
+Paste the SQL query into `#database-lab` to see how the query performs at scale.
+
+- `#database-lab` is a Slack channel which uses a production-sized environment to test your queries.
+- GitLab.com’s production database has a 15 second timeout.
+- Any single query must stay below 1 second execution time with cold caches.
+- Add a specialized index on columns involved to reduce the execution time.
+
+In order to have an understanding of the query's execution we add in the MR description the following information:
+
+- For counters that have a `time_period` test we add information for both cases:
+ - `time_period = {}` for all time periods
+ - `time_period = { created_at: 28.days.ago..Time.current }` for last 28 days period
+- Execution plan and query time before and after optimization
+- Query generated for the index and time
+- Migration output for up and down execution
+
+We also use `#database-lab` and [explain.depesz.com](https://explain.depesz.com/). For more details, see the [database review guide](../database_review.md#preparation-when-adding-or-modifying-queries).
+
+#### Optimization recommendations and examples
+
+- Use specialized indexes [example 1](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/26871), [example 2](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/26445).
+- Use defined `start` and `finish`, and simple queries, because these values can be memoized and reused, [example](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/37155).
+- Avoid joins and write the queries as simply as possible, [example](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/36316).
+- Set a custom `batch_size` for `distinct_count`, [example](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/38000).
+
+### 4. Add the metric definition
+
+When adding, changing, or updating metrics, please update the [Event Dictionary's **Usage Ping** table](event_dictionary.md).
+
+### 5. Add new metric to Versions Application
+
+Check if new metrics need to be added to the Versions Application. See `usage_data` [schema](https://gitlab.com/gitlab-services/version-gitlab-com/-/blob/master/db/schema.rb#L147) and usage data [parameters accepted](https://gitlab.com/gitlab-services/version-gitlab-com/-/blob/master/app/services/usage_ping.rb). Any metrics added under the `counts` key are saved in the `stats` column.
+
+### 6. Add the feature label
+
+Add the `feature` label to the Merge Request for new Usage Ping metrics. These are user-facing changes and are part of expanding the Usage Ping feature.
+
+### 7. Add a changelog file
+
+Ensure you comply with the [Changelog entries guide](../changelog.md).
+
+### 8. Ask for a Product Analytics Review
+
+On GitLab.com, we have DangerBot setup to monitor Product Analytics related files and DangerBot will recommend a Product Analytics review. Mention `@gitlab-org/growth/product_analytics/engineers` in your MR for a review.
+
+### 9. Verify your metric
+
+On GitLab.com, the Product Analytics team regularly monitors Usage Ping. They may alert you that your metrics need further optimization to run quicker and with greater success. You may also use the [Usage Ping QA dashboard](https://app.periscopedata.com/app/gitlab/632033/Usage-Ping-QA) to check how well your metric performs. The dashboard allows filtering by GitLab version, by "Self-managed" & "Saas" and shows you how many failures have occurred for each metric. Whenever you notice a high failure rate, you may re-optimize your metric.
+
+### Optional: Test Prometheus based Usage Ping
+
+If the data submitted includes metrics [queried from Prometheus](#prometheus-queries) that you would like to inspect and verify,
+then you need to ensure that a Prometheus server is running locally, and that furthermore the respective GitLab components
+are exporting metrics to it. If you do not need to test data coming from Prometheus, no further action
+is necessary, since Usage Ping should degrade gracefully in the absence of a running Prometheus server.
+
+There are currently three kinds of components that may export data to Prometheus, and which are included in Usage Ping:
+
+- [`node_exporter`](https://github.com/prometheus/node_exporter) - Exports node metrics from the host machine
+- [`gitlab-exporter`](https://gitlab.com/gitlab-org/gitlab-exporter) - Exports process metrics from various GitLab components
+- various GitLab services such as Sidekiq and the Rails server that export their own metrics
+
+#### Test with an Omnibus container
+
+This is the recommended approach to test Prometheus based Usage Ping.
+
+The easiest way to verify your changes is to build a new Omnibus image from your code branch via CI, then download the image
+and run a local container instance:
+
+1. From your merge request, click on the `qa` stage, then trigger the `package-and-qa` job. This job will trigger an Omnibus
+build in a [downstream pipeline of the `omnibus-gitlab-mirror` project](https://gitlab.com/gitlab-org/build/omnibus-gitlab-mirror/-/pipelines).
+1. In the downstream pipeline, wait for the `gitlab-docker` job to finish.
+1. Open the job logs and locate the full container name including the version. It will take the following form: `registry.gitlab.com/gitlab-org/build/omnibus-gitlab-mirror/gitlab-ee:<VERSION>`.
+1. On your local machine, make sure you are logged 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 logged in, download the new image via `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, please refer to [GitLab Docker images](https://docs.gitlab.com/omnibus/docker/README.html) in the Omnibus documentation.
+
+#### Test with GitLab development toolkits
+
+This is the less recommended approach, since it comes with a number of difficulties when emulating a real GitLab deployment.
+
+The [GDK](https://gitlab.com/gitlab-org/gitlab-development-kit) is not currently set up to run a Prometheus server or `node_exporter` alongside other GitLab components. If you would
+like to do so, [Monitoring the GDK with Prometheus](https://gitlab.com/gitlab-org/gitlab-development-kit/-/blob/master/doc/howto/prometheus/index.md#monitoring-the-gdk-with-prometheus) is a good start.
+
+The [GCK](https://gitlab.com/gitlab-org/gitlab-compose-kit) has limited support for testing Prometheus based Usage Ping.
+By default, it already comes with a fully configured Prometheus service that is set up to scrape a number of components,
+but with the following limitations:
+
+- It does not currently run a `gitlab-exporter` instance, so several `process_*` metrics from services such as Gitaly may be missing.
+- While it runs a `node_exporter`, `docker-compose` services emulate hosts, meaning that it would normally report itself to not be associated
+with any of the other services that are running. That is not how node metrics are reported in a production setup, where `node_exporter`
+always runs as a process alongside other GitLab components on any given node. From Usage Ping's perspective none of the node data would therefore
+appear to be associated to any of the services running, since they all appear to be running on different hosts. To alleviate this problem, the `node_exporter` in GCK was arbitrarily "assigned" to the `web` service, meaning only for this service `node_*` metrics will appear in Usage Ping.
+
+## Example Usage Ping payload
+
+The following is example content of the Usage Ping payload.
+
+```json
+{
+ "uuid": "0000000-0000-0000-0000-000000000000",
+ "hostname": "example.com",
+ "version": "12.10.0-pre",
+ "installation_type": "omnibus-gitlab",
+ "active_user_count": 999,
+ "recorded_at": "2020-04-17T07:43:54.162+00:00",
+ "edition": "EEU",
+ "license_md5": "00000000000000000000000000000000",
+ "license_id": null,
+ "historical_max_users": 999,
+ "licensee": {
+ "Name": "ABC, Inc.",
+ "Email": "email@example.com",
+ "Company": "ABC, Inc."
+ },
+ "license_user_count": 999,
+ "license_starts_at": "2020-01-01",
+ "license_expires_at": "2021-01-01",
+ "license_plan": "ultimate",
+ "license_add_ons": {
+ },
+ "license_trial": false,
+ "counts": {
+ "assignee_lists": 999,
+ "boards": 999,
+ "ci_builds": 999,
+ ...
+ },
+ "container_registry_enabled": true,
+ "dependency_proxy_enabled": false,
+ "gitlab_shared_runners_enabled": true,
+ "gravatar_enabled": true,
+ "influxdb_metrics_enabled": true,
+ "ldap_enabled": false,
+ "mattermost_enabled": false,
+ "omniauth_enabled": true,
+ "prometheus_enabled": false,
+ "prometheus_metrics_enabled": false,
+ "reply_by_email_enabled": "incoming+%{key}@incoming.gitlab.com",
+ "signup_enabled": true,
+ "web_ide_clientside_preview_enabled": true,
+ "ingress_modsecurity_enabled": true,
+ "projects_with_expiration_policy_disabled": 999,
+ "projects_with_expiration_policy_enabled": 999,
+ ...
+ "elasticsearch_enabled": true,
+ "license_trial_ends_on": null,
+ "geo_enabled": false,
+ "git": {
+ "version": {
+ "major": 2,
+ "minor": 26,
+ "patch": 1
+ }
+ },
+ "gitaly": {
+ "version": "12.10.0-rc1-93-g40980d40",
+ "servers": 56,
+ "clusters": 14,
+ "filesystems": [
+ "EXT_2_3_4"
+ ]
+ },
+ "gitlab_pages": {
+ "enabled": true,
+ "version": "1.17.0"
+ },
+ "container_registry_server": {
+ "vendor": "gitlab",
+ "version": "2.9.1-gitlab"
+ },
+ "database": {
+ "adapter": "postgresql",
+ "version": "9.6.15",
+ "pg_system_id": 6842684531675334351
+ },
+ "avg_cycle_analytics": {
+ "issue": {
+ "average": 999,
+ "sd": 999,
+ "missing": 999
+ },
+ "plan": {
+ "average": null,
+ "sd": 999,
+ "missing": 999
+ },
+ "code": {
+ "average": null,
+ "sd": 999,
+ "missing": 999
+ },
+ "test": {
+ "average": null,
+ "sd": 999,
+ "missing": 999
+ },
+ "review": {
+ "average": null,
+ "sd": 999,
+ "missing": 999
+ },
+ "staging": {
+ "average": null,
+ "sd": 999,
+ "missing": 999
+ },
+ "production": {
+ "average": null,
+ "sd": 999,
+ "missing": 999
+ },
+ "total": 999
+ },
+ "analytics_unique_visits": {
+ "g_analytics_contribution": 999,
+ ...
+ },
+ "usage_activity_by_stage": {
+ "configure": {
+ "project_clusters_enabled": 999,
+ ...
+ },
+ "create": {
+ "merge_requests": 999,
+ ...
+ },
+ "manage": {
+ "events": 999,
+ ...
+ },
+ "monitor": {
+ "clusters": 999,
+ ...
+ },
+ "package": {
+ "projects_with_packages": 999
+ },
+ "plan": {
+ "issues": 999,
+ ...
+ },
+ "release": {
+ "deployments": 999,
+ ...
+ },
+ "secure": {
+ "user_container_scanning_jobs": 999,
+ ...
+ },
+ "verify": {
+ "ci_builds": 999,
+ ...
+ }
+ },
+ "usage_activity_by_stage_monthly": {
+ "configure": {
+ "project_clusters_enabled": 999,
+ ...
+ },
+ "create": {
+ "merge_requests": 999,
+ ...
+ },
+ "manage": {
+ "events": 999,
+ ...
+ },
+ "monitor": {
+ "clusters": 999,
+ ...
+ },
+ "package": {
+ "projects_with_packages": 999
+ },
+ "plan": {
+ "issues": 999,
+ ...
+ },
+ "release": {
+ "deployments": 999,
+ ...
+ },
+ "secure": {
+ "user_container_scanning_jobs": 999,
+ ...
+ },
+ "verify": {
+ "ci_builds": 999,
+ ...
+ }
+ },
+ "topology": {
+ "duration_s": 0.013836685999194742,
+ "application_requests_per_hour": 4224,
+ "query_apdex_weekly_average": 0.996,
+ "failures": [],
+ "nodes": [
+ {
+ "node_memory_total_bytes": 33269903360,
+ "node_memory_utilization": 0.35,
+ "node_cpus": 16,
+ "node_cpu_utilization": 0.2,
+ "node_uname_info": {
+ "machine": "x86_64",
+ "sysname": "Linux",
+ "release": "4.19.76-linuxkit"
+ },
+ "node_services": [
+ {
+ "name": "web",
+ "process_count": 16,
+ "process_memory_pss": 233349888,
+ "process_memory_rss": 788220927,
+ "process_memory_uss": 195295487,
+ "server": "puma"
+ },
+ {
+ "name": "sidekiq",
+ "process_count": 1,
+ "process_memory_pss": 734080000,
+ "process_memory_rss": 750051328,
+ "process_memory_uss": 731533312
+ },
+ ...
+ ],
+ ...
+ },
+ ...
+ ]
+ }
+}
+```
+
+## Notable changes
+
+In GitLab 13.5, `pg_system_id` was added to send the [PostgreSQL system identifier](https://www.2ndquadrant.com/en/blog/support-for-postgresqls-system-identifier-in-barman/).
+
+## Exporting Usage Ping SQL queries and definitions
+
+Two Rake tasks exist to export Usage Ping definitions.
+
+- The Rake tasks export the raw SQL queries for `count`, `distinct_count`, `sum`.
+- The Rake tasks export the Redis counter class or the line of the Redis block for `redis_usage_data`.
+- The Rake tasks calculate the `alt_usage_data` metrics.
+
+In the home directory of your local GitLab installation run the following Rake tasks for the YAML and JSON versions respectively:
+
+```shell
+# for YAML export
+bin/rake gitlab:usage_data:dump_sql_in_yaml
+
+# for JSON export
+bin/rake gitlab:usage_data:dump_sql_in_json
+
+# You may pipe the output into a file
+bin/rake gitlab:usage_data:dump_sql_in_yaml > ~/Desktop/usage-metrics-2020-09-02.yaml
+```
diff --git a/doc/development/profiling.md b/doc/development/profiling.md
index f7ead94d725..f5a4d1edb92 100644
--- a/doc/development/profiling.md
+++ b/doc/development/profiling.md
@@ -91,9 +91,6 @@ that builds on this to add some additional niceties, such as allowing
configuration with a single YAML file for multiple URLs, and uploading of the
profile and log output to S3.
-For GitLab.com, you can find the latest results here (restricted to GitLab Team members only):
-`https://redash.gitlab.com/dashboard/gitlab-profiler-statistics`
-
## Sherlock
Sherlock is a custom profiling tool built into GitLab. Sherlock is _only_
diff --git a/doc/development/prometheus.md b/doc/development/prometheus.md
index 902d4e6a1d0..3e7acaf6d94 100644
--- a/doc/development/prometheus.md
+++ b/doc/development/prometheus.md
@@ -1,6 +1,6 @@
---
stage: Monitor
-group: APM
+group: Health
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/#designated-technical-writers
---
@@ -47,3 +47,13 @@ using a Prometheus managed application in Kubernetes:
```
1. Open `localhost:9090` in your browser to display the Prometheus user interface.
+
+## Script access to Prometheus
+
+You can script the access to Prometheus, extracting the name of the pod automatically like this:
+
+```shell
+POD_INFORMATION=$(kubectl get pods -n gitlab-managed-apps | grep 'prometheus-prometheus-server')
+POD_NAME=$(echo $POD_INFORMATION | awk '{print $1;}')
+kubectl port-forward $POD_NAME 9090:9090 -n gitlab-managed-apps
+```
diff --git a/doc/development/prometheus_metrics.md b/doc/development/prometheus_metrics.md
index a39d19d8750..8fcc025b35b 100644
--- a/doc/development/prometheus_metrics.md
+++ b/doc/development/prometheus_metrics.md
@@ -1,6 +1,6 @@
---
stage: Monitor
-group: APM
+group: Health
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/#designated-technical-writers
---
@@ -35,11 +35,6 @@ After you add or change an existing common metric, you must [re-run the import s
Or, you can create a database migration:
-NOTE: **Note:**
-If a query metric (which is identified by `id:`) is removed it will not be removed from database by default.
-You might want to add additional database migration that makes a decision what to do with removed one.
-For example: you might be interested in migrating all dependent data to a different metric.
-
```ruby
class ImportCommonMetrics < ActiveRecord::Migration[4.2]
include Gitlab::Database::MigrationHelpers
@@ -56,6 +51,10 @@ class ImportCommonMetrics < ActiveRecord::Migration[4.2]
end
```
+If a query metric (which is identified by `id:`) is removed it will not be removed from database by default.
+You might want to add additional database migration that makes a decision what to do with removed one.
+For example: you might be interested in migrating all dependent data to a different metric.
+
## GitLab Prometheus metrics
GitLab provides [Prometheus metrics](../administration/monitoring/prometheus/gitlab_metrics.md)
diff --git a/doc/development/reactive_caching.md b/doc/development/reactive_caching.md
index f3386305e93..cf125c46565 100644
--- a/doc/development/reactive_caching.md
+++ b/doc/development/reactive_caching.md
@@ -85,9 +85,7 @@ The ReactiveCaching concern can be used in models as well as `project_services`
1. Implement the `calculate_reactive_cache` method in your model/service.
1. Call `with_reactive_cache` in your model/service where the cached value is needed.
-1. If the `calculate_reactive_cache` method above submits requests to external services
-(e.g. Prometheus, K8s), make sure to change the
-[`reactive_cache_work_type` accordingly](#selfreactive_cache_work_type).
+1. Set the [`reactive_cache_work_type` accordingly](#selfreactive_cache_work_type).
### In controllers
@@ -252,7 +250,7 @@ self.reactive_cache_hard_limit = 5.megabytes
- This is the type of work performed by the `calculate_reactive_cache` method. Based on this attribute,
it's able to pick the right worker to process the caching job. Make sure to
set it as `:external_dependency` if the work performs any external request
-(e.g. Kubernetes, Sentry).
+(e.g. Kubernetes, Sentry); otherwise set it to `:no_dependency`.
#### `self.reactive_cache_worker_finder`
diff --git a/doc/development/redis.md b/doc/development/redis.md
index d205082b9c6..a0ae84beb8d 100644
--- a/doc/development/redis.md
+++ b/doc/development/redis.md
@@ -68,6 +68,10 @@ which is enabled for the `cache` and `shared_state`
## Redis in structured logging
+For GitLab Team Members: There are [basic](https://www.youtube.com/watch?v=Uhdj19Dc6vU) and
+[advanced](https://youtu.be/jw1Wv2IJxzs) videos that show how you can work with the Redis
+structured logging fields on GitLab.com.
+
Our [structured logging](logging.md#use-structured-json-logging) for web
requests and Sidekiq jobs contains fields for the duration, call count,
bytes written, and bytes read per Redis instance, along with a total for
@@ -96,10 +100,14 @@ requests that read the most data from the cache, we can just sort by
### The slow log
+TIP: **Tip:**
+There is a [video showing how to see the slow log](https://youtu.be/BBI68QuYRH8) (GitLab internal)
+on GitLab.com
+
On GitLab.com, entries from the [Redis
slow log](https://redis.io/commands/slowlog) are available in the
`pubsub-redis-inf-gprd*` index with the [`redis.slowlog`
-tag](https://log.gprd.gitlab.net/app/kibana#/discover?_g=(filters:!(),refreshInterval:(pause:!t,value:0),time:(from:now-1d,to:now))&_a=(columns:!(json.type,json.command,json.exec_time),filters:!(('$state':(store:appState),meta:(alias:!n,disabled:!f,index:AWSQX_Vf93rHTYrsexmk,key:json.tag,negate:!f,params:(query:redis.slowlog),type:phrase),query:(match:(json.tag:(query:redis.slowlog,type:phrase))))),index:AWSQX_Vf93rHTYrsexmk)).
+tag](https://log.gprd.gitlab.net/app/kibana#/discover?_g=(filters:!(),refreshInterval:(pause:!t,value:0),time:(from:now-1d,to:now))&_a=(columns:!(json.type,json.command,json.exec_time_s),filters:!(('$state':(store:appState),meta:(alias:!n,disabled:!f,index:AWSQX_Vf93rHTYrsexmk,key:json.tag,negate:!f,params:(query:redis.slowlog),type:phrase),query:(match:(json.tag:(query:redis.slowlog,type:phrase))))),index:AWSQX_Vf93rHTYrsexmk)).
This shows commands that have taken a long time and may be a performance
concern.
@@ -113,7 +121,7 @@ passing to fluentd (and ultimately Elasticsearch).
The [Redis Keyspace
Analyzer](https://gitlab.com/gitlab-com/gl-infra/redis-keyspace-analyzer)
project contains tools for dumping the full key list and memory usage of a Redis
-instance, and then analyzing those lists while elimating potentially sensitive
+instance, and then analyzing those lists while eliminating potentially sensitive
data from the results. It can be used to find the most frequent key patterns, or
those that use the most memory.
diff --git a/doc/development/reference_processing.md b/doc/development/reference_processing.md
index 527fb94f228..cf587043cae 100644
--- a/doc/development/reference_processing.md
+++ b/doc/development/reference_processing.md
@@ -77,6 +77,22 @@ a minimum implementation of `AbstractReferenceFilter` should define:
and an identifier, find the object. For example, this in a reference filter for
merge requests, this might be `project.merge_requests.where(iid: iid)`.
+### Add a new reference prefix and filter
+
+For reference filters for new objects, use a prefix format following the pattern
+`^<object_type>#`, because:
+
+1. Varied single-character prefixes are hard for users to track. Especially for
+ lower-use object types, this can diminish value for the feature.
+1. Suitable single-character prefixes are limited.
+1. Following a consistent pattern allows users to infer the existence of new features.
+
+To add a reference prefix for a new object `apple`,which has both a name and ID,
+format the reference as:
+
+- `^apple#123` for identification by ID.
+- `^apple#"Granny Smith"` for identification by name.
+
### Performance
#### Find object optimization
diff --git a/doc/development/secure_coding_guidelines.md b/doc/development/secure_coding_guidelines.md
index 1961d1dcc34..e35bda82aaa 100644
--- a/doc/development/secure_coding_guidelines.md
+++ b/doc/development/secure_coding_guidelines.md
@@ -1,3 +1,10 @@
+---
+type: reference, dev
+stage: none
+group: Development
+info: "See the Technical Writers assigned to Development Guidelines: https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments-to-development-guidelines"
+---
+
# Secure Coding Guidelines
This document contains descriptions and guidelines for addressing security
@@ -82,7 +89,8 @@ This Ruby Regex specialty can have security impact, as often regular expressions
#### Examples
-GitLab specific examples can be found [here](https://gitlab.com/gitlab-org/gitlab/-/issues/36029#note_251262187) and [there](https://gitlab.com/gitlab-org/gitlab/-/issues/33569).
+GitLab-specific examples can be found in the following [path traversal](https://gitlab.com/gitlab-org/gitlab/-/issues/36029#note_251262187)
+and [open redirect](https://gitlab.com/gitlab-org/gitlab/-/issues/33569) issues.
Another example would be this fictional Ruby on Rails controller:
@@ -392,5 +400,34 @@ In order to prevent Path Traversal vulnerabilities, user-controlled filenames or
#### GitLab specific validations
-- [`Gitlab::Utils.check_path_traversal`](https://gitlab.com/gitlab-org/security/gitlab/-/blob/master/lib/gitlab/utils.rb#L12-24) can be used to validate user input against Path Traversal vulnerabilities. Remember to add further validation when setting the `allowed_absolute` option to `true`.
-- [`file_path` API validator](https://gitlab.com/gitlab-org/security/gitlab/-/blob/master/lib/api/validations/validators/file_path.rb) to validate user input when working with the Grape gem.
+The methods `Gitlab::Utils.check_path_traversal!()` and `Gitlab::Utils.check_allowed_absolute_path!()`
+can be used to validate user-supplied paths and prevent vulnerabilities.
+`check_path_traversal!()` will detect their Path Traversal payloads and accepts URL-encoded paths.
+`check_allowed_absolute_path!()` will check if a path is absolute and whether it is inside the allowed path list. By default, absolute
+paths are not allowed, so you need to pass a list of allowed absolute paths to the `path_allowlist`
+parameter when using `check_allowed_absolute_path!()`.
+
+To use a combination of both checks, follow the example below:
+
+```ruby
+path = Gitlab::Utils.check_path_traversal!(path)
+Gitlab::Utils.check_allowed_absolute_path!(path, path_allowlist)
+```
+
+In the REST API, we have the [`FilePath`](https://gitlab.com/gitlab-org/security/gitlab/-/blob/master/lib/api/validations/validators/file_path.rb)
+validator that can be used to perform the checking on any file path argument the endpoints have.
+It can be used as follows:
+
+```ruby
+requires :file_path, type: String, file_path: { allowlist: ['/foo/bar/', '/home/foo/', '/app/home'] }
+```
+
+The Path Traversal check can also be used to forbid any absolute path:
+
+```ruby
+requires :file_path, type: String, file_path: true
+```
+
+NOTE: **Note:**
+Absolute paths are not allowed by default. If allowing an absolute path is required, you
+need to provide an array of paths to the parameter `allowlist`.
diff --git a/doc/development/shell_scripting_guide/index.md b/doc/development/shell_scripting_guide/index.md
index 622c90d7a97..704b46c7efa 100644
--- a/doc/development/shell_scripting_guide/index.md
+++ b/doc/development/shell_scripting_guide/index.md
@@ -1,7 +1,5 @@
# Shell scripting standards and style guidelines
-## Overview
-
GitLab consists of many various services and sub-projects. The majority of
their backend code is written in [Ruby](https://www.ruby-lang.org) and
[Go](https://golang.org). However, some of them use shell scripts for
@@ -15,7 +13,7 @@ should be eventually harmonized with this guide. If there are any per-project
deviations from this guide, they should be described in the
`README.md` or `PROCESS.md` file for such a project.
-### Avoid using shell scripts
+## Avoid using shell scripts
CAUTION: **Caution:**
This is a must-read section.
diff --git a/doc/development/sidekiq_style_guide.md b/doc/development/sidekiq_style_guide.md
index fdea27f43ca..24570cfc07b 100644
--- a/doc/development/sidekiq_style_guide.md
+++ b/doc/development/sidekiq_style_guide.md
@@ -215,6 +215,85 @@ From the rails console:
Feature.enable!(:disable_authorized_projects_deduplication)
```
+## Limited capacity worker
+
+It is possible to limit the number of concurrent running jobs for a worker class
+by using the `LimitedCapacity::Worker` concern.
+
+The worker must implement three methods:
+
+- `perform_work` - the concern implements the usual `perform` method and calls
+`perform_work` if there is any capacity available.
+- `remaining_work_count` - number of jobs that will have work to perform.
+- `max_running_jobs` - maximum number of jobs allowed to run concurrently.
+
+```ruby
+class MyDummyWorker
+ include ApplicationWorker
+ include LimitedCapacity::Worker
+
+ def perform_work(*args)
+ end
+
+ def remaining_work_count(*args)
+ 5
+ end
+
+ def max_running_jobs
+ 25
+ end
+end
+```
+
+Additional to the regular worker, a cron worker must be defined as well to
+backfill the queue with jobs. the arguments passed to `perform_with_capacity`
+will be passed along to the `perform_work` method.
+
+```ruby
+class ScheduleMyDummyCronWorker
+ include ApplicationWorker
+ include CronjobQueue
+
+ def perform(*args)
+ MyDummyWorker.perform_with_capacity(*args)
+ end
+end
+```
+
+### How many jobs are running?
+
+It will be running `max_running_jobs` at almost all times.
+
+The cron worker will check the remaining capacity on each execution and it
+will schedule at most `max_running_jobs` jobs. Those jobs on completion will
+re-enqueue themselves immediately, but not on failure. The cron worker is in
+charge of replacing those failed jobs.
+
+### Handling errors and idempotence
+
+This concern disables Sidekiq retries, logs the errors, and sends the job to the
+dead queue. This is done to have only one source that produces jobs and because
+the retry would occupy a slot with a job that will be performed in the distant future.
+
+We let the cron worker enqueue new jobs, this could be seen as our retry and
+back off mechanism because the job might fail again if executed immediately.
+This means that for every failed job, we will be running at a lower capacity
+until the cron worker fills the capacity again. If it is important for the
+worker not to get a backlog, exceptions must be handled in `#perform_work` and
+the job should not raise.
+
+The jobs are deduplicated using the `:none` strategy, but the worker is not
+marked as `idempotent!`.
+
+### Metrics
+
+This concern exposes three Prometheus metrics of gauge type with the worker class
+name as label:
+
+- `limited_capacity_worker_running_jobs`
+- `limited_capacity_worker_max_running_jobs`
+- `limited_capacity_worker_remaining_work_count`
+
## Job urgency
Jobs can have an `urgency` attribute set, which can be `:high`,
@@ -617,7 +696,7 @@ during deployment before all Rails and Sidekiq nodes have the updated code.
#### Deprecate and remove an argument
-**Before you remove arguments from the `perform_async` and `perform` methods.**, deprecate them. The
+**Before you remove arguments from the `perform_async` and `perform` methods.**, deprecate them. The
following example deprecates and then removes `arg2` from the `perform_async` method:
1. Provide a default value (usually `nil`) and use a comment to mark the
diff --git a/doc/development/sql.md b/doc/development/sql.md
index 3b969c7d27a..55a8192578b 100644
--- a/doc/development/sql.md
+++ b/doc/development/sql.md
@@ -220,7 +220,7 @@ Project.select(:id, :user_id).joins(:merge_requests)
Never use ActiveRecord's `pluck` to pluck a set of values into memory only to
use them as an argument for another query. For example, this will execute an
-extra unecessary database query and load a lot of unecessary data into memory:
+extra unnecessary database query and load a lot of unnecessary data into memory:
```ruby
projects = Project.all.pluck(:id)
diff --git a/doc/development/swapping_tables.md b/doc/development/swapping_tables.md
index 5c62900dbff..f633721ea9d 100644
--- a/doc/development/swapping_tables.md
+++ b/doc/development/swapping_tables.md
@@ -1,3 +1,9 @@
+---
+stage: Enablement
+group: Database
+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/#designated-technical-writers
+---
+
# Swapping Tables
Sometimes you need to replace one table with another. For example, when
diff --git a/doc/development/telemetry/event_dictionary.md b/doc/development/telemetry/event_dictionary.md
index d8cc32ea8d0..53b7ddea095 100644
--- a/doc/development/telemetry/event_dictionary.md
+++ b/doc/development/telemetry/event_dictionary.md
@@ -1,32 +1,5 @@
---
-stage: Growth
-group: Telemetry
-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/#designated-technical-writers
+redirect_to: '../product_analytics/event_dictionary.md'
---
-# Event Dictionary
-
-**Note: We've temporarily moved the Event Dictionary to a [Google Sheet](https://docs.google.com/spreadsheets/d/1VzE8R72Px_Y_LlE3Z05LxUlG_dumWe3vl-HeUo70TPw/edit?usp=sharing)**. The previous Markdown table exceeded 600 rows making it difficult to manage. In the future, our intention is to move this back into our docs using a [YAML file](https://gitlab.com/gitlab-org/gitlab-docs/-/issues/823).
-
-The event dictionary is a single source of truth for the metrics and events we collect for product usage data. The Event Dictionary lists all the metrics and events we track, why we're tracking them, and where they are tracked.
-
-This is a living document that is updated any time a new event is planned or implemented. It includes the following information.
-
-- Section, stage, or group
-- Description
-- Implementation status
-- Availability by plan type
-- Code path
-
-We're currently focusing our Event Dictionary on [Usage Ping](usage_ping.md). In the future, we will also include [Snowplow](snowplow.md). We currently have an initiative across the entire product organization to complete the [Event Dictionary for Usage Ping](https://gitlab.com/groups/gitlab-org/-/epics/4174).
-
-## Instructions
-
-1. Open the Event Dictionary and fill in all the **PM to edit** columns highlighted in yellow.
-1. Check that all the metrics and events are assigned to the correct section, stage, or group. If a metric is used across many groups, assign it to the stage. If a metric is used across many stages, assign it to the section. If a metric is incorrectly assigned to another section, stage, or group, let the PM know you have reassigned it. If your group has no assigned metrics and events, check that your metrics and events are not incorrectly assigned to another PM.
-1. Add descriptions of what your metrics and events are tracking. Work with your Engineering team or the Telemetry team if you need help understanding this.
-1. Add what plans this metric is available on. Work with your Engineering team or the Telemetry team if you need help understanding this.
-
-## Planned metrics and events
-
-For future metrics and events you plan to track, please add them to the Event Dictionary and note the status as `Planned`, `In Progress`, or `Implemented`. Once you have confirmed the metric has been implemented and have confirmed the metric data is in our data warehouse, change the status to **Data Available**.
+This document was moved to [another location](../product_analytics/event_dictionary.md).
diff --git a/doc/development/telemetry/index.md b/doc/development/telemetry/index.md
index b5032ce3730..79ea80a52ea 100644
--- a/doc/development/telemetry/index.md
+++ b/doc/development/telemetry/index.md
@@ -1,182 +1,5 @@
---
-stage: Growth
-group: Telemetry
-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/#designated-technical-writers
+redirect_to: '../product_analytics/index.md'
---
-# Telemetry Guide
-
-At GitLab, we collect product usage data for the purpose of helping us build a better product. Data helps GitLab understand which parts of the product need improvement and which features we should build next. Product usage data also helps our team better understand the reasons why people use GitLab. With this knowledge we are able to make better product decisions.
-
-We encourage users to enable tracking, and we embrace full transparency with our tracking approach so it can be easily understood and trusted.
-
-By enabling tracking, users can:
-
-- Contribute back to the wider community.
-- Help GitLab improve on the product.
-
-## Our tracking tools
-
-We use three methods to gather product usage data:
-
-- [Snowplow](#snowplow)
-- [Usage Ping](#usage-ping)
-- [Database import](#database-import)
-
-### Snowplow
-
-Snowplow is an enterprise-grade marketing and product analytics platform which helps track the way
-users engage with our website and application.
-
-Snowplow consists of two components:
-
-- [Snowplow JS](https://github.com/snowplow/snowplow/wiki/javascript-tracker) tracks client-side
- events.
-- [Snowplow Ruby](https://github.com/snowplow/snowplow/wiki/ruby-tracker) tracks server-side events.
-
-For more details, read the [Snowplow](snowplow.md) guide.
-
-### Usage Ping
-
-Usage Ping is a method for GitLab Inc to collect usage data on a GitLab instance. Usage Ping is primarily composed of row counts for different tables in the instance’s database. By comparing these counts month over month (or week over week), we can get a rough sense for how an instance is using the different features within the product. This high-level data is used to help our product, support, and sales teams.
-
-For more details, read the [Usage Ping](usage_ping.md) guide.
-
-### Database import
-
-Database imports are full imports of data into GitLab's data warehouse. For GitLab.com, the PostgreSQL database is loaded into Snowflake data warehouse every 6 hours. For more details, see the [data team handbook](https://about.gitlab.com/handbook/business-ops/data-team/platform/#extract-and-load).
-
-## What data can be tracked
-
-Our different tracking tools allows us to track different types of events. The event types and examples of what data can be tracked are outlined below.
-
-The availability of event types and their tracking tools varies by segment. For example, on Self-Managed Users, we only have reporting using Database records via Usage Ping.
-
-| Event Types | SaaS Instance | SaaS Plan | SaaS Group | SaaS Session | SaaS User | SM Instance | SM Plan | SM Group | SM Session | SM User |
-|----------------------------------------|---------------|-----------|------------|--------------|-----------|-------------|---------|----------|------------|---------|
-| Snowplow (JS Pageview events) | ✅ | 📅 | 📅 | ✅ | 📅 | 📅 | 📅 | 📅 | 📅 | 📅 |
-| Snowplow (JS UI events) | ✅ | 📅 | 📅 | ✅ | 📅 | 📅 | 📅 | 📅 | 📅 | 📅 |
-| Snowplow (Ruby Pageview events) | ✅ | 📅 | 📅 | ✅ | 📅 | 📅 | 📅 | 📅 | 📅 | 📅 |
-| Snowplow (Ruby CRUD / API events) | ✅ | 📅 | 📅 | ✅ | 📅 | 📅 | 📅 | 📅 | 📅 | 📅 |
-| Usage Ping (Redis UI counters) | 🔄 | 🔄 | 🔄 | âœ–ï¸ | 🔄 | 🔄 | 🔄 | 🔄 | âœ–ï¸ | 🔄 |
-| Usage Ping (Redis Pageview counters) | 🔄 | 🔄 | 🔄 | âœ–ï¸ | 🔄 | 🔄 | 🔄 | 🔄 | âœ–ï¸ | 🔄 |
-| Usage Ping (Redis CRUD / API counters) | 🔄 | 🔄 | 🔄 | âœ–ï¸ | 🔄 | 🔄 | 🔄 | 🔄 | âœ–ï¸ | 🔄 |
-| Usage Ping (Database counters) | ✅ | 🔄 | 📅 | âœ–ï¸ | ✅ | ✅ | ✅ | ✅ | âœ–ï¸ | ✅ |
-| Usage Ping (Instance settings) | ✅ | 🔄 | 📅 | âœ–ï¸ | ✅ | ✅ | ✅ | ✅ | âœ–ï¸ | ✅ |
-| Usage Ping (Integration settings) | ✅ | 🔄 | 📅 | âœ–ï¸ | ✅ | ✅ | ✅ | ✅ | âœ–ï¸ | ✅ |
-| Database import (Database records) | ✅ | ✅ | ✅ | âœ–ï¸ | ✅ | âœ–ï¸ | âœ–ï¸ | âœ–ï¸ | âœ–ï¸ | âœ–ï¸ |
-
-[Source file](https://docs.google.com/spreadsheets/d/1e8Afo41Ar8x3JxAXJF3nL83UxVZ3hPIyXdt243VnNuE/edit?usp=sharing)
-
-**Legend**
-
-✅ Available, 🔄 In Progress, 📅 Planned, âœ–ï¸ Not Possible
-
-SaaS = GitLab.com. SM = Self-Managed instance
-
-### Pageview events
-
-- Number of sessions that visited the /dashboard/groups page
-
-### UI events
-
-- Number of sessions that clicked on a button or link
-- Number of sessions that closed a modal
-
-UI events are any interface-driven actions from the browser including click data.
-
-### CRUD or API events
-
-- Number of Git pushes
-- Number of GraphQL queries
-- Number of requests to a Rails action or controller
-
-These are backend events that include the creation, read, update, deletion of records, and other events that might be triggered from layers other than those available in the interface.
-
-### Database records
-
-These are raw database records which can be explored using business intelligence tools like Sisense. The full list of available tables can be found in [structure.sql](https://gitlab.com/gitlab-org/gitlab/-/blob/master/db/structure.sql).
-
-### Instance settings
-
-These are settings of your instance such as the instance's Git version and if certain features are enabled such as `container_registry_enabled`.
-
-### Integration settings
-
-These are integrations your GitLab instance interacts with such as an [external storage provider](../../administration/static_objects_external_storage.md) or an [external container registry](../../administration/packages/container_registry.md#use-an-external-container-registry-with-gitlab-as-an-auth-endpoint). These services must be able to send data back into a GitLab instance for data to be tracked.
-
-## Reporting level
-
-Our reporting levels of aggregate or individual reporting varies by segment. For example, on Self-Managed Users, we can report at an aggregate user level using Usage Ping but not on an Individual user level.
-
-| Aggregated Reporting | SaaS Instance | SaaS Plan | SaaS Group | SaaS Session | SaaS User | SM Instance | SM Plan | SM Group | SM Session | SM User |
-|----------------------|---------------|-----------|------------|--------------|-----------|-------------|---------|----------|------------|---------|
-| Snowplow | ✅ | 📅 | 📅 | ✅ | 📅 | ✅ | 📅 | 📅 | ✅ | 📅 |
-| Usage Ping | ✅ | 🔄 | 📅 | 📅 | ✅ | ✅ | ✅ | ✅ | 📅 | ✅ |
-| Database import | ✅ | ✅ | ✅ | âœ–ï¸ | ✅ | âœ–ï¸ | âœ–ï¸ | âœ–ï¸ | âœ–ï¸ | âœ–ï¸ |
-
-| Identifiable Reporting | SaaS Instance | SaaS Plan | SaaS Group | SaaS Session | SaaS User | SM Instance | SM Plan | SM Group | SM Session | SM User |
-|------------------------|---------------|-----------|------------|--------------|-----------|-------------|---------|----------|------------|---------|
-| Snowplow | ✅ | 📅 | 📅 | ✅ | 📅 | âœ–ï¸ | âœ–ï¸ | âœ–ï¸ | âœ–ï¸ | âœ–ï¸ |
-| Usage Ping | ✅ | 🔄 | 📅 | âœ–ï¸ | âœ–ï¸ | ✅ | ✅ | âœ–ï¸ | âœ–ï¸ | âœ–ï¸ |
-| Database import | ✅ | ✅ | ✅ | âœ–ï¸ | ✅ | âœ–ï¸ | âœ–ï¸ | âœ–ï¸ | âœ–ï¸ | âœ–ï¸ |
-
-**Legend**
-
-✅ Available, 🔄 In Progress, 📅 Planned, âœ–ï¸ Not Possible
-
-SaaS = GitLab.com. SM = Self-Managed instance
-
-## Reporting time period
-
-Our reporting time periods varies by segment. For example, on Self-Managed Users, we can report all time counts and 28 day counts in Usage Ping.
-
-| Reporting Time Period | All Time | 28 Days | 7 Days | Daily |
-|-----------------------|----------|---------|--------|-------|
-| Snowplow | ✅ | ✅ | ✅ | ✅ |
-| Usage Ping | ✅ | ✅ | 📅 | âœ–ï¸ |
-| Database import | ✅ | ✅ | ✅ | ✅ |
-
-**Legend**
-
-✅ Available, 🔄 In Progress, 📅 Planned, âœ–ï¸ Not Possible
-
-## Systems overview
-
-The systems overview is a simplified diagram showing the interactions between GitLab Inc and self-managed instances.
-
-![Telemetry_Overview](../img/telemetry_system_overview.png)
-
-[Source file](https://app.diagrams.net/#G13DVpN-XnhWGz9tqReIj8pp1UE4ehk_EC)
-
-### GitLab Inc
-
-For Telemetry purposes, GitLab Inc has three major components:
-
-1. [Data Infrastructure](https://about.gitlab.com/handbook/business-ops/data-team/platform/infrastructure/): This contains everything managed by our data team including Sisense Dashboards for visualization, Snowflake for Data Warehousing, incoming data sources such as PostgreSQL Pipeline and S3 Bucket, and lastly our data collectors [GitLab.com's Snowplow Collector](https://gitlab.com/gitlab-com/gl-infra/readiness/-/tree/master/library/snowplow/) and GitLab's Versions Application.
-1. GitLab.com: This is the production GitLab application which is made up of a Client and Server. On the Client or browser side, a Snowplow JS Tracker (Frontend) is used to track client-side events. On the Server or application side, a Snowplow Ruby Tracker (Backend) is used to track server-side events. The server also contains Usage Ping which leverages a PostgreSQL database and a Redis in-memory data store to report on usage data. Lastly, the server also contains System Logs which are generated from running the GitLab application.
-1. [Monitoring infrastructure](https://about.gitlab.com/handbook/engineering/monitoring/): This is the infrastructure used to ensure GitLab.com is operating smoothly. System Logs are sent from GitLab.com to our monitoring infrastructure and collected by a FluentD collector. From FluentD, logs are either sent to long term Google Cloud Services cold storage via Stackdriver, or, they are sent to our Elastic Cluster via Cloud Pub/Sub which can be explored in real-time using Kibana.
-
-### Self-managed
-
-For Telemetry purposes, self-managed instances have two major components:
-
-1. Data infrastructure: Having a data infrastructure setup is optional on self-managed instances. If you'd like to collect Snowplow tracking events for your self-managed instance, you can setup your own self-managed Snowplow collector and configure your Snowplow events to point to your own collector.
-1. GitLab: A self-managed GitLab instance contains all of the same components as GitLab.com mentioned above.
-
-### Differences between GitLab Inc and Self-managed
-
-As shown by the orange lines, on GitLab.com Snowplow JS, Snowplow Ruby, Usage Ping, and PostgreSQL database imports all flow into GitLab Inc's data infrastructure. However, on self-managed, only Usage Ping flows into GitLab Inc's data infrastructure.
-
-As shown by the green lines, on GitLab.com system logs flow into GitLab Inc's monitoring infrastructure. On self-managed, there are no logs sent to GitLab Inc's monitoring infrastructure.
-
-Note (1): Snowplow JS and Snowplow Ruby are available on self-managed, however, the Snowplow Collector endpoint is set to a self-managed Snowplow Collector which GitLab Inc does not have access to.
-
-## Additional information
-
-More useful links:
-
-- [Telemetry Direction](https://about.gitlab.com/direction/telemetry/)
-- [Data Analysis Process](https://about.gitlab.com/handbook/business-ops/data-team/#data-analysis-process/)
-- [Data for Product Managers](https://about.gitlab.com/handbook/business-ops/data-team/programs/data-for-product-managers/)
-- [Data Infrastructure](https://about.gitlab.com/handbook/business-ops/data-team/platform/infrastructure/)
+This document was moved to [another location](../product_analytics/index.md).
diff --git a/doc/development/telemetry/snowplow.md b/doc/development/telemetry/snowplow.md
index f427d7d1488..fd75d29286b 100644
--- a/doc/development/telemetry/snowplow.md
+++ b/doc/development/telemetry/snowplow.md
@@ -1,410 +1,5 @@
---
-stage: Growth
-group: Telemetry
-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/#designated-technical-writers
+redirect_to: '../product_analytics/snowplow.md'
---
-# Snowplow Guide
-
-This guide provides an overview of how Snowplow works, and implementation details.
-
-For more information about Telemetry, see:
-
-- [Telemetry Guide](index.md)
-- [Usage Ping Guide](usage_ping.md)
-
-More useful links:
-
-- [Telemetry Direction](https://about.gitlab.com/direction/telemetry/)
-- [Data Analysis Process](https://about.gitlab.com/handbook/business-ops/data-team/#data-analysis-process/)
-- [Data for Product Managers](https://about.gitlab.com/handbook/business-ops/data-team/programs/data-for-product-managers/)
-- [Data Infrastructure](https://about.gitlab.com/handbook/business-ops/data-team/platform/infrastructure/)
-
-## What is Snowplow
-
-Snowplow is an enterprise-grade marketing and product analytics platform which helps track the way users engage with our website and application.
-
-[Snowplow](https://github.com/snowplow/snowplow) consists of the following loosely-coupled sub-systems:
-
-- **Trackers** fire Snowplow events. Snowplow has 12 trackers, covering web, mobile, desktop, server, and IoT.
-- **Collectors** receive Snowplow events from trackers. We have three different event collectors, synchronizing events either to Amazon S3, Apache Kafka, or Amazon Kinesis.
-- **Enrich** cleans up the raw Snowplow events, enriches them and puts them into storage. We have an Hadoop-based enrichment process, and a Kinesis-based or Kafka-based process.
-- **Storage** is where the Snowplow events live. We store the Snowplow events in a flat file structure on S3, and in the Redshift and PostgreSQL databases.
-- **Data modeling** is where event-level data is joined with other data sets and aggregated into smaller data sets, and business logic is applied. This produces a clean set of tables which make it easier to perform analysis on the data. We have data models for Redshift and Looker.
-- **Analytics** are performed on the Snowplow events or on the aggregate tables.
-
-![snowplow_flow](../img/snowplow_flow.png)
-
-## Snowplow schema
-
-We have many definitions of Snowplow's schema. We have an active issue to [standardize this schema](https://gitlab.com/gitlab-org/gitlab/-/issues/207930) including the following definitions:
-
-- Frontend and backend taxonomy as listed below
-- [Feature instrumentation taxonomy](https://about.gitlab.com/handbook/business-ops/data-team/programs/data-for-product-managers/#sts=Taxonomy)
-- [Self describing events](https://github.com/snowplow/snowplow/wiki/Custom-events#self-describing-events)
-- [Iglu schema](https://gitlab.com/gitlab-org/iglu/)
-- [Snowplow authored events](https://github.com/snowplow/snowplow/wiki/Snowplow-authored-events)
-
-## Enabling Snowplow
-
-Tracking can be enabled at:
-
-- The instance level, which enables tracking on both the frontend and backend layers.
-- User level, though user tracking can be disabled on a per-user basis. GitLab tracking respects the [Do Not Track](https://www.eff.org/issues/do-not-track) standard, so any user who has enabled the Do Not Track option in their browser is not tracked at a user level.
-
-We utilize Snowplow for the majority of our tracking strategy and it is enabled on GitLab.com. On a self-managed instance, Snowplow can be enabled by navigating to:
-
-- **Admin Area > Settings > Integrations** in the UI.
-- `admin/application_settings/integrations` in your browser.
-
-The following configuration is required:
-
-| Name | Value |
-|---------------|---------------------------|
-| Collector | `snowplow.trx.gitlab.net` |
-| Site ID | `gitlab` |
-| Cookie domain | `.gitlab.com` |
-
-## Snowplow request flow
-
-The following example shows a basic request/response flow between the following components:
-
-- Snowplow JS / Ruby Trackers on GitLab.com
-- [GitLab.com Snowplow Collector](https://gitlab.com/gitlab-com/gl-infra/readiness/-/blob/master/library/snowplow/index.md)
-- GitLab's S3 Bucket
-- GitLab's Snowflake Data Warehouse
-- Sisense:
-
-```mermaid
-sequenceDiagram
- participant Snowplow JS (Frontend)
- participant Snowplow Ruby (Backend)
- participant GitLab.com Snowplow Collector
- participant S3 Bucket
- participant Snowflake DW
- participant Sisense Dashboards
- Snowplow JS (Frontend) ->> GitLab.com Snowplow Collector: FE Tracking event
- Snowplow Ruby (Backend) ->> GitLab.com Snowplow Collector: BE Tracking event
- loop Process using Kinesis Stream
- GitLab.com Snowplow Collector ->> GitLab.com Snowplow Collector: Log raw events
- GitLab.com Snowplow Collector ->> GitLab.com Snowplow Collector: Enrich events
- GitLab.com Snowplow Collector ->> GitLab.com Snowplow Collector: Write to disk
- end
- GitLab.com Snowplow Collector ->> S3 Bucket: Kinesis Firehose
- S3 Bucket->>Snowflake DW: Import data
- Snowflake DW->>Snowflake DW: Transform data using dbt
- Snowflake DW->>Sisense Dashboards: Data available for querying
-```
-
-## Implementing Snowplow JS (Frontend) tracking
-
-GitLab provides `Tracking`, an interface that wraps the [Snowplow JavaScript Tracker](https://github.com/snowplow/snowplow/wiki/javascript-tracker) for tracking custom events. There are a few ways to utilize tracking, but each generally requires at minimum, a `category` and an `action`. Additional data can be provided that adheres to our [Feature instrumentation taxonomy](https://about.gitlab.com/handbook/business-ops/data-team/programs/data-for-product-managers/#sts=Taxonomy).
-
-| field | type | default value | description |
-|:-----------|:-------|:---------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| `category` | string | document.body.dataset.page | Page or subsection of a page that events are being captured within. |
-| `action` | string | 'generic' | Action the user is taking. Clicks should be `click` and activations should be `activate`, so for example, focusing a form field would be `activate_form_input`, and clicking a button would be `click_button`. |
-| `data` | object | {} | Additional data such as `label`, `property`, `value`, and `context` as described [in our Feature Instrumentation taxonomy](https://about.gitlab.com/handbook/business-ops/data-team/programs/data-for-product-managers/#sts=Taxonomy). |
-
-### Tracking in HAML (or Vue Templates)
-
-When working within HAML (or Vue templates) we can add `data-track-*` attributes to elements of interest. All elements that have a `data-track-event` attribute automatically have event tracking bound on clicks.
-
-Below is an example of `data-track-*` attributes assigned to a button:
-
-```haml
-%button.btn{ data: { track: { event: "click_button", label: "template_preview", property: "my-template" } } }
-```
-
-```html
-<button class="btn"
- data-track-event="click_button"
- data-track-label="template_preview"
- data-track-property="my-template"
-/>
-```
-
-Event listeners are bound at the document level to handle click events on or within elements with these data attributes. This allows them to be properly handled on re-rendering and changes to the DOM. Note that because of the way these events are bound, click events should not be stopped from propagating up the DOM tree. If for any reason click events are being stopped from propagating, you need to implement your own listeners and follow the instructions in [Tracking in raw JavaScript](#tracking-in-raw-javascript).
-
-Below is a list of supported `data-track-*` attributes:
-
-| attribute | required | description |
-|:----------------------|:---------|:------------|
-| `data-track-event` | 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 would be `activate_form_input` and clicking a button would be `click_button`. |
-| `data-track-label` | false | The `label` as described [in our Feature Instrumentation taxonomy](https://about.gitlab.com/handbook/business-ops/data-team/programs/data-for-product-managers/#sts=Taxonomy). |
-| `data-track-property` | false | The `property` as described [in our Feature Instrumentation taxonomy](https://about.gitlab.com/handbook/business-ops/data-team/programs/data-for-product-managers/#sts=Taxonomy). |
-| `data-track-value` | false | The `value` as described [in our Feature Instrumentation taxonomy](https://about.gitlab.com/handbook/business-ops/data-team/programs/data-for-product-managers/#sts=Taxonomy). If omitted, this is the element's `value` property or an empty string. For checkboxes, the default value is the element's checked attribute or `false` when unchecked. |
-| `data-track-context` | false | The `context` as described [in our Feature Instrumentation taxonomy](https://about.gitlab.com/handbook/business-ops/data-team/programs/data-for-product-managers/#sts=Taxonomy). |
-
-### Tracking within Vue components
-
-There's a tracking Vue mixin that can be used in components if more complex tracking is required. To use it, first import the `Tracking` library and request a mixin.
-
-```javascript
-import Tracking from '~/tracking';
-const trackingMixin = Tracking.mixin({ label: 'right_sidebar' });
-```
-
-You can provide default options that are passed along whenever an event is tracked from within your component. For instance, if all events within a component should be tracked with a given `label`, you can provide one at this time. Available defaults are `category`, `label`, `property`, and `value`. If no category is specified, `document.body.dataset.page` is used as the default.
-
-You can then use the mixin normally in your component with the `mixin` Vue declaration. The mixin also provides the ability to specify tracking options in `data` or `computed`. These override any defaults and allow the values to be dynamic from props, or based on state.
-
-```javascript
-export default {
- mixins: [trackingMixin],
- // ...[component implementation]...
- data() {
- return {
- expanded: false,
- tracking: {
- label: 'left_sidebar'
- }
- };
- },
-}
-```
-
-The mixin provides a `track` method that can be called within the template, or from component methods. An example of the whole implementation might look like the following.
-
-```javascript
-export default {
- mixins: [Tracking.mixin({ label: 'right_sidebar' })],
- data() {
- return {
- expanded: false,
- };
- },
- methods: {
- toggle() {
- this.expanded = !this.expanded;
- this.track('click_toggle', { value: this.expanded })
- }
- }
-};
-```
-
-And if needed within the template, you can use the `track` method directly as well.
-
-```html
-<template>
- <div>
- <a class="toggle" @click.prevent="toggle">Toggle</a>
- <div v-if="expanded">
- <p>Hello world!</p>
- <a @click.prevent="track('click_action')">Track an event</a>
- </div>
- </div>
-</template>
-```
-
-### Tracking in raw JavaScript
-
-Custom event tracking and instrumentation can be added by directly calling the `Tracking.event` static function. The following example demonstrates tracking a click on a button by calling `Tracking.event` manually.
-
-```javascript
-import Tracking from '~/tracking';
-
-const button = document.getElementById('create_from_template_button');
-button.addEventListener('click', () => {
- Tracking.event('dashboard:projects:index', 'click_button', {
- label: 'create_from_template',
- property: 'template_preview',
- value: 'rails',
- });
-})
-```
-
-### Tests and test helpers
-
-In Jest particularly in Vue tests, you can use the following:
-
-```javascript
-import { mockTracking } from 'helpers/tracking_helper';
-
-describe('MyTracking', () => {
- let spy;
-
- beforeEach(() => {
- spy = mockTracking('_category_', wrapper.element, jest.spyOn);
- });
-
- it('tracks an event when clicked on feedback', () => {
- wrapper.find('.discover-feedback-icon').trigger('click');
-
- expect(spy).toHaveBeenCalledWith('_category_', 'click_button', {
- label: 'security-discover-feedback-cta',
- property: '0',
- });
- });
-});
-```
-
-In obsolete Karma tests it's used as below:
-
-```javascript
-import { mockTracking, triggerEvent } from 'spec/helpers/tracking_helper';
-
-describe('my component', () => {
- let trackingSpy;
-
- beforeEach(() => {
- trackingSpy = mockTracking('_category_', vm.$el, spyOn);
- });
-
- const triggerEvent = () => {
- // action which should trigger a event
- };
-
- it('tracks an event when toggled', () => {
- expect(trackingSpy).not.toHaveBeenCalled();
-
- triggerEvent('a.toggle');
-
- expect(trackingSpy).toHaveBeenCalledWith('_category_', 'click_edit_button', {
- label: 'right_sidebar',
- property: 'confidentiality',
- });
- });
-});
-```
-
-## Implementing Snowplow Ruby (Backend) tracking
-
-GitLab provides `Gitlab::Tracking`, an interface that wraps the [Snowplow Ruby Tracker](https://github.com/snowplow/snowplow/wiki/ruby-tracker) for tracking custom events.
-
-Custom event tracking and instrumentation can be added by directly calling the `GitLab::Tracking.event` class method, which accepts the following arguments:
-
-| argument | type | default value | description |
-|:-----------|:-------|:--------------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| `category` | string | 'application' | Area or aspect of the application. This could be `HealthCheckController` or `Lfs::FileTransformer` for instance. |
-| `action` | string | 'generic' | The action being taken, which can be anything from a controller action like `create` to something like an Active Record callback. |
-| `data` | object | {} | Additional data such as `label`, `property`, `value`, and `context` as described in [Instrumentation at GitLab](https://about.gitlab.com/handbook/business-ops/data-team/programs/data-for-product-managers/#sts=Taxonomy). These are set as empty strings if you don't provide them. |
-
-Tracking can be viewed as either tracking user behavior, or can be utilized for instrumentation to monitor and visualize performance over time in an area or aspect of code.
-
-For example:
-
-```ruby
-class Projects::CreateService < BaseService
- def execute
- project = Project.create(params)
-
- Gitlab::Tracking.event('Projects::CreateService', 'create_project',
- label: project.errors.full_messages.to_sentence,
- value: project.valid?
- )
- end
-end
-```
-
-### Performance
-
-We use the [AsyncEmitter](https://github.com/snowplow/snowplow/wiki/Ruby-Tracker#52-the-asyncemitter-class) when tracking events, which allows for instrumentation calls to be run in a background thread. This is still an active area of development.
-
-## Developing and testing Snowplow
-
-There are several tools for developing and testing Snowplow Event
-
-| Testing Tool | Frontend Tracking | Backend Tracking | Local Development Environment | Production Environment | Production Environment |
-|----------------------------------------------|--------------------|---------------------|-------------------------------|------------------------|------------------------|
-| Snowplow Analytics Debugger Chrome Extension | **{check-circle}** | **{dotted-circle}** | **{check-circle}** | **{check-circle}** | **{check-circle}** |
-| Snowplow Inspector Chrome Extension | **{check-circle}** | **{dotted-circle}** | **{check-circle}** | **{check-circle}** | **{check-circle}** |
-| Snowplow Micro | **{check-circle}** | **{check-circle}** | **{check-circle}** | **{dotted-circle}** | **{dotted-circle}** |
-| Snowplow Mini | **{check-circle}** | **{check-circle}** | **{dotted-circle}** | **{status_preparing}** | **{status_preparing}** |
-
-**Legend**
-
-**{check-circle}** Available, **{status_preparing}** In progress, **{dotted-circle}** Not Planned
-
-### Preparing your MR for Review
-
-1. For frontend events, in the MR description section, add a screenshot of the event's relevant section using the [Snowplow Analytics Debugger](https://chrome.google.com/webstore/detail/snowplow-analytics-debugg/jbnlcgeengmijcghameodeaenefieedm) Chrome browser extension.
-1. For backend events, please use Snowplow Micro and add the output of the Snowplow Micro good events `GET http://localhost:9090/micro/good`.
-
-### Snowplow Analytics Debugger Chrome Extension
-
-Snowplow Analytics Debugger is a browser extension for testing frontend events. This works on production, staging and local development environments.
-
-1. Install the [Snowplow Analytics Debugger](https://chrome.google.com/webstore/detail/snowplow-analytics-debugg/jbnlcgeengmijcghameodeaenefieedm) Chrome browser extension.
-1. Open Chrome DevTools to the Snowplow Analytics Debugger tab.
-1. Learn more at [Igloo Analytics](https://www.iglooanalytics.com/blog/snowplow-analytics-debugger-chrome-extension.html).
-
-### Snowplow Inspector Chrome Extension
-
-Snowplow Inspector Chrome Extension is a browser extension for testing frontend events. This works on production, staging and local development environments.
-
-1. Install [Snowplow Inspector](https://chrome.google.com/webstore/detail/snowplow-inspector/maplkdomeamdlngconidoefjpogkmljm?hl=en).
-1. Open the Chrome extension by pressing the Snowplow Inspector icon beside the address bar.
-1. Click around on a webpage with Snowplow and you should see JavaScript events firing in the inspector window.
-
-### Snowplow Micro
-
-Snowplow Micro is a very small version of a full Snowplow data collection pipeline: small enough that it can be launched by a test suite. Events can be recorded into Snowplow Micro just as they can a full Snowplow pipeline. Micro then exposes an API that can be queried.
-
-Snowplow Micro is a Docker-based solution for testing frontend and backend events in a local development environment. You need to modify GDK using the instructions below to set this up.
-
-- Read [Introducing Snowplow Micro](https://snowplowanalytics.com/blog/2019/07/17/introducing-snowplow-micro/)
-- Look at the [Snowplow Micro repository](https://github.com/snowplow-incubator/snowplow-micro)
-- Watch our [installation guide recording](https://www.youtube.com/watch?v=OX46fo_A0Ag)
-
-1. Install [Snowplow Micro](https://github.com/snowplow-incubator/snowplow-micro):
-
- ```shell
- docker run --mount type=bind,source=$(pwd)/example,destination=/config -p 9090:9090 snowplow/snowplow-micro:latest --collector-config /config/micro.conf --iglu /config/iglu.json
- ```
-
-1. Install snowplow micro by cloning the settings in [this project](https://gitlab.com/a_akgun/snowplow-micro):
-
- ```shell
- git clone git@gitlab.com:a_akgun/snowplow-micro.git
- ./snowplow-micro.sh
- ```
-
-1. Update port in SQL to set `9090`:
-
- ```shell
- gdk psql -d gitlabhq_development
- update application_settings set snowplow_collector_hostname='localhost:9090', snowplow_enabled=true, snowplow_cookie_domain='.gitlab.com';
- ```
-
-1. Update `app/assets/javascripts/tracking.js` to [remove this line](https://gitlab.com/snippets/1918635):
-
- ```javascript
- forceSecureTracker: true
- ```
-
-1. Update `lib/gitlab/tracking.rb` to [add these lines](https://gitlab.com/snippets/1918635):
-
- ```ruby
- protocol: 'http',
- port: 9090,
- ```
-
-1. Update `lib/gitlab/tracking.rb` to [change async emitter from https to http](https://gitlab.com/snippets/1918635):
-
- ```ruby
- SnowplowTracker::AsyncEmitter.new(Gitlab::CurrentSettings.snowplow_collector_hostname, protocol: 'http'),
- ```
-
-1. Enable Snowplow in the admin area, Settings::Integrations::Snowplow to point to:
- `http://localhost:3000/admin/application_settings/integrations#js-snowplow-settings`.
-
-1. Restart GDK:
-
- ```shell
- `gdk restart`
- ```
-
-1. Send a test Snowplow event from the Rails console:
-
- ```ruby
- Gitlab::Tracking.self_describing_event('iglu:com.gitlab/pageview_context/jsonschema/1-0-0', { page_type: 'MY_TYPE' }, context: nil )
- ```
-
-### Snowplow Mini
-
-[Snowplow Mini](https://github.com/snowplow/snowplow-mini) is an easily-deployable, single-instance version of Snowplow.
-
-Snowplow Mini can be used for testing frontend and backend events on a production, staging and local development environment.
-
-For GitLab.com, we're setting up a [QA and Testing environment](https://gitlab.com/gitlab-org/telemetry/-/issues/266) using Snowplow Mini.
+This document was moved to [another location](../product_analytics/snowplow.md).
diff --git a/doc/development/telemetry/usage_ping.md b/doc/development/telemetry/usage_ping.md
index ff4e7e0797b..1026e7a5a66 100644
--- a/doc/development/telemetry/usage_ping.md
+++ b/doc/development/telemetry/usage_ping.md
@@ -1,887 +1,5 @@
---
-stage: Growth
-group: Telemetry
-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/#designated-technical-writers
+redirect_to: '../product_analytics/usage_ping.md'
---
-# Usage Ping Guide
-
-> - Introduced in GitLab Enterprise Edition 8.10.
-> - More statistics were added in GitLab Enterprise Edition 8.12.
-> - Moved to GitLab Core in 9.1.
-> - More statistics were added in GitLab Ultimate 11.2.
-
-This guide describes Usage Ping's purpose and how it's implemented.
-
-For more information about Telemetry, see:
-
-- [Telemetry Guide](index.md)
-- [Snowplow Guide](snowplow.md)
-
-More useful links:
-
-- [Telemetry Direction](https://about.gitlab.com/direction/telemetry/)
-- [Data Analysis Process](https://about.gitlab.com/handbook/business-ops/data-team/#data-analysis-process/)
-- [Data for Product Managers](https://about.gitlab.com/handbook/business-ops/data-team/programs/data-for-product-managers/)
-- [Data Infrastructure](https://about.gitlab.com/handbook/business-ops/data-team/platform/infrastructure/)
-
-## What is Usage Ping?
-
-- GitLab sends a weekly payload containing usage data to GitLab Inc. Usage Ping provides high-level data to help our product, support, and sales teams. It does not send any project names, usernames, or any other specific data. The information from the usage ping is not anonymous, it is linked to the hostname of the instance. Sending usage ping is optional, and any instance can disable analytics.
-- The usage data is primarily composed of row counts for different tables in the instance’s database. By comparing these counts month over month (or week over week), we can get a rough sense for how an instance is using the different features within the product. In addition to counts, other facts
- that help us classify and understand GitLab installations are collected.
-- Usage ping is important to GitLab as we use it to calculate our Stage Monthly Active Users (SMAU) which helps us measure the success of our stages and features.
-- Once usage ping is enabled, GitLab will gather data from the other instances and will be able to show usage statistics of your instance to your users.
-
-### Why should we enable Usage Ping?
-
-- The main purpose of Usage Ping is to build a better GitLab. Data about how GitLab is used is collected to better understand feature/stage adoption and usage, which helps us understand how GitLab is adding value and helps our team better understand the reasons why people use GitLab and with this knowledge we're able to make better product decisions.
-- As a benefit of having the usage ping active, GitLab lets you analyze the users’ activities over time of your GitLab installation.
-- As a benefit of having the usage ping active, GitLab provides you with The DevOps Report,which gives you an overview of your entire instance’s adoption of Concurrent DevOps from planning to monitoring.
-- You will get better, more proactive support. (assuming that our TAMs and support organization used the data to deliver more value)
-- You will get insight and advice into how to get the most value out of your investment in GitLab. Wouldn't you want to know that a number of features or values are not being adopted in your organization?
-- You get a report that illustrates how you compare against other similar organizations (anonymized), with specific advice and recommendations on how to improve your DevOps processes.
-- Usage Ping is enabled by default. To disable it, see [Disable Usage Ping](#disable-usage-ping).
-
-### Limitations
-
-- Usage Ping does not track frontend events things like page views, link clicks, or user sessions, and only focuses on aggregated backend events.
-- Because of these limitations we recommend instrumenting your products with Snowplow for more detailed analytics on GitLab.com and use Usage Ping to track aggregated backend events on self-managed.
-
-## Usage Ping payload
-
-You can view the exact JSON payload sent to GitLab Inc. in the administration panel. To view the payload:
-
-1. Navigate to **Admin Area > Settings > Metrics and profiling**.
-1. Expand the **Usage statistics** section.
-1. Click the **Preview payload** button.
-
-For an example payload, see [Example Usage Ping payload](#example-usage-ping-payload).
-
-## Disable Usage Ping
-
-To disable Usage Ping in the GitLab UI, go to the **Settings** page of your administration panel and uncheck the **Usage Ping** checkbox.
-
-To disable Usage Ping and prevent it from being configured in the future through the administration panel, Omnibus installs can set the following in [`gitlab.rb`](https://docs.gitlab.com/omnibus/settings/configuration.html#configuration-options):
-
-```ruby
-gitlab_rails['usage_ping_enabled'] = false
-```
-
-Source installations can set the following in `gitlab.yml`:
-
-```yaml
-production: &base
- # ...
- gitlab:
- # ...
- usage_ping_enabled: false
-```
-
-## Usage Ping request flow
-
-The following example shows a basic request/response flow between a GitLab instance, the Versions Application, the License Application, Salesforce, GitLab's S3 Bucket, GitLab's Snowflake Data Warehouse, and Sisense:
-
-```mermaid
-sequenceDiagram
- participant GitLab Instance
- participant Versions Application
- participant Licenses Application
- participant Salesforce
- participant S3 Bucket
- participant Snowflake DW
- participant Sisense Dashboards
- GitLab Instance->>Versions Application: Send Usage Ping
- loop Process usage data
- Versions Application->>Versions Application: Parse usage data
- Versions Application->>Versions Application: Write to database
- Versions Application->>Versions Application: Update license ping time
- end
- loop Process data for Salesforce
- Versions Application-xLicenses Application: Request Zuora subscription id
- Licenses Application-xVersions Application: Zuora subscription id
- Versions Application-xSalesforce: Request Zuora account id by Zuora subscription id
- Salesforce-xVersions Application: Zuora account id
- Versions Application-xSalesforce: Usage data for the Zuora account
- end
- Versions Application->>S3 Bucket: Export Versions database
- S3 Bucket->>Snowflake DW: Import data
- Snowflake DW->>Snowflake DW: Transform data using dbt
- Snowflake DW->>Sisense Dashboards: Data available for querying
- Versions Application->>GitLab Instance: DevOps Report (Conversational Development Index)
-```
-
-## How Usage Ping works
-
-1. The Usage Ping [cron job](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/workers/gitlab_usage_ping_worker.rb#L30) is set in Sidekiq to run weekly.
-1. When the cron job runs, it calls [`GitLab::UsageData.to_json`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/services/submit_usage_ping_service.rb#L22).
-1. `GitLab::UsageData.to_json` [cascades down](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/usage_data.rb#L22) to ~400+ other counter method calls.
-1. The response of all methods calls are [merged together](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/usage_data.rb#L14) into a single JSON payload in `GitLab::UsageData.to_json`.
-1. The JSON payload is then [posted to the Versions application]( https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/services/submit_usage_ping_service.rb#L20).
-
-## Implementing Usage Ping
-
-Usage Ping consists of two kinds of data, counters and observations. Counters track how often a certain event
-happened over time, such as how many CI pipelines have run. They are monotonic and always trend up.
-Observations are facts collected from one or more GitLab instances and can carry arbitrary data. There are no
-general guidelines around how to collect those, due to the individual nature of that data.
-
-There are four types of counters which are all found in `usage_data.rb`:
-
-- **Ordinary Batch Counters:** Simple count of a given ActiveRecord_Relation
-- **Distinct Batch Counters:** Distinct count of a given ActiveRecord_Relation on given column
-- **Alternative Counters:** Used for settings and configurations
-- **Redis Counters:** Used for in-memory counts.
-
-NOTE: **Note:**
-Only use the provided counter methods. Each counter method contains a built in fail safe to isolate each counter to avoid breaking the entire Usage Ping.
-
-### Why batch counting
-
-For large tables, PostgreSQL can take a long time to count rows due to MVCC [(Multi-version Concurrency Control)](https://en.wikipedia.org/wiki/Multiversion_concurrency_control). Batch counting is a counting method where a single large query is broken into multiple smaller queries. For example, instead of a single query querying 1,000,000 records, with batch counting, you can execute 100 queries of 10,000 records each. Batch counting is useful for avoiding database timeouts as each batch query is significantly shorter than one single long running query.
-
-For GitLab.com, there are extremely large tables with 15 second query timeouts, so we use batch counting to avoid encountering timeouts. Here are the sizes of some GitLab.com tables:
-
-| Table | Row counts in millions |
-|------------------------------|------------------------|
-| `merge_request_diff_commits` | 2280 |
-| `ci_build_trace_sections` | 1764 |
-| `merge_request_diff_files` | 1082 |
-| `events` | 514 |
-
-There are two batch counting methods provided, `Ordinary Batch Counters` and `Distinct Batch Counters`. Batch counting requires indexes on columns to calculate max, min, and range queries. In some cases, a specialized index may need to be added on the columns involved in a counter.
-
-### Ordinary Batch Counters
-
-Handles `ActiveRecord::StatementInvalid` error
-
-Simple count of a given ActiveRecord_Relation, does a non-distinct batch count, smartly reduces batch_size and handles errors.
-
-Method: `count(relation, column = nil, batch: true, start: nil, finish: nil)`
-
-Arguments:
-
-- `relation` the ActiveRecord_Relation to perform the count
-- `column` the column to perform the count on, by default is the primary key
-- `batch`: default `true` in order to use batch counting
-- `start`: custom start of the batch counting in order to avoid complex min calculations
-- `end`: custom end of the batch counting in order to avoid complex min calculations
-
-Examples:
-
-```ruby
-count(User.active)
-count(::Clusters::Cluster.aws_installed.enabled, :cluster_id)
-count(::Clusters::Cluster.aws_installed.enabled, :cluster_id, start: ::Clusters::Cluster.minimum(:id), finish: ::Clusters::Cluster.maximum(:id))
-```
-
-### Distinct Batch Counters
-
-Handles `ActiveRecord::StatementInvalid` error
-
-Distinct count of a given ActiveRecord_Relation on given column, a distinct batch count, smartly reduces batch_size and handles errors.
-
-Method: `distinct_count(relation, column = nil, batch: true, batch_size: nil, start: nil, finish: nil)`
-
-Arguments:
-
-- `relation` the ActiveRecord_Relation to perform the count
-- `column` the column to perform the distinct count, by default is the primary key
-- `batch`: default `true` in order to use batch counting
-- `batch_size`: if none set it will use default value 10000 from `Gitlab::Database::BatchCounter`
-- `start`: custom start of the batch counting in order to avoid complex min calculations
-- `end`: custom end of the batch counting in order to avoid complex min calculations
-
-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')
-```
-
-### Redis Counters
-
-Handles `::Redis::CommandError` and `Gitlab::UsageDataCounters::BaseCounter::UnknownEvent`
-returns -1 when a block is sent or hash with all values -1 when a `counter(Gitlab::UsageDataCounters)` is sent
-different behavior due to 2 different implementations of Redis counter
-
-Method: `redis_usage_data(counter, &block)`
-
-Arguments:
-
-- `counter`: a counter from `Gitlab::UsageDataCounters`, that has `fallback_totals` method implemented
-- or a `block`: which is evaluated
-
-#### Ordinary Redis Counters
-
-Examples of implementation:
-
-- Using Redis methods [`INCR`](https://redis.io/commands/incr), [`GET`](https://redis.io/commands/get), and [`Gitlab::UsageDataCounters::WikiPageCounter`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/usage_data_counters/wiki_page_counter.rb)
-- Using Redis methods [`HINCRBY`](https://redis.io/commands/hincrby), [`HGETALL`](https://redis.io/commands/hgetall), and [`Gitlab::UsageCounters::PodLogs`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/usage_counters/pod_logs.rb)
-
-#### Redis HLL Counters
-
-With `Gitlab::UsageDataCounters::HLLRedisCounter` we have available data structures used to count unique values.
-
-Implemented using Redis methods [PFADD](https://redis.io/commands/pfadd) and [PFCOUNT](https://redis.io/commands/pfcount).
-
-##### Adding new events
-
-1. Define events in [`known_events.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/usage_data_counters/known_events.yml).
-
- Example event:
-
- ```yaml
- - name: i_compliance_credential_inventory
- category: compliance
- redis_slot: compliance
- expiry: 42 # 6 weeks
- aggregation: weekly
- ```
-
- Keys:
-
- - `name`: unique event name.
-
- Name format `<prefix>_<redis_slot>_name`.
-
- Use one of the following prefixes for the event's name:
-
- - `g_` for group, as an event which is tracked for group.
- - `p_` for project, as an event which is tracked for project.
- - `i_` for instance, as an event which is tracked for instance.
- - `a_` for events encompassing all `g_`, `p_`, `i_`.
- - `o_` for other.
-
- Consider including in the event's name the Redis slot in order to be able to count totals for a specific category.
-
- Example names: `i_compliance_credential_inventory`, `g_analytics_contribution`.
-
- - `category`: event category. Used for getting total counts for events in a category, for easier
- access to a group of events.
- - `redis_slot`: optional Redis slot; default value: event name. Used if needed to calculate totals
- for a group of metrics. Ensure keys are in the same slot. For example:
- `i_compliance_credential_inventory` with `redis_slot: 'compliance'` will build Redis key
- `i_{compliance}_credential_inventory-2020-34`. If `redis_slot` is not defined the Redis key will
- be `{i_compliance_credential_inventory}-2020-34`.
- - `expiry`: expiry time in days. Default: 29 days for daily aggregation and 6 weeks for weekly
- aggregation.
- - `aggregation`: aggregation `:daily` or `:weekly`. The argument defines how we build the Redis
- keys for data storage. For `daily` we keep a key for metric per day of the year, for `weekly` we
- keep a key for metric per week of the year.
-
-1. Track event in controller using `RedisTracking` module with `track_redis_hll_event(*controller_actions, name:, feature:, feature_default_enabled: false)`.
-
- Arguments:
-
- - `controller_actions`: controller actions we want to track.
- - `name`: event name.
- - `feature`: feature name, all metrics we track should be under feature flag.
- - `feature_default_enabled`: feature flag is disabled by default, set to `true` for it to be enabled by default.
-
- Example usage:
-
- ```ruby
- # controller
- class ProjectsController < Projects::ApplicationController
- include RedisTracking
-
- skip_before_action :authenticate_user!, only: :show
- track_redis_hll_event :index, :show, name: 'i_analytics_dev_ops_score', feature: :g_compliance_dashboard_feature, feature_default_enabled: true
-
- def index
- render html: 'index'
- end
-
- def new
- render html: 'new'
- end
-
- def show
- render html: 'show'
- end
- end
- ```
-
-1. Track event in API using `increment_unique_values(event_name, values)` helper method.
-
- In order to be able to track the event, Usage Ping must be enabled and the event feature `usage_data_<event_name>` must be enabled.
-
- Arguments:
-
- - `event_name`: event name.
- - `values`: values counted, one value or array of values.
-
- Example usage:
-
- ```ruby
- get ':id/registry/repositories' do
- repositories = ContainerRepositoriesFinder.new(
- user: current_user, subject: user_group
- ).execute
-
- increment_unique_values('i_list_repositories', current_user.id)
-
- present paginate(repositories), with: Entities::ContainerRegistry::Repository, tags: params[:tags], tags_count: params[:tags_count]
- end
- ```
-
-1. Track event using `track_usage_event(event_name, values) in services and graphql
-
- Increment unique values count using Redis HLL, for given event name.
-
- Example:
-
- [Track usage event for incident created in service](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/services/issues/update_service.rb)
-
- [Track usage event for incident created in graphql](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/graphql/mutations/alert_management/update_alert_status.rb)
-
- ```ruby
- track_usage_event(:incident_management_incident_created, current_user.id)
- ```
-
-1. Track event using `UsageData` API
-
- Increment unique users count using Redis HLL, for given event name.
-
- Tracking events using the `UsageData` API requires the `usage_data_api` feature flag to be enabled, which is disabled by default.
-
- API requests are protected by checking for a valid CSRF token.
-
- In order to be able to increment the values the related feature `usage_data<event_name>` should be enabled.
-
- ```plaintext
- POST /usage_data/increment_unique_users
- ```
-
- | Attribute | Type | Required | Description |
- | :-------- | :--- | :------- | :---------- |
- | `event` | string | yes | The event name it should be tracked |
-
- Response
-
- Return 200 if tracking failed for any reason.
-
- - `200` if event was tracked or any errors
- - `400 Bad request` if event parameter is missing
- - `401 Unauthorized` if user is not authenticated
- - `403 Forbidden` for invalid CSRF token provided
-
-1. Track event using base module `Gitlab::UsageDataCounters::HLLRedisCounter.track_event(entity_id, event_name)`.
-
- Arguments:
-
- - `entity_id`: value we count. For example: user_id, visitor_id.
- - `event_name`: event name.
-
-1. Get event data using `Gitlab::UsageDataCounters::HLLRedisCounter.unique_events(event_names:, start_date:, end_date)`.
-
- Arguments:
-
- - `event_names`: the list of event names.
- - `start_date`: start date of the period for which we want to get event data.
- - `end_date`: end date of the period for which we want to get event data.
-
-Recommendations:
-
-- Key should expire in 29 days for daily and 42 days for weekly.
-- If possible, data granularity should be a week. For example a key could be composed from the
- metric's name and week of the year, `2020-33-{metric_name}`.
-- Use a [feature flag](../../operations/feature_flags.md) to have a control over the impact when
- adding new metrics.
-
-##### Known events in usage data payload
-
-All events added in [`known_events.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/usage_data_counters/known_events.yml) are automatically added to usage data generation under the `redis_hll_counters` key. This column is stored in [version-app as a JSON](https://gitlab.com/gitlab-services/version-gitlab-com/-/blob/master/db/schema.rb#L209).
-For each event we add metrics for the weekly and monthly time frames, and totals for each where applicable:
-
-- `#{event_name}_weekly` data for 7 days for daily [aggregation](#adding-new-events) events and data for last complete week for weekly [aggregation](#adding-new-events) events.
-- `#{event_name}_monthly` data for 28 days for daily [aggregation](#adding-new-events) events and data for last 4 complete weeks for weekly [aggregation](#adding-new-events) events.
-- `#{category}_total_unique_counts_weekly` total unique counts for events in same category for last 7 days or last complete week, if events are in the same Redis slot and if we have more than one metric.
-- `#{event_name}_weekly` - Data for 7 days for daily [aggregation](#adding-new-events) events and data for the last complete week for weekly [aggregation](#adding-new-events) events.
-- `#{event_name}_monthly` - Data for 28 days for daily [aggregation](#adding-new-events) events and data for the last 4 complete weeks for weekly [aggregation](#adding-new-events) events.
-- `#{category}_total_unique_counts_weekly` - Total unique counts for events in the same category for the last 7 days or the last complete week, if events are in the same Redis slot and we have more than one metric.
-- `#{event_name}_weekly`: Data for 7 days for daily [aggregation](#adding-new-events) events and data for last complete week for weekly [aggregation](#adding-new-events) events.
-- `#{event_name}_monthly`: Data for 28 days for daily [aggregation](#adding-new-events) events and data for last 4 complete weeks for weekly [aggregation](#adding-new-events) events.
-- `#{category}_total_unique_counts_weekly` total unique counts for events in same category for last 7 days or last complete week, if events are in the same Redis slot and if we have more than one metric.
-- `#{event_name}_weekly`: Data for 7 days for daily [aggregation](#adding-new-events) events and data for the last complete week for weekly [aggregation](#adding-new-events) events.
-- `#{event_name}_monthly`: Data for 28 days for daily [aggregation](#adding-new-events) events and data for the last 4 complete weeks for weekly [aggregation](#adding-new-events) events.
-- `#{category}_total_unique_counts_weekly`: Total unique counts for events in the same category for the last 7 days or the last complete week, if events are in the same Redis slot and we have more than one metric.
-- `#{category}_total_unique_counts_monthly`: Total unique counts for events in same category for the last 28 days or the last 4 complete weeks, if events are in the same Redis slot and we have more than one metric.
-
-Example of `redis_hll_counters` data:
-
-```ruby
-{:redis_hll_counters=>
- {"compliance"=>
- {"g_compliance_dashboard_weekly"=>0,
- "g_compliance_dashboard_monthly"=>0,
- "g_compliance_audit_events_weekly"=>0,
- "g_compliance_audit_events_monthly"=>0,
- "compliance_total_unique_counts_weekly"=>0,
- "compliance_total_unique_counts_monthly"=>0},
- "analytics"=>
- {"g_analytics_contribution_weekly"=>0,
- "g_analytics_contribution_monthly"=>0,
- "g_analytics_insights_weekly"=>0,
- "g_analytics_insights_monthly"=>0,
- "analytics_total_unique_counts_weekly"=>0,
- "analytics_total_unique_counts_monthly"=>0},
- "ide_edit"=>
- {"g_edit_by_web_ide_weekly"=>0,
- "g_edit_by_web_ide_monthly"=>0,
- "g_edit_by_sfe_weekly"=>0,
- "g_edit_by_sfe_monthly"=>0,
- "ide_edit_total_unique_counts_weekly"=>0,
- "ide_edit_total_unique_counts_monthly"=>0},
- "search"=>
- {"i_search_total_weekly"=>0, "i_search_total_monthly"=>0, "i_search_advanced_weekly"=>0, "i_search_advanced_monthly"=>0, "i_search_paid_weekly"=>0, "i_search_paid_monthly"=>0, "search_total_unique_counts_weekly"=>0, "search_total_unique_counts_monthly"=>0},
- "source_code"=>{"wiki_action_weekly"=>0, "wiki_action_monthly"=>0}
- }
-```
-
-Example usage:
-
-```ruby
-# Redis Counters
-redis_usage_data(Gitlab::UsageDataCounters::WikiPageCounter)
-redis_usage_data { ::Gitlab::UsageCounters::PodLogs.usage_totals[:total] }
-
-# Define events in known_events.yml https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/usage_data_counters/known_events.yml
-
-# Tracking events
-Gitlab::UsageDataCounters::HLLRedisCounter.track_event(visitor_id, 'expand_vulnerabilities')
-
-# Get unique events for metric
-redis_usage_data { Gitlab::UsageDataCounters::HLLRedisCounter.unique_events(event_names: 'expand_vulnerabilities', start_date: 28.days.ago, end_date: Date.current) }
-```
-
-### Alternative Counters
-
-Handles `StandardError` and fallbacks into -1 this way not all measures fail if we encounter one exception.
-Mainly used for settings and configurations.
-
-Method: `alt_usage_data(value = nil, fallback: -1, &block)`
-
-Arguments:
-
-- `value`: a simple static value in which case the value is simply returned.
-- or a `block`: which is evaluated
-- `fallback: -1`: the common value used for any metrics that are failing.
-
-Example of usage:
-
-```ruby
-alt_usage_data { Gitlab::VERSION }
-alt_usage_data { Gitlab::CurrentSettings.uuid }
-alt_usage_data(999)
-```
-
-### Prometheus Queries
-
-In those cases where operational metrics should be part of Usage Ping, a database or Redis query is unlikely
-to provide useful data. Instead, Prometheus might be more appropriate, since most of GitLab's architectural
-components publish metrics to it that can be queried back, aggregated, and included as usage data.
-
-NOTE: **Note:**
-Prometheus as a data source for Usage Ping is currently only available for single-node Omnibus installations
-that are running the [bundled Prometheus](../../administration/monitoring/prometheus/index.md) instance.
-
-In order to query Prometheus for metrics, a helper method is available that will `yield` a fully configured
-`PrometheusClient`, given it is available as per the note above:
-
-```ruby
-with_prometheus_client do |client|
- response = client.query('<your query>')
- ...
-end
-```
-
-Please refer to [the `PrometheusClient` definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/prometheus_client.rb)
-for how to use its API to query for data.
-
-## Developing and testing Usage Ping
-
-### 1. Use your Rails console to manually test counters
-
-```ruby
-# count
-Gitlab::UsageData.count(User.active)
-Gitlab::UsageData.count(::Clusters::Cluster.aws_installed.enabled, :cluster_id)
-
-# count distinct
-Gitlab::UsageData.distinct_count(::Project, :creator_id)
-Gitlab::UsageData.distinct_count(::Note.with_suggestions.where(time_period), :author_id, start: ::User.minimum(:id), finish: ::User.maximum(:id))
-```
-
-### 2. Generate the SQL query
-
-Your Rails console will return the generated SQL queries.
-
-Example:
-
-```ruby
-pry(main)> Gitlab::UsageData.count(User.active)
- (2.6ms) SELECT "features"."key" FROM "features"
- (15.3ms) SELECT MIN("users"."id") FROM "users" WHERE ("users"."state" IN ('active')) AND ("users"."user_type" IS NULL OR "users"."user_type" IN (6, 4))
- (2.4ms) SELECT MAX("users"."id") FROM "users" WHERE ("users"."state" IN ('active')) AND ("users"."user_type" IS NULL OR "users"."user_type" IN (6, 4))
- (1.9ms) SELECT COUNT("users"."id") FROM "users" WHERE ("users"."state" IN ('active')) AND ("users"."user_type" IS NULL OR "users"."user_type" IN (6, 4)) AND "users"."id" BETWEEN 1 AND 100000
-```
-
-### 3. Optimize queries with #database-lab
-
-Paste the SQL query into `#database-lab` to see how the query performs at scale.
-
-- `#database-lab` is a Slack channel which uses a production-sized environment to test your queries.
-- GitLab.com’s production database has a 15 second timeout.
-- Any single query must stay below 1 second execution time with cold caches.
-- Add a specialized index on columns involved to reduce the execution time.
-
-In order to have an understanding of the query's execution we add in the MR description the following information:
-
-- For counters that have a `time_period` test we add information for both cases:
- - `time_period = {}` for all time periods
- - `time_period = { created_at: 28.days.ago..Time.current }` for last 28 days period
-- Execution plan and query time before and after optimization
-- Query generated for the index and time
-- Migration output for up and down execution
-
-We also use `#database-lab` and [explain.depesz.com](https://explain.depesz.com/). For more details, see the [database review guide](../database_review.md#preparation-when-adding-or-modifying-queries).
-
-#### Optimization recommendations and examples
-
-- Use specialized indexes [example 1](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/26871), [example 2](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/26445).
-- Use defined `start` and `finish`, and simple queries, because these values can be memoized and reused, [example](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/37155).
-- Avoid joins and write the queries as simply as possible, [example](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/36316).
-- Set a custom `batch_size` for `distinct_count`, [example](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/38000).
-
-### 4. Add the metric definition
-
-When adding, changing, or updating metrics, please update the [Event Dictionary's **Usage Ping** table](event_dictionary.md).
-
-### 5. Add new metric to Versions Application
-
-Check if new metrics need to be added to the Versions Application. See `usage_data` [schema](https://gitlab.com/gitlab-services/version-gitlab-com/-/blob/master/db/schema.rb#L147) and usage data [parameters accepted](https://gitlab.com/gitlab-services/version-gitlab-com/-/blob/master/app/services/usage_ping.rb). Any metrics added under the `counts` key are saved in the `counts` column.
-
-### 6. Add the feature label
-
-Add the `feature` label to the Merge Request for new Usage Ping metrics. These are user-facing changes and are part of expanding the Usage Ping feature.
-
-### 7. Add a changelog file
-
-Ensure you comply with the [Changelog entries guide](../changelog.md).
-
-### 8. Ask for a Telemetry Review
-
-On GitLab.com, we have DangerBot setup to monitor Telemetry related files and DangerBot will recommend a Telemetry review. Mention `@gitlab-org/growth/telemetry/engineers` in your MR for a review.
-
-### 9. Verify your metric
-
-On GitLab.com, the Product Analytics team regularly monitors Usage Ping. They may alert you that your metrics need further optimization to run quicker and with greater success. You may also use the [Usage Ping QA dashboard](https://app.periscopedata.com/app/gitlab/632033/Usage-Ping-QA) to check how well your metric performs. The dashboard allows filtering by GitLab version, by "Self-managed" & "Saas" and shows you how many failures have occurred for each metric. Whenever you notice a high failure rate, you may re-optimize your metric.
-
-### Optional: Test Prometheus based Usage Ping
-
-If the data submitted includes metrics [queried from Prometheus](#prometheus-queries) that you would like to inspect and verify,
-then you need to ensure that a Prometheus server is running locally, and that furthermore the respective GitLab components
-are exporting metrics to it. If you do not need to test data coming from Prometheus, no further action
-is necessary, since Usage Ping should degrade gracefully in the absence of a running Prometheus server.
-
-There are currently three kinds of components that may export data to Prometheus, and which are included in Usage Ping:
-
-- [`node_exporter`](https://github.com/prometheus/node_exporter) - Exports node metrics from the host machine
-- [`gitlab-exporter`](https://gitlab.com/gitlab-org/gitlab-exporter) - Exports process metrics from various GitLab components
-- various GitLab services such as Sidekiq and the Rails server that export their own metrics
-
-#### Test with an Omnibus container
-
-This is the recommended approach to test Prometheus based Usage Ping.
-
-The easiest way to verify your changes is to build a new Omnibus image from your code branch via CI, then download the image
-and run a local container instance:
-
-1. From your merge request, click on the `qa` stage, then trigger the `package-and-qa` job. This job will trigger an Omnibus
-build in a [downstream pipeline of the `omnibus-gitlab-mirror` project](https://gitlab.com/gitlab-org/build/omnibus-gitlab-mirror/-/pipelines).
-1. In the downstream pipeline, wait for the `gitlab-docker` job to finish.
-1. Open the job logs and locate the full container name including the version. It will take the following form: `registry.gitlab.com/gitlab-org/build/omnibus-gitlab-mirror/gitlab-ee:<VERSION>`.
-1. On your local machine, make sure you are logged in to the GitLab Docker registry. You can find the instructions for this in
-[Authenticating to the GitLab Container Registry](../../user/packages/container_registry/index.md#authenticating-to-the-gitlab-container-registry).
-1. Once logged in, download the new image via `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, please refer to [GitLab Docker images](https://docs.gitlab.com/omnibus/docker/README.html) in the Omnibus documentation.
-
-#### Test with GitLab development toolkits
-
-This is the less recommended approach, since it comes with a number of difficulties when emulating a real GitLab deployment.
-
-The [GDK](https://gitlab.com/gitlab-org/gitlab-development-kit) is not currently set up to run a Prometheus server or `node_exporter` alongside other GitLab components. If you would
-like to do so, [Monitoring the GDK with Prometheus](https://gitlab.com/gitlab-org/gitlab-development-kit/-/blob/master/doc/howto/prometheus/index.md#monitoring-the-gdk-with-prometheus) is a good start.
-
-The [GCK](https://gitlab.com/gitlab-org/gitlab-compose-kit) has limited support for testing Prometheus based Usage Ping.
-By default, it already comes with a fully configured Prometheus service that is set up to scrape a number of components,
-but with the following limitations:
-
-- It does not currently run a `gitlab-exporter` instance, so several `process_*` metrics from services such as Gitaly may be missing.
-- While it runs a `node_exporter`, `docker-compose` services emulate hosts, meaning that it would normally report itself to not be associated
-with any of the other services that are running. That is not how node metrics are reported in a production setup, where `node_exporter`
-always runs as a process alongside other GitLab components on any given node. From Usage Ping's perspective none of the node data would therefore
-appear to be associated to any of the services running, since they all appear to be running on different hosts. To alleviate this problem, the `node_exporter` in GCK was arbitrarily "assigned" to the `web` service, meaning only for this service `node_*` metrics will appear in Usage Ping.
-
-## Example Usage Ping payload
-
-The following is example content of the Usage Ping payload.
-
-```json
-{
- "uuid": "0000000-0000-0000-0000-000000000000",
- "hostname": "example.com",
- "version": "12.10.0-pre",
- "installation_type": "omnibus-gitlab",
- "active_user_count": 999,
- "recorded_at": "2020-04-17T07:43:54.162+00:00",
- "edition": "EEU",
- "license_md5": "00000000000000000000000000000000",
- "license_id": null,
- "historical_max_users": 999,
- "licensee": {
- "Name": "ABC, Inc.",
- "Email": "email@example.com",
- "Company": "ABC, Inc."
- },
- "license_user_count": 999,
- "license_starts_at": "2020-01-01",
- "license_expires_at": "2021-01-01",
- "license_plan": "ultimate",
- "license_add_ons": {
- },
- "license_trial": false,
- "counts": {
- "assignee_lists": 999,
- "boards": 999,
- "ci_builds": 999,
- ...
- },
- "container_registry_enabled": true,
- "dependency_proxy_enabled": false,
- "gitlab_shared_runners_enabled": true,
- "gravatar_enabled": true,
- "influxdb_metrics_enabled": true,
- "ldap_enabled": false,
- "mattermost_enabled": false,
- "omniauth_enabled": true,
- "prometheus_enabled": false,
- "prometheus_metrics_enabled": false,
- "reply_by_email_enabled": "incoming+%{key}@incoming.gitlab.com",
- "signup_enabled": true,
- "web_ide_clientside_preview_enabled": true,
- "ingress_modsecurity_enabled": true,
- "projects_with_expiration_policy_disabled": 999,
- "projects_with_expiration_policy_enabled": 999,
- ...
- "elasticsearch_enabled": true,
- "license_trial_ends_on": null,
- "geo_enabled": false,
- "git": {
- "version": {
- "major": 2,
- "minor": 26,
- "patch": 1
- }
- },
- "gitaly": {
- "version": "12.10.0-rc1-93-g40980d40",
- "servers": 56,
- "clusters": 14,
- "filesystems": [
- "EXT_2_3_4"
- ]
- },
- "gitlab_pages": {
- "enabled": true,
- "version": "1.17.0"
- },
- "container_registry_server": {
- "vendor": "gitlab",
- "version": "2.9.1-gitlab"
- },
- "database": {
- "adapter": "postgresql",
- "version": "9.6.15"
- },
- "avg_cycle_analytics": {
- "issue": {
- "average": 999,
- "sd": 999,
- "missing": 999
- },
- "plan": {
- "average": null,
- "sd": 999,
- "missing": 999
- },
- "code": {
- "average": null,
- "sd": 999,
- "missing": 999
- },
- "test": {
- "average": null,
- "sd": 999,
- "missing": 999
- },
- "review": {
- "average": null,
- "sd": 999,
- "missing": 999
- },
- "staging": {
- "average": null,
- "sd": 999,
- "missing": 999
- },
- "production": {
- "average": null,
- "sd": 999,
- "missing": 999
- },
- "total": 999
- },
- "analytics_unique_visits": {
- "g_analytics_contribution": 999,
- ...
- },
- "usage_activity_by_stage": {
- "configure": {
- "project_clusters_enabled": 999,
- ...
- },
- "create": {
- "merge_requests": 999,
- ...
- },
- "manage": {
- "events": 999,
- ...
- },
- "monitor": {
- "clusters": 999,
- ...
- },
- "package": {
- "projects_with_packages": 999
- },
- "plan": {
- "issues": 999,
- ...
- },
- "release": {
- "deployments": 999,
- ...
- },
- "secure": {
- "user_container_scanning_jobs": 999,
- ...
- },
- "verify": {
- "ci_builds": 999,
- ...
- }
- },
- "usage_activity_by_stage_monthly": {
- "configure": {
- "project_clusters_enabled": 999,
- ...
- },
- "create": {
- "merge_requests": 999,
- ...
- },
- "manage": {
- "events": 999,
- ...
- },
- "monitor": {
- "clusters": 999,
- ...
- },
- "package": {
- "projects_with_packages": 999
- },
- "plan": {
- "issues": 999,
- ...
- },
- "release": {
- "deployments": 999,
- ...
- },
- "secure": {
- "user_container_scanning_jobs": 999,
- ...
- },
- "verify": {
- "ci_builds": 999,
- ...
- }
- },
- "topology": {
- "duration_s": 0.013836685999194742,
- "application_requests_per_hour": 4224,
- "query_apdex_weekly_average": 0.996,
- "failures": [],
- "nodes": [
- {
- "node_memory_total_bytes": 33269903360,
- "node_memory_utilization": 0.35,
- "node_cpus": 16,
- "node_cpu_utilization": 0.2,
- "node_uname_info": {
- "machine": "x86_64",
- "sysname": "Linux",
- "release": "4.19.76-linuxkit"
- },
- "node_services": [
- {
- "name": "web",
- "process_count": 16,
- "process_memory_pss": 233349888,
- "process_memory_rss": 788220927,
- "process_memory_uss": 195295487,
- "server": "puma"
- },
- {
- "name": "sidekiq",
- "process_count": 1,
- "process_memory_pss": 734080000,
- "process_memory_rss": 750051328,
- "process_memory_uss": 731533312
- },
- ...
- ],
- ...
- },
- ...
- ]
- }
-}
-```
-
-## Exporting Usage Ping SQL queries and definitions
-
-Two Rake tasks exist to export Usage Ping definitions.
-
-- The Rake tasks export the raw SQL queries for `count`, `distinct_count`, `sum`.
-- The Rake tasks export the Redis counter class or the line of the Redis block for `redis_usage_data`.
-- The Rake tasks calculate the `alt_usage_data` metrics.
-
-In the home directory of your local GitLab installation run the following Rake tasks for the YAML and JSON versions respectively:
-
-```shell
-# for YAML export
-bin/rake gitlab:usage_data:dump_sql_in_yaml
-
-# for JSON export
-bin/rake gitlab:usage_data:dump_sql_in_json
-
-# You may pipe the output into a file
-bin/rake gitlab:usage_data:dump_sql_in_yaml > ~/Desktop/usage-metrics-2020-09-02.yaml
-```
+This document was moved to [another location](../product_analytics/usage_ping.md).
diff --git a/doc/development/testing_guide/best_practices.md b/doc/development/testing_guide/best_practices.md
index 6ef9be381b4..2c1d70a005e 100644
--- a/doc/development/testing_guide/best_practices.md
+++ b/doc/development/testing_guide/best_practices.md
@@ -81,7 +81,7 @@ browser is much slower than parsing the HTML response from the app.
A common cause of slow tests is excessive creation of objects, and thus
computation and DB time. Factories are essential to development, but they can
-make inserting data into the DB so easy that we may be able to optimize.
+make inserting data into the DB so easy that we may be able to optimize.
The two basic techniques to bear in mind here are:
@@ -151,11 +151,14 @@ In order to reuse a single object for all calls to a named factory in implicit p
can be used:
```ruby
+RSpec.describe API::Search, factory_default: :keep do
let_it_be(:namespace) { create_default(:namespace) }
```
Then every project we create will use this `namespace`, without us having to pass
-it as `namespace: namespace`.
+it as `namespace: namespace`. In order to make it work along with `let_it_be`, `factory_default: :keep`
+must be explicitly specified. That will keep the default factory for every example in a suite instead of
+recreating it for each example.
Maybe we don't need to create 208 different projects - we
can create one and reuse it. In addition, we can see that only about 1/3 of the
@@ -237,7 +240,7 @@ end
it 'schedules a background job' do
expect(BackgroundJob).to receive(:perform_async)
-
+
subject.execute
end
```
@@ -249,7 +252,7 @@ combining the examples:
```ruby
it 'performs the expected side-effects' do
expect(BackgroundJob).to receive(:perform_async)
-
+
expect { subject.execute }
.to change(Event, :count).by(1)
.and change { arg_0.frobulance }.to('wibble')
@@ -481,26 +484,30 @@ This will result in only one `Project`, `User`, and `ProjectMember` created for
is handled automatically using a transaction rollback.
Note that if you modify an object defined inside a `let_it_be` block,
-then you will need to reload the object as needed, or specify the `reload`
-option to reload for every example.
+then you must do one of the following:
+
+- Reload the object as needed.
+- Use the `let_it_be_with_reload` alias.
+- Specify the `reload` option to reload for every example.
```ruby
+let_it_be_with_reload(:project) { create(:project) }
let_it_be(:project, reload: true) { create(:project) }
```
-You can also specify the `refind` option as well to completely load a
-new object.
+You can also use the `let_it_be_with_refind` alias, or specify the `refind`
+option as well to completely load a new object.
```ruby
+let_it_be_with_refind(:project) { create(:project) }
let_it_be(:project, refind: true) { create(:project) }
```
### Time-sensitive tests
-[Timecop](https://github.com/travisjeffery/timecop) is available in our
-Ruby-based tests for verifying things that are time-sensitive. Any test that
-exercises or verifies something time-sensitive should make use of Timecop to
-prevent transient test failures.
+[`ActiveSupport::Testing::TimeHelpers`](https://api.rubyonrails.org/v6.0.3.1/classes/ActiveSupport/Testing/TimeHelpers.html)
+can be used to verify things that are time-sensitive. Any test that exercises or verifies something time-sensitive
+should make use of these helpers to prevent transient test failures.
Example:
@@ -508,7 +515,7 @@ Example:
it 'is overdue' do
issue = build(:issue, due_date: Date.tomorrow)
- Timecop.freeze(3.days.from_now) do
+ travel_to(3.days.from_now) do
expect(issue).to be_overdue
end
end
@@ -888,6 +895,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.
+ 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/ci.md b/doc/development/testing_guide/ci.md
index 6917639454c..8091142410c 100644
--- a/doc/development/testing_guide/ci.md
+++ b/doc/development/testing_guide/ci.md
@@ -28,9 +28,6 @@ After that, the next pipeline will use the up-to-date `knapsack/report-master.js
The GitLab test suite is [monitored](../performance.md#rspec-profiling) for the `master` branch, and any branch
that includes `rspec-profile` in their name.
-A [public dashboard](https://redash.gitlab.com/public/dashboards/l1WhHXaxrCWM5Ai9D7YDqHKehq6OU3bx5gssaiWe?org_slug=default) is available for everyone to see. Feel free to look at the
-slowest test files and try to improve them.
-
## CI setup
- Rails logging to `log/test.log` is disabled by default in CI [for
diff --git a/doc/development/testing_guide/end_to_end/beginners_guide.md b/doc/development/testing_guide/end_to_end/beginners_guide.md
index c552c44c864..a1883f44170 100644
--- a/doc/development/testing_guide/end_to_end/beginners_guide.md
+++ b/doc/development/testing_guide/end_to_end/beginners_guide.md
@@ -196,8 +196,8 @@ end
**What do we test?**
-1. Can we log in?
-1. Can we log out?
+1. Can we sign in?
+1. Can we sign out?
**How do we test?**
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 36cb49256a6..58bae749dc5 100644
--- a/doc/development/testing_guide/end_to_end/best_practices.md
+++ b/doc/development/testing_guide/end_to_end/best_practices.md
@@ -241,7 +241,11 @@ All tests expect to be able to log in at the start of the test.
For an example see: <https://gitlab.com/gitlab-org/gitlab/-/issues/34736>
-Ideally, any actions performed in an `after(:context)` (or [`before(:context)`](#limit-the-use-of-the-ui-in-beforecontext-and-after-hooks)) block would be performed via the API. But if it's necessary to do so via the UI (e.g., if API functionality doesn't exist), make sure to log out at the end of the block.
+Ideally, actions performed in an `after(:context)` (or
+[`before(:context)`](#limit-the-use-of-the-ui-in-beforecontext-and-after-hooks))
+block are performed using the API. If it's necessary to do so with the user
+interface (for example, if API functionality doesn't exist), be sure to sign
+out at the end of the block.
```ruby
after(:all) do
@@ -310,3 +314,56 @@ end
# Using native mouse click events in the case of a mask/overlay
click_element_coordinates(:title)
```
+
+## Ensure `expect` statements wait efficiently
+
+In general, we use an `expect` statement to check that something _is_ as we expect it. For example:
+
+```ruby
+Page::Project::Pipeline::Show.perform do |pipeline|
+ expect(pipeline).to have_job("a_job")
+end
+```
+
+### Ensure `expect` checks for negation efficiently
+
+However, sometimes we want to check that something is _not_ as we _don't_ want it to be. In other
+words, we want to make sure something is absent. In such a case we should use an appropriate
+predicate method that returns quickly, rather than waiting for a state that won't appear.
+
+It's most efficient to use a predicate method that returns immediately when there is no job, or waits
+until it disappears:
+
+```ruby
+# Good
+Page::Project::Pipeline::Show.perform do |pipeline|
+ expect(pipeline).to have_no_job("a_job")
+end
+```
+
+### Problematic alternatives
+
+Alternatively, if we want to check that a job doesn't exist it might be tempting to use `not_to`:
+
+```ruby
+# Bad
+Page::Project::Pipeline::Show.perform do |pipeline|
+ expect(pipeline).not_to have_job("a_job")
+end
+```
+
+For this statement to pass, `have_job("a_job")` has to return `false` so that `not_to` can negate it.
+The problem is that `have_job("a_job")` waits up to ten seconds for `"a job"` to appear before
+returning `false`. Under the expected condition this test will take ten seconds longer than it needs to.
+
+Instead, we could force no wait:
+
+```ruby
+# Not as bad but potentially flaky
+Page::Project::Pipeline::Show.perform do |pipeline|
+ expect(pipeline).not_to have_job("a_job", wait: 0)
+end
+```
+
+The problem is that if `"a_job"` is present and we're waiting for it to disappear, this statement
+will fail.
diff --git a/doc/development/testing_guide/end_to_end/environment_selection.md b/doc/development/testing_guide/end_to_end/environment_selection.md
index 9eb7db72a51..325f251b280 100644
--- a/doc/development/testing_guide/end_to_end/environment_selection.md
+++ b/doc/development/testing_guide/end_to_end/environment_selection.md
@@ -1,7 +1,7 @@
# Environment selection
-Some tests are designed to be run against specific environments. We can specify
-what environments to run tests against using the `only` metadata.
+Some tests are designed to be run against specific environments or [pipelines](https://about.gitlab.com/handbook/engineering/quality/guidelines/debugging-qa-test-failures/#scheduled-qa-test-pipelines).
+We can specify what environments or pipelines to run tests against using the `only` metadata.
## Available switches
@@ -11,15 +11,16 @@ what environments to run tests against using the `only` metadata.
| `subdomain` | Set the subdomain matcher | `Array` or `String` |
| `domain` | Set the domain matcher | `String` |
| `production` | Match against production | `Static` |
+| `pipeline` | Match against a pipeline | `Array` or `Static`|
CAUTION: **Caution:**
-You cannot specify `:production` and `{ <switch>: 'value' }` simultaneously.
+You cannot specify `:production` and `{ <switch>: 'value' }` simultaneously.
These options are mutually exclusive. If you want to specify production, you
can control the `tld` and `domain` independently.
## Examples
-| Environment | Key | Matches (regex) |
+| Environment or pipeline | Key | Matches (regex for environments, string matching for pipelines) |
| ---------------- | --- | --------------- |
| `any` | `` | `.+.com` |
| `gitlab.com` | `only: :production` | `gitlab.com` |
@@ -27,18 +28,24 @@ can control the `tld` and `domain` independently.
| `gitlab.com and staging.gitlab.com` | `only: { subdomain: /(staging.)?/, domain: 'gitlab' }` | `(staging.)?gitlab.com` |
| `dev.gitlab.org` | `only: { tld: '.org', domain: 'gitlab', subdomain: 'dev' }` | `(dev).gitlab.org` |
| `staging.gitlab.com & domain.gitlab.com` | `only: { subdomain: %i[staging domain] }` | `(staging|domain).+.com` |
+| `nightly` | `only: { pipeline: :nightly }` | "nightly" |
+| `nightly`, `canary` | `only_run_in_pipeline: [:nightly, :canary]` | ["nightly"](https://gitlab.com/gitlab-org/quality/nightly) and ["canary"](https://gitlab.com/gitlab-org/quality/canary) |
```ruby
RSpec.describe 'Area' do
- it 'runs in any environment' do; end
+ it 'runs in any environment or pipeline' do; end
- it 'runs only in production', only: :production do; end
+ it 'runs only in production environment', only: :production do; end
- it 'runs only in staging', only: { subdomain: :staging } do; end
+ it 'runs only in staging environment', only: { subdomain: :staging } do; end
- it 'runs in dev', only: { tld: '.org', domain: 'gitlab', subdomain: 'dev' } do; end
+ it 'runs in dev environment', only: { tld: '.org', domain: 'gitlab', subdomain: 'dev' } do; end
- it 'runs in prod and staging', only: { subdomain: /(staging.)?/, domain: 'gitlab' } {}
+ it 'runs in prod and staging environments', only: { subdomain: /(staging.)?/, domain: 'gitlab' } {}
+
+ it 'runs only in nightly pipeline', only: { pipeline: :nightly } do; end
+
+ it 'runs in nightly and canary pipelines', only: { pipeline: [:nightly, :canary] } do; end
end
```
@@ -46,6 +53,8 @@ NOTE: **Note:**
If the test has a `before` or `after`, you must add the `only` metadata
to the outer `RSpec.describe`.
+If you want to run an `only: { :pipeline }` tagged test on your local GDK make sure either the `CI_PROJECT_NAME` environment variable is unset, or that the `CI_PROJECT_NAME` environment variable matches the specified pipeline in the `only: { :pipeline }` tag, or just delete the `only: { :pipeline }` tag.
+
## Quarantining a test for a specific environment
Similarly to specifying that a test should only run against a specific environment, it's also possible to quarantine a
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 87a9738b313..e571774167d 100644
--- a/doc/development/testing_guide/end_to_end/feature_flags.md
+++ b/doc/development/testing_guide/end_to_end/feature_flags.md
@@ -1,29 +1,70 @@
# Testing with feature flags
-To run a specific test with a feature flag enabled you can use the `QA::Runtime::Feature` class to enable and disable feature flags ([via the API](../../../api/features.md)).
+To run a specific test with a feature flag enabled you can use the `QA::Runtime::Feature` class to
+enable and disable feature flags ([via the API](../../../api/features.md)).
-Note that administrator authorization is required to change feature flags. `QA::Runtime::Feature` will automatically authenticate as an administrator as long as you provide an appropriate access token via `GITLAB_QA_ADMIN_ACCESS_TOKEN` (recommended), or provide `GITLAB_ADMIN_USERNAME` and `GITLAB_ADMIN_PASSWORD`.
+Note that administrator authorization is required to change feature flags. `QA::Runtime::Feature`
+will automatically authenticate as an administrator as long as you provide an appropriate access
+token via `GITLAB_QA_ADMIN_ACCESS_TOKEN` (recommended), or provide `GITLAB_ADMIN_USERNAME`
+and `GITLAB_ADMIN_PASSWORD`.
-Please be sure to include the tag `:requires_admin` so that the test can be skipped in environments where admin access is not available.
+Please be sure to include the tag `:requires_admin` so that the test can be skipped in environments
+where admin access is not available.
+
+CAUTION: **Caution:**
+You are strongly advised to [enable feature flags only for a group, project, user](../../feature_flags/development.md#feature-actors),
+or [feature group](../../feature_flags/development.md#feature-groups). This makes it possible to
+test a feature in a shared environment without affecting other users.
+
+For example, the code below would enable a feature flag named `:feature_flag_name` for the project
+created by the test:
```ruby
RSpec.describe "with feature flag enabled", :requires_admin do
+ let(:project) { Resource::Project.fabricate_via_api! }
+
before do
- Runtime::Feature.enable('feature_flag_name')
+ Runtime::Feature.enable(:feature_flag_name, project: project)
end
it "feature flag test" do
- # Execute a test with a feature flag enabled
+ # Execute the test with the feature flag enabled.
+ # It will only affect the project created in this test.
end
after do
- Runtime::Feature.disable('feature_flag_name')
+ Runtime::Feature.disable(:feature_flag_name, project: project)
end
end
```
+Note that the `enable` and `disable` methods first set the flag and then check that the updated
+value is returned by the API.
+
+Similarly, you can enable a feature for a group, user, or feature group:
+
+```ruby
+group = Resource::Group.fabricate_via_api!
+Runtime::Feature.enable(:feature_flag_name, group: group)
+
+user = Resource::User.fabricate_via_api!
+Runtime::Feature.enable(:feature_flag_name, user: user)
+
+feature_group = "a_feature_group"
+Runtime::Feature.enable(:feature_flag_name, feature_group: feature_group)
+```
+
+If no scope is provided, the feature flag will be set instance-wide:
+
+```ruby
+# This will affect all users!
+Runtime::Feature.enable(:feature_flag_name)
+```
+
## Running a scenario with a feature flag enabled
-It's also possible to run an entire scenario with a feature flag enabled, without having to edit existing tests or write new ones.
+It's also possible to run an entire scenario with a feature flag enabled, without having to edit
+existing tests or write new ones.
-Please see the [QA README](https://gitlab.com/gitlab-org/gitlab/tree/master/qa#running-tests-with-a-feature-flag-enabled) for details.
+Please see the [QA README](https://gitlab.com/gitlab-org/gitlab/tree/master/qa#running-tests-with-a-feature-flag-enabled)
+for details.
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 a9f54b53e5a..3a1303d9c0c 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
@@ -11,7 +11,7 @@ This is a partial list of the [RSpec metadata](https://relishapp.com/rspec/rspec
| `:gitaly_cluster` | The test will run against a GitLab instance where repositories are stored on redundant Gitaly nodes behind a Praefect node. All nodes are [separate containers](../../../administration/gitaly/praefect.md#requirements-for-configuring-a-gitaly-cluster). Tests that use this tag have a longer setup time since there are three additional containers that need to be started. |
| `:jira` | The test requires a Jira Server. [GitLab-QA](https://gitlab.com/gitlab-org/gitlab-qa) will provision the Jira Server in a Docker container when the `Test::Integration::Jira` test scenario is run.
| `:kubernetes` | The test includes a GitLab instance that is configured to be run behind an SSH tunnel, allowing a TLS-accessible GitLab. This test will also include provisioning of at least one Kubernetes cluster to test against. *This tag is often be paired with `:orchestrated`.* |
-| `:only` | The test is only to be run against specific environments. See [Environment selection](environment_selection.md) for more information. |
+| `:only` | The test is only to be run against specific environments or pipelines. See [Environment selection](environment_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 GitLab's configuration (for example, Staging). |
| `:quarantine` | The test has been [quarantined](https://about.gitlab.com/handbook/engineering/quality/guidelines/debugging-qa-test-failures/#quarantining-tests), will run in a separate job that only includes quarantined tests, and is allowed to fail. The test will be skipped in its regular job so that if it fails it will not hold up the pipeline. Note that you can also [quarantine a test only when it runs against specific environment](environment_selection.md#quarantining-a-test-for-a-specific-environment). |
| `:reliable` | The test has been [promoted to a reliable test](https://about.gitlab.com/handbook/engineering/quality/guidelines/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/running_tests_that_require_special_setup.md b/doc/development/testing_guide/end_to_end/running_tests_that_require_special_setup.md
index 7ac0a00fcff..658839fcf96 100644
--- a/doc/development/testing_guide/end_to_end/running_tests_that_require_special_setup.md
+++ b/doc/development/testing_guide/end_to_end/running_tests_that_require_special_setup.md
@@ -274,7 +274,7 @@ CHROME_HEADLESS=false bundle exec bin/qa QA::EE::Scenario::Test::Geo --primary-a
### Using Geo in Docker
-You can use [GitLab-QA Orchestrator](https://gitlab.com/gitlab-org/gitlab-qa) to orchestrate two GitLab containers and configure them as a Geo setup.
+You can use [GitLab-QA Orchestrator](https://gitlab.com/gitlab-org/gitlab-qa) to orchestrate two GitLab containers and configure them as a Geo setup.
Geo requires an EE license. To visit the Geo sites in your browser, you will need a reverse proxy server (for example, [NGINX](https://www.nginx.com/)).
@@ -319,7 +319,7 @@ Geo requires an EE license. To visit the Geo sites in your browser, you will nee
_Map the hostnames to the local IP in `/etc/hosts` file on your machine:_
```plaintext
- 127.0.0.1 gitlab-primary.geo gitlab-secondary.geo
+ 127.0.0.1 gitlab-primary.geo gitlab-secondary.geo
```
_Note the assigned ports:_
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 7e9f097f624..645c2633831 100644
--- a/doc/development/testing_guide/end_to_end/style_guide.md
+++ b/doc/development/testing_guide/end_to_end/style_guide.md
@@ -141,7 +141,7 @@ end
```
```ruby
-Page::Project::New.peform do |new_page|
+Page::Project::New.perform do |new_page|
new_page.do_something
end
```
@@ -155,7 +155,7 @@ end
```
```ruby
-Page::Project::New.peform do |page|
+Page::Project::New.perform do |page|
page.do_something
end
```
diff --git a/doc/development/testing_guide/frontend_testing.md b/doc/development/testing_guide/frontend_testing.md
index 30e78766dde..730f8d5ad7d 100644
--- a/doc/development/testing_guide/frontend_testing.md
+++ b/doc/development/testing_guide/frontend_testing.md
@@ -229,7 +229,7 @@ beforeEach(() => {
it('exists', () => {
// Best
- // NOTE: both mount and shallowMount work as long as a DOM element is available
+ // NOTE: both mount and shallowMount work as long as a DOM element is available
// Finds a properly formatted link with an accessible name of "Click Me"
getByRole(el, 'link', { name: /Click Me/i })
getByRole(el, 'link', { name: 'Click Me' })
diff --git a/doc/development/what_requires_downtime.md b/doc/development/what_requires_downtime.md
index 7c99bcde413..9063fb867e2 100644
--- a/doc/development/what_requires_downtime.md
+++ b/doc/development/what_requires_downtime.md
@@ -176,7 +176,7 @@ class ChangeUsersUsernameStringToText < ActiveRecord::Migration[4.2]
end
def down
- cleanup_concurrent_column_type_change :users, :username
+ undo_change_column_type_concurrently :users, :username
end
end
```
@@ -197,7 +197,7 @@ class ChangeUsersUsernameStringToTextCleanup < ActiveRecord::Migration[4.2]
end
def down
- change_column_type_concurrently :users, :username, :string
+ undo_cleanup_concurrent_column_type_change :users, :username, :string
end
end
```
diff --git a/doc/development/wikis.md b/doc/development/wikis.md
new file mode 100644
index 00000000000..9a436762645
--- /dev/null
+++ b/doc/development/wikis.md
@@ -0,0 +1,94 @@
+---
+type: reference, dev
+stage: none
+group: Development
+info: "See the Technical Writers assigned to Development Guidelines: https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments-to-development-guidelines"
+description: "GitLab's development guidelines for Wikis"
+---
+
+# Wikis development guide
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/227027) in GitLab 13.5.
+
+## Overview
+
+The wiki functionality in GitLab is based on [Gollum 4.x](https://github.com/gollum/gollum/),
+which is used in [Gitaly's](gitaly.md) Ruby service and accessed from the Rails app through Gitaly RPC calls.
+
+Wikis use Git repositories as storage backend, and can be accessed through:
+
+- The [Web UI](../user/project/wiki/index.md)
+- The [REST API](../api/wikis.md)
+- [Git itself](../user/project/wiki/#adding-and-editing-wiki-pages-locally)
+
+[Introduced](https://gitlab.com/groups/gitlab-org/-/epics/2214) in GitLab 13.5, wikis are also available
+for groups, in addition to projects.
+
+## Involved Gems
+
+Some notable gems that are used for wikis are:
+
+| Component | Description | Gem name | GitLab project | Upstream project |
+|:--------------|:-----------------------------------------------|:-------------------------------|:--------------------------------------------------------------------------------------------------------|:--------------------------------------------------------------------|
+| `gitlab` | Markup renderer, depends on various other gems | `gitlab-markup` | [`gitlab-org/gitlab-markup`](https://gitlab.com/gitlab-org/gitlab-markup) | [`github/markup`](https://github.com/github/markup) |
+| `gitaly-ruby` | Main Gollum library | `gitlab-gollum-lib` | [`gitlab-org/gollum-lib`](https://gitlab.com/gitlab-org/gollum-lib) | [`gollum/gollum-lib`](https://github.com/gollum/gollum-lib) |
+| | Gollum Git adapter for Rugged | `gitlab-gollum-rugged_adapter` | [`gitlab-org/gitlab-gollum-rugged_adapter`](https://gitlab.com/gitlab-org/gitlab-gollum-rugged_adapter) | [`gollum/rugged_adapter`](https://github.com/gollum/rugged_adapter) |
+| | Rugged (also used in Gitaly itself) | `rugged` | - | [`libgit2/rugged`](https://github.com/libgit2/rugged) |
+
+### Notes on Gollum
+
+We only use Gollum as a storage abstraction layer, to handle the mapping between wiki page slugs and files in the repository.
+
+When rendering wiki pages, we don't use Gollum at all and instead go through a
+[custom Banzai pipeline](https://gitlab.com/gitlab-org/gitlab/blob/master/lib/banzai/pipeline/wiki_pipeline.rb).
+This adds some [wiki-specific markup](../user/markdown.md#wiki-specific-markdown), such as Gollum's `[[link]]` syntax.
+
+Since we do not make use of most of Gollum's features, we plan to move away from it entirely at some point.
+[See this epic](https://gitlab.com/groups/gitlab-org/-/epics/2381) for reference.
+
+## Model classes
+
+The `Wiki` class is the main abstraction around a wiki repository, it needs to be initialized
+with a container which can be either a `Project` or `Group`:
+
+```mermaid
+classDiagram
+ Wiki --> ProjectWiki
+ Wiki --> GroupWiki
+
+ class Wiki {
+ #container
+ #repository
+ }
+
+ class ProjectWiki {
+ #project → #container
+ }
+
+ class GroupWiki {
+ #group → #container
+ }
+```
+
+Some models wrap similar classes from Gitaly and Gollum:
+
+| Rails Model | Gitaly Class | Gollum |
+|:------------|:--------------------------------------------------------|:---------------|
+| `Wiki` | `Gitlab::Git::Wiki` | `Gollum::Wiki` |
+| `WikiPage` | `Gitlab::Git::WikiPage`, `Gitlab::Git::WikiPageVersion` | `Gollum::Page` |
+| | `Gitlab::Git::WikiFile` | `Gollum::File` |
+
+Only some data is persisted in the database:
+
+| Model | Description |
+|:----------------------|:-----------------------------------------|
+| `WikiPage::Meta` | Metadata for wiki pages |
+| `WikiPage::Slug` | Current and previous slugs of wiki pages |
+| `ProjectRepository` | Gitaly storage data for project wikis |
+| `GroupWikiRepository` | Gitaly storage data for group wikis |
+
+## Attachments
+
+The web UI uploads attachments through the REST API, which stores the files as commits in the wiki repository.
+
+Prior to GitLab 11.3 attachments were stored outside of the repository, [see this issue](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/33475).
diff --git a/doc/getting-started/subscription.md b/doc/getting-started/subscription.md
deleted file mode 100644
index 8bcd11c20c8..00000000000
--- a/doc/getting-started/subscription.md
+++ /dev/null
@@ -1,3 +0,0 @@
----
-redirect_to: '../subscriptions/index.md'
----
diff --git a/doc/git_hooks/git_hooks.md b/doc/git_hooks/git_hooks.md
deleted file mode 100644
index b251e58410a..00000000000
--- a/doc/git_hooks/git_hooks.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../push_rules/push_rules.md'
----
-
-This document was moved to [another location](../push_rules/push_rules.md)
diff --git a/doc/gitlab-basics/README.md b/doc/gitlab-basics/README.md
index a7f18e13f74..3850655aaed 100644
--- a/doc/gitlab-basics/README.md
+++ b/doc/gitlab-basics/README.md
@@ -31,7 +31,7 @@ The following are guides to basic GitLab functionality:
- [Add a file](add-file.md), to add new files to a project's repository.
- [Create an issue](../user/project/issues/managing_issues.md#create-a-new-issue),
to start collaborating within a project.
-- [Create a merge request](add-merge-request.md), to request changes made in a branch
+- [Create a merge request](../user/project/merge_requests/creating_merge_requests.md), to request changes made in a branch
be merged into a project's repository.
- See how these features come together in the [GitLab Flow introduction video](https://youtu.be/InKNIvky2KE)
and [GitLab Flow page](../topics/gitlab_flow.md).
diff --git a/doc/gitlab-basics/add-file.md b/doc/gitlab-basics/add-file.md
index c5b57d4623d..0b400d7fdb4 100644
--- a/doc/gitlab-basics/add-file.md
+++ b/doc/gitlab-basics/add-file.md
@@ -29,16 +29,17 @@ to the desired destination:
cd <destination folder>
```
-[Create a branch](create-branch.md) to add your file to, before it is added to the master
-(main) branch of the project. It is not strictly necessary, but working directly in
-the `master` branch is not recommended unless your project is very small, and you are
-the only person working on it. You can [switch to an existing branch](start-using-git.md#work-on-an-existing-branch),
+[Create a new branch](create-branch.md) to add your file into. Submitting changes directly
+to the default branch should be avoided unless your project is very small and you're the
+only person working on it.
+
+You can also [switch to an existing branch](start-using-git.md#work-on-an-existing-branch)
if you have one already.
Using your standard tool for copying files (for example, Finder in macOS, or File Explorer
-in Windows), put the file into a directory within the GitLab project.
+on Windows), put the file into a directory within the GitLab project.
-Check if your file is actually present in the directory (if you are in Windows,
+Check if your file is actually present in the directory (if you're on Windows,
use `dir` instead):
```shell
@@ -79,7 +80,7 @@ Now you can push (send) your changes (in the branch `<branch-name>`) to GitLab
git push origin <branch-name>
```
-Your image will be added to your branch in your repository in GitLab.
+Your image is added to your branch in your repository in GitLab.
<!-- ## Troubleshooting
diff --git a/doc/gitlab-basics/create-branch.md b/doc/gitlab-basics/create-branch.md
index 0ad5cb53e97..9e51a2749a6 100644
--- a/doc/gitlab-basics/create-branch.md
+++ b/doc/gitlab-basics/create-branch.md
@@ -9,11 +9,11 @@ type: howto
A branch is an independent line of development in a [project](../user/project/index.md).
-When you create a new branch (in your [terminal](basic-git-commands.md) or with
+When you create a new branch (in your [terminal](start-using-git.md) or with
[the web interface](../user/project/repository/web_editor.md#create-a-new-branch)),
you are creating a snapshot of a certain branch, usually the main `master` branch,
-at it's current state. From there, you can start to make your own changes without
+at its current state. From there, you can start to make your own changes without
affecting the main codebase. The history of your changes will be tracked in your branch.
When your changes are ready, you then merge them into the rest of the codebase with a
-[merge request](add-merge-request.md).
+[merge request](../user/project/merge_requests/creating_merge_requests.md).
diff --git a/doc/gitlab-basics/create-project.md b/doc/gitlab-basics/create-project.md
index f411ac769c0..616bb752694 100644
--- a/doc/gitlab-basics/create-project.md
+++ b/doc/gitlab-basics/create-project.md
@@ -18,13 +18,13 @@ To create a project in GitLab:
icon in the navigation bar. This opens the **New project** page.
1. On the **New project** page, choose if you want to:
- Create a [blank project](#blank-projects).
- - Create a project using with one of the available [project templates](#project-templates).
+ - Create a project using one of the available [project templates](#project-templates).
- [Import a project](../user/project/import/index.md) from a different repository,
- if enabled on your GitLab instance. Contact your GitLab admin if this is unavailable.
+ if enabled on your GitLab instance. Contact your GitLab administrator if this is unavailable.
- Run [CI/CD pipelines for external repositories](../ci/ci_cd_for_external_repos/index.md). **(PREMIUM)**
NOTE: **Note:**
-For a list of words that cannot be used as project names see
+For a list of words that can't be used as project names see
[Reserved project and group names](../user/reserved_names.md).
### Blank projects
@@ -33,17 +33,17 @@ To create a new blank project on the **New project** page:
1. On the **Blank project** tab, provide the following information:
- The name of your project in the **Project name** field. You can't use
- special characters, but you can use spaces, hyphens, underscores or even
- emoji. When adding the name, the **Project slug** will auto populate.
- The slug is what the GitLab instance will use as the URL path to the project.
+ special characters, but you can use spaces, hyphens, underscores, or even
+ emoji. When adding the name, the **Project slug** auto populates.
+ The slug is what the GitLab instance uses as the URL path to the project.
If you want a different slug, input the project name first,
then change the slug after.
- The path to your project in the **Project slug** field. This is the URL
- path for your project that the GitLab instance will use. If the
- **Project name** is blank, it will auto populate when you fill in
+ path for your project that the GitLab instance uses. If the
+ **Project name** is blank, it auto populates when you fill in
the **Project slug**.
- The **Project description (optional)** field enables you to enter a
- description for your project's dashboard, which will help others
+ description for your project's dashboard, which helps others
understand what your project is about. Though it's not required, it's a good
idea to fill this in.
- Changing the **Visibility Level** modifies the project's
@@ -58,7 +58,7 @@ To create a new blank project on the **New project** page:
Project templates can pre-populate a new project with the necessary files to get you
started quickly.
-There are two types of project templates:
+There are two main types of project templates:
- [Built-in templates](#built-in-templates), sourced from the following groups:
- [`project-templates`](https://gitlab.com/gitlab-org/project-templates)
@@ -128,11 +128,11 @@ To use a custom project template on the **New project** page:
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/26388) in GitLab 10.5.
-When you create a new repository locally, instead of going to GitLab to manually
-create a new project and then [clone the repo](start-using-git.md#clone-a-repository)
+When you create a new repository locally, instead of manually creating a new project in GitLab
+and then [cloning the repository](start-using-git.md#clone-a-repository)
locally, you can directly push it to GitLab to create the new project, all without leaving
-your terminal. If you have access rights to the associated namespace, GitLab will
-automatically create a new project under that GitLab namespace with its visibility
+your terminal. If you have access rights to the associated namespace, GitLab
+automatically creates a new project under that GitLab namespace with its visibility
set to Private by default (you can later change it in the [project's settings](../public_access/public_access.md#how-to-change-project-visibility)).
This can be done by using either SSH or HTTPS:
@@ -145,7 +145,7 @@ git push --set-upstream git@gitlab.example.com:namespace/nonexistent-project.git
git push --set-upstream https://gitlab.example.com/namespace/nonexistent-project.git master
```
-Once the push finishes successfully, a remote message will indicate
+Once the push finishes successfully, a remote message indicates
the command to set the remote and the URL to the new project:
```plaintext
diff --git a/doc/gitlab-basics/start-using-git.md b/doc/gitlab-basics/start-using-git.md
index 3812fd3b92a..b6192700d29 100644
--- a/doc/gitlab-basics/start-using-git.md
+++ b/doc/gitlab-basics/start-using-git.md
@@ -323,19 +323,25 @@ to work on a different **branch**.
When you create a branch in a Git repository, you make a copy of its files at the time of branching. You're free
to do whatever you want with the code in your branch without impacting the main branch or other branches. And when
-you're ready to bring your changes to the main codebase, you can merge your branch into the main one
+you're ready to bring your changes to the main codebase, you can merge your branch into the default branch
used in your project (such as `master`).
+A new branch is often called **feature branch** to differentiate from the
+**default branch**.
+
### Create a branch
-To create a new branch, to work from without affecting the `master` branch, type
-the following (spaces won't be recognized in the branch name, so you will need to
-use a hyphen or underscore):
+To create a new feature branch and work from without affecting the `master`
+branch:
```shell
git checkout -b <name-of-branch>
```
+Note that Git does **not** accept empty spaces and special characters in branch
+names, so use only lowercase letters, numbers, hyphens (`-`), and underscores
+(`_`). Do not use capital letters, as it may cause duplications.
+
### Switch to the master branch
You are always in a branch when working with Git. The main branch is the master
@@ -411,6 +417,9 @@ For example, to push your local commits to the _`master`_ branch of the _`origin
git push origin master
```
+On certain occasions, Git won't allow you to push to your repository, and then
+you'll need to [force an update](../topics/git/git_rebase.md#force-push).
+
NOTE: **Note:**
To create a merge request from a fork to an upstream repository, see the
[forking workflow](../user/project/repository/forking_workflow.md).
@@ -459,6 +468,10 @@ git checkout <name-of-branch>
git merge master
```
+## Advanced use of Git through the command line
+
+For an introduction of more advanced Git techniques, see [Git rebase, force-push, and merge conflicts](../topics/git/git_rebase.md).
+
## Synchronize changes in a forked repository with the upstream
[Forking a repository](../user/project/repository/forking_workflow.md) lets you create
diff --git a/doc/gitlab-geo/README.md b/doc/gitlab-geo/README.md
deleted file mode 100644
index 67e919fc136..00000000000
--- a/doc/gitlab-geo/README.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../administration/geo/index.md'
----
-
-This document was moved to [another location](../administration/geo/index.md).
diff --git a/doc/gitlab-geo/after_setup.md b/doc/gitlab-geo/after_setup.md
deleted file mode 100644
index c8a7b9d1096..00000000000
--- a/doc/gitlab-geo/after_setup.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../administration/geo/replication/using_a_geo_server.md'
----
-
-This document was moved to [another location](../administration/geo/replication/using_a_geo_server.md).
diff --git a/doc/gitlab-geo/bring-primary-back.md b/doc/gitlab-geo/bring-primary-back.md
deleted file mode 100644
index 8c43f4d805f..00000000000
--- a/doc/gitlab-geo/bring-primary-back.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../administration/geo/disaster_recovery/bring_primary_back.md'
----
-
-This document was moved to [another location](../administration/geo/disaster_recovery/bring_primary_back.md).
diff --git a/doc/gitlab-geo/configuration.md b/doc/gitlab-geo/configuration.md
deleted file mode 100644
index b46a2caea4a..00000000000
--- a/doc/gitlab-geo/configuration.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../administration/geo/replication/configuration.md'
----
-
-This document was moved to [another location](../administration/geo/replication/configuration.md).
diff --git a/doc/gitlab-geo/configuration_source.md b/doc/gitlab-geo/configuration_source.md
deleted file mode 100644
index b46a2caea4a..00000000000
--- a/doc/gitlab-geo/configuration_source.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../administration/geo/replication/configuration.md'
----
-
-This document was moved to [another location](../administration/geo/replication/configuration.md).
diff --git a/doc/gitlab-geo/database.md b/doc/gitlab-geo/database.md
deleted file mode 100644
index 2f68068d95b..00000000000
--- a/doc/gitlab-geo/database.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../administration/geo/setup/database.md'
----
-
-This document was moved to [another location](../administration/geo/setup/database.md).
diff --git a/doc/gitlab-geo/database_source.md b/doc/gitlab-geo/database_source.md
deleted file mode 100644
index 2f68068d95b..00000000000
--- a/doc/gitlab-geo/database_source.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../administration/geo/setup/database.md'
----
-
-This document was moved to [another location](../administration/geo/setup/database.md).
diff --git a/doc/gitlab-geo/disaster-recovery.md b/doc/gitlab-geo/disaster-recovery.md
deleted file mode 100644
index d42e815a879..00000000000
--- a/doc/gitlab-geo/disaster-recovery.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../administration/geo/disaster_recovery/index.md'
----
-
-This document was moved to [another location](../administration/geo/disaster_recovery/index.md).
diff --git a/doc/gitlab-geo/docker_registry.md b/doc/gitlab-geo/docker_registry.md
deleted file mode 100644
index 26a708f6845..00000000000
--- a/doc/gitlab-geo/docker_registry.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../administration/geo/replication/docker_registry.md'
----
-
-This document was moved to [another location](../administration/geo/replication/docker_registry.md).
diff --git a/doc/gitlab-geo/faq.md b/doc/gitlab-geo/faq.md
deleted file mode 100644
index f1952bc7e4c..00000000000
--- a/doc/gitlab-geo/faq.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../administration/geo/replication/faq.md'
----
-
-This document was moved to [another location](../administration/geo/replication/faq.md).
diff --git a/doc/gitlab-geo/ha.md b/doc/gitlab-geo/ha.md
deleted file mode 100644
index 0be70791d45..00000000000
--- a/doc/gitlab-geo/ha.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../administration/geo/replication/multiple_servers.md'
----
-
-This document was moved to [another location](../administration/geo/replication/multiple_servers.md).
diff --git a/doc/gitlab-geo/object_storage.md b/doc/gitlab-geo/object_storage.md
deleted file mode 100644
index 1f29b7b7e8c..00000000000
--- a/doc/gitlab-geo/object_storage.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../administration/geo/replication/object_storage.md'
----
-
-This document was moved to [another location](../administration/geo/replication/object_storage.md).
diff --git a/doc/gitlab-geo/planned-failover.md b/doc/gitlab-geo/planned-failover.md
deleted file mode 100644
index 720b6bc9424..00000000000
--- a/doc/gitlab-geo/planned-failover.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../administration/geo/disaster_recovery/planned_failover.md'
----
-
-This document was moved to [another location](../administration/geo/disaster_recovery/planned_failover.md).
diff --git a/doc/gitlab-geo/security-review.md b/doc/gitlab-geo/security-review.md
deleted file mode 100644
index a0a5b0e536c..00000000000
--- a/doc/gitlab-geo/security-review.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../administration/geo/replication/security_review.md'
----
-
-This document was moved to [another location](../administration/geo/replication/security_review.md).
diff --git a/doc/gitlab-geo/ssh.md b/doc/gitlab-geo/ssh.md
deleted file mode 100644
index 4f8db687850..00000000000
--- a/doc/gitlab-geo/ssh.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../administration/operations/fast_ssh_key_lookup.md'
----
-
-This document was moved to [another location](../administration/operations/fast_ssh_key_lookup.md).
diff --git a/doc/gitlab-geo/troubleshooting.md b/doc/gitlab-geo/troubleshooting.md
deleted file mode 100644
index 25fe1372c69..00000000000
--- a/doc/gitlab-geo/troubleshooting.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../administration/geo/replication/troubleshooting.md'
----
-
-This document was moved to [another location](../administration/geo/replication/troubleshooting.md).
diff --git a/doc/gitlab-geo/tuning.md b/doc/gitlab-geo/tuning.md
deleted file mode 100644
index 84ac40f99db..00000000000
--- a/doc/gitlab-geo/tuning.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../administration/geo/replication/tuning.md'
----
-
-This document was moved to [another location](../administration/geo/replication/tuning.md).
diff --git a/doc/gitlab-geo/updating_the_geo_nodes.md b/doc/gitlab-geo/updating_the_geo_nodes.md
deleted file mode 100644
index 28234ec02ed..00000000000
--- a/doc/gitlab-geo/updating_the_geo_nodes.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../administration/geo/replication/updating_the_geo_nodes.md'
----
-
-This document was moved to [another location](../administration/geo/replication/updating_the_geo_nodes.md).
diff --git a/doc/gitlab-geo/using_a_geo_server.md b/doc/gitlab-geo/using_a_geo_server.md
deleted file mode 100644
index c8a7b9d1096..00000000000
--- a/doc/gitlab-geo/using_a_geo_server.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../administration/geo/replication/using_a_geo_server.md'
----
-
-This document was moved to [another location](../administration/geo/replication/using_a_geo_server.md).
diff --git a/doc/hooks/custom_hooks.md b/doc/hooks/custom_hooks.md
deleted file mode 100644
index c6d44bb03e9..00000000000
--- a/doc/hooks/custom_hooks.md
+++ /dev/null
@@ -1,7 +0,0 @@
----
-redirect_to: '../administration/server_hooks.md'
----
-
-# Custom Git Hooks
-
-This document was moved to [administration/server_hooks.md](../administration/server_hooks.md).
diff --git a/doc/incoming_email/README.md b/doc/incoming_email/README.md
deleted file mode 100644
index 9544983974f..00000000000
--- a/doc/incoming_email/README.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../administration/reply_by_email.md'
----
-
-This document was moved to [administration/reply_by_email](../administration/reply_by_email.md).
diff --git a/doc/incoming_email/postfix.md b/doc/incoming_email/postfix.md
deleted file mode 100644
index a7192325229..00000000000
--- a/doc/incoming_email/postfix.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../administration/reply_by_email_postfix_setup.md'
----
-
-This document was moved to [administration/reply_by_email_postfix_setup](../administration/reply_by_email_postfix_setup.md).
diff --git a/doc/install/README.md b/doc/install/README.md
index f1ef368685e..6b08bb28bbb 100644
--- a/doc/install/README.md
+++ b/doc/install/README.md
@@ -1,4 +1,7 @@
---
+stage: Enablement
+group: Distribution
+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/#designated-technical-writers
comments: false
description: Read through the GitLab installation methods.
type: index
@@ -6,33 +9,42 @@ type: index
# Installation **(CORE ONLY)**
-GitLab can be installed in most GNU/Linux distributions and in a number
-of cloud providers. To get the best experience from GitLab, you need to balance
-performance, reliability, ease of administration (backups, upgrades and troubleshooting),
-and cost of hosting.
-
-There are many ways you can install GitLab depending on your platform:
-
-1. **Omnibus GitLab**: The official deb/rpm packages that contain a bundle of GitLab
- and the various components it depends on, like PostgreSQL, Redis, Sidekiq, etc.
-1. **GitLab Helm chart**: The cloud native Helm chart for installing GitLab and all
- its components on Kubernetes.
-1. **Docker**: The Omnibus GitLab packages dockerized.
-1. **Source**: Install GitLab and all its components from scratch.
-
-TIP: **If in doubt, choose Omnibus:**
-The Omnibus GitLab packages are mature,
-[scalable](../administration/reference_architectures/index.md) and are used
+GitLab can be installed in most GNU/Linux distributions and with several
+cloud providers. To get the best experience from GitLab, you must balance
+performance, reliability, ease of administration (backups, upgrades, and
+troubleshooting), and the cost of hosting.
+
+Depending on your platform, select from the following available methods to
+install GitLab:
+
+- [_Omnibus GitLab_](#installing-gitlab-using-the-omnibus-gitlab-package-recommended):
+ The official deb/rpm packages that contain a bundle of GitLab and the
+ components it depends on, including PostgreSQL, Redis, and Sidekiq.
+- [_GitLab Helm chart_](#installing-gitlab-on-kubernetes-via-the-gitlab-helm-charts):
+ The cloud native Helm chart for installing GitLab and all of its components
+ on Kubernetes.
+- [_Docker_](#installing-gitlab-with-docker): The Omnibus GitLab packages,
+ dockerized.
+- [_Source_](#installing-gitlab-from-source): Install GitLab and all of its
+ components from scratch.
+- [_Cloud provider_](#installing-gitlab-on-cloud-providers): Install directly
+ from platforms like AWS, Azure, and GCP.
+
+If you're not sure which installation method to use, we recommend you use
+Omnibus GitLab. The Omnibus GitLab packages are mature,
+[scalable](../administration/reference_architectures/index.md), and are used
today on GitLab.com. The Helm charts are recommended for those who are familiar
with Kubernetes.
## Requirements
-Before installing GitLab, it is of critical importance to review the system [requirements](requirements.md). The system requirements include details on the minimum hardware, software, database, and additional requirements to support GitLab.
+Before you install GitLab, be sure to review the [system requirements](requirements.md).
+The system requirements include details about the minimum hardware, software,
+database, and additional requirements to support GitLab.
## Installing GitLab using the Omnibus GitLab package (recommended)
-The Omnibus GitLab package uses our official deb/rpm repositories. This is
+The Omnibus GitLab package uses our official deb/rpm repositories, and is
recommended for most users.
If you need additional flexibility and resilience, we recommend deploying
@@ -42,11 +54,6 @@ GitLab as described in our [reference architecture documentation](../administrat
## Installing GitLab on Kubernetes via the GitLab Helm charts
-NOTE: **Kubernetes experience required:**
-We recommend being familiar with Kubernetes before using it to deploy GitLab in
-production. The methods for management, observability, and some concepts are
-different than traditional deployments.
-
When installing GitLab on Kubernetes, there are some trade-offs that you
need to be aware of:
@@ -56,11 +63,17 @@ need to be aware of:
are deployed in a redundant fashion.
- There are some feature [limitations to be aware of](https://docs.gitlab.com/charts/#limitations).
+Due to these trade-offs, having Kubernetes experience is a requirement for
+using this method. We recommend being familiar with Kubernetes before using it
+to deploy GitLab in production. The methods for management, observability, and
+some concepts are different than traditional deployments.
+
[**> Install GitLab on Kubernetes using the GitLab Helm charts.**](https://docs.gitlab.com/charts/)
## Installing GitLab with Docker
-GitLab maintains a set of official Docker images based on the Omnibus GitLab package.
+GitLab maintains a set of official Docker images based on the Omnibus GitLab
+package.
[**> Install GitLab using the official GitLab Docker images.**](docker.md)
@@ -68,7 +81,7 @@ GitLab maintains a set of official Docker images based on the Omnibus GitLab pac
If the Omnibus GitLab package is not available in your distribution, you can
install GitLab from source: Useful for unsupported systems like \*BSD. For an
-overview of the directory structure, read the [structure documentation](structure.md).
+overview of the directory structure, read the [structure documentation](installation.md#gitlab-directory-structure).
[**> Install GitLab from source.**](installation.md)
@@ -86,6 +99,37 @@ the above methods, provided the cloud provider supports it.
- _Testing only!_ [DigitalOcean and Docker Machine](digitaloceandocker.md):
Quickly test any version of GitLab on DigitalOcean using Docker Machine.
-## Securing your GitLab installation
-
-After completing your installation, check out our [recommended practices to secure your GitLab instance](../security/README.md#securing-your-gitlab-installation).
+## Next steps
+
+Here are a few resources you might want to check out after completing the
+installation:
+
+- [Upload a license](../user/admin_area/license.md) or [start a free trial](https://about.gitlab.com/free-trial/):
+ Activate all GitLab Enterprise Edition functionality with a license.
+- [Set up runners](https://docs.gitlab.com/runner/): Set up one or more GitLab
+ Runners, the agents that are responsible for all of GitLab's CI/CD features.
+- [GitLab Pages](../administration/pages/index.md): Configure GitLab Pages to
+ allow hosting of static sites.
+- [GitLab Registry](../administration/packages/container_registry.md): With the
+ GitLab Container Registry, every project can have its own space to store Docker
+ images.
+- [Secure GitLab](../security/README.md#securing-your-gitlab-installation):
+ Recommended practices to secure your GitLab instance.
+- [SMTP](https://docs.gitlab.com/omnibus/settings/smtp.html): Configure SMTP
+ for proper email notifications support.
+- [LDAP](../administration/auth/ldap/index.md): Configure LDAP to be used as
+ an authentication mechanism for GitLab.
+- [Back up and restore GitLab](../raketasks/backup_restore.md): Learn the different
+ ways you can back up or restore GitLab.
+- [Upgrade GitLab](../update/README.md): Every 22nd of the month, a new feature-rich GitLab version
+ is released. Learn how to upgrade to it, or to an interim release that contains a security fix.
+- [Scaling GitLab](../administration/reference_architectures/index.md):
+ GitLab supports several different types of clustering.
+- [Advanced Search](../integration/elasticsearch.md): Leverage Elasticsearch for
+ faster, more advanced code search across your entire GitLab instance.
+- [Geo replication](../administration/geo/index.md):
+ Geo is the solution for widely distributed development teams.
+- [Release and maintenance policy](../policy/maintenance.md): Learn about GitLab's
+ policies governing version naming, as well as release pace for major, minor, patch,
+ and security releases.
+- [Pricing](https://about.gitlab.com/pricing/): Pricing for the different tiers.
diff --git a/doc/install/aws/index.md b/doc/install/aws/index.md
index aba76ecf50e..93ac17d823b 100644
--- a/doc/install/aws/index.md
+++ b/doc/install/aws/index.md
@@ -1,4 +1,7 @@
---
+stage: Enablement
+group: Distribution
+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/#designated-technical-writers
type: howto
---
@@ -463,7 +466,7 @@ Connect to your GitLab instance via **Bastion Host A** using [SSH Agent Forwardi
#### Disable Let's Encrypt
-Since we're adding our SSL certificate at the load balancer, we do not need GitLab's built-in support for Let's Encrypt. Let's Encrypt [is enabled by default](https://docs.gitlab.com/omnibus/settings/ssl.html#lets-encrypt-integration) when using an `https` domain since GitLab 10.7, so we need to explicitly disable it:
+Since we're adding our SSL certificate at the load balancer, we do not need GitLab's built-in support for Let's Encrypt. Let's Encrypt [is enabled by default](https://docs.gitlab.com/omnibus/settings/ssl.html#lets-encrypt-integration) when using an `https` domain in GitLab 10.7 and later, so we need to explicitly disable it:
1. Open `/etc/gitlab/gitlab.rb` and disable it:
diff --git a/doc/install/azure/index.md b/doc/install/azure/index.md
index b6e3025a0e0..b5e72a9b84a 100644
--- a/doc/install/azure/index.md
+++ b/doc/install/azure/index.md
@@ -422,7 +422,7 @@ on any cloud service you choose.
## Where to next?
-Check out our other [Technical Articles](../../articles/index.md) or browse the [GitLab Documentation](../../README.md) to learn more about GitLab.
+Check out our other [Technical Articles](../../topics/index.md) or browse the [GitLab Documentation](../../README.md) to learn more about GitLab.
### Useful links
diff --git a/doc/install/docker.md b/doc/install/docker.md
index c2d7655d526..ca780caa563 100644
--- a/doc/install/docker.md
+++ b/doc/install/docker.md
@@ -1,4 +1,7 @@
---
+stage: Enablement
+group: Distribution
+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/#designated-technical-writers
type: index
---
diff --git a/doc/install/google_cloud_platform/index.md b/doc/install/google_cloud_platform/index.md
index 8ca5c5c266a..da2b30df476 100644
--- a/doc/install/google_cloud_platform/index.md
+++ b/doc/install/google_cloud_platform/index.md
@@ -1,4 +1,7 @@
---
+stage: Enablement
+group: Distribution
+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/#designated-technical-writers
description: 'Learn how to install a GitLab instance on Google Cloud Platform.'
type: howto
---
diff --git a/doc/install/installation.md b/doc/install/installation.md
index e2c77073983..0adf09595e4 100644
--- a/doc/install/installation.md
+++ b/doc/install/installation.md
@@ -1,4 +1,7 @@
---
+stage: Enablement
+group: Distribution
+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/#designated-technical-writers
type: howto
---
@@ -66,7 +69,6 @@ of this page:
maintained for all projects. **This area contains critical data for projects.
[Keep a backup](../raketasks/backup_restore.md).**
-NOTE: **Note:**
The default locations for repositories can be configured in `config/gitlab.yml`
of GitLab and `config.yml` of GitLab Shell.
@@ -98,8 +100,9 @@ apt-get upgrade -y
apt-get install sudo -y
```
-NOTE: **Note:**
-During this installation, some files need to be edited manually. If you are familiar with vim, set it as default editor with the commands below. If you are not familiar with vim, skip this and keep using the default editor.
+During this installation, some files need to be edited manually. If you are familiar
+with vim, set it as default editor with the commands below. If you are not familiar
+with vim, skip this and keep using the default editor:
```shell
# Install vim and set as default editor
@@ -119,15 +122,13 @@ sudo apt-get install -y build-essential zlib1g-dev libyaml-dev libssl-dev libgdb
Ubuntu 14.04 (Trusty Tahr) doesn't have the `libre2-dev` package available, but
you can [install re2 manually](https://github.com/google/re2/wiki/Install).
-If you want to use Kerberos for user authentication, install `libkrb5-dev`:
+If you want to use Kerberos for user authentication, install `libkrb5-dev`
+(if you don't know what Kerberos is, you can assume you don't need it):
```shell
sudo apt-get install libkrb5-dev
```
-NOTE: **Note:**
-If you don't know what Kerberos is, you can assume you don't need it.
-
Make sure you have the right version of Git installed:
```shell
@@ -199,8 +200,11 @@ needs to be installed.
sudo apt-get install -y graphicsmagick
```
-NOTE: **Note:**
-In order to receive mail notifications, make sure to install a mail server. By default, Debian is shipped with exim4 but this [has problems](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/12754) while Ubuntu does not ship with one. The recommended mail server is postfix and you can install it with:
+In order to receive mail notifications, make sure to install a mail server.
+By default, Debian is shipped with `exim4` but this
+[has problems](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/12754) while
+Ubuntu does not ship with one. The recommended mail server is `postfix` and you
+can install it with:
```shell
sudo apt-get install -y postfix
@@ -218,10 +222,8 @@ sudo apt-get install -y libimage-exiftool-perl
## 2. Ruby
The Ruby interpreter is required to run GitLab.
-
-NOTE: **Note:**
-The current supported Ruby (MRI) version is 2.6.x. GitLab 12.2
-dropped support for Ruby 2.5.x.
+See the [requirements page](requirements.md#ruby-versions) for the minimum
+Ruby requirements.
The use of Ruby version managers such as [RVM](https://rvm.io/), [rbenv](https://github.com/rbenv/rbenv) or [chruby](https://github.com/postmodern/chruby) with GitLab
in production, frequently leads to hard to diagnose problems. Version managers
@@ -258,7 +260,7 @@ sudo gem install bundler --no-document --version '< 2'
## 3. Go
-Since GitLab 8.0, GitLab has several daemons written in Go. To install
+In GitLab 8.0 and later, GitLab has several daemons written in Go. To install
GitLab we need a Go compiler. The instructions below assume you use 64-bit
Linux. You can find downloads for other platforms at the [Go download
page](https://golang.org/dl).
@@ -276,7 +278,7 @@ rm go1.13.5.linux-amd64.tar.gz
## 4. Node
-Since GitLab 8.17, GitLab requires the use of Node to compile JavaScript
+In GitLab 8.17 and later, GitLab requires the use of Node to compile JavaScript
assets, and Yarn to manage JavaScript dependencies. The current minimum
requirements for these are:
@@ -311,14 +313,14 @@ sudo adduser --disabled-login --gecos 'GitLab' git
## 6. Database
NOTE: **Note:**
-Starting from GitLab 12.1, only PostgreSQL is supported. Since GitLab 13.0, we [require PostgreSQL 11+](requirements.md#postgresql-requirements).
+In GitLab 12.1 and later, only PostgreSQL is supported. In GitLab 13.0 and later, we [require PostgreSQL 11+](requirements.md#postgresql-requirements).
1. Install the database packages:
```shell
sudo apt-get install -y postgresql postgresql-client libpq-dev postgresql-contrib
```
-
+
1. Verify the PostgreSQL version you have is supported by the version of GitLab you're
installing:
@@ -407,7 +409,6 @@ Starting from GitLab 12.1, only PostgreSQL is supported. Since GitLab 13.0, we [
## 7. Redis
-NOTE: **Note:**
See the [requirements page](requirements.md#redis-versions) for the minimum
Redis requirements.
@@ -552,11 +553,9 @@ sudo -u git -H cp config/resque.yml.example config/resque.yml
sudo -u git -H editor config/resque.yml
```
-CAUTION: **Caution:**
Make sure to edit both `gitlab.yml` and `puma.rb` to match your setup.
If you want to use the Unicorn web server, see [Using Unicorn](#using-unicorn) for the additional steps.
-NOTE: **Note:**
If you want to use HTTPS, see [Using HTTPS](#using-https) for the additional steps.
### Configure GitLab DB Settings
@@ -596,13 +595,13 @@ Make sure you have `bundle` (run `bundle -v`):
- `>= 1.5.2`, because some [issues](https://devcenter.heroku.com/changelog-items/411) were [fixed](https://github.com/rubygems/bundler/pull/2817) in 1.5.2.
- `< 2.x`.
+Install the gems (if you want to use Kerberos for user authentication, omit
+`kerberos` in the `--without` option below):
+
```shell
sudo -u git -H bundle install --deployment --without development test mysql aws kerberos
```
-NOTE: **Note:**
-If you want to use Kerberos for user authentication, omit `kerberos` in the `--without` option above.
-
### Install GitLab Shell
GitLab Shell is an SSH access and repository management software developed specially for GitLab.
@@ -616,10 +615,8 @@ sudo -u git -H bundle exec rake gitlab:shell:install RAILS_ENV=production
sudo -u git -H editor /home/git/gitlab-shell/config.yml
```
-NOTE: **Note:**
If you want to use HTTPS, see [Using HTTPS](#using-https) for the additional steps.
-NOTE: **Note:**
Make sure your hostname can be resolved on the machine itself by either a proper DNS record or an additional line in `/etc/hosts` ("127.0.0.1 hostname"). This might be necessary, for example, if you set up GitLab behind a reverse proxy. If the hostname cannot be resolved, the final installation check fails with `Check GitLab API access: FAILED. code: 401` and pushing commits are rejected with `[remote rejected] master -> master (hook declined)`.
### Install GitLab Workhorse
@@ -638,7 +635,7 @@ You can specify a different Git repository by providing it as an extra parameter
sudo -u git -H bundle exec rake "gitlab:workhorse:install[/home/git/gitlab-workhorse,https://example.com/gitlab-workhorse.git]" RAILS_ENV=production
```
-### Install GitLab-Elasticsearch-indexer on Enterprise Edition
+### Install GitLab-Elasticsearch-indexer on Enterprise Edition **(STARTER ONLY)**
GitLab-Elasticsearch-Indexer uses [GNU Make](https://www.gnu.org/software/make/). The
following command-line installs GitLab-Elasticsearch-Indexer in `/home/git/gitlab-elasticsearch-indexer`
@@ -657,9 +654,6 @@ sudo -u git -H bundle exec rake "gitlab:indexer:install[/home/git/gitlab-elastic
The source code first is fetched to the path specified by the first parameter. Then a binary is built under its `bin` directory.
You then need to update `gitlab.yml`'s `production -> elasticsearch -> indexer_path` setting to point to that binary.
-NOTE: **Note:**
-Elasticsearch is a feature of GitLab Enterprise Edition and isn't included in GitLab Community Edition.
-
### Install GitLab Pages
GitLab Pages uses [GNU Make](https://www.gnu.org/software/make/). This step is optional and only needed if you wish to host static sites from within GitLab. The following commands install GitLab Pages in `/home/git/gitlab-pages`. For additional setup steps, consult the [administration guide](https://gitlab.com/gitlab-org/gitlab/blob/master/doc/administration/pages/source.md) for your version of GitLab as the GitLab Pages daemon can be run several different ways.
@@ -726,8 +720,7 @@ sudo -u git -H bundle exec rake gitlab:setup RAILS_ENV=production force=yes
# When done, you see 'Administrator account created:'
```
-NOTE: **Note:**
-You can set the Administrator/root password and e-mail by supplying them in environmental variables, `GITLAB_ROOT_PASSWORD` and `GITLAB_ROOT_EMAIL` respectively, as seen below. If you don't set the password (and it is set to the default one), wait to expose GitLab to the public internet until the installation is done and you've logged into the server the first time. During the first login, you'll be forced to change the default password. An Enterprise Edition license may also be installed at this time by supplying a full path in the `GITLAB_LICENSE_FILE` environment variable.
+You can set the Administrator/root password and email by supplying them in environmental variables, `GITLAB_ROOT_PASSWORD` and `GITLAB_ROOT_EMAIL` respectively, as seen below. If you don't set the password (and it is set to the default one), wait to expose GitLab to the public internet until the installation is done and you've logged into the server the first time. During the first login, you'll be forced to change the default password. An Enterprise Edition license may also be installed at this time by supplying a full path in the `GITLAB_LICENSE_FILE` environment variable.
```shell
sudo -u git -H bundle exec rake gitlab:setup RAILS_ENV=production GITLAB_ROOT_PASSWORD=yourpassword GITLAB_ROOT_EMAIL=youremail GITLAB_LICENSE_FILE="/path/to/license"
@@ -804,7 +797,6 @@ sudo /etc/init.d/gitlab restart
## 9. NGINX
-NOTE: **Note:**
NGINX is the officially supported web server for GitLab. If you cannot or do not want to use NGINX as your web server, see [GitLab recipes](https://gitlab.com/gitlab-org/gitlab-recipes/).
### Installation
@@ -841,7 +833,6 @@ If you intend to enable GitLab Pages, there is a separate NGINX config you need
to use. Read all about the needed configuration at the
[GitLab Pages administration guide](../administration/pages/index.md).
-NOTE: **Note:**
If you want to use HTTPS, replace the `gitlab` NGINX config with `gitlab-ssl`. See [Using HTTPS](#using-https) for HTTPS configuration details.
### Test Configuration
@@ -854,10 +845,18 @@ sudo nginx -t
You should receive `syntax is okay` and `test is successful` messages. If you receive errors check your `gitlab` or `gitlab-ssl` NGINX config file for typos, etc. as indicated in the error message given.
-NOTE: **Note:**
-Verify that the installed version is greater than 1.12.1 by running `nginx -v`. If it's lower, you may receive the error below:
-`nginx: [emerg] unknown "start$temp=[filtered]$rest" variable
-nginx: configuration file /etc/nginx/nginx.conf test failed`
+Verify that the installed version is greater than 1.12.1:
+
+```shell
+nginx -v
+```
+
+If it's lower, you may receive the error below:
+
+```plaintext
+nginx: [emerg] unknown "start$temp=[filtered]$rest" variable
+nginx: configuration file /etc/nginx/nginx.conf test failed
+```
### Restart
@@ -877,7 +876,8 @@ sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production
If all items are green, congratulations on successfully installing GitLab!
-NOTE: Supply `SANITIZE=true` environment variable to `gitlab:check` to omit project names from the output of the check command.
+TIP: **Tip:**
+Supply the `SANITIZE=true` environment variable to `gitlab:check` to omit project names from the output of the check command.
### Initial Login
diff --git a/doc/install/openshift_and_gitlab/index.md b/doc/install/openshift_and_gitlab/index.md
index 022e2095c68..7ac5aa6667a 100644
--- a/doc/install/openshift_and_gitlab/index.md
+++ b/doc/install/openshift_and_gitlab/index.md
@@ -1,6 +1,8 @@
---
+stage: Enablement
+group: Distribution
+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/#designated-technical-writers
type: howto
-date: 2016-06-28
---
# How to install GitLab on OpenShift Origin 3
@@ -372,7 +374,7 @@ running scaled to 2.
Upping the GitLab pods is actually like adding new application servers to your
cluster. You can see how that would work if you didn't use GitLab with
-OpenShift by following the [HA documentation](../../administration/high_availability/gitlab.md) for the application servers.
+OpenShift by following the [HA documentation](../../administration/reference_architectures/index.md) for the application servers.
Bare in mind that you may need more resources (CPU, RAM, disk space) when you
scale up. If a pod is in pending state for too long, you can navigate to
diff --git a/doc/install/relative_url.md b/doc/install/relative_url.md
index 09069a2d1fd..82cf134f968 100644
--- a/doc/install/relative_url.md
+++ b/doc/install/relative_url.md
@@ -1,4 +1,7 @@
---
+stage: Enablement
+group: Distribution
+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/#designated-technical-writers
type: reference
---
diff --git a/doc/install/requirements.md b/doc/install/requirements.md
index da0128fecc3..bc320bcd335 100644
--- a/doc/install/requirements.md
+++ b/doc/install/requirements.md
@@ -1,4 +1,7 @@
---
+stage: Enablement
+group: Distribution
+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/#designated-technical-writers
type: reference
---
diff --git a/doc/install/structure.md b/doc/install/structure.md
index 87ef11c60fe..ca90a3de1b8 100644
--- a/doc/install/structure.md
+++ b/doc/install/structure.md
@@ -2,4 +2,4 @@
redirect_to: installation.md#gitlab-directory-structure
---
-This page was moved to [another location](#installation.md#gitlab-directory-structure).
+This page was moved to [another location](installation.md#gitlab-directory-structure).
diff --git a/doc/integration/README.md b/doc/integration/README.md
index c5c21644d1c..c8ce367e99f 100644
--- a/doc/integration/README.md
+++ b/doc/integration/README.md
@@ -8,15 +8,8 @@ GitLab can be integrated with external services for enhanced functionality.
## 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.
-
-GitLab can be integrated with the following external issue trackers:
-
-- Jira
-- Redmine
-- Bugzilla
-- EWM
-- YouTrack
+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.
## Authentication sources
@@ -26,10 +19,10 @@ GitLab can be configured to authenticate access requests with the following auth
- Enable sign in with [Bitbucket](bitbucket.md) accounts.
- Configure GitLab to sign in using [CAS](cas.md).
- Integrate with [Kerberos](kerberos.md).
-- Enable sign in via [LDAP](ldap.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 via Twitter, GitHub, GitLab.com, Google,
-Bitbucket, Facebook, Shibboleth, SAML, Crowd, Azure or Authentiq ID.
+ Bitbucket, Facebook, Shibboleth, SAML, Crowd, Azure or Authentiq ID.
- 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.
diff --git a/doc/integration/cas.md b/doc/integration/cas.md
index cf4e501e772..eee801350eb 100644
--- a/doc/integration/cas.md
+++ b/doc/integration/cas.md
@@ -45,10 +45,10 @@ To enable the CAS OmniAuth provider you must register your application with your
- { name: 'cas3',
label: 'cas',
args: {
- url: 'CAS_SERVER',
- login_url: '/CAS_PATH/login',
- service_validate_url: '/CAS_PATH/p3/serviceValidate',
- logout_url: '/CAS_PATH/logout'} }
+ url: 'CAS_SERVER',
+ login_url: '/CAS_PATH/login',
+ service_validate_url: '/CAS_PATH/p3/serviceValidate',
+ logout_url: '/CAS_PATH/logout' } }
```
1. Change 'CAS_PATH' to the root of your CAS instance (ie. `cas`).
diff --git a/doc/integration/elasticsearch.md b/doc/integration/elasticsearch.md
index f40955ad8ff..a88f2db5c26 100644
--- a/doc/integration/elasticsearch.md
+++ b/doc/integration/elasticsearch.md
@@ -10,8 +10,8 @@ info: To determine the technical writer assigned to the Stage/Group associated w
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/109 "Elasticsearch Merge Request") in GitLab [Starter](https://about.gitlab.com/pricing/) 8.4.
> - Support for [Amazon Elasticsearch](https://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/es-gsg.html) was [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/1305) in GitLab [Starter](https://about.gitlab.com/pricing/) 9.0.
-This document describes how to set up Elasticsearch with GitLab. After
-Elasticsearch is enabled, you'll have the benefit of fast search response times
+This document describes how to enable Advanced Search. After
+Advanced Search is enabled, you'll have the benefit of fast search response times
and the advantage of the following special searches:
- [Advanced Search](../user/search/advanced_global_search.md)
@@ -66,21 +66,19 @@ source. You must [install it separately](https://www.elastic.co/guide/en/elastic
Be sure to select your version. Providing detailed information on installing
Elasticsearch is out of the scope of this document.
-NOTE: **Note:**
Elasticsearch should be installed on a separate server, whether you install
it yourself or use a cloud hosted offering like Elastic's [Elasticsearch Service](https://www.elastic.co/elasticsearch/service)
(available on AWS, GCP, or Azure) or the [Amazon Elasticsearch](https://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/es-gsg.html)
service. Running Elasticsearch on the same server as GitLab is not recommended
and can cause a degradation in GitLab instance performance.
-NOTE: **Note:**
**For a single node Elasticsearch cluster the functional cluster health status
will be yellow** (will never be green) because the primary shard is allocated but
replicas can not be as there is no other node to which Elasticsearch can assign a
replica.
After the data is added to the database or repository and [Elasticsearch is
-enabled in the Admin Area](#enabling-elasticsearch) the search index will be
+enabled in the Admin Area](#enabling-advanced-search) the search index will be
updated automatically.
## Elasticsearch repository indexer
@@ -155,15 +153,19 @@ Example:
PREFIX=/usr sudo -E make install
```
-After installation, be sure to [enable Elasticsearch](#enabling-elasticsearch).
-
-## Enabling Elasticsearch
+After installation, be sure to [enable Elasticsearch](#enabling-advanced-search).
NOTE: **Note:**
+If you see an error such as `Permission denied - /home/git/gitlab-elasticsearch-indexer/` while indexing, you
+may need to set the `production -> elasticsearch -> indexer_path` setting in your `gitlab.yml` file to
+`/usr/local/bin/gitlab-elasticsearch-indexer`, which is where the binary is installed.
+
+## Enabling Advanced Search
+
For GitLab instances with more than 50GB repository data you can follow the instructions for [Indexing large
instances](#indexing-large-instances) below.
-To enable Elasticsearch, you need to have admin access to GitLab:
+To enable Advanced Search, you need to have admin access to GitLab:
1. Navigate to **Admin Area** (wrench icon), then **Settings > General**
and expand the **Advanced Search** section.
@@ -172,23 +174,12 @@ To enable Elasticsearch, you need to have admin access to GitLab:
To see the Advanced Search section, you need an active Starter
[license](../user/admin_area/license.md).
-1. Configure the [Elasticsearch settings](#elasticsearch-configuration) for
- your Elasticsearch cluster. Do not enable **Elasticsearch indexing** or
- **Search with Elasticsearch enabled** yet.
-1. Click **Save changes** for the changes to take effect.
-1. Before enabling **Elasticsearch indexing** you need to create an index by
- running the Rake task:
-
- ```shell
- # Omnibus installations
- sudo gitlab-rake gitlab:elastic:create_empty_index
-
- # Installations from source
- bundle exec rake gitlab:elastic:create_empty_index RAILS_ENV=production
- ```
-
-1. Now enable `Elasticsearch indexing` in **Admin Area > Settings >
- General > Advanced Search** and click **Save changes**.
+1. Configure the [Advanced Search settings](#advanced-search-configuration) for
+ your Elasticsearch cluster. Do not enable **Search with Elasticsearch enabled**
+ yet.
+1. Now enable **Elasticsearch indexing** in **Admin Area > Settings >
+ General > Advanced Search** and click **Save changes**. This will create
+ an empty index if one does not already exist.
1. Click **Index all projects**.
1. Click **Check progress** in the confirmation message to see the status of
the background jobs.
@@ -206,13 +197,13 @@ To enable Elasticsearch, you need to have admin access to GitLab:
**Admin Area > Settings > General > Advanced Search** and click **Save
changes**.
-### Elasticsearch configuration
+### Advanced Search configuration
The following Elasticsearch settings are available:
| Parameter | Description |
|-------------------------------------------------------|-------------|
-| `Elasticsearch indexing` | Enables or disables Elasticsearch indexing. You may want to enable indexing but disable search in order to give the index time to be fully completed, for example. Also, keep in mind that this option doesn't have any impact on existing data, this only enables/disables the background indexer which tracks data changes and ensures new data is indexed. |
+| `Elasticsearch indexing` | Enables or disables Elasticsearch indexing and creates an empty index if one does not already exist. You may want to enable indexing but disable search in order to give the index time to be fully completed, for example. Also, keep in mind that this option doesn't have any impact on existing data, this only enables/disables the background indexer which tracks data changes and ensures new data is indexed. |
| `Pause Elasticsearch indexing` | Enables or disables temporary indexing pause. This is useful for cluster migration/reindexing. All changes are still tracked, but they are not committed to the Elasticsearch index until unpaused. |
| `Search with Elasticsearch enabled` | Enables or disables using Elasticsearch in search. |
| `URL` | The URL to use for connecting to Elasticsearch. Use a comma-separated list to support clustering (e.g., `http://host1, https://host2:9200`). If your Elasticsearch instance is password protected, pass the `username:password` in the URL (e.g., `http://<username>:<password>@<elastic_host>:9200/`). |
@@ -238,14 +229,14 @@ If you select `Limit namespaces and projects that can be indexed`, more options
You can select namespaces and projects to index exclusively. Note that if the namespace is a group it will include
any sub-groups and projects belonging to those sub-groups to be indexed as well.
-Elasticsearch 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 will not provide a code or commit scope. This will be possible only in the scope of an indexed namespace. Currently there is no way to code/commit search in multiple indexed namespaces (when only a subset of namespaces has been indexed). For example if two groups are indexed, there is no way to run a single code search on both. You can only run a code search on the first group and then on the second.
+Advanced Search only provides cross-group code/commit search (global) if all name-spaces are indexed. In this particular scenario where only a subset of namespaces are indexed, a global search will not provide a code or commit scope. This will be possible only in the scope of an indexed namespace. Currently 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.
![limit namespace filter](img/limit_namespace_filter.png)
NOTE: **Note:**
-If no namespaces or projects are selected, no Elasticsearch indexing will take place.
+If no namespaces or projects are selected, no Advanced Search indexing will take place.
CAUTION: **Warning:**
If you have already indexed your instance, you will have to regenerate the index in order to delete all existing data
@@ -253,7 +244,7 @@ for filtering to work correctly. To do this run the Rake tasks `gitlab:elastic:r
`gitlab:elastic:clear_index_status`. Afterwards, removing a namespace or a project from the list will delete the data
from the Elasticsearch index as expected.
-## Disabling Elasticsearch
+## Disabling Advanced Search
To disable the Elasticsearch integration:
@@ -283,7 +274,7 @@ alias such as we can change the underlying index at will.
NOTE: **Note:**
Any index attached to the production alias is deemed a `primary` and will be
-used by the GitLab Elasticsearch integration.
+used by the GitLab Advanced Search integration.
### Pause the indexing
@@ -315,7 +306,6 @@ CAUTION: **Caution:**
It is highly recommended that you take a snapshot of your cluster to ensure
there is a recovery path if anything goes wrong.
-NOTE: **Note:**
Due to a technical limitation, there will be a slight downtime because of the
fact that we need to reclaim the current `primary` index to be used as the alias.
@@ -413,7 +403,6 @@ To trigger the re-index from `primary` index:
Under **Admin Area > Settings > General > Advanced Search > Elasticsearch zero-downtime reindexing**, click on **Trigger cluster reindexing**.
-NOTE: **Note:**
Reindexing can be a lengthy process depending on the size of your Elasticsearch cluster.
CAUTION: **Caution:**
@@ -421,12 +410,12 @@ After the reindexing is completed, the original index will be scheduled to be de
While the reindexing is running, you will be able to follow its progress under that same section.
-## GitLab Elasticsearch Rake tasks
+## GitLab Advanced Search Rake tasks
Rake tasks are available to:
- [Build and install](#building-and-installing) the indexer.
-- Delete indexes when [disabling Elasticsearch](#disabling-elasticsearch).
+- Delete indexes when [disabling Elasticsearch](#disabling-advanced-search).
- Add GitLab data to an index.
The following are some available Rake tasks:
@@ -436,7 +425,7 @@ The following are some available Rake tasks:
| [`sudo gitlab-rake gitlab:elastic:index`](https://gitlab.com/gitlab-org/gitlab/blob/master/ee/lib/tasks/gitlab/elastic.rake) | Enables Elasticsearch indexing and run `gitlab:elastic:create_empty_index`, `gitlab:elastic:clear_index_status`, `gitlab:elastic:index_projects`, and `gitlab:elastic:index_snippets`. |
| [`sudo gitlab-rake gitlab:elastic:index_projects`](https://gitlab.com/gitlab-org/gitlab/blob/master/ee/lib/tasks/gitlab/elastic.rake) | Iterates over all projects and queues Sidekiq jobs to index them in the background. |
| [`sudo gitlab-rake gitlab:elastic:index_projects_status`](https://gitlab.com/gitlab-org/gitlab/blob/master/ee/lib/tasks/gitlab/elastic.rake) | Determines the overall status of the indexing. It is done by counting the total number of indexed projects, dividing by a count of the total number of projects, then multiplying by 100. |
-| [`sudo gitlab-rake gitlab:elastic:clear_index_status`](https://gitlab.com/gitlab-org/gitlab/blob/master/ee/lib/tasks/gitlab/elastic.rake) | Deletes all instances of IndexStatus for all projects. |
+| [`sudo gitlab-rake gitlab:elastic:clear_index_status`](https://gitlab.com/gitlab-org/gitlab/blob/master/ee/lib/tasks/gitlab/elastic.rake) | Deletes all instances of IndexStatus for all projects. Note that this command will result in a complete wipe of the index, and it should be used with caution. |
| [`sudo gitlab-rake gitlab:elastic:create_empty_index[<TARGET_NAME>]`](https://gitlab.com/gitlab-org/gitlab/blob/master/ee/lib/tasks/gitlab/elastic.rake) | Generates an empty index and assigns an alias for it on the Elasticsearch side only if it doesn't already exist. |
| [`sudo gitlab-rake gitlab:elastic:delete_index[<TARGET_NAME>]`](https://gitlab.com/gitlab-org/gitlab/blob/master/ee/lib/tasks/gitlab/elastic.rake) | Removes the GitLab index and alias (if exists) on the Elasticsearch instance. |
| [`sudo gitlab-rake gitlab:elastic:recreate_index[<TARGET_NAME>]`](https://gitlab.com/gitlab-org/gitlab/blob/master/ee/lib/tasks/gitlab/elastic.rake) | Wrapper task for `gitlab:elastic:delete_index[<TARGET_NAME>]` and `gitlab:elastic:create_empty_index[<TARGET_NAME>]`. |
@@ -467,7 +456,7 @@ Indexing project repositories...I, [2019-03-04T21:27:03.083410 #3384] INFO -- :
I, [2019-03-04T21:27:05.215266 #3384] INFO -- : Indexing GitLab User / test (ID=33) is done!
```
-## Elasticsearch index scopes
+## Advanced Search index scopes
When performing a search, the GitLab index will use the following scopes:
@@ -499,7 +488,7 @@ For basic guidance on choosing a cluster configuration you may refer to [Elastic
- `refresh_interval` is a per index setting. You may want to adjust that from default `1s` to a bigger value if you don't need data in realtime. This will change how soon you will see fresh results. If that's important for you, you should leave it as close as possible to the default value.
- You might want to raise [`indices.memory.index_buffer_size`](https://www.elastic.co/guide/en/elasticsearch/reference/current/indexing-buffer.html) to 30% or 40% if you have a lot of heavy indexing operations.
-### Elasticsearch integration settings guidance
+### Advanced Search integration settings guidance
- The `Number of Elasticsearch shards` setting usually corresponds with the number of CPUs available in your cluster. For example, if you have a 3-node cluster with 4 cores each, this means you will benefit from having at least 3*4=12 shards in the cluster. Please note, it's only possible to change the shards number by using [Split index API](https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-split-index.html) or by reindexing to a different index with a changed number of shards.
- The `Number of Elasticsearch replicas` setting should most of the time be equal to `1` (each shard will have 1 replica). Using `0` is not recommended, because losing one node will corrupt the index.
@@ -507,7 +496,7 @@ For basic guidance on choosing a cluster configuration you may refer to [Elastic
### Indexing large instances
This section may be helpful in the event that the other
-[basic instructions](#enabling-elasticsearch) cause problems
+[basic instructions](#enabling-advanced-search) cause problems
due to large volumes of data being indexed.
CAUTION: **Warning:**
@@ -516,7 +505,7 @@ Make sure to prepare for this task by having a [Scalable and Highly Available
Setup](../administration/reference_architectures/index.md) or creating [extra
Sidekiq processes](../administration/operations/extra_sidekiq_processes.md).
-1. [Configure your Elasticsearch host and port](#enabling-elasticsearch).
+1. [Configure your Elasticsearch host and port](#enabling-advanced-search).
1. Create empty indexes:
```shell
@@ -537,7 +526,7 @@ Sidekiq processes](../administration/operations/extra_sidekiq_processes.md).
bundle exec rake gitlab:elastic:clear_index_status RAILS_ENV=production
```
-1. [Enable **Elasticsearch indexing**](#enabling-elasticsearch).
+1. [Enable **Elasticsearch indexing**](#enabling-advanced-search).
1. Indexing large Git repositories can take a while. To speed up the process, you can [tune for indexing speed](https://www.elastic.co/guide/en/elasticsearch/reference/current/tune-for-indexing-speed.html#tune-for-indexing-speed):
- You can temporarily disable [`refresh`](https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-refresh.html), the operation responsible for making changes to an index available to search.
@@ -664,7 +653,7 @@ Sidekiq processes](../administration/operations/extra_sidekiq_processes.md).
} }'
```
-1. After the indexing has completed, enable [**Search with Elasticsearch enabled**](#enabling-elasticsearch).
+1. After the indexing has completed, enable [**Search with Elasticsearch enabled**](#enabling-advanced-search).
### Deleted documents
@@ -698,96 +687,114 @@ However, some larger installations may wish to tune the merge policy settings:
## Troubleshooting
-### Common issues
+Here are some common pitfalls and how to overcome them.
+
+### How can I verify that my GitLab instance is using Elasticsearch?
-Here are some common pitfalls and how to overcome them:
+There are a couple of ways to achieve that:
-- **How can I verify my GitLab instance is using Elasticsearch?**
+- Whenever you perform a search there will be a link on the search results page
+ in the top right hand corner saying "Advanced search functionality is enabled".
+ This is always correctly identifying whether the current project/namespace
+ being searched is using Elasticsearch.
- The easiest method is via the rails console (`sudo gitlab-rails console`) by running the following:
+- From the admin area under **Settings > General > Elasticsearch** check that the
+ Advanced Search settings are checked.
+
+ Those same settings there can be obtained from the Rails console if necessary:
```ruby
- u = User.find_by_username('your-username')
- s = SearchService.new(u, {:search => 'search_term'})
- pp s.search_objects.class.name
+ ::Gitlab::CurrentSettings.elasticsearch_search? # Whether or not searches will use Elasticsearch
+ ::Gitlab::CurrentSettings.elasticsearch_indexing? # Whether or not content will be indexed in Elasticsearch
+ ::Gitlab::CurrentSettings.elasticsearch_limit_indexing? # Whether or not Elasticsearch is limited only to certain projects/namespaces
```
- If you see `"ActiveRecord::Relation"`, you are **not** using Elasticsearch.
-
- If you see `"Kaminari::PaginatableArray"` you are using Elasticsearch.
+- If Elasticsearch is limited to specific namespaces and you need to know if
+ Elasticsearch is being used for a specific project or namespace, you can use
+ the Rails console:
- NOTE: **Note:**
- The above instructions are used to verify that GitLab is using Elasticsearch only when indexing all namespaces. This is not to be used for scenarios that only index a [subset of namespaces](#limiting-namespaces-and-projects).
+ ```ruby
+ ::Gitlab::CurrentSettings.search_using_elasticsearch?(scope: Namespace.find_by_full_path("/my-namespace"))
+ ::Gitlab::CurrentSettings.search_using_elasticsearch?(scope: Project.find_by_full_path("/my-namespace/my-project"))
+ ```
-- **I updated GitLab and now I can't find anything**
+### I updated GitLab and now I can't find anything
- We continuously make updates to our indexing strategies and aim to support
- newer versions of Elasticsearch. When indexing changes are made, it may
- be necessary for you to [reindex](#zero-downtime-reindexing) after updating GitLab.
+We continuously make updates to our indexing strategies and aim to support
+newer versions of Elasticsearch. When indexing changes are made, it may
+be necessary for you to [reindex](#zero-downtime-reindexing) after updating GitLab.
-- **I indexed all the repositories but I can't find anything**
+### I indexed all the repositories but I can't get any hits for my search term in the UI
- Make sure you indexed all the database data [as stated above](#enabling-elasticsearch).
+Make sure you indexed all the database data [as stated above](#enabling-advanced-search).
- Beyond that, check via the [Elasticsearch Search API](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-search.html) to see if the data shows up on the Elasticsearch side.
+If there aren't any results (hits) in the UI search, check if you are seeing the same results via the rails console (`sudo gitlab-rails console`):
- If it shows up via the [Elasticsearch Search API](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-search.html), check that it shows up via the rails console (`sudo gitlab-rails console`):
+```ruby
+u = User.find_by_username('your-username')
+s = SearchService.new(u, {:search => 'search_term', :scope => 'blobs'})
+pp s.search_objects.to_a
+```
- ```ruby
- u = User.find_by_username('your-username')
- s = SearchService.new(u, {:search => 'search_term', :scope => 'blobs'})
- pp s.search_objects.to_a
- ```
+Beyond that, check via the [Elasticsearch Search API](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-search.html) to see if the data shows up on the Elasticsearch side:
- NOTE: **Note:**
- The above instructions are not to be used for scenarios that only index a [subset of namespaces](#limiting-namespaces-and-projects).
+```shell
+curl --request GET <elasticsearch_server_ip>:9200/gitlab-production/_search?q=<search_term>
+```
- See [Elasticsearch Index Scopes](#elasticsearch-index-scopes) for more information on searching for specific types of data.
+More [complex Elasticsearch API calls](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-filter-context.html) are also possible.
-- **I indexed all the repositories but then switched Elasticsearch servers and now I can't find anything**
+It is important to understand at which level the problem is manifesting (UI, Rails code, Elasticsearch side) to be able to [troubleshoot further](../administration/troubleshooting/elasticsearch.md#search-results-workflow).
- You will need to re-run all the Rake tasks to reindex the database, repositories, and wikis.
+NOTE: **Note:**
+The above instructions are not to be used for scenarios that only index a [subset of namespaces](#limiting-namespaces-and-projects).
-- **The indexing process is taking a very long time**
+See [Elasticsearch Index Scopes](#advanced-search-index-scopes) for more information on searching for specific types of data.
- The more data present in your GitLab instance, the longer the indexing process takes.
+### I indexed all the repositories but then switched Elasticsearch servers and now I can't find anything
-- **There are some projects that weren't indexed, but we don't know which ones**
+You will need to re-run all the Rake tasks to reindex the database, repositories, and wikis.
- You can run `sudo gitlab-rake gitlab:elastic:projects_not_indexed` to display projects that aren't indexed.
+### The indexing process is taking a very long time
-- **No new data is added to the Elasticsearch index when I push code**
+The more data present in your GitLab instance, the longer the indexing process takes.
- NOTE: **Note:**
- This was [fixed in GitLab 13.2](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/35936) and the Rake task is not available for versions greater than that.
+### There are some projects that weren't indexed, but I don't know which ones
- When performing the initial indexing of blobs, we lock all projects until the project finishes indexing. It could happen that an error during the process causes one or multiple projects to remain locked. In order to unlock them, run:
+You can run `sudo gitlab-rake gitlab:elastic:projects_not_indexed` to display projects that aren't indexed.
- ```shell
- sudo gitlab-rake gitlab:elastic:clear_locked_projects
- ```
+### No new data is added to the Elasticsearch index when I push code
-- **"Can't specify parent if no parent field has been configured"**
+NOTE: **Note:**
+This was [fixed in GitLab 13.2](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/35936) and the Rake task is not available for versions greater than that.
- If you enabled Elasticsearch before GitLab 8.12 and have not rebuilt indexes you will get
- exception in lots of different cases:
+When performing the initial indexing of blobs, we lock all projects until the project finishes indexing. It could happen that an error during the process causes one or multiple projects to remain locked. In order to unlock them, run:
- ```plaintext
- Elasticsearch::Transport::Transport::Errors::BadRequest([400] {
- "error": {
- "root_cause": [{
- "type": "illegal_argument_exception",
- "reason": "Can't specify parent if no parent field has been configured"
- }],
- "type": "illegal_argument_exception",
- "reason": "Can't specify parent if no parent field has been configured"
- },
- "status": 400
- }):
- ```
+```shell
+sudo gitlab-rake gitlab:elastic:clear_locked_projects
+```
- This is because we changed the index mapping in GitLab 8.12 and the old indexes should be removed and built from scratch again,
- see details in the [update guide](../update/upgrading_from_source.md).
+### `Can't specify parent if no parent field has been configured` error
+
+If you enabled Elasticsearch before GitLab 8.12 and have not rebuilt indexes you will get
+exception in lots of different cases:
+
+```plaintext
+Elasticsearch::Transport::Transport::Errors::BadRequest([400] {
+ "error": {
+ "root_cause": [{
+ "type": "illegal_argument_exception",
+ "reason": "Can't specify parent if no parent field has been configured"
+ }],
+ "type": "illegal_argument_exception",
+ "reason": "Can't specify parent if no parent field has been configured"
+ },
+ "status": 400
+}):
+```
+
+This is because we changed the index mapping in GitLab 8.12 and the old indexes should be removed and built from scratch again,
+see details in the [update guide](../update/upgrading_from_source.md).
- Exception `Elasticsearch::Transport::Transport::Errors::BadRequest`
@@ -809,50 +816,51 @@ Here are some common pitfalls and how to overcome them:
for this setting ("Maximum Size of HTTP Request Payloads"), based on the size of
the underlying instance.
-- **My single node Elasticsearch cluster status never goes from `yellow` to `green` even though everything seems to be running properly**
+### My single node Elasticsearch cluster status never goes from `yellow` to `green` even though everything seems to be running properly
- **For a single node Elasticsearch cluster the functional cluster health status will be yellow** (will never be green) because the primary shard is allocated but replicas can not be as there is no other node to which Elasticsearch can assign a replica. This also applies if you are using the
-[Amazon Elasticsearch](https://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/aes-handling-errors.html#aes-handling-errors-yellow-cluster-status) service.
+**For a single node Elasticsearch cluster the functional cluster health status will be yellow** (never green) because the primary shard is allocated but replicas cannot be as there is no other node to which Elasticsearch can assign a replica. This also applies if you are using the [Amazon Elasticsearch](https://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/aes-handling-errors.html#aes-handling-errors-yellow-cluster-status) service.
- CAUTION: **Warning:**
- Setting the number of replicas to `0` is not something that we recommend (this is not allowed in the GitLab Elasticsearch Integration menu). If you are planning to add more Elasticsearch nodes (for a total of more than 1 Elasticsearch) the number of replicas will need to be set to an integer value larger than `0`. Failure to do so will result in lack of redundancy (losing one node will corrupt the index).
+CAUTION: **Warning:**
+Setting the number of replicas to `0` is discouraged (this is not allowed in the GitLab Elasticsearch Integration menu). If you are planning to add more Elasticsearch nodes (for a total of more than 1 Elasticsearch) the number of replicas will need to be set to an integer value larger than `0`. Failure to do so will result in lack of redundancy (losing one node will corrupt the index).
- If you have a **hard requirement to have a green status for your single node Elasticsearch cluster**, please make sure you understand the risks outlined in the previous paragraph and then simply run the following query to set the number of replicas to `0`(the cluster will no longer try to create any shard replicas):
+If you have a **hard requirement to have a green status for your single node Elasticsearch cluster**, please make sure you understand the risks outlined in the previous paragraph and then run the following query to set the number of replicas to `0`(the cluster will no longer try to create any shard replicas):
- ```shell
- curl --request PUT localhost:9200/gitlab-production/_settings --header 'Content-Type: application/json' --data '{
- "index" : {
- "number_of_replicas" : 0
- }
- }'
- ```
+```shell
+curl --request PUT localhost:9200/gitlab-production/_settings --header 'Content-Type: application/json' --data '{
+"index" : {
+ "number_of_replicas" : 0
+ }
+}'
+```
-- **I'm getting a `health check timeout: no Elasticsearch node available` error in Sidekiq during the indexing process**
+### `health check timeout: no Elasticsearch node available` error in Sidekiq
- ```plaintext
- Gitlab::Elastic::Indexer::Error: time="2020-01-23T09:13:00Z" level=fatal msg="health check timeout: no Elasticsearch node available"
- ```
+If you're getting a `health check timeout: no Elasticsearch node available` error in Sidekiq during the indexing process:
+
+```plaintext
+Gitlab::Elastic::Indexer::Error: time="2020-01-23T09:13:00Z" level=fatal msg="health check timeout: no Elasticsearch node available"
+```
- You probably have not used either `http://` or `https://` as part of your value in the **"URL"** field of the Elasticsearch Integration Menu. Please make sure you are using either `http://` or `https://` in this field as the [Elasticsearch client for Go](https://github.com/olivere/elastic) that we are using [needs the prefix for the URL to be accepted as valid](https://github.com/olivere/elastic/commit/a80af35aa41856dc2c986204e2b64eab81ccac3a).
- Once you have corrected the formatting of the URL, delete the index (via the [dedicated Rake task](#gitlab-elasticsearch-rake-tasks)) and [reindex the content of your instance](#enabling-elasticsearch).
+You probably have not used either `http://` or `https://` as part of your value in the **"URL"** field of the Elasticsearch Integration Menu. Please make sure you are using either `http://` or `https://` in this field as the [Elasticsearch client for Go](https://github.com/olivere/elastic) that we are using [needs the prefix for the URL to be accepted as valid](https://github.com/olivere/elastic/commit/a80af35aa41856dc2c986204e2b64eab81ccac3a).
+Once you have corrected the formatting of the URL, delete the index (via the [dedicated Rake task](#gitlab-advanced-search-rake-tasks)) and [reindex the content of your instance](#enabling-advanced-search).
### Low-level troubleshooting
There is a [more structured, lower-level troubleshooting document](../administration/troubleshooting/elasticsearch.md) for when you experience other issues, including poor performance.
-### Known Issues
+### Known issues
-- **[Elasticsearch `code_analyzer` doesn't account for all code cases](https://gitlab.com/groups/gitlab-org/-/epics/3621)**
+[Elasticsearch `code_analyzer` doesn't account for all code cases](https://gitlab.com/groups/gitlab-org/-/epics/3621).
- The `code_analyzer` pattern and filter configuration is being evaluated for improvement. We have fixed [most edge cases](https://gitlab.com/groups/gitlab-org/-/epics/3621#note_363429094) that were not returning expected search results due to our pattern and filter configuration.
+The `code_analyzer` pattern and filter configuration is being evaluated for improvement. We have fixed [most edge cases](https://gitlab.com/groups/gitlab-org/-/epics/3621#note_363429094) that were not returning expected search results due to our pattern and filter configuration.
- Improvements to the `code_analyzer` pattern and filters is being discussed in [epic 3621](https://gitlab.com/groups/gitlab-org/-/epics/3621).
+Improvements to the `code_analyzer` pattern and filters are being discussed in [epic 3621](https://gitlab.com/groups/gitlab-org/-/epics/3621).
### Reverting to Basic Search
Sometimes there may be issues with your Elasticsearch index data and as such
GitLab will allow you to revert to "basic search" when there are no search
results and assuming that basic search is supported in that scope. This "basic
-search" will behave as though you don't have Elasticsearch enabled at all for
+search" will behave as though you don't have Advanced Search enabled at all for
your instance and search using other data sources (ie. PostgreSQL data and Git
data).
diff --git a/doc/integration/external-issue-tracker.md b/doc/integration/external-issue-tracker.md
index cde0093f53e..96c9b9d7f62 100644
--- a/doc/integration/external-issue-tracker.md
+++ b/doc/integration/external-issue-tracker.md
@@ -1,7 +1,7 @@
# External issue tracker
-GitLab has a great [issue tracker](../user/project/issues/index.md) but you can also use an external one
-such as Jira, Redmine, YouTrack, Bugzilla, or EWM. External issue trackers are configurable per GitLab project.
+GitLab has a great [issue tracker](../user/project/issues/index.md) but you can also use an external
+one. External issue trackers are configurable per GitLab project.
Once configured, you can reference external issues using the format `CODE-123`, where:
@@ -15,24 +15,23 @@ GitLab menu always opens the internal issue tracker. When disabled, the link is
## Configuration
-The configuration is done via a project's **Integrations**.
+The configuration is done via a project's **Settings > Integrations**.
### Integration
To enable an external issue tracker you must configure the appropriate **Integration**.
Visit the links below for details:
-- [Redmine](../user/project/integrations/redmine.md)
-- [YouTrack](../user/project/integrations/youtrack.md)
-- [Jira](../user/project/integrations/jira.md)
- [Bugzilla](../user/project/integrations/bugzilla.md)
-- [EWM](../user/project/integrations/ewm.md)
- [Custom Issue Tracker](../user/project/integrations/custom_issue_tracker.md)
+- [Engineering Workflow Management](../user/project/integrations/ewm.md)
+- [Jira](../user/project/integrations/jira.md)
+- [Redmine](../user/project/integrations/redmine.md)
+- [YouTrack](../user/project/integrations/youtrack.md)
### Service Template
-To save you the hassle from configuring each project's service individually,
-GitLab provides the ability to set Service Templates which can then be
-overridden in each project's settings.
+To avoid configuring each project's service individually, GitLab provides the ability to set
+Service Templates. These can then be overridden in each project's settings.
Read more on [Services Templates](../user/project/integrations/services_templates.md).
diff --git a/doc/integration/facebook.md b/doc/integration/facebook.md
index fc65191994d..dbefb560fe7 100644
--- a/doc/integration/facebook.md
+++ b/doc/integration/facebook.md
@@ -83,7 +83,7 @@ To enable the Facebook OmniAuth provider you must register your application with
```yaml
- { name: 'facebook', app_id: 'YOUR_APP_ID',
- app_secret: 'YOUR_APP_SECRET' }
+ app_secret: 'YOUR_APP_SECRET' }
```
1. Change 'YOUR_APP_ID' to the API key from Facebook page in step 10.
diff --git a/doc/integration/github.md b/doc/integration/github.md
index ccce4672cbf..ce2b50acc54 100644
--- a/doc/integration/github.md
+++ b/doc/integration/github.md
@@ -71,17 +71,18 @@ Follow these steps to incorporate the GitHub OAuth 2 app in your GitLab server:
```yaml
- { name: 'github', app_id: 'YOUR_APP_ID',
- app_secret: 'YOUR_APP_SECRET',
- args: { scope: 'user:email' } }
+ app_secret: 'YOUR_APP_SECRET',
+ args: { scope: 'user:email' } }
```
For GitHub Enterprise:
```yaml
- - { name: 'github', app_id: 'YOUR_APP_ID',
- app_secret: 'YOUR_APP_SECRET',
- url: "https://github.example.com/",
- args: { scope: 'user:email' } }
+ - { name: 'github',
+ app_id: 'YOUR_APP_ID',
+ app_secret: 'YOUR_APP_SECRET',
+ url: "https://github.example.com/",
+ args: { scope: 'user:email' } }
```
**Replace `https://github.example.com/` with your GitHub URL.**
@@ -125,11 +126,12 @@ omnibus_gitconfig['system'] = { "http" => ["sslVerify = false"] }
For installation from source:
```yaml
-- { name: 'github', app_id: 'YOUR_APP_ID',
- app_secret: 'YOUR_APP_SECRET',
- url: "https://github.example.com/",
- verify_ssl: false,
- args: { scope: 'user:email' } }
+- { name: 'github',
+ app_id: 'YOUR_APP_ID',
+ app_secret: 'YOUR_APP_SECRET',
+ url: "https://github.example.com/",
+ verify_ssl: false,
+ args: { scope: 'user:email' } }
```
You will also need to disable Git SSL verification on the server hosting GitLab.
@@ -148,7 +150,7 @@ via Omnibus, or [restart GitLab](../administration/restart_gitlab.md#installatio
Check the [`production.log`](../administration/logs.md#productionlog)
on your GitLab server to obtain further details. If you are getting the error like
`Faraday::ConnectionFailed (execution expired)` in the log, there may be a connectivity issue
-between your GitLab instance and GitHub Enterprise. To verify it, [start the rails console](../administration/troubleshooting/debug.md#starting-a-rails-console-session)
+between your GitLab instance and GitHub Enterprise. To verify it, [start the rails console](../administration/operations/rails_console.md#starting-a-rails-console-session)
and run the commands below replacing `<github_url>` with the URL of your GitHub Enterprise instance:
```ruby
diff --git a/doc/integration/gitlab.md b/doc/integration/gitlab.md
index f423863ce8e..a200f6b6470 100644
--- a/doc/integration/gitlab.md
+++ b/doc/integration/gitlab.md
@@ -63,9 +63,10 @@ GitLab.com will generate an application ID and secret key for you to use.
For installations from source:
```yaml
- - { name: 'gitlab', app_id: 'YOUR_APP_ID',
- app_secret: 'YOUR_APP_SECRET',
- args: { scope: 'api' } }
+ - { name: 'gitlab',
+ app_id: 'YOUR_APP_ID',
+ app_secret: 'YOUR_APP_SECRET',
+ args: { scope: 'api' } }
```
1. Change 'YOUR_APP_ID' to the Application ID from the GitLab.com application page.
diff --git a/doc/integration/gitpod.md b/doc/integration/gitpod.md
index f26483e3b5e..b4d12b90be0 100644
--- a/doc/integration/gitpod.md
+++ b/doc/integration/gitpod.md
@@ -8,7 +8,8 @@ info: "To determine the technical writer assigned to the Stage/Group associated
# Gitpod Integration
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/228893) in GitLab 13.4.
-> - It's [deployed behind a feature flag](#enable-or-disable-the-gitpod-integration), disabled by default.
+> - It was [deployed behind a feature flag](#enable-or-disable-the-gitpod-integration), disabled by default.
+> - [Became enabled by default](https://gitlab.com/gitlab-org/gitlab/-/issues/258206) in GitLab 13.5.
> - It's enabled on GitLab.com.
> - It's recommended for production use.
> - To use it in GitLab self-managed instances, ask a GitLab administrator to [enable it](#configure-your-gitlab-instance-with-gitpod). **(CORE ONLY)**
@@ -50,25 +51,25 @@ can follow the same steps once the integration has been enabled and configured b
If you are new to Gitpod, head over to the [Gitpod documentation](https://www.gitpod.io/docs/self-hosted/latest/self-hosted/)
and get your instance up and running.
-1. In GitLab, go to **Admin Area > Settings > Integrations**.
+1. In GitLab, go to **Admin Area > Settings > General**.
1. Expand the **Gitpod** configuration section.
1. Check **Enable Gitpod**.
1. Add your Gitpod instance URL (for example, `https://gitpod.example.com`).
## Enable or disable the Gitpod integration **(CORE ONLY)**
-The Gitpod integration is under development and not ready for production use. It is deployed behind a
-feature flag that is **disabled by default**.
+The Gitpod integration is deployed behind a feature flag that is **enabled by default**.
[GitLab administrators with access to the GitLab Rails console](../administration/feature_flags.md)
-can enable it.
+can enable or disable it.
-To enable it:
+To disable it:
```ruby
-Feature.enable(:gitpod)
+Feature.disable(:gitpod)
```
-To disable it:
+To enable it:
```ruby
-Feature.disable(:gitpod)
+Feature.enable(:gitpod)
+```
diff --git a/doc/integration/google.md b/doc/integration/google.md
index 0f848bbc7aa..4cf589c1da8 100644
--- a/doc/integration/google.md
+++ b/doc/integration/google.md
@@ -84,9 +84,10 @@ On your GitLab server:
For installations from source:
```yaml
- - { name: 'google_oauth2', app_id: 'YOUR_APP_ID',
- app_secret: 'YOUR_APP_SECRET',
- args: { access_type: 'offline', approval_prompt: '' } }
+ - { name: 'google_oauth2',
+ app_id: 'YOUR_APP_ID',
+ app_secret: 'YOUR_APP_SECRET',
+ args: { access_type: 'offline', approval_prompt: '' } }
```
1. Change `YOUR_APP_ID` to the client ID from the Google Developer page
diff --git a/doc/integration/jira_development_panel.md b/doc/integration/jira_development_panel.md
index 9b7aa5829c1..b86eb1c38b6 100644
--- a/doc/integration/jira_development_panel.md
+++ b/doc/integration/jira_development_panel.md
@@ -148,7 +148,7 @@ GitLab. No other error messages appear in any logs.
If there was an issue with SSL/TLS, this error message will be generated.
-- The [GitLab Jira integration](jira.md) requires GitLab to connect to Jira. Any
+- The [GitLab Jira integration](../user/project/integrations/jira.md) requires GitLab to connect to Jira. Any
TLS issues that arise from a private certificate authority or self-signed
certificate [are resolved on the GitLab server](https://docs.gitlab.com/omnibus/settings/ssl.html#other-certificate-authorities),
as GitLab is the TLS client.
@@ -184,6 +184,16 @@ The message `Successfully connected` indicates a successful TLS handshake.
If there are problems, the Java TLS library generates errors that you can
look up for more detail.
+##### Scope error when connecting Jira via DVCS
+
+```plaintext
+The requested scope is invalid, unknown, or malformed.
+```
+
+Potential resolutions:
+
+- Verify the URL includes `scope=api` on the end of the URL.
+
##### Jira error adding account and no repositories listed
```plaintext
@@ -253,13 +263,18 @@ The GitLab for Jira App uses an iframe to add namespaces on the settings page. S
> "You need to sign in or sign up before continuing."
-In this case, enable cross-site cookies in your browser.
+In this case, use [Firefox](https://www.mozilla.org/en-US/firefox/), [Google Chrome](https://www.google.com/chrome/index.html) or enable cross-site cookies in your browser.
## Usage
-Once the integration is set up on GitLab and Jira you may refer any Jira issue by its ID in branch names, commit messages and merge request titles on GitLab's side,
-and you will be able to see the linked `branches`, `commits`, and `merge requests` when entering a Jira issue
-(inside the Jira issue, merge requests will be called "pull requests").
+After the integration is set up on GitLab and Jira, you can:
+
+- Refer to any Jira issue by its ID in GitLab branch names, commit messages, and merge request
+ titles.
+- See the linked branches, commits, and merge requests in Jira issues (merge requests are
+ called "pull requests" in Jira issues).
+
+Jira issue IDs must be formatted in uppercase for the integration to work.
![Branch, Commit and Pull Requests links on Jira issue](img/jira_dev_panel_jira_setup_3.png)
diff --git a/doc/integration/kerberos.md b/doc/integration/kerberos.md
index 1b14b5a986f..1a193deca18 100644
--- a/doc/integration/kerberos.md
+++ b/doc/integration/kerberos.md
@@ -1,3 +1,10 @@
+---
+stage: Create
+group: Source Code
+info: "To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers"
+type: reference, how-to
+---
+
# Kerberos integration **(STARTER ONLY)**
GitLab can integrate with [Kerberos](https://web.mit.edu/kerberos/) as an authentication mechanism.
@@ -114,6 +121,40 @@ Taken together, these rules mean that linking will only work if your users'
Kerberos usernames are of the form `foo@AD.EXAMPLE.COM` and their
LDAP Distinguished Names look like `sAMAccountName=foo,dc=ad,dc=example,dc=com`.
+### Custom allowed realms
+
+[Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/9962) in GitLab 13.5.
+
+You can configure custom allowed realms when
+the user's Kerberos realm doesn't match the domain from the user's LDAP DN. The
+configuration value must specify all domains that users may be expected to
+have. Any other domains will be ignored and an LDAP identity will not be linked.
+
+**For Omnibus installations**
+
+1. Edit `/etc/gitlab/gitlab.rb`:
+
+ ```ruby
+ gitlab_rails['kerberos_simple_ldap_linking_allowed_realms'] = ['example.com','kerberos.example.com']
+ ```
+
+1. Save the file and [reconfigure](../administration/restart_gitlab.md#omnibus-gitlab-reconfigure)
+ GitLab for the changes to take effect.
+
+---
+
+**For installations from source**
+
+1. Edit `config/gitlab.yml`:
+
+ ```yaml
+ kerberos:
+ simple_ldap_linking_allowed_realms: ['example.com','kerberos.example.com']
+ ```
+
+1. Save the file and [restart](../administration/restart_gitlab.md#installations-from-source)
+ GitLab for the changes to take effect.
+
## HTTP Git access
A linked Kerberos account enables you to `git pull` and `git push` using your
@@ -123,6 +164,13 @@ GitLab users with a linked Kerberos account can also `git pull` and `git push`
using Kerberos tokens, i.e., without having to send their password with each
operation.
+DANGER: **Danger:**
+There is a [known issue](https://github.com/curl/curl/issues/1261) with `libcurl`
+older than version 7.64.1 wherein it won't reuse connections when negotiating.
+This leads to authorization issues when push is larger than `http.postBuffer`
+config. Ensure that Git is using at least `libcurl` 7.64.1 to avoid this. To
+know the `libcurl` version installed, run `curl-config --version`.
+
### HTTP Git access with Kerberos token (passwordless authentication)
#### Support for Git before 2.4
@@ -207,9 +255,10 @@ remove the OmniAuth provider named `kerberos` from your `gitlab.yml` /
```yaml
omniauth:
+ # Rest of configuration omitted
# ...
providers:
- - { name: 'kerberos' } # <-- remove this line
+ - { name: 'kerberos' } # <-- remove this line
```
1. [Restart GitLab](../administration/restart_gitlab.md#installations-from-source) for the changes to take effect.
diff --git a/doc/integration/omniauth.md b/doc/integration/omniauth.md
index dd183ad9eb0..cf09c2f2803 100644
--- a/doc/integration/omniauth.md
+++ b/doc/integration/omniauth.md
@@ -50,7 +50,7 @@ earlier version, you'll need to explicitly enable it.
- `allow_single_sign_on` allows you to specify the providers you want to allow to
automatically create an account. It defaults to `false`. If `false` users must
be created manually or they will not be able to sign in via OmniAuth.
-- `auto_link_ldap_user` can be used if you have [LDAP / ActiveDirectory](ldap.md)
+- `auto_link_ldap_user` can be used if you have [LDAP / ActiveDirectory](../administration/auth/ldap/index.md)
integration enabled. It defaults to `false`. When enabled, users automatically
created through an OmniAuth provider will have their LDAP identity created in GitLab as well.
- `block_auto_created_users` defaults to `true`. If `true` auto created users will
@@ -104,21 +104,21 @@ To change these settings:
```yaml
## OmniAuth settings
- omniauth:
- # Allow login via Twitter, Google, etc. using OmniAuth providers
- # Versions prior to 11.4 require this to be set to true
- # enabled: true
+ omniauth:
+ # Allow login via Twitter, Google, etc. using OmniAuth providers
+ # Versions prior to 11.4 require this to be set to true
+ # enabled: true
- # CAUTION!
- # This allows users to login without having a user account first. Define the allowed providers
- # using an array, e.g. ["saml", "twitter"], or as true/false to allow all providers or none.
- # User accounts will be created automatically when authentication was successful.
- allow_single_sign_on: ["saml", "twitter"]
+ # CAUTION!
+ # This allows users to login without having a user account first. Define the allowed providers
+ # using an array, e.g. ["saml", "twitter"], or as true/false to allow all providers or none.
+ # User accounts will be created automatically when authentication was successful.
+ allow_single_sign_on: ["saml", "twitter"]
- auto_link_ldap_user: true
+ auto_link_ldap_user: true
- # Locks down those users until they have been cleared by the admin (default: true).
- block_auto_created_users: true
+ # Locks down those users until they have been cleared by the admin (default: true).
+ block_auto_created_users: true
```
Now we can choose one or more of the [Supported Providers](#supported-providers)
@@ -142,7 +142,7 @@ The chosen OmniAuth provider is now active and can be used to sign in to GitLab
## Automatically Link Existing Users to OmniAuth Users
-> [Introduced in GitLab 13.4.](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/36664)
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/36664) in GitLab 13.4.
You can automatically link OmniAuth users with existing GitLab users if their email addresses match.
For example, the following setting is used to enable the auto link feature for both a SAML provider and the Twitter OAuth provider:
diff --git a/doc/integration/salesforce.md b/doc/integration/salesforce.md
index 7e0b2518e76..dbd0a03e3cf 100644
--- a/doc/integration/salesforce.md
+++ b/doc/integration/salesforce.md
@@ -64,7 +64,7 @@ To get the credentials (a pair of Client ID and Client Secret), you must [create
- { name: 'salesforce',
app_id: 'SALESFORCE_CLIENT_ID',
app_secret: 'SALESFORCE_CLIENT_SECRET'
- }
+ }
```
1. Change `SALESFORCE_CLIENT_ID` to the Consumer Key from the Salesforce connected application page.
diff --git a/doc/integration/saml.md b/doc/integration/saml.md
index e7e94b21683..ee08a0026cd 100644
--- a/doc/integration/saml.md
+++ b/doc/integration/saml.md
@@ -113,16 +113,16 @@ in your SAML IdP:
omniauth:
providers:
- {
- name: 'saml',
- args: {
- assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback',
- idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8',
- idp_sso_target_url: 'https://login.example.com/idp',
- issuer: 'https://gitlab.example.com',
- name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent'
- },
- label: 'Company Login' # optional label for SAML login button, defaults to "Saml"
- }
+ name: 'saml',
+ args: {
+ assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback',
+ idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8',
+ idp_sso_target_url: 'https://login.example.com/idp',
+ issuer: 'https://gitlab.example.com',
+ name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent'
+ },
+ label: 'Company Login' # optional label for SAML login button, defaults to "Saml"
+ }
```
1. Change the value for `assertion_consumer_service_url` to match the HTTPS endpoint
@@ -210,7 +210,7 @@ Example:
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:transient'
- } }
+ } }
```
### External Groups **(STARTER ONLY)**
@@ -228,7 +228,7 @@ SAML login supports automatic identification on whether a user should be conside
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'
- } }
+ } }
```
### Admin Groups **(STARTER ONLY)**
@@ -248,7 +248,7 @@ considered admin users.
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:transient'
- } }
+ } }
```
### Auditor Groups **(STARTER ONLY)**
@@ -270,7 +270,7 @@ considered auditor users.
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:transient'
- } }
+ } }
```
## Bypass two factor authentication
@@ -328,22 +328,22 @@ In addition to the changes in GitLab, make sure that your IdP is returning the
omniauth:
providers:
- {
- name: 'saml',
- args: {
- assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback',
- idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8',
- idp_sso_target_url: 'https://login.example.com/idp',
- issuer: 'https://gitlab.example.com',
- name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent',
- upstream_two_factor_authn_contexts:
- [
- 'urn:oasis:names:tc:SAML:2.0:ac:classes:CertificateProtectedTransport',
- 'urn:oasis:names:tc:SAML:2.0:ac:classes:SecondFactorOTPSMS',
- 'urn:oasis:names:tc:SAML:2.0:ac:classes:SecondFactorIGTOKEN'
- ]
- },
- label: 'Company Login' # optional label for SAML login button, defaults to "Saml"
- }
+ name: 'saml',
+ args: {
+ assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback',
+ idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8',
+ idp_sso_target_url: 'https://login.example.com/idp',
+ issuer: 'https://gitlab.example.com',
+ name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent',
+ upstream_two_factor_authn_contexts:
+ [
+ 'urn:oasis:names:tc:SAML:2.0:ac:classes:CertificateProtectedTransport',
+ 'urn:oasis:names:tc:SAML:2.0:ac:classes:SecondFactorOTPSMS',
+ 'urn:oasis:names:tc:SAML:2.0:ac:classes:SecondFactorIGTOKEN'
+ ]
+ },
+ label: 'Company Login' # optional label for SAML login button, defaults to "Saml"
+ }
```
1. Save the file and [restart GitLab](../administration/restart_gitlab.md#installations-from-source) for the changes to take effect
@@ -436,7 +436,7 @@ args: {
issuer: 'https://gitlab.example.com',
name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent',
attribute_statements: { email: ['EmailAddress'] },
- allowed_clock_drift: 1 # for one second clock drift
+ allowed_clock_drift: 1 # for one second clock drift
}
```
@@ -561,10 +561,10 @@ args: {
<redacted>
-----END PRIVATE KEY-----',
security: {
- authn_requests_signed: true, # enable signature on AuthNRequest
- want_assertions_signed: true, # enable the requirement of signed assertion
- embed_sign: true, # embedded signature or HTTP GET parameter signature
- metadata_signed: false, # enable signature on Metadata
+ authn_requests_signed: true, # enable signature on AuthNRequest
+ want_assertions_signed: true, # enable the requirement of signed assertion
+ embed_sign: true, # embedded signature or HTTP GET parameter signature
+ metadata_signed: false, # enable signature on Metadata
signature_method: 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256',
digest_method: 'http://www.w3.org/2001/04/xmlenc#sha256',
}
@@ -588,6 +588,52 @@ Refer to the documentation for your SAML Identity Provider for information on ho
The [Generated passwords for users created through integrated authentication](../security/passwords_for_integrated_authentication_methods.md) guide provides an overview of how GitLab generates and sets passwords for users created via SAML.
+## Configuring Group SAML on a self-managed GitLab instance **(PREMIUM ONLY)**
+
+For information on the GitLab.com implementation, please see the [SAML SSO for GitLab.com groups page](../user/group/saml_sso).
+
+Group SAML SSO helps if you need to allow access via multiple SAML identity providers, but as a multi-tenant solution is less suited to cases where you administer your own GitLab instance.
+
+To proceed with configuring Group SAML SSO instead, you'll need to enable the `group_saml` OmniAuth provider. This can be done from:
+
+- `gitlab.rb` for [Omnibus GitLab installations](#omnibus-installations).
+- `gitlab/config/gitlab.yml` for [source installations](#source-installations).
+
+### Limitations
+
+Group SAML on a self-managed instance is limited when compared to the recommended
+[instance-wide SAML](../user/group/saml_sso/index.md). The recommended solution allows you to take advantage of:
+
+- [LDAP compatibility](../administration/auth/ldap/index.md).
+- [LDAP Group Sync](../user/group/index.md#manage-group-memberships-via-ldap).
+- [Required groups](#required-groups).
+- [Admin groups](#admin-groups).
+- [Auditor groups](#auditor-groups).
+
+### Omnibus installations
+
+1. Make sure GitLab is
+ [configured with HTTPS](../install/installation.md#using-https).
+1. Enable OmniAuth and the `group_saml` provider in `gitlab.rb`:
+
+ ```ruby
+ gitlab_rails['omniauth_enabled'] = true
+ gitlab_rails['omniauth_providers'] = [{ name: 'group_saml' }]
+ ```
+
+### Source installations
+
+1. Make sure GitLab is
+ [configured with HTTPS](../install/installation.md#using-https).
+1. Enable OmniAuth and the `group_saml` provider in `gitlab/config/gitlab.yml`:
+
+ ```yaml
+ omniauth:
+ enabled: true
+ providers:
+ - { name: 'group_saml' }
+ ```
+
## Troubleshooting
You can find the base64-encoded SAML Response in the [`production_json.log`](../administration/logs.md#production_jsonlog).
diff --git a/doc/integration/sourcegraph.md b/doc/integration/sourcegraph.md
index c366dab49b1..47c84643a7d 100644
--- a/doc/integration/sourcegraph.md
+++ b/doc/integration/sourcegraph.md
@@ -74,7 +74,7 @@ You can skip this step if you already have your GitLab repositories searchable i
### Configure your GitLab instance with Sourcegraph
-1. In GitLab, go to **Admin Area > Settings > Integrations**.
+1. In GitLab, go to **Admin Area > Settings > General**.
1. Expand the **Sourcegraph** configuration section.
1. Check **Enable Sourcegraph**.
1. Set the Sourcegraph URL to your Sourcegraph instance, e.g., `https://sourcegraph.example.com`.
diff --git a/doc/integration/twitter.md b/doc/integration/twitter.md
index 95de56f24d8..e501eac0c5f 100644
--- a/doc/integration/twitter.md
+++ b/doc/integration/twitter.md
@@ -65,7 +65,8 @@ To enable the Twitter OmniAuth provider you must register your application with
For installations from source:
```yaml
- - { name: 'twitter', app_id: 'YOUR_APP_ID',
+ - { name: 'twitter',
+ app_id: 'YOUR_APP_ID',
app_secret: 'YOUR_APP_SECRET' }
```
diff --git a/doc/intro/README.md b/doc/intro/README.md
index 4bf9c766fc4..02429f387ee 100644
--- a/doc/intro/README.md
+++ b/doc/intro/README.md
@@ -28,7 +28,7 @@ Create issues, labels, milestones, cast your vote, and review issues.
Create merge requests and review code.
- [Fork a project and contribute to it](../user/project/repository/forking_workflow.md)
-- [Create a new merge request](../gitlab-basics/add-merge-request.md)
+- [Create a new merge request](../user/project/merge_requests/creating_merge_requests.md)
- [Automatically close issues from merge requests](../user/project/issues/managing_issues.md#closing-issues-automatically)
- [Automatically merge when pipeline succeeds](../user/project/merge_requests/merge_when_pipeline_succeeds.md)
- [Revert any commit](../user/project/merge_requests/revert_changes.md)
diff --git a/doc/logs/logs.md b/doc/logs/logs.md
deleted file mode 100644
index 0cb092c85fd..00000000000
--- a/doc/logs/logs.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../administration/logs.md'
----
-
-This document was moved to [administration/logs.md](../administration/logs.md).
diff --git a/doc/operations/error_tracking.md b/doc/operations/error_tracking.md
index c5699ee3d22..150264eddcb 100644
--- a/doc/operations/error_tracking.md
+++ b/doc/operations/error_tracking.md
@@ -20,10 +20,8 @@ You can sign up to the cloud hosted <https://sentry.io>, deploy your own [on-pre
### Enabling Sentry
-NOTE: **Note:**
-You will need at least Maintainer [permissions](../user/permissions.md) to enable the Sentry integration.
-
-GitLab provides an easy way to connect Sentry to your project:
+GitLab provides an easy way to connect Sentry to your project. You will need at
+least Maintainer [permissions](../user/permissions.md) to enable the Sentry integration.
1. Sign up to Sentry.io or [deploy your own](#deploying-sentry) Sentry instance.
1. [Create](https://docs.sentry.io/product/sentry-basics/guides/integrate-frontend/create-new-project/) a new Sentry project. For each GitLab project that you want to integrate, we recommend that you create a new Sentry project.
@@ -46,10 +44,8 @@ You may also want to enable Sentry's GitLab integration by following the steps i
## Error Tracking List
-NOTE: **Note:**
-You will need at least Reporter [permissions](../user/permissions.md) to view the Error Tracking list.
-
-You can find the Error Tracking list at **Operations > Error Tracking** in your project's sidebar.
+Users with at least Reporter [permissions](../user/permissions.md)
+can find the Error Tracking list at **Operations > Error Tracking** in your project's sidebar.
Here, you can filter errors by title or by status (one of Ignored , Resolved, or Unresolved) and sort in descending order by Frequency, First Seen, or Last Seen. By default, the error list is ordered by Last Seen and filtered to Unresolved errors.
![Error Tracking list](img/error_tracking_list_v12_6.png)
diff --git a/doc/operations/feature_flags.md b/doc/operations/feature_flags.md
index fe7be48270a..00ebfe5ccf8 100644
--- a/doc/operations/feature_flags.md
+++ b/doc/operations/feature_flags.md
@@ -4,10 +4,11 @@ group: Progressive Delivery
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/#designated-technical-writers
---
-# Feature Flags **(STARTER)**
+# Feature Flags **(CORE)**
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/7433) in GitLab 11.4.
-> - [Moved](https://gitlab.com/gitlab-org/gitlab/-/issues/212318) to [GitLab Starter](https://about.gitlab.com/pricing/) in 13.4
+> - [Moved](https://gitlab.com/gitlab-org/gitlab/-/issues/212318) to [GitLab Starter](https://about.gitlab.com/pricing/) in 13.4.
+> - [Moved](https://gitlab.com/gitlab-org/gitlab/-/issues/212318) to [GitLab Core](https://about.gitlab.com/pricing/) in 13.5.
With Feature Flags, you can deploy your application's new features to production in smaller batches.
You can toggle a feature on and off to subsets of users, helping you achieve Continuous Delivery.
@@ -55,6 +56,20 @@ To create and enable a feature flag:
You can change these settings by clicking the **{pencil}** (edit) button
next to any feature flag in the list.
+## Maximum number of feature flags
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/254379) in GitLab 13.5.
+
+The maximum number of feature flags per project on self-managed GitLab instances
+is 200. On GitLab.com, the maximum number is determined by [GitLab.com tier](https://about.gitlab.com/pricing/):
+
+| Tier | Number of feature flags per project |
+|----------|-------------------------------------|
+| Free | 50 |
+| Bronze | 100 |
+| Silver | 150 |
+| Gold | 200 |
+
## Feature flag strategies
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/35555) in GitLab 13.0.
@@ -86,12 +101,49 @@ and clicking **{pencil}** (edit).
Enables the feature for all users. It uses the [`default`](https://unleash.github.io/docs/activation_strategy#default)
Unleash activation strategy.
+### Percent Rollout
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/43340) in GitLab 13.5.
+
+Enables the feature for a percentage of page views, with configurable consistency
+of behavior. This consistency is also known as stickiness. It uses the
+[`flexibleRollout`](https://unleash.github.io/docs/activation_strategy#flexiblerollout)
+Unleash activation strategy.
+
+You can configure the consistency to be based on:
+
+- **User IDs**: Each user ID has a consistent behavior, ignoring session IDs.
+- **Session IDs**: Each session ID has a consistent behavior, ignoring user IDs.
+- **Random**: Consistent behavior is not guaranteed. The feature is enabled for the
+ selected percentage of page views randomly. User IDs and session IDs are ignored.
+- **Available ID**: Consistent behavior is attempted based on the status of the user:
+ - If the user is logged in, make behavior consistent based on user ID.
+ - If the user is anonymous, make the behavior consistent based on the session ID.
+ - If there is no user ID or session ID, then the feature is enabled for the selected
+ percentage of page view randomly.
+
+For example, set a value of 15% based on **Available ID** to enable the feature for 15% of page views. For
+authenticated users this is based on their user ID. For anonymous users with a session ID it would be based on their
+session ID instead as they do not have a user ID. Then if no session ID is provided, it falls back to random.
+
+The rollout percentage can be from 0% to 100%.
+
+Selecting a consistency based on User IDs functions the same as the [percent of Users](#percent-of-users) rollout.
+
+CAUTION: **Caution:**
+Selecting **Random** provides inconsistent application behavior for individual users.
+
### Percent of Users
Enables the feature for a percentage of authenticated users. It uses the
[`gradualRolloutUserId`](https://unleash.github.io/docs/activation_strategy#gradualrolloutuserid)
Unleash activation strategy.
+NOTE: **Note:**
+[Percent rollout](#percent-rollout) with a consistency based on **User IDs** has the same
+behavior. It is recommended to use percent rollout instead of percent of users as
+it is more flexible.
+
For example, set a value of 15% to enable the feature for 15% of authenticated users.
The rollout percentage can be from 0% to 100%.
@@ -105,7 +157,8 @@ ID for the feature to be enabled. See the [Ruby example](#ruby-application-examp
### User IDs
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/8240) in GitLab 12.2. [Updated](https://gitlab.com/gitlab-org/gitlab/-/issues/34363) to be defined per environment in GitLab 12.6.
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/8240) in GitLab 12.2.
+> - [Updated](https://gitlab.com/gitlab-org/gitlab/-/issues/34363) to be defined per environment in GitLab 12.6.
Enables the feature for a list of target users. It is implemented
using the Unleash [`userWithId`](https://unleash.github.io/docs/activation_strategy#userwithid)
@@ -353,31 +406,9 @@ end
## Feature Flag Related Issues **(PREMIUM)**
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/36617) in GitLab 13.2.
-> - It's deployed behind a feature flag, enabled by default.
-> - It's enabled on GitLab.com.
-> - It can't be enabled or disabled per-project
-> - It's recommended for production use.
-> - For GitLab self-managed instances, GitLab administrators can opt to disable it.
+> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/251234) in GitLab 13.5.
-You can link related issues to a feature flag. In the **Linked issues** section, click the `+` button and input the issue reference number or the full URL of the issue.
+You can link related issues to a feature flag. In the **Linked issues** section,
+click the `+` button and input the issue reference number or the full URL of the issue.
This feature is similar to the [related issues](../user/project/issues/related_issues.md) feature.
-
-### Enable or disable Feature Flag Related Issues **(CORE ONLY)**
-
-Feature Flag Related Issues is under development but ready for production use.
-It is deployed behind a feature flag that is **enabled by default**.
-[GitLab administrators with access to the GitLab Rails console](../administration/feature_flags.md)
-can opt to disable it for your instance.
-
-To disable it:
-
-```ruby
-Feature.disable(:feature_flags_issue_links)
-```
-
-To enable it:
-
-```ruby
-Feature.enable(:feature_flags_issue_links)
-```
diff --git a/doc/operations/incident_management/alert_details.md b/doc/operations/incident_management/alert_details.md
index 860e6d32ae4..459331ea0a5 100644
--- a/doc/operations/incident_management/alert_details.md
+++ b/doc/operations/incident_management/alert_details.md
@@ -1,200 +1,5 @@
---
-stage: Monitor
-group: Health
-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/#designated-technical-writers
+redirect_to: alerts.md
---
-# Alert details page
-
-Navigate to the Alert details view by visiting the
-[Alert list](./alerts.md) and selecting an alert from the
-list. You need least Developer [permissions](../../user/permissions.md) to access
-alerts.
-
-TIP: **Tip:**
-To review live examples of GitLab alerts, visit the
-[alert list](https://gitlab.com/gitlab-examples/ops/incident-setup/everyone/tanuki-inc/-/alert_management)
-for this demo project. Click any alert in the list to examine its alert details
-page.
-
-Alerts provide **Overview** and **Alert details** tabs to give you the right
-amount of information you need.
-
-## Alert overview tab
-
-The **Overview** tab provides basic information about the alert:
-
-![Alert Detail Overview](./img/alert_detail_overview_v13_1.png)
-
-## Alert details tab
-
-![Alert Full Details](./img/alert_detail_full_v13_1.png)
-
-### Update an alert's status
-
-The Alert detail view enables you to update the Alert Status.
-See [Create and manage alerts in GitLab](./alerts.md) for more details.
-
-### Create an issue from an alert
-
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/217745) in GitLab 13.1.
-
-The Alert detail view enables you to create an issue with a
-description automatically populated from an alert. To create the issue,
-click the **Create Issue** button. You can then view the issue from the
-alert by clicking the **View Issue** button.
-
-Closing a GitLab issue associated with an alert changes the alert's status to Resolved.
-See [Create and manage alerts in GitLab](alerts.md) for more details about alert statuses.
-
-### Update an alert's assignee
-
-> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/3066) in GitLab 13.1.
-
-The Alert detail view allows users to update the Alert assignee.
-
-In large teams, where there is shared ownership of an alert, it can be difficult
-to track who is investigating and working on it. The Alert detail view
-enables you to update the Alert assignee:
-
-NOTE: **Note:**
-GitLab currently only supports a single assignee per alert.
-
-1. To display the list of current alerts, click
- **{cloud-gear}** **Operations > Alerts**:
-
- ![Alert List View Assignee(s)](./img/alert_list_assignees_v13_1.png)
-
-1. Select your desired alert to display its **Alert Details View**:
-
- ![Alert Details View Assignee(s)](./img/alert_details_assignees_v13_1.png)
-
-1. If the right sidebar is not expanded, click
- **{angle-double-right}** **Expand sidebar** to expand it.
-1. In the right sidebar, locate the **Assignee** and click **Edit**. From the
- dropdown menu, select each user you want to assign to the alert. GitLab creates
- a [to-do list item](../../user/todos.md) for each user.
-
- ![Alert Details View Assignee(s)](./img/alert_todo_assignees_v13_1.png)
-
-To remove an assignee, click **Edit** next to the **Assignee** dropdown menu and
-deselect the user from the list of assignees, or click **Unassigned**.
-
-### Alert system notes
-
-> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/3066) in GitLab 13.1.
-
-When you take action on an alert, this is logged as a system note,
-which is visible in the Alert Details view. This gives you a linear
-timeline of the alert's investigation and assignment history.
-
-The following actions will result in a system note:
-
-- [Updating the status of an alert](#update-an-alerts-status)
-- [Creating an issue based on an alert](#create-an-issue-from-an-alert)
-- [Assignment of an alert to a user](#update-an-alerts-assignee)
-
-![Alert Details View System Notes](./img/alert_detail_system_notes_v13_1.png)
-
-### Create a to-do from an alert
-
-> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/3066) in GitLab 13.1.
-
-You can manually create [To-Do list items](../../user/todos.md) for yourself from the
-Alert details screen, and view them later on your **To-Do List**. To add a to-do:
-
-1. To display the list of current alerts, click
- **{cloud-gear}** **Operations > Alerts**.
-1. Select your desired alert to display its **Alert Management Details View**.
-1. Click the **Add a To-Do** button in the right sidebar:
-
- ![Alert Details Add A To Do](./img/alert_detail_add_todo_v13_1.png)
-
-Click the **To-Do** **{todo-done}** in the navigation bar to view your current to-do list.
-
-![Alert Details Added to Do](./img/alert_detail_added_todo_v13_1.png)
-
-### View an alert's metrics data
-
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/217768) in GitLab 13.2.
-
-To view the metrics for an alert:
-
- 1. Sign in as a user with Developer or higher [permissions](../../user/permissions.md).
- 1. Navigate to **{cloud-gear}** **Operations > Alerts**.
- 1. Click the alert you want to view.
- 1. Below the title of the alert, click the **Metrics** tab.
-
-![Alert Metrics View](img/alert_detail_metrics_v13_2.png)
-
-For GitLab-managed Prometheus instances, metrics data is automatically available
-for the alert, making it easy to see surrounding behavior. See
-[Managed Prometheus instances](../metrics/alerts.md#managed-prometheus-instances)
-for information on setting up alerts.
-
-For externally-managed Prometheus instances, you can configure your alerting rules to
-display a chart in the alert. See
-[Embedding metrics based on alerts in incident issues](../metrics/embed.md#embedding-metrics-based-on-alerts-in-incident-issues)
-for information on how to appropriately configure your alerting rules. See
-[External Prometheus instances](../metrics/alerts.md#external-prometheus-instances)
-for information on setting up alerts for your self-managed Prometheus instance.
-
-## Use cases for assigning alerts
-
-Consider a team formed by different sections of monitoring, collaborating on a
-single application. After an alert surfaces, it's extremely important to
-route the alert to the team members who can address and resolve the alert.
-
-Assigning Alerts eases collaboration and delegation. All
-assignees are shown in your team's work-flows, and all assignees receive
-notifications, simplifying communication and ownership of the alert.
-
-After completing their portion of investigating or fixing the alert, users can
-unassign their account from the alert when their role is complete.
-The alert status can be updated on the [Alert list](./alerts.md) to
-reflect if the alert has been resolved.
-
-## View an alert's logs
-
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/217768) in GitLab 13.3.
-
-To view the logs for an alert:
-
- 1. Sign in as a user with Developer or higher [permissions](../../user/permissions.md).
- 1. Navigate to **{cloud-gear}** **Operations > Alerts**.
- 1. Click the alert you want to view.
- 1. Below the title of the alert, click the **Metrics** tab.
- 1. Click the [menu](../metrics/dashboards/index.md#chart-context-menu) of the metric chart to view options.
- 1. Click **View logs**.
-
-Read [View logs from metrics panel](#view-logs-from-metrics-panel) for additional information.
-
-## Embed metrics in incidents and issues
-
-You can embed metrics anywhere [GitLab Markdown](../../user/markdown.md) is used, such as descriptions,
-comments on issues, and merge requests. Embedding metrics helps you share them
-when discussing incidents or performance issues. You can output the dashboard directly
-into any issue, merge request, epic, or any other Markdown text field in GitLab
-by [copying and pasting the link to the metrics dashboard](../metrics/embed.md#embedding-gitlab-managed-kubernetes-metrics).
-
-You can embed both
-[GitLab-hosted metrics](../metrics/embed.md) and
-[Grafana metrics](../metrics/embed_grafana.md)
-in incidents and issue templates.
-
-### Context menu
-
-You can view more details about an embedded metrics panel from the context menu.
-To access the context menu, click the **{ellipsis_v}** **More actions** dropdown box
-above the upper right corner of the panel. For a list of options, see
-[Chart context menu](../metrics/dashboards/index.md#chart-context-menu).
-
-#### View logs from metrics panel
-
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/201846) in GitLab Ultimate 12.8.
-> - [Moved](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/25455) to [GitLab Core](https://about.gitlab.com/pricing/) 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 is affecting
-your application's performance and resolve any problems.
+This document was moved to [another location](alerts.md).
diff --git a/doc/operations/incident_management/alert_integrations.md b/doc/operations/incident_management/alert_integrations.md
new file mode 100644
index 00000000000..58c1e1eae76
--- /dev/null
+++ b/doc/operations/incident_management/alert_integrations.md
@@ -0,0 +1,163 @@
+---
+stage: Monitor
+group: Health
+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/#designated-technical-writers
+---
+
+# Alert integrations
+
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/13203) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 12.4.
+> - [Moved](https://gitlab.com/gitlab-org/gitlab/-/issues/42640) to [GitLab Core](https://about.gitlab.com/pricing/) in 12.8.
+
+GitLab can accept alerts from any source via a webhook receiver. This can be configured generically or, in GitLab versions 13.1 and greater, you can configure
+[External Prometheus instances](../metrics/alerts.md#external-prometheus-instances)
+to use this endpoint.
+
+## Integrations list
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/245331) in [GitLab Core](https://about.gitlab.com/pricing/) 13.5.
+
+With Maintainer or higher [permissions](../../user/permissions.md), you can view
+the list of configured alerts integrations by navigating to
+**Settings > Operations** in your project's sidebar menu, and expanding **Alerts** section.
+The list displays the integration name, type, and status (enabled or disabled):
+
+![Current Integrations](img/integrations_list_v13_5.png)
+
+## Configuration
+
+You can either configure alerts to integrate with an [external Prometheus server](#external-prometheus-integration),
+or provide a [generic HTTP endpoint](#generic-http-endpoint) to receive alerts
+from other services.
+
+### Generic HTTP Endpoint
+
+Enabling the Generic HTTP Endpoint creates a unique HTTP endpoint that can receive alert payloads in JSON format. You can always
+[customize the payload](#customizing-the-payload) to your liking.
+
+You will need to activate the endpoint and obtain credentials to set up this integration:
+
+1. Sign in to GitLab as a user with maintainer [permissions](../../user/permissions.md)
+ for a project.
+1. Navigate to **Settings > Operations** in your project.
+1. Expand the **Alerts** section, and in the **Integration** dropdown menu, select **Generic**.
+1. Toggle the **Active** alert setting to display the **URL** and **Authorization Key**
+ for the webhook configuration.
+
+### External Prometheus integration
+
+For GitLab versions 13.1 and greater, please see [External Prometheus Instances](../metrics/alerts.md#external-prometheus-instances) to configure alerts for this integration.
+
+## Customizing the payload
+
+You can customize the payload by sending the following parameters. This applies to all types of integrations. All fields
+other than `title` are optional:
+
+| Property | Type | Description |
+| ------------------------- | --------------- | ----------- |
+| `title` | String | The title of the incident. Required. |
+| `description` | String | A high-level summary of the problem. |
+| `start_time` | DateTime | The time of the incident. If none is provided, a timestamp of the issue will be used. |
+| `end_time` | DateTime | For existing alerts only. When provided, the alert is resolved and the associated incident is closed. |
+| `service` | String | The affected service. |
+| `monitoring_tool` | String | The name of the associated monitoring tool. |
+| `hosts` | String or Array | One or more hosts, as to where this incident occurred. |
+| `severity` | String | The severity of the alert. Must be one of `critical`, `high`, `medium`, `low`, `info`, `unknown`. Default is `critical`. |
+| `fingerprint` | String or Array | The unique identifier of the alert. This can be used to group occurrences of the same alert. |
+| `gitlab_environment_name` | String | The name of the associated GitLab [environment](../../ci/environments/index.md). This can be used to associate your alert to your environment. |
+
+You can also add custom fields to the alert's payload. The values of extra
+parameters aren't limited to primitive types (such as strings or numbers), but
+can be a nested JSON object. For example:
+
+```json
+{ "foo": { "bar": { "baz": 42 } } }
+```
+
+TIP: **Payload size:**
+Ensure your requests are smaller than the [payload application limits](../../administration/instance_limits.md#generic-alert-json-payloads).
+
+Example request:
+
+```shell
+curl --request POST \
+ --data '{"title": "Incident title"}' \
+ --header "Authorization: Bearer <authorization_key>" \
+ --header "Content-Type: application/json" \
+ <url>
+```
+
+The `<authorization_key>` and `<url>` values can be found when configuring an alert integration.
+
+Example payload:
+
+```json
+{
+ "title": "Incident title",
+ "description": "Short description of the incident",
+ "start_time": "2019-09-12T06:00:55Z",
+ "service": "service affected",
+ "monitoring_tool": "value",
+ "hosts": "value",
+ "severity": "high",
+ "fingerprint": "d19381d4e8ebca87b55cda6e8eee7385",
+ "foo": {
+ "bar": {
+ "baz": 42
+ }
+ }
+}
+```
+
+## Triggering test alerts
+
+> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/3066) in GitLab Core in 13.2.
+
+After a [project maintainer or owner](../../user/permissions.md)
+configures an integration, you can trigger a test
+alert to confirm your integration works properly.
+
+1. Sign in as a user with Developer or greater [permissions](../../user/permissions.md).
+1. Navigate to **Settings > Operations** in your project.
+1. Click **Alerts endpoint** to expand the section.
+1. Enter a sample payload in **Alert test payload** (valid JSON is required).
+1. Click **Test alert payload**.
+
+GitLab displays an error or success message, depending on the outcome of your test.
+
+## Automatic grouping of identical alerts **(PREMIUM)**
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/214557) in [GitLab Premium](https://about.gitlab.com/pricing/) 13.2.
+
+In GitLab versions 13.2 and greater, GitLab groups alerts based on their
+payload. When an incoming alert contains the same payload as another alert
+(excluding the `start_time` and `hosts` attributes), GitLab groups these alerts
+together and displays a counter on the [Alert Management List](./incidents.md)
+and details pages.
+
+If the existing alert is already `resolved`, GitLab creates a new alert instead.
+
+![Alert Management List](./img/alert_list_v13_1.png)
+
+## Link to your Opsgenie Alerts
+
+> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/3066) in [GitLab Premium](https://about.gitlab.com/pricing/) 13.2.
+
+You can monitor alerts using a GitLab integration with [Opsgenie](https://www.atlassian.com/software/opsgenie).
+
+If you enable the Opsgenie integration, you can't have other GitLab alert
+services, such as [Generic Alerts](generic_alerts.md) or Prometheus alerts,
+active at the same time.
+
+To enable Opsgenie integration:
+
+1. Sign in as a user with Maintainer or Owner [permissions](../../user/permissions.md).
+1. Navigate to **Operations > Alerts**.
+1. In the **Integrations** select box, select **Opsgenie**.
+1. Select the **Active** toggle.
+1. In the **API URL** field, enter the base URL for your Opsgenie integration,
+ such as `https://app.opsgenie.com/alert/list`.
+1. Select **Save changes**.
+
+After you enable the integration, navigate to the Alerts list page at
+**Operations > Alerts**, and then select **View alerts in Opsgenie**.
diff --git a/doc/operations/incident_management/alert_notifications.md b/doc/operations/incident_management/alert_notifications.md
new file mode 100644
index 00000000000..130c4e82088
--- /dev/null
+++ b/doc/operations/incident_management/alert_notifications.md
@@ -0,0 +1,36 @@
+---
+stage: Monitor
+group: Health
+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/#designated-technical-writers
+---
+
+# Paging and notifications
+
+When there is a new alert or incident, it is important for a responder to be notified
+immediately so they can triage and respond to the problem. Responders can receive
+notifications using the methods described on this page.
+
+## Slack notifications
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/216326) in GitLab 13.1.
+
+Responders can be paged via Slack using the
+[Slack Notifications Service](../../user/project/integrations/slack.md), which you
+can configure for new alerts and new incidents. After configuring, responders
+receive a **single** page via Slack. To set up Slack notifications on your mobile
+device, make sure to enable notifications for the Slack app on your phone so
+you never miss a page.
+
+## Email notifications
+
+Email notifications are available in projects that have been
+[configured to create incidents automatically](incidents.md#create-incidents-automatically)
+for triggered alerts. Project members with the **Owner** or **Maintainer** roles are
+sent an email notification automatically. (This is not configurable.) To optionally
+send additional email notifications to project members with the **Developer** role:
+
+1. Navigate to **Settings > Operations**.
+1. Expand the **Incidents** section.
+1. In the **Alert Integration** tab, select the **Send a separate email notification to Developers**
+ check box.
+1. Select **Save changes**.
diff --git a/doc/operations/incident_management/alerts.md b/doc/operations/incident_management/alerts.md
index d908af63000..a6168386024 100644
--- a/doc/operations/incident_management/alerts.md
+++ b/doc/operations/incident_management/alerts.md
@@ -4,119 +4,261 @@ group: Health
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/#designated-technical-writers
---
-# Create and manage alerts in GitLab
+# Alerts
-Users with at least Developer [permissions](../../user/permissions.md) can access
-the Alert Management list at **{cloud-gear}** **Operations > Alerts** in your
-project's sidebar. The Alert Management list displays alerts sorted by start time,
-but you can change the sort order by clicking the headers in the Alert Management list.
+Alerts are a critical entity in your incident managment 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
+
+Users with at least Developer [permissions](../../user/permissions.md) can
+access the Alert list at **Operations > Alerts** in your project's
+sidebar. The Alert list displays alerts sorted by start time, but
+you can change the sort order by clicking the headers in the Alert list.
([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/217745) in GitLab 13.1.)
The alert list displays the following information:
-![Alert List](./img/alert_list_v13_1.png)
+![Alert List](img/alert_list_v13_1.png)
-- **Search** - The alert list supports a simple free text search on the title,
+- **Search**: The alert list supports a simple free text search on the title,
description, monitoring tool, and service fields.
([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/213884) in GitLab 13.1.)
-- **Severity** - The current importance of a alert and how much attention it should
- receive. For a listing of all statuses, read [Alert Management severity](#alert-severity).
-- **Start time** - How long ago the alert fired. This field uses the standard
- GitLab pattern of `X time ago`, but is supported by a granular date/time tooltip
- depending on the user's locale.
-- **Alert description** - The description of the alert, which attempts to capture the most meaningful data.
-- **Event count** - The number of times that an alert has fired.
-- **Issue** - A link to the incident issue that has been created for the alert.
-- **Status** - The current status of the alert:
+- **Severity**: The current importance of a alert and how much attention it
+ should receive. For a listing of all statuses, read [Alert Management severity](#alert-severity).
+- **Start time**: How long ago the alert fired. This field uses the standard
+ GitLab pattern of `X time ago`, but is supported by a granular date/time
+ tooltip depending on the user's locale.
+- **Alert description**: The description of the alert, which attempts to
+ capture the most meaningful data.
+- **Event count**: The number of times that an alert has fired.
+- **Issue**: A link to the incident issue that has been created for the alert.
+- **Status**: The current status of the alert:
- **Triggered**: No one has begun investigation.
- **Acknowledged**: Someone is actively investigating the problem.
- **Resolved**: No further work is required.
-
+
TIP: **Tip:**
-Check out a [live example](https://gitlab.com/gitlab-examples/ops/incident-setup/everyone/tanuki-inc/-/alert_management)
+Check out a live example available from the
+[`tanuki-inc` project page](https://gitlab-examples-ops-incident-setup-everyone-tanuki-inc.34.69.64.147.nip.io/)
in GitLab to examine alerts in action.
-## Enable Alerts
+## Alert severity
+
+Each level of alert contains a uniquely shaped and color-coded icon to help
+you identify the severity of a particular alert. These severity icons help you
+immediately identify which alerts you should prioritize investigating:
+
+![Alert Management Severity System](img/alert_management_severity_v13_0.png)
-NOTE: **Note:**
-You need at least Maintainer [permissions](../../user/permissions.md) to enable
-the Alerts feature.
+Alerts contain one of the following icons:
-There are several ways to accept alerts into your GitLab project.
-Enabling any of these methods enables the Alert list. After configuring
-alerts, visit **{cloud-gear}** **Operations > Alerts** in your project's sidebar
-to view the list of alerts.
+| Severity | Icon | Color (hexadecimal) |
+|----------|-------------------------|---------------------|
+| Critical | **{severity-critical}** | `#8b2615` |
+| High | **{severity-high}** | `#c0341d` |
+| Medium | **{severity-medium}** | `#fca429` |
+| Low | **{severity-low}** | `#fdbc60` |
+| Info | **{severity-info}** | `#418cd8` |
+| Unknown | **{severity-unknown}** | `#bababa` |
-### Enable GitLab-managed Prometheus alerts
+## Alert details page
-You can install the GitLab-managed Prometheus application on your Kubernetes
-cluster. For more information, read
-[Managed Prometheus on Kubernetes](../../user/project/integrations/prometheus.md#managed-prometheus-on-kubernetes).
-When GitLab-managed Prometheus is installed, the [Alerts list](alerts.md)
-is also enabled.
+Navigate to the Alert details view by visiting the [Alert list](./alerts.md)
+and selecting an alert from the list. You need least Developer [permissions](../../user/permissions.md)
+to access alerts.
-To populate the alerts with data, read
-[GitLab-Managed Prometheus instances](../metrics/alerts.md#managed-prometheus-instances).
+TIP: **Tip:**
+To review live examples of GitLab alerts, visit the
+[alert list](https://gitlab.com/gitlab-examples/ops/incident-setup/everyone/tanuki-inc/-/alert_management)
+for this demo project. Select any alert in the list to examine its alert details
+page.
-### Enable external Prometheus alerts
+Alerts provide **Overview** and **Alert details** tabs to give you the right
+amount of information you need.
-You can configure an externally-managed Prometheus instance to send alerts
-to GitLab. To set up this configuration, read the [configuring Prometheus](../metrics/alerts.md#external-prometheus-instances) documentation. Activating the external Prometheus
-configuration also enables the [Alerts list](./alerts.md).
+### Alert details tab
-To populate the alerts with data, read
-[External Prometheus instances](../metrics/alerts.md#external-prometheus-instances).
+The **Alert details** tab has two sections. The top section provides a short list of critical details such as the severity, start time, number of events, and originating monitorting tool. The second section displays the full alert payload.
-### Enable a Generic Alerts endpoint
+### Metrics tab
-GitLab provides the Generic Alerts endpoint so you can accept alerts from a third-party
-alerts service. Read the
-[instructions for toggling generic alerts](generic_alerts.md#setting-up-generic-alerts)
-to add this option. After configuring the endpoint, the
-[Alerts list](./alerts.md) is enabled.
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/217768) in GitLab 13.2.
-To populate the alerts with data, read [Customizing the payload](./generic_alerts.md#customizing-the-payload) for requests to the alerts endpoint.
+The **Metrics** tab will display a metrics chart for alerts coming from Prometheus. If the alert originated from any other tool, the **Metrics** tab will be empty. To set up alerts for GitLab-managed Prometheus instances, see [Managed Prometheus instances](../metrics/alerts.md#managed-prometheus-instances). For externally-managed Prometheus instances, you will need to configure your alerting
+rules to display a chart in the alert. For information about how to configure
+your alerting rules, see [Embedding metrics based on alerts in incident issues](../metrics/embed.md#embedding-metrics-based-on-alerts-in-incident-issues). See
+[External Prometheus instances](../metrics/alerts.md#external-prometheus-instances)
+for information about setting up alerts for your self-managed Prometheus
+instance.
-### Opsgenie integration **(PREMIUM)**
+To view the metrics for an alert:
-> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/3066) in [GitLab Premium](https://about.gitlab.com/pricing/) 13.2.
+1. Sign in as a user with Developer or higher [permissions](../../user/permissions.md).
+1. Navigate to **Operations > Alerts**.
+1. Select the alert you want to view.
+1. Below the title of the alert, select the **Metrics** tab.
-A new way of monitoring Alerts via a GitLab integration is with
-[Opsgenie](https://www.atlassian.com/software/opsgenie).
+![Alert Metrics View](img/alert_detail_metrics_v13_2.png)
-NOTE: **Note:**
-If you enable the Opsgenie integration, you can't have other GitLab alert services,
-such as [Generic Alerts](./generic_alerts.md) or
-Prometheus alerts, active at the same time.
+#### View an alert's logs
-To enable Opsgenie integration:
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/201846) in GitLab Ultimate 12.8. and [improved](https://gitlab.com/gitlab-org/gitlab/-/issues/217768) in GitLab 13.3.
+> - [Moved](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/25455) to [GitLab Core](https://about.gitlab.com/pricing/) 12.9.
-1. Sign in as a user with Maintainer or Owner [permissions](../../user/permissions.md).
-1. Navigate to **{cloud-gear}** **Operations > Alerts**.
-1. In the **Integrations** select box, select Opsgenie.
-1. Click the **Active** toggle.
-1. In the **API URL**, enter the base URL for your Opsgenie integration, such
- as `https://app.opsgenie.com/alert/list`.
-1. Click **Save changes**.
+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.
-After enabling the integration, navigate to the Alerts list page at
-**{cloud-gear}** **Operations > Alerts**, and click **View alerts in Opsgenie**.
+To view the logs for an alert:
-## Alert severity
+1. Sign in as a user with Developer or higher [permissions](../../user/permissions.md).
+1. Navigate to **Operations > 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**.
-Each level of alert contains a uniquely shaped and color-coded icon to help
-you identify the severity of a particular alert. These severity icons help you
-immediately identify which alerts you should prioritize investigating:
+### Activity feed tab
-![Alert Management Severity System](./img/alert_management_severity_v13_0.png)
+> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/3066) in GitLab 13.1.
-Alerts contain one of the following icons:
+The **Activity feed** tab is a log of activity on the alert. When you take action on an alert, this is logged as a system note. This gives you a linear
+timeline of the alert's investigation and assignment history.
+
+The following actions will result in a system note:
+
+- [Updating the status of an alert](#update-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)
+
+![Alert Details Activity Feed](img/alert_detail_activity_feed_v13_5.png)
+
+## Alert actions
+
+There are different actions avilable in GitLab to help triage and respond to alerts.
+
+### Update an alert's status
+
+The Alert detail view enables you to update the Alert Status.
+See [Create and manage alerts in GitLab](./alerts.md) for more details.
+
+### Create an incident from an alert
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/217745) in GitLab 13.1.
+
+The Alert detail view enables you to create an issue with a
+description populated from an alert. To create the issue,
+select the **Create Issue** button. You can then view the issue from the
+alert by selecting the **View Issue** button.
+
+Closing a GitLab issue associated with an alert changes the alert's status to
+Resolved. See [Create and manage alerts in GitLab](alerts.md) for more details
+about alert statuses.
+
+### Assign an alert
+
+> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/3066) in GitLab 13.1.
+
+In large teams, where there is shared ownership of an alert, it can be
+difficult to track who is investigating and working on it. Assigning alerts eases collaboration and delegation by indicating which user is owning the alert. GitLab supports only a single assignee per alert.
+
+To assign an alert:
+
+1. To display the list of current alerts, navigate to **Operations > Alerts**:
+
+ ![Alert List View Assignee(s)](./img/alert_list_assignees_v13_1.png)
+
+1. Select your desired alert to display its **Alert Details View**:
+
+ ![Alert Details View Assignee(s)](./img/alert_details_assignees_v13_1.png)
+
+1. If the right sidebar is not expanded, select
+ **{angle-double-right}** **Expand sidebar** to expand it.
+1. In the right sidebar, locate the **Assignee**, and then select **Edit**.
+ From the dropdown menu, select each user you want to assign to the alert.
+ GitLab creates a [to-do item](../../user/todos.md) for each user.
+
+ ![Alert Details View Assignee(s)](./img/alert_todo_assignees_v13_1.png)
+
+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
+and deselect the user from the list of assignees, or select **Unassigned**.
+
+### Create a to do from an alert
+
+> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/3066) in GitLab 13.1.
+
+You can manually create [To-Do list items](../../user/todos.md) for yourself
+from the Alert details screen, and view them later on your **To-Do List**. To
+add a to do:
+
+1. To display the list of current alerts, navigate to **Operations > Alerts**.
+1. Select your desired alert to display its **Alert Management Details View**.
+1. Select the **Add a To-Do** button in the right sidebar:
+
+ ![Alert Details Add A To Do](./img/alert_detail_add_todo_v13_1.png)
+
+Select the **To-Do List** **{todo-done}** in the navigation bar to view your current to-do list.
+
+![Alert Details Added to do](./img/alert_detail_added_todo_v13_1.png)
+
+## Link runbooks to alerts
+
+> Runbook URLs [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/39315) in GitLab 13.3.
+
+When creating alerts from the metrics dashboard for
+[managed Prometheus instances](../metrics/alerts.md#managed-prometheus-instances),
+you can link a runbook. When the alert triggers, you can access the runbook through
+the [chart context menu](../metrics/dashboards/index.md#chart-context-menu) in the
+upper-right corner of the metrics chart, making it easy for you to locate and access
+the correct runbook:
+
+![Linked Runbook in charts](img/link_runbooks_to_alerts_v13_5.png)
+
+## View the environment that generated the alert
+
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/232492) in GitLab 13.5.
+> - It's [deployed behind a feature flag](../../user/feature_flags.md), disabled by default.
+> - It's disabled on GitLab.com.
+> - It's not recommended for production use.
+> - To use it in GitLab self-managed instances, ask a GitLab administrator to [enable it](#enable-or-disable-environment-link-in-alert-details). **(CORE ONLY)**
+
+CAUTION: **Warning:**
+This feature might not be available to you. Check the **version history** note above for details.
+
+The environment information and the link are displayed in the [Alert Details tab](#alert-details-tab).
+
+### Enable or disable Environment Link in Alert Details **(CORE ONLY)**
+
+Viewing the environment is under development and not 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(:expose_environment_path_in_alert_details)
+```
+
+To enable for just a particular project:
+
+```ruby
+project = Project.find_by_full_path('your-group/your-project')
+Feature.enable(:expose_environment_path_in_alert_details, project)
+```
+
+To disable it:
+
+```ruby
+Feature.disable(:expose_environment_path_in_alert_details)
+```
+
+To disable for just a particular project:
-| Severity | Icon | Color (hexadecimal) |
-|---|---|---|
-| Critical | **{severity-critical}** | `#8b2615` |
-| High | **{severity-high}** | `#c0341d` |
-| Medium | **{severity-medium}** | `#fca429` |
-| Low | **{severity-low}** | `#fdbc60` |
-| Info | **{severity-info}** | `#418cd8` |
-| Unknown | **{severity-unknown}** | `#bababa` |
+```ruby
+project = Project.find_by_full_path('your-group/your-project')
+Feature.disable(:expose_environment_path_in_alert_details, project)
+```
diff --git a/doc/operations/incident_management/generic_alerts.md b/doc/operations/incident_management/generic_alerts.md
index 11d4dbc6924..a8f2f9a58a6 100644
--- a/doc/operations/incident_management/generic_alerts.md
+++ b/doc/operations/incident_management/generic_alerts.md
@@ -1,126 +1,5 @@
---
-stage: Monitor
-group: Health
-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/#designated-technical-writers
+redirect_to: alert_notifications.md
---
-# Generic alerts integration
-
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/13203) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 12.4.
-> - [Moved](https://gitlab.com/gitlab-org/gitlab/-/issues/42640) to [GitLab Core](https://about.gitlab.com/pricing/) in 12.8.
-
-GitLab can accept alerts from any source via a generic webhook receiver.
-When you set up the generic alerts integration, a unique endpoint will
-be created which can receive a payload in JSON format, and will in turn
-create an issue with the payload in the body of the issue. You can always
-[customize the payload](#customizing-the-payload) to your liking.
-
-The entire payload will be posted in the issue discussion as a comment
-authored by the GitLab Alert Bot.
-
-NOTE: **Note:**
-In GitLab versions 13.1 and greater, you can configure
-[External Prometheus instances](../metrics/alerts.md#external-prometheus-instances)
-to use this endpoint.
-
-## Setting up generic alerts
-
-To obtain credentials for setting up a generic alerts integration:
-
-- Sign in to GitLab as a user with maintainer [permissions](../../user/permissions.md) for a project.
-- Navigate to the **Operations** page for your project, depending on your installed version of GitLab:
- - *In GitLab versions 13.1 and greater,* navigate to **Settings > Operations** in your project.
- - *In GitLab versions prior to 13.1,* navigate to **Settings > Integrations** in your project. GitLab will display a banner encouraging you to enable the Alerts endpoint in **Settings > Operations** instead.
-- Click **Alerts endpoint**.
-- Toggle the **Active** alert setting to display the **URL** and **Authorization Key** for the webhook configuration.
-
-## Customizing the payload
-
-You can customize the payload by sending the following parameters. All fields other than `title` are optional:
-
-| Property | Type | Description |
-| -------- | ---- | ----------- |
-| `title` | String | The title of the incident. Required. |
-| `description` | String | A high-level summary of the problem. |
-| `start_time` | DateTime | The time of the incident. If none is provided, a timestamp of the issue will be used. |
-| `end_time` | DateTime | For existing alerts only. When provided, the alert is resolved and the associated incident is closed. |
-| `service` | String | The affected service. |
-| `monitoring_tool` | String | The name of the associated monitoring tool. |
-| `hosts` | String or Array | One or more hosts, as to where this incident occurred. |
-| `severity` | String | The severity of the alert. Must be one of `critical`, `high`, `medium`, `low`, `info`, `unknown`. Default is `critical`. |
-| `fingerprint` | String or Array | The unique identifier of the alert. This can be used to group occurrences of the same alert. |
-| `gitlab_environment_name` | String | The name of the associated GitLab [environment](../../ci/environments/index.md). This can be used to associate your alert to your environment. |
-
-You can also add custom fields to the alert's payload. The values of extra parameters
-are not limited to primitive types, such as strings or numbers, but can be a nested
-JSON object. For example:
-
-```json
-{ "foo": { "bar": { "baz": 42 } } }
-```
-
-TIP: **Payload size:**
-Ensure your requests are smaller than the [payload application limits](../../administration/instance_limits.md#generic-alert-json-payloads).
-
-Example request:
-
-```shell
-curl --request POST \
- --data '{"title": "Incident title"}' \
- --header "Authorization: Bearer <authorization_key>" \
- --header "Content-Type: application/json" \
- <url>
-```
-
-The `<authorization_key>` and `<url>` values can be found when [setting up generic alerts](#setting-up-generic-alerts).
-
-Example payload:
-
-```json
-{
- "title": "Incident title",
- "description": "Short description of the incident",
- "start_time": "2019-09-12T06:00:55Z",
- "service": "service affected",
- "monitoring_tool": "value",
- "hosts": "value",
- "severity": "high",
- "fingerprint": "d19381d4e8ebca87b55cda6e8eee7385",
- "foo": {
- "bar": {
- "baz": 42
- }
- }
-}
-```
-
-## Triggering test alerts
-
-> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/3066) in GitLab Core in 13.2.
-
-After a [project maintainer or owner](#setting-up-generic-alerts)
-[configures generic alerts](#setting-up-generic-alerts), you can trigger a
-test alert to confirm your integration works properly.
-
-1. Sign in as a user with Developer or greater [permissions](../../user/permissions.md).
-1. Navigate to **Settings > Operations** in your project.
-1. Click **Alerts endpoint** to expand the section.
-1. Enter a sample payload in **Alert test payload** (valid JSON is required).
-1. Click **Test alert payload**.
-
-GitLab displays an error or success message, depending on the outcome of your test.
-
-## Automatic grouping of identical alerts **(PREMIUM)**
-
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/214557) in [GitLab Premium](https://about.gitlab.com/pricing/) 13.2.
-
-In GitLab versions 13.2 and greater, GitLab groups alerts based on their payload.
-When an incoming alert contains the same payload as another alert (excluding the
-`start_time` and `hosts` attributes), GitLab groups these alerts together and
-displays a counter on the
-[Alert Management List](./incidents.md)
-and details pages.
-
-If the existing alert is already `resolved`, then a new alert will be created instead.
-
-![Alert Management List](./img/alert_list_v13_1.png)
+This document was moved to [another location](alert_notifications.md).
diff --git a/doc/operations/incident_management/img/alert_detail_activity_feed_v13_5.png b/doc/operations/incident_management/img/alert_detail_activity_feed_v13_5.png
new file mode 100644
index 00000000000..2c1c4c39515
--- /dev/null
+++ b/doc/operations/incident_management/img/alert_detail_activity_feed_v13_5.png
Binary files differ
diff --git a/doc/operations/incident_management/img/incident_highlight_bar_v13_5.png b/doc/operations/incident_management/img/incident_highlight_bar_v13_5.png
new file mode 100644
index 00000000000..6a40e97820c
--- /dev/null
+++ b/doc/operations/incident_management/img/incident_highlight_bar_v13_5.png
Binary files differ
diff --git a/doc/operations/incident_management/img/incident_list_v13_4.png b/doc/operations/incident_management/img/incident_list_v13_4.png
deleted file mode 100644
index bf00e630c67..00000000000
--- a/doc/operations/incident_management/img/incident_list_v13_4.png
+++ /dev/null
Binary files differ
diff --git a/doc/operations/incident_management/img/incident_list_v13_5.png b/doc/operations/incident_management/img/incident_list_v13_5.png
new file mode 100644
index 00000000000..88942a70e88
--- /dev/null
+++ b/doc/operations/incident_management/img/incident_list_v13_5.png
Binary files differ
diff --git a/doc/operations/incident_management/img/incident_sla_settings_v13_5.png b/doc/operations/incident_management/img/incident_sla_settings_v13_5.png
new file mode 100644
index 00000000000..94c8b840210
--- /dev/null
+++ b/doc/operations/incident_management/img/incident_sla_settings_v13_5.png
Binary files differ
diff --git a/doc/operations/incident_management/img/integrations_list_v13_5.png b/doc/operations/incident_management/img/integrations_list_v13_5.png
new file mode 100644
index 00000000000..babaa785ad6
--- /dev/null
+++ b/doc/operations/incident_management/img/integrations_list_v13_5.png
Binary files differ
diff --git a/doc/operations/incident_management/img/link_runbooks_to_alerts_v13_5.png b/doc/operations/incident_management/img/link_runbooks_to_alerts_v13_5.png
new file mode 100644
index 00000000000..a63001b4cde
--- /dev/null
+++ b/doc/operations/incident_management/img/link_runbooks_to_alerts_v13_5.png
Binary files differ
diff --git a/doc/operations/incident_management/img/timeline_view_toggle_v13_5.png b/doc/operations/incident_management/img/timeline_view_toggle_v13_5.png
new file mode 100644
index 00000000000..542ca139f7e
--- /dev/null
+++ b/doc/operations/incident_management/img/timeline_view_toggle_v13_5.png
Binary files differ
diff --git a/doc/operations/incident_management/incidents.md b/doc/operations/incident_management/incidents.md
index 3ff02b3dc6b..3d85fa0ebd8 100644
--- a/doc/operations/incident_management/incidents.md
+++ b/doc/operations/incident_management/incidents.md
@@ -4,16 +4,88 @@ group: Health
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/#designated-technical-writers
---
-# Create and manage incidents in GitLab
+# Incidents
-While no configuration is required to use the [manual features](#create-an-incident-manually)
-of incident management, some simple [configuration](#configure-incidents) is needed to automate incident creation.
+Incidents are critical entities in incident management workflows. They represent a service disruption or outage that needs to be restored urgently. GitLab provides tools for the triage, response, and remediation of incidents.
-For users with at least Developer [permissions](../../user/permissions.md), the
-Incident Management list is available at **Operations > Incidents**
+## Incident Creation
+
+You can create an incident manually or automatically.
+
+### Create incidents manually
+
+If you have at least Guest [permissions](../../user/permissions.md), to create an Incident, you have two options to do this manually.
+
+**From the Incidents List:**
+
+> [Moved](https://gitlab.com/gitlab-org/monitor/health/-/issues/24) to GitLab core in 13.3.
+
+- Navigate to **Operations > Incidents** and click **Create Incident**.
+- Create a new issue using the `incident` template available when creating it.
+- Create a new issue and assign the `incident` label to it.
+
+![Incident List Create](./img/incident_list_create_v13_3.png)
+
+**From the Issues List:**
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/230857) in GitLab 13.4.
+
+- Navigate to **Issues > List** and click **Create Issue**.
+- Create a new issue using the `type` drop-down and select `Incident`.
+- The page refreshes and the page only displays fields relevant to Incidents.
+
+![Incident List Create](./img/new_incident_create_v13_4.png)
+
+### Create incidents automatically
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/4925) in GitLab Ultimate 11.11.
+
+With Maintainer or higher [permissions](../../user/permissions.md), you can enable
+ GitLab to create incident automatically whenever an alert is triggered:
+
+1. Navigate to **Settings > Operations > Incidents** and expand
+ **Incidents**:
+
+ ![Incident Management Settings](./img/incident_management_settings_v13_3.png)
+
+1. Check the **Create an incident**
+ checkbox.
+1. To customize the incident, select an [issue templates](../../user/project/description_templates.md#creating-issue-templates).
+1. To send [an email notification](alert_notifications.md#email-notifications) to users
+ with [Developer permissions](../../user/permissions.md), select
+ **Send a separate email notification to Developers**. Email notifications will also be sent to users with **Maintainer** and **Owner** permissions.
+1. Click **Save changes**.
+
+### Create incidents via the PagerDuty webhook
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/119018) in GitLab 13.3.
+
+You can set up a webhook with PagerDuty to automatically create a GitLab incident
+for each PagerDuty incident. This configuration requires you to make changes
+in both PagerDuty and GitLab:
+
+1. Sign in as a user with Maintainer [permissions](../../user/permissions.md).
+1. Navigate to **Settings > Operations > Incidents** and expand **Incidents**.
+1. Select the **PagerDuty integration** tab:
+
+ ![PagerDuty incidents integration](./img/pagerduty_incidents_integration_v13_3.png)
+
+1. Activate the integration, and save the changes in GitLab.
+1. Copy the value of **Webhook URL** for use in a later step.
+1. Follow the steps described in the
+ [PagerDuty documentation](https://support.pagerduty.com/docs/webhooks)
+ to add the webhook URL to a PagerDuty webhook integration.
+
+To confirm the integration is successful, trigger a test incident from PagerDuty to
+confirm that a GitLab incident is created from the incident.
+
+## Incident list
+
+For users with at least Guest [permissions](../../user/permissions.md), the
+Incident list is available at **Operations > Incidents**
in your project's sidebar. The list contains the following metrics:
-![Incident List](img/incident_list_v13_4.png)
+![Incident List](img/incident_list_v13_5.png)
- **Status** - To filter incidents by their status, click **Open**, **Closed**,
or **All** above the incident list.
@@ -27,8 +99,8 @@ in your project's sidebar. The list contains the following metrics:
- **{severity-low}** **Low - S4**
- **{severity-unknown}** **Unknown**
- NOTE: **Note:**
- Editing incident severity on the incident details page was [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/229402) in GitLab 13.4.
+ [Editing incident severity](#change-severity) on the incident details page was
+ [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/229402) in GitLab 13.4.
- **Incident** - The description of the incident, which attempts to capture the
most meaningful data.
@@ -44,113 +116,117 @@ The Incident list displays incidents sorted by incident created date.
To see if a column is sortable, point your mouse at the header. Sortable columns
display an arrow next to the column name.
+Incidents share the [Issues API](../../user/project/issues/index.md).
+
TIP: **Tip:**
For a live example of the incident list in action, visit this
[demo project](https://gitlab.com/gitlab-examples/ops/incident-setup/everyone/tanuki-inc/-/incidents).
-NOTE: **Note:**
-Incidents share the [Issues API](../../user/project/issues/index.md).
+## Incident details
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/230847) in GitLab 13.4.
-## Configure incidents
+Users with at least Reporter [permissions](../../user/permissions.md) can view
+the Incident Details page. Navigate to **Operations > Incidents** in your project's
+sidebar, and select an incident from the list.
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/4925) in GitLab Ultimate 11.11.
+When you take any of these actions on an incident, GitLab logs a system note and
+displays it in the Incident Details view:
-With Maintainer or higher [permissions](../../user/permissions.md), you can enable
-or disable Incident Management features in the GitLab user interface
-to create issues when alerts are triggered:
+- Updating the severity of an incident
+ ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/42358) in GitLab 13.5.)
-1. Navigate to **Settings > Operations > Incidents** and expand
- **Incidents**:
+For live examples of GitLab incidents, visit the `tanuki-inc` project's
+[incident list page](https://gitlab.com/gitlab-examples/ops/incident-setup/everyone/tanuki-inc/-/incidents).
+Click any incident in the list to display its incident details page.
- ![Incident Management Settings](./img/incident_management_settings_v13_3.png)
+### Summary
-1. For GitLab versions 11.11 and greater, you can select the **Create an issue**
- checkbox to create an issue based on your own
- [issue templates](../../user/project/description_templates.md#creating-issue-templates).
- For more information, see
- [Trigger actions from alerts](../metrics/alerts.md#trigger-actions-from-alerts) **(ULTIMATE)**.
-1. To create issues from alerts, select the template in the **Issue Template**
- select box.
-1. To send [separate email notifications](index.md#notify-developers-of-alerts) to users
- with [Developer permissions](../../user/permissions.md), select
- **Send a separate email notification to Developers**.
-1. Click **Save changes**.
+The summary section for incidents provides both critical details about and the
+contents of the issue template (if one was used). The highlighted bar at the top
+of the incident displays from left to right:
-Appropriately configured alerts include an
-[embedded chart](../metrics/embed.md#embedding-metrics-based-on-alerts-in-incident-issues)
-for the query corresponding to the alert. You can also configure GitLab to
-[close issues](../metrics/alerts.md#trigger-actions-from-alerts)
-when you receive notification that the alert is resolved.
+- The link to the original alert.
+- The alert start time.
+- The event count.
-## Create an incident manually
+Beneath the highlight bar, GitLab displays a summary that includes the following fields:
-If you have at least Developer [permissions](../../user/permissions.md), to create an Incident, you have two options.
+- Start time
+- Severity
+- `full_query`
+- Monitoring tool
-### From the Incidents List
+Comments are displayed in threads, but can be displayed chronologically
+[in a timeline view](#timeline-view).
-> [Moved](https://gitlab.com/gitlab-org/monitor/health/-/issues/24) to GitLab core in 13.3.
+### Alert details
-- Navigate to **Operations > Incidents** and click **Create Incident**.
-- Create a new issue using the `incident` template available when creating it.
-- Create a new issue and assign the `incident` label to it.
+Incidents show the details of linked alerts in a separate tab. To populate this
+tab, the incident must have been created with a linked alert. Incidents
+created automatically from alerts have this
+field populated.
-![Incident List Create](./img/incident_list_create_v13_3.png)
+![Incident alert details](./img/incident_alert_details_v13_4.png)
-### From the Issues List
+### Timeline view
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/230857) in GitLab 13.4.
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/227836) in [GitLab Premium](https://about.gitlab.com/pricing/) 13.5.
-- Navigate to **Issues > List** and click **Create Issue**.
-- Create a new issue using the `type` drop-down and select `Incident`.
-- The page refreshes and the page only displays fields relevant to Incidents.
+To quickly see the latest updates on an incident, click
+**{comments}** **Turn timeline view on** in the comment bar to display comments
+un-threaded and ordered chronologically, newest to oldest:
-![Incident List Create](./img/new_incident_create_v13_4.png)
+![Timeline view toggle](./img/timeline_view_toggle_v13_5.png)
-## Configure PagerDuty integration
+### Service Level Agreement countdown timer
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/119018) in GitLab 13.3.
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/241663) in [GitLab Premium](https://about.gitlab.com/pricing/) 13.5.
-You can set up a webhook with PagerDuty to automatically create a GitLab issue
-for each PagerDuty incident. This configuration requires you to make changes
-in both PagerDuty and GitLab:
+After enabling **Incident SLA** in the Incident Management configuration, newly-created
+incidents display a SLA (Service Level Agreement) timer showing the time remaining before
+the SLA period expires. If the incident is not closed before the SLA period ends, GitLab
+adds a `missed::SLA` label to the incident.
-1. Sign in as a user with Maintainer [permissions](../../user/permissions.md).
-1. Navigate to **Settings > Operations > Incidents** and expand **Incidents**.
-1. Select the **PagerDuty integration** tab:
+## Incident Actions
- ![PagerDuty incidents integration](./img/pagerduty_incidents_integration_v13_3.png)
+There are different actions avilable to help triage and respond to incidents.
-1. Activate the integration, and save the changes in GitLab.
-1. Copy the value of **Webhook URL** for use in a later step.
-1. Follow the steps described in the
- [PagerDuty documentation](https://support.pagerduty.com/docs/webhooks)
- to add the webhook URL to a PagerDuty webhook integration.
+### Assign incidents
-To confirm the integration is successful, trigger a test incident from PagerDuty to
-confirm that a GitLab issue is created from the incident.
+Assign incidents to users that are actively responding. Select **Edit** in the right-hand side bar to select or deselect assignees.
-## Incident details
+### Change severity
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/230847) in GitLab 13.4.
+See [Incident List](#incident-list) for a full description of the severities available. Select **Edit** in the right-hand side bar to change the severity of an incident.
-### Summary
+### Add a to do
-The summary section for incidents provides both critical details about and the
-contents of the issue template (if one was used). The highlighted bar at the top
-of the incident displays from left to right: the link to the original alert, the
-alert start time, and the event count. Beneath the highlight bar, GitLab
-displays a summary that includes the following fields:
+Add a to-do for incidents that you want to track in your to-do list. Clicke the **Add a to do** button at the top of the right-hand side bar to add a to do.
-- Start time
-- Severity
-- `full_query`
-- Monitoring tool
+### Manage incidents from Slack
-### Alert details
+Slack slash commands allow you to control GitLab and view GitLab content without leaving Slack.
-Incidents show the details of linked alerts in a separate tab. To populate this
-tab, the incident must have been created with a linked alert. Incidents
-[created automatically](#configure-incidents) from alerts will have this
-field populated.
+Learn how to [set up Slack slash commands](../../user/project/integrations/slack_slash_commands.md)
+and how to [use the available slash commands](../../integration/slash_commands.md).
-![Incident alert details](./img/incident_alert_details_v13_4.png)
+### Associate Zoom calls
+
+GitLab enables you to [associate a Zoom meeting with an issue](../../user/project/issues/associate_zoom_meeting.md)
+for synchronous communication during incident management. After starting a Zoom
+call for an incident, you can associate the conference call with an issue. Your
+team members can join the Zoom call without requesting a link.
+
+### Embed metrics in incidents
+
+You can embed metrics anywhere [GitLab Markdown](../../user/markdown.md) is
+used, such as descriptions, comments on issues, and merge requests. Embedding
+metrics helps you share them when discussing incidents or performance issues.
+You can output the dashboard directly into any issue, merge request, epic, or
+any other Markdown text field in GitLab by
+[copying and pasting the link to the metrics dashboard](../metrics/embed.md#embedding-gitlab-managed-kubernetes-metrics).
+
+You can embed both [GitLab-hosted metrics](../metrics/embed.md) and
+[Grafana metrics](../metrics/embed_grafana.md) in incidents and issue
+templates.
diff --git a/doc/operations/incident_management/index.md b/doc/operations/incident_management/index.md
index 28e69a6bbfe..60571c03d74 100644
--- a/doc/operations/incident_management/index.md
+++ b/doc/operations/incident_management/index.md
@@ -8,74 +8,11 @@ info: To determine the technical writer assigned to the Stage/Group associated w
> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/2877) in GitLab 13.0.
-Incident Management enables developers to easily discover and view the alerts
-generated by their application. By surfacing alert information where the code is
-being developed, efficiency and awareness can be increased.
-
-GitLab offers solutions for handling incidents in your applications and services,
-such as [setting up Prometheus alerts](#configure-prometheus-alerts),
-[displaying metrics](./alert_details.md#embed-metrics-in-incidents-and-issues), and sending notifications.
-
-## Alert notifications
-
-### Slack Notifications
-
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/216326) in GitLab 13.1.
-
-You can be alerted via a Slack message when a new alert has been received.
-
-See the [Slack Notifications Service docs](../../user/project/integrations/slack.md) for information on how to set this up.
-
-### Notify developers of alerts
-
-GitLab can react to the alerts triggered from your applications and services
-by creating issues and alerting developers through email. By default, GitLab
-sends these emails to [owners and maintainers](../../user/permissions.md) of the project.
-These emails contain details of the alert, and a link for more information.
-
-To send separate email notifications to users with
-[Developer permissions](../../user/permissions.md), see
-[Configure incidents](./incidents.md#configure-incidents).
-
-## Configure Prometheus alerts
-
-You can set up Prometheus alerts in:
-
-- [GitLab-managed Prometheus](../metrics/alerts.md) installations.
-- [Self-managed Prometheus](../metrics/alerts.md#external-prometheus-instances) installations.
-
-Prometheus alerts are created by the special Alert Bot user. You can't remove this
-user, but it does not count toward your license limit.
-
-## Configure external generic alerts
-
-GitLab can accept alerts from any source through a generic webhook receiver.
-When [configuring the generic alerts integration](./generic_alerts.md), GitLab
-creates a unique endpoint which receives a JSON-formatted, customizable payload.
-
-After configuration, you can manage your alerts using either the
-[alerts section](./alerts.md) or the [alert details section](./alert_details.md).
-
-## Integrate incidents with Slack
-
-Slack slash commands allow you to control GitLab and view GitLab content without leaving Slack.
-
-Learn how to [set up Slack slash commands](../../user/project/integrations/slack_slash_commands.md)
-and how to [use the available slash commands](../../integration/slash_commands.md).
-
-## Integrate issues with Zoom
-
-GitLab enables you to [associate a Zoom meeting with an issue](../../user/project/issues/associate_zoom_meeting.md)
-for synchronous communication during incident management. After starting a Zoom
-call for an incident, you can associate the conference call with an issue. Your
-team members can join the Zoom call without requesting a link.
-
-## More information
-
-For information about GitLab and incident management, see:
-
-- [Generic alerts](generic_alerts.md)
-- [Alerts](alerts.md)
-- [Alert details](alert_details.md)
-- [Incidents](incidents.md)
-- [Status page](status_page.md)
+Incident Management enables developers to easily triage and view the alerts and incidents
+generated by their application. By surfacing alerts and incidents where the code is
+being developed, efficiency and awareness can be increased. Check out the following sections for more information:
+
+- [Integrate your monitoring tools](alert_integrations.md).
+- Receive [notifications](alert_notifications.md) for triggered alerts.
+- Triage [Alerts](alerts.md) and [Incidents](incidents.md).
+- Inform stakeholders with [Status Page](status_page.md).
diff --git a/doc/operations/incident_management/integrations.md b/doc/operations/incident_management/integrations.md
new file mode 100644
index 00000000000..9d4f32ab2bf
--- /dev/null
+++ b/doc/operations/incident_management/integrations.md
@@ -0,0 +1,16 @@
+---
+stage: Monitor
+group: Health
+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/#designated-technical-writers
+---
+
+# Integrations
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/245331) in [GitLab Core](https://about.gitlab.com/pricing/) 13.5.
+
+With Maintainer or higher [permissions](../../user/permissions.md), you can view
+the list of configured alerts integrations by navigating to
+**Settings > Operations** in your project's sidebar menu, and expanding **Alerts** section.
+The list displays the integration name, type, and status (enabled or disabled):
+
+![Current Integrations](img/integrations_list_v13_5.png)
diff --git a/doc/operations/incident_management/status_page.md b/doc/operations/incident_management/status_page.md
index 9db3593caec..e5d0ae1ddbb 100644
--- a/doc/operations/incident_management/status_page.md
+++ b/doc/operations/incident_management/status_page.md
@@ -4,7 +4,7 @@ group: Health
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/#designated-technical-writers
---
-# GitLab Status Page **(ULTIMATE)**
+# Status Page
> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/2479) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 12.10.
@@ -25,7 +25,7 @@ Clicking an incident displays a detail page with more information about a partic
valid image extension. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/205166) in GitLab 13.1.
- A chronological ordered list of updates to the incident.
-## Set up a GitLab Status Page
+## Set up a Status Page
To configure a GitLab Status Page you must:
@@ -37,11 +37,10 @@ To configure a GitLab Status Page you must:
### Configure GitLab with cloud provider information
-To provide GitLab with the AWS account information needed to push content to your Status Page:
-
-NOTE: **Note:**
Only AWS S3 is supported as a deploy target.
+To provide GitLab with the AWS account information needed to push content to your Status Page:
+
1. Sign into GitLab as a user with Maintainer or greater [permissions](../../user/permissions.md).
1. Navigate to **{settings}** **Settings > Operations**. Next to **Status Page**,
click **Expand**.
@@ -74,8 +73,6 @@ the necessary CI/CD variables to deploy the Status Page to AWS S3:
1. Scroll to **Variables**, and click **Expand**.
1. Add the following variables from your Amazon Console:
- `S3_BUCKET_NAME` - The name of the Amazon S3 bucket.
-
- NOTE: **Note:**
If no bucket with the provided name exists, the first pipeline run creates
one and configures it for
[static website hosting](https://docs.aws.amazon.com/AmazonS3/latest/dev/HostingWebsiteOnS3Setup.html).
@@ -128,10 +125,7 @@ To publish an incident:
1. Create an issue in the project you enabled the GitLab Status Page settings in.
1. A [project or group owner](../../user/permissions.md) must use the
`/publish` [quick action](../../user/project/quick_actions.md) to publish the
- issue to the GitLab Status Page.
-
- NOTE: **Note:**
- Confidential issues can't be published.
+ issue to the GitLab Status Page. Confidential issues can't be published.
A background worker publishes the issue onto the Status Page using the credentials
you provided during setup. As part of publication, GitLab will:
diff --git a/doc/operations/index.md b/doc/operations/index.md
index 7ab34502277..8488f939893 100644
--- a/doc/operations/index.md
+++ b/doc/operations/index.md
@@ -1,6 +1,6 @@
---
stage: Monitor
-group: APM
+group: Health
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/#designated-technical-writers
---
@@ -35,7 +35,7 @@ using metrics and logs, and promote the critical alerts to incidents.
Are your alerts too noisy? Alerts configured on GitLab metrics can configured
and fine-tuned in GitLab immediately following a fire-fight.
-- [Manage alerts and incidents](../user/incident_management/index.md) in GitLab.
+- [Manage alerts and incidents](incident_management/index.md) in GitLab.
- [Configure alerts for metrics](metrics/alerts.md#set-up-alerts-for-prometheus-metrics) in GitLab.
- Create a [status page](incident_management/status_page.md)
to communicate efficiently to your users during an incident.
diff --git a/doc/operations/metrics/alerts.md b/doc/operations/metrics/alerts.md
index 5b880ab9746..79e3bdbd69c 100644
--- a/doc/operations/metrics/alerts.md
+++ b/doc/operations/metrics/alerts.md
@@ -1,6 +1,6 @@
---
stage: Monitor
-group: APM
+group: Health
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/#designated-technical-writers
---
@@ -15,7 +15,7 @@ your team when environment performance falls outside of the boundaries you set.
## Managed Prometheus instances
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/6590) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 11.2 for [custom metrics](index.md#adding-custom-metrics), and GitLab 11.3 for [library metrics](../../user/project/integrations/prometheus_library/metrics.md).
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/6590) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 11.2 for [custom metrics](index.md#adding-custom-metrics), and GitLab 11.3 for [library metrics](../../user/project/integrations/prometheus_library/index.md).
For managed Prometheus instances using auto configuration, you can
[configure alerts for metrics](index.md#adding-custom-metrics) directly in the
@@ -70,14 +70,14 @@ receivers:
bearer_token: 9e1cbfcd546896a9ea8be557caf13a76
send_resolved: true
url: http://192.168.178.31:3001/root/manual_prometheus/prometheus/alerts/notify.json
- ...
+ # Rest of configuration omitted
+ # ...
```
For GitLab to associate your alerts with an [environment](../../ci/environments/index.md),
you must configure a `gitlab_environment_name` label on the alerts you set up in
Prometheus. The value of this should match the name of your environment in GitLab.
-NOTE: **Note:**
In GitLab versions 13.1 and greater, you can configure your manually configured
Prometheus server to use the
[Generic alerts integration](../incident_management/generic_alerts.md).
diff --git a/doc/operations/metrics/dashboards/default.md b/doc/operations/metrics/dashboards/default.md
index f086d7737bd..11e96114f38 100644
--- a/doc/operations/metrics/dashboards/default.md
+++ b/doc/operations/metrics/dashboards/default.md
@@ -1,6 +1,6 @@
---
stage: Monitor
-group: APM
+group: Health
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/#designated-technical-writers
---
@@ -25,7 +25,6 @@ metrics about the [deployed application](../index.md#configure-prometheus-to-gat
## Kubernetes pod health dashboard
-NOTE: **Note:**
This dashboard requires Kubernetes v1.14 or higher, due to the
[change in metric labels](https://github.com/kubernetes/kubernetes/pull/69099)
in Kubernetes 1.14.
diff --git a/doc/operations/metrics/dashboards/develop.md b/doc/operations/metrics/dashboards/develop.md
index b621f5fd727..9254bfe075f 100644
--- a/doc/operations/metrics/dashboards/develop.md
+++ b/doc/operations/metrics/dashboards/develop.md
@@ -1,6 +1,6 @@
---
stage: Monitor
-group: APM
+group: Health
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/#designated-technical-writers
---
diff --git a/doc/operations/metrics/dashboards/img/metrics_dashboard_panel_preview_v13_3.png b/doc/operations/metrics/dashboards/img/metrics_dashboard_panel_preview_v13_3.png
index 4f6d3b3dfa4..3c3203265e1 100644
--- a/doc/operations/metrics/dashboards/img/metrics_dashboard_panel_preview_v13_3.png
+++ b/doc/operations/metrics/dashboards/img/metrics_dashboard_panel_preview_v13_3.png
Binary files differ
diff --git a/doc/operations/metrics/dashboards/index.md b/doc/operations/metrics/dashboards/index.md
index ffcb7dc92c6..4aa340a9e59 100644
--- a/doc/operations/metrics/dashboards/index.md
+++ b/doc/operations/metrics/dashboards/index.md
@@ -1,6 +1,6 @@
---
stage: Monitor
-group: APM
+group: Health
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/#designated-technical-writers
---
@@ -14,7 +14,6 @@ includes a few key metrics, but you can also define your own custom dashboards.
You may create a [new dashboard from scratch](#add-a-new-dashboard-to-your-project)
or [duplicate a GitLab-defined Prometheus dashboard](#duplicate-a-gitlab-defined-dashboard).
-NOTE: **Note:**
The metrics as defined below do not support alerts, unlike
[custom metrics](../index.md#adding-custom-metrics).
@@ -51,16 +50,16 @@ To create a new dashboard from the command line:
- group: 'Group Title'
panels:
- type: area-chart
- title: "Chart Title"
- y_label: "Y-Axis"
+ title: 'Chart Title'
+ y_label: 'Y-Axis'
y_axis:
format: number
precision: 0
metrics:
- id: my_metric_id
query_range: 'http_requests_total'
- label: "Instance: {{instance}}, method: {{method}}"
- unit: "count"
+ label: 'Instance: {{instance}}, method: {{method}}'
+ unit: 'count'
```
1. Save the file, commit, and push to your repository. The file must be present in your **default** branch.
@@ -86,7 +85,7 @@ with the **Add Panel** page:
1. Click **Add panel** in the **{ellipsis_v}** **More actions** menu.
NOTE: **Note:**
- You can add panel only to custom dashboards.
+ You can only add panels to custom dashboards.
![Monitoring Dashboard actions menu with add panel item](img/actions_menu_create_add_panel_v13_3.png)
1. In the **Define and preview panel** section, paste in the YAML you want to
@@ -100,16 +99,12 @@ with the **Add Panel** page:
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/37238) in GitLab 12.7.
> - From [GitLab 12.8 onwards](https://gitlab.com/gitlab-org/gitlab/-/issues/39505), custom metrics are also duplicated when you duplicate a dashboard.
-You can save a complete copy of a GitLab defined dashboard along with all custom metrics added to it.
+You can save a complete copy of a GitLab-defined dashboard along with all custom metrics added to it.
The resulting `.yml` file can be customized and adapted to your project.
You can decide to save the dashboard `.yml` file in the project's **default** branch or in a
-new branch.
+new branch. To duplicate a GitLab-defined dashboard:
1. Click **Duplicate current dashboard** in the **{ellipsis_v}** **More actions** menu.
-
- NOTE: **Note:**
- You can duplicate only GitLab-defined dashboards.
-
1. Enter the filename and other information, such as the new commit's message, and click **Duplicate**.
1. Select a branch to add your dashboard to:
- *If you select your **default** branch,* the new dashboard becomes immediately available.
diff --git a/doc/operations/metrics/dashboards/panel_types.md b/doc/operations/metrics/dashboards/panel_types.md
index b2cbdcb88d9..fd9d2bf7899 100644
--- a/doc/operations/metrics/dashboards/panel_types.md
+++ b/doc/operations/metrics/dashboards/panel_types.md
@@ -1,6 +1,6 @@
---
stage: Monitor
-group: APM
+group: Health
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/#designated-technical-writers
---
@@ -17,16 +17,16 @@ dashboard: 'Dashboard Title'
panel_groups:
- group: 'Group Title'
panels:
- - type: area-chart # or line-chart
+ - type: area-chart # or line-chart
title: 'Area Chart Title'
- y_label: "Y-Axis"
+ y_label: 'Y-Axis'
y_axis:
format: number
precision: 0
metrics:
- id: area_http_requests_total
query_range: 'http_requests_total'
- label: "Instance: {{instance}}, Method: {{method}}"
+ label: 'Instance: {{instance}}, Method: {{method}}'
unit: "count"
```
@@ -55,23 +55,23 @@ panel_groups:
- group: 'Group Title'
panels:
- type: anomaly-chart
- title: "Chart Title"
+ title: 'Chart Title'
y_label: "Y-Axis"
metrics:
- id: anomaly_requests_normal
query_range: 'http_requests_total'
- label: "# of Requests"
- unit: "count"
+ label: '# of Requests'
+ unit: 'count'
metrics:
- id: anomaly_requests_upper_limit
query_range: 10000
- label: "Max # of requests"
- unit: "count"
+ label: 'Max # of requests'
+ unit: 'count'
metrics:
- id: anomaly_requests_lower_limit
query_range: 2000
- label: "Min # of requests"
- unit: "count"
+ label: 'Min # of requests'
+ unit: 'count'
```
Note the following properties:
@@ -93,13 +93,13 @@ panel_groups:
- group: 'Group title'
panels:
- type: bar
- title: "Http Handlers"
+ title: 'HTTP Handlers'
x_label: 'Response Size'
y_axis:
- name: "Handlers"
+ name: 'Handlers'
metrics:
- id: prometheus_http_response_size_bytes_bucket
- query_range: "sum(increase(prometheus_http_response_size_bytes_bucket[1d])) by (handler)"
+ query_range: 'sum(increase(prometheus_http_response_size_bytes_bucket[1d])) by (handler)'
unit: 'Bytes'
```
@@ -121,13 +121,13 @@ dashboard: 'Dashboard Title'
panel_groups:
- group: 'Group title'
panels:
- - title: "Column"
- type: "column"
+ - title: 'Column'
+ type: 'column'
metrics:
- id: 1024_memory
query: 'avg(sum(container_memory_usage_bytes{container_name!="POD",pod_name=~"^%{ci_environment_slug}-([^c].*|c([^a]|a([^n]|n([^a]|a([^r]|r[^y])))).*|)-(.*)",namespace="%{kube_namespace}"}) by (job)) without (job) / count(avg(container_memory_usage_bytes{container_name!="POD",pod_name=~"^%{ci_environment_slug}-([^c].*|c([^a]|a([^n]|n([^a]|a([^r]|r[^y])))).*|)-(.*)",namespace="%{kube_namespace}"}) without (job)) /1024/1024'
unit: MB
- label: "Memory Usage"
+ label: 'Memory Usage'
```
Note the following properties:
@@ -153,19 +153,19 @@ panel_groups:
priority: 5
panels:
- type: 'stacked-column'
- title: "Stacked column"
- y_label: "y label"
+ title: 'Stacked column'
+ y_label: 'y label'
x_label: 'x label'
metrics:
- id: memory_1
query_range: 'memory_query'
- label: "memory query 1"
- unit: "count"
+ label: 'memory query 1'
+ unit: 'count'
series_name: 'group 1'
- id: memory_2
query_range: 'memory_query_2'
- label: "memory query 2"
- unit: "count"
+ label: 'memory query 2'
+ unit: 'count'
series_name: 'group 2'
```
@@ -185,13 +185,13 @@ dashboard: 'Dashboard Title'
panel_groups:
- group: 'Group Title'
panels:
- - title: "Single Stat"
- type: "single-stat"
+ - title: 'Single Stat'
+ type: 'single-stat'
metrics:
- id: 10
query: 'max(go_memstats_alloc_bytes{job="prometheus"})'
unit: MB
- label: "Total"
+ label: 'Total'
```
Note the following properties:
@@ -215,14 +215,14 @@ dashboard: 'Dashboard Title'
panel_groups:
- group: 'Group Title'
panels:
- - title: "Single Stat"
- type: "single-stat"
+ - title: 'Single Stat'
+ type: 'single-stat'
max_value: 100
metrics:
- id: 10
query: 'max(go_memstats_alloc_bytes{job="prometheus"})'
unit: '%'
- label: "Total"
+ label: 'Total'
```
For example, if you have a query value of `53.6`, adding `%` as the unit results in a single stat value of `53.6%`, but if the maximum expected value of the query is `120`, the value would be `44.6%`. Adding the `max_value` causes the correct percentage value to display.
@@ -242,15 +242,15 @@ dashboard: 'Dashboard Title'
panel_groups:
- group: 'Group Title'
panels:
- - title: "Gauge"
- type: "gauge"
+ - title: 'Gauge'
+ type: 'gauge'
min_value: 0
max_value: 1000
split: 5
thresholds:
values: [60, 90]
- mode: "percentage"
- format: "kilobytes"
+ mode: 'percentage'
+ format: 'kilobytes'
metrics:
- id: 10
query: 'floor(max(prometheus_http_response_size_bytes_bucket)/1000)'
@@ -289,13 +289,13 @@ dashboard: 'Dashboard Title'
panel_groups:
- group: 'Group Title'
panels:
- - title: "Heatmap"
- type: "heatmap"
+ - title: 'Heatmap'
+ type: 'heatmap'
metrics:
- id: 10
query: 'sum(rate(nginx_upstream_responses_total{upstream=~"%{kube_namespace}-%{ci_environment_slug}-.*"}[60m])) by (status_code)'
unit: req/sec
- label: "Status code"
+ label: 'Status code'
```
Note the following properties:
diff --git a/doc/operations/metrics/dashboards/settings.md b/doc/operations/metrics/dashboards/settings.md
index a4aef6b1674..aa0b9a81771 100644
--- a/doc/operations/metrics/dashboards/settings.md
+++ b/doc/operations/metrics/dashboards/settings.md
@@ -1,6 +1,6 @@
---
stage: Monitor
-group: APM
+group: Health
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/#designated-technical-writers
---
diff --git a/doc/operations/metrics/dashboards/templating_variables.md b/doc/operations/metrics/dashboards/templating_variables.md
index 71025d41281..1c0b05b0e53 100644
--- a/doc/operations/metrics/dashboards/templating_variables.md
+++ b/doc/operations/metrics/dashboards/templating_variables.md
@@ -1,6 +1,6 @@
---
stage: Monitor
-group: APM
+group: Health
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/#designated-technical-writers
---
diff --git a/doc/operations/metrics/dashboards/variables.md b/doc/operations/metrics/dashboards/variables.md
index 22c8814e8bd..2103f8e66db 100644
--- a/doc/operations/metrics/dashboards/variables.md
+++ b/doc/operations/metrics/dashboards/variables.md
@@ -1,6 +1,6 @@
---
stage: Monitor
-group: APM
+group: Health
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/#designated-technical-writers
---
@@ -16,7 +16,10 @@ Queries that continue to use the old format will show no data.
## Predefined variables
-GitLab supports a limited set of [CI variables](../../../ci/variables/README.md) in the Prometheus query. This is particularly useful for identifying a specific environment, for example with `ci_environment_slug`. The supported variables are:
+GitLab supports a limited set of [CI variables](../../../ci/variables/README.md)
+in the Prometheus query. This is particularly useful for identifying a specific
+environment, for example with `ci_environment_slug`. Variables for Prometheus queries
+must be lowercase. The supported variables are:
- `environment_filter`
- `ci_environment_slug`
@@ -27,9 +30,6 @@ GitLab supports a limited set of [CI variables](../../../ci/variables/README.md)
- `ci_environment_name`
- `__range`
-NOTE: **Note:**
-Variables for Prometheus queries must be lowercase.
-
### environment_filter
`environment_filter` is automatically expanded to `container_name!="POD",environment="ENVIRONMENT_NAME"`
diff --git a/doc/operations/metrics/dashboards/yaml.md b/doc/operations/metrics/dashboards/yaml.md
index f92ba4079e9..c3523327c51 100644
--- a/doc/operations/metrics/dashboards/yaml.md
+++ b/doc/operations/metrics/dashboards/yaml.md
@@ -1,6 +1,6 @@
---
stage: Monitor
-group: APM
+group: Health
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/#designated-technical-writers
---
@@ -45,7 +45,6 @@ Read the documentation on [links](index.md#add-related-links-to-custom-dashboard
Dashboards display panel groups in the order they are listed in the dashboard YAML file.
-NOTE: **Note:**
In GitLab versions 13.3 and below, panel groups were ordered by a `priority` key, which
is no longer used.
@@ -60,7 +59,6 @@ Panels in a panel group are laid out in rows consisting of two panels per row. A
Dashboards display panels in the order they are listed in the dashboard YAML file.
-NOTE: **Note:**
In GitLab versions 13.3 and below, panels were ordered by a `weight` key, which
is no longer used.
@@ -103,8 +101,8 @@ When a static label is used and a query returns multiple time series, then all t
metrics:
- id: my_metric_id
query_range: 'http_requests_total'
- label: "Time Series"
- unit: "count"
+ label: 'Time Series'
+ unit: 'count'
```
This may render a legend like this:
@@ -117,8 +115,8 @@ For labels to be more explicit, using variables that reflect time series labels
metrics:
- id: my_metric_id
query_range: 'http_requests_total'
- label: "Instance: {{instance}}, method: {{method}}"
- unit: "count"
+ label: 'Instance: {{instance}}, method: {{method}}'
+ unit: 'count'
```
The resulting rendered legend will look like this:
@@ -131,8 +129,8 @@ There is also a shorthand value for dynamic dashboard labels that make use of on
metrics:
- id: my_metric_id
query_range: 'http_requests_total'
- label: "Method"
- unit: "count"
+ label: 'Method'
+ unit: 'count'
```
This works by lowercasing the value of `label` and, if there are more words separated by spaces, replacing those spaces with an underscore (`_`). The transformed value is then checked against the labels of the time series returned by the Prometheus query. If a time series label is found that is equal to the transformed value, then the label value will be used and rendered in the legend like this:
diff --git a/doc/operations/metrics/dashboards/yaml_number_format.md b/doc/operations/metrics/dashboards/yaml_number_format.md
index 1a8bd6f4257..db1606faf8d 100644
--- a/doc/operations/metrics/dashboards/yaml_number_format.md
+++ b/doc/operations/metrics/dashboards/yaml_number_format.md
@@ -1,6 +1,6 @@
---
stage: Monitor
-group: APM
+group: Health
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/#designated-technical-writers
---
diff --git a/doc/operations/metrics/embed.md b/doc/operations/metrics/embed.md
index fcf9679d164..c0b30f18156 100644
--- a/doc/operations/metrics/embed.md
+++ b/doc/operations/metrics/embed.md
@@ -1,6 +1,6 @@
---
stage: Monitor
-group: APM
+group: Health
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/#designated-technical-writers
---
@@ -17,8 +17,7 @@ metrics to others, and you want to have relevant information directly available.
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/29691) in GitLab 12.2.
-NOTE: **Note:**
-Requires [Kubernetes](../../user/project/integrations/prometheus_library/kubernetes.md) metrics.
+This feature requires [Kubernetes](../../user/project/integrations/prometheus_library/kubernetes.md) metrics.
Note: **Note:**
In GitLab versions 13.3 and earlier, metrics dashboard links were in the form
diff --git a/doc/operations/metrics/embed_grafana.md b/doc/operations/metrics/embed_grafana.md
index 2843a4319a8..532bf150777 100644
--- a/doc/operations/metrics/embed_grafana.md
+++ b/doc/operations/metrics/embed_grafana.md
@@ -1,6 +1,6 @@
---
stage: Monitor
-group: APM
+group: Health
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/#designated-technical-writers
---
@@ -12,14 +12,13 @@ Grafana metrics can be embedded in [GitLab Flavored Markdown](../../user/markdow
You can embed live [Grafana](https://docs.gitlab.com/omnibus/settings/grafana.html)
charts in issues as a
-[direct linked rendered image](https://grafana.com/docs/grafana/latest/reference/share_panel/#direct-link-rendered-image).
-The **Direct link rendered image** sharing dialog within Grafana provides the link:
+[direct linked rendered image](https://grafana.com/docs/grafana/latest/reference/share_panel/#direct-link-rendered-image). Your Grafana instance must be available to the
+target user, either as a public dashboard or on the same network. The
+**Direct link rendered image** sharing dialog within Grafana provides the link:
![Grafana Direct Linked Rendered Image](img/grafana_live_embed.png)
-NOTE: **Note:**
-For this embed to display correctly, the Grafana instance must be available to the
-target user, either as a public dashboard or on the same network.
+For this embed to display correctly, the
Copy the link and add an image tag as [inline HTML](../../user/markdown.md#inline-html)
in your Markdown. You can tweak the query parameters to meet your needs, such as
diff --git a/doc/operations/metrics/index.md b/doc/operations/metrics/index.md
index 742e6acef0e..39d03ded373 100644
--- a/doc/operations/metrics/index.md
+++ b/doc/operations/metrics/index.md
@@ -1,6 +1,6 @@
---
stage: Monitor
-group: APM
+group: Health
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/#designated-technical-writers
---
diff --git a/doc/operations/product_analytics.md b/doc/operations/product_analytics.md
index 8f660a16b47..65dced97002 100644
--- a/doc/operations/product_analytics.md
+++ b/doc/operations/product_analytics.md
@@ -1,6 +1,6 @@
---
-stage: Monitor
-group: APM
+stage: Growth
+group: Product Analytics
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/#designated-technical-writers
---
diff --git a/doc/operations/tracing.md b/doc/operations/tracing.md
index 07f60c37f1b..b6ef552772e 100644
--- a/doc/operations/tracing.md
+++ b/doc/operations/tracing.md
@@ -1,12 +1,13 @@
---
stage: Monitor
-group: APM
+group: Health
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/#designated-technical-writers
---
-# Tracing **(ULTIMATE)**
+# Tracing
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/7903) in GitLab Ultimate 11.5.
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/7903) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 11.5.
+> - [Moved to GitLab Core](https://gitlab.com/gitlab-org/gitlab/-/issues/42645) in 13.5.
Tracing provides insight into the performance and health of a deployed application,
tracking each function or microservice which handles a given request.
diff --git a/doc/pages/README.md b/doc/pages/README.md
deleted file mode 100644
index c67847f1a83..00000000000
--- a/doc/pages/README.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../user/project/pages/index.md'
----
-
-This document was moved to [another location](../user/project/pages/index.md).
diff --git a/doc/pages/administration.md b/doc/pages/administration.md
deleted file mode 100644
index 015dd54ec7f..00000000000
--- a/doc/pages/administration.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../administration/pages/index.md'
----
-
-This document was moved to [another location](../administration/pages/index.md).
diff --git a/doc/pages/getting_started_part_one.md b/doc/pages/getting_started_part_one.md
deleted file mode 100644
index a0feed0b477..00000000000
--- a/doc/pages/getting_started_part_one.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../user/project/pages/getting_started_part_one.md'
----
-
-This document was moved to [another location](../user/project/pages/getting_started_part_one.md).
diff --git a/doc/pages/getting_started_part_three.md b/doc/pages/getting_started_part_three.md
deleted file mode 100644
index 31a01a6c83b..00000000000
--- a/doc/pages/getting_started_part_three.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../user/project/pages/custom_domains_ssl_tls_certification/index.md'
----
-
-This document was moved to [another location](../user/project/pages/custom_domains_ssl_tls_certification/index.md).
diff --git a/doc/pages/getting_started_part_two.md b/doc/pages/getting_started_part_two.md
deleted file mode 100644
index 05353c171fc..00000000000
--- a/doc/pages/getting_started_part_two.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../user/project/pages/getting_started_part_two.md'
----
-
-This document was moved to [another location](../user/project/pages/getting_started_part_two.md).
diff --git a/doc/policy/maintenance.md b/doc/policy/maintenance.md
index d2e556f3c8d..77b4b22e6a8 100644
--- a/doc/policy/maintenance.md
+++ b/doc/policy/maintenance.md
@@ -115,9 +115,9 @@ Please see the table below for some examples:
| Target version | Your version | Recommended upgrade path | Note |
| --------------------- | ------------ | ------------------------ | ---- |
-| `13.2.3` | `11.5.0` | `11.5.0` -> `11.11.8` -> `12.0.12` -> `12.10.14` -> `13.0.12` -> `13.2.3` | Four intermediate versions are required: the final `11.11`, `12.0`, and `12.10` releases, plus `13.0`. |
-| `13.0.12` | `11.10.8` | `11.10.5` -> `11.11.8` -> `12.0.12` -> `12.10.14` -> `13.0.12` | Three intermediate versions are required: `11.11`, `12.0`, and `12.10`. |
-| `12.10.14` | `11.3.4` | `11.3.4` -> `11.11.8` -> `12.0.12` -> `12.10.14` | Two intermediate versions are required: `11.11` and `12.0` |
+| `13.4.3` | `12.9.2` | `12.9.2` -> `12.10.14` -> `13.0.14` -> `13.4.3` | Two intermediate versions are required: the final `12.10` release, plus `13.0`. |
+| `13.2.10` | `11.5.0` | `11.5.0` -> `11.11.8` -> `12.0.12` -> `12.10.14` -> `13.0.14` -> `13.2.10` | Four intermediate versions are required: the final `11.11`, `12.0`, and `12.10` releases, plus `13.0`. |
+| `12.10.14` | `11.3.4` | `11.3.4` -> `11.11.8` -> `12.0.12` -> `12.10.14` | Two intermediate versions are required: the final `11.11` release and `12.0.12` |
| `12.9.5` | `10.4.5` | `10.4.5` -> `10.8.7` -> `11.11.8` -> `12.0.12` -> `12.9.5` | Three intermediate versions are required: `10.8`, `11.11`, and `12.0`, then `12.9.5` |
| `12.2.5` | `9.2.6` | `9.2.6` -> `9.5.10` -> `10.8.7` -> `11.11.8` -> `12.0.12` -> `12.2.5` | Four intermediate versions are required: `9.5`, `10.8`, `11.11`, `12.0`, then `12.2`. |
| `11.3.4` | `8.13.4` | `8.13.4` -> `8.17.7` -> `9.5.10` -> `10.8.7` -> `11.3.4` | `8.17.7` is the last version in version 8, `9.5.10` is the last version in version 9, `10.8.7` is the last version in version 10. |
diff --git a/doc/profile/README.md b/doc/profile/README.md
deleted file mode 100644
index 4932cf33b87..00000000000
--- a/doc/profile/README.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../user/profile/index.md'
----
-
-This document was moved to [user/profile/account](../user/profile/index.md).
diff --git a/doc/profile/preferences.md b/doc/profile/preferences.md
deleted file mode 100644
index cf99bd61f5d..00000000000
--- a/doc/profile/preferences.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../user/profile/preferences.md'
----
-
-This document was moved to [another location](../user/profile/preferences.md).
diff --git a/doc/profile/two_factor_authentication.md b/doc/profile/two_factor_authentication.md
deleted file mode 100644
index 453ac833f59..00000000000
--- a/doc/profile/two_factor_authentication.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../user/profile/account/two_factor_authentication.md'
----
-
-This document was moved to [user/profile/account](../user/profile/account/two_factor_authentication.md).
diff --git a/doc/project_services/bamboo.md b/doc/project_services/bamboo.md
deleted file mode 100644
index b1d37898516..00000000000
--- a/doc/project_services/bamboo.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../user/project/integrations/bamboo.md'
----
-
-This document was moved to [another location](../user/project/integrations/bamboo.md).
diff --git a/doc/project_services/bugzilla.md b/doc/project_services/bugzilla.md
deleted file mode 100644
index 17dff538c0e..00000000000
--- a/doc/project_services/bugzilla.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../user/project/integrations/bugzilla.md'
----
-
-This document was moved to [another location](../user/project/integrations/bugzilla.md).
diff --git a/doc/project_services/emails_on_push.md b/doc/project_services/emails_on_push.md
deleted file mode 100644
index a7d91934ce9..00000000000
--- a/doc/project_services/emails_on_push.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../user/project/integrations/emails_on_push.md'
----
-
-This document was moved to [another location](../user/project/integrations/emails_on_push.md).
diff --git a/doc/project_services/hipchat.md b/doc/project_services/hipchat.md
deleted file mode 100644
index a2fbbd5cce5..00000000000
--- a/doc/project_services/hipchat.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../user/project/integrations/hipchat.md'
----
-
-This document was moved to [another location](../user/project/integrations/hipchat.md).
diff --git a/doc/project_services/irker.md b/doc/project_services/irker.md
deleted file mode 100644
index 70e46b1b364..00000000000
--- a/doc/project_services/irker.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../user/project/integrations/irker.md'
----
-
-This document was moved to [another location](../user/project/integrations/irker.md).
diff --git a/doc/project_services/jira.md b/doc/project_services/jira.md
deleted file mode 100644
index 37eba25fb5a..00000000000
--- a/doc/project_services/jira.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../user/project/integrations/jira.md'
----
-
-This document was moved to [another location](../user/project/integrations/jira.md).
diff --git a/doc/project_services/kubernetes.md b/doc/project_services/kubernetes.md
deleted file mode 100644
index 585c5ddb002..00000000000
--- a/doc/project_services/kubernetes.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../user/project/integrations/kubernetes.md'
----
-
-This document was moved to [another location](../user/project/integrations/kubernetes.md).
diff --git a/doc/project_services/mattermost.md b/doc/project_services/mattermost.md
deleted file mode 100644
index 78888395031..00000000000
--- a/doc/project_services/mattermost.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../user/project/integrations/mattermost.md'
----
-
-This document was moved to [another location](../user/project/integrations/mattermost.md).
diff --git a/doc/project_services/mattermost_slash_commands.md b/doc/project_services/mattermost_slash_commands.md
deleted file mode 100644
index 0c2774d95e0..00000000000
--- a/doc/project_services/mattermost_slash_commands.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../user/project/integrations/mattermost_slash_commands.md'
----
-
-This document was moved to [another location](../user/project/integrations/mattermost_slash_commands.md).
diff --git a/doc/project_services/project_services.md b/doc/project_services/project_services.md
deleted file mode 100644
index 2d58e0ca065..00000000000
--- a/doc/project_services/project_services.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../user/project/integrations/overview.md'
----
-
-This document was moved to [another location](../user/project/integrations/overview.md).
diff --git a/doc/project_services/redmine.md b/doc/project_services/redmine.md
deleted file mode 100644
index 141c72d6b6b..00000000000
--- a/doc/project_services/redmine.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../user/project/integrations/redmine.md'
----
-
-This document was moved to [another location](../user/project/integrations/redmine.md).
diff --git a/doc/project_services/services_templates.md b/doc/project_services/services_templates.md
deleted file mode 100644
index 8b2c85802de..00000000000
--- a/doc/project_services/services_templates.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../user/project/integrations/services_templates.md'
----
-
-This document was moved to [another location](../user/project/integrations/services_templates.md).
diff --git a/doc/project_services/slack.md b/doc/project_services/slack.md
deleted file mode 100644
index 815032a08d5..00000000000
--- a/doc/project_services/slack.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../user/project/integrations/slack.md'
----
-
-This document was moved to [another location](../user/project/integrations/slack.md).
diff --git a/doc/project_services/slack_slash_commands.md b/doc/project_services/slack_slash_commands.md
deleted file mode 100644
index caae4d2ba4b..00000000000
--- a/doc/project_services/slack_slash_commands.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../user/project/integrations/slack_slash_commands.md'
----
-
-This document was moved to [another location](../user/project/integrations/slack_slash_commands.md).
diff --git a/doc/push_rules/push_rules.md b/doc/push_rules/push_rules.md
index 1643c96d229..d2ec157788a 100644
--- a/doc/push_rules/push_rules.md
+++ b/doc/push_rules/push_rules.md
@@ -97,7 +97,7 @@ The following options are available.
| Restrict by commit message (negative match)| **Starter** 11.1 | Only commit messages that do not match this regular expression are allowed to be pushed. Leave empty to allow any commit message. Uses multiline mode, which can be disabled using `(?-m)`. |
| Restrict by branch name | **Starter** 9.3 | Only branch names that match this regular expression are allowed to be pushed. Leave empty to allow any branch name. |
| Restrict by commit author's email | **Starter** 7.10 | Only commit author's email that match this regular expression are allowed to be pushed. Leave empty to allow any email. |
-| Prohibited file names | **Starter** 7.10 | Any committed filenames that match this regular expression are not allowed to be pushed. Leave empty to allow any filenames. |
+| Prohibited file names | **Starter** 7.10 | Any committed filenames that match this regular expression and do not already exist in the repository are not allowed to be pushed. Leave empty to allow any filenames. See [common examples](#prohibited-file-names). |
| Maximum file size | **Starter** 7.12 | Pushes that contain added or updated files that exceed this file size (in MB) are rejected. Set to 0 to allow files of any size. Files tracked by Git LFS are exempted. |
TIP: **Tip:**
@@ -178,6 +178,44 @@ pry.history
bash_history
```
+## Prohibited file names
+
+> Introduced in [GitLab Starter](https://about.gitlab.com/pricing/) 7.10.
+
+Each file name contained in a Git push is compared to the regular expression in this field. Filenames in Git consist of both the file's name and any directory that may precede it. A singular regular expression can contain multiple independent matches used as exclusions. File names can be broadly matched to any location in the repository, or restricted to specific locations. Filenames can also be partial matches used to exclude file types by extension.
+
+The following examples make use of regex string boundary characters which match the beginning of a string (`^`), and the end (`$`). They also include instances where either the directory path or the filename can include `.` or `/`. Both of these special regex characters have to be escaped with a backslash `\\` to be used as normal characters in a match condition.
+
+Example: prevent pushing any `.exe` files to any location in the repository. This is an example of a partial match, which can match any filename that contains `.exe` at the end:
+
+```plaintext
+\.exe$
+```
+
+Example: prevent a specific configuration file in the repository root from being pushed:
+
+```plaintext
+^config\.yml$
+```
+
+Example: prevent a specific configuration file in a known directory from being pushed:
+
+```plaintext
+^directory-name\/config\.yml$
+```
+
+Example: prevent the specific file named `install.exe` from being pushed to any location in the repository. Note that the parenthesized expression `(^|\/)` will match either a file following a directory separator or a file in the root directory of the repository:
+
+```plaintext
+(^|\/)install\.exe$
+```
+
+Example: combining all of the above in a single expression. Note that all of the preceding expressions rely on the end of string character `$`, so we can move that part of each expression to the end of the grouped collection of match conditions where it will be appended to all matches:
+
+```plaintext
+(\.exe|^config\.yml|^directory-name\/config\.yml|(^|\/)install\.exe)$
+```
+
<!-- ## Troubleshooting
Include any troubleshooting steps that you can foresee. If you know beforehand what issues
diff --git a/doc/raketasks/README.md b/doc/raketasks/README.md
index 523486d5137..7aec74f1243 100644
--- a/doc/raketasks/README.md
+++ b/doc/raketasks/README.md
@@ -21,7 +21,7 @@ The following are available Rake tasks:
| [Clean up](cleanup.md) | Clean up unneeded items from GitLab instances. |
| [Development](../development/rake_tasks.md) | Tasks for GitLab contributors. |
| [Doctor tasks](../administration/raketasks/doctor.md) | Checks for data integrity issues. |
-| [Elasticsearch](../integration/elasticsearch.md#gitlab-elasticsearch-rake-tasks) **(STARTER ONLY)** | Maintain Elasticsearch in a GitLab instance. |
+| [Elasticsearch](../integration/elasticsearch.md#gitlab-advanced-search-rake-tasks) **(STARTER ONLY)** | Maintain Elasticsearch in a GitLab instance. |
| [Enable namespaces](features.md) | Enable usernames and namespaces for user projects. |
| [General maintenance](../administration/raketasks/maintenance.md) | General maintenance and self-check tasks. |
| [Geo maintenance](../administration/raketasks/geo.md) **(PREMIUM ONLY)** | [Geo](../administration/geo/index.md)-related maintenance. |
diff --git a/doc/raketasks/backup_restore.md b/doc/raketasks/backup_restore.md
index 68b076258ce..066a38d68de 100644
--- a/doc/raketasks/backup_restore.md
+++ b/doc/raketasks/backup_restore.md
@@ -10,48 +10,41 @@ of GitLab on which it was created. The best way to migrate your repositories
from one server to another is through backup restore.
CAUTION: **Warning:**
-GitLab will not backup items that are not stored on the
-filesystem. If using [object storage](../administration/object_storage.md),
-remember to enable backups with your object storage provider if desired.
+GitLab won't back up items that aren't stored in the filesystem. If you're
+using [object storage](../administration/object_storage.md), be sure to enable
+backups with your object storage provider, if desired.
## Requirements
-In order to be able to backup and restore, you need one essential tool
-installed on your system.
+To be able to backup and restore, ensure that Rsync is installed on your
+system. If you installed GitLab:
-- **Rsync**: If you installed GitLab:
- - Using the Omnibus package, you're all set.
- - From source, make sure `rsync` is installed. For example:
+- _Using the Omnibus package_, you're all set.
+- _From source_, you need to determine if `rsync` is installed. For example:
- ```shell
- # Debian/Ubuntu
- sudo apt-get install rsync
+ ```shell
+ # Debian/Ubuntu
+ sudo apt-get install rsync
- # RHEL/CentOS
- sudo yum install rsync
- ```
+ # RHEL/CentOS
+ sudo yum install rsync
+ ```
## Backup timestamp
-NOTE: **Note:**
-In GitLab 9.2 the timestamp format was changed from `EPOCH_YYYY_MM_DD` to
-`EPOCH_YYYY_MM_DD_GitLab_version`, for example `1493107454_2018_04_25`
-would become `1493107454_2018_04_25_10.6.4-ce`.
-
The backup archive will be saved in `backup_path`, which is specified in the
-`config/gitlab.yml` file.
-The filename will be `[TIMESTAMP]_gitlab_backup.tar`, where `TIMESTAMP`
-identifies the time at which each backup was created, plus the GitLab version.
-The timestamp is needed if you need to restore GitLab and multiple backups are
-available.
+`config/gitlab.yml` file. The filename will be `[TIMESTAMP]_gitlab_backup.tar`,
+where `TIMESTAMP` identifies the time at which each backup was created, plus
+the GitLab version. The timestamp is needed if you need to restore GitLab and
+multiple backups are available.
For example, if the backup name is `1493107454_2018_04_25_10.6.4-ce_gitlab_backup.tar`,
-then the timestamp is `1493107454_2018_04_25_10.6.4-ce`.
+the timestamp is `1493107454_2018_04_25_10.6.4-ce`.
## Back up GitLab
-GitLab provides a simple command line interface to back up your whole instance.
-It backs up your:
+GitLab provides a command line interface to back up your entire instance,
+including:
- Database
- Attachments
@@ -61,49 +54,62 @@ It backs up your:
- LFS objects
- Container Registry images
- GitLab Pages content
+- Snippets
CAUTION: **Warning:**
-GitLab does not back up any configuration files, SSL certificates, or system files.
-You are highly advised to [read about storing configuration files](#storing-configuration-files).
+GitLab does not back up any configuration files, SSL certificates, or system
+files. You are highly advised to read about [storing configuration files](#storing-configuration-files).
-Use this command if you've installed GitLab with the Omnibus package:
+Depending on your version of GitLab, use the following command if you installed
+GitLab using the Omnibus package:
-```shell
-sudo gitlab-backup create
-```
+- GitLab 12.2 or later:
-NOTE: **Note:**
-For GitLab 12.1 and earlier, use `gitlab-rake gitlab:backup:create`.
+ ```shell
+ sudo gitlab-backup create
+ ```
-Use this if you've installed GitLab from source:
+- GitLab 12.1 and earlier:
+
+ ```shell
+ gitlab-rake gitlab:backup:create
+ ```
+
+If you installed GitLab from source, use the following command:
```shell
sudo -u git -H bundle exec rake gitlab:backup:create RAILS_ENV=production
```
-If you are running GitLab within a Docker container, you can run the backup from the host:
+If you're running GitLab from within a Docker container, run the backup from
+the host, based on your installed version of GitLab:
-```shell
-docker exec -t <container name> gitlab-backup create
-```
+- GitLab 12.2 or later:
-NOTE: **Note:**
-For GitLab 12.1 and earlier, use `gitlab-rake gitlab:backup:create`.
+ ```shell
+ docker exec -t <container name> gitlab-backup create
+ ```
-If you are using the [GitLab Helm chart](https://gitlab.com/gitlab-org/charts/gitlab) on a
-Kubernetes cluster, you can run the backup task using `backup-utility` script on
-the GitLab task runner pod via `kubectl`. Refer to [backing up a GitLab installation](https://gitlab.com/gitlab-org/charts/gitlab/blob/master/doc/backup-restore/backup.md#backing-up-a-gitlab-installation) for more details:
+- GitLab 12.1 and earlier:
+
+ ```shell
+ gitlab-rake gitlab:backup:create
+ ```
+
+If you're using the [GitLab Helm chart](https://gitlab.com/gitlab-org/charts/gitlab)
+on a Kubernetes cluster, you can run the backup task by using `kubectl` to run the `backup-utility`
+script on the GitLab task runner pod. For more details, see
+[backing up a GitLab installation](https://gitlab.com/gitlab-org/charts/gitlab/blob/master/doc/backup-restore/backup.md#backing-up-a-gitlab-installation).
```shell
kubectl exec -it <gitlab task-runner pod> backup-utility
```
-Similarly to the Kubernetes case, if you have scaled out your GitLab
-cluster to use multiple application servers, you should pick a
-designated node (that won't be auto-scaled away) for running the
-backup Rake task. Because the backup Rake task is tightly coupled to
-the main Rails application, this is typically a node on which you're
-also running Unicorn/Puma and/or Sidekiq.
+Similar to the Kubernetes case, if you have scaled out your GitLab cluster to
+use multiple application servers, you should pick a designated node (that won't
+be auto-scaled away) for running the backup Rake task. Because the backup Rake
+task is tightly coupled to the main Rails application, this is typically a node
+on which you're also running Unicorn/Puma or Sidekiq.
Example output:
@@ -136,11 +142,11 @@ Deleting old backups... [SKIPPING]
### Storing configuration files
-The [backup Rake task](#back-up-gitlab) GitLab provides
-does **not** store your configuration files. The primary reason for this is that your
-database contains encrypted information for two-factor authentication, the CI/CD
-'secure variables', and so on. Storing encrypted information along with its key in the
-same place defeats the purpose of using encryption in the first place.
+The [backup Rake task](#back-up-gitlab) GitLab provides does _not_ store your
+configuration files. The primary reason for this is that your database contains
+items including encrypted information for two-factor authentication and the
+CI/CD _secure variables_. Storing encrypted information in the same location
+as its key defeats the purpose of using encryption in the first place.
CAUTION: **Warning:**
The secrets file is essential to preserve your database encryption key.
@@ -158,30 +164,31 @@ For installation from source:
- `/home/git/gitlab/config/gitlab.yml`
For [Docker installations](https://docs.gitlab.com/omnibus/docker/), you must
-back up the volume where the configuration files are stored. If you have created
-the GitLab container according to the documentation, it should be under
-`/srv/gitlab/config`.
+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.
-For [GitLab Helm chart Installations](https://gitlab.com/gitlab-org/charts/gitlab) on a
-Kubernetes cluster, you must follow the [Backup the secrets](https://docs.gitlab.com/charts/backup-restore/backup.html#backup-the-secrets) instructions.
+For [GitLab Helm chart installations](https://gitlab.com/gitlab-org/charts/gitlab)
+on a Kubernetes cluster, you must follow the
+[Backup the secrets](https://docs.gitlab.com/charts/backup-restore/backup.html#backup-the-secrets)
+instructions.
You may also want to back up any TLS keys and certificates, and your
[SSH host keys](https://superuser.com/questions/532040/copy-ssh-keys-from-one-server-to-another-server/532079#532079).
-If you use Omnibus GitLab, see some additional information
-[to backup your configuration](https://docs.gitlab.com/omnibus/settings/backups.html).
+If you use Omnibus GitLab, review additional information to
+[backup your configuration](https://docs.gitlab.com/omnibus/settings/backups.html).
In the unlikely event that the secrets file is lost, see the
[troubleshooting section](#when-the-secrets-file-is-lost).
### Backup options
-The command line tool GitLab provides to backup your instance can take more options.
+The command line tool GitLab provides to backup your instance can accept more
+options.
#### Backup strategy option
-> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/8728) in GitLab 8.17.
-
The default backup strategy is to essentially stream data from the respective
data locations to the backup using the Linux command `tar` and `gzip`. This works
fine in most cases, but can cause problems when data is rapidly changing.
@@ -203,8 +210,7 @@ To use the `copy` strategy instead of the default streaming strategy, specify
sudo gitlab-backup create STRATEGY=copy
```
-NOTE: **Note:**
-For GitLab 12.1 and earlier, use `gitlab-rake gitlab:backup:create`.
+Users of GitLab 12.1 and earlier should use the command `gitlab-rake gitlab:backup:create` instead.
#### Backup filename
@@ -212,34 +218,41 @@ CAUTION: **Warning:**
If you use a custom backup filename, you will not be able to
[limit the lifetime of the backups](#limit-backup-lifetime-for-local-files-prune-old-backups).
-By default a backup file is created according to the specification in [the Backup timestamp](#backup-timestamp) section above. You can however override the `[TIMESTAMP]` part of the filename by setting the `BACKUP` environment variable. For example:
+By default, a backup file is created according to the specification in the
+previous [Backup timestamp](#backup-timestamp) section. You can, however,
+override the `[TIMESTAMP]` portion of the filename by setting the `BACKUP`
+environment variable. For example:
```shell
sudo gitlab-backup create BACKUP=dump
```
-NOTE: **Note:**
-For GitLab 12.1 and earlier, use `gitlab-rake gitlab:backup:create`.
+Users of GitLab 12.1 and earlier should use the command `gitlab-rake gitlab:backup:create` instead.
-The resulting file will then be `dump_gitlab_backup.tar`. This is useful for systems that make use of rsync and incremental backups, and will result in considerably faster transfer speeds.
+The resulting file will then be `dump_gitlab_backup.tar`. This is useful for
+systems that make use of rsync and incremental backups, and will result in
+considerably faster transfer speeds.
#### Rsyncable
-To make sure the generated archive is intelligently transferable by rsync, the `GZIP_RSYNCABLE=yes` option can be set. This will set the `--rsyncable` option to `gzip`. This is only useful in combination with setting [the Backup filename option](#backup-filename).
+To ensure the generated archive is transferable by rsync, you can set the `GZIP_RSYNCABLE=yes`
+option. This sets the `--rsyncable` option to `gzip`, which is useful only in
+combination with setting [the Backup filename option](#backup-filename).
-Note that the `--rsyncable` option in `gzip` is not guaranteed to be available on all distributions. To verify that it is available in your distribution you can run `gzip --help` or consult the man pages.
+Note that the `--rsyncable` option in `gzip` isn't guaranteed to be available
+on all distributions. To verify that it's available in your distribution, run
+`gzip --help` or consult the man pages.
```shell
sudo gitlab-backup create BACKUP=dump GZIP_RSYNCABLE=yes
```
-NOTE: **Note:**
-For GitLab 12.1 and earlier, use `gitlab-rake gitlab:backup:create`.
+Users of GitLab 12.1 and earlier should use the command `gitlab-rake gitlab:backup:create` instead.
#### Excluding specific directories from the backup
-You can choose what should be exempt from the backup up by adding the environment variable `SKIP`.
-The available options are:
+You can choose what should be exempt from the backup by adding the environment
+variable `SKIP`. The available options are:
- `db` (database)
- `uploads` (attachments)
@@ -252,8 +265,8 @@ The available options are:
Use a comma to specify several options at the same time:
-All wikis will be backed up as part of the `repositories` group. Non-existent wikis
-will be skipped during a backup.
+All wikis will be backed up as part of the `repositories` group. Non-existent
+wikis will be skipped during a backup.
For Omnibus GitLab packages:
@@ -261,8 +274,7 @@ For Omnibus GitLab packages:
sudo gitlab-backup create SKIP=db,uploads
```
-NOTE: **Note:**
-For GitLab 12.1 and earlier, use `gitlab-rake gitlab:backup:create`.
+Users of GitLab 12.1 and earlier should use the command `gitlab-rake gitlab:backup:create` instead.
For installations from source:
@@ -317,13 +329,15 @@ sudo -u git -H GITLAB_ASSUME_YES=1 bundle exec rake gitlab:backup:restore RAILS_
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/37158) in GitLab 13.3.
-Repositories can be backed up concurrently to help fully utilise CPU time. The following variables
-are available to modify the default behavior of the Rake task:
+Repositories can be backed up concurrently to help fully utilize CPU time. The
+following variables are available to modify the default behavior of the Rake
+task:
-- `GITLAB_BACKUP_MAX_CONCURRENCY` sets the maximum number of projects to backup at the same time.
- Defaults to 1.
-- `GITLAB_BACKUP_MAX_STORAGE_CONCURRENCY` sets the maximum number of projects to backup at the same time on each storage. This allows the repository backups to be spread across storages.
- Defaults to 1.
+- `GITLAB_BACKUP_MAX_CONCURRENCY`: The maximum number of projects to back up at
+ the same time. Defaults to `1`.
+- `GITLAB_BACKUP_MAX_STORAGE_CONCURRENCY`: The maximum number of projects to
+ back up at the same time on each storage. This allows the repository backups
+ to be spread across storages. Defaults to `1`.
For example, for Omnibus GitLab installations:
@@ -339,12 +353,11 @@ sudo -u git -H bundle exec rake gitlab:backup:create GITLAB_BACKUP_MAX_CONCURREN
#### Uploading backups to a remote (cloud) storage
-Starting with GitLab 7.4 you can let the backup script upload the `.tar` file it creates.
-It uses the [Fog library](http://fog.io/) to perform the upload.
-In the example below we use Amazon S3 for storage, but Fog also lets you use
-[other storage providers](http://fog.io/storage/). GitLab
-[imports cloud drivers](https://gitlab.com/gitlab-org/gitlab/blob/30f5b9a5b711b46f1065baf755e413ceced5646b/Gemfile#L88)
-for AWS, Google, OpenStack Swift, Rackspace, and Aliyun as well. A local driver is
+You can let the backup script upload (using the [Fog library](http://fog.io/))
+the `.tar` file it creates. In the following example, we use Amazon S3 for
+storage, but Fog also lets you use [other storage providers](http://fog.io/storage/).
+GitLab also [imports cloud drivers](https://gitlab.com/gitlab-org/gitlab/blob/da46c9655962df7d49caef0e2b9f6bbe88462a02/Gemfile#L113)
+for AWS, Google, OpenStack Swift, Rackspace, and Aliyun. A local driver is
[also available](#uploading-to-locally-mounted-shares).
[Read more about using object storage with GitLab](../administration/object_storage.md).
@@ -367,11 +380,12 @@ For Omnibus GitLab packages:
gitlab_rails['backup_upload_remote_directory'] = 'my.s3.bucket'
```
-1. [Reconfigure GitLab](../administration/restart_gitlab.md#omnibus-gitlab-reconfigure) for the changes to take effect
+1. [Reconfigure GitLab](../administration/restart_gitlab.md#omnibus-gitlab-reconfigure)
+ for the changes to take effect
##### Digital Ocean Spaces
-This example can be used for a bucket in Amsterdam (AMS3).
+This example can be used for a bucket in Amsterdam (AMS3):
1. Add the following to `/etc/gitlab/gitlab.rb`:
@@ -386,20 +400,20 @@ This example can be used for a bucket in Amsterdam (AMS3).
gitlab_rails['backup_upload_remote_directory'] = 'my.s3.bucket'
```
-1. [Reconfigure GitLab](../administration/restart_gitlab.md#omnibus-gitlab-reconfigure) for the changes to take effect
+1. [Reconfigure GitLab](../administration/restart_gitlab.md#omnibus-gitlab-reconfigure)
+ for the changes to take effect
-NOTE: **Note:**
-If you see `400 Bad Request` by using Digital Ocean Spaces, the cause may be the
-usage of backup encryption. Remove or comment the line that
-contains `gitlab_rails['backup_encryption']` since Digital Ocean Spaces
-doesn't support encryption.
+If you see a `400 Bad Request` error message when using Digital Ocean Spaces,
+the cause may be the use of backup encryption. Because Digital Ocean Spaces
+doesn't support encryption, remove or comment the line that contains
+`gitlab_rails['backup_encryption']`.
##### Other S3 Providers
-Not all S3 providers are fully-compatible with the Fog library. For example,
-if you see `411 Length Required` errors after attempting to upload, you may
-need to downgrade the `aws_signature_version` value from the default value to
-2 [due to this issue](https://github.com/fog/fog-aws/issues/428).
+Not all S3 providers are fully compatible with the Fog library. For example,
+if you see a `411 Length Required` error message after attempting to upload,
+you may need to downgrade the `aws_signature_version` value from the default
+value to `2`, [due to this issue](https://github.com/fog/fog-aws/issues/428).
For installations from source:
@@ -431,9 +445,10 @@ For installations from source:
# storage_class: 'STANDARD'
```
-1. [Restart GitLab](../administration/restart_gitlab.md#installations-from-source) for the changes to take effect
+1. [Restart GitLab](../administration/restart_gitlab.md#installations-from-source)
+ for the changes to take effect
-If you are uploading your backups to S3 you will probably want to create a new
+If you're uploading your backups to S3, you'll probably want to create a new
IAM user with restricted access rights. To give the upload user access only for
uploading backups create the following IAM profile, replacing `my.s3.bucket`
with the name of your bucket:
@@ -486,16 +501,16 @@ with the name of your bucket:
##### Using Google Cloud Storage
-If you want to use Google Cloud Storage to save backups, you'll have to create
-an access key from the Google console first:
+To use Google Cloud Storage to save backups, you must first create an
+access key from the Google console:
-1. Go to the storage settings page <https://console.cloud.google.com/storage/settings>
-1. Select "Interoperability" and create an access key
-1. Make note of the "Access Key" and "Secret" and replace them in the
- configurations below
-1. In the buckets advanced settings ensure the Access Control option "Set object-level
- and bucket-level permissions" is selected
-1. Make sure you already have a bucket created
+1. Go to the [Google storage settings page](https://console.cloud.google.com/storage/settings).
+1. Select **Interoperability**, and then create an access key.
+1. Make note of the **Access Key** and **Secret** and replace them in the
+ following configurations.
+1. In the buckets advanced settings ensure the Access Control option
+ **Set object-level and bucket-level permissions** is selected.
+1. Ensure you have already created a bucket.
For Omnibus GitLab packages:
@@ -516,7 +531,8 @@ For Omnibus GitLab packages:
gitlab_rails['backup_upload_remote_directory'] = 'my.google.bucket'
```
-1. [Reconfigure GitLab](../administration/restart_gitlab.md#omnibus-gitlab-reconfigure) for the changes to take effect
+1. [Reconfigure GitLab](../administration/restart_gitlab.md#omnibus-gitlab-reconfigure)
+ for the changes to take effect
For installations from source:
@@ -532,7 +548,8 @@ For installations from source:
remote_directory: 'my.google.bucket'
```
-1. [Restart GitLab](../administration/restart_gitlab.md#installations-from-source) for the changes to take effect
+1. [Restart GitLab](../administration/restart_gitlab.md#installations-from-source)
+ for the changes to take effect
##### Using Azure Blob storage
@@ -552,7 +569,8 @@ For Omnibus GitLab packages:
gitlab_rails['backup_upload_remote_directory'] = '<AZURE BLOB CONTAINER>'
```
-1. [Reconfigure GitLab](../administration/restart_gitlab.md#omnibus-gitlab-reconfigure) for the changes to take effect
+1. [Reconfigure GitLab](../administration/restart_gitlab.md#omnibus-gitlab-reconfigure)
+ for the changes to take effect
For installations from source:
@@ -568,13 +586,14 @@ For installations from source:
remote_directory: '<AZURE BLOB CONTAINER>'
```
-1. [Restart GitLab](../administration/restart_gitlab.md#installations-from-source) for the changes to take effect
+1. [Restart GitLab](../administration/restart_gitlab.md#installations-from-source)
+ for the changes to take effect
-See [the table of Azure parameters](../administration/object_storage.md#azure-blob-storage) for more details.
+For more details, see the [table of Azure parameters](../administration/object_storage.md#azure-blob-storage).
##### Specifying a custom directory for backups
-Note: This option only works for remote storage. If you want to group your backups
+This option works only for remote storage. If you want to group your backups,
you can pass a `DIRECTORY` environment variable:
```shell
@@ -582,26 +601,25 @@ sudo gitlab-backup create DIRECTORY=daily
sudo gitlab-backup create DIRECTORY=weekly
```
-NOTE: **Note:**
-For GitLab 12.1 and earlier, use `gitlab-rake gitlab:backup:create`.
+Users of GitLab 12.1 and earlier should use the command `gitlab-rake gitlab:backup:create` instead.
#### Uploading to locally mounted shares
-You may also send backups to a mounted share (for example, `NFS`,`CIFS`, or `SMB`) by
-using the Fog [`Local`](https://github.com/fog/fog-local#usage) storage provider.
-The directory pointed to by the `local_root` key **must** be owned by the `git`
-user **when mounted** (mounting with the `uid=` of the `git` user for `CIFS` and
-`SMB`) or the user that you are executing the backup tasks under (for Omnibus
-packages, this is the `git` user).
+You may also send backups to a mounted share (for example, `NFS`,`CIFS`, or
+`SMB`) by using the Fog [`Local`](https://github.com/fog/fog-local#usage)
+storage provider. The directory pointed to by the `local_root` key _must_ be
+owned by the `git` user _when mounted_ (mounting with the `uid=` of the `git`
+user for `CIFS` and `SMB`) or the user that you are executing the backup tasks
+as (for Omnibus packages, this is the `git` user).
-The `backup_upload_remote_directory` **must** be set in addition to the
+The `backup_upload_remote_directory` _must_ be set in addition to the
`local_root` key. This is the sub directory inside the mounted directory that
backups will be copied to, and will be created if it does not exist. If the
directory that you want to copy the tarballs to is the root of your mounted
-directory, just use `.` instead.
+directory, use `.` instead.
-NOTE: **Note:**
-Since file system performance may affect GitLab's overall performance, we do not recommend using EFS for storage. See the [relevant documentation](../administration/nfs.md#avoid-using-awss-elastic-file-system-efs) for more details.
+Because file system performance may affect GitLab's overall performance,
+[GitLab doesn't recommend using EFS for storage](../administration/nfs.md#avoid-using-awss-elastic-file-system-efs).
For Omnibus GitLab packages:
@@ -618,7 +636,8 @@ For Omnibus GitLab packages:
gitlab_rails['backup_upload_remote_directory'] = 'gitlab_backups'
```
-1. [Reconfigure GitLab](../administration/restart_gitlab.md#omnibus-gitlab-reconfigure) for the changes to take effect.
+1. [Reconfigure GitLab](../administration/restart_gitlab.md#omnibus-gitlab-reconfigure)
+ for the changes to take effect.
For installations from source:
@@ -636,14 +655,16 @@ For installations from source:
remote_directory: 'gitlab_backups'
```
-1. [Restart GitLab](../administration/restart_gitlab.md#installations-from-source) for the changes to take effect.
+1. [Restart GitLab](../administration/restart_gitlab.md#installations-from-source)
+ for the changes to take effect.
#### Backup archive permissions
The backup archives created by GitLab (`1393513186_2014_02_27_gitlab_backup.tar`)
-will have owner/group `git`/`git` and 0600 permissions by default.
-This is meant to avoid other system users reading GitLab's data.
-If you need the backup archives to have different permissions you can use the 'archive_permissions' setting.
+will have owner/group `git`/`git` and 0600 permissions by default. This is
+meant to avoid other system users reading GitLab's data. If you need the backup
+archives to have different permissions, you can use the `archive_permissions`
+setting.
For Omnibus GitLab packages:
@@ -653,7 +674,8 @@ For Omnibus GitLab packages:
gitlab_rails['backup_archive_permissions'] = 0644 # Makes the backup archives world-readable
```
-1. [Reconfigure GitLab](../administration/restart_gitlab.md#omnibus-gitlab-reconfigure) for the changes to take effect.
+1. [Reconfigure GitLab](../administration/restart_gitlab.md#omnibus-gitlab-reconfigure)
+ for the changes to take effect.
For installations from source:
@@ -664,7 +686,8 @@ For installations from source:
archive_permissions: 0644 # Makes the backup archives world-readable
```
-1. [Restart GitLab](../administration/restart_gitlab.md#installations-from-source) for the changes to take effect.
+1. [Restart GitLab](../administration/restart_gitlab.md#installations-from-source)
+ for the changes to take effect.
#### Configuring cron to make daily backups
@@ -689,8 +712,7 @@ For Omnibus GitLab packages:
0 2 * * * /opt/gitlab/bin/gitlab-backup create CRON=1
```
- NOTE: **Note:**
- For GitLab 12.1 and earlier, use `gitlab-rake gitlab:backup:create`.
+ Users of GitLab 12.1 and earlier should use the command `gitlab-rake gitlab:backup:create` instead.
For installations from source:
@@ -707,26 +729,25 @@ For installations from source:
0 2 * * * cd /home/git/gitlab && PATH=/usr/local/bin:/usr/bin:/bin bundle exec rake gitlab:backup:create RAILS_ENV=production CRON=1
```
-NOTE: **Note:**
-The `CRON=1` environment setting tells the backup script to suppress all progress output if there are no errors.
-This is recommended to reduce cron spam.
+The `CRON=1` environment setting directs the backup script to hide all progress
+output if there aren't any errors. This is recommended to reduce cron spam.
### Limit backup lifetime for local files (prune old backups)
CAUTION: **Warning:**
-This will not work if you have used a [custom filename](#backup-filename)
+The process described in this section will not work if you used a [custom filename](#backup-filename)
for your backups.
-NOTE: **Note:**
-This configuration option only manages local files. GitLab does not automatically
-prune old files stored in a third-party [object storage](#uploading-backups-to-a-remote-cloud-storage)
-because the user may not have permission to list and delete files. It is
+To prevent regular backups from using all your disk space, you may want to set a limited lifetime
+for backups. The next time the backup task runs, backups older than the `backup_keep_time` are
+pruned.
+
+This configuration option manages only local files. GitLab doesn't prune old
+files stored in a third-party [object storage](#uploading-backups-to-a-remote-cloud-storage)
+because the user may not have permission to list and delete files. It's
recommended that you configure the appropriate retention policy for your object
storage (for example, [AWS S3](https://docs.aws.amazon.com/AmazonS3/latest/user-guide/create-lifecycle.html)).
-You may want to set a limited lifetime for backups to prevent regular
-backups using all your disk space. The next time the backup task is run, backups older than the `backup_keep_time` will be pruned.
-
For Omnibus GitLab packages:
1. Edit `/etc/gitlab/gitlab.rb`:
@@ -736,7 +757,8 @@ For Omnibus GitLab packages:
gitlab_rails['backup_keep_time'] = 604800
```
-1. [Reconfigure GitLab](../administration/restart_gitlab.md#omnibus-gitlab-reconfigure) for the changes to take effect.
+1. [Reconfigure GitLab](../administration/restart_gitlab.md#omnibus-gitlab-reconfigure)
+ for the changes to take effect.
For installations from source:
@@ -748,61 +770,64 @@ For installations from source:
keep_time: 604800
```
-1. [Restart GitLab](../administration/restart_gitlab.md#installations-from-source) for the changes to take effect.
+1. [Restart GitLab](../administration/restart_gitlab.md#installations-from-source)
+ for the changes to take effect.
## Restore GitLab
-GitLab provides a simple command line interface to restore your whole installation,
+GitLab provides a command line interface to restore your entire installation,
and is flexible enough to fit your needs.
The [restore prerequisites section](#restore-prerequisites) includes crucial
-information. Make sure to read and test the whole restore process at least once
-before attempting to perform it in a production environment.
+information. Be sure to read and test the complete restore process at least
+once before attempting to perform it in a production environment.
-You can only restore a backup to **exactly the same version and type (CE/EE)** of
-GitLab that you created it on, for example CE 9.1.0.
+You can restore a backup only to _the exact same version and type (CE/EE)_ of
+GitLab that you created it on (for example CE 9.1.0).
-If your backup is a different version than the current installation, you will
+If your backup is a different version than the current installation, you'll
need to [downgrade your GitLab installation](https://docs.gitlab.com/omnibus/update/README.html#downgrade)
before restoring the backup.
### Restore prerequisites
-You need to have a working GitLab installation before you can perform
-a restore. This is mainly because the system user performing the
-restore actions (`git`) is usually not allowed to create or delete
-the SQL database it needs to import data into (`gitlabhq_production`).
-All existing data will be either erased (SQL) or moved to a separate
-directory (repositories, uploads).
+You need to have a working GitLab installation before you can perform a
+restore. This is because the system user performing the restore actions (`git`)
+is usually not allowed to create or delete the SQL database needed to import
+data into (`gitlabhq_production`). All existing data will be either erased
+(SQL) or moved to a separate directory (such as repositories and uploads).
-To restore a backup, you will also need to restore `/etc/gitlab/gitlab-secrets.json`
-(for Omnibus packages) or `/home/git/gitlab/.secret` (for installations
-from source). This file contains the database encryption key,
+To restore a backup, you'll also need to restore `/etc/gitlab/gitlab-secrets.json`
+(for Omnibus packages) or `/home/git/gitlab/.secret` (for installations from
+source). This file contains the database encryption key,
[CI/CD variables](../ci/variables/README.md#gitlab-cicd-environment-variables), and
variables used for [two-factor authentication](../user/profile/account/two_factor_authentication.md).
If you fail to restore this encryption key file along with the application data
backup, users with two-factor authentication enabled and GitLab Runner will
lose access to your GitLab server.
-You may also want to restore any TLS keys, certificates, or [SSH host keys](https://superuser.com/questions/532040/copy-ssh-keys-from-one-server-to-another-server/532079#532079).
+You may also want to restore any TLS keys, certificates, or
+[SSH host keys](https://superuser.com/questions/532040/copy-ssh-keys-from-one-server-to-another-server/532079#532079).
-Starting with GitLab 12.9 if an untarred backup (like the ones made with
+Starting with GitLab 12.9, if an untarred backup (like the ones made with
`SKIP=tar`) is found, and no backup is chosen with `BACKUP=<timestamp>`, the
untarred backup is used.
Depending on your case, you might want to run the restore command with one or
more of the following options:
-- `BACKUP=timestamp_of_backup` - Required if more than one backup exists.
+- `BACKUP=timestamp_of_backup`: Required if more than one backup exists.
Read what the [backup timestamp is about](#backup-timestamp).
-- `force=yes` - Does not ask if the authorized_keys file should get regenerated and assumes 'yes' for warning that database tables will be removed, enabling the "Write to authorized_keys file" setting, and updating LDAP providers.
+- `force=yes`: Doesn't ask if the authorized_keys file should get regenerated,
+ and assumes 'yes' for warning that database tables will be removed,
+ enabling the "Write to authorized_keys file" setting, and updating LDAP
+ providers.
-If you are restoring into directories that are mount points, you will need to make
-sure these directories are empty before attempting a restore. Otherwise GitLab
-will attempt to move these directories before restoring the new data and this
-would cause an error.
+If you're restoring into directories that are mount points, you must ensure these directories are
+empty before attempting a restore. Otherwise, GitLab attempts to move these directories before
+restoring the new data, which causes an error.
-Read more on [configuring NFS mounts](../administration/nfs.md)
+Read more about [configuring NFS mounts](../administration/nfs.md)
### Restore for installation from source
@@ -845,7 +870,7 @@ Restoring repositories:
Deleting tmp directories...[DONE]
```
-Next, restore `/home/git/gitlab/.secret` if necessary as mentioned above.
+Next, restore `/home/git/gitlab/.secret` if necessary, as previously mentioned.
Restart GitLab:
@@ -862,7 +887,7 @@ This procedure assumes that:
- You have run `sudo gitlab-ctl reconfigure` at least once.
- GitLab is running. If not, start it using `sudo gitlab-ctl start`.
-First make sure your backup tar file is in the backup directory described in the
+First ensure your backup tar file is in the backup directory described in the
`gitlab.rb` configuration `gitlab_rails['backup_path']`. The default is
`/var/opt/gitlab/backups`. It needs to be owned by the `git` user.
@@ -890,15 +915,16 @@ restore:
sudo gitlab-backup restore BACKUP=11493107454_2018_04_25_10.6.4-ce
```
-NOTE: **Note:**
-For GitLab 12.1 and earlier, use `gitlab-rake gitlab:backup:restore`.
+Users of GitLab 12.1 and earlier should use the command `gitlab-rake gitlab:backup:restore` instead.
CAUTION: **Warning:**
-`gitlab-rake gitlab:backup:restore` does not set the right file system permissions on your Registry directory.
-This is a [known issue](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/62759). On GitLab 12.2 or newer, you can
-use `gitlab-backup restore` to avoid this issue.
+`gitlab-rake gitlab:backup:restore` doesn't set the correct file system
+permissions on your Registry directory. This is a [known issue](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/62759).
+On GitLab 12.2 or later, you can use `gitlab-backup restore` to avoid this
+issue.
-Next, restore `/etc/gitlab/gitlab-secrets.json` if necessary as mentioned above.
+Next, restore `/etc/gitlab/gitlab-secrets.json` if necessary, as previously
+mentioned.
Reconfigure, restart and check GitLab:
@@ -908,29 +934,29 @@ sudo gitlab-ctl restart
sudo gitlab-rake gitlab:check SANITIZE=true
```
-If there is a GitLab version mismatch between your backup tar file and the installed
-version of GitLab, the restore command will abort with an error. Install the
-[correct GitLab version](https://packages.gitlab.com/gitlab/) and try again.
+If there's a GitLab version mismatch between your backup tar file and the
+installed version of GitLab, the restore command aborts with an error
+message. Install the [correct GitLab version](https://packages.gitlab.com/gitlab/),
+and then try again.
NOTE: **Note:**
-There is currently a [known issue](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/3470) for restore not working
-with `pgbouncer`. In order to workaround the issue, the Rails node will need to bypass `pgbouncer` and connect
-directly to the primary database node. This can be done by setting `gitlab_rails['db_host']` and `gitlab_rails['port']`
-to connect to the primary database node and [reconfiguring GitLab](../administration/restart_gitlab.md#omnibus-gitlab-reconfigure).
+There is a known issue with restore not working with `pgbouncer`. The [workaround is to bypass
+`pgbouncer` and connect directly to the primary database node](../administration/postgresql/pgbouncer.md#procedure-for-bypassing-pgbouncer).
+[Read more about backup and restore with `pgbouncer`](#backup-and-restore-for-installations-using-pgbouncer).
### Restore for Docker image and GitLab Helm chart installations
-For GitLab installations using the Docker image or the GitLab Helm chart on
-a Kubernetes cluster, the restore task expects the restore directories to be empty.
-However, with Docker and Kubernetes volume mounts, some system level directories
-may be created at the volume roots, like `lost+found` directory found in Linux
-operating systems. These directories are usually owned by `root`, which can
-cause access permission errors since the restore Rake task runs as `git` user.
-So, to restore a GitLab installation, users have to confirm the restore target
-directories are empty.
+For GitLab installations using the Docker image or the GitLab Helm chart on a
+Kubernetes cluster, the restore task expects the restore directories to be
+empty. However, with Docker and Kubernetes volume mounts, some system level
+directories may be created at the volume roots, such as the `lost+found`
+directory found in Linux operating systems. These directories are usually owned
+by `root`, which can cause access permission errors since the restore Rake task
+runs as the `git` user. To restore a GitLab installation, users have to confirm
+the restore target directories are empty.
-For both these installation types, the backup tarball has to be available in the
-backup location (default location is `/var/opt/gitlab/backups`).
+For both these installation types, the backup tarball has to be available in
+the backup location (default location is `/var/opt/gitlab/backups`).
For Docker installations, the restore task can be run from host:
@@ -953,43 +979,43 @@ docker restart <name of container>
docker exec -it <name of container> gitlab-rake gitlab:check SANITIZE=true
```
-NOTE: **Note:**
-For GitLab 12.1 and earlier, use `gitlab-rake gitlab:backup:restore`.
+Users of GitLab 12.1 and earlier should use the command `gitlab-rake gitlab:backup:create` instead.
CAUTION: **Warning:**
-`gitlab-rake gitlab:backup:restore` does not set the right file system permissions on your Registry directory.
-This is a [known issue](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/62759). On GitLab 12.2 or newer, you can
-use `gitlab-backup restore` to avoid this issue.
+`gitlab-rake gitlab:backup:restore` doesn't set the correct file system
+permissions on your Registry directory. This is a [known issue](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/62759).
+On GitLab 12.2 or later, you can use `gitlab-backup restore` to avoid this
+issue.
The GitLab Helm chart uses a different process, documented in
[restoring a GitLab Helm chart installation](https://gitlab.com/gitlab-org/charts/gitlab/blob/master/doc/backup-restore/restore.md).
### Restoring only one or a few project(s) or group(s) from a backup
-While the Rake task used to restore a GitLab instance doesn't support
-restoring a single project or group, you can use a workaround by
-restoring your backup to a separate, temporary GitLab instance, and
-export your project or group from there:
+Although the Rake task used to restore a GitLab instance doesn't support
+restoring a single project or group, you can use a workaround by restoring
+your backup to a separate, temporary GitLab instance, and then export your
+project or group from there:
1. [Install a new GitLab](../install/README.md) instance at the same version as
the backed-up instance from which you want to restore.
-1. [Restore the backup](#restore-gitlab) into this new instance and
+1. [Restore the backup](#restore-gitlab) into this new instance, then
export your [project](../user/project/settings/import_export.md)
- or [group](../user/group/settings/import_export.md). Make sure to
- read the **Important Notes** on either export feature's documentation
- to understand what will be exported and what not.
-1. Once the export is complete, go to the old instance and import it.
-1. After importing only the project(s) or group(s) that you wanted is complete,
- you may delete the new, temporary GitLab instance.
+ or [group](../user/group/settings/import_export.md). Be sure to read the
+ **Important Notes** on either export feature's documentation to understand
+ what is and isn't exported.
+1. After the export is complete, go to the old instance and then import it.
+1. After importing the projects or groups that you wanted is complete, you may
+ delete the new, temporary GitLab instance.
-NOTE: **Note:**
A feature request to provide direct restore of individual projects or groups
is being discussed in [issue #17517](https://gitlab.com/gitlab-org/gitlab/-/issues/17517).
## Alternative backup strategies
-If your GitLab server contains a lot of Git repository data you may find the GitLab backup script to be too slow.
-In this case you can consider using filesystem snapshots as part of your backup strategy.
+If your GitLab server contains a lot of Git repository data, you may find the
+GitLab backup script to be too slow. In this case you can consider using
+filesystem snapshots as part of your backup strategy.
Example: Amazon EBS
@@ -1006,29 +1032,56 @@ Example: LVM snapshots + rsync
> Now we can have a longer running rsync job which will create a consistent replica on the remote server.
> The replica includes all repositories, uploads and PostgreSQL data.
-If you are running GitLab on a virtualized server you can possibly also create VM snapshots of the entire GitLab server.
-It is not uncommon however for a VM snapshot to require you to power down the server, so this approach is probably of limited practical use.
+If you're running GitLab on a virtualized server, you can possibly also create
+VM snapshots of the entire GitLab server. It's not uncommon however for a VM
+snapshot to require you to power down the server, which limits this solution's
+practical use.
+
+## Backup and restore for installations using PgBouncer
+
+PgBouncer can cause the following errors when performing backups and restores:
+
+```ruby
+ActiveRecord::StatementInvalid: PG::UndefinedTable
+```
+
+There is a [known issue](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/3470) for restore not working
+with `pgbouncer`.
+
+To workaround this issue, the GitLab server will need to bypass `pgbouncer` and
+[connect directly to the primary database node](../administration/postgresql/pgbouncer.md#procedure-for-bypassing-pgbouncer)
+to perform the database restore.
+
+There is also a [known issue](https://gitlab.com/gitlab-org/gitlab/-/issues/23211)
+with PostgreSQL 9 and running a database backup through PgBouncer that can cause
+an outage to GitLab. If you're still on PostgreSQL 9 and upgrading PostgreSQL isn't
+an option, workarounds include having a dedicated application node just for backups,
+configured to connect directly the primary database node as noted above. You're
+advised to upgrade your PostgreSQL version though, GitLab 11.11 shipped with PostgreSQL
+10.7, and that is the recommended version for GitLab 12+.
## Additional notes
-This documentation is for GitLab Community and Enterprise Edition. We backup
-GitLab.com and make sure your data is secure, but you can't use these methods
-to export / backup your data yourself from GitLab.com.
+This documentation is for GitLab Community and Enterprise Edition. We back up
+GitLab.com and ensure your data is secure. You can't, however, use these
+methods to export or back up your data yourself from GitLab.com.
-Issues are stored in the database. They can't be stored in Git itself.
+Issues are stored in the database, and can't be stored in Git itself.
-To migrate your repositories from one server to another with an up-to-date version of
-GitLab, you can use the [import Rake task](import.md) to do a mass import of the
-repository. Note that if you do an import Rake task, rather than a backup restore, you
-will have all your repositories, but not any other data.
+To migrate your repositories from one server to another with an up-to-date
+version of GitLab, use the [import Rake task](import.md) to do a mass import of
+the repository. If you do an import Rake task rather than a backup restore,
+you get all of your repositories, but no other data.
## Troubleshooting
-The following are possible problems you might encounter with possible solutions.
+The following are possible problems you might encounter, along with potential
+solutions.
### Restoring database backup using Omnibus packages outputs warnings
-If you are using backup restore procedures you might encounter the following warnings:
+If you're using backup restore procedures, you may encounter the following
+warning messages:
```plaintext
psql:/var/opt/gitlab/backups/db/database.sql:22: ERROR: must be owner of extension plpgsql
@@ -1036,22 +1089,31 @@ psql:/var/opt/gitlab/backups/db/database.sql:2931: WARNING: no privileges could
psql:/var/opt/gitlab/backups/db/database.sql:2933: WARNING: no privileges were granted for "public" (two occurrences)
```
-Be advised that, backup is successfully restored in spite of these warnings.
+Be advised that the backup is successfully restored in spite of these warning
+messages.
-The Rake task runs this as the `gitlab` user which does not have the superuser access to the database. When restore is initiated it will also run as `gitlab` user but it will also try to alter the objects it does not have access to.
-Those objects have no influence on the database backup/restore but they give this annoying warning.
+The Rake task runs this as the `gitlab` user, which doesn't have superuser
+access to the database. When restore is initiated, it also runs as the `gitlab`
+user, but it also tries to alter the objects it doesn't have access to.
+Those objects have no influence on the database backup or restore, but display
+a warning message.
-For more information see similar questions on PostgreSQL issue tracker [here](https://www.postgresql.org/message-id/201110220712.30886.adrian.klaver@gmail.com) and [here](https://www.postgresql.org/message-id/2039.1177339749@sss.pgh.pa.us) as well as [stack overflow](https://stackoverflow.com/questions/4368789/error-must-be-owner-of-language-plpgsql).
+For more information, see:
+
+- PostgreSQL issue tracker:
+ - [Not being a superuser](https://www.postgresql.org/message-id/201110220712.30886.adrian.klaver@gmail.com).
+ - [Having different owners](https://www.postgresql.org/message-id/2039.1177339749@sss.pgh.pa.us).
+
+- Stack Overflow: [Resulting errors](https://stackoverflow.com/questions/4368789/error-must-be-owner-of-language-plpgsql).
### When the secrets file is lost
-If you have failed to [back up the secrets file](#storing-configuration-files), you'll
-need to perform a number of steps to get GitLab working properly again.
+If you didn't [back up the secrets file](#storing-configuration-files), you
+must complete several steps to get GitLab working properly again.
-The secrets file is responsible for storing the encryption key for several
-columns containing sensitive information. If the key is lost, GitLab will be
-unable to decrypt those columns. This will break a wide range of functionality,
-including (but not restricted to):
+The secrets file is responsible for storing the encryption key for the columns
+that contain required, sensitive information. If the key is lost, GitLab can't
+decrypt those columns, preventing access to the following items:
- [CI/CD variables](../ci/variables/README.md)
- [Kubernetes / GCP integration](../user/project/clusters/index.md)
@@ -1061,38 +1123,40 @@ including (but not restricted to):
- [Project mirroring](../user/project/repository/repository_mirroring.md)
- [Web hooks](../user/project/integrations/webhooks.md)
-In cases like CI/CD variables and runner authentication, you might
-experience some unexpected behavior such as:
+In cases like CI/CD variables and runner authentication, you can experience
+unexpected behaviors, such as:
- Stuck jobs.
- 500 errors.
-In this case, you are required to reset all the tokens for CI/CD variables
-and runner authentication, which is described in more detail below. After
-resetting the tokens, you should be able to visit your project and the jobs
-will have started running again. Use the information in the following sections at your own risk.
+In this case, you must reset all the tokens for CI/CD variables and
+runner authentication, which is described in more detail in the following
+sections. After resetting the tokens, you should be able to visit your project
+and the jobs will have started running again.
+
+Use the information in the following sections at your own risk.
#### Check for undecryptable values
-You can check whether you have undecryptable values in the database using
-the [Secrets Doctor Rake task](../administration/raketasks/doctor.md).
+You can determine if you have undecryptable values in the database by using the
+[Secrets Doctor Rake task](../administration/raketasks/doctor.md).
#### Take a backup
-You will need to directly modify GitLab data to work around your lost secrets file.
+You must directly modify GitLab data to work around your lost secrets file.
CAUTION: **Warning:**
-Make sure you've taken a backup beforehand, particularly a full database backup.
+Be sure to create a full database backup before attempting any changes.
#### Disable user two-factor authentication (2FA)
-Users with 2FA enabled will not be able to log into GitLab. In that case,
-you need to [disable 2FA for everyone](../security/two_factor_authentication.md#disabling-2fa-for-everyone)
-and then users will have to reactivate 2FA from scratch.
+Users with 2FA enabled can't sign in to GitLab. In that case, you must
+[disable 2FA for everyone](../security/two_factor_authentication.md#disabling-2fa-for-everyone),
+after which users must reactivate 2FA.
#### Reset CI/CD variables
-1. Enter the DB console:
+1. Enter the database console:
For Omnibus GitLab packages:
@@ -1106,14 +1170,14 @@ and then users will have to reactivate 2FA from scratch.
sudo -u git -H bundle exec rails dbconsole -e production
```
-1. Check the `ci_group_variables` and `ci_variables` tables:
+1. Examine the `ci_group_variables` and `ci_variables` tables:
```sql
SELECT * FROM public."ci_group_variables";
SELECT * FROM public."ci_variables";
```
- Those are the variables that you need to delete.
+ These are the variables that you need to delete.
1. Drop the table:
@@ -1122,12 +1186,11 @@ and then users will have to reactivate 2FA from scratch.
DELETE FROM ci_variables;
```
-1. You may need to reconfigure or restart GitLab for the changes to take
- effect.
+You may need to reconfigure or restart GitLab for the changes to take effect.
#### Reset runner registration tokens
-1. Enter the DB console:
+1. Enter the database console:
For Omnibus GitLab packages:
@@ -1141,11 +1204,11 @@ and then users will have to reactivate 2FA from scratch.
sudo -u git -H bundle exec rails dbconsole -e production
```
-1. Clear all the tokens for projects, groups, and the whole instance:
+1. Clear all tokens for projects, groups, and the entire instance:
CAUTION: **Caution:**
- The last UPDATE operation will stop the runners being able to pick up
- new jobs. You must register new runners.
+ The final `UPDATE` operation stops the runners from being able to pick
+ up new jobs. You must register new runners.
```sql
-- Clear project tokens
@@ -1160,7 +1223,7 @@ and then users will have to reactivate 2FA from scratch.
#### Reset pending pipeline jobs
-1. Enter the DB console:
+1. Enter the database console:
For Omnibus GitLab packages:
@@ -1181,19 +1244,18 @@ and then users will have to reactivate 2FA from scratch.
UPDATE ci_builds SET token = null, token_encrypted = null;
```
-A similar strategy can be employed for the remaining features - by removing the
-data that cannot be decrypted, GitLab can be brought back into working order,
-and the lost data can be manually replaced.
+A similar strategy can be employed for the remaining features. By removing the
+data that can't be decrypted, GitLab can be returned to operation, and the
+lost data can be manually replaced.
#### Fix project integrations
-If you've lost your secrets, the
-[projects' integrations settings pages](../user/project/integrations/index.md)
-are probably generating 500 errors.
+If you've lost your secrets, the [projects' integrations settings pages](../user/project/integrations/index.md)
+are probably displaying `500` error messages.
The fix is to truncate the `web_hooks` table:
-1. Enter the DB console:
+1. Enter the database console:
For Omnibus GitLab packages:
@@ -1207,7 +1269,7 @@ The fix is to truncate the `web_hooks` table:
sudo -u git -H bundle exec rails dbconsole -e production
```
-1. Truncate the table
+1. Truncate the table:
```sql
-- truncate web_hooks table
@@ -1216,11 +1278,11 @@ The fix is to truncate the `web_hooks` table:
### Container Registry push failures after restoring from a backup
-If you use the [Container Registry](../user/packages/container_registry/index.md), you
-may see pushes to the registry fail after restoring your backup on an Omnibus
-GitLab instance after restoring the registry data.
+If you use the [Container Registry](../user/packages/container_registry/index.md),
+pushes to the registry may fail after restoring your backup on an Omnibus GitLab
+instance after restoring the registry data.
-These failures will mention permission issues in the registry logs, like:
+These failures mention permission issues in the registry logs, similar to:
```plaintext
level=error
@@ -1230,9 +1292,9 @@ err.detail="filesystem: mkdir /var/opt/gitlab/gitlab-rails/shared/registry/docke
err.message="unknown error"
```
-This is caused by the restore being run as the unprivileged user `git` which was
-unable to assign the correct ownership to the registry files during the restore
-([issue 62759](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/62759 "Incorrect permissions on registry filesystem after restore")).
+This issue is caused by the restore running as the unprivileged user `git`,
+which is unable to assign the correct ownership to the registry files during
+the restore process ([issue 62759](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/62759 "Incorrect permissions on registry filesystem after restore")).
To get your registry working again:
@@ -1240,14 +1302,12 @@ To get your registry working again:
sudo chown -R registry:registry /var/opt/gitlab/gitlab-rails/shared/registry/docker
```
-NOTE: **Note:**
-If you have changed the default filesystem location for the registry, you will
-want to run the `chown` against your custom location instead of
-`/var/opt/gitlab/gitlab-rails/shared/registry/docker`.
+If you changed the default filesystem location for the registry, run `chown`
+against your custom location, instead of `/var/opt/gitlab/gitlab-rails/shared/registry/docker`.
### Backup fails to complete with Gzip error
-While running the backup, you may receive a Gzip error:
+When running the backup, you may receive a Gzip error message:
```shell
sudo /opt/gitlab/bin/gitlab-backup create
@@ -1259,7 +1319,8 @@ gzip: stdout: Input/output error
Backup failed
```
-If this happens, check the following:
+If this happens, examine the following:
-1. Confirm there is sufficient disk space for the Gzip operation.
-1. If NFS is being used, check if the mount option `timeout` is set. The default is `600`, and changing this to smaller values have resulted in this error.
+- Confirm there is sufficient disk space for the Gzip operation.
+- If NFS is being used, check if the mount option `timeout` is set. The
+ default is `600`, and changing this to smaller values results in this error.
diff --git a/doc/raketasks/cleanup.md b/doc/raketasks/cleanup.md
index c4046b36c55..0b3da39d3d5 100644
--- a/doc/raketasks/cleanup.md
+++ b/doc/raketasks/cleanup.md
@@ -146,7 +146,7 @@ NOTE: **Note:**
These commands will not work for artifacts stored on
[object storage](../administration/object_storage.md).
-When you notice there are more job artifacts files on disk than there
+When you notice there are more job artifacts files and/or directories on disk than there
should be, you can run:
```shell
@@ -157,7 +157,7 @@ This command:
- Scans through the entire artifacts folder.
- Checks which files still have a record in the database.
-- If no database record is found, the file is deleted from disk.
+- If no database record is found, the file and directory is deleted from disk.
By default, this task does not delete anything but shows what it can
delete. Run the command with `DRY_RUN=false` if you actually want to
diff --git a/doc/raketasks/import.md b/doc/raketasks/import.md
index c8ca92b4bae..b0603a76211 100644
--- a/doc/raketasks/import.md
+++ b/doc/raketasks/import.md
@@ -127,11 +127,11 @@ Bare repositories are **not** importable by GitLab 10.4 to GitLab 11.6, if all t
- It was not renamed, transferred, or migrated to [hashed storage](../administration/repository_storage_types.md#hashed-storage) in GitLab 10.4 to GitLab 11.6.
- Its ancestor namespaces were not renamed or transferred in GitLab 10.4 to GitLab 11.6.
-[Since GitLab 11.6](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/41776), all
+[In GitLab 11.6](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/41776) and later, all
bare repositories are importable.
To manually migrate repositories yourself (for GitLab 10.4 to GitLab 11.6), you can use the
-[Rails console](../administration/troubleshooting/debug.md#starting-a-rails-console-session)
+[Rails console](../administration/operations/rails_console.md#starting-a-rails-console-session)
to do so. In a Rails console session, run the following to migrate a project:
```ruby
diff --git a/doc/security/asset_proxy.md b/doc/security/asset_proxy.md
index 91a35c2f2a9..fdceecdf386 100644
--- a/doc/security/asset_proxy.md
+++ b/doc/security/asset_proxy.md
@@ -25,7 +25,7 @@ A Camo server is used to act as the proxy.
To install a Camo server as an asset proxy:
1. Deploy a `go-camo` server. Helpful instructions can be found in
- [building catus/go-camo](https://github.com/cactus/go-camo#building).
+ [building cactus/go-camo](https://github.com/cactus/go-camo#building).
1. Make sure your instance of GitLab is running, and that you have created a private API token.
Using the API, configure the asset proxy settings on your GitLab instance. For example:
diff --git a/doc/security/passwords_for_integrated_authentication_methods.md b/doc/security/passwords_for_integrated_authentication_methods.md
index 704af49b2d2..f2597ef1578 100644
--- a/doc/security/passwords_for_integrated_authentication_methods.md
+++ b/doc/security/passwords_for_integrated_authentication_methods.md
@@ -11,4 +11,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 Devise configuation. The default value is 128 characters.
+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.
diff --git a/doc/security/project_import_decompressed_archive_size_limits.md b/doc/security/project_import_decompressed_archive_size_limits.md
index dd67db23d6b..16821e1f192 100644
--- a/doc/security/project_import_decompressed_archive_size_limits.md
+++ b/doc/security/project_import_decompressed_archive_size_limits.md
@@ -17,7 +17,7 @@ If you have a project with decompressed size exceeding this limit,
it is possible to disable the validation by turning off the
`validate_import_decompressed_archive_size` feature flag.
-Start a [Rails console](../administration/troubleshooting/debug.md#starting-a-rails-console-session).
+Start a [Rails console](../administration/operations/rails_console.md#starting-a-rails-console-session).
```ruby
# Disable
diff --git a/doc/security/rack_attack.md b/doc/security/rack_attack.md
index d3de2222c39..b386917f399 100644
--- a/doc/security/rack_attack.md
+++ b/doc/security/rack_attack.md
@@ -4,8 +4,6 @@ type: reference, howto
# Rack Attack initializer
-## Overview
-
[Rack Attack](https://github.com/kickstarter/rack-attack), also known as Rack::Attack, is a Ruby gem
that is meant to protect GitLab with the ability to customize throttling and
to block user IP addresses.
diff --git a/doc/security/rate_limits.md b/doc/security/rate_limits.md
index af2c14be2cd..9e754cf1917 100644
--- a/doc/security/rate_limits.md
+++ b/doc/security/rate_limits.md
@@ -28,6 +28,25 @@ similarly mitigated by a rate limit.
- [Protected paths](../user/admin_area/settings/protected_paths.md).
- [Import/Export rate limits](../user/admin_area/settings/import_export_rate_limits.md).
+## Non-configurable limits
+
+### Repository archives
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/25750) in GitLab 12.9.
+
+There is a rate limit for [downloading repository archives](../api/repositories.md#get-file-archive),
+which applies to the project and to the user initiating the download either through the UI or the API.
+
+The **rate limit** is 5 requests per minute per user.
+
+### Webhook Testing
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/commit/35bc85c3ca093fee58d60dacdc9ed1fd9a15adec) in GitLab 13.4.
+
+There is a rate limit for [testing webhooks](../user/project/integrations/webhooks.md#testing-webhooks), which prevents abuse of the webhook functionality.
+
+The **rate limit** is 5 requests per minute per user.
+
## Rack Attack initializer
This method of rate limiting is cumbersome, but has some advantages. It allows
diff --git a/doc/security/two_factor_authentication.md b/doc/security/two_factor_authentication.md
index 9d49e1d3af2..995dea7809e 100644
--- a/doc/security/two_factor_authentication.md
+++ b/doc/security/two_factor_authentication.md
@@ -65,9 +65,22 @@ The following are important notes about 2FA:
2FA enabled, 2FA is **not** required for those individually added members.
- If there are multiple 2FA requirements (for example, group + all users, or multiple
groups) the shortest grace period will be used.
+- It is possible to disallow subgroups from setting up their own 2FA requirements.
+ Navigate to the top-level group's **Settings > General > Permissions, LFS, 2FA > Two-factor authentication** and uncheck the **Allow subgroups to set up their own two-factor authentication rule** field. This action will cause all subgroups with 2FA requirements to stop requiring that from their members.
## Disabling 2FA for everyone
+CAUTION: **Caution:**
+Disabling 2FA for everyone does not disable the [enforce 2FA for all users](#enforcing-2fa-for-all-users)
+or [enforce 2FA for all users in a group](#enforcing-2fa-for-all-users-in-a-group)
+settings. In addition to the steps in this section, you will need to disable any enforced 2FA
+settings so users aren't asked to set up 2FA again, the next time the user signs in to GitLab.
+Disabling 2FA for everyone does not disable the [enforce 2FA for all users](#enforcing-2fa-for-all-users)
+or [enforce 2FA for all users in a group](#enforcing-2fa-for-all-users-in-a-group)
+settings if they have been configured. In addition to the steps in this section,
+you will need to disable any enforced 2FA settings so users aren't asked to setup
+2FA again when the next login to GitLab.
+
There may be some special situations where you want to disable 2FA for everyone
even when forced 2FA is disabled. There is a Rake task for that:
diff --git a/doc/ssh/README.md b/doc/ssh/README.md
index 1c5654ae96c..9d851edb688 100644
--- a/doc/ssh/README.md
+++ b/doc/ssh/README.md
@@ -1,6 +1,6 @@
---
-stage: Create
-group: Source Code
+stage: Manage
+group: Access
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/#designated-technical-writers"
type: howto, reference
---
@@ -24,7 +24,7 @@ connections to GitLab repositories.
## Requirements
To support SSH, GitLab requires the installation of the OpenSSH client, which
-comes pre-installed on GNU/Linux and macOS, but not on Windows.
+comes pre-installed on GNU/Linux and macOS, as well as on Windows 10.
Make sure that your system includes SSH version 6.5 or newer, as that excludes
the now insecure MD5 signature scheme. The following command returns the version of
diff --git a/doc/subscriptions/gitlab_com/index.md b/doc/subscriptions/gitlab_com/index.md
index bce61cdad66..128e9d07282 100644
--- a/doc/subscriptions/gitlab_com/index.md
+++ b/doc/subscriptions/gitlab_com/index.md
@@ -39,8 +39,7 @@ subscription according to the maximum number of users enabled at once. You can
add and remove users during the subscription period, as long as the total users
at any given time is within your subscription count.
-Every occupied seat, whether by person, job, or bot is counted in the subscription,
-with the following exception:
+Every occupied seat is counted in the subscription, with the following exception:
- Members with Guest permissions on a Gold subscription.
@@ -149,23 +148,13 @@ as the number of _users over license_, you must pay for the excess number of
users either before renewal, or at the time of renewal. This is also known the
_true up_ process.
-There is no self-service option for purchasing additional seats. You must
-request a quotation from GitLab Sales. To do so, contact GitLab via our
-[support form](https://support.gitlab.com/hc/en-us/requests/new?ticket_form_id=360000071293).
-
-The amount charged per seat is calculated by one of the following methods:
-
-- If paid before renewal, the amount per seat is calculated on a prorated basis.
- For example, if the user was added 3 months before the end of the subscription
- period, the amount owing is calculated as: (3 / 12) x annual fee.
-- If paid on renewal, the amount per seat is the standard annual fee.
-
### Renew or change a GitLab.com subscription
-NOTE: **Note:**
-To renew for more users than are currently active in your GitLab.com plan,
-contact our sales team via `renewals@gitlab.com` for assistance as this can't be
-done in the Customers Portal.
+You can adjust the number of users before renewing your GitLab.com subscription.
+
+- To renew for more users than are currently included in your GitLab.com plan, [add users to your subscription](#add-users-to-your-subscription).
+- To renew for fewer users than are currently included in your GitLab.com plan,
+either [disable](../../user/admin_area/activating_deactivating_users.md#deactivating-a-user) or [block](../../user/admin_area/blocking_unblocking_users.md#blocking-a-user) the user accounts you no longer need.
For details on upgrading your subscription tier, see
[Upgrade your GitLab.com subscription tier](#upgrade-your-gitlabcom-subscription-tier).
@@ -187,12 +176,35 @@ generated for the renewal and available for viewing or download in the
during the renewal process, contact our
[support team](https://support.gitlab.com/hc/en-us/requests/new?ticket_form_id=360000071293) for assistance.
+## Add users to your subscription
+
+You can add users to your subscription at any time during the subscription period. The cost of
+additional users added during the subscription period is prorated from the date of purchase through
+the end of the subscription period.
+
+To add users to a subscription:
+
+1. Log in to the [Customers Portal](https://customers.gitlab.com/).
+1. Navigate to the **Manage Purchases** page.
+1. Select **Add more seats** on the relevant subscription card.
+1. Enter the number of additional users.
+1. Select **Proceed to checkout**.
+1. Review the **Subscription Upgrade Detail**. The system lists the total price for all users on the
+ system and a credit for what you've already paid. You will only be charged for the net change.
+1. Select **Confirm Upgrade**.
+
+The following will be emailed to you:
+
+- A payment receipt. You can also access this information in the Customers Portal under
+ [**View invoices**](https://customers.gitlab.com/receipts).
+
## Upgrade your GitLab.com subscription tier
To upgrade your [GitLab tier](https://about.gitlab.com/pricing/):
1. Log in to the [Customers Portal](https://customers.gitlab.com/customers/sign_in).
-1. Select the **Upgrade** button on the relevant subscription card on the [Manage purchases](https://customers.gitlab.com/subscriptions) page.
+1. Select **Upgrade** on the relevant subscription card on the
+ [Manage purchases](https://customers.gitlab.com/subscriptions) page.
1. Select the desired upgrade.
1. Confirm the active form of payment, or add a new form of payment.
1. Check the **I accept the Privacy Policy and Terms of Service** checkbox.
diff --git a/doc/subscriptions/self_managed/index.md b/doc/subscriptions/self_managed/index.md
index a0eb998c545..5f232bd4ed2 100644
--- a/doc/subscriptions/self_managed/index.md
+++ b/doc/subscriptions/self_managed/index.md
@@ -23,15 +23,14 @@ For instances that aren't offline or on a closed network, the maximum number of
simultaneous users in the self-managed installation is checked each quarter,
using [Seat Link](#seat-link).
-Every occupied seat, whether by person, job, or bot is counted in the subscription,
-with the following exceptions:
+Every occupied seat is counted in the subscription, with the following exceptions:
-- [Deactivated](../../user/admin_area/activating_deactivating_users.md#deactivating-a-user) and
+- [Deactivated](../../user/admin_area/activating_deactivating_users.md#deactivating-a-user), [pending approval](../../user/admin_area/approving_users.md) and
[blocked](../../user/admin_area/blocking_unblocking_users.md) users who are restricted prior to the
renewal of a subscription won't be counted as active users for the renewal subscription. They may
count as active users in the subscription period in which they were originally added.
- Members with Guest permissions on an Ultimate subscription.
-- GitLab-created service accounts: `Ghost User`, `Support Bot` and [`Project bot users`](../../user/project/settings/project_access_tokens.md#project-bot-users).
+- GitLab-created service accounts: `Ghost User` and bots (`Support Bot`, [`Project bot users`](../../user/project/settings/project_access_tokens.md#project-bot-users), etc.).
### Users statistics
@@ -254,20 +253,24 @@ production: &base
## Upgrade your subscription tier
-To upgrade your [GitLab tier](https://about.gitlab.com/pricing/), contact our sales team as this
-can't be done in the Customers Portal. You can either send an email to `renewals@gitlab.com`, or
-complete the [**Contact Sales**](https://about.gitlab.com/sales/) form. Include details of which subscription you want to upgrade and the desired tier in your message.
+To upgrade your [GitLab tier](https://about.gitlab.com/pricing/):
-After messaging the sales team, the workflow is as follows:
+1. Log in to the [Customers Portal](https://customers.gitlab.com/customers/sign_in).
+1. Select the **Upgrade** button on the relevant subscription card on the
+ [Manage purchases](https://customers.gitlab.com/subscriptions) page.
+1. Select the desired upgrade.
+1. Confirm the active form of payment, or add a new form of payment.
+1. Select the **I accept the Privacy Policy and Terms of Service** checkbox.
+1. Select **Purchase**.
-1. Receive a reply from the sales team, asking for confirmation of the upgrade.
-1. Reply to the sales team, confirming details of the upgrade.
-1. Receive a quote from the sales team.
-1. Sign and return the quote.
-1. Receive the new license.
-1. Upload the new license. For details, see [Uploading your license](../../user/admin_area/license.md#uploading-your-license).
+The following is emailed to you:
-The new subscription tier is active when the license file is uploaded.
+- A payment receipt. You can also access this information in the Customers Portal under
+ [**View invoices**](https://customers.gitlab.com/receipts).
+- A new license.
+
+[Upload the new license](../../user/admin_area/license.md#uploading-your-license) to your instance.
+The new tier takes effect when the new license is uploaded.
## Subscription expiry
diff --git a/doc/system_hooks/system_hooks.md b/doc/system_hooks/system_hooks.md
index feea038b7d2..d2bdf935aa1 100644
--- a/doc/system_hooks/system_hooks.md
+++ b/doc/system_hooks/system_hooks.md
@@ -6,26 +6,27 @@ type: reference
Your GitLab instance can perform HTTP POST requests on the following events:
+- `group_create`
+- `group_destroy`
+- `group_rename`
+- `key_create`
+- `key_destroy`
- `project_create`
- `project_destroy`
- `project_rename`
- `project_transfer`
- `project_update`
+- `repository_update`
+- `user_add_to_group`
- `user_add_to_team`
-- `user_remove_from_team`
-- `user_update_for_team`
- `user_create`
- `user_destroy`
- `user_failed_login`
-- `user_rename`
-- `key_create`
-- `key_destroy`
-- `group_create`
-- `group_destroy`
-- `group_rename`
-- `user_add_to_group`
- `user_remove_from_group`
+- `user_remove_from_team`
+- `user_rename`
- `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 (name, description, tags, etc.) *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`).
diff --git a/doc/telemetry/index.md b/doc/telemetry/index.md
index 977b93b712e..4583dbe4753 100644
--- a/doc/telemetry/index.md
+++ b/doc/telemetry/index.md
@@ -1,5 +1,5 @@
---
-redirect_to: '../development/telemetry/index.md'
+redirect_to: '../development/product_analytics/index.md'
---
-This document was moved to [another location](../development/telemetry/index.md).
+This document was moved to [another location](../development/product_analytics/index.md).
diff --git a/doc/telemetry/snowplow.md b/doc/telemetry/snowplow.md
index 977b93b712e..643893bcc22 100644
--- a/doc/telemetry/snowplow.md
+++ b/doc/telemetry/snowplow.md
@@ -1,5 +1,5 @@
---
-redirect_to: '../development/telemetry/index.md'
+redirect_to: '../development/product_analytics/snowplow.md'
---
-This document was moved to [another location](../development/telemetry/index.md).
+This document was moved to [another location](../development/product_analytics/snowplow.md).
diff --git a/doc/topics/autodevops/customize.md b/doc/topics/autodevops/customize.md
index 13aa8f7e035..0026cf4d18a 100644
--- a/doc/topics/autodevops/customize.md
+++ b/doc/topics/autodevops/customize.md
@@ -332,7 +332,7 @@ applications.
| `AUTO_DEVOPS_CHART_REPOSITORY_USERNAME` | From GitLab 11.11, 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` | From GitLab 11.11, used to set a password to connect to the Helm repository. Defaults to no credentials. Also set `AUTO_DEVOPS_CHART_REPOSITORY_USERNAME`. |
| `AUTO_DEVOPS_DEPLOY_DEBUG` | From GitLab 13.1, if this variable is present, Helm will output 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. [More details](upgrading_chart.md#ignore-warning-and-continue-deploying) |
+| `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). |
| `AUTO_DEVOPS_MODSECURITY_SEC_RULE_ENGINE` | From GitLab 12.5, used in combination with [ModSecurity feature flag](../../user/clusters/applications.md#web-application-firewall-modsecurity) to toggle [ModSecurity's `SecRuleEngine`](https://github.com/SpiderLabs/ModSecurity/wiki/Reference-Manual-(v2.x)#SecRuleEngine) behavior. Defaults to `DetectionOnly`. |
| `BUILDPACK_URL` | Buildpack's full URL. Can point to either [a Git repository URL or a tarball URL](#custom-buildpacks). |
| `CANARY_ENABLED` | From GitLab 11.0, used to define a [deploy policy for canary environments](#deploy-policy-for-canary-environments). |
@@ -391,6 +391,8 @@ The following table lists variables used to disable jobs.
| `REVIEW_DISABLED` | From GitLab 11.0, used to disable the `review` and the manual `review:stop` job. If the variable is present, these jobs won't be created. |
| `SAST_DISABLED` | From GitLab 11.0, used to disable the `sast` job. If the variable is present, the job won't be created. |
| `TEST_DISABLED` | From GitLab 11.0, used to disable the `test` job. If the variable is present, the job won't be created. |
+| `SECRET_DETECTION_DISABLED` | From GitLab 13.1, used to disable the `secret_detection` job. If the variable is present, the job won't be created. |
+| `CODE_INTELLIGENCE_DISABLED` | From GitLab 13.6, used to disable the `code_intelligence` job. If the variable is present, the job won't be created. |
### Application secret variables
diff --git a/doc/topics/autodevops/index.md b/doc/topics/autodevops/index.md
index a39f93a26e1..1952fadc076 100644
--- a/doc/topics/autodevops/index.md
+++ b/doc/topics/autodevops/index.md
@@ -3,10 +3,11 @@
> - [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/37115) in GitLab 10.0.
> - Generally available on GitLab 11.0.
-Auto DevOps provides pre-defined CI/CD configuration allowing you to automatically
-detect, build, test, deploy, and monitor your applications. Leveraging CI/CD
-best practices and tools, Auto DevOps aims to simplify the setup and execution
-of a mature and modern software development lifecycle.
+Auto DevOps are default CI/CD templates that auto-discover the source code you have. They
+enable GitLab to automatically detect, build, test, deploy, and monitor your applications.
+Leveraging [CI/CD best practices](../../ci/pipelines/pipeline_efficiency.md) and tools,
+Auto DevOps aims to simplify the setup and execution of a mature and modern software
+development lifecycle.
## Overview
@@ -83,9 +84,9 @@ project in a simple and automatic way:
1. [Auto Build](stages.md#auto-build)
1. [Auto Test](stages.md#auto-test)
-1. [Auto Code Quality](stages.md#auto-code-quality) **(STARTER)**
-1. [Auto SAST (Static Application Security Testing)](stages.md#auto-sast) **(ULTIMATE)**
-1. [Auto Secret Detection](stages.md#auto-secret-detection) **(ULTIMATE)**
+1. [Auto Code Quality](stages.md#auto-code-quality)
+1. [Auto SAST (Static Application Security Testing)](stages.md#auto-sast)
+1. [Auto Secret Detection](stages.md#auto-secret-detection)
1. [Auto Dependency Scanning](stages.md#auto-dependency-scanning) **(ULTIMATE)**
1. [Auto License Compliance](stages.md#auto-license-compliance) **(ULTIMATE)**
1. [Auto Container Scanning](stages.md#auto-container-scanning) **(ULTIMATE)**
@@ -94,6 +95,7 @@ project in a simple and automatic way:
1. [Auto Deploy](stages.md#auto-deploy)
1. [Auto Browser Performance Testing](stages.md#auto-browser-performance-testing) **(PREMIUM)**
1. [Auto Monitoring](stages.md#auto-monitoring)
+1. [Auto Code Intelligence](stages.md#auto-code-intelligence)
As Auto DevOps relies on many different components, you should have a basic
knowledge of the following:
@@ -317,7 +319,7 @@ metadata:
name: gitlab-managed-apps-default-proxy
namespace: gitlab-managed-apps
spec:
- env:
+ env:
- name: http_proxy
value: "PUT_YOUR_HTTP_PROXY_HERE"
- name: https_proxy
@@ -417,6 +419,54 @@ DANGER: **Danger:**
Setting `POSTGRES_ENABLED` to `false` permanently deletes any existing
channel 1 database for your environment.
+### Error: unable to recognize "": no matches for kind "Deployment" in version "extensions/v1beta1"
+
+After upgrading your Kubernetes cluster to [v1.16+](stages.md#kubernetes-116),
+you may encounter this message when deploying with Auto DevOps:
+
+```plaintext
+UPGRADE FAILED
+Error: failed decoding reader into objects: unable to recognize "": no matches for kind "Deployment" in version "extensions/v1beta1"
+```
+
+This can occur if your current deployments on the environment namespace were deployed with a
+deprecated/removed API that doesn't exist in Kubernetes v1.16+. For example,
+if [your in-cluster PostgreSQL was installed in a legacy way](#detected-an-existing-postgresql-database),
+the resource was created via the `extensions/v1beta1` API. However, the deployment resource
+was moved to the `app/v1` API in v1.16.
+
+To recover such outdated resources, you must convert the current deployments by mapping legacy APIs
+to newer APIs. There is a helper tool called [`mapkubeapis`](https://github.com/hickeyma/helm-mapkubeapis)
+that works for this problem. Follow these steps to use the tool in Auto DevOps:
+
+1. Modify your `.gitlab-ci.yml` with:
+
+ ```yaml
+ include:
+ - template: Auto-DevOps.gitlab-ci.yml
+ - remote: https://gitlab.com/shinya.maeda/ci-templates/-/raw/master/map-deprecated-api.gitlab-ci.yml
+
+ variables:
+ HELM_VERSION_FOR_MAPKUBEAPIS: "v2" # If you're using auto-depoy-image v2 or above, please specify "v3".
+ ```
+
+1. Run the job `<environment-name>:map-deprecated-api`. Ensure that this job succeeds before moving
+ to the next step. You should see something like the following output:
+
+ ```shell
+ 2020/10/06 07:20:49 Found deprecated or removed Kubernetes API:
+ "apiVersion: extensions/v1beta1
+ kind: Deployment"
+ Supported API equivalent:
+ "apiVersion: apps/v1
+ kind: Deployment"
+ ```
+
+1. Revert your `.gitlab-ci.yml` to the previous version. You no longer need to include the
+ supplemental template `map-deprecated-api`.
+
+1. Continue the deployments as usual.
+
## Development guides
[Development guide for Auto DevOps](../../development/auto_devops.md)
diff --git a/doc/topics/autodevops/stages.md b/doc/topics/autodevops/stages.md
index b58c369714e..d3f02889a2e 100644
--- a/doc/topics/autodevops/stages.md
+++ b/doc/topics/autodevops/stages.md
@@ -124,7 +124,10 @@ The supported buildpacks are:
If your application needs a buildpack that is not in the above list, you
might want to use a [custom buildpack](customize.md#custom-buildpacks).
-## Auto Code Quality **(STARTER)**
+## Auto Code Quality
+
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/1984) in [GitLab Starter](https://about.gitlab.com/pricing/) 9.3.
+> - Made [available in all tiers](https://gitlab.com/gitlab-org/gitlab/-/issues/212499) in GitLab 13.2.
Auto Code Quality uses the
[Code Quality image](https://gitlab.com/gitlab-org/ci-cd/codequality) to run
@@ -133,9 +136,10 @@ report, it's uploaded as an artifact which you can later download and check
out. The merge request widget also displays any
[differences between the source and target branches](../../user/project/merge_requests/code_quality.md).
-## Auto SAST **(ULTIMATE)**
+## Auto SAST
-> Introduced in [GitLab Ultimate](https://about.gitlab.com/pricing/) 10.3.
+> - Introduced in [GitLab Ultimate](https://about.gitlab.com/pricing/) 10.3.
+> - Select functionality made available in all tiers beginning in 13.1
Static Application Security Testing (SAST) uses the
[SAST Docker image](https://gitlab.com/gitlab-org/security-products/sast) to run static
@@ -151,9 +155,10 @@ warnings.
To learn more about [how SAST works](../../user/application_security/sast/index.md),
see the documentation.
-## Auto Secret Detection **(ULTIMATE)**
+## Auto Secret Detection
-> Introduced in [GitLab Ultimate](https://about.gitlab.com/pricing/) 13.1.
+> - Introduced in [GitLab Ultimate](https://about.gitlab.com/pricing/) 13.1.
+> - [Select functionality made available in all tiers](../../user/application_security/secret_detection/#making-secret-detection-available-to-all-gitlab-tiers) in 13.3
Secret Detection uses the
[Secret Detection Docker image](https://gitlab.com/gitlab-org/security-products/analyzers/secrets) to run Secret Detection on the current code, and checks for leaked secrets. The
@@ -190,7 +195,7 @@ see the documentation.
> Introduced in [GitLab Ultimate](https://about.gitlab.com/pricing/) 11.0.
License Compliance uses the
-[License Compliance Docker image](https://gitlab.com/gitlab-org/security-products/license-management)
+[License Compliance Docker image](https://gitlab.com/gitlab-org/security-products/analyzers/license-finder)
to search the project dependencies for their license. The Auto License Compliance stage
is skipped on licenses other than [Ultimate](https://about.gitlab.com/pricing/).
@@ -242,7 +247,7 @@ Helm, which you can [customize](customize.md#custom-helm-chart). The application
into the [Kubernetes namespace](../../user/project/clusters/index.md#deployment-variables)
for the environment.
-Since GitLab 11.4, [local Tiller](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/22036) is
+In GitLab 11.4 and later, [local Tiller](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/22036) is
used. Previous versions of GitLab had a Tiller installed in the project
namespace.
@@ -360,7 +365,7 @@ chart to deploy the application into the
[Kubernetes namespace](../../user/project/clusters/index.md#deployment-variables)
for the environment.
-Since GitLab 11.4, a
+In GitLab 11.4 and later, a
[local Tiller](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/22036) is
used. Previous versions of GitLab had a Tiller installed in the project
namespace.
@@ -466,7 +471,7 @@ application runs.
### Upgrade auto-deploy-app Chart
-You can upgrade auto-deploy-app chart by following the [upgrade guide](upgrading_chart.md).
+You can upgrade the auto-deploy-app chart by following the [upgrade guide](upgrading_auto_deploy_dependencies.md).
### Workers
@@ -660,3 +665,7 @@ To use Auto Monitoring:
whole Kubernetes cluster, navigate to **Operations > Metrics**.
![Auto Metrics](img/auto_monitoring.png)
+
+## Auto Code Intelligence
+
+Code Intelligence is powered by [LSIF](https://lsif.dev/) and available for Go at this stage. We'll support more languages as they become available.
diff --git a/doc/topics/autodevops/upgrading_auto_deploy_dependencies.md b/doc/topics/autodevops/upgrading_auto_deploy_dependencies.md
new file mode 100644
index 00000000000..1aefb6b34df
--- /dev/null
+++ b/doc/topics/autodevops/upgrading_auto_deploy_dependencies.md
@@ -0,0 +1,262 @@
+---
+stage: Release
+group: Progressive Delivery
+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/#designated-technical-writers
+type: reference
+---
+
+# Upgrading deployments for newer Auto Deploy dependencies (Auto Deploy template, auto-deploy-image and auto-deploy-app chart)
+
+[Auto Deploy](stages.md#auto-deploy) is a feature that deploys your application to a Kubernetes cluster.
+It consists of several dependencies:
+
+- [Auto Deploy template](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Jobs/Deploy.gitlab-ci.yml) is a set of pipeline jobs and scripts that makes use of `auto-deploy-image`.
+- [`auto-deploy-image`](https://gitlab.com/gitlab-org/cluster-integration/auto-deploy-image) is the executable image that communicates with the Kubernetes cluster.
+- [`auto-deploy-app chart`](https://gitlab.com/gitlab-org/cluster-integration/auto-deploy-image/-/tree/master/assets/auto-deploy-app) is the Helm chart for deploying your application.
+
+The `auto-deploy-image` and `auto-deploy-app` charts use [Semantic Versioning](https://semver.org/).
+By default, your Auto DevOps project keeps using the stable and non-breaking version.
+However, these dependencies could be upgraded in a major version release of GitLab
+with breaking changes requiring you to upgrade your deployments.
+
+This guide explains how to upgrade your deployments with newer or different major versions of Auto Deploy dependencies.
+
+## Verify dependency versions
+
+The process to check the current versions differs depending on which template you
+are using. First verify which template is in use:
+
+- For self-managed instances, the [stable Auto Deploy template bundled with the GitLab package](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Jobs/Deploy.gitlab-ci.yml)
+ is being used.
+- [The GitLab.com stable Auto Deploy template](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Jobs/Deploy.gitlab-ci.yml)
+ is being used if **one** of the following is true:
+ - Your Auto DevOps project doesn't have a `.gitlab-ci.yml` file.
+ - Your Auto DevOps project has a `.gitlab-ci.yml` and [includes](../../ci/yaml/README.md#includetemplate)
+ the `Auto-DevOps.gitlab-ci.yml` template.
+- [The latest Auto Deploy template](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Jobs/Deploy.latest.gitlab-ci.yml)
+ is being used if **both** of the following is true:
+ - Your Auto DevOps project has a `.gitlab-ci.yml` file and [includes](../../ci/yaml/README.md#includetemplate)
+ the `Auto-DevOps.gitlab-ci.yml` template.
+ - It also includes [the latest Auto Deploy template](#early-adopters)
+
+If you know what template is being used:
+
+- The `auto-deploy-image` version is in the template (for example `auto-deploy-image:v1.0.3`).
+- The `auto-deploy-app` chart version is [in the auto-deploy-image repository](https://gitlab.com/gitlab-org/cluster-integration/auto-deploy-image/-/blob/v1.0.3/assets/auto-deploy-app/Chart.yaml)
+ (for example `version: 1.0.3`).
+
+## Compatibility
+
+The following table explains the version compatibility between GitLab and Auto Deploy dependencies:
+
+| GitLab version | `auto-deploy-image` version | Notes |
+|------------------|-----------------------------|-------|
+| v10.0 to v14.0 | v0.1.0 to v2.0.0 | v0 and v1 auto-deploy-image are backwards compatible. |
+| v13.4 and higher | v2.0.0 and higher | v2 auto-deploy-image contains breaking changes, as explained in the [upgrade guide](#upgrade-deployments-to-the-v2-auto-deploy-image). |
+
+You can find the current stable version of auto-deploy-image in the [Auto Deploy stable template](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Jobs/Deploy.gitlab-ci.yml).
+
+## Upgrade Guide
+
+Projects using Auto DevOps must use the unmodified chart managed by GitLab.
+[Customized charts](customize.md#custom-helm-chart) are unsupported.
+
+### Upgrade deployments to the v1 `auto-deploy-image`
+
+The v1 chart is backward compatible with the v0 chart, so no configuration changes are needed.
+
+### Upgrade deployments to the v2 `auto-deploy-image`
+
+The v2 auto-deploy-image contains multiple dependency and architectural changes.
+If your Auto DevOps project has an active environment deployed with the v1 `auto-deploy-image`,
+please proceed with the following upgrade guide. Otherwise, you can skip this process.
+
+#### Helm 3
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/228609) in GitLab 13.4.
+
+The `auto-deploy-image` uses the Helm binary to manipulate the releases.
+Previously, `auto-deploy-image` used Helm v2, which used Tiller in a cluster.
+In the v2 `auto-deploy-image`, it uses Helm v3 that doesn't require Tiller anymore.
+
+If your Auto DevOps project has an active environment that was deployed with the v1
+`auto-deploy-image`, use the following steps to upgrade to v2, which uses Helm 3:
+
+1. Modify your `.gitlab-ci.yml` with:
+
+ ```yaml
+ include:
+ - template: Auto-DevOps.gitlab-ci.yml
+ - remote: https://gitlab.com/hfyngvason/ci-templates/-/raw/master/Helm-2to3.gitlab-ci.yml
+
+ variables:
+ # If this variable is not present, the migration jobs will not show up
+ MIGRATE_HELM_2TO3: "true"
+
+ .auto-deploy:
+ image: registry.gitlab.com/gitlab-org/cluster-integration/auto-deploy-image:v2.0.0-beta.1
+ variables:
+ AUTO_DEVOPS_FORCE_DEPLOY_V2: 1
+ ```
+
+1. Run the `<environment-name>:helm-2to3:migrate` job.
+1. Deploy your environment as usual. This deployment uses Helm 3.
+1. If the deployment succeeds, you can safely run `environment:helm-2to3:cleanup`.
+ This deletes all Helm 2 release data from the namespace.
+
+ If you accidentally delete the Helm 2 releases before you are ready, the `<environment-name>:helm2to3:migrate`
+ job saves a backup for 1 week in a job artifact called `helm-2-release-backups`.
+ The backup is in a Kubernetes manifest file that can be restored using
+ `kubectl apply -f $backup`.
+1. Remove the `MIGRATE_HELM_2TO3` variable.
+
+#### Traffic routing change for canary deployments and incremental rollouts
+
+> [Introduced](https://gitlab.com/gitlab-org/cluster-integration/auto-deploy-image/-/merge_requests/109) in GitLab 13.4.
+
+Auto Deploy supports advanced deployment strategies such as [canary deployments](customize.md#deploy-policy-for-canary-environments)
+and [incremental rollouts](../../ci/environments/incremental_rollouts.md).
+
+Previously, `auto-deploy-image` created one service to balance the traffic between
+unstable and stable tracks by changing the replica ratio. In the v2 `auto-deploy-image`,
+it controls the traffic with [Canary Ingress](https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/#canary).
+
+For more details, see the [v2 `auto-deploy-app` chart resource architecture](#v2-chart-resource-architecture).
+
+If your Auto DevOps project has active `canary` or `rollout` track releases in the
+`production` environment deployed with the v1 `auto-deploy-image`, use the following
+steps to upgrade to v2:
+
+1. Verify your project is [using the v1 `auto-deploy-image`](#verify-dependency-versions).
+ If not, [specify the version](#use-a-specific-version-of-auto-deploy-dependencies).
+1. If you're in the process of deploying `canary` or `rollout` deployments, promote
+ them to `production` first to delete the unstable tracks.
+1. Verify your project is [using the v2 `auto-deploy-image`](#verify-dependency-versions).
+ If not, [specify the version](#use-a-specific-version-of-auto-deploy-dependencies).
+1. Add an `AUTO_DEVOPS_FORCE_DEPLOY_V2` environment variable with a value of `true`
+ in the GitLab CI/CD settings.
+1. Create a new pipeline and run the `production` job to renew the resource architecture
+ with the v2 `auto-deploy-app chart`.
+1. Remove the `AUTO_DEVOPS_FORCE_DEPLOY_V2` environment variable.
+
+### Use a specific version of Auto Deploy dependencies
+
+To use a specifc version of Auto Deploy dependencies, specify the previous Auto Deploy
+stable template that contains the [desired version of `auto-deploy-image` and `auto-deploy-app`](#verify-dependency-versions).
+
+For example, if the template is bundled in GitLab v13.3, change your `.gitlab-ci.yml` to:
+
+```yaml
+include:
+ - template: Auto-DevOps.gitlab-ci.yml
+ - remote: https://gitlab.com/gitlab-org/gitlab/-/blob/v13.3.0-ee/lib/gitlab/ci/templates/Jobs/Deploy.gitlab-ci.yml
+```
+
+### Ignore warnings and continue deploying
+
+If you are certain that the new chart version is safe to be deployed, you can add
+the `AUTO_DEVOPS_FORCE_DEPLOY_V<major-version-number>` [environment variable](customize.md#build-and-deployment)
+to force the deployment to continue.
+
+For example, if you want to deploy the `v2.0.0` chart on a deployment that previously
+used the `v0.17.0` chart, add `AUTO_DEVOPS_FORCE_DEPLOY_V2`.
+
+## Early adopters
+
+If you want to use the latest beta or unstable version of `auto-deploy-image`, include
+the latest Auto Deploy template into your `.gitlab-ci.yml`:
+
+```yaml
+include:
+ - template: Auto-DevOps.gitlab-ci.yml
+ - remote: https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Jobs/Deploy.latest.gitlab-ci.yml
+```
+
+CAUTION: **Warning:**
+Using a beta or unstable `auto-deploy-image` could cause unrecoverable damage to
+your environments. Do not test it with important projects or environments.
+
+The next stable template update is [planned for GitLab v14.0](https://gitlab.com/gitlab-org/gitlab/-/issues/232788).
+
+## Resource Architectures of the `auto-deploy-app` chart
+
+### v0 and v1 chart resource architecture
+
+```mermaid
+graph TD;
+subgraph gl-managed-app
+Z[Nginx Ingress]
+end
+Z[Nginx Ingress] --> A(Ingress);
+Z[Nginx Ingress] --> B(Ingress);
+subgraph stg namespace
+B[Ingress] --> H(...);
+end
+subgraph prd namespace
+A[Ingress] --> D(Service);
+D[Service] --> E(Deployment:Pods:app:stable);
+D[Service] --> F(Deployment:Pods:app:canary);
+D[Service] --> I(Deployment:Pods:app:rollout);
+E(Deployment:Pods:app:stable)---id1[(Pods:Postgres)]
+F(Deployment:Pods:app:canary)---id1[(Pods:Postgres)]
+I(Deployment:Pods:app:rollout)---id1[(Pods:Postgres)]
+end
+```
+
+### v2 chart resource architecture
+
+```mermaid
+graph TD;
+subgraph gl-managed-app
+Z[Nginx Ingress]
+end
+Z[Nginx Ingress] --> A(Ingress);
+Z[Nginx Ingress] --> B(Ingress);
+Z[Nginx Ingress] --> |If canary is present or incremental rollout/|J(Canary Ingress);
+subgraph stg namespace
+B[Ingress] --> H(...);
+end
+subgraph prd namespace
+subgraph stable track
+A[Ingress] --> D[Service];
+D[Service] --> E(Deployment:Pods:app:stable);
+end
+subgraph canary track
+J(Canary Ingress) --> K[Service]
+K[Service] --> F(Deployment:Pods:app:canary);
+end
+E(Deployment:Pods:app:stable)---id1[(Pods:Postgres)]
+F(Deployment:Pods:app:canary)---id1[(Pods:Postgres)]
+end
+```
+
+## Troubleshooting
+
+### Major version mismatch warning
+
+If deploying a chart that has a major version that is different from the previous one,
+the new chart might not be correctly deployed. This could be due to an architectural
+change. If that happens, the deployment job fails with a message similar to:
+
+```plaintext
+*************************************************************************************
+ [WARNING]
+Detected a major version difference between the the chart that is currently deploying (auto-deploy-app-v0.7.0), and the previously deployed chart (auto-deploy-app-v1.0.0).
+A new major version might not be backward compatible with the current release (production). The deployment could fail or be stuck in an unrecoverable status.
+...
+```
+
+To clear this error message and resume deployments, you must do one of the following:
+
+- Manually [upgrade the chart version](#upgrade-guide).
+- [Use a specific chart version](#use-a-specific-version-of-auto-deploy-dependencies).
+
+### Error: `missing key "app.kubernetes.io/managed-by": must be set to "Helm"`
+
+If your cluster has a deployment that was deployed with the v1 `auto-deploy-image`,
+you might encounter the following error:
+
+- `Error: rendered manifests contain a resource that already exists. Unable to continue with install: Secret "production-postgresql" in namespace "<project-name>-production" exists and cannot be imported into the current release: invalid ownership metadata; label validation error: missing key "app.kubernetes.io/managed-by": must be set to "Helm"; annotation validation error: missing key "meta.helm.sh/release-name": must be set to "production-postgresql"; annotation validation error: missing key "meta.helm.sh/release-namespace": must be set to "<project-name>-production"`
+
+This is because the previous deployment was deployed with Helm2, which is not compatible with Helm3.
+To resolve the problem, please follow the [upgrade guide](#upgrade-deployments-to-the-v2-auto-deploy-image).
diff --git a/doc/topics/autodevops/upgrading_chart.md b/doc/topics/autodevops/upgrading_chart.md
index ffa485f6d2c..e4fb84d4509 100644
--- a/doc/topics/autodevops/upgrading_chart.md
+++ b/doc/topics/autodevops/upgrading_chart.md
@@ -1,72 +1,5 @@
-# Upgrading auto-deploy-app chart for Auto DevOps
+---
+redirect_to: 'upgrading_auto_deploy_dependencies.md'
+---
-Auto DevOps provides the auto-deploy-app chart for deploying your application to the
-Kubernetes cluster with Helm/Tiller. Major version changes of this chart could have
-a significantly different resource architecture, and may not be backwards compatible.
-
-This guide provides instructions on how to upgrade your deployments to use the latest
-chart and resource architecture.
-
-## Compatibility
-
-The following table lists the version compatibility between GitLab and [auto-deploy-image](https://gitlab.com/gitlab-org/cluster-integration/auto-deploy-image) (with the [auto-deploy-app chart](https://gitlab.com/gitlab-org/cluster-integration/auto-deploy-image/-/tree/master/assets/auto-deploy-app)).
-
-| GitLab version | auto-deploy-image version | Notes |
-|------------------|---------------------------|--------------------------------------------|
-| v10.0 and higher | v0.1.0 and higher | v0 and v1 charts are backwards compatible. |
-
-## Upgrade Guide
-
-The Auto DevOps project must use the unmodified chart managed by GitLab.
-[Customized charts](customize.md#custom-helm-chart) are unsupported.
-
-### v1 chart
-
-The v1 chart is backward compatible with the v0 chart, so no configuration changes are needed.
-
-## Troubleshooting
-
-### Major version mismatch warning
-
-If deploying a chart that has a major version that is different from the previous one,
-the new chart might not be correctly deployed. This could be due to an architectural
-change. If that happens, the deployment job fails with a message similar to:
-
-```plaintext
-*************************************************************************************
- [WARNING]
-Detected a major version difference between the the chart that is currently deploying (auto-deploy-app-v0.7.0), and the previously deployed chart (auto-deploy-app-v1.0.0).
-A new major version might not be backward compatible with the current release (production). The deployment could fail or be stuck in an unrecoverable status.
-...
-```
-
-To clear this error message and resume deployments, you must do one of the following:
-
-- Manually [upgrade the chart version](#upgrade-guide).
-- [Use a specific chart version](#use-a-specific-chart-version).
-
-#### Use a specific chart version
-
-To use a specific chart version, you must specify a corresponding version of [auto-deploy-image](https://gitlab.com/gitlab-org/cluster-integration/auto-deploy-image).
-Do this by [customizing the image in your `.gitlab-ci.yml`](customize.md#customizing-gitlab-ciyml).
-
-For example, create the following `.gitlab-ci.yml` file in the project. It configures Auto DevOps
-to use [auto-deploy-image](https://gitlab.com/gitlab-org/cluster-integration/auto-deploy-image) version `v0.17.0`
-for deployment jobs. It will download the chart from [chart repository](https://charts.gitlab.io/):
-
-```yaml
-include:
- - template: Auto-DevOps.gitlab-ci.yml
-
-.auto-deploy:
- image: "registry.gitlab.com/gitlab-org/cluster-integration/auto-deploy-image:v0.17.0"
-```
-
-#### Ignore warning and continue deploying
-
-If you are certain that the new chart version is safe to be deployed,
-you can add the `AUTO_DEVOPS_FORCE_DEPLOY_V<N>` [environment variable](customize.md#build-and-deployment)
-to force the deployment to continue, where `<N>` is the major version.
-
-For example, if you want to deploy the v2.0.0 chart on a deployment that previously
-used the v0.17.0 chart, add `AUTO_DEVOPS_FORCE_DEPLOY_V2`.
+This document was moved to [another location](upgrading_auto_deploy_dependencies.md).
diff --git a/doc/topics/autodevops/upgrading_postgresql.md b/doc/topics/autodevops/upgrading_postgresql.md
index 2ebe362280f..bcbc1d914be 100644
--- a/doc/topics/autodevops/upgrading_postgresql.md
+++ b/doc/topics/autodevops/upgrading_postgresql.md
@@ -178,8 +178,11 @@ You can also
PostgreSQL.
1. Set `AUTO_DEVOPS_POSTGRES_DELETE_V1` to a non-empty value. This flag is a
safeguard to prevent accidental deletion of databases.
-1. Set `POSTGRES_VERSION` to `11.7`. This is the minimum PostgreSQL
- version supported.
+ <!-- DO NOT REPLACE when upgrading GitLab's supported version. This is NOT related to GitLab's PostgreSQL version support, but the one deployed by Auto DevOps. -->
+1. If you have a `POSTGRES_VERSION` set, make sure it is set to `9.6.16` *or
+higher*. This is the
+ minimum PostgreSQL version supported by Auto DevOps. See also the list of
+ [tags available](https://hub.docker.com/r/bitnami/postgresql/tags).
1. Set `PRODUCTION_REPLICAS` to `0`. For other environments, use
`REPLICAS` with an [environment scope](../../ci/environments/index.md#scoping-environments-with-specs).
1. If you have set the `DB_INITIALIZE` or `DB_MIGRATE` variables, either
diff --git a/doc/topics/cron/index.md b/doc/topics/cron/index.md
index a3dd3b77c22..851dd6d3f77 100644
--- a/doc/topics/cron/index.md
+++ b/doc/topics/cron/index.md
@@ -24,7 +24,7 @@ Cron scheduling uses a series of five numbers, separated by spaces:
# * * * * * <command to execute>
```
-[Source: [Wikipedia](https://en.wikipedia.org/wiki/Cron)]
+(Source: [Wikipedia](https://en.wikipedia.org/wiki/Cron))
In cron syntax, the asterisk (`*`) means 'every,' so the following cron strings
are valid:
diff --git a/doc/topics/git/git_rebase.md b/doc/topics/git/git_rebase.md
new file mode 100644
index 00000000000..6f50dea26dd
--- /dev/null
+++ b/doc/topics/git/git_rebase.md
@@ -0,0 +1,272 @@
+---
+stage: Create
+group: Source Code
+info: "To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers"
+type: concepts, howto
+description: "Introduction to Git rebase, force-push, and resolving merge conflicts through the command line."
+---
+
+# Introduction to Git rebase, force-push, and merge conflicts
+
+This guide helps you to get started with rebasing, force-pushing, and fixing
+merge conflicts locally.
+
+Before diving into this document, make sure you are familiar with using
+[Git through the command line](../../gitlab-basics/start-using-git.md).
+
+## Git rebase
+
+[Rebasing](https://git-scm.com/docs/git-rebase) is a very common operation in
+Git. There are the following rebase options:
+
+- [Regular rebase](#regular-rebase).
+- [Interactive rebase](#interactive-rebase).
+
+### Before rebasing
+
+CAUTION: **Warning:**
+`git rebase` rewrites the commit history. It **can be harmful** to do it in
+shared branches. It can cause complex and hard to resolve merge conflicts. In
+these cases, instead of rebasing your branch against the default branch,
+consider pulling it instead (`git pull origin master`). It has a similar
+effect without compromising the work of your contributors.
+
+It's safer to back up your branch before rebasing to make sure you don't lose
+any changes. For example, consider a [feature branch](../../gitlab-basics/start-using-git.md#branching)
+called `my-feature-branch`:
+
+1. Open your feature branch in the terminal:
+
+ ```shell
+ git checkout my-feature-branch
+ ```
+
+1. Checkout a new branch from it:
+
+ ```shell
+ git checkout -b my-feature-branch-backup
+ ```
+
+1. Go back to your original branch:
+
+ ```shell
+ git checkout my-feature-branch
+ ```
+
+Now you can safely rebase it. If anything goes wrong, you can recover your
+changes by resetting `my-feature-branch` against `my-feature-branch-backup`:
+
+1. Make sure you're in the correct branch (`my-feature-branch`):
+
+ ```shell
+ git checkout my-feature-branch
+ ```
+
+1. Reset it against `my-feature-branch-backup`:
+
+ ```shell
+ git reset --hard my-feature-branch-backup
+ ```
+
+Note that if you added changes to `my-feature-branch` after creating the backup branch,
+you will lose them when resetting.
+
+### Regular rebase
+
+With a regular rebase you can update your feature branch with the default
+branch (or any other branch).
+This is an important step for Git-based development strategies. You can
+ensure that the changes you're adding to the codebase do not break any
+existing changes added to the target branch _after_ you created your feature
+branch.
+
+For example, to update your branch `my-feature-branch` with `master`:
+
+1. Fetch the latest changes from `master`:
+
+ ```shell
+ git fetch origin master
+ ```
+
+1. Checkout your feature branch:
+
+ ```shell
+ git checkout my-feature-branch
+ ```
+
+1. Rebase it against `master`:
+
+ ```shell
+ git rebase origin/master
+ ```
+
+1. [Force-push](#force-push) to your branch.
+
+When you rebase:
+
+1. Git imports all the commits submitted to `master` _after_ the
+ moment you created your feature branch until the present moment.
+1. Git puts the commits you have in your feature branch on top of all
+ the commits imported from `master`:
+
+![Git rebase illustration](img/git_rebase_v13_5.png)
+
+You can replace `master` with any other branch you want to rebase against, for
+example, `release-10-3`. You can also replace `origin` with other remote
+repositories, for example, `upstream`. To check what remotes you have linked to your local
+repository, you can run `git remote -v`.
+
+If there are [merge conflicts](#merge-conflicts), Git will prompt you to fix
+them before continuing the rebase.
+
+To learn more, check Git's documentation on [rebasing](ttps://git-scm.com/book/en/v2/Git-Branching-Rebasing)
+and [rebasing strategies](https://git-scm.com/book/en/v2/Git-Branching-Rebasing).
+
+### Interactive rebase
+
+You can use interactive rebase to modify commits. For example, amend a commit
+message, squash (join multiple commits into one), edit, or delete
+commits. It is handy for changing past commit messages,
+as well as for organizing the commit history of your branch to keep it clean.
+
+TIP: **Tip:**
+If you want to keep the default branch commit history clean, you don't need to
+manually squash all your commits before merging every merge request;
+with [Squash and Merge](../../user/project/merge_requests/squash_and_merge.md)
+GitLab does it automatically.
+
+When you want to change anything in recent commits, use interactive
+rebase by passing the flag `--interactive` (or `-i`) to the rebase command.
+
+For example, if you want to edit the last three commits in your branch
+(`HEAD~3`), run:
+
+```shell
+git rebase -i HEAD~3
+```
+
+Git opens the last three commits in your terminal text editor and describes
+all the interactive rebase options you can use. The default option is `pick`,
+which maintains the commit unchanged. Replace the keyword `pick` according to
+the operation you want to perform in each commit. To do so, you need to edit
+the commits in your terminal's text editor.
+
+For example, if you're using [Vim](https://www.vim.org/) as the text editor in
+a macOS's `ZSH` shell, and you want to **squash** all the three commits
+(join them into one):
+
+1. Press <kbd>i</kbd> on your keyboard to switch to Vim's editing mode.
+1. Navigate with your keyboard arrows to edit the **second** commit keyword
+ from `pick` to `squash` (or `s`). Do the same to the **third** commit.
+ The first commit should be left **unchanged** (`pick`) as we want to squash
+ the second and third into the first.
+1. Press <kbd>Esc</kbd> to leave the editing mode.
+1. Type `:wq` to "write" (save) and "quit".
+1. Git outputs the commit message so you have a chance to edit it:
+ - All lines starting with `#` will be ignored and not included in the commit
+ message. Everything else will be included.
+ - To leave it as it is, type `:wq`. To edit the commit message: switch to the
+ editing mode, edit the commit message, and save it as you just did.
+1. If you haven't pushed your commits to the remote branch before rebasing,
+ push your changes normally. If you had pushed these commits already,
+ [force-push](#force-push) instead.
+
+Note that the steps for editing through the command line can be slightly
+different depending on your operating system and the shell you're using.
+
+See [Numerous undo possibilities in Git](numerous_undo_possibilities_in_git/index.md#with-history-modification)
+for a deeper look into interactive rebase.
+
+## Force-push
+
+When you perform more complex operations, for example, squash commits, reset or
+rebase your branch, you'll have to _force_ an update to the remote branch,
+since these operations imply rewriting the commit history of the branch.
+To force an update, pass the flag `--force` or `-f` to the `push` command. For
+example:
+
+```shell
+git push --force origin my-feature-branch
+```
+
+Forcing an update is **not** recommended when you're working on shared
+branches.
+
+Alternatively, you can pass the flag [`--force-with-lease`](https://git-scm.com/docs/git-push#Documentation/git-push.txt---force-with-leaseltrefnamegt)
+instead. It is safer, as it does not overwrite any work on the remote
+branch if more commits were added to the remote branch by someone else:
+
+```shell
+git push --force-with-lease origin my-feature-branch
+```
+
+If the branch you want to force-push is [protected](../../user/project/protected_branches.md),
+you can't force-push to it unless you unprotect it first. Then you can
+force-push and re-protect it.
+
+## Merge conflicts
+
+As Git is based on comparing versions of a file
+line-by-line, whenever a line changed in your branch coincides with the same
+line changed in the target branch (after the moment you created your feature branch from it), Git
+identifies these changes as a merge conflict. To fix it, you need to choose
+which version of that line you want to keep.
+
+Most conflicts can be [resolved through the GitLab UI](../../user/project/merge_requests/resolve_conflicts.md).
+
+For more complex cases, there are various methods for resolving them. There are
+also [Git GUI apps](https://git-scm.com/downloads/guis) that can help by
+visualizing the differences.
+
+To fix conflicts locally, you can use the following method:
+
+1. Open the terminal and checkout your feature branch, for example, `my-feature-branch`:
+
+ ```shell
+ git checkout my-feature-branch
+ ```
+
+1. [Rebase](#regular-rebase) your branch against the target branch so Git
+ prompts you with the conflicts:
+
+ ```shell
+ git rebase origin/master
+ ```
+
+1. Open the conflicting file in a code editor of your preference.
+1. Look for the conflict block:
+ - It begins with the marker: `<<<<<<< HEAD`.
+ - Below, there is the content with your changes.
+ - The marker: `=======` indicates the end of your changes.
+ - Below, there's the content of the latest changes in the target branch.
+ - The marker `>>>>>>>` indicates the end of the conflict.
+1. Edit the file: choose which version (before or after `=======`) you want to
+ keep, and then delete the portion of the content you don't want in the file.
+1. Delete the markers.
+1. Save the file.
+1. Repeat the process if there are other conflicting files.
+1. Stage your changes:
+
+ ```shell
+ git add .
+ ```
+
+1. Commit your changes:
+
+ ```shell
+ git commit -m "Fix merge conflicts"
+ ```
+
+1. Continue rebasing:
+
+ ```shell
+ git rebase --continue
+ ```
+
+ CAUTION: **Caution:**
+ Up to this point, you can run `git rebase --abort` to stop the process.
+ Git aborts the rebase and rolls back the branch to the state you had before
+ running `git rebase`.
+ Once you run `git rebase --continue` the rebase **cannot** be aborted.
+
+1. [Force-push](#force-push) to your remote branch.
diff --git a/doc/topics/git/img/git_rebase_v13_5.png b/doc/topics/git/img/git_rebase_v13_5.png
new file mode 100644
index 00000000000..ff29fa97798
--- /dev/null
+++ b/doc/topics/git/img/git_rebase_v13_5.png
Binary files differ
diff --git a/doc/topics/git/index.md b/doc/topics/git/index.md
index 92181fb7bb0..cb2d7b74522 100644
--- a/doc/topics/git/index.md
+++ b/doc/topics/git/index.md
@@ -81,6 +81,7 @@ If you have problems with Git, the following may help:
The following are advanced topics for those who want to get the most out of Git:
+- [Introduction to Git rebase, force-push, and merge conflicts](git_rebase.md)
- [Server Hooks](../../administration/server_hooks.md)
- [Git Attributes](../../user/project/git_attributes.md)
- Git Submodules: [Using Git submodules with GitLab CI](../../ci/git_submodules.md#using-git-submodules-with-gitlab-ci)
diff --git a/doc/university/README.md b/doc/university/README.md
index d029c91a19f..6f063e028b5 100644
--- a/doc/university/README.md
+++ b/doc/university/README.md
@@ -65,7 +65,6 @@ The GitLab University curriculum is composed of GitLab videos, screencasts, pres
1. [Making GitLab Great for Everyone - Video](https://www.youtube.com/watch?v=GGC40y4vMx0) - Response to "Dear GitHub" letter
1. [Using Innersourcing to Improve Collaboration](https://about.gitlab.com/blog/2014/09/05/innersourcing-using-the-open-source-workflow-to-improve-collaboration-within-an-organization/)
1. [The Software Development Market and GitLab - Video](https://www.youtube.com/watch?v=sXlhgPK1NTY&list=PLFGfElNsQthbQu_IWlNOxul0TbS_2JH-e&index=6) - [Slides](https://docs.google.com/presentation/d/1vCU-NbZWz8NTNK8Vu3y4zGMAHb5DpC8PE5mHtw1PWfI/edit)
-1. [The GitLab Book Club](bookclub/index.md)
1. [GitLab Resources](https://about.gitlab.com/resources/)
### 1.7 Community and Support
@@ -76,7 +75,6 @@ The GitLab University curriculum is composed of GitLab videos, screencasts, pres
- Getting Technical Support
- Being part of our Great Community and Contributing to GitLab
1. [Getting Started with the GitLab Development Kit (GDK)](https://about.gitlab.com/blog/2016/06/08/getting-started-with-gitlab-development-kit/)
-1. [GitLab Training Workshops](training/end-user/README.md)
1. [GitLab Professional Services](https://about.gitlab.com/services/)
### 1.8 GitLab Training Material
@@ -177,10 +175,10 @@ The GitLab University curriculum is composed of GitLab videos, screencasts, pres
1. [High Availability - Video](https://www.youtube.com/watch?v=36KS808u6bE&index=15&list=PLFGfElNsQthbQu_IWlNOxul0TbS_2JH-e)
1. [High Availability Documentation](https://about.gitlab.com/solutions/reference-architectures/)
-### 3.8 Cycle Analytics
+### 3.8 Value Stream Analytics
-1. [GitLab Cycle Analytics Overview](https://about.gitlab.com/blog/2016/09/21/cycle-analytics-feature-highlight/)
-1. [GitLab Cycle Analytics - Product Page](https://about.gitlab.com/stages-devops-lifecycle/value-stream-analytics/)
+1. [GitLab Value Stream Analytics Overview (as of 2016)](https://about.gitlab.com/blog/2016/09/21/cycle-analytics-feature-highlight/)
+1. [GitLab Value Stream Analytics - Product Page](https://about.gitlab.com/stages-devops-lifecycle/value-stream-analytics/)
### 3.9. Integrations
diff --git a/doc/university/training/index.md b/doc/university/training/index.md
index 69f82392027..4c54108b4fa 100644
--- a/doc/university/training/index.md
+++ b/doc/university/training/index.md
@@ -17,7 +17,7 @@ This section contains the following topics:
- [Cherry pick](topics/cherry_picking.md).
- [Code review and collaboration with Merge Requests](topics/merge_requests.md).
- [Configure your environment](topics/env_setup.md).
-- [Explore GitLab](topics/explore_gitlab.md).
+- [Explore GitLab](../../gitlab-basics/README.md).
- [Feature branching](topics/feature_branching.md).
- [Getting started](topics/getting_started.md).
- [GitLab flow](gitlab_flow.md).
diff --git a/doc/update/10.0-ce-to-ee.md b/doc/update/10.0-ce-to-ee.md
deleted file mode 100644
index 10c9e21fa81..00000000000
--- a/doc/update/10.0-ce-to-ee.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_ce_to_ee.md
----
-
-This document was moved to [another location](upgrading_from_ce_to_ee.md).
diff --git a/doc/update/10.0-to-10.1.md b/doc/update/10.0-to-10.1.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/10.0-to-10.1.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/10.1-ce-to-ee.md b/doc/update/10.1-ce-to-ee.md
deleted file mode 100644
index 10c9e21fa81..00000000000
--- a/doc/update/10.1-ce-to-ee.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_ce_to_ee.md
----
-
-This document was moved to [another location](upgrading_from_ce_to_ee.md).
diff --git a/doc/update/10.1-to-10.2.md b/doc/update/10.1-to-10.2.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/10.1-to-10.2.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/10.2-ce-to-ee.md b/doc/update/10.2-ce-to-ee.md
deleted file mode 100644
index 10c9e21fa81..00000000000
--- a/doc/update/10.2-ce-to-ee.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_ce_to_ee.md
----
-
-This document was moved to [another location](upgrading_from_ce_to_ee.md).
diff --git a/doc/update/10.2-to-10.3.md b/doc/update/10.2-to-10.3.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/10.2-to-10.3.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/10.3-ce-to-ee.md b/doc/update/10.3-ce-to-ee.md
deleted file mode 100644
index 10c9e21fa81..00000000000
--- a/doc/update/10.3-ce-to-ee.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_ce_to_ee.md
----
-
-This document was moved to [another location](upgrading_from_ce_to_ee.md).
diff --git a/doc/update/10.3-to-10.4.md b/doc/update/10.3-to-10.4.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/10.3-to-10.4.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/10.4-ce-to-ee.md b/doc/update/10.4-ce-to-ee.md
deleted file mode 100644
index 10c9e21fa81..00000000000
--- a/doc/update/10.4-ce-to-ee.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_ce_to_ee.md
----
-
-This document was moved to [another location](upgrading_from_ce_to_ee.md).
diff --git a/doc/update/10.4-to-10.5.md b/doc/update/10.4-to-10.5.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/10.4-to-10.5.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/10.5-ce-to-ee.md b/doc/update/10.5-ce-to-ee.md
deleted file mode 100644
index 10c9e21fa81..00000000000
--- a/doc/update/10.5-ce-to-ee.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_ce_to_ee.md
----
-
-This document was moved to [another location](upgrading_from_ce_to_ee.md).
diff --git a/doc/update/10.5-to-10.6.md b/doc/update/10.5-to-10.6.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/10.5-to-10.6.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/10.6-ce-to-ee.md b/doc/update/10.6-ce-to-ee.md
deleted file mode 100644
index 10c9e21fa81..00000000000
--- a/doc/update/10.6-ce-to-ee.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_ce_to_ee.md
----
-
-This document was moved to [another location](upgrading_from_ce_to_ee.md).
diff --git a/doc/update/10.6-to-10.7.md b/doc/update/10.6-to-10.7.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/10.6-to-10.7.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/10.7-ce-to-ee.md b/doc/update/10.7-ce-to-ee.md
deleted file mode 100644
index 10c9e21fa81..00000000000
--- a/doc/update/10.7-ce-to-ee.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_ce_to_ee.md
----
-
-This document was moved to [another location](upgrading_from_ce_to_ee.md).
diff --git a/doc/update/10.7-to-10.8.md b/doc/update/10.7-to-10.8.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/10.7-to-10.8.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/10.8-ce-to-ee.md b/doc/update/10.8-ce-to-ee.md
deleted file mode 100644
index 10c9e21fa81..00000000000
--- a/doc/update/10.8-ce-to-ee.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_ce_to_ee.md
----
-
-This document was moved to [another location](upgrading_from_ce_to_ee.md).
diff --git a/doc/update/10.8-to-11.0.md b/doc/update/10.8-to-11.0.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/10.8-to-11.0.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/11.0-ce-to-ee.md b/doc/update/11.0-ce-to-ee.md
deleted file mode 100644
index 10c9e21fa81..00000000000
--- a/doc/update/11.0-ce-to-ee.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_ce_to_ee.md
----
-
-This document was moved to [another location](upgrading_from_ce_to_ee.md).
diff --git a/doc/update/11.0-to-11.1.md b/doc/update/11.0-to-11.1.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/11.0-to-11.1.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/11.1-ce-to-ee.md b/doc/update/11.1-ce-to-ee.md
deleted file mode 100644
index 10c9e21fa81..00000000000
--- a/doc/update/11.1-ce-to-ee.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_ce_to_ee.md
----
-
-This document was moved to [another location](upgrading_from_ce_to_ee.md).
diff --git a/doc/update/11.1-to-11.2.md b/doc/update/11.1-to-11.2.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/11.1-to-11.2.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/11.2-ce-to-ee.md b/doc/update/11.2-ce-to-ee.md
deleted file mode 100644
index 10c9e21fa81..00000000000
--- a/doc/update/11.2-ce-to-ee.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_ce_to_ee.md
----
-
-This document was moved to [another location](upgrading_from_ce_to_ee.md).
diff --git a/doc/update/11.2-to-11.3.md b/doc/update/11.2-to-11.3.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/11.2-to-11.3.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/11.3-ce-to-ee.md b/doc/update/11.3-ce-to-ee.md
deleted file mode 100644
index 10c9e21fa81..00000000000
--- a/doc/update/11.3-ce-to-ee.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_ce_to_ee.md
----
-
-This document was moved to [another location](upgrading_from_ce_to_ee.md).
diff --git a/doc/update/11.3-to-11.4.md b/doc/update/11.3-to-11.4.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/11.3-to-11.4.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/11.4-ce-to-ee.md b/doc/update/11.4-ce-to-ee.md
deleted file mode 100644
index 10c9e21fa81..00000000000
--- a/doc/update/11.4-ce-to-ee.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_ce_to_ee.md
----
-
-This document was moved to [another location](upgrading_from_ce_to_ee.md).
diff --git a/doc/update/11.4-to-11.5.md b/doc/update/11.4-to-11.5.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/11.4-to-11.5.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/11.5-ce-to-ee.md b/doc/update/11.5-ce-to-ee.md
deleted file mode 100644
index 10c9e21fa81..00000000000
--- a/doc/update/11.5-ce-to-ee.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_ce_to_ee.md
----
-
-This document was moved to [another location](upgrading_from_ce_to_ee.md).
diff --git a/doc/update/11.5-to-11.6.md b/doc/update/11.5-to-11.6.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/11.5-to-11.6.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/11.6-ce-to-ee.md b/doc/update/11.6-ce-to-ee.md
deleted file mode 100644
index 10c9e21fa81..00000000000
--- a/doc/update/11.6-ce-to-ee.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_ce_to_ee.md
----
-
-This document was moved to [another location](upgrading_from_ce_to_ee.md).
diff --git a/doc/update/11.6-to-11.7.md b/doc/update/11.6-to-11.7.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/11.6-to-11.7.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/11.7-ce-to-ee.md b/doc/update/11.7-ce-to-ee.md
deleted file mode 100644
index 10c9e21fa81..00000000000
--- a/doc/update/11.7-ce-to-ee.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_ce_to_ee.md
----
-
-This document was moved to [another location](upgrading_from_ce_to_ee.md).
diff --git a/doc/update/11.7-to-11.8.md b/doc/update/11.7-to-11.8.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/11.7-to-11.8.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/11.8-ce-to-ee.md b/doc/update/11.8-ce-to-ee.md
deleted file mode 100644
index 10c9e21fa81..00000000000
--- a/doc/update/11.8-ce-to-ee.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_ce_to_ee.md
----
-
-This document was moved to [another location](upgrading_from_ce_to_ee.md).
diff --git a/doc/update/2.6-to-3.0.md b/doc/update/2.6-to-3.0.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/2.6-to-3.0.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/2.9-to-3.0.md b/doc/update/2.9-to-3.0.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/2.9-to-3.0.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/3.0-to-3.1.md b/doc/update/3.0-to-3.1.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/3.0-to-3.1.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/3.1-to-4.0.md b/doc/update/3.1-to-4.0.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/3.1-to-4.0.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/4.0-to-4.1.md b/doc/update/4.0-to-4.1.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/4.0-to-4.1.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/4.1-to-4.2.md b/doc/update/4.1-to-4.2.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/4.1-to-4.2.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/4.2-to-5.0.md b/doc/update/4.2-to-5.0.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/4.2-to-5.0.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/5.0-to-5.1.md b/doc/update/5.0-to-5.1.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/5.0-to-5.1.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/5.1-to-5.2.md b/doc/update/5.1-to-5.2.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/5.1-to-5.2.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/5.1-to-5.4.md b/doc/update/5.1-to-5.4.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/5.1-to-5.4.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/5.1-to-6.0.md b/doc/update/5.1-to-6.0.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/5.1-to-6.0.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/5.2-to-5.3.md b/doc/update/5.2-to-5.3.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/5.2-to-5.3.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/5.3-to-5.4.md b/doc/update/5.3-to-5.4.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/5.3-to-5.4.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/5.4-to-6.0.md b/doc/update/5.4-to-6.0.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/5.4-to-6.0.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/6.0-ce-to-ee.md b/doc/update/6.0-ce-to-ee.md
deleted file mode 100644
index 10c9e21fa81..00000000000
--- a/doc/update/6.0-ce-to-ee.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_ce_to_ee.md
----
-
-This document was moved to [another location](upgrading_from_ce_to_ee.md).
diff --git a/doc/update/6.0-to-6.1.md b/doc/update/6.0-to-6.1.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/6.0-to-6.1.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/6.1-ce-to-ee.md b/doc/update/6.1-ce-to-ee.md
deleted file mode 100644
index 10c9e21fa81..00000000000
--- a/doc/update/6.1-ce-to-ee.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_ce_to_ee.md
----
-
-This document was moved to [another location](upgrading_from_ce_to_ee.md).
diff --git a/doc/update/6.1-to-6.2.md b/doc/update/6.1-to-6.2.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/6.1-to-6.2.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/6.2-ce-to-ee.md b/doc/update/6.2-ce-to-ee.md
deleted file mode 100644
index 10c9e21fa81..00000000000
--- a/doc/update/6.2-ce-to-ee.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_ce_to_ee.md
----
-
-This document was moved to [another location](upgrading_from_ce_to_ee.md).
diff --git a/doc/update/6.2-to-6.3.md b/doc/update/6.2-to-6.3.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/6.2-to-6.3.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/6.3-ce-to-ee.md b/doc/update/6.3-ce-to-ee.md
deleted file mode 100644
index 10c9e21fa81..00000000000
--- a/doc/update/6.3-ce-to-ee.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_ce_to_ee.md
----
-
-This document was moved to [another location](upgrading_from_ce_to_ee.md).
diff --git a/doc/update/6.3-to-6.4.md b/doc/update/6.3-to-6.4.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/6.3-to-6.4.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/6.4-ce-to-ee.md b/doc/update/6.4-ce-to-ee.md
deleted file mode 100644
index 10c9e21fa81..00000000000
--- a/doc/update/6.4-ce-to-ee.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_ce_to_ee.md
----
-
-This document was moved to [another location](upgrading_from_ce_to_ee.md).
diff --git a/doc/update/6.4-to-6.5.md b/doc/update/6.4-to-6.5.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/6.4-to-6.5.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/6.5-ce-to-ee.md b/doc/update/6.5-ce-to-ee.md
deleted file mode 100644
index 10c9e21fa81..00000000000
--- a/doc/update/6.5-ce-to-ee.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_ce_to_ee.md
----
-
-This document was moved to [another location](upgrading_from_ce_to_ee.md).
diff --git a/doc/update/6.5-to-6.6.md b/doc/update/6.5-to-6.6.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/6.5-to-6.6.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/6.6-ce-to-ee.md b/doc/update/6.6-ce-to-ee.md
deleted file mode 100644
index 10c9e21fa81..00000000000
--- a/doc/update/6.6-ce-to-ee.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_ce_to_ee.md
----
-
-This document was moved to [another location](upgrading_from_ce_to_ee.md).
diff --git a/doc/update/6.6-to-6.7.md b/doc/update/6.6-to-6.7.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/6.6-to-6.7.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/6.7-ce-to-ee.md b/doc/update/6.7-ce-to-ee.md
deleted file mode 100644
index 10c9e21fa81..00000000000
--- a/doc/update/6.7-ce-to-ee.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_ce_to_ee.md
----
-
-This document was moved to [another location](upgrading_from_ce_to_ee.md).
diff --git a/doc/update/6.7-to-6.8.md b/doc/update/6.7-to-6.8.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/6.7-to-6.8.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/6.8-ce-to-ee.md b/doc/update/6.8-ce-to-ee.md
deleted file mode 100644
index 10c9e21fa81..00000000000
--- a/doc/update/6.8-ce-to-ee.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_ce_to_ee.md
----
-
-This document was moved to [another location](upgrading_from_ce_to_ee.md).
diff --git a/doc/update/6.8-to-6.9.md b/doc/update/6.8-to-6.9.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/6.8-to-6.9.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/6.9-ce-to-ee.md b/doc/update/6.9-ce-to-ee.md
deleted file mode 100644
index 10c9e21fa81..00000000000
--- a/doc/update/6.9-ce-to-ee.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_ce_to_ee.md
----
-
-This document was moved to [another location](upgrading_from_ce_to_ee.md).
diff --git a/doc/update/6.9-to-7.0.md b/doc/update/6.9-to-7.0.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/6.9-to-7.0.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/6.x-or-7.x-to-7.14.md b/doc/update/6.x-or-7.x-to-7.14.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/6.x-or-7.x-to-7.14.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/7.0-ce-to-ee.md b/doc/update/7.0-ce-to-ee.md
deleted file mode 100644
index 10c9e21fa81..00000000000
--- a/doc/update/7.0-ce-to-ee.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_ce_to_ee.md
----
-
-This document was moved to [another location](upgrading_from_ce_to_ee.md).
diff --git a/doc/update/7.0-to-7.1.md b/doc/update/7.0-to-7.1.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/7.0-to-7.1.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/7.1-ce-to-ee.md b/doc/update/7.1-ce-to-ee.md
deleted file mode 100644
index 10c9e21fa81..00000000000
--- a/doc/update/7.1-ce-to-ee.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_ce_to_ee.md
----
-
-This document was moved to [another location](upgrading_from_ce_to_ee.md).
diff --git a/doc/update/7.1-to-7.2.md b/doc/update/7.1-to-7.2.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/7.1-to-7.2.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/7.10-ce-to-ee.md b/doc/update/7.10-ce-to-ee.md
deleted file mode 100644
index 10c9e21fa81..00000000000
--- a/doc/update/7.10-ce-to-ee.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_ce_to_ee.md
----
-
-This document was moved to [another location](upgrading_from_ce_to_ee.md).
diff --git a/doc/update/7.10-to-7.11.md b/doc/update/7.10-to-7.11.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/7.10-to-7.11.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/7.11-ce-to-ee.md b/doc/update/7.11-ce-to-ee.md
deleted file mode 100644
index 10c9e21fa81..00000000000
--- a/doc/update/7.11-ce-to-ee.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_ce_to_ee.md
----
-
-This document was moved to [another location](upgrading_from_ce_to_ee.md).
diff --git a/doc/update/7.11-to-7.12.md b/doc/update/7.11-to-7.12.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/7.11-to-7.12.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/7.12-ce-to-ee.md b/doc/update/7.12-ce-to-ee.md
deleted file mode 100644
index 10c9e21fa81..00000000000
--- a/doc/update/7.12-ce-to-ee.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_ce_to_ee.md
----
-
-This document was moved to [another location](upgrading_from_ce_to_ee.md).
diff --git a/doc/update/7.12-to-7.13.md b/doc/update/7.12-to-7.13.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/7.12-to-7.13.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/7.13-ce-to-ee.md b/doc/update/7.13-ce-to-ee.md
deleted file mode 100644
index 10c9e21fa81..00000000000
--- a/doc/update/7.13-ce-to-ee.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_ce_to_ee.md
----
-
-This document was moved to [another location](upgrading_from_ce_to_ee.md).
diff --git a/doc/update/7.13-to-7.14.md b/doc/update/7.13-to-7.14.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/7.13-to-7.14.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/7.14-ce-to-ee.md b/doc/update/7.14-ce-to-ee.md
deleted file mode 100644
index 10c9e21fa81..00000000000
--- a/doc/update/7.14-ce-to-ee.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_ce_to_ee.md
----
-
-This document was moved to [another location](upgrading_from_ce_to_ee.md).
diff --git a/doc/update/7.14-to-8.0.md b/doc/update/7.14-to-8.0.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/7.14-to-8.0.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/7.2-to-7.3.md b/doc/update/7.2-to-7.3.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/7.2-to-7.3.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/7.3-ce-to-ee.md b/doc/update/7.3-ce-to-ee.md
deleted file mode 100644
index 10c9e21fa81..00000000000
--- a/doc/update/7.3-ce-to-ee.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_ce_to_ee.md
----
-
-This document was moved to [another location](upgrading_from_ce_to_ee.md).
diff --git a/doc/update/7.3-to-7.4.md b/doc/update/7.3-to-7.4.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/7.3-to-7.4.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/7.4-ce-to-ee.md b/doc/update/7.4-ce-to-ee.md
deleted file mode 100644
index 10c9e21fa81..00000000000
--- a/doc/update/7.4-ce-to-ee.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_ce_to_ee.md
----
-
-This document was moved to [another location](upgrading_from_ce_to_ee.md).
diff --git a/doc/update/7.4-to-7.5.md b/doc/update/7.4-to-7.5.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/7.4-to-7.5.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/7.5-ce-to-ee.md b/doc/update/7.5-ce-to-ee.md
deleted file mode 100644
index 10c9e21fa81..00000000000
--- a/doc/update/7.5-ce-to-ee.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_ce_to_ee.md
----
-
-This document was moved to [another location](upgrading_from_ce_to_ee.md).
diff --git a/doc/update/7.5-to-7.6.md b/doc/update/7.5-to-7.6.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/7.5-to-7.6.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/7.6-ce-to-ee.md b/doc/update/7.6-ce-to-ee.md
deleted file mode 100644
index 10c9e21fa81..00000000000
--- a/doc/update/7.6-ce-to-ee.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_ce_to_ee.md
----
-
-This document was moved to [another location](upgrading_from_ce_to_ee.md).
diff --git a/doc/update/7.6-to-7.7.md b/doc/update/7.6-to-7.7.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/7.6-to-7.7.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/7.7-ce-to-ee.md b/doc/update/7.7-ce-to-ee.md
deleted file mode 100644
index 10c9e21fa81..00000000000
--- a/doc/update/7.7-ce-to-ee.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_ce_to_ee.md
----
-
-This document was moved to [another location](upgrading_from_ce_to_ee.md).
diff --git a/doc/update/7.7-to-7.8.md b/doc/update/7.7-to-7.8.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/7.7-to-7.8.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/7.8-ce-to-ee.md b/doc/update/7.8-ce-to-ee.md
deleted file mode 100644
index 10c9e21fa81..00000000000
--- a/doc/update/7.8-ce-to-ee.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_ce_to_ee.md
----
-
-This document was moved to [another location](upgrading_from_ce_to_ee.md).
diff --git a/doc/update/7.8-to-7.9.md b/doc/update/7.8-to-7.9.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/7.8-to-7.9.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/7.9-ce-to-ee.md b/doc/update/7.9-ce-to-ee.md
deleted file mode 100644
index 10c9e21fa81..00000000000
--- a/doc/update/7.9-ce-to-ee.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_ce_to_ee.md
----
-
-This document was moved to [another location](upgrading_from_ce_to_ee.md).
diff --git a/doc/update/7.9-to-7.10.md b/doc/update/7.9-to-7.10.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/7.9-to-7.10.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/8.0-ce-to-ee.md b/doc/update/8.0-ce-to-ee.md
deleted file mode 100644
index 10c9e21fa81..00000000000
--- a/doc/update/8.0-ce-to-ee.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_ce_to_ee.md
----
-
-This document was moved to [another location](upgrading_from_ce_to_ee.md).
diff --git a/doc/update/8.0-to-8.1.md b/doc/update/8.0-to-8.1.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/8.0-to-8.1.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/8.1-ce-to-ee.md b/doc/update/8.1-ce-to-ee.md
deleted file mode 100644
index 10c9e21fa81..00000000000
--- a/doc/update/8.1-ce-to-ee.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_ce_to_ee.md
----
-
-This document was moved to [another location](upgrading_from_ce_to_ee.md).
diff --git a/doc/update/8.1-to-8.2.md b/doc/update/8.1-to-8.2.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/8.1-to-8.2.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/8.10-ce-to-ee.md b/doc/update/8.10-ce-to-ee.md
deleted file mode 100644
index 10c9e21fa81..00000000000
--- a/doc/update/8.10-ce-to-ee.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_ce_to_ee.md
----
-
-This document was moved to [another location](upgrading_from_ce_to_ee.md).
diff --git a/doc/update/8.10-to-8.11.md b/doc/update/8.10-to-8.11.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/8.10-to-8.11.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/8.11-ce-to-ee.md b/doc/update/8.11-ce-to-ee.md
deleted file mode 100644
index 10c9e21fa81..00000000000
--- a/doc/update/8.11-ce-to-ee.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_ce_to_ee.md
----
-
-This document was moved to [another location](upgrading_from_ce_to_ee.md).
diff --git a/doc/update/8.11-to-8.12.md b/doc/update/8.11-to-8.12.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/8.11-to-8.12.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/8.12-ce-to-ee.md b/doc/update/8.12-ce-to-ee.md
deleted file mode 100644
index 10c9e21fa81..00000000000
--- a/doc/update/8.12-ce-to-ee.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_ce_to_ee.md
----
-
-This document was moved to [another location](upgrading_from_ce_to_ee.md).
diff --git a/doc/update/8.12-to-8.13.md b/doc/update/8.12-to-8.13.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/8.12-to-8.13.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/8.13-ce-to-ee.md b/doc/update/8.13-ce-to-ee.md
deleted file mode 100644
index 10c9e21fa81..00000000000
--- a/doc/update/8.13-ce-to-ee.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_ce_to_ee.md
----
-
-This document was moved to [another location](upgrading_from_ce_to_ee.md).
diff --git a/doc/update/8.13-to-8.14.md b/doc/update/8.13-to-8.14.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/8.13-to-8.14.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/8.14-ce-to-ee.md b/doc/update/8.14-ce-to-ee.md
deleted file mode 100644
index 10c9e21fa81..00000000000
--- a/doc/update/8.14-ce-to-ee.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_ce_to_ee.md
----
-
-This document was moved to [another location](upgrading_from_ce_to_ee.md).
diff --git a/doc/update/8.14-to-8.15.md b/doc/update/8.14-to-8.15.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/8.14-to-8.15.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/8.15-ce-to-ee.md b/doc/update/8.15-ce-to-ee.md
deleted file mode 100644
index 10c9e21fa81..00000000000
--- a/doc/update/8.15-ce-to-ee.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_ce_to_ee.md
----
-
-This document was moved to [another location](upgrading_from_ce_to_ee.md).
diff --git a/doc/update/8.15-to-8.16.md b/doc/update/8.15-to-8.16.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/8.15-to-8.16.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/8.16-ce-to-ee.md b/doc/update/8.16-ce-to-ee.md
deleted file mode 100644
index 10c9e21fa81..00000000000
--- a/doc/update/8.16-ce-to-ee.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_ce_to_ee.md
----
-
-This document was moved to [another location](upgrading_from_ce_to_ee.md).
diff --git a/doc/update/8.16-to-8.17.md b/doc/update/8.16-to-8.17.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/8.16-to-8.17.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/8.17-ce-to-ee.md b/doc/update/8.17-ce-to-ee.md
deleted file mode 100644
index 10c9e21fa81..00000000000
--- a/doc/update/8.17-ce-to-ee.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_ce_to_ee.md
----
-
-This document was moved to [another location](upgrading_from_ce_to_ee.md).
diff --git a/doc/update/8.17-to-9.0.md b/doc/update/8.17-to-9.0.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/8.17-to-9.0.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/8.2-ce-to-ee.md b/doc/update/8.2-ce-to-ee.md
deleted file mode 100644
index 10c9e21fa81..00000000000
--- a/doc/update/8.2-ce-to-ee.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_ce_to_ee.md
----
-
-This document was moved to [another location](upgrading_from_ce_to_ee.md).
diff --git a/doc/update/8.2-to-8.3.md b/doc/update/8.2-to-8.3.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/8.2-to-8.3.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/8.3-ce-to-ee.md b/doc/update/8.3-ce-to-ee.md
deleted file mode 100644
index 10c9e21fa81..00000000000
--- a/doc/update/8.3-ce-to-ee.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_ce_to_ee.md
----
-
-This document was moved to [another location](upgrading_from_ce_to_ee.md).
diff --git a/doc/update/8.3-to-8.4.md b/doc/update/8.3-to-8.4.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/8.3-to-8.4.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/8.4-ce-to-ee.md b/doc/update/8.4-ce-to-ee.md
deleted file mode 100644
index 10c9e21fa81..00000000000
--- a/doc/update/8.4-ce-to-ee.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_ce_to_ee.md
----
-
-This document was moved to [another location](upgrading_from_ce_to_ee.md).
diff --git a/doc/update/8.4-to-8.5.md b/doc/update/8.4-to-8.5.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/8.4-to-8.5.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/8.5-ce-to-ee.md b/doc/update/8.5-ce-to-ee.md
deleted file mode 100644
index 10c9e21fa81..00000000000
--- a/doc/update/8.5-ce-to-ee.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_ce_to_ee.md
----
-
-This document was moved to [another location](upgrading_from_ce_to_ee.md).
diff --git a/doc/update/8.5-to-8.6.md b/doc/update/8.5-to-8.6.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/8.5-to-8.6.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/8.6-ce-to-ee.md b/doc/update/8.6-ce-to-ee.md
deleted file mode 100644
index 10c9e21fa81..00000000000
--- a/doc/update/8.6-ce-to-ee.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_ce_to_ee.md
----
-
-This document was moved to [another location](upgrading_from_ce_to_ee.md).
diff --git a/doc/update/8.6-to-8.7.md b/doc/update/8.6-to-8.7.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/8.6-to-8.7.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/8.7-ce-to-ee.md b/doc/update/8.7-ce-to-ee.md
deleted file mode 100644
index 10c9e21fa81..00000000000
--- a/doc/update/8.7-ce-to-ee.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_ce_to_ee.md
----
-
-This document was moved to [another location](upgrading_from_ce_to_ee.md).
diff --git a/doc/update/8.7-to-8.8.md b/doc/update/8.7-to-8.8.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/8.7-to-8.8.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/8.8-ce-to-ee.md b/doc/update/8.8-ce-to-ee.md
deleted file mode 100644
index 10c9e21fa81..00000000000
--- a/doc/update/8.8-ce-to-ee.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_ce_to_ee.md
----
-
-This document was moved to [another location](upgrading_from_ce_to_ee.md).
diff --git a/doc/update/8.8-to-8.9.md b/doc/update/8.8-to-8.9.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/8.8-to-8.9.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/8.9-ce-to-ee.md b/doc/update/8.9-ce-to-ee.md
deleted file mode 100644
index 10c9e21fa81..00000000000
--- a/doc/update/8.9-ce-to-ee.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_ce_to_ee.md
----
-
-This document was moved to [another location](upgrading_from_ce_to_ee.md).
diff --git a/doc/update/8.9-to-8.10.md b/doc/update/8.9-to-8.10.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/8.9-to-8.10.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/9.0-ce-to-ee.md b/doc/update/9.0-ce-to-ee.md
deleted file mode 100644
index 10c9e21fa81..00000000000
--- a/doc/update/9.0-ce-to-ee.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_ce_to_ee.md
----
-
-This document was moved to [another location](upgrading_from_ce_to_ee.md).
diff --git a/doc/update/9.0-to-9.1.md b/doc/update/9.0-to-9.1.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/9.0-to-9.1.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/9.1-ce-to-ee.md b/doc/update/9.1-ce-to-ee.md
deleted file mode 100644
index 10c9e21fa81..00000000000
--- a/doc/update/9.1-ce-to-ee.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_ce_to_ee.md
----
-
-This document was moved to [another location](upgrading_from_ce_to_ee.md).
diff --git a/doc/update/9.1-to-9.2.md b/doc/update/9.1-to-9.2.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/9.1-to-9.2.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/9.2-ce-to-ee.md b/doc/update/9.2-ce-to-ee.md
deleted file mode 100644
index 10c9e21fa81..00000000000
--- a/doc/update/9.2-ce-to-ee.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_ce_to_ee.md
----
-
-This document was moved to [another location](upgrading_from_ce_to_ee.md).
diff --git a/doc/update/9.2-to-9.3.md b/doc/update/9.2-to-9.3.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/9.2-to-9.3.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/9.3-ce-to-ee.md b/doc/update/9.3-ce-to-ee.md
deleted file mode 100644
index 10c9e21fa81..00000000000
--- a/doc/update/9.3-ce-to-ee.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_ce_to_ee.md
----
-
-This document was moved to [another location](upgrading_from_ce_to_ee.md).
diff --git a/doc/update/9.3-to-9.4.md b/doc/update/9.3-to-9.4.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/9.3-to-9.4.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/9.4-ce-to-ee.md b/doc/update/9.4-ce-to-ee.md
deleted file mode 100644
index 10c9e21fa81..00000000000
--- a/doc/update/9.4-ce-to-ee.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_ce_to_ee.md
----
-
-This document was moved to [another location](upgrading_from_ce_to_ee.md).
diff --git a/doc/update/9.4-to-9.5.md b/doc/update/9.4-to-9.5.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/9.4-to-9.5.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/9.5-ce-to-ee.md b/doc/update/9.5-ce-to-ee.md
deleted file mode 100644
index 10c9e21fa81..00000000000
--- a/doc/update/9.5-ce-to-ee.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_ce_to_ee.md
----
-
-This document was moved to [another location](upgrading_from_ce_to_ee.md).
diff --git a/doc/update/9.5-to-10.0.md b/doc/update/9.5-to-10.0.md
deleted file mode 100644
index 8514aa13f48..00000000000
--- a/doc/update/9.5-to-10.0.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: upgrading_from_source.md
----
-
-This document was moved to [another location](upgrading_from_source.md).
diff --git a/doc/update/README.md b/doc/update/README.md
index a7f7aaf5887..b5e99671278 100644
--- a/doc/update/README.md
+++ b/doc/update/README.md
@@ -123,7 +123,7 @@ If using GitLab 12.9 and newer, run:
sudo gitlab-rails runner -e production 'puts Gitlab::BackgroundMigration.remaining'
```
-If using GitLab 12.8 and older, run the following using a [Rails console](../administration/troubleshooting/debug.md#starting-a-rails-console-session):
+If using GitLab 12.8 and older, run the following using a [Rails console](../administration/operations/rails_console.md#starting-a-rails-console-session):
```ruby
puts Sidekiq::Queue.new("background_migration").size
@@ -141,7 +141,7 @@ cd /home/git/gitlab
sudo -u git -H bundle exec rails runner -e production 'puts Gitlab::BackgroundMigration.remaining'
```
-If using GitLab 12.8 and older, run the following using a [Rails console](../administration/troubleshooting/debug.md#starting-a-rails-console-session):
+If using GitLab 12.8 and older, run the following using a [Rails console](../administration/operations/rails_console.md#starting-a-rails-console-session):
```ruby
puts Sidekiq::Queue.new("background_migration").size
diff --git a/doc/user/admin_area/abuse_reports.md b/doc/user/admin_area/abuse_reports.md
index 0283f1a9eff..4c346d7dfe8 100644
--- a/doc/user/admin_area/abuse_reports.md
+++ b/doc/user/admin_area/abuse_reports.md
@@ -20,6 +20,9 @@ To receive notifications of new abuse reports by e-mail, follow these steps:
1. Expand the **Abuse reports** section.
1. Provide an email address.
+The notification email address can also be set and retrieved
+[using the API](../../api/settings.md#list-of-settings-that-can-be-accessed-via-api-calls).
+
## Reporting abuse
To find out more about reporting abuse, see [abuse reports user
@@ -31,14 +34,14 @@ To access abuse reports, go to **Admin Area > Abuse Reports**.
There are 3 ways to resolve an abuse report, with a button for each method:
-- Remove user & report. This will:
- - [Delete the reported user](../profile/account/delete_account.md) from the
+- Remove user & report. This:
+ - [Deletes the reported user](../profile/account/delete_account.md) from the
instance.
- - Remove the abuse report from the list.
+ - Removes the abuse report from the list.
- [Block user](#blocking-users).
-- Remove report. This will:
- - Remove the abuse report from the list.
- - Remove access restrictions for the reported user.
+- Remove report. This:
+ - Removes the abuse report from the list.
+ - Removes access restrictions for the reported user.
The following is an example of the **Abuse Reports** page:
@@ -54,8 +57,7 @@ Blocking a user:
- Leaves them in the abuse report list.
- Changes the **Block user** button to a disabled **Already blocked** button.
-The user will be notified with the
-[following message](https://gitlab.com/gitlab-org/gitlab/blob/master/app/workers/email_receiver_worker.rb#L38):
+The user is notified with the following message:
```plaintext
Your account has been blocked. If you believe this is in error, contact a staff member.
diff --git a/doc/user/admin_area/activating_deactivating_users.md b/doc/user/admin_area/activating_deactivating_users.md
index 29f162616bf..8b3a7682841 100644
--- a/doc/user/admin_area/activating_deactivating_users.md
+++ b/doc/user/admin_area/activating_deactivating_users.md
@@ -39,7 +39,7 @@ A user can be deactivated from the Admin Area. To do this:
Please note that for the deactivation option to be visible to an admin, the user:
- Must be currently active.
-- Must not have signed in, or have any activity, in the last 180 days.
+- Must not have signed in, or have any activity, in the last 90 days.
Users can also be deactivated using the [GitLab API](../../api/users.md#deactivate-user).
diff --git a/doc/user/admin_area/analytics/img/cohorts_v13_4.png b/doc/user/admin_area/analytics/img/cohorts_v13_4.png
index 4af1841a033..6f7dd5101f2 100644
--- a/doc/user/admin_area/analytics/img/cohorts_v13_4.png
+++ b/doc/user/admin_area/analytics/img/cohorts_v13_4.png
Binary files differ
diff --git a/doc/user/admin_area/analytics/img/dev_ops_report_v13_4.png b/doc/user/admin_area/analytics/img/dev_ops_report_v13_4.png
index 1fa070a6915..d47d86cd514 100644
--- a/doc/user/admin_area/analytics/img/dev_ops_report_v13_4.png
+++ b/doc/user/admin_area/analytics/img/dev_ops_report_v13_4.png
Binary files differ
diff --git a/doc/user/admin_area/analytics/index.md b/doc/user/admin_area/analytics/index.md
index b3336b471f8..f79245c7325 100644
--- a/doc/user/admin_area/analytics/index.md
+++ b/doc/user/admin_area/analytics/index.md
@@ -4,7 +4,8 @@
Administrators have access to instance-wide analytics, as shown in **Admin Area > Analytics**.
-There are two kinds of statistics:
+There are several kinds of statistics:
- [DevOps Report](dev_ops_report.md): Provides an overview of your entire instance's feature usage.
+- [Instance Statistics](instance_statistics.md): Shows how much data your instance contains, and how that is changing.
- [User Cohorts](user_cohorts.md): Display the monthly cohorts of new users and their activities over time.
diff --git a/doc/user/admin_area/analytics/instance_statistics.md b/doc/user/admin_area/analytics/instance_statistics.md
new file mode 100644
index 00000000000..bac0e845d2c
--- /dev/null
+++ b/doc/user/admin_area/analytics/instance_statistics.md
@@ -0,0 +1,18 @@
+# Instance Statistics
+
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/235754) in GitLab 13.4.
+
+Instance Statistics gives you an overview of how much data your instance contains, and how quickly this volume is changing over time.
+
+## Total counts
+
+At the top of the page, Instance Statistics shows total counts for:
+
+- Users
+- Projects
+- Groups
+- Issues
+- Merge Requests
+- Pipelines
+
+These figures can be useful for understanding how much data your instance contains in total.
diff --git a/doc/user/admin_area/approving_users.md b/doc/user/admin_area/approving_users.md
new file mode 100644
index 00000000000..486d0b6a25d
--- /dev/null
+++ b/doc/user/admin_area/approving_users.md
@@ -0,0 +1,36 @@
+---
+stage: Manage
+group: Access
+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/#designated-technical-writers
+type: howto
+---
+
+# Users pending approval
+
+> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/4491) in GitLab 13.5.
+
+When [Require admin approval for new sign-ups](settings/sign_up_restrictions.md#require-admin-approval-for-new-sign-ups) is enabled, any user that signs up for an account using the registration form is placed under a **Pending approval** state.
+
+A user pending approval is functionally identical to a [blocked](blocking_unblocking_users.md) user.
+
+A user pending approval:
+
+- Will not be able to sign in.
+- Cannot access Git repositories or the API.
+- Will not receive any notifications from GitLab.
+- Does not consume a [seat](../../subscriptions/self_managed/index.md#choose-the-number-of-users).
+
+## Approving a user
+
+A user that is pending approval can be approved from the Admin Area. To do this:
+
+1. Navigate to **Admin Area > Overview > Users**.
+1. Click on the **Pending approval** tab.
+1. Select a user.
+1. Under the **Account** tab, click **Approve user**.
+
+Approving a user:
+
+1. Activates their account.
+1. Changes the user's state to active and it consumes a
+[seat](../../subscriptions/self_managed/index.md#choose-the-number-of-users).
diff --git a/doc/user/admin_area/credentials_inventory.md b/doc/user/admin_area/credentials_inventory.md
index 7f2d49dafea..b17d0ab3dd5 100644
--- a/doc/user/admin_area/credentials_inventory.md
+++ b/doc/user/admin_area/credentials_inventory.md
@@ -9,11 +9,9 @@ type: howto
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/20912) in GitLab 12.6.
-## Overview
-
GitLab administrators are responsible for the overall security of their instance. To assist, GitLab provides a Credentials inventory to keep track of all the credentials that can be used to access their self-managed instance.
-Using Credentials inventory, you can see all the personal access tokens (PAT) and SSH keys that exist in your GitLab instance. In addition, you can [revoke them](#revoke-a-users-personal-access-token) and see:
+Using Credentials inventory, you can see all the personal access tokens (PAT) and SSH keys that exist in your GitLab instance. In addition, you can [revoke](#revoke-a-users-personal-access-token) and [delete](#delete-a-users-ssh-key) and see:
- Who they belong to.
- Their access scope.
@@ -29,7 +27,7 @@ The following is an example of the Credentials inventory page:
## Revoke a user's personal access token
-[Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/214811) in GitLab 13.4.
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/214811) in GitLab 13.4.
If you see a **Revoke** button, you can revoke that user's PAT. Whether you see a **Revoke** button depends on the token state, and if an expiration date has been set. For more information, see the following table:
@@ -37,7 +35,15 @@ If you see a **Revoke** button, you can revoke that user's PAT. Whether you see
|-------------|------------------------|--------------------|----------------------------------------------------------------------------|
| Active | Yes | Yes | Allows administrators to revoke the PAT, such as for a compromised account |
| Active | No | Yes | Allows administrators to revoke the PAT, such as for a compromised account |
-| Expired | Yes | No | PAT expires automatically |
-| Expired | No | Yes | The administrator may revoke the PAT to prevent indefinite use |
-| Revoked | Yes | No | Not applicable; token is already revoked |
-| Revoked | No | No | Not applicable; token is already revoked |
+| Expired | Yes | No | PAT expires automatically |
+| Expired | No | Yes | The administrator may revoke the PAT to prevent indefinite use |
+| Revoked | Yes | No | Not applicable; token is already revoked |
+| Revoked | No | No | Not applicable; token is already revoked |
+
+## Delete a user's SSH key
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/225248) in GitLab 13.5.
+
+You can **Delete** a user's SSH key by navigating to the credentials inventory's SSH Keys tab.
+
+![Credentials inventory page - SSH keys](img/credentials_inventory_ssh_keys_v13_5.png)
diff --git a/doc/user/admin_area/img/admin_wrench.png b/doc/user/admin_area/img/admin_wrench.png
deleted file mode 100644
index 17eee143e87..00000000000
--- a/doc/user/admin_area/img/admin_wrench.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/admin_area/img/credentials_inventory_ssh_keys_v13_5.png b/doc/user/admin_area/img/credentials_inventory_ssh_keys_v13_5.png
new file mode 100644
index 00000000000..f5edf513bbf
--- /dev/null
+++ b/doc/user/admin_area/img/credentials_inventory_ssh_keys_v13_5.png
Binary files differ
diff --git a/doc/user/admin_area/index.md b/doc/user/admin_area/index.md
index 58430ab615b..0ddbe17580a 100644
--- a/doc/user/admin_area/index.md
+++ b/doc/user/admin_area/index.md
@@ -118,8 +118,15 @@ To list users matching a specific criteria, click on one of the following tabs o
- **[Deactivated](activating_deactivating_users.md)**
- **Without projects**
-For each user, their username, email address, are listed, also the date their account was
-created and the date of last activity. To edit a user, click the **Edit** button in that user's
+For each user, the following are listed:
+
+1. Username
+1. Email address
+1. Project membership count
+1. Date of account creation
+1. Date of last activity
+
+To edit a user, click the **Edit** button in that user's
row. To delete the user, or delete the user and their contributions, click the cog dropdown in
that user's row, and select the desired option.
diff --git a/doc/user/admin_area/license.md b/doc/user/admin_area/license.md
index ecbc615f56a..c37a61d6748 100644
--- a/doc/user/admin_area/license.md
+++ b/doc/user/admin_area/license.md
@@ -8,130 +8,126 @@ type: howto
# Activate GitLab EE with a license **(STARTER ONLY)**
To activate all GitLab Enterprise Edition (EE) functionality, you need to upload
-a license. Once you've received your license from GitLab Inc., you can upload it
-by **signing into your GitLab instance as an admin** or add it at
+a license. After you've received your license from GitLab Inc., you can upload it
+by **signing into your GitLab instance as an admin** or adding it at
installation time.
-The license has the form of a base64 encoded ASCII text with a `.gitlab-license`
-extension and can be obtained when you [purchase one](https://about.gitlab.com/pricing/) or when you sign
-up for a [free trial](https://about.gitlab.com/free-trial/).
+The license is a base64-encoded ASCII text file with a `.gitlab-license`
+extension. You can obtain the file by [purchasing a license](https://about.gitlab.com/pricing/)
+or by signing up for a [free trial](https://about.gitlab.com/free-trial/).
-NOTE: **Note:**
As of GitLab Enterprise Edition 9.4.0, a newly-installed instance without an
-uploaded license will only have the Core features active. A trial license will
-activate all Ultimate features, but after
+uploaded license only has the Core features active. A trial license
+activates all Ultimate features, but after
[the trial expires](#what-happens-when-your-license-expires), some functionality
-will be locked.
+is locked.
## Uploading your license
The very first time you visit your GitLab EE installation signed in as an admin,
you should see a note urging you to upload a license with a link that takes you
-straight to **Admin Area > License**.
+to **Admin Area > License**.
Otherwise, you can:
-1. Navigate manually to the **Admin Area** by clicking the wrench icon in the menu bar.
+1. Navigate manually to the **Admin Area** by clicking the wrench (**{admin}**) icon in the menu bar.
- ![Admin Area icon](img/admin_wrench.png)
-
-1. And then going to the **License** tab and click on **Upload New License**.
+1. Navigate to the **License** tab, and click **Upload New License**.
![License Admin Area](img/license_admin_area.png)
-1. If you've received a `.gitlab-license` file, you should have already downloaded
- it in your local machine. You can then upload it directly by choosing the
- license file and clicking the **Upload license** button. In the image below,
- you can see that the selected license file is named `GitLab.gitlab-license`.
+ - *If you've received a `.gitlab-license` file,* you should have already downloaded
+ it in your local machine. You can then upload it directly by choosing the
+ license file and clicking the **Upload license** button. In the image below,
+ the selected license file is named `GitLab.gitlab-license`.
- ![Upload license](img/license_upload.png)
+ ![Upload license](img/license_upload.png)
- If you've received your license as plain text, you need to select the
- "Enter license key" option, copy the license, paste it into the "License key"
- field and click **Upload license**.
+ - *If you've received your license as plain text,* select the
+ **Enter license key** option, copy the license, paste it into the **License key**
+ field, and click **Upload license**.
## Add your license at install time
-A license can be automatically imported at install time, by placing a file named
-`Gitlab.gitlab-license` in `/etc/gitlab/` for Omnibus, or `config/` for source installations.
+A license can be automatically imported at install time by placing a file named
+`Gitlab.gitlab-license` in `/etc/gitlab/` for Omnibus GitLab, or `config/` for source installations.
-It is also possible to specify a custom location and filename for the license.
+You can also specify a custom location and filename for the license:
-Source installations should set the `GITLAB_LICENSE_FILE` environment
-variable with the path to a valid GitLab Enterprise Edition license.
+- Source installations should set the `GITLAB_LICENSE_FILE` environment
+ variable with the path to a valid GitLab Enterprise Edition license.
-```shell
-export GITLAB_LICENSE_FILE="/path/to/license/file"
-```
+ ```shell
+ export GITLAB_LICENSE_FILE="/path/to/license/file"
+ ```
-Omnibus installations should add this entry to `gitlab.rb`:
+- Omnibus GitLab installations should add this entry to `gitlab.rb`:
-```ruby
-gitlab_rails['initial_license_file'] = "/path/to/license/file"
-```
+ ```ruby
+ gitlab_rails['initial_license_file'] = "/path/to/license/file"
+ ```
CAUTION: **Caution:**
-These methods will only add a license at the time of installation. Use the
-Admin Area in the web user interface to renew or upgrade licenses.
+These methods only add a license at the time of installation. Use the
+**{admin}** **Admin Area** in the web user interface to renew or upgrade licenses.
---
-Once the license is uploaded, all GitLab Enterprise Edition functionality
-will be active until the end of the license period. When that period ends, the
+After the license is uploaded, all GitLab Enterprise Edition functionality
+is active until the end of the license period. When that period ends, the
instance will [fall back](#what-happens-when-your-license-expires) to Core-only
functionality.
-You can review the license details at any time in the License section of the
-Admin Area.
+You can review the license details at any time in the **License** section of the
+**Admin Area**.
![License details](img/license_details.png)
## Notification before the license expires
-One month before the license expires, a message informing when the expiration
-is due to, will start appearing to GitLab admins. Make sure that you update your
-license, otherwise you will miss all the paid features if it expires.
+One month before the license expires, a message informing about the expiration
+date is displayed to GitLab admins. Make sure that you update your
+license, otherwise you miss all the paid features if your license expires.
## What happens when your license expires
-In case your license expires, GitLab will lock down some features like Git pushes,
-issue creation, etc., and a message to inform of the expired license will be
-presented to all admins.
+In case your license expires, GitLab locks down some features like Git pushes,
+and issue creation, and displays a message to all admins to inform of the expired license.
-In order to get back all the previous functionality, a new license must be uploaded.
-To fall back to having only the Core features active, you'll need to delete the
+To get back all the previous functionality, you must upload a new license.
+To fall back to having only the Core features active, you must delete the
expired license(s).
### Remove a license
To remove a license from a self-managed instance:
-1. Go to the [Admin Area](index.md) (click the wrench in the top navigation bar).
+1. In the top navigation bar, click the **{admin}** wrench icon to navigate to the [Admin Area](index.md).
1. Click **License** in the left sidebar.
1. Click **Remove License**.
## License history
-It's possible to upload and view more than one license,
-but only the latest license will be used as the active license.
+You can upload and view more than one license,
+but only the latest license is used as the active license.
## Troubleshooting
### There is no License tab in the Admin Area
-If you originally installed Community Edition rather than Enterprise Edition you will need to
+If you originally installed Community Edition rather than Enterprise Edition you must
[upgrade to Enterprise Edition](../../update/README.md#community-to-enterprise-edition)
before uploading your license.
-GitLab.com users cannot upload and use a self-managed license. If you
-wish to use paid features on GitLab.com, a separate subscription may be
-[purchased](../../subscriptions/gitlab_com/index.md).
+GitLab.com users can't upload and use a self-managed license. If you
+want to use paid features on GitLab.com, you can
+[purchase a separate subscription](../../subscriptions/gitlab_com/index.md).
### Users exceed license limit upon renewal
-If you've added new users to your GitLab instance prior to renewal you may need to
-purchase additional seats to cover those users. If this is the case and a license
-without enough users is uploaded a message is displayed prompting you to purchase
+If you've added new users to your GitLab instance prior to renewal, you may need to
+purchase additional seats to cover those users. If this is the case, and a license
+without enough users is uploaded, GitLab displays a message prompting you to purchase
additional users. More information on how to determine the required number of users
and how to add additional seats can be found in the
[licensing FAQ](https://about.gitlab.com/pricing/licensing-faq/).
diff --git a/doc/user/admin_area/settings/gitaly_timeouts.md b/doc/user/admin_area/settings/gitaly_timeouts.md
index 2003d02c9b3..cac05678a1a 100644
--- a/doc/user/admin_area/settings/gitaly_timeouts.md
+++ b/doc/user/admin_area/settings/gitaly_timeouts.md
@@ -3,36 +3,28 @@ stage: Create
group: Gitaly
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/#designated-technical-writers"
type: reference
-type: reference
---
-# Gitaly timeouts
-
-![Gitaly timeouts](img/gitaly_timeouts.png)
-
-3 timeout types can be configured to make sure that long running
-Gitaly calls don't needlessly take up resources.
-
-- Default timeout
-
-This timeout is the default for most Gitaly calls.
-It should be shorter than the worker timeout that can be configured
-for
-[Puma](https://docs.gitlab.com/omnibus/settings/puma.html#puma-settings)
-or [Unicorn](https://docs.gitlab.com/omnibus/settings/unicorn.html).
-This makes sure that Gitaly calls made within a web request cannot
-exceed these the entire request timeout.
+# Gitaly timeouts **(CORE ONLY)**
-The default for this timeout is 55 seconds.
+[Gitaly](../../../administration/gitaly/index.md) timeouts are configurable. The timeouts can be
+configured to make sure that long running Gitaly calls don't needlessly take up resources.
-- Fast timeout
+To access Gitaly timeout settings:
-This is the timeout for very short Gitaly calls.
+1. Go to **Admin Area > Settings > Preferences**.
+1. Expand the **Gitaly** section.
-The default for this timeout is 10 seconds.
+## Available timeouts
-- Medium timeout
+The following timeouts can be modified:
-This timeout should be between the default and the fast timeout
+- **Default Timeout Period**. This timeout is the default for most Gitaly calls. It should be shorter than the
+ worker timeout that can be configured for [Puma](https://docs.gitlab.com/omnibus/settings/puma.html#puma-settings)
+ or [Unicorn](https://docs.gitlab.com/omnibus/settings/unicorn.html). Used to make sure that Gitaly
+ calls made within a web request cannot exceed the entire request timeout.
+ Defaults to 55 seconds.
-The default for this timeout is 30 seconds.
+- **Fast Timeout Period**. This is the timeout for very short Gitaly calls. Defaults to 10 seconds.
+- **Medium Timeout Period**. This timeout should be between the default and the fast timeout.
+ Defaults to 30 seconds.
diff --git a/doc/user/admin_area/settings/img/email_confirmation_v12_7.png b/doc/user/admin_area/settings/img/email_confirmation_v12_7.png
deleted file mode 100644
index 6bcadb63b9a..00000000000
--- a/doc/user/admin_area/settings/img/email_confirmation_v12_7.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/admin_area/settings/img/gitaly_timeouts.png b/doc/user/admin_area/settings/img/gitaly_timeouts.png
deleted file mode 100644
index 28394d238f7..00000000000
--- a/doc/user/admin_area/settings/img/gitaly_timeouts.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/admin_area/settings/img/sign_up_restrictions_v13_5.png b/doc/user/admin_area/settings/img/sign_up_restrictions_v13_5.png
new file mode 100644
index 00000000000..ebbfad77e69
--- /dev/null
+++ b/doc/user/admin_area/settings/img/sign_up_restrictions_v13_5.png
Binary files differ
diff --git a/doc/user/admin_area/settings/index.md b/doc/user/admin_area/settings/index.md
index ba9bccbf3e7..bc8df63e33f 100644
--- a/doc/user/admin_area/settings/index.md
+++ b/doc/user/admin_area/settings/index.md
@@ -30,11 +30,11 @@ Access the default page for admin area settings by navigating to **Admin Area >
| Option | Description |
| ------ | ----------- |
-| [Elasticsearch](../../../integration/elasticsearch.md#enabling-elasticsearch) | Elasticsearch integration. Elasticsearch AWS IAM. |
+| [Elasticsearch](../../../integration/elasticsearch.md#enabling-advanced-search) | Elasticsearch integration. Elasticsearch AWS IAM. |
| [PlantUML](../../../administration/integration/plantuml.md#gitlab) | Allow rendering of PlantUML diagrams in AsciiDoc documents. |
| [Slack application](../../../user/project/integrations/gitlab_slack_application.md#configuration) **(FREE ONLY)** | Slack integration allows you to interact with GitLab via slash commands in a chat window. This option is only available on GitLab.com, though it may be [available for self-managed instances in the future](https://gitlab.com/gitlab-org/gitlab/-/issues/28164). |
| [Third party offers](third_party_offers.md) | Control the display of third party offers. |
-| [Snowplow](../../../development/telemetry/snowplow.md) | Configure the Snowplow integration. |
+| [Snowplow](../../../development/product_analytics/snowplow.md) | Configure the Snowplow integration. |
| [Google GKE](../../project/clusters/add_gke_clusters.md) | Google GKE integration allows you to provision GKE clusters from GitLab. |
| [Amazon EKS](../../project/clusters/add_eks_clusters.md) | Amazon EKS integration allows you to provision EKS clusters from GitLab. |
@@ -61,7 +61,7 @@ Access the default page for admin area settings by navigating to **Admin Area >
| ------ | ----------- |
| [Continuous Integration and Deployment](continuous_integration.md) | Auto DevOps, runners and job artifacts. |
| [Required pipeline configuration](continuous_integration.md#required-pipeline-configuration) **(PREMIUM ONLY)** | Set an instance-wide auto included [pipeline configuration](../../../ci/yaml/README.md). This pipeline configuration will be run after the project's own configuration. |
-| [Package Registry](continuous_integration.md#package-registry-configuration) | Settings related to the use and experience of using GitLab's Package Registry. Note there are [risks involved](./../../packages/container_registry/index.md#use-with-external-container-registries) in enabling some of these settings. |
+| [Package Registry](continuous_integration.md#package-registry-configuration) | Settings related to the use and experience of using GitLab's Package Registry. Note there are [risks involved](../../packages/container_registry/index.md#use-with-external-container-registries) in enabling some of these settings. |
## Reporting
@@ -102,7 +102,7 @@ Access the default page for admin area settings by navigating to **Admin Area >
| Option | Description |
| ------ | ----------- |
| [Email](email.md) | Various email settings. |
-| [Help page](../../../customization/help_message.md) | Help page text and support page URL. |
+| [Help page](help_page.md) | Help page text and support page URL. |
| [Pages](../../../administration/pages/index.md#custom-domain-verification) | Size and domain settings for static websites |
| [Real-time features](../../../administration/polling.md) | Change this value to influence how frequently the GitLab UI polls for updates. |
| [Gitaly timeouts](gitaly_timeouts.md) | Configure Gitaly timeouts. |
diff --git a/doc/user/admin_area/settings/instance_template_repository.md b/doc/user/admin_area/settings/instance_template_repository.md
index 97380b93295..20f2812bc39 100644
--- a/doc/user/admin_area/settings/instance_template_repository.md
+++ b/doc/user/admin_area/settings/instance_template_repository.md
@@ -9,8 +9,6 @@ type: reference
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/5986) in [GitLab Premium](https://about.gitlab.com/pricing/) 11.3.
-## Overview
-
In hosted systems, enterprises often have a need to share their own templates
across teams. This feature allows an administrator to pick a project to be the
instance-wide collection of file templates. These templates are then exposed to
diff --git a/doc/user/admin_area/settings/project_integration_management.md b/doc/user/admin_area/settings/project_integration_management.md
index e4fe7e36139..748d608676d 100644
--- a/doc/user/admin_area/settings/project_integration_management.md
+++ b/doc/user/admin_area/settings/project_integration_management.md
@@ -4,38 +4,53 @@ group: Ecosystem
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/#designated-technical-writers
---
-# Project integration management **(CORE ONLY)**
+# Project integration management
-> [Introduced in](https://gitlab.com/groups/gitlab-org/-/epics/2137) GitLab 13.3.
+Project integrations can be configured and enabled by project administrators. As a GitLab instance
+administrator, you can set default configuration parameters for a given integration that all projects
+can inherit and use. This enables the integration for all projects that are not already using custom
+settings.
-Project integrations can be configured and enabled by project administrators. As a GitLab instance administrator, you can set default configuration parameters for a given integration that all projects can inherit and use, enabling the integration for all projects that are not already using custom settings.
+You can update these default settings at any time, changing the settings used for all projects that
+are set to use instance-level defaults. Updating the default settings also enables the integration
+for all projects that didn't have it already enabled.
-You can update these default settings at any time, changing the settings in use for all projects that are set to use instance-level defaults. This also enables the integration for all projects on which it was not already enabled.
+Only the complete settings for an integration can be inherited. Per-field inheritance is
+[planned](https://gitlab.com/groups/gitlab-org/-/epics/2137) as is
+[group-level management](https://gitlab.com/groups/gitlab-org/-/epics/2543) of integration settings.
-It is only possible to inherit the complete settings for an integration. Per-field inheritance is [planned](https://gitlab.com/groups/gitlab-org/-/epics/2137), as well as [group-level management](https://gitlab.com/groups/gitlab-org/-/epics/2543) of integration settings.
+## Manage instance-level default settings for a project integration **(CORE ONLY)**
-## Manage default settings for a project integration
+> [Introduced in](https://gitlab.com/groups/gitlab-org/-/epics/2137) GitLab 13.3.
1. Navigate to **Admin Area > Settings > Integrations**.
1. Select a project integration.
1. Enter configuration details and click **Save changes**.
CAUTION: **Caution:**
-This may affect all or most of the projects on your GitLab instance. Please review the details below.
+This may affect all or most of the projects on your GitLab instance. Please review the details
+below.
If this is the first time you are setting up instance-level settings for an integration:
-- The integration is enabled for all projects that do not already have this integration configured if you have the **Enable integration** toggle turned on in the instance-level settings.
-- Projects that already have the integration configured are not affected, but can choose to use the inherited settings at any time.
+- The integration is enabled for all projects that don't already have this integration configured,
+ if you have the **Enable integration** toggle turned on in the instance-level settings.
+- Projects that already have the integration configured are not affected, but can choose to use the
+ inherited settings at any time.
When you make further changes to the instance defaults:
-- They are immediately applied to all projects that have the integration set to use instance-level default settings.
-- They are immediately applied to newer projects, created since you last saved defaults for the integration.
- - If your instance-level default setting has the **Enable integration** toggle turned on, the integration is automatically enabled for all such projects.
-- Projects with custom settings selected for the integration are not immediately affected and may choose to use the latest instance-level defaults at any time.
+- They are immediately applied to all projects that have the integration set to use default settings.
+- They are immediately applied to newer projects, created since you last saved defaults for the
+ integration. If your instance-level default setting has the **Enable integration** toggle turned
+ on, the integration is automatically enabled for all such projects.
+- Projects with custom settings selected for the integration are not immediately affected and may
+ choose to use the latest defaults at any time.
-It is only possible to inherit the complete settings for an integration. Per-field inheritance is [planned](https://gitlab.com/groups/gitlab-org/-/epics/2137). This would allow instance administrators to update settings inherited by projects without enabling the integration on all non-configured projects by default.
+Only the complete settings for an integration can be inherited. Per-field inheritance
+is [planned](https://gitlab.com/groups/gitlab-org/-/epics/2137). This would allow
+administrators to update settings inherited by projects without enabling the
+integration on all non-configured projects by default.
## Use instance-level default settings for a project integration
@@ -47,7 +62,7 @@ It is only possible to inherit the complete settings for an integration. Per-fie
## Use custom settings for a project integration
-1. Navigate to **Project > Settings > Integrations**.
+1. Navigate to project's **Settings > Integrations**.
1. Choose the integration you want to enable or update.
1. From the drop-down, select **Use custom settings**.
1. Ensure the toggle is set to **Enable integration** and enter all required settings.
diff --git a/doc/user/admin_area/settings/sign_up_restrictions.md b/doc/user/admin_area/settings/sign_up_restrictions.md
index 80092102091..f57cf7c2045 100644
--- a/doc/user/admin_area/settings/sign_up_restrictions.md
+++ b/doc/user/admin_area/settings/sign_up_restrictions.md
@@ -7,6 +7,7 @@ type: reference
You can use sign-up restrictions to:
- Disable new sign-ups.
+- Require admin approval for new sign-ups.
- Require user email confirmation.
- Denylist or allowlist email addresses belonging to specific domains.
@@ -32,12 +33,20 @@ Alternatively, you could also consider setting up a
[allowlist](#allowlist-email-domains) or [denylist](#denylist-email-domains) on
email domains to prevent malicious users from creating accounts.
+## Require admin approval for new sign-ups
+
+> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/4491) in GitLab 13.5.
+
+When this setting is enabled, any user visiting your GitLab domain and signing up for a new account will have to be explicitly [approved](../approving_users.md#approving-a-user) by an administrator before they can start using their account.
+
+![Require admin approval for new signups](img/sign_up_restrictions_v13_5.png)
+
## Require email confirmation
You can send confirmation emails during sign-up and require that users confirm
their email address before they are allowed to sign in.
-![Email confirmation](img/email_confirmation_v12_7.png)
+![Email confirmation](img/sign_up_restrictions_v13_5.png)
## Minimum password length limit
diff --git a/doc/user/admin_area/settings/usage_statistics.md b/doc/user/admin_area/settings/usage_statistics.md
index 55bbcfbe1d8..140d149555a 100644
--- a/doc/user/admin_area/settings/usage_statistics.md
+++ b/doc/user/admin_area/settings/usage_statistics.md
@@ -58,7 +58,7 @@ sequenceDiagram
## Usage Ping **(CORE ONLY)**
-See [Usage Ping guide](../../../development/telemetry/usage_ping.md).
+See [Usage Ping guide](../../../development/product_analytics/usage_ping.md).
## Instance-level statistics **(CORE ONLY)**
diff --git a/doc/user/analytics/img/mr_throughput_chart_v13_3.png b/doc/user/analytics/img/mr_throughput_chart_v13_3.png
index 04fa54f323c..100c9a8557c 100644
--- a/doc/user/analytics/img/mr_throughput_chart_v13_3.png
+++ b/doc/user/analytics/img/mr_throughput_chart_v13_3.png
Binary files differ
diff --git a/doc/user/analytics/img/mr_throughput_table_v13_3.png b/doc/user/analytics/img/mr_throughput_table_v13_3.png
index 63ffb9389f4..bb63770dc3f 100644
--- a/doc/user/analytics/img/mr_throughput_table_v13_3.png
+++ b/doc/user/analytics/img/mr_throughput_table_v13_3.png
Binary files differ
diff --git a/doc/user/analytics/img/new_value_stream_v13_3.png b/doc/user/analytics/img/new_value_stream_v13_3.png
index 4284b8ab194..bc8502e85a6 100644
--- a/doc/user/analytics/img/new_value_stream_v13_3.png
+++ b/doc/user/analytics/img/new_value_stream_v13_3.png
Binary files differ
diff --git a/doc/user/analytics/img/vsa_filter_bar_v13.3.png b/doc/user/analytics/img/vsa_filter_bar_v13.3.png
index 71e59892434..506765f63cb 100644
--- a/doc/user/analytics/img/vsa_filter_bar_v13.3.png
+++ b/doc/user/analytics/img/vsa_filter_bar_v13.3.png
Binary files differ
diff --git a/doc/user/analytics/index.md b/doc/user/analytics/index.md
index 044b9eb3e64..54b4c702c5c 100644
--- a/doc/user/analytics/index.md
+++ b/doc/user/analytics/index.md
@@ -25,10 +25,8 @@ The following analytics features are available at the group level:
- [Contribution](../group/contribution_analytics/index.md). **(STARTER)**
- [Insights](../group/insights/index.md). **(ULTIMATE)**
- [Issue](../group/issues_analytics/index.md). **(PREMIUM)**
-- [Productivity](productivity_analytics.md), enabled with the `productivity_analytics`
- [feature flag](../../development/feature_flags/development.md#enabling-a-feature-flag-locally-in-development). **(PREMIUM)**
-- [Value Stream](value_stream_analytics.md), enabled with the `cycle_analytics`
- [feature flag](../../development/feature_flags/development.md#enabling-a-feature-flag-locally-in-development). **(PREMIUM)**
+- [Productivity](productivity_analytics.md) **(PREMIUM)**
+- [Value Stream](value_stream_analytics.md). **(PREMIUM)**
## Project-level analytics
@@ -40,6 +38,5 @@ The following analytics features are available at the project level:
- [Issue](../group/issues_analytics/index.md). **(PREMIUM)**
- [Merge Request](merge_request_analytics.md), enabled with the `project_merge_request_analytics`
[feature flag](../../development/feature_flags/development.md#enabling-a-feature-flag-locally-in-development). **(STARTER)**
-- [Repository](repository_analytics.md).
-- [Value Stream](value_stream_analytics.md), enabled with the `cycle_analytics`
- [feature flag](../../development/feature_flags/development.md#enabling-a-feature-flag-locally-in-development). **(STARTER)**
+- [Repository](repository_analytics.md). **(CORE)**
+- [Value Stream](value_stream_analytics.md). **(CORE)**
diff --git a/doc/user/analytics/merge_request_analytics.md b/doc/user/analytics/merge_request_analytics.md
index 6a18d46fd1a..04a5fa71e19 100644
--- a/doc/user/analytics/merge_request_analytics.md
+++ b/doc/user/analytics/merge_request_analytics.md
@@ -73,18 +73,3 @@ The **Merge Request Analytics** feature can be accessed only:
- On [Starter](https://about.gitlab.com/pricing/) and above.
- By users with [Reporter access](../permissions.md) and above.
-
-## Enable and disable related feature flags
-
-Merge Request Analytics is disabled by default but can be enabled using the following
-[feature flag](../../development/feature_flags/development.md#enabling-a-feature-flag-locally-in-development):
-
-- `project_merge_request_analytics`
-
-A GitLab administrator can:
-
-- Enable this feature by running the following command in a Rails console:
-
- ```ruby
- Feature.enable(:project_merge_request_analytics)
- ```
diff --git a/doc/user/analytics/productivity_analytics.md b/doc/user/analytics/productivity_analytics.md
index 653836de8be..951be1c550b 100644
--- a/doc/user/analytics/productivity_analytics.md
+++ b/doc/user/analytics/productivity_analytics.md
@@ -13,7 +13,7 @@ Track development velocity with Productivity Analytics.
For many companies, the development cycle is a black box and getting an estimate of how
long, on average, it takes to deliver features is an enormous endeavor.
-While [Value Stream Analytics](../project/cycle_analytics.md) focuses on the entire
+While [Value Stream Analytics](../analytics/value_stream_analytics.md) focuses on the entire
Software Development Life Cycle (SDLC) process, Productivity Analytics provides a way for Engineering Management to drill down in a systematic way to uncover patterns and causes for success or failure at an individual, project, or group level.
Productivity can slow down for many reasons ranging from degrading code base to quickly growing teams. In order to investigate, department or team leaders can start by visualizing the time it takes for merge requests to be merged.
@@ -62,29 +62,3 @@ The **Productivity Analytics** dashboard can be accessed only:
- On [Premium or Silver tier](https://about.gitlab.com/pricing/) and above.
- By users with [Reporter access](../permissions.md) and above.
-
-## Enabling and disabling using feature flags
-
-Productivity Analytics is:
-
-- [Enabled by default](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/18754) from GitLab 12.4,
- but can be disabled using the following feature flags:
- - `productivity_analytics`.
- - `productivity_analytics_scatterplot_enabled`.
-- Disabled by default in GitLab 12.3, but can be enabled using the following feature flag:
- - `productivity_analytics`.
-
-A GitLab administrator can:
-
-- Disable this feature from GitLab 12.4 by running the follow in a Rails console:
-
- ```ruby
- Feature.disable(:productivity_analytics)
- Feature.disable(:productivity_analytics_scatterplot_enabled)
- ```
-
-- Enable this feature in GitLab 12.3 by running the following in a Rails console:
-
- ```ruby
- Feature.enable(:productivity_analytics)
- ```
diff --git a/doc/user/analytics/value_stream_analytics.md b/doc/user/analytics/value_stream_analytics.md
index 14012d4a28d..86525587b30 100644
--- a/doc/user/analytics/value_stream_analytics.md
+++ b/doc/user/analytics/value_stream_analytics.md
@@ -12,26 +12,26 @@ info: To determine the technical writer assigned to the Stage/Group associated w
Value Stream Analytics measures the time spent to go from an
[idea to production](https://about.gitlab.com/blog/2016/08/05/continuous-integration-delivery-and-deployment-with-gitlab/#from-idea-to-production-with-gitlab)
-(also known as cycle time) for each of your projects. Value Stream Analytics displays the median time
+(also known as cycle time) for each of your projects or groups. Value Stream Analytics displays the median time
spent in each stage defined in the process.
-For information on how to contribute to the development of Value Stream Analytics, see our [contributor documentation](../../development/value_stream_analytics.md).
-
Value Stream Analytics is useful in order to quickly determine the velocity of a given
project. It points to bottlenecks in the development process, enabling management
to uncover, triage, and identify the root cause of slowdowns in the software development life cycle.
-Value Stream Analytics is tightly coupled with the [GitLab flow](../../topics/gitlab_flow.md) and
-calculates a separate median for each stage.
+For information on how to contribute to the development of Value Stream Analytics, see our [contributor documentation](../../development/value_stream_analytics.md).
+
+## Project Level Value Stream Analytics **(CORE)**
+
+Project Level Value Stream Analytics is available via **Project > Analytics > Value Stream**.
-## Overview
+## Group Level Value Stream Analytics **(PREMIUM)**
-Value Stream Analytics is available:
+From GitLab 12.9, group level Value Stream Analytics is available via **Group > Analytics > Value Stream**.
-- From GitLab 12.9, at the group level via **Group > Analytics > Value Stream**. **(PREMIUM)**
-- At the project level via **Project > Analytics > Value Stream**.
+## Default stages
-There are seven stages that are tracked as part of the Value Stream Analytics calculations.
+The stages tracked by Value Stream Analytics by default represent the [GitLab flow](../../topics/gitlab_flow.md). These stages can be customized in Group Level Value Stream Analytics.
- **Issue** (Tracker)
- Time to schedule an issue (by milestone or by adding it to an issue board)
@@ -96,8 +96,7 @@ Value Stream Analytics records stage time and data based on the project issues w
exception of the staging stage, where only data deployed to
production are measured.
-Specifically, if your CI is not set up and you have not defined a `production`
-or `production/*` [environment](../../ci/yaml/README.md#environment), then you will not have any
+Specifically, if your CI is not set up and you have not defined a [production environment](#how-the-production-environment-is-identified), then you will not have any
data for this stage.
Each stage of Value Stream Analytics is further described in the table below.
@@ -109,7 +108,7 @@ Each stage of Value Stream Analytics is further described in the table below.
| Code | Measures the median time between pushing a first commit (previous stage) and creating a merge request (MR) related to that commit. The key to keep the process tracked is to include the [issue closing pattern](../project/issues/managing_issues.md#closing-issues-automatically) to the description of the merge request (for example, `Closes #xxx`, where `xxx` is the number of the issue related to this merge request). If the issue closing pattern is not present in the merge request description, the MR is not considered to the measurement time of the stage. |
| Test | Measures the median time to run the entire pipeline for that project. It's related to the time GitLab CI/CD takes to run every job for the commits pushed to that merge request defined in the previous stage. It is basically the start->finish time for all pipelines. |
| Review | Measures the median time taken to review the merge request that has a closing issue pattern, between its creation and until it's merged. |
-| Staging | Measures the median time between merging the merge request with a closing issue pattern until the very first deployment to production. It's tracked by the environment set to `production` or matching `production/*` (case-sensitive, `Production` won't work) in your GitLab CI/CD configuration. If there isn't a production environment, this is not tracked. |
+| Staging | Measures the median time between merging the merge request with a closing issue pattern until the very first deployment to a [production environment](#how-the-production-environment-is-identified). If there isn't a production environment, this is not tracked. |
How this works, behind the scenes:
@@ -123,13 +122,23 @@ How this works, behind the scenes:
we need for the stages, like issue creation date, merge request merge time,
etc.
-To sum up, anything that doesn't follow [GitLab flow](../../workflow/gitlab_flow.md) will not be tracked and the
+To sum up, anything that doesn't follow [GitLab flow](../../topics/gitlab_flow.md) will not be tracked and the
Value Stream Analytics dashboard will not present any data for:
- Merge requests that do not close an issue.
- Issues not labeled with a label present in the Issue Board or for issues not assigned a milestone.
-- Staging stage, if the project has no `production` or `production/*`
- environment.
+- Staging stage, if the project has no [production environment](#how-the-production-environment-is-identified).
+
+## How the production environment is identified
+
+Value Stream Analytics identifies production environments by looking for project [environments](../../ci/yaml/README.md#environment) with a name matching any of these patterns:
+
+- `prod` or `prod/*`
+- `production` or `production/*`
+
+These patterns are not case-sensitive.
+
+You can change the name of a project environment in your GitLab CI/CD configuration.
## Example workflow
@@ -345,7 +354,7 @@ administrator can open a Rails console and disable it with the following command
Feature.disable(:cycle_analytics_scatterplot_enabled)
```
-## Type of work - Tasks by type chart **(PREMIUM)**
+## Type of work - Tasks by type chart
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/32421) in [GitLab Premium](https://about.gitlab.com/pricing/) 12.10.
@@ -368,11 +377,8 @@ The current permissions on the Project Value Stream Analytics dashboard are:
You can [read more about permissions](../../user/permissions.md) in general.
-For Value Stream Analytics functionality introduced in GitLab 12.3 and later:
-
-- Users must have Reporter access or above.
-- Features are available only on
- [Premium or Silver tiers](https://about.gitlab.com/pricing/) and above.
+For Value Stream Analytics functionality introduced in GitLab 12.3 and later,
+users must have Reporter access or above.
## More resources
diff --git a/doc/user/application_security/api_fuzzing/index.md b/doc/user/application_security/api_fuzzing/index.md
index ae22655e30b..145422f8736 100644
--- a/doc/user/application_security/api_fuzzing/index.md
+++ b/doc/user/application_security/api_fuzzing/index.md
@@ -8,8 +8,8 @@ type: reference, howto
# Web API Fuzz Testing **(ULTIMATE)**
You can add web API fuzzing to your [GitLab CI/CD](../../../ci/README.md)
-pipelines. This helps you discover bugs and potential security issues that other QA processes may miss.
-API fuzzing performs fuzz testing of API operation parameters.
+pipelines. This helps you discover bugs and potential security issues that other QA processes may miss.
+API fuzzing performs fuzz testing of API operation parameters.
Fuzz testing sets operation parameters to unexpected values in an effort to cause unexpected behavior and errors in the API backend.
We recommend that you use fuzz testing in addition to [GitLab Secure](../index.md)'s
@@ -443,7 +443,7 @@ Example usage for setting a single header:
```json
{
"headers": {
- "Authorization": "Bearer dXNlcm5hbWU6cGFzc3dvcmQ="
+ "Authorization": "Bearer dXNlcm5hbWU6cGFzc3dvcmQ="
}
}
```
@@ -453,7 +453,7 @@ Example usage for setting both a header and cookie:
```json
{
"headers": {
- "Authorization": "Bearer dXNlcm5hbWU6cGFzc3dvcmQ="
+ "Authorization": "Bearer dXNlcm5hbWU6cGFzc3dvcmQ="
},
"cookies": {
"flags": "677"
diff --git a/doc/user/application_security/configuration/index.md b/doc/user/application_security/configuration/index.md
index a6ad701360e..ead34ca227e 100644
--- a/doc/user/application_security/configuration/index.md
+++ b/doc/user/application_security/configuration/index.md
@@ -19,8 +19,9 @@ then in the left sidebar go to **Security & Compliance > Configuration**.
For each security control the page displays:
-- **Status** - Status of the security control: enabled, not enabled, or available.
-- **Manage** - A management option or a link to the documentation.
+- **Security Control:** Name, description, and a documentation link.
+- **Status:** The security control's status (enabled, not enabled, or available).
+- **Manage:** A management option or a documentation link.
## Status
@@ -29,12 +30,11 @@ The status of each security control is determined by the project's latest defaul
If a job with the expected security report artifact exists in the pipeline, the feature's status is
_enabled_.
-For SAST, click **View history** to see the `.gitlab-ci.yml` file’s history.
-
-NOTE: **Note:**
If the latest pipeline used [Auto DevOps](../../../topics/autodevops/index.md),
all security features are configured by default.
+For SAST, click **View history** to see the `.gitlab-ci.yml` file's history.
+
## Manage
You can configure the following security controls:
diff --git a/doc/user/application_security/container_scanning/index.md b/doc/user/application_security/container_scanning/index.md
index 880e5a3875a..9e7f98dd4fc 100644
--- a/doc/user/application_security/container_scanning/index.md
+++ b/doc/user/application_security/container_scanning/index.md
@@ -9,8 +9,6 @@ info: To determine the technical writer assigned to the Stage/Group associated w
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/3672) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 10.4.
-## Overview
-
Your application's Docker image may itself be based on Docker images that contain known
vulnerabilities. By including an extra job in your pipeline that scans for those vulnerabilities and
displays them in a merge request, you can use GitLab to audit your Docker-based apps.
@@ -19,7 +17,6 @@ By default, container scanning in GitLab is based on [Clair](https://github.com/
containers. [GitLab's Klar analyzer](https://gitlab.com/gitlab-org/security-products/analyzers/klar/)
scans the containers and serves as a wrapper for Clair.
-NOTE: **Note:**
To integrate security scanners other than Clair and Klar into GitLab, see
[Security scanner integration](../../../development/integrations/secure.md).
@@ -46,7 +43,7 @@ To enable container scanning in your pipeline, you need the following:
or [`kubernetes`](https://docs.gitlab.com/runner/install/kubernetes.html) executor.
- Docker `18.09.03` or higher installed on the same computer as the runner. If you're using the
shared runners on GitLab.com, then this is already the case.
-- [Build and push](../../packages/container_registry/index.md#container-registry-examples-with-gitlab-cicd)
+- [Build and push](../../packages/container_registry/index.md#build-and-push-by-using-gitlab-cicd)
your Docker image to your project's container registry. The name of the Docker image should use
the following [predefined environment variables](../../../ci/variables/predefined_variables.md):
@@ -65,7 +62,7 @@ To enable container scanning in your pipeline, you need the following:
variables:
IMAGE_TAG: $CI_REGISTRY_IMAGE/$CI_COMMIT_REF_SLUG:$CI_COMMIT_SHA
script:
- - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
+ - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
- docker build -t $IMAGE_TAG .
- docker push $IMAGE_TAG
```
@@ -119,7 +116,7 @@ build:
IMAGE: $CI_REGISTRY_IMAGE/$CI_COMMIT_REF_SLUG:$CI_COMMIT_SHA
script:
- docker info
- - docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY
+ - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
- docker build -t $IMAGE .
- docker push $IMAGE
@@ -219,14 +216,21 @@ To use container scanning in an offline environment, you need:
- GitLab Runner with the [`docker` or `kubernetes` executor](#requirements).
- To configure a local Docker container registry with copies of the container scanning [analyzer](https://gitlab.com/gitlab-org/security-products/analyzers/klar) images, found in the [container scanning container registry](https://gitlab.com/gitlab-org/security-products/analyzers/klar/container_registry).
-NOTE: **Note:**
-GitLab Runner has a [default `pull policy` of `always`](https://docs.gitlab.com/runner/executors/docker.html#using-the-always-pull-policy),
+Note that GitLab Runner has a [default `pull policy` of `always`](https://docs.gitlab.com/runner/executors/docker.html#using-the-always-pull-policy),
meaning the runner tries to pull Docker images from the GitLab container registry even if a local
copy is available. The GitLab Runner [`pull_policy` can be set to `if-not-present`](https://docs.gitlab.com/runner/executors/docker.html#using-the-if-not-present-pull-policy)
in an offline environment if you prefer using only locally available Docker images. However, we
recommend keeping the pull policy setting to `always` if not in an offline environment, as this
enables the use of updated scanners in your CI/CD pipelines.
+##### Support for Custom Certificate Authorities
+
+Support for custom certificate authorities was introduced in the following versions:
+
+| Analyzer | Version |
+| -------- | ------- |
+| `klar` | [v2.3.0](https://gitlab.com/gitlab-org/security-products/analyzers/klar/-/releases/v2.3.0) |
+
#### Make GitLab container scanning analyzer images available inside your Docker registry
For container scanning, import the following default images from `registry.gitlab.com` into your
@@ -287,7 +291,7 @@ build_latest_vulnerabilities:
script:
- docker pull arminc/clair-db:latest
- docker tag arminc/clair-db:latest $CI_REGISTRY/namespace/clair-vulnerabilities-db
- - docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY
+ - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
- docker push $CI_REGISTRY/namespace/clair-vulnerabilities-db
```
@@ -433,3 +437,7 @@ This is a result of a bug in Docker which is now [fixed](https://github.com/cont
To prevent the error, ensure the Docker version that the runner is using is
`18.09.03` or higher. For more information, see
[issue #10241](https://gitlab.com/gitlab-org/gitlab/-/issues/10241 "Investigate why Container Scanning is not working with NFS mounts").
+
+### Getting warning message `gl-container-scanning-report.json: no matching files`
+
+For information on this, see the [general Application Security troubleshooting section](../../../ci/pipelines/job_artifacts.md#error-message-no-files-to-upload).
diff --git a/doc/user/application_security/coverage_fuzzing/index.md b/doc/user/application_security/coverage_fuzzing/index.md
index dff71cb9445..9508407ccae 100644
--- a/doc/user/application_security/coverage_fuzzing/index.md
+++ b/doc/user/application_security/coverage_fuzzing/index.md
@@ -175,6 +175,52 @@ To use coverage fuzzing in an offline environment, follow these steps:
`NEW_URL_GITLAB_COV_FUZ` is the URL of the private `gitlab-cov-fuzz` clone that you set up in the
first step.
+### Continuous fuzzing (long-running async fuzzing jobs)
+
+It's also possible to run the fuzzing jobs longer and without blocking your main pipeline. This
+configuration uses the GitLab [parent-child pipelines](../../../ci/parent_child_pipelines.md).
+The full example is available in the [repository](https://gitlab.com/gitlab-org/security-products/demos/coverage-fuzzing/go-fuzzing-example/-/tree/continuous_fuzzing#running-go-fuzz-from-ci).
+This example uses Go, but is applicable for any other supported languages.
+
+The suggested workflow in this scenario is to have long-running, async fuzzing jobs on a
+main/development branch, and short, blocking sync fuzzing jobs on all other branches and MRs. This
+is a good way to balance the needs of letting a developer's per-commit pipeline complete quickly,
+and also giving the fuzzer a large amount of time to fully explore and test the app.
+
+Long-running fuzzing jobs are usually necessary for the coverage guided fuzzer to find deeper bugs
+in your latest code base. THe following is an example of what `.gitlab-ci.yml` looks like in this
+workflow (for the full example, see the [repository](https://gitlab.com/gitlab-org/security-products/demos/coverage-fuzzing/go-fuzzing-example/-/tree/continuous_fuzzing)):
+
+```yaml
+
+sync_fuzzing:
+ variables:
+ COVFUZZ_ADDITIONAL_ARGS: '-max_total_time=300'
+ trigger:
+ include: .covfuzz-ci.yml
+ strategy: depend
+ rules:
+ - if: $CI_COMMIT_BRANCH != 'continuous_fuzzing' && $CI_PIPELINE_SOURCE != 'merge_request_event'
+
+async_fuzzing:
+ variables:
+ COVFUZZ_ADDITIONAL_ARGS: '-max_total_time=3600'
+ trigger:
+ include: .covfuzz-ci.yml
+ rules:
+ - if: $CI_COMMIT_BRANCH == 'continuous_fuzzing' && $CI_PIPELINE_SOURCE != 'merge_request_event'
+```
+
+This essentially creates two steps:
+
+1. `sync_fuzzing`: Runs all your fuzz targets for a short period of time in a blocking
+ configuration. This finds simple bugs and allows you to be confident that your MRs aren't
+ introducing new bugs or causing old bugs to reappear.
+1. `async_fuzzing`: Runs on your branch and finds deep bugs in your code without blocking your
+ development cycle and MRs.
+
+The `covfuzz-ci.yml` is the same as that in the [original synchronous example](https://gitlab.com/gitlab-org/security-products/demos/coverage-fuzzing/go-fuzzing-example#running-go-fuzz-from-ci).
+
### Glossary
- Seed corpus: The set of test cases given as initial input to the fuzz target. This usually speeds
diff --git a/doc/user/application_security/dast/img/dast_v13_2.png b/doc/user/application_security/dast/img/dast_v13_2.png
deleted file mode 100644
index bbf7944eb40..00000000000
--- a/doc/user/application_security/dast/img/dast_v13_2.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/application_security/dast/img/dast_v13_4.png b/doc/user/application_security/dast/img/dast_v13_4.png
new file mode 100644
index 00000000000..d9c1d1b5c66
--- /dev/null
+++ b/doc/user/application_security/dast/img/dast_v13_4.png
Binary files differ
diff --git a/doc/user/application_security/dast/index.md b/doc/user/application_security/dast/index.md
index 73a8e727389..fffaf4ad26b 100644
--- a/doc/user/application_security/dast/index.md
+++ b/doc/user/application_security/dast/index.md
@@ -9,17 +9,17 @@ type: reference, howto
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/4348) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 10.4.
-NOTE: **Note:**
-The whitepaper ["A Seismic Shift in Application Security"](https://about.gitlab.com/resources/whitepaper-seismic-shift-application-security/)
-explains how **4 of the top 6 attacks were application based**. Download it
-to learn how to protect your organization.
-
Running [static checks](../sast/index.md) on your code is the first step to detect
vulnerabilities that can put the security of your code at risk. Yet, once
deployed, your application is exposed to a new category of possible attacks,
such as cross-site scripting or broken authentication flaws. This is where
Dynamic Application Security Testing (DAST) comes into place.
+NOTE: **Note:**
+The whitepaper ["A Seismic Shift in Application Security"](https://about.gitlab.com/resources/whitepaper-seismic-shift-application-security/)
+explains how 4 of the top 6 attacks were application based. Download it to learn how to protect your
+organization.
+
## Overview
If you're using [GitLab CI/CD](../../../ci/README.md), you can analyze your running web applications
@@ -32,11 +32,10 @@ provided by [Auto DevOps](../../../topics/autodevops/index.md).
GitLab checks the DAST report, compares the found vulnerabilities between the source and target
branches, and shows the information on the merge request.
-NOTE: **Note:**
-This comparison logic uses only the latest pipeline executed for the target branch's base commit.
-Running the pipeline on any other commit has no effect on the merge request.
+Note that this comparison logic uses only the latest pipeline executed for the target branch's base
+commit. Running the pipeline on any other commit has no effect on the merge request.
-![DAST Widget](img/dast_v13_2.png)
+![DAST Widget](img/dast_v13_4.png)
By clicking on one of the detected linked vulnerabilities, you can
see the details and the URL(s) affected.
@@ -53,12 +52,11 @@ However, DAST can be [configured](#full-scan)
to also perform an *active scan*: attack your application and produce a more extensive security report.
It can be very useful combined with [Review Apps](../../../ci/review_apps/index.md).
-NOTE: **Note:**
-A pipeline may consist of multiple jobs, including SAST and DAST scanning. If any
-job fails to finish for any reason, the security dashboard doesn't show DAST scanner
-output. For example, if the DAST job finishes but the SAST job fails, the security
-dashboard doesn't show DAST results. The analyzer outputs an
-[exit code](../../../development/integrations/secure.md#exit-code) on failure.
+Note that a pipeline may consist of multiple jobs, including SAST and DAST scanning. If any job
+fails to finish for any reason, the security dashboard doesn't show DAST scanner output. For
+example, if the DAST job finishes but the SAST job fails, the security dashboard doesn't show DAST
+results. On failure, the analyzer outputs an
+[exit code](../../../development/integrations/secure.md#exit-code).
## Use cases
@@ -206,8 +204,8 @@ variables:
DAST_FULL_SCAN_ENABLED: "true"
```
-NOTE: **Note:**
-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/).
+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/).
#### Domain validation
@@ -398,11 +396,9 @@ variables:
DAST_API_HOST_OVERRIDE: api-test.host.com
```
-NOTE: **Note:**
-Using a host override is ONLY supported when importing the API
-specification from a URL. It does not work and will be ignored when importing
-the specification from a file. This is due to a limitation in the ZAP OpenAPI
-extension.
+Note that using a host override is ONLY supported when importing the API specification from a URL.
+It doesn't work and is ignored when importing the specification from a file. This is due to a
+limitation in the ZAP OpenAPI extension.
#### Authentication using headers
@@ -427,7 +423,8 @@ A URL scan allows you to specify which parts of a website are scanned by DAST.
#### Define the URLs to scan
-To specify the paths to be scanned, add a comma-separated list of the paths to the `DAST_PATHS` environment variable. Note that you can only scan paths of a single host.
+To specify the paths to scan, add a comma-separated list of the paths to the `DAST_PATHS`
+environment variable. Note that you can only scan paths of a single host.
```yaml
include:
@@ -437,8 +434,10 @@ variables:
DAST_PATHS=/page1.html,/category1/page1.html,/page3.html
```
-NOTE: **Note:**
-`DAST_AUTH_EXCLUDE_URLS` are ignored when `DAST_PATHS` is set.
+When using `DAST_PATHS`, note the following:
+
+- The `DAST_PATHS` environment variable has a limit of about 130kb. If you have a list or paths
+ greater than this, you should create multiple DAST jobs and split the paths over each job.
#### Full Scan
@@ -590,8 +589,7 @@ To use DAST in an offline environment, you need:
[container image](https://gitlab.com/gitlab-org/security-products/dast), found in the
[DAST container registry](https://gitlab.com/gitlab-org/security-products/dast/container_registry).
-NOTE: **Note:**
-GitLab Runner has a [default `pull policy` of `always`](https://docs.gitlab.com/runner/executors/docker.html#using-the-always-pull-policy),
+Note that GitLab Runner has a [default `pull policy` of `always`](https://docs.gitlab.com/runner/executors/docker.html#using-the-always-pull-policy),
meaning the runner tries to pull Docker images from the GitLab container registry even if a local
copy is available. The GitLab Runner [`pull_policy` can be set to `if-not-present`](https://docs.gitlab.com/runner/executors/docker.html#using-the-if-not-present-pull-policy)
in an offline environment if you prefer using only locally available Docker images. However, we
@@ -672,11 +670,6 @@ To delete an existing site profile:
## Scanner profile
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/222767) in GitLab 13.4.
-> - [Deployed behind a feature flag](../../feature_flags.md), enabled by default.
-> - Enabled on GitLab.com.
-> - Can be enabled or disabled per-project.
-> - Recommended for production use.
-> - For GitLab self-managed instances, GitLab administrators can [disable this feature](#enable-or-disable-dast-scanner-profiles).
A scanner profile defines the scanner settings used to run an on-demand scan:
@@ -684,6 +677,11 @@ A scanner profile defines the scanner settings used to run an on-demand scan:
- **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.
+- **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.
+- **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.
+
+Scan mode, AJAX spider, Debug messages are [added in GitLab 13.5](https://gitlab.com/gitlab-org/gitlab/-/issues/225804)
### Create a scanner profile
@@ -711,29 +709,6 @@ To delete a scanner profile:
1. Click **Manage** in the **DAST Profiles** row.
1. Click **{remove}** in the scanner profile's row.
-### Enable or disable DAST scanner profiles
-
-The scanner profile feature is ready for production use. It's deployed behind a feature flag that
-is **enabled by default**. [GitLab administrators with access to the GitLab Rails console](../../../administration/feature_flags.md) can opt to disable it.
-
-To disable it:
-
-```ruby
-# Instance-wide
-Feature.disable(:security_on_demand_scans_scanner_profiles)
-# or by project
-Feature.disable(:security_on_demand_scans_scanner_profiles, Project.find(<project id>))
-```
-
-To enable it:
-
-```ruby
-# Instance-wide
-Feature.enable(:security_on_demand_scans_scanner_profiles)
-# or by project
-Feature.enable(:security_on_demand_scans_scanner_profiles, Project.find(<project ID>))
-```
-
## On-demand scans
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/218465) in GitLab 13.2.
@@ -756,7 +731,8 @@ An on-demand DAST scan:
NOTE: **Note:**
You must have permission to run an on-demand DAST scan against a protected branch.
-The default branch is automatically protected. For more details, see [Pipeline security on protected branches](../../../ci/pipelines/index.md#pipeline-security-on-protected-branches).
+The default branch is automatically protected. For more information, see
+[Pipeline security on protected branches](../../../ci/pipelines/index.md#pipeline-security-on-protected-branches).
To run an on-demand DAST scan, you need:
@@ -765,8 +741,8 @@ To run an on-demand DAST scan, you need:
1. From your project's home page, go to **Security & Compliance > On-demand Scans** in the left sidebar.
1. Click **Create new DAST scan**.
-1. In **Scanner settings**, select a scanner profile from the dropdown.
-1. In **Site profiles**, select a site profile from the dropdown.
+1. In **Scanner profile**, select a scanner profile from the dropdown.
+1. In **Site profile**, select a site profile from the dropdown.
1. Click **Run scan**.
The on-demand DAST scan runs and the project's dashboard shows the results.
@@ -866,7 +842,7 @@ include:
template: DAST.gitlab-ci.yml
variables:
- DAST_INCLUDE_ALPHA_VULNERABILITIES: true
+ DAST_INCLUDE_ALPHA_VULNERABILITIES: "true"
```
## Interacting with the vulnerabilities
@@ -923,6 +899,10 @@ Change the number after `-Xmx` to the required memory amount.
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/).
+### Getting warning message `gl-dast-report.json: no matching files`
+
+For information on this, see the [general Application Security troubleshooting section](../../../ci/pipelines/job_artifacts.md#error-message-no-files-to-upload).
+
<!-- ## Troubleshooting
Include any troubleshooting steps that you can foresee. If you know beforehand what issues
diff --git a/doc/user/application_security/dependency_scanning/index.md b/doc/user/application_security/dependency_scanning/index.md
index 5cce336d04c..b90bb37c60f 100644
--- a/doc/user/application_security/dependency_scanning/index.md
+++ b/doc/user/application_security/dependency_scanning/index.md
@@ -9,25 +9,26 @@ info: To determine the technical writer assigned to the Stage/Group associated w
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/5105) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 10.7.
-Dependency Scanning helps to find security vulnerabilities in your dependencies automatically
-while you're developing and testing your applications, such as when your
-application is using an external (open source) library that is known to be vulnerable.
+GitLab's Dependency Scanning feature can automatically find security vulnerabilities in your
+dependencies while you're developing and testing your applications. For example, dependency scanning
+lets you know if your application uses an external (open source) library that is known to be
+vulnerable. You can then take action to protect your application.
## Overview
-If you're using [GitLab CI/CD](../../../ci/README.md), you can analyze your dependencies for known
-vulnerabilities using Dependency Scanning.
-All dependencies are scanned, including the transitive dependencies (also known as nested dependencies).
-You can take advantage of Dependency Scanning by either [including the Dependency Scanning template](#configuration)
-in your existing `.gitlab-ci.yml` file or by implicitly using
-the [Auto Dependency Scanning](../../../topics/autodevops/stages.md#auto-dependency-scanning)
+If you're using [GitLab CI/CD](../../../ci/README.md), you can use dependency scanning to analyze
+your dependencies for known vulnerabilities. GitLab scans all dependencies, including transitive
+dependencies (also known as nested dependencies). You can take advantage of dependency scanning by
+either [including the dependency scanning template](#configuration)
+in your existing `.gitlab-ci.yml` file, or by implicitly using
+the [auto dependency scanning](../../../topics/autodevops/stages.md#auto-dependency-scanning)
provided by [Auto DevOps](../../../topics/autodevops/index.md).
-GitLab checks the Dependency Scanning report, compares the found vulnerabilities
+GitLab checks the dependency scanning report, compares the found vulnerabilities
between the source and target branches, and shows the information on the
merge request.
-![Dependency Scanning Widget](img/dependency_scanning_v13_2.png)
+![Dependency scanning Widget](img/dependency_scanning_v13_2.png)
The results are sorted by the severity of the vulnerability:
@@ -40,7 +41,7 @@ The results are sorted by the severity of the vulnerability:
## Requirements
-To run Dependency Scanning jobs, by default, you need GitLab Runner with the
+To run dependency 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.
@@ -56,24 +57,25 @@ The current detection logic limits the maximum search depth to two levels. For e
The following languages and dependency managers are supported:
-| Language (package managers) | Supported files | Scan tool(s) |
-|----------------------------- | --------------- | ------------ |
-| C# .NET ([NuGet](https://www.nuget.org/) 4.9+) | [`packages.lock.json`](https://docs.microsoft.com/en-us/nuget/consume-packages/package-references-in-project-files#enabling-lock-file) | [Gemnasium](https://gitlab.com/gitlab-org/security-products/gemnasium) |
-| C/C++ ([Conan](https://conan.io/)) | [`conan.lock`](https://docs.conan.io/en/latest/versioning/lockfiles.html) | [Gemnasium](https://gitlab.com/gitlab-org/security-products/gemnasium) |
-| Java ([Gradle](https://gradle.org/), [Maven](https://maven.apache.org/)) | `build.gradle`, `build.gradle.kts`, `pom.xml` | [Gemnasium](https://gitlab.com/gitlab-org/security-products/gemnasium) |
-| JavaScript ([npm](https://www.npmjs.com/), [yarn](https://classic.yarnpkg.com/en/)) | `package-lock.json`, `npm-shrinkwrap.json`, `yarn.lock` | [Gemnasium](https://gitlab.com/gitlab-org/security-products/gemnasium), [Retire.js](https://retirejs.github.io/retire.js/) |
-| Go ([Golang](https://golang.org/)) | `go.sum` | [Gemnasium](https://gitlab.com/gitlab-org/security-products/gemnasium) |
-| PHP ([Composer](https://getcomposer.org/)) | `composer.lock` | [Gemnasium](https://gitlab.com/gitlab-org/security-products/gemnasium) |
-| Python ([setuptools](https://setuptools.readthedocs.io/en/latest/), [pip](https://pip.pypa.io/en/stable/), [Pipenv](https://pipenv.pypa.io/en/latest/)) | `setup.py`, `requirements.txt`, `requirements.pip`, `requires.txt`, `Pipfile` | [Gemnasium](https://gitlab.com/gitlab-org/security-products/gemnasium) |
-| Ruby ([Bundler](https://bundler.io/)) | `Gemfile.lock`, `gems.locked` | [Gemnasium](https://gitlab.com/gitlab-org/security-products/gemnasium), [bundler-audit](https://github.com/rubysec/bundler-audit) |
-| Scala ([sbt](https://www.scala-sbt.org/)) | `build.sbt` | [Gemnasium](https://gitlab.com/gitlab-org/security-products/gemnasium) |
+| Package Managers | Languages | Supported files | Scan tools |
+| ------------------- | --------- | --------------- | ------------ |
+| [Bundler](https://bundler.io/) | Ruby | `Gemfile.lock`, `gems.locked` | [Gemnasium](https://gitlab.com/gitlab-org/security-products/gemnasium), [bundler-audit](https://github.com/rubysec/bundler-audit) |
+| [Composer](https://getcomposer.org/) | PHP | `composer.lock` | [Gemnasium](https://gitlab.com/gitlab-org/security-products/gemnasium) |
+| [Conan](https://conan.io/) | C, C++ | [`conan.lock`](https://docs.conan.io/en/latest/versioning/lockfiles.html) | [Gemnasium](https://gitlab.com/gitlab-org/security-products/gemnasium) |
+| [Golang](https://golang.org/) | Go | `go.sum` | [Gemnasium](https://gitlab.com/gitlab-org/security-products/gemnasium) |
+| [Gradle](https://gradle.org/), [Maven](https://maven.apache.org/) | Java | `build.gradle`, `build.gradle.kts`, `pom.xml` | [Gemnasium](https://gitlab.com/gitlab-org/security-products/gemnasium) |
+| [npm](https://www.npmjs.com/), [yarn](https://classic.yarnpkg.com/en/) | JavaScript | `package-lock.json`, `npm-shrinkwrap.json`, `yarn.lock` | [Gemnasium](https://gitlab.com/gitlab-org/security-products/gemnasium), [Retire.js](https://retirejs.github.io/retire.js/) |
+| [NuGet](https://www.nuget.org/) 4.9+ | .NET, C# | [`packages.lock.json`](https://docs.microsoft.com/en-us/nuget/consume-packages/package-references-in-project-files#enabling-lock-file) | [Gemnasium](https://gitlab.com/gitlab-org/security-products/gemnasium) |
+| [setuptools](https://setuptools.readthedocs.io/en/latest/), [pip](https://pip.pypa.io/en/stable/), [Pipenv](https://pipenv.pypa.io/en/latest/) | Python | `setup.py`, `requirements.txt`, `requirements.pip`, `requires.txt`, `Pipfile` | [Gemnasium](https://gitlab.com/gitlab-org/security-products/gemnasium) |
+| [sbt](https://www.scala-sbt.org/) 1.2 and below ([Ivy](http://ant.apache.org/ivy/)) | Scala | `build.sbt` | [Gemnasium](https://gitlab.com/gitlab-org/security-products/gemnasium) |
Plans are underway for supporting the following languages, dependency managers, and dependency files. For details, see the issue link for each.
-| Language (package managers) | Supported files | Scan tool(s) | Issue |
-|----------------------------- | --------------- | ------------ | ----- |
-| Python ([Poetry](https://python-poetry.org/)) | `poetry.lock` | [Gemnasium](https://gitlab.com/gitlab-org/security-products/gemnasium) | [GitLab#7006](https://gitlab.com/gitlab-org/gitlab/-/issues/7006) |
-| Python ([Pipenv](https://pipenv.pypa.io/en/latest/)) | `Pipfile.lock` | [Gemnasium](https://gitlab.com/gitlab-org/security-products/gemnasium) | [GitLab#11756](https://gitlab.com/gitlab-org/gitlab/-/issues/11756) |
+| Package Managers | Languages | Supported files | Scan tools |
+| ------------------- | --------- | --------------- | ------------ |
+| [Pipenv](https://pipenv.pypa.io/en/latest/) | Python | `Pipfile.lock` | [Gemnasium](https://gitlab.com/gitlab-org/security-products/gemnasium) | [GitLab#11756](https://gitlab.com/gitlab-org/gitlab/-/issues/11756) |
+| [Poetry](https://python-poetry.org/) | Python | `poetry.lock` | [Gemnasium](https://gitlab.com/gitlab-org/security-products/gemnasium) | [GitLab#7006](https://gitlab.com/gitlab-org/gitlab/-/issues/7006) |
+| [sbt](https://www.scala-sbt.org/) 1.3+ ([Coursier](https://get-coursier.io/))| Scala | `build.sbt` | [Gemnasium](https://gitlab.com/gitlab-org/security-products/gemnasium) | [GitLab#249526](https://gitlab.com/gitlab-org/gitlab/-/issues/249526) |
## Contribute your scanner
@@ -81,7 +83,7 @@ The [Security Scanner Integration](../../../development/integrations/secure.md)
## Configuration
-To enable Dependency Scanning for GitLab 11.9 and later, you must
+To enable dependency scanning for GitLab 11.9 and later, you must
[include](../../../ci/yaml/README.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)
that is provided as a part of your GitLab installation.
@@ -95,16 +97,16 @@ include:
- template: Dependency-Scanning.gitlab-ci.yml
```
-The included template creates Dependency Scanning jobs in your CI/CD
+The included template creates dependency scanning jobs in your CI/CD
pipeline and scans your project's source code for possible vulnerabilities.
The results are saved as a
-[Dependency Scanning report artifact](../../../ci/pipelines/job_artifacts.md#artifactsreportsdependency_scanning)
+[dependency scanning report artifact](../../../ci/pipelines/job_artifacts.md#artifactsreportsdependency_scanning)
that you can later download and analyze. Due to implementation limitations, we
-always take the latest Dependency Scanning artifact available.
+always take the latest dependency scanning artifact available.
-### Customizing the Dependency Scanning settings
+### Customizing the dependency scanning settings
-The Dependency Scanning settings can be changed through [environment variables](#available-variables) by using the
+The dependency scanning settings can be changed through [environment variables](#available-variables) by using the
[`variables`](../../../ci/yaml/README.md#variables) parameter in `.gitlab-ci.yml`.
For example:
@@ -119,7 +121,7 @@ variables:
Because template is [evaluated before](../../../ci/yaml/README.md#include) the pipeline
configuration, the last mention of the variable takes precedence.
-### Overriding Dependency Scanning jobs
+### Overriding dependency scanning jobs
CAUTION: **Deprecation:**
Beginning in GitLab 13.0, the use of [`only` and `except`](../../../ci/yaml/README.md#onlyexcept-basic)
@@ -141,10 +143,10 @@ gemnasium-dependency_scanning:
### Available variables
-Dependency Scanning can be [configured](#customizing-the-dependency-scanning-settings)
+Dependency scanning can be [configured](#customizing-the-dependency-scanning-settings)
using environment variables.
-#### Configuring Dependency Scanning
+#### Configuring dependency scanning
The following variables allow configuration of global dependency scanning settings.
@@ -156,7 +158,7 @@ The following variables allow configuration of global dependency scanning settin
| `DS_EXCLUDED_PATHS` | Exclude vulnerabilities from output based on the paths. A comma-separated list of patterns. Patterns can be globs, or file or folder paths (for example, `doc,spec`). Parent directories also match patterns. Default: `"spec, test, tests, tmp"` |
| `SECURE_LOG_LEVEL` | Set the minimum logging level. Messages of this logging level or higher are output. From highest to lowest severity, the logging levels are: `fatal`, `error`, `warn`, `info`, `debug`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/10880) in GitLab 13.1. Default: `info` |
-#### Configuring specific analyzers used by Dependency Scanning
+#### Configuring specific analyzers used by dependency scanning
The following variables are used for configuring specific analyzers (used for a specific language/framework).
@@ -176,7 +178,7 @@ The following variables are used for configuring specific analyzers (used for a
| `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-repos). |
| `GRADLE_CLI_OPTS` | `gemnasium-maven` | | List of command line arguments that are passed to `gradle` by the analyzer. |
| `SBT_CLI_OPTS` | `gemnasium-maven` | | List of command-line arguments that the analyzer passes to `sbt`. |
-| `BUNDLER_AUDIT_UPDATE_DISABLED` | `bundler-audit` | `"false"` | Disable automatic updates for the `bundler-audit` analyzer. Useful if you're running Dependency Scanning in an offline, air-gapped environment.|
+| `BUNDLER_AUDIT_UPDATE_DISABLED` | `bundler-audit` | `"false"` | Disable automatic updates for the `bundler-audit` analyzer. Useful if you're running dependency scanning in an offline, air-gapped environment.|
| `BUNDLER_AUDIT_ADVISORY_DB_URL` | `bundler-audit` | `https://github.com/rubysec/ruby-advisory-db` | URL of the advisory database used by bundler-audit. |
| `BUNDLER_AUDIT_ADVISORY_DB_REF_NAME` | `bundler-audit` | `master` | Git ref for the advisory database specified by `BUNDLER_AUDIT_ADVISORY_DB_URL`. |
| `RETIREJS_JS_ADVISORY_DB` | `retire.js` | `https://raw.githubusercontent.com/RetireJS/retire.js/master/repository/jsrepository.json` | Path or URL to `retire.js` JS vulnerability data file. Note that if the URL hosting the data file uses a custom SSL certificate, for example in an offline installation, you can pass the certificate in the `ADDITIONAL_CA_CERT_BUNDLE` environment variable. |
@@ -214,16 +216,16 @@ For more information about the vulnerabilities database update, check the
## Dependency List
-An additional benefit of Dependency Scanning is the ability to view your
+An additional benefit of dependency scanning is the ability to view your
project's dependencies and their known vulnerabilities. Read more about
the [Dependency List](../dependency_list/index.md).
## Reports JSON format
-The Dependency Scanning tool emits a JSON report file. For more information, see the
+The dependency scanning tool emits a JSON report file. For more information, see the
[schema for this report](https://gitlab.com/gitlab-org/security-products/security-report-schemas/-/blob/master/dist/dependency-scanning-report-format.json).
-Here's an example Dependency Scanning report:
+Here's an example dependency scanning report:
```json-doc
{
@@ -342,36 +344,35 @@ You can search the [gemnasium-db](https://gitlab.com/gitlab-org/security-product
to find a vulnerability in the Gemnasium database.
You can also [submit new vulnerabilities](https://gitlab.com/gitlab-org/security-products/gemnasium-db/blob/master/CONTRIBUTING.md).
-## Running Dependency Scanning in an offline environment
+## Running dependency scanning in an offline environment
For self-managed GitLab instances in an environment with limited, restricted, or intermittent access
-to external resources through the internet, some adjustments are required for Dependency Scanning
+to external resources through the internet, some adjustments are required for dependency scanning
jobs to run successfully. For more information, see [Offline environments](../offline_deployments/index.md).
-### Requirements for offline Dependency Scanning
+### Requirements for offline dependency scanning
-Here are the requirements for using Dependency Scanning in an offline environment:
+Here are the requirements for using dependency scanning in an offline environment:
- GitLab Runner with the [`docker` or `kubernetes` executor](#requirements).
-- Docker Container Registry with locally available copies of Dependency Scanning [analyzer](https://gitlab.com/gitlab-org/security-products/analyzers) images.
+- Docker Container Registry with locally available copies of dependency scanning [analyzer](https://gitlab.com/gitlab-org/security-products/analyzers) images.
- Host an offline Git copy of the [gemnasium-db advisory database](https://gitlab.com/gitlab-org/security-products/gemnasium-db/).
This is required because, in an offline environment, the Gemnasium analyzer can't fetch the latest
advisories from the online repository.
- _Only if scanning Ruby projects_: Host an offline Git copy of the [advisory database](https://github.com/rubysec/ruby-advisory-db).
- _Only if scanning npm/yarn projects_: Host an offline copy of the [retire.js](https://github.com/RetireJS/retire.js/) [node](https://github.com/RetireJS/retire.js/blob/master/repository/npmrepository.json) and [js](https://github.com/RetireJS/retire.js/blob/master/repository/jsrepository.json) advisory databases.
-NOTE: **Note:**
-GitLab Runner has a [default `pull policy` of `always`](https://docs.gitlab.com/runner/executors/docker.html#using-the-always-pull-policy),
+Note that GitLab Runner has a [default `pull policy` of `always`](https://docs.gitlab.com/runner/executors/docker.html#using-the-always-pull-policy),
meaning the runner tries to pull Docker images from the GitLab container registry even if a local
copy is available. The GitLab Runner [`pull_policy` can be set to `if-not-present`](https://docs.gitlab.com/runner/executors/docker.html#using-the-if-not-present-pull-policy)
in an offline environment if you prefer using only locally available Docker images. However, we
recommend keeping the pull policy setting to `always` if not in an offline environment, as this
enables the use of updated scanners in your CI/CD pipelines.
-### Make GitLab Dependency Scanning analyzer images available inside your Docker registry
+### Make GitLab dependency scanning analyzer images available inside your Docker registry
-For Dependency Scanning with all [supported languages and frameworks](#supported-languages-and-package-managers),
-import the following default Dependency Scanning analyzer images from `registry.gitlab.com` into
+For dependency scanning with all [supported languages and frameworks](#supported-languages-and-package-managers),
+import the following default dependency scanning analyzer images from `registry.gitlab.com` into
your [local Docker container registry](../../packages/container_registry/index.md):
```plaintext
@@ -392,7 +393,19 @@ For details on saving and transporting Docker images as a file, see Docker's doc
[`docker save`](https://docs.docker.com/engine/reference/commandline/save/), [`docker load`](https://docs.docker.com/engine/reference/commandline/load/),
[`docker export`](https://docs.docker.com/engine/reference/commandline/export/), and [`docker import`](https://docs.docker.com/engine/reference/commandline/import/).
-### Set Dependency Scanning CI job variables to use local Dependency Scanning analyzers
+#### Support for Custom Certificate Authorities
+
+Support for custom certificate authorities was introduced in the following versions.
+
+| Analyzer | Version |
+| -------- | ------- |
+| `gemnasium` | [v2.8.0](https://gitlab.com/gitlab-org/security-products/analyzers/gemnasium/-/releases/v2.8.0) |
+| `gemnasium-maven` | [v2.9.0](https://gitlab.com/gitlab-org/security-products/analyzers/gemnasium-maven/-/releases/v2.9.0) |
+| `gemnasium-python` | [v2.7.0](https://gitlab.com/gitlab-org/security-products/analyzers/gemnasium-python/-/releases/v2.7.0) |
+| `retire.js` | [v2.4.0](https://gitlab.com/gitlab-org/security-products/analyzers/retire.js/-/releases/v2.4.0) |
+| `bundler-audit` | [v2.4.0](https://gitlab.com/gitlab-org/security-products/analyzers/bundler-audit/-/releases/v2.4.0) |
+
+### Set dependency scanning CI job variables to use local dependency scanning analyzers
Add the following configuration to your `.gitlab-ci.yml` file. You must change the value of
`SECURE_ANALYZERS_PREFIX` to refer to your local Docker container registry. You must also change the
@@ -479,7 +492,19 @@ As a workaround, remove the [`retire.js`](analyzers.md#selecting-specific-analyz
### `Error response from daemon: error processing tar file: docker-tar: relocation error`
-This error occurs when the Docker version that runs the Dependency Scanning job is `19.03.00`.
+This error occurs when the Docker version that runs the dependency scanning job is `19.03.00`.
Consider updating to Docker `19.03.1` or greater. Older versions are not
affected. Read more in
[this issue](https://gitlab.com/gitlab-org/gitlab/-/issues/13830#note_211354992 "Current SAST container fails").
+
+### Getting warning message `gl-dependency-scanning-report.json: no matching files`
+
+For information on this, see the [general Application Security troubleshooting section](../../../ci/pipelines/job_artifacts.md#error-message-no-files-to-upload).
+
+### Limitation when using rules:exists
+
+The [dependency scanning CI template](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Security/Dependency-Scanning.gitlab-ci.yml)
+uses the [`rules:exists`](../../../ci/yaml/README.md#rulesexists)
+syntax. This directive is limited to 10000 checks and always returns `true` after reaching this
+number. Because of this, and depending on the number of files in your repository, a dependency
+scanning job might be triggered even if the scanner doesn't support your project.
diff --git a/doc/user/application_security/img/cve_request_communication.png b/doc/user/application_security/img/cve_request_communication.png
index 0766b371c11..5c58df463ef 100644
--- a/doc/user/application_security/img/cve_request_communication.png
+++ b/doc/user/application_security/img/cve_request_communication.png
Binary files differ
diff --git a/doc/user/application_security/img/cve_request_communication_publication.png b/doc/user/application_security/img/cve_request_communication_publication.png
index 9e34c217e13..9eb6f2f8d9f 100644
--- a/doc/user/application_security/img/cve_request_communication_publication.png
+++ b/doc/user/application_security/img/cve_request_communication_publication.png
Binary files differ
diff --git a/doc/user/application_security/img/new_cve_request_issue.png b/doc/user/application_security/img/new_cve_request_issue.png
index a342c73992e..6ea7ca4a2ab 100644
--- a/doc/user/application_security/img/new_cve_request_issue.png
+++ b/doc/user/application_security/img/new_cve_request_issue.png
Binary files differ
diff --git a/doc/user/application_security/img/unconfigured_security_approval_rules_and_enabled_jobs_v13_4.png b/doc/user/application_security/img/unconfigured_security_approval_rules_and_enabled_jobs_v13_4.png
index f497b0fbc4e..7b04988afdb 100644
--- a/doc/user/application_security/img/unconfigured_security_approval_rules_and_enabled_jobs_v13_4.png
+++ b/doc/user/application_security/img/unconfigured_security_approval_rules_and_enabled_jobs_v13_4.png
Binary files differ
diff --git a/doc/user/application_security/img/unconfigured_security_approval_rules_and_jobs_v13_4.png b/doc/user/application_security/img/unconfigured_security_approval_rules_and_jobs_v13_4.png
index fc847b578f5..b9b6dd13294 100644
--- a/doc/user/application_security/img/unconfigured_security_approval_rules_and_jobs_v13_4.png
+++ b/doc/user/application_security/img/unconfigured_security_approval_rules_and_jobs_v13_4.png
Binary files differ
diff --git a/doc/user/application_security/img/vulnerability-check_v13_4.png b/doc/user/application_security/img/vulnerability-check_v13_4.png
index e0b53059b45..3e38f6eebe7 100644
--- a/doc/user/application_security/img/vulnerability-check_v13_4.png
+++ b/doc/user/application_security/img/vulnerability-check_v13_4.png
Binary files differ
diff --git a/doc/user/application_security/img/vulnerability_solution.png b/doc/user/application_security/img/vulnerability_solution.png
index d86b89a5f99..63e9c1473b6 100644
--- a/doc/user/application_security/img/vulnerability_solution.png
+++ b/doc/user/application_security/img/vulnerability_solution.png
Binary files differ
diff --git a/doc/user/application_security/index.md b/doc/user/application_security/index.md
index d509176f2b2..413a9f894e2 100644
--- a/doc/user/application_security/index.md
+++ b/doc/user/application_security/index.md
@@ -22,10 +22,10 @@ Testing (SAST), and Secret Detection by adding the following to your `.gitlab-ci
```yaml
include:
- - template: Dependency-Scanning.gitlab-ci.yml
- - template: License-Scanning.gitlab-ci.yml
- - template: SAST.gitlab-ci.yml
- - template: Secret-Detection.gitlab-ci.yml
+ - template: Security/Dependency-Scanning.gitlab-ci.yml
+ - template: Security/License-Scanning.gitlab-ci.yml
+ - template: Security/SAST.gitlab-ci.yml
+ - template: Security/Secret-Detection.gitlab-ci.yml
```
To add Dynamic Application Security Testing (DAST) scanning, add the following to your
@@ -33,7 +33,7 @@ To add Dynamic Application Security Testing (DAST) scanning, add the following t
```yaml
include:
- - template: DAST.gitlab-ci.yml
+ - template: Security/DAST.gitlab-ci.yml
variables:
DAST_WEBSITE: https://staging.example.com
@@ -449,7 +449,7 @@ To fix this issue, you can either:
```yaml
include:
- template: SAST.gitlab-ci.yml
+ template: Security/SAST.gitlab-ci.yml
spotbugs-sast:
stage: unit-tests
@@ -458,6 +458,15 @@ To fix this issue, you can either:
[Learn more on overriding SAST jobs](sast/index.md#overriding-sast-jobs).
All the security scanning tools define their stage, so this error can occur with all of them.
+### Getting warning messages `… report.json: no matching files`
+
+This is often followed by the [error `No files to upload`](../../ci/pipelines/job_artifacts.md#error-message-no-files-to-upload),
+and preceded by other errors or warnings that indicate why the JSON report wasn't generated. Please
+check the entire job log for such messages. If you don't find these messages, retry the failed job
+after setting `SECURE_LOG_LEVEL: "debug"` as a
+[custom environment variable](../../ci/variables/README.md#custom-environment-variables).
+This provides useful information to investigate further.
+
### Getting error message `sast job: config key may not be used with 'rules': only/except`
When [including](../../ci/yaml/README.md#includetemplate) a `.gitlab-ci.yml` template
@@ -490,7 +499,7 @@ would look similar to:
```yaml
include:
- - template: SAST.gitlab-ci.yml
+ - template: Security/SAST.gitlab-ci.yml
# Ensure that the scanning is only executed on master or merge requests
spotbugs-sast:
@@ -505,7 +514,7 @@ would be written as follows:
```yaml
include:
- - template: SAST.gitlab-ci.yml
+ - template: Security/SAST.gitlab-ci.yml
# Ensure that the scanning is only executed on master or merge requests
spotbugs-sast:
@@ -519,7 +528,7 @@ it would look similar to:
```yaml
include:
- - template: SAST.gitlab-ci.yml
+ - template: Security/SAST.gitlab-ci.yml
# Ensure that the scanning is not executed on tags
spotbugs-sast:
@@ -531,7 +540,7 @@ To transition to the new `rules` syntax, the override would be rewritten as:
```yaml
include:
- - template: SAST.gitlab-ci.yml
+ - template: Security/SAST.gitlab-ci.yml
# Ensure that the scanning is not executed on tags
spotbugs-sast:
diff --git a/doc/user/application_security/sast/analyzers.md b/doc/user/application_security/sast/analyzers.md
index 727f077aa09..6167c0445f9 100644
--- a/doc/user/application_security/sast/analyzers.md
+++ b/doc/user/application_security/sast/analyzers.md
@@ -25,6 +25,7 @@ SAST supports the following official analyzers:
- [`flawfinder`](https://gitlab.com/gitlab-org/security-products/analyzers/flawfinder) (Flawfinder)
- [`gosec`](https://gitlab.com/gitlab-org/security-products/analyzers/gosec) (Gosec)
- [`kubesec`](https://gitlab.com/gitlab-org/security-products/analyzers/kubesec) (Kubesec)
+- [`mobsf`](https://gitlab.com/gitlab-org/security-products/analyzers/mobsf) (MobSF (beta))
- [`nodejs-scan`](https://gitlab.com/gitlab-org/security-products/analyzers/nodejs-scan) (NodeJsScan)
- [`phpcs-security-audit`](https://gitlab.com/gitlab-org/security-products/analyzers/phpcs-security-audit) (PHP CS security-audit)
- [`pmd-apex`](https://gitlab.com/gitlab-org/security-products/analyzers/pmd-apex) (PMD (Apex only))
@@ -53,7 +54,7 @@ In `.gitlab-ci.yml` define:
```yaml
include:
- - template: SAST.gitlab-ci.yml
+ - template: Security/SAST.gitlab-ci.yml
variables:
SECURE_ANALYZERS_PREFIX: my-docker-registry/gl-images
@@ -70,7 +71,7 @@ In `.gitlab-ci.yml` define:
```yaml
include:
- - template: SAST.gitlab-ci.yml
+ - template: Security/SAST.gitlab-ci.yml
variables:
SAST_DEFAULT_ANALYZERS: "bandit,flawfinder"
@@ -86,7 +87,7 @@ default analyzers. In `.gitlab-ci.yml` define:
```yaml
include:
- - template: SAST.gitlab-ci.yml
+ - template: Security/SAST.gitlab-ci.yml
variables:
SAST_DEFAULT_ANALYZERS: ""
@@ -118,24 +119,24 @@ The [Security Scanner Integration](../../../development/integrations/secure.md)
## Analyzers Data
-| Property / Tool | Apex | Bandit | Brakeman | ESLint security | SpotBugs | Flawfinder | Gosec | Kubesec Scanner | NodeJsScan | PHP CS Security Audit | Security code Scan (.NET) | Sobelow |
-| --------------------------------------- | :------------------: | :------------------: | :------------------: | :------------------: | :------------------: | :------------------: | :------------------: | :------------------: | :------------------: | :---------------------: | :-------------------------: | :----------------: |
-| Severity | ✓ | ✓ | ð„‚ | ð„‚ | ✓ | ✓ | ✓ | ✓ | ð„‚ | ✓ | ð„‚ | ð„‚ |
-| Title | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
-| Description | ✓ | ð„‚ | ð„‚ | ✓ | ✓ | ð„‚ | ð„‚ | ✓ | ✓ | ð„‚ | ð„‚ | ✓ |
-| File | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
-| Start line | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ð„‚ | ✓ | ✓ | ✓ | ✓ |
-| End line | ✓ | ✓ | ð„‚ | ✓ | ✓ | ð„‚ | ð„‚ | ð„‚ | ð„‚ | ð„‚ | ð„‚ | ð„‚ |
-| Start column | ✓ | ð„‚ | ð„‚ | ✓ | ✓ | ✓ | ✓ | ð„‚ | ð„‚ | ✓ | ✓ | ð„‚ |
-| End column | ✓ | ð„‚ | ð„‚ | ✓ | ✓ | ð„‚ | ð„‚ | ð„‚ | ð„‚ | ð„‚ | ð„‚ | ð„‚ |
-| External ID (e.g. CVE) | ð„‚ | ð„‚ | âš  | ð„‚ | âš  | ✓ | ð„‚ | ð„‚ | ð„‚ | ð„‚ | ð„‚ | ð„‚ |
-| URLs | ✓ | ð„‚ | ✓ | ð„‚ | âš  | ð„‚ | âš  | ð„‚ | ð„‚ | ð„‚ | ð„‚ | ð„‚ |
-| Internal doc/explanation | ✓ | âš  | ✓ | ð„‚ | ✓ | ð„‚ | ð„‚ | ð„‚ | ð„‚ | ð„‚ | ð„‚ | ✓ |
-| Solution | ✓ | ð„‚ | ð„‚ | ð„‚ | âš  | ✓ | ð„‚ | ð„‚ | ð„‚ | ð„‚ | ð„‚ | ð„‚ |
-| Affected item (e.g. class or package) | ✓ | ð„‚ | ✓ | ð„‚ | ✓ | ✓ | ð„‚ | ✓ | ð„‚ | ð„‚ | ð„‚ | ð„‚ |
-| Confidence | ð„‚ | ✓ | ✓ | ð„‚ | ✓ | x | ✓ | ✓ | ð„‚ | ð„‚ | ð„‚ | ✓ |
-| Source code extract | ð„‚ | ✓ | ✓ | ✓ | ð„‚ | ✓ | ✓ | ð„‚ | ð„‚ | ð„‚ | ð„‚ | ð„‚ |
-| Internal ID | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ð„‚ | ð„‚ | ✓ | ✓ | ✓ |
+| Property / Tool | Apex | Bandit | Brakeman | ESLint security | SpotBugs | Flawfinder | Gosec | Kubesec Scanner | MobSF | NodeJsScan | PHP CS Security Audit | Security code Scan (.NET) | Sobelow |
+| --------------------------------------- | :------------------: | :------------------: | :------------------: | :------------------: | :------------------: | :------------------: | :------------------: | :------------------: | :------------------: | :------------------: | :---------------------: | :-------------------------: | :----------------: |
+| Severity | ✓ | ✓ | ð„‚ | ð„‚ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ð„‚ | ð„‚ |
+| Title | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| Description | ✓ | ð„‚ | ð„‚ | ✓ | ✓ | ð„‚ | ð„‚ | ✓ | ✓ | ✓ | ð„‚ | ð„‚ | ✓ |
+| File | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| Start line | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ð„‚ | ✓ | ✓ | ✓ | ✓ | ✓ |
+| End line | ✓ | ✓ | ð„‚ | ✓ | ✓ | ð„‚ | ð„‚ | ð„‚ | ð„‚ | ð„‚ | ð„‚ | ð„‚ | ð„‚ |
+| Start column | ✓ | ð„‚ | ð„‚ | ✓ | ✓ | ✓ | ✓ | ð„‚ | ð„‚ | ð„‚ | ✓ | ✓ | ð„‚ |
+| End column | ✓ | ð„‚ | ð„‚ | ✓ | ✓ | ð„‚ | ð„‚ | ð„‚ | ð„‚ | ð„‚ | ð„‚ | ð„‚ | ð„‚ |
+| External ID (e.g. CVE) | ð„‚ | ð„‚ | âš  | ð„‚ | âš  | ✓ | ð„‚ | ð„‚ | ð„‚ | ð„‚ | ð„‚ | ð„‚ | ð„‚ |
+| URLs | ✓ | ð„‚ | ✓ | ð„‚ | âš  | ð„‚ | âš  | ð„‚ | ð„‚ | ð„‚ | ð„‚ | ð„‚ | ð„‚ |
+| Internal doc/explanation | ✓ | âš  | ✓ | ð„‚ | ✓ | ð„‚ | ð„‚ | ð„‚ | ð„‚ | ð„‚ | ð„‚ | ð„‚ | ✓ |
+| Solution | ✓ | ð„‚ | ð„‚ | ð„‚ | âš  | ✓ | ð„‚ | ð„‚ | ð„‚ | ð„‚ | ð„‚ | ð„‚ | ð„‚ |
+| Affected item (e.g. class or package) | ✓ | ð„‚ | ✓ | ð„‚ | ✓ | ✓ | ð„‚ | ✓ | ð„‚ | ð„‚ | ð„‚ | ð„‚ | ð„‚ |
+| Confidence | ð„‚ | ✓ | ✓ | ð„‚ | ✓ | x | ✓ | ✓ | ð„‚ | ð„‚ | ð„‚ | ð„‚ | ✓ |
+| Source code extract | ð„‚ | ✓ | ✓ | ✓ | ð„‚ | ✓ | ✓ | ð„‚ | ð„‚ | ð„‚ | ð„‚ | ð„‚ | ð„‚ |
+| Internal ID | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ð„‚ | ð„‚ | ð„‚ | ✓ | ✓ | ✓ |
- ✓ => we have that data
- âš  => we have that data but it's partially reliable, or we need to extract it from unstructured content
diff --git a/doc/user/application_security/sast/index.md b/doc/user/application_security/sast/index.md
index a4fc3c9e638..9e4d4112ae8 100644
--- a/doc/user/application_security/sast/index.md
+++ b/doc/user/application_security/sast/index.md
@@ -11,8 +11,8 @@ type: reference, howto
NOTE: **Note:**
The whitepaper ["A Seismic Shift in Application Security"](https://about.gitlab.com/resources/whitepaper-seismic-shift-application-security/)
-explains how **4 of the top 6 attacks were application based**. Download it
-to learn how to protect your organization.
+explains how 4 of the top 6 attacks were application based. Download it to learn how to protect your
+organization.
If you're using [GitLab CI/CD](../../../ci/README.md), you can analyze your source code for known
vulnerabilities using Static Application Security Testing (SAST). GitLab checks the SAST report and
@@ -31,8 +31,10 @@ The results are sorted by the priority of the vulnerability:
1. Unknown
1. Everything else
-NOTE: **Note:**
-A pipeline consists of multiple jobs, including SAST and DAST scanning. If any job fails to finish for any reason, the security dashboard doesn't show SAST scanner output. For example, if the SAST job finishes but the DAST job fails, the security dashboard doesn't show SAST results. The analyzer outputs an [exit code](../../../development/integrations/secure.md#exit-code) on failure.
+A pipeline consists of multiple jobs, including SAST and DAST scanning. If any job fails to finish
+for any reason, the security dashboard doesn't show SAST scanner output. For example, if the SAST
+job finishes but the DAST job fails, the security dashboard doesn't show SAST results. On failure,
+the analyzer outputs an [exit code](../../../development/integrations/secure.md#exit-code).
## Use cases
@@ -59,39 +61,41 @@ is **not** `19.03.0`. See [troubleshooting information](#error-response-from-dae
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 will 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).
+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, [moved](https://gitlab.com/groups/gitlab-org/-/epics/2098) to [GitLab Core](https://about.gitlab.com/pricing/) in 13.3 |
-| .NET Framework | [Security Code Scan](https://security-code-scan.github.io) | 13.0, [moved](https://gitlab.com/groups/gitlab-org/-/epics/2098) to [GitLab Core](https://about.gitlab.com/pricing/) in 13.3 |
-| Apex (Salesforce) | [PMD](https://pmd.github.io/pmd/index.html) | 12.1, [moved](https://gitlab.com/groups/gitlab-org/-/epics/2098) to [GitLab Core](https://about.gitlab.com/pricing/) in 13.3 |
-| C/C++ | [Flawfinder](https://github.com/david-a-wheeler/flawfinder) | 10.7, [moved](https://gitlab.com/groups/gitlab-org/-/epics/2098) to [GitLab Core](https://about.gitlab.com/pricing/) in 13.3 |
-| Elixir (Phoenix) | [Sobelow](https://github.com/nccgroup/sobelow) | 11.10, [moved](https://gitlab.com/groups/gitlab-org/-/epics/2098) to [GitLab Core](https://about.gitlab.com/pricing/) in 13.3 |
-| Go | [Gosec](https://github.com/securego/gosec) | 10.7, [moved](https://gitlab.com/groups/gitlab-org/-/epics/2098) to [GitLab Core](https://about.gitlab.com/pricing/) in 13.3 |
-| Groovy ([Ant](https://ant.apache.org/), [Gradle](https://gradle.org/), [Maven](https://maven.apache.org/) and [SBT](https://www.scala-sbt.org/)) | [SpotBugs](https://spotbugs.github.io/) with the [find-sec-bugs](https://find-sec-bugs.github.io/) plugin | 11.3 (Gradle) & 11.9 (Ant, Maven, SBT), [moved](https://gitlab.com/groups/gitlab-org/-/epics/2098) to [GitLab Core](https://about.gitlab.com/pricing/) in 13.3 |
-| Helm Charts | [Kubesec](https://github.com/controlplaneio/kubesec) | 13.1, [moved](https://gitlab.com/groups/gitlab-org/-/epics/2098) to [GitLab Core](https://about.gitlab.com/pricing/) in 13.3 |
-| Java ([Ant](https://ant.apache.org/), [Gradle](https://gradle.org/), [Maven](https://maven.apache.org/) and [SBT](https://www.scala-sbt.org/)) | [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 (Ant, SBT), [moved](https://gitlab.com/groups/gitlab-org/-/epics/2098) to [GitLab Core](https://about.gitlab.com/pricing/) in 13.3 |
-| JavaScript | [ESLint security plugin](https://github.com/nodesecurity/eslint-plugin-security) | 11.8, [moved](https://gitlab.com/groups/gitlab-org/-/epics/2098) to [GitLab Core](https://about.gitlab.com/pricing/) in 13.2 |
-| Kubernetes manifests | [Kubesec](https://github.com/controlplaneio/kubesec) | 12.6, [moved](https://gitlab.com/groups/gitlab-org/-/epics/2098) to [GitLab Core](https://about.gitlab.com/pricing/) in 13.3 |
-| Node.js | [NodeJsScan](https://github.com/ajinabraham/NodeJsScan) | 11.1, [moved](https://gitlab.com/groups/gitlab-org/-/epics/2098) to [GitLab Core](https://about.gitlab.com/pricing/) in 13.3 |
-| PHP | [phpcs-security-audit](https://github.com/FloeDesignTechnologies/phpcs-security-audit) | 10.8, [moved](https://gitlab.com/groups/gitlab-org/-/epics/2098) to [GitLab Core](https://about.gitlab.com/pricing/) in 13.3 |
-| Python ([pip](https://pip.pypa.io/en/stable/)) | [bandit](https://github.com/PyCQA/bandit) | 10.3, [moved](https://gitlab.com/groups/gitlab-org/-/epics/2098) to [GitLab Core](https://about.gitlab.com/pricing/) in 13.3 |
-| React | [ESLint react plugin](https://github.com/yannickcr/eslint-plugin-react) | 12.5, [moved](https://gitlab.com/groups/gitlab-org/-/epics/2098) to [GitLab Core](https://about.gitlab.com/pricing/) in 13.2 |
-| Ruby on Rails | [brakeman](https://brakemanscanner.org) | 10.3, [moved](https://gitlab.com/groups/gitlab-org/-/epics/2098) to [GitLab Core](https://about.gitlab.com/pricing/) in 13.1 |
-| Scala ([Ant](https://ant.apache.org/), [Gradle](https://gradle.org/), [Maven](https://maven.apache.org/) and [SBT](https://www.scala-sbt.org/)) | [SpotBugs](https://spotbugs.github.io/) with the [find-sec-bugs](https://find-sec-bugs.github.io/) plugin | 11.0 (SBT) & 11.9 (Ant, Gradle, Maven), [moved](https://gitlab.com/groups/gitlab-org/-/epics/2098) to [GitLab Core](https://about.gitlab.com/pricing/) in 13.3 |
+| .NET Core | [Security Code Scan](https://security-code-scan.github.io) | 11.0 |
+| .NET Framework | [Security Code Scan](https://security-code-scan.github.io) | 13.0 |
+| Apex (Salesforce) | [PMD](https://pmd.github.io/pmd/index.html) | 12.1 |
+| C/C++ | [Flawfinder](https://github.com/david-a-wheeler/flawfinder) | 10.7 |
+| Elixir (Phoenix) | [Sobelow](https://github.com/nccgroup/sobelow) | 11.1 |
+| Go | [Gosec](https://github.com/securego/gosec) | 10.7 |
+| Groovy ([Ant](https://ant.apache.org/), [Gradle](https://gradle.org/), [Maven](https://maven.apache.org/) and [SBT](https://www.scala-sbt.org/)) | [SpotBugs](https://spotbugs.github.io/) with the [find-sec-bugs](https://find-sec-bugs.github.io/) plugin | 11.3 (Gradle) & 11.9 (Ant, Maven, SBT) |
+| Helm Charts | [Kubesec](https://github.com/controlplaneio/kubesec) | 13.1 |
+| Java ([Ant](https://ant.apache.org/), [Gradle](https://gradle.org/), [Maven](https://maven.apache.org/) and [SBT](https://www.scala-sbt.org/)) | [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 (Ant, SBT) |
+| Java (Android) | [MobSF (beta)](https://github.com/MobSF/Mobile-Security-Framework-MobSF) | 13.5 |
+| JavaScript | [ESLint security plugin](https://github.com/nodesecurity/eslint-plugin-security) | 11.8 |
+| Kotlin (Android) | [MobSF (beta)](https://github.com/MobSF/Mobile-Security-Framework-MobSF) | 13.5 |
+| 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 ([pip](https://pip.pypa.io/en/stable/)) | [bandit](https://github.com/PyCQA/bandit) | 10.3 |
+| React | [ESLint react plugin](https://github.com/yannickcr/eslint-plugin-react) | 12.5 |
+| Ruby on Rails | [brakeman](https://brakemanscanner.org) | 10.3 |
+| Scala ([Ant](https://ant.apache.org/), [Gradle](https://gradle.org/), [Maven](https://maven.apache.org/) and [SBT](https://www.scala-sbt.org/)) | [SpotBugs](https://spotbugs.github.io/) with the [find-sec-bugs](https://find-sec-bugs.github.io/) plugin | 11.0 (SBT) & 11.9 (Ant, Gradle, Maven) |
+| Swift (iOS) | [MobSF (beta)](https://github.com/MobSF/Mobile-Security-Framework-MobSF) | 13.5 |
| TypeScript | [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 |
-NOTE: **Note:**
-The Java analyzers can also be used for variants like the
+Note that the Java analyzers can also be used for variants like the
[Gradle wrapper](https://docs.gradle.org/current/userguide/gradle_wrapper.html),
-[Grails](https://grails.org/) and the [Maven wrapper](https://github.com/takari/maven-wrapper).
+[Grails](https://grails.org/),
+and the [Maven wrapper](https://github.com/takari/maven-wrapper).
### Making SAST analyzers available to all GitLab tiers
-All open source (OSS) analyzers have been moved to the GitLab Core tier. Progress can be
-tracked in the corresponding
-[epic](https://gitlab.com/groups/gitlab-org/-/epics/2098).
+All open source (OSS) analyzers have been moved to the GitLab Core tier as of GitLab 13.3.
#### Summary of features per tier
@@ -147,16 +151,19 @@ always take the latest SAST artifact available.
> - [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/3659) in GitLab Ultimate 13.3.
> - [Improved](https://gitlab.com/gitlab-org/gitlab/-/issues/232862) in GitLab Ultimate 13.4.
+> - [Improved](https://gitlab.com/groups/gitlab-org/-/epics/3635) in GitLab Ultimate 13.5.
You can enable and configure SAST with a basic configuration using the **SAST Configuration**
page:
1. From the project's home page, go to **Security & Compliance** > **Configuration** in the
left sidebar.
-1. If the project does not have a `gitlab-ci.yml` file, click **Enable** in the Static Application Security Testing (SAST) row, otherwise click **Configure**.
-1. Enter the custom SAST values, then click **Create Merge Request**.
+1. If the project does not have a `.gitlab-ci.yml` file, click **Enable** in the Static Application Security Testing (SAST) row, otherwise click **Configure**.
+1. Enter the custom SAST values.
Custom values are stored in the `.gitlab-ci.yml` file. For variables not in the SAST Configuration page, their values are left unchanged. Default values are inherited from the GitLab SAST template.
+1. Optionally, expand the **SAST analyzers** section, select individual [SAST analyzers](./analyzers.md) and enter custom analyzer values.
+1. Click **Create Merge Request**.
1. Review and merge the merge request.
### Customizing the SAST settings
@@ -169,7 +176,7 @@ set the `SAST_GOSEC_LEVEL` variable to `2`:
```yaml
include:
- - template: SAST.gitlab-ci.yml
+ - template: Security/SAST.gitlab-ci.yml
variables:
SAST_GOSEC_LEVEL: 2
@@ -191,13 +198,78 @@ inclusion and specify any additional keys under it. For example, this enables `F
```yaml
include:
- - template: SAST.gitlab-ci.yml
+ - template: Security/SAST.gitlab-ci.yml
spotbugs-sast:
variables:
FAIL_NEVER: 1
```
+### Custom rulesets
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/235382) in GitLab 13.5.
+
+You can customize the default scanning rules provided with SAST's NodeJS-Scan and Gosec analyzers.
+Customization allows you to exclude rules and modify the behavior of existing rules.
+
+To customize the default scanning rules, create a file containing custom rules. These rules
+are passed through to the analyzer's underlying scanner tool.
+
+To create a custom ruleset:
+
+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.
+1. In the `sast-ruleset.toml` file, do one of the following:
+
+ - Define a custom analyzer configuration. In this example, customized rules are defined for the
+ `nodejs-scan` scanner:
+
+ ```toml
+ [nodejs-scan]
+ description = 'custom ruleset for nodejs-scan'
+
+ [[nodejs-scan.passthrough]]
+ type = "raw"
+ value = '''
+ - nodejs-extensions:
+ - .js
+
+ template-extensions:
+ - .new
+ - .hbs
+ - ''
+
+ ignore-filenames:
+ - skip.js
+
+ ignore-paths:
+ - __MACOSX
+ - skip_dir
+ - node_modules
+
+ ignore-extensions:
+ - .hbs
+
+ ignore-rules:
+ - regex_injection_dos
+ - pug_jade_template
+ - express_xss
+
+ '''
+ ```
+
+ - Provide the name of the file containing a custom analyzer configuration. In this example,
+ customized rules for the `gosec` scanner are contained in the file `gosec-config.json`:
+
+ ```toml
+ [gosec]
+ description = 'custom ruleset for gosec'
+
+ [[gosec.passthrough]]
+ type = "file"
+ value = "gosec-config.json"
+ ```
+
### Using environment variables to pass credentials for private repositories
Some analyzers require downloading the project's dependencies in order to
@@ -222,7 +294,7 @@ Kubesec analyzer. In `.gitlab-ci.yml`, define:
```yaml
include:
- - template: SAST.gitlab-ci.yml
+ - template: Security/SAST.gitlab-ci.yml
variables:
SCAN_KUBERNETES_MANIFESTS: "true"
@@ -248,7 +320,7 @@ stages:
- test
include:
- - template: SAST.gitlab-ci.yml
+ - template: Security/SAST.gitlab-ci.yml
build:
stage: build
@@ -264,17 +336,16 @@ spotbugs-sast:
- build
variables:
MAVEN_REPO_PATH: ./.m2/repository
- COMPILE: false
+ COMPILE: "false"
artifacts:
reports:
sast: gl-sast-report.json
```
-NOTE: **Note:**
-The path to the vendored directory must be specified explicitly to allow
-the analyzer to recognize the compiled artifacts. This configuration can vary per
-analyzer but in the case of Java above, `MAVEN_REPO_PATH` can be used.
-See [Analyzer settings](#analyzer-settings) for the complete list of available options.
+To allow the analyzer to recognize the compiled artifacts, you must explicitly specify the path to
+the vendored directory. This configuration can vary per analyzer but in the case of Java above, you
+can use `MAVEN_REPO_PATH`. See
+[Analyzer settings](#analyzer-settings) for the complete list of available options.
### Available variables
@@ -358,13 +429,29 @@ CAUTION: **Caution:**
Variables having names starting with these prefixes will **not** be propagated to the SAST Docker container and/or
analyzer containers: `DOCKER_`, `CI`, `GITLAB_`, `FF_`, `HOME`, `PWD`, `OLDPWD`, `PATH`, `SHLVL`, `HOSTNAME`.
+### Experimental features
+
+Receive early access to experimental features.
+
+Currently, this will enable scanning of iOS and Android apps via the [MobSF analyzer](https://gitlab.com/gitlab-org/security-products/analyzers/mobsf/).
+
+To enable experimental features, add the following to your `.gitlab-ci.yml` file:
+
+```yaml
+include:
+ - template: Security/SAST.gitlab-ci.yml
+
+variables:
+ SAST_EXPERIMENTAL_FEATURES: "true"
+```
+
## Reports JSON format
The SAST tool emits a JSON report file. For more information, see the
[schema for this report](https://gitlab.com/gitlab-org/security-products/security-report-schemas/-/blob/master/dist/sast-report-format.json).
-The JSON report file can be downloaded from the CI pipelines page, for more
-information see [Downloading artifacts](../../../ci/pipelines/job_artifacts.md).
+The JSON report file can be downloaded from the CI pipelines page, or the
+pipelines tab on merge requests. For more information see [Downloading artifacts](../../../ci/pipelines/job_artifacts.md).
Here's an example SAST report:
@@ -480,7 +567,6 @@ To use SAST in an offline environment, you need:
- A Docker Container Registry with locally available copies of SAST [analyzer](https://gitlab.com/gitlab-org/security-products/analyzers) images.
- Configure certificate checking of packages (optional).
-NOTE: **Note:**
GitLab Runner has a [default `pull policy` of `always`](https://docs.gitlab.com/runner/executors/docker.html#using-the-always-pull-policy),
meaning the runner tries to pull Docker images from the GitLab container registry even if a local
copy is available. The GitLab Runner [`pull_policy` can be set to `if-not-present`](https://docs.gitlab.com/runner/executors/docker.html#using-the-if-not-present-pull-policy)
@@ -518,6 +604,25 @@ For details on saving and transporting Docker images as a file, see Docker's doc
[`docker save`](https://docs.docker.com/engine/reference/commandline/save/), [`docker load`](https://docs.docker.com/engine/reference/commandline/load/),
[`docker export`](https://docs.docker.com/engine/reference/commandline/export/), and [`docker import`](https://docs.docker.com/engine/reference/commandline/import/).
+#### If support for Custom Certificate Authorities are needed
+
+Support for custom certificate authorities was introduced in the following versions.
+
+| Analyzer | Version |
+| -------- | ------- |
+| `bandit` | [v2.3.0](https://gitlab.com/gitlab-org/security-products/analyzers/bandit/-/releases/v2.3.0) |
+| `brakeman` | [v2.1.0](https://gitlab.com/gitlab-org/security-products/analyzers/brakeman/-/releases/v2.1.0) |
+| `eslint` | [v2.9.2](https://gitlab.com/gitlab-org/security-products/analyzers/eslint/-/releases/v2.9.2) |
+| `flawfinder` | [v2.3.0](https://gitlab.com/gitlab-org/security-products/analyzers/flawfinder/-/releases/v2.3.0) |
+| `gosec` | [v2.5.0](https://gitlab.com/gitlab-org/security-products/analyzers/gosec/-/releases/v2.5.0) |
+| `kubesec` | [v2.1.0](https://gitlab.com/gitlab-org/security-products/analyzers/kubesec/-/releases/v2.1.0) |
+| `nodejs-scan` | [v2.9.5](https://gitlab.com/gitlab-org/security-products/analyzers/nodejs-scan/-/releases/v2.9.5) |
+| `phpcs-security-audit` | [v2.8.2](https://gitlab.com/gitlab-org/security-products/analyzers/phpcs-security-audit/-/releases/v2.8.2) |
+| `pmd-apex` | [v2.1.0](https://gitlab.com/gitlab-org/security-products/analyzers/pmd-apex/-/releases/v2.1.0) |
+| `security-code-scan` | [v2.7.3](https://gitlab.com/gitlab-org/security-products/analyzers/security-code-scan/-/releases/v2.7.3) |
+| `sobelow` | [v2.2.0](https://gitlab.com/gitlab-org/security-products/analyzers/sobelow/-/releases/v2.2.0) |
+| `spotbugs` | [v2.7.1](https://gitlab.com/gitlab-org/security-products/analyzers/spotbugs/-/releases/v2.7.1) |
+
### Set SAST CI job variables to use local SAST analyzers
Add the following configuration to your `.gitlab-ci.yml` file. You must replace
@@ -525,7 +630,7 @@ Add the following configuration to your `.gitlab-ci.yml` file. You must replace
```yaml
include:
- - template: SAST.gitlab-ci.yml
+ - template: Security/SAST.gitlab-ci.yml
variables:
SECURE_ANALYZERS_PREFIX: "localhost:5000/analyzers"
@@ -549,3 +654,16 @@ This error occurs when the Docker version that runs the SAST job is `19.03.0`.
Consider updating to Docker `19.03.1` or greater. Older versions are not
affected. Read more in
[this issue](https://gitlab.com/gitlab-org/gitlab/-/issues/13830#note_211354992 "Current SAST container fails").
+
+### Getting warning message `gl-sast-report.json: no matching files`
+
+For information on this, see the [general Application Security troubleshooting section](../../../ci/pipelines/job_artifacts.md#error-message-no-files-to-upload).
+
+### Limitation when using rules:exists
+
+The [SAST CI template](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml)
+uses the `rules:exists` parameter. For performance reasons, a maximum number of matches are made
+against the given glob pattern. If the number of matches exceeds the maximum, the `rules:exists`
+parameter returns `true`. Depending on the number of files in your repository, a SAST job might be
+triggered even if the scanner doesn't support your project. For more details about this issue, see
+the [`rules:exists` documentation](../../../ci/yaml/README.md#rulesexists).
diff --git a/doc/user/application_security/secret_detection/index.md b/doc/user/application_security/secret_detection/index.md
index f3e411cdc16..bb10e9d7315 100644
--- a/doc/user/application_security/secret_detection/index.md
+++ b/doc/user/application_security/secret_detection/index.md
@@ -9,8 +9,6 @@ info: To determine the technical writer assigned to the Stage/Group associated w
> [Introduced](https://about.gitlab.com/releases/2019/03/22/gitlab-11-9-released/#detect-secrets-and-credentials-in-the-repository) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 11.9.
-## Overview
-
A recurring problem when developing applications is that developers may unintentionally commit
secrets and credentials to their remote repositories. If other people have access to the source,
or if the project is public, the sensitive information is then exposed and can be leveraged by
@@ -40,7 +38,7 @@ To run Secret Detection jobs, by default, you need GitLab Runner with the
If you're using the shared runners on GitLab.com, this is enabled by default.
CAUTION: **Caution:**
-Our Secret Detection jobs currently expect a Linux container type. Windows containers are not yet supported.
+Our Secret Detection jobs expect a Linux container type. Windows containers are not supported.
CAUTION: **Caution:**
If you use your own runners, make sure the Docker version installed
@@ -67,26 +65,27 @@ as shown in the following table:
## Configuration
-NOTE: **Note:**
-With GitLab 13.1 Secret Detection was split into its own CI/CD template.
+> GitLab 13.1 splits Secret Detection from the [SAST configuration](../sast#configuration) into its own CI/CD template. If you're using GitLab 13.0 or earlier and SAST is enabled, then Secret Detection is already enabled.
Secret Detection is performed by a [specific analyzer](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Security/Secret-Detection.gitlab-ci.yml)
-during the `secret-detection` job. It runs regardless of the programming
-language of your app.
+during the `secret-detection` job. It runs regardless of your app's programming language.
-The Secret Detection analyzer includes [Gitleaks](https://github.com/zricethezav/gitleaks) and [TruffleHog](https://github.com/dxa4481/truffleHog) checks.
+The Secret Detection analyzer includes [Gitleaks](https://github.com/zricethezav/gitleaks) and
+[TruffleHog](https://github.com/dxa4481/truffleHog) checks.
-NOTE: **Note:**
-The Secret Detection analyzer will ignore "Password in URL" vulnerabilities if the password begins
-with a dollar sign (`$`) as this likely indicates the password being used is an environment
-variable. For example, `https://username:$password@example.com/path/to/repo` won't be
-detected, whereas `https://username:password@example.com/path/to/repo` would be detected.
+Note that the Secret Detection analyzer ignores Password-in-URL vulnerabilities if the password
+begins with a dollar sign (`$`), as this likely indicates the password is an environment variable.
+For example, `https://username:$password@example.com/path/to/repo` isn't detected, while
+`https://username:password@example.com/path/to/repo` is.
NOTE: **Note:**
-You don't have to configure Secret Detection manually as shown in this section if you're using [Auto Secret Detection](../../../topics/autodevops/stages.md#auto-secret-detection)
+You don't have to configure Secret Detection manually as shown in this section if you're using
+[Auto Secret Detection](../../../topics/autodevops/stages.md#auto-secret-detection)
provided by [Auto DevOps](../../../topics/autodevops/index.md).
-To enable Secret Detection for GitLab 13.1 and later, you must include the `Secret-Detection.gitlab-ci.yml` template that’s provided as a part of your GitLab installation. For GitLab versions earlier than 11.9, you can copy and use the job as defined in that template.
+To enable Secret Detection for GitLab 13.1 and later, you must include the
+`Secret-Detection.gitlab-ci.yml` template that's provided as a part of your GitLab installation. For
+GitLab versions earlier than 11.9, you can copy and use the job as defined in that template.
Add the following to your `.gitlab-ci.yml` file:
@@ -103,30 +102,6 @@ The results are saved as a
that you can later download and analyze. Due to implementation limitations, we
always take the latest Secret Detection artifact available.
-### Using the SAST Template
-
-Prior to GitLab 13.1, Secret Detection was part of [SAST configuration](../sast#configuration).
-If you already have SAST enabled for your app configured before GitLab 13.1,
-you don't need to manually configure it.
-
-CAUTION: **Planned Deprecation:**
-In a future GitLab release, configuring Secret Detection with the SAST template will be deprecated. Please begin using `Secret-Detection.gitlab-ci.yml`
-to prevent future issues. We have made a
-[video to guide you through the process of transitioning](https://www.youtube.com/watch?v=W2tjcQreDwQ)
-to this new template.
-
-<div class="video-fallback">
- See the video: <a href="https://www.youtube.com/watch?v=W2tjcQreDwQ">Walkthrough of historical secret scan</a>.
-</div>
-<figure class="video-container">
- <iframe src="https://www.youtube.com/embed/W2tjcQreDwQ" frameborder="0" allowfullscreen="true"> </iframe>
-</figure>
-
-When using the SAST template, Secret Detection is performed by a [specific analyzer](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml#L180)
-during the `sast` job. It runs regardless of the programming
-language of your app, and you don't need to change your
-CI/CD configuration file to enable it. Results are available in the SAST report.
-
### Customizing settings
The Secret Detection scan settings can be changed through [environment variables](#available-variables)
@@ -164,9 +139,52 @@ Secret Detection can be customized by defining available variables:
|-------------------------|---------------|-------------|
| `SECRET_DETECTION_COMMIT_FROM` | - | The commit a Gitleaks scan starts at. |
| `SECRET_DETECTION_COMMIT_TO` | - | The commit a Gitleaks scan ends at. |
-| `SECRET_DETECTION_EXCLUDED_PATHS` | "" | Exclude vulnerabilities from output based on the paths. This is a comma-separated list of patterns. Patterns can be globs, or file or folder paths (for example, `doc,spec` ). Parent directories will 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. This is a comma-separated list of patterns. Patterns can be globs, 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. |
+### Custom rulesets
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/211387) in GitLab 13.5.
+
+You can customize the default secret detection rules provided with GitLab.
+Customization allows you to exclude rules and add new rules.
+
+To create a custom ruleset:
+
+1. Create a `.gitlab` directory at the root of your project, if one doesn't already exist.
+1. Create a custom ruleset file named `secret-detection-ruleset.toml` in the `.gitlab` directory.
+1. In the `secret-detection-ruleset.toml` file, do one of the following:
+
+ - Define a custom ruleset:
+
+ ```toml
+ [secrets]
+ description = 'secrets custom rules configuration'
+
+ [[secrets.passthrough]]
+ type = "raw"
+ target = "gitleaks.toml"
+ value = """\
+ title = "gitleaks config"
+ # add regexes to the regex table
+ [[rules]]
+ description = "Test for Raw Custom Rulesets"
+ regex = '''Custom Raw Ruleset T[est]{3}'''
+ """
+ ```
+
+ - Provide the name of the file containing a custom ruleset:
+
+ ```toml
+ [secrets]
+ description = 'secrets custom rules configuration'
+
+ [[secrets.passthrough]]
+ type = "file"
+ target = "gitleaks.toml"
+ value = "config/gitleaks.toml"
+ ```
+
### Logging level
To control the verbosity of logs set the `SECURE_LOG_LEVEL` environment variable. Messages of this logging level or higher are output. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/10880) in GitLab 13.1.
@@ -197,3 +215,35 @@ We have created a [short video walkthrough](https://youtu.be/wDtc_K00Y0A) showca
<figure class="video-container">
<iframe src="https://www.youtube.com/embed/wDtc_K00Y0A" frameborder="0" allowfullscreen="true"> </iframe>
</figure>
+
+### Make GitLab Secret Detection analyzer image available inside your Docker registry
+
+Import the following default Secret Detection analyzer images from `registry.gitlab.com` into your
+[local Docker container registry](../../packages/container_registry/index.md):
+
+```plaintext
+registry.gitlab.com/gitlab-org/security-products/analyzers/secrets:3
+```
+
+The process for importing Docker images into a local offline Docker registry depends on
+**your network security policy**. Please consult your IT staff to find an accepted and approved
+process by which external resources can be imported or temporarily accessed. Note that these scanners are [updated periodically](../index.md#maintenance-and-update-of-the-vulnerabilities-database)
+with new definitions, so consider if you're able to make periodic updates yourself.
+
+For details on saving and transporting Docker images as a file, see Docker's documentation on
+[`docker save`](https://docs.docker.com/engine/reference/commandline/save/), [`docker load`](https://docs.docker.com/engine/reference/commandline/load/),
+[`docker export`](https://docs.docker.com/engine/reference/commandline/export/), and [`docker import`](https://docs.docker.com/engine/reference/commandline/import/).
+
+#### If support for Custom Certificate Authorities are needed
+
+Support for custom certificate authorities was introduced in the following versions.
+
+| Analyzer | Version |
+| -------- | ------- |
+| secrets | [v3.0.0](https://gitlab.com/gitlab-org/security-products/analyzers/secrets/-/releases/v3.0.0) |
+
+## Troubleshooting
+
+### Getting warning message `gl-secret-detection-report.json: no matching files`
+
+For information on this, see the [general Application Security troubleshooting section](../../../ci/pipelines/job_artifacts.md#error-message-no-files-to-upload).
diff --git a/doc/user/application_security/security_dashboard/img/group_vulnerability_report_v13_4.png b/doc/user/application_security/security_dashboard/img/group_vulnerability_report_v13_4.png
index 67a7bb5f368..0310ef3ea0a 100644
--- a/doc/user/application_security/security_dashboard/img/group_vulnerability_report_v13_4.png
+++ b/doc/user/application_security/security_dashboard/img/group_vulnerability_report_v13_4.png
Binary files differ
diff --git a/doc/user/application_security/security_dashboard/img/instance_security_center_settings_v13_4.png b/doc/user/application_security/security_dashboard/img/instance_security_center_settings_v13_4.png
new file mode 100644
index 00000000000..4223494c294
--- /dev/null
+++ b/doc/user/application_security/security_dashboard/img/instance_security_center_settings_v13_4.png
Binary files differ
diff --git a/doc/user/application_security/security_dashboard/img/instance_security_dashboard_empty_v13_4.png b/doc/user/application_security/security_dashboard/img/instance_security_dashboard_empty_v13_4.png
index 3c618090be8..5edceb32e5c 100644
--- a/doc/user/application_security/security_dashboard/img/instance_security_dashboard_empty_v13_4.png
+++ b/doc/user/application_security/security_dashboard/img/instance_security_dashboard_empty_v13_4.png
Binary files differ
diff --git a/doc/user/application_security/security_dashboard/img/instance_security_dashboard_v13_4.png b/doc/user/application_security/security_dashboard/img/instance_security_dashboard_v13_4.png
index d010adcc90c..5379b5c6e5d 100644
--- a/doc/user/application_security/security_dashboard/img/instance_security_dashboard_v13_4.png
+++ b/doc/user/application_security/security_dashboard/img/instance_security_dashboard_v13_4.png
Binary files differ
diff --git a/doc/user/application_security/security_dashboard/img/project_security_dashboard_dismissal_v13_4.png b/doc/user/application_security/security_dashboard/img/project_security_dashboard_dismissal_v13_4.png
new file mode 100644
index 00000000000..eb1dfe6c6f4
--- /dev/null
+++ b/doc/user/application_security/security_dashboard/img/project_security_dashboard_dismissal_v13_4.png
Binary files differ
diff --git a/doc/user/application_security/security_dashboard/img/project_security_dashboard_v13_0.png b/doc/user/application_security/security_dashboard/img/project_security_dashboard_v13_0.png
deleted file mode 100644
index 878bb83c2a2..00000000000
--- a/doc/user/application_security/security_dashboard/img/project_security_dashboard_v13_0.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/application_security/security_dashboard/img/project_security_dashboard_v13_2.png b/doc/user/application_security/security_dashboard/img/project_security_dashboard_v13_2.png
deleted file mode 100644
index 7cab7b0a61f..00000000000
--- a/doc/user/application_security/security_dashboard/img/project_security_dashboard_v13_2.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/application_security/security_dashboard/img/project_security_dashboard_v13_3.png b/doc/user/application_security/security_dashboard/img/project_security_dashboard_v13_3.png
deleted file mode 100644
index 34c64f830ba..00000000000
--- a/doc/user/application_security/security_dashboard/img/project_security_dashboard_v13_3.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/application_security/security_dashboard/img/project_security_dashboard_v13_5.png b/doc/user/application_security/security_dashboard/img/project_security_dashboard_v13_5.png
new file mode 100644
index 00000000000..c46a8295a53
--- /dev/null
+++ b/doc/user/application_security/security_dashboard/img/project_security_dashboard_v13_5.png
Binary files differ
diff --git a/doc/user/application_security/security_dashboard/img/vulnerability_list_table_v13_4.png b/doc/user/application_security/security_dashboard/img/vulnerability_list_table_v13_4.png
index eb91cfc47ad..760942c3239 100644
--- a/doc/user/application_security/security_dashboard/img/vulnerability_list_table_v13_4.png
+++ b/doc/user/application_security/security_dashboard/img/vulnerability_list_table_v13_4.png
Binary files differ
diff --git a/doc/user/application_security/security_dashboard/index.md b/doc/user/application_security/security_dashboard/index.md
index 51d9b4f45cd..5fa8ebb80e0 100644
--- a/doc/user/application_security/security_dashboard/index.md
+++ b/doc/user/application_security/security_dashboard/index.md
@@ -5,21 +5,26 @@ 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/#designated-technical-writers
---
-# GitLab Security Dashboard **(ULTIMATE)**
+# GitLab Security Dashboard, Security Center, and Vulnerability Reports **(ULTIMATE)**
-The Security Dashboard is a good place to get an overview of all the security
-vulnerabilities in your groups, projects, and pipelines.
+GitLab provides a comprehensive set of features for viewing and managing vulnerabilities:
+
+- Security dashboards: An overview of the security status in your instance, groups, and projects.
+- Vulnerability reports: Detailed lists of all vulnerabilities for the instance, group, project, or
+ pipeline. This is where you triage and manage vulnerabilities.
+- Security Center: A dedicated area for vulnerability management at the instance level. This
+ includes a security dashboard, vulnerability report, and settings.
You can also drill down into a vulnerability and get extra information. This includes the project it
comes from, any related file(s), and metadata that helps you analyze the risk it poses. You can also
dismiss a vulnerability or create an issue for it.
-To benefit from the Security Dashboard you must first configure one of the
+To benefit from these features, you must first configure one of the
[security scanners](../index.md).
## Supported reports
-The Security Dashboard displays vulnerabilities detected by scanners such as:
+The vulnerability report displays vulnerabilities detected by scanners such as:
- [Container Scanning](../container_scanning/index.md)
- [Dynamic Application Security Testing](../dast/index.md)
@@ -29,7 +34,7 @@ The Security Dashboard displays vulnerabilities detected by scanners such as:
## Requirements
-To use the instance, group, project, or pipeline security dashboard:
+To use the security dashboards and vulnerability reports:
1. At least one project inside a group must be configured with at least one of
the [supported reports](#supported-reports).
@@ -41,15 +46,19 @@ To use the instance, group, project, or pipeline security dashboard:
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/13496) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 12.3.
-At the pipeline level, the Security section displays the vulnerabilities present in the branch of the project the pipeline was run against.
+At the pipeline level, the Security section displays the vulnerabilities present in the branch of
+the project the pipeline ran against.
![Pipeline Security Dashboard](img/pipeline_security_dashboard_v13_3.png)
Visit the page for any pipeline that ran any of the [supported reports](#supported-reports). To view
the pipeline's security findings, select the **Security** tab when viewing the pipeline.
-NOTE: **Note:**
-A pipeline consists of multiple jobs, including SAST and DAST scanning. If any job fails to finish for any reason, the security dashboard will not show SAST scanner output. For example, if the SAST job finishes but the DAST job fails, the security dashboard will not show SAST results. The analyzer will output an [exit code](../../../development/integrations/secure.md#exit-code) on failure.
+A pipeline consists of multiple jobs, including SAST and DAST scanning. If any job fails to finish
+for any reason, the security dashboard doesn't show SAST scanner output. For example, if the SAST
+job finishes but the DAST job fails, the security dashboard doesn't show SAST results. On failure,
+the analyzer outputs an
+[exit code](../../../development/integrations/secure.md#exit-code).
## Project Security Dashboard
@@ -60,12 +69,15 @@ At the project level, the Security Dashboard displays the vulnerabilities merged
to **Security & Compliance > Security Dashboard**. By default, the Security Dashboard displays all
detected and confirmed vulnerabilities.
-The Security Dashboard first displays the total number of vulnerabilities by severity (for example,
+The Security Dashboard first displays the time at which the last pipeline completed on the project's
+default branch. There's also a link to view this in more detail.
+
+The Security Dashboard next displays the total number of vulnerabilities by severity (for example,
Critical, High, Medium, Low, Info, Unknown). Below this, a table shows each vulnerability's status, severity,
and description. Clicking a vulnerability takes you to its [Vulnerability Details](../vulnerabilities)
page to view more information about that vulnerability.
-![Project Security Dashboard](img/project_security_dashboard_v13_3.png)
+![Project Security Dashboard](img/project_security_dashboard_v13_5.png)
You can filter the vulnerabilities by one or more of the following:
@@ -78,7 +90,7 @@ You can also dismiss vulnerabilities in the table:
1. Select the checkbox for each vulnerability you want to dismiss.
1. In the menu that appears, select the reason for dismissal and click **Dismiss Selected**.
-![Project Security Dashboard](img/project_security_dashboard_v13_2.png)
+![Project Security Dashboard](img/project_security_dashboard_dismissal_v13_4.png)
## Group Security Dashboard
@@ -86,79 +98,99 @@ You can also dismiss vulnerabilities in the table:
The group Security Dashboard gives an overview of the vulnerabilities in the default branches of the
projects in a group and its subgroups. Access it by navigating to **Security > Security Dashboard**
-for your group. By default, the Security Dashboard displays all detected and confirmed
-vulnerabilities.
+after selecting your group. By default, the Security Dashboard displays all detected and confirmed
+vulnerabilities. If you don't see the vulnerabilities over time graph, the likely cause is that you
+have not selected a group.
-NOTE: **Note:**
-The Security Dashboard only shows projects with [security reports](#supported-reports) enabled in a
-group.
+Note that the Security Dashboard only shows projects with
+[security reports](#supported-reports)
+enabled in a group.
![Dashboard with action buttons and metrics](img/group_security_dashboard_v13_3.png)
There is a timeline chart that shows how many open
-vulnerabilities your projects had at various points in time. You can filter among 30, 60, and
-90 days, with the default being 90. Hover over the chart to get more details about
-the open vulnerabilities at a specific time.
+vulnerabilities your projects had at various points in time. You can display the vulnerability
+trends over a 30, 60, or 90-day time frame (the default is 90 days). Hover over the chart to get
+more details about the open vulnerabilities at a specific time.
Next to the timeline chart is a list of projects, grouped and sorted by the severity of the vulnerability found:
-- F: 1 or more "critical"
-- D: 1 or more "high" or "unknown"
-- C: 1 or more "medium"
-- B: 1 or more "low"
-- A: 0 vulnerabilities
+- F: One or more "critical"
+- D: One or more "high" or "unknown"
+- C: One or more "medium"
+- B: One or more "low"
+- A: Zero vulnerabilities
Projects with no vulnerability tests configured will not appear in the list. Additionally, dismissed
-vulnerabilities are not included either.
+vulnerabilities are excluded.
-Navigate to the group's [Vulnerability Report](#vulnerability-list) to view the vulnerabilities found.
+Navigate to the group's [vulnerability report](#vulnerability-report) to view the vulnerabilities found.
-## Instance Security Dashboard
+## Instance Security Center
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/6953) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 12.8.
+> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/3426) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 13.4.
-At the instance level, the Security Dashboard displays the vulnerabilities present in the default
-branches of all the projects you configure to display on the dashboard. It includes all the
-[group Security Dashboard's](#group-security-dashboard)
-features.
+The Security Center is where you manage vulnerabilities for your instance. It displays the
+vulnerabilities present in the default branches of all the projects you configure. It includes the
+following:
+
+- The [group security dashboard's](#group-security-dashboard) features.
+- A [vulnerability report](#vulnerability-report).
+- A dedicated settings area to configure which projects to display.
![Instance Security Dashboard with projects](img/instance_security_dashboard_v13_4.png)
-You can access the Instance Security Dashboard from the menu
+You can access the Instance Security Center from the menu
bar at the top of the page. Under **More**, select **Security**.
-![Instance Security Dashboard navigation link](img/instance_security_dashboard_link_v12_4.png)
+![Instance Security Center navigation link](img/instance_security_dashboard_link_v12_4.png)
-The dashboard is empty before you add projects to it.
+The dashboard and vulnerability report are empty before you add projects.
-![Uninitialized Instance Security Dashboard](img/instance_security_dashboard_empty_v13_4.png)
+![Uninitialized Instance Security Center](img/instance_security_dashboard_empty_v13_4.png)
-### Adding projects to the dashboard
+### Adding projects to the Security Center
-To add projects to the dashboard:
+To add projects to the Security Center:
1. Click **Settings** in the left navigation bar or click the **Add projects** button.
1. Search for and add one or more projects using the **Search your projects** field.
1. Click the **Add projects** button.
-After you add projects, the Security Dashboard displays the vulnerabilities found in those projects'
-default branches.
+![Adding projects to Instance Security Center](img/instance_security_center_settings_v13_4.png)
+
+After you add projects, the security dashboard and vulnerability report display the vulnerabilities
+found in those projects' default branches.
## Export vulnerabilities
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/213014) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 12.10.
-You can export all your vulnerabilities in CSV format by clicking the **{upload}** **Export**
-button located at top right of the **Security Dashboard**. After the report
-is built, the CSV report downloads to your local machine. The report contains all
-vulnerabilities for the projects defined in the **Security Dashboard**,
-as filters don't apply to the export function.
-
-![Export vulnerabilities](img/instance_security_dashboard_export_csv_v13_4.png)
+You can export all your vulnerabilities in CSV (comma separated values) format by clicking the
+**{upload}** **Export** button located at top right of the Security Dashboard. When the report is
+ready, the CSV report downloads to your local machine. The report contains all vulnerabilities for
+the projects defined in the Security Dashboard, as filters don't apply to the export function.
NOTE: **Note:**
It may take several minutes for the download to start if your project contains
-thousands of vulnerabilities. Do not close the page until the download finishes.
+thousands of vulnerabilities. Don't close the page until the download finishes.
+
+The fields in the export include:
+
+- Group Name
+- Project Name
+- Scanner Type
+- Scanner Name
+- Status
+- Vulnerability
+- Details
+- Additional Info
+- Severity
+- [CVE](https://cve.mitre.org/) (Common Vulnerabilities and Exposures)
+- [CWE](https://cwe.mitre.org/) (Common Weakness Enumeration)
+- Other Identifiers
+
+![Export vulnerabilities](img/instance_security_dashboard_export_csv_v13_4.png)
## Keeping the dashboards up to date
@@ -191,14 +223,14 @@ When using [Auto DevOps](../../../topics/autodevops/index.md), use
[special environment variables](../../../topics/autodevops/customize.md#environment-variables)
to configure daily security scans.
-## Vulnerability list
+## Vulnerability report
-Each dashboard's vulnerability list contains vulnerabilities from the latest scans that were merged
+Each vulnerability report contains vulnerabilities from the latest scans that were merged
into the default branch.
![Vulnerability Report](img/group_vulnerability_report_v13_4.png)
-You can filter which vulnerabilities the Security Dashboard displays by:
+You can filter which vulnerabilities the vulnerability report displays by:
- Status
- Severity
@@ -211,8 +243,10 @@ To create an issue associated with the vulnerability, click the **Create Issue**
![Create an issue for the vulnerability](img/vulnerability_page_v13_1.png)
-Once you create the issue, the vulnerability list contains a link to the issue and an icon whose
-color indicates the issue's status (green for open issues, blue for closed issues).
+Once you create the issue, the linked issue icon in the vulnerability list:
+
+- Indicates that an issue has been created for that vulnerability.
+- Shows a tooltip that contains a link to the issue.
![Display attached issues](img/vulnerability_list_table_v13_4.png)
diff --git a/doc/user/application_security/terminology/index.md b/doc/user/application_security/terminology/index.md
index 8006a49ba35..f975de213ef 100644
--- a/doc/user/application_security/terminology/index.md
+++ b/doc/user/application_security/terminology/index.md
@@ -13,7 +13,6 @@ This terminology list for GitLab Secure and Defend aims to:
- Improve the effectiveness of communication regarding GitLab's application security features.
- Get new contributors up to speed faster.
-NOTE: **Note:**
This document defines application security terms in the specific context of GitLab's Secure and
Defend products. Terms may therefore have different meanings outside of GitLab Secure and Defend.
diff --git a/doc/user/application_security/threat_monitoring/index.md b/doc/user/application_security/threat_monitoring/index.md
index 5414800b290..391666a077e 100644
--- a/doc/user/application_security/threat_monitoring/index.md
+++ b/doc/user/application_security/threat_monitoring/index.md
@@ -105,11 +105,10 @@ disabled state. Once enabled,a predefined policy deploys to the
selected environment's deployment platform and you can manage it like
the regular policies.
-NOTE: **Note:**
-If you're using [Auto DevOps](../../../topics/autodevops/index.md) and
-change a policy in this section, your `auto-deploy-values.yaml` file
-doesn't update. Auto DevOps users must make changes by following
-the [Container Network Policy documentation](../../../topics/autodevops/stages.md#network-policy).
+Note that if you're using [Auto DevOps](../../../topics/autodevops/index.md)
+and change a policy in this section, your `auto-deploy-values.yaml` file doesn't update. Auto DevOps
+users must make changes by following the
+[Container Network Policy documentation](../../../topics/autodevops/stages.md#network-policy).
### Changing enforcement status
@@ -119,12 +118,9 @@ To change a network policy's enforcement status:
- Click the **Enforcement status** toggle to update the selected policy.
- Click the **Apply changes** button to deploy network policy changes.
-NOTE: **Note:**
-Disabled network policies have the
-`network-policy.gitlab.com/disabled_by: gitlab` selector inside the
-`podSelector` block. This narrows the scope of such a policy and as a
-result it doesn't affect any pods. The policy itself is still deployed
-to the corresponding deployment namespace.
+Disabled network policies have the `network-policy.gitlab.com/disabled_by: gitlab` selector inside
+the `podSelector` block. This narrows the scope of such a policy and as a result it doesn't affect
+any pods. The policy itself is still deployed to the corresponding deployment namespace.
### Container Network Policy editor
@@ -135,10 +131,8 @@ create a new policy click the **New policy** button located in the
**Policy** tab's header. To edit an existing policy, click**Edit
policy** in the selected policy drawer.
-NOTE: **Note:**
-The policy editor only supports the
-[CiliumNetworkPolicy](https://docs.cilium.io/en/v1.8/policy/)specification. Regular
-Kubernetes
+Note that the policy editor only supports the
+[CiliumNetworkPolicy](https://docs.cilium.io/en/v1.8/policy/)specification. Regular Kubernetes
[NetworkPolicy](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.19/#networkpolicy-v1-networking-k8s-io)
resources aren't supported.
diff --git a/doc/user/application_security/vulnerabilities/index.md b/doc/user/application_security/vulnerabilities/index.md
index ff383fdf553..ee3fd6c4dd4 100644
--- a/doc/user/application_security/vulnerabilities/index.md
+++ b/doc/user/application_security/vulnerabilities/index.md
@@ -14,6 +14,7 @@ Each security vulnerability in a project's [Security Dashboard](../security_dash
- Details of the vulnerability.
- The status of the vulnerability within the project.
- Available actions for the vulnerability.
+- Issues related to the vulnerability.
On the vulnerability page, you can interact with the vulnerability in
several different ways:
@@ -23,6 +24,7 @@ several different ways:
- [Create issue](#creating-an-issue-for-a-vulnerability) - Create a new issue with the
title and description pre-populated with information from the vulnerability report.
By default, such issues are [confidential](../../project/issues/confidential_issues.md).
+- [Link issues](#link-issues-to-the-vulnerability) - Link existing issues to vulnerability.
- [Solution](#automatic-remediation-for-vulnerabilities) - For some vulnerabilities,
a solution is provided for how to fix the vulnerability.
@@ -38,6 +40,9 @@ the following values:
| Dismissed | A user has seen this vulnerability and dismissed it |
| Resolved | The vulnerability has been fixed and is no longer in the codebase |
+A timeline shows you when the vulnerability status has changed,
+and allows you to comment on a change.
+
## Creating an issue for a vulnerability
You can create an issue for a vulnerability by selecting the **Create issue** button.
@@ -47,6 +52,12 @@ project the vulnerability came from, and pre-populates it with useful informatio
the vulnerability report. After the issue is created, GitLab redirects you to the
issue page so you can edit, assign, or comment on the issue.
+## Link issues to the vulnerability
+
+You can link one or more existing issues to the vulnerability. This allows you to
+indicate that this vulnerability affects multiple issues. It also allows you to indicate
+that the resolution of one issue would resolve multiple vulnerabilities.
+
## Automatic remediation for vulnerabilities
You can fix some vulnerabilities by applying the solution that GitLab automatically
diff --git a/doc/user/clusters/agent/index.md b/doc/user/clusters/agent/index.md
index 6521b71e9e6..196c3e9fb43 100644
--- a/doc/user/clusters/agent/index.md
+++ b/doc/user/clusters/agent/index.md
@@ -6,18 +6,23 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# GitLab Kubernetes Agent **(PREMIUM ONLY)**
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/223061) in [GitLab Premium](https://about.gitlab.com/pricing/) 13.4.
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/223061) in [GitLab Premium](https://about.gitlab.com/pricing/) 13.4.
+> - It's disabled on GitLab.com. Rolling this feature out to GitLab.com is [planned](https://gitlab.com/groups/gitlab-org/-/epics/3834).
-## Goals
+CAUTION: **Warning:**
+This feature might not be available to you. Check the **version history** note above for details.
-The [GitLab Kubernetes Agent](https://gitlab.com/gitlab-org/cluster-integration/gitlab-agent) is an active in-cluster component for solving GitLab and Kubernetes integration tasks in a secure and cloud native way.
+The [GitLab Kubernetes Agent](https://gitlab.com/gitlab-org/cluster-integration/gitlab-agent)
+is an active in-cluster component for solving GitLab and Kubernetes integration
+tasks in a secure and cloud-native way. It enables:
-Features:
+- Integrating GitLab with a Kubernetes cluster behind a firewall or NAT
+ (network address translation).
+- Pull-based GitOps deployments by leveraging the
+ [GitOps Engine](https://github.com/argoproj/gitops-engine).
+- Real-time access to API endpoints within a cluster.
-1. Makes it possible to integrate GitLab with a Kubernetes cluster behind a firewall or NAT
-1. Enables pull-based GitOps deployments by leveraging the [GitOps Engine](https://github.com/argoproj/gitops-engine)
-1. Allows for real-time access to API endpoints within a cluster.
-1. Many more features are planned. Please [review our roadmap](https://gitlab.com/groups/gitlab-org/-/epics/3329).
+Many more features are planned. Please [review our roadmap](https://gitlab.com/groups/gitlab-org/-/epics/3329).
## Architecture
@@ -39,34 +44,52 @@ sequenceDiagram
end
```
-Please refer to our [full architecture documentation in the Agent project](https://gitlab.com/gitlab-org/cluster-integration/gitlab-agent/-/blob/master/doc/architecture.md#high-level-architecture).
+Please refer to our [full architecture documentation](https://gitlab.com/gitlab-org/cluster-integration/gitlab-agent/-/blob/master/doc/architecture.md#high-level-architecture)
+in the Agent project.
-## Getting started with GitOps using the GitLab Agent and the GitLab Cloud Native Helm chart
+## Get started with GitOps and the GitLab Agent
There are several components that work in concert for the Agent to accomplish GitOps deployments:
-1. A Kubernetes cluster that is properly configured
-1. A configuration repository that contains a `config.yaml` file. This `config.yaml` tells the Agent which repositories to synchronize with.
-1. A manifest repository that contains a `manifest.yaml`. This `manifest.yaml` (which can be autogenerated) is tracked by the Agent and any changes to the file are automatically applied to the cluster.
+- A properly-configured Kubernetes cluster.
+- A configuration repository that contains a `config.yaml` file, which tells the
+ Agent which repositories to synchronize with.
+- A manifest repository that contains a `manifest.yaml`, which is tracked by the
+ Agent and can be auto-generated. Any changes to `manifest.yaml` are applied to the cluster.
-The setup process involves a few steps that, once completed, will enable GitOps deployments to work
+The setup process involves a few steps to enable GitOps deployments:
-1. Installing the Agent server via GitLab Helm chart
-1. Defining a configuration directory
-1. Creating an Agent record in GitLab
-1. Generating and copying a Secret token used to connect to the Agent
-1. Installing the Agent into the cluster
-1. Creating a `manifest.yaml`
+1. Installing the Agent server.
+1. Defining a configuration directory.
+1. Creating an Agent record in GitLab.
+1. Generating and copying a Secret token used to connect to the Agent.
+1. Installing the Agent into the cluster.
+1. Creating a `manifest.yaml`.
-### Installing the Agent server via Helm
+### Install the Agent server
-Currently the GitLab Kubernetes Agent can only be deployed via our [Helm chart](https://gitlab.com/gitlab-org/charts/gitlab).
+The GitLab Kubernetes Agent can be deployed using [Omnibus
+GitLab](https://docs.gitlab.com/omnibus/) or the [GitLab
+chart](https://gitlab.com/gitlab-org/charts/gitlab). If you don't already have
+GitLab installed, please refer to our [installation
+documentation](https://docs.gitlab.com/ee/install/README.html).
-NOTE: We are working quickly to [include the Agent in Official Linux Package](https://gitlab.com/gitlab-org/gitlab/-/issues/223060).
+NOTE: **Note:**
+GitLab plans to include the Agent on [GitLab.com](https://gitlab.com/groups/gitlab-org/-/epics/3834).
-If you don't already have GitLab installed via Helm please refer to our [installation documentation](https://docs.gitlab.com/charts/installation/)
+When using the [Omnibus GitLab](https://docs.gitlab.com/omnibus/) package:
-When installing/upgrading the GitLab Helm chart please consider the following Helm 2 example (if using Helm 3 please modify):
+1. Edit `/etc/gitlab/gitlab.rb`:
+
+```plaintext
+gitlab_kas['enable'] = true
+```
+
+1. [Reconfigure GitLab](../../../administration/restart_gitlab.md#omnibus-gitlab-reconfigure).
+
+When installing or upgrading the GitLab Helm chart, consider the following Helm 2 example.
+(If you're using Helm 3, you must modify this example.) You must set `global.kas.enabled=true`
+for the Agent to be properly installed and configured:
```shell
helm repo update
@@ -79,15 +102,14 @@ helm upgrade --force --install gitlab gitlab/gitlab \
--set global.kas.enabled=true
```
-`global.kas.enabled=true` must be set in order for the Agent to be properly installed and configured.
-
-### Defining a configuration repository
+### Define a configuration repository
-Next you will need a GitLab repository that will contain your Agent configuration.
+Next, you need a GitLab repository to contain your Agent configuration. The minimal
+repository layout looks like this:
-The minimal repository layout looks like this:
-
-`.gitlab/agents/<agent-name>/config.yaml`
+```plaintext
+.gitlab/agents/<agent-name>/config.yaml
+```
The `config.yaml` file contents should look like this:
@@ -97,31 +119,24 @@ gitops:
- id: "path-to/your-awesome-project"
```
-### Creating an Agent record in GitLab
-
-Next you will need to create an GitLab Rails Agent record so that your GitLab project so that the Agent itself can associate with a GitLab project. This process will also yield a Secret that you will use to configure the Agent in subsequent steps.
+### Create an Agent record in GitLab
-There are two ways to accomplish this:
+Next, create an GitLab Rails Agent record so the Agent can associate itself with
+the configuration repository project. Creating this record also creates a Secret needed to configure
+the Agent in subsequent steps. You can create an Agent record either:
-1. Via the Rails console
-1. Via GraphQL
+- Through the Rails console, by running `rails c`:
-To do this you could either run `rails c` or via GraphQL. From `rails c`:
-
-```ruby
+ ```ruby
project = ::Project.find_by_full_path("path-to/your-awesome-project")
agent = ::Clusters::Agent.create(name: "<agent-name>", project: project)
token = ::Clusters::AgentToken.create(agent: agent)
token.token # this will print out the token you need to use on the next step
-```
+ ```
-or using GraphQL:
+- Through GraphQL: **(PREMIUM ONLY)**
-with this approach, you'll need a premium license to use this feature.
-
-If you are new to using the GitLab GraphQL API please refer to the [Getting started with the GraphQL API page](../../../api/graphql/getting_started.md) or check out the [GraphQL Explorer](https://gitlab.com/-/graphql-explorer).
-
-```json
+ ```graphql
mutation createAgent {
createClusterAgent(input: { projectPath: "path-to/your-awesome-project", name: "<agent-name>" }) {
clusterAgent {
@@ -142,37 +157,77 @@ If you are new to using the GitLab GraphQL API please refer to the [Getting star
errors
}
}
-```
+ ```
-Note that GraphQL will only show you the token once, after you've created it.
+ NOTE: **Note:**
+ GraphQL only displays the token once, after creating it.
-### Creating the Kubernetes secret
+ If you are new to using the GitLab GraphQL API, refer to the
+ [Getting started with the GraphQL API page](../../../api/graphql/getting_started.md),
+ or the [GraphQL Explorer](https://gitlab.com/-/graphql-explorer).
-Once the token has been generated it needs to be applied to the Kubernetes cluster.
+### Create the Kubernetes secret
-If you didn't previously define or create a namespace you need to do that first:
+After generating the token, you must apply it to the Kubernetes cluster.
-```shell
-kubectl create namespace <YOUR-DESIRED-NAMESPACE>
-```
+1. If you haven't previous defined or created a namespace, run the following command:
+
+ ```shell
+ kubectl create namespace <YOUR-DESIRED-NAMESPACE>
+ ```
+
+1. Run the following command to create your Secret:
+
+ ```shell
+ kubectl create secret generic -n <YOUR-DESIRED-NAMESPACE> gitlab-agent-token --from-literal=token='YOUR_AGENT_TOKEN'
+ ```
-Run the following command to create your Secret:
+### Install the Agent into the cluster
+
+Next, install the in-cluster component of the Agent. This example file contains the
+Kubernetes resources required for the Agent to be installed. You can modify this
+example [`resources.yml` file](#example-resourcesyml-file) in the following ways:
+
+- You can replace `gitlab-agent` with `<YOUR-DESIRED-NAMESPACE>`.
+- For the `kas-address` (Kubernetes Agent Server), the agent can use the WebSockets
+ or gRPC protocols to connect to the Agent Server. Depending on your cluster
+ configuration and GitLab architecture, you may need to use one or the other.
+ For the `gitlab-kas` Helm chart, an Ingress is created for the Agent Server using
+ the `/-/kubernetes-agent` endpoint. This can be used for the WebSockets protocol connection.
+ - Specify the `grpc` scheme (such as `grpc://gitlab-kas:5005`) to use gRPC directly.
+ Encrypted gRPC is not supported yet. Follow the
+ [Support TLS for gRPC communication issue](https://gitlab.com/gitlab-org/cluster-integration/gitlab-agent/-/issues/7)
+ for progress updates.
+ - Specify the `ws` scheme (such as `ws://gitlab-kas-ingress:80/-/kubernetes-agent`)
+ to use an unencrypted WebSockets connection.
+ - Specify the `wss` scheme (such as `wss://gitlab-kas-ingress:443/-/kubernetes-agent`)
+ to use an encrypted WebSockets connection. This is the recommended option if
+ installing the Agent into a separate cluster from your Agent Server.
+- If you defined your own secret name, replace `gitlab-agent-token` with your secret name.
+
+To apply this file, run the following command:
```shell
-kubectl create secret generic -n <YOUR-DESIRED-NAMESPACE> gitlab-agent-token --from-literal=token='YOUR_AGENT_TOKEN'
+kubectl apply -n gitlab-agent -f ./resources.yml
```
-### Installing the Agent into the cluster
+To review your configuration, run the following command:
-Next you are now ready to install the in-cluster component of the Agent. The below is an example YAML file of the Kubernetes resources required for the Agent to be installed.
-
-Let's highlight a few of the details in the example below:
+```shell
+$ kubectl get pods --all-namespaces
-1. You can replace `gitlab-agent` with <YOUR-DESIRED-NAMESPACE>
-1. For the `kas-address` (Kubernetes Agent Server), you can replace `grpc://host.docker.internal:5005` with the address of the kas agent that was initialized via your Helm install.
-1. If you defined your own secret name, then replace `gitlab-agent-token` with your secret name.
+NAMESPACE NAME READY STATUS RESTARTS AGE
+gitlab-agent gitlab-agent-77689f7dcb-5skqk 1/1 Running 0 51s
+kube-system coredns-f9fd979d6-n6wcw 1/1 Running 0 14m
+kube-system etcd-minikube 1/1 Running 0 14m
+kube-system kube-apiserver-minikube 1/1 Running 0 14m
+kube-system kube-controller-manager-minikube 1/1 Running 0 14m
+kube-system kube-proxy-j6zdh 1/1 Running 0 14m
+kube-system kube-scheduler-minikube 1/1 Running 0 14m
+kube-system storage-provisioner 1/1 Running 0 14m
+```
-`./resources.yml`
+#### Example `resources.yml` file
```yaml
apiVersion: v1
@@ -201,7 +256,7 @@ spec:
args:
- --token-file=/config/token
- --kas-address
- - grpc://host.docker.internal:5005 # {"$openapi":"kas-address"}
+ - grpc://host.docker.internal:5005 # {"$openapi":"kas-address"}
volumeMounts:
- name: token-volume
mountPath: /config
@@ -269,31 +324,24 @@ subjects:
- name: gitlab-agent
kind: ServiceAccount
namespace: gitlab-agent
-
```
-```shell
-kubectl apply -n gitlab-agent -f ./resources.yml
-```
+### Create a `manifest.yaml`
+
+In a previous step, you configured a `config.yaml` to point to the GitLab projects
+the Agent should synchronize. In each of those projects, you must create a `manifest.yaml`
+file for the Agent to monitor. You can auto-generate this `manifest.yaml` with a
+templating engine or other means.
+
+Each time you commit and push a change to this file, the Agent logs the change:
```plaintext
-$ kubectl get pods --all-namespaces
-NAMESPACE NAME READY STATUS RESTARTS AGE
-gitlab-agent gitlab-agent-77689f7dcb-5skqk 1/1 Running 0 51s
-kube-system coredns-f9fd979d6-n6wcw 1/1 Running 0 14m
-kube-system etcd-minikube 1/1 Running 0 14m
-kube-system kube-apiserver-minikube 1/1 Running 0 14m
-kube-system kube-controller-manager-minikube 1/1 Running 0 14m
-kube-system kube-proxy-j6zdh 1/1 Running 0 14m
-kube-system kube-scheduler-minikube 1/1 Running 0 14m
-kube-system storage-provisioner 1/1 Running 0 14m
+2020-09-15_14:09:04.87946 gitlab-k8s-agent : time="2020-09-15T10:09:04-04:00" level=info msg="Config: new commit" agent_id=1 commit_id=e6a3651f1faa2e928fe6120e254c122451be4eea
```
-### Creating a `manifest.yaml`
-
-In the above step, you configured a `config.yaml` to point to which GitLab projects the Agent should synchronize. Within each one of those projects, you need to create a `manifest.yaml` file which the Agent will monitor. This `manifest.yaml` can be autogenerated by a templating engine or other means.
+#### Example `manifest.yaml` file
-Example `manifest.yaml`:
+This file creates a simple NGINX deployment.
```yaml
apiVersion: apps/v1
@@ -318,14 +366,9 @@ spec:
- containerPort: 80
```
-The above file creates a simple NGINX deployment.
-
-Each time you commit and push a change to the `manifest.yaml` the Agent will observe the change. Example log:
-
-```plaintext
-2020-09-15_14:09:04.87946 gitlab-k8s-agent : time="2020-09-15T10:09:04-04:00" level=info msg="Config: new commit" agent_id=1 commit_id=e6a3651f1faa2e928fe6120e254c122451be4eea
-```
-
## Example projects
-Basic GitOps example deploying NGINX: [Configuration repository](https://gitlab.com/gitlab-org/configure/examples/kubernetes-agent), [Manifest repository](https://gitlab.com/gitlab-org/configure/examples/gitops-project)
+This basic GitOps example deploys NGINX:
+
+- [Configuration repository](https://gitlab.com/gitlab-org/configure/examples/kubernetes-agent)
+- [Manifest repository](https://gitlab.com/gitlab-org/configure/examples/gitops-project)
diff --git a/doc/user/clusters/applications.md b/doc/user/clusters/applications.md
index 2243ffa0cb1..4e0e2991acb 100644
--- a/doc/user/clusters/applications.md
+++ b/doc/user/clusters/applications.md
@@ -6,37 +6,30 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# GitLab Managed Apps
-GitLab provides **GitLab Managed Apps**, a one-click install for various applications which can
-be added directly to your configured cluster.
+GitLab provides **GitLab Managed Apps** for various
+applications which can be added directly to your configured cluster. These
+applications are needed for [Review Apps](../../ci/review_apps/index.md) and
+[deployments](../../ci/environments/index.md) when using [Auto DevOps](../../topics/autodevops/index.md).
+You can install them after you [create a cluster](../project/clusters/add_remove_clusters.md). GitLab provides
+GitLab Managed Apps that can installed with [one-click](#install-with-one-click) or [using CI/CD](#install-using-gitlab-cicd-alpha).
-These applications are needed for [Review Apps](../../ci/review_apps/index.md)
-and [deployments](../../ci/environments/index.md) when using [Auto DevOps](../../topics/autodevops/index.md).
+## Install with one click
-You can install them after you
-[create a cluster](../project/clusters/add_remove_clusters.md).
-
-## Installing applications
-
-Applications managed by GitLab will be installed onto the `gitlab-managed-apps` namespace.
-
-This namespace:
+Applications managed by GitLab are installed onto the `gitlab-managed-apps`
+namespace. This namespace:
- Is different from the namespace used for project deployments.
- Is created once.
- Has a non-configurable name.
-To see a list of available applications to install. For a:
+To view a list of available applications to install for a:
- [Project-level cluster](../project/clusters/index.md), navigate to your project's
**Operations > Kubernetes**.
- [Group-level cluster](../group/clusters/index.md), navigate to your group's
**Kubernetes** page.
-NOTE: **Note:**
-As of GitLab 11.6, Helm will be upgraded to the latest version supported
-by GitLab before installing any of the applications.
-
-The following applications can be installed:
+You can install the following applications with one click:
- [Helm](#helm)
- [Ingress](#ingress)
@@ -49,27 +42,28 @@ The following applications can be installed:
- [Elastic Stack](#elastic-stack)
- [Fluentd](#fluentd)
-With the exception of Knative, the applications will be installed in a dedicated
+With the exception of Knative, the applications are installed in a dedicated
namespace called `gitlab-managed-apps`.
-NOTE: **Note:**
Some applications are installable only for a project-level cluster.
Support for installing these applications in a group-level cluster is
planned for future releases.
-For updates, see [the issue tracking
-progress](https://gitlab.com/gitlab-org/gitlab/-/issues/24411).
+For updates, see the [issue tracking progress](https://gitlab.com/gitlab-org/gitlab/-/issues/24411).
CAUTION: **Caution:**
If you have an existing Kubernetes cluster with Helm already installed,
you should be careful as GitLab cannot detect it. In this case, installing
-Helm via the applications will result in the cluster having it twice, which
+Helm with the applications results in the cluster having it twice, which
can lead to confusion during deployments.
+In GitLab versions 11.6 and greater, Helm is upgraded to the latest version
+supported by GitLab before installing any of the applications.
+
### Helm
> - Introduced in GitLab 10.2 for project-level clusters.
> - Introduced in GitLab 11.6 for group-level clusters.
-> - [Uses a local Tiller](https://gitlab.com/gitlab-org/gitlab/-/issues/209736) since GitLab 13.2.
+> - [Uses a local Tiller](https://gitlab.com/gitlab-org/gitlab/-/issues/209736) in GitLab 13.2 and later.
[Helm](https://helm.sh/docs/) is a package manager for Kubernetes and is
used to install the GitLab-managed apps. GitLab runs each `helm` command
@@ -81,7 +75,6 @@ applications. Prior to [GitLab 13.2](https://gitlab.com/gitlab-org/gitlab/-/issu
GitLab used an in-cluster Tiller server in the `gitlab-managed-apps`
namespace. This server can now be safely removed.
-NOTE: **Note:**
GitLab's Helm integration does not support installing applications behind a proxy,
but a [workaround](../../topics/autodevops/index.md#install-applications-behind-a-proxy)
is available.
@@ -90,26 +83,25 @@ is available.
> Introduced in GitLab 11.6 for project- and group-level clusters.
-[cert-manager](https://cert-manager.io/docs/) is a native
-Kubernetes certificate management controller that helps with issuing
-certificates. Installing cert-manager on your cluster will issue a
-certificate by [Let's Encrypt](https://letsencrypt.org/) and ensure that
-certificates are valid and up-to-date.
+[cert-manager](https://cert-manager.io/docs/) is a native Kubernetes certificate
+management controller that helps with issuing certificates. Installing
+cert-manager on your cluster issues a certificate by [Let's Encrypt](https://letsencrypt.org/)
+and ensures that certificates are valid and up-to-date.
The chart used to install this application depends on the version of GitLab used. In:
-- GitLab 12.3 and newer, the [jetstack/cert-manager](https://github.com/jetstack/cert-manager)
+- GitLab 12.3 and newer, the [`jetstack/cert-manager`](https://github.com/jetstack/cert-manager)
chart is used with a [`values.yaml`](https://gitlab.com/gitlab-org/gitlab/blob/master/vendor/cert_manager/values.yaml)
file.
-- GitLab 12.2 and older, the [stable/cert-manager](https://github.com/helm/charts/tree/master/stable/cert-manager)
+- GitLab 12.2 and older, the [`stable/cert-manager`](https://gi2wthub.com/helm/charts/tree/master/stable/cert-manager)
chart was used.
-If you have installed cert-manager prior to GitLab 12.3, Let's Encrypt will
-[block requests from older versions of cert-manager](https://community.letsencrypt.org/t/blocking-old-cert-manager-versions/98753).
-
-To resolve this:
+If you installed cert-manager prior to GitLab 12.3, Let's Encrypt
+[blocks requests](https://community.letsencrypt.org/t/blocking-old-cert-manager-versions/98753)
+from older versions of `cert-manager`. To resolve this:
-1. Uninstall cert-manager (consider [backing up any additional configuration](https://cert-manager.io/docs/tutorials/backup/)).
+1. [Back up any additional configuration](https://cert-manager.io/docs/tutorials/backup/).
+1. Uninstall cert-manager.
1. Install cert-manager again.
### GitLab Runner
@@ -117,52 +109,52 @@ To resolve this:
> - Introduced in GitLab 10.6 for project-level clusters.
> - Introduced in GitLab 11.10 for group-level clusters.
-[GitLab Runner](https://docs.gitlab.com/runner/) is the open source
-project that is used to run your jobs and send the results back to
-GitLab. It is used in conjunction with [GitLab
-CI/CD](../../ci/README.md), the open-source continuous integration
-service included with GitLab that coordinates the jobs.
-
-If the project is on GitLab.com, shared runners are available
-(the first 2000 minutes are free, you can
-[buy more later](../../subscriptions/gitlab_com/index.md#purchase-additional-ci-minutes))
-and you do not have to deploy one if they are enough for your needs. If a
-project-specific runner is desired, or there are no shared runners, it is easy
-to deploy one.
-
-Note that the deployed runner will be set as **privileged**, which means it will essentially
-have root access to the underlying machine. This is required to build Docker images,
-so it is the default. Make sure you read the
-[security implications](../project/clusters/index.md#security-implications)
+[GitLab Runner](https://docs.gitlab.com/runner/) is the open source project that
+is used to run your jobs and send the results back to GitLab. It's used in
+conjunction with [GitLab CI/CD](../../ci/README.md), the open-source continuous
+integration service included with GitLab that coordinates the jobs.
+
+If the project is on GitLab.com, [shared runners](../gitlab_com/index.md#shared-runners)
+are available. You don't have to deploy one if they are enough for your
+needs. If a project-specific runner is desired, or there are no shared runners,
+you can deploy one.
+
+The deployed runner is set as **privileged**. Root access to the underlying
+server is required to build Docker images, so it's the default. Be sure to read
+the [security implications](../project/clusters/index.md#security-implications)
before deploying one.
-NOTE: **Note:**
The [`runner/gitlab-runner`](https://gitlab.com/gitlab-org/charts/gitlab-runner)
chart is used to install this application, using
[a preconfigured `values.yaml`](https://gitlab.com/gitlab-org/charts/gitlab-runner/-/blob/master/values.yaml)
-file. Customizing the installation by modifying this file is not supported.
+file. Customizing the installation by modifying this file is not supported. This
+also means you cannot modify `config.toml` file for this Runner. If you want to
+have that possibility and still deploy Runner in Kubernetes, consider using the
+[Cluster management project](management_project.md) or installing Runner manually
+via [GitLab Runner Helm Chart](https://docs.gitlab.com/runner/install/kubernetes.html).
### Ingress
> - Introduced in GitLab 10.2 for project-level clusters.
> - Introduced in GitLab 11.6 for group-level clusters.
-[Ingress](https://kubernetes.io/docs/concepts/services-networking/ingress/) provides load balancing, SSL termination, and name-based virtual hosting
+[Ingress](https://kubernetes.io/docs/concepts/services-networking/ingress/)
+provides load balancing, SSL termination, and name-based virtual hosting
out of the box. It acts as a web proxy for your applications and is useful
if you want to use [Auto DevOps](../../topics/autodevops/index.md) or deploy your own web apps.
-The Ingress Controller installed is [Ingress-NGINX](https://kubernetes.io/docs/concepts/services-networking/ingress/),
+The Ingress Controller installed is
+[Ingress-NGINX](https://kubernetes.io/docs/concepts/services-networking/ingress/),
which is supported by the Kubernetes community.
-NOTE: **Note:**
With the following procedure, a load balancer must be installed in your cluster
to obtain the endpoint. You can use either
Ingress, or Knative's own load balancer ([Istio](https://istio.io)) if using Knative.
-In order to publish your web application, you first need to find the endpoint which will be either an IP
+To publish your web application, you first need to find the endpoint, which is either an IP
address or a hostname associated with your load balancer.
-To install it, click on the **Install** button for Ingress. GitLab will attempt
+To install it, click on the **Install** button for Ingress. GitLab attempts
to determine the external endpoint and it should be available within a few minutes.
#### Determining the external endpoint automatically
@@ -178,22 +170,25 @@ using the `KUBE_INGRESS_BASE_DOMAIN` environment variable.
If the endpoint doesn't appear and your cluster runs on Google Kubernetes Engine:
-1. Check your [Kubernetes cluster on Google Kubernetes Engine](https://console.cloud.google.com/kubernetes) to ensure there are no errors on its nodes.
-1. Ensure you have enough [Quotas](https://console.cloud.google.com/iam-admin/quotas) on Google Kubernetes Engine. For more information, see [Resource Quotas](https://cloud.google.com/compute/quotas).
-1. Check [Google Cloud's Status](https://status.cloud.google.com/) to ensure they are not having any disruptions.
+1. [Examine your Kubernetes cluster](https://console.cloud.google.com/kubernetes)
+ on Google Kubernetes Engine to ensure there are no errors on its nodes.
+1. Ensure you have enough [Quotas](https://console.cloud.google.com/iam-admin/quotas)
+ on Google Kubernetes Engine. For more information, see
+ [Resource Quotas](https://cloud.google.com/compute/quotas).
+1. Review [Google Cloud's Status](https://status.cloud.google.com/) for service
+ disruptions.
-Once installed, you may see a `?` for "Ingress IP Address" depending on the
-cloud provider. For EKS specifically, this is because the ELB is created
-with a DNS name, not an IP address. If GitLab is still unable to
-determine the endpoint of your Ingress or Knative application, you can
-[determine it manually](#determining-the-external-endpoint-manually).
-
-NOTE: **Note:**
The [`stable/nginx-ingress`](https://github.com/helm/charts/tree/master/stable/nginx-ingress)
chart is used to install this application with a
[`values.yaml`](https://gitlab.com/gitlab-org/gitlab/blob/master/vendor/ingress/values.yaml)
file.
+After installing, you may see a `?` for **Ingress IP Address** depending on the
+cloud provider. For EKS specifically, this is because the ELB is created
+with a DNS name, not an IP address. If GitLab is still unable to
+determine the endpoint of your Ingress or Knative application, you can
+[determine it manually](#determining-the-external-endpoint-manually).
+
#### Determining the external endpoint manually
If the cluster is on GKE, click the **Google Kubernetes Engine** link in the
@@ -204,62 +199,62 @@ the `gcloud` command in a local terminal or using the **Cloud Shell**.
If the cluster is not on GKE, follow the specific instructions for your
Kubernetes provider to configure `kubectl` with the right credentials.
-The output of the following examples will show the external endpoint of your
+The output of the following examples show the external endpoint of your
cluster. This information can then be used to set up DNS entries and forwarding
rules that allow external access to your deployed applications.
-If you installed Ingress via the **Applications**, run the following command:
+- If you installed Ingress using the **Applications**, run the following
+ command:
-```shell
-kubectl get service --namespace=gitlab-managed-apps ingress-nginx-ingress-controller -o jsonpath='{.status.loadBalancer.ingress[0].ip}'
-```
+ ```shell
+ kubectl get service --namespace=gitlab-managed-apps ingress-nginx-ingress-controller -o jsonpath='{.status.loadBalancer.ingress[0].ip}'
+ ```
-Some Kubernetes clusters return a hostname instead, like [Amazon EKS](https://aws.amazon.com/eks/). For these platforms, run:
+- Some Kubernetes clusters return a hostname instead, like
+ [Amazon EKS](https://aws.amazon.com/eks/). For these platforms, run:
-```shell
-kubectl get service --namespace=gitlab-managed-apps ingress-nginx-ingress-controller -o jsonpath='{.status.loadBalancer.ingress[0].hostname}'
-```
+ ```shell
+ kubectl get service --namespace=gitlab-managed-apps ingress-nginx-ingress-controller -o jsonpath='{.status.loadBalancer.ingress[0].hostname}'
+ ```
-For Istio/Knative, the command will be different:
+ If EKS is used, an [Elastic Load Balancer](https://docs.aws.amazon.com/elasticloadbalancing/)
+ is also created, which will incur additional AWS costs.
-```shell
-kubectl get svc --namespace=istio-system istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip} '
-```
+- For Istio/Knative, the command is different:
-Otherwise, you can list the IP addresses of all load balancers:
+ ```shell
+ kubectl get svc --namespace=istio-system istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip} '
+ ```
-```shell
-kubectl get svc --all-namespaces -o jsonpath='{range.items[?(@.status.loadBalancer.ingress)]}{.status.loadBalancer.ingress[*].ip} '
-```
+- Otherwise, you can list the IP addresses of all load balancers:
-NOTE: **Note:**
-If EKS is used, an [Elastic Load Balancer](https://docs.aws.amazon.com/elasticloadbalancing/)
-will also be created, which will incur additional AWS costs.
+ ```shell
+ kubectl get svc --all-namespaces -o jsonpath='{range.items[?(@.status.loadBalancer.ingress)]}{.status.loadBalancer.ingress[*].ip} '
+ ```
-NOTE: **Note:**
-You may see a trailing `%` on some Kubernetes versions, **do not include it**.
+You may see a trailing `%` on some Kubernetes versions. Do not include it.
-The Ingress is now available at this address and will route incoming requests to
-the proper service based on the DNS name in the request. To support this, a
-wildcard DNS CNAME record should be created for the desired domain name. For example,
+The Ingress is now available at this address, and routes incoming requests to
+the proper service based on the DNS name in the request. To support this, create
+a wildcard DNS CNAME record for the desired domain name. For example,
`*.myekscluster.com` would point to the Ingress hostname obtained earlier.
#### Using a static IP
By default, an ephemeral external IP address is associated to the cluster's load
balancer. If you associate the ephemeral IP with your DNS and the IP changes,
-your apps will not be able to be reached, and you'd have to change the DNS
-record again. In order to avoid that, you should change it into a static
-reserved IP.
+your apps won't be reachable, and you'd have to change the DNS record again.
+To avoid that, change it into a static reserved IP.
Read how to [promote an ephemeral external IP address in GKE](https://cloud.google.com/compute/docs/ip-addresses/reserve-static-external-ip-address#promote_ephemeral_ip).
#### Pointing your DNS at the external endpoint
-Once you've set up the external endpoint, you should associate it with a [wildcard DNS
-record](https://en.wikipedia.org/wiki/Wildcard_DNS_record) such as `*.example.com.`
-in order to be able to reach your apps. If your external endpoint is an IP address,
-use an A record. If your external endpoint is a hostname, use a CNAME record.
+After you have set up the external endpoint, associate it with a
+[wildcard DNS record](https://en.wikipedia.org/wiki/Wildcard_DNS_record) (such
+as `*.example.com.`) to reach your apps. If your external endpoint is an IP
+address, use an A record. If your external endpoint is a hostname, use a CNAME
+record.
#### Web Application Firewall (ModSecurity)
@@ -269,16 +264,15 @@ A Web Application Firewall (WAF) examines traffic being sent or received,
and can block malicious traffic before it reaches your application. The benefits
of a WAF are:
-- Real-time security monitoring for your application
-- Logging of all your HTTP traffic to the application
-- Access control for your application
-- Highly configurable logging and blocking rules
+- Real-time security monitoring for your application.
+- Logging of all your HTTP traffic to the application.
+- Access control for your application.
+- Highly configurable logging and blocking rules.
-Out of the box, GitLab provides you with a WAF known as [`ModSecurity`](https://www.modsecurity.org/).
-
-ModSecurity is a toolkit for real-time web application monitoring, logging,
-and access control. With GitLab's offering, the [OWASP's Core Rule Set](https://www.modsecurity.org/CRS/Documentation/),
-which provides generic attack detection capabilities, is automatically applied.
+By default, GitLab provides you with a WAF known as [`ModSecurity`](https://www.modsecurity.org/),
+which is a toolkit for real-time web application monitoring, logging, and access
+control. GitLab's offering applies the [OWASP's Core Rule Set](https://www.modsecurity.org/CRS/Documentation/),
+which provides generic attack detection capabilities.
This feature:
@@ -299,57 +293,61 @@ There is a small performance overhead by enabling ModSecurity. If this is
considered significant for your application, you can disable ModSecurity's
rule engine for your deployed application in any of the following ways:
-1. Setting [the deployment variable](../../topics/autodevops/index.md)
-`AUTO_DEVOPS_MODSECURITY_SEC_RULE_ENGINE` to `Off`. This will prevent ModSecurity
-from processing any requests for the given application or environment.
-
-1. Switching its respective toggle to the disabled position and applying changes through the **Save changes** button. This will reinstall
-Ingress with the recent changes.
+1. Set the [deployment variable](../../topics/autodevops/index.md)
+ `AUTO_DEVOPS_MODSECURITY_SEC_RULE_ENGINE` to `Off` to prevent ModSecurity
+ from processing any requests for the given application or environment.
+1. Switch its respective toggle to the disabled position, and then apply changes
+ by selecting **Save changes** to reinstall Ingress with the recent changes.
![Disabling WAF](../../topics/web_application_firewall/img/guide_waf_ingress_save_changes_v12_10.png)
##### Logging and blocking modes
To help you tune your WAF rules, you can globally set your WAF to either
-**Logging** or **Blocking** mode:
+*Logging* or *Blocking* mode:
-- **Logging mode** - Allows traffic matching the rule to pass, and logs the event.
-- **Blocking mode** - Prevents traffic matching the rule from passing, and logs the event.
+- *Logging mode*: Allows traffic matching the rule to pass, and logs the event.
+- *Blocking mode*: Prevents traffic matching the rule from passing, and logs the event.
To change your WAF's mode:
-1. [Install ModSecurity](../../topics/web_application_firewall/quick_start_guide.md) if you have not already done so.
+1. If you haven't already done so, [install ModSecurity](../../topics/web_application_firewall/quick_start_guide.md).
1. Navigate to **Operations > Kubernetes**.
1. In **Applications**, scroll to **Ingress**.
1. Under **Global default**, select your desired mode.
-1. Click **Save changes**.
+1. Select **Save changes**.
##### WAF version updates
-Enabling, disabling, or changing the logging mode for **ModSecurity** is only allowed within same version of [Ingress](#ingress) due to limitations in [Helm](https://helm.sh/) which might be overcome in future releases.
+Enabling, disabling, or changing the logging mode for **ModSecurity** is only
+allowed within same version of [Ingress](#ingress) due to limitations in
+[Helm](https://helm.sh/) which might be overcome in future releases.
-**ModSecurity** UI controls are disabled if the version deployed differs from the one available in GitLab, while actions at the [Ingress](#ingress) level, such as uninstalling, can still be performed:
+**ModSecurity** user interface controls are disabled if the version deployed
+differs from the one available in GitLab, while actions at the [Ingress](#ingress)
+level, such as uninstalling, can still be performed:
![WAF settings disabled](../../topics/web_application_firewall/img/guide_waf_ingress_disabled_settings_v12_10.png)
-Updating [Ingress](#ingress) to the most recent version enables you to take advantage of bug fixes, security fixes, and performance improvements. To update [Ingress application](#ingress), you must first uninstall it, and then re-install it as described in [Install ModSecurity](../../topics/web_application_firewall/quick_start_guide.md).
+Update [Ingress](#ingress) to the most recent version to take advantage of bug
+fixes, security fixes, and performance improvements. To update the
+[Ingress application](#ingress), you must first uninstall it, and then re-install
+it as described in [Install ModSecurity](../../topics/web_application_firewall/quick_start_guide.md).
##### Viewing Web Application Firewall traffic
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/14707) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 12.9.
You can view Web Application Firewall traffic by navigating to your project's
-**Security & Compliance > Threat Monitoring** page.
-
-From there, you can see tracked over time:
+**Security & Compliance > Threat Monitoring** page. From there, you can see
+tracked over time:
- The total amount of traffic to your application.
-- The proportion of traffic that is considered anomalous by the Web Application
+- The proportion of traffic that's considered anomalous by the Web Application
Firewall's default [OWASP ruleset](https://www.modsecurity.org/CRS/Documentation/).
-If a significant percentage of traffic is anomalous, it should be investigated
-for potential threats, which can be done by
-[examining the Web Application Firewall logs](#web-application-firewall-modsecurity).
+If a significant percentage of traffic is anomalous, investigate it for potential threats
+by [examining the Web Application Firewall logs](#web-application-firewall-modsecurity).
![Threat Monitoring](img/threat_monitoring_v12_9.png)
@@ -358,55 +356,52 @@ for potential threats, which can be done by
> - Introduced in GitLab 11.0 for project-level clusters.
> - Introduced in GitLab 12.3 for group and instance-level clusters.
-[JupyterHub](https://jupyterhub.readthedocs.io/en/stable/) is a
-multi-user service for managing notebooks across a team. [Jupyter
-Notebooks](https://jupyter-notebook.readthedocs.io/en/latest/) provide a
-web-based interactive programming environment used for data analysis,
+[JupyterHub](https://jupyterhub.readthedocs.io/en/stable/) is a multi-user service
+for managing notebooks across a team. [Jupyter Notebooks](https://jupyter-notebook.readthedocs.io/en/latest/)
+provide a web-based interactive programming environment used for data analysis,
visualization, and machine learning.
-Authentication will be enabled only for [project
-members](../project/members/index.md) for project-level clusters and group
-members for group-level clusters with [Developer or
-higher](../permissions.md) access to the associated project or group.
-
-We use a [custom Jupyter
-image](https://gitlab.com/gitlab-org/jupyterhub-user-image/blob/master/Dockerfile)
-that installs additional useful packages on top of the base Jupyter. You
-will also see ready-to-use DevOps Runbooks built with Nurtch's [Rubix library](https://github.com/Nurtch/rubix).
-
-More information on
-creating executable runbooks can be found in [our Runbooks
-documentation](../project/clusters/runbooks/index.md#configure-an-executable-runbook-with-gitlab). Note that
-Ingress must be installed and have an IP address assigned before
-JupyterHub can be installed.
-
-NOTE: **Note:**
The [`jupyter/jupyterhub`](https://jupyterhub.github.io/helm-chart/)
chart is used to install this application with a
[`values.yaml`](https://gitlab.com/gitlab-org/gitlab/blob/master/vendor/jupyter/values.yaml)
file.
+Authentication is enabled only for [project members](../project/members/index.md)
+for project-level clusters and group members for group-level clusters with
+[Developer or higher](../permissions.md) access to the associated project or group.
+
+GitLab uses a [custom Jupyter image](https://gitlab.com/gitlab-org/jupyterhub-user-image/blob/master/Dockerfile)
+that installs additional useful packages on top of the base Jupyter. Ready-to-use
+DevOps Runbooks built with Nurtch's [Rubix library](https://github.com/Nurtch/rubix)
+are also available.
+
+More information on creating executable runbooks can be found in
+[our Runbooks documentation](../project/clusters/runbooks/index.md#configure-an-executable-runbook-with-gitlab).
+Ingress must be installed and have an IP address assigned before
+JupyterHub can be installed.
+
#### Jupyter Git Integration
> - [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/28783) in GitLab 12.0 for project-level clusters.
> - [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/32512) in GitLab 12.3 for group and instance-level clusters.
-When installing JupyterHub onto your Kubernetes cluster, [JupyterLab's Git extension](https://github.com/jupyterlab/jupyterlab-git)
-is automatically provisioned and configured using the authenticated user's:
+When installing JupyterHub onto your Kubernetes cluster,
+[JupyterLab's Git extension](https://github.com/jupyterlab/jupyterlab-git)
+is provisioned and configured using the authenticated user's:
- Name.
- Email.
- Newly created access token.
-JupyterLab's Git extension enables full version control of your notebooks as well as issuance of Git commands within Jupyter.
-Git commands can be issued via the **Git** tab on the left panel or via Jupyter's command line prompt.
+JupyterLab's Git extension enables full version control of your notebooks, and
+issuance of Git commands within Jupyter. You can issue Git commands through the
+**Git** tab on the left panel, or through Jupyter's command-line prompt.
-NOTE: **Note:**
-JupyterLab's Git extension stores the user token in the JupyterHub DB in encrypted format
-and in the single user Jupyter instance as plain text. This is because [Git requires storing
-credentials as plain text](https://git-scm.com/docs/git-credential-store). Potentially, if
-a nefarious user finds a way to read from the file system in the single user Jupyter instance
-they could retrieve the token.
+JupyterLab's Git extension stores the user token in the JupyterHub DB in encrypted
+format, and in the single user Jupyter instance as plain text, because
+[Git requires storing credentials as plain text](https://git-scm.com/docs/git-credential-store)
+Potentially, if a nefarious user finds a way to read from the file system in the
+single-user Jupyter instance, they could retrieve the token.
![Jupyter's Git Extension](img/jupyter-git-extension.gif)
@@ -421,22 +416,20 @@ You can clone repositories from the files tab in Jupyter:
[Knative](https://cloud.google.com/knative/) provides a platform to
create, deploy, and manage serverless workloads from a Kubernetes
-cluster. It is used in conjunction with, and includes
+cluster. It's used in conjunction with, and includes
[Istio](https://istio.io) to provide an external IP address for all
programs hosted by Knative.
-You will be prompted to enter a wildcard
-domain where your applications will be exposed. Configure your DNS
-server to use the external IP address for that domain. For any
-application created and installed, they will be accessible as
-`<program_name>.<kubernetes_namespace>.<domain_name>`. This will require
-your Kubernetes cluster to have [RBAC
-enabled](../project/clusters/add_remove_clusters.md#rbac-cluster-resources).
-
-NOTE: **Note:**
The [`knative/knative`](https://storage.googleapis.com/triggermesh-charts)
chart is used to install this application.
+During installation, you must enter a wildcard domain where your applications
+will be exposed. Configure your DNS server to use the external IP address for that
+domain. Applications created and installed are accessible as
+`<program_name>.<kubernetes_namespace>.<domain_name>`, which requires
+your Kubernetes cluster to have
+[RBAC enabled](../project/clusters/add_remove_clusters.md#rbac-cluster-resources).
+
### Prometheus
> - Introduced in GitLab 10.4 for project-level clusters.
@@ -446,20 +439,19 @@ chart is used to install this application.
open-source monitoring and alerting system useful to supervise your
deployed applications.
-GitLab is able to monitor applications automatically, using the
+GitLab is able to monitor applications by using the
[Prometheus integration](../project/integrations/prometheus.md). Kubernetes container CPU and
-memory metrics are automatically collected, and response metrics are retrieved
-from NGINX Ingress as well.
+memory metrics are collected, and response metrics are also retrieved
+from NGINX Ingress.
-To enable monitoring, simply install Prometheus into the cluster with the
-**Install** button.
-
-NOTE: **Note:**
The [`stable/prometheus`](https://github.com/helm/charts/tree/master/stable/prometheus)
chart is used to install this application with a
[`values.yaml`](https://gitlab.com/gitlab-org/gitlab/blob/master/vendor/prometheus/values.yaml)
file.
+To enable monitoring, install Prometheus into the cluster with the **Install**
+button.
+
### Crossplane
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/34702) in GitLab 12.5 for project-level clusters.
@@ -481,17 +473,16 @@ The Crossplane GitLab-managed application:
project repository.
- Can then be used to provision infrastructure or managed applications such as
PostgreSQL (for example, CloudSQL from GCP or RDS from AWS) and other services
- required by the application via the Auto DevOps pipeline.
+ required by the application with the Auto DevOps pipeline.
-For information on configuring Crossplane installed on the cluster, see
-[Crossplane configuration](crossplane.md).
-
-NOTE: **Note:**
[`alpha/crossplane`](https://github.com/crossplane/crossplane/tree/v0.4.1/cluster/charts/crossplane) chart v0.4.1 is used to
install Crossplane using the
[`values.yaml`](https://github.com/crossplane/crossplane/blob/master/cluster/charts/crossplane/values.yaml.tmpl)
file.
+For information about configuring Crossplane installed on the cluster, see
+[Crossplane configuration](crossplane.md).
+
### Elastic Stack
> Introduced in GitLab 12.7 for project- and group-level clusters.
@@ -500,37 +491,32 @@ file.
log analysis solution which helps in deep searching, analyzing and visualizing the logs
generated from different machines.
-GitLab is able to gather logs from pods in your cluster automatically.
-Filebeat will run as a DaemonSet on each node in your cluster, and it will ship container logs to Elasticsearch for querying.
-GitLab will then connect to Elasticsearch for logs instead of the Kubernetes API,
-and you will have access to more advanced querying capabilities.
+GitLab can gather logs from pods in your cluster. Filebeat runs as a DaemonSet
+on each node in your cluster, and ships container logs to Elasticsearch for
+querying. GitLab then connects to Elasticsearch for logs, instead of the
+Kubernetes API, giving you access to more advanced querying capabilities. Log
+data is deleted after 30 days, using [Curator](https://www.elastic.co/guide/en/elasticsearch/client/curator/5.5/about.html).
-Log data is automatically deleted after 30 days using [Curator](https://www.elastic.co/guide/en/elasticsearch/client/curator/5.5/about.html).
+The Elastic Stack cluster application is intended as a log aggregation solution
+and is not related to our [Advanced Search](../search/advanced_global_search.md)
+functionality, which uses a separate Elasticsearch cluster.
To enable log shipping:
-1. Ensure your cluster contains at least 3 nodes of instance types larger than
- `f1-micro`, `g1-small`, or `n1-standard-1`.
+1. Ensure your cluster contains at least three nodes of instance types larger
+ than `f1-micro`, `g1-small`, or `n1-standard-1`.
1. Navigate to **Operations > Kubernetes**.
1. In **Kubernetes Cluster**, select a cluster.
-1. In the **Applications** section, find **Elastic Stack** and click **Install**.
+1. In the **Applications** section, find **Elastic Stack**, and then select
+ **Install**.
-NOTE: **Note:**
The [`gitlab/elastic-stack`](https://gitlab.com/gitlab-org/charts/elastic-stack)
chart is used to install this application with a
[`values.yaml`](https://gitlab.com/gitlab-org/gitlab/blob/master/vendor/elastic_stack/values.yaml)
-file.
-
-NOTE: **Note:**
-The chart deploys 3 identical Elasticsearch pods which can't be colocated, and each
-requires 1 CPU and 2 GB of RAM, making them incompatible with clusters containing
-fewer than 3 nodes or consisting of `f1-micro`, `g1-small`, `n1-standard-1`, or
-`*-highcpu-2` instance types.
-
-NOTE: **Note:**
-The Elastic Stack cluster application is intended as a log aggregation solution and is not related to our
-[Advanced Search](../search/advanced_global_search.md) functionality, which uses a separate
-Elasticsearch cluster.
+file. The chart deploys three identical Elasticsearch pods which can't be
+colocated, and each requires one CPU and 2 GB of RAM, making them
+incompatible with clusters containing fewer than three nodes, or consisting of
+`f1-micro`, `g1-small`, `n1-standard-1`, or `*-highcpu-2` instance types.
#### Optional: deploy Kibana to perform advanced queries
@@ -578,8 +564,8 @@ your data. Fluentd sends logs in syslog format.
To enable Fluentd:
1. Navigate to **Operations > Kubernetes** and click
- **Applications**. You will be prompted to enter a host, port and protocol
- where the WAF logs will be sent to via syslog.
+ **Applications**. Enter a host, port, and protocol
+ for sending the WAF logs with syslog.
1. Provide the host domain name or URL in **SIEM Hostname**.
1. Provide the host port number in **SIEM Port**.
1. Select a **SIEM Protocol**.
@@ -599,7 +585,7 @@ to get started.
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/20822) in GitLab 12.6.
CAUTION: **Warning:**
-This is an _alpha_ feature, and it is subject to change at any time without
+This is an _alpha_ feature, and is subject to change at any time without
prior notice.
This alternative method allows users to install GitLab-managed
@@ -639,7 +625,6 @@ To install applications using GitLab CI/CD:
- template: Managed-Cluster-Applications.gitlab-ci.yml
```
- NOTE: **Note:**
The job provided by this template connects to the cluster using tools provided
in a custom Docker image. It requires that you have a runner registered with the Docker,
Kubernetes, or Docker Machine executor.
@@ -657,11 +642,10 @@ To install applications using GitLab CI/CD:
1. Optionally, define `.gitlab/managed-apps/<application>/values.yaml` file to
customize values for the installed application.
-A GitLab CI/CD pipeline will then run on the `master` branch to install the
+A GitLab CI/CD pipeline runs on the `master` branch to install the
applications you have configured. In case of pipeline failure, the
-output of the [Helm
-Tiller](https://v2.helm.sh/docs/install/#running-tiller-locally) binary
-will be saved as a [CI job artifact](../../ci/pipelines/job_artifacts.md).
+output of the [Helm Tiller](https://v2.helm.sh/docs/install/#running-tiller-locally) binary
+is saved as a [CI job artifact](../../ci/pipelines/job_artifacts.md).
### Important notes
@@ -669,10 +653,10 @@ Note the following:
- We recommend using the cluster management project exclusively for managing deployments to a cluster.
Do not add your application's source code to such projects.
-- When you set the value for `installed` key back to `false`, the application will be
+- When you set the value for `installed` key back to `false`, the application is
unprovisioned from the cluster.
- If you update `.gitlab/managed-apps/<application>/values.yaml` with new values, the
- application will be redeployed.
+ application is redeployed.
### Install Ingress using GitLab CI/CD
@@ -684,7 +668,7 @@ ingress:
installed: true
```
-Ingress will then be installed into the `gitlab-managed-apps` namespace
+Ingress is installed into the `gitlab-managed-apps` namespace
of your cluster.
You can customize the installation of Ingress by defining a
@@ -693,9 +677,10 @@ management project. Refer to the
[chart](https://github.com/helm/charts/tree/master/stable/nginx-ingress)
for the available configuration options.
-NOTE: **Note:**
Support for installing the Ingress managed application is provided by the GitLab Configure group.
-If you run into unknown issues, please [open a new issue](https://gitlab.com/gitlab-org/gitlab/-/issues/new) and ping at least 2 people from the [Configure group](https://about.gitlab.com/handbook/product/product-categories/#configure-group).
+If you run into unknown issues, [open a new issue](https://gitlab.com/gitlab-org/gitlab/-/issues/new),
+and ping at least 2 people from the
+[Configure group](https://about.gitlab.com/handbook/product/product-categories/#configure-group).
### Install cert-manager using GitLab CI/CD
@@ -705,7 +690,8 @@ cert-manager is installed using GitLab CI/CD by defining configuration in
cert-manager:
- Is installed into the `gitlab-managed-apps` namespace of your cluster.
-- Can be installed with or without a default [Let's Encrypt `ClusterIssuer`](https://cert-manager.io/docs/configuration/acme/), which requires an
+- Can be installed with or without a default
+ [Let's Encrypt `ClusterIssuer`](https://cert-manager.io/docs/configuration/acme/), which requires an
email address to be specified. The email address is used by Let's Encrypt to
contact you about expiring certificates and issues related to your account.
@@ -734,14 +720,16 @@ management project. Refer to the
[chart](https://hub.helm.sh/charts/jetstack/cert-manager) for the
available configuration options.
-NOTE: **Note:**
-Support for installing the Cert Manager managed application is provided by the GitLab Configure group.
-If you run into unknown issues, please [open a new issue](https://gitlab.com/gitlab-org/gitlab/-/issues/new) and ping at least 2 people from the [Configure group](https://about.gitlab.com/handbook/product/product-categories/#configure-group).
+Support for installing the Cert Manager managed application is provided by the
+GitLab Configure group. If you run into unknown issues,
+[open a new issue](https://gitlab.com/gitlab-org/gitlab/-/issues/new), and ping at
+least 2 people from the
+[Configure group](https://about.gitlab.com/handbook/product/product-categories/#configure-group).
### Install Sentry using GitLab CI/CD
-NOTE: **Note:**
-The Sentry Helm chart [recommends](https://github.com/helm/charts/blob/f6e5784f265dd459c5a77430185d0302ed372665/stable/sentry/values.yaml#L284-L285) at least 3GB of available RAM for database migrations.
+The Sentry Helm chart [recommends](https://github.com/helm/charts/blob/f6e5784f265dd459c5a77430185d0302ed372665/stable/sentry/values.yaml#L284-L285)
+at least 3 GB of available RAM for database migrations.
To install Sentry, define the `.gitlab/managed-apps/config.yaml` file
with:
@@ -751,7 +739,7 @@ sentry:
installed: true
```
-Sentry will then be installed into the `gitlab-managed-apps` namespace
+Sentry is installed into the `gitlab-managed-apps` namespace
of your cluster.
You can customize the installation of Sentry by defining
@@ -766,8 +754,10 @@ We recommend you pay close attention to the following configuration options:
- `user`. Where you can set the login credentials for the default admin user.
- `postgresql`. For a PostgreSQL password that can be used when running future updates.
-NOTE: **Note:**
-When upgrading it is important to provide the existing PostgreSQL password (given using the `postgresql.postgresqlPassword` key) or you will receive authentication errors. See the [PostgreSQL chart documentation](https://github.com/helm/charts/tree/master/stable/postgresql#upgrade) for more information.
+When upgrading, it's important to provide the existing PostgreSQL password (given
+using the `postgresql.postgresqlPassword` key) to avoid authentication errors.
+Read the [PostgreSQL chart documentation](https://github.com/helm/charts/tree/master/stable/postgresql#upgrade)
+for more information.
Here is an example configuration for Sentry:
@@ -799,9 +789,11 @@ postgresql:
postgresqlPassword: example-postgresql-password
```
-NOTE: **Note:**
-Support for installing the Sentry managed application is provided by the GitLab Health group.
-If you run into unknown issues, please [open a new issue](https://gitlab.com/gitlab-org/gitlab/-/issues/new) and ping at least 2 people from the [Health group](https://about.gitlab.com/handbook/product/product-categories/#health-group).
+Support for installing the Sentry managed application is provided by the
+GitLab Health group. If you run into unknown issues,
+[open a new issue](https://gitlab.com/gitlab-org/gitlab/-/issues/new), and ping at
+least 2 people from the
+[Health group](https://about.gitlab.com/handbook/product/product-categories/#health-group).
### Install PostHog using GitLab CI/CD
@@ -816,13 +808,14 @@ posthog:
```
You can customize the installation of PostHog by defining `.gitlab/managed-apps/posthog/values.yaml`
-in your cluster management project. Refer to the [Configuration section of the PostHog chart's README](https://github.com/PostHog/charts/tree/master/charts/posthog)
+in your cluster management project. Refer to the
+[Configuration section of the PostHog chart's README](https://github.com/PostHog/charts/tree/master/charts/posthog)
for the available configuration options.
-NOTE: **Note:**
You must provide a PostgreSQL password in `postgresql.postgresqlPassword`
-or you will receive authentication errors.
-See the [PostgreSQL chart documentation](https://github.com/helm/charts/tree/master/stable/postgresql#upgrade) for more information.
+to avoid authentication errors. Read the
+[PostgreSQL chart documentation](https://github.com/helm/charts/tree/master/stable/postgresql#upgrade)
+for more information.
Redis pods are restarted between upgrades. To prevent downtime, provide a Redis
password using the `redis.password` key. This prevents a new password from
@@ -848,9 +841,9 @@ redis:
password: example-redis-password
```
-NOTE: **Note:**
Support for the PostHog managed application is provided by the PostHog team.
-If you run into issues, please [open a support ticket](https://github.com/PostHog/posthog/issues/new/choose) directly.
+If you run into issues,
+[open a support ticket](https://github.com/PostHog/posthog/issues/new/choose) directly.
### Install Prometheus using GitLab CI/CD
@@ -874,9 +867,10 @@ project. Refer to the
[Configuration section of the Prometheus chart's README](https://github.com/helm/charts/tree/master/stable/prometheus#configuration)
for the available configuration options.
-NOTE: **Note:**
-Support for installing the Prometheus managed application is provided by the GitLab APM group.
-If you run into unknown issues, please [open a new issue](https://gitlab.com/gitlab-org/gitlab/-/issues/new) and ping at least 2 people from the [APM group](https://about.gitlab.com/handbook/product/product-categories/#apm-group).
+Support for installing the Prometheus managed application is provided by the
+GitLab APM group. If you run into unknown issues,
+[open a new issue](https://gitlab.com/gitlab-org/gitlab/-/issues/new), and ping at
+least 2 people from the [APM group](https://about.gitlab.com/handbook/product/product-categories/#apm-group).
### Install GitLab Runner using GitLab CI/CD
@@ -892,16 +886,17 @@ gitlabRunner:
GitLab Runner is installed into the `gitlab-managed-apps` namespace of your cluster.
-In order for GitLab Runner to function, you **must** specify the following:
+For GitLab Runner to function, you _must_ specify the following:
-- `gitlabUrl` - the GitLab server full URL (for example, `https://gitlab.example.com`) to register the Runner against.
-- `runnerRegistrationToken` - The registration token for adding new runners to GitLab. This must be
- [retrieved from your GitLab instance](../../ci/runners/README.md).
+- `gitlabUrl`: The GitLab server full URL (for example, `https://gitlab.example.com`)
+ to register the Runner against.
+- `runnerRegistrationToken`: The registration token for adding new runners to GitLab.
+ This must be [retrieved from your GitLab instance](../../ci/runners/README.md).
These values can be specified using [CI variables](../../ci/variables/README.md):
-- `GITLAB_RUNNER_GITLAB_URL` will be used for `gitlabUrl`.
-- `GITLAB_RUNNER_REGISTRATION_TOKEN` will be used for `runnerRegistrationToken`
+- `GITLAB_RUNNER_GITLAB_URL` is used for `gitlabUrl`.
+- `GITLAB_RUNNER_REGISTRATION_TOKEN` is used for `runnerRegistrationToken`
You can customize the installation of GitLab Runner by defining
`.gitlab/managed-apps/gitlab-runner/values.yaml` file in your cluster
@@ -909,9 +904,11 @@ management project. Refer to the
[chart](https://gitlab.com/gitlab-org/charts/gitlab-runner) for the
available configuration options.
-NOTE: **Note:**
-Support for installing the GitLab Runner managed application is provided by the GitLab Runner group.
-If you run into unknown issues, please [open a new issue](https://gitlab.com/gitlab-org/gitlab/-/issues/new) and ping at least 2 people from the [Runner group](https://about.gitlab.com/handbook/product/product-categories/#runner-group).
+Support for installing the GitLab Runner managed application is provided by the
+GitLab Runner group. If you run into unknown issues,
+[open a new issue](https://gitlab.com/gitlab-org/gitlab/-/issues/new), and ping at
+least 2 people from the
+[Runner group](https://about.gitlab.com/handbook/product/product-categories/#runner-group).
### Install Cilium using GitLab CI/CD
@@ -948,8 +945,10 @@ for the available configuration options.
You can check Cilium's installation status on the cluster management page:
-- [Project-level cluster](../project/clusters/index.md): Navigate to your project's **Operations > Kubernetes** page.
-- [Group-level cluster](../group/clusters/index.md): Navigate to your group's **Kubernetes** page.
+- [Project-level cluster](../project/clusters/index.md): Navigate to your project's
+ **Operations > Kubernetes** page.
+- [Group-level cluster](../group/clusters/index.md): Navigate to your group's
+ **Kubernetes** page.
CAUTION: **Caution:**
Installation and removal of the Cilium requires a **manual**
@@ -959,12 +958,11 @@ of all affected pods in all namespaces to ensure that they are
by the correct networking plugin.
NOTE: **Note:**
-Major upgrades might require additional setup steps, please consult
-the official [upgrade guide](https://docs.cilium.io/en/stable/install/upgrade/) for more
-information.
+Major upgrades might require additional setup steps. For more information, see
+the official [upgrade guide](https://docs.cilium.io/en/stable/install/upgrade/).
-By default, Cilium's [audit
-mode](https://docs.cilium.io/en/v1.8/gettingstarted/policy-creation/?highlight=policy-audit#enable-policy-audit-mode)
+By default, Cilium's
+[audit mode](https://docs.cilium.io/en/v1.8/gettingstarted/policy-creation/?highlight=policy-audit#enable-policy-audit-mode)
is enabled. In audit mode, Cilium doesn't drop disallowed packets. You
can use `policy-verdict` log to observe policy-related decisions. You
can disable audit mode by adding the following to
@@ -1006,7 +1004,7 @@ global:
enabled: false
```
-You can also adjust Helm values for Hubble via
+You can also adjust Helm values for Hubble by using
`.gitlab/managed-apps/cilium/values.yaml`:
```yaml
@@ -1018,9 +1016,11 @@ global:
- 'flow:sourceContext=namespace;destinationContext=namespace'
```
-NOTE: **Note:**
-Support for installing the Cilium managed application is provided by the GitLab Container Security group.
-If you run into unknown issues, please [open a new issue](https://gitlab.com/gitlab-org/gitlab/-/issues/new) and ping at least 2 people from the [Container Security group](https://about.gitlab.com/handbook/product/product-categories/#container-security-group).
+Support for installing the Cilium managed application is provided by the
+GitLab Container Security group. If you run into unknown issues,
+[open a new issue](https://gitlab.com/gitlab-org/gitlab/-/issues/new), and ping at
+least 2 people from the
+[Container Security group](https://about.gitlab.com/handbook/product/product-categories/#container-security-group).
### Install Falco using GitLab CI/CD
@@ -1046,17 +1046,20 @@ management project. Refer to the
for the available configuration options.
CAUTION: **Caution:**
-By default eBPF support is enabled and Falco will use an [eBPF probe](https://falco.org/docs/event-sources/drivers/#using-the-ebpf-probe) to pass system calls to userspace.
-If your cluster doesn't support this, you can configure it to use Falco kernel module instead by adding the following to `.gitlab/managed-apps/falco/values.yaml`:
+By default eBPF support is enabled and Falco uses an
+[eBPF probe](https://falco.org/docs/event-sources/drivers/#using-the-ebpf-probe)
+to pass system calls to user space. If your cluster doesn't support this, you can
+configure it to use Falco kernel module instead by adding the following to
+`.gitlab/managed-apps/falco/values.yaml`:
```yaml
ebpf:
enabled: false
```
-In rare cases where automatic probe installation on your cluster isn't possible and the kernel/probe
-isn't precompiled, you may need to manually prepare the kernel module or eBPF probe with
-[driverkit](https://github.com/falcosecurity/driverkit#against-a-kubernetes-cluster)
+In rare cases where probe installation on your cluster isn't possible and the kernel/probe
+isn't pre-compiled, you may need to manually prepare the kernel module or eBPF probe with
+[`driverkit`](https://github.com/falcosecurity/driverkit#against-a-kubernetes-cluster)
and install it on each cluster node.
By default, Falco is deployed with a limited set of rules. To add more rules, add the following to
@@ -1109,22 +1112,27 @@ You can check these logs with the following command:
kubectl -n gitlab-managed-apps logs -l app=falco
```
-NOTE: **Note:**
-Support for installing the Falco managed application is provided by the GitLab Container Security group.
-If you run into unknown issues, please [open a new issue](https://gitlab.com/gitlab-org/gitlab/-/issues/new) and ping at least 2 people from the [Container Security group](https://about.gitlab.com/handbook/product/product-categories/#container-security-group).
+Support for installing the Falco managed application is provided by the
+GitLab Container Security group. If you run into unknown issues,
+[open a new issue](https://gitlab.com/gitlab-org/gitlab/-/issues/new), and ping at
+least 2 people from the
+[Container Security group](https://about.gitlab.com/handbook/product/product-categories/#container-security-group).
### Install Vault using GitLab CI/CD
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/9982) in GitLab 12.9.
-[Hashicorp Vault](https://www.vaultproject.io/) is a secrets management solution which
-can be used to safely manage and store passwords, credentials, certificates and more. A Vault
+[HashiCorp Vault](https://www.vaultproject.io/) is a secrets management solution which
+can be used to safely manage and store passwords, credentials, certificates, and more. A Vault
installation could be leveraged to provide a single secure data store for credentials
used in your applications, GitLab CI/CD jobs, and more. It could also serve as a way of
providing SSL/TLS certificates to systems and deployments in your infrastructure. Leveraging
Vault as a single source for all these credentials allows greater security by having
a single source of access, control, and auditability around all your sensitive
-credentials and certificates.
+credentials and certificates. This feature requires giving GitLab the highest level of access and
+control. Therefore, if GitLab is compromised, the security of this Vault instance is as well. To
+avoid this security risk, GitLab recommends using your own HashiCorp Vault to leverage
+[external secrets with CI](../../ci/secrets/index.md).
To install Vault, enable it in the `.gitlab/managed-apps/config.yaml` file:
@@ -1133,24 +1141,25 @@ vault:
installed: true
```
-By default you will get a basic Vault setup with no scalable
-storage backend. This is enough for simple testing and small-scale deployments, though has limits
-to how much it can scale, and as it is a single instance deployment, you will experience downtime
-when upgrading the Vault application.
+By default you receive a basic Vault setup with no scalable storage backend. This
+is enough for simple testing and small-scale deployments, though has limits
+to how much it can scale, and as it's a single instance deployment, upgrading the
+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
-[the Vault documentation](https://www.vaultproject.io/docs/internals) as well as
+of the internals of Vault and how to configure it. This can be done by reading
+the [Vault Configuration guide](../../ci/secrets/#configure-your-vault-server),
+the [Vault documentation](https://www.vaultproject.io/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 you will likely set up:
+At a minimum, most users set up:
- A [seal](https://www.vaultproject.io/docs/configuration/seal) for extra encryption
- of the master key.
-- A [storage backend](https://www.vaultproject.io/docs/configuration/storage) that is
+ of the main key.
+- A [storage backend](https://www.vaultproject.io/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).
+- The [Vault UI](https://www.vaultproject.io/docs/configuration/ui).
The following is an example values file (`.gitlab/managed-apps/vault/values.yaml`)
that configures Google Key Management Service for auto-unseal, using a Google Cloud Storage backend, enabling
@@ -1180,7 +1189,7 @@ server:
path = "gcs://my-vault-storage/vault-bucket"
ha_enabled = "true"
}
- # Configure Vault to automatically unseal storage using a GKMS key
+ # Configure Vault to unseal storage using a GKMS key
seal "gcpckms" {
project = "vault-helm-dev-246514"
region = "global"
@@ -1189,10 +1198,13 @@ server:
}
```
-Once you have successfully installed Vault, you will need to [initialize the Vault](https://learn.hashicorp.com/tutorials/vault/getting-started-deploy#initializing-the-vault)
-and obtain the initial root token. You will need access to your Kubernetes cluster that Vault has been deployed into in order to do this.
-To initialize the Vault, get a shell to one of the Vault pods running inside Kubernetes (typically this is done by using the `kubectl` command line tool).
-Once you have a shell into the pod, run the `vault operator init` command:
+Once you have successfully installed Vault, you must
+[initialize the Vault](https://learn.hashicorp.com/tutorials/vault/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 in order to do this. To initialize the Vault, get a
+shell to one of the Vault pods running inside Kubernetes (typically this is done
+by using the `kubectl` command line tool). Once you have a shell into the pod,
+run the `vault operator init` command:
```shell
kubectl -n gitlab-managed-apps exec -it vault-0 sh
@@ -1200,11 +1212,13 @@ kubectl -n gitlab-managed-apps exec -it vault-0 sh
```
This should give you your unseal keys and initial root token. Make sure to note these down
-and keep these safe as you will need them to unseal the Vault throughout its lifecycle.
+and keep these safe, as they're required to unseal the Vault throughout its lifecycle.
-NOTE: **Note:**
-Support for installing the Vault managed application is provided by the GitLab Release Management group.
-If you run into unknown issues, please [open a new issue](https://gitlab.com/gitlab-org/gitlab/-/issues/new) and ping at least 2 people from the [Release Management group](https://about.gitlab.com/handbook/product/product-categories/#release-management-group).
+Support for installing the Vault managed application is provided by the
+GitLab Release Management group. If you run into unknown issues,
+[open a new issue](https://gitlab.com/gitlab-org/gitlab/-/issues/new), and ping at
+least 2 people from the
+[Release Management group](https://about.gitlab.com/handbook/product/product-categories/#release-management-group).
### Install JupyterHub using GitLab CI/CD
@@ -1224,7 +1238,7 @@ In the configuration:
- `gitlabProjectIdWhitelist` restricts GitLab authentication to only members of the specified projects.
- `gitlabGroupWhitelist` restricts GitLab authentication to only members of the specified groups.
-- Specifying an empty array for both will allow any user on the GitLab instance to sign in.
+- Specifying an empty array for both allows any user on the GitLab instance to sign in.
JupyterHub is installed into the `gitlab-managed-apps` namespace of your cluster.
@@ -1236,17 +1250,19 @@ Set:
In addition, the following variables must be specified using [CI variables](../../ci/variables/README.md):
-| CI Variable | Description |
-|:---------------------------------------|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| `JUPYTERHUB_PROXY_SECRET_TOKEN` | Secure string used for signing communications from the hub. See[`proxy.secretToken`](https://zero-to-jupyterhub.readthedocs.io/en/stable/reference/reference.html#proxy-secrettoken). |
-| `JUPYTERHUB_COOKIE_SECRET` | Secure string used for signing secure cookies. See [`hub.cookieSecret`](https://zero-to-jupyterhub.readthedocs.io/en/stable/reference/reference.html#hub-cookiesecret). |
-| `JUPYTERHUB_HOST` | Hostname used for the installation. For example, `jupyter.gitlab.example.com`. |
-| `JUPYTERHUB_GITLAB_HOST` | Hostname of the GitLab instance used for authentication. For example, `gitlab.example.com`. |
-| `JUPYTERHUB_AUTH_CRYPTO_KEY` | A 32-byte encryption key used to set [`auth.state.cryptoKey`](https://zero-to-jupyterhub.readthedocs.io/en/stable/reference/reference.html#auth-state-cryptokey). |
-| `JUPYTERHUB_AUTH_GITLAB_CLIENT_ID` | "Application ID" for the OAuth Application. |
-| `JUPYTERHUB_AUTH_GITLAB_CLIENT_SECRET` | "Secret" for the OAuth Application. |
-
-By default, JupyterHub will be installed using a
+- `JUPYTERHUB_PROXY_SECRET_TOKEN` - Secure string used for signing communications
+ from the hub. Read [`proxy.secretToken`](https://zero-to-jupyterhub.readthedocs.io/en/stable/reference/reference.html#proxy-secrettoken).
+- `JUPYTERHUB_COOKIE_SECRET` - Secure string used for signing secure cookies. Read
+ [`hub.cookieSecret`](https://zero-to-jupyterhub.readthedocs.io/en/stable/reference/reference.html#hub-cookiesecret).
+- `JUPYTERHUB_HOST` - Hostname used for the installation. For example, `jupyter.gitlab.example.com`.
+- `JUPYTERHUB_GITLAB_HOST` - Hostname of the GitLab instance used for authentication.
+ For example, `gitlab.example.com`.
+- `JUPYTERHUB_AUTH_CRYPTO_KEY` - A 32-byte encryption key used to set
+ [`auth.state.cryptoKey`](https://zero-to-jupyterhub.readthedocs.io/en/stable/reference/reference.html#auth-state-cryptokey).
+- `JUPYTERHUB_AUTH_GITLAB_CLIENT_ID` - "Application ID" for the OAuth Application.
+- `JUPYTERHUB_AUTH_GITLAB_CLIENT_SECRET` - "Secret" for the OAuth Application.
+
+By default, JupyterHub is installed using a
[default values file](https://gitlab.com/gitlab-org/cluster-integration/cluster-applications/-/blob/master/src/default-data/jupyterhub/values.yaml.gotmpl).
You can customize the installation of JupyterHub by defining a
`.gitlab/managed-apps/jupyterhub/values.yaml` file in your cluster management project.
@@ -1255,9 +1271,11 @@ Refer to the
[chart reference](https://zero-to-jupyterhub.readthedocs.io/en/stable/reference/reference.html) for the
available configuration options.
-NOTE: **Note:**
Support for installing the JupyterHub managed application is provided by the GitLab Configure group.
-If you run into unknown issues, please [open a new issue](https://gitlab.com/gitlab-org/gitlab/-/issues/new) and ping at least 2 people from the [Configure group](https://about.gitlab.com/handbook/product/product-categories/#configure-group).
+If you run into unknown issues,
+[open a new issue](https://gitlab.com/gitlab-org/gitlab/-/issues/new), and ping at
+least 2 people from the
+[Configure group](https://about.gitlab.com/handbook/product/product-categories/#configure-group).
### Install Elastic Stack using GitLab CI/CD
@@ -1275,20 +1293,25 @@ elasticStack:
Elastic Stack is installed into the `gitlab-managed-apps` namespace of your cluster.
-You can check the default [`values.yaml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/vendor/elastic_stack/values.yaml) we set for this chart.
+You can check the default
+[`values.yaml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/vendor/elastic_stack/values.yaml)
+we set for this chart.
You can customize the installation of Elastic Stack by defining
`.gitlab/managed-apps/elastic-stack/values.yaml` file in your cluster
management project. Refer to the
-[chart](https://gitlab.com/gitlab-org/charts/elastic-stack) for the
+[chart](https://gitlab.com/gitlab-org/charts/elastic-stack) for all
available configuration options.
NOTE: **Note:**
-In this alpha implementation of installing Elastic Stack through CI, reading the environment logs through Elasticsearch is unsupported. This is supported if [installed via the UI](#elastic-stack).
+In this alpha implementation of installing Elastic Stack through CI, reading the
+environment logs through Elasticsearch is unsupported. This is supported if
+[installed with the UI](#elastic-stack).
-NOTE: **Note:**
-Support for installing the Elastic Stack managed application is provided by the GitLab APM group.
-If you run into unknown issues, please [open a new issue](https://gitlab.com/gitlab-org/gitlab/-/issues/new) and ping at least 2 people from the [APM group](https://about.gitlab.com/handbook/product/product-categories/#apm-group).
+Support for installing the Elastic Stack managed application is provided by the
+GitLab APM group. If you run into unknown issues,
+[open a new issue](https://gitlab.com/gitlab-org/gitlab/-/issues/new), and ping at
+least 2 people from the [APM group](https://about.gitlab.com/handbook/product/product-categories/#apm-group).
### Install Crossplane using GitLab CI/CD
@@ -1316,37 +1339,40 @@ management project. Refer to the
[chart](https://github.com/crossplane/crossplane/tree/master/cluster/charts/crossplane#configuration) for the
available configuration options. Note that this link points to the documentation for the current development release, which may differ from the version you have installed.
-NOTE: **Note:**
Support for the Crossplane managed application is provided by the Crossplane team.
-If you run into issues, please [open a support ticket](https://github.com/crossplane/crossplane/issues/new/choose) directly.
+If you run into issues,
+[open a support ticket](https://github.com/crossplane/crossplane/issues/new/choose) directly.
### Install Fluentd using GitLab CI/CD
> [Introduced](https://gitlab.com/gitlab-org/cluster-integration/cluster-applications/-/merge_requests/76) in GitLab 12.10.
-To install Fluentd into the `gitlab-managed-apps` namespace of your cluster using GitLab CI/CD, define the following configuration in `.gitlab/managed-apps/config.yaml`:
+To install Fluentd into the `gitlab-managed-apps` namespace of your cluster using
+GitLab CI/CD, define the following configuration in `.gitlab/managed-apps/config.yaml`:
```yaml
Fluentd:
installed: true
```
-You can also review the default values set for this chart in the [`values.yaml`](https://github.com/helm/charts/blob/master/stable/fluentd/values.yaml) file.
+You can also review the default values set for this chart in the
+[`values.yaml`](https://github.com/helm/charts/blob/master/stable/fluentd/values.yaml) file.
You can customize the installation of Fluentd by defining
`.gitlab/managed-apps/fluentd/values.yaml` file in your cluster management
project. Refer to the
[configuration chart for the current development release of Fluentd](https://github.com/helm/charts/tree/master/stable/fluentd#configuration)
-for the available configuration options.
+for all available configuration options.
-NOTE: **Note:**
The configuration chart link points to the current development release, which
may differ from the version you have installed. To ensure compatibility, switch
to the specific branch or tag you are using.
-NOTE: **Note:**
-Support for installing the Fluentd managed application is provided by the GitLab Container Security group.
-If you run into unknown issues, please [open a new issue](https://gitlab.com/gitlab-org/gitlab/-/issues/new) and ping at least 2 people from the [Container Security group](https://about.gitlab.com/handbook/product/product-categories/#container-security-group).
+Support for installing the Fluentd managed application is provided by the
+GitLab Container Security group. If you run into unknown issues,
+[open a new issue](https://gitlab.com/gitlab-org/gitlab/-/issues/new), and ping at
+least 2 people from the
+[Container Security group](https://about.gitlab.com/handbook/product/product-categories/#container-security-group).
### Install Knative using GitLab CI/CD
@@ -1360,7 +1386,7 @@ knative:
You can customize the installation of Knative by defining `.gitlab/managed-apps/knative/values.yaml`
file in your cluster management project. Refer to the [chart](https://gitlab.com/gitlab-org/charts/knative)
-for the available configuration options.
+for all available configuration options.
Here is an example configuration for Knative:
@@ -1368,11 +1394,14 @@ Here is an example configuration for Knative:
domain: 'my.wildcard.A.record.dns'
```
-If you plan to use GitLab Serverless capabilities, be sure to set an A record wildcard domain on your custom configuration.
+If you plan to use GitLab Serverless capabilities, be sure to set an `A record`
+wildcard domain on your custom configuration.
-NOTE: **Note:**
-Support for installing the Knative managed application is provided by the GitLab Configure group.
-If you run into unknown issues, please [open a new issue](https://gitlab.com/gitlab-org/gitlab/-/issues/new) and ping at least 2 people from the [Configure group](https://about.gitlab.com/handbook/product/product-categories/#configure-group).
+Support for installing the Knative managed application is provided by the
+GitLab Configure group. If you run into unknown issues,
+[open a new issue](https://gitlab.com/gitlab-org/gitlab/-/issues/new), and ping at
+least 2 people from the
+[Configure group](https://about.gitlab.com/handbook/product/product-categories/#configure-group).
#### Knative Metrics
@@ -1398,14 +1427,16 @@ kubectl delete -f https://gitlab.com/gitlab-org/cluster-integration/cluster-appl
> [Introduced](https://gitlab.com/gitlab-org/cluster-integration/cluster-applications/-/merge_requests/100) in GitLab 13.1.
-To install AppArmor into the `gitlab-managed-apps` namespace of your cluster using GitLab CI/CD, define the following configuration in `.gitlab/managed-apps/config.yaml`:
+To install AppArmor into the `gitlab-managed-apps` namespace of your cluster using
+GitLab CI/CD, define the following configuration in `.gitlab/managed-apps/config.yaml`:
```yaml
apparmor:
installed: true
```
-You can define one or more AppArmor profiles by adding them into `.gitlab/managed-apps/apparmor/values.yaml` as the following:
+You can define one or more AppArmor profiles by adding them into
+`.gitlab/managed-apps/apparmor/values.yaml` as the following:
```yaml
profiles:
@@ -1419,25 +1450,27 @@ Refer to the [AppArmor chart](https://gitlab.com/gitlab-org/charts/apparmor) for
#### Using AppArmor profiles in your deployments
-After installing AppAmor, you can use profiles by adding Pod Annotations. If you're using Auto
-DevOps, you can [customize `auto-deploy-values.yaml`](../../topics/autodevops/customize.md#customize-values-for-helm-chart)
-to annotate your pods. Although it's helpful to be aware of the [list of custom attributes](https://gitlab.com/gitlab-org/cluster-integration/auto-deploy-image/-/tree/master/assets/auto-deploy-app#gitlabs-auto-deploy-helm-chart), you're only required to set
-`podAnnotations` as follows:
+After installing AppAmor, you can use profiles by adding Pod Annotations. If you're using
+Auto DevOps, you can [customize `auto-deploy-values.yaml`](../../topics/autodevops/customize.md#customize-values-for-helm-chart)
+to annotate your pods. Although it's helpful to be aware of the
+[list of custom attributes](https://gitlab.com/gitlab-org/cluster-integration/auto-deploy-image/-/tree/master/assets/auto-deploy-app#gitlabs-auto-deploy-helm-chart),
+you're only required to set `podAnnotations` as follows:
```yaml
podAnnotations:
container.apparmor.security.beta.kubernetes.io/auto-deploy-app: localhost/profile-one
```
-The only information to be changed here is the profile name which is `profile-one` in this example. Refer to the [AppArmor tutorial](https://kubernetes.io/docs/tutorials/clusters/apparmor/#securing-a-pod) for more information on how AppArmor is integrated in Kubernetes.
+The only information to be changed here is the profile name which is `profile-one`
+in this example. Refer to the [AppArmor tutorial](https://kubernetes.io/docs/tutorials/clusters/apparmor/#securing-a-pod)
+for more information on how AppArmor is integrated in Kubernetes.
#### Using PodSecurityPolicy in your deployments
-NOTE: **Note:**
To enable AppArmor annotations on a Pod Security Policy you must first
-load the correspondingAppArmor profile.
+load the corresponding AppArmor profile.
-[Pod Security Policies](https://kubernetes.io/docs/concepts/policy/pod-security-policy/)are
+[Pod Security Policies](https://kubernetes.io/docs/concepts/policy/pod-security-policy/) are
resources at the cluster level that control security-related
properties of deployed pods. You can use such a policy to enable
loaded AppArmor profiles and apply necessary pod restrictions across a
@@ -1465,14 +1498,14 @@ securityPolicies:
- '*'
```
-This example creates a single policy named `example` with the provided
-specification, and enables [AppArmor
-annotations](https://kubernetes.io/docs/tutorials/clusters/apparmor/#podsecuritypolicy-annotations)on
-it.
+This example creates a single policy named `example` with the provided specification,
+and enables [AppArmor annotations](https://kubernetes.io/docs/tutorials/clusters/apparmor/#podsecuritypolicy-annotations) on it.
-NOTE: **Note:**
-Support for installing the AppArmor managed application is provided by the GitLab Container Security group.
-If you run into unknown issues, please [open a new issue](https://gitlab.com/gitlab-org/gitlab/-/issues/new) and ping at least 2 people from the [Container Security group](https://about.gitlab.com/handbook/product/product-categories/#container-security-group).
+Support for installing the AppArmor managed application is provided by the
+GitLab Container Security group. If you run into unknown issues,
+[open a new issue](https://gitlab.com/gitlab-org/gitlab/-/issues/new), and ping
+at least 2 people from the
+[Container Security group](https://about.gitlab.com/handbook/product/product-categories/#container-security-group).
## Browse applications logs
@@ -1500,9 +1533,7 @@ To upgrade an application:
1. Select your cluster.
1. If an upgrade is available, the **Upgrade** button is displayed. Click the button to upgrade.
-NOTE: **Note:**
-Upgrades will reset values back to the values built into the `runner`
-chart plus the values set by
+Upgrades reset values back to the values built into the `runner` chart, plus the values set by
[`values.yaml`](https://gitlab.com/gitlab-org/gitlab/blob/master/vendor/runner/values.yaml)
## Uninstalling applications
@@ -1513,16 +1544,16 @@ The applications below can be uninstalled.
| Application | GitLab version | Notes |
| ----------- | -------------- | ----- |
-| cert-manager | 12.2+ | The associated private key will be deleted and cannot be restored. Deployed applications will continue to use HTTPS, but certificates will not be renewed. Before uninstalling, you may wish to [back up your configuration](https://cert-manager.io/docs/tutorials/backup/) or [revoke your certificates](https://letsencrypt.org/docs/revoking/). |
-| GitLab Runner | 12.2+ | Any running pipelines will be canceled. |
-| Helm | 12.2+ | The associated Tiller pod, the `gitlab-managed-apps` namespace, and all of its resources will be deleted and cannot be restored. |
-| Ingress | 12.1+ | The associated load balancer and IP will be deleted and cannot be restored. Furthermore, it can only be uninstalled if JupyterHub is not installed. |
-| JupyterHub | 12.1+ | All data not committed to GitLab will be deleted and cannot be restored. |
-| Knative | 12.1+ | The associated IP will be deleted and cannot be restored. |
-| Prometheus | 11.11+ | All data will be deleted and cannot be restored. |
-| Crossplane | 12.5+ | All data will be deleted and cannot be restored. |
-| Elastic Stack | 12.7+ | All data will be deleted and cannot be restored. |
-| Sentry | 12.6+ | The PostgreSQL persistent volume will remain and should be manually removed for complete uninstall. |
+| cert-manager | 12.2+ | The associated private key is deleted and cannot be restored. Deployed applications continue to use HTTPS, but certificates aren't renewed. Before uninstalling, you may want to [back up your configuration](https://cert-manager.io/docs/tutorials/backup/) or [revoke your certificates](https://letsencrypt.org/docs/revoking/). |
+| GitLab Runner | 12.2+ | Any running pipelines are canceled. |
+| Helm | 12.2+ | The associated Tiller pod, the `gitlab-managed-apps` namespace, and all of its resources are deleted and cannot be restored. |
+| Ingress | 12.1+ | The associated load balancer and IP are deleted and cannot be restored. Furthermore, it can only be uninstalled if JupyterHub is not installed. |
+| JupyterHub | 12.1+ | All data not committed to GitLab are deleted and cannot be restored. |
+| Knative | 12.1+ | The associated IP are deleted and cannot be restored. |
+| Prometheus | 11.11+ | All data are deleted and cannot be restored. |
+| Crossplane | 12.5+ | All data are deleted and cannot be restored. |
+| Elastic Stack | 12.7+ | All data are deleted and cannot be restored. |
+| Sentry | 12.6+ | The PostgreSQL persistent volume remains and should be manually removed for complete uninstall. |
To uninstall an application:
@@ -1535,8 +1566,7 @@ To uninstall an application:
1. Click the **Uninstall** button for the application.
Support for uninstalling all applications is planned for progressive rollout.
-To follow progress, see [the relevant
-epic](https://gitlab.com/groups/gitlab-org/-/epics/1201).
+To follow progress, see the [relevant epic](https://gitlab.com/groups/gitlab-org/-/epics/1201).
## Troubleshooting applications
@@ -1550,9 +1580,10 @@ To avoid installation errors:
- Before starting the installation of applications, make sure that time is synchronized
between your GitLab server and your Kubernetes cluster.
-- Ensure certificates are not out of sync. When installing applications, GitLab expects a new cluster with no previous installation of Helm.
+- Ensure certificates are not out of sync. When installing applications, GitLab
+ expects a new cluster with no previous installation of Helm.
- You can confirm that the certificates match via `kubectl`:
+ You can confirm that the certificates match by using `kubectl`:
```shell
kubectl get configmaps/values-content-configuration-ingress -n gitlab-managed-apps -o \
@@ -1590,5 +1621,5 @@ Installing Prometheus is failing with the following error:
Error: Could not get apiVersions from Kubernetes: unable to retrieve the complete list of server APIs: admission.certmanager.k8s.io/v1beta1: the server is currently unable to handle the request
```
-This is a bug that was introduced in Helm `2.15` and fixed in `3.0.2`. As a workaround, you'll need
-to make sure that [`cert-manager`](#cert-manager) is installed successfully prior to installing Prometheus.
+This is a bug that was introduced in Helm `2.15` and fixed in `3.0.2`. As a workaround,
+ensure [`cert-manager`](#cert-manager) is installed successfully prior to installing Prometheus.
diff --git a/doc/user/clusters/cost_management.md b/doc/user/clusters/cost_management.md
new file mode 100644
index 00000000000..f13be15c6bc
--- /dev/null
+++ b/doc/user/clusters/cost_management.md
@@ -0,0 +1,74 @@
+---
+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/engineering/ux/technical-writing/#designated-technical-writers
+---
+
+# Cluster cost management **(ULTIMATE)**
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/216737) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 13.5.
+
+Cluster cost management provides insights into cluster resource usage. GitLab provides an example
+[`kubecost-cost-model`](https://gitlab.com/gitlab-examples/kubecost-cost-model/)
+project that uses GitLab's Prometheus integration and
+[Kubecost's `cost-model`](https://github.com/kubecost/cost-model) to provide cluster cost
+insights within GitLab:
+
+![Example dashboard](img/kubecost_v13_5.png)
+
+## Configure cluster cost management
+
+To get started with cluster cost management, you need [Maintainer](../permissions.md)
+permissions in a project or group.
+
+1. Clone the [`kubecost-cost-model`](https://gitlab.com/gitlab-examples/kubecost-cost-model/)
+ example repository, which contains minor modifications to the upstream Kubecost
+ `cost-model` project:
+ - Configures your Prometheus endpoint to the GitLab-managed Prometheus. You may
+ need to change this value if you use a non-managed Prometheus.
+ - Adds the necessary annotations to the deployment manifest to be scraped by
+ GitLab-managed Prometheus.
+ - Changes the Google Pricing API access key to GitLab's access key.
+ - Contains definitions for a custom GitLab Metrics dashboard to show the cost insights.
+1. Connect GitLab with Prometheus, depending on your configuration:
+ - *If Prometheus is already configured,* navigate to **Settings > Integrations > Prometheus**
+ to provide the API endpoint of your Prometheus server.
+ - *For GitLab-managed Prometheus,* navigate to your cluster's **Details** page,
+ select the **Applications** tab, and install Prometheus. The integration is
+ auto-configured for you.
+1. Set up the Prometheus integration on the cloned example project.
+1. Add the Kubecost `cost-model` to your cluster:
+ - *For non-managed clusters*, deploy it with GitLab CI/CD.
+ - *To deploy it manually*, use the following commands:
+
+ ```shell
+ kubectl create namespace cost-model
+ kubectl apply -f kubernetes/ --namespace cost-model
+ ```
+
+To access the cost insights, navigate to **Operations > Metrics** and select
+the `default_costs.yml` dashboard. You can [customize](#customize-the-cost-dashboard)
+this dashboard.
+
+### Customize the cost dashboard
+
+You can customize the cost dashboard by editing the `.gitlab/dashboards/default_costs.yml`
+file or creating similar dashboard configuration files. To learn more, read about
+[customizing dashboards in our documentation](/ee/operations/metrics/dashboards/).
+
+#### Available metrics
+
+Metrics contain both instance and node labels. The instance label will be deprecated in a future version.
+
+- `node_cpu_hourly_cost` - Hourly cost per vCPU on this node.
+- `node_gpu_hourly_cost` - Hourly cost per GPU on this node.
+- `node_ram_hourly_cost` - Hourly cost per gigabyte of memory on this node.
+- `node_total_hourly_cost` - Total node cost per hour.
+- `container_cpu_allocation` - Average number of CPUs requested/used over the previous minute.
+- `container_gpu_allocation` - Average number of GPUs requested over the previous minute.
+- `container_memory_allocation_bytes` - Average bytes of RAM requested/used over the previous minute.
+- `pod_pvc_allocation` - Bytes provisioned for a PVC attached to a pod.
+- `pv_hourly_cost` - Hourly cost per GB on a persistent volume.
+
+Some examples are provided in the
+[`kubecost-cost-model` repository](https://gitlab.com/gitlab-examples/kubecost-cost-model/-/blob/master/PROMETHEUS.md#example-queries).
diff --git a/doc/user/clusters/crossplane.md b/doc/user/clusters/crossplane.md
index b30ebc57338..8463917f2f3 100644
--- a/doc/user/clusters/crossplane.md
+++ b/doc/user/clusters/crossplane.md
@@ -78,7 +78,6 @@ provided can manage resources in the `database.crossplane.io` API group:
See [Configure Your Cloud Provider Account](https://crossplane.github.io/docs/v0.4/cloud-providers.html)
to configure the installed cloud provider stack with a user account.
-NOTE: **Note:**
The Secret, and the Provider resource referencing the Secret, must be
applied to the `gitlab-managed-apps` namespace in the guide. Make sure you change that
while following the process.
diff --git a/doc/user/clusters/environments.md b/doc/user/clusters/environments.md
index 2b342ceb06d..3ab20c5466e 100644
--- a/doc/user/clusters/environments.md
+++ b/doc/user/clusters/environments.md
@@ -43,6 +43,5 @@ Once you have successful deployments to your group-level or instance-level clust
1. Navigate to your group's **Kubernetes** page.
1. Click on the **Environments** tab.
-NOTE: **Note:**
-Only successful deployments to the cluster is included in this page.
-Non-cluster environments will not be included.
+Only successful deployments to the cluster are included in this page.
+Non-cluster environments aren't included.
diff --git a/doc/user/clusters/img/kubecost_v13_5.png b/doc/user/clusters/img/kubecost_v13_5.png
new file mode 100644
index 00000000000..a93e2531b16
--- /dev/null
+++ b/doc/user/clusters/img/kubecost_v13_5.png
Binary files differ
diff --git a/doc/user/compliance/compliance_dashboard/img/compliance_dashboard_v13_3_1.png b/doc/user/compliance/compliance_dashboard/img/compliance_dashboard_v13_3_1.png
index a06f8812b41..89f4e917567 100644
--- a/doc/user/compliance/compliance_dashboard/img/compliance_dashboard_v13_3_1.png
+++ b/doc/user/compliance/compliance_dashboard/img/compliance_dashboard_v13_3_1.png
Binary files differ
diff --git a/doc/user/compliance/license_compliance/img/license-check_v13_4.png b/doc/user/compliance/license_compliance/img/license-check_v13_4.png
index d3658cbaa18..bc80f938395 100644
--- a/doc/user/compliance/license_compliance/img/license-check_v13_4.png
+++ b/doc/user/compliance/license_compliance/img/license-check_v13_4.png
Binary files differ
diff --git a/doc/user/compliance/license_compliance/index.md b/doc/user/compliance/license_compliance/index.md
index 79c2d97b972..894c0e14862 100644
--- a/doc/user/compliance/license_compliance/index.md
+++ b/doc/user/compliance/license_compliance/index.md
@@ -121,12 +121,17 @@ The results will be saved as a
[License Compliance report artifact](../../../ci/pipelines/job_artifacts.md#artifactsreportslicense_scanning)
that you can later download and analyze. Due to implementation limitations, we
always take the latest License Compliance artifact available. Behind the scenes, the
-[GitLab License Compliance Docker image](https://gitlab.com/gitlab-org/security-products/license-management)
+[GitLab License Compliance Docker image](https://gitlab.com/gitlab-org/security-products/analyzers/license-finder)
is used to detect the languages/frameworks and in turn analyzes the licenses.
The License Compliance settings can be changed through [environment variables](#available-variables) by using the
[`variables`](../../../ci/yaml/README.md#variables) parameter in `.gitlab-ci.yml`.
+### When License Compliance runs
+
+When using the GitLab `License-Scanning.gitlab-ci.yml` template, the License Compliance job doesn't
+wait for other stages to complete.
+
### Available variables
License Compliance can be configured using environment variables.
@@ -446,7 +451,7 @@ package manager. For a comprehensive list, consult [the Conan documentation](htt
The default [Conan](https://conan.io/) configuration sets [`CONAN_LOGIN_USERNAME`](https://docs.conan.io/en/latest/reference/env_vars.html#conan-login-username-conan-login-username-remote-name)
to `ci_user`, and binds [`CONAN_PASSWORD`](https://docs.conan.io/en/latest/reference/env_vars.html#conan-password-conan-password-remote-name)
to the [`CI_JOB_TOKEN`](../../../ci/variables/predefined_variables.md)
-for the running job. This allows Conan projects to fetch packages from a [GitLab Conan Repository](../../packages/conan_repository/#fetching-conan-package-information-from-the-gitlab-package-registry)
+for the running job. This allows Conan projects to fetch packages from a [GitLab Conan Repository](../../packages/conan_repository/#fetch-conan-package-information-from-the-package-registry)
if a GitLab remote is specified in the `.conan/remotes.json` file.
To override the default credentials specify a [`CONAN_LOGIN_USERNAME_{REMOTE_NAME}`](https://docs.conan.io/en/latest/reference/env_vars.html#conan-login-username-conan-login-username-remote-name)
@@ -629,7 +634,7 @@ import the following default License Compliance analyzer images from `registry.g
offline [local Docker container registry](../../packages/container_registry/index.md):
```plaintext
-registry.gitlab.com/gitlab-org/security-products/license-management:latest
+registry.gitlab.com/gitlab-org/security-products/analyzers/license-finder:latest
```
The process for importing Docker images into a local offline Docker registry depends on
diff --git a/doc/user/gitlab_com/index.md b/doc/user/gitlab_com/index.md
index 67dd31efe2c..ec0c207e190 100644
--- a/doc/user/gitlab_com/index.md
+++ b/doc/user/gitlab_com/index.md
@@ -38,6 +38,14 @@ The IP address for `mg.gitlab.com` is subject to change at any time.
[See our backup strategy](https://about.gitlab.com/handbook/engineering/infrastructure/production/#backups).
+There are several ways to perform backups of your content on GitLab.com.
+
+Projects can be backed up in their entirety by exporting them either [through the UI](../project/settings/import_export.md) or [API](../../api/project_import_export.md#schedule-an-export), the latter of which can be used to programmatically upload exports to a storage platform such as AWS S3.
+
+With exports, be sure to take note of [what is and is not](../project/settings/import_export.md#exported-contents), included in a project export.
+
+Since GitLab is built on Git, you can back up **just** the repository of a project by [cloning](../../gitlab-basics/start-using-git.md#clone-a-repository) it to another machine. Similarly, if you need to back up just the wiki of a repository it can also be cloned and all files uploaded to that wiki will come with it [if they were uploaded after 2020-08-22](../project/wiki/index.md#creating-a-new-wiki-page).
+
## Alternative SSH port
GitLab.com can be reached via a [different SSH port](https://about.gitlab.com/blog/2016/02/18/gitlab-dot-com-now-supports-an-alternate-git-plus-ssh-port/) for `git+ssh`.
@@ -88,6 +96,7 @@ Below are the current settings regarding [GitLab CI/CD](../../ci/README.md).
| [Max pipeline schedules in projects](../../administration/instance_limits.md#number-of-pipeline-schedules) | `10` for Free tier, `50` for all paid tiers | Unlimited |
| [Max number of instance level variables](../../administration/instance_limits.md#number-of-instance-level-variables) | `25` | `25` |
| [Scheduled Job Archival](../../user/admin_area/settings/continuous_integration.md#archive-jobs) | 3 months | Never |
+| Max test cases per [unit test report](../../ci/unit_test_reports.md) | `500_000` | Unlimited |
## Account and limit settings
@@ -474,6 +483,10 @@ More information on this particular change can be found at
of proposed changes can be found at
<https://gitlab.com/gitlab-com/infrastructure/-/issues?scope=all&utf8=%E2%9C%93&state=opened&label_name[]=database&label_name[]=change>.
+## Puma
+
+GitLab.com uses the default of 60 seconds for [Puma request timeouts](https://docs.gitlab.com/omnibus/settings/puma.html#worker-timeout).
+
## Unicorn
GitLab.com adjusts the memory limits for the [unicorn-worker-killer](https://rubygems.org/gems/unicorn-worker-killer) gem.
@@ -529,9 +542,9 @@ Source:
For performance reasons, if a query returns more than 10,000 records, GitLab
doesn't return the following headers:
-- `X-Total`.
-- `X-Total-Pages`.
-- `rel="last"` `Link`.
+- `x-total`.
+- `x-total-pages`.
+- `rel="last"` `link`.
### Rack Attack initializer
@@ -596,6 +609,11 @@ dropped and users get
To help avoid abuse, project and group imports, exports, and export downloads are rate limited. See [Project import/export rate limits](../../user/project/settings/import_export.md#rate-limits) and [Group import/export rate limits](../../user/group/settings/import_export.md#rate-limits) for details.
+### Non-configurable limits
+
+See [non-configurable limits](../../security/rate_limits.md#non-configurable-limits) for information on
+rate limits that are not configurable, and therefore also used on GitLab.com.
+
## GitLab.com Logging
We use [Fluentd](https://gitlab.com/gitlab-com/runbooks/tree/master/logging/doc#fluentd) to parse our logs. Fluentd sends our logs to
diff --git a/doc/user/group/clusters/index.md b/doc/user/group/clusters/index.md
index ebf38aef4a6..1a62d67e468 100644
--- a/doc/user/group/clusters/index.md
+++ b/doc/user/group/clusters/index.md
@@ -14,6 +14,9 @@ Similar to [project-level](../../project/clusters/index.md) and
group-level Kubernetes clusters allow you to connect a Kubernetes cluster to
your group, enabling you to use the same cluster across multiple projects.
+To view your group level Kubernetes clusters, navigate to your project and select
+**Kubernetes** from the left-hand menu.
+
## Installing applications
GitLab can install and manage some applications in your group-level
@@ -69,9 +72,8 @@ for deployments with a cluster not managed by GitLab, you must ensure:
(this is [not automatic](https://gitlab.com/gitlab-org/gitlab/-/issues/31519)). Editing
`KUBE_NAMESPACE` directly is discouraged.
-NOTE: **Note:**
If you [install applications](#installing-applications) on your cluster, GitLab creates
-the resources required to run them even if you choose to manage your own cluster.
+the resources required to run them, even if you choose to manage your own cluster.
### Clearing the cluster cache
diff --git a/doc/user/group/contribution_analytics/index.md b/doc/user/group/contribution_analytics/index.md
index bcc6d958427..a689b7c380b 100644
--- a/doc/user/group/contribution_analytics/index.md
+++ b/doc/user/group/contribution_analytics/index.md
@@ -9,8 +9,6 @@ info: To determine the technical writer assigned to the Stage/Group associated w
> - Introduced in [GitLab Starter](https://about.gitlab.com/pricing/) 8.3.
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/3090) for subgroups in GitLab 12.2.
-## Overview
-
With Contribution Analytics you can get an overview of the following activity in your
group:
diff --git a/doc/user/group/epics/index.md b/doc/user/group/epics/index.md
index e8bcb7219fc..f380b36cc00 100644
--- a/doc/user/group/epics/index.md
+++ b/doc/user/group/epics/index.md
@@ -10,9 +10,8 @@ info: To determine the technical writer assigned to the Stage/Group associated w
> - Introduced in [GitLab Ultimate](https://about.gitlab.com/pricing/) 10.2.
> - Single-level Epics [were moved](https://gitlab.com/gitlab-org/gitlab/-/issues/37081) to [GitLab Premium](https://about.gitlab.com/pricing/) in 12.8.
-Epics let you manage your portfolio of projects more efficiently and with less
-effort by tracking groups of issues that share a theme, across projects and
-milestones.
+Epics let you manage your portfolio of projects more efficiently by tracking groups of issues that
+share a theme across projects and milestones.
An epic's page contains the following tabs:
@@ -22,7 +21,7 @@ An epic's page contains the following tabs:
- Hover over the total counts to see a breakdown of open and closed items.
NOTE: **Note:**
- The number provided here includes all epics associated with this project. The number includes epics for which users may not currently have permission.
+ The number provided here includes all epics associated with this project. The number includes epics for which users may not yet have permission.
- **Roadmap**: a roadmap view of child epics which have start and due dates.
@@ -65,16 +64,19 @@ graph TD
```
See [Manage issues assigned to an epic](manage_epics.md#manage-issues-assigned-to-an-epic) for steps
-to add an issue to an epic, reorder issues, move issues between epics, or promote an issue to an epic.
+to:
+
+- Add an issue to an epic
+- Reorder issues
+- Move an issue between epics
+- Promote an issue to an epic
## Issue health status in Epic tree **(ULTIMATE)**
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/199184) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 12.10.
-> - The health status of a closed issue [will be hidden](https://gitlab.com/gitlab-org/gitlab/-/issues/220867) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 13.3 or later.
+> - The health status of a closed issue [is hidden](https://gitlab.com/gitlab-org/gitlab/-/issues/220867) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 13.3 or later.
-You can report on and quickly respond to the health of individual issues and epics by setting a
-red, amber, or green [health status on an issue](../../project/issues/index.md#health-status),
-which will appear on your Epic tree.
+Report or respond to the health of issues and epics by setting a red, amber, or green [health status](../../project/issues/index.md#health-status), which then appears on your Epic tree.
### Disable Issue health status in Epic tree
@@ -100,7 +102,7 @@ steps to create, move, reorder, or delete child epics.
To set a **Start date** and **Due date** for an epic, select one of the following:
- **Fixed**: Enter a fixed value.
-- **From milestones**: Inherit a dynamic value from the milestones currently assigned to the epic's issues.
+- **From milestones**: Inherit a dynamic value from the milestones that are assigned to the epic's issues.
Note that GitLab 12.5 replaced this option with **Inherited**.
- **Inherited**: Inherit a dynamic value from the epic's issues, child epics, and milestones ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/7332) in GitLab 12.5 to replace **From milestones**).
@@ -108,10 +110,10 @@ To set a **Start date** and **Due date** for an epic, select one of the followin
> [Replaced](https://gitlab.com/gitlab-org/gitlab/-/issues/7332) in GitLab 12.5 by **Inherited**.
-If you select **From milestones** for the start date, GitLab will automatically set the date to be earliest
-start date across all milestones that are currently assigned to the issues that are added to the epic.
-Similarly, if you select **From milestones** for the due date, GitLab will set it to be the latest due date across
-all milestones that are currently assigned to those issues.
+If you select **From milestones** for the start date, GitLab automatically sets the date to be earliest
+start date across all milestones that are assigned to the issues that belong to the epic.
+If you select **From milestones** for the due date, GitLab sets the date to be the latest due date across
+all milestones that are assigned to those issues.
These are dynamic dates which are recalculated if any of the following occur:
@@ -138,8 +140,8 @@ These are dynamic dates and recalculated if any of the following occur:
- Issues are added to, or removed from, the epic.
Because the epic's dates can inherit dates from its children, the start date and due date propagate from the bottom to the top.
-If the start date of a child epic on the lowest level changes, that becomes the earliest possible start date for its parent epic,
-then the parent epic's start date will reflect the change and this will propagate upwards to the top epic.
+If the start date of a child epic on the lowest level changes, that becomes the earliest possible start date for its parent epic.
+The parent epic's start date then reflects this change and propagates upwards to the top epic.
## Roadmap in epics
@@ -153,11 +155,11 @@ have a [start or due date](#start-date-and-due-date), a
## Permissions
-If you have access to view an epic and have access to view an issue already
-added to that epic, then you can view the issue in the epic issue list.
+If you have access to view an epic and an issue added to that epic, you can view the issue in the
+epic's issue list.
-If you have access to edit an epic and have access to edit an issue, then you
-can add the issue to or remove it from the epic.
+If you have access to edit an epic and an issue added to that epic, you can add the issue to or
+remove it from the epic.
Note that for a given group, the visibility of all projects must be the same as
the group, or less restrictive. That means if you have access to a group's epic,
@@ -175,8 +177,8 @@ You can also consult the [group permissions table](../../permissions.md#group-me
Once you write your comment, you can either:
-- Click **Comment**, and your comment will be published.
-- Click **Start thread**, and you will start a thread within that epic's discussion.
+- Click **Comment** to publish your comment.
+- Click **Start thread** to start a thread within that epic's discussion.
### Activity sort order
diff --git a/doc/user/group/index.md b/doc/user/group/index.md
index 32b76cf9280..2c838724cb3 100644
--- a/doc/user/group/index.md
+++ b/doc/user/group/index.md
@@ -371,7 +371,7 @@ To create group links via filter:
### Overriding user permissions **(STARTER ONLY)**
-Since GitLab [v8.15](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/822) LDAP user permissions can now be manually overridden by an admin user. To override a user's permissions:
+In GitLab [8.15](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/822) and later, LDAP user permissions can now be manually overridden by an admin user. To override a user's permissions:
1. Go to your group's **Members** page.
1. Select the pencil icon in the row for the user you are editing.
@@ -391,11 +391,56 @@ milestones.
[Learn more about Epics.](epics/index.md)
+## Group wikis **(PREMIUM)**
+
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/13195) in [GitLab Premium](https://about.gitlab.com/pricing/) 13.5.
+> - It's [deployed behind a feature flag](../feature_flags.md), enabled by default.
+> - It's enabled on GitLab.com.
+> - It's recommended for production use.
+> - For GitLab self-managed instances, GitLab administrators can opt to [disable it](#enable-or-disable-group-wikis).
+
+CAUTION: **Warning:**
+This feature might not be available to you. Check the **version history** note above for details.
+
+Group wikis work the same way as [project wikis](../project/wiki/index.md), please refer to those docs for details on usage.
+
+Group wikis can be edited by members with [Developer permissions](../../user/permissions.md#group-members-permissions)
+and above.
+
+### Group wikis limitations
+
+There are a few limitations compared to project wikis:
+
+- Local Git access is not supported yet.
+- Group wikis are not included in global search, group exports, backups, and Geo replication.
+- Changes to group wikis don't show up in the group's activity feed.
+
+You can follow [this epic](https://gitlab.com/groups/gitlab-org/-/epics/2782) for updates.
+
+### Enable or disable group wikis **(CORE ONLY)**
+
+Group wikis are under development but ready for production use.
+It is deployed behind a feature flag that is **enabled by default**.
+[GitLab administrators with access to the GitLab Rails console](../../administration/feature_flags.md)
+can opt to disable it for your instance.
+
+To enable it:
+
+```ruby
+Feature.enable(:group_wikis)
+```
+
+To disable it:
+
+```ruby
+Feature.disable(:group_wikis)
+```
+
## Group Security Dashboard **(ULTIMATE)**
Get an overview of the vulnerabilities of all the projects in a group and its subgroups.
-[Learn more about the Group Security Dashboard.](security_dashboard/index.md)
+[Learn more about the Group Security Dashboard.](../application_security/security_dashboard/index.md)
## Insights **(ULTIMATE)**
diff --git a/doc/user/group/iterations/index.md b/doc/user/group/iterations/index.md
index 20cbc043d83..2eb50f07de3 100644
--- a/doc/user/group/iterations/index.md
+++ b/doc/user/group/iterations/index.md
@@ -64,6 +64,15 @@ To edit an iteration, click the three-dot menu (**{ellipsis_v}**) > **Edit itera
To learn how to add an issue to an iteration, see the steps in
[Managing issues](../../project/issues/managing_issues.md#add-an-issue-to-an-iteration).
+## View an iteration report
+
+> Viewing iteration reports in projects [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/222763) in [GitLab Starter](https://about.gitlab.com/pricing/) 13.5.
+
+You can track the progress of an iteration by reviewing iteration reports.
+An iteration report displays a list of all the issues assigned to an iteration and their status.
+
+To view an iteration report, go to the iterations list page and click an iteration's title.
+
## Disable Iterations **(CORE ONLY)**
GitLab Iterations feature is deployed with a feature flag that is **enabled by default**.
diff --git a/doc/user/group/repositories_analytics/index.md b/doc/user/group/repositories_analytics/index.md
index b013e371ed2..c9a10146440 100644
--- a/doc/user/group/repositories_analytics/index.md
+++ b/doc/user/group/repositories_analytics/index.md
@@ -1,17 +1,13 @@
---
type: reference
stage: Verify
-group: Analytics
+group: Testing
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/#designated-technical-writers
---
# Repositories Analytics **(PREMIUM)**
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/215104) in [GitLab Premium](https://about.gitlab.com/pricing/) 13.4.
-> - It's [deployed behind a feature flag](../../feature_flags.md), enabled by default.
-> - It's enabled on GitLab.com.
-> - It's recommended for production use.
-> - For GitLab self-managed instances, GitLab administrators can opt to [disable it](#enable-or-disable-repositories-analytics). **(CORE ONLY)**
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/215104) in [GitLab Premium](https://about.gitlab.com/pricing/) 13.4.
CAUTION: **Warning:**
This feature might not be available to you. Check the **version history** note above for details.
@@ -35,25 +31,6 @@ For each day that a coverage report was generated by a job in a project's pipeli
If the project's code coverage was calculated more than once in a day, we will take the last value from that day.
-## Enable or disable Repositories Analytics **(CORE ONLY)**
-
-Repositories Analytics is under development but ready for production use.
-It is deployed behind a feature flag that is **enabled by default**.
-[GitLab administrators with access to the GitLab Rails console](../../../administration/feature_flags.md)
-can opt to disable it.
-
-To enable it:
-
-```ruby
-Feature.enable(:group_coverage_reports)
-```
-
-To disable it:
-
-```ruby
-Feature.disable(:group_coverage_reports)
-```
-
<!-- ## Troubleshooting
Include any troubleshooting steps that you can foresee. If you know beforehand what issues
diff --git a/doc/user/group/saml_sso/index.md b/doc/user/group/saml_sso/index.md
index 57b9cc92c51..3cb566c7f77 100644
--- a/doc/user/group/saml_sso/index.md
+++ b/doc/user/group/saml_sso/index.md
@@ -5,7 +5,7 @@ group: Access
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/#designated-technical-writers
---
-# SAML SSO for GitLab.com groups **(PREMIUM)**
+# SAML SSO for GitLab.com groups **(SILVER ONLY)**
> Introduced in GitLab 11.0.
@@ -256,53 +256,6 @@ For example, to unlink the `MyOrg` account, the following **Disconnect** button
| Issuer | How GitLab identifies itself to the identity provider. Also known as a "Relying party trust identifier". |
| Certificate fingerprint | Used to confirm that communications over SAML are secure by checking that the server is signing communications with the correct certificate. Also known as a certificate thumbprint. |
-## Configuring on a self-managed GitLab instance **(PREMIUM ONLY)**
-
-For self-managed GitLab instances we strongly recommend using the
-[instance-wide SAML OmniAuth Provider](../../../integration/saml.md) instead.
-
-Group SAML SSO helps if you need to allow access via multiple SAML identity providers, but as a multi-tenant solution is less suited to cases where you administer your own GitLab instance.
-
-To proceed with configuring Group SAML SSO instead, you'll need to enable the `group_saml` OmniAuth provider. This can be done from:
-
-- `gitlab.rb` for [Omnibus GitLab installations](#omnibus-installations).
-- `gitlab/config/gitlab.yml` for [source installations](#source-installations).
-
-### Limitations
-
-Group SAML on a self-managed instance is limited when compared to the recommended
-[instance-wide SAML](../../../integration/saml.md). The recommended solution allows you to take advantage of:
-
-- [LDAP compatibility](../../../administration/auth/ldap/index.md).
-- [LDAP Group Sync](../index.md#manage-group-memberships-via-ldap).
-- [Required groups](../../../integration/saml.md#required-groups).
-- [Admin groups](../../../integration/saml.md#admin-groups).
-- [Auditor groups](../../../integration/saml.md#auditor-groups).
-
-### Omnibus installations
-
-1. Make sure GitLab is
- [configured with HTTPS](../../../install/installation.md#using-https).
-1. Enable OmniAuth and the `group_saml` provider in `gitlab.rb`:
-
- ```ruby
- gitlab_rails['omniauth_enabled'] = true
- gitlab_rails['omniauth_providers'] = [{ name: 'group_saml' }]
- ```
-
-### Source installations
-
-1. Make sure GitLab is
- [configured with HTTPS](../../../install/installation.md#using-https).
-1. Enable OmniAuth and the `group_saml` provider in `gitlab/config/gitlab.yml`:
-
- ```yaml
- omniauth:
- enabled: true
- providers:
- - { name: 'group_saml' }
- ```
-
## Passwords for users created via SAML SSO for Groups
The [Generated passwords for users created through integrated authentication](../../../security/passwords_for_integrated_authentication_methods.md) guide provides an overview of how GitLab generates and sets passwords for users created via SAML SSO for Groups.
@@ -336,6 +289,11 @@ Similarly, group members of a role with the appropriate permissions can make use
This can then be compared to the [NameID](#nameid) being sent by the Identity Provider by decoding the message with a [SAML debugging tool](#saml-debugging-tools). We require that these match in order to identify users.
+### Users receive a 404
+
+If a user is trying to sign in for the first time and the GitLab single sign-on URL has not [been configured](#configuring-your-identity-provider), they may see a 404.
+As outlined in the [user access section](#linking-saml-to-your-existing-gitlabcom-account), a group Owner will need to provide the URL to users.
+
### Message: "SAML authentication failed: Extern uid has already been taken"
This error suggests you are signed in as a GitLab user but have already linked your SAML identity to a different GitLab user. Sign out and then try to sign in again using the SSO SAML link, which should log you into GitLab with the linked user account.
diff --git a/doc/user/group/saml_sso/scim_setup.md b/doc/user/group/saml_sso/scim_setup.md
index 4f74e672392..c6444ada165 100644
--- a/doc/user/group/saml_sso/scim_setup.md
+++ b/doc/user/group/saml_sso/scim_setup.md
@@ -17,7 +17,7 @@ GitLab's [SCIM API](../../../api/scim.md) implements part of [the RFC7644 protoc
## Features
-Currently, the following actions are available:
+The following actions are available:
- Create users
- Update users (Azure only)
@@ -51,7 +51,7 @@ Once [Group Single Sign-On](index.md) has been configured, we can:
The SAML application that was created during [Single sign-on](index.md) setup for [Azure](https://docs.microsoft.com/en-us/azure/active-directory/manage-apps/view-applications-portal) now needs to be set up for SCIM.
-1. Check the configuration for your GitLab SAML app and ensure that **Name identifier value** (NameID) points to `user.objectid` or another unique identifier. This will match the `extern_uid` used on GitLab.
+1. Check the configuration for your GitLab SAML app and ensure that **Name identifier value** (NameID) points to `user.objectid` or another unique identifier. This matches the `extern_uid` used on GitLab.
![Name identifier value mapping](img/scim_name_identifier_mapping.png)
@@ -63,7 +63,7 @@ During this configuration, note the following:
- The `Tenant URL` and `secret token` are the ones retrieved in the
[previous step](#gitlab-configuration).
- Should there be any problems with the availability of GitLab or similar
- errors, the notification email set will get those.
+ errors, the notification email set gets those.
- It is recommended to set a notification email and check the **Send an email notification when a failure occurs** checkbox.
- For mappings, we will only leave `Synchronize Azure Active Directory Users to AppName` enabled.
@@ -75,10 +75,10 @@ You can then test the connection by clicking on **Test Connection**. If the conn
1. Click **Delete** next to the `mail` mapping.
1. Map `userPrincipalName` to `emails[type eq "work"].value` and change its **Matching precedence** to `2`.
1. Map `mailNickname` to `userName`.
-1. Determine how GitLab will uniquely identify users.
+1. Determine how GitLab uniquely identifies users.
- Use `objectId` unless users already have SAML linked for your group.
- - If you already have users with SAML linked then use the `Name ID` value from the [SAML configuration](#azure). Using a different value will likely cause duplicate users and prevent users from accessing the GitLab group.
+ - If you already have users with SAML linked then use the `Name ID` value from the [SAML configuration](#azure). Using a different value may cause duplicate users and prevent users from accessing the GitLab group.
1. Create a new mapping:
1. Click **Add New Mapping**.
@@ -110,14 +110,14 @@ You can then test the connection by clicking on **Test Connection**. If the conn
NOTE: **Note:**
You can control what is actually synced by selecting the `Scope`. For example,
- `Sync only assigned users and groups` will only sync the users assigned to
- the application (`Users and groups`), otherwise, it will sync the whole Active Directory.
+ `Sync only assigned users and groups` only syncs the users assigned to
+ the application (`Users and groups`), otherwise, it syncs the whole Active Directory.
-Once enabled, the synchronization details and any errors will appear on the
+Once enabled, the synchronization details and any errors appears on the
bottom of the **Provisioning** screen, together with a link to the audit logs.
CAUTION: **Warning:**
-Once synchronized, changing the field mapped to `id` and `externalId` will likely cause provisioning errors, duplicate users, and prevent existing users from accessing the GitLab group.
+Once synchronized, changing the field mapped to `id` and `externalId` may cause a number of errors. These include provisioning errors, duplicate users, and may prevent existing users from accessing the GitLab group.
### Okta configuration steps
@@ -260,15 +260,9 @@ It is important that this SCIM `id` and SCIM `externalId` are configured to the
Group owners can see the list of users and the `externalId` stored for each user in the group SAML SSO Settings page.
-Alternatively, the [SCIM API](../../../api/scim.md#get-a-list-of-saml-users) can be used to manually retrieve the `externalId` we have stored for users, also called the `external_uid` or `NameId`.
+A possible alternative is to use the [SCIM API](../../../api/scim.md#get-a-list-of-saml-users) to manually retrieve the `externalId` we have stored for users, also called the `external_uid` or `NameId`.
-For example:
-
-```shell
-curl 'https://gitlab.example.com/api/scim/v2/groups/GROUP_NAME/Users?startIndex=1"' --header "Authorization: Bearer <your_scim_token>" --header "Content-Type: application/scim+json"
-```
-
-To see how this compares to the value returned as the SAML NameId, you can have the user use a [SAML Tracer](index.md#saml-debugging-tools).
+To see how the `external_uid` compares to the value returned as the SAML NameId, you can have the user use a [SAML Tracer](index.md#saml-debugging-tools).
#### Update or fix mismatched SCIM externalId and SAML NameId
@@ -285,15 +279,9 @@ you can address the problem in the following ways:
- You can have users unlink and relink themselves, based on the ["SAML authentication failed: User has already been taken"](./index.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.
-- You can use the [SCIM API](../../../api/scim.md#update-a-single-saml-user) to manually correct the `externalId` stored for users to match the SAML `NameId`.
+- It may be possible to use the [SCIM API](../../../api/scim.md#update-a-single-saml-user) to manually correct the `externalId` stored for users to match the SAML `NameId`.
To look up a user, you'll need to know the desired value that matches the `NameId` as well as the current `externalId`.
-It is then possible to issue a manual SCIM#update request, for example:
-
-```shell
-curl --verbose --request PATCH 'https://gitlab.com/api/scim/v2/groups/YOUR_GROUP/Users/OLD_EXTERNAL_UID' --data '{ "Operations": [{"op":"Replace","path":"externalId","value":"NEW_EXTERNAL_UID"}] }' --header "Authorization: Bearer <your_scim_token>" --header "Content-Type: application/scim+json"
-```
-
It is important not to update these to incorrect values, since this will cause users to be unable to sign in. It is also important not to assign a value to the wrong user, as this would cause users to get signed into the wrong account.
#### I need to change my SCIM app
diff --git a/doc/user/img/feature_flags_history_note_info_v13_2.png b/doc/user/img/feature_flags_history_note_info_v13_2.png
index 403a6002603..07d096b6dde 100644
--- a/doc/user/img/feature_flags_history_note_info_v13_2.png
+++ b/doc/user/img/feature_flags_history_note_info_v13_2.png
Binary files differ
diff --git a/doc/user/img/gitlab_snippet_v13_5.png b/doc/user/img/gitlab_snippet_v13_5.png
new file mode 100644
index 00000000000..3fce1d25c3d
--- /dev/null
+++ b/doc/user/img/gitlab_snippet_v13_5.png
Binary files differ
diff --git a/doc/user/img/version_history_notes_collapsed_v13_2.png b/doc/user/img/version_history_notes_collapsed_v13_2.png
index 42ea11ae8ff..b85c9cb36dd 100644
--- a/doc/user/img/version_history_notes_collapsed_v13_2.png
+++ b/doc/user/img/version_history_notes_collapsed_v13_2.png
Binary files differ
diff --git a/doc/user/index.md b/doc/user/index.md
index ce8713591ab..32a1c235882 100644
--- a/doc/user/index.md
+++ b/doc/user/index.md
@@ -46,8 +46,9 @@ GitLab is a Git-based platform that integrates a great number of essential tools
- Building, testing, and deploying with built-in [Continuous Integration](../ci/README.md).
- Deploying personal and professional static websites with [GitLab Pages](project/pages/index.md).
- Integrating with Docker by using [GitLab Container Registry](packages/container_registry/index.md).
-- Tracking the development lifecycle by using [GitLab Value Stream Analytics](project/cycle_analytics.md).
+- Tracking the development lifecycle by using [GitLab Value Stream Analytics](analytics/value_stream_analytics.md).
- Provide support with [Service Desk](project/service_desk.md).
+- [Export issues as CSV](project/issues/csv_export.md).
With GitLab Enterprise Edition, you can also:
@@ -60,8 +61,7 @@ With GitLab Enterprise Edition, you can also:
- Leverage [Elasticsearch](../integration/elasticsearch.md) with [Advanced Search](search/advanced_global_search.md) and [Advanced Search Syntax](search/advanced_search_syntax.md) for faster, more advanced code search across your entire GitLab instance.
- [Authenticate users with Kerberos](../integration/kerberos.md).
- [Mirror a repository](project/repository/repository_mirroring.md) from elsewhere on your local server.
-- [Export issues as CSV](project/issues/csv_export.md).
-- View your entire CI/CD pipeline involving more than one project with [Multiple-Project Pipelines](../ci/multi_project_pipeline_graphs.md).
+- View your entire CI/CD pipeline involving more than one project with [Multiple-Project Pipelines](../ci/multi_project_pipelines.md).
- [Lock files](project/file_lock.md) to prevent conflicts.
- View the current health and status of each CI environment running on Kubernetes with [Deploy Boards](project/deploy_boards.md).
- Leverage continuous delivery method with [Canary Deployments](project/canary_deployments.md).
diff --git a/doc/user/infrastructure/index.md b/doc/user/infrastructure/index.md
index 227a67f8c8a..cee6e21a5c5 100644
--- a/doc/user/infrastructure/index.md
+++ b/doc/user/infrastructure/index.md
@@ -13,6 +13,32 @@ workflows to tie into GitLab's authentication and authorization. These features
lowering the barrier to entry for teams to adopt Terraform, collaborate effectively within
GitLab, and support Terraform best practices.
+## Quick Start
+
+Use the following `.gitlab-ci.yml` to set up a simple Terraform project integration
+for GitLab versions 13.5 and greater:
+
+```yaml
+include:
+ - template: Terraform.latest.gitlab-ci.yml
+
+variables:
+ # If not using GitLab's HTTP backend, remove this line and specify TF_HTTP_* variables
+ TF_STATE_NAME: default
+ TF_CACHE_KEY: default
+```
+
+This template uses `.latest.`, instead of stable, and may include breaking changes.
+This template also includes some opinionated decisions, which you can override:
+
+- Including the latest [GitLab Terraform Image](https://gitlab.com/gitlab-org/terraform-images).
+- Using the [GitLab managed Terraform State](#gitlab-managed-terraform-state) as
+ the Terraform state storage backend.
+- Creating [four pipeline stages](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Terraform.latest.gitlab-ci.yml):
+ `init`, `validate`, `build`, and `deploy`. These stages
+ [run the Terraform commands](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Terraform/Base.latest.gitlab-ci.yml)
+ `init`, `validate`, `plan`, `plan-json`, and `apply`. The `apply` command only runs on `master`.
+
## GitLab managed Terraform State
> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/2673) in GitLab 13.0.
@@ -67,8 +93,9 @@ local machine, this is a simple way to get started:
1. On your local machine, run `terraform init`, passing in the following options,
replacing `<YOUR-STATE-NAME>`, `<YOUR-PROJECT-ID>`, `<YOUR-USERNAME>` and
`<YOUR-ACCESS-TOKEN>` with the relevant values. This command initializes your
- Terraform state, and stores that state within your GitLab project. This example
- uses `gitlab.com`:
+ Terraform state, and stores that state within your GitLab project. The name of
+ your state can contain only uppercase and lowercase letters, decimal digits,
+ hyphens, and underscores. This example uses `gitlab.com`:
```shell
terraform init \
@@ -198,7 +225,7 @@ recommends encrypting plan output or modifying the project visibility settings.
## Example project
-See [this reference project](https://gitlab.com/nicholasklick/gitlab-terraform-aws) using GitLab and Terraform to deploy a basic AWS EC2 within a custom VPC.
+See [this reference project](https://gitlab.com/gitlab-org/configure/examples/gitlab-terraform-aws) using GitLab and Terraform to deploy a basic AWS EC2 within a custom VPC.
## Copy Terraform state between backends
@@ -294,15 +321,15 @@ rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.
```
-If you type `yes`, it will copy your state from the old location to the new
+If you type `yes`, it copies your state from the old location to the new
location. You can then go back to running it from within GitLab CI.
## Output Terraform Plan information into a merge request
Using the [GitLab Terraform Report artifact](../../ci/pipelines/job_artifacts.md#artifactsreportsterraform),
you can expose details from `terraform plan` runs directly into a merge request widget,
-enabling you to see statistics about the resources that Terraform will create,
-modify, or destroy.
+enabling you to see statistics about the resources that Terraform creates,
+modifies, or destroys.
Let's explore how to configure a GitLab Terraform Report artifact. You can
either use a pre-built image which includes a `gitlab-terraform` helper as
@@ -434,7 +461,8 @@ apply:
### Multiple Terraform Plan reports
-Starting with 13.2, you can display multiple reports on the Merge Request page. The reports will also display the `artifacts: name:`. See example below for a suggested setup.
+Starting with GitLab version 13.2, you can display multiple reports on the Merge Request
+page. The reports also display the `artifacts: name:`. See example below for a suggested setup.
```yaml
default:
diff --git a/doc/user/instance/clusters/index.md b/doc/user/instance/clusters/index.md
index 8059b8ca642..c370f9d8725 100644
--- a/doc/user/instance/clusters/index.md
+++ b/doc/user/instance/clusters/index.md
@@ -2,14 +2,14 @@
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/39840) in GitLab 11.11.
-## Overview
-
Similar to [project-level](../../project/clusters/index.md)
and [group-level](../../group/clusters/index.md) Kubernetes clusters,
instance-level Kubernetes clusters allow you to connect a Kubernetes cluster to
the GitLab instance, which enables you to use the same cluster across multiple
projects.
+The instance level Kubernetes clusters can be found in the top menu by navigating to your instance's **{admin}** **Admin Area > Kubernetes**.
+
## Cluster precedence
GitLab will try to match clusters in the following order:
diff --git a/doc/user/markdown.md b/doc/user/markdown.md
index 03a4e4cb244..8b65da4ab94 100644
--- a/doc/user/markdown.md
+++ b/doc/user/markdown.md
@@ -78,13 +78,11 @@ character of the top list item (`C` in this case):
- dark
- milk
-NOTE: **Note:**
-We flag any significant differences between Redcarpet and CommonMark
- Markdown in this document.
+We flag any significant differences between Redcarpet and CommonMark Markdown in this document.
If you have a large volume of Markdown files, it can be tedious to determine
if they display correctly or not. You can use the
-[diff_redcarpet_cmark](https://gitlab.com/digitalmoksha/diff_redcarpet_cmark)
+[`diff_redcarpet_cmark`](https://gitlab.com/digitalmoksha/diff_redcarpet_cmark)
tool (not an officially supported product) to generate a list of files and the
differences between how RedCarpet and CommonMark render the files. It gives
an indication if anything needs to be changed - often nothing needs
@@ -126,7 +124,7 @@ changing how standard Markdown is used:
### Colors
-> If this is not rendered correctly, [view it in GitLab itself](https://gitlab.com/gitlab-org/gitlab/blob/master/doc/user/markdown.md#colors).
+If this section is not rendered correctly, [view it in GitLab](https://gitlab.com/gitlab-org/gitlab/blob/master/doc/user/markdown.md#colors).
It's possible to have color written in HEX, RGB, or HSL format rendered with a color
indicator.
@@ -235,7 +233,7 @@ To make PlantUML available in GitLab, a GitLab administrator needs to enable it
### Emoji
-> If this is not rendered correctly, [view it in GitLab itself](https://gitlab.com/gitlab-org/gitlab/blob/master/doc/user/markdown.md#emoji).
+If this section is not rendered correctly, [view it in GitLab](https://gitlab.com/gitlab-org/gitlab/blob/master/doc/user/markdown.md#emoji).
```markdown
Sometimes you want to :monkey: around a bit and add some :star2: to your :speech_balloon:. Well we have a gift for you:
@@ -259,13 +257,14 @@ If you're new to this, don't be <img src="https://gitlab.com/gitlab-org/gitlab-f
Consult the [Emoji Cheat Sheet](https://www.webfx.com/tools/emoji-cheat-sheet/) for a list of all supported emoji codes. <img src="https://gitlab.com/gitlab-org/gitlab-foss/raw/master/app/assets/images/emoji/thumbsup.png" width="20px" height="20px" style="display:inline;margin:0">
-NOTE: **Note:**
+#### Emoji and your OS
+
The emoji example above uses hard-coded images for this documentation. The emoji,
when rendered within GitLab, may appear different depending on the OS and browser used.
-Most emoji are natively supported on macOS, Windows, iOS, Android, and fall back on image-based emoji where there is no support.
+Most emoji are natively supported on macOS, Windows, iOS, Android, and fall back on image-based
+emoji where there is no support.
-NOTE: **Note:**
On Linux, you can download [Noto Color Emoji](https://www.google.com/get/noto/help/emoji/)
to get full native emoji support. Ubuntu 18.04 (like many modern Linux distributions) has
this font installed by default.
@@ -335,7 +334,7 @@ $example = array(
### Inline diff
-> If this is not rendered correctly, [view it in GitLab itself](https://gitlab.com/gitlab-org/gitlab/blob/master/doc/user/markdown.md#inline-diff).
+If this section is not rendered correctly, [view it in GitLab](https://gitlab.com/gitlab-org/gitlab/blob/master/doc/user/markdown.md#inline-diff).
With inline diff tags you can display `{+ additions +}` or `[- deletions -]`.
@@ -374,7 +373,7 @@ backslash `\`, otherwise the diff highlight don't render correctly:
### Math
-> If this is not rendered correctly, [view it in GitLab itself](https://gitlab.com/gitlab-org/gitlab/blob/master/doc/user/markdown.md#math).
+If this section is not rendered correctly, [view it in GitLab](https://gitlab.com/gitlab-org/gitlab/blob/master/doc/user/markdown.md#math).
It's possible to have math written with LaTeX syntax rendered using [KaTeX](https://github.com/KaTeX/KaTeX).
@@ -402,8 +401,7 @@ a^2+b^2=c^2
_Be advised that KaTeX only supports a [subset](https://katex.org/docs/supported.html) of LaTeX._
-NOTE: **Note:**
-This also works for the Asciidoctor `:stem: latexmath`. For details see
+This also works for the Asciidoctor `:stem: latexmath`. For details, see
the [Asciidoctor user manual](https://asciidoctor.org/docs/user-manual/#activating-stem-support).
### Special GitLab references
@@ -446,7 +444,7 @@ recognized and formatted with text `#123`.
In addition to this, links to some objects are also recognized and formatted. Some examples of these are:
-- Comments on issues: `"https://gitlab.com/gitlab-org/gitlab/-/issues/1234#note_101075757"`, which are rendered as `#1234 (note1)`
+- Comments on issues: `"https://gitlab.com/gitlab-org/gitlab/-/issues/1234#note_101075757"`, which are rendered as `#1234 (comment 101075757)`
- The issues designs tab: `"https://gitlab.com/gitlab-org/gitlab/-/issues/1234/designs"`, which are rendered as `#1234 (designs)`.
- Links to individual designs: `"https://gitlab.com/gitlab-org/gitlab/-/issues/1234/designs/layout.png"`, which are rendered as `#1234[layout.png]`.
@@ -607,9 +605,9 @@ Quote break.
#### Multiline blockquote
-> If this is not rendered correctly, [view it in GitLab itself](https://gitlab.com/gitlab-org/gitlab/blob/master/doc/user/markdown.md#multiline-blockquote).
+If this section is not rendered correctly, [view it in GitLab](https://gitlab.com/gitlab-org/gitlab/blob/master/doc/user/markdown.md#multiline-blockquote).
-GFM extends the standard Markdown standard by also supporting multi-line blockquotes
+GFM extends the standard Markdown by also supporting multi-line blockquotes
fenced by `>>>`:
```markdown
@@ -688,7 +686,7 @@ Tildes are OK too.
#### Colored code and syntax highlighting
-> If this is not rendered correctly, [view it in GitLab itself](https://gitlab.com/gitlab-org/gitlab/blob/master/doc/user/markdown.md#colored-code-and-syntax-highlighting).
+If this section is not rendered correctly, [view it in GitLab](https://gitlab.com/gitlab-org/gitlab/blob/master/doc/user/markdown.md#colored-code-and-syntax-highlighting).
GitLab uses the [Rouge Ruby library](http://rouge.jneen.net/) for more colorful syntax
highlighting in code blocks. For a list of supported languages visit the
@@ -781,7 +779,7 @@ Strikethrough is not part of the core Markdown standard, but is part of GFM.
#### Multiple underscores in words and mid-word emphasis
-> If this is not rendered correctly, [view it in GitLab itself](https://gitlab.com/gitlab-org/gitlab/blob/master/doc/user/markdown.md#multiple-underscores-in-words).
+If this section is not rendered correctly, [view it in GitLab](https://gitlab.com/gitlab-org/gitlab/blob/master/doc/user/markdown.md#multiple-underscores-in-words).
It's not usually useful to italicize just _part_ of a word, especially when you're
dealing with code and names that often appear with multiple underscores. As a result,
@@ -973,7 +971,7 @@ Do not change to a reference style link.
#### Videos
-> If this is not rendered correctly, [view it in GitLab itself](https://gitlab.com/gitlab-org/gitlab/blob/master/doc/user/markdown.md#videos).
+If this section is not rendered correctly, [view it in GitLab](https://gitlab.com/gitlab-org/gitlab/blob/master/doc/user/markdown.md#videos).
Image tags that link to files with a video extension are automatically converted to
a video player. The valid video extensions are `.mp4`, `.m4v`, `.mov`, `.webm`, and `.ogv`:
@@ -990,7 +988,7 @@ Here's a sample video:
#### Audio
-> If this is not rendered correctly, [view it in GitLab itself](https://gitlab.com/gitlab-org/gitlab/blob/master/doc/user/markdown.md#audio).
+If this section is not rendered correctly, [view it in GitLab](https://gitlab.com/gitlab-org/gitlab/blob/master/doc/user/markdown.md#audio).
Similar to videos, link tags for files with an audio extension are automatically converted to
an audio player. The valid audio extensions are `.mp3`, `.oga`, `.ogg`, `.spx`, and `.wav`:
@@ -1007,7 +1005,7 @@ Here's a sample audio clip:
### Inline HTML
-> To see the Markdown rendered within HTML in the second example, [view it in GitLab itself](https://gitlab.com/gitlab-org/gitlab/blob/master/doc/user/markdown.md#inline-html).
+To see the Markdown rendered within HTML in the second example, [view it in GitLab](https://gitlab.com/gitlab-org/gitlab/blob/master/doc/user/markdown.md#inline-html).
You can also use raw HTML in your Markdown, and it usually works pretty well.
@@ -1071,7 +1069,7 @@ Markdown is fine in GitLab.
#### Details and summary
-> To see the Markdown rendered within HTML in the second example, [view it in GitLab itself](https://gitlab.com/gitlab-org/gitlab/blob/master/doc/user/markdown.md#details-and-summary).
+To see the Markdown rendered within HTML in the second example, [view it in GitLab](https://gitlab.com/gitlab-org/gitlab/blob/master/doc/user/markdown.md#details-and-summary).
Content can be collapsed using HTML's [`<details>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/details)
and [`<summary>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/summary)
@@ -1105,7 +1103,7 @@ These details <em>remain</em> <strong>hidden</strong> until expanded.
Markdown inside these tags is supported as well.
-NOTE: **Note:**
+TIP: **Tip:**
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">`.
@@ -1420,26 +1418,20 @@ Example:
```markdown
| header 1 | header 2 | header 3 |
-| --- | ------ |---------:|
+| --- | ------ |----------|
| cell 1 | cell 2 | cell 3 |
| cell 4 | cell 5 is longer | cell 6 is much longer than the others, but that's ok. It eventually wraps the text when the cell is too large for the display size. |
-| cell 7 | | cell <br> 9 |
-| cell 10 | <ul><li> - [ ] Task One </li></ul> | <ul><li> - [ ] Task Two </li><li> - [ ] Task Three </li></ul> |
+| cell 7 | | cell 9 |
```
| header 1 | header 2 | header 3 |
-| --- | ------ |---------:|
+| --- | ------ |----------|
| cell 1 | cell 2 | cell 3 |
| cell 4 | cell 5 is longer | cell 6 is much longer than the others, but that's ok. It eventually wraps the text when the cell is too large for the display size. |
-| cell 7 | | cell <br> 9 |
-| cell 10 | <ul><li> - [ ] Task One </li></ul> | <ul><li> - [ ] Task Two </li><li> - [ ] Task Three </li></ul> |
+| cell 7 | | cell 9 |
Additionally, you can choose the alignment of text within columns by adding colons (`:`)
-to the sides of the "dash" lines in the second row. This affects every cell in the column.
-
-NOTE: **Note:**
-[Within GitLab itself](https://gitlab.com/gitlab-org/gitlab/blob/master/doc/user/markdown.md#tables),
-the headers are always left-aligned in Chrome and Firefox, and centered in Safari.
+to the sides of the "dash" lines in the second row. This affects every cell in the column:
```markdown
| Left Aligned | Centered | Right Aligned | Left Aligned | Centered | Right Aligned |
@@ -1453,6 +1445,34 @@ the headers are always left-aligned in Chrome and Firefox, and centered in Safar
| Cell 1 | Cell 2 | Cell 3 | Cell 4 | Cell 5 | Cell 6 |
| Cell 7 | Cell 8 | Cell 9 | Cell 10 | Cell 11 | Cell 12 |
+[Within GitLab itself](https://gitlab.com/gitlab-org/gitlab/blob/master/doc/user/markdown.md#tables),
+the headers are always left-aligned in Chrome and Firefox, and centered in Safari.
+
+You can use HTML formatting to adjust the rendering of tables. For example, you can
+use `<br>` tags to force a cell to have multiple lines:
+
+```markdown
+| Name | Details |
+|------|---------|
+| Item1 | This is on one line |
+| Item2 | This item has:<br>- Multiple items<br>- That we want listed separately |
+```
+
+| Name | Details |
+|------|---------|
+| Item1 | This is on one line |
+| Item2 | This item has:<br>- Multiple items<br>- That we want listed separately |
+
+You can use HTML formatting within GitLab itself to add [task lists](#task-lists) with checkboxes,
+but they do not render properly on `docs.gitlab.com`:
+
+```markdown
+| header 1 | header 2 |
+|----------|----------|
+| cell 1 | cell 2 |
+| cell 3 | <ul><li> - [ ] Task one </li><li> - [ ] Task two </li></ul> |
+```
+
#### Copy from spreadsheet and paste in Markdown
[Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/27205) in GitLab 12.7.
@@ -1474,5 +1494,5 @@ entry and paste the spreadsheet:
- This document leveraged heavily from the [Markdown-Cheatsheet](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet).
- The original [Markdown Syntax Guide](https://daringfireball.net/projects/markdown/syntax)
at Daring Fireball is an excellent resource for a detailed explanation of standard Markdown.
-- The detailed specification for CommonMark can be found in the [CommonMark Spec](https://spec.commonmark.org/current/)
-- The [CommonMark Dingus](http://try.commonmark.org) is a handy tool for testing CommonMark syntax.
+- You can find the detailed specification for CommonMark in the [CommonMark Spec](https://spec.commonmark.org/current/).
+- The [CommonMark Dingus](https://spec.commonmark.org/dingus/) is a handy tool for testing CommonMark syntax.
diff --git a/doc/user/packages/composer_repository/img/project_id_v13_5.png b/doc/user/packages/composer_repository/img/project_id_v13_5.png
new file mode 100644
index 00000000000..45861b6ff1b
--- /dev/null
+++ b/doc/user/packages/composer_repository/img/project_id_v13_5.png
Binary files differ
diff --git a/doc/user/packages/composer_repository/index.md b/doc/user/packages/composer_repository/index.md
index 89e02b4847c..d4fb662c3a6 100644
--- a/doc/user/packages/composer_repository/index.md
+++ b/doc/user/packages/composer_repository/index.md
@@ -4,172 +4,259 @@ group: Package
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/#designated-technical-writers
---
-# GitLab Composer Repository
+# Composer packages in the Package Registry
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/15886) in [GitLab Premium](https://about.gitlab.com/pricing/) 13.2.
> - [Moved](https://gitlab.com/gitlab-org/gitlab/-/issues/221259) to GitLab Core in 13.3.
-With the GitLab Composer Repository, every project can have its own space to store [Composer](https://getcomposer.org/) packages.
+Publish [Composer](https://getcomposer.org/) packages in your project's Package Registry.
+Then, install the packages whenever you need to use them as a dependency.
-## Enabling the Composer Repository
+Only Composer 1.x is supported. Consider contributing or even adding support for
+[Composer 2.0 in the Package Registry](https://gitlab.com/gitlab-org/gitlab/-/issues/259840).
-NOTE: **Note:**
-This option is available only if your GitLab administrator has
-[enabled support for the Package Registry](../../../administration/packages/index.md).
+## Create a Composer package
-When the Composer Repository is enabled, it is available for all new projects
-by default. To enable it for existing projects, or if you want to disable it:
+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.
-1. Navigate to your project's **Settings > General > Visibility, project features, permissions**.
-1. Find the Packages feature and enable or disable it.
-1. Click on **Save changes** for the changes to take effect.
+1. Create a directory called `my-composer-package` and change to that directory:
-You should then be able to see the **Packages & Registries** section on the left sidebar.
+ ```shell
+ mkdir my-composer-package && cd my-composer-package
+ ```
-## Getting started
+1. Run [`composer init`](https://getcomposer.org/doc/03-cli.md#init) and answer the prompts.
-This section covers creating a new example Composer package to publish. This is a
-quickstart to test out the **GitLab Composer Registry**.
+ For namespace, enter your unique [namespace](../../../user/group/index.md#namespaces), like your GitLab username or group name.
-To complete this section, you need a recent version of [Composer](https://getcomposer.org/).
+ A file called `composer.json` is created:
-### Creating a package project
+ ```json
+ {
+ "name": "<namespace>/composer-test",
+ "description": "Library XY",
+ "type": "library",
+ "license": "GPL-3.0-only",
+ "authors": [
+ {
+ "name": "John Doe",
+ "email": "john@example.com"
+ }
+ ],
+ "require": {}
+ }
+ ```
-Understanding how to create a full Composer project is outside the scope of this
-guide, but you can create a small package to test out the registry. Start by
-creating a new directory called `my-composer-package`:
+1. Run Git commands to tag the changes and push them to your repository:
-```shell
-mkdir my-composer-package && cd my-composer-package
-```
+ ```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 master
+ git push origin v1.0.0
+ ```
-Create a new `composer.json` file inside this directory to set up the basic project:
+The package is now in your GitLab Package Registry.
-```shell
-touch composer.json
-```
+## Publish a Composer package by using the API
-Inside `composer.json`, add the following code:
+Publish a Composer package to the Package Registry,
+so that anyone who can access the project can use the package as a dependency.
-```json
-{
- "name": "<namespace>/composer-test",
- "type": "library",
- "license": "GPL-3.0-only",
- "version": "1.0.0"
-}
-```
+Prerequisites:
-Replace `<namespace>` with a unique namespace like your GitLab username or group name.
+- A package in a GitLab repository.
+- A valid `composer.json` file.
+- The Packages feature is enabled in a GitLab repository.
+- The project ID, which is on the project's home page.
+- A [personal access token](../../../user/profile/personal_access_tokens.md) with the scope set to `api`.
-After this basic package structure is created, we need to tag it in Git and push it to the repository.
+ NOTE: **Note:**
+ [Deploy tokens](./../../project/deploy_tokens/index.md) are
+ [not yet supported](https://gitlab.com/gitlab-org/gitlab/-/issues/240897) for use with Composer.
-```shell
-git init
-git add composer.json
-git commit -m 'Composer package test'
-git tag v1.0.0
-git remote add origin git@gitlab.com:<namespace>/<project-name>.git
-git push --set-upstream origin master
-git push origin v1.0.0
-```
+To publish the package:
-### Publishing the package
+- Send a `POST` request to the [Packages API](../../../api/packages.md).
-Now that the basics of our project is completed, we can publish the package.
-To publish the package, you need:
+ For example, you can use `curl`:
-- A personal access token or `CI_JOB_TOKEN`.
+ ```shell
+ curl --data tag=<tag> "https://__token__:<personal-access-token>@gitlab.example.com/api/v4/projects/<project_id>/packages/composer"
+ ```
- ([Deploy tokens](./../../project/deploy_tokens/index.md) are not yet supported for use with Composer.)
+ - `<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>`.
-- Your project ID which can be found on the home page of your project.
+You can view the published package by going to **Packages & Registries > Package Registry** and
+selecting the **Composer** tab.
-To publish the package hosted on GitLab, make a `POST` request to the GitLab package API.
-A tool like `curl` can be used to make this request:
+## Publish a Composer package by using CI/CD
-You can generate a [personal access token](../../../user/profile/personal_access_tokens.md) with the scope set to `api` for repository authentication. For example:
+You can publish a Composer package to the Package Registry as part of your CI/CD process.
-```shell
-curl --data tag=<tag> 'https://__token__:<personal-access-token>@gitlab.com/api/v4/projects/<project_id>/packages/composer'
-```
+1. Specify a `CI_JOB_TOKEN` in your `.gitlab-ci.yml` file:
-Where:
+ ```yaml
+ stages:
+ - deploy
-- `<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. In this example it should be `v1.0.0`. Notice that instead of `tag=<tag>` you can also use `branch=<branch>` to publish branches.
+ deploy:
+ stage: deploy
+ script:
+ - 'curl --header "Job-Token: $CI_JOB_TOKEN" --data tag=<tag> "https://gitlab.example.com/api/v4/projects/$CI_PROJECT_ID/packages/composer"'
+ ```
-If the above command succeeds, you now should be able to see the package under the **Packages & Registries** section of your project page.
+1. Run the pipeline.
-### Publishing the package with CI/CD
+You can view the published package by going to **Packages & Registries > Package Registry** and selecting the **Composer** tab.
-To work with Composer commands within [GitLab CI/CD](./../../../ci/README.md), you can
-publish Composer packages by using `CI_JOB_TOKEN` in your `.gitlab-ci.yml` file:
+### Use a CI/CD template
-```yaml
-stages:
- - deploy
+A more detailed Composer CI/CD file is also available as a `.gitlab-ci.yml` template:
-deploy:
- stage: deploy
- script:
- - 'curl --header "Job-Token: $CI_JOB_TOKEN" --data tag=<tag> "https://gitlab.example.com/api/v4/projects/$CI_PROJECT_ID/packages/composer"'
-```
+1. On the left sidebar, click **Project overview**.
+1. Above the file list, click **Set up CI/CD**. If this button is not available, select **CI/CD Configuration** and then **Edit**.
+1. From the **Apply a template** list, select **Composer**.
-### Installing a package
+CAUTION: **Warning:**
+Do not save unless you want to overwrite the existing CI/CD file.
-To install your package, you need:
+## Install a Composer package
-- A personal access token. You can generate a [personal access token](../../../user/profile/personal_access_tokens.md) with the scope set to `api` for repository authentication.
-- Your group ID which can be found on the home page of your project's group.
+Install a package from the Package Registry so you can use it as a dependency.
-Add the GitLab Composer package repository to your existing project's `composer.json` file, along with the package name and version you want to install like so:
+Prerequisites:
-```json
-{
- ...
- "repositories": [
- { "type": "composer", "url": "https://gitlab.com/api/v4/group/<group_id>/-/packages/composer/packages.json" }
- ],
- "require": {
- ...
- "<package_name>": "<version>"
- },
- ...
-}
-```
+- A package in the Package Registry.
+- The group ID, which is on the group's home page.
+- A [personal access token](../../../user/profile/personal_access_tokens.md) with the scope set to, at minimum, `read_api`.
-Where:
+ NOTE: **Note:**
+ [Deploy tokens](./../../project/deploy_tokens/index.md) are
+ [not yet supported](https://gitlab.com/gitlab-org/gitlab/-/issues/240897) for use with Composer.
-- `<group_id>` is the group ID found under your project's group page.
-- `<package_name>` is your package name as defined in your package's `composer.json` file.
-- `<version>` is your package version (`1.0.0` in this example).
+To install a package:
-You also need to create a `auth.json` file with your GitLab credentials:
+1. Add the Package Registry URL to your project's `composer.json` file, along with the package name and version you want to install:
-```json
-{
- "gitlab-token": {
- "gitlab.com": "<personal_access_token>"
- }
-}
-```
+ - Connect to the Package Registry for your group:
-Where:
+ ```shell
+ composer config repositories.<group_id> composer https://gitlab.example.com/api/v4/group/<group_id>/-/packages/composer/
+ ```
-- `<personal_access_token>` is your personal access token.
+ - Set the required package version:
-With the `composer.json` and `auth.json` files configured, you can install the package by running `composer`:
+ ```shell
+ composer require <package_name>:<version>
+ ```
-```shell
-composer update
-```
+ Result in the `composer.json` file:
-If successful, you should be able to see the output indicating that the package has been successfully installed.
+ ```json
+ {
+ ...
+ "repositories": {
+ "<group_id>": {
+ "type": "composer",
+ "url": "https://gitlab.example.com/api/v4/group/<group_id>/-/packages/composer/"
+ },
+ ...
+ },
+ "require": {
+ ...
+ "<package_name>": "<version>"
+ },
+ ...
+ }
+ ```
+
+ You can unset this with the command:
+
+ ```shell
+ composer config --unset repositories.<group_id>
+ ```
+
+ - `<group_id>` is the group ID.
+ - `<package_name>` is the package name defined in your package's `composer.json` file.
+ - `<version>` is the package version.
+
+1. Create an `auth.json` file with your GitLab credentials:
+
+ ```shell
+ composer config gitlab-token.<DOMAIN-NAME> <personal_access_token>
+ ```
+
+ Result in the `auth.json` file:
+
+ ```json
+ {
+ ...
+ "gitlab-token": {
+ "<DOMAIN-NAME>": "<personal_access_token>",
+ ...
+ }
+ }
+ ```
+
+ You can unset this with the command:
+
+ ```shell
+ composer config --unset --auth gitlab-token.<DOMAIN-NAME>
+ ```
+
+ - `<DOMAIN-NAME>` is the GitLab instance URL `gitlab.com` or `gitlab.example.com`.
+ - `<personal_access_token>` with the scope set to `read_api`.
+
+1. If you are on a GitLab self-managed instance, add `gitlab-domains` to `composer.json`.
+
+ ```shell
+ composer config gitlab-domains gitlab01.example.com gitlab02.example.com
+ ```
+
+ Result in the `composer.json` file:
+
+ ```json
+ {
+ ...
+ "repositories": [
+ { "type": "composer", "url": "https://gitlab.example.com/api/v4/group/<group_id>/-/packages/composer/" }
+ ],
+ "config": {
+ ...
+ "gitlab-domains": ["gitlab01.example.com", "gitlab02.example.com"]
+ },
+ "require": {
+ ...
+ "<package_name>": "<version>"
+ },
+ ...
+ }
+ ```
+
+ You can unset this with the command:
+
+ ```shell
+ composer config --unset gitlab-domains
+ ```
+
+ NOTE: **Note:**
+ On GitLab.com, Composer uses the GitLab token from `auth.json` as a private token by default.
+ Without the `gitlab-domains` definition in `composer.json`, Composer uses the GitLab token
+ as basic-auth, with the token as a username and a blank password. This results in a 401 error.
+
+Output indicates that the package has been successfully installed.
CAUTION: **Important:**
-Make sure to never commit the `auth.json` file to your repository. To install packages from a CI job,
+Never commit the `auth.json` file to your repository. To install packages from a CI/CD job,
consider using the [`composer config`](https://getcomposer.org/doc/articles/handling-private-packages-with-satis.md#authentication) tool with your personal access token
stored in a [GitLab CI/CD environment variable](../../../ci/variables/README.md) or in
-[Hashicorp Vault](../../../ci/secrets/index.md).
+[HashiCorp Vault](../../../ci/secrets/index.md).
diff --git a/doc/user/packages/conan_repository/img/conan_package_view.png b/doc/user/packages/conan_repository/img/conan_package_view.png
deleted file mode 100644
index 742fb4195da..00000000000
--- a/doc/user/packages/conan_repository/img/conan_package_view.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/packages/conan_repository/index.md b/doc/user/packages/conan_repository/index.md
index 7c3082e0f83..10c820a86be 100644
--- a/doc/user/packages/conan_repository/index.md
+++ b/doc/user/packages/conan_repository/index.md
@@ -4,153 +4,150 @@ group: Package
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/#designated-technical-writers
---
-# GitLab Conan Repository
+# Conan packages in the Package Registry
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/8248) in [GitLab Premium](https://about.gitlab.com/pricing/) 12.6.
> - [Moved](https://gitlab.com/gitlab-org/gitlab/-/issues/221259) to GitLab Core in 13.3.
-With the GitLab Conan Repository, every
-project can have its own space to store Conan packages.
+Publish Conan packages in your project’s Package Registry. Then install the
+packages whenever you need to use them as a dependency.
-![GitLab Conan Repository](img/conan_package_view.png)
+To publish Conan packages to the Package Registry, add the
+Package Registry as a remote and authenticate with it.
-## Enabling the Conan Repository
+Then you can run `conan` commands and publish your package to the Package Registry.
-NOTE: **Note:**
-This option is available only if your GitLab administrator has
-[enabled support for the Conan Repository](../../../administration/packages/index.md).
-
-After the Conan Repository is enabled, it's available for all new projects
-by default. To enable it for existing projects, or if you want to disable it:
-
-1. Navigate to your project's **Settings > General > Visibility, project features, permissions**.
-1. Find the Packages feature and enable or disable it.
-1. Click on **Save changes** for the changes to take effect.
-
-You should then be able to see the **Packages & Registries** section on the left sidebar.
+## Build a Conan package
-## Getting started
+This section explains how to install Conan and build a package for your C/C++ project.
-This section covers installing Conan and building a package for your C/C++ project. This is a quickstart if you're new
-to Conan. If you already are using Conan and understand how to build your own packages, move on to the [next section](#adding-the-gitlab-package-registry-as-a-conan-remote).
+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).
-### Installing Conan
+### Install Conan
-Follow the instructions at [conan.io](https://conan.io/downloads.html) to download the Conan package manager to your local development environment.
+Download the Conan package manager to your local development environment by following
+the instructions at [conan.io](https://conan.io/downloads.html).
-Once installation is complete, verify you can use Conan in your terminal by running
+When installation is complete, verify you can use Conan in your terminal by running:
```shell
conan --version
```
-You should see the Conan version printed in the output:
+The Conan version is printed in the output:
```plaintext
Conan version 1.20.5
```
-### Installing CMake
+### Install CMake
+
+When you develop with C++ and Conan, you have a range of compilers to choose from.
+This example uses the CMake compiler.
+
+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 developing with C++ and Conan, you have a wide range of options for compilers. This tutorial walks through using the cmake
-compiler. In your terminal, run the command
+When installation is complete, verify you can use CMake in your terminal by running:
```shell
cmake --version
```
-You should see the cmake version printed in the output. If you see something else, you may have to install cmake.
+The CMake version is printed in the output.
-On a Mac, you can use [homebrew](https://brew.sh/) to install cmake by running `brew install cmake`. Otherwise, follow
-instructions at [cmake.org](https://cmake.org/install/) for your operating system.
+### Create a project
-### Creating 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).
-Understanding what is needed to create a valid and compilable C++ project is out of the scope of this guide, but if you're new to C++ and want to try out the GitLab
-package registry, Conan.io has a great [hello world starter project](https://github.com/conan-io/hello) that you can clone to get started.
+### Build a package
-Clone the repository and it can be used for the rest of the tutorial if you don't have your own C++ project.
+To build a package:
-### Building 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:
-In your terminal, navigate to the root folder of your project. Generate a new recipe by running `conan new` and providing it with a
-package name and version:
+ ```shell
+ conan new Hello/0.1 -t
+ ```
-```shell
-conan new Hello/0.1 -t
-```
-
-Next, create a package for that recipe by running `conan create` providing the Conan user and channel:
+1. Create a package for the recipe by running `conan create` with the Conan user and channel:
-```shell
-conan create . mycompany/beta
-```
+ ```shell
+ conan create . mycompany/beta
+ ```
-NOTE: **Note:**
-If you are using the [instance level remote](#instance-level-remote), a specific [naming convention](#package-recipe-naming-convention-for-instance-level-remote) must be followed.
+ NOTE: **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).
-These two example commands generate a final package with the recipe `Hello/0.1@mycompany/beta`.
+A package with the recipe `Hello/0.1@mycompany/beta` is created.
-For more advanced details on creating and managing your packages, refer to the [Conan docs](https://docs.conan.io/en/latest/creating_packages.html).
+For more details on creating and managing Conan packages, see the [Conan docs](https://docs.conan.io/en/latest/creating_packages.html).
-You are now ready to upload your package to the GitLab registry. To get started, first you need to set GitLab as a remote. Then you need to add a Conan user for that remote to authenticate your requests.
+## Add the Package Registry as a Conan remote
-## Adding the GitLab Package Registry as a Conan remote
+To run `conan` commands, you must add the Package Registry as a Conan remote for your project or instance.
-You can add the GitLab Package Registry as a Conan remote at the project or instance level.
-
-### Project level remote
+### Add a remote for your project
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/11679) in GitLab 13.4.
-The project level remote allows you to work with packages within a given project.
-The advantage of using the project level remote is there are no restrictions to your
-package name, however all GitLab Conan packages require a full recipe
-with the user and channel (`package_name/version@user/channel`).
+Set a remote so you can work with packages in a project without
+having to specify the remote name in every command.
+
+When you set a remote for a project, there are no restrictions to your package names.
+However, your commands must include the full recipe, including the user and channel,
+for example, `package_name/version@user/channel`.
To add the remote:
-```shell
-conan remote add gitlab https://gitlab.example.com/api/v4/projects/<project_id>/packages/conan
-```
+1. In your terminal, run this command:
-Once the remote is set, you can use the remote when running Conan commands by adding `--remote=gitlab` to the end of your commands.
+ ```shell
+ conan remote add gitlab https://gitlab.example.com/api/v4/projects/<project_id>/packages/conan
+ ```
-For example:
+1. Use the remote by adding `--remote=gitlab` to the end of your Conan command.
-```shell
-conan search Hello* --all --remote=gitlab
-```
+ For example:
-### Instance level remote
+ ```shell
+ conan search Hello* --all --remote=gitlab
+ ```
-The instance level remote allows you to use a single remote to access packages accross your entire
-GitLab instance. However, when using this remote, there are certain
-[package naming restrictions](#package-recipe-naming-convention-for-instance-level-remote)
-that must be followed.
+### Add a remote for your instance
-Add a new remote to your Conan configuration:
+Use a single remote to access packages across your entire GitLab instance.
-```shell
-conan remote add gitlab https://gitlab.example.com/api/v4/packages/conan
-```
+However, when using this remote, you must follow these
+[package naming restrictions](#package-recipe-naming-convention-for-instance-remotes).
+
+To add the remote:
-Once the remote is set, you can use the remote when running Conan commands by adding `--remote=gitlab` to the end of your commands.
+1. In your terminal, run this command:
-For example:
+ ```shell
+ conan remote add gitlab https://gitlab.example.com/api/v4/packages/conan
+ ```
-```shell
-conan search 'Hello*' --remote=gitlab
-```
+1. Use the remote by adding `--remote=gitlab` to the end of your Conan command.
-#### Package recipe naming convention for instance level remote
+ For example:
-The standard Conan recipe convention looks like `package_name/version@user/channel`,
-but if you're using the [instance level remote](#instance-level-remote), the recipe
+ ```shell
+ conan search 'Hello*' --remote=gitlab
+ ```
+
+#### Package recipe naming convention for instance remotes
+
+The standard Conan recipe convention is `package_name/version@user/channel`,
+but if you're using an [instance remote](#add-a-remote-for-your-instance), the recipe
`user` must be the plus sign (`+`) separated project path.
-The following table shows some example recipes you can give your package based on
-the project name and path.
+Example recipe names:
| Project | Package | Supported |
| ---------------------------------- | ----------------------------------------------- | --------- |
@@ -159,179 +156,202 @@ the project name and path.
| `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 |
-NOTE: **Note:**
-[Project level remotes](#project-level-remote) allow for more flexible package names.
+[Project remotes](#add-a-remote-for-your-project) have a more flexible naming convention.
-## Authenticating to the GitLab Conan Repository
+## Authenticate to the Package Registry
-You need a personal access token or deploy token.
+To authenticate to the Package Registry, you need either a personal access token or deploy token.
-For repository authentication:
+- If you use a [personal access token](../../../user/profile/personal_access_tokens.md), set the scope to `api`.
+- If you use a [deploy token](./../../project/deploy_tokens/index.md), set the scope to `read_package_registry`, `write_package_registry`, or both.
-- You can generate a [personal access token](../../../user/profile/personal_access_tokens.md) with the scope set to `api`.
-- You can generate a [deploy token](./../../project/deploy_tokens/index.md) with the scope set to `read_package_registry`, `write_package_registry`, or both.
+### Add your credentials to the GitLab remote
-### Adding a Conan user to the GitLab remote
+Associate your token with the GitLab remote, so that you don't have to explicitly
+add a token to every Conan command.
-Once you have a personal access token and have [set your Conan remote](#adding-the-gitlab-package-registry-as-a-conan-remote), you can associate the token with the remote so you don't have to explicitly add them to each Conan command you run:
+Prerequisites:
+
+- You must have an authentication token.
+- The Conan remote [must be set](#add-the-package-registry-as-a-conan-remote).
+
+In a terminal, run this command. In this example, the remote name is `gitlab`. Use the name of your remote.
```shell
conan user <gitlab_username or deploy_token_username> -r gitlab -p <personal_access_token or deploy_token>
```
-NOTE: **Note:**
-If you named your remote something other than `gitlab`, your remote name should be used in this command instead of `gitlab`.
-
-From now on, when you run commands using `--remote=gitlab`, your username and password is automatically included in the requests.
-
-NOTE: **Note:**
-The personal access token is not stored locally at any moment. Conan uses JSON Web Tokens (JWT), so when you run this command, Conan requests an expirable token from GitLab using your token. The JWT does expire on a regular basis, so you need to re-enter your personal access token when that happens.
+Now when you run commands with `--remote=gitlab`, your username and password are automatically included in the requests.
-Alternatively, you could explicitly include your credentials in any given command.
-For example:
+Alternately, you can explicitly include your credentials in any given command. For example:
```shell
CONAN_LOGIN_USERNAME=<gitlab_username or deploy_token_username> CONAN_PASSWORD=<personal_access_token or deploy_token> conan upload Hello/0.1@mycompany/beta --all --remote=gitlab
```
-### Setting a default remote to your project (optional)
+NOTE: **Note:**
+Your authentication with GitLab expires on a regular basis,
+so occasionally you may need to re-enter your personal access token.
+
+### Set a default remote for your project (optional)
+
+If you want to interact with the GitLab Package Registry without having to specify a remote,
+you can tell Conan to always use the Package Registry for your packages.
-If you'd like Conan to always use GitLab as the registry for your package, you can tell Conan to always reference the GitLab remote for a given package recipe:
+In a terminal, run this command.
```shell
conan remote add_ref Hello/0.1@mycompany/beta gitlab
```
NOTE: **Note:**
-The package recipe does include the version, so setting the default remote for `Hello/0.1@user/channel` will not work for `Hello/0.2@user/channel`.
-This functionality is best suited for when you want to consume or install packages from the GitLab registry without having to specify a remote.
+The package recipe includes the version, so the default remote for `Hello/0.1@user/channel` does not work for `Hello/0.2@user/channel`.
-The rest of the example commands in this documentation assume that you've added a Conan user with your credentials to the `gitlab` remote and will not include the explicit credentials or remote option. With that said, be aware that any of the commands could be run without having added a user or default remote:
+If you do not set a default user or remote, you can still include the user and remote in your commands:
```shell
`CONAN_LOGIN_USERNAME=<gitlab_username or deploy_token_username> CONAN_PASSWORD=<personal_access_token or deploy_token> <conan command> --remote=gitlab
```
-## Uploading a package
+## Publish a Conan package
-First you need to [create your Conan package locally](https://docs.conan.io/en/latest/creating_packages/getting_started.html).
+Publish a Conan package to the Package Registry, so that anyone who can access the project can use the package as a dependency.
-NOTE: **Note:**
-If you are using the [instance level remote](#instance-level-remote), a specific [naming convention](#package-recipe-naming-convention-for-instance-level-remote) must be followed.
+Prerequisites:
+
+To publish a Conan package, you need:
-Ensure you have a project created on GitLab and that the personal access token you're using has the correct permissions for write access to the container registry by selecting the `api` [scope](../../../user/profile/personal_access_tokens.md#limiting-scopes-of-a-personal-access-token).
+- The Package Registry [set as a remote](#add-the-package-registry-as-a-conan-remote).
+- [Authentication](#authenticate-to-the-package-registry) set up with the Package Registry.
+- A local [Conan package](https://docs.conan.io/en/latest/creating_packages/getting_started.html).
+ - For an instance remote, the package must meet the [naming convention](#package-recipe-naming-convention-for-instance-remotes).
+- A project ID, which is on the project's homepage.
-You can upload your package to the GitLab Package Registry using the `conan upload` command:
+To publish the package, use the `conan upload` command:
```shell
conan upload Hello/0.1@mycompany/beta --all
```
-## Installing a package
+## Publish a Conan package by using CI/CD
-Conan packages are commonly installed as dependencies using the `conanfile.txt` file.
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/11678) in [GitLab Premium](https://about.gitlab.com/pricing/) 12.7.
-In your project where you would like to install the Conan package as a dependency, open `conanfile.txt` or create
-an empty file named `conanfile.txt` in the root of your project.
+To work with Conan commands in [GitLab CI/CD](./../../../ci/README.md), you can use
+`CI_JOB_TOKEN` in place of the personal access token in your commands.
-Add the Conan recipe to the `[requires]` section of the file:
+You can provide the `CONAN_LOGIN_USERNAME` and `CONAN_PASSWORD` with each
+Conan command in your `.gitlab-ci.yml` file. For example:
-```ini
- [requires]
- Hello/0.1@mycompany/beta
+```yaml
+image: conanio/gcc7
- [generators]
- cmake
+create_package:
+ stage: deploy
+ script:
+ - conan remote add gitlab https://gitlab.example.com/api/v4/packages/conan
+ - conan new <package-name>/0.1 -t
+ - conan create . <group-name>+<project-name>/stable
+ - CONAN_LOGIN_USERNAME=ci_user CONAN_PASSWORD=${CI_JOB_TOKEN} conan upload <package-name>/0.1@<group-name>+<project-name>/stable --all --remote=gitlab
```
-Next, create a build directory from the root of your project and navigate to it:
+Additional Conan images to use as the basis of your CI file are available
+in the [Conan docs](https://docs.conan.io/en/latest/howtos/run_conan_in_docker.html#available-docker-images).
-```shell
-mkdir build && cd build
-```
+## Install a Conan package
-Now you can install the dependencies listed in `conanfile.txt`:
+Install a Conan package from the Package Registry so you can use it as a dependency.
-```shell
-conan install ..
-```
+Conan packages are often installed as dependencies by using the `conanfile.txt` file.
+
+Prerequisites:
+
+To install a Conan package, you need:
+
+- The Package Registry [set as a remote](#add-the-package-registry-as-a-conan-remote).
+- [Authentication](#authenticate-to-the-package-registry) set up with the Package Registry.
+
+1. In the project where you want to install the package as a dependency, open `conanfile.txt`.
+ Or, in the root of your project, create a file called `conanfile.txt`.
+
+1. Add the Conan recipe to the `[requires]` section of the file:
+
+ ```plaintext
+ [requires]
+ Hello/0.1@mycompany/beta
+
+ [generators]
+ cmake
+ ```
+
+1. At the root of your project, create a `build` directory and change to that directory:
+
+ ```shell
+ mkdir build && cd build
+ ```
+
+1. Install the dependencies listed in `conanfile.txt`:
+
+ ```shell
+ conan install <options>
+ ```
NOTE: **Note:**
-If you're trying to install the package you just created in this tutorial, not much will happen since that package
-already exists on your local machine.
+If you try to install the package you just created in this tutorial, the package
+already exists on your local machine, so this command has no effect.
-## Removing a package
+## Remove a Conan package
There are two ways to remove a Conan package from the GitLab Package Registry.
-- **Using the Conan client in the command line:**
+- From the command line, using the Conan client:
```shell
conan remove Hello/0.2@user/channel --remote=gitlab
```
- You need to explicitly include the remote in this command, otherwise the package is only removed from your
+ You must explicitly include the remote in this command, otherwise the package is only removed from your
local system cache.
NOTE: **Note:**
This command removes all recipe and binary package files from the Package Registry.
-- **GitLab project interface**: in the packages view of your project page, you can delete packages by clicking the red trash icons.
+- From the GitLab user interface:
-## Searching the GitLab Package Registry for Conan packages
+ Go to your project's **Packages & Registries > Package Registry**. Remove the package by clicking the red trash icon.
-The `conan search` command can be run searching by full or partial package name, or by exact recipe.
+## Search for Conan packages in the Package Registry
-To search using a partial name, use the wildcard symbol `*`, which should be placed at the end of your search (for example, `my-packa*`):
+To search by full or partial package name, or by exact recipe, run the `conan search` command.
-```shell
-conan search Hello --all --remote=gitlab
-conan search He* --all --remote=gitlab
-conan search Hello/0.1@mycompany/beta --all --remote=gitlab
-```
+- To search for all packages with a specific package name:
+
+ ```shell
+ conan search Hello --remote=gitlab
+ ```
-The scope of your search includes all projects you have permission to access, this includes your private projects as well as all public projects.
+- To search for a partial name, like all packages starting with `He`:
-## Fetching Conan package information from the GitLab Package Registry
+ ```shell
+ conan search He* --remote=gitlab
+ ```
-The `conan info` command returns information about a given package:
+The scope of your search includes all projects you have permission to access. This includes your private projects as well as all public projects.
+
+## Fetch Conan package information from the Package Registry
+
+The `conan info` command returns information about a package:
```shell
conan info Hello/0.1@mycompany/beta
```
-## List of supported CLI commands
+## Supported CLI commands
The GitLab Conan repository supports the following Conan CLI commands:
-- `conan upload`: Upload your recipe and package files to the GitLab Package Registry.
-- `conan install`: Install a conan package from the GitLab Package Registry, this includes using the `conanfile.txt` file.
-- `conan search`: Search the GitLab Package Registry for public packages, and private packages you have permission to view.
-- `conan info`: View the information on a given package from the GitLab Package Registry.
-- `conan remove`: Delete the package from the GitLab Package Registry.
-
-## Using GitLab CI with Conan packages
-
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/11678) in [GitLab Premium](https://about.gitlab.com/pricing/) 12.7.
-
-To work with Conan commands within [GitLab CI/CD](./../../../ci/README.md), you can use
-`CI_JOB_TOKEN` in place of the personal access token in your commands.
-
-It's easiest to provide the `CONAN_LOGIN_USERNAME` and `CONAN_PASSWORD` with each
-Conan command in your `.gitlab-ci.yml` file. For example:
-
-```yaml
-image: conanio/gcc7
-
-create_package:
- stage: deploy
- script:
- - conan remote add gitlab https://gitlab.example.com/api/v4/packages/conan
- - conan new <package-name>/0.1 -t
- - conan create . <group-name>+<project-name>/stable
- - CONAN_LOGIN_USERNAME=ci_user CONAN_PASSWORD=${CI_JOB_TOKEN} conan upload <package-name>/0.1@<group-name>+<project-name>/stable --all --remote=gitlab
-
-```
-
-You can find additional Conan images to use as the base of your CI file
-in the [Conan docs](https://docs.conan.io/en/latest/howtos/run_conan_in_docker.html#available-docker-images).
+- `conan upload`: Upload your recipe and package files to the Package Registry.
+- `conan install`: Install a Conan package from the Package Registry, this includes using the `conanfile.txt` file.
+- `conan search`: Search the Package Registry for public packages, and private packages you have permission to view.
+- `conan info`: View the information on a given package from the Package Registry.
+- `conan remove`: Delete the package from the Package Registry.
diff --git a/doc/user/packages/container_registry/img/container_registry_group_repositories_v13_1.png b/doc/user/packages/container_registry/img/container_registry_group_repositories_v13_1.png
deleted file mode 100644
index bbbba44eb9b..00000000000
--- a/doc/user/packages/container_registry/img/container_registry_group_repositories_v13_1.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/packages/container_registry/img/container_registry_hover_path_13_4.png b/doc/user/packages/container_registry/img/container_registry_hover_path_13_4.png
new file mode 100644
index 00000000000..2d16c11fe61
--- /dev/null
+++ b/doc/user/packages/container_registry/img/container_registry_hover_path_13_4.png
Binary files differ
diff --git a/doc/user/packages/container_registry/img/container_registry_repositories_v13_1.png b/doc/user/packages/container_registry/img/container_registry_repositories_v13_1.png
deleted file mode 100644
index 13a6d1a4470..00000000000
--- a/doc/user/packages/container_registry/img/container_registry_repositories_v13_1.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/packages/container_registry/img/container_registry_repositories_with_quickstart_v13_1.png b/doc/user/packages/container_registry/img/container_registry_repositories_with_quickstart_v13_1.png
deleted file mode 100644
index 35a02182a77..00000000000
--- a/doc/user/packages/container_registry/img/container_registry_repositories_with_quickstart_v13_1.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/packages/container_registry/img/container_registry_repository_details_v13.0.png b/doc/user/packages/container_registry/img/container_registry_repository_details_v13.0.png
deleted file mode 100644
index 088e80221de..00000000000
--- a/doc/user/packages/container_registry/img/container_registry_repository_details_v13.0.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/packages/container_registry/index.md b/doc/user/packages/container_registry/index.md
index 077666bc036..baadd3c91a7 100644
--- a/doc/user/packages/container_registry/index.md
+++ b/doc/user/packages/container_registry/index.md
@@ -9,235 +9,186 @@ info: To determine the technical writer assigned to the Stage/Group associated w
> - [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/4040) in GitLab 8.8.
> - Docker Registry manifest `v1` support was added in GitLab 8.9 to support Docker
> versions earlier than 1.10.
-> - Starting from GitLab 8.12, if you have 2FA enabled in your account, you need
-> to pass a [personal access token](../../profile/personal_access_tokens.md) instead of your password in order to
-> login to GitLab's Container Registry.
-> - Multiple level image names support was added in GitLab 9.1.
-> - The group level Container Registry was [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/23315) in GitLab 12.10.
+> - Starting in GitLab 8.12, if you have [two-factor authentication](../../profile/account/two_factor_authentication.md) enabled in your account, you need
+> to pass a [personal access token](../../profile/personal_access_tokens.md) instead of your password to
+> sign in to the Container Registry.
+> - Support for multiple level image names was added in GitLab 9.1.
+> - The group-level Container Registry was [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/23315) in GitLab 12.10.
> - Searching by image repository name was [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/31322) in GitLab 13.0.
-NOTE: **Note:**
-This document is the user guide. To learn how to enable GitLab Container
-Registry across your GitLab instance, visit the
-[administrator documentation](../../../administration/packages/container_registry.md).
-
-With the Docker Container Registry integrated into GitLab, every project can
+With the Docker Container Registry integrated into GitLab, every GitLab project can
have its own space to store its Docker images.
You can read more about Docker Registry at <https://docs.docker.com/registry/introduction/>.
-![Container Registry repositories](img/container_registry_repositories_v13_1.png)
-
-## Enable the Container Registry for your project
-
-CAUTION: **Warning:**
-The Container Registry follows the visibility settings of the project. If the project is public, so is the Container Registry.
-
-If you cannot find the **Packages & Registries > Container Registry** entry under your
-project's sidebar, it is not enabled in your GitLab instance. Ask your
-administrator to enable GitLab Container Registry following the
-[administration documentation](../../../administration/packages/container_registry.md).
+This document is the user guide. To learn how to enable the Container
+Registry for your GitLab instance, visit the
+[administrator documentation](../../../administration/packages/container_registry.md).
-If you are using GitLab.com, this is enabled by default so you can start using
-the Registry immediately. Currently there is a soft (10GB) size restriction for
-Registry on GitLab.com, as part of the [repository size limit](../../project/repository/index.md).
+## View the Container Registry
-Once enabled for your GitLab instance, to enable Container Registry for your
-project:
+You can view the Container Registry for a project or group.
-1. Go to your project's **Settings > General** page.
-1. Expand the **Visibility, project features, permissions** section
- and enable the **Container Registry** feature on your project. For new
- projects this might be enabled by default. For existing projects
- (prior GitLab 8.8), enable it explicitly.
-1. Press **Save changes** for the changes to take effect. You should now be able
- to see the **Packages & Registries > Container Registry** link in the sidebar.
+1. Go to your project or group.
+1. Go to **Packages & Registries > Container Registry**.
-## Control Container Registry from within GitLab
+You can search, sort, filter, and [delete](#delete-images-from-within-gitlab) containers on this page.
-GitLab offers a simple Container Registry management panel. This management panel is available
-for both projects and groups.
+Only members of the project or group can access a private project's Container Registry.
-### Control Container Registry for your project
+If a project is public, so is the Container Registry.
-Navigate to your project's **{package}** **Packages & Registries > Container Registry**.
+## Use images from the Container Registry
-![Container Registry project repositories](img/container_registry_repositories_with_quickstart_v13_1.png)
+To download and run a container image hosted in the GitLab Container Registry:
-This view allows you to:
+1. Copy the link to your container image:
+ - Go to your project or group's **Packages & Registries > Container Registry**
+ and find the image you want.
+ - Next to the image name, click the **Copy** button.
-- Show all the image repositories that belong to the project.
-- Filter image repositories by their name.
-- [Delete](#delete-images-from-within-gitlab) one or more image repository.
-- Navigate to the image repository details page.
-- Show a **Quick start** dropdown with the most common commands to log in, build and push.
-- Show a banner if the optional [cleanup policy](#cleanup-policy) is enabled for this project.
+ ![Container Registry image URL](img/container_registry_hover_path_13_4.png)
-### Control Container Registry for your group
+1. Use `docker run` with the image link:
-Navigate to your group's **{package}** **Packages & Registries > Container Registry**.
+ ```shell
+ docker run [options] registry.example.com/group/project/image [arguments]
+ ```
-![Container Registry group repositories](img/container_registry_group_repositories_v13_1.png)
+For more information on running Docker containers, visit the
+[Docker documentation](https://docs.docker.com/engine/userguide/intro/).
-This view allows you to:
+## Image naming convention
-- Show all the image repositories of the projects that belong to this group.
-- [Delete](#delete-images-from-within-gitlab) one or more image repositories.
-- Navigate to a specific image repository details page.
+Images follow this naming convention:
-### Image Repository details page
+```plaintext
+<registry URL>/<namespace>/<project>/<image>
+```
-Clicking on the name of any image repository navigates to the details.
+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.
-![Container Registry project repository details](img/container_registry_repository_details_v13.0.png)
+You can append additional names to the end of an image name, up to three levels deep.
-NOTE: **Note:**
-The following page has the same functionalities both in the **Group level container registry**
-and in the **Project level container registry**.
+For example, these are all valid image names for images within the project named `myproject`:
-This view:
+```plaintext
+registry.example.com/mynamespace/myproject:some-tag
+```
-- Shows all the image repository details.
-- Shows all the tags of the image repository.
-- Allows you to quickly copy the tag path (by clicking on the clipboard button near the tag name).
-- Allows you to [delete one or more tags](#delete-images-from-within-gitlab).
+```plaintext
+registry.example.com/mynamespace/myproject/image:latest
+```
-## Use images from GitLab Container Registry
+```plaintext
+registry.example.com/mynamespace/myproject/my/image:rc1
+```
-To download and run a container from images hosted in GitLab Container Registry,
-use `docker run`:
+## Build and push images by using Docker commands
-```shell
-docker run [options] registry.example.com/group/project/image [arguments]
-```
+To build and push to the Container Registry, you can use Docker commands.
-For more information on running Docker containers, visit the
-[Docker documentation](https://docs.docker.com/engine/userguide/intro/).
+### Authenticate with the Container Registry
-## Authenticating to the GitLab Container Registry
+Before you can build and push images, you must authenticate with the Container Registry.
-If you visit the **Packages & Registries > Container Registry** link under your project's
-menu, you can see the explicit instructions to login to the Container Registry
-using your GitLab credentials.
+To authenticate, you can use:
-For example if the Registry's URL is `registry.example.com`, then you should be
-able to login with:
+- A [personal access token](../../profile/personal_access_tokens.md).
+- A [deploy token](../../project/deploy_tokens/index.md).
-```shell
-docker login registry.example.com
-```
+Both of these require the minimum scope to be:
-NOTE: **Note:**
-If you have [2 Factor Authentication](../../profile/account/two_factor_authentication.md)
-enabled in your account, you need to pass a
-[personal access token](../../profile/personal_access_tokens.md) instead
-of your password in order to login to GitLab's Container Registry.
+- For read (pull) access, `read_registry`.
+- For write (push) access, `write_registry`.
-Credentials must be provided for authorization to any non-public registry. Only project members can access private,
-GitLab-hosted registries.
+To authenticate, run the `docker` command. For example:
-There are two ways to authenticate:
+ ```shell
+ docker login registry.example.com -u <username> -p <token>
+ ```
-- By using a [personal access token](../../profile/personal_access_tokens.md).
-- By using a [deploy token](../../project/deploy_tokens/index.md).
+### Build and push images by using Docker commands
-The minimum scope needed for both of them is `read_registry`.
+To build and push to the Container Registry:
-Example of using a token:
+1. Authenticate with the Container Registry.
-```shell
-docker login registry.example.com -u <username> -p <token>
-```
+1. Run the command to build or push. For example, to build:
-## Build and push images from your local machine
+ ```shell
+ docker build -t registry.example.com/group/project/image .
+ ```
-Building and publishing images should be a straightforward process. Just make
-sure that you are using the Registry URL with the namespace and project name
-that is hosted on GitLab:
+ Or to push:
-```shell
-docker build -t registry.example.com/group/project/image .
-docker push registry.example.com/group/project/image
-```
+ ```shell
+ docker push registry.example.com/group/project/image
+ ```
-Your image is named after the following scheme:
+You can also view these commands by going to your project's **Packages & Registries > Container Registry**.
-```plaintext
-<registry URL>/<namespace>/<project>/<image>
-```
+## Build and push by using GitLab CI/CD
-GitLab supports up to three levels of image repository names.
-The following examples of image tags are valid:
+Use [GitLab CI/CD](../../../ci/yaml/README.md) to build and push images to the
+Container Registry. Use it to test, build, and deploy your project from the Docker
+image you created.
-```plaintext
-registry.example.com/group/project:some-tag
-registry.example.com/group/project/image:latest
-registry.example.com/group/project/my/image:rc1
-```
+### Authenticate by using GitLab CI/CD
-## Build and push images using GitLab CI/CD
-
-While you can build and push your images from your local machine, take
-full advantage of the Container Registry by combining it with GitLab CI/CD.
-You can then create workflows and automate any processes that involve testing,
-building, and eventually deploying your project from the Docker image you
-created.
-
-Before diving into the details, some things you should be aware of:
-
-- You must [authenticate to the container registry](#authenticating-to-the-container-registry-with-gitlab-cicd)
- before running any commands. You can do this in the `before_script` if multiple
- jobs depend on it.
-- Using `docker build --pull` fetches any changes to base
- images before building in case your cache is stale. It takes slightly
- longer, but it means you don’t get stuck without security patches for base images.
-- Doing an explicit `docker pull` before each `docker run` fetches
- the latest image that was just built. This is especially important if you are
- using multiple runners that cache images locally. Using the Git SHA in your
- image tag makes this less necessary since each job is unique and you
- shouldn't ever have a stale image. However, it's still possible to have a
- stale image if you re-build a given commit after a dependency has changed.
-- You don't want to build directly to `latest` tag in case there are multiple jobs
- happening simultaneously.
+Before you can build and push images by using GitLab CI/CD, you must authenticate with the Container Registry.
-### Authenticating to the Container Registry with GitLab CI/CD
+To use CI/CD to authenticate, you can use:
-There are three ways to authenticate to the Container Registry via
-[GitLab CI/CD](../../../ci/yaml/README.md):
+- The `CI_REGISTRY_USER` variable.
-- **Using the special `CI_REGISTRY_USER` variable**: The user specified by this variable is created for you in order to
- push to the Registry connected to your project. Its password is automatically
- set with the `CI_REGISTRY_PASSWORD` variable. This allows you to automate building and deploying
- your Docker images and has read/write access to the Registry. This is ephemeral,
- so it's only valid for one job. You can use the following example as-is:
+ This variable has read-write access to the Container Registry and is valid for
+ one job only. Its password is also automatically created and assigned to `CI_REGISTRY_PASSWORD`.
```shell
docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
```
-- **Using the GitLab Deploy Token**: You can create and use a
- [special deploy token](../../project/deploy_tokens/index.md#gitlab-deploy-token)
- with your projects.
- Once created, you can use the special environment variables, and GitLab CI/CD
- fills them in for you. You can use the following example as-is:
+- A [CI job token](../../../ci/triggers/README.md#ci-job-token).
```shell
- docker login -u $CI_DEPLOY_USER -p $CI_DEPLOY_PASSWORD $CI_REGISTRY
+ docker login -u $CI_JOB_USER -p $CI_JOB_TOKEN $CI_REGISTRY
```
-- **Using a personal access token**: You can create and use a
- [personal access token](../../profile/personal_access_tokens.md)
- in case your project is private:
+- A [deploy token](../../project/deploy_tokens/index.md#gitlab-deploy-token) with the minimum scope of:
+ - For read (pull) access, `read_registry`.
+ - For write (push) access, `write_registry`.
- - For read (pull) access, the scope should be `read_registry`.
- - For write (push) access, the scope should be `write_registry`.
+ ```shell
+ docker login -u $CI_DEPLOY_USER -p $CI_DEPLOY_PASSWORD $CI_REGISTRY
+ ```
- Replace the `<username>` and `<access_token>` in the following example:
+- A [personal access token](../../profile/personal_access_tokens.md) with the minimum scope of:
+ - For read (pull) access, `read_registry`.
+ - For write (push) access, `write_registry`.
```shell
docker login -u <username> -p <access_token> $CI_REGISTRY
```
+### Configure your `.gitlab-ci.yml` file
+
+You can configure your `.gitlab-ci.yml` file to build and push images to the Container Registry.
+
+- If multiple jobs require authentication, put the authentication command in the `before_script`.
+- Before building, use `docker build --pull` to fetch changes to base images. It takes slightly
+ longer, but it ensures your image is up-to-date.
+- Before each `docker run`, do an explicit `docker pull` to fetch
+ the image that was just built. This is especially important if you are
+ using multiple runners that cache images locally.
+
+ If you use the Git SHA in your image tag, each job is unique and you
+ should never have a stale image. However, it's still possible to have a
+ stale image if you re-build a given commit after a dependency has changed.
+- Don't build directly to the `latest` tag because multiple jobs may be
+ happening simultaneously.
+
### Container Registry examples with GitLab CI/CD
If you're using Docker-in-Docker on your runners, this is how your `.gitlab-ci.yml`
@@ -359,15 +310,15 @@ in addition to the steps in the
Below is an example of what your `.gitlab-ci.yml` should look like:
```yaml
- build:
- image: $CI_REGISTRY/group/project/docker:19.03.12
- services:
- - name: $CI_REGISTRY/group/project/docker:19.03.12-dind
- alias: docker
- stage: build
- script:
- - docker build -t my-docker-image .
- - docker run my-docker-image /script/to/run/tests
+build:
+ image: $CI_REGISTRY/group/project/docker:19.03.12
+ services:
+ - name: $CI_REGISTRY/group/project/docker:19.03.12-dind
+ alias: docker
+ stage: build
+ script:
+ - docker build -t my-docker-image .
+ - docker run my-docker-image /script/to/run/tests
```
If you forget to set the service alias, the `docker:19.03.12` image is unable to find the
@@ -394,7 +345,7 @@ the deleted images.
To delete images from within GitLab:
-1. Navigate to your project's or group's **{package}** **Packages & Registries > Container Registry**.
+1. Navigate to your project's or group's **Packages & Registries > Container Registry**.
1. From the **Container Registry** page, you can select what you want to delete,
by either:
@@ -406,8 +357,6 @@ To delete images from within GitLab:
1. In the dialog box, click **Remove tag**.
- ![Container Registry tags](img/container_registry_repository_details_v13.0.png)
-
### Delete images using the API
If you want to automate the process of deleting images, GitLab provides an API. For more
@@ -512,9 +461,28 @@ Cleanup policies can be run on all projects, with these exceptions:
for all projects (even those created before 12.8) in
[GitLab application settings](../../../api/settings.md#change-application-settings)
by setting `container_expiration_policies_enable_historic_entries` to true.
+ Alternatively, you can execute the following command in the [Rails console](../../../administration/operations/rails_console.md#starting-a-rails-console-session):
+
+ ```ruby
+ ApplicationSetting.last.update(container_expiration_policies_enable_historic_entries: true)
+ ```
There are performance risks with enabling it for all projects, especially if you
are using an [external registry](./index.md#use-with-external-container-registries).
+- For self-managed GitLab instances, you can enable or disable the cleanup policy for a specific
+ project.
+
+ To enable it:
+
+ ```ruby
+ Feature.enable(:container_expiration_policies_historic_entry, Project.find(<project id>))
+ ```
+
+ To disable it:
+
+ ```ruby
+ Feature.disable(:container_expiration_policies_historic_entry, Project.find(<project id>))
+ ```
### How the cleanup policy works
@@ -636,7 +604,7 @@ you can use the Container Registry to store Helm Charts. However, due to the way
and stored by Docker, it is not possible for GitLab to parse this data and meet performance standards.
[This epic](https://gitlab.com/groups/gitlab-org/-/epics/2313) updates the architecture of the Container Registry to support Helm Charts.
-You can read more about the above challenges [here](https://gitlab.com/gitlab-org/gitlab/-/issues/38047#note_298842890).
+[Read more about the above challenges](https://gitlab.com/gitlab-org/gitlab/-/issues/38047#note_298842890).
## Limitations
@@ -647,6 +615,19 @@ Container Registry, you must delete all existing images.
- Prior to GitLab 12.10, any tags that use the same image ID as the `latest` tag
are not deleted by the cleanup policy.
+## Disable the Container Registry for a project
+
+The Container Registry is enabled by default.
+
+You can, however, remove the Container Registry for a project:
+
+1. Go to your project's **Settings > General** page.
+1. Expand the **Visibility, project features, permissions** section
+ and disable **Container Registry**.
+1. Click **Save changes**.
+
+The **Packages & Registries > Container Registry** entry is removed from the project's sidebar.
+
## Troubleshooting the GitLab Container Registry
### Docker connection error
@@ -661,6 +642,21 @@ To get around this, you can [change the group path](../../group/index.md#changin
[change the project path](../../project/settings/index.md#renaming-a-repository) or change the branch
name.
+You may also get a `404 Not Found` or `Unknown Manifest` message if you are using
+a Docker Engine version earlier than 17.12. Later versions of Docker Engine use
+[the v2 API](https://docs.docker.com/registry/spec/manifest-v2-2/).
+
+The images in your GitLab Container Registry must also use the Docker v2 API.
+For information on how to update your images, see the [Docker help](https://docs.docker.com/registry/spec/deprecated-schema-v1).
+
+### `Blob unknown to registry` error when pushing a manifest list
+
+When [pushing a Docker manifest list](https://docs.docker.com/engine/reference/commandline/manifest/#create-and-push-a-manifest-list) to the GitLab Container Registry, you may receive the error `manifest blob unknown: blob unknown to registry`. This issue occurs when the individual child manifests referenced in the manifest list were not pushed to the same repository.
+
+For example, you may have two individual images, one for `amd64` and another for `arm64v8`, and you want to build a multi-arch image with them. The `amd64` and `arm64v8` images must be pushed to the same repository where you want to push the multi-arch image.
+
+As a workaround, you should include the architecture in the tag name of individual images. For example, use `mygroup/myapp:1.0.0-amd64` instead of using sub repositories, like `mygroup/myapp/amd64:1.0.0`. You can then tag the manifest list with `mygroup/myapp:1.0.0`.
+
### Troubleshoot as a GitLab server admin
Troubleshooting the GitLab Container Registry, most of the times, requires
diff --git a/doc/user/packages/dependency_proxy/img/group_dependency_proxy.png b/doc/user/packages/dependency_proxy/img/group_dependency_proxy.png
deleted file mode 100644
index e550d296d5a..00000000000
--- a/doc/user/packages/dependency_proxy/img/group_dependency_proxy.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/packages/dependency_proxy/index.md b/doc/user/packages/dependency_proxy/index.md
index e3ee8909165..3fa21ef486b 100644
--- a/doc/user/packages/dependency_proxy/index.md
+++ b/doc/user/packages/dependency_proxy/index.md
@@ -8,80 +8,80 @@ info: To determine the technical writer assigned to the Stage/Group associated w
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/7934) in [GitLab Premium](https://about.gitlab.com/pricing/) 11.11.
-NOTE: **Note:**
-This is the user guide. In order to use the dependency proxy, an administrator
-must first [configure it](../../../administration/packages/dependency_proxy.md).
+The GitLab Dependency Proxy is a local proxy you can use for your frequently-accessed
+upstream images.
-For many organizations, it is desirable to have a local proxy for frequently used
-upstream images/packages. In the case of CI/CD, the proxy is responsible for
-receiving a request and returning the upstream image from a registry, acting
-as a pull-through cache.
+In the case of CI/CD, the Dependency Proxy receives a request and returns the
+upstream image from a registry, acting as a pull-through cache.
-The dependency proxy is available in the group level. To access it, navigate to
-a group's **Packages & Registries > Dependency Proxy**.
+## Prerequisites
-![Dependency Proxy group page](img/group_dependency_proxy.png)
+To use the Dependency Proxy:
-## Supported dependency proxies
+- Your group must be public. Authentication for private groups is [not supported yet](https://gitlab.com/gitlab-org/gitlab/-/issues/11582).
-NOTE: **Note:**
-For a list of the upcoming additions to the proxies, visit the
-[direction page](https://about.gitlab.com/direction/package/dependency_proxy/#top-vision-items).
+### Supported images and packages
-The following dependency proxies are supported.
+The following images and packages are supported.
-| Dependency proxy | GitLab version |
+| Image/Package | GitLab version |
| ---------------- | -------------- |
| Docker | 11.11+ |
-## Using the Docker dependency proxy
+For a list of planned additions, view the
+[direction page](https://about.gitlab.com/direction/package/dependency_proxy/#top-vision-items).
+
+## View the Dependency Proxy
+
+To view the Dependency Proxy:
+
+- Go to your group's **Packages & Registries > Dependency Proxy**.
+
+The Dependency Proxy is not available for projects.
+
+## Use the Dependency Proxy for Docker images
+
+You can use GitLab as a source for your Docker images.
-With the Docker dependency proxy, you can use GitLab as a source for a Docker image.
-To get a Docker image into the dependency proxy:
+Prerequisites:
-1. Find the proxy URL on your group's page under **Packages & Registries > Dependency Proxy**,
- for example `gitlab.com/groupname/dependency_proxy/containers`.
-1. Trigger GitLab to pull the Docker image you want (e.g., `alpine:latest` or
- `linuxserver/nextcloud:latest`) and store it in the proxy storage by using
- one of the following ways:
+- Your images must be stored on [Docker Hub](https://hub.docker.com/).
+- Docker Hub must be available. Follow [this issue](https://gitlab.com/gitlab-org/gitlab/-/issues/241639)
+ for progress on accessing images when Docker Hub is down.
- - Manually pulling the Docker image:
+To store a Docker image in Dependency Proxy storage:
+
+1. Go to your group's **Packages & Registries > Dependency Proxy**.
+1. Copy the **Dependency Proxy URL**.
+1. Use one of these commands. In these examples, the image is `alpine:latest`.
+
+ - Add the URL to your [`.gitlab-ci.yml`](../../../ci/yaml/README.md#image) file:
```shell
- docker pull gitlab.com/groupname/dependency_proxy/containers/alpine:latest
+ image: gitlab.example.com/groupname/dependency_proxy/containers/alpine:latest
```
- - From a `Dockerfile`:
+ - Manually pull the Docker image:
```shell
- FROM gitlab.com/groupname/dependency_proxy/containers/alpine:latest
+ docker pull gitlab.example.com/groupname/dependency_proxy/containers/alpine:latest
```
- - In [`.gitlab-ci.yml`](../../../ci/yaml/README.md#image):
+ - Add the URL to a `Dockerfile`:
```shell
- image: gitlab.com/groupname/dependency_proxy/containers/alpine:latest
+ FROM gitlab.example.com/groupname/dependency_proxy/containers/alpine:latest
```
GitLab pulls the Docker image from Docker Hub and caches the blobs
on the GitLab server. The next time you pull the same image, GitLab gets the latest
-information about the image from Docker Hub but serves the existing blobs
+information about the image from Docker Hub, but serves the existing blobs
from the GitLab server.
-The blobs are kept forever, and there is no hard limit on how much data can be
-stored.
-
-## Clearing the cache
+## Clear the Dependency Proxy cache
-It is possible to use the GitLab API to purge the dependency proxy cache for a
-given group to gain back disk space that may be taken up by image blobs that
-are no longer needed. See the [dependency proxy API documentation](../../../api/dependency_proxy.md)
-for more details.
-
-## Limitations
-
-The following limitations apply:
+Blobs are kept forever on the GitLab server, and there is no hard limit on how much data can be
+stored.
-- Only [public groups are supported](https://gitlab.com/gitlab-org/gitlab/-/issues/11582) (authentication is not supported yet).
-- Only Docker Hub is supported.
-- This feature requires Docker Hub being available.
+To reclaim disk space used by image blobs that are no longer needed, use
+the [Dependency Proxy API](../../../api/dependency_proxy.md).
diff --git a/doc/user/packages/generic_packages/index.md b/doc/user/packages/generic_packages/index.md
new file mode 100644
index 00000000000..0c961b5c86f
--- /dev/null
+++ b/doc/user/packages/generic_packages/index.md
@@ -0,0 +1,139 @@
+---
+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/engineering/ux/technical-writing/#designated-technical-writers
+---
+
+# GitLab Generic Packages Repository **(CORE)**
+
+> - [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/4209) in GitLab 13.5.
+> - It's [deployed behind a feature flag](../../../user/feature_flags.md), enabled by default.
+> - It's enabled on GitLab.com.
+> - It's able to be enabled or disabled per-project.
+> - It's recommended for production use.
+> - For GitLab self-managed instances, GitLab administrators can opt to [disable it](#enable-or-disable-generic-packages-in-the-package-registry).
+
+CAUTION: **Warning:**
+This feature might not be available to you. Check the **version history** note above for details.
+
+Publish generic files, like release binaries, in your project’s Package Registry. Then, install the packages whenever you need to use them as a dependency.
+
+## Authenticate to the Package Registry
+
+To authenticate to the Package Registry, you need either a [personal access token](../../../api/README.md#personalproject-access-tokens)
+or [CI job token](../../../api/README.md#gitlab-ci-job-token).
+
+## Publish a package file
+
+When you publish a package file, if the package does not exist, it is created.
+
+Prerequisites:
+
+- You need to [authenticate with the API](../../../api/README.md#authentication).
+
+```plaintext
+PUT /projects/:id/packages/generic/:package_name/:package_version/:file_name
+```
+
+| Attribute | Type | Required | Description |
+| -------------------| --------------- | ---------| -------------------------------------------------------------------------------------------------------------------------------- |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](../../../api/README.md#namespaced-path-encoding). |
+| `package_name` | string | yes | The package name. It can contain only lowercase letters (`a-z`), uppercase letter (`A-Z`), numbers (`0-9`), dots (`.`), hyphens (`-`), or underscores (`_`).
+| `package_version` | string | yes | The package version. It can contain only numbers (`0-9`), and dots (`.`). Must be in the format of `X.Y.Z`, i.e. should match `/\A\d+\.\d+\.\d+\z/` regular expresion.
+| `file_name` | string | yes | The file name. It can contain only lowercase letters (`a-z`), uppercase letter (`A-Z`), numbers (`0-9`), dots (`.`), hyphens (`-`), or underscores (`_`).
+
+Provide the file context in the request body.
+
+Example request:
+
+```shell
+curl --header "PRIVATE-TOKEN: <your_access_token>" \
+ --upload-file path/to/file.txt \
+ https://gitlab.example.com/api/v4/projects/24/generic/my_package/0.0.1/file.txt
+```
+
+Example response:
+
+```json
+{
+ "message":"201 Created"
+}
+```
+
+## Download package file
+
+Install a package file.
+
+Prerequisites:
+
+- You need to [authenticate with the API](../../../api/README.md#authentication).
+
+```plaintext
+GET /projects/:id/packages/generic/:package_name/:package_version/:file_name
+```
+
+| Attribute | Type | Required | Description |
+| -------------------| --------------- | ---------| ------------------------------------------------------------------------------------|
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](../../../api/README.md#namespaced-path-encoding). |
+| `package_name` | string | yes | The package name. |
+| `package_version` | string | yes | The package version. |
+| `file_name` | string | yes | The file name. |
+
+The file context is served in the response body. The response content type will be `application/octet-stream`.
+
+Example request that uses a personal access token:
+
+```shell
+curl --header "PRIVATE-TOKEN: <your_access_token>" \
+ https://gitlab.example.com/api/v4/projects/24/generic/my_package/0.0.1/file.txt
+```
+
+## Publish a generic package by using CI/CD
+
+To work with generic packages in [GitLab CI/CD](./../../../ci/README.md), you can use
+`CI_JOB_TOKEN` in place of the personal access token in your commands.
+
+For example:
+
+```yaml
+image: curlimages/curl:latest
+
+stages:
+ - upload
+ - download
+
+upload:
+ stage: upload
+ script:
+ - 'curl --header "JOB-TOKEN: $CI_JOB_TOKEN" --upload-file path/to/file.txt ${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/my_package/0.0.1/file.txt'
+
+download:
+ stage: download
+ script:
+ - 'wget --header="JOB-TOKEN: $CI_JOB_TOKEN" ${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/my_package/0.0.1/file.txt'
+```
+
+### Enable or disable generic packages in the Package Registry
+
+Support for generic packages is under development but ready for production use.
+It is deployed behind a feature flag that is **enabled by default**.
+[GitLab administrators with access to the GitLab Rails console](../../../administration/feature_flags.md)
+can opt to disable it.
+
+To enable it:
+
+```ruby
+# For the instance
+Feature.enable(:generic_packages)
+# For a single project
+Feature.enable(:generic_packages, Project.find(<project id>))
+```
+
+To disable it:
+
+```ruby
+# For the instance
+Feature.disable(:generic_packages)
+# For a single project
+Feature.disable(:generic_packages, Project.find(<project id>))
+```
diff --git a/doc/user/packages/go_proxy/index.md b/doc/user/packages/go_proxy/index.md
index edf1528a751..bd3b5b49ebd 100644
--- a/doc/user/packages/go_proxy/index.md
+++ b/doc/user/packages/go_proxy/index.md
@@ -50,7 +50,7 @@ Feature.disable(:go_proxy, Project.find(2))
### Enable the Package Registry
The Package Registry is enabled for new projects by default. If you cannot find
-the **{package}** **Packages > List** entry under your project's sidebar, verify
+the **Packages > List** entry under your project's sidebar, verify
the following:
1. Your GitLab administrator has
diff --git a/doc/user/packages/index.md b/doc/user/packages/index.md
index 92d31c31986..53ba3d01b3e 100644
--- a/doc/user/packages/index.md
+++ b/doc/user/packages/index.md
@@ -23,6 +23,7 @@ The Package Registry supports the following formats:
<tr><td><a href="https://docs.gitlab.com/ee/user/packages/npm_registry/index.html">NPM</a></td><td>11.7+</td></tr>
<tr><td><a href="https://docs.gitlab.com/ee/user/packages/nuget_repository/index.html">NuGet</a></td><td>12.8+</td></tr>
<tr><td><a href="https://docs.gitlab.com/ee/user/packages/pypi_repository/index.html">PyPI</a></td><td>12.10+</td></tr>
+<tr><td><a href="https://docs.gitlab.com/ee/user/packages/generic_packages/index.html">Generic packages</a></td><td>13.5+</td></tr>
</table>
</div>
</div>
diff --git a/doc/user/packages/maven_repository/img/maven_package_view_v12_6.png b/doc/user/packages/maven_repository/img/maven_package_view_v12_6.png
deleted file mode 100644
index 92cefc26660..00000000000
--- a/doc/user/packages/maven_repository/img/maven_package_view_v12_6.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/packages/maven_repository/index.md b/doc/user/packages/maven_repository/index.md
index 7329725a643..d4a8ff0cdb4 100644
--- a/doc/user/packages/maven_repository/index.md
+++ b/doc/user/packages/maven_repository/index.md
@@ -4,44 +4,24 @@ group: Package
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/#designated-technical-writers
---
-# GitLab Maven Repository
+# Maven packages in the Package Repository
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/5811) in [GitLab Premium](https://about.gitlab.com/pricing/) 11.3.
> - [Moved](https://gitlab.com/gitlab-org/gitlab/-/issues/221259) to GitLab Core in 13.3.
-With the GitLab [Maven](https://maven.apache.org) Repository, every
-project can have its own space to store its Maven artifacts.
+Publish [Maven](https://maven.apache.org) artifacts in your project’s Package Registry.
+Then, install the packages whenever you need to use them as a dependency.
-![GitLab Maven Repository](img/maven_package_view_v12_6.png)
+## Build a Maven package
-## Enabling the Maven Repository
+This section explains how to install Maven and build a package.
-NOTE: **Note:**
-This option is available only if your GitLab administrator has
-[enabled support for the Maven repository](../../../administration/packages/index.md).
-
-After the Packages feature is enabled, the Maven Repository is available for
-all new projects by default. To enable it for existing projects, or if you want
-to disable it:
-
-1. Navigate to your project's **Settings > General > Visibility, project features, permissions**.
-1. Find the Packages feature and enable or disable it.
-1. Click on **Save changes** for the changes to take effect.
-
-You should then be able to see the **Packages & Registries** section on the left sidebar.
-Next, you must configure your project to authorize with the GitLab Maven
-repository.
+If you already use Maven and know how to build your own packages, go to the
+[next section](#add-the-package-registry-as-a-maven-remote).
-## Getting Started with Maven
+Maven repositories work well with Gradle, too. To set up a Gradle project, see [get started with Gradle](#use-gradle-to-create-a-java-project).
-This section covers installing Maven and building a package. This is a
-quickstart to help if you're new to building Maven packages. If you're already
-using Maven and understand how to build your own packages, move onto the
-[next section](#adding-the-gitlab-package-registry-as-a-maven-remote).
-
-Maven repositories work well with Gradle, too. Move onto [getting started with Gradle](#getting-started-with-gradle) if you want to setup a Gradle project.
-
-### Installing Maven
+### Install Maven
The required minimum versions are:
@@ -66,7 +46,7 @@ Default locale: en_GB, platform encoding: UTF-8
OS name: "mac os x", version: "10.15.2", arch: "x86_64", family: "mac"
```
-### Creating a project
+### Create a project
Understanding how to create a full Java project is outside the scope of this
guide but you can follow the steps below to create a new project that can be
@@ -105,14 +85,14 @@ your project has been set up successfully:
You should see a new directory where you ran this command matching your
`DartifactId` parameter (in this case it should be `my-project`).
-## Getting started with Gradle
+## Use Gradle to create a Java project
+
+This section explains how to install Gradle and initialize a Java project.
-This section covers installing Gradle and initializing a Java project. This is a
-quickstart to help if you're new to Gradle. If you're already
-using Gradle and understand how to build your own packages, move onto the
-[next section](#adding-the-gitlab-package-registry-as-a-maven-remote).
+If you already use Gradle and know how to build your own packages, go to the
+[next section](#add-the-package-registry-as-a-maven-remote).
-### Installing Gradle
+### Install Gradle
Installation is needed only if you want to create a new Gradle project. Follow
instructions at [gradle.org](https://gradle.org/install/) to download and install
@@ -145,7 +125,7 @@ JVM: 11.0.5 (Oracle Corporation 11.0.5+10)
OS: Windows 10 10.0 amd64
```
-### Creating a project in Gradle
+### Create a Java project
Understanding how to create a full Java project in Gradle is outside the scope of this
guide, but you can follow the steps below to create a new project that can be
@@ -209,23 +189,23 @@ Project name (default: test):
Enter a project name or hit enter to use the directory name as project name.
-## Adding the GitLab Package Registry as a Maven remote
+## Add the Package Registry as a Maven remote
The next step is to add the GitLab Package Registry as a Maven remote. If a
project is private or you want to upload Maven artifacts to GitLab,
credentials must be provided for authorization too. Support is available
-for [personal access tokens](#authenticating-with-a-personal-access-token),
-[CI job tokens](#authenticating-with-a-ci-job-token), and
+for [personal access tokens](#authenticate-with-a-personal-access-token),
+[CI job tokens](#authenticate-with-a-ci-job-token), and
[deploy tokens](../../project/deploy_tokens/index.md) only. Regular username/password
credentials do not work.
-### Authenticating with a personal access token
+### Authenticate with a personal access token
To authenticate with a [personal access token](../../profile/personal_access_tokens.md),
set the scope to `api` when creating one, and add it to your Maven or Gradle configuration
files.
-#### Authenticating with a personal access token in Maven
+#### Authenticate with a personal access token in Maven
Add a corresponding section to your
[`settings.xml`](https://maven.apache.org/settings.html) file:
@@ -248,7 +228,7 @@ Add a corresponding section to your
</settings>
```
-#### Authenticating with a personal access token in Gradle
+#### Authenticate with a personal access token in Gradle
Create a file `~/.gradle/gradle.properties` with the following content:
@@ -278,12 +258,12 @@ repositories {
You should now be able to upload Maven artifacts to your project.
-### Authenticating with a CI job token
+### Authenticate with a CI job token
If you're using GitLab CI/CD, a CI job token can be used instead
of a personal access token.
-#### Authenticating with a CI job token in Maven
+#### Authenticate with a CI job token in Maven
To authenticate with a CI job token, add a corresponding section to your
[`settings.xml`](https://maven.apache.org/settings.html) file:
@@ -309,7 +289,7 @@ To authenticate with a CI job token, add a corresponding section to your
You can read more on
[how to create Maven packages using GitLab CI/CD](#creating-maven-packages-with-gitlab-cicd).
-#### Authenticating with a CI job token in Gradle
+#### Authenticate with a CI job token in Gradle
To authenticate with a CI job token, add a repositories section to your
[`build.gradle`](https://docs.gradle.org/current/userguide/tutorial_using_tasks.html)
@@ -331,7 +311,7 @@ repositories {
}
```
-### Authenticating with a deploy token
+### Authenticate with a deploy token
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/213566) in [GitLab Premium](https://about.gitlab.com/pricing/) 13.0.
@@ -339,7 +319,7 @@ To authenticate with a [deploy token](./../../project/deploy_tokens/index.md),
set the scope to `api` when creating one, and add it to your Maven or Gradle configuration
files.
-#### Authenticating with a deploy token in Maven
+#### Authenticate with a deploy token in Maven
Add a corresponding section to your
[`settings.xml`](https://maven.apache.org/settings.html) file:
@@ -362,7 +342,7 @@ Add a corresponding section to your
</settings>
```
-#### Authenticating with a deploy token in Gradle
+#### Authenticate with a deploy token in Gradle
To authenticate with a deploy token, add a repositories section to your
[`build.gradle`](https://docs.gradle.org/current/userguide/tutorial_using_tasks.html)
@@ -441,7 +421,7 @@ repositories {
```
The `id` must be the same with what you
-[defined in `settings.xml`](#adding-the-gitlab-package-registry-as-a-maven-remote).
+[defined in `settings.xml`](#add-the-package-registry-as-a-maven-remote).
Replace `PROJECT_ID` with your project ID which can be found on the home page
of your project.
@@ -452,7 +432,7 @@ domain name.
NOTE: **Note:**
For retrieving artifacts, you can use either the
[URL encoded](../../../api/README.md#namespaced-path-encoding) path of the project
-(e.g., `group%2Fproject`) or the project's ID (e.g., `42`). However, only the
+(such as `group%2Fproject`) or the project's ID (such as `42`). However, only the
project's ID can be used for uploading.
### Group level Maven endpoint
@@ -505,7 +485,7 @@ repositories {
```
The `id` must be the same with what you
-[defined in `settings.xml`](#adding-the-gitlab-package-registry-as-a-maven-remote).
+[defined in `settings.xml`](#add-the-package-registry-as-a-maven-remote).
Replace `my-group` with your group name and `PROJECT_ID` with your project ID
which can be found on the home page of your project.
@@ -516,7 +496,7 @@ domain name.
NOTE: **Note:**
For retrieving artifacts, you can use either the
[URL encoded](../../../api/README.md#namespaced-path-encoding) path of the group
-(e.g., `group%2Fsubgroup`) or the group's ID (e.g., `12`).
+(such as `group%2Fsubgroup`) or the group's ID (such as `12`).
### Instance level Maven endpoint
@@ -571,7 +551,7 @@ repositories {
```
The `id` must be the same with what you
-[defined in `settings.xml`](#adding-the-gitlab-package-registry-as-a-maven-remote).
+[defined in `settings.xml`](#add-the-package-registry-as-a-maven-remote).
Replace `PROJECT_ID` with your project ID which can be found on the home page
of your project.
@@ -582,12 +562,12 @@ domain name.
NOTE: **Note:**
For retrieving artifacts, you can use either the
[URL encoded](../../../api/README.md#namespaced-path-encoding) path of the project
-(e.g., `group%2Fproject`) or the project's ID (e.g., `42`). However, only the
+(such as `group%2Fproject`) or the project's ID (such as `42`). However, only the
project's ID can be used for uploading.
## Uploading packages
-Once you have set up the [remote and authentication](#adding-the-gitlab-package-registry-as-a-maven-remote)
+Once you have set up the [remote and authentication](#add-the-package-registry-as-a-maven-remote)
and [configured your project](#configuring-your-project-to-use-the-gitlab-maven-repository-url),
test to upload a Maven artifact from a project of yours.
@@ -661,7 +641,7 @@ artifacts or even delete them.
## Installing a package
Installing a package from the GitLab Package Registry requires that you set up
-the [remote and authentication](#adding-the-gitlab-package-registry-as-a-maven-remote)
+the [remote and authentication](#add-the-package-registry-as-a-maven-remote)
as above. Once this is completed, there are two ways to install a package.
### Install using Maven with `mvn install`
@@ -708,7 +688,7 @@ Package details page, allowing for quick and easy installation.
### Install using Gradle
-Add a [dependency](https://docs.gradle.org/current/userguide/declaring_dependencies.html) to build.gradle in the dependencies section:
+Add a [dependency](https://docs.gradle.org/current/userguide/declaring_dependencies.html) to `build.gradle` in the dependencies section:
```groovy
dependencies {
@@ -802,7 +782,7 @@ Docker container), and Maven uses the configured CI
The example below shows how to create a new package each time the `master` branch
is updated:
-1. Make sure you use the Job-Token authentication as described in ["Authenticating with a CI job token in Gradle"](#authenticating-with-a-ci-job-token-in-gradle).
+1. Make sure you use the Job-Token authentication as described in ["Authenticating with a CI job token in Gradle"](#authenticate-with-a-ci-job-token-in-gradle).
1. Add a `deploy` job to your `.gitlab-ci.yml` file:
diff --git a/doc/user/packages/npm_registry/index.md b/doc/user/packages/npm_registry/index.md
index 2a1c12c2afd..f15b31d8b67 100644
--- a/doc/user/packages/npm_registry/index.md
+++ b/doc/user/packages/npm_registry/index.md
@@ -286,6 +286,22 @@ By default, when an NPM package is not found in the GitLab NPM Registry, the req
Administrators can disable this behavior in the [Continuous Integration settings](../../admin_area/settings/continuous_integration.md).
+### Installing packages from other organizations
+
+You can route package requests to organizations and users outside of GitLab.
+
+To do this, add lines to your `.npmrc` file, replacing `my-org` with the namespace or group that owns your project's repository. The name is case-sensitive and must match the name of your group or namespace exactly.
+
+```shell
+@foo:registry=https://gitlab.example.com/api/v4/packages/npm/
+//gitlab.com/api/v4/packages/npm/:_authToken= "<your_token>"
+//gitlab.com/api/v4/projects/<your_project_id>/packages/npm/:_authToken= "<your_token>"
+
+@my-other-org:registry=https://gitlab.example.com/api/v4/packages/npm/
+//gitlab.com/api/v4/packages/npm/:_authToken= "<your_token>"
+//gitlab.com/api/v4/projects/<your_project_id>/packages/npm/:_authToken= "<your_token>"
+```
+
## Removing a package
In the packages view of your project page, you can delete packages by clicking
@@ -340,6 +356,13 @@ with your personal access token or deploy token):
//gitlab.com/api/v4/projects/:_authToken=<your_token>
```
+You can also use `yarn config` instead of `npm config` when setting your auth-token dynamically:
+
+```shell
+yarn config set '//gitlab.com/api/v4/projects/<your_project_id>/packages/npm/:_authToken' "<your_token>"
+yarn config set '//gitlab.com/api/v4/packages/npm/:_authToken' "<your_token>"
+```
+
### `npm publish` targets default NPM registry (`registry.npmjs.org`)
Ensure that your package scope is set consistently in your `package.json` and `.npmrc` files.
@@ -418,5 +441,8 @@ npm dist-tag rm @scope/package@version my-tag # Delete a tag from the package
npm install @scope/package@my-tag # Install a specific tag
```
+NOTE: **Note:**
+You cannot use your `CI_JOB_TOKEN` or deploy token with the `npm dist-tag` commands. View [this issue](https://gitlab.com/gitlab-org/gitlab/-/issues/258835) for details.
+
CAUTION: **Warning:**
Due to a bug in NPM 6.9.0, deleting dist tags fails. Make sure your NPM version is greater than 6.9.1.
diff --git a/doc/user/packages/nuget_repository/index.md b/doc/user/packages/nuget_repository/index.md
index 9fb50ce71fb..22e1a95649d 100644
--- a/doc/user/packages/nuget_repository/index.md
+++ b/doc/user/packages/nuget_repository/index.md
@@ -19,7 +19,7 @@ The GitLab NuGet Repository works with:
## Setting up your development environment
-[NuGet CLI 5.2 or later](https://www.nuget.org/downloads) is required. Earlier versions have not been tested
+[NuGet CLI 5.1 or later](https://www.nuget.org/downloads) is required. Earlier versions have not been tested
against the GitLab NuGet Repository and might not work. If you have [Visual Studio](https://visualstudio.microsoft.com/vs/),
NuGet CLI is probably already installed.
@@ -34,7 +34,7 @@ nuget help
You should see something similar to:
```plaintext
-NuGet Version: 5.2.0.6090
+NuGet Version: 5.1.0.6013
usage: NuGet <command> [args] [options]
Type 'NuGet help <command>' for help on a specific command.
@@ -44,7 +44,7 @@ Available commands:
```
NOTE: **Note:**
-GitLab currently only supports NuGet v3. Earlier versions are not supported.
+GitLab currently only supports NuGet's protocol version 3. Earlier versions are not supported.
### macOS support
@@ -154,7 +154,7 @@ To add the GitLab NuGet Repository as a source for .NET, create a file named `nu
When uploading packages, note that:
-- The maximum allowed size is 50 Megabytes.
+- The Package Registry on GitLab.com can store up to 500 MB of content. This limit is [configurable for self-managed GitLab instances](../../../administration/instance_limits.md#package-registry-limits).
- If you upload the same package with the same version multiple times, each consecutive upload
is saved as a separate file. When installing a package, GitLab serves the most recent file.
- When uploading packages to GitLab, they are not displayed in the packages UI of your project
@@ -250,21 +250,21 @@ is updated:
1. Add a `deploy` job to your `.gitlab-ci.yml` file:
```yaml
- image: mcr.microsoft.com/dotnet/core/sdk:3.1
-
- stages:
- - deploy
-
- deploy:
- stage: deploy
- script:
- - dotnet restore -p:Configuration=Release
- - dotnet build -c Release
- - dotnet pack -c Release
- - dotnet nuget add source "$CI_SERVER_URL/api/v4/projects/$CI_PROJECT_ID/packages/nuget/index.json" --name gitlab --username gitlab-ci-token --password $CI_JOB_TOKEN --store-password-in-clear-text
- - dotnet nuget push "bin/Release/*.nupkg" --source gitlab
- only:
- - master
+ image: mcr.microsoft.com/dotnet/core/sdk:3.1
+
+ stages:
+ - deploy
+
+ deploy:
+ stage: deploy
+ script:
+ - dotnet restore -p:Configuration=Release
+ - dotnet build -c Release
+ - dotnet pack -c Release
+ - dotnet nuget add source "$CI_SERVER_URL/api/v4/projects/$CI_PROJECT_ID/packages/nuget/index.json" --name gitlab --username gitlab-ci-token --password $CI_JOB_TOKEN --store-password-in-clear-text
+ - dotnet nuget push "bin/Release/*.nupkg" --source gitlab
+ only:
+ - master
```
1. Commit the changes and push it to your GitLab repository to trigger a new CI build.
diff --git a/doc/user/packages/package_registry/index.md b/doc/user/packages/package_registry/index.md
index 9f954627b05..ae9ca5b2333 100644
--- a/doc/user/packages/package_registry/index.md
+++ b/doc/user/packages/package_registry/index.md
@@ -17,7 +17,7 @@ packages, which can be easily consumed as a dependency in downstream projects.
You can view packages for your project or group.
1. Go to the project or group.
-1. Go to **{package}** **Packages & Registries > Package Registry**.
+1. Go to **Packages & Registries > Package Registry**.
You can search, sort, and filter packages on this page.
@@ -31,7 +31,7 @@ authenticate with GitLab by using the `CI_JOB_TOKEN`.
CI/CD templates, which you can use to get started, are in [this repo](https://gitlab.com/gitlab-org/gitlab/-/tree/master/lib/gitlab/ci/templates).
-Learn more about [using CI/CD to build Maven packages](../maven_repository/index.md#creating-maven-packages-with-gitlab-cicd), [NPM packages](../npm_registry/index.md#publishing-a-package-with-cicd), [Composer packages](../composer_repository/index.md#publishing-the-package-with-cicd), [NuGet Packages](../nuget_repository/index.md#publishing-a-nuget-package-with-cicd), [Conan Packages](../conan_repository/index.md#using-gitlab-ci-with-conan-packages), and [PyPI packages](../pypi_repository/index.md#using-gitlab-ci-with-pypi-packages).
+Learn more about [using CI/CD to build Maven packages](../maven_repository/index.md#creating-maven-packages-with-gitlab-cicd), [NPM packages](../npm_registry/index.md#publishing-a-package-with-cicd), [Composer packages](../composer_repository/index.md#publish-a-composer-package-by-using-cicd), [NuGet Packages](../nuget_repository/index.md#publishing-a-nuget-package-with-cicd), [Conan Packages](../conan_repository/index.md#publish-a-conan-package-by-using-cicd), [PyPI packages](../pypi_repository/index.md#using-gitlab-ci-with-pypi-packages), and [generic packages](../generic_packages/index.md#publish-a-generic-package-by-using-cicd).
If you use CI/CD to build a package, extended activity
information is displayed when you view the package details:
@@ -45,7 +45,7 @@ user who triggered it.
To download a package:
-1. Go to **{package}** **Packages & Registries > Package Registry**.
+1. Go to **Packages & Registries > Package Registry**.
1. Click the name of the package you want to download.
1. In the **Activity** section, click the name of the package you want to download.
@@ -60,7 +60,7 @@ You can delete packages by using [the API](../../../api/packages.md#delete-a-pro
To delete a package in the UI, from your group or project:
-1. Go to **{package}** **Packages & Registries > Package Registry**.
+1. Go to **Packages & Registries > Package Registry**.
1. Find the name of the package you want to delete.
1. Click **Delete**.
@@ -71,7 +71,7 @@ The package is permanently deleted.
The Package Registry is automatically enabled.
If you are using a self-managed instance of GitLab, your administrator can remove
-the menu item, **{package}** **Packages & Registries**, from the GitLab sidebar. For more information,
+the menu item, **Packages & Registries**, from the GitLab sidebar. For more information,
see the [administration documentation](../../../administration/packages/index.md).
You can also remove the Package Registry for your project specifically:
@@ -81,7 +81,7 @@ You can also remove the Package Registry for your project specifically:
**Packages** feature.
1. Click **Save changes**.
-The **{package}** **Packages & Registries > Package Registry** entry is removed from the sidebar.
+The **Packages & Registries > Package Registry** entry is removed from the sidebar.
## Package workflows
diff --git a/doc/user/packages/pypi_repository/index.md b/doc/user/packages/pypi_repository/index.md
index 97f3f69d676..33c37ee6a6c 100644
--- a/doc/user/packages/pypi_repository/index.md
+++ b/doc/user/packages/pypi_repository/index.md
@@ -4,14 +4,14 @@ group: Package
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/#designated-technical-writers
---
-# GitLab PyPi Repository
+# GitLab PyPI Repository
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/208747) in [GitLab Premium](https://about.gitlab.com/pricing/) 12.10.
> - [Moved](https://gitlab.com/gitlab-org/gitlab/-/issues/221259) to GitLab Core in 13.3.
-With the GitLab PyPi Repository, every project can have its own space to store PyPi packages.
+With the GitLab PyPI Repository, every project can have its own space to store PyPI packages.
-The GitLab PyPi Repository works with:
+The GitLab PyPI Repository works with:
- [pip](https://pypi.org/project/pip/)
- [twine](https://pypi.org/project/twine/)
@@ -20,13 +20,13 @@ The GitLab PyPi Repository works with:
You need a recent version of [pip](https://pypi.org/project/pip/) and [twine](https://pypi.org/project/twine/).
-## Enabling the PyPi Repository
+## Enabling the PyPI Repository
NOTE: **Note:**
This option is available only if your GitLab administrator has
[enabled support for the Package Registry](../../../administration/packages/index.md).
-After the PyPi Repository is enabled, it is available for all new projects
+After the PyPI Repository is enabled, it is available for all new projects
by default. To enable it for existing projects, or if you want to disable it:
1. Navigate to your project's **Settings > General > Visibility, project features, permissions**.
@@ -37,8 +37,8 @@ You should then be able to see the **Packages & Registries** section on the left
## Getting started
-This section covers creating a new example PyPi package to upload. This is a
-quickstart to test out the **GitLab PyPi Registry**. If you already understand how
+This section covers creating a new example PyPI package to upload. This is a
+quickstart to test out the **GitLab PyPI Registry**. If you already understand how
to build and publish your own packages, move on to the [next section](#adding-the-gitlab-pypi-repository-as-a-source).
### Create a project
@@ -111,6 +111,11 @@ touch setup.py
This file contains all the information about our package. For more information
about this file, see [creating setup.py](https://packaging.python.org/tutorials/packaging-projects/#creating-setup-py).
+GitLab identifies packages based on
+[Python normalized names (PEP-503)](https://www.python.org/dev/peps/pep-0503/#normalized-names),
+so ensure your package name meets these requirements.
+See the [installation section](#install-packages) for more details.
+
For this guide, we don't need to extensively fill out this file, simply add the
below to your `setup.py`:
@@ -152,10 +157,10 @@ And confirm your output matches the below:
mypypipackage-0.0.1-py3-none-any.whl mypypipackage-0.0.1.tar.gz
```
-Our package is now all set up and ready to be uploaded to the **GitLab PyPi
+Our package is now all set up and ready to be uploaded to the **GitLab PyPI
Package Registry**. Before we do so, we next need to set up authentication.
-## Adding the GitLab PyPi Repository as a source
+## Adding the GitLab PyPI Repository as a source
### Authenticating with a personal access token
@@ -256,7 +261,7 @@ TWINE_PASSWORD=<personal_access_token or deploy_token> TWINE_USERNAME=<username
```
If you did not follow the guide above, then you need to ensure your package
-has been properly built and you [created a PyPi package with `setuptools`](https://packaging.python.org/tutorials/packaging-projects/).
+has been properly built and you [created a PyPI package with `setuptools`](https://packaging.python.org/tutorials/packaging-projects/).
You can then upload your package using the following command:
@@ -274,7 +279,7 @@ Where:
Install the latest version of a package using the following command:
```shell
-pip install --index-url https://__token__:<personal_access_token>@gitlab.com/api/v4/projects/<project_id>/packages/pypi/simple --no-deps <package_name>
+pip install --extra-index-url https://__token__:<personal_access_token>@gitlab.com/api/v4/projects/<project_id>/packages/pypi/simple --no-deps <package_name>
```
Where:
@@ -287,7 +292,7 @@ If you were following the guide above and want to test installing the
`MyPyPiPackage` package, you can run the following:
```shell
-pip install mypypipackage --no-deps --index-url https://__token__:<personal_access_token>@gitlab.com/api/v4/projects/<your_project_id>/packages/pypi/simple
+pip install mypypipackage --no-deps --extra-index-url https://__token__:<personal_access_token>@gitlab.com/api/v4/projects/<your_project_id>/packages/pypi/simple
```
This should result in the following:
@@ -300,6 +305,12 @@ Installing collected packages: mypypipackage
Successfully installed mypypipackage-0.0.1
```
+GitLab looks for packages using
+[Python normalized names (PEP-503)](https://www.python.org/dev/peps/pep-0503/#normalized-names),
+so the characters `-`, `_`, and `.` are all treated the same and repeated characters are removed.
+A `pip install` request for `my.package` looks for packages that match any of
+the three characters, such as `my-package`, `my_package`, and `my....package`.
+
## Using GitLab CI with PyPI packages
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/202012) in GitLab 13.4.
diff --git a/doc/user/packages/workflows/monorepo.md b/doc/user/packages/workflows/monorepo.md
index c87f181bf82..f20f3427ac5 100644
--- a/doc/user/packages/workflows/monorepo.md
+++ b/doc/user/packages/workflows/monorepo.md
@@ -7,17 +7,17 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Monorepo package management workflows
Oftentimes, one project or Git repository may contain multiple different
-subprojects or submodules that all get packaged and published individually.
+sub-projects or submodules that all get packaged and published individually.
## Publishing different packages to the parent project
The number and name of packages you can publish to one project is not limited.
You can accomplish this by setting up different configuration files for each
package. See the documentation for the package manager of your choice since
-each will have its own specific files and instructions to follow to publish
+each has its own specific files and instructions to follow to publish
a given package.
-Here, we will walk through how to do this with [NPM](../npm_registry/index.md).
+Here, we take a walk through how to do this with [NPM](../npm_registry/index.md).
Let us say we have a project structure like so:
@@ -36,27 +36,27 @@ as well as `Foo`.
Following the instructions in the
[GitLab NPM registry documentation](../npm_registry/index.md),
publishing `MyProject` consists of modifying the `package.json` file with a
-`publishConfig` section, as well as either modifying your local NPM config with
+`publishConfig` section, as well as either modifying your local NPM configuration with
CLI commands like `npm config set`, or saving a `.npmrc` file in the root of the
-project specifying these config settings.
+project specifying these configuration settings.
If you follow the instructions you can publish `MyProject` by running
`npm publish` from the root directory.
Publishing `Foo` is almost exactly the same, you simply have to follow the steps
-while in the `Foo` directory. `Foo` will need its own `package.json` file,
-which can be added manually or using `npm init`. And it will need its own
+while in the `Foo` directory. `Foo` needs its own `package.json` file,
+which can be added manually or using `npm init`. It also needs its own
configuration settings. Since you are publishing to the same place, if you
used `npm config set` to set the registry for the parent project, then no
-additional setup is necessary. If you used a `.npmrc` file, you will need an
+additional setup is necessary. If you used a `.npmrc` file, you need an
additional `.npmrc` file in the `Foo` directory (be sure to add `.npmrc` files
to the `.gitignore` file or use environment variables in place of your access
tokens to prevent them from being exposed). It can be identical to the
one you used in `MyProject`. You can now run `npm publish` from the `Foo`
-directory and you will be able to publish `Foo` separately from `MyProject`
+directory and you can publish `Foo` separately from `MyProject`
A similar process could be followed for Conan packages, instead of dealing with
-`.npmrc` and `package.json`, you will just be dealing with `conanfile.py` in
+`.npmrc` and `package.json`, you just deal with `conanfile.py` in
multiple locations within the project.
## Publishing to other projects
@@ -64,9 +64,9 @@ multiple locations within the project.
A package is associated with a project on GitLab, but the package does not
need to be associated with the code in that project. Notice when configuring
NPM or Maven, you only use the `Project ID` to set the registry URL that the
-package will be uploaded to. If you set this to any project that you have
-access to and update any other config similarly depending on the package type,
-your packages will be published to that project. This means you can publish
+package is to be uploaded to. If you set this to any project that you have
+access to and update any other configuration similarly depending on the package type,
+your packages are published to that project. This means you can publish
multiple packages to one project, even if their code does not exist in the same
place. See the [project registry workflow documentation](./project_registry.md)
for more details.
@@ -77,7 +77,7 @@ CI pipelines open an entire world of possibilities for dealing with the patterns
described in the previous sections. A common desire would be to publish
specific packages only if changes were made to those directories.
-Using the example project above, this `gitlab-ci.yml` file will publish
+Using the example project above, this `gitlab-ci.yml` file publishes
`Foo` anytime changes are made to the `Foo` directory on the `master` branch,
and publish `MyPackage` anytime changes are made to anywhere _except_ the `Foo`
directory on the `master` branch.
diff --git a/doc/user/packages/workflows/project_registry.md b/doc/user/packages/workflows/project_registry.md
index 571cda09e69..24437e6dfac 100644
--- a/doc/user/packages/workflows/project_registry.md
+++ b/doc/user/packages/workflows/project_registry.md
@@ -26,8 +26,8 @@ point them at the same project on GitLab.
There are a few reasons you might want to publish all your packages to one project on GitLab:
1. You want to publish your packages on GitLab, but to a project that is different from where your code is stored.
-1. You would like to group packages together in ways that make sense for your usage (all NPM packages in one project,
- all packages being used by a specific department in one project, all private packages in one project, etc.)
+1. You would like to group packages together in ways that make sense for your usage (such as all NPM packages in one project,
+ all packages being used by a specific department in one project, or all private packages in one project)
1. You want to use one remote for all of your packages when installing them into other projects.
1. You would like to migrate your packages to a single place on GitLab from a third-party package registry and do not
want to worry about setting up separate projects for each package.
@@ -44,7 +44,7 @@ Let's take a look at how you might create a public place to hold all of your pub
### Create a project
First, create a new project on GitLab. It does not have to have any code or content. Make note of the project ID
-displayed on the project overview page, as you will need this later.
+displayed on the project overview page for use later in this process.
### Create an access token
@@ -67,24 +67,24 @@ If you are using NPM, this involves creating an `.npmrc` file and adding the app
to your project using your project ID, then adding a section to your `package.json` file with a similar URL.
Follow
-the instructions in the [GitLab NPM Registry documentation](../npm_registry/index.md#authenticating-to-the-gitlab-npm-registry). Once
-you do this, you will be able to push your NPM package to your project using `npm publish`, as described in the
+the instructions in the [GitLab NPM Registry documentation](../npm_registry/index.md#authenticating-to-the-gitlab-npm-registry). After
+you do this, you can push your NPM package to your project using `npm publish`, as described in the
[uploading packages](../npm_registry/index.md#uploading-packages) section of the docs.
#### Maven
If you are using Maven, this involves updating your `pom.xml` file with distribution sections, including the
appropriate URL for your project, as described in the [GitLab Maven Repository documentation](../maven_repository/index.md#project-level-maven-endpoint).
-Then, you need to add a `settings.xml` file and [include your access token](../maven_repository/index.md#authenticating-with-a-personal-access-token).
+Then, you need to add a `settings.xml` file and [include your access token](../maven_repository/index.md#authenticate-with-a-personal-access-token).
Now you can [deploy Maven packages](../maven_repository/index.md#uploading-packages) to your project.
#### Conan
-For Conan, first you need to add GitLab as a Conan registry remote. Follow the instructions in the [GitLab Conan Repository docs](../conan_repository/index.md#adding-the-gitlab-package-registry-as-a-conan-remote)
+For Conan, first you need to add GitLab as a Conan registry remote. Follow the instructions in the [GitLab Conan Repository docs](../conan_repository/index.md#add-the-package-registry-as-a-conan-remote)
to do so. Then, create your package using the plus-separated (`+`) project path as your Conan user. For example,
if your project is located at `https://gitlab.com/foo/bar/my-proj`, then you can [create your Conan package](../conan_repository/index.md)
-using `conan create . foo+bar+my-proj/channel`, where `channel` is your package channel (`stable`, `beta`, etc.). Once your package
-is created, you are ready to [upload your package](../conan_repository/index.md#uploading-a-package) depending on your final package recipe. For example:
+using `conan create . foo+bar+my-proj/channel`, where `channel` is your package channel (such as `stable` or `beta`). After your package
+is created, you are ready to [upload your package](../conan_repository/index.md#publish-a-conan-package) depending on your final package recipe. For example:
```shell
CONAN_LOGIN_USERNAME=<gitlab-username> CONAN_PASSWORD=<personal_access_token> conan upload MyPackage/1.0.0@foo+bar+my-proj/channel --all --remote=gitlab
diff --git a/doc/user/permissions.md b/doc/user/permissions.md
index e2baac1a962..2e9f36360c6 100644
--- a/doc/user/permissions.md
+++ b/doc/user/permissions.md
@@ -1,5 +1,7 @@
---
-description: 'Understand and explore the user permission levels in GitLab, and what features each of them grants you access to.'
+stage: Manage
+group: Access
+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/#designated-technical-writers
---
# Permissions
@@ -8,7 +10,7 @@ Users have different abilities depending on the access level they have in a
particular group or project. If a user is both in a project's group and the
project itself, the highest permission level is used.
-On public and internal projects the Guest role is not enforced. All users can:
+On public and internal projects, the Guest role is not enforced. All users can:
- Create issues.
- Leave comments.
@@ -42,17 +44,17 @@ or an instance administrator, who receives all permissions. For more information
The following table depicts the various user permission levels in a project.
-| Action | Guest | Reporter | Developer |Maintainer| Owner* |
+| Action | Guest | Reporter | Developer |Maintainer| Owner (*10*) |
|---------------------------------------------------|---------|------------|-------------|----------|--------|
| Download project | ✓ (*1*) | ✓ | ✓ | ✓ | ✓ |
| Leave comments | ✓ | ✓ | ✓ | ✓ | ✓ |
-| View allowed and denied licenses **(ULTIMATE)** | ✓ (*1*) | ✓ | ✓ | ✓ | ✓ |
+| View allowed and denied licenses **(ULTIMATE)** | ✓ (*1*) | ✓ | ✓ | ✓ | ✓ |
| View License Compliance reports **(ULTIMATE)** | ✓ (*1*) | ✓ | ✓ | ✓ | ✓ |
| View Security reports **(ULTIMATE)** | ✓ (*3*) | ✓ | ✓ | ✓ | ✓ |
| View Dependency list **(ULTIMATE)** | ✓ (*1*) | ✓ | ✓ | ✓ | ✓ |
| View License list **(ULTIMATE)** | ✓ (*1*) | ✓ | ✓ | ✓ | ✓ |
| View licenses in Dependency list **(ULTIMATE)** | ✓ (*1*) | ✓ | ✓ | ✓ | ✓ |
-| View [Design Management](project/issues/design_management.md) pages | ✓ | ✓ | ✓ | ✓ | ✓ |
+| View [Design Management](project/issues/design_management.md) pages | ✓ | ✓ | ✓ | ✓ | ✓ |
| View project code | ✓ (*1*) | ✓ | ✓ | ✓ | ✓ |
| Pull project code | ✓ (*1*) | ✓ | ✓ | ✓ | ✓ |
| View GitLab Pages protected by [access control](project/pages/introduction.md#gitlab-pages-access-control) | ✓ | ✓ | ✓ | ✓ | ✓ |
@@ -63,30 +65,35 @@ The following table depicts the various user permission levels in a project.
| Create new issue | ✓ | ✓ | ✓ | ✓ | ✓ |
| See related issues | ✓ | ✓ | ✓ | ✓ | ✓ |
| Create confidential issue | ✓ | ✓ | ✓ | ✓ | ✓ |
-| View confidential issues | (*2*) | ✓ | ✓ | ✓ | ✓ |
| View [Releases](project/releases/index.md) | ✓ (*6*) | ✓ | ✓ | ✓ | ✓ |
| View requirements **(ULTIMATE)** | ✓ | ✓ | ✓ | ✓ | ✓ |
+| View Insights **(ULTIMATE)** | ✓ | ✓ | ✓ | ✓ | ✓ |
+| View Issue analytics **(PREMIUM)** | ✓ | ✓ | ✓ | ✓ | ✓ |
+| View Merge Request analytics **(STARTER)** | ✓ | ✓ | ✓ | ✓ | ✓ |
+| View Value Stream analytics | ✓ | ✓ | ✓ | ✓ | ✓ |
| Manage user-starred metrics dashboards (*7*) | ✓ | ✓ | ✓ | ✓ | ✓ |
+| View confidential issues | (*2*) | ✓ | ✓ | ✓ | ✓ |
| Assign issues | | ✓ | ✓ | ✓ | ✓ |
| Label issues | | ✓ | ✓ | ✓ | ✓ |
| Set issue weight | | ✓ | ✓ | ✓ | ✓ |
| Lock issue threads | | ✓ | ✓ | ✓ | ✓ |
| Manage issue tracker | | ✓ | ✓ | ✓ | ✓ |
-| Manage related issues **(STARTER)** | | ✓ | ✓ | ✓ | ✓ |
+| Manage related issues | | ✓ | ✓ | ✓ | ✓ |
| Manage labels | | ✓ | ✓ | ✓ | ✓ |
| Create code snippets | | ✓ | ✓ | ✓ | ✓ |
| See a commit status | | ✓ | ✓ | ✓ | ✓ |
| See a container registry | | ✓ | ✓ | ✓ | ✓ |
| See environments | | ✓ | ✓ | ✓ | ✓ |
| See a list of merge requests | | ✓ | ✓ | ✓ | ✓ |
-| View project statistics | | | ✓ | ✓ | ✓ |
+| View CI/CD analytics | | ✓ | ✓ | ✓ | ✓ |
+| View Code Review analytics **(STARTER)** | | ✓ | ✓ | ✓ | ✓ |
+| View Repository analytics | | ✓ | ✓ | ✓ | ✓ |
| View Error Tracking list | | ✓ | ✓ | ✓ | ✓ |
| Create new merge request | | ✓ | ✓ | ✓ | ✓ |
| View metrics dashboard annotations | | ✓ | ✓ | ✓ | ✓ |
| Create/edit requirements **(ULTIMATE)** | | ✓ | ✓ | ✓ | ✓ |
| Pull [packages](packages/index.md) | | ✓ | ✓ | ✓ | ✓ |
| Publish [packages](packages/index.md) | | | ✓ | ✓ | ✓ |
-| Delete [packages](packages/index.md) | | | | ✓ | ✓ |
| Create/edit/delete a Cleanup policy | | | ✓ | ✓ | ✓ |
| Upload [Design Management](project/issues/design_management.md) files | | | ✓ | ✓ | ✓ |
| Create/edit/delete [Releases](project/releases/index.md)| | | ✓ | ✓ | ✓ |
@@ -99,9 +106,12 @@ The following table depicts the various user permission levels in a project.
| Lock merge request threads | | | ✓ | ✓ | ✓ |
| Approve merge requests (*9*) | | | ✓ | ✓ | ✓ |
| Manage/Accept merge requests | | | ✓ | ✓ | ✓ |
+| View project statistics | | | ✓ | ✓ | ✓ |
| Create new environments | | | ✓ | ✓ | ✓ |
| Stop environments | | | ✓ | ✓ | ✓ |
| Enable Review Apps | | | ✓ | ✓ | ✓ |
+| View Pods logs | | | ✓ | ✓ | ✓ |
+| Read Terraform state | | | ✓ | ✓ | ✓ |
| Add tags | | | ✓ | ✓ | ✓ |
| Cancel and retry jobs | | | ✓ | ✓ | ✓ |
| Create or update commit status | | | ✓ (*5*) | ✓ | ✓ |
@@ -116,12 +126,14 @@ The following table depicts the various user permission levels in a project.
| Create vulnerability from vulnerability finding **(ULTIMATE)** | | | ✓ | ✓ | ✓ |
| Resolve vulnerability **(ULTIMATE)** | | | ✓ | ✓ | ✓ |
| Dismiss vulnerability **(ULTIMATE)** | | | ✓ | ✓ | ✓ |
+| Revert vulnerability to detected state **(ULTIMATE)** | | | ✓ | ✓ | ✓ |
| Apply code change suggestions | | | ✓ | ✓ | ✓ |
| Create and edit wiki pages | | | ✓ | ✓ | ✓ |
| Rewrite/remove Git tags | | | ✓ | ✓ | ✓ |
| Manage Feature Flags **(PREMIUM)** | | | ✓ | ✓ | ✓ |
| Create/edit/delete metrics dashboard annotations | | | ✓ | ✓ | ✓ |
| Run CI/CD pipeline against a protected branch | | | ✓ (*5*) | ✓ | ✓ |
+| Delete [packages](packages/index.md) | | | | ✓ | ✓ |
| Request a CVE ID **(FREE ONLY)** | | | | ✓ | ✓ |
| Use environment terminals | | | | ✓ | ✓ |
| Run Web IDE's Interactive Web Terminals **(ULTIMATE ONLY)** | | | | ✓ | ✓ |
@@ -132,6 +144,7 @@ The following table depicts the various user permission levels in a project.
| Enable/disable tag protections | | | | ✓ | ✓ |
| Edit project settings | | | | ✓ | ✓ |
| Edit project badges | | | | ✓ | ✓ |
+| Export project | | | | ✓ | ✓ |
| Share (invite) projects with groups | | | | ✓ (*8*) | ✓ (*8*)|
| Add deploy keys to project | | | | ✓ | ✓ |
| Configure project hooks | | | | ✓ | ✓ |
@@ -143,8 +156,6 @@ The following table depicts the various user permission levels in a project.
| Remove GitLab Pages | | | | ✓ | ✓ |
| Manage clusters | | | | ✓ | ✓ |
| Manage Project Operations | | | | ✓ | ✓ |
-| View Pods logs | | | ✓ | ✓ | ✓ |
-| Read Terraform state | | | ✓ | ✓ | ✓ |
| Manage Terraform state | | | | ✓ | ✓ |
| Manage license policy **(ULTIMATE)** | | | | ✓ | ✓ |
| Edit comments (posted by any user) | | | | ✓ | ✓ |
@@ -165,17 +176,8 @@ The following table depicts the various user permission levels in a project.
| Disable notification emails | | | | | ✓ |
| Force push to protected branches (*4*) | | | | | |
| Remove protected branches (*4*) | | | | | |
-| View CI\CD analytics | | ✓ | ✓ | ✓ | ✓ |
-| View Code Review analytics **(STARTER)** | | ✓ | ✓ | ✓ | ✓ |
-| View Insights **(ULTIMATE)** | ✓ | ✓ | ✓ | ✓ | ✓ |
-| View Issue analytics **(PREMIUM)** | ✓ | ✓ | ✓ | ✓ | ✓ |
-| View Merge Request analytics **(STARTER)** | ✓ | ✓ | ✓ | ✓ | ✓ |
-| View Repository analytics | | ✓ | ✓ | ✓ | ✓ |
-| View Value Stream analytics | ✓ | ✓ | ✓ | ✓ | ✓ |
-\* Owner permission is only available at the group or personal namespace level (and for instance admins) and is inherited by its projects.
-
-1. Guest users are able to perform this action on public and internal projects, but not private projects.
+1. Guest users are able to perform this action on public and internal projects, but not private projects. This doesn't apply to [external users](#external-users) where explicit access must be given even if the project is internal.
1. Guest users can only view the confidential issues they created themselves.
1. If **Public pipelines** is enabled in **Project Settings > CI/CD**.
1. Not allowed for Guest, Reporter, Developer, Maintainer, or Owner. See [Protected Branches](./project/protected_branches.md).
@@ -185,6 +187,7 @@ The following table depicts the various user permission levels in a project.
1. When [Share Group Lock](./group/index.md#share-with-group-lock) is enabled the project can't be shared with other groups. It does not affect group with group sharing.
1. For information on eligible approvers for merge requests, see
[Eligible approvers](project/merge_requests/merge_request_approvals.md#eligible-approvers).
+1. Owner permission is only available at the group or personal namespace level (and for instance admins) and is inherited by its projects.
## Project features permissions
@@ -195,7 +198,7 @@ which visibility level you select on project settings.
- Disabled: disabled for everyone
- Only team members: only team members can see even if your project is public or internal
-- Everyone with access: everyone can see depending on your project visibility level
+- Everyone with access: everyone can see depending on your project's visibility level
- Everyone: enabled for everyone (only available for GitLab Pages)
### Protected branches
@@ -224,7 +227,7 @@ Read through the documentation on [permissions for File Locking](project/file_lo
### Confidential Issues permissions
-Confidential issues can be accessed by reporters and higher permission levels,
+Confidential issues can be accessed by users with reporter and higher permission levels,
as well as by guest users that create a confidential issue. To learn more,
read through the documentation on [permissions and access to confidential issues](project/issues/confidential_issues.md#permissions-and-access-to-confidential-issues).
@@ -240,6 +243,7 @@ group.
| Action | Guest | Reporter | Developer | Maintainer | Owner |
|--------------------------------------------------------|-------|----------|-----------|------------|-------|
| Browse group | ✓ | ✓ | ✓ | ✓ | ✓ |
+| View group wiki pages **(PREMIUM)** | ✓ (6) | ✓ | ✓ | ✓ | ✓ |
| View Insights charts **(ULTIMATE)** | ✓ | ✓ | ✓ | ✓ | ✓ |
| View group epic **(ULTIMATE)** | ✓ | ✓ | ✓ | ✓ | ✓ |
| Create/edit group epic **(ULTIMATE)** | | ✓ | ✓ | ✓ | ✓ |
@@ -253,10 +257,12 @@ group.
| Create/edit/delete group milestones | | | ✓ | ✓ | ✓ |
| Create/edit/delete iterations | | | ✓ | ✓ | ✓ |
| Enable/disable a dependency proxy **(PREMIUM)** | | | ✓ | ✓ | ✓ |
+| Create and edit group wiki pages **(PREMIUM)** | | | ✓ | ✓ | ✓ |
| Use security dashboard **(ULTIMATE)** | | | ✓ | ✓ | ✓ |
| Create/edit/delete metrics dashboard annotations | | | ✓ | ✓ | ✓ |
| View/manage group-level Kubernetes cluster | | | | ✓ | ✓ |
| Create subgroup | | | | ✓ (1) | ✓ |
+| Delete group wiki pages **(PREMIUM)** | | | | ✓ | ✓ |
| Edit epic comments (posted by any user) **(ULTIMATE)** | | | | ✓ (2) | ✓ (2) |
| Edit group settings | | | | | ✓ |
| Manage group level CI/CD variables | | | | | ✓ |
@@ -270,7 +276,7 @@ group.
| Disable notification emails | | | | | ✓ |
| View Contribution analytics | ✓ | ✓ | ✓ | ✓ | ✓ |
| View Insights **(ULTIMATE)** | ✓ | ✓ | ✓ | ✓ | ✓ |
-| View Issue analytics **(PREMIUM)** | ✓ | ✓ | ✓ | ✓ | ✓ |
+| View Issue analytics **(PREMIUM)** | ✓ | ✓ | ✓ | ✓ | ✓ |
| View Productivity analytics **(PREMIUM)** | | ✓ | ✓ | ✓ | ✓ |
| View Value Stream analytics | ✓ | ✓ | ✓ | ✓ | ✓ |
| View Billing **(FREE ONLY)** | | | | | ✓ (4) |
@@ -283,7 +289,8 @@ group.
- The [instance level](admin_area/settings/visibility_and_access_controls.md#default-project-creation-protection).
- The [group level](group/index.md#default-project-creation-level).
1. Does not apply to subgroups.
-1. Developers can push commits to the default branch of a new project only if the [default branch protection](group/index.md#changing-the-default-branch-protection-of-a-group) is set to "Partially protected" or "Not protected".
+1. Developers can push commits to the default branch of a new project only if the [default branch protection](group/index.md#changing-the-default-branch-protection-of-a-group) is set to "Partially protected" or "Not protected".
+1. In addition, if your group is public or internal, all users who can see the group can also see group wiki pages.
### Subgroup permissions
@@ -311,7 +318,7 @@ External users:
Access can be granted by adding the user as member to the project or group.
Like usual users, they receive a role in the project or group with all
the abilities that are mentioned in the [permissions table above](#project-members-permissions).
-For example, if an external user is added as Guest, and your project is
+For example, if an external user is added as Guest, and your project is internal or
private, they do not have access to the code; you need to grant the external
user access at the Reporter level or above if you want them to have access to the code. You should
always take into account the
@@ -339,7 +346,7 @@ The **Internal users** field allows specifying an email address regex pattern to
identify default internal users. New users whose email address matches the regex
pattern are set to internal by default rather than an external collaborator.
-The regex pattern format is Ruby, but it needs to be convertible to JavaScript,
+The regex pattern format is in Ruby, but it needs to be convertible to JavaScript,
and the ignore case flag is set (`/regex pattern/i`). Here are some examples:
- Use `\.internal@domain\.com$` to mark email addresses ending with
@@ -384,6 +391,16 @@ with the permissions described on the documentation on [auditor users permission
[Read more about Auditor users.](../administration/auditor_users.md)
+## Users with minimal access **(PREMIUM ONLY)**
+
+>[Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/40942) in [GitLab Premium](https://about.gitlab.com/pricing/) 13.4.
+
+Administrators can add members with a "minimal access" role to a parent group. Such users don't
+automatically have access to projects and subgroups underneath. To support such access, administrators must explicitly add these "minimal access" users to the specific subgroups/projects.
+
+Users with minimal access can list the group in the UI and through the API. However, they cannot see
+details such as projects or subgroups. They do not have access to the group's page or list any of its subgroups or projects.
+
## Project features
Project features like wiki and issues can be hidden from users depending on
@@ -426,7 +443,7 @@ instance and project. In addition, all admins can use the admin interface under
1. Only if the job was:
- Triggered by the user
- - [Since GitLab 13.0](https://gitlab.com/gitlab-org/gitlab/-/issues/35069), not run for a protected branch
+ - [In GitLab 13.0](https://gitlab.com/gitlab-org/gitlab/-/issues/35069) and later, not run for a protected branch
### Job permissions
@@ -473,7 +490,7 @@ for details about the pipelines security model.
## LDAP users permissions
-Since GitLab 8.15, LDAP user permissions can now be manually overridden by an admin user.
+In GitLab 8.15 and later, LDAP user permissions can now be manually overridden by an admin user.
Read through the documentation on [LDAP users permissions](group/index.md#manage-group-memberships-via-ldap) to learn more.
## Project aliases
diff --git a/doc/user/profile/account/create_accounts.md b/doc/user/profile/account/create_accounts.md
index 26c2c1bed89..09bfa7afc9e 100644
--- a/doc/user/profile/account/create_accounts.md
+++ b/doc/user/profile/account/create_accounts.md
@@ -31,9 +31,9 @@ You can also [create users through the API](../../../api/users.md) as an admin.
![Admin User Form](img/admin_user_form.png)
-## Create users through integrations
+## Create users through authentication integrations
Users will be:
-- Automatically created upon first login with the [LDAP integration](../../../administration/auth/ldap/index.md).
-- Created when first logging in via an [OmniAuth provider](../../../integration/omniauth.md) if the `allow_single_sign_on` setting is present.
+- Automatically created upon first sign in with the [LDAP integration](../../../administration/auth/ldap/index.md).
+- Created when first signing in via an [OmniAuth provider](../../../integration/omniauth.md) if the `allow_single_sign_on` setting is present.
diff --git a/doc/user/profile/index.md b/doc/user/profile/index.md
index 894494da513..0400d9ca2e5 100644
--- a/doc/user/profile/index.md
+++ b/doc/user/profile/index.md
@@ -51,7 +51,14 @@ To access your profile settings:
From there, you can:
-- Update your personal information
+- Update your personal information, including:
+ - Full name
+ - Primary email, public email, and commit email
+ - Social media handles
+ - Website URL
+ - Location
+ - Job title
+ - Bio
- Change your [password](#changing-your-password)
- Set a [custom status](#current-status) for your profile
- Manage your [commit email](#commit-email) for your profile
diff --git a/doc/user/profile/personal_access_tokens.md b/doc/user/profile/personal_access_tokens.md
index 1b8c16f401c..911be117716 100644
--- a/doc/user/profile/personal_access_tokens.md
+++ b/doc/user/profile/personal_access_tokens.md
@@ -14,7 +14,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
If you're unable to use [OAuth2](../../api/oauth2.md), you can use a personal access token to authenticate with the [GitLab API](../../api/README.md#personalproject-access-tokens).
-You can also use personal access tokens with Git to authenticate over HTTP or SSH. Personal access tokens are required when [Two-Factor Authentication (2FA)](../account/two_factor_authentication.md) is enabled. In both cases, you can authenticate with a token in place of your password.
+You can also use personal access tokens with Git to authenticate over HTTP or SSH. Personal access tokens are required when [Two-Factor Authentication (2FA)](account/two_factor_authentication.md) is enabled. In both cases, you can authenticate with a token in place of your password.
Personal access tokens expire on the date you define, at midnight UTC.
@@ -71,7 +71,7 @@ the following table.
You can programmatically create a predetermined personal access token for use in
automation or tests. You need sufficient access to run a
-[Rails console session](../../administration/troubleshooting/debug.md#starting-a-rails-console-session)
+[Rails console session](../../administration/operations/rails_console.md#starting-a-rails-console-session)
for your GitLab instance.
To create a token belonging to a user with username `automation-bot`, run the
@@ -101,7 +101,7 @@ The list of valid scopes and what they do can be found
## Programmatically revoking a personal access token
You can programmatically revoke a personal access token. You need
-sufficient access to run a [Rails console session](../../administration/troubleshooting/debug.md#starting-a-rails-console-session)
+sufficient access to run a [Rails console session](../../administration/operations/rails_console.md#starting-a-rails-console-session)
for your GitLab instance.
To revoke a known token `token-string-here123`, run the following in the Rails
diff --git a/doc/user/profile/preferences.md b/doc/user/profile/preferences.md
index f84fc1ae898..61944bb9d0b 100644
--- a/doc/user/profile/preferences.md
+++ b/doc/user/profile/preferences.md
@@ -84,7 +84,7 @@ The default syntax theme is White, and you can choose among 5 different themes:
[Introduced](https://gitlab.com/groups/gitlab-org/-/epics/2389) in 13.0, the theme
you choose also applies to the [Web IDE](../project/web_ide/index.md)'s code editor and [Snippets](../snippets.md).
The themes are available only in the Web IDE file editor, except for the [dark theme](https://gitlab.com/gitlab-org/gitlab/-/issues/209808) and
-the [solarized dark theme](https://gitlab.com/gitlab-org/gitlab/-/issues/219228),
+the [Solarized dark theme](https://gitlab.com/gitlab-org/gitlab/-/issues/219228),
which apply to the entire Web IDE screen.
## Behavior
@@ -131,15 +131,9 @@ You can choose between 2 options:
### Project overview content
-The project overview content setting allows you to choose what content you want to
+The **Project overview content** setting allows you to choose what content you want to
see on a project’s home page.
-You can choose between 3 options:
-
-- Files and Readme (default)
-- Readme
-- Activity
-
### Tab width
You can set the displayed width of tab characters across various parts of
diff --git a/doc/user/project/autocomplete_characters.md b/doc/user/project/autocomplete_characters.md
index 1acdc56de54..ff9cb1c712e 100644
--- a/doc/user/project/autocomplete_characters.md
+++ b/doc/user/project/autocomplete_characters.md
@@ -35,6 +35,8 @@ Autocomplete characters are useful when combined with [Quick Actions](quick_acti
Assume your GitLab instance includes the following users:
+<!-- vale gitlab.Spelling = NO -->
+
| Username | Name |
| :-------------- | :--- |
| alessandra | Rosy Grant |
@@ -43,6 +45,8 @@ Assume your GitLab instance includes the following users:
| logan_gutkowski | Lee Wuckert |
| shelba | Josefine Haley |
+<!-- vale gitlab.Spelling = YES -->
+
In an Issue comment, entering `@l` results in the following popup list
appearing. Note that user `shelba` is not included, because the list includes
only the 5 users most relevant to the Issue.
diff --git a/doc/user/project/badges.md b/doc/user/project/badges.md
index ed6e2460554..fd0287fb5fb 100644
--- a/doc/user/project/badges.md
+++ b/doc/user/project/badges.md
@@ -10,7 +10,7 @@ type: reference, howto
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/41174) in GitLab 10.7.
Badges are a unified way to present condensed pieces of information about your
-projects. They consist of a small image and additionally a URL that the image
+projects. They consist of a small image and a URL that the image
points to. Examples for badges can be the [pipeline status](../../ci/pipelines/settings.md#pipeline-status-badge),
[test coverage](../../ci/pipelines/settings.md#test-coverage-report-badge), or ways to contact the
project maintainers.
diff --git a/doc/user/project/clusters/add_eks_clusters.md b/doc/user/project/clusters/add_eks_clusters.md
index b3b1b51a543..65416d73f06 100644
--- a/doc/user/project/clusters/add_eks_clusters.md
+++ b/doc/user/project/clusters/add_eks_clusters.md
@@ -43,7 +43,7 @@ For example, the following policy document allows assuming a role whose name sta
Generate an access key for the IAM user, and configure GitLab with the credentials:
-1. Navigate to **Admin Area > Settings > Integrations** and expand the **Amazon EKS** section.
+1. Navigate to **Admin Area > Settings > General** and expand the **Amazon EKS** section.
1. Check **Enable Amazon EKS integration**.
1. Enter the account ID and access key credentials into the respective
`Account ID`, `Access key ID` and `Secret access key` fields.
@@ -61,22 +61,13 @@ To create and add a new Kubernetes cluster to your project, group, or instance:
- **Admin Area > Kubernetes**, for an instance-level cluster.
1. Click **Add Kubernetes cluster**.
1. Under the **Create new cluster** tab, click **Amazon EKS**. You will be provided with an
- `Account ID` and `External ID` to use in the next step.
-1. In the [IAM Management Console](https://console.aws.amazon.com/iam/home), create an EKS management IAM role.
- To do so, follow the [Amazon EKS cluster IAM role](https://docs.aws.amazon.com/eks/latest/userguide/service_IAM_role.html) instructions
- to create a IAM role suitable for managing the AWS EKS cluster's resources on your behalf.
- In addition to the policies that guide suggests, you must also include the `AmazonEKSClusterPolicy`
- policy for this role in order for GitLab to manage the EKS cluster correctly.
-1. In the [IAM Management Console](https://console.aws.amazon.com/iam/home), create an IAM role:
- 1. From the left panel, select **Roles**.
- 1. Click **Create role**.
- 1. Under `Select type of trusted entity`, select **Another AWS account**.
- 1. Enter the Account ID from GitLab into the `Account ID` field.
- 1. Check **Require external ID**.
- 1. Enter the External ID from GitLab into the `External ID` field.
- 1. Click **Next: Permissions**.
- 1. Click **Create Policy**, which will open a new window.
- 1. Select the **JSON** tab, and paste in the following snippet in place of the existing content:
+ `Account ID` and `External ID` needed for later steps.
+1. In the [IAM Management Console](https://console.aws.amazon.com/iam/home), create an IAM policy:
+ 1. From the left panel, select **Policies**.
+ 1. Click **Create Policy**, which opens a new window.
+ 1. Select the **JSON** tab, and paste the following snippet in place of the
+ existing content. These permissions give GitLab the ability to create
+ resources, but not delete them:
```json
{
@@ -123,15 +114,26 @@ To create and add a new Kubernetes cluster to your project, group, or instance:
}
```
- NOTE: **Note:**
- These permissions give GitLab the ability to create resources, but not delete them.
- This means that if an error is encountered during the creation process, changes will
+ If an error is encountered during the creation process, changes will
not be rolled back and you must remove resources manually. You can do this by deleting
the relevant [CloudFormation stack](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-console-delete-stack.html)
1. Click **Review policy**.
1. Enter a suitable name for this policy, and click **Create Policy**. You can now close this window.
- 1. Switch back to the "Create role" window, and select the policy you just created.
+
+1. In the [IAM Management Console](https://console.aws.amazon.com/iam/home), create an EKS management IAM role.
+ To do so, follow the [Amazon EKS cluster IAM role](https://docs.aws.amazon.com/eks/latest/userguide/service_IAM_role.html) instructions
+ to create a IAM role suitable for managing the AWS EKS cluster's resources on your behalf.
+ In addition to the policies that guide suggests, you must also include the `AmazonEKSClusterPolicy`
+ policy for this role in order for GitLab to manage the EKS cluster correctly.
+1. In the [IAM Management Console](https://console.aws.amazon.com/iam/home), create an IAM role:
+ 1. From the left panel, select **Roles**.
+ 1. Click **Create role**.
+ 1. Under `Select type of trusted entity`, select **Another AWS account**.
+ 1. Enter the Account ID from GitLab into the `Account ID` field.
+ 1. Check **Require external ID**.
+ 1. Enter the External ID from GitLab into the `External ID` field.
+ 1. Click **Next: Permissions**, and select the policy you just created.
1. Click **Next: Tags**, and optionally enter any tags you wish to associate with this role.
1. Click **Next: Review**.
1. Enter a role name and optional description into the fields provided.
diff --git a/doc/user/project/clusters/add_remove_clusters.md b/doc/user/project/clusters/add_remove_clusters.md
index 18d9fa67ee1..094f4bcf6ba 100644
--- a/doc/user/project/clusters/add_remove_clusters.md
+++ b/doc/user/project/clusters/add_remove_clusters.md
@@ -19,9 +19,12 @@ and learn how to spin up a Kubernetes cluster managed by Google Cloud Platform (
in a few clicks.
TIP: **Tip:**
-Every new Google Cloud Platform (GCP) account receives [$300 in credit upon sign up](https://console.cloud.google.com/freetrial),
-and in partnership with Google, GitLab is able to offer an additional $200 for new GCP accounts to get started with GitLab's
-Google Kubernetes Engine Integration. All you have to do is [follow this link](https://cloud.google.com/partners/partnercredit/?pcn_code=0014M00001h35gDQAQ#contact-form) and apply for credit.
+Every new Google Cloud Platform (GCP) account receives
+[$300 in credit upon sign up](https://console.cloud.google.com/freetrial).
+In partnership with Google, GitLab is able to offer an additional $200 for new GCP
+accounts to get started with GitLab's Google Kubernetes Engine Integration.
+[Follow this link](https://cloud.google.com/partners/partnercredit/?pcn_code=0014M00001h35gDQAQ#contact-form)
+to apply for credit.
## Before you begin
@@ -30,7 +33,7 @@ Before [adding a Kubernetes cluster](#create-new-cluster) using GitLab, you need
- GitLab itself. Either:
- A [GitLab.com account](https://about.gitlab.com/pricing/#gitlab-com).
- A [self-managed installation](https://about.gitlab.com/pricing/#self-managed) with GitLab version
- 12.5 or later. This will ensure the GitLab UI can be used for cluster creation.
+ 12.5 or later. This ensures the GitLab UI can be used for cluster creation.
- The following GitLab access:
- [Maintainer access to a project](../../permissions.md#project-members-permissions) for a
project-level cluster.
@@ -41,28 +44,25 @@ Before [adding a Kubernetes cluster](#create-new-cluster) using GitLab, you need
## Access controls
-When creating a cluster in GitLab, you will be asked if you would like to create either:
+> - Restricted service account for deployment was [introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/51716) in GitLab 11.5.
-- A [Role-based access control (RBAC)](https://kubernetes.io/docs/reference/access-authn-authz/rbac/) cluster.
-- An [Attribute-based access control (ABAC)](https://kubernetes.io/docs/reference/access-authn-authz/abac/) cluster.
+When creating a cluster in GitLab, you are asked if you would like to create either:
-NOTE: **Note:**
-[RBAC](#rbac-cluster-resources) is recommended and the GitLab default.
+- A [Role-based access control (RBAC)](https://kubernetes.io/docs/reference/access-authn-authz/rbac/)
+ cluster, which is the GitLab default and recommended option.
+- An [Attribute-based access control (ABAC)](https://kubernetes.io/docs/reference/access-authn-authz/abac/) cluster.
GitLab creates the necessary service accounts and privileges to install and run
[GitLab managed applications](index.md#installing-applications). When GitLab creates the cluster,
a `gitlab` service account with `cluster-admin` privileges is created in the `default` namespace
to manage the newly created cluster.
-NOTE: **Note:**
-Restricted service account for deployment was [introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/51716) in GitLab 11.5.
-
The first time you install an application into your cluster, the `tiller` service
account is created with `cluster-admin` privileges in the
-`gitlab-managed-apps` namespace. This service account will be used by Helm to
+`gitlab-managed-apps` namespace. This service account is used by Helm to
install and run [GitLab managed applications](index.md#installing-applications).
-Helm will also create additional service accounts and other resources for each
+Helm also creates additional service accounts and other resources for each
installed application. Consult the documentation of the Helm charts for each application
for details.
@@ -77,7 +77,7 @@ Note the following about access controls:
- Environment-specific resources are only created if your cluster is
[managed by GitLab](index.md#gitlab-managed-clusters).
-- If your cluster was created before GitLab 12.2, it will use a single namespace for all project
+- If your cluster was created before GitLab 12.2, it uses a single namespace for all project
environments.
### RBAC cluster resources
@@ -151,11 +151,12 @@ Amazon Elastic Kubernetes Service (EKS) at the project, group, or instance level
## Add existing cluster
-If you have an existing Kubernetes cluster, you can add it to a project, group, or instance.
+If you have an existing Kubernetes cluster, you can add it to a project, group,
+or instance.
-NOTE: **Note:**
-Kubernetes integration is not supported for arm64 clusters. See the issue
-[Helm Tiller fails to install on arm64 cluster](https://gitlab.com/gitlab-org/gitlab/-/issues/29838) for details.
+Kubernetes integration isn't supported for arm64 clusters. See the issue
+[Helm Tiller fails to install on arm64 cluster](https://gitlab.com/gitlab-org/gitlab/-/issues/29838)
+for details.
### Existing Kubernetes cluster
@@ -181,7 +182,7 @@ To add a Kubernetes cluster to your project, group, or instance:
kubectl cluster-info | grep 'Kubernetes master' | awk '/http/ {print $NF}'
```
- 1. **CA certificate** (required) - A valid Kubernetes certificate is needed to authenticate to the cluster. We will use the certificate created by default.
+ 1. **CA certificate** (required) - A valid Kubernetes certificate is needed to authenticate to the cluster. We use the certificate created by default.
1. List the secrets with `kubectl get secrets`, and one should be named similar to
`default-token-xxxxx`. Copy that token name for use below.
1. Get the certificate by running this command:
@@ -190,9 +191,20 @@ To add a Kubernetes cluster to your project, group, or instance:
kubectl get secret <secret name> -o jsonpath="{['data']['ca\.crt']}" | base64 --decode
```
- NOTE: **Note:**
- If the command returns the entire certificate chain, you need copy the *root ca*
- certificate at the bottom of the chain.
+ If the command returns the entire certificate chain, you must copy the Root CA
+ certificate and any intermediate certificates at the bottom of the chain.
+ A chain file has following structure:
+
+ ```plaintext
+ -----BEGIN MY CERTIFICATE-----
+ -----END MY CERTIFICATE-----
+ -----BEGIN INTERMEDIATE CERTIFICATE-----
+ -----END INTERMEDIATE CERTIFICATE-----
+ -----BEGIN INTERMEDIATE CERTIFICATE-----
+ -----END INTERMEDIATE CERTIFICATE-----
+ -----BEGIN ROOT CERTIFICATE-----
+ -----END ROOT CERTIFICATE-----
+ ```
1. **Token** -
GitLab authenticates against Kubernetes using service tokens, which are
@@ -229,10 +241,10 @@ To add a Kubernetes cluster to your project, group, or instance:
kubectl apply -f gitlab-admin-service-account.yaml
```
- You will need the `container.clusterRoleBindings.create` permission
+ You need the `container.clusterRoleBindings.create` permission
to create cluster-level roles. If you do not have this permission,
you can alternatively enable Basic Authentication and then run the
- `kubectl apply` command as an admin:
+ `kubectl apply` command as an administrator:
```shell
kubectl apply -f gitlab-admin-service-account.yaml --username=admin --password=<password>
@@ -257,7 +269,7 @@ To add a Kubernetes cluster to your project, group, or instance:
Copy the `<authentication_token>` value from the output:
- ```yaml
+ ```plaintext
Name: gitlab-token-b5zv4
Namespace: kube-system
Labels: <none>
@@ -274,7 +286,7 @@ To add a Kubernetes cluster to your project, group, or instance:
```
NOTE: **Note:**
- For GKE clusters, you will need the
+ For GKE clusters, you need the
`container.clusterRoleBindings.create` permission to create a cluster
role binding. You can follow the [Google Cloud
documentation](https://cloud.google.com/iam/docs/granting-changing-revoking-access)
@@ -283,7 +295,7 @@ To add a Kubernetes cluster to your project, group, or instance:
1. **GitLab-managed cluster** - Leave this checked if you want GitLab to manage namespaces and service accounts for this cluster.
See the [Managed clusters section](index.md#gitlab-managed-clusters) for more information.
1. **Project namespace** (optional) - You don't have to fill it in; by leaving
- it blank, GitLab will create one for you. Also:
+ it blank, GitLab creates one for you. Also:
- Each project should have a unique namespace.
- The project namespace is not necessarily the namespace of the secret, if
you're using a secret with broader permissions, like the secret from `default`.
@@ -294,21 +306,21 @@ To add a Kubernetes cluster to your project, group, or instance:
1. Finally, click the **Create Kubernetes cluster** button.
-After a couple of minutes, your cluster will be ready to go. You can now proceed
+After a couple of minutes, your cluster is ready. You can now proceed
to install some [pre-defined applications](index.md#installing-applications).
#### Disable Role-Based Access Control (RBAC) (optional)
When connecting a cluster via GitLab integration, you may specify whether the
-cluster is RBAC-enabled or not. This will affect how GitLab interacts with the
+cluster is RBAC-enabled or not. This affects how GitLab interacts with the
cluster for certain operations. If you did *not* check the **RBAC-enabled cluster**
-checkbox at creation time, GitLab will assume RBAC is disabled for your cluster
+checkbox at creation time, GitLab assumes RBAC is disabled for your cluster
when interacting with it. If so, you must disable RBAC on your cluster for the
integration to work properly.
-![rbac](img/rbac_v13_1.png)
+![RBAC](img/rbac_v13_1.png)
-NOTE: **Note:**
+CAUTION: **Caution:**
Disabling RBAC means that any application running in the cluster,
or user who can authenticate to the cluster, has full API access. This is a
[security concern](index.md#security-implications), and may not be desirable.
@@ -356,3 +368,12 @@ When removing the cluster integration, note:
To learn more on automatically deploying your applications,
read about [Auto DevOps](../../../topics/autodevops/index.md).
+
+## Troubleshooting
+
+### There was a problem authenticating with your cluster. Please ensure your CA Certificate and Token are valid
+
+If you encounter this error while adding a Kubernetes cluster, ensure you're
+properly pasting the service token. Some shells may add a line break to the
+service token, making it invalid. Ensure that there are no line breaks by
+pasting your token into an editor and removing any additional spaces.
diff --git a/doc/user/project/clusters/index.md b/doc/user/project/clusters/index.md
index 8d188f00ceb..459ba144186 100644
--- a/doc/user/project/clusters/index.md
+++ b/doc/user/project/clusters/index.md
@@ -1,6 +1,6 @@
---
stage: Monitor
-group: APM
+group: Health
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/#designated-technical-writers
---
@@ -12,8 +12,6 @@ info: To determine the technical writer assigned to the Stage/Group associated w
> - [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/39840) in
> GitLab 11.11 for [instances](../../instance/clusters/index.md).
-## Overview
-
Using the GitLab project Kubernetes integration, you can:
- Use [Review Apps](../../../ci/review_apps/index.md).
@@ -31,6 +29,11 @@ Besides integration at the project level, Kubernetes clusters can also be
integrated at the [group level](../../group/clusters/index.md) or
[GitLab instance level](../../instance/clusters/index.md).
+To view your project level Kubernetes clusters, navigate to **Operations > Kubernetes**
+from your project. On this page, you can [add a new cluster](#adding-and-removing-clusters)
+and view information about your existing clusters, such as nodes count and rough estimates
+of memory and CPU usage.
+
## Setting up
### Supported cluster versions
@@ -49,10 +52,9 @@ Currently, GitLab supports the following Kubernetes versions:
- 1.17
- 1.16
- 1.15
-- 1.14
+- 1.14 (deprecated, support ends on December 22, 2020)
- 1.13 (deprecated, support ends on November 22, 2020)
-NOTE: **Note:**
Some GitLab features may support versions outside the range provided here.
### Adding and removing clusters
@@ -192,7 +194,6 @@ To clear the cache:
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/24580) in GitLab 11.8.
-NOTE: **Note:**
You do not need to specify a base domain on cluster settings when using GitLab Serverless. The domain in that case
will be specified as part of the Knative installation. See [Installing Applications](#installing-applications).
@@ -220,13 +221,11 @@ Auto DevOps automatically detects, builds, tests, deploys, and monitors your
applications.
To make full use of Auto DevOps (Auto Deploy, Auto Review Apps, and
-Auto Monitoring) you will need the Kubernetes project integration enabled.
+Auto Monitoring) you will need the Kubernetes project integration enabled, but
+Kubernetes clusters can be used without Auto DevOps.
[Read more about Auto DevOps](../../../topics/autodevops/index.md)
-NOTE: **Note:**
-Kubernetes clusters can be used without Auto DevOps.
-
## Deploying to a Kubernetes cluster
A Kubernetes cluster can be the destination for a deployment job. If
@@ -249,36 +248,51 @@ GitLab CI/CD build environment.
| Variable | Description |
| -------- | ----------- |
| `KUBE_URL` | Equal to the API URL. |
-| `KUBE_TOKEN` | The Kubernetes token of the [environment service account](add_remove_clusters.md#access-controls). |
-| `KUBE_NAMESPACE` | The namespace associated with the project's deployment service account. In the format `<project_name>-<project_id>-<environment>`. For GitLab-managed clusters, a matching namespace is automatically created by GitLab in the cluster. |
+| `KUBE_TOKEN` | The Kubernetes token of the [environment service account](add_remove_clusters.md#access-controls). Prior to GitLab 11.5, `KUBE_TOKEN` was the Kubernetes token of the main service account of the cluster integration. |
+| `KUBE_NAMESPACE` | The namespace associated with the project's deployment service account. In the format `<project_name>-<project_id>-<environment>`. For GitLab-managed clusters, a matching namespace is automatically created by GitLab in the cluster. If your cluster was created before GitLab 12.2, the default `KUBE_NAMESPACE` is set to `<project_name>-<project_id>`. |
| `KUBE_CA_PEM_FILE` | Path to a file containing PEM data. Only present if a custom CA bundle was specified. |
| `KUBE_CA_PEM` | (**deprecated**) Raw PEM data. Only if a custom CA bundle was specified. |
-| `KUBECONFIG` | Path to a file containing `kubeconfig` for this deployment. CA bundle would be embedded if specified. This config also embeds the same token defined in `KUBE_TOKEN` so you likely will only need this variable. This variable name is also automatically picked up by `kubectl` so you won't actually need to reference it explicitly if using `kubectl`. |
+| `KUBECONFIG` | Path to a file containing `kubeconfig` for this deployment. CA bundle would be embedded if specified. This configuration also embeds the same token defined in `KUBE_TOKEN` so you likely will only need this variable. This variable name is also automatically picked up by `kubectl` so you won't actually need to reference it explicitly if using `kubectl`. |
| `KUBE_INGRESS_BASE_DOMAIN` | From GitLab 11.8, this variable can be used to set a domain per cluster. See [cluster domains](#base-domain) for more information. |
-NOTE: **Note:**
-Prior to GitLab 11.5, `KUBE_TOKEN` was the Kubernetes token of the main
-service account of the cluster integration.
-
-NOTE: **Note:**
-If your cluster was created before GitLab 12.2, default `KUBE_NAMESPACE` will be set to `<project_name>-<project_id>`.
-
### Custom namespace
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/27630) in GitLab 12.6.
-
-The Kubernetes integration defaults to project-environment-specific namespaces
-of the form `<project_name>-<project_id>-<environment>` (see [Deployment
-variables](#deployment-variables)).
-
-For **non**-GitLab-managed clusters, the namespace can be customized using
-[`environment:kubernetes:namespace`](../../../ci/environments/index.md#configuring-kubernetes-deployments)
-in `.gitlab-ci.yml`.
-
-NOTE: **Note:**
-When using a [GitLab-managed cluster](#gitlab-managed-clusters), the
-namespaces are created automatically prior to deployment and [can not be
-customized](https://gitlab.com/gitlab-org/gitlab/-/issues/38054).
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/27630) in GitLab 12.6.
+> - An option to use project-wide namespaces [was added](https://gitlab.com/gitlab-org/gitlab/-/issues/38054) in GitLab 13.5.
+
+The Kubernetes integration provides a `KUBECONFIG` with an auto-generated namespace
+to deployment jobs. It defaults to using project-environment specific namespaces
+of the form `<prefix>-<environment>`, where `<prefix>` is of the form
+`<project_name>-<project_id>`. To learn more, read [Deployment variables](#deployment-variables).
+
+You can customize the deployment namespace in a few ways:
+
+- You can choose between a **namespace per [environment](../../../ci/environments/index.md)**
+ or a **namespace per project**. A namespace per environment is the default and recommended
+ setting, as it prevents the mixing of resources between production and non-production environments.
+- When using a project-level cluster, you can additionally customize the namespace prefix.
+ When using namespace-per-environment, the deployment namespace is `<prefix>-<environment>`,
+ but otherwise just `<prefix>`.
+- For **non-managed** clusters, the auto-generated namespace is set in the `KUBECONFIG`,
+ but the user is responsible for ensuring its existence. You can fully customize
+ this value using
+ [`environment:kubernetes:namespace`](../../../ci/environments/index.md#configuring-kubernetes-deployments)
+ in `.gitlab-ci.yml`.
+
+When you customize the namespace, existing environments remain linked to their current
+namespaces until you [clear the cluster cache](#clearing-the-cluster-cache).
+
+CAUTION: **Warning:**
+By default, anyone who can create a deployment job can access any CI variable within
+an environment's deployment job. This includes `KUBECONFIG`, which gives access to
+any secret available to the associated service account in your cluster.
+To keep your production credentials safe, consider using
+[Protected Environments](../../../ci/environments/protected_environments.md),
+combined with either
+
+- a GitLab-managed cluster and namespace per environment,
+- *or*, an environment-scoped cluster per protected environment. The same cluster
+ can be added multiple times with multiple restricted service accounts.
### Integrations
diff --git a/doc/user/project/clusters/kubernetes_pod_logs.md b/doc/user/project/clusters/kubernetes_pod_logs.md
index afb6d016f45..2e224208eb8 100644
--- a/doc/user/project/clusters/kubernetes_pod_logs.md
+++ b/doc/user/project/clusters/kubernetes_pod_logs.md
@@ -1,6 +1,6 @@
---
stage: Monitor
-group: APM
+group: Health
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/#designated-technical-writers
---
@@ -28,7 +28,6 @@ above the log file data, depending on your configuration:
<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
To learn more about the Log Explorer, see [APM - Log Explorer](https://www.youtube.com/watch?v=hWclZHA7Dgw).
-NOTE: **Note:**
[Learn more about Kubernetes + GitLab](https://about.gitlab.com/solutions/kubernetes/).
Everything you need to build, test, deploy, and run your application at scale.
diff --git a/doc/user/project/clusters/runbooks/index.md b/doc/user/project/clusters/runbooks/index.md
index 360b02efb69..c1e4e821efd 100644
--- a/doc/user/project/clusters/runbooks/index.md
+++ b/doc/user/project/clusters/runbooks/index.md
@@ -115,9 +115,7 @@ the components outlined above and the pre-loaded demo runbook.
VARIABLE_VALUE = project.variables.get('PRIVATE_TOKEN').value
```
-1. To configure the operation of a runbook, create and configure variables:
-
- NOTE: **Note:**
+1. To configure the operation of a runbook, create and configure variables.
For this example, we are using the **Run SQL queries in Notebook** section in the
sample runbook to query a PostgreSQL database. The first four lines of the following
code block define the variables that are required for this query to function:
diff --git a/doc/user/project/clusters/securing.md b/doc/user/project/clusters/securing.md
index a15660051f7..bed01ff4d58 100644
--- a/doc/user/project/clusters/securing.md
+++ b/doc/user/project/clusters/securing.md
@@ -85,7 +85,7 @@ Host Security (Falco) are deployed with this model.
To deploy GitLab Managed Apps to your cluster, you must first
[add your cluster](add_remove_clusters.md)
-to GitLab. Then [install](../../clusters/applications.md#installing-applications)
+to GitLab. Then [install](../../clusters/applications.md#install-with-one-click)
the Web Application Firewall from the project or group Kubernetes page.
Note that your project doesn't have to be hosted or deployed through GitLab. You can manage a
diff --git a/doc/user/project/clusters/serverless/aws.md b/doc/user/project/clusters/serverless/aws.md
index 543ffdbce8f..db91f78fc20 100644
--- a/doc/user/project/clusters/serverless/aws.md
+++ b/doc/user/project/clusters/serverless/aws.md
@@ -136,8 +136,8 @@ This example code does the following:
In order to interact with your AWS account, the GitLab CI/CD pipelines require both `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` to be defined in your GitLab settings under **Settings > CI/CD > Variables**.
For more information please see [Create a custom variable in the UI](../../../../ci/variables/README.md#create-a-custom-variable-in-the-ui).
-NOTE: **Note:**
- The AWS credentials you provide must include IAM policies that provision correct access control to AWS Lambda, API Gateway, CloudFormation, and IAM resources.
+ The AWS credentials you provide must include IAM policies that provision correct
+ access control to AWS Lambda, API Gateway, CloudFormation, and IAM resources.
#### Deploying your function
@@ -154,9 +154,7 @@ endpoints:
#### Manually testing your function
Running the following `curl` command should trigger your function.
-
-NOTE: **Note:**
-Your URL should be the one retrieved from the GitLab deploy stage log.
+Your URL should be the one retrieved from the GitLab deploy stage log:
```shell
curl https://u768nzby1j.execute-api.us-east-1.amazonaws.com/production/hello
@@ -222,7 +220,8 @@ the environment of the deployed function:
```yaml
provider:
- ...
+ # Other configuration omitted
+ # ...
environment:
A_VARIABLE: ${env:A_VARIABLE}
```
@@ -245,10 +244,10 @@ functions:
hello:
handler: src/handler.hello
events:
- - http: # Rewrite this part to enable CORS
+ - http: # Rewrite this part to enable CORS
path: hello
method: get
- cors: true # <-- CORS here
+ cors: true # <-- CORS here
```
You also need to return CORS specific headers in your function response:
@@ -378,7 +377,6 @@ To set these:
`AWS_SECRET_ACCESS_KEY`.
1. Mask the credentials so they do not show in logs using the **Masked** toggle.
-NOTE: **Note:**
The AWS credentials you provide must include IAM policies that provision correct access
control to AWS Lambda, API Gateway, CloudFormation, and IAM resources.
diff --git a/doc/user/project/clusters/serverless/index.md b/doc/user/project/clusters/serverless/index.md
index 1157c2c5632..603c4bd73b1 100644
--- a/doc/user/project/clusters/serverless/index.md
+++ b/doc/user/project/clusters/serverless/index.md
@@ -75,8 +75,8 @@ To run Knative on GitLab, you will need:
## Installing Knative via GitLab's Kubernetes integration
-NOTE: **Note:**
-The minimum recommended cluster size to run Knative is 3-nodes, 6 vCPUs, and 22.50 GB memory. **RBAC must be enabled.**
+The minimum recommended cluster size to run Knative is 3-nodes, 6 vCPUs, and 22.50 GB
+memory. **RBAC must be enabled.**
1. [Add a Kubernetes cluster](../add_remove_clusters.md).
1. Select the **Applications** tab and scroll down to the Knative app section. Enter the domain to be used with
@@ -99,22 +99,19 @@ The minimum recommended cluster size to run Knative is 3-nodes, 6 vCPUs, and 22.
![DNS entry](img/dns-entry.png)
-NOTE: **Note:**
You can deploy either [functions](#deploying-functions) or [serverless applications](#deploying-serverless-applications)
-on a given project but not both. The current implementation makes use of a `serverless.yml` file to signal a FaaS project.
+on a given project, but not both. The current implementation makes use of a
+`serverless.yml` file to signal a FaaS project.
## Using an existing installation of Knative
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/58941) in GitLab 12.0.
-NOTE: **Note:**
-The "invocations" monitoring feature of GitLab serverless will not work when
+The _invocations_ monitoring feature of GitLab serverless won't work when
adding an existing installation of Knative.
-It is also possible to use GitLab Serverless with an existing Kubernetes
-cluster which already has Knative installed.
-
-You must do the following:
+It's also possible to use GitLab Serverless with an existing Kubernetes cluster
+which already has Knative installed. You must do the following:
1. Follow the steps to
[add an existing Kubernetes
@@ -453,16 +450,16 @@ To run a function locally:
> Introduced in GitLab 11.5.
+12345678901234567890123456789012345678901234567890123456789012345678901234567890
Serverless applications are an alternative to [serverless functions](#deploying-functions).
-They are useful in scenarios where an existing runtime does not meet the needs of an application,
-such as one written in a language that has no runtime available. Note though that serverless
-applications should be stateless!
-
-NOTE: **Note:**
-You can reference and import the sample [Knative Ruby App](https://gitlab.com/knative-examples/knative-ruby-app) to get started.
+They're useful in scenarios where an existing runtime does not meet the needs of
+an application, such as one written in a language that has no runtime available.
+Note though that serverless applications should be stateless.
-Add the following `.gitlab-ci.yml` to the root of your repository
-(you may skip this step if you've previously cloned the sample [Knative Ruby App](https://gitlab.com/knative-examples/knative-ruby-app) mentioned above):
+You can reference and import the sample [Knative Ruby App](https://gitlab.com/knative-examples/knative-ruby-app)
+to get started. Add the following `.gitlab-ci.yml` to the root of your repository
+(you may skip this step if you've previously cloned the previously mentioned,
+sample [Knative Ruby App](https://gitlab.com/knative-examples/knative-ruby-app)):
```yaml
include:
@@ -561,14 +558,18 @@ Or:
## Enabling TLS for Knative services
-By default, a GitLab serverless deployment will be served over `http`. In order to serve over `https` you
-must manually obtain and install TLS certificates.
+By default, a GitLab serverless deployment will be served over `http`. To serve
+over `https`, you must manually obtain and install TLS certificates.
-The simplest way to accomplish this is to
-use [Certbot to manually obtain Let's Encrypt certificates](https://knative.dev/docs/serving/using-a-tls-cert/#using-certbot-to-manually-obtain-let-s-encrypt-certificates). Certbot is a free, open source software tool for automatically using Let’s Encrypt certificates on manually-administrated websites to enable HTTPS.
+12345678901234567890123456789012345678901234567890123456789012345678901234567890
+The simplest way to accomplish this is to use Certbot to
+[manually obtain Let's Encrypt certificates](https://knative.dev/docs/serving/using-a-tls-cert/#using-certbot-to-manually-obtain-let-s-encrypt-certificates).
+Certbot is a free, open source software tool for automatically using Let’s Encrypt
+certificates on manually-administered websites to enable HTTPS.
-NOTE: **Note:**
-The instructions below relate to installing and running Certbot on a Linux server that has Python 3 installed and may not work on other operating systems or with other versions of Python.
+The following instructions relate to installing and running Certbot on a Linux
+server that has Python 3 installed, and may not work on other operating systems
+or with other versions of Python.
1. Install Certbot by running the
[`certbot-auto` wrapper script](https://certbot.eff.org/docs/install.html#certbot-auto).
@@ -788,7 +789,7 @@ The instructions below relate to installing and running Certbot on a Linux serve
kubectl edit gateway knative-ingress-gateway --namespace knative-serving
```
- Update the gateway to include the following tls: section and configuration:
+ Update the gateway to include the following `tls:` section and configuration:
```shell
tls:
diff --git a/doc/user/project/code_intelligence.md b/doc/user/project/code_intelligence.md
index f56673e69b7..d0c5a24826a 100644
--- a/doc/user/project/code_intelligence.md
+++ b/doc/user/project/code_intelligence.md
@@ -58,9 +58,9 @@ relevant language.
| Language | Implementation |
|---|---|
-| Go | [sourcegraph/lsif-go](https://github.com/sourcegraph/lsif-go) |
-| JavaScript | [sourcegraph/lsif-node](https://github.com/sourcegraph/lsif-node) |
-| TypeScript | [sourcegraph/lsif-node](https://github.com/sourcegraph/lsif-node) |
+| Go | [`sourcegraph/lsif-go`](https://github.com/sourcegraph/lsif-go) |
+| JavaScript | [`sourcegraph/lsif-node`](https://github.com/sourcegraph/lsif-node) |
+| TypeScript | [`sourcegraph/lsif-node`](https://github.com/sourcegraph/lsif-node) |
View a complete list of [available LSIF indexers](https://lsif.dev/#implementations-server) on their website and
refer to their documentation to see how to generate an LSIF file for your specific language.
diff --git a/doc/user/project/code_owners.md b/doc/user/project/code_owners.md
index 730a9ada428..4ae3d5ec032 100644
--- a/doc/user/project/code_owners.md
+++ b/doc/user/project/code_owners.md
@@ -75,7 +75,6 @@ be used for merge request approvals:
- As [merge request eligible approvers](merge_requests/merge_request_approvals.md#code-owners-as-eligible-approvers).
- As required approvers for [protected branches](protected_branches.md#protected-branches-approval-by-code-owners). **(PREMIUM)**
-NOTE: **Note:**
Developer or higher [permissions](../permissions.md) are required in order to
approve a merge request.
@@ -93,12 +92,14 @@ to specify the actual owners and granular permissions.
Using Code Owners in conjunction with [Protected Branches](protected_branches.md#protected-branches-approval-by-code-owners)
will prevent any user who is not specified in the `CODEOWNERS` file from pushing
-changes for the specified files/paths, even if their role is included in the
+changes for the specified files/paths, except those included in the
**Allowed to push** column. This allows for a more inclusive push strategy, as
administrators don't have to restrict developers from pushing directly to the
protected branch, but can restrict pushing to certain files where a review by
Code Owners is required.
+[Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/35097) in [GitLab Premium](https://about.gitlab.com/pricing/) 13.5, users and groups who are allowed to push to protected branches do not require a merge request to merge their feature branches. Thus, they can skip merge request approval rules, Code Owners included.
+
## The syntax of Code Owners files
Files can be specified using the same kind of patterns you would use
@@ -158,7 +159,7 @@ file.md @group-x @group-x/subgroup-y
### Code Owners Sections **(PREMIUM)**
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/12137) in [GitLab Premium](https://about.gitlab.com/pricing/) 13.2 behind a feature flag, enabled by default.
-> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/42389) in GitLab 13.4.
+> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/42389) in GitLab 13.4.
Code Owner rules can be grouped into named sections. This allows for better
organization of broader categories of Code Owner rules to be applied.
diff --git a/doc/user/project/deploy_boards.md b/doc/user/project/deploy_boards.md
index 8146f39ef87..3c6494d5f1a 100644
--- a/doc/user/project/deploy_boards.md
+++ b/doc/user/project/deploy_boards.md
@@ -85,7 +85,7 @@ To display the Deploy Boards for a specific [environment](../../ci/environments/
[`kubernetes`](https://docs.gitlab.com/runner/executors/kubernetes.html) executor.
1. Configure the [Kubernetes integration](clusters/index.md) in your project for the
cluster. The Kubernetes namespace is of particular note as you will need it
- for your deployment scripts (exposed by the `KUBE_NAMESPACE` env variable).
+ for your deployment scripts (exposed by the `KUBE_NAMESPACE` environment variable).
1. Ensure Kubernetes annotations of `app.gitlab.com/env: $CI_ENVIRONMENT_SLUG`
and `app.gitlab.com/app: $CI_PROJECT_PATH_SLUG` are applied to the
deployments, replica sets, and pods, where `$CI_ENVIRONMENT_SLUG` and
@@ -106,7 +106,7 @@ To display the Deploy Boards for a specific [environment](../../ci/environments/
be done automatically and no action is necessary.
If you are using GCP to manage clusters, you can see the deployment details in GCP itself by going to **Workloads > deployment name > Details**:
-
+
![Deploy Boards Kubernetes Label](img/deploy_boards_kubernetes_label.png)
Once all of the above are set up and the pipeline has run at least once,
diff --git a/doc/user/project/deploy_keys/index.md b/doc/user/project/deploy_keys/index.md
index 81c9008c5b3..4f344554016 100644
--- a/doc/user/project/deploy_keys/index.md
+++ b/doc/user/project/deploy_keys/index.md
@@ -12,7 +12,7 @@ more repositories, by importing an SSH public key to your GitLab instance.
This is useful for cloning repositories to your Continuous
Integration (CI) server. By using deploy keys, you don't have to set up a
-dummy user account.
+fake user account.
There are two types of deploy keys:
diff --git a/doc/user/project/description_templates.md b/doc/user/project/description_templates.md
index aa5987bf5f9..e0c4097d1c5 100644
--- a/doc/user/project/description_templates.md
+++ b/doc/user/project/description_templates.md
@@ -49,8 +49,8 @@ To create a Markdown file:
1. Click the `+` button next to `master` and click **New file**.
1. Add the name of your issue template to the **File name** text field next to `master`.
- Make sure words are separated with underscores and that your file has the `.md` extension, for
- example `feature_request.md`.
+ Make sure that your file has the `.md` extension, for
+ example `feature_request.md` or `Feature Request.md`.
1. Commit and push to your default branch.
If you don't have a `.gitlab/issue_templates` directory in your repository, you'll need to create it.
@@ -79,6 +79,9 @@ This will enable the `Bug` dropdown option when creating or editing issues. When
to the issue description field. The 'Reset template' button will discard any
changes you made after picking the template and return it to its initial status.
+TIP: **Tip:**
+You can create short-cut links to create an issue using a designated template. For example: `https://gitlab.com/gitlab-org/gitlab/-/issues/new?issuable_template=Feature%20proposal`.
+
![Description templates](img/description_templates.png)
## Setting a default template for merge requests and issues **(STARTER)**
diff --git a/doc/user/project/file_lock.md b/doc/user/project/file_lock.md
index 6fd33901621..46c2e211d57 100644
--- a/doc/user/project/file_lock.md
+++ b/doc/user/project/file_lock.md
@@ -69,7 +69,7 @@ brew install git-lfs
```
Once installed, **open your local repository in a terminal window** and
-install Git LFS in your repo. If you're sure that LFS is already installed,
+install Git LFS in your repository. If you're sure that LFS is already installed,
you can skip this step. If you're unsure, re-installing it won't do any harm:
```shell
@@ -159,7 +159,7 @@ command line interface, file locks can be created for any file.
### View exclusively-locked files
To list all the files locked with LFS locally, open a terminal window in your
-repo and run:
+repository and run:
```shell
git lfs locks
@@ -189,7 +189,7 @@ Suggested workflow for shared projects:
1. Lock the file.
1. Edit the file.
1. Commit your changes.
-1. Push to the repo.
+1. Push to the repository.
1. Get your changes reviewed, approved, and merged.
1. Unlock the file.
diff --git a/doc/user/project/img/issue_board_default_lists_v13_4.png b/doc/user/project/img/issue_board_default_lists_v13_4.png
new file mode 100644
index 00000000000..23cdc9b4e22
--- /dev/null
+++ b/doc/user/project/img/issue_board_default_lists_v13_4.png
Binary files differ
diff --git a/doc/user/project/img/issue_board_welcome_message.png b/doc/user/project/img/issue_board_welcome_message.png
deleted file mode 100644
index 357dff42488..00000000000
--- a/doc/user/project/img/issue_board_welcome_message.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/project/img/labels_key_value_v12_1.png b/doc/user/project/img/labels_key_value_v12_1.png
deleted file mode 100644
index ccda944a647..00000000000
--- a/doc/user/project/img/labels_key_value_v12_1.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/project/img/labels_key_value_v13_5.png b/doc/user/project/img/labels_key_value_v13_5.png
new file mode 100644
index 00000000000..4264eb3211e
--- /dev/null
+++ b/doc/user/project/img/labels_key_value_v13_5.png
Binary files differ
diff --git a/doc/user/project/img/labels_prioritized_v12_1.png b/doc/user/project/img/labels_prioritized_v12_1.png
deleted file mode 100644
index 512c5d59a5a..00000000000
--- a/doc/user/project/img/labels_prioritized_v12_1.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/project/img/labels_prioritized_v13_5.png b/doc/user/project/img/labels_prioritized_v13_5.png
new file mode 100644
index 00000000000..04ffd67a59f
--- /dev/null
+++ b/doc/user/project/img/labels_prioritized_v13_5.png
Binary files differ
diff --git a/doc/user/project/img/labels_subscriptions_v12_1.png b/doc/user/project/img/labels_subscriptions_v12_1.png
deleted file mode 100644
index fa83b7db414..00000000000
--- a/doc/user/project/img/labels_subscriptions_v12_1.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/project/img/labels_subscriptions_v13_5.png b/doc/user/project/img/labels_subscriptions_v13_5.png
new file mode 100644
index 00000000000..a2a4e9e50cc
--- /dev/null
+++ b/doc/user/project/img/labels_subscriptions_v13_5.png
Binary files differ
diff --git a/doc/user/project/import/bitbucket.md b/doc/user/project/import/bitbucket.md
index 89130d5822f..56266718d12 100644
--- a/doc/user/project/import/bitbucket.md
+++ b/doc/user/project/import/bitbucket.md
@@ -76,6 +76,3 @@ If you've accidentally started the import process with the wrong account, follow
1. Revoke GitLab access to your Bitbucket account, essentially reversing the process in the following procedure: [Import your Bitbucket repositories](#import-your-bitbucket-repositories).
1. Sign out of the Bitbucket account. Follow the procedure linked from the previous step.
-
-NOTE: **Note:**
-To import a repository including LFS objects from a Bitbucket server repository, use the [Repo by URL](../import/repo_by_url.md) importer.
diff --git a/doc/user/project/import/bitbucket_server.md b/doc/user/project/import/bitbucket_server.md
index d0499730bfe..ac5be2b46a4 100644
--- a/doc/user/project/import/bitbucket_server.md
+++ b/doc/user/project/import/bitbucket_server.md
@@ -37,12 +37,7 @@ Import your projects from Bitbucket Server to GitLab with minimal effort.
empty changes.
1. Attachments in Markdown are currently not imported.
1. Task lists are not imported.
-1. Emoji reactions are not imported.
-1. [LFS objects](../../../topics/git/lfs/index.md) are not imported.
-
- NOTE: **Note:**
- To import a repository including LFS objects from a Bitbucket server repository, use the [Repo by URL](../import/repo_by_url.md) importer.
-
+1. Emoji reactions are not imported
1. Project filtering does not support fuzzy search (only `starts with` or `full
match strings` are currently supported)
@@ -69,20 +64,43 @@ namespace that started the import process.
#### User assignment by username
-Alternatively, user assignment by username is available behind a `bitbucket_server_user_mapping_by_username` feature flag.
-The importer will try to find a user in the GitLab user database using author's `username` or `slug` or `displayName`.
-Falls back to author's `email` if user is not found by username.
-Similarly to user assignment by email, if no such user is available, the project creator is set as the author.
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/218609) in GitLab 13.4.
+> - It's [deployed behind a feature flag](../../feature_flags.md), disabled by default.
+> - It's disabled on GitLab.com.
+> - It's not recommended for production use.
+> - To use it in GitLab self-managed instances, ask a GitLab administrator to enable it.
+
+CAUTION: **Warning:**
+This feature might not be available to you. Check the **version history** note above for details.
+
+If you've enabled this feature, the importer tries to find a user in the GitLab user database with
+the author's:
+
+- `username`
+- `slug`
+- `displayName`
+
+If the user is not found by any of these properties, the search falls back to the author's
+`email` address.
-To enable or disable user assignment by username:
+Alternatively, if there is also no email address, the project creator is set as the author.
-Start a [Rails console](../../../administration/troubleshooting/debug.md#starting-a-rails-console-session).
+##### Enable or disable User assignment by username
+
+User assignment by username is under development and not 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
-# Enable
Feature.enable(:bitbucket_server_user_mapping_by_username)
+```
-# Disable
+To disable it:
+
+```ruby
Feature.disable(:bitbucket_server_user_mapping_by_username)
```
diff --git a/doc/user/project/import/gemnasium.md b/doc/user/project/import/gemnasium.md
index f21ec26bdef..2d0caa7d46e 100644
--- a/doc/user/project/import/gemnasium.md
+++ b/doc/user/project/import/gemnasium.md
@@ -96,7 +96,7 @@ back to both GitLab and GitHub when completed.
The mirroring is pull-only by default, so you may create or update the file on
GitHub:
- ![Edit gitlab-ci.yml file](img/gemnasium/edit_gitlab-ci.png)
+ ![Edit YAML file](img/gemnasium/edit_gitlab-ci.png)
1. Once your file has been committed, a new pipeline will be automatically
triggered if your file is valid:
diff --git a/doc/user/project/import/github.md b/doc/user/project/import/github.md
index 4cd0c9e02c7..6c0105aaded 100644
--- a/doc/user/project/import/github.md
+++ b/doc/user/project/import/github.md
@@ -35,25 +35,20 @@ The namespace is a user or group in GitLab, such as `gitlab.com/janedoe` or `git
This process does not migrate or import any types of groups or organizations from GitHub to GitLab.
-### If you're using GitLab.com
+### Use cases
-If you're using GitLab.com, you can alternatively import
-GitHub repositories using a [personal access token](#using-a-github-token),
-but we don't recommend this method because it can't associate all user activity
-(such as issues and pull requests) with matching GitLab users.
+The steps you take depend on whether you are importing from GitHub.com or GitHub Enterprise, as well as whether you are importing to GitLab.com or self-managed GitLab instance.
-### If you're importing from GitLab Enterprise
-
-If you're importing from GitHub Enterprise, you must enable [GitHub integration][gh-import].
-
-### If you're using a self-managed GitLab instance
-
-If you're an administrator of a self-managed GitLab instance, you must enable
-[GitHub integration][gh-import].
-
-If you're an administrator of a self-managed GitLab instance, you can also use the
-[GitHub Rake task](../../../administration/raketasks/github_import.md) to import projects from
-GitHub without the constraints of a Sidekiq worker.
+- If you're importing to GitLab.com, you can alternatively import GitHub repositories
+ using a [personal access token](#using-a-github-token). We do not recommend
+ this method, as it does not associate all user activity (such as issues and
+ pull requests) with matching GitLab users.
+- If you're importing to a self-managed GitLab instance, you can alternatively use the
+ [GitHub Rake task](../../../administration/raketasks/github_import.md) to import
+ projects without the constraints of a [Sidekiq](../../../development/sidekiq_style_guide.md) worker.
+- If you're importing from GitHub Enterprise to your self-managed GitLab instance, you must first enable
+ [GitHub integration](../../../integration/github.md). However, you cannot import projects from GitHub Enterprise to GitLab.com.
+- If you're importing from GitHub.com to your self-managed GitLab instance, you do not need to set up GitHub integration.
## How it works
@@ -106,7 +101,7 @@ If you are using a self-managed GitLab instance or if you are importing from Git
1. From the top navigation bar, click **+** and select **New project**.
1. Select the **Import project** tab and then select **GitHub**.
1. Select the first button to **List your GitHub repositories**. You are redirected to a page on [GitHub](https://github.com) to authorize the GitLab application.
-1. Click **Authorize gitlabhq**. You are redirected back to GitLab's Import page and all of your GitHub repositories are listed.
+1. Click **Authorize GitlabHQ**. You are redirected back to GitLab's Import page and all of your GitHub repositories are listed.
1. Continue on to [selecting which repositories to import](#selecting-which-repositories-to-import).
### Using a GitHub token
@@ -124,7 +119,7 @@ If you are not using the GitHub integration, you can still perform an authorizat
1. Go to <https://github.com/settings/tokens/new>
1. Enter a token description.
-1. Select the repo scope.
+1. Select the repository scope.
1. Click **Generate token**.
1. Copy the token hash.
1. Go back to GitLab and provide the token to the GitHub importer.
@@ -141,10 +136,10 @@ your GitHub repositories are listed.
1. Select the **Import** button next to any number of repositories, or select **Import all repositories**. Additionally,
you can filter projects by name. If filter is applied, **Import all repositories** only imports matched repositories.
1. The **Status** column shows the import status of each repository. You can choose to leave the page open and it will
- update in realtime or you can return to it later.
+ update in real-time or you can return to it later.
1. Once a repository has been imported, click its GitLab path to open its GitLab URL.
-![Github importer page](img/import_projects_from_github_importer_v12_3.png)
+![GitHub importer page](img/import_projects_from_github_importer_v12_3.png)
## Mirroring and pipeline status sharing
@@ -154,7 +149,7 @@ your imported repository in sync with its GitHub copy.
Additionally, you can configure GitLab to send pipeline status updates back GitHub with the
[GitHub Project Integration](../integrations/github.md). **(PREMIUM)**
-If you import your project using [CI/CD for external repo](../../../ci/ci_cd_for_external_repos/index.md), then both
+If you import your project using [CI/CD for external repository](../../../ci/ci_cd_for_external_repos/index.md), then both
of the above are automatically configured. **(PREMIUM)**
## Improving the speed of imports on self-managed instances
diff --git a/doc/user/project/import/img/manifest_status_v13_3.png b/doc/user/project/import/img/manifest_status_v13_3.png
index 3f0063e6715..c1a55ba1f50 100644
--- a/doc/user/project/import/img/manifest_status_v13_3.png
+++ b/doc/user/project/import/img/manifest_status_v13_3.png
Binary files differ
diff --git a/doc/user/project/import/index.md b/doc/user/project/import/index.md
index 86b671c8371..a1c28cfa2b7 100644
--- a/doc/user/project/import/index.md
+++ b/doc/user/project/import/index.md
@@ -18,7 +18,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
1. [From Perforce](perforce.md)
1. [From SVN](svn.md)
1. [From TFVC](tfvc.md)
-1. [From repo by URL](repo_by_url.md)
+1. [From repository by URL](repo_by_url.md)
1. [By uploading a manifest file (AOSP)](manifest.md)
1. [From Gemnasium](gemnasium.md)
1. [From Phabricator](phabricator.md)
@@ -32,7 +32,7 @@ There is also the option of [connecting your external repository to get CI/CD be
## Migrating from self-managed GitLab to GitLab.com
-If you only need to migrate Git repos, you can [import each project by URL](repo_by_url.md). Issues and merge requests can't be imported.
+If you only need to migrate Git repositories, you can [import each project by URL](repo_by_url.md). Issues and merge requests can't be imported.
If you want to retain all metadata like issues and merge requests, you can use
the [import/export feature](../settings/import_export.md) to export projects from self-managed GitLab and import those projects into GitLab.com.
diff --git a/doc/user/project/import/manifest.md b/doc/user/project/import/manifest.md
index 60524f3cc69..ba1e2011d08 100644
--- a/doc/user/project/import/manifest.md
+++ b/doc/user/project/import/manifest.md
@@ -56,7 +56,7 @@ You can start the import with:
1. From your GitLab dashboard click **New project**
1. Switch to the **Import project** tab
1. Click on the **Manifest file** button
-1. Provide GitLab with a manifest xml file
+1. Provide GitLab with a manifest XML file
1. Select a group you want to import to (you need to create a group first if you don't have one)
1. Click **List available repositories**. At this point, you will be redirected
to the import status page with projects list based on the manifest file.
diff --git a/doc/user/project/import/perforce.md b/doc/user/project/import/perforce.md
index dbc1c491493..4ccc34efe30 100644
--- a/doc/user/project/import/perforce.md
+++ b/doc/user/project/import/perforce.md
@@ -20,7 +20,7 @@ Git:
it creates an integration record in their proprietary database for every file
in the branch, regardless how many were actually changed. Whereas Git was
implemented with a different architecture so that a single SHA acts as a pointer
- to the state of the whole repo after the changes, making it very easy to branch.
+ to the state of the whole repository after the changes, making it very easy to branch.
This is what made feature branching workflows so easy to adopt with Git.
1. Also, context switching between branches is much easier in Git. If your manager
said 'You need to stop work on that new feature and fix this security
diff --git a/doc/user/project/import/repo_by_url.md b/doc/user/project/import/repo_by_url.md
index 9b5e43aae79..5c53b6eaf06 100644
--- a/doc/user/project/import/repo_by_url.md
+++ b/doc/user/project/import/repo_by_url.md
@@ -5,7 +5,7 @@ group: Import
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/#designated-technical-writers
---
-# Import project from repo by URL
+# Import project from repository by URL
You can import your existing repositories by providing the Git URL:
@@ -16,4 +16,4 @@ You can import your existing repositories by providing the Git URL:
1. Click **Create project** to begin the import process
1. Once complete, you will be redirected to your newly created project
-![Import project by repo URL](img/import_projects_from_repo_url.png)
+![Import project by repository URL](img/import_projects_from_repo_url.png)
diff --git a/doc/user/project/index.md b/doc/user/project/index.md
index c79f2be1d3f..a00f93bac9c 100644
--- a/doc/user/project/index.md
+++ b/doc/user/project/index.md
@@ -34,7 +34,7 @@ When you create a project in GitLab, you'll have access to a large number of
- [Protected tags](protected_tags.md): Control over who has
permission to create tags, and prevent accidental update or deletion
- [Repository mirroring](repository/repository_mirroring.md)
- - [Signing commits](gpg_signed_commits/index.md): use GPG to sign your commits
+ - [Signing commits](repository/gpg_signed_commits/index.md): use GPG to sign your commits
- [Deploy tokens](deploy_tokens/index.md): Manage project-based deploy tokens that allow permanent access to the repository and Container Registry.
- [Web IDE](web_ide/index.md)
- [CVE ID Requests](../application_security/cve_id_request.md): Request a CVE identifier to track a
@@ -96,9 +96,9 @@ When you create a project in GitLab, you'll have access to a large number of
- [Wiki](wiki/index.md): document your GitLab project in an integrated Wiki.
- [Snippets](../snippets.md): store, share and collaborate on code snippets.
-- [Value Stream Analytics](cycle_analytics.md): review your development lifecycle.
+- [Value Stream Analytics](../analytics/value_stream_analytics.md): review your development lifecycle.
- [Insights](insights/index.md): configure the Insights that matter for your projects. **(ULTIMATE)**
-- [Security Dashboard](security_dashboard.md): Security Dashboard. **(ULTIMATE)**
+- [Security Dashboard](../application_security/security_dashboard/index.md): Security Dashboard. **(ULTIMATE)**
- [Syntax highlighting](highlighting.md): an alternative to customize
your code blocks, overriding GitLab's default choice of language.
- [Badges](badges.md): badges for the project overview.
diff --git a/doc/user/project/integrations/irker.md b/doc/user/project/integrations/irker.md
index 443ca11be27..bb4a5b2b97f 100644
--- a/doc/user/project/integrations/irker.md
+++ b/doc/user/project/integrations/irker.md
@@ -14,8 +14,8 @@ See the project homepage for further information: <https://gitlab.com/esr/irker>
## Needed setup
-You will first need an Irker daemon. You can download the Irker code from its
-repository on <https://gitlab.com/esr/irker>:
+You will first need an Irker daemon. You can download the Irker code
+[from its repository](https://gitlab.com/esr/irker):
```shell
git clone https://gitlab.com/esr/irker.git
@@ -55,6 +55,6 @@ case, `Aorimn` is treated as a nick and no more as a channel name.
Irker can also join password-protected channels. Users need to append
`?key=thesecretpassword` to the channel name. When using this feature remember to
**not** put the `#` sign in front of the channel name; failing to do so will
-result on irker joining a channel literally named `#chan?key=password` henceforth
+result on Irker joining a channel literally named `#chan?key=password` henceforth
leaking the channel key through the `/whois` IRC command (depending on IRC server
-configuration). This is due to a long standing irker bug.
+configuration). This is due to a long standing Irker bug.
diff --git a/doc/user/project/integrations/jira.md b/doc/user/project/integrations/jira.md
index 3e0b6492477..b4e02bbd5f3 100644
--- a/doc/user/project/integrations/jira.md
+++ b/doc/user/project/integrations/jira.md
@@ -23,7 +23,7 @@ Features include:
- **View a list of Jira issues directly in GitLab** **(PREMIUM)**
For additional features, you can install the
-[Jira Development Panel integration](../../../integration/jira_development_panel.md) **(PREMIUM)**.
+[Jira Development Panel integration](../../../integration/jira_development_panel.md).
This enables you to:
- In a Jira issue, display relevant GitLab information in the [development panel](https://support.atlassian.com/jira-software-cloud/docs/view-development-information-for-an-issue/), including related branches, commits, and merge requests.
@@ -122,6 +122,8 @@ By now you should have [configured Jira](#configuring-jira) and enabled the
you should be able to reference and close Jira issues by just mentioning their
ID in GitLab commits and merge requests.
+Jira issue IDs must be formatted in uppercase for the integration to work.
+
### Reference Jira issues
When GitLab project has Jira issue tracker configured and enabled, mentioning
diff --git a/doc/user/project/integrations/overview.md b/doc/user/project/integrations/overview.md
index 7a1f757c138..a502dfbf320 100644
--- a/doc/user/project/integrations/overview.md
+++ b/doc/user/project/integrations/overview.md
@@ -50,7 +50,7 @@ Click on the service links to see further configuration instructions and details
| [Mattermost slash commands](mattermost_slash_commands.md) | Mattermost chat and ChatOps slash commands | No |
| [Mattermost Notifications](mattermost.md) | Receive event notifications in Mattermost | No |
| [Microsoft teams](microsoft_teams.md) | Receive notifications for actions that happen on GitLab into a room on Microsoft Teams using Office 365 Connectors | No |
-| Packagist | Update your project on Packagist, the main Composer repository | Yes |
+| Packagist | Update your projects on Packagist, the main Composer repository | Yes |
| Pipelines emails | Email the pipeline status to a list of recipients | No |
| [Slack Notifications](slack.md) | Send GitLab events (for example, an issue was created) to Slack as notifications | No |
| [Slack slash commands](slack_slash_commands.md) **(CORE ONLY)** | Use slash commands in Slack to control GitLab | No |
diff --git a/doc/user/project/integrations/prometheus.md b/doc/user/project/integrations/prometheus.md
index a19b819c823..28a9afa5bb0 100644
--- a/doc/user/project/integrations/prometheus.md
+++ b/doc/user/project/integrations/prometheus.md
@@ -1,6 +1,6 @@
---
stage: Monitor
-group: APM
+group: Health
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/#designated-technical-writers
---
@@ -58,6 +58,43 @@ CPU and Memory consumption is monitored, but requires [naming conventions](prome
The [NGINX Ingress](../clusters/index.md#installing-applications) that is deployed by GitLab to clusters, is automatically annotated for monitoring providing key response metrics: latency, throughput, and error rates.
+##### Example of Kubernetes service annotations and labels
+
+As an example, to activate Prometheus monitoring of a service:
+
+1. Add at least this annotation: `prometheus.io/scrape: 'true'`.
+1. Add two labels so GitLab can retrieve metrics dynamically for any environment:
+ - `application: ${CI_ENVIRONMENT_SLUG}`
+ - `release: ${CI_ENVIRONMENT_SLUG}`
+1. Create a dynamic PromQL query. For example, a query like
+ `temperature{application="{{ci_environment_slug}}",release="{{ci_environment_slug}}"}` to either:
+ - Add [custom metrics](../../../operations/metrics/index.md#adding-custom-metrics).
+ - Add [custom dashboards](../../../operations/metrics/dashboards/index.md).
+
+The following is a service definition to accomplish this:
+
+```yaml
+---
+# Service
+apiVersion: v1
+kind: Service
+metadata:
+ name: service-${CI_PROJECT_NAME}-${CI_COMMIT_REF_SLUG}
+ # === Prometheus annotations ===
+ annotations:
+ prometheus.io/scrape: 'true'
+ labels:
+ application: ${CI_ENVIRONMENT_SLUG}
+ release: ${CI_ENVIRONMENT_SLUG}
+ # === End of Prometheus ===
+spec:
+ selector:
+ app: ${CI_PROJECT_NAME}
+ ports:
+ - port: ${EXPOSED_PORT}
+ targetPort: ${CONTAINER_PORT}
+```
+
### Manual configuration of Prometheus
#### Requirements
@@ -136,10 +173,7 @@ one of them will be used:
> - GitLab 9.3 added the [numeric comparison](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/27439) of the 30 minute averages.
Developers can view the performance impact of their changes within the merge
-request workflow.
-
-NOTE: **Note:**
-Requires [Kubernetes](prometheus_library/kubernetes.md) metrics.
+request workflow. This feature requires [Kubernetes](prometheus_library/kubernetes.md) metrics.
When a source branch has been deployed to an environment, a sparkline and
numeric comparison of the average memory consumption will appear. On the
diff --git a/doc/user/project/integrations/prometheus_library/cloudwatch.md b/doc/user/project/integrations/prometheus_library/cloudwatch.md
index e278c7eb664..70f8a55bb07 100644
--- a/doc/user/project/integrations/prometheus_library/cloudwatch.md
+++ b/doc/user/project/integrations/prometheus_library/cloudwatch.md
@@ -1,6 +1,6 @@
---
stage: Monitor
-group: APM
+group: Health
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/#designated-technical-writers
---
diff --git a/doc/user/project/integrations/prometheus_library/haproxy.md b/doc/user/project/integrations/prometheus_library/haproxy.md
index 712805b75f2..0fbc49ddad7 100644
--- a/doc/user/project/integrations/prometheus_library/haproxy.md
+++ b/doc/user/project/integrations/prometheus_library/haproxy.md
@@ -1,6 +1,6 @@
---
stage: Monitor
-group: APM
+group: Health
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/#designated-technical-writers
---
diff --git a/doc/user/project/integrations/prometheus_library/index.md b/doc/user/project/integrations/prometheus_library/index.md
index 6f2c2477eee..35b111ab2b2 100644
--- a/doc/user/project/integrations/prometheus_library/index.md
+++ b/doc/user/project/integrations/prometheus_library/index.md
@@ -1,6 +1,6 @@
---
stage: Monitor
-group: APM
+group: Health
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/#designated-technical-writers
---
diff --git a/doc/user/project/integrations/prometheus_library/kubernetes.md b/doc/user/project/integrations/prometheus_library/kubernetes.md
index 29efe08e53d..43c2d305437 100644
--- a/doc/user/project/integrations/prometheus_library/kubernetes.md
+++ b/doc/user/project/integrations/prometheus_library/kubernetes.md
@@ -1,6 +1,6 @@
---
stage: Monitor
-group: APM
+group: Health
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/#designated-technical-writers
---
@@ -12,7 +12,7 @@ GitLab has support for automatically detecting and monitoring Kubernetes metrics
## Requirements
-The [Prometheus](../prometheus.md) and [Kubernetes](../kubernetes.md)
+The [Prometheus](../prometheus.md) and [Kubernetes](../../clusters/index.md)
integration services must be enabled.
## Metrics supported
diff --git a/doc/user/project/integrations/prometheus_library/nginx.md b/doc/user/project/integrations/prometheus_library/nginx.md
index 0d3042463c9..1757378fb70 100644
--- a/doc/user/project/integrations/prometheus_library/nginx.md
+++ b/doc/user/project/integrations/prometheus_library/nginx.md
@@ -1,6 +1,6 @@
---
stage: Monitor
-group: APM
+group: Health
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/#designated-technical-writers
---
diff --git a/doc/user/project/integrations/prometheus_library/nginx_ingress.md b/doc/user/project/integrations/prometheus_library/nginx_ingress.md
index 7bebe7b1e65..fdea800c410 100644
--- a/doc/user/project/integrations/prometheus_library/nginx_ingress.md
+++ b/doc/user/project/integrations/prometheus_library/nginx_ingress.md
@@ -1,6 +1,6 @@
---
stage: Monitor
-group: APM
+group: Health
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/#designated-technical-writers
---
@@ -8,11 +8,11 @@ info: To determine the technical writer assigned to the Stage/Group associated w
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/22133) in GitLab 11.7.
+GitLab has support for automatically detecting and monitoring the Kubernetes NGINX Ingress controller. This is provided by leveraging the built-in Prometheus metrics included with Kubernetes NGINX Ingress controller [version 0.16.0](https://github.com/kubernetes/ingress-nginx/blob/master/Changelog.md#0160) onward.
+
NOTE: **Note:**
NGINX Ingress versions prior to 0.16.0 offer an included [VTS Prometheus metrics exporter](nginx_ingress_vts.md), which exports metrics different than the built-in metrics.
-GitLab has support for automatically detecting and monitoring the Kubernetes NGINX Ingress controller. This is provided by leveraging the built-in Prometheus metrics included with Kubernetes NGINX Ingress controller [version 0.16.0](https://github.com/kubernetes/ingress-nginx/blob/master/Changelog.md#0160) onward.
-
## Requirements
[Prometheus integration](../prometheus.md) must be active.
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 326931e9790..ec7b1ee6d10 100644
--- a/doc/user/project/integrations/prometheus_library/nginx_ingress_vts.md
+++ b/doc/user/project/integrations/prometheus_library/nginx_ingress_vts.md
@@ -1,6 +1,6 @@
---
stage: Monitor
-group: APM
+group: Health
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/#designated-technical-writers
---
diff --git a/doc/user/project/integrations/services_templates.md b/doc/user/project/integrations/services_templates.md
index 688643a85a7..abb072c9a0a 100644
--- a/doc/user/project/integrations/services_templates.md
+++ b/doc/user/project/integrations/services_templates.md
@@ -6,20 +6,52 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Service templates
-Using a service template, GitLab administrators can provide default values for configuring integrations at the project level.
+Using a service template, GitLab administrators can:
-When you enable a service template, the defaults are applied to **all** projects that do not
-already have the integration enabled or do not otherwise have custom values saved.
-The values are pre-filled on each project's configuration page for the applicable integration.
+- Provide default values for configuring integrations when creating new projects.
+- Bulk configure all existing projects in one step.
-If you disable the template, these values no longer appear as defaults, while
-any values already saved for an integration remain unchanged.
+When you enable a service template:
+
+- The defaults are applied to **all** existing projects that either:
+ - Don't already have the integration enabled.
+ - Don't have custom values stored for already enabled integrations.
+- Values are populated on each project's configuration page for the applicable
+ integration.
+- Settings are stored at the project level.
+
+If you disable the template:
+
+- GitLab default values again become the default values for integrations on
+ new projects.
+- Projects previously configured using the template will continue to use
+ those settings.
+
+If you change the template, the revised values are applied to new projects. This feature
+does not provide central administration of integration settings.
+
+## Central administration of project integrations
+
+A new set of features is being introduced in GitLab to provide more control over
+how integrations are configured at the instance, group, and project level.
+
+[Read more about setting up project integration management](../../admin_area/settings/project_integration_management.md)
+(introduced in GitLab 13.3) and [our plans for managing integrations](https://gitlab.com/groups/gitlab-org/-/epics/2137).
## Enable a service template
Navigate to the **Admin Area > Service Templates** and choose the service
template you wish to create.
+Recommendation:
+
+- Test the settings on some projects individually before enabling a template.
+- Copy the working settings from a project to the template.
+
+There is no "Test settings" option when enabling templates. If the settings do not work,
+these incorrect settings will be applied to all existing projects that do not already have
+the integration configured. Fixing the integration then needs to be done project-by-project.
+
## Service for external issue trackers
The following image shows an example service template for Redmine.
diff --git a/doc/user/project/integrations/slack.md b/doc/user/project/integrations/slack.md
index 03ff5f845b6..e6f12c2532f 100644
--- a/doc/user/project/integrations/slack.md
+++ b/doc/user/project/integrations/slack.md
@@ -64,7 +64,7 @@ The following triggers are available for Slack notifications:
- **Tag push**: Triggered when a new tag is pushed to the repository.
- **Pipeline**: Triggered when a pipeline status changes.
- **Wiki page**: Triggered when a wiki page is created or updated.
-- **Deployment**: Triggered when a deployment finishes.
+- **Deployment**: Triggered when a deployment starts or finishes.
- **Alert**: Triggered when a new, unique alert is recorded.
## Troubleshooting
diff --git a/doc/user/project/integrations/webhooks.md b/doc/user/project/integrations/webhooks.md
index 800eb1d3359..7adea5ebcd6 100644
--- a/doc/user/project/integrations/webhooks.md
+++ b/doc/user/project/integrations/webhooks.md
@@ -1303,7 +1303,12 @@ Note that `commit.id` is the ID of the pipeline, not the ID of the commit.
### Deployment events
-Triggered when deployment is finished/failed/canceled.
+Triggered when a deployment:
+
+- Starts ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/41214) in GitLab 13.5.)
+- Succeeds
+- Fails
+- Is cancelled
**Request Header**:
diff --git a/doc/user/project/issue_board.md b/doc/user/project/issue_board.md
index f8172a0f988..bce40e9a838 100644
--- a/doc/user/project/issue_board.md
+++ b/doc/user/project/issue_board.md
@@ -8,14 +8,12 @@ info: To determine the technical writer assigned to the Stage/Group associated w
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/5554) in [GitLab 8.11](https://about.gitlab.com/releases/2016/08/22/gitlab-8-11-released/#issue-board).
-## Overview
-
The GitLab Issue Board is a software project management tool used to plan,
organize, and visualize a workflow for a feature or product release.
It can be used as a [Kanban](https://en.wikipedia.org/wiki/Kanban_(development)) or a
[Scrum](https://en.wikipedia.org/wiki/Scrum_(software_development)) board.
-It pairs issue tracking and project management, keeping everything in the same place,
+It pairs issue tracking and project management, keeping everything together,
so that you don't need to jump between different platforms to organize your workflow.
Issue boards build on the existing [issue tracking functionality](issues/index.md#issues-list) and
@@ -26,8 +24,8 @@ Issue boards help you to visualize and manage your entire process in GitLab.
You add your labels, and then create the corresponding list for your existing issues.
When you're ready, you can drag your issue cards from one step to another one.
-An issue board can show you what issues your team is working on, who is assigned to each,
-and where in the workflow those issues are.
+An issue board can show you the issues your team is working on, who is assigned to each,
+and where the issues are in the workflow.
To let your team members organize their own workflows, use
[multiple issue boards](#use-cases-for-multiple-issue-boards). This allows creating multiple issue
@@ -60,8 +58,8 @@ Here are some common use cases for issue boards.
### Use cases for a single issue board
-With the GitLab Workflow you can discuss proposals in issues, categorize them
-with labels, and from there, organize and prioritize them with issue boards.
+With the GitLab Workflow you can discuss proposals in issues, label
+them, and organize and prioritize them with issue boards.
For example, let's consider this simplified development workflow:
@@ -155,7 +153,7 @@ card includes:
## Permissions
Users with the [Reporter and higher roles](../permissions.md) can use all the functionality of the
-Issue Board feature to create or delete lists and drag issues from one list to another.
+Issue Board feature to create or delete lists. They can also drag issues from one list to another.
## How GitLab orders issues in a list
@@ -164,20 +162,19 @@ that order by dragging the issues. The changed order is saved, so that anybody w
board later sees the reordering, with some exceptions.
The first time a given issue appears in any board (that is, the first time a user
-loads a board containing that issue), it is ordered in relation to other issues in that list
-according to [label priority](labels.md#label-priority).
+loads a board containing that issue), it is ordered in relation to other issues in that list.
+The order is done according to [label priority](labels.md#label-priority).
At this point, that issue is assigned a relative order value by the system,
-representing its relative order with respect to the other issues in the list. Any time
-you reorder that issue by dragging, its relative order value changes accordingly.
+with respect to the other issues in the list. Any time
+you drag and reorder the issue, its relative order value changes accordingly.
-Also, any time that issue appears in any board when it's loaded by a user,
-the updated relative order value is used for the ordering. It's only the first
-time an issue appears that it takes from the priority order mentioned above. This means that
-if issue `A` is reordered by dragging to be above issue `B` by any user in
-a given board inside your GitLab instance, any time those two issues are subsequently
-loaded in any board in the same instance (could be a different project board or a different group
-board, for example), that ordering is maintained.
+Also, any time that issue appears in any board, the ordering is done according to
+the updated relative order value. It's only the first
+time an issue appears that it takes from the priority order mentioned above. If a user in your GitLab instance
+drags issue `A` above issue `B`, the ordering is maintained when these two issues are subsequently
+loaded in any board in the same instance. This could be a different project board or a different group
+board, for example.
This ordering also affects [issue lists](issues/sorting_issue_lists.md).
Changing the order in an issue board changes the ordering in an issue list,
@@ -195,8 +192,7 @@ advanced functionality is present in [higher tiers only](https://about.gitlab.co
> - Multiple issue boards per group are available in [GitLab Premium](https://about.gitlab.com/pricing/).
Multiple issue boards allow for more than one issue board for a given project or group.
-This is great for large projects with more than one team or in situations where a repository is used
-to host the code of multiple products.
+This is great for large projects with more than one team or when a repository hosts the code of multiple products.
Using the search box at the top of the menu, you can filter the listed boards.
@@ -230,13 +226,13 @@ To delete the currently active issue board:
An issue board can be associated with a GitLab [Milestone](milestones/index.md#milestones),
[Labels](labels.md), Assignee and Weight
-which will automatically filter the Board issues according to these fields.
+which automatically filter the board issues accordingly.
This allows you to create unique boards according to your team's need.
![Create scoped board](img/issue_board_creation.png)
You can define the scope of your board when creating it or by clicking the "Edit board" button.
-Once a milestone, assignee or weight is assigned to an issue board, you will no longer be able to
+Once a milestone, assignee or weight is assigned to an issue board, you can no longer
filter through these in the search bar. In order to do that, you need to remove the desired scope
(for example, milestone, assignee, or weight) from the issue board.
@@ -274,24 +270,22 @@ especially in combination with [assignee lists](#assignee-lists).
### Group issue boards **(PREMIUM)**
-> [Introduced](https://about.gitlab.com/releases/2017/09/22/gitlab-10-0-released/#group-issue-boards) in [GitLab Premium](https://about.gitlab.com/pricing/) 10.0.
+> - One group issue board per group introduced in GitLab 10.6.
+> - Multiple group issue boards [introduced](https://about.gitlab.com/releases/2017/09/22/gitlab-10-0-released/#group-issue-boards) in [GitLab Premium](https://about.gitlab.com/pricing/) 10.0.
-Accessible at the group navigation level, a group issue board offers the same features as a project-level board,
-but it can display issues from all projects in that
+Accessible at the group navigation level, a group issue board offers the same features as a project-level board.
+It can display issues from all projects in that
group and its descendant subgroups. Similarly, you can only filter by group labels for these
boards. When updating milestones and labels for an issue through the sidebar update mechanism, again only
group-level objects are available.
-NOTE: **Note:**
-Multiple group issue boards were originally [introduced](https://about.gitlab.com/releases/2017/09/22/gitlab-10-0-released/#group-issue-boards) in [GitLab Premium](https://about.gitlab.com/pricing/) 10.0, and one group issue board per group was made available in GitLab Core 10.6.
-
![Group issue board](img/group_issue_board.png)
### Assignee lists **(PREMIUM)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/5784) in [GitLab Premium](https://about.gitlab.com/pricing/) 11.0.
-Like in a regular list that shows all issues with a chosen label, you can add
+As in a regular list showing all issues with a chosen label, you can add
an assignee list that shows all issues assigned to a user.
You can have a board with both label lists and assignee lists. To add an
assignee list:
@@ -317,7 +311,7 @@ milestone, giving you more freedom and visibility on the issue board. To add a m
1. Select the **Milestone** tab.
1. Search and click the milestone.
-Similar to the assignee lists, you're now able to [drag issues](#drag-issues-between-lists)
+Like the assignee lists, you're able to [drag issues](#drag-issues-between-lists)
to and from a milestone list to manipulate the milestone of the dragged issues.
As in other list types, click the trash icon to remove a list.
@@ -333,7 +327,7 @@ You cannot set a WIP limit on the default lists (**Open** and **Closed**).
Examples:
-- You have a list with four issues, and a limit of five, the header will show **4/5**.
+- When you have a list with four issues and a limit of five, the header shows **4/5**.
If you exceed the limit, the current number of issues is shown in red.
- You have a list with five issues with a limit of five. When you move another issue to that list,
the list's header displays **6/5**, with the six shown in red.
@@ -374,29 +368,24 @@ If you're not able to do some of the things above, make sure you have the right
### First time using an issue board
-The first time you open an issue board, you are presented with
-the default lists (**Open** and **Closed**) and a welcome message that gives
-you two options. You can either:
+> The automatic creation of the **To Do** and **Doing** lists was [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/202144) in GitLab 13.5.
-- Create a predefined set of labels (by default: **To Do** and **Doing**) and create their
- corresponding lists to the issue board.
-- Opt-out and use your own lists.
+The first time you open an issue board, you are presented with the default lists
+(**Open**, **To Do**, **Doing**, and **Closed**).
-![issue board welcome message](img/issue_board_welcome_message.png)
+If the **To Do** and **Doing** labels don't exist in the project or group, they are created, and
+their lists appear as empty. If any of them already exists, the list is filled with the issues that
+have that label.
-If you choose to use and create the predefined lists, they will appear as empty
-because the labels associated to them will not exist up until that moment,
-which means the system has no way of populating them automatically. That's of
-course if the predefined labels don't already exist. If any of them does exist,
-the list will be created and filled with the issues that have that label.
+![issue board default lists](img/issue_board_default_lists_v13_4.png)
### Create a new list
Create a new list by clicking the **Add list** button in the upper right corner of the issue board.
-![issue board welcome message](img/issue_board_add_list.png)
+![creating a new list in an issue board](img/issue_board_add_list.png)
-Then, choose the label or user to create the list from. The new list will be inserted
+Then, choose the label or user to create the list from. The new list is inserted
at the end of the lists, before **Done**. Moving and reordering lists is as
easy as dragging them around.
@@ -407,15 +396,15 @@ You can now choose it to create a list.
### Delete a list
To delete a list from the issue board, use the small trash icon present
-in the list's heading. A confirmation dialog will appear for you to confirm.
+in the list's heading. A confirmation dialog appears for you to confirm.
-Deleting a list doesn't have any effect in issues and labels, it's just the
-list view that is removed. You can always add it back later if you need.
+Deleting a list doesn't have any effect on issues and labels, as it's just the
+list view that's removed. You can always restore it later if you need.
### Add issues to a list
You can add issues to a list by clicking the **Add issues** button
-present in the upper right corner of the issue board. This will open up a modal
+present in the upper right corner of the issue board. This opens up a modal
window where you can see all the issues that do not belong to any list.
Select one or more issues by clicking the cards and then click **Add issues**
@@ -435,7 +424,7 @@ respective label is removed.
### Filter issues
You should be able to use the filters on top of your issue board to show only
-the results you want. This is similar to the filtering used in the issue tracker
+the results you want. It's similar to the filtering used in the issue tracker
since the metadata from the issues and labels are re-used in the issue board.
You can filter by author, assignee, milestone, and label.
@@ -469,12 +458,12 @@ For example, you can create a list based on the label of **Frontend** and one fo
worked on by the designers.
Then, once they're done, all they have to do is
-drag it to the next list, **Backend**, where a backend developer can
+drag it to the next list, **Backend**. Then, a backend developer can
eventually pick it up. Once they’re done, they move it to **Done**, to close the
issue.
-This process can be seen clearly when visiting an issue since with every move
-to another list the label changes and a system note is recorded.
+This process can be seen clearly when visiting an issue. With every move
+to another list, the label changes and a system note is recorded.
![issue board system notes](img/issue_board_system_notes.png)
diff --git a/doc/user/project/issues/crosslinking_issues.md b/doc/user/project/issues/crosslinking_issues.md
index c721bef8f4d..2a75f8ad837 100644
--- a/doc/user/project/issues/crosslinking_issues.md
+++ b/doc/user/project/issues/crosslinking_issues.md
@@ -33,7 +33,7 @@ Of course, you can replace `gitlab.com` with the URL of your own GitLab instance
NOTE: **Note:**
Linking your first commit to your issue is going to be relevant
-for tracking your process with [GitLab Cycle Analytics](https://about.gitlab.com/stages-devops-lifecycle/value-stream-analytics/).
+for tracking your process with [GitLab Value Stream Analytics](https://about.gitlab.com/stages-devops-lifecycle/value-stream-analytics/).
It will measure the time taken for planning the implementation of that issue,
which is the time between creating an issue and making the first commit.
diff --git a/doc/user/project/issues/design_management.md b/doc/user/project/issues/design_management.md
index 7c9278c8403..6f57487fccd 100644
--- a/doc/user/project/issues/design_management.md
+++ b/doc/user/project/issues/design_management.md
@@ -4,14 +4,12 @@ group: Knowledge
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/#designated-technical-writers"
---
-# Design Management
+# Design Management **(CORE)**
> - [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/660) in [GitLab Premium](https://about.gitlab.com/pricing/) 12.2.
> - Support for SVGs was [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/12771) in [GitLab Premium](https://about.gitlab.com/pricing/) 12.4.
> - Design Management was [moved](https://gitlab.com/gitlab-org/gitlab/-/issues/212566) to GitLab Core in 13.0.
-## Overview
-
Design Management allows you to upload design assets (wireframes, mockups, etc.)
to GitLab issues and keep them stored in one single place, accessed by the Design
Management's page within an issue, giving product designers, product managers, and engineers a
@@ -58,8 +56,7 @@ Support for [PDF](https://gitlab.com/gitlab-org/gitlab/issues/32811) is planned
- From GitLab 13.1, Design filenames are limited to 255 characters.
- Design Management data
[isn't deleted when a project is destroyed](https://gitlab.com/gitlab-org/gitlab/-/issues/13429) yet.
-- Design Management data [won't be moved](https://gitlab.com/gitlab-org/gitlab/-/issues/13426)
- when an issue is moved, nor [deleted](https://gitlab.com/gitlab-org/gitlab/-/issues/13427)
+- Design Management data [won't be deleted](https://gitlab.com/gitlab-org/gitlab/-/issues/13427)
when an issue is deleted.
- From GitLab 12.7, Design Management data [can be replicated](../../../administration/geo/replication/datatypes.md#limitations-on-replicationverification)
by Geo but [not verified](https://gitlab.com/gitlab-org/gitlab/-/issues/32467).
@@ -114,9 +111,6 @@ Designs with the same filename as an existing uploaded design will create a new
of the design, and will replace the previous version. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/34353) in [GitLab Premium](https://about.gitlab.com/pricing/) 12.9, dropping a design on an existing uploaded design will also create a new version,
provided the filenames are the same.
-Designs cannot be added if the issue has been moved, or its
-[discussion is locked](../../discussions/#lock-discussions).
-
### Skipped designs
Designs with the same filename as an existing uploaded design _and_ whose content has not changed will be skipped.
@@ -185,9 +179,7 @@ viewed by browsing previous versions.
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/34382) in GitLab 13.3.
-You can change the order of designs by dragging them to a new position:
-
-![Reorder designs](img/designs_reordering_v13_3.gif)
+You can change the order of designs by dragging them to a new position.
## Starting discussions on designs
@@ -231,47 +223,19 @@ Note that your resolved comment pins will disappear from the Design to free up s
However, if you need to revisit or find a resolved discussion, all of your resolved threads will be
available in the **Resolved Comment** area at the bottom of the right sidebar.
-## Add To-Do for Designs
+## Add to dos for designs
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/198439) in GitLab 13.4.
-> - It's [deployed behind a feature flag](../../feature_flags.md), enabled by default.
-> - It's enabled on GitLab.com.
-> - It's recommended for production use.
-> - For GitLab self-managed instances, GitLab administrators can opt to [disable it](#enable-or-disable-the-design-to-do-button). **(CORE ONLY)**
-
-CAUTION: **Warning:**
-This feature might not be available to you. Check the **version history** note above for details.
-
-Add a to-do for a design by clicking **Add a To-Do** on the design sidebar:
-
-![To-Do button](img/design_todo_button_v13_4.png)
-
-### Enable or disable the design To-Do button **(CORE ONLY)**
-
-The **Add a To-Do** button for Designs is under development but ready for production use. It is
-deployed behind a feature flag that is **enabled by default**.
-[GitLab administrators with access to the GitLab Rails console](../../../administration/feature_flags.md)
-can enable it.
-
-To enable it:
-
-```ruby
-Feature.enable(:design_management_todo_button)
-```
+> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/245074) in GitLab 13.5.
-To disable it:
+Add a to do for a design by clicking **Add a To Do** on the design sidebar:
-```ruby
-Feature.disable(:design_management_todo_button)
-```
+![To-do button](img/design_todo_button_v13_5.png)
## Referring to designs in Markdown
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/217160) in **GitLab 13.1**.
-> - It is deployed behind a feature flag, disabled by default.
-> - It is disabled on GitLab.com.
-> - It is not recommended for production use.
-> - To use it in GitLab self-managed instances, ask a GitLab administrator to [enable it](#enable-or-disable-design-references). **(CORE ONLY)**
+> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/258662) in **GitLab 13.5**
We support referring to designs in [Markdown](../../markdown.md), which is available
throughout the application, including in merge request and issue descriptions, in discussions and comments, and in wiki pages.
@@ -287,25 +251,6 @@ This will be rendered as:
> See [#123[homescreen.png]](https://gitlab.com/your-group/your-project/-/issues/123/designs/homescreen.png)
-### Enable or disable design references **(CORE ONLY)**
-
-Design reference parsing is
-deployed behind a feature flag that is **enabled by default**.
-[GitLab administrators with access to the GitLab Rails console](../../../administration/feature_flags.md)
-can disable it for your instance.
-
-To disable it:
-
-```ruby
-Feature.disable(:design_management_reference_filter_gfm_pipeline)
-```
-
-To re-enable it:
-
-```ruby
-Feature.enable(:design_management_reference_filter_gfm_pipeline)
-```
-
## Design activity records
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/33051) in GitLab 13.1.
diff --git a/doc/user/project/issues/due_dates.md b/doc/user/project/issues/due_dates.md
index 55b45bf9d3d..b3ebefadef0 100644
--- a/doc/user/project/issues/due_dates.md
+++ b/doc/user/project/issues/due_dates.md
@@ -46,7 +46,7 @@ the icon and the date colored red. You can sort issues by those that are
Due dates also appear in your [to-do list](../../todos.md).
-![Issues with due dates in the to-dos](img/due_dates_todos.png)
+![Issues with due dates in the to dos](img/due_dates_todos.png)
The day before an open issue is due, an email will be sent to all participants
of the issue. Like the due date, the "day before the due date" is determined by the
diff --git a/doc/user/project/issues/img/design_todo_button_v13_4.png b/doc/user/project/issues/img/design_todo_button_v13_4.png
deleted file mode 100644
index 62bbecf4ed9..00000000000
--- a/doc/user/project/issues/img/design_todo_button_v13_4.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/project/issues/img/design_todo_button_v13_5.png b/doc/user/project/issues/img/design_todo_button_v13_5.png
new file mode 100644
index 00000000000..970161a6097
--- /dev/null
+++ b/doc/user/project/issues/img/design_todo_button_v13_5.png
Binary files differ
diff --git a/doc/user/project/issues/img/designs_reordering_v13_3.gif b/doc/user/project/issues/img/designs_reordering_v13_3.gif
deleted file mode 100644
index 496eea532e2..00000000000
--- a/doc/user/project/issues/img/designs_reordering_v13_3.gif
+++ /dev/null
Binary files differ
diff --git a/doc/user/project/issues/index.md b/doc/user/project/issues/index.md
index 060266a478f..434af3a4a49 100644
--- a/doc/user/project/issues/index.md
+++ b/doc/user/project/issues/index.md
@@ -156,12 +156,15 @@ collaborate with your team.
efficiently and with less effort by tracking groups of issues that share a theme, across
projects and milestones.
-### Related issues **(STARTER)**
+### Related issues
You can mark two issues as related, so that when viewing one, the other is always
listed in its [Related Issues](related_issues.md) section. This can help display important
context, such as past work, dependencies, or duplicates.
+Users on [GitLab Starter, GitLab Bronze, and higher tiers](https://about.gitlab.com/pricing/), can
+also mark issues as blocking or blocked by another issue.
+
### Crosslinking issues
You can [cross-link issues](crosslinking_issues.md) by referencing an issue from another
diff --git a/doc/user/project/issues/issue_data_and_actions.md b/doc/user/project/issues/issue_data_and_actions.md
index 5356e6aeb40..003444e0ed8 100644
--- a/doc/user/project/issues/issue_data_and_actions.md
+++ b/doc/user/project/issues/issue_data_and_actions.md
@@ -36,7 +36,7 @@ You can find all the information for that issue on one screen.
- **15.** [Edit](#edit)
- **16.** [Description](#description)
- **17.** [Mentions](#mentions)
-- **18.** [Related Issues **(STARTER)**](#related-issues)
+- **18.** [Related Issues](#related-issues)
- **19.** [Related Merge Requests](#related-merge-requests)
- **20.** [Award emoji](#award-emoji)
- **21.** [Show all activity](#show-all-activity)
@@ -80,7 +80,7 @@ The button to do this has a different label depending on whether the issue is al
List or not. If the issue is:
- Already on your To-Do List: The button is labeled **Mark as done**. Click the button to remove the issue from your To-Do List.
-- Not on your To-Do List: The button is labeled **Add a To Do**. Click the button to add the issue to your To-Do List.
+- Not on your To-Do List: The button is labeled **Add a to do**. Click the button to add the issue to your To-Do List.
### Assignee
@@ -191,7 +191,7 @@ The plain text title and description of the issue fill the top center of the iss
The description fully supports [GitLab Flavored Markdown](../../markdown.md#gitlab-flavored-markdown-gfm),
allowing many formatting options.
-> [Since GitLab 12.6](https://gitlab.com/gitlab-org/gitlab/-/issues/10103), changes to an issue's description are listed in the [issue history](#issue-history).**(STARTER)**
+> [In GitLab 12.6](https://gitlab.com/gitlab-org/gitlab/-/issues/10103) and later, changes to an issue's description are listed in the [issue history](#issue-history).**(STARTER)**
### Mentions
@@ -208,7 +208,7 @@ TIP: **Tip:**
Avoid mentioning `@all` in issues and merge requests, as it sends an email notification
to all the members of that project's group, which can be interpreted as spam.
-### Related Issues **(STARTER)**
+### Related Issues
Issues that were mentioned as [related issues](related_issues.md) are listed here.
You can also click the `+` to add more related issues.
@@ -242,7 +242,7 @@ and selecting either:
Also:
- You can mention a user or a group present in your GitLab instance with
- `@username` or `@groupname` and they will be notified via To-Do items
+ `@username` or `@groupname` and they will be notified via to-do items
and email, unless they have [disabled all notifications](#notifications)
in their profile settings.
- Mentions for yourself (the current logged in user), will be highlighted
diff --git a/doc/user/project/issues/managing_issues.md b/doc/user/project/issues/managing_issues.md
index 0e0731528be..b033dc79dcc 100644
--- a/doc/user/project/issues/managing_issues.md
+++ b/doc/user/project/issues/managing_issues.md
@@ -127,6 +127,7 @@ field).
| title | `issue[title]` | |
| description | `issue[description]` | |
| description template | `issuable_template` | |
+| issue type | `issue[issue_type]` | Either `incident` or `issue` |
| confidential | `issue[confidential]` | Parameter value must be `true` to set to confidential |
Follow these examples to form your new issue URL with prefilled fields.
diff --git a/doc/user/project/issues/multiple_assignees_for_issues.md b/doc/user/project/issues/multiple_assignees_for_issues.md
index c11977f5bee..b1806460c08 100644
--- a/doc/user/project/issues/multiple_assignees_for_issues.md
+++ b/doc/user/project/issues/multiple_assignees_for_issues.md
@@ -8,8 +8,6 @@ info: To determine the technical writer assigned to the Stage/Group associated w
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/1904) in [GitLab Starter 9.2](https://about.gitlab.com/releases/2017/05/22/gitlab-9-2-released/#multiple-assignees-for-issues).
-## Overview
-
In large teams, where there is shared ownership of an issue, it can be difficult
to track who is working on it, who already completed their contributions, who
didn't even start yet.
diff --git a/doc/user/project/issues/related_issues.md b/doc/user/project/issues/related_issues.md
index 954e3771722..b040bcf3b03 100644
--- a/doc/user/project/issues/related_issues.md
+++ b/doc/user/project/issues/related_issues.md
@@ -4,33 +4,40 @@ group: Project Management
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/#designated-technical-writers
---
-# Related issues **(STARTER)**
+# Related issues **(CORE)**
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/1797) in [GitLab Starter](https://about.gitlab.com/pricing/) 9.4.
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/1797) in [GitLab Starter](https://about.gitlab.com/pricing/) 9.4.
+> - The simple "relates to" relationship [moved](https://gitlab.com/gitlab-org/gitlab/-/issues/212329) to [GitLab Core](https://about.gitlab.com/pricing/) in 13.4.
Related issues are a bi-directional relationship between any two issues
and appear in a block below the issue description. Issues can be across groups
and projects.
+You can set any issue as:
+
+- Related to another issue
+- Blocking another issue **(STARTER)**
+- Blocked by another issue **(STARTER)**
+
The relationship only shows up in the UI if the user can see both issues.
When you try to close an issue that has open blockers, a warning is displayed.
TIP: **Tip:**
-To manage related issues through our API, see the [API documentation](../../../api/issue_links.md).
+To manage related issues through our API, visit the [issue links API documentation](../../../api/issue_links.md).
## Adding a related issue
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/2035) in [GitLab Starter](https://about.gitlab.com/pricing/) 12.8.
> - [Improved](https://gitlab.com/gitlab-org/gitlab/-/issues/34239) to warn when attempting to close an issue that is blocked by others in [GitLab Starter](https://about.gitlab.com/pricing/) 13.0.
-> When you try to close an issue with open blockers, you'll see a warning that you can dismiss.
+> When you try to close an issue with open blockers, you see a warning that you can dismiss.
1. Relate one issue to another by clicking the related issues "+" button
in the header of the related issue block.
1. Input the issue reference number or paste in the full URL of the issue.
-1. Select whether the current issue relates to, blocks, or is blocked by the issues being entered.
+1. **(STARTER)** Select whether the current issue relates to, blocks, or is blocked by the issues being entered.
![Adding a related issue](img/related_issues_add_v12_8.png)
@@ -42,11 +49,11 @@ in the header of the related issue block.
- same group: `project#44`
- different group: `group/project#44`
- Valid references will be added to a temporary list that you can review.
+ Valid references are added to a temporary list that you can review.
1. When you have added all the related issues, click **Add** to submit.
-When you have finished adding all related issues, you will be able to see
+When you have finished adding all related issues, you can see
them categorized so their relationships can be better understood visually.
![Related issue block](img/related_issue_block_v12_8.png)
@@ -56,7 +63,7 @@ them categorized so their relationships can be better understood visually.
In the related issues block, click the "x" icon on the right-side of each issue
token that you wish to remove.
-Due to the bi-directional relationship, it will no longer appear in either issue.
+Due to the bi-directional relationship, it no longer appears in either issue.
![Removing a related issue](img/related_issues_remove_v12_8.png)
diff --git a/doc/user/project/labels.md b/doc/user/project/labels.md
index 0d02b89be7e..4f0354f86af 100644
--- a/doc/user/project/labels.md
+++ b/doc/user/project/labels.md
@@ -6,8 +6,6 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Labels
-## Overview
-
As your count of issues, merge requests, and epics grows in GitLab, it's more and more challenging
to keep track of those items. Especially as your organization grows from just a few people to
hundreds or thousands. This is where labels come in. They help you organize and tag your work
@@ -32,18 +30,25 @@ There are two types of labels in GitLab:
## Assign and unassign labels
-Every issue, merge request and epic can be assigned any number of labels. The labels are
+> Unassigning labels with the **X** button [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/216881) in GitLab 13.5.
+
+Every issue, merge request, and epic can be assigned any number of labels. The labels are
managed in the right sidebar, where you can assign or unassign labels as needed.
-To assign a label to an issue, merge request or epic:
+To assign or unassign a label:
-1. In the label section of the sidebar, click **Edit**, then:
- - In the list, click the labels you want. Each label is flagged with a checkmark.
- - Find labels by entering a search query and clicking search (**{search}**), then
- click on them. You can search repeatedly and add more labels.
-1. Click **X** or anywhere outside the label section and the labels are applied.
+1. In the **Labels** section of the sidebar, click **Edit**.
+1. In the **Assign labels** list, search for labels by typing their names.
+ You can search repeatedly to add more labels.
+ The selected labels are marked with a checkmark.
+1. Click the labels you want to assign or unassign.
+1. To apply your changes to labels, click **X** next to **Assign labels** or anywhere outside the
+ label section.
-You can also assign a label with the [`/label ~label1 ~label2` quick action](quick_actions.md).
+Alternatively, to unassign a label, click the **X** on the label you want to unassign.
+
+You can also assign a label with the `/label` [quick action](quick_actions.md),
+remove labels with `/unlabel`, and reassign labels (remove all and assign new ones) with `/relabel`.
## Label management
@@ -52,10 +57,13 @@ and edit labels.
### Project labels
-View the project labels list by going to the project and clicking **Issues > Labels**.
+> Showing all inherited labels [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/241990) in 13.5.
+
+To view the project labels list, navigate to the project and click **Issues > Labels**.
The list includes all labels that are defined at the project level, as well as all
-labels inherited from the immediate parent group. You can filter the list by entering a search
-query at the top and clicking search (**{search}**).
+labels defined by its ancestor groups.
+For each label, you can see the project or group path from where it was created.
+You can filter the list by entering a search query at the top and clicking search (**{search}**).
To create a new project label:
@@ -83,19 +91,19 @@ a label by clicking the three dots (**{ellipsis_v}**) next to the **Subscribe**
and selecting **Delete**.
CAUTION: **Caution:**
-If you delete a label, it is permanently deleted. You will not be able to undo the deletion, and all references to the label will be removed from the system.
+If you delete a label, it is permanently deleted. All references to the label are removed from the system and you cannot undo the deletion.
#### Promote a project label to a group label
If you previously created a project label and now want to make it available for other
projects within the same group, you can promote it to a group label.
-If other projects in the same group have a label with the same title, they will all be
-merged with the new group label. If a group label with the same title exists, it will
-also be merged.
+If other projects in the same group have a label with the same title, they are all
+merged with the new group label. If a group label with the same title exists, it is
+also merged.
All issues, merge requests, issue board lists, issue board filters, and label subscriptions
-with the old labels will be assigned to the new group label.
+with the old labels are assigned to the new group label.
CAUTION: **Caution:**
Promoting a label is a permanent action, and cannot be reversed.
@@ -108,7 +116,7 @@ To promote a project label to a group label:
### Group labels
-View the group labels list by going to the group and clicking **Issues > Labels**.
+To view the group labels list, navigate to the group and click **Issues > Labels**.
The list includes all labels that are defined at the group level only. It does not
list any labels that are defined in projects. You can filter the list by entering
a search query at the top and clicking search (**{search}**).
@@ -118,15 +126,15 @@ follow the same process as [creating a project label](#project-labels).
#### Create group labels from epics **(ULTIMATE)**
-You can create group labels from the Epic sidebar. The labels you create will
+You can create group labels from the epic sidebar. The labels you create
belong to the immediate group to which the epic belongs. The process is the same as
creating a [project label from an issue or merge request](#project-labels).
### Generate default labels
If a project or group has no labels, you can generate a default set of project or group
-labels from the label list page. The page will show a **Generate a default set of labels**
-button if the list is empty, and clicking it will add the following default labels
+labels from the label list page. The page shows a **Generate a default set of labels**
+button if the list is empty. Select the button to add the following default labels
to the project:
- `bug`
@@ -149,13 +157,13 @@ by preventing certain labels from being used together.
A label is scoped when it uses a special double-colon (`::`) syntax in the label’s
title, for example:
-![Sample scoped labels](img/labels_key_value_v12_1.png)
+![Scoped labels](img/labels_key_value_v13_5.png)
An issue, merge request or epic cannot have two scoped labels, of the form `key::value`,
-with the same `key`. Adding a new label with the same `key`, but a different `value` will
-cause the previous `key` label to be replaced with the new label.
+with the same `key`. Adding a new label with the same `key`, but a different `value`
+causes the previous `key` label to be replaced with the new label.
-Example use case:
+For example:
1. An issue is identified as being low priority, and a `priority::low` project
label is added to it.
@@ -188,7 +196,7 @@ This functionality is demonstrated in a video regarding
### Scoped labels with nested scopes
You can create a label with a nested scope by using multiple double colons `::` when creating
-it. In this case, everything before the last `::` will be the scope.
+it. In this case, everything before the last `::` is the scope.
For example, `workflow::backend::review` and `workflow::backend::development` are valid
scoped labels, but they **can't** exist on the same issue at the same time, as they
@@ -202,13 +210,13 @@ both have different scopes, `workflow::frontend` and `workflow::backend`.
From the project label list page and the group label list page, you can click **Subscribe**
to the right of any label to enable [notifications](../profile/notifications.md) for that
-label. You will be notified whenever the label is assigned to an epic,
+label. You are notified whenever the label is assigned to an epic,
issue, or merge request.
If you are subscribing to a group label from within a project, you can select to subscribe
to label notifications for the project only, or the whole group.
-![Labels subscriptions](img/labels_subscriptions_v12_1.png)
+![Labels subscriptions](img/labels_subscriptions_v13_5.png)
## Label priority
@@ -222,7 +230,7 @@ from the group label list.
From the project label list page, star a label to indicate that it has a priority.
-![Labels prioritized](img/labels_prioritized_v12_1.png)
+![Labels prioritized](img/labels_prioritized_v13_5.png)
Drag starred labels up and down the list to change their priority, where higher in the list
means higher priority.
diff --git a/doc/user/project/merge_requests/accessibility_testing.md b/doc/user/project/merge_requests/accessibility_testing.md
index f3a0aac9ff4..a07a155745e 100644
--- a/doc/user/project/merge_requests/accessibility_testing.md
+++ b/doc/user/project/merge_requests/accessibility_testing.md
@@ -55,7 +55,7 @@ include:
```
creates an `a11y` job in your CI/CD pipeline, runs
-Pa11y against the webpages defined in `a11y_urls`, and builds an HTML report for each.
+Pa11y against the web pages defined in `a11y_urls`, and builds an HTML report for each.
The report for each URL is saved as an artifact that can be [viewed directly in your browser](../../../ci/pipelines/job_artifacts.md#browsing-artifacts).
diff --git a/doc/user/project/merge_requests/allow_collaboration.md b/doc/user/project/merge_requests/allow_collaboration.md
index 60d247ccc19..4ba0b50a3cf 100644
--- a/doc/user/project/merge_requests/allow_collaboration.md
+++ b/doc/user/project/merge_requests/allow_collaboration.md
@@ -28,11 +28,12 @@ source project and only lasts while the merge request is open. Once enabled,
upstream members will also be able to retry the pipelines and jobs of the
merge request:
-1. Enable the contribution while creating or editing a merge request.
+1. While creating or editing a merge request, select the checkbox **Allow
+ commits from members who can merge to the target branch**.
![Enable contribution](img/allow_collaboration.png)
-1. Once the merge request is created, you'll see that commits from members who
+1. Once the merge request is created, you can see that commits from members who
can merge to the target branch are allowed.
![Check that contribution is enabled](img/allow_collaboration_after_save.png)
diff --git a/doc/user/project/merge_requests/getting_started.md b/doc/user/project/merge_requests/getting_started.md
index a0be32e0708..462b8f68ece 100644
--- a/doc/user/project/merge_requests/getting_started.md
+++ b/doc/user/project/merge_requests/getting_started.md
@@ -111,6 +111,48 @@ It is also possible to manage multiple assignees:
- When creating a merge request.
- Using [quick actions](../quick_actions.md#quick-actions-for-issues-merge-requests-and-epics).
+## Reviewer
+
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/216054) in GitLab 13.5.
+> - It's [deployed behind a feature flag](../../../user/feature_flags.md), enabled by default.
+> - It's disabled on GitLab.com.
+> - It's not recommended for production use.
+> - To use it in GitLab self-managed instances, ask a GitLab administrator to [enable it](#enable-or-disable-merge-request-reviewers). **(CORE ONLY)**
+
+CAUTION: **Warning:**
+This feature might not be available to you. Check the **version history** note above for details.
+
+Requesting a code review is an important part of contributing code. However, deciding who should review
+your code and asking for a review are no easy tasks. Using the "assignee" field for both authors and
+reviewers makes it hard for others to determine who's doing what on a merge request.
+
+GitLab's Merge Request Reviewers easily allow authors to request a review as well as see the status of the
+review. By selecting one or more users from the **Reviewers** field in the merge request's right-hand
+sidebar, the assigned reviewers will receive a notification of the request to review the merge request.
+
+This makes it easy to determine the relevant roles for the users involved in the merge request, as well as formally requesting a review from a peer.
+
+To request it, open the **Reviewers** drop-down box to search for the user you wish to get a review from.
+
+### Enable or disable Merge Request Reviewers **(CORE ONLY)**
+
+Merge Request Reviewers is under development and not 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(:merge_request_reviewers)
+```
+
+To disable it:
+
+```ruby
+Feature.disable(:merge_request_reviewers)
+```
+
### Merge requests to close issues
If the merge request is being created to resolve an issue, you can
diff --git a/doc/user/project/merge_requests/img/commit_nav_v13_4.png b/doc/user/project/merge_requests/img/commit_nav_v13_4.png
new file mode 100644
index 00000000000..0ae6ce32693
--- /dev/null
+++ b/doc/user/project/merge_requests/img/commit_nav_v13_4.png
Binary files differ
diff --git a/doc/user/project/merge_requests/load_performance_testing.md b/doc/user/project/merge_requests/load_performance_testing.md
index daebd71e14f..2675f509eed 100644
--- a/doc/user/project/merge_requests/load_performance_testing.md
+++ b/doc/user/project/merge_requests/load_performance_testing.md
@@ -164,8 +164,8 @@ For example:
1. Capture the dynamic URL and save it into a `.env` file, e.g. `echo "ENVIRONMENT_URL=$CI_ENVIRONMENT_URL" >> review.env`.
1. Set the `.env` file to be a [job artifact](../../../ci/pipelines/job_artifacts.md#job-artifacts).
1. In the `load_performance` job:
- 1. Set it to depend on the review job, so it inherits the env file.
- 1. Set the `K6_DOCKER_OPTIONS` variable with the [Docker cli option for env files](https://docs.docker.com/engine/reference/commandline/run/#set-environment-variables--e---env---env-file), for example `--env-file review.env`.
+ 1. Set it to depend on the review job, so it inherits the environment file.
+ 1. Set the `K6_DOCKER_OPTIONS` variable with the [Docker CLI option for environment files](https://docs.docker.com/engine/reference/commandline/run/#set-environment-variables--e---env---env-file), for example `--env-file review.env`.
1. Configure the k6 test script to use the environment variable in it's steps.
Your `.gitlab-ci.yml` file might be similar to:
diff --git a/doc/user/project/merge_requests/merge_request_approvals.md b/doc/user/project/merge_requests/merge_request_approvals.md
index 185ab0e6298..4b4c930c7af 100644
--- a/doc/user/project/merge_requests/merge_request_approvals.md
+++ b/doc/user/project/merge_requests/merge_request_approvals.md
@@ -5,13 +5,16 @@ info: "To determine the technical writer assigned to the Stage/Group associated
type: reference, concepts
---
-# Merge Request Approvals
+# Merge Request Approvals **(CORE)**
+
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/580) in GitLab Enterprise Edition 7.2. Available in GitLab Core and higher tiers.
+> - Redesign [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/1979) in [GitLab Premium](https://about.gitlab.com/pricing/) 11.8 and [feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/10685) in 12.0.
Code review is an essential practice of every successful project, and giving your
approval once a merge request is in good shape is an important part of the review
process, as it clearly communicates the ability to merge the change.
-## Optional Approvals **(CORE ONLY)**
+## Optional Approvals
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/27426) in GitLab 13.2.
@@ -335,26 +338,6 @@ of your security team when a vulnerability would be introduced by a merge reques
For more information, see
[Security approvals in merge requests](../../application_security/index.md#security-approvals-in-merge-requests).
-### Enabling the new approvals interface
-
-Since [GitLab v12.0](https://gitlab.com/gitlab-org/gitlab/-/issues/10685), an updated approvals
-interface is available by default. In versions older than 12.0, the updated interface is not
-available unless the `approval_rules` feature flag is enabled, which can be done from
-the Rails console by instance administrators.
-
-Use these commands to start the Rails console:
-
-```shell
-# Omnibus GitLab
-gitlab-rails console
-
-# Installation from source
-cd /home/git/gitlab
-sudo -u git -H bin/rails console -e production
-```
-
-Then run `Feature.enable(:approval_rules)` to enable the updated interface.
-
<!-- ## Troubleshooting
Include any troubleshooting steps that you can foresee. If you know beforehand what issues
diff --git a/doc/user/project/merge_requests/revert_changes.md b/doc/user/project/merge_requests/revert_changes.md
index bc4fee749e8..6b302b0ff02 100644
--- a/doc/user/project/merge_requests/revert_changes.md
+++ b/doc/user/project/merge_requests/revert_changes.md
@@ -14,7 +14,7 @@ by clicking the **Revert** button in merge requests and commit details.
NOTE: **Note:**
The **Revert** button will only be available for merge requests
-created since GitLab 8.5. However, you can still revert a merge request
+created in GitLab 8.5 and later. However, you can still revert a merge request
by reverting the merge commit from the list of Commits page.
NOTE: **Note:**
diff --git a/doc/user/project/merge_requests/reviewing_and_managing_merge_requests.md b/doc/user/project/merge_requests/reviewing_and_managing_merge_requests.md
index 3a18cacde64..aef68e0e771 100644
--- a/doc/user/project/merge_requests/reviewing_and_managing_merge_requests.md
+++ b/doc/user/project/merge_requests/reviewing_and_managing_merge_requests.md
@@ -84,7 +84,7 @@ Click **Expand file** on any file to view the changes for that file.
> - For GitLab self-managed instances, GitLab administrators can opt to [disable it](#enable-or-disable-file-by-file-diff-navigation).
For larger merge requests it might sometimes be useful to review single files at a time. To enable,
-from your avatar on the top-right navbar, click **Settings**, and go to **Preferences** on the left
+from your avatar on the top-right navigation bar, click **Settings**, and go to **Preferences** on the left
sidebar. Scroll down to the **Behavior** section and select **Show one file at a time on merge request's Changes tab**.
Click **Save changes** to apply.
@@ -122,6 +122,8 @@ the commits to open the single-commit view. From there, you can navigate among t
by clicking the **Prev** and **Next** buttons on the top-right of the page or by using the
<kbd>X</kbd> and <kbd>C</kbd> keyboard shortcuts.
+![Merge requests commit navigation](img/commit_nav_v13_4.png)
+
### Incrementally expand merge request diffs
By default, the diff shows only the parts of a file which are changed.
diff --git a/doc/user/project/merge_requests/squash_and_merge.md b/doc/user/project/merge_requests/squash_and_merge.md
index 69a0dd6e84f..68f5478038a 100644
--- a/doc/user/project/merge_requests/squash_and_merge.md
+++ b/doc/user/project/merge_requests/squash_and_merge.md
@@ -65,8 +65,8 @@ meaningful commit messages and:
## Enabling squash for a merge request
Anyone who can create or edit a merge request can choose for it to be squashed
-on the merge request form. Users can select or unselect the checkbox at the moment
-they are creating the merge request:
+on the merge request form. Users can select or clear the check box when they
+create the merge request:
![Squash commits checkbox on edit form](img/squash_edit_form.png)
diff --git a/doc/user/project/merge_requests/test_coverage_visualization.md b/doc/user/project/merge_requests/test_coverage_visualization.md
index 56b5774f15b..bded1839f97 100644
--- a/doc/user/project/merge_requests/test_coverage_visualization.md
+++ b/doc/user/project/merge_requests/test_coverage_visualization.md
@@ -5,13 +5,10 @@ info: To determine the technical writer assigned to the Stage/Group associated w
type: reference, howto
---
-# Test Coverage Visualization **(CORE ONLY)**
+# Test Coverage Visualization
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/3708) in GitLab 12.9.
-> - [Feature flag enabled](https://gitlab.com/gitlab-org/gitlab/-/issues/211410) in GitLab 13.4.
-> - It's enabled on GitLab.com.
-> - It can be disabled per-project.
-> - To use it in GitLab self-managed instances, ask a GitLab administrator to [enable it](#enabling-the-feature). **(CORE ONLY)**
+> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/249811) in GitLab 13.5.
With the help of [GitLab CI/CD](../../../ci/README.md), you can collect the test
coverage information of your favorite testing or coverage-analysis tool, and visualize
@@ -58,7 +55,9 @@ NOTE: **Note:**
The Cobertura XML parser currently does not support the `sources` element and ignores it. It is assumed that
the `filename` of a `class` element contains the full path relative to the project root.
-## Example test coverage configuration
+## Example test coverage configurations
+
+### JavaScript example
The following [`gitlab-ci.yml`](../../../ci/yaml/README.md) example uses [Mocha](https://mochajs.org/)
JavaScript testing and [NYC](https://github.com/istanbuljs/nyc) coverage-tooling to
@@ -74,26 +73,84 @@ test:
cobertura: coverage/cobertura-coverage.xml
```
-## Enabling the feature
+### Java examples
+
+#### Maven example
-This feature comes with the `:coverage_report_view` feature flag enabled by
-default. It is enabled on GitLab.com. [GitLab administrators with access to the GitLab Rails console](../../../administration/feature_flags.md)
-can disable it for your instance. Test coverage visualization can be enabled or disabled per-project.
+The following [`gitlab-ci.yml`](../../../ci/yaml/README.md) example for Java uses [Maven](https://maven.apache.org/)
+to build the project and [Jacoco](https://www.eclemma.org/jacoco/) coverage-tooling to
+generate the coverage artifact.
+You can check the [Docker image configuration and scripts](https://gitlab.com/haynes/jacoco2cobertura) if you want to build your own image.
-To enable it:
+GitLab expects the artifact in the Cobertura format, so you have to execute a few
+scripts before uploading it. The `test-jdk11` job tests the code and generates an
+XML artifact. The `coverage-jdk-11` job converts the artifact into a Cobertura report:
-```ruby
-# Instance-wide
-Feature.enable(:coverage_report_view)
-# or by project
-Feature.enable(:coverage_report_view, Project.find(<project id>))
+```yaml
+test-jdk11:
+ stage: test
+ image: maven:3.6.3-jdk-11
+ script:
+ - 'mvn $MAVEN_CLI_OPTS clean org.jacoco:jacoco-maven-plugin:prepare-agent test jacoco:report'
+ artifacts:
+ paths:
+ - target/site/jacoco/jacoco.xml
+
+coverage-jdk11:
+ # Must be in a stage later than test-jdk11's stage.
+ # The `visualize` stage does not exist by default.
+ # Please define it first, or chose an existing stage like `deploy`.
+ stage: visualize
+ image: haynes/jacoco2cobertura:1.0.3
+ script:
+ # convert report from jacoco to cobertura
+ - 'python /opt/cover2cover.py target/site/jacoco/jacoco.xml src/main/java > target/site/cobertura.xml'
+ # read the <source></source> tag and prepend the path to every filename attribute
+ - 'python /opt/source2filename.py target/site/cobertura.xml'
+ needs: ["test-jdk11"]
+ dependencies:
+ - test-jdk11
+ artifacts:
+ reports:
+ cobertura: target/site/cobertura.xml
```
-To disable it:
+#### Gradle example
-```ruby
-# Instance-wide
-Feature.disable(:coverage_report_view)
-# or by project
-Feature.disable(:coverage_report_view, Project.find(<project id>))
+The following [`gitlab-ci.yml`](../../../ci/yaml/README.md) example for Java uses [Gradle](https://gradle.org/)
+to build the project and [Jacoco](https://www.eclemma.org/jacoco/) coverage-tooling to
+generate the coverage artifact.
+You can check the [Docker image configuration and scripts](https://gitlab.com/haynes/jacoco2cobertura) if you want to build your own image.
+
+GitLab expects the artifact in the Cobertura format, so you have to execute a few
+scripts before uploading it. The `test-jdk11` job tests the code and generates an
+XML artifact. The `coverage-jdk-11` job converts the artifact into a Cobertura report:
+
+```yaml
+test-jdk11:
+ stage: test
+ image: gradle:6.6.1-jdk11
+ script:
+ - 'gradle test jacocoTestReport' # jacoco must be configured to create an xml report
+ artifacts:
+ paths:
+ - build/jacoco/jacoco.xml
+
+coverage-jdk11:
+ # Must be in a stage later than test-jdk11's stage.
+ # The `visualize` stage does not exist by default.
+ # Please define it first, or chose an existing stage like `deploy`.
+ stage: visualize
+ image: haynes/jacoco2cobertura:1.0.3
+ script:
+ # convert report from jacoco to cobertura
+ - 'python /opt/cover2cover.py build/jacoco/jacoco.xml src/main/java > build/cobertura.xml'
+ # read the <source></source> tag and prepend the path to every filename attribute
+ - 'python /opt/source2filename.py build/cobertura.xml'
+ needs: ["test-jdk11"]
+ dependencies:
+ - test-jdk11
+ artifacts:
+ reports:
+ cobertura: build/cobertura.xml
```
diff --git a/doc/user/project/merge_requests/work_in_progress_merge_requests.md b/doc/user/project/merge_requests/work_in_progress_merge_requests.md
index d1833318a85..e7abf6e5fb6 100644
--- a/doc/user/project/merge_requests/work_in_progress_merge_requests.md
+++ b/doc/user/project/merge_requests/work_in_progress_merge_requests.md
@@ -5,7 +5,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
type: reference, concepts
---
-# Draft merge requests
+# Draft merge requests **(CORE)**
If a merge request is not yet ready to be merged, perhaps due to continued development
or open threads, you can prevent it from being accepted before it's ready by flagging
@@ -16,10 +16,12 @@ being merged, and it will stay disabled until the "Draft" flag has been removed.
## Adding the "Draft" flag to a merge request
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/32692) in GitLab 13.2, Work-In-Progress (WIP) merge requests were renamed to **Draft**. Support for using **WIP** will be removed in GitLab 14.0.
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/32692) in GitLab 13.2, Work-In-Progress (WIP) merge requests were renamed to **Draft**. Support for using **WIP** will be removed in GitLab 14.0.
+> - **Mark as draft** and **Mark as ready** buttons [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/227421) in GitLab 13.5.
There are several ways to flag a merge request as a Draft:
+- Click the **Mark as draft** button on the top-right corner of the merge request's page.
- Add `[Draft]`, `Draft:` or `(Draft)` to the start of the merge request's title. Clicking on
**Start the title with Draft:**, under the title box, when editing the merge request's
description will have the same effect.
@@ -28,15 +30,16 @@ There are several ways to flag a merge request as a Draft:
- Add the `/wip` [quick action](../quick_actions.md#quick-actions-for-issues-merge-requests-and-epics)
in a comment in the merge request. This is a toggle, and can be repeated
to change the status back. Note that any other text in the comment will be discarded.
-- Add `draft:` or `Draft:` to the start of a commit message targeting the merge request's
- source branch. This is not a toggle, and doing it again in another commit will have
- no effect.
+- Add `draft:`, `Draft:`, `fixup!`, or `Fixup!` to the beginning of a commit message targeting the
+ merge request's source branch. This is not a toggle, and doing it again in another
+ commit will have no effect.
## Removing the "Draft" flag from a merge request
Similar to above, when a Merge Request is ready to be merged, you can remove the
`Draft` flag in several ways:
+- Click the **Mark as ready** button on the top-right corner of the merge request's page.
- Remove `[Draft]`, `Draft:` or `(Draft)` from the start of the merge request's title. Clicking on
**Remove the Draft: prefix from the title**, under the title box, when editing the merge
request's description, will have the same effect.
diff --git a/doc/user/project/milestones/burndown_and_burnup_charts.md b/doc/user/project/milestones/burndown_and_burnup_charts.md
new file mode 100644
index 00000000000..327a52a05ab
--- /dev/null
+++ b/doc/user/project/milestones/burndown_and_burnup_charts.md
@@ -0,0 +1,142 @@
+---
+type: reference
+stage: Plan
+group: Project Management
+info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers
+---
+
+# Burndown and burnup charts **(STARTER)**
+
+[Burndown](#burndown-charts) and [burnup](#burnup-charts) charts show the progress of completing a milestone.
+
+![burndown and burnup chart](img/burndown_and_burnup_charts_v13_5.png)
+
+## Burndown charts
+
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/1540) in [GitLab Starter](https://about.gitlab.com/pricing/) 9.1 for project milestones.
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/5354) in [GitLab Premium](https://about.gitlab.com/pricing/) 10.8 for group milestones.
+> - [Added](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/6495) to [GitLab Starter](https://about.gitlab.com/pricing/) 11.2 for group milestones.
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/6903) [fixed burndown charts](#fixed-burndown-charts) in [GitLab Starter](https://about.gitlab.com/pricing/) 13.5.
+
+Burndown charts show the number of issues over the course of a milestone.
+
+![burndown chart](img/burndown_chart_v13_5.png)
+
+At a glance, you see the current state for the completion a given milestone.
+Without them, you would have to organize the data from the milestone and plot it
+yourself to have the same sense of progress.
+
+GitLab plots it for you and presents it in a clear and beautiful chart.
+
+<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
+For an overview, check the video demonstration on [Mapping work versus time with burndown charts](https://www.youtube.com/watch?v=zJU2MuRChzs).
+
+To view a project's burndown chart:
+
+1. In a project, navigate to **Issues > Milestones**.
+1. Select a milestone from the list.
+
+To view a group's burndown chart:
+
+1. In a group, navigate to **Issues > Milestones**.
+1. Select a milestone from the list.
+
+### Use cases for burndown charts
+
+Burndown charts are generally used for tracking and analyzing the completion of
+a milestone. Therefore, their use cases are tied to the
+[use you are assigning your milestone to](index.md).
+
+For example, suppose you lead a team of developers in a large company,
+and you follow this workflow:
+
+- Your company set the goal for the quarter to deliver 10 new features for your app
+ in the upcoming major release.
+- You create a milestone, and remind your team to assign that milestone to every new issue
+ and merge request that's part of the launch of your app.
+- Every week, you open the milestone, visualize the progress, identify the gaps,
+ and help your team to get their work done.
+- Every month, you check in with your supervisor, and show the progress of that milestone
+ from the burndown chart.
+- By the end of the quarter, your team successfully delivered 100% of that milestone, as
+ it was taken care of closely throughout the whole quarter.
+
+### How burndown charts work
+
+A burndown chart is available for every project or group milestone that has been attributed a **start
+date** and a **due date**.
+
+NOTE: **Note:**
+You're able to [promote project](index.md#promoting-project-milestones-to-group-milestones) to group milestones and still see the **burndown chart** for them, respecting license limitations.
+
+The chart indicates the project's progress throughout that milestone (for issues assigned to it).
+
+In particular, it shows how many issues were or are still open for a given day in the
+milestone's corresponding period.
+
+The burndown chart can also be toggled to display the cumulative open issue
+weight for a given day. When using this feature, make sure issue weights have
+been properly assigned, since an open issue with no weight adds zero to the
+cumulative value.
+
+### Fixed burndown charts
+
+For milestones created before GitLab 13.5, burndown charts have an additional toggle to
+switch between Legacy and Fixed views.
+
+| Legacy | Fixed |
+| ----- | ----- |
+| ![Legacy burndown chart, ](img/burndown_chart_legacy_v13_5.png) | ![Fixed burndown chart, showing a jump when a lot of issues were added to the milestone](img/burndown_chart_fixed_v13_5.png) |
+
+**Fixed burndown** charts track the full history of milestone activity, from its creation until the
+milestone expires. After the milestone due date passes, issues removed from the milestone no longer
+affect the chart.
+
+**Legacy burndown** charts track when issues were created and when they were last closed, not their
+full history. For each day, a legacy burndown chart takes the number of open issues and the issues
+created that day, and subtracts the number of issues closed that day.
+Issues that were created and assigned a milestone before its start date (and remain open as of the
+start date) are considered as having been opened on the start date.
+Therefore, when the milestone start date is changed, the number of opened issues on each day may
+change.
+Reopened issues are considered as having been opened on the day after they were last closed.
+
+## Burnup charts
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/6903) in [GitLab Starter](https://about.gitlab.com/pricing/) 13.5.
+
+Burnup charts show the assigned and completed work for a milestone.
+
+![burnup chart](img/burnup_chart_v13_5.png)
+
+To view a project's burnup chart:
+
+1. In a project, navigate to **Issues > Milestones**.
+1. Select a milestone from the list.
+
+To view a group's burnup chart:
+
+1. In a group, navigate to **Issues > Milestones**.
+1. Select a milestone from the list.
+
+### How burnup charts work
+
+Burnup charts have separate lines for total work and completed work. The total line
+shows when scope is reduced or added to a milestone. The completed work is a count
+of issues closed.
+
+Burnup charts can show either the total number of issues or total weight for each
+day of the milestone. Use the toggle above the charts to switch between total
+and weight.
+
+<!-- ## Troubleshooting
+
+Include any troubleshooting steps that you can foresee. If you know beforehand what issues
+one might have when setting this up, or when something is changed, or on upgrading, it's
+important to describe those, too. Think of things that may go wrong and include them here.
+This is important to minimize requests for support, and to avoid doc comments with
+questions that you know someone might ask.
+
+Each scenario can be a third-level heading, 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. -->
diff --git a/doc/user/project/milestones/burndown_charts.md b/doc/user/project/milestones/burndown_charts.md
index 0c8bba831a9..5aa5534dd37 100644
--- a/doc/user/project/milestones/burndown_charts.md
+++ b/doc/user/project/milestones/burndown_charts.md
@@ -1,89 +1,5 @@
---
-type: reference
-stage: Plan
-group: Project Management
-info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers
+redirect_to: './burndown_and_burnup_charts.md'
---
-# Burndown Charts **(STARTER)**
-
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/1540) in [GitLab Starter](https://about.gitlab.com/pricing/) 9.1 for project milestones.
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/5354) in [GitLab Premium](https://about.gitlab.com/pricing/) 10.8 for group milestones.
-> - [Added](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/6495) to [GitLab Starter](https://about.gitlab.com/pricing/) 11.2 for group milestones.
-> - Closed or reopened issues prior to GitLab 9.1 won't have a `closed_at`
-> value, so the burndown chart considers them as closed on the milestone
-> `start_date`. In that case, a warning will be displayed.
-
-## Overview
-
-Burndown Charts are visual representations of the progress of completing a milestone.
-
-![burndown chart](img/burndown_chart.png)
-
-At a glance, you see the current state for the completion a given milestone.
-Without them, you would have to organize the data from the milestone and plot it
-yourself to have the same sense of progress.
-
-GitLab Starter plots it for you and presents it in a clear and beautiful chart.
-
-<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
-For an overview, check the video demonstration on [Mapping work versus time with Burndown Charts](https://www.youtube.com/watch?v=zJU2MuRChzs).
-
-## Use cases
-
-Burndown Charts are generally used for tracking and analyzing the completion of
-a milestone. Therefore, their use cases are tied to the
-[use you are assigning your milestone to](index.md).
-
-For example, suppose you lead a team of developers in a large company,
-and you follow this workflow:
-
-- Your company set the goal for the quarter to deliver 10 new features for your app
- in the upcoming major release.
-- You create a milestone, and remind your team to assign that milestone to every new issue
- and merge request that's part of the launch of your app.
-- Every week, you open the milestone, visualize the progress, identify the gaps,
- and help your team to get their work done.
-- Every month, you check in with your supervisor, and show the progress of that milestone
- from the Burndown Chart.
-- By the end of the quarter, your team successfully delivered 100% of that milestone, as
- it was taken care of closely throughout the whole quarter.
-
-## How it works
-
-A Burndown Chart is available for every project or group milestone that has been attributed a **start
-date** and a **due date**.
-
-Find your project's **Burndown Chart** under **Project > Issues > Milestones**,
-and select a milestone from your current ones, while for group's, access the **Groups** dashboard,
-select a group, and go through **Issues > Milestones** on the sidebar.
-
-NOTE: **Note:**
-You're able to [promote project](index.md#promoting-project-milestones-to-group-milestones) to group milestones and still see the **Burndown Chart** for them, respecting license limitations.
-
-The chart indicates the project's progress throughout that milestone (for issues assigned to it).
-
-In particular, it shows how many issues were or are still open for a given day in the
-milestone's corresponding period.
-
-The Burndown Chart tracks when issues were created and when they were last closed—not their full history. For each day, it takes the number of issues still open and issues created that day and subtracts the number of issues closed that day.
-**Issues that were created and assigned a milestone before its start date—and remain open as of the start date—are considered as having been opened on the start date**. Therefore, when the milestone start date is changed the number of opened issues on each day may change.
-Reopened issues are
-considered as having been opened on the day after they were last closed.
-
-The Burndown Chart can also be toggled to display the cumulative open issue
-weight for a given day. When using this feature, make sure issue weights have
-been properly assigned, since an open issue with no weight adds zero to the
-cumulative value.
-
-<!-- ## Troubleshooting
-
-Include any troubleshooting steps that you can foresee. If you know beforehand what issues
-one might have when setting this up, or when something is changed, or on upgrading, it's
-important to describe those, too. Think of things that may go wrong and include them here.
-This is important to minimize requests for support, and to avoid doc comments with
-questions that you know someone might ask.
-
-Each scenario can be a third-level heading, 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. -->
+This document was moved to [another location](./burndown_and_burnup_charts.md).
diff --git a/doc/user/project/milestones/img/burndown_and_burnup_charts_v13_5.png b/doc/user/project/milestones/img/burndown_and_burnup_charts_v13_5.png
new file mode 100644
index 00000000000..8d6ba1d4fa7
--- /dev/null
+++ b/doc/user/project/milestones/img/burndown_and_burnup_charts_v13_5.png
Binary files differ
diff --git a/doc/user/project/milestones/img/burndown_chart_fixed_v13_5.png b/doc/user/project/milestones/img/burndown_chart_fixed_v13_5.png
new file mode 100644
index 00000000000..a532bfeeca0
--- /dev/null
+++ b/doc/user/project/milestones/img/burndown_chart_fixed_v13_5.png
Binary files differ
diff --git a/doc/user/project/milestones/img/burndown_chart_legacy_v13_5.png b/doc/user/project/milestones/img/burndown_chart_legacy_v13_5.png
new file mode 100644
index 00000000000..5824fc59ce5
--- /dev/null
+++ b/doc/user/project/milestones/img/burndown_chart_legacy_v13_5.png
Binary files differ
diff --git a/doc/user/project/milestones/img/burndown_chart.png b/doc/user/project/milestones/img/burndown_chart_v13_5.png
index e06b24f9907..e06b24f9907 100644
--- a/doc/user/project/milestones/img/burndown_chart.png
+++ b/doc/user/project/milestones/img/burndown_chart_v13_5.png
Binary files differ
diff --git a/doc/user/project/milestones/img/burnup_chart_v13_5.png b/doc/user/project/milestones/img/burnup_chart_v13_5.png
new file mode 100644
index 00000000000..a850caba348
--- /dev/null
+++ b/doc/user/project/milestones/img/burnup_chart_v13_5.png
Binary files differ
diff --git a/doc/user/project/milestones/index.md b/doc/user/project/milestones/index.md
index 9d02a22f91e..8cbed3de1c6 100644
--- a/doc/user/project/milestones/index.md
+++ b/doc/user/project/milestones/index.md
@@ -7,8 +7,6 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Milestones
-## Overview
-
Milestones in GitLab are a way to track issues and merge requests created to achieve a broader goal in a certain period of time.
Milestones allow you to organize issues and merge requests into a cohesive group, with an optional start date and an optional due date.
@@ -152,7 +150,7 @@ There are also tabs below these that show the following:
For project milestones in [GitLab Starter](https://about.gitlab.com/pricing/), a [burndown chart](burndown_charts.md) is in the milestone view, showing the progress of completing a milestone.
-![burndown chart](img/burndown_chart.png)
+![burndown chart](img/burndown_chart_v13_5.png)
### Group Burndown Charts **(STARTER)**
diff --git a/doc/user/project/new_ci_build_permissions_model.md b/doc/user/project/new_ci_build_permissions_model.md
index c3825371030..a7a72ca4d82 100644
--- a/doc/user/project/new_ci_build_permissions_model.md
+++ b/doc/user/project/new_ci_build_permissions_model.md
@@ -223,7 +223,7 @@ This is how an example usage can look like:
```yaml
test:
script:
- - docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY
+ - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
- docker pull $CI_REGISTRY/group/other-project:latest
- docker run $CI_REGISTRY/group/other-project:latest
```
@@ -236,5 +236,4 @@ to projects and their project permissions.
### API
-GitLab API cannot be used via `CI_JOB_TOKEN` but there is a [proposal](https://gitlab.com/gitlab-org/gitlab/-/issues/35067)
-to support it.
+GitLab API can be used via `CI_JOB_TOKEN`, see [the relevant documentation](../../api/README.md#gitlab-ci-job-token).
diff --git a/doc/user/project/pages/custom_domains_ssl_tls_certification/dns_concepts.md b/doc/user/project/pages/custom_domains_ssl_tls_certification/dns_concepts.md
index 735d27ec04d..810538ab460 100644
--- a/doc/user/project/pages/custom_domains_ssl_tls_certification/dns_concepts.md
+++ b/doc/user/project/pages/custom_domains_ssl_tls_certification/dns_concepts.md
@@ -30,6 +30,8 @@ to do it for you.
To help you out, we've gathered some instructions on how to do that
for the most popular hosting services:
+<!-- vale gitlab.Spelling = NO -->
+
- [Amazon](https://docs.aws.amazon.com/AmazonS3/latest/dev/website-hosting-custom-domain-walkthrough.html)
- [Bluehost](https://www.bluehost.com/help/article/dns-management-add-edit-or-delete-dns-entries)
- [Cloudflare](https://support.cloudflare.com/hc/en-us/articles/201720164-Creating-a-Cloudflare-account-and-adding-a-website)
@@ -41,6 +43,8 @@ for the most popular hosting services:
- [Media Temple](https://mediatemple.net/community/products/dv/204403794/how-can-i-change-the-dns-records-for-my-domain)
- [Microsoft](https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-2000-server/bb727018(v=technet.10))
+<!-- vale gitlab.Spelling = YES -->
+
If your hosting service is not listed above, you can just try to
search the web for `how to add dns record on <my hosting service>`.
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 badafa478ef..9b43dd58afe 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
@@ -61,7 +61,6 @@ according to the type of domain you want to use with your Pages site:
- [For subdomains](#for-subdomains), `subdomain.example.com`.
- [For both](#for-both-root-and-subdomains).
-NOTE: **Note:**
You can [configure IPv6 on self-managed instances](../../../../administration/pages/index.md#advanced-configuration),
but IPv6 is not currently configured for Pages on GitLab.com.
Follow [this issue](https://gitlab.com/gitlab-org/gitlab/-/issues/214718) for details.
@@ -250,8 +249,8 @@ You can use any certificate satisfying the following requirements:
- **A private key**, it's an encrypted key which validates
your PEM against your domain.
-NOTE: **Note:**
-[Cloudflare certificates](https://about.gitlab.com/blog/2017/02/07/setting-up-gitlab-pages-with-cloudflare-certificates/), for example, meet these requirements.
+For example, [Cloudflare certificates](https://about.gitlab.com/blog/2017/02/07/setting-up-gitlab-pages-with-cloudflare-certificates/)
+meet these requirements.
#### Steps
@@ -269,7 +268,6 @@ NOTE: **Note:**
just jumping a line between them.
1. Copy your private key and paste it in the last field.
-NOTE: **Note:**
**Do not** open certificates or encryption keys in
regular text editors. Always use code editors (such as
Sublime Text, Atom, Dreamweaver, Brackets, etc).
@@ -290,8 +288,8 @@ To enable this setting:
1. Navigate to your project's **Settings > Pages**.
1. Tick the checkbox **Force HTTPS (requires valid certificates)**.
-NOTE: **Note:**
-If you use Cloudflare CDN in front of GitLab Pages, make sure to set the SSL connection setting to `full` instead of `flexible`. For more details, see the [Cloudflare CDN directions](https://support.cloudflare.com/hc/en-us/articles/200170416-End-to-end-HTTPS-with-Cloudflare-Part-3-SSL-options#h_4e0d1a7c-eb71-4204-9e22-9d3ef9ef7fef).
+If you use Cloudflare CDN in front of GitLab Pages, make sure to set the SSL connection setting to
+`full` instead of `flexible`. For more details, see the [Cloudflare CDN directions](https://support.cloudflare.com/hc/en-us/articles/200170416-End-to-end-HTTPS-with-Cloudflare-Part-3-SSL-options#h_4e0d1a7c-eb71-4204-9e22-9d3ef9ef7fef).
<!-- ## Troubleshooting
diff --git a/doc/user/project/pages/custom_domains_ssl_tls_certification/lets_encrypt_integration.md b/doc/user/project/pages/custom_domains_ssl_tls_certification/lets_encrypt_integration.md
index 4b4b430b663..24b202dfdbd 100644
--- a/doc/user/project/pages/custom_domains_ssl_tls_certification/lets_encrypt_integration.md
+++ b/doc/user/project/pages/custom_domains_ssl_tls_certification/lets_encrypt_integration.md
@@ -25,7 +25,7 @@ This feature covers only certificates for **custom domains**, not the wildcard c
Before you can enable automatic provisioning of an SSL certificate for your domain, make sure you have:
-- Created a [project](../getting_started_part_two.md) in GitLab
+- Created a [project](../index.md#getting-started) in GitLab
containing your website's source code.
- Acquired a domain (`example.com`) and added a [DNS entry](index.md)
pointing it to your Pages website.
@@ -33,7 +33,6 @@ Before you can enable automatic provisioning of an SSL certificate for your doma
and verified your ownership.
- Verified your website is up and running, accessible through your custom domain.
-NOTE: **Note:**
GitLab's Let's Encrypt integration is enabled and available on GitLab.com.
For **self-managed** GitLab instances, make sure your administrator has
[enabled it](../../../../administration/pages/index.md#lets-encrypt-integration).
diff --git a/doc/user/project/pages/getting_started/new_or_existing_website.md b/doc/user/project/pages/getting_started/new_or_existing_website.md
index 86f36447b93..f19334a1764 100644
--- a/doc/user/project/pages/getting_started/new_or_existing_website.md
+++ b/doc/user/project/pages/getting_started/new_or_existing_website.md
@@ -2,4 +2,4 @@
redirect_to: 'pages_ci_cd_template.md'
---
-This document was moved to [pages_ci_cd_template.md](pages_ci_cd_template.md).
+This document was moved to [another location](pages_ci_cd_template.md).
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 de9bd97b262..7dc3d2197b5 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
@@ -53,4 +53,4 @@ You can take some **optional** further steps:
![Change repo's path](../img/change_path_v12_10.png)
- Now go to your SSG's configuration file and change the [base URL](../getting_started_part_one.md#urls-and-baseurls)
- from `"project-name"` to `""`. The project name setting varies by SSG and may not be in the config file.
+ from `"project-name"` to `""`. The project name setting varies by SSG and may not be in the configuration file.
diff --git a/doc/user/project/pages/getting_started_part_one.md b/doc/user/project/pages/getting_started_part_one.md
index 9272b1f9093..5ef0c4cc7b9 100644
--- a/doc/user/project/pages/getting_started_part_one.md
+++ b/doc/user/project/pages/getting_started_part_one.md
@@ -11,12 +11,9 @@ according to your intended website's URL.
## GitLab Pages default domain names
-NOTE: **Note:**
-If you use your own GitLab instance to deploy your
-site with GitLab Pages, check with your sysadmin what's your
-Pages wildcard domain. This guide is valid for any GitLab instance,
-you just need to replace Pages wildcard domain on GitLab.com
-(`*.gitlab.io`) with your own.
+If you use your own GitLab instance to deploy your site with GitLab Pages, verify your Pages
+wildcard domain with your sysadmin. This guide is valid for any GitLab instance, provided that you
+replace the Pages wildcard domain on GitLab.com (`*.gitlab.io`) with your own.
If you set up a GitLab Pages project on GitLab,
it will automatically be accessible under a
diff --git a/doc/user/project/pages/getting_started_part_three.md b/doc/user/project/pages/getting_started_part_three.md
index 9bc9fe97fd3..4bf5300aa13 100644
--- a/doc/user/project/pages/getting_started_part_three.md
+++ b/doc/user/project/pages/getting_started_part_three.md
@@ -1 +1,5 @@
+---
+redirect_to: 'custom_domains_ssl_tls_certification/index.md'
+---
+
This document was moved to [another location](custom_domains_ssl_tls_certification/index.md).
diff --git a/doc/user/project/pages/index.md b/doc/user/project/pages/index.md
index 6c3b911d033..4f389716f08 100644
--- a/doc/user/project/pages/index.md
+++ b/doc/user/project/pages/index.md
@@ -124,3 +124,24 @@ If you are running a self-managed instance of GitLab (GitLab Community Edition a
[follow the administration steps](../../../administration/pages/index.md) to configure Pages.
<i class="fa fa-youtube-play youtube" aria-hidden="true"></i> Watch a [video tutorial](https://www.youtube.com/watch?v=dD8c7WNcc6s) about how to get started with GitLab Pages administration.
+
+## Security for GitLab Pages
+
+If your username is `foo`, your GitLab Pages website is located at `foo.gitlab.io`.
+GitLab allows usernames to contain a `.`, so a user named `bar.foo` could create
+a GitLab Pages website `bar.foo.gitlab.io` that effectively is a subdomain of your
+`foo.gitlab.io` website. Be careful if you use JavaScript to set cookies for your website.
+The safe way to manually set cookies with JavaScript is to not specify the `domain` at all:
+
+```javascript
+// Safe: This cookie is only visible to foo.gitlab.io
+document.cookie = "key=value";
+
+// Unsafe: This cookie is visible to foo.gitlab.io and its subdomains,
+// regardless of the presence of the leading dot.
+document.cookie = "key=value;domain=.foo.gitlab.io";
+document.cookie = "key=value;domain=foo.gitlab.io";
+```
+
+This issue doesn't affect users with a custom domain, or users who don't set any
+cookies manually with JavaScript.
diff --git a/doc/user/project/pages/introduction.md b/doc/user/project/pages/introduction.md
index cea6bab1a50..b97d5328c07 100644
--- a/doc/user/project/pages/introduction.md
+++ b/doc/user/project/pages/introduction.md
@@ -173,7 +173,7 @@ Most modern browsers support downloading files in a compressed format. This
speeds up downloads by reducing the size of files.
Before serving an uncompressed file, Pages will check whether the same file
-exists with a `.gz` extension. If it does, and the browser supports receiving
+exists with a `.br` or `.gz` extension. If it does, and the browser supports receiving
compressed files, it will serve that version instead of the uncompressed one.
To take advantage of this feature, the artifact you upload to the Pages should
@@ -182,14 +182,17 @@ have this structure:
```plaintext
public/
├─┬ index.html
+│ | index.html.br
│ └ index.html.gz
│
├── css/
│ └─┬ main.css
+│ | main.css.br
│ └ main.css.gz
│
└── js/
└─┬ main.js
+ | main.js.br
â”” main.js.gz
```
@@ -202,6 +205,7 @@ pages:
script:
# Build the public/ directory first
- find public -type f -regex '.*\.\(htm\|html\|txt\|text\|js\|css\)$' -exec gzip -f -k {} \;
+ - find public -type f -regex '.*\.\(htm\|html\|txt\|text\|js\|css\)$' -exec brotli -f -k {} \;
```
By pre-compressing the files and including both versions in the artifact, Pages
@@ -255,9 +259,8 @@ instead. Here are some examples of what will happen given the above Pages site:
| `/other/index` | `200 OK` | `public/other/index.html` |
| `/other/index.html` | `200 OK` | `public/other/index.html` |
-NOTE: **Note:**
-When `public/data/index.html` exists, it takes priority over the `public/data.html`
-file for both the `/data` and `/data/` URL paths.
+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
diff --git a/doc/user/project/pages/lets_encrypt_for_gitlab_pages.md b/doc/user/project/pages/lets_encrypt_for_gitlab_pages.md
index 708d886b352..02d1dd7898a 100644
--- a/doc/user/project/pages/lets_encrypt_for_gitlab_pages.md
+++ b/doc/user/project/pages/lets_encrypt_for_gitlab_pages.md
@@ -33,9 +33,8 @@ To follow along with this tutorial, we assume you already have:
Once you have the requirements addressed, follow the instructions
below to learn how to obtain the certificate.
-NOTE: **Note:**
-The instructions below were tested on macOS Mojave. For other
-operating systems the steps might be slightly different. Follow the
+Note that these instructions were tested on macOS Mojave. For other operating systems the steps
+might be slightly different. Follow the
[CertBot instructions](https://certbot.eff.org/) according to your OS.
1. On your computer, open a terminal and navigate to your repository's
diff --git a/doc/user/project/pages/pages_access_control.md b/doc/user/project/pages/pages_access_control.md
index b6b881b961e..b3705a5835a 100644
--- a/doc/user/project/pages/pages_access_control.md
+++ b/doc/user/project/pages/pages_access_control.md
@@ -20,11 +20,9 @@ on your GitLab instance. When enabled, only
For a demonstration, see [Pages access controls](https://www.youtube.com/watch?v=tSPAr5mQYc8).
1. Navigate to your project's **Settings > General** and expand **Visibility, project features, permissions**.
-1. Toggle the **Pages** button to enable the access control.
- NOTE: **Note:**
- If you don't see the toggle button, that means that it's not enabled.
- Ask your administrator to [enable it](../../../administration/pages/index.md#access-control).
+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
with GitLab Pages, depending on your project's visibility:
@@ -48,9 +46,10 @@ can access the website.
## Terminating a Pages session
-If you want to log out from your Pages website,
-you can do so by revoking application access token for GitLab Pages:
+To sign out of your GitLab Pages website, revoke the application access token
+for GitLab Pages:
-1. Navigate to your profile's **Settings > Applications**.
-1. Find **Authorized applications** at the bottom of the page.
-1. Find **GitLab Pages** and press the **Revoke** button.
+1. In the top menu, select your profile, and then select **Settings**.
+1. In the left sidebar, select **Applications**.
+1. Scroll to the **Authorized applications** section, find the **GitLab Pages**
+ entry, and select its **Revoke** button.
diff --git a/doc/user/project/pages/redirects.md b/doc/user/project/pages/redirects.md
index ae7b1b4fa6e..60fbf368061 100644
--- a/doc/user/project/pages/redirects.md
+++ b/doc/user/project/pages/redirects.md
@@ -6,15 +6,15 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Create redirects for GitLab Pages
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab-pages/-/issues/24) in GitLab Pages 1.25.0 and GitLab 13.4.
-> - It's [deployed behind a feature flag](#enable-or-disable-redirects), disabled by default.
-> - To use it in GitLab self-managed instances, ask a GitLab administrator to [enable it](#enable-or-disable-redirects).
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab-pages/-/issues/24) in GitLab Pages 1.25.0 and GitLab 13.4 behind a feature flag, disabled by default.
+> - [Became enabled by default](https://gitlab.com/gitlab-org/gitlab-pages/-/merge_requests/367) in GitLab 13.5.
CAUTION: **Warning:**
This feature might not be available to you. Check the **version history** note above for details.
-In GitLab Pages, you can [enable](#enable-or-disable-redirects) the redirects feature to configure rules to forward one URL to another using HTTP redirects. GitLab Pages uses
-[Netlify style redirects](https://docs.netlify.com/routing/redirects/#syntax-for-the-redirects-file).
+In GitLab Pages, you can configure rules to forward one URL to another using
+[Netlify style](https://docs.netlify.com/routing/redirects/#syntax-for-the-redirects-file)
+HTTP redirects.
## Supported features
@@ -22,8 +22,10 @@ GitLab Pages only supports the
[`_redirects` plain text file syntax](https://docs.netlify.com/routing/redirects/#syntax-for-the-redirects-file),
and `.toml` files are not supported.
-Redirects are only supported at a basic level, and GitLab Pages doesn't support all
-[special options offered by Netlify](https://docs.netlify.com/routing/redirects/redirect-options/):
+Redirects are only supported at a basic level. GitLab Pages doesn't support all
+[special options offered by Netlify](https://docs.netlify.com/routing/redirects/redirect-options/).
+
+Note that supported paths must start with a forward slash `/`.
| Feature | Supported | Example |
| ------- | --------- | ------- |
@@ -37,12 +39,9 @@ Redirects are only supported at a basic level, and GitLab Pages doesn't support
| Redirect by country or language | **{dotted-circle}** No | `/ /anz 302 Country=au,nz` |
| Redirect by role | **{dotted-circle}** No | `/admin/* 200! Role=admin` |
-NOTE: **Note:**
-Supported paths must start with a forward slash `/`.
-
## Create redirects
-To create redirects after [enabling](#enable-or-disable-redirects) the feature,
+To create redirects,
create a configuration file named `_redirects` in the `public/` directory of your
GitLab Pages site.
@@ -78,8 +77,7 @@ is ignored because `hello.html` exists:
/projectname/hello.html /projectname/world.html 302
```
-NOTE: **Note:**
-GitLab does not support Netlify's
+GitLab doesn't support Netlify's
[force option](https://docs.netlify.com/routing/redirects/rewrites-proxies/#shadowing)
to change this behavior.
@@ -105,19 +103,19 @@ rule 10: valid
rule 11: valid
```
-## Enable or disable redirects
+## Disable redirects
-Redirects in GitLab Pages is under development and not ready for production use. It is
-deployed behind a feature flag that is **disabled by default**.
+Redirects in GitLab Pages is under development, and is deployed behind a feature flag
+that is **enabled by default**.
-For [Omnibus installations](../../../administration/pages/index.md), define the
+To disable redirects, for [Omnibus installations](../../../administration/pages/index.md), define the
`FF_ENABLE_REDIRECTS` environment variable in the
[global settings](../../../administration/pages/index.md#global-settings).
Add the following line to `/etc/gitlab/gitlab.rb` and
[reconfigure the instance](../../../administration/restart_gitlab.md#omnibus-gitlab-reconfigure).
```ruby
-gitlab_pages['env']['FF_ENABLE_REDIRECTS'] = 'true'
+gitlab_pages['env']['FF_ENABLE_REDIRECTS'] = 'false'
```
For [source installations](../../../administration/pages/source.md), define the
@@ -125,6 +123,6 @@ For [source installations](../../../administration/pages/source.md), define the
[restart GitLab](../../../administration/restart_gitlab.md#installations-from-source):
```shell
-export FF_ENABLE_REDIRECTS="true"
+export FF_ENABLE_REDIRECTS="false"
/path/to/pages/bin/gitlab-pages -config gitlab-pages.conf
```
diff --git a/doc/user/project/protected_branches.md b/doc/user/project/protected_branches.md
index 3d0cb1bf3a5..7265fd330e3 100644
--- a/doc/user/project/protected_branches.md
+++ b/doc/user/project/protected_branches.md
@@ -48,7 +48,7 @@ that the `master` branch is protected by default.
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/5081) in GitLab 8.11.
-Since GitLab 8.11, we added another layer of branch protection which provides
+In GitLab 8.11 and later, we added another layer of branch protection which provides
more granular management of protected branches. The "Developers can push"
option was replaced by an "Allowed to push" setting which can be set to
allow/prohibit Maintainers and/or Developers to push to a protected branch.
@@ -185,6 +185,8 @@ When enabled, all merge requests targeting these branches will require approval
by a Code Owner per matched rule before they can be merged.
Additionally, direct pushes to the protected branch are denied if a rule is matched.
+[Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/35097) in [GitLab Premium](https://about.gitlab.com/pricing/) 13.5, users and groups who are allowed to push to protected branches do not require a merge request to merge their feature branches. Thus, they can skip merge request approval rules.
+
## Running pipelines on protected branches
The permission to merge or push to protected branches is used to define if a user can
diff --git a/doc/user/project/quick_actions.md b/doc/user/project/quick_actions.md
index 518cf472b50..2f1b05f481e 100644
--- a/doc/user/project/quick_actions.md
+++ b/doc/user/project/quick_actions.md
@@ -39,22 +39,22 @@ The following quick actions are applicable to descriptions, discussions and thre
| `/copy_metadata <!merge_request>` | ✓ | ✓ | | Copy labels and milestone from another merge request in the project. |
| `/copy_metadata <#issue>` | ✓ | ✓ | | Copy labels and milestone from another issue in the project. |
| `/create_merge_request <branch name>` | ✓ | | | Create a new merge request starting from the current issue. |
-| `/done` | ✓ | ✓ | ✓ | Mark To-Do as done. |
+| `/done` | ✓ | ✓ | ✓ | Mark to do as done. |
| `/due <date>` | ✓ | | | Set due date. Examples of valid `<date>` include `in 2 days`, `this Friday` and `December 31st`. |
| `/duplicate <#issue>` | ✓ | | | Close this issue and mark as a duplicate of another issue. **(CORE)** Also, mark both as related. **(STARTER)** |
| `/epic <epic>` | ✓ | | | Add to epic `<epic>`. The `<epic>` value should be in the format of `&epic`, `group&epic`, or a URL to an epic. **(PREMIUM)** |
| `/estimate <<W>w <DD>d <hh>h <mm>m>` | ✓ | ✓ | | Set time estimate. For example, `/estimate 1w 3d 2h 14m`. |
| `/iteration *iteration:"iteration name"` | ✓ | | | Set iteration. For example, to set the `Late in July` iteration: `/iteration *iteration:"Late in July"` ([introduced in GitLab 13.1](https://gitlab.com/gitlab-org/gitlab/-/issues/196795)). **(STARTER)** |
| `/label ~label1 ~label2` | ✓ | ✓ | ✓ | Add one or more labels. Label names can also start without a tilde (`~`), but mixed syntax is not supported. |
-| `/lock` | ✓ | ✓ | | Lock the thread. |
+| `/lock` | ✓ | ✓ | | Lock the discussions. |
| `/merge` | | ✓ | | Merge changes. Depending on the project setting, this may be [when the pipeline succeeds](merge_requests/merge_when_pipeline_succeeds.md), adding to a [Merge Train](../../ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/index.md), etc. |
| `/milestone %milestone` | ✓ | ✓ | | Set milestone. |
| `/move <path/to/project>` | ✓ | | | Move this issue to another project. |
| `/parent_epic <epic>` | | | ✓ | Set parent epic to `<epic>`. The `<epic>` value should be in the format of `&epic`, `group&epic`, or a URL to an epic ([introduced in GitLab 12.1](https://gitlab.com/gitlab-org/gitlab/-/issues/10556)). **(ULTIMATE)** |
| `/promote` | ✓ | | | Promote issue to epic. **(PREMIUM)** |
| `/publish` | ✓ | | | Publish issue to an associated [Status Page](../../operations/incident_management/status_page.md) ([Introduced in GitLab 13.0](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/30906)) **(ULTIMATE)** |
-| `/reassign @user1 @user2` | ✓ | ✓ | | Change assignee. **(STARTER)** |
-| `/relabel ~label1 ~label2` | ✓ | ✓ | ✓ | Replace existing labels with those specified. |
+| `/reassign @user1 @user2` | ✓ | ✓ | | Replace current assignees with those specified. **(STARTER)** |
+| `/relabel ~label1 ~label2` | ✓ | ✓ | ✓ | Replace current labels with those specified. |
| `/relate #issue1 #issue2` | ✓ | | | Mark issues as related. **(STARTER)** |
| `/remove_child_epic <epic>` | | | ✓ | Remove child epic from `<epic>`. The `<epic>` value should be in the format of `&epic`, `group&epic`, or a URL to an epic ([introduced in GitLab 12.0](https://gitlab.com/gitlab-org/gitlab/-/issues/7330)). **(ULTIMATE)** |
| `/remove_due_date` | ✓ | | | Remove due date. |
@@ -74,11 +74,12 @@ The following quick actions are applicable to descriptions, discussions and thre
| `/tableflip <comment>` | ✓ | ✓ | ✓ | Append the comment with `(╯°□°)╯︵ â”»â”â”»`. |
| `/target_branch <local branch name>` | | ✓ | | Set target branch. |
| `/title <new title>` | ✓ | ✓ | ✓ | Change title. |
-| `/todo` | ✓ | ✓ | ✓ | Add a To-Do. |
+| `/todo` | ✓ | ✓ | ✓ | Add a to do. |
| `/unassign @user1 @user2` | ✓ | ✓ | | Remove specific assignees. **(STARTER)** |
| `/unassign` | ✓ | ✓ | | Remove all assignees. |
-| `/unlabel ~label1 ~label2` or `/remove_label ~label1 ~label2` | ✓ | ✓ | ✓ | Remove all or specific labels. |
-| `/unlock` | ✓ | ✓ | | Unlock the thread. |
+| `/unlabel ~label1 ~label2` or `/remove_label ~label1 ~label2` | ✓ | ✓ | ✓ | Remove specified labels. |
+| `/unlabel` or `/remove_label` | ✓ | ✓ | ✓ | Remove all labels. |
+| `/unlock` | ✓ | ✓ | | Unlock the discussions. |
| `/unsubscribe` | ✓ | ✓ | ✓ | Unsubscribe from notifications. |
| `/weight <value>` | ✓ | | | Set weight. Valid options for `<value>` include `0`, `1`, `2`, and so on. **(STARTER)** |
| `/wip` | | ✓ | | Toggle the Work In Progress status. |
diff --git a/doc/user/project/releases/index.md b/doc/user/project/releases/index.md
index 6c8aacd12b3..962d612cac1 100644
--- a/doc/user/project/releases/index.md
+++ b/doc/user/project/releases/index.md
@@ -47,22 +47,20 @@ To view a list of releases:
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/32812) in GitLab 12.9. Releases can be created directly in the GitLab UI.
-NOTE: **Note:**
-Only users with Developer permissions or higher can create releases.
-Read more about [Release permissions](../../../user/permissions.md#project-members-permissions).
-
You can create a release in the user interface, or by using the
[Releases API](../../../api/releases/index.md#create-a-release).
We recommend using the API to create releases as one of the last steps in your
CI/CD pipeline.
+Only users with Developer permissions or higher can create releases.
+Read more about [Release permissions](../../../user/permissions.md#project-members-permissions).
+
To create a new release through the GitLab UI:
1. Navigate to **Project overview > Releases** and click the **New release**
button.
1. In the [**Tag name**](#tag-name) box, enter a name.
- NOTE: **Note:**
Creating a release based on an existing tag using the user
interface is not yet supported. However, this is possible using the
[Releases API](../../../api/releases/index.md#create-a-release).
@@ -88,7 +86,6 @@ release tag. When the `released_at` date and time has passed, the badge is autom
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/26016) in GitLab 12.6. Asset link editing was [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/9427) in GitLab 12.10.
-NOTE: **Note:**
Only users with Developer permissions or higher can edit releases.
Read more about [Release permissions](../../../user/permissions.md#project-members-permissions).
@@ -225,7 +222,6 @@ The release title can be customized using the **Release title** field when
creating or editing a release. If no title is provided, the release's tag name
is used instead.
-NOTE: **Note:**
Guest users of private projects are allowed to view the **Releases** page
but are _not_ allowed to view details about the Git repository (in particular,
tag names). Because of this, release titles are replaced with a generic
@@ -254,7 +250,6 @@ Every release has a description. You can add any text you like, but we recommend
including a changelog to describe the content of your release. This helps users
quickly scan the differences between each release you publish.
-NOTE: **Note:**
[Git's tagging messages](https://git-scm.com/book/en/v2/Git-Basics-Tagging) and
Release note descriptions are unrelated. Description supports [Markdown](../../markdown.md).
@@ -334,8 +329,7 @@ generate release evidence for an existing release. Because of this, each release
can have multiple release evidence snapshots. You can view the release evidence and
its details on the Releases page.
-NOTE: **Note:**
-When the issue tracker is disabled, release evidence [cannot be downloaded](https://gitlab.com/gitlab-org/gitlab/-/issues/208397).
+When the issue tracker is disabled, release evidence [can't be downloaded](https://gitlab.com/gitlab-org/gitlab/-/issues/208397).
Here is an example of a release evidence object:
@@ -431,10 +425,13 @@ ruby:
junit: rspec.xml
```
-If the pipeline ran successfully, when you create your release, the `rspec.xml` file is saved as release evidence.
+If the pipeline ran successfully, when you create your release, the `rspec.xml` file is saved as
+release evidence.
-NOTE: **Note:**
-If you [schedule release evidence collection](#schedule-release-evidence-collection), some artifacts may already be expired by the time of evidence collection. To avoid this you can use the [`artifacts:expire_in`](../../../ci/yaml/README.md#artifactsexpire_in) keyword. Learn more in [this issue](https://gitlab.com/gitlab-org/gitlab/-/issues/222351).
+If you [schedule release evidence collection](#schedule-release-evidence-collection),
+some artifacts may already be expired by the time of evidence collection. To avoid this you can use
+the [`artifacts:expire_in`](../../../ci/yaml/README.md#artifactsexpire_in)
+keyword. Learn more in [this issue](https://gitlab.com/gitlab-org/gitlab/-/issues/222351).
### Schedule release evidence collection
@@ -449,21 +446,6 @@ In the API:
- If you do not specify a `released_at` date, release evidence is collected on the
date the release is created.
-### Disable release evidence display **(CORE ONLY)**
-
-The `:release_evidence_collection` feature flag is enabled by default in GitLab
-self-managed instances. To turn it off, ask a GitLab administrator with Rails console
-access to run the following command:
-
-```ruby
-Feature.disable(:release_evidence_collection)
-```
-
-NOTE: **Note:**
-Release evidence is collected regardless of this feature flag,
-which only enables or disables the display of the data on the
-Releases page.
-
## GitLab Releaser
> [Introduced](https://gitlab.com/gitlab-org/gitlab-releaser/-/merge_requests/6) in GitLab 12.10.
diff --git a/doc/user/project/repository/forking_workflow.md b/doc/user/project/repository/forking_workflow.md
index e90f0a7354c..b0aa7569579 100644
--- a/doc/user/project/repository/forking_workflow.md
+++ b/doc/user/project/repository/forking_workflow.md
@@ -14,7 +14,7 @@ can create a fork.
A fork is a personal copy of the repository and all its branches, which you create
in a namespace of your choice. This way you can make changes in your own fork and
-submit them through a merge request to the repo you don't have access to.
+submit them through a merge request to the repository you don't have access to.
## Creating a fork
diff --git a/doc/user/project/repository/img/repository_mirroring_push_settings.png b/doc/user/project/repository/img/repository_mirroring_push_settings.png
index d055cc580c4..9fc25dd3b25 100644
--- a/doc/user/project/repository/img/repository_mirroring_push_settings.png
+++ b/doc/user/project/repository/img/repository_mirroring_push_settings.png
Binary files differ
diff --git a/doc/user/project/repository/index.md b/doc/user/project/repository/index.md
index 536cae263b8..5473439a162 100644
--- a/doc/user/project/repository/index.md
+++ b/doc/user/project/repository/index.md
@@ -86,7 +86,7 @@ according to the markup language.
| [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](http://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` |
@@ -234,7 +234,7 @@ lock your files to prevent any conflicting changes.
## Repository's API
-You can access your repos via [repository API](../../../api/repositories.md).
+You can access your repositories via [repository API](../../../api/repositories.md).
## Clone in Apple Xcode
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 28fdda07b05..ad79fd8a8f9 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
@@ -19,7 +19,7 @@ over [`git filter-branch`](https://git-scm.com/docs/git-filter-branch) and
[BFG](https://rtyley.github.io/bfg-repo-cleaner/).
DANGER: **Danger:**
-Rewriting repository history is a destructive operation. Make sure to backup your repository before
+Rewriting repository history is a destructive operation. Make sure to back up your repository before
you begin. The best way back up a repository is to
[export the project](../settings/import_export.md#exporting-a-project-and-its-data).
@@ -230,6 +230,7 @@ This will:
- Run `git gc` against the repository to remove unreferenced objects. Repacking your repository will temporarily
cause the size of your repository to increase significantly, because the old pack files are not removed until the
new pack files have been created.
+- Unlink any unused LFS objects currently attached to your project, freeing up storage space.
- Recalculate the size of your repository on disk.
You will receive an email notification with the recalculated repository size after the cleanup has completed.
@@ -266,21 +267,20 @@ You can still:
- Create new issues.
- Clone the project.
-If you exceed the repository size limit, you might try to:
+If you exceed the repository size limit, you can:
1. Remove some data.
1. Make a new commit.
1. Push back to the repository.
-Perhaps you might also:
+If these actions are insufficient, you can also:
- Move some blobs to LFS.
- Remove some old dependency updates from history.
-Unfortunately, this workflow won't work. Deleting files in a commit doesn't actually reduce the size
-of the repository because the earlier commits and blobs still exist.
-
-What you need to do is rewrite history. We recommend the open-source community-maintained tool
+Unfortunately, this workflow doesn't work. Deleting files in a commit doesn't actually reduce the
+size of the repository, because the earlier commits and blobs still exist. Instead, you must rewrite
+history. We recommend the open-source community-maintained tool
[`git filter-repo`](https://github.com/newren/git-filter-repo).
NOTE: **Note:**
diff --git a/doc/user/project/repository/repository_mirroring.md b/doc/user/project/repository/repository_mirroring.md
index e1d2c20850b..188699e0c77 100644
--- a/doc/user/project/repository/repository_mirroring.md
+++ b/doc/user/project/repository/repository_mirroring.md
@@ -56,6 +56,7 @@ The following are some possible use cases for repository mirroring:
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/249) in GitLab Enterprise Edition 8.7.
> - [Moved to GitLab Core](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/18715) in 10.8.
+> - [LFS support over HTTPS added](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/40137) in 13.5
For an existing project, you can set up push mirroring as follows:
@@ -181,7 +182,7 @@ To set up a mirror from GitLab to AWS CodeCommit:
not confuse it with the IAM user ID or AWS keys of this user.
1. Copy or download special Git HTTPS user ID and password.
-1. In the AWS CodeCommit console, create a new repository to mirror from your GitLab repo.
+1. In the AWS CodeCommit console, create a new repository to mirror from your GitLab repository.
1. Open your new repository and click **Clone URL > Clone HTTPS** (not **Clone HTTPS (GRC)**).
1. In GitLab, open the repository to be push-mirrored.
1. Click **Settings > Repository** and expand **Mirroring repositories**.
@@ -192,7 +193,7 @@ To set up a mirror from GitLab to AWS CodeCommit:
```
Replace `<your_aws_git_userid>` with the AWS **special HTTPS Git user ID** from the IAM Git
- credentials created earlier. Replace `<your_codecommit_repo>` with the name of your repo in CodeCommit.
+ credentials created earlier. Replace `<your_codecommit_repo>` with the name of your repository in CodeCommit.
1. For **Mirror direction**, select **Push**.
1. For **Authentication method**, select **Password** and fill in the **Password** field with the special IAM Git clone user ID **password** created earlier in AWS.
diff --git a/doc/user/project/repository/x509_signed_commits/index.md b/doc/user/project/repository/x509_signed_commits/index.md
index 972a46ee7a3..9b420d84f50 100644
--- a/doc/user/project/repository/x509_signed_commits/index.md
+++ b/doc/user/project/repository/x509_signed_commits/index.md
@@ -26,7 +26,7 @@ For a commit or tag to be *verified* by GitLab:
[Omnibus install custom public certificates](https://docs.gitlab.com/omnibus/settings/ssl.html#install-custom-public-certificates).
- The signing time has to be within the time range of the [certificate validity](https://www.rfc-editor.org/rfc/rfc5280.html#section-4.1.2.5)
which is usually up to three years.
-- The signing time is equal or later then commit time.
+- The signing time is equal or later than commit time.
NOTE: **Note:**
Certificate revocation lists are checked on a daily basis via background worker.
diff --git a/doc/user/project/requirements/img/requirement_create_v13_5.png b/doc/user/project/requirements/img/requirement_create_v13_5.png
new file mode 100644
index 00000000000..ef1bab6e6d2
--- /dev/null
+++ b/doc/user/project/requirements/img/requirement_create_v13_5.png
Binary files differ
diff --git a/doc/user/project/requirements/img/requirement_view_v13_5.png b/doc/user/project/requirements/img/requirement_view_v13_5.png
new file mode 100644
index 00000000000..7fcb24a5e3b
--- /dev/null
+++ b/doc/user/project/requirements/img/requirement_view_v13_5.png
Binary files differ
diff --git a/doc/user/project/requirements/img/requirements_list_v13_1.png b/doc/user/project/requirements/img/requirements_list_v13_1.png
deleted file mode 100644
index 0ebda571928..00000000000
--- a/doc/user/project/requirements/img/requirements_list_v13_1.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/project/requirements/img/requirements_list_v13_5.png b/doc/user/project/requirements/img/requirements_list_v13_5.png
new file mode 100644
index 00000000000..19516e5e66e
--- /dev/null
+++ b/doc/user/project/requirements/img/requirements_list_v13_5.png
Binary files differ
diff --git a/doc/user/project/requirements/index.md b/doc/user/project/requirements/index.md
index 9d7d3914905..f533f8807d2 100644
--- a/doc/user/project/requirements/index.md
+++ b/doc/user/project/requirements/index.md
@@ -7,7 +7,8 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Requirements Management **(ULTIMATE)**
-> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/2703) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 12.10.
+> - [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/2703) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 12.10.
+> - The ability to add and edit a requirement's long description [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/224622) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 13.5.
With requirements, you can set criteria to check your products against. They can be based on users,
stakeholders, system, software, or anything else you find important to capture.
@@ -22,7 +23,7 @@ When a feature is no longer necessary, you can [archive the related requirement]
<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
For an overview, see [GitLab 12.10 Introduces Requirements Management](https://www.youtube.com/watch?v=uSS7oUNSEoU).
-![requirements list view](img/requirements_list_v13_1.png)
+![requirements list view](img/requirements_list_v13_5.png)
## Create a requirement
@@ -32,29 +33,43 @@ can create a new requirement.
To create a requirement:
1. From your project page, go to **{requirements}** **Requirements**.
-1. Click **New requirement**.
-1. Enter a descriptive title and click **Create requirement**.
+1. Select **New requirement**.
+1. Enter a title and description and select **Create requirement**.
-You will see the newly created requirement on the top of the list, as the requirements
-list is sorted by creation date in descending order.
+![requirement create view](img/requirement_create_v13_5.png)
+
+You can see the newly created requirement on the top of the list, with the requirements
+list being sorted by creation date, in descending order.
+
+## View a requirement
+
+You can view a requirement from the list by selecting it.
+
+![requirement view](img/requirement_view_v13_5.png)
+
+To edit a requirement while viewing it, select the **Edit** icon (**{pencil}**)
+next to the requirement title.
## Edit a requirement
+> The ability to mark a requirement as Satisfied [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/218607) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 13.5.
+
You can edit a requirement (if you have the necessary privileges) from the requirements
list page.
To edit a requirement:
-1. From the requirements list, click **Edit** (**{pencil}**).
-1. Update the title in text input field.
-1. Click **Save changes**.
+1. From the requirements list, select the **Edit** icon (**{pencil}**).
+1. Update the title and description in text input field. You can also mark a
+ requirement as satisfied in the edit form by using the check box **Satisfied**.
+1. Select **Save changes**.
## Archive a requirement
You can archive an open requirement (if you have the necessary privileges) while
you're in the **Open** tab.
-To archive a requirement, click **Archive** (**{archive}**).
+To archive a requirement, select **Archive** (**{archive}**).
As soon as a requirement is archived, it no longer appears in the **Open** tab.
@@ -64,7 +79,7 @@ You can view the list of archived requirements in the **Archived** tab.
![archived requirements list](img/requirements_archived_list_view_v13_1.png)
-To reopen an archived requirement, click **Reopen**.
+To reopen an archived requirement, select **Reopen**.
As soon as a requirement is reopened, it no longer appears in the **Archived** tab.
@@ -80,7 +95,7 @@ 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 **{requirements}** **Requirements > List**.
-1. Click the **Search or filter results** field. A dropdown menu appears.
+1. Select the **Search or filter results** field. A dropdown menu appears.
1. Select the requirement author from the dropdown or enter plain text to search by requirement title.
1. Press <kbd>Enter</kbd> on your keyboard to filter the list.
@@ -97,7 +112,7 @@ You can also sort the requirements list by:
GitLab supports [requirements test
reports](../../../ci/pipelines/job_artifacts.md#artifactsreportsrequirements) now.
You can add a job to your CI pipeline that, when triggered, marks all existing
-requirements as Satisfied.
+requirements as Satisfied (you may manually satisfy a requirement in the edit form [edit a requirement](#edit-a-requirement)).
### Add the manual job to CI
diff --git a/doc/user/project/service_desk.md b/doc/user/project/service_desk.md
index e9b07f54b91..0a1b81a6359 100644
--- a/doc/user/project/service_desk.md
+++ b/doc/user/project/service_desk.md
@@ -10,8 +10,6 @@ info: To determine the technical writer assigned to the Stage/Group associated w
> - [Moved](https://gitlab.com/gitlab-org/gitlab/-/issues/214839) to [GitLab Starter](https://about.gitlab.com/pricing/) in 13.0.
> - [Moved](https://gitlab.com/gitlab-org/gitlab/-/issues/215364) to [GitLab Core](https://about.gitlab.com/pricing/) in 13.2.
-## Overview
-
Service Desk is a module that allows your team to connect directly
with any external party through email right inside of GitLab; no external tools required.
An ongoing conversation right where your software is built ensures that user feedback ends
@@ -129,7 +127,7 @@ in the email, `%{ISSUE_PATH}` placeholder which will be replaced by
You can customize the email display name. Emails sent from Service Desk will have
this name in the `From` header. The default display name is `GitLab Support Bot`.
-### Using custom email address
+### Using custom email address **(CORE ONLY)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/2201) in [GitLab Premium](https://about.gitlab.com/pricing/) 13.0.
diff --git a/doc/user/project/settings/index.md b/doc/user/project/settings/index.md
index 395d4bf30c5..8fdcf58b5aa 100644
--- a/doc/user/project/settings/index.md
+++ b/doc/user/project/settings/index.md
@@ -8,7 +8,7 @@ type: reference, index, howto
# Project settings
NOTE: **Note:**
-Only project Maintainers and Admin users have the [permissions](../../permissions.md#project-members-permissions)
+Only project maintainers and administrators have the [permissions](../../permissions.md#project-members-permissions)
to access a project settings.
You can adjust your [project](../index.md) settings by navigating
@@ -145,7 +145,7 @@ Here you can run housekeeping, archive, rename, transfer, [remove a fork relatio
Archiving a project makes it read-only for all users and indicates that it's
no longer actively maintained. Projects that have been archived can also be
-unarchived. Only project Owners and Admin users have the
+unarchived. Only project owners and administrators have the
[permissions](../../permissions.md#project-members-permissions) to archive a project.
When a project is archived, the repository, packages, issues, merge requests, and all
@@ -162,12 +162,12 @@ To archive a project:
#### Unarchiving a project
Unarchiving a project removes the read-only restriction on a project, and makes it
-available in project listings. Only project Owners and Admin users have the
+available in project listings. Only project owners and administrators have the
[permissions](../../permissions.md#project-members-permissions) to unarchive a project.
To find an archived project:
-1. Sign in to GitLab as a user with project Owner or Admin permissions.
+1. Sign in to GitLab as a user with project owner or administrator permissions.
1. If you:
- Have the project's URL, open the project's page in your browser.
- Don't have the project's URL:
@@ -186,7 +186,7 @@ Next, to unarchive the project:
#### Renaming a repository
NOTE: **Note:**
-Only project Maintainers and Admin users have the [permissions](../../permissions.md#project-members-permissions) to rename a
+Only project maintainers and administrators have the [permissions](../../permissions.md#project-members-permissions) to rename a
repository. Not to be confused with a project's name where it can also be
changed from the [general project settings](#general-project-settings).
@@ -207,7 +207,7 @@ old URL won't be able to push or pull. Read more about what happens with the
#### Transferring an existing project into another namespace
NOTE: **Note:**
-Only project Owners and Admin users have the [permissions](../../permissions.md#project-members-permissions)
+Only project owners and administrators have the [permissions](../../permissions.md#project-members-permissions)
to transfer a project.
You can transfer an existing project into a [group](../../group/index.md) if:
@@ -229,13 +229,13 @@ read what happens with the
[redirects from the old project to the new one](../index.md#redirects-when-changing-repository-paths).
NOTE: **Note:**
-GitLab administrators can use the admin interface to move any project to any
+GitLab administrators can use the administration interface to move any project to any
namespace if needed.
#### Delete a project
NOTE: **Note:**
-Only project owners and admins have [permissions](../../permissions.md#project-members-permissions) to delete a project.
+Only project owners and administrators have [permissions](../../permissions.md#project-members-permissions) to delete a project.
To delete a project:
@@ -247,7 +247,7 @@ This action:
- Deletes a project including all associated resources (issues, merge requests etc).
- From [GitLab 13.2](https://gitlab.com/gitlab-org/gitlab/-/issues/220382) on [Premium or Silver](https://about.gitlab.com/pricing/) or higher tiers,
-group admins can [configure](../../group/index.md#enabling-delayed-project-removal) projects within a group
+group administrators can [configure](../../group/index.md#enabling-delayed-project-removal) projects within a group
to be deleted after a delayed period.
When enabled, actual deletion happens after number of days
specified in [instance settings](../../admin_area/settings/visibility_and_access_controls.md#default-deletion-delay).
@@ -270,7 +270,7 @@ To restore a project marked for deletion:
Forking is a great way to [contribute to a project](../repository/forking_workflow.md)
of which you're not a member.
If you want to use the fork for yourself and don't need to send
-[merge requests](../merge_requests.md) to the upstream project,
+[merge requests](../merge_requests/index.md) to the upstream project,
you can safely remove the fork relationship.
CAUTION: **Caution:**
diff --git a/doc/user/project/settings/project_access_tokens.md b/doc/user/project/settings/project_access_tokens.md
index 57cb610a2e9..b6ce21ebea6 100644
--- a/doc/user/project/settings/project_access_tokens.md
+++ b/doc/user/project/settings/project_access_tokens.md
@@ -1,21 +1,22 @@
---
-stage: Create
-group: Source Code
+stage: Manage
+group: Access
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/#designated-technical-writers"
type: reference, howto
---
-# Project access tokens **(CORE ONLY)**
+# Project access tokens
+
+NOTE: **Note:**
+Project access tokens are supported for self-managed instances on Core and above. They are also supported on GitLab.com Bronze and above.
> - [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/2587) in GitLab 13.0.
> - It was [deployed](https://gitlab.com/groups/gitlab-org/-/epics/2587) behind a feature flag, disabled by default.
> - [Became enabled by default](https://gitlab.com/gitlab-org/gitlab/-/issues/218722) in GitLab 13.3.
-> - It's disabled on GitLab.com.
-> - It can be enabled or disabled by project.
+> - [Became available on GitLab.com](https://gitlab.com/gitlab-org/gitlab/-/issues/235765) in 13.5.
> - It's recommended for production use.
-> - For GitLab self-managed instances, GitLab administrators can [disable it](#enable-or-disable-project-access-tokens).
-Project access tokens are scoped to a project and can be used to authenticate with the [GitLab API](../../../api/README.md#personalproject-access-tokens). You can also use project access tokens with Git to authenticate over HTTP or SSH.
+Project access tokens are scoped to a project and can be used to authenticate with the [GitLab API](../../../api/README.md#personalproject-access-tokens). You can also use project access tokens with Git to authenticate over HTTP.
Project access tokens expire on the date you define, at midnight UTC.
@@ -48,12 +49,12 @@ API calls made with a project access token are associated with the corresponding
These users will appear in **Members** but can not be modified.
Furthermore, the bot user can not be added to any other project.
-When the project access token is [revoked](#revoking-a-project-access-token) the bot user will be deleted and all
-records will be moved to a system-wide user with the username "Ghost User". For more information,
-see [Associated Records](../../profile/account/delete_account.md#associated-records).
+- The username is set to `project_{project_id}_bot` for the first access token, such as `project_123_bot`.
+- The username is set to `project_{project_id}_bot{bot_count}` for further access tokens, such as `project_123_bot1`.
+
+When the project access token is [revoked](#revoking-a-project-access-token) the bot user is then deleted and all records are moved to a system-wide user with the username "Ghost User". For more information, see [Associated Records](../../profile/account/delete_account.md#associated-records).
-Project bot users are a [GitLab-created service account](../../../subscriptions/self_managed/index.md#choose-the-number-of-users), but count as a licensed seat.
-These users will not count against your licensed seat in the future when [this issue](https://gitlab.com/gitlab-org/gitlab/-/issues/223695) is resolved.
+Project bot users are [GitLab-created service accounts](../../../subscriptions/self_managed/index.md#choose-the-number-of-users) and do not count as licensed seats.
## Revoking a project access token
@@ -74,33 +75,3 @@ the following table.
| `write_registry` | Allows write-access (push) to [container registry](../../packages/container_registry/index.md). |
| `read_repository` | Allows read-only access (pull) to the repository. |
| `write_repository` | Allows read-write access (pull, push) to the repository. |
-
-### Enable or disable project access tokens
-
-Project access tokens are deployed behind a feature flag that is **enabled by default**.
-[GitLab administrators with access to the GitLab Rails console](../../../administration/feature_flags.md)
-can disable it for your instance, globally or by project.
-
-To disable it globally:
-
-```ruby
-Feature.disable(:resource_access_token)
-```
-
-To disable it for a specific project:
-
-```ruby
-Feature.disable(:resource_access_token, project)
-```
-
-To enable it globally:
-
-```ruby
-Feature.enable(:resource_access_token)
-```
-
-To enable it for a specific project:
-
-```ruby
-Feature.enable(:resource_access_token, project)
-```
diff --git a/doc/user/project/static_site_editor/img/front_matter_ui_v13_4.png b/doc/user/project/static_site_editor/img/front_matter_ui_v13_4.png
new file mode 100644
index 00000000000..89864858ed3
--- /dev/null
+++ b/doc/user/project/static_site_editor/img/front_matter_ui_v13_4.png
Binary files differ
diff --git a/doc/user/project/static_site_editor/index.md b/doc/user/project/static_site_editor/index.md
index ce14cefba92..8a2f62ec7a2 100644
--- a/doc/user/project/static_site_editor/index.md
+++ b/doc/user/project/static_site_editor/index.md
@@ -6,50 +6,43 @@ type: reference, how-to
description: "The static site editor enables users to edit content on static websites without prior knowledge of the underlying templating language, site architecture or Git commands."
---
-# Static Site Editor
+# Static Site Editor **(CORE)**
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/28758) in GitLab 12.10.
> - WYSIWYG editor [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/214559) in GitLab 13.0.
-> - Support for adding images through the WYSIWYG editor [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/216640) in GitLab 13.1.
-> - Markdown front matter hidden on the WYSIWYG editor [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/216834) in GitLab 13.1.
-> - Support for `*.md.erb` files [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/223171) in GitLab 13.2.
> - Non-Markdown content blocks uneditable on the WYSIWYG mode [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/216836) in GitLab 13.3.
-DANGER: **Danger:**
-In GitLab 13.0, we [introduced breaking changes](https://gitlab.com/gitlab-org/gitlab/-/issues/213282)
-to the URL structure of the Static Site Editor. Follow the instructions in this
-[snippet](https://gitlab.com/gitlab-org/project-templates/static-site-editor-middleman/snippets/1976539)
-to update your project with the latest changes.
-
-Static Site Editor enables users to edit content on static websites without
+Static Site Editor (SSE) enables users to edit content on static websites without
prior knowledge of the underlying templating language, site architecture, or
Git commands. A contributor to your project can quickly edit a Markdown page
and submit the changes for review.
## Use cases
-The Static Site Editors allows collaborators to submit changes to static site
+The Static Site Editor allows collaborators to submit changes to static site
files seamlessly. For example:
-- Non-technical collaborators can easily edit a page directly from the browser; they don't need to know Git and the details of your project to be able to contribute.
+- Non-technical collaborators can easily edit a page directly from the browser;
+ they don't need to know Git and the details of your project to be able to contribute.
- Recently hired team members can quickly edit content.
-- Temporary collaborators can jump from project to project and quickly edit pages instead of having to clone or fork every single project they need to submit changes to.
+- Temporary collaborators can jump from project to project and quickly edit pages instead
+ of having to clone or fork every single project they need to submit changes to.
## Requirements
- In order use the Static Site Editor feature, your project needs to be
-pre-configured with the [Static Site Editor Middleman template](https://gitlab.com/gitlab-org/project-templates/static-site-editor-middleman).
-- The editor needs to be logged into GitLab and needs to be a member of the
-project (with Developer or higher permission levels).
+ pre-configured with the [Static Site Editor Middleman template](https://gitlab.com/gitlab-org/project-templates/static-site-editor-middleman).
+- You need to be logged into GitLab and be a member of the
+ project (with Developer or higher permission levels).
## How it works
-The Static Site Editor is in an early stage of development and only works for
+The Static Site Editor is in an early stage of development and only supports
Middleman sites for now. You have to use a specific site template to start
using it. The project template is configured to deploy a [Middleman](https://middlemanapp.com/)
static website with [GitLab Pages](../pages/index.md).
-Once your website is up and running, you'll see a button **Edit this page** on
+Once your website is up and running, an **Edit this page** button displays on
the bottom-left corner of its pages:
![Edit this page button](img/edit_this_page_button_v12_10.png)
@@ -65,44 +58,128 @@ creates a new branch, commits their changes, and opens a merge request. The
editor lands directly on the merge request, and then they can assign it to
a colleague for review.
-## Getting started
+## Set up your project
First, set up the project. Once done, you can use the Static Site Editor to
-easily edit your content.
-
-### Set up your project
-
-1. To get started, create a new project from the
-[Static Site Editor - Middleman](https://gitlab.com/gitlab-org/project-templates/static-site-editor-middleman)
-template. You can either [fork it](../repository/forking_workflow.md#creating-a-fork)
-or [create a new project from a template](../../../gitlab-basics/create-project.md#built-in-templates).
-1. Edit the `data/config.yml` file adding your project's path.
-1. Editing the file triggers a CI/CD pipeline to deploy your project with GitLab Pages.
+easily [edit your content](#edit-content).
+
+1. To get started, create a new project from the [Static Site Editor - Middleman](https://gitlab.com/gitlab-org/project-templates/static-site-editor-middleman)
+ template. You can either [fork it](../repository/forking_workflow.md#creating-a-fork)
+ or [create a new project from a template](../../../gitlab-basics/create-project.md#built-in-templates).
+1. Edit the [`data/config.yml`](#configuration-files) configuration file
+ to replace `<username>` and `<project-name>` with the proper values for
+ your project's path. This triggers a CI/CD pipeline to deploy your project
+ with GitLab Pages.
1. When the pipeline finishes, from your project's left-side menu, go to **Settings > Pages** to find the URL of your new website.
1. Visit your website and look at the bottom-left corner of the screen to see the new **Edit this page** button.
-Anyone satisfying the [requirements](#requirements) will be able to edit the
+Anyone satisfying the [requirements](#requirements) can edit the
content of the pages without prior knowledge of Git or of your site's
codebase.
-NOTE: **Note:**
-From GitLab 13.1 onwards, the YAML front matter of Markdown files is hidden on the
-WYSIWYG editor to avoid unintended changes. To edit it, use the Markdown editing mode, the regular
-GitLab file editor, or the Web IDE.
+## Edit content
+
+> - Support for modifying the default merge request title and description [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/216861) in GitLab 13.5.
+
+After setting up your project, you can start editing content directly from the Static Site Editor.
+
+To edit a file:
+
+1. Visit the page you want to edit.
+1. Click the **Edit this page** button.
+1. The file is opened in the Static Site Editor in **WYSIWYG** mode. If you
+ wish to edit the raw Markdown instead, you can toggle the **Markdown** mode
+ in the bottom-right corner.
+1. When you're done, click **Submit changes...**.
+1. (Optional) Adjust the default title and description of the merge request that will be submitted with your changes.
+1. Click **Submit changes**.
+1. A new merge request is automatically created and you can assign a colleague for review.
+
+### Text
+
+> Support for `*.md.erb` files [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/223171) in GitLab 13.2.
+
+The Static Site Editors supports Markdown files (`.md`, `.md.erb`) for editing text.
+
+### Images
+
+> - Support for adding images through the WYSIWYG editor [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/216640) in GitLab 13.1.
+
+You can add image files on the WYSIWYG mode by clicking the image icon (**{doc-image}**).
+From there, link to a URL, add optional [ALT text](https://moz.com/learn/seo/alt-text),
+and you're done. The link can reference images already hosted in your project, an asset hosted
+externally on a content delivery network, or any other external URL. The editor renders thumbnail previews
+so you can verify the correct image is included and there aren't any references to missing images.
+default directory (`source/images/`).
+
+### Videos
-### Use the Static Site Editor to edit your content
+> - Support for embedding YouTube videos through the WYSIWYG editor [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/216642) in GitLab 13.5.
-For instance, suppose you are a recently hired technical writer at a large
-company and a new feature has been added to the company product.
+You can embed YouTube videos on the WYSIWYG mode by clicking the video icon (**{live-preview}**).
+The following URL/ID formats are supported:
-1. You are assigned the task of updating the documentation.
-1. You visit a page and see content that needs to be edited.
-1. Click the **Edit this page** button on the production site.
-1. The file is opened in the Static Site Editor in **WYSIWYG** mode. If you wish to edit the raw Markdown
- instead, you can toggle the **Markdown** mode in the bottom-right corner.
-1. You edit the file right there and click **Submit changes**.
-1. A new merge request is automatically created and you assign it to your colleague for review.
+- YouTube watch URL (e.g. `https://www.youtube.com/watch?v=0t1DgySidms`)
+- YouTube embed URL (e.g. `https://www.youtube.com/embed/0t1DgySidms`)
+- YouTube video ID (e.g. `0t1DgySidms`)
+
+### Front matter
+
+> - Markdown front matter hidden on the WYSIWYG editor [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/216834) in GitLab 13.1.
+> - Ability to edit page front matter [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/235921) in GitLab 13.5.
+
+Front matter is a flexible and convenient way to define page-specific variables in data files
+intended to be parsed by a static site generator. It is commonly used for setting a page's
+title, layout template, or author, but can be used to pass any kind of metadata to the
+generator as the page renders out to HTML. Included at the very top of each data file, the
+front matter is often formatted as YAML or JSON and requires consistent and accurate syntax.
+
+To edit the front matter from the Static Site Editor you can use the GitLab's regular file editor,
+the Web IDE, or easily update the data directly from the WYSIWYG editor:
+
+1. Click the **Page settings** button on the bottom-right to reveal a web form with the data you
+ have on the page's front matter. The form is populated with the current data:
+
+ ![Editing page front matter in the Static Site Editor](img/front_matter_ui_v13_4.png)
+
+1. Update the values as you wish and close the panel.
+1. When you're done, click **Submit changes...**.
+1. Describe your changes (add a commit message).
+1. Click **Submit changes**.
+1. Click **View merge request** and GitLab will take you there.
+
+Note that support for adding new attributes to the page's front matter from the form is not supported
+yet. You can do so by editing the file locally, through the GitLab regular file editor, or through the Web IDE. Once added, the form will load the new fields.
+
+## Configuration files
+
+The Static Site Editor uses Middleman's configuration file, `data/config.yml`
+to customize the behavior of the project itself and to control the **Edit this
+page** button, rendered through the file [`layout.erb`](https://gitlab.com/gitlab-org/project-templates/static-site-editor-middleman/-/blob/master/source/layouts/layout.erb).
+
+To [configure the project template to your own project](#set-up-your-project),
+you must replace the `<username>` and `<project-name>` in the `data/config.yml`
+file with the proper values for your project's path.
+
+[Other Static Site Generators](#using-other-static-site-generators) used with
+the Static Site Editor may use different configuration files or approaches.
+
+## Using Other Static Site Generators
+
+Although Middleman is the only Static Site Generator currently officially supported
+by the Static Site Editor, you can configure your project's build and deployment
+to use a different Static Site Generator. In this case, use the Middleman layout
+as an example, and follow a similar approach to properly render an **Edit this page**
+button in your Static Site Generator's layout.
+
+## Upgrade from GitLab 12.10 to 13.0
+
+In GitLab 13.0, we [introduced breaking changes](https://gitlab.com/gitlab-org/gitlab/-/issues/213282)
+to the URL structure of the Static Site Editor. Follow the instructions in this
+[snippet](https://gitlab.com/gitlab-org/project-templates/static-site-editor-middleman/snippets/1976539)
+to update your project with the 13.0 changes.
## Limitations
-- The Static Site Editor still cannot be quickly added to existing Middleman sites. Follow this [epic](https://gitlab.com/groups/gitlab-org/-/epics/2784) for updates.
+- The Static Site Editor still cannot be quickly added to existing Middleman sites.
+ Follow this [epic](https://gitlab.com/groups/gitlab-org/-/epics/2784) for updates.
diff --git a/doc/user/project/web_ide/index.md b/doc/user/project/web_ide/index.md
index 821b42af049..4da9b5f88ff 100644
--- a/doc/user/project/web_ide/index.md
+++ b/doc/user/project/web_ide/index.md
@@ -32,7 +32,7 @@ file path fragments to start seeing results.
## Syntax highlighting
As expected from an IDE, syntax highlighting for many languages within
-the Web IDE will make your direct editing even easier.
+the Web IDE makes your direct editing even easier.
The Web IDE currently provides:
@@ -79,7 +79,7 @@ which apply to the entire Web IDE screen.
> - Support for validation based on custom schemas [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/226982) in [GitLab Premium](https://about.gitlab.com/pricing/) 13.4.
The Web IDE provides validation support for certain JSON and YAML files using schemas
-based on the [JSON Schema Store](https://www.schemastore.org/json/).
+based on the [JSON Schema Store](https://www.schemastore.org/json/).
### Predefined schemas
@@ -143,7 +143,7 @@ The Web IDE supports configuration of certain editor settings by using
[`.editorconfig` files](https://editorconfig.org/). When opening a file, the
Web IDE looks for a file named `.editorconfig` in the current directory
and all parent directories. If a configuration file is found and has settings
-that match the file's path, these settings will be enforced on the opened file.
+that match the file's path, these settings are enforced on the opened file.
The Web IDE currently supports the following `.editorconfig` settings:
@@ -166,7 +166,7 @@ review the list of changed files.
Once you have finalized your changes, you can add a commit message, commit the
changes and directly create a merge request. In case you don't have write
-access to the selected branch, you will see a warning, but still be able to create
+access to the selected branch, you see a warning, but can still create
a new branch and start a merge request.
To discard a change in a particular file, click the **Discard changes** button on that
@@ -201,8 +201,7 @@ left.
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/19318) in [GitLab Core](https://about.gitlab.com/pricing/) 11.0.
To switch between your authored and assigned merge requests, click the
-dropdown in the top of the sidebar to open a list of merge requests. You will
-need to commit or discard all your changes before switching to a different merge
+dropdown in the top of the sidebar to open a list of merge requests. You need to commit or discard all your changes before switching to a different merge
request.
## Switching branches
@@ -211,7 +210,7 @@ request.
To switch between branches of the current project repository, click the dropdown
in the top of the sidebar to open a list of branches.
-You will need to commit or discard all your changes before switching to a
+You need to commit or discard all your changes before switching to a
different branch.
## Markdown editing
@@ -226,7 +225,7 @@ supports [GitLab Flavored Markdown](../../markdown.md#gitlab-flavored-markdown-g
You can also upload any local images by pasting them directly in the Markdown file.
The image is uploaded to the same directory and is named `image.png` by default.
If another file already exists with the same name, a numeric suffix is automatically
-added to the file name.
+added to the filename.
## Live Preview
@@ -249,7 +248,7 @@ The Live Preview feature needs to be enabled in the GitLab instances
admin settings. Live Preview is enabled for all projects on
GitLab.com
-![Admin Live Preview setting](img/admin_live_preview_v13_0.png)
+![Administrator Live Preview setting](img/admin_live_preview_v13_0.png)
Once you have done that, you can preview projects with a `package.json` file and
a `main` entry point inside the Web IDE. An example `package.json` is shown
@@ -292,7 +291,7 @@ to work:
[enabled](../../../administration/integration/terminal.md#enabling-and-disabling-terminal-support). **(ULTIMATE ONLY)**
If you have the terminal open and the job has finished with its tasks, the
-terminal will block the job from finishing for the duration configured in
+terminal blocks the job from finishing for the duration configured in
[`[session_server].session_timeout`](https://docs.gitlab.com/runner/configuration/advanced-configuration.html#the-session_server-section)
until you close the terminal window.
@@ -308,15 +307,15 @@ In order to enable the Web IDE terminals you need to create the file
file is fairly similar to the [CI configuration file](../../../ci/yaml/README.md)
syntax but with some restrictions:
-- No global blocks can be defined (ie: `before_script` or `after_script`)
+- No global blocks can be defined (i.e., `before_script` or `after_script`)
- Only one job named `terminal` can be added to this file.
- Only the keywords `image`, `services`, `tags`, `before_script`, `script`, and
`variables` are allowed to be used to configure the job.
- To connect to the interactive terminal, the `terminal` job must be still alive
- and running, otherwise the terminal won't be able to connect to the job's session.
+ and running, otherwise the terminal cannot connect to the job's session.
By default the `script` keyword has the value `sleep 60` to prevent
the job from ending and giving the Web IDE enough time to connect. This means
- that, if you override the default `script` value, you'll have to add a command
+ that, if you override the default `script` value, you have to add a command
which would keep the job running, like `sleep`.
In the code below there is an example of this configuration file:
@@ -333,40 +332,39 @@ terminal:
NODE_ENV: "test"
```
-Once the terminal has started, the console will be displayed and we could access
+Once the terminal has started, the console is displayed and we could access
the project repository files.
**Important**. The terminal job is branch dependent. This means that the
-configuration file used to trigger and configure the terminal will be the one in
+configuration file used to trigger and configure the terminal is the one in
the selected branch of the Web IDE.
-If there is no configuration file in a branch, an error message will be shown.
+If there is no configuration file in a branch, an error message is shown.
### Running interactive terminals in the Web IDE
-If Interactive Terminals are available for the current user, the **Terminal** button
-will be visible in the right sidebar of the Web IDE. Click this button to open
+If Interactive Terminals are available for the current user, the **Terminal** button is visible in the right sidebar of the Web IDE. Click this button to open
or close the terminal tab.
-Once open, the tab will show the **Start Web Terminal** button. This button may
+Once open, the tab shows the **Start Web Terminal** button. This button may
be disabled if the environment is not configured correctly. If so, a status
-message will describe the issue. Here are some reasons why **Start Web Terminal**
+message describes the issue. Here are some reasons why **Start Web Terminal**
may be disabled:
- `.gitlab/.gitlab-webide.yml` does not exist or is set up incorrectly.
- No active private runners are available for the project.
-If active, clicking the **Start Web Terminal** button will load the terminal view
+If active, clicking the **Start Web Terminal** button loads the terminal view
and start connecting to the runner's terminal. At any time, the **Terminal** tab
-can be closed and reopened and the state of the terminal will not be affected.
+can be closed and reopened and the state of the terminal is not affected.
When the terminal is started and is successfully connected to the runner, then the
-runner's shell prompt will appear in the terminal. From here, you can enter
-commands that will be executed within the runner's environment. This is similar
+runner's shell prompt appears in the terminal. From here, you can enter
+commands executed within the runner's environment. This is similar
to running commands in a local terminal or through SSH.
While the terminal is running, it can be stopped by clicking **Stop Terminal**.
-This will disconnect the terminal and stop the runner's terminal job. From here,
+This disconnects the terminal and stops the runner's terminal job. From here,
click **Restart Terminal** to start a new terminal session.
### File syncing to web terminal
@@ -408,14 +406,14 @@ terminal:
more information.
- `$CI_PROJECT_DIR` is a
[predefined environment variable](../../../ci/variables/predefined_variables.md)
- for GitLab Runner. This is where your project's repository will be.
+ for GitLab Runners. This is where your project's repository resides.
Once you have configured the web terminal for file syncing, then when the web
-terminal is started, a **Terminal** status will be visible in the status bar.
+terminal is started, a **Terminal** status is visible in the status bar.
![Web IDE Client Side Evaluation](img/terminal_status.png)
-Changes made to your files via the Web IDE will sync to the running terminal
+Changes made to your files via the Web IDE sync to the running terminal
when:
- <kbd>Ctrl</kbd> + <kbd>S</kbd> (or <kbd>Cmd</kbd> + <kbd>S</kbd> on Mac)
@@ -425,9 +423,12 @@ when:
### Limitations
-Interactive Terminals is in a beta phase and will continue to be improved upon in upcoming
-releases. In the meantime, please note that the user is limited to having only one
-active terminal at a time.
+The Web IDE has a few limitations:
+
+- Interactive Terminals is in a beta phase and continues to be improved in upcoming releases. In the meantime, please note that the user is limited to having only one
+ active terminal at a time.
+
+- LFS files can be rendered and displayed but they cannot be updated and committed using the Web IDE. If an LFS file is modified and pushed to the repository, the LFS pointer in the repository will be overwritten with the modified LFS file content.
### Troubleshooting
diff --git a/doc/user/project/wiki/img/wiki_sidebar.png b/doc/user/project/wiki/img/wiki_sidebar.png
deleted file mode 100644
index ff39c861a73..00000000000
--- a/doc/user/project/wiki/img/wiki_sidebar.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/project/wiki/img/wiki_sidebar_v13_5.png b/doc/user/project/wiki/img/wiki_sidebar_v13_5.png
new file mode 100644
index 00000000000..0f445d61d71
--- /dev/null
+++ b/doc/user/project/wiki/img/wiki_sidebar_v13_5.png
Binary files differ
diff --git a/doc/user/project/wiki/index.md b/doc/user/project/wiki/index.md
index 40ef5e216fd..64608b9a915 100644
--- a/doc/user/project/wiki/index.md
+++ b/doc/user/project/wiki/index.md
@@ -5,7 +5,7 @@ info: "To determine the technical writer assigned to the Stage/Group associated
type: reference, how-to
---
-# Wiki
+# Wiki **(CORE)**
A separate system for documentation called Wiki, is built right into each
GitLab project. It is enabled by default on all new projects and you can find
@@ -19,6 +19,9 @@ You can create Wiki pages in the web interface or
[locally using Git](#adding-and-editing-wiki-pages-locally) since every Wiki is
a separate Git repository.
+[Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/13195) in [GitLab Premium](https://about.gitlab.com/pricing/) 13.5,
+**group wikis** became available. Their usage is similar to project wikis, with a few [limitations](../../group/index.md#group-wikis).
+
## First time creating the Home page
The first time you visit a Wiki, you will be directed to create the Home page.
@@ -127,10 +130,12 @@ be preceded by the slash (`/`) character.
## Viewing a list of all created wiki pages
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/17673/) in GitLab 13.5, wiki pages are displayed as a nested tree in the sidebar and pages overview.
+
Every wiki has a sidebar from which a short list of the created pages can be
found. The list is ordered alphabetically.
-![Wiki sidebar](img/wiki_sidebar.png)
+![Wiki sidebar](img/wiki_sidebar_v13_5.png)
If you have many pages, not all will be listed in the sidebar. Click on
**View All Pages** to see all of them.
@@ -163,48 +168,13 @@ Similar to versioned diff file views, you can see the changes made in a given Wi
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/14902) in **GitLab 12.10.**
> - Git events were [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/216014) in **GitLab 13.0.**
-> - It's enabled on GitLab.com.
-> - Git access activity creation is managed by a feature flag.
-> - To use it in GitLab self-managed instances, ask a GitLab administrator to [enable it](#enable-or-disable-wiki-events-in-git). **(CORE ONLY)**
+> - [Feature flag for Git events was removed](https://gitlab.com/gitlab-org/gitlab/-/issues/258665) in **GitLab 13.5**
Wiki events (creation, deletion, and updates) are tracked by GitLab and
displayed on the [user profile](../../profile/index.md#user-profile),
[group](../../group/index.md#view-group-activity),
and [project](../index.md#project-activity) activity pages.
-### Enable or disable Wiki events in Git **(CORE ONLY)**
-
-Tracking wiki events through Git is under development and not 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 for your instance.
-
-To enable it:
-
-```ruby
-Feature.enable(:wiki_events_on_git_push)
-```
-
-To enable for just a particular project:
-
-```ruby
-project = Project.find_by_full_path('your-group/your-project')
-Feature.enable(:wiki_events_on_git_push, project)
-```
-
-To disable it:
-
-```ruby
-Feature.disable(:wiki_events_on_git_push)
-```
-
-To disable for just a particular project:
-
-```ruby
-project = Project.find_by_full_path('your-group/your-project')
-Feature.disable(:wiki_events_on_git_push, project)
-```
-
## Adding and editing wiki pages locally
Since wikis are based on Git repositories, you can clone them locally and edit
diff --git a/doc/user/search/advanced_global_search.md b/doc/user/search/advanced_global_search.md
index 53ec8b35631..3152229c39f 100644
--- a/doc/user/search/advanced_global_search.md
+++ b/doc/user/search/advanced_global_search.md
@@ -1,6 +1,6 @@
---
-stage: Create
-group: Editor
+stage: Enablement
+group: Global Search
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/#designated-technical-writers"
type: reference
---
diff --git a/doc/user/search/advanced_search_syntax.md b/doc/user/search/advanced_search_syntax.md
index 804d4c540ac..ed5ecc17a8b 100644
--- a/doc/user/search/advanced_search_syntax.md
+++ b/doc/user/search/advanced_search_syntax.md
@@ -1,6 +1,6 @@
---
-stage: Create
-group: Editor
+stage: Enablement
+group: Global Search
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/#designated-technical-writers"
type: reference
---
@@ -62,6 +62,7 @@ The Advanced Search Syntax also supports the use of filters. The available filte
- filename: Filters by filename. You can use the glob (`*`) operator for fuzzy matching.
- path: Filters by path. You can use the glob (`*`) operator for fuzzy matching.
- extension: Filters by extension in the filename. Please write the extension without a leading dot. Exact match only.
+- blob: Filters by Git `object ID`. Exact match only.
To use them, simply add them to your query in the format `<filter_name>:<value>` without
any spaces between the colon (`:`) and the value.
@@ -72,17 +73,19 @@ Examples:
- Finding a file named `found_blob_spec.rb` with the text `CHANGELOG` inside of it: [`CHANGELOG filename:found_blob_spec.rb](https://gitlab.com/search?utf8=%E2%9C%93&snippets=&scope=blobs&repository_ref=&search=CHANGELOG+filename%3Afound_blob_spec.rb&group_id=9970&project_id=278964)
- Finding the text `EpicLinks` inside files with the `.rb` extension: [`EpicLinks extension:rb`](https://gitlab.com/search?utf8=%E2%9C%93&snippets=&scope=blobs&repository_ref=&search=EpicLinks+extension%3Arb&group_id=9970&project_id=278964)
- Finding the text `Sidekiq` in a file, when that file is in a path that includes `elastic`: [`Sidekiq path:elastic`](https://gitlab.com/search?utf8=%E2%9C%93&snippets=&scope=blobs&repository_ref=&search=Sidekiq+path%3Aelastic&group_id=9970&project_id=278964)
+- Finding the files represented by the Git object ID `998707b421c89bd9a3063333f9f728ef3e43d101`: [`* blob:998707b421c89bd9a3063333f9f728ef3e43d101`](https://gitlab.com/search?utf8=%E2%9C%93&snippets=false&scope=blobs&repository_ref=&search=*+blob%3A998707b421c89bd9a3063333f9f728ef3e43d101&group_id=9970)
- Syntax filters can be combined for complex filtering. Finding any file starting with `search` containing `eventHub` and with the `.js` extension: [`eventHub filename:search* extension:js`](https://gitlab.com/search?utf8=%E2%9C%93&snippets=&scope=blobs&repository_ref=&search=eventHub+filename%3Asearch*+extension%3Ajs&group_id=9970&project_id=278964)
#### Excluding filters
[Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/31684) in GitLab Starter 13.3.
-Filters can be inversed to **filter out** results from the result set, by prefixing the filter name with a `-` (hyphen) character, such as:
+Filters can be inverted to **filter out** results from the result set, by prefixing the filter name with a `-` (hyphen) character, such as:
- `-filename`
- `-path`
- `-extension`
+- `-blob`
Examples:
diff --git a/doc/user/search/img/basic_search.png b/doc/user/search/img/basic_search.png
new file mode 100644
index 00000000000..234805d5a4f
--- /dev/null
+++ b/doc/user/search/img/basic_search.png
Binary files differ
diff --git a/doc/user/search/img/basic_search_results.png b/doc/user/search/img/basic_search_results.png
new file mode 100644
index 00000000000..52aa2e3fe6c
--- /dev/null
+++ b/doc/user/search/img/basic_search_results.png
Binary files differ
diff --git a/doc/user/search/index.md b/doc/user/search/index.md
index 475a72385ac..412951f8a3b 100644
--- a/doc/user/search/index.md
+++ b/doc/user/search/index.md
@@ -32,7 +32,7 @@ You can also filter the results using the search and filter field, as described
You'll also find shortcuts to issues and merge requests created by you or assigned to you
on the search field on the top-right of your screen:
-![shortcut to your issues and mrs](img/issues_mrs_shortcut.png)
+![shortcut to your issues and merge requests](img/issues_mrs_shortcut.png)
### Filtering issue and merge request lists
@@ -129,14 +129,6 @@ characters to begin your search. For example, if you want to search for
issues that have the assignee "Simone Presley", you'll need to type at
least "Sim" before autocomplete gives any relevant results.
-## Code search
-
-To search through code or other documents in a single project, you can use
-the search field on the top-right of your screen while the project page is open.
-
-![code search dropdown](img/project_search_dropdown.png)
-![code search results](img/project_code_search.png)
-
## Search history
You can view recent searches by clicking on the little arrow-clock icon, which is to the left of the search input. Click the search entry to run that search again. This feature is available for issues and merge requests. Searches are stored locally in your browser.
@@ -155,24 +147,6 @@ Some filters can be added multiple times. These include but are not limited to a
![multiple assignees filtering](img/multiple_assignees.png)
-## Shortcut
-
-You'll also find a shortcut on the search field on the top-right of the project's dashboard to
-quickly access issues and merge requests created or assigned to you within that project:
-
-![search per project - shortcut](img/project_search.png)
-
-### Autocomplete suggestions
-
-You can also type in this search bar to see autocomplete suggestions for:
-
-- Projects and groups
-- Various help pages (try and type **API help**)
-- Project feature pages (try and type **milestones**)
-- Various settings pages (try and type **user settings**)
-- Recently viewed issues (try and type some word from the title of a recently viewed issue)
-- Recently viewed merge requests (try and type some word from the title of a recently merge request)
-
## To-Do List
Your [To-Do List](../todos.md#gitlab-to-do-list) can be searched by "to do" and "done".
@@ -219,6 +193,61 @@ and **Labels**, select multiple issues to add to a list of your choice:
![search and select issues to add to board](img/search_issues_board.png)
+## Shortcut
+
+You'll find a shortcut on the search field on the top-right of the project's dashboard to
+quickly access issues and merge requests created or assigned to you within that project:
+
+![search per project - shortcut](img/project_search.png)
+
+### Autocomplete suggestions
+
+You can also type in this search bar to see autocomplete suggestions for:
+
+- Projects and groups
+- Various help pages (try and type **API help**)
+- Project feature pages (try and type **milestones**)
+- Various settings pages (try and type **user settings**)
+- Recently viewed issues (try and type some word from the title of a recently viewed issue)
+- Recently viewed merge requests (try and type some word from the title of a recently viewed merge request)
+- Recently viewed epics (try and type some word from the title of a recently viewed epic)
+
+## Basic search
+
+The Basic search in GitLab is a global search service that allows you to search
+across the entire GitLab instance, within a group, or a single project. Basic search is
+backed by the database and allows searching in:
+
+- Projects
+- Issues
+- Merge requests
+- Milestones
+- Users
+- Epics (Group only)
+- Code (Project only)
+- Comments (Project only)
+- Commits (Project only)
+- Wiki (Project only)
+
+To start a search, type into the search bar on the top-right of the screen. You can always search
+in all GitLab and may also see the options to search within a group or project if you are in the
+group or project dashboard.
+
+![basic search](img/basic_search.png)
+
+Once the results are returned, you can modify the search, select a different type of data to
+search, or choose a specific group or project.
+
+![basic_search_results](img/basic_search_results.png)
+
+### Code search
+
+To search through code or other documents in a single project, you can use
+the search field on the top-right of your screen while the project page is open.
+
+![code search dropdown](img/project_search_dropdown.png)
+![code search results](img/project_code_search.png)
+
## Advanced Search **(STARTER)**
Leverage Elasticsearch for faster, more advanced code search across your entire
diff --git a/doc/user/snippets.md b/doc/user/snippets.md
index 15391f034a8..2d0c9d4f943 100644
--- a/doc/user/snippets.md
+++ b/doc/user/snippets.md
@@ -92,6 +92,40 @@ be changed to `http-a-weird-filename-me` to be included in the snippet's
repository. As snippets are stored by ID, changing their filenames will not break
direct or embedded links to the snippet.
+### Multiple files by Snippet
+
+> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/2829) in GitLab 13.5.
+
+GitLab Snippets support multiple files in one single snippet. It can be very handy
+when your code snippet is composed of multiple parts or when they relate
+to a certain context. For example:
+
+- A snippet that includes a script and its output.
+- A snippet that includes HTML, CSS, and JS code.
+- A snippet with a `docker-compose.yml` file and its associated `.env` file.
+- A `gulpfile.js` file coupled with a `package.json` file, which together can be used to bootstrap a project and manage its dependencies.
+
+Snippets support between 1 and 10 files. They can be managed via Git (since they're [versioned](#versioned-snippets)
+by a Git repository), through the [Snippets API](../api/snippets.md), or within the GitLab UI.
+
+![Multi-file Snippet](img/gitlab_snippet_v13_5.png)
+
+To add a new file to your snippet through the GitLab UI:
+
+1. Go to your snippet in the GitLab UI.
+1. Click **Edit** in the top right.
+1. Select **Add another file**.
+1. Add your content to the file in the form fields provided.
+1. Click **Save changes**.
+
+To delete a file from your snippet through the GitLab UI:
+
+1. Go to your snippet in the GitLab UI.
+1. Click **Edit** in the top right.
+1. Select **Delete file** alongside the file name of each file
+you wish to delete.
+1. Click **Save changes**.
+
### Cloning snippets
Snippets can be cloned as a regular Git repository using SSH or HTTPS. Click the **Clone**
@@ -114,16 +148,16 @@ see the documentation on [reducing repository size](../user/project/repository/r
### Limitations
- Binary files are not supported.
-- Creating or deleting branches is not supported. Only a default *master*.
-branch is used.
+- Creating or deleting branches is not supported. Only a default *master* branch is used.
- Git tags are not supported in snippet repositories.
-- Snippets' repositories are limited to one file. Attempting to push more
-than one file will result in an error.
+- Snippets' repositories are limited to 10 files. Attempting to push more
+than 10 files will result in an error.
- Revisions are not *yet* visible to the user on the GitLab UI, but
it's planned to be added in future iterations. See the [revisions tab issue](https://gitlab.com/gitlab-org/gitlab/-/issues/39271)
for updates.
- The [maximum size for a snippet](../administration/snippets/index.md#snippets-content-size-limit)
is 50 MB, by default.
+- Git LFS is not supported.
## Discover snippets
@@ -131,8 +165,8 @@ There are two main ways of how you can discover snippets in GitLab.
For exploring all snippets that are visible to you, you can go to the Snippets
dashboard of your GitLab instance via the top navigation. For GitLab.com you can
-find it [here](https://gitlab.com/dashboard/snippets). This navigates you to an
-overview that shows snippets you created and allows you to explore all snippets.
+navigate to an [overview]((https://gitlab.com/dashboard/snippets)) that shows snippets
+you created and allows you to explore all snippets.
If you want to discover snippets that belong to a specific project, you can navigate
to the Snippets page via the left side navigation on the project page.
diff --git a/doc/user/todos.md b/doc/user/todos.md
index 1fca3c0ab64..c48d2adfa45 100644
--- a/doc/user/todos.md
+++ b/doc/user/todos.md
@@ -15,7 +15,7 @@ spend your time. This can include taking an action, or keeping track of things
do your work, being able to get started quickly is important.
Your *To-Do List* offers a chronological list of items waiting for your input
-(known as *to-dos*) in a single dashboard.
+(known as *to do items*) in a single dashboard.
The To-Do List supports tracking [actions](#what-triggers-a-to-do) related to
the following:
@@ -26,18 +26,18 @@ the following:
![to-do screenshot showing a list of items to check on](img/todos_index.png)
-You can access your To-Do List by clicking the **{task-done}** To-Do List icon
-next to the search bar in the top navigation. If the to-do item count is:
+You can access your To-Do List by clicking the To-Do List icon (**{task-done}**)
+next to the search bar in the top navigation. If the to do item count is:
-- *Less than 100*, the number in blue is the number of to-do items.
+- *Less than 100*, the number in blue is the number of to do items.
- *100 or more*, the number displays as 99+. The exact number displays in the
To-Do List.
![To Do icon](img/todos_icon.png)
-## What triggers a to-do
+## What triggers a to do
-A to-do item appears on your To-Do List when:
+A to do item appears on your To-Do List when:
- An issue or merge request is assigned to you.
- You're `@mentioned` in the description or comment of an issue or merge request
@@ -51,29 +51,29 @@ A to-do item appears on your To-Do List when:
- You're the author.
- You're the user that set the merge request to automatically merge after a
pipeline succeeds.
-- [Since GitLab 13.2](https://gitlab.com/gitlab-org/gitlab/-/issues/12136), a
+- [In GitLab 13.2](https://gitlab.com/gitlab-org/gitlab/-/issues/12136) and later, a
merge request is removed from a
[merge train](../ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/index.md),
and you're the user that added it. **(PREMIUM)**
When several trigger actions occur for the same user on the same object (for
-example, an issue), GitLab displays only the first action as a single to-do
+example, an issue), GitLab displays only the first action as a single to do
item.
-To-do triggers aren't affected by [GitLab notification email settings](profile/notifications.md).
+To do item triggers aren't affected by [GitLab notification email settings](profile/notifications.md).
NOTE: **Note:**
-When a user no longer has access to a resource related to a to-do (such as an
-issue, merge request, project, or group), for security reasons GitLab deletes
-any related to-do items within the next hour. Deletion is delayed to prevent
-data loss, in the case where a user's access is accidentally revoked.
+When a user no longer has access to a resource related to a to do item (such as
+an issue, merge request, project, or group), for security reasons GitLab
+deletes any related to do items within the next hour. Deletion is delayed to
+prevent data loss, in the case where a user's access is accidentally revoked.
-### Directly addressing a to-do
+### Directly addressing a to do
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/7926) in GitLab 9.0.
-If you're mentioned at the start of a line, the to-do you receive will be listed
-as *directly addressed*. For example, in the following comment:
+If you're mentioned at the start of a line, the to do item you receive will be
+listed as *directly addressed*. For example, in the following comment:
```markdown
@alice What do you think? cc: @bob
@@ -87,23 +87,27 @@ as *directly addressed*. For example, in the following comment:
@erin @frank thank you!
```
-The people receiving directly addressed to-do items are `@alice`, `@erin`, and
-`@frank`. Directly addressed to-do items only differ from mentions in their type
+The people receiving directly addressed to do items are `@alice`, `@erin`, and
+`@frank`. Directly addressed to do items only differ from mentions in their type
for filtering purposes; otherwise, they appear as normal.
-### Manually creating a to-do
+### Manually creating a to do
-You can add an issue or merge request (or epic **(ULTIMATE)**) to your
-To-Do List by clicking its **Add a To Do** button.
+You can also add the following to your To-Do List by clicking the **Add a to do** button on an:
+
+- [Issue](project/issues/index.md)
+- [Merge Request](project/merge_requests/index.md)
+- [Epic](group/epics/index.md) **(ULTIMATE)**
+- [Design](project/issues/design_management.md)
![Adding a To Do from the issuable sidebar](img/todos_add_todo_sidebar.png)
-## Marking a to-do as done
+## Marking a to do as done
Any action to an issue or merge request (or epic **(ULTIMATE)**) will mark its
-corresponding to-do as done.
+corresponding to do item as done.
-Actions that dismiss to-do items include:
+Actions that dismiss to do items include:
- Changing the assignee
- Changing the milestone
@@ -111,27 +115,28 @@ Actions that dismiss to-do items include:
- Commenting on the issue
Your To-Do List is personal, and items are only marked as done if you take
-action. If you close the issue or merge request, your to-do is marked as done.
+action. If you close the issue or merge request, your to do item is marked as
+done.
To prevent other users from closing issues without you being notified, if
someone else closes, merges, or takes action on an issue or merge request (or
-epic **(ULTIMATE)**), your to-do will remain pending.
+epic **(ULTIMATE)**), your to do item remains pending.
-There's just one to-do for each of these, so mentioning a user many times in an
-issue will only trigger one to-do item.
+There's just one to do item for each of these, so mentioning a user many times
+in an issue only triggers one to do item.
-If no action is needed, you can manually mark the to-do as done by clicking its
-corresponding **Done** button to have GitLab remove the item from your
-To-Do List.
+If no action is needed, you can manually mark the to do item as done by
+clicking its corresponding **Done** button to have GitLab remove the item from
+your To-Do List.
-![A to-do in the To-Do List](img/todos_todo_list_item.png)
+![A to do in the To-Do List](img/todos_todo_list_item.png)
-You can also mark a to-do as done by clicking the **Mark as done** button in the
-sidebar of an issue or merge request (or epic **(ULTIMATE)**).
+You can also mark a to do item as done by clicking the **Mark as done** button
+in the sidebar of an issue or merge request (or epic **(ULTIMATE)**).
![Mark as done from the issuable sidebar](img/todos_mark_done_sidebar.png)
-You can mark all your to-do items as done at once by clicking the
+You can mark all your to do items as done at once by clicking the
**Mark all as done** button.
## Filtering your To-Do List
@@ -142,9 +147,9 @@ You can use the following types of filters with your To-Do List:
| ------- | ---------------------------------------------------------------- |
| Project | Filter by project. |
| Group | Filter by group. |
-| Author | Filter by the author that triggered the To Do. |
+| Author | Filter by the author that triggered the to do. |
| Type | Filter by issue, merge request, design, or epic. **(ULTIMATE)** |
-| Action | Filter by the action that triggered the To Do. |
+| Action | Filter by the action that triggered the to do. |
You can also filter by more than one of these at the same time. The previously
described [triggering actions](#what-triggers-a-to-do) include:
diff --git a/doc/user/upgrade_email_bypass.md b/doc/user/upgrade_email_bypass.md
index 027f7337228..35fddc4a1d4 100644
--- a/doc/user/upgrade_email_bypass.md
+++ b/doc/user/upgrade_email_bypass.md
@@ -82,7 +82,7 @@ As an administrator, you may also confirm a user in the [Admin Area](admin_area/
## What do I do if I am an administrator and I am locked out?
If you are an administrator and cannot otherwise verify your email address, sign in to your GitLab
-instance with a [Rails console session](../administration/troubleshooting/navigating_gitlab_via_rails_console.md#starting-a-rails-console-session).
+instance with a [Rails console session](../administration/operations/rails_console.md#starting-a-rails-console-session).
Once connected, run the following commands to confirm your administrator account:
```ruby
@@ -94,7 +94,7 @@ admin.save!
## How do I force-confirm all users on my self-managed instance?
If you are an administrator and would like to force-confirm all users on your system, sign in to your GitLab
-instance with a [Rails console session](../administration/troubleshooting/navigating_gitlab_via_rails_console.md#starting-a-rails-console-session).
+instance with a [Rails console session](../administration/operations/rails_console.md#starting-a-rails-console-session).
Once connected, run the following commands to confirm all user accounts:
```ruby
diff --git a/doc/web_hooks/web_hooks.md b/doc/web_hooks/web_hooks.md
deleted file mode 100644
index fffb6a5d86d..00000000000
--- a/doc/web_hooks/web_hooks.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../user/project/integrations/webhooks.md'
----
-
-This document was moved to [project/integrations/webhooks](../user/project/integrations/webhooks.md).
diff --git a/doc/workflow/README.md b/doc/workflow/README.md
deleted file mode 100644
index ce129f0663b..00000000000
--- a/doc/workflow/README.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../README.md'
----
-
-This document was moved to [another location](../README.md).
diff --git a/doc/workflow/add-user/add-user.md b/doc/workflow/add-user/add-user.md
deleted file mode 100644
index f1ec771dd9a..00000000000
--- a/doc/workflow/add-user/add-user.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../../user/project/members/index.md'
----
-
-This document was moved to [../../user/project/members/index.md](../../user/project/members/index.md)
diff --git a/doc/workflow/authorization_for_merge_requests.md b/doc/workflow/authorization_for_merge_requests.md
deleted file mode 100644
index 8e43d340613..00000000000
--- a/doc/workflow/authorization_for_merge_requests.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../user/project/merge_requests/authorization_for_merge_requests.md'
----
-
-This document was moved to [user/project/merge_requests/authorization_for_merge_requests](../user/project/merge_requests/authorization_for_merge_requests.md)
diff --git a/doc/workflow/award_emoji.md b/doc/workflow/award_emoji.md
deleted file mode 100644
index 02db97b8dd6..00000000000
--- a/doc/workflow/award_emoji.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../user/award_emojis.md'
----
-
-This document was moved to [another location](../user/award_emojis.md).
diff --git a/doc/workflow/cherry_pick_changes.md b/doc/workflow/cherry_pick_changes.md
deleted file mode 100644
index 29c4f854416..00000000000
--- a/doc/workflow/cherry_pick_changes.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../user/project/merge_requests/cherry_pick_changes.md'
----
-
-This document was moved to [another location](../user/project/merge_requests/cherry_pick_changes.md).
diff --git a/doc/workflow/ff_merge.md b/doc/workflow/ff_merge.md
deleted file mode 100644
index 11e9e1bbd6b..00000000000
--- a/doc/workflow/ff_merge.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../user/project/merge_requests/fast_forward_merge.md'
----
-
-This document was moved to [user/project/merge_requests/fast_forward_merge](../user/project/merge_requests/fast_forward_merge.md).
diff --git a/doc/workflow/file_finder.md b/doc/workflow/file_finder.md
deleted file mode 100644
index f7098c88fd1..00000000000
--- a/doc/workflow/file_finder.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../user/project/repository/file_finder.md'
----
-
-This document was moved to [another location](../user/project/repository/file_finder.md).
diff --git a/doc/workflow/forking_workflow.md b/doc/workflow/forking_workflow.md
deleted file mode 100644
index fa617d859a5..00000000000
--- a/doc/workflow/forking_workflow.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../user/project/repository/forking_workflow.md'
----
-
-This document was moved to [another location](../user/project/repository/forking_workflow.md).
diff --git a/doc/workflow/git_annex.md b/doc/workflow/git_annex.md
deleted file mode 100644
index e54d52ea70d..00000000000
--- a/doc/workflow/git_annex.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../administration/git_annex.md'
----
-
-This document was moved to [another location](../administration/git_annex.md).
diff --git a/doc/workflow/git_lfs.md b/doc/workflow/git_lfs.md
deleted file mode 100644
index 69939c0efd0..00000000000
--- a/doc/workflow/git_lfs.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../topics/git/lfs/index.md'
----
-
-This document was moved to [another location](../topics/git/lfs/index.md).
diff --git a/doc/workflow/gitlab_flow.md b/doc/workflow/gitlab_flow.md
deleted file mode 100644
index e03281c0ffc..00000000000
--- a/doc/workflow/gitlab_flow.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../topics/gitlab_flow.md'
----
-
-This document was moved to [another location](../topics/gitlab_flow.md).
diff --git a/doc/workflow/groups.md b/doc/workflow/groups.md
deleted file mode 100644
index c7f4647baa9..00000000000
--- a/doc/workflow/groups.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../user/group/index.md'
----
-
-This document was moved to [another location](../user/group/index.md).
diff --git a/doc/workflow/importing/README.md b/doc/workflow/importing/README.md
deleted file mode 100644
index 29da321ba46..00000000000
--- a/doc/workflow/importing/README.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../../user/project/import/index.md'
----
-
-This document was moved to [another location](../../user/project/import/index.md).
diff --git a/doc/workflow/importing/import_projects_from_bitbucket.md b/doc/workflow/importing/import_projects_from_bitbucket.md
deleted file mode 100644
index a42ba7d4518..00000000000
--- a/doc/workflow/importing/import_projects_from_bitbucket.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../../user/project/import/bitbucket.md'
----
-
-This document was moved to [another location](../../user/project/import/bitbucket.md).
diff --git a/doc/workflow/importing/import_projects_from_fogbugz.md b/doc/workflow/importing/import_projects_from_fogbugz.md
deleted file mode 100644
index f5c791dc6de..00000000000
--- a/doc/workflow/importing/import_projects_from_fogbugz.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../../user/project/import/fogbugz.md'
----
-
-This document was moved to [another location](../../user/project/import/fogbugz.md).
diff --git a/doc/workflow/importing/import_projects_from_gitea.md b/doc/workflow/importing/import_projects_from_gitea.md
deleted file mode 100644
index df053835b44..00000000000
--- a/doc/workflow/importing/import_projects_from_gitea.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../../user/project/import/gitea.md'
----
-
-This document was moved to [another location](../../user/project/import/gitea.md).
diff --git a/doc/workflow/importing/import_projects_from_github.md b/doc/workflow/importing/import_projects_from_github.md
deleted file mode 100644
index 6397fcc74b8..00000000000
--- a/doc/workflow/importing/import_projects_from_github.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../../user/project/import/github.md'
----
-
-This document was moved to [another location](../../user/project/import/github.md).
diff --git a/doc/workflow/importing/import_projects_from_gitlab_com.md b/doc/workflow/importing/import_projects_from_gitlab_com.md
deleted file mode 100644
index 135b9704df9..00000000000
--- a/doc/workflow/importing/import_projects_from_gitlab_com.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../../user/project/import/gitlab_com.md'
----
-
-This document was moved to [another location](../../user/project/import/gitlab_com.md).
diff --git a/doc/workflow/importing/migrating_from_svn.md b/doc/workflow/importing/migrating_from_svn.md
deleted file mode 100644
index 99f13d6354c..00000000000
--- a/doc/workflow/importing/migrating_from_svn.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../../user/project/import/svn.md'
----
-
-This document was moved to [another location](../../user/project/import/svn.md).
diff --git a/doc/workflow/issue_weight.md b/doc/workflow/issue_weight.md
deleted file mode 100644
index 94eb38356e8..00000000000
--- a/doc/workflow/issue_weight.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../user/project/issues/issue_weight.md'
----
-
-This document was moved to [another location](../user/project/issues/issue_weight.md).
diff --git a/doc/workflow/labels.md b/doc/workflow/labels.md
deleted file mode 100644
index 3d07d411dd4..00000000000
--- a/doc/workflow/labels.md
+++ /dev/null
@@ -1,7 +0,0 @@
----
-redirect_to: '../user/project/labels.md'
----
-
-# Labels
-
-This document was moved to [user/project/labels.md](../user/project/labels.md).
diff --git a/doc/workflow/lfs/lfs_administration.md b/doc/workflow/lfs/lfs_administration.md
deleted file mode 100644
index 4a784409eff..00000000000
--- a/doc/workflow/lfs/lfs_administration.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../../administration/lfs/index.md'
----
-
-This document was moved to [another location](../../administration/lfs/index.md).
diff --git a/doc/workflow/lfs/manage_large_binaries_with_git_lfs.md b/doc/workflow/lfs/manage_large_binaries_with_git_lfs.md
deleted file mode 100644
index 4656bccf5e6..00000000000
--- a/doc/workflow/lfs/manage_large_binaries_with_git_lfs.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../../topics/git/lfs/index.md'
----
-
-This document was moved to [another location](../../topics/git/lfs/index.md).
diff --git a/doc/workflow/lfs/migrate_from_git_annex_to_git_lfs.md b/doc/workflow/lfs/migrate_from_git_annex_to_git_lfs.md
deleted file mode 100644
index dd98a50e353..00000000000
--- a/doc/workflow/lfs/migrate_from_git_annex_to_git_lfs.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../../topics/git/lfs/migrate_from_git_annex_to_git_lfs.md'
----
-
-This document was moved to [another location](../../topics/git/lfs/migrate_from_git_annex_to_git_lfs.md).
diff --git a/doc/workflow/merge_request_approvals.md b/doc/workflow/merge_request_approvals.md
deleted file mode 100644
index bfcd8faf236..00000000000
--- a/doc/workflow/merge_request_approvals.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../user/project/merge_requests/merge_request_approvals.md'
----
-
-This document was moved to [another location](../user/project/merge_requests/merge_request_approvals.md).
diff --git a/doc/workflow/merge_requests.md b/doc/workflow/merge_requests.md
deleted file mode 100644
index fd9f9b81bc9..00000000000
--- a/doc/workflow/merge_requests.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../user/project/merge_requests/index.md'
----
-
-This document was moved to [user/project/merge_requests/index.md](../user/project/merge_requests/index.md).
diff --git a/doc/workflow/merge_when_build_succeeds.md b/doc/workflow/merge_when_build_succeeds.md
deleted file mode 100644
index 41e6ff0cdd6..00000000000
--- a/doc/workflow/merge_when_build_succeeds.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../user/project/merge_requests/merge_when_pipeline_succeeds.md'
----
-
-This document was moved to [merge_when_pipeline_succeeds](../user/project/merge_requests/merge_when_pipeline_succeeds.md).
diff --git a/doc/workflow/milestones.md b/doc/workflow/milestones.md
deleted file mode 100644
index 18dc15f7327..00000000000
--- a/doc/workflow/milestones.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../user/project/milestones/index.md'
----
-
-This document was moved to [another location](../user/project/milestones/index.md).
diff --git a/doc/workflow/notifications.md b/doc/workflow/notifications.md
deleted file mode 100644
index 23f96360484..00000000000
--- a/doc/workflow/notifications.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../user/profile/notifications.md'
----
-
-This document was moved to [another location](../user/profile/notifications.md).
diff --git a/doc/workflow/project_features.md b/doc/workflow/project_features.md
deleted file mode 100644
index f54afb768a1..00000000000
--- a/doc/workflow/project_features.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../user/project/index.md'
----
-
-This document was moved to [../user/project/index.md](../user/project/index.md)
diff --git a/doc/workflow/protected_branches.md b/doc/workflow/protected_branches.md
deleted file mode 100644
index 1bcac4a2de5..00000000000
--- a/doc/workflow/protected_branches.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../user/project/protected_branches.md'
----
-
-This document was moved to [another location](../user/project/protected_branches.md).
diff --git a/doc/workflow/rebase_before_merge.md b/doc/workflow/rebase_before_merge.md
deleted file mode 100644
index 10e768d3371..00000000000
--- a/doc/workflow/rebase_before_merge.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../user/project/merge_requests/fast_forward_merge.md'
----
-
-This document was moved to [another location](../user/project/merge_requests/fast_forward_merge.md).
diff --git a/doc/workflow/releases.md b/doc/workflow/releases.md
deleted file mode 100644
index f3ba61f6a5c..00000000000
--- a/doc/workflow/releases.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../user/project/releases/index.md#add-release-notes-to-git-tags'
----
-
-This document was moved to [another location](../user/project/releases/index.md#add-release-notes-to-git-tags).
diff --git a/doc/workflow/repository_mirroring.md b/doc/workflow/repository_mirroring.md
deleted file mode 100644
index dc77f4f47af..00000000000
--- a/doc/workflow/repository_mirroring.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../user/project/repository/repository_mirroring.md'
----
-
-This document was moved to [another location](../user/project/repository/repository_mirroring.md).
diff --git a/doc/workflow/revert_changes.md b/doc/workflow/revert_changes.md
deleted file mode 100644
index 15f199af703..00000000000
--- a/doc/workflow/revert_changes.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../user/project/merge_requests/revert_changes.md'
----
-
-This document was moved to [user/project/merge_requests/revert_changes](../user/project/merge_requests/revert_changes.md).
diff --git a/doc/workflow/share_projects_with_other_groups.md b/doc/workflow/share_projects_with_other_groups.md
deleted file mode 100644
index c39cd78f32d..00000000000
--- a/doc/workflow/share_projects_with_other_groups.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../user/project/members/share_project_with_groups.md'
----
-
-This document was moved to [../user/project/members/share_project_with_groups.md](../user/project/members/share_project_with_groups.md)
diff --git a/doc/workflow/share_with_group.md b/doc/workflow/share_with_group.md
deleted file mode 100644
index c39cd78f32d..00000000000
--- a/doc/workflow/share_with_group.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../user/project/members/share_project_with_groups.md'
----
-
-This document was moved to [../user/project/members/share_project_with_groups.md](../user/project/members/share_project_with_groups.md)
diff --git a/doc/workflow/shortcuts.md b/doc/workflow/shortcuts.md
deleted file mode 100644
index 4b35c61ec5e..00000000000
--- a/doc/workflow/shortcuts.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../user/shortcuts.md'
----
-
-This document was moved to [another location](../user/shortcuts.md).
diff --git a/doc/workflow/time_tracking.md b/doc/workflow/time_tracking.md
deleted file mode 100644
index e109410e22d..00000000000
--- a/doc/workflow/time_tracking.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../user/project/time_tracking.md'
----
-
-This document was moved to [another location](../user/project/time_tracking.md).
diff --git a/doc/workflow/timezone.md b/doc/workflow/timezone.md
deleted file mode 100644
index f1a2e1af66a..00000000000
--- a/doc/workflow/timezone.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../administration/timezone.md'
----
-
-This document was moved to [another location](../administration/timezone.md).
diff --git a/doc/workflow/todos.md b/doc/workflow/todos.md
deleted file mode 100644
index 48c9a3faf1d..00000000000
--- a/doc/workflow/todos.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../user/todos.md'
----
-
-This document was moved to [another location](../user/todos.md).
diff --git a/doc/workflow/web_editor.md b/doc/workflow/web_editor.md
deleted file mode 100644
index 2366372d984..00000000000
--- a/doc/workflow/web_editor.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../user/project/repository/web_editor.md'
----
-
-This document was moved to [user/project/repository/web_editor](../user/project/repository/web_editor.md).
diff --git a/doc/workflow/wip_merge_requests.md b/doc/workflow/wip_merge_requests.md
deleted file mode 100644
index 020455dcbdc..00000000000
--- a/doc/workflow/wip_merge_requests.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../user/project/merge_requests/work_in_progress_merge_requests.md'
----
-
-This document was moved to [user/project/merge_requests/work_in_progress_merge_requests](../user/project/merge_requests/work_in_progress_merge_requests.md).
diff --git a/doc/workflow/workflow.md b/doc/workflow/workflow.md
deleted file mode 100644
index c77d95cd326..00000000000
--- a/doc/workflow/workflow.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-redirect_to: '../gitlab-basics/feature_branch_workflow.md'
----
-
-This document was moved to [another location](../gitlab-basics/feature_branch_workflow.md).
diff --git a/docker/README.md b/docker/README.md
index 61b41d2f109..cb6f99a6482 100644
--- a/docker/README.md
+++ b/docker/README.md
@@ -1,3 +1,3 @@
# GitLab Docker images
-This content has been moved to [our documentation site](https://docs.gitlab.com/ce/install/docker.html).
+This content has been moved to [our documentation site](https://docs.gitlab.com/ee/install/docker.html).
diff --git a/geo_architecture.png b/geo_architecture.png
new file mode 100644
index 00000000000..d1ad3d1d93d
--- /dev/null
+++ b/geo_architecture.png
Binary files differ
diff --git a/haml_lint/linter/documentation_links.rb b/haml_lint/linter/documentation_links.rb
index f8e0eec5cdc..a36b095bc11 100644
--- a/haml_lint/linter/documentation_links.rb
+++ b/haml_lint/linter/documentation_links.rb
@@ -13,7 +13,7 @@ module HamlLint
DOCS_DIRECTORY = File.join(File.expand_path('../..', __dir__), 'doc')
HELP_PATH_LINK_PATTERN = <<~PATTERN
- `(send nil? :help_page_path $...)
+ `(send nil? {:help_page_url :help_page_path} $...)
PATTERN
MARKDOWN_HEADER = %r{\A\#{1,6}\s+(?<header>.+)\Z}.freeze
diff --git a/jest.config.base.js b/jest.config.base.js
index ea2ebadd578..9f611775776 100644
--- a/jest.config.base.js
+++ b/jest.config.base.js
@@ -12,7 +12,8 @@ module.exports = path => {
reporters.push([
'jest-junit',
{
- output: './junit_jest.xml',
+ outputName: './junit_jest.xml',
+ addFileAttribute: 'true',
},
]);
}
@@ -33,6 +34,7 @@ module.exports = path => {
'^~(/.*)$': '<rootDir>/app/assets/javascripts$1',
'^ee_component(/.*)$':
'<rootDir>/app/assets/javascripts/vue_shared/components/empty_component.js',
+ '^shared_queries(/.*)$': '<rootDir>/app/graphql/queries$1',
'^ee_else_ce(/.*)$': '<rootDir>/app/assets/javascripts$1',
'^helpers(/.*)$': '<rootDir>/spec/frontend/helpers$1',
'^vendor(/.*)$': '<rootDir>/vendor/assets/javascripts$1',
diff --git a/lib/api/access_requests.rb b/lib/api/access_requests.rb
index 5305b25538f..7e3d70a210a 100644
--- a/lib/api/access_requests.rb
+++ b/lib/api/access_requests.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module API
- class AccessRequests < Grape::API::Instance
+ class AccessRequests < ::API::Base
include PaginationParams
before { authenticate! }
diff --git a/lib/api/admin/ci/variables.rb b/lib/api/admin/ci/variables.rb
index 8721d94d642..44c389d6f94 100644
--- a/lib/api/admin/ci/variables.rb
+++ b/lib/api/admin/ci/variables.rb
@@ -3,7 +3,7 @@
module API
module Admin
module Ci
- class Variables < Grape::API::Instance
+ class Variables < ::API::Base
include PaginationParams
before { authenticated_as_admin! }
diff --git a/lib/api/admin/instance_clusters.rb b/lib/api/admin/instance_clusters.rb
index 8208d10c089..ce1bdd65eff 100644
--- a/lib/api/admin/instance_clusters.rb
+++ b/lib/api/admin/instance_clusters.rb
@@ -2,7 +2,7 @@
module API
module Admin
- class InstanceClusters < Grape::API::Instance
+ class InstanceClusters < ::API::Base
include PaginationParams
before do
@@ -37,6 +37,7 @@ module API
requires :name, type: String, desc: 'Cluster name'
optional :enabled, type: Boolean, default: true, desc: 'Determines if cluster is active or not, defaults to true'
optional :environment_scope, default: '*', type: String, desc: 'The associated environment to the cluster'
+ optional :namespace_per_environment, default: true, type: Boolean, desc: 'Deploy each environment to a separate Kubernetes namespace'
optional :domain, type: String, desc: 'Cluster base domain'
optional :management_project_id, type: Integer, desc: 'The ID of the management project'
optional :managed, type: Boolean, default: true, desc: 'Determines if GitLab will manage namespaces and service accounts for this cluster, defaults to true'
@@ -70,6 +71,7 @@ module API
optional :name, type: String, desc: 'Cluster name'
optional :enabled, type: Boolean, desc: 'Enable or disable Gitlab\'s connection to your Kubernetes cluster'
optional :environment_scope, type: String, desc: 'The associated environment to the cluster'
+ optional :namespace_per_environment, default: true, type: Boolean, desc: 'Deploy each environment to a separate Kubernetes namespace'
optional :domain, type: String, desc: 'Cluster base domain'
optional :management_project_id, type: Integer, desc: 'The ID of the management project'
optional :platform_kubernetes_attributes, type: Hash, desc: %q(Platform Kubernetes data) do
diff --git a/lib/api/admin/sidekiq.rb b/lib/api/admin/sidekiq.rb
index f4c84f2eee8..c2e9de5fb4e 100644
--- a/lib/api/admin/sidekiq.rb
+++ b/lib/api/admin/sidekiq.rb
@@ -2,7 +2,7 @@
module API
module Admin
- class Sidekiq < Grape::API::Instance
+ class Sidekiq < ::API::Base
before { authenticated_as_admin! }
namespace 'admin' do
diff --git a/lib/api/api.rb b/lib/api/api.rb
index b37751e1b47..84b4d5a5835 100644
--- a/lib/api/api.rb
+++ b/lib/api/api.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module API
- class API < Grape::API::Instance
+ class API < ::API::Base
include APIGuard
LOG_FILENAME = Rails.root.join("log", "api_json.log")
@@ -153,6 +153,9 @@ module API
mount ::API::Environments
mount ::API::ErrorTracking
mount ::API::Events
+ mount ::API::FeatureFlags
+ mount ::API::FeatureFlagScopes
+ mount ::API::FeatureFlagsUserLists
mount ::API::Features
mount ::API::Files
mount ::API::FreezePeriods
@@ -196,6 +199,8 @@ module API
mount ::API::ComposerPackages
mount ::API::ConanProjectPackages
mount ::API::ConanInstancePackages
+ mount ::API::DebianGroupPackages
+ mount ::API::DebianProjectPackages
mount ::API::MavenPackages
mount ::API::NpmPackages
mount ::API::GenericPackages
@@ -216,6 +221,7 @@ module API
mount ::API::ProjectStatistics
mount ::API::ProjectTemplates
mount ::API::Terraform::State
+ mount ::API::Terraform::StateVersion
mount ::API::ProtectedBranches
mount ::API::ProtectedTags
mount ::API::Releases
@@ -236,6 +242,7 @@ module API
mount ::API::Templates
mount ::API::Todos
mount ::API::Triggers
+ mount ::API::Unleash
mount ::API::UsageData
mount ::API::UserCounts
mount ::API::Users
@@ -245,6 +252,7 @@ module API
end
mount ::API::Internal::Base
+ mount ::API::Internal::Lfs
mount ::API::Internal::Pages
mount ::API::Internal::Kubernetes
diff --git a/lib/api/api_guard.rb b/lib/api/api_guard.rb
index bf5044b4832..0a486307653 100644
--- a/lib/api/api_guard.rb
+++ b/lib/api/api_guard.rb
@@ -19,6 +19,7 @@ module API
end
use AdminModeMiddleware
+ use ResponseCoercerMiddleware
helpers HelperMethods
@@ -188,6 +189,44 @@ module API
end
end
+ # Prior to Rack v2.1.x, returning a body of [nil] or [201] worked
+ # because the body was coerced to a string. However, this no longer
+ # works in Rack v2.1.0+. The Rack spec
+ # (https://github.com/rack/rack/blob/master/SPEC.rdoc#the-body-)
+ # says:
+ #
+ # The Body must respond to `each` and must only yield String values
+ #
+ # Because it's easy to return the wrong body type, this middleware
+ # will:
+ #
+ # 1. Inspect each element of the body if it is an Array.
+ # 2. Coerce each value to a string if necessary.
+ # 3. Flag a test and development error.
+ class ResponseCoercerMiddleware < ::Grape::Middleware::Base
+ def call(env)
+ response = super(env)
+
+ status = response[0]
+ body = response[2]
+
+ return response if Rack::Utils::STATUS_WITH_NO_ENTITY_BODY[status]
+ return response unless body.is_a?(Array)
+
+ body.map! do |part|
+ if part.is_a?(String)
+ part
+ else
+ err = ArgumentError.new("The response body should be a String, but it is of type #{part.class}")
+ Gitlab::ErrorTracking.track_and_raise_for_dev_exception(err)
+ part.to_s
+ end
+ end
+
+ response
+ end
+ end
+
class AdminModeMiddleware < ::Grape::Middleware::Base
def after
# Use a Grape middleware since the Grape `after` blocks might run
diff --git a/lib/api/appearance.rb b/lib/api/appearance.rb
index f98004af480..00b495bbc1e 100644
--- a/lib/api/appearance.rb
+++ b/lib/api/appearance.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module API
- class Appearance < Grape::API::Instance
+ class Appearance < ::API::Base
before { authenticated_as_admin! }
helpers do
diff --git a/lib/api/applications.rb b/lib/api/applications.rb
index 4f2c3ee79ef..2afe8763d9d 100644
--- a/lib/api/applications.rb
+++ b/lib/api/applications.rb
@@ -2,7 +2,7 @@
module API
# External applications API
- class Applications < Grape::API::Instance
+ class Applications < ::API::Base
before { authenticated_as_admin! }
resource :applications do
diff --git a/lib/api/avatar.rb b/lib/api/avatar.rb
index 9501e777fff..5a9b9940fcf 100644
--- a/lib/api/avatar.rb
+++ b/lib/api/avatar.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module API
- class Avatar < Grape::API::Instance
+ class Avatar < ::API::Base
resource :avatar do
desc 'Return avatar url for a user' do
success Entities::Avatar
diff --git a/lib/api/award_emoji.rb b/lib/api/award_emoji.rb
index 0a3df3ed96e..6d40ae8f5ff 100644
--- a/lib/api/award_emoji.rb
+++ b/lib/api/award_emoji.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module API
- class AwardEmoji < Grape::API::Instance
+ class AwardEmoji < ::API::Base
include PaginationParams
before { authenticate! }
diff --git a/lib/api/badges.rb b/lib/api/badges.rb
index f9728ffc446..fc00594c9ec 100644
--- a/lib/api/badges.rb
+++ b/lib/api/badges.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module API
- class Badges < Grape::API::Instance
+ class Badges < ::API::Base
include PaginationParams
before { authenticate_non_get! }
diff --git a/lib/api/base.rb b/lib/api/base.rb
new file mode 100644
index 00000000000..e174cef3bad
--- /dev/null
+++ b/lib/api/base.rb
@@ -0,0 +1,6 @@
+# frozen_string_literal: true
+
+module API
+ class Base < Grape::API::Instance # rubocop:disable API/Base
+ end
+end
diff --git a/lib/api/boards.rb b/lib/api/boards.rb
index 1f5086127a8..d2d1628aff4 100644
--- a/lib/api/boards.rb
+++ b/lib/api/boards.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module API
- class Boards < Grape::API::Instance
+ class Boards < ::API::Base
include BoardsResponses
include PaginationParams
diff --git a/lib/api/boards_responses.rb b/lib/api/boards_responses.rb
index 68497a08fb8..6a86c02bf4a 100644
--- a/lib/api/boards_responses.rb
+++ b/lib/api/boards_responses.rb
@@ -45,7 +45,7 @@ module API
def destroy_list(list)
destroy_conditionally!(list) do |list|
service = ::Boards::Lists::DestroyService.new(board_parent, current_user)
- unless service.execute(list)
+ if service.execute(list).error?
render_api_error!({ error: 'List could not be deleted!' }, 400)
end
end
diff --git a/lib/api/branches.rb b/lib/api/branches.rb
index 44f7610384e..37cce6eafba 100644
--- a/lib/api/branches.rb
+++ b/lib/api/branches.rb
@@ -3,7 +3,7 @@
require 'mime/types'
module API
- class Branches < Grape::API::Instance
+ class Branches < ::API::Base
include PaginationParams
BRANCH_ENDPOINT_REQUIREMENTS = API::NAMESPACE_OR_PROJECT_REQUIREMENTS.merge(branch: API::NO_SLASH_URL_PART_REGEX)
diff --git a/lib/api/broadcast_messages.rb b/lib/api/broadcast_messages.rb
index dcf950d7a03..8ce7694bbfd 100644
--- a/lib/api/broadcast_messages.rb
+++ b/lib/api/broadcast_messages.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module API
- class BroadcastMessages < Grape::API::Instance
+ class BroadcastMessages < ::API::Base
include PaginationParams
resource :broadcast_messages do
diff --git a/lib/api/ci/pipeline_schedules.rb b/lib/api/ci/pipeline_schedules.rb
index 1afdb0ad34c..18caf85f109 100644
--- a/lib/api/ci/pipeline_schedules.rb
+++ b/lib/api/ci/pipeline_schedules.rb
@@ -2,7 +2,7 @@
module API
module Ci
- class PipelineSchedules < Grape::API::Instance
+ class PipelineSchedules < ::API::Base
include PaginationParams
before { authenticate! }
diff --git a/lib/api/ci/pipelines.rb b/lib/api/ci/pipelines.rb
index 045f81074a7..61e03ed1a95 100644
--- a/lib/api/ci/pipelines.rb
+++ b/lib/api/ci/pipelines.rb
@@ -2,7 +2,7 @@
module API
module Ci
- class Pipelines < Grape::API::Instance
+ class Pipelines < ::API::Base
include PaginationParams
before { authenticate_non_get! }
@@ -128,7 +128,7 @@ module API
pipeline = user_project.all_pipelines.find(params[:pipeline_id])
- if Feature.enabled?(:ci_jobs_finder_refactor)
+ if Feature.enabled?(:ci_jobs_finder_refactor, default_enabled: true)
builds = ::Ci::JobsFinder
.new(current_user: current_user, pipeline: pipeline, params: params)
.execute
@@ -157,7 +157,7 @@ module API
pipeline = user_project.all_pipelines.find(params[:pipeline_id])
- if Feature.enabled?(:ci_jobs_finder_refactor)
+ if Feature.enabled?(:ci_jobs_finder_refactor, default_enabled: true)
bridges = ::Ci::JobsFinder
.new(current_user: current_user, pipeline: pipeline, params: params, type: ::Ci::Bridge)
.execute
diff --git a/lib/api/ci/runner.rb b/lib/api/ci/runner.rb
index 08903dce3dc..ef679147c9f 100644
--- a/lib/api/ci/runner.rb
+++ b/lib/api/ci/runner.rb
@@ -2,7 +2,7 @@
module API
module Ci
- class Runner < Grape::API::Instance
+ class Runner < ::API::Base
helpers ::API::Helpers::Runner
resource :runners do
@@ -72,6 +72,7 @@ module API
post '/verify' do
authenticate_runner!
status 200
+ body "200"
end
end
@@ -181,7 +182,9 @@ module API
.new(job, declared_params(include_missing: false))
service.execute.then do |result|
+ header 'X-GitLab-Trace-Update-Interval', result.backoff
status result.status
+ body result.status.to_s
end
end
@@ -292,6 +295,7 @@ module API
if result[:status] == :success
status :created
+ body "201"
else
render_api_error!(result[:message], result[:http_status])
end
diff --git a/lib/api/ci/runners.rb b/lib/api/ci/runners.rb
index 7bca72f8028..d37f10fe631 100644
--- a/lib/api/ci/runners.rb
+++ b/lib/api/ci/runners.rb
@@ -2,7 +2,7 @@
module API
module Ci
- class Runners < Grape::API::Instance
+ class Runners < ::API::Base
include PaginationParams
before { authenticate! }
diff --git a/lib/api/commit_statuses.rb b/lib/api/commit_statuses.rb
index 9f5a6e87505..af103b8c1f8 100644
--- a/lib/api/commit_statuses.rb
+++ b/lib/api/commit_statuses.rb
@@ -3,7 +3,7 @@
require 'mime/types'
module API
- class CommitStatuses < Grape::API::Instance
+ class CommitStatuses < ::API::Base
params do
requires :id, type: String, desc: 'The ID of a project'
end
diff --git a/lib/api/commits.rb b/lib/api/commits.rb
index 20877fb5c5f..582ccd41847 100644
--- a/lib/api/commits.rb
+++ b/lib/api/commits.rb
@@ -3,7 +3,7 @@
require 'mime/types'
module API
- class Commits < Grape::API::Instance
+ class Commits < ::API::Base
include PaginationParams
before do
@@ -62,19 +62,15 @@ module API
first_parent: first_parent,
order: order)
- commit_count =
- if all || path || before || after || first_parent
- user_project.repository.count_commits(ref: ref, path: path, before: before, after: after, all: all, first_parent: first_parent)
- else
- # Cacheable commit count.
- user_project.repository.commit_count_for_ref(ref)
- end
+ serializer = with_stats ? Entities::CommitWithStats : Entities::Commit
+ # This tells kaminari that there is 1 more commit after the one we've
+ # loaded, meaning there will be a next page, if the currently loaded set
+ # of commits is equal to the requested page size.
+ commit_count = offset + commits.size + 1
paginated_commits = Kaminari.paginate_array(commits, total_count: commit_count)
- serializer = with_stats ? Entities::CommitWithStats : Entities::Commit
-
- present paginate(paginated_commits), with: serializer
+ present paginate(paginated_commits, exclude_total_headers: true), with: serializer
end
desc 'Commit multiple file changes as one commit' do
diff --git a/lib/api/composer_packages.rb b/lib/api/composer_packages.rb
index 31d097c4bea..1becbd668a3 100644
--- a/lib/api/composer_packages.rb
+++ b/lib/api/composer_packages.rb
@@ -2,7 +2,7 @@
# PHP composer support (https://getcomposer.org/)
module API
- class ComposerPackages < Grape::API::Instance
+ class ComposerPackages < ::API::Base
helpers ::API::Helpers::PackagesManagerClientsHelpers
helpers ::API::Helpers::RelatedResourcesHelpers
helpers ::API::Helpers::Packages::BasicAuthHelpers
@@ -26,6 +26,10 @@ module API
render_api_error!(e.message, 400)
end
+ rescue_from Packages::Composer::ComposerJsonService::InvalidJson do |e|
+ render_api_error!(e.message, 422)
+ end
+
helpers do
def packages
strong_memoize(:packages) do
@@ -123,7 +127,7 @@ module API
bad_request!
end
- package_event('push_package')
+ track_package_event('push_package', :composer)
::Packages::Composer::CreatePackageService
.new(authorized_user_project, current_user, declared_params)
diff --git a/lib/api/conan_instance_packages.rb b/lib/api/conan_instance_packages.rb
index 209748d79fa..08265201328 100644
--- a/lib/api/conan_instance_packages.rb
+++ b/lib/api/conan_instance_packages.rb
@@ -2,7 +2,7 @@
# Conan Instance-Level Package Manager Client API
module API
- class ConanInstancePackages < Grape::API::Instance
+ class ConanInstancePackages < ::API::Base
namespace 'packages/conan/v1' do
include ConanPackageEndpoints
end
diff --git a/lib/api/conan_package_endpoints.rb b/lib/api/conan_package_endpoints.rb
index 445447cfcd2..9b6867a328b 100644
--- a/lib/api/conan_package_endpoints.rb
+++ b/lib/api/conan_package_endpoints.rb
@@ -246,7 +246,7 @@ module API
delete do
authorize!(:destroy_package, project)
- package_event('delete_package', category: 'API::ConanPackages')
+ track_package_event('delete_package', :conan, category: 'API::ConanPackages')
package.destroy
end
diff --git a/lib/api/conan_project_packages.rb b/lib/api/conan_project_packages.rb
index c51992231a7..db8cd187811 100644
--- a/lib/api/conan_project_packages.rb
+++ b/lib/api/conan_project_packages.rb
@@ -2,7 +2,7 @@
# Conan Project-Level Package Manager Client API
module API
- class ConanProjectPackages < Grape::API::Instance
+ class ConanProjectPackages < ::API::Base
params do
requires :id, type: Integer, desc: 'The ID of a project', regexp: %r{\A[1-9]\d*\z}
end
diff --git a/lib/api/container_registry_event.rb b/lib/api/container_registry_event.rb
index 0b7c35cadbd..6c4b80b612a 100644
--- a/lib/api/container_registry_event.rb
+++ b/lib/api/container_registry_event.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module API
- class ContainerRegistryEvent < Grape::API::Instance
+ class ContainerRegistryEvent < ::API::Base
DOCKER_DISTRIBUTION_EVENTS_V1_JSON = 'application/vnd.docker.distribution.events.v1+json'
before { authenticate_registry_notification! }
diff --git a/lib/api/debian_group_packages.rb b/lib/api/debian_group_packages.rb
new file mode 100644
index 00000000000..e3cacc4132f
--- /dev/null
+++ b/lib/api/debian_group_packages.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+module API
+ class DebianGroupPackages < ::API::Base
+ params do
+ requires :id, type: String, desc: 'The ID of a group'
+ end
+
+ resource :groups, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
+ before do
+ not_found! unless ::Feature.enabled?(:debian_packages, user_group)
+
+ authorize_read_package!(user_group)
+ end
+
+ namespace ':id/-/packages/debian' do
+ include DebianPackageEndpoints
+ end
+ end
+ end
+end
diff --git a/lib/api/debian_package_endpoints.rb b/lib/api/debian_package_endpoints.rb
new file mode 100644
index 00000000000..168b3ca7a4f
--- /dev/null
+++ b/lib/api/debian_package_endpoints.rb
@@ -0,0 +1,124 @@
+# frozen_string_literal: true
+
+module API
+ module DebianPackageEndpoints
+ extend ActiveSupport::Concern
+
+ DISTRIBUTION_REGEX = %r{[a-zA-Z0-9][a-zA-Z0-9.-]*}.freeze
+ COMPONENT_REGEX = %r{[a-z-]+}.freeze
+ ARCHITECTURE_REGEX = %r{[a-z][a-z0-9]*}.freeze
+ LETTER_REGEX = %r{(lib)?[a-z0-9]}.freeze
+ PACKAGE_REGEX = API::NO_SLASH_URL_PART_REGEX
+ DISTRIBUTION_REQUIREMENTS = {
+ distribution: DISTRIBUTION_REGEX
+ }.freeze
+ COMPONENT_ARCHITECTURE_REQUIREMENTS = {
+ component: COMPONENT_REGEX,
+ architecture: ARCHITECTURE_REGEX
+ }.freeze
+ COMPONENT_LETTER_SOURCE_PACKAGE_REQUIREMENTS = {
+ component: COMPONENT_REGEX,
+ letter: LETTER_REGEX,
+ source_package: PACKAGE_REGEX
+ }.freeze
+ FILE_NAME_REQUIREMENTS = {
+ file_name: API::NO_SLASH_URL_PART_REGEX
+ }.freeze
+
+ included do
+ helpers ::API::Helpers::PackagesHelpers
+ helpers ::API::Helpers::Packages::BasicAuthHelpers
+
+ format :txt
+
+ rescue_from ArgumentError do |e|
+ render_api_error!(e.message, 400)
+ end
+
+ rescue_from ActiveRecord::RecordInvalid do |e|
+ render_api_error!(e.message, 400)
+ end
+
+ before do
+ require_packages_enabled!
+ end
+
+ params do
+ requires :distribution, type: String, desc: 'The Debian Codename', regexp: Gitlab::Regex.debian_distribution_regex
+ end
+
+ namespace 'dists/*distribution', requirements: DISTRIBUTION_REQUIREMENTS do
+ # GET {projects|groups}/:id/-/packages/debian/dists/*distribution/Release.gpg
+ desc 'The Release file signature' do
+ detail 'This feature was introduced in GitLab 13.5'
+ end
+
+ route_setting :authentication, deploy_token_allowed: true, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth
+ get 'Release.gpg' do
+ not_found!
+ end
+
+ # GET {projects|groups}/:id/-/packages/debian/dists/*distribution/Release
+ desc 'The unsigned Release file' do
+ detail 'This feature was introduced in GitLab 13.5'
+ end
+
+ route_setting :authentication, deploy_token_allowed: true, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth
+ get 'Release' do
+ # https://gitlab.com/gitlab-org/gitlab/-/issues/5835#note_414103286
+ 'TODO Release'
+ end
+
+ # GET {projects|groups}/:id/-/packages/debian/dists/*distribution/InRelease
+ desc 'The signed Release file' do
+ detail 'This feature was introduced in GitLab 13.5'
+ end
+
+ route_setting :authentication, deploy_token_allowed: true, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth
+ get 'InRelease' do
+ not_found!
+ end
+
+ params do
+ requires :component, type: String, desc: 'The Debian Component', regexp: Gitlab::Regex.debian_component_regex
+ requires :architecture, type: String, desc: 'The Debian Architecture', regexp: Gitlab::Regex.debian_architecture_regex
+ end
+
+ namespace ':component/binary-:architecture', requirements: COMPONENT_ARCHITECTURE_REQUIREMENTS do
+ # GET {projects|groups}/:id/-/packages/debian/dists/*distribution/:component/binary-:architecture/Packages
+ desc 'The binary files index' do
+ detail 'This feature was introduced in GitLab 13.5'
+ end
+
+ route_setting :authentication, deploy_token_allowed: true, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth
+ get 'Packages' do
+ # https://gitlab.com/gitlab-org/gitlab/-/issues/5835#note_414103286
+ 'TODO Packages'
+ end
+ end
+ end
+
+ params do
+ requires :component, type: String, desc: 'The Debian Component', regexp: Gitlab::Regex.debian_component_regex
+ requires :letter, type: String, desc: 'The Debian Classification (first-letter or lib-first-letter)'
+ requires :source_package, type: String, desc: 'The Debian Source Package Name', regexp: Gitlab::Regex.debian_package_name_regex
+ end
+
+ namespace 'pool/:component/:letter/:source_package', requirements: COMPONENT_LETTER_SOURCE_PACKAGE_REQUIREMENTS do
+ # GET {projects|groups}/:id/-/packages/debian/pool/:component/:letter/:source_package/:file_name
+ params do
+ requires :file_name, type: String, desc: 'The Debian File Name'
+ end
+ desc 'The package' do
+ detail 'This feature was introduced in GitLab 13.5'
+ end
+
+ route_setting :authentication, deploy_token_allowed: true, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth
+ get ':file_name', requirements: FILE_NAME_REQUIREMENTS do
+ # https://gitlab.com/gitlab-org/gitlab/-/issues/5835#note_414103286
+ 'TODO File'
+ end
+ end
+ end
+ end
+end
diff --git a/lib/api/debian_project_packages.rb b/lib/api/debian_project_packages.rb
new file mode 100644
index 00000000000..bcb4e8c8cbc
--- /dev/null
+++ b/lib/api/debian_project_packages.rb
@@ -0,0 +1,56 @@
+# frozen_string_literal: true
+
+module API
+ class DebianProjectPackages < ::API::Base
+ params do
+ requires :id, type: String, desc: 'The ID of a project'
+ end
+
+ resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
+ before do
+ not_found! unless ::Feature.enabled?(:debian_packages, user_project)
+
+ authorize_read_package!
+ end
+
+ namespace ':id/-/packages/debian' do
+ include DebianPackageEndpoints
+
+ params do
+ requires :file_name, type: String, desc: 'The file name'
+ end
+
+ namespace 'incoming/:file_name', requirements: FILE_NAME_REQUIREMENTS do
+ # PUT {projects|groups}/:id/-/packages/debian/incoming/:file_name
+ params do
+ requires :file, type: ::API::Validations::Types::WorkhorseFile, desc: 'The package file to be published (generated by Multipart middleware)'
+ end
+
+ route_setting :authentication, deploy_token_allowed: true, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth
+ put do
+ authorize_upload!(authorized_user_project)
+ bad_request!('File is too large') if authorized_user_project.actual_limits.exceeded?(:debian_max_file_size, params[:file].size)
+
+ track_package_event('push_package', :debian)
+
+ created!
+ rescue ObjectStorage::RemoteStoreError => e
+ Gitlab::ErrorTracking.track_exception(e, extra: { file_name: params[:file_name], project_id: authorized_user_project.id })
+
+ forbidden!
+ end
+
+ # PUT {projects|groups}/:id/-/packages/debian/incoming/:file_name/authorize
+ route_setting :authentication, deploy_token_allowed: true, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth
+ post 'authorize' do
+ authorize_workhorse!(
+ subject: authorized_user_project,
+ has_length: false,
+ maximum_size: authorized_user_project.actual_limits.debian_max_file_size
+ )
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/api/deploy_keys.rb b/lib/api/deploy_keys.rb
index ad37b7578ad..314f5b6ee1d 100644
--- a/lib/api/deploy_keys.rb
+++ b/lib/api/deploy_keys.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module API
- class DeployKeys < Grape::API::Instance
+ class DeployKeys < ::API::Base
include PaginationParams
before { authenticate! }
diff --git a/lib/api/deploy_tokens.rb b/lib/api/deploy_tokens.rb
index 96aa2445f56..1c156b8b3bb 100644
--- a/lib/api/deploy_tokens.rb
+++ b/lib/api/deploy_tokens.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module API
- class DeployTokens < Grape::API::Instance
+ class DeployTokens < ::API::Base
include PaginationParams
helpers do
diff --git a/lib/api/deployments.rb b/lib/api/deployments.rb
index 87144fd31cc..ff06bdbae16 100644
--- a/lib/api/deployments.rb
+++ b/lib/api/deployments.rb
@@ -2,7 +2,7 @@
module API
# Deployments RESTful API endpoints
- class Deployments < Grape::API::Instance
+ class Deployments < ::API::Base
include PaginationParams
before { authenticate! }
diff --git a/lib/api/discussions.rb b/lib/api/discussions.rb
index c431ec8e1e4..3d2608c8c5a 100644
--- a/lib/api/discussions.rb
+++ b/lib/api/discussions.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module API
- class Discussions < Grape::API::Instance
+ class Discussions < ::API::Base
include PaginationParams
helpers ::API::Helpers::NotesHelpers
helpers ::RendersNotes
diff --git a/lib/api/entities/ci/lint/result.rb b/lib/api/entities/ci/lint/result.rb
new file mode 100644
index 00000000000..0e4aa238ba2
--- /dev/null
+++ b/lib/api/entities/ci/lint/result.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+module API
+ module Entities
+ module Ci
+ module Lint
+ class Result < Grape::Entity
+ expose :valid?, as: :valid
+ expose :errors
+ expose :warnings
+ expose :merged_yaml
+ end
+ end
+ end
+ end
+end
diff --git a/lib/api/entities/cluster.rb b/lib/api/entities/cluster.rb
index 4cb54e988ce..67459092a33 100644
--- a/lib/api/entities/cluster.rb
+++ b/lib/api/entities/cluster.rb
@@ -4,7 +4,7 @@ module API
module Entities
class Cluster < Grape::Entity
expose :id, :name, :created_at, :domain
- expose :provider_type, :platform_type, :environment_scope, :cluster_type
+ expose :provider_type, :platform_type, :environment_scope, :cluster_type, :namespace_per_environment
expose :user, using: Entities::UserBasic
expose :platform_kubernetes, using: Entities::Platform::Kubernetes
expose :provider_gcp, using: Entities::Provider::Gcp
diff --git a/lib/api/entities/container_registry.rb b/lib/api/entities/container_registry.rb
index cff627ab50a..c430b73580b 100644
--- a/lib/api/entities/container_registry.rb
+++ b/lib/api/entities/container_registry.rb
@@ -16,6 +16,7 @@ module API
expose :project_id
expose :location
expose :created_at
+ expose :expiration_policy_started_at, as: :cleanup_policy_started_at
expose :tags_count, if: -> (_, options) { options[:tags_count] }
expose :tags, using: Tag, if: -> (_, options) { options[:tags] }
end
diff --git a/lib/api/entities/feature_flag.rb b/lib/api/entities/feature_flag.rb
new file mode 100644
index 00000000000..82fdb20af00
--- /dev/null
+++ b/lib/api/entities/feature_flag.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+module API
+ module Entities
+ class FeatureFlag < Grape::Entity
+ expose :name
+ expose :description
+ expose :active
+ expose :version, if: :feature_flags_new_version_enabled
+ expose :created_at
+ expose :updated_at
+ expose :scopes, using: FeatureFlag::LegacyScope
+ expose :strategies, using: FeatureFlag::Strategy, if: :feature_flags_new_version_enabled
+ end
+ end
+end
diff --git a/lib/api/entities/feature_flag/detailed_legacy_scope.rb b/lib/api/entities/feature_flag/detailed_legacy_scope.rb
new file mode 100644
index 00000000000..47078c1dfde
--- /dev/null
+++ b/lib/api/entities/feature_flag/detailed_legacy_scope.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+module API
+ module Entities
+ class FeatureFlag < Grape::Entity
+ class DetailedLegacyScope < LegacyScope
+ expose :name
+ end
+ end
+ end
+end
diff --git a/lib/api/entities/feature_flag/legacy_scope.rb b/lib/api/entities/feature_flag/legacy_scope.rb
new file mode 100644
index 00000000000..7329f71c599
--- /dev/null
+++ b/lib/api/entities/feature_flag/legacy_scope.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+module API
+ module Entities
+ class FeatureFlag < Grape::Entity
+ class LegacyScope < Grape::Entity
+ expose :id
+ expose :active
+ expose :environment_scope
+ expose :strategies
+ expose :created_at
+ expose :updated_at
+ end
+ end
+ end
+end
diff --git a/lib/api/entities/feature_flag/scope.rb b/lib/api/entities/feature_flag/scope.rb
new file mode 100644
index 00000000000..906fe718257
--- /dev/null
+++ b/lib/api/entities/feature_flag/scope.rb
@@ -0,0 +1,12 @@
+# frozen_string_literal: true
+
+module API
+ module Entities
+ class FeatureFlag < Grape::Entity
+ class Scope < Grape::Entity
+ expose :id
+ expose :environment_scope
+ end
+ end
+ end
+end
diff --git a/lib/api/entities/feature_flag/strategy.rb b/lib/api/entities/feature_flag/strategy.rb
new file mode 100644
index 00000000000..32699be0ee3
--- /dev/null
+++ b/lib/api/entities/feature_flag/strategy.rb
@@ -0,0 +1,14 @@
+# frozen_string_literal: true
+
+module API
+ module Entities
+ class FeatureFlag < Grape::Entity
+ class Strategy < Grape::Entity
+ expose :id
+ expose :name
+ expose :parameters
+ expose :scopes, using: FeatureFlag::Scope
+ end
+ end
+ end
+end
diff --git a/lib/api/entities/feature_flag/user_list.rb b/lib/api/entities/feature_flag/user_list.rb
new file mode 100644
index 00000000000..bc8b12ea22e
--- /dev/null
+++ b/lib/api/entities/feature_flag/user_list.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+module API
+ module Entities
+ class FeatureFlag < Grape::Entity
+ 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 :path do |list|
+ project_feature_flags_user_list_path(list.project, list)
+ end
+
+ expose :edit_path do |list|
+ edit_project_feature_flags_user_list_path(list.project, list)
+ end
+ end
+ end
+ end
+end
diff --git a/lib/api/entities/job_request/cache.rb b/lib/api/entities/job_request/cache.rb
index a75affbaf84..cd533d7e5b3 100644
--- a/lib/api/entities/job_request/cache.rb
+++ b/lib/api/entities/job_request/cache.rb
@@ -4,7 +4,7 @@ module API
module Entities
module JobRequest
class Cache < Grape::Entity
- expose :key, :untracked, :paths, :policy
+ expose :key, :untracked, :paths, :policy, :when
end
end
end
diff --git a/lib/api/entities/member.rb b/lib/api/entities/member.rb
index 14e97f41e77..ad62f92e5a0 100644
--- a/lib/api/entities/member.rb
+++ b/lib/api/entities/member.rb
@@ -5,6 +5,7 @@ module API
class Member < Grape::Entity
expose :user, merge: true, using: UserBasic
expose :access_level
+ expose :created_at
expose :expires_at
end
end
diff --git a/lib/api/entities/package.rb b/lib/api/entities/package.rb
index d903f50befa..b54f0e04a9d 100644
--- a/lib/api/entities/package.rb
+++ b/lib/api/entities/package.rb
@@ -7,7 +7,19 @@ module API
extend ::API::Entities::EntityHelpers
expose :id
- expose :name
+
+ expose :name do |package|
+ if package.conan?
+ package.conan_recipe
+ else
+ package.name
+ end
+ end
+
+ expose :conan_package_name, if: ->(package) { package.conan? } do |package|
+ package.name
+ end
+
expose :version
expose :package_type
diff --git a/lib/api/entities/project.rb b/lib/api/entities/project.rb
index fb599d68d72..82a44c75382 100644
--- a/lib/api/entities/project.rb
+++ b/lib/api/entities/project.rb
@@ -84,6 +84,7 @@ module API
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 :public_builds, as: :public_jobs
expose :build_git_strategy, if: lambda { |project, options| options[:user_can_admin_project] } do |project, options|
project.build_allow_git_fetch ? 'fetch' : 'clone'
diff --git a/lib/api/entities/snippet.rb b/lib/api/entities/snippet.rb
index 40488eb882d..85148c03d18 100644
--- a/lib/api/entities/snippet.rb
+++ b/lib/api/entities/snippet.rb
@@ -17,7 +17,7 @@ module API
expose :file_name do |snippet|
snippet.file_name_on_repo || snippet.file_name
end
- expose :files, if: ->(snippet, options) { snippet_multiple_files?(snippet, options[:current_user]) } do |snippet, options|
+ expose :files do |snippet, options|
snippet.list_files.map do |file|
{
path: file,
@@ -25,10 +25,6 @@ module API
}
end
end
-
- def snippet_multiple_files?(snippet, current_user)
- ::Feature.enabled?(:snippet_multiple_files, current_user) && snippet.repository_exists?
- end
end
end
end
diff --git a/lib/api/entities/unleash_feature.rb b/lib/api/entities/unleash_feature.rb
new file mode 100644
index 00000000000..8ee87d1fc11
--- /dev/null
+++ b/lib/api/entities/unleash_feature.rb
@@ -0,0 +1,32 @@
+# frozen_string_literal: true
+
+module API
+ module Entities
+ class UnleashFeature < Grape::Entity
+ expose :name
+ expose :description, unless: ->(feature) { feature.description.nil? }
+ expose :active, as: :enabled
+ expose :strategies do |flag|
+ flag.strategies.map do |strategy|
+ if legacy_strategy?(strategy)
+ UnleashLegacyStrategy.represent(strategy)
+ elsif gitlab_user_list_strategy?(strategy)
+ UnleashGitlabUserListStrategy.represent(strategy)
+ else
+ UnleashStrategy.represent(strategy)
+ end
+ end
+ end
+
+ private
+
+ def legacy_strategy?(strategy)
+ !strategy.respond_to?(:name)
+ end
+
+ def gitlab_user_list_strategy?(strategy)
+ strategy.name == ::Operations::FeatureFlags::Strategy::STRATEGY_GITLABUSERLIST
+ end
+ end
+ end
+end
diff --git a/lib/api/entities/unleash_gitlab_user_list_strategy.rb b/lib/api/entities/unleash_gitlab_user_list_strategy.rb
new file mode 100644
index 00000000000..5617f8002d9
--- /dev/null
+++ b/lib/api/entities/unleash_gitlab_user_list_strategy.rb
@@ -0,0 +1,14 @@
+# frozen_string_literal: true
+
+module API
+ module Entities
+ class UnleashGitlabUserListStrategy < Grape::Entity
+ expose :name do |_strategy|
+ ::Operations::FeatureFlags::Strategy::STRATEGY_USERWITHID
+ end
+ expose :parameters do |strategy|
+ { userIds: strategy.user_list.user_xids }
+ end
+ end
+ end
+end
diff --git a/lib/api/entities/unleash_legacy_strategy.rb b/lib/api/entities/unleash_legacy_strategy.rb
new file mode 100644
index 00000000000..5d5954f8da0
--- /dev/null
+++ b/lib/api/entities/unleash_legacy_strategy.rb
@@ -0,0 +1,14 @@
+# frozen_string_literal: true
+
+module API
+ module Entities
+ class UnleashLegacyStrategy < Grape::Entity
+ expose :name do |strategy|
+ strategy['name']
+ end
+ expose :parameters do |strategy|
+ strategy['parameters']
+ end
+ end
+ end
+end
diff --git a/lib/api/entities/unleash_strategy.rb b/lib/api/entities/unleash_strategy.rb
new file mode 100644
index 00000000000..7627ce3873c
--- /dev/null
+++ b/lib/api/entities/unleash_strategy.rb
@@ -0,0 +1,10 @@
+# frozen_string_literal: true
+
+module API
+ module Entities
+ class UnleashStrategy < Grape::Entity
+ expose :name
+ expose :parameters
+ end
+ end
+end
diff --git a/lib/api/entities/user_with_admin.rb b/lib/api/entities/user_with_admin.rb
index c225ade6eb6..ab7bc738ff8 100644
--- a/lib/api/entities/user_with_admin.rb
+++ b/lib/api/entities/user_with_admin.rb
@@ -8,3 +8,5 @@ module API
end
end
end
+
+API::Entities::UserWithAdmin.prepend_if_ee('EE::API::Entities::UserWithAdmin')
diff --git a/lib/api/environments.rb b/lib/api/environments.rb
index b825904e2c5..0e780d4ef36 100644
--- a/lib/api/environments.rb
+++ b/lib/api/environments.rb
@@ -2,7 +2,7 @@
module API
# Environments RESTfull API endpoints
- class Environments < Grape::API::Instance
+ class Environments < ::API::Base
include PaginationParams
before { authenticate! }
diff --git a/lib/api/error_tracking.rb b/lib/api/error_tracking.rb
index 64ec6f0a57a..03f83477954 100644
--- a/lib/api/error_tracking.rb
+++ b/lib/api/error_tracking.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module API
- class ErrorTracking < Grape::API::Instance
+ class ErrorTracking < ::API::Base
before { authenticate! }
params do
diff --git a/lib/api/events.rb b/lib/api/events.rb
index 0b79431a76d..43efacf9c0b 100644
--- a/lib/api/events.rb
+++ b/lib/api/events.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module API
- class Events < Grape::API::Instance
+ class Events < ::API::Base
include PaginationParams
include APIGuard
helpers ::API::Helpers::EventsHelpers
diff --git a/lib/api/feature_flag_scopes.rb b/lib/api/feature_flag_scopes.rb
new file mode 100644
index 00000000000..d77e243aa88
--- /dev/null
+++ b/lib/api/feature_flag_scopes.rb
@@ -0,0 +1,158 @@
+# frozen_string_literal: true
+
+module API
+ class FeatureFlagScopes < ::API::Base
+ include PaginationParams
+
+ ENVIRONMENT_SCOPE_ENDPOINT_REQUIREMENTS = FeatureFlags::FEATURE_FLAG_ENDPOINT_REQUIREMENTS
+ .merge(environment_scope: API::NO_SLASH_URL_PART_REGEX)
+
+ before do
+ authorize_read_feature_flags!
+ end
+
+ params do
+ requires :id, type: String, desc: 'The ID of a project'
+ end
+ resource 'projects/:id', requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
+ resource :feature_flag_scopes do
+ desc 'Get all effective feature flags under the environment' do
+ detail 'This feature was introduced in GitLab 12.5'
+ success ::API::Entities::FeatureFlag::DetailedLegacyScope
+ end
+ params do
+ requires :environment, type: String, desc: 'The environment name'
+ end
+ get do
+ present scopes_for_environment, with: ::API::Entities::FeatureFlag::DetailedLegacyScope
+ end
+ end
+
+ params do
+ requires :name, type: String, desc: 'The name of the feature flag'
+ end
+ resource 'feature_flags/:name', requirements: FeatureFlags::FEATURE_FLAG_ENDPOINT_REQUIREMENTS do
+ resource :scopes do
+ desc 'Get all scopes of a feature flag' do
+ detail 'This feature was introduced in GitLab 12.5'
+ success ::API::Entities::FeatureFlag::LegacyScope
+ end
+ params do
+ use :pagination
+ end
+ get do
+ present paginate(feature_flag.scopes), with: ::API::Entities::FeatureFlag::LegacyScope
+ end
+
+ desc 'Create a scope of a feature flag' do
+ detail 'This feature was introduced in GitLab 12.5'
+ success ::API::Entities::FeatureFlag::LegacyScope
+ end
+ params do
+ requires :environment_scope, type: String, desc: 'The environment scope of the scope'
+ requires :active, type: Boolean, desc: 'Whether the scope is active'
+ requires :strategies, type: JSON, desc: 'The strategies of the scope'
+ end
+ post do
+ authorize_update_feature_flag!
+
+ result = ::FeatureFlags::UpdateService
+ .new(user_project, current_user, scopes_attributes: [declared_params])
+ .execute(feature_flag)
+
+ if result[:status] == :success
+ present scope, with: ::API::Entities::FeatureFlag::LegacyScope
+ else
+ render_api_error!(result[:message], result[:http_status])
+ end
+ end
+
+ params do
+ requires :environment_scope, type: String, desc: 'URL-encoded environment scope'
+ end
+ resource ':environment_scope', requirements: ENVIRONMENT_SCOPE_ENDPOINT_REQUIREMENTS do
+ desc 'Get a scope of a feature flag' do
+ detail 'This feature was introduced in GitLab 12.5'
+ success ::API::Entities::FeatureFlag::LegacyScope
+ end
+ get do
+ present scope, with: ::API::Entities::FeatureFlag::LegacyScope
+ end
+
+ desc 'Update a scope of a feature flag' do
+ detail 'This feature was introduced in GitLab 12.5'
+ success ::API::Entities::FeatureFlag::LegacyScope
+ end
+ params do
+ optional :active, type: Boolean, desc: 'Whether the scope is active'
+ optional :strategies, type: JSON, desc: 'The strategies of the scope'
+ end
+ put do
+ authorize_update_feature_flag!
+
+ scope_attributes = declared_params.merge(id: scope.id)
+
+ result = ::FeatureFlags::UpdateService
+ .new(user_project, current_user, scopes_attributes: [scope_attributes])
+ .execute(feature_flag)
+
+ if result[:status] == :success
+ updated_scope = result[:feature_flag].scopes
+ .find { |scope| scope.environment_scope == params[:environment_scope] }
+
+ present updated_scope, with: ::API::Entities::FeatureFlag::LegacyScope
+ else
+ render_api_error!(result[:message], result[:http_status])
+ end
+ end
+
+ desc 'Delete a scope from a feature flag' do
+ detail 'This feature was introduced in GitLab 12.5'
+ success ::API::Entities::FeatureFlag::LegacyScope
+ end
+ delete do
+ authorize_update_feature_flag!
+
+ param = { scopes_attributes: [{ id: scope.id, _destroy: true }] }
+
+ result = ::FeatureFlags::UpdateService
+ .new(user_project, current_user, param)
+ .execute(feature_flag)
+
+ if result[:status] == :success
+ status :no_content
+ else
+ render_api_error!(result[:message], result[:http_status])
+ end
+ end
+ end
+ end
+ end
+ end
+
+ helpers do
+ def authorize_read_feature_flags!
+ authorize! :read_feature_flag, user_project
+ end
+
+ def authorize_update_feature_flag!
+ authorize! :update_feature_flag, feature_flag
+ end
+
+ def feature_flag
+ @feature_flag ||= user_project.operations_feature_flags
+ .find_by_name!(params[:name])
+ end
+
+ def scope
+ @scope ||= feature_flag.scopes
+ .find_by_environment_scope!(CGI.unescape(params[:environment_scope]))
+ end
+
+ def scopes_for_environment
+ Operations::FeatureFlagScope
+ .for_unleash_client(user_project, params[:environment])
+ end
+ end
+ end
+end
diff --git a/lib/api/feature_flags.rb b/lib/api/feature_flags.rb
new file mode 100644
index 00000000000..613c3fb0f5b
--- /dev/null
+++ b/lib/api/feature_flags.rb
@@ -0,0 +1,266 @@
+# frozen_string_literal: true
+
+module API
+ class FeatureFlags < ::API::Base
+ include PaginationParams
+
+ FEATURE_FLAG_ENDPOINT_REQUIREMENTS = API::NAMESPACE_OR_PROJECT_REQUIREMENTS
+ .merge(name: API::NO_SLASH_URL_PART_REGEX)
+
+ before do
+ authorize_read_feature_flags!
+ end
+
+ params do
+ requires :id, type: String, desc: 'The ID of a 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'
+ success ::API::Entities::FeatureFlag
+ end
+ params do
+ optional :scope, type: String, desc: 'The scope of feature flags',
+ values: %w[enabled disabled]
+ use :pagination
+ end
+ get do
+ feature_flags = ::FeatureFlagsFinder
+ .new(user_project, current_user, declared_params(include_missing: false))
+ .execute
+
+ present_entity(paginate(feature_flags))
+ end
+
+ desc 'Create a new feature flag' do
+ detail 'This feature was introduced in GitLab 12.5'
+ success ::API::Entities::FeatureFlag
+ end
+ params do
+ requires :name, type: String, desc: 'The name of 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 :strategies, type: Array do
+ requires :name, type: String, desc: 'The strategy name'
+ requires :parameters, type: JSON, desc: 'The strategy parameters'
+ optional :scopes, type: Array do
+ requires :environment_scope, type: String, desc: 'The environment scope of the scope'
+ end
+ end
+ end
+ post do
+ authorize_create_feature_flag!
+
+ attrs = declared_params(include_missing: false)
+
+ ensure_post_version_2_flags_enabled! if attrs[:version] == 'new_version_flag'
+
+ rename_key(attrs, :scopes, :scopes_attributes)
+ rename_key(attrs, :strategies, :strategies_attributes)
+ update_value(attrs, :strategies_attributes) do |strategies|
+ strategies.map { |s| rename_key(s, :scopes, :scopes_attributes) }
+ end
+
+ result = ::FeatureFlags::CreateService
+ .new(user_project, current_user, attrs)
+ .execute
+
+ if result[:status] == :success
+ present_entity(result[:feature_flag])
+ else
+ render_api_error!(result[:message], result[:http_status])
+ end
+ end
+ end
+
+ params do
+ 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'
+ success ::API::Entities::FeatureFlag
+ end
+ get do
+ authorize_read_feature_flag!
+
+ present_entity(feature_flag)
+ end
+
+ desc 'Enable a strategy for a feature flag on an environment' do
+ detail 'This feature was introduced in GitLab 12.5'
+ success ::API::Entities::FeatureFlag
+ end
+ params do
+ requires :environment_scope, type: String, desc: 'The environment scope of the feature flag'
+ requires :strategy, type: JSON, desc: 'The strategy to be enabled on the scope'
+ end
+ post :enable do
+ not_found! unless Feature.enabled?(:feature_flag_api, user_project)
+ render_api_error!('Version 2 flags not supported', :unprocessable_entity) if new_version_flag_present?
+
+ result = ::FeatureFlags::EnableService
+ .new(user_project, current_user, params).execute
+
+ if result[:status] == :success
+ status :ok
+ present_entity(result[:feature_flag])
+ else
+ render_api_error!(result[:message], result[:http_status])
+ end
+ end
+
+ desc 'Disable a strategy for a feature flag on an environment' do
+ detail 'This feature is going to be introduced in GitLab 12.5 if `feature_flag_api` feature flag is removed'
+ success ::API::Entities::FeatureFlag
+ end
+ params do
+ requires :environment_scope, type: String, desc: 'The environment scope of the feature flag'
+ requires :strategy, type: JSON, desc: 'The strategy to be disabled on the scope'
+ end
+ post :disable do
+ not_found! unless Feature.enabled?(:feature_flag_api, user_project)
+ render_api_error!('Version 2 flags not supported', :unprocessable_entity) if feature_flag.new_version_flag?
+
+ result = ::FeatureFlags::DisableService
+ .new(user_project, current_user, params).execute
+
+ if result[:status] == :success
+ status :ok
+ present_entity(result[:feature_flag])
+ else
+ render_api_error!(result[:message], result[:http_status])
+ end
+ end
+
+ desc 'Update a feature flag' do
+ detail 'This feature will be introduced in GitLab 13.1 if feature_flags_new_version feature flag is removed'
+ success ::API::Entities::FeatureFlag
+ end
+ params do
+ optional :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 :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 :_destroy, type: Boolean, desc: 'Delete the strategy when true'
+ optional :scopes, type: Array do
+ optional :id, type: Integer, desc: 'The environment 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
+ end
+ end
+ put do
+ not_found! unless feature_flags_new_version_enabled?
+ authorize_update_feature_flag!
+ render_api_error!('PUT operations are not supported for legacy feature flags', :unprocessable_entity) if feature_flag.legacy_flag?
+
+ attrs = declared_params(include_missing: false)
+
+ rename_key(attrs, :strategies, :strategies_attributes)
+ update_value(attrs, :strategies_attributes) do |strategies|
+ strategies.map { |s| rename_key(s, :scopes, :scopes_attributes) }
+ end
+
+ result = ::FeatureFlags::UpdateService
+ .new(user_project, current_user, attrs)
+ .execute(feature_flag)
+
+ if result[:status] == :success
+ present_entity(result[:feature_flag])
+ else
+ render_api_error!(result[:message], result[:http_status])
+ end
+ end
+
+ desc 'Delete a feature flag' do
+ detail 'This feature was introduced in GitLab 12.5'
+ success ::API::Entities::FeatureFlag
+ end
+ delete do
+ authorize_destroy_feature_flag!
+
+ result = ::FeatureFlags::DestroyService
+ .new(user_project, current_user, declared_params(include_missing: false))
+ .execute(feature_flag)
+
+ if result[:status] == :success
+ present_entity(result[:feature_flag])
+ else
+ render_api_error!(result[:message], result[:http_status])
+ end
+ end
+ end
+ end
+
+ helpers do
+ def authorize_read_feature_flags!
+ authorize! :read_feature_flag, user_project
+ end
+
+ def authorize_read_feature_flag!
+ authorize! :read_feature_flag, feature_flag
+ end
+
+ def authorize_create_feature_flag!
+ authorize! :create_feature_flag, user_project
+ end
+
+ def authorize_update_feature_flag!
+ authorize! :update_feature_flag, feature_flag
+ end
+
+ def authorize_destroy_feature_flag!
+ authorize! :destroy_feature_flag, feature_flag
+ end
+
+ def present_entity(result)
+ present result,
+ with: ::API::Entities::FeatureFlag,
+ feature_flags_new_version_enabled: feature_flags_new_version_enabled?
+ end
+
+ def ensure_post_version_2_flags_enabled!
+ unless feature_flags_new_version_enabled?
+ render_api_error!('Version 2 flags are not enabled for this project', :unprocessable_entity)
+ end
+ end
+
+ def feature_flag
+ @feature_flag ||= if feature_flags_new_version_enabled?
+ user_project.operations_feature_flags.find_by_name!(params[:feature_flag_name])
+ else
+ user_project.operations_feature_flags.legacy_flag.find_by_name!(params[:feature_flag_name])
+ end
+ end
+
+ def new_version_flag_present?
+ user_project.operations_feature_flags.new_version_flag.find_by_name(params[:name]).present?
+ end
+
+ def feature_flags_new_version_enabled?
+ Feature.enabled?(:feature_flags_new_version, user_project, default_enabled: true)
+ end
+
+ def rename_key(hash, old_key, new_key)
+ hash[new_key] = hash.delete(old_key) if hash.key?(old_key)
+ hash
+ end
+
+ def update_value(hash, key)
+ hash[key] = yield(hash[key]) if hash.key?(key)
+ hash
+ end
+ end
+ end
+end
diff --git a/lib/api/feature_flags_user_lists.rb b/lib/api/feature_flags_user_lists.rb
new file mode 100644
index 00000000000..e5218cfd7f1
--- /dev/null
+++ b/lib/api/feature_flags_user_lists.rb
@@ -0,0 +1,100 @@
+# frozen_string_literal: true
+
+module API
+ class FeatureFlagsUserLists < ::API::Base
+ include PaginationParams
+
+ error_formatter :json, -> (message, _backtrace, _options, _env, _original_exception) {
+ message.is_a?(String) ? { message: message }.to_json : message.to_json
+ }
+
+ before do
+ authorize_admin_feature_flags_user_lists!
+ end
+
+ params do
+ requires :id, type: String, desc: 'The ID of a 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'
+ success ::API::Entities::FeatureFlag::UserList
+ end
+ params do
+ use :pagination
+ end
+ get do
+ present paginate(user_project.operations_feature_flags_user_lists),
+ 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'
+ success ::API::Entities::FeatureFlag::UserList
+ end
+ params do
+ requires :name, type: String, desc: 'The name of the list'
+ requires :user_xids, type: String, desc: 'A comma separated list of external user ids'
+ end
+ post do
+ list = user_project.operations_feature_flags_user_lists.create(declared_params)
+
+ if list.save
+ present list, with: ::API::Entities::FeatureFlag::UserList
+ else
+ render_api_error!(list.errors.full_messages, :bad_request)
+ end
+ end
+ end
+
+ params do
+ requires :iid, type: String, desc: 'The internal id of the 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'
+ success ::API::Entities::FeatureFlag::UserList
+ end
+ get do
+ present user_project.operations_feature_flags_user_lists.find_by_iid!(params[:iid]),
+ with: ::API::Entities::FeatureFlag::UserList
+ end
+
+ desc 'Update a feature flag user list' do
+ detail 'This feature was introduced in GitLab 12.10'
+ success ::API::Entities::FeatureFlag::UserList
+ end
+ params do
+ optional :name, type: String, desc: 'The name of the list'
+ optional :user_xids, type: String, desc: 'A comma separated list of external user ids'
+ end
+ put do
+ list = user_project.operations_feature_flags_user_lists.find_by_iid!(params[:iid])
+
+ if list.update(declared_params(include_missing: false))
+ present list, with: ::API::Entities::FeatureFlag::UserList
+ else
+ render_api_error!(list.errors.full_messages, :bad_request)
+ end
+ end
+
+ desc 'Delete a feature flag user list' do
+ detail 'This feature was introduced in GitLab 12.10'
+ end
+ delete do
+ list = user_project.operations_feature_flags_user_lists.find_by_iid!(params[:iid])
+ unless list.destroy
+ render_api_error!(list.errors.full_messages, :conflict)
+ end
+ end
+ end
+ end
+
+ helpers do
+ def authorize_admin_feature_flags_user_lists!
+ authorize! :admin_feature_flags_user_lists, user_project
+ end
+ end
+ end
+end
diff --git a/lib/api/features.rb b/lib/api/features.rb
index 9d011d658f6..5d2e545abd6 100644
--- a/lib/api/features.rb
+++ b/lib/api/features.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module API
- class Features < Grape::API::Instance
+ class Features < ::API::Base
before { authenticated_as_admin! }
helpers do
diff --git a/lib/api/files.rb b/lib/api/files.rb
index 748bdfa894d..6833fc429e2 100644
--- a/lib/api/files.rb
+++ b/lib/api/files.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module API
- class Files < Grape::API::Instance
+ class Files < ::API::Base
include APIGuard
FILE_ENDPOINT_REQUIREMENTS = API::NAMESPACE_OR_PROJECT_REQUIREMENTS.merge(file_path: API::NO_SLASH_URL_PART_REGEX)
diff --git a/lib/api/freeze_periods.rb b/lib/api/freeze_periods.rb
index b8254ee9ab4..a83e36165a2 100644
--- a/lib/api/freeze_periods.rb
+++ b/lib/api/freeze_periods.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module API
- class FreezePeriods < Grape::API::Instance
+ class FreezePeriods < ::API::Base
include PaginationParams
before { authenticate! }
diff --git a/lib/api/generic_packages.rb b/lib/api/generic_packages.rb
index 98b8a40c7c9..a0c33ab65b9 100644
--- a/lib/api/generic_packages.rb
+++ b/lib/api/generic_packages.rb
@@ -1,7 +1,12 @@
# frozen_string_literal: true
module API
- class GenericPackages < Grape::API::Instance
+ class GenericPackages < ::API::Base
+ GENERIC_PACKAGES_REQUIREMENTS = {
+ package_name: API::NO_SLASH_URL_PART_REGEX,
+ file_name: API::NO_SLASH_URL_PART_REGEX
+ }.freeze
+
before do
require_packages_enabled!
authenticate!
@@ -17,17 +22,94 @@ module API
route_setting :authentication, job_token_allowed: true
namespace ':id/packages/generic' do
- get 'ping' do
- :pong
+ namespace ':package_name/*package_version/:file_name', requirements: GENERIC_PACKAGES_REQUIREMENTS do
+ desc 'Workhorse authorize generic package file' do
+ detail 'This feature was introduced in GitLab 13.5'
+ end
+
+ route_setting :authentication, job_token_allowed: true
+
+ params do
+ requires :package_name, type: String, desc: 'Package name', regexp: Gitlab::Regex.generic_package_name_regex, file_path: true
+ 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
+ end
+
+ put 'authorize' do
+ authorize_workhorse!(subject: project, maximum_size: project.actual_limits.generic_packages_max_file_size)
+ end
+
+ desc 'Upload package file' do
+ detail 'This feature was introduced in GitLab 13.5'
+ end
+
+ params do
+ requires :package_name, type: String, desc: 'Package name', regexp: Gitlab::Regex.generic_package_name_regex, file_path: true
+ 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
+ requires :file, type: ::API::Validations::Types::WorkhorseFile, desc: 'The package file to be published (generated by Multipart middleware)'
+ end
+
+ route_setting :authentication, job_token_allowed: true
+
+ put do
+ authorize_upload!(project)
+ bad_request!('File is too large') if max_file_size_exceeded?
+
+ track_event('push_package')
+
+ create_package_file_params = declared_params.merge(build: current_authenticated_job)
+ ::Packages::Generic::CreatePackageFileService
+ .new(project, current_user, create_package_file_params)
+ .execute
+
+ created!
+ rescue ObjectStorage::RemoteStoreError => e
+ Gitlab::ErrorTracking.track_exception(e, extra: { file_name: params[:file_name], project_id: project.id })
+
+ forbidden!
+ end
+
+ desc 'Download package file' do
+ detail 'This feature was introduced in GitLab 13.5'
+ end
+
+ params do
+ requires :package_name, type: String, desc: 'Package name', regexp: Gitlab::Regex.generic_package_name_regex, file_path: true
+ 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
+ end
+
+ route_setting :authentication, job_token_allowed: true
+
+ get do
+ authorize_read_package!(project)
+
+ package = ::Packages::Generic::PackageFinder.new(project).execute!(params[:package_name], params[:package_version])
+ package_file = ::Packages::PackageFileFinder.new(package, params[:file_name]).execute!
+
+ track_event('pull_package')
+
+ present_carrierwave_file!(package_file.file)
+ end
end
end
end
helpers do
include ::API::Helpers::PackagesHelpers
+ include ::API::Helpers::Packages::BasicAuthHelpers
def require_generic_packages_available!
- not_found! unless Feature.enabled?(:generic_packages, user_project)
+ not_found! unless Feature.enabled?(:generic_packages, project, default_enabled: true)
+ end
+
+ def project
+ authorized_user_project
+ end
+
+ def max_file_size_exceeded?
+ project.actual_limits.exceeded?(:generic_packages_max_file_size, params[:file].size)
end
end
end
diff --git a/lib/api/github/entities.rb b/lib/api/github/entities.rb
index c28a0b8eb7e..fe228c9a2d2 100644
--- a/lib/api/github/entities.rb
+++ b/lib/api/github/entities.rb
@@ -119,7 +119,9 @@ module API
expose :username, as: :login
expose :user_url, as: :url
expose :user_url, as: :html_url
- expose :avatar_url
+ expose :avatar_url do |user|
+ user.avatar_url(only_path: false)
+ end
private
diff --git a/lib/api/go_proxy.rb b/lib/api/go_proxy.rb
index c0207f9169c..30f0cfb4dfd 100755
--- a/lib/api/go_proxy.rb
+++ b/lib/api/go_proxy.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
module API
- class GoProxy < Grape::API::Instance
+ class GoProxy < ::API::Base
helpers Gitlab::Golang
helpers ::API::Helpers::PackagesHelpers
diff --git a/lib/api/group_boards.rb b/lib/api/group_boards.rb
index 7efc12121d2..d4574b22d99 100644
--- a/lib/api/group_boards.rb
+++ b/lib/api/group_boards.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module API
- class GroupBoards < Grape::API::Instance
+ class GroupBoards < ::API::Base
include BoardsResponses
include PaginationParams
diff --git a/lib/api/group_clusters.rb b/lib/api/group_clusters.rb
index ae41d9f13b8..75429cf7a5c 100644
--- a/lib/api/group_clusters.rb
+++ b/lib/api/group_clusters.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module API
- class GroupClusters < Grape::API::Instance
+ class GroupClusters < ::API::Base
include PaginationParams
before { authenticate! }
@@ -41,6 +41,7 @@ module API
requires :name, type: String, desc: 'Cluster name'
optional :enabled, type: Boolean, default: true, desc: 'Determines if cluster is active or not, defaults to true'
optional :environment_scope, default: '*', type: String, desc: 'The associated environment to the cluster'
+ optional :namespace_per_environment, default: true, type: Boolean, desc: 'Deploy each environment to a separate Kubernetes namespace'
optional :domain, type: String, desc: 'Cluster base domain'
optional :management_project_id, type: Integer, desc: 'The ID of the management project'
optional :managed, type: Boolean, default: true, desc: 'Determines if GitLab will manage namespaces and service accounts for this cluster, defaults to true'
@@ -74,6 +75,7 @@ module API
optional :name, type: String, desc: 'Cluster name'
optional :domain, type: String, desc: 'Cluster base domain'
optional :environment_scope, type: String, desc: 'The associated environment to the cluster'
+ optional :namespace_per_environment, default: true, type: Boolean, desc: 'Deploy each environment to a separate Kubernetes namespace'
optional :management_project_id, type: Integer, desc: 'The ID of the management project'
optional :platform_kubernetes_attributes, type: Hash, desc: %q(Platform Kubernetes data) do
optional :api_url, type: String, desc: 'URL to access the Kubernetes API'
diff --git a/lib/api/group_container_repositories.rb b/lib/api/group_container_repositories.rb
index 25b3059f63b..1bb26b3931c 100644
--- a/lib/api/group_container_repositories.rb
+++ b/lib/api/group_container_repositories.rb
@@ -1,9 +1,11 @@
# frozen_string_literal: true
module API
- class GroupContainerRepositories < Grape::API::Instance
+ class GroupContainerRepositories < ::API::Base
include PaginationParams
+ helpers ::API::Helpers::PackagesHelpers
+
before { authorize_read_group_container_images! }
REPOSITORY_ENDPOINT_REQUIREMENTS = API::NAMESPACE_OR_PROJECT_REQUIREMENTS.merge(
@@ -27,7 +29,7 @@ module API
user: current_user, subject: user_group
).execute
- track_event('list_repositories')
+ track_package_event('list_repositories', :container)
present paginate(repositories), with: Entities::ContainerRegistry::Repository, tags: params[:tags], tags_count: params[:tags_count]
end
diff --git a/lib/api/group_export.rb b/lib/api/group_export.rb
index dc14813eefc..6ebaa8de185 100644
--- a/lib/api/group_export.rb
+++ b/lib/api/group_export.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module API
- class GroupExport < Grape::API::Instance
+ class GroupExport < ::API::Base
helpers Helpers::RateLimiter
before do
diff --git a/lib/api/group_import.rb b/lib/api/group_import.rb
index b82d9fc519a..e703a217fd5 100644
--- a/lib/api/group_import.rb
+++ b/lib/api/group_import.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module API
- class GroupImport < Grape::API::Instance
+ class GroupImport < ::API::Base
helpers Helpers::FileUploadHelpers
helpers do
diff --git a/lib/api/group_labels.rb b/lib/api/group_labels.rb
index 56f2b769464..8443ddf10ce 100644
--- a/lib/api/group_labels.rb
+++ b/lib/api/group_labels.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module API
- class GroupLabels < Grape::API::Instance
+ class GroupLabels < ::API::Base
include PaginationParams
helpers ::API::Helpers::LabelHelpers
diff --git a/lib/api/group_milestones.rb b/lib/api/group_milestones.rb
index 82f5df79356..aef9877b84c 100644
--- a/lib/api/group_milestones.rb
+++ b/lib/api/group_milestones.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module API
- class GroupMilestones < Grape::API::Instance
+ class GroupMilestones < ::API::Base
include MilestoneResponses
include PaginationParams
diff --git a/lib/api/group_packages.rb b/lib/api/group_packages.rb
index aa047e260f5..5b6290df0dd 100644
--- a/lib/api/group_packages.rb
+++ b/lib/api/group_packages.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module API
- class GroupPackages < Grape::API::Instance
+ class GroupPackages < ::API::Base
include PaginationParams
before do
diff --git a/lib/api/group_variables.rb b/lib/api/group_variables.rb
index e7b8cd10197..ee110d67fa5 100644
--- a/lib/api/group_variables.rb
+++ b/lib/api/group_variables.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module API
- class GroupVariables < Grape::API::Instance
+ class GroupVariables < ::API::Base
include PaginationParams
before { authenticate! }
diff --git a/lib/api/groups.rb b/lib/api/groups.rb
index 813e41b4d39..bf3d6c3c7e0 100644
--- a/lib/api/groups.rb
+++ b/lib/api/groups.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module API
- class Groups < Grape::API::Instance
+ class Groups < ::API::Base
include PaginationParams
include Helpers::CustomAttributes
@@ -29,7 +29,12 @@ module API
# rubocop: disable CodeReuse/ActiveRecord
def find_groups(params, parent_id = nil)
- find_params = params.slice(:all_available, :custom_attributes, :owned, :min_access_level)
+ find_params = params.slice(
+ :all_available,
+ :custom_attributes,
+ :owned, :min_access_level,
+ :include_parent_descendants
+ )
find_params[:parent] = if params[:top_level_only]
[nil]
@@ -309,6 +314,19 @@ module API
present_groups params, groups
end
+ desc 'Get a list of descendant groups of this group.' do
+ success Entities::Group
+ end
+ params do
+ use :group_list_params
+ use :with_custom_attributes
+ end
+ get ":id/descendant_groups" do
+ finder_params = declared_params(include_missing: false).merge(include_parent_descendants: true)
+ groups = find_groups(finder_params, params[:id])
+ present_groups params, groups
+ end
+
desc 'Transfer a project to the group namespace. Available only for admin.' do
success Entities::GroupDetail
end
diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb
index 1912a06682e..c8aee1f3479 100644
--- a/lib/api/helpers.rb
+++ b/lib/api/helpers.rb
@@ -522,7 +522,7 @@ module API
else
header(*Gitlab::Workhorse.send_url(file.url))
status :ok
- body
+ body ""
end
end
@@ -544,7 +544,6 @@ module API
feature_name = "usage_data_#{event_name}"
return unless Feature.enabled?(feature_name)
- return unless Gitlab::CurrentSettings.usage_ping_enabled?
Gitlab::UsageDataCounters::HLLRedisCounter.track_event(values, event_name)
rescue => error
diff --git a/lib/api/helpers/groups_helpers.rb b/lib/api/helpers/groups_helpers.rb
index f3dfc093926..ba07a70ee32 100644
--- a/lib/api/helpers/groups_helpers.rb
+++ b/lib/api/helpers/groups_helpers.rb
@@ -24,6 +24,7 @@ module API
optional :lfs_enabled, type: Boolean, desc: 'Enable/disable LFS for the projects in this group'
optional :request_access_enabled, type: Boolean, desc: 'Allow users to request member access'
optional :default_branch_protection, type: Integer, values: ::Gitlab::Access.protection_values, desc: 'Determine if developers can push to master'
+ optional :shared_runners_setting, type: String, values: ::Namespace::SHARED_RUNNERS_SETTINGS, desc: 'Enable/disable shared runners for the group and its subgroups and projects'
end
params :optional_params_ee do
diff --git a/lib/api/helpers/merge_requests_helpers.rb b/lib/api/helpers/merge_requests_helpers.rb
index e4163c63575..9b38eeb1e72 100644
--- a/lib/api/helpers/merge_requests_helpers.rb
+++ b/lib/api/helpers/merge_requests_helpers.rb
@@ -73,6 +73,13 @@ module API
optional :not, type: Hash, desc: 'Parameters to negate' do
use :merge_requests_negatable_params
end
+
+ optional :deployed_before,
+ 'Return merge requests deployed before the given date/time'
+ optional :deployed_after,
+ 'Return merge requests deployed after the given date/time'
+ optional :environment,
+ 'Returns merge requests deployed to the given environment'
end
params :optional_scope_param do
diff --git a/lib/api/helpers/packages/conan/api_helpers.rb b/lib/api/helpers/packages/conan/api_helpers.rb
index dcbf933a4e1..934e18bdd0a 100644
--- a/lib/api/helpers/packages/conan/api_helpers.rb
+++ b/lib/api/helpers/packages/conan/api_helpers.rb
@@ -158,7 +158,7 @@ module API
conan_package_reference: params[:conan_package_reference]
).execute!
- package_event('pull_package', category: 'API::ConanPackages') if params[:file_name] == ::Packages::Conan::FileMetadatum::PACKAGE_BINARY
+ track_package_event('pull_package', :conan, category: 'API::ConanPackages') if params[:file_name] == ::Packages::Conan::FileMetadatum::PACKAGE_BINARY
present_carrierwave_file!(package_file.file)
end
@@ -169,7 +169,7 @@ module API
def track_push_package_event
if params[:file_name] == ::Packages::Conan::FileMetadatum::PACKAGE_BINARY && params[:file].size > 0 # rubocop: disable Style/ZeroLengthPredicate
- package_event('push_package', category: 'API::ConanPackages')
+ track_package_event('push_package', :conan, category: 'API::ConanPackages')
end
end
diff --git a/lib/api/helpers/packages/dependency_proxy_helpers.rb b/lib/api/helpers/packages/dependency_proxy_helpers.rb
index 254af7690a2..577ba97d68a 100644
--- a/lib/api/helpers/packages/dependency_proxy_helpers.rb
+++ b/lib/api/helpers/packages/dependency_proxy_helpers.rb
@@ -10,6 +10,7 @@ module API
def redirect_registry_request(forward_to_registry, package_type, options)
if forward_to_registry && redirect_registry_request_available?
+ track_event("#{package_type}_request_forward")
redirect(registry_url(package_type, options))
else
yield
diff --git a/lib/api/helpers/packages_helpers.rb b/lib/api/helpers/packages_helpers.rb
index 403f5ea3851..e1898d28ef7 100644
--- a/lib/api/helpers/packages_helpers.rb
+++ b/lib/api/helpers/packages_helpers.rb
@@ -40,7 +40,7 @@ module API
params = { has_length: has_length }
params[:maximum_size] = maximum_size unless has_length
- ::Packages::PackageFileUploader.workhorse_authorize(params)
+ ::Packages::PackageFileUploader.workhorse_authorize(**params)
end
def authorize_upload!(subject = user_project)
@@ -48,7 +48,8 @@ module API
require_gitlab_workhorse!
end
- def package_event(event_name, **args)
+ def track_package_event(event_name, scope, **args)
+ ::Packages::CreateEventService.new(nil, current_user, event_name: event_name, scope: scope).execute
track_event(event_name, **args)
end
end
diff --git a/lib/api/helpers/pagination.rb b/lib/api/helpers/pagination.rb
index a6ae9a87f98..227aec224e5 100644
--- a/lib/api/helpers/pagination.rb
+++ b/lib/api/helpers/pagination.rb
@@ -3,8 +3,8 @@
module API
module Helpers
module Pagination
- def paginate(relation)
- Gitlab::Pagination::OffsetPagination.new(self).paginate(relation)
+ def paginate(*args)
+ Gitlab::Pagination::OffsetPagination.new(self).paginate(*args)
end
end
end
diff --git a/lib/api/helpers/presentable.rb b/lib/api/helpers/presentable.rb
index a5186cc56ea..40e1b266df5 100644
--- a/lib/api/helpers/presentable.rb
+++ b/lib/api/helpers/presentable.rb
@@ -23,7 +23,7 @@ module API
def initialize(object, options = {})
options = options.opts_hash if options.is_a?(Grape::Entity::Options)
- super(object.present(options), options)
+ super(object.present(**options), options)
end
end
end
diff --git a/lib/api/helpers/projects_helpers.rb b/lib/api/helpers/projects_helpers.rb
index 8c20f5b8fc2..0364ba2ad9e 100644
--- a/lib/api/helpers/projects_helpers.rb
+++ b/lib/api/helpers/projects_helpers.rb
@@ -83,9 +83,18 @@ module API
params :optional_filter_params_ee do
end
+ params :optional_update_params_ce do
+ optional :ci_forward_deployment_enabled, type: Boolean, desc: 'Skip older deployment jobs that are still pending'
+ end
+
params :optional_update_params_ee do
end
+ params :optional_update_params do
+ use :optional_update_params_ce
+ use :optional_update_params_ee
+ end
+
params :optional_container_expiration_policy_params do
optional :cadence, type: String, desc: 'Container expiration policy cadence for recurring job'
optional :keep_n, type: String, desc: 'Container expiration policy number of images to keep'
@@ -108,6 +117,7 @@ module API
:builds_access_level,
:ci_config_path,
:ci_default_git_depth,
+ :ci_forward_deployment_enabled,
:container_registry_enabled,
:container_expiration_policy_attributes,
:default_branch,
diff --git a/lib/api/helpers/runner.rb b/lib/api/helpers/runner.rb
index 34a2fb09875..1c85669a626 100644
--- a/lib/api/helpers/runner.rb
+++ b/lib/api/helpers/runner.rb
@@ -51,9 +51,7 @@ module API
job_forbidden!(job, 'Job is not running') unless job.running?
end
- if Gitlab::Ci::Features.job_heartbeats_runner?(job.project)
- job.runner&.heartbeat(get_runner_ip)
- end
+ job.runner&.heartbeat(get_runner_ip)
job
end
diff --git a/lib/api/helpers/services_helpers.rb b/lib/api/helpers/services_helpers.rb
index 4bceda51900..4adb27a7414 100644
--- a/lib/api/helpers/services_helpers.rb
+++ b/lib/api/helpers/services_helpers.rb
@@ -381,6 +381,12 @@ module API
type: String,
desc: 'The Hangouts Chat webhook. e.g. https://chat.googleapis.com/v1/spaces…'
},
+ {
+ required: false,
+ name: :branches_to_be_notified,
+ type: String,
+ desc: 'Branches for which notifications are to be sent'
+ },
chat_notification_events
].flatten,
'hipchat' => [
diff --git a/lib/api/helpers/settings_helpers.rb b/lib/api/helpers/settings_helpers.rb
index 65aec6ae2e7..451e578fdd6 100644
--- a/lib/api/helpers/settings_helpers.rb
+++ b/lib/api/helpers/settings_helpers.rb
@@ -12,6 +12,7 @@ module API
def self.optional_attributes
[*::ApplicationSettingsHelper.visible_attributes,
*::ApplicationSettingsHelper.external_authorization_service_attributes,
+ *::ApplicationSettingsHelper.deprecated_attributes,
:performance_bar_allowed_group_id].freeze
end
end
diff --git a/lib/api/helpers/snippets_helpers.rb b/lib/api/helpers/snippets_helpers.rb
index 9224381735f..42f56680ded 100644
--- a/lib/api/helpers/snippets_helpers.rb
+++ b/lib/api/helpers/snippets_helpers.rb
@@ -93,7 +93,7 @@ module API
def validate_params_for_multiple_files(snippet)
return unless params[:content] || params[:file_name]
- if Feature.enabled?(:snippet_multiple_files, current_user) && snippet.multiple_files?
+ if snippet.multiple_files?
render_api_error!({ error: _('To update Snippets with multiple files, you must use the `files` parameter') }, 400)
end
end
diff --git a/lib/api/import_bitbucket_server.rb b/lib/api/import_bitbucket_server.rb
index df3235420e9..a0238c24f3b 100644
--- a/lib/api/import_bitbucket_server.rb
+++ b/lib/api/import_bitbucket_server.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module API
- class ImportBitbucketServer < Grape::API::Instance
+ class ImportBitbucketServer < ::API::Base
helpers do
def client
@client ||= BitbucketServer::Client.new(credentials)
diff --git a/lib/api/import_github.rb b/lib/api/import_github.rb
index 0bab891eada..61fce7a2c1b 100644
--- a/lib/api/import_github.rb
+++ b/lib/api/import_github.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module API
- class ImportGithub < Grape::API::Instance
+ class ImportGithub < ::API::Base
rescue_from Octokit::Unauthorized, with: :provider_unauthorized
before do
diff --git a/lib/api/internal/base.rb b/lib/api/internal/base.rb
index ff687a57888..6d8f13c36e6 100644
--- a/lib/api/internal/base.rb
+++ b/lib/api/internal/base.rb
@@ -3,7 +3,7 @@
module API
# Internal access API
module Internal
- class Base < Grape::API::Instance
+ class Base < ::API::Base
before { authenticate_by_gitlab_shell_token! }
before do
@@ -99,6 +99,14 @@ module API
@project = @container = access_checker.container
end
end
+
+ def validate_actor_key(actor, key_id)
+ return 'Could not find a user without a key' unless key_id
+
+ return 'Could not find the given key' unless actor.key
+
+ 'Could not find a user for the given key' unless actor.user
+ end
end
namespace 'internal' do
@@ -163,28 +171,23 @@ module API
redis: redis_ping
}
end
+
post '/two_factor_recovery_codes' do
status 200
actor.update_last_used_at!
user = actor.user
- if params[:key_id]
- unless actor.key
- break { success: false, message: 'Could not find the given key' }
- end
-
- if actor.key.is_a?(DeployKey)
- break { success: false, message: 'Deploy keys cannot be used to retrieve recovery codes' }
- end
+ error_message = validate_actor_key(actor, params[:key_id])
- unless user
- break { success: false, message: 'Could not find a user for the given key' }
- end
- elsif params[:user_id] && user.nil?
+ if params[:user_id] && user.nil?
break { success: false, message: 'Could not find the given user' }
+ elsif error_message
+ break { success: false, message: error_message }
end
+ break { success: false, message: 'Deploy keys cannot be used to retrieve recovery codes' } if actor.key.is_a?(DeployKey)
+
unless user.two_factor_enabled?
break { success: false, message: 'Two-factor authentication is not enabled for this user' }
end
@@ -204,20 +207,14 @@ module API
actor.update_last_used_at!
user = actor.user
- if params[:key_id]
- unless actor.key
- break { success: false, message: 'Could not find the given key' }
- end
+ error_message = validate_actor_key(actor, params[:key_id])
- if actor.key.is_a?(DeployKey)
- break { success: false, message: 'Deploy keys cannot be used to create personal access tokens' }
- end
+ break { success: false, message: 'Deploy keys cannot be used to create personal access tokens' } if actor.key.is_a?(DeployKey)
- unless user
- break { success: false, message: 'Could not find a user for the given key' }
- end
- elsif params[:user_id] && user.nil?
+ if params[:user_id] && user.nil?
break { success: false, message: 'Could not find the given user' }
+ elsif error_message
+ break { success: false, message: error_message }
end
if params[:name].blank?
@@ -269,6 +266,53 @@ module API
present response, with: Entities::InternalPostReceive::Response
end
+
+ post '/two_factor_config' do
+ status 200
+
+ break { success: false } unless Feature.enabled?(:two_factor_for_cli)
+
+ actor.update_last_used_at!
+ user = actor.user
+
+ error_message = validate_actor_key(actor, params[:key_id])
+
+ if error_message
+ { success: false, message: error_message }
+ elsif actor.key.is_a?(DeployKey)
+ { success: true, two_factor_required: false }
+ else
+ {
+ success: true,
+ two_factor_required: user.two_factor_enabled?
+ }
+ end
+ end
+
+ post '/two_factor_otp_check' do
+ status 200
+
+ break { success: false } unless Feature.enabled?(:two_factor_for_cli)
+
+ actor.update_last_used_at!
+ user = actor.user
+
+ error_message = validate_actor_key(actor, params[:key_id])
+
+ break { success: false, message: error_message } if error_message
+
+ break { success: false, message: 'Deploy keys cannot be used for Two Factor' } if actor.key.is_a?(DeployKey)
+
+ break { success: false, message: 'Two-factor authentication is not enabled for this user' } unless user.two_factor_enabled?
+
+ otp_validation_result = ::Users::ValidateOtpService.new(user).execute(params.fetch(:otp_attempt))
+
+ if otp_validation_result[:status] == :success
+ { success: true }
+ else
+ { success: false, message: 'Invalid OTP' }
+ end
+ end
end
end
end
diff --git a/lib/api/internal/kubernetes.rb b/lib/api/internal/kubernetes.rb
index 6d5dfd086e7..8175b81f900 100644
--- a/lib/api/internal/kubernetes.rb
+++ b/lib/api/internal/kubernetes.rb
@@ -3,7 +3,7 @@
module API
# Kubernetes Internal API
module Internal
- class Kubernetes < Grape::API::Instance
+ class Kubernetes < ::API::Base
before do
check_feature_enabled
authenticate_gitlab_kas_request!
diff --git a/lib/api/internal/lfs.rb b/lib/api/internal/lfs.rb
new file mode 100644
index 00000000000..630f0ec77a8
--- /dev/null
+++ b/lib/api/internal/lfs.rb
@@ -0,0 +1,54 @@
+# frozen_string_literal: true
+
+module API
+ module Internal
+ class Lfs < ::API::Base
+ use Rack::Sendfile
+
+ before { authenticate_by_gitlab_shell_token! }
+
+ helpers do
+ def find_lfs_object(lfs_oid)
+ LfsObject.find_by_oid(lfs_oid)
+ end
+ end
+
+ namespace 'internal' do
+ namespace 'lfs' do
+ desc 'Get LFS URL for object ID' do
+ detail 'This feature was introduced in GitLab 13.5.'
+ end
+ params do
+ requires :oid, type: String, desc: 'The object ID to query'
+ requires :gl_repository, type: String, desc: "Project identifier (e.g. project-1)"
+ end
+ get "/" do
+ lfs_object = find_lfs_object(params[:oid])
+
+ not_found! unless lfs_object
+
+ _, project, repo_type = Gitlab::GlRepository.parse(params[:gl_repository])
+
+ not_found! unless repo_type.project? && project
+ not_found! unless lfs_object.project_allowed_access?(project)
+
+ file = lfs_object.file
+
+ not_found! unless file&.exists?
+
+ content_type 'application/octet-stream'
+
+ if file.file_storage?
+ sendfile file.path
+ else
+ workhorse_headers = Gitlab::Workhorse.send_url(file.url)
+ header workhorse_headers[0], workhorse_headers[1]
+ env['api.format'] = :binary
+ body ""
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/api/internal/pages.rb b/lib/api/internal/pages.rb
index 5f8d23f15fa..51136144c19 100644
--- a/lib/api/internal/pages.rb
+++ b/lib/api/internal/pages.rb
@@ -3,7 +3,7 @@
module API
# Pages Internal API
module Internal
- class Pages < Grape::API::Instance
+ class Pages < ::API::Base
before do
authenticate_gitlab_pages_request!
end
diff --git a/lib/api/issue_links.rb b/lib/api/issue_links.rb
index 6cc5b344f47..db4979c9052 100644
--- a/lib/api/issue_links.rb
+++ b/lib/api/issue_links.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module API
- class IssueLinks < Grape::API::Instance
+ class IssueLinks < ::API::Base
include PaginationParams
before { authenticate! }
diff --git a/lib/api/issues.rb b/lib/api/issues.rb
index 0e5b0fae6e2..143f9e40736 100644
--- a/lib/api/issues.rb
+++ b/lib/api/issues.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module API
- class Issues < Grape::API::Instance
+ class Issues < ::API::Base
include PaginationParams
helpers Helpers::IssuesHelpers
helpers Helpers::RateLimiter
@@ -231,9 +231,6 @@ module API
authorize! :create_issue, user_project
- params.delete(:created_at) unless current_user.can?(:set_issue_created_at, user_project)
- params.delete(:iid) unless current_user.can?(:set_issue_iid, user_project)
-
issue_params = declared_params(include_missing: false)
issue_params[:system_note_timestamp] = params[:created_at]
@@ -279,8 +276,6 @@ module API
issue = user_project.issues.find_by!(iid: params.delete(:issue_iid))
authorize! :update_issue, issue
- # Setting updated_at is allowed only for admins and owners
- params.delete(:updated_at) unless current_user.can?(:set_issue_updated_at, user_project)
issue.system_note_timestamp = params[:updated_at]
update_params = declared_params(include_missing: false).merge(request: request, api: true)
diff --git a/lib/api/job_artifacts.rb b/lib/api/job_artifacts.rb
index bc7bc956580..536b361b308 100644
--- a/lib/api/job_artifacts.rb
+++ b/lib/api/job_artifacts.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module API
- class JobArtifacts < Grape::API::Instance
+ class JobArtifacts < ::API::Base
before { authenticate_non_get! }
# EE::API::JobArtifacts would override the following helpers
diff --git a/lib/api/jobs.rb b/lib/api/jobs.rb
index ad46d948f3b..bdb23b4a9be 100644
--- a/lib/api/jobs.rb
+++ b/lib/api/jobs.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module API
- class Jobs < Grape::API::Instance
+ class Jobs < ::API::Base
include PaginationParams
before { authenticate! }
diff --git a/lib/api/keys.rb b/lib/api/keys.rb
index c014641ca04..2e4568029b5 100644
--- a/lib/api/keys.rb
+++ b/lib/api/keys.rb
@@ -2,7 +2,7 @@
module API
# Keys API
- class Keys < Grape::API::Instance
+ class Keys < ::API::Base
before { authenticate! }
resource :keys do
diff --git a/lib/api/labels.rb b/lib/api/labels.rb
index edf4a8ca14e..0cc9f33bd07 100644
--- a/lib/api/labels.rb
+++ b/lib/api/labels.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module API
- class Labels < Grape::API::Instance
+ class Labels < ::API::Base
include PaginationParams
helpers ::API::Helpers::LabelHelpers
diff --git a/lib/api/lint.rb b/lib/api/lint.rb
index f7796b1e969..bfd152f70b1 100644
--- a/lib/api/lint.rb
+++ b/lib/api/lint.rb
@@ -1,24 +1,48 @@
# frozen_string_literal: true
module API
- class Lint < Grape::API::Instance
+ class Lint < ::API::Base
namespace :ci do
desc 'Validation of .gitlab-ci.yml content'
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'
end
post '/lint' do
- error = Gitlab::Ci::YamlProcessor.validation_message(params[:content],
- user: current_user)
+ result = Gitlab::Ci::YamlProcessor.new(params[:content], user: current_user).execute
+ error = result.errors.first
status 200
- if error.blank?
- { status: 'valid', errors: [] }
- else
- { status: 'invalid', errors: [error] }
+ response = if error.blank?
+ { status: 'valid', errors: [] }
+ else
+ { status: 'invalid', errors: [error] }
+ end
+
+ response.tap do |response|
+ response[:merged_yaml] = result.merged_yaml if params[:include_merged_yaml]
end
end
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.'
+ end
+ params do
+ optional :dry_run, type: Boolean, default: false, desc: 'Run pipeline creation simulation, or only do static check.'
+ end
+ get ':id/ci/lint' do
+ authorize! :download_code, user_project
+
+ content = user_project.repository.gitlab_ci_yml_for(user_project.commit.id, user_project.ci_config_path_or_default)
+ result = Gitlab::Ci::Lint
+ .new(project: user_project, current_user: current_user)
+ .validate(content, dry_run: params[:dry_run])
+
+ present result, with: Entities::Ci::Lint::Result, current_user: current_user
+ end
+ end
end
end
diff --git a/lib/api/markdown.rb b/lib/api/markdown.rb
index a0822271cca..97549abd273 100644
--- a/lib/api/markdown.rb
+++ b/lib/api/markdown.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module API
- class Markdown < Grape::API::Instance
+ class Markdown < ::API::Base
params do
requires :text, type: String, desc: "The markdown text to render"
optional :gfm, type: Boolean, desc: "Render text using GitLab Flavored Markdown"
diff --git a/lib/api/maven_packages.rb b/lib/api/maven_packages.rb
index e6d9a9a7c20..a3e2fa84c32 100644
--- a/lib/api/maven_packages.rb
+++ b/lib/api/maven_packages.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
module API
- class MavenPackages < Grape::API::Instance
+ class MavenPackages < ::API::Base
MAVEN_ENDPOINT_REQUIREMENTS = {
file_name: API::NO_SLASH_URL_PART_REGEX
}.freeze
@@ -32,10 +32,10 @@ module API
end
def verify_package_file(package_file, uploaded_file)
- stored_sha1 = Digest::SHA256.hexdigest(package_file.file_sha1)
- expected_sha1 = uploaded_file.sha256
+ stored_sha256 = Digest::SHA256.hexdigest(package_file.file_sha1)
+ expected_sha256 = uploaded_file.sha256
- if stored_sha1 == expected_sha1
+ if stored_sha256 == expected_sha256
no_content!
else
conflict!
@@ -107,7 +107,7 @@ module API
when 'sha1'
package_file.file_sha1
else
- package_event('pull_package') if jar_file?(format)
+ track_package_event('pull_package', :maven) if jar_file?(format)
present_carrierwave_file_with_head_support!(package_file.file)
end
end
@@ -145,7 +145,7 @@ module API
when 'sha1'
package_file.file_sha1
else
- package_event('pull_package') if jar_file?(format)
+ track_package_event('pull_package', :maven) if jar_file?(format)
present_carrierwave_file_with_head_support!(package_file.file)
end
@@ -181,7 +181,7 @@ module API
when 'sha1'
package_file.file_sha1
else
- package_event('pull_package') if jar_file?(format)
+ track_package_event('pull_package', :maven) if jar_file?(format)
present_carrierwave_file_with_head_support!(package_file.file)
end
@@ -231,9 +231,9 @@ module API
verify_package_file(package_file, params[:file])
when 'md5'
- nil
+ ''
else
- package_event('push_package') if jar_file?(format)
+ track_package_event('push_package', :maven) if jar_file?(format)
file_params = {
file: params[:file],
diff --git a/lib/api/members.rb b/lib/api/members.rb
index 4edf94c6350..c28b3b1cc7c 100644
--- a/lib/api/members.rb
+++ b/lib/api/members.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module API
- class Members < Grape::API::Instance
+ class Members < ::API::Base
include PaginationParams
before { authenticate! }
@@ -88,8 +88,8 @@ module API
success Entities::Member
end
params do
- requires :user_id, type: Integer, desc: 'The user ID of the new member'
requires :access_level, type: Integer, desc: 'A valid access level (defaults: `30`, developer access level)'
+ requires :user_id, types: [Integer, String], 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'
end
# rubocop: disable CodeReuse/ActiveRecord
@@ -97,20 +97,26 @@ module API
source = find_source(source_type, params[:id])
authorize_admin_source!(source_type, source)
- member = source.members.find_by(user_id: params[:user_id])
- conflict!('Member already exists') if member
+ if params[:user_id].to_s.include?(',')
+ create_service_params = params.except(:user_id).merge({ user_ids: params[:user_id] })
- user = User.find_by_id(params[:user_id])
- not_found!('User') unless user
+ ::Members::CreateService.new(current_user, create_service_params).execute(source)
+ elsif params[:user_id].present?
+ member = source.members.find_by(user_id: params[:user_id])
+ conflict!('Member already exists') if member
- member = create_member(current_user, user, source, params)
+ user = User.find_by_id(params[:user_id])
+ not_found!('User') unless user
- if !member
- not_allowed! # This currently can only be reached in EE
- elsif member.valid? && member.persisted?
- present_members(member)
- else
- render_validation_error!(member)
+ member = create_member(current_user, user, source, params)
+
+ if !member
+ not_allowed! # This currently can only be reached in EE
+ elsif member.valid? && member.persisted?
+ present_members(member)
+ else
+ render_validation_error!(member)
+ end
end
end
# rubocop: enable CodeReuse/ActiveRecord
diff --git a/lib/api/merge_request_approvals.rb b/lib/api/merge_request_approvals.rb
index 035ed9f0e04..14d6e3995ea 100644
--- a/lib/api/merge_request_approvals.rb
+++ b/lib/api/merge_request_approvals.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module API
- class MergeRequestApprovals < ::Grape::API::Instance
+ class MergeRequestApprovals < ::API::Base
before { authenticate_non_get! }
helpers do
diff --git a/lib/api/merge_request_diffs.rb b/lib/api/merge_request_diffs.rb
index 3e43fe8b257..22023888bbd 100644
--- a/lib/api/merge_request_diffs.rb
+++ b/lib/api/merge_request_diffs.rb
@@ -2,7 +2,7 @@
module API
# MergeRequestDiff API
- class MergeRequestDiffs < Grape::API::Instance
+ class MergeRequestDiffs < ::API::Base
include PaginationParams
before { authenticate! }
diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb
index 4bd72b267a9..b24dd870c8b 100644
--- a/lib/api/merge_requests.rb
+++ b/lib/api/merge_requests.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module API
- class MergeRequests < Grape::API::Instance
+ class MergeRequests < ::API::Base
include PaginationParams
CONTEXT_COMMITS_POST_LIMIT = 20
diff --git a/lib/api/metrics/dashboard/annotations.rb b/lib/api/metrics/dashboard/annotations.rb
index e07762ac6d3..b6bc0af2202 100644
--- a/lib/api/metrics/dashboard/annotations.rb
+++ b/lib/api/metrics/dashboard/annotations.rb
@@ -3,7 +3,7 @@
module API
module Metrics
module Dashboard
- class Annotations < Grape::API::Instance
+ class Annotations < ::API::Base
desc 'Create a new monitoring dashboard annotation' do
success Entities::Metrics::Dashboard::Annotation
end
diff --git a/lib/api/metrics/user_starred_dashboards.rb b/lib/api/metrics/user_starred_dashboards.rb
index 263d2394276..cb6e7099247 100644
--- a/lib/api/metrics/user_starred_dashboards.rb
+++ b/lib/api/metrics/user_starred_dashboards.rb
@@ -2,7 +2,7 @@
module API
module Metrics
- class UserStarredDashboards < Grape::API::Instance
+ class UserStarredDashboards < ::API::Base
resource :projects do
desc 'Marks selected metrics dashboard as starred' do
success Entities::Metrics::UserStarredDashboard
diff --git a/lib/api/namespaces.rb b/lib/api/namespaces.rb
index e1f279df045..f98a1f6dd1d 100644
--- a/lib/api/namespaces.rb
+++ b/lib/api/namespaces.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module API
- class Namespaces < Grape::API::Instance
+ class Namespaces < ::API::Base
include PaginationParams
before { authenticate! }
@@ -32,7 +32,9 @@ module API
get do
namespaces = current_user.admin ? Namespace.all : current_user.namespaces
- namespaces = namespaces.include_gitlab_subscription if Gitlab.ee?
+ namespaces = namespaces.include_route
+
+ namespaces = namespaces.include_gitlab_subscription_with_hosted_plan if Gitlab.ee?
namespaces = namespaces.search(params[:search]) if params[:search].present?
diff --git a/lib/api/notes.rb b/lib/api/notes.rb
index e4989243f3d..0db537ca616 100644
--- a/lib/api/notes.rb
+++ b/lib/api/notes.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module API
- class Notes < Grape::API::Instance
+ class Notes < ::API::Base
include PaginationParams
helpers ::API::Helpers::NotesHelpers
diff --git a/lib/api/notification_settings.rb b/lib/api/notification_settings.rb
index f8b621c1c38..bad3f5ead7a 100644
--- a/lib/api/notification_settings.rb
+++ b/lib/api/notification_settings.rb
@@ -2,7 +2,7 @@
module API
# notification_settings API
- class NotificationSettings < Grape::API::Instance
+ class NotificationSettings < ::API::Base
before { authenticate! }
helpers ::API::Helpers::MembersHelpers
diff --git a/lib/api/npm_packages.rb b/lib/api/npm_packages.rb
index fca405b76b7..1443b28c1ee 100644
--- a/lib/api/npm_packages.rb
+++ b/lib/api/npm_packages.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
module API
- class NpmPackages < Grape::API::Instance
+ class NpmPackages < ::API::Base
helpers ::API::Helpers::PackagesHelpers
helpers ::API::Helpers::Packages::DependencyProxyHelpers
@@ -141,7 +141,7 @@ module API
package_file = ::Packages::PackageFileFinder
.new(package, params[:file_name]).execute!
- package_event('pull_package')
+ track_package_event('pull_package', package)
present_carrierwave_file!(package_file.file)
end
@@ -157,7 +157,7 @@ module API
put ':id/packages/npm/:package_name', requirements: NPM_ENDPOINT_REQUIREMENTS do
authorize_create_package!(user_project)
- package_event('push_package')
+ track_package_event('push_package', :npm)
created_package = ::Packages::Npm::CreatePackageService
.new(user_project, current_user, params.merge(build: current_authenticated_job)).execute
diff --git a/lib/api/nuget_packages.rb b/lib/api/nuget_packages.rb
index f84a3acbe6d..0f2c956a9df 100644
--- a/lib/api/nuget_packages.rb
+++ b/lib/api/nuget_packages.rb
@@ -6,7 +6,7 @@
# called by the NuGet package manager client when users run commands
# like `nuget install` or `nuget push`.
module API
- class NugetPackages < Grape::API::Instance
+ class NugetPackages < ::API::Base
helpers ::API::Helpers::PackagesManagerClientsHelpers
helpers ::API::Helpers::Packages::BasicAuthHelpers
@@ -42,7 +42,7 @@ module API
def package_finder(finder_params = {})
::Packages::Nuget::PackageFinder.new(
authorized_user_project,
- finder_params.merge(package_name: params[:package_name])
+ **finder_params.merge(package_name: params[:package_name])
)
end
end
@@ -73,7 +73,7 @@ module API
get 'index', format: :json do
authorize_read_package!(authorized_user_project)
- track_event('nuget_service_index')
+ track_package_event('cli_metadata', :nuget)
present ::Packages::Nuget::ServiceIndexPresenter.new(authorized_user_project),
with: ::API::Entities::Nuget::ServiceIndex
@@ -105,7 +105,7 @@ module API
package_file = ::Packages::CreatePackageFileService.new(package, file_params)
.execute
- package_event('push_package')
+ track_package_event('push_package', :nuget)
::Packages::Nuget::ExtractionWorker.perform_async(package_file.id) # rubocop:disable CodeReuse/Worker
@@ -198,7 +198,7 @@ module API
not_found!('Package') unless package_file
- package_event('pull_package')
+ track_package_event('pull_package', :nuget)
# nuget and dotnet don't support 302 Moved status codes, supports_direct_download has to be set to false
present_carrierwave_file!(package_file.file, supports_direct_download: false)
@@ -233,7 +233,7 @@ module API
.new(authorized_user_project, params[:q], search_options)
.execute
- package_event('search_package')
+ track_package_event('search_package', :nuget)
present ::Packages::Nuget::SearchResultsPresenter.new(search),
with: ::API::Entities::Nuget::SearchResults
diff --git a/lib/api/package_files.rb b/lib/api/package_files.rb
index 17b92df629c..c1fc9a6e4d8 100644
--- a/lib/api/package_files.rb
+++ b/lib/api/package_files.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module API
- class PackageFiles < Grape::API::Instance
+ class PackageFiles < ::API::Base
include PaginationParams
before do
diff --git a/lib/api/pages.rb b/lib/api/pages.rb
index 79a6b527581..813307c498f 100644
--- a/lib/api/pages.rb
+++ b/lib/api/pages.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module API
- class Pages < Grape::API::Instance
+ class Pages < ::API::Base
before do
require_pages_config_enabled!
authenticated_with_can_read_all_resources!
diff --git a/lib/api/pages_domains.rb b/lib/api/pages_domains.rb
index 7d27b575efa..00c51298c45 100644
--- a/lib/api/pages_domains.rb
+++ b/lib/api/pages_domains.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module API
- class PagesDomains < Grape::API::Instance
+ class PagesDomains < ::API::Base
include PaginationParams
PAGES_DOMAINS_ENDPOINT_REQUIREMENTS = API::NAMESPACE_OR_PROJECT_REQUIREMENTS.merge(domain: API::NO_SLASH_URL_PART_REGEX)
diff --git a/lib/api/project_clusters.rb b/lib/api/project_clusters.rb
index 0e5605984e6..46ccb4ba1a0 100644
--- a/lib/api/project_clusters.rb
+++ b/lib/api/project_clusters.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module API
- class ProjectClusters < Grape::API::Instance
+ class ProjectClusters < ::API::Base
include PaginationParams
before { authenticate! }
@@ -45,6 +45,7 @@ module API
optional :enabled, type: Boolean, default: true, desc: 'Determines if cluster is active or not, defaults to true'
optional :domain, type: String, desc: 'Cluster base domain'
optional :environment_scope, default: '*', type: String, desc: 'The associated environment to the cluster'
+ optional :namespace_per_environment, default: true, type: Boolean, desc: 'Deploy each environment to a separate Kubernetes namespace'
optional :management_project_id, type: Integer, desc: 'The ID of the management project'
optional :managed, type: Boolean, default: true, desc: 'Determines if GitLab will manage namespaces and service accounts for this cluster, defaults to true'
requires :platform_kubernetes_attributes, type: Hash, desc: %q(Platform Kubernetes data) do
@@ -78,6 +79,7 @@ module API
optional :name, type: String, desc: 'Cluster name'
optional :domain, type: String, desc: 'Cluster base domain'
optional :environment_scope, type: String, desc: 'The associated environment to the cluster'
+ optional :namespace_per_environment, default: true, type: Boolean, desc: 'Deploy each environment to a separate Kubernetes namespace'
optional :management_project_id, type: Integer, desc: 'The ID of the management project'
optional :platform_kubernetes_attributes, type: Hash, desc: %q(Platform Kubernetes data) do
optional :api_url, type: String, desc: 'URL to access the Kubernetes API'
diff --git a/lib/api/project_container_repositories.rb b/lib/api/project_container_repositories.rb
index 8f2a62bc5a4..d565531d372 100644
--- a/lib/api/project_container_repositories.rb
+++ b/lib/api/project_container_repositories.rb
@@ -1,13 +1,13 @@
# frozen_string_literal: true
module API
- class ProjectContainerRepositories < Grape::API::Instance
+ class ProjectContainerRepositories < ::API::Base
include PaginationParams
+ helpers ::API::Helpers::PackagesHelpers
REPOSITORY_ENDPOINT_REQUIREMENTS = API::NAMESPACE_OR_PROJECT_REQUIREMENTS.merge(
tag_name: API::NO_SLASH_URL_PART_REGEX)
- before { error!('404 Not Found', 404) unless Feature.enabled?(:container_registry_api, user_project, default_enabled: true) }
before { authorize_read_container_images! }
params do
@@ -28,7 +28,7 @@ module API
user: current_user, subject: user_project
).execute
- track_event( 'list_repositories')
+ track_package_event('list_repositories', :container)
present paginate(repositories), with: Entities::ContainerRegistry::Repository, tags: params[:tags], tags_count: params[:tags_count]
end
@@ -43,7 +43,7 @@ module API
authorize_admin_container_image!
DeleteContainerRepositoryWorker.perform_async(current_user.id, repository.id) # rubocop:disable CodeReuse/Worker
- track_event('delete_repository')
+ track_package_event('delete_repository', :container)
status :accepted
end
@@ -60,7 +60,7 @@ module API
authorize_read_container_image!
tags = Kaminari.paginate_array(repository.tags)
- track_event('list_tags')
+ track_package_event('list_tags', :container)
present paginate(tags), with: Entities::ContainerRegistry::Tag
end
@@ -89,7 +89,7 @@ module API
declared_params.except(:repository_id).merge(container_expiration_policy: false))
# rubocop:enable CodeReuse/Worker
- track_event('delete_tag_bulk')
+ track_package_event('delete_tag_bulk', :container)
status :accepted
end
@@ -125,7 +125,7 @@ module API
.execute(repository)
if result[:status] == :success
- track_event('delete_tag')
+ track_package_event('delete_tag', :container)
status :ok
else
diff --git a/lib/api/project_events.rb b/lib/api/project_events.rb
index 726e693826e..3765473bc0e 100644
--- a/lib/api/project_events.rb
+++ b/lib/api/project_events.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module API
- class ProjectEvents < Grape::API::Instance
+ class ProjectEvents < ::API::Base
include PaginationParams
include APIGuard
helpers ::API::Helpers::EventsHelpers
diff --git a/lib/api/project_export.rb b/lib/api/project_export.rb
index 377d61689b3..184f89200ab 100644
--- a/lib/api/project_export.rb
+++ b/lib/api/project_export.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module API
- class ProjectExport < Grape::API::Instance
+ class ProjectExport < ::API::Base
helpers Helpers::RateLimiter
before do
@@ -55,7 +55,7 @@ module API
export_strategy = if after_export_params[:url].present?
params = after_export_params.slice(:url, :http_method).symbolize_keys
- Gitlab::ImportExport::AfterExportStrategies::WebUploadStrategy.new(params)
+ Gitlab::ImportExport::AfterExportStrategies::WebUploadStrategy.new(**params)
end
if export_strategy&.invalid?
diff --git a/lib/api/project_hooks.rb b/lib/api/project_hooks.rb
index e68a3b106b1..bc2d8c816a8 100644
--- a/lib/api/project_hooks.rb
+++ b/lib/api/project_hooks.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module API
- class ProjectHooks < Grape::API::Instance
+ class ProjectHooks < ::API::Base
include PaginationParams
before { authenticate! }
@@ -104,7 +104,9 @@ module API
delete ":id/hooks/:hook_id" do
hook = user_project.hooks.find(params.delete(:hook_id))
- destroy_conditionally!(hook)
+ destroy_conditionally!(hook) do
+ WebHooks::DestroyService.new(current_user).execute(hook)
+ end
end
end
end
diff --git a/lib/api/project_import.rb b/lib/api/project_import.rb
index 9f43c3c7993..5c4e1d73ee1 100644
--- a/lib/api/project_import.rb
+++ b/lib/api/project_import.rb
@@ -1,11 +1,9 @@
# frozen_string_literal: true
module API
- class ProjectImport < Grape::API::Instance
+ class ProjectImport < ::API::Base
include PaginationParams
- MAXIMUM_FILE_SIZE = 50.megabytes
-
helpers Helpers::ProjectsHelpers
helpers Helpers::FileUploadHelpers
helpers Helpers::RateLimiter
diff --git a/lib/api/project_milestones.rb b/lib/api/project_milestones.rb
index 2f8dd1085dc..a81118f44bd 100644
--- a/lib/api/project_milestones.rb
+++ b/lib/api/project_milestones.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module API
- class ProjectMilestones < Grape::API::Instance
+ class ProjectMilestones < ::API::Base
include PaginationParams
include MilestoneResponses
diff --git a/lib/api/project_packages.rb b/lib/api/project_packages.rb
index 359514f1f78..b8d97b1243a 100644
--- a/lib/api/project_packages.rb
+++ b/lib/api/project_packages.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module API
- class ProjectPackages < Grape::API::Instance
+ class ProjectPackages < ::API::Base
include PaginationParams
before do
diff --git a/lib/api/project_repository_storage_moves.rb b/lib/api/project_repository_storage_moves.rb
index c318907542b..38eb74663d3 100644
--- a/lib/api/project_repository_storage_moves.rb
+++ b/lib/api/project_repository_storage_moves.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module API
- class ProjectRepositoryStorageMoves < Grape::API::Instance
+ class ProjectRepositoryStorageMoves < ::API::Base
include PaginationParams
before { authenticated_as_admin! }
@@ -69,7 +69,7 @@ module API
success Entities::ProjectRepositoryStorageMove
end
params do
- requires :destination_storage_name, type: String, desc: 'The destination storage shard'
+ 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(
diff --git a/lib/api/project_snapshots.rb b/lib/api/project_snapshots.rb
index 360000861fc..e19afb6e8e4 100644
--- a/lib/api/project_snapshots.rb
+++ b/lib/api/project_snapshots.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module API
- class ProjectSnapshots < Grape::API::Instance
+ class ProjectSnapshots < ::API::Base
helpers ::API::Helpers::ProjectSnapshotsHelpers
before { authorize_read_git_snapshot! }
diff --git a/lib/api/project_snippets.rb b/lib/api/project_snippets.rb
index f6e87fece89..b4de260fe49 100644
--- a/lib/api/project_snippets.rb
+++ b/lib/api/project_snippets.rb
@@ -1,10 +1,9 @@
# frozen_string_literal: true
module API
- class ProjectSnippets < Grape::API::Instance
+ class ProjectSnippets < ::API::Base
include PaginationParams
- before { authenticate! }
before { check_snippets_enabled }
params do
@@ -37,6 +36,8 @@ module API
use :pagination
end
get ":id/snippets" do
+ authenticate!
+
present paginate(snippets_for_current_user), with: Entities::ProjectSnippet, current_user: current_user
end
@@ -48,6 +49,9 @@ module API
end
get ":id/snippets/:snippet_id" do
snippet = snippets_for_current_user.find(params[:snippet_id])
+
+ not_found!('Snippet') unless snippet
+
present snippet, with: Entities::ProjectSnippet, current_user: current_user
end
@@ -63,6 +67,8 @@ module API
use :create_file_params
end
post ":id/snippets" do
+ authenticate!
+
authorize! :create_snippet, user_project
snippet_params = process_create_params(declared_params(include_missing: false))
@@ -97,6 +103,8 @@ module API
end
# rubocop: disable CodeReuse/ActiveRecord
put ":id/snippets/:snippet_id" do
+ authenticate!
+
snippet = snippets_for_current_user.find_by(id: params.delete(:snippet_id))
not_found!('Snippet') unless snippet
@@ -125,6 +133,8 @@ module API
end
# rubocop: disable CodeReuse/ActiveRecord
delete ":id/snippets/:snippet_id" do
+ authenticate!
+
snippet = snippets_for_current_user.find_by(id: params[:snippet_id])
not_found!('Snippet') unless snippet
diff --git a/lib/api/project_statistics.rb b/lib/api/project_statistics.rb
index 2196801096f..1ead969fc81 100644
--- a/lib/api/project_statistics.rb
+++ b/lib/api/project_statistics.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module API
- class ProjectStatistics < Grape::API::Instance
+ class ProjectStatistics < ::API::Base
before do
authenticate!
authorize! :daily_statistics, user_project
diff --git a/lib/api/project_templates.rb b/lib/api/project_templates.rb
index 48c3dbed3b0..7d851de0237 100644
--- a/lib/api/project_templates.rb
+++ b/lib/api/project_templates.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module API
- class ProjectTemplates < Grape::API::Instance
+ class ProjectTemplates < ::API::Base
include PaginationParams
TEMPLATE_TYPES = %w[dockerfiles gitignores gitlab_ci_ymls licenses metrics_dashboard_ymls issues merge_requests].freeze
diff --git a/lib/api/projects.rb b/lib/api/projects.rb
index abbdb11a3f7..ecee76ae60c 100644
--- a/lib/api/projects.rb
+++ b/lib/api/projects.rb
@@ -3,7 +3,7 @@
require_dependency 'declarative_policy'
module API
- class Projects < Grape::API::Instance
+ class Projects < ::API::Base
include PaginationParams
include Helpers::CustomAttributes
@@ -353,7 +353,7 @@ module API
optional :path, type: String, desc: 'The path of the repository'
use :optional_project_params
- use :optional_update_params_ee
+ use :optional_update_params
at_least_one_of(*Helpers::ProjectsHelpers.update_params_at_least_one_of)
end
diff --git a/lib/api/protected_branches.rb b/lib/api/protected_branches.rb
index b0a7f898eec..a448682d8bd 100644
--- a/lib/api/protected_branches.rb
+++ b/lib/api/protected_branches.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module API
- class ProtectedBranches < Grape::API::Instance
+ class ProtectedBranches < ::API::Base
include PaginationParams
BRANCH_ENDPOINT_REQUIREMENTS = API::NAMESPACE_OR_PROJECT_REQUIREMENTS.merge(name: API::NO_SLASH_URL_PART_REGEX)
diff --git a/lib/api/protected_tags.rb b/lib/api/protected_tags.rb
index aaa31cb7cc6..dd3e407ffc9 100644
--- a/lib/api/protected_tags.rb
+++ b/lib/api/protected_tags.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module API
- class ProtectedTags < Grape::API::Instance
+ class ProtectedTags < ::API::Base
include PaginationParams
TAG_ENDPOINT_REQUIREMENTS = API::NAMESPACE_OR_PROJECT_REQUIREMENTS.merge(name: API::NO_SLASH_URL_PART_REGEX)
diff --git a/lib/api/pypi_packages.rb b/lib/api/pypi_packages.rb
index c07db68f8a8..5622bc6e42d 100644
--- a/lib/api/pypi_packages.rb
+++ b/lib/api/pypi_packages.rb
@@ -6,7 +6,7 @@
# called by the PyPI package manager client when users run commands
# like `pip install` or `twine upload`.
module API
- class PypiPackages < Grape::API::Instance
+ class PypiPackages < ::API::Base
helpers ::API::Helpers::PackagesManagerClientsHelpers
helpers ::API::Helpers::RelatedResourcesHelpers
helpers ::API::Helpers::Packages::BasicAuthHelpers
@@ -33,7 +33,7 @@ module API
def find_package_versions
packages = packages_finder
- .with_name(params[:package_name])
+ .with_normalized_pypi_name(params[:package_name])
not_found!('Package') if packages.empty?
@@ -72,7 +72,7 @@ module API
package = packages_finder(project).by_file_name_and_sha256(filename, params[:sha256])
package_file = ::Packages::PackageFileFinder.new(package, filename, with_file_name_like: false).execute
- package_event('pull_package')
+ track_package_event('pull_package', :pypi)
present_carrierwave_file!(package_file.file, supports_direct_download: true)
end
@@ -91,7 +91,7 @@ module API
get 'simple/*package_name', format: :txt do
authorize_read_package!(authorized_user_project)
- package_event('list_package')
+ track_package_event('list_package', :pypi)
packages = find_package_versions
presenter = ::Packages::Pypi::PackagePresenter.new(packages, authorized_user_project)
@@ -122,7 +122,7 @@ module API
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)
- package_event('push_package')
+ track_package_event('push_package', :pypi)
::Packages::Pypi::CreatePackageService
.new(authorized_user_project, current_user, declared_params)
diff --git a/lib/api/release/links.rb b/lib/api/release/links.rb
index 9624b8924e5..23de9f9fc9f 100644
--- a/lib/api/release/links.rb
+++ b/lib/api/release/links.rb
@@ -2,7 +2,7 @@
module API
module Release
- class Links < Grape::API::Instance
+ class Links < ::API::Base
include PaginationParams
RELEASE_ENDPOINT_REQUIREMENTS = API::NAMESPACE_OR_PROJECT_REQUIREMENTS
diff --git a/lib/api/releases.rb b/lib/api/releases.rb
index 3c38721129f..3bd6ea77403 100644
--- a/lib/api/releases.rb
+++ b/lib/api/releases.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module API
- class Releases < Grape::API::Instance
+ class Releases < ::API::Base
include PaginationParams
RELEASE_ENDPOINT_REQUIREMENTS = API::NAMESPACE_OR_PROJECT_REQUIREMENTS
@@ -19,9 +19,13 @@ module API
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.'
end
get ':id/releases' do
- releases = ::ReleasesFinder.new(user_project, current_user).execute
+ releases = ::ReleasesFinder.new(user_project, current_user, declared_params.slice(:order_by, :sort)).execute
present paginate(releases), with: Entities::Release, current_user: current_user
end
@@ -152,7 +156,7 @@ module API
end
def authorize_create_evidence!
- # This is a separate method so that EE can extend its behaviour
+ # extended in EE
end
def release
@@ -160,15 +164,15 @@ module API
end
def log_release_created_audit_event(release)
- # This is a separate method so that EE can extend its behaviour
+ # extended in EE
end
def log_release_updated_audit_event
- # This is a separate method so that EE can extend its behaviour
+ # extended in EE
end
def log_release_milestones_updated_audit_event
- # This is a separate method so that EE can extend its behaviour
+ # extended in EE
end
end
end
diff --git a/lib/api/remote_mirrors.rb b/lib/api/remote_mirrors.rb
index d1def05808b..f63ea04a529 100644
--- a/lib/api/remote_mirrors.rb
+++ b/lib/api/remote_mirrors.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module API
- class RemoteMirrors < Grape::API::Instance
+ class RemoteMirrors < ::API::Base
include PaginationParams
before do
diff --git a/lib/api/repositories.rb b/lib/api/repositories.rb
index 81702f8f02a..38ac1f22a48 100644
--- a/lib/api/repositories.rb
+++ b/lib/api/repositories.rb
@@ -3,7 +3,7 @@
require 'mime/types'
module API
- class Repositories < Grape::API::Instance
+ class Repositories < ::API::Base
include PaginationParams
helpers ::API::Helpers::HeadersHelpers
diff --git a/lib/api/resource_label_events.rb b/lib/api/resource_label_events.rb
index a8d3419528c..d3a219f0810 100644
--- a/lib/api/resource_label_events.rb
+++ b/lib/api/resource_label_events.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module API
- class ResourceLabelEvents < Grape::API::Instance
+ class ResourceLabelEvents < ::API::Base
include PaginationParams
helpers ::API::Helpers::NotesHelpers
diff --git a/lib/api/resource_milestone_events.rb b/lib/api/resource_milestone_events.rb
index a8f221f8740..21411f68dd5 100644
--- a/lib/api/resource_milestone_events.rb
+++ b/lib/api/resource_milestone_events.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module API
- class ResourceMilestoneEvents < Grape::API::Instance
+ class ResourceMilestoneEvents < ::API::Base
include PaginationParams
helpers ::API::Helpers::NotesHelpers
diff --git a/lib/api/resource_state_events.rb b/lib/api/resource_state_events.rb
index 1c1a90c09a3..9bfda39be90 100644
--- a/lib/api/resource_state_events.rb
+++ b/lib/api/resource_state_events.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module API
- class ResourceStateEvents < Grape::API::Instance
+ class ResourceStateEvents < ::API::Base
include PaginationParams
helpers ::API::Helpers::NotesHelpers
diff --git a/lib/api/search.rb b/lib/api/search.rb
index b9c6a823f4f..85f0a8e2e60 100644
--- a/lib/api/search.rb
+++ b/lib/api/search.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module API
- class Search < Grape::API::Instance
+ class Search < ::API::Base
include PaginationParams
before { authenticate! }
@@ -33,6 +33,7 @@ module API
scope: params[:scope],
search: params[:search],
state: params[:state],
+ confidential: params[:confidential],
snippets: snippets?,
page: params[:page],
per_page: params[:per_page]
@@ -62,12 +63,6 @@ module API
# Defining this method here as a noop allows us to easily extend it in
# EE, without having to modify this file directly.
end
-
- def check_users_search_allowed!
- if params[:scope].to_sym == :users && Feature.disabled?(:users_search, default_enabled: true)
- render_api_error!({ error: _("Scope not supported with disabled 'users_search' feature!") }, 400)
- end
- end
end
resource :search do
@@ -81,11 +76,11 @@ module API
desc: 'The scope of the search',
values: Helpers::SearchHelpers.global_search_scopes
optional :state, type: String, desc: 'Filter results by state', values: Helpers::SearchHelpers.search_states
+ optional :confidential, type: Boolean, desc: 'Filter results by confidentiality'
use :pagination
end
get do
verify_search_scope!(resource: nil)
- check_users_search_allowed!
present search, with: entity
end
@@ -103,11 +98,11 @@ module API
desc: 'The scope of the search',
values: Helpers::SearchHelpers.group_search_scopes
optional :state, type: String, desc: 'Filter results by state', values: Helpers::SearchHelpers.search_states
+ optional :confidential, type: Boolean, desc: 'Filter results by confidentiality'
use :pagination
end
get ':id/(-/)search' do
verify_search_scope!(resource: user_group)
- check_users_search_allowed!
present search(group_id: user_group.id), with: entity
end
@@ -126,11 +121,10 @@ module API
values: Helpers::SearchHelpers.project_search_scopes
optional :ref, type: String, desc: 'The name of a repository branch or tag. If not given, the default branch is used'
optional :state, type: String, desc: 'Filter results by state', values: Helpers::SearchHelpers.search_states
+ optional :confidential, type: Boolean, desc: 'Filter results by confidentiality'
use :pagination
end
get ':id/(-/)search' do
- check_users_search_allowed!
-
present search({ project_id: user_project.id, repository_ref: params[:ref] }), with: entity
end
end
diff --git a/lib/api/services.rb b/lib/api/services.rb
index 9ee1822339c..5f3d14010a8 100644
--- a/lib/api/services.rb
+++ b/lib/api/services.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
module API
- class Services < Grape::API::Instance
+ class Services < ::API::Base
services = Helpers::ServicesHelpers.services
service_classes = Helpers::ServicesHelpers.service_classes
diff --git a/lib/api/settings.rb b/lib/api/settings.rb
index 6e5534d0c9a..dc917d9c529 100644
--- a/lib/api/settings.rb
+++ b/lib/api/settings.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module API
- class Settings < Grape::API::Instance
+ class Settings < ::API::Base
before { authenticated_as_admin! }
helpers Helpers::SettingsHelpers
@@ -29,7 +29,8 @@ module API
success Entities::ApplicationSetting
end
params do
- optional :admin_notification_email, type: String, desc: 'Abuse reports will be sent to this address if it is set. Abuse reports are always available in the admin area.'
+ optional :admin_notification_email, type: String, desc: 'Deprecated: Use :abuse_notification_email instead. Abuse reports will be sent to this address if it is set. Abuse reports are always available in the admin area.'
+ optional :abuse_notification_email, type: String, desc: 'Abuse reports will be sent to this address if it is set. Abuse reports are always available in the admin area.'
optional :after_sign_up_text, type: String, desc: 'Text shown after sign up'
optional :after_sign_out_path, type: String, desc: 'We will redirect users to this page after they sign out'
optional :akismet_enabled, type: Boolean, desc: 'Helps prevent bots from creating issues'
@@ -73,6 +74,7 @@ module API
optional :gravatar_enabled, type: Boolean, desc: 'Flag indicating if the Gravatar service is enabled'
optional :help_page_hide_commercial_content, type: Boolean, desc: 'Hide marketing-related entries from help'
optional :help_page_support_url, type: String, desc: 'Alternate support URL for help page and help dropdown'
+ optional :help_page_documentation_base_url, type: String, desc: 'Alternate documentation pages URL'
optional :help_page_text, type: String, desc: 'Custom text displayed on the help page'
optional :home_page_url, type: String, desc: 'We will redirect non-logged in users to this page'
optional :housekeeping_enabled, type: Boolean, desc: 'Enable automatic repository housekeeping (git repack, git gc)'
@@ -194,6 +196,11 @@ module API
attrs[:allow_local_requests_from_web_hooks_and_services] = attrs.delete(:allow_local_requests_from_hooks_and_services)
end
+ # support legacy names, can be removed in v5
+ if attrs.has_key?(:admin_notification_email)
+ attrs[:abuse_notification_email] = attrs.delete(:admin_notification_email)
+ end
+
# since 13.0 it's not possible to disable hashed storage - support can be removed in 14.0
attrs.delete(:hashed_storage_enabled) if attrs.has_key?(:hashed_storage_enabled)
diff --git a/lib/api/sidekiq_metrics.rb b/lib/api/sidekiq_metrics.rb
index 77f2b1e871e..b025dbfab37 100644
--- a/lib/api/sidekiq_metrics.rb
+++ b/lib/api/sidekiq_metrics.rb
@@ -3,7 +3,7 @@
require 'sidekiq/api'
module API
- class SidekiqMetrics < Grape::API::Instance
+ class SidekiqMetrics < ::API::Base
before { authenticated_as_admin! }
helpers do
diff --git a/lib/api/snippets.rb b/lib/api/snippets.rb
index c6ef35875fc..2e67b9649bc 100644
--- a/lib/api/snippets.rb
+++ b/lib/api/snippets.rb
@@ -2,11 +2,9 @@
module API
# Snippets API
- class Snippets < Grape::API::Instance
+ class Snippets < ::API::Base
include PaginationParams
- before { authenticate! }
-
resource :snippets do
helpers Helpers::SnippetsHelpers
helpers do
@@ -23,7 +21,7 @@ module API
end
end
- desc 'Get a snippets list for authenticated user' do
+ desc 'Get a snippets list for an authenticated user' do
detail 'This feature was introduced in GitLab 8.15.'
success Entities::Snippet
end
@@ -31,6 +29,8 @@ module API
use :pagination
end
get do
+ authenticate!
+
present paginate(snippets_for_current_user), with: Entities::Snippet, current_user: current_user
end
@@ -42,6 +42,8 @@ module API
use :pagination
end
get 'public' do
+ authenticate!
+
present paginate(public_snippets), with: Entities::PersonalSnippet, current_user: current_user
end
@@ -74,6 +76,8 @@ module API
use :create_file_params
end
post do
+ authenticate!
+
authorize! :create_snippet
attrs = process_create_params(declared_params(include_missing: false))
@@ -109,6 +113,8 @@ module API
use :minimum_update_params
end
put ':id' do
+ authenticate!
+
snippet = snippets_for_current_user.find_by_id(params.delete(:id))
break not_found!('Snippet') unless snippet
@@ -139,6 +145,8 @@ module API
requires :id, type: Integer, desc: 'The ID of a snippet'
end
delete ':id' do
+ authenticate!
+
snippet = snippets_for_current_user.find_by_id(params.delete(:id))
break not_found!('Snippet') unless snippet
diff --git a/lib/api/statistics.rb b/lib/api/statistics.rb
index 3869fd3ac76..fa7176491ba 100644
--- a/lib/api/statistics.rb
+++ b/lib/api/statistics.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module API
- class Statistics < Grape::API::Instance
+ class Statistics < ::API::Base
before { authenticated_as_admin! }
COUNTED_ITEMS = [Project, User, Group, ForkNetworkMember, ForkNetwork, Issue,
diff --git a/lib/api/submodules.rb b/lib/api/submodules.rb
index 34d21d3d7d8..e2ceb49c119 100644
--- a/lib/api/submodules.rb
+++ b/lib/api/submodules.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module API
- class Submodules < Grape::API::Instance
+ class Submodules < ::API::Base
before { authenticate! }
helpers do
diff --git a/lib/api/subscriptions.rb b/lib/api/subscriptions.rb
index 533663fb087..35a28da4736 100644
--- a/lib/api/subscriptions.rb
+++ b/lib/api/subscriptions.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module API
- class Subscriptions < Grape::API::Instance
+ class Subscriptions < ::API::Base
helpers ::API::Helpers::LabelHelpers
before { authenticate! }
diff --git a/lib/api/suggestions.rb b/lib/api/suggestions.rb
index 38e96c080f2..f23d279c3f4 100644
--- a/lib/api/suggestions.rb
+++ b/lib/api/suggestions.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module API
- class Suggestions < Grape::API::Instance
+ class Suggestions < ::API::Base
before { authenticate! }
resource :suggestions do
diff --git a/lib/api/system_hooks.rb b/lib/api/system_hooks.rb
index d8e0a425625..2820d305d0f 100644
--- a/lib/api/system_hooks.rb
+++ b/lib/api/system_hooks.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module API
- class SystemHooks < Grape::API::Instance
+ class SystemHooks < ::API::Base
include PaginationParams
before do
@@ -70,7 +70,9 @@ module API
hook = SystemHook.find_by(id: params[:id])
not_found!('System hook') unless hook
- destroy_conditionally!(hook)
+ destroy_conditionally!(hook) do
+ WebHooks::DestroyService.new(current_user).execute(hook)
+ end
end
# rubocop: enable CodeReuse/ActiveRecord
end
diff --git a/lib/api/tags.rb b/lib/api/tags.rb
index c1fbd3ca7c6..b969394ec47 100644
--- a/lib/api/tags.rb
+++ b/lib/api/tags.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module API
- class Tags < Grape::API::Instance
+ class Tags < ::API::Base
include PaginationParams
TAG_ENDPOINT_REQUIREMENTS = API::NAMESPACE_OR_PROJECT_REQUIREMENTS.merge(tag_name: API::NO_SLASH_URL_PART_REGEX)
diff --git a/lib/api/templates.rb b/lib/api/templates.rb
index 80a97aae429..0b427bbf5b9 100644
--- a/lib/api/templates.rb
+++ b/lib/api/templates.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module API
- class Templates < Grape::API::Instance
+ class Templates < ::API::Base
include PaginationParams
GLOBAL_TEMPLATE_TYPES = {
diff --git a/lib/api/terraform/state.rb b/lib/api/terraform/state.rb
index 7063a3d08b5..4168cce21ef 100644
--- a/lib/api/terraform/state.rb
+++ b/lib/api/terraform/state.rb
@@ -4,7 +4,7 @@ require_dependency 'api/validations/validators/limit'
module API
module Terraform
- class State < Grape::API::Instance
+ class State < ::API::Base
include ::Gitlab::Utils::StrongMemoize
default_format :json
diff --git a/lib/api/terraform/state_version.rb b/lib/api/terraform/state_version.rb
new file mode 100644
index 00000000000..b4a0efd7a2b
--- /dev/null
+++ b/lib/api/terraform/state_version.rb
@@ -0,0 +1,68 @@
+# frozen_string_literal: true
+
+module API
+ module Terraform
+ class StateVersion < ::API::Base
+ default_format :json
+
+ before do
+ authenticate!
+ authorize! :read_terraform_state, user_project
+ end
+
+ params do
+ requires :id, type: String, desc: 'The ID of a project'
+ end
+
+ resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
+ namespace ':id/terraform/state/:name/versions/:serial' do
+ params do
+ requires :name, type: String, desc: 'The name of a Terraform state'
+ requires :serial, type: Integer, desc: 'The version number of the state'
+ end
+
+ helpers do
+ def remote_state_handler
+ ::Terraform::RemoteStateHandler.new(user_project, current_user, name: params[:name])
+ end
+
+ def find_version(serial)
+ remote_state_handler.find_with_lock do |state|
+ version = state.versions.find_by_version(serial)
+
+ if version.present?
+ yield version
+ else
+ not_found!
+ end
+ end
+ end
+ end
+
+ desc 'Get a terraform state version'
+ route_setting :authentication, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth
+ get do
+ find_version(params[:serial]) do |version|
+ env['api.format'] = :binary # Bypass json serialization
+ body version.file.read
+ status :ok
+ end
+ end
+
+ desc 'Delete a terraform state version'
+ route_setting :authentication, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth
+ delete do
+ authorize! :admin_terraform_state, user_project
+
+ find_version(params[:serial]) do |version|
+ version.destroy!
+
+ body false
+ status :no_content
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/api/todos.rb b/lib/api/todos.rb
index 5eae92a251e..ce07d13cc9a 100644
--- a/lib/api/todos.rb
+++ b/lib/api/todos.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module API
- class Todos < Grape::API::Instance
+ class Todos < ::API::Base
include PaginationParams
before { authenticate! }
diff --git a/lib/api/triggers.rb b/lib/api/triggers.rb
index f398bbf3e32..960d004a04c 100644
--- a/lib/api/triggers.rb
+++ b/lib/api/triggers.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module API
- class Triggers < Grape::API::Instance
+ class Triggers < ::API::Base
include PaginationParams
HTTP_GITLAB_EVENT_HEADER = "HTTP_#{WebHookService::GITLAB_EVENT_HEADER}".underscore.upcase
diff --git a/lib/api/unleash.rb b/lib/api/unleash.rb
new file mode 100644
index 00000000000..907422118f1
--- /dev/null
+++ b/lib/api/unleash.rb
@@ -0,0 +1,77 @@
+# frozen_string_literal: true
+
+module API
+ class Unleash < ::API::Base
+ include PaginationParams
+
+ 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'
+ end
+ route_param :project_id do
+ before do
+ authorize_by_unleash_instance_id!
+ end
+
+ get do
+ # not supported yet
+ status :ok
+ end
+
+ desc 'Get a list of features (deprecated, v2 client support)'
+ get 'features' do
+ present :version, 1
+ present :features, feature_flags, with: ::API::Entities::UnleashFeature
+ end
+
+ desc 'Get a list of features'
+ get 'client/features' do
+ present :version, 1
+ present :features, feature_flags, with: ::API::Entities::UnleashFeature
+ end
+
+ post 'client/register' do
+ # not supported yet
+ status :ok
+ end
+
+ post 'client/metrics' do
+ # not supported yet
+ status :ok
+ end
+ end
+ end
+ end
+
+ helpers do
+ def project
+ @project ||= find_project(params[:project_id])
+ end
+
+ def unleash_instance_id
+ env['HTTP_UNLEASH_INSTANCEID'] || params[:instance_id]
+ end
+
+ def unleash_app_name
+ env['HTTP_UNLEASH_APPNAME'] || params[:app_name]
+ end
+
+ def authorize_by_unleash_instance_id!
+ unauthorized! unless Operations::FeatureFlagsClient
+ .find_for_project_and_token(project, unleash_instance_id)
+ end
+
+ def feature_flags
+ return [] unless unleash_app_name.present?
+
+ legacy_flags = Operations::FeatureFlagScope.for_unleash_client(project, unleash_app_name)
+ new_version_flags = Operations::FeatureFlag.for_unleash_client(project, unleash_app_name)
+
+ legacy_flags + new_version_flags
+ end
+ end
+ end
+end
diff --git a/lib/api/usage_data.rb b/lib/api/usage_data.rb
index a1512197ee1..fa5bfc1cbe9 100644
--- a/lib/api/usage_data.rb
+++ b/lib/api/usage_data.rb
@@ -1,12 +1,12 @@
# frozen_string_literal: true
module API
- class UsageData < Grape::API::Instance
+ class UsageData < ::API::Base
before { authenticate! }
namespace 'usage_data' do
before do
- not_found! unless Feature.enabled?(:usage_data_api)
+ not_found! unless Feature.enabled?(:usage_data_api, default_enabled: true)
forbidden!('Invalid CSRF token is provided') unless verified_request?
end
diff --git a/lib/api/user_counts.rb b/lib/api/user_counts.rb
index 90127ecbc73..6d9db53fec8 100644
--- a/lib/api/user_counts.rb
+++ b/lib/api/user_counts.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module API
- class UserCounts < Grape::API::Instance
+ class UserCounts < ::API::Base
resource :user_counts do
desc 'Return the user specific counts' do
detail 'Open MR Count'
diff --git a/lib/api/users.rb b/lib/api/users.rb
index 73bb43b88fc..e7c1d644324 100644
--- a/lib/api/users.rb
+++ b/lib/api/users.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module API
- class Users < Grape::API::Instance
+ class Users < ::API::Base
include PaginationParams
include APIGuard
include Helpers::CustomAttributes
@@ -348,7 +348,7 @@ module API
end
# rubocop: enable CodeReuse/ActiveRecord
- desc 'Get the GPG keys of a specified user. Available only for admins.' do
+ desc 'Get the GPG keys of a specified user.' do
detail 'This feature was added in GitLab 10.0'
success Entities::GpgKey
end
@@ -358,8 +358,6 @@ module API
end
# rubocop: disable CodeReuse/ActiveRecord
get ':id/gpg_keys' do
- authenticated_as_admin!
-
user = User.find_by(id: params[:id])
not_found!('User') unless user
@@ -367,6 +365,26 @@ module API
end
# rubocop: enable CodeReuse/ActiveRecord
+ desc 'Get a specific GPG key for a given user.' do
+ detail 'This feature was added in GitLab 13.5'
+ success Entities::GpgKey
+ end
+ params do
+ requires :id, type: Integer, desc: 'The ID of the user'
+ requires :key_id, type: Integer, desc: 'The ID of the GPG key'
+ end
+ # rubocop: disable CodeReuse/ActiveRecord
+ get ':id/gpg_keys/:key_id' do
+ user = User.find_by(id: params[:id])
+ not_found!('User') unless user
+
+ key = user.gpg_keys.find_by(id: params[:key_id])
+ not_found!('GPG Key') unless key
+
+ present key, with: Entities::GpgKey
+ end
+ # rubocop: enable CodeReuse/ActiveRecord
+
desc 'Delete an existing GPG key from a specified user. Available only for admins.' do
detail 'This feature was added in GitLab 10.0'
end
@@ -529,10 +547,15 @@ module API
unless user.can_be_deactivated?
forbidden!('A blocked user cannot be deactivated by the API') if user.blocked?
+ forbidden!('An internal user cannot be deactivated by the API') if user.internal?
forbidden!("The user you are trying to deactivate has been active in the past #{::User::MINIMUM_INACTIVE_DAYS} days and cannot be deactivated")
end
- user.deactivate
+ if user.deactivate
+ true
+ else
+ render_api_error!(user.errors.full_messages, 400)
+ end
end
# rubocop: enable CodeReuse/ActiveRecord
diff --git a/lib/api/v3/github.rb b/lib/api/v3/github.rb
index 593f90460ac..aed88e6091c 100644
--- a/lib/api/v3/github.rb
+++ b/lib/api/v3/github.rb
@@ -7,7 +7,7 @@
#
module API
module V3
- class Github < Grape::API::Instance
+ class Github < ::API::Base
NO_SLASH_URL_PART_REGEX = %r{[^/]+}.freeze
ENDPOINT_REQUIREMENTS = {
namespace: NO_SLASH_URL_PART_REGEX,
@@ -51,7 +51,7 @@ module API
def find_project_with_access(params)
project = find_project!(
- ::Gitlab::Jira::Dvcs.restore_full_path(params.slice(:namespace, :project).symbolize_keys)
+ ::Gitlab::Jira::Dvcs.restore_full_path(**params.slice(:namespace, :project).symbolize_keys)
)
not_found! unless can?(current_user, :download_code, project)
project
diff --git a/lib/api/variables.rb b/lib/api/variables.rb
index 0b3ec10f1b4..f5de3d844e6 100644
--- a/lib/api/variables.rb
+++ b/lib/api/variables.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module API
- class Variables < Grape::API::Instance
+ class Variables < ::API::Base
include PaginationParams
before { authenticate! }
diff --git a/lib/api/version.rb b/lib/api/version.rb
index 6a480fc2bd9..841b55f8d6c 100644
--- a/lib/api/version.rb
+++ b/lib/api/version.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module API
- class Version < Grape::API::Instance
+ class Version < ::API::Base
helpers ::API::Helpers::GraphqlHelpers
include APIGuard
diff --git a/lib/api/wikis.rb b/lib/api/wikis.rb
index 4eba12157bd..21f457046f1 100644
--- a/lib/api/wikis.rb
+++ b/lib/api/wikis.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module API
- class Wikis < Grape::API::Instance
+ class Wikis < ::API::Base
helpers ::API::Helpers::WikisHelpers
helpers do
diff --git a/lib/backup/artifacts.rb b/lib/backup/artifacts.rb
index c2266f0bad6..6a45baa60ec 100644
--- a/lib/backup/artifacts.rb
+++ b/lib/backup/artifacts.rb
@@ -1,9 +1,7 @@
# frozen_string_literal: true
-require 'backup/files'
-
module Backup
- class Artifacts < Files
+ class Artifacts < Backup::Files
attr_reader :progress
def initialize(progress)
diff --git a/lib/backup/builds.rb b/lib/backup/builds.rb
index 5e795a449de..9c3b7165de7 100644
--- a/lib/backup/builds.rb
+++ b/lib/backup/builds.rb
@@ -1,9 +1,7 @@
# frozen_string_literal: true
-require 'backup/files'
-
module Backup
- class Builds < Files
+ class Builds < Backup::Files
attr_reader :progress
def initialize(progress)
diff --git a/lib/backup/lfs.rb b/lib/backup/lfs.rb
index 0dfe56e214f..514d52d7f65 100644
--- a/lib/backup/lfs.rb
+++ b/lib/backup/lfs.rb
@@ -1,9 +1,7 @@
# frozen_string_literal: true
-require 'backup/files'
-
module Backup
- class Lfs < Files
+ class Lfs < Backup::Files
attr_reader :progress
def initialize(progress)
diff --git a/lib/backup/pages.rb b/lib/backup/pages.rb
index d7aab33d7cb..ae293073ba2 100644
--- a/lib/backup/pages.rb
+++ b/lib/backup/pages.rb
@@ -1,9 +1,7 @@
# frozen_string_literal: true
-require 'backup/files'
-
module Backup
- class Pages < Files
+ class Pages < Backup::Files
attr_reader :progress
def initialize(progress)
diff --git a/lib/backup/registry.rb b/lib/backup/registry.rb
index d16ed2facf1..9645a07dfb8 100644
--- a/lib/backup/registry.rb
+++ b/lib/backup/registry.rb
@@ -1,9 +1,7 @@
# frozen_string_literal: true
-require 'backup/files'
-
module Backup
- class Registry < Files
+ class Registry < Backup::Files
attr_reader :progress
def initialize(progress)
diff --git a/lib/backup/repositories.rb b/lib/backup/repositories.rb
new file mode 100644
index 00000000000..4248a86dc7c
--- /dev/null
+++ b/lib/backup/repositories.rb
@@ -0,0 +1,310 @@
+# frozen_string_literal: true
+
+require 'yaml'
+
+module Backup
+ class Repositories
+ attr_reader :progress
+
+ def initialize(progress)
+ @progress = progress
+ end
+
+ def dump(max_concurrency:, max_storage_concurrency:)
+ prepare
+
+ if max_concurrency <= 1 && max_storage_concurrency <= 1
+ return dump_consecutive
+ end
+
+ check_valid_storages!
+
+ semaphore = Concurrent::Semaphore.new(max_concurrency)
+ errors = Queue.new
+
+ threads = Gitlab.config.repositories.storages.keys.map do |storage|
+ Thread.new do
+ Rails.application.executor.wrap do
+ dump_storage(storage, semaphore, max_storage_concurrency: max_storage_concurrency)
+ rescue => e
+ errors << e
+ end
+ end
+ end
+
+ ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
+ threads.each(&:join)
+ end
+
+ raise errors.pop unless errors.empty?
+ end
+
+ def restore
+ Project.find_each(batch_size: 1000) do |project|
+ restore_repository(project, Gitlab::GlRepository::PROJECT)
+ restore_repository(project, Gitlab::GlRepository::WIKI)
+ restore_repository(project, Gitlab::GlRepository::DESIGN)
+ end
+
+ invalid_ids = Snippet.find_each(batch_size: 1000)
+ .map { |snippet| restore_snippet_repository(snippet) }
+ .compact
+
+ cleanup_snippets_without_repositories(invalid_ids)
+
+ restore_object_pools
+ end
+
+ private
+
+ def check_valid_storages!
+ [ProjectRepository, SnippetRepository].each do |klass|
+ if klass.excluding_repository_storage(Gitlab.config.repositories.storages.keys).exists?
+ raise Error, "repositories.storages in gitlab.yml does not include all storages used by #{klass}"
+ end
+ end
+ end
+
+ def backup_repos_path
+ @backup_repos_path ||= File.join(Gitlab.config.backup.path, 'repositories')
+ end
+
+ def prepare
+ FileUtils.rm_rf(backup_repos_path)
+ FileUtils.mkdir_p(Gitlab.config.backup.path)
+ FileUtils.mkdir(backup_repos_path, mode: 0700)
+ end
+
+ def dump_consecutive
+ dump_consecutive_projects
+ dump_consecutive_snippets
+ end
+
+ def dump_consecutive_projects
+ project_relation.find_each(batch_size: 1000) do |project|
+ dump_project(project)
+ end
+ end
+
+ def dump_consecutive_snippets
+ Snippet.find_each(batch_size: 1000) { |snippet| dump_snippet(snippet) }
+ end
+
+ def dump_storage(storage, semaphore, max_storage_concurrency:)
+ errors = Queue.new
+ queue = InterlockSizedQueue.new(1)
+
+ threads = Array.new(max_storage_concurrency) do
+ Thread.new do
+ Rails.application.executor.wrap do
+ while container = queue.pop
+ ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
+ semaphore.acquire
+ end
+
+ begin
+ case container
+ when Project
+ dump_project(container)
+ when Snippet
+ dump_snippet(container)
+ end
+ rescue => e
+ errors << e
+ break
+ ensure
+ semaphore.release
+ end
+ end
+ end
+ end
+ end
+
+ enqueue_records_for_storage(storage, queue, errors)
+
+ raise errors.pop unless errors.empty?
+ ensure
+ queue.close
+ ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
+ threads.each(&:join)
+ end
+ end
+
+ def dump_project(project)
+ backup_repository(project, Gitlab::GlRepository::PROJECT)
+ backup_repository(project, Gitlab::GlRepository::WIKI)
+ backup_repository(project, Gitlab::GlRepository::DESIGN)
+ end
+
+ def dump_snippet(snippet)
+ backup_repository(snippet, Gitlab::GlRepository::SNIPPET)
+ end
+
+ def enqueue_records_for_storage(storage, queue, errors)
+ records_to_enqueue(storage).each do |relation|
+ relation.find_each(batch_size: 100) do |project|
+ break unless errors.empty?
+
+ queue.push(project)
+ end
+ end
+ end
+
+ def records_to_enqueue(storage)
+ [projects_in_storage(storage), snippets_in_storage(storage)]
+ end
+
+ def projects_in_storage(storage)
+ project_relation.id_in(ProjectRepository.for_repository_storage(storage).select(:project_id))
+ end
+
+ def project_relation
+ Project.includes(:route, :group, namespace: :owner)
+ end
+
+ def snippets_in_storage(storage)
+ Snippet.id_in(SnippetRepository.for_repository_storage(storage).select(:snippet_id))
+ end
+
+ def backup_repository(container, type)
+ BackupRestore.new(
+ progress,
+ type.repository_for(container),
+ backup_repos_path
+ ).backup
+ end
+
+ def restore_repository(container, type)
+ BackupRestore.new(
+ progress,
+ type.repository_for(container),
+ backup_repos_path
+ ).restore(always_create: type.project?)
+ end
+
+ def restore_object_pools
+ PoolRepository.includes(:source_project).find_each do |pool|
+ progress.puts " - Object pool #{pool.disk_path}..."
+
+ pool.source_project ||= pool.member_projects.first.root_of_fork_network
+ pool.state = 'none'
+ pool.save
+
+ pool.schedule
+ end
+ end
+
+ def restore_snippet_repository(snippet)
+ restore_repository(snippet, Gitlab::GlRepository::SNIPPET)
+
+ response = Snippets::RepositoryValidationService.new(nil, snippet).execute
+
+ if response.error?
+ snippet.repository.remove
+
+ progress.puts("Snippet #{snippet.full_path} can't be restored: #{response.message}")
+
+ snippet.id
+ else
+ nil
+ end
+ end
+
+ # Snippets without a repository should be removed because they failed to import
+ # due to having invalid repositories
+ def cleanup_snippets_without_repositories(ids)
+ Snippet.id_in(ids).delete_all
+ end
+
+ class BackupRestore
+ attr_accessor :progress, :repository, :backup_repos_path
+
+ def initialize(progress, repository, backup_repos_path)
+ @progress = progress
+ @repository = repository
+ @backup_repos_path = backup_repos_path
+ end
+
+ def backup
+ progress.puts " * #{display_repo_path} ... "
+
+ if repository.empty?
+ progress.puts " * #{display_repo_path} ... " + "[SKIPPED]".color(:cyan)
+ return
+ end
+
+ FileUtils.mkdir_p(repository_backup_path)
+
+ repository.bundle_to_disk(path_to_bundle)
+ repository.gitaly_repository_client.backup_custom_hooks(custom_hooks_tar)
+
+ progress.puts " * #{display_repo_path} ... " + "[DONE]".color(:green)
+
+ rescue => e
+ progress.puts "[Failed] backing up #{display_repo_path}".color(:red)
+ progress.puts "Error #{e}".color(:red)
+ end
+
+ def restore(always_create: false)
+ progress.puts " * #{display_repo_path} ... "
+
+ repository.remove rescue nil
+
+ if File.exist?(path_to_bundle)
+ repository.create_from_bundle(path_to_bundle)
+ restore_custom_hooks
+ elsif always_create
+ repository.create_repository
+ end
+
+ progress.puts " * #{display_repo_path} ... " + "[DONE]".color(:green)
+
+ rescue => e
+ progress.puts "[Failed] restoring #{display_repo_path}".color(:red)
+ progress.puts "Error #{e}".color(:red)
+ end
+
+ private
+
+ def display_repo_path
+ "#{repository.full_path} (#{repository.disk_path})"
+ end
+
+ def repository_backup_path
+ @repository_backup_path ||= File.join(backup_repos_path, repository.disk_path)
+ end
+
+ def path_to_bundle
+ @path_to_bundle ||= File.join(backup_repos_path, repository.disk_path + '.bundle')
+ end
+
+ def restore_custom_hooks
+ return unless File.exist?(custom_hooks_tar)
+
+ repository.gitaly_repository_client.restore_custom_hooks(custom_hooks_tar)
+ end
+
+ def custom_hooks_tar
+ File.join(repository_backup_path, "custom_hooks.tar")
+ end
+ end
+
+ class InterlockSizedQueue < SizedQueue
+ extend ::Gitlab::Utils::Override
+
+ override :pop
+ def pop(*)
+ ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
+ super
+ end
+ end
+
+ override :push
+ def push(*)
+ ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
+ super
+ end
+ end
+ end
+ end
+end
diff --git a/lib/backup/repository.rb b/lib/backup/repository.rb
deleted file mode 100644
index eb0b230904e..00000000000
--- a/lib/backup/repository.rb
+++ /dev/null
@@ -1,265 +0,0 @@
-# frozen_string_literal: true
-
-require 'yaml'
-
-module Backup
- class Repository
- attr_reader :progress
-
- def initialize(progress)
- @progress = progress
- end
-
- def dump(max_concurrency:, max_storage_concurrency:)
- prepare
-
- if max_concurrency <= 1 && max_storage_concurrency <= 1
- return dump_consecutive
- end
-
- if Project.excluding_repository_storage(Gitlab.config.repositories.storages.keys).exists?
- raise Error, 'repositories.storages in gitlab.yml is misconfigured'
- end
-
- semaphore = Concurrent::Semaphore.new(max_concurrency)
- errors = Queue.new
-
- threads = Gitlab.config.repositories.storages.keys.map do |storage|
- Thread.new do
- Rails.application.executor.wrap do
- dump_storage(storage, semaphore, max_storage_concurrency: max_storage_concurrency)
- rescue => e
- errors << e
- end
- end
- end
-
- ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
- threads.each(&:join)
- end
-
- raise errors.pop unless errors.empty?
- end
-
- def backup_project(project)
- path_to_project_bundle = path_to_bundle(project)
- Gitlab::GitalyClient::RepositoryService.new(project.repository)
- .create_bundle(path_to_project_bundle)
-
- backup_custom_hooks(project)
- rescue => e
- progress_warn(project, e, 'Failed to backup repo')
- end
-
- def backup_custom_hooks(project)
- FileUtils.mkdir_p(project_backup_path(project))
-
- custom_hooks_path = custom_hooks_tar(project)
- Gitlab::GitalyClient::RepositoryService.new(project.repository)
- .backup_custom_hooks(custom_hooks_path)
- end
-
- def restore_custom_hooks(project)
- return unless Dir.exist?(project_backup_path(project))
- return if Dir.glob("#{project_backup_path(project)}/custom_hooks*").none?
-
- custom_hooks_path = custom_hooks_tar(project)
- Gitlab::GitalyClient::RepositoryService.new(project.repository)
- .restore_custom_hooks(custom_hooks_path)
- end
-
- def restore
- Project.find_each(batch_size: 1000) do |project|
- progress.print " * #{project.full_path} ... "
-
- restore_repo_success =
- begin
- try_restore_repository(project)
- rescue => err
- progress.puts "Error: #{err}".color(:red)
- false
- end
-
- if restore_repo_success
- progress.puts "[DONE]".color(:green)
- else
- progress.puts "[Failed] restoring #{project.full_path} repository".color(:red)
- end
-
- wiki = ProjectWiki.new(project)
- wiki.repository.remove rescue nil
- path_to_wiki_bundle = path_to_bundle(wiki)
-
- if File.exist?(path_to_wiki_bundle)
- progress.print " * #{wiki.full_path} ... "
- begin
- wiki.repository.create_from_bundle(path_to_wiki_bundle)
- restore_custom_hooks(wiki)
-
- progress.puts "[DONE]".color(:green)
- rescue => e
- progress.puts "[Failed] restoring #{wiki.full_path} wiki".color(:red)
- progress.puts "Error #{e}".color(:red)
- end
- end
- end
-
- restore_object_pools
- end
-
- protected
-
- def try_restore_repository(project)
- path_to_project_bundle = path_to_bundle(project)
- project.repository.remove rescue nil
-
- if File.exist?(path_to_project_bundle)
- project.repository.create_from_bundle(path_to_project_bundle)
- restore_custom_hooks(project)
- else
- project.repository.create_repository
- end
-
- true
- end
-
- def path_to_bundle(project)
- File.join(backup_repos_path, project.disk_path + '.bundle')
- end
-
- def project_backup_path(project)
- File.join(backup_repos_path, project.disk_path)
- end
-
- def custom_hooks_tar(project)
- File.join(project_backup_path(project), "custom_hooks.tar")
- end
-
- def backup_repos_path
- File.join(Gitlab.config.backup.path, 'repositories')
- end
-
- def prepare
- FileUtils.rm_rf(backup_repos_path)
- FileUtils.mkdir_p(Gitlab.config.backup.path)
- FileUtils.mkdir(backup_repos_path, mode: 0700)
- end
-
- private
-
- def dump_consecutive
- Project.includes(:route, :group, namespace: :owner).find_each(batch_size: 1000) do |project|
- dump_project(project)
- end
- end
-
- def dump_storage(storage, semaphore, max_storage_concurrency:)
- errors = Queue.new
- queue = InterlockSizedQueue.new(1)
-
- threads = Array.new(max_storage_concurrency) do
- Thread.new do
- Rails.application.executor.wrap do
- while project = queue.pop
- ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
- semaphore.acquire
- end
-
- begin
- dump_project(project)
- rescue => e
- errors << e
- break
- ensure
- semaphore.release
- end
- end
- end
- end
- end
-
- Project.for_repository_storage(storage).includes(:route, :group, namespace: :owner).find_each(batch_size: 100) do |project|
- break unless errors.empty?
-
- queue.push(project)
- end
-
- raise errors.pop unless errors.empty?
- ensure
- queue.close
- ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
- threads.each(&:join)
- end
- end
-
- def dump_project(project)
- progress.puts " * #{display_repo_path(project)} ... "
-
- if project.hashed_storage?(:repository)
- FileUtils.mkdir_p(File.dirname(File.join(backup_repos_path, project.disk_path)))
- else
- FileUtils.mkdir_p(File.join(backup_repos_path, project.namespace.full_path)) if project.namespace
- end
-
- if !empty_repo?(project)
- backup_project(project)
- progress.puts " * #{display_repo_path(project)} ... " + "[DONE]".color(:green)
- else
- progress.puts " * #{display_repo_path(project)} ... " + "[SKIPPED]".color(:cyan)
- end
-
- wiki = ProjectWiki.new(project)
-
- if !empty_repo?(wiki)
- backup_project(wiki)
- progress.puts " * #{display_repo_path(project)} ... " + "[DONE] Wiki".color(:green)
- else
- progress.puts " * #{display_repo_path(project)} ... " + "[SKIPPED] Wiki".color(:cyan)
- end
- end
-
- def progress_warn(project, cmd, output)
- progress.puts "[WARNING] Executing #{cmd}".color(:orange)
- progress.puts "Ignoring error on #{display_repo_path(project)} - #{output}".color(:orange)
- end
-
- def empty_repo?(project_or_wiki)
- project_or_wiki.repository.expire_emptiness_caches
- project_or_wiki.repository.empty?
- end
-
- def display_repo_path(project)
- project.hashed_storage?(:repository) ? "#{project.full_path} (#{project.disk_path})" : project.full_path
- end
-
- def restore_object_pools
- PoolRepository.includes(:source_project).find_each do |pool|
- progress.puts " - Object pool #{pool.disk_path}..."
-
- pool.source_project ||= pool.member_projects.first.root_of_fork_network
- pool.state = 'none'
- pool.save
-
- pool.schedule
- end
- end
-
- class InterlockSizedQueue < SizedQueue
- extend ::Gitlab::Utils::Override
-
- override :pop
- def pop(*)
- ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
- super
- end
- end
-
- override :push
- def push(*)
- ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
- super
- end
- end
- end
- end
-end
diff --git a/lib/backup/uploads.rb b/lib/backup/uploads.rb
index b6a62bc3f29..9665624f71b 100644
--- a/lib/backup/uploads.rb
+++ b/lib/backup/uploads.rb
@@ -1,9 +1,7 @@
# frozen_string_literal: true
-require 'backup/files'
-
module Backup
- class Uploads < Files
+ class Uploads < Backup::Files
attr_reader :progress
def initialize(progress)
diff --git a/lib/banzai/filter/design_reference_filter.rb b/lib/banzai/filter/design_reference_filter.rb
index 2ab47c5c6db..1754fec93d4 100644
--- a/lib/banzai/filter/design_reference_filter.rb
+++ b/lib/banzai/filter/design_reference_filter.rb
@@ -3,8 +3,6 @@
module Banzai
module Filter
class DesignReferenceFilter < AbstractReferenceFilter
- FEATURE_FLAG = :design_management_reference_filter_gfm_pipeline
-
class Identifier
include Comparable
attr_reader :issue_iid, :filename
@@ -35,14 +33,6 @@ module Banzai
self.reference_type = :design
- # This filter must be enabled by setting the
- # design_management_reference_filter_gfm_pipeline flag
- def call
- return doc unless enabled?
-
- super
- end
-
def find_object(project, identifier)
records_per_parent[project][identifier]
end
@@ -112,10 +102,6 @@ module Banzai
.in_groups_of(100, false) # limitation of by_issue_id_and_filename, so we batch
.flat_map { |ids| DesignManagement::Design.by_issue_id_and_filename(ids) }
end
-
- def enabled?
- Feature.enabled?(FEATURE_FLAG, parent, default_enabled: true)
- end
end
end
end
diff --git a/lib/banzai/reference_parser.rb b/lib/banzai/reference_parser.rb
index c08d3364a87..8b5d689a984 100644
--- a/lib/banzai/reference_parser.rb
+++ b/lib/banzai/reference_parser.rb
@@ -2,6 +2,8 @@
module Banzai
module ReferenceParser
+ InvalidReferenceType = Class.new(StandardError)
+
# Returns the reference parser class for the given type
#
# Example:
@@ -11,6 +13,8 @@ module Banzai
# This would return the `Banzai::ReferenceParser::IssueParser` class.
def self.[](name)
const_get("#{name.to_s.camelize}Parser", false)
+ rescue NameError
+ raise InvalidReferenceType
end
end
end
diff --git a/lib/banzai/reference_parser/mentioned_group_parser.rb b/lib/banzai/reference_parser/mentioned_group_parser.rb
index a0892e15df8..75d05ef59f9 100644
--- a/lib/banzai/reference_parser/mentioned_group_parser.rb
+++ b/lib/banzai/reference_parser/mentioned_group_parser.rb
@@ -16,7 +16,7 @@ module Banzai
end
def nodes_visible_to_user(user, nodes)
- groups = lazy { grouped_objects_for_nodes(nodes, Group, GROUP_ATTR) }
+ groups = lazy { grouped_objects_for_nodes(nodes, references_relation, GROUP_ATTR) }
nodes.select do |node|
node.has_attribute?(GROUP_ATTR) && can_read_group_reference?(node, user, groups)
diff --git a/lib/banzai/reference_redactor.rb b/lib/banzai/reference_redactor.rb
index 936436982e7..81e4fd45966 100644
--- a/lib/banzai/reference_redactor.rb
+++ b/lib/banzai/reference_redactor.rb
@@ -111,6 +111,7 @@ module Banzai
parser = Banzai::ReferenceParser[type].new(context)
visible.merge(parser.nodes_visible_to_user(user, nodes))
+ rescue Banzai::ReferenceParser::InvalidReferenceType
end
visible
diff --git a/lib/feature.rb b/lib/feature.rb
index 71241e98723..1f8c530bee5 100644
--- a/lib/feature.rb
+++ b/lib/feature.rb
@@ -138,7 +138,7 @@ class Feature
def register_definitions
return unless check_feature_flags_definition?
- Feature::Definition.load_all!
+ Feature::Definition.reload!
end
def register_hot_reloader
diff --git a/lib/feature/definition.rb b/lib/feature/definition.rb
index ee779a86952..0ba1bdc4799 100644
--- a/lib/feature/definition.rb
+++ b/lib/feature/definition.rb
@@ -84,17 +84,14 @@ class Feature
end
def definitions
- @definitions ||= {}
+ # We lazily load all definitions
+ # The hot reloading might request a feature flag
+ # before we can properly call `load_all!`
+ @definitions ||= load_all!
end
- def load_all!
- definitions.clear
-
- paths.each do |glob_path|
- load_all_from_path!(glob_path)
- end
-
- definitions
+ def reload!
+ @definitions = load_all!
end
def valid_usage!(key, type:, default_enabled:)
@@ -110,9 +107,7 @@ class Feature
def register_hot_reloader!
# Reload feature flags on change of this file or any `.yml`
file_watcher = Rails.configuration.file_watcher.new(reload_files, reload_directories) do
- # We use `Feature::Definition` as on Ruby code-reload
- # a new class definition is created
- Feature::Definition.load_all!
+ Feature::Definition.reload!
end
Rails.application.reloaders << file_watcher
@@ -123,6 +118,16 @@ class Feature
private
+ def load_all!
+ # We currently do not load feature flag definitions
+ # in production environments
+ return [] unless Gitlab.dev_or_test_env?
+
+ paths.each_with_object({}) do |glob_path, definitions|
+ load_all_from_path!(definitions, glob_path)
+ end
+ end
+
def load_from_file(path)
definition = File.read(path)
definition = YAML.safe_load(definition)
@@ -133,7 +138,7 @@ class Feature
raise Feature::InvalidFeatureFlagError, "Invalid definition for `#{path}`: #{e.message}"
end
- def load_all_from_path!(glob_path)
+ def load_all_from_path!(definitions, glob_path)
Dir.glob(glob_path).each do |path|
definition = load_from_file(path)
@@ -146,7 +151,7 @@ class Feature
end
def reload_files
- [File.expand_path(__FILE__)]
+ []
end
def reload_directories
diff --git a/lib/feature/shared.rb b/lib/feature/shared.rb
index c06f699ef27..9ec56ee6b52 100644
--- a/lib/feature/shared.rb
+++ b/lib/feature/shared.rb
@@ -9,12 +9,14 @@ class Feature
# optional: defines if a on-disk definition is required for this feature flag type
# rollout_issue: defines if `bin/feature-flag` asks for rollout issue
# default_enabled: defines a default state of a feature flag when created by `bin/feature-flag`
+ # ee_only: defines that a feature flag can only be created in a context of EE
# example: usage being shown when exception is raised
TYPES = {
development: {
description: 'Short lived, used to enable unfinished code to be deployed',
- optional: true,
+ optional: false,
rollout_issue: true,
+ ee_only: false,
default_enabled: false,
example: <<-EOS
Feature.enabled?(:my_feature_flag, project)
@@ -26,6 +28,7 @@ class Feature
description: "Long-lived feature flags that control operational aspects of GitLab's behavior",
optional: true,
rollout_issue: false,
+ ee_only: false,
default_enabled: false,
example: <<-EOS
Feature.enabled?(:my_ops_flag, type: ops)
@@ -36,6 +39,7 @@ class Feature
description: 'Permanent feature flags used to temporarily disable licensed features.',
optional: true,
rollout_issue: false,
+ ee_only: true,
default_enabled: true,
example: <<-EOS
project.feature_available?(:my_licensed_feature)
@@ -44,13 +48,15 @@ class Feature
}
}.freeze
+ # The ordering of PARAMS defines an order in YAML
+ # This is done to ease the file comparison
PARAMS = %i[
name
- default_enabled
- type
introduced_by_url
rollout_issue_url
+ type
group
+ default_enabled
].freeze
end
end
diff --git a/lib/gitlab/alert_management/alert_params.rb b/lib/gitlab/alert_management/alert_params.rb
deleted file mode 100644
index 3bb839c1114..00000000000
--- a/lib/gitlab/alert_management/alert_params.rb
+++ /dev/null
@@ -1,46 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module AlertManagement
- class AlertParams
- MONITORING_TOOLS = {
- prometheus: 'Prometheus'
- }.freeze
-
- def self.from_generic_alert(project:, payload:)
- parsed_payload = Gitlab::Alerting::NotificationPayloadParser.call(payload, project).with_indifferent_access
- annotations = parsed_payload[:annotations]
-
- {
- project_id: project.id,
- title: annotations[:title],
- description: annotations[:description],
- monitoring_tool: annotations[:monitoring_tool],
- service: annotations[:service],
- hosts: Array(annotations[:hosts]),
- payload: payload,
- started_at: parsed_payload['startsAt'],
- ended_at: parsed_payload['endsAt'],
- severity: annotations[:severity],
- fingerprint: annotations[:fingerprint],
- environment: annotations[:environment]
- }
- end
-
- def self.from_prometheus_alert(project:, parsed_alert:)
- {
- project_id: project.id,
- title: parsed_alert.title,
- description: parsed_alert.description,
- monitoring_tool: MONITORING_TOOLS[:prometheus],
- payload: parsed_alert.payload,
- started_at: parsed_alert.starts_at,
- ended_at: parsed_alert.ends_at,
- fingerprint: parsed_alert.gitlab_fingerprint,
- environment: parsed_alert.environment,
- prometheus_alert: parsed_alert.gitlab_alert
- }
- end
- end
- end
-end
diff --git a/lib/gitlab/alert_management/alert_status_counts.rb b/lib/gitlab/alert_management/alert_status_counts.rb
index 382026236e0..e55e0016599 100644
--- a/lib/gitlab/alert_management/alert_status_counts.rb
+++ b/lib/gitlab/alert_management/alert_status_counts.rb
@@ -6,8 +6,6 @@ module Gitlab
class AlertStatusCounts
include Gitlab::Utils::StrongMemoize
- STATUSES = ::AlertManagement::Alert::STATUSES
-
attr_reader :project
def self.declarative_policy_class
@@ -21,7 +19,7 @@ module Gitlab
end
# Define method for each status
- STATUSES.each_key do |status|
+ ::AlertManagement::Alert.status_names.each do |status|
define_method(status) { counts[status] }
end
@@ -30,7 +28,7 @@ module Gitlab
end
def all
- counts.values.sum # rubocop:disable CodeReuse/ActiveRecord
+ counts.values.sum
end
private
@@ -44,9 +42,7 @@ module Gitlab
end
def counts_by_status
- ::AlertManagement::AlertsFinder
- .counts_by_status(current_user, project, params)
- .transform_keys { |status_id| STATUSES.key(status_id) }
+ ::AlertManagement::AlertsFinder.counts_by_status(current_user, project, params)
end
end
end
diff --git a/lib/gitlab/alert_management/payload/base.rb b/lib/gitlab/alert_management/payload/base.rb
index 74e47e5226e..0fd593a3780 100644
--- a/lib/gitlab/alert_management/payload/base.rb
+++ b/lib/gitlab/alert_management/payload/base.rb
@@ -88,19 +88,19 @@ module Gitlab
# AlertManagement::Alert directly for read operations.
def alert_params
{
- description: description,
+ description: description&.truncate(::AlertManagement::Alert::DESCRIPTION_MAX_LENGTH),
ended_at: ends_at,
environment: environment,
fingerprint: gitlab_fingerprint,
- hosts: Array(hosts),
- monitoring_tool: monitoring_tool,
+ hosts: truncate_hosts(Array(hosts).flatten),
+ monitoring_tool: monitoring_tool&.truncate(::AlertManagement::Alert::TOOL_MAX_LENGTH),
payload: payload,
project_id: project.id,
prometheus_alert: gitlab_alert,
- service: service,
+ service: service&.truncate(::AlertManagement::Alert::SERVICE_MAX_LENGTH),
severity: severity,
started_at: starts_at,
- title: title
+ title: title&.truncate(::AlertManagement::Alert::TITLE_MAX_LENGTH)
}.transform_values(&:presence).compact
end
@@ -135,6 +135,18 @@ module Gitlab
def plain_gitlab_fingerprint; end
+ def truncate_hosts(hosts)
+ return hosts if hosts.join.length <= ::AlertManagement::Alert::HOSTS_MAX_LENGTH
+
+ hosts.inject([]) do |new_hosts, host|
+ remaining_length = ::AlertManagement::Alert::HOSTS_MAX_LENGTH - new_hosts.join.length
+
+ break new_hosts unless remaining_length > 0
+
+ new_hosts << host.to_s.truncate(remaining_length, omission: '')
+ end
+ end
+
def value_for_paths(paths)
target_path = paths.find { |path| payload&.dig(*path) }
diff --git a/lib/gitlab/alert_management/payload/generic.rb b/lib/gitlab/alert_management/payload/generic.rb
index 7efdfac75dc..e8e85155bef 100644
--- a/lib/gitlab/alert_management/payload/generic.rb
+++ b/lib/gitlab/alert_management/payload/generic.rb
@@ -8,6 +8,8 @@ module Gitlab
DEFAULT_TITLE = 'New: Incident'
DEFAULT_SEVERITY = 'critical'
+ attribute :description, paths: 'description'
+ attribute :ends_at, paths: 'end_time', type: :time
attribute :environment_name, paths: 'gitlab_environment_name'
attribute :hosts, paths: 'hosts'
attribute :monitoring_tool, paths: 'monitoring_tool'
@@ -23,3 +25,5 @@ module Gitlab
end
end
end
+
+Gitlab::AlertManagement::Payload::Generic.prepend_if_ee('EE::Gitlab::AlertManagement::Payload::Generic')
diff --git a/lib/gitlab/alerting/alert.rb b/lib/gitlab/alerting/alert.rb
deleted file mode 100644
index 94b81b7d290..00000000000
--- a/lib/gitlab/alerting/alert.rb
+++ /dev/null
@@ -1,215 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module Alerting
- class Alert
- include ActiveModel::Model
- include Gitlab::Utils::StrongMemoize
- include Presentable
-
- attr_accessor :project, :payload, :am_alert
-
- def self.for_alert_management_alert(project:, alert:)
- params = if alert.prometheus?
- alert.payload
- else
- Gitlab::Alerting::NotificationPayloadParser.call(alert.payload.to_h, alert.project)
- end
-
- self.new(project: project, payload: params, am_alert: alert)
- end
-
- def gitlab_alert
- strong_memoize(:gitlab_alert) do
- parse_gitlab_alert_from_payload
- end
- end
-
- def metric_id
- strong_memoize(:metric_id) do
- payload&.dig('labels', 'gitlab_alert_id')
- end
- end
-
- def gitlab_prometheus_alert_id
- strong_memoize(:gitlab_prometheus_alert_id) do
- payload&.dig('labels', 'gitlab_prometheus_alert_id')
- end
- end
-
- def title
- strong_memoize(:title) do
- gitlab_alert&.title || parse_title_from_payload
- end
- end
-
- def description
- strong_memoize(:description) do
- parse_description_from_payload
- end
- end
-
- def environment
- strong_memoize(:environment) do
- gitlab_alert&.environment || parse_environment_from_payload
- end
- end
-
- def annotations
- strong_memoize(:annotations) do
- parse_annotations_from_payload || []
- end
- end
-
- def starts_at
- strong_memoize(:starts_at) do
- parse_datetime_from_payload('startsAt')
- end
- end
-
- def starts_at_raw
- strong_memoize(:starts_at_raw) do
- payload&.dig('startsAt')
- end
- end
-
- def ends_at
- strong_memoize(:ends_at) do
- parse_datetime_from_payload('endsAt')
- end
- end
-
- def full_query
- strong_memoize(:full_query) do
- gitlab_alert&.full_query || parse_expr_from_payload
- end
- end
-
- def y_label
- strong_memoize(:y_label) do
- parse_y_label_from_payload || title
- end
- end
-
- def alert_markdown
- strong_memoize(:alert_markdown) do
- parse_alert_markdown_from_payload
- end
- end
-
- def status
- strong_memoize(:status) do
- payload&.dig('status')
- end
- end
-
- def firing?
- status == 'firing'
- end
-
- def resolved?
- status == 'resolved'
- end
-
- def gitlab_managed?
- metric_id.present?
- end
-
- def gitlab_fingerprint
- Gitlab::AlertManagement::Fingerprint.generate(plain_gitlab_fingerprint)
- end
-
- def valid?
- payload.respond_to?(:dig) && project && title && starts_at
- end
-
- def present
- super(presenter_class: Projects::Prometheus::AlertPresenter)
- end
-
- private
-
- def plain_gitlab_fingerprint
- if gitlab_managed?
- [metric_id, starts_at_raw].join('/')
- else # self managed
- [starts_at_raw, title, full_query].join('/')
- end
- end
-
- def parse_environment_from_payload
- environment_name = payload&.dig('labels', 'gitlab_environment_name')
-
- return unless environment_name
-
- EnvironmentsFinder.new(project, nil, { name: environment_name })
- .find
- &.first
- end
-
- def parse_gitlab_alert_from_payload
- alerts_found = matching_gitlab_alerts
-
- return if alerts_found.blank? || alerts_found.size > 1
-
- alerts_found.first
- end
-
- def matching_gitlab_alerts
- return unless metric_id || gitlab_prometheus_alert_id
-
- Projects::Prometheus::AlertsFinder
- .new(project: project, metric: metric_id, id: gitlab_prometheus_alert_id)
- .execute
- end
-
- def parse_title_from_payload
- payload&.dig('annotations', 'title') ||
- payload&.dig('annotations', 'summary') ||
- payload&.dig('labels', 'alertname')
- end
-
- def parse_description_from_payload
- payload&.dig('annotations', 'description')
- end
-
- def parse_annotations_from_payload
- payload&.dig('annotations')&.map do |label, value|
- Alerting::AlertAnnotation.new(label: label, value: value)
- end
- end
-
- def parse_datetime_from_payload(field)
- value = payload&.dig(field)
- return unless value
-
- # value is a rfc3339 timestamp
- # Timestamps from Prometheus and Alertmanager are UTC RFC3339 timestamps like: '2018-03-12T09:06:00Z' (Z represents 0 offset or UTC)
- # .utc sets the datetime zone to `UTC`
- Time.rfc3339(value).utc
- rescue ArgumentError
- end
-
- # Parses `g0.expr` from `generatorURL`.
- #
- # Example: http://localhost:9090/graph?g0.expr=vector%281%29&g0.tab=1
- def parse_expr_from_payload
- url = payload&.dig('generatorURL')
- return unless url
-
- uri = URI(url)
-
- Rack::Utils.parse_query(uri.query).fetch('g0.expr')
- rescue URI::InvalidURIError, KeyError
- end
-
- def parse_alert_markdown_from_payload
- payload&.dig('annotations', 'gitlab_incident_markdown')
- end
-
- def parse_y_label_from_payload
- payload&.dig('annotations', 'gitlab_y_label')
- end
- end
- end
-end
diff --git a/lib/gitlab/alerting/alert_annotation.rb b/lib/gitlab/alerting/alert_annotation.rb
deleted file mode 100644
index a4b3a97b08c..00000000000
--- a/lib/gitlab/alerting/alert_annotation.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module Alerting
- class AlertAnnotation
- include ActiveModel::Model
-
- attr_accessor :label, :value
- end
- end
-end
diff --git a/lib/gitlab/alerting/notification_payload_parser.rb b/lib/gitlab/alerting/notification_payload_parser.rb
deleted file mode 100644
index 348f851f551..00000000000
--- a/lib/gitlab/alerting/notification_payload_parser.rb
+++ /dev/null
@@ -1,107 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module Alerting
- class NotificationPayloadParser
- BadPayloadError = Class.new(StandardError)
-
- DEFAULT_TITLE = 'New: Incident'
- DEFAULT_SEVERITY = 'critical'
-
- def initialize(payload, project)
- @payload = payload.to_h.with_indifferent_access
- @project = project
- end
-
- def self.call(payload, project)
- new(payload, project).call
- end
-
- def call
- {
- 'annotations' => annotations,
- 'startsAt' => starts_at,
- 'endsAt' => ends_at
- }.compact
- end
-
- private
-
- attr_reader :payload, :project
-
- def title
- payload[:title].presence || DEFAULT_TITLE
- end
-
- def severity
- payload[:severity].presence || DEFAULT_SEVERITY
- end
-
- def fingerprint
- Gitlab::AlertManagement::Fingerprint.generate(payload[:fingerprint])
- end
-
- def annotations
- primary_params
- .reverse_merge(flatten_secondary_params)
- .transform_values(&:presence)
- .compact
- end
-
- def primary_params
- {
- 'title' => title,
- 'description' => payload[:description],
- 'monitoring_tool' => payload[:monitoring_tool],
- 'service' => payload[:service],
- 'hosts' => hosts.presence,
- 'severity' => severity,
- 'fingerprint' => fingerprint,
- 'environment' => environment
- }
- end
-
- def hosts
- Array(payload[:hosts]).reject(&:blank?)
- end
-
- def current_time
- Time.current.change(usec: 0).rfc3339
- end
-
- def starts_at
- Time.parse(payload[:start_time].to_s).rfc3339
- rescue ArgumentError
- current_time
- end
-
- def ends_at
- Time.parse(payload[:end_time].to_s).rfc3339
- rescue ArgumentError
- nil
- end
-
- def environment
- environment_name = payload[:gitlab_environment_name]
-
- return unless environment_name
-
- EnvironmentsFinder.new(project, nil, { name: environment_name })
- .find
- &.first
- end
-
- def secondary_params
- payload.except(:start_time, :end_time)
- end
-
- def flatten_secondary_params
- Gitlab::Utils::SafeInlineHash.merge_keys!(secondary_params)
- rescue ArgumentError
- raise BadPayloadError, 'The payload is too big'
- end
- end
- end
-end
-
-Gitlab::Alerting::NotificationPayloadParser.prepend_if_ee('EE::Gitlab::Alerting::NotificationPayloadParser')
diff --git a/lib/gitlab/application_context.rb b/lib/gitlab/application_context.rb
index 30cb74bcf54..b4bbb309c36 100644
--- a/lib/gitlab/application_context.rb
+++ b/lib/gitlab/application_context.rb
@@ -12,7 +12,8 @@ module Gitlab
Attribute.new(:namespace, Namespace),
Attribute.new(:user, User),
Attribute.new(:caller_id, String),
- Attribute.new(:related_class, String)
+ Attribute.new(:related_class, String),
+ Attribute.new(:feature_category, String)
].freeze
def self.with_context(args, &block)
@@ -45,6 +46,7 @@ module Gitlab
hash[:root_namespace] = -> { root_namespace_path } if include_namespace?
hash[:caller_id] = caller_id if set_values.include?(:caller_id)
hash[:related_class] = related_class if set_values.include?(:related_class)
+ hash[:feature_category] = feature_category if set_values.include?(:feature_category)
end
end
diff --git a/lib/gitlab/auth.rb b/lib/gitlab/auth.rb
index 609eef5e365..001c083c778 100644
--- a/lib/gitlab/auth.rb
+++ b/lib/gitlab/auth.rb
@@ -371,7 +371,7 @@ module Gitlab
end
def find_build_by_token(token)
- ::Ci::Build.running.find_by_token(token)
+ ::Ci::AuthJobFinder.new(token: token).execute
end
def user_auth_attempt!(user, success:)
diff --git a/lib/gitlab/auth/auth_finders.rb b/lib/gitlab/auth/auth_finders.rb
index ccf52bae9a5..3d3f7212053 100644
--- a/lib/gitlab/auth/auth_finders.rb
+++ b/lib/gitlab/auth/auth_finders.rb
@@ -290,7 +290,7 @@ module Gitlab
end
def api_request?
- current_request.path.starts_with?('/api/')
+ current_request.path.starts_with?(Gitlab::Utils.append_path(Gitlab.config.gitlab.relative_url_root, '/api/'))
end
def archive_request?
diff --git a/lib/gitlab/auth/otp/strategies/base.rb b/lib/gitlab/auth/otp/strategies/base.rb
new file mode 100644
index 00000000000..718630e0e31
--- /dev/null
+++ b/lib/gitlab/auth/otp/strategies/base.rb
@@ -0,0 +1,32 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Auth
+ module Otp
+ module Strategies
+ class Base
+ def initialize(user)
+ @user = user
+ end
+
+ private
+
+ attr_reader :user
+
+ def success
+ { status: :success }
+ end
+
+ def error(message, http_status = nil)
+ result = { message: message,
+ status: :error }
+
+ result[:http_status] = http_status if http_status
+
+ result
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/auth/otp/strategies/devise.rb b/lib/gitlab/auth/otp/strategies/devise.rb
new file mode 100644
index 00000000000..93068d6c9b0
--- /dev/null
+++ b/lib/gitlab/auth/otp/strategies/devise.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Auth
+ module Otp
+ module Strategies
+ class Devise < Base
+ def validate(otp_code)
+ user.validate_and_consume_otp!(otp_code) ? success : error('invalid OTP code')
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/auth/otp/strategies/forti_authenticator.rb b/lib/gitlab/auth/otp/strategies/forti_authenticator.rb
new file mode 100644
index 00000000000..fbcb9fd8cdb
--- /dev/null
+++ b/lib/gitlab/auth/otp/strategies/forti_authenticator.rb
@@ -0,0 +1,41 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Auth
+ module Otp
+ module Strategies
+ class FortiAuthenticator < Base
+ def validate(otp_code)
+ body = { username: user.username,
+ token_code: otp_code }
+
+ response = Gitlab::HTTP.post(
+ auth_url,
+ headers: { 'Content-Type': 'application/json' },
+ body: body.to_json,
+ basic_auth: api_credentials)
+
+ # Successful authentication results in HTTP 200: OK
+ # https://docs.fortinet.com/document/fortiauthenticator/6.2.0/rest-api-solution-guide/704555/authentication-auth
+ response.ok? ? success : error(message: response.message, http_status: response.code)
+ end
+
+ private
+
+ def auth_url
+ host = ::Gitlab.config.forti_authenticator.host
+ port = ::Gitlab.config.forti_authenticator.port
+ path = 'api/v1/auth/'
+
+ "https://#{host}:#{port}/#{path}"
+ end
+
+ def api_credentials
+ { username: ::Gitlab.config.forti_authenticator.username,
+ password: ::Gitlab.config.forti_authenticator.token }
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/auth/user_access_denied_reason.rb b/lib/gitlab/auth/user_access_denied_reason.rb
index cc4b8d887ff..36b54ba2e46 100644
--- a/lib/gitlab/auth/user_access_denied_reason.rb
+++ b/lib/gitlab/auth/user_access_denied_reason.rb
@@ -11,6 +11,8 @@ module Gitlab
case rejection_type
when :internal
"This action cannot be performed by internal users"
+ when :blocked_pending_approval
+ "Your account is pending approval from your administrator and hence blocked."
when :terms_not_accepted
"You (#{@user.to_reference}) must accept the Terms of Service in order to perform this action. "\
"Please access GitLab from a web browser to accept these terms."
@@ -31,6 +33,8 @@ module Gitlab
def rejection_type
if @user.internal?
:internal
+ elsif @user.blocked_pending_approval?
+ :blocked_pending_approval
elsif @user.required_terms_not_accepted?
:terms_not_accepted
elsif @user.deactivated?
diff --git a/lib/gitlab/background_migration/add_modified_to_approval_merge_request_rule.rb b/lib/gitlab/background_migration/add_modified_to_approval_merge_request_rule.rb
new file mode 100644
index 00000000000..2148e96f6b4
--- /dev/null
+++ b/lib/gitlab/background_migration/add_modified_to_approval_merge_request_rule.rb
@@ -0,0 +1,73 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module BackgroundMigration
+ # Compare all current rules to project rules
+ class AddModifiedToApprovalMergeRequestRule
+ # Stubbed class to access the Group table
+ class Group < ActiveRecord::Base
+ self.table_name = 'namespaces'
+ self.inheritance_column = :_type_disabled
+ end
+
+ # Stubbed class to access the ApprovalMergeRequestRule table
+ class ApprovalMergeRequestRule < ActiveRecord::Base
+ self.table_name = 'approval_merge_request_rules'
+
+ has_one :approval_merge_request_rule_source, class_name: 'AddModifiedToApprovalMergeRequestRule::ApprovalMergeRequestRuleSource'
+ has_one :approval_project_rule, through: :approval_merge_request_rule_source
+ has_and_belongs_to_many :groups,
+ class_name: 'AddModifiedToApprovalMergeRequestRule::Group', join_table: "#{self.table_name}_groups"
+ end
+
+ # Stubbed class to access the ApprovalProjectRule table
+ class ApprovalProjectRule < ActiveRecord::Base
+ self.table_name = 'approval_project_rules'
+
+ has_many :approval_merge_request_rule_sources, class_name: 'AddModifiedToApprovalMergeRequestRule::ApprovalMergeRequestRuleSource'
+ has_and_belongs_to_many :groups,
+ class_name: 'AddModifiedToApprovalMergeRequestRule::Group', join_table: "#{self.table_name}_groups"
+ end
+
+ # Stubbed class to access the ApprovalMergeRequestRuleSource table
+ class ApprovalMergeRequestRuleSource < ActiveRecord::Base
+ self.table_name = 'approval_merge_request_rule_sources'
+
+ belongs_to :approval_merge_request_rule, class_name: 'AddModifiedToApprovalMergeRequestRule::ApprovalMergeRequestRule'
+ belongs_to :approval_project_rule, class_name: 'AddModifiedToApprovalMergeRequestRule::ApprovalProjectRule'
+ end
+
+ def perform(start_id, stop_id)
+ approval_merge_requests_rules = ApprovalMergeRequestRule
+ .joins(:groups, :approval_merge_request_rule_source)
+ .where(id: start_id..stop_id)
+ .pluck(
+ 'approval_merge_request_rule_sources.id as ars_id',
+ 'approval_merge_request_rules_groups.id as amrg_id'
+ )
+
+ approval_project_rules = ApprovalProjectRule
+ .joins(:groups, approval_merge_request_rule_sources: :approval_merge_request_rule)
+ .where(approval_merge_request_rules: { id: start_id..stop_id })
+ .pluck(
+ 'approval_merge_request_rule_sources.id as ars_id',
+ 'approval_project_rules_groups.id as apg_id'
+ )
+
+ different_names_or_approval_sources = ApprovalMergeRequestRule.joins(:approval_project_rule, :approval_merge_request_rule_source)
+ .where(id: start_id..stop_id)
+ .where('approval_merge_request_rules.name != approval_project_rules.name OR ' \
+ 'approval_merge_request_rules.approvals_required != approval_project_rules.approvals_required')
+ .pluck('approval_merge_request_rule_sources.id as ars_id')
+
+ intersected_set = approval_merge_requests_rules.to_set ^ approval_project_rules.to_set
+ source_ids = intersected_set.collect { |rule| rule[0] }.uniq
+
+ rule_sources = ApprovalMergeRequestRuleSource.where(id: source_ids + different_names_or_approval_sources)
+ changed_merge_request_rules = ApprovalMergeRequestRule.where(id: rule_sources.select(:approval_merge_request_rule_id))
+
+ changed_merge_request_rules.update_all(modified_from_project_rule: true)
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/background_migration/backfill_snippet_repositories.rb b/lib/gitlab/background_migration/backfill_snippet_repositories.rb
index 21538000fec..8befade8c3a 100644
--- a/lib/gitlab/background_migration/backfill_snippet_repositories.rb
+++ b/lib/gitlab/background_migration/backfill_snippet_repositories.rb
@@ -109,7 +109,7 @@ module Gitlab
end
def create_commit(snippet)
- snippet.snippet_repository.multi_files_action(commit_author(snippet), snippet_action(snippet), commit_attrs)
+ snippet.snippet_repository.multi_files_action(commit_author(snippet), snippet_action(snippet), **commit_attrs)
end
# If the user is not allowed to access git or update the snippet
diff --git a/lib/gitlab/background_migration/migrate_u2f_webauthn.rb b/lib/gitlab/background_migration/migrate_u2f_webauthn.rb
new file mode 100644
index 00000000000..b8c14aa2573
--- /dev/null
+++ b/lib/gitlab/background_migration/migrate_u2f_webauthn.rb
@@ -0,0 +1,46 @@
+# frozen_string_literal: true
+# rubocop:disable Style/Documentation
+require "webauthn/u2f_migrator"
+
+module Gitlab
+ module BackgroundMigration
+ class MigrateU2fWebauthn
+ class U2fRegistration < ActiveRecord::Base
+ self.table_name = 'u2f_registrations'
+ end
+
+ class WebauthnRegistration < ActiveRecord::Base
+ self.table_name = 'webauthn_registrations'
+ end
+
+ def perform(start_id, end_id)
+ old_registrations = U2fRegistration.where(id: start_id..end_id)
+ old_registrations.each_slice(100) do |slice|
+ now = Time.now
+ values = slice.map do |u2f_registration|
+ converted_credential = WebAuthn::U2fMigrator.new(
+ app_id: Gitlab.config.gitlab.url,
+ certificate: u2f_registration.certificate,
+ key_handle: u2f_registration.key_handle,
+ public_key: u2f_registration.public_key,
+ counter: u2f_registration.counter
+ ).credential
+
+ {
+ credential_xid: Base64.strict_encode64(converted_credential.id),
+ public_key: Base64.strict_encode64(converted_credential.public_key),
+ counter: u2f_registration.counter || 0,
+ name: u2f_registration.name || '',
+ user_id: u2f_registration.user_id,
+ u2f_registration_id: u2f_registration.id,
+ created_at: now,
+ updated_at: now
+ }
+ end
+
+ WebauthnRegistration.insert_all(values, unique_by: :credential_xid, returning: false)
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/background_migration/migrate_users_bio_to_user_details.rb b/lib/gitlab/background_migration/migrate_users_bio_to_user_details.rb
index ca64d13b118..bbe2164ae4e 100644
--- a/lib/gitlab/background_migration/migrate_users_bio_to_user_details.rb
+++ b/lib/gitlab/background_migration/migrate_users_bio_to_user_details.rb
@@ -13,8 +13,6 @@ module Gitlab
end
def perform(start_id, stop_id)
- return if Feature.disabled?(:migrate_bio_to_user_details, default_enabled: true)
-
relation = User
.select("id AS user_id", "substring(COALESCE(bio, '') from 1 for 255) AS bio")
.where("(COALESCE(bio, '') IS DISTINCT FROM '')")
diff --git a/lib/gitlab/background_migration/remove_duplicated_cs_findings_without_vulnerability_id.rb b/lib/gitlab/background_migration/remove_duplicated_cs_findings_without_vulnerability_id.rb
new file mode 100644
index 00000000000..cd305adc7cd
--- /dev/null
+++ b/lib/gitlab/background_migration/remove_duplicated_cs_findings_without_vulnerability_id.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+# rubocop:disable Style/Documentation
+
+module Gitlab
+ module BackgroundMigration
+ class RemoveDuplicatedCsFindingsWithoutVulnerabilityId
+ def perform(start_id, stop_id)
+ end
+ end
+ end
+end
+
+Gitlab::BackgroundMigration::RemoveDuplicatedCsFindingsWithoutVulnerabilityId.prepend_if_ee('EE::Gitlab::BackgroundMigration::RemoveDuplicatedCsFindingsWithoutVulnerabilityId')
diff --git a/lib/gitlab/background_migration/replace_blocked_by_links.rb b/lib/gitlab/background_migration/replace_blocked_by_links.rb
new file mode 100644
index 00000000000..26626aaef79
--- /dev/null
+++ b/lib/gitlab/background_migration/replace_blocked_by_links.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+# rubocop:disable Style/Documentation
+
+module Gitlab
+ module BackgroundMigration
+ class ReplaceBlockedByLinks
+ class IssueLink < ActiveRecord::Base
+ self.table_name = 'issue_links'
+ end
+
+ def perform(start_id, stop_id)
+ blocked_by_links = IssueLink.where(id: start_id..stop_id).where(link_type: 2)
+
+ ActiveRecord::Base.transaction do
+ # if there is duplicit bi-directional relation (issue2 is blocked by issue1
+ # and issue1 already links issue2), then we can just delete 'blocked by'.
+ # This should be rare as we have a pre-create check which checks if issues are
+ # already linked
+ blocked_by_links
+ .joins('INNER JOIN issue_links as opposite_links ON issue_links.source_id = opposite_links.target_id AND issue_links.target_id = opposite_links.source_id')
+ .where('opposite_links.link_type': 1)
+ .delete_all
+
+ blocked_by_links.update_all('source_id=target_id,target_id=source_id,link_type=1')
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/background_migration/sync_blocking_issues_count.rb b/lib/gitlab/background_migration/sync_blocking_issues_count.rb
new file mode 100644
index 00000000000..6262320128c
--- /dev/null
+++ b/lib/gitlab/background_migration/sync_blocking_issues_count.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+# rubocop:disable Style/Documentation
+
+module Gitlab
+ module BackgroundMigration
+ class SyncBlockingIssuesCount
+ def perform(start_id, end_id)
+ end
+ end
+ end
+end
+
+Gitlab::BackgroundMigration::SyncBlockingIssuesCount.prepend_if_ee('EE::Gitlab::BackgroundMigration::SyncBlockingIssuesCount')
diff --git a/lib/gitlab/background_migration/user_mentions/lib/banzai/reference_parser.rb b/lib/gitlab/background_migration/user_mentions/lib/banzai/reference_parser.rb
new file mode 100644
index 00000000000..3def5eb3369
--- /dev/null
+++ b/lib/gitlab/background_migration/user_mentions/lib/banzai/reference_parser.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module BackgroundMigration
+ module UserMentions
+ module Lib
+ module Banzai
+ # isolated Banzai::ReferenceParser
+ module ReferenceParser
+ # Returns the reference parser class for the given type
+ #
+ # Example:
+ #
+ # Banzai::ReferenceParser['isolated_mentioned_group']
+ #
+ # This would return the `::Gitlab::BackgroundMigration::UserMentions::Lib::Banzai::ReferenceParser::IsolatedMentionedGroupParser` class.
+ def self.[](name)
+ const_get("::Gitlab::BackgroundMigration::UserMentions::Lib::Banzai::ReferenceParser::#{name.to_s.camelize}Parser", false)
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/background_migration/user_mentions/lib/banzai/reference_parser/isolated_mentioned_group_parser.rb b/lib/gitlab/background_migration/user_mentions/lib/banzai/reference_parser/isolated_mentioned_group_parser.rb
new file mode 100644
index 00000000000..d3d032ba433
--- /dev/null
+++ b/lib/gitlab/background_migration/user_mentions/lib/banzai/reference_parser/isolated_mentioned_group_parser.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module BackgroundMigration
+ module UserMentions
+ module Lib
+ module Banzai
+ module ReferenceParser
+ # isolated Banzai::ReferenceParser::MentionedGroupParser
+ class IsolatedMentionedGroupParser < ::Banzai::ReferenceParser::MentionedGroupParser
+ extend ::Gitlab::Utils::Override
+
+ self.reference_type = :user
+
+ override :references_relation
+ def references_relation
+ ::Gitlab::BackgroundMigration::UserMentions::Models::Group
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/background_migration/user_mentions/lib/gitlab/isolated_reference_extractor.rb b/lib/gitlab/background_migration/user_mentions/lib/gitlab/isolated_reference_extractor.rb
new file mode 100644
index 00000000000..1d3a3af81a1
--- /dev/null
+++ b/lib/gitlab/background_migration/user_mentions/lib/gitlab/isolated_reference_extractor.rb
@@ -0,0 +1,30 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module BackgroundMigration
+ module UserMentions
+ module Lib
+ module Gitlab
+ # Extract possible GFM references from an arbitrary String for further processing.
+ class IsolatedReferenceExtractor < ::Gitlab::ReferenceExtractor
+ REFERABLES = %i(isolated_mentioned_group).freeze
+
+ REFERABLES.each do |type|
+ define_method("#{type}s") do
+ @references[type] ||= isolated_references(type)
+ end
+ end
+
+ def isolated_references(type)
+ context = ::Banzai::RenderContext.new(project, current_user)
+ processor = ::Gitlab::BackgroundMigration::UserMentions::Lib::Banzai::ReferenceParser[type].new(context)
+
+ refs = processor.process(html_documents)
+ refs[:visible]
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/background_migration/user_mentions/models/concerns/isolated_mentionable.rb b/lib/gitlab/background_migration/user_mentions/models/concerns/isolated_mentionable.rb
index 69ba3f9132b..be9c0ad2b3a 100644
--- a/lib/gitlab/background_migration/user_mentions/models/concerns/isolated_mentionable.rb
+++ b/lib/gitlab/background_migration/user_mentions/models/concerns/isolated_mentionable.rb
@@ -36,7 +36,8 @@ module Gitlab
if extractor
extractors[current_user] = extractor
else
- extractor = extractors[current_user] ||= ::Gitlab::ReferenceExtractor.new(project, current_user)
+ extractor = extractors[current_user] ||=
+ Gitlab::BackgroundMigration::UserMentions::Lib::Gitlab::IsolatedReferenceExtractor.new(project, current_user)
extractor.reset_memoized_values
end
@@ -71,7 +72,7 @@ module Gitlab
mentioned_users_ids = array_to_sql(refs.mentioned_users.pluck(:id))
mentioned_projects_ids = array_to_sql(refs.mentioned_projects.pluck(:id))
- mentioned_groups_ids = array_to_sql(refs.mentioned_groups.pluck(:id))
+ mentioned_groups_ids = array_to_sql(refs.isolated_mentioned_groups.pluck(:id))
return if mentioned_users_ids.blank? && mentioned_projects_ids.blank? && mentioned_groups_ids.blank?
diff --git a/lib/gitlab/background_migration/user_mentions/models/concerns/namespace/recursive_traversal.rb b/lib/gitlab/background_migration/user_mentions/models/concerns/namespace/recursive_traversal.rb
new file mode 100644
index 00000000000..5cadfa45b5b
--- /dev/null
+++ b/lib/gitlab/background_migration/user_mentions/models/concerns/namespace/recursive_traversal.rb
@@ -0,0 +1,74 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module BackgroundMigration
+ module UserMentions
+ module Models
+ module Concerns
+ module Namespace
+ # extracted methods for recursive traversing of namespace hierarchy
+ module RecursiveTraversal
+ extend ActiveSupport::Concern
+
+ def root_ancestor
+ return self if persisted? && parent_id.nil?
+
+ strong_memoize(:root_ancestor) do
+ Gitlab::ObjectHierarchy
+ .new(self.class.where(id: id))
+ .base_and_ancestors
+ .reorder(nil)
+ .find_by(parent_id: nil)
+ end
+ end
+
+ # Returns all ancestors, self, and descendants of the current namespace.
+ def self_and_hierarchy
+ Gitlab::ObjectHierarchy
+ .new(self.class.where(id: id))
+ .all_objects
+ end
+
+ # Returns all the ancestors of the current namespaces.
+ def ancestors
+ return self.class.none unless parent_id
+
+ Gitlab::ObjectHierarchy
+ .new(self.class.where(id: parent_id))
+ .base_and_ancestors
+ end
+
+ # returns all ancestors upto but excluding the given namespace
+ # when no namespace is given, all ancestors upto the top are returned
+ def ancestors_upto(top = nil, hierarchy_order: nil)
+ Gitlab::ObjectHierarchy.new(self.class.where(id: id))
+ .ancestors(upto: top, hierarchy_order: hierarchy_order)
+ end
+
+ def self_and_ancestors(hierarchy_order: nil)
+ return self.class.where(id: id) unless parent_id
+
+ Gitlab::ObjectHierarchy
+ .new(self.class.where(id: id))
+ .base_and_ancestors(hierarchy_order: hierarchy_order)
+ end
+
+ # Returns all the descendants of the current namespace.
+ def descendants
+ Gitlab::ObjectHierarchy
+ .new(self.class.where(parent_id: id))
+ .base_and_descendants
+ end
+
+ def self_and_descendants
+ Gitlab::ObjectHierarchy
+ .new(self.class.where(id: id))
+ .base_and_descendants
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/background_migration/user_mentions/models/group.rb b/lib/gitlab/background_migration/user_mentions/models/group.rb
new file mode 100644
index 00000000000..bc04172b9a2
--- /dev/null
+++ b/lib/gitlab/background_migration/user_mentions/models/group.rb
@@ -0,0 +1,91 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module BackgroundMigration
+ module UserMentions
+ module Models
+ # isolated Group model
+ class Group < ::Gitlab::BackgroundMigration::UserMentions::Models::Namespace
+ self.store_full_sti_class = false
+ has_one :saml_provider
+
+ def self.declarative_policy_class
+ "GroupPolicy"
+ end
+
+ def max_member_access_for_user(user)
+ return GroupMember::NO_ACCESS unless user
+
+ return GroupMember::OWNER if user.admin?
+
+ max_member_access = members_with_parents.where(user_id: user)
+ .reorder(access_level: :desc)
+ .first
+ &.access_level
+
+ max_member_access || GroupMember::NO_ACCESS
+ end
+
+ def members_with_parents
+ # Avoids an unnecessary SELECT when the group has no parents
+ source_ids =
+ if has_parent?
+ self_and_ancestors.reorder(nil).select(:id)
+ else
+ id
+ end
+
+ group_hierarchy_members = GroupMember.active_without_invites_and_requests
+ .where(source_id: source_ids)
+
+ GroupMember.from_union([group_hierarchy_members,
+ members_from_self_and_ancestor_group_shares])
+ end
+
+ # rubocop: disable Metrics/AbcSize
+ def members_from_self_and_ancestor_group_shares
+ group_group_link_table = GroupGroupLink.arel_table
+ group_member_table = GroupMember.arel_table
+
+ source_ids =
+ if has_parent?
+ self_and_ancestors.reorder(nil).select(:id)
+ else
+ id
+ end
+
+ group_group_links_query = GroupGroupLink.where(shared_group_id: source_ids)
+ cte = Gitlab::SQL::CTE.new(:group_group_links_cte, group_group_links_query)
+ cte_alias = cte.table.alias(GroupGroupLink.table_name)
+
+ # Instead of members.access_level, we need to maximize that access_level at
+ # the respective group_group_links.group_access.
+ member_columns = GroupMember.attribute_names.map do |column_name|
+ if column_name == 'access_level'
+ smallest_value_arel([cte_alias[:group_access], group_member_table[:access_level]],
+ 'access_level')
+ else
+ group_member_table[column_name]
+ end
+ end
+
+ GroupMember
+ .with(cte.to_arel)
+ .select(*member_columns)
+ .from([group_member_table, cte.alias_to(group_group_link_table)])
+ .where(group_member_table[:requested_at].eq(nil))
+ .where(group_member_table[:source_id].eq(group_group_link_table[:shared_with_group_id]))
+ .where(group_member_table[:source_type].eq('Namespace'))
+ end
+ # rubocop: enable Metrics/AbcSize
+
+ def smallest_value_arel(args, column_alias)
+ Arel::Nodes::As.new(
+ Arel::Nodes::NamedFunction.new('LEAST', args),
+ Arel::Nodes::SqlLiteral.new(column_alias))
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/background_migration/user_mentions/models/namespace.rb b/lib/gitlab/background_migration/user_mentions/models/namespace.rb
new file mode 100644
index 00000000000..6d7b9a86e69
--- /dev/null
+++ b/lib/gitlab/background_migration/user_mentions/models/namespace.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module BackgroundMigration
+ module UserMentions
+ module Models
+ # isolated Namespace model
+ class Namespace < ApplicationRecord
+ include ::Gitlab::VisibilityLevel
+ include ::Gitlab::Utils::StrongMemoize
+ include Gitlab::BackgroundMigration::UserMentions::Models::Concerns::Namespace::RecursiveTraversal
+
+ belongs_to :parent, class_name: "::Gitlab::BackgroundMigration::UserMentions::Models::Namespace"
+
+ def visibility_level_field
+ :visibility_level
+ end
+
+ def has_parent?
+ parent_id.present? || parent.present?
+ end
+
+ # Overridden in EE::Namespace
+ def feature_available?(_feature)
+ false
+ end
+ end
+ end
+ end
+ end
+end
+
+Namespace.prepend_if_ee('::EE::Namespace')
diff --git a/lib/gitlab/bulk_import/client.rb b/lib/gitlab/bulk_import/client.rb
new file mode 100644
index 00000000000..c6e77a158cd
--- /dev/null
+++ b/lib/gitlab/bulk_import/client.rb
@@ -0,0 +1,72 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module BulkImport
+ class Client
+ API_VERSION = 'v4'.freeze
+ DEFAULT_PAGE = 1.freeze
+ DEFAULT_PER_PAGE = 30.freeze
+
+ ConnectionError = Class.new(StandardError)
+
+ def initialize(uri:, token:, page: DEFAULT_PAGE, per_page: DEFAULT_PER_PAGE, api_version: API_VERSION)
+ @uri = URI.parse(uri)
+ @token = token&.strip
+ @page = page
+ @per_page = per_page
+ @api_version = api_version
+ end
+
+ def get(resource, query = {})
+ response = with_error_handling do
+ Gitlab::HTTP.get(
+ resource_url(resource),
+ headers: request_headers,
+ follow_redirects: false,
+ query: query.merge(request_query)
+ )
+ end
+
+ response.parsed_response
+ end
+
+ private
+
+ def request_query
+ {
+ page: @page,
+ per_page: @per_page
+ }
+ end
+
+ def request_headers
+ {
+ 'Content-Type' => 'application/json',
+ 'Authorization' => "Bearer #{@token}"
+ }
+ end
+
+ def with_error_handling
+ response = yield
+
+ raise ConnectionError.new("Error #{response.code}") unless response.success?
+
+ response
+ rescue *Gitlab::HTTP::HTTP_ERRORS => e
+ raise ConnectionError, e
+ end
+
+ def base_uri
+ @base_uri ||= "#{@uri.scheme}://#{@uri.host}:#{@uri.port}"
+ end
+
+ def api_url
+ Gitlab::Utils.append_path(base_uri, "/api/#{@api_version}")
+ end
+
+ def resource_url(resource)
+ Gitlab::Utils.append_path(api_url, resource)
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/checks/matching_merge_request.rb b/lib/gitlab/checks/matching_merge_request.rb
index 71361b12d07..db7af0088d0 100644
--- a/lib/gitlab/checks/matching_merge_request.rb
+++ b/lib/gitlab/checks/matching_merge_request.rb
@@ -20,3 +20,5 @@ module Gitlab
end
end
end
+
+Gitlab::Checks::MatchingMergeRequest.prepend_if_ee('EE::Gitlab::Checks::MatchingMergeRequest')
diff --git a/lib/gitlab/checks/post_push_message.rb b/lib/gitlab/checks/post_push_message.rb
index b3c981d252b..0d93e7ac8a1 100644
--- a/lib/gitlab/checks/post_push_message.rb
+++ b/lib/gitlab/checks/post_push_message.rb
@@ -44,11 +44,7 @@ module Gitlab
end
def url_to_repo
- protocol == 'ssh' ? message_subject.ssh_url_to_repo : message_subject.http_url_to_repo
- end
-
- def message_subject
- repository.repo_type.wiki? ? project.wiki : container
+ protocol == 'ssh' ? container.ssh_url_to_repo : container.http_url_to_repo
end
end
end
diff --git a/lib/gitlab/ci/ansi2json/converter.rb b/lib/gitlab/ci/ansi2json/converter.rb
index 0373a12ab69..6d152c052dc 100644
--- a/lib/gitlab/ci/ansi2json/converter.rb
+++ b/lib/gitlab/ci/ansi2json/converter.rb
@@ -104,23 +104,24 @@ module Gitlab
action = scanner[1]
timestamp = scanner[2]
section = scanner[3]
+ options = parse_section_options(scanner[4])
section_name = sanitize_section_name(section)
- if action == "start"
- handle_section_start(scanner, section_name, timestamp)
- elsif action == "end"
+ if action == 'start'
+ handle_section_start(scanner, section_name, timestamp, options)
+ elsif action == 'end'
handle_section_end(scanner, section_name, timestamp)
else
raise 'unsupported action'
end
end
- def handle_section_start(scanner, section, timestamp)
+ def handle_section_start(scanner, section, timestamp, options)
# We make a new line for new section
flush_current_line
- @state.open_section(section, timestamp)
+ @state.open_section(section, timestamp, options)
# we need to consume match after handling
# the open of section, as we want the section
@@ -157,6 +158,18 @@ module Gitlab
def sanitize_section_name(section)
section.to_s.downcase.gsub(/[^a-z0-9]/, '-')
end
+
+ def parse_section_options(raw_options)
+ return unless raw_options
+
+ # We need to remove the square brackets and split
+ # by comma to get a list of the options
+ options = raw_options[1...-1].split ','
+
+ # Now split each option by equals to separate
+ # each in the format [key, value]
+ options.to_h { |option| option.split '=' }
+ end
end
end
end
diff --git a/lib/gitlab/ci/ansi2json/line.rb b/lib/gitlab/ci/ansi2json/line.rb
index 21aa1f84353..b1dee0e1ecc 100644
--- a/lib/gitlab/ci/ansi2json/line.rb
+++ b/lib/gitlab/ci/ansi2json/line.rb
@@ -32,7 +32,7 @@ module Gitlab
end
attr_reader :offset, :sections, :segments, :current_segment,
- :section_header, :section_duration
+ :section_header, :section_duration, :section_options
def initialize(offset:, style:, sections: [])
@offset = offset
@@ -68,6 +68,10 @@ module Gitlab
@sections << section
end
+ def set_section_options(options)
+ @section_options = options
+ end
+
def set_as_section_header
@section_header = true
end
@@ -90,6 +94,7 @@ module Gitlab
result[:section] = sections.last if sections.any?
result[:section_header] = true if @section_header
result[:section_duration] = @section_duration if @section_duration
+ result[:section_options] = @section_options if @section_options
end
end
end
diff --git a/lib/gitlab/ci/ansi2json/state.rb b/lib/gitlab/ci/ansi2json/state.rb
index 38d36e6950c..b2b6ce649ed 100644
--- a/lib/gitlab/ci/ansi2json/state.rb
+++ b/lib/gitlab/ci/ansi2json/state.rb
@@ -26,10 +26,11 @@ module Gitlab
Base64.urlsafe_encode64(state.to_json)
end
- def open_section(section, timestamp)
+ def open_section(section, timestamp, options)
@open_sections[section] = timestamp
@current_line.add_section(section)
+ @current_line.set_section_options(options)
@current_line.set_as_section_header
end
diff --git a/lib/gitlab/ci/artifact_file_reader.rb b/lib/gitlab/ci/artifact_file_reader.rb
index 6395a20ca99..b0fad026ec5 100644
--- a/lib/gitlab/ci/artifact_file_reader.rb
+++ b/lib/gitlab/ci/artifact_file_reader.rb
@@ -45,14 +45,6 @@ module Gitlab
end
def read_zip_file!(file_path)
- if ::Gitlab::Ci::Features.new_artifact_file_reader_enabled?(job.project)
- read_with_new_artifact_file_reader(file_path)
- else
- read_with_legacy_artifact_file_reader(file_path)
- end
- end
-
- def read_with_new_artifact_file_reader(file_path)
job.artifacts_file.use_open_file do |file|
zip_file = Zip::File.new(file, false, true)
entry = zip_file.find_entry(file_path)
@@ -69,25 +61,6 @@ module Gitlab
end
end
- def read_with_legacy_artifact_file_reader(file_path)
- job.artifacts_file.use_file do |archive_path|
- Zip::File.open(archive_path) do |zip_file|
- entry = zip_file.find_entry(file_path)
- unless entry
- raise Error, "Path `#{file_path}` does not exist inside the `#{job.name}` artifacts archive!"
- end
-
- if entry.name_is_directory?
- raise Error, "Path `#{file_path}` was expected to be a file but it was a directory!"
- end
-
- zip_file.get_input_stream(entry) do |is|
- is.read
- end
- end
- end
- end
-
def max_archive_size_in_mb
ActiveSupport::NumberHelper.number_to_human_size(MAX_ARCHIVE_SIZE)
end
diff --git a/lib/gitlab/ci/config.rb b/lib/gitlab/ci/config.rb
index 9d269831679..071a8ef830f 100644
--- a/lib/gitlab/ci/config.rb
+++ b/lib/gitlab/ci/config.rb
@@ -54,6 +54,10 @@ module Gitlab
root.variables_value
end
+ def variables_with_data
+ root.variables_entry.value_with_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 a8b67a1db4f..1740032e5c7 100644
--- a/lib/gitlab/ci/config/entry/bridge.rb
+++ b/lib/gitlab/ci/config/entry/bridge.rb
@@ -11,15 +11,18 @@ module Gitlab
class Bridge < ::Gitlab::Config::Entry::Node
include ::Gitlab::Ci::Config::Entry::Processable
+ ALLOWED_WHEN = %w[on_success on_failure always manual].freeze
ALLOWED_KEYS = %i[trigger].freeze
validations do
validates :config, allowed_keys: ALLOWED_KEYS + PROCESSABLE_ALLOWED_KEYS
with_options allow_nil: true do
- validates :when,
- inclusion: { in: %w[on_success on_failure always],
- message: 'should be on_success, on_failure or always' }
+ validates :allow_failure, boolean: true
+ validates :when, inclusion: {
+ in: ALLOWED_WHEN,
+ message: "should be one of: #{ALLOWED_WHEN.join(', ')}"
+ }
end
validate on: :composed do
@@ -57,11 +60,19 @@ module Gitlab
true
end
+ def manual_action?
+ self.when == 'manual'
+ end
+
+ def ignored?
+ allow_failure.nil? ? manual_action? : allow_failure
+ end
+
def value
super.merge(
trigger: (trigger_value if trigger_defined?),
needs: (needs_value if needs_defined?),
- ignore: !!allow_failure,
+ ignore: ignored?,
when: self.when,
scheduling_type: needs_defined? && !bridge_needs ? :dag : :stage
).compact
diff --git a/lib/gitlab/ci/config/entry/cache.rb b/lib/gitlab/ci/config/entry/cache.rb
index a304d9b724f..6b036182706 100644
--- a/lib/gitlab/ci/config/entry/cache.rb
+++ b/lib/gitlab/ci/config/entry/cache.rb
@@ -9,14 +9,28 @@ module Gitlab
#
class Cache < ::Gitlab::Config::Entry::Node
include ::Gitlab::Config::Entry::Configurable
+ include ::Gitlab::Config::Entry::Validatable
include ::Gitlab::Config::Entry::Attributable
- ALLOWED_KEYS = %i[key untracked paths policy].freeze
+ ALLOWED_KEYS = %i[key untracked paths when policy].freeze
+ ALLOWED_POLICY = %w[pull-push push pull].freeze
DEFAULT_POLICY = 'pull-push'
+ ALLOWED_WHEN = %w[on_success on_failure always].freeze
+ DEFAULT_WHEN = 'on_success'
validations do
- validates :config, allowed_keys: ALLOWED_KEYS
- validates :policy, inclusion: { in: %w[pull-push push pull], message: 'should be pull-push, push, or pull' }, allow_blank: true
+ validates :config, type: Hash, allowed_keys: ALLOWED_KEYS
+ validates :policy,
+ inclusion: { in: ALLOWED_POLICY, message: 'should be pull-push, push, or pull' },
+ allow_blank: true
+
+ with_options allow_nil: true do
+ validates :when,
+ inclusion: {
+ in: ALLOWED_WHEN,
+ message: 'should be on_success, on_failure or always'
+ }
+ end
end
entry :key, Entry::Key,
@@ -28,13 +42,15 @@ module Gitlab
entry :paths, Entry::Paths,
description: 'Specify which paths should be cached across builds.'
- attributes :policy
+ attributes :policy, :when
def value
result = super
result[:key] = key_value
result[:policy] = policy || DEFAULT_POLICY
+ # Use self.when to avoid conflict with reserved word
+ result[:when] = self.when || DEFAULT_WHEN
result
end
diff --git a/lib/gitlab/ci/config/entry/include.rb b/lib/gitlab/ci/config/entry/include.rb
index 9c2e5f641d0..ad0ed00aa6f 100644
--- a/lib/gitlab/ci/config/entry/include.rb
+++ b/lib/gitlab/ci/config/entry/include.rb
@@ -10,7 +10,7 @@ module Gitlab
class Include < ::Gitlab::Config::Entry::Node
include ::Gitlab::Config::Entry::Validatable
- ALLOWED_KEYS = %i[local file remote template artifact job].freeze
+ ALLOWED_KEYS = %i[local file remote template artifact job project ref].freeze
validations do
validates :config, hash_or_string: true
@@ -22,6 +22,10 @@ module Gitlab
if config[:artifact] && config[:job].blank?
errors.add(:config, "must specify the job where to fetch the artifact from")
end
+
+ if config[:project] && config[:file].blank?
+ errors.add(:config, "must specify the file where to fetch the config from")
+ end
end
end
end
diff --git a/lib/gitlab/ci/config/entry/jobs.rb b/lib/gitlab/ci/config/entry/jobs.rb
index b5ce42969a5..b0fd9cef10b 100644
--- a/lib/gitlab/ci/config/entry/jobs.rb
+++ b/lib/gitlab/ci/config/entry/jobs.rb
@@ -7,7 +7,7 @@ module Gitlab
##
# Entry that represents a set of jobs.
#
- class Jobs < ::Gitlab::Config::Entry::Node
+ class Jobs < ::Gitlab::Config::Entry::ComposableHash
include ::Gitlab::Config::Entry::Validatable
validations do
@@ -36,6 +36,10 @@ module Gitlab
end
end
+ def composable_class(name, config)
+ self.class.find_type(name, config)
+ end
+
TYPES = [Entry::Hidden, Entry::Job, Entry::Bridge].freeze
private_constant :TYPES
@@ -49,29 +53,6 @@ module Gitlab
type.matching?(name, config)
end
end
-
- # rubocop: disable CodeReuse/ActiveRecord
- def compose!(deps = nil)
- super do
- @config.each do |name, config|
- node = self.class.find_type(name, config)
- next unless node
-
- factory = ::Gitlab::Config::Entry::Factory.new(node)
- .value(config || {})
- .metadata(name: name)
- .with(key: name, parent: self,
- description: "#{name} job definition.")
-
- @entries[name] = factory.create!
- end
-
- @entries.each_value do |entry|
- entry.compose!(deps)
- end
- end
- end
- # rubocop: enable CodeReuse/ActiveRecord
end
end
end
diff --git a/lib/gitlab/ci/config/entry/needs.rb b/lib/gitlab/ci/config/entry/needs.rb
index d7ba8624882..66cd57b8cf3 100644
--- a/lib/gitlab/ci/config/entry/needs.rb
+++ b/lib/gitlab/ci/config/entry/needs.rb
@@ -7,7 +7,7 @@ module Gitlab
##
# Entry that represents a set of needs dependencies.
#
- class Needs < ::Gitlab::Config::Entry::Node
+ class Needs < ::Gitlab::Config::Entry::ComposableArray
include ::Gitlab::Config::Entry::Validatable
validations do
@@ -29,27 +29,16 @@ module Gitlab
end
end
- def compose!(deps = nil)
- super(deps) do
- [@config].flatten.each_with_index do |need, index|
- @entries[index] = ::Gitlab::Config::Entry::Factory.new(Entry::Need)
- .value(need)
- .with(key: "need", parent: self, description: "need definition.") # rubocop:disable CodeReuse/ActiveRecord
- .create!
- end
-
- @entries.each_value do |entry|
- entry.compose!(deps)
- end
- end
- end
-
def value
- values = @entries.values.select(&:type)
+ values = @entries.select(&:type)
values.group_by(&:type).transform_values do |values|
values.map(&:value)
end
end
+
+ def composable_class
+ Entry::Need
+ end
end
end
end
diff --git a/lib/gitlab/ci/config/entry/ports.rb b/lib/gitlab/ci/config/entry/ports.rb
index 01ffcc7dd87..d26b31deca8 100644
--- a/lib/gitlab/ci/config/entry/ports.rb
+++ b/lib/gitlab/ci/config/entry/ports.rb
@@ -7,7 +7,7 @@ module Gitlab
##
# Entry that represents a configuration of the ports of a Docker service.
#
- class Ports < ::Gitlab::Config::Entry::Node
+ class Ports < ::Gitlab::Config::Entry::ComposableArray
include ::Gitlab::Config::Entry::Validatable
validations do
@@ -16,28 +16,8 @@ module Gitlab
validates :config, port_unique: true
end
- def compose!(deps = nil)
- super do
- @entries = []
- @config.each do |config|
- @entries << ::Gitlab::Config::Entry::Factory.new(Entry::Port)
- .value(config || {})
- .with(key: "port", parent: self, description: "port definition.") # rubocop:disable CodeReuse/ActiveRecord
- .create!
- end
-
- @entries.each do |entry|
- entry.compose!(deps)
- end
- end
- end
-
- def value
- @entries.map(&:value)
- end
-
- def descendants
- @entries
+ def composable_class
+ Entry::Port
end
end
end
diff --git a/lib/gitlab/ci/config/entry/product/matrix.rb b/lib/gitlab/ci/config/entry/product/matrix.rb
index 6af809d46c1..d4ee0978e1b 100644
--- a/lib/gitlab/ci/config/entry/product/matrix.rb
+++ b/lib/gitlab/ci/config/entry/product/matrix.rb
@@ -46,13 +46,11 @@ module Gitlab
end
end
- # rubocop:disable CodeReuse/ActiveRecord
def number_of_generated_jobs
value.sum do |config|
config.values.reduce(1) { |acc, values| acc * values.size }
end
end
- # rubocop:enable CodeReuse/ActiveRecord
end
end
end
diff --git a/lib/gitlab/ci/config/entry/product/variables.rb b/lib/gitlab/ci/config/entry/product/variables.rb
index ac4f70fb69e..2481989060e 100644
--- a/lib/gitlab/ci/config/entry/product/variables.rb
+++ b/lib/gitlab/ci/config/entry/product/variables.rb
@@ -14,7 +14,7 @@ module Gitlab
validations do
validates :config, variables: { array_values: true }
validates :config, length: {
- minimum: 2,
+ minimum: :minimum,
too_short: 'requires at least %{count} items'
}
end
@@ -28,6 +28,10 @@ module Gitlab
.map { |key, value| [key.to_s, Array(value).map(&:to_s)] }
.to_h
end
+
+ def minimum
+ ::Gitlab::Ci::Features.one_dimensional_matrix_enabled? ? 1 : 2
+ end
end
end
end
diff --git a/lib/gitlab/ci/config/entry/reports.rb b/lib/gitlab/ci/config/entry/reports.rb
index 0ae65f43723..f2fd8ac7fd9 100644
--- a/lib/gitlab/ci/config/entry/reports.rb
+++ b/lib/gitlab/ci/config/entry/reports.rb
@@ -15,7 +15,7 @@ module Gitlab
%i[junit codequality sast secret_detection dependency_scanning container_scanning
dast performance browser_performance load_performance license_management license_scanning metrics lsif
dotenv cobertura terraform accessibility cluster_applications
- requirements coverage_fuzzing].freeze
+ requirements coverage_fuzzing api_fuzzing].freeze
attributes ALLOWED_KEYS
@@ -25,6 +25,7 @@ module Gitlab
with_options allow_nil: true do
validates :junit, array_of_strings_or_string: true
+ validates :api_fuzzing, array_of_strings_or_string: true
validates :coverage_fuzzing, array_of_strings_or_string: true
validates :sast, array_of_strings_or_string: true
validates :sast, array_of_strings_or_string: true
diff --git a/lib/gitlab/ci/config/entry/rules.rb b/lib/gitlab/ci/config/entry/rules.rb
index 2fbc3d9e367..bf74f995e80 100644
--- a/lib/gitlab/ci/config/entry/rules.rb
+++ b/lib/gitlab/ci/config/entry/rules.rb
@@ -4,7 +4,7 @@ module Gitlab
module Ci
class Config
module Entry
- class Rules < ::Gitlab::Config::Entry::Node
+ class Rules < ::Gitlab::Config::Entry::ComposableArray
include ::Gitlab::Config::Entry::Validatable
validations do
@@ -12,24 +12,13 @@ module Gitlab
validates :config, type: Array
end
- def compose!(deps = nil)
- super(deps) do
- @config.each_with_index do |rule, index|
- @entries[index] = ::Gitlab::Config::Entry::Factory.new(Entry::Rules::Rule)
- .value(rule)
- .with(key: "rule", parent: self, description: "rule definition.") # rubocop:disable CodeReuse/ActiveRecord
- .create!
- end
-
- @entries.each_value do |entry|
- entry.compose!(deps)
- end
- end
- end
-
def value
@config
end
+
+ def composable_class
+ Entry::Rules::Rule
+ end
end
end
end
diff --git a/lib/gitlab/ci/config/entry/services.rb b/lib/gitlab/ci/config/entry/services.rb
index 83baa83711f..44e2903a300 100644
--- a/lib/gitlab/ci/config/entry/services.rb
+++ b/lib/gitlab/ci/config/entry/services.rb
@@ -7,7 +7,7 @@ module Gitlab
##
# Entry that represents a configuration of Docker services.
#
- class Services < ::Gitlab::Config::Entry::Node
+ class Services < ::Gitlab::Config::Entry::ComposableArray
include ::Gitlab::Config::Entry::Validatable
validations do
@@ -15,28 +15,8 @@ module Gitlab
validates :config, services_with_ports_alias_unique: true, if: ->(record) { record.opt(:with_image_ports) }
end
- def compose!(deps = nil)
- super do
- @entries = []
- @config.each do |config|
- @entries << ::Gitlab::Config::Entry::Factory.new(Entry::Service)
- .value(config || {})
- .with(key: "service", parent: self, description: "service definition.") # rubocop:disable CodeReuse/ActiveRecord
- .create!
- end
-
- @entries.each do |entry|
- entry.compose!(deps)
- end
- end
- end
-
- def value
- @entries.map(&:value)
- end
-
- def descendants
- @entries
+ def composable_class
+ Entry::Service
end
end
end
diff --git a/lib/gitlab/ci/config/entry/variables.rb b/lib/gitlab/ci/config/entry/variables.rb
index c9d0c7cb568..e258f7128fc 100644
--- a/lib/gitlab/ci/config/entry/variables.rb
+++ b/lib/gitlab/ci/config/entry/variables.rb
@@ -10,16 +10,32 @@ module Gitlab
class Variables < ::Gitlab::Config::Entry::Node
include ::Gitlab::Config::Entry::Validatable
+ ALLOWED_VALUE_DATA = %i[value description].freeze
+
validations do
- validates :config, variables: true
+ validates :config, variables: { allowed_value_data: ALLOWED_VALUE_DATA }
+ end
+
+ def value
+ Hash[@config.map { |key, value| [key.to_s, expand_value(value)[:value]] }]
end
def self.default(**)
{}
end
- def value
- Hash[@config.map { |key, value| [key.to_s, value.to_s] }]
+ def value_with_data
+ Hash[@config.map { |key, value| [key.to_s, expand_value(value)] }]
+ end
+
+ private
+
+ def expand_value(value)
+ if value.is_a?(Hash)
+ { value: value[:value].to_s, description: value[:description] }
+ else
+ { value: value.to_s, description: nil }
+ end
end
end
end
diff --git a/lib/gitlab/ci/features.rb b/lib/gitlab/ci/features.rb
index e770187b124..1b58e3ec71a 100644
--- a/lib/gitlab/ci/features.rb
+++ b/lib/gitlab/ci/features.rb
@@ -10,10 +10,6 @@ module Gitlab
::Feature.enabled?(:ci_artifacts_exclude, default_enabled: true)
end
- def self.job_heartbeats_runner?(project)
- ::Feature.enabled?(:ci_job_heartbeats_runner, project, default_enabled: true)
- end
-
def self.instance_variables_ui_enabled?
::Feature.enabled?(:ci_instance_variables_ui, default_enabled: true)
end
@@ -35,10 +31,6 @@ module Gitlab
::Feature.enabled?(:ci_raise_job_rules_without_workflow_rules_warning, default_enabled: true)
end
- def self.bulk_insert_on_create?(project)
- ::Feature.enabled?(:ci_bulk_insert_on_create, project, default_enabled: true)
- end
-
# NOTE: The feature flag `disallow_to_create_merge_request_pipelines_in_target_project`
# is a safe switch to disable the feature for a parituclar project when something went wrong,
# therefore it's not supposed to be enabled by default.
@@ -54,25 +46,25 @@ module Gitlab
Feature.enabled?(:project_transactionless_destroy, project, default_enabled: false)
end
- def self.coverage_report_view?(project)
- ::Feature.enabled?(:coverage_report_view, project, default_enabled: true)
- end
-
- def self.child_of_child_pipeline_enabled?(project)
- ::Feature.enabled?(:ci_child_of_child_pipeline, project, default_enabled: true)
- end
-
def self.trace_overwrite?
::Feature.enabled?(:ci_trace_overwrite, type: :ops, default_enabled: false)
end
def self.accept_trace?(project)
::Feature.enabled?(:ci_enable_live_trace, project) &&
- ::Feature.enabled?(:ci_accept_trace, project, type: :ops, default_enabled: false)
+ ::Feature.enabled?(:ci_accept_trace, project, type: :ops, default_enabled: true)
+ end
+
+ def self.log_invalid_trace_chunks?(project)
+ ::Feature.enabled?(:ci_trace_log_invalid_chunks, project, type: :ops, default_enabled: false)
+ end
+
+ def self.one_dimensional_matrix_enabled?
+ ::Feature.enabled?(:one_dimensional_matrix, default_enabled: true)
end
- def self.new_artifact_file_reader_enabled?(project)
- ::Feature.enabled?(:ci_new_artifact_file_reader, project, default_enabled: false)
+ def self.manual_bridges_enabled?(project)
+ ::Feature.enabled?(:ci_manual_bridges, project, default_enabled: true)
end
end
end
diff --git a/lib/gitlab/ci/lint.rb b/lib/gitlab/ci/lint.rb
index 86a9ebfa451..44f2ac23ce3 100644
--- a/lib/gitlab/ci/lint.rb
+++ b/lib/gitlab/ci/lint.rb
@@ -4,10 +4,11 @@ module Gitlab
module Ci
class Lint
class Result
- attr_reader :jobs, :errors, :warnings
+ attr_reader :jobs, :merged_yaml, :errors, :warnings
- def initialize(jobs:, errors:, warnings:)
+ def initialize(jobs:, merged_yaml:, errors:, warnings:)
@jobs = jobs
+ @merged_yaml = merged_yaml
@errors = errors
@warnings = warnings
end
@@ -39,6 +40,7 @@ module Gitlab
Result.new(
jobs: dry_run_convert_to_jobs(pipeline.stages),
+ merged_yaml: pipeline.merged_yaml,
errors: pipeline.error_messages.map(&:content),
warnings: pipeline.warning_messages(limit: ::Gitlab::Ci::Warnings::MAX_LIMIT).map(&:content)
)
@@ -54,6 +56,7 @@ module Gitlab
Result.new(
jobs: static_validation_convert_to_jobs(result),
+ merged_yaml: result.merged_yaml,
errors: result.errors,
warnings: result.warnings.take(::Gitlab::Ci::Warnings::MAX_LIMIT) # rubocop: disable CodeReuse/ActiveRecord
)
diff --git a/lib/gitlab/ci/parsers/test/junit.rb b/lib/gitlab/ci/parsers/test/junit.rb
index 5746f38ae5b..50cd703da4a 100644
--- a/lib/gitlab/ci/parsers/test/junit.rb
+++ b/lib/gitlab/ci/parsers/test/junit.rb
@@ -8,12 +8,17 @@ module Gitlab
JunitParserError = Class.new(Gitlab::Ci::Parsers::ParserError)
ATTACHMENT_TAG_REGEX = /\[\[ATTACHMENT\|(?<path>.+?)\]\]/.freeze
- def parse!(xml_data, test_suite, **args)
+ def parse!(xml_data, test_suite, job:)
root = Hash.from_xml(xml_data)
+ total_parsed = 0
+ max_test_cases = job.max_test_cases_per_report
all_cases(root) do |test_case|
- test_case = create_test_case(test_case, args)
+ test_case = create_test_case(test_case, test_suite, job)
test_suite.add_test_case(test_case)
+ total_parsed += 1
+
+ ensure_test_cases_limited!(total_parsed, max_test_cases)
end
rescue Nokogiri::XML::SyntaxError => e
test_suite.set_suite_error("JUnit XML parsing failed: #{e}")
@@ -23,6 +28,12 @@ module Gitlab
private
+ def ensure_test_cases_limited!(total_parsed, limit)
+ return unless limit > 0 && total_parsed > limit
+
+ raise JunitParserError.new("number of test cases exceeded the limit of #{limit}")
+ end
+
def all_cases(root, parent = nil, &blk)
return unless root.present?
@@ -33,20 +44,24 @@ module Gitlab
all_cases(node['testsuites'], root, &blk) unless parent
# we require at least one level of testsuites or testsuite
- each_case(node['testcase'], &blk) if parent
+ each_case(node['testcase'], node['name'], &blk) if parent
# we allow multiple nested 'testsuite' (eg. PHPUnit)
all_cases(node['testsuite'], root, &blk)
end
end
- def each_case(testcase, &blk)
+ def each_case(testcase, testsuite_name, &blk)
return unless testcase.present?
- [testcase].flatten.compact.map(&blk)
+ [testcase].flatten.compact.each do |tc|
+ tc['suite_name'] = testsuite_name
+
+ yield(tc)
+ end
end
- def create_test_case(data, args)
+ def create_test_case(data, test_suite, job)
if data.key?('failure')
status = ::Gitlab::Ci::Reports::TestCase::STATUS_FAILED
system_output = data['failure']
@@ -63,6 +78,7 @@ module Gitlab
end
::Gitlab::Ci::Reports::TestCase.new(
+ suite_name: data['suite_name'] || test_suite.name,
classname: data['classname'],
name: data['name'],
file: data['file'],
@@ -70,10 +86,14 @@ module Gitlab
status: status,
system_output: system_output,
attachment: attachment,
- job: args.fetch(:job)
+ job: job
)
end
+ def suite_name(parent, test_suite)
+ parent.dig('testsuite', 'name') || test_suite.name
+ end
+
def attachment_path(data)
return unless data
diff --git a/lib/gitlab/ci/pipeline/chain/command.rb b/lib/gitlab/ci/pipeline/chain/command.rb
index d1882059dd8..06096a33f27 100644
--- a/lib/gitlab/ci/pipeline/chain/command.rb
+++ b/lib/gitlab/ci/pipeline/chain/command.rb
@@ -16,7 +16,7 @@ module Gitlab
) do
include Gitlab::Utils::StrongMemoize
- def initialize(**params)
+ def initialize(params = {})
params.each do |key, value|
self[key] = value
end
diff --git a/lib/gitlab/ci/pipeline/chain/config/process.rb b/lib/gitlab/ci/pipeline/chain/config/process.rb
index 8ccb33ffd34..c3fbd0c9e24 100644
--- a/lib/gitlab/ci/pipeline/chain/config/process.rb
+++ b/lib/gitlab/ci/pipeline/chain/config/process.rb
@@ -28,6 +28,8 @@ module Gitlab
error(result.errors.first, config_error: true)
end
+ @pipeline.merged_yaml = result.merged_yaml
+
rescue => ex
Gitlab::ErrorTracking.track_exception(ex,
project_id: project.id,
diff --git a/lib/gitlab/ci/pipeline/chain/create.rb b/lib/gitlab/ci/pipeline/chain/create.rb
index 34649fe16f3..81ef3bb074d 100644
--- a/lib/gitlab/ci/pipeline/chain/create.rb
+++ b/lib/gitlab/ci/pipeline/chain/create.rb
@@ -8,7 +8,7 @@ module Gitlab
include Chain::Helpers
def perform!
- BulkInsertableAssociations.with_bulk_insert(enabled: ::Gitlab::Ci::Features.bulk_insert_on_create?(project)) do
+ BulkInsertableAssociations.with_bulk_insert do
pipeline.save!
end
rescue ActiveRecord::RecordInvalid => e
diff --git a/lib/gitlab/ci/pipeline/seed/build/cache.rb b/lib/gitlab/ci/pipeline/seed/build/cache.rb
index a4127ea0be2..8d6fe13c3b9 100644
--- a/lib/gitlab/ci/pipeline/seed/build/cache.rb
+++ b/lib/gitlab/ci/pipeline/seed/build/cache.rb
@@ -13,6 +13,7 @@ module Gitlab
@paths = local_cache.delete(:paths)
@policy = local_cache.delete(:policy)
@untracked = local_cache.delete(:untracked)
+ @when = local_cache.delete(:when)
raise ArgumentError, "unknown cache keys: #{local_cache.keys}" if local_cache.any?
end
@@ -24,7 +25,8 @@ module Gitlab
key: key_string,
paths: @paths,
policy: @policy,
- untracked: @untracked
+ untracked: @untracked,
+ when: @when
}.compact.presence
}.compact
}
diff --git a/lib/gitlab/ci/reports/test_case.rb b/lib/gitlab/ci/reports/test_case.rb
index 15a3c862c9e..8c70dbb6931 100644
--- a/lib/gitlab/ci/reports/test_case.rb
+++ b/lib/gitlab/ci/reports/test_case.rb
@@ -10,9 +10,10 @@ module Gitlab
STATUS_ERROR = 'error'
STATUS_TYPES = [STATUS_ERROR, STATUS_FAILED, STATUS_SUCCESS, STATUS_SKIPPED].freeze
- attr_reader :name, :classname, :execution_time, :status, :file, :system_output, :stack_trace, :key, :attachment, :job
+ attr_reader :suite_name, :name, :classname, :execution_time, :status, :file, :system_output, :stack_trace, :key, :attachment, :job
def initialize(params)
+ @suite_name = params.fetch(:suite_name)
@name = params.fetch(:name)
@classname = params.fetch(:classname)
@file = params.fetch(:file, nil)
@@ -23,7 +24,7 @@ module Gitlab
@attachment = params.fetch(:attachment, nil)
@job = params.fetch(:job, nil)
- @key = sanitize_key_name("#{classname}_#{name}")
+ @key = hash_key("#{suite_name}_#{classname}_#{name}")
end
def has_attachment?
@@ -42,8 +43,8 @@ module Gitlab
private
- def sanitize_key_name(key)
- key.gsub(/[^0-9A-Za-z]/, '-')
+ def hash_key(key)
+ Digest::SHA256.hexdigest(key)
end
end
end
diff --git a/lib/gitlab/ci/reports/test_suite.rb b/lib/gitlab/ci/reports/test_suite.rb
index e9b78b841e4..00920dfbd54 100644
--- a/lib/gitlab/ci/reports/test_suite.rb
+++ b/lib/gitlab/ci/reports/test_suite.rb
@@ -12,18 +12,24 @@ module Gitlab
def initialize(name = nil)
@name = name
@test_cases = {}
+ @all_test_cases = []
@total_time = 0.0
- @duplicate_cases = []
end
def add_test_case(test_case)
- @duplicate_cases << test_case if existing_key?(test_case)
-
@test_cases[test_case.status] ||= {}
@test_cases[test_case.status][test_case.key] = test_case
@total_time += test_case.execution_time
end
+ def each_test_case
+ @test_cases.each do |status, test_cases|
+ test_cases.values.each do |test_case|
+ yield test_case
+ end
+ end
+ end
+
# rubocop: disable CodeReuse/ActiveRecord
def total_count
return 0 if suite_error
@@ -86,10 +92,6 @@ module Gitlab
private
- def existing_key?(test_case)
- @test_cases[test_case.status]&.key?(test_case.key)
- end
-
def sort_by_status
@test_cases = @test_cases.sort_by { |status, _| Gitlab::Ci::Reports::TestCase::STATUS_TYPES.index(status) }.to_h
end
diff --git a/lib/gitlab/ci/runner/backoff.rb b/lib/gitlab/ci/runner/backoff.rb
new file mode 100644
index 00000000000..95d7719e9cb
--- /dev/null
+++ b/lib/gitlab/ci/runner/backoff.rb
@@ -0,0 +1,75 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Ci
+ module Runner
+ ##
+ # Runner Backoff class is an implementation of an exponential backoff
+ # used when a runner communicates with GitLab. We typically use it when a
+ # runner retries sending a build status after we created a build pending
+ # state.
+ #
+ # Backoff is calculated based on the backoff slot which is always a power
+ # of 2:
+ #
+ # 0s - 3s duration -> 1 second backoff
+ # 4s - 7s duration -> 2 seconds backoff
+ # 8s - 15s duration -> 4 seconds backoff
+ # 16s - 31s duration -> 8 seconds backoff
+ # 32s - 63s duration -> 16 seconds backoff
+ # 64s - 127s duration -> 32 seconds backoff
+ # 127s - 256s+ duration -> 64 seconds backoff
+ #
+ # It means that first 15 requests made by a runner will need to respect
+ # following backoffs:
+ #
+ # 0s -> 1 second backoff (backoff started, slot 0, 2^0 backoff)
+ # 1s -> 1 second backoff
+ # 2s -> 1 second backoff
+ # 3s -> 1 seconds backoff
+ # (slot 1 - 2^1 backoff)
+ # 4s -> 2 seconds backoff
+ # 6s -> 2 seconds backoff
+ # (slot 2 - 2^2 backoff)
+ # 8s -> 4 seconds backoff
+ # 12s -> 4 seconds backoff
+ # (slot 3 - 2^3 backoff)
+ # 16s -> 8 seconds backoff
+ # 24s -> 8 seconds backoff
+ # (slot 4 - 2^4 backoff)
+ # 32s -> 16 seconds backoff
+ # 48s -> 16 seconds backoff
+ # (slot 5 - 2^5 backoff)
+ # 64s -> 32 seconds backoff
+ # 96s -> 32 seconds backoff
+ # (slot 6 - 2^6 backoff)
+ # 128s -> 64 seconds backoff
+ #
+ # There is a cap on the backoff - it will never exceed 64 seconds.
+ #
+ class Backoff
+ def initialize(started)
+ @started = started
+
+ if duration < 0
+ raise ArgumentError, 'backoff duration negative'
+ end
+ end
+
+ def duration
+ (Time.current - @started).ceil
+ end
+
+ def slot
+ return 0 if duration < 2
+
+ Math.log(duration, 2).floor - 1
+ end
+
+ def to_seconds
+ 2**[slot, 6].min
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/ci/status/bridge/action.rb b/lib/gitlab/ci/status/bridge/action.rb
new file mode 100644
index 00000000000..1ba4700d9b0
--- /dev/null
+++ b/lib/gitlab/ci/status/bridge/action.rb
@@ -0,0 +1,12 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Ci
+ module Status
+ module Bridge
+ class Action < Status::Build::Action
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/ci/status/bridge/common.rb b/lib/gitlab/ci/status/bridge/common.rb
index b95565b5e09..d66d4b20bba 100644
--- a/lib/gitlab/ci/status/bridge/common.rb
+++ b/lib/gitlab/ci/status/bridge/common.rb
@@ -14,7 +14,6 @@ module Gitlab
end
def details_path
- return unless Feature.enabled?(:ci_bridge_pipeline_details, subject.project, default_enabled: true)
return unless can?(user, :read_pipeline, downstream_pipeline)
project_pipeline_path(downstream_project, downstream_pipeline)
diff --git a/lib/gitlab/ci/status/bridge/factory.rb b/lib/gitlab/ci/status/bridge/factory.rb
index 5d397dba0de..b9bd66cee71 100644
--- a/lib/gitlab/ci/status/bridge/factory.rb
+++ b/lib/gitlab/ci/status/bridge/factory.rb
@@ -6,7 +6,10 @@ module Gitlab
module Bridge
class Factory < Status::Factory
def self.extended_statuses
- [Status::Bridge::Failed]
+ [[Status::Bridge::Failed],
+ [Status::Bridge::Manual],
+ [Status::Bridge::Play],
+ [Status::Bridge::Action]]
end
def self.common_helpers
diff --git a/lib/gitlab/ci/status/bridge/manual.rb b/lib/gitlab/ci/status/bridge/manual.rb
new file mode 100644
index 00000000000..e07e645a34d
--- /dev/null
+++ b/lib/gitlab/ci/status/bridge/manual.rb
@@ -0,0 +1,12 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Ci
+ module Status
+ module Bridge
+ class Manual < Status::Build::Manual
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/ci/status/bridge/play.rb b/lib/gitlab/ci/status/bridge/play.rb
new file mode 100644
index 00000000000..ae00ef6c2ad
--- /dev/null
+++ b/lib/gitlab/ci/status/bridge/play.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Ci
+ module Status
+ module Bridge
+ class Play < Status::Build::Play
+ def has_action?
+ can?(user, :play_job, subject)
+ end
+
+ def self.matches?(bridge, user)
+ bridge.playable?
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/ci/status/canceled.rb b/lib/gitlab/ci/status/canceled.rb
index 07f37732023..f173964b36c 100644
--- a/lib/gitlab/ci/status/canceled.rb
+++ b/lib/gitlab/ci/status/canceled.rb
@@ -19,6 +19,10 @@ module Gitlab
def favicon
'favicon_status_canceled'
end
+
+ def details_path
+ nil
+ end
end
end
end
diff --git a/lib/gitlab/ci/status/created.rb b/lib/gitlab/ci/status/created.rb
index fface4bb97b..33e67314d93 100644
--- a/lib/gitlab/ci/status/created.rb
+++ b/lib/gitlab/ci/status/created.rb
@@ -19,6 +19,10 @@ module Gitlab
def favicon
'favicon_status_created'
end
+
+ def details_path
+ nil
+ end
end
end
end
diff --git a/lib/gitlab/ci/status/failed.rb b/lib/gitlab/ci/status/failed.rb
index 770ed7d4d5a..215d27734a7 100644
--- a/lib/gitlab/ci/status/failed.rb
+++ b/lib/gitlab/ci/status/failed.rb
@@ -19,6 +19,10 @@ module Gitlab
def favicon
'favicon_status_failed'
end
+
+ def details_path
+ nil
+ end
end
end
end
diff --git a/lib/gitlab/ci/status/manual.rb b/lib/gitlab/ci/status/manual.rb
index 50c92add400..eb376df5f22 100644
--- a/lib/gitlab/ci/status/manual.rb
+++ b/lib/gitlab/ci/status/manual.rb
@@ -19,6 +19,10 @@ module Gitlab
def favicon
'favicon_status_manual'
end
+
+ def details_path
+ nil
+ end
end
end
end
diff --git a/lib/gitlab/ci/status/pending.rb b/lib/gitlab/ci/status/pending.rb
index cea7e6ed938..4280ad84534 100644
--- a/lib/gitlab/ci/status/pending.rb
+++ b/lib/gitlab/ci/status/pending.rb
@@ -19,6 +19,10 @@ module Gitlab
def favicon
'favicon_status_pending'
end
+
+ def details_path
+ nil
+ end
end
end
end
diff --git a/lib/gitlab/ci/status/preparing.rb b/lib/gitlab/ci/status/preparing.rb
index 1ebdbc482b7..e59d1d2eed1 100644
--- a/lib/gitlab/ci/status/preparing.rb
+++ b/lib/gitlab/ci/status/preparing.rb
@@ -19,6 +19,10 @@ module Gitlab
def favicon
'favicon_status_preparing'
end
+
+ def details_path
+ nil
+ end
end
end
end
diff --git a/lib/gitlab/ci/status/running.rb b/lib/gitlab/ci/status/running.rb
index ac7dd74cdce..eed1983e60e 100644
--- a/lib/gitlab/ci/status/running.rb
+++ b/lib/gitlab/ci/status/running.rb
@@ -19,6 +19,10 @@ module Gitlab
def favicon
'favicon_status_running'
end
+
+ def details_path
+ nil
+ end
end
end
end
diff --git a/lib/gitlab/ci/status/scheduled.rb b/lib/gitlab/ci/status/scheduled.rb
index 16ad1da89e3..e9068c326cf 100644
--- a/lib/gitlab/ci/status/scheduled.rb
+++ b/lib/gitlab/ci/status/scheduled.rb
@@ -19,6 +19,10 @@ module Gitlab
def favicon
'favicon_status_scheduled'
end
+
+ def details_path
+ nil
+ end
end
end
end
diff --git a/lib/gitlab/ci/status/skipped.rb b/lib/gitlab/ci/status/skipped.rb
index aaec1e1d201..238aa3ab4f9 100644
--- a/lib/gitlab/ci/status/skipped.rb
+++ b/lib/gitlab/ci/status/skipped.rb
@@ -19,6 +19,10 @@ module Gitlab
def favicon
'favicon_status_skipped'
end
+
+ def details_path
+ nil
+ end
end
end
end
diff --git a/lib/gitlab/ci/status/success.rb b/lib/gitlab/ci/status/success.rb
index 020f2c5b89f..2a10e60414e 100644
--- a/lib/gitlab/ci/status/success.rb
+++ b/lib/gitlab/ci/status/success.rb
@@ -19,6 +19,10 @@ module Gitlab
def favicon
'favicon_status_success'
end
+
+ def details_path
+ nil
+ end
end
end
end
diff --git a/lib/gitlab/ci/status/waiting_for_resource.rb b/lib/gitlab/ci/status/waiting_for_resource.rb
index 4c9e706bc51..2026148f752 100644
--- a/lib/gitlab/ci/status/waiting_for_resource.rb
+++ b/lib/gitlab/ci/status/waiting_for_resource.rb
@@ -23,6 +23,10 @@ module Gitlab
def group
'waiting-for-resource'
end
+
+ def details_path
+ nil
+ end
end
end
end
diff --git a/lib/gitlab/ci/templates/AWS/CF-Provision-and-Deploy-EC2.gitlab-ci.yml b/lib/gitlab/ci/templates/AWS/CF-Provision-and-Deploy-EC2.gitlab-ci.yml
new file mode 100644
index 00000000000..267027a1b8a
--- /dev/null
+++ b/lib/gitlab/ci/templates/AWS/CF-Provision-and-Deploy-EC2.gitlab-ci.yml
@@ -0,0 +1,11 @@
+stages:
+ - provision
+ - review
+ - production
+
+variables:
+ AUTO_DEVOPS_PLATFORM_TARGET: EC2
+
+include:
+ - template: Jobs/CF-Provision.gitlab-ci.yml
+ - template: Jobs/Deploy/EC2.gitlab-ci.yml
diff --git a/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml b/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml
index 6966ce88b30..cba13f374f4 100644
--- a/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml
@@ -20,6 +20,7 @@
# * dast: DAST_DISABLED
# * review: REVIEW_DISABLED
# * stop_review: REVIEW_DISABLED
+# * code_intelligence: CODE_INTELLIGENCE_DISABLED
#
# In order to deploy, you must have a Kubernetes cluster configured either
# via a project integration, or via group/project variables.
@@ -159,6 +160,7 @@ include:
- template: Jobs/Build.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab/blob/master/lib/gitlab/ci/templates/Jobs/Build.gitlab-ci.yml
- template: Jobs/Test.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab/blob/master/lib/gitlab/ci/templates/Jobs/Test.gitlab-ci.yml
- template: Jobs/Code-Quality.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab/blob/master/lib/gitlab/ci/templates/Jobs/Code-Quality.gitlab-ci.yml
+ - template: Jobs/Code-Intelligence.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab/blob/master/lib/gitlab/ci/templates/Jobs/Code-Intelligence.gitlab-ci.yml
- template: Jobs/Deploy.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab/blob/master/lib/gitlab/ci/templates/Jobs/Deploy.gitlab-ci.yml
- template: Jobs/Deploy/ECS.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab/blob/master/lib/gitlab/ci/templates/Jobs/Deploy/ECS.gitlab-ci.yml
- template: Jobs/DAST-Default-Branch-Deploy.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab/blob/master/lib/gitlab/ci/templates/Jobs/DAST-Default-Branch-Deploy.gitlab-ci.yml
diff --git a/lib/gitlab/ci/templates/Bash.gitlab-ci.yml b/lib/gitlab/ci/templates/Bash.gitlab-ci.yml
index 368069844ea..67e58d9ee99 100644
--- a/lib/gitlab/ci/templates/Bash.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Bash.gitlab-ci.yml
@@ -1,4 +1,4 @@
-# see https://docs.gitlab.com/ce/ci/yaml/README.html for all available options
+# see https://docs.gitlab.com/ee/ci/yaml/README.html for all available options
# you can delete this line if you're not using Docker
image: busybox:latest
diff --git a/lib/gitlab/ci/templates/Clojure.gitlab-ci.yml b/lib/gitlab/ci/templates/Clojure.gitlab-ci.yml
index c3568c0d2c8..0c5850bdb8e 100644
--- a/lib/gitlab/ci/templates/Clojure.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Clojure.gitlab-ci.yml
@@ -1,7 +1,7 @@
# Based on openjdk:8, already includes lein
image: clojure:lein-2.7.0
# If you need to configure a database, add a `services` section here
-# See https://docs.gitlab.com/ce/ci/services/postgres.html
+# See https://docs.gitlab.com/ee/ci/services/postgres.html
# Make sure you configure the connection as well
before_script:
diff --git a/lib/gitlab/ci/templates/Crystal.gitlab-ci.yml b/lib/gitlab/ci/templates/Crystal.gitlab-ci.yml
index e9301a2638d..538f96c4084 100644
--- a/lib/gitlab/ci/templates/Crystal.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Crystal.gitlab-ci.yml
@@ -4,7 +4,7 @@ image: "crystallang/crystal:latest"
# Pick zero or more services to be used on all builds.
# Only needed when using a docker container to run your tests in.
-# Check out: http://docs.gitlab.com/ce/ci/docker/using_docker_images.html#what-is-a-service
+# Check out: http://docs.gitlab.com/ee/ci/docker/using_docker_images.html#what-is-a-service
# services:
# - mysql:latest
# - redis:latest
diff --git a/lib/gitlab/ci/templates/Django.gitlab-ci.yml b/lib/gitlab/ci/templates/Django.gitlab-ci.yml
index d35fcb0f807..c657c7e8eb1 100644
--- a/lib/gitlab/ci/templates/Django.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Django.gitlab-ci.yml
@@ -4,7 +4,7 @@ image: python:latest
# Pick zero or more services to be used on all builds.
# Only needed when using a docker container to run your tests in.
-# Check out: http://docs.gitlab.com/ce/ci/docker/using_docker_images.html#what-is-a-service
+# Check out: http://docs.gitlab.com/ee/ci/docker/using_docker_images.html#what-is-a-service
services:
- mysql:latest
- postgres:latest
@@ -13,7 +13,7 @@ variables:
POSTGRES_DB: database_name
# This folder is cached between builds
-# http://docs.gitlab.com/ce/ci/yaml/README.html#cache
+# http://docs.gitlab.com/ee/ci/yaml/README.html#cache
cache:
paths:
- ~/.cache/pip/
diff --git a/lib/gitlab/ci/templates/Elixir.gitlab-ci.yml b/lib/gitlab/ci/templates/Elixir.gitlab-ci.yml
index 4d4c6a64cd5..7271526ab1b 100644
--- a/lib/gitlab/ci/templates/Elixir.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Elixir.gitlab-ci.yml
@@ -2,7 +2,7 @@ image: elixir:latest
# Pick zero or more services to be used on all builds.
# Only needed when using a docker container to run your tests in.
-# Check out: http://docs.gitlab.com/ce/ci/docker/using_docker_images.html#what-is-a-service
+# Check out: http://docs.gitlab.com/ee/ci/docker/using_docker_images.html#what-is-a-service
services:
- mysql:latest
- redis:latest
diff --git a/lib/gitlab/ci/templates/Jobs/CF-Provision.gitlab-ci.yml b/lib/gitlab/ci/templates/Jobs/CF-Provision.gitlab-ci.yml
new file mode 100644
index 00000000000..31ca68c57d7
--- /dev/null
+++ b/lib/gitlab/ci/templates/Jobs/CF-Provision.gitlab-ci.yml
@@ -0,0 +1,14 @@
+stages:
+ - provision
+
+cloud_formation:
+ image: 'registry.gitlab.com/gitlab-org/cloud-deploy/aws-cloudformation:latest'
+ stage: provision
+ script:
+ - gl-cloudformation create-stack
+ rules:
+ - if: '($AUTO_DEVOPS_PLATFORM_TARGET != "EC2") || ($AUTO_DEVOPS_PLATFORM_TARGET != "ECS")'
+ when: never
+ - if: '$CI_KUBERNETES_ACTIVE'
+ when: never
+ - if: '$CI_COMMIT_TAG || $CI_COMMIT_BRANCH'
diff --git a/lib/gitlab/ci/templates/Jobs/Code-Intelligence.gitlab-ci.yml b/lib/gitlab/ci/templates/Jobs/Code-Intelligence.gitlab-ci.yml
new file mode 100644
index 00000000000..83bc5548614
--- /dev/null
+++ b/lib/gitlab/ci/templates/Jobs/Code-Intelligence.gitlab-ci.yml
@@ -0,0 +1,16 @@
+code_intelligence_go:
+ stage: test
+ needs: []
+ allow_failure: true
+ image: sourcegraph/lsif-go:v1
+ rules:
+ - if: $CODE_INTELLIGENCE_DISABLED
+ when: never
+ - if: $CI_COMMIT_BRANCH
+ exists:
+ - '**/*.go'
+ script:
+ - lsif-go
+ artifacts:
+ reports:
+ lsif: dump.lsif
diff --git a/lib/gitlab/ci/templates/Jobs/Code-Quality.gitlab-ci.yml b/lib/gitlab/ci/templates/Jobs/Code-Quality.gitlab-ci.yml
index 568ceceeaa2..ec33020205b 100644
--- a/lib/gitlab/ci/templates/Jobs/Code-Quality.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Jobs/Code-Quality.gitlab-ci.yml
@@ -9,9 +9,8 @@ code_quality:
DOCKER_TLS_CERTDIR: ""
CODE_QUALITY_IMAGE: "registry.gitlab.com/gitlab-org/ci-cd/codequality:0.85.10-gitlab.1"
needs: []
- before_script:
- - export SOURCE_CODE=$PWD
script:
+ - export SOURCE_CODE=$PWD
- |
if ! docker info &>/dev/null; then
if [ -z "$DOCKER_HOST" -a "$KUBERNETES_PORT" ]; then
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 86f946aafda..77216a6e404 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 @@
.dast-auto-deploy:
- image: "registry.gitlab.com/gitlab-org/cluster-integration/auto-deploy-image:v1.0.3"
+ image: "registry.gitlab.com/gitlab-org/cluster-integration/auto-deploy-image:v1.0.5"
dast_environment_deploy:
extends: .dast-auto-deploy
diff --git a/lib/gitlab/ci/templates/Jobs/Deploy.gitlab-ci.yml b/lib/gitlab/ci/templates/Jobs/Deploy.gitlab-ci.yml
index 829fd7a722f..32a207a85d1 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 @@
.auto-deploy:
- image: "registry.gitlab.com/gitlab-org/cluster-integration/auto-deploy-image:v1.0.3"
+ image: "registry.gitlab.com/gitlab-org/cluster-integration/auto-deploy-image:v1.0.5"
dependencies: []
review:
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 829fd7a722f..8b921305c11 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 @@
.auto-deploy:
- image: "registry.gitlab.com/gitlab-org/cluster-integration/auto-deploy-image:v1.0.3"
+ image: "registry.gitlab.com/gitlab-org/cluster-integration/auto-deploy-image:v2.0.0-beta.2"
dependencies: []
review:
@@ -91,7 +91,7 @@ canary:
- auto-deploy ensure_namespace
- auto-deploy initialize_tiller
- auto-deploy create_secret
- - auto-deploy deploy canary
+ - auto-deploy deploy canary 50
environment:
name: production
url: http://$CI_PROJECT_PATH_SLUG.$KUBE_INGRESS_BASE_DOMAIN
@@ -114,7 +114,6 @@ canary:
- auto-deploy create_secret
- auto-deploy deploy
- auto-deploy delete canary
- - auto-deploy delete rollout
- auto-deploy persist_environment_url
environment:
name: production
@@ -163,9 +162,7 @@ production_manual:
- auto-deploy ensure_namespace
- auto-deploy initialize_tiller
- auto-deploy create_secret
- - auto-deploy deploy rollout $ROLLOUT_PERCENTAGE
- - auto-deploy scale stable $((100-ROLLOUT_PERCENTAGE))
- - auto-deploy delete canary
+ - auto-deploy deploy canary $ROLLOUT_PERCENTAGE
- auto-deploy persist_environment_url
environment:
name: production
diff --git a/lib/gitlab/ci/templates/Jobs/Deploy/EC2.gitlab-ci.yml b/lib/gitlab/ci/templates/Jobs/Deploy/EC2.gitlab-ci.yml
new file mode 100644
index 00000000000..ed2172ef7f5
--- /dev/null
+++ b/lib/gitlab/ci/templates/Jobs/Deploy/EC2.gitlab-ci.yml
@@ -0,0 +1,39 @@
+stages:
+ - review
+ - production
+
+.push-and-deploy:
+ image: 'registry.gitlab.com/gitlab-org/cloud-deploy/aws-ec2:latest'
+ script:
+ - gl-ec2 push-to-s3
+ - gl-ec2 deploy-to-ec2
+
+review_ec2:
+ extends: .push-and-deploy
+ stage: review
+ environment:
+ name: review/$CI_COMMIT_REF_NAME
+ rules:
+ - if: '$AUTO_DEVOPS_PLATFORM_TARGET != "EC2"'
+ when: never
+ - if: '$CI_KUBERNETES_ACTIVE'
+ when: never
+ - if: '$REVIEW_DISABLED'
+ when: never
+ - if: '$CI_COMMIT_BRANCH == "master"'
+ when: never
+ - if: '$CI_COMMIT_TAG || $CI_COMMIT_BRANCH'
+
+production_ec2:
+ extends: .push-and-deploy
+ stage: production
+ environment:
+ name: production
+ rules:
+ - if: '$AUTO_DEVOPS_PLATFORM_TARGET != "EC2"'
+ when: never
+ - if: '$CI_KUBERNETES_ACTIVE'
+ when: never
+ - if: '$CI_COMMIT_BRANCH != "master"'
+ when: never
+ - if: '$CI_COMMIT_TAG || $CI_COMMIT_BRANCH'
diff --git a/lib/gitlab/ci/templates/Jobs/Deploy/ECS.gitlab-ci.yml b/lib/gitlab/ci/templates/Jobs/Deploy/ECS.gitlab-ci.yml
index da474f8ac88..317e8bfab0e 100644
--- a/lib/gitlab/ci/templates/Jobs/Deploy/ECS.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Jobs/Deploy/ECS.gitlab-ci.yml
@@ -10,6 +10,7 @@
.deploy_to_ecs:
image: 'registry.gitlab.com/gitlab-org/cloud-deploy/aws-ecs:latest'
+ dependencies: []
script:
- ecs update-task-definition
diff --git a/lib/gitlab/ci/templates/Laravel.gitlab-ci.yml b/lib/gitlab/ci/templates/Laravel.gitlab-ci.yml
index 9bde04dff19..5d2c8024524 100644
--- a/lib/gitlab/ci/templates/Laravel.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Laravel.gitlab-ci.yml
@@ -4,7 +4,7 @@ image: php:latest
# Pick zero or more services to be used on all builds.
# Only needed when using a docker container to run your tests in.
-# Check out: http://docs.gitlab.com/ce/ci/docker/using_docker_images.html#what-is-a-service
+# Check out: http://docs.gitlab.com/ee/ci/docker/using_docker_images.html#what-is-a-service
services:
- mysql:latest
@@ -13,7 +13,7 @@ variables:
MYSQL_ROOT_PASSWORD: secret
# This folder is cached between builds
-# http://docs.gitlab.com/ce/ci/yaml/README.html#cache
+# http://docs.gitlab.com/ee/ci/yaml/README.html#cache
cache:
paths:
- vendor/
diff --git a/lib/gitlab/ci/templates/Managed-Cluster-Applications.gitlab-ci.yml b/lib/gitlab/ci/templates/Managed-Cluster-Applications.gitlab-ci.yml
index 7050b41e045..a9638f564f3 100644
--- a/lib/gitlab/ci/templates/Managed-Cluster-Applications.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Managed-Cluster-Applications.gitlab-ci.yml
@@ -1,6 +1,6 @@
apply:
stage: deploy
- image: "registry.gitlab.com/gitlab-org/cluster-integration/cluster-applications:v0.29.0"
+ image: "registry.gitlab.com/gitlab-org/cluster-integration/cluster-applications:v0.33.0"
environment:
name: production
variables:
diff --git a/lib/gitlab/ci/templates/Nodejs.gitlab-ci.yml b/lib/gitlab/ci/templates/Nodejs.gitlab-ci.yml
index b87178141a1..92379ded77c 100644
--- a/lib/gitlab/ci/templates/Nodejs.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Nodejs.gitlab-ci.yml
@@ -4,14 +4,14 @@ image: node:latest
# Pick zero or more services to be used on all builds.
# Only needed when using a docker container to run your tests in.
-# Check out: http://docs.gitlab.com/ce/ci/docker/using_docker_images.html#what-is-a-service
+# Check out: http://docs.gitlab.com/ee/ci/docker/using_docker_images.html#what-is-a-service
services:
- mysql:latest
- redis:latest
- postgres:latest
# This folder is cached between builds
-# http://docs.gitlab.com/ce/ci/yaml/README.html#cache
+# http://docs.gitlab.com/ee/ci/yaml/README.html#cache
cache:
paths:
- node_modules/
diff --git a/lib/gitlab/ci/templates/PHP.gitlab-ci.yml b/lib/gitlab/ci/templates/PHP.gitlab-ci.yml
index 25ea20e454f..84e8223e69b 100644
--- a/lib/gitlab/ci/templates/PHP.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/PHP.gitlab-ci.yml
@@ -19,7 +19,7 @@ before_script:
- php composer.phar install
# Bring in any services we need http://docs.gitlab.com/ee/ci/docker/using_docker_images.html#what-is-a-service
-# See http://docs.gitlab.com/ce/ci/services/README.html for examples.
+# See http://docs.gitlab.com/ee/ci/services/README.html for examples.
services:
- mysql:5.7
diff --git a/lib/gitlab/ci/templates/Pages/Gatsby.gitlab-ci.yml b/lib/gitlab/ci/templates/Pages/Gatsby.gitlab-ci.yml
index a683561a455..3a6eac63892 100644
--- a/lib/gitlab/ci/templates/Pages/Gatsby.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Pages/Gatsby.gitlab-ci.yml
@@ -1,7 +1,7 @@
image: node:latest
# This folder is cached between builds
-# http://docs.gitlab.com/ce/ci/yaml/README.html#cache
+# http://docs.gitlab.com/ee/ci/yaml/README.html#cache
cache:
paths:
- node_modules/
diff --git a/lib/gitlab/ci/templates/Pages/Jekyll.gitlab-ci.yml b/lib/gitlab/ci/templates/Pages/Jekyll.gitlab-ci.yml
index 0c8859dc779..f2f92fe0704 100644
--- a/lib/gitlab/ci/templates/Pages/Jekyll.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Pages/Jekyll.gitlab-ci.yml
@@ -1,5 +1,5 @@
# Template project: https://gitlab.com/pages/jekyll
-# Docs: https://docs.gitlab.com/ce/pages/
+# Docs: https://docs.gitlab.com/ee/pages/
image: ruby:2.6
variables:
diff --git a/lib/gitlab/ci/templates/Ruby.gitlab-ci.yml b/lib/gitlab/ci/templates/Ruby.gitlab-ci.yml
index b3cad8b858a..275364afae4 100644
--- a/lib/gitlab/ci/templates/Ruby.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Ruby.gitlab-ci.yml
@@ -4,7 +4,7 @@ image: "ruby:2.5"
# Pick zero or more services to be used on all builds.
# Only needed when using a docker container to run your tests in.
-# Check out: http://docs.gitlab.com/ce/ci/docker/using_docker_images.html#what-is-a-service
+# Check out: http://docs.gitlab.com/ee/ci/docker/using_docker_images.html#what-is-a-service
services:
- mysql:latest
- redis:latest
diff --git a/lib/gitlab/ci/templates/Rust.gitlab-ci.yml b/lib/gitlab/ci/templates/Rust.gitlab-ci.yml
index f35470367cc..94117a79d1c 100644
--- a/lib/gitlab/ci/templates/Rust.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Rust.gitlab-ci.yml
@@ -4,7 +4,7 @@ image: "rust:latest"
# Optional: Pick zero or more services to be used on all builds.
# Only needed when using a docker container to run your tests in.
-# Check out: http://docs.gitlab.com/ce/ci/docker/using_docker_images.html#what-is-a-service
+# Check out: http://docs.gitlab.com/ee/ci/docker/using_docker_images.html#what-is-a-service
# services:
# - mysql:latest
# - redis:latest
diff --git a/lib/gitlab/ci/templates/Security/Coverage-Fuzzing.gitlab-ci.yml b/lib/gitlab/ci/templates/Security/Coverage-Fuzzing.gitlab-ci.yml
index 4b957a8f771..e268b48d133 100644
--- a/lib/gitlab/ci/templates/Security/Coverage-Fuzzing.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Security/Coverage-Fuzzing.gitlab-ci.yml
@@ -35,4 +35,3 @@ variables:
- if: $COVFUZZ_DISABLED
when: never
- if: $CI_COMMIT_BRANCH && $GITLAB_FEATURES =~ /\bcoverage_fuzzing\b/
- - if: $CI_RUNNER_EXECUTABLE_ARCH == "linux"
diff --git a/lib/gitlab/ci/templates/Security/License-Scanning.gitlab-ci.yml b/lib/gitlab/ci/templates/Security/License-Scanning.gitlab-ci.yml
index cc34d23decc..63237e41376 100644
--- a/lib/gitlab/ci/templates/Security/License-Scanning.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Security/License-Scanning.gitlab-ci.yml
@@ -1,7 +1,7 @@
# Read more about this feature here: https://docs.gitlab.com/ee/user/application_security/license_compliance/
#
# Configure the scanning tool through the environment variables.
-# List of the variables: https://gitlab.com/gitlab-org/security-products/license-management#settings
+# List of the variables: https://gitlab.com/gitlab-org/security-products/analyzers/license-finder#settings
# How to set: https://docs.gitlab.com/ee/ci/yaml/#variables
variables:
diff --git a/lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml b/lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml
index 77ea11d01d1..4418ff18d73 100644
--- a/lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml
@@ -9,7 +9,7 @@ variables:
# (SAST, Dependency Scanning, ...)
SECURE_ANALYZERS_PREFIX: "registry.gitlab.com/gitlab-org/security-products/analyzers"
- SAST_DEFAULT_ANALYZERS: "bandit, brakeman, gosec, spotbugs, flawfinder, phpcs-security-audit, security-code-scan, nodejs-scan, eslint, sobelow, pmd-apex, kubesec"
+ SAST_DEFAULT_ANALYZERS: "bandit, brakeman, gosec, spotbugs, flawfinder, phpcs-security-audit, security-code-scan, nodejs-scan, eslint, sobelow, pmd-apex, kubesec, mobsf"
SAST_EXCLUDED_PATHS: "spec, test, tests, tmp"
SAST_ANALYZER_IMAGE_TAG: 2
SCAN_KUBERNETES_MANIFESTS: "false"
@@ -125,6 +125,42 @@ gosec-sast:
exists:
- '**/*.go'
+mobsf-android-sast:
+ extends: .sast-analyzer
+ services:
+ - name: opensecurity/mobile-security-framework-mobsf:latest
+ alias: mobsf
+ image:
+ name: "$SAST_ANALYZER_IMAGE"
+ variables:
+ SAST_ANALYZER_IMAGE: "$SECURE_ANALYZERS_PREFIX/mobsf:$SAST_ANALYZER_IMAGE_TAG"
+ rules:
+ - if: $SAST_DISABLED
+ when: never
+ - if: $CI_COMMIT_BRANCH &&
+ $SAST_DEFAULT_ANALYZERS =~ /mobsf/ &&
+ $SAST_EXPERIMENTAL_FEATURES == 'true'
+ exists:
+ - '**/AndroidManifest.xml'
+
+mobsf-ios-sast:
+ extends: .sast-analyzer
+ services:
+ - name: opensecurity/mobile-security-framework-mobsf:latest
+ alias: mobsf
+ image:
+ name: "$SAST_ANALYZER_IMAGE"
+ variables:
+ SAST_ANALYZER_IMAGE: "$SECURE_ANALYZERS_PREFIX/mobsf:$SAST_ANALYZER_IMAGE_TAG"
+ rules:
+ - if: $SAST_DISABLED
+ when: never
+ - if: $CI_COMMIT_BRANCH &&
+ $SAST_DEFAULT_ANALYZERS =~ /mobsf/ &&
+ $SAST_EXPERIMENTAL_FEATURES == 'true'
+ exists:
+ - '**/*.xcodeproj/*'
+
nodejs-scan-sast:
extends: .sast-analyzer
image:
@@ -203,6 +239,11 @@ spotbugs-sast:
variables:
SAST_ANALYZER_IMAGE: "$SECURE_ANALYZERS_PREFIX/spotbugs:$SAST_ANALYZER_IMAGE_TAG"
rules:
+ - if: $SAST_DEFAULT_ANALYZERS =~ /mobsf/ &&
+ $SAST_EXPERIMENTAL_FEATURES == 'true'
+ exists:
+ - '**/AndroidManifest.xml'
+ when: never
- if: $SAST_DISABLED
when: never
- if: $CI_COMMIT_BRANCH &&
diff --git a/lib/gitlab/ci/templates/Security/Secret-Detection.gitlab-ci.yml b/lib/gitlab/ci/templates/Security/Secret-Detection.gitlab-ci.yml
index bde6a0fbebb..6ebff102ccb 100644
--- a/lib/gitlab/ci/templates/Security/Secret-Detection.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Security/Secret-Detection.gitlab-ci.yml
@@ -34,8 +34,8 @@ secret_detection:
when: never
- if: $CI_COMMIT_BRANCH && $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH
script:
- - git fetch origin $CI_DEFAULT_BRANCH $CI_BUILD_REF_NAME
- - git log --left-right --cherry-pick --pretty=format:"%H" refs/remotes/origin/$CI_DEFAULT_BRANCH...refs/remotes/origin/$CI_BUILD_REF_NAME > "$CI_COMMIT_SHA"_commit_list.txt
+ - git fetch origin $CI_DEFAULT_BRANCH $CI_COMMIT_REF_NAME
+ - git log --left-right --cherry-pick --pretty=format:"%H" refs/remotes/origin/$CI_DEFAULT_BRANCH...refs/remotes/origin/$CI_COMMIT_REF_NAME > "$CI_COMMIT_SHA"_commit_list.txt
- export SECRET_DETECTION_COMMITS_FILE="$CI_COMMIT_SHA"_commit_list.txt
- /analyzer run
- rm "$CI_COMMIT_SHA"_commit_list.txt
diff --git a/lib/gitlab/ci/templates/Terraform.latest.gitlab-ci.yml b/lib/gitlab/ci/templates/Terraform.latest.gitlab-ci.yml
new file mode 100644
index 00000000000..b08ccf18b58
--- /dev/null
+++ b/lib/gitlab/ci/templates/Terraform.latest.gitlab-ci.yml
@@ -0,0 +1,22 @@
+include:
+ - template: Terraform/Base.latest.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab/blob/master/lib/gitlab/ci/templates/Terraform/Base.gitlab-ci.yml
+
+stages:
+ - init
+ - validate
+ - build
+ - deploy
+
+init:
+ extends: .init
+
+validate:
+ extends: .validate
+
+build:
+ extends: .build
+
+deploy:
+ extends: .deploy
+ dependencies:
+ - build
diff --git a/lib/gitlab/ci/templates/Terraform/Base.latest.gitlab-ci.yml b/lib/gitlab/ci/templates/Terraform/Base.latest.gitlab-ci.yml
new file mode 100644
index 00000000000..000a1a7f580
--- /dev/null
+++ b/lib/gitlab/ci/templates/Terraform/Base.latest.gitlab-ci.yml
@@ -0,0 +1,53 @@
+# Terraform/Base.latest
+#
+# The purpose of this template is to provide flexibility to the user so
+# they are able to only include the jobs that they find interesting.
+#
+# Therefore, this template is not supposed to run any jobs. The idea is to only
+# create hidden jobs. See: https://docs.gitlab.com/ee/ci/yaml/#hide-jobs
+#
+# There is a more opinionated template which we suggest the users to abide,
+# which is the lib/gitlab/ci/templates/Terraform.latest.gitlab-ci.yml
+
+image:
+ name: registry.gitlab.com/gitlab-org/terraform-images/stable:latest
+
+before_script:
+ - cd ${TF_ROOT}
+
+variables:
+ TF_ROOT: ${CI_PROJECT_DIR}
+
+cache:
+ key: "${TF_ROOT}"
+ paths:
+ - ${TF_ROOT}/.terraform/
+
+.init: &init
+ stage: init
+ script:
+ - gitlab-terraform init
+
+.validate: &validate
+ stage: validate
+ script:
+ - gitlab-terraform validate
+
+.build: &build
+ stage: build
+ script:
+ - gitlab-terraform plan
+ - gitlab-terraform plan-json
+ artifacts:
+ paths:
+ - ${TF_ROOT}/plan.cache
+ reports:
+ terraform: ${TF_ROOT}/plan.json
+
+.deploy: &deploy
+ stage: deploy
+ script:
+ - gitlab-terraform apply
+ when: manual
+ only:
+ - master
diff --git a/lib/gitlab/ci/trace.rb b/lib/gitlab/ci/trace.rb
index 348e5472cb4..0222ca021b7 100644
--- a/lib/gitlab/ci/trace.rb
+++ b/lib/gitlab/ci/trace.rb
@@ -16,6 +16,7 @@ module Gitlab
ArchiveError = Class.new(StandardError)
AlreadyArchivedError = Class.new(StandardError)
+ LockedError = Class.new(StandardError)
attr_reader :job
@@ -79,11 +80,9 @@ module Gitlab
job.trace_chunks.any? || current_path.present? || old_trace.present?
end
- def read(should_retry: true, &block)
+ def read(&block)
read_stream(&block)
- rescue Errno::ENOENT
- raise unless should_retry
-
+ rescue Errno::ENOENT, ChunkedIO::FailedToGetChunkError
job.reset
read_stream(&block)
end
@@ -130,6 +129,12 @@ module Gitlab
end
end
+ def lock(&block)
+ in_write_lock(&block)
+ rescue FailedToObtainLockError
+ raise LockedError, "build trace `#{job.id}` is locked"
+ end
+
private
def read_stream
diff --git a/lib/gitlab/ci/trace/checksum.rb b/lib/gitlab/ci/trace/checksum.rb
new file mode 100644
index 00000000000..62532ef1cd2
--- /dev/null
+++ b/lib/gitlab/ci/trace/checksum.rb
@@ -0,0 +1,83 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Ci
+ class Trace
+ ##
+ # Trace::Checksum class is responsible for calculating a CRC32 checksum
+ # of an entire build trace using partial build trace chunks stored in a
+ # database.
+ #
+ # CRC32 checksum can be easily calculated by combining partial checksums
+ # in a right order.
+ #
+ # Then we compare CRC32 checksum provided by a GitLab Runner and expect
+ # it to be the same as the CRC32 checksum derived from partial chunks.
+ #
+ class Checksum
+ include Gitlab::Utils::StrongMemoize
+
+ attr_reader :build
+
+ def initialize(build)
+ @build = build
+ end
+
+ def valid?
+ return false unless state_crc32.present?
+
+ state_crc32 == chunks_crc32
+ end
+
+ def state_crc32
+ strong_memoize(:state_crc32) { build.pending_state&.crc32 }
+ end
+
+ def chunks_crc32
+ strong_memoize(:chunks_crc32) do
+ trace_chunks.reduce(0) do |crc32, chunk|
+ Zlib.crc32_combine(crc32, chunk.crc32, chunk_size(chunk))
+ end
+ end
+ end
+
+ def last_chunk
+ strong_memoize(:last_chunk) { trace_chunks.max }
+ end
+
+ ##
+ # Trace chunks will be persisted in a database if an object store is
+ # not configured - in that case we do not want to load entire raw data
+ # of all the chunks into memory.
+ #
+ # We ignore `raw_data` attribute instead, and rely on internal build
+ # trace chunk database adapter to handle
+ # `ActiveModel::MissingAttributeError` exception.
+ #
+ # Alternative solution would be separating chunk data from chunk
+ # metadata on the database level too.
+ #
+ def trace_chunks
+ strong_memoize(:trace_chunks) do
+ build.trace_chunks.persisted
+ .select(::Ci::BuildTraceChunk.metadata_attributes)
+ end
+ end
+
+ def chunks_count
+ trace_chunks.to_a.size
+ end
+
+ private
+
+ def chunk_size(chunk)
+ if chunk == last_chunk
+ chunk.size
+ else
+ ::Ci::BuildTraceChunk::CHUNK_SIZE
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/ci/trace/metrics.rb b/lib/gitlab/ci/trace/metrics.rb
index 82a7d5fb83c..097436d84ea 100644
--- a/lib/gitlab/ci/trace/metrics.rb
+++ b/lib/gitlab/ci/trace/metrics.rb
@@ -6,8 +6,20 @@ module Gitlab
class Metrics
extend Gitlab::Utils::StrongMemoize
- OPERATIONS = [:appended, :streamed, :chunked, :mutated, :overwrite,
- :accepted, :finalized, :discarded, :conflict].freeze
+ OPERATIONS = [
+ :appended, # new trace data has been written to a chunk
+ :streamed, # new trace data has been sent by a runner
+ :chunked, # new trace chunk has been created
+ :mutated, # trace has been mutated when removing secrets
+ :overwrite, # runner requested overwritting a build trace
+ :accepted, # scheduled chunks for migration and responded with 202
+ :finalized, # all live build trace chunks have been persisted
+ :discarded, # failed to persist live chunks before timeout
+ :conflict, # runner has sent unrecognized build state details
+ :locked, # build trace has been locked by a different mechanism
+ :stalled, # failed to migrate chunk due to a worker duplication
+ :invalid # malformed build trace has been detected using CRC32
+ ].freeze
def increment_trace_operation(operation: :unknown)
unless OPERATIONS.include?(operation)
@@ -18,7 +30,11 @@ module Gitlab
end
def increment_trace_bytes(size)
- self.class.trace_bytes.increment(by: size.to_i)
+ self.class.trace_bytes.increment({}, size.to_i)
+ end
+
+ def observe_migration_duration(seconds)
+ self.class.finalize_histogram.observe({}, seconds.to_f)
end
def self.trace_operations
@@ -38,6 +54,17 @@ module Gitlab
Gitlab::Metrics.counter(name, comment)
end
end
+
+ def self.finalize_histogram
+ strong_memoize(:finalize_histogram) do
+ name = :gitlab_ci_trace_finalize_duration_seconds
+ comment = 'Duration of build trace chunks migration to object storage'
+ buckets = [0.1, 0.5, 1.0, 2.0, 3.0, 5.0, 7.0, 10.0, 20.0, 30.0, 60.0, 300.0]
+ labels = {}
+
+ ::Gitlab::Metrics.histogram(name, comment, labels, buckets)
+ end
+ end
end
end
end
diff --git a/lib/gitlab/ci/variables/collection/item.rb b/lib/gitlab/ci/variables/collection/item.rb
index a072036daa8..84a9280e507 100644
--- a/lib/gitlab/ci/variables/collection/item.rb
+++ b/lib/gitlab/ci/variables/collection/item.rb
@@ -36,9 +36,9 @@ module Gitlab
def self.fabricate(resource)
case resource
when Hash
- self.new(resource.symbolize_keys)
+ self.new(**resource.symbolize_keys)
when ::Ci::HasVariable
- self.new(resource.to_runner_variable)
+ self.new(**resource.to_runner_variable)
when self
resource.dup
else
diff --git a/lib/gitlab/ci/yaml_processor/result.rb b/lib/gitlab/ci/yaml_processor/result.rb
index 68f61e52df7..52a00e41214 100644
--- a/lib/gitlab/ci/yaml_processor/result.rb
+++ b/lib/gitlab/ci/yaml_processor/result.rb
@@ -95,6 +95,14 @@ module Gitlab
}.compact }.compact
end
+ def merged_yaml
+ @ci_config&.to_hash&.to_yaml
+ end
+
+ def variables_with_data
+ @ci_config.variables_with_data
+ end
+
private
def variables
diff --git a/lib/gitlab/cleanup/orphan_lfs_file_references.rb b/lib/gitlab/cleanup/orphan_lfs_file_references.rb
index 14eac474e27..a6638b2cbc8 100644
--- a/lib/gitlab/cleanup/orphan_lfs_file_references.rb
+++ b/lib/gitlab/cleanup/orphan_lfs_file_references.rb
@@ -19,6 +19,11 @@ module Gitlab
def run!
log_info("Looking for orphan LFS files for project #{project.name_with_namespace}")
+ if project.lfs_objects.empty?
+ log_info("Project #{project.name_with_namespace} is linked to 0 LFS objects. Nothing to do")
+ return
+ end
+
remove_orphan_references
end
diff --git a/lib/gitlab/cluster/puma_worker_killer_initializer.rb b/lib/gitlab/cluster/puma_worker_killer_initializer.rb
index 92c799875b5..822012e0ed6 100644
--- a/lib/gitlab/cluster/puma_worker_killer_initializer.rb
+++ b/lib/gitlab/cluster/puma_worker_killer_initializer.rb
@@ -5,8 +5,8 @@ module Gitlab
class PumaWorkerKillerInitializer
def self.start(
puma_options,
- puma_per_worker_max_memory_mb: 850,
- puma_master_max_memory_mb: 550,
+ puma_per_worker_max_memory_mb: 1024,
+ puma_master_max_memory_mb: 800,
additional_puma_dev_max_memory_mb: 200
)
require 'puma_worker_killer'
diff --git a/lib/gitlab/code_navigation_path.rb b/lib/gitlab/code_navigation_path.rb
index 909d0536b5f..7d36f2f12cf 100644
--- a/lib/gitlab/code_navigation_path.rb
+++ b/lib/gitlab/code_navigation_path.rb
@@ -13,7 +13,6 @@ module Gitlab
end
def full_json_path_for(path)
- return unless Feature.enabled?(:code_navigation, project, default_enabled: true)
return unless build
raw_project_job_artifacts_path(project, build, path: "lsif/#{path}.json", file_type: :lsif)
diff --git a/lib/gitlab/config/entry/composable_array.rb b/lib/gitlab/config/entry/composable_array.rb
new file mode 100644
index 00000000000..e7ad259e826
--- /dev/null
+++ b/lib/gitlab/config/entry/composable_array.rb
@@ -0,0 +1,58 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Config
+ module Entry
+ ##
+ # Entry that represents a composable array definition
+ #
+ class ComposableArray < ::Gitlab::Config::Entry::Node
+ include ::Gitlab::Config::Entry::Validatable
+ include Gitlab::Utils::StrongMemoize
+
+ # TODO: Refactor `Validatable` code so that validations can apply to a child class
+ # See: https://gitlab.com/gitlab-org/gitlab/-/issues/263231
+ validations do
+ validates :config, type: Array
+ end
+
+ def compose!(deps = nil)
+ super do
+ @entries = Array(@entries)
+
+ # TODO: Isolate handling for a hash via: `[@config].flatten` to the `Needs` entry
+ # See: https://gitlab.com/gitlab-org/gitlab/-/issues/264376
+ [@config].flatten.each_with_index do |value, index|
+ raise ArgumentError, 'Missing Composable class' unless composable_class
+
+ composable_class_name = composable_class.name.demodulize.underscore
+
+ @entries << ::Gitlab::Config::Entry::Factory.new(composable_class)
+ .value(value)
+ .with(key: composable_class_name, parent: self, description: "#{composable_class_name} definition") # rubocop:disable CodeReuse/ActiveRecord
+ .create!
+ end
+
+ @entries.each do |entry|
+ entry.compose!(deps)
+ end
+ end
+ end
+
+ def value
+ @entries.map(&:value)
+ end
+
+ def descendants
+ @entries
+ end
+
+ def composable_class
+ strong_memoize(:composable_class) do
+ opt(:composable_class)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/config/entry/composable_hash.rb b/lib/gitlab/config/entry/composable_hash.rb
new file mode 100644
index 00000000000..9531b7e56fd
--- /dev/null
+++ b/lib/gitlab/config/entry/composable_hash.rb
@@ -0,0 +1,47 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Config
+ module Entry
+ ##
+ # Entry that represents a composable hash definition
+ # Where each hash key can be any value written by the user
+ #
+ class ComposableHash < ::Gitlab::Config::Entry::Node
+ include ::Gitlab::Config::Entry::Validatable
+
+ # TODO: Refactor `Validatable` code so that validations can apply to a child class
+ # See: https://gitlab.com/gitlab-org/gitlab/-/issues/263231
+ validations do
+ validates :config, type: Hash
+ end
+
+ def compose!(deps = nil)
+ super do
+ @config.each do |name, config|
+ entry_class = composable_class(name, config)
+ raise ArgumentError, 'Missing Composable class' unless entry_class
+
+ entry_class_name = entry_class.name.demodulize.underscore
+
+ factory = ::Gitlab::Config::Entry::Factory.new(entry_class)
+ .value(config || {})
+ .with(key: name, parent: self, description: "#{name} #{entry_class_name} definition") # rubocop:disable CodeReuse/ActiveRecord
+ .metadata(name: name)
+
+ @entries[name] = factory.create!
+ end
+
+ @entries.each_value do |entry|
+ entry.compose!(deps)
+ end
+ end
+ end
+
+ def composable_class(name, config)
+ opt(:composable_class)
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/config/entry/factory.rb b/lib/gitlab/config/entry/factory.rb
index 7c5ffaa7621..f76c98f7cbf 100644
--- a/lib/gitlab/config/entry/factory.rb
+++ b/lib/gitlab/config/entry/factory.rb
@@ -79,7 +79,7 @@ module Gitlab
end
def fabricate(entry_class, value = nil)
- entry_class.new(value, @metadata) do |node|
+ entry_class.new(value, **@metadata) do |node|
node.key = @attributes[:key]
node.parent = @attributes[:parent]
node.default = @attributes[:default]
diff --git a/lib/gitlab/config/entry/legacy_validation_helpers.rb b/lib/gitlab/config/entry/legacy_validation_helpers.rb
index 415f6f77214..be7d26fed4e 100644
--- a/lib/gitlab/config/entry/legacy_validation_helpers.rb
+++ b/lib/gitlab/config/entry/legacy_validation_helpers.rb
@@ -50,6 +50,12 @@ module Gitlab
variables.values.flatten(1).all?(&method(:validate_alphanumeric))
end
+ def validate_string_or_hash_value_variables(variables, allowed_value_data)
+ variables.is_a?(Hash) &&
+ variables.keys.all?(&method(:validate_alphanumeric)) &&
+ variables.values.all? { |value| validate_string_or_hash_value_variable(value, allowed_value_data) }
+ end
+
def validate_alphanumeric(value)
validate_string(value) || validate_integer(value)
end
@@ -62,6 +68,14 @@ module Gitlab
value.is_a?(String) || value.is_a?(Symbol)
end
+ def validate_string_or_hash_value_variable(value, allowed_value_data)
+ if value.is_a?(Hash)
+ (value.keys - allowed_value_data).empty? && value.values.all?(&method(:validate_alphanumeric))
+ else
+ validate_alphanumeric(value)
+ end
+ end
+
def validate_regexp(value)
Gitlab::UntrustedRegexp::RubySyntax.valid?(value)
end
diff --git a/lib/gitlab/config/entry/simplifiable.rb b/lib/gitlab/config/entry/simplifiable.rb
index 315f1947e2c..ee28891a174 100644
--- a/lib/gitlab/config/entry/simplifiable.rb
+++ b/lib/gitlab/config/entry/simplifiable.rb
@@ -19,7 +19,7 @@ module Gitlab
entry = self.class.entry_class(strategy)
- @subject = entry.new(config, metadata, &blk)
+ @subject = entry.new(config, **metadata, &blk)
super(@subject)
end
diff --git a/lib/gitlab/config/entry/validators.rb b/lib/gitlab/config/entry/validators.rb
index a7ec98ace6e..2a386657e0b 100644
--- a/lib/gitlab/config/entry/validators.rb
+++ b/lib/gitlab/config/entry/validators.rb
@@ -274,6 +274,8 @@ module Gitlab
def validate_each(record, attribute, value)
if options[:array_values]
validate_key_array_values(record, attribute, value)
+ elsif options[:allowed_value_data]
+ validate_key_hash_values(record, attribute, value, options[:allowed_value_data])
else
validate_key_values(record, attribute, value)
end
@@ -290,6 +292,12 @@ module Gitlab
record.errors.add(attribute, 'should be a hash of key value pairs, value can be an array')
end
end
+
+ def validate_key_hash_values(record, attribute, value, allowed_value_data)
+ unless validate_string_or_hash_value_variables(value, allowed_value_data)
+ record.errors.add(attribute, 'should be a hash of key value pairs, value can be a hash')
+ end
+ end
end
class ExpressionValidator < ActiveModel::EachValidator
diff --git a/lib/gitlab/conflict/file_collection.rb b/lib/gitlab/conflict/file_collection.rb
index 53406af2c4e..047600af267 100644
--- a/lib/gitlab/conflict/file_collection.rb
+++ b/lib/gitlab/conflict/file_collection.rb
@@ -21,11 +21,13 @@ module Gitlab
def resolve(user, commit_message, files)
msg = commit_message || default_commit_message
resolution = Gitlab::Git::Conflict::Resolution.new(user, files, msg)
- args = {
+
+ resolver.resolve_conflicts(
+ @source_repo,
+ resolution,
source_branch: merge_request.source_branch,
target_branch: merge_request.target_branch
- }
- resolver.resolve_conflicts(@source_repo, resolution, args)
+ )
ensure
@merge_request.clear_memoized_shas
end
diff --git a/lib/gitlab/danger/commit_linter.rb b/lib/gitlab/danger/commit_linter.rb
index 954934518d7..7b01db125a9 100644
--- a/lib/gitlab/danger/commit_linter.rb
+++ b/lib/gitlab/danger/commit_linter.rb
@@ -10,7 +10,7 @@ module Gitlab
MAX_LINE_LENGTH = 72
MAX_CHANGED_FILES_IN_COMMIT = 3
MAX_CHANGED_LINES_IN_COMMIT = 30
- SHORT_REFERENCE_REGEX = %r{([\w\-\/]+)?(#|!|&|%)\d+\b}.freeze
+ SHORT_REFERENCE_REGEX = %r{([\w\-\/]+)?(?<!`)(#|!|&|%)\d+(?<!`)}.freeze
DEFAULT_SUBJECT_DESCRIPTION = 'commit subject'
WIP_PREFIX = 'WIP: '
PROBLEMS = {
@@ -118,7 +118,7 @@ module Gitlab
next unless line_too_long?(line)
- url_size = line.scan(%r((https?://\S+))).sum { |(url)| url.length } # rubocop:disable CodeReuse/ActiveRecord
+ url_size = line.scan(%r((https?://\S+))).sum { |(url)| url.length }
# If the line includes a URL, we'll allow it to exceed MAX_LINE_LENGTH characters, but
# only if the line _without_ the URL does not exceed this limit.
diff --git a/lib/gitlab/danger/helper.rb b/lib/gitlab/danger/helper.rb
index 3626ec5bf5b..783a5f1715c 100644
--- a/lib/gitlab/danger/helper.rb
+++ b/lib/gitlab/danger/helper.rb
@@ -123,7 +123,8 @@ module Gitlab
none: "",
qa: "~QA",
test: "~test ~Quality for `spec/features/*`",
- engineering_productivity: '~"Engineering Productivity" for CI, Danger'
+ engineering_productivity: '~"Engineering Productivity" for CI, Danger',
+ ci_template: '~"ci::templates"'
}.freeze
# First-match win, so be sure to put more specific regex at the top...
CATEGORIES = {
@@ -176,6 +177,8 @@ module Gitlab
%r{(CODEOWNERS)} => :engineering_productivity,
%r{(tests.yml)} => :engineering_productivity,
+ %r{\Alib/gitlab/ci/templates} => :ci_template,
+
%r{\A(ee/)?spec/features/} => :test,
%r{\A(ee/)?spec/support/shared_examples/features/} => :test,
%r{\A(ee/)?spec/support/shared_contexts/features/} => :test,
@@ -214,6 +217,12 @@ module Gitlab
title.gsub(DRAFT_REGEX, '').gsub(/`/, '\\\`')
end
+ def draft_mr?
+ return false unless gitlab_helper
+
+ DRAFT_REGEX.match?(gitlab_helper.mr_json['title'])
+ end
+
def security_mr?
return false unless gitlab_helper
diff --git a/lib/gitlab/danger/roulette.rb b/lib/gitlab/danger/roulette.rb
index a6866868e6c..23f877b4e0f 100644
--- a/lib/gitlab/danger/roulette.rb
+++ b/lib/gitlab/danger/roulette.rb
@@ -52,6 +52,11 @@ module Gitlab
# Fetch an already picked backend maintainer, or pick one otherwise
spin.maintainer = backend_spin&.maintainer || spin_for_category(project, :backend, timezone_experiment: including_timezone).maintainer
end
+ when :ci_template
+ if spin.maintainer.nil?
+ # Fetch an already picked backend maintainer, or pick one otherwise
+ spin.maintainer = backend_spin&.maintainer || spin_for_category(project, :backend, timezone_experiment: including_timezone).maintainer
+ end
end
end
@@ -146,13 +151,19 @@ module Gitlab
%i[reviewer traintainer maintainer].map do |role|
spin_role_for_category(team, role, project, category)
end
+ hungry_reviewers = reviewers.select { |member| member.hungry }
+ hungry_traintainers = traintainers.select { |member| member.hungry }
# TODO: take CODEOWNERS into account?
# https://gitlab.com/gitlab-org/gitlab/issues/26723
- # Make traintainers have triple the chance to be picked as a reviewer
random = new_random(mr_source_branch)
- reviewer = spin_for_person(reviewers + traintainers + traintainers, random: random, timezone_experiment: timezone_experiment)
+
+ # Make hungry traintainers have 4x the chance to be picked as a reviewer
+ # Make traintainers have 3x the chance to be picked as a reviewer
+ # Make hungry reviewers have 2x the chance to be picked as a reviewer
+ weighted_reviewers = reviewers + hungry_reviewers + traintainers + traintainers + traintainers + hungry_traintainers
+ reviewer = spin_for_person(weighted_reviewers, random: random, timezone_experiment: timezone_experiment)
maintainer = spin_for_person(maintainers, random: random, timezone_experiment: timezone_experiment)
Spin.new(category, reviewer, maintainer, false, timezone_experiment)
diff --git a/lib/gitlab/danger/teammate.rb b/lib/gitlab/danger/teammate.rb
index ebd96be40d7..4481977db15 100644
--- a/lib/gitlab/danger/teammate.rb
+++ b/lib/gitlab/danger/teammate.rb
@@ -3,7 +3,7 @@
module Gitlab
module Danger
class Teammate
- attr_reader :options, :username, :name, :role, :projects, :available, :tz_offset_hours
+ attr_reader :options, :username, :name, :role, :projects, :available, :hungry, :tz_offset_hours
# The options data are produced by https://gitlab.com/gitlab-org/gitlab-roulette/-/blob/master/lib/team_member.rb
def initialize(options = {})
@@ -14,6 +14,7 @@ module Gitlab
@role = options['role']
@projects = options['projects']
@available = options['available']
+ @hungry = options['hungry']
@tz_offset_hours = options['tz_offset_hours']
end
@@ -31,10 +32,8 @@ module Gitlab
projects&.has_key?(name)
end
- # Traintainers also count as reviewers
def reviewer?(project, category, labels)
- has_capability?(project, category, :reviewer, labels) ||
- traintainer?(project, category, labels)
+ has_capability?(project, category, :reviewer, labels)
end
def traintainer?(project, category, labels)
diff --git a/lib/gitlab/data_builder/deployment.rb b/lib/gitlab/data_builder/deployment.rb
index 70587b3132a..87ebe832862 100644
--- a/lib/gitlab/data_builder/deployment.rb
+++ b/lib/gitlab/data_builder/deployment.rb
@@ -20,8 +20,8 @@ module Gitlab
environment: deployment.environment.name,
project: deployment.project.hook_attrs,
short_sha: deployment.short_sha,
- user: deployment.user.hook_attrs,
- user_url: Gitlab::UrlBuilder.build(deployment.user),
+ user: deployment.deployed_by.hook_attrs,
+ user_url: Gitlab::UrlBuilder.build(deployment.deployed_by),
commit_url: Gitlab::UrlBuilder.build(deployment.commit),
commit_title: deployment.commit.title
}
diff --git a/lib/gitlab/database.rb b/lib/gitlab/database.rb
index accc6330253..45d271a2fd4 100644
--- a/lib/gitlab/database.rb
+++ b/lib/gitlab/database.rb
@@ -92,10 +92,6 @@ module Gitlab
@version ||= database_version.match(/\A(?:PostgreSQL |)([^\s]+).*\z/)[1]
end
- def self.postgresql_9_or_less?
- version.to_f < 10
- end
-
def self.postgresql_minimum_supported_version?
version.to_f >= MINIMUM_POSTGRES_VERSION
end
@@ -127,28 +123,6 @@ module Gitlab
# ignore - happens when Rake tasks yet have to create a database, e.g. for testing
end
- # map some of the function names that changed between PostgreSQL 9 and 10
- # https://wiki.postgresql.org/wiki/New_in_postgres_10
- def self.pg_wal_lsn_diff
- Gitlab::Database.postgresql_9_or_less? ? 'pg_xlog_location_diff' : 'pg_wal_lsn_diff'
- end
-
- def self.pg_current_wal_insert_lsn
- Gitlab::Database.postgresql_9_or_less? ? 'pg_current_xlog_insert_location' : 'pg_current_wal_insert_lsn'
- end
-
- def self.pg_last_wal_receive_lsn
- Gitlab::Database.postgresql_9_or_less? ? 'pg_last_xlog_receive_location' : 'pg_last_wal_receive_lsn'
- end
-
- def self.pg_last_wal_replay_lsn
- Gitlab::Database.postgresql_9_or_less? ? 'pg_last_xlog_replay_location' : 'pg_last_wal_replay_lsn'
- end
-
- def self.pg_last_xact_replay_timestamp
- 'pg_last_xact_replay_timestamp'
- end
-
def self.nulls_last_order(field, direction = 'ASC')
Arel.sql("#{field} #{direction} NULLS LAST")
end
@@ -276,6 +250,20 @@ module Gitlab
false
end
+ def self.system_id
+ row = connection.execute('SELECT system_identifier FROM pg_control_system()').first
+
+ row['system_identifier']
+ end
+
+ def self.get_write_location(ar_connection)
+ row = ar_connection
+ .select_all("SELECT pg_current_wal_insert_lsn()::text AS location")
+ .first
+
+ row['location'] if row
+ end
+
private_class_method :database_version
def self.add_post_migrate_path_to_rails(force: false)
diff --git a/lib/gitlab/database/batch_count.rb b/lib/gitlab/database/batch_count.rb
index 1762b81b7d8..11d9881aac2 100644
--- a/lib/gitlab/database/batch_count.rb
+++ b/lib/gitlab/database/batch_count.rb
@@ -8,15 +8,20 @@
# In order to not use a possible complex time consuming query when calculating min and max for batch_distinct_count
# the start and finish can be sent specifically
#
+# Grouped relations can be used as well. However, the preferred batch count should be around 10K because group by count is more expensive.
+#
# See https://gitlab.com/gitlab-org/gitlab/-/merge_requests/22705
#
# Examples:
# extend ::Gitlab::Database::BatchCount
# batch_count(User.active)
# batch_count(::Clusters::Cluster.aws_installed.enabled, :cluster_id)
+# batch_count(Namespace.group(:type))
# batch_distinct_count(::Project, :creator_id)
# batch_distinct_count(::Project.with_active_services.service_desk_enabled.where(time_period), start: ::User.minimum(:id), finish: ::User.maximum(:id))
+# batch_distinct_count(Project.group(:visibility_level), :creator_id)
# batch_sum(User, :sign_in_count)
+# batch_sum(Issue.group(:state_id), :weight))
module Gitlab
module Database
module BatchCount
@@ -77,34 +82,45 @@ module Gitlab
raise "Batch counting expects positive values only for #{@column}" if start < 0 || finish < 0
return FALLBACK if unwanted_configuration?(finish, batch_size, start)
- counter = 0
+ results = nil
batch_start = start
while batch_start <= finish
+ batch_relation = build_relation_batch(batch_start, batch_start + batch_size, mode)
begin
- counter += batch_fetch(batch_start, batch_start + batch_size, mode)
+ results = merge_results(results, batch_relation.send(@operation, *@operation_args)) # rubocop:disable GitlabSecurity/PublicSend
batch_start += batch_size
- rescue ActiveRecord::QueryCanceled
+ rescue ActiveRecord::QueryCanceled => error
# retry with a safe batch size & warmer cache
if batch_size >= 2 * MIN_REQUIRED_BATCH_SIZE
batch_size /= 2
else
+ log_canceled_batch_fetch(batch_start, mode, batch_relation.to_sql, error)
return FALLBACK
end
end
sleep(SLEEP_TIME_IN_SECONDS)
end
- counter
+ results
end
- def batch_fetch(start, finish, mode)
- # rubocop:disable GitlabSecurity/PublicSend
- @relation.select(@column).public_send(mode).where(between_condition(start, finish)).send(@operation, *@operation_args)
+ def merge_results(results, object)
+ return object unless results
+
+ if object.is_a?(Hash)
+ results.merge!(object) { |_, a, b| a + b }
+ else
+ results + object
+ end
end
private
+ def build_relation_batch(start, finish, mode)
+ @relation.select(@column).public_send(mode).where(between_condition(start, finish)) # rubocop:disable GitlabSecurity/PublicSend
+ end
+
def batch_size_for_mode_and_operation(mode, operation)
return DEFAULT_SUM_BATCH_SIZE if operation == :sum
@@ -118,11 +134,11 @@ module Gitlab
end
def actual_start(start)
- start || @relation.minimum(@column) || 0
+ start || @relation.unscope(:group, :having).minimum(@column) || 0
end
def actual_finish(finish)
- finish || @relation.maximum(@column) || 0
+ finish || @relation.unscope(:group, :having).maximum(@column) || 0
end
def check_mode!(mode)
@@ -130,6 +146,20 @@ module Gitlab
raise 'Use distinct count for optimized distinct counting' if @relation.limit(1).distinct_value.present? && mode != :distinct
raise 'Use distinct count only with non id fields' if @column == :id && mode == :distinct
end
+
+ def log_canceled_batch_fetch(batch_start, mode, query, error)
+ Gitlab::AppJsonLogger
+ .error(
+ event: 'batch_count',
+ relation: @relation.table_name,
+ operation: @operation,
+ operation_args: @operation_args,
+ start: batch_start,
+ mode: mode,
+ query: query,
+ message: "Query has been canceled with message: #{error.message}"
+ )
+ end
end
end
end
diff --git a/lib/gitlab/database/bulk_update.rb b/lib/gitlab/database/bulk_update.rb
new file mode 100644
index 00000000000..1403d561890
--- /dev/null
+++ b/lib/gitlab/database/bulk_update.rb
@@ -0,0 +1,168 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Database
+ # Constructs queries of the form:
+ #
+ # with cte(a, b, c) as (
+ # select * from (values (:x, :y, :z), (:q, :r, :s)) as t
+ # )
+ # update table set b = cte.b, c = cte.c where a = cte.a
+ #
+ # Which is useful if you want to update a set of records in a single query
+ # but cannot express the update as a calculation (i.e. you have arbitrary
+ # updates to perform).
+ #
+ # The requirements are that the table must have an ID column used to
+ # identify the rows to be updated.
+ #
+ # Usage:
+ #
+ # mapping = {
+ # issue_a => { title: 'This title', relative_position: 100 },
+ # issue_b => { title: 'That title', relative_position: 173 }
+ # }
+ #
+ # ::Gitlab::Database::BulkUpdate.execute(%i[title relative_position], mapping)
+ #
+ # Note that this is a very low level tool, and operates on the raw column
+ # values. Enums/state fields must be translated into their underlying
+ # representations, for example, and no hooks will be called.
+ #
+ module BulkUpdate
+ LIST_SEPARATOR = ', '
+
+ class Setter
+ include Gitlab::Utils::StrongMemoize
+
+ def initialize(model, columns, mapping)
+ @table_name = model.table_name
+ @connection = model.connection
+ @columns = self.class.column_definitions(model, columns)
+ @mapping = self.class.value_mapping(mapping)
+ end
+
+ def update!
+ if without_prepared_statement?
+ # A workaround for https://github.com/rails/rails/issues/24893
+ # When prepared statements are prevented (such as when using the
+ # query counter or in omnibus by default), we cannot call
+ # `exec_update`, since that will discard the bindings.
+ connection.send(:exec_no_cache, sql, log_name, params) # rubocop: disable GitlabSecurity/PublicSend
+ else
+ connection.exec_update(sql, log_name, params)
+ end
+ end
+
+ def self.column_definitions(model, columns)
+ raise ArgumentError, 'invalid columns' if columns.blank? || columns.any? { |c| !c.is_a?(Symbol) }
+ raise ArgumentError, 'cannot set ID' if columns.include?(:id)
+
+ ([:id] | columns).map { |name| column_definition(model, name) }
+ end
+
+ def self.column_definition(model, name)
+ definition = model.column_for_attribute(name)
+ raise ArgumentError, "Unknown column: #{name}" unless definition.type
+
+ definition
+ end
+
+ def self.value_mapping(mapping)
+ raise ArgumentError, 'invalid mapping' if mapping.blank?
+ raise ArgumentError, 'invalid mapping value' if mapping.any? { |_k, v| !v.is_a?(Hash) }
+
+ mapping
+ end
+
+ private
+
+ attr_reader :table_name, :connection, :columns, :mapping
+
+ def log_name
+ strong_memoize(:log_name) do
+ "BulkUpdate #{table_name} #{columns.drop(1).map(&:name)}:#{mapping.size}"
+ end
+ end
+
+ def params
+ mapping.flat_map do |k, v|
+ obj_id = k.try(:id) || k
+ v = v.merge(id: obj_id)
+ columns.map { |c| query_attribute(c, k, v.with_indifferent_access) }
+ end
+ end
+
+ # A workaround for https://github.com/rails/rails/issues/24893
+ # We need to detect if prepared statements have been disabled.
+ def without_prepared_statement?
+ strong_memoize(:without_prepared_statement) do
+ connection.send(:without_prepared_statement?, [1]) # rubocop: disable GitlabSecurity/PublicSend
+ end
+ end
+
+ def query_attribute(column, key, values)
+ value = values[column.name]
+ key[column.name] = value if key.try(:id) # optimistic update
+ ActiveRecord::Relation::QueryAttribute.from_user(nil, value, ActiveModel::Type.lookup(column.type))
+ end
+
+ def values
+ counter = 0
+ typed = false
+
+ mapping.map do |k, v|
+ binds = columns.map do |c|
+ bind = "$#{counter += 1}"
+ # PG is not great at inferring types - help it for the first row.
+ bind += "::#{c.sql_type}" unless typed
+ bind
+ end
+ typed = true
+
+ "(#{list_of(binds)})"
+ end
+ end
+
+ def list_of(list)
+ list.join(LIST_SEPARATOR)
+ end
+
+ def sql
+ <<~SQL
+ WITH cte(#{list_of(cte_columns)}) AS (VALUES #{list_of(values)})
+ UPDATE #{table_name} SET #{list_of(updates)} FROM cte WHERE cte_id = id
+ SQL
+ end
+
+ def column_names
+ strong_memoize(:column_names) { columns.map(&:name) }
+ end
+
+ def cte_columns
+ strong_memoize(:cte_columns) do
+ column_names.map do |c|
+ connection.quote_column_name("cte_#{c}")
+ end
+ end
+ end
+
+ def updates
+ column_names.zip(cte_columns).drop(1).map do |dest, src|
+ "#{connection.quote_column_name(dest)} = cte.#{src}"
+ end
+ end
+ end
+
+ def self.execute(columns, mapping, &to_class)
+ raise ArgumentError if mapping.blank?
+
+ entries_by_class = mapping.group_by { |k, v| block_given? ? to_class.call(k) : k.class }
+
+ entries_by_class.each do |model, entries|
+ Setter.new(model, columns, entries).update!
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/database/concurrent_reindex.rb b/lib/gitlab/database/concurrent_reindex.rb
deleted file mode 100644
index 485ab35e55d..00000000000
--- a/lib/gitlab/database/concurrent_reindex.rb
+++ /dev/null
@@ -1,143 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module Database
- class ConcurrentReindex
- include Gitlab::Utils::StrongMemoize
- include MigrationHelpers
-
- ReindexError = Class.new(StandardError)
-
- PG_IDENTIFIER_LENGTH = 63
- TEMPORARY_INDEX_PREFIX = 'tmp_reindex_'
- REPLACED_INDEX_PREFIX = 'old_reindex_'
-
- attr_reader :index_name, :logger
-
- def initialize(index_name, logger:)
- @index_name = index_name
- @logger = logger
- end
-
- def execute
- raise ReindexError, "index #{index_name} does not exist" unless index_exists?
-
- raise ReindexError, 'UNIQUE indexes are currently not supported' if index_unique?
-
- logger.debug("dropping dangling index from previous run: #{replacement_index_name}")
- remove_replacement_index
-
- begin
- create_replacement_index
-
- unless replacement_index_valid?
- message = 'replacement index was created as INVALID'
- logger.error("#{message}, cleaning up")
- raise ReindexError, "failed to reindex #{index_name}: #{message}"
- end
-
- swap_replacement_index
- rescue Gitlab::Database::WithLockRetries::AttemptsExhaustedError => e
- logger.error('failed to obtain the required database locks to swap the indexes, cleaning up')
- raise ReindexError, e.message
- rescue ActiveRecord::ActiveRecordError, PG::Error => e
- logger.error("database error while attempting reindex of #{index_name}: #{e.message}")
- raise ReindexError, e.message
- ensure
- logger.info("dropping unneeded replacement index: #{replacement_index_name}")
- remove_replacement_index
- end
- end
-
- private
-
- def connection
- @connection ||= ActiveRecord::Base.connection
- end
-
- def replacement_index_name
- @replacement_index_name ||= constrained_index_name(TEMPORARY_INDEX_PREFIX)
- end
-
- def index
- strong_memoize(:index) do
- find_index(index_name)
- end
- end
-
- def index_exists?
- !index.nil?
- end
-
- def index_unique?
- index.indisunique
- end
-
- def constrained_index_name(prefix)
- "#{prefix}#{index_name}".slice(0, PG_IDENTIFIER_LENGTH)
- end
-
- def create_replacement_index
- create_replacement_index_statement = index.indexdef
- .sub(/CREATE INDEX/, 'CREATE INDEX CONCURRENTLY')
- .sub(/#{index_name}/, replacement_index_name)
-
- logger.info("creating replacement index #{replacement_index_name}")
- logger.debug("replacement index definition: #{create_replacement_index_statement}")
-
- disable_statement_timeout do
- connection.execute(create_replacement_index_statement)
- end
- end
-
- def replacement_index_valid?
- find_index(replacement_index_name).indisvalid
- end
-
- def find_index(index_name)
- record = connection.select_one(<<~SQL)
- SELECT
- pg_index.indisunique,
- pg_index.indisvalid,
- pg_indexes.indexdef
- FROM pg_index
- INNER JOIN pg_class ON pg_class.oid = pg_index.indexrelid
- INNER JOIN pg_namespace ON pg_class.relnamespace = pg_namespace.oid
- INNER JOIN pg_indexes ON pg_class.relname = pg_indexes.indexname
- WHERE pg_namespace.nspname = 'public'
- AND pg_class.relname = #{connection.quote(index_name)}
- SQL
-
- OpenStruct.new(record) if record
- end
-
- def swap_replacement_index
- replaced_index_name = constrained_index_name(REPLACED_INDEX_PREFIX)
-
- logger.info("swapping replacement index #{replacement_index_name} with #{index_name}")
-
- with_lock_retries do
- rename_index(index_name, replaced_index_name)
- rename_index(replacement_index_name, index_name)
- rename_index(replaced_index_name, replacement_index_name)
- end
- end
-
- def rename_index(old_index_name, new_index_name)
- connection.execute("ALTER INDEX #{old_index_name} RENAME TO #{new_index_name}")
- end
-
- def remove_replacement_index
- disable_statement_timeout do
- connection.execute("DROP INDEX CONCURRENTLY IF EXISTS #{replacement_index_name}")
- end
- end
-
- def with_lock_retries(&block)
- arguments = { klass: self.class, logger: logger }
-
- Gitlab::Database::WithLockRetries.new(arguments).run(raise_on_exhaustion: true, &block)
- end
- end
- end
-end
diff --git a/lib/gitlab/database/count/reltuples_count_strategy.rb b/lib/gitlab/database/count/reltuples_count_strategy.rb
index e226ed7613a..89190320cf9 100644
--- a/lib/gitlab/database/count/reltuples_count_strategy.rb
+++ b/lib/gitlab/database/count/reltuples_count_strategy.rb
@@ -74,8 +74,9 @@ module Gitlab
def get_statistics(table_names, check_statistics: true)
time = 6.hours.ago
- query = PgClass.joins("LEFT JOIN pg_stat_user_tables USING (relname)")
+ query = PgClass.joins("LEFT JOIN pg_stat_user_tables ON pg_stat_user_tables.relid = pg_class.oid")
.where(relname: table_names)
+ .where('schemaname = current_schema()')
.select('pg_class.relname AS table_name, reltuples::bigint AS estimate')
if check_statistics
diff --git a/lib/gitlab/database/migration_helpers.rb b/lib/gitlab/database/migration_helpers.rb
index 723f0f6a308..66b6ce1ec55 100644
--- a/lib/gitlab/database/migration_helpers.rb
+++ b/lib/gitlab/database/migration_helpers.rb
@@ -176,7 +176,7 @@ module Gitlab
name: name.presence || concurrent_foreign_key_name(source, column)
}
- if foreign_key_exists?(source, target, options)
+ if foreign_key_exists?(source, target, **options)
warning_message = "Foreign key not created because it exists already " \
"(this may be due to an aborted migration or similar): " \
"source: #{source}, target: #{target}, column: #{options[:column]}, "\
@@ -330,13 +330,13 @@ module Gitlab
# * +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, &block)
+ def with_lock_retries(*args, **kwargs, &block)
merged_args = {
klass: self.class,
logger: Gitlab::BackgroundMigration::Logger
- }.merge(args)
+ }.merge(kwargs)
- Gitlab::Database::WithLockRetries.new(merged_args).run(&block)
+ Gitlab::Database::WithLockRetries.new(**merged_args).run(&block)
end
def true_value
@@ -544,6 +544,16 @@ module Gitlab
rename_column_concurrently(table, column, temp_column, type: new_type, type_cast_function: type_cast_function, batch_column_name: batch_column_name)
end
+ # Reverses operations performed by change_column_type_concurrently.
+ #
+ # table - The table containing the column.
+ # column - The name of the column to change.
+ def undo_change_column_type_concurrently(table, column)
+ temp_column = "#{column}_for_type_change"
+
+ undo_rename_column_concurrently(table, column, temp_column)
+ end
+
# Performs cleanup of a concurrent type change.
#
# table - The table containing the column.
@@ -560,6 +570,65 @@ module Gitlab
end
end
+ # Reverses operations performed by cleanup_concurrent_column_type_change.
+ #
+ # table - The table containing the column.
+ # column - The name of the column to change.
+ # old_type - The type of the original column used with change_column_type_concurrently.
+ # type_cast_function - Required if the conversion back to the original type is not automatic
+ # batch_column_name - option for tables without a primary key, in this case
+ # another unique integer column can be used. Example: :user_id
+ def undo_cleanup_concurrent_column_type_change(table, column, old_type, type_cast_function: nil, batch_column_name: :id)
+ temp_column = "#{column}_for_type_change"
+
+ # Using a descriptive name that includes orinal column's name risks
+ # taking us above the 63 character limit, so we use a hash
+ identifier = "#{table}_#{column}_for_type_change"
+ hashed_identifier = Digest::SHA256.hexdigest(identifier).first(10)
+ temp_undo_cleanup_column = "tmp_undo_cleanup_column_#{hashed_identifier}"
+
+ unless column_exists?(table, batch_column_name)
+ raise "Column #{batch_column_name} does not exist on #{table}"
+ end
+
+ if transaction_open?
+ raise 'undo_cleanup_concurrent_column_type_change can not be run inside a transaction'
+ end
+
+ check_trigger_permissions!(table)
+
+ begin
+ create_column_from(
+ table,
+ column,
+ temp_undo_cleanup_column,
+ type: old_type,
+ batch_column_name: batch_column_name,
+ type_cast_function: type_cast_function
+ )
+
+ transaction do
+ # This has to be performed in a transaction as otherwise we might
+ # have inconsistent data.
+ rename_column(table, column, temp_column)
+ rename_column(table, temp_undo_cleanup_column, column)
+
+ install_rename_triggers(table, column, temp_column)
+ end
+ rescue
+ # create_column_from can not run inside a transaction, which means
+ # that there is a risk that if any of the operations that follow it
+ # fail, we'll be left with an inconsistent schema
+ # For those reasons, we make sure that we drop temp_undo_cleanup_column
+ # if an error is caught
+ if column_exists?(table, temp_undo_cleanup_column)
+ remove_column(table, temp_undo_cleanup_column)
+ end
+
+ raise
+ end
+ end
+
# Cleans up a concurrent column name.
#
# This method takes care of removing previously installed triggers as well
@@ -882,7 +951,7 @@ module Gitlab
# column.
opclasses[new] = opclasses.delete(old) if opclasses[old]
- options[:opclasses] = opclasses
+ options[:opclass] = opclasses
end
add_concurrent_index(table, new_columns, options)
@@ -994,10 +1063,10 @@ into similar problems in the future (e.g. when new tables are created).
def postgres_exists_by_name?(table, name)
index_sql = <<~SQL
SELECT COUNT(*)
- FROM pg_index
- JOIN pg_class i ON (indexrelid=i.oid)
- JOIN pg_class t ON (indrelid=t.oid)
- WHERE i.relname = '#{name}' AND t.relname = '#{table}'
+ FROM pg_catalog.pg_indexes
+ WHERE schemaname = #{connection.quote(current_schema)}
+ AND tablename = #{connection.quote(table)}
+ AND indexname = #{connection.quote(name)}
SQL
connection.select_value(index_sql).to_i > 0
@@ -1053,11 +1122,15 @@ into similar problems in the future (e.g. when new tables are created).
# the table name in addition to using the constraint_name
check_sql = <<~SQL
SELECT COUNT(*)
- FROM pg_constraint
- JOIN pg_class ON pg_constraint.conrelid = pg_class.oid
- WHERE pg_constraint.contype = 'c'
- AND pg_constraint.conname = '#{constraint_name}'
- AND pg_class.relname = '#{table}'
+ 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
@@ -1147,6 +1220,64 @@ into similar problems in the future (e.g. when new tables are created).
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(
@@ -1274,6 +1405,37 @@ into similar problems in the future (e.g. when new tables are created).
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
+
+ connection.exec_query(check_sql)
+ end
+
def statement_timeout_disabled?
# This is a string of the form "100ms" or "0" when disabled
connection.select_value('SHOW statement_timeout') == "0"
@@ -1284,8 +1446,9 @@ into similar problems in the future (e.g. when new tables are created).
check_sql = <<~SQL
SELECT c.is_nullable
FROM information_schema.columns c
- WHERE c.table_name = '#{table}'
- AND c.column_name = '#{column}'
+ WHERE c.table_schema = #{connection.quote(current_schema)}
+ AND c.table_name = #{connection.quote(table)}
+ AND c.column_name = #{connection.quote(column)}
SQL
connection.select_value(check_sql) == 'YES'
@@ -1352,6 +1515,7 @@ into similar problems in the future (e.g. when new tables are created).
copy_indexes(table, old, new)
copy_foreign_keys(table, old, new)
+ copy_check_constraints(table, old, new)
end
def validate_timestamp_column_name!(column_name)
diff --git a/lib/gitlab/database/partitioning/partition_creator.rb b/lib/gitlab/database/partitioning/partition_creator.rb
index 4c1b13fe3b5..547e0b9b957 100644
--- a/lib/gitlab/database/partitioning/partition_creator.rb
+++ b/lib/gitlab/database/partitioning/partition_creator.rb
@@ -72,10 +72,10 @@ module Gitlab
end
def with_lock_retries(&block)
- Gitlab::Database::WithLockRetries.new({
+ Gitlab::Database::WithLockRetries.new(
klass: self.class,
logger: Gitlab::AppLogger
- }).run(&block)
+ ).run(&block)
end
def connection
diff --git a/lib/gitlab/database/partitioning_migration_helpers/backfill_partitioned_table.rb b/lib/gitlab/database/partitioning_migration_helpers/backfill_partitioned_table.rb
index f9ad1e60776..17a42d997e6 100644
--- a/lib/gitlab/database/partitioning_migration_helpers/backfill_partitioned_table.rb
+++ b/lib/gitlab/database/partitioning_migration_helpers/backfill_partitioned_table.rb
@@ -11,8 +11,6 @@ module Gitlab
PAUSE_SECONDS = 0.25
def perform(start_id, stop_id, source_table, partitioned_table, source_column)
- return unless Feature.enabled?(:backfill_partitioned_audit_events, default_enabled: true)
-
if transaction_open?
raise "Aborting job to backfill partitioned #{source_table} table! Do not run this job in a transaction block!"
end
diff --git a/lib/gitlab/database/postgres_index.rb b/lib/gitlab/database/postgres_index.rb
new file mode 100644
index 00000000000..2a9f23f0098
--- /dev/null
+++ b/lib/gitlab/database/postgres_index.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Database
+ class PostgresIndex < ActiveRecord::Base
+ self.table_name = 'postgres_indexes'
+ self.primary_key = 'identifier'
+
+ scope :by_identifier, ->(identifier) do
+ raise ArgumentError, "Index name is not fully qualified with a schema: #{identifier}" unless identifier =~ /^\w+\.\w+$/
+
+ find(identifier)
+ end
+
+ # A 'regular' index is a non-unique index,
+ # that does not serve an exclusion constraint and
+ # is defined on a table that is not partitioned.
+ scope :regular, -> { where(unique: false, partitioned: false, exclusion: false)}
+
+ scope :random_few, ->(how_many) do
+ limit(how_many).order(Arel.sql('RANDOM()'))
+ end
+
+ scope :not_match, ->(regex) { where("name !~ ?", regex)}
+
+ def to_s
+ name
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/database/reindexing.rb b/lib/gitlab/database/reindexing.rb
new file mode 100644
index 00000000000..074752fe75b
--- /dev/null
+++ b/lib/gitlab/database/reindexing.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Database
+ module Reindexing
+ def self.perform(index_selector)
+ Coordinator.new(index_selector).perform
+ end
+
+ def self.candidate_indexes
+ Gitlab::Database::PostgresIndex
+ .regular
+ .not_match("^#{ConcurrentReindex::TEMPORARY_INDEX_PREFIX}")
+ .not_match("^#{ConcurrentReindex::REPLACED_INDEX_PREFIX}")
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/database/reindexing/concurrent_reindex.rb b/lib/gitlab/database/reindexing/concurrent_reindex.rb
new file mode 100644
index 00000000000..fd3dca88567
--- /dev/null
+++ b/lib/gitlab/database/reindexing/concurrent_reindex.rb
@@ -0,0 +1,127 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Database
+ module Reindexing
+ class ConcurrentReindex
+ include Gitlab::Utils::StrongMemoize
+
+ ReindexError = Class.new(StandardError)
+
+ PG_IDENTIFIER_LENGTH = 63
+ TEMPORARY_INDEX_PREFIX = 'tmp_reindex_'
+ REPLACED_INDEX_PREFIX = 'old_reindex_'
+ STATEMENT_TIMEOUT = 6.hours
+
+ attr_reader :index, :logger
+
+ def initialize(index, logger: Gitlab::AppLogger)
+ @index = index
+ @logger = logger
+ end
+
+ def perform
+ raise ReindexError, 'UNIQUE indexes are currently not supported' if index.unique?
+ raise ReindexError, 'partitioned indexes are currently not supported' if index.partitioned?
+ raise ReindexError, 'indexes serving an exclusion constraint are currently not supported' if index.exclusion?
+ raise ReindexError, 'index is a left-over temporary index from a previous reindexing run' if index.name.start_with?(TEMPORARY_INDEX_PREFIX, REPLACED_INDEX_PREFIX)
+
+ logger.info "Starting reindex of #{index}"
+
+ with_rebuilt_index do |replacement_index|
+ swap_index(replacement_index)
+ end
+ end
+
+ private
+
+ def with_rebuilt_index
+ if Gitlab::Database::PostgresIndex.find_by(schema: index.schema, name: replacement_index_name)
+ logger.debug("dropping dangling index from previous run (if it exists): #{replacement_index_name}")
+ remove_index(index.schema, replacement_index_name)
+ end
+
+ create_replacement_index_statement = index.definition
+ .sub(/CREATE INDEX #{index.name}/, "CREATE INDEX CONCURRENTLY #{replacement_index_name}")
+
+ logger.info("creating replacement index #{replacement_index_name}")
+ logger.debug("replacement index definition: #{create_replacement_index_statement}")
+
+ set_statement_timeout do
+ connection.execute(create_replacement_index_statement)
+ end
+
+ replacement_index = Gitlab::Database::PostgresIndex.find_by(schema: index.schema, name: replacement_index_name)
+
+ unless replacement_index.valid_index?
+ message = 'replacement index was created as INVALID'
+ logger.error("#{message}, cleaning up")
+ raise ReindexError, "failed to reindex #{index}: #{message}"
+ end
+
+ yield replacement_index
+ ensure
+ begin
+ remove_index(index.schema, replacement_index_name)
+ rescue => e
+ logger.error(e)
+ end
+ end
+
+ def swap_index(replacement_index)
+ logger.info("swapping replacement index #{replacement_index} with #{index}")
+
+ with_lock_retries do
+ rename_index(index.schema, index.name, replaced_index_name)
+ rename_index(replacement_index.schema, replacement_index.name, index.name)
+ rename_index(index.schema, replaced_index_name, replacement_index.name)
+ end
+ end
+
+ def rename_index(schema, old_index_name, new_index_name)
+ connection.execute(<<~SQL)
+ ALTER INDEX #{quote_table_name(schema)}.#{quote_table_name(old_index_name)}
+ RENAME TO #{quote_table_name(new_index_name)}
+ SQL
+ end
+
+ def remove_index(schema, name)
+ logger.info("Removing index #{schema}.#{name}")
+
+ set_statement_timeout do
+ connection.execute(<<~SQL)
+ DROP INDEX CONCURRENTLY
+ IF EXISTS #{quote_table_name(schema)}.#{quote_table_name(name)}
+ SQL
+ end
+ end
+
+ def replacement_index_name
+ @replacement_index_name ||= "#{TEMPORARY_INDEX_PREFIX}#{index.indexrelid}"
+ end
+
+ def replaced_index_name
+ @replaced_index_name ||= "#{REPLACED_INDEX_PREFIX}#{index.indexrelid}"
+ end
+
+ def with_lock_retries(&block)
+ arguments = { klass: self.class, logger: logger }
+
+ Gitlab::Database::WithLockRetries.new(**arguments).run(raise_on_exhaustion: true, &block)
+ end
+
+ def set_statement_timeout
+ execute("SET statement_timeout TO '%ds'" % STATEMENT_TIMEOUT)
+ yield
+ ensure
+ execute('RESET statement_timeout')
+ end
+
+ delegate :execute, :quote_table_name, to: :connection
+ def connection
+ @connection ||= ActiveRecord::Base.connection
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/database/reindexing/coordinator.rb b/lib/gitlab/database/reindexing/coordinator.rb
new file mode 100644
index 00000000000..0957f43e166
--- /dev/null
+++ b/lib/gitlab/database/reindexing/coordinator.rb
@@ -0,0 +1,41 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Database
+ module Reindexing
+ class Coordinator
+ include ExclusiveLeaseGuard
+
+ # Maximum lease time for the global Redis lease
+ # This should be higher than the maximum time for any
+ # long running step in the reindexing process (compare with
+ # statement timeouts).
+ TIMEOUT_PER_ACTION = 1.day
+
+ attr_reader :indexes
+
+ def initialize(indexes)
+ @indexes = indexes
+ end
+
+ def perform
+ indexes.each do |index|
+ # This obtains a global lease such that there's
+ # only one live reindexing process at a time.
+ try_obtain_lease do
+ ReindexAction.keep_track_of(index) do
+ ConcurrentReindex.new(index).perform
+ end
+ end
+ end
+ end
+
+ private
+
+ def lease_timeout
+ TIMEOUT_PER_ACTION
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/database/reindexing/reindex_action.rb b/lib/gitlab/database/reindexing/reindex_action.rb
new file mode 100644
index 00000000000..0928ef90e5d
--- /dev/null
+++ b/lib/gitlab/database/reindexing/reindex_action.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Database
+ module Reindexing
+ class ReindexAction < ActiveRecord::Base
+ self.table_name = 'postgres_reindex_actions'
+
+ enum state: { started: 0, finished: 1, failed: 2 }
+
+ def self.keep_track_of(index, &block)
+ action = create!(
+ index_identifier: index.identifier,
+ action_start: Time.zone.now,
+ ondisk_size_bytes_start: index.ondisk_size_bytes
+ )
+
+ yield
+
+ action.state = :finished
+ rescue
+ action.state = :failed
+ raise
+ ensure
+ index.reload # rubocop:disable Cop/ActiveRecordAssociationReload
+
+ action.action_end = Time.zone.now
+ action.ondisk_size_bytes_end = index.ondisk_size_bytes
+
+ action.save!
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/database/schema_helpers.rb b/lib/gitlab/database/schema_helpers.rb
index dda4d8eecdb..3d929c62933 100644
--- a/lib/gitlab/database/schema_helpers.rb
+++ b/lib/gitlab/database/schema_helpers.rb
@@ -32,11 +32,14 @@ module Gitlab
def trigger_exists?(table_name, name)
connection.select_value(<<~SQL)
SELECT 1
- FROM pg_trigger
- INNER JOIN pg_class
- ON pg_trigger.tgrelid = pg_class.oid
- WHERE pg_class.relname = '#{table_name}'
- AND pg_trigger.tgname = '#{name}'
+ FROM pg_catalog.pg_trigger trgr
+ INNER JOIN pg_catalog.pg_class rel
+ ON trgr.tgrelid = rel.oid
+ INNER JOIN pg_catalog.pg_namespace nsp
+ ON nsp.oid = rel.relnamespace
+ WHERE nsp.nspname = #{connection.quote(current_schema)}
+ AND rel.relname = #{connection.quote(table_name)}
+ AND trgr.tgname = #{connection.quote(name)}
SQL
end
@@ -68,10 +71,10 @@ module Gitlab
end
def with_lock_retries(&block)
- Gitlab::Database::WithLockRetries.new({
+ Gitlab::Database::WithLockRetries.new(
klass: self.class,
logger: Gitlab::BackgroundMigration::Logger
- }).run(&block)
+ ).run(&block)
end
def assert_not_in_transaction_block(scope:)
diff --git a/lib/gitlab/database/similarity_score.rb b/lib/gitlab/database/similarity_score.rb
index 2633c29438a..ff78fd0218c 100644
--- a/lib/gitlab/database/similarity_score.rb
+++ b/lib/gitlab/database/similarity_score.rb
@@ -6,6 +6,11 @@ module Gitlab
EMPTY_STRING = Arel.sql("''").freeze
EXPRESSION_ON_INVALID_INPUT = Arel::Nodes::NamedFunction.new('CAST', [Arel.sql('0').as('integer')]).freeze
DEFAULT_MULTIPLIER = 1
+ DISPLAY_NAME = self.name.underscore.freeze
+
+ # Adds a "magic" comment in the generated SQL expression in order to be able to tell if we're sorting by similarity.
+ # Example: /* gitlab/database/similarity_score */ SIMILARITY(COALESCE...
+ SIMILARITY_FUNCTION_CALL_WITH_ANNOTATION = "/* #{DISPLAY_NAME} */ SIMILARITY".freeze
# This method returns an Arel expression that can be used in an ActiveRecord query to order the resultset by similarity.
#
@@ -74,6 +79,10 @@ module Gitlab
end
end
+ def self.order_by_similarity?(arel_query)
+ arel_query.to_sql.include?(SIMILARITY_FUNCTION_CALL_WITH_ANNOTATION)
+ end
+
# (SIMILARITY(COALESCE(column, ''), 'search_string') * CAST(multiplier AS numeric))
def self.rule_to_arel(search, rule)
Arel::Nodes::Grouping.new(
@@ -91,7 +100,7 @@ module Gitlab
# SIMILARITY(COALESCE(column, ''), 'search_string')
def self.similarity_function_call(search, column)
- Arel::Nodes::NamedFunction.new('SIMILARITY', [column, Arel.sql(search)])
+ Arel::Nodes::NamedFunction.new(SIMILARITY_FUNCTION_CALL_WITH_ANNOTATION, [column, Arel.sql(search)])
end
# CAST(multiplier AS numeric)
diff --git a/lib/gitlab/database/with_lock_retries.rb b/lib/gitlab/database/with_lock_retries.rb
index a9c86e4e267..3fb52d786ad 100644
--- a/lib/gitlab/database/with_lock_retries.rb
+++ b/lib/gitlab/database/with_lock_retries.rb
@@ -95,7 +95,7 @@ module Gitlab
run_block_with_transaction
rescue ActiveRecord::LockWaitTimeout
if retry_with_lock_timeout?
- disable_idle_in_transaction_timeout
+ disable_idle_in_transaction_timeout if ActiveRecord::Base.connection.transaction_open?
wait_until_next_retry
reset_db_settings
@@ -149,7 +149,7 @@ module Gitlab
log(message: "Couldn't acquire lock to perform the migration", current_iteration: current_iteration)
log(message: "Executing the migration without lock timeout", current_iteration: current_iteration)
- execute("SET LOCAL lock_timeout TO '0'")
+ disable_lock_timeout if ActiveRecord::Base.connection.transaction_open?
run_block
@@ -184,6 +184,10 @@ module Gitlab
execute("SET LOCAL idle_in_transaction_session_timeout TO '0'")
end
+ def disable_lock_timeout
+ execute("SET LOCAL lock_timeout TO '0'")
+ end
+
def reset_db_settings
execute('RESET idle_in_transaction_session_timeout; RESET lock_timeout')
end
diff --git a/lib/gitlab/design_management/copy_design_collection_model_attributes.yml b/lib/gitlab/design_management/copy_design_collection_model_attributes.yml
new file mode 100644
index 00000000000..1d341e6520e
--- /dev/null
+++ b/lib/gitlab/design_management/copy_design_collection_model_attributes.yml
@@ -0,0 +1,43 @@
+# This file exists to lock the attributes of Design Management models
+# that get copied in `DesignManagement::CopyDesignCollection::CopyService`
+# to specific schemas.
+#
+# This allows us to perform sanity checks and alert when there are changes
+# to the schema by running expectations against the lists in this file
+# and the actual schema of the models in `copy_designs_service_spec.rb`.
+#
+# If you are here because you received a failed test in
+# `copy_designs_service_spec.rb`, you need to decide how to handle the
+# changes and whether the new attribute(s) should be included in the copy
+# or ignored.
+
+# COPY.
+# Add attributes that should be copied to the `{model}_attributes` lists:
+design_attributes:
+ - filename
+ - relative_position
+
+version_attributes:
+ - author_id
+ - created_at
+
+action_attributes: # (None)
+
+# IGNORE.
+# Add attributes that should not be copied to the `ignore_{model}_attributes` lists:
+ignore_design_attributes:
+ - id
+ - issue_id
+ - project_id
+
+ignore_version_attributes:
+ - id
+ - issue_id
+ - sha
+
+ignore_action_attributes:
+ - id
+ - design_id
+ - event
+ - image_v432x230
+ - version_id
diff --git a/lib/gitlab/diff/file_collection/merge_request_diff_base.rb b/lib/gitlab/diff/file_collection/merge_request_diff_base.rb
index d54e1aad19a..16257bb5ff5 100644
--- a/lib/gitlab/diff/file_collection/merge_request_diff_base.rb
+++ b/lib/gitlab/diff/file_collection/merge_request_diff_base.rb
@@ -11,7 +11,7 @@ module Gitlab
super(merge_request_diff,
project: merge_request_diff.project,
- diff_options: diff_options,
+ diff_options: merged_diff_options(diff_options),
diff_refs: merge_request_diff.diff_refs,
fallback_diff_refs: merge_request_diff.fallback_diff_refs)
end
@@ -64,6 +64,13 @@ module Gitlab
diff_stats_cache.read || super
end
end
+
+ def merged_diff_options(diff_options)
+ project = @merge_request_diff.project
+ max_diff_options = ::Commit.max_diff_options(project: project).merge(project: project)
+
+ diff_options.present? ? diff_options.merge(max_diff_options) : max_diff_options
+ end
end
end
end
diff --git a/lib/gitlab/diff/highlight_cache.rb b/lib/gitlab/diff/highlight_cache.rb
index 0eb22e6b3cb..90cb9c8638a 100644
--- a/lib/gitlab/diff/highlight_cache.rb
+++ b/lib/gitlab/diff/highlight_cache.rb
@@ -20,10 +20,27 @@ module Gitlab
# - Assigns DiffFile#highlighted_diff_lines for cached files
#
def decorate(diff_file)
- if content = read_file(diff_file)
- diff_file.highlighted_diff_lines = content.map do |line|
- Gitlab::Diff::Line.safe_init_from_hash(line)
- end
+ content = read_file(diff_file)
+
+ return [] unless content
+
+ # TODO: We could add some kind of flag to #initialize that would allow
+ # us to force re-caching
+ # https://gitlab.com/gitlab-org/gitlab/-/issues/263508
+ #
+ if content.empty? && recache_due_to_size?(diff_file)
+ # If the file is missing from the cache and there's reason to believe
+ # it is uncached due to a size issue around changing the values for
+ # max patch size, manually populate the hash and then set the value.
+ #
+ new_cache_content = {}
+ new_cache_content[diff_file.file_path] = diff_file.highlighted_diff_lines.map(&:to_hash)
+
+ write_to_redis_hash(new_cache_content)
+
+ set_highlighted_diff_lines(diff_file, read_file(diff_file))
+ else
+ set_highlighted_diff_lines(diff_file, content)
end
end
@@ -58,6 +75,28 @@ module Gitlab
private
+ def set_highlighted_diff_lines(diff_file, content)
+ diff_file.highlighted_diff_lines = content.map do |line|
+ Gitlab::Diff::Line.safe_init_from_hash(line)
+ end
+ end
+
+ def recache_due_to_size?(diff_file)
+ diff_file_class = diff_file.diff.class
+
+ current_patch_safe_limit_bytes = diff_file_class.patch_safe_limit_bytes
+ default_patch_safe_limit_bytes = diff_file_class.patch_safe_limit_bytes(diff_file_class::DEFAULT_MAX_PATCH_BYTES)
+
+ # If the diff is >= than the default limit, but less than the current
+ # limit, it is likely uncached due to having hit the default limit,
+ # making it eligible for recalculating.
+ #
+ diff_file.diff.diff_bytesize.between?(
+ default_patch_safe_limit_bytes,
+ current_patch_safe_limit_bytes
+ )
+ end
+
def cacheable_files
strong_memoize(:cacheable_files) do
diff_files.select { |file| cacheable?(file) && read_file(file).nil? }
diff --git a/lib/gitlab/exclusive_lease_helpers.rb b/lib/gitlab/exclusive_lease_helpers.rb
index 10762d83588..da5b0afad38 100644
--- a/lib/gitlab/exclusive_lease_helpers.rb
+++ b/lib/gitlab/exclusive_lease_helpers.rb
@@ -35,7 +35,7 @@ module Gitlab
lease.obtain(1 + retries)
- yield(lease.retried?)
+ yield(lease.retried?, lease)
ensure
lease&.cancel
end
diff --git a/lib/gitlab/experimentation.rb b/lib/gitlab/experimentation.rb
index dca60c93fb2..1ce3ffe4c86 100644
--- a/lib/gitlab/experimentation.rb
+++ b/lib/gitlab/experimentation.rb
@@ -48,12 +48,12 @@ module Gitlab
invite_members_version_a: {
tracking_category: 'Growth::Expansion::Experiment::InviteMembersVersionA'
},
+ invite_members_version_b: {
+ tracking_category: 'Growth::Expansion::Experiment::InviteMembersVersionB'
+ },
new_create_project_ui: {
tracking_category: 'Manage::Import::Experiment::NewCreateProjectUi'
},
- terms_opt_in: {
- tracking_category: 'Growth::Acquisition::Experiment::TermsOptIn'
- },
contact_sales_btn_in_app: {
tracking_category: 'Growth::Conversion::Experiment::ContactSalesInApp'
},
@@ -62,6 +62,15 @@ module Gitlab
},
invite_email: {
tracking_category: 'Growth::Acquisition::Experiment::InviteEmail'
+ },
+ invitation_reminders: {
+ tracking_category: 'Growth::Acquisition::Experiment::InvitationReminders'
+ },
+ group_only_trials: {
+ tracking_category: 'Growth::Conversion::Experiment::GroupOnlyTrials'
+ },
+ default_to_issues_board: {
+ tracking_category: 'Growth::Conversion::Experiment::DefaultToIssuesBoard'
}
}.freeze
@@ -91,28 +100,40 @@ module Gitlab
}
end
+ def push_frontend_experiment(experiment_key)
+ var_name = experiment_key.to_s.camelize(:lower)
+ enabled = experiment_enabled?(experiment_key)
+
+ gon.push({ experiments: { var_name => enabled } }, true)
+ end
+
def experiment_enabled?(experiment_key)
return false if dnt_enabled?
- return true if Experimentation.enabled_for_user?(experiment_key, experimentation_subject_index)
+ return true if Experimentation.enabled_for_value?(experiment_key, experimentation_subject_index)
return true if forced_enabled?(experiment_key)
false
end
def track_experiment_event(experiment_key, action, value = nil)
+ return if dnt_enabled?
+
track_experiment_event_for(experiment_key, action, value) do |tracking_data|
- ::Gitlab::Tracking.event(tracking_data.delete(:category), tracking_data.delete(:action), tracking_data)
+ ::Gitlab::Tracking.event(tracking_data.delete(:category), tracking_data.delete(:action), **tracking_data)
end
end
def frontend_experimentation_tracking_data(experiment_key, action, value = nil)
+ return if dnt_enabled?
+
track_experiment_event_for(experiment_key, action, value) do |tracking_data|
gon.push(tracking_data: tracking_data)
end
end
def record_experiment_user(experiment_key)
+ return if dnt_enabled?
return unless Experimentation.enabled?(experiment_key) && current_user
::Experiment.add_user(experiment_key, tracking_group(experiment_key), current_user)
@@ -183,9 +204,14 @@ module Gitlab
experiment.enabled? && experiment.enabled_for_environment?
end
- def enabled_for_user?(experiment_key, experimentation_subject_index)
+ def enabled_for_attribute?(experiment_key, attribute)
+ index = Digest::SHA1.hexdigest(attribute).hex % 100
+ enabled_for_value?(experiment_key, index)
+ end
+
+ def enabled_for_value?(experiment_key, experimentation_subject_index)
enabled?(experiment_key) &&
- experiment(experiment_key).enabled_for_experimentation_subject?(experimentation_subject_index)
+ experiment(experiment_key).enabled_for_index?(experimentation_subject_index)
end
end
@@ -200,10 +226,10 @@ module Gitlab
environment
end
- def enabled_for_experimentation_subject?(experimentation_subject_index)
- return false if experimentation_subject_index.blank?
+ def enabled_for_index?(index)
+ return false if index.blank?
- experimentation_subject_index <= experiment_percentage
+ index <= experiment_percentage
end
private
diff --git a/lib/gitlab/git/diff.rb b/lib/gitlab/git/diff.rb
index 09a49b6c1ca..78c47023c08 100644
--- a/lib/gitlab/git/diff.rb
+++ b/lib/gitlab/git/diff.rb
@@ -120,8 +120,8 @@ module Gitlab
# default.
#
# Patches surpassing this limit should still be persisted in the database.
- def patch_safe_limit_bytes
- patch_hard_limit_bytes / 10
+ def patch_safe_limit_bytes(limit = patch_hard_limit_bytes)
+ limit / 10
end
# Returns the limit for a single diff file (patch).
@@ -174,9 +174,13 @@ module Gitlab
@line_count ||= Util.count_lines(@diff)
end
+ def diff_bytesize
+ @diff_bytesize ||= @diff.bytesize
+ end
+
def too_large?
if @too_large.nil?
- @too_large = @diff.bytesize >= self.class.patch_hard_limit_bytes
+ @too_large = diff_bytesize >= self.class.patch_hard_limit_bytes
else
@too_large
end
@@ -194,7 +198,7 @@ module Gitlab
def collapsed?
return @collapsed if defined?(@collapsed)
- @collapsed = !expanded && @diff.bytesize >= self.class.patch_safe_limit_bytes
+ @collapsed = !expanded && diff_bytesize >= self.class.patch_safe_limit_bytes
end
def collapse!
diff --git a/lib/gitlab/git/diff_collection.rb b/lib/gitlab/git/diff_collection.rb
index e6121d688ba..6090d1b9f69 100644
--- a/lib/gitlab/git/diff_collection.rb
+++ b/lib/gitlab/git/diff_collection.rb
@@ -7,19 +7,27 @@ module Gitlab
class DiffCollection
include Enumerable
- DEFAULT_LIMITS = { max_files: 100, max_lines: 5000 }.freeze
-
attr_reader :limits
delegate :max_files, :max_lines, :max_bytes, :safe_max_files, :safe_max_lines, :safe_max_bytes, to: :limits
+ def self.default_limits(project: nil)
+ if Feature.enabled?(:increased_diff_limits, project)
+ { max_files: 200, max_lines: 7500 }
+ else
+ { max_files: 100, max_lines: 5000 }
+ end
+ end
+
def self.limits(options = {})
limits = {}
- limits[:max_files] = options.fetch(:max_files, DEFAULT_LIMITS[:max_files])
- limits[:max_lines] = options.fetch(:max_lines, DEFAULT_LIMITS[:max_lines])
+ defaults = default_limits(project: options[:project])
+ limits[:max_files] = options.fetch(:max_files, defaults[:max_files])
+ limits[:max_lines] = options.fetch(:max_lines, defaults[:max_lines])
limits[:max_bytes] = limits[:max_files] * 5.kilobytes # Average 5 KB per file
- limits[:safe_max_files] = [limits[:max_files], DEFAULT_LIMITS[:max_files]].min
- limits[:safe_max_lines] = [limits[:max_lines], DEFAULT_LIMITS[:max_lines]].min
+
+ limits[:safe_max_files] = [limits[:max_files], defaults[:max_files]].min
+ limits[:safe_max_lines] = [limits[:max_lines], defaults[:max_lines]].min
limits[:safe_max_bytes] = limits[:safe_max_files] * 5.kilobytes # Average 5 KB per file
limits[:max_patch_bytes] = Gitlab::Git::Diff.patch_hard_limit_bytes
@@ -110,11 +118,17 @@ module Gitlab
files >= safe_max_files || @line_count > safe_max_lines || @byte_count >= safe_max_bytes
end
+ def expand_diff?
+ # Force single-entry diff collections to always present as expanded
+ #
+ @iterator.size == 1 || !@enforce_limits || @expanded
+ end
+
def each_gitaly_patch
i = @array.length
@iterator.each do |raw|
- diff = Gitlab::Git::Diff.new(raw, expanded: !@enforce_limits || @expanded)
+ diff = Gitlab::Git::Diff.new(raw, expanded: expand_diff?)
if raw.overflow_marker
@overflow = true
@@ -137,11 +151,9 @@ module Gitlab
break
end
- expanded = !@enforce_limits || @expanded
-
- diff = Gitlab::Git::Diff.new(raw, expanded: expanded)
+ diff = Gitlab::Git::Diff.new(raw, expanded: expand_diff?)
- if !expanded && over_safe_limits?(i) && diff.line_count > 0
+ if !expand_diff? && over_safe_limits?(i) && diff.line_count > 0
diff.collapse!
end
diff --git a/lib/gitlab/git/diff_stats_collection.rb b/lib/gitlab/git/diff_stats_collection.rb
index 7e49d79676e..e30ec836a49 100644
--- a/lib/gitlab/git/diff_stats_collection.rb
+++ b/lib/gitlab/git/diff_stats_collection.rb
@@ -22,8 +22,8 @@ module Gitlab
@collection.map(&:path)
end
- def real_size
- max_files = ::Commit.max_diff_options[:max_files]
+ def real_size(project: nil)
+ max_files = ::Commit.max_diff_options(project: project)[:max_files]
if paths.size > max_files
"#{max_files}+"
else
diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb
index 8ace4157ad7..1a3409c1f84 100644
--- a/lib/gitlab/git/repository.rb
+++ b/lib/gitlab/git/repository.rb
@@ -297,10 +297,17 @@ module Gitlab
end
file_name = "#{name}.#{extension}"
- File.join(storage_path, self.gl_repository, sha, file_name)
+ File.join(storage_path, self.gl_repository, sha, archive_version_path, file_name)
end
private :archive_file_path
+ def archive_version_path
+ return '' unless Feature.enabled?(:include_lfs_blobs_in_archive)
+
+ '@v2'
+ end
+ private :archive_version_path
+
# Return repo size in megabytes
def size
size = gitaly_repository_client.repository_size
@@ -580,9 +587,9 @@ module Gitlab
tags.find { |tag| tag.name == name }
end
- def merge_to_ref(user, source_sha, branch, target_ref, message, first_parent_ref)
+ def merge_to_ref(user, source_sha, branch, target_ref, message, first_parent_ref, allow_conflicts)
wrapped_gitaly_errors do
- gitaly_operation_client.user_merge_to_ref(user, source_sha, branch, target_ref, message, first_parent_ref)
+ gitaly_operation_client.user_merge_to_ref(user, source_sha, branch, target_ref, message, first_parent_ref, allow_conflicts)
end
end
@@ -610,7 +617,7 @@ module Gitlab
}
wrapped_gitaly_errors do
- gitaly_operation_client.user_revert(args)
+ gitaly_operation_client.user_revert(**args)
end
end
@@ -626,7 +633,7 @@ module Gitlab
}
wrapped_gitaly_errors do
- gitaly_operation_client.user_cherry_pick(args)
+ gitaly_operation_client.user_cherry_pick(**args)
end
end
@@ -640,7 +647,7 @@ module Gitlab
}
wrapped_gitaly_errors do
- gitaly_operation_client.user_update_submodule(args)
+ gitaly_operation_client.user_update_submodule(**args)
end
end
diff --git a/lib/gitlab/git/wiki.rb b/lib/gitlab/git/wiki.rb
index da2d015ca4a..11919be594d 100644
--- a/lib/gitlab/git/wiki.rb
+++ b/lib/gitlab/git/wiki.rb
@@ -100,10 +100,6 @@ module Gitlab
wrapped_gitaly_errors do
gitaly_find_page(title: title, version: version, dir: dir)
end
- rescue Gitlab::Git::CommandError
- # Return nil for invalid versions.
- # This can be removed with https://gitlab.com/gitlab-org/gitaly/-/merge_requests/2323 in place.
- nil
end
def file(name, version)
@@ -159,6 +155,8 @@ module Gitlab
return unless wiki_page
Gitlab::Git::WikiPage.new(wiki_page, version)
+ rescue GRPC::InvalidArgument
+ nil
end
def gitaly_find_file(name, version)
@@ -173,9 +171,9 @@ module Gitlab
gitaly_pages =
if load_content
- gitaly_wiki_client.load_all_pages(params)
+ gitaly_wiki_client.load_all_pages(**params)
else
- gitaly_wiki_client.list_all_pages(params)
+ gitaly_wiki_client.list_all_pages(**params)
end
gitaly_pages.map do |wiki_page, version|
diff --git a/lib/gitlab/git_access.rb b/lib/gitlab/git_access.rb
index b67b3a37440..0576d1dd9db 100644
--- a/lib/gitlab/git_access.rb
+++ b/lib/gitlab/git_access.rb
@@ -47,6 +47,16 @@ module Gitlab
:cmd, :changes
attr_accessor :container
+ def self.error_message(key)
+ self.ancestors.each do |cls|
+ return cls.const_get('ERROR_MESSAGES', false).fetch(key)
+ rescue NameError, KeyError
+ next
+ end
+
+ raise ArgumentError, "No error message defined for #{key}"
+ end
+
def initialize(actor, container, protocol, authentication_abilities:, namespace_path: nil, repository_path: nil, redirected_path: nil, auth_result_type: nil)
@actor = actor
@container = container
@@ -137,6 +147,10 @@ module Gitlab
private
def check_container!
+ # Strict nil check, to avoid any surprises with Object#present?
+ # which can delegate to #empty?
+ raise NotFoundError, not_found_message if container.nil?
+
check_project! if project?
end
@@ -204,9 +218,7 @@ module Gitlab
end
def check_project_accessibility!
- if project.blank? || !can_read_project?
- raise NotFoundError, not_found_message
- end
+ raise NotFoundError, not_found_message unless can_read_project?
end
def not_found_message
@@ -279,10 +291,10 @@ module Gitlab
error_message(:download)
end
- # We assume that all git-access classes are in project context by default.
- # Override this method to be more specific.
def project?
- true
+ # Strict nil check, to avoid any surprises with Object#present?
+ # which can delegate to #empty?
+ !project.nil?
end
def project
@@ -290,7 +302,7 @@ module Gitlab
end
def check_push_access!
- if container.repository_read_only?
+ if project&.repository_read_only?
raise ForbiddenError, error_message(:read_only)
end
@@ -411,13 +423,7 @@ module Gitlab
protected
def error_message(key)
- self.class.ancestors.each do |cls|
- return cls.const_get('ERROR_MESSAGES', false).fetch(key)
- rescue NameError, KeyError
- next
- end
-
- raise ArgumentError, "No error message defined for #{key}"
+ self.class.error_message(key)
end
def success_result
@@ -504,7 +510,7 @@ module Gitlab
changes_size = 0
changes_list.each do |change|
- changes_size += repository.new_blobs(change[:newrev]).sum(&:size) # rubocop: disable CodeReuse/ActiveRecord
+ changes_size += repository.new_blobs(change[:newrev]).sum(&:size)
check_size_against_limit(changes_size)
end
diff --git a/lib/gitlab/git_access_result/custom_action.rb b/lib/gitlab/git_access_result/custom_action.rb
index e03459ea7a1..224c6b9eb52 100644
--- a/lib/gitlab/git_access_result/custom_action.rb
+++ b/lib/gitlab/git_access_result/custom_action.rb
@@ -12,7 +12,7 @@ module Gitlab
# 'data' => {
# 'api_endpoints' => %w{geo/proxy_git_ssh/info_refs_receive_pack geo/proxy_git_ssh/receive_pack},
# 'gl_username' => user.username,
- # 'primary_repo' => geo_primary_http_url_to_repo(project_or_wiki)
+ # 'primary_repo' => geo_primary_http_url_to_repo(container)
# }
# }
#
diff --git a/lib/gitlab/git_access_snippet.rb b/lib/gitlab/git_access_snippet.rb
index ae83e45f2b3..710e2ce90ec 100644
--- a/lib/gitlab/git_access_snippet.rb
+++ b/lib/gitlab/git_access_snippet.rb
@@ -21,6 +21,11 @@ module Gitlab
@authentication_abilities &= [:download_code, :push_code]
end
+ override :project
+ def project
+ container.project if container.is_a?(ProjectSnippet)
+ end
+
override :check
def check(cmd, changes)
check_snippet_accessibility!
@@ -46,29 +51,19 @@ module Gitlab
# snippets never return custom actions, such as geo replication.
end
- override :project?
- def project?
- project_snippet?
- end
-
- override :project
- def project
- snippet&.project
- end
-
override :check_valid_actor!
def check_valid_actor!
# TODO: Investigate if expanding actor/authentication types are needed.
# https://gitlab.com/gitlab-org/gitlab/issues/202190
- if actor && !actor.is_a?(User) && !actor.instance_of?(Key)
+ if actor && !allowed_actor?
raise ForbiddenError, ERROR_MESSAGES[:authentication_mechanism]
end
super
end
- def project_snippet?
- snippet.is_a?(ProjectSnippet)
+ def allowed_actor?
+ actor.is_a?(User) || actor.instance_of?(Key)
end
override :check_push_access!
@@ -120,7 +115,7 @@ module Gitlab
override :check_single_change_access
def check_single_change_access(change, _skip_lfs_integrity_check: false)
Checks::SnippetCheck.new(change, default_branch: snippet.default_branch, logger: logger).validate!
- Checks::PushFileCountCheck.new(change, repository: repository, limit: Snippet.max_file_limit(user), logger: logger).validate!
+ Checks::PushFileCountCheck.new(change, repository: repository, limit: Snippet.max_file_limit, logger: logger).validate!
rescue Checks::TimedLogger::TimeoutError
raise TimeoutError, logger.full_message
end
@@ -138,3 +133,5 @@ module Gitlab
end
end
end
+
+Gitlab::GitAccessSnippet.prepend_if_ee('EE::Gitlab::GitAccessSnippet')
diff --git a/lib/gitlab/git_access_wiki.rb b/lib/gitlab/git_access_wiki.rb
index a941282e713..3011b794b8f 100644
--- a/lib/gitlab/git_access_wiki.rb
+++ b/lib/gitlab/git_access_wiki.rb
@@ -12,6 +12,11 @@ module Gitlab
write_to_wiki: "You are not allowed to write to this project's wiki."
}.freeze
+ override :project
+ def project
+ container.project if container.is_a?(ProjectWiki)
+ end
+
override :download_ability
def download_ability
:download_wiki_code
@@ -40,11 +45,6 @@ module Gitlab
def not_found_message
error_message(:not_found)
end
-
- override :repository
- def repository
- container.wiki.repository
- end
end
end
diff --git a/lib/gitlab/gitaly_client/diff_stitcher.rb b/lib/gitlab/gitaly_client/diff_stitcher.rb
index 98d327a7329..e98ae75590d 100644
--- a/lib/gitlab/gitaly_client/diff_stitcher.rb
+++ b/lib/gitlab/gitaly_client/diff_stitcher.rb
@@ -5,8 +5,10 @@ module Gitlab
class DiffStitcher
include Enumerable
- def initialize(rpc_response)
- @rpc_response = rpc_response
+ delegate :size, to: :rpc_response
+
+ def initialize(rpc_response_param)
+ @rpc_response = rpc_response_param
end
def each
@@ -31,6 +33,10 @@ module Gitlab
end
end
end
+
+ private
+
+ attr_reader :rpc_response
end
end
end
diff --git a/lib/gitlab/gitaly_client/operation_service.rb b/lib/gitlab/gitaly_client/operation_service.rb
index 786eb3ca4ae..4850d646de4 100644
--- a/lib/gitlab/gitaly_client/operation_service.rb
+++ b/lib/gitlab/gitaly_client/operation_service.rb
@@ -102,7 +102,7 @@ module Gitlab
end
end
- def user_merge_to_ref(user, source_sha, branch, target_ref, message, first_parent_ref)
+ def user_merge_to_ref(user, source_sha, branch, target_ref, message, first_parent_ref, allow_conflicts)
request = Gitaly::UserMergeToRefRequest.new(
repository: @gitaly_repo,
source_sha: source_sha,
@@ -110,7 +110,8 @@ module Gitlab
target_ref: encode_binary(target_ref),
user: Gitlab::Git::User.from_gitlab(user).to_gitaly,
message: encode_binary(message),
- first_parent_ref: encode_binary(first_parent_ref)
+ first_parent_ref: encode_binary(first_parent_ref),
+ allow_conflicts: allow_conflicts
)
response = GitalyClient.call(@repository.storage, :operation_service,
diff --git a/lib/gitlab/gitpod.rb b/lib/gitlab/gitpod.rb
index 11b54db72ea..e35fb8fed02 100644
--- a/lib/gitlab/gitpod.rb
+++ b/lib/gitlab/gitpod.rb
@@ -3,17 +3,13 @@
module Gitlab
class Gitpod
class << self
- def feature_conditional?
- feature.conditional?
- end
-
def feature_available?
# The gitpod_bundle feature could be conditionally applied, so check if `!off?`
- !feature.off?
+ !feature.off? || feature_enabled?
end
def feature_enabled?(actor = nil)
- feature.enabled?(actor)
+ Feature.enabled?(:gitpod, actor, default_enabled: true)
end
def feature_and_settings_enabled?(actor = nil)
diff --git a/lib/gitlab/gl_repository.rb b/lib/gitlab/gl_repository.rb
index 54dca93a891..352a93817be 100644
--- a/lib/gitlab/gl_repository.rb
+++ b/lib/gitlab/gl_repository.rb
@@ -4,6 +4,8 @@ module Gitlab
class GlRepository
include Singleton
+ # TODO: Refactor these constants into proper classes
+ # https://gitlab.com/gitlab-org/gitlab/-/issues/259008
PROJECT = RepoType.new(
name: :project,
access_checker_class: Gitlab::GitAccessProject,
@@ -12,8 +14,12 @@ module Gitlab
WIKI = RepoType.new(
name: :wiki,
access_checker_class: Gitlab::GitAccessWiki,
- repository_resolver: -> (container) { ::Repository.new(container.wiki.full_path, container, shard: container.wiki.repository_storage, disk_path: container.wiki.disk_path, repo_type: WIKI) },
- project_resolver: -> (container) { container.is_a?(Project) ? container : nil },
+ repository_resolver: -> (container) do
+ wiki = container.is_a?(Wiki) ? container : container.wiki # Also allow passing a Project, Group, or Geo::DeletedProject
+ ::Repository.new(wiki.full_path, wiki, shard: wiki.repository_storage, disk_path: wiki.disk_path, repo_type: WIKI)
+ end,
+ container_class: ProjectWiki,
+ project_resolver: -> (wiki) { wiki.try(:project) },
suffix: :wiki
).freeze
SNIPPET = RepoType.new(
diff --git a/lib/gitlab/gl_repository/identifier.rb b/lib/gitlab/gl_repository/identifier.rb
index 57350b1edb0..f521a14ea19 100644
--- a/lib/gitlab/gl_repository/identifier.rb
+++ b/lib/gitlab/gl_repository/identifier.rb
@@ -53,12 +53,13 @@ module Gitlab
private
def container_class
- case @container_type
- when 'project'
- Project
- when 'group'
- Group
- end
+ # NOTE: This is currently only used and supported for group wikis
+ # https://gitlab.com/gitlab-org/gitlab/-/issues/219192
+ return unless @repo_type_name == 'wiki'
+
+ "#{@container_type}_#{@repo_type_name}".classify.constantize
+ rescue NameError
+ nil
end
end
diff --git a/lib/gitlab/gl_repository/repo_type.rb b/lib/gitlab/gl_repository/repo_type.rb
index 346f6be0d98..4b1f4fcc2a2 100644
--- a/lib/gitlab/gl_repository/repo_type.rb
+++ b/lib/gitlab/gl_repository/repo_type.rb
@@ -29,10 +29,6 @@ module Gitlab
end
def identifier_for_container(container)
- if container.is_a?(Group)
- return "#{container.class.name.underscore}-#{container.id}-#{name}"
- end
-
"#{name}-#{container.id}"
end
@@ -84,3 +80,5 @@ module Gitlab
end
end
end
+
+Gitlab::GlRepository::RepoType.prepend_if_ee('EE::Gitlab::GlRepository::RepoType')
diff --git a/lib/gitlab/gon_helper.rb b/lib/gitlab/gon_helper.rb
index 66517ecd743..10660649623 100644
--- a/lib/gitlab/gon_helper.rb
+++ b/lib/gitlab/gon_helper.rb
@@ -43,12 +43,10 @@ module Gitlab
# Initialize gon.features with any flags that should be
# made globally available to the frontend
- push_frontend_feature_flag(:snippets_vue, default_enabled: true)
- push_frontend_feature_flag(:monaco_blobs, default_enabled: true)
- push_frontend_feature_flag(:monaco_ci, default_enabled: false)
- push_frontend_feature_flag(:snippets_edit_vue, default_enabled: true)
push_frontend_feature_flag(:webperf_experiment, default_enabled: false)
push_frontend_feature_flag(:snippets_binary_blob, default_enabled: false)
+ push_frontend_feature_flag(:usage_data_api, default_enabled: true)
+ push_frontend_feature_flag(:security_auto_fix, default_enabled: false)
# Startup CSS feature is a special one as it can be enabled by means of cookies and params
gon.push({ features: { 'startupCss' => use_startup_css? } }, true)
@@ -59,9 +57,9 @@ module Gitlab
# name - The name of the feature flag, e.g. `my_feature`.
# args - Any additional arguments to pass to `Feature.enabled?`. This allows
# you to check if a flag is enabled for a particular user.
- def push_frontend_feature_flag(name, *args)
+ def push_frontend_feature_flag(name, *args, **kwargs)
var_name = name.to_s.camelize(:lower)
- enabled = Feature.enabled?(name, *args)
+ enabled = Feature.enabled?(name, *args, **kwargs)
# Here the `true` argument signals gon that the value should be merged
# into any existing ones, instead of overwriting them. This allows you to
diff --git a/lib/gitlab/graphql/authorize/authorize_resource.rb b/lib/gitlab/graphql/authorize/authorize_resource.rb
index 27673e5c27a..c70127553fd 100644
--- a/lib/gitlab/graphql/authorize/authorize_resource.rb
+++ b/lib/gitlab/graphql/authorize/authorize_resource.rb
@@ -29,8 +29,8 @@ module Gitlab
raise NotImplementedError, "Implement #find_object in #{self.class.name}"
end
- def authorized_find!(*args)
- object = Graphql::Lazy.force(find_object(*args))
+ def authorized_find!(*args, **kwargs)
+ object = Graphql::Lazy.force(find_object(*args, **kwargs))
authorize!(object)
diff --git a/lib/gitlab/graphql/global_id_compatibility.rb b/lib/gitlab/graphql/global_id_compatibility.rb
new file mode 100644
index 00000000000..a96e4c4b976
--- /dev/null
+++ b/lib/gitlab/graphql/global_id_compatibility.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Graphql
+ module GlobalIDCompatibility
+ # TODO: remove this module once the compatibility layer is no longer needed.
+ # See: https://gitlab.com/gitlab-org/gitlab/-/issues/257883
+ def coerce_global_id_arguments!(args)
+ global_id_arguments = self.class.arguments.values.select do |arg|
+ arg.type.is_a?(Class) && arg.type <= ::Types::GlobalIDType
+ end
+
+ global_id_arguments.each do |arg|
+ k = arg.keyword
+ args[k] &&= arg.type.coerce_isolated_input(args[k])
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/graphql/markdown_field.rb b/lib/gitlab/graphql/markdown_field.rb
index 7be6810f7ba..0b5bde8d8d9 100644
--- a/lib/gitlab/graphql/markdown_field.rb
+++ b/lib/gitlab/graphql/markdown_field.rb
@@ -12,13 +12,19 @@ module Gitlab
end
method_name = kwargs.delete(:method) || name.to_s.sub(/_html$/, '')
- kwargs[:resolve] = Gitlab::Graphql::MarkdownField::Resolver.new(method_name.to_sym).proc
+ resolver_method = "#{name}_resolver".to_sym
+ kwargs[:resolver_method] = resolver_method
kwargs[:description] ||= "The GitLab Flavored Markdown rendering of `#{method_name}`"
# Adding complexity to rendered notes since that could cause queries.
kwargs[:complexity] ||= 5
field name, GraphQL::STRING_TYPE, **kwargs
+
+ define_method resolver_method do
+ # We need to `dup` the context so the MarkdownHelper doesn't modify it
+ ::MarkupHelper.markdown_field(object, method_name.to_sym, context.to_h.dup)
+ end
end
end
end
diff --git a/lib/gitlab/graphql/markdown_field/resolver.rb b/lib/gitlab/graphql/markdown_field/resolver.rb
deleted file mode 100644
index 11a01b95ad1..00000000000
--- a/lib/gitlab/graphql/markdown_field/resolver.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module Graphql
- module MarkdownField
- class Resolver
- attr_reader :method_name
-
- def initialize(method_name)
- @method_name = method_name
- end
-
- def proc
- -> (object, _args, ctx) do
- # We need to `dup` the context so the MarkdownHelper doesn't modify it
- ::MarkupHelper.markdown_field(object, method_name, ctx.to_h.dup)
- end
- end
- end
- end
- end
-end
diff --git a/lib/gitlab/graphql/pagination/keyset/connection.rb b/lib/gitlab/graphql/pagination/keyset/connection.rb
index 17cd22d38ad..252f6371765 100644
--- a/lib/gitlab/graphql/pagination/keyset/connection.rb
+++ b/lib/gitlab/graphql/pagination/keyset/connection.rb
@@ -110,8 +110,7 @@ module Gitlab
end
if last
- # grab one more than we need
- paginated_nodes = sliced_nodes.last(limit_value + 1)
+ paginated_nodes = LastItems.take_items(sliced_nodes, limit_value + 1)
# there is an extra node, so there is a previous page
@has_previous_page = paginated_nodes.count > limit_value
diff --git a/lib/gitlab/graphql/pagination/keyset/last_items.rb b/lib/gitlab/graphql/pagination/keyset/last_items.rb
new file mode 100644
index 00000000000..45bf15236c1
--- /dev/null
+++ b/lib/gitlab/graphql/pagination/keyset/last_items.rb
@@ -0,0 +1,57 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Graphql
+ module Pagination
+ module Keyset
+ # This class handles the last(N) ActiveRecord call even if a special ORDER BY configuration is present.
+ # For the last(N) call, ActiveRecord calls reverse_order, however for some cases it raises
+ # ActiveRecord::IrreversibleOrderError error.
+ class LastItems
+ # rubocop: disable CodeReuse/ActiveRecord
+ def self.take_items(scope, count)
+ if custom_order = lookup_custom_reverse_order(scope.order_values)
+ items = scope.reorder(*custom_order).first(count) # returns a single record when count is nil
+ items.is_a?(Array) ? items.reverse : items
+ else
+ scope.last(count)
+ end
+ end
+ # rubocop: enable CodeReuse/ActiveRecord
+
+ # Detect special ordering and provide the reversed order
+ def self.lookup_custom_reverse_order(order_values)
+ if ordering_by_merged_at_and_mr_id_desc?(order_values)
+ [
+ Gitlab::Database.nulls_first_order('merge_request_metrics.merged_at', 'ASC'), # reversing the order
+ MergeRequest.arel_table[:id].asc
+ ]
+ elsif ordering_by_merged_at_and_mr_id_asc?(order_values)
+ [
+ Gitlab::Database.nulls_first_order('merge_request_metrics.merged_at', 'DESC'),
+ MergeRequest.arel_table[:id].asc
+ ]
+ end
+ end
+
+ def self.ordering_by_merged_at_and_mr_id_desc?(order_values)
+ order_values.size == 2 &&
+ order_values.first.to_s == Gitlab::Database.nulls_last_order('merge_request_metrics.merged_at', 'DESC') &&
+ order_values.last.is_a?(Arel::Nodes::Descending) &&
+ order_values.last.to_sql == MergeRequest.arel_table[:id].desc.to_sql
+ end
+
+ def self.ordering_by_merged_at_and_mr_id_asc?(order_values)
+ order_values.size == 2 &&
+ order_values.first.to_s == Gitlab::Database.nulls_last_order('merge_request_metrics.merged_at', 'ASC') &&
+ order_values.last.is_a?(Arel::Nodes::Descending) &&
+ order_values.last.to_sql == MergeRequest.arel_table[:id].desc.to_sql
+ end
+
+ private_class_method :ordering_by_merged_at_and_mr_id_desc?
+ private_class_method :ordering_by_merged_at_and_mr_id_asc?
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/graphql/pagination/keyset/order_info.rb b/lib/gitlab/graphql/pagination/keyset/order_info.rb
index f54695ddb9a..f3ce3a10703 100644
--- a/lib/gitlab/graphql/pagination/keyset/order_info.rb
+++ b/lib/gitlab/graphql/pagination/keyset/order_info.rb
@@ -94,6 +94,10 @@ module Gitlab
[order_value.expr.expressions[0].name.to_s, order_value.direction, order_value.expr]
elsif ordering_by_similarity?(order_value)
['similarity', order_value.direction, order_value.expr]
+ elsif ordering_by_case?(order_value)
+ ['case_order_value', order_value.direction, order_value.expr]
+ elsif ordering_by_array_position?(order_value)
+ ['array_position', order_value.direction, order_value.expr]
else
[order_value.expr.name, order_value.direction, nil]
end
@@ -104,9 +108,19 @@ module Gitlab
order_value.expr.is_a?(Arel::Nodes::NamedFunction) && order_value.expr&.name&.downcase == 'lower'
end
+ # determine if ordering using ARRAY_POSITION, eg. "ORDER BY ARRAY_POSITION(Array[4,3,1,2]::smallint, state)"
+ def ordering_by_array_position?(order_value)
+ order_value.expr.is_a?(Arel::Nodes::NamedFunction) && order_value.expr&.name&.downcase == 'array_position'
+ end
+
# determine if ordering using SIMILARITY scoring based on Gitlab::Database::SimilarityScore
def ordering_by_similarity?(order_value)
- order_value.to_sql.match?(/SIMILARITY\(.+\*/)
+ Gitlab::Database::SimilarityScore.order_by_similarity?(order_value)
+ end
+
+ # determine if ordering using CASE
+ def ordering_by_case?(order_value)
+ order_value.expr.is_a?(Arel::Nodes::Case)
end
end
end
diff --git a/lib/gitlab/graphql/query_analyzers/logger_analyzer.rb b/lib/gitlab/graphql/query_analyzers/logger_analyzer.rb
index 6b6bb72eb31..1285365376f 100644
--- a/lib/gitlab/graphql/query_analyzers/logger_analyzer.rb
+++ b/lib/gitlab/graphql/query_analyzers/logger_analyzer.rb
@@ -6,6 +6,8 @@ module Gitlab
class LoggerAnalyzer
COMPLEXITY_ANALYZER = GraphQL::Analysis::QueryComplexity.new { |query, complexity_value| complexity_value }
DEPTH_ANALYZER = GraphQL::Analysis::QueryDepth.new { |query, depth_value| depth_value }
+ FIELD_USAGE_ANALYZER = GraphQL::Analysis::FieldUsage.new { |query, used_fields, used_deprecated_fields| [used_fields, used_deprecated_fields] }
+ ALL_ANALYZERS = [COMPLEXITY_ANALYZER, DEPTH_ANALYZER, FIELD_USAGE_ANALYZER].freeze
def analyze?(query)
Feature.enabled?(:graphql_logging, default_enabled: true)
@@ -23,18 +25,21 @@ module Gitlab
end
def call(memo, visit_type, irep_node)
- memo
+ RequestStore.store[:graphql_logs] = memo
end
def final_value(memo)
return if memo.nil?
- analyzers = [COMPLEXITY_ANALYZER, DEPTH_ANALYZER]
- complexity, depth = GraphQL::Analysis.analyze_query(memo[:query], analyzers)
+ complexity, depth, field_usages = GraphQL::Analysis.analyze_query(memo[:query], ALL_ANALYZERS)
memo[:depth] = depth
memo[:complexity] = complexity
+ # This duration is not the execution time of the
+ # query but the execution time of the analyzer.
memo[:duration_s] = duration(memo[:time_started]).round(1)
+ memo[:used_fields] = field_usages.first
+ memo[:used_deprecated_fields] = field_usages.second
GraphqlLogger.info(memo.except!(:time_started, :query))
rescue => e
diff --git a/lib/gitlab/group_search_results.rb b/lib/gitlab/group_search_results.rb
index 0cc3de297ba..5fec50eecd2 100644
--- a/lib/gitlab/group_search_results.rb
+++ b/lib/gitlab/group_search_results.rb
@@ -4,10 +4,10 @@ module Gitlab
class GroupSearchResults < SearchResults
attr_reader :group
- def initialize(current_user, query, limit_projects = nil, group:, default_project_filter: false, filters: {})
+ def initialize(current_user, query, limit_projects = nil, group:, default_project_filter: false, sort: nil, filters: {})
@group = group
- super(current_user, query, limit_projects, default_project_filter: default_project_filter, filters: filters)
+ super(current_user, query, limit_projects, default_project_filter: default_project_filter, sort: sort, filters: filters)
end
# rubocop:disable CodeReuse/ActiveRecord
@@ -38,3 +38,5 @@ module Gitlab
end
end
end
+
+Gitlab::GroupSearchResults.prepend_if_ee('EE::Gitlab::GroupSearchResults')
diff --git a/lib/gitlab/health_checks/unicorn_check.rb b/lib/gitlab/health_checks/unicorn_check.rb
index cdc6d2a7519..f0c6fdab600 100644
--- a/lib/gitlab/health_checks/unicorn_check.rb
+++ b/lib/gitlab/health_checks/unicorn_check.rb
@@ -22,7 +22,7 @@ module Gitlab
def check
return unless http_servers
- http_servers.sum(&:worker_processes) # rubocop: disable CodeReuse/ActiveRecord
+ http_servers.sum(&:worker_processes)
end
# Traversal of ObjectSpace is expensive, on fully loaded application
diff --git a/lib/gitlab/import_export/attribute_cleaner.rb b/lib/gitlab/import_export/attribute_cleaner.rb
index 018cb36fc58..379a734b19c 100644
--- a/lib/gitlab/import_export/attribute_cleaner.rb
+++ b/lib/gitlab/import_export/attribute_cleaner.rb
@@ -20,8 +20,8 @@ module Gitlab
/\Aremote_\w+_(url|urls|request_header)\Z/ # carrierwave automatically creates these attribute methods for uploads
).freeze
- def self.clean(*args)
- new(*args).clean
+ def self.clean(*args, **kwargs)
+ new(*args, **kwargs).clean
end
def initialize(relation_hash:, relation_class:, excluded_keys: [])
diff --git a/lib/gitlab/import_export/base/relation_factory.rb b/lib/gitlab/import_export/base/relation_factory.rb
index 05b69362976..d60bc79df4c 100644
--- a/lib/gitlab/import_export/base/relation_factory.rb
+++ b/lib/gitlab/import_export/base/relation_factory.rb
@@ -31,8 +31,8 @@ module Gitlab
TOKEN_RESET_MODELS = %i[Project Namespace Group Ci::Trigger Ci::Build Ci::Runner ProjectHook].freeze
- def self.create(*args)
- new(*args).create
+ def self.create(*args, **kwargs)
+ new(*args, **kwargs).create
end
def self.relation_class(relation_name)
@@ -53,6 +53,7 @@ module Gitlab
@importable = importable
@imported_object_retries = 0
@relation_hash[importable_column_name] = @importable.id
+ @original_user = {}
# Remove excluded keys from relation_hash
# We don't do this in the parsed_relation_hash because of the 'transformed attributes'
@@ -112,6 +113,7 @@ module Gitlab
def update_user_references
self.class::USER_REFERENCES.each do |reference|
if @relation_hash[reference]
+ @original_user[reference] = @relation_hash[reference]
@relation_hash[reference] = @members_mapper.map[@relation_hash[reference]]
end
end
@@ -243,28 +245,20 @@ module Gitlab
# will be used. Otherwise, a note stating the original author name
# is left.
def set_note_author
- old_author_id = @relation_hash['author_id']
+ old_author_id = @original_user['author_id']
author = @relation_hash.delete('author')
- update_note_for_missing_author(author['name']) unless has_author?(old_author_id)
- end
-
- def has_author?(old_author_id)
- admin_user? && @members_mapper.include?(old_author_id)
+ unless @members_mapper.include?(old_author_id)
+ @relation_hash['note'] = "%{note}\n\n %{missing_author_note}" % {
+ note: @relation_hash['note'].presence || '*Blank note*',
+ missing_author_note: missing_author_note(@relation_hash['updated_at'], author['name'])
+ }
+ end
end
def missing_author_note(updated_at, author_name)
timestamp = updated_at.split('.').first
- "\n\n *By #{author_name} on #{timestamp} (imported from GitLab project)*"
- end
-
- def update_note_for_missing_author(author_name)
- @relation_hash['note'] = '*Blank note*' if @relation_hash['note'].blank?
- @relation_hash['note'] = "#{@relation_hash['note']}#{missing_author_note(@relation_hash['updated_at'], author_name)}"
- end
-
- def admin_user?
- @user.admin?
+ "*By #{author_name} on #{timestamp} (imported from GitLab)*"
end
def existing_object?
diff --git a/lib/gitlab/import_export/file_importer.rb b/lib/gitlab/import_export/file_importer.rb
index 081745a49f4..5a6f6e017d2 100644
--- a/lib/gitlab/import_export/file_importer.rb
+++ b/lib/gitlab/import_export/file_importer.rb
@@ -10,8 +10,8 @@ module Gitlab
MAX_RETRIES = 8
IGNORED_FILENAMES = %w(. ..).freeze
- def self.import(*args)
- new(*args).import
+ def self.import(*args, **kwargs)
+ new(*args, **kwargs).import
end
def initialize(importable:, archive_file:, shared:)
diff --git a/lib/gitlab/import_export/json/ndjson_reader.rb b/lib/gitlab/import_export/json/ndjson_reader.rb
index e9b05afc7d4..0d9839b86cf 100644
--- a/lib/gitlab/import_export/json/ndjson_reader.rb
+++ b/lib/gitlab/import_export/json/ndjson_reader.rb
@@ -35,6 +35,7 @@ module Gitlab
# This reads from `tree/project/merge_requests.ndjson`
path = file_path(importable_path, "#{key}.ndjson")
+
next unless File.exist?(path)
File.foreach(path, MAX_JSON_DOCUMENT_SIZE).with_index do |line, line_num|
@@ -43,6 +44,11 @@ module Gitlab
end
end
+ # TODO: Move clear logic into main comsume_relation method (see https://gitlab.com/gitlab-org/gitlab/-/merge_requests/41699#note_430465330)
+ def clear_consumed_relations
+ @consumed_relations.clear
+ end
+
private
def json_decode(string)
diff --git a/lib/gitlab/import_export/lfs_saver.rb b/lib/gitlab/import_export/lfs_saver.rb
index 515fd98630c..4964b8b16f4 100644
--- a/lib/gitlab/import_export/lfs_saver.rb
+++ b/lib/gitlab/import_export/lfs_saver.rb
@@ -21,10 +21,10 @@ module Gitlab
save_lfs_object(lfs_object)
end
- append_lfs_json_for_batch(batch) if write_lfs_json_enabled?
+ append_lfs_json_for_batch(batch)
end
- write_lfs_json if write_lfs_json_enabled?
+ write_lfs_json
true
rescue => e
@@ -35,10 +35,6 @@ module Gitlab
private
- def write_lfs_json_enabled?
- ::Feature.enabled?(:export_lfs_objects_projects, default_enabled: true)
- end
-
def save_lfs_object(lfs_object)
if lfs_object.local_store?
copy_file_for_lfs_object(lfs_object)
diff --git a/lib/gitlab/import_export/members_mapper.rb b/lib/gitlab/import_export/members_mapper.rb
index 31d1f7b48bd..6b37683ea68 100644
--- a/lib/gitlab/import_export/members_mapper.rb
+++ b/lib/gitlab/import_export/members_mapper.rb
@@ -34,8 +34,8 @@ module Gitlab
@user.id
end
- def include?(old_author_id)
- map.has_key?(old_author_id) && map[old_author_id] != default_user_id
+ def include?(old_user_id)
+ map.has_key?(old_user_id)
end
private
@@ -63,6 +63,8 @@ module Gitlab
end
def add_team_member(member, existing_user = nil)
+ return true if existing_user && @importable.members.exists?(user_id: existing_user.id)
+
member['user'] = existing_user
member_hash = member_hash(member)
diff --git a/lib/gitlab/import_export/project/import_export.yml b/lib/gitlab/import_export/project/import_export.yml
index 9ec5df8cde9..a0526ba0414 100644
--- a/lib/gitlab/import_export/project/import_export.yml
+++ b/lib/gitlab/import_export/project/import_export.yml
@@ -403,9 +403,15 @@ ee:
- issues:
- epic_issue:
- :epic
+ - :issuable_sla
- protected_branches:
- :unprotect_access_levels
- protected_environments:
- :deploy_access_levels
- :service_desk_setting
- :security_setting
+
+ included_attributes:
+ issuable_sla:
+ - :issue
+ - :due_at
diff --git a/lib/gitlab/import_export/project/sample/date_calculator.rb b/lib/gitlab/import_export/project/sample/date_calculator.rb
new file mode 100644
index 00000000000..2d989d21166
--- /dev/null
+++ b/lib/gitlab/import_export/project/sample/date_calculator.rb
@@ -0,0 +1,37 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module ImportExport
+ module Project
+ module Sample
+ class DateCalculator
+ include Gitlab::Utils::StrongMemoize
+
+ def initialize(dates)
+ @dates = dates.dup
+ @dates.flatten!
+ @dates.compact!
+ @dates.sort!
+ @dates.map! { |date| date.to_time.to_f }
+ end
+
+ def closest_date_to_average
+ strong_memoize(:closest_date_to_average) do
+ next if @dates.empty?
+
+ average_date = (@dates.first + @dates.last) / 2.0
+ closest_date = @dates.min_by { |date| (date - average_date).abs }
+ Time.zone.at(closest_date)
+ end
+ end
+
+ def calculate_by_closest_date_to_average(date)
+ return date unless closest_date_to_average && closest_date_to_average < Time.current
+
+ date + (Time.current - closest_date_to_average).seconds
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/import_export/project/sample/sample_data_relation_tree_restorer.rb b/lib/gitlab/import_export/project/sample/sample_data_relation_tree_restorer.rb
new file mode 100644
index 00000000000..b0c3940b5f9
--- /dev/null
+++ b/lib/gitlab/import_export/project/sample/sample_data_relation_tree_restorer.rb
@@ -0,0 +1,51 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module ImportExport
+ module Project
+ module Sample
+ class SampleDataRelationTreeRestorer < RelationTreeRestorer
+ DATE_MODELS = %i[issues milestones].freeze
+
+ def initialize(*args)
+ super
+
+ date_calculator
+ end
+
+ private
+
+ def build_relation(relation_key, relation_definition, data_hash)
+ # Override due date attributes in data hash for Sample Data templates
+ # Dates are moved by taking the closest one to average and moving that (and rest around it) to the date of import
+ # TODO: To move this logic to RelationFactory (see: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/41699#note_430465333)
+ override_date_attributes!(relation_key, data_hash)
+ super
+ end
+
+ def override_date_attributes!(relation_key, data_hash)
+ return unless DATE_MODELS.include?(relation_key.to_sym)
+
+ data_hash['start_date'] = date_calculator.calculate_by_closest_date_to_average(data_hash['start_date'].to_time) unless data_hash['start_date'].nil?
+ data_hash['due_date'] = date_calculator.calculate_by_closest_date_to_average(data_hash['due_date'].to_time) unless data_hash['due_date'].nil?
+ end
+
+ # TODO: Move clear logic into main comsume_relation method (see https://gitlab.com/gitlab-org/gitlab/-/merge_requests/41699#note_430465330)
+ def dates
+ unless relation_reader.legacy?
+ DATE_MODELS.map do |tag|
+ relation_reader.consume_relation(@importable_path, tag).map { |model| model.first['due_date'] }.tap do
+ relation_reader.clear_consumed_relations
+ end
+ end
+ end
+ end
+
+ def date_calculator
+ @date_calculator ||= Gitlab::ImportExport::Project::Sample::DateCalculator.new(dates)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/import_export/project/tree_restorer.rb b/lib/gitlab/import_export/project/tree_restorer.rb
index a16ffe36054..b1d647281ab 100644
--- a/lib/gitlab/import_export/project/tree_restorer.rb
+++ b/lib/gitlab/import_export/project/tree_restorer.rb
@@ -70,7 +70,7 @@ module Gitlab
end
def relation_tree_restorer
- @relation_tree_restorer ||= RelationTreeRestorer.new(
+ @relation_tree_restorer ||= relation_tree_restorer_class.new(
user: @user,
shared: @shared,
relation_reader: relation_reader,
@@ -84,6 +84,14 @@ module Gitlab
)
end
+ def relation_tree_restorer_class
+ sample_data_template? ? Sample::SampleDataRelationTreeRestorer : RelationTreeRestorer
+ end
+
+ def sample_data_template?
+ @project&.import_data&.data&.dig('sample_data')
+ end
+
def members_mapper
@members_mapper ||= Gitlab::ImportExport::MembersMapper.new(exported_members: @project_members,
user: @user,
diff --git a/lib/gitlab/import_export/project/tree_saver.rb b/lib/gitlab/import_export/project/tree_saver.rb
index 7cca3596da6..80dacf2eb20 100644
--- a/lib/gitlab/import_export/project/tree_saver.rb
+++ b/lib/gitlab/import_export/project/tree_saver.rb
@@ -36,7 +36,7 @@ module Gitlab
end
def exportable
- @project.present(exportable_params)
+ @project.present(**exportable_params)
end
def exportable_params
diff --git a/lib/gitlab/import_export/repo_restorer.rb b/lib/gitlab/import_export/repo_restorer.rb
index 9e10e7aea13..f808e30bd6e 100644
--- a/lib/gitlab/import_export/repo_restorer.rb
+++ b/lib/gitlab/import_export/repo_restorer.rb
@@ -14,10 +14,10 @@ module Gitlab
def restore
return true unless File.exist?(path_to_bundle)
+ ensure_repository_does_not_exist!
+
repository.create_from_bundle(path_to_bundle)
rescue => e
- Repositories::DestroyService.new(repository).execute
-
shared.error(e)
false
end
@@ -25,6 +25,16 @@ module Gitlab
private
attr_accessor :repository, :path_to_bundle, :shared
+
+ def ensure_repository_does_not_exist!
+ if repository.exists?
+ shared.logger.info(
+ message: %Q{Deleting existing "#{repository.path}" to re-import it.}
+ )
+
+ Repositories::DestroyService.new(repository).execute
+ end
+ end
end
end
end
diff --git a/lib/gitlab/import_export/saver.rb b/lib/gitlab/import_export/saver.rb
index e4724659eff..045ba2495bf 100644
--- a/lib/gitlab/import_export/saver.rb
+++ b/lib/gitlab/import_export/saver.rb
@@ -5,8 +5,8 @@ module Gitlab
class Saver
include Gitlab::ImportExport::CommandLineUtil
- def self.save(*args)
- new(*args).save
+ def self.save(*args, **kwargs)
+ new(*args, **kwargs).save
end
def initialize(exportable:, shared:)
diff --git a/lib/gitlab/import_export/uploads_manager.rb b/lib/gitlab/import_export/uploads_manager.rb
index dca8e3a7449..26e7d2cf765 100644
--- a/lib/gitlab/import_export/uploads_manager.rb
+++ b/lib/gitlab/import_export/uploads_manager.rb
@@ -40,7 +40,7 @@ module Gitlab
def add_upload(upload)
uploader_context = FileUploader.extract_dynamic_path(upload).named_captures.symbolize_keys
- UploadService.new(@project, File.open(upload, 'r'), FileUploader, uploader_context).execute.to_h
+ UploadService.new(@project, File.open(upload, 'r'), FileUploader, **uploader_context).execute.to_h
end
def copy_project_uploads
diff --git a/lib/gitlab/import_export/version_checker.rb b/lib/gitlab/import_export/version_checker.rb
index 4154d4fe775..48f5b558e52 100644
--- a/lib/gitlab/import_export/version_checker.rb
+++ b/lib/gitlab/import_export/version_checker.rb
@@ -3,8 +3,8 @@
module Gitlab
module ImportExport
class VersionChecker
- def self.check!(*args)
- new(*args).check!
+ def self.check!(*args, **kwargs)
+ new(*args, **kwargs).check!
end
def initialize(shared:)
diff --git a/lib/gitlab/instrumentation/redis.rb b/lib/gitlab/instrumentation/redis.rb
index 4a85a313fd7..d1ac6a55fb7 100644
--- a/lib/gitlab/instrumentation/redis.rb
+++ b/lib/gitlab/instrumentation/redis.rb
@@ -37,7 +37,7 @@ module Gitlab
%i[get_request_count query_time read_bytes write_bytes].each do |method|
define_method method do
- STORAGES.sum(&method) # rubocop:disable CodeReuse/ActiveRecord
+ STORAGES.sum(&method)
end
end
end
diff --git a/lib/gitlab/issuables_count_for_state.rb b/lib/gitlab/issuables_count_for_state.rb
index 7be54a214dd..945ab7f40c2 100644
--- a/lib/gitlab/issuables_count_for_state.rb
+++ b/lib/gitlab/issuables_count_for_state.rb
@@ -16,9 +16,12 @@ module Gitlab
end
# finder - The finder class to use for retrieving the issuables.
- def initialize(finder, project = nil)
+ # fast_fail - restrict counting to a shorter period, degrading gracefully on
+ # failure
+ def initialize(finder, project = nil, fast_fail: false)
@finder = finder
@project = project
+ @fast_fail = fast_fail
@cache = Gitlab::SafeRequestStore[CACHE_KEY] ||= initialize_cache
end
@@ -26,6 +29,10 @@ module Gitlab
self[state || :opened]
end
+ def fast_fail?
+ !!@fast_fail
+ end
+
# Define method for each state
STATES.each do |state|
define_method(state) { self[state] }
@@ -53,7 +60,53 @@ module Gitlab
end
def initialize_cache
- Hash.new { |hash, finder| hash[finder] = finder.count_by_state }
+ Hash.new { |hash, finder| hash[finder] = perform_count(finder) }
+ end
+
+ def perform_count(finder)
+ return finder.count_by_state unless fast_fail?
+
+ fast_count_by_state_attempt!
+
+ # Determining counts when referring to issuable titles or descriptions can
+ # be very expensive, and involve the database reading gigabytes of data
+ # for a relatively minor piece of functionality. This may slow index pages
+ # by seconds in the best case, or lead to a statement timeout in the worst
+ # case.
+ #
+ # In time, we may be able to use elasticsearch or postgresql tsv columns
+ # to perform the calculation more efficiently. Until then, use a shorter
+ # timeout and return -1 as a sentinel value if it is triggered
+ begin
+ ApplicationRecord.with_fast_statement_timeout do
+ finder.count_by_state
+ end
+ rescue ActiveRecord::QueryCanceled => err
+ fast_count_by_state_failure!
+
+ Gitlab::ErrorTracking.track_exception(
+ err,
+ params: finder.params,
+ current_user_id: finder.current_user&.id,
+ issue_url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/249180'
+ )
+
+ Hash.new(-1)
+ end
+ end
+
+ def fast_count_by_state_attempt!
+ Gitlab::Metrics.counter(
+ :gitlab_issuable_fast_count_by_state_total,
+ "Count of total calls to IssuableFinder#count_by_state with fast failure"
+ ).increment
+ end
+
+ def fast_count_by_state_failure!
+ Gitlab::Metrics.counter(
+ :gitlab_issuable_fast_count_by_state_failures_total,
+ "Count of failed calls to IssuableFinder#count_by_state with fast failure"
+ ).increment
end
end
end
diff --git a/lib/gitlab/job_waiter.rb b/lib/gitlab/job_waiter.rb
index e7a8cc6305a..2cede524cac 100644
--- a/lib/gitlab/job_waiter.rb
+++ b/lib/gitlab/job_waiter.rb
@@ -23,7 +23,15 @@ module Gitlab
TIMEOUTS_METRIC = :gitlab_job_waiter_timeouts_total
def self.notify(key, jid)
- Gitlab::Redis::SharedState.with { |redis| redis.lpush(key, jid) }
+ Gitlab::Redis::SharedState.with do |redis|
+ # Use a Redis MULTI transaction to ensure we always set an expiry
+ redis.multi do |multi|
+ multi.lpush(key, jid)
+ # This TTL needs to be long enough to allow whichever Sidekiq job calls
+ # JobWaiter#wait to reach BLPOP.
+ multi.expire(key, 6.hours.to_i)
+ end
+ end
end
def self.key?(key)
@@ -52,10 +60,6 @@ module Gitlab
increment_counter(STARTED_METRIC)
Gitlab::Redis::SharedState.with do |redis|
- # Fallback key expiry: allow a long grace period to reduce the chance of
- # a job pushing to an expired key and recreating it
- redis.expire(key, [timeout * 2, 10.minutes.to_i].max)
-
while jobs_remaining > 0
# Redis will not take fractional seconds. Prefer waiting too long over
# not waiting long enough
@@ -75,9 +79,6 @@ module Gitlab
@finished << jid
@jobs_remaining -= 1
end
-
- # All jobs have finished, so expire the key immediately
- redis.expire(key, 0) if jobs_remaining == 0
end
finished
diff --git a/lib/gitlab/kubernetes/kube_client.rb b/lib/gitlab/kubernetes/kube_client.rb
index fa68afd39f5..13cd6dcad3f 100644
--- a/lib/gitlab/kubernetes/kube_client.rb
+++ b/lib/gitlab/kubernetes/kube_client.rb
@@ -167,6 +167,21 @@ module Gitlab
end
end
+ # Ingresses resource is currently on the apis/extensions api group
+ # until Kubernetes 1.21. Kubernetest 1.22+ has ingresses resources in
+ # the networking.k8s.io/v1 api group.
+ #
+ # As we still support Kubernetes 1.12+, we will need to support both.
+ def get_ingresses(**args)
+ extensions_client.discover unless extensions_client.discovered
+
+ if extensions_client.respond_to?(:get_ingresses)
+ extensions_client.get_ingresses(**args)
+ else
+ networking_client.get_ingresses(**args)
+ end
+ end
+
def create_or_update_cluster_role_binding(resource)
update_cluster_role_binding(resource)
end
diff --git a/lib/gitlab/kubernetes/pod.rb b/lib/gitlab/kubernetes/pod.rb
index d247662dc3b..a5651f2f184 100644
--- a/lib/gitlab/kubernetes/pod.rb
+++ b/lib/gitlab/kubernetes/pod.rb
@@ -2,13 +2,47 @@
module Gitlab
module Kubernetes
- module Pod
+ class Pod
PENDING = 'Pending'
RUNNING = 'Running'
SUCCEEDED = 'Succeeded'
FAILED = 'Failed'
UNKNOWN = 'Unknown'
PHASES = [PENDING, RUNNING, SUCCEEDED, FAILED, UNKNOWN].freeze
+
+ STABLE_TRACK_VALUE = 'stable'
+
+ def initialize(attributes = {})
+ @attributes = attributes
+ end
+
+ def track
+ attributes.dig('metadata', 'labels', 'track') || STABLE_TRACK_VALUE
+ end
+
+ def name
+ metadata['name'] || metadata['generateName']
+ end
+
+ def stable?
+ track == STABLE_TRACK_VALUE
+ end
+
+ def status
+ attributes.dig('status', 'phase')
+ end
+
+ def order
+ stable? ? 1 : 0
+ end
+
+ private
+
+ attr_reader :attributes
+
+ def metadata
+ attributes.fetch('metadata', {})
+ end
end
end
end
diff --git a/lib/gitlab/lfs/client.rb b/lib/gitlab/lfs/client.rb
index e4d600694c2..825d7399190 100644
--- a/lib/gitlab/lfs/client.rb
+++ b/lib/gitlab/lfs/client.rb
@@ -6,6 +6,14 @@ module Gitlab
# * https://github.com/git-lfs/git-lfs/blob/master/docs/api/batch.md
# * https://github.com/git-lfs/git-lfs/blob/master/docs/api/basic-transfers.md
class Client
+ GIT_LFS_CONTENT_TYPE = 'application/vnd.git-lfs+json'
+ GIT_LFS_USER_AGENT = "GitLab #{Gitlab::VERSION} LFS client"
+ DEFAULT_HEADERS = {
+ 'Accept' => GIT_LFS_CONTENT_TYPE,
+ 'Content-Type' => GIT_LFS_CONTENT_TYPE,
+ 'User-Agent' => GIT_LFS_USER_AGENT
+ }.freeze
+
attr_reader :base_url
def initialize(base_url, credentials:)
@@ -13,19 +21,19 @@ module Gitlab
@credentials = credentials
end
- def batch(operation, objects)
+ def batch!(operation, objects)
body = {
operation: operation,
transfers: ['basic'],
# We don't know `ref`, so can't send it
- objects: objects.map { |object| { oid: object.oid, size: object.size } }
+ objects: objects.as_json(only: [:oid, :size])
}
rsp = Gitlab::HTTP.post(
batch_url,
basic_auth: basic_auth,
body: body.to_json,
- headers: { 'Content-Type' => 'application/vnd.git-lfs+json' }
+ headers: build_request_headers
)
raise BatchSubmitError unless rsp.success?
@@ -40,17 +48,19 @@ module Gitlab
body
end
- def upload(object, upload_action, authenticated:)
+ def upload!(object, upload_action, authenticated:)
file = object.file.open
params = {
body_stream: file,
headers: {
'Content-Length' => object.size.to_s,
- 'Content-Type' => 'application/octet-stream'
+ 'Content-Type' => 'application/octet-stream',
+ 'User-Agent' => GIT_LFS_USER_AGENT
}.merge(upload_action['header'] || {})
}
+ authenticated = true if params[:headers].key?('Authorization')
params[:basic_auth] = basic_auth unless authenticated
rsp = Gitlab::HTTP.put(upload_action['href'], params)
@@ -60,8 +70,26 @@ module Gitlab
file&.close
end
+ def verify!(object, verify_action, authenticated:)
+ params = {
+ body: object.to_json(only: [:oid, :size]),
+ headers: build_request_headers(verify_action['header'])
+ }
+
+ authenticated = true if params[:headers].key?('Authorization')
+ params[:basic_auth] = basic_auth unless authenticated
+
+ rsp = Gitlab::HTTP.post(verify_action['href'], params)
+
+ raise ObjectVerifyError unless rsp.success?
+ end
+
private
+ def build_request_headers(extra_headers = nil)
+ DEFAULT_HEADERS.merge(extra_headers || {})
+ end
+
attr_reader :credentials
def batch_url
@@ -96,6 +124,12 @@ module Gitlab
"Failed to upload object"
end
end
+
+ class ObjectVerifyError < StandardError
+ def message
+ "Failed to verify object"
+ end
+ end
end
end
end
diff --git a/lib/gitlab/manifest_import/metadata.rb b/lib/gitlab/manifest_import/metadata.rb
new file mode 100644
index 00000000000..80dff075391
--- /dev/null
+++ b/lib/gitlab/manifest_import/metadata.rb
@@ -0,0 +1,49 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module ManifestImport
+ class Metadata
+ EXPIRY_TIME = 1.week
+
+ attr_reader :user, :fallback
+
+ def initialize(user, fallback: {})
+ @user = user
+ @fallback = fallback
+ end
+
+ def save(repositories, group_id)
+ Gitlab::Redis::SharedState.with do |redis|
+ redis.multi do
+ redis.set(key_for('repositories'), Gitlab::Json.dump(repositories), ex: EXPIRY_TIME)
+ redis.set(key_for('group_id'), group_id, ex: EXPIRY_TIME)
+ end
+ end
+ end
+
+ def repositories
+ redis_get('repositories').then do |repositories|
+ next unless repositories
+
+ Gitlab::Json.parse(repositories).map(&:symbolize_keys)
+ end || fallback[:manifest_import_repositories]
+ end
+
+ def group_id
+ redis_get('group_id')&.to_i || fallback[:manifest_import_group_id]
+ end
+
+ private
+
+ def key_for(field)
+ "manifest_import:metadata:user:#{user.id}:#{field}"
+ end
+
+ def redis_get(field)
+ Gitlab::Redis::SharedState.with do |redis|
+ redis.get(key_for(field))
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/marginalia.rb b/lib/gitlab/marginalia.rb
index 24e21a1d512..325a8c5c325 100644
--- a/lib/gitlab/marginalia.rb
+++ b/lib/gitlab/marginalia.rb
@@ -4,8 +4,6 @@ module Gitlab
module Marginalia
cattr_accessor :enabled, default: false
- MARGINALIA_FEATURE_FLAG = :marginalia
-
def self.set_application_name
::Marginalia.application_name = Gitlab.process_name
end
@@ -16,15 +14,11 @@ module Gitlab
end
end
- def self.cached_feature_enabled?
- enabled
- end
-
- def self.set_feature_cache
+ def self.set_enabled_from_feature_flag
# During db:create and db:bootstrap skip feature query as DB is not available yet.
return false unless Gitlab::Database.cached_table_exists?('features')
- self.enabled = Feature.enabled?(MARGINALIA_FEATURE_FLAG)
+ self.enabled = Feature.enabled?(:marginalia, type: :ops)
end
end
end
diff --git a/lib/gitlab/marginalia/active_record_instrumentation.rb b/lib/gitlab/marginalia/active_record_instrumentation.rb
index 3266b9f8336..452f472bf6a 100644
--- a/lib/gitlab/marginalia/active_record_instrumentation.rb
+++ b/lib/gitlab/marginalia/active_record_instrumentation.rb
@@ -5,7 +5,7 @@ module Gitlab
module Marginalia
module ActiveRecordInstrumentation
def annotate_sql(sql)
- Gitlab::Marginalia.cached_feature_enabled? ? super(sql) : sql
+ Gitlab::Marginalia.enabled ? super(sql) : sql
end
end
end
diff --git a/lib/gitlab/markdown_cache.rb b/lib/gitlab/markdown_cache.rb
index da3b597a74e..36e9a6ccef6 100644
--- a/lib/gitlab/markdown_cache.rb
+++ b/lib/gitlab/markdown_cache.rb
@@ -3,7 +3,7 @@
module Gitlab
module MarkdownCache
# Increment this number every time the renderer changes its output
- CACHE_COMMONMARK_VERSION = 25
+ CACHE_COMMONMARK_VERSION = 26
CACHE_COMMONMARK_VERSION_START = 10
BaseError = Class.new(StandardError)
diff --git a/lib/gitlab/metrics/dashboard/importers/prometheus_metrics.rb b/lib/gitlab/metrics/dashboard/importers/prometheus_metrics.rb
index d1490d5d9b6..8a176be30a2 100644
--- a/lib/gitlab/metrics/dashboard/importers/prometheus_metrics.rb
+++ b/lib/gitlab/metrics/dashboard/importers/prometheus_metrics.rb
@@ -13,11 +13,12 @@ module Gitlab
@dashboard_hash = dashboard_hash
@project = project
@dashboard_path = dashboard_path
+ @affected_environment_ids = []
end
def execute
import
- rescue ActiveRecord::RecordInvalid, ::Gitlab::Metrics::Dashboard::Transformers::TransformerError
+ rescue ActiveRecord::RecordInvalid, Dashboard::Transformers::Errors::BaseError
false
end
@@ -32,28 +33,51 @@ module Gitlab
def import
delete_stale_metrics
create_or_update_metrics
+ update_prometheus_environments
end
# rubocop: disable CodeReuse/ActiveRecord
def create_or_update_metrics
# TODO: use upsert and worker for callbacks?
+
+ affected_metric_ids = []
prometheus_metrics_attributes.each do |attributes|
- prometheus_metric = PrometheusMetric.find_or_initialize_by(attributes.slice(:identifier, :project))
+ prometheus_metric = PrometheusMetric.find_or_initialize_by(attributes.slice(:dashboard_path, :identifier, :project))
prometheus_metric.update!(attributes.slice(*ALLOWED_ATTRIBUTES))
+
+ affected_metric_ids << prometheus_metric.id
end
+
+ @affected_environment_ids += find_alerts(affected_metric_ids).get_environment_id
end
# rubocop: enable CodeReuse/ActiveRecord
def delete_stale_metrics
- identifiers = prometheus_metrics_attributes.map { |metric_attributes| metric_attributes[:identifier] }
+ identifiers_from_yml = prometheus_metrics_attributes.map { |metric_attributes| metric_attributes[:identifier] }
stale_metrics = PrometheusMetric.for_project(project)
.for_dashboard_path(dashboard_path)
.for_group(Enums::PrometheusMetric.groups[:custom])
- .not_identifier(identifiers)
+ .not_identifier(identifiers_from_yml)
+
+ return unless stale_metrics.exists?
+
+ delete_stale_alerts(stale_metrics)
+ stale_metrics.each_batch { |batch| batch.delete_all }
+ end
+
+ def delete_stale_alerts(stale_metrics)
+ stale_alerts = find_alerts(stale_metrics)
+
+ affected_environment_ids = stale_alerts.get_environment_id
+ return unless affected_environment_ids.present?
- # TODO: use destroy_all and worker for callbacks?
- stale_metrics.each(&:destroy)
+ @affected_environment_ids += affected_environment_ids
+ stale_alerts.each_batch { |batch| batch.delete_all }
+ end
+
+ def find_alerts(metrics)
+ Projects::Prometheus::AlertsFinder.new(project: project, metric: metrics).execute
end
def prometheus_metrics_attributes
@@ -65,6 +89,19 @@ module Gitlab
).execute
end
end
+
+ def update_prometheus_environments
+ affected_environments = ::Environment.for_id(@affected_environment_ids.flatten.uniq).for_project(project)
+
+ return unless affected_environments.exists?
+
+ affected_environments.each do |affected_environment|
+ ::Clusters::Applications::ScheduleUpdateService.new(
+ affected_environment.cluster_prometheus_adapter,
+ project
+ ).execute
+ end
+ end
end
end
end
diff --git a/lib/gitlab/metrics/dashboard/stages/custom_dashboard_metrics_inserter.rb b/lib/gitlab/metrics/dashboard/stages/custom_dashboard_metrics_inserter.rb
new file mode 100644
index 00000000000..5ed4466f440
--- /dev/null
+++ b/lib/gitlab/metrics/dashboard/stages/custom_dashboard_metrics_inserter.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Metrics
+ module Dashboard
+ module Stages
+ # Acts on metrics which have been ingested from source controlled dashboards
+ class CustomDashboardMetricsInserter < BaseStage
+ # For each metric in the dashboard config, attempts to
+ # find a corresponding database record. If found, includes
+ # the record's id in the dashboard config.
+ def transform!
+ database_metrics = ::PrometheusMetricsFinder.new(common: false, group: :custom, project: project).execute
+
+ for_metrics do |metric|
+ metric_record = database_metrics.find { |m| m.identifier == metric[:id] }
+ metric[:metric_id] = metric_record.id if metric_record
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/metrics/dashboard/stages/url_validator.rb b/lib/gitlab/metrics/dashboard/stages/url_validator.rb
index 9e2bb0d1a70..ad9d78133af 100644
--- a/lib/gitlab/metrics/dashboard/stages/url_validator.rb
+++ b/lib/gitlab/metrics/dashboard/stages/url_validator.rb
@@ -46,7 +46,7 @@ module Gitlab
links&.each do |link|
next unless link.is_a? Hash
- Gitlab::UrlBlocker.validate!(link[:url], blocker_args)
+ Gitlab::UrlBlocker.validate!(link[:url], **blocker_args)
rescue Gitlab::UrlBlocker::BlockedUrlError
link[:url] = ''
end
diff --git a/lib/gitlab/metrics/dashboard/transformers/errors.rb b/lib/gitlab/metrics/dashboard/transformers/errors.rb
index 4d94ab098ae..bc85dc4e131 100644
--- a/lib/gitlab/metrics/dashboard/transformers/errors.rb
+++ b/lib/gitlab/metrics/dashboard/transformers/errors.rb
@@ -4,10 +4,10 @@ module Gitlab
module Metrics
module Dashboard
module Transformers
- TransformerError = Class.new(StandardError)
-
module Errors
- class MissingAttribute < TransformerError
+ BaseError = Class.new(StandardError)
+
+ class MissingAttribute < BaseError
def initialize(attribute_name)
super("Missing attribute: '#{attribute_name}'")
end
diff --git a/lib/gitlab/metrics/requests_rack_middleware.rb b/lib/gitlab/metrics/requests_rack_middleware.rb
index 15db3999fa4..f6bda0dbea4 100644
--- a/lib/gitlab/metrics/requests_rack_middleware.rb
+++ b/lib/gitlab/metrics/requests_rack_middleware.rb
@@ -3,20 +3,13 @@
module Gitlab
module Metrics
class RequestsRackMiddleware
- HTTP_METHODS = {
- "delete" => %w(200 202 204 303 400 401 403 404 410 422 500 503),
- "get" => %w(200 204 301 302 303 304 307 400 401 403 404 410 412 422 429 500 503),
- "head" => %w(200 204 301 302 303 304 400 401 403 404 410 429 500 503),
- "options" => %w(200 404),
- "patch" => %w(200 202 204 400 403 404 409 416 422 500),
- "post" => %w(200 201 202 204 301 302 303 304 400 401 403 404 406 409 410 412 413 415 422 429 500 503),
- "propfind" => %w(404),
- "put" => %w(200 202 204 400 401 403 404 405 406 409 410 415 422 500),
- "report" => %w(404)
- }.freeze
+ HTTP_METHODS = %w(delete get head options patch post put).to_set.freeze
HEALTH_ENDPOINT = /^\/-\/(liveness|readiness|health|metrics)\/?$/.freeze
+ FEATURE_CATEGORY_HEADER = 'X-Gitlab-Feature-Category'
+ FEATURE_CATEGORY_DEFAULT = 'unknown'
+
def initialize(app)
@app = app
end
@@ -39,33 +32,39 @@ module Gitlab
end
def self.initialize_http_request_duration_seconds
- HTTP_METHODS.each do |method, statuses|
- statuses.each do |status|
- http_request_duration_seconds.get({ method: method, status: status.to_s })
- end
+ HTTP_METHODS.each do |method|
+ http_request_duration_seconds.get({ method: method })
end
end
def call(env)
method = env['REQUEST_METHOD'].downcase
+ method = 'INVALID' unless HTTP_METHODS.include?(method)
started = Time.now.to_f
+ health_endpoint = health_endpoint?(env['PATH_INFO'])
+ status = 'undefined'
+ feature_category = nil
begin
- if health_endpoint?(env['PATH_INFO'])
- RequestsRackMiddleware.http_health_requests_total.increment(method: method)
- else
- RequestsRackMiddleware.http_request_total.increment(method: method)
- end
-
status, headers, body = @app.call(env)
elapsed = Time.now.to_f - started
- RequestsRackMiddleware.http_request_duration_seconds.observe({ method: method, status: status.to_s }, elapsed)
+ feature_category = headers&.fetch(FEATURE_CATEGORY_HEADER, nil)
+
+ unless health_endpoint
+ RequestsRackMiddleware.http_request_duration_seconds.observe({ method: method }, elapsed)
+ end
[status, headers, body]
rescue
RequestsRackMiddleware.rack_uncaught_errors_count.increment
raise
+ ensure
+ if health_endpoint
+ RequestsRackMiddleware.http_health_requests_total.increment(status: status, method: method)
+ else
+ RequestsRackMiddleware.http_request_total.increment(status: status, method: method, feature_category: feature_category || FEATURE_CATEGORY_DEFAULT)
+ end
end
end
diff --git a/lib/gitlab/metrics/samplers/unicorn_sampler.rb b/lib/gitlab/metrics/samplers/unicorn_sampler.rb
index 8c4d150adad..d7935d65e12 100644
--- a/lib/gitlab/metrics/samplers/unicorn_sampler.rb
+++ b/lib/gitlab/metrics/samplers/unicorn_sampler.rb
@@ -54,7 +54,7 @@ module Gitlab
end
def unicorn_workers_count
- http_servers.sum(&:worker_processes) # rubocop: disable CodeReuse/ActiveRecord
+ http_servers.sum(&:worker_processes)
end
# Traversal of ObjectSpace is expensive, on fully loaded application
diff --git a/lib/gitlab/metrics/subscribers/active_record.rb b/lib/gitlab/metrics/subscribers/active_record.rb
index e53ac00e77f..f9ba0a69b0e 100644
--- a/lib/gitlab/metrics/subscribers/active_record.rb
+++ b/lib/gitlab/metrics/subscribers/active_record.rb
@@ -61,7 +61,7 @@ module Gitlab
end
def current_transaction
- Transaction.current
+ ::Gitlab::Metrics::Transaction.current
end
end
end
diff --git a/lib/gitlab/middleware/go.rb b/lib/gitlab/middleware/go.rb
index 47d0b9ba8cb..4b65bbcc791 100644
--- a/lib/gitlab/middleware/go.rb
+++ b/lib/gitlab/middleware/go.rb
@@ -18,6 +18,15 @@ module Gitlab
request = ActionDispatch::Request.new(env)
render_go_doc(request) || @app.call(env)
+ rescue Gitlab::Auth::IpBlacklisted
+ Gitlab::AuthLogger.error(
+ message: 'Rack_Attack',
+ env: :blocklist,
+ remote_ip: request.ip,
+ request_method: request.request_method,
+ path: request.fullpath
+ )
+ Rack::Response.new('', 403).finish
end
private
diff --git a/lib/gitlab/middleware/handle_null_bytes.rb b/lib/gitlab/middleware/handle_null_bytes.rb
new file mode 100644
index 00000000000..c88dfb6ee0b
--- /dev/null
+++ b/lib/gitlab/middleware/handle_null_bytes.rb
@@ -0,0 +1,61 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Middleware
+ # There is no valid reason for a request to contain a null byte (U+0000)
+ # so just return HTTP 400 (Bad Request) if we receive one
+ class HandleNullBytes
+ NULL_BYTE_REGEX = Regexp.new(Regexp.escape("\u0000")).freeze
+
+ attr_reader :app
+
+ def initialize(app)
+ @app = app
+ end
+
+ def call(env)
+ return [400, {}, ["Bad Request"]] if request_has_null_byte?(env)
+
+ app.call(env)
+ end
+
+ private
+
+ def request_has_null_byte?(request)
+ return false if ENV['REJECT_NULL_BYTES'] == "1"
+
+ request = Rack::Request.new(request)
+
+ request.params.values.any? do |value|
+ param_has_null_byte?(value)
+ end
+ end
+
+ def param_has_null_byte?(value, depth = 0)
+ # Guard against possible attack sending large amounts of nested params
+ # Should be safe as deeply nested params are highly uncommon.
+ return false if depth > 2
+
+ depth += 1
+
+ if value.respond_to?(:match)
+ string_contains_null_byte?(value)
+ elsif value.respond_to?(:values)
+ value.values.any? do |hash_value|
+ param_has_null_byte?(hash_value, depth)
+ end
+ elsif value.is_a?(Array)
+ value.any? do |array_value|
+ param_has_null_byte?(array_value, depth)
+ end
+ else
+ false
+ end
+ end
+
+ def string_contains_null_byte?(string)
+ string.match?(NULL_BYTE_REGEX)
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/middleware/multipart.rb b/lib/gitlab/middleware/multipart.rb
index 8e6ac7610f2..7e98f1fc1f7 100644
--- a/lib/gitlab/middleware/multipart.rb
+++ b/lib/gitlab/middleware/multipart.rb
@@ -137,6 +137,7 @@ module Gitlab
# TODO this class is meant to replace Handler when the feature flag
# upload_middleware_jwt_params_handler is removed
+ # See https://gitlab.com/gitlab-org/gitlab/-/issues/233895#roll-out-steps
class HandlerForJWTParams < Handler
def with_open_files
@rewritten_fields.keys.each do |field|
@@ -228,7 +229,7 @@ module Gitlab
private
def handler_class
- if Feature.enabled?(:upload_middleware_jwt_params_handler)
+ if Feature.enabled?(:upload_middleware_jwt_params_handler, default_enabled: true)
::Gitlab::Middleware::Multipart::HandlerForJWTParams
else
::Gitlab::Middleware::Multipart::Handler
diff --git a/lib/gitlab/pagination/offset_pagination.rb b/lib/gitlab/pagination/offset_pagination.rb
index 8796dd4d7ec..46c74b8fe3c 100644
--- a/lib/gitlab/pagination/offset_pagination.rb
+++ b/lib/gitlab/pagination/offset_pagination.rb
@@ -10,9 +10,9 @@ module Gitlab
@request_context = request_context
end
- def paginate(relation)
+ def paginate(relation, exclude_total_headers: false)
paginate_with_limit_optimization(add_default_order(relation)).tap do |data|
- add_pagination_headers(data)
+ add_pagination_headers(data, exclude_total_headers)
end
end
@@ -27,7 +27,7 @@ module Gitlab
end
return pagination_data unless pagination_data.is_a?(ActiveRecord::Relation)
- return pagination_data unless Feature.enabled?(:api_kaminari_count_with_limit)
+ return pagination_data unless Feature.enabled?(:api_kaminari_count_with_limit, type: :ops)
limited_total_count = pagination_data.total_count_with_limit
if limited_total_count > Kaminari::ActiveRecordRelationMethods::MAX_COUNT_LIMIT
@@ -47,14 +47,14 @@ module Gitlab
relation
end
- def add_pagination_headers(paginated_data)
+ def add_pagination_headers(paginated_data, exclude_total_headers)
header 'X-Per-Page', paginated_data.limit_value.to_s
header 'X-Page', paginated_data.current_page.to_s
header 'X-Next-Page', paginated_data.next_page.to_s
header 'X-Prev-Page', paginated_data.prev_page.to_s
header 'Link', pagination_links(paginated_data)
- return if data_without_counts?(paginated_data)
+ return if exclude_total_headers || data_without_counts?(paginated_data)
header 'X-Total', paginated_data.total_count.to_s
header 'X-Total-Pages', total_pages(paginated_data).to_s
diff --git a/lib/gitlab/project_search_results.rb b/lib/gitlab/project_search_results.rb
index ded8d4ade3f..333564bee01 100644
--- a/lib/gitlab/project_search_results.rb
+++ b/lib/gitlab/project_search_results.rb
@@ -4,11 +4,11 @@ module Gitlab
class ProjectSearchResults < SearchResults
attr_reader :project, :repository_ref
- def initialize(current_user, query, project:, repository_ref: nil, filters: {})
+ def initialize(current_user, query, project:, repository_ref: nil, sort: nil, filters: {})
@project = project
@repository_ref = repository_ref.presence
- super(current_user, query, [project], filters: filters)
+ super(current_user, query, [project], sort: sort, filters: filters)
end
def objects(scope, page: nil, per_page: DEFAULT_PER_PAGE, preload_method: nil)
diff --git a/lib/gitlab/project_template.rb b/lib/gitlab/project_template.rb
index e6e599e079d..a830f949b21 100644
--- a/lib/gitlab/project_template.rb
+++ b/lib/gitlab/project_template.rb
@@ -36,35 +36,37 @@ module Gitlab
name == other.name && title == other.title
end
- def self.localized_templates_table
- [
- ProjectTemplate.new('rails', 'Ruby on Rails', _('Includes an MVC structure, Gemfile, Rakefile, along with many others, to help you get started.'), 'https://gitlab.com/gitlab-org/project-templates/rails', 'illustrations/logos/rails.svg'),
- ProjectTemplate.new('spring', 'Spring', _('Includes an MVC structure, mvnw and pom.xml to help you get started.'), 'https://gitlab.com/gitlab-org/project-templates/spring', 'illustrations/logos/spring.svg'),
- ProjectTemplate.new('express', 'NodeJS Express', _('Includes an MVC structure to help you get started.'), 'https://gitlab.com/gitlab-org/project-templates/express', 'illustrations/logos/express.svg'),
- ProjectTemplate.new('iosswift', 'iOS (Swift)', _('A ready-to-go template for use with iOS Swift apps.'), 'https://gitlab.com/gitlab-org/project-templates/iosswift', 'illustrations/logos/swift.svg'),
- ProjectTemplate.new('dotnetcore', '.NET Core', _('A .NET Core console application template, customizable for any .NET Core project'), 'https://gitlab.com/gitlab-org/project-templates/dotnetcore', 'illustrations/logos/dotnet.svg'),
- ProjectTemplate.new('android', 'Android', _('A ready-to-go template for use with Android apps.'), 'https://gitlab.com/gitlab-org/project-templates/android', 'illustrations/logos/android.svg'),
- ProjectTemplate.new('gomicro', 'Go Micro', _('Go Micro is a framework for micro service development.'), 'https://gitlab.com/gitlab-org/project-templates/go-micro', 'illustrations/logos/gomicro.svg'),
- ProjectTemplate.new('gatsby', 'Pages/Gatsby', _('Everything you need to create a GitLab Pages site using Gatsby.'), 'https://gitlab.com/pages/gatsby'),
- ProjectTemplate.new('hugo', 'Pages/Hugo', _('Everything you need to create a GitLab Pages site using Hugo.'), 'https://gitlab.com/pages/hugo', 'illustrations/logos/hugo.svg'),
- ProjectTemplate.new('jekyll', 'Pages/Jekyll', _('Everything you need to create a GitLab Pages site using Jekyll.'), 'https://gitlab.com/pages/jekyll', 'illustrations/logos/jekyll.svg'),
- ProjectTemplate.new('plainhtml', 'Pages/Plain HTML', _('Everything you need to create a GitLab Pages site using plain HTML.'), 'https://gitlab.com/pages/plain-html'),
- ProjectTemplate.new('gitbook', 'Pages/GitBook', _('Everything you need to create a GitLab Pages site using GitBook.'), 'https://gitlab.com/pages/gitbook', 'illustrations/logos/gitbook.svg'),
- ProjectTemplate.new('hexo', 'Pages/Hexo', _('Everything you need to create a GitLab Pages site using Hexo.'), 'https://gitlab.com/pages/hexo', 'illustrations/logos/hexo.svg'),
- ProjectTemplate.new('sse_middleman', 'Static Site Editor/Middleman', _('Middleman project with Static Site Editor support'), 'https://gitlab.com/gitlab-org/project-templates/static-site-editor-middleman'),
- ProjectTemplate.new('nfhugo', 'Netlify/Hugo', _('A Hugo site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features.'), 'https://gitlab.com/pages/nfhugo', 'illustrations/logos/netlify.svg'),
- ProjectTemplate.new('nfjekyll', 'Netlify/Jekyll', _('A Jekyll site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features.'), 'https://gitlab.com/pages/nfjekyll', 'illustrations/logos/netlify.svg'),
- ProjectTemplate.new('nfplainhtml', 'Netlify/Plain HTML', _('A plain HTML site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features.'), 'https://gitlab.com/pages/nfplain-html', 'illustrations/logos/netlify.svg'),
- ProjectTemplate.new('nfgitbook', 'Netlify/GitBook', _('A GitBook site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features.'), 'https://gitlab.com/pages/nfgitbook', 'illustrations/logos/netlify.svg'),
- ProjectTemplate.new('nfhexo', 'Netlify/Hexo', _('A Hexo site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features.'), 'https://gitlab.com/pages/nfhexo', 'illustrations/logos/netlify.svg'),
- ProjectTemplate.new('salesforcedx', 'SalesforceDX', _('A project boilerplate for Salesforce App development with Salesforce Developer tools.'), 'https://gitlab.com/gitlab-org/project-templates/salesforcedx'),
- ProjectTemplate.new('serverless_framework', 'Serverless Framework/JS', _('A basic page and serverless function that uses AWS Lambda, AWS API Gateway, and GitLab Pages'), 'https://gitlab.com/gitlab-org/project-templates/serverless-framework', 'illustrations/logos/serverless_framework.svg'),
- ProjectTemplate.new('jsonnet', 'Jsonnet for Dynamic Child Pipelines', _('An example showing how to use Jsonnet with GitLab dynamic child pipelines'), 'https://gitlab.com/gitlab-org/project-templates/jsonnet'),
- ProjectTemplate.new('cluster_management', 'GitLab Cluster Management', _('An example project for managing Kubernetes clusters integrated with GitLab.'), 'https://gitlab.com/gitlab-org/project-templates/cluster-management')
- ].freeze
- end
-
class << self
+ # TODO: Review child inheritance of this table (see: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/41699#note_430928221)
+ def localized_templates_table
+ [
+ ProjectTemplate.new('rails', 'Ruby on Rails', _('Includes an MVC structure, Gemfile, Rakefile, along with many others, to help you get started.'), 'https://gitlab.com/gitlab-org/project-templates/rails', 'illustrations/logos/rails.svg'),
+ ProjectTemplate.new('spring', 'Spring', _('Includes an MVC structure, mvnw and pom.xml to help you get started.'), 'https://gitlab.com/gitlab-org/project-templates/spring', 'illustrations/logos/spring.svg'),
+ ProjectTemplate.new('express', 'NodeJS Express', _('Includes an MVC structure to help you get started.'), 'https://gitlab.com/gitlab-org/project-templates/express', 'illustrations/logos/express.svg'),
+ ProjectTemplate.new('iosswift', 'iOS (Swift)', _('A ready-to-go template for use with iOS Swift apps.'), 'https://gitlab.com/gitlab-org/project-templates/iosswift', 'illustrations/logos/swift.svg'),
+ ProjectTemplate.new('dotnetcore', '.NET Core', _('A .NET Core console application template, customizable for any .NET Core project'), 'https://gitlab.com/gitlab-org/project-templates/dotnetcore', 'illustrations/logos/dotnet.svg'),
+ ProjectTemplate.new('android', 'Android', _('A ready-to-go template for use with Android apps.'), 'https://gitlab.com/gitlab-org/project-templates/android', 'illustrations/logos/android.svg'),
+ ProjectTemplate.new('gomicro', 'Go Micro', _('Go Micro is a framework for micro service development.'), 'https://gitlab.com/gitlab-org/project-templates/go-micro', 'illustrations/logos/gomicro.svg'),
+ ProjectTemplate.new('gatsby', 'Pages/Gatsby', _('Everything you need to create a GitLab Pages site using Gatsby.'), 'https://gitlab.com/pages/gatsby'),
+ ProjectTemplate.new('hugo', 'Pages/Hugo', _('Everything you need to create a GitLab Pages site using Hugo.'), 'https://gitlab.com/pages/hugo', 'illustrations/logos/hugo.svg'),
+ ProjectTemplate.new('jekyll', 'Pages/Jekyll', _('Everything you need to create a GitLab Pages site using Jekyll.'), 'https://gitlab.com/pages/jekyll', 'illustrations/logos/jekyll.svg'),
+ ProjectTemplate.new('plainhtml', 'Pages/Plain HTML', _('Everything you need to create a GitLab Pages site using plain HTML.'), 'https://gitlab.com/pages/plain-html'),
+ ProjectTemplate.new('gitbook', 'Pages/GitBook', _('Everything you need to create a GitLab Pages site using GitBook.'), 'https://gitlab.com/pages/gitbook', 'illustrations/logos/gitbook.svg'),
+ ProjectTemplate.new('hexo', 'Pages/Hexo', _('Everything you need to create a GitLab Pages site using Hexo.'), 'https://gitlab.com/pages/hexo', 'illustrations/logos/hexo.svg'),
+ ProjectTemplate.new('sse_middleman', 'Static Site Editor/Middleman', _('Middleman project with Static Site Editor support'), 'https://gitlab.com/gitlab-org/project-templates/static-site-editor-middleman', 'illustrations/logos/middleman.svg'),
+ ProjectTemplate.new('gitpod_spring_petclinic', 'Gitpod/Spring Petclinic', _('A Gitpod configured Webapplication in Spring and Java'), 'https://gitlab.com/gitlab-org/project-templates/gitpod-spring-petclinic', 'illustrations/logos/gitpod.svg'),
+ ProjectTemplate.new('nfhugo', 'Netlify/Hugo', _('A Hugo site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features.'), 'https://gitlab.com/pages/nfhugo', 'illustrations/logos/netlify.svg'),
+ ProjectTemplate.new('nfjekyll', 'Netlify/Jekyll', _('A Jekyll site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features.'), 'https://gitlab.com/pages/nfjekyll', 'illustrations/logos/netlify.svg'),
+ ProjectTemplate.new('nfplainhtml', 'Netlify/Plain HTML', _('A plain HTML site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features.'), 'https://gitlab.com/pages/nfplain-html', 'illustrations/logos/netlify.svg'),
+ ProjectTemplate.new('nfgitbook', 'Netlify/GitBook', _('A GitBook site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features.'), 'https://gitlab.com/pages/nfgitbook', 'illustrations/logos/netlify.svg'),
+ ProjectTemplate.new('nfhexo', 'Netlify/Hexo', _('A Hexo site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features.'), 'https://gitlab.com/pages/nfhexo', 'illustrations/logos/netlify.svg'),
+ ProjectTemplate.new('salesforcedx', 'SalesforceDX', _('A project boilerplate for Salesforce App development with Salesforce Developer tools.'), 'https://gitlab.com/gitlab-org/project-templates/salesforcedx'),
+ ProjectTemplate.new('serverless_framework', 'Serverless Framework/JS', _('A basic page and serverless function that uses AWS Lambda, AWS API Gateway, and GitLab Pages'), 'https://gitlab.com/gitlab-org/project-templates/serverless-framework', 'illustrations/logos/serverless_framework.svg'),
+ ProjectTemplate.new('jsonnet', 'Jsonnet for Dynamic Child Pipelines', _('An example showing how to use Jsonnet with GitLab dynamic child pipelines'), 'https://gitlab.com/gitlab-org/project-templates/jsonnet'),
+ ProjectTemplate.new('cluster_management', 'GitLab Cluster Management', _('An example project for managing Kubernetes clusters integrated with GitLab.'), 'https://gitlab.com/gitlab-org/project-templates/cluster-management')
+ ].freeze
+ end
+
def all
localized_templates_table
end
diff --git a/lib/gitlab/quick_actions/issuable_actions.rb b/lib/gitlab/quick_actions/issuable_actions.rb
index 6aa3f515ef0..efe07aa8ab2 100644
--- a/lib/gitlab/quick_actions/issuable_actions.rb
+++ b/lib/gitlab/quick_actions/issuable_actions.rb
@@ -145,9 +145,9 @@ module Gitlab
run_label_command(labels: find_labels(labels_param), command: :relabel, updates_key: :label_ids)
end
- desc _('Add a To Do')
- explanation _('Adds a To Do.')
- execution_message _('Added a To Do.')
+ desc _('Add a to do')
+ explanation _('Adds a to do.')
+ execution_message _('Added a to do.')
types Issuable
condition do
quick_action_target.persisted? &&
@@ -157,9 +157,9 @@ module Gitlab
@updates[:todo_event] = 'add'
end
- desc _('Mark To Do as done')
- explanation _('Marks To Do as done.')
- execution_message _('Marked To Do as done.')
+ desc _('Mark to do as done')
+ explanation _('Marks to do as done.')
+ execution_message _('Marked to do as done.')
types Issuable
condition do
quick_action_target.persisted? &&
diff --git a/lib/gitlab/quick_actions/merge_request_actions.rb b/lib/gitlab/quick_actions/merge_request_actions.rb
index 98db8ff761e..c8c949a9363 100644
--- a/lib/gitlab/quick_actions/merge_request_actions.rb
+++ b/lib/gitlab/quick_actions/merge_request_actions.rb
@@ -121,6 +121,20 @@ module Gitlab
result[:message]
end
end
+
+ desc _('Approve a merge request')
+ explanation _('Approve the current merge request.')
+ types MergeRequest
+ condition do
+ quick_action_target.persisted? && quick_action_target.can_be_approved_by?(current_user)
+ end
+ command :approve do
+ success = MergeRequests::ApprovalService.new(quick_action_target.project, current_user).execute(quick_action_target)
+
+ next unless success
+
+ @execution_message[:approve] = _('Approved the current merge request.')
+ end
end
def merge_orchestration_service
diff --git a/lib/gitlab/redis/hll.rb b/lib/gitlab/redis/hll.rb
index ff5754675e2..010a6b59da5 100644
--- a/lib/gitlab/redis/hll.rb
+++ b/lib/gitlab/redis/hll.rb
@@ -3,15 +3,16 @@
module Gitlab
module Redis
class HLL
+ BATCH_SIZE = 300
KEY_REGEX = %r{\A(\w|-|:)*\{\w*\}(\w|-|:)*\z}.freeze
KeyFormatError = Class.new(StandardError)
def self.count(params)
- self.new.count(params)
+ self.new.count(**params)
end
def self.add(params)
- self.new.add(params)
+ self.new.add(**params)
end
def count(keys:)
@@ -29,17 +30,24 @@ module Gitlab
# 2020-216-{project_action}
# i_{analytics}_dev_ops_score-2020-32
def add(key:, value:, expiry:)
- unless KEY_REGEX.match?(key)
- raise KeyFormatError.new("Invalid key format. #{key} key should have changeable parts in curly braces. See https://docs.gitlab.com/ee/development/redis.html#multi-key-commands")
- end
+ validate_key!(key)
Gitlab::Redis::SharedState.with do |redis|
redis.multi do |multi|
- multi.pfadd(key, value)
+ Array.wrap(value).each_slice(BATCH_SIZE) { |batch| multi.pfadd(key, batch) }
+
multi.expire(key, expiry)
end
end
end
+
+ private
+
+ def validate_key!(key)
+ return if KEY_REGEX.match?(key)
+
+ raise KeyFormatError.new("Invalid key format. #{key} key should have changeable parts in curly braces. See https://docs.gitlab.com/ee/development/redis.html#multi-key-commands")
+ end
end
end
end
diff --git a/lib/gitlab/regex.rb b/lib/gitlab/regex.rb
index 8e23ac6aca5..693a10a9de3 100644
--- a/lib/gitlab/regex.rb
+++ b/lib/gitlab/regex.rb
@@ -46,6 +46,12 @@ module Gitlab
maven_app_name_regex
end
+ def nuget_version_regex
+ @nuget_version_regex ||= /
+ \A#{_semver_major_minor_patch_regex}(\.\d*)?#{_semver_prerelease_build_regex}\z
+ /x.freeze
+ end
+
def pypi_version_regex
# See the official regex: https://github.com/pypa/packaging/blob/16.7/packaging/version.py#L159
@@ -61,6 +67,39 @@ module Gitlab
)\z}xi.freeze
end
+ def debian_package_name_regex
+ # See official parser
+ # https://git.dpkg.org/cgit/dpkg/dpkg.git/tree/lib/dpkg/parsehelp.c?id=9e0c88ec09475f4d1addde9cdba1ad7849720356#n122
+ # @debian_package_name_regex ||= %r{\A[a-z0-9][-+\._a-z0-9]*\z}i.freeze
+ # But we prefer a more strict version from Lintian
+ # https://salsa.debian.org/lintian/lintian/-/blob/5080c0068ffc4a9ddee92022a91d0c2ff53e56d1/lib/Lintian/Util.pm#L116
+ @debian_package_name_regex ||= %r{\A[a-z0-9][-+\.a-z0-9]+\z}.freeze
+ end
+
+ def debian_version_regex
+ # See official parser: https://git.dpkg.org/cgit/dpkg/dpkg.git/tree/lib/dpkg/parsehelp.c?id=9e0c88ec09475f4d1addde9cdba1ad7849720356#n205
+ @debian_version_regex ||= %r{
+ \A(?:
+ (?:([0-9]{1,9}):)? (?# epoch)
+ ([0-9][0-9a-z\.+~-]*) (?# version)
+ (?:(-[0-0a-z\.+~]+))? (?# revision)
+ )\z}xi.freeze
+ end
+
+ def debian_architecture_regex
+ # See official parser: https://git.dpkg.org/cgit/dpkg/dpkg.git/tree/lib/dpkg/arch.c?id=9e0c88ec09475f4d1addde9cdba1ad7849720356#n43
+ # But we limit to lower case
+ @debian_architecture_regex ||= %r{\A[a-z0-9][-a-z0-9]*\z}.freeze
+ end
+
+ def debian_distribution_regex
+ @debian_distribution_regex ||= %r{\A[a-z0-9][a-z0-9\.-]*\z}i.freeze
+ end
+
+ def debian_component_regex
+ @debian_component_regex ||= %r{#{debian_distribution_regex}}.freeze
+ end
+
def unbounded_semver_regex
# See the official regex: https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string
@@ -68,16 +107,34 @@ module Gitlab
# reordered to be greedy. Without this change, the unbounded regex would
# only partially match "v0.0.0-20201230123456-abcdefabcdef".
@unbounded_semver_regex ||= /
+ #{_semver_major_minor_patch_regex}#{_semver_prerelease_build_regex}
+ /x.freeze
+ end
+
+ def semver_regex
+ @semver_regex ||= Regexp.new("\\A#{::Gitlab::Regex.unbounded_semver_regex.source}\\z", ::Gitlab::Regex.unbounded_semver_regex.options)
+ end
+
+ # These partial semver regexes are intended for use in composing other
+ # regexes rather than being used alone.
+ def _semver_major_minor_patch_regex
+ @_semver_major_minor_patch_regex ||= /
(?<major>0|[1-9]\d*)
\.(?<minor>0|[1-9]\d*)
\.(?<patch>0|[1-9]\d*)
+ /x.freeze
+ end
+
+ def _semver_prerelease_build_regex
+ @_semver_prerelease_build_regex ||= /
(?:-(?<prerelease>(?:\d*[a-zA-Z-][0-9a-zA-Z-]*|[1-9]\d*|0)(?:\.(?:\d*[a-zA-Z-][0-9a-zA-Z-]*|[1-9]\d*|0))*))?
(?:\+(?<build>[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?
/x.freeze
end
- def semver_regex
- @semver_regex ||= Regexp.new("\\A#{::Gitlab::Regex.unbounded_semver_regex.source}\\z", ::Gitlab::Regex.unbounded_semver_regex.options)
+ def prefixed_semver_regex
+ # identical to semver_regex, except starting with 'v'
+ @prefixed_semver_regex ||= Regexp.new("\\Av#{::Gitlab::Regex.unbounded_semver_regex.source}\\z", ::Gitlab::Regex.unbounded_semver_regex.options)
end
def go_package_regex
@@ -103,6 +160,14 @@ module Gitlab
def generic_package_version_regex
/\A\d+\.\d+\.\d+\z/
end
+
+ def generic_package_name_regex
+ maven_file_name_regex
+ end
+
+ def generic_package_file_name_regex
+ generic_package_name_regex
+ end
end
extend self
@@ -211,8 +276,27 @@ module Gitlab
"Must start with a letter, and cannot end with '-'"
end
+ # The section start, e.g. section_start:12345678:NAME
+ def logs_section_prefix_regex
+ /section_((?:start)|(?:end)):(\d+):([a-zA-Z0-9_.-]+)/
+ end
+
+ # The optional section options, e.g. [collapsed=true]
+ def logs_section_options_regex
+ /(\[(?:\w+=\w+)(?:, ?(?:\w+=\w+))*\])?/
+ end
+
+ # The region end, always: \r\e\[0K
+ def logs_section_suffix_regex
+ /\r\033\[0K/
+ end
+
def build_trace_section_regex
- @build_trace_section_regexp ||= /section_((?:start)|(?:end)):(\d+):([a-zA-Z0-9_.-]+)\r\033\[0K/.freeze
+ @build_trace_section_regexp ||= %r{
+ #{logs_section_prefix_regex}
+ #{logs_section_options_regex}
+ #{logs_section_suffix_regex}
+ }x.freeze
end
def markdown_code_or_html_blocks
diff --git a/lib/gitlab/relative_positioning/item_context.rb b/lib/gitlab/relative_positioning/item_context.rb
index cd03a347355..8f5495ece5e 100644
--- a/lib/gitlab/relative_positioning/item_context.rb
+++ b/lib/gitlab/relative_positioning/item_context.rb
@@ -131,12 +131,12 @@ module Gitlab
def shift_left
move_sequence_before(true)
- object.reset
+ object.reset_relative_position
end
def shift_right
move_sequence_after(true)
- object.reset
+ object.reset_relative_position
end
def create_space_left
diff --git a/lib/gitlab/repo_path.rb b/lib/gitlab/repo_path.rb
index 67e23624045..9ee6f67e455 100644
--- a/lib/gitlab/repo_path.rb
+++ b/lib/gitlab/repo_path.rb
@@ -35,6 +35,10 @@ module Gitlab
snippet, redirected_path = find_snippet(full_path)
[snippet, snippet&.project, redirected_path]
+ elsif type.wiki?
+ wiki, redirected_path = find_wiki(full_path)
+
+ [wiki, wiki.try(:project), redirected_path]
else
project, redirected_path = find_project(full_path)
@@ -67,6 +71,17 @@ module Gitlab
[Snippet.find_by_id_and_project(id: snippet_id, project: project), redirected_path]
end
+ # Wiki path can be either:
+ # - namespace/project
+ # - group/subgroup/project
+ def self.find_wiki(wiki_path)
+ return [nil, nil] if wiki_path.blank?
+
+ project, redirected_path = find_project(wiki_path)
+
+ [project&.wiki, redirected_path]
+ end
+
def self.extract_snippet_info(snippet_path)
path_segments = snippet_path.split('/')
snippet_id = path_segments.pop
diff --git a/lib/gitlab/repository_size_checker.rb b/lib/gitlab/repository_size_checker.rb
index 82c57f7a07d..03d9f961dd9 100644
--- a/lib/gitlab/repository_size_checker.rb
+++ b/lib/gitlab/repository_size_checker.rb
@@ -6,9 +6,10 @@ module Gitlab
attr_reader :limit
# @param current_size_proc [Proc] returns repository size in bytes
- def initialize(current_size_proc:, limit:, enabled: true)
+ def initialize(current_size_proc:, limit:, namespace:, enabled: true)
@current_size_proc = current_size_proc
@limit = limit
+ @namespace = namespace
@enabled = enabled && limit != 0
end
@@ -40,7 +41,13 @@ module Gitlab
end
def error_message
- @error_message_object ||= Gitlab::RepositorySizeErrorMessage.new(self)
+ @error_message_object ||= ::Gitlab::RepositorySizeErrorMessage.new(self)
end
+
+ private
+
+ attr_reader :namespace
end
end
+
+Gitlab::RepositorySizeChecker.prepend_if_ee('EE::Gitlab::RepositorySizeChecker')
diff --git a/lib/gitlab/sample_data_template.rb b/lib/gitlab/sample_data_template.rb
new file mode 100644
index 00000000000..ae74dc710b7
--- /dev/null
+++ b/lib/gitlab/sample_data_template.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+module Gitlab
+ class SampleDataTemplate < ProjectTemplate
+ class << self
+ def localized_templates_table
+ [
+ SampleDataTemplate.new('basic', 'Basic', _('Basic Sample Data template with Issues, Merge Requests and Milestones.'), 'https://gitlab.com/gitlab-org/sample-data-templates/basic'),
+ SampleDataTemplate.new('serenity_valley', 'Serenity Valley', _('Serenity Valley Sample Data template.'), 'https://gitlab.com/gitlab-org/sample-data-templates/serenity-valley')
+ ].freeze
+ end
+
+ def all
+ localized_templates_table
+ end
+
+ def archive_directory
+ Rails.root.join("vendor/sample_data_templates")
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/search/recent_items.rb b/lib/gitlab/search/recent_items.rb
index 40d96ded275..593148025e1 100644
--- a/lib/gitlab/search/recent_items.rb
+++ b/lib/gitlab/search/recent_items.rb
@@ -6,9 +6,12 @@ module Gitlab
# items. The #type and #finder methods are the only ones needed to be
# implemented by classes inheriting from this.
class RecentItems
- ITEMS_LIMIT = 100
+ ITEMS_LIMIT = 100 # How much history to remember from the user
+ SEARCH_LIMIT = 5 # How many matching items to return from search
EXPIRES_AFTER = 7.days
+ attr_reader :user
+
def initialize(user:, items_limit: ITEMS_LIMIT, expires_after: EXPIRES_AFTER)
@user = user
@items_limit = items_limit
@@ -30,21 +33,25 @@ module Gitlab
end
def search(term)
- ids = with_redis do |redis|
- redis.zrevrange(key, 0, @items_limit - 1)
- end.map(&:to_i)
-
- finder.new(@user, search: term, in: 'title').execute.reorder(nil).id_in_ordered(ids) # rubocop: disable CodeReuse/ActiveRecord
+ finder.new(user, search: term, in: 'title')
+ .execute
+ .limit(SEARCH_LIMIT).reorder(nil).id_in_ordered(latest_ids) # rubocop: disable CodeReuse/ActiveRecord
end
private
+ def latest_ids
+ with_redis do |redis|
+ redis.zrevrange(key, 0, @items_limit - 1)
+ end.map(&:to_i)
+ end
+
def with_redis(&blk)
Gitlab::Redis::SharedState.with(&blk) # rubocop: disable CodeReuse/ActiveRecord
end
def key
- "recent_items:#{type.name.downcase}:#{@user.id}"
+ "recent_items:#{type.name.downcase}:#{user.id}"
end
def type
diff --git a/lib/gitlab/search_results.rb b/lib/gitlab/search_results.rb
index 06d8dca2f70..b81264c5d0c 100644
--- a/lib/gitlab/search_results.rb
+++ b/lib/gitlab/search_results.rb
@@ -7,7 +7,7 @@ module Gitlab
DEFAULT_PAGE = 1
DEFAULT_PER_PAGE = 20
- attr_reader :current_user, :query, :filters
+ attr_reader :current_user, :query, :sort, :filters
# Limit search results by passed projects
# It allows us to search only for projects user has access to
@@ -19,31 +19,23 @@ module Gitlab
# query
attr_reader :default_project_filter
- def initialize(current_user, query, limit_projects = nil, default_project_filter: false, filters: {})
+ def initialize(current_user, query, limit_projects = nil, sort: nil, default_project_filter: false, filters: {})
@current_user = current_user
@query = query
@limit_projects = limit_projects || Project.all
@default_project_filter = default_project_filter
+ @sort = sort
@filters = filters
end
def objects(scope, page: nil, per_page: DEFAULT_PER_PAGE, without_count: true, preload_method: nil)
should_preload = preload_method.present?
- collection = case scope
- when 'projects'
- projects
- when 'issues'
- issues
- when 'merge_requests'
- merge_requests
- when 'milestones'
- milestones
- when 'users'
- users
- else
- should_preload = false
- Kaminari.paginate_array([])
- end
+ collection = collection_for(scope)
+
+ if collection.nil?
+ should_preload = false
+ collection = Kaminari.paginate_array([])
+ end
collection = collection.public_send(preload_method) if should_preload # rubocop:disable GitlabSecurity/PublicSend
collection = collection.page(page).per(per_page)
@@ -116,8 +108,41 @@ module Gitlab
UsersFinder.new(current_user, search: query).execute
end
+ # highlighting is only performed by Elasticsearch backed results
+ def highlight_map(scope)
+ {}
+ end
+
private
+ def collection_for(scope)
+ case scope
+ when 'projects'
+ projects
+ when 'issues'
+ issues
+ when 'merge_requests'
+ merge_requests
+ when 'milestones'
+ milestones
+ when 'users'
+ users
+ end
+ end
+
+ # rubocop: disable CodeReuse/ActiveRecord
+ def apply_sort(scope)
+ case sort
+ when 'oldest'
+ scope.reorder('created_at ASC')
+ when 'newest'
+ scope.reorder('created_at DESC')
+ else
+ scope
+ end
+ end
+ # rubocop: enable CodeReuse/ActiveRecord
+
def projects
limit_projects.search(query)
end
@@ -129,7 +154,7 @@ module Gitlab
issues = issues.where(project_id: project_ids_relation) # rubocop: disable CodeReuse/ActiveRecord
end
- issues
+ apply_sort(issues)
end
# rubocop: disable CodeReuse/ActiveRecord
@@ -149,7 +174,7 @@ module Gitlab
merge_requests = merge_requests.in_projects(project_ids_relation)
end
- merge_requests
+ apply_sort(merge_requests)
end
def default_scope
@@ -193,6 +218,10 @@ module Gitlab
end
params[:state] = filters[:state] if filters.key?(:state)
+
+ if [true, false].include?(filters[:confidential]) && Feature.enabled?(:search_filter_by_confidential)
+ params[:confidential] = filters[:confidential]
+ end
end
end
diff --git a/lib/gitlab/seeder.rb b/lib/gitlab/seeder.rb
index e26d45e1b33..4158cec9b09 100644
--- a/lib/gitlab/seeder.rb
+++ b/lib/gitlab/seeder.rb
@@ -87,7 +87,9 @@ module Gitlab
SeedFu.quiet = true
- yield
+ without_statement_timeout do
+ yield
+ end
SeedFu.quiet = false
ActiveRecord::Base.logger = old_logger
@@ -114,6 +116,13 @@ module Gitlab
def self.mute_mailer
ActionMailer::MessageDelivery.prepend(DeliverNever)
end
+
+ def self.without_statement_timeout
+ ActiveRecord::Base.connection.execute('SET statement_timeout=0')
+ yield
+ ensure
+ ActiveRecord::Base.connection.execute('RESET statement_timeout')
+ end
end
end
# :nocov:
diff --git a/lib/gitlab/sidekiq_daemon/memory_killer.rb b/lib/gitlab/sidekiq_daemon/memory_killer.rb
index e1a87a77f04..8793a672693 100644
--- a/lib/gitlab/sidekiq_daemon/memory_killer.rb
+++ b/lib/gitlab/sidekiq_daemon/memory_killer.rb
@@ -231,7 +231,7 @@ module Gitlab
def rss_increase_by_jobs
Gitlab::SidekiqDaemon::Monitor.instance.jobs_mutex.synchronize do
- Gitlab::SidekiqDaemon::Monitor.instance.jobs.sum do |job| # rubocop:disable CodeReuse/ActiveRecord
+ Gitlab::SidekiqDaemon::Monitor.instance.jobs.sum do |job|
rss_increase_by_job(job)
end
end
diff --git a/lib/gitlab/sidekiq_middleware/worker_context/server.rb b/lib/gitlab/sidekiq_middleware/worker_context/server.rb
index d2d84742c17..2d8fd8002d2 100644
--- a/lib/gitlab/sidekiq_middleware/worker_context/server.rb
+++ b/lib/gitlab/sidekiq_middleware/worker_context/server.rb
@@ -12,8 +12,10 @@ module Gitlab
# This is not a worker we know about, perhaps from a gem
return yield unless worker_class.respond_to?(:get_worker_context)
- # Use the context defined on the class level as a base context
- wrap_in_optional_context(worker_class.get_worker_context, &block)
+ Gitlab::ApplicationContext.with_context(feature_category: worker_class.get_feature_category.to_s) do
+ # Use the context defined on the class level as the more specific context
+ wrap_in_optional_context(worker_class.get_worker_context, &block)
+ end
end
end
end
diff --git a/lib/gitlab/slash_commands/presenters/help.rb b/lib/gitlab/slash_commands/presenters/help.rb
index 2d8df2ca204..714ca77c3e5 100644
--- a/lib/gitlab/slash_commands/presenters/help.rb
+++ b/lib/gitlab/slash_commands/presenters/help.rb
@@ -48,7 +48,7 @@ module Gitlab
*Documentation*
For more information about GitLab chatops, refer to its
- documentation: https://docs.gitlab.com/ce/ci/chatops/README.html.
+ documentation: https://docs.gitlab.com/ee/ci/chatops/README.html.
MESSAGE
message
diff --git a/lib/gitlab/static_site_editor/config/file_config.rb b/lib/gitlab/static_site_editor/config/file_config.rb
index f647c85e1c8..315c603c1dd 100644
--- a/lib/gitlab/static_site_editor/config/file_config.rb
+++ b/lib/gitlab/static_site_editor/config/file_config.rb
@@ -3,11 +3,38 @@
module Gitlab
module StaticSiteEditor
module Config
+ #
+ # Base GitLab Static Site Editor Configuration facade
+ #
class FileConfig
- def data
- {
- static_site_generator: 'middleman'
- }
+ ConfigError = Class.new(StandardError)
+
+ def initialize(yaml)
+ content_hash = content_hash(yaml)
+ @global = Entry::Global.new(content_hash)
+ @global.compose!
+ rescue Gitlab::Config::Loader::FormatError => e
+ raise FileConfig::ConfigError, e.message
+ end
+
+ def valid?
+ @global.valid?
+ end
+
+ def errors
+ @global.errors
+ end
+
+ def to_hash_with_defaults
+ # NOTE: The current approach of simply mapping all the descendents' keys and values ('config')
+ # into a flat hash may need to be enhanced as we add more complex, non-scalar entries.
+ @global.descendants.map { |descendant| [descendant.key, descendant.config] }.to_h
+ end
+
+ private
+
+ def content_hash(yaml)
+ Gitlab::Config::Loader::Yaml.new(yaml).load!
end
end
end
diff --git a/lib/gitlab/static_site_editor/config/file_config/entry/global.rb b/lib/gitlab/static_site_editor/config/file_config/entry/global.rb
new file mode 100644
index 00000000000..c295ccf1d11
--- /dev/null
+++ b/lib/gitlab/static_site_editor/config/file_config/entry/global.rb
@@ -0,0 +1,39 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module StaticSiteEditor
+ module Config
+ class FileConfig
+ module Entry
+ ##
+ # This class represents a global entry - root Entry for entire
+ # GitLab StaticSiteEditor Configuration file.
+ #
+ class Global < ::Gitlab::Config::Entry::Node
+ include ::Gitlab::Config::Entry::Configurable
+ include ::Gitlab::Config::Entry::Attributable
+
+ ALLOWED_KEYS = %i[
+ image_upload_path
+ mounts
+ static_site_generator
+ ].freeze
+
+ attributes ALLOWED_KEYS
+
+ validations do
+ validates :config, allowed_keys: ALLOWED_KEYS
+ end
+
+ entry :image_upload_path, Entry::ImageUploadPath,
+ description: 'Configuration of the Static Site Editor image upload path.'
+ entry :mounts, Entry::Mounts,
+ description: 'Configuration of the Static Site Editor mounts.'
+ entry :static_site_generator, Entry::StaticSiteGenerator,
+ description: 'Configuration of the Static Site Editor static site generator.'
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/static_site_editor/config/file_config/entry/image_upload_path.rb b/lib/gitlab/static_site_editor/config/file_config/entry/image_upload_path.rb
new file mode 100644
index 00000000000..6a2b9e10d33
--- /dev/null
+++ b/lib/gitlab/static_site_editor/config/file_config/entry/image_upload_path.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module StaticSiteEditor
+ module Config
+ class FileConfig
+ module Entry
+ ##
+ # Entry that represents the path to which images will be uploaded
+ #
+ class ImageUploadPath < ::Gitlab::Config::Entry::Node
+ include ::Gitlab::Config::Entry::Validatable
+
+ validations do
+ validates :config, type: String
+ end
+
+ def self.default
+ 'source/images'
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/static_site_editor/config/file_config/entry/mount.rb b/lib/gitlab/static_site_editor/config/file_config/entry/mount.rb
new file mode 100644
index 00000000000..b10956e17a5
--- /dev/null
+++ b/lib/gitlab/static_site_editor/config/file_config/entry/mount.rb
@@ -0,0 +1,39 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module StaticSiteEditor
+ module Config
+ class FileConfig
+ module Entry
+ ##
+ # Entry that represents the mappings of mounted source directories to target paths
+ #
+ class Mount < ::Gitlab::Config::Entry::Node
+ include ::Gitlab::Config::Entry::Validatable
+ include ::Gitlab::Config::Entry::Attributable
+
+ ALLOWED_KEYS = %i[source target].freeze
+
+ attributes ALLOWED_KEYS
+
+ validations do
+ validates :config, allowed_keys: ALLOWED_KEYS
+
+ validates :source, type: String, presence: true
+ validates :target, type: String, presence: true, allow_blank: true
+ end
+
+ def self.default
+ # NOTE: This is the default for middleman projects. Ideally, this would be determined
+ # based on the defaults for whatever `static_site_generator` is configured.
+ {
+ source: 'source',
+ target: ''
+ }
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/static_site_editor/config/file_config/entry/mounts.rb b/lib/gitlab/static_site_editor/config/file_config/entry/mounts.rb
new file mode 100644
index 00000000000..10bd377e419
--- /dev/null
+++ b/lib/gitlab/static_site_editor/config/file_config/entry/mounts.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module StaticSiteEditor
+ module Config
+ class FileConfig
+ module Entry
+ ##
+ # Entry that represents the mappings of mounted source directories to target paths
+ #
+ class Mounts < ::Gitlab::Config::Entry::Node
+ include ::Gitlab::Config::Entry::Configurable
+ include ::Gitlab::Config::Entry::Validatable
+
+ entry :mount, Entry::Mount, description: 'Configuration of a Static Site Editor mount.'
+
+ validations do
+ validates :config, type: Array, presence: true
+ end
+
+ def skip_config_hash_validation?
+ true
+ end
+
+ def self.default
+ [Entry::Mount.default]
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/static_site_editor/config/file_config/entry/static_site_generator.rb b/lib/gitlab/static_site_editor/config/file_config/entry/static_site_generator.rb
new file mode 100644
index 00000000000..593c0951f93
--- /dev/null
+++ b/lib/gitlab/static_site_editor/config/file_config/entry/static_site_generator.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module StaticSiteEditor
+ module Config
+ class FileConfig
+ module Entry
+ ##
+ # Entry that represents the static site generator tool/framework.
+ #
+ class StaticSiteGenerator < ::Gitlab::Config::Entry::Node
+ include ::Gitlab::Config::Entry::Validatable
+
+ validations do
+ validates :config, type: String, inclusion: { in: %w[middleman], message: "should be 'middleman'" }
+ end
+
+ def self.default
+ 'middleman'
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/static_site_editor/config/generated_config.rb b/lib/gitlab/static_site_editor/config/generated_config.rb
index f3dce74a32f..ff24ec69ab0 100644
--- a/lib/gitlab/static_site_editor/config/generated_config.rb
+++ b/lib/gitlab/static_site_editor/config/generated_config.rb
@@ -4,8 +4,6 @@ module Gitlab
module StaticSiteEditor
module Config
class GeneratedConfig
- SUPPORTED_EXTENSIONS = %w[.md].freeze
-
def initialize(repository, ref, path, return_url)
@repository = repository
@ref = ref
@@ -23,7 +21,7 @@ module Gitlab
project: project.path,
namespace: project.namespace.full_path,
return_url: sanitize_url(return_url),
- is_supported_content: supported_content?.to_s,
+ is_supported_content: supported_content?,
base_url: Gitlab::Routing.url_helpers.project_show_sse_path(project, full_path),
merge_requests_illustration_path: merge_requests_illustration_path
}
@@ -35,8 +33,12 @@ module Gitlab
delegate :project, to: :repository
+ def supported_extensions
+ %w[.md].freeze
+ end
+
def commit_id
- repository.commit(ref)&.id if ref
+ repository.commit(ref)&.id
end
def supported_content?
@@ -50,7 +52,7 @@ module Gitlab
def extension_supported?
return true if path.end_with?('.md.erb') && Feature.enabled?(:sse_erb_support, project)
- SUPPORTED_EXTENSIONS.any? { |ext| path.end_with?(ext) }
+ supported_extensions.any? { |ext| path.end_with?(ext) }
end
def file_exists?
diff --git a/lib/gitlab/subscription_portal.rb b/lib/gitlab/subscription_portal.rb
new file mode 100644
index 00000000000..a918e7bec80
--- /dev/null
+++ b/lib/gitlab/subscription_portal.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module SubscriptionPortal
+ def self.default_subscriptions_url
+ ::Gitlab.dev_or_test_env? ? 'https://customers.stg.gitlab.com' : 'https://customers.gitlab.com'
+ end
+
+ SUBSCRIPTIONS_URL = ENV.fetch('CUSTOMER_PORTAL_URL', default_subscriptions_url).freeze
+ end
+end
diff --git a/lib/gitlab/template/gitlab_ci_yml_template.rb b/lib/gitlab/template/gitlab_ci_yml_template.rb
index bb1e9db55fa..e12af6bf0a4 100644
--- a/lib/gitlab/template/gitlab_ci_yml_template.rb
+++ b/lib/gitlab/template/gitlab_ci_yml_template.rb
@@ -3,7 +3,7 @@
module Gitlab
module Template
class GitlabCiYmlTemplate < BaseTemplate
- BASE_EXCLUDED_PATTERNS = [%r{\.latest$}].freeze
+ BASE_EXCLUDED_PATTERNS = [%r{\.latest\.}].freeze
def content
explanation = "# This file is a template, and might need editing before it works on your project."
diff --git a/lib/gitlab/themes.rb b/lib/gitlab/themes.rb
index 72783a2d682..16e7b8a7eca 100644
--- a/lib/gitlab/themes.rb
+++ b/lib/gitlab/themes.rb
@@ -10,21 +10,21 @@ module Gitlab
APPLICATION_DEFAULT = 1
# Struct class representing a single Theme
- Theme = Struct.new(:id, :name, :css_class)
+ Theme = Struct.new(:id, :name, :css_class, :css_filename)
# All available Themes
THEMES = [
- Theme.new(1, 'Indigo', 'ui-indigo'),
- Theme.new(6, 'Light Indigo', 'ui-light-indigo'),
- Theme.new(4, 'Blue', 'ui-blue'),
- Theme.new(7, 'Light Blue', 'ui-light-blue'),
- Theme.new(5, 'Green', 'ui-green'),
- Theme.new(8, 'Light Green', 'ui-light-green'),
- Theme.new(9, 'Red', 'ui-red'),
- Theme.new(10, 'Light Red', 'ui-light-red'),
- Theme.new(2, 'Dark', 'ui-dark'),
- Theme.new(3, 'Light', 'ui-light'),
- Theme.new(11, 'Dark Mode (alpha)', 'gl-dark')
+ Theme.new(1, 'Indigo', 'ui-indigo', 'theme_indigo'),
+ Theme.new(6, 'Light Indigo', 'ui-light-indigo', 'theme_light_indigo'),
+ Theme.new(4, 'Blue', 'ui-blue', 'theme_blue'),
+ Theme.new(7, 'Light Blue', 'ui-light-blue', 'theme_light_blue'),
+ Theme.new(5, 'Green', 'ui-green', 'theme_green'),
+ Theme.new(8, 'Light Green', 'ui-light-green', 'theme_light_green'),
+ Theme.new(9, 'Red', 'ui-red', 'theme_red'),
+ Theme.new(10, 'Light Red', 'ui-light-red', 'theme_light_red'),
+ Theme.new(2, 'Dark', 'ui-dark', 'theme_dark'),
+ Theme.new(3, 'Light', 'ui-light', 'theme_light'),
+ Theme.new(11, 'Dark Mode (alpha)', 'gl-dark', nil)
].freeze
# Convenience method to get a space-separated String of all the theme
diff --git a/lib/gitlab/usage_data.rb b/lib/gitlab/usage_data.rb
index 89605ce5d07..68f24559b1f 100644
--- a/lib/gitlab/usage_data.rb
+++ b/lib/gitlab/usage_data.rb
@@ -12,6 +12,19 @@
# redis_usage_data { ::Gitlab::UsageCounters::PodLogs.usage_totals[:total] }
module Gitlab
class UsageData
+ CE_MEMOIZED_VALUES = %i(
+ issue_minimum_id
+ issue_maximum_id
+ project_minimum_id
+ project_maximum_id
+ user_minimum_id
+ user_maximum_id
+ unique_visit_service
+ deployment_minimum_id
+ deployment_maximum_id
+ auth_providers
+ ).freeze
+
class << self
include Gitlab::Utils::UsageData
include Gitlab::Utils::StrongMemoize
@@ -138,8 +151,10 @@ module Gitlab
pages_domains: count(PagesDomain),
pool_repositories: count(PoolRepository),
projects: count(Project),
+ projects_creating_incidents: distinct_count(Issue.incident, :project_id),
projects_imported_from_github: count(Project.where(import_type: 'github')),
projects_with_repositories_enabled: count(ProjectFeature.where('repository_access_level > ?', ProjectFeature::DISABLED)),
+ projects_with_tracing_enabled: count(ProjectTracingSetting),
projects_with_error_tracking_enabled: count(::ErrorTracking::ProjectErrorTrackingSetting.where(enabled: true)),
projects_with_alerts_service_enabled: count(AlertsService.active),
projects_with_prometheus_alerts: distinct_count(PrometheusAlert, :project_id),
@@ -166,8 +181,7 @@ module Gitlab
user_preferences_usage,
ingress_modsecurity_usage,
container_expiration_policies_usage,
- service_desk_counts,
- snowplow_event_counts
+ service_desk_counts
).tap do |data|
data[:snippets] = data[:personal_snippets] + data[:project_snippets]
end
@@ -175,7 +189,7 @@ module Gitlab
end
# rubocop: enable Metrics/AbcSize
- def snowplow_event_counts(time_period: {})
+ def snowplow_event_counts(time_period)
return {} unless report_snowplow_events?
{
@@ -200,7 +214,7 @@ module Gitlab
personal_snippets: count(PersonalSnippet.where(last_28_days_time_period)),
project_snippets: count(ProjectSnippet.where(last_28_days_time_period))
}.merge(
- snowplow_event_counts(time_period: last_28_days_time_period(column: :collector_tstamp))
+ snowplow_event_counts(last_28_days_time_period(column: :collector_tstamp))
).tap do |data|
data[:snippets] = data[:personal_snippets] + data[:project_snippets]
end
@@ -242,7 +256,8 @@ module Gitlab
signup_enabled: alt_usage_data(fallback: nil) { Gitlab::CurrentSettings.allow_signup? },
web_ide_clientside_preview_enabled: alt_usage_data(fallback: nil) { Gitlab::CurrentSettings.web_ide_clientside_preview_enabled? },
ingress_modsecurity_enabled: Feature.enabled?(:ingress_modsecurity),
- grafana_link_enabled: alt_usage_data(fallback: nil) { Gitlab::CurrentSettings.grafana_enabled? }
+ grafana_link_enabled: alt_usage_data(fallback: nil) { Gitlab::CurrentSettings.grafana_enabled? },
+ gitpod_enabled: alt_usage_data(fallback: nil) { Gitlab::CurrentSettings.gitpod_enabled? }
}
end
@@ -264,7 +279,8 @@ module Gitlab
Gitlab::UsageDataCounters::SourceCodeCounter,
Gitlab::UsageDataCounters::MergeRequestCounter,
Gitlab::UsageDataCounters::DesignsCounter,
- Gitlab::UsageDataCounters::KubernetesAgentCounter
+ Gitlab::UsageDataCounters::KubernetesAgentCounter,
+ Gitlab::UsageDataCounters::StaticSiteEditorCounter
]
end
@@ -287,7 +303,8 @@ module Gitlab
},
database: {
adapter: alt_usage_data { Gitlab::Database.adapter_name },
- version: alt_usage_data { Gitlab::Database.version }
+ version: alt_usage_data { Gitlab::Database.version },
+ pg_system_id: alt_usage_data { Gitlab::Database.system_id }
},
mail: {
smtp_server: alt_usage_data { ActionMailer::Base.smtp_settings[:address] }
@@ -385,10 +402,12 @@ module Gitlab
def services_usage
# rubocop: disable UsageData/LargeTable:
Service.available_services_names.each_with_object({}) do |service_name, response|
- response["projects_#{service_name}_active".to_sym] = count(Service.active.where(template: false, instance: false, type: "#{service_name}_service".camelize))
+ response["projects_#{service_name}_active".to_sym] = count(Service.active.where.not(project: nil).where(type: "#{service_name}_service".camelize))
+ response["groups_#{service_name}_active".to_sym] = count(Service.active.where.not(group: nil).where(type: "#{service_name}_service".camelize))
response["templates_#{service_name}_active".to_sym] = count(Service.active.where(template: true, type: "#{service_name}_service".camelize))
response["instances_#{service_name}_active".to_sym] = count(Service.active.where(instance: true, type: "#{service_name}_service".camelize))
- response["projects_inheriting_instance_#{service_name}_active".to_sym] = count(Service.active.where.not(inherit_from_id: nil).where(type: "#{service_name}_service".camelize))
+ response["projects_inheriting_#{service_name}_active".to_sym] = count(Service.active.where.not(project: nil).where.not(inherit_from_id: nil).where(type: "#{service_name}_service".camelize))
+ response["groups_inheriting_#{service_name}_active".to_sym] = count(Service.active.where.not(group: nil).where.not(inherit_from_id: nil).where(type: "#{service_name}_service".camelize))
end.merge(jira_usage, jira_import_usage)
# rubocop: enable UsageData/LargeTable:
end
@@ -444,8 +463,11 @@ module Gitlab
# rubocop: enable UsageData/LargeTable
# rubocop: enable CodeReuse/ActiveRecord
+ # augmented in EE
def user_preferences_usage
- {} # augmented in EE
+ {
+ user_preferences_user_gitpod_enabled: count(UserPreference.with_user.gitpod_enabled.merge(User.active))
+ }
end
def merge_requests_users(time_period)
@@ -469,7 +491,7 @@ module Gitlab
end
def last_28_days_time_period(column: :created_at)
- { column => 28.days.ago..Time.current }
+ { column => 30.days.ago..2.days.ago }
end
# Source: https://gitlab.com/gitlab-data/analytics/blob/master/transform/snowflake-dbt/data/ping_metrics_to_stage_mapping_data.csv
@@ -541,6 +563,7 @@ module Gitlab
groups: distinct_count(::GroupMember.where(time_period), :user_id),
users_created: count(::User.where(time_period), start: user_minimum_id, finish: user_maximum_id),
omniauth_providers: filtered_omniauth_provider_names.reject { |name| name == 'group_saml' },
+ user_auth_by_provider: distinct_count_user_auth_by_provider(time_period),
projects_imported: {
gitlab_project: projects_imported_count('gitlab_project', time_period),
gitlab: projects_imported_count('gitlab', time_period),
@@ -555,7 +578,8 @@ module Gitlab
jira: distinct_count(::JiraImportState.where(time_period), :user_id),
fogbugz: projects_imported_count('fogbugz', time_period),
phabricator: projects_imported_count('phabricator', time_period)
- }
+ },
+ groups_imported: distinct_count(::GroupImportState.where(time_period), :user_id)
}
end
# rubocop: enable CodeReuse/ActiveRecord
@@ -567,7 +591,8 @@ module Gitlab
clusters_applications_prometheus: cluster_applications_user_distinct_count(::Clusters::Applications::Prometheus, time_period),
operations_dashboard_default_dashboard: count(::User.active.with_dashboard('operations').where(time_period),
start: user_minimum_id,
- finish: user_maximum_id)
+ finish: user_maximum_id),
+ projects_with_tracing_enabled: distinct_count(::Project.with_tracing_enabled.where(time_period), :creator_id)
}
end
# rubocop: enable CodeReuse/ActiveRecord
@@ -696,10 +721,10 @@ module Gitlab
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) }
+ 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
@@ -801,17 +826,7 @@ module Gitlab
end
def clear_memoized
- clear_memoization(:issue_minimum_id)
- clear_memoization(:issue_maximum_id)
- clear_memoization(:user_minimum_id)
- clear_memoization(:user_maximum_id)
- clear_memoization(:unique_visit_service)
- clear_memoization(:deployment_minimum_id)
- clear_memoization(:deployment_maximum_id)
- clear_memoization(:approval_merge_request_rule_minimum_id)
- clear_memoization(:approval_merge_request_rule_maximum_id)
- clear_memoization(:project_minimum_id)
- clear_memoization(:project_maximum_id)
+ CE_MEMOIZED_VALUES.each { |v| clear_memoization(v) }
end
# rubocop: disable CodeReuse/ActiveRecord
@@ -843,6 +858,39 @@ module Gitlab
def projects_imported_count(from, time_period)
distinct_count(::Project.imported_from(from).where(time_period), :creator_id) # rubocop: disable CodeReuse/ActiveRecord
end
+
+ # rubocop:disable CodeReuse/ActiveRecord
+ def distinct_count_user_auth_by_provider(time_period)
+ counts = auth_providers_except_ldap.each_with_object({}) do |provider, hash|
+ hash[provider] = distinct_count(
+ ::AuthenticationEvent.success.for_provider(provider).where(time_period), :user_id)
+ end
+
+ if any_ldap_auth_providers?
+ counts['ldap'] = distinct_count(
+ ::AuthenticationEvent.success.ldap.where(time_period), :user_id
+ )
+ end
+
+ counts
+ end
+ # rubocop:enable CodeReuse/ActiveRecord
+
+ # rubocop:disable UsageData/LargeTable
+ def auth_providers
+ strong_memoize(:auth_providers) do
+ ::AuthenticationEvent.providers
+ end
+ end
+ # rubocop:enable UsageData/LargeTable
+
+ def auth_providers_except_ldap
+ auth_providers.reject { |provider| provider.starts_with?('ldap') }
+ end
+
+ def any_ldap_auth_providers?
+ auth_providers.any? { |provider| provider.starts_with?('ldap') }
+ end
end
end
end
diff --git a/lib/gitlab/usage_data_counters/hll_redis_counter.rb b/lib/gitlab/usage_data_counters/hll_redis_counter.rb
index 53bf6daea4c..eb132ef0967 100644
--- a/lib/gitlab/usage_data_counters/hll_redis_counter.rb
+++ b/lib/gitlab/usage_data_counters/hll_redis_counter.rb
@@ -72,7 +72,8 @@ module Gitlab
events_names = events_for_category(category)
event_results = events_names.each_with_object({}) do |event, hash|
- hash[event] = unique_events(event_names: event, start_date: 7.days.ago.to_date, end_date: Date.current)
+ hash["#{event}_weekly"] = unique_events(event_names: event, start_date: 7.days.ago.to_date, end_date: Date.current)
+ hash["#{event}_monthly"] = unique_events(event_names: event, start_date: 4.weeks.ago.to_date, end_date: Date.current)
end
if eligible_for_totals?(events_names)
diff --git a/lib/gitlab/usage_data_counters/issue_activity_unique_counter.rb b/lib/gitlab/usage_data_counters/issue_activity_unique_counter.rb
index fc1b5a59487..e8839875109 100644
--- a/lib/gitlab/usage_data_counters/issue_activity_unique_counter.rb
+++ b/lib/gitlab/usage_data_counters/issue_activity_unique_counter.rb
@@ -3,14 +3,42 @@
module Gitlab
module UsageDataCounters
module IssueActivityUniqueCounter
- ISSUE_TITLE_CHANGED = 'g_project_management_issue_title_changed'
- ISSUE_DESCRIPTION_CHANGED = 'g_project_management_issue_description_changed'
+ ISSUE_CATEGORY = 'issues_edit'
+
ISSUE_ASSIGNEE_CHANGED = 'g_project_management_issue_assignee_changed'
+ ISSUE_CREATED = 'g_project_management_issue_created'
+ ISSUE_CLOSED = 'g_project_management_issue_closed'
+ ISSUE_DESCRIPTION_CHANGED = 'g_project_management_issue_description_changed'
+ ISSUE_ITERATION_CHANGED = 'g_project_management_issue_iteration_changed'
+ ISSUE_LABEL_CHANGED = 'g_project_management_issue_label_changed'
ISSUE_MADE_CONFIDENTIAL = 'g_project_management_issue_made_confidential'
ISSUE_MADE_VISIBLE = 'g_project_management_issue_made_visible'
- ISSUE_CATEGORY = 'issues_edit'
+ ISSUE_MILESTONE_CHANGED = 'g_project_management_issue_milestone_changed'
+ ISSUE_REOPENED = 'g_project_management_issue_reopened'
+ ISSUE_TITLE_CHANGED = 'g_project_management_issue_title_changed'
+ ISSUE_WEIGHT_CHANGED = 'g_project_management_issue_weight_changed'
+ ISSUE_CROSS_REFERENCED = 'g_project_management_issue_cross_referenced'
+ ISSUE_MOVED = 'g_project_management_issue_moved'
+ ISSUE_RELATED = 'g_project_management_issue_related'
+ ISSUE_UNRELATED = 'g_project_management_issue_unrelated'
+ ISSUE_MARKED_AS_DUPLICATE = 'g_project_management_issue_marked_as_duplicate'
+ ISSUE_LOCKED = 'g_project_management_issue_locked'
+ ISSUE_UNLOCKED = 'g_project_management_issue_unlocked'
+ ISSUE_ADDED_TO_EPIC = 'g_project_management_issue_added_to_epic'
+ ISSUE_REMOVED_FROM_EPIC = 'g_project_management_issue_removed_from_epic'
+ ISSUE_CHANGED_EPIC = 'g_project_management_issue_changed_epic'
+ ISSUE_DESIGNS_ADDED = 'g_project_management_issue_designs_added'
+ ISSUE_DESIGNS_MODIFIED = 'g_project_management_issue_designs_modified'
+ ISSUE_DESIGNS_REMOVED = 'g_project_management_issue_designs_removed'
+ ISSUE_DUE_DATE_CHANGED = 'g_project_management_issue_due_date_changed'
+ ISSUE_TIME_ESTIMATE_CHANGED = 'g_project_management_issue_time_estimate_changed'
+ ISSUE_TIME_SPENT_CHANGED = 'g_project_management_issue_time_spent_changed'
class << self
+ def track_issue_created_action(author:, time: Time.zone.now)
+ track_unique_action(ISSUE_CREATED, author, time)
+ end
+
def track_issue_title_changed_action(author:, time: Time.zone.now)
track_unique_action(ISSUE_TITLE_CHANGED, author, time)
end
@@ -31,10 +59,98 @@ module Gitlab
track_unique_action(ISSUE_MADE_VISIBLE, author, time)
end
+ def track_issue_closed_action(author:, time: Time.zone.now)
+ track_unique_action(ISSUE_CLOSED, author, time)
+ end
+
+ def track_issue_reopened_action(author:, time: Time.zone.now)
+ track_unique_action(ISSUE_REOPENED, author, time)
+ end
+
+ def track_issue_label_changed_action(author:, time: Time.zone.now)
+ track_unique_action(ISSUE_LABEL_CHANGED, author, time)
+ end
+
+ def track_issue_milestone_changed_action(author:, time: Time.zone.now)
+ track_unique_action(ISSUE_MILESTONE_CHANGED, author, time)
+ end
+
+ def track_issue_iteration_changed_action(author:, time: Time.zone.now)
+ track_unique_action(ISSUE_ITERATION_CHANGED, author, time)
+ end
+
+ def track_issue_weight_changed_action(author:, time: Time.zone.now)
+ track_unique_action(ISSUE_WEIGHT_CHANGED, author, time)
+ end
+
+ def track_issue_cross_referenced_action(author:, time: Time.zone.now)
+ track_unique_action(ISSUE_CROSS_REFERENCED, author, time)
+ end
+
+ def track_issue_moved_action(author:, time: Time.zone.now)
+ track_unique_action(ISSUE_MOVED, author, time)
+ end
+
+ def track_issue_related_action(author:, time: Time.zone.now)
+ track_unique_action(ISSUE_RELATED, author, time)
+ end
+
+ def track_issue_unrelated_action(author:, time: Time.zone.now)
+ track_unique_action(ISSUE_UNRELATED, author, time)
+ end
+
+ def track_issue_marked_as_duplicate_action(author:, time: Time.zone.now)
+ track_unique_action(ISSUE_MARKED_AS_DUPLICATE, author, time)
+ end
+
+ def track_issue_locked_action(author:, time: Time.zone.now)
+ track_unique_action(ISSUE_LOCKED, author, time)
+ end
+
+ def track_issue_unlocked_action(author:, time: Time.zone.now)
+ track_unique_action(ISSUE_UNLOCKED, author, time)
+ end
+
+ def track_issue_added_to_epic_action(author:, time: Time.zone.now)
+ track_unique_action(ISSUE_ADDED_TO_EPIC, author, time)
+ end
+
+ def track_issue_removed_from_epic_action(author:, time: Time.zone.now)
+ track_unique_action(ISSUE_REMOVED_FROM_EPIC, author, time)
+ end
+
+ def track_issue_changed_epic_action(author:, time: Time.zone.now)
+ track_unique_action(ISSUE_CHANGED_EPIC, author, time)
+ end
+
+ def track_issue_designs_added_action(author:, time: Time.zone.now)
+ track_unique_action(ISSUE_DESIGNS_ADDED, author, time)
+ end
+
+ def track_issue_designs_modified_action(author:, time: Time.zone.now)
+ track_unique_action(ISSUE_DESIGNS_MODIFIED, author, time)
+ end
+
+ def track_issue_designs_removed_action(author:, time: Time.zone.now)
+ track_unique_action(ISSUE_DESIGNS_REMOVED, author, time)
+ end
+
+ def track_issue_due_date_changed_action(author:, time: Time.zone.now)
+ track_unique_action(ISSUE_DUE_DATE_CHANGED, author, time)
+ end
+
+ def track_issue_time_estimate_changed_action(author:, time: Time.zone.now)
+ track_unique_action(ISSUE_TIME_ESTIMATE_CHANGED, author, time)
+ end
+
+ def track_issue_time_spent_changed_action(author:, time: Time.zone.now)
+ track_unique_action(ISSUE_TIME_SPENT_CHANGED, author, time)
+ end
+
private
def track_unique_action(action, author, time)
- return unless Feature.enabled?(:track_issue_activity_actions)
+ return unless Feature.enabled?(:track_issue_activity_actions, default_enabled: true)
return unless author
Gitlab::UsageDataCounters::HLLRedisCounter.track_event(author.id, action, time)
diff --git a/lib/gitlab/usage_data_counters/known_events.yml b/lib/gitlab/usage_data_counters/known_events.yml
index 25e7f858bb1..bc56c5d6d9b 100644
--- a/lib/gitlab/usage_data_counters/known_events.yml
+++ b/lib/gitlab/usage_data_counters/known_events.yml
@@ -185,6 +185,11 @@
redis_slot: incident_management
category: incident_management
aggregation: weekly
+# Testing category
+- name: i_testing_test_case_parsed
+ category: testing
+ redis_slot: testing
+ aggregation: weekly
# Project Management group
- name: g_project_management_issue_title_changed
category: issues_edit
@@ -206,3 +211,95 @@
category: issues_edit
redis_slot: project_management
aggregation: daily
+- name: g_project_management_issue_created
+ category: issues_edit
+ redis_slot: project_management
+ aggregation: daily
+- name: g_project_management_issue_closed
+ category: issues_edit
+ redis_slot: project_management
+ aggregation: daily
+- name: g_project_management_issue_reopened
+ category: issues_edit
+ redis_slot: project_management
+ aggregation: daily
+- name: g_project_management_issue_label_changed
+ category: issues_edit
+ redis_slot: project_management
+ aggregation: daily
+- name: g_project_management_issue_milestone_changed
+ category: issues_edit
+ redis_slot: project_management
+ aggregation: daily
+- name: g_project_management_issue_iteration_changed
+ category: issues_edit
+ redis_slot: project_management
+ aggregation: daily
+- name: g_project_management_issue_weight_changed
+ category: issues_edit
+ redis_slot: project_management
+ aggregation: daily
+- name: g_project_management_issue_cross_referenced
+ category: issues_edit
+ redis_slot: project_management
+ aggregation: daily
+- name: g_project_management_issue_moved
+ category: issues_edit
+ redis_slot: project_management
+ aggregation: daily
+- name: g_project_management_issue_related
+ category: issues_edit
+ redis_slot: project_management
+ aggregation: daily
+- name: g_project_management_issue_unrelated
+ category: issues_edit
+ redis_slot: project_management
+ aggregation: daily
+- name: g_project_management_issue_marked_as_duplicate
+ category: issues_edit
+ redis_slot: project_management
+ aggregation: daily
+- name: g_project_management_issue_locked
+ category: issues_edit
+ redis_slot: project_management
+ aggregation: daily
+- name: g_project_management_issue_unlocked
+ category: issues_edit
+ redis_slot: project_management
+ aggregation: daily
+- name: g_project_management_issue_added_to_epic
+ category: issues_edit
+ redis_slot: project_management
+ aggregation: daily
+- name: g_project_management_issue_removed_from_epic
+ category: issues_edit
+ redis_slot: project_management
+ aggregation: daily
+- name: g_project_management_issue_changed_epic
+ category: issues_edit
+ redis_slot: project_management
+ aggregation: daily
+- name: g_project_management_issue_designs_added
+ category: issues_edit
+ redis_slot: project_management
+ aggregation: daily
+- name: g_project_management_issue_designs_modified
+ category: issues_edit
+ redis_slot: project_management
+ aggregation: daily
+- name: g_project_management_issue_designs_removed
+ category: issues_edit
+ redis_slot: project_management
+ aggregation: daily
+- name: g_project_management_issue_due_date_changed
+ category: issues_edit
+ redis_slot: project_management
+ aggregation: daily
+- name: g_project_management_issue_time_estimate_changed
+ category: issues_edit
+ redis_slot: project_management
+ aggregation: daily
+- name: g_project_management_issue_time_spent_changed
+ category: issues_edit
+ redis_slot: project_management
+ aggregation: daily
diff --git a/lib/gitlab/usage_data_counters/static_site_editor_counter.rb b/lib/gitlab/usage_data_counters/static_site_editor_counter.rb
new file mode 100644
index 00000000000..8886a106da8
--- /dev/null
+++ b/lib/gitlab/usage_data_counters/static_site_editor_counter.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module UsageDataCounters
+ class StaticSiteEditorCounter < BaseCounter
+ KNOWN_EVENTS = %w[views].freeze
+ PREFIX = 'static_site_editor'
+
+ class << self
+ def increment_views_count
+ count(:views)
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/usage_data_queries.rb b/lib/gitlab/usage_data_queries.rb
index bacd63ab282..c54e766230e 100644
--- a/lib/gitlab/usage_data_queries.rb
+++ b/lib/gitlab/usage_data_queries.rb
@@ -22,7 +22,7 @@ module Gitlab
end
def sum(relation, column, *rest)
- relation.select(relation.all.table[column].sum).to_sql # rubocop:disable CodeReuse/ActiveRecord
+ relation.select(relation.all.table[column].sum).to_sql
end
private
diff --git a/lib/gitlab/utils/usage_data.rb b/lib/gitlab/utils/usage_data.rb
index ca6a36c9cea..5267733d220 100644
--- a/lib/gitlab/utils/usage_data.rb
+++ b/lib/gitlab/utils/usage_data.rb
@@ -39,9 +39,9 @@ module Gitlab
FALLBACK = -1
- def count(relation, column = nil, batch: true, start: nil, finish: nil)
+ def count(relation, column = nil, batch: true, batch_size: nil, start: nil, finish: nil)
if batch
- Gitlab::Database::BatchCount.batch_count(relation, column, start: start, finish: finish)
+ Gitlab::Database::BatchCount.batch_count(relation, column, batch_size: batch_size, start: start, finish: finish)
else
relation.count
end
@@ -106,7 +106,6 @@ module Gitlab
# @param values [Array|String] the values counted
def track_usage_event(event_name, values)
return unless Feature.enabled?(:"usage_data_#{event_name}", default_enabled: true)
- return unless Gitlab::CurrentSettings.usage_ping_enabled?
Gitlab::UsageDataCounters::HLLRedisCounter.track_event(values, event_name.to_s)
end
diff --git a/lib/gitlab/view/presenter/factory.rb b/lib/gitlab/view/presenter/factory.rb
index 302697ff8eb..5768bab03c6 100644
--- a/lib/gitlab/view/presenter/factory.rb
+++ b/lib/gitlab/view/presenter/factory.rb
@@ -10,7 +10,7 @@ module Gitlab
end
def fabricate!
- presenter_class.new(subject, attributes)
+ presenter_class.new(subject, **attributes)
end
private
diff --git a/lib/gitlab/visibility_level_checker.rb b/lib/gitlab/visibility_level_checker.rb
index f15f1486a4e..3ffd86c4f8c 100644
--- a/lib/gitlab/visibility_level_checker.rb
+++ b/lib/gitlab/visibility_level_checker.rb
@@ -3,7 +3,7 @@
# Gitlab::VisibilityLevelChecker verifies that:
# - Current @project.visibility_level is not restricted
# - Override visibility param is not restricted
-# - @see https://docs.gitlab.com/ce/api/project_import_export.html#import-a-file
+# - @see https://docs.gitlab.com/ee/api/project_import_export.html#import-a-file
#
# @param current_user [User] Current user object to verify visibility level against
# @param project [Project] Current project that is being created/imported
diff --git a/lib/gitlab/webpack/dev_server_middleware.rb b/lib/gitlab/webpack/dev_server_middleware.rb
index fda41da5a94..069e68e8d29 100644
--- a/lib/gitlab/webpack/dev_server_middleware.rb
+++ b/lib/gitlab/webpack/dev_server_middleware.rb
@@ -11,8 +11,15 @@ module Gitlab
@proxy_host = opts.fetch(:proxy_host, 'localhost')
@proxy_port = opts.fetch(:proxy_port, 3808)
@proxy_path = opts[:proxy_path] if opts[:proxy_path]
+ @proxy_scheme = opts[:proxy_https] ? 'https' : 'http'
- super(app, backend: "http://#{@proxy_host}:#{@proxy_port}", **opts)
+ super(app, backend: "#{@proxy_scheme}://#{@proxy_host}:#{@proxy_port}", **opts)
+ end
+
+ # disable SSL check since any cert used here will likely be self-signed
+ def rewrite_env(env)
+ env["rack.ssl_verify_none"] = true
+ env
end
def perform_request(env)
diff --git a/lib/gitlab/webpack/manifest.rb b/lib/gitlab/webpack/manifest.rb
index d2c01bbd55e..5873d9c2b99 100644
--- a/lib/gitlab/webpack/manifest.rb
+++ b/lib/gitlab/webpack/manifest.rb
@@ -1,16 +1,33 @@
# frozen_string_literal: true
-require 'webpack/rails/manifest'
+require 'net/http'
+require 'uri'
module Gitlab
module Webpack
- class Manifest < ::Webpack::Rails::Manifest
- # Raised if a supplied asset does not exist in the webpack manifest
+ class Manifest
+ # Raised if we can't read our webpack manifest for whatever reason
+ class ManifestLoadError < StandardError
+ def initialize(message, orig)
+ super "#{message}\n\n(original error #{orig.class.name}: #{orig})"
+ end
+ end
+
+ # Raised if webpack couldn't build one of your entry points
+ class WebpackError < StandardError
+ def initialize(errors)
+ super "Error in webpack compile, details follow below:\n#{errors.join("\n\n")}"
+ end
+ end
+
+ # Raised if a supplied entry point does not exist in the webpack manifest
AssetMissingError = Class.new(StandardError)
class << self
+ include Gitlab::Utils::StrongMemoize
+
def entrypoint_paths(source)
- raise ::Webpack::Rails::Manifest::WebpackError, manifest["errors"] unless manifest_bundled?
+ raise WebpackError, manifest["errors"] unless manifest_bundled?
dll_assets = manifest.fetch("dllAssets", [])
entrypoint = manifest["entrypoints"][source]
@@ -18,12 +35,93 @@ module Gitlab
# Can be either a string or an array of strings.
# Do not include source maps as they are not javascript
[dll_assets, entrypoint["assets"]].flatten.reject { |p| p =~ /.*\.map$/ }.map do |p|
- "/#{::Rails.configuration.webpack.public_path}/#{p}"
+ "/#{Gitlab.config.webpack.public_path}/#{p}"
+ end
+ else
+ raise AssetMissingError, "Can't find asset '#{source}' in webpack manifest"
+ end
+ end
+
+ def asset_paths(source)
+ raise WebpackError, manifest["errors"] unless manifest_bundled?
+
+ paths = manifest["assetsByChunkName"][source]
+ if paths
+ # Can be either a string or an array of strings.
+ # Do not include source maps as they are not javascript
+ [paths].flatten.reject { |p| p =~ /.*\.map$/ }.map do |p|
+ "/#{Gitlab.config.webpack.public_path}/#{p}"
end
else
raise AssetMissingError, "Can't find entry point '#{source}' in webpack manifest"
end
end
+
+ def clear_manifest!
+ clear_memoization(:manifest)
+ end
+
+ private
+
+ def manifest_bundled?
+ !manifest["errors"].any? { |error| error.include? "Module build failed" }
+ end
+
+ def manifest
+ if Gitlab.config.webpack.dev_server.enabled
+ # Don't cache if we're in dev server mode, manifest may change ...
+ load_manifest
+ else
+ # ... otherwise cache at class level, as JSON loading/parsing can be expensive
+ strong_memoize(:manifest) { load_manifest }
+ end
+ end
+
+ def load_manifest
+ data = if Gitlab.config.webpack.dev_server.enabled
+ load_dev_server_manifest
+ else
+ load_static_manifest
+ end
+
+ Gitlab::Json.parse(data)
+ end
+
+ def load_dev_server_manifest
+ host = Gitlab.config.webpack.dev_server.host
+ port = Gitlab.config.webpack.dev_server.port
+ scheme = Gitlab.config.webpack.dev_server.https ? 'https' : 'http'
+ uri = Addressable::URI.new(scheme: scheme, host: host, port: port, path: dev_server_path)
+
+ # localhost could be blocked via Gitlab::HTTP
+ response = HTTParty.get(uri.to_s, verify: false) # rubocop:disable Gitlab/HTTParty
+
+ return response.body if response.code == 200
+
+ raise "HTTP error #{response.code}"
+ rescue OpenSSL::SSL::SSLError, EOFError => e
+ ssl_status = Gitlab.config.webpack.dev_server.https ? ' over SSL' : ''
+ raise ManifestLoadError.new("Could not connect to webpack-dev-server at #{uri}#{ssl_status}.\n\nIs SSL enabled? Check that settings in `gitlab.yml` and webpack-dev-server match.", e)
+ rescue => e
+ raise ManifestLoadError.new("Could not load manifest from webpack-dev-server at #{uri}.\n\nIs webpack-dev-server running? Try running `gdk status webpack` or `gdk tail webpack`.", e)
+ end
+
+ def load_static_manifest
+ File.read(static_manifest_path)
+ rescue => e
+ raise ManifestLoadError.new("Could not load compiled manifest from #{static_manifest_path}.\n\nHave you run `rake gitlab:assets:compile`?", e)
+ end
+
+ def static_manifest_path
+ ::Rails.root.join(
+ Gitlab.config.webpack.output_dir,
+ Gitlab.config.webpack.manifest_filename
+ )
+ end
+
+ def dev_server_path
+ "/#{Gitlab.config.webpack.public_path}/#{Gitlab.config.webpack.manifest_filename}"
+ end
end
end
end
diff --git a/lib/gitlab/whats_new.rb b/lib/gitlab/whats_new.rb
new file mode 100644
index 00000000000..e95ace2c475
--- /dev/null
+++ b/lib/gitlab/whats_new.rb
@@ -0,0 +1,28 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module WhatsNew
+ CACHE_DURATION = 1.day
+ WHATS_NEW_FILES_PATH = Rails.root.join('data', 'whats_new', '*.yml')
+
+ private
+
+ def whats_new_most_recent_release_items
+ Rails.cache.fetch('whats_new:release_items', expires_in: CACHE_DURATION) do
+ file = File.read(most_recent_release_file_path)
+
+ items = YAML.safe_load(file, permitted_classes: [Date])
+
+ items if items.is_a?(Array)
+ end
+ rescue => e
+ Gitlab::ErrorTracking.track_exception(e, yaml_file_path: most_recent_release_file_path)
+
+ nil
+ end
+
+ def most_recent_release_file_path
+ @most_recent_release_file_path ||= Dir.glob(WHATS_NEW_FILES_PATH).max
+ end
+ end
+end
diff --git a/lib/gitlab/workhorse.rb b/lib/gitlab/workhorse.rb
index 8a5acd242d9..eb780a2f7f6 100644
--- a/lib/gitlab/workhorse.rb
+++ b/lib/gitlab/workhorse.rb
@@ -269,7 +269,8 @@ module Gitlab
commit_id: metadata['CommitId'],
prefix: metadata['ArchivePrefix'],
format: format,
- path: path.presence || ""
+ path: path.presence || "",
+ include_lfs_blobs: Feature.enabled?(:include_lfs_blobs_in_archive)
).to_proto
)
}
diff --git a/lib/gitlab_danger.rb b/lib/gitlab_danger.rb
index a906beda80e..bbb64e0d5da 100644
--- a/lib/gitlab_danger.rb
+++ b/lib/gitlab_danger.rb
@@ -11,7 +11,7 @@ class GitlabDanger
karma
database
commit_messages
- telemetry
+ product_analytics
utility_css
pajamas
].freeze
@@ -24,6 +24,7 @@ class GitlabDanger
ce_ee_vue_templates
sidekiq_queues
specialization_labels
+ ci_templates
].freeze
MESSAGE_PREFIX = '==>'.freeze
diff --git a/lib/google_api/cloud_platform/client.rb b/lib/google_api/cloud_platform/client.rb
index 9668badc757..f16bd7c735b 100644
--- a/lib/google_api/cloud_platform/client.rb
+++ b/lib/google_api/cloud_platform/client.rb
@@ -66,7 +66,7 @@ module GoogleApi
cluster_options = make_cluster_options(cluster_name, cluster_size, machine_type, legacy_abac, enable_addons)
- request_body = Google::Apis::ContainerV1beta1::CreateClusterRequest.new(cluster_options)
+ request_body = Google::Apis::ContainerV1beta1::CreateClusterRequest.new(**cluster_options)
service.create_cluster(project_id, zone, request_body, options: user_agent_header)
end
diff --git a/lib/grafana/client.rb b/lib/grafana/client.rb
index b419f79bace..7c0e56b61c8 100644
--- a/lib/grafana/client.rb
+++ b/lib/grafana/client.rb
@@ -19,8 +19,8 @@ module Grafana
# @param name [String] Unique identifier for a Grafana datasource
def get_datasource(name:)
# CGI#escape formats strings such that the Grafana endpoint
- # will not recognize the dashboard name. Preferring URI#escape.
- http_get("#{@api_url}/api/datasources/name/#{URI.escape(name)}") # rubocop:disable Lint/UriEscapeUnescape
+ # will not recognize the dashboard name. Prefer Addressable::URI#encode_component.
+ http_get("#{@api_url}/api/datasources/name/#{Addressable::URI.encode_component(name)}")
end
# @param datasource_id [String] Grafana ID for the datasource
diff --git a/lib/pager_duty/validator/schemas/message.json b/lib/pager_duty/validator/schemas/message.json
new file mode 100644
index 00000000000..b1a3185cd1a
--- /dev/null
+++ b/lib/pager_duty/validator/schemas/message.json
@@ -0,0 +1,47 @@
+{
+ "type": "object",
+ "required": ["event", "incident"],
+ "properties": {
+ "event": { "type": "string" },
+ "incident": {
+ "type": "object",
+ "required": [
+ "html_url",
+ "incident_number",
+ "title",
+ "status",
+ "created_at",
+ "urgency",
+ "incident_key"
+ ],
+ "properties": {
+ "html_url": { "type": "string" },
+ "incindent_number": { "type": "integer" },
+ "title": { "type": "string" },
+ "status": { "type": "string" },
+ "created_at": { "type": "string" },
+ "urgency": { "type": "string", "enum": ["high", "low"] },
+ "incident_key": { "type": ["string", "null"] },
+ "assignments": {
+ "type": "array",
+ "items": {
+ "assignee": {
+ "type": "array",
+ "items": {
+ "summary": { "type": "string" },
+ "html_url": { "type": "string" }
+ }
+ }
+ }
+ },
+ "impacted_services": {
+ "type": "array",
+ "items": {
+ "summary": { "type": "string" },
+ "html_url": { "type": "string" }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/lib/pager_duty/webhook_payload_parser.rb b/lib/pager_duty/webhook_payload_parser.rb
index 573fb36f0ca..11071926cf2 100644
--- a/lib/pager_duty/webhook_payload_parser.rb
+++ b/lib/pager_duty/webhook_payload_parser.rb
@@ -2,6 +2,8 @@
module PagerDuty
class WebhookPayloadParser
+ SCHEMA_PATH = File.join('lib', 'pager_duty', 'validator', 'schemas', 'message.json')
+
def initialize(payload)
@payload = payload
end
@@ -11,7 +13,7 @@ module PagerDuty
end
def call
- Array(payload['messages']).map { |msg| parse_message(msg) }
+ Array(payload['messages']).map { |msg| parse_message(msg) }.reject(&:empty?)
end
private
@@ -19,6 +21,8 @@ module PagerDuty
attr_reader :payload
def parse_message(message)
+ return {} unless valid_message?(message)
+
{
'event' => message['event'],
'incident' => parse_incident(message['incident'])
@@ -26,8 +30,6 @@ module PagerDuty
end
def parse_incident(incident)
- return {} if incident.blank?
-
{
'url' => incident['html_url'],
'incident_number' => incident['incident_number'],
@@ -62,5 +64,9 @@ module PagerDuty
def reject_empty(entities)
Array(entities).reject { |e| e['summary'].blank? && e['url'].blank? }
end
+
+ def valid_message?(message)
+ ::JSONSchemer.schema(Pathname.new(SCHEMA_PATH)).valid?(message)
+ end
end
end
diff --git a/lib/peek/views/active_record.rb b/lib/peek/views/active_record.rb
index ed3470f81f4..77108bb81ca 100644
--- a/lib/peek/views/active_record.rb
+++ b/lib/peek/views/active_record.rb
@@ -17,24 +17,35 @@ module Peek
}
}.freeze
+ def results
+ super.merge(calls: detailed_calls)
+ end
+
def self.thresholds
@thresholds ||= THRESHOLDS.fetch(Rails.env.to_sym, DEFAULT_THRESHOLDS)
end
private
+ def detailed_calls
+ "#{calls} (#{cached_calls} cached)"
+ end
+
+ def cached_calls
+ detail_store.count { |item| item[:cached] == 'cached' }
+ end
+
def setup_subscribers
super
subscribe('sql.active_record') do |_, start, finish, _, data|
if Gitlab::PerformanceBar.enabled_for_request?
- unless data[:cached]
- detail_store << {
- duration: finish - start,
- sql: data[:sql].strip,
- backtrace: Gitlab::BacktraceCleaner.clean_backtrace(caller)
- }
- end
+ detail_store << {
+ duration: finish - start,
+ sql: data[:sql].strip,
+ backtrace: Gitlab::BacktraceCleaner.clean_backtrace(caller),
+ cached: data[:cached] ? 'cached' : ''
+ }
end
end
end
diff --git a/lib/peek/views/detailed_view.rb b/lib/peek/views/detailed_view.rb
index 389f5301079..4cc2e85c7bb 100644
--- a/lib/peek/views/detailed_view.rb
+++ b/lib/peek/views/detailed_view.rb
@@ -23,7 +23,7 @@ module Peek
private
def duration
- detail_store.map { |entry| entry[:duration] }.sum * 1000 # rubocop:disable CodeReuse/ActiveRecord
+ detail_store.map { |entry| entry[:duration] }.sum * 1000
end
def calls
diff --git a/lib/safe_zip/extract.rb b/lib/safe_zip/extract.rb
index 679c021c730..ac33f0b3c2c 100644
--- a/lib/safe_zip/extract.rb
+++ b/lib/safe_zip/extract.rb
@@ -19,11 +19,7 @@ module SafeZip
def extract(opts = {})
params = SafeZip::ExtractParams.new(**opts)
- if Feature.enabled?(:safezip_use_rubyzip, default_enabled: true)
- extract_with_ruby_zip(params)
- else
- legacy_unsafe_extract_with_system_zip(params)
- end
+ extract_with_ruby_zip(params)
end
private
@@ -53,21 +49,5 @@ module SafeZip
.extract
end
end
-
- def legacy_unsafe_extract_with_system_zip(params)
- # Requires UnZip at least 6.00 Info-ZIP.
- # -n never overwrite existing files
- args = %W(unzip -n -qq #{archive_path})
-
- # We add * to end of directory, because we want to extract directory and all subdirectories
- args += params.directories_wildcard
-
- # Target directory where we extract
- args += %W(-d #{params.extract_path})
-
- unless system(*args)
- raise Error, 'archive failed to extract'
- end
- end
end
end
diff --git a/lib/sentry/client/issue.rb b/lib/sentry/client/issue.rb
index c5e9df9cd21..f714bda49fd 100644
--- a/lib/sentry/client/issue.rb
+++ b/lib/sentry/client/issue.rb
@@ -14,7 +14,7 @@ module Sentry
}.freeze
def list_issues(**keyword_args)
- response = get_issues(keyword_args)
+ response = get_issues(**keyword_args)
issues = response[:issues]
pagination = response[:pagination]
@@ -44,7 +44,7 @@ module Sentry
def get_issues(**keyword_args)
response = http_get(
api_urls.issues_url,
- query: list_issue_sentry_query(keyword_args)
+ query: list_issue_sentry_query(**keyword_args)
)
{
diff --git a/lib/system_check/app/redis_version_check.rb b/lib/system_check/app/redis_version_check.rb
index 697ced3590b..a205861b9a9 100644
--- a/lib/system_check/app/redis_version_check.rb
+++ b/lib/system_check/app/redis_version_check.rb
@@ -37,7 +37,7 @@ module SystemCheck
@custom_error_message
)
for_more_information(
- 'doc/administration/high_availability/redis.md#provide-your-own-redis-instance'
+ 'doc/administration/redis/index.html#redis-replication-and-failover-using-the-non-bundled-redis'
)
fix_and_rerun
end
diff --git a/lib/tasks/gettext.rake b/lib/tasks/gettext.rake
index 1e28d15f75e..e2c92054d62 100644
--- a/lib/tasks/gettext.rake
+++ b/lib/tasks/gettext.rake
@@ -38,7 +38,7 @@ namespace :gettext do
Rake::Task['gettext:find'].invoke
# leave only the required changes.
- unless system(*%w(git checkout -- locale/*/gitlab.po))
+ unless system(*%w(git -c core.hooksPath=/dev/null checkout -- locale/*/gitlab.po))
raise 'failed to cleanup generated locale/*/gitlab.po files'
end
diff --git a/lib/tasks/gitlab/assets.rake b/lib/tasks/gitlab/assets.rake
index caa583fb3a9..ab2d77eeaf0 100644
--- a/lib/tasks/gitlab/assets.rake
+++ b/lib/tasks/gitlab/assets.rake
@@ -81,7 +81,7 @@ namespace :gitlab do
if head_assets_md5 != master_assets_md5 || !public_assets_webpack_dir_exists
FileUtils.rm_r(Tasks::Gitlab::Assets::PUBLIC_ASSETS_WEBPACK_DIR) if public_assets_webpack_dir_exists
- Rake::Task['webpack:compile'].invoke
+ system('yarn webpack')
end
end
diff --git a/lib/tasks/gitlab/backup.rake b/lib/tasks/gitlab/backup.rake
index 2a3713ed85c..de2dfca8c1b 100644
--- a/lib/tasks/gitlab/backup.rake
+++ b/lib/tasks/gitlab/backup.rake
@@ -107,7 +107,7 @@ namespace :gitlab do
puts "GITLAB_BACKUP_MAX_CONCURRENCY and GITLAB_BACKUP_MAX_STORAGE_CONCURRENCY must have a value of at least 1".color(:red)
exit 1
else
- Backup::Repository.new(progress).dump(
+ Backup::Repositories.new(progress).dump(
max_concurrency: max_concurrency,
max_storage_concurrency: max_storage_concurrency
)
@@ -117,7 +117,7 @@ namespace :gitlab do
task restore: :gitlab_environment do
puts_time "Restoring repositories ...".color(:blue)
- Backup::Repository.new(progress).restore
+ Backup::Repositories.new(progress).restore
puts_time "done".color(:green)
end
end
diff --git a/lib/tasks/gitlab/db.rake b/lib/tasks/gitlab/db.rake
index 425f66918b0..a3f20f31f64 100644
--- a/lib/tasks/gitlab/db.rake
+++ b/lib/tasks/gitlab/db.rake
@@ -35,6 +35,11 @@ namespace :gitlab do
# Truncate schema_migrations to ensure migrations re-run
connection.execute('TRUNCATE schema_migrations') if connection.table_exists? 'schema_migrations'
+ # Drop any views
+ connection.views.each do |view|
+ connection.execute("DROP VIEW IF EXISTS #{connection.quote_table_name(view)} CASCADE")
+ end
+
# Drop tables with cascade to avoid dependent table errors
# PG: http://www.postgresql.org/docs/current/static/ddl-depend.html
# Add `IF EXISTS` because cascade could have already deleted a table.
@@ -60,6 +65,19 @@ namespace :gitlab do
end
end
+ desc 'GitLab | DB | Run database migrations and print `unattended_migrations_completed` if action taken'
+ task unattended: :environment do
+ no_database = !ActiveRecord::Base.connection.schema_migration.table_exists?
+ needs_migrations = ActiveRecord::Base.connection.migration_context.needs_migration?
+
+ if no_database || needs_migrations
+ Rake::Task['gitlab:db:configure'].invoke
+ puts "unattended_migrations_completed"
+ else
+ puts "unattended_migrations_static"
+ end
+ end
+
desc 'GitLab | DB | Checks if migrations require downtime or not'
task :downtime_check, [:ref] => :environment do |_, args|
abort 'You must specify a Git reference to compare with' unless args[:ref]
@@ -169,9 +187,21 @@ namespace :gitlab do
desc 'reindex a regular (non-unique) index without downtime to eliminate bloat'
task :reindex, [:index_name] => :environment do |_, args|
- raise ArgumentError, 'must give the index name to reindex' unless args[:index_name]
+ unless Feature.enabled?(:database_reindexing, type: :ops)
+ puts "This feature (database_reindexing) is currently disabled.".color(:yellow)
+ exit
+ end
+
+ indexes = if args[:index_name]
+ [Gitlab::Database::PostgresIndex.by_identifier(args[:index_name])]
+ else
+ Gitlab::Database::Reindexing.candidate_indexes.random_few(2)
+ end
- Gitlab::Database::ConcurrentReindex.new(args[:index_name], logger: Logger.new(STDOUT)).execute
+ Gitlab::Database::Reindexing.perform(indexes)
+ rescue => e
+ Gitlab::AppLogger.error(e)
+ raise
end
end
end
diff --git a/lib/tasks/gitlab/web_hook.rake b/lib/tasks/gitlab/web_hook.rake
index 0b98755a77c..b242329d720 100644
--- a/lib/tasks/gitlab/web_hook.rake
+++ b/lib/tasks/gitlab/web_hook.rake
@@ -37,7 +37,10 @@ namespace :gitlab do
web_hooks.find_each do |hook|
next unless hook.url == web_hook_url
- hook.destroy!
+ result = WebHooks::DestroyService.new(nil).sync_destroy(hook)
+
+ raise "Unable to destroy Web hook" unless result[:status] == :success
+
count += 1
end
diff --git a/lib/uploaded_file.rb b/lib/uploaded_file.rb
index cd5943b552e..9b034d1c6c2 100644
--- a/lib/uploaded_file.rb
+++ b/lib/uploaded_file.rb
@@ -42,6 +42,9 @@ class UploadedFile
@remote_id = remote_id
end
+ # TODO this function is meant to replace .from_params when the feature flag
+ # upload_middleware_jwt_params_handler is removed
+ # See https://gitlab.com/gitlab-org/gitlab/-/issues/233895#roll-out-steps
def self.from_params_without_field(params, upload_paths)
path = params['path']
remote_id = params['remote_id']
@@ -68,6 +71,10 @@ class UploadedFile
)
end
+ # Deprecated. Don't use it.
+ # .from_params_without_field will replace this one
+ # See .from_params_without_field and
+ # https://gitlab.com/gitlab-org/gitlab/-/issues/233895#roll-out-steps
def self.from_params(params, field, upload_paths, path_override = nil)
path = path_override || params["#{field}.path"]
remote_id = params["#{field}.remote_id"]
diff --git a/locale/am_ET/gitlab.po b/locale/am_ET/gitlab.po
index faf7e76b843..ccb2d2cfd20 100644
--- a/locale/am_ET/gitlab.po
+++ b/locale/am_ET/gitlab.po
@@ -14,7 +14,10 @@ msgstr ""
"X-Crowdin-Language: am\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 6\n"
-"PO-Revision-Date: 2020-09-04 23:05\n"
+"PO-Revision-Date: 2020-10-02 18:45\n"
+
+msgid " %{project_name}#%{issue_iid} &middot; opened %{issue_created} by %{author}"
+msgstr ""
msgid " %{start} to %{end}"
msgstr ""
@@ -74,6 +77,16 @@ msgstr "\"%{path}\" በ\"%{ref}\" ላይ አáˆá‰°áŒˆáŠ˜áˆ"
msgid "\"el\" parameter is required for createInstance()"
msgstr ""
+msgid "%d Approval"
+msgid_plural "%d Approvals"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d Package"
+msgid_plural "%d Packages"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d Scanned URL"
msgid_plural "%d Scanned URLs"
msgstr[0] ""
@@ -137,6 +150,11 @@ msgstr[1] "%d commits á¥"
msgid "%d commits"
msgstr "%d commits"
+msgid "%d completed issue"
+msgid_plural "%d completed issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d contribution"
msgid_plural "%d contributions"
msgstr[0] "%d መዋጮ"
@@ -147,6 +165,11 @@ msgid_plural "%d days"
msgstr[0] ""
msgstr[1] ""
+msgid "%d day until tags are automatically removed"
+msgid_plural "%d days until tags are automatically removed"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d error"
msgid_plural "%d errors"
msgstr[0] ""
@@ -237,6 +260,16 @@ msgid_plural "%d more comments"
msgstr[0] "%d ተጨማሪ አስተያየት"
msgstr[1] "%d ተጨማሪ አስተያየቶች"
+msgid "%d open issue"
+msgid_plural "%d open issues"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d pending comment"
+msgid_plural "%d pending comments"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d personal project will be removed and cannot be restored."
msgid_plural "%d personal projects will be removed and cannot be restored."
msgstr[0] ""
@@ -252,6 +285,11 @@ msgid_plural "%d projects"
msgstr[0] "%d á•áˆ®áŒ€áŠ­á‰µ"
msgstr[1] "%d á•áˆ®áŒ€áŠ­á‰¶á‰½"
+msgid "%d project selected"
+msgid_plural "%d projects selected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d request with warnings"
msgid_plural "%d requests with warnings"
msgstr[0] "%d ማስጠንቀቂ ያለዠጥያቄ"
@@ -272,6 +310,11 @@ msgid_plural "%d tags"
msgstr[0] "%d መለያ"
msgstr[1] "%d መለያዎች"
+msgid "%d tag per image name"
+msgid_plural "%d tags per image name"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d unassigned issue"
msgid_plural "%d unassigned issues"
msgstr[0] ""
@@ -292,6 +335,11 @@ msgid_plural "%d vulnerabilities dismissed"
msgstr[0] ""
msgstr[1] ""
+msgid "%d warning found:"
+msgid_plural "%d warnings found:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%s additional commit has been omitted to prevent performance issues."
msgid_plural "%s additional commits have been omitted to prevent performance issues."
msgstr[0] "የአáˆáƒá€áˆ እክሎች እንዳያጋጥሙ %s ተጨማሪ commit አáˆá‰°áŠ«á‰°á‰°áˆá¢"
@@ -330,6 +378,9 @@ msgstr ""
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr "%{commit_timeago} በ%{commit_author_link} የተደረሰ"
+msgid "%{completedCount} completed weight"
+msgstr ""
+
msgid "%{completedWeight} of %{totalWeight} weight completed"
msgstr ""
@@ -378,14 +429,12 @@ msgid_plural "%{count} participants"
msgstr[0] "%{count} ተሳታáŠ"
msgstr[1] "%{count} ተሳታáŠá‹Žá‰½"
-msgid "%{count} pending comment"
-msgid_plural "%{count} pending comments"
-msgstr[0] "%{count} በመጠባበቅ ላይ ያለ አስተያየት"
-msgstr[1] "%{count} በመጠባበቅ ላይ ያሉ አስተያየቶች"
-
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr "%{count} ተዛማጅ %{pluralized_subject}: %{links}"
+msgid "%{count} total weight"
+msgstr ""
+
msgid "%{dashboard_path} could not be found."
msgstr ""
@@ -440,6 +489,9 @@ msgstr ""
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 መለያ መáጠር ይኖርቦታáˆá¢"
+msgid "%{group_name}&%{epic_iid} &middot; opened %{epic_created} by %{author}"
+msgstr ""
+
msgid "%{host} sign-in from new location"
msgstr ""
@@ -452,8 +504,8 @@ msgstr ""
msgid "%{issuableType} will be removed! Are you sure?"
msgstr "%{issuableType} ይወገዳáˆ! እርáŒáŒ áŠ› ኖት? "
-msgid "%{issuesSize} issues with a limit of %{maxIssueCount}"
-msgstr "%{issuesSize} ጉዳዮች ባለ %{maxIssueCount} ወሰን"
+msgid "%{issuesCount} issues with a limit of %{maxIssueCount}"
+msgstr ""
msgid "%{issuesSize} with a limit of %{maxIssueCount}"
msgstr ""
@@ -485,7 +537,7 @@ msgstr ""
msgid "%{labelStart}Namespace:%{labelEnd} %{namespace}"
msgstr ""
-msgid "%{labelStart}Report Type:%{labelEnd} %{reportType}"
+msgid "%{labelStart}Scan Type:%{labelEnd} %{reportType}"
msgstr ""
msgid "%{labelStart}Scanner:%{labelEnd} %{scanner}"
@@ -682,9 +734,6 @@ msgid_plural "%{securityScanner} results are not available because a pipeline ha
msgstr[0] ""
msgstr[1] ""
-msgid "%{service_title} %{message}."
-msgstr ""
-
msgid "%{size} GiB"
msgstr ""
@@ -773,6 +822,12 @@ msgstr ""
msgid "%{timebox_name} should belong either to a project or a group."
msgstr ""
+msgid "%{timebox_type} does not support burnup charts"
+msgstr ""
+
+msgid "%{timebox_type} must have a start and due date"
+msgstr ""
+
msgid "%{title} %{operator} %{threshold}"
msgstr ""
@@ -797,7 +852,7 @@ msgstr ""
msgid "%{total} open issue weight"
msgstr ""
-msgid "%{total} open issues"
+msgid "%{total} warnings found: showing first %{warningsDisplayed}"
msgstr ""
msgid "%{usage_ping_link_start}Learn more%{usage_ping_link_end} about what information is shared with GitLab Inc."
@@ -830,9 +885,6 @@ msgstr ""
msgid "&lt; 1 hour"
msgstr ""
-msgid "&lt;no name set&gt;"
-msgstr ""
-
msgid "&lt;no scopes selected&gt;"
msgstr ""
@@ -863,6 +915,9 @@ msgstr ""
msgid "'%{name}' Value Stream created"
msgstr ""
+msgid "'%{name}' Value Stream deleted"
+msgstr ""
+
msgid "'%{name}' stage already exists"
msgstr ""
@@ -922,6 +977,9 @@ msgstr ""
msgid "+ %{numberOfHiddenAssignees} more"
msgstr ""
+msgid "+ %{numberOfHiddenReviewers} more"
+msgstr ""
+
msgid "+%d more"
msgid_plural "+%d more"
msgstr[0] ""
@@ -982,6 +1040,11 @@ msgid_plural "%d Days"
msgstr[0] ""
msgstr[1] ""
+msgid "1 Issue"
+msgid_plural "%d Issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "1 closed issue"
msgid_plural "%{issues} closed issues"
msgstr[0] ""
@@ -997,6 +1060,11 @@ msgid_plural "%d days"
msgstr[0] ""
msgstr[1] ""
+msgid "1 deploy key"
+msgid_plural "%d deploy keys"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1099,6 +1167,9 @@ msgstr ""
msgid ":%{startLine} to %{endLine}"
msgstr ""
+msgid "A %{incident_docs_start}modified issue%{incident_docs_end} to guide the resolution of incidents."
+msgstr ""
+
msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr ""
@@ -1111,6 +1182,9 @@ msgstr ""
msgid "A GitBook site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
+msgid "A Gitpod configured Webapplication in Spring and Java"
+msgstr ""
+
msgid "A Hexo site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
@@ -1282,9 +1356,15 @@ msgstr ""
msgid "Access expiration date"
msgstr ""
+msgid "Access expires"
+msgstr ""
+
msgid "Access forbidden. Check your access level."
msgstr ""
+msgid "Access granted"
+msgstr ""
+
msgid "Access requests"
msgstr ""
@@ -1294,6 +1374,9 @@ msgstr ""
msgid "Access to Pages websites are controlled based on the user's membership to a given project. By checking this box, users will be required to be logged in to have access to all Pages websites in your instance."
msgstr ""
+msgid "AccessDropdown|Deploy Keys"
+msgstr ""
+
msgid "AccessDropdown|Groups"
msgstr ""
@@ -1411,12 +1494,6 @@ msgstr ""
msgid "Active Sessions"
msgstr ""
-msgid "Active Users:"
-msgstr ""
-
-msgid "Active users"
-msgstr ""
-
msgid "Activity"
msgstr ""
@@ -1584,9 +1661,6 @@ msgstr ""
msgid "Add label(s)"
msgstr ""
-msgid "Add license"
-msgstr ""
-
msgid "Add list"
msgstr ""
@@ -1761,21 +1835,51 @@ msgstr ""
msgid "AdminArea|Bots"
msgstr ""
+msgid "AdminArea|Components"
+msgstr ""
+
msgid "AdminArea|Developer"
msgstr ""
+msgid "AdminArea|Features"
+msgstr ""
+
+msgid "AdminArea|Groups: %{number_of_groups}"
+msgstr ""
+
msgid "AdminArea|Guest"
msgstr ""
msgid "AdminArea|Included Free in license"
msgstr ""
+msgid "AdminArea|Latest groups"
+msgstr ""
+
+msgid "AdminArea|Latest projects"
+msgstr ""
+
+msgid "AdminArea|Latest users"
+msgstr ""
+
msgid "AdminArea|Maintainer"
msgstr ""
+msgid "AdminArea|New group"
+msgstr ""
+
+msgid "AdminArea|New project"
+msgstr ""
+
+msgid "AdminArea|New user"
+msgstr ""
+
msgid "AdminArea|Owner"
msgstr ""
+msgid "AdminArea|Projects: %{number_of_projects}"
+msgstr ""
+
msgid "AdminArea|Reporter"
msgstr ""
@@ -1803,6 +1907,9 @@ msgstr ""
msgid "AdminArea|Users without a Group and Project"
msgstr ""
+msgid "AdminArea|Users: %{number_of_users}"
+msgstr ""
+
msgid "AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running."
msgstr ""
@@ -1821,9 +1928,6 @@ msgstr ""
msgid "AdminProjects|Delete Project %{projectName}?"
msgstr ""
-msgid "AdminProjects|Delete project"
-msgstr ""
-
msgid "AdminSettings|Apply integration settings to all Projects"
msgstr ""
@@ -2061,21 +2165,30 @@ msgstr ""
msgid "AdminUsers|Without projects"
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 ""
msgid "AdminUsers|You cannot remove your own admin rights."
msgstr ""
+msgid "AdminUsers|You must transfer ownership or delete the groups owned by this user before you can delete their account"
+msgstr ""
+
msgid "Administration"
msgstr ""
msgid "Advanced"
msgstr ""
+msgid "Advanced Search"
+msgstr ""
+
+msgid "Advanced Search with Elasticsearch"
+msgstr ""
+
msgid "Advanced Settings"
msgstr ""
@@ -2153,6 +2266,9 @@ msgstr ""
msgid "AlertManagement|Edit"
msgstr ""
+msgid "AlertManagement|Environment"
+msgstr ""
+
msgid "AlertManagement|Events"
msgstr ""
@@ -2165,6 +2281,9 @@ msgstr ""
msgid "AlertManagement|Issue"
msgstr ""
+msgid "AlertManagement|Key"
+msgstr ""
+
msgid "AlertManagement|Low"
msgstr ""
@@ -2258,6 +2377,9 @@ msgstr ""
msgid "AlertManagement|Unknown"
msgstr ""
+msgid "AlertManagement|Value"
+msgstr ""
+
msgid "AlertManagement|View alerts in Opsgenie"
msgstr ""
@@ -2417,6 +2539,9 @@ msgstr ""
msgid "All projects"
msgstr ""
+msgid "All projects selected"
+msgstr ""
+
msgid "All security scans are enabled because %{linkStart}Auto DevOps%{linkEnd} is enabled on this project"
msgstr ""
@@ -2504,6 +2629,9 @@ msgstr ""
msgid "Almost there"
msgstr ""
+msgid "Already blocked"
+msgstr ""
+
msgid "Also called \"Issuer\" or \"Relying party trust identifier\""
msgstr ""
@@ -2558,6 +2686,9 @@ msgstr ""
msgid "An error has occurred"
msgstr ""
+msgid "An error occured while making the changes: %{error}"
+msgstr ""
+
msgid "An error occurred adding a draft to the thread."
msgstr ""
@@ -2585,12 +2716,6 @@ msgstr ""
msgid "An error occurred when toggling the notification subscription"
msgstr ""
-msgid "An error occurred when trying to resolve a comment. Please try again."
-msgstr ""
-
-msgid "An error occurred when trying to resolve a discussion. Please try again."
-msgstr ""
-
msgid "An error occurred when updating the issue weight"
msgstr ""
@@ -2606,12 +2731,6 @@ msgstr ""
msgid "An error occurred while checking group path. Please refresh and try again."
msgstr ""
-msgid "An error occurred while committing your changes."
-msgstr ""
-
-msgid "An error occurred while creating the list. Please try again."
-msgstr ""
-
msgid "An error occurred while decoding the file."
msgstr ""
@@ -2684,25 +2803,19 @@ msgstr ""
msgid "An error occurred while fetching the Service Desk address."
msgstr ""
-msgid "An error occurred while fetching the board issues. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the board lists. Please reload the page."
msgstr ""
msgid "An error occurred while fetching the board lists. Please try again."
msgstr ""
-msgid "An error occurred while fetching the board swimlanes. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the builds."
msgstr ""
msgid "An error occurred while fetching the job log."
msgstr ""
-msgid "An error occurred while fetching the job trace."
+msgid "An error occurred while fetching the job logs."
msgstr ""
msgid "An error occurred while fetching the job."
@@ -2849,9 +2962,6 @@ msgstr ""
msgid "An error occurred while saving assignees"
msgstr ""
-msgid "An error occurred while saving the template. Please check if the template exists."
-msgstr ""
-
msgid "An error occurred while searching for milestones"
msgstr ""
@@ -2870,10 +2980,10 @@ msgstr ""
msgid "An error occurred while updating approvers"
msgstr ""
-msgid "An error occurred while updating the comment"
+msgid "An error occurred while updating labels."
msgstr ""
-msgid "An error occurred while updating the list. Please try again."
+msgid "An error occurred while updating the comment"
msgstr ""
msgid "An error occurred while validating group path"
@@ -2927,6 +3037,9 @@ msgstr ""
msgid "An unknown error occurred while loading this graph."
msgstr ""
+msgid "An unknown error occurred."
+msgstr ""
+
msgid "Analytics"
msgstr ""
@@ -2960,10 +3073,10 @@ msgstr ""
msgid "Any"
msgstr ""
-msgid "Any Author"
+msgid "Any %{header}"
msgstr ""
-msgid "Any Status"
+msgid "Any Author"
msgstr ""
msgid "Any branch"
@@ -3017,6 +3130,9 @@ msgstr ""
msgid "Application ID"
msgstr ""
+msgid "Application limits saved successfully"
+msgstr ""
+
msgid "Application settings saved successfully"
msgstr ""
@@ -3226,6 +3342,9 @@ msgstr ""
msgid "Are you sure you want to close this blocked issue?"
msgstr ""
+msgid "Are you sure you want to delete \"%{name}\" Value Stream?"
+msgstr ""
+
msgid "Are you sure you want to delete %{name}?"
msgstr ""
@@ -3235,6 +3354,9 @@ msgstr ""
msgid "Are you sure you want to delete this %{typeOfComment}?"
msgstr ""
+msgid "Are you sure you want to delete this SSH key?"
+msgstr ""
+
msgid "Are you sure you want to delete this board?"
msgstr ""
@@ -3259,6 +3381,11 @@ msgstr ""
msgid "Are you sure you want to erase this build?"
msgstr ""
+msgid "Are you sure you want to import %d repository?"
+msgid_plural "Are you sure you want to import %d repositories?"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Are you sure you want to lose unsaved changes?"
msgstr ""
@@ -3268,15 +3395,15 @@ msgstr ""
msgid "Are you sure you want to merge immediately?"
msgstr ""
-msgid "Are you sure you want to permanently delete this license?"
-msgstr ""
-
msgid "Are you sure you want to re-deploy this environment?"
msgstr ""
msgid "Are you sure you want to regenerate the public key? You will have to update the public key on the remote server before mirroring will work again."
msgstr ""
+msgid "Are you sure you want to reindex?"
+msgstr ""
+
msgid "Are you sure you want to remove %{group_name}?"
msgstr ""
@@ -3304,6 +3431,9 @@ msgstr ""
msgid "Are you sure you want to revoke this nickname?"
msgstr ""
+msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
+msgstr ""
+
msgid "Are you sure you want to stop this environment?"
msgstr ""
@@ -3325,6 +3455,9 @@ msgstr ""
msgid "Are you sure? The device will be signed out of GitLab and all remember me tokens revoked."
msgstr ""
+msgid "Are you sure? This will invalidate your registered applications and U2F / WebAuthn devices."
+msgstr ""
+
msgid "Are you sure? This will invalidate your registered applications and U2F devices."
msgstr ""
@@ -3343,9 +3476,6 @@ msgstr ""
msgid "Artifacts"
msgstr ""
-msgid "As U2F devices are only supported by a few browsers, we require that you set up a two-factor authentication app before a U2F device. That way you'll always be able to log in - even when you're using an unsupported browser."
-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 ""
@@ -3539,6 +3669,9 @@ msgstr ""
msgid "AuditLogs|Target"
msgstr ""
+msgid "AuditLogs|This month"
+msgstr ""
+
msgid "AuditLogs|User Events"
msgstr ""
@@ -3578,6 +3711,9 @@ msgstr ""
msgid "Authentication via U2F device failed."
msgstr ""
+msgid "Authentication via WebAuthn device failed."
+msgstr ""
+
msgid "Author"
msgstr ""
@@ -3845,15 +3981,6 @@ msgstr ""
msgid "BambooService|You must set up automatic revision labeling and a repository trigger in Bamboo."
msgstr ""
-msgid "BatchComments|Delete all pending comments"
-msgstr ""
-
-msgid "BatchComments|Discard review?"
-msgstr ""
-
-msgid "BatchComments|You're about to discard your review which will delete all of your pending comments. The deleted comments %{strong_start}cannot%{strong_end} be restored."
-msgstr ""
-
msgid "Be careful. Changing the project's namespace can have unintended side effects."
msgstr ""
@@ -3875,6 +4002,9 @@ msgstr ""
msgid "Bi-weekly code coverage"
msgstr ""
+msgid "Billable Users:"
+msgstr ""
+
msgid "Billing"
msgstr ""
@@ -3884,7 +4014,7 @@ msgstr ""
msgid "BillingPlans|@%{user_name} you are currently using the %{plan_name} plan."
msgstr ""
-msgid "BillingPlans|Congratulations, your new trial is activated"
+msgid "BillingPlans|Congratulations, your free trial is activated."
msgstr ""
msgid "BillingPlans|If you would like to downgrade your plan please contact %{support_link_start}Customer Support%{support_link_end}."
@@ -3947,6 +4077,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Block user"
+msgstr ""
+
msgid "Blocked"
msgstr ""
@@ -3962,31 +4095,37 @@ msgstr ""
msgid "Blog"
msgstr ""
-msgid "Board name"
-msgstr ""
-
msgid "Board scope"
msgstr ""
msgid "Board scope affects which issues are displayed for anyone who visits this board"
msgstr ""
-msgid "BoardBlankState|Add default lists"
+msgid "Boards"
msgstr ""
-msgid "BoardBlankState|Add the following default lists to your Issue Board with one click:"
+msgid "Boards and Board Lists"
msgstr ""
-msgid "BoardBlankState|Nevermind, I'll use my own"
+msgid "Boards|An error occurred while creating the issue. Please try again."
msgstr ""
-msgid "BoardBlankState|Starting out with the default set of lists will get you right on the way to making the most of your board."
+msgid "Boards|An error occurred while creating the list. Please try again."
msgstr ""
-msgid "Boards"
+msgid "Boards|An error occurred while fetching issues. Please reload the page."
msgstr ""
-msgid "Boards and Board Lists"
+msgid "Boards|An error occurred while fetching the board issues. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching the board swimlanes. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while moving the issue. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while updating the list. Please try again."
msgstr ""
msgid "Boards|Collapse"
@@ -4013,7 +4152,7 @@ msgstr ""
msgid "Branch %{branch_name} was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr ""
-msgid "Branch has changed"
+msgid "Branch changed"
msgstr ""
msgid "Branch is already taken"
@@ -4319,6 +4458,9 @@ msgstr ""
msgid "CLOSED (MOVED)"
msgstr ""
+msgid "CODEOWNERS rule violation"
+msgstr ""
+
msgid "CONTRIBUTING"
msgstr ""
@@ -4349,9 +4491,6 @@ msgstr ""
msgid "Can't create snippet: %{err}"
msgstr ""
-msgid "Can't edit as source branch was deleted"
-msgstr ""
-
msgid "Can't fetch content for the blob: %{err}"
msgstr ""
@@ -4364,9 +4503,6 @@ msgstr ""
msgid "Can't load mermaid module: %{err}"
msgstr ""
-msgid "Can't remove group members without group managed account"
-msgstr ""
-
msgid "Can't scan the code?"
msgstr ""
@@ -4409,6 +4545,9 @@ msgstr ""
msgid "Cannot create the abuse report. This user has been blocked."
msgstr ""
+msgid "Cannot enable shared runners because parent group does not allow it"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -4514,6 +4653,15 @@ msgstr ""
msgid "Change your password or recover your current one"
msgstr ""
+msgid "ChangeReviewer|Reviewer changed from %{old} to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Reviewer changed to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Unassigned"
+msgstr ""
+
msgid "ChangeTypeActionLabel|Pick into branch"
msgstr ""
@@ -4553,6 +4701,9 @@ msgstr ""
msgid "Changes the title to \"%{title_param}\"."
msgstr ""
+msgid "Changes were successfully made."
+msgstr ""
+
msgid "Changes won't take place until the index is %{link_start}recreated%{link_end}."
msgstr ""
@@ -4958,6 +5109,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove variable"
+msgstr ""
+
msgid "CiVariables|Remove variable row"
msgstr ""
@@ -5036,9 +5190,6 @@ msgstr ""
msgid "Clear due date"
msgstr ""
-msgid "Clear input"
-msgstr ""
-
msgid "Clear recent searches"
msgstr ""
@@ -5087,6 +5238,9 @@ msgstr ""
msgid "Client authentication key password"
msgstr ""
+msgid "Client request timeout"
+msgstr ""
+
msgid "Clients"
msgstr ""
@@ -5171,6 +5325,27 @@ msgstr ""
msgid "Cluster type must be specificed for Stages::ClusterEndpointInserter"
msgstr ""
+msgid "ClusterAgents|Configuration"
+msgstr ""
+
+msgid "ClusterAgents|Connect your cluster with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate Kubernetes with a GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Name"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Agent also requires %{linkStart}enabling the Agent Server%{linkEnd}"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Kubernetes Agent allows an Infrastructure as Code, GitOps approach to integrating Kubernetes clusters with GitLab. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "ClusterAgent|This feature is only available for premium plans"
msgstr ""
@@ -5240,10 +5415,10 @@ msgstr ""
msgid "ClusterIntegration|All installed applications and related resources"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster."
+msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{linkStart}More information%{linkEnd}"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{startLink}More information%{endLink}"
+msgid "ClusterIntegration|Allow GitLab to manage namespaces and service accounts for this cluster."
msgstr ""
msgid "ClusterIntegration|Alternatively, "
@@ -5264,6 +5439,9 @@ msgstr ""
msgid "ClusterIntegration|An error occurred while trying to fetch zone machine types: %{error}"
msgstr ""
+msgid "ClusterIntegration|An unknown error occurred while attempting to connect to Kubernetes."
+msgstr ""
+
msgid "ClusterIntegration|Any project namespaces"
msgstr ""
@@ -5279,6 +5457,9 @@ msgstr ""
msgid "ClusterIntegration|Authenticate with Amazon Web Services"
msgstr ""
+msgid "ClusterIntegration|Authentication Error"
+msgstr ""
+
msgid "ClusterIntegration|Base domain"
msgstr ""
@@ -5297,13 +5478,22 @@ msgstr ""
msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}security group %{externalLinkIcon} %{endLink} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
+msgid "ClusterIntegration|Check your CA certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Check your cluster status"
+msgstr ""
+
+msgid "ClusterIntegration|Check your token"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}subnets %{externalLinkIcon} %{endLink} in your VPC where your worker nodes will run."
+msgid "ClusterIntegration|Choose the %{linkStart}security group %{linkEnd} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
msgstr ""
-msgid "ClusterIntegration|Choose the worker node %{startLink}instance type %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Choose the %{linkStart}subnets %{linkEnd} in your VPC where your worker nodes will run."
+msgstr ""
+
+msgid "ClusterIntegration|Choose the worker node %{linkStart}instance type%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Choose which applications to install on your Kubernetes cluster."
@@ -5315,10 +5505,7 @@ msgstr ""
msgid "ClusterIntegration|Clear cluster cache"
msgstr ""
-msgid "ClusterIntegration|Clear the local cache of namespace and service accounts. This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
-msgstr ""
-
-msgid "ClusterIntegration|Cluster being created"
+msgid "ClusterIntegration|Clear the local cache of namespace and service accounts."
msgstr ""
msgid "ClusterIntegration|Cluster management project (alpha)"
@@ -5330,15 +5517,21 @@ msgstr ""
msgid "ClusterIntegration|Cluster_applications artifact too big. Maximum allowable size: %{human_size}"
msgstr ""
-msgid "ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters."
+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|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}"
+msgid "ClusterIntegration|Clusters connected with a certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Connect cluster with certificate"
msgstr ""
msgid "ClusterIntegration|Connect existing cluster"
msgstr ""
+msgid "ClusterIntegration|Connection Error"
+msgstr ""
+
msgid "ClusterIntegration|Copy API URL"
msgstr ""
@@ -5414,6 +5607,12 @@ msgstr ""
msgid "ClusterIntegration|Deletes all GitLab resources attached to this cluster during removal"
msgstr ""
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared."
+msgstr ""
+
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared. %{linkStart}More information%{linkEnd}"
+msgstr ""
+
msgid "ClusterIntegration|Did you know?"
msgstr ""
@@ -5483,6 +5682,9 @@ msgstr ""
msgid "ClusterIntegration|Fluentd is an open source data collector, which lets you unify the data collection and consumption for a better use and understanding of data. It requires at least one of the following logs to be successfully installed."
msgstr ""
+msgid "ClusterIntegration|GitLab Agent managed clusters"
+msgstr ""
+
msgid "ClusterIntegration|GitLab Container Network Policies"
msgstr ""
@@ -5495,6 +5697,12 @@ msgstr ""
msgid "ClusterIntegration|GitLab Runner connects to the repository and executes CI/CD jobs, pushing results back and deploying applications to production."
msgstr ""
+msgid "ClusterIntegration|GitLab failed to authenticate."
+msgstr ""
+
+msgid "ClusterIntegration|GitLab failed to connect to the cluster."
+msgstr ""
+
msgid "ClusterIntegration|GitLab-managed cluster"
msgstr ""
@@ -5516,6 +5724,9 @@ msgstr ""
msgid "ClusterIntegration|Group cluster"
msgstr ""
+msgid "ClusterIntegration|HTTP Error"
+msgstr ""
+
msgid "ClusterIntegration|Helm Tiller"
msgstr ""
@@ -5549,7 +5760,10 @@ msgstr ""
msgid "ClusterIntegration|Instance type"
msgstr ""
-msgid "ClusterIntegration|Integrate Kubernetes cluster automation"
+msgid "ClusterIntegration|Integrate Kubernetes with a cluster certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Integrate with a cluster certificate"
msgstr ""
msgid "ClusterIntegration|Issuer Email"
@@ -5585,9 +5799,6 @@ msgstr ""
msgid "ClusterIntegration|Knative extends Kubernetes to provide a set of middleware components that are essential to build modern, source-centric, and container-based applications that can run anywhere: on premises, in the cloud, or even in a third-party data center."
msgstr ""
-msgid "ClusterIntegration|Kubernetes cluster"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes cluster is being created..."
msgstr ""
@@ -5600,9 +5811,6 @@ msgstr ""
msgid "ClusterIntegration|Kubernetes clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr ""
-msgid "ClusterIntegration|Kubernetes clusters can be used to deploy applications and to provide Review Apps for this project"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes version"
msgstr ""
@@ -5615,7 +5823,7 @@ msgstr ""
msgid "ClusterIntegration|Learn more about %{help_link_start}zones%{help_link_end}."
msgstr ""
-msgid "ClusterIntegration|Learn more about %{startLink}Regions %{externalLinkIcon}%{endLink}."
+msgid "ClusterIntegration|Learn more about %{linkStart}Regions%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Learn more about Kubernetes"
@@ -5660,12 +5868,18 @@ msgstr ""
msgid "ClusterIntegration|Machine type"
msgstr ""
+msgid "ClusterIntegration|Make sure your API endpoint is correct"
+msgstr ""
+
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create Kubernetes clusters"
msgstr ""
msgid "ClusterIntegration|Manage your Kubernetes cluster by visiting %{provider_link}"
msgstr ""
+msgid "ClusterIntegration|Namespace per environment"
+msgstr ""
+
msgid "ClusterIntegration|No IAM Roles found"
msgstr ""
@@ -5711,6 +5925,9 @@ msgstr ""
msgid "ClusterIntegration|No zones matched your search"
msgstr ""
+msgid "ClusterIntegration|Node calculations use the Kubernetes Metrics API. Make sure your cluster has metrics installed"
+msgstr ""
+
msgid "ClusterIntegration|Number of nodes"
msgstr ""
@@ -5753,6 +5970,9 @@ msgstr ""
msgid "ClusterIntegration|RBAC-enabled cluster"
msgstr ""
+msgid "ClusterIntegration|Read our %{linkStart}help page%{linkEnd} on Kubernetes cluster integration."
+msgstr ""
+
msgid "ClusterIntegration|Read our %{link_start}help page%{link_end} on Kubernetes cluster integration."
msgstr ""
@@ -5855,7 +6075,7 @@ msgstr ""
msgid "ClusterIntegration|Select a VPC to choose a subnet"
msgstr ""
-msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{linkStart}Amazon Web Services %{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select a network to choose a subnetwork"
@@ -5888,7 +6108,7 @@ msgstr ""
msgid "ClusterIntegration|Select project to choose zone"
msgstr ""
-msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select zone"
@@ -5978,9 +6198,18 @@ msgstr ""
msgid "ClusterIntegration|There was a problem authenticating with your cluster. Please ensure your CA Certificate and Token are valid."
msgstr ""
+msgid "ClusterIntegration|There was an HTTP error when connecting to your cluster."
+msgstr ""
+
msgid "ClusterIntegration|This account must have permissions to create a Kubernetes cluster in the %{link_to_container_project} specified below"
msgstr ""
+msgid "ClusterIntegration|This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
+msgstr ""
+
+msgid "ClusterIntegration|This is necessary to clear existing environment-namespace associations from clusters previously managed by GitLab."
+msgstr ""
+
msgid "ClusterIntegration|This option will allow you to install applications on RBAC clusters."
msgstr ""
@@ -6005,9 +6234,21 @@ msgstr ""
msgid "ClusterIntegration|To use a new project, first create one on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}."
msgstr ""
+msgid "ClusterIntegration|Troubleshooting tips:"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Authenticate"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Connect"
+msgstr ""
+
msgid "ClusterIntegration|Uninstall %{appTitle}"
msgstr ""
+msgid "ClusterIntegration|Unknown Error"
+msgstr ""
+
msgid "ClusterIntegration|Update %{appTitle}"
msgstr ""
@@ -6068,7 +6309,7 @@ msgstr ""
msgid "ClusterIntegration|Your cluster API is unreachable. Please ensure your API URL is correct."
msgstr ""
-msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Zone"
@@ -6188,6 +6429,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse all threads"
+msgstr ""
+
msgid "Collapse approvers"
msgstr ""
@@ -6337,7 +6581,7 @@ msgstr ""
msgid "Commit…"
msgstr ""
-msgid "Company"
+msgid "Community forum"
msgstr ""
msgid "Company name"
@@ -6346,6 +6590,9 @@ msgstr ""
msgid "Compare"
msgstr ""
+msgid "Compare %{oldCommitId}...%{newCommitId}"
+msgstr ""
+
msgid "Compare Git revisions"
msgstr ""
@@ -6361,6 +6608,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare submodule commit revisions"
+msgstr ""
+
msgid "Compare with previous version"
msgstr ""
@@ -6496,6 +6746,9 @@ msgstr ""
msgid "Configure the way a user creates a new account."
msgstr ""
+msgid "Configure which lists are shown for anyone who visits this board"
+msgstr ""
+
msgid "Confirm"
msgstr ""
@@ -6721,6 +6974,9 @@ msgstr[1] ""
msgid "ContainerRegistry|Set cleanup policy"
msgstr ""
+msgid "ContainerRegistry|Some tags were not deleted"
+msgstr ""
+
msgid "ContainerRegistry|Something went wrong while fetching the cleanup policy."
msgstr ""
@@ -6760,6 +7016,9 @@ msgstr ""
msgid "ContainerRegistry|Tags with names matching this regex pattern will %{italicStart}expire:%{italicEnd}"
msgstr ""
+msgid "ContainerRegistry|The cleanup policy timed out before it could delete all tags. An administrator can %{adminLinkStart}manually run cleanup now%{adminLinkEnd} or you can wait for the cleanup policy to automatically run again. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "ContainerRegistry|The last tag related to this image was recently removed. This empty image and any associated data will be automatically removed as part of the regular Garbage Collection process. If you have any questions, contact your administrator."
msgstr ""
@@ -6892,6 +7151,9 @@ msgstr ""
msgid "Contributions per group member"
msgstr ""
+msgid "Contributor"
+msgstr ""
+
msgid "Contributors"
msgstr ""
@@ -7021,6 +7283,9 @@ msgstr ""
msgid "Could not change HEAD: branch '%{branch}' does not exist"
msgstr ""
+msgid "Could not commit. An unexpected error occurred."
+msgstr ""
+
msgid "Could not connect to FogBugz, check your URL"
msgstr ""
@@ -7060,6 +7325,9 @@ msgstr ""
msgid "Could not find iteration"
msgstr ""
+msgid "Could not load instance counts. Please refresh the page to try again."
+msgstr ""
+
msgid "Could not remove the trigger."
msgstr ""
@@ -7084,10 +7352,10 @@ msgstr ""
msgid "Could not save prometheus manual configuration"
msgstr ""
-msgid "Could not udpdate wiki page"
+msgid "Could not update the LDAP settings"
msgstr ""
-msgid "Could not update the LDAP settings"
+msgid "Could not update wiki page"
msgstr ""
msgid "Could not upload your designs as one or more files uploaded are not supported."
@@ -7745,6 +8013,9 @@ msgstr ""
msgid "DastProfiles|Are you sure you want to delete this profile?"
msgstr ""
+msgid "DastProfiles|Could not create site validation token. Please refresh the page, or try again later."
+msgstr ""
+
msgid "DastProfiles|Could not create the scanner profile. Please try again."
msgstr ""
@@ -7769,6 +8040,12 @@ msgstr ""
msgid "DastProfiles|Could not fetch site profiles. Please refresh the page, or try again later."
msgstr ""
+msgid "DastProfiles|Could not retrieve site validation status. Please refresh the page, or try again later."
+msgstr ""
+
+msgid "DastProfiles|Could not update the scanner profile. Please try again."
+msgstr ""
+
msgid "DastProfiles|Could not update the site profile. Please try again."
msgstr ""
@@ -7784,7 +8061,7 @@ msgstr ""
msgid "DastProfiles|Download validation text file"
msgstr ""
-msgid "DastProfiles|Edit feature will come soon. Please create a new profile if changes needed"
+msgid "DastProfiles|Edit scanner profile"
msgstr ""
msgid "DastProfiles|Edit site profile"
@@ -7817,6 +8094,9 @@ msgstr ""
msgid "DastProfiles|No profiles created yet"
msgstr ""
+msgid "DastProfiles|Passive"
+msgstr ""
+
msgid "DastProfiles|Please enter a valid URL format, ex: http://www.example.com/home"
msgstr ""
@@ -7832,6 +8112,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan mode"
+msgstr ""
+
msgid "DastProfiles|Scanner Profile"
msgstr ""
@@ -7871,10 +8154,10 @@ msgstr ""
msgid "DastProfiles|Text file validation"
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
+msgid "DastProfiles|The maximum number of minutes allowed for the spider to traverse the site."
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the spider to traverse the site."
+msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
msgstr ""
msgid "DastProfiles|Validate"
@@ -7907,6 +8190,9 @@ msgstr ""
msgid "Date picker"
msgstr ""
+msgid "Date range"
+msgstr ""
+
msgid "Date range cannot exceed %{maxDateRange} days."
msgstr ""
@@ -7931,6 +8217,9 @@ msgstr ""
msgid "Days to merge"
msgstr ""
+msgid "Dear Administrator,"
+msgstr ""
+
msgid "Debug"
msgstr ""
@@ -8042,12 +8331,18 @@ msgstr ""
msgid "Delete"
msgstr ""
+msgid "Delete %{name}"
+msgstr ""
+
msgid "Delete Comment"
msgstr ""
msgid "Delete Snippet"
msgstr ""
+msgid "Delete Value Stream"
+msgstr ""
+
msgid "Delete account"
msgstr ""
@@ -8069,9 +8364,6 @@ msgstr ""
msgid "Delete label: %{label_name} ?"
msgstr ""
-msgid "Delete license"
-msgstr ""
-
msgid "Delete list"
msgstr ""
@@ -8147,15 +8439,6 @@ msgstr ""
msgid "Deleting a project places it into a read-only state until %{date}, at which point the project will be permanently deleted. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "Deleting the license failed."
-msgstr ""
-
-msgid "Deleting the license failed. The license was not found."
-msgstr ""
-
-msgid "Deleting the license failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "Deleting the project will delete its repository and all related resources including issues, merge requests etc."
msgstr ""
@@ -8651,7 +8934,10 @@ msgstr ""
msgid "DesignManagement|The maximum number of designs allowed to be uploaded is %{upload_limit}. Please try again."
msgstr ""
-msgid "DesignManagement|To upload designs, you'll need to enable LFS. %{requirements_link_start}More information%{requirements_link_end}"
+msgid "DesignManagement|There was an error moving your designs. Please upload your designs below."
+msgstr ""
+
+msgid "DesignManagement|To upload designs, you'll need to enable LFS and have admin enable hashed storage. %{requirements_link_start}More information%{requirements_link_end}"
msgstr ""
msgid "DesignManagement|Unresolve thread"
@@ -8663,6 +8949,9 @@ msgstr ""
msgid "DesignManagement|Upload skipped."
msgstr ""
+msgid "DesignManagement|Your designs are being copied and are on their way… Please refresh to update."
+msgstr ""
+
msgid "DesignManagement|and %{moreCount} more."
msgstr ""
@@ -8720,6 +9009,9 @@ msgstr ""
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
+msgid "Direct member"
+msgstr ""
+
msgid "Direction"
msgstr ""
@@ -8768,9 +9060,6 @@ msgstr ""
msgid "Discard draft"
msgstr ""
-msgid "Discard review"
-msgstr ""
-
msgid "DiscordService|Discord Notifications"
msgstr ""
@@ -8839,10 +9128,10 @@ msgstr ""
msgid "Dismiss Merge Request promotion"
msgstr ""
-msgid "Dismiss Selected"
+msgid "Dismiss Value Stream Analytics introduction box"
msgstr ""
-msgid "Dismiss Value Stream Analytics introduction box"
+msgid "Dismiss selected"
msgstr ""
msgid "Dismiss trial promotion"
@@ -8893,9 +9182,6 @@ msgstr ""
msgid "Documents reindexed: %{processed_documents} (%{percentage}%%)"
msgstr ""
-msgid "Doing"
-msgstr ""
-
msgid "Domain"
msgstr ""
@@ -9091,9 +9377,6 @@ msgstr ""
msgid "Edit environment"
msgstr ""
-msgid "Edit file"
-msgstr ""
-
msgid "Edit files in the editor and commit changes here"
msgstr ""
@@ -9106,6 +9389,12 @@ msgstr ""
msgid "Edit identity for %{user_name}"
msgstr ""
+msgid "Edit in Web IDE"
+msgstr ""
+
+msgid "Edit in single-file editor"
+msgstr ""
+
msgid "Edit issues"
msgstr ""
@@ -9133,10 +9422,10 @@ msgstr ""
msgid "Editing"
msgstr ""
-msgid "Elasticsearch"
+msgid "Elasticsearch AWS IAM credentials"
msgstr ""
-msgid "Elasticsearch AWS IAM credentials"
+msgid "Elasticsearch HTTP client timeout value in seconds."
msgstr ""
msgid "Elasticsearch indexing restrictions"
@@ -9145,9 +9434,6 @@ msgstr ""
msgid "Elasticsearch indexing started"
msgstr ""
-msgid "Elasticsearch integration. Elasticsearch AWS IAM."
-msgstr ""
-
msgid "Elasticsearch reindexing is already in progress"
msgstr ""
@@ -9175,9 +9461,6 @@ msgstr ""
msgid "Email Notification"
msgstr ""
-msgid "Email address"
-msgstr ""
-
msgid "Email could not be sent"
msgstr ""
@@ -9241,6 +9524,9 @@ msgstr ""
msgid "Emails sent from Service Desk will have this name"
msgstr ""
+msgid "Emails sent to %{email} will still be supported"
+msgstr ""
+
msgid "Emails separated by comma"
msgstr ""
@@ -9274,9 +9560,18 @@ msgstr ""
msgid "Enable"
msgstr ""
+msgid "Enable %{link_start}Gitpod%{link_end} integration to launch a development environment in your browser directly from GitLab."
+msgstr ""
+
msgid "Enable Auto DevOps"
msgstr ""
+msgid "Enable Gitpod"
+msgstr ""
+
+msgid "Enable Gitpod?"
+msgstr ""
+
msgid "Enable HTML emails"
msgstr ""
@@ -9406,9 +9701,6 @@ msgstr ""
msgid "Encountered an error while rendering: %{err}"
msgstr ""
-msgid "End date"
-msgstr ""
-
msgid "Ends at (UTC)"
msgstr ""
@@ -9568,7 +9860,7 @@ msgstr ""
msgid "EnvironmentsDashboard|The environments dashboard provides a summary of each project's environments' status, including pipeline and alert statuses."
msgstr ""
-msgid "EnvironmentsDashboard|This dashboard displays a maximum of 7 projects and 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
+msgid "EnvironmentsDashboard|This dashboard displays 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
msgstr ""
msgid "Environments|An error occurred while canceling the auto stop, please try again"
@@ -9889,6 +10181,9 @@ msgstr ""
msgid "Error deleting project. Check logs for error details."
msgstr ""
+msgid "Error fetching burnup chart data"
+msgstr ""
+
msgid "Error fetching diverging counts for branches. Please try again."
msgstr ""
@@ -9967,6 +10262,9 @@ msgstr ""
msgid "Error occurred when saving assignees"
msgstr ""
+msgid "Error occurred when saving reviewers"
+msgstr ""
+
msgid "Error occurred when toggling the notification subscription"
msgstr ""
@@ -10219,10 +10517,13 @@ msgstr ""
msgid "Expand all"
msgstr ""
-msgid "Expand approvers"
+msgid "Expand all files"
msgstr ""
-msgid "Expand dropdown"
+msgid "Expand all threads"
+msgstr ""
+
+msgid "Expand approvers"
msgstr ""
msgid "Expand milestones"
@@ -10393,6 +10694,9 @@ msgstr ""
msgid "Failed to create Merge Request. Please try again."
msgstr ""
+msgid "Failed to create To-Do for the design."
+msgstr ""
+
msgid "Failed to create a branch for this issue. Please try again."
msgstr ""
@@ -10432,6 +10736,12 @@ msgstr ""
msgid "Failed to load authors. Please try again."
msgstr ""
+msgid "Failed to load branches. Please try again."
+msgstr ""
+
+msgid "Failed to load deploy keys."
+msgstr ""
+
msgid "Failed to load emoji list."
msgstr ""
@@ -10447,6 +10757,9 @@ msgstr ""
msgid "Failed to load groups & users."
msgstr ""
+msgid "Failed to load groups, users and deploy keys."
+msgstr ""
+
msgid "Failed to load labels. Please try again."
msgstr ""
@@ -10456,6 +10769,12 @@ msgstr ""
msgid "Failed to load related branches"
msgstr ""
+msgid "Failed to load sidebar confidential toggle"
+msgstr ""
+
+msgid "Failed to load sidebar lock status"
+msgstr ""
+
msgid "Failed to load stacktrace."
msgstr ""
@@ -10483,6 +10802,9 @@ msgstr ""
msgid "Failed to publish issue on status page."
msgstr ""
+msgid "Failed to remove To-Do for the design."
+msgstr ""
+
msgid "Failed to remove a Zoom meeting"
msgstr ""
@@ -10525,6 +10847,9 @@ msgstr ""
msgid "Failed to signing using smartcard authentication"
msgstr ""
+msgid "Failed to toggle To-Do for the design."
+msgstr ""
+
msgid "Failed to update branch!"
msgstr ""
@@ -10638,7 +10963,7 @@ msgstr ""
msgid "FeatureFlags|Edit User List"
msgstr ""
-msgid "FeatureFlags|Enable features for specific users and specific environments by defining feature flag strategies."
+msgid "FeatureFlags|Enable features for specific users and environments by configuring feature flag strategies."
msgstr ""
msgid "FeatureFlags|Environment Spec"
@@ -10698,7 +11023,7 @@ msgstr ""
msgid "FeatureFlags|Include additional user IDs"
msgstr ""
-msgid "FeatureFlags|Install a %{docs_link_anchored_start}compatible client library%{docs_link_anchored_end} and specify the API URL, application name, and instance ID during the configuration setup. %{docs_link_start}More Information%{docs_link_end}"
+msgid "FeatureFlags|Install a %{docsLinkAnchoredStart}compatible client library%{docsLinkAnchoredEnd} and specify the API URL, application name, and instance ID during the configuration setup. %{docsLinkStart}More Information%{docsLinkEnd}"
msgstr ""
msgid "FeatureFlags|Instance ID"
@@ -10710,6 +11035,9 @@ msgstr ""
msgid "FeatureFlags|Loading feature flags"
msgstr ""
+msgid "FeatureFlags|Loading user lists"
+msgstr ""
+
msgid "FeatureFlags|More information"
msgstr ""
@@ -10728,7 +11056,7 @@ msgstr ""
msgid "FeatureFlags|New feature flag"
msgstr ""
-msgid "FeatureFlags|New list"
+msgid "FeatureFlags|New user list"
msgstr ""
msgid "FeatureFlags|Percent of users"
@@ -10767,6 +11095,9 @@ msgstr ""
msgid "FeatureFlags|There was an error fetching the feature flags."
msgstr ""
+msgid "FeatureFlags|There was an error fetching the user lists."
+msgstr ""
+
msgid "FeatureFlags|There was an error retrieving user lists"
msgstr ""
@@ -10782,6 +11113,9 @@ msgstr ""
msgid "FeatureFlags|User List"
msgstr ""
+msgid "FeatureFlags|User Lists"
+msgstr ""
+
msgid "FeatureFlag|List"
msgstr ""
@@ -10809,15 +11143,6 @@ msgstr ""
msgid "Fetching incoming email"
msgstr ""
-msgid "Fetching licenses failed."
-msgstr ""
-
-msgid "Fetching licenses failed. The request endpoint was not found."
-msgstr ""
-
-msgid "Fetching licenses failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "File"
msgstr ""
@@ -10920,12 +11245,21 @@ msgstr ""
msgid "Filter by status"
msgstr ""
+msgid "Filter by test cases that are currently archived."
+msgstr ""
+
+msgid "Filter by test cases that are currently opened."
+msgstr ""
+
msgid "Filter by two-factor authentication"
msgstr ""
msgid "Filter by user"
msgstr ""
+msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
+msgstr ""
+
msgid "Filter pipelines"
msgstr ""
@@ -10941,7 +11275,7 @@ msgstr ""
msgid "Filter results..."
msgstr ""
-msgid "Filter your projects by name"
+msgid "Filter your repositories by name"
msgstr ""
msgid "Filter..."
@@ -10950,7 +11284,7 @@ msgstr ""
msgid "Find File"
msgstr ""
-msgid "Find bugs in your code with coverage-guided fuzzing"
+msgid "Find bugs in your code with coverage-guided fuzzing."
msgstr ""
msgid "Find by path"
@@ -10977,9 +11311,6 @@ msgstr ""
msgid "Finish editing this message first!"
msgstr ""
-msgid "Finish review"
-msgstr ""
-
msgid "Finish setting up your dedicated account for %{group_name}."
msgstr ""
@@ -11049,6 +11380,9 @@ msgstr ""
msgid "Footer message"
msgstr ""
+msgid "For a faster browsing experience, some files are collapsed by default."
+msgstr ""
+
msgid "For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
@@ -11058,6 +11392,9 @@ msgstr ""
msgid "For more info, read the documentation."
msgstr ""
+msgid "For more information on how the number of active users is calculated, see the %{self_managed_subscriptions_doc_link} documentation."
+msgstr ""
+
msgid "For more information, go to the "
msgstr ""
@@ -11196,6 +11533,9 @@ msgstr ""
msgid "Generate new token"
msgstr ""
+msgid "Generic package file size in bytes"
+msgstr ""
+
msgid "Geo"
msgstr ""
@@ -11457,6 +11797,9 @@ msgstr ""
msgid "Geo|Please refer to Geo Troubleshooting."
msgstr ""
+msgid "Geo|Primary node"
+msgstr ""
+
msgid "Geo|Project"
msgstr ""
@@ -11499,6 +11842,9 @@ msgstr ""
msgid "Geo|Review replication status, and resynchronize and reverify items with the primary node."
msgstr ""
+msgid "Geo|Secondary node"
+msgstr ""
+
msgid "Geo|Status"
msgstr ""
@@ -11538,6 +11884,9 @@ msgstr ""
msgid "Geo|URL must be a valid url (ex: https://gitlab.com)"
msgstr ""
+msgid "Geo|Undefined"
+msgstr ""
+
msgid "Geo|Unknown state"
msgstr ""
@@ -11613,10 +11962,16 @@ msgstr ""
msgid "GitHub import"
msgstr ""
+msgid "GitLab"
+msgstr ""
+
msgid "GitLab / Unsubscribe"
msgstr ""
-msgid "GitLab Enterprise Edition %{plan}"
+msgid "GitLab API"
+msgstr ""
+
+msgid "GitLab Billing Team."
msgstr ""
msgid "GitLab Group Runners can execute code for all the projects in this group."
@@ -11628,12 +11983,18 @@ msgstr ""
msgid "GitLab Issue"
msgstr ""
+msgid "GitLab Pages"
+msgstr ""
+
msgid "GitLab Service Desk is a simple way to allow people to create issues in your GitLab instance without needing their own user account. It provides a unique email address for end users to create issues in a project, and replies can be sent either through the GitLab interface or by email. End users will only see the thread through email."
msgstr ""
msgid "GitLab Shared Runners execute code of different projects on the same Runner unless you configure GitLab Runner Autoscale with MaxBuilds 1 (which it is on GitLab.com)."
msgstr ""
+msgid "GitLab Shell"
+msgstr ""
+
msgid "GitLab Support Bot"
msgstr ""
@@ -11643,7 +12004,7 @@ msgstr ""
msgid "GitLab User"
msgstr ""
-msgid "GitLab allows you to continue using your license even if you exceed the number of seats you purchased. You will be required to pay for these seats when you renew your license."
+msgid "GitLab Workhorse"
msgstr ""
msgid "GitLab commit"
@@ -11811,6 +12172,21 @@ msgstr ""
msgid "Gitlab Pages"
msgstr ""
+msgid "Gitpod"
+msgstr ""
+
+msgid "Gitpod|Add the URL to your Gitpod instance configured to read your GitLab projects."
+msgstr ""
+
+msgid "Gitpod|Enable Gitpod integration"
+msgstr ""
+
+msgid "Gitpod|Gitpod URL"
+msgstr ""
+
+msgid "Gitpod|e.g. https://gitpod.example.com"
+msgstr ""
+
msgid "Given access %{time_ago}"
msgstr ""
@@ -12318,9 +12694,6 @@ msgstr ""
msgid "GroupSAML|Valid SAML Response"
msgstr ""
-msgid "GroupSAML|With group managed accounts enabled, all the users without a group managed account will be excluded from the group."
-msgstr ""
-
msgid "GroupSAML|With prohibit outer forks flag enabled group members will be able to fork project only inside your group."
msgstr ""
@@ -12534,10 +12907,10 @@ msgstr ""
msgid "GroupsNew|Create group"
msgstr ""
-msgid "GroupsNew|GitLab group export"
+msgid "GroupsNew|Import"
msgstr ""
-msgid "GroupsNew|Import"
+msgid "GroupsNew|Import a GitLab group export file"
msgstr ""
msgid "GroupsNew|Import group"
@@ -12680,6 +13053,9 @@ msgid_plural "Hide charts"
msgstr[0] ""
msgstr[1] ""
+msgid "Hide comments on this file"
+msgstr ""
+
msgid "Hide details"
msgstr ""
@@ -12724,6 +13100,15 @@ msgstr ""
msgid "Highest role:"
msgstr ""
+msgid "HighlightBar|Alert events:"
+msgstr ""
+
+msgid "HighlightBar|Alert start time:"
+msgstr ""
+
+msgid "HighlightBar|Original alert:"
+msgstr ""
+
msgid "History"
msgstr ""
@@ -12901,6 +13286,9 @@ msgstr ""
msgid "If enabled, access to projects will be validated on an external service using their classification label."
msgstr ""
+msgid "If the number of active users exceeds the user limit, you will be charged for the number of %{users_over_license_link} at your next license reconciliation."
+msgstr ""
+
msgid "If there is no previous license or if the previous license has expired, some GitLab functionality will be blocked until a new, valid license is uploaded."
msgstr ""
@@ -12940,9 +13328,6 @@ msgstr ""
msgid "If your HTTP repository is not publicly accessible, add your credentials."
msgstr ""
-msgid "Iglu registry URL (optional)"
-msgstr ""
-
msgid "Ignore"
msgstr ""
@@ -12979,6 +13364,16 @@ msgstr ""
msgid "Import"
msgstr ""
+msgid "Import %d compatible repository"
+msgid_plural "Import %d compatible repositories"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Import %d repository"
+msgid_plural "Import %d repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Import CSV"
msgstr ""
@@ -12988,15 +13383,9 @@ msgstr ""
msgid "Import all compatible projects"
msgstr ""
-msgid "Import all compatible repositories"
-msgstr ""
-
msgid "Import all projects"
msgstr ""
-msgid "Import all repositories"
-msgstr ""
-
msgid "Import an exported GitLab project"
msgstr ""
@@ -13084,6 +13473,9 @@ msgstr ""
msgid "ImportProjects|Error importing repository %{project_safe_import_url} into %{project_full_path} - %{message}"
msgstr ""
+msgid "ImportProjects|Import repositories"
+msgstr ""
+
msgid "ImportProjects|Importing the project failed"
msgstr ""
@@ -13096,7 +13488,7 @@ msgstr ""
msgid "ImportProjects|Requesting your %{provider} repositories failed"
msgstr ""
-msgid "ImportProjects|Select the projects you want to import"
+msgid "ImportProjects|Select the repositories you want to import"
msgstr ""
msgid "ImportProjects|The remote data could not be imported."
@@ -13132,9 +13524,6 @@ msgstr ""
msgid "In order to enable Service Desk for your instance, you must first set up incoming email."
msgstr ""
-msgid "In order to gather accurate feature usage data, it can take 1 to 2 weeks to see your index."
-msgstr ""
-
msgid "In order to personalize your experience with GitLab%{br_tag}we would like to know a bit more about you."
msgstr ""
@@ -13165,18 +13554,30 @@ msgstr ""
msgid "IncidentManagement|Create incident"
msgstr ""
+msgid "IncidentManagement|Critical - S1"
+msgstr ""
+
msgid "IncidentManagement|Date created"
msgstr ""
msgid "IncidentManagement|Display your incidents in a dedicated view"
msgstr ""
+msgid "IncidentManagement|High - S2"
+msgstr ""
+
msgid "IncidentManagement|Incident"
msgstr ""
msgid "IncidentManagement|Incidents"
msgstr ""
+msgid "IncidentManagement|Low - S4"
+msgstr ""
+
+msgid "IncidentManagement|Medium - S3"
+msgstr ""
+
msgid "IncidentManagement|No incidents to display."
msgstr ""
@@ -13189,6 +13590,9 @@ msgstr ""
msgid "IncidentManagement|Published to status page"
msgstr ""
+msgid "IncidentManagement|Severity"
+msgstr ""
+
msgid "IncidentManagement|There are no closed incidents"
msgstr ""
@@ -13198,6 +13602,9 @@ msgstr ""
msgid "IncidentManagement|Unassigned"
msgstr ""
+msgid "IncidentManagement|Unknown"
+msgstr ""
+
msgid "IncidentManagement|Unpublished"
msgstr ""
@@ -13219,6 +13626,15 @@ msgstr ""
msgid "Incidents"
msgstr ""
+msgid "Incident|Alert details"
+msgstr ""
+
+msgid "Incident|Summary"
+msgstr ""
+
+msgid "Incident|There was an issue loading alert data. Please try again."
+msgstr ""
+
msgid "Include a Terms of Service agreement and Privacy Policy that all users must accept."
msgstr ""
@@ -13279,6 +13695,9 @@ msgstr ""
msgid "Information about additional Pages templates and how to install them can be found in our %{pages_getting_started_guide}."
msgstr ""
+msgid "Inherited"
+msgstr ""
+
msgid "Inherited:"
msgstr ""
@@ -13359,7 +13778,22 @@ msgstr ""
msgid "Instance administrators group already exists"
msgstr ""
-msgid "Instance license"
+msgid "InstanceStatistics|Groups"
+msgstr ""
+
+msgid "InstanceStatistics|Issues"
+msgstr ""
+
+msgid "InstanceStatistics|Merge Requests"
+msgstr ""
+
+msgid "InstanceStatistics|Pipelines"
+msgstr ""
+
+msgid "InstanceStatistics|Projects"
+msgstr ""
+
+msgid "InstanceStatistics|Users"
msgstr ""
msgid "Integration"
@@ -13371,6 +13805,12 @@ msgstr ""
msgid "Integrations"
msgstr ""
+msgid "Integrations|%{integration} settings saved and active."
+msgstr ""
+
+msgid "Integrations|%{integration} settings saved, but not active."
+msgstr ""
+
msgid "Integrations|All details"
msgstr ""
@@ -13380,6 +13820,12 @@ msgstr ""
msgid "Integrations|Comment settings:"
msgstr ""
+msgid "Integrations|Connection failed. Please check your settings."
+msgstr ""
+
+msgid "Integrations|Connection successful."
+msgstr ""
+
msgid "Integrations|Default settings are inherited from the group level."
msgstr ""
@@ -13395,6 +13841,15 @@ msgstr ""
msgid "Integrations|Includes commit title and branch"
msgstr ""
+msgid "Integrations|Projects using custom settings will not be impacted unless the project owner chooses to use instance-level defaults."
+msgstr ""
+
+msgid "Integrations|Save settings?"
+msgstr ""
+
+msgid "Integrations|Saving will update the default settings for all projects that are not using custom settings."
+msgstr ""
+
msgid "Integrations|Standard"
msgstr ""
@@ -13527,6 +13982,9 @@ msgstr ""
msgid "Invitation"
msgstr ""
+msgid "Invitation declined"
+msgstr ""
+
msgid "Invite"
msgstr ""
@@ -13578,6 +14036,42 @@ 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|%{linkStart}Read more%{linkEnd} about role permissions"
+msgstr ""
+
+msgid "InviteMembersModal|Access expiration date (optional)"
+msgstr ""
+
+msgid "InviteMembersModal|Cancel"
+msgstr ""
+
+msgid "InviteMembersModal|Choose a role permission"
+msgstr ""
+
+msgid "InviteMembersModal|GitLab member or Email address"
+msgstr ""
+
+msgid "InviteMembersModal|Invite"
+msgstr ""
+
+msgid "InviteMembersModal|Invite team members"
+msgstr ""
+
+msgid "InviteMembersModal|Search for members to invite"
+msgstr ""
+
+msgid "InviteMembersModal|User not invited. Feature coming soon!"
+msgstr ""
+
+msgid "InviteMembersModal|Users were succesfully added"
+msgstr ""
+
+msgid "InviteMembersModal|You're inviting members to the %{group_name} group"
+msgstr ""
+
+msgid "InviteMembers|Invite team members"
+msgstr ""
+
msgid "Invited"
msgstr ""
@@ -13632,10 +14126,13 @@ msgstr ""
msgid "Issue cannot be found."
msgstr ""
+msgid "Issue created from vulnerability %{vulnerability_link}"
+msgstr ""
+
msgid "Issue events"
msgstr ""
-msgid "Issue first depoloyed to production"
+msgid "Issue first deployed to production"
msgstr ""
msgid "Issue label"
@@ -13713,6 +14210,9 @@ msgstr ""
msgid "IssueTracker|Custom issue tracker"
msgstr ""
+msgid "IssueTracker|EWM work items tracker"
+msgstr ""
+
msgid "IssueTracker|Redmine issue tracker"
msgstr ""
@@ -13779,6 +14279,9 @@ msgstr ""
msgid "It looks like you have some draft commits in this branch."
msgstr ""
+msgid "It may be several days before you see feature usage data."
+msgstr ""
+
msgid "It must have a header row and at least two columns: the first column is the issue title and the second column is the issue description. The separator is automatically detected."
msgstr ""
@@ -14061,13 +14564,13 @@ msgstr ""
msgid "Join Zoom meeting"
msgstr ""
-msgid "Jul"
+msgid "Joined %{time_ago}"
msgstr ""
-msgid "July"
+msgid "Jul"
msgstr ""
-msgid "Jump to first unresolved thread"
+msgid "July"
msgstr ""
msgid "Jump to next unresolved thread"
@@ -14103,6 +14606,9 @@ msgstr ""
msgid "Keyboard shortcuts"
msgstr ""
+msgid "KeyboardKey|Ctrl+"
+msgstr ""
+
msgid "Keys"
msgstr ""
@@ -14151,6 +14657,9 @@ msgstr ""
msgid "LDAP Synchronization"
msgstr ""
+msgid "LDAP group settings"
+msgstr ""
+
msgid "LDAP settings"
msgstr ""
@@ -14160,6 +14669,9 @@ msgstr ""
msgid "LDAP sync in progress. This could take a few minutes. Refresh the page to see the changes."
msgstr ""
+msgid "LDAP synchronizations"
+msgstr ""
+
msgid "LFS"
msgstr ""
@@ -14240,7 +14752,16 @@ msgid_plural "Last %d days"
msgstr[0] ""
msgstr[1] ""
-msgid "Last %{days} days"
+msgid "Last 2 weeks"
+msgstr ""
+
+msgid "Last 30 days"
+msgstr ""
+
+msgid "Last 60 days"
+msgstr ""
+
+msgid "Last 90 days"
msgstr ""
msgid "Last Accessed On"
@@ -14318,6 +14839,9 @@ msgstr ""
msgid "Last used on:"
msgstr ""
+msgid "Last week"
+msgstr ""
+
msgid "LastCommit|authored"
msgstr ""
@@ -14333,6 +14857,9 @@ msgstr ""
msgid "Latest pipeline for the most recent commit on this branch"
msgstr ""
+msgid "Launch a ready-to-code development environment for your project."
+msgstr ""
+
msgid "Lead"
msgstr ""
@@ -14713,6 +15240,9 @@ msgstr ""
msgid "List of all merge commits"
msgstr ""
+msgid "List options"
+msgstr ""
+
msgid "List settings"
msgstr ""
@@ -14725,9 +15255,6 @@ msgstr ""
msgid "List your Bitbucket Server repositories"
msgstr ""
-msgid "Lists"
-msgstr ""
-
msgid "Live preview"
msgstr ""
@@ -14974,6 +15501,12 @@ msgstr ""
msgid "Mark as done"
msgstr ""
+msgid "Mark as draft"
+msgstr ""
+
+msgid "Mark as ready"
+msgstr ""
+
msgid "Mark as resolved"
msgstr ""
@@ -14995,6 +15528,24 @@ msgstr ""
msgid "Markdown is supported"
msgstr ""
+msgid "MarkdownEditor|Add a link (%{modifierKey}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add a link (%{modifier_key}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifierKey}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifier_key}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifierKey}I)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifier_key}I)"
+msgstr ""
+
msgid "Marked For Deletion At - %{deletion_time}"
msgstr ""
@@ -15079,7 +15630,25 @@ msgstr ""
msgid "Max access level"
msgstr ""
-msgid "Max seats used"
+msgid "Max role"
+msgstr ""
+
+msgid "Max size 15 MB"
+msgstr ""
+
+msgid "Maximum Conan package file size in bytes"
+msgstr ""
+
+msgid "Maximum Maven package file size in bytes"
+msgstr ""
+
+msgid "Maximum NPM package file size in bytes"
+msgstr ""
+
+msgid "Maximum NuGet package file size in bytes"
+msgstr ""
+
+msgid "Maximum PyPI package file size in bytes"
msgstr ""
msgid "Maximum Users:"
@@ -15211,6 +15780,18 @@ msgstr ""
msgid "Members with access to %{strong_start}%{group_name}%{strong_end}"
msgstr ""
+msgid "Members|%{time} by %{user}"
+msgstr ""
+
+msgid "Members|Expired"
+msgstr ""
+
+msgid "Members|No expiration set"
+msgstr ""
+
+msgid "Members|in %{time}"
+msgstr ""
+
msgid "Memory Usage"
msgstr ""
@@ -15397,9 +15978,6 @@ msgstr ""
msgid "MergeRequests|Thread will be unresolved"
msgstr ""
-msgid "MergeRequests|Toggle comments for this file"
-msgstr ""
-
msgid "MergeRequests|View file @ %{commitId}"
msgstr ""
@@ -15460,6 +16038,9 @@ msgstr ""
msgid "Merging immediately isn't recommended as it may negatively impact the existing merge train. Read the %{docsLinkStart}documentation%{docsLinkEnd} for more information."
msgstr ""
+msgid "Message"
+msgstr ""
+
msgid "Messages"
msgstr ""
@@ -15845,18 +16426,12 @@ msgid_plural "Milestones"
msgstr[0] ""
msgstr[1] ""
-msgid "Milestone does not support burnup charts"
-msgstr ""
-
msgid "Milestone lists not available with your current license"
msgstr ""
msgid "Milestone lists show all issues from the selected milestone."
msgstr ""
-msgid "Milestone must have a start and due date"
-msgstr ""
-
msgid "MilestoneSidebar|Closed:"
msgstr ""
@@ -16223,6 +16798,9 @@ msgstr ""
msgid "Namespace"
msgstr ""
+msgid "Namespace ID:"
+msgstr ""
+
msgid "Namespace is empty"
msgstr ""
@@ -16307,6 +16885,9 @@ msgstr ""
msgid "NetworkPolicies|Allow all outbound traffic from %{selector} to %{ruleSelector} on %{ports}"
msgstr ""
+msgid "NetworkPolicies|Are you sure you want to delete this policy? This action cannot be undone."
+msgstr ""
+
msgid "NetworkPolicies|Choose whether to enforce this policy."
msgstr ""
@@ -16316,12 +16897,21 @@ msgstr ""
msgid "NetworkPolicies|Define this policy's location, conditions and actions."
msgstr ""
+msgid "NetworkPolicies|Delete policy"
+msgstr ""
+
+msgid "NetworkPolicies|Delete policy: %{policy}"
+msgstr ""
+
msgid "NetworkPolicies|Deny all traffic"
msgstr ""
msgid "NetworkPolicies|Description"
msgstr ""
+msgid "NetworkPolicies|Edit policy"
+msgstr ""
+
msgid "NetworkPolicies|Editor mode"
msgstr ""
@@ -16349,6 +16939,9 @@ msgstr ""
msgid "NetworkPolicies|Name"
msgstr ""
+msgid "NetworkPolicies|Namespace"
+msgstr ""
+
msgid "NetworkPolicies|Network Policy"
msgstr ""
@@ -16400,6 +16993,9 @@ msgstr ""
msgid "NetworkPolicies|Rules"
msgstr ""
+msgid "NetworkPolicies|Save changes"
+msgstr ""
+
msgid "NetworkPolicies|Something went wrong, failed to update policy"
msgstr ""
@@ -16412,6 +17008,9 @@ msgstr ""
msgid "NetworkPolicies|Traffic that does not match any rule will be blocked."
msgstr ""
+msgid "NetworkPolicies|Unable to parse policy"
+msgstr ""
+
msgid "NetworkPolicies|YAML editor"
msgstr ""
@@ -16525,6 +17124,9 @@ msgstr ""
msgid "New Snippet"
msgstr ""
+msgid "New Test Case"
+msgstr ""
+
msgid "New User"
msgstr ""
@@ -16624,6 +17226,9 @@ msgstr ""
msgid "New tag"
msgstr ""
+msgid "New test case"
+msgstr ""
+
msgid "New users set to external"
msgstr ""
@@ -16696,7 +17301,7 @@ msgstr ""
msgid "No changes"
msgstr ""
-msgid "No changes between %{ref_start}%{source_branch}%{ref_end} and %{ref_start}%{target_branch}%{ref_end}"
+msgid "No changes between %{sourceBranch} and %{targetBranch}"
msgstr ""
msgid "No child epics match applied filters"
@@ -16711,6 +17316,9 @@ msgstr ""
msgid "No containers available"
msgstr ""
+msgid "No content to show"
+msgstr ""
+
msgid "No contributions"
msgstr ""
@@ -16786,9 +17394,6 @@ msgstr ""
msgid "No license. All rights reserved"
msgstr ""
-msgid "No licenses found."
-msgstr ""
-
msgid "No matches found"
msgstr ""
@@ -16801,6 +17406,9 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No members found"
+msgstr ""
+
msgid "No merge requests found"
msgstr ""
@@ -16822,6 +17430,9 @@ msgstr ""
msgid "No parent group"
msgstr ""
+msgid "No plan"
+msgstr ""
+
msgid "No pods available"
msgstr ""
@@ -16918,6 +17529,12 @@ msgstr ""
msgid "Not Implemented"
msgstr ""
+msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+msgstr ""
+
+msgid "Not all browsers support WebAuthn. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even from an unsupported browser."
+msgstr ""
+
msgid "Not all data has been processed yet, the accuracy of the chart for the selected timeframe is limited."
msgstr ""
@@ -17014,6 +17631,9 @@ msgstr ""
msgid "Notification settings saved"
msgstr ""
+msgid "NotificationEvent|Change reviewer merge request"
+msgstr ""
+
msgid "NotificationEvent|Close issue"
msgstr ""
@@ -17176,10 +17796,7 @@ msgstr ""
msgid "On track"
msgstr ""
-msgid "OnDemandScans|Attached branch"
-msgstr ""
-
-msgid "OnDemandScans|Attached branch is where the scan job runs."
+msgid "OnDemandScans|Could not fetch scanner profiles. Please refresh the page, or try again later."
msgstr ""
msgid "OnDemandScans|Could not fetch site profiles. Please refresh the page, or try again later."
@@ -17188,6 +17805,9 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
+msgid "OnDemandScans|Create a new scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Create a new site profile"
msgstr ""
@@ -17200,6 +17820,9 @@ msgstr ""
msgid "OnDemandScans|New on-demand DAST scan"
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 ""
@@ -17209,16 +17832,10 @@ msgstr ""
msgid "OnDemandScans|On-demand scans run outside the DevOps cycle and find vulnerabilities in your projects. %{learnMoreLinkStart}Learn more%{learnMoreLinkEnd}"
msgstr ""
-msgid "OnDemandScans|Only a passive scan can be performed on demand."
-msgstr ""
-
-msgid "OnDemandScans|Passive"
-msgstr ""
-
msgid "OnDemandScans|Run scan"
msgstr ""
-msgid "OnDemandScans|Scan mode"
+msgid "OnDemandScans|Scanner profile"
msgstr ""
msgid "OnDemandScans|Scanner settings"
@@ -17230,9 +17847,15 @@ msgstr ""
msgid "OnDemandScans|Select one of the existing profiles"
msgstr ""
+msgid "OnDemandScans|Site profile"
+msgstr ""
+
msgid "OnDemandScans|Site profiles"
msgstr ""
+msgid "OnDemandScans|Use existing scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Use existing site profile"
msgstr ""
@@ -17331,9 +17954,6 @@ msgstr ""
msgid "Open Selection"
msgstr ""
-msgid "Open Web IDE"
-msgstr ""
-
msgid "Open comment type dropdown"
msgstr ""
@@ -17439,6 +18059,9 @@ msgstr ""
msgid "Origin"
msgstr ""
+msgid "Orphaned member"
+msgstr ""
+
msgid "Other Labels"
msgstr ""
@@ -17454,6 +18077,9 @@ msgstr ""
msgid "Other visibility settings have been disabled by the administrator."
msgstr ""
+msgid "Our documentation includes an example DevOps Score report."
+msgstr ""
+
msgid "Out-of-compliance with this project's policies and should be removed"
msgstr ""
@@ -17478,6 +18104,9 @@ msgstr ""
msgid "Overwrite diverged branches"
msgstr ""
+msgid "Owned by %{image_tag}"
+msgstr ""
+
msgid "Owned by anyone"
msgstr ""
@@ -17499,6 +18128,9 @@ msgstr ""
msgid "Package deleted successfully"
msgstr ""
+msgid "Package file size limits"
+msgstr ""
+
msgid "Package recipe already exists"
msgstr ""
@@ -17514,9 +18146,6 @@ msgstr ""
msgid "Package type must be PyPi"
msgstr ""
-msgid "Package was removed"
-msgstr ""
-
msgid "PackageRegistry|%{name} version %{version} was created %{datetime}"
msgstr ""
@@ -17658,12 +18287,18 @@ msgstr ""
msgid "PackageRegistry|NuGet Command"
msgstr ""
+msgid "PackageRegistry|Package Registry"
+msgstr ""
+
msgid "PackageRegistry|Pip Command"
msgstr ""
msgid "PackageRegistry|Pipeline %{link} triggered %{datetime} by %{author}"
msgstr ""
+msgid "PackageRegistry|Publish and share packages for a variety of common package managers. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "PackageRegistry|Published to the %{project} Package Registry %{datetime}"
msgstr ""
@@ -17763,6 +18398,9 @@ msgstr ""
msgid "Page not found"
msgstr ""
+msgid "Page settings"
+msgstr ""
+
msgid "Page was successfully deleted"
msgstr ""
@@ -17904,7 +18542,7 @@ msgstr ""
msgid "Paste issue link"
msgstr ""
-msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Don't use your private SSH key."
+msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Do not paste your private SSH key, as that can compromise your identity."
msgstr ""
msgid "Patch to apply"
@@ -17931,6 +18569,9 @@ msgstr ""
msgid "Pending"
msgstr ""
+msgid "Pending comments"
+msgstr ""
+
msgid "People without permission will never get a notification and won't be able to comment."
msgstr ""
@@ -18129,6 +18770,9 @@ msgstr ""
msgid "Pipelines|Build with confidence"
msgstr ""
+msgid "Pipelines|By revoking a trigger you will break any processes making use of it. Are you sure?"
+msgstr ""
+
msgid "Pipelines|CI Lint"
msgstr ""
@@ -18141,6 +18785,15 @@ msgstr ""
msgid "Pipelines|Continuous Integration can help catch bugs by running your tests automatically, while Continuous Deployment can help you deliver code to your product environment."
msgstr ""
+msgid "Pipelines|Copy trigger token"
+msgstr ""
+
+msgid "Pipelines|Description"
+msgstr ""
+
+msgid "Pipelines|Edit"
+msgstr ""
+
msgid "Pipelines|Get started with Pipelines"
msgstr ""
@@ -18156,15 +18809,27 @@ msgstr ""
msgid "Pipelines|It is recommended the code is reviewed thoroughly before running this pipeline with the parent project's CI resource."
msgstr ""
+msgid "Pipelines|Last Used"
+msgstr ""
+
msgid "Pipelines|Loading Pipelines"
msgstr ""
msgid "Pipelines|More Information"
msgstr ""
+msgid "Pipelines|No triggers have been created yet. Add one using the form above."
+msgstr ""
+
+msgid "Pipelines|Owner"
+msgstr ""
+
msgid "Pipelines|Project cache successfully reset."
msgstr ""
+msgid "Pipelines|Revoke"
+msgstr ""
+
msgid "Pipelines|Run Pipeline"
msgstr ""
@@ -18189,6 +18854,15 @@ msgstr ""
msgid "Pipelines|This project is not currently set up to run pipelines."
msgstr ""
+msgid "Pipelines|Token"
+msgstr ""
+
+msgid "Pipelines|Trigger user has insufficient permissions to project"
+msgstr ""
+
+msgid "Pipelines|invalid"
+msgstr ""
+
msgid "Pipelines|parent"
msgstr ""
@@ -18447,10 +19121,10 @@ msgstr ""
msgid "Please provide attributes to update"
msgstr ""
-msgid "Please refer to %{docs_url}"
+msgid "Please reach out if you have any questions and we'll be happy to assist."
msgstr ""
-msgid "Please retype the email address."
+msgid "Please refer to %{docs_url}"
msgstr ""
msgid "Please select"
@@ -18480,6 +19154,9 @@ msgstr ""
msgid "Please set a new password before proceeding."
msgstr ""
+msgid "Please share your feedback about %{featureName} %{linkStart}in this issue%{linkEnd} to help us improve the experience."
+msgstr ""
+
msgid "Please solve the reCAPTCHA"
msgstr ""
@@ -18783,6 +19460,9 @@ msgstr ""
msgid "Profiles| You are going to change the username %{currentUsernameBold} to %{newUsernameBold}. Profile and projects will be redirected to the %{newUsername} namespace but this redirect will expire once the %{currentUsername} namespace is registered by another user or group. Please update your Git repository remotes as soon as possible."
msgstr ""
+msgid "Profiles|%{provider} Active"
+msgstr ""
+
msgid "Profiles|@username"
msgstr ""
@@ -18834,7 +19514,7 @@ msgstr ""
msgid "Profiles|Commit email"
msgstr ""
-msgid "Profiles|Connect"
+msgid "Profiles|Connect %{provider}"
msgstr ""
msgid "Profiles|Connected Accounts"
@@ -18858,6 +19538,9 @@ msgstr ""
msgid "Profiles|Disconnect"
msgstr ""
+msgid "Profiles|Disconnect %{provider}"
+msgstr ""
+
msgid "Profiles|Do not show on profile"
msgstr ""
@@ -18882,7 +19565,7 @@ msgstr ""
msgid "Profiles|Full name"
msgstr ""
-msgid "Profiles|Give your individual key a title. This will be publically visible."
+msgid "Profiles|Give your individual key a title."
msgstr ""
msgid "Profiles|Include private contributions on my profile"
@@ -18972,7 +19655,7 @@ msgstr ""
msgid "Profiles|The maximum file size allowed is 200KB."
msgstr ""
-msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it?"
+msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it? It will be publicly visible."
msgstr ""
msgid "Profiles|This email will be displayed on your public profile"
@@ -19047,6 +19730,9 @@ msgstr ""
msgid "Profiles|You don't have access to delete this user."
msgstr ""
+msgid "Profiles|You must transfer ownership or delete groups you are an owner of before you can delete your account"
+msgstr ""
+
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
@@ -19635,6 +20321,9 @@ msgstr ""
msgid "ProjectTemplates|GitLab Cluster Management"
msgstr ""
+msgid "ProjectTemplates|Gitpod/Spring Petclinic"
+msgstr ""
+
msgid "ProjectTemplates|Go Micro"
msgstr ""
@@ -20244,6 +20933,9 @@ msgstr ""
msgid "Publish to status page"
msgstr ""
+msgid "Published"
+msgstr ""
+
msgid "Published on status page"
msgstr ""
@@ -20361,9 +21053,15 @@ msgstr ""
msgid "Quick range"
msgstr ""
+msgid "Quickly and easily edit multiple files in your project."
+msgstr ""
+
msgid "README"
msgstr ""
+msgid "Rails"
+msgstr ""
+
msgid "Rake Tasks Help"
msgstr ""
@@ -20483,10 +21181,13 @@ msgstr ""
msgid "Register Two-Factor Authenticator"
msgstr ""
-msgid "Register U2F device"
+msgid "Register Universal Two-Factor (U2F) Device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register WebAuthn Device"
+msgstr ""
+
+msgid "Register device"
msgstr ""
msgid "Register for GitLab"
@@ -20498,9 +21199,6 @@ msgstr ""
msgid "Register with two-factor app"
msgstr ""
-msgid "Registration"
-msgstr ""
-
msgid "Registration|Checkout"
msgstr ""
@@ -20617,9 +21315,6 @@ msgstr ""
msgid "Release|Something went wrong while saving the release details"
msgstr ""
-msgid "Remediated: needs review"
-msgstr ""
-
msgid "Remediations"
msgstr ""
@@ -20725,6 +21420,9 @@ msgstr ""
msgid "Remove priority"
msgstr ""
+msgid "Remove report"
+msgstr ""
+
msgid "Remove secondary node"
msgstr ""
@@ -20737,6 +21435,12 @@ msgstr ""
msgid "Remove time estimate"
msgstr ""
+msgid "Remove user & report"
+msgstr ""
+
+msgid "Remove user from group"
+msgstr ""
+
msgid "Removed"
msgstr ""
@@ -20818,9 +21522,6 @@ msgstr ""
msgid "Removes time estimate."
msgstr ""
-msgid "Removing license…"
-msgstr ""
-
msgid "Removing this group also removes all child projects, including archived projects, and their resources."
msgstr ""
@@ -20905,6 +21606,9 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
+msgid "Reported by %{reporter}"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -20991,6 +21695,27 @@ msgstr ""
msgid "Repositories"
msgstr ""
+msgid "Repositories Analytics"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download Historic Test Coverage Data"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download historic test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Historic Test Coverage Data is available in raw format (.csv) for further analysis."
+msgstr ""
+
+msgid "RepositoriesAnalytics|Test Code Coverage"
+msgstr ""
+
+msgid "RepositoriesAnalytics|There was an error fetching the projects."
+msgstr ""
+
msgid "Repository"
msgstr ""
@@ -21069,9 +21794,15 @@ msgstr ""
msgid "Request parameter %{param} is missing."
msgstr ""
+msgid "Request review from"
+msgstr ""
+
msgid "Request to link SAML account must be authorized"
msgstr ""
+msgid "Requested"
+msgstr ""
+
msgid "Requested %{time_ago}"
msgstr ""
@@ -21090,6 +21821,9 @@ msgstr ""
msgid "Requests to these domain(s)/address(es) on the local network will be allowed when local requests from hooks and services are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 or 127.0.0.0/28 are supported. Domain wildcards are not supported currently. Use comma, semicolon, or newline to separate multiple entries. The allowlist can hold a maximum of 1000 entries. Domains should use IDNA encoding. Ex: example.com, 192.168.1.1, 127.0.0.0/28, xn--itlab-j1a.com."
msgstr ""
+msgid "Require admin approval for new sign-ups"
+msgstr ""
+
msgid "Require all users in this group to setup Two-factor authentication"
msgstr ""
@@ -21217,9 +21951,6 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
-msgid "Resolved by %{resolvedByName}"
-msgstr ""
-
msgid "Resolves IP addresses once and uses them to submit requests"
msgstr ""
@@ -21339,6 +22070,14 @@ msgstr ""
msgid "ReviewApp|Enable Review App"
msgstr ""
+msgid "Reviewer"
+msgid_plural "%d Reviewers"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Reviewer(s)"
+msgstr ""
+
msgid "Reviewing"
msgstr ""
@@ -21378,6 +22117,9 @@ msgstr ""
msgid "Rook"
msgstr ""
+msgid "Ruby"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -21456,6 +22198,63 @@ msgstr ""
msgid "Runners page."
msgstr ""
+msgid "Runners|Active"
+msgstr ""
+
+msgid "Runners|Architecture"
+msgstr ""
+
+msgid "Runners|Can run untagged jobs"
+msgstr ""
+
+msgid "Runners|Description"
+msgstr ""
+
+msgid "Runners|Group"
+msgstr ""
+
+msgid "Runners|IP Address"
+msgstr ""
+
+msgid "Runners|Last contact"
+msgstr ""
+
+msgid "Runners|Locked to this project"
+msgstr ""
+
+msgid "Runners|Maximum job timeout"
+msgstr ""
+
+msgid "Runners|Name"
+msgstr ""
+
+msgid "Runners|Platform"
+msgstr ""
+
+msgid "Runners|Property Name"
+msgstr ""
+
+msgid "Runners|Protected"
+msgstr ""
+
+msgid "Runners|Revision"
+msgstr ""
+
+msgid "Runners|Shared"
+msgstr ""
+
+msgid "Runners|Specific"
+msgstr ""
+
+msgid "Runners|Tags"
+msgstr ""
+
+msgid "Runners|Value"
+msgstr ""
+
+msgid "Runners|Version"
+msgstr ""
+
msgid "Runners|You have used %{quotaUsed} out of %{quotaLimit} of your shared Runners pipeline minutes."
msgstr ""
@@ -21468,6 +22267,9 @@ msgstr ""
msgid "Runs a number of housekeeping tasks within the current repository, such as compressing file revisions and removing unreachable objects."
msgstr ""
+msgid "SAML"
+msgstr ""
+
msgid "SAML SSO"
msgstr ""
@@ -21519,6 +22321,9 @@ msgstr ""
msgid "Save"
msgstr ""
+msgid "Save %{name} size limits"
+msgstr ""
+
msgid "Save Changes"
msgstr ""
@@ -21549,9 +22354,6 @@ msgstr ""
msgid "Save space and find tags in the Container Registry more easily. Enable the cleanup policy to remove stale tags and keep only the ones you need."
msgstr ""
-msgid "Save template"
-msgstr ""
-
msgid "Save variables"
msgstr ""
@@ -21594,9 +22396,6 @@ msgstr ""
msgid "Scope"
msgstr ""
-msgid "Scope not supported with disabled 'users_search' feature!"
-msgstr ""
-
msgid "Scoped issue boards"
msgstr ""
@@ -21723,9 +22522,6 @@ msgstr ""
msgid "Search requirements"
msgstr ""
-msgid "Search results…"
-msgstr ""
-
msgid "Search users"
msgstr ""
@@ -21798,6 +22594,11 @@ msgid_plural "SearchResults|commits"
msgstr[0] ""
msgstr[1] ""
+msgid "SearchResults|epic"
+msgid_plural "SearchResults|epics"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "SearchResults|issue"
msgid_plural "SearchResults|issues"
msgstr[0] ""
@@ -21842,10 +22643,10 @@ msgstr ""
msgid "Seat Link is disabled, and cannot be configured through this form."
msgstr ""
-msgid "Seats currently in use"
+msgid "Seats usage data as of %{last_enqueue_time}"
msgstr ""
-msgid "Seats in license"
+msgid "Seats usage data is updated every day at 12:00pm UTC"
msgstr ""
msgid "Secondary"
@@ -21899,6 +22700,9 @@ msgstr ""
msgid "SecurityConfiguration|Available for on-demand DAST"
msgstr ""
+msgid "SecurityConfiguration|By default, all analyzers are applied in order to cover all languages across your project, and only run if the language is detected in the Merge Request."
+msgstr ""
+
msgid "SecurityConfiguration|Configure"
msgstr ""
@@ -21929,16 +22733,19 @@ msgstr ""
msgid "SecurityConfiguration|Manage"
msgstr ""
+msgid "SecurityConfiguration|More information"
+msgstr ""
+
msgid "SecurityConfiguration|Not enabled"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|Security Control"
+msgid "SecurityConfiguration|SAST Configuration"
msgstr ""
-msgid "SecurityConfiguration|See documentation"
+msgid "SecurityConfiguration|Security Control"
msgstr ""
msgid "SecurityConfiguration|Status"
@@ -21950,6 +22757,9 @@ msgstr ""
msgid "SecurityConfiguration|Using custom settings. You won't receive automatic updates on this variable. %{anchorStart}Restore to default%{anchorEnd}"
msgstr ""
+msgid "SecurityConfiguration|View history"
+msgstr ""
+
msgid "SecurityConfiguration|You can quickly enable all security scanning tools by enabling %{linkStart}Auto DevOps%{linkEnd}."
msgstr ""
@@ -22028,9 +22838,6 @@ msgstr ""
msgid "SecurityReports|Learn more about setting up your dashboard"
msgstr ""
-msgid "SecurityReports|Load more vulnerabilities"
-msgstr ""
-
msgid "SecurityReports|Monitor vulnerabilities in your code"
msgstr ""
@@ -22310,7 +23117,7 @@ msgstr ""
msgid "Select status"
msgstr ""
-msgid "Select strategy activation method"
+msgid "Select strategy activation method."
msgstr ""
msgid "Select subscription"
@@ -22325,7 +23132,7 @@ msgstr ""
msgid "Select the custom project template source group."
msgstr ""
-msgid "Select timeframe"
+msgid "Select the environment scope for this feature flag."
msgstr ""
msgid "Select timezone"
@@ -22574,6 +23381,9 @@ msgstr ""
msgid "Set iteration"
msgstr ""
+msgid "Set limit to 0 to allow any file size."
+msgstr ""
+
msgid "Set max session time for web terminal."
msgstr ""
@@ -22652,10 +23462,13 @@ msgstr ""
msgid "Set up a %{type} Runner manually"
msgstr ""
+msgid "Set up a hardware device as a second factor to sign in."
+msgstr ""
+
msgid "Set up assertions/attributes/claims (email, first_name, last_name) and NameID according to %{docsLinkStart}the documentation %{icon}%{docsLinkEnd}"
msgstr ""
-msgid "Set up new U2F device"
+msgid "Set up new device"
msgstr ""
msgid "Set up new password"
@@ -22724,6 +23537,9 @@ msgstr ""
msgid "Sets weight to %{weight}."
msgstr ""
+msgid "Setting this to 0 means using the system default timeout value."
+msgstr ""
+
msgid "Settings"
msgstr ""
@@ -22739,6 +23555,15 @@ msgstr ""
msgid "Severity"
msgstr ""
+msgid "SeverityWidget|Severity"
+msgstr ""
+
+msgid "SeverityWidget|Severity: %{severity}"
+msgstr ""
+
+msgid "SeverityWidget|There was an error while updating severity."
+msgstr ""
+
msgid "Shards (%{shards})"
msgstr ""
@@ -22784,6 +23609,9 @@ msgstr ""
msgid "Show all requirements."
msgstr ""
+msgid "Show all test cases."
+msgstr ""
+
msgid "Show archived projects"
msgstr ""
@@ -22796,6 +23624,9 @@ msgstr ""
msgid "Show comments"
msgstr ""
+msgid "Show comments on this file"
+msgstr ""
+
msgid "Show comments only"
msgstr ""
@@ -22841,6 +23672,12 @@ msgstr ""
msgid "Show parent subgroups"
msgstr ""
+msgid "Show the Closed list"
+msgstr ""
+
+msgid "Show the Open list"
+msgstr ""
+
msgid "Show whitespace changes"
msgstr ""
@@ -22884,9 +23721,6 @@ msgstr ""
msgid "Sidebar|Assign health status"
msgstr ""
-msgid "Sidebar|Change weight"
-msgstr ""
-
msgid "Sidebar|Health status"
msgstr ""
@@ -23070,6 +23904,9 @@ msgstr ""
msgid "Snippets|Add another file %{num}/%{total}"
msgstr ""
+msgid "Snippets|Authored %{time_ago} by %{author}"
+msgstr ""
+
msgid "Snippets|Delete file"
msgstr ""
@@ -23097,6 +23934,9 @@ msgstr ""
msgid "Solution"
msgstr ""
+msgid "Some changes are not shown"
+msgstr ""
+
msgid "Some child epics may be hidden due to applied filters"
msgstr ""
@@ -23463,6 +24303,12 @@ msgstr ""
msgid "Source (branch or tag)"
msgstr ""
+msgid "Source Branch"
+msgstr ""
+
+msgid "Source branch: %{source_branch_open}%{source_branch}%{source_branch_close}"
+msgstr ""
+
msgid "Source code"
msgstr ""
@@ -23628,9 +24474,6 @@ msgstr ""
msgid "Start and due date"
msgstr ""
-msgid "Start by choosing a group to see how your team is spending time. You can then drill down to the project level."
-msgstr ""
-
msgid "Start by choosing a group to start exploring the merge requests in that group. You can then proceed to filter by projects, labels, milestones and authors."
msgstr ""
@@ -23712,18 +24555,27 @@ msgstr ""
msgid "StaticSiteEditor|3. Assign a person to review and accept the merge request."
msgstr ""
+msgid "StaticSiteEditor|A link to view the merge request will appear once ready."
+msgstr ""
+
msgid "StaticSiteEditor|An error occurred while submitting your changes."
msgstr ""
msgid "StaticSiteEditor|Branch could not be created."
msgstr ""
+msgid "StaticSiteEditor|Copy update"
+msgstr ""
+
msgid "StaticSiteEditor|Could not commit the content changes."
msgstr ""
msgid "StaticSiteEditor|Could not create merge request."
msgstr ""
+msgid "StaticSiteEditor|Creating your merge request"
+msgstr ""
+
msgid "StaticSiteEditor|Incompatible file content"
msgstr ""
@@ -23745,6 +24597,9 @@ msgstr ""
msgid "StaticSiteEditor|View documentation"
msgstr ""
+msgid "StaticSiteEditor|You can set an assignee to get your changes reviewed and deployed once your merge request is created."
+msgstr ""
+
msgid "StaticSiteEditor|Your merge request has been created"
msgstr ""
@@ -23874,15 +24729,15 @@ msgstr ""
msgid "Submit %{humanized_resource_name}"
msgstr ""
-msgid "Submit Changes"
-msgstr ""
-
msgid "Submit a review"
msgstr ""
msgid "Submit as spam"
msgstr ""
+msgid "Submit changes"
+msgstr ""
+
msgid "Submit feedback"
msgstr ""
@@ -24036,6 +24891,9 @@ msgstr ""
msgid "Successfully deleted U2F device."
msgstr ""
+msgid "Successfully deleted WebAuthn device."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -24354,9 +25212,6 @@ msgstr ""
msgid "Template to append to all Service Desk issues"
msgstr ""
-msgid "Template was successfully saved."
-msgstr ""
-
msgid "Templates"
msgstr ""
@@ -24435,10 +25290,28 @@ msgid_plural "Test coverage: %d hits"
msgstr[0] ""
msgstr[1] ""
-msgid "Test failed."
+msgid "Test settings"
msgstr ""
-msgid "Test settings and save changes"
+msgid "TestCases|New Test Case"
+msgstr ""
+
+msgid "TestCases|New test case"
+msgstr ""
+
+msgid "TestCases|Search test cases"
+msgstr ""
+
+msgid "TestCases|Something went wrong while creating a test case."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching count of test cases."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching test cases list."
+msgstr ""
+
+msgid "TestCases|Submit test case"
msgstr ""
msgid "TestHooks|Ensure one of your projects has merge requests."
@@ -24504,6 +25377,9 @@ msgstr ""
msgid "Thank you for signing up for your free trial! You will get additional instructions in your inbox shortly."
msgstr ""
+msgid "Thank you for your business."
+msgstr ""
+
msgid "Thank you for your feedback!"
msgstr ""
@@ -24563,9 +25439,6 @@ msgstr ""
msgid "The URL to use for connecting to Elasticsearch. Use a comma-separated list to support clustering (e.g., \"http://localhost:9200, http://localhost:9201\")."
msgstr ""
-msgid "The Web IDE offers advanced syntax highlighting capabilities and more."
-msgstr ""
-
msgid "The X509 Certificate to use when mutual TLS is required to communicate with the external authorization service. If left blank, the server certificate is still validated when accessing over HTTPS."
msgstr ""
@@ -24676,6 +25549,9 @@ msgstr ""
msgid "The form contains the following error:"
msgstr ""
+msgid "The form contains the following warning:"
+msgstr ""
+
msgid "The global settings require you to enable Two-Factor Authentication for your account."
msgstr ""
@@ -24790,9 +25666,6 @@ msgstr ""
msgid "The private key to use when a client certificate is provided. This value is encrypted at rest."
msgstr ""
-msgid "The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The project can be accessed by any logged in user."
msgstr ""
@@ -24829,7 +25702,7 @@ msgstr ""
msgid "The remote repository is being updated..."
msgstr ""
-msgid "The repository can be commited to, and issues, comments and other entities can be created."
+msgid "The repository can be committed to, and issues, comments and other entities can be created."
msgstr ""
msgid "The repository for this project does not exist."
@@ -24883,9 +25756,6 @@ msgstr ""
msgid "The time taken by each data entry gathered by that stage."
msgstr ""
-msgid "The total stage shows the time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The update action will time out after %{number_of_minutes} minutes. For big repositories, use a clone/push combination."
msgstr ""
@@ -24949,6 +25819,9 @@ msgstr ""
msgid "There are no archived requirements"
msgstr ""
+msgid "There are no archived test cases"
+msgstr ""
+
msgid "There are no changes"
msgstr ""
@@ -24988,6 +25861,9 @@ msgstr ""
msgid "There are no open requirements"
msgstr ""
+msgid "There are no open test cases"
+msgstr ""
+
msgid "There are no packages yet"
msgstr ""
@@ -25000,6 +25876,9 @@ msgstr ""
msgid "There is a limit of %{ci_project_subscriptions_limit} subscriptions from or to a project."
msgstr ""
+msgid "There is already a To-Do for this design."
+msgstr ""
+
msgid "There is already a repository with that name on disk"
msgstr ""
@@ -25018,6 +25897,9 @@ msgstr ""
msgid "There was a problem communicating with your device."
msgstr ""
+msgid "There was a problem fetching branches."
+msgstr ""
+
msgid "There was a problem fetching groups."
msgstr ""
@@ -25246,9 +26128,15 @@ msgstr ""
msgid "This action can lead to data loss. To prevent accidental actions we ask you to confirm your intention."
msgstr ""
+msgid "This action cannot be undone, and will permanently delete the %{key} SSH key"
+msgstr ""
+
msgid "This action cannot be undone. You will lose the project's repository and all content: issues, merge requests, etc."
msgstr ""
+msgid "This action has been performed too many times. Try again later."
+msgstr ""
+
msgid "This action will %{strongOpen}permanently delete%{strongClose} %{codeOpen}%{project}%{codeClose} %{strongOpen}immediately%{strongClose}, including its repositories and all content: issues, merge requests, etc."
msgstr ""
@@ -25276,9 +26164,6 @@ msgstr ""
msgid "This board's scope is reduced"
msgstr ""
-msgid "This branch has changed since you started editing. Would you like to create a new branch?"
-msgstr ""
-
msgid "This chart could not be displayed"
msgstr ""
@@ -25405,15 +26290,9 @@ msgstr ""
msgid "This is a security log of important events involving your account."
msgstr ""
-msgid "This is the author's first Merge Request to this project."
-msgstr ""
-
msgid "This is the highest peak of users on your installation since the license started."
msgstr ""
-msgid "This is the maximum number of users that have existed at the same time since the license started. This is the minimum number of seats you will need to buy when you renew your license."
-msgstr ""
-
msgid "This is the number of currently active users on your installation, and this is the minimum number you need to purchase when you renew your license."
msgstr ""
@@ -25645,6 +26524,15 @@ msgstr ""
msgid "This user has no identities"
msgstr ""
+msgid "This user has previously committed to the %{name} project."
+msgstr ""
+
+msgid "This user has the %{access} role in the %{name} project."
+msgstr ""
+
+msgid "This user is the author of this %{noteable}."
+msgstr ""
+
msgid "This user will be the author of all events in the activity feed that are the result of an update, like new branches being created or new commits being pushed to existing branches."
msgstr ""
@@ -25675,6 +26563,9 @@ msgstr ""
msgid "Threat Monitoring"
msgstr ""
+msgid "ThreatMonitoring|All Environments"
+msgstr ""
+
msgid "ThreatMonitoring|Anomalous Requests"
msgstr ""
@@ -25702,9 +26593,6 @@ msgstr ""
msgid "ThreatMonitoring|Operations Per Second"
msgstr ""
-msgid "ThreatMonitoring|Overview"
-msgstr ""
-
msgid "ThreatMonitoring|Packet Activity"
msgstr ""
@@ -25723,6 +26611,9 @@ msgstr ""
msgid "ThreatMonitoring|Something went wrong, unable to fetch statistics"
msgstr ""
+msgid "ThreatMonitoring|Statistics"
+msgstr ""
+
msgid "ThreatMonitoring|The firewall is not installed or has been disabled. To view this data, ensure the web application firewall is installed and enabled for your cluster."
msgstr ""
@@ -26114,6 +27005,9 @@ msgstr ""
msgid "To update Snippets with multiple files, you must use the `files` parameter"
msgstr ""
+msgid "To use Gitpod you must first enable the feature in the integrations section of your %{user_prefs}."
+msgstr ""
+
msgid "To view all %{scannedResourcesCount} scanned URLs, please download the CSV file"
msgstr ""
@@ -26147,9 +27041,6 @@ msgstr ""
msgid "Toggle Sidebar"
msgstr ""
-msgid "Toggle all threads"
-msgstr ""
-
msgid "Toggle backtrace"
msgstr ""
@@ -26174,9 +27065,6 @@ msgstr ""
msgid "Toggle navigation"
msgstr ""
-msgid "Toggle project"
-msgstr ""
-
msgid "Toggle sidebar"
msgstr ""
@@ -26216,6 +27104,9 @@ msgstr ""
msgid "Too many projects enabled. You will need to manage them via the console or the API."
msgstr ""
+msgid "Too much data"
+msgstr ""
+
msgid "Topics (optional)"
msgstr ""
@@ -26234,6 +27125,9 @@ msgstr ""
msgid "Total cores (CPUs)"
msgstr ""
+msgid "Total days to completion"
+msgstr ""
+
msgid "Total issues"
msgstr ""
@@ -26330,6 +27224,9 @@ msgstr ""
msgid "Trending"
msgstr ""
+msgid "Trials|Create a new group to start your GitLab Gold trial."
+msgstr ""
+
msgid "Trials|Go back to GitLab"
msgstr ""
@@ -26339,6 +27236,15 @@ msgstr ""
msgid "Trials|You can always resume this process by selecting your avatar and choosing 'Start a Gold trial'"
msgstr ""
+msgid "Trials|You can apply your trial to a new group or an existing group."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group or your personal account."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group, an existing group, or your personal account."
+msgstr ""
+
msgid "Trials|You won't get a free trial right now but you can always resume this process by clicking on your avatar and choosing 'Start a free trial'"
msgstr ""
@@ -26408,6 +27314,9 @@ msgstr ""
msgid "Try using a different search term to find the file you are looking for."
msgstr ""
+msgid "Trying to communicate with your device. Plug it in (if needed) and press the button on the device now."
+msgstr ""
+
msgid "Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now."
msgstr ""
@@ -26495,6 +27404,12 @@ msgstr ""
msgid "URL or request ID"
msgstr ""
+msgid "USER %{user} WILL BE REMOVED! Are you sure?"
+msgstr ""
+
+msgid "USER WILL BE BLOCKED! Are you sure?"
+msgstr ""
+
msgid "UTC"
msgstr ""
@@ -26552,9 +27467,6 @@ msgstr ""
msgid "Unable to load the merge request widget. Try reloading the page."
msgstr ""
-msgid "Unable to resolve"
-msgstr ""
-
msgid "Unable to save iteration. Please try again"
msgstr ""
@@ -26603,6 +27515,9 @@ msgstr ""
msgid "Undo ignore"
msgstr ""
+msgid "Unexpected error"
+msgstr ""
+
msgid "Unfortunately, your email message to GitLab could not be processed."
msgstr ""
@@ -26636,6 +27551,9 @@ msgstr ""
msgid "Unknown response text"
msgstr ""
+msgid "Unless otherwise agreed to in writing with GitLab, by clicking \"Upload License\" you agree that your use of GitLab Software is subject to the %{eula_link_start}Terms of Service%{eula_link_end}."
+msgstr ""
+
msgid "Unlimited"
msgstr ""
@@ -27002,9 +27920,6 @@ msgstr ""
msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
msgstr ""
-msgid "Use a hardware device to add the second factor of authentication."
-msgstr ""
-
msgid "Use an one time password authenticator on your mobile device or computer to enable two-factor authentication (2FA)."
msgstr ""
@@ -27278,13 +28193,13 @@ msgstr ""
msgid "Users"
msgstr ""
-msgid "Users in License:"
+msgid "Users in License"
msgstr ""
-msgid "Users or groups set as approvers in the project's or merge request's settings."
+msgid "Users in License:"
msgstr ""
-msgid "Users outside of license"
+msgid "Users or groups set as approvers in the project's or merge request's settings."
msgstr ""
msgid "Users over License:"
@@ -27302,9 +28217,6 @@ msgstr ""
msgid "Users with a Guest role or those who don't belong to a Project or Group will not use a seat from your license."
msgstr ""
-msgid "Users with a Guest role or those who don't belong to any projects or groups don't count towards seats in use."
-msgstr ""
-
msgid "UsersSelect|%{name} + %{length} more"
msgstr ""
@@ -27344,9 +28256,6 @@ msgstr ""
msgid "Validations failed."
msgstr ""
-msgid "Validity"
-msgstr ""
-
msgid "Value"
msgstr ""
@@ -27365,6 +28274,9 @@ msgstr ""
msgid "Value Stream Name"
msgstr ""
+msgid "ValueStreamAnalyticsStage|We don't have enough data to show this stage."
+msgstr ""
+
msgid "ValueStreamAnalytics|%{days}d"
msgstr ""
@@ -27621,6 +28533,9 @@ msgstr ""
msgid "VisualReviewApp|Steps 1 and 2 (and sometimes 3) are performed once by the developer before requesting feedback. Steps 3 (if necessary), 4 is performed by the reviewer each time they perform a review."
msgstr ""
+msgid "Visualization"
+msgstr ""
+
msgid "Vulnerabilities"
msgstr ""
@@ -27648,34 +28563,31 @@ msgstr ""
msgid "VulnerabilityChart|Severity"
msgstr ""
-msgid "VulnerabilityManagement|A true-positive and will fix"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Change status"
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|Confirm"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Confirmed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
-msgstr ""
-
-msgid "VulnerabilityManagement|Detected %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|A true-positive and will fix"
msgstr ""
-msgid "VulnerabilityManagement|Dismiss"
+msgid "VulnerabilityManagement|Change status"
msgstr ""
-msgid "VulnerabilityManagement|Dismissed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
msgstr ""
-msgid "VulnerabilityManagement|Resolved"
+msgid "VulnerabilityManagement|Detected"
msgstr ""
-msgid "VulnerabilityManagement|Resolved %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Needs triage"
msgstr ""
msgid "VulnerabilityManagement|Something went wrong while trying to delete the comment. Please try again later."
@@ -27726,6 +28638,9 @@ msgstr ""
msgid "Vulnerability|%{scannerName} (version %{scannerVersion})"
msgstr ""
+msgid "Vulnerability|Activity"
+msgstr ""
+
msgid "Vulnerability|Class"
msgstr ""
@@ -27738,6 +28653,9 @@ msgstr ""
msgid "Vulnerability|Description"
msgstr ""
+msgid "Vulnerability|Detected"
+msgstr ""
+
msgid "Vulnerability|Evidence"
msgstr ""
@@ -27801,6 +28719,9 @@ msgstr ""
msgid "Warning: Displaying this diagram might cause performance issues on this page."
msgstr ""
+msgid "We are currently unable to fetch data for the pipeline header."
+msgstr ""
+
msgid "We are currently unable to fetch data for this graph."
msgstr ""
@@ -27840,6 +28761,12 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
+msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
+msgstr ""
+
+msgid "We would like to inform you that your subscription GitLab Enterprise Edition %{plan_name} is nearing its user limit. You have %{active_user_count} active users, which is almost at the user limit of %{maximum_user_count}."
+msgstr ""
+
msgid "We've found no vulnerabilities"
msgstr ""
@@ -27855,6 +28782,12 @@ msgstr ""
msgid "Web terminal"
msgstr ""
+msgid "WebAuthn Devices (%{length})"
+msgstr ""
+
+msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
+msgstr ""
+
msgid "WebIDE|Merge request"
msgstr ""
@@ -27993,15 +28926,9 @@ msgstr ""
msgid "Welcome to the guided GitLab tour"
msgstr ""
-msgid "Welcome to your Issue Board!"
-msgstr ""
-
msgid "Welcome to your issue board!"
msgstr ""
-msgid "We’ve been making changes to %{featureName} and we’d love your feedback %{linkStart}in this issue%{linkEnd} to help us improve the experience."
-msgstr ""
-
msgid "What are you searching for?"
msgstr ""
@@ -28020,6 +28947,9 @@ msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
msgstr ""
+msgid "When enabled, any user visiting %{host} and creating an account will have to be explicitly approved by the admin before they can login. This setting is effective only if sign-ups are enabled."
+msgstr ""
+
msgid "When enabled, any user visiting %{host} will be able to create an account."
msgstr ""
@@ -28244,6 +29174,9 @@ msgstr ""
msgid "With requirements, you can set criteria to check your products against."
msgstr ""
+msgid "With test cases, you can define conditions for your project to meet in determining quality"
+msgstr ""
+
msgid "Withdraw Access Request"
msgstr ""
@@ -28259,6 +29192,9 @@ msgstr ""
msgid "Workflow Help"
msgstr ""
+msgid "Would you like to create a new branch?"
+msgstr ""
+
msgid "Write"
msgstr ""
@@ -28280,6 +29216,9 @@ msgstr ""
msgid "Wrong extern UID provided. Make sure Auth0 is configured correctly."
msgstr ""
+msgid "YYYY-MM-DD"
+msgstr ""
+
msgid "Yes"
msgstr ""
@@ -28337,7 +29276,7 @@ msgstr ""
msgid "You are going to remove the fork relationship from %{project_full_name}. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "You are going to transfer %{project_full_name} to another owner. Are you ABSOLUTELY sure?"
+msgid "You are going to transfer %{project_full_name} to another namespace. Are you ABSOLUTELY sure?"
msgstr ""
msgid "You are going to turn off the confidentiality. This means %{strongStart}everyone%{strongEnd} will be able to see and leave a comment on this %{issuableType}."
@@ -28397,9 +29336,6 @@ msgstr ""
msgid "You can always edit this later"
msgstr ""
-msgid "You can apply your Trial to your Personal account or create a New Group."
-msgstr ""
-
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings"
msgstr ""
@@ -28421,12 +29357,18 @@ msgstr ""
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
+msgid "You can find more information about GitLab subscriptions in %{subscriptions_doc_link}."
+msgstr ""
+
msgid "You can generate an access token scoped to this project for each application to use the GitLab API."
msgstr ""
msgid "You can get started by cloning the repository or start adding files to it with one of the following options."
msgstr ""
+msgid "You can group test cases using labels. To learn about the future direction of this feature, visit %{linkStart}Quality Management direction page%{linkEnd}."
+msgstr ""
+
msgid "You can invite a new member to %{project_name} or invite another group."
msgstr ""
@@ -28442,6 +29384,9 @@ msgstr ""
msgid "You can notify the app / group or a project by sending them an email notification"
msgstr ""
+msgid "You can now close this window."
+msgstr ""
+
msgid "You can now export your security dashboard to a CSV report."
msgstr ""
@@ -28490,9 +29435,6 @@ msgstr ""
msgid "You can test your .gitlab-ci.yml in %{linkStart}CI Lint%{linkEnd}."
msgstr ""
-msgid "You can try again using %{begin_link}basic search%{end_link}"
-msgstr ""
-
msgid "You cannot access the raw file. Please wait a minute."
msgstr ""
@@ -28544,6 +29486,9 @@ msgstr ""
msgid "You don't have any U2F devices registered yet."
msgstr ""
+msgid "You don't have any WebAuthn devices registered yet."
+msgstr ""
+
msgid "You don't have any active chat names."
msgstr ""
@@ -28631,6 +29576,9 @@ msgstr ""
msgid "You must accept our Terms of Service and privacy policy in order to register an account"
msgstr ""
+msgid "You must be logged in to search across all of GitLab"
+msgstr ""
+
msgid "You must disassociate %{domain} from all clusters it is attached to before deletion."
msgstr ""
@@ -28670,7 +29618,7 @@ msgstr ""
msgid "You need to be logged in."
msgstr ""
-msgid "You need to register a two-factor authentication app before you can set up a U2F device."
+msgid "You need to register a two-factor authentication app before you can set up a device."
msgstr ""
msgid "You need to set terms to be enforced"
@@ -28688,6 +29636,9 @@ msgstr ""
msgid "You reached %{usage_in_percent} of %{namespace_name}'s storage capacity (%{used_storage} of %{storage_limit})"
msgstr ""
+msgid "You successfully declined the invitation"
+msgstr ""
+
msgid "You tried to fork %{link_to_the_project} but it failed for the following reason:"
msgstr ""
@@ -28853,10 +29804,13 @@ msgstr ""
msgid "Your U2F device did not send a valid JSON response."
msgstr ""
-msgid "Your U2F device needs to be set up. Plug it in (if not already) and click the button on the left."
+msgid "Your U2F device was registered!"
msgstr ""
-msgid "Your U2F device was registered!"
+msgid "Your WebAuthn device did not send a valid JSON response."
+msgstr ""
+
+msgid "Your WebAuthn device was registered!"
msgstr ""
msgid "Your access request to the %{source_type} has been withdrawn."
@@ -28880,6 +29834,9 @@ msgstr ""
msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
msgstr ""
+msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
+msgstr ""
+
msgid "Your changes can be committed to %{branch_name} because a merge request is open."
msgstr ""
@@ -28916,6 +29873,12 @@ msgstr ""
msgid "Your deployment services will be broken, you will need to manually fix the services after renaming."
msgstr ""
+msgid "Your device is not compatible with GitLab. Please try another device"
+msgstr ""
+
+msgid "Your device needs to be set up. Plug it in (if needed) and click the button on the left."
+msgstr ""
+
msgid "Your device was successfully set up! Give it a name and register it with the GitLab server."
msgstr ""
@@ -29029,9 +29992,6 @@ msgstr[1] ""
msgid "access:"
msgstr ""
-msgid "activated"
-msgstr ""
-
msgid "added %{created_at_timeago}"
msgstr ""
@@ -29104,9 +30064,21 @@ msgstr ""
msgid "by %{user}"
msgstr ""
+msgid "cannot be a date in the past"
+msgstr ""
+
msgid "cannot be changed if a personal project has container registry tags."
msgstr ""
+msgid "cannot be changed if shared runners are enabled"
+msgstr ""
+
+msgid "cannot be enabled because parent group does not allow it"
+msgstr ""
+
+msgid "cannot be enabled because parent group has shared Runners disabled"
+msgstr ""
+
msgid "cannot be enabled unless all domains have TLS certificates"
msgstr ""
@@ -29152,7 +30124,7 @@ msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about SAST %{linkEndTag}"
msgstr ""
-msgid "ciReport|%{linkStartTag}Learn more about Secret Scanning %{linkEndTag}"
+msgid "ciReport|%{linkStartTag}Learn more about Secret Detection %{linkEndTag}"
msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about codequality reports %{linkEndTag}"
@@ -29467,9 +30439,6 @@ msgstr ""
msgid "error"
msgstr ""
-msgid "error code:"
-msgstr ""
-
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr ""
@@ -29491,6 +30460,9 @@ msgstr ""
msgid "failed to dismiss associated finding(id=%{finding_id}): %{message}"
msgstr ""
+msgid "failed to revert associated finding(id=%{finding_id}) to detected"
+msgstr ""
+
msgid "file"
msgid_plural "files"
msgstr[0] ""
@@ -30033,6 +31005,9 @@ msgstr ""
msgid "must be a root namespace"
msgstr ""
+msgid "must be a valid IPv4 or IPv6 address"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -30069,6 +31044,9 @@ msgstr ""
msgid "no expiration"
msgstr ""
+msgid "no name set"
+msgstr ""
+
msgid "no one can merge"
msgstr ""
@@ -30247,9 +31225,6 @@ msgstr ""
msgid "security Reports|There was an error creating the merge request"
msgstr ""
-msgid "settings saved, but not activated"
-msgstr ""
-
msgid "severity|Critical"
msgstr ""
@@ -30376,9 +31351,6 @@ msgstr ""
msgid "toggle collapse"
msgstr ""
-msgid "toggle dropdown"
-msgstr ""
-
msgid "triggered"
msgstr ""
@@ -30406,6 +31378,9 @@ msgstr ""
msgid "user avatar"
msgstr ""
+msgid "user preferences"
+msgstr ""
+
msgid "username"
msgstr ""
diff --git a/locale/ar_SA/gitlab.po b/locale/ar_SA/gitlab.po
index 1f59b345d0a..ed9ee601d86 100644
--- a/locale/ar_SA/gitlab.po
+++ b/locale/ar_SA/gitlab.po
@@ -14,7 +14,10 @@ msgstr ""
"X-Crowdin-Language: ar\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 6\n"
-"PO-Revision-Date: 2020-09-04 23:06\n"
+"PO-Revision-Date: 2020-10-02 18:46\n"
+
+msgid " %{project_name}#%{issue_iid} &middot; opened %{issue_created} by %{author}"
+msgstr ""
msgid " %{start} to %{end}"
msgstr ""
@@ -82,6 +85,24 @@ msgstr ""
msgid "\"el\" parameter is required for createInstance()"
msgstr ""
+msgid "%d Approval"
+msgid_plural "%d Approvals"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+msgstr[5] ""
+
+msgid "%d Package"
+msgid_plural "%d Packages"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+msgstr[5] ""
+
msgid "%d Scanned URL"
msgid_plural "%d Scanned URLs"
msgstr[0] ""
@@ -193,6 +214,15 @@ msgstr[5] ""
msgid "%d commits"
msgstr ""
+msgid "%d completed issue"
+msgid_plural "%d completed issues"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+msgstr[5] ""
+
msgid "%d contribution"
msgid_plural "%d contributions"
msgstr[0] ""
@@ -211,6 +241,15 @@ msgstr[3] ""
msgstr[4] ""
msgstr[5] ""
+msgid "%d day until tags are automatically removed"
+msgid_plural "%d days until tags are automatically removed"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+msgstr[5] ""
+
msgid "%d error"
msgid_plural "%d errors"
msgstr[0] ""
@@ -373,6 +412,24 @@ msgstr[3] ""
msgstr[4] ""
msgstr[5] ""
+msgid "%d open issue"
+msgid_plural "%d open issues"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+msgstr[5] ""
+
+msgid "%d pending comment"
+msgid_plural "%d pending comments"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+msgstr[5] ""
+
msgid "%d personal project will be removed and cannot be restored."
msgid_plural "%d personal projects will be removed and cannot be restored."
msgstr[0] ""
@@ -400,6 +457,15 @@ msgstr[3] ""
msgstr[4] ""
msgstr[5] ""
+msgid "%d project selected"
+msgid_plural "%d projects selected"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+msgstr[5] ""
+
msgid "%d request with warnings"
msgid_plural "%d requests with warnings"
msgstr[0] ""
@@ -436,6 +502,15 @@ msgstr[3] ""
msgstr[4] ""
msgstr[5] ""
+msgid "%d tag per image name"
+msgid_plural "%d tags per image name"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+msgstr[5] ""
+
msgid "%d unassigned issue"
msgid_plural "%d unassigned issues"
msgstr[0] ""
@@ -472,6 +547,15 @@ msgstr[3] ""
msgstr[4] ""
msgstr[5] ""
+msgid "%d warning found:"
+msgid_plural "%d warnings found:"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+msgstr[5] ""
+
msgid "%s additional commit has been omitted to prevent performance issues."
msgid_plural "%s additional commits have been omitted to prevent performance issues."
msgstr[0] ""
@@ -514,6 +598,9 @@ msgstr ""
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr ""
+msgid "%{completedCount} completed weight"
+msgstr ""
+
msgid "%{completedWeight} of %{totalWeight} weight completed"
msgstr ""
@@ -574,18 +661,12 @@ msgstr[3] ""
msgstr[4] ""
msgstr[5] ""
-msgid "%{count} pending comment"
-msgid_plural "%{count} pending comments"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-msgstr[4] ""
-msgstr[5] ""
-
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
+msgid "%{count} total weight"
+msgstr ""
+
msgid "%{dashboard_path} could not be found."
msgstr ""
@@ -640,6 +721,9 @@ msgstr ""
msgid "%{group_name} uses group managed accounts. You need to create a new GitLab account which will be managed by %{group_name}."
msgstr ""
+msgid "%{group_name}&%{epic_iid} &middot; opened %{epic_created} by %{author}"
+msgstr ""
+
msgid "%{host} sign-in from new location"
msgstr ""
@@ -652,7 +736,7 @@ msgstr ""
msgid "%{issuableType} will be removed! Are you sure?"
msgstr ""
-msgid "%{issuesSize} issues with a limit of %{maxIssueCount}"
+msgid "%{issuesCount} issues with a limit of %{maxIssueCount}"
msgstr ""
msgid "%{issuesSize} with a limit of %{maxIssueCount}"
@@ -685,7 +769,7 @@ msgstr ""
msgid "%{labelStart}Namespace:%{labelEnd} %{namespace}"
msgstr ""
-msgid "%{labelStart}Report Type:%{labelEnd} %{reportType}"
+msgid "%{labelStart}Scan Type:%{labelEnd} %{reportType}"
msgstr ""
msgid "%{labelStart}Scanner:%{labelEnd} %{scanner}"
@@ -910,9 +994,6 @@ msgstr[3] ""
msgstr[4] ""
msgstr[5] ""
-msgid "%{service_title} %{message}."
-msgstr ""
-
msgid "%{size} GiB"
msgstr ""
@@ -1021,6 +1102,12 @@ msgstr ""
msgid "%{timebox_name} should belong either to a project or a group."
msgstr ""
+msgid "%{timebox_type} does not support burnup charts"
+msgstr ""
+
+msgid "%{timebox_type} must have a start and due date"
+msgstr ""
+
msgid "%{title} %{operator} %{threshold}"
msgstr ""
@@ -1045,7 +1132,7 @@ msgstr ""
msgid "%{total} open issue weight"
msgstr ""
-msgid "%{total} open issues"
+msgid "%{total} warnings found: showing first %{warningsDisplayed}"
msgstr ""
msgid "%{usage_ping_link_start}Learn more%{usage_ping_link_end} about what information is shared with GitLab Inc."
@@ -1078,9 +1165,6 @@ msgstr ""
msgid "&lt; 1 hour"
msgstr ""
-msgid "&lt;no name set&gt;"
-msgstr ""
-
msgid "&lt;no scopes selected&gt;"
msgstr ""
@@ -1111,6 +1195,9 @@ msgstr ""
msgid "'%{name}' Value Stream created"
msgstr ""
+msgid "'%{name}' Value Stream deleted"
+msgstr ""
+
msgid "'%{name}' stage already exists"
msgstr ""
@@ -1174,6 +1261,9 @@ msgstr ""
msgid "+ %{numberOfHiddenAssignees} more"
msgstr ""
+msgid "+ %{numberOfHiddenReviewers} more"
+msgstr ""
+
msgid "+%d more"
msgid_plural "+%d more"
msgstr[0] ""
@@ -1258,6 +1348,15 @@ msgstr[3] ""
msgstr[4] ""
msgstr[5] ""
+msgid "1 Issue"
+msgid_plural "%d Issues"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+msgstr[5] ""
+
msgid "1 closed issue"
msgid_plural "%{issues} closed issues"
msgstr[0] ""
@@ -1285,6 +1384,15 @@ msgstr[3] ""
msgstr[4] ""
msgstr[5] ""
+msgid "1 deploy key"
+msgid_plural "%d deploy keys"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+msgstr[5] ""
+
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1423,6 +1531,9 @@ msgstr ""
msgid ":%{startLine} to %{endLine}"
msgstr ""
+msgid "A %{incident_docs_start}modified issue%{incident_docs_end} to guide the resolution of incidents."
+msgstr ""
+
msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr ""
@@ -1435,6 +1546,9 @@ msgstr ""
msgid "A GitBook site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
+msgid "A Gitpod configured Webapplication in Spring and Java"
+msgstr ""
+
msgid "A Hexo site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
@@ -1606,9 +1720,15 @@ msgstr ""
msgid "Access expiration date"
msgstr ""
+msgid "Access expires"
+msgstr ""
+
msgid "Access forbidden. Check your access level."
msgstr ""
+msgid "Access granted"
+msgstr ""
+
msgid "Access requests"
msgstr ""
@@ -1618,6 +1738,9 @@ msgstr ""
msgid "Access to Pages websites are controlled based on the user's membership to a given project. By checking this box, users will be required to be logged in to have access to all Pages websites in your instance."
msgstr ""
+msgid "AccessDropdown|Deploy Keys"
+msgstr ""
+
msgid "AccessDropdown|Groups"
msgstr ""
@@ -1735,12 +1858,6 @@ msgstr ""
msgid "Active Sessions"
msgstr ""
-msgid "Active Users:"
-msgstr ""
-
-msgid "Active users"
-msgstr ""
-
msgid "Activity"
msgstr ""
@@ -1912,9 +2029,6 @@ msgstr ""
msgid "Add label(s)"
msgstr ""
-msgid "Add license"
-msgstr ""
-
msgid "Add list"
msgstr ""
@@ -2089,21 +2203,51 @@ msgstr ""
msgid "AdminArea|Bots"
msgstr ""
+msgid "AdminArea|Components"
+msgstr ""
+
msgid "AdminArea|Developer"
msgstr ""
+msgid "AdminArea|Features"
+msgstr ""
+
+msgid "AdminArea|Groups: %{number_of_groups}"
+msgstr ""
+
msgid "AdminArea|Guest"
msgstr ""
msgid "AdminArea|Included Free in license"
msgstr ""
+msgid "AdminArea|Latest groups"
+msgstr ""
+
+msgid "AdminArea|Latest projects"
+msgstr ""
+
+msgid "AdminArea|Latest users"
+msgstr ""
+
msgid "AdminArea|Maintainer"
msgstr ""
+msgid "AdminArea|New group"
+msgstr ""
+
+msgid "AdminArea|New project"
+msgstr ""
+
+msgid "AdminArea|New user"
+msgstr ""
+
msgid "AdminArea|Owner"
msgstr ""
+msgid "AdminArea|Projects: %{number_of_projects}"
+msgstr ""
+
msgid "AdminArea|Reporter"
msgstr ""
@@ -2131,6 +2275,9 @@ msgstr ""
msgid "AdminArea|Users without a Group and Project"
msgstr ""
+msgid "AdminArea|Users: %{number_of_users}"
+msgstr ""
+
msgid "AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running."
msgstr ""
@@ -2149,9 +2296,6 @@ msgstr ""
msgid "AdminProjects|Delete Project %{projectName}?"
msgstr ""
-msgid "AdminProjects|Delete project"
-msgstr ""
-
msgid "AdminSettings|Apply integration settings to all Projects"
msgstr ""
@@ -2389,21 +2533,30 @@ msgstr ""
msgid "AdminUsers|Without projects"
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 ""
msgid "AdminUsers|You cannot remove your own admin rights."
msgstr ""
+msgid "AdminUsers|You must transfer ownership or delete the groups owned by this user before you can delete their account"
+msgstr ""
+
msgid "Administration"
msgstr ""
msgid "Advanced"
msgstr ""
+msgid "Advanced Search"
+msgstr ""
+
+msgid "Advanced Search with Elasticsearch"
+msgstr ""
+
msgid "Advanced Settings"
msgstr ""
@@ -2485,6 +2638,9 @@ msgstr ""
msgid "AlertManagement|Edit"
msgstr ""
+msgid "AlertManagement|Environment"
+msgstr ""
+
msgid "AlertManagement|Events"
msgstr ""
@@ -2497,6 +2653,9 @@ msgstr ""
msgid "AlertManagement|Issue"
msgstr ""
+msgid "AlertManagement|Key"
+msgstr ""
+
msgid "AlertManagement|Low"
msgstr ""
@@ -2590,6 +2749,9 @@ msgstr ""
msgid "AlertManagement|Unknown"
msgstr ""
+msgid "AlertManagement|Value"
+msgstr ""
+
msgid "AlertManagement|View alerts in Opsgenie"
msgstr ""
@@ -2749,6 +2911,9 @@ msgstr ""
msgid "All projects"
msgstr ""
+msgid "All projects selected"
+msgstr ""
+
msgid "All security scans are enabled because %{linkStart}Auto DevOps%{linkEnd} is enabled on this project"
msgstr ""
@@ -2836,6 +3001,9 @@ msgstr ""
msgid "Almost there"
msgstr ""
+msgid "Already blocked"
+msgstr ""
+
msgid "Also called \"Issuer\" or \"Relying party trust identifier\""
msgstr ""
@@ -2890,6 +3058,9 @@ msgstr ""
msgid "An error has occurred"
msgstr ""
+msgid "An error occured while making the changes: %{error}"
+msgstr ""
+
msgid "An error occurred adding a draft to the thread."
msgstr ""
@@ -2917,12 +3088,6 @@ msgstr ""
msgid "An error occurred when toggling the notification subscription"
msgstr ""
-msgid "An error occurred when trying to resolve a comment. Please try again."
-msgstr ""
-
-msgid "An error occurred when trying to resolve a discussion. Please try again."
-msgstr ""
-
msgid "An error occurred when updating the issue weight"
msgstr ""
@@ -2938,12 +3103,6 @@ msgstr ""
msgid "An error occurred while checking group path. Please refresh and try again."
msgstr ""
-msgid "An error occurred while committing your changes."
-msgstr ""
-
-msgid "An error occurred while creating the list. Please try again."
-msgstr ""
-
msgid "An error occurred while decoding the file."
msgstr ""
@@ -3016,25 +3175,19 @@ msgstr ""
msgid "An error occurred while fetching the Service Desk address."
msgstr ""
-msgid "An error occurred while fetching the board issues. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the board lists. Please reload the page."
msgstr ""
msgid "An error occurred while fetching the board lists. Please try again."
msgstr ""
-msgid "An error occurred while fetching the board swimlanes. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the builds."
msgstr ""
msgid "An error occurred while fetching the job log."
msgstr ""
-msgid "An error occurred while fetching the job trace."
+msgid "An error occurred while fetching the job logs."
msgstr ""
msgid "An error occurred while fetching the job."
@@ -3181,9 +3334,6 @@ msgstr ""
msgid "An error occurred while saving assignees"
msgstr ""
-msgid "An error occurred while saving the template. Please check if the template exists."
-msgstr ""
-
msgid "An error occurred while searching for milestones"
msgstr ""
@@ -3202,10 +3352,10 @@ msgstr ""
msgid "An error occurred while updating approvers"
msgstr ""
-msgid "An error occurred while updating the comment"
+msgid "An error occurred while updating labels."
msgstr ""
-msgid "An error occurred while updating the list. Please try again."
+msgid "An error occurred while updating the comment"
msgstr ""
msgid "An error occurred while validating group path"
@@ -3259,6 +3409,9 @@ msgstr ""
msgid "An unknown error occurred while loading this graph."
msgstr ""
+msgid "An unknown error occurred."
+msgstr ""
+
msgid "Analytics"
msgstr ""
@@ -3292,10 +3445,10 @@ msgstr ""
msgid "Any"
msgstr ""
-msgid "Any Author"
+msgid "Any %{header}"
msgstr ""
-msgid "Any Status"
+msgid "Any Author"
msgstr ""
msgid "Any branch"
@@ -3349,6 +3502,9 @@ msgstr ""
msgid "Application ID"
msgstr ""
+msgid "Application limits saved successfully"
+msgstr ""
+
msgid "Application settings saved successfully"
msgstr ""
@@ -3574,6 +3730,9 @@ msgstr ""
msgid "Are you sure you want to close this blocked issue?"
msgstr ""
+msgid "Are you sure you want to delete \"%{name}\" Value Stream?"
+msgstr ""
+
msgid "Are you sure you want to delete %{name}?"
msgstr ""
@@ -3583,6 +3742,9 @@ msgstr ""
msgid "Are you sure you want to delete this %{typeOfComment}?"
msgstr ""
+msgid "Are you sure you want to delete this SSH key?"
+msgstr ""
+
msgid "Are you sure you want to delete this board?"
msgstr ""
@@ -3607,6 +3769,15 @@ msgstr ""
msgid "Are you sure you want to erase this build?"
msgstr ""
+msgid "Are you sure you want to import %d repository?"
+msgid_plural "Are you sure you want to import %d repositories?"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+msgstr[5] ""
+
msgid "Are you sure you want to lose unsaved changes?"
msgstr ""
@@ -3616,15 +3787,15 @@ msgstr ""
msgid "Are you sure you want to merge immediately?"
msgstr ""
-msgid "Are you sure you want to permanently delete this license?"
-msgstr ""
-
msgid "Are you sure you want to re-deploy this environment?"
msgstr ""
msgid "Are you sure you want to regenerate the public key? You will have to update the public key on the remote server before mirroring will work again."
msgstr ""
+msgid "Are you sure you want to reindex?"
+msgstr ""
+
msgid "Are you sure you want to remove %{group_name}?"
msgstr ""
@@ -3652,6 +3823,9 @@ msgstr ""
msgid "Are you sure you want to revoke this nickname?"
msgstr ""
+msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
+msgstr ""
+
msgid "Are you sure you want to stop this environment?"
msgstr ""
@@ -3673,6 +3847,9 @@ msgstr ""
msgid "Are you sure? The device will be signed out of GitLab and all remember me tokens revoked."
msgstr ""
+msgid "Are you sure? This will invalidate your registered applications and U2F / WebAuthn devices."
+msgstr ""
+
msgid "Are you sure? This will invalidate your registered applications and U2F devices."
msgstr ""
@@ -3691,9 +3868,6 @@ msgstr ""
msgid "Artifacts"
msgstr ""
-msgid "As U2F devices are only supported by a few browsers, we require that you set up a two-factor authentication app before a U2F device. That way you'll always be able to log in - even when you're using an unsupported browser."
-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 ""
@@ -3895,6 +4069,9 @@ msgstr ""
msgid "AuditLogs|Target"
msgstr ""
+msgid "AuditLogs|This month"
+msgstr ""
+
msgid "AuditLogs|User Events"
msgstr ""
@@ -3934,6 +4111,9 @@ msgstr ""
msgid "Authentication via U2F device failed."
msgstr ""
+msgid "Authentication via WebAuthn device failed."
+msgstr ""
+
msgid "Author"
msgstr ""
@@ -4201,15 +4381,6 @@ msgstr ""
msgid "BambooService|You must set up automatic revision labeling and a repository trigger in Bamboo."
msgstr ""
-msgid "BatchComments|Delete all pending comments"
-msgstr ""
-
-msgid "BatchComments|Discard review?"
-msgstr ""
-
-msgid "BatchComments|You're about to discard your review which will delete all of your pending comments. The deleted comments %{strong_start}cannot%{strong_end} be restored."
-msgstr ""
-
msgid "Be careful. Changing the project's namespace can have unintended side effects."
msgstr ""
@@ -4231,6 +4402,9 @@ msgstr ""
msgid "Bi-weekly code coverage"
msgstr ""
+msgid "Billable Users:"
+msgstr ""
+
msgid "Billing"
msgstr ""
@@ -4240,7 +4414,7 @@ msgstr ""
msgid "BillingPlans|@%{user_name} you are currently using the %{plan_name} plan."
msgstr ""
-msgid "BillingPlans|Congratulations, your new trial is activated"
+msgid "BillingPlans|Congratulations, your free trial is activated."
msgstr ""
msgid "BillingPlans|If you would like to downgrade your plan please contact %{support_link_start}Customer Support%{support_link_end}."
@@ -4303,6 +4477,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Block user"
+msgstr ""
+
msgid "Blocked"
msgstr ""
@@ -4318,31 +4495,37 @@ msgstr ""
msgid "Blog"
msgstr ""
-msgid "Board name"
-msgstr ""
-
msgid "Board scope"
msgstr ""
msgid "Board scope affects which issues are displayed for anyone who visits this board"
msgstr ""
-msgid "BoardBlankState|Add default lists"
+msgid "Boards"
msgstr ""
-msgid "BoardBlankState|Add the following default lists to your Issue Board with one click:"
+msgid "Boards and Board Lists"
msgstr ""
-msgid "BoardBlankState|Nevermind, I'll use my own"
+msgid "Boards|An error occurred while creating the issue. Please try again."
msgstr ""
-msgid "BoardBlankState|Starting out with the default set of lists will get you right on the way to making the most of your board."
+msgid "Boards|An error occurred while creating the list. Please try again."
msgstr ""
-msgid "Boards"
+msgid "Boards|An error occurred while fetching issues. Please reload the page."
msgstr ""
-msgid "Boards and Board Lists"
+msgid "Boards|An error occurred while fetching the board issues. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching the board swimlanes. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while moving the issue. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while updating the list. Please try again."
msgstr ""
msgid "Boards|Collapse"
@@ -4369,7 +4552,7 @@ msgstr ""
msgid "Branch %{branch_name} was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr ""
-msgid "Branch has changed"
+msgid "Branch changed"
msgstr ""
msgid "Branch is already taken"
@@ -4675,6 +4858,9 @@ msgstr ""
msgid "CLOSED (MOVED)"
msgstr ""
+msgid "CODEOWNERS rule violation"
+msgstr ""
+
msgid "CONTRIBUTING"
msgstr ""
@@ -4705,9 +4891,6 @@ msgstr ""
msgid "Can't create snippet: %{err}"
msgstr ""
-msgid "Can't edit as source branch was deleted"
-msgstr ""
-
msgid "Can't fetch content for the blob: %{err}"
msgstr ""
@@ -4720,9 +4903,6 @@ msgstr ""
msgid "Can't load mermaid module: %{err}"
msgstr ""
-msgid "Can't remove group members without group managed account"
-msgstr ""
-
msgid "Can't scan the code?"
msgstr ""
@@ -4765,6 +4945,9 @@ msgstr ""
msgid "Cannot create the abuse report. This user has been blocked."
msgstr ""
+msgid "Cannot enable shared runners because parent group does not allow it"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -4870,6 +5053,15 @@ msgstr ""
msgid "Change your password or recover your current one"
msgstr ""
+msgid "ChangeReviewer|Reviewer changed from %{old} to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Reviewer changed to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Unassigned"
+msgstr ""
+
msgid "ChangeTypeActionLabel|Pick into branch"
msgstr ""
@@ -4909,6 +5101,9 @@ msgstr ""
msgid "Changes the title to \"%{title_param}\"."
msgstr ""
+msgid "Changes were successfully made."
+msgstr ""
+
msgid "Changes won't take place until the index is %{link_start}recreated%{link_end}."
msgstr ""
@@ -5314,6 +5509,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove variable"
+msgstr ""
+
msgid "CiVariables|Remove variable row"
msgstr ""
@@ -5392,9 +5590,6 @@ msgstr ""
msgid "Clear due date"
msgstr ""
-msgid "Clear input"
-msgstr ""
-
msgid "Clear recent searches"
msgstr ""
@@ -5443,6 +5638,9 @@ msgstr ""
msgid "Client authentication key password"
msgstr ""
+msgid "Client request timeout"
+msgstr ""
+
msgid "Clients"
msgstr ""
@@ -5527,6 +5725,27 @@ msgstr ""
msgid "Cluster type must be specificed for Stages::ClusterEndpointInserter"
msgstr ""
+msgid "ClusterAgents|Configuration"
+msgstr ""
+
+msgid "ClusterAgents|Connect your cluster with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate Kubernetes with a GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Name"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Agent also requires %{linkStart}enabling the Agent Server%{linkEnd}"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Kubernetes Agent allows an Infrastructure as Code, GitOps approach to integrating Kubernetes clusters with GitLab. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "ClusterAgent|This feature is only available for premium plans"
msgstr ""
@@ -5596,10 +5815,10 @@ msgstr ""
msgid "ClusterIntegration|All installed applications and related resources"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster."
+msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{linkStart}More information%{linkEnd}"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{startLink}More information%{endLink}"
+msgid "ClusterIntegration|Allow GitLab to manage namespaces and service accounts for this cluster."
msgstr ""
msgid "ClusterIntegration|Alternatively, "
@@ -5620,6 +5839,9 @@ msgstr ""
msgid "ClusterIntegration|An error occurred while trying to fetch zone machine types: %{error}"
msgstr ""
+msgid "ClusterIntegration|An unknown error occurred while attempting to connect to Kubernetes."
+msgstr ""
+
msgid "ClusterIntegration|Any project namespaces"
msgstr ""
@@ -5635,6 +5857,9 @@ msgstr ""
msgid "ClusterIntegration|Authenticate with Amazon Web Services"
msgstr ""
+msgid "ClusterIntegration|Authentication Error"
+msgstr ""
+
msgid "ClusterIntegration|Base domain"
msgstr ""
@@ -5653,13 +5878,22 @@ msgstr ""
msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}security group %{externalLinkIcon} %{endLink} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
+msgid "ClusterIntegration|Check your CA certificate"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}subnets %{externalLinkIcon} %{endLink} in your VPC where your worker nodes will run."
+msgid "ClusterIntegration|Check your cluster status"
msgstr ""
-msgid "ClusterIntegration|Choose the worker node %{startLink}instance type %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Check your token"
+msgstr ""
+
+msgid "ClusterIntegration|Choose the %{linkStart}security group %{linkEnd} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
+msgstr ""
+
+msgid "ClusterIntegration|Choose the %{linkStart}subnets %{linkEnd} in your VPC where your worker nodes will run."
+msgstr ""
+
+msgid "ClusterIntegration|Choose the worker node %{linkStart}instance type%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Choose which applications to install on your Kubernetes cluster."
@@ -5671,10 +5905,7 @@ msgstr ""
msgid "ClusterIntegration|Clear cluster cache"
msgstr ""
-msgid "ClusterIntegration|Clear the local cache of namespace and service accounts. This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
-msgstr ""
-
-msgid "ClusterIntegration|Cluster being created"
+msgid "ClusterIntegration|Clear the local cache of namespace and service accounts."
msgstr ""
msgid "ClusterIntegration|Cluster management project (alpha)"
@@ -5686,15 +5917,21 @@ msgstr ""
msgid "ClusterIntegration|Cluster_applications artifact too big. Maximum allowable size: %{human_size}"
msgstr ""
-msgid "ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters."
+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|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}"
+msgid "ClusterIntegration|Clusters connected with a certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Connect cluster with certificate"
msgstr ""
msgid "ClusterIntegration|Connect existing cluster"
msgstr ""
+msgid "ClusterIntegration|Connection Error"
+msgstr ""
+
msgid "ClusterIntegration|Copy API URL"
msgstr ""
@@ -5770,6 +6007,12 @@ msgstr ""
msgid "ClusterIntegration|Deletes all GitLab resources attached to this cluster during removal"
msgstr ""
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared."
+msgstr ""
+
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared. %{linkStart}More information%{linkEnd}"
+msgstr ""
+
msgid "ClusterIntegration|Did you know?"
msgstr ""
@@ -5839,6 +6082,9 @@ msgstr ""
msgid "ClusterIntegration|Fluentd is an open source data collector, which lets you unify the data collection and consumption for a better use and understanding of data. It requires at least one of the following logs to be successfully installed."
msgstr ""
+msgid "ClusterIntegration|GitLab Agent managed clusters"
+msgstr ""
+
msgid "ClusterIntegration|GitLab Container Network Policies"
msgstr ""
@@ -5851,6 +6097,12 @@ msgstr ""
msgid "ClusterIntegration|GitLab Runner connects to the repository and executes CI/CD jobs, pushing results back and deploying applications to production."
msgstr ""
+msgid "ClusterIntegration|GitLab failed to authenticate."
+msgstr ""
+
+msgid "ClusterIntegration|GitLab failed to connect to the cluster."
+msgstr ""
+
msgid "ClusterIntegration|GitLab-managed cluster"
msgstr ""
@@ -5872,6 +6124,9 @@ msgstr ""
msgid "ClusterIntegration|Group cluster"
msgstr ""
+msgid "ClusterIntegration|HTTP Error"
+msgstr ""
+
msgid "ClusterIntegration|Helm Tiller"
msgstr ""
@@ -5905,7 +6160,10 @@ msgstr ""
msgid "ClusterIntegration|Instance type"
msgstr ""
-msgid "ClusterIntegration|Integrate Kubernetes cluster automation"
+msgid "ClusterIntegration|Integrate Kubernetes with a cluster certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Integrate with a cluster certificate"
msgstr ""
msgid "ClusterIntegration|Issuer Email"
@@ -5941,9 +6199,6 @@ msgstr ""
msgid "ClusterIntegration|Knative extends Kubernetes to provide a set of middleware components that are essential to build modern, source-centric, and container-based applications that can run anywhere: on premises, in the cloud, or even in a third-party data center."
msgstr ""
-msgid "ClusterIntegration|Kubernetes cluster"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes cluster is being created..."
msgstr ""
@@ -5956,9 +6211,6 @@ msgstr ""
msgid "ClusterIntegration|Kubernetes clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr ""
-msgid "ClusterIntegration|Kubernetes clusters can be used to deploy applications and to provide Review Apps for this project"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes version"
msgstr ""
@@ -5971,7 +6223,7 @@ msgstr ""
msgid "ClusterIntegration|Learn more about %{help_link_start}zones%{help_link_end}."
msgstr ""
-msgid "ClusterIntegration|Learn more about %{startLink}Regions %{externalLinkIcon}%{endLink}."
+msgid "ClusterIntegration|Learn more about %{linkStart}Regions%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Learn more about Kubernetes"
@@ -6016,12 +6268,18 @@ msgstr ""
msgid "ClusterIntegration|Machine type"
msgstr ""
+msgid "ClusterIntegration|Make sure your API endpoint is correct"
+msgstr ""
+
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create Kubernetes clusters"
msgstr ""
msgid "ClusterIntegration|Manage your Kubernetes cluster by visiting %{provider_link}"
msgstr ""
+msgid "ClusterIntegration|Namespace per environment"
+msgstr ""
+
msgid "ClusterIntegration|No IAM Roles found"
msgstr ""
@@ -6067,6 +6325,9 @@ msgstr ""
msgid "ClusterIntegration|No zones matched your search"
msgstr ""
+msgid "ClusterIntegration|Node calculations use the Kubernetes Metrics API. Make sure your cluster has metrics installed"
+msgstr ""
+
msgid "ClusterIntegration|Number of nodes"
msgstr ""
@@ -6109,6 +6370,9 @@ msgstr ""
msgid "ClusterIntegration|RBAC-enabled cluster"
msgstr ""
+msgid "ClusterIntegration|Read our %{linkStart}help page%{linkEnd} on Kubernetes cluster integration."
+msgstr ""
+
msgid "ClusterIntegration|Read our %{link_start}help page%{link_end} on Kubernetes cluster integration."
msgstr ""
@@ -6211,7 +6475,7 @@ msgstr ""
msgid "ClusterIntegration|Select a VPC to choose a subnet"
msgstr ""
-msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{linkStart}Amazon Web Services %{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select a network to choose a subnetwork"
@@ -6244,7 +6508,7 @@ msgstr ""
msgid "ClusterIntegration|Select project to choose zone"
msgstr ""
-msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select zone"
@@ -6334,9 +6598,18 @@ msgstr ""
msgid "ClusterIntegration|There was a problem authenticating with your cluster. Please ensure your CA Certificate and Token are valid."
msgstr ""
+msgid "ClusterIntegration|There was an HTTP error when connecting to your cluster."
+msgstr ""
+
msgid "ClusterIntegration|This account must have permissions to create a Kubernetes cluster in the %{link_to_container_project} specified below"
msgstr ""
+msgid "ClusterIntegration|This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
+msgstr ""
+
+msgid "ClusterIntegration|This is necessary to clear existing environment-namespace associations from clusters previously managed by GitLab."
+msgstr ""
+
msgid "ClusterIntegration|This option will allow you to install applications on RBAC clusters."
msgstr ""
@@ -6361,9 +6634,21 @@ msgstr ""
msgid "ClusterIntegration|To use a new project, first create one on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}."
msgstr ""
+msgid "ClusterIntegration|Troubleshooting tips:"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Authenticate"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Connect"
+msgstr ""
+
msgid "ClusterIntegration|Uninstall %{appTitle}"
msgstr ""
+msgid "ClusterIntegration|Unknown Error"
+msgstr ""
+
msgid "ClusterIntegration|Update %{appTitle}"
msgstr ""
@@ -6424,7 +6709,7 @@ msgstr ""
msgid "ClusterIntegration|Your cluster API is unreachable. Please ensure your API URL is correct."
msgstr ""
-msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Zone"
@@ -6544,6 +6829,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse all threads"
+msgstr ""
+
msgid "Collapse approvers"
msgstr ""
@@ -6697,7 +6985,7 @@ msgstr ""
msgid "Commit…"
msgstr ""
-msgid "Company"
+msgid "Community forum"
msgstr ""
msgid "Company name"
@@ -6706,6 +6994,9 @@ msgstr ""
msgid "Compare"
msgstr ""
+msgid "Compare %{oldCommitId}...%{newCommitId}"
+msgstr ""
+
msgid "Compare Git revisions"
msgstr ""
@@ -6721,6 +7012,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare submodule commit revisions"
+msgstr ""
+
msgid "Compare with previous version"
msgstr ""
@@ -6856,6 +7150,9 @@ msgstr ""
msgid "Configure the way a user creates a new account."
msgstr ""
+msgid "Configure which lists are shown for anyone who visits this board"
+msgstr ""
+
msgid "Confirm"
msgstr ""
@@ -7093,6 +7390,9 @@ msgstr[5] ""
msgid "ContainerRegistry|Set cleanup policy"
msgstr ""
+msgid "ContainerRegistry|Some tags were not deleted"
+msgstr ""
+
msgid "ContainerRegistry|Something went wrong while fetching the cleanup policy."
msgstr ""
@@ -7132,6 +7432,9 @@ msgstr ""
msgid "ContainerRegistry|Tags with names matching this regex pattern will %{italicStart}expire:%{italicEnd}"
msgstr ""
+msgid "ContainerRegistry|The cleanup policy timed out before it could delete all tags. An administrator can %{adminLinkStart}manually run cleanup now%{adminLinkEnd} or you can wait for the cleanup policy to automatically run again. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "ContainerRegistry|The last tag related to this image was recently removed. This empty image and any associated data will be automatically removed as part of the regular Garbage Collection process. If you have any questions, contact your administrator."
msgstr ""
@@ -7264,6 +7567,9 @@ msgstr ""
msgid "Contributions per group member"
msgstr ""
+msgid "Contributor"
+msgstr ""
+
msgid "Contributors"
msgstr ""
@@ -7393,6 +7699,9 @@ msgstr ""
msgid "Could not change HEAD: branch '%{branch}' does not exist"
msgstr ""
+msgid "Could not commit. An unexpected error occurred."
+msgstr ""
+
msgid "Could not connect to FogBugz, check your URL"
msgstr ""
@@ -7432,6 +7741,9 @@ msgstr ""
msgid "Could not find iteration"
msgstr ""
+msgid "Could not load instance counts. Please refresh the page to try again."
+msgstr ""
+
msgid "Could not remove the trigger."
msgstr ""
@@ -7456,10 +7768,10 @@ msgstr ""
msgid "Could not save prometheus manual configuration"
msgstr ""
-msgid "Could not udpdate wiki page"
+msgid "Could not update the LDAP settings"
msgstr ""
-msgid "Could not update the LDAP settings"
+msgid "Could not update wiki page"
msgstr ""
msgid "Could not upload your designs as one or more files uploaded are not supported."
@@ -8125,6 +8437,9 @@ msgstr ""
msgid "DastProfiles|Are you sure you want to delete this profile?"
msgstr ""
+msgid "DastProfiles|Could not create site validation token. Please refresh the page, or try again later."
+msgstr ""
+
msgid "DastProfiles|Could not create the scanner profile. Please try again."
msgstr ""
@@ -8149,6 +8464,12 @@ msgstr ""
msgid "DastProfiles|Could not fetch site profiles. Please refresh the page, or try again later."
msgstr ""
+msgid "DastProfiles|Could not retrieve site validation status. Please refresh the page, or try again later."
+msgstr ""
+
+msgid "DastProfiles|Could not update the scanner profile. Please try again."
+msgstr ""
+
msgid "DastProfiles|Could not update the site profile. Please try again."
msgstr ""
@@ -8164,7 +8485,7 @@ msgstr ""
msgid "DastProfiles|Download validation text file"
msgstr ""
-msgid "DastProfiles|Edit feature will come soon. Please create a new profile if changes needed"
+msgid "DastProfiles|Edit scanner profile"
msgstr ""
msgid "DastProfiles|Edit site profile"
@@ -8197,6 +8518,9 @@ msgstr ""
msgid "DastProfiles|No profiles created yet"
msgstr ""
+msgid "DastProfiles|Passive"
+msgstr ""
+
msgid "DastProfiles|Please enter a valid URL format, ex: http://www.example.com/home"
msgstr ""
@@ -8212,6 +8536,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan mode"
+msgstr ""
+
msgid "DastProfiles|Scanner Profile"
msgstr ""
@@ -8251,10 +8578,10 @@ msgstr ""
msgid "DastProfiles|Text file validation"
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
+msgid "DastProfiles|The maximum number of minutes allowed for the spider to traverse the site."
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the spider to traverse the site."
+msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
msgstr ""
msgid "DastProfiles|Validate"
@@ -8287,6 +8614,9 @@ msgstr ""
msgid "Date picker"
msgstr ""
+msgid "Date range"
+msgstr ""
+
msgid "Date range cannot exceed %{maxDateRange} days."
msgstr ""
@@ -8311,6 +8641,9 @@ msgstr ""
msgid "Days to merge"
msgstr ""
+msgid "Dear Administrator,"
+msgstr ""
+
msgid "Debug"
msgstr ""
@@ -8422,12 +8755,18 @@ msgstr ""
msgid "Delete"
msgstr ""
+msgid "Delete %{name}"
+msgstr ""
+
msgid "Delete Comment"
msgstr ""
msgid "Delete Snippet"
msgstr ""
+msgid "Delete Value Stream"
+msgstr ""
+
msgid "Delete account"
msgstr ""
@@ -8449,9 +8788,6 @@ msgstr ""
msgid "Delete label: %{label_name} ?"
msgstr ""
-msgid "Delete license"
-msgstr ""
-
msgid "Delete list"
msgstr ""
@@ -8527,15 +8863,6 @@ msgstr ""
msgid "Deleting a project places it into a read-only state until %{date}, at which point the project will be permanently deleted. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "Deleting the license failed."
-msgstr ""
-
-msgid "Deleting the license failed. The license was not found."
-msgstr ""
-
-msgid "Deleting the license failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "Deleting the project will delete its repository and all related resources including issues, merge requests etc."
msgstr ""
@@ -9055,7 +9382,10 @@ msgstr ""
msgid "DesignManagement|The maximum number of designs allowed to be uploaded is %{upload_limit}. Please try again."
msgstr ""
-msgid "DesignManagement|To upload designs, you'll need to enable LFS. %{requirements_link_start}More information%{requirements_link_end}"
+msgid "DesignManagement|There was an error moving your designs. Please upload your designs below."
+msgstr ""
+
+msgid "DesignManagement|To upload designs, you'll need to enable LFS and have admin enable hashed storage. %{requirements_link_start}More information%{requirements_link_end}"
msgstr ""
msgid "DesignManagement|Unresolve thread"
@@ -9067,6 +9397,9 @@ msgstr ""
msgid "DesignManagement|Upload skipped."
msgstr ""
+msgid "DesignManagement|Your designs are being copied and are on their way… Please refresh to update."
+msgstr ""
+
msgid "DesignManagement|and %{moreCount} more."
msgstr ""
@@ -9124,6 +9457,9 @@ msgstr ""
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
+msgid "Direct member"
+msgstr ""
+
msgid "Direction"
msgstr ""
@@ -9172,9 +9508,6 @@ msgstr ""
msgid "Discard draft"
msgstr ""
-msgid "Discard review"
-msgstr ""
-
msgid "DiscordService|Discord Notifications"
msgstr ""
@@ -9247,10 +9580,10 @@ msgstr ""
msgid "Dismiss Merge Request promotion"
msgstr ""
-msgid "Dismiss Selected"
+msgid "Dismiss Value Stream Analytics introduction box"
msgstr ""
-msgid "Dismiss Value Stream Analytics introduction box"
+msgid "Dismiss selected"
msgstr ""
msgid "Dismiss trial promotion"
@@ -9301,9 +9634,6 @@ msgstr ""
msgid "Documents reindexed: %{processed_documents} (%{percentage}%%)"
msgstr ""
-msgid "Doing"
-msgstr ""
-
msgid "Domain"
msgstr ""
@@ -9499,9 +9829,6 @@ msgstr ""
msgid "Edit environment"
msgstr ""
-msgid "Edit file"
-msgstr ""
-
msgid "Edit files in the editor and commit changes here"
msgstr ""
@@ -9514,6 +9841,12 @@ msgstr ""
msgid "Edit identity for %{user_name}"
msgstr ""
+msgid "Edit in Web IDE"
+msgstr ""
+
+msgid "Edit in single-file editor"
+msgstr ""
+
msgid "Edit issues"
msgstr ""
@@ -9541,10 +9874,10 @@ msgstr ""
msgid "Editing"
msgstr ""
-msgid "Elasticsearch"
+msgid "Elasticsearch AWS IAM credentials"
msgstr ""
-msgid "Elasticsearch AWS IAM credentials"
+msgid "Elasticsearch HTTP client timeout value in seconds."
msgstr ""
msgid "Elasticsearch indexing restrictions"
@@ -9553,9 +9886,6 @@ msgstr ""
msgid "Elasticsearch indexing started"
msgstr ""
-msgid "Elasticsearch integration. Elasticsearch AWS IAM."
-msgstr ""
-
msgid "Elasticsearch reindexing is already in progress"
msgstr ""
@@ -9583,9 +9913,6 @@ msgstr ""
msgid "Email Notification"
msgstr ""
-msgid "Email address"
-msgstr ""
-
msgid "Email could not be sent"
msgstr ""
@@ -9649,6 +9976,9 @@ msgstr ""
msgid "Emails sent from Service Desk will have this name"
msgstr ""
+msgid "Emails sent to %{email} will still be supported"
+msgstr ""
+
msgid "Emails separated by comma"
msgstr ""
@@ -9682,9 +10012,18 @@ msgstr ""
msgid "Enable"
msgstr ""
+msgid "Enable %{link_start}Gitpod%{link_end} integration to launch a development environment in your browser directly from GitLab."
+msgstr ""
+
msgid "Enable Auto DevOps"
msgstr ""
+msgid "Enable Gitpod"
+msgstr ""
+
+msgid "Enable Gitpod?"
+msgstr ""
+
msgid "Enable HTML emails"
msgstr ""
@@ -9814,9 +10153,6 @@ msgstr ""
msgid "Encountered an error while rendering: %{err}"
msgstr ""
-msgid "End date"
-msgstr ""
-
msgid "Ends at (UTC)"
msgstr ""
@@ -9976,7 +10312,7 @@ msgstr ""
msgid "EnvironmentsDashboard|The environments dashboard provides a summary of each project's environments' status, including pipeline and alert statuses."
msgstr ""
-msgid "EnvironmentsDashboard|This dashboard displays a maximum of 7 projects and 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
+msgid "EnvironmentsDashboard|This dashboard displays 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
msgstr ""
msgid "Environments|An error occurred while canceling the auto stop, please try again"
@@ -10297,6 +10633,9 @@ msgstr ""
msgid "Error deleting project. Check logs for error details."
msgstr ""
+msgid "Error fetching burnup chart data"
+msgstr ""
+
msgid "Error fetching diverging counts for branches. Please try again."
msgstr ""
@@ -10375,6 +10714,9 @@ msgstr ""
msgid "Error occurred when saving assignees"
msgstr ""
+msgid "Error occurred when saving reviewers"
+msgstr ""
+
msgid "Error occurred when toggling the notification subscription"
msgstr ""
@@ -10627,10 +10969,13 @@ msgstr ""
msgid "Expand all"
msgstr ""
-msgid "Expand approvers"
+msgid "Expand all files"
msgstr ""
-msgid "Expand dropdown"
+msgid "Expand all threads"
+msgstr ""
+
+msgid "Expand approvers"
msgstr ""
msgid "Expand milestones"
@@ -10801,6 +11146,9 @@ msgstr ""
msgid "Failed to create Merge Request. Please try again."
msgstr ""
+msgid "Failed to create To-Do for the design."
+msgstr ""
+
msgid "Failed to create a branch for this issue. Please try again."
msgstr ""
@@ -10840,6 +11188,12 @@ msgstr ""
msgid "Failed to load authors. Please try again."
msgstr ""
+msgid "Failed to load branches. Please try again."
+msgstr ""
+
+msgid "Failed to load deploy keys."
+msgstr ""
+
msgid "Failed to load emoji list."
msgstr ""
@@ -10855,6 +11209,9 @@ msgstr ""
msgid "Failed to load groups & users."
msgstr ""
+msgid "Failed to load groups, users and deploy keys."
+msgstr ""
+
msgid "Failed to load labels. Please try again."
msgstr ""
@@ -10864,6 +11221,12 @@ msgstr ""
msgid "Failed to load related branches"
msgstr ""
+msgid "Failed to load sidebar confidential toggle"
+msgstr ""
+
+msgid "Failed to load sidebar lock status"
+msgstr ""
+
msgid "Failed to load stacktrace."
msgstr ""
@@ -10891,6 +11254,9 @@ msgstr ""
msgid "Failed to publish issue on status page."
msgstr ""
+msgid "Failed to remove To-Do for the design."
+msgstr ""
+
msgid "Failed to remove a Zoom meeting"
msgstr ""
@@ -10933,6 +11299,9 @@ msgstr ""
msgid "Failed to signing using smartcard authentication"
msgstr ""
+msgid "Failed to toggle To-Do for the design."
+msgstr ""
+
msgid "Failed to update branch!"
msgstr ""
@@ -11050,7 +11419,7 @@ msgstr ""
msgid "FeatureFlags|Edit User List"
msgstr ""
-msgid "FeatureFlags|Enable features for specific users and specific environments by defining feature flag strategies."
+msgid "FeatureFlags|Enable features for specific users and environments by configuring feature flag strategies."
msgstr ""
msgid "FeatureFlags|Environment Spec"
@@ -11110,7 +11479,7 @@ msgstr ""
msgid "FeatureFlags|Include additional user IDs"
msgstr ""
-msgid "FeatureFlags|Install a %{docs_link_anchored_start}compatible client library%{docs_link_anchored_end} and specify the API URL, application name, and instance ID during the configuration setup. %{docs_link_start}More Information%{docs_link_end}"
+msgid "FeatureFlags|Install a %{docsLinkAnchoredStart}compatible client library%{docsLinkAnchoredEnd} and specify the API URL, application name, and instance ID during the configuration setup. %{docsLinkStart}More Information%{docsLinkEnd}"
msgstr ""
msgid "FeatureFlags|Instance ID"
@@ -11122,6 +11491,9 @@ msgstr ""
msgid "FeatureFlags|Loading feature flags"
msgstr ""
+msgid "FeatureFlags|Loading user lists"
+msgstr ""
+
msgid "FeatureFlags|More information"
msgstr ""
@@ -11140,7 +11512,7 @@ msgstr ""
msgid "FeatureFlags|New feature flag"
msgstr ""
-msgid "FeatureFlags|New list"
+msgid "FeatureFlags|New user list"
msgstr ""
msgid "FeatureFlags|Percent of users"
@@ -11179,6 +11551,9 @@ msgstr ""
msgid "FeatureFlags|There was an error fetching the feature flags."
msgstr ""
+msgid "FeatureFlags|There was an error fetching the user lists."
+msgstr ""
+
msgid "FeatureFlags|There was an error retrieving user lists"
msgstr ""
@@ -11194,6 +11569,9 @@ msgstr ""
msgid "FeatureFlags|User List"
msgstr ""
+msgid "FeatureFlags|User Lists"
+msgstr ""
+
msgid "FeatureFlag|List"
msgstr ""
@@ -11221,15 +11599,6 @@ msgstr ""
msgid "Fetching incoming email"
msgstr ""
-msgid "Fetching licenses failed."
-msgstr ""
-
-msgid "Fetching licenses failed. The request endpoint was not found."
-msgstr ""
-
-msgid "Fetching licenses failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "File"
msgstr ""
@@ -11332,12 +11701,21 @@ msgstr ""
msgid "Filter by status"
msgstr ""
+msgid "Filter by test cases that are currently archived."
+msgstr ""
+
+msgid "Filter by test cases that are currently opened."
+msgstr ""
+
msgid "Filter by two-factor authentication"
msgstr ""
msgid "Filter by user"
msgstr ""
+msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
+msgstr ""
+
msgid "Filter pipelines"
msgstr ""
@@ -11353,7 +11731,7 @@ msgstr ""
msgid "Filter results..."
msgstr ""
-msgid "Filter your projects by name"
+msgid "Filter your repositories by name"
msgstr ""
msgid "Filter..."
@@ -11362,7 +11740,7 @@ msgstr ""
msgid "Find File"
msgstr ""
-msgid "Find bugs in your code with coverage-guided fuzzing"
+msgid "Find bugs in your code with coverage-guided fuzzing."
msgstr ""
msgid "Find by path"
@@ -11389,9 +11767,6 @@ msgstr ""
msgid "Finish editing this message first!"
msgstr ""
-msgid "Finish review"
-msgstr ""
-
msgid "Finish setting up your dedicated account for %{group_name}."
msgstr ""
@@ -11461,6 +11836,9 @@ msgstr ""
msgid "Footer message"
msgstr ""
+msgid "For a faster browsing experience, some files are collapsed by default."
+msgstr ""
+
msgid "For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
@@ -11470,6 +11848,9 @@ msgstr ""
msgid "For more info, read the documentation."
msgstr ""
+msgid "For more information on how the number of active users is calculated, see the %{self_managed_subscriptions_doc_link} documentation."
+msgstr ""
+
msgid "For more information, go to the "
msgstr ""
@@ -11608,6 +11989,9 @@ msgstr ""
msgid "Generate new token"
msgstr ""
+msgid "Generic package file size in bytes"
+msgstr ""
+
msgid "Geo"
msgstr ""
@@ -11869,6 +12253,9 @@ msgstr ""
msgid "Geo|Please refer to Geo Troubleshooting."
msgstr ""
+msgid "Geo|Primary node"
+msgstr ""
+
msgid "Geo|Project"
msgstr ""
@@ -11911,6 +12298,9 @@ msgstr ""
msgid "Geo|Review replication status, and resynchronize and reverify items with the primary node."
msgstr ""
+msgid "Geo|Secondary node"
+msgstr ""
+
msgid "Geo|Status"
msgstr ""
@@ -11950,6 +12340,9 @@ msgstr ""
msgid "Geo|URL must be a valid url (ex: https://gitlab.com)"
msgstr ""
+msgid "Geo|Undefined"
+msgstr ""
+
msgid "Geo|Unknown state"
msgstr ""
@@ -12025,10 +12418,16 @@ msgstr ""
msgid "GitHub import"
msgstr ""
+msgid "GitLab"
+msgstr ""
+
msgid "GitLab / Unsubscribe"
msgstr ""
-msgid "GitLab Enterprise Edition %{plan}"
+msgid "GitLab API"
+msgstr ""
+
+msgid "GitLab Billing Team."
msgstr ""
msgid "GitLab Group Runners can execute code for all the projects in this group."
@@ -12040,12 +12439,18 @@ msgstr ""
msgid "GitLab Issue"
msgstr ""
+msgid "GitLab Pages"
+msgstr ""
+
msgid "GitLab Service Desk is a simple way to allow people to create issues in your GitLab instance without needing their own user account. It provides a unique email address for end users to create issues in a project, and replies can be sent either through the GitLab interface or by email. End users will only see the thread through email."
msgstr ""
msgid "GitLab Shared Runners execute code of different projects on the same Runner unless you configure GitLab Runner Autoscale with MaxBuilds 1 (which it is on GitLab.com)."
msgstr ""
+msgid "GitLab Shell"
+msgstr ""
+
msgid "GitLab Support Bot"
msgstr ""
@@ -12055,7 +12460,7 @@ msgstr ""
msgid "GitLab User"
msgstr ""
-msgid "GitLab allows you to continue using your license even if you exceed the number of seats you purchased. You will be required to pay for these seats when you renew your license."
+msgid "GitLab Workhorse"
msgstr ""
msgid "GitLab commit"
@@ -12223,6 +12628,21 @@ msgstr ""
msgid "Gitlab Pages"
msgstr ""
+msgid "Gitpod"
+msgstr ""
+
+msgid "Gitpod|Add the URL to your Gitpod instance configured to read your GitLab projects."
+msgstr ""
+
+msgid "Gitpod|Enable Gitpod integration"
+msgstr ""
+
+msgid "Gitpod|Gitpod URL"
+msgstr ""
+
+msgid "Gitpod|e.g. https://gitpod.example.com"
+msgstr ""
+
msgid "Given access %{time_ago}"
msgstr ""
@@ -12730,9 +13150,6 @@ msgstr ""
msgid "GroupSAML|Valid SAML Response"
msgstr ""
-msgid "GroupSAML|With group managed accounts enabled, all the users without a group managed account will be excluded from the group."
-msgstr ""
-
msgid "GroupSAML|With prohibit outer forks flag enabled group members will be able to fork project only inside your group."
msgstr ""
@@ -12946,10 +13363,10 @@ msgstr ""
msgid "GroupsNew|Create group"
msgstr ""
-msgid "GroupsNew|GitLab group export"
+msgid "GroupsNew|Import"
msgstr ""
-msgid "GroupsNew|Import"
+msgid "GroupsNew|Import a GitLab group export file"
msgstr ""
msgid "GroupsNew|Import group"
@@ -13096,6 +13513,9 @@ msgstr[3] ""
msgstr[4] ""
msgstr[5] ""
+msgid "Hide comments on this file"
+msgstr ""
+
msgid "Hide details"
msgstr ""
@@ -13144,6 +13564,15 @@ msgstr ""
msgid "Highest role:"
msgstr ""
+msgid "HighlightBar|Alert events:"
+msgstr ""
+
+msgid "HighlightBar|Alert start time:"
+msgstr ""
+
+msgid "HighlightBar|Original alert:"
+msgstr ""
+
msgid "History"
msgstr ""
@@ -13321,6 +13750,9 @@ msgstr ""
msgid "If enabled, access to projects will be validated on an external service using their classification label."
msgstr ""
+msgid "If the number of active users exceeds the user limit, you will be charged for the number of %{users_over_license_link} at your next license reconciliation."
+msgstr ""
+
msgid "If there is no previous license or if the previous license has expired, some GitLab functionality will be blocked until a new, valid license is uploaded."
msgstr ""
@@ -13360,9 +13792,6 @@ msgstr ""
msgid "If your HTTP repository is not publicly accessible, add your credentials."
msgstr ""
-msgid "Iglu registry URL (optional)"
-msgstr ""
-
msgid "Ignore"
msgstr ""
@@ -13399,6 +13828,24 @@ msgstr ""
msgid "Import"
msgstr ""
+msgid "Import %d compatible repository"
+msgid_plural "Import %d compatible repositories"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+msgstr[5] ""
+
+msgid "Import %d repository"
+msgid_plural "Import %d repositories"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+msgstr[5] ""
+
msgid "Import CSV"
msgstr ""
@@ -13408,15 +13855,9 @@ msgstr ""
msgid "Import all compatible projects"
msgstr ""
-msgid "Import all compatible repositories"
-msgstr ""
-
msgid "Import all projects"
msgstr ""
-msgid "Import all repositories"
-msgstr ""
-
msgid "Import an exported GitLab project"
msgstr ""
@@ -13504,6 +13945,9 @@ msgstr ""
msgid "ImportProjects|Error importing repository %{project_safe_import_url} into %{project_full_path} - %{message}"
msgstr ""
+msgid "ImportProjects|Import repositories"
+msgstr ""
+
msgid "ImportProjects|Importing the project failed"
msgstr ""
@@ -13516,7 +13960,7 @@ msgstr ""
msgid "ImportProjects|Requesting your %{provider} repositories failed"
msgstr ""
-msgid "ImportProjects|Select the projects you want to import"
+msgid "ImportProjects|Select the repositories you want to import"
msgstr ""
msgid "ImportProjects|The remote data could not be imported."
@@ -13552,9 +13996,6 @@ msgstr ""
msgid "In order to enable Service Desk for your instance, you must first set up incoming email."
msgstr ""
-msgid "In order to gather accurate feature usage data, it can take 1 to 2 weeks to see your index."
-msgstr ""
-
msgid "In order to personalize your experience with GitLab%{br_tag}we would like to know a bit more about you."
msgstr ""
@@ -13585,18 +14026,30 @@ msgstr ""
msgid "IncidentManagement|Create incident"
msgstr ""
+msgid "IncidentManagement|Critical - S1"
+msgstr ""
+
msgid "IncidentManagement|Date created"
msgstr ""
msgid "IncidentManagement|Display your incidents in a dedicated view"
msgstr ""
+msgid "IncidentManagement|High - S2"
+msgstr ""
+
msgid "IncidentManagement|Incident"
msgstr ""
msgid "IncidentManagement|Incidents"
msgstr ""
+msgid "IncidentManagement|Low - S4"
+msgstr ""
+
+msgid "IncidentManagement|Medium - S3"
+msgstr ""
+
msgid "IncidentManagement|No incidents to display."
msgstr ""
@@ -13609,6 +14062,9 @@ msgstr ""
msgid "IncidentManagement|Published to status page"
msgstr ""
+msgid "IncidentManagement|Severity"
+msgstr ""
+
msgid "IncidentManagement|There are no closed incidents"
msgstr ""
@@ -13618,6 +14074,9 @@ msgstr ""
msgid "IncidentManagement|Unassigned"
msgstr ""
+msgid "IncidentManagement|Unknown"
+msgstr ""
+
msgid "IncidentManagement|Unpublished"
msgstr ""
@@ -13639,6 +14098,15 @@ msgstr ""
msgid "Incidents"
msgstr ""
+msgid "Incident|Alert details"
+msgstr ""
+
+msgid "Incident|Summary"
+msgstr ""
+
+msgid "Incident|There was an issue loading alert data. Please try again."
+msgstr ""
+
msgid "Include a Terms of Service agreement and Privacy Policy that all users must accept."
msgstr ""
@@ -13699,6 +14167,9 @@ msgstr ""
msgid "Information about additional Pages templates and how to install them can be found in our %{pages_getting_started_guide}."
msgstr ""
+msgid "Inherited"
+msgstr ""
+
msgid "Inherited:"
msgstr ""
@@ -13783,7 +14254,22 @@ msgstr ""
msgid "Instance administrators group already exists"
msgstr ""
-msgid "Instance license"
+msgid "InstanceStatistics|Groups"
+msgstr ""
+
+msgid "InstanceStatistics|Issues"
+msgstr ""
+
+msgid "InstanceStatistics|Merge Requests"
+msgstr ""
+
+msgid "InstanceStatistics|Pipelines"
+msgstr ""
+
+msgid "InstanceStatistics|Projects"
+msgstr ""
+
+msgid "InstanceStatistics|Users"
msgstr ""
msgid "Integration"
@@ -13795,6 +14281,12 @@ msgstr ""
msgid "Integrations"
msgstr ""
+msgid "Integrations|%{integration} settings saved and active."
+msgstr ""
+
+msgid "Integrations|%{integration} settings saved, but not active."
+msgstr ""
+
msgid "Integrations|All details"
msgstr ""
@@ -13804,6 +14296,12 @@ msgstr ""
msgid "Integrations|Comment settings:"
msgstr ""
+msgid "Integrations|Connection failed. Please check your settings."
+msgstr ""
+
+msgid "Integrations|Connection successful."
+msgstr ""
+
msgid "Integrations|Default settings are inherited from the group level."
msgstr ""
@@ -13819,6 +14317,15 @@ msgstr ""
msgid "Integrations|Includes commit title and branch"
msgstr ""
+msgid "Integrations|Projects using custom settings will not be impacted unless the project owner chooses to use instance-level defaults."
+msgstr ""
+
+msgid "Integrations|Save settings?"
+msgstr ""
+
+msgid "Integrations|Saving will update the default settings for all projects that are not using custom settings."
+msgstr ""
+
msgid "Integrations|Standard"
msgstr ""
@@ -13951,6 +14458,9 @@ msgstr ""
msgid "Invitation"
msgstr ""
+msgid "Invitation declined"
+msgstr ""
+
msgid "Invite"
msgstr ""
@@ -14002,6 +14512,42 @@ 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|%{linkStart}Read more%{linkEnd} about role permissions"
+msgstr ""
+
+msgid "InviteMembersModal|Access expiration date (optional)"
+msgstr ""
+
+msgid "InviteMembersModal|Cancel"
+msgstr ""
+
+msgid "InviteMembersModal|Choose a role permission"
+msgstr ""
+
+msgid "InviteMembersModal|GitLab member or Email address"
+msgstr ""
+
+msgid "InviteMembersModal|Invite"
+msgstr ""
+
+msgid "InviteMembersModal|Invite team members"
+msgstr ""
+
+msgid "InviteMembersModal|Search for members to invite"
+msgstr ""
+
+msgid "InviteMembersModal|User not invited. Feature coming soon!"
+msgstr ""
+
+msgid "InviteMembersModal|Users were succesfully added"
+msgstr ""
+
+msgid "InviteMembersModal|You're inviting members to the %{group_name} group"
+msgstr ""
+
+msgid "InviteMembers|Invite team members"
+msgstr ""
+
msgid "Invited"
msgstr ""
@@ -14056,10 +14602,13 @@ msgstr ""
msgid "Issue cannot be found."
msgstr ""
+msgid "Issue created from vulnerability %{vulnerability_link}"
+msgstr ""
+
msgid "Issue events"
msgstr ""
-msgid "Issue first depoloyed to production"
+msgid "Issue first deployed to production"
msgstr ""
msgid "Issue label"
@@ -14137,6 +14686,9 @@ msgstr ""
msgid "IssueTracker|Custom issue tracker"
msgstr ""
+msgid "IssueTracker|EWM work items tracker"
+msgstr ""
+
msgid "IssueTracker|Redmine issue tracker"
msgstr ""
@@ -14203,6 +14755,9 @@ msgstr ""
msgid "It looks like you have some draft commits in this branch."
msgstr ""
+msgid "It may be several days before you see feature usage data."
+msgstr ""
+
msgid "It must have a header row and at least two columns: the first column is the issue title and the second column is the issue description. The separator is automatically detected."
msgstr ""
@@ -14485,13 +15040,13 @@ msgstr ""
msgid "Join Zoom meeting"
msgstr ""
-msgid "Jul"
+msgid "Joined %{time_ago}"
msgstr ""
-msgid "July"
+msgid "Jul"
msgstr ""
-msgid "Jump to first unresolved thread"
+msgid "July"
msgstr ""
msgid "Jump to next unresolved thread"
@@ -14527,6 +15082,9 @@ msgstr ""
msgid "Keyboard shortcuts"
msgstr ""
+msgid "KeyboardKey|Ctrl+"
+msgstr ""
+
msgid "Keys"
msgstr ""
@@ -14575,6 +15133,9 @@ msgstr ""
msgid "LDAP Synchronization"
msgstr ""
+msgid "LDAP group settings"
+msgstr ""
+
msgid "LDAP settings"
msgstr ""
@@ -14584,6 +15145,9 @@ msgstr ""
msgid "LDAP sync in progress. This could take a few minutes. Refresh the page to see the changes."
msgstr ""
+msgid "LDAP synchronizations"
+msgstr ""
+
msgid "LFS"
msgstr ""
@@ -14668,7 +15232,16 @@ msgstr[3] ""
msgstr[4] ""
msgstr[5] ""
-msgid "Last %{days} days"
+msgid "Last 2 weeks"
+msgstr ""
+
+msgid "Last 30 days"
+msgstr ""
+
+msgid "Last 60 days"
+msgstr ""
+
+msgid "Last 90 days"
msgstr ""
msgid "Last Accessed On"
@@ -14746,6 +15319,9 @@ msgstr ""
msgid "Last used on:"
msgstr ""
+msgid "Last week"
+msgstr ""
+
msgid "LastCommit|authored"
msgstr ""
@@ -14761,6 +15337,9 @@ msgstr ""
msgid "Latest pipeline for the most recent commit on this branch"
msgstr ""
+msgid "Launch a ready-to-code development environment for your project."
+msgstr ""
+
msgid "Lead"
msgstr ""
@@ -15169,6 +15748,9 @@ msgstr ""
msgid "List of all merge commits"
msgstr ""
+msgid "List options"
+msgstr ""
+
msgid "List settings"
msgstr ""
@@ -15181,9 +15763,6 @@ msgstr ""
msgid "List your Bitbucket Server repositories"
msgstr ""
-msgid "Lists"
-msgstr ""
-
msgid "Live preview"
msgstr ""
@@ -15430,6 +16009,12 @@ msgstr ""
msgid "Mark as done"
msgstr ""
+msgid "Mark as draft"
+msgstr ""
+
+msgid "Mark as ready"
+msgstr ""
+
msgid "Mark as resolved"
msgstr ""
@@ -15451,6 +16036,24 @@ msgstr ""
msgid "Markdown is supported"
msgstr ""
+msgid "MarkdownEditor|Add a link (%{modifierKey}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add a link (%{modifier_key}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifierKey}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifier_key}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifierKey}I)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifier_key}I)"
+msgstr ""
+
msgid "Marked For Deletion At - %{deletion_time}"
msgstr ""
@@ -15535,7 +16138,25 @@ msgstr ""
msgid "Max access level"
msgstr ""
-msgid "Max seats used"
+msgid "Max role"
+msgstr ""
+
+msgid "Max size 15 MB"
+msgstr ""
+
+msgid "Maximum Conan package file size in bytes"
+msgstr ""
+
+msgid "Maximum Maven package file size in bytes"
+msgstr ""
+
+msgid "Maximum NPM package file size in bytes"
+msgstr ""
+
+msgid "Maximum NuGet package file size in bytes"
+msgstr ""
+
+msgid "Maximum PyPI package file size in bytes"
msgstr ""
msgid "Maximum Users:"
@@ -15667,6 +16288,18 @@ msgstr ""
msgid "Members with access to %{strong_start}%{group_name}%{strong_end}"
msgstr ""
+msgid "Members|%{time} by %{user}"
+msgstr ""
+
+msgid "Members|Expired"
+msgstr ""
+
+msgid "Members|No expiration set"
+msgstr ""
+
+msgid "Members|in %{time}"
+msgstr ""
+
msgid "Memory Usage"
msgstr ""
@@ -15853,9 +16486,6 @@ msgstr ""
msgid "MergeRequests|Thread will be unresolved"
msgstr ""
-msgid "MergeRequests|Toggle comments for this file"
-msgstr ""
-
msgid "MergeRequests|View file @ %{commitId}"
msgstr ""
@@ -15916,6 +16546,9 @@ msgstr ""
msgid "Merging immediately isn't recommended as it may negatively impact the existing merge train. Read the %{docsLinkStart}documentation%{docsLinkEnd} for more information."
msgstr ""
+msgid "Message"
+msgstr ""
+
msgid "Messages"
msgstr ""
@@ -16309,18 +16942,12 @@ msgstr[3] ""
msgstr[4] ""
msgstr[5] ""
-msgid "Milestone does not support burnup charts"
-msgstr ""
-
msgid "Milestone lists not available with your current license"
msgstr ""
msgid "Milestone lists show all issues from the selected milestone."
msgstr ""
-msgid "Milestone must have a start and due date"
-msgstr ""
-
msgid "MilestoneSidebar|Closed:"
msgstr ""
@@ -16687,6 +17314,9 @@ msgstr ""
msgid "Namespace"
msgstr ""
+msgid "Namespace ID:"
+msgstr ""
+
msgid "Namespace is empty"
msgstr ""
@@ -16771,6 +17401,9 @@ msgstr ""
msgid "NetworkPolicies|Allow all outbound traffic from %{selector} to %{ruleSelector} on %{ports}"
msgstr ""
+msgid "NetworkPolicies|Are you sure you want to delete this policy? This action cannot be undone."
+msgstr ""
+
msgid "NetworkPolicies|Choose whether to enforce this policy."
msgstr ""
@@ -16780,12 +17413,21 @@ msgstr ""
msgid "NetworkPolicies|Define this policy's location, conditions and actions."
msgstr ""
+msgid "NetworkPolicies|Delete policy"
+msgstr ""
+
+msgid "NetworkPolicies|Delete policy: %{policy}"
+msgstr ""
+
msgid "NetworkPolicies|Deny all traffic"
msgstr ""
msgid "NetworkPolicies|Description"
msgstr ""
+msgid "NetworkPolicies|Edit policy"
+msgstr ""
+
msgid "NetworkPolicies|Editor mode"
msgstr ""
@@ -16813,6 +17455,9 @@ msgstr ""
msgid "NetworkPolicies|Name"
msgstr ""
+msgid "NetworkPolicies|Namespace"
+msgstr ""
+
msgid "NetworkPolicies|Network Policy"
msgstr ""
@@ -16864,6 +17509,9 @@ msgstr ""
msgid "NetworkPolicies|Rules"
msgstr ""
+msgid "NetworkPolicies|Save changes"
+msgstr ""
+
msgid "NetworkPolicies|Something went wrong, failed to update policy"
msgstr ""
@@ -16876,6 +17524,9 @@ msgstr ""
msgid "NetworkPolicies|Traffic that does not match any rule will be blocked."
msgstr ""
+msgid "NetworkPolicies|Unable to parse policy"
+msgstr ""
+
msgid "NetworkPolicies|YAML editor"
msgstr ""
@@ -16993,6 +17644,9 @@ msgstr ""
msgid "New Snippet"
msgstr ""
+msgid "New Test Case"
+msgstr ""
+
msgid "New User"
msgstr ""
@@ -17092,6 +17746,9 @@ msgstr ""
msgid "New tag"
msgstr ""
+msgid "New test case"
+msgstr ""
+
msgid "New users set to external"
msgstr ""
@@ -17164,7 +17821,7 @@ msgstr ""
msgid "No changes"
msgstr ""
-msgid "No changes between %{ref_start}%{source_branch}%{ref_end} and %{ref_start}%{target_branch}%{ref_end}"
+msgid "No changes between %{sourceBranch} and %{targetBranch}"
msgstr ""
msgid "No child epics match applied filters"
@@ -17179,6 +17836,9 @@ msgstr ""
msgid "No containers available"
msgstr ""
+msgid "No content to show"
+msgstr ""
+
msgid "No contributions"
msgstr ""
@@ -17254,9 +17914,6 @@ msgstr ""
msgid "No license. All rights reserved"
msgstr ""
-msgid "No licenses found."
-msgstr ""
-
msgid "No matches found"
msgstr ""
@@ -17269,6 +17926,9 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No members found"
+msgstr ""
+
msgid "No merge requests found"
msgstr ""
@@ -17290,6 +17950,9 @@ msgstr ""
msgid "No parent group"
msgstr ""
+msgid "No plan"
+msgstr ""
+
msgid "No pods available"
msgstr ""
@@ -17386,6 +18049,12 @@ msgstr ""
msgid "Not Implemented"
msgstr ""
+msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+msgstr ""
+
+msgid "Not all browsers support WebAuthn. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even from an unsupported browser."
+msgstr ""
+
msgid "Not all data has been processed yet, the accuracy of the chart for the selected timeframe is limited."
msgstr ""
@@ -17482,6 +18151,9 @@ msgstr ""
msgid "Notification settings saved"
msgstr ""
+msgid "NotificationEvent|Change reviewer merge request"
+msgstr ""
+
msgid "NotificationEvent|Close issue"
msgstr ""
@@ -17644,10 +18316,7 @@ msgstr ""
msgid "On track"
msgstr ""
-msgid "OnDemandScans|Attached branch"
-msgstr ""
-
-msgid "OnDemandScans|Attached branch is where the scan job runs."
+msgid "OnDemandScans|Could not fetch scanner profiles. Please refresh the page, or try again later."
msgstr ""
msgid "OnDemandScans|Could not fetch site profiles. Please refresh the page, or try again later."
@@ -17656,6 +18325,9 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
+msgid "OnDemandScans|Create a new scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Create a new site profile"
msgstr ""
@@ -17668,6 +18340,9 @@ msgstr ""
msgid "OnDemandScans|New on-demand DAST scan"
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 ""
@@ -17677,16 +18352,10 @@ msgstr ""
msgid "OnDemandScans|On-demand scans run outside the DevOps cycle and find vulnerabilities in your projects. %{learnMoreLinkStart}Learn more%{learnMoreLinkEnd}"
msgstr ""
-msgid "OnDemandScans|Only a passive scan can be performed on demand."
-msgstr ""
-
-msgid "OnDemandScans|Passive"
-msgstr ""
-
msgid "OnDemandScans|Run scan"
msgstr ""
-msgid "OnDemandScans|Scan mode"
+msgid "OnDemandScans|Scanner profile"
msgstr ""
msgid "OnDemandScans|Scanner settings"
@@ -17698,9 +18367,15 @@ msgstr ""
msgid "OnDemandScans|Select one of the existing profiles"
msgstr ""
+msgid "OnDemandScans|Site profile"
+msgstr ""
+
msgid "OnDemandScans|Site profiles"
msgstr ""
+msgid "OnDemandScans|Use existing scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Use existing site profile"
msgstr ""
@@ -17803,9 +18478,6 @@ msgstr ""
msgid "Open Selection"
msgstr ""
-msgid "Open Web IDE"
-msgstr ""
-
msgid "Open comment type dropdown"
msgstr ""
@@ -17911,6 +18583,9 @@ msgstr ""
msgid "Origin"
msgstr ""
+msgid "Orphaned member"
+msgstr ""
+
msgid "Other Labels"
msgstr ""
@@ -17926,6 +18601,9 @@ msgstr ""
msgid "Other visibility settings have been disabled by the administrator."
msgstr ""
+msgid "Our documentation includes an example DevOps Score report."
+msgstr ""
+
msgid "Out-of-compliance with this project's policies and should be removed"
msgstr ""
@@ -17950,6 +18628,9 @@ msgstr ""
msgid "Overwrite diverged branches"
msgstr ""
+msgid "Owned by %{image_tag}"
+msgstr ""
+
msgid "Owned by anyone"
msgstr ""
@@ -17971,6 +18652,9 @@ msgstr ""
msgid "Package deleted successfully"
msgstr ""
+msgid "Package file size limits"
+msgstr ""
+
msgid "Package recipe already exists"
msgstr ""
@@ -17986,9 +18670,6 @@ msgstr ""
msgid "Package type must be PyPi"
msgstr ""
-msgid "Package was removed"
-msgstr ""
-
msgid "PackageRegistry|%{name} version %{version} was created %{datetime}"
msgstr ""
@@ -18130,12 +18811,18 @@ msgstr ""
msgid "PackageRegistry|NuGet Command"
msgstr ""
+msgid "PackageRegistry|Package Registry"
+msgstr ""
+
msgid "PackageRegistry|Pip Command"
msgstr ""
msgid "PackageRegistry|Pipeline %{link} triggered %{datetime} by %{author}"
msgstr ""
+msgid "PackageRegistry|Publish and share packages for a variety of common package managers. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "PackageRegistry|Published to the %{project} Package Registry %{datetime}"
msgstr ""
@@ -18235,6 +18922,9 @@ msgstr ""
msgid "Page not found"
msgstr ""
+msgid "Page settings"
+msgstr ""
+
msgid "Page was successfully deleted"
msgstr ""
@@ -18376,7 +19066,7 @@ msgstr ""
msgid "Paste issue link"
msgstr ""
-msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Don't use your private SSH key."
+msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Do not paste your private SSH key, as that can compromise your identity."
msgstr ""
msgid "Patch to apply"
@@ -18403,6 +19093,9 @@ msgstr ""
msgid "Pending"
msgstr ""
+msgid "Pending comments"
+msgstr ""
+
msgid "People without permission will never get a notification and won't be able to comment."
msgstr ""
@@ -18601,6 +19294,9 @@ msgstr ""
msgid "Pipelines|Build with confidence"
msgstr ""
+msgid "Pipelines|By revoking a trigger you will break any processes making use of it. Are you sure?"
+msgstr ""
+
msgid "Pipelines|CI Lint"
msgstr ""
@@ -18613,6 +19309,15 @@ msgstr ""
msgid "Pipelines|Continuous Integration can help catch bugs by running your tests automatically, while Continuous Deployment can help you deliver code to your product environment."
msgstr ""
+msgid "Pipelines|Copy trigger token"
+msgstr ""
+
+msgid "Pipelines|Description"
+msgstr ""
+
+msgid "Pipelines|Edit"
+msgstr ""
+
msgid "Pipelines|Get started with Pipelines"
msgstr ""
@@ -18628,15 +19333,27 @@ msgstr ""
msgid "Pipelines|It is recommended the code is reviewed thoroughly before running this pipeline with the parent project's CI resource."
msgstr ""
+msgid "Pipelines|Last Used"
+msgstr ""
+
msgid "Pipelines|Loading Pipelines"
msgstr ""
msgid "Pipelines|More Information"
msgstr ""
+msgid "Pipelines|No triggers have been created yet. Add one using the form above."
+msgstr ""
+
+msgid "Pipelines|Owner"
+msgstr ""
+
msgid "Pipelines|Project cache successfully reset."
msgstr ""
+msgid "Pipelines|Revoke"
+msgstr ""
+
msgid "Pipelines|Run Pipeline"
msgstr ""
@@ -18661,6 +19378,15 @@ msgstr ""
msgid "Pipelines|This project is not currently set up to run pipelines."
msgstr ""
+msgid "Pipelines|Token"
+msgstr ""
+
+msgid "Pipelines|Trigger user has insufficient permissions to project"
+msgstr ""
+
+msgid "Pipelines|invalid"
+msgstr ""
+
msgid "Pipelines|parent"
msgstr ""
@@ -18919,10 +19645,10 @@ msgstr ""
msgid "Please provide attributes to update"
msgstr ""
-msgid "Please refer to %{docs_url}"
+msgid "Please reach out if you have any questions and we'll be happy to assist."
msgstr ""
-msgid "Please retype the email address."
+msgid "Please refer to %{docs_url}"
msgstr ""
msgid "Please select"
@@ -18952,6 +19678,9 @@ msgstr ""
msgid "Please set a new password before proceeding."
msgstr ""
+msgid "Please share your feedback about %{featureName} %{linkStart}in this issue%{linkEnd} to help us improve the experience."
+msgstr ""
+
msgid "Please solve the reCAPTCHA"
msgstr ""
@@ -19255,6 +19984,9 @@ msgstr ""
msgid "Profiles| You are going to change the username %{currentUsernameBold} to %{newUsernameBold}. Profile and projects will be redirected to the %{newUsername} namespace but this redirect will expire once the %{currentUsername} namespace is registered by another user or group. Please update your Git repository remotes as soon as possible."
msgstr ""
+msgid "Profiles|%{provider} Active"
+msgstr ""
+
msgid "Profiles|@username"
msgstr ""
@@ -19306,7 +20038,7 @@ msgstr ""
msgid "Profiles|Commit email"
msgstr ""
-msgid "Profiles|Connect"
+msgid "Profiles|Connect %{provider}"
msgstr ""
msgid "Profiles|Connected Accounts"
@@ -19330,6 +20062,9 @@ msgstr ""
msgid "Profiles|Disconnect"
msgstr ""
+msgid "Profiles|Disconnect %{provider}"
+msgstr ""
+
msgid "Profiles|Do not show on profile"
msgstr ""
@@ -19354,7 +20089,7 @@ msgstr ""
msgid "Profiles|Full name"
msgstr ""
-msgid "Profiles|Give your individual key a title. This will be publically visible."
+msgid "Profiles|Give your individual key a title."
msgstr ""
msgid "Profiles|Include private contributions on my profile"
@@ -19444,7 +20179,7 @@ msgstr ""
msgid "Profiles|The maximum file size allowed is 200KB."
msgstr ""
-msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it?"
+msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it? It will be publicly visible."
msgstr ""
msgid "Profiles|This email will be displayed on your public profile"
@@ -19519,6 +20254,9 @@ msgstr ""
msgid "Profiles|You don't have access to delete this user."
msgstr ""
+msgid "Profiles|You must transfer ownership or delete groups you are an owner of before you can delete your account"
+msgstr ""
+
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
@@ -20107,6 +20845,9 @@ msgstr ""
msgid "ProjectTemplates|GitLab Cluster Management"
msgstr ""
+msgid "ProjectTemplates|Gitpod/Spring Petclinic"
+msgstr ""
+
msgid "ProjectTemplates|Go Micro"
msgstr ""
@@ -20716,6 +21457,9 @@ msgstr ""
msgid "Publish to status page"
msgstr ""
+msgid "Published"
+msgstr ""
+
msgid "Published on status page"
msgstr ""
@@ -20833,9 +21577,15 @@ msgstr ""
msgid "Quick range"
msgstr ""
+msgid "Quickly and easily edit multiple files in your project."
+msgstr ""
+
msgid "README"
msgstr ""
+msgid "Rails"
+msgstr ""
+
msgid "Rake Tasks Help"
msgstr ""
@@ -20959,10 +21709,13 @@ msgstr ""
msgid "Register Two-Factor Authenticator"
msgstr ""
-msgid "Register U2F device"
+msgid "Register Universal Two-Factor (U2F) Device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register WebAuthn Device"
+msgstr ""
+
+msgid "Register device"
msgstr ""
msgid "Register for GitLab"
@@ -20974,9 +21727,6 @@ msgstr ""
msgid "Register with two-factor app"
msgstr ""
-msgid "Registration"
-msgstr ""
-
msgid "Registration|Checkout"
msgstr ""
@@ -21097,9 +21847,6 @@ msgstr ""
msgid "Release|Something went wrong while saving the release details"
msgstr ""
-msgid "Remediated: needs review"
-msgstr ""
-
msgid "Remediations"
msgstr ""
@@ -21205,6 +21952,9 @@ msgstr ""
msgid "Remove priority"
msgstr ""
+msgid "Remove report"
+msgstr ""
+
msgid "Remove secondary node"
msgstr ""
@@ -21217,6 +21967,12 @@ msgstr ""
msgid "Remove time estimate"
msgstr ""
+msgid "Remove user & report"
+msgstr ""
+
+msgid "Remove user from group"
+msgstr ""
+
msgid "Removed"
msgstr ""
@@ -21298,9 +22054,6 @@ msgstr ""
msgid "Removes time estimate."
msgstr ""
-msgid "Removing license…"
-msgstr ""
-
msgid "Removing this group also removes all child projects, including archived projects, and their resources."
msgstr ""
@@ -21385,6 +22138,9 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
+msgid "Reported by %{reporter}"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -21475,6 +22231,27 @@ msgstr ""
msgid "Repositories"
msgstr ""
+msgid "Repositories Analytics"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download Historic Test Coverage Data"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download historic test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Historic Test Coverage Data is available in raw format (.csv) for further analysis."
+msgstr ""
+
+msgid "RepositoriesAnalytics|Test Code Coverage"
+msgstr ""
+
+msgid "RepositoriesAnalytics|There was an error fetching the projects."
+msgstr ""
+
msgid "Repository"
msgstr ""
@@ -21553,9 +22330,15 @@ msgstr ""
msgid "Request parameter %{param} is missing."
msgstr ""
+msgid "Request review from"
+msgstr ""
+
msgid "Request to link SAML account must be authorized"
msgstr ""
+msgid "Requested"
+msgstr ""
+
msgid "Requested %{time_ago}"
msgstr ""
@@ -21574,6 +22357,9 @@ msgstr ""
msgid "Requests to these domain(s)/address(es) on the local network will be allowed when local requests from hooks and services are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 or 127.0.0.0/28 are supported. Domain wildcards are not supported currently. Use comma, semicolon, or newline to separate multiple entries. The allowlist can hold a maximum of 1000 entries. Domains should use IDNA encoding. Ex: example.com, 192.168.1.1, 127.0.0.0/28, xn--itlab-j1a.com."
msgstr ""
+msgid "Require admin approval for new sign-ups"
+msgstr ""
+
msgid "Require all users in this group to setup Two-factor authentication"
msgstr ""
@@ -21709,9 +22495,6 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
-msgid "Resolved by %{resolvedByName}"
-msgstr ""
-
msgid "Resolves IP addresses once and uses them to submit requests"
msgstr ""
@@ -21835,6 +22618,18 @@ msgstr ""
msgid "ReviewApp|Enable Review App"
msgstr ""
+msgid "Reviewer"
+msgid_plural "%d Reviewers"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+msgstr[5] ""
+
+msgid "Reviewer(s)"
+msgstr ""
+
msgid "Reviewing"
msgstr ""
@@ -21874,6 +22669,9 @@ msgstr ""
msgid "Rook"
msgstr ""
+msgid "Ruby"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -21952,6 +22750,63 @@ msgstr ""
msgid "Runners page."
msgstr ""
+msgid "Runners|Active"
+msgstr ""
+
+msgid "Runners|Architecture"
+msgstr ""
+
+msgid "Runners|Can run untagged jobs"
+msgstr ""
+
+msgid "Runners|Description"
+msgstr ""
+
+msgid "Runners|Group"
+msgstr ""
+
+msgid "Runners|IP Address"
+msgstr ""
+
+msgid "Runners|Last contact"
+msgstr ""
+
+msgid "Runners|Locked to this project"
+msgstr ""
+
+msgid "Runners|Maximum job timeout"
+msgstr ""
+
+msgid "Runners|Name"
+msgstr ""
+
+msgid "Runners|Platform"
+msgstr ""
+
+msgid "Runners|Property Name"
+msgstr ""
+
+msgid "Runners|Protected"
+msgstr ""
+
+msgid "Runners|Revision"
+msgstr ""
+
+msgid "Runners|Shared"
+msgstr ""
+
+msgid "Runners|Specific"
+msgstr ""
+
+msgid "Runners|Tags"
+msgstr ""
+
+msgid "Runners|Value"
+msgstr ""
+
+msgid "Runners|Version"
+msgstr ""
+
msgid "Runners|You have used %{quotaUsed} out of %{quotaLimit} of your shared Runners pipeline minutes."
msgstr ""
@@ -21964,6 +22819,9 @@ msgstr ""
msgid "Runs a number of housekeeping tasks within the current repository, such as compressing file revisions and removing unreachable objects."
msgstr ""
+msgid "SAML"
+msgstr ""
+
msgid "SAML SSO"
msgstr ""
@@ -22015,6 +22873,9 @@ msgstr ""
msgid "Save"
msgstr ""
+msgid "Save %{name} size limits"
+msgstr ""
+
msgid "Save Changes"
msgstr ""
@@ -22045,9 +22906,6 @@ msgstr ""
msgid "Save space and find tags in the Container Registry more easily. Enable the cleanup policy to remove stale tags and keep only the ones you need."
msgstr ""
-msgid "Save template"
-msgstr ""
-
msgid "Save variables"
msgstr ""
@@ -22090,9 +22948,6 @@ msgstr ""
msgid "Scope"
msgstr ""
-msgid "Scope not supported with disabled 'users_search' feature!"
-msgstr ""
-
msgid "Scoped issue boards"
msgstr ""
@@ -22219,9 +23074,6 @@ msgstr ""
msgid "Search requirements"
msgstr ""
-msgid "Search results…"
-msgstr ""
-
msgid "Search users"
msgstr ""
@@ -22306,6 +23158,15 @@ msgstr[3] ""
msgstr[4] ""
msgstr[5] ""
+msgid "SearchResults|epic"
+msgid_plural "SearchResults|epics"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+msgstr[5] ""
+
msgid "SearchResults|issue"
msgid_plural "SearchResults|issues"
msgstr[0] ""
@@ -22378,10 +23239,10 @@ msgstr ""
msgid "Seat Link is disabled, and cannot be configured through this form."
msgstr ""
-msgid "Seats currently in use"
+msgid "Seats usage data as of %{last_enqueue_time}"
msgstr ""
-msgid "Seats in license"
+msgid "Seats usage data is updated every day at 12:00pm UTC"
msgstr ""
msgid "Secondary"
@@ -22435,6 +23296,9 @@ msgstr ""
msgid "SecurityConfiguration|Available for on-demand DAST"
msgstr ""
+msgid "SecurityConfiguration|By default, all analyzers are applied in order to cover all languages across your project, and only run if the language is detected in the Merge Request."
+msgstr ""
+
msgid "SecurityConfiguration|Configure"
msgstr ""
@@ -22465,16 +23329,19 @@ msgstr ""
msgid "SecurityConfiguration|Manage"
msgstr ""
+msgid "SecurityConfiguration|More information"
+msgstr ""
+
msgid "SecurityConfiguration|Not enabled"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|Security Control"
+msgid "SecurityConfiguration|SAST Configuration"
msgstr ""
-msgid "SecurityConfiguration|See documentation"
+msgid "SecurityConfiguration|Security Control"
msgstr ""
msgid "SecurityConfiguration|Status"
@@ -22486,6 +23353,9 @@ msgstr ""
msgid "SecurityConfiguration|Using custom settings. You won't receive automatic updates on this variable. %{anchorStart}Restore to default%{anchorEnd}"
msgstr ""
+msgid "SecurityConfiguration|View history"
+msgstr ""
+
msgid "SecurityConfiguration|You can quickly enable all security scanning tools by enabling %{linkStart}Auto DevOps%{linkEnd}."
msgstr ""
@@ -22564,9 +23434,6 @@ msgstr ""
msgid "SecurityReports|Learn more about setting up your dashboard"
msgstr ""
-msgid "SecurityReports|Load more vulnerabilities"
-msgstr ""
-
msgid "SecurityReports|Monitor vulnerabilities in your code"
msgstr ""
@@ -22846,7 +23713,7 @@ msgstr ""
msgid "Select status"
msgstr ""
-msgid "Select strategy activation method"
+msgid "Select strategy activation method."
msgstr ""
msgid "Select subscription"
@@ -22861,7 +23728,7 @@ msgstr ""
msgid "Select the custom project template source group."
msgstr ""
-msgid "Select timeframe"
+msgid "Select the environment scope for this feature flag."
msgstr ""
msgid "Select timezone"
@@ -23110,6 +23977,9 @@ msgstr ""
msgid "Set iteration"
msgstr ""
+msgid "Set limit to 0 to allow any file size."
+msgstr ""
+
msgid "Set max session time for web terminal."
msgstr ""
@@ -23188,10 +24058,13 @@ msgstr ""
msgid "Set up a %{type} Runner manually"
msgstr ""
+msgid "Set up a hardware device as a second factor to sign in."
+msgstr ""
+
msgid "Set up assertions/attributes/claims (email, first_name, last_name) and NameID according to %{docsLinkStart}the documentation %{icon}%{docsLinkEnd}"
msgstr ""
-msgid "Set up new U2F device"
+msgid "Set up new device"
msgstr ""
msgid "Set up new password"
@@ -23260,6 +24133,9 @@ msgstr ""
msgid "Sets weight to %{weight}."
msgstr ""
+msgid "Setting this to 0 means using the system default timeout value."
+msgstr ""
+
msgid "Settings"
msgstr ""
@@ -23275,6 +24151,15 @@ msgstr ""
msgid "Severity"
msgstr ""
+msgid "SeverityWidget|Severity"
+msgstr ""
+
+msgid "SeverityWidget|Severity: %{severity}"
+msgstr ""
+
+msgid "SeverityWidget|There was an error while updating severity."
+msgstr ""
+
msgid "Shards (%{shards})"
msgstr ""
@@ -23320,6 +24205,9 @@ msgstr ""
msgid "Show all requirements."
msgstr ""
+msgid "Show all test cases."
+msgstr ""
+
msgid "Show archived projects"
msgstr ""
@@ -23332,6 +24220,9 @@ msgstr ""
msgid "Show comments"
msgstr ""
+msgid "Show comments on this file"
+msgstr ""
+
msgid "Show comments only"
msgstr ""
@@ -23377,6 +24268,12 @@ msgstr ""
msgid "Show parent subgroups"
msgstr ""
+msgid "Show the Closed list"
+msgstr ""
+
+msgid "Show the Open list"
+msgstr ""
+
msgid "Show whitespace changes"
msgstr ""
@@ -23428,9 +24325,6 @@ msgstr ""
msgid "Sidebar|Assign health status"
msgstr ""
-msgid "Sidebar|Change weight"
-msgstr ""
-
msgid "Sidebar|Health status"
msgstr ""
@@ -23614,6 +24508,9 @@ msgstr ""
msgid "Snippets|Add another file %{num}/%{total}"
msgstr ""
+msgid "Snippets|Authored %{time_ago} by %{author}"
+msgstr ""
+
msgid "Snippets|Delete file"
msgstr ""
@@ -23641,6 +24538,9 @@ msgstr ""
msgid "Solution"
msgstr ""
+msgid "Some changes are not shown"
+msgstr ""
+
msgid "Some child epics may be hidden due to applied filters"
msgstr ""
@@ -24007,6 +24907,12 @@ msgstr ""
msgid "Source (branch or tag)"
msgstr ""
+msgid "Source Branch"
+msgstr ""
+
+msgid "Source branch: %{source_branch_open}%{source_branch}%{source_branch_close}"
+msgstr ""
+
msgid "Source code"
msgstr ""
@@ -24172,9 +25078,6 @@ msgstr ""
msgid "Start and due date"
msgstr ""
-msgid "Start by choosing a group to see how your team is spending time. You can then drill down to the project level."
-msgstr ""
-
msgid "Start by choosing a group to start exploring the merge requests in that group. You can then proceed to filter by projects, labels, milestones and authors."
msgstr ""
@@ -24256,18 +25159,27 @@ msgstr ""
msgid "StaticSiteEditor|3. Assign a person to review and accept the merge request."
msgstr ""
+msgid "StaticSiteEditor|A link to view the merge request will appear once ready."
+msgstr ""
+
msgid "StaticSiteEditor|An error occurred while submitting your changes."
msgstr ""
msgid "StaticSiteEditor|Branch could not be created."
msgstr ""
+msgid "StaticSiteEditor|Copy update"
+msgstr ""
+
msgid "StaticSiteEditor|Could not commit the content changes."
msgstr ""
msgid "StaticSiteEditor|Could not create merge request."
msgstr ""
+msgid "StaticSiteEditor|Creating your merge request"
+msgstr ""
+
msgid "StaticSiteEditor|Incompatible file content"
msgstr ""
@@ -24289,6 +25201,9 @@ msgstr ""
msgid "StaticSiteEditor|View documentation"
msgstr ""
+msgid "StaticSiteEditor|You can set an assignee to get your changes reviewed and deployed once your merge request is created."
+msgstr ""
+
msgid "StaticSiteEditor|Your merge request has been created"
msgstr ""
@@ -24418,15 +25333,15 @@ msgstr ""
msgid "Submit %{humanized_resource_name}"
msgstr ""
-msgid "Submit Changes"
-msgstr ""
-
msgid "Submit a review"
msgstr ""
msgid "Submit as spam"
msgstr ""
+msgid "Submit changes"
+msgstr ""
+
msgid "Submit feedback"
msgstr ""
@@ -24580,6 +25495,9 @@ msgstr ""
msgid "Successfully deleted U2F device."
msgstr ""
+msgid "Successfully deleted WebAuthn device."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -24898,9 +25816,6 @@ msgstr ""
msgid "Template to append to all Service Desk issues"
msgstr ""
-msgid "Template was successfully saved."
-msgstr ""
-
msgid "Templates"
msgstr ""
@@ -24991,10 +25906,28 @@ msgstr[3] ""
msgstr[4] ""
msgstr[5] ""
-msgid "Test failed."
+msgid "Test settings"
+msgstr ""
+
+msgid "TestCases|New Test Case"
+msgstr ""
+
+msgid "TestCases|New test case"
+msgstr ""
+
+msgid "TestCases|Search test cases"
msgstr ""
-msgid "Test settings and save changes"
+msgid "TestCases|Something went wrong while creating a test case."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching count of test cases."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching test cases list."
+msgstr ""
+
+msgid "TestCases|Submit test case"
msgstr ""
msgid "TestHooks|Ensure one of your projects has merge requests."
@@ -25060,6 +25993,9 @@ msgstr ""
msgid "Thank you for signing up for your free trial! You will get additional instructions in your inbox shortly."
msgstr ""
+msgid "Thank you for your business."
+msgstr ""
+
msgid "Thank you for your feedback!"
msgstr ""
@@ -25123,9 +26059,6 @@ msgstr ""
msgid "The URL to use for connecting to Elasticsearch. Use a comma-separated list to support clustering (e.g., \"http://localhost:9200, http://localhost:9201\")."
msgstr ""
-msgid "The Web IDE offers advanced syntax highlighting capabilities and more."
-msgstr ""
-
msgid "The X509 Certificate to use when mutual TLS is required to communicate with the external authorization service. If left blank, the server certificate is still validated when accessing over HTTPS."
msgstr ""
@@ -25240,6 +26173,9 @@ msgstr ""
msgid "The form contains the following error:"
msgstr ""
+msgid "The form contains the following warning:"
+msgstr ""
+
msgid "The global settings require you to enable Two-Factor Authentication for your account."
msgstr ""
@@ -25354,9 +26290,6 @@ msgstr ""
msgid "The private key to use when a client certificate is provided. This value is encrypted at rest."
msgstr ""
-msgid "The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The project can be accessed by any logged in user."
msgstr ""
@@ -25393,7 +26326,7 @@ msgstr ""
msgid "The remote repository is being updated..."
msgstr ""
-msgid "The repository can be commited to, and issues, comments and other entities can be created."
+msgid "The repository can be committed to, and issues, comments and other entities can be created."
msgstr ""
msgid "The repository for this project does not exist."
@@ -25447,9 +26380,6 @@ msgstr ""
msgid "The time taken by each data entry gathered by that stage."
msgstr ""
-msgid "The total stage shows the time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The update action will time out after %{number_of_minutes} minutes. For big repositories, use a clone/push combination."
msgstr ""
@@ -25513,6 +26443,9 @@ msgstr ""
msgid "There are no archived requirements"
msgstr ""
+msgid "There are no archived test cases"
+msgstr ""
+
msgid "There are no changes"
msgstr ""
@@ -25552,6 +26485,9 @@ msgstr ""
msgid "There are no open requirements"
msgstr ""
+msgid "There are no open test cases"
+msgstr ""
+
msgid "There are no packages yet"
msgstr ""
@@ -25564,6 +26500,9 @@ msgstr ""
msgid "There is a limit of %{ci_project_subscriptions_limit} subscriptions from or to a project."
msgstr ""
+msgid "There is already a To-Do for this design."
+msgstr ""
+
msgid "There is already a repository with that name on disk"
msgstr ""
@@ -25582,6 +26521,9 @@ msgstr ""
msgid "There was a problem communicating with your device."
msgstr ""
+msgid "There was a problem fetching branches."
+msgstr ""
+
msgid "There was a problem fetching groups."
msgstr ""
@@ -25810,9 +26752,15 @@ msgstr ""
msgid "This action can lead to data loss. To prevent accidental actions we ask you to confirm your intention."
msgstr ""
+msgid "This action cannot be undone, and will permanently delete the %{key} SSH key"
+msgstr ""
+
msgid "This action cannot be undone. You will lose the project's repository and all content: issues, merge requests, etc."
msgstr ""
+msgid "This action has been performed too many times. Try again later."
+msgstr ""
+
msgid "This action will %{strongOpen}permanently delete%{strongClose} %{codeOpen}%{project}%{codeClose} %{strongOpen}immediately%{strongClose}, including its repositories and all content: issues, merge requests, etc."
msgstr ""
@@ -25840,9 +26788,6 @@ msgstr ""
msgid "This board's scope is reduced"
msgstr ""
-msgid "This branch has changed since you started editing. Would you like to create a new branch?"
-msgstr ""
-
msgid "This chart could not be displayed"
msgstr ""
@@ -25969,15 +26914,9 @@ msgstr ""
msgid "This is a security log of important events involving your account."
msgstr ""
-msgid "This is the author's first Merge Request to this project."
-msgstr ""
-
msgid "This is the highest peak of users on your installation since the license started."
msgstr ""
-msgid "This is the maximum number of users that have existed at the same time since the license started. This is the minimum number of seats you will need to buy when you renew your license."
-msgstr ""
-
msgid "This is the number of currently active users on your installation, and this is the minimum number you need to purchase when you renew your license."
msgstr ""
@@ -26209,6 +27148,15 @@ msgstr ""
msgid "This user has no identities"
msgstr ""
+msgid "This user has previously committed to the %{name} project."
+msgstr ""
+
+msgid "This user has the %{access} role in the %{name} project."
+msgstr ""
+
+msgid "This user is the author of this %{noteable}."
+msgstr ""
+
msgid "This user will be the author of all events in the activity feed that are the result of an update, like new branches being created or new commits being pushed to existing branches."
msgstr ""
@@ -26239,6 +27187,9 @@ msgstr ""
msgid "Threat Monitoring"
msgstr ""
+msgid "ThreatMonitoring|All Environments"
+msgstr ""
+
msgid "ThreatMonitoring|Anomalous Requests"
msgstr ""
@@ -26266,9 +27217,6 @@ msgstr ""
msgid "ThreatMonitoring|Operations Per Second"
msgstr ""
-msgid "ThreatMonitoring|Overview"
-msgstr ""
-
msgid "ThreatMonitoring|Packet Activity"
msgstr ""
@@ -26287,6 +27235,9 @@ msgstr ""
msgid "ThreatMonitoring|Something went wrong, unable to fetch statistics"
msgstr ""
+msgid "ThreatMonitoring|Statistics"
+msgstr ""
+
msgid "ThreatMonitoring|The firewall is not installed or has been disabled. To view this data, ensure the web application firewall is installed and enabled for your cluster."
msgstr ""
@@ -26686,6 +27637,9 @@ msgstr ""
msgid "To update Snippets with multiple files, you must use the `files` parameter"
msgstr ""
+msgid "To use Gitpod you must first enable the feature in the integrations section of your %{user_prefs}."
+msgstr ""
+
msgid "To view all %{scannedResourcesCount} scanned URLs, please download the CSV file"
msgstr ""
@@ -26719,9 +27673,6 @@ msgstr ""
msgid "Toggle Sidebar"
msgstr ""
-msgid "Toggle all threads"
-msgstr ""
-
msgid "Toggle backtrace"
msgstr ""
@@ -26746,9 +27697,6 @@ msgstr ""
msgid "Toggle navigation"
msgstr ""
-msgid "Toggle project"
-msgstr ""
-
msgid "Toggle sidebar"
msgstr ""
@@ -26788,6 +27736,9 @@ msgstr ""
msgid "Too many projects enabled. You will need to manage them via the console or the API."
msgstr ""
+msgid "Too much data"
+msgstr ""
+
msgid "Topics (optional)"
msgstr ""
@@ -26806,6 +27757,9 @@ msgstr ""
msgid "Total cores (CPUs)"
msgstr ""
+msgid "Total days to completion"
+msgstr ""
+
msgid "Total issues"
msgstr ""
@@ -26902,6 +27856,9 @@ msgstr ""
msgid "Trending"
msgstr ""
+msgid "Trials|Create a new group to start your GitLab Gold trial."
+msgstr ""
+
msgid "Trials|Go back to GitLab"
msgstr ""
@@ -26911,6 +27868,15 @@ msgstr ""
msgid "Trials|You can always resume this process by selecting your avatar and choosing 'Start a Gold trial'"
msgstr ""
+msgid "Trials|You can apply your trial to a new group or an existing group."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group or your personal account."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group, an existing group, or your personal account."
+msgstr ""
+
msgid "Trials|You won't get a free trial right now but you can always resume this process by clicking on your avatar and choosing 'Start a free trial'"
msgstr ""
@@ -26980,6 +27946,9 @@ msgstr ""
msgid "Try using a different search term to find the file you are looking for."
msgstr ""
+msgid "Trying to communicate with your device. Plug it in (if needed) and press the button on the device now."
+msgstr ""
+
msgid "Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now."
msgstr ""
@@ -27067,6 +28036,12 @@ msgstr ""
msgid "URL or request ID"
msgstr ""
+msgid "USER %{user} WILL BE REMOVED! Are you sure?"
+msgstr ""
+
+msgid "USER WILL BE BLOCKED! Are you sure?"
+msgstr ""
+
msgid "UTC"
msgstr ""
@@ -27124,9 +28099,6 @@ msgstr ""
msgid "Unable to load the merge request widget. Try reloading the page."
msgstr ""
-msgid "Unable to resolve"
-msgstr ""
-
msgid "Unable to save iteration. Please try again"
msgstr ""
@@ -27175,6 +28147,9 @@ msgstr ""
msgid "Undo ignore"
msgstr ""
+msgid "Unexpected error"
+msgstr ""
+
msgid "Unfortunately, your email message to GitLab could not be processed."
msgstr ""
@@ -27208,6 +28183,9 @@ msgstr ""
msgid "Unknown response text"
msgstr ""
+msgid "Unless otherwise agreed to in writing with GitLab, by clicking \"Upload License\" you agree that your use of GitLab Software is subject to the %{eula_link_start}Terms of Service%{eula_link_end}."
+msgstr ""
+
msgid "Unlimited"
msgstr ""
@@ -27574,9 +28552,6 @@ msgstr ""
msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
msgstr ""
-msgid "Use a hardware device to add the second factor of authentication."
-msgstr ""
-
msgid "Use an one time password authenticator on your mobile device or computer to enable two-factor authentication (2FA)."
msgstr ""
@@ -27850,13 +28825,13 @@ msgstr ""
msgid "Users"
msgstr ""
-msgid "Users in License:"
+msgid "Users in License"
msgstr ""
-msgid "Users or groups set as approvers in the project's or merge request's settings."
+msgid "Users in License:"
msgstr ""
-msgid "Users outside of license"
+msgid "Users or groups set as approvers in the project's or merge request's settings."
msgstr ""
msgid "Users over License:"
@@ -27874,9 +28849,6 @@ msgstr ""
msgid "Users with a Guest role or those who don't belong to a Project or Group will not use a seat from your license."
msgstr ""
-msgid "Users with a Guest role or those who don't belong to any projects or groups don't count towards seats in use."
-msgstr ""
-
msgid "UsersSelect|%{name} + %{length} more"
msgstr ""
@@ -27916,9 +28888,6 @@ msgstr ""
msgid "Validations failed."
msgstr ""
-msgid "Validity"
-msgstr ""
-
msgid "Value"
msgstr ""
@@ -27937,6 +28906,9 @@ msgstr ""
msgid "Value Stream Name"
msgstr ""
+msgid "ValueStreamAnalyticsStage|We don't have enough data to show this stage."
+msgstr ""
+
msgid "ValueStreamAnalytics|%{days}d"
msgstr ""
@@ -28201,6 +29173,9 @@ msgstr ""
msgid "VisualReviewApp|Steps 1 and 2 (and sometimes 3) are performed once by the developer before requesting feedback. Steps 3 (if necessary), 4 is performed by the reviewer each time they perform a review."
msgstr ""
+msgid "Visualization"
+msgstr ""
+
msgid "Vulnerabilities"
msgstr ""
@@ -28228,34 +29203,31 @@ msgstr ""
msgid "VulnerabilityChart|Severity"
msgstr ""
-msgid "VulnerabilityManagement|A true-positive and will fix"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Change status"
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|Confirm"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Confirmed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
-msgstr ""
-
-msgid "VulnerabilityManagement|Detected %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|A true-positive and will fix"
msgstr ""
-msgid "VulnerabilityManagement|Dismiss"
+msgid "VulnerabilityManagement|Change status"
msgstr ""
-msgid "VulnerabilityManagement|Dismissed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
msgstr ""
-msgid "VulnerabilityManagement|Resolved"
+msgid "VulnerabilityManagement|Detected"
msgstr ""
-msgid "VulnerabilityManagement|Resolved %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Needs triage"
msgstr ""
msgid "VulnerabilityManagement|Something went wrong while trying to delete the comment. Please try again later."
@@ -28306,6 +29278,9 @@ msgstr ""
msgid "Vulnerability|%{scannerName} (version %{scannerVersion})"
msgstr ""
+msgid "Vulnerability|Activity"
+msgstr ""
+
msgid "Vulnerability|Class"
msgstr ""
@@ -28318,6 +29293,9 @@ msgstr ""
msgid "Vulnerability|Description"
msgstr ""
+msgid "Vulnerability|Detected"
+msgstr ""
+
msgid "Vulnerability|Evidence"
msgstr ""
@@ -28381,6 +29359,9 @@ msgstr ""
msgid "Warning: Displaying this diagram might cause performance issues on this page."
msgstr ""
+msgid "We are currently unable to fetch data for the pipeline header."
+msgstr ""
+
msgid "We are currently unable to fetch data for this graph."
msgstr ""
@@ -28420,6 +29401,12 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
+msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
+msgstr ""
+
+msgid "We would like to inform you that your subscription GitLab Enterprise Edition %{plan_name} is nearing its user limit. You have %{active_user_count} active users, which is almost at the user limit of %{maximum_user_count}."
+msgstr ""
+
msgid "We've found no vulnerabilities"
msgstr ""
@@ -28435,6 +29422,12 @@ msgstr ""
msgid "Web terminal"
msgstr ""
+msgid "WebAuthn Devices (%{length})"
+msgstr ""
+
+msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
+msgstr ""
+
msgid "WebIDE|Merge request"
msgstr ""
@@ -28573,15 +29566,9 @@ msgstr ""
msgid "Welcome to the guided GitLab tour"
msgstr ""
-msgid "Welcome to your Issue Board!"
-msgstr ""
-
msgid "Welcome to your issue board!"
msgstr ""
-msgid "We’ve been making changes to %{featureName} and we’d love your feedback %{linkStart}in this issue%{linkEnd} to help us improve the experience."
-msgstr ""
-
msgid "What are you searching for?"
msgstr ""
@@ -28600,6 +29587,9 @@ msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
msgstr ""
+msgid "When enabled, any user visiting %{host} and creating an account will have to be explicitly approved by the admin before they can login. This setting is effective only if sign-ups are enabled."
+msgstr ""
+
msgid "When enabled, any user visiting %{host} will be able to create an account."
msgstr ""
@@ -28828,6 +29818,9 @@ msgstr ""
msgid "With requirements, you can set criteria to check your products against."
msgstr ""
+msgid "With test cases, you can define conditions for your project to meet in determining quality"
+msgstr ""
+
msgid "Withdraw Access Request"
msgstr ""
@@ -28843,6 +29836,9 @@ msgstr ""
msgid "Workflow Help"
msgstr ""
+msgid "Would you like to create a new branch?"
+msgstr ""
+
msgid "Write"
msgstr ""
@@ -28864,6 +29860,9 @@ msgstr ""
msgid "Wrong extern UID provided. Make sure Auth0 is configured correctly."
msgstr ""
+msgid "YYYY-MM-DD"
+msgstr ""
+
msgid "Yes"
msgstr ""
@@ -28921,7 +29920,7 @@ msgstr ""
msgid "You are going to remove the fork relationship from %{project_full_name}. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "You are going to transfer %{project_full_name} to another owner. Are you ABSOLUTELY sure?"
+msgid "You are going to transfer %{project_full_name} to another namespace. Are you ABSOLUTELY sure?"
msgstr ""
msgid "You are going to turn off the confidentiality. This means %{strongStart}everyone%{strongEnd} will be able to see and leave a comment on this %{issuableType}."
@@ -28981,9 +29980,6 @@ msgstr ""
msgid "You can always edit this later"
msgstr ""
-msgid "You can apply your Trial to your Personal account or create a New Group."
-msgstr ""
-
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings"
msgstr ""
@@ -29005,12 +30001,18 @@ msgstr ""
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
+msgid "You can find more information about GitLab subscriptions in %{subscriptions_doc_link}."
+msgstr ""
+
msgid "You can generate an access token scoped to this project for each application to use the GitLab API."
msgstr ""
msgid "You can get started by cloning the repository or start adding files to it with one of the following options."
msgstr ""
+msgid "You can group test cases using labels. To learn about the future direction of this feature, visit %{linkStart}Quality Management direction page%{linkEnd}."
+msgstr ""
+
msgid "You can invite a new member to %{project_name} or invite another group."
msgstr ""
@@ -29026,6 +30028,9 @@ msgstr ""
msgid "You can notify the app / group or a project by sending them an email notification"
msgstr ""
+msgid "You can now close this window."
+msgstr ""
+
msgid "You can now export your security dashboard to a CSV report."
msgstr ""
@@ -29074,9 +30079,6 @@ msgstr ""
msgid "You can test your .gitlab-ci.yml in %{linkStart}CI Lint%{linkEnd}."
msgstr ""
-msgid "You can try again using %{begin_link}basic search%{end_link}"
-msgstr ""
-
msgid "You cannot access the raw file. Please wait a minute."
msgstr ""
@@ -29128,6 +30130,9 @@ msgstr ""
msgid "You don't have any U2F devices registered yet."
msgstr ""
+msgid "You don't have any WebAuthn devices registered yet."
+msgstr ""
+
msgid "You don't have any active chat names."
msgstr ""
@@ -29215,6 +30220,9 @@ msgstr ""
msgid "You must accept our Terms of Service and privacy policy in order to register an account"
msgstr ""
+msgid "You must be logged in to search across all of GitLab"
+msgstr ""
+
msgid "You must disassociate %{domain} from all clusters it is attached to before deletion."
msgstr ""
@@ -29254,7 +30262,7 @@ msgstr ""
msgid "You need to be logged in."
msgstr ""
-msgid "You need to register a two-factor authentication app before you can set up a U2F device."
+msgid "You need to register a two-factor authentication app before you can set up a device."
msgstr ""
msgid "You need to set terms to be enforced"
@@ -29272,6 +30280,9 @@ msgstr ""
msgid "You reached %{usage_in_percent} of %{namespace_name}'s storage capacity (%{used_storage} of %{storage_limit})"
msgstr ""
+msgid "You successfully declined the invitation"
+msgstr ""
+
msgid "You tried to fork %{link_to_the_project} but it failed for the following reason:"
msgstr ""
@@ -29437,10 +30448,13 @@ msgstr ""
msgid "Your U2F device did not send a valid JSON response."
msgstr ""
-msgid "Your U2F device needs to be set up. Plug it in (if not already) and click the button on the left."
+msgid "Your U2F device was registered!"
msgstr ""
-msgid "Your U2F device was registered!"
+msgid "Your WebAuthn device did not send a valid JSON response."
+msgstr ""
+
+msgid "Your WebAuthn device was registered!"
msgstr ""
msgid "Your access request to the %{source_type} has been withdrawn."
@@ -29464,6 +30478,9 @@ msgstr ""
msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
msgstr ""
+msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
+msgstr ""
+
msgid "Your changes can be committed to %{branch_name} because a merge request is open."
msgstr ""
@@ -29500,6 +30517,12 @@ msgstr ""
msgid "Your deployment services will be broken, you will need to manually fix the services after renaming."
msgstr ""
+msgid "Your device is not compatible with GitLab. Please try another device"
+msgstr ""
+
+msgid "Your device needs to be set up. Plug it in (if needed) and click the button on the left."
+msgstr ""
+
msgid "Your device was successfully set up! Give it a name and register it with the GitLab server."
msgstr ""
@@ -29617,9 +30640,6 @@ msgstr[5] ""
msgid "access:"
msgstr ""
-msgid "activated"
-msgstr ""
-
msgid "added %{created_at_timeago}"
msgstr ""
@@ -29692,9 +30712,21 @@ msgstr ""
msgid "by %{user}"
msgstr ""
+msgid "cannot be a date in the past"
+msgstr ""
+
msgid "cannot be changed if a personal project has container registry tags."
msgstr ""
+msgid "cannot be changed if shared runners are enabled"
+msgstr ""
+
+msgid "cannot be enabled because parent group does not allow it"
+msgstr ""
+
+msgid "cannot be enabled because parent group has shared Runners disabled"
+msgstr ""
+
msgid "cannot be enabled unless all domains have TLS certificates"
msgstr ""
@@ -29740,7 +30772,7 @@ msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about SAST %{linkEndTag}"
msgstr ""
-msgid "ciReport|%{linkStartTag}Learn more about Secret Scanning %{linkEndTag}"
+msgid "ciReport|%{linkStartTag}Learn more about Secret Detection %{linkEndTag}"
msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about codequality reports %{linkEndTag}"
@@ -30067,9 +31099,6 @@ msgstr ""
msgid "error"
msgstr ""
-msgid "error code:"
-msgstr ""
-
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr ""
@@ -30091,6 +31120,9 @@ msgstr ""
msgid "failed to dismiss associated finding(id=%{finding_id}): %{message}"
msgstr ""
+msgid "failed to revert associated finding(id=%{finding_id}) to detected"
+msgstr ""
+
msgid "file"
msgid_plural "files"
msgstr[0] ""
@@ -30649,6 +31681,9 @@ msgstr ""
msgid "must be a root namespace"
msgstr ""
+msgid "must be a valid IPv4 or IPv6 address"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -30685,6 +31720,9 @@ msgstr ""
msgid "no expiration"
msgstr ""
+msgid "no name set"
+msgstr ""
+
msgid "no one can merge"
msgstr ""
@@ -30883,9 +31921,6 @@ msgstr ""
msgid "security Reports|There was an error creating the merge request"
msgstr ""
-msgid "settings saved, but not activated"
-msgstr ""
-
msgid "severity|Critical"
msgstr ""
@@ -31012,9 +32047,6 @@ msgstr ""
msgid "toggle collapse"
msgstr ""
-msgid "toggle dropdown"
-msgstr ""
-
msgid "triggered"
msgstr ""
@@ -31042,6 +32074,9 @@ msgstr ""
msgid "user avatar"
msgstr ""
+msgid "user preferences"
+msgstr ""
+
msgid "username"
msgstr ""
diff --git a/locale/as_IN/gitlab.po b/locale/as_IN/gitlab.po
index c1ee1e1cfbe..9d2e0d1981a 100644
--- a/locale/as_IN/gitlab.po
+++ b/locale/as_IN/gitlab.po
@@ -14,7 +14,10 @@ msgstr ""
"X-Crowdin-Language: as\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 6\n"
-"PO-Revision-Date: 2020-09-04 23:04\n"
+"PO-Revision-Date: 2020-10-02 18:44\n"
+
+msgid " %{project_name}#%{issue_iid} &middot; opened %{issue_created} by %{author}"
+msgstr ""
msgid " %{start} to %{end}"
msgstr ""
@@ -74,6 +77,16 @@ msgstr ""
msgid "\"el\" parameter is required for createInstance()"
msgstr ""
+msgid "%d Approval"
+msgid_plural "%d Approvals"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d Package"
+msgid_plural "%d Packages"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d Scanned URL"
msgid_plural "%d Scanned URLs"
msgstr[0] ""
@@ -137,6 +150,11 @@ msgstr[1] ""
msgid "%d commits"
msgstr ""
+msgid "%d completed issue"
+msgid_plural "%d completed issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d contribution"
msgid_plural "%d contributions"
msgstr[0] ""
@@ -147,6 +165,11 @@ msgid_plural "%d days"
msgstr[0] ""
msgstr[1] ""
+msgid "%d day until tags are automatically removed"
+msgid_plural "%d days until tags are automatically removed"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d error"
msgid_plural "%d errors"
msgstr[0] ""
@@ -237,6 +260,16 @@ msgid_plural "%d more comments"
msgstr[0] ""
msgstr[1] ""
+msgid "%d open issue"
+msgid_plural "%d open issues"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d pending comment"
+msgid_plural "%d pending comments"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d personal project will be removed and cannot be restored."
msgid_plural "%d personal projects will be removed and cannot be restored."
msgstr[0] ""
@@ -252,6 +285,11 @@ msgid_plural "%d projects"
msgstr[0] ""
msgstr[1] ""
+msgid "%d project selected"
+msgid_plural "%d projects selected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d request with warnings"
msgid_plural "%d requests with warnings"
msgstr[0] ""
@@ -272,6 +310,11 @@ msgid_plural "%d tags"
msgstr[0] ""
msgstr[1] ""
+msgid "%d tag per image name"
+msgid_plural "%d tags per image name"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d unassigned issue"
msgid_plural "%d unassigned issues"
msgstr[0] ""
@@ -292,6 +335,11 @@ msgid_plural "%d vulnerabilities dismissed"
msgstr[0] ""
msgstr[1] ""
+msgid "%d warning found:"
+msgid_plural "%d warnings found:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%s additional commit has been omitted to prevent performance issues."
msgid_plural "%s additional commits have been omitted to prevent performance issues."
msgstr[0] ""
@@ -330,6 +378,9 @@ msgstr ""
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr ""
+msgid "%{completedCount} completed weight"
+msgstr ""
+
msgid "%{completedWeight} of %{totalWeight} weight completed"
msgstr ""
@@ -378,14 +429,12 @@ msgid_plural "%{count} participants"
msgstr[0] ""
msgstr[1] ""
-msgid "%{count} pending comment"
-msgid_plural "%{count} pending comments"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
+msgid "%{count} total weight"
+msgstr ""
+
msgid "%{dashboard_path} could not be found."
msgstr ""
@@ -440,6 +489,9 @@ msgstr ""
msgid "%{group_name} uses group managed accounts. You need to create a new GitLab account which will be managed by %{group_name}."
msgstr ""
+msgid "%{group_name}&%{epic_iid} &middot; opened %{epic_created} by %{author}"
+msgstr ""
+
msgid "%{host} sign-in from new location"
msgstr ""
@@ -452,7 +504,7 @@ msgstr ""
msgid "%{issuableType} will be removed! Are you sure?"
msgstr ""
-msgid "%{issuesSize} issues with a limit of %{maxIssueCount}"
+msgid "%{issuesCount} issues with a limit of %{maxIssueCount}"
msgstr ""
msgid "%{issuesSize} with a limit of %{maxIssueCount}"
@@ -485,7 +537,7 @@ msgstr ""
msgid "%{labelStart}Namespace:%{labelEnd} %{namespace}"
msgstr ""
-msgid "%{labelStart}Report Type:%{labelEnd} %{reportType}"
+msgid "%{labelStart}Scan Type:%{labelEnd} %{reportType}"
msgstr ""
msgid "%{labelStart}Scanner:%{labelEnd} %{scanner}"
@@ -682,9 +734,6 @@ msgid_plural "%{securityScanner} results are not available because a pipeline ha
msgstr[0] ""
msgstr[1] ""
-msgid "%{service_title} %{message}."
-msgstr ""
-
msgid "%{size} GiB"
msgstr ""
@@ -773,6 +822,12 @@ msgstr ""
msgid "%{timebox_name} should belong either to a project or a group."
msgstr ""
+msgid "%{timebox_type} does not support burnup charts"
+msgstr ""
+
+msgid "%{timebox_type} must have a start and due date"
+msgstr ""
+
msgid "%{title} %{operator} %{threshold}"
msgstr ""
@@ -797,7 +852,7 @@ msgstr ""
msgid "%{total} open issue weight"
msgstr ""
-msgid "%{total} open issues"
+msgid "%{total} warnings found: showing first %{warningsDisplayed}"
msgstr ""
msgid "%{usage_ping_link_start}Learn more%{usage_ping_link_end} about what information is shared with GitLab Inc."
@@ -830,9 +885,6 @@ msgstr ""
msgid "&lt; 1 hour"
msgstr ""
-msgid "&lt;no name set&gt;"
-msgstr ""
-
msgid "&lt;no scopes selected&gt;"
msgstr ""
@@ -863,6 +915,9 @@ msgstr ""
msgid "'%{name}' Value Stream created"
msgstr ""
+msgid "'%{name}' Value Stream deleted"
+msgstr ""
+
msgid "'%{name}' stage already exists"
msgstr ""
@@ -922,6 +977,9 @@ msgstr ""
msgid "+ %{numberOfHiddenAssignees} more"
msgstr ""
+msgid "+ %{numberOfHiddenReviewers} more"
+msgstr ""
+
msgid "+%d more"
msgid_plural "+%d more"
msgstr[0] ""
@@ -982,6 +1040,11 @@ msgid_plural "%d Days"
msgstr[0] ""
msgstr[1] ""
+msgid "1 Issue"
+msgid_plural "%d Issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "1 closed issue"
msgid_plural "%{issues} closed issues"
msgstr[0] ""
@@ -997,6 +1060,11 @@ msgid_plural "%d days"
msgstr[0] ""
msgstr[1] ""
+msgid "1 deploy key"
+msgid_plural "%d deploy keys"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1099,6 +1167,9 @@ msgstr ""
msgid ":%{startLine} to %{endLine}"
msgstr ""
+msgid "A %{incident_docs_start}modified issue%{incident_docs_end} to guide the resolution of incidents."
+msgstr ""
+
msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr ""
@@ -1111,6 +1182,9 @@ msgstr ""
msgid "A GitBook site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
+msgid "A Gitpod configured Webapplication in Spring and Java"
+msgstr ""
+
msgid "A Hexo site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
@@ -1282,9 +1356,15 @@ msgstr ""
msgid "Access expiration date"
msgstr ""
+msgid "Access expires"
+msgstr ""
+
msgid "Access forbidden. Check your access level."
msgstr ""
+msgid "Access granted"
+msgstr ""
+
msgid "Access requests"
msgstr ""
@@ -1294,6 +1374,9 @@ msgstr ""
msgid "Access to Pages websites are controlled based on the user's membership to a given project. By checking this box, users will be required to be logged in to have access to all Pages websites in your instance."
msgstr ""
+msgid "AccessDropdown|Deploy Keys"
+msgstr ""
+
msgid "AccessDropdown|Groups"
msgstr ""
@@ -1411,12 +1494,6 @@ msgstr ""
msgid "Active Sessions"
msgstr ""
-msgid "Active Users:"
-msgstr ""
-
-msgid "Active users"
-msgstr ""
-
msgid "Activity"
msgstr ""
@@ -1584,9 +1661,6 @@ msgstr ""
msgid "Add label(s)"
msgstr ""
-msgid "Add license"
-msgstr ""
-
msgid "Add list"
msgstr ""
@@ -1761,21 +1835,51 @@ msgstr ""
msgid "AdminArea|Bots"
msgstr ""
+msgid "AdminArea|Components"
+msgstr ""
+
msgid "AdminArea|Developer"
msgstr ""
+msgid "AdminArea|Features"
+msgstr ""
+
+msgid "AdminArea|Groups: %{number_of_groups}"
+msgstr ""
+
msgid "AdminArea|Guest"
msgstr ""
msgid "AdminArea|Included Free in license"
msgstr ""
+msgid "AdminArea|Latest groups"
+msgstr ""
+
+msgid "AdminArea|Latest projects"
+msgstr ""
+
+msgid "AdminArea|Latest users"
+msgstr ""
+
msgid "AdminArea|Maintainer"
msgstr ""
+msgid "AdminArea|New group"
+msgstr ""
+
+msgid "AdminArea|New project"
+msgstr ""
+
+msgid "AdminArea|New user"
+msgstr ""
+
msgid "AdminArea|Owner"
msgstr ""
+msgid "AdminArea|Projects: %{number_of_projects}"
+msgstr ""
+
msgid "AdminArea|Reporter"
msgstr ""
@@ -1803,6 +1907,9 @@ msgstr ""
msgid "AdminArea|Users without a Group and Project"
msgstr ""
+msgid "AdminArea|Users: %{number_of_users}"
+msgstr ""
+
msgid "AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running."
msgstr ""
@@ -1821,9 +1928,6 @@ msgstr ""
msgid "AdminProjects|Delete Project %{projectName}?"
msgstr ""
-msgid "AdminProjects|Delete project"
-msgstr ""
-
msgid "AdminSettings|Apply integration settings to all Projects"
msgstr ""
@@ -2061,21 +2165,30 @@ msgstr ""
msgid "AdminUsers|Without projects"
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 ""
msgid "AdminUsers|You cannot remove your own admin rights."
msgstr ""
+msgid "AdminUsers|You must transfer ownership or delete the groups owned by this user before you can delete their account"
+msgstr ""
+
msgid "Administration"
msgstr ""
msgid "Advanced"
msgstr ""
+msgid "Advanced Search"
+msgstr ""
+
+msgid "Advanced Search with Elasticsearch"
+msgstr ""
+
msgid "Advanced Settings"
msgstr ""
@@ -2153,6 +2266,9 @@ msgstr ""
msgid "AlertManagement|Edit"
msgstr ""
+msgid "AlertManagement|Environment"
+msgstr ""
+
msgid "AlertManagement|Events"
msgstr ""
@@ -2165,6 +2281,9 @@ msgstr ""
msgid "AlertManagement|Issue"
msgstr ""
+msgid "AlertManagement|Key"
+msgstr ""
+
msgid "AlertManagement|Low"
msgstr ""
@@ -2258,6 +2377,9 @@ msgstr ""
msgid "AlertManagement|Unknown"
msgstr ""
+msgid "AlertManagement|Value"
+msgstr ""
+
msgid "AlertManagement|View alerts in Opsgenie"
msgstr ""
@@ -2417,6 +2539,9 @@ msgstr ""
msgid "All projects"
msgstr ""
+msgid "All projects selected"
+msgstr ""
+
msgid "All security scans are enabled because %{linkStart}Auto DevOps%{linkEnd} is enabled on this project"
msgstr ""
@@ -2504,6 +2629,9 @@ msgstr ""
msgid "Almost there"
msgstr ""
+msgid "Already blocked"
+msgstr ""
+
msgid "Also called \"Issuer\" or \"Relying party trust identifier\""
msgstr ""
@@ -2558,6 +2686,9 @@ msgstr ""
msgid "An error has occurred"
msgstr ""
+msgid "An error occured while making the changes: %{error}"
+msgstr ""
+
msgid "An error occurred adding a draft to the thread."
msgstr ""
@@ -2585,12 +2716,6 @@ msgstr ""
msgid "An error occurred when toggling the notification subscription"
msgstr ""
-msgid "An error occurred when trying to resolve a comment. Please try again."
-msgstr ""
-
-msgid "An error occurred when trying to resolve a discussion. Please try again."
-msgstr ""
-
msgid "An error occurred when updating the issue weight"
msgstr ""
@@ -2606,12 +2731,6 @@ msgstr ""
msgid "An error occurred while checking group path. Please refresh and try again."
msgstr ""
-msgid "An error occurred while committing your changes."
-msgstr ""
-
-msgid "An error occurred while creating the list. Please try again."
-msgstr ""
-
msgid "An error occurred while decoding the file."
msgstr ""
@@ -2684,25 +2803,19 @@ msgstr ""
msgid "An error occurred while fetching the Service Desk address."
msgstr ""
-msgid "An error occurred while fetching the board issues. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the board lists. Please reload the page."
msgstr ""
msgid "An error occurred while fetching the board lists. Please try again."
msgstr ""
-msgid "An error occurred while fetching the board swimlanes. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the builds."
msgstr ""
msgid "An error occurred while fetching the job log."
msgstr ""
-msgid "An error occurred while fetching the job trace."
+msgid "An error occurred while fetching the job logs."
msgstr ""
msgid "An error occurred while fetching the job."
@@ -2849,9 +2962,6 @@ msgstr ""
msgid "An error occurred while saving assignees"
msgstr ""
-msgid "An error occurred while saving the template. Please check if the template exists."
-msgstr ""
-
msgid "An error occurred while searching for milestones"
msgstr ""
@@ -2870,10 +2980,10 @@ msgstr ""
msgid "An error occurred while updating approvers"
msgstr ""
-msgid "An error occurred while updating the comment"
+msgid "An error occurred while updating labels."
msgstr ""
-msgid "An error occurred while updating the list. Please try again."
+msgid "An error occurred while updating the comment"
msgstr ""
msgid "An error occurred while validating group path"
@@ -2927,6 +3037,9 @@ msgstr ""
msgid "An unknown error occurred while loading this graph."
msgstr ""
+msgid "An unknown error occurred."
+msgstr ""
+
msgid "Analytics"
msgstr ""
@@ -2960,10 +3073,10 @@ msgstr ""
msgid "Any"
msgstr ""
-msgid "Any Author"
+msgid "Any %{header}"
msgstr ""
-msgid "Any Status"
+msgid "Any Author"
msgstr ""
msgid "Any branch"
@@ -3017,6 +3130,9 @@ msgstr ""
msgid "Application ID"
msgstr ""
+msgid "Application limits saved successfully"
+msgstr ""
+
msgid "Application settings saved successfully"
msgstr ""
@@ -3226,6 +3342,9 @@ msgstr ""
msgid "Are you sure you want to close this blocked issue?"
msgstr ""
+msgid "Are you sure you want to delete \"%{name}\" Value Stream?"
+msgstr ""
+
msgid "Are you sure you want to delete %{name}?"
msgstr ""
@@ -3235,6 +3354,9 @@ msgstr ""
msgid "Are you sure you want to delete this %{typeOfComment}?"
msgstr ""
+msgid "Are you sure you want to delete this SSH key?"
+msgstr ""
+
msgid "Are you sure you want to delete this board?"
msgstr ""
@@ -3259,6 +3381,11 @@ msgstr ""
msgid "Are you sure you want to erase this build?"
msgstr ""
+msgid "Are you sure you want to import %d repository?"
+msgid_plural "Are you sure you want to import %d repositories?"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Are you sure you want to lose unsaved changes?"
msgstr ""
@@ -3268,15 +3395,15 @@ msgstr ""
msgid "Are you sure you want to merge immediately?"
msgstr ""
-msgid "Are you sure you want to permanently delete this license?"
-msgstr ""
-
msgid "Are you sure you want to re-deploy this environment?"
msgstr ""
msgid "Are you sure you want to regenerate the public key? You will have to update the public key on the remote server before mirroring will work again."
msgstr ""
+msgid "Are you sure you want to reindex?"
+msgstr ""
+
msgid "Are you sure you want to remove %{group_name}?"
msgstr ""
@@ -3304,6 +3431,9 @@ msgstr ""
msgid "Are you sure you want to revoke this nickname?"
msgstr ""
+msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
+msgstr ""
+
msgid "Are you sure you want to stop this environment?"
msgstr ""
@@ -3325,6 +3455,9 @@ msgstr ""
msgid "Are you sure? The device will be signed out of GitLab and all remember me tokens revoked."
msgstr ""
+msgid "Are you sure? This will invalidate your registered applications and U2F / WebAuthn devices."
+msgstr ""
+
msgid "Are you sure? This will invalidate your registered applications and U2F devices."
msgstr ""
@@ -3343,9 +3476,6 @@ msgstr ""
msgid "Artifacts"
msgstr ""
-msgid "As U2F devices are only supported by a few browsers, we require that you set up a two-factor authentication app before a U2F device. That way you'll always be able to log in - even when you're using an unsupported browser."
-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 ""
@@ -3539,6 +3669,9 @@ msgstr ""
msgid "AuditLogs|Target"
msgstr ""
+msgid "AuditLogs|This month"
+msgstr ""
+
msgid "AuditLogs|User Events"
msgstr ""
@@ -3578,6 +3711,9 @@ msgstr ""
msgid "Authentication via U2F device failed."
msgstr ""
+msgid "Authentication via WebAuthn device failed."
+msgstr ""
+
msgid "Author"
msgstr ""
@@ -3845,15 +3981,6 @@ msgstr ""
msgid "BambooService|You must set up automatic revision labeling and a repository trigger in Bamboo."
msgstr ""
-msgid "BatchComments|Delete all pending comments"
-msgstr ""
-
-msgid "BatchComments|Discard review?"
-msgstr ""
-
-msgid "BatchComments|You're about to discard your review which will delete all of your pending comments. The deleted comments %{strong_start}cannot%{strong_end} be restored."
-msgstr ""
-
msgid "Be careful. Changing the project's namespace can have unintended side effects."
msgstr ""
@@ -3875,6 +4002,9 @@ msgstr ""
msgid "Bi-weekly code coverage"
msgstr ""
+msgid "Billable Users:"
+msgstr ""
+
msgid "Billing"
msgstr ""
@@ -3884,7 +4014,7 @@ msgstr ""
msgid "BillingPlans|@%{user_name} you are currently using the %{plan_name} plan."
msgstr ""
-msgid "BillingPlans|Congratulations, your new trial is activated"
+msgid "BillingPlans|Congratulations, your free trial is activated."
msgstr ""
msgid "BillingPlans|If you would like to downgrade your plan please contact %{support_link_start}Customer Support%{support_link_end}."
@@ -3947,6 +4077,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Block user"
+msgstr ""
+
msgid "Blocked"
msgstr ""
@@ -3962,31 +4095,37 @@ msgstr ""
msgid "Blog"
msgstr ""
-msgid "Board name"
-msgstr ""
-
msgid "Board scope"
msgstr ""
msgid "Board scope affects which issues are displayed for anyone who visits this board"
msgstr ""
-msgid "BoardBlankState|Add default lists"
+msgid "Boards"
msgstr ""
-msgid "BoardBlankState|Add the following default lists to your Issue Board with one click:"
+msgid "Boards and Board Lists"
msgstr ""
-msgid "BoardBlankState|Nevermind, I'll use my own"
+msgid "Boards|An error occurred while creating the issue. Please try again."
msgstr ""
-msgid "BoardBlankState|Starting out with the default set of lists will get you right on the way to making the most of your board."
+msgid "Boards|An error occurred while creating the list. Please try again."
msgstr ""
-msgid "Boards"
+msgid "Boards|An error occurred while fetching issues. Please reload the page."
msgstr ""
-msgid "Boards and Board Lists"
+msgid "Boards|An error occurred while fetching the board issues. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching the board swimlanes. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while moving the issue. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while updating the list. Please try again."
msgstr ""
msgid "Boards|Collapse"
@@ -4013,7 +4152,7 @@ msgstr ""
msgid "Branch %{branch_name} was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr ""
-msgid "Branch has changed"
+msgid "Branch changed"
msgstr ""
msgid "Branch is already taken"
@@ -4319,6 +4458,9 @@ msgstr ""
msgid "CLOSED (MOVED)"
msgstr ""
+msgid "CODEOWNERS rule violation"
+msgstr ""
+
msgid "CONTRIBUTING"
msgstr ""
@@ -4349,9 +4491,6 @@ msgstr ""
msgid "Can't create snippet: %{err}"
msgstr ""
-msgid "Can't edit as source branch was deleted"
-msgstr ""
-
msgid "Can't fetch content for the blob: %{err}"
msgstr ""
@@ -4364,9 +4503,6 @@ msgstr ""
msgid "Can't load mermaid module: %{err}"
msgstr ""
-msgid "Can't remove group members without group managed account"
-msgstr ""
-
msgid "Can't scan the code?"
msgstr ""
@@ -4409,6 +4545,9 @@ msgstr ""
msgid "Cannot create the abuse report. This user has been blocked."
msgstr ""
+msgid "Cannot enable shared runners because parent group does not allow it"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -4514,6 +4653,15 @@ msgstr ""
msgid "Change your password or recover your current one"
msgstr ""
+msgid "ChangeReviewer|Reviewer changed from %{old} to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Reviewer changed to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Unassigned"
+msgstr ""
+
msgid "ChangeTypeActionLabel|Pick into branch"
msgstr ""
@@ -4553,6 +4701,9 @@ msgstr ""
msgid "Changes the title to \"%{title_param}\"."
msgstr ""
+msgid "Changes were successfully made."
+msgstr ""
+
msgid "Changes won't take place until the index is %{link_start}recreated%{link_end}."
msgstr ""
@@ -4958,6 +5109,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove variable"
+msgstr ""
+
msgid "CiVariables|Remove variable row"
msgstr ""
@@ -5036,9 +5190,6 @@ msgstr ""
msgid "Clear due date"
msgstr ""
-msgid "Clear input"
-msgstr ""
-
msgid "Clear recent searches"
msgstr ""
@@ -5087,6 +5238,9 @@ msgstr ""
msgid "Client authentication key password"
msgstr ""
+msgid "Client request timeout"
+msgstr ""
+
msgid "Clients"
msgstr ""
@@ -5171,6 +5325,27 @@ msgstr ""
msgid "Cluster type must be specificed for Stages::ClusterEndpointInserter"
msgstr ""
+msgid "ClusterAgents|Configuration"
+msgstr ""
+
+msgid "ClusterAgents|Connect your cluster with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate Kubernetes with a GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Name"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Agent also requires %{linkStart}enabling the Agent Server%{linkEnd}"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Kubernetes Agent allows an Infrastructure as Code, GitOps approach to integrating Kubernetes clusters with GitLab. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "ClusterAgent|This feature is only available for premium plans"
msgstr ""
@@ -5240,10 +5415,10 @@ msgstr ""
msgid "ClusterIntegration|All installed applications and related resources"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster."
+msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{linkStart}More information%{linkEnd}"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{startLink}More information%{endLink}"
+msgid "ClusterIntegration|Allow GitLab to manage namespaces and service accounts for this cluster."
msgstr ""
msgid "ClusterIntegration|Alternatively, "
@@ -5264,6 +5439,9 @@ msgstr ""
msgid "ClusterIntegration|An error occurred while trying to fetch zone machine types: %{error}"
msgstr ""
+msgid "ClusterIntegration|An unknown error occurred while attempting to connect to Kubernetes."
+msgstr ""
+
msgid "ClusterIntegration|Any project namespaces"
msgstr ""
@@ -5279,6 +5457,9 @@ msgstr ""
msgid "ClusterIntegration|Authenticate with Amazon Web Services"
msgstr ""
+msgid "ClusterIntegration|Authentication Error"
+msgstr ""
+
msgid "ClusterIntegration|Base domain"
msgstr ""
@@ -5297,13 +5478,22 @@ msgstr ""
msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}security group %{externalLinkIcon} %{endLink} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
+msgid "ClusterIntegration|Check your CA certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Check your cluster status"
+msgstr ""
+
+msgid "ClusterIntegration|Check your token"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}subnets %{externalLinkIcon} %{endLink} in your VPC where your worker nodes will run."
+msgid "ClusterIntegration|Choose the %{linkStart}security group %{linkEnd} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
msgstr ""
-msgid "ClusterIntegration|Choose the worker node %{startLink}instance type %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Choose the %{linkStart}subnets %{linkEnd} in your VPC where your worker nodes will run."
+msgstr ""
+
+msgid "ClusterIntegration|Choose the worker node %{linkStart}instance type%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Choose which applications to install on your Kubernetes cluster."
@@ -5315,10 +5505,7 @@ msgstr ""
msgid "ClusterIntegration|Clear cluster cache"
msgstr ""
-msgid "ClusterIntegration|Clear the local cache of namespace and service accounts. This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
-msgstr ""
-
-msgid "ClusterIntegration|Cluster being created"
+msgid "ClusterIntegration|Clear the local cache of namespace and service accounts."
msgstr ""
msgid "ClusterIntegration|Cluster management project (alpha)"
@@ -5330,15 +5517,21 @@ msgstr ""
msgid "ClusterIntegration|Cluster_applications artifact too big. Maximum allowable size: %{human_size}"
msgstr ""
-msgid "ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters."
+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|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}"
+msgid "ClusterIntegration|Clusters connected with a certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Connect cluster with certificate"
msgstr ""
msgid "ClusterIntegration|Connect existing cluster"
msgstr ""
+msgid "ClusterIntegration|Connection Error"
+msgstr ""
+
msgid "ClusterIntegration|Copy API URL"
msgstr ""
@@ -5414,6 +5607,12 @@ msgstr ""
msgid "ClusterIntegration|Deletes all GitLab resources attached to this cluster during removal"
msgstr ""
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared."
+msgstr ""
+
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared. %{linkStart}More information%{linkEnd}"
+msgstr ""
+
msgid "ClusterIntegration|Did you know?"
msgstr ""
@@ -5483,6 +5682,9 @@ msgstr ""
msgid "ClusterIntegration|Fluentd is an open source data collector, which lets you unify the data collection and consumption for a better use and understanding of data. It requires at least one of the following logs to be successfully installed."
msgstr ""
+msgid "ClusterIntegration|GitLab Agent managed clusters"
+msgstr ""
+
msgid "ClusterIntegration|GitLab Container Network Policies"
msgstr ""
@@ -5495,6 +5697,12 @@ msgstr ""
msgid "ClusterIntegration|GitLab Runner connects to the repository and executes CI/CD jobs, pushing results back and deploying applications to production."
msgstr ""
+msgid "ClusterIntegration|GitLab failed to authenticate."
+msgstr ""
+
+msgid "ClusterIntegration|GitLab failed to connect to the cluster."
+msgstr ""
+
msgid "ClusterIntegration|GitLab-managed cluster"
msgstr ""
@@ -5516,6 +5724,9 @@ msgstr ""
msgid "ClusterIntegration|Group cluster"
msgstr ""
+msgid "ClusterIntegration|HTTP Error"
+msgstr ""
+
msgid "ClusterIntegration|Helm Tiller"
msgstr ""
@@ -5549,7 +5760,10 @@ msgstr ""
msgid "ClusterIntegration|Instance type"
msgstr ""
-msgid "ClusterIntegration|Integrate Kubernetes cluster automation"
+msgid "ClusterIntegration|Integrate Kubernetes with a cluster certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Integrate with a cluster certificate"
msgstr ""
msgid "ClusterIntegration|Issuer Email"
@@ -5585,9 +5799,6 @@ msgstr ""
msgid "ClusterIntegration|Knative extends Kubernetes to provide a set of middleware components that are essential to build modern, source-centric, and container-based applications that can run anywhere: on premises, in the cloud, or even in a third-party data center."
msgstr ""
-msgid "ClusterIntegration|Kubernetes cluster"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes cluster is being created..."
msgstr ""
@@ -5600,9 +5811,6 @@ msgstr ""
msgid "ClusterIntegration|Kubernetes clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr ""
-msgid "ClusterIntegration|Kubernetes clusters can be used to deploy applications and to provide Review Apps for this project"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes version"
msgstr ""
@@ -5615,7 +5823,7 @@ msgstr ""
msgid "ClusterIntegration|Learn more about %{help_link_start}zones%{help_link_end}."
msgstr ""
-msgid "ClusterIntegration|Learn more about %{startLink}Regions %{externalLinkIcon}%{endLink}."
+msgid "ClusterIntegration|Learn more about %{linkStart}Regions%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Learn more about Kubernetes"
@@ -5660,12 +5868,18 @@ msgstr ""
msgid "ClusterIntegration|Machine type"
msgstr ""
+msgid "ClusterIntegration|Make sure your API endpoint is correct"
+msgstr ""
+
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create Kubernetes clusters"
msgstr ""
msgid "ClusterIntegration|Manage your Kubernetes cluster by visiting %{provider_link}"
msgstr ""
+msgid "ClusterIntegration|Namespace per environment"
+msgstr ""
+
msgid "ClusterIntegration|No IAM Roles found"
msgstr ""
@@ -5711,6 +5925,9 @@ msgstr ""
msgid "ClusterIntegration|No zones matched your search"
msgstr ""
+msgid "ClusterIntegration|Node calculations use the Kubernetes Metrics API. Make sure your cluster has metrics installed"
+msgstr ""
+
msgid "ClusterIntegration|Number of nodes"
msgstr ""
@@ -5753,6 +5970,9 @@ msgstr ""
msgid "ClusterIntegration|RBAC-enabled cluster"
msgstr ""
+msgid "ClusterIntegration|Read our %{linkStart}help page%{linkEnd} on Kubernetes cluster integration."
+msgstr ""
+
msgid "ClusterIntegration|Read our %{link_start}help page%{link_end} on Kubernetes cluster integration."
msgstr ""
@@ -5855,7 +6075,7 @@ msgstr ""
msgid "ClusterIntegration|Select a VPC to choose a subnet"
msgstr ""
-msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{linkStart}Amazon Web Services %{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select a network to choose a subnetwork"
@@ -5888,7 +6108,7 @@ msgstr ""
msgid "ClusterIntegration|Select project to choose zone"
msgstr ""
-msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select zone"
@@ -5978,9 +6198,18 @@ msgstr ""
msgid "ClusterIntegration|There was a problem authenticating with your cluster. Please ensure your CA Certificate and Token are valid."
msgstr ""
+msgid "ClusterIntegration|There was an HTTP error when connecting to your cluster."
+msgstr ""
+
msgid "ClusterIntegration|This account must have permissions to create a Kubernetes cluster in the %{link_to_container_project} specified below"
msgstr ""
+msgid "ClusterIntegration|This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
+msgstr ""
+
+msgid "ClusterIntegration|This is necessary to clear existing environment-namespace associations from clusters previously managed by GitLab."
+msgstr ""
+
msgid "ClusterIntegration|This option will allow you to install applications on RBAC clusters."
msgstr ""
@@ -6005,9 +6234,21 @@ msgstr ""
msgid "ClusterIntegration|To use a new project, first create one on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}."
msgstr ""
+msgid "ClusterIntegration|Troubleshooting tips:"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Authenticate"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Connect"
+msgstr ""
+
msgid "ClusterIntegration|Uninstall %{appTitle}"
msgstr ""
+msgid "ClusterIntegration|Unknown Error"
+msgstr ""
+
msgid "ClusterIntegration|Update %{appTitle}"
msgstr ""
@@ -6068,7 +6309,7 @@ msgstr ""
msgid "ClusterIntegration|Your cluster API is unreachable. Please ensure your API URL is correct."
msgstr ""
-msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Zone"
@@ -6188,6 +6429,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse all threads"
+msgstr ""
+
msgid "Collapse approvers"
msgstr ""
@@ -6337,7 +6581,7 @@ msgstr ""
msgid "Commit…"
msgstr ""
-msgid "Company"
+msgid "Community forum"
msgstr ""
msgid "Company name"
@@ -6346,6 +6590,9 @@ msgstr ""
msgid "Compare"
msgstr ""
+msgid "Compare %{oldCommitId}...%{newCommitId}"
+msgstr ""
+
msgid "Compare Git revisions"
msgstr ""
@@ -6361,6 +6608,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare submodule commit revisions"
+msgstr ""
+
msgid "Compare with previous version"
msgstr ""
@@ -6496,6 +6746,9 @@ msgstr ""
msgid "Configure the way a user creates a new account."
msgstr ""
+msgid "Configure which lists are shown for anyone who visits this board"
+msgstr ""
+
msgid "Confirm"
msgstr ""
@@ -6721,6 +6974,9 @@ msgstr[1] ""
msgid "ContainerRegistry|Set cleanup policy"
msgstr ""
+msgid "ContainerRegistry|Some tags were not deleted"
+msgstr ""
+
msgid "ContainerRegistry|Something went wrong while fetching the cleanup policy."
msgstr ""
@@ -6760,6 +7016,9 @@ msgstr ""
msgid "ContainerRegistry|Tags with names matching this regex pattern will %{italicStart}expire:%{italicEnd}"
msgstr ""
+msgid "ContainerRegistry|The cleanup policy timed out before it could delete all tags. An administrator can %{adminLinkStart}manually run cleanup now%{adminLinkEnd} or you can wait for the cleanup policy to automatically run again. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "ContainerRegistry|The last tag related to this image was recently removed. This empty image and any associated data will be automatically removed as part of the regular Garbage Collection process. If you have any questions, contact your administrator."
msgstr ""
@@ -6892,6 +7151,9 @@ msgstr ""
msgid "Contributions per group member"
msgstr ""
+msgid "Contributor"
+msgstr ""
+
msgid "Contributors"
msgstr ""
@@ -7021,6 +7283,9 @@ msgstr ""
msgid "Could not change HEAD: branch '%{branch}' does not exist"
msgstr ""
+msgid "Could not commit. An unexpected error occurred."
+msgstr ""
+
msgid "Could not connect to FogBugz, check your URL"
msgstr ""
@@ -7060,6 +7325,9 @@ msgstr ""
msgid "Could not find iteration"
msgstr ""
+msgid "Could not load instance counts. Please refresh the page to try again."
+msgstr ""
+
msgid "Could not remove the trigger."
msgstr ""
@@ -7084,10 +7352,10 @@ msgstr ""
msgid "Could not save prometheus manual configuration"
msgstr ""
-msgid "Could not udpdate wiki page"
+msgid "Could not update the LDAP settings"
msgstr ""
-msgid "Could not update the LDAP settings"
+msgid "Could not update wiki page"
msgstr ""
msgid "Could not upload your designs as one or more files uploaded are not supported."
@@ -7745,6 +8013,9 @@ msgstr ""
msgid "DastProfiles|Are you sure you want to delete this profile?"
msgstr ""
+msgid "DastProfiles|Could not create site validation token. Please refresh the page, or try again later."
+msgstr ""
+
msgid "DastProfiles|Could not create the scanner profile. Please try again."
msgstr ""
@@ -7769,6 +8040,12 @@ msgstr ""
msgid "DastProfiles|Could not fetch site profiles. Please refresh the page, or try again later."
msgstr ""
+msgid "DastProfiles|Could not retrieve site validation status. Please refresh the page, or try again later."
+msgstr ""
+
+msgid "DastProfiles|Could not update the scanner profile. Please try again."
+msgstr ""
+
msgid "DastProfiles|Could not update the site profile. Please try again."
msgstr ""
@@ -7784,7 +8061,7 @@ msgstr ""
msgid "DastProfiles|Download validation text file"
msgstr ""
-msgid "DastProfiles|Edit feature will come soon. Please create a new profile if changes needed"
+msgid "DastProfiles|Edit scanner profile"
msgstr ""
msgid "DastProfiles|Edit site profile"
@@ -7817,6 +8094,9 @@ msgstr ""
msgid "DastProfiles|No profiles created yet"
msgstr ""
+msgid "DastProfiles|Passive"
+msgstr ""
+
msgid "DastProfiles|Please enter a valid URL format, ex: http://www.example.com/home"
msgstr ""
@@ -7832,6 +8112,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan mode"
+msgstr ""
+
msgid "DastProfiles|Scanner Profile"
msgstr ""
@@ -7871,10 +8154,10 @@ msgstr ""
msgid "DastProfiles|Text file validation"
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
+msgid "DastProfiles|The maximum number of minutes allowed for the spider to traverse the site."
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the spider to traverse the site."
+msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
msgstr ""
msgid "DastProfiles|Validate"
@@ -7907,6 +8190,9 @@ msgstr ""
msgid "Date picker"
msgstr ""
+msgid "Date range"
+msgstr ""
+
msgid "Date range cannot exceed %{maxDateRange} days."
msgstr ""
@@ -7931,6 +8217,9 @@ msgstr ""
msgid "Days to merge"
msgstr ""
+msgid "Dear Administrator,"
+msgstr ""
+
msgid "Debug"
msgstr ""
@@ -8042,12 +8331,18 @@ msgstr ""
msgid "Delete"
msgstr ""
+msgid "Delete %{name}"
+msgstr ""
+
msgid "Delete Comment"
msgstr ""
msgid "Delete Snippet"
msgstr ""
+msgid "Delete Value Stream"
+msgstr ""
+
msgid "Delete account"
msgstr ""
@@ -8069,9 +8364,6 @@ msgstr ""
msgid "Delete label: %{label_name} ?"
msgstr ""
-msgid "Delete license"
-msgstr ""
-
msgid "Delete list"
msgstr ""
@@ -8147,15 +8439,6 @@ msgstr ""
msgid "Deleting a project places it into a read-only state until %{date}, at which point the project will be permanently deleted. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "Deleting the license failed."
-msgstr ""
-
-msgid "Deleting the license failed. The license was not found."
-msgstr ""
-
-msgid "Deleting the license failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "Deleting the project will delete its repository and all related resources including issues, merge requests etc."
msgstr ""
@@ -8651,7 +8934,10 @@ msgstr ""
msgid "DesignManagement|The maximum number of designs allowed to be uploaded is %{upload_limit}. Please try again."
msgstr ""
-msgid "DesignManagement|To upload designs, you'll need to enable LFS. %{requirements_link_start}More information%{requirements_link_end}"
+msgid "DesignManagement|There was an error moving your designs. Please upload your designs below."
+msgstr ""
+
+msgid "DesignManagement|To upload designs, you'll need to enable LFS and have admin enable hashed storage. %{requirements_link_start}More information%{requirements_link_end}"
msgstr ""
msgid "DesignManagement|Unresolve thread"
@@ -8663,6 +8949,9 @@ msgstr ""
msgid "DesignManagement|Upload skipped."
msgstr ""
+msgid "DesignManagement|Your designs are being copied and are on their way… Please refresh to update."
+msgstr ""
+
msgid "DesignManagement|and %{moreCount} more."
msgstr ""
@@ -8720,6 +9009,9 @@ msgstr ""
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
+msgid "Direct member"
+msgstr ""
+
msgid "Direction"
msgstr ""
@@ -8768,9 +9060,6 @@ msgstr ""
msgid "Discard draft"
msgstr ""
-msgid "Discard review"
-msgstr ""
-
msgid "DiscordService|Discord Notifications"
msgstr ""
@@ -8839,10 +9128,10 @@ msgstr ""
msgid "Dismiss Merge Request promotion"
msgstr ""
-msgid "Dismiss Selected"
+msgid "Dismiss Value Stream Analytics introduction box"
msgstr ""
-msgid "Dismiss Value Stream Analytics introduction box"
+msgid "Dismiss selected"
msgstr ""
msgid "Dismiss trial promotion"
@@ -8893,9 +9182,6 @@ msgstr ""
msgid "Documents reindexed: %{processed_documents} (%{percentage}%%)"
msgstr ""
-msgid "Doing"
-msgstr ""
-
msgid "Domain"
msgstr ""
@@ -9091,9 +9377,6 @@ msgstr ""
msgid "Edit environment"
msgstr ""
-msgid "Edit file"
-msgstr ""
-
msgid "Edit files in the editor and commit changes here"
msgstr ""
@@ -9106,6 +9389,12 @@ msgstr ""
msgid "Edit identity for %{user_name}"
msgstr ""
+msgid "Edit in Web IDE"
+msgstr ""
+
+msgid "Edit in single-file editor"
+msgstr ""
+
msgid "Edit issues"
msgstr ""
@@ -9133,10 +9422,10 @@ msgstr ""
msgid "Editing"
msgstr ""
-msgid "Elasticsearch"
+msgid "Elasticsearch AWS IAM credentials"
msgstr ""
-msgid "Elasticsearch AWS IAM credentials"
+msgid "Elasticsearch HTTP client timeout value in seconds."
msgstr ""
msgid "Elasticsearch indexing restrictions"
@@ -9145,9 +9434,6 @@ msgstr ""
msgid "Elasticsearch indexing started"
msgstr ""
-msgid "Elasticsearch integration. Elasticsearch AWS IAM."
-msgstr ""
-
msgid "Elasticsearch reindexing is already in progress"
msgstr ""
@@ -9175,9 +9461,6 @@ msgstr ""
msgid "Email Notification"
msgstr ""
-msgid "Email address"
-msgstr ""
-
msgid "Email could not be sent"
msgstr ""
@@ -9241,6 +9524,9 @@ msgstr ""
msgid "Emails sent from Service Desk will have this name"
msgstr ""
+msgid "Emails sent to %{email} will still be supported"
+msgstr ""
+
msgid "Emails separated by comma"
msgstr ""
@@ -9274,9 +9560,18 @@ msgstr ""
msgid "Enable"
msgstr ""
+msgid "Enable %{link_start}Gitpod%{link_end} integration to launch a development environment in your browser directly from GitLab."
+msgstr ""
+
msgid "Enable Auto DevOps"
msgstr ""
+msgid "Enable Gitpod"
+msgstr ""
+
+msgid "Enable Gitpod?"
+msgstr ""
+
msgid "Enable HTML emails"
msgstr ""
@@ -9406,9 +9701,6 @@ msgstr ""
msgid "Encountered an error while rendering: %{err}"
msgstr ""
-msgid "End date"
-msgstr ""
-
msgid "Ends at (UTC)"
msgstr ""
@@ -9568,7 +9860,7 @@ msgstr ""
msgid "EnvironmentsDashboard|The environments dashboard provides a summary of each project's environments' status, including pipeline and alert statuses."
msgstr ""
-msgid "EnvironmentsDashboard|This dashboard displays a maximum of 7 projects and 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
+msgid "EnvironmentsDashboard|This dashboard displays 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
msgstr ""
msgid "Environments|An error occurred while canceling the auto stop, please try again"
@@ -9889,6 +10181,9 @@ msgstr ""
msgid "Error deleting project. Check logs for error details."
msgstr ""
+msgid "Error fetching burnup chart data"
+msgstr ""
+
msgid "Error fetching diverging counts for branches. Please try again."
msgstr ""
@@ -9967,6 +10262,9 @@ msgstr ""
msgid "Error occurred when saving assignees"
msgstr ""
+msgid "Error occurred when saving reviewers"
+msgstr ""
+
msgid "Error occurred when toggling the notification subscription"
msgstr ""
@@ -10219,10 +10517,13 @@ msgstr ""
msgid "Expand all"
msgstr ""
-msgid "Expand approvers"
+msgid "Expand all files"
msgstr ""
-msgid "Expand dropdown"
+msgid "Expand all threads"
+msgstr ""
+
+msgid "Expand approvers"
msgstr ""
msgid "Expand milestones"
@@ -10393,6 +10694,9 @@ msgstr ""
msgid "Failed to create Merge Request. Please try again."
msgstr ""
+msgid "Failed to create To-Do for the design."
+msgstr ""
+
msgid "Failed to create a branch for this issue. Please try again."
msgstr ""
@@ -10432,6 +10736,12 @@ msgstr ""
msgid "Failed to load authors. Please try again."
msgstr ""
+msgid "Failed to load branches. Please try again."
+msgstr ""
+
+msgid "Failed to load deploy keys."
+msgstr ""
+
msgid "Failed to load emoji list."
msgstr ""
@@ -10447,6 +10757,9 @@ msgstr ""
msgid "Failed to load groups & users."
msgstr ""
+msgid "Failed to load groups, users and deploy keys."
+msgstr ""
+
msgid "Failed to load labels. Please try again."
msgstr ""
@@ -10456,6 +10769,12 @@ msgstr ""
msgid "Failed to load related branches"
msgstr ""
+msgid "Failed to load sidebar confidential toggle"
+msgstr ""
+
+msgid "Failed to load sidebar lock status"
+msgstr ""
+
msgid "Failed to load stacktrace."
msgstr ""
@@ -10483,6 +10802,9 @@ msgstr ""
msgid "Failed to publish issue on status page."
msgstr ""
+msgid "Failed to remove To-Do for the design."
+msgstr ""
+
msgid "Failed to remove a Zoom meeting"
msgstr ""
@@ -10525,6 +10847,9 @@ msgstr ""
msgid "Failed to signing using smartcard authentication"
msgstr ""
+msgid "Failed to toggle To-Do for the design."
+msgstr ""
+
msgid "Failed to update branch!"
msgstr ""
@@ -10638,7 +10963,7 @@ msgstr ""
msgid "FeatureFlags|Edit User List"
msgstr ""
-msgid "FeatureFlags|Enable features for specific users and specific environments by defining feature flag strategies."
+msgid "FeatureFlags|Enable features for specific users and environments by configuring feature flag strategies."
msgstr ""
msgid "FeatureFlags|Environment Spec"
@@ -10698,7 +11023,7 @@ msgstr ""
msgid "FeatureFlags|Include additional user IDs"
msgstr ""
-msgid "FeatureFlags|Install a %{docs_link_anchored_start}compatible client library%{docs_link_anchored_end} and specify the API URL, application name, and instance ID during the configuration setup. %{docs_link_start}More Information%{docs_link_end}"
+msgid "FeatureFlags|Install a %{docsLinkAnchoredStart}compatible client library%{docsLinkAnchoredEnd} and specify the API URL, application name, and instance ID during the configuration setup. %{docsLinkStart}More Information%{docsLinkEnd}"
msgstr ""
msgid "FeatureFlags|Instance ID"
@@ -10710,6 +11035,9 @@ msgstr ""
msgid "FeatureFlags|Loading feature flags"
msgstr ""
+msgid "FeatureFlags|Loading user lists"
+msgstr ""
+
msgid "FeatureFlags|More information"
msgstr ""
@@ -10728,7 +11056,7 @@ msgstr ""
msgid "FeatureFlags|New feature flag"
msgstr ""
-msgid "FeatureFlags|New list"
+msgid "FeatureFlags|New user list"
msgstr ""
msgid "FeatureFlags|Percent of users"
@@ -10767,6 +11095,9 @@ msgstr ""
msgid "FeatureFlags|There was an error fetching the feature flags."
msgstr ""
+msgid "FeatureFlags|There was an error fetching the user lists."
+msgstr ""
+
msgid "FeatureFlags|There was an error retrieving user lists"
msgstr ""
@@ -10782,6 +11113,9 @@ msgstr ""
msgid "FeatureFlags|User List"
msgstr ""
+msgid "FeatureFlags|User Lists"
+msgstr ""
+
msgid "FeatureFlag|List"
msgstr ""
@@ -10809,15 +11143,6 @@ msgstr ""
msgid "Fetching incoming email"
msgstr ""
-msgid "Fetching licenses failed."
-msgstr ""
-
-msgid "Fetching licenses failed. The request endpoint was not found."
-msgstr ""
-
-msgid "Fetching licenses failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "File"
msgstr ""
@@ -10920,12 +11245,21 @@ msgstr ""
msgid "Filter by status"
msgstr ""
+msgid "Filter by test cases that are currently archived."
+msgstr ""
+
+msgid "Filter by test cases that are currently opened."
+msgstr ""
+
msgid "Filter by two-factor authentication"
msgstr ""
msgid "Filter by user"
msgstr ""
+msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
+msgstr ""
+
msgid "Filter pipelines"
msgstr ""
@@ -10941,7 +11275,7 @@ msgstr ""
msgid "Filter results..."
msgstr ""
-msgid "Filter your projects by name"
+msgid "Filter your repositories by name"
msgstr ""
msgid "Filter..."
@@ -10950,7 +11284,7 @@ msgstr ""
msgid "Find File"
msgstr ""
-msgid "Find bugs in your code with coverage-guided fuzzing"
+msgid "Find bugs in your code with coverage-guided fuzzing."
msgstr ""
msgid "Find by path"
@@ -10977,9 +11311,6 @@ msgstr ""
msgid "Finish editing this message first!"
msgstr ""
-msgid "Finish review"
-msgstr ""
-
msgid "Finish setting up your dedicated account for %{group_name}."
msgstr ""
@@ -11049,6 +11380,9 @@ msgstr ""
msgid "Footer message"
msgstr ""
+msgid "For a faster browsing experience, some files are collapsed by default."
+msgstr ""
+
msgid "For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
@@ -11058,6 +11392,9 @@ msgstr ""
msgid "For more info, read the documentation."
msgstr ""
+msgid "For more information on how the number of active users is calculated, see the %{self_managed_subscriptions_doc_link} documentation."
+msgstr ""
+
msgid "For more information, go to the "
msgstr ""
@@ -11196,6 +11533,9 @@ msgstr ""
msgid "Generate new token"
msgstr ""
+msgid "Generic package file size in bytes"
+msgstr ""
+
msgid "Geo"
msgstr ""
@@ -11457,6 +11797,9 @@ msgstr ""
msgid "Geo|Please refer to Geo Troubleshooting."
msgstr ""
+msgid "Geo|Primary node"
+msgstr ""
+
msgid "Geo|Project"
msgstr ""
@@ -11499,6 +11842,9 @@ msgstr ""
msgid "Geo|Review replication status, and resynchronize and reverify items with the primary node."
msgstr ""
+msgid "Geo|Secondary node"
+msgstr ""
+
msgid "Geo|Status"
msgstr ""
@@ -11538,6 +11884,9 @@ msgstr ""
msgid "Geo|URL must be a valid url (ex: https://gitlab.com)"
msgstr ""
+msgid "Geo|Undefined"
+msgstr ""
+
msgid "Geo|Unknown state"
msgstr ""
@@ -11613,10 +11962,16 @@ msgstr ""
msgid "GitHub import"
msgstr ""
+msgid "GitLab"
+msgstr ""
+
msgid "GitLab / Unsubscribe"
msgstr ""
-msgid "GitLab Enterprise Edition %{plan}"
+msgid "GitLab API"
+msgstr ""
+
+msgid "GitLab Billing Team."
msgstr ""
msgid "GitLab Group Runners can execute code for all the projects in this group."
@@ -11628,12 +11983,18 @@ msgstr ""
msgid "GitLab Issue"
msgstr ""
+msgid "GitLab Pages"
+msgstr ""
+
msgid "GitLab Service Desk is a simple way to allow people to create issues in your GitLab instance without needing their own user account. It provides a unique email address for end users to create issues in a project, and replies can be sent either through the GitLab interface or by email. End users will only see the thread through email."
msgstr ""
msgid "GitLab Shared Runners execute code of different projects on the same Runner unless you configure GitLab Runner Autoscale with MaxBuilds 1 (which it is on GitLab.com)."
msgstr ""
+msgid "GitLab Shell"
+msgstr ""
+
msgid "GitLab Support Bot"
msgstr ""
@@ -11643,7 +12004,7 @@ msgstr ""
msgid "GitLab User"
msgstr ""
-msgid "GitLab allows you to continue using your license even if you exceed the number of seats you purchased. You will be required to pay for these seats when you renew your license."
+msgid "GitLab Workhorse"
msgstr ""
msgid "GitLab commit"
@@ -11811,6 +12172,21 @@ msgstr ""
msgid "Gitlab Pages"
msgstr ""
+msgid "Gitpod"
+msgstr ""
+
+msgid "Gitpod|Add the URL to your Gitpod instance configured to read your GitLab projects."
+msgstr ""
+
+msgid "Gitpod|Enable Gitpod integration"
+msgstr ""
+
+msgid "Gitpod|Gitpod URL"
+msgstr ""
+
+msgid "Gitpod|e.g. https://gitpod.example.com"
+msgstr ""
+
msgid "Given access %{time_ago}"
msgstr ""
@@ -12318,9 +12694,6 @@ msgstr ""
msgid "GroupSAML|Valid SAML Response"
msgstr ""
-msgid "GroupSAML|With group managed accounts enabled, all the users without a group managed account will be excluded from the group."
-msgstr ""
-
msgid "GroupSAML|With prohibit outer forks flag enabled group members will be able to fork project only inside your group."
msgstr ""
@@ -12534,10 +12907,10 @@ msgstr ""
msgid "GroupsNew|Create group"
msgstr ""
-msgid "GroupsNew|GitLab group export"
+msgid "GroupsNew|Import"
msgstr ""
-msgid "GroupsNew|Import"
+msgid "GroupsNew|Import a GitLab group export file"
msgstr ""
msgid "GroupsNew|Import group"
@@ -12680,6 +13053,9 @@ msgid_plural "Hide charts"
msgstr[0] ""
msgstr[1] ""
+msgid "Hide comments on this file"
+msgstr ""
+
msgid "Hide details"
msgstr ""
@@ -12724,6 +13100,15 @@ msgstr ""
msgid "Highest role:"
msgstr ""
+msgid "HighlightBar|Alert events:"
+msgstr ""
+
+msgid "HighlightBar|Alert start time:"
+msgstr ""
+
+msgid "HighlightBar|Original alert:"
+msgstr ""
+
msgid "History"
msgstr ""
@@ -12901,6 +13286,9 @@ msgstr ""
msgid "If enabled, access to projects will be validated on an external service using their classification label."
msgstr ""
+msgid "If the number of active users exceeds the user limit, you will be charged for the number of %{users_over_license_link} at your next license reconciliation."
+msgstr ""
+
msgid "If there is no previous license or if the previous license has expired, some GitLab functionality will be blocked until a new, valid license is uploaded."
msgstr ""
@@ -12940,9 +13328,6 @@ msgstr ""
msgid "If your HTTP repository is not publicly accessible, add your credentials."
msgstr ""
-msgid "Iglu registry URL (optional)"
-msgstr ""
-
msgid "Ignore"
msgstr ""
@@ -12979,6 +13364,16 @@ msgstr ""
msgid "Import"
msgstr ""
+msgid "Import %d compatible repository"
+msgid_plural "Import %d compatible repositories"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Import %d repository"
+msgid_plural "Import %d repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Import CSV"
msgstr ""
@@ -12988,15 +13383,9 @@ msgstr ""
msgid "Import all compatible projects"
msgstr ""
-msgid "Import all compatible repositories"
-msgstr ""
-
msgid "Import all projects"
msgstr ""
-msgid "Import all repositories"
-msgstr ""
-
msgid "Import an exported GitLab project"
msgstr ""
@@ -13084,6 +13473,9 @@ msgstr ""
msgid "ImportProjects|Error importing repository %{project_safe_import_url} into %{project_full_path} - %{message}"
msgstr ""
+msgid "ImportProjects|Import repositories"
+msgstr ""
+
msgid "ImportProjects|Importing the project failed"
msgstr ""
@@ -13096,7 +13488,7 @@ msgstr ""
msgid "ImportProjects|Requesting your %{provider} repositories failed"
msgstr ""
-msgid "ImportProjects|Select the projects you want to import"
+msgid "ImportProjects|Select the repositories you want to import"
msgstr ""
msgid "ImportProjects|The remote data could not be imported."
@@ -13132,9 +13524,6 @@ msgstr ""
msgid "In order to enable Service Desk for your instance, you must first set up incoming email."
msgstr ""
-msgid "In order to gather accurate feature usage data, it can take 1 to 2 weeks to see your index."
-msgstr ""
-
msgid "In order to personalize your experience with GitLab%{br_tag}we would like to know a bit more about you."
msgstr ""
@@ -13165,18 +13554,30 @@ msgstr ""
msgid "IncidentManagement|Create incident"
msgstr ""
+msgid "IncidentManagement|Critical - S1"
+msgstr ""
+
msgid "IncidentManagement|Date created"
msgstr ""
msgid "IncidentManagement|Display your incidents in a dedicated view"
msgstr ""
+msgid "IncidentManagement|High - S2"
+msgstr ""
+
msgid "IncidentManagement|Incident"
msgstr ""
msgid "IncidentManagement|Incidents"
msgstr ""
+msgid "IncidentManagement|Low - S4"
+msgstr ""
+
+msgid "IncidentManagement|Medium - S3"
+msgstr ""
+
msgid "IncidentManagement|No incidents to display."
msgstr ""
@@ -13189,6 +13590,9 @@ msgstr ""
msgid "IncidentManagement|Published to status page"
msgstr ""
+msgid "IncidentManagement|Severity"
+msgstr ""
+
msgid "IncidentManagement|There are no closed incidents"
msgstr ""
@@ -13198,6 +13602,9 @@ msgstr ""
msgid "IncidentManagement|Unassigned"
msgstr ""
+msgid "IncidentManagement|Unknown"
+msgstr ""
+
msgid "IncidentManagement|Unpublished"
msgstr ""
@@ -13219,6 +13626,15 @@ msgstr ""
msgid "Incidents"
msgstr ""
+msgid "Incident|Alert details"
+msgstr ""
+
+msgid "Incident|Summary"
+msgstr ""
+
+msgid "Incident|There was an issue loading alert data. Please try again."
+msgstr ""
+
msgid "Include a Terms of Service agreement and Privacy Policy that all users must accept."
msgstr ""
@@ -13279,6 +13695,9 @@ msgstr ""
msgid "Information about additional Pages templates and how to install them can be found in our %{pages_getting_started_guide}."
msgstr ""
+msgid "Inherited"
+msgstr ""
+
msgid "Inherited:"
msgstr ""
@@ -13359,7 +13778,22 @@ msgstr ""
msgid "Instance administrators group already exists"
msgstr ""
-msgid "Instance license"
+msgid "InstanceStatistics|Groups"
+msgstr ""
+
+msgid "InstanceStatistics|Issues"
+msgstr ""
+
+msgid "InstanceStatistics|Merge Requests"
+msgstr ""
+
+msgid "InstanceStatistics|Pipelines"
+msgstr ""
+
+msgid "InstanceStatistics|Projects"
+msgstr ""
+
+msgid "InstanceStatistics|Users"
msgstr ""
msgid "Integration"
@@ -13371,6 +13805,12 @@ msgstr ""
msgid "Integrations"
msgstr ""
+msgid "Integrations|%{integration} settings saved and active."
+msgstr ""
+
+msgid "Integrations|%{integration} settings saved, but not active."
+msgstr ""
+
msgid "Integrations|All details"
msgstr ""
@@ -13380,6 +13820,12 @@ msgstr ""
msgid "Integrations|Comment settings:"
msgstr ""
+msgid "Integrations|Connection failed. Please check your settings."
+msgstr ""
+
+msgid "Integrations|Connection successful."
+msgstr ""
+
msgid "Integrations|Default settings are inherited from the group level."
msgstr ""
@@ -13395,6 +13841,15 @@ msgstr ""
msgid "Integrations|Includes commit title and branch"
msgstr ""
+msgid "Integrations|Projects using custom settings will not be impacted unless the project owner chooses to use instance-level defaults."
+msgstr ""
+
+msgid "Integrations|Save settings?"
+msgstr ""
+
+msgid "Integrations|Saving will update the default settings for all projects that are not using custom settings."
+msgstr ""
+
msgid "Integrations|Standard"
msgstr ""
@@ -13527,6 +13982,9 @@ msgstr ""
msgid "Invitation"
msgstr ""
+msgid "Invitation declined"
+msgstr ""
+
msgid "Invite"
msgstr ""
@@ -13578,6 +14036,42 @@ 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|%{linkStart}Read more%{linkEnd} about role permissions"
+msgstr ""
+
+msgid "InviteMembersModal|Access expiration date (optional)"
+msgstr ""
+
+msgid "InviteMembersModal|Cancel"
+msgstr ""
+
+msgid "InviteMembersModal|Choose a role permission"
+msgstr ""
+
+msgid "InviteMembersModal|GitLab member or Email address"
+msgstr ""
+
+msgid "InviteMembersModal|Invite"
+msgstr ""
+
+msgid "InviteMembersModal|Invite team members"
+msgstr ""
+
+msgid "InviteMembersModal|Search for members to invite"
+msgstr ""
+
+msgid "InviteMembersModal|User not invited. Feature coming soon!"
+msgstr ""
+
+msgid "InviteMembersModal|Users were succesfully added"
+msgstr ""
+
+msgid "InviteMembersModal|You're inviting members to the %{group_name} group"
+msgstr ""
+
+msgid "InviteMembers|Invite team members"
+msgstr ""
+
msgid "Invited"
msgstr ""
@@ -13632,10 +14126,13 @@ msgstr ""
msgid "Issue cannot be found."
msgstr ""
+msgid "Issue created from vulnerability %{vulnerability_link}"
+msgstr ""
+
msgid "Issue events"
msgstr ""
-msgid "Issue first depoloyed to production"
+msgid "Issue first deployed to production"
msgstr ""
msgid "Issue label"
@@ -13713,6 +14210,9 @@ msgstr ""
msgid "IssueTracker|Custom issue tracker"
msgstr ""
+msgid "IssueTracker|EWM work items tracker"
+msgstr ""
+
msgid "IssueTracker|Redmine issue tracker"
msgstr ""
@@ -13779,6 +14279,9 @@ msgstr ""
msgid "It looks like you have some draft commits in this branch."
msgstr ""
+msgid "It may be several days before you see feature usage data."
+msgstr ""
+
msgid "It must have a header row and at least two columns: the first column is the issue title and the second column is the issue description. The separator is automatically detected."
msgstr ""
@@ -14061,13 +14564,13 @@ msgstr ""
msgid "Join Zoom meeting"
msgstr ""
-msgid "Jul"
+msgid "Joined %{time_ago}"
msgstr ""
-msgid "July"
+msgid "Jul"
msgstr ""
-msgid "Jump to first unresolved thread"
+msgid "July"
msgstr ""
msgid "Jump to next unresolved thread"
@@ -14103,6 +14606,9 @@ msgstr ""
msgid "Keyboard shortcuts"
msgstr ""
+msgid "KeyboardKey|Ctrl+"
+msgstr ""
+
msgid "Keys"
msgstr ""
@@ -14151,6 +14657,9 @@ msgstr ""
msgid "LDAP Synchronization"
msgstr ""
+msgid "LDAP group settings"
+msgstr ""
+
msgid "LDAP settings"
msgstr ""
@@ -14160,6 +14669,9 @@ msgstr ""
msgid "LDAP sync in progress. This could take a few minutes. Refresh the page to see the changes."
msgstr ""
+msgid "LDAP synchronizations"
+msgstr ""
+
msgid "LFS"
msgstr ""
@@ -14240,7 +14752,16 @@ msgid_plural "Last %d days"
msgstr[0] ""
msgstr[1] ""
-msgid "Last %{days} days"
+msgid "Last 2 weeks"
+msgstr ""
+
+msgid "Last 30 days"
+msgstr ""
+
+msgid "Last 60 days"
+msgstr ""
+
+msgid "Last 90 days"
msgstr ""
msgid "Last Accessed On"
@@ -14318,6 +14839,9 @@ msgstr ""
msgid "Last used on:"
msgstr ""
+msgid "Last week"
+msgstr ""
+
msgid "LastCommit|authored"
msgstr ""
@@ -14333,6 +14857,9 @@ msgstr ""
msgid "Latest pipeline for the most recent commit on this branch"
msgstr ""
+msgid "Launch a ready-to-code development environment for your project."
+msgstr ""
+
msgid "Lead"
msgstr ""
@@ -14713,6 +15240,9 @@ msgstr ""
msgid "List of all merge commits"
msgstr ""
+msgid "List options"
+msgstr ""
+
msgid "List settings"
msgstr ""
@@ -14725,9 +15255,6 @@ msgstr ""
msgid "List your Bitbucket Server repositories"
msgstr ""
-msgid "Lists"
-msgstr ""
-
msgid "Live preview"
msgstr ""
@@ -14974,6 +15501,12 @@ msgstr ""
msgid "Mark as done"
msgstr ""
+msgid "Mark as draft"
+msgstr ""
+
+msgid "Mark as ready"
+msgstr ""
+
msgid "Mark as resolved"
msgstr ""
@@ -14995,6 +15528,24 @@ msgstr ""
msgid "Markdown is supported"
msgstr ""
+msgid "MarkdownEditor|Add a link (%{modifierKey}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add a link (%{modifier_key}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifierKey}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifier_key}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifierKey}I)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifier_key}I)"
+msgstr ""
+
msgid "Marked For Deletion At - %{deletion_time}"
msgstr ""
@@ -15079,7 +15630,25 @@ msgstr ""
msgid "Max access level"
msgstr ""
-msgid "Max seats used"
+msgid "Max role"
+msgstr ""
+
+msgid "Max size 15 MB"
+msgstr ""
+
+msgid "Maximum Conan package file size in bytes"
+msgstr ""
+
+msgid "Maximum Maven package file size in bytes"
+msgstr ""
+
+msgid "Maximum NPM package file size in bytes"
+msgstr ""
+
+msgid "Maximum NuGet package file size in bytes"
+msgstr ""
+
+msgid "Maximum PyPI package file size in bytes"
msgstr ""
msgid "Maximum Users:"
@@ -15211,6 +15780,18 @@ msgstr ""
msgid "Members with access to %{strong_start}%{group_name}%{strong_end}"
msgstr ""
+msgid "Members|%{time} by %{user}"
+msgstr ""
+
+msgid "Members|Expired"
+msgstr ""
+
+msgid "Members|No expiration set"
+msgstr ""
+
+msgid "Members|in %{time}"
+msgstr ""
+
msgid "Memory Usage"
msgstr ""
@@ -15397,9 +15978,6 @@ msgstr ""
msgid "MergeRequests|Thread will be unresolved"
msgstr ""
-msgid "MergeRequests|Toggle comments for this file"
-msgstr ""
-
msgid "MergeRequests|View file @ %{commitId}"
msgstr ""
@@ -15460,6 +16038,9 @@ msgstr ""
msgid "Merging immediately isn't recommended as it may negatively impact the existing merge train. Read the %{docsLinkStart}documentation%{docsLinkEnd} for more information."
msgstr ""
+msgid "Message"
+msgstr ""
+
msgid "Messages"
msgstr ""
@@ -15845,18 +16426,12 @@ msgid_plural "Milestones"
msgstr[0] ""
msgstr[1] ""
-msgid "Milestone does not support burnup charts"
-msgstr ""
-
msgid "Milestone lists not available with your current license"
msgstr ""
msgid "Milestone lists show all issues from the selected milestone."
msgstr ""
-msgid "Milestone must have a start and due date"
-msgstr ""
-
msgid "MilestoneSidebar|Closed:"
msgstr ""
@@ -16223,6 +16798,9 @@ msgstr ""
msgid "Namespace"
msgstr ""
+msgid "Namespace ID:"
+msgstr ""
+
msgid "Namespace is empty"
msgstr ""
@@ -16307,6 +16885,9 @@ msgstr ""
msgid "NetworkPolicies|Allow all outbound traffic from %{selector} to %{ruleSelector} on %{ports}"
msgstr ""
+msgid "NetworkPolicies|Are you sure you want to delete this policy? This action cannot be undone."
+msgstr ""
+
msgid "NetworkPolicies|Choose whether to enforce this policy."
msgstr ""
@@ -16316,12 +16897,21 @@ msgstr ""
msgid "NetworkPolicies|Define this policy's location, conditions and actions."
msgstr ""
+msgid "NetworkPolicies|Delete policy"
+msgstr ""
+
+msgid "NetworkPolicies|Delete policy: %{policy}"
+msgstr ""
+
msgid "NetworkPolicies|Deny all traffic"
msgstr ""
msgid "NetworkPolicies|Description"
msgstr ""
+msgid "NetworkPolicies|Edit policy"
+msgstr ""
+
msgid "NetworkPolicies|Editor mode"
msgstr ""
@@ -16349,6 +16939,9 @@ msgstr ""
msgid "NetworkPolicies|Name"
msgstr ""
+msgid "NetworkPolicies|Namespace"
+msgstr ""
+
msgid "NetworkPolicies|Network Policy"
msgstr ""
@@ -16400,6 +16993,9 @@ msgstr ""
msgid "NetworkPolicies|Rules"
msgstr ""
+msgid "NetworkPolicies|Save changes"
+msgstr ""
+
msgid "NetworkPolicies|Something went wrong, failed to update policy"
msgstr ""
@@ -16412,6 +17008,9 @@ msgstr ""
msgid "NetworkPolicies|Traffic that does not match any rule will be blocked."
msgstr ""
+msgid "NetworkPolicies|Unable to parse policy"
+msgstr ""
+
msgid "NetworkPolicies|YAML editor"
msgstr ""
@@ -16525,6 +17124,9 @@ msgstr ""
msgid "New Snippet"
msgstr ""
+msgid "New Test Case"
+msgstr ""
+
msgid "New User"
msgstr ""
@@ -16624,6 +17226,9 @@ msgstr ""
msgid "New tag"
msgstr ""
+msgid "New test case"
+msgstr ""
+
msgid "New users set to external"
msgstr ""
@@ -16696,7 +17301,7 @@ msgstr ""
msgid "No changes"
msgstr ""
-msgid "No changes between %{ref_start}%{source_branch}%{ref_end} and %{ref_start}%{target_branch}%{ref_end}"
+msgid "No changes between %{sourceBranch} and %{targetBranch}"
msgstr ""
msgid "No child epics match applied filters"
@@ -16711,6 +17316,9 @@ msgstr ""
msgid "No containers available"
msgstr ""
+msgid "No content to show"
+msgstr ""
+
msgid "No contributions"
msgstr ""
@@ -16786,9 +17394,6 @@ msgstr ""
msgid "No license. All rights reserved"
msgstr ""
-msgid "No licenses found."
-msgstr ""
-
msgid "No matches found"
msgstr ""
@@ -16801,6 +17406,9 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No members found"
+msgstr ""
+
msgid "No merge requests found"
msgstr ""
@@ -16822,6 +17430,9 @@ msgstr ""
msgid "No parent group"
msgstr ""
+msgid "No plan"
+msgstr ""
+
msgid "No pods available"
msgstr ""
@@ -16918,6 +17529,12 @@ msgstr ""
msgid "Not Implemented"
msgstr ""
+msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+msgstr ""
+
+msgid "Not all browsers support WebAuthn. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even from an unsupported browser."
+msgstr ""
+
msgid "Not all data has been processed yet, the accuracy of the chart for the selected timeframe is limited."
msgstr ""
@@ -17014,6 +17631,9 @@ msgstr ""
msgid "Notification settings saved"
msgstr ""
+msgid "NotificationEvent|Change reviewer merge request"
+msgstr ""
+
msgid "NotificationEvent|Close issue"
msgstr ""
@@ -17176,10 +17796,7 @@ msgstr ""
msgid "On track"
msgstr ""
-msgid "OnDemandScans|Attached branch"
-msgstr ""
-
-msgid "OnDemandScans|Attached branch is where the scan job runs."
+msgid "OnDemandScans|Could not fetch scanner profiles. Please refresh the page, or try again later."
msgstr ""
msgid "OnDemandScans|Could not fetch site profiles. Please refresh the page, or try again later."
@@ -17188,6 +17805,9 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
+msgid "OnDemandScans|Create a new scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Create a new site profile"
msgstr ""
@@ -17200,6 +17820,9 @@ msgstr ""
msgid "OnDemandScans|New on-demand DAST scan"
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 ""
@@ -17209,16 +17832,10 @@ msgstr ""
msgid "OnDemandScans|On-demand scans run outside the DevOps cycle and find vulnerabilities in your projects. %{learnMoreLinkStart}Learn more%{learnMoreLinkEnd}"
msgstr ""
-msgid "OnDemandScans|Only a passive scan can be performed on demand."
-msgstr ""
-
-msgid "OnDemandScans|Passive"
-msgstr ""
-
msgid "OnDemandScans|Run scan"
msgstr ""
-msgid "OnDemandScans|Scan mode"
+msgid "OnDemandScans|Scanner profile"
msgstr ""
msgid "OnDemandScans|Scanner settings"
@@ -17230,9 +17847,15 @@ msgstr ""
msgid "OnDemandScans|Select one of the existing profiles"
msgstr ""
+msgid "OnDemandScans|Site profile"
+msgstr ""
+
msgid "OnDemandScans|Site profiles"
msgstr ""
+msgid "OnDemandScans|Use existing scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Use existing site profile"
msgstr ""
@@ -17331,9 +17954,6 @@ msgstr ""
msgid "Open Selection"
msgstr ""
-msgid "Open Web IDE"
-msgstr ""
-
msgid "Open comment type dropdown"
msgstr ""
@@ -17439,6 +18059,9 @@ msgstr ""
msgid "Origin"
msgstr ""
+msgid "Orphaned member"
+msgstr ""
+
msgid "Other Labels"
msgstr ""
@@ -17454,6 +18077,9 @@ msgstr ""
msgid "Other visibility settings have been disabled by the administrator."
msgstr ""
+msgid "Our documentation includes an example DevOps Score report."
+msgstr ""
+
msgid "Out-of-compliance with this project's policies and should be removed"
msgstr ""
@@ -17478,6 +18104,9 @@ msgstr ""
msgid "Overwrite diverged branches"
msgstr ""
+msgid "Owned by %{image_tag}"
+msgstr ""
+
msgid "Owned by anyone"
msgstr ""
@@ -17499,6 +18128,9 @@ msgstr ""
msgid "Package deleted successfully"
msgstr ""
+msgid "Package file size limits"
+msgstr ""
+
msgid "Package recipe already exists"
msgstr ""
@@ -17514,9 +18146,6 @@ msgstr ""
msgid "Package type must be PyPi"
msgstr ""
-msgid "Package was removed"
-msgstr ""
-
msgid "PackageRegistry|%{name} version %{version} was created %{datetime}"
msgstr ""
@@ -17658,12 +18287,18 @@ msgstr ""
msgid "PackageRegistry|NuGet Command"
msgstr ""
+msgid "PackageRegistry|Package Registry"
+msgstr ""
+
msgid "PackageRegistry|Pip Command"
msgstr ""
msgid "PackageRegistry|Pipeline %{link} triggered %{datetime} by %{author}"
msgstr ""
+msgid "PackageRegistry|Publish and share packages for a variety of common package managers. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "PackageRegistry|Published to the %{project} Package Registry %{datetime}"
msgstr ""
@@ -17763,6 +18398,9 @@ msgstr ""
msgid "Page not found"
msgstr ""
+msgid "Page settings"
+msgstr ""
+
msgid "Page was successfully deleted"
msgstr ""
@@ -17904,7 +18542,7 @@ msgstr ""
msgid "Paste issue link"
msgstr ""
-msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Don't use your private SSH key."
+msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Do not paste your private SSH key, as that can compromise your identity."
msgstr ""
msgid "Patch to apply"
@@ -17931,6 +18569,9 @@ msgstr ""
msgid "Pending"
msgstr ""
+msgid "Pending comments"
+msgstr ""
+
msgid "People without permission will never get a notification and won't be able to comment."
msgstr ""
@@ -18129,6 +18770,9 @@ msgstr ""
msgid "Pipelines|Build with confidence"
msgstr ""
+msgid "Pipelines|By revoking a trigger you will break any processes making use of it. Are you sure?"
+msgstr ""
+
msgid "Pipelines|CI Lint"
msgstr ""
@@ -18141,6 +18785,15 @@ msgstr ""
msgid "Pipelines|Continuous Integration can help catch bugs by running your tests automatically, while Continuous Deployment can help you deliver code to your product environment."
msgstr ""
+msgid "Pipelines|Copy trigger token"
+msgstr ""
+
+msgid "Pipelines|Description"
+msgstr ""
+
+msgid "Pipelines|Edit"
+msgstr ""
+
msgid "Pipelines|Get started with Pipelines"
msgstr ""
@@ -18156,15 +18809,27 @@ msgstr ""
msgid "Pipelines|It is recommended the code is reviewed thoroughly before running this pipeline with the parent project's CI resource."
msgstr ""
+msgid "Pipelines|Last Used"
+msgstr ""
+
msgid "Pipelines|Loading Pipelines"
msgstr ""
msgid "Pipelines|More Information"
msgstr ""
+msgid "Pipelines|No triggers have been created yet. Add one using the form above."
+msgstr ""
+
+msgid "Pipelines|Owner"
+msgstr ""
+
msgid "Pipelines|Project cache successfully reset."
msgstr ""
+msgid "Pipelines|Revoke"
+msgstr ""
+
msgid "Pipelines|Run Pipeline"
msgstr ""
@@ -18189,6 +18854,15 @@ msgstr ""
msgid "Pipelines|This project is not currently set up to run pipelines."
msgstr ""
+msgid "Pipelines|Token"
+msgstr ""
+
+msgid "Pipelines|Trigger user has insufficient permissions to project"
+msgstr ""
+
+msgid "Pipelines|invalid"
+msgstr ""
+
msgid "Pipelines|parent"
msgstr ""
@@ -18447,10 +19121,10 @@ msgstr ""
msgid "Please provide attributes to update"
msgstr ""
-msgid "Please refer to %{docs_url}"
+msgid "Please reach out if you have any questions and we'll be happy to assist."
msgstr ""
-msgid "Please retype the email address."
+msgid "Please refer to %{docs_url}"
msgstr ""
msgid "Please select"
@@ -18480,6 +19154,9 @@ msgstr ""
msgid "Please set a new password before proceeding."
msgstr ""
+msgid "Please share your feedback about %{featureName} %{linkStart}in this issue%{linkEnd} to help us improve the experience."
+msgstr ""
+
msgid "Please solve the reCAPTCHA"
msgstr ""
@@ -18783,6 +19460,9 @@ msgstr ""
msgid "Profiles| You are going to change the username %{currentUsernameBold} to %{newUsernameBold}. Profile and projects will be redirected to the %{newUsername} namespace but this redirect will expire once the %{currentUsername} namespace is registered by another user or group. Please update your Git repository remotes as soon as possible."
msgstr ""
+msgid "Profiles|%{provider} Active"
+msgstr ""
+
msgid "Profiles|@username"
msgstr ""
@@ -18834,7 +19514,7 @@ msgstr ""
msgid "Profiles|Commit email"
msgstr ""
-msgid "Profiles|Connect"
+msgid "Profiles|Connect %{provider}"
msgstr ""
msgid "Profiles|Connected Accounts"
@@ -18858,6 +19538,9 @@ msgstr ""
msgid "Profiles|Disconnect"
msgstr ""
+msgid "Profiles|Disconnect %{provider}"
+msgstr ""
+
msgid "Profiles|Do not show on profile"
msgstr ""
@@ -18882,7 +19565,7 @@ msgstr ""
msgid "Profiles|Full name"
msgstr ""
-msgid "Profiles|Give your individual key a title. This will be publically visible."
+msgid "Profiles|Give your individual key a title."
msgstr ""
msgid "Profiles|Include private contributions on my profile"
@@ -18972,7 +19655,7 @@ msgstr ""
msgid "Profiles|The maximum file size allowed is 200KB."
msgstr ""
-msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it?"
+msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it? It will be publicly visible."
msgstr ""
msgid "Profiles|This email will be displayed on your public profile"
@@ -19047,6 +19730,9 @@ msgstr ""
msgid "Profiles|You don't have access to delete this user."
msgstr ""
+msgid "Profiles|You must transfer ownership or delete groups you are an owner of before you can delete your account"
+msgstr ""
+
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
@@ -19635,6 +20321,9 @@ msgstr ""
msgid "ProjectTemplates|GitLab Cluster Management"
msgstr ""
+msgid "ProjectTemplates|Gitpod/Spring Petclinic"
+msgstr ""
+
msgid "ProjectTemplates|Go Micro"
msgstr ""
@@ -20244,6 +20933,9 @@ msgstr ""
msgid "Publish to status page"
msgstr ""
+msgid "Published"
+msgstr ""
+
msgid "Published on status page"
msgstr ""
@@ -20361,9 +21053,15 @@ msgstr ""
msgid "Quick range"
msgstr ""
+msgid "Quickly and easily edit multiple files in your project."
+msgstr ""
+
msgid "README"
msgstr ""
+msgid "Rails"
+msgstr ""
+
msgid "Rake Tasks Help"
msgstr ""
@@ -20483,10 +21181,13 @@ msgstr ""
msgid "Register Two-Factor Authenticator"
msgstr ""
-msgid "Register U2F device"
+msgid "Register Universal Two-Factor (U2F) Device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register WebAuthn Device"
+msgstr ""
+
+msgid "Register device"
msgstr ""
msgid "Register for GitLab"
@@ -20498,9 +21199,6 @@ msgstr ""
msgid "Register with two-factor app"
msgstr ""
-msgid "Registration"
-msgstr ""
-
msgid "Registration|Checkout"
msgstr ""
@@ -20617,9 +21315,6 @@ msgstr ""
msgid "Release|Something went wrong while saving the release details"
msgstr ""
-msgid "Remediated: needs review"
-msgstr ""
-
msgid "Remediations"
msgstr ""
@@ -20725,6 +21420,9 @@ msgstr ""
msgid "Remove priority"
msgstr ""
+msgid "Remove report"
+msgstr ""
+
msgid "Remove secondary node"
msgstr ""
@@ -20737,6 +21435,12 @@ msgstr ""
msgid "Remove time estimate"
msgstr ""
+msgid "Remove user & report"
+msgstr ""
+
+msgid "Remove user from group"
+msgstr ""
+
msgid "Removed"
msgstr ""
@@ -20818,9 +21522,6 @@ msgstr ""
msgid "Removes time estimate."
msgstr ""
-msgid "Removing license…"
-msgstr ""
-
msgid "Removing this group also removes all child projects, including archived projects, and their resources."
msgstr ""
@@ -20905,6 +21606,9 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
+msgid "Reported by %{reporter}"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -20991,6 +21695,27 @@ msgstr ""
msgid "Repositories"
msgstr ""
+msgid "Repositories Analytics"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download Historic Test Coverage Data"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download historic test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Historic Test Coverage Data is available in raw format (.csv) for further analysis."
+msgstr ""
+
+msgid "RepositoriesAnalytics|Test Code Coverage"
+msgstr ""
+
+msgid "RepositoriesAnalytics|There was an error fetching the projects."
+msgstr ""
+
msgid "Repository"
msgstr ""
@@ -21069,9 +21794,15 @@ msgstr ""
msgid "Request parameter %{param} is missing."
msgstr ""
+msgid "Request review from"
+msgstr ""
+
msgid "Request to link SAML account must be authorized"
msgstr ""
+msgid "Requested"
+msgstr ""
+
msgid "Requested %{time_ago}"
msgstr ""
@@ -21090,6 +21821,9 @@ msgstr ""
msgid "Requests to these domain(s)/address(es) on the local network will be allowed when local requests from hooks and services are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 or 127.0.0.0/28 are supported. Domain wildcards are not supported currently. Use comma, semicolon, or newline to separate multiple entries. The allowlist can hold a maximum of 1000 entries. Domains should use IDNA encoding. Ex: example.com, 192.168.1.1, 127.0.0.0/28, xn--itlab-j1a.com."
msgstr ""
+msgid "Require admin approval for new sign-ups"
+msgstr ""
+
msgid "Require all users in this group to setup Two-factor authentication"
msgstr ""
@@ -21217,9 +21951,6 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
-msgid "Resolved by %{resolvedByName}"
-msgstr ""
-
msgid "Resolves IP addresses once and uses them to submit requests"
msgstr ""
@@ -21339,6 +22070,14 @@ msgstr ""
msgid "ReviewApp|Enable Review App"
msgstr ""
+msgid "Reviewer"
+msgid_plural "%d Reviewers"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Reviewer(s)"
+msgstr ""
+
msgid "Reviewing"
msgstr ""
@@ -21378,6 +22117,9 @@ msgstr ""
msgid "Rook"
msgstr ""
+msgid "Ruby"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -21456,6 +22198,63 @@ msgstr ""
msgid "Runners page."
msgstr ""
+msgid "Runners|Active"
+msgstr ""
+
+msgid "Runners|Architecture"
+msgstr ""
+
+msgid "Runners|Can run untagged jobs"
+msgstr ""
+
+msgid "Runners|Description"
+msgstr ""
+
+msgid "Runners|Group"
+msgstr ""
+
+msgid "Runners|IP Address"
+msgstr ""
+
+msgid "Runners|Last contact"
+msgstr ""
+
+msgid "Runners|Locked to this project"
+msgstr ""
+
+msgid "Runners|Maximum job timeout"
+msgstr ""
+
+msgid "Runners|Name"
+msgstr ""
+
+msgid "Runners|Platform"
+msgstr ""
+
+msgid "Runners|Property Name"
+msgstr ""
+
+msgid "Runners|Protected"
+msgstr ""
+
+msgid "Runners|Revision"
+msgstr ""
+
+msgid "Runners|Shared"
+msgstr ""
+
+msgid "Runners|Specific"
+msgstr ""
+
+msgid "Runners|Tags"
+msgstr ""
+
+msgid "Runners|Value"
+msgstr ""
+
+msgid "Runners|Version"
+msgstr ""
+
msgid "Runners|You have used %{quotaUsed} out of %{quotaLimit} of your shared Runners pipeline minutes."
msgstr ""
@@ -21468,6 +22267,9 @@ msgstr ""
msgid "Runs a number of housekeeping tasks within the current repository, such as compressing file revisions and removing unreachable objects."
msgstr ""
+msgid "SAML"
+msgstr ""
+
msgid "SAML SSO"
msgstr ""
@@ -21519,6 +22321,9 @@ msgstr ""
msgid "Save"
msgstr ""
+msgid "Save %{name} size limits"
+msgstr ""
+
msgid "Save Changes"
msgstr ""
@@ -21549,9 +22354,6 @@ msgstr ""
msgid "Save space and find tags in the Container Registry more easily. Enable the cleanup policy to remove stale tags and keep only the ones you need."
msgstr ""
-msgid "Save template"
-msgstr ""
-
msgid "Save variables"
msgstr ""
@@ -21594,9 +22396,6 @@ msgstr ""
msgid "Scope"
msgstr ""
-msgid "Scope not supported with disabled 'users_search' feature!"
-msgstr ""
-
msgid "Scoped issue boards"
msgstr ""
@@ -21723,9 +22522,6 @@ msgstr ""
msgid "Search requirements"
msgstr ""
-msgid "Search results…"
-msgstr ""
-
msgid "Search users"
msgstr ""
@@ -21798,6 +22594,11 @@ msgid_plural "SearchResults|commits"
msgstr[0] ""
msgstr[1] ""
+msgid "SearchResults|epic"
+msgid_plural "SearchResults|epics"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "SearchResults|issue"
msgid_plural "SearchResults|issues"
msgstr[0] ""
@@ -21842,10 +22643,10 @@ msgstr ""
msgid "Seat Link is disabled, and cannot be configured through this form."
msgstr ""
-msgid "Seats currently in use"
+msgid "Seats usage data as of %{last_enqueue_time}"
msgstr ""
-msgid "Seats in license"
+msgid "Seats usage data is updated every day at 12:00pm UTC"
msgstr ""
msgid "Secondary"
@@ -21899,6 +22700,9 @@ msgstr ""
msgid "SecurityConfiguration|Available for on-demand DAST"
msgstr ""
+msgid "SecurityConfiguration|By default, all analyzers are applied in order to cover all languages across your project, and only run if the language is detected in the Merge Request."
+msgstr ""
+
msgid "SecurityConfiguration|Configure"
msgstr ""
@@ -21929,16 +22733,19 @@ msgstr ""
msgid "SecurityConfiguration|Manage"
msgstr ""
+msgid "SecurityConfiguration|More information"
+msgstr ""
+
msgid "SecurityConfiguration|Not enabled"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|Security Control"
+msgid "SecurityConfiguration|SAST Configuration"
msgstr ""
-msgid "SecurityConfiguration|See documentation"
+msgid "SecurityConfiguration|Security Control"
msgstr ""
msgid "SecurityConfiguration|Status"
@@ -21950,6 +22757,9 @@ msgstr ""
msgid "SecurityConfiguration|Using custom settings. You won't receive automatic updates on this variable. %{anchorStart}Restore to default%{anchorEnd}"
msgstr ""
+msgid "SecurityConfiguration|View history"
+msgstr ""
+
msgid "SecurityConfiguration|You can quickly enable all security scanning tools by enabling %{linkStart}Auto DevOps%{linkEnd}."
msgstr ""
@@ -22028,9 +22838,6 @@ msgstr ""
msgid "SecurityReports|Learn more about setting up your dashboard"
msgstr ""
-msgid "SecurityReports|Load more vulnerabilities"
-msgstr ""
-
msgid "SecurityReports|Monitor vulnerabilities in your code"
msgstr ""
@@ -22310,7 +23117,7 @@ msgstr ""
msgid "Select status"
msgstr ""
-msgid "Select strategy activation method"
+msgid "Select strategy activation method."
msgstr ""
msgid "Select subscription"
@@ -22325,7 +23132,7 @@ msgstr ""
msgid "Select the custom project template source group."
msgstr ""
-msgid "Select timeframe"
+msgid "Select the environment scope for this feature flag."
msgstr ""
msgid "Select timezone"
@@ -22574,6 +23381,9 @@ msgstr ""
msgid "Set iteration"
msgstr ""
+msgid "Set limit to 0 to allow any file size."
+msgstr ""
+
msgid "Set max session time for web terminal."
msgstr ""
@@ -22652,10 +23462,13 @@ msgstr ""
msgid "Set up a %{type} Runner manually"
msgstr ""
+msgid "Set up a hardware device as a second factor to sign in."
+msgstr ""
+
msgid "Set up assertions/attributes/claims (email, first_name, last_name) and NameID according to %{docsLinkStart}the documentation %{icon}%{docsLinkEnd}"
msgstr ""
-msgid "Set up new U2F device"
+msgid "Set up new device"
msgstr ""
msgid "Set up new password"
@@ -22724,6 +23537,9 @@ msgstr ""
msgid "Sets weight to %{weight}."
msgstr ""
+msgid "Setting this to 0 means using the system default timeout value."
+msgstr ""
+
msgid "Settings"
msgstr ""
@@ -22739,6 +23555,15 @@ msgstr ""
msgid "Severity"
msgstr ""
+msgid "SeverityWidget|Severity"
+msgstr ""
+
+msgid "SeverityWidget|Severity: %{severity}"
+msgstr ""
+
+msgid "SeverityWidget|There was an error while updating severity."
+msgstr ""
+
msgid "Shards (%{shards})"
msgstr ""
@@ -22784,6 +23609,9 @@ msgstr ""
msgid "Show all requirements."
msgstr ""
+msgid "Show all test cases."
+msgstr ""
+
msgid "Show archived projects"
msgstr ""
@@ -22796,6 +23624,9 @@ msgstr ""
msgid "Show comments"
msgstr ""
+msgid "Show comments on this file"
+msgstr ""
+
msgid "Show comments only"
msgstr ""
@@ -22841,6 +23672,12 @@ msgstr ""
msgid "Show parent subgroups"
msgstr ""
+msgid "Show the Closed list"
+msgstr ""
+
+msgid "Show the Open list"
+msgstr ""
+
msgid "Show whitespace changes"
msgstr ""
@@ -22884,9 +23721,6 @@ msgstr ""
msgid "Sidebar|Assign health status"
msgstr ""
-msgid "Sidebar|Change weight"
-msgstr ""
-
msgid "Sidebar|Health status"
msgstr ""
@@ -23070,6 +23904,9 @@ msgstr ""
msgid "Snippets|Add another file %{num}/%{total}"
msgstr ""
+msgid "Snippets|Authored %{time_ago} by %{author}"
+msgstr ""
+
msgid "Snippets|Delete file"
msgstr ""
@@ -23097,6 +23934,9 @@ msgstr ""
msgid "Solution"
msgstr ""
+msgid "Some changes are not shown"
+msgstr ""
+
msgid "Some child epics may be hidden due to applied filters"
msgstr ""
@@ -23463,6 +24303,12 @@ msgstr ""
msgid "Source (branch or tag)"
msgstr ""
+msgid "Source Branch"
+msgstr ""
+
+msgid "Source branch: %{source_branch_open}%{source_branch}%{source_branch_close}"
+msgstr ""
+
msgid "Source code"
msgstr ""
@@ -23628,9 +24474,6 @@ msgstr ""
msgid "Start and due date"
msgstr ""
-msgid "Start by choosing a group to see how your team is spending time. You can then drill down to the project level."
-msgstr ""
-
msgid "Start by choosing a group to start exploring the merge requests in that group. You can then proceed to filter by projects, labels, milestones and authors."
msgstr ""
@@ -23712,18 +24555,27 @@ msgstr ""
msgid "StaticSiteEditor|3. Assign a person to review and accept the merge request."
msgstr ""
+msgid "StaticSiteEditor|A link to view the merge request will appear once ready."
+msgstr ""
+
msgid "StaticSiteEditor|An error occurred while submitting your changes."
msgstr ""
msgid "StaticSiteEditor|Branch could not be created."
msgstr ""
+msgid "StaticSiteEditor|Copy update"
+msgstr ""
+
msgid "StaticSiteEditor|Could not commit the content changes."
msgstr ""
msgid "StaticSiteEditor|Could not create merge request."
msgstr ""
+msgid "StaticSiteEditor|Creating your merge request"
+msgstr ""
+
msgid "StaticSiteEditor|Incompatible file content"
msgstr ""
@@ -23745,6 +24597,9 @@ msgstr ""
msgid "StaticSiteEditor|View documentation"
msgstr ""
+msgid "StaticSiteEditor|You can set an assignee to get your changes reviewed and deployed once your merge request is created."
+msgstr ""
+
msgid "StaticSiteEditor|Your merge request has been created"
msgstr ""
@@ -23874,15 +24729,15 @@ msgstr ""
msgid "Submit %{humanized_resource_name}"
msgstr ""
-msgid "Submit Changes"
-msgstr ""
-
msgid "Submit a review"
msgstr ""
msgid "Submit as spam"
msgstr ""
+msgid "Submit changes"
+msgstr ""
+
msgid "Submit feedback"
msgstr ""
@@ -24036,6 +24891,9 @@ msgstr ""
msgid "Successfully deleted U2F device."
msgstr ""
+msgid "Successfully deleted WebAuthn device."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -24354,9 +25212,6 @@ msgstr ""
msgid "Template to append to all Service Desk issues"
msgstr ""
-msgid "Template was successfully saved."
-msgstr ""
-
msgid "Templates"
msgstr ""
@@ -24435,10 +25290,28 @@ msgid_plural "Test coverage: %d hits"
msgstr[0] ""
msgstr[1] ""
-msgid "Test failed."
+msgid "Test settings"
msgstr ""
-msgid "Test settings and save changes"
+msgid "TestCases|New Test Case"
+msgstr ""
+
+msgid "TestCases|New test case"
+msgstr ""
+
+msgid "TestCases|Search test cases"
+msgstr ""
+
+msgid "TestCases|Something went wrong while creating a test case."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching count of test cases."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching test cases list."
+msgstr ""
+
+msgid "TestCases|Submit test case"
msgstr ""
msgid "TestHooks|Ensure one of your projects has merge requests."
@@ -24504,6 +25377,9 @@ msgstr ""
msgid "Thank you for signing up for your free trial! You will get additional instructions in your inbox shortly."
msgstr ""
+msgid "Thank you for your business."
+msgstr ""
+
msgid "Thank you for your feedback!"
msgstr ""
@@ -24563,9 +25439,6 @@ msgstr ""
msgid "The URL to use for connecting to Elasticsearch. Use a comma-separated list to support clustering (e.g., \"http://localhost:9200, http://localhost:9201\")."
msgstr ""
-msgid "The Web IDE offers advanced syntax highlighting capabilities and more."
-msgstr ""
-
msgid "The X509 Certificate to use when mutual TLS is required to communicate with the external authorization service. If left blank, the server certificate is still validated when accessing over HTTPS."
msgstr ""
@@ -24676,6 +25549,9 @@ msgstr ""
msgid "The form contains the following error:"
msgstr ""
+msgid "The form contains the following warning:"
+msgstr ""
+
msgid "The global settings require you to enable Two-Factor Authentication for your account."
msgstr ""
@@ -24790,9 +25666,6 @@ msgstr ""
msgid "The private key to use when a client certificate is provided. This value is encrypted at rest."
msgstr ""
-msgid "The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The project can be accessed by any logged in user."
msgstr ""
@@ -24829,7 +25702,7 @@ msgstr ""
msgid "The remote repository is being updated..."
msgstr ""
-msgid "The repository can be commited to, and issues, comments and other entities can be created."
+msgid "The repository can be committed to, and issues, comments and other entities can be created."
msgstr ""
msgid "The repository for this project does not exist."
@@ -24883,9 +25756,6 @@ msgstr ""
msgid "The time taken by each data entry gathered by that stage."
msgstr ""
-msgid "The total stage shows the time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The update action will time out after %{number_of_minutes} minutes. For big repositories, use a clone/push combination."
msgstr ""
@@ -24949,6 +25819,9 @@ msgstr ""
msgid "There are no archived requirements"
msgstr ""
+msgid "There are no archived test cases"
+msgstr ""
+
msgid "There are no changes"
msgstr ""
@@ -24988,6 +25861,9 @@ msgstr ""
msgid "There are no open requirements"
msgstr ""
+msgid "There are no open test cases"
+msgstr ""
+
msgid "There are no packages yet"
msgstr ""
@@ -25000,6 +25876,9 @@ msgstr ""
msgid "There is a limit of %{ci_project_subscriptions_limit} subscriptions from or to a project."
msgstr ""
+msgid "There is already a To-Do for this design."
+msgstr ""
+
msgid "There is already a repository with that name on disk"
msgstr ""
@@ -25018,6 +25897,9 @@ msgstr ""
msgid "There was a problem communicating with your device."
msgstr ""
+msgid "There was a problem fetching branches."
+msgstr ""
+
msgid "There was a problem fetching groups."
msgstr ""
@@ -25246,9 +26128,15 @@ msgstr ""
msgid "This action can lead to data loss. To prevent accidental actions we ask you to confirm your intention."
msgstr ""
+msgid "This action cannot be undone, and will permanently delete the %{key} SSH key"
+msgstr ""
+
msgid "This action cannot be undone. You will lose the project's repository and all content: issues, merge requests, etc."
msgstr ""
+msgid "This action has been performed too many times. Try again later."
+msgstr ""
+
msgid "This action will %{strongOpen}permanently delete%{strongClose} %{codeOpen}%{project}%{codeClose} %{strongOpen}immediately%{strongClose}, including its repositories and all content: issues, merge requests, etc."
msgstr ""
@@ -25276,9 +26164,6 @@ msgstr ""
msgid "This board's scope is reduced"
msgstr ""
-msgid "This branch has changed since you started editing. Would you like to create a new branch?"
-msgstr ""
-
msgid "This chart could not be displayed"
msgstr ""
@@ -25405,15 +26290,9 @@ msgstr ""
msgid "This is a security log of important events involving your account."
msgstr ""
-msgid "This is the author's first Merge Request to this project."
-msgstr ""
-
msgid "This is the highest peak of users on your installation since the license started."
msgstr ""
-msgid "This is the maximum number of users that have existed at the same time since the license started. This is the minimum number of seats you will need to buy when you renew your license."
-msgstr ""
-
msgid "This is the number of currently active users on your installation, and this is the minimum number you need to purchase when you renew your license."
msgstr ""
@@ -25645,6 +26524,15 @@ msgstr ""
msgid "This user has no identities"
msgstr ""
+msgid "This user has previously committed to the %{name} project."
+msgstr ""
+
+msgid "This user has the %{access} role in the %{name} project."
+msgstr ""
+
+msgid "This user is the author of this %{noteable}."
+msgstr ""
+
msgid "This user will be the author of all events in the activity feed that are the result of an update, like new branches being created or new commits being pushed to existing branches."
msgstr ""
@@ -25675,6 +26563,9 @@ msgstr ""
msgid "Threat Monitoring"
msgstr ""
+msgid "ThreatMonitoring|All Environments"
+msgstr ""
+
msgid "ThreatMonitoring|Anomalous Requests"
msgstr ""
@@ -25702,9 +26593,6 @@ msgstr ""
msgid "ThreatMonitoring|Operations Per Second"
msgstr ""
-msgid "ThreatMonitoring|Overview"
-msgstr ""
-
msgid "ThreatMonitoring|Packet Activity"
msgstr ""
@@ -25723,6 +26611,9 @@ msgstr ""
msgid "ThreatMonitoring|Something went wrong, unable to fetch statistics"
msgstr ""
+msgid "ThreatMonitoring|Statistics"
+msgstr ""
+
msgid "ThreatMonitoring|The firewall is not installed or has been disabled. To view this data, ensure the web application firewall is installed and enabled for your cluster."
msgstr ""
@@ -26114,6 +27005,9 @@ msgstr ""
msgid "To update Snippets with multiple files, you must use the `files` parameter"
msgstr ""
+msgid "To use Gitpod you must first enable the feature in the integrations section of your %{user_prefs}."
+msgstr ""
+
msgid "To view all %{scannedResourcesCount} scanned URLs, please download the CSV file"
msgstr ""
@@ -26147,9 +27041,6 @@ msgstr ""
msgid "Toggle Sidebar"
msgstr ""
-msgid "Toggle all threads"
-msgstr ""
-
msgid "Toggle backtrace"
msgstr ""
@@ -26174,9 +27065,6 @@ msgstr ""
msgid "Toggle navigation"
msgstr ""
-msgid "Toggle project"
-msgstr ""
-
msgid "Toggle sidebar"
msgstr ""
@@ -26216,6 +27104,9 @@ msgstr ""
msgid "Too many projects enabled. You will need to manage them via the console or the API."
msgstr ""
+msgid "Too much data"
+msgstr ""
+
msgid "Topics (optional)"
msgstr ""
@@ -26234,6 +27125,9 @@ msgstr ""
msgid "Total cores (CPUs)"
msgstr ""
+msgid "Total days to completion"
+msgstr ""
+
msgid "Total issues"
msgstr ""
@@ -26330,6 +27224,9 @@ msgstr ""
msgid "Trending"
msgstr ""
+msgid "Trials|Create a new group to start your GitLab Gold trial."
+msgstr ""
+
msgid "Trials|Go back to GitLab"
msgstr ""
@@ -26339,6 +27236,15 @@ msgstr ""
msgid "Trials|You can always resume this process by selecting your avatar and choosing 'Start a Gold trial'"
msgstr ""
+msgid "Trials|You can apply your trial to a new group or an existing group."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group or your personal account."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group, an existing group, or your personal account."
+msgstr ""
+
msgid "Trials|You won't get a free trial right now but you can always resume this process by clicking on your avatar and choosing 'Start a free trial'"
msgstr ""
@@ -26408,6 +27314,9 @@ msgstr ""
msgid "Try using a different search term to find the file you are looking for."
msgstr ""
+msgid "Trying to communicate with your device. Plug it in (if needed) and press the button on the device now."
+msgstr ""
+
msgid "Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now."
msgstr ""
@@ -26495,6 +27404,12 @@ msgstr ""
msgid "URL or request ID"
msgstr ""
+msgid "USER %{user} WILL BE REMOVED! Are you sure?"
+msgstr ""
+
+msgid "USER WILL BE BLOCKED! Are you sure?"
+msgstr ""
+
msgid "UTC"
msgstr ""
@@ -26552,9 +27467,6 @@ msgstr ""
msgid "Unable to load the merge request widget. Try reloading the page."
msgstr ""
-msgid "Unable to resolve"
-msgstr ""
-
msgid "Unable to save iteration. Please try again"
msgstr ""
@@ -26603,6 +27515,9 @@ msgstr ""
msgid "Undo ignore"
msgstr ""
+msgid "Unexpected error"
+msgstr ""
+
msgid "Unfortunately, your email message to GitLab could not be processed."
msgstr ""
@@ -26636,6 +27551,9 @@ msgstr ""
msgid "Unknown response text"
msgstr ""
+msgid "Unless otherwise agreed to in writing with GitLab, by clicking \"Upload License\" you agree that your use of GitLab Software is subject to the %{eula_link_start}Terms of Service%{eula_link_end}."
+msgstr ""
+
msgid "Unlimited"
msgstr ""
@@ -27002,9 +27920,6 @@ msgstr ""
msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
msgstr ""
-msgid "Use a hardware device to add the second factor of authentication."
-msgstr ""
-
msgid "Use an one time password authenticator on your mobile device or computer to enable two-factor authentication (2FA)."
msgstr ""
@@ -27278,13 +28193,13 @@ msgstr ""
msgid "Users"
msgstr ""
-msgid "Users in License:"
+msgid "Users in License"
msgstr ""
-msgid "Users or groups set as approvers in the project's or merge request's settings."
+msgid "Users in License:"
msgstr ""
-msgid "Users outside of license"
+msgid "Users or groups set as approvers in the project's or merge request's settings."
msgstr ""
msgid "Users over License:"
@@ -27302,9 +28217,6 @@ msgstr ""
msgid "Users with a Guest role or those who don't belong to a Project or Group will not use a seat from your license."
msgstr ""
-msgid "Users with a Guest role or those who don't belong to any projects or groups don't count towards seats in use."
-msgstr ""
-
msgid "UsersSelect|%{name} + %{length} more"
msgstr ""
@@ -27344,9 +28256,6 @@ msgstr ""
msgid "Validations failed."
msgstr ""
-msgid "Validity"
-msgstr ""
-
msgid "Value"
msgstr ""
@@ -27365,6 +28274,9 @@ msgstr ""
msgid "Value Stream Name"
msgstr ""
+msgid "ValueStreamAnalyticsStage|We don't have enough data to show this stage."
+msgstr ""
+
msgid "ValueStreamAnalytics|%{days}d"
msgstr ""
@@ -27621,6 +28533,9 @@ msgstr ""
msgid "VisualReviewApp|Steps 1 and 2 (and sometimes 3) are performed once by the developer before requesting feedback. Steps 3 (if necessary), 4 is performed by the reviewer each time they perform a review."
msgstr ""
+msgid "Visualization"
+msgstr ""
+
msgid "Vulnerabilities"
msgstr ""
@@ -27648,34 +28563,31 @@ msgstr ""
msgid "VulnerabilityChart|Severity"
msgstr ""
-msgid "VulnerabilityManagement|A true-positive and will fix"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Change status"
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|Confirm"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Confirmed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
-msgstr ""
-
-msgid "VulnerabilityManagement|Detected %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|A true-positive and will fix"
msgstr ""
-msgid "VulnerabilityManagement|Dismiss"
+msgid "VulnerabilityManagement|Change status"
msgstr ""
-msgid "VulnerabilityManagement|Dismissed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
msgstr ""
-msgid "VulnerabilityManagement|Resolved"
+msgid "VulnerabilityManagement|Detected"
msgstr ""
-msgid "VulnerabilityManagement|Resolved %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Needs triage"
msgstr ""
msgid "VulnerabilityManagement|Something went wrong while trying to delete the comment. Please try again later."
@@ -27726,6 +28638,9 @@ msgstr ""
msgid "Vulnerability|%{scannerName} (version %{scannerVersion})"
msgstr ""
+msgid "Vulnerability|Activity"
+msgstr ""
+
msgid "Vulnerability|Class"
msgstr ""
@@ -27738,6 +28653,9 @@ msgstr ""
msgid "Vulnerability|Description"
msgstr ""
+msgid "Vulnerability|Detected"
+msgstr ""
+
msgid "Vulnerability|Evidence"
msgstr ""
@@ -27801,6 +28719,9 @@ msgstr ""
msgid "Warning: Displaying this diagram might cause performance issues on this page."
msgstr ""
+msgid "We are currently unable to fetch data for the pipeline header."
+msgstr ""
+
msgid "We are currently unable to fetch data for this graph."
msgstr ""
@@ -27840,6 +28761,12 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
+msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
+msgstr ""
+
+msgid "We would like to inform you that your subscription GitLab Enterprise Edition %{plan_name} is nearing its user limit. You have %{active_user_count} active users, which is almost at the user limit of %{maximum_user_count}."
+msgstr ""
+
msgid "We've found no vulnerabilities"
msgstr ""
@@ -27855,6 +28782,12 @@ msgstr ""
msgid "Web terminal"
msgstr ""
+msgid "WebAuthn Devices (%{length})"
+msgstr ""
+
+msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
+msgstr ""
+
msgid "WebIDE|Merge request"
msgstr ""
@@ -27993,15 +28926,9 @@ msgstr ""
msgid "Welcome to the guided GitLab tour"
msgstr ""
-msgid "Welcome to your Issue Board!"
-msgstr ""
-
msgid "Welcome to your issue board!"
msgstr ""
-msgid "We’ve been making changes to %{featureName} and we’d love your feedback %{linkStart}in this issue%{linkEnd} to help us improve the experience."
-msgstr ""
-
msgid "What are you searching for?"
msgstr ""
@@ -28020,6 +28947,9 @@ msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
msgstr ""
+msgid "When enabled, any user visiting %{host} and creating an account will have to be explicitly approved by the admin before they can login. This setting is effective only if sign-ups are enabled."
+msgstr ""
+
msgid "When enabled, any user visiting %{host} will be able to create an account."
msgstr ""
@@ -28244,6 +29174,9 @@ msgstr ""
msgid "With requirements, you can set criteria to check your products against."
msgstr ""
+msgid "With test cases, you can define conditions for your project to meet in determining quality"
+msgstr ""
+
msgid "Withdraw Access Request"
msgstr ""
@@ -28259,6 +29192,9 @@ msgstr ""
msgid "Workflow Help"
msgstr ""
+msgid "Would you like to create a new branch?"
+msgstr ""
+
msgid "Write"
msgstr ""
@@ -28280,6 +29216,9 @@ msgstr ""
msgid "Wrong extern UID provided. Make sure Auth0 is configured correctly."
msgstr ""
+msgid "YYYY-MM-DD"
+msgstr ""
+
msgid "Yes"
msgstr ""
@@ -28337,7 +29276,7 @@ msgstr ""
msgid "You are going to remove the fork relationship from %{project_full_name}. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "You are going to transfer %{project_full_name} to another owner. Are you ABSOLUTELY sure?"
+msgid "You are going to transfer %{project_full_name} to another namespace. Are you ABSOLUTELY sure?"
msgstr ""
msgid "You are going to turn off the confidentiality. This means %{strongStart}everyone%{strongEnd} will be able to see and leave a comment on this %{issuableType}."
@@ -28397,9 +29336,6 @@ msgstr ""
msgid "You can always edit this later"
msgstr ""
-msgid "You can apply your Trial to your Personal account or create a New Group."
-msgstr ""
-
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings"
msgstr ""
@@ -28421,12 +29357,18 @@ msgstr ""
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
+msgid "You can find more information about GitLab subscriptions in %{subscriptions_doc_link}."
+msgstr ""
+
msgid "You can generate an access token scoped to this project for each application to use the GitLab API."
msgstr ""
msgid "You can get started by cloning the repository or start adding files to it with one of the following options."
msgstr ""
+msgid "You can group test cases using labels. To learn about the future direction of this feature, visit %{linkStart}Quality Management direction page%{linkEnd}."
+msgstr ""
+
msgid "You can invite a new member to %{project_name} or invite another group."
msgstr ""
@@ -28442,6 +29384,9 @@ msgstr ""
msgid "You can notify the app / group or a project by sending them an email notification"
msgstr ""
+msgid "You can now close this window."
+msgstr ""
+
msgid "You can now export your security dashboard to a CSV report."
msgstr ""
@@ -28490,9 +29435,6 @@ msgstr ""
msgid "You can test your .gitlab-ci.yml in %{linkStart}CI Lint%{linkEnd}."
msgstr ""
-msgid "You can try again using %{begin_link}basic search%{end_link}"
-msgstr ""
-
msgid "You cannot access the raw file. Please wait a minute."
msgstr ""
@@ -28544,6 +29486,9 @@ msgstr ""
msgid "You don't have any U2F devices registered yet."
msgstr ""
+msgid "You don't have any WebAuthn devices registered yet."
+msgstr ""
+
msgid "You don't have any active chat names."
msgstr ""
@@ -28631,6 +29576,9 @@ msgstr ""
msgid "You must accept our Terms of Service and privacy policy in order to register an account"
msgstr ""
+msgid "You must be logged in to search across all of GitLab"
+msgstr ""
+
msgid "You must disassociate %{domain} from all clusters it is attached to before deletion."
msgstr ""
@@ -28670,7 +29618,7 @@ msgstr ""
msgid "You need to be logged in."
msgstr ""
-msgid "You need to register a two-factor authentication app before you can set up a U2F device."
+msgid "You need to register a two-factor authentication app before you can set up a device."
msgstr ""
msgid "You need to set terms to be enforced"
@@ -28688,6 +29636,9 @@ msgstr ""
msgid "You reached %{usage_in_percent} of %{namespace_name}'s storage capacity (%{used_storage} of %{storage_limit})"
msgstr ""
+msgid "You successfully declined the invitation"
+msgstr ""
+
msgid "You tried to fork %{link_to_the_project} but it failed for the following reason:"
msgstr ""
@@ -28853,10 +29804,13 @@ msgstr ""
msgid "Your U2F device did not send a valid JSON response."
msgstr ""
-msgid "Your U2F device needs to be set up. Plug it in (if not already) and click the button on the left."
+msgid "Your U2F device was registered!"
msgstr ""
-msgid "Your U2F device was registered!"
+msgid "Your WebAuthn device did not send a valid JSON response."
+msgstr ""
+
+msgid "Your WebAuthn device was registered!"
msgstr ""
msgid "Your access request to the %{source_type} has been withdrawn."
@@ -28880,6 +29834,9 @@ msgstr ""
msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
msgstr ""
+msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
+msgstr ""
+
msgid "Your changes can be committed to %{branch_name} because a merge request is open."
msgstr ""
@@ -28916,6 +29873,12 @@ msgstr ""
msgid "Your deployment services will be broken, you will need to manually fix the services after renaming."
msgstr ""
+msgid "Your device is not compatible with GitLab. Please try another device"
+msgstr ""
+
+msgid "Your device needs to be set up. Plug it in (if needed) and click the button on the left."
+msgstr ""
+
msgid "Your device was successfully set up! Give it a name and register it with the GitLab server."
msgstr ""
@@ -29029,9 +29992,6 @@ msgstr[1] ""
msgid "access:"
msgstr ""
-msgid "activated"
-msgstr ""
-
msgid "added %{created_at_timeago}"
msgstr ""
@@ -29104,9 +30064,21 @@ msgstr ""
msgid "by %{user}"
msgstr ""
+msgid "cannot be a date in the past"
+msgstr ""
+
msgid "cannot be changed if a personal project has container registry tags."
msgstr ""
+msgid "cannot be changed if shared runners are enabled"
+msgstr ""
+
+msgid "cannot be enabled because parent group does not allow it"
+msgstr ""
+
+msgid "cannot be enabled because parent group has shared Runners disabled"
+msgstr ""
+
msgid "cannot be enabled unless all domains have TLS certificates"
msgstr ""
@@ -29152,7 +30124,7 @@ msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about SAST %{linkEndTag}"
msgstr ""
-msgid "ciReport|%{linkStartTag}Learn more about Secret Scanning %{linkEndTag}"
+msgid "ciReport|%{linkStartTag}Learn more about Secret Detection %{linkEndTag}"
msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about codequality reports %{linkEndTag}"
@@ -29467,9 +30439,6 @@ msgstr ""
msgid "error"
msgstr ""
-msgid "error code:"
-msgstr ""
-
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr ""
@@ -29491,6 +30460,9 @@ msgstr ""
msgid "failed to dismiss associated finding(id=%{finding_id}): %{message}"
msgstr ""
+msgid "failed to revert associated finding(id=%{finding_id}) to detected"
+msgstr ""
+
msgid "file"
msgid_plural "files"
msgstr[0] ""
@@ -30033,6 +31005,9 @@ msgstr ""
msgid "must be a root namespace"
msgstr ""
+msgid "must be a valid IPv4 or IPv6 address"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -30069,6 +31044,9 @@ msgstr ""
msgid "no expiration"
msgstr ""
+msgid "no name set"
+msgstr ""
+
msgid "no one can merge"
msgstr ""
@@ -30247,9 +31225,6 @@ msgstr ""
msgid "security Reports|There was an error creating the merge request"
msgstr ""
-msgid "settings saved, but not activated"
-msgstr ""
-
msgid "severity|Critical"
msgstr ""
@@ -30376,9 +31351,6 @@ msgstr ""
msgid "toggle collapse"
msgstr ""
-msgid "toggle dropdown"
-msgstr ""
-
msgid "triggered"
msgstr ""
@@ -30406,6 +31378,9 @@ msgstr ""
msgid "user avatar"
msgstr ""
+msgid "user preferences"
+msgstr ""
+
msgid "username"
msgstr ""
diff --git a/locale/az_AZ/gitlab.po b/locale/az_AZ/gitlab.po
index e462330f7c1..1cbe8715233 100644
--- a/locale/az_AZ/gitlab.po
+++ b/locale/az_AZ/gitlab.po
@@ -14,7 +14,10 @@ msgstr ""
"X-Crowdin-Language: az\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 6\n"
-"PO-Revision-Date: 2020-09-04 23:03\n"
+"PO-Revision-Date: 2020-10-02 18:42\n"
+
+msgid " %{project_name}#%{issue_iid} &middot; opened %{issue_created} by %{author}"
+msgstr ""
msgid " %{start} to %{end}"
msgstr ""
@@ -74,6 +77,16 @@ msgstr ""
msgid "\"el\" parameter is required for createInstance()"
msgstr ""
+msgid "%d Approval"
+msgid_plural "%d Approvals"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d Package"
+msgid_plural "%d Packages"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d Scanned URL"
msgid_plural "%d Scanned URLs"
msgstr[0] ""
@@ -137,6 +150,11 @@ msgstr[1] ""
msgid "%d commits"
msgstr ""
+msgid "%d completed issue"
+msgid_plural "%d completed issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d contribution"
msgid_plural "%d contributions"
msgstr[0] ""
@@ -147,6 +165,11 @@ msgid_plural "%d days"
msgstr[0] ""
msgstr[1] ""
+msgid "%d day until tags are automatically removed"
+msgid_plural "%d days until tags are automatically removed"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d error"
msgid_plural "%d errors"
msgstr[0] ""
@@ -237,6 +260,16 @@ msgid_plural "%d more comments"
msgstr[0] ""
msgstr[1] ""
+msgid "%d open issue"
+msgid_plural "%d open issues"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d pending comment"
+msgid_plural "%d pending comments"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d personal project will be removed and cannot be restored."
msgid_plural "%d personal projects will be removed and cannot be restored."
msgstr[0] ""
@@ -252,6 +285,11 @@ msgid_plural "%d projects"
msgstr[0] ""
msgstr[1] ""
+msgid "%d project selected"
+msgid_plural "%d projects selected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d request with warnings"
msgid_plural "%d requests with warnings"
msgstr[0] ""
@@ -272,6 +310,11 @@ msgid_plural "%d tags"
msgstr[0] ""
msgstr[1] ""
+msgid "%d tag per image name"
+msgid_plural "%d tags per image name"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d unassigned issue"
msgid_plural "%d unassigned issues"
msgstr[0] ""
@@ -292,6 +335,11 @@ msgid_plural "%d vulnerabilities dismissed"
msgstr[0] ""
msgstr[1] ""
+msgid "%d warning found:"
+msgid_plural "%d warnings found:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%s additional commit has been omitted to prevent performance issues."
msgid_plural "%s additional commits have been omitted to prevent performance issues."
msgstr[0] ""
@@ -330,6 +378,9 @@ msgstr ""
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr ""
+msgid "%{completedCount} completed weight"
+msgstr ""
+
msgid "%{completedWeight} of %{totalWeight} weight completed"
msgstr ""
@@ -378,14 +429,12 @@ msgid_plural "%{count} participants"
msgstr[0] ""
msgstr[1] ""
-msgid "%{count} pending comment"
-msgid_plural "%{count} pending comments"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
+msgid "%{count} total weight"
+msgstr ""
+
msgid "%{dashboard_path} could not be found."
msgstr ""
@@ -440,6 +489,9 @@ msgstr ""
msgid "%{group_name} uses group managed accounts. You need to create a new GitLab account which will be managed by %{group_name}."
msgstr ""
+msgid "%{group_name}&%{epic_iid} &middot; opened %{epic_created} by %{author}"
+msgstr ""
+
msgid "%{host} sign-in from new location"
msgstr ""
@@ -452,7 +504,7 @@ msgstr ""
msgid "%{issuableType} will be removed! Are you sure?"
msgstr ""
-msgid "%{issuesSize} issues with a limit of %{maxIssueCount}"
+msgid "%{issuesCount} issues with a limit of %{maxIssueCount}"
msgstr ""
msgid "%{issuesSize} with a limit of %{maxIssueCount}"
@@ -485,7 +537,7 @@ msgstr ""
msgid "%{labelStart}Namespace:%{labelEnd} %{namespace}"
msgstr ""
-msgid "%{labelStart}Report Type:%{labelEnd} %{reportType}"
+msgid "%{labelStart}Scan Type:%{labelEnd} %{reportType}"
msgstr ""
msgid "%{labelStart}Scanner:%{labelEnd} %{scanner}"
@@ -682,9 +734,6 @@ msgid_plural "%{securityScanner} results are not available because a pipeline ha
msgstr[0] ""
msgstr[1] ""
-msgid "%{service_title} %{message}."
-msgstr ""
-
msgid "%{size} GiB"
msgstr ""
@@ -773,6 +822,12 @@ msgstr ""
msgid "%{timebox_name} should belong either to a project or a group."
msgstr ""
+msgid "%{timebox_type} does not support burnup charts"
+msgstr ""
+
+msgid "%{timebox_type} must have a start and due date"
+msgstr ""
+
msgid "%{title} %{operator} %{threshold}"
msgstr ""
@@ -797,7 +852,7 @@ msgstr ""
msgid "%{total} open issue weight"
msgstr ""
-msgid "%{total} open issues"
+msgid "%{total} warnings found: showing first %{warningsDisplayed}"
msgstr ""
msgid "%{usage_ping_link_start}Learn more%{usage_ping_link_end} about what information is shared with GitLab Inc."
@@ -830,9 +885,6 @@ msgstr ""
msgid "&lt; 1 hour"
msgstr ""
-msgid "&lt;no name set&gt;"
-msgstr ""
-
msgid "&lt;no scopes selected&gt;"
msgstr ""
@@ -863,6 +915,9 @@ msgstr ""
msgid "'%{name}' Value Stream created"
msgstr ""
+msgid "'%{name}' Value Stream deleted"
+msgstr ""
+
msgid "'%{name}' stage already exists"
msgstr ""
@@ -922,6 +977,9 @@ msgstr ""
msgid "+ %{numberOfHiddenAssignees} more"
msgstr ""
+msgid "+ %{numberOfHiddenReviewers} more"
+msgstr ""
+
msgid "+%d more"
msgid_plural "+%d more"
msgstr[0] ""
@@ -982,6 +1040,11 @@ msgid_plural "%d Days"
msgstr[0] ""
msgstr[1] ""
+msgid "1 Issue"
+msgid_plural "%d Issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "1 closed issue"
msgid_plural "%{issues} closed issues"
msgstr[0] ""
@@ -997,6 +1060,11 @@ msgid_plural "%d days"
msgstr[0] ""
msgstr[1] ""
+msgid "1 deploy key"
+msgid_plural "%d deploy keys"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1099,6 +1167,9 @@ msgstr ""
msgid ":%{startLine} to %{endLine}"
msgstr ""
+msgid "A %{incident_docs_start}modified issue%{incident_docs_end} to guide the resolution of incidents."
+msgstr ""
+
msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr ""
@@ -1111,6 +1182,9 @@ msgstr ""
msgid "A GitBook site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
+msgid "A Gitpod configured Webapplication in Spring and Java"
+msgstr ""
+
msgid "A Hexo site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
@@ -1282,9 +1356,15 @@ msgstr ""
msgid "Access expiration date"
msgstr ""
+msgid "Access expires"
+msgstr ""
+
msgid "Access forbidden. Check your access level."
msgstr ""
+msgid "Access granted"
+msgstr ""
+
msgid "Access requests"
msgstr ""
@@ -1294,6 +1374,9 @@ msgstr ""
msgid "Access to Pages websites are controlled based on the user's membership to a given project. By checking this box, users will be required to be logged in to have access to all Pages websites in your instance."
msgstr ""
+msgid "AccessDropdown|Deploy Keys"
+msgstr ""
+
msgid "AccessDropdown|Groups"
msgstr ""
@@ -1411,12 +1494,6 @@ msgstr ""
msgid "Active Sessions"
msgstr ""
-msgid "Active Users:"
-msgstr ""
-
-msgid "Active users"
-msgstr ""
-
msgid "Activity"
msgstr ""
@@ -1584,9 +1661,6 @@ msgstr ""
msgid "Add label(s)"
msgstr ""
-msgid "Add license"
-msgstr ""
-
msgid "Add list"
msgstr ""
@@ -1761,21 +1835,51 @@ msgstr ""
msgid "AdminArea|Bots"
msgstr ""
+msgid "AdminArea|Components"
+msgstr ""
+
msgid "AdminArea|Developer"
msgstr ""
+msgid "AdminArea|Features"
+msgstr ""
+
+msgid "AdminArea|Groups: %{number_of_groups}"
+msgstr ""
+
msgid "AdminArea|Guest"
msgstr ""
msgid "AdminArea|Included Free in license"
msgstr ""
+msgid "AdminArea|Latest groups"
+msgstr ""
+
+msgid "AdminArea|Latest projects"
+msgstr ""
+
+msgid "AdminArea|Latest users"
+msgstr ""
+
msgid "AdminArea|Maintainer"
msgstr ""
+msgid "AdminArea|New group"
+msgstr ""
+
+msgid "AdminArea|New project"
+msgstr ""
+
+msgid "AdminArea|New user"
+msgstr ""
+
msgid "AdminArea|Owner"
msgstr ""
+msgid "AdminArea|Projects: %{number_of_projects}"
+msgstr ""
+
msgid "AdminArea|Reporter"
msgstr ""
@@ -1803,6 +1907,9 @@ msgstr ""
msgid "AdminArea|Users without a Group and Project"
msgstr ""
+msgid "AdminArea|Users: %{number_of_users}"
+msgstr ""
+
msgid "AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running."
msgstr ""
@@ -1821,9 +1928,6 @@ msgstr ""
msgid "AdminProjects|Delete Project %{projectName}?"
msgstr ""
-msgid "AdminProjects|Delete project"
-msgstr ""
-
msgid "AdminSettings|Apply integration settings to all Projects"
msgstr ""
@@ -2061,21 +2165,30 @@ msgstr ""
msgid "AdminUsers|Without projects"
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 ""
msgid "AdminUsers|You cannot remove your own admin rights."
msgstr ""
+msgid "AdminUsers|You must transfer ownership or delete the groups owned by this user before you can delete their account"
+msgstr ""
+
msgid "Administration"
msgstr ""
msgid "Advanced"
msgstr ""
+msgid "Advanced Search"
+msgstr ""
+
+msgid "Advanced Search with Elasticsearch"
+msgstr ""
+
msgid "Advanced Settings"
msgstr ""
@@ -2153,6 +2266,9 @@ msgstr ""
msgid "AlertManagement|Edit"
msgstr ""
+msgid "AlertManagement|Environment"
+msgstr ""
+
msgid "AlertManagement|Events"
msgstr ""
@@ -2165,6 +2281,9 @@ msgstr ""
msgid "AlertManagement|Issue"
msgstr ""
+msgid "AlertManagement|Key"
+msgstr ""
+
msgid "AlertManagement|Low"
msgstr ""
@@ -2258,6 +2377,9 @@ msgstr ""
msgid "AlertManagement|Unknown"
msgstr ""
+msgid "AlertManagement|Value"
+msgstr ""
+
msgid "AlertManagement|View alerts in Opsgenie"
msgstr ""
@@ -2417,6 +2539,9 @@ msgstr ""
msgid "All projects"
msgstr ""
+msgid "All projects selected"
+msgstr ""
+
msgid "All security scans are enabled because %{linkStart}Auto DevOps%{linkEnd} is enabled on this project"
msgstr ""
@@ -2504,6 +2629,9 @@ msgstr ""
msgid "Almost there"
msgstr ""
+msgid "Already blocked"
+msgstr ""
+
msgid "Also called \"Issuer\" or \"Relying party trust identifier\""
msgstr ""
@@ -2558,6 +2686,9 @@ msgstr ""
msgid "An error has occurred"
msgstr ""
+msgid "An error occured while making the changes: %{error}"
+msgstr ""
+
msgid "An error occurred adding a draft to the thread."
msgstr ""
@@ -2585,12 +2716,6 @@ msgstr ""
msgid "An error occurred when toggling the notification subscription"
msgstr ""
-msgid "An error occurred when trying to resolve a comment. Please try again."
-msgstr ""
-
-msgid "An error occurred when trying to resolve a discussion. Please try again."
-msgstr ""
-
msgid "An error occurred when updating the issue weight"
msgstr ""
@@ -2606,12 +2731,6 @@ msgstr ""
msgid "An error occurred while checking group path. Please refresh and try again."
msgstr ""
-msgid "An error occurred while committing your changes."
-msgstr ""
-
-msgid "An error occurred while creating the list. Please try again."
-msgstr ""
-
msgid "An error occurred while decoding the file."
msgstr ""
@@ -2684,25 +2803,19 @@ msgstr ""
msgid "An error occurred while fetching the Service Desk address."
msgstr ""
-msgid "An error occurred while fetching the board issues. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the board lists. Please reload the page."
msgstr ""
msgid "An error occurred while fetching the board lists. Please try again."
msgstr ""
-msgid "An error occurred while fetching the board swimlanes. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the builds."
msgstr ""
msgid "An error occurred while fetching the job log."
msgstr ""
-msgid "An error occurred while fetching the job trace."
+msgid "An error occurred while fetching the job logs."
msgstr ""
msgid "An error occurred while fetching the job."
@@ -2849,9 +2962,6 @@ msgstr ""
msgid "An error occurred while saving assignees"
msgstr ""
-msgid "An error occurred while saving the template. Please check if the template exists."
-msgstr ""
-
msgid "An error occurred while searching for milestones"
msgstr ""
@@ -2870,10 +2980,10 @@ msgstr ""
msgid "An error occurred while updating approvers"
msgstr ""
-msgid "An error occurred while updating the comment"
+msgid "An error occurred while updating labels."
msgstr ""
-msgid "An error occurred while updating the list. Please try again."
+msgid "An error occurred while updating the comment"
msgstr ""
msgid "An error occurred while validating group path"
@@ -2927,6 +3037,9 @@ msgstr ""
msgid "An unknown error occurred while loading this graph."
msgstr ""
+msgid "An unknown error occurred."
+msgstr ""
+
msgid "Analytics"
msgstr ""
@@ -2960,10 +3073,10 @@ msgstr ""
msgid "Any"
msgstr ""
-msgid "Any Author"
+msgid "Any %{header}"
msgstr ""
-msgid "Any Status"
+msgid "Any Author"
msgstr ""
msgid "Any branch"
@@ -3017,6 +3130,9 @@ msgstr ""
msgid "Application ID"
msgstr ""
+msgid "Application limits saved successfully"
+msgstr ""
+
msgid "Application settings saved successfully"
msgstr ""
@@ -3226,6 +3342,9 @@ msgstr ""
msgid "Are you sure you want to close this blocked issue?"
msgstr ""
+msgid "Are you sure you want to delete \"%{name}\" Value Stream?"
+msgstr ""
+
msgid "Are you sure you want to delete %{name}?"
msgstr ""
@@ -3235,6 +3354,9 @@ msgstr ""
msgid "Are you sure you want to delete this %{typeOfComment}?"
msgstr ""
+msgid "Are you sure you want to delete this SSH key?"
+msgstr ""
+
msgid "Are you sure you want to delete this board?"
msgstr ""
@@ -3259,6 +3381,11 @@ msgstr ""
msgid "Are you sure you want to erase this build?"
msgstr ""
+msgid "Are you sure you want to import %d repository?"
+msgid_plural "Are you sure you want to import %d repositories?"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Are you sure you want to lose unsaved changes?"
msgstr ""
@@ -3268,15 +3395,15 @@ msgstr ""
msgid "Are you sure you want to merge immediately?"
msgstr ""
-msgid "Are you sure you want to permanently delete this license?"
-msgstr ""
-
msgid "Are you sure you want to re-deploy this environment?"
msgstr ""
msgid "Are you sure you want to regenerate the public key? You will have to update the public key on the remote server before mirroring will work again."
msgstr ""
+msgid "Are you sure you want to reindex?"
+msgstr ""
+
msgid "Are you sure you want to remove %{group_name}?"
msgstr ""
@@ -3304,6 +3431,9 @@ msgstr ""
msgid "Are you sure you want to revoke this nickname?"
msgstr ""
+msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
+msgstr ""
+
msgid "Are you sure you want to stop this environment?"
msgstr ""
@@ -3325,6 +3455,9 @@ msgstr ""
msgid "Are you sure? The device will be signed out of GitLab and all remember me tokens revoked."
msgstr ""
+msgid "Are you sure? This will invalidate your registered applications and U2F / WebAuthn devices."
+msgstr ""
+
msgid "Are you sure? This will invalidate your registered applications and U2F devices."
msgstr ""
@@ -3343,9 +3476,6 @@ msgstr ""
msgid "Artifacts"
msgstr ""
-msgid "As U2F devices are only supported by a few browsers, we require that you set up a two-factor authentication app before a U2F device. That way you'll always be able to log in - even when you're using an unsupported browser."
-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 ""
@@ -3539,6 +3669,9 @@ msgstr ""
msgid "AuditLogs|Target"
msgstr ""
+msgid "AuditLogs|This month"
+msgstr ""
+
msgid "AuditLogs|User Events"
msgstr ""
@@ -3578,6 +3711,9 @@ msgstr ""
msgid "Authentication via U2F device failed."
msgstr ""
+msgid "Authentication via WebAuthn device failed."
+msgstr ""
+
msgid "Author"
msgstr ""
@@ -3845,15 +3981,6 @@ msgstr ""
msgid "BambooService|You must set up automatic revision labeling and a repository trigger in Bamboo."
msgstr ""
-msgid "BatchComments|Delete all pending comments"
-msgstr ""
-
-msgid "BatchComments|Discard review?"
-msgstr ""
-
-msgid "BatchComments|You're about to discard your review which will delete all of your pending comments. The deleted comments %{strong_start}cannot%{strong_end} be restored."
-msgstr ""
-
msgid "Be careful. Changing the project's namespace can have unintended side effects."
msgstr ""
@@ -3875,6 +4002,9 @@ msgstr ""
msgid "Bi-weekly code coverage"
msgstr ""
+msgid "Billable Users:"
+msgstr ""
+
msgid "Billing"
msgstr ""
@@ -3884,7 +4014,7 @@ msgstr ""
msgid "BillingPlans|@%{user_name} you are currently using the %{plan_name} plan."
msgstr ""
-msgid "BillingPlans|Congratulations, your new trial is activated"
+msgid "BillingPlans|Congratulations, your free trial is activated."
msgstr ""
msgid "BillingPlans|If you would like to downgrade your plan please contact %{support_link_start}Customer Support%{support_link_end}."
@@ -3947,6 +4077,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Block user"
+msgstr ""
+
msgid "Blocked"
msgstr ""
@@ -3962,31 +4095,37 @@ msgstr ""
msgid "Blog"
msgstr ""
-msgid "Board name"
-msgstr ""
-
msgid "Board scope"
msgstr ""
msgid "Board scope affects which issues are displayed for anyone who visits this board"
msgstr ""
-msgid "BoardBlankState|Add default lists"
+msgid "Boards"
msgstr ""
-msgid "BoardBlankState|Add the following default lists to your Issue Board with one click:"
+msgid "Boards and Board Lists"
msgstr ""
-msgid "BoardBlankState|Nevermind, I'll use my own"
+msgid "Boards|An error occurred while creating the issue. Please try again."
msgstr ""
-msgid "BoardBlankState|Starting out with the default set of lists will get you right on the way to making the most of your board."
+msgid "Boards|An error occurred while creating the list. Please try again."
msgstr ""
-msgid "Boards"
+msgid "Boards|An error occurred while fetching issues. Please reload the page."
msgstr ""
-msgid "Boards and Board Lists"
+msgid "Boards|An error occurred while fetching the board issues. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching the board swimlanes. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while moving the issue. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while updating the list. Please try again."
msgstr ""
msgid "Boards|Collapse"
@@ -4013,7 +4152,7 @@ msgstr ""
msgid "Branch %{branch_name} was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr ""
-msgid "Branch has changed"
+msgid "Branch changed"
msgstr ""
msgid "Branch is already taken"
@@ -4319,6 +4458,9 @@ msgstr ""
msgid "CLOSED (MOVED)"
msgstr ""
+msgid "CODEOWNERS rule violation"
+msgstr ""
+
msgid "CONTRIBUTING"
msgstr ""
@@ -4349,9 +4491,6 @@ msgstr ""
msgid "Can't create snippet: %{err}"
msgstr ""
-msgid "Can't edit as source branch was deleted"
-msgstr ""
-
msgid "Can't fetch content for the blob: %{err}"
msgstr ""
@@ -4364,9 +4503,6 @@ msgstr ""
msgid "Can't load mermaid module: %{err}"
msgstr ""
-msgid "Can't remove group members without group managed account"
-msgstr ""
-
msgid "Can't scan the code?"
msgstr ""
@@ -4409,6 +4545,9 @@ msgstr ""
msgid "Cannot create the abuse report. This user has been blocked."
msgstr ""
+msgid "Cannot enable shared runners because parent group does not allow it"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -4514,6 +4653,15 @@ msgstr ""
msgid "Change your password or recover your current one"
msgstr ""
+msgid "ChangeReviewer|Reviewer changed from %{old} to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Reviewer changed to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Unassigned"
+msgstr ""
+
msgid "ChangeTypeActionLabel|Pick into branch"
msgstr ""
@@ -4553,6 +4701,9 @@ msgstr ""
msgid "Changes the title to \"%{title_param}\"."
msgstr ""
+msgid "Changes were successfully made."
+msgstr ""
+
msgid "Changes won't take place until the index is %{link_start}recreated%{link_end}."
msgstr ""
@@ -4958,6 +5109,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove variable"
+msgstr ""
+
msgid "CiVariables|Remove variable row"
msgstr ""
@@ -5036,9 +5190,6 @@ msgstr ""
msgid "Clear due date"
msgstr ""
-msgid "Clear input"
-msgstr ""
-
msgid "Clear recent searches"
msgstr ""
@@ -5087,6 +5238,9 @@ msgstr ""
msgid "Client authentication key password"
msgstr ""
+msgid "Client request timeout"
+msgstr ""
+
msgid "Clients"
msgstr ""
@@ -5171,6 +5325,27 @@ msgstr ""
msgid "Cluster type must be specificed for Stages::ClusterEndpointInserter"
msgstr ""
+msgid "ClusterAgents|Configuration"
+msgstr ""
+
+msgid "ClusterAgents|Connect your cluster with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate Kubernetes with a GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Name"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Agent also requires %{linkStart}enabling the Agent Server%{linkEnd}"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Kubernetes Agent allows an Infrastructure as Code, GitOps approach to integrating Kubernetes clusters with GitLab. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "ClusterAgent|This feature is only available for premium plans"
msgstr ""
@@ -5240,10 +5415,10 @@ msgstr ""
msgid "ClusterIntegration|All installed applications and related resources"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster."
+msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{linkStart}More information%{linkEnd}"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{startLink}More information%{endLink}"
+msgid "ClusterIntegration|Allow GitLab to manage namespaces and service accounts for this cluster."
msgstr ""
msgid "ClusterIntegration|Alternatively, "
@@ -5264,6 +5439,9 @@ msgstr ""
msgid "ClusterIntegration|An error occurred while trying to fetch zone machine types: %{error}"
msgstr ""
+msgid "ClusterIntegration|An unknown error occurred while attempting to connect to Kubernetes."
+msgstr ""
+
msgid "ClusterIntegration|Any project namespaces"
msgstr ""
@@ -5279,6 +5457,9 @@ msgstr ""
msgid "ClusterIntegration|Authenticate with Amazon Web Services"
msgstr ""
+msgid "ClusterIntegration|Authentication Error"
+msgstr ""
+
msgid "ClusterIntegration|Base domain"
msgstr ""
@@ -5297,13 +5478,22 @@ msgstr ""
msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}security group %{externalLinkIcon} %{endLink} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
+msgid "ClusterIntegration|Check your CA certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Check your cluster status"
+msgstr ""
+
+msgid "ClusterIntegration|Check your token"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}subnets %{externalLinkIcon} %{endLink} in your VPC where your worker nodes will run."
+msgid "ClusterIntegration|Choose the %{linkStart}security group %{linkEnd} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
msgstr ""
-msgid "ClusterIntegration|Choose the worker node %{startLink}instance type %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Choose the %{linkStart}subnets %{linkEnd} in your VPC where your worker nodes will run."
+msgstr ""
+
+msgid "ClusterIntegration|Choose the worker node %{linkStart}instance type%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Choose which applications to install on your Kubernetes cluster."
@@ -5315,10 +5505,7 @@ msgstr ""
msgid "ClusterIntegration|Clear cluster cache"
msgstr ""
-msgid "ClusterIntegration|Clear the local cache of namespace and service accounts. This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
-msgstr ""
-
-msgid "ClusterIntegration|Cluster being created"
+msgid "ClusterIntegration|Clear the local cache of namespace and service accounts."
msgstr ""
msgid "ClusterIntegration|Cluster management project (alpha)"
@@ -5330,15 +5517,21 @@ msgstr ""
msgid "ClusterIntegration|Cluster_applications artifact too big. Maximum allowable size: %{human_size}"
msgstr ""
-msgid "ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters."
+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|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}"
+msgid "ClusterIntegration|Clusters connected with a certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Connect cluster with certificate"
msgstr ""
msgid "ClusterIntegration|Connect existing cluster"
msgstr ""
+msgid "ClusterIntegration|Connection Error"
+msgstr ""
+
msgid "ClusterIntegration|Copy API URL"
msgstr ""
@@ -5414,6 +5607,12 @@ msgstr ""
msgid "ClusterIntegration|Deletes all GitLab resources attached to this cluster during removal"
msgstr ""
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared."
+msgstr ""
+
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared. %{linkStart}More information%{linkEnd}"
+msgstr ""
+
msgid "ClusterIntegration|Did you know?"
msgstr ""
@@ -5483,6 +5682,9 @@ msgstr ""
msgid "ClusterIntegration|Fluentd is an open source data collector, which lets you unify the data collection and consumption for a better use and understanding of data. It requires at least one of the following logs to be successfully installed."
msgstr ""
+msgid "ClusterIntegration|GitLab Agent managed clusters"
+msgstr ""
+
msgid "ClusterIntegration|GitLab Container Network Policies"
msgstr ""
@@ -5495,6 +5697,12 @@ msgstr ""
msgid "ClusterIntegration|GitLab Runner connects to the repository and executes CI/CD jobs, pushing results back and deploying applications to production."
msgstr ""
+msgid "ClusterIntegration|GitLab failed to authenticate."
+msgstr ""
+
+msgid "ClusterIntegration|GitLab failed to connect to the cluster."
+msgstr ""
+
msgid "ClusterIntegration|GitLab-managed cluster"
msgstr ""
@@ -5516,6 +5724,9 @@ msgstr ""
msgid "ClusterIntegration|Group cluster"
msgstr ""
+msgid "ClusterIntegration|HTTP Error"
+msgstr ""
+
msgid "ClusterIntegration|Helm Tiller"
msgstr ""
@@ -5549,7 +5760,10 @@ msgstr ""
msgid "ClusterIntegration|Instance type"
msgstr ""
-msgid "ClusterIntegration|Integrate Kubernetes cluster automation"
+msgid "ClusterIntegration|Integrate Kubernetes with a cluster certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Integrate with a cluster certificate"
msgstr ""
msgid "ClusterIntegration|Issuer Email"
@@ -5585,9 +5799,6 @@ msgstr ""
msgid "ClusterIntegration|Knative extends Kubernetes to provide a set of middleware components that are essential to build modern, source-centric, and container-based applications that can run anywhere: on premises, in the cloud, or even in a third-party data center."
msgstr ""
-msgid "ClusterIntegration|Kubernetes cluster"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes cluster is being created..."
msgstr ""
@@ -5600,9 +5811,6 @@ msgstr ""
msgid "ClusterIntegration|Kubernetes clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr ""
-msgid "ClusterIntegration|Kubernetes clusters can be used to deploy applications and to provide Review Apps for this project"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes version"
msgstr ""
@@ -5615,7 +5823,7 @@ msgstr ""
msgid "ClusterIntegration|Learn more about %{help_link_start}zones%{help_link_end}."
msgstr ""
-msgid "ClusterIntegration|Learn more about %{startLink}Regions %{externalLinkIcon}%{endLink}."
+msgid "ClusterIntegration|Learn more about %{linkStart}Regions%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Learn more about Kubernetes"
@@ -5660,12 +5868,18 @@ msgstr ""
msgid "ClusterIntegration|Machine type"
msgstr ""
+msgid "ClusterIntegration|Make sure your API endpoint is correct"
+msgstr ""
+
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create Kubernetes clusters"
msgstr ""
msgid "ClusterIntegration|Manage your Kubernetes cluster by visiting %{provider_link}"
msgstr ""
+msgid "ClusterIntegration|Namespace per environment"
+msgstr ""
+
msgid "ClusterIntegration|No IAM Roles found"
msgstr ""
@@ -5711,6 +5925,9 @@ msgstr ""
msgid "ClusterIntegration|No zones matched your search"
msgstr ""
+msgid "ClusterIntegration|Node calculations use the Kubernetes Metrics API. Make sure your cluster has metrics installed"
+msgstr ""
+
msgid "ClusterIntegration|Number of nodes"
msgstr ""
@@ -5753,6 +5970,9 @@ msgstr ""
msgid "ClusterIntegration|RBAC-enabled cluster"
msgstr ""
+msgid "ClusterIntegration|Read our %{linkStart}help page%{linkEnd} on Kubernetes cluster integration."
+msgstr ""
+
msgid "ClusterIntegration|Read our %{link_start}help page%{link_end} on Kubernetes cluster integration."
msgstr ""
@@ -5855,7 +6075,7 @@ msgstr ""
msgid "ClusterIntegration|Select a VPC to choose a subnet"
msgstr ""
-msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{linkStart}Amazon Web Services %{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select a network to choose a subnetwork"
@@ -5888,7 +6108,7 @@ msgstr ""
msgid "ClusterIntegration|Select project to choose zone"
msgstr ""
-msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select zone"
@@ -5978,9 +6198,18 @@ msgstr ""
msgid "ClusterIntegration|There was a problem authenticating with your cluster. Please ensure your CA Certificate and Token are valid."
msgstr ""
+msgid "ClusterIntegration|There was an HTTP error when connecting to your cluster."
+msgstr ""
+
msgid "ClusterIntegration|This account must have permissions to create a Kubernetes cluster in the %{link_to_container_project} specified below"
msgstr ""
+msgid "ClusterIntegration|This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
+msgstr ""
+
+msgid "ClusterIntegration|This is necessary to clear existing environment-namespace associations from clusters previously managed by GitLab."
+msgstr ""
+
msgid "ClusterIntegration|This option will allow you to install applications on RBAC clusters."
msgstr ""
@@ -6005,9 +6234,21 @@ msgstr ""
msgid "ClusterIntegration|To use a new project, first create one on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}."
msgstr ""
+msgid "ClusterIntegration|Troubleshooting tips:"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Authenticate"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Connect"
+msgstr ""
+
msgid "ClusterIntegration|Uninstall %{appTitle}"
msgstr ""
+msgid "ClusterIntegration|Unknown Error"
+msgstr ""
+
msgid "ClusterIntegration|Update %{appTitle}"
msgstr ""
@@ -6068,7 +6309,7 @@ msgstr ""
msgid "ClusterIntegration|Your cluster API is unreachable. Please ensure your API URL is correct."
msgstr ""
-msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Zone"
@@ -6188,6 +6429,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse all threads"
+msgstr ""
+
msgid "Collapse approvers"
msgstr ""
@@ -6337,7 +6581,7 @@ msgstr ""
msgid "Commit…"
msgstr ""
-msgid "Company"
+msgid "Community forum"
msgstr ""
msgid "Company name"
@@ -6346,6 +6590,9 @@ msgstr ""
msgid "Compare"
msgstr ""
+msgid "Compare %{oldCommitId}...%{newCommitId}"
+msgstr ""
+
msgid "Compare Git revisions"
msgstr ""
@@ -6361,6 +6608,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare submodule commit revisions"
+msgstr ""
+
msgid "Compare with previous version"
msgstr ""
@@ -6496,6 +6746,9 @@ msgstr ""
msgid "Configure the way a user creates a new account."
msgstr ""
+msgid "Configure which lists are shown for anyone who visits this board"
+msgstr ""
+
msgid "Confirm"
msgstr ""
@@ -6721,6 +6974,9 @@ msgstr[1] ""
msgid "ContainerRegistry|Set cleanup policy"
msgstr ""
+msgid "ContainerRegistry|Some tags were not deleted"
+msgstr ""
+
msgid "ContainerRegistry|Something went wrong while fetching the cleanup policy."
msgstr ""
@@ -6760,6 +7016,9 @@ msgstr ""
msgid "ContainerRegistry|Tags with names matching this regex pattern will %{italicStart}expire:%{italicEnd}"
msgstr ""
+msgid "ContainerRegistry|The cleanup policy timed out before it could delete all tags. An administrator can %{adminLinkStart}manually run cleanup now%{adminLinkEnd} or you can wait for the cleanup policy to automatically run again. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "ContainerRegistry|The last tag related to this image was recently removed. This empty image and any associated data will be automatically removed as part of the regular Garbage Collection process. If you have any questions, contact your administrator."
msgstr ""
@@ -6892,6 +7151,9 @@ msgstr ""
msgid "Contributions per group member"
msgstr ""
+msgid "Contributor"
+msgstr ""
+
msgid "Contributors"
msgstr ""
@@ -7021,6 +7283,9 @@ msgstr ""
msgid "Could not change HEAD: branch '%{branch}' does not exist"
msgstr ""
+msgid "Could not commit. An unexpected error occurred."
+msgstr ""
+
msgid "Could not connect to FogBugz, check your URL"
msgstr ""
@@ -7060,6 +7325,9 @@ msgstr ""
msgid "Could not find iteration"
msgstr ""
+msgid "Could not load instance counts. Please refresh the page to try again."
+msgstr ""
+
msgid "Could not remove the trigger."
msgstr ""
@@ -7084,10 +7352,10 @@ msgstr ""
msgid "Could not save prometheus manual configuration"
msgstr ""
-msgid "Could not udpdate wiki page"
+msgid "Could not update the LDAP settings"
msgstr ""
-msgid "Could not update the LDAP settings"
+msgid "Could not update wiki page"
msgstr ""
msgid "Could not upload your designs as one or more files uploaded are not supported."
@@ -7745,6 +8013,9 @@ msgstr ""
msgid "DastProfiles|Are you sure you want to delete this profile?"
msgstr ""
+msgid "DastProfiles|Could not create site validation token. Please refresh the page, or try again later."
+msgstr ""
+
msgid "DastProfiles|Could not create the scanner profile. Please try again."
msgstr ""
@@ -7769,6 +8040,12 @@ msgstr ""
msgid "DastProfiles|Could not fetch site profiles. Please refresh the page, or try again later."
msgstr ""
+msgid "DastProfiles|Could not retrieve site validation status. Please refresh the page, or try again later."
+msgstr ""
+
+msgid "DastProfiles|Could not update the scanner profile. Please try again."
+msgstr ""
+
msgid "DastProfiles|Could not update the site profile. Please try again."
msgstr ""
@@ -7784,7 +8061,7 @@ msgstr ""
msgid "DastProfiles|Download validation text file"
msgstr ""
-msgid "DastProfiles|Edit feature will come soon. Please create a new profile if changes needed"
+msgid "DastProfiles|Edit scanner profile"
msgstr ""
msgid "DastProfiles|Edit site profile"
@@ -7817,6 +8094,9 @@ msgstr ""
msgid "DastProfiles|No profiles created yet"
msgstr ""
+msgid "DastProfiles|Passive"
+msgstr ""
+
msgid "DastProfiles|Please enter a valid URL format, ex: http://www.example.com/home"
msgstr ""
@@ -7832,6 +8112,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan mode"
+msgstr ""
+
msgid "DastProfiles|Scanner Profile"
msgstr ""
@@ -7871,10 +8154,10 @@ msgstr ""
msgid "DastProfiles|Text file validation"
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
+msgid "DastProfiles|The maximum number of minutes allowed for the spider to traverse the site."
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the spider to traverse the site."
+msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
msgstr ""
msgid "DastProfiles|Validate"
@@ -7907,6 +8190,9 @@ msgstr ""
msgid "Date picker"
msgstr ""
+msgid "Date range"
+msgstr ""
+
msgid "Date range cannot exceed %{maxDateRange} days."
msgstr ""
@@ -7931,6 +8217,9 @@ msgstr ""
msgid "Days to merge"
msgstr ""
+msgid "Dear Administrator,"
+msgstr ""
+
msgid "Debug"
msgstr ""
@@ -8042,12 +8331,18 @@ msgstr ""
msgid "Delete"
msgstr ""
+msgid "Delete %{name}"
+msgstr ""
+
msgid "Delete Comment"
msgstr ""
msgid "Delete Snippet"
msgstr ""
+msgid "Delete Value Stream"
+msgstr ""
+
msgid "Delete account"
msgstr ""
@@ -8069,9 +8364,6 @@ msgstr ""
msgid "Delete label: %{label_name} ?"
msgstr ""
-msgid "Delete license"
-msgstr ""
-
msgid "Delete list"
msgstr ""
@@ -8147,15 +8439,6 @@ msgstr ""
msgid "Deleting a project places it into a read-only state until %{date}, at which point the project will be permanently deleted. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "Deleting the license failed."
-msgstr ""
-
-msgid "Deleting the license failed. The license was not found."
-msgstr ""
-
-msgid "Deleting the license failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "Deleting the project will delete its repository and all related resources including issues, merge requests etc."
msgstr ""
@@ -8651,7 +8934,10 @@ msgstr ""
msgid "DesignManagement|The maximum number of designs allowed to be uploaded is %{upload_limit}. Please try again."
msgstr ""
-msgid "DesignManagement|To upload designs, you'll need to enable LFS. %{requirements_link_start}More information%{requirements_link_end}"
+msgid "DesignManagement|There was an error moving your designs. Please upload your designs below."
+msgstr ""
+
+msgid "DesignManagement|To upload designs, you'll need to enable LFS and have admin enable hashed storage. %{requirements_link_start}More information%{requirements_link_end}"
msgstr ""
msgid "DesignManagement|Unresolve thread"
@@ -8663,6 +8949,9 @@ msgstr ""
msgid "DesignManagement|Upload skipped."
msgstr ""
+msgid "DesignManagement|Your designs are being copied and are on their way… Please refresh to update."
+msgstr ""
+
msgid "DesignManagement|and %{moreCount} more."
msgstr ""
@@ -8720,6 +9009,9 @@ msgstr ""
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
+msgid "Direct member"
+msgstr ""
+
msgid "Direction"
msgstr ""
@@ -8768,9 +9060,6 @@ msgstr ""
msgid "Discard draft"
msgstr ""
-msgid "Discard review"
-msgstr ""
-
msgid "DiscordService|Discord Notifications"
msgstr ""
@@ -8839,10 +9128,10 @@ msgstr ""
msgid "Dismiss Merge Request promotion"
msgstr ""
-msgid "Dismiss Selected"
+msgid "Dismiss Value Stream Analytics introduction box"
msgstr ""
-msgid "Dismiss Value Stream Analytics introduction box"
+msgid "Dismiss selected"
msgstr ""
msgid "Dismiss trial promotion"
@@ -8893,9 +9182,6 @@ msgstr ""
msgid "Documents reindexed: %{processed_documents} (%{percentage}%%)"
msgstr ""
-msgid "Doing"
-msgstr ""
-
msgid "Domain"
msgstr ""
@@ -9091,9 +9377,6 @@ msgstr ""
msgid "Edit environment"
msgstr ""
-msgid "Edit file"
-msgstr ""
-
msgid "Edit files in the editor and commit changes here"
msgstr ""
@@ -9106,6 +9389,12 @@ msgstr ""
msgid "Edit identity for %{user_name}"
msgstr ""
+msgid "Edit in Web IDE"
+msgstr ""
+
+msgid "Edit in single-file editor"
+msgstr ""
+
msgid "Edit issues"
msgstr ""
@@ -9133,10 +9422,10 @@ msgstr ""
msgid "Editing"
msgstr ""
-msgid "Elasticsearch"
+msgid "Elasticsearch AWS IAM credentials"
msgstr ""
-msgid "Elasticsearch AWS IAM credentials"
+msgid "Elasticsearch HTTP client timeout value in seconds."
msgstr ""
msgid "Elasticsearch indexing restrictions"
@@ -9145,9 +9434,6 @@ msgstr ""
msgid "Elasticsearch indexing started"
msgstr ""
-msgid "Elasticsearch integration. Elasticsearch AWS IAM."
-msgstr ""
-
msgid "Elasticsearch reindexing is already in progress"
msgstr ""
@@ -9175,9 +9461,6 @@ msgstr ""
msgid "Email Notification"
msgstr ""
-msgid "Email address"
-msgstr ""
-
msgid "Email could not be sent"
msgstr ""
@@ -9241,6 +9524,9 @@ msgstr ""
msgid "Emails sent from Service Desk will have this name"
msgstr ""
+msgid "Emails sent to %{email} will still be supported"
+msgstr ""
+
msgid "Emails separated by comma"
msgstr ""
@@ -9274,9 +9560,18 @@ msgstr ""
msgid "Enable"
msgstr ""
+msgid "Enable %{link_start}Gitpod%{link_end} integration to launch a development environment in your browser directly from GitLab."
+msgstr ""
+
msgid "Enable Auto DevOps"
msgstr ""
+msgid "Enable Gitpod"
+msgstr ""
+
+msgid "Enable Gitpod?"
+msgstr ""
+
msgid "Enable HTML emails"
msgstr ""
@@ -9406,9 +9701,6 @@ msgstr ""
msgid "Encountered an error while rendering: %{err}"
msgstr ""
-msgid "End date"
-msgstr ""
-
msgid "Ends at (UTC)"
msgstr ""
@@ -9568,7 +9860,7 @@ msgstr ""
msgid "EnvironmentsDashboard|The environments dashboard provides a summary of each project's environments' status, including pipeline and alert statuses."
msgstr ""
-msgid "EnvironmentsDashboard|This dashboard displays a maximum of 7 projects and 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
+msgid "EnvironmentsDashboard|This dashboard displays 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
msgstr ""
msgid "Environments|An error occurred while canceling the auto stop, please try again"
@@ -9889,6 +10181,9 @@ msgstr ""
msgid "Error deleting project. Check logs for error details."
msgstr ""
+msgid "Error fetching burnup chart data"
+msgstr ""
+
msgid "Error fetching diverging counts for branches. Please try again."
msgstr ""
@@ -9967,6 +10262,9 @@ msgstr ""
msgid "Error occurred when saving assignees"
msgstr ""
+msgid "Error occurred when saving reviewers"
+msgstr ""
+
msgid "Error occurred when toggling the notification subscription"
msgstr ""
@@ -10219,10 +10517,13 @@ msgstr ""
msgid "Expand all"
msgstr ""
-msgid "Expand approvers"
+msgid "Expand all files"
msgstr ""
-msgid "Expand dropdown"
+msgid "Expand all threads"
+msgstr ""
+
+msgid "Expand approvers"
msgstr ""
msgid "Expand milestones"
@@ -10393,6 +10694,9 @@ msgstr ""
msgid "Failed to create Merge Request. Please try again."
msgstr ""
+msgid "Failed to create To-Do for the design."
+msgstr ""
+
msgid "Failed to create a branch for this issue. Please try again."
msgstr ""
@@ -10432,6 +10736,12 @@ msgstr ""
msgid "Failed to load authors. Please try again."
msgstr ""
+msgid "Failed to load branches. Please try again."
+msgstr ""
+
+msgid "Failed to load deploy keys."
+msgstr ""
+
msgid "Failed to load emoji list."
msgstr ""
@@ -10447,6 +10757,9 @@ msgstr ""
msgid "Failed to load groups & users."
msgstr ""
+msgid "Failed to load groups, users and deploy keys."
+msgstr ""
+
msgid "Failed to load labels. Please try again."
msgstr ""
@@ -10456,6 +10769,12 @@ msgstr ""
msgid "Failed to load related branches"
msgstr ""
+msgid "Failed to load sidebar confidential toggle"
+msgstr ""
+
+msgid "Failed to load sidebar lock status"
+msgstr ""
+
msgid "Failed to load stacktrace."
msgstr ""
@@ -10483,6 +10802,9 @@ msgstr ""
msgid "Failed to publish issue on status page."
msgstr ""
+msgid "Failed to remove To-Do for the design."
+msgstr ""
+
msgid "Failed to remove a Zoom meeting"
msgstr ""
@@ -10525,6 +10847,9 @@ msgstr ""
msgid "Failed to signing using smartcard authentication"
msgstr ""
+msgid "Failed to toggle To-Do for the design."
+msgstr ""
+
msgid "Failed to update branch!"
msgstr ""
@@ -10638,7 +10963,7 @@ msgstr ""
msgid "FeatureFlags|Edit User List"
msgstr ""
-msgid "FeatureFlags|Enable features for specific users and specific environments by defining feature flag strategies."
+msgid "FeatureFlags|Enable features for specific users and environments by configuring feature flag strategies."
msgstr ""
msgid "FeatureFlags|Environment Spec"
@@ -10698,7 +11023,7 @@ msgstr ""
msgid "FeatureFlags|Include additional user IDs"
msgstr ""
-msgid "FeatureFlags|Install a %{docs_link_anchored_start}compatible client library%{docs_link_anchored_end} and specify the API URL, application name, and instance ID during the configuration setup. %{docs_link_start}More Information%{docs_link_end}"
+msgid "FeatureFlags|Install a %{docsLinkAnchoredStart}compatible client library%{docsLinkAnchoredEnd} and specify the API URL, application name, and instance ID during the configuration setup. %{docsLinkStart}More Information%{docsLinkEnd}"
msgstr ""
msgid "FeatureFlags|Instance ID"
@@ -10710,6 +11035,9 @@ msgstr ""
msgid "FeatureFlags|Loading feature flags"
msgstr ""
+msgid "FeatureFlags|Loading user lists"
+msgstr ""
+
msgid "FeatureFlags|More information"
msgstr ""
@@ -10728,7 +11056,7 @@ msgstr ""
msgid "FeatureFlags|New feature flag"
msgstr ""
-msgid "FeatureFlags|New list"
+msgid "FeatureFlags|New user list"
msgstr ""
msgid "FeatureFlags|Percent of users"
@@ -10767,6 +11095,9 @@ msgstr ""
msgid "FeatureFlags|There was an error fetching the feature flags."
msgstr ""
+msgid "FeatureFlags|There was an error fetching the user lists."
+msgstr ""
+
msgid "FeatureFlags|There was an error retrieving user lists"
msgstr ""
@@ -10782,6 +11113,9 @@ msgstr ""
msgid "FeatureFlags|User List"
msgstr ""
+msgid "FeatureFlags|User Lists"
+msgstr ""
+
msgid "FeatureFlag|List"
msgstr ""
@@ -10809,15 +11143,6 @@ msgstr ""
msgid "Fetching incoming email"
msgstr ""
-msgid "Fetching licenses failed."
-msgstr ""
-
-msgid "Fetching licenses failed. The request endpoint was not found."
-msgstr ""
-
-msgid "Fetching licenses failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "File"
msgstr ""
@@ -10920,12 +11245,21 @@ msgstr ""
msgid "Filter by status"
msgstr ""
+msgid "Filter by test cases that are currently archived."
+msgstr ""
+
+msgid "Filter by test cases that are currently opened."
+msgstr ""
+
msgid "Filter by two-factor authentication"
msgstr ""
msgid "Filter by user"
msgstr ""
+msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
+msgstr ""
+
msgid "Filter pipelines"
msgstr ""
@@ -10941,7 +11275,7 @@ msgstr ""
msgid "Filter results..."
msgstr ""
-msgid "Filter your projects by name"
+msgid "Filter your repositories by name"
msgstr ""
msgid "Filter..."
@@ -10950,7 +11284,7 @@ msgstr ""
msgid "Find File"
msgstr ""
-msgid "Find bugs in your code with coverage-guided fuzzing"
+msgid "Find bugs in your code with coverage-guided fuzzing."
msgstr ""
msgid "Find by path"
@@ -10977,9 +11311,6 @@ msgstr ""
msgid "Finish editing this message first!"
msgstr ""
-msgid "Finish review"
-msgstr ""
-
msgid "Finish setting up your dedicated account for %{group_name}."
msgstr ""
@@ -11049,6 +11380,9 @@ msgstr ""
msgid "Footer message"
msgstr ""
+msgid "For a faster browsing experience, some files are collapsed by default."
+msgstr ""
+
msgid "For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
@@ -11058,6 +11392,9 @@ msgstr ""
msgid "For more info, read the documentation."
msgstr ""
+msgid "For more information on how the number of active users is calculated, see the %{self_managed_subscriptions_doc_link} documentation."
+msgstr ""
+
msgid "For more information, go to the "
msgstr ""
@@ -11196,6 +11533,9 @@ msgstr ""
msgid "Generate new token"
msgstr ""
+msgid "Generic package file size in bytes"
+msgstr ""
+
msgid "Geo"
msgstr ""
@@ -11457,6 +11797,9 @@ msgstr ""
msgid "Geo|Please refer to Geo Troubleshooting."
msgstr ""
+msgid "Geo|Primary node"
+msgstr ""
+
msgid "Geo|Project"
msgstr ""
@@ -11499,6 +11842,9 @@ msgstr ""
msgid "Geo|Review replication status, and resynchronize and reverify items with the primary node."
msgstr ""
+msgid "Geo|Secondary node"
+msgstr ""
+
msgid "Geo|Status"
msgstr ""
@@ -11538,6 +11884,9 @@ msgstr ""
msgid "Geo|URL must be a valid url (ex: https://gitlab.com)"
msgstr ""
+msgid "Geo|Undefined"
+msgstr ""
+
msgid "Geo|Unknown state"
msgstr ""
@@ -11613,10 +11962,16 @@ msgstr ""
msgid "GitHub import"
msgstr ""
+msgid "GitLab"
+msgstr ""
+
msgid "GitLab / Unsubscribe"
msgstr ""
-msgid "GitLab Enterprise Edition %{plan}"
+msgid "GitLab API"
+msgstr ""
+
+msgid "GitLab Billing Team."
msgstr ""
msgid "GitLab Group Runners can execute code for all the projects in this group."
@@ -11628,12 +11983,18 @@ msgstr ""
msgid "GitLab Issue"
msgstr ""
+msgid "GitLab Pages"
+msgstr ""
+
msgid "GitLab Service Desk is a simple way to allow people to create issues in your GitLab instance without needing their own user account. It provides a unique email address for end users to create issues in a project, and replies can be sent either through the GitLab interface or by email. End users will only see the thread through email."
msgstr ""
msgid "GitLab Shared Runners execute code of different projects on the same Runner unless you configure GitLab Runner Autoscale with MaxBuilds 1 (which it is on GitLab.com)."
msgstr ""
+msgid "GitLab Shell"
+msgstr ""
+
msgid "GitLab Support Bot"
msgstr ""
@@ -11643,7 +12004,7 @@ msgstr ""
msgid "GitLab User"
msgstr ""
-msgid "GitLab allows you to continue using your license even if you exceed the number of seats you purchased. You will be required to pay for these seats when you renew your license."
+msgid "GitLab Workhorse"
msgstr ""
msgid "GitLab commit"
@@ -11811,6 +12172,21 @@ msgstr ""
msgid "Gitlab Pages"
msgstr ""
+msgid "Gitpod"
+msgstr ""
+
+msgid "Gitpod|Add the URL to your Gitpod instance configured to read your GitLab projects."
+msgstr ""
+
+msgid "Gitpod|Enable Gitpod integration"
+msgstr ""
+
+msgid "Gitpod|Gitpod URL"
+msgstr ""
+
+msgid "Gitpod|e.g. https://gitpod.example.com"
+msgstr ""
+
msgid "Given access %{time_ago}"
msgstr ""
@@ -12318,9 +12694,6 @@ msgstr ""
msgid "GroupSAML|Valid SAML Response"
msgstr ""
-msgid "GroupSAML|With group managed accounts enabled, all the users without a group managed account will be excluded from the group."
-msgstr ""
-
msgid "GroupSAML|With prohibit outer forks flag enabled group members will be able to fork project only inside your group."
msgstr ""
@@ -12534,10 +12907,10 @@ msgstr ""
msgid "GroupsNew|Create group"
msgstr ""
-msgid "GroupsNew|GitLab group export"
+msgid "GroupsNew|Import"
msgstr ""
-msgid "GroupsNew|Import"
+msgid "GroupsNew|Import a GitLab group export file"
msgstr ""
msgid "GroupsNew|Import group"
@@ -12680,6 +13053,9 @@ msgid_plural "Hide charts"
msgstr[0] ""
msgstr[1] ""
+msgid "Hide comments on this file"
+msgstr ""
+
msgid "Hide details"
msgstr ""
@@ -12724,6 +13100,15 @@ msgstr ""
msgid "Highest role:"
msgstr ""
+msgid "HighlightBar|Alert events:"
+msgstr ""
+
+msgid "HighlightBar|Alert start time:"
+msgstr ""
+
+msgid "HighlightBar|Original alert:"
+msgstr ""
+
msgid "History"
msgstr ""
@@ -12901,6 +13286,9 @@ msgstr ""
msgid "If enabled, access to projects will be validated on an external service using their classification label."
msgstr ""
+msgid "If the number of active users exceeds the user limit, you will be charged for the number of %{users_over_license_link} at your next license reconciliation."
+msgstr ""
+
msgid "If there is no previous license or if the previous license has expired, some GitLab functionality will be blocked until a new, valid license is uploaded."
msgstr ""
@@ -12940,9 +13328,6 @@ msgstr ""
msgid "If your HTTP repository is not publicly accessible, add your credentials."
msgstr ""
-msgid "Iglu registry URL (optional)"
-msgstr ""
-
msgid "Ignore"
msgstr ""
@@ -12979,6 +13364,16 @@ msgstr ""
msgid "Import"
msgstr ""
+msgid "Import %d compatible repository"
+msgid_plural "Import %d compatible repositories"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Import %d repository"
+msgid_plural "Import %d repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Import CSV"
msgstr ""
@@ -12988,15 +13383,9 @@ msgstr ""
msgid "Import all compatible projects"
msgstr ""
-msgid "Import all compatible repositories"
-msgstr ""
-
msgid "Import all projects"
msgstr ""
-msgid "Import all repositories"
-msgstr ""
-
msgid "Import an exported GitLab project"
msgstr ""
@@ -13084,6 +13473,9 @@ msgstr ""
msgid "ImportProjects|Error importing repository %{project_safe_import_url} into %{project_full_path} - %{message}"
msgstr ""
+msgid "ImportProjects|Import repositories"
+msgstr ""
+
msgid "ImportProjects|Importing the project failed"
msgstr ""
@@ -13096,7 +13488,7 @@ msgstr ""
msgid "ImportProjects|Requesting your %{provider} repositories failed"
msgstr ""
-msgid "ImportProjects|Select the projects you want to import"
+msgid "ImportProjects|Select the repositories you want to import"
msgstr ""
msgid "ImportProjects|The remote data could not be imported."
@@ -13132,9 +13524,6 @@ msgstr ""
msgid "In order to enable Service Desk for your instance, you must first set up incoming email."
msgstr ""
-msgid "In order to gather accurate feature usage data, it can take 1 to 2 weeks to see your index."
-msgstr ""
-
msgid "In order to personalize your experience with GitLab%{br_tag}we would like to know a bit more about you."
msgstr ""
@@ -13165,18 +13554,30 @@ msgstr ""
msgid "IncidentManagement|Create incident"
msgstr ""
+msgid "IncidentManagement|Critical - S1"
+msgstr ""
+
msgid "IncidentManagement|Date created"
msgstr ""
msgid "IncidentManagement|Display your incidents in a dedicated view"
msgstr ""
+msgid "IncidentManagement|High - S2"
+msgstr ""
+
msgid "IncidentManagement|Incident"
msgstr ""
msgid "IncidentManagement|Incidents"
msgstr ""
+msgid "IncidentManagement|Low - S4"
+msgstr ""
+
+msgid "IncidentManagement|Medium - S3"
+msgstr ""
+
msgid "IncidentManagement|No incidents to display."
msgstr ""
@@ -13189,6 +13590,9 @@ msgstr ""
msgid "IncidentManagement|Published to status page"
msgstr ""
+msgid "IncidentManagement|Severity"
+msgstr ""
+
msgid "IncidentManagement|There are no closed incidents"
msgstr ""
@@ -13198,6 +13602,9 @@ msgstr ""
msgid "IncidentManagement|Unassigned"
msgstr ""
+msgid "IncidentManagement|Unknown"
+msgstr ""
+
msgid "IncidentManagement|Unpublished"
msgstr ""
@@ -13219,6 +13626,15 @@ msgstr ""
msgid "Incidents"
msgstr ""
+msgid "Incident|Alert details"
+msgstr ""
+
+msgid "Incident|Summary"
+msgstr ""
+
+msgid "Incident|There was an issue loading alert data. Please try again."
+msgstr ""
+
msgid "Include a Terms of Service agreement and Privacy Policy that all users must accept."
msgstr ""
@@ -13279,6 +13695,9 @@ msgstr ""
msgid "Information about additional Pages templates and how to install them can be found in our %{pages_getting_started_guide}."
msgstr ""
+msgid "Inherited"
+msgstr ""
+
msgid "Inherited:"
msgstr ""
@@ -13359,7 +13778,22 @@ msgstr ""
msgid "Instance administrators group already exists"
msgstr ""
-msgid "Instance license"
+msgid "InstanceStatistics|Groups"
+msgstr ""
+
+msgid "InstanceStatistics|Issues"
+msgstr ""
+
+msgid "InstanceStatistics|Merge Requests"
+msgstr ""
+
+msgid "InstanceStatistics|Pipelines"
+msgstr ""
+
+msgid "InstanceStatistics|Projects"
+msgstr ""
+
+msgid "InstanceStatistics|Users"
msgstr ""
msgid "Integration"
@@ -13371,6 +13805,12 @@ msgstr ""
msgid "Integrations"
msgstr ""
+msgid "Integrations|%{integration} settings saved and active."
+msgstr ""
+
+msgid "Integrations|%{integration} settings saved, but not active."
+msgstr ""
+
msgid "Integrations|All details"
msgstr ""
@@ -13380,6 +13820,12 @@ msgstr ""
msgid "Integrations|Comment settings:"
msgstr ""
+msgid "Integrations|Connection failed. Please check your settings."
+msgstr ""
+
+msgid "Integrations|Connection successful."
+msgstr ""
+
msgid "Integrations|Default settings are inherited from the group level."
msgstr ""
@@ -13395,6 +13841,15 @@ msgstr ""
msgid "Integrations|Includes commit title and branch"
msgstr ""
+msgid "Integrations|Projects using custom settings will not be impacted unless the project owner chooses to use instance-level defaults."
+msgstr ""
+
+msgid "Integrations|Save settings?"
+msgstr ""
+
+msgid "Integrations|Saving will update the default settings for all projects that are not using custom settings."
+msgstr ""
+
msgid "Integrations|Standard"
msgstr ""
@@ -13527,6 +13982,9 @@ msgstr ""
msgid "Invitation"
msgstr ""
+msgid "Invitation declined"
+msgstr ""
+
msgid "Invite"
msgstr ""
@@ -13578,6 +14036,42 @@ 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|%{linkStart}Read more%{linkEnd} about role permissions"
+msgstr ""
+
+msgid "InviteMembersModal|Access expiration date (optional)"
+msgstr ""
+
+msgid "InviteMembersModal|Cancel"
+msgstr ""
+
+msgid "InviteMembersModal|Choose a role permission"
+msgstr ""
+
+msgid "InviteMembersModal|GitLab member or Email address"
+msgstr ""
+
+msgid "InviteMembersModal|Invite"
+msgstr ""
+
+msgid "InviteMembersModal|Invite team members"
+msgstr ""
+
+msgid "InviteMembersModal|Search for members to invite"
+msgstr ""
+
+msgid "InviteMembersModal|User not invited. Feature coming soon!"
+msgstr ""
+
+msgid "InviteMembersModal|Users were succesfully added"
+msgstr ""
+
+msgid "InviteMembersModal|You're inviting members to the %{group_name} group"
+msgstr ""
+
+msgid "InviteMembers|Invite team members"
+msgstr ""
+
msgid "Invited"
msgstr ""
@@ -13632,10 +14126,13 @@ msgstr ""
msgid "Issue cannot be found."
msgstr ""
+msgid "Issue created from vulnerability %{vulnerability_link}"
+msgstr ""
+
msgid "Issue events"
msgstr ""
-msgid "Issue first depoloyed to production"
+msgid "Issue first deployed to production"
msgstr ""
msgid "Issue label"
@@ -13713,6 +14210,9 @@ msgstr ""
msgid "IssueTracker|Custom issue tracker"
msgstr ""
+msgid "IssueTracker|EWM work items tracker"
+msgstr ""
+
msgid "IssueTracker|Redmine issue tracker"
msgstr ""
@@ -13779,6 +14279,9 @@ msgstr ""
msgid "It looks like you have some draft commits in this branch."
msgstr ""
+msgid "It may be several days before you see feature usage data."
+msgstr ""
+
msgid "It must have a header row and at least two columns: the first column is the issue title and the second column is the issue description. The separator is automatically detected."
msgstr ""
@@ -14061,13 +14564,13 @@ msgstr ""
msgid "Join Zoom meeting"
msgstr ""
-msgid "Jul"
+msgid "Joined %{time_ago}"
msgstr ""
-msgid "July"
+msgid "Jul"
msgstr ""
-msgid "Jump to first unresolved thread"
+msgid "July"
msgstr ""
msgid "Jump to next unresolved thread"
@@ -14103,6 +14606,9 @@ msgstr ""
msgid "Keyboard shortcuts"
msgstr ""
+msgid "KeyboardKey|Ctrl+"
+msgstr ""
+
msgid "Keys"
msgstr ""
@@ -14151,6 +14657,9 @@ msgstr ""
msgid "LDAP Synchronization"
msgstr ""
+msgid "LDAP group settings"
+msgstr ""
+
msgid "LDAP settings"
msgstr ""
@@ -14160,6 +14669,9 @@ msgstr ""
msgid "LDAP sync in progress. This could take a few minutes. Refresh the page to see the changes."
msgstr ""
+msgid "LDAP synchronizations"
+msgstr ""
+
msgid "LFS"
msgstr ""
@@ -14240,7 +14752,16 @@ msgid_plural "Last %d days"
msgstr[0] ""
msgstr[1] ""
-msgid "Last %{days} days"
+msgid "Last 2 weeks"
+msgstr ""
+
+msgid "Last 30 days"
+msgstr ""
+
+msgid "Last 60 days"
+msgstr ""
+
+msgid "Last 90 days"
msgstr ""
msgid "Last Accessed On"
@@ -14318,6 +14839,9 @@ msgstr ""
msgid "Last used on:"
msgstr ""
+msgid "Last week"
+msgstr ""
+
msgid "LastCommit|authored"
msgstr ""
@@ -14333,6 +14857,9 @@ msgstr ""
msgid "Latest pipeline for the most recent commit on this branch"
msgstr ""
+msgid "Launch a ready-to-code development environment for your project."
+msgstr ""
+
msgid "Lead"
msgstr ""
@@ -14713,6 +15240,9 @@ msgstr ""
msgid "List of all merge commits"
msgstr ""
+msgid "List options"
+msgstr ""
+
msgid "List settings"
msgstr ""
@@ -14725,9 +15255,6 @@ msgstr ""
msgid "List your Bitbucket Server repositories"
msgstr ""
-msgid "Lists"
-msgstr ""
-
msgid "Live preview"
msgstr ""
@@ -14974,6 +15501,12 @@ msgstr ""
msgid "Mark as done"
msgstr ""
+msgid "Mark as draft"
+msgstr ""
+
+msgid "Mark as ready"
+msgstr ""
+
msgid "Mark as resolved"
msgstr ""
@@ -14995,6 +15528,24 @@ msgstr ""
msgid "Markdown is supported"
msgstr ""
+msgid "MarkdownEditor|Add a link (%{modifierKey}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add a link (%{modifier_key}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifierKey}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifier_key}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifierKey}I)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifier_key}I)"
+msgstr ""
+
msgid "Marked For Deletion At - %{deletion_time}"
msgstr ""
@@ -15079,7 +15630,25 @@ msgstr ""
msgid "Max access level"
msgstr ""
-msgid "Max seats used"
+msgid "Max role"
+msgstr ""
+
+msgid "Max size 15 MB"
+msgstr ""
+
+msgid "Maximum Conan package file size in bytes"
+msgstr ""
+
+msgid "Maximum Maven package file size in bytes"
+msgstr ""
+
+msgid "Maximum NPM package file size in bytes"
+msgstr ""
+
+msgid "Maximum NuGet package file size in bytes"
+msgstr ""
+
+msgid "Maximum PyPI package file size in bytes"
msgstr ""
msgid "Maximum Users:"
@@ -15211,6 +15780,18 @@ msgstr ""
msgid "Members with access to %{strong_start}%{group_name}%{strong_end}"
msgstr ""
+msgid "Members|%{time} by %{user}"
+msgstr ""
+
+msgid "Members|Expired"
+msgstr ""
+
+msgid "Members|No expiration set"
+msgstr ""
+
+msgid "Members|in %{time}"
+msgstr ""
+
msgid "Memory Usage"
msgstr ""
@@ -15397,9 +15978,6 @@ msgstr ""
msgid "MergeRequests|Thread will be unresolved"
msgstr ""
-msgid "MergeRequests|Toggle comments for this file"
-msgstr ""
-
msgid "MergeRequests|View file @ %{commitId}"
msgstr ""
@@ -15460,6 +16038,9 @@ msgstr ""
msgid "Merging immediately isn't recommended as it may negatively impact the existing merge train. Read the %{docsLinkStart}documentation%{docsLinkEnd} for more information."
msgstr ""
+msgid "Message"
+msgstr ""
+
msgid "Messages"
msgstr ""
@@ -15845,18 +16426,12 @@ msgid_plural "Milestones"
msgstr[0] ""
msgstr[1] ""
-msgid "Milestone does not support burnup charts"
-msgstr ""
-
msgid "Milestone lists not available with your current license"
msgstr ""
msgid "Milestone lists show all issues from the selected milestone."
msgstr ""
-msgid "Milestone must have a start and due date"
-msgstr ""
-
msgid "MilestoneSidebar|Closed:"
msgstr ""
@@ -16223,6 +16798,9 @@ msgstr ""
msgid "Namespace"
msgstr ""
+msgid "Namespace ID:"
+msgstr ""
+
msgid "Namespace is empty"
msgstr ""
@@ -16307,6 +16885,9 @@ msgstr ""
msgid "NetworkPolicies|Allow all outbound traffic from %{selector} to %{ruleSelector} on %{ports}"
msgstr ""
+msgid "NetworkPolicies|Are you sure you want to delete this policy? This action cannot be undone."
+msgstr ""
+
msgid "NetworkPolicies|Choose whether to enforce this policy."
msgstr ""
@@ -16316,12 +16897,21 @@ msgstr ""
msgid "NetworkPolicies|Define this policy's location, conditions and actions."
msgstr ""
+msgid "NetworkPolicies|Delete policy"
+msgstr ""
+
+msgid "NetworkPolicies|Delete policy: %{policy}"
+msgstr ""
+
msgid "NetworkPolicies|Deny all traffic"
msgstr ""
msgid "NetworkPolicies|Description"
msgstr ""
+msgid "NetworkPolicies|Edit policy"
+msgstr ""
+
msgid "NetworkPolicies|Editor mode"
msgstr ""
@@ -16349,6 +16939,9 @@ msgstr ""
msgid "NetworkPolicies|Name"
msgstr ""
+msgid "NetworkPolicies|Namespace"
+msgstr ""
+
msgid "NetworkPolicies|Network Policy"
msgstr ""
@@ -16400,6 +16993,9 @@ msgstr ""
msgid "NetworkPolicies|Rules"
msgstr ""
+msgid "NetworkPolicies|Save changes"
+msgstr ""
+
msgid "NetworkPolicies|Something went wrong, failed to update policy"
msgstr ""
@@ -16412,6 +17008,9 @@ msgstr ""
msgid "NetworkPolicies|Traffic that does not match any rule will be blocked."
msgstr ""
+msgid "NetworkPolicies|Unable to parse policy"
+msgstr ""
+
msgid "NetworkPolicies|YAML editor"
msgstr ""
@@ -16525,6 +17124,9 @@ msgstr ""
msgid "New Snippet"
msgstr ""
+msgid "New Test Case"
+msgstr ""
+
msgid "New User"
msgstr ""
@@ -16624,6 +17226,9 @@ msgstr ""
msgid "New tag"
msgstr ""
+msgid "New test case"
+msgstr ""
+
msgid "New users set to external"
msgstr ""
@@ -16696,7 +17301,7 @@ msgstr ""
msgid "No changes"
msgstr ""
-msgid "No changes between %{ref_start}%{source_branch}%{ref_end} and %{ref_start}%{target_branch}%{ref_end}"
+msgid "No changes between %{sourceBranch} and %{targetBranch}"
msgstr ""
msgid "No child epics match applied filters"
@@ -16711,6 +17316,9 @@ msgstr ""
msgid "No containers available"
msgstr ""
+msgid "No content to show"
+msgstr ""
+
msgid "No contributions"
msgstr ""
@@ -16786,9 +17394,6 @@ msgstr ""
msgid "No license. All rights reserved"
msgstr ""
-msgid "No licenses found."
-msgstr ""
-
msgid "No matches found"
msgstr ""
@@ -16801,6 +17406,9 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No members found"
+msgstr ""
+
msgid "No merge requests found"
msgstr ""
@@ -16822,6 +17430,9 @@ msgstr ""
msgid "No parent group"
msgstr ""
+msgid "No plan"
+msgstr ""
+
msgid "No pods available"
msgstr ""
@@ -16918,6 +17529,12 @@ msgstr ""
msgid "Not Implemented"
msgstr ""
+msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+msgstr ""
+
+msgid "Not all browsers support WebAuthn. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even from an unsupported browser."
+msgstr ""
+
msgid "Not all data has been processed yet, the accuracy of the chart for the selected timeframe is limited."
msgstr ""
@@ -17014,6 +17631,9 @@ msgstr ""
msgid "Notification settings saved"
msgstr ""
+msgid "NotificationEvent|Change reviewer merge request"
+msgstr ""
+
msgid "NotificationEvent|Close issue"
msgstr ""
@@ -17176,10 +17796,7 @@ msgstr ""
msgid "On track"
msgstr ""
-msgid "OnDemandScans|Attached branch"
-msgstr ""
-
-msgid "OnDemandScans|Attached branch is where the scan job runs."
+msgid "OnDemandScans|Could not fetch scanner profiles. Please refresh the page, or try again later."
msgstr ""
msgid "OnDemandScans|Could not fetch site profiles. Please refresh the page, or try again later."
@@ -17188,6 +17805,9 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
+msgid "OnDemandScans|Create a new scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Create a new site profile"
msgstr ""
@@ -17200,6 +17820,9 @@ msgstr ""
msgid "OnDemandScans|New on-demand DAST scan"
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 ""
@@ -17209,16 +17832,10 @@ msgstr ""
msgid "OnDemandScans|On-demand scans run outside the DevOps cycle and find vulnerabilities in your projects. %{learnMoreLinkStart}Learn more%{learnMoreLinkEnd}"
msgstr ""
-msgid "OnDemandScans|Only a passive scan can be performed on demand."
-msgstr ""
-
-msgid "OnDemandScans|Passive"
-msgstr ""
-
msgid "OnDemandScans|Run scan"
msgstr ""
-msgid "OnDemandScans|Scan mode"
+msgid "OnDemandScans|Scanner profile"
msgstr ""
msgid "OnDemandScans|Scanner settings"
@@ -17230,9 +17847,15 @@ msgstr ""
msgid "OnDemandScans|Select one of the existing profiles"
msgstr ""
+msgid "OnDemandScans|Site profile"
+msgstr ""
+
msgid "OnDemandScans|Site profiles"
msgstr ""
+msgid "OnDemandScans|Use existing scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Use existing site profile"
msgstr ""
@@ -17331,9 +17954,6 @@ msgstr ""
msgid "Open Selection"
msgstr ""
-msgid "Open Web IDE"
-msgstr ""
-
msgid "Open comment type dropdown"
msgstr ""
@@ -17439,6 +18059,9 @@ msgstr ""
msgid "Origin"
msgstr ""
+msgid "Orphaned member"
+msgstr ""
+
msgid "Other Labels"
msgstr ""
@@ -17454,6 +18077,9 @@ msgstr ""
msgid "Other visibility settings have been disabled by the administrator."
msgstr ""
+msgid "Our documentation includes an example DevOps Score report."
+msgstr ""
+
msgid "Out-of-compliance with this project's policies and should be removed"
msgstr ""
@@ -17478,6 +18104,9 @@ msgstr ""
msgid "Overwrite diverged branches"
msgstr ""
+msgid "Owned by %{image_tag}"
+msgstr ""
+
msgid "Owned by anyone"
msgstr ""
@@ -17499,6 +18128,9 @@ msgstr ""
msgid "Package deleted successfully"
msgstr ""
+msgid "Package file size limits"
+msgstr ""
+
msgid "Package recipe already exists"
msgstr ""
@@ -17514,9 +18146,6 @@ msgstr ""
msgid "Package type must be PyPi"
msgstr ""
-msgid "Package was removed"
-msgstr ""
-
msgid "PackageRegistry|%{name} version %{version} was created %{datetime}"
msgstr ""
@@ -17658,12 +18287,18 @@ msgstr ""
msgid "PackageRegistry|NuGet Command"
msgstr ""
+msgid "PackageRegistry|Package Registry"
+msgstr ""
+
msgid "PackageRegistry|Pip Command"
msgstr ""
msgid "PackageRegistry|Pipeline %{link} triggered %{datetime} by %{author}"
msgstr ""
+msgid "PackageRegistry|Publish and share packages for a variety of common package managers. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "PackageRegistry|Published to the %{project} Package Registry %{datetime}"
msgstr ""
@@ -17763,6 +18398,9 @@ msgstr ""
msgid "Page not found"
msgstr ""
+msgid "Page settings"
+msgstr ""
+
msgid "Page was successfully deleted"
msgstr ""
@@ -17904,7 +18542,7 @@ msgstr ""
msgid "Paste issue link"
msgstr ""
-msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Don't use your private SSH key."
+msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Do not paste your private SSH key, as that can compromise your identity."
msgstr ""
msgid "Patch to apply"
@@ -17931,6 +18569,9 @@ msgstr ""
msgid "Pending"
msgstr ""
+msgid "Pending comments"
+msgstr ""
+
msgid "People without permission will never get a notification and won't be able to comment."
msgstr ""
@@ -18129,6 +18770,9 @@ msgstr ""
msgid "Pipelines|Build with confidence"
msgstr ""
+msgid "Pipelines|By revoking a trigger you will break any processes making use of it. Are you sure?"
+msgstr ""
+
msgid "Pipelines|CI Lint"
msgstr ""
@@ -18141,6 +18785,15 @@ msgstr ""
msgid "Pipelines|Continuous Integration can help catch bugs by running your tests automatically, while Continuous Deployment can help you deliver code to your product environment."
msgstr ""
+msgid "Pipelines|Copy trigger token"
+msgstr ""
+
+msgid "Pipelines|Description"
+msgstr ""
+
+msgid "Pipelines|Edit"
+msgstr ""
+
msgid "Pipelines|Get started with Pipelines"
msgstr ""
@@ -18156,15 +18809,27 @@ msgstr ""
msgid "Pipelines|It is recommended the code is reviewed thoroughly before running this pipeline with the parent project's CI resource."
msgstr ""
+msgid "Pipelines|Last Used"
+msgstr ""
+
msgid "Pipelines|Loading Pipelines"
msgstr ""
msgid "Pipelines|More Information"
msgstr ""
+msgid "Pipelines|No triggers have been created yet. Add one using the form above."
+msgstr ""
+
+msgid "Pipelines|Owner"
+msgstr ""
+
msgid "Pipelines|Project cache successfully reset."
msgstr ""
+msgid "Pipelines|Revoke"
+msgstr ""
+
msgid "Pipelines|Run Pipeline"
msgstr ""
@@ -18189,6 +18854,15 @@ msgstr ""
msgid "Pipelines|This project is not currently set up to run pipelines."
msgstr ""
+msgid "Pipelines|Token"
+msgstr ""
+
+msgid "Pipelines|Trigger user has insufficient permissions to project"
+msgstr ""
+
+msgid "Pipelines|invalid"
+msgstr ""
+
msgid "Pipelines|parent"
msgstr ""
@@ -18447,10 +19121,10 @@ msgstr ""
msgid "Please provide attributes to update"
msgstr ""
-msgid "Please refer to %{docs_url}"
+msgid "Please reach out if you have any questions and we'll be happy to assist."
msgstr ""
-msgid "Please retype the email address."
+msgid "Please refer to %{docs_url}"
msgstr ""
msgid "Please select"
@@ -18480,6 +19154,9 @@ msgstr ""
msgid "Please set a new password before proceeding."
msgstr ""
+msgid "Please share your feedback about %{featureName} %{linkStart}in this issue%{linkEnd} to help us improve the experience."
+msgstr ""
+
msgid "Please solve the reCAPTCHA"
msgstr ""
@@ -18783,6 +19460,9 @@ msgstr ""
msgid "Profiles| You are going to change the username %{currentUsernameBold} to %{newUsernameBold}. Profile and projects will be redirected to the %{newUsername} namespace but this redirect will expire once the %{currentUsername} namespace is registered by another user or group. Please update your Git repository remotes as soon as possible."
msgstr ""
+msgid "Profiles|%{provider} Active"
+msgstr ""
+
msgid "Profiles|@username"
msgstr ""
@@ -18834,7 +19514,7 @@ msgstr ""
msgid "Profiles|Commit email"
msgstr ""
-msgid "Profiles|Connect"
+msgid "Profiles|Connect %{provider}"
msgstr ""
msgid "Profiles|Connected Accounts"
@@ -18858,6 +19538,9 @@ msgstr ""
msgid "Profiles|Disconnect"
msgstr ""
+msgid "Profiles|Disconnect %{provider}"
+msgstr ""
+
msgid "Profiles|Do not show on profile"
msgstr ""
@@ -18882,7 +19565,7 @@ msgstr ""
msgid "Profiles|Full name"
msgstr ""
-msgid "Profiles|Give your individual key a title. This will be publically visible."
+msgid "Profiles|Give your individual key a title."
msgstr ""
msgid "Profiles|Include private contributions on my profile"
@@ -18972,7 +19655,7 @@ msgstr ""
msgid "Profiles|The maximum file size allowed is 200KB."
msgstr ""
-msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it?"
+msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it? It will be publicly visible."
msgstr ""
msgid "Profiles|This email will be displayed on your public profile"
@@ -19047,6 +19730,9 @@ msgstr ""
msgid "Profiles|You don't have access to delete this user."
msgstr ""
+msgid "Profiles|You must transfer ownership or delete groups you are an owner of before you can delete your account"
+msgstr ""
+
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
@@ -19635,6 +20321,9 @@ msgstr ""
msgid "ProjectTemplates|GitLab Cluster Management"
msgstr ""
+msgid "ProjectTemplates|Gitpod/Spring Petclinic"
+msgstr ""
+
msgid "ProjectTemplates|Go Micro"
msgstr ""
@@ -20244,6 +20933,9 @@ msgstr ""
msgid "Publish to status page"
msgstr ""
+msgid "Published"
+msgstr ""
+
msgid "Published on status page"
msgstr ""
@@ -20361,9 +21053,15 @@ msgstr ""
msgid "Quick range"
msgstr ""
+msgid "Quickly and easily edit multiple files in your project."
+msgstr ""
+
msgid "README"
msgstr ""
+msgid "Rails"
+msgstr ""
+
msgid "Rake Tasks Help"
msgstr ""
@@ -20483,10 +21181,13 @@ msgstr ""
msgid "Register Two-Factor Authenticator"
msgstr ""
-msgid "Register U2F device"
+msgid "Register Universal Two-Factor (U2F) Device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register WebAuthn Device"
+msgstr ""
+
+msgid "Register device"
msgstr ""
msgid "Register for GitLab"
@@ -20498,9 +21199,6 @@ msgstr ""
msgid "Register with two-factor app"
msgstr ""
-msgid "Registration"
-msgstr ""
-
msgid "Registration|Checkout"
msgstr ""
@@ -20617,9 +21315,6 @@ msgstr ""
msgid "Release|Something went wrong while saving the release details"
msgstr ""
-msgid "Remediated: needs review"
-msgstr ""
-
msgid "Remediations"
msgstr ""
@@ -20725,6 +21420,9 @@ msgstr ""
msgid "Remove priority"
msgstr ""
+msgid "Remove report"
+msgstr ""
+
msgid "Remove secondary node"
msgstr ""
@@ -20737,6 +21435,12 @@ msgstr ""
msgid "Remove time estimate"
msgstr ""
+msgid "Remove user & report"
+msgstr ""
+
+msgid "Remove user from group"
+msgstr ""
+
msgid "Removed"
msgstr ""
@@ -20818,9 +21522,6 @@ msgstr ""
msgid "Removes time estimate."
msgstr ""
-msgid "Removing license…"
-msgstr ""
-
msgid "Removing this group also removes all child projects, including archived projects, and their resources."
msgstr ""
@@ -20905,6 +21606,9 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
+msgid "Reported by %{reporter}"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -20991,6 +21695,27 @@ msgstr ""
msgid "Repositories"
msgstr ""
+msgid "Repositories Analytics"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download Historic Test Coverage Data"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download historic test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Historic Test Coverage Data is available in raw format (.csv) for further analysis."
+msgstr ""
+
+msgid "RepositoriesAnalytics|Test Code Coverage"
+msgstr ""
+
+msgid "RepositoriesAnalytics|There was an error fetching the projects."
+msgstr ""
+
msgid "Repository"
msgstr ""
@@ -21069,9 +21794,15 @@ msgstr ""
msgid "Request parameter %{param} is missing."
msgstr ""
+msgid "Request review from"
+msgstr ""
+
msgid "Request to link SAML account must be authorized"
msgstr ""
+msgid "Requested"
+msgstr ""
+
msgid "Requested %{time_ago}"
msgstr ""
@@ -21090,6 +21821,9 @@ msgstr ""
msgid "Requests to these domain(s)/address(es) on the local network will be allowed when local requests from hooks and services are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 or 127.0.0.0/28 are supported. Domain wildcards are not supported currently. Use comma, semicolon, or newline to separate multiple entries. The allowlist can hold a maximum of 1000 entries. Domains should use IDNA encoding. Ex: example.com, 192.168.1.1, 127.0.0.0/28, xn--itlab-j1a.com."
msgstr ""
+msgid "Require admin approval for new sign-ups"
+msgstr ""
+
msgid "Require all users in this group to setup Two-factor authentication"
msgstr ""
@@ -21217,9 +21951,6 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
-msgid "Resolved by %{resolvedByName}"
-msgstr ""
-
msgid "Resolves IP addresses once and uses them to submit requests"
msgstr ""
@@ -21339,6 +22070,14 @@ msgstr ""
msgid "ReviewApp|Enable Review App"
msgstr ""
+msgid "Reviewer"
+msgid_plural "%d Reviewers"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Reviewer(s)"
+msgstr ""
+
msgid "Reviewing"
msgstr ""
@@ -21378,6 +22117,9 @@ msgstr ""
msgid "Rook"
msgstr ""
+msgid "Ruby"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -21456,6 +22198,63 @@ msgstr ""
msgid "Runners page."
msgstr ""
+msgid "Runners|Active"
+msgstr ""
+
+msgid "Runners|Architecture"
+msgstr ""
+
+msgid "Runners|Can run untagged jobs"
+msgstr ""
+
+msgid "Runners|Description"
+msgstr ""
+
+msgid "Runners|Group"
+msgstr ""
+
+msgid "Runners|IP Address"
+msgstr ""
+
+msgid "Runners|Last contact"
+msgstr ""
+
+msgid "Runners|Locked to this project"
+msgstr ""
+
+msgid "Runners|Maximum job timeout"
+msgstr ""
+
+msgid "Runners|Name"
+msgstr ""
+
+msgid "Runners|Platform"
+msgstr ""
+
+msgid "Runners|Property Name"
+msgstr ""
+
+msgid "Runners|Protected"
+msgstr ""
+
+msgid "Runners|Revision"
+msgstr ""
+
+msgid "Runners|Shared"
+msgstr ""
+
+msgid "Runners|Specific"
+msgstr ""
+
+msgid "Runners|Tags"
+msgstr ""
+
+msgid "Runners|Value"
+msgstr ""
+
+msgid "Runners|Version"
+msgstr ""
+
msgid "Runners|You have used %{quotaUsed} out of %{quotaLimit} of your shared Runners pipeline minutes."
msgstr ""
@@ -21468,6 +22267,9 @@ msgstr ""
msgid "Runs a number of housekeeping tasks within the current repository, such as compressing file revisions and removing unreachable objects."
msgstr ""
+msgid "SAML"
+msgstr ""
+
msgid "SAML SSO"
msgstr ""
@@ -21519,6 +22321,9 @@ msgstr ""
msgid "Save"
msgstr ""
+msgid "Save %{name} size limits"
+msgstr ""
+
msgid "Save Changes"
msgstr ""
@@ -21549,9 +22354,6 @@ msgstr ""
msgid "Save space and find tags in the Container Registry more easily. Enable the cleanup policy to remove stale tags and keep only the ones you need."
msgstr ""
-msgid "Save template"
-msgstr ""
-
msgid "Save variables"
msgstr ""
@@ -21594,9 +22396,6 @@ msgstr ""
msgid "Scope"
msgstr ""
-msgid "Scope not supported with disabled 'users_search' feature!"
-msgstr ""
-
msgid "Scoped issue boards"
msgstr ""
@@ -21723,9 +22522,6 @@ msgstr ""
msgid "Search requirements"
msgstr ""
-msgid "Search results…"
-msgstr ""
-
msgid "Search users"
msgstr ""
@@ -21798,6 +22594,11 @@ msgid_plural "SearchResults|commits"
msgstr[0] ""
msgstr[1] ""
+msgid "SearchResults|epic"
+msgid_plural "SearchResults|epics"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "SearchResults|issue"
msgid_plural "SearchResults|issues"
msgstr[0] ""
@@ -21842,10 +22643,10 @@ msgstr ""
msgid "Seat Link is disabled, and cannot be configured through this form."
msgstr ""
-msgid "Seats currently in use"
+msgid "Seats usage data as of %{last_enqueue_time}"
msgstr ""
-msgid "Seats in license"
+msgid "Seats usage data is updated every day at 12:00pm UTC"
msgstr ""
msgid "Secondary"
@@ -21899,6 +22700,9 @@ msgstr ""
msgid "SecurityConfiguration|Available for on-demand DAST"
msgstr ""
+msgid "SecurityConfiguration|By default, all analyzers are applied in order to cover all languages across your project, and only run if the language is detected in the Merge Request."
+msgstr ""
+
msgid "SecurityConfiguration|Configure"
msgstr ""
@@ -21929,16 +22733,19 @@ msgstr ""
msgid "SecurityConfiguration|Manage"
msgstr ""
+msgid "SecurityConfiguration|More information"
+msgstr ""
+
msgid "SecurityConfiguration|Not enabled"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|Security Control"
+msgid "SecurityConfiguration|SAST Configuration"
msgstr ""
-msgid "SecurityConfiguration|See documentation"
+msgid "SecurityConfiguration|Security Control"
msgstr ""
msgid "SecurityConfiguration|Status"
@@ -21950,6 +22757,9 @@ msgstr ""
msgid "SecurityConfiguration|Using custom settings. You won't receive automatic updates on this variable. %{anchorStart}Restore to default%{anchorEnd}"
msgstr ""
+msgid "SecurityConfiguration|View history"
+msgstr ""
+
msgid "SecurityConfiguration|You can quickly enable all security scanning tools by enabling %{linkStart}Auto DevOps%{linkEnd}."
msgstr ""
@@ -22028,9 +22838,6 @@ msgstr ""
msgid "SecurityReports|Learn more about setting up your dashboard"
msgstr ""
-msgid "SecurityReports|Load more vulnerabilities"
-msgstr ""
-
msgid "SecurityReports|Monitor vulnerabilities in your code"
msgstr ""
@@ -22310,7 +23117,7 @@ msgstr ""
msgid "Select status"
msgstr ""
-msgid "Select strategy activation method"
+msgid "Select strategy activation method."
msgstr ""
msgid "Select subscription"
@@ -22325,7 +23132,7 @@ msgstr ""
msgid "Select the custom project template source group."
msgstr ""
-msgid "Select timeframe"
+msgid "Select the environment scope for this feature flag."
msgstr ""
msgid "Select timezone"
@@ -22574,6 +23381,9 @@ msgstr ""
msgid "Set iteration"
msgstr ""
+msgid "Set limit to 0 to allow any file size."
+msgstr ""
+
msgid "Set max session time for web terminal."
msgstr ""
@@ -22652,10 +23462,13 @@ msgstr ""
msgid "Set up a %{type} Runner manually"
msgstr ""
+msgid "Set up a hardware device as a second factor to sign in."
+msgstr ""
+
msgid "Set up assertions/attributes/claims (email, first_name, last_name) and NameID according to %{docsLinkStart}the documentation %{icon}%{docsLinkEnd}"
msgstr ""
-msgid "Set up new U2F device"
+msgid "Set up new device"
msgstr ""
msgid "Set up new password"
@@ -22724,6 +23537,9 @@ msgstr ""
msgid "Sets weight to %{weight}."
msgstr ""
+msgid "Setting this to 0 means using the system default timeout value."
+msgstr ""
+
msgid "Settings"
msgstr ""
@@ -22739,6 +23555,15 @@ msgstr ""
msgid "Severity"
msgstr ""
+msgid "SeverityWidget|Severity"
+msgstr ""
+
+msgid "SeverityWidget|Severity: %{severity}"
+msgstr ""
+
+msgid "SeverityWidget|There was an error while updating severity."
+msgstr ""
+
msgid "Shards (%{shards})"
msgstr ""
@@ -22784,6 +23609,9 @@ msgstr ""
msgid "Show all requirements."
msgstr ""
+msgid "Show all test cases."
+msgstr ""
+
msgid "Show archived projects"
msgstr ""
@@ -22796,6 +23624,9 @@ msgstr ""
msgid "Show comments"
msgstr ""
+msgid "Show comments on this file"
+msgstr ""
+
msgid "Show comments only"
msgstr ""
@@ -22841,6 +23672,12 @@ msgstr ""
msgid "Show parent subgroups"
msgstr ""
+msgid "Show the Closed list"
+msgstr ""
+
+msgid "Show the Open list"
+msgstr ""
+
msgid "Show whitespace changes"
msgstr ""
@@ -22884,9 +23721,6 @@ msgstr ""
msgid "Sidebar|Assign health status"
msgstr ""
-msgid "Sidebar|Change weight"
-msgstr ""
-
msgid "Sidebar|Health status"
msgstr ""
@@ -23070,6 +23904,9 @@ msgstr ""
msgid "Snippets|Add another file %{num}/%{total}"
msgstr ""
+msgid "Snippets|Authored %{time_ago} by %{author}"
+msgstr ""
+
msgid "Snippets|Delete file"
msgstr ""
@@ -23097,6 +23934,9 @@ msgstr ""
msgid "Solution"
msgstr ""
+msgid "Some changes are not shown"
+msgstr ""
+
msgid "Some child epics may be hidden due to applied filters"
msgstr ""
@@ -23463,6 +24303,12 @@ msgstr ""
msgid "Source (branch or tag)"
msgstr ""
+msgid "Source Branch"
+msgstr ""
+
+msgid "Source branch: %{source_branch_open}%{source_branch}%{source_branch_close}"
+msgstr ""
+
msgid "Source code"
msgstr ""
@@ -23628,9 +24474,6 @@ msgstr ""
msgid "Start and due date"
msgstr ""
-msgid "Start by choosing a group to see how your team is spending time. You can then drill down to the project level."
-msgstr ""
-
msgid "Start by choosing a group to start exploring the merge requests in that group. You can then proceed to filter by projects, labels, milestones and authors."
msgstr ""
@@ -23712,18 +24555,27 @@ msgstr ""
msgid "StaticSiteEditor|3. Assign a person to review and accept the merge request."
msgstr ""
+msgid "StaticSiteEditor|A link to view the merge request will appear once ready."
+msgstr ""
+
msgid "StaticSiteEditor|An error occurred while submitting your changes."
msgstr ""
msgid "StaticSiteEditor|Branch could not be created."
msgstr ""
+msgid "StaticSiteEditor|Copy update"
+msgstr ""
+
msgid "StaticSiteEditor|Could not commit the content changes."
msgstr ""
msgid "StaticSiteEditor|Could not create merge request."
msgstr ""
+msgid "StaticSiteEditor|Creating your merge request"
+msgstr ""
+
msgid "StaticSiteEditor|Incompatible file content"
msgstr ""
@@ -23745,6 +24597,9 @@ msgstr ""
msgid "StaticSiteEditor|View documentation"
msgstr ""
+msgid "StaticSiteEditor|You can set an assignee to get your changes reviewed and deployed once your merge request is created."
+msgstr ""
+
msgid "StaticSiteEditor|Your merge request has been created"
msgstr ""
@@ -23874,15 +24729,15 @@ msgstr ""
msgid "Submit %{humanized_resource_name}"
msgstr ""
-msgid "Submit Changes"
-msgstr ""
-
msgid "Submit a review"
msgstr ""
msgid "Submit as spam"
msgstr ""
+msgid "Submit changes"
+msgstr ""
+
msgid "Submit feedback"
msgstr ""
@@ -24036,6 +24891,9 @@ msgstr ""
msgid "Successfully deleted U2F device."
msgstr ""
+msgid "Successfully deleted WebAuthn device."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -24354,9 +25212,6 @@ msgstr ""
msgid "Template to append to all Service Desk issues"
msgstr ""
-msgid "Template was successfully saved."
-msgstr ""
-
msgid "Templates"
msgstr ""
@@ -24435,10 +25290,28 @@ msgid_plural "Test coverage: %d hits"
msgstr[0] ""
msgstr[1] ""
-msgid "Test failed."
+msgid "Test settings"
msgstr ""
-msgid "Test settings and save changes"
+msgid "TestCases|New Test Case"
+msgstr ""
+
+msgid "TestCases|New test case"
+msgstr ""
+
+msgid "TestCases|Search test cases"
+msgstr ""
+
+msgid "TestCases|Something went wrong while creating a test case."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching count of test cases."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching test cases list."
+msgstr ""
+
+msgid "TestCases|Submit test case"
msgstr ""
msgid "TestHooks|Ensure one of your projects has merge requests."
@@ -24504,6 +25377,9 @@ msgstr ""
msgid "Thank you for signing up for your free trial! You will get additional instructions in your inbox shortly."
msgstr ""
+msgid "Thank you for your business."
+msgstr ""
+
msgid "Thank you for your feedback!"
msgstr ""
@@ -24563,9 +25439,6 @@ msgstr ""
msgid "The URL to use for connecting to Elasticsearch. Use a comma-separated list to support clustering (e.g., \"http://localhost:9200, http://localhost:9201\")."
msgstr ""
-msgid "The Web IDE offers advanced syntax highlighting capabilities and more."
-msgstr ""
-
msgid "The X509 Certificate to use when mutual TLS is required to communicate with the external authorization service. If left blank, the server certificate is still validated when accessing over HTTPS."
msgstr ""
@@ -24676,6 +25549,9 @@ msgstr ""
msgid "The form contains the following error:"
msgstr ""
+msgid "The form contains the following warning:"
+msgstr ""
+
msgid "The global settings require you to enable Two-Factor Authentication for your account."
msgstr ""
@@ -24790,9 +25666,6 @@ msgstr ""
msgid "The private key to use when a client certificate is provided. This value is encrypted at rest."
msgstr ""
-msgid "The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The project can be accessed by any logged in user."
msgstr ""
@@ -24829,7 +25702,7 @@ msgstr ""
msgid "The remote repository is being updated..."
msgstr ""
-msgid "The repository can be commited to, and issues, comments and other entities can be created."
+msgid "The repository can be committed to, and issues, comments and other entities can be created."
msgstr ""
msgid "The repository for this project does not exist."
@@ -24883,9 +25756,6 @@ msgstr ""
msgid "The time taken by each data entry gathered by that stage."
msgstr ""
-msgid "The total stage shows the time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The update action will time out after %{number_of_minutes} minutes. For big repositories, use a clone/push combination."
msgstr ""
@@ -24949,6 +25819,9 @@ msgstr ""
msgid "There are no archived requirements"
msgstr ""
+msgid "There are no archived test cases"
+msgstr ""
+
msgid "There are no changes"
msgstr ""
@@ -24988,6 +25861,9 @@ msgstr ""
msgid "There are no open requirements"
msgstr ""
+msgid "There are no open test cases"
+msgstr ""
+
msgid "There are no packages yet"
msgstr ""
@@ -25000,6 +25876,9 @@ msgstr ""
msgid "There is a limit of %{ci_project_subscriptions_limit} subscriptions from or to a project."
msgstr ""
+msgid "There is already a To-Do for this design."
+msgstr ""
+
msgid "There is already a repository with that name on disk"
msgstr ""
@@ -25018,6 +25897,9 @@ msgstr ""
msgid "There was a problem communicating with your device."
msgstr ""
+msgid "There was a problem fetching branches."
+msgstr ""
+
msgid "There was a problem fetching groups."
msgstr ""
@@ -25246,9 +26128,15 @@ msgstr ""
msgid "This action can lead to data loss. To prevent accidental actions we ask you to confirm your intention."
msgstr ""
+msgid "This action cannot be undone, and will permanently delete the %{key} SSH key"
+msgstr ""
+
msgid "This action cannot be undone. You will lose the project's repository and all content: issues, merge requests, etc."
msgstr ""
+msgid "This action has been performed too many times. Try again later."
+msgstr ""
+
msgid "This action will %{strongOpen}permanently delete%{strongClose} %{codeOpen}%{project}%{codeClose} %{strongOpen}immediately%{strongClose}, including its repositories and all content: issues, merge requests, etc."
msgstr ""
@@ -25276,9 +26164,6 @@ msgstr ""
msgid "This board's scope is reduced"
msgstr ""
-msgid "This branch has changed since you started editing. Would you like to create a new branch?"
-msgstr ""
-
msgid "This chart could not be displayed"
msgstr ""
@@ -25405,15 +26290,9 @@ msgstr ""
msgid "This is a security log of important events involving your account."
msgstr ""
-msgid "This is the author's first Merge Request to this project."
-msgstr ""
-
msgid "This is the highest peak of users on your installation since the license started."
msgstr ""
-msgid "This is the maximum number of users that have existed at the same time since the license started. This is the minimum number of seats you will need to buy when you renew your license."
-msgstr ""
-
msgid "This is the number of currently active users on your installation, and this is the minimum number you need to purchase when you renew your license."
msgstr ""
@@ -25645,6 +26524,15 @@ msgstr ""
msgid "This user has no identities"
msgstr ""
+msgid "This user has previously committed to the %{name} project."
+msgstr ""
+
+msgid "This user has the %{access} role in the %{name} project."
+msgstr ""
+
+msgid "This user is the author of this %{noteable}."
+msgstr ""
+
msgid "This user will be the author of all events in the activity feed that are the result of an update, like new branches being created or new commits being pushed to existing branches."
msgstr ""
@@ -25675,6 +26563,9 @@ msgstr ""
msgid "Threat Monitoring"
msgstr ""
+msgid "ThreatMonitoring|All Environments"
+msgstr ""
+
msgid "ThreatMonitoring|Anomalous Requests"
msgstr ""
@@ -25702,9 +26593,6 @@ msgstr ""
msgid "ThreatMonitoring|Operations Per Second"
msgstr ""
-msgid "ThreatMonitoring|Overview"
-msgstr ""
-
msgid "ThreatMonitoring|Packet Activity"
msgstr ""
@@ -25723,6 +26611,9 @@ msgstr ""
msgid "ThreatMonitoring|Something went wrong, unable to fetch statistics"
msgstr ""
+msgid "ThreatMonitoring|Statistics"
+msgstr ""
+
msgid "ThreatMonitoring|The firewall is not installed or has been disabled. To view this data, ensure the web application firewall is installed and enabled for your cluster."
msgstr ""
@@ -26114,6 +27005,9 @@ msgstr ""
msgid "To update Snippets with multiple files, you must use the `files` parameter"
msgstr ""
+msgid "To use Gitpod you must first enable the feature in the integrations section of your %{user_prefs}."
+msgstr ""
+
msgid "To view all %{scannedResourcesCount} scanned URLs, please download the CSV file"
msgstr ""
@@ -26147,9 +27041,6 @@ msgstr ""
msgid "Toggle Sidebar"
msgstr ""
-msgid "Toggle all threads"
-msgstr ""
-
msgid "Toggle backtrace"
msgstr ""
@@ -26174,9 +27065,6 @@ msgstr ""
msgid "Toggle navigation"
msgstr ""
-msgid "Toggle project"
-msgstr ""
-
msgid "Toggle sidebar"
msgstr ""
@@ -26216,6 +27104,9 @@ msgstr ""
msgid "Too many projects enabled. You will need to manage them via the console or the API."
msgstr ""
+msgid "Too much data"
+msgstr ""
+
msgid "Topics (optional)"
msgstr ""
@@ -26234,6 +27125,9 @@ msgstr ""
msgid "Total cores (CPUs)"
msgstr ""
+msgid "Total days to completion"
+msgstr ""
+
msgid "Total issues"
msgstr ""
@@ -26330,6 +27224,9 @@ msgstr ""
msgid "Trending"
msgstr ""
+msgid "Trials|Create a new group to start your GitLab Gold trial."
+msgstr ""
+
msgid "Trials|Go back to GitLab"
msgstr ""
@@ -26339,6 +27236,15 @@ msgstr ""
msgid "Trials|You can always resume this process by selecting your avatar and choosing 'Start a Gold trial'"
msgstr ""
+msgid "Trials|You can apply your trial to a new group or an existing group."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group or your personal account."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group, an existing group, or your personal account."
+msgstr ""
+
msgid "Trials|You won't get a free trial right now but you can always resume this process by clicking on your avatar and choosing 'Start a free trial'"
msgstr ""
@@ -26408,6 +27314,9 @@ msgstr ""
msgid "Try using a different search term to find the file you are looking for."
msgstr ""
+msgid "Trying to communicate with your device. Plug it in (if needed) and press the button on the device now."
+msgstr ""
+
msgid "Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now."
msgstr ""
@@ -26495,6 +27404,12 @@ msgstr ""
msgid "URL or request ID"
msgstr ""
+msgid "USER %{user} WILL BE REMOVED! Are you sure?"
+msgstr ""
+
+msgid "USER WILL BE BLOCKED! Are you sure?"
+msgstr ""
+
msgid "UTC"
msgstr ""
@@ -26552,9 +27467,6 @@ msgstr ""
msgid "Unable to load the merge request widget. Try reloading the page."
msgstr ""
-msgid "Unable to resolve"
-msgstr ""
-
msgid "Unable to save iteration. Please try again"
msgstr ""
@@ -26603,6 +27515,9 @@ msgstr ""
msgid "Undo ignore"
msgstr ""
+msgid "Unexpected error"
+msgstr ""
+
msgid "Unfortunately, your email message to GitLab could not be processed."
msgstr ""
@@ -26636,6 +27551,9 @@ msgstr ""
msgid "Unknown response text"
msgstr ""
+msgid "Unless otherwise agreed to in writing with GitLab, by clicking \"Upload License\" you agree that your use of GitLab Software is subject to the %{eula_link_start}Terms of Service%{eula_link_end}."
+msgstr ""
+
msgid "Unlimited"
msgstr ""
@@ -27002,9 +27920,6 @@ msgstr ""
msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
msgstr ""
-msgid "Use a hardware device to add the second factor of authentication."
-msgstr ""
-
msgid "Use an one time password authenticator on your mobile device or computer to enable two-factor authentication (2FA)."
msgstr ""
@@ -27278,13 +28193,13 @@ msgstr ""
msgid "Users"
msgstr ""
-msgid "Users in License:"
+msgid "Users in License"
msgstr ""
-msgid "Users or groups set as approvers in the project's or merge request's settings."
+msgid "Users in License:"
msgstr ""
-msgid "Users outside of license"
+msgid "Users or groups set as approvers in the project's or merge request's settings."
msgstr ""
msgid "Users over License:"
@@ -27302,9 +28217,6 @@ msgstr ""
msgid "Users with a Guest role or those who don't belong to a Project or Group will not use a seat from your license."
msgstr ""
-msgid "Users with a Guest role or those who don't belong to any projects or groups don't count towards seats in use."
-msgstr ""
-
msgid "UsersSelect|%{name} + %{length} more"
msgstr ""
@@ -27344,9 +28256,6 @@ msgstr ""
msgid "Validations failed."
msgstr ""
-msgid "Validity"
-msgstr ""
-
msgid "Value"
msgstr ""
@@ -27365,6 +28274,9 @@ msgstr ""
msgid "Value Stream Name"
msgstr ""
+msgid "ValueStreamAnalyticsStage|We don't have enough data to show this stage."
+msgstr ""
+
msgid "ValueStreamAnalytics|%{days}d"
msgstr ""
@@ -27621,6 +28533,9 @@ msgstr ""
msgid "VisualReviewApp|Steps 1 and 2 (and sometimes 3) are performed once by the developer before requesting feedback. Steps 3 (if necessary), 4 is performed by the reviewer each time they perform a review."
msgstr ""
+msgid "Visualization"
+msgstr ""
+
msgid "Vulnerabilities"
msgstr ""
@@ -27648,34 +28563,31 @@ msgstr ""
msgid "VulnerabilityChart|Severity"
msgstr ""
-msgid "VulnerabilityManagement|A true-positive and will fix"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Change status"
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|Confirm"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Confirmed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
-msgstr ""
-
-msgid "VulnerabilityManagement|Detected %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|A true-positive and will fix"
msgstr ""
-msgid "VulnerabilityManagement|Dismiss"
+msgid "VulnerabilityManagement|Change status"
msgstr ""
-msgid "VulnerabilityManagement|Dismissed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
msgstr ""
-msgid "VulnerabilityManagement|Resolved"
+msgid "VulnerabilityManagement|Detected"
msgstr ""
-msgid "VulnerabilityManagement|Resolved %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Needs triage"
msgstr ""
msgid "VulnerabilityManagement|Something went wrong while trying to delete the comment. Please try again later."
@@ -27726,6 +28638,9 @@ msgstr ""
msgid "Vulnerability|%{scannerName} (version %{scannerVersion})"
msgstr ""
+msgid "Vulnerability|Activity"
+msgstr ""
+
msgid "Vulnerability|Class"
msgstr ""
@@ -27738,6 +28653,9 @@ msgstr ""
msgid "Vulnerability|Description"
msgstr ""
+msgid "Vulnerability|Detected"
+msgstr ""
+
msgid "Vulnerability|Evidence"
msgstr ""
@@ -27801,6 +28719,9 @@ msgstr ""
msgid "Warning: Displaying this diagram might cause performance issues on this page."
msgstr ""
+msgid "We are currently unable to fetch data for the pipeline header."
+msgstr ""
+
msgid "We are currently unable to fetch data for this graph."
msgstr ""
@@ -27840,6 +28761,12 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
+msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
+msgstr ""
+
+msgid "We would like to inform you that your subscription GitLab Enterprise Edition %{plan_name} is nearing its user limit. You have %{active_user_count} active users, which is almost at the user limit of %{maximum_user_count}."
+msgstr ""
+
msgid "We've found no vulnerabilities"
msgstr ""
@@ -27855,6 +28782,12 @@ msgstr ""
msgid "Web terminal"
msgstr ""
+msgid "WebAuthn Devices (%{length})"
+msgstr ""
+
+msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
+msgstr ""
+
msgid "WebIDE|Merge request"
msgstr ""
@@ -27993,15 +28926,9 @@ msgstr ""
msgid "Welcome to the guided GitLab tour"
msgstr ""
-msgid "Welcome to your Issue Board!"
-msgstr ""
-
msgid "Welcome to your issue board!"
msgstr ""
-msgid "We’ve been making changes to %{featureName} and we’d love your feedback %{linkStart}in this issue%{linkEnd} to help us improve the experience."
-msgstr ""
-
msgid "What are you searching for?"
msgstr ""
@@ -28020,6 +28947,9 @@ msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
msgstr ""
+msgid "When enabled, any user visiting %{host} and creating an account will have to be explicitly approved by the admin before they can login. This setting is effective only if sign-ups are enabled."
+msgstr ""
+
msgid "When enabled, any user visiting %{host} will be able to create an account."
msgstr ""
@@ -28244,6 +29174,9 @@ msgstr ""
msgid "With requirements, you can set criteria to check your products against."
msgstr ""
+msgid "With test cases, you can define conditions for your project to meet in determining quality"
+msgstr ""
+
msgid "Withdraw Access Request"
msgstr ""
@@ -28259,6 +29192,9 @@ msgstr ""
msgid "Workflow Help"
msgstr ""
+msgid "Would you like to create a new branch?"
+msgstr ""
+
msgid "Write"
msgstr ""
@@ -28280,6 +29216,9 @@ msgstr ""
msgid "Wrong extern UID provided. Make sure Auth0 is configured correctly."
msgstr ""
+msgid "YYYY-MM-DD"
+msgstr ""
+
msgid "Yes"
msgstr ""
@@ -28337,7 +29276,7 @@ msgstr ""
msgid "You are going to remove the fork relationship from %{project_full_name}. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "You are going to transfer %{project_full_name} to another owner. Are you ABSOLUTELY sure?"
+msgid "You are going to transfer %{project_full_name} to another namespace. Are you ABSOLUTELY sure?"
msgstr ""
msgid "You are going to turn off the confidentiality. This means %{strongStart}everyone%{strongEnd} will be able to see and leave a comment on this %{issuableType}."
@@ -28397,9 +29336,6 @@ msgstr ""
msgid "You can always edit this later"
msgstr ""
-msgid "You can apply your Trial to your Personal account or create a New Group."
-msgstr ""
-
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings"
msgstr ""
@@ -28421,12 +29357,18 @@ msgstr ""
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
+msgid "You can find more information about GitLab subscriptions in %{subscriptions_doc_link}."
+msgstr ""
+
msgid "You can generate an access token scoped to this project for each application to use the GitLab API."
msgstr ""
msgid "You can get started by cloning the repository or start adding files to it with one of the following options."
msgstr ""
+msgid "You can group test cases using labels. To learn about the future direction of this feature, visit %{linkStart}Quality Management direction page%{linkEnd}."
+msgstr ""
+
msgid "You can invite a new member to %{project_name} or invite another group."
msgstr ""
@@ -28442,6 +29384,9 @@ msgstr ""
msgid "You can notify the app / group or a project by sending them an email notification"
msgstr ""
+msgid "You can now close this window."
+msgstr ""
+
msgid "You can now export your security dashboard to a CSV report."
msgstr ""
@@ -28490,9 +29435,6 @@ msgstr ""
msgid "You can test your .gitlab-ci.yml in %{linkStart}CI Lint%{linkEnd}."
msgstr ""
-msgid "You can try again using %{begin_link}basic search%{end_link}"
-msgstr ""
-
msgid "You cannot access the raw file. Please wait a minute."
msgstr ""
@@ -28544,6 +29486,9 @@ msgstr ""
msgid "You don't have any U2F devices registered yet."
msgstr ""
+msgid "You don't have any WebAuthn devices registered yet."
+msgstr ""
+
msgid "You don't have any active chat names."
msgstr ""
@@ -28631,6 +29576,9 @@ msgstr ""
msgid "You must accept our Terms of Service and privacy policy in order to register an account"
msgstr ""
+msgid "You must be logged in to search across all of GitLab"
+msgstr ""
+
msgid "You must disassociate %{domain} from all clusters it is attached to before deletion."
msgstr ""
@@ -28670,7 +29618,7 @@ msgstr ""
msgid "You need to be logged in."
msgstr ""
-msgid "You need to register a two-factor authentication app before you can set up a U2F device."
+msgid "You need to register a two-factor authentication app before you can set up a device."
msgstr ""
msgid "You need to set terms to be enforced"
@@ -28688,6 +29636,9 @@ msgstr ""
msgid "You reached %{usage_in_percent} of %{namespace_name}'s storage capacity (%{used_storage} of %{storage_limit})"
msgstr ""
+msgid "You successfully declined the invitation"
+msgstr ""
+
msgid "You tried to fork %{link_to_the_project} but it failed for the following reason:"
msgstr ""
@@ -28853,10 +29804,13 @@ msgstr ""
msgid "Your U2F device did not send a valid JSON response."
msgstr ""
-msgid "Your U2F device needs to be set up. Plug it in (if not already) and click the button on the left."
+msgid "Your U2F device was registered!"
msgstr ""
-msgid "Your U2F device was registered!"
+msgid "Your WebAuthn device did not send a valid JSON response."
+msgstr ""
+
+msgid "Your WebAuthn device was registered!"
msgstr ""
msgid "Your access request to the %{source_type} has been withdrawn."
@@ -28880,6 +29834,9 @@ msgstr ""
msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
msgstr ""
+msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
+msgstr ""
+
msgid "Your changes can be committed to %{branch_name} because a merge request is open."
msgstr ""
@@ -28916,6 +29873,12 @@ msgstr ""
msgid "Your deployment services will be broken, you will need to manually fix the services after renaming."
msgstr ""
+msgid "Your device is not compatible with GitLab. Please try another device"
+msgstr ""
+
+msgid "Your device needs to be set up. Plug it in (if needed) and click the button on the left."
+msgstr ""
+
msgid "Your device was successfully set up! Give it a name and register it with the GitLab server."
msgstr ""
@@ -29029,9 +29992,6 @@ msgstr[1] ""
msgid "access:"
msgstr ""
-msgid "activated"
-msgstr ""
-
msgid "added %{created_at_timeago}"
msgstr ""
@@ -29104,9 +30064,21 @@ msgstr ""
msgid "by %{user}"
msgstr ""
+msgid "cannot be a date in the past"
+msgstr ""
+
msgid "cannot be changed if a personal project has container registry tags."
msgstr ""
+msgid "cannot be changed if shared runners are enabled"
+msgstr ""
+
+msgid "cannot be enabled because parent group does not allow it"
+msgstr ""
+
+msgid "cannot be enabled because parent group has shared Runners disabled"
+msgstr ""
+
msgid "cannot be enabled unless all domains have TLS certificates"
msgstr ""
@@ -29152,7 +30124,7 @@ msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about SAST %{linkEndTag}"
msgstr ""
-msgid "ciReport|%{linkStartTag}Learn more about Secret Scanning %{linkEndTag}"
+msgid "ciReport|%{linkStartTag}Learn more about Secret Detection %{linkEndTag}"
msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about codequality reports %{linkEndTag}"
@@ -29467,9 +30439,6 @@ msgstr ""
msgid "error"
msgstr ""
-msgid "error code:"
-msgstr ""
-
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr ""
@@ -29491,6 +30460,9 @@ msgstr ""
msgid "failed to dismiss associated finding(id=%{finding_id}): %{message}"
msgstr ""
+msgid "failed to revert associated finding(id=%{finding_id}) to detected"
+msgstr ""
+
msgid "file"
msgid_plural "files"
msgstr[0] ""
@@ -30033,6 +31005,9 @@ msgstr ""
msgid "must be a root namespace"
msgstr ""
+msgid "must be a valid IPv4 or IPv6 address"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -30069,6 +31044,9 @@ msgstr ""
msgid "no expiration"
msgstr ""
+msgid "no name set"
+msgstr ""
+
msgid "no one can merge"
msgstr ""
@@ -30247,9 +31225,6 @@ msgstr ""
msgid "security Reports|There was an error creating the merge request"
msgstr ""
-msgid "settings saved, but not activated"
-msgstr ""
-
msgid "severity|Critical"
msgstr ""
@@ -30376,9 +31351,6 @@ msgstr ""
msgid "toggle collapse"
msgstr ""
-msgid "toggle dropdown"
-msgstr ""
-
msgid "triggered"
msgstr ""
@@ -30406,6 +31378,9 @@ msgstr ""
msgid "user avatar"
msgstr ""
+msgid "user preferences"
+msgstr ""
+
msgid "username"
msgstr ""
diff --git a/locale/ba_RU/gitlab.po b/locale/ba_RU/gitlab.po
index af8136d5b83..b2de628096f 100644
--- a/locale/ba_RU/gitlab.po
+++ b/locale/ba_RU/gitlab.po
@@ -14,7 +14,10 @@ msgstr ""
"X-Crowdin-Language: ba\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 6\n"
-"PO-Revision-Date: 2020-09-04 23:05\n"
+"PO-Revision-Date: 2020-10-02 18:44\n"
+
+msgid " %{project_name}#%{issue_iid} &middot; opened %{issue_created} by %{author}"
+msgstr ""
msgid " %{start} to %{end}"
msgstr ""
@@ -72,6 +75,14 @@ msgstr ""
msgid "\"el\" parameter is required for createInstance()"
msgstr ""
+msgid "%d Approval"
+msgid_plural "%d Approvals"
+msgstr[0] ""
+
+msgid "%d Package"
+msgid_plural "%d Packages"
+msgstr[0] ""
+
msgid "%d Scanned URL"
msgid_plural "%d Scanned URLs"
msgstr[0] ""
@@ -123,6 +134,10 @@ msgstr[0] ""
msgid "%d commits"
msgstr ""
+msgid "%d completed issue"
+msgid_plural "%d completed issues"
+msgstr[0] ""
+
msgid "%d contribution"
msgid_plural "%d contributions"
msgstr[0] ""
@@ -131,6 +146,10 @@ msgid "%d day"
msgid_plural "%d days"
msgstr[0] ""
+msgid "%d day until tags are automatically removed"
+msgid_plural "%d days until tags are automatically removed"
+msgstr[0] ""
+
msgid "%d error"
msgid_plural "%d errors"
msgstr[0] ""
@@ -203,6 +222,14 @@ msgid "%d more comment"
msgid_plural "%d more comments"
msgstr[0] ""
+msgid "%d open issue"
+msgid_plural "%d open issues"
+msgstr[0] ""
+
+msgid "%d pending comment"
+msgid_plural "%d pending comments"
+msgstr[0] ""
+
msgid "%d personal project will be removed and cannot be restored."
msgid_plural "%d personal projects will be removed and cannot be restored."
msgstr[0] ""
@@ -215,6 +242,10 @@ msgid "%d project"
msgid_plural "%d projects"
msgstr[0] ""
+msgid "%d project selected"
+msgid_plural "%d projects selected"
+msgstr[0] ""
+
msgid "%d request with warnings"
msgid_plural "%d requests with warnings"
msgstr[0] ""
@@ -231,6 +262,10 @@ msgid "%d tag"
msgid_plural "%d tags"
msgstr[0] ""
+msgid "%d tag per image name"
+msgid_plural "%d tags per image name"
+msgstr[0] ""
+
msgid "%d unassigned issue"
msgid_plural "%d unassigned issues"
msgstr[0] ""
@@ -247,6 +282,10 @@ msgid "%d vulnerability dismissed"
msgid_plural "%d vulnerabilities dismissed"
msgstr[0] ""
+msgid "%d warning found:"
+msgid_plural "%d warnings found:"
+msgstr[0] ""
+
msgid "%s additional commit has been omitted to prevent performance issues."
msgid_plural "%s additional commits have been omitted to prevent performance issues."
msgstr[0] ""
@@ -284,6 +323,9 @@ msgstr ""
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr ""
+msgid "%{completedCount} completed weight"
+msgstr ""
+
msgid "%{completedWeight} of %{totalWeight} weight completed"
msgstr ""
@@ -329,13 +371,12 @@ msgid "%{count} participant"
msgid_plural "%{count} participants"
msgstr[0] ""
-msgid "%{count} pending comment"
-msgid_plural "%{count} pending comments"
-msgstr[0] ""
-
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
+msgid "%{count} total weight"
+msgstr ""
+
msgid "%{dashboard_path} could not be found."
msgstr ""
@@ -390,6 +431,9 @@ msgstr ""
msgid "%{group_name} uses group managed accounts. You need to create a new GitLab account which will be managed by %{group_name}."
msgstr ""
+msgid "%{group_name}&%{epic_iid} &middot; opened %{epic_created} by %{author}"
+msgstr ""
+
msgid "%{host} sign-in from new location"
msgstr ""
@@ -402,7 +446,7 @@ msgstr ""
msgid "%{issuableType} will be removed! Are you sure?"
msgstr ""
-msgid "%{issuesSize} issues with a limit of %{maxIssueCount}"
+msgid "%{issuesCount} issues with a limit of %{maxIssueCount}"
msgstr ""
msgid "%{issuesSize} with a limit of %{maxIssueCount}"
@@ -435,7 +479,7 @@ msgstr ""
msgid "%{labelStart}Namespace:%{labelEnd} %{namespace}"
msgstr ""
-msgid "%{labelStart}Report Type:%{labelEnd} %{reportType}"
+msgid "%{labelStart}Scan Type:%{labelEnd} %{reportType}"
msgstr ""
msgid "%{labelStart}Scanner:%{labelEnd} %{scanner}"
@@ -625,9 +669,6 @@ msgid "%{securityScanner} result is not available because a pipeline has not bee
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] ""
-msgid "%{service_title} %{message}."
-msgstr ""
-
msgid "%{size} GiB"
msgstr ""
@@ -711,6 +752,12 @@ msgstr ""
msgid "%{timebox_name} should belong either to a project or a group."
msgstr ""
+msgid "%{timebox_type} does not support burnup charts"
+msgstr ""
+
+msgid "%{timebox_type} must have a start and due date"
+msgstr ""
+
msgid "%{title} %{operator} %{threshold}"
msgstr ""
@@ -735,7 +782,7 @@ msgstr ""
msgid "%{total} open issue weight"
msgstr ""
-msgid "%{total} open issues"
+msgid "%{total} warnings found: showing first %{warningsDisplayed}"
msgstr ""
msgid "%{usage_ping_link_start}Learn more%{usage_ping_link_end} about what information is shared with GitLab Inc."
@@ -768,9 +815,6 @@ msgstr ""
msgid "&lt; 1 hour"
msgstr ""
-msgid "&lt;no name set&gt;"
-msgstr ""
-
msgid "&lt;no scopes selected&gt;"
msgstr ""
@@ -801,6 +845,9 @@ msgstr ""
msgid "'%{name}' Value Stream created"
msgstr ""
+msgid "'%{name}' Value Stream deleted"
+msgstr ""
+
msgid "'%{name}' stage already exists"
msgstr ""
@@ -859,6 +906,9 @@ msgstr ""
msgid "+ %{numberOfHiddenAssignees} more"
msgstr ""
+msgid "+ %{numberOfHiddenReviewers} more"
+msgstr ""
+
msgid "+%d more"
msgid_plural "+%d more"
msgstr[0] ""
@@ -913,6 +963,10 @@ msgid "1 Day"
msgid_plural "%d Days"
msgstr[0] ""
+msgid "1 Issue"
+msgid_plural "%d Issues"
+msgstr[0] ""
+
msgid "1 closed issue"
msgid_plural "%{issues} closed issues"
msgstr[0] ""
@@ -925,6 +979,10 @@ msgid "1 day"
msgid_plural "%d days"
msgstr[0] ""
+msgid "1 deploy key"
+msgid_plural "%d deploy keys"
+msgstr[0] ""
+
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1018,6 +1076,9 @@ msgstr ""
msgid ":%{startLine} to %{endLine}"
msgstr ""
+msgid "A %{incident_docs_start}modified issue%{incident_docs_end} to guide the resolution of incidents."
+msgstr ""
+
msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr ""
@@ -1030,6 +1091,9 @@ msgstr ""
msgid "A GitBook site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
+msgid "A Gitpod configured Webapplication in Spring and Java"
+msgstr ""
+
msgid "A Hexo site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
@@ -1201,9 +1265,15 @@ msgstr ""
msgid "Access expiration date"
msgstr ""
+msgid "Access expires"
+msgstr ""
+
msgid "Access forbidden. Check your access level."
msgstr ""
+msgid "Access granted"
+msgstr ""
+
msgid "Access requests"
msgstr ""
@@ -1213,6 +1283,9 @@ msgstr ""
msgid "Access to Pages websites are controlled based on the user's membership to a given project. By checking this box, users will be required to be logged in to have access to all Pages websites in your instance."
msgstr ""
+msgid "AccessDropdown|Deploy Keys"
+msgstr ""
+
msgid "AccessDropdown|Groups"
msgstr ""
@@ -1330,12 +1403,6 @@ msgstr ""
msgid "Active Sessions"
msgstr ""
-msgid "Active Users:"
-msgstr ""
-
-msgid "Active users"
-msgstr ""
-
msgid "Activity"
msgstr ""
@@ -1502,9 +1569,6 @@ msgstr ""
msgid "Add label(s)"
msgstr ""
-msgid "Add license"
-msgstr ""
-
msgid "Add list"
msgstr ""
@@ -1679,21 +1743,51 @@ msgstr ""
msgid "AdminArea|Bots"
msgstr ""
+msgid "AdminArea|Components"
+msgstr ""
+
msgid "AdminArea|Developer"
msgstr ""
+msgid "AdminArea|Features"
+msgstr ""
+
+msgid "AdminArea|Groups: %{number_of_groups}"
+msgstr ""
+
msgid "AdminArea|Guest"
msgstr ""
msgid "AdminArea|Included Free in license"
msgstr ""
+msgid "AdminArea|Latest groups"
+msgstr ""
+
+msgid "AdminArea|Latest projects"
+msgstr ""
+
+msgid "AdminArea|Latest users"
+msgstr ""
+
msgid "AdminArea|Maintainer"
msgstr ""
+msgid "AdminArea|New group"
+msgstr ""
+
+msgid "AdminArea|New project"
+msgstr ""
+
+msgid "AdminArea|New user"
+msgstr ""
+
msgid "AdminArea|Owner"
msgstr ""
+msgid "AdminArea|Projects: %{number_of_projects}"
+msgstr ""
+
msgid "AdminArea|Reporter"
msgstr ""
@@ -1721,6 +1815,9 @@ msgstr ""
msgid "AdminArea|Users without a Group and Project"
msgstr ""
+msgid "AdminArea|Users: %{number_of_users}"
+msgstr ""
+
msgid "AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running."
msgstr ""
@@ -1739,9 +1836,6 @@ msgstr ""
msgid "AdminProjects|Delete Project %{projectName}?"
msgstr ""
-msgid "AdminProjects|Delete project"
-msgstr ""
-
msgid "AdminSettings|Apply integration settings to all Projects"
msgstr ""
@@ -1979,21 +2073,30 @@ msgstr ""
msgid "AdminUsers|Without projects"
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 ""
msgid "AdminUsers|You cannot remove your own admin rights."
msgstr ""
+msgid "AdminUsers|You must transfer ownership or delete the groups owned by this user before you can delete their account"
+msgstr ""
+
msgid "Administration"
msgstr ""
msgid "Advanced"
msgstr ""
+msgid "Advanced Search"
+msgstr ""
+
+msgid "Advanced Search with Elasticsearch"
+msgstr ""
+
msgid "Advanced Settings"
msgstr ""
@@ -2070,6 +2173,9 @@ msgstr ""
msgid "AlertManagement|Edit"
msgstr ""
+msgid "AlertManagement|Environment"
+msgstr ""
+
msgid "AlertManagement|Events"
msgstr ""
@@ -2082,6 +2188,9 @@ msgstr ""
msgid "AlertManagement|Issue"
msgstr ""
+msgid "AlertManagement|Key"
+msgstr ""
+
msgid "AlertManagement|Low"
msgstr ""
@@ -2175,6 +2284,9 @@ msgstr ""
msgid "AlertManagement|Unknown"
msgstr ""
+msgid "AlertManagement|Value"
+msgstr ""
+
msgid "AlertManagement|View alerts in Opsgenie"
msgstr ""
@@ -2334,6 +2446,9 @@ msgstr ""
msgid "All projects"
msgstr ""
+msgid "All projects selected"
+msgstr ""
+
msgid "All security scans are enabled because %{linkStart}Auto DevOps%{linkEnd} is enabled on this project"
msgstr ""
@@ -2421,6 +2536,9 @@ msgstr ""
msgid "Almost there"
msgstr ""
+msgid "Already blocked"
+msgstr ""
+
msgid "Also called \"Issuer\" or \"Relying party trust identifier\""
msgstr ""
@@ -2475,6 +2593,9 @@ msgstr ""
msgid "An error has occurred"
msgstr ""
+msgid "An error occured while making the changes: %{error}"
+msgstr ""
+
msgid "An error occurred adding a draft to the thread."
msgstr ""
@@ -2502,12 +2623,6 @@ msgstr ""
msgid "An error occurred when toggling the notification subscription"
msgstr ""
-msgid "An error occurred when trying to resolve a comment. Please try again."
-msgstr ""
-
-msgid "An error occurred when trying to resolve a discussion. Please try again."
-msgstr ""
-
msgid "An error occurred when updating the issue weight"
msgstr ""
@@ -2523,12 +2638,6 @@ msgstr ""
msgid "An error occurred while checking group path. Please refresh and try again."
msgstr ""
-msgid "An error occurred while committing your changes."
-msgstr ""
-
-msgid "An error occurred while creating the list. Please try again."
-msgstr ""
-
msgid "An error occurred while decoding the file."
msgstr ""
@@ -2601,25 +2710,19 @@ msgstr ""
msgid "An error occurred while fetching the Service Desk address."
msgstr ""
-msgid "An error occurred while fetching the board issues. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the board lists. Please reload the page."
msgstr ""
msgid "An error occurred while fetching the board lists. Please try again."
msgstr ""
-msgid "An error occurred while fetching the board swimlanes. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the builds."
msgstr ""
msgid "An error occurred while fetching the job log."
msgstr ""
-msgid "An error occurred while fetching the job trace."
+msgid "An error occurred while fetching the job logs."
msgstr ""
msgid "An error occurred while fetching the job."
@@ -2766,9 +2869,6 @@ msgstr ""
msgid "An error occurred while saving assignees"
msgstr ""
-msgid "An error occurred while saving the template. Please check if the template exists."
-msgstr ""
-
msgid "An error occurred while searching for milestones"
msgstr ""
@@ -2787,10 +2887,10 @@ msgstr ""
msgid "An error occurred while updating approvers"
msgstr ""
-msgid "An error occurred while updating the comment"
+msgid "An error occurred while updating labels."
msgstr ""
-msgid "An error occurred while updating the list. Please try again."
+msgid "An error occurred while updating the comment"
msgstr ""
msgid "An error occurred while validating group path"
@@ -2844,6 +2944,9 @@ msgstr ""
msgid "An unknown error occurred while loading this graph."
msgstr ""
+msgid "An unknown error occurred."
+msgstr ""
+
msgid "Analytics"
msgstr ""
@@ -2877,10 +2980,10 @@ msgstr ""
msgid "Any"
msgstr ""
-msgid "Any Author"
+msgid "Any %{header}"
msgstr ""
-msgid "Any Status"
+msgid "Any Author"
msgstr ""
msgid "Any branch"
@@ -2934,6 +3037,9 @@ msgstr ""
msgid "Application ID"
msgstr ""
+msgid "Application limits saved successfully"
+msgstr ""
+
msgid "Application settings saved successfully"
msgstr ""
@@ -3139,6 +3245,9 @@ msgstr ""
msgid "Are you sure you want to close this blocked issue?"
msgstr ""
+msgid "Are you sure you want to delete \"%{name}\" Value Stream?"
+msgstr ""
+
msgid "Are you sure you want to delete %{name}?"
msgstr ""
@@ -3148,6 +3257,9 @@ msgstr ""
msgid "Are you sure you want to delete this %{typeOfComment}?"
msgstr ""
+msgid "Are you sure you want to delete this SSH key?"
+msgstr ""
+
msgid "Are you sure you want to delete this board?"
msgstr ""
@@ -3172,6 +3284,10 @@ msgstr ""
msgid "Are you sure you want to erase this build?"
msgstr ""
+msgid "Are you sure you want to import %d repository?"
+msgid_plural "Are you sure you want to import %d repositories?"
+msgstr[0] ""
+
msgid "Are you sure you want to lose unsaved changes?"
msgstr ""
@@ -3181,15 +3297,15 @@ msgstr ""
msgid "Are you sure you want to merge immediately?"
msgstr ""
-msgid "Are you sure you want to permanently delete this license?"
-msgstr ""
-
msgid "Are you sure you want to re-deploy this environment?"
msgstr ""
msgid "Are you sure you want to regenerate the public key? You will have to update the public key on the remote server before mirroring will work again."
msgstr ""
+msgid "Are you sure you want to reindex?"
+msgstr ""
+
msgid "Are you sure you want to remove %{group_name}?"
msgstr ""
@@ -3217,6 +3333,9 @@ msgstr ""
msgid "Are you sure you want to revoke this nickname?"
msgstr ""
+msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
+msgstr ""
+
msgid "Are you sure you want to stop this environment?"
msgstr ""
@@ -3238,6 +3357,9 @@ msgstr ""
msgid "Are you sure? The device will be signed out of GitLab and all remember me tokens revoked."
msgstr ""
+msgid "Are you sure? This will invalidate your registered applications and U2F / WebAuthn devices."
+msgstr ""
+
msgid "Are you sure? This will invalidate your registered applications and U2F devices."
msgstr ""
@@ -3256,9 +3378,6 @@ msgstr ""
msgid "Artifacts"
msgstr ""
-msgid "As U2F devices are only supported by a few browsers, we require that you set up a two-factor authentication app before a U2F device. That way you'll always be able to log in - even when you're using an unsupported browser."
-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 ""
@@ -3450,6 +3569,9 @@ msgstr ""
msgid "AuditLogs|Target"
msgstr ""
+msgid "AuditLogs|This month"
+msgstr ""
+
msgid "AuditLogs|User Events"
msgstr ""
@@ -3489,6 +3611,9 @@ msgstr ""
msgid "Authentication via U2F device failed."
msgstr ""
+msgid "Authentication via WebAuthn device failed."
+msgstr ""
+
msgid "Author"
msgstr ""
@@ -3756,15 +3881,6 @@ msgstr ""
msgid "BambooService|You must set up automatic revision labeling and a repository trigger in Bamboo."
msgstr ""
-msgid "BatchComments|Delete all pending comments"
-msgstr ""
-
-msgid "BatchComments|Discard review?"
-msgstr ""
-
-msgid "BatchComments|You're about to discard your review which will delete all of your pending comments. The deleted comments %{strong_start}cannot%{strong_end} be restored."
-msgstr ""
-
msgid "Be careful. Changing the project's namespace can have unintended side effects."
msgstr ""
@@ -3786,6 +3902,9 @@ msgstr ""
msgid "Bi-weekly code coverage"
msgstr ""
+msgid "Billable Users:"
+msgstr ""
+
msgid "Billing"
msgstr ""
@@ -3795,7 +3914,7 @@ msgstr ""
msgid "BillingPlans|@%{user_name} you are currently using the %{plan_name} plan."
msgstr ""
-msgid "BillingPlans|Congratulations, your new trial is activated"
+msgid "BillingPlans|Congratulations, your free trial is activated."
msgstr ""
msgid "BillingPlans|If you would like to downgrade your plan please contact %{support_link_start}Customer Support%{support_link_end}."
@@ -3858,6 +3977,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Block user"
+msgstr ""
+
msgid "Blocked"
msgstr ""
@@ -3873,31 +3995,37 @@ msgstr ""
msgid "Blog"
msgstr ""
-msgid "Board name"
-msgstr ""
-
msgid "Board scope"
msgstr ""
msgid "Board scope affects which issues are displayed for anyone who visits this board"
msgstr ""
-msgid "BoardBlankState|Add default lists"
+msgid "Boards"
+msgstr ""
+
+msgid "Boards and Board Lists"
msgstr ""
-msgid "BoardBlankState|Add the following default lists to your Issue Board with one click:"
+msgid "Boards|An error occurred while creating the issue. Please try again."
msgstr ""
-msgid "BoardBlankState|Nevermind, I'll use my own"
+msgid "Boards|An error occurred while creating the list. Please try again."
msgstr ""
-msgid "BoardBlankState|Starting out with the default set of lists will get you right on the way to making the most of your board."
+msgid "Boards|An error occurred while fetching issues. Please reload the page."
msgstr ""
-msgid "Boards"
+msgid "Boards|An error occurred while fetching the board issues. Please reload the page."
msgstr ""
-msgid "Boards and Board Lists"
+msgid "Boards|An error occurred while fetching the board swimlanes. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while moving the issue. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while updating the list. Please try again."
msgstr ""
msgid "Boards|Collapse"
@@ -3924,7 +4052,7 @@ msgstr ""
msgid "Branch %{branch_name} was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr ""
-msgid "Branch has changed"
+msgid "Branch changed"
msgstr ""
msgid "Branch is already taken"
@@ -4230,6 +4358,9 @@ msgstr ""
msgid "CLOSED (MOVED)"
msgstr ""
+msgid "CODEOWNERS rule violation"
+msgstr ""
+
msgid "CONTRIBUTING"
msgstr ""
@@ -4260,9 +4391,6 @@ msgstr ""
msgid "Can't create snippet: %{err}"
msgstr ""
-msgid "Can't edit as source branch was deleted"
-msgstr ""
-
msgid "Can't fetch content for the blob: %{err}"
msgstr ""
@@ -4275,9 +4403,6 @@ msgstr ""
msgid "Can't load mermaid module: %{err}"
msgstr ""
-msgid "Can't remove group members without group managed account"
-msgstr ""
-
msgid "Can't scan the code?"
msgstr ""
@@ -4320,6 +4445,9 @@ msgstr ""
msgid "Cannot create the abuse report. This user has been blocked."
msgstr ""
+msgid "Cannot enable shared runners because parent group does not allow it"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -4425,6 +4553,15 @@ msgstr ""
msgid "Change your password or recover your current one"
msgstr ""
+msgid "ChangeReviewer|Reviewer changed from %{old} to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Reviewer changed to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Unassigned"
+msgstr ""
+
msgid "ChangeTypeActionLabel|Pick into branch"
msgstr ""
@@ -4464,6 +4601,9 @@ msgstr ""
msgid "Changes the title to \"%{title_param}\"."
msgstr ""
+msgid "Changes were successfully made."
+msgstr ""
+
msgid "Changes won't take place until the index is %{link_start}recreated%{link_end}."
msgstr ""
@@ -4869,6 +5009,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove variable"
+msgstr ""
+
msgid "CiVariables|Remove variable row"
msgstr ""
@@ -4947,9 +5090,6 @@ msgstr ""
msgid "Clear due date"
msgstr ""
-msgid "Clear input"
-msgstr ""
-
msgid "Clear recent searches"
msgstr ""
@@ -4998,6 +5138,9 @@ msgstr ""
msgid "Client authentication key password"
msgstr ""
+msgid "Client request timeout"
+msgstr ""
+
msgid "Clients"
msgstr ""
@@ -5082,6 +5225,27 @@ msgstr ""
msgid "Cluster type must be specificed for Stages::ClusterEndpointInserter"
msgstr ""
+msgid "ClusterAgents|Configuration"
+msgstr ""
+
+msgid "ClusterAgents|Connect your cluster with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate Kubernetes with a GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Name"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Agent also requires %{linkStart}enabling the Agent Server%{linkEnd}"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Kubernetes Agent allows an Infrastructure as Code, GitOps approach to integrating Kubernetes clusters with GitLab. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "ClusterAgent|This feature is only available for premium plans"
msgstr ""
@@ -5151,10 +5315,10 @@ msgstr ""
msgid "ClusterIntegration|All installed applications and related resources"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster."
+msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{linkStart}More information%{linkEnd}"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{startLink}More information%{endLink}"
+msgid "ClusterIntegration|Allow GitLab to manage namespaces and service accounts for this cluster."
msgstr ""
msgid "ClusterIntegration|Alternatively, "
@@ -5175,6 +5339,9 @@ msgstr ""
msgid "ClusterIntegration|An error occurred while trying to fetch zone machine types: %{error}"
msgstr ""
+msgid "ClusterIntegration|An unknown error occurred while attempting to connect to Kubernetes."
+msgstr ""
+
msgid "ClusterIntegration|Any project namespaces"
msgstr ""
@@ -5190,6 +5357,9 @@ msgstr ""
msgid "ClusterIntegration|Authenticate with Amazon Web Services"
msgstr ""
+msgid "ClusterIntegration|Authentication Error"
+msgstr ""
+
msgid "ClusterIntegration|Base domain"
msgstr ""
@@ -5208,13 +5378,22 @@ msgstr ""
msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}security group %{externalLinkIcon} %{endLink} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
+msgid "ClusterIntegration|Check your CA certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Check your cluster status"
+msgstr ""
+
+msgid "ClusterIntegration|Check your token"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}subnets %{externalLinkIcon} %{endLink} in your VPC where your worker nodes will run."
+msgid "ClusterIntegration|Choose the %{linkStart}security group %{linkEnd} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
msgstr ""
-msgid "ClusterIntegration|Choose the worker node %{startLink}instance type %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Choose the %{linkStart}subnets %{linkEnd} in your VPC where your worker nodes will run."
+msgstr ""
+
+msgid "ClusterIntegration|Choose the worker node %{linkStart}instance type%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Choose which applications to install on your Kubernetes cluster."
@@ -5226,10 +5405,7 @@ msgstr ""
msgid "ClusterIntegration|Clear cluster cache"
msgstr ""
-msgid "ClusterIntegration|Clear the local cache of namespace and service accounts. This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
-msgstr ""
-
-msgid "ClusterIntegration|Cluster being created"
+msgid "ClusterIntegration|Clear the local cache of namespace and service accounts."
msgstr ""
msgid "ClusterIntegration|Cluster management project (alpha)"
@@ -5241,15 +5417,21 @@ msgstr ""
msgid "ClusterIntegration|Cluster_applications artifact too big. Maximum allowable size: %{human_size}"
msgstr ""
-msgid "ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters."
+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|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}"
+msgid "ClusterIntegration|Clusters connected with a certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Connect cluster with certificate"
msgstr ""
msgid "ClusterIntegration|Connect existing cluster"
msgstr ""
+msgid "ClusterIntegration|Connection Error"
+msgstr ""
+
msgid "ClusterIntegration|Copy API URL"
msgstr ""
@@ -5325,6 +5507,12 @@ msgstr ""
msgid "ClusterIntegration|Deletes all GitLab resources attached to this cluster during removal"
msgstr ""
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared."
+msgstr ""
+
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared. %{linkStart}More information%{linkEnd}"
+msgstr ""
+
msgid "ClusterIntegration|Did you know?"
msgstr ""
@@ -5394,6 +5582,9 @@ msgstr ""
msgid "ClusterIntegration|Fluentd is an open source data collector, which lets you unify the data collection and consumption for a better use and understanding of data. It requires at least one of the following logs to be successfully installed."
msgstr ""
+msgid "ClusterIntegration|GitLab Agent managed clusters"
+msgstr ""
+
msgid "ClusterIntegration|GitLab Container Network Policies"
msgstr ""
@@ -5406,6 +5597,12 @@ msgstr ""
msgid "ClusterIntegration|GitLab Runner connects to the repository and executes CI/CD jobs, pushing results back and deploying applications to production."
msgstr ""
+msgid "ClusterIntegration|GitLab failed to authenticate."
+msgstr ""
+
+msgid "ClusterIntegration|GitLab failed to connect to the cluster."
+msgstr ""
+
msgid "ClusterIntegration|GitLab-managed cluster"
msgstr ""
@@ -5427,6 +5624,9 @@ msgstr ""
msgid "ClusterIntegration|Group cluster"
msgstr ""
+msgid "ClusterIntegration|HTTP Error"
+msgstr ""
+
msgid "ClusterIntegration|Helm Tiller"
msgstr ""
@@ -5460,7 +5660,10 @@ msgstr ""
msgid "ClusterIntegration|Instance type"
msgstr ""
-msgid "ClusterIntegration|Integrate Kubernetes cluster automation"
+msgid "ClusterIntegration|Integrate Kubernetes with a cluster certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Integrate with a cluster certificate"
msgstr ""
msgid "ClusterIntegration|Issuer Email"
@@ -5496,9 +5699,6 @@ msgstr ""
msgid "ClusterIntegration|Knative extends Kubernetes to provide a set of middleware components that are essential to build modern, source-centric, and container-based applications that can run anywhere: on premises, in the cloud, or even in a third-party data center."
msgstr ""
-msgid "ClusterIntegration|Kubernetes cluster"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes cluster is being created..."
msgstr ""
@@ -5511,9 +5711,6 @@ msgstr ""
msgid "ClusterIntegration|Kubernetes clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr ""
-msgid "ClusterIntegration|Kubernetes clusters can be used to deploy applications and to provide Review Apps for this project"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes version"
msgstr ""
@@ -5526,7 +5723,7 @@ msgstr ""
msgid "ClusterIntegration|Learn more about %{help_link_start}zones%{help_link_end}."
msgstr ""
-msgid "ClusterIntegration|Learn more about %{startLink}Regions %{externalLinkIcon}%{endLink}."
+msgid "ClusterIntegration|Learn more about %{linkStart}Regions%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Learn more about Kubernetes"
@@ -5571,12 +5768,18 @@ msgstr ""
msgid "ClusterIntegration|Machine type"
msgstr ""
+msgid "ClusterIntegration|Make sure your API endpoint is correct"
+msgstr ""
+
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create Kubernetes clusters"
msgstr ""
msgid "ClusterIntegration|Manage your Kubernetes cluster by visiting %{provider_link}"
msgstr ""
+msgid "ClusterIntegration|Namespace per environment"
+msgstr ""
+
msgid "ClusterIntegration|No IAM Roles found"
msgstr ""
@@ -5622,6 +5825,9 @@ msgstr ""
msgid "ClusterIntegration|No zones matched your search"
msgstr ""
+msgid "ClusterIntegration|Node calculations use the Kubernetes Metrics API. Make sure your cluster has metrics installed"
+msgstr ""
+
msgid "ClusterIntegration|Number of nodes"
msgstr ""
@@ -5664,6 +5870,9 @@ msgstr ""
msgid "ClusterIntegration|RBAC-enabled cluster"
msgstr ""
+msgid "ClusterIntegration|Read our %{linkStart}help page%{linkEnd} on Kubernetes cluster integration."
+msgstr ""
+
msgid "ClusterIntegration|Read our %{link_start}help page%{link_end} on Kubernetes cluster integration."
msgstr ""
@@ -5766,7 +5975,7 @@ msgstr ""
msgid "ClusterIntegration|Select a VPC to choose a subnet"
msgstr ""
-msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{linkStart}Amazon Web Services %{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select a network to choose a subnetwork"
@@ -5799,7 +6008,7 @@ msgstr ""
msgid "ClusterIntegration|Select project to choose zone"
msgstr ""
-msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select zone"
@@ -5889,9 +6098,18 @@ msgstr ""
msgid "ClusterIntegration|There was a problem authenticating with your cluster. Please ensure your CA Certificate and Token are valid."
msgstr ""
+msgid "ClusterIntegration|There was an HTTP error when connecting to your cluster."
+msgstr ""
+
msgid "ClusterIntegration|This account must have permissions to create a Kubernetes cluster in the %{link_to_container_project} specified below"
msgstr ""
+msgid "ClusterIntegration|This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
+msgstr ""
+
+msgid "ClusterIntegration|This is necessary to clear existing environment-namespace associations from clusters previously managed by GitLab."
+msgstr ""
+
msgid "ClusterIntegration|This option will allow you to install applications on RBAC clusters."
msgstr ""
@@ -5916,9 +6134,21 @@ msgstr ""
msgid "ClusterIntegration|To use a new project, first create one on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}."
msgstr ""
+msgid "ClusterIntegration|Troubleshooting tips:"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Authenticate"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Connect"
+msgstr ""
+
msgid "ClusterIntegration|Uninstall %{appTitle}"
msgstr ""
+msgid "ClusterIntegration|Unknown Error"
+msgstr ""
+
msgid "ClusterIntegration|Update %{appTitle}"
msgstr ""
@@ -5979,7 +6209,7 @@ msgstr ""
msgid "ClusterIntegration|Your cluster API is unreachable. Please ensure your API URL is correct."
msgstr ""
-msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Zone"
@@ -6099,6 +6329,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse all threads"
+msgstr ""
+
msgid "Collapse approvers"
msgstr ""
@@ -6247,7 +6480,7 @@ msgstr ""
msgid "Commit…"
msgstr ""
-msgid "Company"
+msgid "Community forum"
msgstr ""
msgid "Company name"
@@ -6256,6 +6489,9 @@ msgstr ""
msgid "Compare"
msgstr ""
+msgid "Compare %{oldCommitId}...%{newCommitId}"
+msgstr ""
+
msgid "Compare Git revisions"
msgstr ""
@@ -6271,6 +6507,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare submodule commit revisions"
+msgstr ""
+
msgid "Compare with previous version"
msgstr ""
@@ -6406,6 +6645,9 @@ msgstr ""
msgid "Configure the way a user creates a new account."
msgstr ""
+msgid "Configure which lists are shown for anyone who visits this board"
+msgstr ""
+
msgid "Confirm"
msgstr ""
@@ -6628,6 +6870,9 @@ msgstr[0] ""
msgid "ContainerRegistry|Set cleanup policy"
msgstr ""
+msgid "ContainerRegistry|Some tags were not deleted"
+msgstr ""
+
msgid "ContainerRegistry|Something went wrong while fetching the cleanup policy."
msgstr ""
@@ -6667,6 +6912,9 @@ msgstr ""
msgid "ContainerRegistry|Tags with names matching this regex pattern will %{italicStart}expire:%{italicEnd}"
msgstr ""
+msgid "ContainerRegistry|The cleanup policy timed out before it could delete all tags. An administrator can %{adminLinkStart}manually run cleanup now%{adminLinkEnd} or you can wait for the cleanup policy to automatically run again. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "ContainerRegistry|The last tag related to this image was recently removed. This empty image and any associated data will be automatically removed as part of the regular Garbage Collection process. If you have any questions, contact your administrator."
msgstr ""
@@ -6799,6 +7047,9 @@ msgstr ""
msgid "Contributions per group member"
msgstr ""
+msgid "Contributor"
+msgstr ""
+
msgid "Contributors"
msgstr ""
@@ -6928,6 +7179,9 @@ msgstr ""
msgid "Could not change HEAD: branch '%{branch}' does not exist"
msgstr ""
+msgid "Could not commit. An unexpected error occurred."
+msgstr ""
+
msgid "Could not connect to FogBugz, check your URL"
msgstr ""
@@ -6967,6 +7221,9 @@ msgstr ""
msgid "Could not find iteration"
msgstr ""
+msgid "Could not load instance counts. Please refresh the page to try again."
+msgstr ""
+
msgid "Could not remove the trigger."
msgstr ""
@@ -6991,10 +7248,10 @@ msgstr ""
msgid "Could not save prometheus manual configuration"
msgstr ""
-msgid "Could not udpdate wiki page"
+msgid "Could not update the LDAP settings"
msgstr ""
-msgid "Could not update the LDAP settings"
+msgid "Could not update wiki page"
msgstr ""
msgid "Could not upload your designs as one or more files uploaded are not supported."
@@ -7650,6 +7907,9 @@ msgstr ""
msgid "DastProfiles|Are you sure you want to delete this profile?"
msgstr ""
+msgid "DastProfiles|Could not create site validation token. Please refresh the page, or try again later."
+msgstr ""
+
msgid "DastProfiles|Could not create the scanner profile. Please try again."
msgstr ""
@@ -7674,6 +7934,12 @@ msgstr ""
msgid "DastProfiles|Could not fetch site profiles. Please refresh the page, or try again later."
msgstr ""
+msgid "DastProfiles|Could not retrieve site validation status. Please refresh the page, or try again later."
+msgstr ""
+
+msgid "DastProfiles|Could not update the scanner profile. Please try again."
+msgstr ""
+
msgid "DastProfiles|Could not update the site profile. Please try again."
msgstr ""
@@ -7689,7 +7955,7 @@ msgstr ""
msgid "DastProfiles|Download validation text file"
msgstr ""
-msgid "DastProfiles|Edit feature will come soon. Please create a new profile if changes needed"
+msgid "DastProfiles|Edit scanner profile"
msgstr ""
msgid "DastProfiles|Edit site profile"
@@ -7722,6 +7988,9 @@ msgstr ""
msgid "DastProfiles|No profiles created yet"
msgstr ""
+msgid "DastProfiles|Passive"
+msgstr ""
+
msgid "DastProfiles|Please enter a valid URL format, ex: http://www.example.com/home"
msgstr ""
@@ -7737,6 +8006,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan mode"
+msgstr ""
+
msgid "DastProfiles|Scanner Profile"
msgstr ""
@@ -7776,10 +8048,10 @@ msgstr ""
msgid "DastProfiles|Text file validation"
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
+msgid "DastProfiles|The maximum number of minutes allowed for the spider to traverse the site."
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the spider to traverse the site."
+msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
msgstr ""
msgid "DastProfiles|Validate"
@@ -7812,6 +8084,9 @@ msgstr ""
msgid "Date picker"
msgstr ""
+msgid "Date range"
+msgstr ""
+
msgid "Date range cannot exceed %{maxDateRange} days."
msgstr ""
@@ -7836,6 +8111,9 @@ msgstr ""
msgid "Days to merge"
msgstr ""
+msgid "Dear Administrator,"
+msgstr ""
+
msgid "Debug"
msgstr ""
@@ -7947,12 +8225,18 @@ msgstr ""
msgid "Delete"
msgstr ""
+msgid "Delete %{name}"
+msgstr ""
+
msgid "Delete Comment"
msgstr ""
msgid "Delete Snippet"
msgstr ""
+msgid "Delete Value Stream"
+msgstr ""
+
msgid "Delete account"
msgstr ""
@@ -7974,9 +8258,6 @@ msgstr ""
msgid "Delete label: %{label_name} ?"
msgstr ""
-msgid "Delete license"
-msgstr ""
-
msgid "Delete list"
msgstr ""
@@ -8052,15 +8333,6 @@ msgstr ""
msgid "Deleting a project places it into a read-only state until %{date}, at which point the project will be permanently deleted. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "Deleting the license failed."
-msgstr ""
-
-msgid "Deleting the license failed. The license was not found."
-msgstr ""
-
-msgid "Deleting the license failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "Deleting the project will delete its repository and all related resources including issues, merge requests etc."
msgstr ""
@@ -8550,7 +8822,10 @@ msgstr ""
msgid "DesignManagement|The maximum number of designs allowed to be uploaded is %{upload_limit}. Please try again."
msgstr ""
-msgid "DesignManagement|To upload designs, you'll need to enable LFS. %{requirements_link_start}More information%{requirements_link_end}"
+msgid "DesignManagement|There was an error moving your designs. Please upload your designs below."
+msgstr ""
+
+msgid "DesignManagement|To upload designs, you'll need to enable LFS and have admin enable hashed storage. %{requirements_link_start}More information%{requirements_link_end}"
msgstr ""
msgid "DesignManagement|Unresolve thread"
@@ -8562,6 +8837,9 @@ msgstr ""
msgid "DesignManagement|Upload skipped."
msgstr ""
+msgid "DesignManagement|Your designs are being copied and are on their way… Please refresh to update."
+msgstr ""
+
msgid "DesignManagement|and %{moreCount} more."
msgstr ""
@@ -8619,6 +8897,9 @@ msgstr ""
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
+msgid "Direct member"
+msgstr ""
+
msgid "Direction"
msgstr ""
@@ -8667,9 +8948,6 @@ msgstr ""
msgid "Discard draft"
msgstr ""
-msgid "Discard review"
-msgstr ""
-
msgid "DiscordService|Discord Notifications"
msgstr ""
@@ -8737,10 +9015,10 @@ msgstr ""
msgid "Dismiss Merge Request promotion"
msgstr ""
-msgid "Dismiss Selected"
+msgid "Dismiss Value Stream Analytics introduction box"
msgstr ""
-msgid "Dismiss Value Stream Analytics introduction box"
+msgid "Dismiss selected"
msgstr ""
msgid "Dismiss trial promotion"
@@ -8791,9 +9069,6 @@ msgstr ""
msgid "Documents reindexed: %{processed_documents} (%{percentage}%%)"
msgstr ""
-msgid "Doing"
-msgstr ""
-
msgid "Domain"
msgstr ""
@@ -8989,9 +9264,6 @@ msgstr ""
msgid "Edit environment"
msgstr ""
-msgid "Edit file"
-msgstr ""
-
msgid "Edit files in the editor and commit changes here"
msgstr ""
@@ -9004,6 +9276,12 @@ msgstr ""
msgid "Edit identity for %{user_name}"
msgstr ""
+msgid "Edit in Web IDE"
+msgstr ""
+
+msgid "Edit in single-file editor"
+msgstr ""
+
msgid "Edit issues"
msgstr ""
@@ -9031,10 +9309,10 @@ msgstr ""
msgid "Editing"
msgstr ""
-msgid "Elasticsearch"
+msgid "Elasticsearch AWS IAM credentials"
msgstr ""
-msgid "Elasticsearch AWS IAM credentials"
+msgid "Elasticsearch HTTP client timeout value in seconds."
msgstr ""
msgid "Elasticsearch indexing restrictions"
@@ -9043,9 +9321,6 @@ msgstr ""
msgid "Elasticsearch indexing started"
msgstr ""
-msgid "Elasticsearch integration. Elasticsearch AWS IAM."
-msgstr ""
-
msgid "Elasticsearch reindexing is already in progress"
msgstr ""
@@ -9073,9 +9348,6 @@ msgstr ""
msgid "Email Notification"
msgstr ""
-msgid "Email address"
-msgstr ""
-
msgid "Email could not be sent"
msgstr ""
@@ -9139,6 +9411,9 @@ msgstr ""
msgid "Emails sent from Service Desk will have this name"
msgstr ""
+msgid "Emails sent to %{email} will still be supported"
+msgstr ""
+
msgid "Emails separated by comma"
msgstr ""
@@ -9172,9 +9447,18 @@ msgstr ""
msgid "Enable"
msgstr ""
+msgid "Enable %{link_start}Gitpod%{link_end} integration to launch a development environment in your browser directly from GitLab."
+msgstr ""
+
msgid "Enable Auto DevOps"
msgstr ""
+msgid "Enable Gitpod"
+msgstr ""
+
+msgid "Enable Gitpod?"
+msgstr ""
+
msgid "Enable HTML emails"
msgstr ""
@@ -9304,9 +9588,6 @@ msgstr ""
msgid "Encountered an error while rendering: %{err}"
msgstr ""
-msgid "End date"
-msgstr ""
-
msgid "Ends at (UTC)"
msgstr ""
@@ -9466,7 +9747,7 @@ msgstr ""
msgid "EnvironmentsDashboard|The environments dashboard provides a summary of each project's environments' status, including pipeline and alert statuses."
msgstr ""
-msgid "EnvironmentsDashboard|This dashboard displays a maximum of 7 projects and 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
+msgid "EnvironmentsDashboard|This dashboard displays 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
msgstr ""
msgid "Environments|An error occurred while canceling the auto stop, please try again"
@@ -9787,6 +10068,9 @@ msgstr ""
msgid "Error deleting project. Check logs for error details."
msgstr ""
+msgid "Error fetching burnup chart data"
+msgstr ""
+
msgid "Error fetching diverging counts for branches. Please try again."
msgstr ""
@@ -9865,6 +10149,9 @@ msgstr ""
msgid "Error occurred when saving assignees"
msgstr ""
+msgid "Error occurred when saving reviewers"
+msgstr ""
+
msgid "Error occurred when toggling the notification subscription"
msgstr ""
@@ -10117,10 +10404,13 @@ msgstr ""
msgid "Expand all"
msgstr ""
-msgid "Expand approvers"
+msgid "Expand all files"
msgstr ""
-msgid "Expand dropdown"
+msgid "Expand all threads"
+msgstr ""
+
+msgid "Expand approvers"
msgstr ""
msgid "Expand milestones"
@@ -10291,6 +10581,9 @@ msgstr ""
msgid "Failed to create Merge Request. Please try again."
msgstr ""
+msgid "Failed to create To-Do for the design."
+msgstr ""
+
msgid "Failed to create a branch for this issue. Please try again."
msgstr ""
@@ -10330,6 +10623,12 @@ msgstr ""
msgid "Failed to load authors. Please try again."
msgstr ""
+msgid "Failed to load branches. Please try again."
+msgstr ""
+
+msgid "Failed to load deploy keys."
+msgstr ""
+
msgid "Failed to load emoji list."
msgstr ""
@@ -10345,6 +10644,9 @@ msgstr ""
msgid "Failed to load groups & users."
msgstr ""
+msgid "Failed to load groups, users and deploy keys."
+msgstr ""
+
msgid "Failed to load labels. Please try again."
msgstr ""
@@ -10354,6 +10656,12 @@ msgstr ""
msgid "Failed to load related branches"
msgstr ""
+msgid "Failed to load sidebar confidential toggle"
+msgstr ""
+
+msgid "Failed to load sidebar lock status"
+msgstr ""
+
msgid "Failed to load stacktrace."
msgstr ""
@@ -10381,6 +10689,9 @@ msgstr ""
msgid "Failed to publish issue on status page."
msgstr ""
+msgid "Failed to remove To-Do for the design."
+msgstr ""
+
msgid "Failed to remove a Zoom meeting"
msgstr ""
@@ -10423,6 +10734,9 @@ msgstr ""
msgid "Failed to signing using smartcard authentication"
msgstr ""
+msgid "Failed to toggle To-Do for the design."
+msgstr ""
+
msgid "Failed to update branch!"
msgstr ""
@@ -10535,7 +10849,7 @@ msgstr ""
msgid "FeatureFlags|Edit User List"
msgstr ""
-msgid "FeatureFlags|Enable features for specific users and specific environments by defining feature flag strategies."
+msgid "FeatureFlags|Enable features for specific users and environments by configuring feature flag strategies."
msgstr ""
msgid "FeatureFlags|Environment Spec"
@@ -10595,7 +10909,7 @@ msgstr ""
msgid "FeatureFlags|Include additional user IDs"
msgstr ""
-msgid "FeatureFlags|Install a %{docs_link_anchored_start}compatible client library%{docs_link_anchored_end} and specify the API URL, application name, and instance ID during the configuration setup. %{docs_link_start}More Information%{docs_link_end}"
+msgid "FeatureFlags|Install a %{docsLinkAnchoredStart}compatible client library%{docsLinkAnchoredEnd} and specify the API URL, application name, and instance ID during the configuration setup. %{docsLinkStart}More Information%{docsLinkEnd}"
msgstr ""
msgid "FeatureFlags|Instance ID"
@@ -10607,6 +10921,9 @@ msgstr ""
msgid "FeatureFlags|Loading feature flags"
msgstr ""
+msgid "FeatureFlags|Loading user lists"
+msgstr ""
+
msgid "FeatureFlags|More information"
msgstr ""
@@ -10625,7 +10942,7 @@ msgstr ""
msgid "FeatureFlags|New feature flag"
msgstr ""
-msgid "FeatureFlags|New list"
+msgid "FeatureFlags|New user list"
msgstr ""
msgid "FeatureFlags|Percent of users"
@@ -10664,6 +10981,9 @@ msgstr ""
msgid "FeatureFlags|There was an error fetching the feature flags."
msgstr ""
+msgid "FeatureFlags|There was an error fetching the user lists."
+msgstr ""
+
msgid "FeatureFlags|There was an error retrieving user lists"
msgstr ""
@@ -10679,6 +10999,9 @@ msgstr ""
msgid "FeatureFlags|User List"
msgstr ""
+msgid "FeatureFlags|User Lists"
+msgstr ""
+
msgid "FeatureFlag|List"
msgstr ""
@@ -10706,15 +11029,6 @@ msgstr ""
msgid "Fetching incoming email"
msgstr ""
-msgid "Fetching licenses failed."
-msgstr ""
-
-msgid "Fetching licenses failed. The request endpoint was not found."
-msgstr ""
-
-msgid "Fetching licenses failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "File"
msgstr ""
@@ -10817,12 +11131,21 @@ msgstr ""
msgid "Filter by status"
msgstr ""
+msgid "Filter by test cases that are currently archived."
+msgstr ""
+
+msgid "Filter by test cases that are currently opened."
+msgstr ""
+
msgid "Filter by two-factor authentication"
msgstr ""
msgid "Filter by user"
msgstr ""
+msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
+msgstr ""
+
msgid "Filter pipelines"
msgstr ""
@@ -10838,7 +11161,7 @@ msgstr ""
msgid "Filter results..."
msgstr ""
-msgid "Filter your projects by name"
+msgid "Filter your repositories by name"
msgstr ""
msgid "Filter..."
@@ -10847,7 +11170,7 @@ msgstr ""
msgid "Find File"
msgstr ""
-msgid "Find bugs in your code with coverage-guided fuzzing"
+msgid "Find bugs in your code with coverage-guided fuzzing."
msgstr ""
msgid "Find by path"
@@ -10874,9 +11197,6 @@ msgstr ""
msgid "Finish editing this message first!"
msgstr ""
-msgid "Finish review"
-msgstr ""
-
msgid "Finish setting up your dedicated account for %{group_name}."
msgstr ""
@@ -10946,6 +11266,9 @@ msgstr ""
msgid "Footer message"
msgstr ""
+msgid "For a faster browsing experience, some files are collapsed by default."
+msgstr ""
+
msgid "For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
@@ -10955,6 +11278,9 @@ msgstr ""
msgid "For more info, read the documentation."
msgstr ""
+msgid "For more information on how the number of active users is calculated, see the %{self_managed_subscriptions_doc_link} documentation."
+msgstr ""
+
msgid "For more information, go to the "
msgstr ""
@@ -11093,6 +11419,9 @@ msgstr ""
msgid "Generate new token"
msgstr ""
+msgid "Generic package file size in bytes"
+msgstr ""
+
msgid "Geo"
msgstr ""
@@ -11354,6 +11683,9 @@ msgstr ""
msgid "Geo|Please refer to Geo Troubleshooting."
msgstr ""
+msgid "Geo|Primary node"
+msgstr ""
+
msgid "Geo|Project"
msgstr ""
@@ -11396,6 +11728,9 @@ msgstr ""
msgid "Geo|Review replication status, and resynchronize and reverify items with the primary node."
msgstr ""
+msgid "Geo|Secondary node"
+msgstr ""
+
msgid "Geo|Status"
msgstr ""
@@ -11435,6 +11770,9 @@ msgstr ""
msgid "Geo|URL must be a valid url (ex: https://gitlab.com)"
msgstr ""
+msgid "Geo|Undefined"
+msgstr ""
+
msgid "Geo|Unknown state"
msgstr ""
@@ -11510,10 +11848,16 @@ msgstr ""
msgid "GitHub import"
msgstr ""
+msgid "GitLab"
+msgstr ""
+
msgid "GitLab / Unsubscribe"
msgstr ""
-msgid "GitLab Enterprise Edition %{plan}"
+msgid "GitLab API"
+msgstr ""
+
+msgid "GitLab Billing Team."
msgstr ""
msgid "GitLab Group Runners can execute code for all the projects in this group."
@@ -11525,12 +11869,18 @@ msgstr ""
msgid "GitLab Issue"
msgstr ""
+msgid "GitLab Pages"
+msgstr ""
+
msgid "GitLab Service Desk is a simple way to allow people to create issues in your GitLab instance without needing their own user account. It provides a unique email address for end users to create issues in a project, and replies can be sent either through the GitLab interface or by email. End users will only see the thread through email."
msgstr ""
msgid "GitLab Shared Runners execute code of different projects on the same Runner unless you configure GitLab Runner Autoscale with MaxBuilds 1 (which it is on GitLab.com)."
msgstr ""
+msgid "GitLab Shell"
+msgstr ""
+
msgid "GitLab Support Bot"
msgstr ""
@@ -11540,7 +11890,7 @@ msgstr ""
msgid "GitLab User"
msgstr ""
-msgid "GitLab allows you to continue using your license even if you exceed the number of seats you purchased. You will be required to pay for these seats when you renew your license."
+msgid "GitLab Workhorse"
msgstr ""
msgid "GitLab commit"
@@ -11708,6 +12058,21 @@ msgstr ""
msgid "Gitlab Pages"
msgstr ""
+msgid "Gitpod"
+msgstr ""
+
+msgid "Gitpod|Add the URL to your Gitpod instance configured to read your GitLab projects."
+msgstr ""
+
+msgid "Gitpod|Enable Gitpod integration"
+msgstr ""
+
+msgid "Gitpod|Gitpod URL"
+msgstr ""
+
+msgid "Gitpod|e.g. https://gitpod.example.com"
+msgstr ""
+
msgid "Given access %{time_ago}"
msgstr ""
@@ -12215,9 +12580,6 @@ msgstr ""
msgid "GroupSAML|Valid SAML Response"
msgstr ""
-msgid "GroupSAML|With group managed accounts enabled, all the users without a group managed account will be excluded from the group."
-msgstr ""
-
msgid "GroupSAML|With prohibit outer forks flag enabled group members will be able to fork project only inside your group."
msgstr ""
@@ -12431,10 +12793,10 @@ msgstr ""
msgid "GroupsNew|Create group"
msgstr ""
-msgid "GroupsNew|GitLab group export"
+msgid "GroupsNew|Import"
msgstr ""
-msgid "GroupsNew|Import"
+msgid "GroupsNew|Import a GitLab group export file"
msgstr ""
msgid "GroupsNew|Import group"
@@ -12576,6 +12938,9 @@ msgid "Hide chart"
msgid_plural "Hide charts"
msgstr[0] ""
+msgid "Hide comments on this file"
+msgstr ""
+
msgid "Hide details"
msgstr ""
@@ -12619,6 +12984,15 @@ msgstr ""
msgid "Highest role:"
msgstr ""
+msgid "HighlightBar|Alert events:"
+msgstr ""
+
+msgid "HighlightBar|Alert start time:"
+msgstr ""
+
+msgid "HighlightBar|Original alert:"
+msgstr ""
+
msgid "History"
msgstr ""
@@ -12796,6 +13170,9 @@ msgstr ""
msgid "If enabled, access to projects will be validated on an external service using their classification label."
msgstr ""
+msgid "If the number of active users exceeds the user limit, you will be charged for the number of %{users_over_license_link} at your next license reconciliation."
+msgstr ""
+
msgid "If there is no previous license or if the previous license has expired, some GitLab functionality will be blocked until a new, valid license is uploaded."
msgstr ""
@@ -12835,9 +13212,6 @@ msgstr ""
msgid "If your HTTP repository is not publicly accessible, add your credentials."
msgstr ""
-msgid "Iglu registry URL (optional)"
-msgstr ""
-
msgid "Ignore"
msgstr ""
@@ -12874,6 +13248,14 @@ msgstr ""
msgid "Import"
msgstr ""
+msgid "Import %d compatible repository"
+msgid_plural "Import %d compatible repositories"
+msgstr[0] ""
+
+msgid "Import %d repository"
+msgid_plural "Import %d repositories"
+msgstr[0] ""
+
msgid "Import CSV"
msgstr ""
@@ -12883,15 +13265,9 @@ msgstr ""
msgid "Import all compatible projects"
msgstr ""
-msgid "Import all compatible repositories"
-msgstr ""
-
msgid "Import all projects"
msgstr ""
-msgid "Import all repositories"
-msgstr ""
-
msgid "Import an exported GitLab project"
msgstr ""
@@ -12979,6 +13355,9 @@ msgstr ""
msgid "ImportProjects|Error importing repository %{project_safe_import_url} into %{project_full_path} - %{message}"
msgstr ""
+msgid "ImportProjects|Import repositories"
+msgstr ""
+
msgid "ImportProjects|Importing the project failed"
msgstr ""
@@ -12991,7 +13370,7 @@ msgstr ""
msgid "ImportProjects|Requesting your %{provider} repositories failed"
msgstr ""
-msgid "ImportProjects|Select the projects you want to import"
+msgid "ImportProjects|Select the repositories you want to import"
msgstr ""
msgid "ImportProjects|The remote data could not be imported."
@@ -13027,9 +13406,6 @@ msgstr ""
msgid "In order to enable Service Desk for your instance, you must first set up incoming email."
msgstr ""
-msgid "In order to gather accurate feature usage data, it can take 1 to 2 weeks to see your index."
-msgstr ""
-
msgid "In order to personalize your experience with GitLab%{br_tag}we would like to know a bit more about you."
msgstr ""
@@ -13060,18 +13436,30 @@ msgstr ""
msgid "IncidentManagement|Create incident"
msgstr ""
+msgid "IncidentManagement|Critical - S1"
+msgstr ""
+
msgid "IncidentManagement|Date created"
msgstr ""
msgid "IncidentManagement|Display your incidents in a dedicated view"
msgstr ""
+msgid "IncidentManagement|High - S2"
+msgstr ""
+
msgid "IncidentManagement|Incident"
msgstr ""
msgid "IncidentManagement|Incidents"
msgstr ""
+msgid "IncidentManagement|Low - S4"
+msgstr ""
+
+msgid "IncidentManagement|Medium - S3"
+msgstr ""
+
msgid "IncidentManagement|No incidents to display."
msgstr ""
@@ -13084,6 +13472,9 @@ msgstr ""
msgid "IncidentManagement|Published to status page"
msgstr ""
+msgid "IncidentManagement|Severity"
+msgstr ""
+
msgid "IncidentManagement|There are no closed incidents"
msgstr ""
@@ -13093,6 +13484,9 @@ msgstr ""
msgid "IncidentManagement|Unassigned"
msgstr ""
+msgid "IncidentManagement|Unknown"
+msgstr ""
+
msgid "IncidentManagement|Unpublished"
msgstr ""
@@ -13114,6 +13508,15 @@ msgstr ""
msgid "Incidents"
msgstr ""
+msgid "Incident|Alert details"
+msgstr ""
+
+msgid "Incident|Summary"
+msgstr ""
+
+msgid "Incident|There was an issue loading alert data. Please try again."
+msgstr ""
+
msgid "Include a Terms of Service agreement and Privacy Policy that all users must accept."
msgstr ""
@@ -13174,6 +13577,9 @@ msgstr ""
msgid "Information about additional Pages templates and how to install them can be found in our %{pages_getting_started_guide}."
msgstr ""
+msgid "Inherited"
+msgstr ""
+
msgid "Inherited:"
msgstr ""
@@ -13253,7 +13659,22 @@ msgstr ""
msgid "Instance administrators group already exists"
msgstr ""
-msgid "Instance license"
+msgid "InstanceStatistics|Groups"
+msgstr ""
+
+msgid "InstanceStatistics|Issues"
+msgstr ""
+
+msgid "InstanceStatistics|Merge Requests"
+msgstr ""
+
+msgid "InstanceStatistics|Pipelines"
+msgstr ""
+
+msgid "InstanceStatistics|Projects"
+msgstr ""
+
+msgid "InstanceStatistics|Users"
msgstr ""
msgid "Integration"
@@ -13265,6 +13686,12 @@ msgstr ""
msgid "Integrations"
msgstr ""
+msgid "Integrations|%{integration} settings saved and active."
+msgstr ""
+
+msgid "Integrations|%{integration} settings saved, but not active."
+msgstr ""
+
msgid "Integrations|All details"
msgstr ""
@@ -13274,6 +13701,12 @@ msgstr ""
msgid "Integrations|Comment settings:"
msgstr ""
+msgid "Integrations|Connection failed. Please check your settings."
+msgstr ""
+
+msgid "Integrations|Connection successful."
+msgstr ""
+
msgid "Integrations|Default settings are inherited from the group level."
msgstr ""
@@ -13289,6 +13722,15 @@ msgstr ""
msgid "Integrations|Includes commit title and branch"
msgstr ""
+msgid "Integrations|Projects using custom settings will not be impacted unless the project owner chooses to use instance-level defaults."
+msgstr ""
+
+msgid "Integrations|Save settings?"
+msgstr ""
+
+msgid "Integrations|Saving will update the default settings for all projects that are not using custom settings."
+msgstr ""
+
msgid "Integrations|Standard"
msgstr ""
@@ -13421,6 +13863,9 @@ msgstr ""
msgid "Invitation"
msgstr ""
+msgid "Invitation declined"
+msgstr ""
+
msgid "Invite"
msgstr ""
@@ -13472,6 +13917,42 @@ 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|%{linkStart}Read more%{linkEnd} about role permissions"
+msgstr ""
+
+msgid "InviteMembersModal|Access expiration date (optional)"
+msgstr ""
+
+msgid "InviteMembersModal|Cancel"
+msgstr ""
+
+msgid "InviteMembersModal|Choose a role permission"
+msgstr ""
+
+msgid "InviteMembersModal|GitLab member or Email address"
+msgstr ""
+
+msgid "InviteMembersModal|Invite"
+msgstr ""
+
+msgid "InviteMembersModal|Invite team members"
+msgstr ""
+
+msgid "InviteMembersModal|Search for members to invite"
+msgstr ""
+
+msgid "InviteMembersModal|User not invited. Feature coming soon!"
+msgstr ""
+
+msgid "InviteMembersModal|Users were succesfully added"
+msgstr ""
+
+msgid "InviteMembersModal|You're inviting members to the %{group_name} group"
+msgstr ""
+
+msgid "InviteMembers|Invite team members"
+msgstr ""
+
msgid "Invited"
msgstr ""
@@ -13526,10 +14007,13 @@ msgstr ""
msgid "Issue cannot be found."
msgstr ""
+msgid "Issue created from vulnerability %{vulnerability_link}"
+msgstr ""
+
msgid "Issue events"
msgstr ""
-msgid "Issue first depoloyed to production"
+msgid "Issue first deployed to production"
msgstr ""
msgid "Issue label"
@@ -13607,6 +14091,9 @@ msgstr ""
msgid "IssueTracker|Custom issue tracker"
msgstr ""
+msgid "IssueTracker|EWM work items tracker"
+msgstr ""
+
msgid "IssueTracker|Redmine issue tracker"
msgstr ""
@@ -13673,6 +14160,9 @@ msgstr ""
msgid "It looks like you have some draft commits in this branch."
msgstr ""
+msgid "It may be several days before you see feature usage data."
+msgstr ""
+
msgid "It must have a header row and at least two columns: the first column is the issue title and the second column is the issue description. The separator is automatically detected."
msgstr ""
@@ -13955,13 +14445,13 @@ msgstr ""
msgid "Join Zoom meeting"
msgstr ""
-msgid "Jul"
+msgid "Joined %{time_ago}"
msgstr ""
-msgid "July"
+msgid "Jul"
msgstr ""
-msgid "Jump to first unresolved thread"
+msgid "July"
msgstr ""
msgid "Jump to next unresolved thread"
@@ -13997,6 +14487,9 @@ msgstr ""
msgid "Keyboard shortcuts"
msgstr ""
+msgid "KeyboardKey|Ctrl+"
+msgstr ""
+
msgid "Keys"
msgstr ""
@@ -14045,6 +14538,9 @@ msgstr ""
msgid "LDAP Synchronization"
msgstr ""
+msgid "LDAP group settings"
+msgstr ""
+
msgid "LDAP settings"
msgstr ""
@@ -14054,6 +14550,9 @@ msgstr ""
msgid "LDAP sync in progress. This could take a few minutes. Refresh the page to see the changes."
msgstr ""
+msgid "LDAP synchronizations"
+msgstr ""
+
msgid "LFS"
msgstr ""
@@ -14133,7 +14632,16 @@ msgid "Last %d day"
msgid_plural "Last %d days"
msgstr[0] ""
-msgid "Last %{days} days"
+msgid "Last 2 weeks"
+msgstr ""
+
+msgid "Last 30 days"
+msgstr ""
+
+msgid "Last 60 days"
+msgstr ""
+
+msgid "Last 90 days"
msgstr ""
msgid "Last Accessed On"
@@ -14211,6 +14719,9 @@ msgstr ""
msgid "Last used on:"
msgstr ""
+msgid "Last week"
+msgstr ""
+
msgid "LastCommit|authored"
msgstr ""
@@ -14226,6 +14737,9 @@ msgstr ""
msgid "Latest pipeline for the most recent commit on this branch"
msgstr ""
+msgid "Launch a ready-to-code development environment for your project."
+msgstr ""
+
msgid "Lead"
msgstr ""
@@ -14599,6 +15113,9 @@ msgstr ""
msgid "List of all merge commits"
msgstr ""
+msgid "List options"
+msgstr ""
+
msgid "List settings"
msgstr ""
@@ -14611,9 +15128,6 @@ msgstr ""
msgid "List your Bitbucket Server repositories"
msgstr ""
-msgid "Lists"
-msgstr ""
-
msgid "Live preview"
msgstr ""
@@ -14860,6 +15374,12 @@ msgstr ""
msgid "Mark as done"
msgstr ""
+msgid "Mark as draft"
+msgstr ""
+
+msgid "Mark as ready"
+msgstr ""
+
msgid "Mark as resolved"
msgstr ""
@@ -14881,6 +15401,24 @@ msgstr ""
msgid "Markdown is supported"
msgstr ""
+msgid "MarkdownEditor|Add a link (%{modifierKey}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add a link (%{modifier_key}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifierKey}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifier_key}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifierKey}I)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifier_key}I)"
+msgstr ""
+
msgid "Marked For Deletion At - %{deletion_time}"
msgstr ""
@@ -14965,7 +15503,25 @@ msgstr ""
msgid "Max access level"
msgstr ""
-msgid "Max seats used"
+msgid "Max role"
+msgstr ""
+
+msgid "Max size 15 MB"
+msgstr ""
+
+msgid "Maximum Conan package file size in bytes"
+msgstr ""
+
+msgid "Maximum Maven package file size in bytes"
+msgstr ""
+
+msgid "Maximum NPM package file size in bytes"
+msgstr ""
+
+msgid "Maximum NuGet package file size in bytes"
+msgstr ""
+
+msgid "Maximum PyPI package file size in bytes"
msgstr ""
msgid "Maximum Users:"
@@ -15097,6 +15653,18 @@ msgstr ""
msgid "Members with access to %{strong_start}%{group_name}%{strong_end}"
msgstr ""
+msgid "Members|%{time} by %{user}"
+msgstr ""
+
+msgid "Members|Expired"
+msgstr ""
+
+msgid "Members|No expiration set"
+msgstr ""
+
+msgid "Members|in %{time}"
+msgstr ""
+
msgid "Memory Usage"
msgstr ""
@@ -15283,9 +15851,6 @@ msgstr ""
msgid "MergeRequests|Thread will be unresolved"
msgstr ""
-msgid "MergeRequests|Toggle comments for this file"
-msgstr ""
-
msgid "MergeRequests|View file @ %{commitId}"
msgstr ""
@@ -15346,6 +15911,9 @@ msgstr ""
msgid "Merging immediately isn't recommended as it may negatively impact the existing merge train. Read the %{docsLinkStart}documentation%{docsLinkEnd} for more information."
msgstr ""
+msgid "Message"
+msgstr ""
+
msgid "Messages"
msgstr ""
@@ -15729,18 +16297,12 @@ msgid "Milestone"
msgid_plural "Milestones"
msgstr[0] ""
-msgid "Milestone does not support burnup charts"
-msgstr ""
-
msgid "Milestone lists not available with your current license"
msgstr ""
msgid "Milestone lists show all issues from the selected milestone."
msgstr ""
-msgid "Milestone must have a start and due date"
-msgstr ""
-
msgid "MilestoneSidebar|Closed:"
msgstr ""
@@ -16107,6 +16669,9 @@ msgstr ""
msgid "Namespace"
msgstr ""
+msgid "Namespace ID:"
+msgstr ""
+
msgid "Namespace is empty"
msgstr ""
@@ -16191,6 +16756,9 @@ msgstr ""
msgid "NetworkPolicies|Allow all outbound traffic from %{selector} to %{ruleSelector} on %{ports}"
msgstr ""
+msgid "NetworkPolicies|Are you sure you want to delete this policy? This action cannot be undone."
+msgstr ""
+
msgid "NetworkPolicies|Choose whether to enforce this policy."
msgstr ""
@@ -16200,12 +16768,21 @@ msgstr ""
msgid "NetworkPolicies|Define this policy's location, conditions and actions."
msgstr ""
+msgid "NetworkPolicies|Delete policy"
+msgstr ""
+
+msgid "NetworkPolicies|Delete policy: %{policy}"
+msgstr ""
+
msgid "NetworkPolicies|Deny all traffic"
msgstr ""
msgid "NetworkPolicies|Description"
msgstr ""
+msgid "NetworkPolicies|Edit policy"
+msgstr ""
+
msgid "NetworkPolicies|Editor mode"
msgstr ""
@@ -16233,6 +16810,9 @@ msgstr ""
msgid "NetworkPolicies|Name"
msgstr ""
+msgid "NetworkPolicies|Namespace"
+msgstr ""
+
msgid "NetworkPolicies|Network Policy"
msgstr ""
@@ -16284,6 +16864,9 @@ msgstr ""
msgid "NetworkPolicies|Rules"
msgstr ""
+msgid "NetworkPolicies|Save changes"
+msgstr ""
+
msgid "NetworkPolicies|Something went wrong, failed to update policy"
msgstr ""
@@ -16296,6 +16879,9 @@ msgstr ""
msgid "NetworkPolicies|Traffic that does not match any rule will be blocked."
msgstr ""
+msgid "NetworkPolicies|Unable to parse policy"
+msgstr ""
+
msgid "NetworkPolicies|YAML editor"
msgstr ""
@@ -16408,6 +16994,9 @@ msgstr ""
msgid "New Snippet"
msgstr ""
+msgid "New Test Case"
+msgstr ""
+
msgid "New User"
msgstr ""
@@ -16507,6 +17096,9 @@ msgstr ""
msgid "New tag"
msgstr ""
+msgid "New test case"
+msgstr ""
+
msgid "New users set to external"
msgstr ""
@@ -16579,7 +17171,7 @@ msgstr ""
msgid "No changes"
msgstr ""
-msgid "No changes between %{ref_start}%{source_branch}%{ref_end} and %{ref_start}%{target_branch}%{ref_end}"
+msgid "No changes between %{sourceBranch} and %{targetBranch}"
msgstr ""
msgid "No child epics match applied filters"
@@ -16594,6 +17186,9 @@ msgstr ""
msgid "No containers available"
msgstr ""
+msgid "No content to show"
+msgstr ""
+
msgid "No contributions"
msgstr ""
@@ -16669,9 +17264,6 @@ msgstr ""
msgid "No license. All rights reserved"
msgstr ""
-msgid "No licenses found."
-msgstr ""
-
msgid "No matches found"
msgstr ""
@@ -16684,6 +17276,9 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No members found"
+msgstr ""
+
msgid "No merge requests found"
msgstr ""
@@ -16705,6 +17300,9 @@ msgstr ""
msgid "No parent group"
msgstr ""
+msgid "No plan"
+msgstr ""
+
msgid "No pods available"
msgstr ""
@@ -16801,6 +17399,12 @@ msgstr ""
msgid "Not Implemented"
msgstr ""
+msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+msgstr ""
+
+msgid "Not all browsers support WebAuthn. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even from an unsupported browser."
+msgstr ""
+
msgid "Not all data has been processed yet, the accuracy of the chart for the selected timeframe is limited."
msgstr ""
@@ -16897,6 +17501,9 @@ msgstr ""
msgid "Notification settings saved"
msgstr ""
+msgid "NotificationEvent|Change reviewer merge request"
+msgstr ""
+
msgid "NotificationEvent|Close issue"
msgstr ""
@@ -17059,10 +17666,7 @@ msgstr ""
msgid "On track"
msgstr ""
-msgid "OnDemandScans|Attached branch"
-msgstr ""
-
-msgid "OnDemandScans|Attached branch is where the scan job runs."
+msgid "OnDemandScans|Could not fetch scanner profiles. Please refresh the page, or try again later."
msgstr ""
msgid "OnDemandScans|Could not fetch site profiles. Please refresh the page, or try again later."
@@ -17071,6 +17675,9 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
+msgid "OnDemandScans|Create a new scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Create a new site profile"
msgstr ""
@@ -17083,6 +17690,9 @@ msgstr ""
msgid "OnDemandScans|New on-demand DAST scan"
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 ""
@@ -17092,16 +17702,10 @@ msgstr ""
msgid "OnDemandScans|On-demand scans run outside the DevOps cycle and find vulnerabilities in your projects. %{learnMoreLinkStart}Learn more%{learnMoreLinkEnd}"
msgstr ""
-msgid "OnDemandScans|Only a passive scan can be performed on demand."
-msgstr ""
-
-msgid "OnDemandScans|Passive"
-msgstr ""
-
msgid "OnDemandScans|Run scan"
msgstr ""
-msgid "OnDemandScans|Scan mode"
+msgid "OnDemandScans|Scanner profile"
msgstr ""
msgid "OnDemandScans|Scanner settings"
@@ -17113,9 +17717,15 @@ msgstr ""
msgid "OnDemandScans|Select one of the existing profiles"
msgstr ""
+msgid "OnDemandScans|Site profile"
+msgstr ""
+
msgid "OnDemandScans|Site profiles"
msgstr ""
+msgid "OnDemandScans|Use existing scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Use existing site profile"
msgstr ""
@@ -17213,9 +17823,6 @@ msgstr ""
msgid "Open Selection"
msgstr ""
-msgid "Open Web IDE"
-msgstr ""
-
msgid "Open comment type dropdown"
msgstr ""
@@ -17321,6 +17928,9 @@ msgstr ""
msgid "Origin"
msgstr ""
+msgid "Orphaned member"
+msgstr ""
+
msgid "Other Labels"
msgstr ""
@@ -17336,6 +17946,9 @@ msgstr ""
msgid "Other visibility settings have been disabled by the administrator."
msgstr ""
+msgid "Our documentation includes an example DevOps Score report."
+msgstr ""
+
msgid "Out-of-compliance with this project's policies and should be removed"
msgstr ""
@@ -17360,6 +17973,9 @@ msgstr ""
msgid "Overwrite diverged branches"
msgstr ""
+msgid "Owned by %{image_tag}"
+msgstr ""
+
msgid "Owned by anyone"
msgstr ""
@@ -17381,6 +17997,9 @@ msgstr ""
msgid "Package deleted successfully"
msgstr ""
+msgid "Package file size limits"
+msgstr ""
+
msgid "Package recipe already exists"
msgstr ""
@@ -17396,9 +18015,6 @@ msgstr ""
msgid "Package type must be PyPi"
msgstr ""
-msgid "Package was removed"
-msgstr ""
-
msgid "PackageRegistry|%{name} version %{version} was created %{datetime}"
msgstr ""
@@ -17540,12 +18156,18 @@ msgstr ""
msgid "PackageRegistry|NuGet Command"
msgstr ""
+msgid "PackageRegistry|Package Registry"
+msgstr ""
+
msgid "PackageRegistry|Pip Command"
msgstr ""
msgid "PackageRegistry|Pipeline %{link} triggered %{datetime} by %{author}"
msgstr ""
+msgid "PackageRegistry|Publish and share packages for a variety of common package managers. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "PackageRegistry|Published to the %{project} Package Registry %{datetime}"
msgstr ""
@@ -17645,6 +18267,9 @@ msgstr ""
msgid "Page not found"
msgstr ""
+msgid "Page settings"
+msgstr ""
+
msgid "Page was successfully deleted"
msgstr ""
@@ -17786,7 +18411,7 @@ msgstr ""
msgid "Paste issue link"
msgstr ""
-msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Don't use your private SSH key."
+msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Do not paste your private SSH key, as that can compromise your identity."
msgstr ""
msgid "Patch to apply"
@@ -17813,6 +18438,9 @@ msgstr ""
msgid "Pending"
msgstr ""
+msgid "Pending comments"
+msgstr ""
+
msgid "People without permission will never get a notification and won't be able to comment."
msgstr ""
@@ -18011,6 +18639,9 @@ msgstr ""
msgid "Pipelines|Build with confidence"
msgstr ""
+msgid "Pipelines|By revoking a trigger you will break any processes making use of it. Are you sure?"
+msgstr ""
+
msgid "Pipelines|CI Lint"
msgstr ""
@@ -18023,6 +18654,15 @@ msgstr ""
msgid "Pipelines|Continuous Integration can help catch bugs by running your tests automatically, while Continuous Deployment can help you deliver code to your product environment."
msgstr ""
+msgid "Pipelines|Copy trigger token"
+msgstr ""
+
+msgid "Pipelines|Description"
+msgstr ""
+
+msgid "Pipelines|Edit"
+msgstr ""
+
msgid "Pipelines|Get started with Pipelines"
msgstr ""
@@ -18038,15 +18678,27 @@ msgstr ""
msgid "Pipelines|It is recommended the code is reviewed thoroughly before running this pipeline with the parent project's CI resource."
msgstr ""
+msgid "Pipelines|Last Used"
+msgstr ""
+
msgid "Pipelines|Loading Pipelines"
msgstr ""
msgid "Pipelines|More Information"
msgstr ""
+msgid "Pipelines|No triggers have been created yet. Add one using the form above."
+msgstr ""
+
+msgid "Pipelines|Owner"
+msgstr ""
+
msgid "Pipelines|Project cache successfully reset."
msgstr ""
+msgid "Pipelines|Revoke"
+msgstr ""
+
msgid "Pipelines|Run Pipeline"
msgstr ""
@@ -18071,6 +18723,15 @@ msgstr ""
msgid "Pipelines|This project is not currently set up to run pipelines."
msgstr ""
+msgid "Pipelines|Token"
+msgstr ""
+
+msgid "Pipelines|Trigger user has insufficient permissions to project"
+msgstr ""
+
+msgid "Pipelines|invalid"
+msgstr ""
+
msgid "Pipelines|parent"
msgstr ""
@@ -18329,10 +18990,10 @@ msgstr ""
msgid "Please provide attributes to update"
msgstr ""
-msgid "Please refer to %{docs_url}"
+msgid "Please reach out if you have any questions and we'll be happy to assist."
msgstr ""
-msgid "Please retype the email address."
+msgid "Please refer to %{docs_url}"
msgstr ""
msgid "Please select"
@@ -18362,6 +19023,9 @@ msgstr ""
msgid "Please set a new password before proceeding."
msgstr ""
+msgid "Please share your feedback about %{featureName} %{linkStart}in this issue%{linkEnd} to help us improve the experience."
+msgstr ""
+
msgid "Please solve the reCAPTCHA"
msgstr ""
@@ -18665,6 +19329,9 @@ msgstr ""
msgid "Profiles| You are going to change the username %{currentUsernameBold} to %{newUsernameBold}. Profile and projects will be redirected to the %{newUsername} namespace but this redirect will expire once the %{currentUsername} namespace is registered by another user or group. Please update your Git repository remotes as soon as possible."
msgstr ""
+msgid "Profiles|%{provider} Active"
+msgstr ""
+
msgid "Profiles|@username"
msgstr ""
@@ -18716,7 +19383,7 @@ msgstr ""
msgid "Profiles|Commit email"
msgstr ""
-msgid "Profiles|Connect"
+msgid "Profiles|Connect %{provider}"
msgstr ""
msgid "Profiles|Connected Accounts"
@@ -18740,6 +19407,9 @@ msgstr ""
msgid "Profiles|Disconnect"
msgstr ""
+msgid "Profiles|Disconnect %{provider}"
+msgstr ""
+
msgid "Profiles|Do not show on profile"
msgstr ""
@@ -18764,7 +19434,7 @@ msgstr ""
msgid "Profiles|Full name"
msgstr ""
-msgid "Profiles|Give your individual key a title. This will be publically visible."
+msgid "Profiles|Give your individual key a title."
msgstr ""
msgid "Profiles|Include private contributions on my profile"
@@ -18854,7 +19524,7 @@ msgstr ""
msgid "Profiles|The maximum file size allowed is 200KB."
msgstr ""
-msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it?"
+msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it? It will be publicly visible."
msgstr ""
msgid "Profiles|This email will be displayed on your public profile"
@@ -18929,6 +19599,9 @@ msgstr ""
msgid "Profiles|You don't have access to delete this user."
msgstr ""
+msgid "Profiles|You must transfer ownership or delete groups you are an owner of before you can delete your account"
+msgstr ""
+
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
@@ -19517,6 +20190,9 @@ msgstr ""
msgid "ProjectTemplates|GitLab Cluster Management"
msgstr ""
+msgid "ProjectTemplates|Gitpod/Spring Petclinic"
+msgstr ""
+
msgid "ProjectTemplates|Go Micro"
msgstr ""
@@ -20126,6 +20802,9 @@ msgstr ""
msgid "Publish to status page"
msgstr ""
+msgid "Published"
+msgstr ""
+
msgid "Published on status page"
msgstr ""
@@ -20243,9 +20922,15 @@ msgstr ""
msgid "Quick range"
msgstr ""
+msgid "Quickly and easily edit multiple files in your project."
+msgstr ""
+
msgid "README"
msgstr ""
+msgid "Rails"
+msgstr ""
+
msgid "Rake Tasks Help"
msgstr ""
@@ -20364,10 +21049,13 @@ msgstr ""
msgid "Register Two-Factor Authenticator"
msgstr ""
-msgid "Register U2F device"
+msgid "Register Universal Two-Factor (U2F) Device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register WebAuthn Device"
+msgstr ""
+
+msgid "Register device"
msgstr ""
msgid "Register for GitLab"
@@ -20379,9 +21067,6 @@ msgstr ""
msgid "Register with two-factor app"
msgstr ""
-msgid "Registration"
-msgstr ""
-
msgid "Registration|Checkout"
msgstr ""
@@ -20497,9 +21182,6 @@ msgstr ""
msgid "Release|Something went wrong while saving the release details"
msgstr ""
-msgid "Remediated: needs review"
-msgstr ""
-
msgid "Remediations"
msgstr ""
@@ -20605,6 +21287,9 @@ msgstr ""
msgid "Remove priority"
msgstr ""
+msgid "Remove report"
+msgstr ""
+
msgid "Remove secondary node"
msgstr ""
@@ -20617,6 +21302,12 @@ msgstr ""
msgid "Remove time estimate"
msgstr ""
+msgid "Remove user & report"
+msgstr ""
+
+msgid "Remove user from group"
+msgstr ""
+
msgid "Removed"
msgstr ""
@@ -20698,9 +21389,6 @@ msgstr ""
msgid "Removes time estimate."
msgstr ""
-msgid "Removing license…"
-msgstr ""
-
msgid "Removing this group also removes all child projects, including archived projects, and their resources."
msgstr ""
@@ -20785,6 +21473,9 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
+msgid "Reported by %{reporter}"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -20870,6 +21561,27 @@ msgstr ""
msgid "Repositories"
msgstr ""
+msgid "Repositories Analytics"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download Historic Test Coverage Data"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download historic test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Historic Test Coverage Data is available in raw format (.csv) for further analysis."
+msgstr ""
+
+msgid "RepositoriesAnalytics|Test Code Coverage"
+msgstr ""
+
+msgid "RepositoriesAnalytics|There was an error fetching the projects."
+msgstr ""
+
msgid "Repository"
msgstr ""
@@ -20948,9 +21660,15 @@ msgstr ""
msgid "Request parameter %{param} is missing."
msgstr ""
+msgid "Request review from"
+msgstr ""
+
msgid "Request to link SAML account must be authorized"
msgstr ""
+msgid "Requested"
+msgstr ""
+
msgid "Requested %{time_ago}"
msgstr ""
@@ -20969,6 +21687,9 @@ msgstr ""
msgid "Requests to these domain(s)/address(es) on the local network will be allowed when local requests from hooks and services are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 or 127.0.0.0/28 are supported. Domain wildcards are not supported currently. Use comma, semicolon, or newline to separate multiple entries. The allowlist can hold a maximum of 1000 entries. Domains should use IDNA encoding. Ex: example.com, 192.168.1.1, 127.0.0.0/28, xn--itlab-j1a.com."
msgstr ""
+msgid "Require admin approval for new sign-ups"
+msgstr ""
+
msgid "Require all users in this group to setup Two-factor authentication"
msgstr ""
@@ -21094,9 +21815,6 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
-msgid "Resolved by %{resolvedByName}"
-msgstr ""
-
msgid "Resolves IP addresses once and uses them to submit requests"
msgstr ""
@@ -21215,6 +21933,13 @@ msgstr ""
msgid "ReviewApp|Enable Review App"
msgstr ""
+msgid "Reviewer"
+msgid_plural "%d Reviewers"
+msgstr[0] ""
+
+msgid "Reviewer(s)"
+msgstr ""
+
msgid "Reviewing"
msgstr ""
@@ -21254,6 +21979,9 @@ msgstr ""
msgid "Rook"
msgstr ""
+msgid "Ruby"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -21332,6 +22060,63 @@ msgstr ""
msgid "Runners page."
msgstr ""
+msgid "Runners|Active"
+msgstr ""
+
+msgid "Runners|Architecture"
+msgstr ""
+
+msgid "Runners|Can run untagged jobs"
+msgstr ""
+
+msgid "Runners|Description"
+msgstr ""
+
+msgid "Runners|Group"
+msgstr ""
+
+msgid "Runners|IP Address"
+msgstr ""
+
+msgid "Runners|Last contact"
+msgstr ""
+
+msgid "Runners|Locked to this project"
+msgstr ""
+
+msgid "Runners|Maximum job timeout"
+msgstr ""
+
+msgid "Runners|Name"
+msgstr ""
+
+msgid "Runners|Platform"
+msgstr ""
+
+msgid "Runners|Property Name"
+msgstr ""
+
+msgid "Runners|Protected"
+msgstr ""
+
+msgid "Runners|Revision"
+msgstr ""
+
+msgid "Runners|Shared"
+msgstr ""
+
+msgid "Runners|Specific"
+msgstr ""
+
+msgid "Runners|Tags"
+msgstr ""
+
+msgid "Runners|Value"
+msgstr ""
+
+msgid "Runners|Version"
+msgstr ""
+
msgid "Runners|You have used %{quotaUsed} out of %{quotaLimit} of your shared Runners pipeline minutes."
msgstr ""
@@ -21344,6 +22129,9 @@ msgstr ""
msgid "Runs a number of housekeeping tasks within the current repository, such as compressing file revisions and removing unreachable objects."
msgstr ""
+msgid "SAML"
+msgstr ""
+
msgid "SAML SSO"
msgstr ""
@@ -21395,6 +22183,9 @@ msgstr ""
msgid "Save"
msgstr ""
+msgid "Save %{name} size limits"
+msgstr ""
+
msgid "Save Changes"
msgstr ""
@@ -21425,9 +22216,6 @@ msgstr ""
msgid "Save space and find tags in the Container Registry more easily. Enable the cleanup policy to remove stale tags and keep only the ones you need."
msgstr ""
-msgid "Save template"
-msgstr ""
-
msgid "Save variables"
msgstr ""
@@ -21470,9 +22258,6 @@ msgstr ""
msgid "Scope"
msgstr ""
-msgid "Scope not supported with disabled 'users_search' feature!"
-msgstr ""
-
msgid "Scoped issue boards"
msgstr ""
@@ -21599,9 +22384,6 @@ msgstr ""
msgid "Search requirements"
msgstr ""
-msgid "Search results…"
-msgstr ""
-
msgid "Search users"
msgstr ""
@@ -21671,6 +22453,10 @@ msgid "SearchResults|commit"
msgid_plural "SearchResults|commits"
msgstr[0] ""
+msgid "SearchResults|epic"
+msgid_plural "SearchResults|epics"
+msgstr[0] ""
+
msgid "SearchResults|issue"
msgid_plural "SearchResults|issues"
msgstr[0] ""
@@ -21708,10 +22494,10 @@ msgstr ""
msgid "Seat Link is disabled, and cannot be configured through this form."
msgstr ""
-msgid "Seats currently in use"
+msgid "Seats usage data as of %{last_enqueue_time}"
msgstr ""
-msgid "Seats in license"
+msgid "Seats usage data is updated every day at 12:00pm UTC"
msgstr ""
msgid "Secondary"
@@ -21765,6 +22551,9 @@ msgstr ""
msgid "SecurityConfiguration|Available for on-demand DAST"
msgstr ""
+msgid "SecurityConfiguration|By default, all analyzers are applied in order to cover all languages across your project, and only run if the language is detected in the Merge Request."
+msgstr ""
+
msgid "SecurityConfiguration|Configure"
msgstr ""
@@ -21795,16 +22584,19 @@ msgstr ""
msgid "SecurityConfiguration|Manage"
msgstr ""
+msgid "SecurityConfiguration|More information"
+msgstr ""
+
msgid "SecurityConfiguration|Not enabled"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|Security Control"
+msgid "SecurityConfiguration|SAST Configuration"
msgstr ""
-msgid "SecurityConfiguration|See documentation"
+msgid "SecurityConfiguration|Security Control"
msgstr ""
msgid "SecurityConfiguration|Status"
@@ -21816,6 +22608,9 @@ msgstr ""
msgid "SecurityConfiguration|Using custom settings. You won't receive automatic updates on this variable. %{anchorStart}Restore to default%{anchorEnd}"
msgstr ""
+msgid "SecurityConfiguration|View history"
+msgstr ""
+
msgid "SecurityConfiguration|You can quickly enable all security scanning tools by enabling %{linkStart}Auto DevOps%{linkEnd}."
msgstr ""
@@ -21894,9 +22689,6 @@ msgstr ""
msgid "SecurityReports|Learn more about setting up your dashboard"
msgstr ""
-msgid "SecurityReports|Load more vulnerabilities"
-msgstr ""
-
msgid "SecurityReports|Monitor vulnerabilities in your code"
msgstr ""
@@ -22176,7 +22968,7 @@ msgstr ""
msgid "Select status"
msgstr ""
-msgid "Select strategy activation method"
+msgid "Select strategy activation method."
msgstr ""
msgid "Select subscription"
@@ -22191,7 +22983,7 @@ msgstr ""
msgid "Select the custom project template source group."
msgstr ""
-msgid "Select timeframe"
+msgid "Select the environment scope for this feature flag."
msgstr ""
msgid "Select timezone"
@@ -22440,6 +23232,9 @@ msgstr ""
msgid "Set iteration"
msgstr ""
+msgid "Set limit to 0 to allow any file size."
+msgstr ""
+
msgid "Set max session time for web terminal."
msgstr ""
@@ -22518,10 +23313,13 @@ msgstr ""
msgid "Set up a %{type} Runner manually"
msgstr ""
+msgid "Set up a hardware device as a second factor to sign in."
+msgstr ""
+
msgid "Set up assertions/attributes/claims (email, first_name, last_name) and NameID according to %{docsLinkStart}the documentation %{icon}%{docsLinkEnd}"
msgstr ""
-msgid "Set up new U2F device"
+msgid "Set up new device"
msgstr ""
msgid "Set up new password"
@@ -22590,6 +23388,9 @@ msgstr ""
msgid "Sets weight to %{weight}."
msgstr ""
+msgid "Setting this to 0 means using the system default timeout value."
+msgstr ""
+
msgid "Settings"
msgstr ""
@@ -22605,6 +23406,15 @@ msgstr ""
msgid "Severity"
msgstr ""
+msgid "SeverityWidget|Severity"
+msgstr ""
+
+msgid "SeverityWidget|Severity: %{severity}"
+msgstr ""
+
+msgid "SeverityWidget|There was an error while updating severity."
+msgstr ""
+
msgid "Shards (%{shards})"
msgstr ""
@@ -22650,6 +23460,9 @@ msgstr ""
msgid "Show all requirements."
msgstr ""
+msgid "Show all test cases."
+msgstr ""
+
msgid "Show archived projects"
msgstr ""
@@ -22662,6 +23475,9 @@ msgstr ""
msgid "Show comments"
msgstr ""
+msgid "Show comments on this file"
+msgstr ""
+
msgid "Show comments only"
msgstr ""
@@ -22707,6 +23523,12 @@ msgstr ""
msgid "Show parent subgroups"
msgstr ""
+msgid "Show the Closed list"
+msgstr ""
+
+msgid "Show the Open list"
+msgstr ""
+
msgid "Show whitespace changes"
msgstr ""
@@ -22748,9 +23570,6 @@ msgstr ""
msgid "Sidebar|Assign health status"
msgstr ""
-msgid "Sidebar|Change weight"
-msgstr ""
-
msgid "Sidebar|Health status"
msgstr ""
@@ -22934,6 +23753,9 @@ msgstr ""
msgid "Snippets|Add another file %{num}/%{total}"
msgstr ""
+msgid "Snippets|Authored %{time_ago} by %{author}"
+msgstr ""
+
msgid "Snippets|Delete file"
msgstr ""
@@ -22961,6 +23783,9 @@ msgstr ""
msgid "Solution"
msgstr ""
+msgid "Some changes are not shown"
+msgstr ""
+
msgid "Some child epics may be hidden due to applied filters"
msgstr ""
@@ -23327,6 +24152,12 @@ msgstr ""
msgid "Source (branch or tag)"
msgstr ""
+msgid "Source Branch"
+msgstr ""
+
+msgid "Source branch: %{source_branch_open}%{source_branch}%{source_branch_close}"
+msgstr ""
+
msgid "Source code"
msgstr ""
@@ -23492,9 +24323,6 @@ msgstr ""
msgid "Start and due date"
msgstr ""
-msgid "Start by choosing a group to see how your team is spending time. You can then drill down to the project level."
-msgstr ""
-
msgid "Start by choosing a group to start exploring the merge requests in that group. You can then proceed to filter by projects, labels, milestones and authors."
msgstr ""
@@ -23576,18 +24404,27 @@ msgstr ""
msgid "StaticSiteEditor|3. Assign a person to review and accept the merge request."
msgstr ""
+msgid "StaticSiteEditor|A link to view the merge request will appear once ready."
+msgstr ""
+
msgid "StaticSiteEditor|An error occurred while submitting your changes."
msgstr ""
msgid "StaticSiteEditor|Branch could not be created."
msgstr ""
+msgid "StaticSiteEditor|Copy update"
+msgstr ""
+
msgid "StaticSiteEditor|Could not commit the content changes."
msgstr ""
msgid "StaticSiteEditor|Could not create merge request."
msgstr ""
+msgid "StaticSiteEditor|Creating your merge request"
+msgstr ""
+
msgid "StaticSiteEditor|Incompatible file content"
msgstr ""
@@ -23609,6 +24446,9 @@ msgstr ""
msgid "StaticSiteEditor|View documentation"
msgstr ""
+msgid "StaticSiteEditor|You can set an assignee to get your changes reviewed and deployed once your merge request is created."
+msgstr ""
+
msgid "StaticSiteEditor|Your merge request has been created"
msgstr ""
@@ -23738,15 +24578,15 @@ msgstr ""
msgid "Submit %{humanized_resource_name}"
msgstr ""
-msgid "Submit Changes"
-msgstr ""
-
msgid "Submit a review"
msgstr ""
msgid "Submit as spam"
msgstr ""
+msgid "Submit changes"
+msgstr ""
+
msgid "Submit feedback"
msgstr ""
@@ -23900,6 +24740,9 @@ msgstr ""
msgid "Successfully deleted U2F device."
msgstr ""
+msgid "Successfully deleted WebAuthn device."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -24218,9 +25061,6 @@ msgstr ""
msgid "Template to append to all Service Desk issues"
msgstr ""
-msgid "Template was successfully saved."
-msgstr ""
-
msgid "Templates"
msgstr ""
@@ -24296,10 +25136,28 @@ msgid "Test coverage: %d hit"
msgid_plural "Test coverage: %d hits"
msgstr[0] ""
-msgid "Test failed."
+msgid "Test settings"
+msgstr ""
+
+msgid "TestCases|New Test Case"
+msgstr ""
+
+msgid "TestCases|New test case"
+msgstr ""
+
+msgid "TestCases|Search test cases"
+msgstr ""
+
+msgid "TestCases|Something went wrong while creating a test case."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching count of test cases."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching test cases list."
msgstr ""
-msgid "Test settings and save changes"
+msgid "TestCases|Submit test case"
msgstr ""
msgid "TestHooks|Ensure one of your projects has merge requests."
@@ -24365,6 +25223,9 @@ msgstr ""
msgid "Thank you for signing up for your free trial! You will get additional instructions in your inbox shortly."
msgstr ""
+msgid "Thank you for your business."
+msgstr ""
+
msgid "Thank you for your feedback!"
msgstr ""
@@ -24423,9 +25284,6 @@ msgstr ""
msgid "The URL to use for connecting to Elasticsearch. Use a comma-separated list to support clustering (e.g., \"http://localhost:9200, http://localhost:9201\")."
msgstr ""
-msgid "The Web IDE offers advanced syntax highlighting capabilities and more."
-msgstr ""
-
msgid "The X509 Certificate to use when mutual TLS is required to communicate with the external authorization service. If left blank, the server certificate is still validated when accessing over HTTPS."
msgstr ""
@@ -24535,6 +25393,9 @@ msgstr ""
msgid "The form contains the following error:"
msgstr ""
+msgid "The form contains the following warning:"
+msgstr ""
+
msgid "The global settings require you to enable Two-Factor Authentication for your account."
msgstr ""
@@ -24649,9 +25510,6 @@ msgstr ""
msgid "The private key to use when a client certificate is provided. This value is encrypted at rest."
msgstr ""
-msgid "The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The project can be accessed by any logged in user."
msgstr ""
@@ -24688,7 +25546,7 @@ msgstr ""
msgid "The remote repository is being updated..."
msgstr ""
-msgid "The repository can be commited to, and issues, comments and other entities can be created."
+msgid "The repository can be committed to, and issues, comments and other entities can be created."
msgstr ""
msgid "The repository for this project does not exist."
@@ -24742,9 +25600,6 @@ msgstr ""
msgid "The time taken by each data entry gathered by that stage."
msgstr ""
-msgid "The total stage shows the time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The update action will time out after %{number_of_minutes} minutes. For big repositories, use a clone/push combination."
msgstr ""
@@ -24808,6 +25663,9 @@ msgstr ""
msgid "There are no archived requirements"
msgstr ""
+msgid "There are no archived test cases"
+msgstr ""
+
msgid "There are no changes"
msgstr ""
@@ -24847,6 +25705,9 @@ msgstr ""
msgid "There are no open requirements"
msgstr ""
+msgid "There are no open test cases"
+msgstr ""
+
msgid "There are no packages yet"
msgstr ""
@@ -24859,6 +25720,9 @@ msgstr ""
msgid "There is a limit of %{ci_project_subscriptions_limit} subscriptions from or to a project."
msgstr ""
+msgid "There is already a To-Do for this design."
+msgstr ""
+
msgid "There is already a repository with that name on disk"
msgstr ""
@@ -24877,6 +25741,9 @@ msgstr ""
msgid "There was a problem communicating with your device."
msgstr ""
+msgid "There was a problem fetching branches."
+msgstr ""
+
msgid "There was a problem fetching groups."
msgstr ""
@@ -25105,9 +25972,15 @@ msgstr ""
msgid "This action can lead to data loss. To prevent accidental actions we ask you to confirm your intention."
msgstr ""
+msgid "This action cannot be undone, and will permanently delete the %{key} SSH key"
+msgstr ""
+
msgid "This action cannot be undone. You will lose the project's repository and all content: issues, merge requests, etc."
msgstr ""
+msgid "This action has been performed too many times. Try again later."
+msgstr ""
+
msgid "This action will %{strongOpen}permanently delete%{strongClose} %{codeOpen}%{project}%{codeClose} %{strongOpen}immediately%{strongClose}, including its repositories and all content: issues, merge requests, etc."
msgstr ""
@@ -25135,9 +26008,6 @@ msgstr ""
msgid "This board's scope is reduced"
msgstr ""
-msgid "This branch has changed since you started editing. Would you like to create a new branch?"
-msgstr ""
-
msgid "This chart could not be displayed"
msgstr ""
@@ -25264,15 +26134,9 @@ msgstr ""
msgid "This is a security log of important events involving your account."
msgstr ""
-msgid "This is the author's first Merge Request to this project."
-msgstr ""
-
msgid "This is the highest peak of users on your installation since the license started."
msgstr ""
-msgid "This is the maximum number of users that have existed at the same time since the license started. This is the minimum number of seats you will need to buy when you renew your license."
-msgstr ""
-
msgid "This is the number of currently active users on your installation, and this is the minimum number you need to purchase when you renew your license."
msgstr ""
@@ -25504,6 +26368,15 @@ msgstr ""
msgid "This user has no identities"
msgstr ""
+msgid "This user has previously committed to the %{name} project."
+msgstr ""
+
+msgid "This user has the %{access} role in the %{name} project."
+msgstr ""
+
+msgid "This user is the author of this %{noteable}."
+msgstr ""
+
msgid "This user will be the author of all events in the activity feed that are the result of an update, like new branches being created or new commits being pushed to existing branches."
msgstr ""
@@ -25534,6 +26407,9 @@ msgstr ""
msgid "Threat Monitoring"
msgstr ""
+msgid "ThreatMonitoring|All Environments"
+msgstr ""
+
msgid "ThreatMonitoring|Anomalous Requests"
msgstr ""
@@ -25561,9 +26437,6 @@ msgstr ""
msgid "ThreatMonitoring|Operations Per Second"
msgstr ""
-msgid "ThreatMonitoring|Overview"
-msgstr ""
-
msgid "ThreatMonitoring|Packet Activity"
msgstr ""
@@ -25582,6 +26455,9 @@ msgstr ""
msgid "ThreatMonitoring|Something went wrong, unable to fetch statistics"
msgstr ""
+msgid "ThreatMonitoring|Statistics"
+msgstr ""
+
msgid "ThreatMonitoring|The firewall is not installed or has been disabled. To view this data, ensure the web application firewall is installed and enabled for your cluster."
msgstr ""
@@ -25971,6 +26847,9 @@ msgstr ""
msgid "To update Snippets with multiple files, you must use the `files` parameter"
msgstr ""
+msgid "To use Gitpod you must first enable the feature in the integrations section of your %{user_prefs}."
+msgstr ""
+
msgid "To view all %{scannedResourcesCount} scanned URLs, please download the CSV file"
msgstr ""
@@ -26004,9 +26883,6 @@ msgstr ""
msgid "Toggle Sidebar"
msgstr ""
-msgid "Toggle all threads"
-msgstr ""
-
msgid "Toggle backtrace"
msgstr ""
@@ -26031,9 +26907,6 @@ msgstr ""
msgid "Toggle navigation"
msgstr ""
-msgid "Toggle project"
-msgstr ""
-
msgid "Toggle sidebar"
msgstr ""
@@ -26073,6 +26946,9 @@ msgstr ""
msgid "Too many projects enabled. You will need to manage them via the console or the API."
msgstr ""
+msgid "Too much data"
+msgstr ""
+
msgid "Topics (optional)"
msgstr ""
@@ -26091,6 +26967,9 @@ msgstr ""
msgid "Total cores (CPUs)"
msgstr ""
+msgid "Total days to completion"
+msgstr ""
+
msgid "Total issues"
msgstr ""
@@ -26187,6 +27066,9 @@ msgstr ""
msgid "Trending"
msgstr ""
+msgid "Trials|Create a new group to start your GitLab Gold trial."
+msgstr ""
+
msgid "Trials|Go back to GitLab"
msgstr ""
@@ -26196,6 +27078,15 @@ msgstr ""
msgid "Trials|You can always resume this process by selecting your avatar and choosing 'Start a Gold trial'"
msgstr ""
+msgid "Trials|You can apply your trial to a new group or an existing group."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group or your personal account."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group, an existing group, or your personal account."
+msgstr ""
+
msgid "Trials|You won't get a free trial right now but you can always resume this process by clicking on your avatar and choosing 'Start a free trial'"
msgstr ""
@@ -26265,6 +27156,9 @@ msgstr ""
msgid "Try using a different search term to find the file you are looking for."
msgstr ""
+msgid "Trying to communicate with your device. Plug it in (if needed) and press the button on the device now."
+msgstr ""
+
msgid "Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now."
msgstr ""
@@ -26352,6 +27246,12 @@ msgstr ""
msgid "URL or request ID"
msgstr ""
+msgid "USER %{user} WILL BE REMOVED! Are you sure?"
+msgstr ""
+
+msgid "USER WILL BE BLOCKED! Are you sure?"
+msgstr ""
+
msgid "UTC"
msgstr ""
@@ -26409,9 +27309,6 @@ msgstr ""
msgid "Unable to load the merge request widget. Try reloading the page."
msgstr ""
-msgid "Unable to resolve"
-msgstr ""
-
msgid "Unable to save iteration. Please try again"
msgstr ""
@@ -26460,6 +27357,9 @@ msgstr ""
msgid "Undo ignore"
msgstr ""
+msgid "Unexpected error"
+msgstr ""
+
msgid "Unfortunately, your email message to GitLab could not be processed."
msgstr ""
@@ -26493,6 +27393,9 @@ msgstr ""
msgid "Unknown response text"
msgstr ""
+msgid "Unless otherwise agreed to in writing with GitLab, by clicking \"Upload License\" you agree that your use of GitLab Software is subject to the %{eula_link_start}Terms of Service%{eula_link_end}."
+msgstr ""
+
msgid "Unlimited"
msgstr ""
@@ -26859,9 +27762,6 @@ msgstr ""
msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
msgstr ""
-msgid "Use a hardware device to add the second factor of authentication."
-msgstr ""
-
msgid "Use an one time password authenticator on your mobile device or computer to enable two-factor authentication (2FA)."
msgstr ""
@@ -27135,13 +28035,13 @@ msgstr ""
msgid "Users"
msgstr ""
-msgid "Users in License:"
+msgid "Users in License"
msgstr ""
-msgid "Users or groups set as approvers in the project's or merge request's settings."
+msgid "Users in License:"
msgstr ""
-msgid "Users outside of license"
+msgid "Users or groups set as approvers in the project's or merge request's settings."
msgstr ""
msgid "Users over License:"
@@ -27159,9 +28059,6 @@ msgstr ""
msgid "Users with a Guest role or those who don't belong to a Project or Group will not use a seat from your license."
msgstr ""
-msgid "Users with a Guest role or those who don't belong to any projects or groups don't count towards seats in use."
-msgstr ""
-
msgid "UsersSelect|%{name} + %{length} more"
msgstr ""
@@ -27201,9 +28098,6 @@ msgstr ""
msgid "Validations failed."
msgstr ""
-msgid "Validity"
-msgstr ""
-
msgid "Value"
msgstr ""
@@ -27222,6 +28116,9 @@ msgstr ""
msgid "Value Stream Name"
msgstr ""
+msgid "ValueStreamAnalyticsStage|We don't have enough data to show this stage."
+msgstr ""
+
msgid "ValueStreamAnalytics|%{days}d"
msgstr ""
@@ -27476,6 +28373,9 @@ msgstr ""
msgid "VisualReviewApp|Steps 1 and 2 (and sometimes 3) are performed once by the developer before requesting feedback. Steps 3 (if necessary), 4 is performed by the reviewer each time they perform a review."
msgstr ""
+msgid "Visualization"
+msgstr ""
+
msgid "Vulnerabilities"
msgstr ""
@@ -27503,34 +28403,31 @@ msgstr ""
msgid "VulnerabilityChart|Severity"
msgstr ""
-msgid "VulnerabilityManagement|A true-positive and will fix"
-msgstr ""
-
-msgid "VulnerabilityManagement|Change status"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Confirm"
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|Confirmed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Detected %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|A true-positive and will fix"
msgstr ""
-msgid "VulnerabilityManagement|Dismiss"
+msgid "VulnerabilityManagement|Change status"
msgstr ""
-msgid "VulnerabilityManagement|Dismissed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
msgstr ""
-msgid "VulnerabilityManagement|Resolved"
+msgid "VulnerabilityManagement|Detected"
msgstr ""
-msgid "VulnerabilityManagement|Resolved %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Needs triage"
msgstr ""
msgid "VulnerabilityManagement|Something went wrong while trying to delete the comment. Please try again later."
@@ -27581,6 +28478,9 @@ msgstr ""
msgid "Vulnerability|%{scannerName} (version %{scannerVersion})"
msgstr ""
+msgid "Vulnerability|Activity"
+msgstr ""
+
msgid "Vulnerability|Class"
msgstr ""
@@ -27593,6 +28493,9 @@ msgstr ""
msgid "Vulnerability|Description"
msgstr ""
+msgid "Vulnerability|Detected"
+msgstr ""
+
msgid "Vulnerability|Evidence"
msgstr ""
@@ -27656,6 +28559,9 @@ msgstr ""
msgid "Warning: Displaying this diagram might cause performance issues on this page."
msgstr ""
+msgid "We are currently unable to fetch data for the pipeline header."
+msgstr ""
+
msgid "We are currently unable to fetch data for this graph."
msgstr ""
@@ -27695,6 +28601,12 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
+msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
+msgstr ""
+
+msgid "We would like to inform you that your subscription GitLab Enterprise Edition %{plan_name} is nearing its user limit. You have %{active_user_count} active users, which is almost at the user limit of %{maximum_user_count}."
+msgstr ""
+
msgid "We've found no vulnerabilities"
msgstr ""
@@ -27710,6 +28622,12 @@ msgstr ""
msgid "Web terminal"
msgstr ""
+msgid "WebAuthn Devices (%{length})"
+msgstr ""
+
+msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
+msgstr ""
+
msgid "WebIDE|Merge request"
msgstr ""
@@ -27848,15 +28766,9 @@ msgstr ""
msgid "Welcome to the guided GitLab tour"
msgstr ""
-msgid "Welcome to your Issue Board!"
-msgstr ""
-
msgid "Welcome to your issue board!"
msgstr ""
-msgid "We’ve been making changes to %{featureName} and we’d love your feedback %{linkStart}in this issue%{linkEnd} to help us improve the experience."
-msgstr ""
-
msgid "What are you searching for?"
msgstr ""
@@ -27875,6 +28787,9 @@ msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
msgstr ""
+msgid "When enabled, any user visiting %{host} and creating an account will have to be explicitly approved by the admin before they can login. This setting is effective only if sign-ups are enabled."
+msgstr ""
+
msgid "When enabled, any user visiting %{host} will be able to create an account."
msgstr ""
@@ -28098,6 +29013,9 @@ msgstr ""
msgid "With requirements, you can set criteria to check your products against."
msgstr ""
+msgid "With test cases, you can define conditions for your project to meet in determining quality"
+msgstr ""
+
msgid "Withdraw Access Request"
msgstr ""
@@ -28113,6 +29031,9 @@ msgstr ""
msgid "Workflow Help"
msgstr ""
+msgid "Would you like to create a new branch?"
+msgstr ""
+
msgid "Write"
msgstr ""
@@ -28134,6 +29055,9 @@ msgstr ""
msgid "Wrong extern UID provided. Make sure Auth0 is configured correctly."
msgstr ""
+msgid "YYYY-MM-DD"
+msgstr ""
+
msgid "Yes"
msgstr ""
@@ -28191,7 +29115,7 @@ msgstr ""
msgid "You are going to remove the fork relationship from %{project_full_name}. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "You are going to transfer %{project_full_name} to another owner. Are you ABSOLUTELY sure?"
+msgid "You are going to transfer %{project_full_name} to another namespace. Are you ABSOLUTELY sure?"
msgstr ""
msgid "You are going to turn off the confidentiality. This means %{strongStart}everyone%{strongEnd} will be able to see and leave a comment on this %{issuableType}."
@@ -28251,9 +29175,6 @@ msgstr ""
msgid "You can always edit this later"
msgstr ""
-msgid "You can apply your Trial to your Personal account or create a New Group."
-msgstr ""
-
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings"
msgstr ""
@@ -28275,12 +29196,18 @@ msgstr ""
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
+msgid "You can find more information about GitLab subscriptions in %{subscriptions_doc_link}."
+msgstr ""
+
msgid "You can generate an access token scoped to this project for each application to use the GitLab API."
msgstr ""
msgid "You can get started by cloning the repository or start adding files to it with one of the following options."
msgstr ""
+msgid "You can group test cases using labels. To learn about the future direction of this feature, visit %{linkStart}Quality Management direction page%{linkEnd}."
+msgstr ""
+
msgid "You can invite a new member to %{project_name} or invite another group."
msgstr ""
@@ -28296,6 +29223,9 @@ msgstr ""
msgid "You can notify the app / group or a project by sending them an email notification"
msgstr ""
+msgid "You can now close this window."
+msgstr ""
+
msgid "You can now export your security dashboard to a CSV report."
msgstr ""
@@ -28344,9 +29274,6 @@ msgstr ""
msgid "You can test your .gitlab-ci.yml in %{linkStart}CI Lint%{linkEnd}."
msgstr ""
-msgid "You can try again using %{begin_link}basic search%{end_link}"
-msgstr ""
-
msgid "You cannot access the raw file. Please wait a minute."
msgstr ""
@@ -28398,6 +29325,9 @@ msgstr ""
msgid "You don't have any U2F devices registered yet."
msgstr ""
+msgid "You don't have any WebAuthn devices registered yet."
+msgstr ""
+
msgid "You don't have any active chat names."
msgstr ""
@@ -28485,6 +29415,9 @@ msgstr ""
msgid "You must accept our Terms of Service and privacy policy in order to register an account"
msgstr ""
+msgid "You must be logged in to search across all of GitLab"
+msgstr ""
+
msgid "You must disassociate %{domain} from all clusters it is attached to before deletion."
msgstr ""
@@ -28524,7 +29457,7 @@ msgstr ""
msgid "You need to be logged in."
msgstr ""
-msgid "You need to register a two-factor authentication app before you can set up a U2F device."
+msgid "You need to register a two-factor authentication app before you can set up a device."
msgstr ""
msgid "You need to set terms to be enforced"
@@ -28542,6 +29475,9 @@ msgstr ""
msgid "You reached %{usage_in_percent} of %{namespace_name}'s storage capacity (%{used_storage} of %{storage_limit})"
msgstr ""
+msgid "You successfully declined the invitation"
+msgstr ""
+
msgid "You tried to fork %{link_to_the_project} but it failed for the following reason:"
msgstr ""
@@ -28707,10 +29643,13 @@ msgstr ""
msgid "Your U2F device did not send a valid JSON response."
msgstr ""
-msgid "Your U2F device needs to be set up. Plug it in (if not already) and click the button on the left."
+msgid "Your U2F device was registered!"
msgstr ""
-msgid "Your U2F device was registered!"
+msgid "Your WebAuthn device did not send a valid JSON response."
+msgstr ""
+
+msgid "Your WebAuthn device was registered!"
msgstr ""
msgid "Your access request to the %{source_type} has been withdrawn."
@@ -28734,6 +29673,9 @@ msgstr ""
msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
msgstr ""
+msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
+msgstr ""
+
msgid "Your changes can be committed to %{branch_name} because a merge request is open."
msgstr ""
@@ -28770,6 +29712,12 @@ msgstr ""
msgid "Your deployment services will be broken, you will need to manually fix the services after renaming."
msgstr ""
+msgid "Your device is not compatible with GitLab. Please try another device"
+msgstr ""
+
+msgid "Your device needs to be set up. Plug it in (if needed) and click the button on the left."
+msgstr ""
+
msgid "Your device was successfully set up! Give it a name and register it with the GitLab server."
msgstr ""
@@ -28882,9 +29830,6 @@ msgstr[0] ""
msgid "access:"
msgstr ""
-msgid "activated"
-msgstr ""
-
msgid "added %{created_at_timeago}"
msgstr ""
@@ -28957,9 +29902,21 @@ msgstr ""
msgid "by %{user}"
msgstr ""
+msgid "cannot be a date in the past"
+msgstr ""
+
msgid "cannot be changed if a personal project has container registry tags."
msgstr ""
+msgid "cannot be changed if shared runners are enabled"
+msgstr ""
+
+msgid "cannot be enabled because parent group does not allow it"
+msgstr ""
+
+msgid "cannot be enabled because parent group has shared Runners disabled"
+msgstr ""
+
msgid "cannot be enabled unless all domains have TLS certificates"
msgstr ""
@@ -29005,7 +29962,7 @@ msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about SAST %{linkEndTag}"
msgstr ""
-msgid "ciReport|%{linkStartTag}Learn more about Secret Scanning %{linkEndTag}"
+msgid "ciReport|%{linkStartTag}Learn more about Secret Detection %{linkEndTag}"
msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about codequality reports %{linkEndTag}"
@@ -29317,9 +30274,6 @@ msgstr ""
msgid "error"
msgstr ""
-msgid "error code:"
-msgstr ""
-
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr ""
@@ -29341,6 +30295,9 @@ msgstr ""
msgid "failed to dismiss associated finding(id=%{finding_id}): %{message}"
msgstr ""
+msgid "failed to revert associated finding(id=%{finding_id}) to detected"
+msgstr ""
+
msgid "file"
msgid_plural "files"
msgstr[0] ""
@@ -29879,6 +30836,9 @@ msgstr ""
msgid "must be a root namespace"
msgstr ""
+msgid "must be a valid IPv4 or IPv6 address"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -29915,6 +30875,9 @@ msgstr ""
msgid "no expiration"
msgstr ""
+msgid "no name set"
+msgstr ""
+
msgid "no one can merge"
msgstr ""
@@ -30088,9 +31051,6 @@ msgstr ""
msgid "security Reports|There was an error creating the merge request"
msgstr ""
-msgid "settings saved, but not activated"
-msgstr ""
-
msgid "severity|Critical"
msgstr ""
@@ -30217,9 +31177,6 @@ msgstr ""
msgid "toggle collapse"
msgstr ""
-msgid "toggle dropdown"
-msgstr ""
-
msgid "triggered"
msgstr ""
@@ -30247,6 +31204,9 @@ msgstr ""
msgid "user avatar"
msgstr ""
+msgid "user preferences"
+msgstr ""
+
msgid "username"
msgstr ""
diff --git a/locale/bg/gitlab.po b/locale/bg/gitlab.po
index f7e1994c42e..e45c2a55932 100644
--- a/locale/bg/gitlab.po
+++ b/locale/bg/gitlab.po
@@ -14,7 +14,10 @@ msgstr ""
"X-Crowdin-Language: bg\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 6\n"
-"PO-Revision-Date: 2020-09-04 23:07\n"
+"PO-Revision-Date: 2020-10-02 18:46\n"
+
+msgid " %{project_name}#%{issue_iid} &middot; opened %{issue_created} by %{author}"
+msgstr ""
msgid " %{start} to %{end}"
msgstr ""
@@ -74,6 +77,16 @@ msgstr ""
msgid "\"el\" parameter is required for createInstance()"
msgstr ""
+msgid "%d Approval"
+msgid_plural "%d Approvals"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d Package"
+msgid_plural "%d Packages"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d Scanned URL"
msgid_plural "%d Scanned URLs"
msgstr[0] ""
@@ -137,6 +150,11 @@ msgstr[1] ""
msgid "%d commits"
msgstr ""
+msgid "%d completed issue"
+msgid_plural "%d completed issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d contribution"
msgid_plural "%d contributions"
msgstr[0] ""
@@ -147,6 +165,11 @@ msgid_plural "%d days"
msgstr[0] ""
msgstr[1] ""
+msgid "%d day until tags are automatically removed"
+msgid_plural "%d days until tags are automatically removed"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d error"
msgid_plural "%d errors"
msgstr[0] ""
@@ -237,6 +260,16 @@ msgid_plural "%d more comments"
msgstr[0] ""
msgstr[1] ""
+msgid "%d open issue"
+msgid_plural "%d open issues"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d pending comment"
+msgid_plural "%d pending comments"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d personal project will be removed and cannot be restored."
msgid_plural "%d personal projects will be removed and cannot be restored."
msgstr[0] ""
@@ -252,6 +285,11 @@ msgid_plural "%d projects"
msgstr[0] ""
msgstr[1] ""
+msgid "%d project selected"
+msgid_plural "%d projects selected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d request with warnings"
msgid_plural "%d requests with warnings"
msgstr[0] ""
@@ -272,6 +310,11 @@ msgid_plural "%d tags"
msgstr[0] ""
msgstr[1] ""
+msgid "%d tag per image name"
+msgid_plural "%d tags per image name"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d unassigned issue"
msgid_plural "%d unassigned issues"
msgstr[0] ""
@@ -292,6 +335,11 @@ msgid_plural "%d vulnerabilities dismissed"
msgstr[0] ""
msgstr[1] ""
+msgid "%d warning found:"
+msgid_plural "%d warnings found:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%s additional commit has been omitted to prevent performance issues."
msgid_plural "%s additional commits have been omitted to prevent performance issues."
msgstr[0] "%s подаване беше пропуÑнато, за да не Ñе натоварва ÑиÑтемата."
@@ -330,6 +378,9 @@ msgstr ""
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr ""
+msgid "%{completedCount} completed weight"
+msgstr ""
+
msgid "%{completedWeight} of %{totalWeight} weight completed"
msgstr ""
@@ -378,14 +429,12 @@ msgid_plural "%{count} participants"
msgstr[0] ""
msgstr[1] ""
-msgid "%{count} pending comment"
-msgid_plural "%{count} pending comments"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
+msgid "%{count} total weight"
+msgstr ""
+
msgid "%{dashboard_path} could not be found."
msgstr ""
@@ -440,6 +489,9 @@ msgstr ""
msgid "%{group_name} uses group managed accounts. You need to create a new GitLab account which will be managed by %{group_name}."
msgstr ""
+msgid "%{group_name}&%{epic_iid} &middot; opened %{epic_created} by %{author}"
+msgstr ""
+
msgid "%{host} sign-in from new location"
msgstr ""
@@ -452,7 +504,7 @@ msgstr ""
msgid "%{issuableType} will be removed! Are you sure?"
msgstr ""
-msgid "%{issuesSize} issues with a limit of %{maxIssueCount}"
+msgid "%{issuesCount} issues with a limit of %{maxIssueCount}"
msgstr ""
msgid "%{issuesSize} with a limit of %{maxIssueCount}"
@@ -485,7 +537,7 @@ msgstr ""
msgid "%{labelStart}Namespace:%{labelEnd} %{namespace}"
msgstr ""
-msgid "%{labelStart}Report Type:%{labelEnd} %{reportType}"
+msgid "%{labelStart}Scan Type:%{labelEnd} %{reportType}"
msgstr ""
msgid "%{labelStart}Scanner:%{labelEnd} %{scanner}"
@@ -682,9 +734,6 @@ msgid_plural "%{securityScanner} results are not available because a pipeline ha
msgstr[0] ""
msgstr[1] ""
-msgid "%{service_title} %{message}."
-msgstr ""
-
msgid "%{size} GiB"
msgstr ""
@@ -773,6 +822,12 @@ msgstr ""
msgid "%{timebox_name} should belong either to a project or a group."
msgstr ""
+msgid "%{timebox_type} does not support burnup charts"
+msgstr ""
+
+msgid "%{timebox_type} must have a start and due date"
+msgstr ""
+
msgid "%{title} %{operator} %{threshold}"
msgstr ""
@@ -797,7 +852,7 @@ msgstr ""
msgid "%{total} open issue weight"
msgstr ""
-msgid "%{total} open issues"
+msgid "%{total} warnings found: showing first %{warningsDisplayed}"
msgstr ""
msgid "%{usage_ping_link_start}Learn more%{usage_ping_link_end} about what information is shared with GitLab Inc."
@@ -830,9 +885,6 @@ msgstr ""
msgid "&lt; 1 hour"
msgstr ""
-msgid "&lt;no name set&gt;"
-msgstr ""
-
msgid "&lt;no scopes selected&gt;"
msgstr ""
@@ -863,6 +915,9 @@ msgstr ""
msgid "'%{name}' Value Stream created"
msgstr ""
+msgid "'%{name}' Value Stream deleted"
+msgstr ""
+
msgid "'%{name}' stage already exists"
msgstr ""
@@ -922,6 +977,9 @@ msgstr ""
msgid "+ %{numberOfHiddenAssignees} more"
msgstr ""
+msgid "+ %{numberOfHiddenReviewers} more"
+msgstr ""
+
msgid "+%d more"
msgid_plural "+%d more"
msgstr[0] ""
@@ -982,6 +1040,11 @@ msgid_plural "%d Days"
msgstr[0] ""
msgstr[1] ""
+msgid "1 Issue"
+msgid_plural "%d Issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "1 closed issue"
msgid_plural "%{issues} closed issues"
msgstr[0] "1 затворен проблем"
@@ -997,6 +1060,11 @@ msgid_plural "%d days"
msgstr[0] ""
msgstr[1] ""
+msgid "1 deploy key"
+msgid_plural "%d deploy keys"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1099,6 +1167,9 @@ msgstr ""
msgid ":%{startLine} to %{endLine}"
msgstr ""
+msgid "A %{incident_docs_start}modified issue%{incident_docs_end} to guide the resolution of incidents."
+msgstr ""
+
msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr ""
@@ -1111,6 +1182,9 @@ msgstr ""
msgid "A GitBook site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
+msgid "A Gitpod configured Webapplication in Spring and Java"
+msgstr ""
+
msgid "A Hexo site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
@@ -1282,9 +1356,15 @@ msgstr ""
msgid "Access expiration date"
msgstr ""
+msgid "Access expires"
+msgstr ""
+
msgid "Access forbidden. Check your access level."
msgstr ""
+msgid "Access granted"
+msgstr ""
+
msgid "Access requests"
msgstr ""
@@ -1294,6 +1374,9 @@ msgstr ""
msgid "Access to Pages websites are controlled based on the user's membership to a given project. By checking this box, users will be required to be logged in to have access to all Pages websites in your instance."
msgstr ""
+msgid "AccessDropdown|Deploy Keys"
+msgstr ""
+
msgid "AccessDropdown|Groups"
msgstr ""
@@ -1411,12 +1494,6 @@ msgstr ""
msgid "Active Sessions"
msgstr ""
-msgid "Active Users:"
-msgstr ""
-
-msgid "Active users"
-msgstr ""
-
msgid "Activity"
msgstr "ДейноÑÑ‚"
@@ -1584,9 +1661,6 @@ msgstr ""
msgid "Add label(s)"
msgstr ""
-msgid "Add license"
-msgstr ""
-
msgid "Add list"
msgstr ""
@@ -1761,21 +1835,51 @@ msgstr ""
msgid "AdminArea|Bots"
msgstr ""
+msgid "AdminArea|Components"
+msgstr ""
+
msgid "AdminArea|Developer"
msgstr ""
+msgid "AdminArea|Features"
+msgstr ""
+
+msgid "AdminArea|Groups: %{number_of_groups}"
+msgstr ""
+
msgid "AdminArea|Guest"
msgstr ""
msgid "AdminArea|Included Free in license"
msgstr ""
+msgid "AdminArea|Latest groups"
+msgstr ""
+
+msgid "AdminArea|Latest projects"
+msgstr ""
+
+msgid "AdminArea|Latest users"
+msgstr ""
+
msgid "AdminArea|Maintainer"
msgstr ""
+msgid "AdminArea|New group"
+msgstr ""
+
+msgid "AdminArea|New project"
+msgstr ""
+
+msgid "AdminArea|New user"
+msgstr ""
+
msgid "AdminArea|Owner"
msgstr ""
+msgid "AdminArea|Projects: %{number_of_projects}"
+msgstr ""
+
msgid "AdminArea|Reporter"
msgstr ""
@@ -1803,6 +1907,9 @@ msgstr ""
msgid "AdminArea|Users without a Group and Project"
msgstr ""
+msgid "AdminArea|Users: %{number_of_users}"
+msgstr ""
+
msgid "AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running."
msgstr ""
@@ -1821,9 +1928,6 @@ msgstr ""
msgid "AdminProjects|Delete Project %{projectName}?"
msgstr ""
-msgid "AdminProjects|Delete project"
-msgstr ""
-
msgid "AdminSettings|Apply integration settings to all Projects"
msgstr ""
@@ -2061,21 +2165,30 @@ msgstr ""
msgid "AdminUsers|Without projects"
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 ""
msgid "AdminUsers|You cannot remove your own admin rights."
msgstr ""
+msgid "AdminUsers|You must transfer ownership or delete the groups owned by this user before you can delete their account"
+msgstr ""
+
msgid "Administration"
msgstr ""
msgid "Advanced"
msgstr ""
+msgid "Advanced Search"
+msgstr ""
+
+msgid "Advanced Search with Elasticsearch"
+msgstr ""
+
msgid "Advanced Settings"
msgstr ""
@@ -2153,6 +2266,9 @@ msgstr ""
msgid "AlertManagement|Edit"
msgstr ""
+msgid "AlertManagement|Environment"
+msgstr ""
+
msgid "AlertManagement|Events"
msgstr ""
@@ -2165,6 +2281,9 @@ msgstr ""
msgid "AlertManagement|Issue"
msgstr ""
+msgid "AlertManagement|Key"
+msgstr ""
+
msgid "AlertManagement|Low"
msgstr ""
@@ -2258,6 +2377,9 @@ msgstr ""
msgid "AlertManagement|Unknown"
msgstr ""
+msgid "AlertManagement|Value"
+msgstr ""
+
msgid "AlertManagement|View alerts in Opsgenie"
msgstr ""
@@ -2417,6 +2539,9 @@ msgstr ""
msgid "All projects"
msgstr ""
+msgid "All projects selected"
+msgstr ""
+
msgid "All security scans are enabled because %{linkStart}Auto DevOps%{linkEnd} is enabled on this project"
msgstr ""
@@ -2504,6 +2629,9 @@ msgstr ""
msgid "Almost there"
msgstr ""
+msgid "Already blocked"
+msgstr ""
+
msgid "Also called \"Issuer\" or \"Relying party trust identifier\""
msgstr ""
@@ -2558,6 +2686,9 @@ msgstr ""
msgid "An error has occurred"
msgstr ""
+msgid "An error occured while making the changes: %{error}"
+msgstr ""
+
msgid "An error occurred adding a draft to the thread."
msgstr ""
@@ -2585,12 +2716,6 @@ msgstr ""
msgid "An error occurred when toggling the notification subscription"
msgstr ""
-msgid "An error occurred when trying to resolve a comment. Please try again."
-msgstr ""
-
-msgid "An error occurred when trying to resolve a discussion. Please try again."
-msgstr ""
-
msgid "An error occurred when updating the issue weight"
msgstr ""
@@ -2606,12 +2731,6 @@ msgstr ""
msgid "An error occurred while checking group path. Please refresh and try again."
msgstr ""
-msgid "An error occurred while committing your changes."
-msgstr ""
-
-msgid "An error occurred while creating the list. Please try again."
-msgstr ""
-
msgid "An error occurred while decoding the file."
msgstr ""
@@ -2684,25 +2803,19 @@ msgstr ""
msgid "An error occurred while fetching the Service Desk address."
msgstr ""
-msgid "An error occurred while fetching the board issues. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the board lists. Please reload the page."
msgstr ""
msgid "An error occurred while fetching the board lists. Please try again."
msgstr ""
-msgid "An error occurred while fetching the board swimlanes. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the builds."
msgstr ""
msgid "An error occurred while fetching the job log."
msgstr ""
-msgid "An error occurred while fetching the job trace."
+msgid "An error occurred while fetching the job logs."
msgstr ""
msgid "An error occurred while fetching the job."
@@ -2849,9 +2962,6 @@ msgstr ""
msgid "An error occurred while saving assignees"
msgstr ""
-msgid "An error occurred while saving the template. Please check if the template exists."
-msgstr ""
-
msgid "An error occurred while searching for milestones"
msgstr ""
@@ -2870,10 +2980,10 @@ msgstr ""
msgid "An error occurred while updating approvers"
msgstr ""
-msgid "An error occurred while updating the comment"
+msgid "An error occurred while updating labels."
msgstr ""
-msgid "An error occurred while updating the list. Please try again."
+msgid "An error occurred while updating the comment"
msgstr ""
msgid "An error occurred while validating group path"
@@ -2927,6 +3037,9 @@ msgstr ""
msgid "An unknown error occurred while loading this graph."
msgstr ""
+msgid "An unknown error occurred."
+msgstr ""
+
msgid "Analytics"
msgstr ""
@@ -2960,10 +3073,10 @@ msgstr ""
msgid "Any"
msgstr ""
-msgid "Any Author"
+msgid "Any %{header}"
msgstr ""
-msgid "Any Status"
+msgid "Any Author"
msgstr ""
msgid "Any branch"
@@ -3017,6 +3130,9 @@ msgstr ""
msgid "Application ID"
msgstr ""
+msgid "Application limits saved successfully"
+msgstr ""
+
msgid "Application settings saved successfully"
msgstr ""
@@ -3226,6 +3342,9 @@ msgstr ""
msgid "Are you sure you want to close this blocked issue?"
msgstr ""
+msgid "Are you sure you want to delete \"%{name}\" Value Stream?"
+msgstr ""
+
msgid "Are you sure you want to delete %{name}?"
msgstr ""
@@ -3235,6 +3354,9 @@ msgstr ""
msgid "Are you sure you want to delete this %{typeOfComment}?"
msgstr ""
+msgid "Are you sure you want to delete this SSH key?"
+msgstr ""
+
msgid "Are you sure you want to delete this board?"
msgstr ""
@@ -3259,6 +3381,11 @@ msgstr ""
msgid "Are you sure you want to erase this build?"
msgstr ""
+msgid "Are you sure you want to import %d repository?"
+msgid_plural "Are you sure you want to import %d repositories?"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Are you sure you want to lose unsaved changes?"
msgstr ""
@@ -3268,15 +3395,15 @@ msgstr ""
msgid "Are you sure you want to merge immediately?"
msgstr ""
-msgid "Are you sure you want to permanently delete this license?"
-msgstr ""
-
msgid "Are you sure you want to re-deploy this environment?"
msgstr ""
msgid "Are you sure you want to regenerate the public key? You will have to update the public key on the remote server before mirroring will work again."
msgstr ""
+msgid "Are you sure you want to reindex?"
+msgstr ""
+
msgid "Are you sure you want to remove %{group_name}?"
msgstr ""
@@ -3304,6 +3431,9 @@ msgstr ""
msgid "Are you sure you want to revoke this nickname?"
msgstr ""
+msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
+msgstr ""
+
msgid "Are you sure you want to stop this environment?"
msgstr ""
@@ -3325,6 +3455,9 @@ msgstr ""
msgid "Are you sure? The device will be signed out of GitLab and all remember me tokens revoked."
msgstr ""
+msgid "Are you sure? This will invalidate your registered applications and U2F / WebAuthn devices."
+msgstr ""
+
msgid "Are you sure? This will invalidate your registered applications and U2F devices."
msgstr ""
@@ -3343,9 +3476,6 @@ msgstr ""
msgid "Artifacts"
msgstr ""
-msgid "As U2F devices are only supported by a few browsers, we require that you set up a two-factor authentication app before a U2F device. That way you'll always be able to log in - even when you're using an unsupported browser."
-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 ""
@@ -3539,6 +3669,9 @@ msgstr ""
msgid "AuditLogs|Target"
msgstr ""
+msgid "AuditLogs|This month"
+msgstr ""
+
msgid "AuditLogs|User Events"
msgstr ""
@@ -3578,6 +3711,9 @@ msgstr ""
msgid "Authentication via U2F device failed."
msgstr ""
+msgid "Authentication via WebAuthn device failed."
+msgstr ""
+
msgid "Author"
msgstr ""
@@ -3845,15 +3981,6 @@ msgstr ""
msgid "BambooService|You must set up automatic revision labeling and a repository trigger in Bamboo."
msgstr ""
-msgid "BatchComments|Delete all pending comments"
-msgstr ""
-
-msgid "BatchComments|Discard review?"
-msgstr ""
-
-msgid "BatchComments|You're about to discard your review which will delete all of your pending comments. The deleted comments %{strong_start}cannot%{strong_end} be restored."
-msgstr ""
-
msgid "Be careful. Changing the project's namespace can have unintended side effects."
msgstr ""
@@ -3875,6 +4002,9 @@ msgstr ""
msgid "Bi-weekly code coverage"
msgstr ""
+msgid "Billable Users:"
+msgstr ""
+
msgid "Billing"
msgstr ""
@@ -3884,7 +4014,7 @@ msgstr ""
msgid "BillingPlans|@%{user_name} you are currently using the %{plan_name} plan."
msgstr ""
-msgid "BillingPlans|Congratulations, your new trial is activated"
+msgid "BillingPlans|Congratulations, your free trial is activated."
msgstr ""
msgid "BillingPlans|If you would like to downgrade your plan please contact %{support_link_start}Customer Support%{support_link_end}."
@@ -3947,6 +4077,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Block user"
+msgstr ""
+
msgid "Blocked"
msgstr ""
@@ -3962,31 +4095,37 @@ msgstr ""
msgid "Blog"
msgstr ""
-msgid "Board name"
-msgstr ""
-
msgid "Board scope"
msgstr ""
msgid "Board scope affects which issues are displayed for anyone who visits this board"
msgstr ""
-msgid "BoardBlankState|Add default lists"
+msgid "Boards"
msgstr ""
-msgid "BoardBlankState|Add the following default lists to your Issue Board with one click:"
+msgid "Boards and Board Lists"
msgstr ""
-msgid "BoardBlankState|Nevermind, I'll use my own"
+msgid "Boards|An error occurred while creating the issue. Please try again."
msgstr ""
-msgid "BoardBlankState|Starting out with the default set of lists will get you right on the way to making the most of your board."
+msgid "Boards|An error occurred while creating the list. Please try again."
msgstr ""
-msgid "Boards"
+msgid "Boards|An error occurred while fetching issues. Please reload the page."
msgstr ""
-msgid "Boards and Board Lists"
+msgid "Boards|An error occurred while fetching the board issues. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching the board swimlanes. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while moving the issue. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while updating the list. Please try again."
msgstr ""
msgid "Boards|Collapse"
@@ -4013,7 +4152,7 @@ msgstr ""
msgid "Branch %{branch_name} was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr ""
-msgid "Branch has changed"
+msgid "Branch changed"
msgstr ""
msgid "Branch is already taken"
@@ -4319,6 +4458,9 @@ msgstr ""
msgid "CLOSED (MOVED)"
msgstr ""
+msgid "CODEOWNERS rule violation"
+msgstr ""
+
msgid "CONTRIBUTING"
msgstr ""
@@ -4349,9 +4491,6 @@ msgstr ""
msgid "Can't create snippet: %{err}"
msgstr ""
-msgid "Can't edit as source branch was deleted"
-msgstr ""
-
msgid "Can't fetch content for the blob: %{err}"
msgstr ""
@@ -4364,9 +4503,6 @@ msgstr ""
msgid "Can't load mermaid module: %{err}"
msgstr ""
-msgid "Can't remove group members without group managed account"
-msgstr ""
-
msgid "Can't scan the code?"
msgstr ""
@@ -4409,6 +4545,9 @@ msgstr ""
msgid "Cannot create the abuse report. This user has been blocked."
msgstr ""
+msgid "Cannot enable shared runners because parent group does not allow it"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -4514,6 +4653,15 @@ msgstr ""
msgid "Change your password or recover your current one"
msgstr ""
+msgid "ChangeReviewer|Reviewer changed from %{old} to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Reviewer changed to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Unassigned"
+msgstr ""
+
msgid "ChangeTypeActionLabel|Pick into branch"
msgstr "Избиране в клона"
@@ -4553,6 +4701,9 @@ msgstr ""
msgid "Changes the title to \"%{title_param}\"."
msgstr ""
+msgid "Changes were successfully made."
+msgstr ""
+
msgid "Changes won't take place until the index is %{link_start}recreated%{link_end}."
msgstr ""
@@ -4958,6 +5109,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove variable"
+msgstr ""
+
msgid "CiVariables|Remove variable row"
msgstr ""
@@ -5036,9 +5190,6 @@ msgstr ""
msgid "Clear due date"
msgstr ""
-msgid "Clear input"
-msgstr ""
-
msgid "Clear recent searches"
msgstr ""
@@ -5087,6 +5238,9 @@ msgstr ""
msgid "Client authentication key password"
msgstr ""
+msgid "Client request timeout"
+msgstr ""
+
msgid "Clients"
msgstr ""
@@ -5171,6 +5325,27 @@ msgstr ""
msgid "Cluster type must be specificed for Stages::ClusterEndpointInserter"
msgstr ""
+msgid "ClusterAgents|Configuration"
+msgstr ""
+
+msgid "ClusterAgents|Connect your cluster with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate Kubernetes with a GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Name"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Agent also requires %{linkStart}enabling the Agent Server%{linkEnd}"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Kubernetes Agent allows an Infrastructure as Code, GitOps approach to integrating Kubernetes clusters with GitLab. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "ClusterAgent|This feature is only available for premium plans"
msgstr ""
@@ -5240,10 +5415,10 @@ msgstr ""
msgid "ClusterIntegration|All installed applications and related resources"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster."
+msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{linkStart}More information%{linkEnd}"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{startLink}More information%{endLink}"
+msgid "ClusterIntegration|Allow GitLab to manage namespaces and service accounts for this cluster."
msgstr ""
msgid "ClusterIntegration|Alternatively, "
@@ -5264,6 +5439,9 @@ msgstr ""
msgid "ClusterIntegration|An error occurred while trying to fetch zone machine types: %{error}"
msgstr ""
+msgid "ClusterIntegration|An unknown error occurred while attempting to connect to Kubernetes."
+msgstr ""
+
msgid "ClusterIntegration|Any project namespaces"
msgstr ""
@@ -5279,6 +5457,9 @@ msgstr ""
msgid "ClusterIntegration|Authenticate with Amazon Web Services"
msgstr ""
+msgid "ClusterIntegration|Authentication Error"
+msgstr ""
+
msgid "ClusterIntegration|Base domain"
msgstr ""
@@ -5297,13 +5478,22 @@ msgstr ""
msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}security group %{externalLinkIcon} %{endLink} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
+msgid "ClusterIntegration|Check your CA certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Check your cluster status"
+msgstr ""
+
+msgid "ClusterIntegration|Check your token"
+msgstr ""
+
+msgid "ClusterIntegration|Choose the %{linkStart}security group %{linkEnd} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}subnets %{externalLinkIcon} %{endLink} in your VPC where your worker nodes will run."
+msgid "ClusterIntegration|Choose the %{linkStart}subnets %{linkEnd} in your VPC where your worker nodes will run."
msgstr ""
-msgid "ClusterIntegration|Choose the worker node %{startLink}instance type %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Choose the worker node %{linkStart}instance type%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Choose which applications to install on your Kubernetes cluster."
@@ -5315,10 +5505,7 @@ msgstr ""
msgid "ClusterIntegration|Clear cluster cache"
msgstr ""
-msgid "ClusterIntegration|Clear the local cache of namespace and service accounts. This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
-msgstr ""
-
-msgid "ClusterIntegration|Cluster being created"
+msgid "ClusterIntegration|Clear the local cache of namespace and service accounts."
msgstr ""
msgid "ClusterIntegration|Cluster management project (alpha)"
@@ -5330,15 +5517,21 @@ msgstr ""
msgid "ClusterIntegration|Cluster_applications artifact too big. Maximum allowable size: %{human_size}"
msgstr ""
-msgid "ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters."
+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|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}"
+msgid "ClusterIntegration|Clusters connected with a certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Connect cluster with certificate"
msgstr ""
msgid "ClusterIntegration|Connect existing cluster"
msgstr ""
+msgid "ClusterIntegration|Connection Error"
+msgstr ""
+
msgid "ClusterIntegration|Copy API URL"
msgstr ""
@@ -5414,6 +5607,12 @@ msgstr ""
msgid "ClusterIntegration|Deletes all GitLab resources attached to this cluster during removal"
msgstr ""
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared."
+msgstr ""
+
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared. %{linkStart}More information%{linkEnd}"
+msgstr ""
+
msgid "ClusterIntegration|Did you know?"
msgstr ""
@@ -5483,6 +5682,9 @@ msgstr ""
msgid "ClusterIntegration|Fluentd is an open source data collector, which lets you unify the data collection and consumption for a better use and understanding of data. It requires at least one of the following logs to be successfully installed."
msgstr ""
+msgid "ClusterIntegration|GitLab Agent managed clusters"
+msgstr ""
+
msgid "ClusterIntegration|GitLab Container Network Policies"
msgstr ""
@@ -5495,6 +5697,12 @@ msgstr ""
msgid "ClusterIntegration|GitLab Runner connects to the repository and executes CI/CD jobs, pushing results back and deploying applications to production."
msgstr ""
+msgid "ClusterIntegration|GitLab failed to authenticate."
+msgstr ""
+
+msgid "ClusterIntegration|GitLab failed to connect to the cluster."
+msgstr ""
+
msgid "ClusterIntegration|GitLab-managed cluster"
msgstr ""
@@ -5516,6 +5724,9 @@ msgstr ""
msgid "ClusterIntegration|Group cluster"
msgstr ""
+msgid "ClusterIntegration|HTTP Error"
+msgstr ""
+
msgid "ClusterIntegration|Helm Tiller"
msgstr ""
@@ -5549,7 +5760,10 @@ msgstr ""
msgid "ClusterIntegration|Instance type"
msgstr ""
-msgid "ClusterIntegration|Integrate Kubernetes cluster automation"
+msgid "ClusterIntegration|Integrate Kubernetes with a cluster certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Integrate with a cluster certificate"
msgstr ""
msgid "ClusterIntegration|Issuer Email"
@@ -5585,9 +5799,6 @@ msgstr ""
msgid "ClusterIntegration|Knative extends Kubernetes to provide a set of middleware components that are essential to build modern, source-centric, and container-based applications that can run anywhere: on premises, in the cloud, or even in a third-party data center."
msgstr ""
-msgid "ClusterIntegration|Kubernetes cluster"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes cluster is being created..."
msgstr ""
@@ -5600,9 +5811,6 @@ msgstr ""
msgid "ClusterIntegration|Kubernetes clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr ""
-msgid "ClusterIntegration|Kubernetes clusters can be used to deploy applications and to provide Review Apps for this project"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes version"
msgstr ""
@@ -5615,7 +5823,7 @@ msgstr ""
msgid "ClusterIntegration|Learn more about %{help_link_start}zones%{help_link_end}."
msgstr ""
-msgid "ClusterIntegration|Learn more about %{startLink}Regions %{externalLinkIcon}%{endLink}."
+msgid "ClusterIntegration|Learn more about %{linkStart}Regions%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Learn more about Kubernetes"
@@ -5660,12 +5868,18 @@ msgstr ""
msgid "ClusterIntegration|Machine type"
msgstr ""
+msgid "ClusterIntegration|Make sure your API endpoint is correct"
+msgstr ""
+
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create Kubernetes clusters"
msgstr ""
msgid "ClusterIntegration|Manage your Kubernetes cluster by visiting %{provider_link}"
msgstr ""
+msgid "ClusterIntegration|Namespace per environment"
+msgstr ""
+
msgid "ClusterIntegration|No IAM Roles found"
msgstr ""
@@ -5711,6 +5925,9 @@ msgstr ""
msgid "ClusterIntegration|No zones matched your search"
msgstr ""
+msgid "ClusterIntegration|Node calculations use the Kubernetes Metrics API. Make sure your cluster has metrics installed"
+msgstr ""
+
msgid "ClusterIntegration|Number of nodes"
msgstr ""
@@ -5753,6 +5970,9 @@ msgstr ""
msgid "ClusterIntegration|RBAC-enabled cluster"
msgstr ""
+msgid "ClusterIntegration|Read our %{linkStart}help page%{linkEnd} on Kubernetes cluster integration."
+msgstr ""
+
msgid "ClusterIntegration|Read our %{link_start}help page%{link_end} on Kubernetes cluster integration."
msgstr ""
@@ -5855,7 +6075,7 @@ msgstr ""
msgid "ClusterIntegration|Select a VPC to choose a subnet"
msgstr ""
-msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{linkStart}Amazon Web Services %{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select a network to choose a subnetwork"
@@ -5888,7 +6108,7 @@ msgstr ""
msgid "ClusterIntegration|Select project to choose zone"
msgstr ""
-msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select zone"
@@ -5978,9 +6198,18 @@ msgstr ""
msgid "ClusterIntegration|There was a problem authenticating with your cluster. Please ensure your CA Certificate and Token are valid."
msgstr ""
+msgid "ClusterIntegration|There was an HTTP error when connecting to your cluster."
+msgstr ""
+
msgid "ClusterIntegration|This account must have permissions to create a Kubernetes cluster in the %{link_to_container_project} specified below"
msgstr ""
+msgid "ClusterIntegration|This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
+msgstr ""
+
+msgid "ClusterIntegration|This is necessary to clear existing environment-namespace associations from clusters previously managed by GitLab."
+msgstr ""
+
msgid "ClusterIntegration|This option will allow you to install applications on RBAC clusters."
msgstr ""
@@ -6005,9 +6234,21 @@ msgstr ""
msgid "ClusterIntegration|To use a new project, first create one on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}."
msgstr ""
+msgid "ClusterIntegration|Troubleshooting tips:"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Authenticate"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Connect"
+msgstr ""
+
msgid "ClusterIntegration|Uninstall %{appTitle}"
msgstr ""
+msgid "ClusterIntegration|Unknown Error"
+msgstr ""
+
msgid "ClusterIntegration|Update %{appTitle}"
msgstr ""
@@ -6068,7 +6309,7 @@ msgstr ""
msgid "ClusterIntegration|Your cluster API is unreachable. Please ensure your API URL is correct."
msgstr ""
-msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Zone"
@@ -6188,6 +6429,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse all threads"
+msgstr ""
+
msgid "Collapse approvers"
msgstr ""
@@ -6337,7 +6581,7 @@ msgstr "Подадено от"
msgid "Commit…"
msgstr ""
-msgid "Company"
+msgid "Community forum"
msgstr ""
msgid "Company name"
@@ -6346,6 +6590,9 @@ msgstr ""
msgid "Compare"
msgstr "Сравнение"
+msgid "Compare %{oldCommitId}...%{newCommitId}"
+msgstr ""
+
msgid "Compare Git revisions"
msgstr ""
@@ -6361,6 +6608,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare submodule commit revisions"
+msgstr ""
+
msgid "Compare with previous version"
msgstr ""
@@ -6496,6 +6746,9 @@ msgstr ""
msgid "Configure the way a user creates a new account."
msgstr ""
+msgid "Configure which lists are shown for anyone who visits this board"
+msgstr ""
+
msgid "Confirm"
msgstr ""
@@ -6721,6 +6974,9 @@ msgstr[1] ""
msgid "ContainerRegistry|Set cleanup policy"
msgstr ""
+msgid "ContainerRegistry|Some tags were not deleted"
+msgstr ""
+
msgid "ContainerRegistry|Something went wrong while fetching the cleanup policy."
msgstr ""
@@ -6760,6 +7016,9 @@ msgstr ""
msgid "ContainerRegistry|Tags with names matching this regex pattern will %{italicStart}expire:%{italicEnd}"
msgstr ""
+msgid "ContainerRegistry|The cleanup policy timed out before it could delete all tags. An administrator can %{adminLinkStart}manually run cleanup now%{adminLinkEnd} or you can wait for the cleanup policy to automatically run again. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "ContainerRegistry|The last tag related to this image was recently removed. This empty image and any associated data will be automatically removed as part of the regular Garbage Collection process. If you have any questions, contact your administrator."
msgstr ""
@@ -6892,6 +7151,9 @@ msgstr ""
msgid "Contributions per group member"
msgstr ""
+msgid "Contributor"
+msgstr ""
+
msgid "Contributors"
msgstr "Сътрудници"
@@ -7021,6 +7283,9 @@ msgstr ""
msgid "Could not change HEAD: branch '%{branch}' does not exist"
msgstr ""
+msgid "Could not commit. An unexpected error occurred."
+msgstr ""
+
msgid "Could not connect to FogBugz, check your URL"
msgstr ""
@@ -7060,6 +7325,9 @@ msgstr ""
msgid "Could not find iteration"
msgstr ""
+msgid "Could not load instance counts. Please refresh the page to try again."
+msgstr ""
+
msgid "Could not remove the trigger."
msgstr ""
@@ -7084,10 +7352,10 @@ msgstr ""
msgid "Could not save prometheus manual configuration"
msgstr ""
-msgid "Could not udpdate wiki page"
+msgid "Could not update the LDAP settings"
msgstr ""
-msgid "Could not update the LDAP settings"
+msgid "Could not update wiki page"
msgstr ""
msgid "Could not upload your designs as one or more files uploaded are not supported."
@@ -7745,6 +8013,9 @@ msgstr ""
msgid "DastProfiles|Are you sure you want to delete this profile?"
msgstr ""
+msgid "DastProfiles|Could not create site validation token. Please refresh the page, or try again later."
+msgstr ""
+
msgid "DastProfiles|Could not create the scanner profile. Please try again."
msgstr ""
@@ -7769,6 +8040,12 @@ msgstr ""
msgid "DastProfiles|Could not fetch site profiles. Please refresh the page, or try again later."
msgstr ""
+msgid "DastProfiles|Could not retrieve site validation status. Please refresh the page, or try again later."
+msgstr ""
+
+msgid "DastProfiles|Could not update the scanner profile. Please try again."
+msgstr ""
+
msgid "DastProfiles|Could not update the site profile. Please try again."
msgstr ""
@@ -7784,7 +8061,7 @@ msgstr ""
msgid "DastProfiles|Download validation text file"
msgstr ""
-msgid "DastProfiles|Edit feature will come soon. Please create a new profile if changes needed"
+msgid "DastProfiles|Edit scanner profile"
msgstr ""
msgid "DastProfiles|Edit site profile"
@@ -7817,6 +8094,9 @@ msgstr ""
msgid "DastProfiles|No profiles created yet"
msgstr ""
+msgid "DastProfiles|Passive"
+msgstr ""
+
msgid "DastProfiles|Please enter a valid URL format, ex: http://www.example.com/home"
msgstr ""
@@ -7832,6 +8112,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan mode"
+msgstr ""
+
msgid "DastProfiles|Scanner Profile"
msgstr ""
@@ -7871,10 +8154,10 @@ msgstr ""
msgid "DastProfiles|Text file validation"
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
+msgid "DastProfiles|The maximum number of minutes allowed for the spider to traverse the site."
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the spider to traverse the site."
+msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
msgstr ""
msgid "DastProfiles|Validate"
@@ -7907,6 +8190,9 @@ msgstr ""
msgid "Date picker"
msgstr ""
+msgid "Date range"
+msgstr ""
+
msgid "Date range cannot exceed %{maxDateRange} days."
msgstr ""
@@ -7931,6 +8217,9 @@ msgstr ""
msgid "Days to merge"
msgstr ""
+msgid "Dear Administrator,"
+msgstr ""
+
msgid "Debug"
msgstr ""
@@ -8042,12 +8331,18 @@ msgstr ""
msgid "Delete"
msgstr "Изтриване"
+msgid "Delete %{name}"
+msgstr ""
+
msgid "Delete Comment"
msgstr ""
msgid "Delete Snippet"
msgstr ""
+msgid "Delete Value Stream"
+msgstr ""
+
msgid "Delete account"
msgstr ""
@@ -8069,9 +8364,6 @@ msgstr ""
msgid "Delete label: %{label_name} ?"
msgstr ""
-msgid "Delete license"
-msgstr ""
-
msgid "Delete list"
msgstr ""
@@ -8147,15 +8439,6 @@ msgstr ""
msgid "Deleting a project places it into a read-only state until %{date}, at which point the project will be permanently deleted. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "Deleting the license failed."
-msgstr ""
-
-msgid "Deleting the license failed. The license was not found."
-msgstr ""
-
-msgid "Deleting the license failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "Deleting the project will delete its repository and all related resources including issues, merge requests etc."
msgstr ""
@@ -8651,7 +8934,10 @@ msgstr ""
msgid "DesignManagement|The maximum number of designs allowed to be uploaded is %{upload_limit}. Please try again."
msgstr ""
-msgid "DesignManagement|To upload designs, you'll need to enable LFS. %{requirements_link_start}More information%{requirements_link_end}"
+msgid "DesignManagement|There was an error moving your designs. Please upload your designs below."
+msgstr ""
+
+msgid "DesignManagement|To upload designs, you'll need to enable LFS and have admin enable hashed storage. %{requirements_link_start}More information%{requirements_link_end}"
msgstr ""
msgid "DesignManagement|Unresolve thread"
@@ -8663,6 +8949,9 @@ msgstr ""
msgid "DesignManagement|Upload skipped."
msgstr ""
+msgid "DesignManagement|Your designs are being copied and are on their way… Please refresh to update."
+msgstr ""
+
msgid "DesignManagement|and %{moreCount} more."
msgstr ""
@@ -8720,6 +9009,9 @@ msgstr ""
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
+msgid "Direct member"
+msgstr ""
+
msgid "Direction"
msgstr ""
@@ -8768,9 +9060,6 @@ msgstr ""
msgid "Discard draft"
msgstr ""
-msgid "Discard review"
-msgstr ""
-
msgid "DiscordService|Discord Notifications"
msgstr ""
@@ -8839,10 +9128,10 @@ msgstr ""
msgid "Dismiss Merge Request promotion"
msgstr ""
-msgid "Dismiss Selected"
+msgid "Dismiss Value Stream Analytics introduction box"
msgstr ""
-msgid "Dismiss Value Stream Analytics introduction box"
+msgid "Dismiss selected"
msgstr ""
msgid "Dismiss trial promotion"
@@ -8893,9 +9182,6 @@ msgstr ""
msgid "Documents reindexed: %{processed_documents} (%{percentage}%%)"
msgstr ""
-msgid "Doing"
-msgstr ""
-
msgid "Domain"
msgstr ""
@@ -9091,9 +9377,6 @@ msgstr ""
msgid "Edit environment"
msgstr ""
-msgid "Edit file"
-msgstr ""
-
msgid "Edit files in the editor and commit changes here"
msgstr ""
@@ -9106,6 +9389,12 @@ msgstr ""
msgid "Edit identity for %{user_name}"
msgstr ""
+msgid "Edit in Web IDE"
+msgstr ""
+
+msgid "Edit in single-file editor"
+msgstr ""
+
msgid "Edit issues"
msgstr ""
@@ -9133,10 +9422,10 @@ msgstr ""
msgid "Editing"
msgstr ""
-msgid "Elasticsearch"
+msgid "Elasticsearch AWS IAM credentials"
msgstr ""
-msgid "Elasticsearch AWS IAM credentials"
+msgid "Elasticsearch HTTP client timeout value in seconds."
msgstr ""
msgid "Elasticsearch indexing restrictions"
@@ -9145,9 +9434,6 @@ msgstr ""
msgid "Elasticsearch indexing started"
msgstr ""
-msgid "Elasticsearch integration. Elasticsearch AWS IAM."
-msgstr ""
-
msgid "Elasticsearch reindexing is already in progress"
msgstr ""
@@ -9175,9 +9461,6 @@ msgstr ""
msgid "Email Notification"
msgstr ""
-msgid "Email address"
-msgstr ""
-
msgid "Email could not be sent"
msgstr ""
@@ -9241,6 +9524,9 @@ msgstr ""
msgid "Emails sent from Service Desk will have this name"
msgstr ""
+msgid "Emails sent to %{email} will still be supported"
+msgstr ""
+
msgid "Emails separated by comma"
msgstr ""
@@ -9274,9 +9560,18 @@ msgstr ""
msgid "Enable"
msgstr ""
+msgid "Enable %{link_start}Gitpod%{link_end} integration to launch a development environment in your browser directly from GitLab."
+msgstr ""
+
msgid "Enable Auto DevOps"
msgstr ""
+msgid "Enable Gitpod"
+msgstr ""
+
+msgid "Enable Gitpod?"
+msgstr ""
+
msgid "Enable HTML emails"
msgstr ""
@@ -9406,9 +9701,6 @@ msgstr ""
msgid "Encountered an error while rendering: %{err}"
msgstr ""
-msgid "End date"
-msgstr ""
-
msgid "Ends at (UTC)"
msgstr ""
@@ -9568,7 +9860,7 @@ msgstr ""
msgid "EnvironmentsDashboard|The environments dashboard provides a summary of each project's environments' status, including pipeline and alert statuses."
msgstr ""
-msgid "EnvironmentsDashboard|This dashboard displays a maximum of 7 projects and 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
+msgid "EnvironmentsDashboard|This dashboard displays 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
msgstr ""
msgid "Environments|An error occurred while canceling the auto stop, please try again"
@@ -9889,6 +10181,9 @@ msgstr ""
msgid "Error deleting project. Check logs for error details."
msgstr ""
+msgid "Error fetching burnup chart data"
+msgstr ""
+
msgid "Error fetching diverging counts for branches. Please try again."
msgstr ""
@@ -9967,6 +10262,9 @@ msgstr ""
msgid "Error occurred when saving assignees"
msgstr ""
+msgid "Error occurred when saving reviewers"
+msgstr ""
+
msgid "Error occurred when toggling the notification subscription"
msgstr ""
@@ -10219,10 +10517,13 @@ msgstr ""
msgid "Expand all"
msgstr ""
-msgid "Expand approvers"
+msgid "Expand all files"
msgstr ""
-msgid "Expand dropdown"
+msgid "Expand all threads"
+msgstr ""
+
+msgid "Expand approvers"
msgstr ""
msgid "Expand milestones"
@@ -10393,6 +10694,9 @@ msgstr ""
msgid "Failed to create Merge Request. Please try again."
msgstr ""
+msgid "Failed to create To-Do for the design."
+msgstr ""
+
msgid "Failed to create a branch for this issue. Please try again."
msgstr ""
@@ -10432,6 +10736,12 @@ msgstr ""
msgid "Failed to load authors. Please try again."
msgstr ""
+msgid "Failed to load branches. Please try again."
+msgstr ""
+
+msgid "Failed to load deploy keys."
+msgstr ""
+
msgid "Failed to load emoji list."
msgstr ""
@@ -10447,6 +10757,9 @@ msgstr ""
msgid "Failed to load groups & users."
msgstr ""
+msgid "Failed to load groups, users and deploy keys."
+msgstr ""
+
msgid "Failed to load labels. Please try again."
msgstr ""
@@ -10456,6 +10769,12 @@ msgstr ""
msgid "Failed to load related branches"
msgstr ""
+msgid "Failed to load sidebar confidential toggle"
+msgstr ""
+
+msgid "Failed to load sidebar lock status"
+msgstr ""
+
msgid "Failed to load stacktrace."
msgstr ""
@@ -10483,6 +10802,9 @@ msgstr ""
msgid "Failed to publish issue on status page."
msgstr ""
+msgid "Failed to remove To-Do for the design."
+msgstr ""
+
msgid "Failed to remove a Zoom meeting"
msgstr ""
@@ -10525,6 +10847,9 @@ msgstr ""
msgid "Failed to signing using smartcard authentication"
msgstr ""
+msgid "Failed to toggle To-Do for the design."
+msgstr ""
+
msgid "Failed to update branch!"
msgstr ""
@@ -10638,7 +10963,7 @@ msgstr ""
msgid "FeatureFlags|Edit User List"
msgstr ""
-msgid "FeatureFlags|Enable features for specific users and specific environments by defining feature flag strategies."
+msgid "FeatureFlags|Enable features for specific users and environments by configuring feature flag strategies."
msgstr ""
msgid "FeatureFlags|Environment Spec"
@@ -10698,7 +11023,7 @@ msgstr ""
msgid "FeatureFlags|Include additional user IDs"
msgstr ""
-msgid "FeatureFlags|Install a %{docs_link_anchored_start}compatible client library%{docs_link_anchored_end} and specify the API URL, application name, and instance ID during the configuration setup. %{docs_link_start}More Information%{docs_link_end}"
+msgid "FeatureFlags|Install a %{docsLinkAnchoredStart}compatible client library%{docsLinkAnchoredEnd} and specify the API URL, application name, and instance ID during the configuration setup. %{docsLinkStart}More Information%{docsLinkEnd}"
msgstr ""
msgid "FeatureFlags|Instance ID"
@@ -10710,6 +11035,9 @@ msgstr ""
msgid "FeatureFlags|Loading feature flags"
msgstr ""
+msgid "FeatureFlags|Loading user lists"
+msgstr ""
+
msgid "FeatureFlags|More information"
msgstr ""
@@ -10728,7 +11056,7 @@ msgstr ""
msgid "FeatureFlags|New feature flag"
msgstr ""
-msgid "FeatureFlags|New list"
+msgid "FeatureFlags|New user list"
msgstr ""
msgid "FeatureFlags|Percent of users"
@@ -10767,6 +11095,9 @@ msgstr ""
msgid "FeatureFlags|There was an error fetching the feature flags."
msgstr ""
+msgid "FeatureFlags|There was an error fetching the user lists."
+msgstr ""
+
msgid "FeatureFlags|There was an error retrieving user lists"
msgstr ""
@@ -10782,6 +11113,9 @@ msgstr ""
msgid "FeatureFlags|User List"
msgstr ""
+msgid "FeatureFlags|User Lists"
+msgstr ""
+
msgid "FeatureFlag|List"
msgstr ""
@@ -10809,15 +11143,6 @@ msgstr ""
msgid "Fetching incoming email"
msgstr ""
-msgid "Fetching licenses failed."
-msgstr ""
-
-msgid "Fetching licenses failed. The request endpoint was not found."
-msgstr ""
-
-msgid "Fetching licenses failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "File"
msgstr ""
@@ -10920,12 +11245,21 @@ msgstr ""
msgid "Filter by status"
msgstr ""
+msgid "Filter by test cases that are currently archived."
+msgstr ""
+
+msgid "Filter by test cases that are currently opened."
+msgstr ""
+
msgid "Filter by two-factor authentication"
msgstr ""
msgid "Filter by user"
msgstr ""
+msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
+msgstr ""
+
msgid "Filter pipelines"
msgstr ""
@@ -10941,7 +11275,7 @@ msgstr ""
msgid "Filter results..."
msgstr ""
-msgid "Filter your projects by name"
+msgid "Filter your repositories by name"
msgstr ""
msgid "Filter..."
@@ -10950,7 +11284,7 @@ msgstr ""
msgid "Find File"
msgstr ""
-msgid "Find bugs in your code with coverage-guided fuzzing"
+msgid "Find bugs in your code with coverage-guided fuzzing."
msgstr ""
msgid "Find by path"
@@ -10977,9 +11311,6 @@ msgstr ""
msgid "Finish editing this message first!"
msgstr ""
-msgid "Finish review"
-msgstr ""
-
msgid "Finish setting up your dedicated account for %{group_name}."
msgstr ""
@@ -11049,6 +11380,9 @@ msgstr ""
msgid "Footer message"
msgstr ""
+msgid "For a faster browsing experience, some files are collapsed by default."
+msgstr ""
+
msgid "For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
@@ -11058,6 +11392,9 @@ msgstr ""
msgid "For more info, read the documentation."
msgstr ""
+msgid "For more information on how the number of active users is calculated, see the %{self_managed_subscriptions_doc_link} documentation."
+msgstr ""
+
msgid "For more information, go to the "
msgstr ""
@@ -11196,6 +11533,9 @@ msgstr ""
msgid "Generate new token"
msgstr ""
+msgid "Generic package file size in bytes"
+msgstr ""
+
msgid "Geo"
msgstr ""
@@ -11457,6 +11797,9 @@ msgstr ""
msgid "Geo|Please refer to Geo Troubleshooting."
msgstr ""
+msgid "Geo|Primary node"
+msgstr ""
+
msgid "Geo|Project"
msgstr ""
@@ -11499,6 +11842,9 @@ msgstr ""
msgid "Geo|Review replication status, and resynchronize and reverify items with the primary node."
msgstr ""
+msgid "Geo|Secondary node"
+msgstr ""
+
msgid "Geo|Status"
msgstr ""
@@ -11538,6 +11884,9 @@ msgstr ""
msgid "Geo|URL must be a valid url (ex: https://gitlab.com)"
msgstr ""
+msgid "Geo|Undefined"
+msgstr ""
+
msgid "Geo|Unknown state"
msgstr ""
@@ -11613,10 +11962,16 @@ msgstr ""
msgid "GitHub import"
msgstr ""
+msgid "GitLab"
+msgstr ""
+
msgid "GitLab / Unsubscribe"
msgstr ""
-msgid "GitLab Enterprise Edition %{plan}"
+msgid "GitLab API"
+msgstr ""
+
+msgid "GitLab Billing Team."
msgstr ""
msgid "GitLab Group Runners can execute code for all the projects in this group."
@@ -11628,12 +11983,18 @@ msgstr ""
msgid "GitLab Issue"
msgstr ""
+msgid "GitLab Pages"
+msgstr ""
+
msgid "GitLab Service Desk is a simple way to allow people to create issues in your GitLab instance without needing their own user account. It provides a unique email address for end users to create issues in a project, and replies can be sent either through the GitLab interface or by email. End users will only see the thread through email."
msgstr ""
msgid "GitLab Shared Runners execute code of different projects on the same Runner unless you configure GitLab Runner Autoscale with MaxBuilds 1 (which it is on GitLab.com)."
msgstr ""
+msgid "GitLab Shell"
+msgstr ""
+
msgid "GitLab Support Bot"
msgstr ""
@@ -11643,7 +12004,7 @@ msgstr ""
msgid "GitLab User"
msgstr ""
-msgid "GitLab allows you to continue using your license even if you exceed the number of seats you purchased. You will be required to pay for these seats when you renew your license."
+msgid "GitLab Workhorse"
msgstr ""
msgid "GitLab commit"
@@ -11811,6 +12172,21 @@ msgstr ""
msgid "Gitlab Pages"
msgstr ""
+msgid "Gitpod"
+msgstr ""
+
+msgid "Gitpod|Add the URL to your Gitpod instance configured to read your GitLab projects."
+msgstr ""
+
+msgid "Gitpod|Enable Gitpod integration"
+msgstr ""
+
+msgid "Gitpod|Gitpod URL"
+msgstr ""
+
+msgid "Gitpod|e.g. https://gitpod.example.com"
+msgstr ""
+
msgid "Given access %{time_ago}"
msgstr ""
@@ -12318,9 +12694,6 @@ msgstr ""
msgid "GroupSAML|Valid SAML Response"
msgstr ""
-msgid "GroupSAML|With group managed accounts enabled, all the users without a group managed account will be excluded from the group."
-msgstr ""
-
msgid "GroupSAML|With prohibit outer forks flag enabled group members will be able to fork project only inside your group."
msgstr ""
@@ -12534,10 +12907,10 @@ msgstr ""
msgid "GroupsNew|Create group"
msgstr ""
-msgid "GroupsNew|GitLab group export"
+msgid "GroupsNew|Import"
msgstr ""
-msgid "GroupsNew|Import"
+msgid "GroupsNew|Import a GitLab group export file"
msgstr ""
msgid "GroupsNew|Import group"
@@ -12680,6 +13053,9 @@ msgid_plural "Hide charts"
msgstr[0] ""
msgstr[1] ""
+msgid "Hide comments on this file"
+msgstr ""
+
msgid "Hide details"
msgstr ""
@@ -12724,6 +13100,15 @@ msgstr ""
msgid "Highest role:"
msgstr ""
+msgid "HighlightBar|Alert events:"
+msgstr ""
+
+msgid "HighlightBar|Alert start time:"
+msgstr ""
+
+msgid "HighlightBar|Original alert:"
+msgstr ""
+
msgid "History"
msgstr ""
@@ -12901,6 +13286,9 @@ msgstr ""
msgid "If enabled, access to projects will be validated on an external service using their classification label."
msgstr ""
+msgid "If the number of active users exceeds the user limit, you will be charged for the number of %{users_over_license_link} at your next license reconciliation."
+msgstr ""
+
msgid "If there is no previous license or if the previous license has expired, some GitLab functionality will be blocked until a new, valid license is uploaded."
msgstr ""
@@ -12940,9 +13328,6 @@ msgstr ""
msgid "If your HTTP repository is not publicly accessible, add your credentials."
msgstr ""
-msgid "Iglu registry URL (optional)"
-msgstr ""
-
msgid "Ignore"
msgstr ""
@@ -12979,6 +13364,16 @@ msgstr ""
msgid "Import"
msgstr ""
+msgid "Import %d compatible repository"
+msgid_plural "Import %d compatible repositories"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Import %d repository"
+msgid_plural "Import %d repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Import CSV"
msgstr ""
@@ -12988,15 +13383,9 @@ msgstr ""
msgid "Import all compatible projects"
msgstr ""
-msgid "Import all compatible repositories"
-msgstr ""
-
msgid "Import all projects"
msgstr ""
-msgid "Import all repositories"
-msgstr ""
-
msgid "Import an exported GitLab project"
msgstr ""
@@ -13084,6 +13473,9 @@ msgstr ""
msgid "ImportProjects|Error importing repository %{project_safe_import_url} into %{project_full_path} - %{message}"
msgstr ""
+msgid "ImportProjects|Import repositories"
+msgstr ""
+
msgid "ImportProjects|Importing the project failed"
msgstr ""
@@ -13096,7 +13488,7 @@ msgstr ""
msgid "ImportProjects|Requesting your %{provider} repositories failed"
msgstr ""
-msgid "ImportProjects|Select the projects you want to import"
+msgid "ImportProjects|Select the repositories you want to import"
msgstr ""
msgid "ImportProjects|The remote data could not be imported."
@@ -13132,9 +13524,6 @@ msgstr ""
msgid "In order to enable Service Desk for your instance, you must first set up incoming email."
msgstr ""
-msgid "In order to gather accurate feature usage data, it can take 1 to 2 weeks to see your index."
-msgstr ""
-
msgid "In order to personalize your experience with GitLab%{br_tag}we would like to know a bit more about you."
msgstr ""
@@ -13165,18 +13554,30 @@ msgstr ""
msgid "IncidentManagement|Create incident"
msgstr ""
+msgid "IncidentManagement|Critical - S1"
+msgstr ""
+
msgid "IncidentManagement|Date created"
msgstr ""
msgid "IncidentManagement|Display your incidents in a dedicated view"
msgstr ""
+msgid "IncidentManagement|High - S2"
+msgstr ""
+
msgid "IncidentManagement|Incident"
msgstr ""
msgid "IncidentManagement|Incidents"
msgstr ""
+msgid "IncidentManagement|Low - S4"
+msgstr ""
+
+msgid "IncidentManagement|Medium - S3"
+msgstr ""
+
msgid "IncidentManagement|No incidents to display."
msgstr ""
@@ -13189,6 +13590,9 @@ msgstr ""
msgid "IncidentManagement|Published to status page"
msgstr ""
+msgid "IncidentManagement|Severity"
+msgstr ""
+
msgid "IncidentManagement|There are no closed incidents"
msgstr ""
@@ -13198,6 +13602,9 @@ msgstr ""
msgid "IncidentManagement|Unassigned"
msgstr ""
+msgid "IncidentManagement|Unknown"
+msgstr ""
+
msgid "IncidentManagement|Unpublished"
msgstr ""
@@ -13219,6 +13626,15 @@ msgstr ""
msgid "Incidents"
msgstr ""
+msgid "Incident|Alert details"
+msgstr ""
+
+msgid "Incident|Summary"
+msgstr ""
+
+msgid "Incident|There was an issue loading alert data. Please try again."
+msgstr ""
+
msgid "Include a Terms of Service agreement and Privacy Policy that all users must accept."
msgstr ""
@@ -13279,6 +13695,9 @@ msgstr ""
msgid "Information about additional Pages templates and how to install them can be found in our %{pages_getting_started_guide}."
msgstr ""
+msgid "Inherited"
+msgstr ""
+
msgid "Inherited:"
msgstr ""
@@ -13359,7 +13778,22 @@ msgstr ""
msgid "Instance administrators group already exists"
msgstr ""
-msgid "Instance license"
+msgid "InstanceStatistics|Groups"
+msgstr ""
+
+msgid "InstanceStatistics|Issues"
+msgstr ""
+
+msgid "InstanceStatistics|Merge Requests"
+msgstr ""
+
+msgid "InstanceStatistics|Pipelines"
+msgstr ""
+
+msgid "InstanceStatistics|Projects"
+msgstr ""
+
+msgid "InstanceStatistics|Users"
msgstr ""
msgid "Integration"
@@ -13371,6 +13805,12 @@ msgstr ""
msgid "Integrations"
msgstr ""
+msgid "Integrations|%{integration} settings saved and active."
+msgstr ""
+
+msgid "Integrations|%{integration} settings saved, but not active."
+msgstr ""
+
msgid "Integrations|All details"
msgstr ""
@@ -13380,6 +13820,12 @@ msgstr ""
msgid "Integrations|Comment settings:"
msgstr ""
+msgid "Integrations|Connection failed. Please check your settings."
+msgstr ""
+
+msgid "Integrations|Connection successful."
+msgstr ""
+
msgid "Integrations|Default settings are inherited from the group level."
msgstr ""
@@ -13395,6 +13841,15 @@ msgstr ""
msgid "Integrations|Includes commit title and branch"
msgstr ""
+msgid "Integrations|Projects using custom settings will not be impacted unless the project owner chooses to use instance-level defaults."
+msgstr ""
+
+msgid "Integrations|Save settings?"
+msgstr ""
+
+msgid "Integrations|Saving will update the default settings for all projects that are not using custom settings."
+msgstr ""
+
msgid "Integrations|Standard"
msgstr ""
@@ -13527,6 +13982,9 @@ msgstr ""
msgid "Invitation"
msgstr ""
+msgid "Invitation declined"
+msgstr ""
+
msgid "Invite"
msgstr ""
@@ -13578,6 +14036,42 @@ 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|%{linkStart}Read more%{linkEnd} about role permissions"
+msgstr ""
+
+msgid "InviteMembersModal|Access expiration date (optional)"
+msgstr ""
+
+msgid "InviteMembersModal|Cancel"
+msgstr ""
+
+msgid "InviteMembersModal|Choose a role permission"
+msgstr ""
+
+msgid "InviteMembersModal|GitLab member or Email address"
+msgstr ""
+
+msgid "InviteMembersModal|Invite"
+msgstr ""
+
+msgid "InviteMembersModal|Invite team members"
+msgstr ""
+
+msgid "InviteMembersModal|Search for members to invite"
+msgstr ""
+
+msgid "InviteMembersModal|User not invited. Feature coming soon!"
+msgstr ""
+
+msgid "InviteMembersModal|Users were succesfully added"
+msgstr ""
+
+msgid "InviteMembersModal|You're inviting members to the %{group_name} group"
+msgstr ""
+
+msgid "InviteMembers|Invite team members"
+msgstr ""
+
msgid "Invited"
msgstr ""
@@ -13632,10 +14126,13 @@ msgstr ""
msgid "Issue cannot be found."
msgstr ""
+msgid "Issue created from vulnerability %{vulnerability_link}"
+msgstr ""
+
msgid "Issue events"
msgstr ""
-msgid "Issue first depoloyed to production"
+msgid "Issue first deployed to production"
msgstr ""
msgid "Issue label"
@@ -13713,6 +14210,9 @@ msgstr ""
msgid "IssueTracker|Custom issue tracker"
msgstr ""
+msgid "IssueTracker|EWM work items tracker"
+msgstr ""
+
msgid "IssueTracker|Redmine issue tracker"
msgstr ""
@@ -13779,6 +14279,9 @@ msgstr ""
msgid "It looks like you have some draft commits in this branch."
msgstr ""
+msgid "It may be several days before you see feature usage data."
+msgstr ""
+
msgid "It must have a header row and at least two columns: the first column is the issue title and the second column is the issue description. The separator is automatically detected."
msgstr ""
@@ -14061,13 +14564,13 @@ msgstr ""
msgid "Join Zoom meeting"
msgstr ""
-msgid "Jul"
+msgid "Joined %{time_ago}"
msgstr ""
-msgid "July"
+msgid "Jul"
msgstr ""
-msgid "Jump to first unresolved thread"
+msgid "July"
msgstr ""
msgid "Jump to next unresolved thread"
@@ -14103,6 +14606,9 @@ msgstr ""
msgid "Keyboard shortcuts"
msgstr ""
+msgid "KeyboardKey|Ctrl+"
+msgstr ""
+
msgid "Keys"
msgstr ""
@@ -14151,6 +14657,9 @@ msgstr ""
msgid "LDAP Synchronization"
msgstr ""
+msgid "LDAP group settings"
+msgstr ""
+
msgid "LDAP settings"
msgstr ""
@@ -14160,6 +14669,9 @@ msgstr ""
msgid "LDAP sync in progress. This could take a few minutes. Refresh the page to see the changes."
msgstr ""
+msgid "LDAP synchronizations"
+msgstr ""
+
msgid "LFS"
msgstr ""
@@ -14240,7 +14752,16 @@ msgid_plural "Last %d days"
msgstr[0] "ПоÑÐ»ÐµÐ´Ð½Ð¸Ñ %d ден"
msgstr[1] "ПоÑледните %d дни"
-msgid "Last %{days} days"
+msgid "Last 2 weeks"
+msgstr ""
+
+msgid "Last 30 days"
+msgstr ""
+
+msgid "Last 60 days"
+msgstr ""
+
+msgid "Last 90 days"
msgstr ""
msgid "Last Accessed On"
@@ -14318,6 +14839,9 @@ msgstr ""
msgid "Last used on:"
msgstr ""
+msgid "Last week"
+msgstr ""
+
msgid "LastCommit|authored"
msgstr ""
@@ -14333,6 +14857,9 @@ msgstr ""
msgid "Latest pipeline for the most recent commit on this branch"
msgstr ""
+msgid "Launch a ready-to-code development environment for your project."
+msgstr ""
+
msgid "Lead"
msgstr ""
@@ -14713,6 +15240,9 @@ msgstr ""
msgid "List of all merge commits"
msgstr ""
+msgid "List options"
+msgstr ""
+
msgid "List settings"
msgstr ""
@@ -14725,9 +15255,6 @@ msgstr ""
msgid "List your Bitbucket Server repositories"
msgstr ""
-msgid "Lists"
-msgstr ""
-
msgid "Live preview"
msgstr ""
@@ -14974,6 +15501,12 @@ msgstr ""
msgid "Mark as done"
msgstr ""
+msgid "Mark as draft"
+msgstr ""
+
+msgid "Mark as ready"
+msgstr ""
+
msgid "Mark as resolved"
msgstr ""
@@ -14995,6 +15528,24 @@ msgstr ""
msgid "Markdown is supported"
msgstr ""
+msgid "MarkdownEditor|Add a link (%{modifierKey}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add a link (%{modifier_key}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifierKey}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifier_key}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifierKey}I)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifier_key}I)"
+msgstr ""
+
msgid "Marked For Deletion At - %{deletion_time}"
msgstr ""
@@ -15079,7 +15630,25 @@ msgstr ""
msgid "Max access level"
msgstr ""
-msgid "Max seats used"
+msgid "Max role"
+msgstr ""
+
+msgid "Max size 15 MB"
+msgstr ""
+
+msgid "Maximum Conan package file size in bytes"
+msgstr ""
+
+msgid "Maximum Maven package file size in bytes"
+msgstr ""
+
+msgid "Maximum NPM package file size in bytes"
+msgstr ""
+
+msgid "Maximum NuGet package file size in bytes"
+msgstr ""
+
+msgid "Maximum PyPI package file size in bytes"
msgstr ""
msgid "Maximum Users:"
@@ -15211,6 +15780,18 @@ msgstr ""
msgid "Members with access to %{strong_start}%{group_name}%{strong_end}"
msgstr ""
+msgid "Members|%{time} by %{user}"
+msgstr ""
+
+msgid "Members|Expired"
+msgstr ""
+
+msgid "Members|No expiration set"
+msgstr ""
+
+msgid "Members|in %{time}"
+msgstr ""
+
msgid "Memory Usage"
msgstr ""
@@ -15397,9 +15978,6 @@ msgstr ""
msgid "MergeRequests|Thread will be unresolved"
msgstr ""
-msgid "MergeRequests|Toggle comments for this file"
-msgstr ""
-
msgid "MergeRequests|View file @ %{commitId}"
msgstr ""
@@ -15460,6 +16038,9 @@ msgstr ""
msgid "Merging immediately isn't recommended as it may negatively impact the existing merge train. Read the %{docsLinkStart}documentation%{docsLinkEnd} for more information."
msgstr ""
+msgid "Message"
+msgstr ""
+
msgid "Messages"
msgstr ""
@@ -15845,18 +16426,12 @@ msgid_plural "Milestones"
msgstr[0] ""
msgstr[1] ""
-msgid "Milestone does not support burnup charts"
-msgstr ""
-
msgid "Milestone lists not available with your current license"
msgstr ""
msgid "Milestone lists show all issues from the selected milestone."
msgstr ""
-msgid "Milestone must have a start and due date"
-msgstr ""
-
msgid "MilestoneSidebar|Closed:"
msgstr ""
@@ -16223,6 +16798,9 @@ msgstr ""
msgid "Namespace"
msgstr ""
+msgid "Namespace ID:"
+msgstr ""
+
msgid "Namespace is empty"
msgstr ""
@@ -16307,6 +16885,9 @@ msgstr ""
msgid "NetworkPolicies|Allow all outbound traffic from %{selector} to %{ruleSelector} on %{ports}"
msgstr ""
+msgid "NetworkPolicies|Are you sure you want to delete this policy? This action cannot be undone."
+msgstr ""
+
msgid "NetworkPolicies|Choose whether to enforce this policy."
msgstr ""
@@ -16316,12 +16897,21 @@ msgstr ""
msgid "NetworkPolicies|Define this policy's location, conditions and actions."
msgstr ""
+msgid "NetworkPolicies|Delete policy"
+msgstr ""
+
+msgid "NetworkPolicies|Delete policy: %{policy}"
+msgstr ""
+
msgid "NetworkPolicies|Deny all traffic"
msgstr ""
msgid "NetworkPolicies|Description"
msgstr ""
+msgid "NetworkPolicies|Edit policy"
+msgstr ""
+
msgid "NetworkPolicies|Editor mode"
msgstr ""
@@ -16349,6 +16939,9 @@ msgstr ""
msgid "NetworkPolicies|Name"
msgstr ""
+msgid "NetworkPolicies|Namespace"
+msgstr ""
+
msgid "NetworkPolicies|Network Policy"
msgstr ""
@@ -16400,6 +16993,9 @@ msgstr ""
msgid "NetworkPolicies|Rules"
msgstr ""
+msgid "NetworkPolicies|Save changes"
+msgstr ""
+
msgid "NetworkPolicies|Something went wrong, failed to update policy"
msgstr ""
@@ -16412,6 +17008,9 @@ msgstr ""
msgid "NetworkPolicies|Traffic that does not match any rule will be blocked."
msgstr ""
+msgid "NetworkPolicies|Unable to parse policy"
+msgstr ""
+
msgid "NetworkPolicies|YAML editor"
msgstr ""
@@ -16525,6 +17124,9 @@ msgstr ""
msgid "New Snippet"
msgstr ""
+msgid "New Test Case"
+msgstr ""
+
msgid "New User"
msgstr ""
@@ -16624,6 +17226,9 @@ msgstr ""
msgid "New tag"
msgstr "Ðов етикет"
+msgid "New test case"
+msgstr ""
+
msgid "New users set to external"
msgstr ""
@@ -16696,7 +17301,7 @@ msgstr ""
msgid "No changes"
msgstr ""
-msgid "No changes between %{ref_start}%{source_branch}%{ref_end} and %{ref_start}%{target_branch}%{ref_end}"
+msgid "No changes between %{sourceBranch} and %{targetBranch}"
msgstr ""
msgid "No child epics match applied filters"
@@ -16711,6 +17316,9 @@ msgstr ""
msgid "No containers available"
msgstr ""
+msgid "No content to show"
+msgstr ""
+
msgid "No contributions"
msgstr ""
@@ -16786,9 +17394,6 @@ msgstr ""
msgid "No license. All rights reserved"
msgstr ""
-msgid "No licenses found."
-msgstr ""
-
msgid "No matches found"
msgstr ""
@@ -16801,6 +17406,9 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No members found"
+msgstr ""
+
msgid "No merge requests found"
msgstr ""
@@ -16822,6 +17430,9 @@ msgstr ""
msgid "No parent group"
msgstr ""
+msgid "No plan"
+msgstr ""
+
msgid "No pods available"
msgstr ""
@@ -16918,6 +17529,12 @@ msgstr ""
msgid "Not Implemented"
msgstr ""
+msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+msgstr ""
+
+msgid "Not all browsers support WebAuthn. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even from an unsupported browser."
+msgstr ""
+
msgid "Not all data has been processed yet, the accuracy of the chart for the selected timeframe is limited."
msgstr ""
@@ -17014,6 +17631,9 @@ msgstr ""
msgid "Notification settings saved"
msgstr ""
+msgid "NotificationEvent|Change reviewer merge request"
+msgstr ""
+
msgid "NotificationEvent|Close issue"
msgstr "ЗатварÑне на проблем"
@@ -17176,10 +17796,7 @@ msgstr ""
msgid "On track"
msgstr ""
-msgid "OnDemandScans|Attached branch"
-msgstr ""
-
-msgid "OnDemandScans|Attached branch is where the scan job runs."
+msgid "OnDemandScans|Could not fetch scanner profiles. Please refresh the page, or try again later."
msgstr ""
msgid "OnDemandScans|Could not fetch site profiles. Please refresh the page, or try again later."
@@ -17188,6 +17805,9 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
+msgid "OnDemandScans|Create a new scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Create a new site profile"
msgstr ""
@@ -17200,6 +17820,9 @@ msgstr ""
msgid "OnDemandScans|New on-demand DAST scan"
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 ""
@@ -17209,16 +17832,10 @@ msgstr ""
msgid "OnDemandScans|On-demand scans run outside the DevOps cycle and find vulnerabilities in your projects. %{learnMoreLinkStart}Learn more%{learnMoreLinkEnd}"
msgstr ""
-msgid "OnDemandScans|Only a passive scan can be performed on demand."
-msgstr ""
-
-msgid "OnDemandScans|Passive"
-msgstr ""
-
msgid "OnDemandScans|Run scan"
msgstr ""
-msgid "OnDemandScans|Scan mode"
+msgid "OnDemandScans|Scanner profile"
msgstr ""
msgid "OnDemandScans|Scanner settings"
@@ -17230,9 +17847,15 @@ msgstr ""
msgid "OnDemandScans|Select one of the existing profiles"
msgstr ""
+msgid "OnDemandScans|Site profile"
+msgstr ""
+
msgid "OnDemandScans|Site profiles"
msgstr ""
+msgid "OnDemandScans|Use existing scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Use existing site profile"
msgstr ""
@@ -17331,9 +17954,6 @@ msgstr ""
msgid "Open Selection"
msgstr ""
-msgid "Open Web IDE"
-msgstr ""
-
msgid "Open comment type dropdown"
msgstr ""
@@ -17439,6 +18059,9 @@ msgstr ""
msgid "Origin"
msgstr ""
+msgid "Orphaned member"
+msgstr ""
+
msgid "Other Labels"
msgstr ""
@@ -17454,6 +18077,9 @@ msgstr ""
msgid "Other visibility settings have been disabled by the administrator."
msgstr ""
+msgid "Our documentation includes an example DevOps Score report."
+msgstr ""
+
msgid "Out-of-compliance with this project's policies and should be removed"
msgstr ""
@@ -17478,6 +18104,9 @@ msgstr ""
msgid "Overwrite diverged branches"
msgstr ""
+msgid "Owned by %{image_tag}"
+msgstr ""
+
msgid "Owned by anyone"
msgstr ""
@@ -17499,6 +18128,9 @@ msgstr ""
msgid "Package deleted successfully"
msgstr ""
+msgid "Package file size limits"
+msgstr ""
+
msgid "Package recipe already exists"
msgstr ""
@@ -17514,9 +18146,6 @@ msgstr ""
msgid "Package type must be PyPi"
msgstr ""
-msgid "Package was removed"
-msgstr ""
-
msgid "PackageRegistry|%{name} version %{version} was created %{datetime}"
msgstr ""
@@ -17658,12 +18287,18 @@ msgstr ""
msgid "PackageRegistry|NuGet Command"
msgstr ""
+msgid "PackageRegistry|Package Registry"
+msgstr ""
+
msgid "PackageRegistry|Pip Command"
msgstr ""
msgid "PackageRegistry|Pipeline %{link} triggered %{datetime} by %{author}"
msgstr ""
+msgid "PackageRegistry|Publish and share packages for a variety of common package managers. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "PackageRegistry|Published to the %{project} Package Registry %{datetime}"
msgstr ""
@@ -17763,6 +18398,9 @@ msgstr ""
msgid "Page not found"
msgstr ""
+msgid "Page settings"
+msgstr ""
+
msgid "Page was successfully deleted"
msgstr ""
@@ -17904,7 +18542,7 @@ msgstr ""
msgid "Paste issue link"
msgstr ""
-msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Don't use your private SSH key."
+msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Do not paste your private SSH key, as that can compromise your identity."
msgstr ""
msgid "Patch to apply"
@@ -17931,6 +18569,9 @@ msgstr ""
msgid "Pending"
msgstr ""
+msgid "Pending comments"
+msgstr ""
+
msgid "People without permission will never get a notification and won't be able to comment."
msgstr ""
@@ -18129,6 +18770,9 @@ msgstr ""
msgid "Pipelines|Build with confidence"
msgstr ""
+msgid "Pipelines|By revoking a trigger you will break any processes making use of it. Are you sure?"
+msgstr ""
+
msgid "Pipelines|CI Lint"
msgstr ""
@@ -18141,6 +18785,15 @@ msgstr ""
msgid "Pipelines|Continuous Integration can help catch bugs by running your tests automatically, while Continuous Deployment can help you deliver code to your product environment."
msgstr ""
+msgid "Pipelines|Copy trigger token"
+msgstr ""
+
+msgid "Pipelines|Description"
+msgstr ""
+
+msgid "Pipelines|Edit"
+msgstr ""
+
msgid "Pipelines|Get started with Pipelines"
msgstr ""
@@ -18156,15 +18809,27 @@ msgstr ""
msgid "Pipelines|It is recommended the code is reviewed thoroughly before running this pipeline with the parent project's CI resource."
msgstr ""
+msgid "Pipelines|Last Used"
+msgstr ""
+
msgid "Pipelines|Loading Pipelines"
msgstr ""
msgid "Pipelines|More Information"
msgstr ""
+msgid "Pipelines|No triggers have been created yet. Add one using the form above."
+msgstr ""
+
+msgid "Pipelines|Owner"
+msgstr ""
+
msgid "Pipelines|Project cache successfully reset."
msgstr ""
+msgid "Pipelines|Revoke"
+msgstr ""
+
msgid "Pipelines|Run Pipeline"
msgstr ""
@@ -18189,6 +18854,15 @@ msgstr ""
msgid "Pipelines|This project is not currently set up to run pipelines."
msgstr ""
+msgid "Pipelines|Token"
+msgstr ""
+
+msgid "Pipelines|Trigger user has insufficient permissions to project"
+msgstr ""
+
+msgid "Pipelines|invalid"
+msgstr ""
+
msgid "Pipelines|parent"
msgstr ""
@@ -18447,10 +19121,10 @@ msgstr ""
msgid "Please provide attributes to update"
msgstr ""
-msgid "Please refer to %{docs_url}"
+msgid "Please reach out if you have any questions and we'll be happy to assist."
msgstr ""
-msgid "Please retype the email address."
+msgid "Please refer to %{docs_url}"
msgstr ""
msgid "Please select"
@@ -18480,6 +19154,9 @@ msgstr ""
msgid "Please set a new password before proceeding."
msgstr ""
+msgid "Please share your feedback about %{featureName} %{linkStart}in this issue%{linkEnd} to help us improve the experience."
+msgstr ""
+
msgid "Please solve the reCAPTCHA"
msgstr ""
@@ -18783,6 +19460,9 @@ msgstr ""
msgid "Profiles| You are going to change the username %{currentUsernameBold} to %{newUsernameBold}. Profile and projects will be redirected to the %{newUsername} namespace but this redirect will expire once the %{currentUsername} namespace is registered by another user or group. Please update your Git repository remotes as soon as possible."
msgstr ""
+msgid "Profiles|%{provider} Active"
+msgstr ""
+
msgid "Profiles|@username"
msgstr ""
@@ -18834,7 +19514,7 @@ msgstr ""
msgid "Profiles|Commit email"
msgstr ""
-msgid "Profiles|Connect"
+msgid "Profiles|Connect %{provider}"
msgstr ""
msgid "Profiles|Connected Accounts"
@@ -18858,6 +19538,9 @@ msgstr ""
msgid "Profiles|Disconnect"
msgstr ""
+msgid "Profiles|Disconnect %{provider}"
+msgstr ""
+
msgid "Profiles|Do not show on profile"
msgstr ""
@@ -18882,7 +19565,7 @@ msgstr ""
msgid "Profiles|Full name"
msgstr ""
-msgid "Profiles|Give your individual key a title. This will be publically visible."
+msgid "Profiles|Give your individual key a title."
msgstr ""
msgid "Profiles|Include private contributions on my profile"
@@ -18972,7 +19655,7 @@ msgstr ""
msgid "Profiles|The maximum file size allowed is 200KB."
msgstr ""
-msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it?"
+msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it? It will be publicly visible."
msgstr ""
msgid "Profiles|This email will be displayed on your public profile"
@@ -19047,6 +19730,9 @@ msgstr ""
msgid "Profiles|You don't have access to delete this user."
msgstr ""
+msgid "Profiles|You must transfer ownership or delete groups you are an owner of before you can delete your account"
+msgstr ""
+
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
@@ -19635,6 +20321,9 @@ msgstr ""
msgid "ProjectTemplates|GitLab Cluster Management"
msgstr ""
+msgid "ProjectTemplates|Gitpod/Spring Petclinic"
+msgstr ""
+
msgid "ProjectTemplates|Go Micro"
msgstr ""
@@ -20244,6 +20933,9 @@ msgstr ""
msgid "Publish to status page"
msgstr ""
+msgid "Published"
+msgstr ""
+
msgid "Published on status page"
msgstr ""
@@ -20361,9 +21053,15 @@ msgstr ""
msgid "Quick range"
msgstr ""
+msgid "Quickly and easily edit multiple files in your project."
+msgstr ""
+
msgid "README"
msgstr ""
+msgid "Rails"
+msgstr ""
+
msgid "Rake Tasks Help"
msgstr ""
@@ -20483,10 +21181,13 @@ msgstr ""
msgid "Register Two-Factor Authenticator"
msgstr ""
-msgid "Register U2F device"
+msgid "Register Universal Two-Factor (U2F) Device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register WebAuthn Device"
+msgstr ""
+
+msgid "Register device"
msgstr ""
msgid "Register for GitLab"
@@ -20498,9 +21199,6 @@ msgstr ""
msgid "Register with two-factor app"
msgstr ""
-msgid "Registration"
-msgstr ""
-
msgid "Registration|Checkout"
msgstr ""
@@ -20617,9 +21315,6 @@ msgstr ""
msgid "Release|Something went wrong while saving the release details"
msgstr ""
-msgid "Remediated: needs review"
-msgstr ""
-
msgid "Remediations"
msgstr ""
@@ -20725,6 +21420,9 @@ msgstr ""
msgid "Remove priority"
msgstr ""
+msgid "Remove report"
+msgstr ""
+
msgid "Remove secondary node"
msgstr ""
@@ -20737,6 +21435,12 @@ msgstr ""
msgid "Remove time estimate"
msgstr ""
+msgid "Remove user & report"
+msgstr ""
+
+msgid "Remove user from group"
+msgstr ""
+
msgid "Removed"
msgstr ""
@@ -20818,9 +21522,6 @@ msgstr ""
msgid "Removes time estimate."
msgstr ""
-msgid "Removing license…"
-msgstr ""
-
msgid "Removing this group also removes all child projects, including archived projects, and their resources."
msgstr ""
@@ -20905,6 +21606,9 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
+msgid "Reported by %{reporter}"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -20991,6 +21695,27 @@ msgstr ""
msgid "Repositories"
msgstr ""
+msgid "Repositories Analytics"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download Historic Test Coverage Data"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download historic test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Historic Test Coverage Data is available in raw format (.csv) for further analysis."
+msgstr ""
+
+msgid "RepositoriesAnalytics|Test Code Coverage"
+msgstr ""
+
+msgid "RepositoriesAnalytics|There was an error fetching the projects."
+msgstr ""
+
msgid "Repository"
msgstr ""
@@ -21069,9 +21794,15 @@ msgstr ""
msgid "Request parameter %{param} is missing."
msgstr ""
+msgid "Request review from"
+msgstr ""
+
msgid "Request to link SAML account must be authorized"
msgstr ""
+msgid "Requested"
+msgstr ""
+
msgid "Requested %{time_ago}"
msgstr ""
@@ -21090,6 +21821,9 @@ msgstr ""
msgid "Requests to these domain(s)/address(es) on the local network will be allowed when local requests from hooks and services are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 or 127.0.0.0/28 are supported. Domain wildcards are not supported currently. Use comma, semicolon, or newline to separate multiple entries. The allowlist can hold a maximum of 1000 entries. Domains should use IDNA encoding. Ex: example.com, 192.168.1.1, 127.0.0.0/28, xn--itlab-j1a.com."
msgstr ""
+msgid "Require admin approval for new sign-ups"
+msgstr ""
+
msgid "Require all users in this group to setup Two-factor authentication"
msgstr ""
@@ -21217,9 +21951,6 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
-msgid "Resolved by %{resolvedByName}"
-msgstr ""
-
msgid "Resolves IP addresses once and uses them to submit requests"
msgstr ""
@@ -21339,6 +22070,14 @@ msgstr ""
msgid "ReviewApp|Enable Review App"
msgstr ""
+msgid "Reviewer"
+msgid_plural "%d Reviewers"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Reviewer(s)"
+msgstr ""
+
msgid "Reviewing"
msgstr ""
@@ -21378,6 +22117,9 @@ msgstr ""
msgid "Rook"
msgstr ""
+msgid "Ruby"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -21456,6 +22198,63 @@ msgstr ""
msgid "Runners page."
msgstr ""
+msgid "Runners|Active"
+msgstr ""
+
+msgid "Runners|Architecture"
+msgstr ""
+
+msgid "Runners|Can run untagged jobs"
+msgstr ""
+
+msgid "Runners|Description"
+msgstr ""
+
+msgid "Runners|Group"
+msgstr ""
+
+msgid "Runners|IP Address"
+msgstr ""
+
+msgid "Runners|Last contact"
+msgstr ""
+
+msgid "Runners|Locked to this project"
+msgstr ""
+
+msgid "Runners|Maximum job timeout"
+msgstr ""
+
+msgid "Runners|Name"
+msgstr ""
+
+msgid "Runners|Platform"
+msgstr ""
+
+msgid "Runners|Property Name"
+msgstr ""
+
+msgid "Runners|Protected"
+msgstr ""
+
+msgid "Runners|Revision"
+msgstr ""
+
+msgid "Runners|Shared"
+msgstr ""
+
+msgid "Runners|Specific"
+msgstr ""
+
+msgid "Runners|Tags"
+msgstr ""
+
+msgid "Runners|Value"
+msgstr ""
+
+msgid "Runners|Version"
+msgstr ""
+
msgid "Runners|You have used %{quotaUsed} out of %{quotaLimit} of your shared Runners pipeline minutes."
msgstr ""
@@ -21468,6 +22267,9 @@ msgstr ""
msgid "Runs a number of housekeeping tasks within the current repository, such as compressing file revisions and removing unreachable objects."
msgstr ""
+msgid "SAML"
+msgstr ""
+
msgid "SAML SSO"
msgstr ""
@@ -21519,6 +22321,9 @@ msgstr ""
msgid "Save"
msgstr ""
+msgid "Save %{name} size limits"
+msgstr ""
+
msgid "Save Changes"
msgstr ""
@@ -21549,9 +22354,6 @@ msgstr "Запазване на плана за Ñхема"
msgid "Save space and find tags in the Container Registry more easily. Enable the cleanup policy to remove stale tags and keep only the ones you need."
msgstr ""
-msgid "Save template"
-msgstr ""
-
msgid "Save variables"
msgstr ""
@@ -21594,9 +22396,6 @@ msgstr "Планиране на Ñхемите"
msgid "Scope"
msgstr ""
-msgid "Scope not supported with disabled 'users_search' feature!"
-msgstr ""
-
msgid "Scoped issue boards"
msgstr ""
@@ -21723,9 +22522,6 @@ msgstr ""
msgid "Search requirements"
msgstr ""
-msgid "Search results…"
-msgstr ""
-
msgid "Search users"
msgstr ""
@@ -21798,6 +22594,11 @@ msgid_plural "SearchResults|commits"
msgstr[0] ""
msgstr[1] ""
+msgid "SearchResults|epic"
+msgid_plural "SearchResults|epics"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "SearchResults|issue"
msgid_plural "SearchResults|issues"
msgstr[0] ""
@@ -21842,10 +22643,10 @@ msgstr ""
msgid "Seat Link is disabled, and cannot be configured through this form."
msgstr ""
-msgid "Seats currently in use"
+msgid "Seats usage data as of %{last_enqueue_time}"
msgstr ""
-msgid "Seats in license"
+msgid "Seats usage data is updated every day at 12:00pm UTC"
msgstr ""
msgid "Secondary"
@@ -21899,6 +22700,9 @@ msgstr ""
msgid "SecurityConfiguration|Available for on-demand DAST"
msgstr ""
+msgid "SecurityConfiguration|By default, all analyzers are applied in order to cover all languages across your project, and only run if the language is detected in the Merge Request."
+msgstr ""
+
msgid "SecurityConfiguration|Configure"
msgstr ""
@@ -21929,16 +22733,19 @@ msgstr ""
msgid "SecurityConfiguration|Manage"
msgstr ""
+msgid "SecurityConfiguration|More information"
+msgstr ""
+
msgid "SecurityConfiguration|Not enabled"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|Security Control"
+msgid "SecurityConfiguration|SAST Configuration"
msgstr ""
-msgid "SecurityConfiguration|See documentation"
+msgid "SecurityConfiguration|Security Control"
msgstr ""
msgid "SecurityConfiguration|Status"
@@ -21950,6 +22757,9 @@ msgstr ""
msgid "SecurityConfiguration|Using custom settings. You won't receive automatic updates on this variable. %{anchorStart}Restore to default%{anchorEnd}"
msgstr ""
+msgid "SecurityConfiguration|View history"
+msgstr ""
+
msgid "SecurityConfiguration|You can quickly enable all security scanning tools by enabling %{linkStart}Auto DevOps%{linkEnd}."
msgstr ""
@@ -22028,9 +22838,6 @@ msgstr ""
msgid "SecurityReports|Learn more about setting up your dashboard"
msgstr ""
-msgid "SecurityReports|Load more vulnerabilities"
-msgstr ""
-
msgid "SecurityReports|Monitor vulnerabilities in your code"
msgstr ""
@@ -22310,7 +23117,7 @@ msgstr ""
msgid "Select status"
msgstr ""
-msgid "Select strategy activation method"
+msgid "Select strategy activation method."
msgstr ""
msgid "Select subscription"
@@ -22325,7 +23132,7 @@ msgstr ""
msgid "Select the custom project template source group."
msgstr ""
-msgid "Select timeframe"
+msgid "Select the environment scope for this feature flag."
msgstr ""
msgid "Select timezone"
@@ -22574,6 +23381,9 @@ msgstr ""
msgid "Set iteration"
msgstr ""
+msgid "Set limit to 0 to allow any file size."
+msgstr ""
+
msgid "Set max session time for web terminal."
msgstr ""
@@ -22652,10 +23462,13 @@ msgstr ""
msgid "Set up a %{type} Runner manually"
msgstr ""
+msgid "Set up a hardware device as a second factor to sign in."
+msgstr ""
+
msgid "Set up assertions/attributes/claims (email, first_name, last_name) and NameID according to %{docsLinkStart}the documentation %{icon}%{docsLinkEnd}"
msgstr ""
-msgid "Set up new U2F device"
+msgid "Set up new device"
msgstr ""
msgid "Set up new password"
@@ -22724,6 +23537,9 @@ msgstr ""
msgid "Sets weight to %{weight}."
msgstr ""
+msgid "Setting this to 0 means using the system default timeout value."
+msgstr ""
+
msgid "Settings"
msgstr ""
@@ -22739,6 +23555,15 @@ msgstr ""
msgid "Severity"
msgstr ""
+msgid "SeverityWidget|Severity"
+msgstr ""
+
+msgid "SeverityWidget|Severity: %{severity}"
+msgstr ""
+
+msgid "SeverityWidget|There was an error while updating severity."
+msgstr ""
+
msgid "Shards (%{shards})"
msgstr ""
@@ -22784,6 +23609,9 @@ msgstr ""
msgid "Show all requirements."
msgstr ""
+msgid "Show all test cases."
+msgstr ""
+
msgid "Show archived projects"
msgstr ""
@@ -22796,6 +23624,9 @@ msgstr ""
msgid "Show comments"
msgstr ""
+msgid "Show comments on this file"
+msgstr ""
+
msgid "Show comments only"
msgstr ""
@@ -22841,6 +23672,12 @@ msgstr ""
msgid "Show parent subgroups"
msgstr ""
+msgid "Show the Closed list"
+msgstr ""
+
+msgid "Show the Open list"
+msgstr ""
+
msgid "Show whitespace changes"
msgstr ""
@@ -22884,9 +23721,6 @@ msgstr ""
msgid "Sidebar|Assign health status"
msgstr ""
-msgid "Sidebar|Change weight"
-msgstr ""
-
msgid "Sidebar|Health status"
msgstr ""
@@ -23070,6 +23904,9 @@ msgstr ""
msgid "Snippets|Add another file %{num}/%{total}"
msgstr ""
+msgid "Snippets|Authored %{time_ago} by %{author}"
+msgstr ""
+
msgid "Snippets|Delete file"
msgstr ""
@@ -23097,6 +23934,9 @@ msgstr ""
msgid "Solution"
msgstr ""
+msgid "Some changes are not shown"
+msgstr ""
+
msgid "Some child epics may be hidden due to applied filters"
msgstr ""
@@ -23463,6 +24303,12 @@ msgstr ""
msgid "Source (branch or tag)"
msgstr ""
+msgid "Source Branch"
+msgstr ""
+
+msgid "Source branch: %{source_branch_open}%{source_branch}%{source_branch_close}"
+msgstr ""
+
msgid "Source code"
msgstr "Изходен код"
@@ -23628,9 +24474,6 @@ msgstr ""
msgid "Start and due date"
msgstr ""
-msgid "Start by choosing a group to see how your team is spending time. You can then drill down to the project level."
-msgstr ""
-
msgid "Start by choosing a group to start exploring the merge requests in that group. You can then proceed to filter by projects, labels, milestones and authors."
msgstr ""
@@ -23712,18 +24555,27 @@ msgstr ""
msgid "StaticSiteEditor|3. Assign a person to review and accept the merge request."
msgstr ""
+msgid "StaticSiteEditor|A link to view the merge request will appear once ready."
+msgstr ""
+
msgid "StaticSiteEditor|An error occurred while submitting your changes."
msgstr ""
msgid "StaticSiteEditor|Branch could not be created."
msgstr ""
+msgid "StaticSiteEditor|Copy update"
+msgstr ""
+
msgid "StaticSiteEditor|Could not commit the content changes."
msgstr ""
msgid "StaticSiteEditor|Could not create merge request."
msgstr ""
+msgid "StaticSiteEditor|Creating your merge request"
+msgstr ""
+
msgid "StaticSiteEditor|Incompatible file content"
msgstr ""
@@ -23745,6 +24597,9 @@ msgstr ""
msgid "StaticSiteEditor|View documentation"
msgstr ""
+msgid "StaticSiteEditor|You can set an assignee to get your changes reviewed and deployed once your merge request is created."
+msgstr ""
+
msgid "StaticSiteEditor|Your merge request has been created"
msgstr ""
@@ -23874,15 +24729,15 @@ msgstr ""
msgid "Submit %{humanized_resource_name}"
msgstr ""
-msgid "Submit Changes"
-msgstr ""
-
msgid "Submit a review"
msgstr ""
msgid "Submit as spam"
msgstr ""
+msgid "Submit changes"
+msgstr ""
+
msgid "Submit feedback"
msgstr ""
@@ -24036,6 +24891,9 @@ msgstr ""
msgid "Successfully deleted U2F device."
msgstr ""
+msgid "Successfully deleted WebAuthn device."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -24354,9 +25212,6 @@ msgstr ""
msgid "Template to append to all Service Desk issues"
msgstr ""
-msgid "Template was successfully saved."
-msgstr ""
-
msgid "Templates"
msgstr ""
@@ -24435,10 +25290,28 @@ msgid_plural "Test coverage: %d hits"
msgstr[0] ""
msgstr[1] ""
-msgid "Test failed."
+msgid "Test settings"
msgstr ""
-msgid "Test settings and save changes"
+msgid "TestCases|New Test Case"
+msgstr ""
+
+msgid "TestCases|New test case"
+msgstr ""
+
+msgid "TestCases|Search test cases"
+msgstr ""
+
+msgid "TestCases|Something went wrong while creating a test case."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching count of test cases."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching test cases list."
+msgstr ""
+
+msgid "TestCases|Submit test case"
msgstr ""
msgid "TestHooks|Ensure one of your projects has merge requests."
@@ -24504,6 +25377,9 @@ msgstr ""
msgid "Thank you for signing up for your free trial! You will get additional instructions in your inbox shortly."
msgstr ""
+msgid "Thank you for your business."
+msgstr ""
+
msgid "Thank you for your feedback!"
msgstr ""
@@ -24563,9 +25439,6 @@ msgstr ""
msgid "The URL to use for connecting to Elasticsearch. Use a comma-separated list to support clustering (e.g., \"http://localhost:9200, http://localhost:9201\")."
msgstr ""
-msgid "The Web IDE offers advanced syntax highlighting capabilities and more."
-msgstr ""
-
msgid "The X509 Certificate to use when mutual TLS is required to communicate with the external authorization service. If left blank, the server certificate is still validated when accessing over HTTPS."
msgstr ""
@@ -24676,6 +25549,9 @@ msgstr "Връзката на разклонение беше премахнат
msgid "The form contains the following error:"
msgstr ""
+msgid "The form contains the following warning:"
+msgstr ""
+
msgid "The global settings require you to enable Two-Factor Authentication for your account."
msgstr ""
@@ -24790,9 +25666,6 @@ msgstr "Етапът на планиране показва колко е вре
msgid "The private key to use when a client certificate is provided. This value is encrypted at rest."
msgstr ""
-msgid "The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr "Етапът на издаване показва общото време, което е нужно от Ñъздаването на проблем до внедрÑването на кода в крайната верÑиÑ. Данните ще бъдат добавени автоматично Ñлед като завършите един пълен цикъл и превърнете първата Ñи Ð¸Ð´ÐµÑ Ð² реалноÑÑ‚."
-
msgid "The project can be accessed by any logged in user."
msgstr "Ð’Ñеки впиÑан потребител има доÑтъп до проекта."
@@ -24829,7 +25702,7 @@ msgstr ""
msgid "The remote repository is being updated..."
msgstr ""
-msgid "The repository can be commited to, and issues, comments and other entities can be created."
+msgid "The repository can be committed to, and issues, comments and other entities can be created."
msgstr ""
msgid "The repository for this project does not exist."
@@ -24883,9 +25756,6 @@ msgstr "Етапът на теÑтване показва времето, кое
msgid "The time taken by each data entry gathered by that stage."
msgstr "Времето, което отнема вÑеки Ð·Ð°Ð¿Ð¸Ñ Ð¾Ñ‚ данни за ÑÑŠÐ¾Ñ‚Ð²ÐµÑ‚Ð½Ð¸Ñ ÐµÑ‚Ð°Ð¿."
-msgid "The total stage shows the time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The update action will time out after %{number_of_minutes} minutes. For big repositories, use a clone/push combination."
msgstr ""
@@ -24949,6 +25819,9 @@ msgstr ""
msgid "There are no archived requirements"
msgstr ""
+msgid "There are no archived test cases"
+msgstr ""
+
msgid "There are no changes"
msgstr ""
@@ -24988,6 +25861,9 @@ msgstr ""
msgid "There are no open requirements"
msgstr ""
+msgid "There are no open test cases"
+msgstr ""
+
msgid "There are no packages yet"
msgstr ""
@@ -25000,6 +25876,9 @@ msgstr ""
msgid "There is a limit of %{ci_project_subscriptions_limit} subscriptions from or to a project."
msgstr ""
+msgid "There is already a To-Do for this design."
+msgstr ""
+
msgid "There is already a repository with that name on disk"
msgstr ""
@@ -25018,6 +25897,9 @@ msgstr ""
msgid "There was a problem communicating with your device."
msgstr ""
+msgid "There was a problem fetching branches."
+msgstr ""
+
msgid "There was a problem fetching groups."
msgstr ""
@@ -25246,9 +26128,15 @@ msgstr ""
msgid "This action can lead to data loss. To prevent accidental actions we ask you to confirm your intention."
msgstr ""
+msgid "This action cannot be undone, and will permanently delete the %{key} SSH key"
+msgstr ""
+
msgid "This action cannot be undone. You will lose the project's repository and all content: issues, merge requests, etc."
msgstr ""
+msgid "This action has been performed too many times. Try again later."
+msgstr ""
+
msgid "This action will %{strongOpen}permanently delete%{strongClose} %{codeOpen}%{project}%{codeClose} %{strongOpen}immediately%{strongClose}, including its repositories and all content: issues, merge requests, etc."
msgstr ""
@@ -25276,9 +26164,6 @@ msgstr ""
msgid "This board's scope is reduced"
msgstr ""
-msgid "This branch has changed since you started editing. Would you like to create a new branch?"
-msgstr ""
-
msgid "This chart could not be displayed"
msgstr ""
@@ -25405,15 +26290,9 @@ msgstr ""
msgid "This is a security log of important events involving your account."
msgstr ""
-msgid "This is the author's first Merge Request to this project."
-msgstr ""
-
msgid "This is the highest peak of users on your installation since the license started."
msgstr ""
-msgid "This is the maximum number of users that have existed at the same time since the license started. This is the minimum number of seats you will need to buy when you renew your license."
-msgstr ""
-
msgid "This is the number of currently active users on your installation, and this is the minimum number you need to purchase when you renew your license."
msgstr ""
@@ -25645,6 +26524,15 @@ msgstr ""
msgid "This user has no identities"
msgstr ""
+msgid "This user has previously committed to the %{name} project."
+msgstr ""
+
+msgid "This user has the %{access} role in the %{name} project."
+msgstr ""
+
+msgid "This user is the author of this %{noteable}."
+msgstr ""
+
msgid "This user will be the author of all events in the activity feed that are the result of an update, like new branches being created or new commits being pushed to existing branches."
msgstr ""
@@ -25675,6 +26563,9 @@ msgstr ""
msgid "Threat Monitoring"
msgstr ""
+msgid "ThreatMonitoring|All Environments"
+msgstr ""
+
msgid "ThreatMonitoring|Anomalous Requests"
msgstr ""
@@ -25702,9 +26593,6 @@ msgstr ""
msgid "ThreatMonitoring|Operations Per Second"
msgstr ""
-msgid "ThreatMonitoring|Overview"
-msgstr ""
-
msgid "ThreatMonitoring|Packet Activity"
msgstr ""
@@ -25723,6 +26611,9 @@ msgstr ""
msgid "ThreatMonitoring|Something went wrong, unable to fetch statistics"
msgstr ""
+msgid "ThreatMonitoring|Statistics"
+msgstr ""
+
msgid "ThreatMonitoring|The firewall is not installed or has been disabled. To view this data, ensure the web application firewall is installed and enabled for your cluster."
msgstr ""
@@ -26114,6 +27005,9 @@ msgstr ""
msgid "To update Snippets with multiple files, you must use the `files` parameter"
msgstr ""
+msgid "To use Gitpod you must first enable the feature in the integrations section of your %{user_prefs}."
+msgstr ""
+
msgid "To view all %{scannedResourcesCount} scanned URLs, please download the CSV file"
msgstr ""
@@ -26147,9 +27041,6 @@ msgstr ""
msgid "Toggle Sidebar"
msgstr ""
-msgid "Toggle all threads"
-msgstr ""
-
msgid "Toggle backtrace"
msgstr ""
@@ -26174,9 +27065,6 @@ msgstr ""
msgid "Toggle navigation"
msgstr ""
-msgid "Toggle project"
-msgstr ""
-
msgid "Toggle sidebar"
msgstr ""
@@ -26216,6 +27104,9 @@ msgstr ""
msgid "Too many projects enabled. You will need to manage them via the console or the API."
msgstr ""
+msgid "Too much data"
+msgstr ""
+
msgid "Topics (optional)"
msgstr ""
@@ -26234,6 +27125,9 @@ msgstr ""
msgid "Total cores (CPUs)"
msgstr ""
+msgid "Total days to completion"
+msgstr ""
+
msgid "Total issues"
msgstr ""
@@ -26330,6 +27224,9 @@ msgstr ""
msgid "Trending"
msgstr ""
+msgid "Trials|Create a new group to start your GitLab Gold trial."
+msgstr ""
+
msgid "Trials|Go back to GitLab"
msgstr ""
@@ -26339,6 +27236,15 @@ msgstr ""
msgid "Trials|You can always resume this process by selecting your avatar and choosing 'Start a Gold trial'"
msgstr ""
+msgid "Trials|You can apply your trial to a new group or an existing group."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group or your personal account."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group, an existing group, or your personal account."
+msgstr ""
+
msgid "Trials|You won't get a free trial right now but you can always resume this process by clicking on your avatar and choosing 'Start a free trial'"
msgstr ""
@@ -26408,6 +27314,9 @@ msgstr ""
msgid "Try using a different search term to find the file you are looking for."
msgstr ""
+msgid "Trying to communicate with your device. Plug it in (if needed) and press the button on the device now."
+msgstr ""
+
msgid "Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now."
msgstr ""
@@ -26495,6 +27404,12 @@ msgstr ""
msgid "URL or request ID"
msgstr ""
+msgid "USER %{user} WILL BE REMOVED! Are you sure?"
+msgstr ""
+
+msgid "USER WILL BE BLOCKED! Are you sure?"
+msgstr ""
+
msgid "UTC"
msgstr ""
@@ -26552,9 +27467,6 @@ msgstr ""
msgid "Unable to load the merge request widget. Try reloading the page."
msgstr ""
-msgid "Unable to resolve"
-msgstr ""
-
msgid "Unable to save iteration. Please try again"
msgstr ""
@@ -26603,6 +27515,9 @@ msgstr ""
msgid "Undo ignore"
msgstr ""
+msgid "Unexpected error"
+msgstr ""
+
msgid "Unfortunately, your email message to GitLab could not be processed."
msgstr ""
@@ -26636,6 +27551,9 @@ msgstr ""
msgid "Unknown response text"
msgstr ""
+msgid "Unless otherwise agreed to in writing with GitLab, by clicking \"Upload License\" you agree that your use of GitLab Software is subject to the %{eula_link_start}Terms of Service%{eula_link_end}."
+msgstr ""
+
msgid "Unlimited"
msgstr ""
@@ -27002,9 +27920,6 @@ msgstr ""
msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
msgstr ""
-msgid "Use a hardware device to add the second factor of authentication."
-msgstr ""
-
msgid "Use an one time password authenticator on your mobile device or computer to enable two-factor authentication (2FA)."
msgstr ""
@@ -27278,13 +28193,13 @@ msgstr ""
msgid "Users"
msgstr ""
-msgid "Users in License:"
+msgid "Users in License"
msgstr ""
-msgid "Users or groups set as approvers in the project's or merge request's settings."
+msgid "Users in License:"
msgstr ""
-msgid "Users outside of license"
+msgid "Users or groups set as approvers in the project's or merge request's settings."
msgstr ""
msgid "Users over License:"
@@ -27302,9 +28217,6 @@ msgstr ""
msgid "Users with a Guest role or those who don't belong to a Project or Group will not use a seat from your license."
msgstr ""
-msgid "Users with a Guest role or those who don't belong to any projects or groups don't count towards seats in use."
-msgstr ""
-
msgid "UsersSelect|%{name} + %{length} more"
msgstr ""
@@ -27344,9 +28256,6 @@ msgstr ""
msgid "Validations failed."
msgstr ""
-msgid "Validity"
-msgstr ""
-
msgid "Value"
msgstr ""
@@ -27365,6 +28274,9 @@ msgstr ""
msgid "Value Stream Name"
msgstr ""
+msgid "ValueStreamAnalyticsStage|We don't have enough data to show this stage."
+msgstr ""
+
msgid "ValueStreamAnalytics|%{days}d"
msgstr ""
@@ -27621,6 +28533,9 @@ msgstr ""
msgid "VisualReviewApp|Steps 1 and 2 (and sometimes 3) are performed once by the developer before requesting feedback. Steps 3 (if necessary), 4 is performed by the reviewer each time they perform a review."
msgstr ""
+msgid "Visualization"
+msgstr ""
+
msgid "Vulnerabilities"
msgstr ""
@@ -27648,34 +28563,31 @@ msgstr ""
msgid "VulnerabilityChart|Severity"
msgstr ""
-msgid "VulnerabilityManagement|A true-positive and will fix"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Change status"
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|Confirm"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Confirmed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
-msgstr ""
-
-msgid "VulnerabilityManagement|Detected %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|A true-positive and will fix"
msgstr ""
-msgid "VulnerabilityManagement|Dismiss"
+msgid "VulnerabilityManagement|Change status"
msgstr ""
-msgid "VulnerabilityManagement|Dismissed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
msgstr ""
-msgid "VulnerabilityManagement|Resolved"
+msgid "VulnerabilityManagement|Detected"
msgstr ""
-msgid "VulnerabilityManagement|Resolved %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Needs triage"
msgstr ""
msgid "VulnerabilityManagement|Something went wrong while trying to delete the comment. Please try again later."
@@ -27726,6 +28638,9 @@ msgstr ""
msgid "Vulnerability|%{scannerName} (version %{scannerVersion})"
msgstr ""
+msgid "Vulnerability|Activity"
+msgstr ""
+
msgid "Vulnerability|Class"
msgstr ""
@@ -27738,6 +28653,9 @@ msgstr ""
msgid "Vulnerability|Description"
msgstr ""
+msgid "Vulnerability|Detected"
+msgstr ""
+
msgid "Vulnerability|Evidence"
msgstr ""
@@ -27801,6 +28719,9 @@ msgstr ""
msgid "Warning: Displaying this diagram might cause performance issues on this page."
msgstr ""
+msgid "We are currently unable to fetch data for the pipeline header."
+msgstr ""
+
msgid "We are currently unable to fetch data for this graph."
msgstr ""
@@ -27840,6 +28761,12 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
+msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
+msgstr ""
+
+msgid "We would like to inform you that your subscription GitLab Enterprise Edition %{plan_name} is nearing its user limit. You have %{active_user_count} active users, which is almost at the user limit of %{maximum_user_count}."
+msgstr ""
+
msgid "We've found no vulnerabilities"
msgstr ""
@@ -27855,6 +28782,12 @@ msgstr ""
msgid "Web terminal"
msgstr ""
+msgid "WebAuthn Devices (%{length})"
+msgstr ""
+
+msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
+msgstr ""
+
msgid "WebIDE|Merge request"
msgstr ""
@@ -27993,15 +28926,9 @@ msgstr ""
msgid "Welcome to the guided GitLab tour"
msgstr ""
-msgid "Welcome to your Issue Board!"
-msgstr ""
-
msgid "Welcome to your issue board!"
msgstr ""
-msgid "We’ve been making changes to %{featureName} and we’d love your feedback %{linkStart}in this issue%{linkEnd} to help us improve the experience."
-msgstr ""
-
msgid "What are you searching for?"
msgstr ""
@@ -28020,6 +28947,9 @@ msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
msgstr ""
+msgid "When enabled, any user visiting %{host} and creating an account will have to be explicitly approved by the admin before they can login. This setting is effective only if sign-ups are enabled."
+msgstr ""
+
msgid "When enabled, any user visiting %{host} will be able to create an account."
msgstr ""
@@ -28244,6 +29174,9 @@ msgstr ""
msgid "With requirements, you can set criteria to check your products against."
msgstr ""
+msgid "With test cases, you can define conditions for your project to meet in determining quality"
+msgstr ""
+
msgid "Withdraw Access Request"
msgstr "ОттеглÑне на заÑвката за доÑтъп"
@@ -28259,6 +29192,9 @@ msgstr ""
msgid "Workflow Help"
msgstr ""
+msgid "Would you like to create a new branch?"
+msgstr ""
+
msgid "Write"
msgstr ""
@@ -28280,6 +29216,9 @@ msgstr ""
msgid "Wrong extern UID provided. Make sure Auth0 is configured correctly."
msgstr ""
+msgid "YYYY-MM-DD"
+msgstr ""
+
msgid "Yes"
msgstr ""
@@ -28337,7 +29276,7 @@ msgstr ""
msgid "You are going to remove the fork relationship from %{project_full_name}. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "You are going to transfer %{project_full_name} to another owner. Are you ABSOLUTELY sure?"
+msgid "You are going to transfer %{project_full_name} to another namespace. Are you ABSOLUTELY sure?"
msgstr ""
msgid "You are going to turn off the confidentiality. This means %{strongStart}everyone%{strongEnd} will be able to see and leave a comment on this %{issuableType}."
@@ -28397,9 +29336,6 @@ msgstr ""
msgid "You can always edit this later"
msgstr ""
-msgid "You can apply your Trial to your Personal account or create a New Group."
-msgstr ""
-
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings"
msgstr ""
@@ -28421,12 +29357,18 @@ msgstr ""
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
+msgid "You can find more information about GitLab subscriptions in %{subscriptions_doc_link}."
+msgstr ""
+
msgid "You can generate an access token scoped to this project for each application to use the GitLab API."
msgstr ""
msgid "You can get started by cloning the repository or start adding files to it with one of the following options."
msgstr ""
+msgid "You can group test cases using labels. To learn about the future direction of this feature, visit %{linkStart}Quality Management direction page%{linkEnd}."
+msgstr ""
+
msgid "You can invite a new member to %{project_name} or invite another group."
msgstr ""
@@ -28442,6 +29384,9 @@ msgstr ""
msgid "You can notify the app / group or a project by sending them an email notification"
msgstr ""
+msgid "You can now close this window."
+msgstr ""
+
msgid "You can now export your security dashboard to a CSV report."
msgstr ""
@@ -28490,9 +29435,6 @@ msgstr ""
msgid "You can test your .gitlab-ci.yml in %{linkStart}CI Lint%{linkEnd}."
msgstr ""
-msgid "You can try again using %{begin_link}basic search%{end_link}"
-msgstr ""
-
msgid "You cannot access the raw file. Please wait a minute."
msgstr ""
@@ -28544,6 +29486,9 @@ msgstr ""
msgid "You don't have any U2F devices registered yet."
msgstr ""
+msgid "You don't have any WebAuthn devices registered yet."
+msgstr ""
+
msgid "You don't have any active chat names."
msgstr ""
@@ -28631,6 +29576,9 @@ msgstr ""
msgid "You must accept our Terms of Service and privacy policy in order to register an account"
msgstr ""
+msgid "You must be logged in to search across all of GitLab"
+msgstr ""
+
msgid "You must disassociate %{domain} from all clusters it is attached to before deletion."
msgstr ""
@@ -28670,7 +29618,7 @@ msgstr "Ðуждаете Ñе от разрешение."
msgid "You need to be logged in."
msgstr ""
-msgid "You need to register a two-factor authentication app before you can set up a U2F device."
+msgid "You need to register a two-factor authentication app before you can set up a device."
msgstr ""
msgid "You need to set terms to be enforced"
@@ -28688,6 +29636,9 @@ msgstr ""
msgid "You reached %{usage_in_percent} of %{namespace_name}'s storage capacity (%{used_storage} of %{storage_limit})"
msgstr ""
+msgid "You successfully declined the invitation"
+msgstr ""
+
msgid "You tried to fork %{link_to_the_project} but it failed for the following reason:"
msgstr ""
@@ -28853,10 +29804,13 @@ msgstr ""
msgid "Your U2F device did not send a valid JSON response."
msgstr ""
-msgid "Your U2F device needs to be set up. Plug it in (if not already) and click the button on the left."
+msgid "Your U2F device was registered!"
msgstr ""
-msgid "Your U2F device was registered!"
+msgid "Your WebAuthn device did not send a valid JSON response."
+msgstr ""
+
+msgid "Your WebAuthn device was registered!"
msgstr ""
msgid "Your access request to the %{source_type} has been withdrawn."
@@ -28880,6 +29834,9 @@ msgstr ""
msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
msgstr ""
+msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
+msgstr ""
+
msgid "Your changes can be committed to %{branch_name} because a merge request is open."
msgstr ""
@@ -28916,6 +29873,12 @@ msgstr ""
msgid "Your deployment services will be broken, you will need to manually fix the services after renaming."
msgstr ""
+msgid "Your device is not compatible with GitLab. Please try another device"
+msgstr ""
+
+msgid "Your device needs to be set up. Plug it in (if needed) and click the button on the left."
+msgstr ""
+
msgid "Your device was successfully set up! Give it a name and register it with the GitLab server."
msgstr ""
@@ -29029,9 +29992,6 @@ msgstr[1] ""
msgid "access:"
msgstr ""
-msgid "activated"
-msgstr ""
-
msgid "added %{created_at_timeago}"
msgstr ""
@@ -29104,9 +30064,21 @@ msgstr ""
msgid "by %{user}"
msgstr ""
+msgid "cannot be a date in the past"
+msgstr ""
+
msgid "cannot be changed if a personal project has container registry tags."
msgstr ""
+msgid "cannot be changed if shared runners are enabled"
+msgstr ""
+
+msgid "cannot be enabled because parent group does not allow it"
+msgstr ""
+
+msgid "cannot be enabled because parent group has shared Runners disabled"
+msgstr ""
+
msgid "cannot be enabled unless all domains have TLS certificates"
msgstr ""
@@ -29152,7 +30124,7 @@ msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about SAST %{linkEndTag}"
msgstr ""
-msgid "ciReport|%{linkStartTag}Learn more about Secret Scanning %{linkEndTag}"
+msgid "ciReport|%{linkStartTag}Learn more about Secret Detection %{linkEndTag}"
msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about codequality reports %{linkEndTag}"
@@ -29467,9 +30439,6 @@ msgstr ""
msgid "error"
msgstr ""
-msgid "error code:"
-msgstr ""
-
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr ""
@@ -29491,6 +30460,9 @@ msgstr ""
msgid "failed to dismiss associated finding(id=%{finding_id}): %{message}"
msgstr ""
+msgid "failed to revert associated finding(id=%{finding_id}) to detected"
+msgstr ""
+
msgid "file"
msgid_plural "files"
msgstr[0] ""
@@ -30033,6 +31005,9 @@ msgstr ""
msgid "must be a root namespace"
msgstr ""
+msgid "must be a valid IPv4 or IPv6 address"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -30069,6 +31044,9 @@ msgstr ""
msgid "no expiration"
msgstr ""
+msgid "no name set"
+msgstr ""
+
msgid "no one can merge"
msgstr ""
@@ -30247,9 +31225,6 @@ msgstr ""
msgid "security Reports|There was an error creating the merge request"
msgstr ""
-msgid "settings saved, but not activated"
-msgstr ""
-
msgid "severity|Critical"
msgstr ""
@@ -30376,9 +31351,6 @@ msgstr ""
msgid "toggle collapse"
msgstr ""
-msgid "toggle dropdown"
-msgstr ""
-
msgid "triggered"
msgstr ""
@@ -30406,6 +31378,9 @@ msgstr ""
msgid "user avatar"
msgstr ""
+msgid "user preferences"
+msgstr ""
+
msgid "username"
msgstr ""
diff --git a/locale/bn_BD/gitlab.po b/locale/bn_BD/gitlab.po
index 5937e8df6c1..06b0aaf5053 100644
--- a/locale/bn_BD/gitlab.po
+++ b/locale/bn_BD/gitlab.po
@@ -14,7 +14,10 @@ msgstr ""
"X-Crowdin-Language: bn\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 6\n"
-"PO-Revision-Date: 2020-09-04 23:02\n"
+"PO-Revision-Date: 2020-10-02 18:42\n"
+
+msgid " %{project_name}#%{issue_iid} &middot; opened %{issue_created} by %{author}"
+msgstr ""
msgid " %{start} to %{end}"
msgstr ""
@@ -74,6 +77,16 @@ msgstr ""
msgid "\"el\" parameter is required for createInstance()"
msgstr ""
+msgid "%d Approval"
+msgid_plural "%d Approvals"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d Package"
+msgid_plural "%d Packages"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d Scanned URL"
msgid_plural "%d Scanned URLs"
msgstr[0] ""
@@ -137,6 +150,11 @@ msgstr[1] ""
msgid "%d commits"
msgstr ""
+msgid "%d completed issue"
+msgid_plural "%d completed issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d contribution"
msgid_plural "%d contributions"
msgstr[0] ""
@@ -147,6 +165,11 @@ msgid_plural "%d days"
msgstr[0] ""
msgstr[1] ""
+msgid "%d day until tags are automatically removed"
+msgid_plural "%d days until tags are automatically removed"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d error"
msgid_plural "%d errors"
msgstr[0] ""
@@ -237,6 +260,16 @@ msgid_plural "%d more comments"
msgstr[0] ""
msgstr[1] ""
+msgid "%d open issue"
+msgid_plural "%d open issues"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d pending comment"
+msgid_plural "%d pending comments"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d personal project will be removed and cannot be restored."
msgid_plural "%d personal projects will be removed and cannot be restored."
msgstr[0] ""
@@ -252,6 +285,11 @@ msgid_plural "%d projects"
msgstr[0] ""
msgstr[1] ""
+msgid "%d project selected"
+msgid_plural "%d projects selected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d request with warnings"
msgid_plural "%d requests with warnings"
msgstr[0] ""
@@ -272,6 +310,11 @@ msgid_plural "%d tags"
msgstr[0] ""
msgstr[1] ""
+msgid "%d tag per image name"
+msgid_plural "%d tags per image name"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d unassigned issue"
msgid_plural "%d unassigned issues"
msgstr[0] ""
@@ -292,6 +335,11 @@ msgid_plural "%d vulnerabilities dismissed"
msgstr[0] ""
msgstr[1] ""
+msgid "%d warning found:"
+msgid_plural "%d warnings found:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%s additional commit has been omitted to prevent performance issues."
msgid_plural "%s additional commits have been omitted to prevent performance issues."
msgstr[0] ""
@@ -330,6 +378,9 @@ msgstr ""
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr ""
+msgid "%{completedCount} completed weight"
+msgstr ""
+
msgid "%{completedWeight} of %{totalWeight} weight completed"
msgstr ""
@@ -378,14 +429,12 @@ msgid_plural "%{count} participants"
msgstr[0] ""
msgstr[1] ""
-msgid "%{count} pending comment"
-msgid_plural "%{count} pending comments"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
+msgid "%{count} total weight"
+msgstr ""
+
msgid "%{dashboard_path} could not be found."
msgstr ""
@@ -440,6 +489,9 @@ msgstr ""
msgid "%{group_name} uses group managed accounts. You need to create a new GitLab account which will be managed by %{group_name}."
msgstr ""
+msgid "%{group_name}&%{epic_iid} &middot; opened %{epic_created} by %{author}"
+msgstr ""
+
msgid "%{host} sign-in from new location"
msgstr ""
@@ -452,7 +504,7 @@ msgstr ""
msgid "%{issuableType} will be removed! Are you sure?"
msgstr ""
-msgid "%{issuesSize} issues with a limit of %{maxIssueCount}"
+msgid "%{issuesCount} issues with a limit of %{maxIssueCount}"
msgstr ""
msgid "%{issuesSize} with a limit of %{maxIssueCount}"
@@ -485,7 +537,7 @@ msgstr ""
msgid "%{labelStart}Namespace:%{labelEnd} %{namespace}"
msgstr ""
-msgid "%{labelStart}Report Type:%{labelEnd} %{reportType}"
+msgid "%{labelStart}Scan Type:%{labelEnd} %{reportType}"
msgstr ""
msgid "%{labelStart}Scanner:%{labelEnd} %{scanner}"
@@ -682,9 +734,6 @@ msgid_plural "%{securityScanner} results are not available because a pipeline ha
msgstr[0] ""
msgstr[1] ""
-msgid "%{service_title} %{message}."
-msgstr ""
-
msgid "%{size} GiB"
msgstr ""
@@ -773,6 +822,12 @@ msgstr ""
msgid "%{timebox_name} should belong either to a project or a group."
msgstr ""
+msgid "%{timebox_type} does not support burnup charts"
+msgstr ""
+
+msgid "%{timebox_type} must have a start and due date"
+msgstr ""
+
msgid "%{title} %{operator} %{threshold}"
msgstr ""
@@ -797,7 +852,7 @@ msgstr ""
msgid "%{total} open issue weight"
msgstr ""
-msgid "%{total} open issues"
+msgid "%{total} warnings found: showing first %{warningsDisplayed}"
msgstr ""
msgid "%{usage_ping_link_start}Learn more%{usage_ping_link_end} about what information is shared with GitLab Inc."
@@ -830,9 +885,6 @@ msgstr ""
msgid "&lt; 1 hour"
msgstr ""
-msgid "&lt;no name set&gt;"
-msgstr ""
-
msgid "&lt;no scopes selected&gt;"
msgstr ""
@@ -863,6 +915,9 @@ msgstr ""
msgid "'%{name}' Value Stream created"
msgstr ""
+msgid "'%{name}' Value Stream deleted"
+msgstr ""
+
msgid "'%{name}' stage already exists"
msgstr ""
@@ -922,6 +977,9 @@ msgstr ""
msgid "+ %{numberOfHiddenAssignees} more"
msgstr ""
+msgid "+ %{numberOfHiddenReviewers} more"
+msgstr ""
+
msgid "+%d more"
msgid_plural "+%d more"
msgstr[0] ""
@@ -982,6 +1040,11 @@ msgid_plural "%d Days"
msgstr[0] ""
msgstr[1] ""
+msgid "1 Issue"
+msgid_plural "%d Issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "1 closed issue"
msgid_plural "%{issues} closed issues"
msgstr[0] ""
@@ -997,6 +1060,11 @@ msgid_plural "%d days"
msgstr[0] ""
msgstr[1] ""
+msgid "1 deploy key"
+msgid_plural "%d deploy keys"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1099,6 +1167,9 @@ msgstr ""
msgid ":%{startLine} to %{endLine}"
msgstr ""
+msgid "A %{incident_docs_start}modified issue%{incident_docs_end} to guide the resolution of incidents."
+msgstr ""
+
msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr ""
@@ -1111,6 +1182,9 @@ msgstr ""
msgid "A GitBook site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
+msgid "A Gitpod configured Webapplication in Spring and Java"
+msgstr ""
+
msgid "A Hexo site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
@@ -1282,9 +1356,15 @@ msgstr ""
msgid "Access expiration date"
msgstr ""
+msgid "Access expires"
+msgstr ""
+
msgid "Access forbidden. Check your access level."
msgstr ""
+msgid "Access granted"
+msgstr ""
+
msgid "Access requests"
msgstr ""
@@ -1294,6 +1374,9 @@ msgstr ""
msgid "Access to Pages websites are controlled based on the user's membership to a given project. By checking this box, users will be required to be logged in to have access to all Pages websites in your instance."
msgstr ""
+msgid "AccessDropdown|Deploy Keys"
+msgstr ""
+
msgid "AccessDropdown|Groups"
msgstr ""
@@ -1411,12 +1494,6 @@ msgstr ""
msgid "Active Sessions"
msgstr ""
-msgid "Active Users:"
-msgstr ""
-
-msgid "Active users"
-msgstr ""
-
msgid "Activity"
msgstr ""
@@ -1584,9 +1661,6 @@ msgstr ""
msgid "Add label(s)"
msgstr ""
-msgid "Add license"
-msgstr ""
-
msgid "Add list"
msgstr ""
@@ -1761,21 +1835,51 @@ msgstr ""
msgid "AdminArea|Bots"
msgstr ""
+msgid "AdminArea|Components"
+msgstr ""
+
msgid "AdminArea|Developer"
msgstr ""
+msgid "AdminArea|Features"
+msgstr ""
+
+msgid "AdminArea|Groups: %{number_of_groups}"
+msgstr ""
+
msgid "AdminArea|Guest"
msgstr ""
msgid "AdminArea|Included Free in license"
msgstr ""
+msgid "AdminArea|Latest groups"
+msgstr ""
+
+msgid "AdminArea|Latest projects"
+msgstr ""
+
+msgid "AdminArea|Latest users"
+msgstr ""
+
msgid "AdminArea|Maintainer"
msgstr ""
+msgid "AdminArea|New group"
+msgstr ""
+
+msgid "AdminArea|New project"
+msgstr ""
+
+msgid "AdminArea|New user"
+msgstr ""
+
msgid "AdminArea|Owner"
msgstr ""
+msgid "AdminArea|Projects: %{number_of_projects}"
+msgstr ""
+
msgid "AdminArea|Reporter"
msgstr ""
@@ -1803,6 +1907,9 @@ msgstr ""
msgid "AdminArea|Users without a Group and Project"
msgstr ""
+msgid "AdminArea|Users: %{number_of_users}"
+msgstr ""
+
msgid "AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running."
msgstr ""
@@ -1821,9 +1928,6 @@ msgstr ""
msgid "AdminProjects|Delete Project %{projectName}?"
msgstr ""
-msgid "AdminProjects|Delete project"
-msgstr ""
-
msgid "AdminSettings|Apply integration settings to all Projects"
msgstr ""
@@ -2061,21 +2165,30 @@ msgstr ""
msgid "AdminUsers|Without projects"
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 ""
msgid "AdminUsers|You cannot remove your own admin rights."
msgstr ""
+msgid "AdminUsers|You must transfer ownership or delete the groups owned by this user before you can delete their account"
+msgstr ""
+
msgid "Administration"
msgstr ""
msgid "Advanced"
msgstr ""
+msgid "Advanced Search"
+msgstr ""
+
+msgid "Advanced Search with Elasticsearch"
+msgstr ""
+
msgid "Advanced Settings"
msgstr ""
@@ -2153,6 +2266,9 @@ msgstr ""
msgid "AlertManagement|Edit"
msgstr ""
+msgid "AlertManagement|Environment"
+msgstr ""
+
msgid "AlertManagement|Events"
msgstr ""
@@ -2165,6 +2281,9 @@ msgstr ""
msgid "AlertManagement|Issue"
msgstr ""
+msgid "AlertManagement|Key"
+msgstr ""
+
msgid "AlertManagement|Low"
msgstr ""
@@ -2258,6 +2377,9 @@ msgstr ""
msgid "AlertManagement|Unknown"
msgstr ""
+msgid "AlertManagement|Value"
+msgstr ""
+
msgid "AlertManagement|View alerts in Opsgenie"
msgstr ""
@@ -2417,6 +2539,9 @@ msgstr ""
msgid "All projects"
msgstr ""
+msgid "All projects selected"
+msgstr ""
+
msgid "All security scans are enabled because %{linkStart}Auto DevOps%{linkEnd} is enabled on this project"
msgstr ""
@@ -2504,6 +2629,9 @@ msgstr ""
msgid "Almost there"
msgstr ""
+msgid "Already blocked"
+msgstr ""
+
msgid "Also called \"Issuer\" or \"Relying party trust identifier\""
msgstr ""
@@ -2558,6 +2686,9 @@ msgstr ""
msgid "An error has occurred"
msgstr ""
+msgid "An error occured while making the changes: %{error}"
+msgstr ""
+
msgid "An error occurred adding a draft to the thread."
msgstr ""
@@ -2585,12 +2716,6 @@ msgstr ""
msgid "An error occurred when toggling the notification subscription"
msgstr ""
-msgid "An error occurred when trying to resolve a comment. Please try again."
-msgstr ""
-
-msgid "An error occurred when trying to resolve a discussion. Please try again."
-msgstr ""
-
msgid "An error occurred when updating the issue weight"
msgstr ""
@@ -2606,12 +2731,6 @@ msgstr ""
msgid "An error occurred while checking group path. Please refresh and try again."
msgstr ""
-msgid "An error occurred while committing your changes."
-msgstr ""
-
-msgid "An error occurred while creating the list. Please try again."
-msgstr ""
-
msgid "An error occurred while decoding the file."
msgstr ""
@@ -2684,25 +2803,19 @@ msgstr ""
msgid "An error occurred while fetching the Service Desk address."
msgstr ""
-msgid "An error occurred while fetching the board issues. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the board lists. Please reload the page."
msgstr ""
msgid "An error occurred while fetching the board lists. Please try again."
msgstr ""
-msgid "An error occurred while fetching the board swimlanes. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the builds."
msgstr ""
msgid "An error occurred while fetching the job log."
msgstr ""
-msgid "An error occurred while fetching the job trace."
+msgid "An error occurred while fetching the job logs."
msgstr ""
msgid "An error occurred while fetching the job."
@@ -2849,9 +2962,6 @@ msgstr ""
msgid "An error occurred while saving assignees"
msgstr ""
-msgid "An error occurred while saving the template. Please check if the template exists."
-msgstr ""
-
msgid "An error occurred while searching for milestones"
msgstr ""
@@ -2870,10 +2980,10 @@ msgstr ""
msgid "An error occurred while updating approvers"
msgstr ""
-msgid "An error occurred while updating the comment"
+msgid "An error occurred while updating labels."
msgstr ""
-msgid "An error occurred while updating the list. Please try again."
+msgid "An error occurred while updating the comment"
msgstr ""
msgid "An error occurred while validating group path"
@@ -2927,6 +3037,9 @@ msgstr ""
msgid "An unknown error occurred while loading this graph."
msgstr ""
+msgid "An unknown error occurred."
+msgstr ""
+
msgid "Analytics"
msgstr ""
@@ -2960,10 +3073,10 @@ msgstr ""
msgid "Any"
msgstr ""
-msgid "Any Author"
+msgid "Any %{header}"
msgstr ""
-msgid "Any Status"
+msgid "Any Author"
msgstr ""
msgid "Any branch"
@@ -3017,6 +3130,9 @@ msgstr ""
msgid "Application ID"
msgstr ""
+msgid "Application limits saved successfully"
+msgstr ""
+
msgid "Application settings saved successfully"
msgstr ""
@@ -3226,6 +3342,9 @@ msgstr ""
msgid "Are you sure you want to close this blocked issue?"
msgstr ""
+msgid "Are you sure you want to delete \"%{name}\" Value Stream?"
+msgstr ""
+
msgid "Are you sure you want to delete %{name}?"
msgstr ""
@@ -3235,6 +3354,9 @@ msgstr ""
msgid "Are you sure you want to delete this %{typeOfComment}?"
msgstr ""
+msgid "Are you sure you want to delete this SSH key?"
+msgstr ""
+
msgid "Are you sure you want to delete this board?"
msgstr ""
@@ -3259,6 +3381,11 @@ msgstr ""
msgid "Are you sure you want to erase this build?"
msgstr ""
+msgid "Are you sure you want to import %d repository?"
+msgid_plural "Are you sure you want to import %d repositories?"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Are you sure you want to lose unsaved changes?"
msgstr ""
@@ -3268,15 +3395,15 @@ msgstr ""
msgid "Are you sure you want to merge immediately?"
msgstr ""
-msgid "Are you sure you want to permanently delete this license?"
-msgstr ""
-
msgid "Are you sure you want to re-deploy this environment?"
msgstr ""
msgid "Are you sure you want to regenerate the public key? You will have to update the public key on the remote server before mirroring will work again."
msgstr ""
+msgid "Are you sure you want to reindex?"
+msgstr ""
+
msgid "Are you sure you want to remove %{group_name}?"
msgstr ""
@@ -3304,6 +3431,9 @@ msgstr ""
msgid "Are you sure you want to revoke this nickname?"
msgstr ""
+msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
+msgstr ""
+
msgid "Are you sure you want to stop this environment?"
msgstr ""
@@ -3325,6 +3455,9 @@ msgstr ""
msgid "Are you sure? The device will be signed out of GitLab and all remember me tokens revoked."
msgstr ""
+msgid "Are you sure? This will invalidate your registered applications and U2F / WebAuthn devices."
+msgstr ""
+
msgid "Are you sure? This will invalidate your registered applications and U2F devices."
msgstr ""
@@ -3343,9 +3476,6 @@ msgstr ""
msgid "Artifacts"
msgstr ""
-msgid "As U2F devices are only supported by a few browsers, we require that you set up a two-factor authentication app before a U2F device. That way you'll always be able to log in - even when you're using an unsupported browser."
-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 ""
@@ -3539,6 +3669,9 @@ msgstr ""
msgid "AuditLogs|Target"
msgstr ""
+msgid "AuditLogs|This month"
+msgstr ""
+
msgid "AuditLogs|User Events"
msgstr ""
@@ -3578,6 +3711,9 @@ msgstr ""
msgid "Authentication via U2F device failed."
msgstr ""
+msgid "Authentication via WebAuthn device failed."
+msgstr ""
+
msgid "Author"
msgstr ""
@@ -3845,15 +3981,6 @@ msgstr ""
msgid "BambooService|You must set up automatic revision labeling and a repository trigger in Bamboo."
msgstr ""
-msgid "BatchComments|Delete all pending comments"
-msgstr ""
-
-msgid "BatchComments|Discard review?"
-msgstr ""
-
-msgid "BatchComments|You're about to discard your review which will delete all of your pending comments. The deleted comments %{strong_start}cannot%{strong_end} be restored."
-msgstr ""
-
msgid "Be careful. Changing the project's namespace can have unintended side effects."
msgstr ""
@@ -3875,6 +4002,9 @@ msgstr ""
msgid "Bi-weekly code coverage"
msgstr ""
+msgid "Billable Users:"
+msgstr ""
+
msgid "Billing"
msgstr ""
@@ -3884,7 +4014,7 @@ msgstr ""
msgid "BillingPlans|@%{user_name} you are currently using the %{plan_name} plan."
msgstr ""
-msgid "BillingPlans|Congratulations, your new trial is activated"
+msgid "BillingPlans|Congratulations, your free trial is activated."
msgstr ""
msgid "BillingPlans|If you would like to downgrade your plan please contact %{support_link_start}Customer Support%{support_link_end}."
@@ -3947,6 +4077,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Block user"
+msgstr ""
+
msgid "Blocked"
msgstr ""
@@ -3962,31 +4095,37 @@ msgstr ""
msgid "Blog"
msgstr ""
-msgid "Board name"
-msgstr ""
-
msgid "Board scope"
msgstr ""
msgid "Board scope affects which issues are displayed for anyone who visits this board"
msgstr ""
-msgid "BoardBlankState|Add default lists"
+msgid "Boards"
msgstr ""
-msgid "BoardBlankState|Add the following default lists to your Issue Board with one click:"
+msgid "Boards and Board Lists"
msgstr ""
-msgid "BoardBlankState|Nevermind, I'll use my own"
+msgid "Boards|An error occurred while creating the issue. Please try again."
msgstr ""
-msgid "BoardBlankState|Starting out with the default set of lists will get you right on the way to making the most of your board."
+msgid "Boards|An error occurred while creating the list. Please try again."
msgstr ""
-msgid "Boards"
+msgid "Boards|An error occurred while fetching issues. Please reload the page."
msgstr ""
-msgid "Boards and Board Lists"
+msgid "Boards|An error occurred while fetching the board issues. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching the board swimlanes. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while moving the issue. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while updating the list. Please try again."
msgstr ""
msgid "Boards|Collapse"
@@ -4013,7 +4152,7 @@ msgstr ""
msgid "Branch %{branch_name} was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr ""
-msgid "Branch has changed"
+msgid "Branch changed"
msgstr ""
msgid "Branch is already taken"
@@ -4319,6 +4458,9 @@ msgstr ""
msgid "CLOSED (MOVED)"
msgstr ""
+msgid "CODEOWNERS rule violation"
+msgstr ""
+
msgid "CONTRIBUTING"
msgstr ""
@@ -4349,9 +4491,6 @@ msgstr ""
msgid "Can't create snippet: %{err}"
msgstr ""
-msgid "Can't edit as source branch was deleted"
-msgstr ""
-
msgid "Can't fetch content for the blob: %{err}"
msgstr ""
@@ -4364,9 +4503,6 @@ msgstr ""
msgid "Can't load mermaid module: %{err}"
msgstr ""
-msgid "Can't remove group members without group managed account"
-msgstr ""
-
msgid "Can't scan the code?"
msgstr ""
@@ -4409,6 +4545,9 @@ msgstr ""
msgid "Cannot create the abuse report. This user has been blocked."
msgstr ""
+msgid "Cannot enable shared runners because parent group does not allow it"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -4514,6 +4653,15 @@ msgstr ""
msgid "Change your password or recover your current one"
msgstr ""
+msgid "ChangeReviewer|Reviewer changed from %{old} to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Reviewer changed to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Unassigned"
+msgstr ""
+
msgid "ChangeTypeActionLabel|Pick into branch"
msgstr ""
@@ -4553,6 +4701,9 @@ msgstr ""
msgid "Changes the title to \"%{title_param}\"."
msgstr ""
+msgid "Changes were successfully made."
+msgstr ""
+
msgid "Changes won't take place until the index is %{link_start}recreated%{link_end}."
msgstr ""
@@ -4958,6 +5109,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove variable"
+msgstr ""
+
msgid "CiVariables|Remove variable row"
msgstr ""
@@ -5036,9 +5190,6 @@ msgstr ""
msgid "Clear due date"
msgstr ""
-msgid "Clear input"
-msgstr ""
-
msgid "Clear recent searches"
msgstr ""
@@ -5087,6 +5238,9 @@ msgstr ""
msgid "Client authentication key password"
msgstr ""
+msgid "Client request timeout"
+msgstr ""
+
msgid "Clients"
msgstr ""
@@ -5171,6 +5325,27 @@ msgstr ""
msgid "Cluster type must be specificed for Stages::ClusterEndpointInserter"
msgstr ""
+msgid "ClusterAgents|Configuration"
+msgstr ""
+
+msgid "ClusterAgents|Connect your cluster with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate Kubernetes with a GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Name"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Agent also requires %{linkStart}enabling the Agent Server%{linkEnd}"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Kubernetes Agent allows an Infrastructure as Code, GitOps approach to integrating Kubernetes clusters with GitLab. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "ClusterAgent|This feature is only available for premium plans"
msgstr ""
@@ -5240,10 +5415,10 @@ msgstr ""
msgid "ClusterIntegration|All installed applications and related resources"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster."
+msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{linkStart}More information%{linkEnd}"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{startLink}More information%{endLink}"
+msgid "ClusterIntegration|Allow GitLab to manage namespaces and service accounts for this cluster."
msgstr ""
msgid "ClusterIntegration|Alternatively, "
@@ -5264,6 +5439,9 @@ msgstr ""
msgid "ClusterIntegration|An error occurred while trying to fetch zone machine types: %{error}"
msgstr ""
+msgid "ClusterIntegration|An unknown error occurred while attempting to connect to Kubernetes."
+msgstr ""
+
msgid "ClusterIntegration|Any project namespaces"
msgstr ""
@@ -5279,6 +5457,9 @@ msgstr ""
msgid "ClusterIntegration|Authenticate with Amazon Web Services"
msgstr ""
+msgid "ClusterIntegration|Authentication Error"
+msgstr ""
+
msgid "ClusterIntegration|Base domain"
msgstr ""
@@ -5297,13 +5478,22 @@ msgstr ""
msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}security group %{externalLinkIcon} %{endLink} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
+msgid "ClusterIntegration|Check your CA certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Check your cluster status"
+msgstr ""
+
+msgid "ClusterIntegration|Check your token"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}subnets %{externalLinkIcon} %{endLink} in your VPC where your worker nodes will run."
+msgid "ClusterIntegration|Choose the %{linkStart}security group %{linkEnd} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
msgstr ""
-msgid "ClusterIntegration|Choose the worker node %{startLink}instance type %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Choose the %{linkStart}subnets %{linkEnd} in your VPC where your worker nodes will run."
+msgstr ""
+
+msgid "ClusterIntegration|Choose the worker node %{linkStart}instance type%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Choose which applications to install on your Kubernetes cluster."
@@ -5315,10 +5505,7 @@ msgstr ""
msgid "ClusterIntegration|Clear cluster cache"
msgstr ""
-msgid "ClusterIntegration|Clear the local cache of namespace and service accounts. This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
-msgstr ""
-
-msgid "ClusterIntegration|Cluster being created"
+msgid "ClusterIntegration|Clear the local cache of namespace and service accounts."
msgstr ""
msgid "ClusterIntegration|Cluster management project (alpha)"
@@ -5330,15 +5517,21 @@ msgstr ""
msgid "ClusterIntegration|Cluster_applications artifact too big. Maximum allowable size: %{human_size}"
msgstr ""
-msgid "ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters."
+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|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}"
+msgid "ClusterIntegration|Clusters connected with a certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Connect cluster with certificate"
msgstr ""
msgid "ClusterIntegration|Connect existing cluster"
msgstr ""
+msgid "ClusterIntegration|Connection Error"
+msgstr ""
+
msgid "ClusterIntegration|Copy API URL"
msgstr ""
@@ -5414,6 +5607,12 @@ msgstr ""
msgid "ClusterIntegration|Deletes all GitLab resources attached to this cluster during removal"
msgstr ""
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared."
+msgstr ""
+
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared. %{linkStart}More information%{linkEnd}"
+msgstr ""
+
msgid "ClusterIntegration|Did you know?"
msgstr ""
@@ -5483,6 +5682,9 @@ msgstr ""
msgid "ClusterIntegration|Fluentd is an open source data collector, which lets you unify the data collection and consumption for a better use and understanding of data. It requires at least one of the following logs to be successfully installed."
msgstr ""
+msgid "ClusterIntegration|GitLab Agent managed clusters"
+msgstr ""
+
msgid "ClusterIntegration|GitLab Container Network Policies"
msgstr ""
@@ -5495,6 +5697,12 @@ msgstr ""
msgid "ClusterIntegration|GitLab Runner connects to the repository and executes CI/CD jobs, pushing results back and deploying applications to production."
msgstr ""
+msgid "ClusterIntegration|GitLab failed to authenticate."
+msgstr ""
+
+msgid "ClusterIntegration|GitLab failed to connect to the cluster."
+msgstr ""
+
msgid "ClusterIntegration|GitLab-managed cluster"
msgstr ""
@@ -5516,6 +5724,9 @@ msgstr ""
msgid "ClusterIntegration|Group cluster"
msgstr ""
+msgid "ClusterIntegration|HTTP Error"
+msgstr ""
+
msgid "ClusterIntegration|Helm Tiller"
msgstr ""
@@ -5549,7 +5760,10 @@ msgstr ""
msgid "ClusterIntegration|Instance type"
msgstr ""
-msgid "ClusterIntegration|Integrate Kubernetes cluster automation"
+msgid "ClusterIntegration|Integrate Kubernetes with a cluster certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Integrate with a cluster certificate"
msgstr ""
msgid "ClusterIntegration|Issuer Email"
@@ -5585,9 +5799,6 @@ msgstr ""
msgid "ClusterIntegration|Knative extends Kubernetes to provide a set of middleware components that are essential to build modern, source-centric, and container-based applications that can run anywhere: on premises, in the cloud, or even in a third-party data center."
msgstr ""
-msgid "ClusterIntegration|Kubernetes cluster"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes cluster is being created..."
msgstr ""
@@ -5600,9 +5811,6 @@ msgstr ""
msgid "ClusterIntegration|Kubernetes clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr ""
-msgid "ClusterIntegration|Kubernetes clusters can be used to deploy applications and to provide Review Apps for this project"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes version"
msgstr ""
@@ -5615,7 +5823,7 @@ msgstr ""
msgid "ClusterIntegration|Learn more about %{help_link_start}zones%{help_link_end}."
msgstr ""
-msgid "ClusterIntegration|Learn more about %{startLink}Regions %{externalLinkIcon}%{endLink}."
+msgid "ClusterIntegration|Learn more about %{linkStart}Regions%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Learn more about Kubernetes"
@@ -5660,12 +5868,18 @@ msgstr ""
msgid "ClusterIntegration|Machine type"
msgstr ""
+msgid "ClusterIntegration|Make sure your API endpoint is correct"
+msgstr ""
+
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create Kubernetes clusters"
msgstr ""
msgid "ClusterIntegration|Manage your Kubernetes cluster by visiting %{provider_link}"
msgstr ""
+msgid "ClusterIntegration|Namespace per environment"
+msgstr ""
+
msgid "ClusterIntegration|No IAM Roles found"
msgstr ""
@@ -5711,6 +5925,9 @@ msgstr ""
msgid "ClusterIntegration|No zones matched your search"
msgstr ""
+msgid "ClusterIntegration|Node calculations use the Kubernetes Metrics API. Make sure your cluster has metrics installed"
+msgstr ""
+
msgid "ClusterIntegration|Number of nodes"
msgstr ""
@@ -5753,6 +5970,9 @@ msgstr ""
msgid "ClusterIntegration|RBAC-enabled cluster"
msgstr ""
+msgid "ClusterIntegration|Read our %{linkStart}help page%{linkEnd} on Kubernetes cluster integration."
+msgstr ""
+
msgid "ClusterIntegration|Read our %{link_start}help page%{link_end} on Kubernetes cluster integration."
msgstr ""
@@ -5855,7 +6075,7 @@ msgstr ""
msgid "ClusterIntegration|Select a VPC to choose a subnet"
msgstr ""
-msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{linkStart}Amazon Web Services %{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select a network to choose a subnetwork"
@@ -5888,7 +6108,7 @@ msgstr ""
msgid "ClusterIntegration|Select project to choose zone"
msgstr ""
-msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select zone"
@@ -5978,9 +6198,18 @@ msgstr ""
msgid "ClusterIntegration|There was a problem authenticating with your cluster. Please ensure your CA Certificate and Token are valid."
msgstr ""
+msgid "ClusterIntegration|There was an HTTP error when connecting to your cluster."
+msgstr ""
+
msgid "ClusterIntegration|This account must have permissions to create a Kubernetes cluster in the %{link_to_container_project} specified below"
msgstr ""
+msgid "ClusterIntegration|This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
+msgstr ""
+
+msgid "ClusterIntegration|This is necessary to clear existing environment-namespace associations from clusters previously managed by GitLab."
+msgstr ""
+
msgid "ClusterIntegration|This option will allow you to install applications on RBAC clusters."
msgstr ""
@@ -6005,9 +6234,21 @@ msgstr ""
msgid "ClusterIntegration|To use a new project, first create one on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}."
msgstr ""
+msgid "ClusterIntegration|Troubleshooting tips:"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Authenticate"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Connect"
+msgstr ""
+
msgid "ClusterIntegration|Uninstall %{appTitle}"
msgstr ""
+msgid "ClusterIntegration|Unknown Error"
+msgstr ""
+
msgid "ClusterIntegration|Update %{appTitle}"
msgstr ""
@@ -6068,7 +6309,7 @@ msgstr ""
msgid "ClusterIntegration|Your cluster API is unreachable. Please ensure your API URL is correct."
msgstr ""
-msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Zone"
@@ -6188,6 +6429,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse all threads"
+msgstr ""
+
msgid "Collapse approvers"
msgstr ""
@@ -6337,7 +6581,7 @@ msgstr ""
msgid "Commit…"
msgstr ""
-msgid "Company"
+msgid "Community forum"
msgstr ""
msgid "Company name"
@@ -6346,6 +6590,9 @@ msgstr ""
msgid "Compare"
msgstr ""
+msgid "Compare %{oldCommitId}...%{newCommitId}"
+msgstr ""
+
msgid "Compare Git revisions"
msgstr ""
@@ -6361,6 +6608,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare submodule commit revisions"
+msgstr ""
+
msgid "Compare with previous version"
msgstr ""
@@ -6496,6 +6746,9 @@ msgstr ""
msgid "Configure the way a user creates a new account."
msgstr ""
+msgid "Configure which lists are shown for anyone who visits this board"
+msgstr ""
+
msgid "Confirm"
msgstr ""
@@ -6721,6 +6974,9 @@ msgstr[1] ""
msgid "ContainerRegistry|Set cleanup policy"
msgstr ""
+msgid "ContainerRegistry|Some tags were not deleted"
+msgstr ""
+
msgid "ContainerRegistry|Something went wrong while fetching the cleanup policy."
msgstr ""
@@ -6760,6 +7016,9 @@ msgstr ""
msgid "ContainerRegistry|Tags with names matching this regex pattern will %{italicStart}expire:%{italicEnd}"
msgstr ""
+msgid "ContainerRegistry|The cleanup policy timed out before it could delete all tags. An administrator can %{adminLinkStart}manually run cleanup now%{adminLinkEnd} or you can wait for the cleanup policy to automatically run again. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "ContainerRegistry|The last tag related to this image was recently removed. This empty image and any associated data will be automatically removed as part of the regular Garbage Collection process. If you have any questions, contact your administrator."
msgstr ""
@@ -6892,6 +7151,9 @@ msgstr ""
msgid "Contributions per group member"
msgstr ""
+msgid "Contributor"
+msgstr ""
+
msgid "Contributors"
msgstr ""
@@ -7021,6 +7283,9 @@ msgstr ""
msgid "Could not change HEAD: branch '%{branch}' does not exist"
msgstr ""
+msgid "Could not commit. An unexpected error occurred."
+msgstr ""
+
msgid "Could not connect to FogBugz, check your URL"
msgstr ""
@@ -7060,6 +7325,9 @@ msgstr ""
msgid "Could not find iteration"
msgstr ""
+msgid "Could not load instance counts. Please refresh the page to try again."
+msgstr ""
+
msgid "Could not remove the trigger."
msgstr ""
@@ -7084,10 +7352,10 @@ msgstr ""
msgid "Could not save prometheus manual configuration"
msgstr ""
-msgid "Could not udpdate wiki page"
+msgid "Could not update the LDAP settings"
msgstr ""
-msgid "Could not update the LDAP settings"
+msgid "Could not update wiki page"
msgstr ""
msgid "Could not upload your designs as one or more files uploaded are not supported."
@@ -7745,6 +8013,9 @@ msgstr ""
msgid "DastProfiles|Are you sure you want to delete this profile?"
msgstr ""
+msgid "DastProfiles|Could not create site validation token. Please refresh the page, or try again later."
+msgstr ""
+
msgid "DastProfiles|Could not create the scanner profile. Please try again."
msgstr ""
@@ -7769,6 +8040,12 @@ msgstr ""
msgid "DastProfiles|Could not fetch site profiles. Please refresh the page, or try again later."
msgstr ""
+msgid "DastProfiles|Could not retrieve site validation status. Please refresh the page, or try again later."
+msgstr ""
+
+msgid "DastProfiles|Could not update the scanner profile. Please try again."
+msgstr ""
+
msgid "DastProfiles|Could not update the site profile. Please try again."
msgstr ""
@@ -7784,7 +8061,7 @@ msgstr ""
msgid "DastProfiles|Download validation text file"
msgstr ""
-msgid "DastProfiles|Edit feature will come soon. Please create a new profile if changes needed"
+msgid "DastProfiles|Edit scanner profile"
msgstr ""
msgid "DastProfiles|Edit site profile"
@@ -7817,6 +8094,9 @@ msgstr ""
msgid "DastProfiles|No profiles created yet"
msgstr ""
+msgid "DastProfiles|Passive"
+msgstr ""
+
msgid "DastProfiles|Please enter a valid URL format, ex: http://www.example.com/home"
msgstr ""
@@ -7832,6 +8112,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan mode"
+msgstr ""
+
msgid "DastProfiles|Scanner Profile"
msgstr ""
@@ -7871,10 +8154,10 @@ msgstr ""
msgid "DastProfiles|Text file validation"
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
+msgid "DastProfiles|The maximum number of minutes allowed for the spider to traverse the site."
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the spider to traverse the site."
+msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
msgstr ""
msgid "DastProfiles|Validate"
@@ -7907,6 +8190,9 @@ msgstr ""
msgid "Date picker"
msgstr ""
+msgid "Date range"
+msgstr ""
+
msgid "Date range cannot exceed %{maxDateRange} days."
msgstr ""
@@ -7931,6 +8217,9 @@ msgstr ""
msgid "Days to merge"
msgstr ""
+msgid "Dear Administrator,"
+msgstr ""
+
msgid "Debug"
msgstr ""
@@ -8042,12 +8331,18 @@ msgstr ""
msgid "Delete"
msgstr ""
+msgid "Delete %{name}"
+msgstr ""
+
msgid "Delete Comment"
msgstr ""
msgid "Delete Snippet"
msgstr ""
+msgid "Delete Value Stream"
+msgstr ""
+
msgid "Delete account"
msgstr ""
@@ -8069,9 +8364,6 @@ msgstr ""
msgid "Delete label: %{label_name} ?"
msgstr ""
-msgid "Delete license"
-msgstr ""
-
msgid "Delete list"
msgstr ""
@@ -8147,15 +8439,6 @@ msgstr ""
msgid "Deleting a project places it into a read-only state until %{date}, at which point the project will be permanently deleted. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "Deleting the license failed."
-msgstr ""
-
-msgid "Deleting the license failed. The license was not found."
-msgstr ""
-
-msgid "Deleting the license failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "Deleting the project will delete its repository and all related resources including issues, merge requests etc."
msgstr ""
@@ -8651,7 +8934,10 @@ msgstr ""
msgid "DesignManagement|The maximum number of designs allowed to be uploaded is %{upload_limit}. Please try again."
msgstr ""
-msgid "DesignManagement|To upload designs, you'll need to enable LFS. %{requirements_link_start}More information%{requirements_link_end}"
+msgid "DesignManagement|There was an error moving your designs. Please upload your designs below."
+msgstr ""
+
+msgid "DesignManagement|To upload designs, you'll need to enable LFS and have admin enable hashed storage. %{requirements_link_start}More information%{requirements_link_end}"
msgstr ""
msgid "DesignManagement|Unresolve thread"
@@ -8663,6 +8949,9 @@ msgstr ""
msgid "DesignManagement|Upload skipped."
msgstr ""
+msgid "DesignManagement|Your designs are being copied and are on their way… Please refresh to update."
+msgstr ""
+
msgid "DesignManagement|and %{moreCount} more."
msgstr ""
@@ -8720,6 +9009,9 @@ msgstr ""
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
+msgid "Direct member"
+msgstr ""
+
msgid "Direction"
msgstr ""
@@ -8768,9 +9060,6 @@ msgstr ""
msgid "Discard draft"
msgstr ""
-msgid "Discard review"
-msgstr ""
-
msgid "DiscordService|Discord Notifications"
msgstr ""
@@ -8839,10 +9128,10 @@ msgstr ""
msgid "Dismiss Merge Request promotion"
msgstr ""
-msgid "Dismiss Selected"
+msgid "Dismiss Value Stream Analytics introduction box"
msgstr ""
-msgid "Dismiss Value Stream Analytics introduction box"
+msgid "Dismiss selected"
msgstr ""
msgid "Dismiss trial promotion"
@@ -8893,9 +9182,6 @@ msgstr ""
msgid "Documents reindexed: %{processed_documents} (%{percentage}%%)"
msgstr ""
-msgid "Doing"
-msgstr ""
-
msgid "Domain"
msgstr ""
@@ -9091,9 +9377,6 @@ msgstr ""
msgid "Edit environment"
msgstr ""
-msgid "Edit file"
-msgstr ""
-
msgid "Edit files in the editor and commit changes here"
msgstr ""
@@ -9106,6 +9389,12 @@ msgstr ""
msgid "Edit identity for %{user_name}"
msgstr ""
+msgid "Edit in Web IDE"
+msgstr ""
+
+msgid "Edit in single-file editor"
+msgstr ""
+
msgid "Edit issues"
msgstr ""
@@ -9133,10 +9422,10 @@ msgstr ""
msgid "Editing"
msgstr ""
-msgid "Elasticsearch"
+msgid "Elasticsearch AWS IAM credentials"
msgstr ""
-msgid "Elasticsearch AWS IAM credentials"
+msgid "Elasticsearch HTTP client timeout value in seconds."
msgstr ""
msgid "Elasticsearch indexing restrictions"
@@ -9145,9 +9434,6 @@ msgstr ""
msgid "Elasticsearch indexing started"
msgstr ""
-msgid "Elasticsearch integration. Elasticsearch AWS IAM."
-msgstr ""
-
msgid "Elasticsearch reindexing is already in progress"
msgstr ""
@@ -9175,9 +9461,6 @@ msgstr ""
msgid "Email Notification"
msgstr ""
-msgid "Email address"
-msgstr ""
-
msgid "Email could not be sent"
msgstr ""
@@ -9241,6 +9524,9 @@ msgstr ""
msgid "Emails sent from Service Desk will have this name"
msgstr ""
+msgid "Emails sent to %{email} will still be supported"
+msgstr ""
+
msgid "Emails separated by comma"
msgstr ""
@@ -9274,9 +9560,18 @@ msgstr ""
msgid "Enable"
msgstr ""
+msgid "Enable %{link_start}Gitpod%{link_end} integration to launch a development environment in your browser directly from GitLab."
+msgstr ""
+
msgid "Enable Auto DevOps"
msgstr ""
+msgid "Enable Gitpod"
+msgstr ""
+
+msgid "Enable Gitpod?"
+msgstr ""
+
msgid "Enable HTML emails"
msgstr ""
@@ -9406,9 +9701,6 @@ msgstr ""
msgid "Encountered an error while rendering: %{err}"
msgstr ""
-msgid "End date"
-msgstr ""
-
msgid "Ends at (UTC)"
msgstr ""
@@ -9568,7 +9860,7 @@ msgstr ""
msgid "EnvironmentsDashboard|The environments dashboard provides a summary of each project's environments' status, including pipeline and alert statuses."
msgstr ""
-msgid "EnvironmentsDashboard|This dashboard displays a maximum of 7 projects and 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
+msgid "EnvironmentsDashboard|This dashboard displays 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
msgstr ""
msgid "Environments|An error occurred while canceling the auto stop, please try again"
@@ -9889,6 +10181,9 @@ msgstr ""
msgid "Error deleting project. Check logs for error details."
msgstr ""
+msgid "Error fetching burnup chart data"
+msgstr ""
+
msgid "Error fetching diverging counts for branches. Please try again."
msgstr ""
@@ -9967,6 +10262,9 @@ msgstr ""
msgid "Error occurred when saving assignees"
msgstr ""
+msgid "Error occurred when saving reviewers"
+msgstr ""
+
msgid "Error occurred when toggling the notification subscription"
msgstr ""
@@ -10219,10 +10517,13 @@ msgstr ""
msgid "Expand all"
msgstr ""
-msgid "Expand approvers"
+msgid "Expand all files"
msgstr ""
-msgid "Expand dropdown"
+msgid "Expand all threads"
+msgstr ""
+
+msgid "Expand approvers"
msgstr ""
msgid "Expand milestones"
@@ -10393,6 +10694,9 @@ msgstr ""
msgid "Failed to create Merge Request. Please try again."
msgstr ""
+msgid "Failed to create To-Do for the design."
+msgstr ""
+
msgid "Failed to create a branch for this issue. Please try again."
msgstr ""
@@ -10432,6 +10736,12 @@ msgstr ""
msgid "Failed to load authors. Please try again."
msgstr ""
+msgid "Failed to load branches. Please try again."
+msgstr ""
+
+msgid "Failed to load deploy keys."
+msgstr ""
+
msgid "Failed to load emoji list."
msgstr ""
@@ -10447,6 +10757,9 @@ msgstr ""
msgid "Failed to load groups & users."
msgstr ""
+msgid "Failed to load groups, users and deploy keys."
+msgstr ""
+
msgid "Failed to load labels. Please try again."
msgstr ""
@@ -10456,6 +10769,12 @@ msgstr ""
msgid "Failed to load related branches"
msgstr ""
+msgid "Failed to load sidebar confidential toggle"
+msgstr ""
+
+msgid "Failed to load sidebar lock status"
+msgstr ""
+
msgid "Failed to load stacktrace."
msgstr ""
@@ -10483,6 +10802,9 @@ msgstr ""
msgid "Failed to publish issue on status page."
msgstr ""
+msgid "Failed to remove To-Do for the design."
+msgstr ""
+
msgid "Failed to remove a Zoom meeting"
msgstr ""
@@ -10525,6 +10847,9 @@ msgstr ""
msgid "Failed to signing using smartcard authentication"
msgstr ""
+msgid "Failed to toggle To-Do for the design."
+msgstr ""
+
msgid "Failed to update branch!"
msgstr ""
@@ -10638,7 +10963,7 @@ msgstr ""
msgid "FeatureFlags|Edit User List"
msgstr ""
-msgid "FeatureFlags|Enable features for specific users and specific environments by defining feature flag strategies."
+msgid "FeatureFlags|Enable features for specific users and environments by configuring feature flag strategies."
msgstr ""
msgid "FeatureFlags|Environment Spec"
@@ -10698,7 +11023,7 @@ msgstr ""
msgid "FeatureFlags|Include additional user IDs"
msgstr ""
-msgid "FeatureFlags|Install a %{docs_link_anchored_start}compatible client library%{docs_link_anchored_end} and specify the API URL, application name, and instance ID during the configuration setup. %{docs_link_start}More Information%{docs_link_end}"
+msgid "FeatureFlags|Install a %{docsLinkAnchoredStart}compatible client library%{docsLinkAnchoredEnd} and specify the API URL, application name, and instance ID during the configuration setup. %{docsLinkStart}More Information%{docsLinkEnd}"
msgstr ""
msgid "FeatureFlags|Instance ID"
@@ -10710,6 +11035,9 @@ msgstr ""
msgid "FeatureFlags|Loading feature flags"
msgstr ""
+msgid "FeatureFlags|Loading user lists"
+msgstr ""
+
msgid "FeatureFlags|More information"
msgstr ""
@@ -10728,7 +11056,7 @@ msgstr ""
msgid "FeatureFlags|New feature flag"
msgstr ""
-msgid "FeatureFlags|New list"
+msgid "FeatureFlags|New user list"
msgstr ""
msgid "FeatureFlags|Percent of users"
@@ -10767,6 +11095,9 @@ msgstr ""
msgid "FeatureFlags|There was an error fetching the feature flags."
msgstr ""
+msgid "FeatureFlags|There was an error fetching the user lists."
+msgstr ""
+
msgid "FeatureFlags|There was an error retrieving user lists"
msgstr ""
@@ -10782,6 +11113,9 @@ msgstr ""
msgid "FeatureFlags|User List"
msgstr ""
+msgid "FeatureFlags|User Lists"
+msgstr ""
+
msgid "FeatureFlag|List"
msgstr ""
@@ -10809,15 +11143,6 @@ msgstr ""
msgid "Fetching incoming email"
msgstr ""
-msgid "Fetching licenses failed."
-msgstr ""
-
-msgid "Fetching licenses failed. The request endpoint was not found."
-msgstr ""
-
-msgid "Fetching licenses failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "File"
msgstr ""
@@ -10920,12 +11245,21 @@ msgstr ""
msgid "Filter by status"
msgstr ""
+msgid "Filter by test cases that are currently archived."
+msgstr ""
+
+msgid "Filter by test cases that are currently opened."
+msgstr ""
+
msgid "Filter by two-factor authentication"
msgstr ""
msgid "Filter by user"
msgstr ""
+msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
+msgstr ""
+
msgid "Filter pipelines"
msgstr ""
@@ -10941,7 +11275,7 @@ msgstr ""
msgid "Filter results..."
msgstr ""
-msgid "Filter your projects by name"
+msgid "Filter your repositories by name"
msgstr ""
msgid "Filter..."
@@ -10950,7 +11284,7 @@ msgstr ""
msgid "Find File"
msgstr ""
-msgid "Find bugs in your code with coverage-guided fuzzing"
+msgid "Find bugs in your code with coverage-guided fuzzing."
msgstr ""
msgid "Find by path"
@@ -10977,9 +11311,6 @@ msgstr ""
msgid "Finish editing this message first!"
msgstr ""
-msgid "Finish review"
-msgstr ""
-
msgid "Finish setting up your dedicated account for %{group_name}."
msgstr ""
@@ -11049,6 +11380,9 @@ msgstr ""
msgid "Footer message"
msgstr ""
+msgid "For a faster browsing experience, some files are collapsed by default."
+msgstr ""
+
msgid "For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
@@ -11058,6 +11392,9 @@ msgstr ""
msgid "For more info, read the documentation."
msgstr ""
+msgid "For more information on how the number of active users is calculated, see the %{self_managed_subscriptions_doc_link} documentation."
+msgstr ""
+
msgid "For more information, go to the "
msgstr ""
@@ -11196,6 +11533,9 @@ msgstr ""
msgid "Generate new token"
msgstr ""
+msgid "Generic package file size in bytes"
+msgstr ""
+
msgid "Geo"
msgstr ""
@@ -11457,6 +11797,9 @@ msgstr ""
msgid "Geo|Please refer to Geo Troubleshooting."
msgstr ""
+msgid "Geo|Primary node"
+msgstr ""
+
msgid "Geo|Project"
msgstr ""
@@ -11499,6 +11842,9 @@ msgstr ""
msgid "Geo|Review replication status, and resynchronize and reverify items with the primary node."
msgstr ""
+msgid "Geo|Secondary node"
+msgstr ""
+
msgid "Geo|Status"
msgstr ""
@@ -11538,6 +11884,9 @@ msgstr ""
msgid "Geo|URL must be a valid url (ex: https://gitlab.com)"
msgstr ""
+msgid "Geo|Undefined"
+msgstr ""
+
msgid "Geo|Unknown state"
msgstr ""
@@ -11613,10 +11962,16 @@ msgstr ""
msgid "GitHub import"
msgstr ""
+msgid "GitLab"
+msgstr ""
+
msgid "GitLab / Unsubscribe"
msgstr ""
-msgid "GitLab Enterprise Edition %{plan}"
+msgid "GitLab API"
+msgstr ""
+
+msgid "GitLab Billing Team."
msgstr ""
msgid "GitLab Group Runners can execute code for all the projects in this group."
@@ -11628,12 +11983,18 @@ msgstr ""
msgid "GitLab Issue"
msgstr ""
+msgid "GitLab Pages"
+msgstr ""
+
msgid "GitLab Service Desk is a simple way to allow people to create issues in your GitLab instance without needing their own user account. It provides a unique email address for end users to create issues in a project, and replies can be sent either through the GitLab interface or by email. End users will only see the thread through email."
msgstr ""
msgid "GitLab Shared Runners execute code of different projects on the same Runner unless you configure GitLab Runner Autoscale with MaxBuilds 1 (which it is on GitLab.com)."
msgstr ""
+msgid "GitLab Shell"
+msgstr ""
+
msgid "GitLab Support Bot"
msgstr ""
@@ -11643,7 +12004,7 @@ msgstr ""
msgid "GitLab User"
msgstr ""
-msgid "GitLab allows you to continue using your license even if you exceed the number of seats you purchased. You will be required to pay for these seats when you renew your license."
+msgid "GitLab Workhorse"
msgstr ""
msgid "GitLab commit"
@@ -11811,6 +12172,21 @@ msgstr ""
msgid "Gitlab Pages"
msgstr ""
+msgid "Gitpod"
+msgstr ""
+
+msgid "Gitpod|Add the URL to your Gitpod instance configured to read your GitLab projects."
+msgstr ""
+
+msgid "Gitpod|Enable Gitpod integration"
+msgstr ""
+
+msgid "Gitpod|Gitpod URL"
+msgstr ""
+
+msgid "Gitpod|e.g. https://gitpod.example.com"
+msgstr ""
+
msgid "Given access %{time_ago}"
msgstr ""
@@ -12318,9 +12694,6 @@ msgstr ""
msgid "GroupSAML|Valid SAML Response"
msgstr ""
-msgid "GroupSAML|With group managed accounts enabled, all the users without a group managed account will be excluded from the group."
-msgstr ""
-
msgid "GroupSAML|With prohibit outer forks flag enabled group members will be able to fork project only inside your group."
msgstr ""
@@ -12534,10 +12907,10 @@ msgstr ""
msgid "GroupsNew|Create group"
msgstr ""
-msgid "GroupsNew|GitLab group export"
+msgid "GroupsNew|Import"
msgstr ""
-msgid "GroupsNew|Import"
+msgid "GroupsNew|Import a GitLab group export file"
msgstr ""
msgid "GroupsNew|Import group"
@@ -12680,6 +13053,9 @@ msgid_plural "Hide charts"
msgstr[0] ""
msgstr[1] ""
+msgid "Hide comments on this file"
+msgstr ""
+
msgid "Hide details"
msgstr ""
@@ -12724,6 +13100,15 @@ msgstr ""
msgid "Highest role:"
msgstr ""
+msgid "HighlightBar|Alert events:"
+msgstr ""
+
+msgid "HighlightBar|Alert start time:"
+msgstr ""
+
+msgid "HighlightBar|Original alert:"
+msgstr ""
+
msgid "History"
msgstr ""
@@ -12901,6 +13286,9 @@ msgstr ""
msgid "If enabled, access to projects will be validated on an external service using their classification label."
msgstr ""
+msgid "If the number of active users exceeds the user limit, you will be charged for the number of %{users_over_license_link} at your next license reconciliation."
+msgstr ""
+
msgid "If there is no previous license or if the previous license has expired, some GitLab functionality will be blocked until a new, valid license is uploaded."
msgstr ""
@@ -12940,9 +13328,6 @@ msgstr ""
msgid "If your HTTP repository is not publicly accessible, add your credentials."
msgstr ""
-msgid "Iglu registry URL (optional)"
-msgstr ""
-
msgid "Ignore"
msgstr ""
@@ -12979,6 +13364,16 @@ msgstr ""
msgid "Import"
msgstr ""
+msgid "Import %d compatible repository"
+msgid_plural "Import %d compatible repositories"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Import %d repository"
+msgid_plural "Import %d repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Import CSV"
msgstr ""
@@ -12988,15 +13383,9 @@ msgstr ""
msgid "Import all compatible projects"
msgstr ""
-msgid "Import all compatible repositories"
-msgstr ""
-
msgid "Import all projects"
msgstr ""
-msgid "Import all repositories"
-msgstr ""
-
msgid "Import an exported GitLab project"
msgstr ""
@@ -13084,6 +13473,9 @@ msgstr ""
msgid "ImportProjects|Error importing repository %{project_safe_import_url} into %{project_full_path} - %{message}"
msgstr ""
+msgid "ImportProjects|Import repositories"
+msgstr ""
+
msgid "ImportProjects|Importing the project failed"
msgstr ""
@@ -13096,7 +13488,7 @@ msgstr ""
msgid "ImportProjects|Requesting your %{provider} repositories failed"
msgstr ""
-msgid "ImportProjects|Select the projects you want to import"
+msgid "ImportProjects|Select the repositories you want to import"
msgstr ""
msgid "ImportProjects|The remote data could not be imported."
@@ -13132,9 +13524,6 @@ msgstr ""
msgid "In order to enable Service Desk for your instance, you must first set up incoming email."
msgstr ""
-msgid "In order to gather accurate feature usage data, it can take 1 to 2 weeks to see your index."
-msgstr ""
-
msgid "In order to personalize your experience with GitLab%{br_tag}we would like to know a bit more about you."
msgstr ""
@@ -13165,18 +13554,30 @@ msgstr ""
msgid "IncidentManagement|Create incident"
msgstr ""
+msgid "IncidentManagement|Critical - S1"
+msgstr ""
+
msgid "IncidentManagement|Date created"
msgstr ""
msgid "IncidentManagement|Display your incidents in a dedicated view"
msgstr ""
+msgid "IncidentManagement|High - S2"
+msgstr ""
+
msgid "IncidentManagement|Incident"
msgstr ""
msgid "IncidentManagement|Incidents"
msgstr ""
+msgid "IncidentManagement|Low - S4"
+msgstr ""
+
+msgid "IncidentManagement|Medium - S3"
+msgstr ""
+
msgid "IncidentManagement|No incidents to display."
msgstr ""
@@ -13189,6 +13590,9 @@ msgstr ""
msgid "IncidentManagement|Published to status page"
msgstr ""
+msgid "IncidentManagement|Severity"
+msgstr ""
+
msgid "IncidentManagement|There are no closed incidents"
msgstr ""
@@ -13198,6 +13602,9 @@ msgstr ""
msgid "IncidentManagement|Unassigned"
msgstr ""
+msgid "IncidentManagement|Unknown"
+msgstr ""
+
msgid "IncidentManagement|Unpublished"
msgstr ""
@@ -13219,6 +13626,15 @@ msgstr ""
msgid "Incidents"
msgstr ""
+msgid "Incident|Alert details"
+msgstr ""
+
+msgid "Incident|Summary"
+msgstr ""
+
+msgid "Incident|There was an issue loading alert data. Please try again."
+msgstr ""
+
msgid "Include a Terms of Service agreement and Privacy Policy that all users must accept."
msgstr ""
@@ -13279,6 +13695,9 @@ msgstr ""
msgid "Information about additional Pages templates and how to install them can be found in our %{pages_getting_started_guide}."
msgstr ""
+msgid "Inherited"
+msgstr ""
+
msgid "Inherited:"
msgstr ""
@@ -13359,7 +13778,22 @@ msgstr ""
msgid "Instance administrators group already exists"
msgstr ""
-msgid "Instance license"
+msgid "InstanceStatistics|Groups"
+msgstr ""
+
+msgid "InstanceStatistics|Issues"
+msgstr ""
+
+msgid "InstanceStatistics|Merge Requests"
+msgstr ""
+
+msgid "InstanceStatistics|Pipelines"
+msgstr ""
+
+msgid "InstanceStatistics|Projects"
+msgstr ""
+
+msgid "InstanceStatistics|Users"
msgstr ""
msgid "Integration"
@@ -13371,6 +13805,12 @@ msgstr ""
msgid "Integrations"
msgstr ""
+msgid "Integrations|%{integration} settings saved and active."
+msgstr ""
+
+msgid "Integrations|%{integration} settings saved, but not active."
+msgstr ""
+
msgid "Integrations|All details"
msgstr ""
@@ -13380,6 +13820,12 @@ msgstr ""
msgid "Integrations|Comment settings:"
msgstr ""
+msgid "Integrations|Connection failed. Please check your settings."
+msgstr ""
+
+msgid "Integrations|Connection successful."
+msgstr ""
+
msgid "Integrations|Default settings are inherited from the group level."
msgstr ""
@@ -13395,6 +13841,15 @@ msgstr ""
msgid "Integrations|Includes commit title and branch"
msgstr ""
+msgid "Integrations|Projects using custom settings will not be impacted unless the project owner chooses to use instance-level defaults."
+msgstr ""
+
+msgid "Integrations|Save settings?"
+msgstr ""
+
+msgid "Integrations|Saving will update the default settings for all projects that are not using custom settings."
+msgstr ""
+
msgid "Integrations|Standard"
msgstr ""
@@ -13527,6 +13982,9 @@ msgstr ""
msgid "Invitation"
msgstr ""
+msgid "Invitation declined"
+msgstr ""
+
msgid "Invite"
msgstr ""
@@ -13578,6 +14036,42 @@ 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|%{linkStart}Read more%{linkEnd} about role permissions"
+msgstr ""
+
+msgid "InviteMembersModal|Access expiration date (optional)"
+msgstr ""
+
+msgid "InviteMembersModal|Cancel"
+msgstr ""
+
+msgid "InviteMembersModal|Choose a role permission"
+msgstr ""
+
+msgid "InviteMembersModal|GitLab member or Email address"
+msgstr ""
+
+msgid "InviteMembersModal|Invite"
+msgstr ""
+
+msgid "InviteMembersModal|Invite team members"
+msgstr ""
+
+msgid "InviteMembersModal|Search for members to invite"
+msgstr ""
+
+msgid "InviteMembersModal|User not invited. Feature coming soon!"
+msgstr ""
+
+msgid "InviteMembersModal|Users were succesfully added"
+msgstr ""
+
+msgid "InviteMembersModal|You're inviting members to the %{group_name} group"
+msgstr ""
+
+msgid "InviteMembers|Invite team members"
+msgstr ""
+
msgid "Invited"
msgstr ""
@@ -13632,10 +14126,13 @@ msgstr ""
msgid "Issue cannot be found."
msgstr ""
+msgid "Issue created from vulnerability %{vulnerability_link}"
+msgstr ""
+
msgid "Issue events"
msgstr ""
-msgid "Issue first depoloyed to production"
+msgid "Issue first deployed to production"
msgstr ""
msgid "Issue label"
@@ -13713,6 +14210,9 @@ msgstr ""
msgid "IssueTracker|Custom issue tracker"
msgstr ""
+msgid "IssueTracker|EWM work items tracker"
+msgstr ""
+
msgid "IssueTracker|Redmine issue tracker"
msgstr ""
@@ -13779,6 +14279,9 @@ msgstr ""
msgid "It looks like you have some draft commits in this branch."
msgstr ""
+msgid "It may be several days before you see feature usage data."
+msgstr ""
+
msgid "It must have a header row and at least two columns: the first column is the issue title and the second column is the issue description. The separator is automatically detected."
msgstr ""
@@ -14061,13 +14564,13 @@ msgstr ""
msgid "Join Zoom meeting"
msgstr ""
-msgid "Jul"
+msgid "Joined %{time_ago}"
msgstr ""
-msgid "July"
+msgid "Jul"
msgstr ""
-msgid "Jump to first unresolved thread"
+msgid "July"
msgstr ""
msgid "Jump to next unresolved thread"
@@ -14103,6 +14606,9 @@ msgstr ""
msgid "Keyboard shortcuts"
msgstr ""
+msgid "KeyboardKey|Ctrl+"
+msgstr ""
+
msgid "Keys"
msgstr ""
@@ -14151,6 +14657,9 @@ msgstr ""
msgid "LDAP Synchronization"
msgstr ""
+msgid "LDAP group settings"
+msgstr ""
+
msgid "LDAP settings"
msgstr ""
@@ -14160,6 +14669,9 @@ msgstr ""
msgid "LDAP sync in progress. This could take a few minutes. Refresh the page to see the changes."
msgstr ""
+msgid "LDAP synchronizations"
+msgstr ""
+
msgid "LFS"
msgstr ""
@@ -14240,7 +14752,16 @@ msgid_plural "Last %d days"
msgstr[0] ""
msgstr[1] ""
-msgid "Last %{days} days"
+msgid "Last 2 weeks"
+msgstr ""
+
+msgid "Last 30 days"
+msgstr ""
+
+msgid "Last 60 days"
+msgstr ""
+
+msgid "Last 90 days"
msgstr ""
msgid "Last Accessed On"
@@ -14318,6 +14839,9 @@ msgstr ""
msgid "Last used on:"
msgstr ""
+msgid "Last week"
+msgstr ""
+
msgid "LastCommit|authored"
msgstr ""
@@ -14333,6 +14857,9 @@ msgstr ""
msgid "Latest pipeline for the most recent commit on this branch"
msgstr ""
+msgid "Launch a ready-to-code development environment for your project."
+msgstr ""
+
msgid "Lead"
msgstr ""
@@ -14713,6 +15240,9 @@ msgstr ""
msgid "List of all merge commits"
msgstr ""
+msgid "List options"
+msgstr ""
+
msgid "List settings"
msgstr ""
@@ -14725,9 +15255,6 @@ msgstr ""
msgid "List your Bitbucket Server repositories"
msgstr ""
-msgid "Lists"
-msgstr ""
-
msgid "Live preview"
msgstr ""
@@ -14974,6 +15501,12 @@ msgstr ""
msgid "Mark as done"
msgstr ""
+msgid "Mark as draft"
+msgstr ""
+
+msgid "Mark as ready"
+msgstr ""
+
msgid "Mark as resolved"
msgstr ""
@@ -14995,6 +15528,24 @@ msgstr ""
msgid "Markdown is supported"
msgstr ""
+msgid "MarkdownEditor|Add a link (%{modifierKey}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add a link (%{modifier_key}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifierKey}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifier_key}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifierKey}I)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifier_key}I)"
+msgstr ""
+
msgid "Marked For Deletion At - %{deletion_time}"
msgstr ""
@@ -15079,7 +15630,25 @@ msgstr ""
msgid "Max access level"
msgstr ""
-msgid "Max seats used"
+msgid "Max role"
+msgstr ""
+
+msgid "Max size 15 MB"
+msgstr ""
+
+msgid "Maximum Conan package file size in bytes"
+msgstr ""
+
+msgid "Maximum Maven package file size in bytes"
+msgstr ""
+
+msgid "Maximum NPM package file size in bytes"
+msgstr ""
+
+msgid "Maximum NuGet package file size in bytes"
+msgstr ""
+
+msgid "Maximum PyPI package file size in bytes"
msgstr ""
msgid "Maximum Users:"
@@ -15211,6 +15780,18 @@ msgstr ""
msgid "Members with access to %{strong_start}%{group_name}%{strong_end}"
msgstr ""
+msgid "Members|%{time} by %{user}"
+msgstr ""
+
+msgid "Members|Expired"
+msgstr ""
+
+msgid "Members|No expiration set"
+msgstr ""
+
+msgid "Members|in %{time}"
+msgstr ""
+
msgid "Memory Usage"
msgstr ""
@@ -15397,9 +15978,6 @@ msgstr ""
msgid "MergeRequests|Thread will be unresolved"
msgstr ""
-msgid "MergeRequests|Toggle comments for this file"
-msgstr ""
-
msgid "MergeRequests|View file @ %{commitId}"
msgstr ""
@@ -15460,6 +16038,9 @@ msgstr ""
msgid "Merging immediately isn't recommended as it may negatively impact the existing merge train. Read the %{docsLinkStart}documentation%{docsLinkEnd} for more information."
msgstr ""
+msgid "Message"
+msgstr ""
+
msgid "Messages"
msgstr ""
@@ -15845,18 +16426,12 @@ msgid_plural "Milestones"
msgstr[0] ""
msgstr[1] ""
-msgid "Milestone does not support burnup charts"
-msgstr ""
-
msgid "Milestone lists not available with your current license"
msgstr ""
msgid "Milestone lists show all issues from the selected milestone."
msgstr ""
-msgid "Milestone must have a start and due date"
-msgstr ""
-
msgid "MilestoneSidebar|Closed:"
msgstr ""
@@ -16223,6 +16798,9 @@ msgstr ""
msgid "Namespace"
msgstr ""
+msgid "Namespace ID:"
+msgstr ""
+
msgid "Namespace is empty"
msgstr ""
@@ -16307,6 +16885,9 @@ msgstr ""
msgid "NetworkPolicies|Allow all outbound traffic from %{selector} to %{ruleSelector} on %{ports}"
msgstr ""
+msgid "NetworkPolicies|Are you sure you want to delete this policy? This action cannot be undone."
+msgstr ""
+
msgid "NetworkPolicies|Choose whether to enforce this policy."
msgstr ""
@@ -16316,12 +16897,21 @@ msgstr ""
msgid "NetworkPolicies|Define this policy's location, conditions and actions."
msgstr ""
+msgid "NetworkPolicies|Delete policy"
+msgstr ""
+
+msgid "NetworkPolicies|Delete policy: %{policy}"
+msgstr ""
+
msgid "NetworkPolicies|Deny all traffic"
msgstr ""
msgid "NetworkPolicies|Description"
msgstr ""
+msgid "NetworkPolicies|Edit policy"
+msgstr ""
+
msgid "NetworkPolicies|Editor mode"
msgstr ""
@@ -16349,6 +16939,9 @@ msgstr ""
msgid "NetworkPolicies|Name"
msgstr ""
+msgid "NetworkPolicies|Namespace"
+msgstr ""
+
msgid "NetworkPolicies|Network Policy"
msgstr ""
@@ -16400,6 +16993,9 @@ msgstr ""
msgid "NetworkPolicies|Rules"
msgstr ""
+msgid "NetworkPolicies|Save changes"
+msgstr ""
+
msgid "NetworkPolicies|Something went wrong, failed to update policy"
msgstr ""
@@ -16412,6 +17008,9 @@ msgstr ""
msgid "NetworkPolicies|Traffic that does not match any rule will be blocked."
msgstr ""
+msgid "NetworkPolicies|Unable to parse policy"
+msgstr ""
+
msgid "NetworkPolicies|YAML editor"
msgstr ""
@@ -16525,6 +17124,9 @@ msgstr ""
msgid "New Snippet"
msgstr ""
+msgid "New Test Case"
+msgstr ""
+
msgid "New User"
msgstr ""
@@ -16624,6 +17226,9 @@ msgstr ""
msgid "New tag"
msgstr ""
+msgid "New test case"
+msgstr ""
+
msgid "New users set to external"
msgstr ""
@@ -16696,7 +17301,7 @@ msgstr ""
msgid "No changes"
msgstr ""
-msgid "No changes between %{ref_start}%{source_branch}%{ref_end} and %{ref_start}%{target_branch}%{ref_end}"
+msgid "No changes between %{sourceBranch} and %{targetBranch}"
msgstr ""
msgid "No child epics match applied filters"
@@ -16711,6 +17316,9 @@ msgstr ""
msgid "No containers available"
msgstr ""
+msgid "No content to show"
+msgstr ""
+
msgid "No contributions"
msgstr ""
@@ -16786,9 +17394,6 @@ msgstr ""
msgid "No license. All rights reserved"
msgstr ""
-msgid "No licenses found."
-msgstr ""
-
msgid "No matches found"
msgstr ""
@@ -16801,6 +17406,9 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No members found"
+msgstr ""
+
msgid "No merge requests found"
msgstr ""
@@ -16822,6 +17430,9 @@ msgstr ""
msgid "No parent group"
msgstr ""
+msgid "No plan"
+msgstr ""
+
msgid "No pods available"
msgstr ""
@@ -16918,6 +17529,12 @@ msgstr ""
msgid "Not Implemented"
msgstr ""
+msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+msgstr ""
+
+msgid "Not all browsers support WebAuthn. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even from an unsupported browser."
+msgstr ""
+
msgid "Not all data has been processed yet, the accuracy of the chart for the selected timeframe is limited."
msgstr ""
@@ -17014,6 +17631,9 @@ msgstr ""
msgid "Notification settings saved"
msgstr ""
+msgid "NotificationEvent|Change reviewer merge request"
+msgstr ""
+
msgid "NotificationEvent|Close issue"
msgstr ""
@@ -17176,10 +17796,7 @@ msgstr ""
msgid "On track"
msgstr ""
-msgid "OnDemandScans|Attached branch"
-msgstr ""
-
-msgid "OnDemandScans|Attached branch is where the scan job runs."
+msgid "OnDemandScans|Could not fetch scanner profiles. Please refresh the page, or try again later."
msgstr ""
msgid "OnDemandScans|Could not fetch site profiles. Please refresh the page, or try again later."
@@ -17188,6 +17805,9 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
+msgid "OnDemandScans|Create a new scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Create a new site profile"
msgstr ""
@@ -17200,6 +17820,9 @@ msgstr ""
msgid "OnDemandScans|New on-demand DAST scan"
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 ""
@@ -17209,16 +17832,10 @@ msgstr ""
msgid "OnDemandScans|On-demand scans run outside the DevOps cycle and find vulnerabilities in your projects. %{learnMoreLinkStart}Learn more%{learnMoreLinkEnd}"
msgstr ""
-msgid "OnDemandScans|Only a passive scan can be performed on demand."
-msgstr ""
-
-msgid "OnDemandScans|Passive"
-msgstr ""
-
msgid "OnDemandScans|Run scan"
msgstr ""
-msgid "OnDemandScans|Scan mode"
+msgid "OnDemandScans|Scanner profile"
msgstr ""
msgid "OnDemandScans|Scanner settings"
@@ -17230,9 +17847,15 @@ msgstr ""
msgid "OnDemandScans|Select one of the existing profiles"
msgstr ""
+msgid "OnDemandScans|Site profile"
+msgstr ""
+
msgid "OnDemandScans|Site profiles"
msgstr ""
+msgid "OnDemandScans|Use existing scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Use existing site profile"
msgstr ""
@@ -17331,9 +17954,6 @@ msgstr ""
msgid "Open Selection"
msgstr ""
-msgid "Open Web IDE"
-msgstr ""
-
msgid "Open comment type dropdown"
msgstr ""
@@ -17439,6 +18059,9 @@ msgstr ""
msgid "Origin"
msgstr ""
+msgid "Orphaned member"
+msgstr ""
+
msgid "Other Labels"
msgstr ""
@@ -17454,6 +18077,9 @@ msgstr ""
msgid "Other visibility settings have been disabled by the administrator."
msgstr ""
+msgid "Our documentation includes an example DevOps Score report."
+msgstr ""
+
msgid "Out-of-compliance with this project's policies and should be removed"
msgstr ""
@@ -17478,6 +18104,9 @@ msgstr ""
msgid "Overwrite diverged branches"
msgstr ""
+msgid "Owned by %{image_tag}"
+msgstr ""
+
msgid "Owned by anyone"
msgstr ""
@@ -17499,6 +18128,9 @@ msgstr ""
msgid "Package deleted successfully"
msgstr ""
+msgid "Package file size limits"
+msgstr ""
+
msgid "Package recipe already exists"
msgstr ""
@@ -17514,9 +18146,6 @@ msgstr ""
msgid "Package type must be PyPi"
msgstr ""
-msgid "Package was removed"
-msgstr ""
-
msgid "PackageRegistry|%{name} version %{version} was created %{datetime}"
msgstr ""
@@ -17658,12 +18287,18 @@ msgstr ""
msgid "PackageRegistry|NuGet Command"
msgstr ""
+msgid "PackageRegistry|Package Registry"
+msgstr ""
+
msgid "PackageRegistry|Pip Command"
msgstr ""
msgid "PackageRegistry|Pipeline %{link} triggered %{datetime} by %{author}"
msgstr ""
+msgid "PackageRegistry|Publish and share packages for a variety of common package managers. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "PackageRegistry|Published to the %{project} Package Registry %{datetime}"
msgstr ""
@@ -17763,6 +18398,9 @@ msgstr ""
msgid "Page not found"
msgstr ""
+msgid "Page settings"
+msgstr ""
+
msgid "Page was successfully deleted"
msgstr ""
@@ -17904,7 +18542,7 @@ msgstr ""
msgid "Paste issue link"
msgstr ""
-msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Don't use your private SSH key."
+msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Do not paste your private SSH key, as that can compromise your identity."
msgstr ""
msgid "Patch to apply"
@@ -17931,6 +18569,9 @@ msgstr ""
msgid "Pending"
msgstr ""
+msgid "Pending comments"
+msgstr ""
+
msgid "People without permission will never get a notification and won't be able to comment."
msgstr ""
@@ -18129,6 +18770,9 @@ msgstr ""
msgid "Pipelines|Build with confidence"
msgstr ""
+msgid "Pipelines|By revoking a trigger you will break any processes making use of it. Are you sure?"
+msgstr ""
+
msgid "Pipelines|CI Lint"
msgstr ""
@@ -18141,6 +18785,15 @@ msgstr ""
msgid "Pipelines|Continuous Integration can help catch bugs by running your tests automatically, while Continuous Deployment can help you deliver code to your product environment."
msgstr ""
+msgid "Pipelines|Copy trigger token"
+msgstr ""
+
+msgid "Pipelines|Description"
+msgstr ""
+
+msgid "Pipelines|Edit"
+msgstr ""
+
msgid "Pipelines|Get started with Pipelines"
msgstr ""
@@ -18156,15 +18809,27 @@ msgstr ""
msgid "Pipelines|It is recommended the code is reviewed thoroughly before running this pipeline with the parent project's CI resource."
msgstr ""
+msgid "Pipelines|Last Used"
+msgstr ""
+
msgid "Pipelines|Loading Pipelines"
msgstr ""
msgid "Pipelines|More Information"
msgstr ""
+msgid "Pipelines|No triggers have been created yet. Add one using the form above."
+msgstr ""
+
+msgid "Pipelines|Owner"
+msgstr ""
+
msgid "Pipelines|Project cache successfully reset."
msgstr ""
+msgid "Pipelines|Revoke"
+msgstr ""
+
msgid "Pipelines|Run Pipeline"
msgstr ""
@@ -18189,6 +18854,15 @@ msgstr ""
msgid "Pipelines|This project is not currently set up to run pipelines."
msgstr ""
+msgid "Pipelines|Token"
+msgstr ""
+
+msgid "Pipelines|Trigger user has insufficient permissions to project"
+msgstr ""
+
+msgid "Pipelines|invalid"
+msgstr ""
+
msgid "Pipelines|parent"
msgstr ""
@@ -18447,10 +19121,10 @@ msgstr ""
msgid "Please provide attributes to update"
msgstr ""
-msgid "Please refer to %{docs_url}"
+msgid "Please reach out if you have any questions and we'll be happy to assist."
msgstr ""
-msgid "Please retype the email address."
+msgid "Please refer to %{docs_url}"
msgstr ""
msgid "Please select"
@@ -18480,6 +19154,9 @@ msgstr ""
msgid "Please set a new password before proceeding."
msgstr ""
+msgid "Please share your feedback about %{featureName} %{linkStart}in this issue%{linkEnd} to help us improve the experience."
+msgstr ""
+
msgid "Please solve the reCAPTCHA"
msgstr ""
@@ -18783,6 +19460,9 @@ msgstr ""
msgid "Profiles| You are going to change the username %{currentUsernameBold} to %{newUsernameBold}. Profile and projects will be redirected to the %{newUsername} namespace but this redirect will expire once the %{currentUsername} namespace is registered by another user or group. Please update your Git repository remotes as soon as possible."
msgstr ""
+msgid "Profiles|%{provider} Active"
+msgstr ""
+
msgid "Profiles|@username"
msgstr ""
@@ -18834,7 +19514,7 @@ msgstr ""
msgid "Profiles|Commit email"
msgstr ""
-msgid "Profiles|Connect"
+msgid "Profiles|Connect %{provider}"
msgstr ""
msgid "Profiles|Connected Accounts"
@@ -18858,6 +19538,9 @@ msgstr ""
msgid "Profiles|Disconnect"
msgstr ""
+msgid "Profiles|Disconnect %{provider}"
+msgstr ""
+
msgid "Profiles|Do not show on profile"
msgstr ""
@@ -18882,7 +19565,7 @@ msgstr ""
msgid "Profiles|Full name"
msgstr ""
-msgid "Profiles|Give your individual key a title. This will be publically visible."
+msgid "Profiles|Give your individual key a title."
msgstr ""
msgid "Profiles|Include private contributions on my profile"
@@ -18972,7 +19655,7 @@ msgstr ""
msgid "Profiles|The maximum file size allowed is 200KB."
msgstr ""
-msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it?"
+msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it? It will be publicly visible."
msgstr ""
msgid "Profiles|This email will be displayed on your public profile"
@@ -19047,6 +19730,9 @@ msgstr ""
msgid "Profiles|You don't have access to delete this user."
msgstr ""
+msgid "Profiles|You must transfer ownership or delete groups you are an owner of before you can delete your account"
+msgstr ""
+
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
@@ -19635,6 +20321,9 @@ msgstr ""
msgid "ProjectTemplates|GitLab Cluster Management"
msgstr ""
+msgid "ProjectTemplates|Gitpod/Spring Petclinic"
+msgstr ""
+
msgid "ProjectTemplates|Go Micro"
msgstr ""
@@ -20244,6 +20933,9 @@ msgstr ""
msgid "Publish to status page"
msgstr ""
+msgid "Published"
+msgstr ""
+
msgid "Published on status page"
msgstr ""
@@ -20361,9 +21053,15 @@ msgstr ""
msgid "Quick range"
msgstr ""
+msgid "Quickly and easily edit multiple files in your project."
+msgstr ""
+
msgid "README"
msgstr ""
+msgid "Rails"
+msgstr ""
+
msgid "Rake Tasks Help"
msgstr ""
@@ -20483,10 +21181,13 @@ msgstr ""
msgid "Register Two-Factor Authenticator"
msgstr ""
-msgid "Register U2F device"
+msgid "Register Universal Two-Factor (U2F) Device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register WebAuthn Device"
+msgstr ""
+
+msgid "Register device"
msgstr ""
msgid "Register for GitLab"
@@ -20498,9 +21199,6 @@ msgstr ""
msgid "Register with two-factor app"
msgstr ""
-msgid "Registration"
-msgstr ""
-
msgid "Registration|Checkout"
msgstr ""
@@ -20617,9 +21315,6 @@ msgstr ""
msgid "Release|Something went wrong while saving the release details"
msgstr ""
-msgid "Remediated: needs review"
-msgstr ""
-
msgid "Remediations"
msgstr ""
@@ -20725,6 +21420,9 @@ msgstr ""
msgid "Remove priority"
msgstr ""
+msgid "Remove report"
+msgstr ""
+
msgid "Remove secondary node"
msgstr ""
@@ -20737,6 +21435,12 @@ msgstr ""
msgid "Remove time estimate"
msgstr ""
+msgid "Remove user & report"
+msgstr ""
+
+msgid "Remove user from group"
+msgstr ""
+
msgid "Removed"
msgstr ""
@@ -20818,9 +21522,6 @@ msgstr ""
msgid "Removes time estimate."
msgstr ""
-msgid "Removing license…"
-msgstr ""
-
msgid "Removing this group also removes all child projects, including archived projects, and their resources."
msgstr ""
@@ -20905,6 +21606,9 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
+msgid "Reported by %{reporter}"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -20991,6 +21695,27 @@ msgstr ""
msgid "Repositories"
msgstr ""
+msgid "Repositories Analytics"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download Historic Test Coverage Data"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download historic test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Historic Test Coverage Data is available in raw format (.csv) for further analysis."
+msgstr ""
+
+msgid "RepositoriesAnalytics|Test Code Coverage"
+msgstr ""
+
+msgid "RepositoriesAnalytics|There was an error fetching the projects."
+msgstr ""
+
msgid "Repository"
msgstr ""
@@ -21069,9 +21794,15 @@ msgstr ""
msgid "Request parameter %{param} is missing."
msgstr ""
+msgid "Request review from"
+msgstr ""
+
msgid "Request to link SAML account must be authorized"
msgstr ""
+msgid "Requested"
+msgstr ""
+
msgid "Requested %{time_ago}"
msgstr ""
@@ -21090,6 +21821,9 @@ msgstr ""
msgid "Requests to these domain(s)/address(es) on the local network will be allowed when local requests from hooks and services are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 or 127.0.0.0/28 are supported. Domain wildcards are not supported currently. Use comma, semicolon, or newline to separate multiple entries. The allowlist can hold a maximum of 1000 entries. Domains should use IDNA encoding. Ex: example.com, 192.168.1.1, 127.0.0.0/28, xn--itlab-j1a.com."
msgstr ""
+msgid "Require admin approval for new sign-ups"
+msgstr ""
+
msgid "Require all users in this group to setup Two-factor authentication"
msgstr ""
@@ -21217,9 +21951,6 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
-msgid "Resolved by %{resolvedByName}"
-msgstr ""
-
msgid "Resolves IP addresses once and uses them to submit requests"
msgstr ""
@@ -21339,6 +22070,14 @@ msgstr ""
msgid "ReviewApp|Enable Review App"
msgstr ""
+msgid "Reviewer"
+msgid_plural "%d Reviewers"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Reviewer(s)"
+msgstr ""
+
msgid "Reviewing"
msgstr ""
@@ -21378,6 +22117,9 @@ msgstr ""
msgid "Rook"
msgstr ""
+msgid "Ruby"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -21456,6 +22198,63 @@ msgstr ""
msgid "Runners page."
msgstr ""
+msgid "Runners|Active"
+msgstr ""
+
+msgid "Runners|Architecture"
+msgstr ""
+
+msgid "Runners|Can run untagged jobs"
+msgstr ""
+
+msgid "Runners|Description"
+msgstr ""
+
+msgid "Runners|Group"
+msgstr ""
+
+msgid "Runners|IP Address"
+msgstr ""
+
+msgid "Runners|Last contact"
+msgstr ""
+
+msgid "Runners|Locked to this project"
+msgstr ""
+
+msgid "Runners|Maximum job timeout"
+msgstr ""
+
+msgid "Runners|Name"
+msgstr ""
+
+msgid "Runners|Platform"
+msgstr ""
+
+msgid "Runners|Property Name"
+msgstr ""
+
+msgid "Runners|Protected"
+msgstr ""
+
+msgid "Runners|Revision"
+msgstr ""
+
+msgid "Runners|Shared"
+msgstr ""
+
+msgid "Runners|Specific"
+msgstr ""
+
+msgid "Runners|Tags"
+msgstr ""
+
+msgid "Runners|Value"
+msgstr ""
+
+msgid "Runners|Version"
+msgstr ""
+
msgid "Runners|You have used %{quotaUsed} out of %{quotaLimit} of your shared Runners pipeline minutes."
msgstr ""
@@ -21468,6 +22267,9 @@ msgstr ""
msgid "Runs a number of housekeeping tasks within the current repository, such as compressing file revisions and removing unreachable objects."
msgstr ""
+msgid "SAML"
+msgstr ""
+
msgid "SAML SSO"
msgstr ""
@@ -21519,6 +22321,9 @@ msgstr ""
msgid "Save"
msgstr ""
+msgid "Save %{name} size limits"
+msgstr ""
+
msgid "Save Changes"
msgstr ""
@@ -21549,9 +22354,6 @@ msgstr ""
msgid "Save space and find tags in the Container Registry more easily. Enable the cleanup policy to remove stale tags and keep only the ones you need."
msgstr ""
-msgid "Save template"
-msgstr ""
-
msgid "Save variables"
msgstr ""
@@ -21594,9 +22396,6 @@ msgstr ""
msgid "Scope"
msgstr ""
-msgid "Scope not supported with disabled 'users_search' feature!"
-msgstr ""
-
msgid "Scoped issue boards"
msgstr ""
@@ -21723,9 +22522,6 @@ msgstr ""
msgid "Search requirements"
msgstr ""
-msgid "Search results…"
-msgstr ""
-
msgid "Search users"
msgstr ""
@@ -21798,6 +22594,11 @@ msgid_plural "SearchResults|commits"
msgstr[0] ""
msgstr[1] ""
+msgid "SearchResults|epic"
+msgid_plural "SearchResults|epics"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "SearchResults|issue"
msgid_plural "SearchResults|issues"
msgstr[0] ""
@@ -21842,10 +22643,10 @@ msgstr ""
msgid "Seat Link is disabled, and cannot be configured through this form."
msgstr ""
-msgid "Seats currently in use"
+msgid "Seats usage data as of %{last_enqueue_time}"
msgstr ""
-msgid "Seats in license"
+msgid "Seats usage data is updated every day at 12:00pm UTC"
msgstr ""
msgid "Secondary"
@@ -21899,6 +22700,9 @@ msgstr ""
msgid "SecurityConfiguration|Available for on-demand DAST"
msgstr ""
+msgid "SecurityConfiguration|By default, all analyzers are applied in order to cover all languages across your project, and only run if the language is detected in the Merge Request."
+msgstr ""
+
msgid "SecurityConfiguration|Configure"
msgstr ""
@@ -21929,16 +22733,19 @@ msgstr ""
msgid "SecurityConfiguration|Manage"
msgstr ""
+msgid "SecurityConfiguration|More information"
+msgstr ""
+
msgid "SecurityConfiguration|Not enabled"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|Security Control"
+msgid "SecurityConfiguration|SAST Configuration"
msgstr ""
-msgid "SecurityConfiguration|See documentation"
+msgid "SecurityConfiguration|Security Control"
msgstr ""
msgid "SecurityConfiguration|Status"
@@ -21950,6 +22757,9 @@ msgstr ""
msgid "SecurityConfiguration|Using custom settings. You won't receive automatic updates on this variable. %{anchorStart}Restore to default%{anchorEnd}"
msgstr ""
+msgid "SecurityConfiguration|View history"
+msgstr ""
+
msgid "SecurityConfiguration|You can quickly enable all security scanning tools by enabling %{linkStart}Auto DevOps%{linkEnd}."
msgstr ""
@@ -22028,9 +22838,6 @@ msgstr ""
msgid "SecurityReports|Learn more about setting up your dashboard"
msgstr ""
-msgid "SecurityReports|Load more vulnerabilities"
-msgstr ""
-
msgid "SecurityReports|Monitor vulnerabilities in your code"
msgstr ""
@@ -22310,7 +23117,7 @@ msgstr ""
msgid "Select status"
msgstr ""
-msgid "Select strategy activation method"
+msgid "Select strategy activation method."
msgstr ""
msgid "Select subscription"
@@ -22325,7 +23132,7 @@ msgstr ""
msgid "Select the custom project template source group."
msgstr ""
-msgid "Select timeframe"
+msgid "Select the environment scope for this feature flag."
msgstr ""
msgid "Select timezone"
@@ -22574,6 +23381,9 @@ msgstr ""
msgid "Set iteration"
msgstr ""
+msgid "Set limit to 0 to allow any file size."
+msgstr ""
+
msgid "Set max session time for web terminal."
msgstr ""
@@ -22652,10 +23462,13 @@ msgstr ""
msgid "Set up a %{type} Runner manually"
msgstr ""
+msgid "Set up a hardware device as a second factor to sign in."
+msgstr ""
+
msgid "Set up assertions/attributes/claims (email, first_name, last_name) and NameID according to %{docsLinkStart}the documentation %{icon}%{docsLinkEnd}"
msgstr ""
-msgid "Set up new U2F device"
+msgid "Set up new device"
msgstr ""
msgid "Set up new password"
@@ -22724,6 +23537,9 @@ msgstr ""
msgid "Sets weight to %{weight}."
msgstr ""
+msgid "Setting this to 0 means using the system default timeout value."
+msgstr ""
+
msgid "Settings"
msgstr ""
@@ -22739,6 +23555,15 @@ msgstr ""
msgid "Severity"
msgstr ""
+msgid "SeverityWidget|Severity"
+msgstr ""
+
+msgid "SeverityWidget|Severity: %{severity}"
+msgstr ""
+
+msgid "SeverityWidget|There was an error while updating severity."
+msgstr ""
+
msgid "Shards (%{shards})"
msgstr ""
@@ -22784,6 +23609,9 @@ msgstr ""
msgid "Show all requirements."
msgstr ""
+msgid "Show all test cases."
+msgstr ""
+
msgid "Show archived projects"
msgstr ""
@@ -22796,6 +23624,9 @@ msgstr ""
msgid "Show comments"
msgstr ""
+msgid "Show comments on this file"
+msgstr ""
+
msgid "Show comments only"
msgstr ""
@@ -22841,6 +23672,12 @@ msgstr ""
msgid "Show parent subgroups"
msgstr ""
+msgid "Show the Closed list"
+msgstr ""
+
+msgid "Show the Open list"
+msgstr ""
+
msgid "Show whitespace changes"
msgstr ""
@@ -22884,9 +23721,6 @@ msgstr ""
msgid "Sidebar|Assign health status"
msgstr ""
-msgid "Sidebar|Change weight"
-msgstr ""
-
msgid "Sidebar|Health status"
msgstr ""
@@ -23070,6 +23904,9 @@ msgstr ""
msgid "Snippets|Add another file %{num}/%{total}"
msgstr ""
+msgid "Snippets|Authored %{time_ago} by %{author}"
+msgstr ""
+
msgid "Snippets|Delete file"
msgstr ""
@@ -23097,6 +23934,9 @@ msgstr ""
msgid "Solution"
msgstr ""
+msgid "Some changes are not shown"
+msgstr ""
+
msgid "Some child epics may be hidden due to applied filters"
msgstr ""
@@ -23463,6 +24303,12 @@ msgstr ""
msgid "Source (branch or tag)"
msgstr ""
+msgid "Source Branch"
+msgstr ""
+
+msgid "Source branch: %{source_branch_open}%{source_branch}%{source_branch_close}"
+msgstr ""
+
msgid "Source code"
msgstr ""
@@ -23628,9 +24474,6 @@ msgstr ""
msgid "Start and due date"
msgstr ""
-msgid "Start by choosing a group to see how your team is spending time. You can then drill down to the project level."
-msgstr ""
-
msgid "Start by choosing a group to start exploring the merge requests in that group. You can then proceed to filter by projects, labels, milestones and authors."
msgstr ""
@@ -23712,18 +24555,27 @@ msgstr ""
msgid "StaticSiteEditor|3. Assign a person to review and accept the merge request."
msgstr ""
+msgid "StaticSiteEditor|A link to view the merge request will appear once ready."
+msgstr ""
+
msgid "StaticSiteEditor|An error occurred while submitting your changes."
msgstr ""
msgid "StaticSiteEditor|Branch could not be created."
msgstr ""
+msgid "StaticSiteEditor|Copy update"
+msgstr ""
+
msgid "StaticSiteEditor|Could not commit the content changes."
msgstr ""
msgid "StaticSiteEditor|Could not create merge request."
msgstr ""
+msgid "StaticSiteEditor|Creating your merge request"
+msgstr ""
+
msgid "StaticSiteEditor|Incompatible file content"
msgstr ""
@@ -23745,6 +24597,9 @@ msgstr ""
msgid "StaticSiteEditor|View documentation"
msgstr ""
+msgid "StaticSiteEditor|You can set an assignee to get your changes reviewed and deployed once your merge request is created."
+msgstr ""
+
msgid "StaticSiteEditor|Your merge request has been created"
msgstr ""
@@ -23874,15 +24729,15 @@ msgstr ""
msgid "Submit %{humanized_resource_name}"
msgstr ""
-msgid "Submit Changes"
-msgstr ""
-
msgid "Submit a review"
msgstr ""
msgid "Submit as spam"
msgstr ""
+msgid "Submit changes"
+msgstr ""
+
msgid "Submit feedback"
msgstr ""
@@ -24036,6 +24891,9 @@ msgstr ""
msgid "Successfully deleted U2F device."
msgstr ""
+msgid "Successfully deleted WebAuthn device."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -24354,9 +25212,6 @@ msgstr ""
msgid "Template to append to all Service Desk issues"
msgstr ""
-msgid "Template was successfully saved."
-msgstr ""
-
msgid "Templates"
msgstr ""
@@ -24435,10 +25290,28 @@ msgid_plural "Test coverage: %d hits"
msgstr[0] ""
msgstr[1] ""
-msgid "Test failed."
+msgid "Test settings"
msgstr ""
-msgid "Test settings and save changes"
+msgid "TestCases|New Test Case"
+msgstr ""
+
+msgid "TestCases|New test case"
+msgstr ""
+
+msgid "TestCases|Search test cases"
+msgstr ""
+
+msgid "TestCases|Something went wrong while creating a test case."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching count of test cases."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching test cases list."
+msgstr ""
+
+msgid "TestCases|Submit test case"
msgstr ""
msgid "TestHooks|Ensure one of your projects has merge requests."
@@ -24504,6 +25377,9 @@ msgstr ""
msgid "Thank you for signing up for your free trial! You will get additional instructions in your inbox shortly."
msgstr ""
+msgid "Thank you for your business."
+msgstr ""
+
msgid "Thank you for your feedback!"
msgstr ""
@@ -24563,9 +25439,6 @@ msgstr ""
msgid "The URL to use for connecting to Elasticsearch. Use a comma-separated list to support clustering (e.g., \"http://localhost:9200, http://localhost:9201\")."
msgstr ""
-msgid "The Web IDE offers advanced syntax highlighting capabilities and more."
-msgstr ""
-
msgid "The X509 Certificate to use when mutual TLS is required to communicate with the external authorization service. If left blank, the server certificate is still validated when accessing over HTTPS."
msgstr ""
@@ -24676,6 +25549,9 @@ msgstr ""
msgid "The form contains the following error:"
msgstr ""
+msgid "The form contains the following warning:"
+msgstr ""
+
msgid "The global settings require you to enable Two-Factor Authentication for your account."
msgstr ""
@@ -24790,9 +25666,6 @@ msgstr ""
msgid "The private key to use when a client certificate is provided. This value is encrypted at rest."
msgstr ""
-msgid "The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The project can be accessed by any logged in user."
msgstr ""
@@ -24829,7 +25702,7 @@ msgstr ""
msgid "The remote repository is being updated..."
msgstr ""
-msgid "The repository can be commited to, and issues, comments and other entities can be created."
+msgid "The repository can be committed to, and issues, comments and other entities can be created."
msgstr ""
msgid "The repository for this project does not exist."
@@ -24883,9 +25756,6 @@ msgstr ""
msgid "The time taken by each data entry gathered by that stage."
msgstr ""
-msgid "The total stage shows the time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The update action will time out after %{number_of_minutes} minutes. For big repositories, use a clone/push combination."
msgstr ""
@@ -24949,6 +25819,9 @@ msgstr ""
msgid "There are no archived requirements"
msgstr ""
+msgid "There are no archived test cases"
+msgstr ""
+
msgid "There are no changes"
msgstr ""
@@ -24988,6 +25861,9 @@ msgstr ""
msgid "There are no open requirements"
msgstr ""
+msgid "There are no open test cases"
+msgstr ""
+
msgid "There are no packages yet"
msgstr ""
@@ -25000,6 +25876,9 @@ msgstr ""
msgid "There is a limit of %{ci_project_subscriptions_limit} subscriptions from or to a project."
msgstr ""
+msgid "There is already a To-Do for this design."
+msgstr ""
+
msgid "There is already a repository with that name on disk"
msgstr ""
@@ -25018,6 +25897,9 @@ msgstr ""
msgid "There was a problem communicating with your device."
msgstr ""
+msgid "There was a problem fetching branches."
+msgstr ""
+
msgid "There was a problem fetching groups."
msgstr ""
@@ -25246,9 +26128,15 @@ msgstr ""
msgid "This action can lead to data loss. To prevent accidental actions we ask you to confirm your intention."
msgstr ""
+msgid "This action cannot be undone, and will permanently delete the %{key} SSH key"
+msgstr ""
+
msgid "This action cannot be undone. You will lose the project's repository and all content: issues, merge requests, etc."
msgstr ""
+msgid "This action has been performed too many times. Try again later."
+msgstr ""
+
msgid "This action will %{strongOpen}permanently delete%{strongClose} %{codeOpen}%{project}%{codeClose} %{strongOpen}immediately%{strongClose}, including its repositories and all content: issues, merge requests, etc."
msgstr ""
@@ -25276,9 +26164,6 @@ msgstr ""
msgid "This board's scope is reduced"
msgstr ""
-msgid "This branch has changed since you started editing. Would you like to create a new branch?"
-msgstr ""
-
msgid "This chart could not be displayed"
msgstr ""
@@ -25405,15 +26290,9 @@ msgstr ""
msgid "This is a security log of important events involving your account."
msgstr ""
-msgid "This is the author's first Merge Request to this project."
-msgstr ""
-
msgid "This is the highest peak of users on your installation since the license started."
msgstr ""
-msgid "This is the maximum number of users that have existed at the same time since the license started. This is the minimum number of seats you will need to buy when you renew your license."
-msgstr ""
-
msgid "This is the number of currently active users on your installation, and this is the minimum number you need to purchase when you renew your license."
msgstr ""
@@ -25645,6 +26524,15 @@ msgstr ""
msgid "This user has no identities"
msgstr ""
+msgid "This user has previously committed to the %{name} project."
+msgstr ""
+
+msgid "This user has the %{access} role in the %{name} project."
+msgstr ""
+
+msgid "This user is the author of this %{noteable}."
+msgstr ""
+
msgid "This user will be the author of all events in the activity feed that are the result of an update, like new branches being created or new commits being pushed to existing branches."
msgstr ""
@@ -25675,6 +26563,9 @@ msgstr ""
msgid "Threat Monitoring"
msgstr ""
+msgid "ThreatMonitoring|All Environments"
+msgstr ""
+
msgid "ThreatMonitoring|Anomalous Requests"
msgstr ""
@@ -25702,9 +26593,6 @@ msgstr ""
msgid "ThreatMonitoring|Operations Per Second"
msgstr ""
-msgid "ThreatMonitoring|Overview"
-msgstr ""
-
msgid "ThreatMonitoring|Packet Activity"
msgstr ""
@@ -25723,6 +26611,9 @@ msgstr ""
msgid "ThreatMonitoring|Something went wrong, unable to fetch statistics"
msgstr ""
+msgid "ThreatMonitoring|Statistics"
+msgstr ""
+
msgid "ThreatMonitoring|The firewall is not installed or has been disabled. To view this data, ensure the web application firewall is installed and enabled for your cluster."
msgstr ""
@@ -26114,6 +27005,9 @@ msgstr ""
msgid "To update Snippets with multiple files, you must use the `files` parameter"
msgstr ""
+msgid "To use Gitpod you must first enable the feature in the integrations section of your %{user_prefs}."
+msgstr ""
+
msgid "To view all %{scannedResourcesCount} scanned URLs, please download the CSV file"
msgstr ""
@@ -26147,9 +27041,6 @@ msgstr ""
msgid "Toggle Sidebar"
msgstr ""
-msgid "Toggle all threads"
-msgstr ""
-
msgid "Toggle backtrace"
msgstr ""
@@ -26174,9 +27065,6 @@ msgstr ""
msgid "Toggle navigation"
msgstr ""
-msgid "Toggle project"
-msgstr ""
-
msgid "Toggle sidebar"
msgstr ""
@@ -26216,6 +27104,9 @@ msgstr ""
msgid "Too many projects enabled. You will need to manage them via the console or the API."
msgstr ""
+msgid "Too much data"
+msgstr ""
+
msgid "Topics (optional)"
msgstr ""
@@ -26234,6 +27125,9 @@ msgstr ""
msgid "Total cores (CPUs)"
msgstr ""
+msgid "Total days to completion"
+msgstr ""
+
msgid "Total issues"
msgstr ""
@@ -26330,6 +27224,9 @@ msgstr ""
msgid "Trending"
msgstr ""
+msgid "Trials|Create a new group to start your GitLab Gold trial."
+msgstr ""
+
msgid "Trials|Go back to GitLab"
msgstr ""
@@ -26339,6 +27236,15 @@ msgstr ""
msgid "Trials|You can always resume this process by selecting your avatar and choosing 'Start a Gold trial'"
msgstr ""
+msgid "Trials|You can apply your trial to a new group or an existing group."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group or your personal account."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group, an existing group, or your personal account."
+msgstr ""
+
msgid "Trials|You won't get a free trial right now but you can always resume this process by clicking on your avatar and choosing 'Start a free trial'"
msgstr ""
@@ -26408,6 +27314,9 @@ msgstr ""
msgid "Try using a different search term to find the file you are looking for."
msgstr ""
+msgid "Trying to communicate with your device. Plug it in (if needed) and press the button on the device now."
+msgstr ""
+
msgid "Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now."
msgstr ""
@@ -26495,6 +27404,12 @@ msgstr ""
msgid "URL or request ID"
msgstr ""
+msgid "USER %{user} WILL BE REMOVED! Are you sure?"
+msgstr ""
+
+msgid "USER WILL BE BLOCKED! Are you sure?"
+msgstr ""
+
msgid "UTC"
msgstr ""
@@ -26552,9 +27467,6 @@ msgstr ""
msgid "Unable to load the merge request widget. Try reloading the page."
msgstr ""
-msgid "Unable to resolve"
-msgstr ""
-
msgid "Unable to save iteration. Please try again"
msgstr ""
@@ -26603,6 +27515,9 @@ msgstr ""
msgid "Undo ignore"
msgstr ""
+msgid "Unexpected error"
+msgstr ""
+
msgid "Unfortunately, your email message to GitLab could not be processed."
msgstr ""
@@ -26636,6 +27551,9 @@ msgstr ""
msgid "Unknown response text"
msgstr ""
+msgid "Unless otherwise agreed to in writing with GitLab, by clicking \"Upload License\" you agree that your use of GitLab Software is subject to the %{eula_link_start}Terms of Service%{eula_link_end}."
+msgstr ""
+
msgid "Unlimited"
msgstr ""
@@ -27002,9 +27920,6 @@ msgstr ""
msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
msgstr ""
-msgid "Use a hardware device to add the second factor of authentication."
-msgstr ""
-
msgid "Use an one time password authenticator on your mobile device or computer to enable two-factor authentication (2FA)."
msgstr ""
@@ -27278,13 +28193,13 @@ msgstr ""
msgid "Users"
msgstr ""
-msgid "Users in License:"
+msgid "Users in License"
msgstr ""
-msgid "Users or groups set as approvers in the project's or merge request's settings."
+msgid "Users in License:"
msgstr ""
-msgid "Users outside of license"
+msgid "Users or groups set as approvers in the project's or merge request's settings."
msgstr ""
msgid "Users over License:"
@@ -27302,9 +28217,6 @@ msgstr ""
msgid "Users with a Guest role or those who don't belong to a Project or Group will not use a seat from your license."
msgstr ""
-msgid "Users with a Guest role or those who don't belong to any projects or groups don't count towards seats in use."
-msgstr ""
-
msgid "UsersSelect|%{name} + %{length} more"
msgstr ""
@@ -27344,9 +28256,6 @@ msgstr ""
msgid "Validations failed."
msgstr ""
-msgid "Validity"
-msgstr ""
-
msgid "Value"
msgstr ""
@@ -27365,6 +28274,9 @@ msgstr ""
msgid "Value Stream Name"
msgstr ""
+msgid "ValueStreamAnalyticsStage|We don't have enough data to show this stage."
+msgstr ""
+
msgid "ValueStreamAnalytics|%{days}d"
msgstr ""
@@ -27621,6 +28533,9 @@ msgstr ""
msgid "VisualReviewApp|Steps 1 and 2 (and sometimes 3) are performed once by the developer before requesting feedback. Steps 3 (if necessary), 4 is performed by the reviewer each time they perform a review."
msgstr ""
+msgid "Visualization"
+msgstr ""
+
msgid "Vulnerabilities"
msgstr ""
@@ -27648,34 +28563,31 @@ msgstr ""
msgid "VulnerabilityChart|Severity"
msgstr ""
-msgid "VulnerabilityManagement|A true-positive and will fix"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Change status"
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|Confirm"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Confirmed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
-msgstr ""
-
-msgid "VulnerabilityManagement|Detected %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|A true-positive and will fix"
msgstr ""
-msgid "VulnerabilityManagement|Dismiss"
+msgid "VulnerabilityManagement|Change status"
msgstr ""
-msgid "VulnerabilityManagement|Dismissed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
msgstr ""
-msgid "VulnerabilityManagement|Resolved"
+msgid "VulnerabilityManagement|Detected"
msgstr ""
-msgid "VulnerabilityManagement|Resolved %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Needs triage"
msgstr ""
msgid "VulnerabilityManagement|Something went wrong while trying to delete the comment. Please try again later."
@@ -27726,6 +28638,9 @@ msgstr ""
msgid "Vulnerability|%{scannerName} (version %{scannerVersion})"
msgstr ""
+msgid "Vulnerability|Activity"
+msgstr ""
+
msgid "Vulnerability|Class"
msgstr ""
@@ -27738,6 +28653,9 @@ msgstr ""
msgid "Vulnerability|Description"
msgstr ""
+msgid "Vulnerability|Detected"
+msgstr ""
+
msgid "Vulnerability|Evidence"
msgstr ""
@@ -27801,6 +28719,9 @@ msgstr ""
msgid "Warning: Displaying this diagram might cause performance issues on this page."
msgstr ""
+msgid "We are currently unable to fetch data for the pipeline header."
+msgstr ""
+
msgid "We are currently unable to fetch data for this graph."
msgstr ""
@@ -27840,6 +28761,12 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
+msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
+msgstr ""
+
+msgid "We would like to inform you that your subscription GitLab Enterprise Edition %{plan_name} is nearing its user limit. You have %{active_user_count} active users, which is almost at the user limit of %{maximum_user_count}."
+msgstr ""
+
msgid "We've found no vulnerabilities"
msgstr ""
@@ -27855,6 +28782,12 @@ msgstr ""
msgid "Web terminal"
msgstr ""
+msgid "WebAuthn Devices (%{length})"
+msgstr ""
+
+msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
+msgstr ""
+
msgid "WebIDE|Merge request"
msgstr ""
@@ -27993,15 +28926,9 @@ msgstr ""
msgid "Welcome to the guided GitLab tour"
msgstr ""
-msgid "Welcome to your Issue Board!"
-msgstr ""
-
msgid "Welcome to your issue board!"
msgstr ""
-msgid "We’ve been making changes to %{featureName} and we’d love your feedback %{linkStart}in this issue%{linkEnd} to help us improve the experience."
-msgstr ""
-
msgid "What are you searching for?"
msgstr ""
@@ -28020,6 +28947,9 @@ msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
msgstr ""
+msgid "When enabled, any user visiting %{host} and creating an account will have to be explicitly approved by the admin before they can login. This setting is effective only if sign-ups are enabled."
+msgstr ""
+
msgid "When enabled, any user visiting %{host} will be able to create an account."
msgstr ""
@@ -28244,6 +29174,9 @@ msgstr ""
msgid "With requirements, you can set criteria to check your products against."
msgstr ""
+msgid "With test cases, you can define conditions for your project to meet in determining quality"
+msgstr ""
+
msgid "Withdraw Access Request"
msgstr ""
@@ -28259,6 +29192,9 @@ msgstr ""
msgid "Workflow Help"
msgstr ""
+msgid "Would you like to create a new branch?"
+msgstr ""
+
msgid "Write"
msgstr ""
@@ -28280,6 +29216,9 @@ msgstr ""
msgid "Wrong extern UID provided. Make sure Auth0 is configured correctly."
msgstr ""
+msgid "YYYY-MM-DD"
+msgstr ""
+
msgid "Yes"
msgstr ""
@@ -28337,7 +29276,7 @@ msgstr ""
msgid "You are going to remove the fork relationship from %{project_full_name}. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "You are going to transfer %{project_full_name} to another owner. Are you ABSOLUTELY sure?"
+msgid "You are going to transfer %{project_full_name} to another namespace. Are you ABSOLUTELY sure?"
msgstr ""
msgid "You are going to turn off the confidentiality. This means %{strongStart}everyone%{strongEnd} will be able to see and leave a comment on this %{issuableType}."
@@ -28397,9 +29336,6 @@ msgstr ""
msgid "You can always edit this later"
msgstr ""
-msgid "You can apply your Trial to your Personal account or create a New Group."
-msgstr ""
-
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings"
msgstr ""
@@ -28421,12 +29357,18 @@ msgstr ""
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
+msgid "You can find more information about GitLab subscriptions in %{subscriptions_doc_link}."
+msgstr ""
+
msgid "You can generate an access token scoped to this project for each application to use the GitLab API."
msgstr ""
msgid "You can get started by cloning the repository or start adding files to it with one of the following options."
msgstr ""
+msgid "You can group test cases using labels. To learn about the future direction of this feature, visit %{linkStart}Quality Management direction page%{linkEnd}."
+msgstr ""
+
msgid "You can invite a new member to %{project_name} or invite another group."
msgstr ""
@@ -28442,6 +29384,9 @@ msgstr ""
msgid "You can notify the app / group or a project by sending them an email notification"
msgstr ""
+msgid "You can now close this window."
+msgstr ""
+
msgid "You can now export your security dashboard to a CSV report."
msgstr ""
@@ -28490,9 +29435,6 @@ msgstr ""
msgid "You can test your .gitlab-ci.yml in %{linkStart}CI Lint%{linkEnd}."
msgstr ""
-msgid "You can try again using %{begin_link}basic search%{end_link}"
-msgstr ""
-
msgid "You cannot access the raw file. Please wait a minute."
msgstr ""
@@ -28544,6 +29486,9 @@ msgstr ""
msgid "You don't have any U2F devices registered yet."
msgstr ""
+msgid "You don't have any WebAuthn devices registered yet."
+msgstr ""
+
msgid "You don't have any active chat names."
msgstr ""
@@ -28631,6 +29576,9 @@ msgstr ""
msgid "You must accept our Terms of Service and privacy policy in order to register an account"
msgstr ""
+msgid "You must be logged in to search across all of GitLab"
+msgstr ""
+
msgid "You must disassociate %{domain} from all clusters it is attached to before deletion."
msgstr ""
@@ -28670,7 +29618,7 @@ msgstr ""
msgid "You need to be logged in."
msgstr ""
-msgid "You need to register a two-factor authentication app before you can set up a U2F device."
+msgid "You need to register a two-factor authentication app before you can set up a device."
msgstr ""
msgid "You need to set terms to be enforced"
@@ -28688,6 +29636,9 @@ msgstr ""
msgid "You reached %{usage_in_percent} of %{namespace_name}'s storage capacity (%{used_storage} of %{storage_limit})"
msgstr ""
+msgid "You successfully declined the invitation"
+msgstr ""
+
msgid "You tried to fork %{link_to_the_project} but it failed for the following reason:"
msgstr ""
@@ -28853,10 +29804,13 @@ msgstr ""
msgid "Your U2F device did not send a valid JSON response."
msgstr ""
-msgid "Your U2F device needs to be set up. Plug it in (if not already) and click the button on the left."
+msgid "Your U2F device was registered!"
msgstr ""
-msgid "Your U2F device was registered!"
+msgid "Your WebAuthn device did not send a valid JSON response."
+msgstr ""
+
+msgid "Your WebAuthn device was registered!"
msgstr ""
msgid "Your access request to the %{source_type} has been withdrawn."
@@ -28880,6 +29834,9 @@ msgstr ""
msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
msgstr ""
+msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
+msgstr ""
+
msgid "Your changes can be committed to %{branch_name} because a merge request is open."
msgstr ""
@@ -28916,6 +29873,12 @@ msgstr ""
msgid "Your deployment services will be broken, you will need to manually fix the services after renaming."
msgstr ""
+msgid "Your device is not compatible with GitLab. Please try another device"
+msgstr ""
+
+msgid "Your device needs to be set up. Plug it in (if needed) and click the button on the left."
+msgstr ""
+
msgid "Your device was successfully set up! Give it a name and register it with the GitLab server."
msgstr ""
@@ -29029,9 +29992,6 @@ msgstr[1] ""
msgid "access:"
msgstr ""
-msgid "activated"
-msgstr ""
-
msgid "added %{created_at_timeago}"
msgstr ""
@@ -29104,9 +30064,21 @@ msgstr ""
msgid "by %{user}"
msgstr ""
+msgid "cannot be a date in the past"
+msgstr ""
+
msgid "cannot be changed if a personal project has container registry tags."
msgstr ""
+msgid "cannot be changed if shared runners are enabled"
+msgstr ""
+
+msgid "cannot be enabled because parent group does not allow it"
+msgstr ""
+
+msgid "cannot be enabled because parent group has shared Runners disabled"
+msgstr ""
+
msgid "cannot be enabled unless all domains have TLS certificates"
msgstr ""
@@ -29152,7 +30124,7 @@ msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about SAST %{linkEndTag}"
msgstr ""
-msgid "ciReport|%{linkStartTag}Learn more about Secret Scanning %{linkEndTag}"
+msgid "ciReport|%{linkStartTag}Learn more about Secret Detection %{linkEndTag}"
msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about codequality reports %{linkEndTag}"
@@ -29467,9 +30439,6 @@ msgstr ""
msgid "error"
msgstr ""
-msgid "error code:"
-msgstr ""
-
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr ""
@@ -29491,6 +30460,9 @@ msgstr ""
msgid "failed to dismiss associated finding(id=%{finding_id}): %{message}"
msgstr ""
+msgid "failed to revert associated finding(id=%{finding_id}) to detected"
+msgstr ""
+
msgid "file"
msgid_plural "files"
msgstr[0] ""
@@ -30033,6 +31005,9 @@ msgstr ""
msgid "must be a root namespace"
msgstr ""
+msgid "must be a valid IPv4 or IPv6 address"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -30069,6 +31044,9 @@ msgstr ""
msgid "no expiration"
msgstr ""
+msgid "no name set"
+msgstr ""
+
msgid "no one can merge"
msgstr ""
@@ -30247,9 +31225,6 @@ msgstr ""
msgid "security Reports|There was an error creating the merge request"
msgstr ""
-msgid "settings saved, but not activated"
-msgstr ""
-
msgid "severity|Critical"
msgstr ""
@@ -30376,9 +31351,6 @@ msgstr ""
msgid "toggle collapse"
msgstr ""
-msgid "toggle dropdown"
-msgstr ""
-
msgid "triggered"
msgstr ""
@@ -30406,6 +31378,9 @@ msgstr ""
msgid "user avatar"
msgstr ""
+msgid "user preferences"
+msgstr ""
+
msgid "username"
msgstr ""
diff --git a/locale/bn_IN/gitlab.po b/locale/bn_IN/gitlab.po
index 15d36fcc4e5..cab59b3f095 100644
--- a/locale/bn_IN/gitlab.po
+++ b/locale/bn_IN/gitlab.po
@@ -14,7 +14,10 @@ msgstr ""
"X-Crowdin-Language: bn-IN\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 6\n"
-"PO-Revision-Date: 2020-09-04 23:05\n"
+"PO-Revision-Date: 2020-10-02 18:44\n"
+
+msgid " %{project_name}#%{issue_iid} &middot; opened %{issue_created} by %{author}"
+msgstr ""
msgid " %{start} to %{end}"
msgstr ""
@@ -74,6 +77,16 @@ msgstr ""
msgid "\"el\" parameter is required for createInstance()"
msgstr ""
+msgid "%d Approval"
+msgid_plural "%d Approvals"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d Package"
+msgid_plural "%d Packages"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d Scanned URL"
msgid_plural "%d Scanned URLs"
msgstr[0] ""
@@ -137,6 +150,11 @@ msgstr[1] ""
msgid "%d commits"
msgstr ""
+msgid "%d completed issue"
+msgid_plural "%d completed issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d contribution"
msgid_plural "%d contributions"
msgstr[0] ""
@@ -147,6 +165,11 @@ msgid_plural "%d days"
msgstr[0] ""
msgstr[1] ""
+msgid "%d day until tags are automatically removed"
+msgid_plural "%d days until tags are automatically removed"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d error"
msgid_plural "%d errors"
msgstr[0] ""
@@ -237,6 +260,16 @@ msgid_plural "%d more comments"
msgstr[0] ""
msgstr[1] ""
+msgid "%d open issue"
+msgid_plural "%d open issues"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d pending comment"
+msgid_plural "%d pending comments"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d personal project will be removed and cannot be restored."
msgid_plural "%d personal projects will be removed and cannot be restored."
msgstr[0] ""
@@ -252,6 +285,11 @@ msgid_plural "%d projects"
msgstr[0] ""
msgstr[1] ""
+msgid "%d project selected"
+msgid_plural "%d projects selected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d request with warnings"
msgid_plural "%d requests with warnings"
msgstr[0] ""
@@ -272,6 +310,11 @@ msgid_plural "%d tags"
msgstr[0] ""
msgstr[1] ""
+msgid "%d tag per image name"
+msgid_plural "%d tags per image name"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d unassigned issue"
msgid_plural "%d unassigned issues"
msgstr[0] ""
@@ -292,6 +335,11 @@ msgid_plural "%d vulnerabilities dismissed"
msgstr[0] ""
msgstr[1] ""
+msgid "%d warning found:"
+msgid_plural "%d warnings found:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%s additional commit has been omitted to prevent performance issues."
msgid_plural "%s additional commits have been omitted to prevent performance issues."
msgstr[0] ""
@@ -330,6 +378,9 @@ msgstr ""
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr ""
+msgid "%{completedCount} completed weight"
+msgstr ""
+
msgid "%{completedWeight} of %{totalWeight} weight completed"
msgstr ""
@@ -378,14 +429,12 @@ msgid_plural "%{count} participants"
msgstr[0] ""
msgstr[1] ""
-msgid "%{count} pending comment"
-msgid_plural "%{count} pending comments"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
+msgid "%{count} total weight"
+msgstr ""
+
msgid "%{dashboard_path} could not be found."
msgstr ""
@@ -440,6 +489,9 @@ msgstr ""
msgid "%{group_name} uses group managed accounts. You need to create a new GitLab account which will be managed by %{group_name}."
msgstr ""
+msgid "%{group_name}&%{epic_iid} &middot; opened %{epic_created} by %{author}"
+msgstr ""
+
msgid "%{host} sign-in from new location"
msgstr ""
@@ -452,7 +504,7 @@ msgstr ""
msgid "%{issuableType} will be removed! Are you sure?"
msgstr ""
-msgid "%{issuesSize} issues with a limit of %{maxIssueCount}"
+msgid "%{issuesCount} issues with a limit of %{maxIssueCount}"
msgstr ""
msgid "%{issuesSize} with a limit of %{maxIssueCount}"
@@ -485,7 +537,7 @@ msgstr ""
msgid "%{labelStart}Namespace:%{labelEnd} %{namespace}"
msgstr ""
-msgid "%{labelStart}Report Type:%{labelEnd} %{reportType}"
+msgid "%{labelStart}Scan Type:%{labelEnd} %{reportType}"
msgstr ""
msgid "%{labelStart}Scanner:%{labelEnd} %{scanner}"
@@ -682,9 +734,6 @@ msgid_plural "%{securityScanner} results are not available because a pipeline ha
msgstr[0] ""
msgstr[1] ""
-msgid "%{service_title} %{message}."
-msgstr ""
-
msgid "%{size} GiB"
msgstr ""
@@ -773,6 +822,12 @@ msgstr ""
msgid "%{timebox_name} should belong either to a project or a group."
msgstr ""
+msgid "%{timebox_type} does not support burnup charts"
+msgstr ""
+
+msgid "%{timebox_type} must have a start and due date"
+msgstr ""
+
msgid "%{title} %{operator} %{threshold}"
msgstr ""
@@ -797,7 +852,7 @@ msgstr ""
msgid "%{total} open issue weight"
msgstr ""
-msgid "%{total} open issues"
+msgid "%{total} warnings found: showing first %{warningsDisplayed}"
msgstr ""
msgid "%{usage_ping_link_start}Learn more%{usage_ping_link_end} about what information is shared with GitLab Inc."
@@ -830,9 +885,6 @@ msgstr ""
msgid "&lt; 1 hour"
msgstr ""
-msgid "&lt;no name set&gt;"
-msgstr ""
-
msgid "&lt;no scopes selected&gt;"
msgstr ""
@@ -863,6 +915,9 @@ msgstr ""
msgid "'%{name}' Value Stream created"
msgstr ""
+msgid "'%{name}' Value Stream deleted"
+msgstr ""
+
msgid "'%{name}' stage already exists"
msgstr ""
@@ -922,6 +977,9 @@ msgstr ""
msgid "+ %{numberOfHiddenAssignees} more"
msgstr ""
+msgid "+ %{numberOfHiddenReviewers} more"
+msgstr ""
+
msgid "+%d more"
msgid_plural "+%d more"
msgstr[0] ""
@@ -982,6 +1040,11 @@ msgid_plural "%d Days"
msgstr[0] ""
msgstr[1] ""
+msgid "1 Issue"
+msgid_plural "%d Issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "1 closed issue"
msgid_plural "%{issues} closed issues"
msgstr[0] ""
@@ -997,6 +1060,11 @@ msgid_plural "%d days"
msgstr[0] ""
msgstr[1] ""
+msgid "1 deploy key"
+msgid_plural "%d deploy keys"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1099,6 +1167,9 @@ msgstr ""
msgid ":%{startLine} to %{endLine}"
msgstr ""
+msgid "A %{incident_docs_start}modified issue%{incident_docs_end} to guide the resolution of incidents."
+msgstr ""
+
msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr ""
@@ -1111,6 +1182,9 @@ msgstr ""
msgid "A GitBook site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
+msgid "A Gitpod configured Webapplication in Spring and Java"
+msgstr ""
+
msgid "A Hexo site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
@@ -1282,9 +1356,15 @@ msgstr ""
msgid "Access expiration date"
msgstr ""
+msgid "Access expires"
+msgstr ""
+
msgid "Access forbidden. Check your access level."
msgstr ""
+msgid "Access granted"
+msgstr ""
+
msgid "Access requests"
msgstr ""
@@ -1294,6 +1374,9 @@ msgstr ""
msgid "Access to Pages websites are controlled based on the user's membership to a given project. By checking this box, users will be required to be logged in to have access to all Pages websites in your instance."
msgstr ""
+msgid "AccessDropdown|Deploy Keys"
+msgstr ""
+
msgid "AccessDropdown|Groups"
msgstr ""
@@ -1411,12 +1494,6 @@ msgstr ""
msgid "Active Sessions"
msgstr ""
-msgid "Active Users:"
-msgstr ""
-
-msgid "Active users"
-msgstr ""
-
msgid "Activity"
msgstr ""
@@ -1584,9 +1661,6 @@ msgstr ""
msgid "Add label(s)"
msgstr ""
-msgid "Add license"
-msgstr ""
-
msgid "Add list"
msgstr ""
@@ -1761,21 +1835,51 @@ msgstr ""
msgid "AdminArea|Bots"
msgstr ""
+msgid "AdminArea|Components"
+msgstr ""
+
msgid "AdminArea|Developer"
msgstr ""
+msgid "AdminArea|Features"
+msgstr ""
+
+msgid "AdminArea|Groups: %{number_of_groups}"
+msgstr ""
+
msgid "AdminArea|Guest"
msgstr ""
msgid "AdminArea|Included Free in license"
msgstr ""
+msgid "AdminArea|Latest groups"
+msgstr ""
+
+msgid "AdminArea|Latest projects"
+msgstr ""
+
+msgid "AdminArea|Latest users"
+msgstr ""
+
msgid "AdminArea|Maintainer"
msgstr ""
+msgid "AdminArea|New group"
+msgstr ""
+
+msgid "AdminArea|New project"
+msgstr ""
+
+msgid "AdminArea|New user"
+msgstr ""
+
msgid "AdminArea|Owner"
msgstr ""
+msgid "AdminArea|Projects: %{number_of_projects}"
+msgstr ""
+
msgid "AdminArea|Reporter"
msgstr ""
@@ -1803,6 +1907,9 @@ msgstr ""
msgid "AdminArea|Users without a Group and Project"
msgstr ""
+msgid "AdminArea|Users: %{number_of_users}"
+msgstr ""
+
msgid "AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running."
msgstr ""
@@ -1821,9 +1928,6 @@ msgstr ""
msgid "AdminProjects|Delete Project %{projectName}?"
msgstr ""
-msgid "AdminProjects|Delete project"
-msgstr ""
-
msgid "AdminSettings|Apply integration settings to all Projects"
msgstr ""
@@ -2061,21 +2165,30 @@ msgstr ""
msgid "AdminUsers|Without projects"
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 ""
msgid "AdminUsers|You cannot remove your own admin rights."
msgstr ""
+msgid "AdminUsers|You must transfer ownership or delete the groups owned by this user before you can delete their account"
+msgstr ""
+
msgid "Administration"
msgstr ""
msgid "Advanced"
msgstr ""
+msgid "Advanced Search"
+msgstr ""
+
+msgid "Advanced Search with Elasticsearch"
+msgstr ""
+
msgid "Advanced Settings"
msgstr ""
@@ -2153,6 +2266,9 @@ msgstr ""
msgid "AlertManagement|Edit"
msgstr ""
+msgid "AlertManagement|Environment"
+msgstr ""
+
msgid "AlertManagement|Events"
msgstr ""
@@ -2165,6 +2281,9 @@ msgstr ""
msgid "AlertManagement|Issue"
msgstr ""
+msgid "AlertManagement|Key"
+msgstr ""
+
msgid "AlertManagement|Low"
msgstr ""
@@ -2258,6 +2377,9 @@ msgstr ""
msgid "AlertManagement|Unknown"
msgstr ""
+msgid "AlertManagement|Value"
+msgstr ""
+
msgid "AlertManagement|View alerts in Opsgenie"
msgstr ""
@@ -2417,6 +2539,9 @@ msgstr ""
msgid "All projects"
msgstr ""
+msgid "All projects selected"
+msgstr ""
+
msgid "All security scans are enabled because %{linkStart}Auto DevOps%{linkEnd} is enabled on this project"
msgstr ""
@@ -2504,6 +2629,9 @@ msgstr ""
msgid "Almost there"
msgstr ""
+msgid "Already blocked"
+msgstr ""
+
msgid "Also called \"Issuer\" or \"Relying party trust identifier\""
msgstr ""
@@ -2558,6 +2686,9 @@ msgstr ""
msgid "An error has occurred"
msgstr ""
+msgid "An error occured while making the changes: %{error}"
+msgstr ""
+
msgid "An error occurred adding a draft to the thread."
msgstr ""
@@ -2585,12 +2716,6 @@ msgstr ""
msgid "An error occurred when toggling the notification subscription"
msgstr ""
-msgid "An error occurred when trying to resolve a comment. Please try again."
-msgstr ""
-
-msgid "An error occurred when trying to resolve a discussion. Please try again."
-msgstr ""
-
msgid "An error occurred when updating the issue weight"
msgstr ""
@@ -2606,12 +2731,6 @@ msgstr ""
msgid "An error occurred while checking group path. Please refresh and try again."
msgstr ""
-msgid "An error occurred while committing your changes."
-msgstr ""
-
-msgid "An error occurred while creating the list. Please try again."
-msgstr ""
-
msgid "An error occurred while decoding the file."
msgstr ""
@@ -2684,25 +2803,19 @@ msgstr ""
msgid "An error occurred while fetching the Service Desk address."
msgstr ""
-msgid "An error occurred while fetching the board issues. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the board lists. Please reload the page."
msgstr ""
msgid "An error occurred while fetching the board lists. Please try again."
msgstr ""
-msgid "An error occurred while fetching the board swimlanes. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the builds."
msgstr ""
msgid "An error occurred while fetching the job log."
msgstr ""
-msgid "An error occurred while fetching the job trace."
+msgid "An error occurred while fetching the job logs."
msgstr ""
msgid "An error occurred while fetching the job."
@@ -2849,9 +2962,6 @@ msgstr ""
msgid "An error occurred while saving assignees"
msgstr ""
-msgid "An error occurred while saving the template. Please check if the template exists."
-msgstr ""
-
msgid "An error occurred while searching for milestones"
msgstr ""
@@ -2870,10 +2980,10 @@ msgstr ""
msgid "An error occurred while updating approvers"
msgstr ""
-msgid "An error occurred while updating the comment"
+msgid "An error occurred while updating labels."
msgstr ""
-msgid "An error occurred while updating the list. Please try again."
+msgid "An error occurred while updating the comment"
msgstr ""
msgid "An error occurred while validating group path"
@@ -2927,6 +3037,9 @@ msgstr ""
msgid "An unknown error occurred while loading this graph."
msgstr ""
+msgid "An unknown error occurred."
+msgstr ""
+
msgid "Analytics"
msgstr ""
@@ -2960,10 +3073,10 @@ msgstr ""
msgid "Any"
msgstr ""
-msgid "Any Author"
+msgid "Any %{header}"
msgstr ""
-msgid "Any Status"
+msgid "Any Author"
msgstr ""
msgid "Any branch"
@@ -3017,6 +3130,9 @@ msgstr ""
msgid "Application ID"
msgstr ""
+msgid "Application limits saved successfully"
+msgstr ""
+
msgid "Application settings saved successfully"
msgstr ""
@@ -3226,6 +3342,9 @@ msgstr ""
msgid "Are you sure you want to close this blocked issue?"
msgstr ""
+msgid "Are you sure you want to delete \"%{name}\" Value Stream?"
+msgstr ""
+
msgid "Are you sure you want to delete %{name}?"
msgstr ""
@@ -3235,6 +3354,9 @@ msgstr ""
msgid "Are you sure you want to delete this %{typeOfComment}?"
msgstr ""
+msgid "Are you sure you want to delete this SSH key?"
+msgstr ""
+
msgid "Are you sure you want to delete this board?"
msgstr ""
@@ -3259,6 +3381,11 @@ msgstr ""
msgid "Are you sure you want to erase this build?"
msgstr ""
+msgid "Are you sure you want to import %d repository?"
+msgid_plural "Are you sure you want to import %d repositories?"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Are you sure you want to lose unsaved changes?"
msgstr ""
@@ -3268,15 +3395,15 @@ msgstr ""
msgid "Are you sure you want to merge immediately?"
msgstr ""
-msgid "Are you sure you want to permanently delete this license?"
-msgstr ""
-
msgid "Are you sure you want to re-deploy this environment?"
msgstr ""
msgid "Are you sure you want to regenerate the public key? You will have to update the public key on the remote server before mirroring will work again."
msgstr ""
+msgid "Are you sure you want to reindex?"
+msgstr ""
+
msgid "Are you sure you want to remove %{group_name}?"
msgstr ""
@@ -3304,6 +3431,9 @@ msgstr ""
msgid "Are you sure you want to revoke this nickname?"
msgstr ""
+msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
+msgstr ""
+
msgid "Are you sure you want to stop this environment?"
msgstr ""
@@ -3325,6 +3455,9 @@ msgstr ""
msgid "Are you sure? The device will be signed out of GitLab and all remember me tokens revoked."
msgstr ""
+msgid "Are you sure? This will invalidate your registered applications and U2F / WebAuthn devices."
+msgstr ""
+
msgid "Are you sure? This will invalidate your registered applications and U2F devices."
msgstr ""
@@ -3343,9 +3476,6 @@ msgstr ""
msgid "Artifacts"
msgstr ""
-msgid "As U2F devices are only supported by a few browsers, we require that you set up a two-factor authentication app before a U2F device. That way you'll always be able to log in - even when you're using an unsupported browser."
-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 ""
@@ -3539,6 +3669,9 @@ msgstr ""
msgid "AuditLogs|Target"
msgstr ""
+msgid "AuditLogs|This month"
+msgstr ""
+
msgid "AuditLogs|User Events"
msgstr ""
@@ -3578,6 +3711,9 @@ msgstr ""
msgid "Authentication via U2F device failed."
msgstr ""
+msgid "Authentication via WebAuthn device failed."
+msgstr ""
+
msgid "Author"
msgstr ""
@@ -3845,15 +3981,6 @@ msgstr ""
msgid "BambooService|You must set up automatic revision labeling and a repository trigger in Bamboo."
msgstr ""
-msgid "BatchComments|Delete all pending comments"
-msgstr ""
-
-msgid "BatchComments|Discard review?"
-msgstr ""
-
-msgid "BatchComments|You're about to discard your review which will delete all of your pending comments. The deleted comments %{strong_start}cannot%{strong_end} be restored."
-msgstr ""
-
msgid "Be careful. Changing the project's namespace can have unintended side effects."
msgstr ""
@@ -3875,6 +4002,9 @@ msgstr ""
msgid "Bi-weekly code coverage"
msgstr ""
+msgid "Billable Users:"
+msgstr ""
+
msgid "Billing"
msgstr ""
@@ -3884,7 +4014,7 @@ msgstr ""
msgid "BillingPlans|@%{user_name} you are currently using the %{plan_name} plan."
msgstr ""
-msgid "BillingPlans|Congratulations, your new trial is activated"
+msgid "BillingPlans|Congratulations, your free trial is activated."
msgstr ""
msgid "BillingPlans|If you would like to downgrade your plan please contact %{support_link_start}Customer Support%{support_link_end}."
@@ -3947,6 +4077,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Block user"
+msgstr ""
+
msgid "Blocked"
msgstr ""
@@ -3962,31 +4095,37 @@ msgstr ""
msgid "Blog"
msgstr ""
-msgid "Board name"
-msgstr ""
-
msgid "Board scope"
msgstr ""
msgid "Board scope affects which issues are displayed for anyone who visits this board"
msgstr ""
-msgid "BoardBlankState|Add default lists"
+msgid "Boards"
msgstr ""
-msgid "BoardBlankState|Add the following default lists to your Issue Board with one click:"
+msgid "Boards and Board Lists"
msgstr ""
-msgid "BoardBlankState|Nevermind, I'll use my own"
+msgid "Boards|An error occurred while creating the issue. Please try again."
msgstr ""
-msgid "BoardBlankState|Starting out with the default set of lists will get you right on the way to making the most of your board."
+msgid "Boards|An error occurred while creating the list. Please try again."
msgstr ""
-msgid "Boards"
+msgid "Boards|An error occurred while fetching issues. Please reload the page."
msgstr ""
-msgid "Boards and Board Lists"
+msgid "Boards|An error occurred while fetching the board issues. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching the board swimlanes. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while moving the issue. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while updating the list. Please try again."
msgstr ""
msgid "Boards|Collapse"
@@ -4013,7 +4152,7 @@ msgstr ""
msgid "Branch %{branch_name} was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr ""
-msgid "Branch has changed"
+msgid "Branch changed"
msgstr ""
msgid "Branch is already taken"
@@ -4319,6 +4458,9 @@ msgstr ""
msgid "CLOSED (MOVED)"
msgstr ""
+msgid "CODEOWNERS rule violation"
+msgstr ""
+
msgid "CONTRIBUTING"
msgstr ""
@@ -4349,9 +4491,6 @@ msgstr ""
msgid "Can't create snippet: %{err}"
msgstr ""
-msgid "Can't edit as source branch was deleted"
-msgstr ""
-
msgid "Can't fetch content for the blob: %{err}"
msgstr ""
@@ -4364,9 +4503,6 @@ msgstr ""
msgid "Can't load mermaid module: %{err}"
msgstr ""
-msgid "Can't remove group members without group managed account"
-msgstr ""
-
msgid "Can't scan the code?"
msgstr ""
@@ -4409,6 +4545,9 @@ msgstr ""
msgid "Cannot create the abuse report. This user has been blocked."
msgstr ""
+msgid "Cannot enable shared runners because parent group does not allow it"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -4514,6 +4653,15 @@ msgstr ""
msgid "Change your password or recover your current one"
msgstr ""
+msgid "ChangeReviewer|Reviewer changed from %{old} to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Reviewer changed to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Unassigned"
+msgstr ""
+
msgid "ChangeTypeActionLabel|Pick into branch"
msgstr ""
@@ -4553,6 +4701,9 @@ msgstr ""
msgid "Changes the title to \"%{title_param}\"."
msgstr ""
+msgid "Changes were successfully made."
+msgstr ""
+
msgid "Changes won't take place until the index is %{link_start}recreated%{link_end}."
msgstr ""
@@ -4958,6 +5109,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove variable"
+msgstr ""
+
msgid "CiVariables|Remove variable row"
msgstr ""
@@ -5036,9 +5190,6 @@ msgstr ""
msgid "Clear due date"
msgstr ""
-msgid "Clear input"
-msgstr ""
-
msgid "Clear recent searches"
msgstr ""
@@ -5087,6 +5238,9 @@ msgstr ""
msgid "Client authentication key password"
msgstr ""
+msgid "Client request timeout"
+msgstr ""
+
msgid "Clients"
msgstr ""
@@ -5171,6 +5325,27 @@ msgstr ""
msgid "Cluster type must be specificed for Stages::ClusterEndpointInserter"
msgstr ""
+msgid "ClusterAgents|Configuration"
+msgstr ""
+
+msgid "ClusterAgents|Connect your cluster with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate Kubernetes with a GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Name"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Agent also requires %{linkStart}enabling the Agent Server%{linkEnd}"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Kubernetes Agent allows an Infrastructure as Code, GitOps approach to integrating Kubernetes clusters with GitLab. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "ClusterAgent|This feature is only available for premium plans"
msgstr ""
@@ -5240,10 +5415,10 @@ msgstr ""
msgid "ClusterIntegration|All installed applications and related resources"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster."
+msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{linkStart}More information%{linkEnd}"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{startLink}More information%{endLink}"
+msgid "ClusterIntegration|Allow GitLab to manage namespaces and service accounts for this cluster."
msgstr ""
msgid "ClusterIntegration|Alternatively, "
@@ -5264,6 +5439,9 @@ msgstr ""
msgid "ClusterIntegration|An error occurred while trying to fetch zone machine types: %{error}"
msgstr ""
+msgid "ClusterIntegration|An unknown error occurred while attempting to connect to Kubernetes."
+msgstr ""
+
msgid "ClusterIntegration|Any project namespaces"
msgstr ""
@@ -5279,6 +5457,9 @@ msgstr ""
msgid "ClusterIntegration|Authenticate with Amazon Web Services"
msgstr ""
+msgid "ClusterIntegration|Authentication Error"
+msgstr ""
+
msgid "ClusterIntegration|Base domain"
msgstr ""
@@ -5297,13 +5478,22 @@ msgstr ""
msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}security group %{externalLinkIcon} %{endLink} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
+msgid "ClusterIntegration|Check your CA certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Check your cluster status"
+msgstr ""
+
+msgid "ClusterIntegration|Check your token"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}subnets %{externalLinkIcon} %{endLink} in your VPC where your worker nodes will run."
+msgid "ClusterIntegration|Choose the %{linkStart}security group %{linkEnd} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
msgstr ""
-msgid "ClusterIntegration|Choose the worker node %{startLink}instance type %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Choose the %{linkStart}subnets %{linkEnd} in your VPC where your worker nodes will run."
+msgstr ""
+
+msgid "ClusterIntegration|Choose the worker node %{linkStart}instance type%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Choose which applications to install on your Kubernetes cluster."
@@ -5315,10 +5505,7 @@ msgstr ""
msgid "ClusterIntegration|Clear cluster cache"
msgstr ""
-msgid "ClusterIntegration|Clear the local cache of namespace and service accounts. This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
-msgstr ""
-
-msgid "ClusterIntegration|Cluster being created"
+msgid "ClusterIntegration|Clear the local cache of namespace and service accounts."
msgstr ""
msgid "ClusterIntegration|Cluster management project (alpha)"
@@ -5330,15 +5517,21 @@ msgstr ""
msgid "ClusterIntegration|Cluster_applications artifact too big. Maximum allowable size: %{human_size}"
msgstr ""
-msgid "ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters."
+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|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}"
+msgid "ClusterIntegration|Clusters connected with a certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Connect cluster with certificate"
msgstr ""
msgid "ClusterIntegration|Connect existing cluster"
msgstr ""
+msgid "ClusterIntegration|Connection Error"
+msgstr ""
+
msgid "ClusterIntegration|Copy API URL"
msgstr ""
@@ -5414,6 +5607,12 @@ msgstr ""
msgid "ClusterIntegration|Deletes all GitLab resources attached to this cluster during removal"
msgstr ""
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared."
+msgstr ""
+
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared. %{linkStart}More information%{linkEnd}"
+msgstr ""
+
msgid "ClusterIntegration|Did you know?"
msgstr ""
@@ -5483,6 +5682,9 @@ msgstr ""
msgid "ClusterIntegration|Fluentd is an open source data collector, which lets you unify the data collection and consumption for a better use and understanding of data. It requires at least one of the following logs to be successfully installed."
msgstr ""
+msgid "ClusterIntegration|GitLab Agent managed clusters"
+msgstr ""
+
msgid "ClusterIntegration|GitLab Container Network Policies"
msgstr ""
@@ -5495,6 +5697,12 @@ msgstr ""
msgid "ClusterIntegration|GitLab Runner connects to the repository and executes CI/CD jobs, pushing results back and deploying applications to production."
msgstr ""
+msgid "ClusterIntegration|GitLab failed to authenticate."
+msgstr ""
+
+msgid "ClusterIntegration|GitLab failed to connect to the cluster."
+msgstr ""
+
msgid "ClusterIntegration|GitLab-managed cluster"
msgstr ""
@@ -5516,6 +5724,9 @@ msgstr ""
msgid "ClusterIntegration|Group cluster"
msgstr ""
+msgid "ClusterIntegration|HTTP Error"
+msgstr ""
+
msgid "ClusterIntegration|Helm Tiller"
msgstr ""
@@ -5549,7 +5760,10 @@ msgstr ""
msgid "ClusterIntegration|Instance type"
msgstr ""
-msgid "ClusterIntegration|Integrate Kubernetes cluster automation"
+msgid "ClusterIntegration|Integrate Kubernetes with a cluster certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Integrate with a cluster certificate"
msgstr ""
msgid "ClusterIntegration|Issuer Email"
@@ -5585,9 +5799,6 @@ msgstr ""
msgid "ClusterIntegration|Knative extends Kubernetes to provide a set of middleware components that are essential to build modern, source-centric, and container-based applications that can run anywhere: on premises, in the cloud, or even in a third-party data center."
msgstr ""
-msgid "ClusterIntegration|Kubernetes cluster"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes cluster is being created..."
msgstr ""
@@ -5600,9 +5811,6 @@ msgstr ""
msgid "ClusterIntegration|Kubernetes clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr ""
-msgid "ClusterIntegration|Kubernetes clusters can be used to deploy applications and to provide Review Apps for this project"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes version"
msgstr ""
@@ -5615,7 +5823,7 @@ msgstr ""
msgid "ClusterIntegration|Learn more about %{help_link_start}zones%{help_link_end}."
msgstr ""
-msgid "ClusterIntegration|Learn more about %{startLink}Regions %{externalLinkIcon}%{endLink}."
+msgid "ClusterIntegration|Learn more about %{linkStart}Regions%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Learn more about Kubernetes"
@@ -5660,12 +5868,18 @@ msgstr ""
msgid "ClusterIntegration|Machine type"
msgstr ""
+msgid "ClusterIntegration|Make sure your API endpoint is correct"
+msgstr ""
+
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create Kubernetes clusters"
msgstr ""
msgid "ClusterIntegration|Manage your Kubernetes cluster by visiting %{provider_link}"
msgstr ""
+msgid "ClusterIntegration|Namespace per environment"
+msgstr ""
+
msgid "ClusterIntegration|No IAM Roles found"
msgstr ""
@@ -5711,6 +5925,9 @@ msgstr ""
msgid "ClusterIntegration|No zones matched your search"
msgstr ""
+msgid "ClusterIntegration|Node calculations use the Kubernetes Metrics API. Make sure your cluster has metrics installed"
+msgstr ""
+
msgid "ClusterIntegration|Number of nodes"
msgstr ""
@@ -5753,6 +5970,9 @@ msgstr ""
msgid "ClusterIntegration|RBAC-enabled cluster"
msgstr ""
+msgid "ClusterIntegration|Read our %{linkStart}help page%{linkEnd} on Kubernetes cluster integration."
+msgstr ""
+
msgid "ClusterIntegration|Read our %{link_start}help page%{link_end} on Kubernetes cluster integration."
msgstr ""
@@ -5855,7 +6075,7 @@ msgstr ""
msgid "ClusterIntegration|Select a VPC to choose a subnet"
msgstr ""
-msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{linkStart}Amazon Web Services %{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select a network to choose a subnetwork"
@@ -5888,7 +6108,7 @@ msgstr ""
msgid "ClusterIntegration|Select project to choose zone"
msgstr ""
-msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select zone"
@@ -5978,9 +6198,18 @@ msgstr ""
msgid "ClusterIntegration|There was a problem authenticating with your cluster. Please ensure your CA Certificate and Token are valid."
msgstr ""
+msgid "ClusterIntegration|There was an HTTP error when connecting to your cluster."
+msgstr ""
+
msgid "ClusterIntegration|This account must have permissions to create a Kubernetes cluster in the %{link_to_container_project} specified below"
msgstr ""
+msgid "ClusterIntegration|This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
+msgstr ""
+
+msgid "ClusterIntegration|This is necessary to clear existing environment-namespace associations from clusters previously managed by GitLab."
+msgstr ""
+
msgid "ClusterIntegration|This option will allow you to install applications on RBAC clusters."
msgstr ""
@@ -6005,9 +6234,21 @@ msgstr ""
msgid "ClusterIntegration|To use a new project, first create one on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}."
msgstr ""
+msgid "ClusterIntegration|Troubleshooting tips:"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Authenticate"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Connect"
+msgstr ""
+
msgid "ClusterIntegration|Uninstall %{appTitle}"
msgstr ""
+msgid "ClusterIntegration|Unknown Error"
+msgstr ""
+
msgid "ClusterIntegration|Update %{appTitle}"
msgstr ""
@@ -6068,7 +6309,7 @@ msgstr ""
msgid "ClusterIntegration|Your cluster API is unreachable. Please ensure your API URL is correct."
msgstr ""
-msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Zone"
@@ -6188,6 +6429,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse all threads"
+msgstr ""
+
msgid "Collapse approvers"
msgstr ""
@@ -6337,7 +6581,7 @@ msgstr ""
msgid "Commit…"
msgstr ""
-msgid "Company"
+msgid "Community forum"
msgstr ""
msgid "Company name"
@@ -6346,6 +6590,9 @@ msgstr ""
msgid "Compare"
msgstr ""
+msgid "Compare %{oldCommitId}...%{newCommitId}"
+msgstr ""
+
msgid "Compare Git revisions"
msgstr ""
@@ -6361,6 +6608,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare submodule commit revisions"
+msgstr ""
+
msgid "Compare with previous version"
msgstr ""
@@ -6496,6 +6746,9 @@ msgstr ""
msgid "Configure the way a user creates a new account."
msgstr ""
+msgid "Configure which lists are shown for anyone who visits this board"
+msgstr ""
+
msgid "Confirm"
msgstr ""
@@ -6721,6 +6974,9 @@ msgstr[1] ""
msgid "ContainerRegistry|Set cleanup policy"
msgstr ""
+msgid "ContainerRegistry|Some tags were not deleted"
+msgstr ""
+
msgid "ContainerRegistry|Something went wrong while fetching the cleanup policy."
msgstr ""
@@ -6760,6 +7016,9 @@ msgstr ""
msgid "ContainerRegistry|Tags with names matching this regex pattern will %{italicStart}expire:%{italicEnd}"
msgstr ""
+msgid "ContainerRegistry|The cleanup policy timed out before it could delete all tags. An administrator can %{adminLinkStart}manually run cleanup now%{adminLinkEnd} or you can wait for the cleanup policy to automatically run again. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "ContainerRegistry|The last tag related to this image was recently removed. This empty image and any associated data will be automatically removed as part of the regular Garbage Collection process. If you have any questions, contact your administrator."
msgstr ""
@@ -6892,6 +7151,9 @@ msgstr ""
msgid "Contributions per group member"
msgstr ""
+msgid "Contributor"
+msgstr ""
+
msgid "Contributors"
msgstr ""
@@ -7021,6 +7283,9 @@ msgstr ""
msgid "Could not change HEAD: branch '%{branch}' does not exist"
msgstr ""
+msgid "Could not commit. An unexpected error occurred."
+msgstr ""
+
msgid "Could not connect to FogBugz, check your URL"
msgstr ""
@@ -7060,6 +7325,9 @@ msgstr ""
msgid "Could not find iteration"
msgstr ""
+msgid "Could not load instance counts. Please refresh the page to try again."
+msgstr ""
+
msgid "Could not remove the trigger."
msgstr ""
@@ -7084,10 +7352,10 @@ msgstr ""
msgid "Could not save prometheus manual configuration"
msgstr ""
-msgid "Could not udpdate wiki page"
+msgid "Could not update the LDAP settings"
msgstr ""
-msgid "Could not update the LDAP settings"
+msgid "Could not update wiki page"
msgstr ""
msgid "Could not upload your designs as one or more files uploaded are not supported."
@@ -7745,6 +8013,9 @@ msgstr ""
msgid "DastProfiles|Are you sure you want to delete this profile?"
msgstr ""
+msgid "DastProfiles|Could not create site validation token. Please refresh the page, or try again later."
+msgstr ""
+
msgid "DastProfiles|Could not create the scanner profile. Please try again."
msgstr ""
@@ -7769,6 +8040,12 @@ msgstr ""
msgid "DastProfiles|Could not fetch site profiles. Please refresh the page, or try again later."
msgstr ""
+msgid "DastProfiles|Could not retrieve site validation status. Please refresh the page, or try again later."
+msgstr ""
+
+msgid "DastProfiles|Could not update the scanner profile. Please try again."
+msgstr ""
+
msgid "DastProfiles|Could not update the site profile. Please try again."
msgstr ""
@@ -7784,7 +8061,7 @@ msgstr ""
msgid "DastProfiles|Download validation text file"
msgstr ""
-msgid "DastProfiles|Edit feature will come soon. Please create a new profile if changes needed"
+msgid "DastProfiles|Edit scanner profile"
msgstr ""
msgid "DastProfiles|Edit site profile"
@@ -7817,6 +8094,9 @@ msgstr ""
msgid "DastProfiles|No profiles created yet"
msgstr ""
+msgid "DastProfiles|Passive"
+msgstr ""
+
msgid "DastProfiles|Please enter a valid URL format, ex: http://www.example.com/home"
msgstr ""
@@ -7832,6 +8112,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan mode"
+msgstr ""
+
msgid "DastProfiles|Scanner Profile"
msgstr ""
@@ -7871,10 +8154,10 @@ msgstr ""
msgid "DastProfiles|Text file validation"
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
+msgid "DastProfiles|The maximum number of minutes allowed for the spider to traverse the site."
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the spider to traverse the site."
+msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
msgstr ""
msgid "DastProfiles|Validate"
@@ -7907,6 +8190,9 @@ msgstr ""
msgid "Date picker"
msgstr ""
+msgid "Date range"
+msgstr ""
+
msgid "Date range cannot exceed %{maxDateRange} days."
msgstr ""
@@ -7931,6 +8217,9 @@ msgstr ""
msgid "Days to merge"
msgstr ""
+msgid "Dear Administrator,"
+msgstr ""
+
msgid "Debug"
msgstr ""
@@ -8042,12 +8331,18 @@ msgstr ""
msgid "Delete"
msgstr ""
+msgid "Delete %{name}"
+msgstr ""
+
msgid "Delete Comment"
msgstr ""
msgid "Delete Snippet"
msgstr ""
+msgid "Delete Value Stream"
+msgstr ""
+
msgid "Delete account"
msgstr ""
@@ -8069,9 +8364,6 @@ msgstr ""
msgid "Delete label: %{label_name} ?"
msgstr ""
-msgid "Delete license"
-msgstr ""
-
msgid "Delete list"
msgstr ""
@@ -8147,15 +8439,6 @@ msgstr ""
msgid "Deleting a project places it into a read-only state until %{date}, at which point the project will be permanently deleted. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "Deleting the license failed."
-msgstr ""
-
-msgid "Deleting the license failed. The license was not found."
-msgstr ""
-
-msgid "Deleting the license failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "Deleting the project will delete its repository and all related resources including issues, merge requests etc."
msgstr ""
@@ -8651,7 +8934,10 @@ msgstr ""
msgid "DesignManagement|The maximum number of designs allowed to be uploaded is %{upload_limit}. Please try again."
msgstr ""
-msgid "DesignManagement|To upload designs, you'll need to enable LFS. %{requirements_link_start}More information%{requirements_link_end}"
+msgid "DesignManagement|There was an error moving your designs. Please upload your designs below."
+msgstr ""
+
+msgid "DesignManagement|To upload designs, you'll need to enable LFS and have admin enable hashed storage. %{requirements_link_start}More information%{requirements_link_end}"
msgstr ""
msgid "DesignManagement|Unresolve thread"
@@ -8663,6 +8949,9 @@ msgstr ""
msgid "DesignManagement|Upload skipped."
msgstr ""
+msgid "DesignManagement|Your designs are being copied and are on their way… Please refresh to update."
+msgstr ""
+
msgid "DesignManagement|and %{moreCount} more."
msgstr ""
@@ -8720,6 +9009,9 @@ msgstr ""
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
+msgid "Direct member"
+msgstr ""
+
msgid "Direction"
msgstr ""
@@ -8768,9 +9060,6 @@ msgstr ""
msgid "Discard draft"
msgstr ""
-msgid "Discard review"
-msgstr ""
-
msgid "DiscordService|Discord Notifications"
msgstr ""
@@ -8839,10 +9128,10 @@ msgstr ""
msgid "Dismiss Merge Request promotion"
msgstr ""
-msgid "Dismiss Selected"
+msgid "Dismiss Value Stream Analytics introduction box"
msgstr ""
-msgid "Dismiss Value Stream Analytics introduction box"
+msgid "Dismiss selected"
msgstr ""
msgid "Dismiss trial promotion"
@@ -8893,9 +9182,6 @@ msgstr ""
msgid "Documents reindexed: %{processed_documents} (%{percentage}%%)"
msgstr ""
-msgid "Doing"
-msgstr ""
-
msgid "Domain"
msgstr ""
@@ -9091,9 +9377,6 @@ msgstr ""
msgid "Edit environment"
msgstr ""
-msgid "Edit file"
-msgstr ""
-
msgid "Edit files in the editor and commit changes here"
msgstr ""
@@ -9106,6 +9389,12 @@ msgstr ""
msgid "Edit identity for %{user_name}"
msgstr ""
+msgid "Edit in Web IDE"
+msgstr ""
+
+msgid "Edit in single-file editor"
+msgstr ""
+
msgid "Edit issues"
msgstr ""
@@ -9133,10 +9422,10 @@ msgstr ""
msgid "Editing"
msgstr ""
-msgid "Elasticsearch"
+msgid "Elasticsearch AWS IAM credentials"
msgstr ""
-msgid "Elasticsearch AWS IAM credentials"
+msgid "Elasticsearch HTTP client timeout value in seconds."
msgstr ""
msgid "Elasticsearch indexing restrictions"
@@ -9145,9 +9434,6 @@ msgstr ""
msgid "Elasticsearch indexing started"
msgstr ""
-msgid "Elasticsearch integration. Elasticsearch AWS IAM."
-msgstr ""
-
msgid "Elasticsearch reindexing is already in progress"
msgstr ""
@@ -9175,9 +9461,6 @@ msgstr ""
msgid "Email Notification"
msgstr ""
-msgid "Email address"
-msgstr ""
-
msgid "Email could not be sent"
msgstr ""
@@ -9241,6 +9524,9 @@ msgstr ""
msgid "Emails sent from Service Desk will have this name"
msgstr ""
+msgid "Emails sent to %{email} will still be supported"
+msgstr ""
+
msgid "Emails separated by comma"
msgstr ""
@@ -9274,9 +9560,18 @@ msgstr ""
msgid "Enable"
msgstr ""
+msgid "Enable %{link_start}Gitpod%{link_end} integration to launch a development environment in your browser directly from GitLab."
+msgstr ""
+
msgid "Enable Auto DevOps"
msgstr ""
+msgid "Enable Gitpod"
+msgstr ""
+
+msgid "Enable Gitpod?"
+msgstr ""
+
msgid "Enable HTML emails"
msgstr ""
@@ -9406,9 +9701,6 @@ msgstr ""
msgid "Encountered an error while rendering: %{err}"
msgstr ""
-msgid "End date"
-msgstr ""
-
msgid "Ends at (UTC)"
msgstr ""
@@ -9568,7 +9860,7 @@ msgstr ""
msgid "EnvironmentsDashboard|The environments dashboard provides a summary of each project's environments' status, including pipeline and alert statuses."
msgstr ""
-msgid "EnvironmentsDashboard|This dashboard displays a maximum of 7 projects and 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
+msgid "EnvironmentsDashboard|This dashboard displays 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
msgstr ""
msgid "Environments|An error occurred while canceling the auto stop, please try again"
@@ -9889,6 +10181,9 @@ msgstr ""
msgid "Error deleting project. Check logs for error details."
msgstr ""
+msgid "Error fetching burnup chart data"
+msgstr ""
+
msgid "Error fetching diverging counts for branches. Please try again."
msgstr ""
@@ -9967,6 +10262,9 @@ msgstr ""
msgid "Error occurred when saving assignees"
msgstr ""
+msgid "Error occurred when saving reviewers"
+msgstr ""
+
msgid "Error occurred when toggling the notification subscription"
msgstr ""
@@ -10219,10 +10517,13 @@ msgstr ""
msgid "Expand all"
msgstr ""
-msgid "Expand approvers"
+msgid "Expand all files"
msgstr ""
-msgid "Expand dropdown"
+msgid "Expand all threads"
+msgstr ""
+
+msgid "Expand approvers"
msgstr ""
msgid "Expand milestones"
@@ -10393,6 +10694,9 @@ msgstr ""
msgid "Failed to create Merge Request. Please try again."
msgstr ""
+msgid "Failed to create To-Do for the design."
+msgstr ""
+
msgid "Failed to create a branch for this issue. Please try again."
msgstr ""
@@ -10432,6 +10736,12 @@ msgstr ""
msgid "Failed to load authors. Please try again."
msgstr ""
+msgid "Failed to load branches. Please try again."
+msgstr ""
+
+msgid "Failed to load deploy keys."
+msgstr ""
+
msgid "Failed to load emoji list."
msgstr ""
@@ -10447,6 +10757,9 @@ msgstr ""
msgid "Failed to load groups & users."
msgstr ""
+msgid "Failed to load groups, users and deploy keys."
+msgstr ""
+
msgid "Failed to load labels. Please try again."
msgstr ""
@@ -10456,6 +10769,12 @@ msgstr ""
msgid "Failed to load related branches"
msgstr ""
+msgid "Failed to load sidebar confidential toggle"
+msgstr ""
+
+msgid "Failed to load sidebar lock status"
+msgstr ""
+
msgid "Failed to load stacktrace."
msgstr ""
@@ -10483,6 +10802,9 @@ msgstr ""
msgid "Failed to publish issue on status page."
msgstr ""
+msgid "Failed to remove To-Do for the design."
+msgstr ""
+
msgid "Failed to remove a Zoom meeting"
msgstr ""
@@ -10525,6 +10847,9 @@ msgstr ""
msgid "Failed to signing using smartcard authentication"
msgstr ""
+msgid "Failed to toggle To-Do for the design."
+msgstr ""
+
msgid "Failed to update branch!"
msgstr ""
@@ -10638,7 +10963,7 @@ msgstr ""
msgid "FeatureFlags|Edit User List"
msgstr ""
-msgid "FeatureFlags|Enable features for specific users and specific environments by defining feature flag strategies."
+msgid "FeatureFlags|Enable features for specific users and environments by configuring feature flag strategies."
msgstr ""
msgid "FeatureFlags|Environment Spec"
@@ -10698,7 +11023,7 @@ msgstr ""
msgid "FeatureFlags|Include additional user IDs"
msgstr ""
-msgid "FeatureFlags|Install a %{docs_link_anchored_start}compatible client library%{docs_link_anchored_end} and specify the API URL, application name, and instance ID during the configuration setup. %{docs_link_start}More Information%{docs_link_end}"
+msgid "FeatureFlags|Install a %{docsLinkAnchoredStart}compatible client library%{docsLinkAnchoredEnd} and specify the API URL, application name, and instance ID during the configuration setup. %{docsLinkStart}More Information%{docsLinkEnd}"
msgstr ""
msgid "FeatureFlags|Instance ID"
@@ -10710,6 +11035,9 @@ msgstr ""
msgid "FeatureFlags|Loading feature flags"
msgstr ""
+msgid "FeatureFlags|Loading user lists"
+msgstr ""
+
msgid "FeatureFlags|More information"
msgstr ""
@@ -10728,7 +11056,7 @@ msgstr ""
msgid "FeatureFlags|New feature flag"
msgstr ""
-msgid "FeatureFlags|New list"
+msgid "FeatureFlags|New user list"
msgstr ""
msgid "FeatureFlags|Percent of users"
@@ -10767,6 +11095,9 @@ msgstr ""
msgid "FeatureFlags|There was an error fetching the feature flags."
msgstr ""
+msgid "FeatureFlags|There was an error fetching the user lists."
+msgstr ""
+
msgid "FeatureFlags|There was an error retrieving user lists"
msgstr ""
@@ -10782,6 +11113,9 @@ msgstr ""
msgid "FeatureFlags|User List"
msgstr ""
+msgid "FeatureFlags|User Lists"
+msgstr ""
+
msgid "FeatureFlag|List"
msgstr ""
@@ -10809,15 +11143,6 @@ msgstr ""
msgid "Fetching incoming email"
msgstr ""
-msgid "Fetching licenses failed."
-msgstr ""
-
-msgid "Fetching licenses failed. The request endpoint was not found."
-msgstr ""
-
-msgid "Fetching licenses failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "File"
msgstr ""
@@ -10920,12 +11245,21 @@ msgstr ""
msgid "Filter by status"
msgstr ""
+msgid "Filter by test cases that are currently archived."
+msgstr ""
+
+msgid "Filter by test cases that are currently opened."
+msgstr ""
+
msgid "Filter by two-factor authentication"
msgstr ""
msgid "Filter by user"
msgstr ""
+msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
+msgstr ""
+
msgid "Filter pipelines"
msgstr ""
@@ -10941,7 +11275,7 @@ msgstr ""
msgid "Filter results..."
msgstr ""
-msgid "Filter your projects by name"
+msgid "Filter your repositories by name"
msgstr ""
msgid "Filter..."
@@ -10950,7 +11284,7 @@ msgstr ""
msgid "Find File"
msgstr ""
-msgid "Find bugs in your code with coverage-guided fuzzing"
+msgid "Find bugs in your code with coverage-guided fuzzing."
msgstr ""
msgid "Find by path"
@@ -10977,9 +11311,6 @@ msgstr ""
msgid "Finish editing this message first!"
msgstr ""
-msgid "Finish review"
-msgstr ""
-
msgid "Finish setting up your dedicated account for %{group_name}."
msgstr ""
@@ -11049,6 +11380,9 @@ msgstr ""
msgid "Footer message"
msgstr ""
+msgid "For a faster browsing experience, some files are collapsed by default."
+msgstr ""
+
msgid "For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
@@ -11058,6 +11392,9 @@ msgstr ""
msgid "For more info, read the documentation."
msgstr ""
+msgid "For more information on how the number of active users is calculated, see the %{self_managed_subscriptions_doc_link} documentation."
+msgstr ""
+
msgid "For more information, go to the "
msgstr ""
@@ -11196,6 +11533,9 @@ msgstr ""
msgid "Generate new token"
msgstr ""
+msgid "Generic package file size in bytes"
+msgstr ""
+
msgid "Geo"
msgstr ""
@@ -11457,6 +11797,9 @@ msgstr ""
msgid "Geo|Please refer to Geo Troubleshooting."
msgstr ""
+msgid "Geo|Primary node"
+msgstr ""
+
msgid "Geo|Project"
msgstr ""
@@ -11499,6 +11842,9 @@ msgstr ""
msgid "Geo|Review replication status, and resynchronize and reverify items with the primary node."
msgstr ""
+msgid "Geo|Secondary node"
+msgstr ""
+
msgid "Geo|Status"
msgstr ""
@@ -11538,6 +11884,9 @@ msgstr ""
msgid "Geo|URL must be a valid url (ex: https://gitlab.com)"
msgstr ""
+msgid "Geo|Undefined"
+msgstr ""
+
msgid "Geo|Unknown state"
msgstr ""
@@ -11613,10 +11962,16 @@ msgstr ""
msgid "GitHub import"
msgstr ""
+msgid "GitLab"
+msgstr ""
+
msgid "GitLab / Unsubscribe"
msgstr ""
-msgid "GitLab Enterprise Edition %{plan}"
+msgid "GitLab API"
+msgstr ""
+
+msgid "GitLab Billing Team."
msgstr ""
msgid "GitLab Group Runners can execute code for all the projects in this group."
@@ -11628,12 +11983,18 @@ msgstr ""
msgid "GitLab Issue"
msgstr ""
+msgid "GitLab Pages"
+msgstr ""
+
msgid "GitLab Service Desk is a simple way to allow people to create issues in your GitLab instance without needing their own user account. It provides a unique email address for end users to create issues in a project, and replies can be sent either through the GitLab interface or by email. End users will only see the thread through email."
msgstr ""
msgid "GitLab Shared Runners execute code of different projects on the same Runner unless you configure GitLab Runner Autoscale with MaxBuilds 1 (which it is on GitLab.com)."
msgstr ""
+msgid "GitLab Shell"
+msgstr ""
+
msgid "GitLab Support Bot"
msgstr ""
@@ -11643,7 +12004,7 @@ msgstr ""
msgid "GitLab User"
msgstr ""
-msgid "GitLab allows you to continue using your license even if you exceed the number of seats you purchased. You will be required to pay for these seats when you renew your license."
+msgid "GitLab Workhorse"
msgstr ""
msgid "GitLab commit"
@@ -11811,6 +12172,21 @@ msgstr ""
msgid "Gitlab Pages"
msgstr ""
+msgid "Gitpod"
+msgstr ""
+
+msgid "Gitpod|Add the URL to your Gitpod instance configured to read your GitLab projects."
+msgstr ""
+
+msgid "Gitpod|Enable Gitpod integration"
+msgstr ""
+
+msgid "Gitpod|Gitpod URL"
+msgstr ""
+
+msgid "Gitpod|e.g. https://gitpod.example.com"
+msgstr ""
+
msgid "Given access %{time_ago}"
msgstr ""
@@ -12318,9 +12694,6 @@ msgstr ""
msgid "GroupSAML|Valid SAML Response"
msgstr ""
-msgid "GroupSAML|With group managed accounts enabled, all the users without a group managed account will be excluded from the group."
-msgstr ""
-
msgid "GroupSAML|With prohibit outer forks flag enabled group members will be able to fork project only inside your group."
msgstr ""
@@ -12534,10 +12907,10 @@ msgstr ""
msgid "GroupsNew|Create group"
msgstr ""
-msgid "GroupsNew|GitLab group export"
+msgid "GroupsNew|Import"
msgstr ""
-msgid "GroupsNew|Import"
+msgid "GroupsNew|Import a GitLab group export file"
msgstr ""
msgid "GroupsNew|Import group"
@@ -12680,6 +13053,9 @@ msgid_plural "Hide charts"
msgstr[0] ""
msgstr[1] ""
+msgid "Hide comments on this file"
+msgstr ""
+
msgid "Hide details"
msgstr ""
@@ -12724,6 +13100,15 @@ msgstr ""
msgid "Highest role:"
msgstr ""
+msgid "HighlightBar|Alert events:"
+msgstr ""
+
+msgid "HighlightBar|Alert start time:"
+msgstr ""
+
+msgid "HighlightBar|Original alert:"
+msgstr ""
+
msgid "History"
msgstr ""
@@ -12901,6 +13286,9 @@ msgstr ""
msgid "If enabled, access to projects will be validated on an external service using their classification label."
msgstr ""
+msgid "If the number of active users exceeds the user limit, you will be charged for the number of %{users_over_license_link} at your next license reconciliation."
+msgstr ""
+
msgid "If there is no previous license or if the previous license has expired, some GitLab functionality will be blocked until a new, valid license is uploaded."
msgstr ""
@@ -12940,9 +13328,6 @@ msgstr ""
msgid "If your HTTP repository is not publicly accessible, add your credentials."
msgstr ""
-msgid "Iglu registry URL (optional)"
-msgstr ""
-
msgid "Ignore"
msgstr ""
@@ -12979,6 +13364,16 @@ msgstr ""
msgid "Import"
msgstr ""
+msgid "Import %d compatible repository"
+msgid_plural "Import %d compatible repositories"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Import %d repository"
+msgid_plural "Import %d repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Import CSV"
msgstr ""
@@ -12988,15 +13383,9 @@ msgstr ""
msgid "Import all compatible projects"
msgstr ""
-msgid "Import all compatible repositories"
-msgstr ""
-
msgid "Import all projects"
msgstr ""
-msgid "Import all repositories"
-msgstr ""
-
msgid "Import an exported GitLab project"
msgstr ""
@@ -13084,6 +13473,9 @@ msgstr ""
msgid "ImportProjects|Error importing repository %{project_safe_import_url} into %{project_full_path} - %{message}"
msgstr ""
+msgid "ImportProjects|Import repositories"
+msgstr ""
+
msgid "ImportProjects|Importing the project failed"
msgstr ""
@@ -13096,7 +13488,7 @@ msgstr ""
msgid "ImportProjects|Requesting your %{provider} repositories failed"
msgstr ""
-msgid "ImportProjects|Select the projects you want to import"
+msgid "ImportProjects|Select the repositories you want to import"
msgstr ""
msgid "ImportProjects|The remote data could not be imported."
@@ -13132,9 +13524,6 @@ msgstr ""
msgid "In order to enable Service Desk for your instance, you must first set up incoming email."
msgstr ""
-msgid "In order to gather accurate feature usage data, it can take 1 to 2 weeks to see your index."
-msgstr ""
-
msgid "In order to personalize your experience with GitLab%{br_tag}we would like to know a bit more about you."
msgstr ""
@@ -13165,18 +13554,30 @@ msgstr ""
msgid "IncidentManagement|Create incident"
msgstr ""
+msgid "IncidentManagement|Critical - S1"
+msgstr ""
+
msgid "IncidentManagement|Date created"
msgstr ""
msgid "IncidentManagement|Display your incidents in a dedicated view"
msgstr ""
+msgid "IncidentManagement|High - S2"
+msgstr ""
+
msgid "IncidentManagement|Incident"
msgstr ""
msgid "IncidentManagement|Incidents"
msgstr ""
+msgid "IncidentManagement|Low - S4"
+msgstr ""
+
+msgid "IncidentManagement|Medium - S3"
+msgstr ""
+
msgid "IncidentManagement|No incidents to display."
msgstr ""
@@ -13189,6 +13590,9 @@ msgstr ""
msgid "IncidentManagement|Published to status page"
msgstr ""
+msgid "IncidentManagement|Severity"
+msgstr ""
+
msgid "IncidentManagement|There are no closed incidents"
msgstr ""
@@ -13198,6 +13602,9 @@ msgstr ""
msgid "IncidentManagement|Unassigned"
msgstr ""
+msgid "IncidentManagement|Unknown"
+msgstr ""
+
msgid "IncidentManagement|Unpublished"
msgstr ""
@@ -13219,6 +13626,15 @@ msgstr ""
msgid "Incidents"
msgstr ""
+msgid "Incident|Alert details"
+msgstr ""
+
+msgid "Incident|Summary"
+msgstr ""
+
+msgid "Incident|There was an issue loading alert data. Please try again."
+msgstr ""
+
msgid "Include a Terms of Service agreement and Privacy Policy that all users must accept."
msgstr ""
@@ -13279,6 +13695,9 @@ msgstr ""
msgid "Information about additional Pages templates and how to install them can be found in our %{pages_getting_started_guide}."
msgstr ""
+msgid "Inherited"
+msgstr ""
+
msgid "Inherited:"
msgstr ""
@@ -13359,7 +13778,22 @@ msgstr ""
msgid "Instance administrators group already exists"
msgstr ""
-msgid "Instance license"
+msgid "InstanceStatistics|Groups"
+msgstr ""
+
+msgid "InstanceStatistics|Issues"
+msgstr ""
+
+msgid "InstanceStatistics|Merge Requests"
+msgstr ""
+
+msgid "InstanceStatistics|Pipelines"
+msgstr ""
+
+msgid "InstanceStatistics|Projects"
+msgstr ""
+
+msgid "InstanceStatistics|Users"
msgstr ""
msgid "Integration"
@@ -13371,6 +13805,12 @@ msgstr ""
msgid "Integrations"
msgstr ""
+msgid "Integrations|%{integration} settings saved and active."
+msgstr ""
+
+msgid "Integrations|%{integration} settings saved, but not active."
+msgstr ""
+
msgid "Integrations|All details"
msgstr ""
@@ -13380,6 +13820,12 @@ msgstr ""
msgid "Integrations|Comment settings:"
msgstr ""
+msgid "Integrations|Connection failed. Please check your settings."
+msgstr ""
+
+msgid "Integrations|Connection successful."
+msgstr ""
+
msgid "Integrations|Default settings are inherited from the group level."
msgstr ""
@@ -13395,6 +13841,15 @@ msgstr ""
msgid "Integrations|Includes commit title and branch"
msgstr ""
+msgid "Integrations|Projects using custom settings will not be impacted unless the project owner chooses to use instance-level defaults."
+msgstr ""
+
+msgid "Integrations|Save settings?"
+msgstr ""
+
+msgid "Integrations|Saving will update the default settings for all projects that are not using custom settings."
+msgstr ""
+
msgid "Integrations|Standard"
msgstr ""
@@ -13527,6 +13982,9 @@ msgstr ""
msgid "Invitation"
msgstr ""
+msgid "Invitation declined"
+msgstr ""
+
msgid "Invite"
msgstr ""
@@ -13578,6 +14036,42 @@ 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|%{linkStart}Read more%{linkEnd} about role permissions"
+msgstr ""
+
+msgid "InviteMembersModal|Access expiration date (optional)"
+msgstr ""
+
+msgid "InviteMembersModal|Cancel"
+msgstr ""
+
+msgid "InviteMembersModal|Choose a role permission"
+msgstr ""
+
+msgid "InviteMembersModal|GitLab member or Email address"
+msgstr ""
+
+msgid "InviteMembersModal|Invite"
+msgstr ""
+
+msgid "InviteMembersModal|Invite team members"
+msgstr ""
+
+msgid "InviteMembersModal|Search for members to invite"
+msgstr ""
+
+msgid "InviteMembersModal|User not invited. Feature coming soon!"
+msgstr ""
+
+msgid "InviteMembersModal|Users were succesfully added"
+msgstr ""
+
+msgid "InviteMembersModal|You're inviting members to the %{group_name} group"
+msgstr ""
+
+msgid "InviteMembers|Invite team members"
+msgstr ""
+
msgid "Invited"
msgstr ""
@@ -13632,10 +14126,13 @@ msgstr ""
msgid "Issue cannot be found."
msgstr ""
+msgid "Issue created from vulnerability %{vulnerability_link}"
+msgstr ""
+
msgid "Issue events"
msgstr ""
-msgid "Issue first depoloyed to production"
+msgid "Issue first deployed to production"
msgstr ""
msgid "Issue label"
@@ -13713,6 +14210,9 @@ msgstr ""
msgid "IssueTracker|Custom issue tracker"
msgstr ""
+msgid "IssueTracker|EWM work items tracker"
+msgstr ""
+
msgid "IssueTracker|Redmine issue tracker"
msgstr ""
@@ -13779,6 +14279,9 @@ msgstr ""
msgid "It looks like you have some draft commits in this branch."
msgstr ""
+msgid "It may be several days before you see feature usage data."
+msgstr ""
+
msgid "It must have a header row and at least two columns: the first column is the issue title and the second column is the issue description. The separator is automatically detected."
msgstr ""
@@ -14061,13 +14564,13 @@ msgstr ""
msgid "Join Zoom meeting"
msgstr ""
-msgid "Jul"
+msgid "Joined %{time_ago}"
msgstr ""
-msgid "July"
+msgid "Jul"
msgstr ""
-msgid "Jump to first unresolved thread"
+msgid "July"
msgstr ""
msgid "Jump to next unresolved thread"
@@ -14103,6 +14606,9 @@ msgstr ""
msgid "Keyboard shortcuts"
msgstr ""
+msgid "KeyboardKey|Ctrl+"
+msgstr ""
+
msgid "Keys"
msgstr ""
@@ -14151,6 +14657,9 @@ msgstr ""
msgid "LDAP Synchronization"
msgstr ""
+msgid "LDAP group settings"
+msgstr ""
+
msgid "LDAP settings"
msgstr ""
@@ -14160,6 +14669,9 @@ msgstr ""
msgid "LDAP sync in progress. This could take a few minutes. Refresh the page to see the changes."
msgstr ""
+msgid "LDAP synchronizations"
+msgstr ""
+
msgid "LFS"
msgstr ""
@@ -14240,7 +14752,16 @@ msgid_plural "Last %d days"
msgstr[0] ""
msgstr[1] ""
-msgid "Last %{days} days"
+msgid "Last 2 weeks"
+msgstr ""
+
+msgid "Last 30 days"
+msgstr ""
+
+msgid "Last 60 days"
+msgstr ""
+
+msgid "Last 90 days"
msgstr ""
msgid "Last Accessed On"
@@ -14318,6 +14839,9 @@ msgstr ""
msgid "Last used on:"
msgstr ""
+msgid "Last week"
+msgstr ""
+
msgid "LastCommit|authored"
msgstr ""
@@ -14333,6 +14857,9 @@ msgstr ""
msgid "Latest pipeline for the most recent commit on this branch"
msgstr ""
+msgid "Launch a ready-to-code development environment for your project."
+msgstr ""
+
msgid "Lead"
msgstr ""
@@ -14713,6 +15240,9 @@ msgstr ""
msgid "List of all merge commits"
msgstr ""
+msgid "List options"
+msgstr ""
+
msgid "List settings"
msgstr ""
@@ -14725,9 +15255,6 @@ msgstr ""
msgid "List your Bitbucket Server repositories"
msgstr ""
-msgid "Lists"
-msgstr ""
-
msgid "Live preview"
msgstr ""
@@ -14974,6 +15501,12 @@ msgstr ""
msgid "Mark as done"
msgstr ""
+msgid "Mark as draft"
+msgstr ""
+
+msgid "Mark as ready"
+msgstr ""
+
msgid "Mark as resolved"
msgstr ""
@@ -14995,6 +15528,24 @@ msgstr ""
msgid "Markdown is supported"
msgstr ""
+msgid "MarkdownEditor|Add a link (%{modifierKey}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add a link (%{modifier_key}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifierKey}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifier_key}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifierKey}I)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifier_key}I)"
+msgstr ""
+
msgid "Marked For Deletion At - %{deletion_time}"
msgstr ""
@@ -15079,7 +15630,25 @@ msgstr ""
msgid "Max access level"
msgstr ""
-msgid "Max seats used"
+msgid "Max role"
+msgstr ""
+
+msgid "Max size 15 MB"
+msgstr ""
+
+msgid "Maximum Conan package file size in bytes"
+msgstr ""
+
+msgid "Maximum Maven package file size in bytes"
+msgstr ""
+
+msgid "Maximum NPM package file size in bytes"
+msgstr ""
+
+msgid "Maximum NuGet package file size in bytes"
+msgstr ""
+
+msgid "Maximum PyPI package file size in bytes"
msgstr ""
msgid "Maximum Users:"
@@ -15211,6 +15780,18 @@ msgstr ""
msgid "Members with access to %{strong_start}%{group_name}%{strong_end}"
msgstr ""
+msgid "Members|%{time} by %{user}"
+msgstr ""
+
+msgid "Members|Expired"
+msgstr ""
+
+msgid "Members|No expiration set"
+msgstr ""
+
+msgid "Members|in %{time}"
+msgstr ""
+
msgid "Memory Usage"
msgstr ""
@@ -15397,9 +15978,6 @@ msgstr ""
msgid "MergeRequests|Thread will be unresolved"
msgstr ""
-msgid "MergeRequests|Toggle comments for this file"
-msgstr ""
-
msgid "MergeRequests|View file @ %{commitId}"
msgstr ""
@@ -15460,6 +16038,9 @@ msgstr ""
msgid "Merging immediately isn't recommended as it may negatively impact the existing merge train. Read the %{docsLinkStart}documentation%{docsLinkEnd} for more information."
msgstr ""
+msgid "Message"
+msgstr ""
+
msgid "Messages"
msgstr ""
@@ -15845,18 +16426,12 @@ msgid_plural "Milestones"
msgstr[0] ""
msgstr[1] ""
-msgid "Milestone does not support burnup charts"
-msgstr ""
-
msgid "Milestone lists not available with your current license"
msgstr ""
msgid "Milestone lists show all issues from the selected milestone."
msgstr ""
-msgid "Milestone must have a start and due date"
-msgstr ""
-
msgid "MilestoneSidebar|Closed:"
msgstr ""
@@ -16223,6 +16798,9 @@ msgstr ""
msgid "Namespace"
msgstr ""
+msgid "Namespace ID:"
+msgstr ""
+
msgid "Namespace is empty"
msgstr ""
@@ -16307,6 +16885,9 @@ msgstr ""
msgid "NetworkPolicies|Allow all outbound traffic from %{selector} to %{ruleSelector} on %{ports}"
msgstr ""
+msgid "NetworkPolicies|Are you sure you want to delete this policy? This action cannot be undone."
+msgstr ""
+
msgid "NetworkPolicies|Choose whether to enforce this policy."
msgstr ""
@@ -16316,12 +16897,21 @@ msgstr ""
msgid "NetworkPolicies|Define this policy's location, conditions and actions."
msgstr ""
+msgid "NetworkPolicies|Delete policy"
+msgstr ""
+
+msgid "NetworkPolicies|Delete policy: %{policy}"
+msgstr ""
+
msgid "NetworkPolicies|Deny all traffic"
msgstr ""
msgid "NetworkPolicies|Description"
msgstr ""
+msgid "NetworkPolicies|Edit policy"
+msgstr ""
+
msgid "NetworkPolicies|Editor mode"
msgstr ""
@@ -16349,6 +16939,9 @@ msgstr ""
msgid "NetworkPolicies|Name"
msgstr ""
+msgid "NetworkPolicies|Namespace"
+msgstr ""
+
msgid "NetworkPolicies|Network Policy"
msgstr ""
@@ -16400,6 +16993,9 @@ msgstr ""
msgid "NetworkPolicies|Rules"
msgstr ""
+msgid "NetworkPolicies|Save changes"
+msgstr ""
+
msgid "NetworkPolicies|Something went wrong, failed to update policy"
msgstr ""
@@ -16412,6 +17008,9 @@ msgstr ""
msgid "NetworkPolicies|Traffic that does not match any rule will be blocked."
msgstr ""
+msgid "NetworkPolicies|Unable to parse policy"
+msgstr ""
+
msgid "NetworkPolicies|YAML editor"
msgstr ""
@@ -16525,6 +17124,9 @@ msgstr ""
msgid "New Snippet"
msgstr ""
+msgid "New Test Case"
+msgstr ""
+
msgid "New User"
msgstr ""
@@ -16624,6 +17226,9 @@ msgstr ""
msgid "New tag"
msgstr ""
+msgid "New test case"
+msgstr ""
+
msgid "New users set to external"
msgstr ""
@@ -16696,7 +17301,7 @@ msgstr ""
msgid "No changes"
msgstr ""
-msgid "No changes between %{ref_start}%{source_branch}%{ref_end} and %{ref_start}%{target_branch}%{ref_end}"
+msgid "No changes between %{sourceBranch} and %{targetBranch}"
msgstr ""
msgid "No child epics match applied filters"
@@ -16711,6 +17316,9 @@ msgstr ""
msgid "No containers available"
msgstr ""
+msgid "No content to show"
+msgstr ""
+
msgid "No contributions"
msgstr ""
@@ -16786,9 +17394,6 @@ msgstr ""
msgid "No license. All rights reserved"
msgstr ""
-msgid "No licenses found."
-msgstr ""
-
msgid "No matches found"
msgstr ""
@@ -16801,6 +17406,9 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No members found"
+msgstr ""
+
msgid "No merge requests found"
msgstr ""
@@ -16822,6 +17430,9 @@ msgstr ""
msgid "No parent group"
msgstr ""
+msgid "No plan"
+msgstr ""
+
msgid "No pods available"
msgstr ""
@@ -16918,6 +17529,12 @@ msgstr ""
msgid "Not Implemented"
msgstr ""
+msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+msgstr ""
+
+msgid "Not all browsers support WebAuthn. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even from an unsupported browser."
+msgstr ""
+
msgid "Not all data has been processed yet, the accuracy of the chart for the selected timeframe is limited."
msgstr ""
@@ -17014,6 +17631,9 @@ msgstr ""
msgid "Notification settings saved"
msgstr ""
+msgid "NotificationEvent|Change reviewer merge request"
+msgstr ""
+
msgid "NotificationEvent|Close issue"
msgstr ""
@@ -17176,10 +17796,7 @@ msgstr ""
msgid "On track"
msgstr ""
-msgid "OnDemandScans|Attached branch"
-msgstr ""
-
-msgid "OnDemandScans|Attached branch is where the scan job runs."
+msgid "OnDemandScans|Could not fetch scanner profiles. Please refresh the page, or try again later."
msgstr ""
msgid "OnDemandScans|Could not fetch site profiles. Please refresh the page, or try again later."
@@ -17188,6 +17805,9 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
+msgid "OnDemandScans|Create a new scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Create a new site profile"
msgstr ""
@@ -17200,6 +17820,9 @@ msgstr ""
msgid "OnDemandScans|New on-demand DAST scan"
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 ""
@@ -17209,16 +17832,10 @@ msgstr ""
msgid "OnDemandScans|On-demand scans run outside the DevOps cycle and find vulnerabilities in your projects. %{learnMoreLinkStart}Learn more%{learnMoreLinkEnd}"
msgstr ""
-msgid "OnDemandScans|Only a passive scan can be performed on demand."
-msgstr ""
-
-msgid "OnDemandScans|Passive"
-msgstr ""
-
msgid "OnDemandScans|Run scan"
msgstr ""
-msgid "OnDemandScans|Scan mode"
+msgid "OnDemandScans|Scanner profile"
msgstr ""
msgid "OnDemandScans|Scanner settings"
@@ -17230,9 +17847,15 @@ msgstr ""
msgid "OnDemandScans|Select one of the existing profiles"
msgstr ""
+msgid "OnDemandScans|Site profile"
+msgstr ""
+
msgid "OnDemandScans|Site profiles"
msgstr ""
+msgid "OnDemandScans|Use existing scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Use existing site profile"
msgstr ""
@@ -17331,9 +17954,6 @@ msgstr ""
msgid "Open Selection"
msgstr ""
-msgid "Open Web IDE"
-msgstr ""
-
msgid "Open comment type dropdown"
msgstr ""
@@ -17439,6 +18059,9 @@ msgstr ""
msgid "Origin"
msgstr ""
+msgid "Orphaned member"
+msgstr ""
+
msgid "Other Labels"
msgstr ""
@@ -17454,6 +18077,9 @@ msgstr ""
msgid "Other visibility settings have been disabled by the administrator."
msgstr ""
+msgid "Our documentation includes an example DevOps Score report."
+msgstr ""
+
msgid "Out-of-compliance with this project's policies and should be removed"
msgstr ""
@@ -17478,6 +18104,9 @@ msgstr ""
msgid "Overwrite diverged branches"
msgstr ""
+msgid "Owned by %{image_tag}"
+msgstr ""
+
msgid "Owned by anyone"
msgstr ""
@@ -17499,6 +18128,9 @@ msgstr ""
msgid "Package deleted successfully"
msgstr ""
+msgid "Package file size limits"
+msgstr ""
+
msgid "Package recipe already exists"
msgstr ""
@@ -17514,9 +18146,6 @@ msgstr ""
msgid "Package type must be PyPi"
msgstr ""
-msgid "Package was removed"
-msgstr ""
-
msgid "PackageRegistry|%{name} version %{version} was created %{datetime}"
msgstr ""
@@ -17658,12 +18287,18 @@ msgstr ""
msgid "PackageRegistry|NuGet Command"
msgstr ""
+msgid "PackageRegistry|Package Registry"
+msgstr ""
+
msgid "PackageRegistry|Pip Command"
msgstr ""
msgid "PackageRegistry|Pipeline %{link} triggered %{datetime} by %{author}"
msgstr ""
+msgid "PackageRegistry|Publish and share packages for a variety of common package managers. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "PackageRegistry|Published to the %{project} Package Registry %{datetime}"
msgstr ""
@@ -17763,6 +18398,9 @@ msgstr ""
msgid "Page not found"
msgstr ""
+msgid "Page settings"
+msgstr ""
+
msgid "Page was successfully deleted"
msgstr ""
@@ -17904,7 +18542,7 @@ msgstr ""
msgid "Paste issue link"
msgstr ""
-msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Don't use your private SSH key."
+msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Do not paste your private SSH key, as that can compromise your identity."
msgstr ""
msgid "Patch to apply"
@@ -17931,6 +18569,9 @@ msgstr ""
msgid "Pending"
msgstr ""
+msgid "Pending comments"
+msgstr ""
+
msgid "People without permission will never get a notification and won't be able to comment."
msgstr ""
@@ -18129,6 +18770,9 @@ msgstr ""
msgid "Pipelines|Build with confidence"
msgstr ""
+msgid "Pipelines|By revoking a trigger you will break any processes making use of it. Are you sure?"
+msgstr ""
+
msgid "Pipelines|CI Lint"
msgstr ""
@@ -18141,6 +18785,15 @@ msgstr ""
msgid "Pipelines|Continuous Integration can help catch bugs by running your tests automatically, while Continuous Deployment can help you deliver code to your product environment."
msgstr ""
+msgid "Pipelines|Copy trigger token"
+msgstr ""
+
+msgid "Pipelines|Description"
+msgstr ""
+
+msgid "Pipelines|Edit"
+msgstr ""
+
msgid "Pipelines|Get started with Pipelines"
msgstr ""
@@ -18156,15 +18809,27 @@ msgstr ""
msgid "Pipelines|It is recommended the code is reviewed thoroughly before running this pipeline with the parent project's CI resource."
msgstr ""
+msgid "Pipelines|Last Used"
+msgstr ""
+
msgid "Pipelines|Loading Pipelines"
msgstr ""
msgid "Pipelines|More Information"
msgstr ""
+msgid "Pipelines|No triggers have been created yet. Add one using the form above."
+msgstr ""
+
+msgid "Pipelines|Owner"
+msgstr ""
+
msgid "Pipelines|Project cache successfully reset."
msgstr ""
+msgid "Pipelines|Revoke"
+msgstr ""
+
msgid "Pipelines|Run Pipeline"
msgstr ""
@@ -18189,6 +18854,15 @@ msgstr ""
msgid "Pipelines|This project is not currently set up to run pipelines."
msgstr ""
+msgid "Pipelines|Token"
+msgstr ""
+
+msgid "Pipelines|Trigger user has insufficient permissions to project"
+msgstr ""
+
+msgid "Pipelines|invalid"
+msgstr ""
+
msgid "Pipelines|parent"
msgstr ""
@@ -18447,10 +19121,10 @@ msgstr ""
msgid "Please provide attributes to update"
msgstr ""
-msgid "Please refer to %{docs_url}"
+msgid "Please reach out if you have any questions and we'll be happy to assist."
msgstr ""
-msgid "Please retype the email address."
+msgid "Please refer to %{docs_url}"
msgstr ""
msgid "Please select"
@@ -18480,6 +19154,9 @@ msgstr ""
msgid "Please set a new password before proceeding."
msgstr ""
+msgid "Please share your feedback about %{featureName} %{linkStart}in this issue%{linkEnd} to help us improve the experience."
+msgstr ""
+
msgid "Please solve the reCAPTCHA"
msgstr ""
@@ -18783,6 +19460,9 @@ msgstr ""
msgid "Profiles| You are going to change the username %{currentUsernameBold} to %{newUsernameBold}. Profile and projects will be redirected to the %{newUsername} namespace but this redirect will expire once the %{currentUsername} namespace is registered by another user or group. Please update your Git repository remotes as soon as possible."
msgstr ""
+msgid "Profiles|%{provider} Active"
+msgstr ""
+
msgid "Profiles|@username"
msgstr ""
@@ -18834,7 +19514,7 @@ msgstr ""
msgid "Profiles|Commit email"
msgstr ""
-msgid "Profiles|Connect"
+msgid "Profiles|Connect %{provider}"
msgstr ""
msgid "Profiles|Connected Accounts"
@@ -18858,6 +19538,9 @@ msgstr ""
msgid "Profiles|Disconnect"
msgstr ""
+msgid "Profiles|Disconnect %{provider}"
+msgstr ""
+
msgid "Profiles|Do not show on profile"
msgstr ""
@@ -18882,7 +19565,7 @@ msgstr ""
msgid "Profiles|Full name"
msgstr ""
-msgid "Profiles|Give your individual key a title. This will be publically visible."
+msgid "Profiles|Give your individual key a title."
msgstr ""
msgid "Profiles|Include private contributions on my profile"
@@ -18972,7 +19655,7 @@ msgstr ""
msgid "Profiles|The maximum file size allowed is 200KB."
msgstr ""
-msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it?"
+msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it? It will be publicly visible."
msgstr ""
msgid "Profiles|This email will be displayed on your public profile"
@@ -19047,6 +19730,9 @@ msgstr ""
msgid "Profiles|You don't have access to delete this user."
msgstr ""
+msgid "Profiles|You must transfer ownership or delete groups you are an owner of before you can delete your account"
+msgstr ""
+
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
@@ -19635,6 +20321,9 @@ msgstr ""
msgid "ProjectTemplates|GitLab Cluster Management"
msgstr ""
+msgid "ProjectTemplates|Gitpod/Spring Petclinic"
+msgstr ""
+
msgid "ProjectTemplates|Go Micro"
msgstr ""
@@ -20244,6 +20933,9 @@ msgstr ""
msgid "Publish to status page"
msgstr ""
+msgid "Published"
+msgstr ""
+
msgid "Published on status page"
msgstr ""
@@ -20361,9 +21053,15 @@ msgstr ""
msgid "Quick range"
msgstr ""
+msgid "Quickly and easily edit multiple files in your project."
+msgstr ""
+
msgid "README"
msgstr ""
+msgid "Rails"
+msgstr ""
+
msgid "Rake Tasks Help"
msgstr ""
@@ -20483,10 +21181,13 @@ msgstr ""
msgid "Register Two-Factor Authenticator"
msgstr ""
-msgid "Register U2F device"
+msgid "Register Universal Two-Factor (U2F) Device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register WebAuthn Device"
+msgstr ""
+
+msgid "Register device"
msgstr ""
msgid "Register for GitLab"
@@ -20498,9 +21199,6 @@ msgstr ""
msgid "Register with two-factor app"
msgstr ""
-msgid "Registration"
-msgstr ""
-
msgid "Registration|Checkout"
msgstr ""
@@ -20617,9 +21315,6 @@ msgstr ""
msgid "Release|Something went wrong while saving the release details"
msgstr ""
-msgid "Remediated: needs review"
-msgstr ""
-
msgid "Remediations"
msgstr ""
@@ -20725,6 +21420,9 @@ msgstr ""
msgid "Remove priority"
msgstr ""
+msgid "Remove report"
+msgstr ""
+
msgid "Remove secondary node"
msgstr ""
@@ -20737,6 +21435,12 @@ msgstr ""
msgid "Remove time estimate"
msgstr ""
+msgid "Remove user & report"
+msgstr ""
+
+msgid "Remove user from group"
+msgstr ""
+
msgid "Removed"
msgstr ""
@@ -20818,9 +21522,6 @@ msgstr ""
msgid "Removes time estimate."
msgstr ""
-msgid "Removing license…"
-msgstr ""
-
msgid "Removing this group also removes all child projects, including archived projects, and their resources."
msgstr ""
@@ -20905,6 +21606,9 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
+msgid "Reported by %{reporter}"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -20991,6 +21695,27 @@ msgstr ""
msgid "Repositories"
msgstr ""
+msgid "Repositories Analytics"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download Historic Test Coverage Data"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download historic test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Historic Test Coverage Data is available in raw format (.csv) for further analysis."
+msgstr ""
+
+msgid "RepositoriesAnalytics|Test Code Coverage"
+msgstr ""
+
+msgid "RepositoriesAnalytics|There was an error fetching the projects."
+msgstr ""
+
msgid "Repository"
msgstr ""
@@ -21069,9 +21794,15 @@ msgstr ""
msgid "Request parameter %{param} is missing."
msgstr ""
+msgid "Request review from"
+msgstr ""
+
msgid "Request to link SAML account must be authorized"
msgstr ""
+msgid "Requested"
+msgstr ""
+
msgid "Requested %{time_ago}"
msgstr ""
@@ -21090,6 +21821,9 @@ msgstr ""
msgid "Requests to these domain(s)/address(es) on the local network will be allowed when local requests from hooks and services are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 or 127.0.0.0/28 are supported. Domain wildcards are not supported currently. Use comma, semicolon, or newline to separate multiple entries. The allowlist can hold a maximum of 1000 entries. Domains should use IDNA encoding. Ex: example.com, 192.168.1.1, 127.0.0.0/28, xn--itlab-j1a.com."
msgstr ""
+msgid "Require admin approval for new sign-ups"
+msgstr ""
+
msgid "Require all users in this group to setup Two-factor authentication"
msgstr ""
@@ -21217,9 +21951,6 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
-msgid "Resolved by %{resolvedByName}"
-msgstr ""
-
msgid "Resolves IP addresses once and uses them to submit requests"
msgstr ""
@@ -21339,6 +22070,14 @@ msgstr ""
msgid "ReviewApp|Enable Review App"
msgstr ""
+msgid "Reviewer"
+msgid_plural "%d Reviewers"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Reviewer(s)"
+msgstr ""
+
msgid "Reviewing"
msgstr ""
@@ -21378,6 +22117,9 @@ msgstr ""
msgid "Rook"
msgstr ""
+msgid "Ruby"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -21456,6 +22198,63 @@ msgstr ""
msgid "Runners page."
msgstr ""
+msgid "Runners|Active"
+msgstr ""
+
+msgid "Runners|Architecture"
+msgstr ""
+
+msgid "Runners|Can run untagged jobs"
+msgstr ""
+
+msgid "Runners|Description"
+msgstr ""
+
+msgid "Runners|Group"
+msgstr ""
+
+msgid "Runners|IP Address"
+msgstr ""
+
+msgid "Runners|Last contact"
+msgstr ""
+
+msgid "Runners|Locked to this project"
+msgstr ""
+
+msgid "Runners|Maximum job timeout"
+msgstr ""
+
+msgid "Runners|Name"
+msgstr ""
+
+msgid "Runners|Platform"
+msgstr ""
+
+msgid "Runners|Property Name"
+msgstr ""
+
+msgid "Runners|Protected"
+msgstr ""
+
+msgid "Runners|Revision"
+msgstr ""
+
+msgid "Runners|Shared"
+msgstr ""
+
+msgid "Runners|Specific"
+msgstr ""
+
+msgid "Runners|Tags"
+msgstr ""
+
+msgid "Runners|Value"
+msgstr ""
+
+msgid "Runners|Version"
+msgstr ""
+
msgid "Runners|You have used %{quotaUsed} out of %{quotaLimit} of your shared Runners pipeline minutes."
msgstr ""
@@ -21468,6 +22267,9 @@ msgstr ""
msgid "Runs a number of housekeeping tasks within the current repository, such as compressing file revisions and removing unreachable objects."
msgstr ""
+msgid "SAML"
+msgstr ""
+
msgid "SAML SSO"
msgstr ""
@@ -21519,6 +22321,9 @@ msgstr ""
msgid "Save"
msgstr ""
+msgid "Save %{name} size limits"
+msgstr ""
+
msgid "Save Changes"
msgstr ""
@@ -21549,9 +22354,6 @@ msgstr ""
msgid "Save space and find tags in the Container Registry more easily. Enable the cleanup policy to remove stale tags and keep only the ones you need."
msgstr ""
-msgid "Save template"
-msgstr ""
-
msgid "Save variables"
msgstr ""
@@ -21594,9 +22396,6 @@ msgstr ""
msgid "Scope"
msgstr ""
-msgid "Scope not supported with disabled 'users_search' feature!"
-msgstr ""
-
msgid "Scoped issue boards"
msgstr ""
@@ -21723,9 +22522,6 @@ msgstr ""
msgid "Search requirements"
msgstr ""
-msgid "Search results…"
-msgstr ""
-
msgid "Search users"
msgstr ""
@@ -21798,6 +22594,11 @@ msgid_plural "SearchResults|commits"
msgstr[0] ""
msgstr[1] ""
+msgid "SearchResults|epic"
+msgid_plural "SearchResults|epics"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "SearchResults|issue"
msgid_plural "SearchResults|issues"
msgstr[0] ""
@@ -21842,10 +22643,10 @@ msgstr ""
msgid "Seat Link is disabled, and cannot be configured through this form."
msgstr ""
-msgid "Seats currently in use"
+msgid "Seats usage data as of %{last_enqueue_time}"
msgstr ""
-msgid "Seats in license"
+msgid "Seats usage data is updated every day at 12:00pm UTC"
msgstr ""
msgid "Secondary"
@@ -21899,6 +22700,9 @@ msgstr ""
msgid "SecurityConfiguration|Available for on-demand DAST"
msgstr ""
+msgid "SecurityConfiguration|By default, all analyzers are applied in order to cover all languages across your project, and only run if the language is detected in the Merge Request."
+msgstr ""
+
msgid "SecurityConfiguration|Configure"
msgstr ""
@@ -21929,16 +22733,19 @@ msgstr ""
msgid "SecurityConfiguration|Manage"
msgstr ""
+msgid "SecurityConfiguration|More information"
+msgstr ""
+
msgid "SecurityConfiguration|Not enabled"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|Security Control"
+msgid "SecurityConfiguration|SAST Configuration"
msgstr ""
-msgid "SecurityConfiguration|See documentation"
+msgid "SecurityConfiguration|Security Control"
msgstr ""
msgid "SecurityConfiguration|Status"
@@ -21950,6 +22757,9 @@ msgstr ""
msgid "SecurityConfiguration|Using custom settings. You won't receive automatic updates on this variable. %{anchorStart}Restore to default%{anchorEnd}"
msgstr ""
+msgid "SecurityConfiguration|View history"
+msgstr ""
+
msgid "SecurityConfiguration|You can quickly enable all security scanning tools by enabling %{linkStart}Auto DevOps%{linkEnd}."
msgstr ""
@@ -22028,9 +22838,6 @@ msgstr ""
msgid "SecurityReports|Learn more about setting up your dashboard"
msgstr ""
-msgid "SecurityReports|Load more vulnerabilities"
-msgstr ""
-
msgid "SecurityReports|Monitor vulnerabilities in your code"
msgstr ""
@@ -22310,7 +23117,7 @@ msgstr ""
msgid "Select status"
msgstr ""
-msgid "Select strategy activation method"
+msgid "Select strategy activation method."
msgstr ""
msgid "Select subscription"
@@ -22325,7 +23132,7 @@ msgstr ""
msgid "Select the custom project template source group."
msgstr ""
-msgid "Select timeframe"
+msgid "Select the environment scope for this feature flag."
msgstr ""
msgid "Select timezone"
@@ -22574,6 +23381,9 @@ msgstr ""
msgid "Set iteration"
msgstr ""
+msgid "Set limit to 0 to allow any file size."
+msgstr ""
+
msgid "Set max session time for web terminal."
msgstr ""
@@ -22652,10 +23462,13 @@ msgstr ""
msgid "Set up a %{type} Runner manually"
msgstr ""
+msgid "Set up a hardware device as a second factor to sign in."
+msgstr ""
+
msgid "Set up assertions/attributes/claims (email, first_name, last_name) and NameID according to %{docsLinkStart}the documentation %{icon}%{docsLinkEnd}"
msgstr ""
-msgid "Set up new U2F device"
+msgid "Set up new device"
msgstr ""
msgid "Set up new password"
@@ -22724,6 +23537,9 @@ msgstr ""
msgid "Sets weight to %{weight}."
msgstr ""
+msgid "Setting this to 0 means using the system default timeout value."
+msgstr ""
+
msgid "Settings"
msgstr ""
@@ -22739,6 +23555,15 @@ msgstr ""
msgid "Severity"
msgstr ""
+msgid "SeverityWidget|Severity"
+msgstr ""
+
+msgid "SeverityWidget|Severity: %{severity}"
+msgstr ""
+
+msgid "SeverityWidget|There was an error while updating severity."
+msgstr ""
+
msgid "Shards (%{shards})"
msgstr ""
@@ -22784,6 +23609,9 @@ msgstr ""
msgid "Show all requirements."
msgstr ""
+msgid "Show all test cases."
+msgstr ""
+
msgid "Show archived projects"
msgstr ""
@@ -22796,6 +23624,9 @@ msgstr ""
msgid "Show comments"
msgstr ""
+msgid "Show comments on this file"
+msgstr ""
+
msgid "Show comments only"
msgstr ""
@@ -22841,6 +23672,12 @@ msgstr ""
msgid "Show parent subgroups"
msgstr ""
+msgid "Show the Closed list"
+msgstr ""
+
+msgid "Show the Open list"
+msgstr ""
+
msgid "Show whitespace changes"
msgstr ""
@@ -22884,9 +23721,6 @@ msgstr ""
msgid "Sidebar|Assign health status"
msgstr ""
-msgid "Sidebar|Change weight"
-msgstr ""
-
msgid "Sidebar|Health status"
msgstr ""
@@ -23070,6 +23904,9 @@ msgstr ""
msgid "Snippets|Add another file %{num}/%{total}"
msgstr ""
+msgid "Snippets|Authored %{time_ago} by %{author}"
+msgstr ""
+
msgid "Snippets|Delete file"
msgstr ""
@@ -23097,6 +23934,9 @@ msgstr ""
msgid "Solution"
msgstr ""
+msgid "Some changes are not shown"
+msgstr ""
+
msgid "Some child epics may be hidden due to applied filters"
msgstr ""
@@ -23463,6 +24303,12 @@ msgstr ""
msgid "Source (branch or tag)"
msgstr ""
+msgid "Source Branch"
+msgstr ""
+
+msgid "Source branch: %{source_branch_open}%{source_branch}%{source_branch_close}"
+msgstr ""
+
msgid "Source code"
msgstr ""
@@ -23628,9 +24474,6 @@ msgstr ""
msgid "Start and due date"
msgstr ""
-msgid "Start by choosing a group to see how your team is spending time. You can then drill down to the project level."
-msgstr ""
-
msgid "Start by choosing a group to start exploring the merge requests in that group. You can then proceed to filter by projects, labels, milestones and authors."
msgstr ""
@@ -23712,18 +24555,27 @@ msgstr ""
msgid "StaticSiteEditor|3. Assign a person to review and accept the merge request."
msgstr ""
+msgid "StaticSiteEditor|A link to view the merge request will appear once ready."
+msgstr ""
+
msgid "StaticSiteEditor|An error occurred while submitting your changes."
msgstr ""
msgid "StaticSiteEditor|Branch could not be created."
msgstr ""
+msgid "StaticSiteEditor|Copy update"
+msgstr ""
+
msgid "StaticSiteEditor|Could not commit the content changes."
msgstr ""
msgid "StaticSiteEditor|Could not create merge request."
msgstr ""
+msgid "StaticSiteEditor|Creating your merge request"
+msgstr ""
+
msgid "StaticSiteEditor|Incompatible file content"
msgstr ""
@@ -23745,6 +24597,9 @@ msgstr ""
msgid "StaticSiteEditor|View documentation"
msgstr ""
+msgid "StaticSiteEditor|You can set an assignee to get your changes reviewed and deployed once your merge request is created."
+msgstr ""
+
msgid "StaticSiteEditor|Your merge request has been created"
msgstr ""
@@ -23874,15 +24729,15 @@ msgstr ""
msgid "Submit %{humanized_resource_name}"
msgstr ""
-msgid "Submit Changes"
-msgstr ""
-
msgid "Submit a review"
msgstr ""
msgid "Submit as spam"
msgstr ""
+msgid "Submit changes"
+msgstr ""
+
msgid "Submit feedback"
msgstr ""
@@ -24036,6 +24891,9 @@ msgstr ""
msgid "Successfully deleted U2F device."
msgstr ""
+msgid "Successfully deleted WebAuthn device."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -24354,9 +25212,6 @@ msgstr ""
msgid "Template to append to all Service Desk issues"
msgstr ""
-msgid "Template was successfully saved."
-msgstr ""
-
msgid "Templates"
msgstr ""
@@ -24435,10 +25290,28 @@ msgid_plural "Test coverage: %d hits"
msgstr[0] ""
msgstr[1] ""
-msgid "Test failed."
+msgid "Test settings"
msgstr ""
-msgid "Test settings and save changes"
+msgid "TestCases|New Test Case"
+msgstr ""
+
+msgid "TestCases|New test case"
+msgstr ""
+
+msgid "TestCases|Search test cases"
+msgstr ""
+
+msgid "TestCases|Something went wrong while creating a test case."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching count of test cases."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching test cases list."
+msgstr ""
+
+msgid "TestCases|Submit test case"
msgstr ""
msgid "TestHooks|Ensure one of your projects has merge requests."
@@ -24504,6 +25377,9 @@ msgstr ""
msgid "Thank you for signing up for your free trial! You will get additional instructions in your inbox shortly."
msgstr ""
+msgid "Thank you for your business."
+msgstr ""
+
msgid "Thank you for your feedback!"
msgstr ""
@@ -24563,9 +25439,6 @@ msgstr ""
msgid "The URL to use for connecting to Elasticsearch. Use a comma-separated list to support clustering (e.g., \"http://localhost:9200, http://localhost:9201\")."
msgstr ""
-msgid "The Web IDE offers advanced syntax highlighting capabilities and more."
-msgstr ""
-
msgid "The X509 Certificate to use when mutual TLS is required to communicate with the external authorization service. If left blank, the server certificate is still validated when accessing over HTTPS."
msgstr ""
@@ -24676,6 +25549,9 @@ msgstr ""
msgid "The form contains the following error:"
msgstr ""
+msgid "The form contains the following warning:"
+msgstr ""
+
msgid "The global settings require you to enable Two-Factor Authentication for your account."
msgstr ""
@@ -24790,9 +25666,6 @@ msgstr ""
msgid "The private key to use when a client certificate is provided. This value is encrypted at rest."
msgstr ""
-msgid "The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The project can be accessed by any logged in user."
msgstr ""
@@ -24829,7 +25702,7 @@ msgstr ""
msgid "The remote repository is being updated..."
msgstr ""
-msgid "The repository can be commited to, and issues, comments and other entities can be created."
+msgid "The repository can be committed to, and issues, comments and other entities can be created."
msgstr ""
msgid "The repository for this project does not exist."
@@ -24883,9 +25756,6 @@ msgstr ""
msgid "The time taken by each data entry gathered by that stage."
msgstr ""
-msgid "The total stage shows the time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The update action will time out after %{number_of_minutes} minutes. For big repositories, use a clone/push combination."
msgstr ""
@@ -24949,6 +25819,9 @@ msgstr ""
msgid "There are no archived requirements"
msgstr ""
+msgid "There are no archived test cases"
+msgstr ""
+
msgid "There are no changes"
msgstr ""
@@ -24988,6 +25861,9 @@ msgstr ""
msgid "There are no open requirements"
msgstr ""
+msgid "There are no open test cases"
+msgstr ""
+
msgid "There are no packages yet"
msgstr ""
@@ -25000,6 +25876,9 @@ msgstr ""
msgid "There is a limit of %{ci_project_subscriptions_limit} subscriptions from or to a project."
msgstr ""
+msgid "There is already a To-Do for this design."
+msgstr ""
+
msgid "There is already a repository with that name on disk"
msgstr ""
@@ -25018,6 +25897,9 @@ msgstr ""
msgid "There was a problem communicating with your device."
msgstr ""
+msgid "There was a problem fetching branches."
+msgstr ""
+
msgid "There was a problem fetching groups."
msgstr ""
@@ -25246,9 +26128,15 @@ msgstr ""
msgid "This action can lead to data loss. To prevent accidental actions we ask you to confirm your intention."
msgstr ""
+msgid "This action cannot be undone, and will permanently delete the %{key} SSH key"
+msgstr ""
+
msgid "This action cannot be undone. You will lose the project's repository and all content: issues, merge requests, etc."
msgstr ""
+msgid "This action has been performed too many times. Try again later."
+msgstr ""
+
msgid "This action will %{strongOpen}permanently delete%{strongClose} %{codeOpen}%{project}%{codeClose} %{strongOpen}immediately%{strongClose}, including its repositories and all content: issues, merge requests, etc."
msgstr ""
@@ -25276,9 +26164,6 @@ msgstr ""
msgid "This board's scope is reduced"
msgstr ""
-msgid "This branch has changed since you started editing. Would you like to create a new branch?"
-msgstr ""
-
msgid "This chart could not be displayed"
msgstr ""
@@ -25405,15 +26290,9 @@ msgstr ""
msgid "This is a security log of important events involving your account."
msgstr ""
-msgid "This is the author's first Merge Request to this project."
-msgstr ""
-
msgid "This is the highest peak of users on your installation since the license started."
msgstr ""
-msgid "This is the maximum number of users that have existed at the same time since the license started. This is the minimum number of seats you will need to buy when you renew your license."
-msgstr ""
-
msgid "This is the number of currently active users on your installation, and this is the minimum number you need to purchase when you renew your license."
msgstr ""
@@ -25645,6 +26524,15 @@ msgstr ""
msgid "This user has no identities"
msgstr ""
+msgid "This user has previously committed to the %{name} project."
+msgstr ""
+
+msgid "This user has the %{access} role in the %{name} project."
+msgstr ""
+
+msgid "This user is the author of this %{noteable}."
+msgstr ""
+
msgid "This user will be the author of all events in the activity feed that are the result of an update, like new branches being created or new commits being pushed to existing branches."
msgstr ""
@@ -25675,6 +26563,9 @@ msgstr ""
msgid "Threat Monitoring"
msgstr ""
+msgid "ThreatMonitoring|All Environments"
+msgstr ""
+
msgid "ThreatMonitoring|Anomalous Requests"
msgstr ""
@@ -25702,9 +26593,6 @@ msgstr ""
msgid "ThreatMonitoring|Operations Per Second"
msgstr ""
-msgid "ThreatMonitoring|Overview"
-msgstr ""
-
msgid "ThreatMonitoring|Packet Activity"
msgstr ""
@@ -25723,6 +26611,9 @@ msgstr ""
msgid "ThreatMonitoring|Something went wrong, unable to fetch statistics"
msgstr ""
+msgid "ThreatMonitoring|Statistics"
+msgstr ""
+
msgid "ThreatMonitoring|The firewall is not installed or has been disabled. To view this data, ensure the web application firewall is installed and enabled for your cluster."
msgstr ""
@@ -26114,6 +27005,9 @@ msgstr ""
msgid "To update Snippets with multiple files, you must use the `files` parameter"
msgstr ""
+msgid "To use Gitpod you must first enable the feature in the integrations section of your %{user_prefs}."
+msgstr ""
+
msgid "To view all %{scannedResourcesCount} scanned URLs, please download the CSV file"
msgstr ""
@@ -26147,9 +27041,6 @@ msgstr ""
msgid "Toggle Sidebar"
msgstr ""
-msgid "Toggle all threads"
-msgstr ""
-
msgid "Toggle backtrace"
msgstr ""
@@ -26174,9 +27065,6 @@ msgstr ""
msgid "Toggle navigation"
msgstr ""
-msgid "Toggle project"
-msgstr ""
-
msgid "Toggle sidebar"
msgstr ""
@@ -26216,6 +27104,9 @@ msgstr ""
msgid "Too many projects enabled. You will need to manage them via the console or the API."
msgstr ""
+msgid "Too much data"
+msgstr ""
+
msgid "Topics (optional)"
msgstr ""
@@ -26234,6 +27125,9 @@ msgstr ""
msgid "Total cores (CPUs)"
msgstr ""
+msgid "Total days to completion"
+msgstr ""
+
msgid "Total issues"
msgstr ""
@@ -26330,6 +27224,9 @@ msgstr ""
msgid "Trending"
msgstr ""
+msgid "Trials|Create a new group to start your GitLab Gold trial."
+msgstr ""
+
msgid "Trials|Go back to GitLab"
msgstr ""
@@ -26339,6 +27236,15 @@ msgstr ""
msgid "Trials|You can always resume this process by selecting your avatar and choosing 'Start a Gold trial'"
msgstr ""
+msgid "Trials|You can apply your trial to a new group or an existing group."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group or your personal account."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group, an existing group, or your personal account."
+msgstr ""
+
msgid "Trials|You won't get a free trial right now but you can always resume this process by clicking on your avatar and choosing 'Start a free trial'"
msgstr ""
@@ -26408,6 +27314,9 @@ msgstr ""
msgid "Try using a different search term to find the file you are looking for."
msgstr ""
+msgid "Trying to communicate with your device. Plug it in (if needed) and press the button on the device now."
+msgstr ""
+
msgid "Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now."
msgstr ""
@@ -26495,6 +27404,12 @@ msgstr ""
msgid "URL or request ID"
msgstr ""
+msgid "USER %{user} WILL BE REMOVED! Are you sure?"
+msgstr ""
+
+msgid "USER WILL BE BLOCKED! Are you sure?"
+msgstr ""
+
msgid "UTC"
msgstr ""
@@ -26552,9 +27467,6 @@ msgstr ""
msgid "Unable to load the merge request widget. Try reloading the page."
msgstr ""
-msgid "Unable to resolve"
-msgstr ""
-
msgid "Unable to save iteration. Please try again"
msgstr ""
@@ -26603,6 +27515,9 @@ msgstr ""
msgid "Undo ignore"
msgstr ""
+msgid "Unexpected error"
+msgstr ""
+
msgid "Unfortunately, your email message to GitLab could not be processed."
msgstr ""
@@ -26636,6 +27551,9 @@ msgstr ""
msgid "Unknown response text"
msgstr ""
+msgid "Unless otherwise agreed to in writing with GitLab, by clicking \"Upload License\" you agree that your use of GitLab Software is subject to the %{eula_link_start}Terms of Service%{eula_link_end}."
+msgstr ""
+
msgid "Unlimited"
msgstr ""
@@ -27002,9 +27920,6 @@ msgstr ""
msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
msgstr ""
-msgid "Use a hardware device to add the second factor of authentication."
-msgstr ""
-
msgid "Use an one time password authenticator on your mobile device or computer to enable two-factor authentication (2FA)."
msgstr ""
@@ -27278,13 +28193,13 @@ msgstr ""
msgid "Users"
msgstr ""
-msgid "Users in License:"
+msgid "Users in License"
msgstr ""
-msgid "Users or groups set as approvers in the project's or merge request's settings."
+msgid "Users in License:"
msgstr ""
-msgid "Users outside of license"
+msgid "Users or groups set as approvers in the project's or merge request's settings."
msgstr ""
msgid "Users over License:"
@@ -27302,9 +28217,6 @@ msgstr ""
msgid "Users with a Guest role or those who don't belong to a Project or Group will not use a seat from your license."
msgstr ""
-msgid "Users with a Guest role or those who don't belong to any projects or groups don't count towards seats in use."
-msgstr ""
-
msgid "UsersSelect|%{name} + %{length} more"
msgstr ""
@@ -27344,9 +28256,6 @@ msgstr ""
msgid "Validations failed."
msgstr ""
-msgid "Validity"
-msgstr ""
-
msgid "Value"
msgstr ""
@@ -27365,6 +28274,9 @@ msgstr ""
msgid "Value Stream Name"
msgstr ""
+msgid "ValueStreamAnalyticsStage|We don't have enough data to show this stage."
+msgstr ""
+
msgid "ValueStreamAnalytics|%{days}d"
msgstr ""
@@ -27621,6 +28533,9 @@ msgstr ""
msgid "VisualReviewApp|Steps 1 and 2 (and sometimes 3) are performed once by the developer before requesting feedback. Steps 3 (if necessary), 4 is performed by the reviewer each time they perform a review."
msgstr ""
+msgid "Visualization"
+msgstr ""
+
msgid "Vulnerabilities"
msgstr ""
@@ -27648,34 +28563,31 @@ msgstr ""
msgid "VulnerabilityChart|Severity"
msgstr ""
-msgid "VulnerabilityManagement|A true-positive and will fix"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Change status"
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|Confirm"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Confirmed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
-msgstr ""
-
-msgid "VulnerabilityManagement|Detected %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|A true-positive and will fix"
msgstr ""
-msgid "VulnerabilityManagement|Dismiss"
+msgid "VulnerabilityManagement|Change status"
msgstr ""
-msgid "VulnerabilityManagement|Dismissed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
msgstr ""
-msgid "VulnerabilityManagement|Resolved"
+msgid "VulnerabilityManagement|Detected"
msgstr ""
-msgid "VulnerabilityManagement|Resolved %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Needs triage"
msgstr ""
msgid "VulnerabilityManagement|Something went wrong while trying to delete the comment. Please try again later."
@@ -27726,6 +28638,9 @@ msgstr ""
msgid "Vulnerability|%{scannerName} (version %{scannerVersion})"
msgstr ""
+msgid "Vulnerability|Activity"
+msgstr ""
+
msgid "Vulnerability|Class"
msgstr ""
@@ -27738,6 +28653,9 @@ msgstr ""
msgid "Vulnerability|Description"
msgstr ""
+msgid "Vulnerability|Detected"
+msgstr ""
+
msgid "Vulnerability|Evidence"
msgstr ""
@@ -27801,6 +28719,9 @@ msgstr ""
msgid "Warning: Displaying this diagram might cause performance issues on this page."
msgstr ""
+msgid "We are currently unable to fetch data for the pipeline header."
+msgstr ""
+
msgid "We are currently unable to fetch data for this graph."
msgstr ""
@@ -27840,6 +28761,12 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
+msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
+msgstr ""
+
+msgid "We would like to inform you that your subscription GitLab Enterprise Edition %{plan_name} is nearing its user limit. You have %{active_user_count} active users, which is almost at the user limit of %{maximum_user_count}."
+msgstr ""
+
msgid "We've found no vulnerabilities"
msgstr ""
@@ -27855,6 +28782,12 @@ msgstr ""
msgid "Web terminal"
msgstr ""
+msgid "WebAuthn Devices (%{length})"
+msgstr ""
+
+msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
+msgstr ""
+
msgid "WebIDE|Merge request"
msgstr ""
@@ -27993,15 +28926,9 @@ msgstr ""
msgid "Welcome to the guided GitLab tour"
msgstr ""
-msgid "Welcome to your Issue Board!"
-msgstr ""
-
msgid "Welcome to your issue board!"
msgstr ""
-msgid "We’ve been making changes to %{featureName} and we’d love your feedback %{linkStart}in this issue%{linkEnd} to help us improve the experience."
-msgstr ""
-
msgid "What are you searching for?"
msgstr ""
@@ -28020,6 +28947,9 @@ msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
msgstr ""
+msgid "When enabled, any user visiting %{host} and creating an account will have to be explicitly approved by the admin before they can login. This setting is effective only if sign-ups are enabled."
+msgstr ""
+
msgid "When enabled, any user visiting %{host} will be able to create an account."
msgstr ""
@@ -28244,6 +29174,9 @@ msgstr ""
msgid "With requirements, you can set criteria to check your products against."
msgstr ""
+msgid "With test cases, you can define conditions for your project to meet in determining quality"
+msgstr ""
+
msgid "Withdraw Access Request"
msgstr ""
@@ -28259,6 +29192,9 @@ msgstr ""
msgid "Workflow Help"
msgstr ""
+msgid "Would you like to create a new branch?"
+msgstr ""
+
msgid "Write"
msgstr ""
@@ -28280,6 +29216,9 @@ msgstr ""
msgid "Wrong extern UID provided. Make sure Auth0 is configured correctly."
msgstr ""
+msgid "YYYY-MM-DD"
+msgstr ""
+
msgid "Yes"
msgstr ""
@@ -28337,7 +29276,7 @@ msgstr ""
msgid "You are going to remove the fork relationship from %{project_full_name}. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "You are going to transfer %{project_full_name} to another owner. Are you ABSOLUTELY sure?"
+msgid "You are going to transfer %{project_full_name} to another namespace. Are you ABSOLUTELY sure?"
msgstr ""
msgid "You are going to turn off the confidentiality. This means %{strongStart}everyone%{strongEnd} will be able to see and leave a comment on this %{issuableType}."
@@ -28397,9 +29336,6 @@ msgstr ""
msgid "You can always edit this later"
msgstr ""
-msgid "You can apply your Trial to your Personal account or create a New Group."
-msgstr ""
-
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings"
msgstr ""
@@ -28421,12 +29357,18 @@ msgstr ""
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
+msgid "You can find more information about GitLab subscriptions in %{subscriptions_doc_link}."
+msgstr ""
+
msgid "You can generate an access token scoped to this project for each application to use the GitLab API."
msgstr ""
msgid "You can get started by cloning the repository or start adding files to it with one of the following options."
msgstr ""
+msgid "You can group test cases using labels. To learn about the future direction of this feature, visit %{linkStart}Quality Management direction page%{linkEnd}."
+msgstr ""
+
msgid "You can invite a new member to %{project_name} or invite another group."
msgstr ""
@@ -28442,6 +29384,9 @@ msgstr ""
msgid "You can notify the app / group or a project by sending them an email notification"
msgstr ""
+msgid "You can now close this window."
+msgstr ""
+
msgid "You can now export your security dashboard to a CSV report."
msgstr ""
@@ -28490,9 +29435,6 @@ msgstr ""
msgid "You can test your .gitlab-ci.yml in %{linkStart}CI Lint%{linkEnd}."
msgstr ""
-msgid "You can try again using %{begin_link}basic search%{end_link}"
-msgstr ""
-
msgid "You cannot access the raw file. Please wait a minute."
msgstr ""
@@ -28544,6 +29486,9 @@ msgstr ""
msgid "You don't have any U2F devices registered yet."
msgstr ""
+msgid "You don't have any WebAuthn devices registered yet."
+msgstr ""
+
msgid "You don't have any active chat names."
msgstr ""
@@ -28631,6 +29576,9 @@ msgstr ""
msgid "You must accept our Terms of Service and privacy policy in order to register an account"
msgstr ""
+msgid "You must be logged in to search across all of GitLab"
+msgstr ""
+
msgid "You must disassociate %{domain} from all clusters it is attached to before deletion."
msgstr ""
@@ -28670,7 +29618,7 @@ msgstr ""
msgid "You need to be logged in."
msgstr ""
-msgid "You need to register a two-factor authentication app before you can set up a U2F device."
+msgid "You need to register a two-factor authentication app before you can set up a device."
msgstr ""
msgid "You need to set terms to be enforced"
@@ -28688,6 +29636,9 @@ msgstr ""
msgid "You reached %{usage_in_percent} of %{namespace_name}'s storage capacity (%{used_storage} of %{storage_limit})"
msgstr ""
+msgid "You successfully declined the invitation"
+msgstr ""
+
msgid "You tried to fork %{link_to_the_project} but it failed for the following reason:"
msgstr ""
@@ -28853,10 +29804,13 @@ msgstr ""
msgid "Your U2F device did not send a valid JSON response."
msgstr ""
-msgid "Your U2F device needs to be set up. Plug it in (if not already) and click the button on the left."
+msgid "Your U2F device was registered!"
msgstr ""
-msgid "Your U2F device was registered!"
+msgid "Your WebAuthn device did not send a valid JSON response."
+msgstr ""
+
+msgid "Your WebAuthn device was registered!"
msgstr ""
msgid "Your access request to the %{source_type} has been withdrawn."
@@ -28880,6 +29834,9 @@ msgstr ""
msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
msgstr ""
+msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
+msgstr ""
+
msgid "Your changes can be committed to %{branch_name} because a merge request is open."
msgstr ""
@@ -28916,6 +29873,12 @@ msgstr ""
msgid "Your deployment services will be broken, you will need to manually fix the services after renaming."
msgstr ""
+msgid "Your device is not compatible with GitLab. Please try another device"
+msgstr ""
+
+msgid "Your device needs to be set up. Plug it in (if needed) and click the button on the left."
+msgstr ""
+
msgid "Your device was successfully set up! Give it a name and register it with the GitLab server."
msgstr ""
@@ -29029,9 +29992,6 @@ msgstr[1] ""
msgid "access:"
msgstr ""
-msgid "activated"
-msgstr ""
-
msgid "added %{created_at_timeago}"
msgstr ""
@@ -29104,9 +30064,21 @@ msgstr ""
msgid "by %{user}"
msgstr ""
+msgid "cannot be a date in the past"
+msgstr ""
+
msgid "cannot be changed if a personal project has container registry tags."
msgstr ""
+msgid "cannot be changed if shared runners are enabled"
+msgstr ""
+
+msgid "cannot be enabled because parent group does not allow it"
+msgstr ""
+
+msgid "cannot be enabled because parent group has shared Runners disabled"
+msgstr ""
+
msgid "cannot be enabled unless all domains have TLS certificates"
msgstr ""
@@ -29152,7 +30124,7 @@ msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about SAST %{linkEndTag}"
msgstr ""
-msgid "ciReport|%{linkStartTag}Learn more about Secret Scanning %{linkEndTag}"
+msgid "ciReport|%{linkStartTag}Learn more about Secret Detection %{linkEndTag}"
msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about codequality reports %{linkEndTag}"
@@ -29467,9 +30439,6 @@ msgstr ""
msgid "error"
msgstr ""
-msgid "error code:"
-msgstr ""
-
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr ""
@@ -29491,6 +30460,9 @@ msgstr ""
msgid "failed to dismiss associated finding(id=%{finding_id}): %{message}"
msgstr ""
+msgid "failed to revert associated finding(id=%{finding_id}) to detected"
+msgstr ""
+
msgid "file"
msgid_plural "files"
msgstr[0] ""
@@ -30033,6 +31005,9 @@ msgstr ""
msgid "must be a root namespace"
msgstr ""
+msgid "must be a valid IPv4 or IPv6 address"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -30069,6 +31044,9 @@ msgstr ""
msgid "no expiration"
msgstr ""
+msgid "no name set"
+msgstr ""
+
msgid "no one can merge"
msgstr ""
@@ -30247,9 +31225,6 @@ msgstr ""
msgid "security Reports|There was an error creating the merge request"
msgstr ""
-msgid "settings saved, but not activated"
-msgstr ""
-
msgid "severity|Critical"
msgstr ""
@@ -30376,9 +31351,6 @@ msgstr ""
msgid "toggle collapse"
msgstr ""
-msgid "toggle dropdown"
-msgstr ""
-
msgid "triggered"
msgstr ""
@@ -30406,6 +31378,9 @@ msgstr ""
msgid "user avatar"
msgstr ""
+msgid "user preferences"
+msgstr ""
+
msgid "username"
msgstr ""
diff --git a/locale/bs_BA/gitlab.po b/locale/bs_BA/gitlab.po
index cfa8b24e732..69e80843023 100644
--- a/locale/bs_BA/gitlab.po
+++ b/locale/bs_BA/gitlab.po
@@ -14,7 +14,10 @@ msgstr ""
"X-Crowdin-Language: bs\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 6\n"
-"PO-Revision-Date: 2020-09-04 23:04\n"
+"PO-Revision-Date: 2020-10-02 18:43\n"
+
+msgid " %{project_name}#%{issue_iid} &middot; opened %{issue_created} by %{author}"
+msgstr ""
msgid " %{start} to %{end}"
msgstr ""
@@ -76,6 +79,18 @@ msgstr ""
msgid "\"el\" parameter is required for createInstance()"
msgstr ""
+msgid "%d Approval"
+msgid_plural "%d Approvals"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
+msgid "%d Package"
+msgid_plural "%d Packages"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "%d Scanned URL"
msgid_plural "%d Scanned URLs"
msgstr[0] ""
@@ -151,6 +166,12 @@ msgstr[2] ""
msgid "%d commits"
msgstr ""
+msgid "%d completed issue"
+msgid_plural "%d completed issues"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "%d contribution"
msgid_plural "%d contributions"
msgstr[0] ""
@@ -163,6 +184,12 @@ msgstr[0] "%d dan"
msgstr[1] "%d dana"
msgstr[2] "%d dana"
+msgid "%d day until tags are automatically removed"
+msgid_plural "%d days until tags are automatically removed"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "%d error"
msgid_plural "%d errors"
msgstr[0] ""
@@ -271,6 +298,18 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgid "%d open issue"
+msgid_plural "%d open issues"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
+msgid "%d pending comment"
+msgid_plural "%d pending comments"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "%d personal project will be removed and cannot be restored."
msgid_plural "%d personal projects will be removed and cannot be restored."
msgstr[0] ""
@@ -289,6 +328,12 @@ msgstr[0] "%d projekat"
msgstr[1] "%d projekta"
msgstr[2] "%d projekata"
+msgid "%d project selected"
+msgid_plural "%d projects selected"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "%d request with warnings"
msgid_plural "%d requests with warnings"
msgstr[0] ""
@@ -313,6 +358,12 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgid "%d tag per image name"
+msgid_plural "%d tags per image name"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "%d unassigned issue"
msgid_plural "%d unassigned issues"
msgstr[0] ""
@@ -337,6 +388,12 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgid "%d warning found:"
+msgid_plural "%d warnings found:"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "%s additional commit has been omitted to prevent performance issues."
msgid_plural "%s additional commits have been omitted to prevent performance issues."
msgstr[0] ""
@@ -376,6 +433,9 @@ msgstr ""
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr ""
+msgid "%{completedCount} completed weight"
+msgstr ""
+
msgid "%{completedWeight} of %{totalWeight} weight completed"
msgstr ""
@@ -427,15 +487,12 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
-msgid "%{count} pending comment"
-msgid_plural "%{count} pending comments"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
+msgid "%{count} total weight"
+msgstr ""
+
msgid "%{dashboard_path} could not be found."
msgstr ""
@@ -490,6 +547,9 @@ msgstr ""
msgid "%{group_name} uses group managed accounts. You need to create a new GitLab account which will be managed by %{group_name}."
msgstr ""
+msgid "%{group_name}&%{epic_iid} &middot; opened %{epic_created} by %{author}"
+msgstr ""
+
msgid "%{host} sign-in from new location"
msgstr ""
@@ -502,7 +562,7 @@ msgstr ""
msgid "%{issuableType} will be removed! Are you sure?"
msgstr ""
-msgid "%{issuesSize} issues with a limit of %{maxIssueCount}"
+msgid "%{issuesCount} issues with a limit of %{maxIssueCount}"
msgstr ""
msgid "%{issuesSize} with a limit of %{maxIssueCount}"
@@ -535,7 +595,7 @@ msgstr ""
msgid "%{labelStart}Namespace:%{labelEnd} %{namespace}"
msgstr ""
-msgid "%{labelStart}Report Type:%{labelEnd} %{reportType}"
+msgid "%{labelStart}Scan Type:%{labelEnd} %{reportType}"
msgstr ""
msgid "%{labelStart}Scanner:%{labelEnd} %{scanner}"
@@ -739,9 +799,6 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
-msgid "%{service_title} %{message}."
-msgstr ""
-
msgid "%{size} GiB"
msgstr ""
@@ -835,6 +892,12 @@ msgstr ""
msgid "%{timebox_name} should belong either to a project or a group."
msgstr ""
+msgid "%{timebox_type} does not support burnup charts"
+msgstr ""
+
+msgid "%{timebox_type} must have a start and due date"
+msgstr ""
+
msgid "%{title} %{operator} %{threshold}"
msgstr ""
@@ -859,7 +922,7 @@ msgstr ""
msgid "%{total} open issue weight"
msgstr ""
-msgid "%{total} open issues"
+msgid "%{total} warnings found: showing first %{warningsDisplayed}"
msgstr ""
msgid "%{usage_ping_link_start}Learn more%{usage_ping_link_end} about what information is shared with GitLab Inc."
@@ -892,9 +955,6 @@ msgstr ""
msgid "&lt; 1 hour"
msgstr ""
-msgid "&lt;no name set&gt;"
-msgstr ""
-
msgid "&lt;no scopes selected&gt;"
msgstr ""
@@ -925,6 +985,9 @@ msgstr ""
msgid "'%{name}' Value Stream created"
msgstr ""
+msgid "'%{name}' Value Stream deleted"
+msgstr ""
+
msgid "'%{name}' stage already exists"
msgstr ""
@@ -985,6 +1048,9 @@ msgstr ""
msgid "+ %{numberOfHiddenAssignees} more"
msgstr ""
+msgid "+ %{numberOfHiddenReviewers} more"
+msgstr ""
+
msgid "+%d more"
msgid_plural "+%d more"
msgstr[0] ""
@@ -1051,6 +1117,12 @@ msgstr[0] "1 dan"
msgstr[1] "%d dana"
msgstr[2] "%d dana"
+msgid "1 Issue"
+msgid_plural "%d Issues"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "1 closed issue"
msgid_plural "%{issues} closed issues"
msgstr[0] ""
@@ -1069,6 +1141,12 @@ msgstr[0] "1 dan"
msgstr[1] "%d dana"
msgstr[2] "%d dana"
+msgid "1 deploy key"
+msgid_plural "%d deploy keys"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1180,6 +1258,9 @@ msgstr ""
msgid ":%{startLine} to %{endLine}"
msgstr ""
+msgid "A %{incident_docs_start}modified issue%{incident_docs_end} to guide the resolution of incidents."
+msgstr ""
+
msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr ""
@@ -1192,6 +1273,9 @@ msgstr ""
msgid "A GitBook site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
+msgid "A Gitpod configured Webapplication in Spring and Java"
+msgstr ""
+
msgid "A Hexo site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
@@ -1363,9 +1447,15 @@ msgstr ""
msgid "Access expiration date"
msgstr ""
+msgid "Access expires"
+msgstr ""
+
msgid "Access forbidden. Check your access level."
msgstr ""
+msgid "Access granted"
+msgstr ""
+
msgid "Access requests"
msgstr ""
@@ -1375,6 +1465,9 @@ msgstr ""
msgid "Access to Pages websites are controlled based on the user's membership to a given project. By checking this box, users will be required to be logged in to have access to all Pages websites in your instance."
msgstr ""
+msgid "AccessDropdown|Deploy Keys"
+msgstr ""
+
msgid "AccessDropdown|Groups"
msgstr ""
@@ -1492,12 +1585,6 @@ msgstr ""
msgid "Active Sessions"
msgstr ""
-msgid "Active Users:"
-msgstr ""
-
-msgid "Active users"
-msgstr ""
-
msgid "Activity"
msgstr ""
@@ -1666,9 +1753,6 @@ msgstr ""
msgid "Add label(s)"
msgstr ""
-msgid "Add license"
-msgstr ""
-
msgid "Add list"
msgstr ""
@@ -1843,21 +1927,51 @@ msgstr ""
msgid "AdminArea|Bots"
msgstr ""
+msgid "AdminArea|Components"
+msgstr ""
+
msgid "AdminArea|Developer"
msgstr ""
+msgid "AdminArea|Features"
+msgstr ""
+
+msgid "AdminArea|Groups: %{number_of_groups}"
+msgstr ""
+
msgid "AdminArea|Guest"
msgstr ""
msgid "AdminArea|Included Free in license"
msgstr ""
+msgid "AdminArea|Latest groups"
+msgstr ""
+
+msgid "AdminArea|Latest projects"
+msgstr ""
+
+msgid "AdminArea|Latest users"
+msgstr ""
+
msgid "AdminArea|Maintainer"
msgstr ""
+msgid "AdminArea|New group"
+msgstr ""
+
+msgid "AdminArea|New project"
+msgstr ""
+
+msgid "AdminArea|New user"
+msgstr ""
+
msgid "AdminArea|Owner"
msgstr ""
+msgid "AdminArea|Projects: %{number_of_projects}"
+msgstr ""
+
msgid "AdminArea|Reporter"
msgstr ""
@@ -1885,6 +1999,9 @@ msgstr ""
msgid "AdminArea|Users without a Group and Project"
msgstr ""
+msgid "AdminArea|Users: %{number_of_users}"
+msgstr ""
+
msgid "AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running."
msgstr ""
@@ -1903,9 +2020,6 @@ msgstr ""
msgid "AdminProjects|Delete Project %{projectName}?"
msgstr ""
-msgid "AdminProjects|Delete project"
-msgstr ""
-
msgid "AdminSettings|Apply integration settings to all Projects"
msgstr ""
@@ -2143,21 +2257,30 @@ msgstr ""
msgid "AdminUsers|Without projects"
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 ""
msgid "AdminUsers|You cannot remove your own admin rights."
msgstr ""
+msgid "AdminUsers|You must transfer ownership or delete the groups owned by this user before you can delete their account"
+msgstr ""
+
msgid "Administration"
msgstr ""
msgid "Advanced"
msgstr ""
+msgid "Advanced Search"
+msgstr ""
+
+msgid "Advanced Search with Elasticsearch"
+msgstr ""
+
msgid "Advanced Settings"
msgstr ""
@@ -2236,6 +2359,9 @@ msgstr ""
msgid "AlertManagement|Edit"
msgstr ""
+msgid "AlertManagement|Environment"
+msgstr ""
+
msgid "AlertManagement|Events"
msgstr ""
@@ -2248,6 +2374,9 @@ msgstr ""
msgid "AlertManagement|Issue"
msgstr ""
+msgid "AlertManagement|Key"
+msgstr ""
+
msgid "AlertManagement|Low"
msgstr ""
@@ -2341,6 +2470,9 @@ msgstr ""
msgid "AlertManagement|Unknown"
msgstr ""
+msgid "AlertManagement|Value"
+msgstr ""
+
msgid "AlertManagement|View alerts in Opsgenie"
msgstr ""
@@ -2500,6 +2632,9 @@ msgstr ""
msgid "All projects"
msgstr "Svi projekti"
+msgid "All projects selected"
+msgstr ""
+
msgid "All security scans are enabled because %{linkStart}Auto DevOps%{linkEnd} is enabled on this project"
msgstr ""
@@ -2587,6 +2722,9 @@ msgstr ""
msgid "Almost there"
msgstr ""
+msgid "Already blocked"
+msgstr ""
+
msgid "Also called \"Issuer\" or \"Relying party trust identifier\""
msgstr ""
@@ -2641,6 +2779,9 @@ msgstr ""
msgid "An error has occurred"
msgstr ""
+msgid "An error occured while making the changes: %{error}"
+msgstr ""
+
msgid "An error occurred adding a draft to the thread."
msgstr ""
@@ -2668,12 +2809,6 @@ msgstr ""
msgid "An error occurred when toggling the notification subscription"
msgstr ""
-msgid "An error occurred when trying to resolve a comment. Please try again."
-msgstr ""
-
-msgid "An error occurred when trying to resolve a discussion. Please try again."
-msgstr ""
-
msgid "An error occurred when updating the issue weight"
msgstr ""
@@ -2689,12 +2824,6 @@ msgstr ""
msgid "An error occurred while checking group path. Please refresh and try again."
msgstr ""
-msgid "An error occurred while committing your changes."
-msgstr ""
-
-msgid "An error occurred while creating the list. Please try again."
-msgstr ""
-
msgid "An error occurred while decoding the file."
msgstr ""
@@ -2767,25 +2896,19 @@ msgstr ""
msgid "An error occurred while fetching the Service Desk address."
msgstr ""
-msgid "An error occurred while fetching the board issues. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the board lists. Please reload the page."
msgstr ""
msgid "An error occurred while fetching the board lists. Please try again."
msgstr ""
-msgid "An error occurred while fetching the board swimlanes. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the builds."
msgstr ""
msgid "An error occurred while fetching the job log."
msgstr ""
-msgid "An error occurred while fetching the job trace."
+msgid "An error occurred while fetching the job logs."
msgstr ""
msgid "An error occurred while fetching the job."
@@ -2932,9 +3055,6 @@ msgstr ""
msgid "An error occurred while saving assignees"
msgstr ""
-msgid "An error occurred while saving the template. Please check if the template exists."
-msgstr ""
-
msgid "An error occurred while searching for milestones"
msgstr ""
@@ -2953,10 +3073,10 @@ msgstr ""
msgid "An error occurred while updating approvers"
msgstr ""
-msgid "An error occurred while updating the comment"
+msgid "An error occurred while updating labels."
msgstr ""
-msgid "An error occurred while updating the list. Please try again."
+msgid "An error occurred while updating the comment"
msgstr ""
msgid "An error occurred while validating group path"
@@ -3010,6 +3130,9 @@ msgstr ""
msgid "An unknown error occurred while loading this graph."
msgstr ""
+msgid "An unknown error occurred."
+msgstr ""
+
msgid "Analytics"
msgstr ""
@@ -3043,10 +3166,10 @@ msgstr ""
msgid "Any"
msgstr ""
-msgid "Any Author"
+msgid "Any %{header}"
msgstr ""
-msgid "Any Status"
+msgid "Any Author"
msgstr ""
msgid "Any branch"
@@ -3100,6 +3223,9 @@ msgstr ""
msgid "Application ID"
msgstr ""
+msgid "Application limits saved successfully"
+msgstr ""
+
msgid "Application settings saved successfully"
msgstr ""
@@ -3313,6 +3439,9 @@ msgstr ""
msgid "Are you sure you want to close this blocked issue?"
msgstr ""
+msgid "Are you sure you want to delete \"%{name}\" Value Stream?"
+msgstr ""
+
msgid "Are you sure you want to delete %{name}?"
msgstr ""
@@ -3322,6 +3451,9 @@ msgstr ""
msgid "Are you sure you want to delete this %{typeOfComment}?"
msgstr ""
+msgid "Are you sure you want to delete this SSH key?"
+msgstr ""
+
msgid "Are you sure you want to delete this board?"
msgstr ""
@@ -3346,6 +3478,12 @@ msgstr ""
msgid "Are you sure you want to erase this build?"
msgstr ""
+msgid "Are you sure you want to import %d repository?"
+msgid_plural "Are you sure you want to import %d repositories?"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "Are you sure you want to lose unsaved changes?"
msgstr ""
@@ -3355,15 +3493,15 @@ msgstr ""
msgid "Are you sure you want to merge immediately?"
msgstr ""
-msgid "Are you sure you want to permanently delete this license?"
-msgstr ""
-
msgid "Are you sure you want to re-deploy this environment?"
msgstr ""
msgid "Are you sure you want to regenerate the public key? You will have to update the public key on the remote server before mirroring will work again."
msgstr ""
+msgid "Are you sure you want to reindex?"
+msgstr ""
+
msgid "Are you sure you want to remove %{group_name}?"
msgstr ""
@@ -3391,6 +3529,9 @@ msgstr ""
msgid "Are you sure you want to revoke this nickname?"
msgstr ""
+msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
+msgstr ""
+
msgid "Are you sure you want to stop this environment?"
msgstr ""
@@ -3412,6 +3553,9 @@ msgstr ""
msgid "Are you sure? The device will be signed out of GitLab and all remember me tokens revoked."
msgstr ""
+msgid "Are you sure? This will invalidate your registered applications and U2F / WebAuthn devices."
+msgstr ""
+
msgid "Are you sure? This will invalidate your registered applications and U2F devices."
msgstr ""
@@ -3430,9 +3574,6 @@ msgstr ""
msgid "Artifacts"
msgstr ""
-msgid "As U2F devices are only supported by a few browsers, we require that you set up a two-factor authentication app before a U2F device. That way you'll always be able to log in - even when you're using an unsupported browser."
-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 ""
@@ -3628,6 +3769,9 @@ msgstr ""
msgid "AuditLogs|Target"
msgstr ""
+msgid "AuditLogs|This month"
+msgstr ""
+
msgid "AuditLogs|User Events"
msgstr ""
@@ -3667,6 +3811,9 @@ msgstr ""
msgid "Authentication via U2F device failed."
msgstr ""
+msgid "Authentication via WebAuthn device failed."
+msgstr ""
+
msgid "Author"
msgstr ""
@@ -3934,15 +4081,6 @@ msgstr ""
msgid "BambooService|You must set up automatic revision labeling and a repository trigger in Bamboo."
msgstr ""
-msgid "BatchComments|Delete all pending comments"
-msgstr ""
-
-msgid "BatchComments|Discard review?"
-msgstr ""
-
-msgid "BatchComments|You're about to discard your review which will delete all of your pending comments. The deleted comments %{strong_start}cannot%{strong_end} be restored."
-msgstr ""
-
msgid "Be careful. Changing the project's namespace can have unintended side effects."
msgstr ""
@@ -3964,6 +4102,9 @@ msgstr ""
msgid "Bi-weekly code coverage"
msgstr ""
+msgid "Billable Users:"
+msgstr ""
+
msgid "Billing"
msgstr "Naplata"
@@ -3973,7 +4114,7 @@ msgstr ""
msgid "BillingPlans|@%{user_name} you are currently using the %{plan_name} plan."
msgstr ""
-msgid "BillingPlans|Congratulations, your new trial is activated"
+msgid "BillingPlans|Congratulations, your free trial is activated."
msgstr ""
msgid "BillingPlans|If you would like to downgrade your plan please contact %{support_link_start}Customer Support%{support_link_end}."
@@ -4036,6 +4177,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Block user"
+msgstr ""
+
msgid "Blocked"
msgstr ""
@@ -4051,31 +4195,37 @@ msgstr ""
msgid "Blog"
msgstr ""
-msgid "Board name"
-msgstr ""
-
msgid "Board scope"
msgstr ""
msgid "Board scope affects which issues are displayed for anyone who visits this board"
msgstr ""
-msgid "BoardBlankState|Add default lists"
+msgid "Boards"
msgstr ""
-msgid "BoardBlankState|Add the following default lists to your Issue Board with one click:"
+msgid "Boards and Board Lists"
msgstr ""
-msgid "BoardBlankState|Nevermind, I'll use my own"
+msgid "Boards|An error occurred while creating the issue. Please try again."
msgstr ""
-msgid "BoardBlankState|Starting out with the default set of lists will get you right on the way to making the most of your board."
+msgid "Boards|An error occurred while creating the list. Please try again."
msgstr ""
-msgid "Boards"
+msgid "Boards|An error occurred while fetching issues. Please reload the page."
msgstr ""
-msgid "Boards and Board Lists"
+msgid "Boards|An error occurred while fetching the board issues. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching the board swimlanes. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while moving the issue. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while updating the list. Please try again."
msgstr ""
msgid "Boards|Collapse"
@@ -4102,7 +4252,7 @@ msgstr ""
msgid "Branch %{branch_name} was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr ""
-msgid "Branch has changed"
+msgid "Branch changed"
msgstr ""
msgid "Branch is already taken"
@@ -4408,6 +4558,9 @@ msgstr ""
msgid "CLOSED (MOVED)"
msgstr ""
+msgid "CODEOWNERS rule violation"
+msgstr ""
+
msgid "CONTRIBUTING"
msgstr ""
@@ -4438,9 +4591,6 @@ msgstr ""
msgid "Can't create snippet: %{err}"
msgstr ""
-msgid "Can't edit as source branch was deleted"
-msgstr ""
-
msgid "Can't fetch content for the blob: %{err}"
msgstr ""
@@ -4453,9 +4603,6 @@ msgstr ""
msgid "Can't load mermaid module: %{err}"
msgstr ""
-msgid "Can't remove group members without group managed account"
-msgstr ""
-
msgid "Can't scan the code?"
msgstr ""
@@ -4498,6 +4645,9 @@ msgstr ""
msgid "Cannot create the abuse report. This user has been blocked."
msgstr ""
+msgid "Cannot enable shared runners because parent group does not allow it"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -4603,6 +4753,15 @@ msgstr ""
msgid "Change your password or recover your current one"
msgstr ""
+msgid "ChangeReviewer|Reviewer changed from %{old} to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Reviewer changed to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Unassigned"
+msgstr ""
+
msgid "ChangeTypeActionLabel|Pick into branch"
msgstr ""
@@ -4642,6 +4801,9 @@ msgstr ""
msgid "Changes the title to \"%{title_param}\"."
msgstr ""
+msgid "Changes were successfully made."
+msgstr ""
+
msgid "Changes won't take place until the index is %{link_start}recreated%{link_end}."
msgstr ""
@@ -5047,6 +5209,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove variable"
+msgstr ""
+
msgid "CiVariables|Remove variable row"
msgstr ""
@@ -5125,9 +5290,6 @@ msgstr ""
msgid "Clear due date"
msgstr ""
-msgid "Clear input"
-msgstr ""
-
msgid "Clear recent searches"
msgstr ""
@@ -5176,6 +5338,9 @@ msgstr ""
msgid "Client authentication key password"
msgstr ""
+msgid "Client request timeout"
+msgstr ""
+
msgid "Clients"
msgstr ""
@@ -5260,6 +5425,27 @@ msgstr ""
msgid "Cluster type must be specificed for Stages::ClusterEndpointInserter"
msgstr ""
+msgid "ClusterAgents|Configuration"
+msgstr ""
+
+msgid "ClusterAgents|Connect your cluster with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate Kubernetes with a GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Name"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Agent also requires %{linkStart}enabling the Agent Server%{linkEnd}"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Kubernetes Agent allows an Infrastructure as Code, GitOps approach to integrating Kubernetes clusters with GitLab. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "ClusterAgent|This feature is only available for premium plans"
msgstr ""
@@ -5329,10 +5515,10 @@ msgstr ""
msgid "ClusterIntegration|All installed applications and related resources"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster."
+msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{linkStart}More information%{linkEnd}"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{startLink}More information%{endLink}"
+msgid "ClusterIntegration|Allow GitLab to manage namespaces and service accounts for this cluster."
msgstr ""
msgid "ClusterIntegration|Alternatively, "
@@ -5353,6 +5539,9 @@ msgstr ""
msgid "ClusterIntegration|An error occurred while trying to fetch zone machine types: %{error}"
msgstr ""
+msgid "ClusterIntegration|An unknown error occurred while attempting to connect to Kubernetes."
+msgstr ""
+
msgid "ClusterIntegration|Any project namespaces"
msgstr ""
@@ -5368,6 +5557,9 @@ msgstr ""
msgid "ClusterIntegration|Authenticate with Amazon Web Services"
msgstr ""
+msgid "ClusterIntegration|Authentication Error"
+msgstr ""
+
msgid "ClusterIntegration|Base domain"
msgstr ""
@@ -5386,13 +5578,22 @@ msgstr ""
msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}security group %{externalLinkIcon} %{endLink} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
+msgid "ClusterIntegration|Check your CA certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Check your cluster status"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}subnets %{externalLinkIcon} %{endLink} in your VPC where your worker nodes will run."
+msgid "ClusterIntegration|Check your token"
msgstr ""
-msgid "ClusterIntegration|Choose the worker node %{startLink}instance type %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Choose the %{linkStart}security group %{linkEnd} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
+msgstr ""
+
+msgid "ClusterIntegration|Choose the %{linkStart}subnets %{linkEnd} in your VPC where your worker nodes will run."
+msgstr ""
+
+msgid "ClusterIntegration|Choose the worker node %{linkStart}instance type%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Choose which applications to install on your Kubernetes cluster."
@@ -5404,10 +5605,7 @@ msgstr ""
msgid "ClusterIntegration|Clear cluster cache"
msgstr ""
-msgid "ClusterIntegration|Clear the local cache of namespace and service accounts. This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
-msgstr ""
-
-msgid "ClusterIntegration|Cluster being created"
+msgid "ClusterIntegration|Clear the local cache of namespace and service accounts."
msgstr ""
msgid "ClusterIntegration|Cluster management project (alpha)"
@@ -5419,15 +5617,21 @@ msgstr ""
msgid "ClusterIntegration|Cluster_applications artifact too big. Maximum allowable size: %{human_size}"
msgstr ""
-msgid "ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters."
+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|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}"
+msgid "ClusterIntegration|Clusters connected with a certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Connect cluster with certificate"
msgstr ""
msgid "ClusterIntegration|Connect existing cluster"
msgstr ""
+msgid "ClusterIntegration|Connection Error"
+msgstr ""
+
msgid "ClusterIntegration|Copy API URL"
msgstr ""
@@ -5503,6 +5707,12 @@ msgstr ""
msgid "ClusterIntegration|Deletes all GitLab resources attached to this cluster during removal"
msgstr ""
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared."
+msgstr ""
+
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared. %{linkStart}More information%{linkEnd}"
+msgstr ""
+
msgid "ClusterIntegration|Did you know?"
msgstr ""
@@ -5572,6 +5782,9 @@ msgstr ""
msgid "ClusterIntegration|Fluentd is an open source data collector, which lets you unify the data collection and consumption for a better use and understanding of data. It requires at least one of the following logs to be successfully installed."
msgstr ""
+msgid "ClusterIntegration|GitLab Agent managed clusters"
+msgstr ""
+
msgid "ClusterIntegration|GitLab Container Network Policies"
msgstr ""
@@ -5584,6 +5797,12 @@ msgstr ""
msgid "ClusterIntegration|GitLab Runner connects to the repository and executes CI/CD jobs, pushing results back and deploying applications to production."
msgstr ""
+msgid "ClusterIntegration|GitLab failed to authenticate."
+msgstr ""
+
+msgid "ClusterIntegration|GitLab failed to connect to the cluster."
+msgstr ""
+
msgid "ClusterIntegration|GitLab-managed cluster"
msgstr ""
@@ -5605,6 +5824,9 @@ msgstr ""
msgid "ClusterIntegration|Group cluster"
msgstr ""
+msgid "ClusterIntegration|HTTP Error"
+msgstr ""
+
msgid "ClusterIntegration|Helm Tiller"
msgstr ""
@@ -5638,7 +5860,10 @@ msgstr ""
msgid "ClusterIntegration|Instance type"
msgstr ""
-msgid "ClusterIntegration|Integrate Kubernetes cluster automation"
+msgid "ClusterIntegration|Integrate Kubernetes with a cluster certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Integrate with a cluster certificate"
msgstr ""
msgid "ClusterIntegration|Issuer Email"
@@ -5674,9 +5899,6 @@ msgstr ""
msgid "ClusterIntegration|Knative extends Kubernetes to provide a set of middleware components that are essential to build modern, source-centric, and container-based applications that can run anywhere: on premises, in the cloud, or even in a third-party data center."
msgstr ""
-msgid "ClusterIntegration|Kubernetes cluster"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes cluster is being created..."
msgstr ""
@@ -5689,9 +5911,6 @@ msgstr ""
msgid "ClusterIntegration|Kubernetes clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr ""
-msgid "ClusterIntegration|Kubernetes clusters can be used to deploy applications and to provide Review Apps for this project"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes version"
msgstr ""
@@ -5704,7 +5923,7 @@ msgstr ""
msgid "ClusterIntegration|Learn more about %{help_link_start}zones%{help_link_end}."
msgstr ""
-msgid "ClusterIntegration|Learn more about %{startLink}Regions %{externalLinkIcon}%{endLink}."
+msgid "ClusterIntegration|Learn more about %{linkStart}Regions%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Learn more about Kubernetes"
@@ -5749,12 +5968,18 @@ msgstr ""
msgid "ClusterIntegration|Machine type"
msgstr ""
+msgid "ClusterIntegration|Make sure your API endpoint is correct"
+msgstr ""
+
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create Kubernetes clusters"
msgstr ""
msgid "ClusterIntegration|Manage your Kubernetes cluster by visiting %{provider_link}"
msgstr ""
+msgid "ClusterIntegration|Namespace per environment"
+msgstr ""
+
msgid "ClusterIntegration|No IAM Roles found"
msgstr ""
@@ -5800,6 +6025,9 @@ msgstr ""
msgid "ClusterIntegration|No zones matched your search"
msgstr ""
+msgid "ClusterIntegration|Node calculations use the Kubernetes Metrics API. Make sure your cluster has metrics installed"
+msgstr ""
+
msgid "ClusterIntegration|Number of nodes"
msgstr ""
@@ -5842,6 +6070,9 @@ msgstr ""
msgid "ClusterIntegration|RBAC-enabled cluster"
msgstr ""
+msgid "ClusterIntegration|Read our %{linkStart}help page%{linkEnd} on Kubernetes cluster integration."
+msgstr ""
+
msgid "ClusterIntegration|Read our %{link_start}help page%{link_end} on Kubernetes cluster integration."
msgstr ""
@@ -5944,7 +6175,7 @@ msgstr ""
msgid "ClusterIntegration|Select a VPC to choose a subnet"
msgstr ""
-msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{linkStart}Amazon Web Services %{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select a network to choose a subnetwork"
@@ -5977,7 +6208,7 @@ msgstr ""
msgid "ClusterIntegration|Select project to choose zone"
msgstr ""
-msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select zone"
@@ -6067,9 +6298,18 @@ msgstr ""
msgid "ClusterIntegration|There was a problem authenticating with your cluster. Please ensure your CA Certificate and Token are valid."
msgstr ""
+msgid "ClusterIntegration|There was an HTTP error when connecting to your cluster."
+msgstr ""
+
msgid "ClusterIntegration|This account must have permissions to create a Kubernetes cluster in the %{link_to_container_project} specified below"
msgstr ""
+msgid "ClusterIntegration|This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
+msgstr ""
+
+msgid "ClusterIntegration|This is necessary to clear existing environment-namespace associations from clusters previously managed by GitLab."
+msgstr ""
+
msgid "ClusterIntegration|This option will allow you to install applications on RBAC clusters."
msgstr ""
@@ -6094,9 +6334,21 @@ msgstr ""
msgid "ClusterIntegration|To use a new project, first create one on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}."
msgstr ""
+msgid "ClusterIntegration|Troubleshooting tips:"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Authenticate"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Connect"
+msgstr ""
+
msgid "ClusterIntegration|Uninstall %{appTitle}"
msgstr ""
+msgid "ClusterIntegration|Unknown Error"
+msgstr ""
+
msgid "ClusterIntegration|Update %{appTitle}"
msgstr ""
@@ -6157,7 +6409,7 @@ msgstr ""
msgid "ClusterIntegration|Your cluster API is unreachable. Please ensure your API URL is correct."
msgstr ""
-msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Zone"
@@ -6277,6 +6529,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse all threads"
+msgstr ""
+
msgid "Collapse approvers"
msgstr ""
@@ -6427,7 +6682,7 @@ msgstr ""
msgid "Commit…"
msgstr ""
-msgid "Company"
+msgid "Community forum"
msgstr ""
msgid "Company name"
@@ -6436,6 +6691,9 @@ msgstr ""
msgid "Compare"
msgstr ""
+msgid "Compare %{oldCommitId}...%{newCommitId}"
+msgstr ""
+
msgid "Compare Git revisions"
msgstr ""
@@ -6451,6 +6709,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare submodule commit revisions"
+msgstr ""
+
msgid "Compare with previous version"
msgstr ""
@@ -6586,6 +6847,9 @@ msgstr ""
msgid "Configure the way a user creates a new account."
msgstr ""
+msgid "Configure which lists are shown for anyone who visits this board"
+msgstr ""
+
msgid "Confirm"
msgstr ""
@@ -6814,6 +7078,9 @@ msgstr[2] ""
msgid "ContainerRegistry|Set cleanup policy"
msgstr ""
+msgid "ContainerRegistry|Some tags were not deleted"
+msgstr ""
+
msgid "ContainerRegistry|Something went wrong while fetching the cleanup policy."
msgstr ""
@@ -6853,6 +7120,9 @@ msgstr ""
msgid "ContainerRegistry|Tags with names matching this regex pattern will %{italicStart}expire:%{italicEnd}"
msgstr ""
+msgid "ContainerRegistry|The cleanup policy timed out before it could delete all tags. An administrator can %{adminLinkStart}manually run cleanup now%{adminLinkEnd} or you can wait for the cleanup policy to automatically run again. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "ContainerRegistry|The last tag related to this image was recently removed. This empty image and any associated data will be automatically removed as part of the regular Garbage Collection process. If you have any questions, contact your administrator."
msgstr ""
@@ -6985,6 +7255,9 @@ msgstr ""
msgid "Contributions per group member"
msgstr ""
+msgid "Contributor"
+msgstr ""
+
msgid "Contributors"
msgstr ""
@@ -7114,6 +7387,9 @@ msgstr ""
msgid "Could not change HEAD: branch '%{branch}' does not exist"
msgstr ""
+msgid "Could not commit. An unexpected error occurred."
+msgstr ""
+
msgid "Could not connect to FogBugz, check your URL"
msgstr ""
@@ -7153,6 +7429,9 @@ msgstr ""
msgid "Could not find iteration"
msgstr ""
+msgid "Could not load instance counts. Please refresh the page to try again."
+msgstr ""
+
msgid "Could not remove the trigger."
msgstr ""
@@ -7177,10 +7456,10 @@ msgstr ""
msgid "Could not save prometheus manual configuration"
msgstr ""
-msgid "Could not udpdate wiki page"
+msgid "Could not update the LDAP settings"
msgstr ""
-msgid "Could not update the LDAP settings"
+msgid "Could not update wiki page"
msgstr ""
msgid "Could not upload your designs as one or more files uploaded are not supported."
@@ -7840,6 +8119,9 @@ msgstr ""
msgid "DastProfiles|Are you sure you want to delete this profile?"
msgstr ""
+msgid "DastProfiles|Could not create site validation token. Please refresh the page, or try again later."
+msgstr ""
+
msgid "DastProfiles|Could not create the scanner profile. Please try again."
msgstr ""
@@ -7864,6 +8146,12 @@ msgstr ""
msgid "DastProfiles|Could not fetch site profiles. Please refresh the page, or try again later."
msgstr ""
+msgid "DastProfiles|Could not retrieve site validation status. Please refresh the page, or try again later."
+msgstr ""
+
+msgid "DastProfiles|Could not update the scanner profile. Please try again."
+msgstr ""
+
msgid "DastProfiles|Could not update the site profile. Please try again."
msgstr ""
@@ -7879,7 +8167,7 @@ msgstr ""
msgid "DastProfiles|Download validation text file"
msgstr ""
-msgid "DastProfiles|Edit feature will come soon. Please create a new profile if changes needed"
+msgid "DastProfiles|Edit scanner profile"
msgstr ""
msgid "DastProfiles|Edit site profile"
@@ -7912,6 +8200,9 @@ msgstr ""
msgid "DastProfiles|No profiles created yet"
msgstr ""
+msgid "DastProfiles|Passive"
+msgstr ""
+
msgid "DastProfiles|Please enter a valid URL format, ex: http://www.example.com/home"
msgstr ""
@@ -7927,6 +8218,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan mode"
+msgstr ""
+
msgid "DastProfiles|Scanner Profile"
msgstr ""
@@ -7966,10 +8260,10 @@ msgstr ""
msgid "DastProfiles|Text file validation"
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
+msgid "DastProfiles|The maximum number of minutes allowed for the spider to traverse the site."
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the spider to traverse the site."
+msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
msgstr ""
msgid "DastProfiles|Validate"
@@ -8002,6 +8296,9 @@ msgstr ""
msgid "Date picker"
msgstr ""
+msgid "Date range"
+msgstr ""
+
msgid "Date range cannot exceed %{maxDateRange} days."
msgstr ""
@@ -8026,6 +8323,9 @@ msgstr "Dani"
msgid "Days to merge"
msgstr ""
+msgid "Dear Administrator,"
+msgstr ""
+
msgid "Debug"
msgstr ""
@@ -8137,12 +8437,18 @@ msgstr ""
msgid "Delete"
msgstr ""
+msgid "Delete %{name}"
+msgstr ""
+
msgid "Delete Comment"
msgstr ""
msgid "Delete Snippet"
msgstr ""
+msgid "Delete Value Stream"
+msgstr ""
+
msgid "Delete account"
msgstr ""
@@ -8164,9 +8470,6 @@ msgstr ""
msgid "Delete label: %{label_name} ?"
msgstr ""
-msgid "Delete license"
-msgstr ""
-
msgid "Delete list"
msgstr ""
@@ -8242,15 +8545,6 @@ msgstr ""
msgid "Deleting a project places it into a read-only state until %{date}, at which point the project will be permanently deleted. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "Deleting the license failed."
-msgstr ""
-
-msgid "Deleting the license failed. The license was not found."
-msgstr ""
-
-msgid "Deleting the license failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "Deleting the project will delete its repository and all related resources including issues, merge requests etc."
msgstr ""
@@ -8752,7 +9046,10 @@ msgstr ""
msgid "DesignManagement|The maximum number of designs allowed to be uploaded is %{upload_limit}. Please try again."
msgstr ""
-msgid "DesignManagement|To upload designs, you'll need to enable LFS. %{requirements_link_start}More information%{requirements_link_end}"
+msgid "DesignManagement|There was an error moving your designs. Please upload your designs below."
+msgstr ""
+
+msgid "DesignManagement|To upload designs, you'll need to enable LFS and have admin enable hashed storage. %{requirements_link_start}More information%{requirements_link_end}"
msgstr ""
msgid "DesignManagement|Unresolve thread"
@@ -8764,6 +9061,9 @@ msgstr ""
msgid "DesignManagement|Upload skipped."
msgstr ""
+msgid "DesignManagement|Your designs are being copied and are on their way… Please refresh to update."
+msgstr ""
+
msgid "DesignManagement|and %{moreCount} more."
msgstr ""
@@ -8821,6 +9121,9 @@ msgstr ""
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
+msgid "Direct member"
+msgstr ""
+
msgid "Direction"
msgstr ""
@@ -8869,9 +9172,6 @@ msgstr ""
msgid "Discard draft"
msgstr ""
-msgid "Discard review"
-msgstr ""
-
msgid "DiscordService|Discord Notifications"
msgstr ""
@@ -8941,10 +9241,10 @@ msgstr ""
msgid "Dismiss Merge Request promotion"
msgstr ""
-msgid "Dismiss Selected"
+msgid "Dismiss Value Stream Analytics introduction box"
msgstr ""
-msgid "Dismiss Value Stream Analytics introduction box"
+msgid "Dismiss selected"
msgstr ""
msgid "Dismiss trial promotion"
@@ -8995,9 +9295,6 @@ msgstr ""
msgid "Documents reindexed: %{processed_documents} (%{percentage}%%)"
msgstr ""
-msgid "Doing"
-msgstr ""
-
msgid "Domain"
msgstr ""
@@ -9193,9 +9490,6 @@ msgstr ""
msgid "Edit environment"
msgstr ""
-msgid "Edit file"
-msgstr ""
-
msgid "Edit files in the editor and commit changes here"
msgstr ""
@@ -9208,6 +9502,12 @@ msgstr ""
msgid "Edit identity for %{user_name}"
msgstr ""
+msgid "Edit in Web IDE"
+msgstr ""
+
+msgid "Edit in single-file editor"
+msgstr ""
+
msgid "Edit issues"
msgstr ""
@@ -9235,19 +9535,16 @@ msgstr ""
msgid "Editing"
msgstr ""
-msgid "Elasticsearch"
-msgstr "Elasticsearch"
-
msgid "Elasticsearch AWS IAM credentials"
msgstr ""
-msgid "Elasticsearch indexing restrictions"
+msgid "Elasticsearch HTTP client timeout value in seconds."
msgstr ""
-msgid "Elasticsearch indexing started"
+msgid "Elasticsearch indexing restrictions"
msgstr ""
-msgid "Elasticsearch integration. Elasticsearch AWS IAM."
+msgid "Elasticsearch indexing started"
msgstr ""
msgid "Elasticsearch reindexing is already in progress"
@@ -9277,9 +9574,6 @@ msgstr ""
msgid "Email Notification"
msgstr ""
-msgid "Email address"
-msgstr ""
-
msgid "Email could not be sent"
msgstr ""
@@ -9343,6 +9637,9 @@ msgstr ""
msgid "Emails sent from Service Desk will have this name"
msgstr ""
+msgid "Emails sent to %{email} will still be supported"
+msgstr ""
+
msgid "Emails separated by comma"
msgstr ""
@@ -9376,9 +9673,18 @@ msgstr ""
msgid "Enable"
msgstr ""
+msgid "Enable %{link_start}Gitpod%{link_end} integration to launch a development environment in your browser directly from GitLab."
+msgstr ""
+
msgid "Enable Auto DevOps"
msgstr ""
+msgid "Enable Gitpod"
+msgstr ""
+
+msgid "Enable Gitpod?"
+msgstr ""
+
msgid "Enable HTML emails"
msgstr ""
@@ -9508,9 +9814,6 @@ msgstr ""
msgid "Encountered an error while rendering: %{err}"
msgstr ""
-msgid "End date"
-msgstr ""
-
msgid "Ends at (UTC)"
msgstr ""
@@ -9670,7 +9973,7 @@ msgstr ""
msgid "EnvironmentsDashboard|The environments dashboard provides a summary of each project's environments' status, including pipeline and alert statuses."
msgstr ""
-msgid "EnvironmentsDashboard|This dashboard displays a maximum of 7 projects and 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
+msgid "EnvironmentsDashboard|This dashboard displays 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
msgstr ""
msgid "Environments|An error occurred while canceling the auto stop, please try again"
@@ -9991,6 +10294,9 @@ msgstr ""
msgid "Error deleting project. Check logs for error details."
msgstr ""
+msgid "Error fetching burnup chart data"
+msgstr ""
+
msgid "Error fetching diverging counts for branches. Please try again."
msgstr ""
@@ -10069,6 +10375,9 @@ msgstr ""
msgid "Error occurred when saving assignees"
msgstr ""
+msgid "Error occurred when saving reviewers"
+msgstr ""
+
msgid "Error occurred when toggling the notification subscription"
msgstr ""
@@ -10321,10 +10630,13 @@ msgstr ""
msgid "Expand all"
msgstr ""
-msgid "Expand approvers"
+msgid "Expand all files"
+msgstr ""
+
+msgid "Expand all threads"
msgstr ""
-msgid "Expand dropdown"
+msgid "Expand approvers"
msgstr ""
msgid "Expand milestones"
@@ -10495,6 +10807,9 @@ msgstr ""
msgid "Failed to create Merge Request. Please try again."
msgstr ""
+msgid "Failed to create To-Do for the design."
+msgstr ""
+
msgid "Failed to create a branch for this issue. Please try again."
msgstr ""
@@ -10534,6 +10849,12 @@ msgstr ""
msgid "Failed to load authors. Please try again."
msgstr ""
+msgid "Failed to load branches. Please try again."
+msgstr ""
+
+msgid "Failed to load deploy keys."
+msgstr ""
+
msgid "Failed to load emoji list."
msgstr ""
@@ -10549,6 +10870,9 @@ msgstr ""
msgid "Failed to load groups & users."
msgstr ""
+msgid "Failed to load groups, users and deploy keys."
+msgstr ""
+
msgid "Failed to load labels. Please try again."
msgstr ""
@@ -10558,6 +10882,12 @@ msgstr ""
msgid "Failed to load related branches"
msgstr ""
+msgid "Failed to load sidebar confidential toggle"
+msgstr ""
+
+msgid "Failed to load sidebar lock status"
+msgstr ""
+
msgid "Failed to load stacktrace."
msgstr ""
@@ -10585,6 +10915,9 @@ msgstr ""
msgid "Failed to publish issue on status page."
msgstr ""
+msgid "Failed to remove To-Do for the design."
+msgstr ""
+
msgid "Failed to remove a Zoom meeting"
msgstr ""
@@ -10627,6 +10960,9 @@ msgstr ""
msgid "Failed to signing using smartcard authentication"
msgstr ""
+msgid "Failed to toggle To-Do for the design."
+msgstr ""
+
msgid "Failed to update branch!"
msgstr ""
@@ -10741,7 +11077,7 @@ msgstr ""
msgid "FeatureFlags|Edit User List"
msgstr ""
-msgid "FeatureFlags|Enable features for specific users and specific environments by defining feature flag strategies."
+msgid "FeatureFlags|Enable features for specific users and environments by configuring feature flag strategies."
msgstr ""
msgid "FeatureFlags|Environment Spec"
@@ -10801,7 +11137,7 @@ msgstr ""
msgid "FeatureFlags|Include additional user IDs"
msgstr ""
-msgid "FeatureFlags|Install a %{docs_link_anchored_start}compatible client library%{docs_link_anchored_end} and specify the API URL, application name, and instance ID during the configuration setup. %{docs_link_start}More Information%{docs_link_end}"
+msgid "FeatureFlags|Install a %{docsLinkAnchoredStart}compatible client library%{docsLinkAnchoredEnd} and specify the API URL, application name, and instance ID during the configuration setup. %{docsLinkStart}More Information%{docsLinkEnd}"
msgstr ""
msgid "FeatureFlags|Instance ID"
@@ -10813,6 +11149,9 @@ msgstr ""
msgid "FeatureFlags|Loading feature flags"
msgstr ""
+msgid "FeatureFlags|Loading user lists"
+msgstr ""
+
msgid "FeatureFlags|More information"
msgstr ""
@@ -10831,7 +11170,7 @@ msgstr ""
msgid "FeatureFlags|New feature flag"
msgstr ""
-msgid "FeatureFlags|New list"
+msgid "FeatureFlags|New user list"
msgstr ""
msgid "FeatureFlags|Percent of users"
@@ -10870,6 +11209,9 @@ msgstr ""
msgid "FeatureFlags|There was an error fetching the feature flags."
msgstr ""
+msgid "FeatureFlags|There was an error fetching the user lists."
+msgstr ""
+
msgid "FeatureFlags|There was an error retrieving user lists"
msgstr ""
@@ -10885,6 +11227,9 @@ msgstr ""
msgid "FeatureFlags|User List"
msgstr ""
+msgid "FeatureFlags|User Lists"
+msgstr ""
+
msgid "FeatureFlag|List"
msgstr ""
@@ -10912,15 +11257,6 @@ msgstr ""
msgid "Fetching incoming email"
msgstr ""
-msgid "Fetching licenses failed."
-msgstr ""
-
-msgid "Fetching licenses failed. The request endpoint was not found."
-msgstr ""
-
-msgid "Fetching licenses failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "File"
msgstr ""
@@ -11023,12 +11359,21 @@ msgstr ""
msgid "Filter by status"
msgstr ""
+msgid "Filter by test cases that are currently archived."
+msgstr ""
+
+msgid "Filter by test cases that are currently opened."
+msgstr ""
+
msgid "Filter by two-factor authentication"
msgstr ""
msgid "Filter by user"
msgstr ""
+msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
+msgstr ""
+
msgid "Filter pipelines"
msgstr ""
@@ -11044,7 +11389,7 @@ msgstr ""
msgid "Filter results..."
msgstr ""
-msgid "Filter your projects by name"
+msgid "Filter your repositories by name"
msgstr ""
msgid "Filter..."
@@ -11053,7 +11398,7 @@ msgstr ""
msgid "Find File"
msgstr ""
-msgid "Find bugs in your code with coverage-guided fuzzing"
+msgid "Find bugs in your code with coverage-guided fuzzing."
msgstr ""
msgid "Find by path"
@@ -11080,9 +11425,6 @@ msgstr ""
msgid "Finish editing this message first!"
msgstr ""
-msgid "Finish review"
-msgstr ""
-
msgid "Finish setting up your dedicated account for %{group_name}."
msgstr ""
@@ -11152,6 +11494,9 @@ msgstr ""
msgid "Footer message"
msgstr ""
+msgid "For a faster browsing experience, some files are collapsed by default."
+msgstr ""
+
msgid "For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
@@ -11161,6 +11506,9 @@ msgstr ""
msgid "For more info, read the documentation."
msgstr ""
+msgid "For more information on how the number of active users is calculated, see the %{self_managed_subscriptions_doc_link} documentation."
+msgstr ""
+
msgid "For more information, go to the "
msgstr ""
@@ -11299,6 +11647,9 @@ msgstr ""
msgid "Generate new token"
msgstr ""
+msgid "Generic package file size in bytes"
+msgstr ""
+
msgid "Geo"
msgstr ""
@@ -11560,6 +11911,9 @@ msgstr ""
msgid "Geo|Please refer to Geo Troubleshooting."
msgstr ""
+msgid "Geo|Primary node"
+msgstr ""
+
msgid "Geo|Project"
msgstr ""
@@ -11602,6 +11956,9 @@ msgstr ""
msgid "Geo|Review replication status, and resynchronize and reverify items with the primary node."
msgstr ""
+msgid "Geo|Secondary node"
+msgstr ""
+
msgid "Geo|Status"
msgstr ""
@@ -11641,6 +11998,9 @@ msgstr ""
msgid "Geo|URL must be a valid url (ex: https://gitlab.com)"
msgstr ""
+msgid "Geo|Undefined"
+msgstr ""
+
msgid "Geo|Unknown state"
msgstr ""
@@ -11716,10 +12076,16 @@ msgstr ""
msgid "GitHub import"
msgstr ""
+msgid "GitLab"
+msgstr ""
+
msgid "GitLab / Unsubscribe"
msgstr ""
-msgid "GitLab Enterprise Edition %{plan}"
+msgid "GitLab API"
+msgstr ""
+
+msgid "GitLab Billing Team."
msgstr ""
msgid "GitLab Group Runners can execute code for all the projects in this group."
@@ -11731,12 +12097,18 @@ msgstr ""
msgid "GitLab Issue"
msgstr ""
+msgid "GitLab Pages"
+msgstr ""
+
msgid "GitLab Service Desk is a simple way to allow people to create issues in your GitLab instance without needing their own user account. It provides a unique email address for end users to create issues in a project, and replies can be sent either through the GitLab interface or by email. End users will only see the thread through email."
msgstr ""
msgid "GitLab Shared Runners execute code of different projects on the same Runner unless you configure GitLab Runner Autoscale with MaxBuilds 1 (which it is on GitLab.com)."
msgstr ""
+msgid "GitLab Shell"
+msgstr ""
+
msgid "GitLab Support Bot"
msgstr ""
@@ -11746,7 +12118,7 @@ msgstr ""
msgid "GitLab User"
msgstr ""
-msgid "GitLab allows you to continue using your license even if you exceed the number of seats you purchased. You will be required to pay for these seats when you renew your license."
+msgid "GitLab Workhorse"
msgstr ""
msgid "GitLab commit"
@@ -11914,6 +12286,21 @@ msgstr ""
msgid "Gitlab Pages"
msgstr ""
+msgid "Gitpod"
+msgstr ""
+
+msgid "Gitpod|Add the URL to your Gitpod instance configured to read your GitLab projects."
+msgstr ""
+
+msgid "Gitpod|Enable Gitpod integration"
+msgstr ""
+
+msgid "Gitpod|Gitpod URL"
+msgstr ""
+
+msgid "Gitpod|e.g. https://gitpod.example.com"
+msgstr ""
+
msgid "Given access %{time_ago}"
msgstr ""
@@ -12421,9 +12808,6 @@ msgstr ""
msgid "GroupSAML|Valid SAML Response"
msgstr ""
-msgid "GroupSAML|With group managed accounts enabled, all the users without a group managed account will be excluded from the group."
-msgstr ""
-
msgid "GroupSAML|With prohibit outer forks flag enabled group members will be able to fork project only inside your group."
msgstr ""
@@ -12637,10 +13021,10 @@ msgstr ""
msgid "GroupsNew|Create group"
msgstr ""
-msgid "GroupsNew|GitLab group export"
+msgid "GroupsNew|Import"
msgstr ""
-msgid "GroupsNew|Import"
+msgid "GroupsNew|Import a GitLab group export file"
msgstr ""
msgid "GroupsNew|Import group"
@@ -12784,6 +13168,9 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgid "Hide comments on this file"
+msgstr ""
+
msgid "Hide details"
msgstr ""
@@ -12829,6 +13216,15 @@ msgstr ""
msgid "Highest role:"
msgstr ""
+msgid "HighlightBar|Alert events:"
+msgstr ""
+
+msgid "HighlightBar|Alert start time:"
+msgstr ""
+
+msgid "HighlightBar|Original alert:"
+msgstr ""
+
msgid "History"
msgstr ""
@@ -13006,6 +13402,9 @@ msgstr ""
msgid "If enabled, access to projects will be validated on an external service using their classification label."
msgstr ""
+msgid "If the number of active users exceeds the user limit, you will be charged for the number of %{users_over_license_link} at your next license reconciliation."
+msgstr ""
+
msgid "If there is no previous license or if the previous license has expired, some GitLab functionality will be blocked until a new, valid license is uploaded."
msgstr ""
@@ -13045,9 +13444,6 @@ msgstr ""
msgid "If your HTTP repository is not publicly accessible, add your credentials."
msgstr ""
-msgid "Iglu registry URL (optional)"
-msgstr ""
-
msgid "Ignore"
msgstr ""
@@ -13084,6 +13480,18 @@ msgstr ""
msgid "Import"
msgstr ""
+msgid "Import %d compatible repository"
+msgid_plural "Import %d compatible repositories"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
+msgid "Import %d repository"
+msgid_plural "Import %d repositories"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "Import CSV"
msgstr ""
@@ -13093,15 +13501,9 @@ msgstr ""
msgid "Import all compatible projects"
msgstr ""
-msgid "Import all compatible repositories"
-msgstr ""
-
msgid "Import all projects"
msgstr ""
-msgid "Import all repositories"
-msgstr ""
-
msgid "Import an exported GitLab project"
msgstr ""
@@ -13189,6 +13591,9 @@ msgstr ""
msgid "ImportProjects|Error importing repository %{project_safe_import_url} into %{project_full_path} - %{message}"
msgstr ""
+msgid "ImportProjects|Import repositories"
+msgstr ""
+
msgid "ImportProjects|Importing the project failed"
msgstr ""
@@ -13201,7 +13606,7 @@ msgstr ""
msgid "ImportProjects|Requesting your %{provider} repositories failed"
msgstr ""
-msgid "ImportProjects|Select the projects you want to import"
+msgid "ImportProjects|Select the repositories you want to import"
msgstr ""
msgid "ImportProjects|The remote data could not be imported."
@@ -13237,9 +13642,6 @@ msgstr ""
msgid "In order to enable Service Desk for your instance, you must first set up incoming email."
msgstr ""
-msgid "In order to gather accurate feature usage data, it can take 1 to 2 weeks to see your index."
-msgstr ""
-
msgid "In order to personalize your experience with GitLab%{br_tag}we would like to know a bit more about you."
msgstr ""
@@ -13270,18 +13672,30 @@ msgstr ""
msgid "IncidentManagement|Create incident"
msgstr ""
+msgid "IncidentManagement|Critical - S1"
+msgstr ""
+
msgid "IncidentManagement|Date created"
msgstr ""
msgid "IncidentManagement|Display your incidents in a dedicated view"
msgstr ""
+msgid "IncidentManagement|High - S2"
+msgstr ""
+
msgid "IncidentManagement|Incident"
msgstr ""
msgid "IncidentManagement|Incidents"
msgstr ""
+msgid "IncidentManagement|Low - S4"
+msgstr ""
+
+msgid "IncidentManagement|Medium - S3"
+msgstr ""
+
msgid "IncidentManagement|No incidents to display."
msgstr ""
@@ -13294,6 +13708,9 @@ msgstr ""
msgid "IncidentManagement|Published to status page"
msgstr ""
+msgid "IncidentManagement|Severity"
+msgstr ""
+
msgid "IncidentManagement|There are no closed incidents"
msgstr ""
@@ -13303,6 +13720,9 @@ msgstr ""
msgid "IncidentManagement|Unassigned"
msgstr ""
+msgid "IncidentManagement|Unknown"
+msgstr ""
+
msgid "IncidentManagement|Unpublished"
msgstr ""
@@ -13324,6 +13744,15 @@ msgstr ""
msgid "Incidents"
msgstr ""
+msgid "Incident|Alert details"
+msgstr ""
+
+msgid "Incident|Summary"
+msgstr ""
+
+msgid "Incident|There was an issue loading alert data. Please try again."
+msgstr ""
+
msgid "Include a Terms of Service agreement and Privacy Policy that all users must accept."
msgstr ""
@@ -13384,6 +13813,9 @@ msgstr ""
msgid "Information about additional Pages templates and how to install them can be found in our %{pages_getting_started_guide}."
msgstr ""
+msgid "Inherited"
+msgstr ""
+
msgid "Inherited:"
msgstr ""
@@ -13465,7 +13897,22 @@ msgstr ""
msgid "Instance administrators group already exists"
msgstr ""
-msgid "Instance license"
+msgid "InstanceStatistics|Groups"
+msgstr ""
+
+msgid "InstanceStatistics|Issues"
+msgstr ""
+
+msgid "InstanceStatistics|Merge Requests"
+msgstr ""
+
+msgid "InstanceStatistics|Pipelines"
+msgstr ""
+
+msgid "InstanceStatistics|Projects"
+msgstr ""
+
+msgid "InstanceStatistics|Users"
msgstr ""
msgid "Integration"
@@ -13477,6 +13924,12 @@ msgstr ""
msgid "Integrations"
msgstr ""
+msgid "Integrations|%{integration} settings saved and active."
+msgstr ""
+
+msgid "Integrations|%{integration} settings saved, but not active."
+msgstr ""
+
msgid "Integrations|All details"
msgstr ""
@@ -13486,6 +13939,12 @@ msgstr ""
msgid "Integrations|Comment settings:"
msgstr ""
+msgid "Integrations|Connection failed. Please check your settings."
+msgstr ""
+
+msgid "Integrations|Connection successful."
+msgstr ""
+
msgid "Integrations|Default settings are inherited from the group level."
msgstr ""
@@ -13501,6 +13960,15 @@ msgstr ""
msgid "Integrations|Includes commit title and branch"
msgstr ""
+msgid "Integrations|Projects using custom settings will not be impacted unless the project owner chooses to use instance-level defaults."
+msgstr ""
+
+msgid "Integrations|Save settings?"
+msgstr ""
+
+msgid "Integrations|Saving will update the default settings for all projects that are not using custom settings."
+msgstr ""
+
msgid "Integrations|Standard"
msgstr ""
@@ -13633,6 +14101,9 @@ msgstr ""
msgid "Invitation"
msgstr ""
+msgid "Invitation declined"
+msgstr ""
+
msgid "Invite"
msgstr ""
@@ -13684,6 +14155,42 @@ 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|%{linkStart}Read more%{linkEnd} about role permissions"
+msgstr ""
+
+msgid "InviteMembersModal|Access expiration date (optional)"
+msgstr ""
+
+msgid "InviteMembersModal|Cancel"
+msgstr ""
+
+msgid "InviteMembersModal|Choose a role permission"
+msgstr ""
+
+msgid "InviteMembersModal|GitLab member or Email address"
+msgstr ""
+
+msgid "InviteMembersModal|Invite"
+msgstr ""
+
+msgid "InviteMembersModal|Invite team members"
+msgstr ""
+
+msgid "InviteMembersModal|Search for members to invite"
+msgstr ""
+
+msgid "InviteMembersModal|User not invited. Feature coming soon!"
+msgstr ""
+
+msgid "InviteMembersModal|Users were succesfully added"
+msgstr ""
+
+msgid "InviteMembersModal|You're inviting members to the %{group_name} group"
+msgstr ""
+
+msgid "InviteMembers|Invite team members"
+msgstr ""
+
msgid "Invited"
msgstr ""
@@ -13738,10 +14245,13 @@ msgstr ""
msgid "Issue cannot be found."
msgstr ""
+msgid "Issue created from vulnerability %{vulnerability_link}"
+msgstr ""
+
msgid "Issue events"
msgstr ""
-msgid "Issue first depoloyed to production"
+msgid "Issue first deployed to production"
msgstr ""
msgid "Issue label"
@@ -13819,6 +14329,9 @@ msgstr ""
msgid "IssueTracker|Custom issue tracker"
msgstr ""
+msgid "IssueTracker|EWM work items tracker"
+msgstr ""
+
msgid "IssueTracker|Redmine issue tracker"
msgstr ""
@@ -13885,6 +14398,9 @@ msgstr ""
msgid "It looks like you have some draft commits in this branch."
msgstr ""
+msgid "It may be several days before you see feature usage data."
+msgstr ""
+
msgid "It must have a header row and at least two columns: the first column is the issue title and the second column is the issue description. The separator is automatically detected."
msgstr ""
@@ -14167,13 +14683,13 @@ msgstr ""
msgid "Join Zoom meeting"
msgstr ""
-msgid "Jul"
+msgid "Joined %{time_ago}"
msgstr ""
-msgid "July"
+msgid "Jul"
msgstr ""
-msgid "Jump to first unresolved thread"
+msgid "July"
msgstr ""
msgid "Jump to next unresolved thread"
@@ -14209,6 +14725,9 @@ msgstr ""
msgid "Keyboard shortcuts"
msgstr ""
+msgid "KeyboardKey|Ctrl+"
+msgstr ""
+
msgid "Keys"
msgstr ""
@@ -14257,6 +14776,9 @@ msgstr ""
msgid "LDAP Synchronization"
msgstr ""
+msgid "LDAP group settings"
+msgstr ""
+
msgid "LDAP settings"
msgstr ""
@@ -14266,6 +14788,9 @@ msgstr ""
msgid "LDAP sync in progress. This could take a few minutes. Refresh the page to see the changes."
msgstr ""
+msgid "LDAP synchronizations"
+msgstr ""
+
msgid "LFS"
msgstr ""
@@ -14347,8 +14872,17 @@ msgstr[0] "Zadnjih %d dan"
msgstr[1] "Zadnjih %d dana"
msgstr[2] "Zadnjih %d dana"
-msgid "Last %{days} days"
-msgstr "Zadnjih %{days} dana"
+msgid "Last 2 weeks"
+msgstr ""
+
+msgid "Last 30 days"
+msgstr ""
+
+msgid "Last 60 days"
+msgstr ""
+
+msgid "Last 90 days"
+msgstr ""
msgid "Last Accessed On"
msgstr ""
@@ -14425,6 +14959,9 @@ msgstr ""
msgid "Last used on:"
msgstr ""
+msgid "Last week"
+msgstr ""
+
msgid "LastCommit|authored"
msgstr ""
@@ -14440,6 +14977,9 @@ msgstr ""
msgid "Latest pipeline for the most recent commit on this branch"
msgstr ""
+msgid "Launch a ready-to-code development environment for your project."
+msgstr ""
+
msgid "Lead"
msgstr ""
@@ -14827,6 +15367,9 @@ msgstr ""
msgid "List of all merge commits"
msgstr ""
+msgid "List options"
+msgstr ""
+
msgid "List settings"
msgstr ""
@@ -14839,9 +15382,6 @@ msgstr ""
msgid "List your Bitbucket Server repositories"
msgstr ""
-msgid "Lists"
-msgstr ""
-
msgid "Live preview"
msgstr ""
@@ -15088,6 +15628,12 @@ msgstr ""
msgid "Mark as done"
msgstr ""
+msgid "Mark as draft"
+msgstr ""
+
+msgid "Mark as ready"
+msgstr ""
+
msgid "Mark as resolved"
msgstr ""
@@ -15109,6 +15655,24 @@ msgstr ""
msgid "Markdown is supported"
msgstr ""
+msgid "MarkdownEditor|Add a link (%{modifierKey}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add a link (%{modifier_key}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifierKey}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifier_key}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifierKey}I)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifier_key}I)"
+msgstr ""
+
msgid "Marked For Deletion At - %{deletion_time}"
msgstr ""
@@ -15193,7 +15757,25 @@ msgstr ""
msgid "Max access level"
msgstr ""
-msgid "Max seats used"
+msgid "Max role"
+msgstr ""
+
+msgid "Max size 15 MB"
+msgstr ""
+
+msgid "Maximum Conan package file size in bytes"
+msgstr ""
+
+msgid "Maximum Maven package file size in bytes"
+msgstr ""
+
+msgid "Maximum NPM package file size in bytes"
+msgstr ""
+
+msgid "Maximum NuGet package file size in bytes"
+msgstr ""
+
+msgid "Maximum PyPI package file size in bytes"
msgstr ""
msgid "Maximum Users:"
@@ -15325,6 +15907,18 @@ msgstr ""
msgid "Members with access to %{strong_start}%{group_name}%{strong_end}"
msgstr ""
+msgid "Members|%{time} by %{user}"
+msgstr ""
+
+msgid "Members|Expired"
+msgstr ""
+
+msgid "Members|No expiration set"
+msgstr ""
+
+msgid "Members|in %{time}"
+msgstr ""
+
msgid "Memory Usage"
msgstr ""
@@ -15511,9 +16105,6 @@ msgstr ""
msgid "MergeRequests|Thread will be unresolved"
msgstr ""
-msgid "MergeRequests|Toggle comments for this file"
-msgstr ""
-
msgid "MergeRequests|View file @ %{commitId}"
msgstr ""
@@ -15574,6 +16165,9 @@ msgstr ""
msgid "Merging immediately isn't recommended as it may negatively impact the existing merge train. Read the %{docsLinkStart}documentation%{docsLinkEnd} for more information."
msgstr ""
+msgid "Message"
+msgstr ""
+
msgid "Messages"
msgstr ""
@@ -15961,18 +16555,12 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
-msgid "Milestone does not support burnup charts"
-msgstr ""
-
msgid "Milestone lists not available with your current license"
msgstr ""
msgid "Milestone lists show all issues from the selected milestone."
msgstr ""
-msgid "Milestone must have a start and due date"
-msgstr ""
-
msgid "MilestoneSidebar|Closed:"
msgstr ""
@@ -16339,6 +16927,9 @@ msgstr ""
msgid "Namespace"
msgstr ""
+msgid "Namespace ID:"
+msgstr ""
+
msgid "Namespace is empty"
msgstr ""
@@ -16423,6 +17014,9 @@ msgstr ""
msgid "NetworkPolicies|Allow all outbound traffic from %{selector} to %{ruleSelector} on %{ports}"
msgstr ""
+msgid "NetworkPolicies|Are you sure you want to delete this policy? This action cannot be undone."
+msgstr ""
+
msgid "NetworkPolicies|Choose whether to enforce this policy."
msgstr ""
@@ -16432,12 +17026,21 @@ msgstr ""
msgid "NetworkPolicies|Define this policy's location, conditions and actions."
msgstr ""
+msgid "NetworkPolicies|Delete policy"
+msgstr ""
+
+msgid "NetworkPolicies|Delete policy: %{policy}"
+msgstr ""
+
msgid "NetworkPolicies|Deny all traffic"
msgstr ""
msgid "NetworkPolicies|Description"
msgstr ""
+msgid "NetworkPolicies|Edit policy"
+msgstr ""
+
msgid "NetworkPolicies|Editor mode"
msgstr ""
@@ -16465,6 +17068,9 @@ msgstr ""
msgid "NetworkPolicies|Name"
msgstr ""
+msgid "NetworkPolicies|Namespace"
+msgstr ""
+
msgid "NetworkPolicies|Network Policy"
msgstr ""
@@ -16516,6 +17122,9 @@ msgstr ""
msgid "NetworkPolicies|Rules"
msgstr ""
+msgid "NetworkPolicies|Save changes"
+msgstr ""
+
msgid "NetworkPolicies|Something went wrong, failed to update policy"
msgstr ""
@@ -16528,6 +17137,9 @@ msgstr ""
msgid "NetworkPolicies|Traffic that does not match any rule will be blocked."
msgstr ""
+msgid "NetworkPolicies|Unable to parse policy"
+msgstr ""
+
msgid "NetworkPolicies|YAML editor"
msgstr ""
@@ -16642,6 +17254,9 @@ msgstr ""
msgid "New Snippet"
msgstr ""
+msgid "New Test Case"
+msgstr ""
+
msgid "New User"
msgstr ""
@@ -16741,6 +17356,9 @@ msgstr ""
msgid "New tag"
msgstr ""
+msgid "New test case"
+msgstr ""
+
msgid "New users set to external"
msgstr ""
@@ -16813,7 +17431,7 @@ msgstr ""
msgid "No changes"
msgstr ""
-msgid "No changes between %{ref_start}%{source_branch}%{ref_end} and %{ref_start}%{target_branch}%{ref_end}"
+msgid "No changes between %{sourceBranch} and %{targetBranch}"
msgstr ""
msgid "No child epics match applied filters"
@@ -16828,6 +17446,9 @@ msgstr ""
msgid "No containers available"
msgstr ""
+msgid "No content to show"
+msgstr ""
+
msgid "No contributions"
msgstr ""
@@ -16903,9 +17524,6 @@ msgstr ""
msgid "No license. All rights reserved"
msgstr ""
-msgid "No licenses found."
-msgstr ""
-
msgid "No matches found"
msgstr ""
@@ -16918,6 +17536,9 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No members found"
+msgstr ""
+
msgid "No merge requests found"
msgstr ""
@@ -16939,6 +17560,9 @@ msgstr ""
msgid "No parent group"
msgstr ""
+msgid "No plan"
+msgstr ""
+
msgid "No pods available"
msgstr ""
@@ -17035,6 +17659,12 @@ msgstr ""
msgid "Not Implemented"
msgstr ""
+msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+msgstr ""
+
+msgid "Not all browsers support WebAuthn. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even from an unsupported browser."
+msgstr ""
+
msgid "Not all data has been processed yet, the accuracy of the chart for the selected timeframe is limited."
msgstr ""
@@ -17131,6 +17761,9 @@ msgstr ""
msgid "Notification settings saved"
msgstr ""
+msgid "NotificationEvent|Change reviewer merge request"
+msgstr ""
+
msgid "NotificationEvent|Close issue"
msgstr ""
@@ -17293,10 +17926,7 @@ msgstr ""
msgid "On track"
msgstr ""
-msgid "OnDemandScans|Attached branch"
-msgstr ""
-
-msgid "OnDemandScans|Attached branch is where the scan job runs."
+msgid "OnDemandScans|Could not fetch scanner profiles. Please refresh the page, or try again later."
msgstr ""
msgid "OnDemandScans|Could not fetch site profiles. Please refresh the page, or try again later."
@@ -17305,6 +17935,9 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
+msgid "OnDemandScans|Create a new scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Create a new site profile"
msgstr ""
@@ -17317,6 +17950,9 @@ msgstr ""
msgid "OnDemandScans|New on-demand DAST scan"
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 ""
@@ -17326,16 +17962,10 @@ msgstr ""
msgid "OnDemandScans|On-demand scans run outside the DevOps cycle and find vulnerabilities in your projects. %{learnMoreLinkStart}Learn more%{learnMoreLinkEnd}"
msgstr ""
-msgid "OnDemandScans|Only a passive scan can be performed on demand."
-msgstr ""
-
-msgid "OnDemandScans|Passive"
-msgstr ""
-
msgid "OnDemandScans|Run scan"
msgstr ""
-msgid "OnDemandScans|Scan mode"
+msgid "OnDemandScans|Scanner profile"
msgstr ""
msgid "OnDemandScans|Scanner settings"
@@ -17347,9 +17977,15 @@ msgstr ""
msgid "OnDemandScans|Select one of the existing profiles"
msgstr ""
+msgid "OnDemandScans|Site profile"
+msgstr ""
+
msgid "OnDemandScans|Site profiles"
msgstr ""
+msgid "OnDemandScans|Use existing scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Use existing site profile"
msgstr ""
@@ -17449,9 +18085,6 @@ msgstr ""
msgid "Open Selection"
msgstr ""
-msgid "Open Web IDE"
-msgstr ""
-
msgid "Open comment type dropdown"
msgstr ""
@@ -17557,6 +18190,9 @@ msgstr ""
msgid "Origin"
msgstr ""
+msgid "Orphaned member"
+msgstr ""
+
msgid "Other Labels"
msgstr ""
@@ -17572,6 +18208,9 @@ msgstr ""
msgid "Other visibility settings have been disabled by the administrator."
msgstr ""
+msgid "Our documentation includes an example DevOps Score report."
+msgstr ""
+
msgid "Out-of-compliance with this project's policies and should be removed"
msgstr ""
@@ -17596,6 +18235,9 @@ msgstr "Pregled"
msgid "Overwrite diverged branches"
msgstr ""
+msgid "Owned by %{image_tag}"
+msgstr ""
+
msgid "Owned by anyone"
msgstr ""
@@ -17617,6 +18259,9 @@ msgstr ""
msgid "Package deleted successfully"
msgstr ""
+msgid "Package file size limits"
+msgstr ""
+
msgid "Package recipe already exists"
msgstr ""
@@ -17632,9 +18277,6 @@ msgstr ""
msgid "Package type must be PyPi"
msgstr ""
-msgid "Package was removed"
-msgstr ""
-
msgid "PackageRegistry|%{name} version %{version} was created %{datetime}"
msgstr ""
@@ -17776,12 +18418,18 @@ msgstr ""
msgid "PackageRegistry|NuGet Command"
msgstr ""
+msgid "PackageRegistry|Package Registry"
+msgstr ""
+
msgid "PackageRegistry|Pip Command"
msgstr ""
msgid "PackageRegistry|Pipeline %{link} triggered %{datetime} by %{author}"
msgstr ""
+msgid "PackageRegistry|Publish and share packages for a variety of common package managers. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "PackageRegistry|Published to the %{project} Package Registry %{datetime}"
msgstr ""
@@ -17881,6 +18529,9 @@ msgstr ""
msgid "Page not found"
msgstr ""
+msgid "Page settings"
+msgstr ""
+
msgid "Page was successfully deleted"
msgstr ""
@@ -18022,7 +18673,7 @@ msgstr ""
msgid "Paste issue link"
msgstr ""
-msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Don't use your private SSH key."
+msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Do not paste your private SSH key, as that can compromise your identity."
msgstr ""
msgid "Patch to apply"
@@ -18049,6 +18700,9 @@ msgstr ""
msgid "Pending"
msgstr ""
+msgid "Pending comments"
+msgstr ""
+
msgid "People without permission will never get a notification and won't be able to comment."
msgstr ""
@@ -18247,6 +18901,9 @@ msgstr ""
msgid "Pipelines|Build with confidence"
msgstr ""
+msgid "Pipelines|By revoking a trigger you will break any processes making use of it. Are you sure?"
+msgstr ""
+
msgid "Pipelines|CI Lint"
msgstr ""
@@ -18259,6 +18916,15 @@ msgstr ""
msgid "Pipelines|Continuous Integration can help catch bugs by running your tests automatically, while Continuous Deployment can help you deliver code to your product environment."
msgstr ""
+msgid "Pipelines|Copy trigger token"
+msgstr ""
+
+msgid "Pipelines|Description"
+msgstr ""
+
+msgid "Pipelines|Edit"
+msgstr ""
+
msgid "Pipelines|Get started with Pipelines"
msgstr ""
@@ -18274,15 +18940,27 @@ msgstr ""
msgid "Pipelines|It is recommended the code is reviewed thoroughly before running this pipeline with the parent project's CI resource."
msgstr ""
+msgid "Pipelines|Last Used"
+msgstr ""
+
msgid "Pipelines|Loading Pipelines"
msgstr ""
msgid "Pipelines|More Information"
msgstr ""
+msgid "Pipelines|No triggers have been created yet. Add one using the form above."
+msgstr ""
+
+msgid "Pipelines|Owner"
+msgstr ""
+
msgid "Pipelines|Project cache successfully reset."
msgstr ""
+msgid "Pipelines|Revoke"
+msgstr ""
+
msgid "Pipelines|Run Pipeline"
msgstr ""
@@ -18307,6 +18985,15 @@ msgstr ""
msgid "Pipelines|This project is not currently set up to run pipelines."
msgstr ""
+msgid "Pipelines|Token"
+msgstr ""
+
+msgid "Pipelines|Trigger user has insufficient permissions to project"
+msgstr ""
+
+msgid "Pipelines|invalid"
+msgstr ""
+
msgid "Pipelines|parent"
msgstr ""
@@ -18565,10 +19252,10 @@ msgstr ""
msgid "Please provide attributes to update"
msgstr ""
-msgid "Please refer to %{docs_url}"
+msgid "Please reach out if you have any questions and we'll be happy to assist."
msgstr ""
-msgid "Please retype the email address."
+msgid "Please refer to %{docs_url}"
msgstr ""
msgid "Please select"
@@ -18598,6 +19285,9 @@ msgstr ""
msgid "Please set a new password before proceeding."
msgstr ""
+msgid "Please share your feedback about %{featureName} %{linkStart}in this issue%{linkEnd} to help us improve the experience."
+msgstr ""
+
msgid "Please solve the reCAPTCHA"
msgstr ""
@@ -18901,6 +19591,9 @@ msgstr ""
msgid "Profiles| You are going to change the username %{currentUsernameBold} to %{newUsernameBold}. Profile and projects will be redirected to the %{newUsername} namespace but this redirect will expire once the %{currentUsername} namespace is registered by another user or group. Please update your Git repository remotes as soon as possible."
msgstr ""
+msgid "Profiles|%{provider} Active"
+msgstr ""
+
msgid "Profiles|@username"
msgstr ""
@@ -18952,7 +19645,7 @@ msgstr ""
msgid "Profiles|Commit email"
msgstr ""
-msgid "Profiles|Connect"
+msgid "Profiles|Connect %{provider}"
msgstr ""
msgid "Profiles|Connected Accounts"
@@ -18976,6 +19669,9 @@ msgstr ""
msgid "Profiles|Disconnect"
msgstr ""
+msgid "Profiles|Disconnect %{provider}"
+msgstr ""
+
msgid "Profiles|Do not show on profile"
msgstr ""
@@ -19000,7 +19696,7 @@ msgstr ""
msgid "Profiles|Full name"
msgstr ""
-msgid "Profiles|Give your individual key a title. This will be publically visible."
+msgid "Profiles|Give your individual key a title."
msgstr ""
msgid "Profiles|Include private contributions on my profile"
@@ -19090,7 +19786,7 @@ msgstr ""
msgid "Profiles|The maximum file size allowed is 200KB."
msgstr ""
-msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it?"
+msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it? It will be publicly visible."
msgstr ""
msgid "Profiles|This email will be displayed on your public profile"
@@ -19165,6 +19861,9 @@ msgstr ""
msgid "Profiles|You don't have access to delete this user."
msgstr ""
+msgid "Profiles|You must transfer ownership or delete groups you are an owner of before you can delete your account"
+msgstr ""
+
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
@@ -19753,6 +20452,9 @@ msgstr ""
msgid "ProjectTemplates|GitLab Cluster Management"
msgstr ""
+msgid "ProjectTemplates|Gitpod/Spring Petclinic"
+msgstr ""
+
msgid "ProjectTemplates|Go Micro"
msgstr ""
@@ -20362,6 +21064,9 @@ msgstr ""
msgid "Publish to status page"
msgstr ""
+msgid "Published"
+msgstr ""
+
msgid "Published on status page"
msgstr ""
@@ -20479,9 +21184,15 @@ msgstr ""
msgid "Quick range"
msgstr ""
+msgid "Quickly and easily edit multiple files in your project."
+msgstr ""
+
msgid "README"
msgstr ""
+msgid "Rails"
+msgstr ""
+
msgid "Rake Tasks Help"
msgstr ""
@@ -20602,10 +21313,13 @@ msgstr ""
msgid "Register Two-Factor Authenticator"
msgstr ""
-msgid "Register U2F device"
+msgid "Register Universal Two-Factor (U2F) Device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register WebAuthn Device"
+msgstr ""
+
+msgid "Register device"
msgstr ""
msgid "Register for GitLab"
@@ -20617,9 +21331,6 @@ msgstr ""
msgid "Register with two-factor app"
msgstr ""
-msgid "Registration"
-msgstr ""
-
msgid "Registration|Checkout"
msgstr ""
@@ -20737,9 +21448,6 @@ msgstr ""
msgid "Release|Something went wrong while saving the release details"
msgstr ""
-msgid "Remediated: needs review"
-msgstr ""
-
msgid "Remediations"
msgstr ""
@@ -20845,6 +21553,9 @@ msgstr ""
msgid "Remove priority"
msgstr ""
+msgid "Remove report"
+msgstr ""
+
msgid "Remove secondary node"
msgstr ""
@@ -20857,6 +21568,12 @@ msgstr ""
msgid "Remove time estimate"
msgstr ""
+msgid "Remove user & report"
+msgstr ""
+
+msgid "Remove user from group"
+msgstr ""
+
msgid "Removed"
msgstr ""
@@ -20938,9 +21655,6 @@ msgstr ""
msgid "Removes time estimate."
msgstr ""
-msgid "Removing license…"
-msgstr ""
-
msgid "Removing this group also removes all child projects, including archived projects, and their resources."
msgstr ""
@@ -21025,6 +21739,9 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
+msgid "Reported by %{reporter}"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -21112,6 +21829,27 @@ msgstr ""
msgid "Repositories"
msgstr ""
+msgid "Repositories Analytics"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download Historic Test Coverage Data"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download historic test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Historic Test Coverage Data is available in raw format (.csv) for further analysis."
+msgstr ""
+
+msgid "RepositoriesAnalytics|Test Code Coverage"
+msgstr ""
+
+msgid "RepositoriesAnalytics|There was an error fetching the projects."
+msgstr ""
+
msgid "Repository"
msgstr ""
@@ -21190,9 +21928,15 @@ msgstr ""
msgid "Request parameter %{param} is missing."
msgstr ""
+msgid "Request review from"
+msgstr ""
+
msgid "Request to link SAML account must be authorized"
msgstr ""
+msgid "Requested"
+msgstr ""
+
msgid "Requested %{time_ago}"
msgstr ""
@@ -21211,6 +21955,9 @@ msgstr ""
msgid "Requests to these domain(s)/address(es) on the local network will be allowed when local requests from hooks and services are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 or 127.0.0.0/28 are supported. Domain wildcards are not supported currently. Use comma, semicolon, or newline to separate multiple entries. The allowlist can hold a maximum of 1000 entries. Domains should use IDNA encoding. Ex: example.com, 192.168.1.1, 127.0.0.0/28, xn--itlab-j1a.com."
msgstr ""
+msgid "Require admin approval for new sign-ups"
+msgstr ""
+
msgid "Require all users in this group to setup Two-factor authentication"
msgstr ""
@@ -21340,9 +22087,6 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
-msgid "Resolved by %{resolvedByName}"
-msgstr ""
-
msgid "Resolves IP addresses once and uses them to submit requests"
msgstr ""
@@ -21463,6 +22207,15 @@ msgstr ""
msgid "ReviewApp|Enable Review App"
msgstr ""
+msgid "Reviewer"
+msgid_plural "%d Reviewers"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
+msgid "Reviewer(s)"
+msgstr ""
+
msgid "Reviewing"
msgstr ""
@@ -21502,6 +22255,9 @@ msgstr ""
msgid "Rook"
msgstr ""
+msgid "Ruby"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -21580,6 +22336,63 @@ msgstr ""
msgid "Runners page."
msgstr ""
+msgid "Runners|Active"
+msgstr ""
+
+msgid "Runners|Architecture"
+msgstr ""
+
+msgid "Runners|Can run untagged jobs"
+msgstr ""
+
+msgid "Runners|Description"
+msgstr ""
+
+msgid "Runners|Group"
+msgstr ""
+
+msgid "Runners|IP Address"
+msgstr ""
+
+msgid "Runners|Last contact"
+msgstr ""
+
+msgid "Runners|Locked to this project"
+msgstr ""
+
+msgid "Runners|Maximum job timeout"
+msgstr ""
+
+msgid "Runners|Name"
+msgstr ""
+
+msgid "Runners|Platform"
+msgstr ""
+
+msgid "Runners|Property Name"
+msgstr ""
+
+msgid "Runners|Protected"
+msgstr ""
+
+msgid "Runners|Revision"
+msgstr ""
+
+msgid "Runners|Shared"
+msgstr ""
+
+msgid "Runners|Specific"
+msgstr ""
+
+msgid "Runners|Tags"
+msgstr ""
+
+msgid "Runners|Value"
+msgstr ""
+
+msgid "Runners|Version"
+msgstr ""
+
msgid "Runners|You have used %{quotaUsed} out of %{quotaLimit} of your shared Runners pipeline minutes."
msgstr ""
@@ -21592,6 +22405,9 @@ msgstr ""
msgid "Runs a number of housekeeping tasks within the current repository, such as compressing file revisions and removing unreachable objects."
msgstr ""
+msgid "SAML"
+msgstr ""
+
msgid "SAML SSO"
msgstr ""
@@ -21643,6 +22459,9 @@ msgstr "Subota"
msgid "Save"
msgstr ""
+msgid "Save %{name} size limits"
+msgstr ""
+
msgid "Save Changes"
msgstr ""
@@ -21673,9 +22492,6 @@ msgstr ""
msgid "Save space and find tags in the Container Registry more easily. Enable the cleanup policy to remove stale tags and keep only the ones you need."
msgstr ""
-msgid "Save template"
-msgstr ""
-
msgid "Save variables"
msgstr ""
@@ -21718,9 +22534,6 @@ msgstr ""
msgid "Scope"
msgstr ""
-msgid "Scope not supported with disabled 'users_search' feature!"
-msgstr ""
-
msgid "Scoped issue boards"
msgstr ""
@@ -21847,9 +22660,6 @@ msgstr ""
msgid "Search requirements"
msgstr ""
-msgid "Search results…"
-msgstr ""
-
msgid "Search users"
msgstr ""
@@ -21925,6 +22735,12 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgid "SearchResults|epic"
+msgid_plural "SearchResults|epics"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "SearchResults|issue"
msgid_plural "SearchResults|issues"
msgstr[0] ""
@@ -21976,10 +22792,10 @@ msgstr ""
msgid "Seat Link is disabled, and cannot be configured through this form."
msgstr ""
-msgid "Seats currently in use"
+msgid "Seats usage data as of %{last_enqueue_time}"
msgstr ""
-msgid "Seats in license"
+msgid "Seats usage data is updated every day at 12:00pm UTC"
msgstr ""
msgid "Secondary"
@@ -22033,6 +22849,9 @@ msgstr ""
msgid "SecurityConfiguration|Available for on-demand DAST"
msgstr ""
+msgid "SecurityConfiguration|By default, all analyzers are applied in order to cover all languages across your project, and only run if the language is detected in the Merge Request."
+msgstr ""
+
msgid "SecurityConfiguration|Configure"
msgstr ""
@@ -22063,16 +22882,19 @@ msgstr ""
msgid "SecurityConfiguration|Manage"
msgstr ""
+msgid "SecurityConfiguration|More information"
+msgstr ""
+
msgid "SecurityConfiguration|Not enabled"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|Security Control"
+msgid "SecurityConfiguration|SAST Configuration"
msgstr ""
-msgid "SecurityConfiguration|See documentation"
+msgid "SecurityConfiguration|Security Control"
msgstr ""
msgid "SecurityConfiguration|Status"
@@ -22084,6 +22906,9 @@ msgstr ""
msgid "SecurityConfiguration|Using custom settings. You won't receive automatic updates on this variable. %{anchorStart}Restore to default%{anchorEnd}"
msgstr ""
+msgid "SecurityConfiguration|View history"
+msgstr ""
+
msgid "SecurityConfiguration|You can quickly enable all security scanning tools by enabling %{linkStart}Auto DevOps%{linkEnd}."
msgstr ""
@@ -22162,9 +22987,6 @@ msgstr ""
msgid "SecurityReports|Learn more about setting up your dashboard"
msgstr ""
-msgid "SecurityReports|Load more vulnerabilities"
-msgstr ""
-
msgid "SecurityReports|Monitor vulnerabilities in your code"
msgstr ""
@@ -22444,7 +23266,7 @@ msgstr ""
msgid "Select status"
msgstr ""
-msgid "Select strategy activation method"
+msgid "Select strategy activation method."
msgstr ""
msgid "Select subscription"
@@ -22459,7 +23281,7 @@ msgstr ""
msgid "Select the custom project template source group."
msgstr ""
-msgid "Select timeframe"
+msgid "Select the environment scope for this feature flag."
msgstr ""
msgid "Select timezone"
@@ -22708,6 +23530,9 @@ msgstr ""
msgid "Set iteration"
msgstr ""
+msgid "Set limit to 0 to allow any file size."
+msgstr ""
+
msgid "Set max session time for web terminal."
msgstr ""
@@ -22786,10 +23611,13 @@ msgstr ""
msgid "Set up a %{type} Runner manually"
msgstr ""
+msgid "Set up a hardware device as a second factor to sign in."
+msgstr ""
+
msgid "Set up assertions/attributes/claims (email, first_name, last_name) and NameID according to %{docsLinkStart}the documentation %{icon}%{docsLinkEnd}"
msgstr ""
-msgid "Set up new U2F device"
+msgid "Set up new device"
msgstr ""
msgid "Set up new password"
@@ -22858,6 +23686,9 @@ msgstr ""
msgid "Sets weight to %{weight}."
msgstr ""
+msgid "Setting this to 0 means using the system default timeout value."
+msgstr ""
+
msgid "Settings"
msgstr ""
@@ -22873,6 +23704,15 @@ msgstr ""
msgid "Severity"
msgstr ""
+msgid "SeverityWidget|Severity"
+msgstr ""
+
+msgid "SeverityWidget|Severity: %{severity}"
+msgstr ""
+
+msgid "SeverityWidget|There was an error while updating severity."
+msgstr ""
+
msgid "Shards (%{shards})"
msgstr ""
@@ -22918,6 +23758,9 @@ msgstr ""
msgid "Show all requirements."
msgstr ""
+msgid "Show all test cases."
+msgstr ""
+
msgid "Show archived projects"
msgstr ""
@@ -22930,6 +23773,9 @@ msgstr ""
msgid "Show comments"
msgstr ""
+msgid "Show comments on this file"
+msgstr ""
+
msgid "Show comments only"
msgstr ""
@@ -22975,6 +23821,12 @@ msgstr ""
msgid "Show parent subgroups"
msgstr ""
+msgid "Show the Closed list"
+msgstr ""
+
+msgid "Show the Open list"
+msgstr ""
+
msgid "Show whitespace changes"
msgstr ""
@@ -23020,9 +23872,6 @@ msgstr ""
msgid "Sidebar|Assign health status"
msgstr ""
-msgid "Sidebar|Change weight"
-msgstr ""
-
msgid "Sidebar|Health status"
msgstr ""
@@ -23206,6 +24055,9 @@ msgstr ""
msgid "Snippets|Add another file %{num}/%{total}"
msgstr ""
+msgid "Snippets|Authored %{time_ago} by %{author}"
+msgstr ""
+
msgid "Snippets|Delete file"
msgstr ""
@@ -23233,6 +24085,9 @@ msgstr ""
msgid "Solution"
msgstr ""
+msgid "Some changes are not shown"
+msgstr ""
+
msgid "Some child epics may be hidden due to applied filters"
msgstr ""
@@ -23599,6 +24454,12 @@ msgstr ""
msgid "Source (branch or tag)"
msgstr ""
+msgid "Source Branch"
+msgstr ""
+
+msgid "Source branch: %{source_branch_open}%{source_branch}%{source_branch_close}"
+msgstr ""
+
msgid "Source code"
msgstr ""
@@ -23764,9 +24625,6 @@ msgstr ""
msgid "Start and due date"
msgstr ""
-msgid "Start by choosing a group to see how your team is spending time. You can then drill down to the project level."
-msgstr ""
-
msgid "Start by choosing a group to start exploring the merge requests in that group. You can then proceed to filter by projects, labels, milestones and authors."
msgstr ""
@@ -23848,18 +24706,27 @@ msgstr ""
msgid "StaticSiteEditor|3. Assign a person to review and accept the merge request."
msgstr ""
+msgid "StaticSiteEditor|A link to view the merge request will appear once ready."
+msgstr ""
+
msgid "StaticSiteEditor|An error occurred while submitting your changes."
msgstr ""
msgid "StaticSiteEditor|Branch could not be created."
msgstr ""
+msgid "StaticSiteEditor|Copy update"
+msgstr ""
+
msgid "StaticSiteEditor|Could not commit the content changes."
msgstr ""
msgid "StaticSiteEditor|Could not create merge request."
msgstr ""
+msgid "StaticSiteEditor|Creating your merge request"
+msgstr ""
+
msgid "StaticSiteEditor|Incompatible file content"
msgstr ""
@@ -23881,6 +24748,9 @@ msgstr ""
msgid "StaticSiteEditor|View documentation"
msgstr ""
+msgid "StaticSiteEditor|You can set an assignee to get your changes reviewed and deployed once your merge request is created."
+msgstr ""
+
msgid "StaticSiteEditor|Your merge request has been created"
msgstr ""
@@ -24010,15 +24880,15 @@ msgstr ""
msgid "Submit %{humanized_resource_name}"
msgstr ""
-msgid "Submit Changes"
-msgstr ""
-
msgid "Submit a review"
msgstr ""
msgid "Submit as spam"
msgstr ""
+msgid "Submit changes"
+msgstr ""
+
msgid "Submit feedback"
msgstr ""
@@ -24172,6 +25042,9 @@ msgstr ""
msgid "Successfully deleted U2F device."
msgstr ""
+msgid "Successfully deleted WebAuthn device."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -24490,9 +25363,6 @@ msgstr "Å ablon"
msgid "Template to append to all Service Desk issues"
msgstr ""
-msgid "Template was successfully saved."
-msgstr ""
-
msgid "Templates"
msgstr ""
@@ -24574,10 +25444,28 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
-msgid "Test failed."
+msgid "Test settings"
+msgstr ""
+
+msgid "TestCases|New Test Case"
+msgstr ""
+
+msgid "TestCases|New test case"
+msgstr ""
+
+msgid "TestCases|Search test cases"
msgstr ""
-msgid "Test settings and save changes"
+msgid "TestCases|Something went wrong while creating a test case."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching count of test cases."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching test cases list."
+msgstr ""
+
+msgid "TestCases|Submit test case"
msgstr ""
msgid "TestHooks|Ensure one of your projects has merge requests."
@@ -24643,6 +25531,9 @@ msgstr ""
msgid "Thank you for signing up for your free trial! You will get additional instructions in your inbox shortly."
msgstr ""
+msgid "Thank you for your business."
+msgstr ""
+
msgid "Thank you for your feedback!"
msgstr ""
@@ -24703,9 +25594,6 @@ msgstr ""
msgid "The URL to use for connecting to Elasticsearch. Use a comma-separated list to support clustering (e.g., \"http://localhost:9200, http://localhost:9201\")."
msgstr ""
-msgid "The Web IDE offers advanced syntax highlighting capabilities and more."
-msgstr ""
-
msgid "The X509 Certificate to use when mutual TLS is required to communicate with the external authorization service. If left blank, the server certificate is still validated when accessing over HTTPS."
msgstr ""
@@ -24817,6 +25705,9 @@ msgstr ""
msgid "The form contains the following error:"
msgstr ""
+msgid "The form contains the following warning:"
+msgstr ""
+
msgid "The global settings require you to enable Two-Factor Authentication for your account."
msgstr ""
@@ -24931,9 +25822,6 @@ msgstr ""
msgid "The private key to use when a client certificate is provided. This value is encrypted at rest."
msgstr ""
-msgid "The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The project can be accessed by any logged in user."
msgstr ""
@@ -24970,7 +25858,7 @@ msgstr ""
msgid "The remote repository is being updated..."
msgstr ""
-msgid "The repository can be commited to, and issues, comments and other entities can be created."
+msgid "The repository can be committed to, and issues, comments and other entities can be created."
msgstr ""
msgid "The repository for this project does not exist."
@@ -25024,9 +25912,6 @@ msgstr ""
msgid "The time taken by each data entry gathered by that stage."
msgstr ""
-msgid "The total stage shows the time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The update action will time out after %{number_of_minutes} minutes. For big repositories, use a clone/push combination."
msgstr ""
@@ -25090,6 +25975,9 @@ msgstr ""
msgid "There are no archived requirements"
msgstr ""
+msgid "There are no archived test cases"
+msgstr ""
+
msgid "There are no changes"
msgstr ""
@@ -25129,6 +26017,9 @@ msgstr ""
msgid "There are no open requirements"
msgstr ""
+msgid "There are no open test cases"
+msgstr ""
+
msgid "There are no packages yet"
msgstr ""
@@ -25141,6 +26032,9 @@ msgstr ""
msgid "There is a limit of %{ci_project_subscriptions_limit} subscriptions from or to a project."
msgstr ""
+msgid "There is already a To-Do for this design."
+msgstr ""
+
msgid "There is already a repository with that name on disk"
msgstr ""
@@ -25159,6 +26053,9 @@ msgstr ""
msgid "There was a problem communicating with your device."
msgstr ""
+msgid "There was a problem fetching branches."
+msgstr ""
+
msgid "There was a problem fetching groups."
msgstr ""
@@ -25387,9 +26284,15 @@ msgstr ""
msgid "This action can lead to data loss. To prevent accidental actions we ask you to confirm your intention."
msgstr ""
+msgid "This action cannot be undone, and will permanently delete the %{key} SSH key"
+msgstr ""
+
msgid "This action cannot be undone. You will lose the project's repository and all content: issues, merge requests, etc."
msgstr ""
+msgid "This action has been performed too many times. Try again later."
+msgstr ""
+
msgid "This action will %{strongOpen}permanently delete%{strongClose} %{codeOpen}%{project}%{codeClose} %{strongOpen}immediately%{strongClose}, including its repositories and all content: issues, merge requests, etc."
msgstr ""
@@ -25417,9 +26320,6 @@ msgstr ""
msgid "This board's scope is reduced"
msgstr ""
-msgid "This branch has changed since you started editing. Would you like to create a new branch?"
-msgstr ""
-
msgid "This chart could not be displayed"
msgstr ""
@@ -25546,15 +26446,9 @@ msgstr ""
msgid "This is a security log of important events involving your account."
msgstr ""
-msgid "This is the author's first Merge Request to this project."
-msgstr ""
-
msgid "This is the highest peak of users on your installation since the license started."
msgstr ""
-msgid "This is the maximum number of users that have existed at the same time since the license started. This is the minimum number of seats you will need to buy when you renew your license."
-msgstr ""
-
msgid "This is the number of currently active users on your installation, and this is the minimum number you need to purchase when you renew your license."
msgstr ""
@@ -25786,6 +26680,15 @@ msgstr ""
msgid "This user has no identities"
msgstr ""
+msgid "This user has previously committed to the %{name} project."
+msgstr ""
+
+msgid "This user has the %{access} role in the %{name} project."
+msgstr ""
+
+msgid "This user is the author of this %{noteable}."
+msgstr ""
+
msgid "This user will be the author of all events in the activity feed that are the result of an update, like new branches being created or new commits being pushed to existing branches."
msgstr ""
@@ -25816,6 +26719,9 @@ msgstr ""
msgid "Threat Monitoring"
msgstr ""
+msgid "ThreatMonitoring|All Environments"
+msgstr ""
+
msgid "ThreatMonitoring|Anomalous Requests"
msgstr ""
@@ -25843,9 +26749,6 @@ msgstr ""
msgid "ThreatMonitoring|Operations Per Second"
msgstr ""
-msgid "ThreatMonitoring|Overview"
-msgstr ""
-
msgid "ThreatMonitoring|Packet Activity"
msgstr ""
@@ -25864,6 +26767,9 @@ msgstr ""
msgid "ThreatMonitoring|Something went wrong, unable to fetch statistics"
msgstr ""
+msgid "ThreatMonitoring|Statistics"
+msgstr ""
+
msgid "ThreatMonitoring|The firewall is not installed or has been disabled. To view this data, ensure the web application firewall is installed and enabled for your cluster."
msgstr ""
@@ -26257,6 +27163,9 @@ msgstr ""
msgid "To update Snippets with multiple files, you must use the `files` parameter"
msgstr ""
+msgid "To use Gitpod you must first enable the feature in the integrations section of your %{user_prefs}."
+msgstr ""
+
msgid "To view all %{scannedResourcesCount} scanned URLs, please download the CSV file"
msgstr ""
@@ -26290,9 +27199,6 @@ msgstr ""
msgid "Toggle Sidebar"
msgstr ""
-msgid "Toggle all threads"
-msgstr ""
-
msgid "Toggle backtrace"
msgstr ""
@@ -26317,9 +27223,6 @@ msgstr ""
msgid "Toggle navigation"
msgstr ""
-msgid "Toggle project"
-msgstr ""
-
msgid "Toggle sidebar"
msgstr ""
@@ -26359,6 +27262,9 @@ msgstr ""
msgid "Too many projects enabled. You will need to manage them via the console or the API."
msgstr ""
+msgid "Too much data"
+msgstr ""
+
msgid "Topics (optional)"
msgstr ""
@@ -26377,6 +27283,9 @@ msgstr ""
msgid "Total cores (CPUs)"
msgstr ""
+msgid "Total days to completion"
+msgstr ""
+
msgid "Total issues"
msgstr ""
@@ -26473,6 +27382,9 @@ msgstr ""
msgid "Trending"
msgstr ""
+msgid "Trials|Create a new group to start your GitLab Gold trial."
+msgstr ""
+
msgid "Trials|Go back to GitLab"
msgstr ""
@@ -26482,6 +27394,15 @@ msgstr ""
msgid "Trials|You can always resume this process by selecting your avatar and choosing 'Start a Gold trial'"
msgstr ""
+msgid "Trials|You can apply your trial to a new group or an existing group."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group or your personal account."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group, an existing group, or your personal account."
+msgstr ""
+
msgid "Trials|You won't get a free trial right now but you can always resume this process by clicking on your avatar and choosing 'Start a free trial'"
msgstr ""
@@ -26551,6 +27472,9 @@ msgstr ""
msgid "Try using a different search term to find the file you are looking for."
msgstr ""
+msgid "Trying to communicate with your device. Plug it in (if needed) and press the button on the device now."
+msgstr ""
+
msgid "Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now."
msgstr ""
@@ -26638,6 +27562,12 @@ msgstr ""
msgid "URL or request ID"
msgstr ""
+msgid "USER %{user} WILL BE REMOVED! Are you sure?"
+msgstr ""
+
+msgid "USER WILL BE BLOCKED! Are you sure?"
+msgstr ""
+
msgid "UTC"
msgstr ""
@@ -26695,9 +27625,6 @@ msgstr ""
msgid "Unable to load the merge request widget. Try reloading the page."
msgstr ""
-msgid "Unable to resolve"
-msgstr ""
-
msgid "Unable to save iteration. Please try again"
msgstr ""
@@ -26746,6 +27673,9 @@ msgstr ""
msgid "Undo ignore"
msgstr ""
+msgid "Unexpected error"
+msgstr ""
+
msgid "Unfortunately, your email message to GitLab could not be processed."
msgstr ""
@@ -26779,6 +27709,9 @@ msgstr ""
msgid "Unknown response text"
msgstr ""
+msgid "Unless otherwise agreed to in writing with GitLab, by clicking \"Upload License\" you agree that your use of GitLab Software is subject to the %{eula_link_start}Terms of Service%{eula_link_end}."
+msgstr ""
+
msgid "Unlimited"
msgstr ""
@@ -27145,9 +28078,6 @@ msgstr ""
msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
msgstr ""
-msgid "Use a hardware device to add the second factor of authentication."
-msgstr ""
-
msgid "Use an one time password authenticator on your mobile device or computer to enable two-factor authentication (2FA)."
msgstr ""
@@ -27421,13 +28351,13 @@ msgstr ""
msgid "Users"
msgstr ""
-msgid "Users in License:"
+msgid "Users in License"
msgstr ""
-msgid "Users or groups set as approvers in the project's or merge request's settings."
+msgid "Users in License:"
msgstr ""
-msgid "Users outside of license"
+msgid "Users or groups set as approvers in the project's or merge request's settings."
msgstr ""
msgid "Users over License:"
@@ -27445,9 +28375,6 @@ msgstr ""
msgid "Users with a Guest role or those who don't belong to a Project or Group will not use a seat from your license."
msgstr ""
-msgid "Users with a Guest role or those who don't belong to any projects or groups don't count towards seats in use."
-msgstr ""
-
msgid "UsersSelect|%{name} + %{length} more"
msgstr ""
@@ -27487,9 +28414,6 @@ msgstr ""
msgid "Validations failed."
msgstr ""
-msgid "Validity"
-msgstr ""
-
msgid "Value"
msgstr ""
@@ -27508,6 +28432,9 @@ msgstr ""
msgid "Value Stream Name"
msgstr ""
+msgid "ValueStreamAnalyticsStage|We don't have enough data to show this stage."
+msgstr ""
+
msgid "ValueStreamAnalytics|%{days}d"
msgstr ""
@@ -27766,6 +28693,9 @@ msgstr ""
msgid "VisualReviewApp|Steps 1 and 2 (and sometimes 3) are performed once by the developer before requesting feedback. Steps 3 (if necessary), 4 is performed by the reviewer each time they perform a review."
msgstr ""
+msgid "Visualization"
+msgstr ""
+
msgid "Vulnerabilities"
msgstr ""
@@ -27793,34 +28723,31 @@ msgstr ""
msgid "VulnerabilityChart|Severity"
msgstr ""
-msgid "VulnerabilityManagement|A true-positive and will fix"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Change status"
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|Confirm"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Confirmed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
-msgstr ""
-
-msgid "VulnerabilityManagement|Detected %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|A true-positive and will fix"
msgstr ""
-msgid "VulnerabilityManagement|Dismiss"
+msgid "VulnerabilityManagement|Change status"
msgstr ""
-msgid "VulnerabilityManagement|Dismissed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
msgstr ""
-msgid "VulnerabilityManagement|Resolved"
+msgid "VulnerabilityManagement|Detected"
msgstr ""
-msgid "VulnerabilityManagement|Resolved %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Needs triage"
msgstr ""
msgid "VulnerabilityManagement|Something went wrong while trying to delete the comment. Please try again later."
@@ -27871,6 +28798,9 @@ msgstr ""
msgid "Vulnerability|%{scannerName} (version %{scannerVersion})"
msgstr ""
+msgid "Vulnerability|Activity"
+msgstr ""
+
msgid "Vulnerability|Class"
msgstr ""
@@ -27883,6 +28813,9 @@ msgstr ""
msgid "Vulnerability|Description"
msgstr ""
+msgid "Vulnerability|Detected"
+msgstr ""
+
msgid "Vulnerability|Evidence"
msgstr ""
@@ -27946,6 +28879,9 @@ msgstr ""
msgid "Warning: Displaying this diagram might cause performance issues on this page."
msgstr ""
+msgid "We are currently unable to fetch data for the pipeline header."
+msgstr ""
+
msgid "We are currently unable to fetch data for this graph."
msgstr ""
@@ -27985,6 +28921,12 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
+msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
+msgstr ""
+
+msgid "We would like to inform you that your subscription GitLab Enterprise Edition %{plan_name} is nearing its user limit. You have %{active_user_count} active users, which is almost at the user limit of %{maximum_user_count}."
+msgstr ""
+
msgid "We've found no vulnerabilities"
msgstr ""
@@ -28000,6 +28942,12 @@ msgstr ""
msgid "Web terminal"
msgstr ""
+msgid "WebAuthn Devices (%{length})"
+msgstr ""
+
+msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
+msgstr ""
+
msgid "WebIDE|Merge request"
msgstr ""
@@ -28138,15 +29086,9 @@ msgstr ""
msgid "Welcome to the guided GitLab tour"
msgstr ""
-msgid "Welcome to your Issue Board!"
-msgstr ""
-
msgid "Welcome to your issue board!"
msgstr ""
-msgid "We’ve been making changes to %{featureName} and we’d love your feedback %{linkStart}in this issue%{linkEnd} to help us improve the experience."
-msgstr ""
-
msgid "What are you searching for?"
msgstr ""
@@ -28165,6 +29107,9 @@ msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
msgstr ""
+msgid "When enabled, any user visiting %{host} and creating an account will have to be explicitly approved by the admin before they can login. This setting is effective only if sign-ups are enabled."
+msgstr ""
+
msgid "When enabled, any user visiting %{host} will be able to create an account."
msgstr ""
@@ -28390,6 +29335,9 @@ msgstr ""
msgid "With requirements, you can set criteria to check your products against."
msgstr ""
+msgid "With test cases, you can define conditions for your project to meet in determining quality"
+msgstr ""
+
msgid "Withdraw Access Request"
msgstr ""
@@ -28405,6 +29353,9 @@ msgstr ""
msgid "Workflow Help"
msgstr ""
+msgid "Would you like to create a new branch?"
+msgstr ""
+
msgid "Write"
msgstr ""
@@ -28426,6 +29377,9 @@ msgstr ""
msgid "Wrong extern UID provided. Make sure Auth0 is configured correctly."
msgstr ""
+msgid "YYYY-MM-DD"
+msgstr ""
+
msgid "Yes"
msgstr ""
@@ -28483,7 +29437,7 @@ msgstr ""
msgid "You are going to remove the fork relationship from %{project_full_name}. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "You are going to transfer %{project_full_name} to another owner. Are you ABSOLUTELY sure?"
+msgid "You are going to transfer %{project_full_name} to another namespace. Are you ABSOLUTELY sure?"
msgstr ""
msgid "You are going to turn off the confidentiality. This means %{strongStart}everyone%{strongEnd} will be able to see and leave a comment on this %{issuableType}."
@@ -28543,9 +29497,6 @@ msgstr ""
msgid "You can always edit this later"
msgstr ""
-msgid "You can apply your Trial to your Personal account or create a New Group."
-msgstr ""
-
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings"
msgstr ""
@@ -28567,12 +29518,18 @@ msgstr ""
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
+msgid "You can find more information about GitLab subscriptions in %{subscriptions_doc_link}."
+msgstr ""
+
msgid "You can generate an access token scoped to this project for each application to use the GitLab API."
msgstr ""
msgid "You can get started by cloning the repository or start adding files to it with one of the following options."
msgstr ""
+msgid "You can group test cases using labels. To learn about the future direction of this feature, visit %{linkStart}Quality Management direction page%{linkEnd}."
+msgstr ""
+
msgid "You can invite a new member to %{project_name} or invite another group."
msgstr ""
@@ -28588,6 +29545,9 @@ msgstr ""
msgid "You can notify the app / group or a project by sending them an email notification"
msgstr ""
+msgid "You can now close this window."
+msgstr ""
+
msgid "You can now export your security dashboard to a CSV report."
msgstr ""
@@ -28636,9 +29596,6 @@ msgstr ""
msgid "You can test your .gitlab-ci.yml in %{linkStart}CI Lint%{linkEnd}."
msgstr ""
-msgid "You can try again using %{begin_link}basic search%{end_link}"
-msgstr ""
-
msgid "You cannot access the raw file. Please wait a minute."
msgstr ""
@@ -28690,6 +29647,9 @@ msgstr ""
msgid "You don't have any U2F devices registered yet."
msgstr ""
+msgid "You don't have any WebAuthn devices registered yet."
+msgstr ""
+
msgid "You don't have any active chat names."
msgstr ""
@@ -28777,6 +29737,9 @@ msgstr ""
msgid "You must accept our Terms of Service and privacy policy in order to register an account"
msgstr ""
+msgid "You must be logged in to search across all of GitLab"
+msgstr ""
+
msgid "You must disassociate %{domain} from all clusters it is attached to before deletion."
msgstr ""
@@ -28816,7 +29779,7 @@ msgstr ""
msgid "You need to be logged in."
msgstr ""
-msgid "You need to register a two-factor authentication app before you can set up a U2F device."
+msgid "You need to register a two-factor authentication app before you can set up a device."
msgstr ""
msgid "You need to set terms to be enforced"
@@ -28834,6 +29797,9 @@ msgstr ""
msgid "You reached %{usage_in_percent} of %{namespace_name}'s storage capacity (%{used_storage} of %{storage_limit})"
msgstr ""
+msgid "You successfully declined the invitation"
+msgstr ""
+
msgid "You tried to fork %{link_to_the_project} but it failed for the following reason:"
msgstr ""
@@ -28999,10 +29965,13 @@ msgstr ""
msgid "Your U2F device did not send a valid JSON response."
msgstr ""
-msgid "Your U2F device needs to be set up. Plug it in (if not already) and click the button on the left."
+msgid "Your U2F device was registered!"
+msgstr ""
+
+msgid "Your WebAuthn device did not send a valid JSON response."
msgstr ""
-msgid "Your U2F device was registered!"
+msgid "Your WebAuthn device was registered!"
msgstr ""
msgid "Your access request to the %{source_type} has been withdrawn."
@@ -29026,6 +29995,9 @@ msgstr ""
msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
msgstr ""
+msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
+msgstr ""
+
msgid "Your changes can be committed to %{branch_name} because a merge request is open."
msgstr ""
@@ -29062,6 +30034,12 @@ msgstr ""
msgid "Your deployment services will be broken, you will need to manually fix the services after renaming."
msgstr ""
+msgid "Your device is not compatible with GitLab. Please try another device"
+msgstr ""
+
+msgid "Your device needs to be set up. Plug it in (if needed) and click the button on the left."
+msgstr ""
+
msgid "Your device was successfully set up! Give it a name and register it with the GitLab server."
msgstr ""
@@ -29176,9 +30154,6 @@ msgstr[2] ""
msgid "access:"
msgstr ""
-msgid "activated"
-msgstr ""
-
msgid "added %{created_at_timeago}"
msgstr ""
@@ -29251,9 +30226,21 @@ msgstr ""
msgid "by %{user}"
msgstr ""
+msgid "cannot be a date in the past"
+msgstr ""
+
msgid "cannot be changed if a personal project has container registry tags."
msgstr ""
+msgid "cannot be changed if shared runners are enabled"
+msgstr ""
+
+msgid "cannot be enabled because parent group does not allow it"
+msgstr ""
+
+msgid "cannot be enabled because parent group has shared Runners disabled"
+msgstr ""
+
msgid "cannot be enabled unless all domains have TLS certificates"
msgstr ""
@@ -29299,7 +30286,7 @@ msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about SAST %{linkEndTag}"
msgstr ""
-msgid "ciReport|%{linkStartTag}Learn more about Secret Scanning %{linkEndTag}"
+msgid "ciReport|%{linkStartTag}Learn more about Secret Detection %{linkEndTag}"
msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about codequality reports %{linkEndTag}"
@@ -29617,9 +30604,6 @@ msgstr ""
msgid "error"
msgstr "greška"
-msgid "error code:"
-msgstr ""
-
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr ""
@@ -29641,6 +30625,9 @@ msgstr ""
msgid "failed to dismiss associated finding(id=%{finding_id}): %{message}"
msgstr ""
+msgid "failed to revert associated finding(id=%{finding_id}) to detected"
+msgstr ""
+
msgid "file"
msgid_plural "files"
msgstr[0] ""
@@ -30187,6 +31174,9 @@ msgstr ""
msgid "must be a root namespace"
msgstr ""
+msgid "must be a valid IPv4 or IPv6 address"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -30223,6 +31213,9 @@ msgstr ""
msgid "no expiration"
msgstr ""
+msgid "no name set"
+msgstr ""
+
msgid "no one can merge"
msgstr ""
@@ -30406,9 +31399,6 @@ msgstr ""
msgid "security Reports|There was an error creating the merge request"
msgstr ""
-msgid "settings saved, but not activated"
-msgstr ""
-
msgid "severity|Critical"
msgstr ""
@@ -30535,9 +31525,6 @@ msgstr ""
msgid "toggle collapse"
msgstr ""
-msgid "toggle dropdown"
-msgstr ""
-
msgid "triggered"
msgstr ""
@@ -30565,6 +31552,9 @@ msgstr ""
msgid "user avatar"
msgstr ""
+msgid "user preferences"
+msgstr ""
+
msgid "username"
msgstr "korisniÄko ime"
diff --git a/locale/ca_ES/gitlab.po b/locale/ca_ES/gitlab.po
index d35b4a25cf7..77eb61ca568 100644
--- a/locale/ca_ES/gitlab.po
+++ b/locale/ca_ES/gitlab.po
@@ -14,7 +14,10 @@ msgstr ""
"X-Crowdin-Language: ca\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 6\n"
-"PO-Revision-Date: 2020-09-04 23:07\n"
+"PO-Revision-Date: 2020-10-02 18:46\n"
+
+msgid " %{project_name}#%{issue_iid} &middot; opened %{issue_created} by %{author}"
+msgstr ""
msgid " %{start} to %{end}"
msgstr " Des de %{start} fins %{end}"
@@ -74,6 +77,16 @@ msgstr "\"%{path}\" no existeix a \"%{ref}\""
msgid "\"el\" parameter is required for createInstance()"
msgstr ""
+msgid "%d Approval"
+msgid_plural "%d Approvals"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d Package"
+msgid_plural "%d Packages"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d Scanned URL"
msgid_plural "%d Scanned URLs"
msgstr[0] ""
@@ -137,6 +150,11 @@ msgstr[1] ""
msgid "%d commits"
msgstr ""
+msgid "%d completed issue"
+msgid_plural "%d completed issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d contribution"
msgid_plural "%d contributions"
msgstr[0] ""
@@ -147,6 +165,11 @@ msgid_plural "%d days"
msgstr[0] ""
msgstr[1] ""
+msgid "%d day until tags are automatically removed"
+msgid_plural "%d days until tags are automatically removed"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d error"
msgid_plural "%d errors"
msgstr[0] ""
@@ -237,6 +260,16 @@ msgid_plural "%d more comments"
msgstr[0] ""
msgstr[1] ""
+msgid "%d open issue"
+msgid_plural "%d open issues"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d pending comment"
+msgid_plural "%d pending comments"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d personal project will be removed and cannot be restored."
msgid_plural "%d personal projects will be removed and cannot be restored."
msgstr[0] ""
@@ -252,6 +285,11 @@ msgid_plural "%d projects"
msgstr[0] "%d projecte"
msgstr[1] "%d projectes"
+msgid "%d project selected"
+msgid_plural "%d projects selected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d request with warnings"
msgid_plural "%d requests with warnings"
msgstr[0] ""
@@ -272,6 +310,11 @@ msgid_plural "%d tags"
msgstr[0] ""
msgstr[1] ""
+msgid "%d tag per image name"
+msgid_plural "%d tags per image name"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d unassigned issue"
msgid_plural "%d unassigned issues"
msgstr[0] ""
@@ -292,6 +335,11 @@ msgid_plural "%d vulnerabilities dismissed"
msgstr[0] "%d vulnerabilitat descartada"
msgstr[1] "%d vulnerabilitats descartades"
+msgid "%d warning found:"
+msgid_plural "%d warnings found:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%s additional commit has been omitted to prevent performance issues."
msgid_plural "%s additional commits have been omitted to prevent performance issues."
msgstr[0] ""
@@ -330,6 +378,9 @@ msgstr ""
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr ""
+msgid "%{completedCount} completed weight"
+msgstr ""
+
msgid "%{completedWeight} of %{totalWeight} weight completed"
msgstr ""
@@ -378,14 +429,12 @@ msgid_plural "%{count} participants"
msgstr[0] "%{count} participant"
msgstr[1] "%{count} participants"
-msgid "%{count} pending comment"
-msgid_plural "%{count} pending comments"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
+msgid "%{count} total weight"
+msgstr ""
+
msgid "%{dashboard_path} could not be found."
msgstr ""
@@ -440,6 +489,9 @@ msgstr ""
msgid "%{group_name} uses group managed accounts. You need to create a new GitLab account which will be managed by %{group_name}."
msgstr ""
+msgid "%{group_name}&%{epic_iid} &middot; opened %{epic_created} by %{author}"
+msgstr ""
+
msgid "%{host} sign-in from new location"
msgstr ""
@@ -452,7 +504,7 @@ msgstr ""
msgid "%{issuableType} will be removed! Are you sure?"
msgstr ""
-msgid "%{issuesSize} issues with a limit of %{maxIssueCount}"
+msgid "%{issuesCount} issues with a limit of %{maxIssueCount}"
msgstr ""
msgid "%{issuesSize} with a limit of %{maxIssueCount}"
@@ -485,7 +537,7 @@ msgstr ""
msgid "%{labelStart}Namespace:%{labelEnd} %{namespace}"
msgstr ""
-msgid "%{labelStart}Report Type:%{labelEnd} %{reportType}"
+msgid "%{labelStart}Scan Type:%{labelEnd} %{reportType}"
msgstr ""
msgid "%{labelStart}Scanner:%{labelEnd} %{scanner}"
@@ -682,9 +734,6 @@ msgid_plural "%{securityScanner} results are not available because a pipeline ha
msgstr[0] ""
msgstr[1] ""
-msgid "%{service_title} %{message}."
-msgstr ""
-
msgid "%{size} GiB"
msgstr "%{size} GB"
@@ -773,6 +822,12 @@ msgstr ""
msgid "%{timebox_name} should belong either to a project or a group."
msgstr ""
+msgid "%{timebox_type} does not support burnup charts"
+msgstr ""
+
+msgid "%{timebox_type} must have a start and due date"
+msgstr ""
+
msgid "%{title} %{operator} %{threshold}"
msgstr ""
@@ -797,7 +852,7 @@ msgstr ""
msgid "%{total} open issue weight"
msgstr ""
-msgid "%{total} open issues"
+msgid "%{total} warnings found: showing first %{warningsDisplayed}"
msgstr ""
msgid "%{usage_ping_link_start}Learn more%{usage_ping_link_end} about what information is shared with GitLab Inc."
@@ -830,9 +885,6 @@ msgstr ""
msgid "&lt; 1 hour"
msgstr ""
-msgid "&lt;no name set&gt;"
-msgstr ""
-
msgid "&lt;no scopes selected&gt;"
msgstr ""
@@ -863,6 +915,9 @@ msgstr ""
msgid "'%{name}' Value Stream created"
msgstr ""
+msgid "'%{name}' Value Stream deleted"
+msgstr ""
+
msgid "'%{name}' stage already exists"
msgstr ""
@@ -922,6 +977,9 @@ msgstr ""
msgid "+ %{numberOfHiddenAssignees} more"
msgstr ""
+msgid "+ %{numberOfHiddenReviewers} more"
+msgstr ""
+
msgid "+%d more"
msgid_plural "+%d more"
msgstr[0] ""
@@ -982,6 +1040,11 @@ msgid_plural "%d Days"
msgstr[0] ""
msgstr[1] ""
+msgid "1 Issue"
+msgid_plural "%d Issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "1 closed issue"
msgid_plural "%{issues} closed issues"
msgstr[0] ""
@@ -997,6 +1060,11 @@ msgid_plural "%d days"
msgstr[0] ""
msgstr[1] ""
+msgid "1 deploy key"
+msgid_plural "%d deploy keys"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] "1 grup"
@@ -1099,6 +1167,9 @@ msgstr ""
msgid ":%{startLine} to %{endLine}"
msgstr ""
+msgid "A %{incident_docs_start}modified issue%{incident_docs_end} to guide the resolution of incidents."
+msgstr ""
+
msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr ""
@@ -1111,6 +1182,9 @@ msgstr ""
msgid "A GitBook site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
+msgid "A Gitpod configured Webapplication in Spring and Java"
+msgstr ""
+
msgid "A Hexo site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
@@ -1282,9 +1356,15 @@ msgstr ""
msgid "Access expiration date"
msgstr ""
+msgid "Access expires"
+msgstr ""
+
msgid "Access forbidden. Check your access level."
msgstr ""
+msgid "Access granted"
+msgstr ""
+
msgid "Access requests"
msgstr ""
@@ -1294,6 +1374,9 @@ msgstr ""
msgid "Access to Pages websites are controlled based on the user's membership to a given project. By checking this box, users will be required to be logged in to have access to all Pages websites in your instance."
msgstr ""
+msgid "AccessDropdown|Deploy Keys"
+msgstr ""
+
msgid "AccessDropdown|Groups"
msgstr ""
@@ -1411,12 +1494,6 @@ msgstr ""
msgid "Active Sessions"
msgstr "Sessions actives"
-msgid "Active Users:"
-msgstr ""
-
-msgid "Active users"
-msgstr ""
-
msgid "Activity"
msgstr "Activitat"
@@ -1584,9 +1661,6 @@ msgstr ""
msgid "Add label(s)"
msgstr ""
-msgid "Add license"
-msgstr "Afegeix una llicència"
-
msgid "Add list"
msgstr ""
@@ -1761,21 +1835,51 @@ msgstr ""
msgid "AdminArea|Bots"
msgstr ""
+msgid "AdminArea|Components"
+msgstr ""
+
msgid "AdminArea|Developer"
msgstr ""
+msgid "AdminArea|Features"
+msgstr ""
+
+msgid "AdminArea|Groups: %{number_of_groups}"
+msgstr ""
+
msgid "AdminArea|Guest"
msgstr ""
msgid "AdminArea|Included Free in license"
msgstr ""
+msgid "AdminArea|Latest groups"
+msgstr ""
+
+msgid "AdminArea|Latest projects"
+msgstr ""
+
+msgid "AdminArea|Latest users"
+msgstr ""
+
msgid "AdminArea|Maintainer"
msgstr ""
+msgid "AdminArea|New group"
+msgstr ""
+
+msgid "AdminArea|New project"
+msgstr ""
+
+msgid "AdminArea|New user"
+msgstr ""
+
msgid "AdminArea|Owner"
msgstr ""
+msgid "AdminArea|Projects: %{number_of_projects}"
+msgstr ""
+
msgid "AdminArea|Reporter"
msgstr ""
@@ -1803,6 +1907,9 @@ msgstr ""
msgid "AdminArea|Users without a Group and Project"
msgstr ""
+msgid "AdminArea|Users: %{number_of_users}"
+msgstr ""
+
msgid "AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running."
msgstr ""
@@ -1821,9 +1928,6 @@ msgstr ""
msgid "AdminProjects|Delete Project %{projectName}?"
msgstr ""
-msgid "AdminProjects|Delete project"
-msgstr ""
-
msgid "AdminSettings|Apply integration settings to all Projects"
msgstr ""
@@ -2061,21 +2165,30 @@ msgstr ""
msgid "AdminUsers|Without projects"
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 ""
msgid "AdminUsers|You cannot remove your own admin rights."
msgstr ""
+msgid "AdminUsers|You must transfer ownership or delete the groups owned by this user before you can delete their account"
+msgstr ""
+
msgid "Administration"
msgstr ""
msgid "Advanced"
msgstr ""
+msgid "Advanced Search"
+msgstr ""
+
+msgid "Advanced Search with Elasticsearch"
+msgstr ""
+
msgid "Advanced Settings"
msgstr ""
@@ -2153,6 +2266,9 @@ msgstr ""
msgid "AlertManagement|Edit"
msgstr ""
+msgid "AlertManagement|Environment"
+msgstr ""
+
msgid "AlertManagement|Events"
msgstr ""
@@ -2165,6 +2281,9 @@ msgstr ""
msgid "AlertManagement|Issue"
msgstr ""
+msgid "AlertManagement|Key"
+msgstr ""
+
msgid "AlertManagement|Low"
msgstr ""
@@ -2258,6 +2377,9 @@ msgstr ""
msgid "AlertManagement|Unknown"
msgstr ""
+msgid "AlertManagement|Value"
+msgstr ""
+
msgid "AlertManagement|View alerts in Opsgenie"
msgstr ""
@@ -2417,6 +2539,9 @@ msgstr ""
msgid "All projects"
msgstr ""
+msgid "All projects selected"
+msgstr ""
+
msgid "All security scans are enabled because %{linkStart}Auto DevOps%{linkEnd} is enabled on this project"
msgstr ""
@@ -2504,6 +2629,9 @@ msgstr ""
msgid "Almost there"
msgstr ""
+msgid "Already blocked"
+msgstr ""
+
msgid "Also called \"Issuer\" or \"Relying party trust identifier\""
msgstr ""
@@ -2558,6 +2686,9 @@ msgstr ""
msgid "An error has occurred"
msgstr ""
+msgid "An error occured while making the changes: %{error}"
+msgstr ""
+
msgid "An error occurred adding a draft to the thread."
msgstr ""
@@ -2585,12 +2716,6 @@ msgstr ""
msgid "An error occurred when toggling the notification subscription"
msgstr ""
-msgid "An error occurred when trying to resolve a comment. Please try again."
-msgstr ""
-
-msgid "An error occurred when trying to resolve a discussion. Please try again."
-msgstr ""
-
msgid "An error occurred when updating the issue weight"
msgstr ""
@@ -2606,12 +2731,6 @@ msgstr ""
msgid "An error occurred while checking group path. Please refresh and try again."
msgstr ""
-msgid "An error occurred while committing your changes."
-msgstr ""
-
-msgid "An error occurred while creating the list. Please try again."
-msgstr ""
-
msgid "An error occurred while decoding the file."
msgstr ""
@@ -2684,25 +2803,19 @@ msgstr ""
msgid "An error occurred while fetching the Service Desk address."
msgstr ""
-msgid "An error occurred while fetching the board issues. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the board lists. Please reload the page."
msgstr ""
msgid "An error occurred while fetching the board lists. Please try again."
msgstr ""
-msgid "An error occurred while fetching the board swimlanes. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the builds."
msgstr ""
msgid "An error occurred while fetching the job log."
msgstr ""
-msgid "An error occurred while fetching the job trace."
+msgid "An error occurred while fetching the job logs."
msgstr ""
msgid "An error occurred while fetching the job."
@@ -2849,9 +2962,6 @@ msgstr ""
msgid "An error occurred while saving assignees"
msgstr ""
-msgid "An error occurred while saving the template. Please check if the template exists."
-msgstr ""
-
msgid "An error occurred while searching for milestones"
msgstr ""
@@ -2870,10 +2980,10 @@ msgstr ""
msgid "An error occurred while updating approvers"
msgstr ""
-msgid "An error occurred while updating the comment"
+msgid "An error occurred while updating labels."
msgstr ""
-msgid "An error occurred while updating the list. Please try again."
+msgid "An error occurred while updating the comment"
msgstr ""
msgid "An error occurred while validating group path"
@@ -2927,6 +3037,9 @@ msgstr ""
msgid "An unknown error occurred while loading this graph."
msgstr ""
+msgid "An unknown error occurred."
+msgstr ""
+
msgid "Analytics"
msgstr "Analítiques"
@@ -2960,10 +3073,10 @@ msgstr "Verificació contra el correu brossa"
msgid "Any"
msgstr "Qualsevol"
-msgid "Any Author"
+msgid "Any %{header}"
msgstr ""
-msgid "Any Status"
+msgid "Any Author"
msgstr ""
msgid "Any branch"
@@ -3017,6 +3130,9 @@ msgstr "Aplicació"
msgid "Application ID"
msgstr "ID de l'aplicació"
+msgid "Application limits saved successfully"
+msgstr ""
+
msgid "Application settings saved successfully"
msgstr ""
@@ -3226,6 +3342,9 @@ msgstr ""
msgid "Are you sure you want to close this blocked issue?"
msgstr ""
+msgid "Are you sure you want to delete \"%{name}\" Value Stream?"
+msgstr ""
+
msgid "Are you sure you want to delete %{name}?"
msgstr ""
@@ -3235,6 +3354,9 @@ msgstr ""
msgid "Are you sure you want to delete this %{typeOfComment}?"
msgstr ""
+msgid "Are you sure you want to delete this SSH key?"
+msgstr ""
+
msgid "Are you sure you want to delete this board?"
msgstr ""
@@ -3259,6 +3381,11 @@ msgstr ""
msgid "Are you sure you want to erase this build?"
msgstr ""
+msgid "Are you sure you want to import %d repository?"
+msgid_plural "Are you sure you want to import %d repositories?"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Are you sure you want to lose unsaved changes?"
msgstr ""
@@ -3268,15 +3395,15 @@ msgstr ""
msgid "Are you sure you want to merge immediately?"
msgstr ""
-msgid "Are you sure you want to permanently delete this license?"
-msgstr ""
-
msgid "Are you sure you want to re-deploy this environment?"
msgstr ""
msgid "Are you sure you want to regenerate the public key? You will have to update the public key on the remote server before mirroring will work again."
msgstr ""
+msgid "Are you sure you want to reindex?"
+msgstr ""
+
msgid "Are you sure you want to remove %{group_name}?"
msgstr ""
@@ -3304,6 +3431,9 @@ msgstr ""
msgid "Are you sure you want to revoke this nickname?"
msgstr ""
+msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
+msgstr ""
+
msgid "Are you sure you want to stop this environment?"
msgstr ""
@@ -3325,6 +3455,9 @@ msgstr ""
msgid "Are you sure? The device will be signed out of GitLab and all remember me tokens revoked."
msgstr ""
+msgid "Are you sure? This will invalidate your registered applications and U2F / WebAuthn devices."
+msgstr ""
+
msgid "Are you sure? This will invalidate your registered applications and U2F devices."
msgstr ""
@@ -3343,9 +3476,6 @@ msgstr ""
msgid "Artifacts"
msgstr "Artefactes"
-msgid "As U2F devices are only supported by a few browsers, we require that you set up a two-factor authentication app before a U2F device. That way you'll always be able to log in - even when you're using an unsupported browser."
-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 ""
@@ -3539,6 +3669,9 @@ msgstr ""
msgid "AuditLogs|Target"
msgstr ""
+msgid "AuditLogs|This month"
+msgstr ""
+
msgid "AuditLogs|User Events"
msgstr ""
@@ -3578,6 +3711,9 @@ msgstr ""
msgid "Authentication via U2F device failed."
msgstr ""
+msgid "Authentication via WebAuthn device failed."
+msgstr ""
+
msgid "Author"
msgstr "Autor"
@@ -3845,15 +3981,6 @@ msgstr ""
msgid "BambooService|You must set up automatic revision labeling and a repository trigger in Bamboo."
msgstr ""
-msgid "BatchComments|Delete all pending comments"
-msgstr ""
-
-msgid "BatchComments|Discard review?"
-msgstr ""
-
-msgid "BatchComments|You're about to discard your review which will delete all of your pending comments. The deleted comments %{strong_start}cannot%{strong_end} be restored."
-msgstr ""
-
msgid "Be careful. Changing the project's namespace can have unintended side effects."
msgstr ""
@@ -3875,6 +4002,9 @@ msgstr ""
msgid "Bi-weekly code coverage"
msgstr ""
+msgid "Billable Users:"
+msgstr ""
+
msgid "Billing"
msgstr "Facturació"
@@ -3884,7 +4014,7 @@ msgstr ""
msgid "BillingPlans|@%{user_name} you are currently using the %{plan_name} plan."
msgstr ""
-msgid "BillingPlans|Congratulations, your new trial is activated"
+msgid "BillingPlans|Congratulations, your free trial is activated."
msgstr ""
msgid "BillingPlans|If you would like to downgrade your plan please contact %{support_link_start}Customer Support%{support_link_end}."
@@ -3947,6 +4077,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Block user"
+msgstr ""
+
msgid "Blocked"
msgstr ""
@@ -3962,31 +4095,37 @@ msgstr ""
msgid "Blog"
msgstr ""
-msgid "Board name"
-msgstr ""
-
msgid "Board scope"
msgstr ""
msgid "Board scope affects which issues are displayed for anyone who visits this board"
msgstr ""
-msgid "BoardBlankState|Add default lists"
+msgid "Boards"
+msgstr "Taulers"
+
+msgid "Boards and Board Lists"
msgstr ""
-msgid "BoardBlankState|Add the following default lists to your Issue Board with one click:"
+msgid "Boards|An error occurred while creating the issue. Please try again."
msgstr ""
-msgid "BoardBlankState|Nevermind, I'll use my own"
+msgid "Boards|An error occurred while creating the list. Please try again."
msgstr ""
-msgid "BoardBlankState|Starting out with the default set of lists will get you right on the way to making the most of your board."
+msgid "Boards|An error occurred while fetching issues. Please reload the page."
msgstr ""
-msgid "Boards"
-msgstr "Taulers"
+msgid "Boards|An error occurred while fetching the board issues. Please reload the page."
+msgstr ""
-msgid "Boards and Board Lists"
+msgid "Boards|An error occurred while fetching the board swimlanes. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while moving the issue. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while updating the list. Please try again."
msgstr ""
msgid "Boards|Collapse"
@@ -4013,7 +4152,7 @@ msgstr ""
msgid "Branch %{branch_name} was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr ""
-msgid "Branch has changed"
+msgid "Branch changed"
msgstr ""
msgid "Branch is already taken"
@@ -4319,6 +4458,9 @@ msgstr ""
msgid "CLOSED (MOVED)"
msgstr ""
+msgid "CODEOWNERS rule violation"
+msgstr ""
+
msgid "CONTRIBUTING"
msgstr ""
@@ -4349,9 +4491,6 @@ msgstr ""
msgid "Can't create snippet: %{err}"
msgstr ""
-msgid "Can't edit as source branch was deleted"
-msgstr ""
-
msgid "Can't fetch content for the blob: %{err}"
msgstr ""
@@ -4364,9 +4503,6 @@ msgstr ""
msgid "Can't load mermaid module: %{err}"
msgstr ""
-msgid "Can't remove group members without group managed account"
-msgstr ""
-
msgid "Can't scan the code?"
msgstr ""
@@ -4409,6 +4545,9 @@ msgstr ""
msgid "Cannot create the abuse report. This user has been blocked."
msgstr ""
+msgid "Cannot enable shared runners because parent group does not allow it"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -4514,6 +4653,15 @@ msgstr ""
msgid "Change your password or recover your current one"
msgstr ""
+msgid "ChangeReviewer|Reviewer changed from %{old} to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Reviewer changed to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Unassigned"
+msgstr ""
+
msgid "ChangeTypeActionLabel|Pick into branch"
msgstr ""
@@ -4553,6 +4701,9 @@ msgstr ""
msgid "Changes the title to \"%{title_param}\"."
msgstr ""
+msgid "Changes were successfully made."
+msgstr ""
+
msgid "Changes won't take place until the index is %{link_start}recreated%{link_end}."
msgstr ""
@@ -4958,6 +5109,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove variable"
+msgstr ""
+
msgid "CiVariables|Remove variable row"
msgstr ""
@@ -5036,9 +5190,6 @@ msgstr ""
msgid "Clear due date"
msgstr ""
-msgid "Clear input"
-msgstr ""
-
msgid "Clear recent searches"
msgstr ""
@@ -5087,6 +5238,9 @@ msgstr ""
msgid "Client authentication key password"
msgstr ""
+msgid "Client request timeout"
+msgstr ""
+
msgid "Clients"
msgstr "Clients"
@@ -5171,6 +5325,27 @@ msgstr ""
msgid "Cluster type must be specificed for Stages::ClusterEndpointInserter"
msgstr ""
+msgid "ClusterAgents|Configuration"
+msgstr ""
+
+msgid "ClusterAgents|Connect your cluster with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate Kubernetes with a GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Name"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Agent also requires %{linkStart}enabling the Agent Server%{linkEnd}"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Kubernetes Agent allows an Infrastructure as Code, GitOps approach to integrating Kubernetes clusters with GitLab. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "ClusterAgent|This feature is only available for premium plans"
msgstr ""
@@ -5240,10 +5415,10 @@ msgstr ""
msgid "ClusterIntegration|All installed applications and related resources"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster."
+msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{linkStart}More information%{linkEnd}"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{startLink}More information%{endLink}"
+msgid "ClusterIntegration|Allow GitLab to manage namespaces and service accounts for this cluster."
msgstr ""
msgid "ClusterIntegration|Alternatively, "
@@ -5264,6 +5439,9 @@ msgstr ""
msgid "ClusterIntegration|An error occurred while trying to fetch zone machine types: %{error}"
msgstr ""
+msgid "ClusterIntegration|An unknown error occurred while attempting to connect to Kubernetes."
+msgstr ""
+
msgid "ClusterIntegration|Any project namespaces"
msgstr ""
@@ -5279,6 +5457,9 @@ msgstr ""
msgid "ClusterIntegration|Authenticate with Amazon Web Services"
msgstr ""
+msgid "ClusterIntegration|Authentication Error"
+msgstr ""
+
msgid "ClusterIntegration|Base domain"
msgstr ""
@@ -5297,13 +5478,22 @@ msgstr ""
msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}security group %{externalLinkIcon} %{endLink} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
+msgid "ClusterIntegration|Check your CA certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Check your cluster status"
+msgstr ""
+
+msgid "ClusterIntegration|Check your token"
+msgstr ""
+
+msgid "ClusterIntegration|Choose the %{linkStart}security group %{linkEnd} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}subnets %{externalLinkIcon} %{endLink} in your VPC where your worker nodes will run."
+msgid "ClusterIntegration|Choose the %{linkStart}subnets %{linkEnd} in your VPC where your worker nodes will run."
msgstr ""
-msgid "ClusterIntegration|Choose the worker node %{startLink}instance type %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Choose the worker node %{linkStart}instance type%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Choose which applications to install on your Kubernetes cluster."
@@ -5315,10 +5505,7 @@ msgstr ""
msgid "ClusterIntegration|Clear cluster cache"
msgstr ""
-msgid "ClusterIntegration|Clear the local cache of namespace and service accounts. This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
-msgstr ""
-
-msgid "ClusterIntegration|Cluster being created"
+msgid "ClusterIntegration|Clear the local cache of namespace and service accounts."
msgstr ""
msgid "ClusterIntegration|Cluster management project (alpha)"
@@ -5330,15 +5517,21 @@ msgstr ""
msgid "ClusterIntegration|Cluster_applications artifact too big. Maximum allowable size: %{human_size}"
msgstr ""
-msgid "ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters."
+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|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}"
+msgid "ClusterIntegration|Clusters connected with a certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Connect cluster with certificate"
msgstr ""
msgid "ClusterIntegration|Connect existing cluster"
msgstr ""
+msgid "ClusterIntegration|Connection Error"
+msgstr ""
+
msgid "ClusterIntegration|Copy API URL"
msgstr ""
@@ -5414,6 +5607,12 @@ msgstr ""
msgid "ClusterIntegration|Deletes all GitLab resources attached to this cluster during removal"
msgstr ""
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared."
+msgstr ""
+
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared. %{linkStart}More information%{linkEnd}"
+msgstr ""
+
msgid "ClusterIntegration|Did you know?"
msgstr ""
@@ -5483,6 +5682,9 @@ msgstr ""
msgid "ClusterIntegration|Fluentd is an open source data collector, which lets you unify the data collection and consumption for a better use and understanding of data. It requires at least one of the following logs to be successfully installed."
msgstr ""
+msgid "ClusterIntegration|GitLab Agent managed clusters"
+msgstr ""
+
msgid "ClusterIntegration|GitLab Container Network Policies"
msgstr ""
@@ -5495,6 +5697,12 @@ msgstr ""
msgid "ClusterIntegration|GitLab Runner connects to the repository and executes CI/CD jobs, pushing results back and deploying applications to production."
msgstr ""
+msgid "ClusterIntegration|GitLab failed to authenticate."
+msgstr ""
+
+msgid "ClusterIntegration|GitLab failed to connect to the cluster."
+msgstr ""
+
msgid "ClusterIntegration|GitLab-managed cluster"
msgstr ""
@@ -5516,6 +5724,9 @@ msgstr ""
msgid "ClusterIntegration|Group cluster"
msgstr ""
+msgid "ClusterIntegration|HTTP Error"
+msgstr ""
+
msgid "ClusterIntegration|Helm Tiller"
msgstr ""
@@ -5549,7 +5760,10 @@ msgstr ""
msgid "ClusterIntegration|Instance type"
msgstr ""
-msgid "ClusterIntegration|Integrate Kubernetes cluster automation"
+msgid "ClusterIntegration|Integrate Kubernetes with a cluster certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Integrate with a cluster certificate"
msgstr ""
msgid "ClusterIntegration|Issuer Email"
@@ -5585,9 +5799,6 @@ msgstr ""
msgid "ClusterIntegration|Knative extends Kubernetes to provide a set of middleware components that are essential to build modern, source-centric, and container-based applications that can run anywhere: on premises, in the cloud, or even in a third-party data center."
msgstr ""
-msgid "ClusterIntegration|Kubernetes cluster"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes cluster is being created..."
msgstr ""
@@ -5600,9 +5811,6 @@ msgstr ""
msgid "ClusterIntegration|Kubernetes clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr ""
-msgid "ClusterIntegration|Kubernetes clusters can be used to deploy applications and to provide Review Apps for this project"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes version"
msgstr ""
@@ -5615,7 +5823,7 @@ msgstr ""
msgid "ClusterIntegration|Learn more about %{help_link_start}zones%{help_link_end}."
msgstr ""
-msgid "ClusterIntegration|Learn more about %{startLink}Regions %{externalLinkIcon}%{endLink}."
+msgid "ClusterIntegration|Learn more about %{linkStart}Regions%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Learn more about Kubernetes"
@@ -5660,12 +5868,18 @@ msgstr ""
msgid "ClusterIntegration|Machine type"
msgstr ""
+msgid "ClusterIntegration|Make sure your API endpoint is correct"
+msgstr ""
+
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create Kubernetes clusters"
msgstr ""
msgid "ClusterIntegration|Manage your Kubernetes cluster by visiting %{provider_link}"
msgstr ""
+msgid "ClusterIntegration|Namespace per environment"
+msgstr ""
+
msgid "ClusterIntegration|No IAM Roles found"
msgstr ""
@@ -5711,6 +5925,9 @@ msgstr ""
msgid "ClusterIntegration|No zones matched your search"
msgstr ""
+msgid "ClusterIntegration|Node calculations use the Kubernetes Metrics API. Make sure your cluster has metrics installed"
+msgstr ""
+
msgid "ClusterIntegration|Number of nodes"
msgstr ""
@@ -5753,6 +5970,9 @@ msgstr ""
msgid "ClusterIntegration|RBAC-enabled cluster"
msgstr ""
+msgid "ClusterIntegration|Read our %{linkStart}help page%{linkEnd} on Kubernetes cluster integration."
+msgstr ""
+
msgid "ClusterIntegration|Read our %{link_start}help page%{link_end} on Kubernetes cluster integration."
msgstr ""
@@ -5855,7 +6075,7 @@ msgstr ""
msgid "ClusterIntegration|Select a VPC to choose a subnet"
msgstr ""
-msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{linkStart}Amazon Web Services %{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select a network to choose a subnetwork"
@@ -5888,7 +6108,7 @@ msgstr ""
msgid "ClusterIntegration|Select project to choose zone"
msgstr ""
-msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select zone"
@@ -5978,9 +6198,18 @@ msgstr ""
msgid "ClusterIntegration|There was a problem authenticating with your cluster. Please ensure your CA Certificate and Token are valid."
msgstr ""
+msgid "ClusterIntegration|There was an HTTP error when connecting to your cluster."
+msgstr ""
+
msgid "ClusterIntegration|This account must have permissions to create a Kubernetes cluster in the %{link_to_container_project} specified below"
msgstr ""
+msgid "ClusterIntegration|This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
+msgstr ""
+
+msgid "ClusterIntegration|This is necessary to clear existing environment-namespace associations from clusters previously managed by GitLab."
+msgstr ""
+
msgid "ClusterIntegration|This option will allow you to install applications on RBAC clusters."
msgstr ""
@@ -6005,9 +6234,21 @@ msgstr ""
msgid "ClusterIntegration|To use a new project, first create one on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}."
msgstr ""
+msgid "ClusterIntegration|Troubleshooting tips:"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Authenticate"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Connect"
+msgstr ""
+
msgid "ClusterIntegration|Uninstall %{appTitle}"
msgstr ""
+msgid "ClusterIntegration|Unknown Error"
+msgstr ""
+
msgid "ClusterIntegration|Update %{appTitle}"
msgstr ""
@@ -6068,7 +6309,7 @@ msgstr ""
msgid "ClusterIntegration|Your cluster API is unreachable. Please ensure your API URL is correct."
msgstr ""
-msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Zone"
@@ -6188,6 +6429,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse all threads"
+msgstr ""
+
msgid "Collapse approvers"
msgstr ""
@@ -6337,7 +6581,7 @@ msgstr ""
msgid "Commit…"
msgstr ""
-msgid "Company"
+msgid "Community forum"
msgstr ""
msgid "Company name"
@@ -6346,6 +6590,9 @@ msgstr ""
msgid "Compare"
msgstr "Compara"
+msgid "Compare %{oldCommitId}...%{newCommitId}"
+msgstr ""
+
msgid "Compare Git revisions"
msgstr ""
@@ -6361,6 +6608,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare submodule commit revisions"
+msgstr ""
+
msgid "Compare with previous version"
msgstr ""
@@ -6496,6 +6746,9 @@ msgstr ""
msgid "Configure the way a user creates a new account."
msgstr ""
+msgid "Configure which lists are shown for anyone who visits this board"
+msgstr ""
+
msgid "Confirm"
msgstr ""
@@ -6721,6 +6974,9 @@ msgstr[1] ""
msgid "ContainerRegistry|Set cleanup policy"
msgstr ""
+msgid "ContainerRegistry|Some tags were not deleted"
+msgstr ""
+
msgid "ContainerRegistry|Something went wrong while fetching the cleanup policy."
msgstr ""
@@ -6760,6 +7016,9 @@ msgstr ""
msgid "ContainerRegistry|Tags with names matching this regex pattern will %{italicStart}expire:%{italicEnd}"
msgstr ""
+msgid "ContainerRegistry|The cleanup policy timed out before it could delete all tags. An administrator can %{adminLinkStart}manually run cleanup now%{adminLinkEnd} or you can wait for the cleanup policy to automatically run again. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "ContainerRegistry|The last tag related to this image was recently removed. This empty image and any associated data will be automatically removed as part of the regular Garbage Collection process. If you have any questions, contact your administrator."
msgstr ""
@@ -6892,6 +7151,9 @@ msgstr ""
msgid "Contributions per group member"
msgstr ""
+msgid "Contributor"
+msgstr ""
+
msgid "Contributors"
msgstr ""
@@ -7021,6 +7283,9 @@ msgstr ""
msgid "Could not change HEAD: branch '%{branch}' does not exist"
msgstr ""
+msgid "Could not commit. An unexpected error occurred."
+msgstr ""
+
msgid "Could not connect to FogBugz, check your URL"
msgstr ""
@@ -7060,6 +7325,9 @@ msgstr ""
msgid "Could not find iteration"
msgstr ""
+msgid "Could not load instance counts. Please refresh the page to try again."
+msgstr ""
+
msgid "Could not remove the trigger."
msgstr ""
@@ -7084,10 +7352,10 @@ msgstr ""
msgid "Could not save prometheus manual configuration"
msgstr ""
-msgid "Could not udpdate wiki page"
+msgid "Could not update the LDAP settings"
msgstr ""
-msgid "Could not update the LDAP settings"
+msgid "Could not update wiki page"
msgstr ""
msgid "Could not upload your designs as one or more files uploaded are not supported."
@@ -7745,6 +8013,9 @@ msgstr ""
msgid "DastProfiles|Are you sure you want to delete this profile?"
msgstr ""
+msgid "DastProfiles|Could not create site validation token. Please refresh the page, or try again later."
+msgstr ""
+
msgid "DastProfiles|Could not create the scanner profile. Please try again."
msgstr ""
@@ -7769,6 +8040,12 @@ msgstr ""
msgid "DastProfiles|Could not fetch site profiles. Please refresh the page, or try again later."
msgstr ""
+msgid "DastProfiles|Could not retrieve site validation status. Please refresh the page, or try again later."
+msgstr ""
+
+msgid "DastProfiles|Could not update the scanner profile. Please try again."
+msgstr ""
+
msgid "DastProfiles|Could not update the site profile. Please try again."
msgstr ""
@@ -7784,7 +8061,7 @@ msgstr ""
msgid "DastProfiles|Download validation text file"
msgstr ""
-msgid "DastProfiles|Edit feature will come soon. Please create a new profile if changes needed"
+msgid "DastProfiles|Edit scanner profile"
msgstr ""
msgid "DastProfiles|Edit site profile"
@@ -7817,6 +8094,9 @@ msgstr ""
msgid "DastProfiles|No profiles created yet"
msgstr ""
+msgid "DastProfiles|Passive"
+msgstr ""
+
msgid "DastProfiles|Please enter a valid URL format, ex: http://www.example.com/home"
msgstr ""
@@ -7832,6 +8112,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan mode"
+msgstr ""
+
msgid "DastProfiles|Scanner Profile"
msgstr ""
@@ -7871,10 +8154,10 @@ msgstr ""
msgid "DastProfiles|Text file validation"
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
+msgid "DastProfiles|The maximum number of minutes allowed for the spider to traverse the site."
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the spider to traverse the site."
+msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
msgstr ""
msgid "DastProfiles|Validate"
@@ -7907,6 +8190,9 @@ msgstr ""
msgid "Date picker"
msgstr "Selector de data"
+msgid "Date range"
+msgstr ""
+
msgid "Date range cannot exceed %{maxDateRange} days."
msgstr ""
@@ -7931,6 +8217,9 @@ msgstr ""
msgid "Days to merge"
msgstr ""
+msgid "Dear Administrator,"
+msgstr ""
+
msgid "Debug"
msgstr "Depura"
@@ -8042,12 +8331,18 @@ msgstr ""
msgid "Delete"
msgstr "Suprimeix"
+msgid "Delete %{name}"
+msgstr ""
+
msgid "Delete Comment"
msgstr ""
msgid "Delete Snippet"
msgstr ""
+msgid "Delete Value Stream"
+msgstr ""
+
msgid "Delete account"
msgstr ""
@@ -8069,9 +8364,6 @@ msgstr ""
msgid "Delete label: %{label_name} ?"
msgstr ""
-msgid "Delete license"
-msgstr ""
-
msgid "Delete list"
msgstr "Suprimeix la llista"
@@ -8147,15 +8439,6 @@ msgstr ""
msgid "Deleting a project places it into a read-only state until %{date}, at which point the project will be permanently deleted. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "Deleting the license failed."
-msgstr ""
-
-msgid "Deleting the license failed. The license was not found."
-msgstr ""
-
-msgid "Deleting the license failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "Deleting the project will delete its repository and all related resources including issues, merge requests etc."
msgstr ""
@@ -8651,7 +8934,10 @@ msgstr ""
msgid "DesignManagement|The maximum number of designs allowed to be uploaded is %{upload_limit}. Please try again."
msgstr ""
-msgid "DesignManagement|To upload designs, you'll need to enable LFS. %{requirements_link_start}More information%{requirements_link_end}"
+msgid "DesignManagement|There was an error moving your designs. Please upload your designs below."
+msgstr ""
+
+msgid "DesignManagement|To upload designs, you'll need to enable LFS and have admin enable hashed storage. %{requirements_link_start}More information%{requirements_link_end}"
msgstr ""
msgid "DesignManagement|Unresolve thread"
@@ -8663,6 +8949,9 @@ msgstr ""
msgid "DesignManagement|Upload skipped."
msgstr ""
+msgid "DesignManagement|Your designs are being copied and are on their way… Please refresh to update."
+msgstr ""
+
msgid "DesignManagement|and %{moreCount} more."
msgstr ""
@@ -8720,6 +9009,9 @@ msgstr ""
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
+msgid "Direct member"
+msgstr ""
+
msgid "Direction"
msgstr "Direcció"
@@ -8768,9 +9060,6 @@ msgstr ""
msgid "Discard draft"
msgstr ""
-msgid "Discard review"
-msgstr ""
-
msgid "DiscordService|Discord Notifications"
msgstr ""
@@ -8839,10 +9128,10 @@ msgstr ""
msgid "Dismiss Merge Request promotion"
msgstr ""
-msgid "Dismiss Selected"
+msgid "Dismiss Value Stream Analytics introduction box"
msgstr ""
-msgid "Dismiss Value Stream Analytics introduction box"
+msgid "Dismiss selected"
msgstr ""
msgid "Dismiss trial promotion"
@@ -8893,9 +9182,6 @@ msgstr ""
msgid "Documents reindexed: %{processed_documents} (%{percentage}%%)"
msgstr ""
-msgid "Doing"
-msgstr ""
-
msgid "Domain"
msgstr "Domini"
@@ -9091,9 +9377,6 @@ msgstr ""
msgid "Edit environment"
msgstr ""
-msgid "Edit file"
-msgstr ""
-
msgid "Edit files in the editor and commit changes here"
msgstr ""
@@ -9106,6 +9389,12 @@ msgstr "Edita el grup: %{group_name}"
msgid "Edit identity for %{user_name}"
msgstr ""
+msgid "Edit in Web IDE"
+msgstr ""
+
+msgid "Edit in single-file editor"
+msgstr ""
+
msgid "Edit issues"
msgstr ""
@@ -9133,19 +9422,16 @@ msgstr ""
msgid "Editing"
msgstr ""
-msgid "Elasticsearch"
-msgstr "Elasticsearch"
-
msgid "Elasticsearch AWS IAM credentials"
msgstr ""
-msgid "Elasticsearch indexing restrictions"
+msgid "Elasticsearch HTTP client timeout value in seconds."
msgstr ""
-msgid "Elasticsearch indexing started"
+msgid "Elasticsearch indexing restrictions"
msgstr ""
-msgid "Elasticsearch integration. Elasticsearch AWS IAM."
+msgid "Elasticsearch indexing started"
msgstr ""
msgid "Elasticsearch reindexing is already in progress"
@@ -9175,9 +9461,6 @@ msgstr ""
msgid "Email Notification"
msgstr ""
-msgid "Email address"
-msgstr ""
-
msgid "Email could not be sent"
msgstr ""
@@ -9241,6 +9524,9 @@ msgstr ""
msgid "Emails sent from Service Desk will have this name"
msgstr ""
+msgid "Emails sent to %{email} will still be supported"
+msgstr ""
+
msgid "Emails separated by comma"
msgstr ""
@@ -9274,9 +9560,18 @@ msgstr ""
msgid "Enable"
msgstr "Activa"
+msgid "Enable %{link_start}Gitpod%{link_end} integration to launch a development environment in your browser directly from GitLab."
+msgstr ""
+
msgid "Enable Auto DevOps"
msgstr ""
+msgid "Enable Gitpod"
+msgstr ""
+
+msgid "Enable Gitpod?"
+msgstr ""
+
msgid "Enable HTML emails"
msgstr ""
@@ -9406,9 +9701,6 @@ msgstr ""
msgid "Encountered an error while rendering: %{err}"
msgstr ""
-msgid "End date"
-msgstr ""
-
msgid "Ends at (UTC)"
msgstr ""
@@ -9568,7 +9860,7 @@ msgstr ""
msgid "EnvironmentsDashboard|The environments dashboard provides a summary of each project's environments' status, including pipeline and alert statuses."
msgstr ""
-msgid "EnvironmentsDashboard|This dashboard displays a maximum of 7 projects and 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
+msgid "EnvironmentsDashboard|This dashboard displays 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
msgstr ""
msgid "Environments|An error occurred while canceling the auto stop, please try again"
@@ -9889,6 +10181,9 @@ msgstr ""
msgid "Error deleting project. Check logs for error details."
msgstr ""
+msgid "Error fetching burnup chart data"
+msgstr ""
+
msgid "Error fetching diverging counts for branches. Please try again."
msgstr ""
@@ -9967,6 +10262,9 @@ msgstr ""
msgid "Error occurred when saving assignees"
msgstr ""
+msgid "Error occurred when saving reviewers"
+msgstr ""
+
msgid "Error occurred when toggling the notification subscription"
msgstr ""
@@ -10219,10 +10517,13 @@ msgstr ""
msgid "Expand all"
msgstr ""
-msgid "Expand approvers"
+msgid "Expand all files"
msgstr ""
-msgid "Expand dropdown"
+msgid "Expand all threads"
+msgstr ""
+
+msgid "Expand approvers"
msgstr ""
msgid "Expand milestones"
@@ -10393,6 +10694,9 @@ msgstr ""
msgid "Failed to create Merge Request. Please try again."
msgstr ""
+msgid "Failed to create To-Do for the design."
+msgstr ""
+
msgid "Failed to create a branch for this issue. Please try again."
msgstr ""
@@ -10432,6 +10736,12 @@ msgstr ""
msgid "Failed to load authors. Please try again."
msgstr ""
+msgid "Failed to load branches. Please try again."
+msgstr ""
+
+msgid "Failed to load deploy keys."
+msgstr ""
+
msgid "Failed to load emoji list."
msgstr ""
@@ -10447,6 +10757,9 @@ msgstr ""
msgid "Failed to load groups & users."
msgstr ""
+msgid "Failed to load groups, users and deploy keys."
+msgstr ""
+
msgid "Failed to load labels. Please try again."
msgstr ""
@@ -10456,6 +10769,12 @@ msgstr ""
msgid "Failed to load related branches"
msgstr ""
+msgid "Failed to load sidebar confidential toggle"
+msgstr ""
+
+msgid "Failed to load sidebar lock status"
+msgstr ""
+
msgid "Failed to load stacktrace."
msgstr ""
@@ -10483,6 +10802,9 @@ msgstr ""
msgid "Failed to publish issue on status page."
msgstr ""
+msgid "Failed to remove To-Do for the design."
+msgstr ""
+
msgid "Failed to remove a Zoom meeting"
msgstr ""
@@ -10525,6 +10847,9 @@ msgstr ""
msgid "Failed to signing using smartcard authentication"
msgstr ""
+msgid "Failed to toggle To-Do for the design."
+msgstr ""
+
msgid "Failed to update branch!"
msgstr ""
@@ -10638,7 +10963,7 @@ msgstr ""
msgid "FeatureFlags|Edit User List"
msgstr ""
-msgid "FeatureFlags|Enable features for specific users and specific environments by defining feature flag strategies."
+msgid "FeatureFlags|Enable features for specific users and environments by configuring feature flag strategies."
msgstr ""
msgid "FeatureFlags|Environment Spec"
@@ -10698,7 +11023,7 @@ msgstr ""
msgid "FeatureFlags|Include additional user IDs"
msgstr ""
-msgid "FeatureFlags|Install a %{docs_link_anchored_start}compatible client library%{docs_link_anchored_end} and specify the API URL, application name, and instance ID during the configuration setup. %{docs_link_start}More Information%{docs_link_end}"
+msgid "FeatureFlags|Install a %{docsLinkAnchoredStart}compatible client library%{docsLinkAnchoredEnd} and specify the API URL, application name, and instance ID during the configuration setup. %{docsLinkStart}More Information%{docsLinkEnd}"
msgstr ""
msgid "FeatureFlags|Instance ID"
@@ -10710,6 +11035,9 @@ msgstr ""
msgid "FeatureFlags|Loading feature flags"
msgstr ""
+msgid "FeatureFlags|Loading user lists"
+msgstr ""
+
msgid "FeatureFlags|More information"
msgstr ""
@@ -10728,7 +11056,7 @@ msgstr ""
msgid "FeatureFlags|New feature flag"
msgstr ""
-msgid "FeatureFlags|New list"
+msgid "FeatureFlags|New user list"
msgstr ""
msgid "FeatureFlags|Percent of users"
@@ -10767,6 +11095,9 @@ msgstr ""
msgid "FeatureFlags|There was an error fetching the feature flags."
msgstr ""
+msgid "FeatureFlags|There was an error fetching the user lists."
+msgstr ""
+
msgid "FeatureFlags|There was an error retrieving user lists"
msgstr ""
@@ -10782,6 +11113,9 @@ msgstr ""
msgid "FeatureFlags|User List"
msgstr ""
+msgid "FeatureFlags|User Lists"
+msgstr ""
+
msgid "FeatureFlag|List"
msgstr ""
@@ -10809,15 +11143,6 @@ msgstr "febrer"
msgid "Fetching incoming email"
msgstr ""
-msgid "Fetching licenses failed."
-msgstr ""
-
-msgid "Fetching licenses failed. The request endpoint was not found."
-msgstr ""
-
-msgid "Fetching licenses failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "File"
msgstr ""
@@ -10920,12 +11245,21 @@ msgstr ""
msgid "Filter by status"
msgstr ""
+msgid "Filter by test cases that are currently archived."
+msgstr ""
+
+msgid "Filter by test cases that are currently opened."
+msgstr ""
+
msgid "Filter by two-factor authentication"
msgstr ""
msgid "Filter by user"
msgstr ""
+msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
+msgstr ""
+
msgid "Filter pipelines"
msgstr ""
@@ -10941,7 +11275,7 @@ msgstr ""
msgid "Filter results..."
msgstr ""
-msgid "Filter your projects by name"
+msgid "Filter your repositories by name"
msgstr ""
msgid "Filter..."
@@ -10950,7 +11284,7 @@ msgstr "Filtra..."
msgid "Find File"
msgstr ""
-msgid "Find bugs in your code with coverage-guided fuzzing"
+msgid "Find bugs in your code with coverage-guided fuzzing."
msgstr ""
msgid "Find by path"
@@ -10977,9 +11311,6 @@ msgstr ""
msgid "Finish editing this message first!"
msgstr ""
-msgid "Finish review"
-msgstr ""
-
msgid "Finish setting up your dedicated account for %{group_name}."
msgstr ""
@@ -11049,6 +11380,9 @@ msgstr "Color del tipus de lletra"
msgid "Footer message"
msgstr "Missatge a peu de pàgina"
+msgid "For a faster browsing experience, some files are collapsed by default."
+msgstr ""
+
msgid "For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
@@ -11058,6 +11392,9 @@ msgstr ""
msgid "For more info, read the documentation."
msgstr ""
+msgid "For more information on how the number of active users is calculated, see the %{self_managed_subscriptions_doc_link} documentation."
+msgstr ""
+
msgid "For more information, go to the "
msgstr ""
@@ -11196,6 +11533,9 @@ msgstr ""
msgid "Generate new token"
msgstr ""
+msgid "Generic package file size in bytes"
+msgstr ""
+
msgid "Geo"
msgstr ""
@@ -11457,6 +11797,9 @@ msgstr ""
msgid "Geo|Please refer to Geo Troubleshooting."
msgstr ""
+msgid "Geo|Primary node"
+msgstr ""
+
msgid "Geo|Project"
msgstr ""
@@ -11499,6 +11842,9 @@ msgstr ""
msgid "Geo|Review replication status, and resynchronize and reverify items with the primary node."
msgstr ""
+msgid "Geo|Secondary node"
+msgstr ""
+
msgid "Geo|Status"
msgstr "Estat"
@@ -11538,6 +11884,9 @@ msgstr ""
msgid "Geo|URL must be a valid url (ex: https://gitlab.com)"
msgstr ""
+msgid "Geo|Undefined"
+msgstr ""
+
msgid "Geo|Unknown state"
msgstr "Estat desconegut"
@@ -11613,10 +11962,16 @@ msgstr ""
msgid "GitHub import"
msgstr ""
+msgid "GitLab"
+msgstr ""
+
msgid "GitLab / Unsubscribe"
msgstr ""
-msgid "GitLab Enterprise Edition %{plan}"
+msgid "GitLab API"
+msgstr ""
+
+msgid "GitLab Billing Team."
msgstr ""
msgid "GitLab Group Runners can execute code for all the projects in this group."
@@ -11628,12 +11983,18 @@ msgstr ""
msgid "GitLab Issue"
msgstr ""
+msgid "GitLab Pages"
+msgstr ""
+
msgid "GitLab Service Desk is a simple way to allow people to create issues in your GitLab instance without needing their own user account. It provides a unique email address for end users to create issues in a project, and replies can be sent either through the GitLab interface or by email. End users will only see the thread through email."
msgstr ""
msgid "GitLab Shared Runners execute code of different projects on the same Runner unless you configure GitLab Runner Autoscale with MaxBuilds 1 (which it is on GitLab.com)."
msgstr ""
+msgid "GitLab Shell"
+msgstr ""
+
msgid "GitLab Support Bot"
msgstr ""
@@ -11643,7 +12004,7 @@ msgstr ""
msgid "GitLab User"
msgstr "Usuari del GitLab"
-msgid "GitLab allows you to continue using your license even if you exceed the number of seats you purchased. You will be required to pay for these seats when you renew your license."
+msgid "GitLab Workhorse"
msgstr ""
msgid "GitLab commit"
@@ -11811,6 +12172,21 @@ msgstr ""
msgid "Gitlab Pages"
msgstr ""
+msgid "Gitpod"
+msgstr ""
+
+msgid "Gitpod|Add the URL to your Gitpod instance configured to read your GitLab projects."
+msgstr ""
+
+msgid "Gitpod|Enable Gitpod integration"
+msgstr ""
+
+msgid "Gitpod|Gitpod URL"
+msgstr ""
+
+msgid "Gitpod|e.g. https://gitpod.example.com"
+msgstr ""
+
msgid "Given access %{time_ago}"
msgstr ""
@@ -12318,9 +12694,6 @@ msgstr ""
msgid "GroupSAML|Valid SAML Response"
msgstr ""
-msgid "GroupSAML|With group managed accounts enabled, all the users without a group managed account will be excluded from the group."
-msgstr ""
-
msgid "GroupSAML|With prohibit outer forks flag enabled group members will be able to fork project only inside your group."
msgstr ""
@@ -12534,10 +12907,10 @@ msgstr ""
msgid "GroupsNew|Create group"
msgstr ""
-msgid "GroupsNew|GitLab group export"
+msgid "GroupsNew|Import"
msgstr ""
-msgid "GroupsNew|Import"
+msgid "GroupsNew|Import a GitLab group export file"
msgstr ""
msgid "GroupsNew|Import group"
@@ -12680,6 +13053,9 @@ msgid_plural "Hide charts"
msgstr[0] ""
msgstr[1] ""
+msgid "Hide comments on this file"
+msgstr ""
+
msgid "Hide details"
msgstr ""
@@ -12724,6 +13100,15 @@ msgstr ""
msgid "Highest role:"
msgstr ""
+msgid "HighlightBar|Alert events:"
+msgstr ""
+
+msgid "HighlightBar|Alert start time:"
+msgstr ""
+
+msgid "HighlightBar|Original alert:"
+msgstr ""
+
msgid "History"
msgstr "Historial"
@@ -12901,6 +13286,9 @@ msgstr ""
msgid "If enabled, access to projects will be validated on an external service using their classification label."
msgstr ""
+msgid "If the number of active users exceeds the user limit, you will be charged for the number of %{users_over_license_link} at your next license reconciliation."
+msgstr ""
+
msgid "If there is no previous license or if the previous license has expired, some GitLab functionality will be blocked until a new, valid license is uploaded."
msgstr ""
@@ -12940,9 +13328,6 @@ msgstr ""
msgid "If your HTTP repository is not publicly accessible, add your credentials."
msgstr ""
-msgid "Iglu registry URL (optional)"
-msgstr ""
-
msgid "Ignore"
msgstr ""
@@ -12979,6 +13364,16 @@ msgstr ""
msgid "Import"
msgstr "Importa"
+msgid "Import %d compatible repository"
+msgid_plural "Import %d compatible repositories"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Import %d repository"
+msgid_plural "Import %d repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Import CSV"
msgstr ""
@@ -12988,15 +13383,9 @@ msgstr ""
msgid "Import all compatible projects"
msgstr ""
-msgid "Import all compatible repositories"
-msgstr ""
-
msgid "Import all projects"
msgstr ""
-msgid "Import all repositories"
-msgstr ""
-
msgid "Import an exported GitLab project"
msgstr ""
@@ -13084,6 +13473,9 @@ msgstr ""
msgid "ImportProjects|Error importing repository %{project_safe_import_url} into %{project_full_path} - %{message}"
msgstr ""
+msgid "ImportProjects|Import repositories"
+msgstr ""
+
msgid "ImportProjects|Importing the project failed"
msgstr ""
@@ -13096,7 +13488,7 @@ msgstr ""
msgid "ImportProjects|Requesting your %{provider} repositories failed"
msgstr ""
-msgid "ImportProjects|Select the projects you want to import"
+msgid "ImportProjects|Select the repositories you want to import"
msgstr ""
msgid "ImportProjects|The remote data could not be imported."
@@ -13132,9 +13524,6 @@ msgstr ""
msgid "In order to enable Service Desk for your instance, you must first set up incoming email."
msgstr ""
-msgid "In order to gather accurate feature usage data, it can take 1 to 2 weeks to see your index."
-msgstr ""
-
msgid "In order to personalize your experience with GitLab%{br_tag}we would like to know a bit more about you."
msgstr ""
@@ -13165,18 +13554,30 @@ msgstr ""
msgid "IncidentManagement|Create incident"
msgstr ""
+msgid "IncidentManagement|Critical - S1"
+msgstr ""
+
msgid "IncidentManagement|Date created"
msgstr ""
msgid "IncidentManagement|Display your incidents in a dedicated view"
msgstr ""
+msgid "IncidentManagement|High - S2"
+msgstr ""
+
msgid "IncidentManagement|Incident"
msgstr ""
msgid "IncidentManagement|Incidents"
msgstr ""
+msgid "IncidentManagement|Low - S4"
+msgstr ""
+
+msgid "IncidentManagement|Medium - S3"
+msgstr ""
+
msgid "IncidentManagement|No incidents to display."
msgstr ""
@@ -13189,6 +13590,9 @@ msgstr ""
msgid "IncidentManagement|Published to status page"
msgstr ""
+msgid "IncidentManagement|Severity"
+msgstr ""
+
msgid "IncidentManagement|There are no closed incidents"
msgstr ""
@@ -13198,6 +13602,9 @@ msgstr ""
msgid "IncidentManagement|Unassigned"
msgstr ""
+msgid "IncidentManagement|Unknown"
+msgstr ""
+
msgid "IncidentManagement|Unpublished"
msgstr ""
@@ -13219,6 +13626,15 @@ msgstr ""
msgid "Incidents"
msgstr ""
+msgid "Incident|Alert details"
+msgstr ""
+
+msgid "Incident|Summary"
+msgstr ""
+
+msgid "Incident|There was an issue loading alert data. Please try again."
+msgstr ""
+
msgid "Include a Terms of Service agreement and Privacy Policy that all users must accept."
msgstr ""
@@ -13279,6 +13695,9 @@ msgstr ""
msgid "Information about additional Pages templates and how to install them can be found in our %{pages_getting_started_guide}."
msgstr ""
+msgid "Inherited"
+msgstr ""
+
msgid "Inherited:"
msgstr ""
@@ -13359,7 +13778,22 @@ msgstr ""
msgid "Instance administrators group already exists"
msgstr ""
-msgid "Instance license"
+msgid "InstanceStatistics|Groups"
+msgstr ""
+
+msgid "InstanceStatistics|Issues"
+msgstr ""
+
+msgid "InstanceStatistics|Merge Requests"
+msgstr ""
+
+msgid "InstanceStatistics|Pipelines"
+msgstr ""
+
+msgid "InstanceStatistics|Projects"
+msgstr ""
+
+msgid "InstanceStatistics|Users"
msgstr ""
msgid "Integration"
@@ -13371,6 +13805,12 @@ msgstr ""
msgid "Integrations"
msgstr ""
+msgid "Integrations|%{integration} settings saved and active."
+msgstr ""
+
+msgid "Integrations|%{integration} settings saved, but not active."
+msgstr ""
+
msgid "Integrations|All details"
msgstr ""
@@ -13380,6 +13820,12 @@ msgstr ""
msgid "Integrations|Comment settings:"
msgstr ""
+msgid "Integrations|Connection failed. Please check your settings."
+msgstr ""
+
+msgid "Integrations|Connection successful."
+msgstr ""
+
msgid "Integrations|Default settings are inherited from the group level."
msgstr ""
@@ -13395,6 +13841,15 @@ msgstr ""
msgid "Integrations|Includes commit title and branch"
msgstr ""
+msgid "Integrations|Projects using custom settings will not be impacted unless the project owner chooses to use instance-level defaults."
+msgstr ""
+
+msgid "Integrations|Save settings?"
+msgstr ""
+
+msgid "Integrations|Saving will update the default settings for all projects that are not using custom settings."
+msgstr ""
+
msgid "Integrations|Standard"
msgstr ""
@@ -13527,6 +13982,9 @@ msgstr ""
msgid "Invitation"
msgstr ""
+msgid "Invitation declined"
+msgstr ""
+
msgid "Invite"
msgstr ""
@@ -13578,6 +14036,42 @@ 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|%{linkStart}Read more%{linkEnd} about role permissions"
+msgstr ""
+
+msgid "InviteMembersModal|Access expiration date (optional)"
+msgstr ""
+
+msgid "InviteMembersModal|Cancel"
+msgstr ""
+
+msgid "InviteMembersModal|Choose a role permission"
+msgstr ""
+
+msgid "InviteMembersModal|GitLab member or Email address"
+msgstr ""
+
+msgid "InviteMembersModal|Invite"
+msgstr ""
+
+msgid "InviteMembersModal|Invite team members"
+msgstr ""
+
+msgid "InviteMembersModal|Search for members to invite"
+msgstr ""
+
+msgid "InviteMembersModal|User not invited. Feature coming soon!"
+msgstr ""
+
+msgid "InviteMembersModal|Users were succesfully added"
+msgstr ""
+
+msgid "InviteMembersModal|You're inviting members to the %{group_name} group"
+msgstr ""
+
+msgid "InviteMembers|Invite team members"
+msgstr ""
+
msgid "Invited"
msgstr ""
@@ -13632,10 +14126,13 @@ msgstr ""
msgid "Issue cannot be found."
msgstr ""
+msgid "Issue created from vulnerability %{vulnerability_link}"
+msgstr ""
+
msgid "Issue events"
msgstr ""
-msgid "Issue first depoloyed to production"
+msgid "Issue first deployed to production"
msgstr ""
msgid "Issue label"
@@ -13713,6 +14210,9 @@ msgstr ""
msgid "IssueTracker|Custom issue tracker"
msgstr ""
+msgid "IssueTracker|EWM work items tracker"
+msgstr ""
+
msgid "IssueTracker|Redmine issue tracker"
msgstr ""
@@ -13779,6 +14279,9 @@ msgstr ""
msgid "It looks like you have some draft commits in this branch."
msgstr ""
+msgid "It may be several days before you see feature usage data."
+msgstr ""
+
msgid "It must have a header row and at least two columns: the first column is the issue title and the second column is the issue description. The separator is automatically detected."
msgstr ""
@@ -14061,13 +14564,13 @@ msgstr ""
msgid "Join Zoom meeting"
msgstr ""
-msgid "Jul"
+msgid "Joined %{time_ago}"
msgstr ""
-msgid "July"
+msgid "Jul"
msgstr ""
-msgid "Jump to first unresolved thread"
+msgid "July"
msgstr ""
msgid "Jump to next unresolved thread"
@@ -14103,6 +14606,9 @@ msgstr ""
msgid "Keyboard shortcuts"
msgstr ""
+msgid "KeyboardKey|Ctrl+"
+msgstr ""
+
msgid "Keys"
msgstr ""
@@ -14151,6 +14657,9 @@ msgstr ""
msgid "LDAP Synchronization"
msgstr ""
+msgid "LDAP group settings"
+msgstr ""
+
msgid "LDAP settings"
msgstr ""
@@ -14160,6 +14669,9 @@ msgstr ""
msgid "LDAP sync in progress. This could take a few minutes. Refresh the page to see the changes."
msgstr ""
+msgid "LDAP synchronizations"
+msgstr ""
+
msgid "LFS"
msgstr ""
@@ -14240,7 +14752,16 @@ msgid_plural "Last %d days"
msgstr[0] ""
msgstr[1] ""
-msgid "Last %{days} days"
+msgid "Last 2 weeks"
+msgstr ""
+
+msgid "Last 30 days"
+msgstr ""
+
+msgid "Last 60 days"
+msgstr ""
+
+msgid "Last 90 days"
msgstr ""
msgid "Last Accessed On"
@@ -14318,6 +14839,9 @@ msgstr ""
msgid "Last used on:"
msgstr ""
+msgid "Last week"
+msgstr ""
+
msgid "LastCommit|authored"
msgstr ""
@@ -14333,6 +14857,9 @@ msgstr ""
msgid "Latest pipeline for the most recent commit on this branch"
msgstr ""
+msgid "Launch a ready-to-code development environment for your project."
+msgstr ""
+
msgid "Lead"
msgstr ""
@@ -14713,6 +15240,9 @@ msgstr ""
msgid "List of all merge commits"
msgstr ""
+msgid "List options"
+msgstr ""
+
msgid "List settings"
msgstr ""
@@ -14725,9 +15255,6 @@ msgstr ""
msgid "List your Bitbucket Server repositories"
msgstr ""
-msgid "Lists"
-msgstr ""
-
msgid "Live preview"
msgstr ""
@@ -14974,6 +15501,12 @@ msgstr ""
msgid "Mark as done"
msgstr ""
+msgid "Mark as draft"
+msgstr ""
+
+msgid "Mark as ready"
+msgstr ""
+
msgid "Mark as resolved"
msgstr ""
@@ -14995,6 +15528,24 @@ msgstr ""
msgid "Markdown is supported"
msgstr ""
+msgid "MarkdownEditor|Add a link (%{modifierKey}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add a link (%{modifier_key}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifierKey}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifier_key}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifierKey}I)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifier_key}I)"
+msgstr ""
+
msgid "Marked For Deletion At - %{deletion_time}"
msgstr ""
@@ -15079,7 +15630,25 @@ msgstr ""
msgid "Max access level"
msgstr ""
-msgid "Max seats used"
+msgid "Max role"
+msgstr ""
+
+msgid "Max size 15 MB"
+msgstr ""
+
+msgid "Maximum Conan package file size in bytes"
+msgstr ""
+
+msgid "Maximum Maven package file size in bytes"
+msgstr ""
+
+msgid "Maximum NPM package file size in bytes"
+msgstr ""
+
+msgid "Maximum NuGet package file size in bytes"
+msgstr ""
+
+msgid "Maximum PyPI package file size in bytes"
msgstr ""
msgid "Maximum Users:"
@@ -15211,6 +15780,18 @@ msgstr ""
msgid "Members with access to %{strong_start}%{group_name}%{strong_end}"
msgstr ""
+msgid "Members|%{time} by %{user}"
+msgstr ""
+
+msgid "Members|Expired"
+msgstr ""
+
+msgid "Members|No expiration set"
+msgstr ""
+
+msgid "Members|in %{time}"
+msgstr ""
+
msgid "Memory Usage"
msgstr ""
@@ -15397,9 +15978,6 @@ msgstr ""
msgid "MergeRequests|Thread will be unresolved"
msgstr ""
-msgid "MergeRequests|Toggle comments for this file"
-msgstr ""
-
msgid "MergeRequests|View file @ %{commitId}"
msgstr ""
@@ -15460,6 +16038,9 @@ msgstr ""
msgid "Merging immediately isn't recommended as it may negatively impact the existing merge train. Read the %{docsLinkStart}documentation%{docsLinkEnd} for more information."
msgstr ""
+msgid "Message"
+msgstr ""
+
msgid "Messages"
msgstr "Missatges"
@@ -15845,18 +16426,12 @@ msgid_plural "Milestones"
msgstr[0] ""
msgstr[1] ""
-msgid "Milestone does not support burnup charts"
-msgstr ""
-
msgid "Milestone lists not available with your current license"
msgstr ""
msgid "Milestone lists show all issues from the selected milestone."
msgstr ""
-msgid "Milestone must have a start and due date"
-msgstr ""
-
msgid "MilestoneSidebar|Closed:"
msgstr ""
@@ -16223,6 +16798,9 @@ msgstr "Nom:"
msgid "Namespace"
msgstr ""
+msgid "Namespace ID:"
+msgstr ""
+
msgid "Namespace is empty"
msgstr ""
@@ -16307,6 +16885,9 @@ msgstr ""
msgid "NetworkPolicies|Allow all outbound traffic from %{selector} to %{ruleSelector} on %{ports}"
msgstr ""
+msgid "NetworkPolicies|Are you sure you want to delete this policy? This action cannot be undone."
+msgstr ""
+
msgid "NetworkPolicies|Choose whether to enforce this policy."
msgstr ""
@@ -16316,12 +16897,21 @@ msgstr ""
msgid "NetworkPolicies|Define this policy's location, conditions and actions."
msgstr ""
+msgid "NetworkPolicies|Delete policy"
+msgstr ""
+
+msgid "NetworkPolicies|Delete policy: %{policy}"
+msgstr ""
+
msgid "NetworkPolicies|Deny all traffic"
msgstr ""
msgid "NetworkPolicies|Description"
msgstr ""
+msgid "NetworkPolicies|Edit policy"
+msgstr ""
+
msgid "NetworkPolicies|Editor mode"
msgstr ""
@@ -16349,6 +16939,9 @@ msgstr ""
msgid "NetworkPolicies|Name"
msgstr ""
+msgid "NetworkPolicies|Namespace"
+msgstr ""
+
msgid "NetworkPolicies|Network Policy"
msgstr ""
@@ -16400,6 +16993,9 @@ msgstr ""
msgid "NetworkPolicies|Rules"
msgstr ""
+msgid "NetworkPolicies|Save changes"
+msgstr ""
+
msgid "NetworkPolicies|Something went wrong, failed to update policy"
msgstr ""
@@ -16412,6 +17008,9 @@ msgstr ""
msgid "NetworkPolicies|Traffic that does not match any rule will be blocked."
msgstr ""
+msgid "NetworkPolicies|Unable to parse policy"
+msgstr ""
+
msgid "NetworkPolicies|YAML editor"
msgstr ""
@@ -16525,6 +17124,9 @@ msgstr ""
msgid "New Snippet"
msgstr ""
+msgid "New Test Case"
+msgstr ""
+
msgid "New User"
msgstr ""
@@ -16624,6 +17226,9 @@ msgstr ""
msgid "New tag"
msgstr ""
+msgid "New test case"
+msgstr ""
+
msgid "New users set to external"
msgstr ""
@@ -16696,7 +17301,7 @@ msgstr ""
msgid "No changes"
msgstr ""
-msgid "No changes between %{ref_start}%{source_branch}%{ref_end} and %{ref_start}%{target_branch}%{ref_end}"
+msgid "No changes between %{sourceBranch} and %{targetBranch}"
msgstr ""
msgid "No child epics match applied filters"
@@ -16711,6 +17316,9 @@ msgstr ""
msgid "No containers available"
msgstr ""
+msgid "No content to show"
+msgstr ""
+
msgid "No contributions"
msgstr ""
@@ -16786,9 +17394,6 @@ msgstr ""
msgid "No license. All rights reserved"
msgstr ""
-msgid "No licenses found."
-msgstr ""
-
msgid "No matches found"
msgstr ""
@@ -16801,6 +17406,9 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No members found"
+msgstr ""
+
msgid "No merge requests found"
msgstr ""
@@ -16822,6 +17430,9 @@ msgstr ""
msgid "No parent group"
msgstr ""
+msgid "No plan"
+msgstr ""
+
msgid "No pods available"
msgstr ""
@@ -16918,6 +17529,12 @@ msgstr ""
msgid "Not Implemented"
msgstr ""
+msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+msgstr ""
+
+msgid "Not all browsers support WebAuthn. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even from an unsupported browser."
+msgstr ""
+
msgid "Not all data has been processed yet, the accuracy of the chart for the selected timeframe is limited."
msgstr ""
@@ -17014,6 +17631,9 @@ msgstr ""
msgid "Notification settings saved"
msgstr ""
+msgid "NotificationEvent|Change reviewer merge request"
+msgstr ""
+
msgid "NotificationEvent|Close issue"
msgstr ""
@@ -17176,10 +17796,7 @@ msgstr ""
msgid "On track"
msgstr ""
-msgid "OnDemandScans|Attached branch"
-msgstr ""
-
-msgid "OnDemandScans|Attached branch is where the scan job runs."
+msgid "OnDemandScans|Could not fetch scanner profiles. Please refresh the page, or try again later."
msgstr ""
msgid "OnDemandScans|Could not fetch site profiles. Please refresh the page, or try again later."
@@ -17188,6 +17805,9 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
+msgid "OnDemandScans|Create a new scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Create a new site profile"
msgstr ""
@@ -17200,6 +17820,9 @@ msgstr ""
msgid "OnDemandScans|New on-demand DAST scan"
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 ""
@@ -17209,16 +17832,10 @@ msgstr ""
msgid "OnDemandScans|On-demand scans run outside the DevOps cycle and find vulnerabilities in your projects. %{learnMoreLinkStart}Learn more%{learnMoreLinkEnd}"
msgstr ""
-msgid "OnDemandScans|Only a passive scan can be performed on demand."
-msgstr ""
-
-msgid "OnDemandScans|Passive"
-msgstr ""
-
msgid "OnDemandScans|Run scan"
msgstr ""
-msgid "OnDemandScans|Scan mode"
+msgid "OnDemandScans|Scanner profile"
msgstr ""
msgid "OnDemandScans|Scanner settings"
@@ -17230,9 +17847,15 @@ msgstr ""
msgid "OnDemandScans|Select one of the existing profiles"
msgstr ""
+msgid "OnDemandScans|Site profile"
+msgstr ""
+
msgid "OnDemandScans|Site profiles"
msgstr ""
+msgid "OnDemandScans|Use existing scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Use existing site profile"
msgstr ""
@@ -17331,9 +17954,6 @@ msgstr ""
msgid "Open Selection"
msgstr ""
-msgid "Open Web IDE"
-msgstr ""
-
msgid "Open comment type dropdown"
msgstr ""
@@ -17439,6 +18059,9 @@ msgstr ""
msgid "Origin"
msgstr ""
+msgid "Orphaned member"
+msgstr ""
+
msgid "Other Labels"
msgstr ""
@@ -17454,6 +18077,9 @@ msgstr ""
msgid "Other visibility settings have been disabled by the administrator."
msgstr ""
+msgid "Our documentation includes an example DevOps Score report."
+msgstr ""
+
msgid "Out-of-compliance with this project's policies and should be removed"
msgstr ""
@@ -17478,6 +18104,9 @@ msgstr ""
msgid "Overwrite diverged branches"
msgstr ""
+msgid "Owned by %{image_tag}"
+msgstr ""
+
msgid "Owned by anyone"
msgstr ""
@@ -17499,6 +18128,9 @@ msgstr ""
msgid "Package deleted successfully"
msgstr ""
+msgid "Package file size limits"
+msgstr ""
+
msgid "Package recipe already exists"
msgstr ""
@@ -17514,9 +18146,6 @@ msgstr ""
msgid "Package type must be PyPi"
msgstr ""
-msgid "Package was removed"
-msgstr ""
-
msgid "PackageRegistry|%{name} version %{version} was created %{datetime}"
msgstr ""
@@ -17658,12 +18287,18 @@ msgstr ""
msgid "PackageRegistry|NuGet Command"
msgstr ""
+msgid "PackageRegistry|Package Registry"
+msgstr ""
+
msgid "PackageRegistry|Pip Command"
msgstr ""
msgid "PackageRegistry|Pipeline %{link} triggered %{datetime} by %{author}"
msgstr ""
+msgid "PackageRegistry|Publish and share packages for a variety of common package managers. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "PackageRegistry|Published to the %{project} Package Registry %{datetime}"
msgstr ""
@@ -17763,6 +18398,9 @@ msgstr ""
msgid "Page not found"
msgstr ""
+msgid "Page settings"
+msgstr ""
+
msgid "Page was successfully deleted"
msgstr ""
@@ -17904,7 +18542,7 @@ msgstr ""
msgid "Paste issue link"
msgstr ""
-msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Don't use your private SSH key."
+msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Do not paste your private SSH key, as that can compromise your identity."
msgstr ""
msgid "Patch to apply"
@@ -17931,6 +18569,9 @@ msgstr ""
msgid "Pending"
msgstr ""
+msgid "Pending comments"
+msgstr ""
+
msgid "People without permission will never get a notification and won't be able to comment."
msgstr ""
@@ -18129,6 +18770,9 @@ msgstr ""
msgid "Pipelines|Build with confidence"
msgstr ""
+msgid "Pipelines|By revoking a trigger you will break any processes making use of it. Are you sure?"
+msgstr ""
+
msgid "Pipelines|CI Lint"
msgstr ""
@@ -18141,6 +18785,15 @@ msgstr ""
msgid "Pipelines|Continuous Integration can help catch bugs by running your tests automatically, while Continuous Deployment can help you deliver code to your product environment."
msgstr ""
+msgid "Pipelines|Copy trigger token"
+msgstr ""
+
+msgid "Pipelines|Description"
+msgstr ""
+
+msgid "Pipelines|Edit"
+msgstr ""
+
msgid "Pipelines|Get started with Pipelines"
msgstr ""
@@ -18156,15 +18809,27 @@ msgstr ""
msgid "Pipelines|It is recommended the code is reviewed thoroughly before running this pipeline with the parent project's CI resource."
msgstr ""
+msgid "Pipelines|Last Used"
+msgstr ""
+
msgid "Pipelines|Loading Pipelines"
msgstr ""
msgid "Pipelines|More Information"
msgstr ""
+msgid "Pipelines|No triggers have been created yet. Add one using the form above."
+msgstr ""
+
+msgid "Pipelines|Owner"
+msgstr ""
+
msgid "Pipelines|Project cache successfully reset."
msgstr ""
+msgid "Pipelines|Revoke"
+msgstr ""
+
msgid "Pipelines|Run Pipeline"
msgstr ""
@@ -18189,6 +18854,15 @@ msgstr ""
msgid "Pipelines|This project is not currently set up to run pipelines."
msgstr ""
+msgid "Pipelines|Token"
+msgstr ""
+
+msgid "Pipelines|Trigger user has insufficient permissions to project"
+msgstr ""
+
+msgid "Pipelines|invalid"
+msgstr ""
+
msgid "Pipelines|parent"
msgstr ""
@@ -18447,10 +19121,10 @@ msgstr ""
msgid "Please provide attributes to update"
msgstr ""
-msgid "Please refer to %{docs_url}"
+msgid "Please reach out if you have any questions and we'll be happy to assist."
msgstr ""
-msgid "Please retype the email address."
+msgid "Please refer to %{docs_url}"
msgstr ""
msgid "Please select"
@@ -18480,6 +19154,9 @@ msgstr ""
msgid "Please set a new password before proceeding."
msgstr ""
+msgid "Please share your feedback about %{featureName} %{linkStart}in this issue%{linkEnd} to help us improve the experience."
+msgstr ""
+
msgid "Please solve the reCAPTCHA"
msgstr ""
@@ -18783,6 +19460,9 @@ msgstr ""
msgid "Profiles| You are going to change the username %{currentUsernameBold} to %{newUsernameBold}. Profile and projects will be redirected to the %{newUsername} namespace but this redirect will expire once the %{currentUsername} namespace is registered by another user or group. Please update your Git repository remotes as soon as possible."
msgstr ""
+msgid "Profiles|%{provider} Active"
+msgstr ""
+
msgid "Profiles|@username"
msgstr ""
@@ -18834,7 +19514,7 @@ msgstr ""
msgid "Profiles|Commit email"
msgstr ""
-msgid "Profiles|Connect"
+msgid "Profiles|Connect %{provider}"
msgstr ""
msgid "Profiles|Connected Accounts"
@@ -18858,6 +19538,9 @@ msgstr ""
msgid "Profiles|Disconnect"
msgstr ""
+msgid "Profiles|Disconnect %{provider}"
+msgstr ""
+
msgid "Profiles|Do not show on profile"
msgstr ""
@@ -18882,7 +19565,7 @@ msgstr ""
msgid "Profiles|Full name"
msgstr ""
-msgid "Profiles|Give your individual key a title. This will be publically visible."
+msgid "Profiles|Give your individual key a title."
msgstr ""
msgid "Profiles|Include private contributions on my profile"
@@ -18972,7 +19655,7 @@ msgstr ""
msgid "Profiles|The maximum file size allowed is 200KB."
msgstr ""
-msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it?"
+msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it? It will be publicly visible."
msgstr ""
msgid "Profiles|This email will be displayed on your public profile"
@@ -19047,6 +19730,9 @@ msgstr ""
msgid "Profiles|You don't have access to delete this user."
msgstr ""
+msgid "Profiles|You must transfer ownership or delete groups you are an owner of before you can delete your account"
+msgstr ""
+
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
@@ -19635,6 +20321,9 @@ msgstr ""
msgid "ProjectTemplates|GitLab Cluster Management"
msgstr ""
+msgid "ProjectTemplates|Gitpod/Spring Petclinic"
+msgstr ""
+
msgid "ProjectTemplates|Go Micro"
msgstr ""
@@ -20244,6 +20933,9 @@ msgstr ""
msgid "Publish to status page"
msgstr ""
+msgid "Published"
+msgstr ""
+
msgid "Published on status page"
msgstr ""
@@ -20361,9 +21053,15 @@ msgstr ""
msgid "Quick range"
msgstr ""
+msgid "Quickly and easily edit multiple files in your project."
+msgstr ""
+
msgid "README"
msgstr ""
+msgid "Rails"
+msgstr ""
+
msgid "Rake Tasks Help"
msgstr ""
@@ -20483,10 +21181,13 @@ msgstr ""
msgid "Register Two-Factor Authenticator"
msgstr ""
-msgid "Register U2F device"
+msgid "Register Universal Two-Factor (U2F) Device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register WebAuthn Device"
+msgstr ""
+
+msgid "Register device"
msgstr ""
msgid "Register for GitLab"
@@ -20498,9 +21199,6 @@ msgstr ""
msgid "Register with two-factor app"
msgstr ""
-msgid "Registration"
-msgstr ""
-
msgid "Registration|Checkout"
msgstr ""
@@ -20617,9 +21315,6 @@ msgstr ""
msgid "Release|Something went wrong while saving the release details"
msgstr ""
-msgid "Remediated: needs review"
-msgstr ""
-
msgid "Remediations"
msgstr ""
@@ -20725,6 +21420,9 @@ msgstr ""
msgid "Remove priority"
msgstr ""
+msgid "Remove report"
+msgstr ""
+
msgid "Remove secondary node"
msgstr ""
@@ -20737,6 +21435,12 @@ msgstr ""
msgid "Remove time estimate"
msgstr ""
+msgid "Remove user & report"
+msgstr ""
+
+msgid "Remove user from group"
+msgstr ""
+
msgid "Removed"
msgstr ""
@@ -20818,9 +21522,6 @@ msgstr ""
msgid "Removes time estimate."
msgstr ""
-msgid "Removing license…"
-msgstr ""
-
msgid "Removing this group also removes all child projects, including archived projects, and their resources."
msgstr ""
@@ -20905,6 +21606,9 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
+msgid "Reported by %{reporter}"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -20991,6 +21695,27 @@ msgstr ""
msgid "Repositories"
msgstr ""
+msgid "Repositories Analytics"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download Historic Test Coverage Data"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download historic test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Historic Test Coverage Data is available in raw format (.csv) for further analysis."
+msgstr ""
+
+msgid "RepositoriesAnalytics|Test Code Coverage"
+msgstr ""
+
+msgid "RepositoriesAnalytics|There was an error fetching the projects."
+msgstr ""
+
msgid "Repository"
msgstr ""
@@ -21069,9 +21794,15 @@ msgstr ""
msgid "Request parameter %{param} is missing."
msgstr ""
+msgid "Request review from"
+msgstr ""
+
msgid "Request to link SAML account must be authorized"
msgstr ""
+msgid "Requested"
+msgstr ""
+
msgid "Requested %{time_ago}"
msgstr ""
@@ -21090,6 +21821,9 @@ msgstr ""
msgid "Requests to these domain(s)/address(es) on the local network will be allowed when local requests from hooks and services are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 or 127.0.0.0/28 are supported. Domain wildcards are not supported currently. Use comma, semicolon, or newline to separate multiple entries. The allowlist can hold a maximum of 1000 entries. Domains should use IDNA encoding. Ex: example.com, 192.168.1.1, 127.0.0.0/28, xn--itlab-j1a.com."
msgstr ""
+msgid "Require admin approval for new sign-ups"
+msgstr ""
+
msgid "Require all users in this group to setup Two-factor authentication"
msgstr ""
@@ -21217,9 +21951,6 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
-msgid "Resolved by %{resolvedByName}"
-msgstr ""
-
msgid "Resolves IP addresses once and uses them to submit requests"
msgstr ""
@@ -21339,6 +22070,14 @@ msgstr ""
msgid "ReviewApp|Enable Review App"
msgstr ""
+msgid "Reviewer"
+msgid_plural "%d Reviewers"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Reviewer(s)"
+msgstr ""
+
msgid "Reviewing"
msgstr ""
@@ -21378,6 +22117,9 @@ msgstr ""
msgid "Rook"
msgstr ""
+msgid "Ruby"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -21456,6 +22198,63 @@ msgstr ""
msgid "Runners page."
msgstr ""
+msgid "Runners|Active"
+msgstr ""
+
+msgid "Runners|Architecture"
+msgstr ""
+
+msgid "Runners|Can run untagged jobs"
+msgstr ""
+
+msgid "Runners|Description"
+msgstr ""
+
+msgid "Runners|Group"
+msgstr ""
+
+msgid "Runners|IP Address"
+msgstr ""
+
+msgid "Runners|Last contact"
+msgstr ""
+
+msgid "Runners|Locked to this project"
+msgstr ""
+
+msgid "Runners|Maximum job timeout"
+msgstr ""
+
+msgid "Runners|Name"
+msgstr ""
+
+msgid "Runners|Platform"
+msgstr ""
+
+msgid "Runners|Property Name"
+msgstr ""
+
+msgid "Runners|Protected"
+msgstr ""
+
+msgid "Runners|Revision"
+msgstr ""
+
+msgid "Runners|Shared"
+msgstr ""
+
+msgid "Runners|Specific"
+msgstr ""
+
+msgid "Runners|Tags"
+msgstr ""
+
+msgid "Runners|Value"
+msgstr ""
+
+msgid "Runners|Version"
+msgstr ""
+
msgid "Runners|You have used %{quotaUsed} out of %{quotaLimit} of your shared Runners pipeline minutes."
msgstr ""
@@ -21468,6 +22267,9 @@ msgstr ""
msgid "Runs a number of housekeeping tasks within the current repository, such as compressing file revisions and removing unreachable objects."
msgstr ""
+msgid "SAML"
+msgstr ""
+
msgid "SAML SSO"
msgstr ""
@@ -21519,6 +22321,9 @@ msgstr ""
msgid "Save"
msgstr ""
+msgid "Save %{name} size limits"
+msgstr ""
+
msgid "Save Changes"
msgstr ""
@@ -21549,9 +22354,6 @@ msgstr ""
msgid "Save space and find tags in the Container Registry more easily. Enable the cleanup policy to remove stale tags and keep only the ones you need."
msgstr ""
-msgid "Save template"
-msgstr ""
-
msgid "Save variables"
msgstr ""
@@ -21594,9 +22396,6 @@ msgstr ""
msgid "Scope"
msgstr ""
-msgid "Scope not supported with disabled 'users_search' feature!"
-msgstr ""
-
msgid "Scoped issue boards"
msgstr ""
@@ -21723,9 +22522,6 @@ msgstr ""
msgid "Search requirements"
msgstr ""
-msgid "Search results…"
-msgstr ""
-
msgid "Search users"
msgstr ""
@@ -21798,6 +22594,11 @@ msgid_plural "SearchResults|commits"
msgstr[0] ""
msgstr[1] ""
+msgid "SearchResults|epic"
+msgid_plural "SearchResults|epics"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "SearchResults|issue"
msgid_plural "SearchResults|issues"
msgstr[0] ""
@@ -21842,10 +22643,10 @@ msgstr ""
msgid "Seat Link is disabled, and cannot be configured through this form."
msgstr ""
-msgid "Seats currently in use"
+msgid "Seats usage data as of %{last_enqueue_time}"
msgstr ""
-msgid "Seats in license"
+msgid "Seats usage data is updated every day at 12:00pm UTC"
msgstr ""
msgid "Secondary"
@@ -21899,6 +22700,9 @@ msgstr ""
msgid "SecurityConfiguration|Available for on-demand DAST"
msgstr ""
+msgid "SecurityConfiguration|By default, all analyzers are applied in order to cover all languages across your project, and only run if the language is detected in the Merge Request."
+msgstr ""
+
msgid "SecurityConfiguration|Configure"
msgstr ""
@@ -21929,16 +22733,19 @@ msgstr ""
msgid "SecurityConfiguration|Manage"
msgstr ""
+msgid "SecurityConfiguration|More information"
+msgstr ""
+
msgid "SecurityConfiguration|Not enabled"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|Security Control"
+msgid "SecurityConfiguration|SAST Configuration"
msgstr ""
-msgid "SecurityConfiguration|See documentation"
+msgid "SecurityConfiguration|Security Control"
msgstr ""
msgid "SecurityConfiguration|Status"
@@ -21950,6 +22757,9 @@ msgstr ""
msgid "SecurityConfiguration|Using custom settings. You won't receive automatic updates on this variable. %{anchorStart}Restore to default%{anchorEnd}"
msgstr ""
+msgid "SecurityConfiguration|View history"
+msgstr ""
+
msgid "SecurityConfiguration|You can quickly enable all security scanning tools by enabling %{linkStart}Auto DevOps%{linkEnd}."
msgstr ""
@@ -22028,9 +22838,6 @@ msgstr ""
msgid "SecurityReports|Learn more about setting up your dashboard"
msgstr ""
-msgid "SecurityReports|Load more vulnerabilities"
-msgstr ""
-
msgid "SecurityReports|Monitor vulnerabilities in your code"
msgstr ""
@@ -22310,7 +23117,7 @@ msgstr ""
msgid "Select status"
msgstr ""
-msgid "Select strategy activation method"
+msgid "Select strategy activation method."
msgstr ""
msgid "Select subscription"
@@ -22325,7 +23132,7 @@ msgstr ""
msgid "Select the custom project template source group."
msgstr ""
-msgid "Select timeframe"
+msgid "Select the environment scope for this feature flag."
msgstr ""
msgid "Select timezone"
@@ -22574,6 +23381,9 @@ msgstr ""
msgid "Set iteration"
msgstr ""
+msgid "Set limit to 0 to allow any file size."
+msgstr ""
+
msgid "Set max session time for web terminal."
msgstr ""
@@ -22652,10 +23462,13 @@ msgstr ""
msgid "Set up a %{type} Runner manually"
msgstr ""
+msgid "Set up a hardware device as a second factor to sign in."
+msgstr ""
+
msgid "Set up assertions/attributes/claims (email, first_name, last_name) and NameID according to %{docsLinkStart}the documentation %{icon}%{docsLinkEnd}"
msgstr ""
-msgid "Set up new U2F device"
+msgid "Set up new device"
msgstr ""
msgid "Set up new password"
@@ -22724,6 +23537,9 @@ msgstr ""
msgid "Sets weight to %{weight}."
msgstr ""
+msgid "Setting this to 0 means using the system default timeout value."
+msgstr ""
+
msgid "Settings"
msgstr ""
@@ -22739,6 +23555,15 @@ msgstr ""
msgid "Severity"
msgstr ""
+msgid "SeverityWidget|Severity"
+msgstr ""
+
+msgid "SeverityWidget|Severity: %{severity}"
+msgstr ""
+
+msgid "SeverityWidget|There was an error while updating severity."
+msgstr ""
+
msgid "Shards (%{shards})"
msgstr ""
@@ -22784,6 +23609,9 @@ msgstr ""
msgid "Show all requirements."
msgstr ""
+msgid "Show all test cases."
+msgstr ""
+
msgid "Show archived projects"
msgstr ""
@@ -22796,6 +23624,9 @@ msgstr ""
msgid "Show comments"
msgstr ""
+msgid "Show comments on this file"
+msgstr ""
+
msgid "Show comments only"
msgstr ""
@@ -22841,6 +23672,12 @@ msgstr ""
msgid "Show parent subgroups"
msgstr ""
+msgid "Show the Closed list"
+msgstr ""
+
+msgid "Show the Open list"
+msgstr ""
+
msgid "Show whitespace changes"
msgstr ""
@@ -22884,9 +23721,6 @@ msgstr ""
msgid "Sidebar|Assign health status"
msgstr ""
-msgid "Sidebar|Change weight"
-msgstr ""
-
msgid "Sidebar|Health status"
msgstr ""
@@ -23070,6 +23904,9 @@ msgstr ""
msgid "Snippets|Add another file %{num}/%{total}"
msgstr ""
+msgid "Snippets|Authored %{time_ago} by %{author}"
+msgstr ""
+
msgid "Snippets|Delete file"
msgstr ""
@@ -23097,6 +23934,9 @@ msgstr ""
msgid "Solution"
msgstr ""
+msgid "Some changes are not shown"
+msgstr ""
+
msgid "Some child epics may be hidden due to applied filters"
msgstr ""
@@ -23463,6 +24303,12 @@ msgstr ""
msgid "Source (branch or tag)"
msgstr ""
+msgid "Source Branch"
+msgstr ""
+
+msgid "Source branch: %{source_branch_open}%{source_branch}%{source_branch_close}"
+msgstr ""
+
msgid "Source code"
msgstr ""
@@ -23628,9 +24474,6 @@ msgstr ""
msgid "Start and due date"
msgstr ""
-msgid "Start by choosing a group to see how your team is spending time. You can then drill down to the project level."
-msgstr ""
-
msgid "Start by choosing a group to start exploring the merge requests in that group. You can then proceed to filter by projects, labels, milestones and authors."
msgstr ""
@@ -23712,18 +24555,27 @@ msgstr ""
msgid "StaticSiteEditor|3. Assign a person to review and accept the merge request."
msgstr ""
+msgid "StaticSiteEditor|A link to view the merge request will appear once ready."
+msgstr ""
+
msgid "StaticSiteEditor|An error occurred while submitting your changes."
msgstr ""
msgid "StaticSiteEditor|Branch could not be created."
msgstr ""
+msgid "StaticSiteEditor|Copy update"
+msgstr ""
+
msgid "StaticSiteEditor|Could not commit the content changes."
msgstr ""
msgid "StaticSiteEditor|Could not create merge request."
msgstr ""
+msgid "StaticSiteEditor|Creating your merge request"
+msgstr ""
+
msgid "StaticSiteEditor|Incompatible file content"
msgstr ""
@@ -23745,6 +24597,9 @@ msgstr ""
msgid "StaticSiteEditor|View documentation"
msgstr ""
+msgid "StaticSiteEditor|You can set an assignee to get your changes reviewed and deployed once your merge request is created."
+msgstr ""
+
msgid "StaticSiteEditor|Your merge request has been created"
msgstr ""
@@ -23874,15 +24729,15 @@ msgstr ""
msgid "Submit %{humanized_resource_name}"
msgstr ""
-msgid "Submit Changes"
-msgstr ""
-
msgid "Submit a review"
msgstr ""
msgid "Submit as spam"
msgstr ""
+msgid "Submit changes"
+msgstr ""
+
msgid "Submit feedback"
msgstr ""
@@ -24036,6 +24891,9 @@ msgstr ""
msgid "Successfully deleted U2F device."
msgstr ""
+msgid "Successfully deleted WebAuthn device."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -24354,9 +25212,6 @@ msgstr ""
msgid "Template to append to all Service Desk issues"
msgstr ""
-msgid "Template was successfully saved."
-msgstr ""
-
msgid "Templates"
msgstr ""
@@ -24435,10 +25290,28 @@ msgid_plural "Test coverage: %d hits"
msgstr[0] ""
msgstr[1] ""
-msgid "Test failed."
+msgid "Test settings"
msgstr ""
-msgid "Test settings and save changes"
+msgid "TestCases|New Test Case"
+msgstr ""
+
+msgid "TestCases|New test case"
+msgstr ""
+
+msgid "TestCases|Search test cases"
+msgstr ""
+
+msgid "TestCases|Something went wrong while creating a test case."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching count of test cases."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching test cases list."
+msgstr ""
+
+msgid "TestCases|Submit test case"
msgstr ""
msgid "TestHooks|Ensure one of your projects has merge requests."
@@ -24504,6 +25377,9 @@ msgstr ""
msgid "Thank you for signing up for your free trial! You will get additional instructions in your inbox shortly."
msgstr ""
+msgid "Thank you for your business."
+msgstr ""
+
msgid "Thank you for your feedback!"
msgstr ""
@@ -24563,9 +25439,6 @@ msgstr ""
msgid "The URL to use for connecting to Elasticsearch. Use a comma-separated list to support clustering (e.g., \"http://localhost:9200, http://localhost:9201\")."
msgstr ""
-msgid "The Web IDE offers advanced syntax highlighting capabilities and more."
-msgstr ""
-
msgid "The X509 Certificate to use when mutual TLS is required to communicate with the external authorization service. If left blank, the server certificate is still validated when accessing over HTTPS."
msgstr ""
@@ -24676,6 +25549,9 @@ msgstr ""
msgid "The form contains the following error:"
msgstr ""
+msgid "The form contains the following warning:"
+msgstr ""
+
msgid "The global settings require you to enable Two-Factor Authentication for your account."
msgstr ""
@@ -24790,9 +25666,6 @@ msgstr ""
msgid "The private key to use when a client certificate is provided. This value is encrypted at rest."
msgstr ""
-msgid "The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The project can be accessed by any logged in user."
msgstr ""
@@ -24829,7 +25702,7 @@ msgstr ""
msgid "The remote repository is being updated..."
msgstr ""
-msgid "The repository can be commited to, and issues, comments and other entities can be created."
+msgid "The repository can be committed to, and issues, comments and other entities can be created."
msgstr ""
msgid "The repository for this project does not exist."
@@ -24883,9 +25756,6 @@ msgstr ""
msgid "The time taken by each data entry gathered by that stage."
msgstr ""
-msgid "The total stage shows the time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The update action will time out after %{number_of_minutes} minutes. For big repositories, use a clone/push combination."
msgstr ""
@@ -24949,6 +25819,9 @@ msgstr ""
msgid "There are no archived requirements"
msgstr ""
+msgid "There are no archived test cases"
+msgstr ""
+
msgid "There are no changes"
msgstr ""
@@ -24988,6 +25861,9 @@ msgstr ""
msgid "There are no open requirements"
msgstr ""
+msgid "There are no open test cases"
+msgstr ""
+
msgid "There are no packages yet"
msgstr ""
@@ -25000,6 +25876,9 @@ msgstr ""
msgid "There is a limit of %{ci_project_subscriptions_limit} subscriptions from or to a project."
msgstr ""
+msgid "There is already a To-Do for this design."
+msgstr ""
+
msgid "There is already a repository with that name on disk"
msgstr ""
@@ -25018,6 +25897,9 @@ msgstr ""
msgid "There was a problem communicating with your device."
msgstr ""
+msgid "There was a problem fetching branches."
+msgstr ""
+
msgid "There was a problem fetching groups."
msgstr ""
@@ -25246,9 +26128,15 @@ msgstr ""
msgid "This action can lead to data loss. To prevent accidental actions we ask you to confirm your intention."
msgstr ""
+msgid "This action cannot be undone, and will permanently delete the %{key} SSH key"
+msgstr ""
+
msgid "This action cannot be undone. You will lose the project's repository and all content: issues, merge requests, etc."
msgstr ""
+msgid "This action has been performed too many times. Try again later."
+msgstr ""
+
msgid "This action will %{strongOpen}permanently delete%{strongClose} %{codeOpen}%{project}%{codeClose} %{strongOpen}immediately%{strongClose}, including its repositories and all content: issues, merge requests, etc."
msgstr ""
@@ -25276,9 +26164,6 @@ msgstr ""
msgid "This board's scope is reduced"
msgstr ""
-msgid "This branch has changed since you started editing. Would you like to create a new branch?"
-msgstr ""
-
msgid "This chart could not be displayed"
msgstr ""
@@ -25405,15 +26290,9 @@ msgstr ""
msgid "This is a security log of important events involving your account."
msgstr ""
-msgid "This is the author's first Merge Request to this project."
-msgstr ""
-
msgid "This is the highest peak of users on your installation since the license started."
msgstr ""
-msgid "This is the maximum number of users that have existed at the same time since the license started. This is the minimum number of seats you will need to buy when you renew your license."
-msgstr ""
-
msgid "This is the number of currently active users on your installation, and this is the minimum number you need to purchase when you renew your license."
msgstr ""
@@ -25645,6 +26524,15 @@ msgstr ""
msgid "This user has no identities"
msgstr ""
+msgid "This user has previously committed to the %{name} project."
+msgstr ""
+
+msgid "This user has the %{access} role in the %{name} project."
+msgstr ""
+
+msgid "This user is the author of this %{noteable}."
+msgstr ""
+
msgid "This user will be the author of all events in the activity feed that are the result of an update, like new branches being created or new commits being pushed to existing branches."
msgstr ""
@@ -25675,6 +26563,9 @@ msgstr ""
msgid "Threat Monitoring"
msgstr ""
+msgid "ThreatMonitoring|All Environments"
+msgstr ""
+
msgid "ThreatMonitoring|Anomalous Requests"
msgstr ""
@@ -25702,9 +26593,6 @@ msgstr ""
msgid "ThreatMonitoring|Operations Per Second"
msgstr ""
-msgid "ThreatMonitoring|Overview"
-msgstr ""
-
msgid "ThreatMonitoring|Packet Activity"
msgstr ""
@@ -25723,6 +26611,9 @@ msgstr ""
msgid "ThreatMonitoring|Something went wrong, unable to fetch statistics"
msgstr ""
+msgid "ThreatMonitoring|Statistics"
+msgstr ""
+
msgid "ThreatMonitoring|The firewall is not installed or has been disabled. To view this data, ensure the web application firewall is installed and enabled for your cluster."
msgstr ""
@@ -26114,6 +27005,9 @@ msgstr ""
msgid "To update Snippets with multiple files, you must use the `files` parameter"
msgstr ""
+msgid "To use Gitpod you must first enable the feature in the integrations section of your %{user_prefs}."
+msgstr ""
+
msgid "To view all %{scannedResourcesCount} scanned URLs, please download the CSV file"
msgstr ""
@@ -26147,9 +27041,6 @@ msgstr ""
msgid "Toggle Sidebar"
msgstr ""
-msgid "Toggle all threads"
-msgstr ""
-
msgid "Toggle backtrace"
msgstr ""
@@ -26174,9 +27065,6 @@ msgstr ""
msgid "Toggle navigation"
msgstr ""
-msgid "Toggle project"
-msgstr ""
-
msgid "Toggle sidebar"
msgstr ""
@@ -26216,6 +27104,9 @@ msgstr ""
msgid "Too many projects enabled. You will need to manage them via the console or the API."
msgstr ""
+msgid "Too much data"
+msgstr ""
+
msgid "Topics (optional)"
msgstr ""
@@ -26234,6 +27125,9 @@ msgstr ""
msgid "Total cores (CPUs)"
msgstr ""
+msgid "Total days to completion"
+msgstr ""
+
msgid "Total issues"
msgstr ""
@@ -26330,6 +27224,9 @@ msgstr ""
msgid "Trending"
msgstr ""
+msgid "Trials|Create a new group to start your GitLab Gold trial."
+msgstr ""
+
msgid "Trials|Go back to GitLab"
msgstr ""
@@ -26339,6 +27236,15 @@ msgstr ""
msgid "Trials|You can always resume this process by selecting your avatar and choosing 'Start a Gold trial'"
msgstr ""
+msgid "Trials|You can apply your trial to a new group or an existing group."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group or your personal account."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group, an existing group, or your personal account."
+msgstr ""
+
msgid "Trials|You won't get a free trial right now but you can always resume this process by clicking on your avatar and choosing 'Start a free trial'"
msgstr ""
@@ -26408,6 +27314,9 @@ msgstr ""
msgid "Try using a different search term to find the file you are looking for."
msgstr ""
+msgid "Trying to communicate with your device. Plug it in (if needed) and press the button on the device now."
+msgstr ""
+
msgid "Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now."
msgstr ""
@@ -26495,6 +27404,12 @@ msgstr ""
msgid "URL or request ID"
msgstr ""
+msgid "USER %{user} WILL BE REMOVED! Are you sure?"
+msgstr ""
+
+msgid "USER WILL BE BLOCKED! Are you sure?"
+msgstr ""
+
msgid "UTC"
msgstr ""
@@ -26552,9 +27467,6 @@ msgstr ""
msgid "Unable to load the merge request widget. Try reloading the page."
msgstr ""
-msgid "Unable to resolve"
-msgstr ""
-
msgid "Unable to save iteration. Please try again"
msgstr ""
@@ -26603,6 +27515,9 @@ msgstr ""
msgid "Undo ignore"
msgstr ""
+msgid "Unexpected error"
+msgstr ""
+
msgid "Unfortunately, your email message to GitLab could not be processed."
msgstr ""
@@ -26636,6 +27551,9 @@ msgstr ""
msgid "Unknown response text"
msgstr ""
+msgid "Unless otherwise agreed to in writing with GitLab, by clicking \"Upload License\" you agree that your use of GitLab Software is subject to the %{eula_link_start}Terms of Service%{eula_link_end}."
+msgstr ""
+
msgid "Unlimited"
msgstr ""
@@ -27002,9 +27920,6 @@ msgstr ""
msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
msgstr ""
-msgid "Use a hardware device to add the second factor of authentication."
-msgstr ""
-
msgid "Use an one time password authenticator on your mobile device or computer to enable two-factor authentication (2FA)."
msgstr ""
@@ -27278,13 +28193,13 @@ msgstr ""
msgid "Users"
msgstr ""
-msgid "Users in License:"
+msgid "Users in License"
msgstr ""
-msgid "Users or groups set as approvers in the project's or merge request's settings."
+msgid "Users in License:"
msgstr ""
-msgid "Users outside of license"
+msgid "Users or groups set as approvers in the project's or merge request's settings."
msgstr ""
msgid "Users over License:"
@@ -27302,9 +28217,6 @@ msgstr ""
msgid "Users with a Guest role or those who don't belong to a Project or Group will not use a seat from your license."
msgstr ""
-msgid "Users with a Guest role or those who don't belong to any projects or groups don't count towards seats in use."
-msgstr ""
-
msgid "UsersSelect|%{name} + %{length} more"
msgstr ""
@@ -27344,9 +28256,6 @@ msgstr ""
msgid "Validations failed."
msgstr ""
-msgid "Validity"
-msgstr ""
-
msgid "Value"
msgstr ""
@@ -27365,6 +28274,9 @@ msgstr ""
msgid "Value Stream Name"
msgstr ""
+msgid "ValueStreamAnalyticsStage|We don't have enough data to show this stage."
+msgstr ""
+
msgid "ValueStreamAnalytics|%{days}d"
msgstr ""
@@ -27621,6 +28533,9 @@ msgstr ""
msgid "VisualReviewApp|Steps 1 and 2 (and sometimes 3) are performed once by the developer before requesting feedback. Steps 3 (if necessary), 4 is performed by the reviewer each time they perform a review."
msgstr ""
+msgid "Visualization"
+msgstr ""
+
msgid "Vulnerabilities"
msgstr ""
@@ -27648,34 +28563,31 @@ msgstr ""
msgid "VulnerabilityChart|Severity"
msgstr ""
-msgid "VulnerabilityManagement|A true-positive and will fix"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Change status"
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|Confirm"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Confirmed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
-msgstr ""
-
-msgid "VulnerabilityManagement|Detected %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|A true-positive and will fix"
msgstr ""
-msgid "VulnerabilityManagement|Dismiss"
+msgid "VulnerabilityManagement|Change status"
msgstr ""
-msgid "VulnerabilityManagement|Dismissed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
msgstr ""
-msgid "VulnerabilityManagement|Resolved"
+msgid "VulnerabilityManagement|Detected"
msgstr ""
-msgid "VulnerabilityManagement|Resolved %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Needs triage"
msgstr ""
msgid "VulnerabilityManagement|Something went wrong while trying to delete the comment. Please try again later."
@@ -27726,6 +28638,9 @@ msgstr ""
msgid "Vulnerability|%{scannerName} (version %{scannerVersion})"
msgstr ""
+msgid "Vulnerability|Activity"
+msgstr ""
+
msgid "Vulnerability|Class"
msgstr ""
@@ -27738,6 +28653,9 @@ msgstr ""
msgid "Vulnerability|Description"
msgstr ""
+msgid "Vulnerability|Detected"
+msgstr ""
+
msgid "Vulnerability|Evidence"
msgstr ""
@@ -27801,6 +28719,9 @@ msgstr ""
msgid "Warning: Displaying this diagram might cause performance issues on this page."
msgstr ""
+msgid "We are currently unable to fetch data for the pipeline header."
+msgstr ""
+
msgid "We are currently unable to fetch data for this graph."
msgstr ""
@@ -27840,6 +28761,12 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
+msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
+msgstr ""
+
+msgid "We would like to inform you that your subscription GitLab Enterprise Edition %{plan_name} is nearing its user limit. You have %{active_user_count} active users, which is almost at the user limit of %{maximum_user_count}."
+msgstr ""
+
msgid "We've found no vulnerabilities"
msgstr ""
@@ -27855,6 +28782,12 @@ msgstr ""
msgid "Web terminal"
msgstr ""
+msgid "WebAuthn Devices (%{length})"
+msgstr ""
+
+msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
+msgstr ""
+
msgid "WebIDE|Merge request"
msgstr ""
@@ -27993,15 +28926,9 @@ msgstr ""
msgid "Welcome to the guided GitLab tour"
msgstr ""
-msgid "Welcome to your Issue Board!"
-msgstr ""
-
msgid "Welcome to your issue board!"
msgstr ""
-msgid "We’ve been making changes to %{featureName} and we’d love your feedback %{linkStart}in this issue%{linkEnd} to help us improve the experience."
-msgstr ""
-
msgid "What are you searching for?"
msgstr ""
@@ -28020,6 +28947,9 @@ msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
msgstr ""
+msgid "When enabled, any user visiting %{host} and creating an account will have to be explicitly approved by the admin before they can login. This setting is effective only if sign-ups are enabled."
+msgstr ""
+
msgid "When enabled, any user visiting %{host} will be able to create an account."
msgstr ""
@@ -28244,6 +29174,9 @@ msgstr ""
msgid "With requirements, you can set criteria to check your products against."
msgstr ""
+msgid "With test cases, you can define conditions for your project to meet in determining quality"
+msgstr ""
+
msgid "Withdraw Access Request"
msgstr ""
@@ -28259,6 +29192,9 @@ msgstr ""
msgid "Workflow Help"
msgstr ""
+msgid "Would you like to create a new branch?"
+msgstr ""
+
msgid "Write"
msgstr ""
@@ -28280,6 +29216,9 @@ msgstr ""
msgid "Wrong extern UID provided. Make sure Auth0 is configured correctly."
msgstr ""
+msgid "YYYY-MM-DD"
+msgstr ""
+
msgid "Yes"
msgstr ""
@@ -28337,7 +29276,7 @@ msgstr ""
msgid "You are going to remove the fork relationship from %{project_full_name}. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "You are going to transfer %{project_full_name} to another owner. Are you ABSOLUTELY sure?"
+msgid "You are going to transfer %{project_full_name} to another namespace. Are you ABSOLUTELY sure?"
msgstr ""
msgid "You are going to turn off the confidentiality. This means %{strongStart}everyone%{strongEnd} will be able to see and leave a comment on this %{issuableType}."
@@ -28397,9 +29336,6 @@ msgstr ""
msgid "You can always edit this later"
msgstr ""
-msgid "You can apply your Trial to your Personal account or create a New Group."
-msgstr ""
-
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings"
msgstr ""
@@ -28421,12 +29357,18 @@ msgstr ""
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
+msgid "You can find more information about GitLab subscriptions in %{subscriptions_doc_link}."
+msgstr ""
+
msgid "You can generate an access token scoped to this project for each application to use the GitLab API."
msgstr ""
msgid "You can get started by cloning the repository or start adding files to it with one of the following options."
msgstr ""
+msgid "You can group test cases using labels. To learn about the future direction of this feature, visit %{linkStart}Quality Management direction page%{linkEnd}."
+msgstr ""
+
msgid "You can invite a new member to %{project_name} or invite another group."
msgstr ""
@@ -28442,6 +29384,9 @@ msgstr ""
msgid "You can notify the app / group or a project by sending them an email notification"
msgstr ""
+msgid "You can now close this window."
+msgstr ""
+
msgid "You can now export your security dashboard to a CSV report."
msgstr ""
@@ -28490,9 +29435,6 @@ msgstr ""
msgid "You can test your .gitlab-ci.yml in %{linkStart}CI Lint%{linkEnd}."
msgstr ""
-msgid "You can try again using %{begin_link}basic search%{end_link}"
-msgstr ""
-
msgid "You cannot access the raw file. Please wait a minute."
msgstr ""
@@ -28544,6 +29486,9 @@ msgstr ""
msgid "You don't have any U2F devices registered yet."
msgstr ""
+msgid "You don't have any WebAuthn devices registered yet."
+msgstr ""
+
msgid "You don't have any active chat names."
msgstr ""
@@ -28631,6 +29576,9 @@ msgstr ""
msgid "You must accept our Terms of Service and privacy policy in order to register an account"
msgstr ""
+msgid "You must be logged in to search across all of GitLab"
+msgstr ""
+
msgid "You must disassociate %{domain} from all clusters it is attached to before deletion."
msgstr ""
@@ -28670,7 +29618,7 @@ msgstr ""
msgid "You need to be logged in."
msgstr ""
-msgid "You need to register a two-factor authentication app before you can set up a U2F device."
+msgid "You need to register a two-factor authentication app before you can set up a device."
msgstr ""
msgid "You need to set terms to be enforced"
@@ -28688,6 +29636,9 @@ msgstr ""
msgid "You reached %{usage_in_percent} of %{namespace_name}'s storage capacity (%{used_storage} of %{storage_limit})"
msgstr ""
+msgid "You successfully declined the invitation"
+msgstr ""
+
msgid "You tried to fork %{link_to_the_project} but it failed for the following reason:"
msgstr ""
@@ -28853,10 +29804,13 @@ msgstr ""
msgid "Your U2F device did not send a valid JSON response."
msgstr ""
-msgid "Your U2F device needs to be set up. Plug it in (if not already) and click the button on the left."
+msgid "Your U2F device was registered!"
msgstr ""
-msgid "Your U2F device was registered!"
+msgid "Your WebAuthn device did not send a valid JSON response."
+msgstr ""
+
+msgid "Your WebAuthn device was registered!"
msgstr ""
msgid "Your access request to the %{source_type} has been withdrawn."
@@ -28880,6 +29834,9 @@ msgstr ""
msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
msgstr ""
+msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
+msgstr ""
+
msgid "Your changes can be committed to %{branch_name} because a merge request is open."
msgstr ""
@@ -28916,6 +29873,12 @@ msgstr ""
msgid "Your deployment services will be broken, you will need to manually fix the services after renaming."
msgstr ""
+msgid "Your device is not compatible with GitLab. Please try another device"
+msgstr ""
+
+msgid "Your device needs to be set up. Plug it in (if needed) and click the button on the left."
+msgstr ""
+
msgid "Your device was successfully set up! Give it a name and register it with the GitLab server."
msgstr ""
@@ -29029,9 +29992,6 @@ msgstr[1] ""
msgid "access:"
msgstr ""
-msgid "activated"
-msgstr ""
-
msgid "added %{created_at_timeago}"
msgstr ""
@@ -29104,9 +30064,21 @@ msgstr ""
msgid "by %{user}"
msgstr ""
+msgid "cannot be a date in the past"
+msgstr ""
+
msgid "cannot be changed if a personal project has container registry tags."
msgstr ""
+msgid "cannot be changed if shared runners are enabled"
+msgstr ""
+
+msgid "cannot be enabled because parent group does not allow it"
+msgstr ""
+
+msgid "cannot be enabled because parent group has shared Runners disabled"
+msgstr ""
+
msgid "cannot be enabled unless all domains have TLS certificates"
msgstr ""
@@ -29152,7 +30124,7 @@ msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about SAST %{linkEndTag}"
msgstr ""
-msgid "ciReport|%{linkStartTag}Learn more about Secret Scanning %{linkEndTag}"
+msgid "ciReport|%{linkStartTag}Learn more about Secret Detection %{linkEndTag}"
msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about codequality reports %{linkEndTag}"
@@ -29467,9 +30439,6 @@ msgstr ""
msgid "error"
msgstr ""
-msgid "error code:"
-msgstr ""
-
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr ""
@@ -29491,6 +30460,9 @@ msgstr ""
msgid "failed to dismiss associated finding(id=%{finding_id}): %{message}"
msgstr ""
+msgid "failed to revert associated finding(id=%{finding_id}) to detected"
+msgstr ""
+
msgid "file"
msgid_plural "files"
msgstr[0] ""
@@ -30033,6 +31005,9 @@ msgstr ""
msgid "must be a root namespace"
msgstr ""
+msgid "must be a valid IPv4 or IPv6 address"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -30069,6 +31044,9 @@ msgstr ""
msgid "no expiration"
msgstr ""
+msgid "no name set"
+msgstr ""
+
msgid "no one can merge"
msgstr ""
@@ -30247,9 +31225,6 @@ msgstr ""
msgid "security Reports|There was an error creating the merge request"
msgstr ""
-msgid "settings saved, but not activated"
-msgstr ""
-
msgid "severity|Critical"
msgstr ""
@@ -30376,9 +31351,6 @@ msgstr ""
msgid "toggle collapse"
msgstr ""
-msgid "toggle dropdown"
-msgstr ""
-
msgid "triggered"
msgstr ""
@@ -30406,6 +31378,9 @@ msgstr ""
msgid "user avatar"
msgstr ""
+msgid "user preferences"
+msgstr ""
+
msgid "username"
msgstr ""
diff --git a/locale/cs_CZ/gitlab.po b/locale/cs_CZ/gitlab.po
index ab1e11a272a..26c41224f85 100644
--- a/locale/cs_CZ/gitlab.po
+++ b/locale/cs_CZ/gitlab.po
@@ -14,7 +14,10 @@ msgstr ""
"X-Crowdin-Language: cs\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 6\n"
-"PO-Revision-Date: 2020-09-04 23:07\n"
+"PO-Revision-Date: 2020-10-02 18:46\n"
+
+msgid " %{project_name}#%{issue_iid} &middot; opened %{issue_created} by %{author}"
+msgstr ""
msgid " %{start} to %{end}"
msgstr ""
@@ -78,6 +81,20 @@ msgstr ""
msgid "\"el\" parameter is required for createInstance()"
msgstr ""
+msgid "%d Approval"
+msgid_plural "%d Approvals"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
+msgid "%d Package"
+msgid_plural "%d Packages"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%d Scanned URL"
msgid_plural "%d Scanned URLs"
msgstr[0] ""
@@ -165,6 +182,13 @@ msgstr[3] ""
msgid "%d commits"
msgstr ""
+msgid "%d completed issue"
+msgid_plural "%d completed issues"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%d contribution"
msgid_plural "%d contributions"
msgstr[0] ""
@@ -179,6 +203,13 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "%d day until tags are automatically removed"
+msgid_plural "%d days until tags are automatically removed"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%d error"
msgid_plural "%d errors"
msgstr[0] ""
@@ -305,6 +336,20 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "%d open issue"
+msgid_plural "%d open issues"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
+msgid "%d pending comment"
+msgid_plural "%d pending comments"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%d personal project will be removed and cannot be restored."
msgid_plural "%d personal projects will be removed and cannot be restored."
msgstr[0] ""
@@ -326,6 +371,13 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "%d project selected"
+msgid_plural "%d projects selected"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%d request with warnings"
msgid_plural "%d requests with warnings"
msgstr[0] ""
@@ -354,6 +406,13 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "%d tag per image name"
+msgid_plural "%d tags per image name"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%d unassigned issue"
msgid_plural "%d unassigned issues"
msgstr[0] ""
@@ -382,6 +441,13 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "%d warning found:"
+msgid_plural "%d warnings found:"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%s additional commit has been omitted to prevent performance issues."
msgid_plural "%s additional commits have been omitted to prevent performance issues."
msgstr[0] "%s další commit byl vynechán, aby se předešlo problémům s výkonem."
@@ -422,6 +488,9 @@ msgstr ""
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr ""
+msgid "%{completedCount} completed weight"
+msgstr ""
+
msgid "%{completedWeight} of %{totalWeight} weight completed"
msgstr ""
@@ -476,16 +545,12 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "%{count} pending comment"
-msgid_plural "%{count} pending comments"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
+msgid "%{count} total weight"
+msgstr ""
+
msgid "%{dashboard_path} could not be found."
msgstr ""
@@ -540,6 +605,9 @@ msgstr ""
msgid "%{group_name} uses group managed accounts. You need to create a new GitLab account which will be managed by %{group_name}."
msgstr ""
+msgid "%{group_name}&%{epic_iid} &middot; opened %{epic_created} by %{author}"
+msgstr ""
+
msgid "%{host} sign-in from new location"
msgstr ""
@@ -552,7 +620,7 @@ msgstr ""
msgid "%{issuableType} will be removed! Are you sure?"
msgstr ""
-msgid "%{issuesSize} issues with a limit of %{maxIssueCount}"
+msgid "%{issuesCount} issues with a limit of %{maxIssueCount}"
msgstr ""
msgid "%{issuesSize} with a limit of %{maxIssueCount}"
@@ -585,7 +653,7 @@ msgstr ""
msgid "%{labelStart}Namespace:%{labelEnd} %{namespace}"
msgstr ""
-msgid "%{labelStart}Report Type:%{labelEnd} %{reportType}"
+msgid "%{labelStart}Scan Type:%{labelEnd} %{reportType}"
msgstr ""
msgid "%{labelStart}Scanner:%{labelEnd} %{scanner}"
@@ -796,9 +864,6 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "%{service_title} %{message}."
-msgstr ""
-
msgid "%{size} GiB"
msgstr ""
@@ -812,7 +877,7 @@ msgid "%{size} bytes"
msgstr ""
msgid "%{sourceBranch} into %{targetBranch}"
-msgstr ""
+msgstr "%{sourceBranch} do %{targetBranch}"
msgid "%{spammable_titlecase} was submitted to Akismet successfully."
msgstr ""
@@ -830,7 +895,7 @@ msgid "%{state} epics"
msgstr ""
msgid "%{strongStart}Deletes%{strongEnd} source branch"
-msgstr ""
+msgstr "%{strongStart}Odstraní%{strongEnd} zdrojovou větev"
msgid "%{strongStart}Note:%{strongEnd} Once a custom stage has been added you can re-order stages by dragging them into the desired position."
msgstr ""
@@ -897,6 +962,12 @@ msgstr "%{text} je k dispozici"
msgid "%{timebox_name} should belong either to a project or a group."
msgstr ""
+msgid "%{timebox_type} does not support burnup charts"
+msgstr ""
+
+msgid "%{timebox_type} must have a start and due date"
+msgstr ""
+
msgid "%{title} %{operator} %{threshold}"
msgstr ""
@@ -921,7 +992,7 @@ msgstr ""
msgid "%{total} open issue weight"
msgstr ""
-msgid "%{total} open issues"
+msgid "%{total} warnings found: showing first %{warningsDisplayed}"
msgstr ""
msgid "%{usage_ping_link_start}Learn more%{usage_ping_link_end} about what information is shared with GitLab Inc."
@@ -954,9 +1025,6 @@ msgstr ""
msgid "&lt; 1 hour"
msgstr ""
-msgid "&lt;no name set&gt;"
-msgstr ""
-
msgid "&lt;no scopes selected&gt;"
msgstr ""
@@ -987,6 +1055,9 @@ msgstr ""
msgid "'%{name}' Value Stream created"
msgstr ""
+msgid "'%{name}' Value Stream deleted"
+msgstr ""
+
msgid "'%{name}' stage already exists"
msgstr ""
@@ -1048,6 +1119,9 @@ msgstr ""
msgid "+ %{numberOfHiddenAssignees} more"
msgstr ""
+msgid "+ %{numberOfHiddenReviewers} more"
+msgstr ""
+
msgid "+%d more"
msgid_plural "+%d more"
msgstr[0] ""
@@ -1120,6 +1194,13 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "1 Issue"
+msgid_plural "%d Issues"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "1 closed issue"
msgid_plural "%{issues} closed issues"
msgstr[0] ""
@@ -1141,6 +1222,13 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "1 deploy key"
+msgid_plural "%d deploy keys"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1261,6 +1349,9 @@ msgstr ""
msgid ":%{startLine} to %{endLine}"
msgstr ""
+msgid "A %{incident_docs_start}modified issue%{incident_docs_end} to guide the resolution of incidents."
+msgstr ""
+
msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr ""
@@ -1273,6 +1364,9 @@ msgstr ""
msgid "A GitBook site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
+msgid "A Gitpod configured Webapplication in Spring and Java"
+msgstr ""
+
msgid "A Hexo site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
@@ -1444,9 +1538,15 @@ msgstr ""
msgid "Access expiration date"
msgstr ""
+msgid "Access expires"
+msgstr ""
+
msgid "Access forbidden. Check your access level."
msgstr ""
+msgid "Access granted"
+msgstr ""
+
msgid "Access requests"
msgstr ""
@@ -1456,6 +1556,9 @@ msgstr ""
msgid "Access to Pages websites are controlled based on the user's membership to a given project. By checking this box, users will be required to be logged in to have access to all Pages websites in your instance."
msgstr ""
+msgid "AccessDropdown|Deploy Keys"
+msgstr ""
+
msgid "AccessDropdown|Groups"
msgstr ""
@@ -1573,12 +1676,6 @@ msgstr ""
msgid "Active Sessions"
msgstr ""
-msgid "Active Users:"
-msgstr ""
-
-msgid "Active users"
-msgstr ""
-
msgid "Activity"
msgstr ""
@@ -1748,9 +1845,6 @@ msgstr ""
msgid "Add label(s)"
msgstr ""
-msgid "Add license"
-msgstr ""
-
msgid "Add list"
msgstr ""
@@ -1896,7 +1990,7 @@ msgid "Admin Notifications"
msgstr ""
msgid "Admin Overview"
-msgstr ""
+msgstr "Admin Přehled"
msgid "Admin Section"
msgstr ""
@@ -1925,21 +2019,51 @@ msgstr ""
msgid "AdminArea|Bots"
msgstr ""
+msgid "AdminArea|Components"
+msgstr ""
+
msgid "AdminArea|Developer"
msgstr ""
+msgid "AdminArea|Features"
+msgstr ""
+
+msgid "AdminArea|Groups: %{number_of_groups}"
+msgstr ""
+
msgid "AdminArea|Guest"
msgstr ""
msgid "AdminArea|Included Free in license"
msgstr ""
+msgid "AdminArea|Latest groups"
+msgstr ""
+
+msgid "AdminArea|Latest projects"
+msgstr ""
+
+msgid "AdminArea|Latest users"
+msgstr ""
+
msgid "AdminArea|Maintainer"
msgstr ""
+msgid "AdminArea|New group"
+msgstr ""
+
+msgid "AdminArea|New project"
+msgstr ""
+
+msgid "AdminArea|New user"
+msgstr ""
+
msgid "AdminArea|Owner"
msgstr ""
+msgid "AdminArea|Projects: %{number_of_projects}"
+msgstr ""
+
msgid "AdminArea|Reporter"
msgstr ""
@@ -1967,6 +2091,9 @@ msgstr ""
msgid "AdminArea|Users without a Group and Project"
msgstr ""
+msgid "AdminArea|Users: %{number_of_users}"
+msgstr ""
+
msgid "AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running."
msgstr "Chystáte se zastavit všechny úlohy. To způsobí přerušení všech aktuálně spuštěných úloh."
@@ -1985,9 +2112,6 @@ msgstr ""
msgid "AdminProjects|Delete Project %{projectName}?"
msgstr ""
-msgid "AdminProjects|Delete project"
-msgstr ""
-
msgid "AdminSettings|Apply integration settings to all Projects"
msgstr ""
@@ -2225,21 +2349,30 @@ msgstr ""
msgid "AdminUsers|Without projects"
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 ""
msgid "AdminUsers|You cannot remove your own admin rights."
msgstr ""
+msgid "AdminUsers|You must transfer ownership or delete the groups owned by this user before you can delete their account"
+msgstr ""
+
msgid "Administration"
msgstr ""
msgid "Advanced"
msgstr ""
+msgid "Advanced Search"
+msgstr ""
+
+msgid "Advanced Search with Elasticsearch"
+msgstr ""
+
msgid "Advanced Settings"
msgstr ""
@@ -2319,6 +2452,9 @@ msgstr ""
msgid "AlertManagement|Edit"
msgstr ""
+msgid "AlertManagement|Environment"
+msgstr ""
+
msgid "AlertManagement|Events"
msgstr ""
@@ -2331,6 +2467,9 @@ msgstr ""
msgid "AlertManagement|Issue"
msgstr ""
+msgid "AlertManagement|Key"
+msgstr ""
+
msgid "AlertManagement|Low"
msgstr ""
@@ -2424,6 +2563,9 @@ msgstr ""
msgid "AlertManagement|Unknown"
msgstr ""
+msgid "AlertManagement|Value"
+msgstr ""
+
msgid "AlertManagement|View alerts in Opsgenie"
msgstr ""
@@ -2583,6 +2725,9 @@ msgstr ""
msgid "All projects"
msgstr ""
+msgid "All projects selected"
+msgstr ""
+
msgid "All security scans are enabled because %{linkStart}Auto DevOps%{linkEnd} is enabled on this project"
msgstr ""
@@ -2670,6 +2815,9 @@ msgstr ""
msgid "Almost there"
msgstr ""
+msgid "Already blocked"
+msgstr ""
+
msgid "Also called \"Issuer\" or \"Relying party trust identifier\""
msgstr ""
@@ -2724,6 +2872,9 @@ msgstr ""
msgid "An error has occurred"
msgstr ""
+msgid "An error occured while making the changes: %{error}"
+msgstr ""
+
msgid "An error occurred adding a draft to the thread."
msgstr ""
@@ -2751,12 +2902,6 @@ msgstr ""
msgid "An error occurred when toggling the notification subscription"
msgstr ""
-msgid "An error occurred when trying to resolve a comment. Please try again."
-msgstr ""
-
-msgid "An error occurred when trying to resolve a discussion. Please try again."
-msgstr ""
-
msgid "An error occurred when updating the issue weight"
msgstr ""
@@ -2772,12 +2917,6 @@ msgstr ""
msgid "An error occurred while checking group path. Please refresh and try again."
msgstr ""
-msgid "An error occurred while committing your changes."
-msgstr ""
-
-msgid "An error occurred while creating the list. Please try again."
-msgstr ""
-
msgid "An error occurred while decoding the file."
msgstr ""
@@ -2850,25 +2989,19 @@ msgstr ""
msgid "An error occurred while fetching the Service Desk address."
msgstr ""
-msgid "An error occurred while fetching the board issues. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the board lists. Please reload the page."
msgstr ""
msgid "An error occurred while fetching the board lists. Please try again."
msgstr ""
-msgid "An error occurred while fetching the board swimlanes. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the builds."
msgstr ""
msgid "An error occurred while fetching the job log."
msgstr ""
-msgid "An error occurred while fetching the job trace."
+msgid "An error occurred while fetching the job logs."
msgstr ""
msgid "An error occurred while fetching the job."
@@ -3015,9 +3148,6 @@ msgstr ""
msgid "An error occurred while saving assignees"
msgstr ""
-msgid "An error occurred while saving the template. Please check if the template exists."
-msgstr ""
-
msgid "An error occurred while searching for milestones"
msgstr ""
@@ -3036,10 +3166,10 @@ msgstr ""
msgid "An error occurred while updating approvers"
msgstr ""
-msgid "An error occurred while updating the comment"
+msgid "An error occurred while updating labels."
msgstr ""
-msgid "An error occurred while updating the list. Please try again."
+msgid "An error occurred while updating the comment"
msgstr ""
msgid "An error occurred while validating group path"
@@ -3093,6 +3223,9 @@ msgstr ""
msgid "An unknown error occurred while loading this graph."
msgstr ""
+msgid "An unknown error occurred."
+msgstr ""
+
msgid "Analytics"
msgstr ""
@@ -3126,10 +3259,10 @@ msgstr ""
msgid "Any"
msgstr ""
-msgid "Any Author"
+msgid "Any %{header}"
msgstr ""
-msgid "Any Status"
+msgid "Any Author"
msgstr ""
msgid "Any branch"
@@ -3183,6 +3316,9 @@ msgstr ""
msgid "Application ID"
msgstr ""
+msgid "Application limits saved successfully"
+msgstr ""
+
msgid "Application settings saved successfully"
msgstr ""
@@ -3400,6 +3536,9 @@ msgstr ""
msgid "Are you sure you want to close this blocked issue?"
msgstr ""
+msgid "Are you sure you want to delete \"%{name}\" Value Stream?"
+msgstr ""
+
msgid "Are you sure you want to delete %{name}?"
msgstr ""
@@ -3409,6 +3548,9 @@ msgstr ""
msgid "Are you sure you want to delete this %{typeOfComment}?"
msgstr ""
+msgid "Are you sure you want to delete this SSH key?"
+msgstr ""
+
msgid "Are you sure you want to delete this board?"
msgstr ""
@@ -3433,6 +3575,13 @@ msgstr ""
msgid "Are you sure you want to erase this build?"
msgstr ""
+msgid "Are you sure you want to import %d repository?"
+msgid_plural "Are you sure you want to import %d repositories?"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "Are you sure you want to lose unsaved changes?"
msgstr ""
@@ -3442,15 +3591,15 @@ msgstr ""
msgid "Are you sure you want to merge immediately?"
msgstr ""
-msgid "Are you sure you want to permanently delete this license?"
-msgstr ""
-
msgid "Are you sure you want to re-deploy this environment?"
msgstr ""
msgid "Are you sure you want to regenerate the public key? You will have to update the public key on the remote server before mirroring will work again."
msgstr ""
+msgid "Are you sure you want to reindex?"
+msgstr ""
+
msgid "Are you sure you want to remove %{group_name}?"
msgstr ""
@@ -3478,6 +3627,9 @@ msgstr ""
msgid "Are you sure you want to revoke this nickname?"
msgstr ""
+msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
+msgstr ""
+
msgid "Are you sure you want to stop this environment?"
msgstr ""
@@ -3499,6 +3651,9 @@ msgstr ""
msgid "Are you sure? The device will be signed out of GitLab and all remember me tokens revoked."
msgstr ""
+msgid "Are you sure? This will invalidate your registered applications and U2F / WebAuthn devices."
+msgstr ""
+
msgid "Are you sure? This will invalidate your registered applications and U2F devices."
msgstr ""
@@ -3517,9 +3672,6 @@ msgstr ""
msgid "Artifacts"
msgstr "Artefakty"
-msgid "As U2F devices are only supported by a few browsers, we require that you set up a two-factor authentication app before a U2F device. That way you'll always be able to log in - even when you're using an unsupported browser."
-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 ""
@@ -3717,6 +3869,9 @@ msgstr ""
msgid "AuditLogs|Target"
msgstr ""
+msgid "AuditLogs|This month"
+msgstr ""
+
msgid "AuditLogs|User Events"
msgstr ""
@@ -3756,6 +3911,9 @@ msgstr ""
msgid "Authentication via U2F device failed."
msgstr ""
+msgid "Authentication via WebAuthn device failed."
+msgstr ""
+
msgid "Author"
msgstr "Autor"
@@ -4023,15 +4181,6 @@ msgstr ""
msgid "BambooService|You must set up automatic revision labeling and a repository trigger in Bamboo."
msgstr ""
-msgid "BatchComments|Delete all pending comments"
-msgstr ""
-
-msgid "BatchComments|Discard review?"
-msgstr ""
-
-msgid "BatchComments|You're about to discard your review which will delete all of your pending comments. The deleted comments %{strong_start}cannot%{strong_end} be restored."
-msgstr ""
-
msgid "Be careful. Changing the project's namespace can have unintended side effects."
msgstr ""
@@ -4053,6 +4202,9 @@ msgstr ""
msgid "Bi-weekly code coverage"
msgstr ""
+msgid "Billable Users:"
+msgstr ""
+
msgid "Billing"
msgstr ""
@@ -4062,7 +4214,7 @@ msgstr ""
msgid "BillingPlans|@%{user_name} you are currently using the %{plan_name} plan."
msgstr ""
-msgid "BillingPlans|Congratulations, your new trial is activated"
+msgid "BillingPlans|Congratulations, your free trial is activated."
msgstr ""
msgid "BillingPlans|If you would like to downgrade your plan please contact %{support_link_start}Customer Support%{support_link_end}."
@@ -4125,6 +4277,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Block user"
+msgstr ""
+
msgid "Blocked"
msgstr ""
@@ -4140,31 +4295,37 @@ msgstr ""
msgid "Blog"
msgstr ""
-msgid "Board name"
-msgstr ""
-
msgid "Board scope"
msgstr ""
msgid "Board scope affects which issues are displayed for anyone who visits this board"
msgstr ""
-msgid "BoardBlankState|Add default lists"
+msgid "Boards"
msgstr ""
-msgid "BoardBlankState|Add the following default lists to your Issue Board with one click:"
+msgid "Boards and Board Lists"
msgstr ""
-msgid "BoardBlankState|Nevermind, I'll use my own"
+msgid "Boards|An error occurred while creating the issue. Please try again."
msgstr ""
-msgid "BoardBlankState|Starting out with the default set of lists will get you right on the way to making the most of your board."
+msgid "Boards|An error occurred while creating the list. Please try again."
msgstr ""
-msgid "Boards"
+msgid "Boards|An error occurred while fetching issues. Please reload the page."
msgstr ""
-msgid "Boards and Board Lists"
+msgid "Boards|An error occurred while fetching the board issues. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching the board swimlanes. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while moving the issue. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while updating the list. Please try again."
msgstr ""
msgid "Boards|Collapse"
@@ -4183,7 +4344,7 @@ msgid "Both project and dashboard_path are required"
msgstr ""
msgid "Branch"
-msgstr ""
+msgstr "Větev"
msgid "Branch %{branchName} was not found in this project's repository."
msgstr ""
@@ -4191,14 +4352,14 @@ msgstr ""
msgid "Branch %{branch_name} was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr ""
-msgid "Branch has changed"
+msgid "Branch changed"
msgstr ""
msgid "Branch is already taken"
-msgstr ""
+msgstr "Tato větev již existuje"
msgid "Branch name"
-msgstr ""
+msgstr "Název větve"
msgid "Branch not loaded - %{branchId}"
msgstr ""
@@ -4213,37 +4374,37 @@ msgid "BranchSwitcherTitle|Switch branch"
msgstr ""
msgid "Branches"
-msgstr ""
+msgstr "Větve"
msgid "Branches|Active"
-msgstr ""
+msgstr "Aktivní"
msgid "Branches|Active branches"
-msgstr ""
+msgstr "Aktivní větve"
msgid "Branches|All"
-msgstr ""
+msgstr "VÅ¡echny"
msgid "Branches|Cant find HEAD commit for this branch"
msgstr ""
msgid "Branches|Compare"
-msgstr ""
+msgstr "Porovnat"
msgid "Branches|Delete all branches that are merged into '%{default_branch}'"
msgstr ""
msgid "Branches|Delete branch"
-msgstr ""
+msgstr "Odstranit větev"
msgid "Branches|Delete merged branches"
msgstr ""
msgid "Branches|Delete protected branch"
-msgstr ""
+msgstr "Odstranit chráněnou větev"
msgid "Branches|Delete protected branch '%{branch_name}'?"
-msgstr ""
+msgstr "Odstranit chráněnou větev '%{branch_name}'?"
msgid "Branches|Deleting the '%{branch_name}' branch cannot be undone. Are you sure?"
msgstr ""
@@ -4252,61 +4413,61 @@ msgid "Branches|Deleting the merged branches cannot be undone. Are you sure?"
msgstr ""
msgid "Branches|Filter by branch name"
-msgstr ""
+msgstr "Filtrovat podle názvu větve"
msgid "Branches|Merged into %{default_branch}"
msgstr ""
msgid "Branches|New branch"
-msgstr ""
+msgstr "Nová větev"
msgid "Branches|No branches to show"
-msgstr ""
+msgstr "Žádné větve k zobrazení"
msgid "Branches|Once you confirm and press %{delete_protected_branch}, it cannot be undone or recovered."
msgstr ""
msgid "Branches|Only a project maintainer or owner can delete a protected branch"
-msgstr ""
+msgstr "Pouze správce projektu může odstranit chráněnou větev"
msgid "Branches|Overview"
-msgstr ""
+msgstr "Přehled"
msgid "Branches|Protected branches can be managed in %{project_settings_link}."
msgstr ""
msgid "Branches|Show active branches"
-msgstr ""
+msgstr "Zobrazit aktivní větve"
msgid "Branches|Show all branches"
-msgstr ""
+msgstr "Zobrazit všechny větve"
msgid "Branches|Show more active branches"
-msgstr ""
+msgstr "Zobrazit další aktivní větve"
msgid "Branches|Show more stale branches"
-msgstr ""
+msgstr "Zobrazit další zastaralé větve"
msgid "Branches|Show overview of the branches"
-msgstr ""
+msgstr "Zobrazit přehled větví"
msgid "Branches|Show stale branches"
-msgstr ""
+msgstr "Zobrazit zastaralé větve"
msgid "Branches|Sort by"
-msgstr ""
+msgstr "Seřadit podle"
msgid "Branches|Stale"
-msgstr ""
+msgstr "Zastaralé"
msgid "Branches|Stale branches"
-msgstr ""
+msgstr "Zastaralé větve"
msgid "Branches|The branch could not be updated automatically because it has diverged from its upstream counterpart."
msgstr ""
msgid "Branches|The default branch cannot be deleted"
-msgstr ""
+msgstr "Výchozí větev nelze odstranit"
msgid "Branches|This branch hasn’t been merged into %{default_branch}."
msgstr ""
@@ -4321,7 +4482,7 @@ msgid "Branches|To discard the local changes and overwrite the branch with the u
msgstr ""
msgid "Branches|You’re about to permanently delete the protected branch %{branch_name}."
-msgstr ""
+msgstr "Chystáte se trvale odstranit chráněnou větev %{branch_name}."
msgid "Branches|diverged from upstream"
msgstr ""
@@ -4330,7 +4491,7 @@ msgid "Branches|merged"
msgstr ""
msgid "Branches|project settings"
-msgstr ""
+msgstr "nastavení projektu"
msgid "Branches|protected"
msgstr ""
@@ -4497,6 +4658,9 @@ msgstr ""
msgid "CLOSED (MOVED)"
msgstr ""
+msgid "CODEOWNERS rule violation"
+msgstr ""
+
msgid "CONTRIBUTING"
msgstr ""
@@ -4527,9 +4691,6 @@ msgstr ""
msgid "Can't create snippet: %{err}"
msgstr ""
-msgid "Can't edit as source branch was deleted"
-msgstr ""
-
msgid "Can't fetch content for the blob: %{err}"
msgstr ""
@@ -4542,9 +4703,6 @@ msgstr ""
msgid "Can't load mermaid module: %{err}"
msgstr ""
-msgid "Can't remove group members without group managed account"
-msgstr ""
-
msgid "Can't scan the code?"
msgstr ""
@@ -4587,6 +4745,9 @@ msgstr ""
msgid "Cannot create the abuse report. This user has been blocked."
msgstr ""
+msgid "Cannot enable shared runners because parent group does not allow it"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -4692,6 +4853,15 @@ msgstr ""
msgid "Change your password or recover your current one"
msgstr ""
+msgid "ChangeReviewer|Reviewer changed from %{old} to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Reviewer changed to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Unassigned"
+msgstr ""
+
msgid "ChangeTypeActionLabel|Pick into branch"
msgstr ""
@@ -4731,6 +4901,9 @@ msgstr ""
msgid "Changes the title to \"%{title_param}\"."
msgstr ""
+msgid "Changes were successfully made."
+msgstr ""
+
msgid "Changes won't take place until the index is %{link_start}recreated%{link_end}."
msgstr ""
@@ -5136,6 +5309,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove variable"
+msgstr ""
+
msgid "CiVariables|Remove variable row"
msgstr ""
@@ -5214,9 +5390,6 @@ msgstr ""
msgid "Clear due date"
msgstr ""
-msgid "Clear input"
-msgstr ""
-
msgid "Clear recent searches"
msgstr ""
@@ -5265,6 +5438,9 @@ msgstr ""
msgid "Client authentication key password"
msgstr ""
+msgid "Client request timeout"
+msgstr ""
+
msgid "Clients"
msgstr ""
@@ -5349,6 +5525,27 @@ msgstr ""
msgid "Cluster type must be specificed for Stages::ClusterEndpointInserter"
msgstr ""
+msgid "ClusterAgents|Configuration"
+msgstr ""
+
+msgid "ClusterAgents|Connect your cluster with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate Kubernetes with a GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Name"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Agent also requires %{linkStart}enabling the Agent Server%{linkEnd}"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Kubernetes Agent allows an Infrastructure as Code, GitOps approach to integrating Kubernetes clusters with GitLab. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "ClusterAgent|This feature is only available for premium plans"
msgstr ""
@@ -5418,10 +5615,10 @@ msgstr ""
msgid "ClusterIntegration|All installed applications and related resources"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster."
+msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{linkStart}More information%{linkEnd}"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{startLink}More information%{endLink}"
+msgid "ClusterIntegration|Allow GitLab to manage namespaces and service accounts for this cluster."
msgstr ""
msgid "ClusterIntegration|Alternatively, "
@@ -5442,6 +5639,9 @@ msgstr ""
msgid "ClusterIntegration|An error occurred while trying to fetch zone machine types: %{error}"
msgstr ""
+msgid "ClusterIntegration|An unknown error occurred while attempting to connect to Kubernetes."
+msgstr ""
+
msgid "ClusterIntegration|Any project namespaces"
msgstr ""
@@ -5457,6 +5657,9 @@ msgstr ""
msgid "ClusterIntegration|Authenticate with Amazon Web Services"
msgstr ""
+msgid "ClusterIntegration|Authentication Error"
+msgstr ""
+
msgid "ClusterIntegration|Base domain"
msgstr ""
@@ -5475,13 +5678,22 @@ msgstr ""
msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}security group %{externalLinkIcon} %{endLink} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
+msgid "ClusterIntegration|Check your CA certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Check your cluster status"
+msgstr ""
+
+msgid "ClusterIntegration|Check your token"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}subnets %{externalLinkIcon} %{endLink} in your VPC where your worker nodes will run."
+msgid "ClusterIntegration|Choose the %{linkStart}security group %{linkEnd} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
msgstr ""
-msgid "ClusterIntegration|Choose the worker node %{startLink}instance type %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Choose the %{linkStart}subnets %{linkEnd} in your VPC where your worker nodes will run."
+msgstr ""
+
+msgid "ClusterIntegration|Choose the worker node %{linkStart}instance type%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Choose which applications to install on your Kubernetes cluster."
@@ -5493,10 +5705,7 @@ msgstr ""
msgid "ClusterIntegration|Clear cluster cache"
msgstr ""
-msgid "ClusterIntegration|Clear the local cache of namespace and service accounts. This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
-msgstr ""
-
-msgid "ClusterIntegration|Cluster being created"
+msgid "ClusterIntegration|Clear the local cache of namespace and service accounts."
msgstr ""
msgid "ClusterIntegration|Cluster management project (alpha)"
@@ -5508,15 +5717,21 @@ msgstr ""
msgid "ClusterIntegration|Cluster_applications artifact too big. Maximum allowable size: %{human_size}"
msgstr ""
-msgid "ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters."
+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|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}"
+msgid "ClusterIntegration|Clusters connected with a certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Connect cluster with certificate"
msgstr ""
msgid "ClusterIntegration|Connect existing cluster"
msgstr ""
+msgid "ClusterIntegration|Connection Error"
+msgstr ""
+
msgid "ClusterIntegration|Copy API URL"
msgstr ""
@@ -5592,6 +5807,12 @@ msgstr ""
msgid "ClusterIntegration|Deletes all GitLab resources attached to this cluster during removal"
msgstr ""
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared."
+msgstr ""
+
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared. %{linkStart}More information%{linkEnd}"
+msgstr ""
+
msgid "ClusterIntegration|Did you know?"
msgstr ""
@@ -5661,6 +5882,9 @@ msgstr ""
msgid "ClusterIntegration|Fluentd is an open source data collector, which lets you unify the data collection and consumption for a better use and understanding of data. It requires at least one of the following logs to be successfully installed."
msgstr ""
+msgid "ClusterIntegration|GitLab Agent managed clusters"
+msgstr ""
+
msgid "ClusterIntegration|GitLab Container Network Policies"
msgstr ""
@@ -5673,6 +5897,12 @@ msgstr ""
msgid "ClusterIntegration|GitLab Runner connects to the repository and executes CI/CD jobs, pushing results back and deploying applications to production."
msgstr ""
+msgid "ClusterIntegration|GitLab failed to authenticate."
+msgstr ""
+
+msgid "ClusterIntegration|GitLab failed to connect to the cluster."
+msgstr ""
+
msgid "ClusterIntegration|GitLab-managed cluster"
msgstr ""
@@ -5694,6 +5924,9 @@ msgstr ""
msgid "ClusterIntegration|Group cluster"
msgstr ""
+msgid "ClusterIntegration|HTTP Error"
+msgstr ""
+
msgid "ClusterIntegration|Helm Tiller"
msgstr ""
@@ -5727,7 +5960,10 @@ msgstr ""
msgid "ClusterIntegration|Instance type"
msgstr ""
-msgid "ClusterIntegration|Integrate Kubernetes cluster automation"
+msgid "ClusterIntegration|Integrate Kubernetes with a cluster certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Integrate with a cluster certificate"
msgstr ""
msgid "ClusterIntegration|Issuer Email"
@@ -5763,9 +5999,6 @@ msgstr ""
msgid "ClusterIntegration|Knative extends Kubernetes to provide a set of middleware components that are essential to build modern, source-centric, and container-based applications that can run anywhere: on premises, in the cloud, or even in a third-party data center."
msgstr ""
-msgid "ClusterIntegration|Kubernetes cluster"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes cluster is being created..."
msgstr ""
@@ -5778,9 +6011,6 @@ msgstr ""
msgid "ClusterIntegration|Kubernetes clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr ""
-msgid "ClusterIntegration|Kubernetes clusters can be used to deploy applications and to provide Review Apps for this project"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes version"
msgstr ""
@@ -5793,7 +6023,7 @@ msgstr ""
msgid "ClusterIntegration|Learn more about %{help_link_start}zones%{help_link_end}."
msgstr ""
-msgid "ClusterIntegration|Learn more about %{startLink}Regions %{externalLinkIcon}%{endLink}."
+msgid "ClusterIntegration|Learn more about %{linkStart}Regions%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Learn more about Kubernetes"
@@ -5838,12 +6068,18 @@ msgstr ""
msgid "ClusterIntegration|Machine type"
msgstr ""
+msgid "ClusterIntegration|Make sure your API endpoint is correct"
+msgstr ""
+
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create Kubernetes clusters"
msgstr ""
msgid "ClusterIntegration|Manage your Kubernetes cluster by visiting %{provider_link}"
msgstr ""
+msgid "ClusterIntegration|Namespace per environment"
+msgstr ""
+
msgid "ClusterIntegration|No IAM Roles found"
msgstr ""
@@ -5889,6 +6125,9 @@ msgstr ""
msgid "ClusterIntegration|No zones matched your search"
msgstr ""
+msgid "ClusterIntegration|Node calculations use the Kubernetes Metrics API. Make sure your cluster has metrics installed"
+msgstr ""
+
msgid "ClusterIntegration|Number of nodes"
msgstr ""
@@ -5931,6 +6170,9 @@ msgstr ""
msgid "ClusterIntegration|RBAC-enabled cluster"
msgstr ""
+msgid "ClusterIntegration|Read our %{linkStart}help page%{linkEnd} on Kubernetes cluster integration."
+msgstr ""
+
msgid "ClusterIntegration|Read our %{link_start}help page%{link_end} on Kubernetes cluster integration."
msgstr ""
@@ -6033,7 +6275,7 @@ msgstr ""
msgid "ClusterIntegration|Select a VPC to choose a subnet"
msgstr ""
-msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{linkStart}Amazon Web Services %{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select a network to choose a subnetwork"
@@ -6066,7 +6308,7 @@ msgstr ""
msgid "ClusterIntegration|Select project to choose zone"
msgstr ""
-msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select zone"
@@ -6156,9 +6398,18 @@ msgstr ""
msgid "ClusterIntegration|There was a problem authenticating with your cluster. Please ensure your CA Certificate and Token are valid."
msgstr ""
+msgid "ClusterIntegration|There was an HTTP error when connecting to your cluster."
+msgstr ""
+
msgid "ClusterIntegration|This account must have permissions to create a Kubernetes cluster in the %{link_to_container_project} specified below"
msgstr ""
+msgid "ClusterIntegration|This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
+msgstr ""
+
+msgid "ClusterIntegration|This is necessary to clear existing environment-namespace associations from clusters previously managed by GitLab."
+msgstr ""
+
msgid "ClusterIntegration|This option will allow you to install applications on RBAC clusters."
msgstr ""
@@ -6183,9 +6434,21 @@ msgstr ""
msgid "ClusterIntegration|To use a new project, first create one on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}."
msgstr ""
+msgid "ClusterIntegration|Troubleshooting tips:"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Authenticate"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Connect"
+msgstr ""
+
msgid "ClusterIntegration|Uninstall %{appTitle}"
msgstr ""
+msgid "ClusterIntegration|Unknown Error"
+msgstr ""
+
msgid "ClusterIntegration|Update %{appTitle}"
msgstr ""
@@ -6246,7 +6509,7 @@ msgstr ""
msgid "ClusterIntegration|Your cluster API is unreachable. Please ensure your API URL is correct."
msgstr ""
-msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Zone"
@@ -6366,6 +6629,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse all threads"
+msgstr ""
+
msgid "Collapse approvers"
msgstr ""
@@ -6517,7 +6783,7 @@ msgstr ""
msgid "Commit…"
msgstr ""
-msgid "Company"
+msgid "Community forum"
msgstr ""
msgid "Company name"
@@ -6526,6 +6792,9 @@ msgstr ""
msgid "Compare"
msgstr ""
+msgid "Compare %{oldCommitId}...%{newCommitId}"
+msgstr ""
+
msgid "Compare Git revisions"
msgstr ""
@@ -6541,6 +6810,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare submodule commit revisions"
+msgstr ""
+
msgid "Compare with previous version"
msgstr ""
@@ -6548,13 +6820,13 @@ msgid "CompareBranches|%{source_branch} and %{target_branch} are the same."
msgstr ""
msgid "CompareBranches|Compare"
-msgstr ""
+msgstr "Porovnat"
msgid "CompareBranches|Source"
-msgstr ""
+msgstr "Zdroj"
msgid "CompareBranches|Target"
-msgstr ""
+msgstr "Cíl"
msgid "CompareBranches|There isn't anything to compare."
msgstr ""
@@ -6676,6 +6948,9 @@ msgstr ""
msgid "Configure the way a user creates a new account."
msgstr ""
+msgid "Configure which lists are shown for anyone who visits this board"
+msgstr ""
+
msgid "Confirm"
msgstr ""
@@ -6907,6 +7182,9 @@ msgstr[3] ""
msgid "ContainerRegistry|Set cleanup policy"
msgstr ""
+msgid "ContainerRegistry|Some tags were not deleted"
+msgstr ""
+
msgid "ContainerRegistry|Something went wrong while fetching the cleanup policy."
msgstr ""
@@ -6946,6 +7224,9 @@ msgstr ""
msgid "ContainerRegistry|Tags with names matching this regex pattern will %{italicStart}expire:%{italicEnd}"
msgstr ""
+msgid "ContainerRegistry|The cleanup policy timed out before it could delete all tags. An administrator can %{adminLinkStart}manually run cleanup now%{adminLinkEnd} or you can wait for the cleanup policy to automatically run again. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "ContainerRegistry|The last tag related to this image was recently removed. This empty image and any associated data will be automatically removed as part of the regular Garbage Collection process. If you have any questions, contact your administrator."
msgstr ""
@@ -7078,6 +7359,9 @@ msgstr ""
msgid "Contributions per group member"
msgstr ""
+msgid "Contributor"
+msgstr ""
+
msgid "Contributors"
msgstr ""
@@ -7133,7 +7417,7 @@ msgid "Copy URL"
msgstr ""
msgid "Copy branch name"
-msgstr ""
+msgstr "Kopírovat název větve"
msgid "Copy command"
msgstr ""
@@ -7207,6 +7491,9 @@ msgstr ""
msgid "Could not change HEAD: branch '%{branch}' does not exist"
msgstr ""
+msgid "Could not commit. An unexpected error occurred."
+msgstr ""
+
msgid "Could not connect to FogBugz, check your URL"
msgstr ""
@@ -7246,6 +7533,9 @@ msgstr ""
msgid "Could not find iteration"
msgstr ""
+msgid "Could not load instance counts. Please refresh the page to try again."
+msgstr ""
+
msgid "Could not remove the trigger."
msgstr ""
@@ -7270,10 +7560,10 @@ msgstr ""
msgid "Could not save prometheus manual configuration"
msgstr ""
-msgid "Could not udpdate wiki page"
+msgid "Could not update the LDAP settings"
msgstr ""
-msgid "Could not update the LDAP settings"
+msgid "Could not update wiki page"
msgstr ""
msgid "Could not upload your designs as one or more files uploaded are not supported."
@@ -7935,6 +8225,9 @@ msgstr ""
msgid "DastProfiles|Are you sure you want to delete this profile?"
msgstr ""
+msgid "DastProfiles|Could not create site validation token. Please refresh the page, or try again later."
+msgstr ""
+
msgid "DastProfiles|Could not create the scanner profile. Please try again."
msgstr ""
@@ -7959,6 +8252,12 @@ msgstr ""
msgid "DastProfiles|Could not fetch site profiles. Please refresh the page, or try again later."
msgstr ""
+msgid "DastProfiles|Could not retrieve site validation status. Please refresh the page, or try again later."
+msgstr ""
+
+msgid "DastProfiles|Could not update the scanner profile. Please try again."
+msgstr ""
+
msgid "DastProfiles|Could not update the site profile. Please try again."
msgstr ""
@@ -7974,7 +8273,7 @@ msgstr ""
msgid "DastProfiles|Download validation text file"
msgstr ""
-msgid "DastProfiles|Edit feature will come soon. Please create a new profile if changes needed"
+msgid "DastProfiles|Edit scanner profile"
msgstr ""
msgid "DastProfiles|Edit site profile"
@@ -8007,6 +8306,9 @@ msgstr ""
msgid "DastProfiles|No profiles created yet"
msgstr ""
+msgid "DastProfiles|Passive"
+msgstr ""
+
msgid "DastProfiles|Please enter a valid URL format, ex: http://www.example.com/home"
msgstr ""
@@ -8022,6 +8324,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan mode"
+msgstr ""
+
msgid "DastProfiles|Scanner Profile"
msgstr ""
@@ -8061,10 +8366,10 @@ msgstr ""
msgid "DastProfiles|Text file validation"
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
+msgid "DastProfiles|The maximum number of minutes allowed for the spider to traverse the site."
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the spider to traverse the site."
+msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
msgstr ""
msgid "DastProfiles|Validate"
@@ -8097,6 +8402,9 @@ msgstr ""
msgid "Date picker"
msgstr ""
+msgid "Date range"
+msgstr ""
+
msgid "Date range cannot exceed %{maxDateRange} days."
msgstr ""
@@ -8121,6 +8429,9 @@ msgstr ""
msgid "Days to merge"
msgstr ""
+msgid "Dear Administrator,"
+msgstr ""
+
msgid "Debug"
msgstr ""
@@ -8232,12 +8543,18 @@ msgstr ""
msgid "Delete"
msgstr ""
+msgid "Delete %{name}"
+msgstr ""
+
msgid "Delete Comment"
msgstr ""
msgid "Delete Snippet"
msgstr ""
+msgid "Delete Value Stream"
+msgstr ""
+
msgid "Delete account"
msgstr ""
@@ -8259,9 +8576,6 @@ msgstr ""
msgid "Delete label: %{label_name} ?"
msgstr ""
-msgid "Delete license"
-msgstr ""
-
msgid "Delete list"
msgstr ""
@@ -8337,15 +8651,6 @@ msgstr ""
msgid "Deleting a project places it into a read-only state until %{date}, at which point the project will be permanently deleted. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "Deleting the license failed."
-msgstr ""
-
-msgid "Deleting the license failed. The license was not found."
-msgstr ""
-
-msgid "Deleting the license failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "Deleting the project will delete its repository and all related resources including issues, merge requests etc."
msgstr ""
@@ -8853,7 +9158,10 @@ msgstr ""
msgid "DesignManagement|The maximum number of designs allowed to be uploaded is %{upload_limit}. Please try again."
msgstr ""
-msgid "DesignManagement|To upload designs, you'll need to enable LFS. %{requirements_link_start}More information%{requirements_link_end}"
+msgid "DesignManagement|There was an error moving your designs. Please upload your designs below."
+msgstr ""
+
+msgid "DesignManagement|To upload designs, you'll need to enable LFS and have admin enable hashed storage. %{requirements_link_start}More information%{requirements_link_end}"
msgstr ""
msgid "DesignManagement|Unresolve thread"
@@ -8865,6 +9173,9 @@ msgstr ""
msgid "DesignManagement|Upload skipped."
msgstr ""
+msgid "DesignManagement|Your designs are being copied and are on their way… Please refresh to update."
+msgstr ""
+
msgid "DesignManagement|and %{moreCount} more."
msgstr ""
@@ -8922,6 +9233,9 @@ msgstr ""
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
+msgid "Direct member"
+msgstr ""
+
msgid "Direction"
msgstr ""
@@ -8970,9 +9284,6 @@ msgstr ""
msgid "Discard draft"
msgstr ""
-msgid "Discard review"
-msgstr ""
-
msgid "DiscordService|Discord Notifications"
msgstr ""
@@ -9043,10 +9354,10 @@ msgstr ""
msgid "Dismiss Merge Request promotion"
msgstr ""
-msgid "Dismiss Selected"
+msgid "Dismiss Value Stream Analytics introduction box"
msgstr ""
-msgid "Dismiss Value Stream Analytics introduction box"
+msgid "Dismiss selected"
msgstr ""
msgid "Dismiss trial promotion"
@@ -9097,9 +9408,6 @@ msgstr ""
msgid "Documents reindexed: %{processed_documents} (%{percentage}%%)"
msgstr ""
-msgid "Doing"
-msgstr ""
-
msgid "Domain"
msgstr ""
@@ -9295,9 +9603,6 @@ msgstr ""
msgid "Edit environment"
msgstr ""
-msgid "Edit file"
-msgstr ""
-
msgid "Edit files in the editor and commit changes here"
msgstr ""
@@ -9310,6 +9615,12 @@ msgstr ""
msgid "Edit identity for %{user_name}"
msgstr ""
+msgid "Edit in Web IDE"
+msgstr ""
+
+msgid "Edit in single-file editor"
+msgstr ""
+
msgid "Edit issues"
msgstr ""
@@ -9337,10 +9648,10 @@ msgstr ""
msgid "Editing"
msgstr ""
-msgid "Elasticsearch"
+msgid "Elasticsearch AWS IAM credentials"
msgstr ""
-msgid "Elasticsearch AWS IAM credentials"
+msgid "Elasticsearch HTTP client timeout value in seconds."
msgstr ""
msgid "Elasticsearch indexing restrictions"
@@ -9349,9 +9660,6 @@ msgstr ""
msgid "Elasticsearch indexing started"
msgstr ""
-msgid "Elasticsearch integration. Elasticsearch AWS IAM."
-msgstr ""
-
msgid "Elasticsearch reindexing is already in progress"
msgstr ""
@@ -9379,9 +9687,6 @@ msgstr ""
msgid "Email Notification"
msgstr ""
-msgid "Email address"
-msgstr ""
-
msgid "Email could not be sent"
msgstr ""
@@ -9445,6 +9750,9 @@ msgstr ""
msgid "Emails sent from Service Desk will have this name"
msgstr ""
+msgid "Emails sent to %{email} will still be supported"
+msgstr ""
+
msgid "Emails separated by comma"
msgstr ""
@@ -9478,9 +9786,18 @@ msgstr ""
msgid "Enable"
msgstr ""
+msgid "Enable %{link_start}Gitpod%{link_end} integration to launch a development environment in your browser directly from GitLab."
+msgstr ""
+
msgid "Enable Auto DevOps"
msgstr ""
+msgid "Enable Gitpod"
+msgstr ""
+
+msgid "Enable Gitpod?"
+msgstr ""
+
msgid "Enable HTML emails"
msgstr ""
@@ -9610,9 +9927,6 @@ msgstr ""
msgid "Encountered an error while rendering: %{err}"
msgstr ""
-msgid "End date"
-msgstr ""
-
msgid "Ends at (UTC)"
msgstr ""
@@ -9772,7 +10086,7 @@ msgstr ""
msgid "EnvironmentsDashboard|The environments dashboard provides a summary of each project's environments' status, including pipeline and alert statuses."
msgstr ""
-msgid "EnvironmentsDashboard|This dashboard displays a maximum of 7 projects and 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
+msgid "EnvironmentsDashboard|This dashboard displays 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
msgstr ""
msgid "Environments|An error occurred while canceling the auto stop, please try again"
@@ -10093,6 +10407,9 @@ msgstr ""
msgid "Error deleting project. Check logs for error details."
msgstr ""
+msgid "Error fetching burnup chart data"
+msgstr ""
+
msgid "Error fetching diverging counts for branches. Please try again."
msgstr ""
@@ -10171,6 +10488,9 @@ msgstr ""
msgid "Error occurred when saving assignees"
msgstr ""
+msgid "Error occurred when saving reviewers"
+msgstr ""
+
msgid "Error occurred when toggling the notification subscription"
msgstr ""
@@ -10423,10 +10743,13 @@ msgstr ""
msgid "Expand all"
msgstr ""
-msgid "Expand approvers"
+msgid "Expand all files"
msgstr ""
-msgid "Expand dropdown"
+msgid "Expand all threads"
+msgstr ""
+
+msgid "Expand approvers"
msgstr ""
msgid "Expand milestones"
@@ -10597,6 +10920,9 @@ msgstr ""
msgid "Failed to create Merge Request. Please try again."
msgstr ""
+msgid "Failed to create To-Do for the design."
+msgstr ""
+
msgid "Failed to create a branch for this issue. Please try again."
msgstr ""
@@ -10636,6 +10962,12 @@ msgstr ""
msgid "Failed to load authors. Please try again."
msgstr ""
+msgid "Failed to load branches. Please try again."
+msgstr ""
+
+msgid "Failed to load deploy keys."
+msgstr ""
+
msgid "Failed to load emoji list."
msgstr ""
@@ -10651,6 +10983,9 @@ msgstr ""
msgid "Failed to load groups & users."
msgstr ""
+msgid "Failed to load groups, users and deploy keys."
+msgstr ""
+
msgid "Failed to load labels. Please try again."
msgstr ""
@@ -10660,6 +10995,12 @@ msgstr ""
msgid "Failed to load related branches"
msgstr ""
+msgid "Failed to load sidebar confidential toggle"
+msgstr ""
+
+msgid "Failed to load sidebar lock status"
+msgstr ""
+
msgid "Failed to load stacktrace."
msgstr ""
@@ -10687,6 +11028,9 @@ msgstr ""
msgid "Failed to publish issue on status page."
msgstr ""
+msgid "Failed to remove To-Do for the design."
+msgstr ""
+
msgid "Failed to remove a Zoom meeting"
msgstr ""
@@ -10729,6 +11073,9 @@ msgstr ""
msgid "Failed to signing using smartcard authentication"
msgstr ""
+msgid "Failed to toggle To-Do for the design."
+msgstr ""
+
msgid "Failed to update branch!"
msgstr ""
@@ -10844,7 +11191,7 @@ msgstr ""
msgid "FeatureFlags|Edit User List"
msgstr ""
-msgid "FeatureFlags|Enable features for specific users and specific environments by defining feature flag strategies."
+msgid "FeatureFlags|Enable features for specific users and environments by configuring feature flag strategies."
msgstr ""
msgid "FeatureFlags|Environment Spec"
@@ -10904,7 +11251,7 @@ msgstr ""
msgid "FeatureFlags|Include additional user IDs"
msgstr ""
-msgid "FeatureFlags|Install a %{docs_link_anchored_start}compatible client library%{docs_link_anchored_end} and specify the API URL, application name, and instance ID during the configuration setup. %{docs_link_start}More Information%{docs_link_end}"
+msgid "FeatureFlags|Install a %{docsLinkAnchoredStart}compatible client library%{docsLinkAnchoredEnd} and specify the API URL, application name, and instance ID during the configuration setup. %{docsLinkStart}More Information%{docsLinkEnd}"
msgstr ""
msgid "FeatureFlags|Instance ID"
@@ -10916,6 +11263,9 @@ msgstr ""
msgid "FeatureFlags|Loading feature flags"
msgstr ""
+msgid "FeatureFlags|Loading user lists"
+msgstr ""
+
msgid "FeatureFlags|More information"
msgstr ""
@@ -10934,7 +11284,7 @@ msgstr ""
msgid "FeatureFlags|New feature flag"
msgstr ""
-msgid "FeatureFlags|New list"
+msgid "FeatureFlags|New user list"
msgstr ""
msgid "FeatureFlags|Percent of users"
@@ -10973,6 +11323,9 @@ msgstr ""
msgid "FeatureFlags|There was an error fetching the feature flags."
msgstr ""
+msgid "FeatureFlags|There was an error fetching the user lists."
+msgstr ""
+
msgid "FeatureFlags|There was an error retrieving user lists"
msgstr ""
@@ -10988,6 +11341,9 @@ msgstr ""
msgid "FeatureFlags|User List"
msgstr ""
+msgid "FeatureFlags|User Lists"
+msgstr ""
+
msgid "FeatureFlag|List"
msgstr ""
@@ -11015,15 +11371,6 @@ msgstr ""
msgid "Fetching incoming email"
msgstr ""
-msgid "Fetching licenses failed."
-msgstr ""
-
-msgid "Fetching licenses failed. The request endpoint was not found."
-msgstr ""
-
-msgid "Fetching licenses failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "File"
msgstr ""
@@ -11126,12 +11473,21 @@ msgstr ""
msgid "Filter by status"
msgstr ""
+msgid "Filter by test cases that are currently archived."
+msgstr ""
+
+msgid "Filter by test cases that are currently opened."
+msgstr ""
+
msgid "Filter by two-factor authentication"
msgstr ""
msgid "Filter by user"
msgstr ""
+msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
+msgstr ""
+
msgid "Filter pipelines"
msgstr ""
@@ -11147,7 +11503,7 @@ msgstr ""
msgid "Filter results..."
msgstr ""
-msgid "Filter your projects by name"
+msgid "Filter your repositories by name"
msgstr ""
msgid "Filter..."
@@ -11156,7 +11512,7 @@ msgstr ""
msgid "Find File"
msgstr ""
-msgid "Find bugs in your code with coverage-guided fuzzing"
+msgid "Find bugs in your code with coverage-guided fuzzing."
msgstr ""
msgid "Find by path"
@@ -11183,9 +11539,6 @@ msgstr ""
msgid "Finish editing this message first!"
msgstr ""
-msgid "Finish review"
-msgstr ""
-
msgid "Finish setting up your dedicated account for %{group_name}."
msgstr ""
@@ -11255,6 +11608,9 @@ msgstr ""
msgid "Footer message"
msgstr ""
+msgid "For a faster browsing experience, some files are collapsed by default."
+msgstr ""
+
msgid "For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
@@ -11264,6 +11620,9 @@ msgstr ""
msgid "For more info, read the documentation."
msgstr ""
+msgid "For more information on how the number of active users is calculated, see the %{self_managed_subscriptions_doc_link} documentation."
+msgstr ""
+
msgid "For more information, go to the "
msgstr ""
@@ -11402,6 +11761,9 @@ msgstr ""
msgid "Generate new token"
msgstr ""
+msgid "Generic package file size in bytes"
+msgstr ""
+
msgid "Geo"
msgstr ""
@@ -11663,6 +12025,9 @@ msgstr ""
msgid "Geo|Please refer to Geo Troubleshooting."
msgstr ""
+msgid "Geo|Primary node"
+msgstr ""
+
msgid "Geo|Project"
msgstr ""
@@ -11705,6 +12070,9 @@ msgstr ""
msgid "Geo|Review replication status, and resynchronize and reverify items with the primary node."
msgstr ""
+msgid "Geo|Secondary node"
+msgstr ""
+
msgid "Geo|Status"
msgstr ""
@@ -11744,6 +12112,9 @@ msgstr ""
msgid "Geo|URL must be a valid url (ex: https://gitlab.com)"
msgstr ""
+msgid "Geo|Undefined"
+msgstr ""
+
msgid "Geo|Unknown state"
msgstr ""
@@ -11819,10 +12190,16 @@ msgstr ""
msgid "GitHub import"
msgstr ""
+msgid "GitLab"
+msgstr ""
+
msgid "GitLab / Unsubscribe"
msgstr ""
-msgid "GitLab Enterprise Edition %{plan}"
+msgid "GitLab API"
+msgstr ""
+
+msgid "GitLab Billing Team."
msgstr ""
msgid "GitLab Group Runners can execute code for all the projects in this group."
@@ -11834,12 +12211,18 @@ msgstr ""
msgid "GitLab Issue"
msgstr ""
+msgid "GitLab Pages"
+msgstr ""
+
msgid "GitLab Service Desk is a simple way to allow people to create issues in your GitLab instance without needing their own user account. It provides a unique email address for end users to create issues in a project, and replies can be sent either through the GitLab interface or by email. End users will only see the thread through email."
msgstr ""
msgid "GitLab Shared Runners execute code of different projects on the same Runner unless you configure GitLab Runner Autoscale with MaxBuilds 1 (which it is on GitLab.com)."
msgstr ""
+msgid "GitLab Shell"
+msgstr ""
+
msgid "GitLab Support Bot"
msgstr ""
@@ -11849,7 +12232,7 @@ msgstr ""
msgid "GitLab User"
msgstr ""
-msgid "GitLab allows you to continue using your license even if you exceed the number of seats you purchased. You will be required to pay for these seats when you renew your license."
+msgid "GitLab Workhorse"
msgstr ""
msgid "GitLab commit"
@@ -12017,6 +12400,21 @@ msgstr ""
msgid "Gitlab Pages"
msgstr ""
+msgid "Gitpod"
+msgstr ""
+
+msgid "Gitpod|Add the URL to your Gitpod instance configured to read your GitLab projects."
+msgstr ""
+
+msgid "Gitpod|Enable Gitpod integration"
+msgstr ""
+
+msgid "Gitpod|Gitpod URL"
+msgstr ""
+
+msgid "Gitpod|e.g. https://gitpod.example.com"
+msgstr ""
+
msgid "Given access %{time_ago}"
msgstr ""
@@ -12524,9 +12922,6 @@ msgstr ""
msgid "GroupSAML|Valid SAML Response"
msgstr ""
-msgid "GroupSAML|With group managed accounts enabled, all the users without a group managed account will be excluded from the group."
-msgstr ""
-
msgid "GroupSAML|With prohibit outer forks flag enabled group members will be able to fork project only inside your group."
msgstr ""
@@ -12740,10 +13135,10 @@ msgstr ""
msgid "GroupsNew|Create group"
msgstr ""
-msgid "GroupsNew|GitLab group export"
+msgid "GroupsNew|Import"
msgstr ""
-msgid "GroupsNew|Import"
+msgid "GroupsNew|Import a GitLab group export file"
msgstr ""
msgid "GroupsNew|Import group"
@@ -12888,6 +13283,9 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "Hide comments on this file"
+msgstr ""
+
msgid "Hide details"
msgstr ""
@@ -12934,6 +13332,15 @@ msgstr ""
msgid "Highest role:"
msgstr ""
+msgid "HighlightBar|Alert events:"
+msgstr ""
+
+msgid "HighlightBar|Alert start time:"
+msgstr ""
+
+msgid "HighlightBar|Original alert:"
+msgstr ""
+
msgid "History"
msgstr ""
@@ -13111,6 +13518,9 @@ msgstr ""
msgid "If enabled, access to projects will be validated on an external service using their classification label."
msgstr ""
+msgid "If the number of active users exceeds the user limit, you will be charged for the number of %{users_over_license_link} at your next license reconciliation."
+msgstr ""
+
msgid "If there is no previous license or if the previous license has expired, some GitLab functionality will be blocked until a new, valid license is uploaded."
msgstr ""
@@ -13150,9 +13560,6 @@ msgstr ""
msgid "If your HTTP repository is not publicly accessible, add your credentials."
msgstr ""
-msgid "Iglu registry URL (optional)"
-msgstr ""
-
msgid "Ignore"
msgstr ""
@@ -13189,6 +13596,20 @@ msgstr ""
msgid "Import"
msgstr ""
+msgid "Import %d compatible repository"
+msgid_plural "Import %d compatible repositories"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
+msgid "Import %d repository"
+msgid_plural "Import %d repositories"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "Import CSV"
msgstr ""
@@ -13198,15 +13619,9 @@ msgstr ""
msgid "Import all compatible projects"
msgstr ""
-msgid "Import all compatible repositories"
-msgstr ""
-
msgid "Import all projects"
msgstr ""
-msgid "Import all repositories"
-msgstr ""
-
msgid "Import an exported GitLab project"
msgstr ""
@@ -13294,6 +13709,9 @@ msgstr ""
msgid "ImportProjects|Error importing repository %{project_safe_import_url} into %{project_full_path} - %{message}"
msgstr ""
+msgid "ImportProjects|Import repositories"
+msgstr ""
+
msgid "ImportProjects|Importing the project failed"
msgstr ""
@@ -13306,7 +13724,7 @@ msgstr ""
msgid "ImportProjects|Requesting your %{provider} repositories failed"
msgstr ""
-msgid "ImportProjects|Select the projects you want to import"
+msgid "ImportProjects|Select the repositories you want to import"
msgstr ""
msgid "ImportProjects|The remote data could not be imported."
@@ -13342,9 +13760,6 @@ msgstr ""
msgid "In order to enable Service Desk for your instance, you must first set up incoming email."
msgstr ""
-msgid "In order to gather accurate feature usage data, it can take 1 to 2 weeks to see your index."
-msgstr ""
-
msgid "In order to personalize your experience with GitLab%{br_tag}we would like to know a bit more about you."
msgstr ""
@@ -13375,18 +13790,30 @@ msgstr ""
msgid "IncidentManagement|Create incident"
msgstr ""
+msgid "IncidentManagement|Critical - S1"
+msgstr ""
+
msgid "IncidentManagement|Date created"
msgstr ""
msgid "IncidentManagement|Display your incidents in a dedicated view"
msgstr ""
+msgid "IncidentManagement|High - S2"
+msgstr ""
+
msgid "IncidentManagement|Incident"
msgstr ""
msgid "IncidentManagement|Incidents"
msgstr ""
+msgid "IncidentManagement|Low - S4"
+msgstr ""
+
+msgid "IncidentManagement|Medium - S3"
+msgstr ""
+
msgid "IncidentManagement|No incidents to display."
msgstr ""
@@ -13399,6 +13826,9 @@ msgstr ""
msgid "IncidentManagement|Published to status page"
msgstr ""
+msgid "IncidentManagement|Severity"
+msgstr ""
+
msgid "IncidentManagement|There are no closed incidents"
msgstr ""
@@ -13408,6 +13838,9 @@ msgstr ""
msgid "IncidentManagement|Unassigned"
msgstr ""
+msgid "IncidentManagement|Unknown"
+msgstr ""
+
msgid "IncidentManagement|Unpublished"
msgstr ""
@@ -13429,6 +13862,15 @@ msgstr ""
msgid "Incidents"
msgstr ""
+msgid "Incident|Alert details"
+msgstr ""
+
+msgid "Incident|Summary"
+msgstr ""
+
+msgid "Incident|There was an issue loading alert data. Please try again."
+msgstr ""
+
msgid "Include a Terms of Service agreement and Privacy Policy that all users must accept."
msgstr ""
@@ -13489,6 +13931,9 @@ msgstr ""
msgid "Information about additional Pages templates and how to install them can be found in our %{pages_getting_started_guide}."
msgstr ""
+msgid "Inherited"
+msgstr ""
+
msgid "Inherited:"
msgstr ""
@@ -13571,7 +14016,22 @@ msgstr ""
msgid "Instance administrators group already exists"
msgstr ""
-msgid "Instance license"
+msgid "InstanceStatistics|Groups"
+msgstr ""
+
+msgid "InstanceStatistics|Issues"
+msgstr ""
+
+msgid "InstanceStatistics|Merge Requests"
+msgstr ""
+
+msgid "InstanceStatistics|Pipelines"
+msgstr ""
+
+msgid "InstanceStatistics|Projects"
+msgstr ""
+
+msgid "InstanceStatistics|Users"
msgstr ""
msgid "Integration"
@@ -13583,6 +14043,12 @@ msgstr ""
msgid "Integrations"
msgstr ""
+msgid "Integrations|%{integration} settings saved and active."
+msgstr ""
+
+msgid "Integrations|%{integration} settings saved, but not active."
+msgstr ""
+
msgid "Integrations|All details"
msgstr ""
@@ -13592,6 +14058,12 @@ msgstr ""
msgid "Integrations|Comment settings:"
msgstr ""
+msgid "Integrations|Connection failed. Please check your settings."
+msgstr ""
+
+msgid "Integrations|Connection successful."
+msgstr ""
+
msgid "Integrations|Default settings are inherited from the group level."
msgstr ""
@@ -13607,6 +14079,15 @@ msgstr ""
msgid "Integrations|Includes commit title and branch"
msgstr ""
+msgid "Integrations|Projects using custom settings will not be impacted unless the project owner chooses to use instance-level defaults."
+msgstr ""
+
+msgid "Integrations|Save settings?"
+msgstr ""
+
+msgid "Integrations|Saving will update the default settings for all projects that are not using custom settings."
+msgstr ""
+
msgid "Integrations|Standard"
msgstr ""
@@ -13739,6 +14220,9 @@ msgstr ""
msgid "Invitation"
msgstr ""
+msgid "Invitation declined"
+msgstr ""
+
msgid "Invite"
msgstr ""
@@ -13790,6 +14274,42 @@ 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|%{linkStart}Read more%{linkEnd} about role permissions"
+msgstr ""
+
+msgid "InviteMembersModal|Access expiration date (optional)"
+msgstr ""
+
+msgid "InviteMembersModal|Cancel"
+msgstr ""
+
+msgid "InviteMembersModal|Choose a role permission"
+msgstr ""
+
+msgid "InviteMembersModal|GitLab member or Email address"
+msgstr ""
+
+msgid "InviteMembersModal|Invite"
+msgstr ""
+
+msgid "InviteMembersModal|Invite team members"
+msgstr ""
+
+msgid "InviteMembersModal|Search for members to invite"
+msgstr ""
+
+msgid "InviteMembersModal|User not invited. Feature coming soon!"
+msgstr ""
+
+msgid "InviteMembersModal|Users were succesfully added"
+msgstr ""
+
+msgid "InviteMembersModal|You're inviting members to the %{group_name} group"
+msgstr ""
+
+msgid "InviteMembers|Invite team members"
+msgstr ""
+
msgid "Invited"
msgstr ""
@@ -13844,10 +14364,13 @@ msgstr ""
msgid "Issue cannot be found."
msgstr ""
+msgid "Issue created from vulnerability %{vulnerability_link}"
+msgstr ""
+
msgid "Issue events"
msgstr ""
-msgid "Issue first depoloyed to production"
+msgid "Issue first deployed to production"
msgstr ""
msgid "Issue label"
@@ -13925,6 +14448,9 @@ msgstr ""
msgid "IssueTracker|Custom issue tracker"
msgstr ""
+msgid "IssueTracker|EWM work items tracker"
+msgstr ""
+
msgid "IssueTracker|Redmine issue tracker"
msgstr ""
@@ -13991,6 +14517,9 @@ msgstr ""
msgid "It looks like you have some draft commits in this branch."
msgstr ""
+msgid "It may be several days before you see feature usage data."
+msgstr ""
+
msgid "It must have a header row and at least two columns: the first column is the issue title and the second column is the issue description. The separator is automatically detected."
msgstr ""
@@ -14273,13 +14802,13 @@ msgstr ""
msgid "Join Zoom meeting"
msgstr ""
-msgid "Jul"
+msgid "Joined %{time_ago}"
msgstr ""
-msgid "July"
+msgid "Jul"
msgstr ""
-msgid "Jump to first unresolved thread"
+msgid "July"
msgstr ""
msgid "Jump to next unresolved thread"
@@ -14315,6 +14844,9 @@ msgstr ""
msgid "Keyboard shortcuts"
msgstr ""
+msgid "KeyboardKey|Ctrl+"
+msgstr ""
+
msgid "Keys"
msgstr ""
@@ -14363,6 +14895,9 @@ msgstr ""
msgid "LDAP Synchronization"
msgstr ""
+msgid "LDAP group settings"
+msgstr ""
+
msgid "LDAP settings"
msgstr ""
@@ -14372,6 +14907,9 @@ msgstr ""
msgid "LDAP sync in progress. This could take a few minutes. Refresh the page to see the changes."
msgstr ""
+msgid "LDAP synchronizations"
+msgstr ""
+
msgid "LFS"
msgstr ""
@@ -14454,7 +14992,16 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "Last %{days} days"
+msgid "Last 2 weeks"
+msgstr ""
+
+msgid "Last 30 days"
+msgstr ""
+
+msgid "Last 60 days"
+msgstr ""
+
+msgid "Last 90 days"
msgstr ""
msgid "Last Accessed On"
@@ -14532,6 +15079,9 @@ msgstr ""
msgid "Last used on:"
msgstr ""
+msgid "Last week"
+msgstr ""
+
msgid "LastCommit|authored"
msgstr ""
@@ -14547,6 +15097,9 @@ msgstr ""
msgid "Latest pipeline for the most recent commit on this branch"
msgstr ""
+msgid "Launch a ready-to-code development environment for your project."
+msgstr ""
+
msgid "Lead"
msgstr ""
@@ -14941,6 +15494,9 @@ msgstr ""
msgid "List of all merge commits"
msgstr ""
+msgid "List options"
+msgstr ""
+
msgid "List settings"
msgstr ""
@@ -14953,9 +15509,6 @@ msgstr ""
msgid "List your Bitbucket Server repositories"
msgstr ""
-msgid "Lists"
-msgstr ""
-
msgid "Live preview"
msgstr ""
@@ -15202,6 +15755,12 @@ msgstr ""
msgid "Mark as done"
msgstr ""
+msgid "Mark as draft"
+msgstr ""
+
+msgid "Mark as ready"
+msgstr ""
+
msgid "Mark as resolved"
msgstr ""
@@ -15223,6 +15782,24 @@ msgstr ""
msgid "Markdown is supported"
msgstr ""
+msgid "MarkdownEditor|Add a link (%{modifierKey}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add a link (%{modifier_key}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifierKey}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifier_key}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifierKey}I)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifier_key}I)"
+msgstr ""
+
msgid "Marked For Deletion At - %{deletion_time}"
msgstr ""
@@ -15307,7 +15884,25 @@ msgstr ""
msgid "Max access level"
msgstr ""
-msgid "Max seats used"
+msgid "Max role"
+msgstr ""
+
+msgid "Max size 15 MB"
+msgstr ""
+
+msgid "Maximum Conan package file size in bytes"
+msgstr ""
+
+msgid "Maximum Maven package file size in bytes"
+msgstr ""
+
+msgid "Maximum NPM package file size in bytes"
+msgstr ""
+
+msgid "Maximum NuGet package file size in bytes"
+msgstr ""
+
+msgid "Maximum PyPI package file size in bytes"
msgstr ""
msgid "Maximum Users:"
@@ -15439,6 +16034,18 @@ msgstr ""
msgid "Members with access to %{strong_start}%{group_name}%{strong_end}"
msgstr ""
+msgid "Members|%{time} by %{user}"
+msgstr ""
+
+msgid "Members|Expired"
+msgstr ""
+
+msgid "Members|No expiration set"
+msgstr ""
+
+msgid "Members|in %{time}"
+msgstr ""
+
msgid "Memory Usage"
msgstr ""
@@ -15625,9 +16232,6 @@ msgstr ""
msgid "MergeRequests|Thread will be unresolved"
msgstr ""
-msgid "MergeRequests|Toggle comments for this file"
-msgstr ""
-
msgid "MergeRequests|View file @ %{commitId}"
msgstr ""
@@ -15688,6 +16292,9 @@ msgstr ""
msgid "Merging immediately isn't recommended as it may negatively impact the existing merge train. Read the %{docsLinkStart}documentation%{docsLinkEnd} for more information."
msgstr ""
+msgid "Message"
+msgstr ""
+
msgid "Messages"
msgstr ""
@@ -16077,18 +16684,12 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "Milestone does not support burnup charts"
-msgstr ""
-
msgid "Milestone lists not available with your current license"
msgstr ""
msgid "Milestone lists show all issues from the selected milestone."
msgstr ""
-msgid "Milestone must have a start and due date"
-msgstr ""
-
msgid "MilestoneSidebar|Closed:"
msgstr ""
@@ -16455,6 +17056,9 @@ msgstr ""
msgid "Namespace"
msgstr ""
+msgid "Namespace ID:"
+msgstr ""
+
msgid "Namespace is empty"
msgstr ""
@@ -16539,6 +17143,9 @@ msgstr ""
msgid "NetworkPolicies|Allow all outbound traffic from %{selector} to %{ruleSelector} on %{ports}"
msgstr ""
+msgid "NetworkPolicies|Are you sure you want to delete this policy? This action cannot be undone."
+msgstr ""
+
msgid "NetworkPolicies|Choose whether to enforce this policy."
msgstr ""
@@ -16548,12 +17155,21 @@ msgstr ""
msgid "NetworkPolicies|Define this policy's location, conditions and actions."
msgstr ""
+msgid "NetworkPolicies|Delete policy"
+msgstr ""
+
+msgid "NetworkPolicies|Delete policy: %{policy}"
+msgstr ""
+
msgid "NetworkPolicies|Deny all traffic"
msgstr ""
msgid "NetworkPolicies|Description"
msgstr ""
+msgid "NetworkPolicies|Edit policy"
+msgstr ""
+
msgid "NetworkPolicies|Editor mode"
msgstr ""
@@ -16581,6 +17197,9 @@ msgstr ""
msgid "NetworkPolicies|Name"
msgstr ""
+msgid "NetworkPolicies|Namespace"
+msgstr ""
+
msgid "NetworkPolicies|Network Policy"
msgstr ""
@@ -16632,6 +17251,9 @@ msgstr ""
msgid "NetworkPolicies|Rules"
msgstr ""
+msgid "NetworkPolicies|Save changes"
+msgstr ""
+
msgid "NetworkPolicies|Something went wrong, failed to update policy"
msgstr ""
@@ -16644,6 +17266,9 @@ msgstr ""
msgid "NetworkPolicies|Traffic that does not match any rule will be blocked."
msgstr ""
+msgid "NetworkPolicies|Unable to parse policy"
+msgstr ""
+
msgid "NetworkPolicies|YAML editor"
msgstr ""
@@ -16759,6 +17384,9 @@ msgstr ""
msgid "New Snippet"
msgstr ""
+msgid "New Test Case"
+msgstr ""
+
msgid "New User"
msgstr ""
@@ -16858,6 +17486,9 @@ msgstr ""
msgid "New tag"
msgstr ""
+msgid "New test case"
+msgstr ""
+
msgid "New users set to external"
msgstr ""
@@ -16930,7 +17561,7 @@ msgstr ""
msgid "No changes"
msgstr ""
-msgid "No changes between %{ref_start}%{source_branch}%{ref_end} and %{ref_start}%{target_branch}%{ref_end}"
+msgid "No changes between %{sourceBranch} and %{targetBranch}"
msgstr ""
msgid "No child epics match applied filters"
@@ -16945,6 +17576,9 @@ msgstr ""
msgid "No containers available"
msgstr ""
+msgid "No content to show"
+msgstr ""
+
msgid "No contributions"
msgstr ""
@@ -17020,9 +17654,6 @@ msgstr ""
msgid "No license. All rights reserved"
msgstr ""
-msgid "No licenses found."
-msgstr ""
-
msgid "No matches found"
msgstr ""
@@ -17035,6 +17666,9 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No members found"
+msgstr ""
+
msgid "No merge requests found"
msgstr ""
@@ -17056,6 +17690,9 @@ msgstr ""
msgid "No parent group"
msgstr ""
+msgid "No plan"
+msgstr ""
+
msgid "No pods available"
msgstr ""
@@ -17152,6 +17789,12 @@ msgstr ""
msgid "Not Implemented"
msgstr ""
+msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+msgstr ""
+
+msgid "Not all browsers support WebAuthn. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even from an unsupported browser."
+msgstr ""
+
msgid "Not all data has been processed yet, the accuracy of the chart for the selected timeframe is limited."
msgstr ""
@@ -17248,6 +17891,9 @@ msgstr ""
msgid "Notification settings saved"
msgstr ""
+msgid "NotificationEvent|Change reviewer merge request"
+msgstr ""
+
msgid "NotificationEvent|Close issue"
msgstr ""
@@ -17410,10 +18056,7 @@ msgstr ""
msgid "On track"
msgstr ""
-msgid "OnDemandScans|Attached branch"
-msgstr ""
-
-msgid "OnDemandScans|Attached branch is where the scan job runs."
+msgid "OnDemandScans|Could not fetch scanner profiles. Please refresh the page, or try again later."
msgstr ""
msgid "OnDemandScans|Could not fetch site profiles. Please refresh the page, or try again later."
@@ -17422,6 +18065,9 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
+msgid "OnDemandScans|Create a new scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Create a new site profile"
msgstr ""
@@ -17434,6 +18080,9 @@ msgstr ""
msgid "OnDemandScans|New on-demand DAST scan"
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 ""
@@ -17443,16 +18092,10 @@ msgstr ""
msgid "OnDemandScans|On-demand scans run outside the DevOps cycle and find vulnerabilities in your projects. %{learnMoreLinkStart}Learn more%{learnMoreLinkEnd}"
msgstr ""
-msgid "OnDemandScans|Only a passive scan can be performed on demand."
-msgstr ""
-
-msgid "OnDemandScans|Passive"
-msgstr ""
-
msgid "OnDemandScans|Run scan"
msgstr ""
-msgid "OnDemandScans|Scan mode"
+msgid "OnDemandScans|Scanner profile"
msgstr ""
msgid "OnDemandScans|Scanner settings"
@@ -17464,9 +18107,15 @@ msgstr ""
msgid "OnDemandScans|Select one of the existing profiles"
msgstr ""
+msgid "OnDemandScans|Site profile"
+msgstr ""
+
msgid "OnDemandScans|Site profiles"
msgstr ""
+msgid "OnDemandScans|Use existing scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Use existing site profile"
msgstr ""
@@ -17567,9 +18216,6 @@ msgstr ""
msgid "Open Selection"
msgstr ""
-msgid "Open Web IDE"
-msgstr ""
-
msgid "Open comment type dropdown"
msgstr ""
@@ -17675,6 +18321,9 @@ msgstr ""
msgid "Origin"
msgstr ""
+msgid "Orphaned member"
+msgstr ""
+
msgid "Other Labels"
msgstr ""
@@ -17690,6 +18339,9 @@ msgstr ""
msgid "Other visibility settings have been disabled by the administrator."
msgstr ""
+msgid "Our documentation includes an example DevOps Score report."
+msgstr ""
+
msgid "Out-of-compliance with this project's policies and should be removed"
msgstr ""
@@ -17709,11 +18361,14 @@ msgid "Overridden"
msgstr ""
msgid "Overview"
-msgstr ""
+msgstr "Přehled"
msgid "Overwrite diverged branches"
msgstr ""
+msgid "Owned by %{image_tag}"
+msgstr ""
+
msgid "Owned by anyone"
msgstr ""
@@ -17735,6 +18390,9 @@ msgstr ""
msgid "Package deleted successfully"
msgstr ""
+msgid "Package file size limits"
+msgstr ""
+
msgid "Package recipe already exists"
msgstr ""
@@ -17750,9 +18408,6 @@ msgstr ""
msgid "Package type must be PyPi"
msgstr ""
-msgid "Package was removed"
-msgstr ""
-
msgid "PackageRegistry|%{name} version %{version} was created %{datetime}"
msgstr ""
@@ -17894,12 +18549,18 @@ msgstr ""
msgid "PackageRegistry|NuGet Command"
msgstr ""
+msgid "PackageRegistry|Package Registry"
+msgstr ""
+
msgid "PackageRegistry|Pip Command"
msgstr ""
msgid "PackageRegistry|Pipeline %{link} triggered %{datetime} by %{author}"
msgstr ""
+msgid "PackageRegistry|Publish and share packages for a variety of common package managers. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "PackageRegistry|Published to the %{project} Package Registry %{datetime}"
msgstr ""
@@ -17999,6 +18660,9 @@ msgstr ""
msgid "Page not found"
msgstr ""
+msgid "Page settings"
+msgstr ""
+
msgid "Page was successfully deleted"
msgstr ""
@@ -18140,7 +18804,7 @@ msgstr ""
msgid "Paste issue link"
msgstr ""
-msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Don't use your private SSH key."
+msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Do not paste your private SSH key, as that can compromise your identity."
msgstr ""
msgid "Patch to apply"
@@ -18167,6 +18831,9 @@ msgstr ""
msgid "Pending"
msgstr ""
+msgid "Pending comments"
+msgstr ""
+
msgid "People without permission will never get a notification and won't be able to comment."
msgstr ""
@@ -18365,6 +19032,9 @@ msgstr ""
msgid "Pipelines|Build with confidence"
msgstr ""
+msgid "Pipelines|By revoking a trigger you will break any processes making use of it. Are you sure?"
+msgstr ""
+
msgid "Pipelines|CI Lint"
msgstr ""
@@ -18377,6 +19047,15 @@ msgstr ""
msgid "Pipelines|Continuous Integration can help catch bugs by running your tests automatically, while Continuous Deployment can help you deliver code to your product environment."
msgstr ""
+msgid "Pipelines|Copy trigger token"
+msgstr ""
+
+msgid "Pipelines|Description"
+msgstr ""
+
+msgid "Pipelines|Edit"
+msgstr ""
+
msgid "Pipelines|Get started with Pipelines"
msgstr ""
@@ -18392,15 +19071,27 @@ msgstr ""
msgid "Pipelines|It is recommended the code is reviewed thoroughly before running this pipeline with the parent project's CI resource."
msgstr ""
+msgid "Pipelines|Last Used"
+msgstr ""
+
msgid "Pipelines|Loading Pipelines"
msgstr ""
msgid "Pipelines|More Information"
msgstr ""
+msgid "Pipelines|No triggers have been created yet. Add one using the form above."
+msgstr ""
+
+msgid "Pipelines|Owner"
+msgstr ""
+
msgid "Pipelines|Project cache successfully reset."
msgstr ""
+msgid "Pipelines|Revoke"
+msgstr ""
+
msgid "Pipelines|Run Pipeline"
msgstr ""
@@ -18425,6 +19116,15 @@ msgstr ""
msgid "Pipelines|This project is not currently set up to run pipelines."
msgstr ""
+msgid "Pipelines|Token"
+msgstr ""
+
+msgid "Pipelines|Trigger user has insufficient permissions to project"
+msgstr ""
+
+msgid "Pipelines|invalid"
+msgstr ""
+
msgid "Pipelines|parent"
msgstr ""
@@ -18683,10 +19383,10 @@ msgstr ""
msgid "Please provide attributes to update"
msgstr ""
-msgid "Please refer to %{docs_url}"
+msgid "Please reach out if you have any questions and we'll be happy to assist."
msgstr ""
-msgid "Please retype the email address."
+msgid "Please refer to %{docs_url}"
msgstr ""
msgid "Please select"
@@ -18716,6 +19416,9 @@ msgstr ""
msgid "Please set a new password before proceeding."
msgstr ""
+msgid "Please share your feedback about %{featureName} %{linkStart}in this issue%{linkEnd} to help us improve the experience."
+msgstr ""
+
msgid "Please solve the reCAPTCHA"
msgstr ""
@@ -19019,6 +19722,9 @@ msgstr ""
msgid "Profiles| You are going to change the username %{currentUsernameBold} to %{newUsernameBold}. Profile and projects will be redirected to the %{newUsername} namespace but this redirect will expire once the %{currentUsername} namespace is registered by another user or group. Please update your Git repository remotes as soon as possible."
msgstr ""
+msgid "Profiles|%{provider} Active"
+msgstr ""
+
msgid "Profiles|@username"
msgstr ""
@@ -19070,7 +19776,7 @@ msgstr ""
msgid "Profiles|Commit email"
msgstr ""
-msgid "Profiles|Connect"
+msgid "Profiles|Connect %{provider}"
msgstr ""
msgid "Profiles|Connected Accounts"
@@ -19094,6 +19800,9 @@ msgstr ""
msgid "Profiles|Disconnect"
msgstr ""
+msgid "Profiles|Disconnect %{provider}"
+msgstr ""
+
msgid "Profiles|Do not show on profile"
msgstr ""
@@ -19118,7 +19827,7 @@ msgstr ""
msgid "Profiles|Full name"
msgstr ""
-msgid "Profiles|Give your individual key a title. This will be publically visible."
+msgid "Profiles|Give your individual key a title."
msgstr ""
msgid "Profiles|Include private contributions on my profile"
@@ -19208,7 +19917,7 @@ msgstr ""
msgid "Profiles|The maximum file size allowed is 200KB."
msgstr ""
-msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it?"
+msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it? It will be publicly visible."
msgstr ""
msgid "Profiles|This email will be displayed on your public profile"
@@ -19283,6 +19992,9 @@ msgstr ""
msgid "Profiles|You don't have access to delete this user."
msgstr ""
+msgid "Profiles|You must transfer ownership or delete groups you are an owner of before you can delete your account"
+msgstr ""
+
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
@@ -19871,6 +20583,9 @@ msgstr ""
msgid "ProjectTemplates|GitLab Cluster Management"
msgstr ""
+msgid "ProjectTemplates|Gitpod/Spring Petclinic"
+msgstr ""
+
msgid "ProjectTemplates|Go Micro"
msgstr ""
@@ -20480,6 +21195,9 @@ msgstr ""
msgid "Publish to status page"
msgstr ""
+msgid "Published"
+msgstr ""
+
msgid "Published on status page"
msgstr ""
@@ -20597,9 +21315,15 @@ msgstr ""
msgid "Quick range"
msgstr ""
+msgid "Quickly and easily edit multiple files in your project."
+msgstr ""
+
msgid "README"
msgstr ""
+msgid "Rails"
+msgstr ""
+
msgid "Rake Tasks Help"
msgstr ""
@@ -20721,10 +21445,13 @@ msgstr ""
msgid "Register Two-Factor Authenticator"
msgstr ""
-msgid "Register U2F device"
+msgid "Register Universal Two-Factor (U2F) Device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register WebAuthn Device"
+msgstr ""
+
+msgid "Register device"
msgstr ""
msgid "Register for GitLab"
@@ -20736,9 +21463,6 @@ msgstr ""
msgid "Register with two-factor app"
msgstr ""
-msgid "Registration"
-msgstr ""
-
msgid "Registration|Checkout"
msgstr ""
@@ -20857,9 +21581,6 @@ msgstr ""
msgid "Release|Something went wrong while saving the release details"
msgstr ""
-msgid "Remediated: needs review"
-msgstr ""
-
msgid "Remediations"
msgstr ""
@@ -20965,6 +21686,9 @@ msgstr ""
msgid "Remove priority"
msgstr ""
+msgid "Remove report"
+msgstr ""
+
msgid "Remove secondary node"
msgstr ""
@@ -20977,6 +21701,12 @@ msgstr ""
msgid "Remove time estimate"
msgstr ""
+msgid "Remove user & report"
+msgstr ""
+
+msgid "Remove user from group"
+msgstr ""
+
msgid "Removed"
msgstr ""
@@ -21058,9 +21788,6 @@ msgstr ""
msgid "Removes time estimate."
msgstr ""
-msgid "Removing license…"
-msgstr ""
-
msgid "Removing this group also removes all child projects, including archived projects, and their resources."
msgstr ""
@@ -21145,6 +21872,9 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
+msgid "Reported by %{reporter}"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -21233,6 +21963,27 @@ msgstr ""
msgid "Repositories"
msgstr ""
+msgid "Repositories Analytics"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download Historic Test Coverage Data"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download historic test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Historic Test Coverage Data is available in raw format (.csv) for further analysis."
+msgstr ""
+
+msgid "RepositoriesAnalytics|Test Code Coverage"
+msgstr ""
+
+msgid "RepositoriesAnalytics|There was an error fetching the projects."
+msgstr ""
+
msgid "Repository"
msgstr ""
@@ -21311,9 +22062,15 @@ msgstr ""
msgid "Request parameter %{param} is missing."
msgstr ""
+msgid "Request review from"
+msgstr ""
+
msgid "Request to link SAML account must be authorized"
msgstr ""
+msgid "Requested"
+msgstr ""
+
msgid "Requested %{time_ago}"
msgstr ""
@@ -21332,6 +22089,9 @@ msgstr ""
msgid "Requests to these domain(s)/address(es) on the local network will be allowed when local requests from hooks and services are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 or 127.0.0.0/28 are supported. Domain wildcards are not supported currently. Use comma, semicolon, or newline to separate multiple entries. The allowlist can hold a maximum of 1000 entries. Domains should use IDNA encoding. Ex: example.com, 192.168.1.1, 127.0.0.0/28, xn--itlab-j1a.com."
msgstr ""
+msgid "Require admin approval for new sign-ups"
+msgstr ""
+
msgid "Require all users in this group to setup Two-factor authentication"
msgstr ""
@@ -21463,9 +22223,6 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
-msgid "Resolved by %{resolvedByName}"
-msgstr ""
-
msgid "Resolves IP addresses once and uses them to submit requests"
msgstr ""
@@ -21587,6 +22344,16 @@ msgstr ""
msgid "ReviewApp|Enable Review App"
msgstr ""
+msgid "Reviewer"
+msgid_plural "%d Reviewers"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
+msgid "Reviewer(s)"
+msgstr ""
+
msgid "Reviewing"
msgstr ""
@@ -21626,6 +22393,9 @@ msgstr ""
msgid "Rook"
msgstr ""
+msgid "Ruby"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -21704,6 +22474,63 @@ msgstr ""
msgid "Runners page."
msgstr ""
+msgid "Runners|Active"
+msgstr ""
+
+msgid "Runners|Architecture"
+msgstr ""
+
+msgid "Runners|Can run untagged jobs"
+msgstr ""
+
+msgid "Runners|Description"
+msgstr ""
+
+msgid "Runners|Group"
+msgstr ""
+
+msgid "Runners|IP Address"
+msgstr ""
+
+msgid "Runners|Last contact"
+msgstr ""
+
+msgid "Runners|Locked to this project"
+msgstr ""
+
+msgid "Runners|Maximum job timeout"
+msgstr ""
+
+msgid "Runners|Name"
+msgstr ""
+
+msgid "Runners|Platform"
+msgstr ""
+
+msgid "Runners|Property Name"
+msgstr ""
+
+msgid "Runners|Protected"
+msgstr ""
+
+msgid "Runners|Revision"
+msgstr ""
+
+msgid "Runners|Shared"
+msgstr ""
+
+msgid "Runners|Specific"
+msgstr ""
+
+msgid "Runners|Tags"
+msgstr ""
+
+msgid "Runners|Value"
+msgstr ""
+
+msgid "Runners|Version"
+msgstr ""
+
msgid "Runners|You have used %{quotaUsed} out of %{quotaLimit} of your shared Runners pipeline minutes."
msgstr ""
@@ -21716,6 +22543,9 @@ msgstr ""
msgid "Runs a number of housekeeping tasks within the current repository, such as compressing file revisions and removing unreachable objects."
msgstr ""
+msgid "SAML"
+msgstr ""
+
msgid "SAML SSO"
msgstr ""
@@ -21767,6 +22597,9 @@ msgstr ""
msgid "Save"
msgstr ""
+msgid "Save %{name} size limits"
+msgstr ""
+
msgid "Save Changes"
msgstr ""
@@ -21797,9 +22630,6 @@ msgstr ""
msgid "Save space and find tags in the Container Registry more easily. Enable the cleanup policy to remove stale tags and keep only the ones you need."
msgstr ""
-msgid "Save template"
-msgstr ""
-
msgid "Save variables"
msgstr ""
@@ -21842,9 +22672,6 @@ msgstr ""
msgid "Scope"
msgstr ""
-msgid "Scope not supported with disabled 'users_search' feature!"
-msgstr ""
-
msgid "Scoped issue boards"
msgstr ""
@@ -21971,9 +22798,6 @@ msgstr ""
msgid "Search requirements"
msgstr ""
-msgid "Search results…"
-msgstr ""
-
msgid "Search users"
msgstr ""
@@ -22052,6 +22876,13 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "SearchResults|epic"
+msgid_plural "SearchResults|epics"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "SearchResults|issue"
msgid_plural "SearchResults|issues"
msgstr[0] ""
@@ -22110,10 +22941,10 @@ msgstr ""
msgid "Seat Link is disabled, and cannot be configured through this form."
msgstr ""
-msgid "Seats currently in use"
+msgid "Seats usage data as of %{last_enqueue_time}"
msgstr ""
-msgid "Seats in license"
+msgid "Seats usage data is updated every day at 12:00pm UTC"
msgstr ""
msgid "Secondary"
@@ -22167,6 +22998,9 @@ msgstr ""
msgid "SecurityConfiguration|Available for on-demand DAST"
msgstr ""
+msgid "SecurityConfiguration|By default, all analyzers are applied in order to cover all languages across your project, and only run if the language is detected in the Merge Request."
+msgstr ""
+
msgid "SecurityConfiguration|Configure"
msgstr ""
@@ -22197,16 +23031,19 @@ msgstr ""
msgid "SecurityConfiguration|Manage"
msgstr ""
+msgid "SecurityConfiguration|More information"
+msgstr ""
+
msgid "SecurityConfiguration|Not enabled"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|Security Control"
+msgid "SecurityConfiguration|SAST Configuration"
msgstr ""
-msgid "SecurityConfiguration|See documentation"
+msgid "SecurityConfiguration|Security Control"
msgstr ""
msgid "SecurityConfiguration|Status"
@@ -22218,6 +23055,9 @@ msgstr ""
msgid "SecurityConfiguration|Using custom settings. You won't receive automatic updates on this variable. %{anchorStart}Restore to default%{anchorEnd}"
msgstr ""
+msgid "SecurityConfiguration|View history"
+msgstr ""
+
msgid "SecurityConfiguration|You can quickly enable all security scanning tools by enabling %{linkStart}Auto DevOps%{linkEnd}."
msgstr ""
@@ -22296,9 +23136,6 @@ msgstr ""
msgid "SecurityReports|Learn more about setting up your dashboard"
msgstr ""
-msgid "SecurityReports|Load more vulnerabilities"
-msgstr ""
-
msgid "SecurityReports|Monitor vulnerabilities in your code"
msgstr ""
@@ -22578,7 +23415,7 @@ msgstr ""
msgid "Select status"
msgstr ""
-msgid "Select strategy activation method"
+msgid "Select strategy activation method."
msgstr ""
msgid "Select subscription"
@@ -22593,7 +23430,7 @@ msgstr ""
msgid "Select the custom project template source group."
msgstr ""
-msgid "Select timeframe"
+msgid "Select the environment scope for this feature flag."
msgstr ""
msgid "Select timezone"
@@ -22842,6 +23679,9 @@ msgstr ""
msgid "Set iteration"
msgstr ""
+msgid "Set limit to 0 to allow any file size."
+msgstr ""
+
msgid "Set max session time for web terminal."
msgstr ""
@@ -22920,10 +23760,13 @@ msgstr ""
msgid "Set up a %{type} Runner manually"
msgstr ""
+msgid "Set up a hardware device as a second factor to sign in."
+msgstr ""
+
msgid "Set up assertions/attributes/claims (email, first_name, last_name) and NameID according to %{docsLinkStart}the documentation %{icon}%{docsLinkEnd}"
msgstr ""
-msgid "Set up new U2F device"
+msgid "Set up new device"
msgstr ""
msgid "Set up new password"
@@ -22992,6 +23835,9 @@ msgstr ""
msgid "Sets weight to %{weight}."
msgstr ""
+msgid "Setting this to 0 means using the system default timeout value."
+msgstr ""
+
msgid "Settings"
msgstr ""
@@ -23007,6 +23853,15 @@ msgstr ""
msgid "Severity"
msgstr ""
+msgid "SeverityWidget|Severity"
+msgstr ""
+
+msgid "SeverityWidget|Severity: %{severity}"
+msgstr ""
+
+msgid "SeverityWidget|There was an error while updating severity."
+msgstr ""
+
msgid "Shards (%{shards})"
msgstr ""
@@ -23052,6 +23907,9 @@ msgstr ""
msgid "Show all requirements."
msgstr ""
+msgid "Show all test cases."
+msgstr ""
+
msgid "Show archived projects"
msgstr ""
@@ -23064,6 +23922,9 @@ msgstr ""
msgid "Show comments"
msgstr ""
+msgid "Show comments on this file"
+msgstr ""
+
msgid "Show comments only"
msgstr ""
@@ -23109,6 +23970,12 @@ msgstr ""
msgid "Show parent subgroups"
msgstr ""
+msgid "Show the Closed list"
+msgstr ""
+
+msgid "Show the Open list"
+msgstr ""
+
msgid "Show whitespace changes"
msgstr ""
@@ -23156,9 +24023,6 @@ msgstr ""
msgid "Sidebar|Assign health status"
msgstr ""
-msgid "Sidebar|Change weight"
-msgstr ""
-
msgid "Sidebar|Health status"
msgstr ""
@@ -23342,6 +24206,9 @@ msgstr ""
msgid "Snippets|Add another file %{num}/%{total}"
msgstr ""
+msgid "Snippets|Authored %{time_ago} by %{author}"
+msgstr ""
+
msgid "Snippets|Delete file"
msgstr ""
@@ -23369,6 +24236,9 @@ msgstr ""
msgid "Solution"
msgstr ""
+msgid "Some changes are not shown"
+msgstr ""
+
msgid "Some child epics may be hidden due to applied filters"
msgstr ""
@@ -23735,6 +24605,12 @@ msgstr ""
msgid "Source (branch or tag)"
msgstr ""
+msgid "Source Branch"
+msgstr ""
+
+msgid "Source branch: %{source_branch_open}%{source_branch}%{source_branch_close}"
+msgstr ""
+
msgid "Source code"
msgstr ""
@@ -23900,9 +24776,6 @@ msgstr ""
msgid "Start and due date"
msgstr ""
-msgid "Start by choosing a group to see how your team is spending time. You can then drill down to the project level."
-msgstr ""
-
msgid "Start by choosing a group to start exploring the merge requests in that group. You can then proceed to filter by projects, labels, milestones and authors."
msgstr ""
@@ -23984,18 +24857,27 @@ msgstr ""
msgid "StaticSiteEditor|3. Assign a person to review and accept the merge request."
msgstr ""
+msgid "StaticSiteEditor|A link to view the merge request will appear once ready."
+msgstr ""
+
msgid "StaticSiteEditor|An error occurred while submitting your changes."
msgstr ""
msgid "StaticSiteEditor|Branch could not be created."
msgstr ""
+msgid "StaticSiteEditor|Copy update"
+msgstr ""
+
msgid "StaticSiteEditor|Could not commit the content changes."
msgstr ""
msgid "StaticSiteEditor|Could not create merge request."
msgstr ""
+msgid "StaticSiteEditor|Creating your merge request"
+msgstr ""
+
msgid "StaticSiteEditor|Incompatible file content"
msgstr ""
@@ -24017,6 +24899,9 @@ msgstr ""
msgid "StaticSiteEditor|View documentation"
msgstr ""
+msgid "StaticSiteEditor|You can set an assignee to get your changes reviewed and deployed once your merge request is created."
+msgstr ""
+
msgid "StaticSiteEditor|Your merge request has been created"
msgstr ""
@@ -24146,15 +25031,15 @@ msgstr ""
msgid "Submit %{humanized_resource_name}"
msgstr ""
-msgid "Submit Changes"
-msgstr ""
-
msgid "Submit a review"
msgstr ""
msgid "Submit as spam"
msgstr ""
+msgid "Submit changes"
+msgstr ""
+
msgid "Submit feedback"
msgstr ""
@@ -24308,6 +25193,9 @@ msgstr ""
msgid "Successfully deleted U2F device."
msgstr ""
+msgid "Successfully deleted WebAuthn device."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -24626,9 +25514,6 @@ msgstr ""
msgid "Template to append to all Service Desk issues"
msgstr ""
-msgid "Template was successfully saved."
-msgstr ""
-
msgid "Templates"
msgstr ""
@@ -24713,10 +25598,28 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "Test failed."
+msgid "Test settings"
+msgstr ""
+
+msgid "TestCases|New Test Case"
+msgstr ""
+
+msgid "TestCases|New test case"
+msgstr ""
+
+msgid "TestCases|Search test cases"
msgstr ""
-msgid "Test settings and save changes"
+msgid "TestCases|Something went wrong while creating a test case."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching count of test cases."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching test cases list."
+msgstr ""
+
+msgid "TestCases|Submit test case"
msgstr ""
msgid "TestHooks|Ensure one of your projects has merge requests."
@@ -24782,6 +25685,9 @@ msgstr ""
msgid "Thank you for signing up for your free trial! You will get additional instructions in your inbox shortly."
msgstr ""
+msgid "Thank you for your business."
+msgstr ""
+
msgid "Thank you for your feedback!"
msgstr ""
@@ -24843,9 +25749,6 @@ msgstr ""
msgid "The URL to use for connecting to Elasticsearch. Use a comma-separated list to support clustering (e.g., \"http://localhost:9200, http://localhost:9201\")."
msgstr ""
-msgid "The Web IDE offers advanced syntax highlighting capabilities and more."
-msgstr ""
-
msgid "The X509 Certificate to use when mutual TLS is required to communicate with the external authorization service. If left blank, the server certificate is still validated when accessing over HTTPS."
msgstr ""
@@ -24958,6 +25861,9 @@ msgstr ""
msgid "The form contains the following error:"
msgstr ""
+msgid "The form contains the following warning:"
+msgstr ""
+
msgid "The global settings require you to enable Two-Factor Authentication for your account."
msgstr ""
@@ -25072,9 +25978,6 @@ msgstr ""
msgid "The private key to use when a client certificate is provided. This value is encrypted at rest."
msgstr ""
-msgid "The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The project can be accessed by any logged in user."
msgstr ""
@@ -25111,7 +26014,7 @@ msgstr ""
msgid "The remote repository is being updated..."
msgstr ""
-msgid "The repository can be commited to, and issues, comments and other entities can be created."
+msgid "The repository can be committed to, and issues, comments and other entities can be created."
msgstr ""
msgid "The repository for this project does not exist."
@@ -25165,9 +26068,6 @@ msgstr ""
msgid "The time taken by each data entry gathered by that stage."
msgstr ""
-msgid "The total stage shows the time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The update action will time out after %{number_of_minutes} minutes. For big repositories, use a clone/push combination."
msgstr ""
@@ -25231,6 +26131,9 @@ msgstr ""
msgid "There are no archived requirements"
msgstr ""
+msgid "There are no archived test cases"
+msgstr ""
+
msgid "There are no changes"
msgstr ""
@@ -25270,6 +26173,9 @@ msgstr ""
msgid "There are no open requirements"
msgstr ""
+msgid "There are no open test cases"
+msgstr ""
+
msgid "There are no packages yet"
msgstr ""
@@ -25282,6 +26188,9 @@ msgstr ""
msgid "There is a limit of %{ci_project_subscriptions_limit} subscriptions from or to a project."
msgstr ""
+msgid "There is already a To-Do for this design."
+msgstr ""
+
msgid "There is already a repository with that name on disk"
msgstr ""
@@ -25300,6 +26209,9 @@ msgstr ""
msgid "There was a problem communicating with your device."
msgstr ""
+msgid "There was a problem fetching branches."
+msgstr ""
+
msgid "There was a problem fetching groups."
msgstr ""
@@ -25528,9 +26440,15 @@ msgstr ""
msgid "This action can lead to data loss. To prevent accidental actions we ask you to confirm your intention."
msgstr ""
+msgid "This action cannot be undone, and will permanently delete the %{key} SSH key"
+msgstr ""
+
msgid "This action cannot be undone. You will lose the project's repository and all content: issues, merge requests, etc."
msgstr ""
+msgid "This action has been performed too many times. Try again later."
+msgstr ""
+
msgid "This action will %{strongOpen}permanently delete%{strongClose} %{codeOpen}%{project}%{codeClose} %{strongOpen}immediately%{strongClose}, including its repositories and all content: issues, merge requests, etc."
msgstr ""
@@ -25558,9 +26476,6 @@ msgstr ""
msgid "This board's scope is reduced"
msgstr ""
-msgid "This branch has changed since you started editing. Would you like to create a new branch?"
-msgstr ""
-
msgid "This chart could not be displayed"
msgstr ""
@@ -25687,15 +26602,9 @@ msgstr ""
msgid "This is a security log of important events involving your account."
msgstr ""
-msgid "This is the author's first Merge Request to this project."
-msgstr ""
-
msgid "This is the highest peak of users on your installation since the license started."
msgstr ""
-msgid "This is the maximum number of users that have existed at the same time since the license started. This is the minimum number of seats you will need to buy when you renew your license."
-msgstr ""
-
msgid "This is the number of currently active users on your installation, and this is the minimum number you need to purchase when you renew your license."
msgstr ""
@@ -25927,6 +26836,15 @@ msgstr ""
msgid "This user has no identities"
msgstr ""
+msgid "This user has previously committed to the %{name} project."
+msgstr ""
+
+msgid "This user has the %{access} role in the %{name} project."
+msgstr ""
+
+msgid "This user is the author of this %{noteable}."
+msgstr ""
+
msgid "This user will be the author of all events in the activity feed that are the result of an update, like new branches being created or new commits being pushed to existing branches."
msgstr ""
@@ -25957,6 +26875,9 @@ msgstr ""
msgid "Threat Monitoring"
msgstr ""
+msgid "ThreatMonitoring|All Environments"
+msgstr ""
+
msgid "ThreatMonitoring|Anomalous Requests"
msgstr ""
@@ -25984,9 +26905,6 @@ msgstr ""
msgid "ThreatMonitoring|Operations Per Second"
msgstr ""
-msgid "ThreatMonitoring|Overview"
-msgstr ""
-
msgid "ThreatMonitoring|Packet Activity"
msgstr ""
@@ -26005,6 +26923,9 @@ msgstr ""
msgid "ThreatMonitoring|Something went wrong, unable to fetch statistics"
msgstr ""
+msgid "ThreatMonitoring|Statistics"
+msgstr ""
+
msgid "ThreatMonitoring|The firewall is not installed or has been disabled. To view this data, ensure the web application firewall is installed and enabled for your cluster."
msgstr ""
@@ -26400,6 +27321,9 @@ msgstr ""
msgid "To update Snippets with multiple files, you must use the `files` parameter"
msgstr ""
+msgid "To use Gitpod you must first enable the feature in the integrations section of your %{user_prefs}."
+msgstr ""
+
msgid "To view all %{scannedResourcesCount} scanned URLs, please download the CSV file"
msgstr ""
@@ -26433,9 +27357,6 @@ msgstr ""
msgid "Toggle Sidebar"
msgstr ""
-msgid "Toggle all threads"
-msgstr ""
-
msgid "Toggle backtrace"
msgstr ""
@@ -26460,9 +27381,6 @@ msgstr ""
msgid "Toggle navigation"
msgstr ""
-msgid "Toggle project"
-msgstr ""
-
msgid "Toggle sidebar"
msgstr ""
@@ -26502,6 +27420,9 @@ msgstr ""
msgid "Too many projects enabled. You will need to manage them via the console or the API."
msgstr ""
+msgid "Too much data"
+msgstr ""
+
msgid "Topics (optional)"
msgstr ""
@@ -26520,6 +27441,9 @@ msgstr ""
msgid "Total cores (CPUs)"
msgstr ""
+msgid "Total days to completion"
+msgstr ""
+
msgid "Total issues"
msgstr ""
@@ -26616,6 +27540,9 @@ msgstr ""
msgid "Trending"
msgstr ""
+msgid "Trials|Create a new group to start your GitLab Gold trial."
+msgstr ""
+
msgid "Trials|Go back to GitLab"
msgstr ""
@@ -26625,6 +27552,15 @@ msgstr ""
msgid "Trials|You can always resume this process by selecting your avatar and choosing 'Start a Gold trial'"
msgstr ""
+msgid "Trials|You can apply your trial to a new group or an existing group."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group or your personal account."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group, an existing group, or your personal account."
+msgstr ""
+
msgid "Trials|You won't get a free trial right now but you can always resume this process by clicking on your avatar and choosing 'Start a free trial'"
msgstr ""
@@ -26694,6 +27630,9 @@ msgstr ""
msgid "Try using a different search term to find the file you are looking for."
msgstr ""
+msgid "Trying to communicate with your device. Plug it in (if needed) and press the button on the device now."
+msgstr ""
+
msgid "Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now."
msgstr ""
@@ -26781,6 +27720,12 @@ msgstr ""
msgid "URL or request ID"
msgstr ""
+msgid "USER %{user} WILL BE REMOVED! Are you sure?"
+msgstr ""
+
+msgid "USER WILL BE BLOCKED! Are you sure?"
+msgstr ""
+
msgid "UTC"
msgstr ""
@@ -26838,9 +27783,6 @@ msgstr ""
msgid "Unable to load the merge request widget. Try reloading the page."
msgstr ""
-msgid "Unable to resolve"
-msgstr ""
-
msgid "Unable to save iteration. Please try again"
msgstr ""
@@ -26889,6 +27831,9 @@ msgstr ""
msgid "Undo ignore"
msgstr ""
+msgid "Unexpected error"
+msgstr ""
+
msgid "Unfortunately, your email message to GitLab could not be processed."
msgstr ""
@@ -26922,6 +27867,9 @@ msgstr ""
msgid "Unknown response text"
msgstr ""
+msgid "Unless otherwise agreed to in writing with GitLab, by clicking \"Upload License\" you agree that your use of GitLab Software is subject to the %{eula_link_start}Terms of Service%{eula_link_end}."
+msgstr ""
+
msgid "Unlimited"
msgstr ""
@@ -27288,9 +28236,6 @@ msgstr "Pomocí %{code_start}::%{code_end} vytvoÅ™te sadu %{link_start} Å¡títkÅ
msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
msgstr ""
-msgid "Use a hardware device to add the second factor of authentication."
-msgstr ""
-
msgid "Use an one time password authenticator on your mobile device or computer to enable two-factor authentication (2FA)."
msgstr ""
@@ -27564,13 +28509,13 @@ msgstr ""
msgid "Users"
msgstr ""
-msgid "Users in License:"
+msgid "Users in License"
msgstr ""
-msgid "Users or groups set as approvers in the project's or merge request's settings."
+msgid "Users in License:"
msgstr ""
-msgid "Users outside of license"
+msgid "Users or groups set as approvers in the project's or merge request's settings."
msgstr ""
msgid "Users over License:"
@@ -27588,9 +28533,6 @@ msgstr ""
msgid "Users with a Guest role or those who don't belong to a Project or Group will not use a seat from your license."
msgstr ""
-msgid "Users with a Guest role or those who don't belong to any projects or groups don't count towards seats in use."
-msgstr ""
-
msgid "UsersSelect|%{name} + %{length} more"
msgstr ""
@@ -27630,9 +28572,6 @@ msgstr ""
msgid "Validations failed."
msgstr ""
-msgid "Validity"
-msgstr ""
-
msgid "Value"
msgstr ""
@@ -27651,6 +28590,9 @@ msgstr ""
msgid "Value Stream Name"
msgstr ""
+msgid "ValueStreamAnalyticsStage|We don't have enough data to show this stage."
+msgstr ""
+
msgid "ValueStreamAnalytics|%{days}d"
msgstr ""
@@ -27911,6 +28853,9 @@ msgstr ""
msgid "VisualReviewApp|Steps 1 and 2 (and sometimes 3) are performed once by the developer before requesting feedback. Steps 3 (if necessary), 4 is performed by the reviewer each time they perform a review."
msgstr ""
+msgid "Visualization"
+msgstr ""
+
msgid "Vulnerabilities"
msgstr ""
@@ -27938,34 +28883,31 @@ msgstr ""
msgid "VulnerabilityChart|Severity"
msgstr ""
-msgid "VulnerabilityManagement|A true-positive and will fix"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Change status"
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|Confirm"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Confirmed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
-msgstr ""
-
-msgid "VulnerabilityManagement|Detected %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|A true-positive and will fix"
msgstr ""
-msgid "VulnerabilityManagement|Dismiss"
+msgid "VulnerabilityManagement|Change status"
msgstr ""
-msgid "VulnerabilityManagement|Dismissed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
msgstr ""
-msgid "VulnerabilityManagement|Resolved"
+msgid "VulnerabilityManagement|Detected"
msgstr ""
-msgid "VulnerabilityManagement|Resolved %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Needs triage"
msgstr ""
msgid "VulnerabilityManagement|Something went wrong while trying to delete the comment. Please try again later."
@@ -28016,6 +28958,9 @@ msgstr ""
msgid "Vulnerability|%{scannerName} (version %{scannerVersion})"
msgstr ""
+msgid "Vulnerability|Activity"
+msgstr ""
+
msgid "Vulnerability|Class"
msgstr ""
@@ -28028,6 +28973,9 @@ msgstr ""
msgid "Vulnerability|Description"
msgstr ""
+msgid "Vulnerability|Detected"
+msgstr ""
+
msgid "Vulnerability|Evidence"
msgstr ""
@@ -28091,6 +29039,9 @@ msgstr ""
msgid "Warning: Displaying this diagram might cause performance issues on this page."
msgstr ""
+msgid "We are currently unable to fetch data for the pipeline header."
+msgstr ""
+
msgid "We are currently unable to fetch data for this graph."
msgstr ""
@@ -28130,6 +29081,12 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
+msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
+msgstr ""
+
+msgid "We would like to inform you that your subscription GitLab Enterprise Edition %{plan_name} is nearing its user limit. You have %{active_user_count} active users, which is almost at the user limit of %{maximum_user_count}."
+msgstr ""
+
msgid "We've found no vulnerabilities"
msgstr ""
@@ -28145,6 +29102,12 @@ msgstr ""
msgid "Web terminal"
msgstr ""
+msgid "WebAuthn Devices (%{length})"
+msgstr ""
+
+msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
+msgstr ""
+
msgid "WebIDE|Merge request"
msgstr ""
@@ -28283,15 +29246,9 @@ msgstr ""
msgid "Welcome to the guided GitLab tour"
msgstr ""
-msgid "Welcome to your Issue Board!"
-msgstr ""
-
msgid "Welcome to your issue board!"
msgstr ""
-msgid "We’ve been making changes to %{featureName} and we’d love your feedback %{linkStart}in this issue%{linkEnd} to help us improve the experience."
-msgstr ""
-
msgid "What are you searching for?"
msgstr ""
@@ -28310,6 +29267,9 @@ msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
msgstr ""
+msgid "When enabled, any user visiting %{host} and creating an account will have to be explicitly approved by the admin before they can login. This setting is effective only if sign-ups are enabled."
+msgstr ""
+
msgid "When enabled, any user visiting %{host} will be able to create an account."
msgstr ""
@@ -28536,6 +29496,9 @@ msgstr ""
msgid "With requirements, you can set criteria to check your products against."
msgstr ""
+msgid "With test cases, you can define conditions for your project to meet in determining quality"
+msgstr ""
+
msgid "Withdraw Access Request"
msgstr ""
@@ -28551,6 +29514,9 @@ msgstr ""
msgid "Workflow Help"
msgstr ""
+msgid "Would you like to create a new branch?"
+msgstr ""
+
msgid "Write"
msgstr ""
@@ -28572,6 +29538,9 @@ msgstr ""
msgid "Wrong extern UID provided. Make sure Auth0 is configured correctly."
msgstr ""
+msgid "YYYY-MM-DD"
+msgstr ""
+
msgid "Yes"
msgstr ""
@@ -28629,7 +29598,7 @@ msgstr ""
msgid "You are going to remove the fork relationship from %{project_full_name}. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "You are going to transfer %{project_full_name} to another owner. Are you ABSOLUTELY sure?"
+msgid "You are going to transfer %{project_full_name} to another namespace. Are you ABSOLUTELY sure?"
msgstr ""
msgid "You are going to turn off the confidentiality. This means %{strongStart}everyone%{strongEnd} will be able to see and leave a comment on this %{issuableType}."
@@ -28689,9 +29658,6 @@ msgstr ""
msgid "You can always edit this later"
msgstr ""
-msgid "You can apply your Trial to your Personal account or create a New Group."
-msgstr ""
-
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings"
msgstr ""
@@ -28713,12 +29679,18 @@ msgstr ""
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
+msgid "You can find more information about GitLab subscriptions in %{subscriptions_doc_link}."
+msgstr ""
+
msgid "You can generate an access token scoped to this project for each application to use the GitLab API."
msgstr ""
msgid "You can get started by cloning the repository or start adding files to it with one of the following options."
msgstr ""
+msgid "You can group test cases using labels. To learn about the future direction of this feature, visit %{linkStart}Quality Management direction page%{linkEnd}."
+msgstr ""
+
msgid "You can invite a new member to %{project_name} or invite another group."
msgstr ""
@@ -28734,6 +29706,9 @@ msgstr ""
msgid "You can notify the app / group or a project by sending them an email notification"
msgstr ""
+msgid "You can now close this window."
+msgstr ""
+
msgid "You can now export your security dashboard to a CSV report."
msgstr ""
@@ -28782,9 +29757,6 @@ msgstr ""
msgid "You can test your .gitlab-ci.yml in %{linkStart}CI Lint%{linkEnd}."
msgstr ""
-msgid "You can try again using %{begin_link}basic search%{end_link}"
-msgstr ""
-
msgid "You cannot access the raw file. Please wait a minute."
msgstr ""
@@ -28836,6 +29808,9 @@ msgstr ""
msgid "You don't have any U2F devices registered yet."
msgstr ""
+msgid "You don't have any WebAuthn devices registered yet."
+msgstr ""
+
msgid "You don't have any active chat names."
msgstr ""
@@ -28923,6 +29898,9 @@ msgstr ""
msgid "You must accept our Terms of Service and privacy policy in order to register an account"
msgstr ""
+msgid "You must be logged in to search across all of GitLab"
+msgstr ""
+
msgid "You must disassociate %{domain} from all clusters it is attached to before deletion."
msgstr ""
@@ -28962,7 +29940,7 @@ msgstr ""
msgid "You need to be logged in."
msgstr ""
-msgid "You need to register a two-factor authentication app before you can set up a U2F device."
+msgid "You need to register a two-factor authentication app before you can set up a device."
msgstr ""
msgid "You need to set terms to be enforced"
@@ -28980,6 +29958,9 @@ msgstr ""
msgid "You reached %{usage_in_percent} of %{namespace_name}'s storage capacity (%{used_storage} of %{storage_limit})"
msgstr ""
+msgid "You successfully declined the invitation"
+msgstr ""
+
msgid "You tried to fork %{link_to_the_project} but it failed for the following reason:"
msgstr ""
@@ -29145,10 +30126,13 @@ msgstr ""
msgid "Your U2F device did not send a valid JSON response."
msgstr ""
-msgid "Your U2F device needs to be set up. Plug it in (if not already) and click the button on the left."
+msgid "Your U2F device was registered!"
msgstr ""
-msgid "Your U2F device was registered!"
+msgid "Your WebAuthn device did not send a valid JSON response."
+msgstr ""
+
+msgid "Your WebAuthn device was registered!"
msgstr ""
msgid "Your access request to the %{source_type} has been withdrawn."
@@ -29172,6 +30156,9 @@ msgstr ""
msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
msgstr ""
+msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
+msgstr ""
+
msgid "Your changes can be committed to %{branch_name} because a merge request is open."
msgstr ""
@@ -29208,6 +30195,12 @@ msgstr ""
msgid "Your deployment services will be broken, you will need to manually fix the services after renaming."
msgstr ""
+msgid "Your device is not compatible with GitLab. Please try another device"
+msgstr ""
+
+msgid "Your device needs to be set up. Plug it in (if needed) and click the button on the left."
+msgstr ""
+
msgid "Your device was successfully set up! Give it a name and register it with the GitLab server."
msgstr ""
@@ -29323,9 +30316,6 @@ msgstr[3] ""
msgid "access:"
msgstr ""
-msgid "activated"
-msgstr ""
-
msgid "added %{created_at_timeago}"
msgstr ""
@@ -29398,9 +30388,21 @@ msgstr ""
msgid "by %{user}"
msgstr ""
+msgid "cannot be a date in the past"
+msgstr ""
+
msgid "cannot be changed if a personal project has container registry tags."
msgstr ""
+msgid "cannot be changed if shared runners are enabled"
+msgstr ""
+
+msgid "cannot be enabled because parent group does not allow it"
+msgstr ""
+
+msgid "cannot be enabled because parent group has shared Runners disabled"
+msgstr ""
+
msgid "cannot be enabled unless all domains have TLS certificates"
msgstr ""
@@ -29446,7 +30448,7 @@ msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about SAST %{linkEndTag}"
msgstr ""
-msgid "ciReport|%{linkStartTag}Learn more about Secret Scanning %{linkEndTag}"
+msgid "ciReport|%{linkStartTag}Learn more about Secret Detection %{linkEndTag}"
msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about codequality reports %{linkEndTag}"
@@ -29767,9 +30769,6 @@ msgstr ""
msgid "error"
msgstr ""
-msgid "error code:"
-msgstr ""
-
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr ""
@@ -29791,6 +30790,9 @@ msgstr ""
msgid "failed to dismiss associated finding(id=%{finding_id}): %{message}"
msgstr ""
+msgid "failed to revert associated finding(id=%{finding_id}) to detected"
+msgstr ""
+
msgid "file"
msgid_plural "files"
msgstr[0] ""
@@ -30341,6 +31343,9 @@ msgstr ""
msgid "must be a root namespace"
msgstr ""
+msgid "must be a valid IPv4 or IPv6 address"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -30377,6 +31382,9 @@ msgstr ""
msgid "no expiration"
msgstr ""
+msgid "no name set"
+msgstr ""
+
msgid "no one can merge"
msgstr ""
@@ -30565,9 +31573,6 @@ msgstr ""
msgid "security Reports|There was an error creating the merge request"
msgstr ""
-msgid "settings saved, but not activated"
-msgstr ""
-
msgid "severity|Critical"
msgstr ""
@@ -30694,9 +31699,6 @@ msgstr ""
msgid "toggle collapse"
msgstr ""
-msgid "toggle dropdown"
-msgstr ""
-
msgid "triggered"
msgstr ""
@@ -30724,6 +31726,9 @@ msgstr ""
msgid "user avatar"
msgstr ""
+msgid "user preferences"
+msgstr ""
+
msgid "username"
msgstr ""
diff --git a/locale/cy_GB/gitlab.po b/locale/cy_GB/gitlab.po
index dc0f7859d54..20a9e54653f 100644
--- a/locale/cy_GB/gitlab.po
+++ b/locale/cy_GB/gitlab.po
@@ -14,7 +14,10 @@ msgstr ""
"X-Crowdin-Language: cy\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 6\n"
-"PO-Revision-Date: 2020-09-04 23:01\n"
+"PO-Revision-Date: 2020-10-02 18:41\n"
+
+msgid " %{project_name}#%{issue_iid} &middot; opened %{issue_created} by %{author}"
+msgstr ""
msgid " %{start} to %{end}"
msgstr " %{start} i %{end}"
@@ -82,6 +85,24 @@ msgstr "Nid oedd \"%{path}\" yn bodoli ar \"%{ref}\""
msgid "\"el\" parameter is required for createInstance()"
msgstr ""
+msgid "%d Approval"
+msgid_plural "%d Approvals"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+msgstr[5] ""
+
+msgid "%d Package"
+msgid_plural "%d Packages"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+msgstr[5] ""
+
msgid "%d Scanned URL"
msgid_plural "%d Scanned URLs"
msgstr[0] ""
@@ -193,6 +214,15 @@ msgstr[5] ""
msgid "%d commits"
msgstr ""
+msgid "%d completed issue"
+msgid_plural "%d completed issues"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+msgstr[5] ""
+
msgid "%d contribution"
msgid_plural "%d contributions"
msgstr[0] ""
@@ -211,6 +241,15 @@ msgstr[3] ""
msgstr[4] ""
msgstr[5] ""
+msgid "%d day until tags are automatically removed"
+msgid_plural "%d days until tags are automatically removed"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+msgstr[5] ""
+
msgid "%d error"
msgid_plural "%d errors"
msgstr[0] ""
@@ -373,6 +412,24 @@ msgstr[3] ""
msgstr[4] ""
msgstr[5] ""
+msgid "%d open issue"
+msgid_plural "%d open issues"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+msgstr[5] ""
+
+msgid "%d pending comment"
+msgid_plural "%d pending comments"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+msgstr[5] ""
+
msgid "%d personal project will be removed and cannot be restored."
msgid_plural "%d personal projects will be removed and cannot be restored."
msgstr[0] ""
@@ -400,6 +457,15 @@ msgstr[3] ""
msgstr[4] ""
msgstr[5] ""
+msgid "%d project selected"
+msgid_plural "%d projects selected"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+msgstr[5] ""
+
msgid "%d request with warnings"
msgid_plural "%d requests with warnings"
msgstr[0] ""
@@ -436,6 +502,15 @@ msgstr[3] ""
msgstr[4] ""
msgstr[5] ""
+msgid "%d tag per image name"
+msgid_plural "%d tags per image name"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+msgstr[5] ""
+
msgid "%d unassigned issue"
msgid_plural "%d unassigned issues"
msgstr[0] ""
@@ -472,6 +547,15 @@ msgstr[3] ""
msgstr[4] ""
msgstr[5] ""
+msgid "%d warning found:"
+msgid_plural "%d warnings found:"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+msgstr[5] ""
+
msgid "%s additional commit has been omitted to prevent performance issues."
msgid_plural "%s additional commits have been omitted to prevent performance issues."
msgstr[0] ""
@@ -514,6 +598,9 @@ msgstr ""
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr ""
+msgid "%{completedCount} completed weight"
+msgstr ""
+
msgid "%{completedWeight} of %{totalWeight} weight completed"
msgstr ""
@@ -574,18 +661,12 @@ msgstr[3] "%{count} cyfranogwr"
msgstr[4] "%{count} chyfranogwr"
msgstr[5] "%{count} cyfranogwr"
-msgid "%{count} pending comment"
-msgid_plural "%{count} pending comments"
-msgstr[0] "%{count} sylwadau dan ystyriaeth"
-msgstr[1] "%{count} sylw dan ystyriaeth"
-msgstr[2] "%{count} sylw dan ystyriaeth"
-msgstr[3] "%{count} sylw dan ystyriaeth"
-msgstr[4] "%{count} sylw dan ystyriaeth"
-msgstr[5] "%{count} sylw dan ystyriaeth"
-
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr "%{count} %{pluralized_subject} cysylltiedig: %{links}"
+msgid "%{count} total weight"
+msgstr ""
+
msgid "%{dashboard_path} could not be found."
msgstr ""
@@ -640,6 +721,9 @@ msgstr ""
msgid "%{group_name} uses group managed accounts. You need to create a new GitLab account which will be managed by %{group_name}."
msgstr ""
+msgid "%{group_name}&%{epic_iid} &middot; opened %{epic_created} by %{author}"
+msgstr ""
+
msgid "%{host} sign-in from new location"
msgstr ""
@@ -652,7 +736,7 @@ msgstr ""
msgid "%{issuableType} will be removed! Are you sure?"
msgstr ""
-msgid "%{issuesSize} issues with a limit of %{maxIssueCount}"
+msgid "%{issuesCount} issues with a limit of %{maxIssueCount}"
msgstr ""
msgid "%{issuesSize} with a limit of %{maxIssueCount}"
@@ -685,7 +769,7 @@ msgstr ""
msgid "%{labelStart}Namespace:%{labelEnd} %{namespace}"
msgstr ""
-msgid "%{labelStart}Report Type:%{labelEnd} %{reportType}"
+msgid "%{labelStart}Scan Type:%{labelEnd} %{reportType}"
msgstr ""
msgid "%{labelStart}Scanner:%{labelEnd} %{scanner}"
@@ -910,9 +994,6 @@ msgstr[3] ""
msgstr[4] ""
msgstr[5] ""
-msgid "%{service_title} %{message}."
-msgstr ""
-
msgid "%{size} GiB"
msgstr ""
@@ -1021,6 +1102,12 @@ msgstr ""
msgid "%{timebox_name} should belong either to a project or a group."
msgstr ""
+msgid "%{timebox_type} does not support burnup charts"
+msgstr ""
+
+msgid "%{timebox_type} must have a start and due date"
+msgstr ""
+
msgid "%{title} %{operator} %{threshold}"
msgstr ""
@@ -1045,7 +1132,7 @@ msgstr ""
msgid "%{total} open issue weight"
msgstr ""
-msgid "%{total} open issues"
+msgid "%{total} warnings found: showing first %{warningsDisplayed}"
msgstr ""
msgid "%{usage_ping_link_start}Learn more%{usage_ping_link_end} about what information is shared with GitLab Inc."
@@ -1078,9 +1165,6 @@ msgstr ""
msgid "&lt; 1 hour"
msgstr ""
-msgid "&lt;no name set&gt;"
-msgstr ""
-
msgid "&lt;no scopes selected&gt;"
msgstr ""
@@ -1111,6 +1195,9 @@ msgstr ""
msgid "'%{name}' Value Stream created"
msgstr ""
+msgid "'%{name}' Value Stream deleted"
+msgstr ""
+
msgid "'%{name}' stage already exists"
msgstr ""
@@ -1174,6 +1261,9 @@ msgstr ""
msgid "+ %{numberOfHiddenAssignees} more"
msgstr ""
+msgid "+ %{numberOfHiddenReviewers} more"
+msgstr ""
+
msgid "+%d more"
msgid_plural "+%d more"
msgstr[0] ""
@@ -1258,6 +1348,15 @@ msgstr[3] ""
msgstr[4] ""
msgstr[5] ""
+msgid "1 Issue"
+msgid_plural "%d Issues"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+msgstr[5] ""
+
msgid "1 closed issue"
msgid_plural "%{issues} closed issues"
msgstr[0] ""
@@ -1285,6 +1384,15 @@ msgstr[3] ""
msgstr[4] ""
msgstr[5] ""
+msgid "1 deploy key"
+msgid_plural "%d deploy keys"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+msgstr[5] ""
+
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1423,6 +1531,9 @@ msgstr ""
msgid ":%{startLine} to %{endLine}"
msgstr ""
+msgid "A %{incident_docs_start}modified issue%{incident_docs_end} to guide the resolution of incidents."
+msgstr ""
+
msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr ""
@@ -1435,6 +1546,9 @@ msgstr ""
msgid "A GitBook site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
+msgid "A Gitpod configured Webapplication in Spring and Java"
+msgstr ""
+
msgid "A Hexo site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
@@ -1606,9 +1720,15 @@ msgstr ""
msgid "Access expiration date"
msgstr ""
+msgid "Access expires"
+msgstr ""
+
msgid "Access forbidden. Check your access level."
msgstr ""
+msgid "Access granted"
+msgstr ""
+
msgid "Access requests"
msgstr ""
@@ -1618,6 +1738,9 @@ msgstr ""
msgid "Access to Pages websites are controlled based on the user's membership to a given project. By checking this box, users will be required to be logged in to have access to all Pages websites in your instance."
msgstr ""
+msgid "AccessDropdown|Deploy Keys"
+msgstr ""
+
msgid "AccessDropdown|Groups"
msgstr ""
@@ -1735,12 +1858,6 @@ msgstr ""
msgid "Active Sessions"
msgstr ""
-msgid "Active Users:"
-msgstr ""
-
-msgid "Active users"
-msgstr ""
-
msgid "Activity"
msgstr ""
@@ -1912,9 +2029,6 @@ msgstr ""
msgid "Add label(s)"
msgstr ""
-msgid "Add license"
-msgstr ""
-
msgid "Add list"
msgstr ""
@@ -2089,21 +2203,51 @@ msgstr ""
msgid "AdminArea|Bots"
msgstr ""
+msgid "AdminArea|Components"
+msgstr ""
+
msgid "AdminArea|Developer"
msgstr ""
+msgid "AdminArea|Features"
+msgstr ""
+
+msgid "AdminArea|Groups: %{number_of_groups}"
+msgstr ""
+
msgid "AdminArea|Guest"
msgstr ""
msgid "AdminArea|Included Free in license"
msgstr ""
+msgid "AdminArea|Latest groups"
+msgstr ""
+
+msgid "AdminArea|Latest projects"
+msgstr ""
+
+msgid "AdminArea|Latest users"
+msgstr ""
+
msgid "AdminArea|Maintainer"
msgstr ""
+msgid "AdminArea|New group"
+msgstr ""
+
+msgid "AdminArea|New project"
+msgstr ""
+
+msgid "AdminArea|New user"
+msgstr ""
+
msgid "AdminArea|Owner"
msgstr ""
+msgid "AdminArea|Projects: %{number_of_projects}"
+msgstr ""
+
msgid "AdminArea|Reporter"
msgstr ""
@@ -2131,6 +2275,9 @@ msgstr ""
msgid "AdminArea|Users without a Group and Project"
msgstr ""
+msgid "AdminArea|Users: %{number_of_users}"
+msgstr ""
+
msgid "AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running."
msgstr ""
@@ -2149,9 +2296,6 @@ msgstr ""
msgid "AdminProjects|Delete Project %{projectName}?"
msgstr ""
-msgid "AdminProjects|Delete project"
-msgstr ""
-
msgid "AdminSettings|Apply integration settings to all Projects"
msgstr ""
@@ -2389,21 +2533,30 @@ msgstr ""
msgid "AdminUsers|Without projects"
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 ""
msgid "AdminUsers|You cannot remove your own admin rights."
msgstr ""
+msgid "AdminUsers|You must transfer ownership or delete the groups owned by this user before you can delete their account"
+msgstr ""
+
msgid "Administration"
msgstr ""
msgid "Advanced"
msgstr ""
+msgid "Advanced Search"
+msgstr ""
+
+msgid "Advanced Search with Elasticsearch"
+msgstr ""
+
msgid "Advanced Settings"
msgstr ""
@@ -2485,6 +2638,9 @@ msgstr ""
msgid "AlertManagement|Edit"
msgstr ""
+msgid "AlertManagement|Environment"
+msgstr ""
+
msgid "AlertManagement|Events"
msgstr ""
@@ -2497,6 +2653,9 @@ msgstr ""
msgid "AlertManagement|Issue"
msgstr ""
+msgid "AlertManagement|Key"
+msgstr ""
+
msgid "AlertManagement|Low"
msgstr ""
@@ -2590,6 +2749,9 @@ msgstr ""
msgid "AlertManagement|Unknown"
msgstr ""
+msgid "AlertManagement|Value"
+msgstr ""
+
msgid "AlertManagement|View alerts in Opsgenie"
msgstr ""
@@ -2749,6 +2911,9 @@ msgstr ""
msgid "All projects"
msgstr ""
+msgid "All projects selected"
+msgstr ""
+
msgid "All security scans are enabled because %{linkStart}Auto DevOps%{linkEnd} is enabled on this project"
msgstr ""
@@ -2836,6 +3001,9 @@ msgstr ""
msgid "Almost there"
msgstr ""
+msgid "Already blocked"
+msgstr ""
+
msgid "Also called \"Issuer\" or \"Relying party trust identifier\""
msgstr ""
@@ -2890,6 +3058,9 @@ msgstr ""
msgid "An error has occurred"
msgstr ""
+msgid "An error occured while making the changes: %{error}"
+msgstr ""
+
msgid "An error occurred adding a draft to the thread."
msgstr ""
@@ -2917,12 +3088,6 @@ msgstr ""
msgid "An error occurred when toggling the notification subscription"
msgstr ""
-msgid "An error occurred when trying to resolve a comment. Please try again."
-msgstr ""
-
-msgid "An error occurred when trying to resolve a discussion. Please try again."
-msgstr ""
-
msgid "An error occurred when updating the issue weight"
msgstr ""
@@ -2938,12 +3103,6 @@ msgstr ""
msgid "An error occurred while checking group path. Please refresh and try again."
msgstr ""
-msgid "An error occurred while committing your changes."
-msgstr ""
-
-msgid "An error occurred while creating the list. Please try again."
-msgstr ""
-
msgid "An error occurred while decoding the file."
msgstr ""
@@ -3016,25 +3175,19 @@ msgstr ""
msgid "An error occurred while fetching the Service Desk address."
msgstr ""
-msgid "An error occurred while fetching the board issues. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the board lists. Please reload the page."
msgstr ""
msgid "An error occurred while fetching the board lists. Please try again."
msgstr ""
-msgid "An error occurred while fetching the board swimlanes. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the builds."
msgstr ""
msgid "An error occurred while fetching the job log."
msgstr ""
-msgid "An error occurred while fetching the job trace."
+msgid "An error occurred while fetching the job logs."
msgstr ""
msgid "An error occurred while fetching the job."
@@ -3181,9 +3334,6 @@ msgstr ""
msgid "An error occurred while saving assignees"
msgstr ""
-msgid "An error occurred while saving the template. Please check if the template exists."
-msgstr ""
-
msgid "An error occurred while searching for milestones"
msgstr ""
@@ -3202,10 +3352,10 @@ msgstr ""
msgid "An error occurred while updating approvers"
msgstr ""
-msgid "An error occurred while updating the comment"
+msgid "An error occurred while updating labels."
msgstr ""
-msgid "An error occurred while updating the list. Please try again."
+msgid "An error occurred while updating the comment"
msgstr ""
msgid "An error occurred while validating group path"
@@ -3259,6 +3409,9 @@ msgstr ""
msgid "An unknown error occurred while loading this graph."
msgstr ""
+msgid "An unknown error occurred."
+msgstr ""
+
msgid "Analytics"
msgstr ""
@@ -3292,10 +3445,10 @@ msgstr ""
msgid "Any"
msgstr ""
-msgid "Any Author"
+msgid "Any %{header}"
msgstr ""
-msgid "Any Status"
+msgid "Any Author"
msgstr ""
msgid "Any branch"
@@ -3349,6 +3502,9 @@ msgstr ""
msgid "Application ID"
msgstr ""
+msgid "Application limits saved successfully"
+msgstr ""
+
msgid "Application settings saved successfully"
msgstr ""
@@ -3574,6 +3730,9 @@ msgstr ""
msgid "Are you sure you want to close this blocked issue?"
msgstr ""
+msgid "Are you sure you want to delete \"%{name}\" Value Stream?"
+msgstr ""
+
msgid "Are you sure you want to delete %{name}?"
msgstr ""
@@ -3583,6 +3742,9 @@ msgstr ""
msgid "Are you sure you want to delete this %{typeOfComment}?"
msgstr ""
+msgid "Are you sure you want to delete this SSH key?"
+msgstr ""
+
msgid "Are you sure you want to delete this board?"
msgstr ""
@@ -3607,6 +3769,15 @@ msgstr ""
msgid "Are you sure you want to erase this build?"
msgstr ""
+msgid "Are you sure you want to import %d repository?"
+msgid_plural "Are you sure you want to import %d repositories?"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+msgstr[5] ""
+
msgid "Are you sure you want to lose unsaved changes?"
msgstr ""
@@ -3616,15 +3787,15 @@ msgstr ""
msgid "Are you sure you want to merge immediately?"
msgstr ""
-msgid "Are you sure you want to permanently delete this license?"
-msgstr ""
-
msgid "Are you sure you want to re-deploy this environment?"
msgstr ""
msgid "Are you sure you want to regenerate the public key? You will have to update the public key on the remote server before mirroring will work again."
msgstr ""
+msgid "Are you sure you want to reindex?"
+msgstr ""
+
msgid "Are you sure you want to remove %{group_name}?"
msgstr ""
@@ -3652,6 +3823,9 @@ msgstr ""
msgid "Are you sure you want to revoke this nickname?"
msgstr ""
+msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
+msgstr ""
+
msgid "Are you sure you want to stop this environment?"
msgstr ""
@@ -3673,6 +3847,9 @@ msgstr ""
msgid "Are you sure? The device will be signed out of GitLab and all remember me tokens revoked."
msgstr ""
+msgid "Are you sure? This will invalidate your registered applications and U2F / WebAuthn devices."
+msgstr ""
+
msgid "Are you sure? This will invalidate your registered applications and U2F devices."
msgstr ""
@@ -3691,9 +3868,6 @@ msgstr ""
msgid "Artifacts"
msgstr ""
-msgid "As U2F devices are only supported by a few browsers, we require that you set up a two-factor authentication app before a U2F device. That way you'll always be able to log in - even when you're using an unsupported browser."
-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 ""
@@ -3895,6 +4069,9 @@ msgstr ""
msgid "AuditLogs|Target"
msgstr ""
+msgid "AuditLogs|This month"
+msgstr ""
+
msgid "AuditLogs|User Events"
msgstr ""
@@ -3934,6 +4111,9 @@ msgstr ""
msgid "Authentication via U2F device failed."
msgstr ""
+msgid "Authentication via WebAuthn device failed."
+msgstr ""
+
msgid "Author"
msgstr ""
@@ -4201,15 +4381,6 @@ msgstr ""
msgid "BambooService|You must set up automatic revision labeling and a repository trigger in Bamboo."
msgstr ""
-msgid "BatchComments|Delete all pending comments"
-msgstr ""
-
-msgid "BatchComments|Discard review?"
-msgstr ""
-
-msgid "BatchComments|You're about to discard your review which will delete all of your pending comments. The deleted comments %{strong_start}cannot%{strong_end} be restored."
-msgstr ""
-
msgid "Be careful. Changing the project's namespace can have unintended side effects."
msgstr ""
@@ -4231,6 +4402,9 @@ msgstr ""
msgid "Bi-weekly code coverage"
msgstr ""
+msgid "Billable Users:"
+msgstr ""
+
msgid "Billing"
msgstr ""
@@ -4240,7 +4414,7 @@ msgstr ""
msgid "BillingPlans|@%{user_name} you are currently using the %{plan_name} plan."
msgstr ""
-msgid "BillingPlans|Congratulations, your new trial is activated"
+msgid "BillingPlans|Congratulations, your free trial is activated."
msgstr ""
msgid "BillingPlans|If you would like to downgrade your plan please contact %{support_link_start}Customer Support%{support_link_end}."
@@ -4303,6 +4477,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Block user"
+msgstr ""
+
msgid "Blocked"
msgstr ""
@@ -4318,31 +4495,37 @@ msgstr ""
msgid "Blog"
msgstr ""
-msgid "Board name"
-msgstr ""
-
msgid "Board scope"
msgstr ""
msgid "Board scope affects which issues are displayed for anyone who visits this board"
msgstr ""
-msgid "BoardBlankState|Add default lists"
+msgid "Boards"
msgstr ""
-msgid "BoardBlankState|Add the following default lists to your Issue Board with one click:"
+msgid "Boards and Board Lists"
msgstr ""
-msgid "BoardBlankState|Nevermind, I'll use my own"
+msgid "Boards|An error occurred while creating the issue. Please try again."
msgstr ""
-msgid "BoardBlankState|Starting out with the default set of lists will get you right on the way to making the most of your board."
+msgid "Boards|An error occurred while creating the list. Please try again."
msgstr ""
-msgid "Boards"
+msgid "Boards|An error occurred while fetching issues. Please reload the page."
msgstr ""
-msgid "Boards and Board Lists"
+msgid "Boards|An error occurred while fetching the board issues. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching the board swimlanes. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while moving the issue. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while updating the list. Please try again."
msgstr ""
msgid "Boards|Collapse"
@@ -4369,7 +4552,7 @@ msgstr ""
msgid "Branch %{branch_name} was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr ""
-msgid "Branch has changed"
+msgid "Branch changed"
msgstr ""
msgid "Branch is already taken"
@@ -4675,6 +4858,9 @@ msgstr ""
msgid "CLOSED (MOVED)"
msgstr ""
+msgid "CODEOWNERS rule violation"
+msgstr ""
+
msgid "CONTRIBUTING"
msgstr ""
@@ -4705,9 +4891,6 @@ msgstr ""
msgid "Can't create snippet: %{err}"
msgstr ""
-msgid "Can't edit as source branch was deleted"
-msgstr ""
-
msgid "Can't fetch content for the blob: %{err}"
msgstr ""
@@ -4720,9 +4903,6 @@ msgstr ""
msgid "Can't load mermaid module: %{err}"
msgstr ""
-msgid "Can't remove group members without group managed account"
-msgstr ""
-
msgid "Can't scan the code?"
msgstr ""
@@ -4765,6 +4945,9 @@ msgstr ""
msgid "Cannot create the abuse report. This user has been blocked."
msgstr ""
+msgid "Cannot enable shared runners because parent group does not allow it"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -4870,6 +5053,15 @@ msgstr ""
msgid "Change your password or recover your current one"
msgstr ""
+msgid "ChangeReviewer|Reviewer changed from %{old} to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Reviewer changed to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Unassigned"
+msgstr ""
+
msgid "ChangeTypeActionLabel|Pick into branch"
msgstr ""
@@ -4909,6 +5101,9 @@ msgstr ""
msgid "Changes the title to \"%{title_param}\"."
msgstr ""
+msgid "Changes were successfully made."
+msgstr ""
+
msgid "Changes won't take place until the index is %{link_start}recreated%{link_end}."
msgstr ""
@@ -5314,6 +5509,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove variable"
+msgstr ""
+
msgid "CiVariables|Remove variable row"
msgstr ""
@@ -5392,9 +5590,6 @@ msgstr ""
msgid "Clear due date"
msgstr ""
-msgid "Clear input"
-msgstr ""
-
msgid "Clear recent searches"
msgstr ""
@@ -5443,6 +5638,9 @@ msgstr ""
msgid "Client authentication key password"
msgstr ""
+msgid "Client request timeout"
+msgstr ""
+
msgid "Clients"
msgstr ""
@@ -5527,6 +5725,27 @@ msgstr ""
msgid "Cluster type must be specificed for Stages::ClusterEndpointInserter"
msgstr ""
+msgid "ClusterAgents|Configuration"
+msgstr ""
+
+msgid "ClusterAgents|Connect your cluster with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate Kubernetes with a GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Name"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Agent also requires %{linkStart}enabling the Agent Server%{linkEnd}"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Kubernetes Agent allows an Infrastructure as Code, GitOps approach to integrating Kubernetes clusters with GitLab. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "ClusterAgent|This feature is only available for premium plans"
msgstr ""
@@ -5596,10 +5815,10 @@ msgstr ""
msgid "ClusterIntegration|All installed applications and related resources"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster."
+msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{linkStart}More information%{linkEnd}"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{startLink}More information%{endLink}"
+msgid "ClusterIntegration|Allow GitLab to manage namespaces and service accounts for this cluster."
msgstr ""
msgid "ClusterIntegration|Alternatively, "
@@ -5620,6 +5839,9 @@ msgstr ""
msgid "ClusterIntegration|An error occurred while trying to fetch zone machine types: %{error}"
msgstr ""
+msgid "ClusterIntegration|An unknown error occurred while attempting to connect to Kubernetes."
+msgstr ""
+
msgid "ClusterIntegration|Any project namespaces"
msgstr ""
@@ -5635,6 +5857,9 @@ msgstr ""
msgid "ClusterIntegration|Authenticate with Amazon Web Services"
msgstr ""
+msgid "ClusterIntegration|Authentication Error"
+msgstr ""
+
msgid "ClusterIntegration|Base domain"
msgstr ""
@@ -5653,13 +5878,22 @@ msgstr ""
msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}security group %{externalLinkIcon} %{endLink} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
+msgid "ClusterIntegration|Check your CA certificate"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}subnets %{externalLinkIcon} %{endLink} in your VPC where your worker nodes will run."
+msgid "ClusterIntegration|Check your cluster status"
msgstr ""
-msgid "ClusterIntegration|Choose the worker node %{startLink}instance type %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Check your token"
+msgstr ""
+
+msgid "ClusterIntegration|Choose the %{linkStart}security group %{linkEnd} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
+msgstr ""
+
+msgid "ClusterIntegration|Choose the %{linkStart}subnets %{linkEnd} in your VPC where your worker nodes will run."
+msgstr ""
+
+msgid "ClusterIntegration|Choose the worker node %{linkStart}instance type%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Choose which applications to install on your Kubernetes cluster."
@@ -5671,10 +5905,7 @@ msgstr ""
msgid "ClusterIntegration|Clear cluster cache"
msgstr ""
-msgid "ClusterIntegration|Clear the local cache of namespace and service accounts. This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
-msgstr ""
-
-msgid "ClusterIntegration|Cluster being created"
+msgid "ClusterIntegration|Clear the local cache of namespace and service accounts."
msgstr ""
msgid "ClusterIntegration|Cluster management project (alpha)"
@@ -5686,15 +5917,21 @@ msgstr ""
msgid "ClusterIntegration|Cluster_applications artifact too big. Maximum allowable size: %{human_size}"
msgstr ""
-msgid "ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters."
+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|Clusters connected with a certificate"
msgstr ""
-msgid "ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters. %{linkStart}More information%{linkEnd}"
+msgid "ClusterIntegration|Connect cluster with certificate"
msgstr ""
msgid "ClusterIntegration|Connect existing cluster"
msgstr ""
+msgid "ClusterIntegration|Connection Error"
+msgstr ""
+
msgid "ClusterIntegration|Copy API URL"
msgstr ""
@@ -5770,6 +6007,12 @@ msgstr ""
msgid "ClusterIntegration|Deletes all GitLab resources attached to this cluster during removal"
msgstr ""
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared."
+msgstr ""
+
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared. %{linkStart}More information%{linkEnd}"
+msgstr ""
+
msgid "ClusterIntegration|Did you know?"
msgstr ""
@@ -5839,6 +6082,9 @@ msgstr ""
msgid "ClusterIntegration|Fluentd is an open source data collector, which lets you unify the data collection and consumption for a better use and understanding of data. It requires at least one of the following logs to be successfully installed."
msgstr ""
+msgid "ClusterIntegration|GitLab Agent managed clusters"
+msgstr ""
+
msgid "ClusterIntegration|GitLab Container Network Policies"
msgstr ""
@@ -5851,6 +6097,12 @@ msgstr ""
msgid "ClusterIntegration|GitLab Runner connects to the repository and executes CI/CD jobs, pushing results back and deploying applications to production."
msgstr ""
+msgid "ClusterIntegration|GitLab failed to authenticate."
+msgstr ""
+
+msgid "ClusterIntegration|GitLab failed to connect to the cluster."
+msgstr ""
+
msgid "ClusterIntegration|GitLab-managed cluster"
msgstr ""
@@ -5872,6 +6124,9 @@ msgstr ""
msgid "ClusterIntegration|Group cluster"
msgstr ""
+msgid "ClusterIntegration|HTTP Error"
+msgstr ""
+
msgid "ClusterIntegration|Helm Tiller"
msgstr ""
@@ -5905,7 +6160,10 @@ msgstr ""
msgid "ClusterIntegration|Instance type"
msgstr ""
-msgid "ClusterIntegration|Integrate Kubernetes cluster automation"
+msgid "ClusterIntegration|Integrate Kubernetes with a cluster certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Integrate with a cluster certificate"
msgstr ""
msgid "ClusterIntegration|Issuer Email"
@@ -5941,9 +6199,6 @@ msgstr ""
msgid "ClusterIntegration|Knative extends Kubernetes to provide a set of middleware components that are essential to build modern, source-centric, and container-based applications that can run anywhere: on premises, in the cloud, or even in a third-party data center."
msgstr ""
-msgid "ClusterIntegration|Kubernetes cluster"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes cluster is being created..."
msgstr ""
@@ -5956,9 +6211,6 @@ msgstr ""
msgid "ClusterIntegration|Kubernetes clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr ""
-msgid "ClusterIntegration|Kubernetes clusters can be used to deploy applications and to provide Review Apps for this project"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes version"
msgstr ""
@@ -5971,7 +6223,7 @@ msgstr ""
msgid "ClusterIntegration|Learn more about %{help_link_start}zones%{help_link_end}."
msgstr ""
-msgid "ClusterIntegration|Learn more about %{startLink}Regions %{externalLinkIcon}%{endLink}."
+msgid "ClusterIntegration|Learn more about %{linkStart}Regions%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Learn more about Kubernetes"
@@ -6016,12 +6268,18 @@ msgstr ""
msgid "ClusterIntegration|Machine type"
msgstr ""
+msgid "ClusterIntegration|Make sure your API endpoint is correct"
+msgstr ""
+
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create Kubernetes clusters"
msgstr ""
msgid "ClusterIntegration|Manage your Kubernetes cluster by visiting %{provider_link}"
msgstr ""
+msgid "ClusterIntegration|Namespace per environment"
+msgstr ""
+
msgid "ClusterIntegration|No IAM Roles found"
msgstr ""
@@ -6067,6 +6325,9 @@ msgstr ""
msgid "ClusterIntegration|No zones matched your search"
msgstr ""
+msgid "ClusterIntegration|Node calculations use the Kubernetes Metrics API. Make sure your cluster has metrics installed"
+msgstr ""
+
msgid "ClusterIntegration|Number of nodes"
msgstr ""
@@ -6109,6 +6370,9 @@ msgstr ""
msgid "ClusterIntegration|RBAC-enabled cluster"
msgstr ""
+msgid "ClusterIntegration|Read our %{linkStart}help page%{linkEnd} on Kubernetes cluster integration."
+msgstr ""
+
msgid "ClusterIntegration|Read our %{link_start}help page%{link_end} on Kubernetes cluster integration."
msgstr ""
@@ -6211,7 +6475,7 @@ msgstr ""
msgid "ClusterIntegration|Select a VPC to choose a subnet"
msgstr ""
-msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{linkStart}Amazon Web Services %{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select a network to choose a subnetwork"
@@ -6244,7 +6508,7 @@ msgstr ""
msgid "ClusterIntegration|Select project to choose zone"
msgstr ""
-msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select zone"
@@ -6334,9 +6598,18 @@ msgstr ""
msgid "ClusterIntegration|There was a problem authenticating with your cluster. Please ensure your CA Certificate and Token are valid."
msgstr ""
+msgid "ClusterIntegration|There was an HTTP error when connecting to your cluster."
+msgstr ""
+
msgid "ClusterIntegration|This account must have permissions to create a Kubernetes cluster in the %{link_to_container_project} specified below"
msgstr ""
+msgid "ClusterIntegration|This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
+msgstr ""
+
+msgid "ClusterIntegration|This is necessary to clear existing environment-namespace associations from clusters previously managed by GitLab."
+msgstr ""
+
msgid "ClusterIntegration|This option will allow you to install applications on RBAC clusters."
msgstr ""
@@ -6361,9 +6634,21 @@ msgstr ""
msgid "ClusterIntegration|To use a new project, first create one on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}."
msgstr ""
+msgid "ClusterIntegration|Troubleshooting tips:"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Authenticate"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Connect"
+msgstr ""
+
msgid "ClusterIntegration|Uninstall %{appTitle}"
msgstr ""
+msgid "ClusterIntegration|Unknown Error"
+msgstr ""
+
msgid "ClusterIntegration|Update %{appTitle}"
msgstr ""
@@ -6424,7 +6709,7 @@ msgstr ""
msgid "ClusterIntegration|Your cluster API is unreachable. Please ensure your API URL is correct."
msgstr ""
-msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Zone"
@@ -6544,6 +6829,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse all threads"
+msgstr ""
+
msgid "Collapse approvers"
msgstr ""
@@ -6697,7 +6985,7 @@ msgstr ""
msgid "Commit…"
msgstr ""
-msgid "Company"
+msgid "Community forum"
msgstr ""
msgid "Company name"
@@ -6706,6 +6994,9 @@ msgstr ""
msgid "Compare"
msgstr ""
+msgid "Compare %{oldCommitId}...%{newCommitId}"
+msgstr ""
+
msgid "Compare Git revisions"
msgstr ""
@@ -6721,6 +7012,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare submodule commit revisions"
+msgstr ""
+
msgid "Compare with previous version"
msgstr ""
@@ -6856,6 +7150,9 @@ msgstr ""
msgid "Configure the way a user creates a new account."
msgstr ""
+msgid "Configure which lists are shown for anyone who visits this board"
+msgstr ""
+
msgid "Confirm"
msgstr ""
@@ -7093,6 +7390,9 @@ msgstr[5] ""
msgid "ContainerRegistry|Set cleanup policy"
msgstr ""
+msgid "ContainerRegistry|Some tags were not deleted"
+msgstr ""
+
msgid "ContainerRegistry|Something went wrong while fetching the cleanup policy."
msgstr ""
@@ -7132,6 +7432,9 @@ msgstr ""
msgid "ContainerRegistry|Tags with names matching this regex pattern will %{italicStart}expire:%{italicEnd}"
msgstr ""
+msgid "ContainerRegistry|The cleanup policy timed out before it could delete all tags. An administrator can %{adminLinkStart}manually run cleanup now%{adminLinkEnd} or you can wait for the cleanup policy to automatically run again. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "ContainerRegistry|The last tag related to this image was recently removed. This empty image and any associated data will be automatically removed as part of the regular Garbage Collection process. If you have any questions, contact your administrator."
msgstr ""
@@ -7264,6 +7567,9 @@ msgstr ""
msgid "Contributions per group member"
msgstr ""
+msgid "Contributor"
+msgstr ""
+
msgid "Contributors"
msgstr ""
@@ -7393,6 +7699,9 @@ msgstr ""
msgid "Could not change HEAD: branch '%{branch}' does not exist"
msgstr ""
+msgid "Could not commit. An unexpected error occurred."
+msgstr ""
+
msgid "Could not connect to FogBugz, check your URL"
msgstr ""
@@ -7432,6 +7741,9 @@ msgstr ""
msgid "Could not find iteration"
msgstr ""
+msgid "Could not load instance counts. Please refresh the page to try again."
+msgstr ""
+
msgid "Could not remove the trigger."
msgstr ""
@@ -7456,10 +7768,10 @@ msgstr ""
msgid "Could not save prometheus manual configuration"
msgstr ""
-msgid "Could not udpdate wiki page"
+msgid "Could not update the LDAP settings"
msgstr ""
-msgid "Could not update the LDAP settings"
+msgid "Could not update wiki page"
msgstr ""
msgid "Could not upload your designs as one or more files uploaded are not supported."
@@ -8125,6 +8437,9 @@ msgstr ""
msgid "DastProfiles|Are you sure you want to delete this profile?"
msgstr ""
+msgid "DastProfiles|Could not create site validation token. Please refresh the page, or try again later."
+msgstr ""
+
msgid "DastProfiles|Could not create the scanner profile. Please try again."
msgstr ""
@@ -8149,6 +8464,12 @@ msgstr ""
msgid "DastProfiles|Could not fetch site profiles. Please refresh the page, or try again later."
msgstr ""
+msgid "DastProfiles|Could not retrieve site validation status. Please refresh the page, or try again later."
+msgstr ""
+
+msgid "DastProfiles|Could not update the scanner profile. Please try again."
+msgstr ""
+
msgid "DastProfiles|Could not update the site profile. Please try again."
msgstr ""
@@ -8164,7 +8485,7 @@ msgstr ""
msgid "DastProfiles|Download validation text file"
msgstr ""
-msgid "DastProfiles|Edit feature will come soon. Please create a new profile if changes needed"
+msgid "DastProfiles|Edit scanner profile"
msgstr ""
msgid "DastProfiles|Edit site profile"
@@ -8197,6 +8518,9 @@ msgstr ""
msgid "DastProfiles|No profiles created yet"
msgstr ""
+msgid "DastProfiles|Passive"
+msgstr ""
+
msgid "DastProfiles|Please enter a valid URL format, ex: http://www.example.com/home"
msgstr ""
@@ -8212,6 +8536,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan mode"
+msgstr ""
+
msgid "DastProfiles|Scanner Profile"
msgstr ""
@@ -8251,10 +8578,10 @@ msgstr ""
msgid "DastProfiles|Text file validation"
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
+msgid "DastProfiles|The maximum number of minutes allowed for the spider to traverse the site."
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the spider to traverse the site."
+msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
msgstr ""
msgid "DastProfiles|Validate"
@@ -8287,6 +8614,9 @@ msgstr ""
msgid "Date picker"
msgstr ""
+msgid "Date range"
+msgstr ""
+
msgid "Date range cannot exceed %{maxDateRange} days."
msgstr ""
@@ -8311,6 +8641,9 @@ msgstr ""
msgid "Days to merge"
msgstr ""
+msgid "Dear Administrator,"
+msgstr ""
+
msgid "Debug"
msgstr ""
@@ -8422,12 +8755,18 @@ msgstr ""
msgid "Delete"
msgstr ""
+msgid "Delete %{name}"
+msgstr ""
+
msgid "Delete Comment"
msgstr ""
msgid "Delete Snippet"
msgstr ""
+msgid "Delete Value Stream"
+msgstr ""
+
msgid "Delete account"
msgstr ""
@@ -8449,9 +8788,6 @@ msgstr ""
msgid "Delete label: %{label_name} ?"
msgstr ""
-msgid "Delete license"
-msgstr ""
-
msgid "Delete list"
msgstr ""
@@ -8527,15 +8863,6 @@ msgstr ""
msgid "Deleting a project places it into a read-only state until %{date}, at which point the project will be permanently deleted. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "Deleting the license failed."
-msgstr ""
-
-msgid "Deleting the license failed. The license was not found."
-msgstr ""
-
-msgid "Deleting the license failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "Deleting the project will delete its repository and all related resources including issues, merge requests etc."
msgstr ""
@@ -9055,7 +9382,10 @@ msgstr ""
msgid "DesignManagement|The maximum number of designs allowed to be uploaded is %{upload_limit}. Please try again."
msgstr ""
-msgid "DesignManagement|To upload designs, you'll need to enable LFS. %{requirements_link_start}More information%{requirements_link_end}"
+msgid "DesignManagement|There was an error moving your designs. Please upload your designs below."
+msgstr ""
+
+msgid "DesignManagement|To upload designs, you'll need to enable LFS and have admin enable hashed storage. %{requirements_link_start}More information%{requirements_link_end}"
msgstr ""
msgid "DesignManagement|Unresolve thread"
@@ -9067,6 +9397,9 @@ msgstr ""
msgid "DesignManagement|Upload skipped."
msgstr ""
+msgid "DesignManagement|Your designs are being copied and are on their way… Please refresh to update."
+msgstr ""
+
msgid "DesignManagement|and %{moreCount} more."
msgstr ""
@@ -9124,6 +9457,9 @@ msgstr ""
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
+msgid "Direct member"
+msgstr ""
+
msgid "Direction"
msgstr ""
@@ -9172,9 +9508,6 @@ msgstr ""
msgid "Discard draft"
msgstr ""
-msgid "Discard review"
-msgstr ""
-
msgid "DiscordService|Discord Notifications"
msgstr ""
@@ -9247,10 +9580,10 @@ msgstr ""
msgid "Dismiss Merge Request promotion"
msgstr ""
-msgid "Dismiss Selected"
+msgid "Dismiss Value Stream Analytics introduction box"
msgstr ""
-msgid "Dismiss Value Stream Analytics introduction box"
+msgid "Dismiss selected"
msgstr ""
msgid "Dismiss trial promotion"
@@ -9301,9 +9634,6 @@ msgstr ""
msgid "Documents reindexed: %{processed_documents} (%{percentage}%%)"
msgstr ""
-msgid "Doing"
-msgstr ""
-
msgid "Domain"
msgstr ""
@@ -9499,9 +9829,6 @@ msgstr ""
msgid "Edit environment"
msgstr ""
-msgid "Edit file"
-msgstr ""
-
msgid "Edit files in the editor and commit changes here"
msgstr ""
@@ -9514,6 +9841,12 @@ msgstr ""
msgid "Edit identity for %{user_name}"
msgstr ""
+msgid "Edit in Web IDE"
+msgstr ""
+
+msgid "Edit in single-file editor"
+msgstr ""
+
msgid "Edit issues"
msgstr ""
@@ -9541,10 +9874,10 @@ msgstr ""
msgid "Editing"
msgstr ""
-msgid "Elasticsearch"
+msgid "Elasticsearch AWS IAM credentials"
msgstr ""
-msgid "Elasticsearch AWS IAM credentials"
+msgid "Elasticsearch HTTP client timeout value in seconds."
msgstr ""
msgid "Elasticsearch indexing restrictions"
@@ -9553,9 +9886,6 @@ msgstr ""
msgid "Elasticsearch indexing started"
msgstr ""
-msgid "Elasticsearch integration. Elasticsearch AWS IAM."
-msgstr ""
-
msgid "Elasticsearch reindexing is already in progress"
msgstr ""
@@ -9583,9 +9913,6 @@ msgstr ""
msgid "Email Notification"
msgstr ""
-msgid "Email address"
-msgstr ""
-
msgid "Email could not be sent"
msgstr ""
@@ -9649,6 +9976,9 @@ msgstr ""
msgid "Emails sent from Service Desk will have this name"
msgstr ""
+msgid "Emails sent to %{email} will still be supported"
+msgstr ""
+
msgid "Emails separated by comma"
msgstr ""
@@ -9682,9 +10012,18 @@ msgstr ""
msgid "Enable"
msgstr ""
+msgid "Enable %{link_start}Gitpod%{link_end} integration to launch a development environment in your browser directly from GitLab."
+msgstr ""
+
msgid "Enable Auto DevOps"
msgstr ""
+msgid "Enable Gitpod"
+msgstr ""
+
+msgid "Enable Gitpod?"
+msgstr ""
+
msgid "Enable HTML emails"
msgstr ""
@@ -9814,9 +10153,6 @@ msgstr ""
msgid "Encountered an error while rendering: %{err}"
msgstr ""
-msgid "End date"
-msgstr ""
-
msgid "Ends at (UTC)"
msgstr ""
@@ -9976,7 +10312,7 @@ msgstr ""
msgid "EnvironmentsDashboard|The environments dashboard provides a summary of each project's environments' status, including pipeline and alert statuses."
msgstr ""
-msgid "EnvironmentsDashboard|This dashboard displays a maximum of 7 projects and 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
+msgid "EnvironmentsDashboard|This dashboard displays 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
msgstr ""
msgid "Environments|An error occurred while canceling the auto stop, please try again"
@@ -10297,6 +10633,9 @@ msgstr ""
msgid "Error deleting project. Check logs for error details."
msgstr ""
+msgid "Error fetching burnup chart data"
+msgstr ""
+
msgid "Error fetching diverging counts for branches. Please try again."
msgstr ""
@@ -10375,6 +10714,9 @@ msgstr ""
msgid "Error occurred when saving assignees"
msgstr ""
+msgid "Error occurred when saving reviewers"
+msgstr ""
+
msgid "Error occurred when toggling the notification subscription"
msgstr ""
@@ -10627,10 +10969,13 @@ msgstr ""
msgid "Expand all"
msgstr ""
-msgid "Expand approvers"
+msgid "Expand all files"
+msgstr ""
+
+msgid "Expand all threads"
msgstr ""
-msgid "Expand dropdown"
+msgid "Expand approvers"
msgstr ""
msgid "Expand milestones"
@@ -10801,6 +11146,9 @@ msgstr ""
msgid "Failed to create Merge Request. Please try again."
msgstr ""
+msgid "Failed to create To-Do for the design."
+msgstr ""
+
msgid "Failed to create a branch for this issue. Please try again."
msgstr ""
@@ -10840,6 +11188,12 @@ msgstr ""
msgid "Failed to load authors. Please try again."
msgstr ""
+msgid "Failed to load branches. Please try again."
+msgstr ""
+
+msgid "Failed to load deploy keys."
+msgstr ""
+
msgid "Failed to load emoji list."
msgstr ""
@@ -10855,6 +11209,9 @@ msgstr ""
msgid "Failed to load groups & users."
msgstr ""
+msgid "Failed to load groups, users and deploy keys."
+msgstr ""
+
msgid "Failed to load labels. Please try again."
msgstr ""
@@ -10864,6 +11221,12 @@ msgstr ""
msgid "Failed to load related branches"
msgstr ""
+msgid "Failed to load sidebar confidential toggle"
+msgstr ""
+
+msgid "Failed to load sidebar lock status"
+msgstr ""
+
msgid "Failed to load stacktrace."
msgstr ""
@@ -10891,6 +11254,9 @@ msgstr ""
msgid "Failed to publish issue on status page."
msgstr ""
+msgid "Failed to remove To-Do for the design."
+msgstr ""
+
msgid "Failed to remove a Zoom meeting"
msgstr ""
@@ -10933,6 +11299,9 @@ msgstr ""
msgid "Failed to signing using smartcard authentication"
msgstr ""
+msgid "Failed to toggle To-Do for the design."
+msgstr ""
+
msgid "Failed to update branch!"
msgstr ""
@@ -11050,7 +11419,7 @@ msgstr ""
msgid "FeatureFlags|Edit User List"
msgstr ""
-msgid "FeatureFlags|Enable features for specific users and specific environments by defining feature flag strategies."
+msgid "FeatureFlags|Enable features for specific users and environments by configuring feature flag strategies."
msgstr ""
msgid "FeatureFlags|Environment Spec"
@@ -11110,7 +11479,7 @@ msgstr ""
msgid "FeatureFlags|Include additional user IDs"
msgstr ""
-msgid "FeatureFlags|Install a %{docs_link_anchored_start}compatible client library%{docs_link_anchored_end} and specify the API URL, application name, and instance ID during the configuration setup. %{docs_link_start}More Information%{docs_link_end}"
+msgid "FeatureFlags|Install a %{docsLinkAnchoredStart}compatible client library%{docsLinkAnchoredEnd} and specify the API URL, application name, and instance ID during the configuration setup. %{docsLinkStart}More Information%{docsLinkEnd}"
msgstr ""
msgid "FeatureFlags|Instance ID"
@@ -11122,6 +11491,9 @@ msgstr ""
msgid "FeatureFlags|Loading feature flags"
msgstr ""
+msgid "FeatureFlags|Loading user lists"
+msgstr ""
+
msgid "FeatureFlags|More information"
msgstr ""
@@ -11140,7 +11512,7 @@ msgstr ""
msgid "FeatureFlags|New feature flag"
msgstr ""
-msgid "FeatureFlags|New list"
+msgid "FeatureFlags|New user list"
msgstr ""
msgid "FeatureFlags|Percent of users"
@@ -11179,6 +11551,9 @@ msgstr ""
msgid "FeatureFlags|There was an error fetching the feature flags."
msgstr ""
+msgid "FeatureFlags|There was an error fetching the user lists."
+msgstr ""
+
msgid "FeatureFlags|There was an error retrieving user lists"
msgstr ""
@@ -11194,6 +11569,9 @@ msgstr ""
msgid "FeatureFlags|User List"
msgstr ""
+msgid "FeatureFlags|User Lists"
+msgstr ""
+
msgid "FeatureFlag|List"
msgstr ""
@@ -11221,15 +11599,6 @@ msgstr ""
msgid "Fetching incoming email"
msgstr ""
-msgid "Fetching licenses failed."
-msgstr ""
-
-msgid "Fetching licenses failed. The request endpoint was not found."
-msgstr ""
-
-msgid "Fetching licenses failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "File"
msgstr ""
@@ -11332,12 +11701,21 @@ msgstr ""
msgid "Filter by status"
msgstr ""
+msgid "Filter by test cases that are currently archived."
+msgstr ""
+
+msgid "Filter by test cases that are currently opened."
+msgstr ""
+
msgid "Filter by two-factor authentication"
msgstr ""
msgid "Filter by user"
msgstr ""
+msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
+msgstr ""
+
msgid "Filter pipelines"
msgstr ""
@@ -11353,7 +11731,7 @@ msgstr ""
msgid "Filter results..."
msgstr ""
-msgid "Filter your projects by name"
+msgid "Filter your repositories by name"
msgstr ""
msgid "Filter..."
@@ -11362,7 +11740,7 @@ msgstr ""
msgid "Find File"
msgstr ""
-msgid "Find bugs in your code with coverage-guided fuzzing"
+msgid "Find bugs in your code with coverage-guided fuzzing."
msgstr ""
msgid "Find by path"
@@ -11389,9 +11767,6 @@ msgstr ""
msgid "Finish editing this message first!"
msgstr ""
-msgid "Finish review"
-msgstr ""
-
msgid "Finish setting up your dedicated account for %{group_name}."
msgstr ""
@@ -11461,6 +11836,9 @@ msgstr ""
msgid "Footer message"
msgstr ""
+msgid "For a faster browsing experience, some files are collapsed by default."
+msgstr ""
+
msgid "For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
@@ -11470,6 +11848,9 @@ msgstr ""
msgid "For more info, read the documentation."
msgstr ""
+msgid "For more information on how the number of active users is calculated, see the %{self_managed_subscriptions_doc_link} documentation."
+msgstr ""
+
msgid "For more information, go to the "
msgstr ""
@@ -11608,6 +11989,9 @@ msgstr ""
msgid "Generate new token"
msgstr ""
+msgid "Generic package file size in bytes"
+msgstr ""
+
msgid "Geo"
msgstr ""
@@ -11869,6 +12253,9 @@ msgstr ""
msgid "Geo|Please refer to Geo Troubleshooting."
msgstr ""
+msgid "Geo|Primary node"
+msgstr ""
+
msgid "Geo|Project"
msgstr ""
@@ -11911,6 +12298,9 @@ msgstr ""
msgid "Geo|Review replication status, and resynchronize and reverify items with the primary node."
msgstr ""
+msgid "Geo|Secondary node"
+msgstr ""
+
msgid "Geo|Status"
msgstr ""
@@ -11950,6 +12340,9 @@ msgstr ""
msgid "Geo|URL must be a valid url (ex: https://gitlab.com)"
msgstr ""
+msgid "Geo|Undefined"
+msgstr ""
+
msgid "Geo|Unknown state"
msgstr ""
@@ -12025,10 +12418,16 @@ msgstr ""
msgid "GitHub import"
msgstr ""
+msgid "GitLab"
+msgstr ""
+
msgid "GitLab / Unsubscribe"
msgstr ""
-msgid "GitLab Enterprise Edition %{plan}"
+msgid "GitLab API"
+msgstr ""
+
+msgid "GitLab Billing Team."
msgstr ""
msgid "GitLab Group Runners can execute code for all the projects in this group."
@@ -12040,12 +12439,18 @@ msgstr ""
msgid "GitLab Issue"
msgstr ""
+msgid "GitLab Pages"
+msgstr ""
+
msgid "GitLab Service Desk is a simple way to allow people to create issues in your GitLab instance without needing their own user account. It provides a unique email address for end users to create issues in a project, and replies can be sent either through the GitLab interface or by email. End users will only see the thread through email."
msgstr ""
msgid "GitLab Shared Runners execute code of different projects on the same Runner unless you configure GitLab Runner Autoscale with MaxBuilds 1 (which it is on GitLab.com)."
msgstr ""
+msgid "GitLab Shell"
+msgstr ""
+
msgid "GitLab Support Bot"
msgstr ""
@@ -12055,7 +12460,7 @@ msgstr ""
msgid "GitLab User"
msgstr ""
-msgid "GitLab allows you to continue using your license even if you exceed the number of seats you purchased. You will be required to pay for these seats when you renew your license."
+msgid "GitLab Workhorse"
msgstr ""
msgid "GitLab commit"
@@ -12223,6 +12628,21 @@ msgstr ""
msgid "Gitlab Pages"
msgstr ""
+msgid "Gitpod"
+msgstr ""
+
+msgid "Gitpod|Add the URL to your Gitpod instance configured to read your GitLab projects."
+msgstr ""
+
+msgid "Gitpod|Enable Gitpod integration"
+msgstr ""
+
+msgid "Gitpod|Gitpod URL"
+msgstr ""
+
+msgid "Gitpod|e.g. https://gitpod.example.com"
+msgstr ""
+
msgid "Given access %{time_ago}"
msgstr ""
@@ -12730,9 +13150,6 @@ msgstr ""
msgid "GroupSAML|Valid SAML Response"
msgstr ""
-msgid "GroupSAML|With group managed accounts enabled, all the users without a group managed account will be excluded from the group."
-msgstr ""
-
msgid "GroupSAML|With prohibit outer forks flag enabled group members will be able to fork project only inside your group."
msgstr ""
@@ -12946,10 +13363,10 @@ msgstr ""
msgid "GroupsNew|Create group"
msgstr ""
-msgid "GroupsNew|GitLab group export"
+msgid "GroupsNew|Import"
msgstr ""
-msgid "GroupsNew|Import"
+msgid "GroupsNew|Import a GitLab group export file"
msgstr ""
msgid "GroupsNew|Import group"
@@ -13096,6 +13513,9 @@ msgstr[3] ""
msgstr[4] ""
msgstr[5] ""
+msgid "Hide comments on this file"
+msgstr ""
+
msgid "Hide details"
msgstr ""
@@ -13144,6 +13564,15 @@ msgstr ""
msgid "Highest role:"
msgstr ""
+msgid "HighlightBar|Alert events:"
+msgstr ""
+
+msgid "HighlightBar|Alert start time:"
+msgstr ""
+
+msgid "HighlightBar|Original alert:"
+msgstr ""
+
msgid "History"
msgstr ""
@@ -13321,6 +13750,9 @@ msgstr ""
msgid "If enabled, access to projects will be validated on an external service using their classification label."
msgstr ""
+msgid "If the number of active users exceeds the user limit, you will be charged for the number of %{users_over_license_link} at your next license reconciliation."
+msgstr ""
+
msgid "If there is no previous license or if the previous license has expired, some GitLab functionality will be blocked until a new, valid license is uploaded."
msgstr ""
@@ -13360,9 +13792,6 @@ msgstr ""
msgid "If your HTTP repository is not publicly accessible, add your credentials."
msgstr ""
-msgid "Iglu registry URL (optional)"
-msgstr ""
-
msgid "Ignore"
msgstr ""
@@ -13399,6 +13828,24 @@ msgstr ""
msgid "Import"
msgstr ""
+msgid "Import %d compatible repository"
+msgid_plural "Import %d compatible repositories"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+msgstr[5] ""
+
+msgid "Import %d repository"
+msgid_plural "Import %d repositories"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+msgstr[5] ""
+
msgid "Import CSV"
msgstr ""
@@ -13408,15 +13855,9 @@ msgstr ""
msgid "Import all compatible projects"
msgstr ""
-msgid "Import all compatible repositories"
-msgstr ""
-
msgid "Import all projects"
msgstr ""
-msgid "Import all repositories"
-msgstr ""
-
msgid "Import an exported GitLab project"
msgstr ""
@@ -13504,6 +13945,9 @@ msgstr ""
msgid "ImportProjects|Error importing repository %{project_safe_import_url} into %{project_full_path} - %{message}"
msgstr ""
+msgid "ImportProjects|Import repositories"
+msgstr ""
+
msgid "ImportProjects|Importing the project failed"
msgstr ""
@@ -13516,7 +13960,7 @@ msgstr ""
msgid "ImportProjects|Requesting your %{provider} repositories failed"
msgstr ""
-msgid "ImportProjects|Select the projects you want to import"
+msgid "ImportProjects|Select the repositories you want to import"
msgstr ""
msgid "ImportProjects|The remote data could not be imported."
@@ -13552,9 +13996,6 @@ msgstr ""
msgid "In order to enable Service Desk for your instance, you must first set up incoming email."
msgstr ""
-msgid "In order to gather accurate feature usage data, it can take 1 to 2 weeks to see your index."
-msgstr ""
-
msgid "In order to personalize your experience with GitLab%{br_tag}we would like to know a bit more about you."
msgstr ""
@@ -13585,18 +14026,30 @@ msgstr ""
msgid "IncidentManagement|Create incident"
msgstr ""
+msgid "IncidentManagement|Critical - S1"
+msgstr ""
+
msgid "IncidentManagement|Date created"
msgstr ""
msgid "IncidentManagement|Display your incidents in a dedicated view"
msgstr ""
+msgid "IncidentManagement|High - S2"
+msgstr ""
+
msgid "IncidentManagement|Incident"
msgstr ""
msgid "IncidentManagement|Incidents"
msgstr ""
+msgid "IncidentManagement|Low - S4"
+msgstr ""
+
+msgid "IncidentManagement|Medium - S3"
+msgstr ""
+
msgid "IncidentManagement|No incidents to display."
msgstr ""
@@ -13609,6 +14062,9 @@ msgstr ""
msgid "IncidentManagement|Published to status page"
msgstr ""
+msgid "IncidentManagement|Severity"
+msgstr ""
+
msgid "IncidentManagement|There are no closed incidents"
msgstr ""
@@ -13618,6 +14074,9 @@ msgstr ""
msgid "IncidentManagement|Unassigned"
msgstr ""
+msgid "IncidentManagement|Unknown"
+msgstr ""
+
msgid "IncidentManagement|Unpublished"
msgstr ""
@@ -13639,6 +14098,15 @@ msgstr ""
msgid "Incidents"
msgstr ""
+msgid "Incident|Alert details"
+msgstr ""
+
+msgid "Incident|Summary"
+msgstr ""
+
+msgid "Incident|There was an issue loading alert data. Please try again."
+msgstr ""
+
msgid "Include a Terms of Service agreement and Privacy Policy that all users must accept."
msgstr ""
@@ -13699,6 +14167,9 @@ msgstr ""
msgid "Information about additional Pages templates and how to install them can be found in our %{pages_getting_started_guide}."
msgstr ""
+msgid "Inherited"
+msgstr ""
+
msgid "Inherited:"
msgstr ""
@@ -13783,7 +14254,22 @@ msgstr ""
msgid "Instance administrators group already exists"
msgstr ""
-msgid "Instance license"
+msgid "InstanceStatistics|Groups"
+msgstr ""
+
+msgid "InstanceStatistics|Issues"
+msgstr ""
+
+msgid "InstanceStatistics|Merge Requests"
+msgstr ""
+
+msgid "InstanceStatistics|Pipelines"
+msgstr ""
+
+msgid "InstanceStatistics|Projects"
+msgstr ""
+
+msgid "InstanceStatistics|Users"
msgstr ""
msgid "Integration"
@@ -13795,6 +14281,12 @@ msgstr ""
msgid "Integrations"
msgstr ""
+msgid "Integrations|%{integration} settings saved and active."
+msgstr ""
+
+msgid "Integrations|%{integration} settings saved, but not active."
+msgstr ""
+
msgid "Integrations|All details"
msgstr ""
@@ -13804,6 +14296,12 @@ msgstr ""
msgid "Integrations|Comment settings:"
msgstr ""
+msgid "Integrations|Connection failed. Please check your settings."
+msgstr ""
+
+msgid "Integrations|Connection successful."
+msgstr ""
+
msgid "Integrations|Default settings are inherited from the group level."
msgstr ""
@@ -13819,6 +14317,15 @@ msgstr ""
msgid "Integrations|Includes commit title and branch"
msgstr ""
+msgid "Integrations|Projects using custom settings will not be impacted unless the project owner chooses to use instance-level defaults."
+msgstr ""
+
+msgid "Integrations|Save settings?"
+msgstr ""
+
+msgid "Integrations|Saving will update the default settings for all projects that are not using custom settings."
+msgstr ""
+
msgid "Integrations|Standard"
msgstr ""
@@ -13951,6 +14458,9 @@ msgstr ""
msgid "Invitation"
msgstr ""
+msgid "Invitation declined"
+msgstr ""
+
msgid "Invite"
msgstr ""
@@ -14002,6 +14512,42 @@ 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|%{linkStart}Read more%{linkEnd} about role permissions"
+msgstr ""
+
+msgid "InviteMembersModal|Access expiration date (optional)"
+msgstr ""
+
+msgid "InviteMembersModal|Cancel"
+msgstr ""
+
+msgid "InviteMembersModal|Choose a role permission"
+msgstr ""
+
+msgid "InviteMembersModal|GitLab member or Email address"
+msgstr ""
+
+msgid "InviteMembersModal|Invite"
+msgstr ""
+
+msgid "InviteMembersModal|Invite team members"
+msgstr ""
+
+msgid "InviteMembersModal|Search for members to invite"
+msgstr ""
+
+msgid "InviteMembersModal|User not invited. Feature coming soon!"
+msgstr ""
+
+msgid "InviteMembersModal|Users were succesfully added"
+msgstr ""
+
+msgid "InviteMembersModal|You're inviting members to the %{group_name} group"
+msgstr ""
+
+msgid "InviteMembers|Invite team members"
+msgstr ""
+
msgid "Invited"
msgstr ""
@@ -14056,10 +14602,13 @@ msgstr ""
msgid "Issue cannot be found."
msgstr ""
+msgid "Issue created from vulnerability %{vulnerability_link}"
+msgstr ""
+
msgid "Issue events"
msgstr ""
-msgid "Issue first depoloyed to production"
+msgid "Issue first deployed to production"
msgstr ""
msgid "Issue label"
@@ -14137,6 +14686,9 @@ msgstr ""
msgid "IssueTracker|Custom issue tracker"
msgstr ""
+msgid "IssueTracker|EWM work items tracker"
+msgstr ""
+
msgid "IssueTracker|Redmine issue tracker"
msgstr ""
@@ -14203,6 +14755,9 @@ msgstr ""
msgid "It looks like you have some draft commits in this branch."
msgstr ""
+msgid "It may be several days before you see feature usage data."
+msgstr ""
+
msgid "It must have a header row and at least two columns: the first column is the issue title and the second column is the issue description. The separator is automatically detected."
msgstr ""
@@ -14485,13 +15040,13 @@ msgstr ""
msgid "Join Zoom meeting"
msgstr ""
-msgid "Jul"
+msgid "Joined %{time_ago}"
msgstr ""
-msgid "July"
+msgid "Jul"
msgstr ""
-msgid "Jump to first unresolved thread"
+msgid "July"
msgstr ""
msgid "Jump to next unresolved thread"
@@ -14527,6 +15082,9 @@ msgstr ""
msgid "Keyboard shortcuts"
msgstr ""
+msgid "KeyboardKey|Ctrl+"
+msgstr ""
+
msgid "Keys"
msgstr ""
@@ -14575,6 +15133,9 @@ msgstr ""
msgid "LDAP Synchronization"
msgstr ""
+msgid "LDAP group settings"
+msgstr ""
+
msgid "LDAP settings"
msgstr ""
@@ -14584,6 +15145,9 @@ msgstr ""
msgid "LDAP sync in progress. This could take a few minutes. Refresh the page to see the changes."
msgstr ""
+msgid "LDAP synchronizations"
+msgstr ""
+
msgid "LFS"
msgstr ""
@@ -14668,7 +15232,16 @@ msgstr[3] ""
msgstr[4] ""
msgstr[5] ""
-msgid "Last %{days} days"
+msgid "Last 2 weeks"
+msgstr ""
+
+msgid "Last 30 days"
+msgstr ""
+
+msgid "Last 60 days"
+msgstr ""
+
+msgid "Last 90 days"
msgstr ""
msgid "Last Accessed On"
@@ -14746,6 +15319,9 @@ msgstr ""
msgid "Last used on:"
msgstr ""
+msgid "Last week"
+msgstr ""
+
msgid "LastCommit|authored"
msgstr ""
@@ -14761,6 +15337,9 @@ msgstr ""
msgid "Latest pipeline for the most recent commit on this branch"
msgstr ""
+msgid "Launch a ready-to-code development environment for your project."
+msgstr ""
+
msgid "Lead"
msgstr ""
@@ -15169,6 +15748,9 @@ msgstr ""
msgid "List of all merge commits"
msgstr ""
+msgid "List options"
+msgstr ""
+
msgid "List settings"
msgstr ""
@@ -15181,9 +15763,6 @@ msgstr ""
msgid "List your Bitbucket Server repositories"
msgstr ""
-msgid "Lists"
-msgstr ""
-
msgid "Live preview"
msgstr ""
@@ -15430,6 +16009,12 @@ msgstr ""
msgid "Mark as done"
msgstr ""
+msgid "Mark as draft"
+msgstr ""
+
+msgid "Mark as ready"
+msgstr ""
+
msgid "Mark as resolved"
msgstr ""
@@ -15451,6 +16036,24 @@ msgstr ""
msgid "Markdown is supported"
msgstr ""
+msgid "MarkdownEditor|Add a link (%{modifierKey}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add a link (%{modifier_key}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifierKey}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifier_key}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifierKey}I)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifier_key}I)"
+msgstr ""
+
msgid "Marked For Deletion At - %{deletion_time}"
msgstr ""
@@ -15535,7 +16138,25 @@ msgstr ""
msgid "Max access level"
msgstr ""
-msgid "Max seats used"
+msgid "Max role"
+msgstr ""
+
+msgid "Max size 15 MB"
+msgstr ""
+
+msgid "Maximum Conan package file size in bytes"
+msgstr ""
+
+msgid "Maximum Maven package file size in bytes"
+msgstr ""
+
+msgid "Maximum NPM package file size in bytes"
+msgstr ""
+
+msgid "Maximum NuGet package file size in bytes"
+msgstr ""
+
+msgid "Maximum PyPI package file size in bytes"
msgstr ""
msgid "Maximum Users:"
@@ -15667,6 +16288,18 @@ msgstr ""
msgid "Members with access to %{strong_start}%{group_name}%{strong_end}"
msgstr ""
+msgid "Members|%{time} by %{user}"
+msgstr ""
+
+msgid "Members|Expired"
+msgstr ""
+
+msgid "Members|No expiration set"
+msgstr ""
+
+msgid "Members|in %{time}"
+msgstr ""
+
msgid "Memory Usage"
msgstr ""
@@ -15853,9 +16486,6 @@ msgstr ""
msgid "MergeRequests|Thread will be unresolved"
msgstr ""
-msgid "MergeRequests|Toggle comments for this file"
-msgstr ""
-
msgid "MergeRequests|View file @ %{commitId}"
msgstr ""
@@ -15916,6 +16546,9 @@ msgstr ""
msgid "Merging immediately isn't recommended as it may negatively impact the existing merge train. Read the %{docsLinkStart}documentation%{docsLinkEnd} for more information."
msgstr ""
+msgid "Message"
+msgstr ""
+
msgid "Messages"
msgstr ""
@@ -16309,18 +16942,12 @@ msgstr[3] ""
msgstr[4] ""
msgstr[5] ""
-msgid "Milestone does not support burnup charts"
-msgstr ""
-
msgid "Milestone lists not available with your current license"
msgstr ""
msgid "Milestone lists show all issues from the selected milestone."
msgstr ""
-msgid "Milestone must have a start and due date"
-msgstr ""
-
msgid "MilestoneSidebar|Closed:"
msgstr ""
@@ -16687,6 +17314,9 @@ msgstr ""
msgid "Namespace"
msgstr ""
+msgid "Namespace ID:"
+msgstr ""
+
msgid "Namespace is empty"
msgstr ""
@@ -16771,6 +17401,9 @@ msgstr ""
msgid "NetworkPolicies|Allow all outbound traffic from %{selector} to %{ruleSelector} on %{ports}"
msgstr ""
+msgid "NetworkPolicies|Are you sure you want to delete this policy? This action cannot be undone."
+msgstr ""
+
msgid "NetworkPolicies|Choose whether to enforce this policy."
msgstr ""
@@ -16780,12 +17413,21 @@ msgstr ""
msgid "NetworkPolicies|Define this policy's location, conditions and actions."
msgstr ""
+msgid "NetworkPolicies|Delete policy"
+msgstr ""
+
+msgid "NetworkPolicies|Delete policy: %{policy}"
+msgstr ""
+
msgid "NetworkPolicies|Deny all traffic"
msgstr ""
msgid "NetworkPolicies|Description"
msgstr ""
+msgid "NetworkPolicies|Edit policy"
+msgstr ""
+
msgid "NetworkPolicies|Editor mode"
msgstr ""
@@ -16813,6 +17455,9 @@ msgstr ""
msgid "NetworkPolicies|Name"
msgstr ""
+msgid "NetworkPolicies|Namespace"
+msgstr ""
+
msgid "NetworkPolicies|Network Policy"
msgstr ""
@@ -16864,6 +17509,9 @@ msgstr ""
msgid "NetworkPolicies|Rules"
msgstr ""
+msgid "NetworkPolicies|Save changes"
+msgstr ""
+
msgid "NetworkPolicies|Something went wrong, failed to update policy"
msgstr ""
@@ -16876,6 +17524,9 @@ msgstr ""
msgid "NetworkPolicies|Traffic that does not match any rule will be blocked."
msgstr ""
+msgid "NetworkPolicies|Unable to parse policy"
+msgstr ""
+
msgid "NetworkPolicies|YAML editor"
msgstr ""
@@ -16993,6 +17644,9 @@ msgstr ""
msgid "New Snippet"
msgstr ""
+msgid "New Test Case"
+msgstr ""
+
msgid "New User"
msgstr ""
@@ -17092,6 +17746,9 @@ msgstr ""
msgid "New tag"
msgstr ""
+msgid "New test case"
+msgstr ""
+
msgid "New users set to external"
msgstr ""
@@ -17164,7 +17821,7 @@ msgstr ""
msgid "No changes"
msgstr ""
-msgid "No changes between %{ref_start}%{source_branch}%{ref_end} and %{ref_start}%{target_branch}%{ref_end}"
+msgid "No changes between %{sourceBranch} and %{targetBranch}"
msgstr ""
msgid "No child epics match applied filters"
@@ -17179,6 +17836,9 @@ msgstr ""
msgid "No containers available"
msgstr ""
+msgid "No content to show"
+msgstr ""
+
msgid "No contributions"
msgstr ""
@@ -17254,9 +17914,6 @@ msgstr ""
msgid "No license. All rights reserved"
msgstr ""
-msgid "No licenses found."
-msgstr ""
-
msgid "No matches found"
msgstr ""
@@ -17269,6 +17926,9 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No members found"
+msgstr ""
+
msgid "No merge requests found"
msgstr ""
@@ -17290,6 +17950,9 @@ msgstr ""
msgid "No parent group"
msgstr ""
+msgid "No plan"
+msgstr ""
+
msgid "No pods available"
msgstr ""
@@ -17386,6 +18049,12 @@ msgstr ""
msgid "Not Implemented"
msgstr ""
+msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+msgstr ""
+
+msgid "Not all browsers support WebAuthn. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even from an unsupported browser."
+msgstr ""
+
msgid "Not all data has been processed yet, the accuracy of the chart for the selected timeframe is limited."
msgstr ""
@@ -17482,6 +18151,9 @@ msgstr ""
msgid "Notification settings saved"
msgstr ""
+msgid "NotificationEvent|Change reviewer merge request"
+msgstr ""
+
msgid "NotificationEvent|Close issue"
msgstr ""
@@ -17644,10 +18316,7 @@ msgstr ""
msgid "On track"
msgstr ""
-msgid "OnDemandScans|Attached branch"
-msgstr ""
-
-msgid "OnDemandScans|Attached branch is where the scan job runs."
+msgid "OnDemandScans|Could not fetch scanner profiles. Please refresh the page, or try again later."
msgstr ""
msgid "OnDemandScans|Could not fetch site profiles. Please refresh the page, or try again later."
@@ -17656,6 +18325,9 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
+msgid "OnDemandScans|Create a new scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Create a new site profile"
msgstr ""
@@ -17668,6 +18340,9 @@ msgstr ""
msgid "OnDemandScans|New on-demand DAST scan"
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 ""
@@ -17677,16 +18352,10 @@ msgstr ""
msgid "OnDemandScans|On-demand scans run outside the DevOps cycle and find vulnerabilities in your projects. %{learnMoreLinkStart}Learn more%{learnMoreLinkEnd}"
msgstr ""
-msgid "OnDemandScans|Only a passive scan can be performed on demand."
-msgstr ""
-
-msgid "OnDemandScans|Passive"
-msgstr ""
-
msgid "OnDemandScans|Run scan"
msgstr ""
-msgid "OnDemandScans|Scan mode"
+msgid "OnDemandScans|Scanner profile"
msgstr ""
msgid "OnDemandScans|Scanner settings"
@@ -17698,9 +18367,15 @@ msgstr ""
msgid "OnDemandScans|Select one of the existing profiles"
msgstr ""
+msgid "OnDemandScans|Site profile"
+msgstr ""
+
msgid "OnDemandScans|Site profiles"
msgstr ""
+msgid "OnDemandScans|Use existing scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Use existing site profile"
msgstr ""
@@ -17803,9 +18478,6 @@ msgstr ""
msgid "Open Selection"
msgstr ""
-msgid "Open Web IDE"
-msgstr ""
-
msgid "Open comment type dropdown"
msgstr ""
@@ -17911,6 +18583,9 @@ msgstr ""
msgid "Origin"
msgstr ""
+msgid "Orphaned member"
+msgstr ""
+
msgid "Other Labels"
msgstr ""
@@ -17926,6 +18601,9 @@ msgstr ""
msgid "Other visibility settings have been disabled by the administrator."
msgstr ""
+msgid "Our documentation includes an example DevOps Score report."
+msgstr ""
+
msgid "Out-of-compliance with this project's policies and should be removed"
msgstr ""
@@ -17950,6 +18628,9 @@ msgstr ""
msgid "Overwrite diverged branches"
msgstr ""
+msgid "Owned by %{image_tag}"
+msgstr ""
+
msgid "Owned by anyone"
msgstr ""
@@ -17971,6 +18652,9 @@ msgstr ""
msgid "Package deleted successfully"
msgstr ""
+msgid "Package file size limits"
+msgstr ""
+
msgid "Package recipe already exists"
msgstr ""
@@ -17986,9 +18670,6 @@ msgstr ""
msgid "Package type must be PyPi"
msgstr ""
-msgid "Package was removed"
-msgstr ""
-
msgid "PackageRegistry|%{name} version %{version} was created %{datetime}"
msgstr ""
@@ -18130,12 +18811,18 @@ msgstr ""
msgid "PackageRegistry|NuGet Command"
msgstr ""
+msgid "PackageRegistry|Package Registry"
+msgstr ""
+
msgid "PackageRegistry|Pip Command"
msgstr ""
msgid "PackageRegistry|Pipeline %{link} triggered %{datetime} by %{author}"
msgstr ""
+msgid "PackageRegistry|Publish and share packages for a variety of common package managers. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "PackageRegistry|Published to the %{project} Package Registry %{datetime}"
msgstr ""
@@ -18235,6 +18922,9 @@ msgstr ""
msgid "Page not found"
msgstr ""
+msgid "Page settings"
+msgstr ""
+
msgid "Page was successfully deleted"
msgstr ""
@@ -18376,7 +19066,7 @@ msgstr ""
msgid "Paste issue link"
msgstr ""
-msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Don't use your private SSH key."
+msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Do not paste your private SSH key, as that can compromise your identity."
msgstr ""
msgid "Patch to apply"
@@ -18403,6 +19093,9 @@ msgstr ""
msgid "Pending"
msgstr ""
+msgid "Pending comments"
+msgstr ""
+
msgid "People without permission will never get a notification and won't be able to comment."
msgstr ""
@@ -18601,6 +19294,9 @@ msgstr ""
msgid "Pipelines|Build with confidence"
msgstr ""
+msgid "Pipelines|By revoking a trigger you will break any processes making use of it. Are you sure?"
+msgstr ""
+
msgid "Pipelines|CI Lint"
msgstr ""
@@ -18613,6 +19309,15 @@ msgstr ""
msgid "Pipelines|Continuous Integration can help catch bugs by running your tests automatically, while Continuous Deployment can help you deliver code to your product environment."
msgstr ""
+msgid "Pipelines|Copy trigger token"
+msgstr ""
+
+msgid "Pipelines|Description"
+msgstr ""
+
+msgid "Pipelines|Edit"
+msgstr ""
+
msgid "Pipelines|Get started with Pipelines"
msgstr ""
@@ -18628,15 +19333,27 @@ msgstr ""
msgid "Pipelines|It is recommended the code is reviewed thoroughly before running this pipeline with the parent project's CI resource."
msgstr ""
+msgid "Pipelines|Last Used"
+msgstr ""
+
msgid "Pipelines|Loading Pipelines"
msgstr ""
msgid "Pipelines|More Information"
msgstr ""
+msgid "Pipelines|No triggers have been created yet. Add one using the form above."
+msgstr ""
+
+msgid "Pipelines|Owner"
+msgstr ""
+
msgid "Pipelines|Project cache successfully reset."
msgstr ""
+msgid "Pipelines|Revoke"
+msgstr ""
+
msgid "Pipelines|Run Pipeline"
msgstr ""
@@ -18661,6 +19378,15 @@ msgstr ""
msgid "Pipelines|This project is not currently set up to run pipelines."
msgstr ""
+msgid "Pipelines|Token"
+msgstr ""
+
+msgid "Pipelines|Trigger user has insufficient permissions to project"
+msgstr ""
+
+msgid "Pipelines|invalid"
+msgstr ""
+
msgid "Pipelines|parent"
msgstr ""
@@ -18919,10 +19645,10 @@ msgstr ""
msgid "Please provide attributes to update"
msgstr ""
-msgid "Please refer to %{docs_url}"
+msgid "Please reach out if you have any questions and we'll be happy to assist."
msgstr ""
-msgid "Please retype the email address."
+msgid "Please refer to %{docs_url}"
msgstr ""
msgid "Please select"
@@ -18952,6 +19678,9 @@ msgstr ""
msgid "Please set a new password before proceeding."
msgstr ""
+msgid "Please share your feedback about %{featureName} %{linkStart}in this issue%{linkEnd} to help us improve the experience."
+msgstr ""
+
msgid "Please solve the reCAPTCHA"
msgstr ""
@@ -19255,6 +19984,9 @@ msgstr ""
msgid "Profiles| You are going to change the username %{currentUsernameBold} to %{newUsernameBold}. Profile and projects will be redirected to the %{newUsername} namespace but this redirect will expire once the %{currentUsername} namespace is registered by another user or group. Please update your Git repository remotes as soon as possible."
msgstr ""
+msgid "Profiles|%{provider} Active"
+msgstr ""
+
msgid "Profiles|@username"
msgstr ""
@@ -19306,7 +20038,7 @@ msgstr ""
msgid "Profiles|Commit email"
msgstr ""
-msgid "Profiles|Connect"
+msgid "Profiles|Connect %{provider}"
msgstr ""
msgid "Profiles|Connected Accounts"
@@ -19330,6 +20062,9 @@ msgstr ""
msgid "Profiles|Disconnect"
msgstr ""
+msgid "Profiles|Disconnect %{provider}"
+msgstr ""
+
msgid "Profiles|Do not show on profile"
msgstr ""
@@ -19354,7 +20089,7 @@ msgstr ""
msgid "Profiles|Full name"
msgstr ""
-msgid "Profiles|Give your individual key a title. This will be publically visible."
+msgid "Profiles|Give your individual key a title."
msgstr ""
msgid "Profiles|Include private contributions on my profile"
@@ -19444,7 +20179,7 @@ msgstr ""
msgid "Profiles|The maximum file size allowed is 200KB."
msgstr ""
-msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it?"
+msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it? It will be publicly visible."
msgstr ""
msgid "Profiles|This email will be displayed on your public profile"
@@ -19519,6 +20254,9 @@ msgstr ""
msgid "Profiles|You don't have access to delete this user."
msgstr ""
+msgid "Profiles|You must transfer ownership or delete groups you are an owner of before you can delete your account"
+msgstr ""
+
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
@@ -20107,6 +20845,9 @@ msgstr ""
msgid "ProjectTemplates|GitLab Cluster Management"
msgstr ""
+msgid "ProjectTemplates|Gitpod/Spring Petclinic"
+msgstr ""
+
msgid "ProjectTemplates|Go Micro"
msgstr ""
@@ -20716,6 +21457,9 @@ msgstr ""
msgid "Publish to status page"
msgstr ""
+msgid "Published"
+msgstr ""
+
msgid "Published on status page"
msgstr ""
@@ -20833,9 +21577,15 @@ msgstr ""
msgid "Quick range"
msgstr ""
+msgid "Quickly and easily edit multiple files in your project."
+msgstr ""
+
msgid "README"
msgstr ""
+msgid "Rails"
+msgstr ""
+
msgid "Rake Tasks Help"
msgstr ""
@@ -20959,10 +21709,13 @@ msgstr ""
msgid "Register Two-Factor Authenticator"
msgstr ""
-msgid "Register U2F device"
+msgid "Register Universal Two-Factor (U2F) Device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register WebAuthn Device"
+msgstr ""
+
+msgid "Register device"
msgstr ""
msgid "Register for GitLab"
@@ -20974,9 +21727,6 @@ msgstr ""
msgid "Register with two-factor app"
msgstr ""
-msgid "Registration"
-msgstr ""
-
msgid "Registration|Checkout"
msgstr ""
@@ -21097,9 +21847,6 @@ msgstr ""
msgid "Release|Something went wrong while saving the release details"
msgstr ""
-msgid "Remediated: needs review"
-msgstr ""
-
msgid "Remediations"
msgstr ""
@@ -21205,6 +21952,9 @@ msgstr ""
msgid "Remove priority"
msgstr ""
+msgid "Remove report"
+msgstr ""
+
msgid "Remove secondary node"
msgstr ""
@@ -21217,6 +21967,12 @@ msgstr ""
msgid "Remove time estimate"
msgstr ""
+msgid "Remove user & report"
+msgstr ""
+
+msgid "Remove user from group"
+msgstr ""
+
msgid "Removed"
msgstr ""
@@ -21298,9 +22054,6 @@ msgstr ""
msgid "Removes time estimate."
msgstr ""
-msgid "Removing license…"
-msgstr ""
-
msgid "Removing this group also removes all child projects, including archived projects, and their resources."
msgstr ""
@@ -21385,6 +22138,9 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
+msgid "Reported by %{reporter}"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -21475,6 +22231,27 @@ msgstr ""
msgid "Repositories"
msgstr ""
+msgid "Repositories Analytics"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download Historic Test Coverage Data"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download historic test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Historic Test Coverage Data is available in raw format (.csv) for further analysis."
+msgstr ""
+
+msgid "RepositoriesAnalytics|Test Code Coverage"
+msgstr ""
+
+msgid "RepositoriesAnalytics|There was an error fetching the projects."
+msgstr ""
+
msgid "Repository"
msgstr ""
@@ -21553,9 +22330,15 @@ msgstr ""
msgid "Request parameter %{param} is missing."
msgstr ""
+msgid "Request review from"
+msgstr ""
+
msgid "Request to link SAML account must be authorized"
msgstr ""
+msgid "Requested"
+msgstr ""
+
msgid "Requested %{time_ago}"
msgstr ""
@@ -21574,6 +22357,9 @@ msgstr ""
msgid "Requests to these domain(s)/address(es) on the local network will be allowed when local requests from hooks and services are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 or 127.0.0.0/28 are supported. Domain wildcards are not supported currently. Use comma, semicolon, or newline to separate multiple entries. The allowlist can hold a maximum of 1000 entries. Domains should use IDNA encoding. Ex: example.com, 192.168.1.1, 127.0.0.0/28, xn--itlab-j1a.com."
msgstr ""
+msgid "Require admin approval for new sign-ups"
+msgstr ""
+
msgid "Require all users in this group to setup Two-factor authentication"
msgstr ""
@@ -21709,9 +22495,6 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
-msgid "Resolved by %{resolvedByName}"
-msgstr ""
-
msgid "Resolves IP addresses once and uses them to submit requests"
msgstr ""
@@ -21835,6 +22618,18 @@ msgstr ""
msgid "ReviewApp|Enable Review App"
msgstr ""
+msgid "Reviewer"
+msgid_plural "%d Reviewers"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+msgstr[5] ""
+
+msgid "Reviewer(s)"
+msgstr ""
+
msgid "Reviewing"
msgstr ""
@@ -21874,6 +22669,9 @@ msgstr ""
msgid "Rook"
msgstr ""
+msgid "Ruby"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -21952,6 +22750,63 @@ msgstr ""
msgid "Runners page."
msgstr ""
+msgid "Runners|Active"
+msgstr ""
+
+msgid "Runners|Architecture"
+msgstr ""
+
+msgid "Runners|Can run untagged jobs"
+msgstr ""
+
+msgid "Runners|Description"
+msgstr ""
+
+msgid "Runners|Group"
+msgstr ""
+
+msgid "Runners|IP Address"
+msgstr ""
+
+msgid "Runners|Last contact"
+msgstr ""
+
+msgid "Runners|Locked to this project"
+msgstr ""
+
+msgid "Runners|Maximum job timeout"
+msgstr ""
+
+msgid "Runners|Name"
+msgstr ""
+
+msgid "Runners|Platform"
+msgstr ""
+
+msgid "Runners|Property Name"
+msgstr ""
+
+msgid "Runners|Protected"
+msgstr ""
+
+msgid "Runners|Revision"
+msgstr ""
+
+msgid "Runners|Shared"
+msgstr ""
+
+msgid "Runners|Specific"
+msgstr ""
+
+msgid "Runners|Tags"
+msgstr ""
+
+msgid "Runners|Value"
+msgstr ""
+
+msgid "Runners|Version"
+msgstr ""
+
msgid "Runners|You have used %{quotaUsed} out of %{quotaLimit} of your shared Runners pipeline minutes."
msgstr ""
@@ -21964,6 +22819,9 @@ msgstr ""
msgid "Runs a number of housekeeping tasks within the current repository, such as compressing file revisions and removing unreachable objects."
msgstr ""
+msgid "SAML"
+msgstr ""
+
msgid "SAML SSO"
msgstr ""
@@ -22015,6 +22873,9 @@ msgstr ""
msgid "Save"
msgstr ""
+msgid "Save %{name} size limits"
+msgstr ""
+
msgid "Save Changes"
msgstr ""
@@ -22045,9 +22906,6 @@ msgstr ""
msgid "Save space and find tags in the Container Registry more easily. Enable the cleanup policy to remove stale tags and keep only the ones you need."
msgstr ""
-msgid "Save template"
-msgstr ""
-
msgid "Save variables"
msgstr ""
@@ -22090,9 +22948,6 @@ msgstr ""
msgid "Scope"
msgstr ""
-msgid "Scope not supported with disabled 'users_search' feature!"
-msgstr ""
-
msgid "Scoped issue boards"
msgstr ""
@@ -22219,9 +23074,6 @@ msgstr ""
msgid "Search requirements"
msgstr ""
-msgid "Search results…"
-msgstr ""
-
msgid "Search users"
msgstr ""
@@ -22306,6 +23158,15 @@ msgstr[3] ""
msgstr[4] ""
msgstr[5] ""
+msgid "SearchResults|epic"
+msgid_plural "SearchResults|epics"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+msgstr[5] ""
+
msgid "SearchResults|issue"
msgid_plural "SearchResults|issues"
msgstr[0] ""
@@ -22378,10 +23239,10 @@ msgstr ""
msgid "Seat Link is disabled, and cannot be configured through this form."
msgstr ""
-msgid "Seats currently in use"
+msgid "Seats usage data as of %{last_enqueue_time}"
msgstr ""
-msgid "Seats in license"
+msgid "Seats usage data is updated every day at 12:00pm UTC"
msgstr ""
msgid "Secondary"
@@ -22435,6 +23296,9 @@ msgstr ""
msgid "SecurityConfiguration|Available for on-demand DAST"
msgstr ""
+msgid "SecurityConfiguration|By default, all analyzers are applied in order to cover all languages across your project, and only run if the language is detected in the Merge Request."
+msgstr ""
+
msgid "SecurityConfiguration|Configure"
msgstr ""
@@ -22465,16 +23329,19 @@ msgstr ""
msgid "SecurityConfiguration|Manage"
msgstr ""
+msgid "SecurityConfiguration|More information"
+msgstr ""
+
msgid "SecurityConfiguration|Not enabled"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|Security Control"
+msgid "SecurityConfiguration|SAST Configuration"
msgstr ""
-msgid "SecurityConfiguration|See documentation"
+msgid "SecurityConfiguration|Security Control"
msgstr ""
msgid "SecurityConfiguration|Status"
@@ -22486,6 +23353,9 @@ msgstr ""
msgid "SecurityConfiguration|Using custom settings. You won't receive automatic updates on this variable. %{anchorStart}Restore to default%{anchorEnd}"
msgstr ""
+msgid "SecurityConfiguration|View history"
+msgstr ""
+
msgid "SecurityConfiguration|You can quickly enable all security scanning tools by enabling %{linkStart}Auto DevOps%{linkEnd}."
msgstr ""
@@ -22564,9 +23434,6 @@ msgstr ""
msgid "SecurityReports|Learn more about setting up your dashboard"
msgstr ""
-msgid "SecurityReports|Load more vulnerabilities"
-msgstr ""
-
msgid "SecurityReports|Monitor vulnerabilities in your code"
msgstr ""
@@ -22846,7 +23713,7 @@ msgstr ""
msgid "Select status"
msgstr ""
-msgid "Select strategy activation method"
+msgid "Select strategy activation method."
msgstr ""
msgid "Select subscription"
@@ -22861,7 +23728,7 @@ msgstr ""
msgid "Select the custom project template source group."
msgstr ""
-msgid "Select timeframe"
+msgid "Select the environment scope for this feature flag."
msgstr ""
msgid "Select timezone"
@@ -23110,6 +23977,9 @@ msgstr ""
msgid "Set iteration"
msgstr ""
+msgid "Set limit to 0 to allow any file size."
+msgstr ""
+
msgid "Set max session time for web terminal."
msgstr ""
@@ -23188,10 +24058,13 @@ msgstr ""
msgid "Set up a %{type} Runner manually"
msgstr ""
+msgid "Set up a hardware device as a second factor to sign in."
+msgstr ""
+
msgid "Set up assertions/attributes/claims (email, first_name, last_name) and NameID according to %{docsLinkStart}the documentation %{icon}%{docsLinkEnd}"
msgstr ""
-msgid "Set up new U2F device"
+msgid "Set up new device"
msgstr ""
msgid "Set up new password"
@@ -23260,6 +24133,9 @@ msgstr ""
msgid "Sets weight to %{weight}."
msgstr ""
+msgid "Setting this to 0 means using the system default timeout value."
+msgstr ""
+
msgid "Settings"
msgstr ""
@@ -23275,6 +24151,15 @@ msgstr ""
msgid "Severity"
msgstr ""
+msgid "SeverityWidget|Severity"
+msgstr ""
+
+msgid "SeverityWidget|Severity: %{severity}"
+msgstr ""
+
+msgid "SeverityWidget|There was an error while updating severity."
+msgstr ""
+
msgid "Shards (%{shards})"
msgstr ""
@@ -23320,6 +24205,9 @@ msgstr ""
msgid "Show all requirements."
msgstr ""
+msgid "Show all test cases."
+msgstr ""
+
msgid "Show archived projects"
msgstr ""
@@ -23332,6 +24220,9 @@ msgstr ""
msgid "Show comments"
msgstr ""
+msgid "Show comments on this file"
+msgstr ""
+
msgid "Show comments only"
msgstr ""
@@ -23377,6 +24268,12 @@ msgstr ""
msgid "Show parent subgroups"
msgstr ""
+msgid "Show the Closed list"
+msgstr ""
+
+msgid "Show the Open list"
+msgstr ""
+
msgid "Show whitespace changes"
msgstr ""
@@ -23428,9 +24325,6 @@ msgstr ""
msgid "Sidebar|Assign health status"
msgstr ""
-msgid "Sidebar|Change weight"
-msgstr ""
-
msgid "Sidebar|Health status"
msgstr ""
@@ -23614,6 +24508,9 @@ msgstr ""
msgid "Snippets|Add another file %{num}/%{total}"
msgstr ""
+msgid "Snippets|Authored %{time_ago} by %{author}"
+msgstr ""
+
msgid "Snippets|Delete file"
msgstr ""
@@ -23641,6 +24538,9 @@ msgstr ""
msgid "Solution"
msgstr ""
+msgid "Some changes are not shown"
+msgstr ""
+
msgid "Some child epics may be hidden due to applied filters"
msgstr ""
@@ -24007,6 +24907,12 @@ msgstr ""
msgid "Source (branch or tag)"
msgstr ""
+msgid "Source Branch"
+msgstr ""
+
+msgid "Source branch: %{source_branch_open}%{source_branch}%{source_branch_close}"
+msgstr ""
+
msgid "Source code"
msgstr ""
@@ -24172,9 +25078,6 @@ msgstr ""
msgid "Start and due date"
msgstr ""
-msgid "Start by choosing a group to see how your team is spending time. You can then drill down to the project level."
-msgstr ""
-
msgid "Start by choosing a group to start exploring the merge requests in that group. You can then proceed to filter by projects, labels, milestones and authors."
msgstr ""
@@ -24256,18 +25159,27 @@ msgstr ""
msgid "StaticSiteEditor|3. Assign a person to review and accept the merge request."
msgstr ""
+msgid "StaticSiteEditor|A link to view the merge request will appear once ready."
+msgstr ""
+
msgid "StaticSiteEditor|An error occurred while submitting your changes."
msgstr ""
msgid "StaticSiteEditor|Branch could not be created."
msgstr ""
+msgid "StaticSiteEditor|Copy update"
+msgstr ""
+
msgid "StaticSiteEditor|Could not commit the content changes."
msgstr ""
msgid "StaticSiteEditor|Could not create merge request."
msgstr ""
+msgid "StaticSiteEditor|Creating your merge request"
+msgstr ""
+
msgid "StaticSiteEditor|Incompatible file content"
msgstr ""
@@ -24289,6 +25201,9 @@ msgstr ""
msgid "StaticSiteEditor|View documentation"
msgstr ""
+msgid "StaticSiteEditor|You can set an assignee to get your changes reviewed and deployed once your merge request is created."
+msgstr ""
+
msgid "StaticSiteEditor|Your merge request has been created"
msgstr ""
@@ -24418,15 +25333,15 @@ msgstr ""
msgid "Submit %{humanized_resource_name}"
msgstr ""
-msgid "Submit Changes"
-msgstr ""
-
msgid "Submit a review"
msgstr ""
msgid "Submit as spam"
msgstr ""
+msgid "Submit changes"
+msgstr ""
+
msgid "Submit feedback"
msgstr ""
@@ -24580,6 +25495,9 @@ msgstr ""
msgid "Successfully deleted U2F device."
msgstr ""
+msgid "Successfully deleted WebAuthn device."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -24898,9 +25816,6 @@ msgstr ""
msgid "Template to append to all Service Desk issues"
msgstr ""
-msgid "Template was successfully saved."
-msgstr ""
-
msgid "Templates"
msgstr ""
@@ -24991,10 +25906,28 @@ msgstr[3] ""
msgstr[4] ""
msgstr[5] ""
-msgid "Test failed."
+msgid "Test settings"
+msgstr ""
+
+msgid "TestCases|New Test Case"
+msgstr ""
+
+msgid "TestCases|New test case"
+msgstr ""
+
+msgid "TestCases|Search test cases"
+msgstr ""
+
+msgid "TestCases|Something went wrong while creating a test case."
msgstr ""
-msgid "Test settings and save changes"
+msgid "TestCases|Something went wrong while fetching count of test cases."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching test cases list."
+msgstr ""
+
+msgid "TestCases|Submit test case"
msgstr ""
msgid "TestHooks|Ensure one of your projects has merge requests."
@@ -25060,6 +25993,9 @@ msgstr ""
msgid "Thank you for signing up for your free trial! You will get additional instructions in your inbox shortly."
msgstr ""
+msgid "Thank you for your business."
+msgstr ""
+
msgid "Thank you for your feedback!"
msgstr ""
@@ -25123,9 +26059,6 @@ msgstr ""
msgid "The URL to use for connecting to Elasticsearch. Use a comma-separated list to support clustering (e.g., \"http://localhost:9200, http://localhost:9201\")."
msgstr ""
-msgid "The Web IDE offers advanced syntax highlighting capabilities and more."
-msgstr ""
-
msgid "The X509 Certificate to use when mutual TLS is required to communicate with the external authorization service. If left blank, the server certificate is still validated when accessing over HTTPS."
msgstr ""
@@ -25240,6 +26173,9 @@ msgstr ""
msgid "The form contains the following error:"
msgstr ""
+msgid "The form contains the following warning:"
+msgstr ""
+
msgid "The global settings require you to enable Two-Factor Authentication for your account."
msgstr ""
@@ -25354,9 +26290,6 @@ msgstr ""
msgid "The private key to use when a client certificate is provided. This value is encrypted at rest."
msgstr ""
-msgid "The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The project can be accessed by any logged in user."
msgstr ""
@@ -25393,7 +26326,7 @@ msgstr ""
msgid "The remote repository is being updated..."
msgstr ""
-msgid "The repository can be commited to, and issues, comments and other entities can be created."
+msgid "The repository can be committed to, and issues, comments and other entities can be created."
msgstr ""
msgid "The repository for this project does not exist."
@@ -25447,9 +26380,6 @@ msgstr ""
msgid "The time taken by each data entry gathered by that stage."
msgstr ""
-msgid "The total stage shows the time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The update action will time out after %{number_of_minutes} minutes. For big repositories, use a clone/push combination."
msgstr ""
@@ -25513,6 +26443,9 @@ msgstr ""
msgid "There are no archived requirements"
msgstr ""
+msgid "There are no archived test cases"
+msgstr ""
+
msgid "There are no changes"
msgstr ""
@@ -25552,6 +26485,9 @@ msgstr ""
msgid "There are no open requirements"
msgstr ""
+msgid "There are no open test cases"
+msgstr ""
+
msgid "There are no packages yet"
msgstr ""
@@ -25564,6 +26500,9 @@ msgstr ""
msgid "There is a limit of %{ci_project_subscriptions_limit} subscriptions from or to a project."
msgstr ""
+msgid "There is already a To-Do for this design."
+msgstr ""
+
msgid "There is already a repository with that name on disk"
msgstr ""
@@ -25582,6 +26521,9 @@ msgstr ""
msgid "There was a problem communicating with your device."
msgstr ""
+msgid "There was a problem fetching branches."
+msgstr ""
+
msgid "There was a problem fetching groups."
msgstr ""
@@ -25810,9 +26752,15 @@ msgstr ""
msgid "This action can lead to data loss. To prevent accidental actions we ask you to confirm your intention."
msgstr ""
+msgid "This action cannot be undone, and will permanently delete the %{key} SSH key"
+msgstr ""
+
msgid "This action cannot be undone. You will lose the project's repository and all content: issues, merge requests, etc."
msgstr ""
+msgid "This action has been performed too many times. Try again later."
+msgstr ""
+
msgid "This action will %{strongOpen}permanently delete%{strongClose} %{codeOpen}%{project}%{codeClose} %{strongOpen}immediately%{strongClose}, including its repositories and all content: issues, merge requests, etc."
msgstr ""
@@ -25840,9 +26788,6 @@ msgstr ""
msgid "This board's scope is reduced"
msgstr ""
-msgid "This branch has changed since you started editing. Would you like to create a new branch?"
-msgstr ""
-
msgid "This chart could not be displayed"
msgstr ""
@@ -25969,15 +26914,9 @@ msgstr ""
msgid "This is a security log of important events involving your account."
msgstr ""
-msgid "This is the author's first Merge Request to this project."
-msgstr ""
-
msgid "This is the highest peak of users on your installation since the license started."
msgstr ""
-msgid "This is the maximum number of users that have existed at the same time since the license started. This is the minimum number of seats you will need to buy when you renew your license."
-msgstr ""
-
msgid "This is the number of currently active users on your installation, and this is the minimum number you need to purchase when you renew your license."
msgstr ""
@@ -26209,6 +27148,15 @@ msgstr ""
msgid "This user has no identities"
msgstr ""
+msgid "This user has previously committed to the %{name} project."
+msgstr ""
+
+msgid "This user has the %{access} role in the %{name} project."
+msgstr ""
+
+msgid "This user is the author of this %{noteable}."
+msgstr ""
+
msgid "This user will be the author of all events in the activity feed that are the result of an update, like new branches being created or new commits being pushed to existing branches."
msgstr ""
@@ -26239,6 +27187,9 @@ msgstr ""
msgid "Threat Monitoring"
msgstr ""
+msgid "ThreatMonitoring|All Environments"
+msgstr ""
+
msgid "ThreatMonitoring|Anomalous Requests"
msgstr ""
@@ -26266,9 +27217,6 @@ msgstr ""
msgid "ThreatMonitoring|Operations Per Second"
msgstr ""
-msgid "ThreatMonitoring|Overview"
-msgstr ""
-
msgid "ThreatMonitoring|Packet Activity"
msgstr ""
@@ -26287,6 +27235,9 @@ msgstr ""
msgid "ThreatMonitoring|Something went wrong, unable to fetch statistics"
msgstr ""
+msgid "ThreatMonitoring|Statistics"
+msgstr ""
+
msgid "ThreatMonitoring|The firewall is not installed or has been disabled. To view this data, ensure the web application firewall is installed and enabled for your cluster."
msgstr ""
@@ -26686,6 +27637,9 @@ msgstr ""
msgid "To update Snippets with multiple files, you must use the `files` parameter"
msgstr ""
+msgid "To use Gitpod you must first enable the feature in the integrations section of your %{user_prefs}."
+msgstr ""
+
msgid "To view all %{scannedResourcesCount} scanned URLs, please download the CSV file"
msgstr ""
@@ -26719,9 +27673,6 @@ msgstr ""
msgid "Toggle Sidebar"
msgstr ""
-msgid "Toggle all threads"
-msgstr ""
-
msgid "Toggle backtrace"
msgstr ""
@@ -26746,9 +27697,6 @@ msgstr ""
msgid "Toggle navigation"
msgstr ""
-msgid "Toggle project"
-msgstr ""
-
msgid "Toggle sidebar"
msgstr ""
@@ -26788,6 +27736,9 @@ msgstr ""
msgid "Too many projects enabled. You will need to manage them via the console or the API."
msgstr ""
+msgid "Too much data"
+msgstr ""
+
msgid "Topics (optional)"
msgstr ""
@@ -26806,6 +27757,9 @@ msgstr ""
msgid "Total cores (CPUs)"
msgstr ""
+msgid "Total days to completion"
+msgstr ""
+
msgid "Total issues"
msgstr ""
@@ -26902,6 +27856,9 @@ msgstr ""
msgid "Trending"
msgstr ""
+msgid "Trials|Create a new group to start your GitLab Gold trial."
+msgstr ""
+
msgid "Trials|Go back to GitLab"
msgstr ""
@@ -26911,6 +27868,15 @@ msgstr ""
msgid "Trials|You can always resume this process by selecting your avatar and choosing 'Start a Gold trial'"
msgstr ""
+msgid "Trials|You can apply your trial to a new group or an existing group."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group or your personal account."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group, an existing group, or your personal account."
+msgstr ""
+
msgid "Trials|You won't get a free trial right now but you can always resume this process by clicking on your avatar and choosing 'Start a free trial'"
msgstr ""
@@ -26980,6 +27946,9 @@ msgstr ""
msgid "Try using a different search term to find the file you are looking for."
msgstr ""
+msgid "Trying to communicate with your device. Plug it in (if needed) and press the button on the device now."
+msgstr ""
+
msgid "Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now."
msgstr ""
@@ -27067,6 +28036,12 @@ msgstr ""
msgid "URL or request ID"
msgstr ""
+msgid "USER %{user} WILL BE REMOVED! Are you sure?"
+msgstr ""
+
+msgid "USER WILL BE BLOCKED! Are you sure?"
+msgstr ""
+
msgid "UTC"
msgstr ""
@@ -27124,9 +28099,6 @@ msgstr ""
msgid "Unable to load the merge request widget. Try reloading the page."
msgstr ""
-msgid "Unable to resolve"
-msgstr ""
-
msgid "Unable to save iteration. Please try again"
msgstr ""
@@ -27175,6 +28147,9 @@ msgstr ""
msgid "Undo ignore"
msgstr ""
+msgid "Unexpected error"
+msgstr ""
+
msgid "Unfortunately, your email message to GitLab could not be processed."
msgstr ""
@@ -27208,6 +28183,9 @@ msgstr ""
msgid "Unknown response text"
msgstr ""
+msgid "Unless otherwise agreed to in writing with GitLab, by clicking \"Upload License\" you agree that your use of GitLab Software is subject to the %{eula_link_start}Terms of Service%{eula_link_end}."
+msgstr ""
+
msgid "Unlimited"
msgstr ""
@@ -27574,9 +28552,6 @@ msgstr ""
msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
msgstr ""
-msgid "Use a hardware device to add the second factor of authentication."
-msgstr ""
-
msgid "Use an one time password authenticator on your mobile device or computer to enable two-factor authentication (2FA)."
msgstr ""
@@ -27850,13 +28825,13 @@ msgstr ""
msgid "Users"
msgstr ""
-msgid "Users in License:"
+msgid "Users in License"
msgstr ""
-msgid "Users or groups set as approvers in the project's or merge request's settings."
+msgid "Users in License:"
msgstr ""
-msgid "Users outside of license"
+msgid "Users or groups set as approvers in the project's or merge request's settings."
msgstr ""
msgid "Users over License:"
@@ -27874,9 +28849,6 @@ msgstr ""
msgid "Users with a Guest role or those who don't belong to a Project or Group will not use a seat from your license."
msgstr ""
-msgid "Users with a Guest role or those who don't belong to any projects or groups don't count towards seats in use."
-msgstr ""
-
msgid "UsersSelect|%{name} + %{length} more"
msgstr ""
@@ -27916,9 +28888,6 @@ msgstr ""
msgid "Validations failed."
msgstr ""
-msgid "Validity"
-msgstr ""
-
msgid "Value"
msgstr ""
@@ -27937,6 +28906,9 @@ msgstr ""
msgid "Value Stream Name"
msgstr ""
+msgid "ValueStreamAnalyticsStage|We don't have enough data to show this stage."
+msgstr ""
+
msgid "ValueStreamAnalytics|%{days}d"
msgstr ""
@@ -28201,6 +29173,9 @@ msgstr ""
msgid "VisualReviewApp|Steps 1 and 2 (and sometimes 3) are performed once by the developer before requesting feedback. Steps 3 (if necessary), 4 is performed by the reviewer each time they perform a review."
msgstr ""
+msgid "Visualization"
+msgstr ""
+
msgid "Vulnerabilities"
msgstr ""
@@ -28228,34 +29203,31 @@ msgstr ""
msgid "VulnerabilityChart|Severity"
msgstr ""
-msgid "VulnerabilityManagement|A true-positive and will fix"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Change status"
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|Confirm"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Confirmed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
-msgstr ""
-
-msgid "VulnerabilityManagement|Detected %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|A true-positive and will fix"
msgstr ""
-msgid "VulnerabilityManagement|Dismiss"
+msgid "VulnerabilityManagement|Change status"
msgstr ""
-msgid "VulnerabilityManagement|Dismissed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
msgstr ""
-msgid "VulnerabilityManagement|Resolved"
+msgid "VulnerabilityManagement|Detected"
msgstr ""
-msgid "VulnerabilityManagement|Resolved %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Needs triage"
msgstr ""
msgid "VulnerabilityManagement|Something went wrong while trying to delete the comment. Please try again later."
@@ -28306,6 +29278,9 @@ msgstr ""
msgid "Vulnerability|%{scannerName} (version %{scannerVersion})"
msgstr ""
+msgid "Vulnerability|Activity"
+msgstr ""
+
msgid "Vulnerability|Class"
msgstr ""
@@ -28318,6 +29293,9 @@ msgstr ""
msgid "Vulnerability|Description"
msgstr ""
+msgid "Vulnerability|Detected"
+msgstr ""
+
msgid "Vulnerability|Evidence"
msgstr ""
@@ -28381,6 +29359,9 @@ msgstr ""
msgid "Warning: Displaying this diagram might cause performance issues on this page."
msgstr ""
+msgid "We are currently unable to fetch data for the pipeline header."
+msgstr ""
+
msgid "We are currently unable to fetch data for this graph."
msgstr ""
@@ -28420,6 +29401,12 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
+msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
+msgstr ""
+
+msgid "We would like to inform you that your subscription GitLab Enterprise Edition %{plan_name} is nearing its user limit. You have %{active_user_count} active users, which is almost at the user limit of %{maximum_user_count}."
+msgstr ""
+
msgid "We've found no vulnerabilities"
msgstr ""
@@ -28435,6 +29422,12 @@ msgstr ""
msgid "Web terminal"
msgstr ""
+msgid "WebAuthn Devices (%{length})"
+msgstr ""
+
+msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
+msgstr ""
+
msgid "WebIDE|Merge request"
msgstr ""
@@ -28573,15 +29566,9 @@ msgstr ""
msgid "Welcome to the guided GitLab tour"
msgstr ""
-msgid "Welcome to your Issue Board!"
-msgstr ""
-
msgid "Welcome to your issue board!"
msgstr ""
-msgid "We’ve been making changes to %{featureName} and we’d love your feedback %{linkStart}in this issue%{linkEnd} to help us improve the experience."
-msgstr ""
-
msgid "What are you searching for?"
msgstr ""
@@ -28600,6 +29587,9 @@ msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
msgstr ""
+msgid "When enabled, any user visiting %{host} and creating an account will have to be explicitly approved by the admin before they can login. This setting is effective only if sign-ups are enabled."
+msgstr ""
+
msgid "When enabled, any user visiting %{host} will be able to create an account."
msgstr ""
@@ -28828,6 +29818,9 @@ msgstr ""
msgid "With requirements, you can set criteria to check your products against."
msgstr ""
+msgid "With test cases, you can define conditions for your project to meet in determining quality"
+msgstr ""
+
msgid "Withdraw Access Request"
msgstr ""
@@ -28843,6 +29836,9 @@ msgstr ""
msgid "Workflow Help"
msgstr ""
+msgid "Would you like to create a new branch?"
+msgstr ""
+
msgid "Write"
msgstr ""
@@ -28864,6 +29860,9 @@ msgstr ""
msgid "Wrong extern UID provided. Make sure Auth0 is configured correctly."
msgstr ""
+msgid "YYYY-MM-DD"
+msgstr ""
+
msgid "Yes"
msgstr ""
@@ -28921,7 +29920,7 @@ msgstr ""
msgid "You are going to remove the fork relationship from %{project_full_name}. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "You are going to transfer %{project_full_name} to another owner. Are you ABSOLUTELY sure?"
+msgid "You are going to transfer %{project_full_name} to another namespace. Are you ABSOLUTELY sure?"
msgstr ""
msgid "You are going to turn off the confidentiality. This means %{strongStart}everyone%{strongEnd} will be able to see and leave a comment on this %{issuableType}."
@@ -28981,9 +29980,6 @@ msgstr ""
msgid "You can always edit this later"
msgstr ""
-msgid "You can apply your Trial to your Personal account or create a New Group."
-msgstr ""
-
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings"
msgstr ""
@@ -29005,12 +30001,18 @@ msgstr ""
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
+msgid "You can find more information about GitLab subscriptions in %{subscriptions_doc_link}."
+msgstr ""
+
msgid "You can generate an access token scoped to this project for each application to use the GitLab API."
msgstr ""
msgid "You can get started by cloning the repository or start adding files to it with one of the following options."
msgstr ""
+msgid "You can group test cases using labels. To learn about the future direction of this feature, visit %{linkStart}Quality Management direction page%{linkEnd}."
+msgstr ""
+
msgid "You can invite a new member to %{project_name} or invite another group."
msgstr ""
@@ -29026,6 +30028,9 @@ msgstr ""
msgid "You can notify the app / group or a project by sending them an email notification"
msgstr ""
+msgid "You can now close this window."
+msgstr ""
+
msgid "You can now export your security dashboard to a CSV report."
msgstr ""
@@ -29074,9 +30079,6 @@ msgstr ""
msgid "You can test your .gitlab-ci.yml in %{linkStart}CI Lint%{linkEnd}."
msgstr ""
-msgid "You can try again using %{begin_link}basic search%{end_link}"
-msgstr ""
-
msgid "You cannot access the raw file. Please wait a minute."
msgstr ""
@@ -29128,6 +30130,9 @@ msgstr ""
msgid "You don't have any U2F devices registered yet."
msgstr ""
+msgid "You don't have any WebAuthn devices registered yet."
+msgstr ""
+
msgid "You don't have any active chat names."
msgstr ""
@@ -29215,6 +30220,9 @@ msgstr ""
msgid "You must accept our Terms of Service and privacy policy in order to register an account"
msgstr ""
+msgid "You must be logged in to search across all of GitLab"
+msgstr ""
+
msgid "You must disassociate %{domain} from all clusters it is attached to before deletion."
msgstr ""
@@ -29254,7 +30262,7 @@ msgstr ""
msgid "You need to be logged in."
msgstr ""
-msgid "You need to register a two-factor authentication app before you can set up a U2F device."
+msgid "You need to register a two-factor authentication app before you can set up a device."
msgstr ""
msgid "You need to set terms to be enforced"
@@ -29272,6 +30280,9 @@ msgstr ""
msgid "You reached %{usage_in_percent} of %{namespace_name}'s storage capacity (%{used_storage} of %{storage_limit})"
msgstr ""
+msgid "You successfully declined the invitation"
+msgstr ""
+
msgid "You tried to fork %{link_to_the_project} but it failed for the following reason:"
msgstr ""
@@ -29437,10 +30448,13 @@ msgstr ""
msgid "Your U2F device did not send a valid JSON response."
msgstr ""
-msgid "Your U2F device needs to be set up. Plug it in (if not already) and click the button on the left."
+msgid "Your U2F device was registered!"
msgstr ""
-msgid "Your U2F device was registered!"
+msgid "Your WebAuthn device did not send a valid JSON response."
+msgstr ""
+
+msgid "Your WebAuthn device was registered!"
msgstr ""
msgid "Your access request to the %{source_type} has been withdrawn."
@@ -29464,6 +30478,9 @@ msgstr ""
msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
msgstr ""
+msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
+msgstr ""
+
msgid "Your changes can be committed to %{branch_name} because a merge request is open."
msgstr ""
@@ -29500,6 +30517,12 @@ msgstr ""
msgid "Your deployment services will be broken, you will need to manually fix the services after renaming."
msgstr ""
+msgid "Your device is not compatible with GitLab. Please try another device"
+msgstr ""
+
+msgid "Your device needs to be set up. Plug it in (if needed) and click the button on the left."
+msgstr ""
+
msgid "Your device was successfully set up! Give it a name and register it with the GitLab server."
msgstr ""
@@ -29617,9 +30640,6 @@ msgstr[5] ""
msgid "access:"
msgstr ""
-msgid "activated"
-msgstr ""
-
msgid "added %{created_at_timeago}"
msgstr ""
@@ -29692,9 +30712,21 @@ msgstr ""
msgid "by %{user}"
msgstr ""
+msgid "cannot be a date in the past"
+msgstr ""
+
msgid "cannot be changed if a personal project has container registry tags."
msgstr ""
+msgid "cannot be changed if shared runners are enabled"
+msgstr ""
+
+msgid "cannot be enabled because parent group does not allow it"
+msgstr ""
+
+msgid "cannot be enabled because parent group has shared Runners disabled"
+msgstr ""
+
msgid "cannot be enabled unless all domains have TLS certificates"
msgstr ""
@@ -29740,7 +30772,7 @@ msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about SAST %{linkEndTag}"
msgstr ""
-msgid "ciReport|%{linkStartTag}Learn more about Secret Scanning %{linkEndTag}"
+msgid "ciReport|%{linkStartTag}Learn more about Secret Detection %{linkEndTag}"
msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about codequality reports %{linkEndTag}"
@@ -30067,9 +31099,6 @@ msgstr ""
msgid "error"
msgstr ""
-msgid "error code:"
-msgstr ""
-
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr ""
@@ -30091,6 +31120,9 @@ msgstr ""
msgid "failed to dismiss associated finding(id=%{finding_id}): %{message}"
msgstr ""
+msgid "failed to revert associated finding(id=%{finding_id}) to detected"
+msgstr ""
+
msgid "file"
msgid_plural "files"
msgstr[0] ""
@@ -30649,6 +31681,9 @@ msgstr ""
msgid "must be a root namespace"
msgstr ""
+msgid "must be a valid IPv4 or IPv6 address"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -30685,6 +31720,9 @@ msgstr ""
msgid "no expiration"
msgstr ""
+msgid "no name set"
+msgstr ""
+
msgid "no one can merge"
msgstr ""
@@ -30883,9 +31921,6 @@ msgstr ""
msgid "security Reports|There was an error creating the merge request"
msgstr ""
-msgid "settings saved, but not activated"
-msgstr ""
-
msgid "severity|Critical"
msgstr ""
@@ -31012,9 +32047,6 @@ msgstr ""
msgid "toggle collapse"
msgstr ""
-msgid "toggle dropdown"
-msgstr ""
-
msgid "triggered"
msgstr ""
@@ -31042,6 +32074,9 @@ msgstr ""
msgid "user avatar"
msgstr ""
+msgid "user preferences"
+msgstr ""
+
msgid "username"
msgstr ""
diff --git a/locale/da_DK/gitlab.po b/locale/da_DK/gitlab.po
index bd1283c895f..2f8727463ef 100644
--- a/locale/da_DK/gitlab.po
+++ b/locale/da_DK/gitlab.po
@@ -14,7 +14,10 @@ msgstr ""
"X-Crowdin-Language: da\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 6\n"
-"PO-Revision-Date: 2020-09-04 23:07\n"
+"PO-Revision-Date: 2020-10-02 18:47\n"
+
+msgid " %{project_name}#%{issue_iid} &middot; opened %{issue_created} by %{author}"
+msgstr ""
msgid " %{start} to %{end}"
msgstr ""
@@ -74,6 +77,16 @@ msgstr ""
msgid "\"el\" parameter is required for createInstance()"
msgstr ""
+msgid "%d Approval"
+msgid_plural "%d Approvals"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d Package"
+msgid_plural "%d Packages"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d Scanned URL"
msgid_plural "%d Scanned URLs"
msgstr[0] ""
@@ -137,6 +150,11 @@ msgstr[1] ""
msgid "%d commits"
msgstr ""
+msgid "%d completed issue"
+msgid_plural "%d completed issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d contribution"
msgid_plural "%d contributions"
msgstr[0] ""
@@ -147,6 +165,11 @@ msgid_plural "%d days"
msgstr[0] ""
msgstr[1] ""
+msgid "%d day until tags are automatically removed"
+msgid_plural "%d days until tags are automatically removed"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d error"
msgid_plural "%d errors"
msgstr[0] ""
@@ -237,6 +260,16 @@ msgid_plural "%d more comments"
msgstr[0] ""
msgstr[1] ""
+msgid "%d open issue"
+msgid_plural "%d open issues"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d pending comment"
+msgid_plural "%d pending comments"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d personal project will be removed and cannot be restored."
msgid_plural "%d personal projects will be removed and cannot be restored."
msgstr[0] ""
@@ -252,6 +285,11 @@ msgid_plural "%d projects"
msgstr[0] ""
msgstr[1] ""
+msgid "%d project selected"
+msgid_plural "%d projects selected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d request with warnings"
msgid_plural "%d requests with warnings"
msgstr[0] ""
@@ -272,6 +310,11 @@ msgid_plural "%d tags"
msgstr[0] ""
msgstr[1] ""
+msgid "%d tag per image name"
+msgid_plural "%d tags per image name"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d unassigned issue"
msgid_plural "%d unassigned issues"
msgstr[0] ""
@@ -292,6 +335,11 @@ msgid_plural "%d vulnerabilities dismissed"
msgstr[0] ""
msgstr[1] ""
+msgid "%d warning found:"
+msgid_plural "%d warnings found:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%s additional commit has been omitted to prevent performance issues."
msgid_plural "%s additional commits have been omitted to prevent performance issues."
msgstr[0] ""
@@ -330,6 +378,9 @@ msgstr ""
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr ""
+msgid "%{completedCount} completed weight"
+msgstr ""
+
msgid "%{completedWeight} of %{totalWeight} weight completed"
msgstr ""
@@ -378,14 +429,12 @@ msgid_plural "%{count} participants"
msgstr[0] ""
msgstr[1] ""
-msgid "%{count} pending comment"
-msgid_plural "%{count} pending comments"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
+msgid "%{count} total weight"
+msgstr ""
+
msgid "%{dashboard_path} could not be found."
msgstr ""
@@ -440,6 +489,9 @@ msgstr ""
msgid "%{group_name} uses group managed accounts. You need to create a new GitLab account which will be managed by %{group_name}."
msgstr ""
+msgid "%{group_name}&%{epic_iid} &middot; opened %{epic_created} by %{author}"
+msgstr ""
+
msgid "%{host} sign-in from new location"
msgstr ""
@@ -452,7 +504,7 @@ msgstr ""
msgid "%{issuableType} will be removed! Are you sure?"
msgstr ""
-msgid "%{issuesSize} issues with a limit of %{maxIssueCount}"
+msgid "%{issuesCount} issues with a limit of %{maxIssueCount}"
msgstr ""
msgid "%{issuesSize} with a limit of %{maxIssueCount}"
@@ -485,7 +537,7 @@ msgstr ""
msgid "%{labelStart}Namespace:%{labelEnd} %{namespace}"
msgstr ""
-msgid "%{labelStart}Report Type:%{labelEnd} %{reportType}"
+msgid "%{labelStart}Scan Type:%{labelEnd} %{reportType}"
msgstr ""
msgid "%{labelStart}Scanner:%{labelEnd} %{scanner}"
@@ -682,9 +734,6 @@ msgid_plural "%{securityScanner} results are not available because a pipeline ha
msgstr[0] ""
msgstr[1] ""
-msgid "%{service_title} %{message}."
-msgstr ""
-
msgid "%{size} GiB"
msgstr ""
@@ -773,6 +822,12 @@ msgstr ""
msgid "%{timebox_name} should belong either to a project or a group."
msgstr ""
+msgid "%{timebox_type} does not support burnup charts"
+msgstr ""
+
+msgid "%{timebox_type} must have a start and due date"
+msgstr ""
+
msgid "%{title} %{operator} %{threshold}"
msgstr ""
@@ -797,7 +852,7 @@ msgstr ""
msgid "%{total} open issue weight"
msgstr ""
-msgid "%{total} open issues"
+msgid "%{total} warnings found: showing first %{warningsDisplayed}"
msgstr ""
msgid "%{usage_ping_link_start}Learn more%{usage_ping_link_end} about what information is shared with GitLab Inc."
@@ -830,9 +885,6 @@ msgstr ""
msgid "&lt; 1 hour"
msgstr ""
-msgid "&lt;no name set&gt;"
-msgstr ""
-
msgid "&lt;no scopes selected&gt;"
msgstr ""
@@ -863,6 +915,9 @@ msgstr ""
msgid "'%{name}' Value Stream created"
msgstr ""
+msgid "'%{name}' Value Stream deleted"
+msgstr ""
+
msgid "'%{name}' stage already exists"
msgstr ""
@@ -922,6 +977,9 @@ msgstr ""
msgid "+ %{numberOfHiddenAssignees} more"
msgstr ""
+msgid "+ %{numberOfHiddenReviewers} more"
+msgstr ""
+
msgid "+%d more"
msgid_plural "+%d more"
msgstr[0] ""
@@ -982,6 +1040,11 @@ msgid_plural "%d Days"
msgstr[0] ""
msgstr[1] ""
+msgid "1 Issue"
+msgid_plural "%d Issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "1 closed issue"
msgid_plural "%{issues} closed issues"
msgstr[0] ""
@@ -997,6 +1060,11 @@ msgid_plural "%d days"
msgstr[0] ""
msgstr[1] ""
+msgid "1 deploy key"
+msgid_plural "%d deploy keys"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1099,6 +1167,9 @@ msgstr ""
msgid ":%{startLine} to %{endLine}"
msgstr ""
+msgid "A %{incident_docs_start}modified issue%{incident_docs_end} to guide the resolution of incidents."
+msgstr ""
+
msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr ""
@@ -1111,6 +1182,9 @@ msgstr ""
msgid "A GitBook site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
+msgid "A Gitpod configured Webapplication in Spring and Java"
+msgstr ""
+
msgid "A Hexo site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
@@ -1282,9 +1356,15 @@ msgstr ""
msgid "Access expiration date"
msgstr ""
+msgid "Access expires"
+msgstr ""
+
msgid "Access forbidden. Check your access level."
msgstr ""
+msgid "Access granted"
+msgstr ""
+
msgid "Access requests"
msgstr ""
@@ -1294,6 +1374,9 @@ msgstr ""
msgid "Access to Pages websites are controlled based on the user's membership to a given project. By checking this box, users will be required to be logged in to have access to all Pages websites in your instance."
msgstr ""
+msgid "AccessDropdown|Deploy Keys"
+msgstr ""
+
msgid "AccessDropdown|Groups"
msgstr ""
@@ -1411,12 +1494,6 @@ msgstr ""
msgid "Active Sessions"
msgstr ""
-msgid "Active Users:"
-msgstr ""
-
-msgid "Active users"
-msgstr ""
-
msgid "Activity"
msgstr ""
@@ -1584,9 +1661,6 @@ msgstr ""
msgid "Add label(s)"
msgstr ""
-msgid "Add license"
-msgstr ""
-
msgid "Add list"
msgstr ""
@@ -1761,21 +1835,51 @@ msgstr ""
msgid "AdminArea|Bots"
msgstr ""
+msgid "AdminArea|Components"
+msgstr ""
+
msgid "AdminArea|Developer"
msgstr ""
+msgid "AdminArea|Features"
+msgstr ""
+
+msgid "AdminArea|Groups: %{number_of_groups}"
+msgstr ""
+
msgid "AdminArea|Guest"
msgstr ""
msgid "AdminArea|Included Free in license"
msgstr ""
+msgid "AdminArea|Latest groups"
+msgstr ""
+
+msgid "AdminArea|Latest projects"
+msgstr ""
+
+msgid "AdminArea|Latest users"
+msgstr ""
+
msgid "AdminArea|Maintainer"
msgstr ""
+msgid "AdminArea|New group"
+msgstr ""
+
+msgid "AdminArea|New project"
+msgstr ""
+
+msgid "AdminArea|New user"
+msgstr ""
+
msgid "AdminArea|Owner"
msgstr ""
+msgid "AdminArea|Projects: %{number_of_projects}"
+msgstr ""
+
msgid "AdminArea|Reporter"
msgstr ""
@@ -1803,6 +1907,9 @@ msgstr ""
msgid "AdminArea|Users without a Group and Project"
msgstr ""
+msgid "AdminArea|Users: %{number_of_users}"
+msgstr ""
+
msgid "AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running."
msgstr ""
@@ -1821,9 +1928,6 @@ msgstr ""
msgid "AdminProjects|Delete Project %{projectName}?"
msgstr ""
-msgid "AdminProjects|Delete project"
-msgstr ""
-
msgid "AdminSettings|Apply integration settings to all Projects"
msgstr ""
@@ -2061,21 +2165,30 @@ msgstr ""
msgid "AdminUsers|Without projects"
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 ""
msgid "AdminUsers|You cannot remove your own admin rights."
msgstr ""
+msgid "AdminUsers|You must transfer ownership or delete the groups owned by this user before you can delete their account"
+msgstr ""
+
msgid "Administration"
msgstr ""
msgid "Advanced"
msgstr ""
+msgid "Advanced Search"
+msgstr ""
+
+msgid "Advanced Search with Elasticsearch"
+msgstr ""
+
msgid "Advanced Settings"
msgstr ""
@@ -2153,6 +2266,9 @@ msgstr ""
msgid "AlertManagement|Edit"
msgstr ""
+msgid "AlertManagement|Environment"
+msgstr ""
+
msgid "AlertManagement|Events"
msgstr ""
@@ -2165,6 +2281,9 @@ msgstr ""
msgid "AlertManagement|Issue"
msgstr ""
+msgid "AlertManagement|Key"
+msgstr ""
+
msgid "AlertManagement|Low"
msgstr ""
@@ -2258,6 +2377,9 @@ msgstr ""
msgid "AlertManagement|Unknown"
msgstr ""
+msgid "AlertManagement|Value"
+msgstr ""
+
msgid "AlertManagement|View alerts in Opsgenie"
msgstr ""
@@ -2417,6 +2539,9 @@ msgstr ""
msgid "All projects"
msgstr ""
+msgid "All projects selected"
+msgstr ""
+
msgid "All security scans are enabled because %{linkStart}Auto DevOps%{linkEnd} is enabled on this project"
msgstr ""
@@ -2504,6 +2629,9 @@ msgstr ""
msgid "Almost there"
msgstr ""
+msgid "Already blocked"
+msgstr ""
+
msgid "Also called \"Issuer\" or \"Relying party trust identifier\""
msgstr ""
@@ -2558,6 +2686,9 @@ msgstr ""
msgid "An error has occurred"
msgstr ""
+msgid "An error occured while making the changes: %{error}"
+msgstr ""
+
msgid "An error occurred adding a draft to the thread."
msgstr ""
@@ -2585,12 +2716,6 @@ msgstr ""
msgid "An error occurred when toggling the notification subscription"
msgstr ""
-msgid "An error occurred when trying to resolve a comment. Please try again."
-msgstr ""
-
-msgid "An error occurred when trying to resolve a discussion. Please try again."
-msgstr ""
-
msgid "An error occurred when updating the issue weight"
msgstr ""
@@ -2606,12 +2731,6 @@ msgstr ""
msgid "An error occurred while checking group path. Please refresh and try again."
msgstr ""
-msgid "An error occurred while committing your changes."
-msgstr ""
-
-msgid "An error occurred while creating the list. Please try again."
-msgstr ""
-
msgid "An error occurred while decoding the file."
msgstr ""
@@ -2684,25 +2803,19 @@ msgstr ""
msgid "An error occurred while fetching the Service Desk address."
msgstr ""
-msgid "An error occurred while fetching the board issues. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the board lists. Please reload the page."
msgstr ""
msgid "An error occurred while fetching the board lists. Please try again."
msgstr ""
-msgid "An error occurred while fetching the board swimlanes. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the builds."
msgstr ""
msgid "An error occurred while fetching the job log."
msgstr ""
-msgid "An error occurred while fetching the job trace."
+msgid "An error occurred while fetching the job logs."
msgstr ""
msgid "An error occurred while fetching the job."
@@ -2849,9 +2962,6 @@ msgstr ""
msgid "An error occurred while saving assignees"
msgstr ""
-msgid "An error occurred while saving the template. Please check if the template exists."
-msgstr ""
-
msgid "An error occurred while searching for milestones"
msgstr ""
@@ -2870,10 +2980,10 @@ msgstr ""
msgid "An error occurred while updating approvers"
msgstr ""
-msgid "An error occurred while updating the comment"
+msgid "An error occurred while updating labels."
msgstr ""
-msgid "An error occurred while updating the list. Please try again."
+msgid "An error occurred while updating the comment"
msgstr ""
msgid "An error occurred while validating group path"
@@ -2927,6 +3037,9 @@ msgstr ""
msgid "An unknown error occurred while loading this graph."
msgstr ""
+msgid "An unknown error occurred."
+msgstr ""
+
msgid "Analytics"
msgstr ""
@@ -2960,10 +3073,10 @@ msgstr ""
msgid "Any"
msgstr ""
-msgid "Any Author"
+msgid "Any %{header}"
msgstr ""
-msgid "Any Status"
+msgid "Any Author"
msgstr ""
msgid "Any branch"
@@ -3017,6 +3130,9 @@ msgstr ""
msgid "Application ID"
msgstr ""
+msgid "Application limits saved successfully"
+msgstr ""
+
msgid "Application settings saved successfully"
msgstr ""
@@ -3226,6 +3342,9 @@ msgstr ""
msgid "Are you sure you want to close this blocked issue?"
msgstr ""
+msgid "Are you sure you want to delete \"%{name}\" Value Stream?"
+msgstr ""
+
msgid "Are you sure you want to delete %{name}?"
msgstr ""
@@ -3235,6 +3354,9 @@ msgstr ""
msgid "Are you sure you want to delete this %{typeOfComment}?"
msgstr ""
+msgid "Are you sure you want to delete this SSH key?"
+msgstr ""
+
msgid "Are you sure you want to delete this board?"
msgstr ""
@@ -3259,6 +3381,11 @@ msgstr ""
msgid "Are you sure you want to erase this build?"
msgstr ""
+msgid "Are you sure you want to import %d repository?"
+msgid_plural "Are you sure you want to import %d repositories?"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Are you sure you want to lose unsaved changes?"
msgstr ""
@@ -3268,15 +3395,15 @@ msgstr ""
msgid "Are you sure you want to merge immediately?"
msgstr ""
-msgid "Are you sure you want to permanently delete this license?"
-msgstr ""
-
msgid "Are you sure you want to re-deploy this environment?"
msgstr ""
msgid "Are you sure you want to regenerate the public key? You will have to update the public key on the remote server before mirroring will work again."
msgstr ""
+msgid "Are you sure you want to reindex?"
+msgstr ""
+
msgid "Are you sure you want to remove %{group_name}?"
msgstr ""
@@ -3304,6 +3431,9 @@ msgstr ""
msgid "Are you sure you want to revoke this nickname?"
msgstr ""
+msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
+msgstr ""
+
msgid "Are you sure you want to stop this environment?"
msgstr ""
@@ -3325,6 +3455,9 @@ msgstr ""
msgid "Are you sure? The device will be signed out of GitLab and all remember me tokens revoked."
msgstr ""
+msgid "Are you sure? This will invalidate your registered applications and U2F / WebAuthn devices."
+msgstr ""
+
msgid "Are you sure? This will invalidate your registered applications and U2F devices."
msgstr ""
@@ -3343,9 +3476,6 @@ msgstr ""
msgid "Artifacts"
msgstr ""
-msgid "As U2F devices are only supported by a few browsers, we require that you set up a two-factor authentication app before a U2F device. That way you'll always be able to log in - even when you're using an unsupported browser."
-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 ""
@@ -3539,6 +3669,9 @@ msgstr ""
msgid "AuditLogs|Target"
msgstr ""
+msgid "AuditLogs|This month"
+msgstr ""
+
msgid "AuditLogs|User Events"
msgstr ""
@@ -3578,6 +3711,9 @@ msgstr ""
msgid "Authentication via U2F device failed."
msgstr ""
+msgid "Authentication via WebAuthn device failed."
+msgstr ""
+
msgid "Author"
msgstr ""
@@ -3845,15 +3981,6 @@ msgstr ""
msgid "BambooService|You must set up automatic revision labeling and a repository trigger in Bamboo."
msgstr ""
-msgid "BatchComments|Delete all pending comments"
-msgstr ""
-
-msgid "BatchComments|Discard review?"
-msgstr ""
-
-msgid "BatchComments|You're about to discard your review which will delete all of your pending comments. The deleted comments %{strong_start}cannot%{strong_end} be restored."
-msgstr ""
-
msgid "Be careful. Changing the project's namespace can have unintended side effects."
msgstr ""
@@ -3875,6 +4002,9 @@ msgstr ""
msgid "Bi-weekly code coverage"
msgstr ""
+msgid "Billable Users:"
+msgstr ""
+
msgid "Billing"
msgstr ""
@@ -3884,7 +4014,7 @@ msgstr ""
msgid "BillingPlans|@%{user_name} you are currently using the %{plan_name} plan."
msgstr ""
-msgid "BillingPlans|Congratulations, your new trial is activated"
+msgid "BillingPlans|Congratulations, your free trial is activated."
msgstr ""
msgid "BillingPlans|If you would like to downgrade your plan please contact %{support_link_start}Customer Support%{support_link_end}."
@@ -3947,6 +4077,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Block user"
+msgstr ""
+
msgid "Blocked"
msgstr ""
@@ -3962,31 +4095,37 @@ msgstr ""
msgid "Blog"
msgstr ""
-msgid "Board name"
-msgstr ""
-
msgid "Board scope"
msgstr ""
msgid "Board scope affects which issues are displayed for anyone who visits this board"
msgstr ""
-msgid "BoardBlankState|Add default lists"
+msgid "Boards"
msgstr ""
-msgid "BoardBlankState|Add the following default lists to your Issue Board with one click:"
+msgid "Boards and Board Lists"
msgstr ""
-msgid "BoardBlankState|Nevermind, I'll use my own"
+msgid "Boards|An error occurred while creating the issue. Please try again."
msgstr ""
-msgid "BoardBlankState|Starting out with the default set of lists will get you right on the way to making the most of your board."
+msgid "Boards|An error occurred while creating the list. Please try again."
msgstr ""
-msgid "Boards"
+msgid "Boards|An error occurred while fetching issues. Please reload the page."
msgstr ""
-msgid "Boards and Board Lists"
+msgid "Boards|An error occurred while fetching the board issues. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching the board swimlanes. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while moving the issue. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while updating the list. Please try again."
msgstr ""
msgid "Boards|Collapse"
@@ -4013,7 +4152,7 @@ msgstr ""
msgid "Branch %{branch_name} was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr ""
-msgid "Branch has changed"
+msgid "Branch changed"
msgstr ""
msgid "Branch is already taken"
@@ -4319,6 +4458,9 @@ msgstr ""
msgid "CLOSED (MOVED)"
msgstr ""
+msgid "CODEOWNERS rule violation"
+msgstr ""
+
msgid "CONTRIBUTING"
msgstr ""
@@ -4349,9 +4491,6 @@ msgstr ""
msgid "Can't create snippet: %{err}"
msgstr ""
-msgid "Can't edit as source branch was deleted"
-msgstr ""
-
msgid "Can't fetch content for the blob: %{err}"
msgstr ""
@@ -4364,9 +4503,6 @@ msgstr ""
msgid "Can't load mermaid module: %{err}"
msgstr ""
-msgid "Can't remove group members without group managed account"
-msgstr ""
-
msgid "Can't scan the code?"
msgstr ""
@@ -4409,6 +4545,9 @@ msgstr ""
msgid "Cannot create the abuse report. This user has been blocked."
msgstr ""
+msgid "Cannot enable shared runners because parent group does not allow it"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -4514,6 +4653,15 @@ msgstr ""
msgid "Change your password or recover your current one"
msgstr ""
+msgid "ChangeReviewer|Reviewer changed from %{old} to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Reviewer changed to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Unassigned"
+msgstr ""
+
msgid "ChangeTypeActionLabel|Pick into branch"
msgstr ""
@@ -4553,6 +4701,9 @@ msgstr ""
msgid "Changes the title to \"%{title_param}\"."
msgstr ""
+msgid "Changes were successfully made."
+msgstr ""
+
msgid "Changes won't take place until the index is %{link_start}recreated%{link_end}."
msgstr ""
@@ -4958,6 +5109,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove variable"
+msgstr ""
+
msgid "CiVariables|Remove variable row"
msgstr ""
@@ -5036,9 +5190,6 @@ msgstr ""
msgid "Clear due date"
msgstr ""
-msgid "Clear input"
-msgstr ""
-
msgid "Clear recent searches"
msgstr ""
@@ -5087,6 +5238,9 @@ msgstr ""
msgid "Client authentication key password"
msgstr ""
+msgid "Client request timeout"
+msgstr ""
+
msgid "Clients"
msgstr ""
@@ -5171,6 +5325,27 @@ msgstr ""
msgid "Cluster type must be specificed for Stages::ClusterEndpointInserter"
msgstr ""
+msgid "ClusterAgents|Configuration"
+msgstr ""
+
+msgid "ClusterAgents|Connect your cluster with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate Kubernetes with a GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Name"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Agent also requires %{linkStart}enabling the Agent Server%{linkEnd}"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Kubernetes Agent allows an Infrastructure as Code, GitOps approach to integrating Kubernetes clusters with GitLab. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "ClusterAgent|This feature is only available for premium plans"
msgstr ""
@@ -5240,10 +5415,10 @@ msgstr ""
msgid "ClusterIntegration|All installed applications and related resources"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster."
+msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{linkStart}More information%{linkEnd}"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{startLink}More information%{endLink}"
+msgid "ClusterIntegration|Allow GitLab to manage namespaces and service accounts for this cluster."
msgstr ""
msgid "ClusterIntegration|Alternatively, "
@@ -5264,6 +5439,9 @@ msgstr ""
msgid "ClusterIntegration|An error occurred while trying to fetch zone machine types: %{error}"
msgstr ""
+msgid "ClusterIntegration|An unknown error occurred while attempting to connect to Kubernetes."
+msgstr ""
+
msgid "ClusterIntegration|Any project namespaces"
msgstr ""
@@ -5279,6 +5457,9 @@ msgstr ""
msgid "ClusterIntegration|Authenticate with Amazon Web Services"
msgstr ""
+msgid "ClusterIntegration|Authentication Error"
+msgstr ""
+
msgid "ClusterIntegration|Base domain"
msgstr ""
@@ -5297,13 +5478,22 @@ msgstr ""
msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}security group %{externalLinkIcon} %{endLink} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
+msgid "ClusterIntegration|Check your CA certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Check your cluster status"
+msgstr ""
+
+msgid "ClusterIntegration|Check your token"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}subnets %{externalLinkIcon} %{endLink} in your VPC where your worker nodes will run."
+msgid "ClusterIntegration|Choose the %{linkStart}security group %{linkEnd} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
msgstr ""
-msgid "ClusterIntegration|Choose the worker node %{startLink}instance type %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Choose the %{linkStart}subnets %{linkEnd} in your VPC where your worker nodes will run."
+msgstr ""
+
+msgid "ClusterIntegration|Choose the worker node %{linkStart}instance type%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Choose which applications to install on your Kubernetes cluster."
@@ -5315,10 +5505,7 @@ msgstr ""
msgid "ClusterIntegration|Clear cluster cache"
msgstr ""
-msgid "ClusterIntegration|Clear the local cache of namespace and service accounts. This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
-msgstr ""
-
-msgid "ClusterIntegration|Cluster being created"
+msgid "ClusterIntegration|Clear the local cache of namespace and service accounts."
msgstr ""
msgid "ClusterIntegration|Cluster management project (alpha)"
@@ -5330,15 +5517,21 @@ msgstr ""
msgid "ClusterIntegration|Cluster_applications artifact too big. Maximum allowable size: %{human_size}"
msgstr ""
-msgid "ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters."
+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|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}"
+msgid "ClusterIntegration|Clusters connected with a certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Connect cluster with certificate"
msgstr ""
msgid "ClusterIntegration|Connect existing cluster"
msgstr ""
+msgid "ClusterIntegration|Connection Error"
+msgstr ""
+
msgid "ClusterIntegration|Copy API URL"
msgstr ""
@@ -5414,6 +5607,12 @@ msgstr ""
msgid "ClusterIntegration|Deletes all GitLab resources attached to this cluster during removal"
msgstr ""
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared."
+msgstr ""
+
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared. %{linkStart}More information%{linkEnd}"
+msgstr ""
+
msgid "ClusterIntegration|Did you know?"
msgstr ""
@@ -5483,6 +5682,9 @@ msgstr ""
msgid "ClusterIntegration|Fluentd is an open source data collector, which lets you unify the data collection and consumption for a better use and understanding of data. It requires at least one of the following logs to be successfully installed."
msgstr ""
+msgid "ClusterIntegration|GitLab Agent managed clusters"
+msgstr ""
+
msgid "ClusterIntegration|GitLab Container Network Policies"
msgstr ""
@@ -5495,6 +5697,12 @@ msgstr ""
msgid "ClusterIntegration|GitLab Runner connects to the repository and executes CI/CD jobs, pushing results back and deploying applications to production."
msgstr ""
+msgid "ClusterIntegration|GitLab failed to authenticate."
+msgstr ""
+
+msgid "ClusterIntegration|GitLab failed to connect to the cluster."
+msgstr ""
+
msgid "ClusterIntegration|GitLab-managed cluster"
msgstr ""
@@ -5516,6 +5724,9 @@ msgstr ""
msgid "ClusterIntegration|Group cluster"
msgstr ""
+msgid "ClusterIntegration|HTTP Error"
+msgstr ""
+
msgid "ClusterIntegration|Helm Tiller"
msgstr ""
@@ -5549,7 +5760,10 @@ msgstr ""
msgid "ClusterIntegration|Instance type"
msgstr ""
-msgid "ClusterIntegration|Integrate Kubernetes cluster automation"
+msgid "ClusterIntegration|Integrate Kubernetes with a cluster certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Integrate with a cluster certificate"
msgstr ""
msgid "ClusterIntegration|Issuer Email"
@@ -5585,9 +5799,6 @@ msgstr ""
msgid "ClusterIntegration|Knative extends Kubernetes to provide a set of middleware components that are essential to build modern, source-centric, and container-based applications that can run anywhere: on premises, in the cloud, or even in a third-party data center."
msgstr ""
-msgid "ClusterIntegration|Kubernetes cluster"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes cluster is being created..."
msgstr ""
@@ -5600,9 +5811,6 @@ msgstr ""
msgid "ClusterIntegration|Kubernetes clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr ""
-msgid "ClusterIntegration|Kubernetes clusters can be used to deploy applications and to provide Review Apps for this project"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes version"
msgstr ""
@@ -5615,7 +5823,7 @@ msgstr ""
msgid "ClusterIntegration|Learn more about %{help_link_start}zones%{help_link_end}."
msgstr ""
-msgid "ClusterIntegration|Learn more about %{startLink}Regions %{externalLinkIcon}%{endLink}."
+msgid "ClusterIntegration|Learn more about %{linkStart}Regions%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Learn more about Kubernetes"
@@ -5660,12 +5868,18 @@ msgstr ""
msgid "ClusterIntegration|Machine type"
msgstr ""
+msgid "ClusterIntegration|Make sure your API endpoint is correct"
+msgstr ""
+
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create Kubernetes clusters"
msgstr ""
msgid "ClusterIntegration|Manage your Kubernetes cluster by visiting %{provider_link}"
msgstr ""
+msgid "ClusterIntegration|Namespace per environment"
+msgstr ""
+
msgid "ClusterIntegration|No IAM Roles found"
msgstr ""
@@ -5711,6 +5925,9 @@ msgstr ""
msgid "ClusterIntegration|No zones matched your search"
msgstr ""
+msgid "ClusterIntegration|Node calculations use the Kubernetes Metrics API. Make sure your cluster has metrics installed"
+msgstr ""
+
msgid "ClusterIntegration|Number of nodes"
msgstr ""
@@ -5753,6 +5970,9 @@ msgstr ""
msgid "ClusterIntegration|RBAC-enabled cluster"
msgstr ""
+msgid "ClusterIntegration|Read our %{linkStart}help page%{linkEnd} on Kubernetes cluster integration."
+msgstr ""
+
msgid "ClusterIntegration|Read our %{link_start}help page%{link_end} on Kubernetes cluster integration."
msgstr ""
@@ -5855,7 +6075,7 @@ msgstr ""
msgid "ClusterIntegration|Select a VPC to choose a subnet"
msgstr ""
-msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{linkStart}Amazon Web Services %{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select a network to choose a subnetwork"
@@ -5888,7 +6108,7 @@ msgstr ""
msgid "ClusterIntegration|Select project to choose zone"
msgstr ""
-msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select zone"
@@ -5978,9 +6198,18 @@ msgstr ""
msgid "ClusterIntegration|There was a problem authenticating with your cluster. Please ensure your CA Certificate and Token are valid."
msgstr ""
+msgid "ClusterIntegration|There was an HTTP error when connecting to your cluster."
+msgstr ""
+
msgid "ClusterIntegration|This account must have permissions to create a Kubernetes cluster in the %{link_to_container_project} specified below"
msgstr ""
+msgid "ClusterIntegration|This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
+msgstr ""
+
+msgid "ClusterIntegration|This is necessary to clear existing environment-namespace associations from clusters previously managed by GitLab."
+msgstr ""
+
msgid "ClusterIntegration|This option will allow you to install applications on RBAC clusters."
msgstr ""
@@ -6005,9 +6234,21 @@ msgstr ""
msgid "ClusterIntegration|To use a new project, first create one on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}."
msgstr ""
+msgid "ClusterIntegration|Troubleshooting tips:"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Authenticate"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Connect"
+msgstr ""
+
msgid "ClusterIntegration|Uninstall %{appTitle}"
msgstr ""
+msgid "ClusterIntegration|Unknown Error"
+msgstr ""
+
msgid "ClusterIntegration|Update %{appTitle}"
msgstr ""
@@ -6068,7 +6309,7 @@ msgstr ""
msgid "ClusterIntegration|Your cluster API is unreachable. Please ensure your API URL is correct."
msgstr ""
-msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Zone"
@@ -6188,6 +6429,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse all threads"
+msgstr ""
+
msgid "Collapse approvers"
msgstr ""
@@ -6337,7 +6581,7 @@ msgstr ""
msgid "Commit…"
msgstr ""
-msgid "Company"
+msgid "Community forum"
msgstr ""
msgid "Company name"
@@ -6346,6 +6590,9 @@ msgstr ""
msgid "Compare"
msgstr ""
+msgid "Compare %{oldCommitId}...%{newCommitId}"
+msgstr ""
+
msgid "Compare Git revisions"
msgstr ""
@@ -6361,6 +6608,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare submodule commit revisions"
+msgstr ""
+
msgid "Compare with previous version"
msgstr ""
@@ -6496,6 +6746,9 @@ msgstr ""
msgid "Configure the way a user creates a new account."
msgstr ""
+msgid "Configure which lists are shown for anyone who visits this board"
+msgstr ""
+
msgid "Confirm"
msgstr ""
@@ -6721,6 +6974,9 @@ msgstr[1] ""
msgid "ContainerRegistry|Set cleanup policy"
msgstr ""
+msgid "ContainerRegistry|Some tags were not deleted"
+msgstr ""
+
msgid "ContainerRegistry|Something went wrong while fetching the cleanup policy."
msgstr ""
@@ -6760,6 +7016,9 @@ msgstr ""
msgid "ContainerRegistry|Tags with names matching this regex pattern will %{italicStart}expire:%{italicEnd}"
msgstr ""
+msgid "ContainerRegistry|The cleanup policy timed out before it could delete all tags. An administrator can %{adminLinkStart}manually run cleanup now%{adminLinkEnd} or you can wait for the cleanup policy to automatically run again. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "ContainerRegistry|The last tag related to this image was recently removed. This empty image and any associated data will be automatically removed as part of the regular Garbage Collection process. If you have any questions, contact your administrator."
msgstr ""
@@ -6892,6 +7151,9 @@ msgstr ""
msgid "Contributions per group member"
msgstr ""
+msgid "Contributor"
+msgstr ""
+
msgid "Contributors"
msgstr ""
@@ -7021,6 +7283,9 @@ msgstr ""
msgid "Could not change HEAD: branch '%{branch}' does not exist"
msgstr ""
+msgid "Could not commit. An unexpected error occurred."
+msgstr ""
+
msgid "Could not connect to FogBugz, check your URL"
msgstr ""
@@ -7060,6 +7325,9 @@ msgstr ""
msgid "Could not find iteration"
msgstr ""
+msgid "Could not load instance counts. Please refresh the page to try again."
+msgstr ""
+
msgid "Could not remove the trigger."
msgstr ""
@@ -7084,10 +7352,10 @@ msgstr ""
msgid "Could not save prometheus manual configuration"
msgstr ""
-msgid "Could not udpdate wiki page"
+msgid "Could not update the LDAP settings"
msgstr ""
-msgid "Could not update the LDAP settings"
+msgid "Could not update wiki page"
msgstr ""
msgid "Could not upload your designs as one or more files uploaded are not supported."
@@ -7745,6 +8013,9 @@ msgstr ""
msgid "DastProfiles|Are you sure you want to delete this profile?"
msgstr ""
+msgid "DastProfiles|Could not create site validation token. Please refresh the page, or try again later."
+msgstr ""
+
msgid "DastProfiles|Could not create the scanner profile. Please try again."
msgstr ""
@@ -7769,6 +8040,12 @@ msgstr ""
msgid "DastProfiles|Could not fetch site profiles. Please refresh the page, or try again later."
msgstr ""
+msgid "DastProfiles|Could not retrieve site validation status. Please refresh the page, or try again later."
+msgstr ""
+
+msgid "DastProfiles|Could not update the scanner profile. Please try again."
+msgstr ""
+
msgid "DastProfiles|Could not update the site profile. Please try again."
msgstr ""
@@ -7784,7 +8061,7 @@ msgstr ""
msgid "DastProfiles|Download validation text file"
msgstr ""
-msgid "DastProfiles|Edit feature will come soon. Please create a new profile if changes needed"
+msgid "DastProfiles|Edit scanner profile"
msgstr ""
msgid "DastProfiles|Edit site profile"
@@ -7817,6 +8094,9 @@ msgstr ""
msgid "DastProfiles|No profiles created yet"
msgstr ""
+msgid "DastProfiles|Passive"
+msgstr ""
+
msgid "DastProfiles|Please enter a valid URL format, ex: http://www.example.com/home"
msgstr ""
@@ -7832,6 +8112,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan mode"
+msgstr ""
+
msgid "DastProfiles|Scanner Profile"
msgstr ""
@@ -7871,10 +8154,10 @@ msgstr ""
msgid "DastProfiles|Text file validation"
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
+msgid "DastProfiles|The maximum number of minutes allowed for the spider to traverse the site."
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the spider to traverse the site."
+msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
msgstr ""
msgid "DastProfiles|Validate"
@@ -7907,6 +8190,9 @@ msgstr ""
msgid "Date picker"
msgstr ""
+msgid "Date range"
+msgstr ""
+
msgid "Date range cannot exceed %{maxDateRange} days."
msgstr ""
@@ -7931,6 +8217,9 @@ msgstr ""
msgid "Days to merge"
msgstr ""
+msgid "Dear Administrator,"
+msgstr ""
+
msgid "Debug"
msgstr ""
@@ -8042,12 +8331,18 @@ msgstr ""
msgid "Delete"
msgstr ""
+msgid "Delete %{name}"
+msgstr ""
+
msgid "Delete Comment"
msgstr ""
msgid "Delete Snippet"
msgstr ""
+msgid "Delete Value Stream"
+msgstr ""
+
msgid "Delete account"
msgstr ""
@@ -8069,9 +8364,6 @@ msgstr ""
msgid "Delete label: %{label_name} ?"
msgstr ""
-msgid "Delete license"
-msgstr ""
-
msgid "Delete list"
msgstr ""
@@ -8147,15 +8439,6 @@ msgstr ""
msgid "Deleting a project places it into a read-only state until %{date}, at which point the project will be permanently deleted. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "Deleting the license failed."
-msgstr ""
-
-msgid "Deleting the license failed. The license was not found."
-msgstr ""
-
-msgid "Deleting the license failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "Deleting the project will delete its repository and all related resources including issues, merge requests etc."
msgstr ""
@@ -8651,7 +8934,10 @@ msgstr ""
msgid "DesignManagement|The maximum number of designs allowed to be uploaded is %{upload_limit}. Please try again."
msgstr ""
-msgid "DesignManagement|To upload designs, you'll need to enable LFS. %{requirements_link_start}More information%{requirements_link_end}"
+msgid "DesignManagement|There was an error moving your designs. Please upload your designs below."
+msgstr ""
+
+msgid "DesignManagement|To upload designs, you'll need to enable LFS and have admin enable hashed storage. %{requirements_link_start}More information%{requirements_link_end}"
msgstr ""
msgid "DesignManagement|Unresolve thread"
@@ -8663,6 +8949,9 @@ msgstr ""
msgid "DesignManagement|Upload skipped."
msgstr ""
+msgid "DesignManagement|Your designs are being copied and are on their way… Please refresh to update."
+msgstr ""
+
msgid "DesignManagement|and %{moreCount} more."
msgstr ""
@@ -8720,6 +9009,9 @@ msgstr ""
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
+msgid "Direct member"
+msgstr ""
+
msgid "Direction"
msgstr ""
@@ -8768,9 +9060,6 @@ msgstr ""
msgid "Discard draft"
msgstr ""
-msgid "Discard review"
-msgstr ""
-
msgid "DiscordService|Discord Notifications"
msgstr ""
@@ -8839,10 +9128,10 @@ msgstr ""
msgid "Dismiss Merge Request promotion"
msgstr ""
-msgid "Dismiss Selected"
+msgid "Dismiss Value Stream Analytics introduction box"
msgstr ""
-msgid "Dismiss Value Stream Analytics introduction box"
+msgid "Dismiss selected"
msgstr ""
msgid "Dismiss trial promotion"
@@ -8893,9 +9182,6 @@ msgstr ""
msgid "Documents reindexed: %{processed_documents} (%{percentage}%%)"
msgstr ""
-msgid "Doing"
-msgstr ""
-
msgid "Domain"
msgstr ""
@@ -9091,9 +9377,6 @@ msgstr ""
msgid "Edit environment"
msgstr ""
-msgid "Edit file"
-msgstr ""
-
msgid "Edit files in the editor and commit changes here"
msgstr ""
@@ -9106,6 +9389,12 @@ msgstr ""
msgid "Edit identity for %{user_name}"
msgstr ""
+msgid "Edit in Web IDE"
+msgstr ""
+
+msgid "Edit in single-file editor"
+msgstr ""
+
msgid "Edit issues"
msgstr ""
@@ -9133,10 +9422,10 @@ msgstr ""
msgid "Editing"
msgstr ""
-msgid "Elasticsearch"
+msgid "Elasticsearch AWS IAM credentials"
msgstr ""
-msgid "Elasticsearch AWS IAM credentials"
+msgid "Elasticsearch HTTP client timeout value in seconds."
msgstr ""
msgid "Elasticsearch indexing restrictions"
@@ -9145,9 +9434,6 @@ msgstr ""
msgid "Elasticsearch indexing started"
msgstr ""
-msgid "Elasticsearch integration. Elasticsearch AWS IAM."
-msgstr ""
-
msgid "Elasticsearch reindexing is already in progress"
msgstr ""
@@ -9175,9 +9461,6 @@ msgstr ""
msgid "Email Notification"
msgstr ""
-msgid "Email address"
-msgstr ""
-
msgid "Email could not be sent"
msgstr ""
@@ -9241,6 +9524,9 @@ msgstr ""
msgid "Emails sent from Service Desk will have this name"
msgstr ""
+msgid "Emails sent to %{email} will still be supported"
+msgstr ""
+
msgid "Emails separated by comma"
msgstr ""
@@ -9274,9 +9560,18 @@ msgstr ""
msgid "Enable"
msgstr ""
+msgid "Enable %{link_start}Gitpod%{link_end} integration to launch a development environment in your browser directly from GitLab."
+msgstr ""
+
msgid "Enable Auto DevOps"
msgstr ""
+msgid "Enable Gitpod"
+msgstr ""
+
+msgid "Enable Gitpod?"
+msgstr ""
+
msgid "Enable HTML emails"
msgstr ""
@@ -9406,9 +9701,6 @@ msgstr ""
msgid "Encountered an error while rendering: %{err}"
msgstr ""
-msgid "End date"
-msgstr ""
-
msgid "Ends at (UTC)"
msgstr ""
@@ -9568,7 +9860,7 @@ msgstr ""
msgid "EnvironmentsDashboard|The environments dashboard provides a summary of each project's environments' status, including pipeline and alert statuses."
msgstr ""
-msgid "EnvironmentsDashboard|This dashboard displays a maximum of 7 projects and 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
+msgid "EnvironmentsDashboard|This dashboard displays 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
msgstr ""
msgid "Environments|An error occurred while canceling the auto stop, please try again"
@@ -9889,6 +10181,9 @@ msgstr ""
msgid "Error deleting project. Check logs for error details."
msgstr ""
+msgid "Error fetching burnup chart data"
+msgstr ""
+
msgid "Error fetching diverging counts for branches. Please try again."
msgstr ""
@@ -9967,6 +10262,9 @@ msgstr ""
msgid "Error occurred when saving assignees"
msgstr ""
+msgid "Error occurred when saving reviewers"
+msgstr ""
+
msgid "Error occurred when toggling the notification subscription"
msgstr ""
@@ -10219,10 +10517,13 @@ msgstr ""
msgid "Expand all"
msgstr ""
-msgid "Expand approvers"
+msgid "Expand all files"
msgstr ""
-msgid "Expand dropdown"
+msgid "Expand all threads"
+msgstr ""
+
+msgid "Expand approvers"
msgstr ""
msgid "Expand milestones"
@@ -10393,6 +10694,9 @@ msgstr ""
msgid "Failed to create Merge Request. Please try again."
msgstr ""
+msgid "Failed to create To-Do for the design."
+msgstr ""
+
msgid "Failed to create a branch for this issue. Please try again."
msgstr ""
@@ -10432,6 +10736,12 @@ msgstr ""
msgid "Failed to load authors. Please try again."
msgstr ""
+msgid "Failed to load branches. Please try again."
+msgstr ""
+
+msgid "Failed to load deploy keys."
+msgstr ""
+
msgid "Failed to load emoji list."
msgstr ""
@@ -10447,6 +10757,9 @@ msgstr ""
msgid "Failed to load groups & users."
msgstr ""
+msgid "Failed to load groups, users and deploy keys."
+msgstr ""
+
msgid "Failed to load labels. Please try again."
msgstr ""
@@ -10456,6 +10769,12 @@ msgstr ""
msgid "Failed to load related branches"
msgstr ""
+msgid "Failed to load sidebar confidential toggle"
+msgstr ""
+
+msgid "Failed to load sidebar lock status"
+msgstr ""
+
msgid "Failed to load stacktrace."
msgstr ""
@@ -10483,6 +10802,9 @@ msgstr ""
msgid "Failed to publish issue on status page."
msgstr ""
+msgid "Failed to remove To-Do for the design."
+msgstr ""
+
msgid "Failed to remove a Zoom meeting"
msgstr ""
@@ -10525,6 +10847,9 @@ msgstr ""
msgid "Failed to signing using smartcard authentication"
msgstr ""
+msgid "Failed to toggle To-Do for the design."
+msgstr ""
+
msgid "Failed to update branch!"
msgstr ""
@@ -10638,7 +10963,7 @@ msgstr ""
msgid "FeatureFlags|Edit User List"
msgstr ""
-msgid "FeatureFlags|Enable features for specific users and specific environments by defining feature flag strategies."
+msgid "FeatureFlags|Enable features for specific users and environments by configuring feature flag strategies."
msgstr ""
msgid "FeatureFlags|Environment Spec"
@@ -10698,7 +11023,7 @@ msgstr ""
msgid "FeatureFlags|Include additional user IDs"
msgstr ""
-msgid "FeatureFlags|Install a %{docs_link_anchored_start}compatible client library%{docs_link_anchored_end} and specify the API URL, application name, and instance ID during the configuration setup. %{docs_link_start}More Information%{docs_link_end}"
+msgid "FeatureFlags|Install a %{docsLinkAnchoredStart}compatible client library%{docsLinkAnchoredEnd} and specify the API URL, application name, and instance ID during the configuration setup. %{docsLinkStart}More Information%{docsLinkEnd}"
msgstr ""
msgid "FeatureFlags|Instance ID"
@@ -10710,6 +11035,9 @@ msgstr ""
msgid "FeatureFlags|Loading feature flags"
msgstr ""
+msgid "FeatureFlags|Loading user lists"
+msgstr ""
+
msgid "FeatureFlags|More information"
msgstr ""
@@ -10728,7 +11056,7 @@ msgstr ""
msgid "FeatureFlags|New feature flag"
msgstr ""
-msgid "FeatureFlags|New list"
+msgid "FeatureFlags|New user list"
msgstr ""
msgid "FeatureFlags|Percent of users"
@@ -10767,6 +11095,9 @@ msgstr ""
msgid "FeatureFlags|There was an error fetching the feature flags."
msgstr ""
+msgid "FeatureFlags|There was an error fetching the user lists."
+msgstr ""
+
msgid "FeatureFlags|There was an error retrieving user lists"
msgstr ""
@@ -10782,6 +11113,9 @@ msgstr ""
msgid "FeatureFlags|User List"
msgstr ""
+msgid "FeatureFlags|User Lists"
+msgstr ""
+
msgid "FeatureFlag|List"
msgstr ""
@@ -10809,15 +11143,6 @@ msgstr ""
msgid "Fetching incoming email"
msgstr ""
-msgid "Fetching licenses failed."
-msgstr ""
-
-msgid "Fetching licenses failed. The request endpoint was not found."
-msgstr ""
-
-msgid "Fetching licenses failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "File"
msgstr ""
@@ -10920,12 +11245,21 @@ msgstr ""
msgid "Filter by status"
msgstr ""
+msgid "Filter by test cases that are currently archived."
+msgstr ""
+
+msgid "Filter by test cases that are currently opened."
+msgstr ""
+
msgid "Filter by two-factor authentication"
msgstr ""
msgid "Filter by user"
msgstr ""
+msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
+msgstr ""
+
msgid "Filter pipelines"
msgstr ""
@@ -10941,7 +11275,7 @@ msgstr ""
msgid "Filter results..."
msgstr ""
-msgid "Filter your projects by name"
+msgid "Filter your repositories by name"
msgstr ""
msgid "Filter..."
@@ -10950,7 +11284,7 @@ msgstr ""
msgid "Find File"
msgstr ""
-msgid "Find bugs in your code with coverage-guided fuzzing"
+msgid "Find bugs in your code with coverage-guided fuzzing."
msgstr ""
msgid "Find by path"
@@ -10977,9 +11311,6 @@ msgstr ""
msgid "Finish editing this message first!"
msgstr ""
-msgid "Finish review"
-msgstr ""
-
msgid "Finish setting up your dedicated account for %{group_name}."
msgstr ""
@@ -11049,6 +11380,9 @@ msgstr ""
msgid "Footer message"
msgstr ""
+msgid "For a faster browsing experience, some files are collapsed by default."
+msgstr ""
+
msgid "For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
@@ -11058,6 +11392,9 @@ msgstr ""
msgid "For more info, read the documentation."
msgstr ""
+msgid "For more information on how the number of active users is calculated, see the %{self_managed_subscriptions_doc_link} documentation."
+msgstr ""
+
msgid "For more information, go to the "
msgstr ""
@@ -11196,6 +11533,9 @@ msgstr ""
msgid "Generate new token"
msgstr ""
+msgid "Generic package file size in bytes"
+msgstr ""
+
msgid "Geo"
msgstr ""
@@ -11457,6 +11797,9 @@ msgstr ""
msgid "Geo|Please refer to Geo Troubleshooting."
msgstr ""
+msgid "Geo|Primary node"
+msgstr ""
+
msgid "Geo|Project"
msgstr ""
@@ -11499,6 +11842,9 @@ msgstr ""
msgid "Geo|Review replication status, and resynchronize and reverify items with the primary node."
msgstr ""
+msgid "Geo|Secondary node"
+msgstr ""
+
msgid "Geo|Status"
msgstr ""
@@ -11538,6 +11884,9 @@ msgstr ""
msgid "Geo|URL must be a valid url (ex: https://gitlab.com)"
msgstr ""
+msgid "Geo|Undefined"
+msgstr ""
+
msgid "Geo|Unknown state"
msgstr ""
@@ -11613,10 +11962,16 @@ msgstr ""
msgid "GitHub import"
msgstr ""
+msgid "GitLab"
+msgstr ""
+
msgid "GitLab / Unsubscribe"
msgstr ""
-msgid "GitLab Enterprise Edition %{plan}"
+msgid "GitLab API"
+msgstr ""
+
+msgid "GitLab Billing Team."
msgstr ""
msgid "GitLab Group Runners can execute code for all the projects in this group."
@@ -11628,12 +11983,18 @@ msgstr ""
msgid "GitLab Issue"
msgstr ""
+msgid "GitLab Pages"
+msgstr ""
+
msgid "GitLab Service Desk is a simple way to allow people to create issues in your GitLab instance without needing their own user account. It provides a unique email address for end users to create issues in a project, and replies can be sent either through the GitLab interface or by email. End users will only see the thread through email."
msgstr ""
msgid "GitLab Shared Runners execute code of different projects on the same Runner unless you configure GitLab Runner Autoscale with MaxBuilds 1 (which it is on GitLab.com)."
msgstr ""
+msgid "GitLab Shell"
+msgstr ""
+
msgid "GitLab Support Bot"
msgstr ""
@@ -11643,7 +12004,7 @@ msgstr ""
msgid "GitLab User"
msgstr ""
-msgid "GitLab allows you to continue using your license even if you exceed the number of seats you purchased. You will be required to pay for these seats when you renew your license."
+msgid "GitLab Workhorse"
msgstr ""
msgid "GitLab commit"
@@ -11811,6 +12172,21 @@ msgstr ""
msgid "Gitlab Pages"
msgstr ""
+msgid "Gitpod"
+msgstr ""
+
+msgid "Gitpod|Add the URL to your Gitpod instance configured to read your GitLab projects."
+msgstr ""
+
+msgid "Gitpod|Enable Gitpod integration"
+msgstr ""
+
+msgid "Gitpod|Gitpod URL"
+msgstr ""
+
+msgid "Gitpod|e.g. https://gitpod.example.com"
+msgstr ""
+
msgid "Given access %{time_ago}"
msgstr ""
@@ -12318,9 +12694,6 @@ msgstr ""
msgid "GroupSAML|Valid SAML Response"
msgstr ""
-msgid "GroupSAML|With group managed accounts enabled, all the users without a group managed account will be excluded from the group."
-msgstr ""
-
msgid "GroupSAML|With prohibit outer forks flag enabled group members will be able to fork project only inside your group."
msgstr ""
@@ -12534,10 +12907,10 @@ msgstr ""
msgid "GroupsNew|Create group"
msgstr ""
-msgid "GroupsNew|GitLab group export"
+msgid "GroupsNew|Import"
msgstr ""
-msgid "GroupsNew|Import"
+msgid "GroupsNew|Import a GitLab group export file"
msgstr ""
msgid "GroupsNew|Import group"
@@ -12680,6 +13053,9 @@ msgid_plural "Hide charts"
msgstr[0] ""
msgstr[1] ""
+msgid "Hide comments on this file"
+msgstr ""
+
msgid "Hide details"
msgstr ""
@@ -12724,6 +13100,15 @@ msgstr ""
msgid "Highest role:"
msgstr ""
+msgid "HighlightBar|Alert events:"
+msgstr ""
+
+msgid "HighlightBar|Alert start time:"
+msgstr ""
+
+msgid "HighlightBar|Original alert:"
+msgstr ""
+
msgid "History"
msgstr ""
@@ -12901,6 +13286,9 @@ msgstr ""
msgid "If enabled, access to projects will be validated on an external service using their classification label."
msgstr ""
+msgid "If the number of active users exceeds the user limit, you will be charged for the number of %{users_over_license_link} at your next license reconciliation."
+msgstr ""
+
msgid "If there is no previous license or if the previous license has expired, some GitLab functionality will be blocked until a new, valid license is uploaded."
msgstr ""
@@ -12940,9 +13328,6 @@ msgstr ""
msgid "If your HTTP repository is not publicly accessible, add your credentials."
msgstr ""
-msgid "Iglu registry URL (optional)"
-msgstr ""
-
msgid "Ignore"
msgstr ""
@@ -12979,6 +13364,16 @@ msgstr ""
msgid "Import"
msgstr ""
+msgid "Import %d compatible repository"
+msgid_plural "Import %d compatible repositories"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Import %d repository"
+msgid_plural "Import %d repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Import CSV"
msgstr ""
@@ -12988,15 +13383,9 @@ msgstr ""
msgid "Import all compatible projects"
msgstr ""
-msgid "Import all compatible repositories"
-msgstr ""
-
msgid "Import all projects"
msgstr ""
-msgid "Import all repositories"
-msgstr ""
-
msgid "Import an exported GitLab project"
msgstr ""
@@ -13084,6 +13473,9 @@ msgstr ""
msgid "ImportProjects|Error importing repository %{project_safe_import_url} into %{project_full_path} - %{message}"
msgstr ""
+msgid "ImportProjects|Import repositories"
+msgstr ""
+
msgid "ImportProjects|Importing the project failed"
msgstr ""
@@ -13096,7 +13488,7 @@ msgstr ""
msgid "ImportProjects|Requesting your %{provider} repositories failed"
msgstr ""
-msgid "ImportProjects|Select the projects you want to import"
+msgid "ImportProjects|Select the repositories you want to import"
msgstr ""
msgid "ImportProjects|The remote data could not be imported."
@@ -13132,9 +13524,6 @@ msgstr ""
msgid "In order to enable Service Desk for your instance, you must first set up incoming email."
msgstr ""
-msgid "In order to gather accurate feature usage data, it can take 1 to 2 weeks to see your index."
-msgstr ""
-
msgid "In order to personalize your experience with GitLab%{br_tag}we would like to know a bit more about you."
msgstr ""
@@ -13165,18 +13554,30 @@ msgstr ""
msgid "IncidentManagement|Create incident"
msgstr ""
+msgid "IncidentManagement|Critical - S1"
+msgstr ""
+
msgid "IncidentManagement|Date created"
msgstr ""
msgid "IncidentManagement|Display your incidents in a dedicated view"
msgstr ""
+msgid "IncidentManagement|High - S2"
+msgstr ""
+
msgid "IncidentManagement|Incident"
msgstr ""
msgid "IncidentManagement|Incidents"
msgstr ""
+msgid "IncidentManagement|Low - S4"
+msgstr ""
+
+msgid "IncidentManagement|Medium - S3"
+msgstr ""
+
msgid "IncidentManagement|No incidents to display."
msgstr ""
@@ -13189,6 +13590,9 @@ msgstr ""
msgid "IncidentManagement|Published to status page"
msgstr ""
+msgid "IncidentManagement|Severity"
+msgstr ""
+
msgid "IncidentManagement|There are no closed incidents"
msgstr ""
@@ -13198,6 +13602,9 @@ msgstr ""
msgid "IncidentManagement|Unassigned"
msgstr ""
+msgid "IncidentManagement|Unknown"
+msgstr ""
+
msgid "IncidentManagement|Unpublished"
msgstr ""
@@ -13219,6 +13626,15 @@ msgstr ""
msgid "Incidents"
msgstr ""
+msgid "Incident|Alert details"
+msgstr ""
+
+msgid "Incident|Summary"
+msgstr ""
+
+msgid "Incident|There was an issue loading alert data. Please try again."
+msgstr ""
+
msgid "Include a Terms of Service agreement and Privacy Policy that all users must accept."
msgstr ""
@@ -13279,6 +13695,9 @@ msgstr ""
msgid "Information about additional Pages templates and how to install them can be found in our %{pages_getting_started_guide}."
msgstr ""
+msgid "Inherited"
+msgstr ""
+
msgid "Inherited:"
msgstr ""
@@ -13359,7 +13778,22 @@ msgstr ""
msgid "Instance administrators group already exists"
msgstr ""
-msgid "Instance license"
+msgid "InstanceStatistics|Groups"
+msgstr ""
+
+msgid "InstanceStatistics|Issues"
+msgstr ""
+
+msgid "InstanceStatistics|Merge Requests"
+msgstr ""
+
+msgid "InstanceStatistics|Pipelines"
+msgstr ""
+
+msgid "InstanceStatistics|Projects"
+msgstr ""
+
+msgid "InstanceStatistics|Users"
msgstr ""
msgid "Integration"
@@ -13371,6 +13805,12 @@ msgstr ""
msgid "Integrations"
msgstr ""
+msgid "Integrations|%{integration} settings saved and active."
+msgstr ""
+
+msgid "Integrations|%{integration} settings saved, but not active."
+msgstr ""
+
msgid "Integrations|All details"
msgstr ""
@@ -13380,6 +13820,12 @@ msgstr ""
msgid "Integrations|Comment settings:"
msgstr ""
+msgid "Integrations|Connection failed. Please check your settings."
+msgstr ""
+
+msgid "Integrations|Connection successful."
+msgstr ""
+
msgid "Integrations|Default settings are inherited from the group level."
msgstr ""
@@ -13395,6 +13841,15 @@ msgstr ""
msgid "Integrations|Includes commit title and branch"
msgstr ""
+msgid "Integrations|Projects using custom settings will not be impacted unless the project owner chooses to use instance-level defaults."
+msgstr ""
+
+msgid "Integrations|Save settings?"
+msgstr ""
+
+msgid "Integrations|Saving will update the default settings for all projects that are not using custom settings."
+msgstr ""
+
msgid "Integrations|Standard"
msgstr ""
@@ -13527,6 +13982,9 @@ msgstr ""
msgid "Invitation"
msgstr ""
+msgid "Invitation declined"
+msgstr ""
+
msgid "Invite"
msgstr ""
@@ -13578,6 +14036,42 @@ 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|%{linkStart}Read more%{linkEnd} about role permissions"
+msgstr ""
+
+msgid "InviteMembersModal|Access expiration date (optional)"
+msgstr ""
+
+msgid "InviteMembersModal|Cancel"
+msgstr ""
+
+msgid "InviteMembersModal|Choose a role permission"
+msgstr ""
+
+msgid "InviteMembersModal|GitLab member or Email address"
+msgstr ""
+
+msgid "InviteMembersModal|Invite"
+msgstr ""
+
+msgid "InviteMembersModal|Invite team members"
+msgstr ""
+
+msgid "InviteMembersModal|Search for members to invite"
+msgstr ""
+
+msgid "InviteMembersModal|User not invited. Feature coming soon!"
+msgstr ""
+
+msgid "InviteMembersModal|Users were succesfully added"
+msgstr ""
+
+msgid "InviteMembersModal|You're inviting members to the %{group_name} group"
+msgstr ""
+
+msgid "InviteMembers|Invite team members"
+msgstr ""
+
msgid "Invited"
msgstr ""
@@ -13632,10 +14126,13 @@ msgstr ""
msgid "Issue cannot be found."
msgstr ""
+msgid "Issue created from vulnerability %{vulnerability_link}"
+msgstr ""
+
msgid "Issue events"
msgstr ""
-msgid "Issue first depoloyed to production"
+msgid "Issue first deployed to production"
msgstr ""
msgid "Issue label"
@@ -13713,6 +14210,9 @@ msgstr ""
msgid "IssueTracker|Custom issue tracker"
msgstr ""
+msgid "IssueTracker|EWM work items tracker"
+msgstr ""
+
msgid "IssueTracker|Redmine issue tracker"
msgstr ""
@@ -13779,6 +14279,9 @@ msgstr ""
msgid "It looks like you have some draft commits in this branch."
msgstr ""
+msgid "It may be several days before you see feature usage data."
+msgstr ""
+
msgid "It must have a header row and at least two columns: the first column is the issue title and the second column is the issue description. The separator is automatically detected."
msgstr ""
@@ -14061,13 +14564,13 @@ msgstr ""
msgid "Join Zoom meeting"
msgstr ""
-msgid "Jul"
+msgid "Joined %{time_ago}"
msgstr ""
-msgid "July"
+msgid "Jul"
msgstr ""
-msgid "Jump to first unresolved thread"
+msgid "July"
msgstr ""
msgid "Jump to next unresolved thread"
@@ -14103,6 +14606,9 @@ msgstr ""
msgid "Keyboard shortcuts"
msgstr ""
+msgid "KeyboardKey|Ctrl+"
+msgstr ""
+
msgid "Keys"
msgstr ""
@@ -14151,6 +14657,9 @@ msgstr ""
msgid "LDAP Synchronization"
msgstr ""
+msgid "LDAP group settings"
+msgstr ""
+
msgid "LDAP settings"
msgstr ""
@@ -14160,6 +14669,9 @@ msgstr ""
msgid "LDAP sync in progress. This could take a few minutes. Refresh the page to see the changes."
msgstr ""
+msgid "LDAP synchronizations"
+msgstr ""
+
msgid "LFS"
msgstr ""
@@ -14240,7 +14752,16 @@ msgid_plural "Last %d days"
msgstr[0] ""
msgstr[1] ""
-msgid "Last %{days} days"
+msgid "Last 2 weeks"
+msgstr ""
+
+msgid "Last 30 days"
+msgstr ""
+
+msgid "Last 60 days"
+msgstr ""
+
+msgid "Last 90 days"
msgstr ""
msgid "Last Accessed On"
@@ -14318,6 +14839,9 @@ msgstr ""
msgid "Last used on:"
msgstr ""
+msgid "Last week"
+msgstr ""
+
msgid "LastCommit|authored"
msgstr ""
@@ -14333,6 +14857,9 @@ msgstr ""
msgid "Latest pipeline for the most recent commit on this branch"
msgstr ""
+msgid "Launch a ready-to-code development environment for your project."
+msgstr ""
+
msgid "Lead"
msgstr ""
@@ -14713,6 +15240,9 @@ msgstr ""
msgid "List of all merge commits"
msgstr ""
+msgid "List options"
+msgstr ""
+
msgid "List settings"
msgstr ""
@@ -14725,9 +15255,6 @@ msgstr ""
msgid "List your Bitbucket Server repositories"
msgstr ""
-msgid "Lists"
-msgstr ""
-
msgid "Live preview"
msgstr ""
@@ -14974,6 +15501,12 @@ msgstr ""
msgid "Mark as done"
msgstr ""
+msgid "Mark as draft"
+msgstr ""
+
+msgid "Mark as ready"
+msgstr ""
+
msgid "Mark as resolved"
msgstr ""
@@ -14995,6 +15528,24 @@ msgstr ""
msgid "Markdown is supported"
msgstr ""
+msgid "MarkdownEditor|Add a link (%{modifierKey}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add a link (%{modifier_key}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifierKey}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifier_key}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifierKey}I)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifier_key}I)"
+msgstr ""
+
msgid "Marked For Deletion At - %{deletion_time}"
msgstr ""
@@ -15079,7 +15630,25 @@ msgstr ""
msgid "Max access level"
msgstr ""
-msgid "Max seats used"
+msgid "Max role"
+msgstr ""
+
+msgid "Max size 15 MB"
+msgstr ""
+
+msgid "Maximum Conan package file size in bytes"
+msgstr ""
+
+msgid "Maximum Maven package file size in bytes"
+msgstr ""
+
+msgid "Maximum NPM package file size in bytes"
+msgstr ""
+
+msgid "Maximum NuGet package file size in bytes"
+msgstr ""
+
+msgid "Maximum PyPI package file size in bytes"
msgstr ""
msgid "Maximum Users:"
@@ -15211,6 +15780,18 @@ msgstr ""
msgid "Members with access to %{strong_start}%{group_name}%{strong_end}"
msgstr ""
+msgid "Members|%{time} by %{user}"
+msgstr ""
+
+msgid "Members|Expired"
+msgstr ""
+
+msgid "Members|No expiration set"
+msgstr ""
+
+msgid "Members|in %{time}"
+msgstr ""
+
msgid "Memory Usage"
msgstr ""
@@ -15397,9 +15978,6 @@ msgstr ""
msgid "MergeRequests|Thread will be unresolved"
msgstr ""
-msgid "MergeRequests|Toggle comments for this file"
-msgstr ""
-
msgid "MergeRequests|View file @ %{commitId}"
msgstr ""
@@ -15460,6 +16038,9 @@ msgstr ""
msgid "Merging immediately isn't recommended as it may negatively impact the existing merge train. Read the %{docsLinkStart}documentation%{docsLinkEnd} for more information."
msgstr ""
+msgid "Message"
+msgstr ""
+
msgid "Messages"
msgstr ""
@@ -15845,18 +16426,12 @@ msgid_plural "Milestones"
msgstr[0] ""
msgstr[1] ""
-msgid "Milestone does not support burnup charts"
-msgstr ""
-
msgid "Milestone lists not available with your current license"
msgstr ""
msgid "Milestone lists show all issues from the selected milestone."
msgstr ""
-msgid "Milestone must have a start and due date"
-msgstr ""
-
msgid "MilestoneSidebar|Closed:"
msgstr ""
@@ -16223,6 +16798,9 @@ msgstr ""
msgid "Namespace"
msgstr ""
+msgid "Namespace ID:"
+msgstr ""
+
msgid "Namespace is empty"
msgstr ""
@@ -16307,6 +16885,9 @@ msgstr ""
msgid "NetworkPolicies|Allow all outbound traffic from %{selector} to %{ruleSelector} on %{ports}"
msgstr ""
+msgid "NetworkPolicies|Are you sure you want to delete this policy? This action cannot be undone."
+msgstr ""
+
msgid "NetworkPolicies|Choose whether to enforce this policy."
msgstr ""
@@ -16316,12 +16897,21 @@ msgstr ""
msgid "NetworkPolicies|Define this policy's location, conditions and actions."
msgstr ""
+msgid "NetworkPolicies|Delete policy"
+msgstr ""
+
+msgid "NetworkPolicies|Delete policy: %{policy}"
+msgstr ""
+
msgid "NetworkPolicies|Deny all traffic"
msgstr ""
msgid "NetworkPolicies|Description"
msgstr ""
+msgid "NetworkPolicies|Edit policy"
+msgstr ""
+
msgid "NetworkPolicies|Editor mode"
msgstr ""
@@ -16349,6 +16939,9 @@ msgstr ""
msgid "NetworkPolicies|Name"
msgstr ""
+msgid "NetworkPolicies|Namespace"
+msgstr ""
+
msgid "NetworkPolicies|Network Policy"
msgstr ""
@@ -16400,6 +16993,9 @@ msgstr ""
msgid "NetworkPolicies|Rules"
msgstr ""
+msgid "NetworkPolicies|Save changes"
+msgstr ""
+
msgid "NetworkPolicies|Something went wrong, failed to update policy"
msgstr ""
@@ -16412,6 +17008,9 @@ msgstr ""
msgid "NetworkPolicies|Traffic that does not match any rule will be blocked."
msgstr ""
+msgid "NetworkPolicies|Unable to parse policy"
+msgstr ""
+
msgid "NetworkPolicies|YAML editor"
msgstr ""
@@ -16525,6 +17124,9 @@ msgstr ""
msgid "New Snippet"
msgstr ""
+msgid "New Test Case"
+msgstr ""
+
msgid "New User"
msgstr ""
@@ -16624,6 +17226,9 @@ msgstr ""
msgid "New tag"
msgstr ""
+msgid "New test case"
+msgstr ""
+
msgid "New users set to external"
msgstr ""
@@ -16696,7 +17301,7 @@ msgstr ""
msgid "No changes"
msgstr ""
-msgid "No changes between %{ref_start}%{source_branch}%{ref_end} and %{ref_start}%{target_branch}%{ref_end}"
+msgid "No changes between %{sourceBranch} and %{targetBranch}"
msgstr ""
msgid "No child epics match applied filters"
@@ -16711,6 +17316,9 @@ msgstr ""
msgid "No containers available"
msgstr ""
+msgid "No content to show"
+msgstr ""
+
msgid "No contributions"
msgstr ""
@@ -16786,9 +17394,6 @@ msgstr ""
msgid "No license. All rights reserved"
msgstr ""
-msgid "No licenses found."
-msgstr ""
-
msgid "No matches found"
msgstr ""
@@ -16801,6 +17406,9 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No members found"
+msgstr ""
+
msgid "No merge requests found"
msgstr ""
@@ -16822,6 +17430,9 @@ msgstr ""
msgid "No parent group"
msgstr ""
+msgid "No plan"
+msgstr ""
+
msgid "No pods available"
msgstr ""
@@ -16918,6 +17529,12 @@ msgstr ""
msgid "Not Implemented"
msgstr ""
+msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+msgstr ""
+
+msgid "Not all browsers support WebAuthn. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even from an unsupported browser."
+msgstr ""
+
msgid "Not all data has been processed yet, the accuracy of the chart for the selected timeframe is limited."
msgstr ""
@@ -17014,6 +17631,9 @@ msgstr ""
msgid "Notification settings saved"
msgstr ""
+msgid "NotificationEvent|Change reviewer merge request"
+msgstr ""
+
msgid "NotificationEvent|Close issue"
msgstr ""
@@ -17176,10 +17796,7 @@ msgstr ""
msgid "On track"
msgstr ""
-msgid "OnDemandScans|Attached branch"
-msgstr ""
-
-msgid "OnDemandScans|Attached branch is where the scan job runs."
+msgid "OnDemandScans|Could not fetch scanner profiles. Please refresh the page, or try again later."
msgstr ""
msgid "OnDemandScans|Could not fetch site profiles. Please refresh the page, or try again later."
@@ -17188,6 +17805,9 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
+msgid "OnDemandScans|Create a new scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Create a new site profile"
msgstr ""
@@ -17200,6 +17820,9 @@ msgstr ""
msgid "OnDemandScans|New on-demand DAST scan"
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 ""
@@ -17209,16 +17832,10 @@ msgstr ""
msgid "OnDemandScans|On-demand scans run outside the DevOps cycle and find vulnerabilities in your projects. %{learnMoreLinkStart}Learn more%{learnMoreLinkEnd}"
msgstr ""
-msgid "OnDemandScans|Only a passive scan can be performed on demand."
-msgstr ""
-
-msgid "OnDemandScans|Passive"
-msgstr ""
-
msgid "OnDemandScans|Run scan"
msgstr ""
-msgid "OnDemandScans|Scan mode"
+msgid "OnDemandScans|Scanner profile"
msgstr ""
msgid "OnDemandScans|Scanner settings"
@@ -17230,9 +17847,15 @@ msgstr ""
msgid "OnDemandScans|Select one of the existing profiles"
msgstr ""
+msgid "OnDemandScans|Site profile"
+msgstr ""
+
msgid "OnDemandScans|Site profiles"
msgstr ""
+msgid "OnDemandScans|Use existing scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Use existing site profile"
msgstr ""
@@ -17331,9 +17954,6 @@ msgstr ""
msgid "Open Selection"
msgstr ""
-msgid "Open Web IDE"
-msgstr ""
-
msgid "Open comment type dropdown"
msgstr ""
@@ -17439,6 +18059,9 @@ msgstr ""
msgid "Origin"
msgstr ""
+msgid "Orphaned member"
+msgstr ""
+
msgid "Other Labels"
msgstr ""
@@ -17454,6 +18077,9 @@ msgstr ""
msgid "Other visibility settings have been disabled by the administrator."
msgstr ""
+msgid "Our documentation includes an example DevOps Score report."
+msgstr ""
+
msgid "Out-of-compliance with this project's policies and should be removed"
msgstr ""
@@ -17478,6 +18104,9 @@ msgstr ""
msgid "Overwrite diverged branches"
msgstr ""
+msgid "Owned by %{image_tag}"
+msgstr ""
+
msgid "Owned by anyone"
msgstr ""
@@ -17499,6 +18128,9 @@ msgstr ""
msgid "Package deleted successfully"
msgstr ""
+msgid "Package file size limits"
+msgstr ""
+
msgid "Package recipe already exists"
msgstr ""
@@ -17514,9 +18146,6 @@ msgstr ""
msgid "Package type must be PyPi"
msgstr ""
-msgid "Package was removed"
-msgstr ""
-
msgid "PackageRegistry|%{name} version %{version} was created %{datetime}"
msgstr ""
@@ -17658,12 +18287,18 @@ msgstr ""
msgid "PackageRegistry|NuGet Command"
msgstr ""
+msgid "PackageRegistry|Package Registry"
+msgstr ""
+
msgid "PackageRegistry|Pip Command"
msgstr ""
msgid "PackageRegistry|Pipeline %{link} triggered %{datetime} by %{author}"
msgstr ""
+msgid "PackageRegistry|Publish and share packages for a variety of common package managers. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "PackageRegistry|Published to the %{project} Package Registry %{datetime}"
msgstr ""
@@ -17763,6 +18398,9 @@ msgstr ""
msgid "Page not found"
msgstr ""
+msgid "Page settings"
+msgstr ""
+
msgid "Page was successfully deleted"
msgstr ""
@@ -17904,7 +18542,7 @@ msgstr ""
msgid "Paste issue link"
msgstr ""
-msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Don't use your private SSH key."
+msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Do not paste your private SSH key, as that can compromise your identity."
msgstr ""
msgid "Patch to apply"
@@ -17931,6 +18569,9 @@ msgstr ""
msgid "Pending"
msgstr ""
+msgid "Pending comments"
+msgstr ""
+
msgid "People without permission will never get a notification and won't be able to comment."
msgstr ""
@@ -18129,6 +18770,9 @@ msgstr ""
msgid "Pipelines|Build with confidence"
msgstr ""
+msgid "Pipelines|By revoking a trigger you will break any processes making use of it. Are you sure?"
+msgstr ""
+
msgid "Pipelines|CI Lint"
msgstr ""
@@ -18141,6 +18785,15 @@ msgstr ""
msgid "Pipelines|Continuous Integration can help catch bugs by running your tests automatically, while Continuous Deployment can help you deliver code to your product environment."
msgstr ""
+msgid "Pipelines|Copy trigger token"
+msgstr ""
+
+msgid "Pipelines|Description"
+msgstr ""
+
+msgid "Pipelines|Edit"
+msgstr ""
+
msgid "Pipelines|Get started with Pipelines"
msgstr ""
@@ -18156,15 +18809,27 @@ msgstr ""
msgid "Pipelines|It is recommended the code is reviewed thoroughly before running this pipeline with the parent project's CI resource."
msgstr ""
+msgid "Pipelines|Last Used"
+msgstr ""
+
msgid "Pipelines|Loading Pipelines"
msgstr ""
msgid "Pipelines|More Information"
msgstr ""
+msgid "Pipelines|No triggers have been created yet. Add one using the form above."
+msgstr ""
+
+msgid "Pipelines|Owner"
+msgstr ""
+
msgid "Pipelines|Project cache successfully reset."
msgstr ""
+msgid "Pipelines|Revoke"
+msgstr ""
+
msgid "Pipelines|Run Pipeline"
msgstr ""
@@ -18189,6 +18854,15 @@ msgstr ""
msgid "Pipelines|This project is not currently set up to run pipelines."
msgstr ""
+msgid "Pipelines|Token"
+msgstr ""
+
+msgid "Pipelines|Trigger user has insufficient permissions to project"
+msgstr ""
+
+msgid "Pipelines|invalid"
+msgstr ""
+
msgid "Pipelines|parent"
msgstr ""
@@ -18447,10 +19121,10 @@ msgstr ""
msgid "Please provide attributes to update"
msgstr ""
-msgid "Please refer to %{docs_url}"
+msgid "Please reach out if you have any questions and we'll be happy to assist."
msgstr ""
-msgid "Please retype the email address."
+msgid "Please refer to %{docs_url}"
msgstr ""
msgid "Please select"
@@ -18480,6 +19154,9 @@ msgstr ""
msgid "Please set a new password before proceeding."
msgstr ""
+msgid "Please share your feedback about %{featureName} %{linkStart}in this issue%{linkEnd} to help us improve the experience."
+msgstr ""
+
msgid "Please solve the reCAPTCHA"
msgstr ""
@@ -18783,6 +19460,9 @@ msgstr ""
msgid "Profiles| You are going to change the username %{currentUsernameBold} to %{newUsernameBold}. Profile and projects will be redirected to the %{newUsername} namespace but this redirect will expire once the %{currentUsername} namespace is registered by another user or group. Please update your Git repository remotes as soon as possible."
msgstr ""
+msgid "Profiles|%{provider} Active"
+msgstr ""
+
msgid "Profiles|@username"
msgstr ""
@@ -18834,7 +19514,7 @@ msgstr ""
msgid "Profiles|Commit email"
msgstr ""
-msgid "Profiles|Connect"
+msgid "Profiles|Connect %{provider}"
msgstr ""
msgid "Profiles|Connected Accounts"
@@ -18858,6 +19538,9 @@ msgstr ""
msgid "Profiles|Disconnect"
msgstr ""
+msgid "Profiles|Disconnect %{provider}"
+msgstr ""
+
msgid "Profiles|Do not show on profile"
msgstr ""
@@ -18882,7 +19565,7 @@ msgstr ""
msgid "Profiles|Full name"
msgstr ""
-msgid "Profiles|Give your individual key a title. This will be publically visible."
+msgid "Profiles|Give your individual key a title."
msgstr ""
msgid "Profiles|Include private contributions on my profile"
@@ -18972,7 +19655,7 @@ msgstr ""
msgid "Profiles|The maximum file size allowed is 200KB."
msgstr ""
-msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it?"
+msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it? It will be publicly visible."
msgstr ""
msgid "Profiles|This email will be displayed on your public profile"
@@ -19047,6 +19730,9 @@ msgstr ""
msgid "Profiles|You don't have access to delete this user."
msgstr ""
+msgid "Profiles|You must transfer ownership or delete groups you are an owner of before you can delete your account"
+msgstr ""
+
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
@@ -19635,6 +20321,9 @@ msgstr ""
msgid "ProjectTemplates|GitLab Cluster Management"
msgstr ""
+msgid "ProjectTemplates|Gitpod/Spring Petclinic"
+msgstr ""
+
msgid "ProjectTemplates|Go Micro"
msgstr ""
@@ -20244,6 +20933,9 @@ msgstr ""
msgid "Publish to status page"
msgstr ""
+msgid "Published"
+msgstr ""
+
msgid "Published on status page"
msgstr ""
@@ -20361,9 +21053,15 @@ msgstr ""
msgid "Quick range"
msgstr ""
+msgid "Quickly and easily edit multiple files in your project."
+msgstr ""
+
msgid "README"
msgstr ""
+msgid "Rails"
+msgstr ""
+
msgid "Rake Tasks Help"
msgstr ""
@@ -20483,10 +21181,13 @@ msgstr ""
msgid "Register Two-Factor Authenticator"
msgstr ""
-msgid "Register U2F device"
+msgid "Register Universal Two-Factor (U2F) Device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register WebAuthn Device"
+msgstr ""
+
+msgid "Register device"
msgstr ""
msgid "Register for GitLab"
@@ -20498,9 +21199,6 @@ msgstr ""
msgid "Register with two-factor app"
msgstr ""
-msgid "Registration"
-msgstr ""
-
msgid "Registration|Checkout"
msgstr ""
@@ -20617,9 +21315,6 @@ msgstr ""
msgid "Release|Something went wrong while saving the release details"
msgstr ""
-msgid "Remediated: needs review"
-msgstr ""
-
msgid "Remediations"
msgstr ""
@@ -20725,6 +21420,9 @@ msgstr ""
msgid "Remove priority"
msgstr ""
+msgid "Remove report"
+msgstr ""
+
msgid "Remove secondary node"
msgstr ""
@@ -20737,6 +21435,12 @@ msgstr ""
msgid "Remove time estimate"
msgstr ""
+msgid "Remove user & report"
+msgstr ""
+
+msgid "Remove user from group"
+msgstr ""
+
msgid "Removed"
msgstr ""
@@ -20818,9 +21522,6 @@ msgstr ""
msgid "Removes time estimate."
msgstr ""
-msgid "Removing license…"
-msgstr ""
-
msgid "Removing this group also removes all child projects, including archived projects, and their resources."
msgstr ""
@@ -20905,6 +21606,9 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
+msgid "Reported by %{reporter}"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -20991,6 +21695,27 @@ msgstr ""
msgid "Repositories"
msgstr ""
+msgid "Repositories Analytics"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download Historic Test Coverage Data"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download historic test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Historic Test Coverage Data is available in raw format (.csv) for further analysis."
+msgstr ""
+
+msgid "RepositoriesAnalytics|Test Code Coverage"
+msgstr ""
+
+msgid "RepositoriesAnalytics|There was an error fetching the projects."
+msgstr ""
+
msgid "Repository"
msgstr ""
@@ -21069,9 +21794,15 @@ msgstr ""
msgid "Request parameter %{param} is missing."
msgstr ""
+msgid "Request review from"
+msgstr ""
+
msgid "Request to link SAML account must be authorized"
msgstr ""
+msgid "Requested"
+msgstr ""
+
msgid "Requested %{time_ago}"
msgstr ""
@@ -21090,6 +21821,9 @@ msgstr ""
msgid "Requests to these domain(s)/address(es) on the local network will be allowed when local requests from hooks and services are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 or 127.0.0.0/28 are supported. Domain wildcards are not supported currently. Use comma, semicolon, or newline to separate multiple entries. The allowlist can hold a maximum of 1000 entries. Domains should use IDNA encoding. Ex: example.com, 192.168.1.1, 127.0.0.0/28, xn--itlab-j1a.com."
msgstr ""
+msgid "Require admin approval for new sign-ups"
+msgstr ""
+
msgid "Require all users in this group to setup Two-factor authentication"
msgstr ""
@@ -21217,9 +21951,6 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
-msgid "Resolved by %{resolvedByName}"
-msgstr ""
-
msgid "Resolves IP addresses once and uses them to submit requests"
msgstr ""
@@ -21339,6 +22070,14 @@ msgstr ""
msgid "ReviewApp|Enable Review App"
msgstr ""
+msgid "Reviewer"
+msgid_plural "%d Reviewers"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Reviewer(s)"
+msgstr ""
+
msgid "Reviewing"
msgstr ""
@@ -21378,6 +22117,9 @@ msgstr ""
msgid "Rook"
msgstr ""
+msgid "Ruby"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -21456,6 +22198,63 @@ msgstr ""
msgid "Runners page."
msgstr ""
+msgid "Runners|Active"
+msgstr ""
+
+msgid "Runners|Architecture"
+msgstr ""
+
+msgid "Runners|Can run untagged jobs"
+msgstr ""
+
+msgid "Runners|Description"
+msgstr ""
+
+msgid "Runners|Group"
+msgstr ""
+
+msgid "Runners|IP Address"
+msgstr ""
+
+msgid "Runners|Last contact"
+msgstr ""
+
+msgid "Runners|Locked to this project"
+msgstr ""
+
+msgid "Runners|Maximum job timeout"
+msgstr ""
+
+msgid "Runners|Name"
+msgstr ""
+
+msgid "Runners|Platform"
+msgstr ""
+
+msgid "Runners|Property Name"
+msgstr ""
+
+msgid "Runners|Protected"
+msgstr ""
+
+msgid "Runners|Revision"
+msgstr ""
+
+msgid "Runners|Shared"
+msgstr ""
+
+msgid "Runners|Specific"
+msgstr ""
+
+msgid "Runners|Tags"
+msgstr ""
+
+msgid "Runners|Value"
+msgstr ""
+
+msgid "Runners|Version"
+msgstr ""
+
msgid "Runners|You have used %{quotaUsed} out of %{quotaLimit} of your shared Runners pipeline minutes."
msgstr ""
@@ -21468,6 +22267,9 @@ msgstr ""
msgid "Runs a number of housekeeping tasks within the current repository, such as compressing file revisions and removing unreachable objects."
msgstr ""
+msgid "SAML"
+msgstr ""
+
msgid "SAML SSO"
msgstr ""
@@ -21519,6 +22321,9 @@ msgstr ""
msgid "Save"
msgstr ""
+msgid "Save %{name} size limits"
+msgstr ""
+
msgid "Save Changes"
msgstr ""
@@ -21549,9 +22354,6 @@ msgstr ""
msgid "Save space and find tags in the Container Registry more easily. Enable the cleanup policy to remove stale tags and keep only the ones you need."
msgstr ""
-msgid "Save template"
-msgstr ""
-
msgid "Save variables"
msgstr ""
@@ -21594,9 +22396,6 @@ msgstr ""
msgid "Scope"
msgstr ""
-msgid "Scope not supported with disabled 'users_search' feature!"
-msgstr ""
-
msgid "Scoped issue boards"
msgstr ""
@@ -21723,9 +22522,6 @@ msgstr ""
msgid "Search requirements"
msgstr ""
-msgid "Search results…"
-msgstr ""
-
msgid "Search users"
msgstr ""
@@ -21798,6 +22594,11 @@ msgid_plural "SearchResults|commits"
msgstr[0] ""
msgstr[1] ""
+msgid "SearchResults|epic"
+msgid_plural "SearchResults|epics"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "SearchResults|issue"
msgid_plural "SearchResults|issues"
msgstr[0] ""
@@ -21842,10 +22643,10 @@ msgstr ""
msgid "Seat Link is disabled, and cannot be configured through this form."
msgstr ""
-msgid "Seats currently in use"
+msgid "Seats usage data as of %{last_enqueue_time}"
msgstr ""
-msgid "Seats in license"
+msgid "Seats usage data is updated every day at 12:00pm UTC"
msgstr ""
msgid "Secondary"
@@ -21899,6 +22700,9 @@ msgstr ""
msgid "SecurityConfiguration|Available for on-demand DAST"
msgstr ""
+msgid "SecurityConfiguration|By default, all analyzers are applied in order to cover all languages across your project, and only run if the language is detected in the Merge Request."
+msgstr ""
+
msgid "SecurityConfiguration|Configure"
msgstr ""
@@ -21929,16 +22733,19 @@ msgstr ""
msgid "SecurityConfiguration|Manage"
msgstr ""
+msgid "SecurityConfiguration|More information"
+msgstr ""
+
msgid "SecurityConfiguration|Not enabled"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|Security Control"
+msgid "SecurityConfiguration|SAST Configuration"
msgstr ""
-msgid "SecurityConfiguration|See documentation"
+msgid "SecurityConfiguration|Security Control"
msgstr ""
msgid "SecurityConfiguration|Status"
@@ -21950,6 +22757,9 @@ msgstr ""
msgid "SecurityConfiguration|Using custom settings. You won't receive automatic updates on this variable. %{anchorStart}Restore to default%{anchorEnd}"
msgstr ""
+msgid "SecurityConfiguration|View history"
+msgstr ""
+
msgid "SecurityConfiguration|You can quickly enable all security scanning tools by enabling %{linkStart}Auto DevOps%{linkEnd}."
msgstr ""
@@ -22028,9 +22838,6 @@ msgstr ""
msgid "SecurityReports|Learn more about setting up your dashboard"
msgstr ""
-msgid "SecurityReports|Load more vulnerabilities"
-msgstr ""
-
msgid "SecurityReports|Monitor vulnerabilities in your code"
msgstr ""
@@ -22310,7 +23117,7 @@ msgstr ""
msgid "Select status"
msgstr ""
-msgid "Select strategy activation method"
+msgid "Select strategy activation method."
msgstr ""
msgid "Select subscription"
@@ -22325,7 +23132,7 @@ msgstr ""
msgid "Select the custom project template source group."
msgstr ""
-msgid "Select timeframe"
+msgid "Select the environment scope for this feature flag."
msgstr ""
msgid "Select timezone"
@@ -22574,6 +23381,9 @@ msgstr ""
msgid "Set iteration"
msgstr ""
+msgid "Set limit to 0 to allow any file size."
+msgstr ""
+
msgid "Set max session time for web terminal."
msgstr ""
@@ -22652,10 +23462,13 @@ msgstr ""
msgid "Set up a %{type} Runner manually"
msgstr ""
+msgid "Set up a hardware device as a second factor to sign in."
+msgstr ""
+
msgid "Set up assertions/attributes/claims (email, first_name, last_name) and NameID according to %{docsLinkStart}the documentation %{icon}%{docsLinkEnd}"
msgstr ""
-msgid "Set up new U2F device"
+msgid "Set up new device"
msgstr ""
msgid "Set up new password"
@@ -22724,6 +23537,9 @@ msgstr ""
msgid "Sets weight to %{weight}."
msgstr ""
+msgid "Setting this to 0 means using the system default timeout value."
+msgstr ""
+
msgid "Settings"
msgstr ""
@@ -22739,6 +23555,15 @@ msgstr ""
msgid "Severity"
msgstr ""
+msgid "SeverityWidget|Severity"
+msgstr ""
+
+msgid "SeverityWidget|Severity: %{severity}"
+msgstr ""
+
+msgid "SeverityWidget|There was an error while updating severity."
+msgstr ""
+
msgid "Shards (%{shards})"
msgstr ""
@@ -22784,6 +23609,9 @@ msgstr ""
msgid "Show all requirements."
msgstr ""
+msgid "Show all test cases."
+msgstr ""
+
msgid "Show archived projects"
msgstr ""
@@ -22796,6 +23624,9 @@ msgstr ""
msgid "Show comments"
msgstr ""
+msgid "Show comments on this file"
+msgstr ""
+
msgid "Show comments only"
msgstr ""
@@ -22841,6 +23672,12 @@ msgstr ""
msgid "Show parent subgroups"
msgstr ""
+msgid "Show the Closed list"
+msgstr ""
+
+msgid "Show the Open list"
+msgstr ""
+
msgid "Show whitespace changes"
msgstr ""
@@ -22884,9 +23721,6 @@ msgstr ""
msgid "Sidebar|Assign health status"
msgstr ""
-msgid "Sidebar|Change weight"
-msgstr ""
-
msgid "Sidebar|Health status"
msgstr ""
@@ -23070,6 +23904,9 @@ msgstr ""
msgid "Snippets|Add another file %{num}/%{total}"
msgstr ""
+msgid "Snippets|Authored %{time_ago} by %{author}"
+msgstr ""
+
msgid "Snippets|Delete file"
msgstr ""
@@ -23097,6 +23934,9 @@ msgstr ""
msgid "Solution"
msgstr ""
+msgid "Some changes are not shown"
+msgstr ""
+
msgid "Some child epics may be hidden due to applied filters"
msgstr ""
@@ -23463,6 +24303,12 @@ msgstr ""
msgid "Source (branch or tag)"
msgstr ""
+msgid "Source Branch"
+msgstr ""
+
+msgid "Source branch: %{source_branch_open}%{source_branch}%{source_branch_close}"
+msgstr ""
+
msgid "Source code"
msgstr ""
@@ -23628,9 +24474,6 @@ msgstr ""
msgid "Start and due date"
msgstr ""
-msgid "Start by choosing a group to see how your team is spending time. You can then drill down to the project level."
-msgstr ""
-
msgid "Start by choosing a group to start exploring the merge requests in that group. You can then proceed to filter by projects, labels, milestones and authors."
msgstr ""
@@ -23712,18 +24555,27 @@ msgstr ""
msgid "StaticSiteEditor|3. Assign a person to review and accept the merge request."
msgstr ""
+msgid "StaticSiteEditor|A link to view the merge request will appear once ready."
+msgstr ""
+
msgid "StaticSiteEditor|An error occurred while submitting your changes."
msgstr ""
msgid "StaticSiteEditor|Branch could not be created."
msgstr ""
+msgid "StaticSiteEditor|Copy update"
+msgstr ""
+
msgid "StaticSiteEditor|Could not commit the content changes."
msgstr ""
msgid "StaticSiteEditor|Could not create merge request."
msgstr ""
+msgid "StaticSiteEditor|Creating your merge request"
+msgstr ""
+
msgid "StaticSiteEditor|Incompatible file content"
msgstr ""
@@ -23745,6 +24597,9 @@ msgstr ""
msgid "StaticSiteEditor|View documentation"
msgstr ""
+msgid "StaticSiteEditor|You can set an assignee to get your changes reviewed and deployed once your merge request is created."
+msgstr ""
+
msgid "StaticSiteEditor|Your merge request has been created"
msgstr ""
@@ -23874,15 +24729,15 @@ msgstr ""
msgid "Submit %{humanized_resource_name}"
msgstr ""
-msgid "Submit Changes"
-msgstr ""
-
msgid "Submit a review"
msgstr ""
msgid "Submit as spam"
msgstr ""
+msgid "Submit changes"
+msgstr ""
+
msgid "Submit feedback"
msgstr ""
@@ -24036,6 +24891,9 @@ msgstr ""
msgid "Successfully deleted U2F device."
msgstr ""
+msgid "Successfully deleted WebAuthn device."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -24354,9 +25212,6 @@ msgstr ""
msgid "Template to append to all Service Desk issues"
msgstr ""
-msgid "Template was successfully saved."
-msgstr ""
-
msgid "Templates"
msgstr ""
@@ -24435,10 +25290,28 @@ msgid_plural "Test coverage: %d hits"
msgstr[0] ""
msgstr[1] ""
-msgid "Test failed."
+msgid "Test settings"
msgstr ""
-msgid "Test settings and save changes"
+msgid "TestCases|New Test Case"
+msgstr ""
+
+msgid "TestCases|New test case"
+msgstr ""
+
+msgid "TestCases|Search test cases"
+msgstr ""
+
+msgid "TestCases|Something went wrong while creating a test case."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching count of test cases."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching test cases list."
+msgstr ""
+
+msgid "TestCases|Submit test case"
msgstr ""
msgid "TestHooks|Ensure one of your projects has merge requests."
@@ -24504,6 +25377,9 @@ msgstr ""
msgid "Thank you for signing up for your free trial! You will get additional instructions in your inbox shortly."
msgstr ""
+msgid "Thank you for your business."
+msgstr ""
+
msgid "Thank you for your feedback!"
msgstr ""
@@ -24563,9 +25439,6 @@ msgstr ""
msgid "The URL to use for connecting to Elasticsearch. Use a comma-separated list to support clustering (e.g., \"http://localhost:9200, http://localhost:9201\")."
msgstr ""
-msgid "The Web IDE offers advanced syntax highlighting capabilities and more."
-msgstr ""
-
msgid "The X509 Certificate to use when mutual TLS is required to communicate with the external authorization service. If left blank, the server certificate is still validated when accessing over HTTPS."
msgstr ""
@@ -24676,6 +25549,9 @@ msgstr ""
msgid "The form contains the following error:"
msgstr ""
+msgid "The form contains the following warning:"
+msgstr ""
+
msgid "The global settings require you to enable Two-Factor Authentication for your account."
msgstr ""
@@ -24790,9 +25666,6 @@ msgstr ""
msgid "The private key to use when a client certificate is provided. This value is encrypted at rest."
msgstr ""
-msgid "The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The project can be accessed by any logged in user."
msgstr ""
@@ -24829,7 +25702,7 @@ msgstr ""
msgid "The remote repository is being updated..."
msgstr ""
-msgid "The repository can be commited to, and issues, comments and other entities can be created."
+msgid "The repository can be committed to, and issues, comments and other entities can be created."
msgstr ""
msgid "The repository for this project does not exist."
@@ -24883,9 +25756,6 @@ msgstr ""
msgid "The time taken by each data entry gathered by that stage."
msgstr ""
-msgid "The total stage shows the time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The update action will time out after %{number_of_minutes} minutes. For big repositories, use a clone/push combination."
msgstr ""
@@ -24949,6 +25819,9 @@ msgstr ""
msgid "There are no archived requirements"
msgstr ""
+msgid "There are no archived test cases"
+msgstr ""
+
msgid "There are no changes"
msgstr ""
@@ -24988,6 +25861,9 @@ msgstr ""
msgid "There are no open requirements"
msgstr ""
+msgid "There are no open test cases"
+msgstr ""
+
msgid "There are no packages yet"
msgstr ""
@@ -25000,6 +25876,9 @@ msgstr ""
msgid "There is a limit of %{ci_project_subscriptions_limit} subscriptions from or to a project."
msgstr ""
+msgid "There is already a To-Do for this design."
+msgstr ""
+
msgid "There is already a repository with that name on disk"
msgstr ""
@@ -25018,6 +25897,9 @@ msgstr ""
msgid "There was a problem communicating with your device."
msgstr ""
+msgid "There was a problem fetching branches."
+msgstr ""
+
msgid "There was a problem fetching groups."
msgstr ""
@@ -25246,9 +26128,15 @@ msgstr ""
msgid "This action can lead to data loss. To prevent accidental actions we ask you to confirm your intention."
msgstr ""
+msgid "This action cannot be undone, and will permanently delete the %{key} SSH key"
+msgstr ""
+
msgid "This action cannot be undone. You will lose the project's repository and all content: issues, merge requests, etc."
msgstr ""
+msgid "This action has been performed too many times. Try again later."
+msgstr ""
+
msgid "This action will %{strongOpen}permanently delete%{strongClose} %{codeOpen}%{project}%{codeClose} %{strongOpen}immediately%{strongClose}, including its repositories and all content: issues, merge requests, etc."
msgstr ""
@@ -25276,9 +26164,6 @@ msgstr ""
msgid "This board's scope is reduced"
msgstr ""
-msgid "This branch has changed since you started editing. Would you like to create a new branch?"
-msgstr ""
-
msgid "This chart could not be displayed"
msgstr ""
@@ -25405,15 +26290,9 @@ msgstr ""
msgid "This is a security log of important events involving your account."
msgstr ""
-msgid "This is the author's first Merge Request to this project."
-msgstr ""
-
msgid "This is the highest peak of users on your installation since the license started."
msgstr ""
-msgid "This is the maximum number of users that have existed at the same time since the license started. This is the minimum number of seats you will need to buy when you renew your license."
-msgstr ""
-
msgid "This is the number of currently active users on your installation, and this is the minimum number you need to purchase when you renew your license."
msgstr ""
@@ -25645,6 +26524,15 @@ msgstr ""
msgid "This user has no identities"
msgstr ""
+msgid "This user has previously committed to the %{name} project."
+msgstr ""
+
+msgid "This user has the %{access} role in the %{name} project."
+msgstr ""
+
+msgid "This user is the author of this %{noteable}."
+msgstr ""
+
msgid "This user will be the author of all events in the activity feed that are the result of an update, like new branches being created or new commits being pushed to existing branches."
msgstr ""
@@ -25675,6 +26563,9 @@ msgstr ""
msgid "Threat Monitoring"
msgstr ""
+msgid "ThreatMonitoring|All Environments"
+msgstr ""
+
msgid "ThreatMonitoring|Anomalous Requests"
msgstr ""
@@ -25702,9 +26593,6 @@ msgstr ""
msgid "ThreatMonitoring|Operations Per Second"
msgstr ""
-msgid "ThreatMonitoring|Overview"
-msgstr ""
-
msgid "ThreatMonitoring|Packet Activity"
msgstr ""
@@ -25723,6 +26611,9 @@ msgstr ""
msgid "ThreatMonitoring|Something went wrong, unable to fetch statistics"
msgstr ""
+msgid "ThreatMonitoring|Statistics"
+msgstr ""
+
msgid "ThreatMonitoring|The firewall is not installed or has been disabled. To view this data, ensure the web application firewall is installed and enabled for your cluster."
msgstr ""
@@ -26114,6 +27005,9 @@ msgstr ""
msgid "To update Snippets with multiple files, you must use the `files` parameter"
msgstr ""
+msgid "To use Gitpod you must first enable the feature in the integrations section of your %{user_prefs}."
+msgstr ""
+
msgid "To view all %{scannedResourcesCount} scanned URLs, please download the CSV file"
msgstr ""
@@ -26147,9 +27041,6 @@ msgstr ""
msgid "Toggle Sidebar"
msgstr ""
-msgid "Toggle all threads"
-msgstr ""
-
msgid "Toggle backtrace"
msgstr ""
@@ -26174,9 +27065,6 @@ msgstr ""
msgid "Toggle navigation"
msgstr ""
-msgid "Toggle project"
-msgstr ""
-
msgid "Toggle sidebar"
msgstr ""
@@ -26216,6 +27104,9 @@ msgstr ""
msgid "Too many projects enabled. You will need to manage them via the console or the API."
msgstr ""
+msgid "Too much data"
+msgstr ""
+
msgid "Topics (optional)"
msgstr ""
@@ -26234,6 +27125,9 @@ msgstr ""
msgid "Total cores (CPUs)"
msgstr ""
+msgid "Total days to completion"
+msgstr ""
+
msgid "Total issues"
msgstr ""
@@ -26330,6 +27224,9 @@ msgstr ""
msgid "Trending"
msgstr ""
+msgid "Trials|Create a new group to start your GitLab Gold trial."
+msgstr ""
+
msgid "Trials|Go back to GitLab"
msgstr ""
@@ -26339,6 +27236,15 @@ msgstr ""
msgid "Trials|You can always resume this process by selecting your avatar and choosing 'Start a Gold trial'"
msgstr ""
+msgid "Trials|You can apply your trial to a new group or an existing group."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group or your personal account."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group, an existing group, or your personal account."
+msgstr ""
+
msgid "Trials|You won't get a free trial right now but you can always resume this process by clicking on your avatar and choosing 'Start a free trial'"
msgstr ""
@@ -26408,6 +27314,9 @@ msgstr ""
msgid "Try using a different search term to find the file you are looking for."
msgstr ""
+msgid "Trying to communicate with your device. Plug it in (if needed) and press the button on the device now."
+msgstr ""
+
msgid "Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now."
msgstr ""
@@ -26495,6 +27404,12 @@ msgstr ""
msgid "URL or request ID"
msgstr ""
+msgid "USER %{user} WILL BE REMOVED! Are you sure?"
+msgstr ""
+
+msgid "USER WILL BE BLOCKED! Are you sure?"
+msgstr ""
+
msgid "UTC"
msgstr ""
@@ -26552,9 +27467,6 @@ msgstr ""
msgid "Unable to load the merge request widget. Try reloading the page."
msgstr ""
-msgid "Unable to resolve"
-msgstr ""
-
msgid "Unable to save iteration. Please try again"
msgstr ""
@@ -26603,6 +27515,9 @@ msgstr ""
msgid "Undo ignore"
msgstr ""
+msgid "Unexpected error"
+msgstr ""
+
msgid "Unfortunately, your email message to GitLab could not be processed."
msgstr ""
@@ -26636,6 +27551,9 @@ msgstr ""
msgid "Unknown response text"
msgstr ""
+msgid "Unless otherwise agreed to in writing with GitLab, by clicking \"Upload License\" you agree that your use of GitLab Software is subject to the %{eula_link_start}Terms of Service%{eula_link_end}."
+msgstr ""
+
msgid "Unlimited"
msgstr ""
@@ -27002,9 +27920,6 @@ msgstr ""
msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
msgstr ""
-msgid "Use a hardware device to add the second factor of authentication."
-msgstr ""
-
msgid "Use an one time password authenticator on your mobile device or computer to enable two-factor authentication (2FA)."
msgstr ""
@@ -27278,13 +28193,13 @@ msgstr ""
msgid "Users"
msgstr ""
-msgid "Users in License:"
+msgid "Users in License"
msgstr ""
-msgid "Users or groups set as approvers in the project's or merge request's settings."
+msgid "Users in License:"
msgstr ""
-msgid "Users outside of license"
+msgid "Users or groups set as approvers in the project's or merge request's settings."
msgstr ""
msgid "Users over License:"
@@ -27302,9 +28217,6 @@ msgstr ""
msgid "Users with a Guest role or those who don't belong to a Project or Group will not use a seat from your license."
msgstr ""
-msgid "Users with a Guest role or those who don't belong to any projects or groups don't count towards seats in use."
-msgstr ""
-
msgid "UsersSelect|%{name} + %{length} more"
msgstr ""
@@ -27344,9 +28256,6 @@ msgstr ""
msgid "Validations failed."
msgstr ""
-msgid "Validity"
-msgstr ""
-
msgid "Value"
msgstr ""
@@ -27365,6 +28274,9 @@ msgstr ""
msgid "Value Stream Name"
msgstr ""
+msgid "ValueStreamAnalyticsStage|We don't have enough data to show this stage."
+msgstr ""
+
msgid "ValueStreamAnalytics|%{days}d"
msgstr ""
@@ -27621,6 +28533,9 @@ msgstr ""
msgid "VisualReviewApp|Steps 1 and 2 (and sometimes 3) are performed once by the developer before requesting feedback. Steps 3 (if necessary), 4 is performed by the reviewer each time they perform a review."
msgstr ""
+msgid "Visualization"
+msgstr ""
+
msgid "Vulnerabilities"
msgstr ""
@@ -27648,34 +28563,31 @@ msgstr ""
msgid "VulnerabilityChart|Severity"
msgstr ""
-msgid "VulnerabilityManagement|A true-positive and will fix"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Change status"
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|Confirm"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Confirmed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
-msgstr ""
-
-msgid "VulnerabilityManagement|Detected %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|A true-positive and will fix"
msgstr ""
-msgid "VulnerabilityManagement|Dismiss"
+msgid "VulnerabilityManagement|Change status"
msgstr ""
-msgid "VulnerabilityManagement|Dismissed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
msgstr ""
-msgid "VulnerabilityManagement|Resolved"
+msgid "VulnerabilityManagement|Detected"
msgstr ""
-msgid "VulnerabilityManagement|Resolved %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Needs triage"
msgstr ""
msgid "VulnerabilityManagement|Something went wrong while trying to delete the comment. Please try again later."
@@ -27726,6 +28638,9 @@ msgstr ""
msgid "Vulnerability|%{scannerName} (version %{scannerVersion})"
msgstr ""
+msgid "Vulnerability|Activity"
+msgstr ""
+
msgid "Vulnerability|Class"
msgstr ""
@@ -27738,6 +28653,9 @@ msgstr ""
msgid "Vulnerability|Description"
msgstr ""
+msgid "Vulnerability|Detected"
+msgstr ""
+
msgid "Vulnerability|Evidence"
msgstr ""
@@ -27801,6 +28719,9 @@ msgstr ""
msgid "Warning: Displaying this diagram might cause performance issues on this page."
msgstr ""
+msgid "We are currently unable to fetch data for the pipeline header."
+msgstr ""
+
msgid "We are currently unable to fetch data for this graph."
msgstr ""
@@ -27840,6 +28761,12 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
+msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
+msgstr ""
+
+msgid "We would like to inform you that your subscription GitLab Enterprise Edition %{plan_name} is nearing its user limit. You have %{active_user_count} active users, which is almost at the user limit of %{maximum_user_count}."
+msgstr ""
+
msgid "We've found no vulnerabilities"
msgstr ""
@@ -27855,6 +28782,12 @@ msgstr ""
msgid "Web terminal"
msgstr ""
+msgid "WebAuthn Devices (%{length})"
+msgstr ""
+
+msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
+msgstr ""
+
msgid "WebIDE|Merge request"
msgstr ""
@@ -27993,15 +28926,9 @@ msgstr ""
msgid "Welcome to the guided GitLab tour"
msgstr ""
-msgid "Welcome to your Issue Board!"
-msgstr ""
-
msgid "Welcome to your issue board!"
msgstr ""
-msgid "We’ve been making changes to %{featureName} and we’d love your feedback %{linkStart}in this issue%{linkEnd} to help us improve the experience."
-msgstr ""
-
msgid "What are you searching for?"
msgstr ""
@@ -28020,6 +28947,9 @@ msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
msgstr ""
+msgid "When enabled, any user visiting %{host} and creating an account will have to be explicitly approved by the admin before they can login. This setting is effective only if sign-ups are enabled."
+msgstr ""
+
msgid "When enabled, any user visiting %{host} will be able to create an account."
msgstr ""
@@ -28244,6 +29174,9 @@ msgstr ""
msgid "With requirements, you can set criteria to check your products against."
msgstr ""
+msgid "With test cases, you can define conditions for your project to meet in determining quality"
+msgstr ""
+
msgid "Withdraw Access Request"
msgstr ""
@@ -28259,6 +29192,9 @@ msgstr ""
msgid "Workflow Help"
msgstr ""
+msgid "Would you like to create a new branch?"
+msgstr ""
+
msgid "Write"
msgstr ""
@@ -28280,6 +29216,9 @@ msgstr ""
msgid "Wrong extern UID provided. Make sure Auth0 is configured correctly."
msgstr ""
+msgid "YYYY-MM-DD"
+msgstr ""
+
msgid "Yes"
msgstr ""
@@ -28337,7 +29276,7 @@ msgstr ""
msgid "You are going to remove the fork relationship from %{project_full_name}. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "You are going to transfer %{project_full_name} to another owner. Are you ABSOLUTELY sure?"
+msgid "You are going to transfer %{project_full_name} to another namespace. Are you ABSOLUTELY sure?"
msgstr ""
msgid "You are going to turn off the confidentiality. This means %{strongStart}everyone%{strongEnd} will be able to see and leave a comment on this %{issuableType}."
@@ -28397,9 +29336,6 @@ msgstr ""
msgid "You can always edit this later"
msgstr ""
-msgid "You can apply your Trial to your Personal account or create a New Group."
-msgstr ""
-
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings"
msgstr ""
@@ -28421,12 +29357,18 @@ msgstr ""
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
+msgid "You can find more information about GitLab subscriptions in %{subscriptions_doc_link}."
+msgstr ""
+
msgid "You can generate an access token scoped to this project for each application to use the GitLab API."
msgstr ""
msgid "You can get started by cloning the repository or start adding files to it with one of the following options."
msgstr ""
+msgid "You can group test cases using labels. To learn about the future direction of this feature, visit %{linkStart}Quality Management direction page%{linkEnd}."
+msgstr ""
+
msgid "You can invite a new member to %{project_name} or invite another group."
msgstr ""
@@ -28442,6 +29384,9 @@ msgstr ""
msgid "You can notify the app / group or a project by sending them an email notification"
msgstr ""
+msgid "You can now close this window."
+msgstr ""
+
msgid "You can now export your security dashboard to a CSV report."
msgstr ""
@@ -28490,9 +29435,6 @@ msgstr ""
msgid "You can test your .gitlab-ci.yml in %{linkStart}CI Lint%{linkEnd}."
msgstr ""
-msgid "You can try again using %{begin_link}basic search%{end_link}"
-msgstr ""
-
msgid "You cannot access the raw file. Please wait a minute."
msgstr ""
@@ -28544,6 +29486,9 @@ msgstr ""
msgid "You don't have any U2F devices registered yet."
msgstr ""
+msgid "You don't have any WebAuthn devices registered yet."
+msgstr ""
+
msgid "You don't have any active chat names."
msgstr ""
@@ -28631,6 +29576,9 @@ msgstr ""
msgid "You must accept our Terms of Service and privacy policy in order to register an account"
msgstr ""
+msgid "You must be logged in to search across all of GitLab"
+msgstr ""
+
msgid "You must disassociate %{domain} from all clusters it is attached to before deletion."
msgstr ""
@@ -28670,7 +29618,7 @@ msgstr ""
msgid "You need to be logged in."
msgstr ""
-msgid "You need to register a two-factor authentication app before you can set up a U2F device."
+msgid "You need to register a two-factor authentication app before you can set up a device."
msgstr ""
msgid "You need to set terms to be enforced"
@@ -28688,6 +29636,9 @@ msgstr ""
msgid "You reached %{usage_in_percent} of %{namespace_name}'s storage capacity (%{used_storage} of %{storage_limit})"
msgstr ""
+msgid "You successfully declined the invitation"
+msgstr ""
+
msgid "You tried to fork %{link_to_the_project} but it failed for the following reason:"
msgstr ""
@@ -28853,10 +29804,13 @@ msgstr ""
msgid "Your U2F device did not send a valid JSON response."
msgstr ""
-msgid "Your U2F device needs to be set up. Plug it in (if not already) and click the button on the left."
+msgid "Your U2F device was registered!"
msgstr ""
-msgid "Your U2F device was registered!"
+msgid "Your WebAuthn device did not send a valid JSON response."
+msgstr ""
+
+msgid "Your WebAuthn device was registered!"
msgstr ""
msgid "Your access request to the %{source_type} has been withdrawn."
@@ -28880,6 +29834,9 @@ msgstr ""
msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
msgstr ""
+msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
+msgstr ""
+
msgid "Your changes can be committed to %{branch_name} because a merge request is open."
msgstr ""
@@ -28916,6 +29873,12 @@ msgstr ""
msgid "Your deployment services will be broken, you will need to manually fix the services after renaming."
msgstr ""
+msgid "Your device is not compatible with GitLab. Please try another device"
+msgstr ""
+
+msgid "Your device needs to be set up. Plug it in (if needed) and click the button on the left."
+msgstr ""
+
msgid "Your device was successfully set up! Give it a name and register it with the GitLab server."
msgstr ""
@@ -29029,9 +29992,6 @@ msgstr[1] ""
msgid "access:"
msgstr ""
-msgid "activated"
-msgstr ""
-
msgid "added %{created_at_timeago}"
msgstr ""
@@ -29104,9 +30064,21 @@ msgstr ""
msgid "by %{user}"
msgstr ""
+msgid "cannot be a date in the past"
+msgstr ""
+
msgid "cannot be changed if a personal project has container registry tags."
msgstr ""
+msgid "cannot be changed if shared runners are enabled"
+msgstr ""
+
+msgid "cannot be enabled because parent group does not allow it"
+msgstr ""
+
+msgid "cannot be enabled because parent group has shared Runners disabled"
+msgstr ""
+
msgid "cannot be enabled unless all domains have TLS certificates"
msgstr ""
@@ -29152,7 +30124,7 @@ msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about SAST %{linkEndTag}"
msgstr ""
-msgid "ciReport|%{linkStartTag}Learn more about Secret Scanning %{linkEndTag}"
+msgid "ciReport|%{linkStartTag}Learn more about Secret Detection %{linkEndTag}"
msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about codequality reports %{linkEndTag}"
@@ -29467,9 +30439,6 @@ msgstr ""
msgid "error"
msgstr ""
-msgid "error code:"
-msgstr ""
-
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr ""
@@ -29491,6 +30460,9 @@ msgstr ""
msgid "failed to dismiss associated finding(id=%{finding_id}): %{message}"
msgstr ""
+msgid "failed to revert associated finding(id=%{finding_id}) to detected"
+msgstr ""
+
msgid "file"
msgid_plural "files"
msgstr[0] ""
@@ -30033,6 +31005,9 @@ msgstr ""
msgid "must be a root namespace"
msgstr ""
+msgid "must be a valid IPv4 or IPv6 address"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -30069,6 +31044,9 @@ msgstr ""
msgid "no expiration"
msgstr ""
+msgid "no name set"
+msgstr ""
+
msgid "no one can merge"
msgstr ""
@@ -30247,9 +31225,6 @@ msgstr ""
msgid "security Reports|There was an error creating the merge request"
msgstr ""
-msgid "settings saved, but not activated"
-msgstr ""
-
msgid "severity|Critical"
msgstr ""
@@ -30376,9 +31351,6 @@ msgstr ""
msgid "toggle collapse"
msgstr ""
-msgid "toggle dropdown"
-msgstr ""
-
msgid "triggered"
msgstr ""
@@ -30406,6 +31378,9 @@ msgstr ""
msgid "user avatar"
msgstr ""
+msgid "user preferences"
+msgstr ""
+
msgid "username"
msgstr ""
diff --git a/locale/de/gitlab.po b/locale/de/gitlab.po
index de0261850b7..73d9e05089c 100644
--- a/locale/de/gitlab.po
+++ b/locale/de/gitlab.po
@@ -14,7 +14,10 @@ msgstr ""
"X-Crowdin-Language: de\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 6\n"
-"PO-Revision-Date: 2020-09-04 23:07\n"
+"PO-Revision-Date: 2020-10-02 18:47\n"
+
+msgid " %{project_name}#%{issue_iid} &middot; opened %{issue_created} by %{author}"
+msgstr ""
msgid " %{start} to %{end}"
msgstr " %{start} bis %{end}"
@@ -74,6 +77,16 @@ msgstr "\"%{path}\" existiert nicht auf \"%{ref}\""
msgid "\"el\" parameter is required for createInstance()"
msgstr ""
+msgid "%d Approval"
+msgid_plural "%d Approvals"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d Package"
+msgid_plural "%d Packages"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d Scanned URL"
msgid_plural "%d Scanned URLs"
msgstr[0] ""
@@ -137,6 +150,11 @@ msgstr[1] "%d Commits,"
msgid "%d commits"
msgstr "%d Commits"
+msgid "%d completed issue"
+msgid_plural "%d completed issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d contribution"
msgid_plural "%d contributions"
msgstr[0] "%d Beitrag"
@@ -147,6 +165,11 @@ msgid_plural "%d days"
msgstr[0] ""
msgstr[1] ""
+msgid "%d day until tags are automatically removed"
+msgid_plural "%d days until tags are automatically removed"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d error"
msgid_plural "%d errors"
msgstr[0] ""
@@ -237,6 +260,16 @@ msgid_plural "%d more comments"
msgstr[0] "%d weiterer Kommentar"
msgstr[1] "%d weiterere Kommentare"
+msgid "%d open issue"
+msgid_plural "%d open issues"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d pending comment"
+msgid_plural "%d pending comments"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d personal project will be removed and cannot be restored."
msgid_plural "%d personal projects will be removed and cannot be restored."
msgstr[0] ""
@@ -252,6 +285,11 @@ msgid_plural "%d projects"
msgstr[0] "%d Projekt"
msgstr[1] "%d Projekte"
+msgid "%d project selected"
+msgid_plural "%d projects selected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d request with warnings"
msgid_plural "%d requests with warnings"
msgstr[0] "%d Anfrage mit Warnungen"
@@ -272,6 +310,11 @@ msgid_plural "%d tags"
msgstr[0] "%d Tag"
msgstr[1] "%d Tags"
+msgid "%d tag per image name"
+msgid_plural "%d tags per image name"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d unassigned issue"
msgid_plural "%d unassigned issues"
msgstr[0] ""
@@ -292,6 +335,11 @@ msgid_plural "%d vulnerabilities dismissed"
msgstr[0] ""
msgstr[1] ""
+msgid "%d warning found:"
+msgid_plural "%d warnings found:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%s additional commit has been omitted to prevent performance issues."
msgid_plural "%s additional commits have been omitted to prevent performance issues."
msgstr[0] "%s zusätzlicher Commit wurde ausgelassen um Leistungsprobleme zu verhindern."
@@ -330,6 +378,9 @@ msgstr ""
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr "%{commit_author_link} verfasste %{commit_timeago}"
+msgid "%{completedCount} completed weight"
+msgstr ""
+
msgid "%{completedWeight} of %{totalWeight} weight completed"
msgstr ""
@@ -378,14 +429,12 @@ msgid_plural "%{count} participants"
msgstr[0] "%{count} Teilnehmer(in)"
msgstr[1] "%{count} Teilnehmer(innen)"
-msgid "%{count} pending comment"
-msgid_plural "%{count} pending comments"
-msgstr[0] "%{count} ausstehender Kommentar"
-msgstr[1] "%{count} ausstehende Kommentare"
-
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr "%{count} verwandte %{pluralized_subject}: %{links}"
+msgid "%{count} total weight"
+msgstr ""
+
msgid "%{dashboard_path} could not be found."
msgstr ""
@@ -440,6 +489,9 @@ msgstr ""
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} nutzt Accounts, die von einer Gruppe verwaltet werden. Du musst dir einen neuen GitLab-Account erstellen, welcher von %{group_name} verwaltet wird."
+msgid "%{group_name}&%{epic_iid} &middot; opened %{epic_created} by %{author}"
+msgstr ""
+
msgid "%{host} sign-in from new location"
msgstr ""
@@ -452,8 +504,8 @@ msgstr ""
msgid "%{issuableType} will be removed! Are you sure?"
msgstr "%{issuableType} wird entfernt! Bist du sicher?"
-msgid "%{issuesSize} issues with a limit of %{maxIssueCount}"
-msgstr "%{issuesSize} Tickets mit einem Limit von %{maxIssueCount}"
+msgid "%{issuesCount} issues with a limit of %{maxIssueCount}"
+msgstr ""
msgid "%{issuesSize} with a limit of %{maxIssueCount}"
msgstr ""
@@ -485,7 +537,7 @@ msgstr ""
msgid "%{labelStart}Namespace:%{labelEnd} %{namespace}"
msgstr ""
-msgid "%{labelStart}Report Type:%{labelEnd} %{reportType}"
+msgid "%{labelStart}Scan Type:%{labelEnd} %{reportType}"
msgstr ""
msgid "%{labelStart}Scanner:%{labelEnd} %{scanner}"
@@ -682,9 +734,6 @@ msgid_plural "%{securityScanner} results are not available because a pipeline ha
msgstr[0] ""
msgstr[1] ""
-msgid "%{service_title} %{message}."
-msgstr ""
-
msgid "%{size} GiB"
msgstr "%{size} GiB"
@@ -773,6 +822,12 @@ msgstr "%{text} ist verfügbar"
msgid "%{timebox_name} should belong either to a project or a group."
msgstr ""
+msgid "%{timebox_type} does not support burnup charts"
+msgstr ""
+
+msgid "%{timebox_type} must have a start and due date"
+msgstr ""
+
msgid "%{title} %{operator} %{threshold}"
msgstr "%{title} %{operator} %{threshold}"
@@ -797,8 +852,8 @@ msgstr ""
msgid "%{total} open issue weight"
msgstr "%{total} offenes Ticketgewicht"
-msgid "%{total} open issues"
-msgstr "%{total} offene Tickets"
+msgid "%{total} warnings found: showing first %{warningsDisplayed}"
+msgstr ""
msgid "%{usage_ping_link_start}Learn more%{usage_ping_link_end} about what information is shared with GitLab Inc."
msgstr "%{usage_ping_link_start}Erfahre mehr%{usage_ping_link_end} darüber, welche Informationen mit GitLab Inc. geteilt werden."
@@ -830,9 +885,6 @@ msgstr ""
msgid "&lt; 1 hour"
msgstr ""
-msgid "&lt;no name set&gt;"
-msgstr ""
-
msgid "&lt;no scopes selected&gt;"
msgstr ""
@@ -863,6 +915,9 @@ msgstr "'%{level}' ist kein gültiger Sichtbarkeitslevel"
msgid "'%{name}' Value Stream created"
msgstr ""
+msgid "'%{name}' Value Stream deleted"
+msgstr ""
+
msgid "'%{name}' stage already exists"
msgstr ""
@@ -922,6 +977,9 @@ msgstr "+ %{moreCount} weitere"
msgid "+ %{numberOfHiddenAssignees} more"
msgstr "+ %{numberOfHiddenAssignees} weitere"
+msgid "+ %{numberOfHiddenReviewers} more"
+msgstr ""
+
msgid "+%d more"
msgid_plural "+%d more"
msgstr[0] ""
@@ -982,6 +1040,11 @@ msgid_plural "%d Days"
msgstr[0] "1 Tag"
msgstr[1] "%d Tage"
+msgid "1 Issue"
+msgid_plural "%d Issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "1 closed issue"
msgid_plural "%{issues} closed issues"
msgstr[0] "1 geschlossenes Ticket"
@@ -997,6 +1060,11 @@ msgid_plural "%d days"
msgstr[0] "1 Tag"
msgstr[1] "%d Tage"
+msgid "1 deploy key"
+msgid_plural "%d deploy keys"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] "Eine Gruppe"
@@ -1099,6 +1167,9 @@ msgstr "8 Stunden"
msgid ":%{startLine} to %{endLine}"
msgstr ""
+msgid "A %{incident_docs_start}modified issue%{incident_docs_end} to guide the resolution of incidents."
+msgstr ""
+
msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr "Ein 'Runner' ist ein Prozess, welcher ein Job ausführt. Du kannst so viele Runner erstellen wie du benötigst."
@@ -1111,6 +1182,9 @@ msgstr ""
msgid "A GitBook site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr "Eine GitBook-Seite, welche statt GitLab Netlify für CI/CD nutzt, aber trotzdem von all den anderen nützlichen GitLab-Funktionen profitiert."
+msgid "A Gitpod configured Webapplication in Spring and Java"
+msgstr ""
+
msgid "A Hexo site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr "Eine Hexo-Seite, die statt GitLab Netlify für CI/CD nutzt, aber trotzdem von all den anderen nützlichen GitLab-Funktionen profitiert."
@@ -1282,9 +1356,15 @@ msgstr "Zugriff abgelehnt! Stelle sicher, dass du diesem Repository Bereitstellu
msgid "Access expiration date"
msgstr "Zugriff auf das Ablaufdatum"
+msgid "Access expires"
+msgstr ""
+
msgid "Access forbidden. Check your access level."
msgstr "Zugriff verboten. Überprüfe deine Zugriffsebene."
+msgid "Access granted"
+msgstr ""
+
msgid "Access requests"
msgstr ""
@@ -1294,6 +1374,9 @@ msgstr "Zugriff auf '%{classification_label}' nicht erlaubt"
msgid "Access to Pages websites are controlled based on the user's membership to a given project. By checking this box, users will be required to be logged in to have access to all Pages websites in your instance."
msgstr ""
+msgid "AccessDropdown|Deploy Keys"
+msgstr ""
+
msgid "AccessDropdown|Groups"
msgstr "Gruppen"
@@ -1411,12 +1494,6 @@ msgstr ""
msgid "Active Sessions"
msgstr "Aktive Sitzungen"
-msgid "Active Users:"
-msgstr ""
-
-msgid "Active users"
-msgstr ""
-
msgid "Activity"
msgstr "Aktivität"
@@ -1584,9 +1661,6 @@ msgstr ""
msgid "Add label(s)"
msgstr "Label(s) hinzufügen"
-msgid "Add license"
-msgstr "Lizenz hinzufügen"
-
msgid "Add list"
msgstr "Liste hinzufügen"
@@ -1761,21 +1835,51 @@ msgstr ""
msgid "AdminArea|Bots"
msgstr ""
+msgid "AdminArea|Components"
+msgstr ""
+
msgid "AdminArea|Developer"
msgstr ""
+msgid "AdminArea|Features"
+msgstr ""
+
+msgid "AdminArea|Groups: %{number_of_groups}"
+msgstr ""
+
msgid "AdminArea|Guest"
msgstr ""
msgid "AdminArea|Included Free in license"
msgstr ""
+msgid "AdminArea|Latest groups"
+msgstr ""
+
+msgid "AdminArea|Latest projects"
+msgstr ""
+
+msgid "AdminArea|Latest users"
+msgstr ""
+
msgid "AdminArea|Maintainer"
msgstr ""
+msgid "AdminArea|New group"
+msgstr ""
+
+msgid "AdminArea|New project"
+msgstr ""
+
+msgid "AdminArea|New user"
+msgstr ""
+
msgid "AdminArea|Owner"
msgstr "Inhaber(in)"
+msgid "AdminArea|Projects: %{number_of_projects}"
+msgstr ""
+
msgid "AdminArea|Reporter"
msgstr ""
@@ -1803,6 +1907,9 @@ msgstr ""
msgid "AdminArea|Users without a Group and Project"
msgstr ""
+msgid "AdminArea|Users: %{number_of_users}"
+msgstr ""
+
msgid "AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running."
msgstr "Du bist dabei, alle Jobs zu stoppen. Dies hält alle aktuellen Jobs, die ausgeführt werden, an."
@@ -1821,9 +1928,6 @@ msgstr "Löschen"
msgid "AdminProjects|Delete Project %{projectName}?"
msgstr "Projekt %{projectName} löschen?"
-msgid "AdminProjects|Delete project"
-msgstr "Projekt löschen"
-
msgid "AdminSettings|Apply integration settings to all Projects"
msgstr ""
@@ -2061,21 +2165,30 @@ msgstr "Wenn diese(r) Benutzer(in) sich wieder anmeldet, wird das Konto vollstä
msgid "AdminUsers|Without projects"
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 %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 ""
msgid "AdminUsers|You cannot remove your own admin rights."
msgstr ""
+msgid "AdminUsers|You must transfer ownership or delete the groups owned by this user before you can delete their account"
+msgstr ""
+
msgid "Administration"
msgstr ""
msgid "Advanced"
msgstr "Erweitert"
+msgid "Advanced Search"
+msgstr ""
+
+msgid "Advanced Search with Elasticsearch"
+msgstr ""
+
msgid "Advanced Settings"
msgstr ""
@@ -2153,6 +2266,9 @@ msgstr ""
msgid "AlertManagement|Edit"
msgstr ""
+msgid "AlertManagement|Environment"
+msgstr ""
+
msgid "AlertManagement|Events"
msgstr ""
@@ -2165,6 +2281,9 @@ msgstr ""
msgid "AlertManagement|Issue"
msgstr ""
+msgid "AlertManagement|Key"
+msgstr ""
+
msgid "AlertManagement|Low"
msgstr ""
@@ -2258,6 +2377,9 @@ msgstr ""
msgid "AlertManagement|Unknown"
msgstr ""
+msgid "AlertManagement|Value"
+msgstr ""
+
msgid "AlertManagement|View alerts in Opsgenie"
msgstr ""
@@ -2417,6 +2539,9 @@ msgstr "Alle Pfade sind relativ zur GitLab-URL. Füge keine %{relative_url_link_
msgid "All projects"
msgstr "Alle Projekte"
+msgid "All projects selected"
+msgstr ""
+
msgid "All security scans are enabled because %{linkStart}Auto DevOps%{linkEnd} is enabled on this project"
msgstr "Alle Sicherheits-Scans sind aktiviert, weil %{linkStart}Auto DevOps%{linkEnd} in diesem Projekt aktiviert ist"
@@ -2504,6 +2629,9 @@ msgstr "Ermöglicht dir das Hinzufügen und Verwalten von Kubernetes-Clustern."
msgid "Almost there"
msgstr "Fast geschafft"
+msgid "Already blocked"
+msgstr ""
+
msgid "Also called \"Issuer\" or \"Relying party trust identifier\""
msgstr "Wird auch \"Herausgeber\" oder \"Relying-Party-Trust-Identifier\" genannt"
@@ -2558,6 +2686,9 @@ msgstr "Bei einem leeren GitLab-Benutzerfeld wird der vollständigen Namen des F
msgid "An error has occurred"
msgstr "Es ist ein Fehler aufgetreten"
+msgid "An error occured while making the changes: %{error}"
+msgstr ""
+
msgid "An error occurred adding a draft to the thread."
msgstr "Beim Hinzufügen eines Entwurfs zur Diskussion ist ein Fehler aufgetreten."
@@ -2585,12 +2716,6 @@ msgstr "Bei der Vorschau des Blobs ist ein Fehler aufgetreten"
msgid "An error occurred when toggling the notification subscription"
msgstr "Beim Umschalten des Benachrichtigungs-Abonnements trat ein Fehler auf"
-msgid "An error occurred when trying to resolve a comment. Please try again."
-msgstr "Beim Versuch, einen Kommentar zu lösen, ist ein Fehler aufgetreten. Bitte versuche es erneut."
-
-msgid "An error occurred when trying to resolve a discussion. Please try again."
-msgstr "Beim Versuch, eine Diskussion zu lösen, ist ein Fehler aufgetreten. Bitte versuche es erneut."
-
msgid "An error occurred when updating the issue weight"
msgstr "Beim Aktualisieren der Ticket-Gewichtung ist ein Fehler aufgetreten"
@@ -2606,12 +2731,6 @@ msgstr ""
msgid "An error occurred while checking group path. Please refresh and try again."
msgstr ""
-msgid "An error occurred while committing your changes."
-msgstr ""
-
-msgid "An error occurred while creating the list. Please try again."
-msgstr ""
-
msgid "An error occurred while decoding the file."
msgstr ""
@@ -2684,25 +2803,19 @@ msgstr ""
msgid "An error occurred while fetching the Service Desk address."
msgstr "Beim Abrufen der Service-Desk-Adresse ist ein Fehler aufgetreten."
-msgid "An error occurred while fetching the board issues. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the board lists. Please reload the page."
msgstr ""
msgid "An error occurred while fetching the board lists. Please try again."
msgstr "Beim Abrufen der Board-Listen ist ein Fehler aufgetreten. Bitte versuche es erneut."
-msgid "An error occurred while fetching the board swimlanes. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the builds."
msgstr "Beim Abrufen der Builds ist ein Fehler aufgetreten."
msgid "An error occurred while fetching the job log."
msgstr "Beim Abrufen des Jobprotokolls ist ein Fehler aufgetreten."
-msgid "An error occurred while fetching the job trace."
+msgid "An error occurred while fetching the job logs."
msgstr ""
msgid "An error occurred while fetching the job."
@@ -2849,9 +2962,6 @@ msgstr "Beim Speichern des LDAP-Ãœberschreibungsstatus ist ein Fehler aufgetrete
msgid "An error occurred while saving assignees"
msgstr "Beim Speichern der Zuweisungen ist ein Fehler aufgetreten"
-msgid "An error occurred while saving the template. Please check if the template exists."
-msgstr ""
-
msgid "An error occurred while searching for milestones"
msgstr ""
@@ -2870,12 +2980,12 @@ msgstr "Beim Abbestellen der Benachrichtigungen ist ein Fehler aufgetreten."
msgid "An error occurred while updating approvers"
msgstr "Beim Ändern der Genehmigungsberechtigten ist ein Fehler aufgetreten"
+msgid "An error occurred while updating labels."
+msgstr ""
+
msgid "An error occurred while updating the comment"
msgstr "Beim Aktualisieren des Kommentars ist ein Fehler aufgetreten"
-msgid "An error occurred while updating the list. Please try again."
-msgstr ""
-
msgid "An error occurred while validating group path"
msgstr ""
@@ -2927,6 +3037,9 @@ msgstr "Beim Beenden des Web-Terminals ist ein unerwarteter Fehler aufgetreten."
msgid "An unknown error occurred while loading this graph."
msgstr ""
+msgid "An unknown error occurred."
+msgstr ""
+
msgid "Analytics"
msgstr "Analysen"
@@ -2960,10 +3073,10 @@ msgstr "Anti-Spam-Überprüfung"
msgid "Any"
msgstr "Irgendein"
-msgid "Any Author"
+msgid "Any %{header}"
msgstr ""
-msgid "Any Status"
+msgid "Any Author"
msgstr ""
msgid "Any branch"
@@ -3017,6 +3130,9 @@ msgstr "Anwendung"
msgid "Application ID"
msgstr "Anwendungs-ID"
+msgid "Application limits saved successfully"
+msgstr ""
+
msgid "Application settings saved successfully"
msgstr "Anwendungseinstellungen erfolgreich gespeichert"
@@ -3226,6 +3342,9 @@ msgstr "Möchtest du wirklich die Bearbeitung dieses Kommentars abbrechen?"
msgid "Are you sure you want to close this blocked issue?"
msgstr ""
+msgid "Are you sure you want to delete \"%{name}\" Value Stream?"
+msgstr ""
+
msgid "Are you sure you want to delete %{name}?"
msgstr ""
@@ -3235,6 +3354,9 @@ msgstr "Möchtest du diese Artefakte wirklich löschen?"
msgid "Are you sure you want to delete this %{typeOfComment}?"
msgstr "Möchtest du diesen %{typeOfComment} wirklich entfernen?"
+msgid "Are you sure you want to delete this SSH key?"
+msgstr ""
+
msgid "Are you sure you want to delete this board?"
msgstr "Möchtest du dieses Board wirklich löschen?"
@@ -3259,6 +3381,11 @@ msgstr ""
msgid "Are you sure you want to erase this build?"
msgstr "Bist du sicher, dass du diesen Build löschen möchtest?"
+msgid "Are you sure you want to import %d repository?"
+msgid_plural "Are you sure you want to import %d repositories?"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Are you sure you want to lose unsaved changes?"
msgstr "Bist du sicher, dass du alle nicht gespeicherten Änderungen verwerfen möchtest?"
@@ -3268,15 +3395,15 @@ msgstr "Möchtest du wirklich die Ticketinformationen verlieren?"
msgid "Are you sure you want to merge immediately?"
msgstr ""
-msgid "Are you sure you want to permanently delete this license?"
-msgstr "Möchtest du wirklich diese Lizenz dauerhaft löschen?"
-
msgid "Are you sure you want to re-deploy this environment?"
msgstr ""
msgid "Are you sure you want to regenerate the public key? You will have to update the public key on the remote server before mirroring will work again."
msgstr "Möchtest du den öffentlichen Schlüssel wirklich neu generieren? Du musst dann den öffentlichen Schlüssel auf dem Remote-Server aktualisieren, bevor die Spiegelung wieder funktioniert."
+msgid "Are you sure you want to reindex?"
+msgstr ""
+
msgid "Are you sure you want to remove %{group_name}?"
msgstr "Bist du sicher, dass du %{group_name} wirklich entfernen willst?"
@@ -3304,6 +3431,9 @@ msgstr ""
msgid "Are you sure you want to revoke this nickname?"
msgstr ""
+msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
+msgstr ""
+
msgid "Are you sure you want to stop this environment?"
msgstr "Bist du sicher, dass du diese Umgebung stoppen möchtest?"
@@ -3325,6 +3455,9 @@ msgstr ""
msgid "Are you sure? The device will be signed out of GitLab and all remember me tokens revoked."
msgstr ""
+msgid "Are you sure? This will invalidate your registered applications and U2F / WebAuthn devices."
+msgstr ""
+
msgid "Are you sure? This will invalidate your registered applications and U2F devices."
msgstr "Bist du sicher? Dadurch werden deine registrierten Anwendungen und U2F-Geräte ungültig."
@@ -3343,9 +3476,6 @@ msgstr "Artefakt wurde erfolgreich gelöscht."
msgid "Artifacts"
msgstr "Artefakte"
-msgid "As U2F devices are only supported by a few browsers, we require that you set up a two-factor authentication app before a U2F device. That way you'll always be able to log in - even when you're using an unsupported browser."
-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 ""
@@ -3539,6 +3669,9 @@ msgstr ""
msgid "AuditLogs|Target"
msgstr ""
+msgid "AuditLogs|This month"
+msgstr ""
+
msgid "AuditLogs|User Events"
msgstr ""
@@ -3578,6 +3711,9 @@ msgstr "Authentifizierungsmethode aktualisiert"
msgid "Authentication via U2F device failed."
msgstr "Authentifizierung mittels U2F-Gerät fehlgeschlagen."
+msgid "Authentication via WebAuthn device failed."
+msgstr ""
+
msgid "Author"
msgstr "Autor(in)"
@@ -3845,15 +3981,6 @@ msgstr "Bamboo Root-URL, z.B. https://bamboo.example.com"
msgid "BambooService|You must set up automatic revision labeling and a repository trigger in Bamboo."
msgstr "Du musst in Bamboo eine automatische Versionskennzeichnung und einen Repository-Trigger einrichten."
-msgid "BatchComments|Delete all pending comments"
-msgstr "Alle ausstehenden Kommentare löschen"
-
-msgid "BatchComments|Discard review?"
-msgstr "Review verwerfen?"
-
-msgid "BatchComments|You're about to discard your review which will delete all of your pending comments. The deleted comments %{strong_start}cannot%{strong_end} be restored."
-msgstr "Du bist dabei deinen Review zu verwerfen und damit alle ausstehenden Kommentare zu löschen. Die gelöschten Kommentare können %{strong_start}nicht%{strong_end} wiederhergestellt werden."
-
msgid "Be careful. Changing the project's namespace can have unintended side effects."
msgstr "Vorsicht. Änderungen am Projektnamensraum können unbeabsichtigte Nebenwirkungen haben."
@@ -3875,6 +4002,9 @@ msgstr "Unten findest du alle Gruppen, die öffentlich sind."
msgid "Bi-weekly code coverage"
msgstr ""
+msgid "Billable Users:"
+msgstr ""
+
msgid "Billing"
msgstr "Abrechnung"
@@ -3884,7 +4014,7 @@ msgstr ""
msgid "BillingPlans|@%{user_name} you are currently using the %{plan_name} plan."
msgstr ""
-msgid "BillingPlans|Congratulations, your new trial is activated"
+msgid "BillingPlans|Congratulations, your free trial is activated."
msgstr ""
msgid "BillingPlans|If you would like to downgrade your plan please contact %{support_link_start}Customer Support%{support_link_end}."
@@ -3947,6 +4077,9 @@ msgstr "Bitbucket-Import"
msgid "Blame"
msgstr ""
+msgid "Block user"
+msgstr ""
+
msgid "Blocked"
msgstr "Gesperrt"
@@ -3962,31 +4095,37 @@ msgstr "Blöcke"
msgid "Blog"
msgstr "Blog"
-msgid "Board name"
-msgstr "Board Name"
-
msgid "Board scope"
msgstr "Board-Bereich"
msgid "Board scope affects which issues are displayed for anyone who visits this board"
msgstr "Der Board-Bereich beeinflusst, welche Themen für jeden angezeigt werden, der dieses Board besucht"
-msgid "BoardBlankState|Add default lists"
-msgstr "Standardlisten hinzufügen"
+msgid "Boards"
+msgstr "Boards"
-msgid "BoardBlankState|Add the following default lists to your Issue Board with one click:"
-msgstr "Fügen Sie Ihrem Ticketboard mit einem Klick die folgenden Standardlisten hinzu:"
+msgid "Boards and Board Lists"
+msgstr ""
-msgid "BoardBlankState|Nevermind, I'll use my own"
+msgid "Boards|An error occurred while creating the issue. Please try again."
msgstr ""
-msgid "BoardBlankState|Starting out with the default set of lists will get you right on the way to making the most of your board."
+msgid "Boards|An error occurred while creating the list. Please try again."
msgstr ""
-msgid "Boards"
-msgstr "Boards"
+msgid "Boards|An error occurred while fetching issues. Please reload the page."
+msgstr ""
-msgid "Boards and Board Lists"
+msgid "Boards|An error occurred while fetching the board issues. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching the board swimlanes. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while moving the issue. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while updating the list. Please try again."
msgstr ""
msgid "Boards|Collapse"
@@ -4013,8 +4152,8 @@ msgstr "Branch %{branchName} wurde im Repository dieses Projekts nicht gefunden.
msgid "Branch %{branch_name} was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr ""
-msgid "Branch has changed"
-msgstr "Branch wurde geändert"
+msgid "Branch changed"
+msgstr ""
msgid "Branch is already taken"
msgstr "Branch existiert bereits"
@@ -4319,6 +4458,9 @@ msgstr "GESCHLOSSEN"
msgid "CLOSED (MOVED)"
msgstr "GESCHLOSSEN (VERSCHOBEN)"
+msgid "CODEOWNERS rule violation"
+msgstr ""
+
msgid "CONTRIBUTING"
msgstr "CONTRIBUTING"
@@ -4349,9 +4491,6 @@ msgstr ""
msgid "Can't create snippet: %{err}"
msgstr ""
-msgid "Can't edit as source branch was deleted"
-msgstr ""
-
msgid "Can't fetch content for the blob: %{err}"
msgstr ""
@@ -4364,9 +4503,6 @@ msgstr "Kann Variable nicht finden: ZiteReader"
msgid "Can't load mermaid module: %{err}"
msgstr ""
-msgid "Can't remove group members without group managed account"
-msgstr "Ohne ein gruppenverwaltetes Konto können keine Gruppenmitglieder entfernt werden"
-
msgid "Can't scan the code?"
msgstr ""
@@ -4409,6 +4545,9 @@ msgstr "Der Missbrauchsbericht kann nicht erstellt werden. Der/Die Benutzer(in)
msgid "Cannot create the abuse report. This user has been blocked."
msgstr "Der Missbrauchsbericht kann nicht erstellt werden. Der/Die Benutzer(in) wurde gesperrt."
+msgid "Cannot enable shared runners because parent group does not allow it"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -4514,6 +4653,15 @@ msgstr "Ändere dein Passwort"
msgid "Change your password or recover your current one"
msgstr "Ändere dein Passwort oder stelle dein aktuelles wieder her"
+msgid "ChangeReviewer|Reviewer changed from %{old} to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Reviewer changed to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Unassigned"
+msgstr ""
+
msgid "ChangeTypeActionLabel|Pick into branch"
msgstr "In dem Branch wählen"
@@ -4553,6 +4701,9 @@ msgstr "Änderungen unterdrückt. Zum Anzeigen klicken."
msgid "Changes the title to \"%{title_param}\"."
msgstr "Ändert den Titel in \"%{title_param}\"."
+msgid "Changes were successfully made."
+msgstr ""
+
msgid "Changes won't take place until the index is %{link_start}recreated%{link_end}."
msgstr "Die Änderungen werden nicht ausgeführt bis %{link_start}neu indexiert%{link_end} wurde."
@@ -4958,6 +5109,9 @@ msgstr "Maskiert"
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove variable"
+msgstr ""
+
msgid "CiVariables|Remove variable row"
msgstr "Variable jetzt löschen"
@@ -5036,9 +5190,6 @@ msgstr ""
msgid "Clear due date"
msgstr ""
-msgid "Clear input"
-msgstr "Eingabe löschen"
-
msgid "Clear recent searches"
msgstr "Letzte Suchen löschen"
@@ -5087,6 +5238,9 @@ msgstr "Client-Authentifizierungsschlüssel"
msgid "Client authentication key password"
msgstr "Kennwort für den Client-Authentifizierungsschlüssel"
+msgid "Client request timeout"
+msgstr ""
+
msgid "Clients"
msgstr "Kunden"
@@ -5171,6 +5325,27 @@ msgstr ""
msgid "Cluster type must be specificed for Stages::ClusterEndpointInserter"
msgstr ""
+msgid "ClusterAgents|Configuration"
+msgstr ""
+
+msgid "ClusterAgents|Connect your cluster with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate Kubernetes with a GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Name"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Agent also requires %{linkStart}enabling the Agent Server%{linkEnd}"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Kubernetes Agent allows an Infrastructure as Code, GitOps approach to integrating Kubernetes clusters with GitLab. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "ClusterAgent|This feature is only available for premium plans"
msgstr ""
@@ -5240,11 +5415,11 @@ msgstr ""
msgid "ClusterIntegration|All installed applications and related resources"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster."
+msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{linkStart}More information%{linkEnd}"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{startLink}More information%{endLink}"
-msgstr "Ermögliche GitLab, Namespace- und Service-Konten für diesen Cluster zu verwalten. %{startLink}Weitere Informationen%{endLink}"
+msgid "ClusterIntegration|Allow GitLab to manage namespaces and service accounts for this cluster."
+msgstr ""
msgid "ClusterIntegration|Alternatively, "
msgstr ""
@@ -5264,6 +5439,9 @@ msgstr "Beim Fetchen deiner Projekte ist ein Fehler aufgetreten: %{error}"
msgid "ClusterIntegration|An error occurred while trying to fetch zone machine types: %{error}"
msgstr "Beim Fetchen der Maschinentypen der Zone ist ein Fehler aufgetreten: %{error}"
+msgid "ClusterIntegration|An unknown error occurred while attempting to connect to Kubernetes."
+msgstr ""
+
msgid "ClusterIntegration|Any project namespaces"
msgstr ""
@@ -5279,6 +5457,9 @@ msgstr "Mit AWS authentifizieren"
msgid "ClusterIntegration|Authenticate with Amazon Web Services"
msgstr ""
+msgid "ClusterIntegration|Authentication Error"
+msgstr ""
+
msgid "ClusterIntegration|Base domain"
msgstr "Basisdomäne"
@@ -5297,13 +5478,22 @@ msgstr ""
msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
msgstr "Zertifizierungsstellen-Bundle (PEM-Format)"
-msgid "ClusterIntegration|Choose the %{startLink}security group %{externalLinkIcon} %{endLink} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
+msgid "ClusterIntegration|Check your CA certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Check your cluster status"
+msgstr ""
+
+msgid "ClusterIntegration|Check your token"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}subnets %{externalLinkIcon} %{endLink} in your VPC where your worker nodes will run."
+msgid "ClusterIntegration|Choose the %{linkStart}security group %{linkEnd} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
msgstr ""
-msgid "ClusterIntegration|Choose the worker node %{startLink}instance type %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Choose the %{linkStart}subnets %{linkEnd} in your VPC where your worker nodes will run."
+msgstr ""
+
+msgid "ClusterIntegration|Choose the worker node %{linkStart}instance type%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Choose which applications to install on your Kubernetes cluster."
@@ -5315,10 +5505,7 @@ msgstr "Wähle, welche deiner Umgebungen du für dieses Cluster verwenden willst
msgid "ClusterIntegration|Clear cluster cache"
msgstr ""
-msgid "ClusterIntegration|Clear the local cache of namespace and service accounts. This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
-msgstr ""
-
-msgid "ClusterIntegration|Cluster being created"
+msgid "ClusterIntegration|Clear the local cache of namespace and service accounts."
msgstr ""
msgid "ClusterIntegration|Cluster management project (alpha)"
@@ -5330,15 +5517,21 @@ msgstr ""
msgid "ClusterIntegration|Cluster_applications artifact too big. Maximum allowable size: %{human_size}"
msgstr ""
-msgid "ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters."
+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|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}"
+msgid "ClusterIntegration|Clusters connected with a certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Connect cluster with certificate"
msgstr ""
msgid "ClusterIntegration|Connect existing cluster"
msgstr ""
+msgid "ClusterIntegration|Connection Error"
+msgstr ""
+
msgid "ClusterIntegration|Copy API URL"
msgstr "API-URL kopieren"
@@ -5414,6 +5607,12 @@ msgstr ""
msgid "ClusterIntegration|Deletes all GitLab resources attached to this cluster during removal"
msgstr ""
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared."
+msgstr ""
+
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared. %{linkStart}More information%{linkEnd}"
+msgstr ""
+
msgid "ClusterIntegration|Did you know?"
msgstr "Wusstest du schon?"
@@ -5483,6 +5682,9 @@ msgstr "Fluentd"
msgid "ClusterIntegration|Fluentd is an open source data collector, which lets you unify the data collection and consumption for a better use and understanding of data. It requires at least one of the following logs to be successfully installed."
msgstr ""
+msgid "ClusterIntegration|GitLab Agent managed clusters"
+msgstr ""
+
msgid "ClusterIntegration|GitLab Container Network Policies"
msgstr ""
@@ -5495,6 +5697,12 @@ msgstr "GitLab Runner"
msgid "ClusterIntegration|GitLab Runner connects to the repository and executes CI/CD jobs, pushing results back and deploying applications to production."
msgstr ""
+msgid "ClusterIntegration|GitLab failed to authenticate."
+msgstr ""
+
+msgid "ClusterIntegration|GitLab failed to connect to the cluster."
+msgstr ""
+
msgid "ClusterIntegration|GitLab-managed cluster"
msgstr ""
@@ -5516,6 +5724,9 @@ msgstr "Google Kubernetes-Engine-Projekt"
msgid "ClusterIntegration|Group cluster"
msgstr "Cluster gruppieren"
+msgid "ClusterIntegration|HTTP Error"
+msgstr ""
+
msgid "ClusterIntegration|Helm Tiller"
msgstr "Helm Tiller"
@@ -5549,8 +5760,11 @@ msgstr ""
msgid "ClusterIntegration|Instance type"
msgstr ""
-msgid "ClusterIntegration|Integrate Kubernetes cluster automation"
-msgstr "Kubernetes-Cluster-Automatisierung integrieren"
+msgid "ClusterIntegration|Integrate Kubernetes with a cluster certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Integrate with a cluster certificate"
+msgstr ""
msgid "ClusterIntegration|Issuer Email"
msgstr ""
@@ -5585,9 +5799,6 @@ msgstr ""
msgid "ClusterIntegration|Knative extends Kubernetes to provide a set of middleware components that are essential to build modern, source-centric, and container-based applications that can run anywhere: on premises, in the cloud, or even in a third-party data center."
msgstr "Knative erweitert Kubernetes und bietet eine Reihe von Middleware-Komponenten. Diese sind essentiell für moderne, Quellcode-basiert, containerisierte, überall lauffähige Anwendungen: ein eigenen RZ, in der Cloud oder im Rechenzentrum eines Drittanbieters."
-msgid "ClusterIntegration|Kubernetes cluster"
-msgstr "Kubernetes-Cluster"
-
msgid "ClusterIntegration|Kubernetes cluster is being created..."
msgstr ""
@@ -5600,9 +5811,6 @@ msgstr ""
msgid "ClusterIntegration|Kubernetes clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr "Kubernetes-Cluster ermöglichen dir auf einfache Weise die Benutzung der Review-Anwendungen, die Bereitstellung deiner Anwendungen, deine Pipelines auszuführen, und vieles mehr."
-msgid "ClusterIntegration|Kubernetes clusters can be used to deploy applications and to provide Review Apps for this project"
-msgstr "Kubernetes-Cluster können zum Bereitstellen von Anwendungen und zur Zur­ver­fü­gung­stel­lung von Review-Anwendungen für dieses Projekt verwendet werden"
-
msgid "ClusterIntegration|Kubernetes version"
msgstr ""
@@ -5615,7 +5823,7 @@ msgstr "Erfahre mehr über %{help_link_start_machine_type}Maschinentypen%{help_l
msgid "ClusterIntegration|Learn more about %{help_link_start}zones%{help_link_end}."
msgstr "Erfahre mehr über %{help_link_start}Zonen%{help_link_end}."
-msgid "ClusterIntegration|Learn more about %{startLink}Regions %{externalLinkIcon}%{endLink}."
+msgid "ClusterIntegration|Learn more about %{linkStart}Regions%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Learn more about Kubernetes"
@@ -5660,12 +5868,18 @@ msgstr ""
msgid "ClusterIntegration|Machine type"
msgstr "Maschinentyp"
+msgid "ClusterIntegration|Make sure your API endpoint is correct"
+msgstr ""
+
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create Kubernetes clusters"
msgstr "Stelle sicher, dass dein Konto %{link_to_requirements}, um Kubernetes-Cluster zu erstellen"
msgid "ClusterIntegration|Manage your Kubernetes cluster by visiting %{provider_link}"
msgstr ""
+msgid "ClusterIntegration|Namespace per environment"
+msgstr ""
+
msgid "ClusterIntegration|No IAM Roles found"
msgstr ""
@@ -5711,6 +5925,9 @@ msgstr "Keine Subnetzwerke gefunden"
msgid "ClusterIntegration|No zones matched your search"
msgstr "Keine Zonen entsprechen deiner Suche"
+msgid "ClusterIntegration|Node calculations use the Kubernetes Metrics API. Make sure your cluster has metrics installed"
+msgstr ""
+
msgid "ClusterIntegration|Number of nodes"
msgstr "Anzahl der Knoten"
@@ -5753,6 +5970,9 @@ msgstr ""
msgid "ClusterIntegration|RBAC-enabled cluster"
msgstr "RBAC-kompatibles Cluster"
+msgid "ClusterIntegration|Read our %{linkStart}help page%{linkEnd} on Kubernetes cluster integration."
+msgstr ""
+
msgid "ClusterIntegration|Read our %{link_start}help page%{link_end} on Kubernetes cluster integration."
msgstr ""
@@ -5855,7 +6075,7 @@ msgstr ""
msgid "ClusterIntegration|Select a VPC to choose a subnet"
msgstr ""
-msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{linkStart}Amazon Web Services %{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select a network to choose a subnetwork"
@@ -5888,7 +6108,7 @@ msgstr "Wähle ein Projekt und ein Zone, um den Maschinentyp auszuwählen"
msgid "ClusterIntegration|Select project to choose zone"
msgstr "Wähle ein Projekt aus, um die Zone auszuwählen"
-msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select zone"
@@ -5978,9 +6198,18 @@ msgstr ""
msgid "ClusterIntegration|There was a problem authenticating with your cluster. Please ensure your CA Certificate and Token are valid."
msgstr ""
+msgid "ClusterIntegration|There was an HTTP error when connecting to your cluster."
+msgstr ""
+
msgid "ClusterIntegration|This account must have permissions to create a Kubernetes cluster in the %{link_to_container_project} specified below"
msgstr "Dieses Konto benötigt die Berechtigungen um ein Kubernetes-Cluster in dem untenstehenden %{link_to_container_project} zu erstellen"
+msgid "ClusterIntegration|This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
+msgstr ""
+
+msgid "ClusterIntegration|This is necessary to clear existing environment-namespace associations from clusters previously managed by GitLab."
+msgstr ""
+
msgid "ClusterIntegration|This option will allow you to install applications on RBAC clusters."
msgstr "Mit dieser Option kannst du Anwendungen auf RBAC-Clustern installieren."
@@ -6005,9 +6234,21 @@ msgstr ""
msgid "ClusterIntegration|To use a new project, first create one on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}."
msgstr ""
+msgid "ClusterIntegration|Troubleshooting tips:"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Authenticate"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Connect"
+msgstr ""
+
msgid "ClusterIntegration|Uninstall %{appTitle}"
msgstr "%{appTitle} deinstallieren"
+msgid "ClusterIntegration|Unknown Error"
+msgstr ""
+
msgid "ClusterIntegration|Update %{appTitle}"
msgstr ""
@@ -6068,7 +6309,7 @@ msgstr "Dein Account benötigt eine %{link_to_kubernetes_engine}"
msgid "ClusterIntegration|Your cluster API is unreachable. Please ensure your API URL is correct."
msgstr ""
-msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Zone"
@@ -6188,6 +6429,9 @@ msgstr ""
msgid "Collapse"
msgstr "Reduzieren"
+msgid "Collapse all threads"
+msgstr ""
+
msgid "Collapse approvers"
msgstr "Genehmigungsberechtigte ausblenden"
@@ -6337,8 +6581,8 @@ msgstr "Committed von"
msgid "Commit…"
msgstr "Commit…"
-msgid "Company"
-msgstr "Unternehmen"
+msgid "Community forum"
+msgstr ""
msgid "Company name"
msgstr ""
@@ -6346,6 +6590,9 @@ msgstr ""
msgid "Compare"
msgstr "Vergleichen"
+msgid "Compare %{oldCommitId}...%{newCommitId}"
+msgstr ""
+
msgid "Compare Git revisions"
msgstr "Vergleiche Git-Revisionen"
@@ -6361,6 +6608,9 @@ msgstr "Vergleiche Änderungen mit dem letzten Commit"
msgid "Compare changes with the merge request target branch"
msgstr "Vergleiche die Änderungen mit dem Zielbranch des Merge-Requests"
+msgid "Compare submodule commit revisions"
+msgstr ""
+
msgid "Compare with previous version"
msgstr ""
@@ -6496,6 +6746,9 @@ msgstr "Die %{link}-Integration konfigurieren."
msgid "Configure the way a user creates a new account."
msgstr "Konfiguriere, wie ein(e) Benutzer(in) ein neues Konto erstellt."
+msgid "Configure which lists are shown for anyone who visits this board"
+msgstr ""
+
msgid "Confirm"
msgstr "Bestätigen"
@@ -6721,6 +6974,9 @@ msgstr[1] ""
msgid "ContainerRegistry|Set cleanup policy"
msgstr ""
+msgid "ContainerRegistry|Some tags were not deleted"
+msgstr ""
+
msgid "ContainerRegistry|Something went wrong while fetching the cleanup policy."
msgstr ""
@@ -6760,6 +7016,9 @@ msgstr ""
msgid "ContainerRegistry|Tags with names matching this regex pattern will %{italicStart}expire:%{italicEnd}"
msgstr ""
+msgid "ContainerRegistry|The cleanup policy timed out before it could delete all tags. An administrator can %{adminLinkStart}manually run cleanup now%{adminLinkEnd} or you can wait for the cleanup policy to automatically run again. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "ContainerRegistry|The last tag related to this image was recently removed. This empty image and any associated data will be automatically removed as part of the regular Garbage Collection process. If you have any questions, contact your administrator."
msgstr ""
@@ -6892,6 +7151,9 @@ msgstr ""
msgid "Contributions per group member"
msgstr "Beiträge pro Gruppenmitglied"
+msgid "Contributor"
+msgstr ""
+
msgid "Contributors"
msgstr "Mitwirkende"
@@ -7021,6 +7283,9 @@ msgstr ""
msgid "Could not change HEAD: branch '%{branch}' does not exist"
msgstr ""
+msgid "Could not commit. An unexpected error occurred."
+msgstr ""
+
msgid "Could not connect to FogBugz, check your URL"
msgstr ""
@@ -7060,6 +7325,9 @@ msgstr ""
msgid "Could not find iteration"
msgstr ""
+msgid "Could not load instance counts. Please refresh the page to try again."
+msgstr ""
+
msgid "Could not remove the trigger."
msgstr ""
@@ -7084,10 +7352,10 @@ msgstr ""
msgid "Could not save prometheus manual configuration"
msgstr ""
-msgid "Could not udpdate wiki page"
+msgid "Could not update the LDAP settings"
msgstr ""
-msgid "Could not update the LDAP settings"
+msgid "Could not update wiki page"
msgstr ""
msgid "Could not upload your designs as one or more files uploaded are not supported."
@@ -7745,6 +8013,9 @@ msgstr ""
msgid "DastProfiles|Are you sure you want to delete this profile?"
msgstr ""
+msgid "DastProfiles|Could not create site validation token. Please refresh the page, or try again later."
+msgstr ""
+
msgid "DastProfiles|Could not create the scanner profile. Please try again."
msgstr ""
@@ -7769,6 +8040,12 @@ msgstr ""
msgid "DastProfiles|Could not fetch site profiles. Please refresh the page, or try again later."
msgstr ""
+msgid "DastProfiles|Could not retrieve site validation status. Please refresh the page, or try again later."
+msgstr ""
+
+msgid "DastProfiles|Could not update the scanner profile. Please try again."
+msgstr ""
+
msgid "DastProfiles|Could not update the site profile. Please try again."
msgstr ""
@@ -7784,7 +8061,7 @@ msgstr ""
msgid "DastProfiles|Download validation text file"
msgstr ""
-msgid "DastProfiles|Edit feature will come soon. Please create a new profile if changes needed"
+msgid "DastProfiles|Edit scanner profile"
msgstr ""
msgid "DastProfiles|Edit site profile"
@@ -7817,6 +8094,9 @@ msgstr ""
msgid "DastProfiles|No profiles created yet"
msgstr ""
+msgid "DastProfiles|Passive"
+msgstr ""
+
msgid "DastProfiles|Please enter a valid URL format, ex: http://www.example.com/home"
msgstr ""
@@ -7832,6 +8112,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan mode"
+msgstr ""
+
msgid "DastProfiles|Scanner Profile"
msgstr ""
@@ -7871,10 +8154,10 @@ msgstr ""
msgid "DastProfiles|Text file validation"
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
+msgid "DastProfiles|The maximum number of minutes allowed for the spider to traverse the site."
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the spider to traverse the site."
+msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
msgstr ""
msgid "DastProfiles|Validate"
@@ -7907,6 +8190,9 @@ msgstr ""
msgid "Date picker"
msgstr "Datumsauswahl"
+msgid "Date range"
+msgstr ""
+
msgid "Date range cannot exceed %{maxDateRange} days."
msgstr ""
@@ -7931,6 +8217,9 @@ msgstr ""
msgid "Days to merge"
msgstr ""
+msgid "Dear Administrator,"
+msgstr ""
+
msgid "Debug"
msgstr "Debug"
@@ -8042,12 +8331,18 @@ msgstr "verzögert"
msgid "Delete"
msgstr "Löschen"
+msgid "Delete %{name}"
+msgstr ""
+
msgid "Delete Comment"
msgstr ""
msgid "Delete Snippet"
msgstr "Codeausschnitt löschen"
+msgid "Delete Value Stream"
+msgstr ""
+
msgid "Delete account"
msgstr ""
@@ -8069,9 +8364,6 @@ msgstr ""
msgid "Delete label: %{label_name} ?"
msgstr ""
-msgid "Delete license"
-msgstr ""
-
msgid "Delete list"
msgstr "Liste löschen"
@@ -8147,15 +8439,6 @@ msgstr ""
msgid "Deleting a project places it into a read-only state until %{date}, at which point the project will be permanently deleted. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "Deleting the license failed."
-msgstr ""
-
-msgid "Deleting the license failed. The license was not found."
-msgstr ""
-
-msgid "Deleting the license failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "Deleting the project will delete its repository and all related resources including issues, merge requests etc."
msgstr ""
@@ -8651,7 +8934,10 @@ msgstr ""
msgid "DesignManagement|The maximum number of designs allowed to be uploaded is %{upload_limit}. Please try again."
msgstr ""
-msgid "DesignManagement|To upload designs, you'll need to enable LFS. %{requirements_link_start}More information%{requirements_link_end}"
+msgid "DesignManagement|There was an error moving your designs. Please upload your designs below."
+msgstr ""
+
+msgid "DesignManagement|To upload designs, you'll need to enable LFS and have admin enable hashed storage. %{requirements_link_start}More information%{requirements_link_end}"
msgstr ""
msgid "DesignManagement|Unresolve thread"
@@ -8663,6 +8949,9 @@ msgstr ""
msgid "DesignManagement|Upload skipped."
msgstr ""
+msgid "DesignManagement|Your designs are being copied and are on their way… Please refresh to update."
+msgstr ""
+
msgid "DesignManagement|and %{moreCount} more."
msgstr ""
@@ -8720,6 +9009,9 @@ msgstr ""
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr "Etwas ging schief, während die Diff-Zeilen abgerufen wurden."
+msgid "Direct member"
+msgstr ""
+
msgid "Direction"
msgstr "Richtung"
@@ -8768,9 +9060,6 @@ msgstr "Änderungen in %{path} verwerfen?"
msgid "Discard draft"
msgstr "Entwurf verwerfen"
-msgid "Discard review"
-msgstr "Review verwerfen"
-
msgid "DiscordService|Discord Notifications"
msgstr "Discord-Benachrichtigungen"
@@ -8839,10 +9128,10 @@ msgstr ""
msgid "Dismiss Merge Request promotion"
msgstr "Hervorheben des Merge-Requests beenden"
-msgid "Dismiss Selected"
+msgid "Dismiss Value Stream Analytics introduction box"
msgstr ""
-msgid "Dismiss Value Stream Analytics introduction box"
+msgid "Dismiss selected"
msgstr ""
msgid "Dismiss trial promotion"
@@ -8893,9 +9182,6 @@ msgstr "Dokumentation für gängige Identitätsanbieter"
msgid "Documents reindexed: %{processed_documents} (%{percentage}%%)"
msgstr ""
-msgid "Doing"
-msgstr "In Bearbeitung"
-
msgid "Domain"
msgstr "Domäne"
@@ -9091,9 +9377,6 @@ msgstr "Beschreibung bearbeiten"
msgid "Edit environment"
msgstr "Umgebung bearbeiten"
-msgid "Edit file"
-msgstr "Datei bearbeiten"
-
msgid "Edit files in the editor and commit changes here"
msgstr "Bearbeite Dateien im Editor und committe die Änderungen hier"
@@ -9106,6 +9389,12 @@ msgstr "Gruppe bearbeiten: %{group_name}"
msgid "Edit identity for %{user_name}"
msgstr "Identität für %{user_name} bearbeiten"
+msgid "Edit in Web IDE"
+msgstr ""
+
+msgid "Edit in single-file editor"
+msgstr ""
+
msgid "Edit issues"
msgstr "Tickets bearbeiten"
@@ -9133,21 +9422,18 @@ msgstr ""
msgid "Editing"
msgstr ""
-msgid "Elasticsearch"
-msgstr "Elasticsearch"
-
msgid "Elasticsearch AWS IAM credentials"
msgstr ""
+msgid "Elasticsearch HTTP client timeout value in seconds."
+msgstr ""
+
msgid "Elasticsearch indexing restrictions"
msgstr "Indizierungsbeschränkungen für Elasticsearch"
msgid "Elasticsearch indexing started"
msgstr "Elasticsearch Indizierung gestartet"
-msgid "Elasticsearch integration. Elasticsearch AWS IAM."
-msgstr "Elasticsearch-Integration. Elasticsearch AWS IAM."
-
msgid "Elasticsearch reindexing is already in progress"
msgstr ""
@@ -9175,9 +9461,6 @@ msgstr ""
msgid "Email Notification"
msgstr ""
-msgid "Email address"
-msgstr "E-Mail-Adresse"
-
msgid "Email could not be sent"
msgstr ""
@@ -9241,6 +9524,9 @@ msgstr "E-Mails"
msgid "Emails sent from Service Desk will have this name"
msgstr ""
+msgid "Emails sent to %{email} will still be supported"
+msgstr ""
+
msgid "Emails separated by comma"
msgstr ""
@@ -9274,9 +9560,18 @@ msgstr ""
msgid "Enable"
msgstr "Aktivieren"
+msgid "Enable %{link_start}Gitpod%{link_end} integration to launch a development environment in your browser directly from GitLab."
+msgstr ""
+
msgid "Enable Auto DevOps"
msgstr "Auto-DevOps aktivieren"
+msgid "Enable Gitpod"
+msgstr ""
+
+msgid "Enable Gitpod?"
+msgstr ""
+
msgid "Enable HTML emails"
msgstr ""
@@ -9406,9 +9701,6 @@ msgstr ""
msgid "Encountered an error while rendering: %{err}"
msgstr ""
-msgid "End date"
-msgstr ""
-
msgid "Ends at (UTC)"
msgstr "Endet am (UTC)"
@@ -9568,7 +9860,7 @@ msgstr "Entfernen"
msgid "EnvironmentsDashboard|The environments dashboard provides a summary of each project's environments' status, including pipeline and alert statuses."
msgstr ""
-msgid "EnvironmentsDashboard|This dashboard displays a maximum of 7 projects and 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
+msgid "EnvironmentsDashboard|This dashboard displays 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
msgstr ""
msgid "Environments|An error occurred while canceling the auto stop, please try again"
@@ -9889,6 +10181,9 @@ msgstr ""
msgid "Error deleting project. Check logs for error details."
msgstr ""
+msgid "Error fetching burnup chart data"
+msgstr ""
+
msgid "Error fetching diverging counts for branches. Please try again."
msgstr ""
@@ -9967,6 +10262,9 @@ msgstr ""
msgid "Error occurred when saving assignees"
msgstr ""
+msgid "Error occurred when saving reviewers"
+msgstr ""
+
msgid "Error occurred when toggling the notification subscription"
msgstr "Beim Umschalten des Benachrichtigungs-Abonnements trat ein Fehler auf"
@@ -10219,12 +10517,15 @@ msgstr "Aufklappen"
msgid "Expand all"
msgstr "Alle erweitern"
-msgid "Expand approvers"
-msgstr "Genehmigungsberechtigte anzeigen"
+msgid "Expand all files"
+msgstr ""
-msgid "Expand dropdown"
+msgid "Expand all threads"
msgstr ""
+msgid "Expand approvers"
+msgstr "Genehmigungsberechtigte anzeigen"
+
msgid "Expand milestones"
msgstr ""
@@ -10393,6 +10694,9 @@ msgstr "Verwandte Branches konnten nicht überprüft werden."
msgid "Failed to create Merge Request. Please try again."
msgstr ""
+msgid "Failed to create To-Do for the design."
+msgstr ""
+
msgid "Failed to create a branch for this issue. Please try again."
msgstr ""
@@ -10432,6 +10736,12 @@ msgstr ""
msgid "Failed to load authors. Please try again."
msgstr ""
+msgid "Failed to load branches. Please try again."
+msgstr ""
+
+msgid "Failed to load deploy keys."
+msgstr ""
+
msgid "Failed to load emoji list."
msgstr "Fehler beim Laden der Emoji-Liste."
@@ -10447,6 +10757,9 @@ msgstr ""
msgid "Failed to load groups & users."
msgstr ""
+msgid "Failed to load groups, users and deploy keys."
+msgstr ""
+
msgid "Failed to load labels. Please try again."
msgstr ""
@@ -10456,6 +10769,12 @@ msgstr ""
msgid "Failed to load related branches"
msgstr ""
+msgid "Failed to load sidebar confidential toggle"
+msgstr ""
+
+msgid "Failed to load sidebar lock status"
+msgstr ""
+
msgid "Failed to load stacktrace."
msgstr ""
@@ -10483,6 +10802,9 @@ msgstr ""
msgid "Failed to publish issue on status page."
msgstr ""
+msgid "Failed to remove To-Do for the design."
+msgstr ""
+
msgid "Failed to remove a Zoom meeting"
msgstr ""
@@ -10525,6 +10847,9 @@ msgstr ""
msgid "Failed to signing using smartcard authentication"
msgstr "Signieren mit Smartcard-Authentifizierung fehlgeschlagen"
+msgid "Failed to toggle To-Do for the design."
+msgstr ""
+
msgid "Failed to update branch!"
msgstr ""
@@ -10638,7 +10963,7 @@ msgstr "Feature-Flag bearbeiten"
msgid "FeatureFlags|Edit User List"
msgstr ""
-msgid "FeatureFlags|Enable features for specific users and specific environments by defining feature flag strategies."
+msgid "FeatureFlags|Enable features for specific users and environments by configuring feature flag strategies."
msgstr ""
msgid "FeatureFlags|Environment Spec"
@@ -10698,7 +11023,7 @@ msgstr ""
msgid "FeatureFlags|Include additional user IDs"
msgstr ""
-msgid "FeatureFlags|Install a %{docs_link_anchored_start}compatible client library%{docs_link_anchored_end} and specify the API URL, application name, and instance ID during the configuration setup. %{docs_link_start}More Information%{docs_link_end}"
+msgid "FeatureFlags|Install a %{docsLinkAnchoredStart}compatible client library%{docsLinkAnchoredEnd} and specify the API URL, application name, and instance ID during the configuration setup. %{docsLinkStart}More Information%{docsLinkEnd}"
msgstr ""
msgid "FeatureFlags|Instance ID"
@@ -10710,6 +11035,9 @@ msgstr ""
msgid "FeatureFlags|Loading feature flags"
msgstr ""
+msgid "FeatureFlags|Loading user lists"
+msgstr ""
+
msgid "FeatureFlags|More information"
msgstr ""
@@ -10728,7 +11056,7 @@ msgstr ""
msgid "FeatureFlags|New feature flag"
msgstr ""
-msgid "FeatureFlags|New list"
+msgid "FeatureFlags|New user list"
msgstr ""
msgid "FeatureFlags|Percent of users"
@@ -10767,6 +11095,9 @@ msgstr ""
msgid "FeatureFlags|There was an error fetching the feature flags."
msgstr ""
+msgid "FeatureFlags|There was an error fetching the user lists."
+msgstr ""
+
msgid "FeatureFlags|There was an error retrieving user lists"
msgstr ""
@@ -10782,6 +11113,9 @@ msgstr ""
msgid "FeatureFlags|User List"
msgstr ""
+msgid "FeatureFlags|User Lists"
+msgstr ""
+
msgid "FeatureFlag|List"
msgstr ""
@@ -10809,15 +11143,6 @@ msgstr "Februar"
msgid "Fetching incoming email"
msgstr ""
-msgid "Fetching licenses failed."
-msgstr ""
-
-msgid "Fetching licenses failed. The request endpoint was not found."
-msgstr ""
-
-msgid "Fetching licenses failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "File"
msgstr ""
@@ -10920,12 +11245,21 @@ msgstr ""
msgid "Filter by status"
msgstr ""
+msgid "Filter by test cases that are currently archived."
+msgstr ""
+
+msgid "Filter by test cases that are currently opened."
+msgstr ""
+
msgid "Filter by two-factor authentication"
msgstr ""
msgid "Filter by user"
msgstr ""
+msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
+msgstr ""
+
msgid "Filter pipelines"
msgstr ""
@@ -10941,7 +11275,7 @@ msgstr ""
msgid "Filter results..."
msgstr ""
-msgid "Filter your projects by name"
+msgid "Filter your repositories by name"
msgstr ""
msgid "Filter..."
@@ -10950,7 +11284,7 @@ msgstr "Filter..."
msgid "Find File"
msgstr ""
-msgid "Find bugs in your code with coverage-guided fuzzing"
+msgid "Find bugs in your code with coverage-guided fuzzing."
msgstr ""
msgid "Find by path"
@@ -10977,9 +11311,6 @@ msgstr "Fingerabdrücke"
msgid "Finish editing this message first!"
msgstr ""
-msgid "Finish review"
-msgstr "Review beenden"
-
msgid "Finish setting up your dedicated account for %{group_name}."
msgstr ""
@@ -11049,6 +11380,9 @@ msgstr "Schriftfarbe"
msgid "Footer message"
msgstr "Fußzeilennachricht"
+msgid "For a faster browsing experience, some files are collapsed by default."
+msgstr ""
+
msgid "For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
@@ -11058,6 +11392,9 @@ msgstr "Bei interne Projekte kann jede(r) angemeldete Benutzer(in) die Pipelines
msgid "For more info, read the documentation."
msgstr ""
+msgid "For more information on how the number of active users is calculated, see the %{self_managed_subscriptions_doc_link} documentation."
+msgstr ""
+
msgid "For more information, go to the "
msgstr "Für mehr Informationen, gehe zu "
@@ -11196,6 +11533,9 @@ msgstr ""
msgid "Generate new token"
msgstr ""
+msgid "Generic package file size in bytes"
+msgstr ""
+
msgid "Geo"
msgstr "Geo"
@@ -11457,6 +11797,9 @@ msgstr "Ausstehende Überprüfung"
msgid "Geo|Please refer to Geo Troubleshooting."
msgstr ""
+msgid "Geo|Primary node"
+msgstr ""
+
msgid "Geo|Project"
msgstr ""
@@ -11499,6 +11842,9 @@ msgstr ""
msgid "Geo|Review replication status, and resynchronize and reverify items with the primary node."
msgstr ""
+msgid "Geo|Secondary node"
+msgstr ""
+
msgid "Geo|Status"
msgstr "Status"
@@ -11538,6 +11884,9 @@ msgstr ""
msgid "Geo|URL must be a valid url (ex: https://gitlab.com)"
msgstr ""
+msgid "Geo|Undefined"
+msgstr ""
+
msgid "Geo|Unknown state"
msgstr "Unbekannter Status"
@@ -11613,10 +11962,16 @@ msgstr ""
msgid "GitHub import"
msgstr "GitHub-Import"
+msgid "GitLab"
+msgstr ""
+
msgid "GitLab / Unsubscribe"
msgstr ""
-msgid "GitLab Enterprise Edition %{plan}"
+msgid "GitLab API"
+msgstr ""
+
+msgid "GitLab Billing Team."
msgstr ""
msgid "GitLab Group Runners can execute code for all the projects in this group."
@@ -11628,12 +11983,18 @@ msgstr "GitLab-Import"
msgid "GitLab Issue"
msgstr ""
+msgid "GitLab Pages"
+msgstr ""
+
msgid "GitLab Service Desk is a simple way to allow people to create issues in your GitLab instance without needing their own user account. It provides a unique email address for end users to create issues in a project, and replies can be sent either through the GitLab interface or by email. End users will only see the thread through email."
msgstr ""
msgid "GitLab Shared Runners execute code of different projects on the same Runner unless you configure GitLab Runner Autoscale with MaxBuilds 1 (which it is on GitLab.com)."
msgstr ""
+msgid "GitLab Shell"
+msgstr ""
+
msgid "GitLab Support Bot"
msgstr ""
@@ -11643,7 +12004,7 @@ msgstr ""
msgid "GitLab User"
msgstr "GitLab-Nutzer(in)"
-msgid "GitLab allows you to continue using your license even if you exceed the number of seats you purchased. You will be required to pay for these seats when you renew your license."
+msgid "GitLab Workhorse"
msgstr ""
msgid "GitLab commit"
@@ -11811,6 +12172,21 @@ msgstr "Gitea-Import"
msgid "Gitlab Pages"
msgstr ""
+msgid "Gitpod"
+msgstr ""
+
+msgid "Gitpod|Add the URL to your Gitpod instance configured to read your GitLab projects."
+msgstr ""
+
+msgid "Gitpod|Enable Gitpod integration"
+msgstr ""
+
+msgid "Gitpod|Gitpod URL"
+msgstr ""
+
+msgid "Gitpod|e.g. https://gitpod.example.com"
+msgstr ""
+
msgid "Given access %{time_ago}"
msgstr ""
@@ -12318,9 +12694,6 @@ msgstr ""
msgid "GroupSAML|Valid SAML Response"
msgstr ""
-msgid "GroupSAML|With group managed accounts enabled, all the users without a group managed account will be excluded from the group."
-msgstr ""
-
msgid "GroupSAML|With prohibit outer forks flag enabled group members will be able to fork project only inside your group."
msgstr ""
@@ -12534,10 +12907,10 @@ msgstr ""
msgid "GroupsNew|Create group"
msgstr ""
-msgid "GroupsNew|GitLab group export"
+msgid "GroupsNew|Import"
msgstr ""
-msgid "GroupsNew|Import"
+msgid "GroupsNew|Import a GitLab group export file"
msgstr ""
msgid "GroupsNew|Import group"
@@ -12680,6 +13053,9 @@ msgid_plural "Hide charts"
msgstr[0] ""
msgstr[1] ""
+msgid "Hide comments on this file"
+msgstr ""
+
msgid "Hide details"
msgstr ""
@@ -12724,6 +13100,15 @@ msgstr ""
msgid "Highest role:"
msgstr ""
+msgid "HighlightBar|Alert events:"
+msgstr ""
+
+msgid "HighlightBar|Alert start time:"
+msgstr ""
+
+msgid "HighlightBar|Original alert:"
+msgstr ""
+
msgid "History"
msgstr "Verlauf"
@@ -12901,6 +13286,9 @@ msgstr ""
msgid "If enabled, access to projects will be validated on an external service using their classification label."
msgstr "Wenn diese Option aktiviert ist, wird der Zugriff auf Projekte mit einem externen Service anhand ihrer Klassifizierungslabels überprüft."
+msgid "If the number of active users exceeds the user limit, you will be charged for the number of %{users_over_license_link} at your next license reconciliation."
+msgstr ""
+
msgid "If there is no previous license or if the previous license has expired, some GitLab functionality will be blocked until a new, valid license is uploaded."
msgstr ""
@@ -12940,9 +13328,6 @@ msgstr ""
msgid "If your HTTP repository is not publicly accessible, add your credentials."
msgstr ""
-msgid "Iglu registry URL (optional)"
-msgstr ""
-
msgid "Ignore"
msgstr ""
@@ -12979,6 +13364,16 @@ msgstr ""
msgid "Import"
msgstr "Importieren"
+msgid "Import %d compatible repository"
+msgid_plural "Import %d compatible repositories"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Import %d repository"
+msgid_plural "Import %d repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Import CSV"
msgstr ""
@@ -12988,15 +13383,9 @@ msgstr "Importiere Projekte von Gitea"
msgid "Import all compatible projects"
msgstr "Importiere alle kompatiblen Projekte"
-msgid "Import all compatible repositories"
-msgstr ""
-
msgid "Import all projects"
msgstr "Alle Projekte importieren"
-msgid "Import all repositories"
-msgstr "Alle Repositories importieren"
-
msgid "Import an exported GitLab project"
msgstr "Importiere ein exportiertes GitLab-Projekt"
@@ -13084,6 +13473,9 @@ msgstr ""
msgid "ImportProjects|Error importing repository %{project_safe_import_url} into %{project_full_path} - %{message}"
msgstr ""
+msgid "ImportProjects|Import repositories"
+msgstr ""
+
msgid "ImportProjects|Importing the project failed"
msgstr ""
@@ -13096,7 +13488,7 @@ msgstr ""
msgid "ImportProjects|Requesting your %{provider} repositories failed"
msgstr ""
-msgid "ImportProjects|Select the projects you want to import"
+msgid "ImportProjects|Select the repositories you want to import"
msgstr ""
msgid "ImportProjects|The remote data could not be imported."
@@ -13132,9 +13524,6 @@ msgstr ""
msgid "In order to enable Service Desk for your instance, you must first set up incoming email."
msgstr ""
-msgid "In order to gather accurate feature usage data, it can take 1 to 2 weeks to see your index."
-msgstr ""
-
msgid "In order to personalize your experience with GitLab%{br_tag}we would like to know a bit more about you."
msgstr ""
@@ -13165,18 +13554,30 @@ msgstr ""
msgid "IncidentManagement|Create incident"
msgstr ""
+msgid "IncidentManagement|Critical - S1"
+msgstr ""
+
msgid "IncidentManagement|Date created"
msgstr ""
msgid "IncidentManagement|Display your incidents in a dedicated view"
msgstr ""
+msgid "IncidentManagement|High - S2"
+msgstr ""
+
msgid "IncidentManagement|Incident"
msgstr ""
msgid "IncidentManagement|Incidents"
msgstr ""
+msgid "IncidentManagement|Low - S4"
+msgstr ""
+
+msgid "IncidentManagement|Medium - S3"
+msgstr ""
+
msgid "IncidentManagement|No incidents to display."
msgstr ""
@@ -13189,6 +13590,9 @@ msgstr ""
msgid "IncidentManagement|Published to status page"
msgstr ""
+msgid "IncidentManagement|Severity"
+msgstr ""
+
msgid "IncidentManagement|There are no closed incidents"
msgstr ""
@@ -13198,6 +13602,9 @@ msgstr ""
msgid "IncidentManagement|Unassigned"
msgstr ""
+msgid "IncidentManagement|Unknown"
+msgstr ""
+
msgid "IncidentManagement|Unpublished"
msgstr ""
@@ -13219,6 +13626,15 @@ msgstr ""
msgid "Incidents"
msgstr ""
+msgid "Incident|Alert details"
+msgstr ""
+
+msgid "Incident|Summary"
+msgstr ""
+
+msgid "Incident|There was an issue loading alert data. Please try again."
+msgstr ""
+
msgid "Include a Terms of Service agreement and Privacy Policy that all users must accept."
msgstr "Füge Nutzungsbedingungen und eine Datenschutzrichtlinie hinzu, die alle Benutzer(innen) akzeptieren müssen."
@@ -13279,6 +13695,9 @@ msgstr ""
msgid "Information about additional Pages templates and how to install them can be found in our %{pages_getting_started_guide}."
msgstr ""
+msgid "Inherited"
+msgstr ""
+
msgid "Inherited:"
msgstr ""
@@ -13359,7 +13778,22 @@ msgstr ""
msgid "Instance administrators group already exists"
msgstr ""
-msgid "Instance license"
+msgid "InstanceStatistics|Groups"
+msgstr ""
+
+msgid "InstanceStatistics|Issues"
+msgstr ""
+
+msgid "InstanceStatistics|Merge Requests"
+msgstr ""
+
+msgid "InstanceStatistics|Pipelines"
+msgstr ""
+
+msgid "InstanceStatistics|Projects"
+msgstr ""
+
+msgid "InstanceStatistics|Users"
msgstr ""
msgid "Integration"
@@ -13371,6 +13805,12 @@ msgstr ""
msgid "Integrations"
msgstr "Integrationen"
+msgid "Integrations|%{integration} settings saved and active."
+msgstr ""
+
+msgid "Integrations|%{integration} settings saved, but not active."
+msgstr ""
+
msgid "Integrations|All details"
msgstr ""
@@ -13380,6 +13820,12 @@ msgstr ""
msgid "Integrations|Comment settings:"
msgstr ""
+msgid "Integrations|Connection failed. Please check your settings."
+msgstr ""
+
+msgid "Integrations|Connection successful."
+msgstr ""
+
msgid "Integrations|Default settings are inherited from the group level."
msgstr ""
@@ -13395,6 +13841,15 @@ msgstr ""
msgid "Integrations|Includes commit title and branch"
msgstr ""
+msgid "Integrations|Projects using custom settings will not be impacted unless the project owner chooses to use instance-level defaults."
+msgstr ""
+
+msgid "Integrations|Save settings?"
+msgstr ""
+
+msgid "Integrations|Saving will update the default settings for all projects that are not using custom settings."
+msgstr ""
+
msgid "Integrations|Standard"
msgstr ""
@@ -13527,6 +13982,9 @@ msgstr ""
msgid "Invitation"
msgstr ""
+msgid "Invitation declined"
+msgstr ""
+
msgid "Invite"
msgstr "Einladen"
@@ -13578,6 +14036,42 @@ 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|%{linkStart}Read more%{linkEnd} about role permissions"
+msgstr ""
+
+msgid "InviteMembersModal|Access expiration date (optional)"
+msgstr ""
+
+msgid "InviteMembersModal|Cancel"
+msgstr ""
+
+msgid "InviteMembersModal|Choose a role permission"
+msgstr ""
+
+msgid "InviteMembersModal|GitLab member or Email address"
+msgstr ""
+
+msgid "InviteMembersModal|Invite"
+msgstr ""
+
+msgid "InviteMembersModal|Invite team members"
+msgstr ""
+
+msgid "InviteMembersModal|Search for members to invite"
+msgstr ""
+
+msgid "InviteMembersModal|User not invited. Feature coming soon!"
+msgstr ""
+
+msgid "InviteMembersModal|Users were succesfully added"
+msgstr ""
+
+msgid "InviteMembersModal|You're inviting members to the %{group_name} group"
+msgstr ""
+
+msgid "InviteMembers|Invite team members"
+msgstr ""
+
msgid "Invited"
msgstr ""
@@ -13632,10 +14126,13 @@ msgstr ""
msgid "Issue cannot be found."
msgstr ""
+msgid "Issue created from vulnerability %{vulnerability_link}"
+msgstr ""
+
msgid "Issue events"
msgstr "Ticketereignisse"
-msgid "Issue first depoloyed to production"
+msgid "Issue first deployed to production"
msgstr ""
msgid "Issue label"
@@ -13713,6 +14210,9 @@ msgstr ""
msgid "IssueTracker|Custom issue tracker"
msgstr ""
+msgid "IssueTracker|EWM work items tracker"
+msgstr ""
+
msgid "IssueTracker|Redmine issue tracker"
msgstr ""
@@ -13779,6 +14279,9 @@ msgstr "Titel"
msgid "It looks like you have some draft commits in this branch."
msgstr ""
+msgid "It may be several days before you see feature usage data."
+msgstr ""
+
msgid "It must have a header row and at least two columns: the first column is the issue title and the second column is the issue description. The separator is automatically detected."
msgstr ""
@@ -14061,15 +14564,15 @@ msgstr ""
msgid "Join Zoom meeting"
msgstr ""
+msgid "Joined %{time_ago}"
+msgstr ""
+
msgid "Jul"
msgstr "Juli"
msgid "July"
msgstr "Juli"
-msgid "Jump to first unresolved thread"
-msgstr ""
-
msgid "Jump to next unresolved thread"
msgstr ""
@@ -14103,6 +14606,9 @@ msgstr ""
msgid "Keyboard shortcuts"
msgstr ""
+msgid "KeyboardKey|Ctrl+"
+msgstr ""
+
msgid "Keys"
msgstr ""
@@ -14151,6 +14657,9 @@ msgstr ""
msgid "LDAP Synchronization"
msgstr ""
+msgid "LDAP group settings"
+msgstr ""
+
msgid "LDAP settings"
msgstr ""
@@ -14160,6 +14669,9 @@ msgstr ""
msgid "LDAP sync in progress. This could take a few minutes. Refresh the page to see the changes."
msgstr ""
+msgid "LDAP synchronizations"
+msgstr ""
+
msgid "LFS"
msgstr "LFS"
@@ -14240,7 +14752,16 @@ msgid_plural "Last %d days"
msgstr[0] "Letzten %d Tag"
msgstr[1] "Letzten %d Tage"
-msgid "Last %{days} days"
+msgid "Last 2 weeks"
+msgstr ""
+
+msgid "Last 30 days"
+msgstr ""
+
+msgid "Last 60 days"
+msgstr ""
+
+msgid "Last 90 days"
msgstr ""
msgid "Last Accessed On"
@@ -14318,6 +14839,9 @@ msgstr ""
msgid "Last used on:"
msgstr ""
+msgid "Last week"
+msgstr ""
+
msgid "LastCommit|authored"
msgstr ""
@@ -14333,6 +14857,9 @@ msgstr "Letzte Änderungen"
msgid "Latest pipeline for the most recent commit on this branch"
msgstr ""
+msgid "Launch a ready-to-code development environment for your project."
+msgstr ""
+
msgid "Lead"
msgstr ""
@@ -14713,6 +15240,9 @@ msgstr "Verfügbare Repositories auflisten"
msgid "List of all merge commits"
msgstr ""
+msgid "List options"
+msgstr ""
+
msgid "List settings"
msgstr ""
@@ -14725,9 +15255,6 @@ msgstr "Listenansicht"
msgid "List your Bitbucket Server repositories"
msgstr "Liste deine Bitbucket-Server-Repositorys auf"
-msgid "Lists"
-msgstr ""
-
msgid "Live preview"
msgstr "Live-Vorschau"
@@ -14974,6 +15501,12 @@ msgstr ""
msgid "Mark as done"
msgstr ""
+msgid "Mark as draft"
+msgstr ""
+
+msgid "Mark as ready"
+msgstr ""
+
msgid "Mark as resolved"
msgstr ""
@@ -14995,6 +15528,24 @@ msgstr "Markdown aktiviert"
msgid "Markdown is supported"
msgstr ""
+msgid "MarkdownEditor|Add a link (%{modifierKey}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add a link (%{modifier_key}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifierKey}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifier_key}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifierKey}I)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifier_key}I)"
+msgstr ""
+
msgid "Marked For Deletion At - %{deletion_time}"
msgstr ""
@@ -15079,7 +15630,25 @@ msgstr ""
msgid "Max access level"
msgstr "Maximale Zugriffsstufe"
-msgid "Max seats used"
+msgid "Max role"
+msgstr ""
+
+msgid "Max size 15 MB"
+msgstr ""
+
+msgid "Maximum Conan package file size in bytes"
+msgstr ""
+
+msgid "Maximum Maven package file size in bytes"
+msgstr ""
+
+msgid "Maximum NPM package file size in bytes"
+msgstr ""
+
+msgid "Maximum NuGet package file size in bytes"
+msgstr ""
+
+msgid "Maximum PyPI package file size in bytes"
msgstr ""
msgid "Maximum Users:"
@@ -15211,6 +15780,18 @@ msgstr ""
msgid "Members with access to %{strong_start}%{group_name}%{strong_end}"
msgstr ""
+msgid "Members|%{time} by %{user}"
+msgstr ""
+
+msgid "Members|Expired"
+msgstr ""
+
+msgid "Members|No expiration set"
+msgstr ""
+
+msgid "Members|in %{time}"
+msgstr ""
+
msgid "Memory Usage"
msgstr ""
@@ -15397,9 +15978,6 @@ msgstr ""
msgid "MergeRequests|Thread will be unresolved"
msgstr ""
-msgid "MergeRequests|Toggle comments for this file"
-msgstr "Kommentare für diese Datei umschalten"
-
msgid "MergeRequests|View file @ %{commitId}"
msgstr "Datei anzeigen @ %{commitId}"
@@ -15460,6 +16038,9 @@ msgstr ""
msgid "Merging immediately isn't recommended as it may negatively impact the existing merge train. Read the %{docsLinkStart}documentation%{docsLinkEnd} for more information."
msgstr ""
+msgid "Message"
+msgstr ""
+
msgid "Messages"
msgstr "Nachrichten"
@@ -15845,18 +16426,12 @@ msgid_plural "Milestones"
msgstr[0] ""
msgstr[1] ""
-msgid "Milestone does not support burnup charts"
-msgstr ""
-
msgid "Milestone lists not available with your current license"
msgstr "Meilensteinlisten ist mit deiner momentanen Lizenz nicht verfügbar"
msgid "Milestone lists show all issues from the selected milestone."
msgstr "Meilensteinlisten zeigen alle Tickets des ausgewählten Meilensteins an."
-msgid "Milestone must have a start and due date"
-msgstr ""
-
msgid "MilestoneSidebar|Closed:"
msgstr ""
@@ -16223,6 +16798,9 @@ msgstr "Name:"
msgid "Namespace"
msgstr ""
+msgid "Namespace ID:"
+msgstr ""
+
msgid "Namespace is empty"
msgstr "Namensraum ist leer"
@@ -16307,6 +16885,9 @@ msgstr ""
msgid "NetworkPolicies|Allow all outbound traffic from %{selector} to %{ruleSelector} on %{ports}"
msgstr ""
+msgid "NetworkPolicies|Are you sure you want to delete this policy? This action cannot be undone."
+msgstr ""
+
msgid "NetworkPolicies|Choose whether to enforce this policy."
msgstr ""
@@ -16316,12 +16897,21 @@ msgstr ""
msgid "NetworkPolicies|Define this policy's location, conditions and actions."
msgstr ""
+msgid "NetworkPolicies|Delete policy"
+msgstr ""
+
+msgid "NetworkPolicies|Delete policy: %{policy}"
+msgstr ""
+
msgid "NetworkPolicies|Deny all traffic"
msgstr ""
msgid "NetworkPolicies|Description"
msgstr ""
+msgid "NetworkPolicies|Edit policy"
+msgstr ""
+
msgid "NetworkPolicies|Editor mode"
msgstr ""
@@ -16349,6 +16939,9 @@ msgstr ""
msgid "NetworkPolicies|Name"
msgstr ""
+msgid "NetworkPolicies|Namespace"
+msgstr ""
+
msgid "NetworkPolicies|Network Policy"
msgstr ""
@@ -16400,6 +16993,9 @@ msgstr ""
msgid "NetworkPolicies|Rules"
msgstr ""
+msgid "NetworkPolicies|Save changes"
+msgstr ""
+
msgid "NetworkPolicies|Something went wrong, failed to update policy"
msgstr ""
@@ -16412,6 +17008,9 @@ msgstr ""
msgid "NetworkPolicies|Traffic that does not match any rule will be blocked."
msgstr ""
+msgid "NetworkPolicies|Unable to parse policy"
+msgstr ""
+
msgid "NetworkPolicies|YAML editor"
msgstr ""
@@ -16525,6 +17124,9 @@ msgstr ""
msgid "New Snippet"
msgstr "Neuer Codeausschnitt"
+msgid "New Test Case"
+msgstr ""
+
msgid "New User"
msgstr ""
@@ -16624,6 +17226,9 @@ msgstr "Neue Untergruppe"
msgid "New tag"
msgstr "Neuer Tag"
+msgid "New test case"
+msgstr ""
+
msgid "New users set to external"
msgstr ""
@@ -16696,7 +17301,7 @@ msgstr "Keine Branches gefunden"
msgid "No changes"
msgstr "Keine Änderungen"
-msgid "No changes between %{ref_start}%{source_branch}%{ref_end} and %{ref_start}%{target_branch}%{ref_end}"
+msgid "No changes between %{sourceBranch} and %{targetBranch}"
msgstr ""
msgid "No child epics match applied filters"
@@ -16711,6 +17316,9 @@ msgstr "Es konnte keine Verbindung zu einem Gitaly-Server hergestellt werden. Bi
msgid "No containers available"
msgstr ""
+msgid "No content to show"
+msgstr ""
+
msgid "No contributions"
msgstr ""
@@ -16786,9 +17394,6 @@ msgstr "Keine Tags mit einem solchen Namen oder einer solchen Beschreibung"
msgid "No license. All rights reserved"
msgstr "Keine Lizenz. Alle Rechte vorbehalten"
-msgid "No licenses found."
-msgstr ""
-
msgid "No matches found"
msgstr ""
@@ -16801,6 +17406,9 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No members found"
+msgstr ""
+
msgid "No merge requests found"
msgstr "Keine Merge-Requests gefunden"
@@ -16822,6 +17430,9 @@ msgstr ""
msgid "No parent group"
msgstr ""
+msgid "No plan"
+msgstr ""
+
msgid "No pods available"
msgstr ""
@@ -16918,6 +17529,12 @@ msgstr "Keine"
msgid "Not Implemented"
msgstr ""
+msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+msgstr ""
+
+msgid "Not all browsers support WebAuthn. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even from an unsupported browser."
+msgstr ""
+
msgid "Not all data has been processed yet, the accuracy of the chart for the selected timeframe is limited."
msgstr ""
@@ -17014,6 +17631,9 @@ msgstr ""
msgid "Notification settings saved"
msgstr ""
+msgid "NotificationEvent|Change reviewer merge request"
+msgstr ""
+
msgid "NotificationEvent|Close issue"
msgstr "Ticket schließen"
@@ -17176,10 +17796,7 @@ msgstr ""
msgid "On track"
msgstr ""
-msgid "OnDemandScans|Attached branch"
-msgstr ""
-
-msgid "OnDemandScans|Attached branch is where the scan job runs."
+msgid "OnDemandScans|Could not fetch scanner profiles. Please refresh the page, or try again later."
msgstr ""
msgid "OnDemandScans|Could not fetch site profiles. Please refresh the page, or try again later."
@@ -17188,6 +17805,9 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
+msgid "OnDemandScans|Create a new scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Create a new site profile"
msgstr ""
@@ -17200,6 +17820,9 @@ msgstr ""
msgid "OnDemandScans|New on-demand DAST scan"
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 ""
@@ -17209,16 +17832,10 @@ msgstr ""
msgid "OnDemandScans|On-demand scans run outside the DevOps cycle and find vulnerabilities in your projects. %{learnMoreLinkStart}Learn more%{learnMoreLinkEnd}"
msgstr ""
-msgid "OnDemandScans|Only a passive scan can be performed on demand."
-msgstr ""
-
-msgid "OnDemandScans|Passive"
-msgstr ""
-
msgid "OnDemandScans|Run scan"
msgstr ""
-msgid "OnDemandScans|Scan mode"
+msgid "OnDemandScans|Scanner profile"
msgstr ""
msgid "OnDemandScans|Scanner settings"
@@ -17230,9 +17847,15 @@ msgstr ""
msgid "OnDemandScans|Select one of the existing profiles"
msgstr ""
+msgid "OnDemandScans|Site profile"
+msgstr ""
+
msgid "OnDemandScans|Site profiles"
msgstr ""
+msgid "OnDemandScans|Use existing scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Use existing site profile"
msgstr ""
@@ -17331,9 +17954,6 @@ msgstr "Offen"
msgid "Open Selection"
msgstr ""
-msgid "Open Web IDE"
-msgstr ""
-
msgid "Open comment type dropdown"
msgstr ""
@@ -17439,6 +18059,9 @@ msgstr "Oder du wählst eine der unten vorgeschlagenen Farben"
msgid "Origin"
msgstr ""
+msgid "Orphaned member"
+msgstr ""
+
msgid "Other Labels"
msgstr "Andere Labels"
@@ -17454,6 +18077,9 @@ msgstr ""
msgid "Other visibility settings have been disabled by the administrator."
msgstr ""
+msgid "Our documentation includes an example DevOps Score report."
+msgstr ""
+
msgid "Out-of-compliance with this project's policies and should be removed"
msgstr ""
@@ -17478,6 +18104,9 @@ msgstr "Ãœbersicht"
msgid "Overwrite diverged branches"
msgstr "Ãœberschreibe abweichende Branches"
+msgid "Owned by %{image_tag}"
+msgstr ""
+
msgid "Owned by anyone"
msgstr "Im Besitz von irgendwem"
@@ -17499,6 +18128,9 @@ msgstr ""
msgid "Package deleted successfully"
msgstr ""
+msgid "Package file size limits"
+msgstr ""
+
msgid "Package recipe already exists"
msgstr ""
@@ -17514,9 +18146,6 @@ msgstr ""
msgid "Package type must be PyPi"
msgstr ""
-msgid "Package was removed"
-msgstr "Paket wurde entfernt"
-
msgid "PackageRegistry|%{name} version %{version} was created %{datetime}"
msgstr ""
@@ -17658,12 +18287,18 @@ msgstr ""
msgid "PackageRegistry|NuGet Command"
msgstr ""
+msgid "PackageRegistry|Package Registry"
+msgstr ""
+
msgid "PackageRegistry|Pip Command"
msgstr ""
msgid "PackageRegistry|Pipeline %{link} triggered %{datetime} by %{author}"
msgstr ""
+msgid "PackageRegistry|Publish and share packages for a variety of common package managers. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "PackageRegistry|Published to the %{project} Package Registry %{datetime}"
msgstr ""
@@ -17763,6 +18398,9 @@ msgstr ""
msgid "Page not found"
msgstr "Seite nicht gefunden"
+msgid "Page settings"
+msgstr ""
+
msgid "Page was successfully deleted"
msgstr ""
@@ -17904,7 +18542,7 @@ msgstr ""
msgid "Paste issue link"
msgstr ""
-msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Don't use your private SSH key."
+msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Do not paste your private SSH key, as that can compromise your identity."
msgstr ""
msgid "Patch to apply"
@@ -17931,6 +18569,9 @@ msgstr "Angehaltene Runner akzeptieren keine neuen Jobs"
msgid "Pending"
msgstr "In Arbeit"
+msgid "Pending comments"
+msgstr ""
+
msgid "People without permission will never get a notification and won't be able to comment."
msgstr "Personen ohne Berechtigung werden nie eine Benachrichtigung bekommen und können auch nicht kommentieren."
@@ -18129,6 +18770,9 @@ msgstr ""
msgid "Pipelines|Build with confidence"
msgstr "Baue mit Vertrauen"
+msgid "Pipelines|By revoking a trigger you will break any processes making use of it. Are you sure?"
+msgstr ""
+
msgid "Pipelines|CI Lint"
msgstr "CI Lint"
@@ -18141,6 +18785,15 @@ msgstr "Runner-Caches löschen"
msgid "Pipelines|Continuous Integration can help catch bugs by running your tests automatically, while Continuous Deployment can help you deliver code to your product environment."
msgstr "Kontinuierliche Integration (CI) kann dabei helfen, Fehler zu erkennen, indem es deine Tests automatisch ausführt. Kontinuierliche Bereitstellung (CD) wiederum kann dir helfen, Code für deine Produktumgebung bereitzustellen."
+msgid "Pipelines|Copy trigger token"
+msgstr ""
+
+msgid "Pipelines|Description"
+msgstr ""
+
+msgid "Pipelines|Edit"
+msgstr ""
+
msgid "Pipelines|Get started with Pipelines"
msgstr "Erste Schritte mit Pipelines"
@@ -18156,15 +18809,27 @@ msgstr ""
msgid "Pipelines|It is recommended the code is reviewed thoroughly before running this pipeline with the parent project's CI resource."
msgstr ""
+msgid "Pipelines|Last Used"
+msgstr ""
+
msgid "Pipelines|Loading Pipelines"
msgstr "Pipelines laden"
msgid "Pipelines|More Information"
msgstr ""
+msgid "Pipelines|No triggers have been created yet. Add one using the form above."
+msgstr ""
+
+msgid "Pipelines|Owner"
+msgstr ""
+
msgid "Pipelines|Project cache successfully reset."
msgstr "Der Projekt-Cache wurde erfolgreich zurückgesetzt."
+msgid "Pipelines|Revoke"
+msgstr ""
+
msgid "Pipelines|Run Pipeline"
msgstr "Pipeline ausführen"
@@ -18189,6 +18854,15 @@ msgstr ""
msgid "Pipelines|This project is not currently set up to run pipelines."
msgstr "Dieses Projekt ist derzeit nicht zum Ausführen von Pipelines eingerichtet."
+msgid "Pipelines|Token"
+msgstr ""
+
+msgid "Pipelines|Trigger user has insufficient permissions to project"
+msgstr ""
+
+msgid "Pipelines|invalid"
+msgstr ""
+
msgid "Pipelines|parent"
msgstr ""
@@ -18447,10 +19121,10 @@ msgstr ""
msgid "Please provide attributes to update"
msgstr ""
-msgid "Please refer to %{docs_url}"
+msgid "Please reach out if you have any questions and we'll be happy to assist."
msgstr ""
-msgid "Please retype the email address."
+msgid "Please refer to %{docs_url}"
msgstr ""
msgid "Please select"
@@ -18480,6 +19154,9 @@ msgstr "Bitte wähle zumindest einen Filter um Ergebnisse zu sehen"
msgid "Please set a new password before proceeding."
msgstr ""
+msgid "Please share your feedback about %{featureName} %{linkStart}in this issue%{linkEnd} to help us improve the experience."
+msgstr ""
+
msgid "Please solve the reCAPTCHA"
msgstr "Bitte löse das reCAPTCHA"
@@ -18783,6 +19460,9 @@ msgstr "Du bist dabei, %{yourAccount} permanent zu löschen, inklusive aller Tic
msgid "Profiles| You are going to change the username %{currentUsernameBold} to %{newUsernameBold}. Profile and projects will be redirected to the %{newUsername} namespace but this redirect will expire once the %{currentUsername} namespace is registered by another user or group. Please update your Git repository remotes as soon as possible."
msgstr "Du bist dabei, deinen Benutzernamen von %{currentUsernameBold} in %{newUsernameBold} zu ändern. Profile und Projekte werden auf den neuen %{newUsername}-Namensraum umgeleitet, aber diese Umleitung wird auslaufen, sobald der %{currentUsername}-Namensraum von einem anderen Benutzer oder einer anderen Gruppe registriert wird. Bitte aktualisiere deine Git-Repository-Remotes so bald wie möglich."
+msgid "Profiles|%{provider} Active"
+msgstr ""
+
msgid "Profiles|@username"
msgstr ""
@@ -18834,7 +19514,7 @@ msgstr ""
msgid "Profiles|Commit email"
msgstr ""
-msgid "Profiles|Connect"
+msgid "Profiles|Connect %{provider}"
msgstr ""
msgid "Profiles|Connected Accounts"
@@ -18858,6 +19538,9 @@ msgstr "Löschen eines Kontos hat folgende Auswirkungen:"
msgid "Profiles|Disconnect"
msgstr ""
+msgid "Profiles|Disconnect %{provider}"
+msgstr ""
+
msgid "Profiles|Do not show on profile"
msgstr "Nicht im Profil zeigen"
@@ -18882,7 +19565,7 @@ msgstr ""
msgid "Profiles|Full name"
msgstr ""
-msgid "Profiles|Give your individual key a title. This will be publically visible."
+msgid "Profiles|Give your individual key a title."
msgstr ""
msgid "Profiles|Include private contributions on my profile"
@@ -18972,8 +19655,8 @@ msgstr ""
msgid "Profiles|The maximum file size allowed is 200KB."
msgstr "Die maximal zulässige Dateigröße beträgt 200KB."
-msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it?"
-msgstr "Das sieht nicht wie ein öffentlicher SSH-Schlüssel aus. Bist du sicher, dass du ihn hinzufügen willst?"
+msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it? It will be publicly visible."
+msgstr ""
msgid "Profiles|This email will be displayed on your public profile"
msgstr ""
@@ -19047,6 +19730,9 @@ msgstr "Du kannst deinen Avatar hier hochladen oder bei %{gravatar_link} ändern
msgid "Profiles|You don't have access to delete this user."
msgstr "Du hast keine Berechtigung, um diese(n) Benutzer(in) zu löschen."
+msgid "Profiles|You must transfer ownership or delete groups you are an owner of before you can delete your account"
+msgstr ""
+
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr "Du musst die Eigentumsrechte dieser Gruppen übertragen oder die Gruppen löschen, bevor du dein Konto löschen kannst."
@@ -19635,6 +20321,9 @@ msgstr ""
msgid "ProjectTemplates|GitLab Cluster Management"
msgstr ""
+msgid "ProjectTemplates|Gitpod/Spring Petclinic"
+msgstr ""
+
msgid "ProjectTemplates|Go Micro"
msgstr ""
@@ -20244,6 +20933,9 @@ msgstr ""
msgid "Publish to status page"
msgstr ""
+msgid "Published"
+msgstr ""
+
msgid "Published on status page"
msgstr ""
@@ -20361,9 +21053,15 @@ msgstr "Kurzbefehle können in Ticket-Beschreibungen und Kommentarfeldern verwen
msgid "Quick range"
msgstr ""
+msgid "Quickly and easily edit multiple files in your project."
+msgstr ""
+
msgid "README"
msgstr ""
+msgid "Rails"
+msgstr ""
+
msgid "Rake Tasks Help"
msgstr ""
@@ -20483,10 +21181,13 @@ msgstr "Anmelden"
msgid "Register Two-Factor Authenticator"
msgstr ""
-msgid "Register U2F device"
+msgid "Register Universal Two-Factor (U2F) Device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register WebAuthn Device"
+msgstr ""
+
+msgid "Register device"
msgstr ""
msgid "Register for GitLab"
@@ -20498,9 +21199,6 @@ msgstr ""
msgid "Register with two-factor app"
msgstr ""
-msgid "Registration"
-msgstr ""
-
msgid "Registration|Checkout"
msgstr ""
@@ -20617,9 +21315,6 @@ msgstr ""
msgid "Release|Something went wrong while saving the release details"
msgstr ""
-msgid "Remediated: needs review"
-msgstr ""
-
msgid "Remediations"
msgstr ""
@@ -20725,6 +21420,9 @@ msgstr "Primärknoten entfernen"
msgid "Remove priority"
msgstr "Priorität entfernen"
+msgid "Remove report"
+msgstr ""
+
msgid "Remove secondary node"
msgstr "Sekundärknoten entfernen"
@@ -20737,6 +21435,12 @@ msgstr "Stufe entfernen"
msgid "Remove time estimate"
msgstr ""
+msgid "Remove user & report"
+msgstr ""
+
+msgid "Remove user from group"
+msgstr ""
+
msgid "Removed"
msgstr ""
@@ -20818,9 +21522,6 @@ msgstr ""
msgid "Removes time estimate."
msgstr ""
-msgid "Removing license…"
-msgstr ""
-
msgid "Removing this group also removes all child projects, including archived projects, and their resources."
msgstr ""
@@ -20905,6 +21606,9 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
+msgid "Reported by %{reporter}"
+msgstr ""
+
msgid "Reporting"
msgstr "Statusbericht"
@@ -20991,6 +21695,27 @@ msgstr "Keine geänderten Testergebnisse"
msgid "Repositories"
msgstr ""
+msgid "Repositories Analytics"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download Historic Test Coverage Data"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download historic test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Historic Test Coverage Data is available in raw format (.csv) for further analysis."
+msgstr ""
+
+msgid "RepositoriesAnalytics|Test Code Coverage"
+msgstr ""
+
+msgid "RepositoriesAnalytics|There was an error fetching the projects."
+msgstr ""
+
msgid "Repository"
msgstr "Repository"
@@ -21069,9 +21794,15 @@ msgstr ""
msgid "Request parameter %{param} is missing."
msgstr ""
+msgid "Request review from"
+msgstr ""
+
msgid "Request to link SAML account must be authorized"
msgstr ""
+msgid "Requested"
+msgstr ""
+
msgid "Requested %{time_ago}"
msgstr ""
@@ -21090,6 +21821,9 @@ msgstr "Fordert Profile an"
msgid "Requests to these domain(s)/address(es) on the local network will be allowed when local requests from hooks and services are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 or 127.0.0.0/28 are supported. Domain wildcards are not supported currently. Use comma, semicolon, or newline to separate multiple entries. The allowlist can hold a maximum of 1000 entries. Domains should use IDNA encoding. Ex: example.com, 192.168.1.1, 127.0.0.0/28, xn--itlab-j1a.com."
msgstr ""
+msgid "Require admin approval for new sign-ups"
+msgstr ""
+
msgid "Require all users in this group to setup Two-factor authentication"
msgstr "Alle Benutzer(innen) dieser Gruppe müssen die Zwei-Faktor-Authentifizierung einrichten"
@@ -21217,9 +21951,6 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
-msgid "Resolved by %{resolvedByName}"
-msgstr ""
-
msgid "Resolves IP addresses once and uses them to submit requests"
msgstr ""
@@ -21339,6 +22070,14 @@ msgstr ""
msgid "ReviewApp|Enable Review App"
msgstr ""
+msgid "Reviewer"
+msgid_plural "%d Reviewers"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Reviewer(s)"
+msgstr ""
+
msgid "Reviewing"
msgstr "Überprüfung"
@@ -21378,6 +22117,9 @@ msgstr ""
msgid "Rook"
msgstr "Rook"
+msgid "Ruby"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -21456,6 +22198,63 @@ msgstr "Runner derzeit online: %{active_runners_count}"
msgid "Runners page."
msgstr "Runners-Seite."
+msgid "Runners|Active"
+msgstr ""
+
+msgid "Runners|Architecture"
+msgstr ""
+
+msgid "Runners|Can run untagged jobs"
+msgstr ""
+
+msgid "Runners|Description"
+msgstr ""
+
+msgid "Runners|Group"
+msgstr ""
+
+msgid "Runners|IP Address"
+msgstr ""
+
+msgid "Runners|Last contact"
+msgstr ""
+
+msgid "Runners|Locked to this project"
+msgstr ""
+
+msgid "Runners|Maximum job timeout"
+msgstr ""
+
+msgid "Runners|Name"
+msgstr ""
+
+msgid "Runners|Platform"
+msgstr ""
+
+msgid "Runners|Property Name"
+msgstr ""
+
+msgid "Runners|Protected"
+msgstr ""
+
+msgid "Runners|Revision"
+msgstr ""
+
+msgid "Runners|Shared"
+msgstr ""
+
+msgid "Runners|Specific"
+msgstr ""
+
+msgid "Runners|Tags"
+msgstr ""
+
+msgid "Runners|Value"
+msgstr ""
+
+msgid "Runners|Version"
+msgstr ""
+
msgid "Runners|You have used %{quotaUsed} out of %{quotaLimit} of your shared Runners pipeline minutes."
msgstr ""
@@ -21468,6 +22267,9 @@ msgstr ""
msgid "Runs a number of housekeeping tasks within the current repository, such as compressing file revisions and removing unreachable objects."
msgstr ""
+msgid "SAML"
+msgstr ""
+
msgid "SAML SSO"
msgstr "SAML SSO"
@@ -21519,6 +22321,9 @@ msgstr "Samstag"
msgid "Save"
msgstr "Speichern"
+msgid "Save %{name} size limits"
+msgstr ""
+
msgid "Save Changes"
msgstr ""
@@ -21549,9 +22354,6 @@ msgstr "Zeitplan der Pipeline speichern"
msgid "Save space and find tags in the Container Registry more easily. Enable the cleanup policy to remove stale tags and keep only the ones you need."
msgstr ""
-msgid "Save template"
-msgstr ""
-
msgid "Save variables"
msgstr "Variablen speichern"
@@ -21594,9 +22396,6 @@ msgstr "Pipelines planen"
msgid "Scope"
msgstr "Gültigkeitsbereich"
-msgid "Scope not supported with disabled 'users_search' feature!"
-msgstr ""
-
msgid "Scoped issue boards"
msgstr "Ticketboards mit festgelegtem Umfang"
@@ -21723,9 +22522,6 @@ msgstr ""
msgid "Search requirements"
msgstr ""
-msgid "Search results…"
-msgstr ""
-
msgid "Search users"
msgstr "Suche Benutzer(innen)"
@@ -21798,6 +22594,11 @@ msgid_plural "SearchResults|commits"
msgstr[0] ""
msgstr[1] ""
+msgid "SearchResults|epic"
+msgid_plural "SearchResults|epics"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "SearchResults|issue"
msgid_plural "SearchResults|issues"
msgstr[0] ""
@@ -21842,10 +22643,10 @@ msgstr ""
msgid "Seat Link is disabled, and cannot be configured through this form."
msgstr ""
-msgid "Seats currently in use"
+msgid "Seats usage data as of %{last_enqueue_time}"
msgstr ""
-msgid "Seats in license"
+msgid "Seats usage data is updated every day at 12:00pm UTC"
msgstr ""
msgid "Secondary"
@@ -21899,6 +22700,9 @@ msgstr ""
msgid "SecurityConfiguration|Available for on-demand DAST"
msgstr ""
+msgid "SecurityConfiguration|By default, all analyzers are applied in order to cover all languages across your project, and only run if the language is detected in the Merge Request."
+msgstr ""
+
msgid "SecurityConfiguration|Configure"
msgstr ""
@@ -21929,16 +22733,19 @@ msgstr ""
msgid "SecurityConfiguration|Manage"
msgstr ""
+msgid "SecurityConfiguration|More information"
+msgstr ""
+
msgid "SecurityConfiguration|Not enabled"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|Security Control"
+msgid "SecurityConfiguration|SAST Configuration"
msgstr ""
-msgid "SecurityConfiguration|See documentation"
+msgid "SecurityConfiguration|Security Control"
msgstr ""
msgid "SecurityConfiguration|Status"
@@ -21950,6 +22757,9 @@ msgstr ""
msgid "SecurityConfiguration|Using custom settings. You won't receive automatic updates on this variable. %{anchorStart}Restore to default%{anchorEnd}"
msgstr ""
+msgid "SecurityConfiguration|View history"
+msgstr ""
+
msgid "SecurityConfiguration|You can quickly enable all security scanning tools by enabling %{linkStart}Auto DevOps%{linkEnd}."
msgstr ""
@@ -22028,9 +22838,6 @@ msgstr ""
msgid "SecurityReports|Learn more about setting up your dashboard"
msgstr ""
-msgid "SecurityReports|Load more vulnerabilities"
-msgstr ""
-
msgid "SecurityReports|Monitor vulnerabilities in your code"
msgstr ""
@@ -22310,7 +23117,7 @@ msgstr ""
msgid "Select status"
msgstr ""
-msgid "Select strategy activation method"
+msgid "Select strategy activation method."
msgstr ""
msgid "Select subscription"
@@ -22325,7 +23132,7 @@ msgstr "Wähle den Branch aus, den du als Standard für dieses Projekt festlegen
msgid "Select the custom project template source group."
msgstr "Wähle die Quellgruppe der benutzerdefinierten Projektvorlage aus."
-msgid "Select timeframe"
+msgid "Select the environment scope for this feature flag."
msgstr ""
msgid "Select timezone"
@@ -22574,6 +23381,9 @@ msgstr "Lege ein Instanz-weites Vorlagen-Repository"
msgid "Set iteration"
msgstr ""
+msgid "Set limit to 0 to allow any file size."
+msgstr ""
+
msgid "Set max session time for web terminal."
msgstr "Lege die maximale Sitzungszeit für das Web-Terminal fest."
@@ -22652,10 +23462,13 @@ msgstr ""
msgid "Set up a %{type} Runner manually"
msgstr "Einen %{type} Runner manuell erstellen"
+msgid "Set up a hardware device as a second factor to sign in."
+msgstr ""
+
msgid "Set up assertions/attributes/claims (email, first_name, last_name) and NameID according to %{docsLinkStart}the documentation %{icon}%{docsLinkEnd}"
msgstr "Richte notwendige Angaben (E-Mail, Vorname, Nachname) und NameID gemäß %{docsLinkStart}der Dokumentation %{icon}%{docsLinkEnd} ein"
-msgid "Set up new U2F device"
+msgid "Set up new device"
msgstr ""
msgid "Set up new password"
@@ -22724,6 +23537,9 @@ msgstr ""
msgid "Sets weight to %{weight}."
msgstr ""
+msgid "Setting this to 0 means using the system default timeout value."
+msgstr ""
+
msgid "Settings"
msgstr "Einstellungen"
@@ -22739,6 +23555,15 @@ msgstr ""
msgid "Severity"
msgstr ""
+msgid "SeverityWidget|Severity"
+msgstr ""
+
+msgid "SeverityWidget|Severity: %{severity}"
+msgstr ""
+
+msgid "SeverityWidget|There was an error while updating severity."
+msgstr ""
+
msgid "Shards (%{shards})"
msgstr ""
@@ -22784,6 +23609,9 @@ msgstr "Alle Mitglieder anzeigen"
msgid "Show all requirements."
msgstr ""
+msgid "Show all test cases."
+msgstr ""
+
msgid "Show archived projects"
msgstr "Archivierte Projekte anzeigen"
@@ -22796,6 +23624,9 @@ msgstr "Befehl anzeigen"
msgid "Show comments"
msgstr ""
+msgid "Show comments on this file"
+msgstr ""
+
msgid "Show comments only"
msgstr ""
@@ -22841,6 +23672,12 @@ msgstr "Ãœbergeordnete Seiten anzeigen"
msgid "Show parent subgroups"
msgstr "Zeige übergeordnete Untergruppen"
+msgid "Show the Closed list"
+msgstr ""
+
+msgid "Show the Open list"
+msgstr ""
+
msgid "Show whitespace changes"
msgstr "Leerzeichenänderungen anzeigen"
@@ -22884,9 +23721,6 @@ msgstr "Nebeneinander"
msgid "Sidebar|Assign health status"
msgstr ""
-msgid "Sidebar|Change weight"
-msgstr "Gewichtung ändern"
-
msgid "Sidebar|Health status"
msgstr ""
@@ -23070,6 +23904,9 @@ msgstr ""
msgid "Snippets|Add another file %{num}/%{total}"
msgstr ""
+msgid "Snippets|Authored %{time_ago} by %{author}"
+msgstr ""
+
msgid "Snippets|Delete file"
msgstr ""
@@ -23097,6 +23934,9 @@ msgstr ""
msgid "Solution"
msgstr ""
+msgid "Some changes are not shown"
+msgstr ""
+
msgid "Some child epics may be hidden due to applied filters"
msgstr ""
@@ -23463,6 +24303,12 @@ msgstr "Quelle"
msgid "Source (branch or tag)"
msgstr "Quelle (Branch oder Tag)"
+msgid "Source Branch"
+msgstr ""
+
+msgid "Source branch: %{source_branch_open}%{source_branch}%{source_branch_close}"
+msgstr ""
+
msgid "Source code"
msgstr "Quellcode"
@@ -23628,9 +24474,6 @@ msgstr "Einen Review starten"
msgid "Start and due date"
msgstr "Start- und Fälligkeitsdatum"
-msgid "Start by choosing a group to see how your team is spending time. You can then drill down to the project level."
-msgstr ""
-
msgid "Start by choosing a group to start exploring the merge requests in that group. You can then proceed to filter by projects, labels, milestones and authors."
msgstr ""
@@ -23712,18 +24555,27 @@ msgstr ""
msgid "StaticSiteEditor|3. Assign a person to review and accept the merge request."
msgstr ""
+msgid "StaticSiteEditor|A link to view the merge request will appear once ready."
+msgstr ""
+
msgid "StaticSiteEditor|An error occurred while submitting your changes."
msgstr ""
msgid "StaticSiteEditor|Branch could not be created."
msgstr ""
+msgid "StaticSiteEditor|Copy update"
+msgstr ""
+
msgid "StaticSiteEditor|Could not commit the content changes."
msgstr ""
msgid "StaticSiteEditor|Could not create merge request."
msgstr ""
+msgid "StaticSiteEditor|Creating your merge request"
+msgstr ""
+
msgid "StaticSiteEditor|Incompatible file content"
msgstr ""
@@ -23745,6 +24597,9 @@ msgstr ""
msgid "StaticSiteEditor|View documentation"
msgstr ""
+msgid "StaticSiteEditor|You can set an assignee to get your changes reviewed and deployed once your merge request is created."
+msgstr ""
+
msgid "StaticSiteEditor|Your merge request has been created"
msgstr ""
@@ -23874,15 +24729,15 @@ msgstr ""
msgid "Submit %{humanized_resource_name}"
msgstr ""
-msgid "Submit Changes"
-msgstr ""
-
msgid "Submit a review"
msgstr ""
msgid "Submit as spam"
msgstr "Als Spam einreichen"
+msgid "Submit changes"
+msgstr ""
+
msgid "Submit feedback"
msgstr ""
@@ -24036,6 +24891,9 @@ msgstr ""
msgid "Successfully deleted U2F device."
msgstr ""
+msgid "Successfully deleted WebAuthn device."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -24354,9 +25212,6 @@ msgstr "Vorlage"
msgid "Template to append to all Service Desk issues"
msgstr ""
-msgid "Template was successfully saved."
-msgstr ""
-
msgid "Templates"
msgstr "Vorlagen"
@@ -24435,10 +25290,28 @@ msgid_plural "Test coverage: %d hits"
msgstr[0] ""
msgstr[1] ""
-msgid "Test failed."
+msgid "Test settings"
msgstr ""
-msgid "Test settings and save changes"
+msgid "TestCases|New Test Case"
+msgstr ""
+
+msgid "TestCases|New test case"
+msgstr ""
+
+msgid "TestCases|Search test cases"
+msgstr ""
+
+msgid "TestCases|Something went wrong while creating a test case."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching count of test cases."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching test cases list."
+msgstr ""
+
+msgid "TestCases|Submit test case"
msgstr ""
msgid "TestHooks|Ensure one of your projects has merge requests."
@@ -24504,6 +25377,9 @@ msgstr ""
msgid "Thank you for signing up for your free trial! You will get additional instructions in your inbox shortly."
msgstr ""
+msgid "Thank you for your business."
+msgstr ""
+
msgid "Thank you for your feedback!"
msgstr ""
@@ -24563,9 +25439,6 @@ msgstr ""
msgid "The URL to use for connecting to Elasticsearch. Use a comma-separated list to support clustering (e.g., \"http://localhost:9200, http://localhost:9201\")."
msgstr ""
-msgid "The Web IDE offers advanced syntax highlighting capabilities and more."
-msgstr ""
-
msgid "The X509 Certificate to use when mutual TLS is required to communicate with the external authorization service. If left blank, the server certificate is still validated when accessing over HTTPS."
msgstr "Das zu verwendende X.509-Zertifikat, wenn über MTLS mit dem externen Autorisierungsdienst kommunizieren muss. Wenn dieses Feld leer gelassen wird, wird das Serverzertifikat beim Zugriff über HTTPS weiterhin überprüft."
@@ -24676,6 +25549,9 @@ msgstr "Die Beziehung des Forks wurde entfernt."
msgid "The form contains the following error:"
msgstr ""
+msgid "The form contains the following warning:"
+msgstr ""
+
msgid "The global settings require you to enable Two-Factor Authentication for your account."
msgstr ""
@@ -24790,9 +25666,6 @@ msgstr "Die Planungsphase stellt die Zeit vom vorherigen Schritt bis zum Pushen
msgid "The private key to use when a client certificate is provided. This value is encrypted at rest."
msgstr "Der private Schlüssel, der verwendet werden soll, wenn ein Clientzertifikat bereitgestellt wird. Dieser Wert wird im Ruhezustand verschlüsselt."
-msgid "The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr "Die Produktionsphase stellt die Gesamtzeit vom Anlegen eines Tickets bis zur Bereitstellung des Codes auf der Produktivumgebung dar. Sobald du den vollständigen Entwicklungszyklus, von einer Idee bis zur Fertigstellung, durchlaufen hast, erscheinen die Daten hier."
-
msgid "The project can be accessed by any logged in user."
msgstr "Auf das Projekt kann jede(r) angemeldete Nutzer(in) zugreifen."
@@ -24829,7 +25702,7 @@ msgstr ""
msgid "The remote repository is being updated..."
msgstr ""
-msgid "The repository can be commited to, and issues, comments and other entities can be created."
+msgid "The repository can be committed to, and issues, comments and other entities can be created."
msgstr ""
msgid "The repository for this project does not exist."
@@ -24883,9 +25756,6 @@ msgstr "Die Testphase stellt die Zeit dar, die GitLab CI benötigt um die Pipeli
msgid "The time taken by each data entry gathered by that stage."
msgstr "Die Zeit, die jede Dateneingabe in dieser Phase benötigt."
-msgid "The total stage shows the time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The update action will time out after %{number_of_minutes} minutes. For big repositories, use a clone/push combination."
msgstr "Die Aktualisierungsaktion wird nach %{number_of_minutes} Minuten abgebrochen. Verwende für große Repositories eine Clone / Push-Kombination."
@@ -24949,6 +25819,9 @@ msgstr "Es gibt noch keine archivierten Projekte"
msgid "There are no archived requirements"
msgstr ""
+msgid "There are no archived test cases"
+msgstr ""
+
msgid "There are no changes"
msgstr ""
@@ -24988,6 +25861,9 @@ msgstr ""
msgid "There are no open requirements"
msgstr ""
+msgid "There are no open test cases"
+msgstr ""
+
msgid "There are no packages yet"
msgstr ""
@@ -25000,6 +25876,9 @@ msgstr ""
msgid "There is a limit of %{ci_project_subscriptions_limit} subscriptions from or to a project."
msgstr ""
+msgid "There is already a To-Do for this design."
+msgstr ""
+
msgid "There is already a repository with that name on disk"
msgstr ""
@@ -25018,6 +25897,9 @@ msgstr ""
msgid "There was a problem communicating with your device."
msgstr ""
+msgid "There was a problem fetching branches."
+msgstr ""
+
msgid "There was a problem fetching groups."
msgstr ""
@@ -25246,9 +26128,15 @@ msgstr ""
msgid "This action can lead to data loss. To prevent accidental actions we ask you to confirm your intention."
msgstr ""
+msgid "This action cannot be undone, and will permanently delete the %{key} SSH key"
+msgstr ""
+
msgid "This action cannot be undone. You will lose the project's repository and all content: issues, merge requests, etc."
msgstr ""
+msgid "This action has been performed too many times. Try again later."
+msgstr ""
+
msgid "This action will %{strongOpen}permanently delete%{strongClose} %{codeOpen}%{project}%{codeClose} %{strongOpen}immediately%{strongClose}, including its repositories and all content: issues, merge requests, etc."
msgstr ""
@@ -25276,9 +26164,6 @@ msgstr ""
msgid "This board's scope is reduced"
msgstr "Der Umfang dieses Boards ist reduziert"
-msgid "This branch has changed since you started editing. Would you like to create a new branch?"
-msgstr "Dieser Branch wurde verändert, seit du begonnen hast ihn zu bearbeiten. Möchtest du einen neuen Branch anlegen?"
-
msgid "This chart could not be displayed"
msgstr ""
@@ -25405,15 +26290,9 @@ msgstr ""
msgid "This is a security log of important events involving your account."
msgstr ""
-msgid "This is the author's first Merge Request to this project."
-msgstr "Dies ist der erste Merge-Request des Autors für dieses Projekt."
-
msgid "This is the highest peak of users on your installation since the license started."
msgstr ""
-msgid "This is the maximum number of users that have existed at the same time since the license started. This is the minimum number of seats you will need to buy when you renew your license."
-msgstr ""
-
msgid "This is the number of currently active users on your installation, and this is the minimum number you need to purchase when you renew your license."
msgstr ""
@@ -25645,6 +26524,15 @@ msgstr ""
msgid "This user has no identities"
msgstr "Diese(r) Benutzer(in) hat keine Identitäten"
+msgid "This user has previously committed to the %{name} project."
+msgstr ""
+
+msgid "This user has the %{access} role in the %{name} project."
+msgstr ""
+
+msgid "This user is the author of this %{noteable}."
+msgstr ""
+
msgid "This user will be the author of all events in the activity feed that are the result of an update, like new branches being created or new commits being pushed to existing branches."
msgstr "Diese(r) Benutzer(in) wird der/die Autor(in) aller Ereignisse im Aktivitätsfeed sein, die die Folge eines Updates, wie die Erstellung neuer Branches oder das Pushen neuer Commits zu existierenden Branches, sind."
@@ -25675,6 +26563,9 @@ msgstr ""
msgid "Threat Monitoring"
msgstr ""
+msgid "ThreatMonitoring|All Environments"
+msgstr ""
+
msgid "ThreatMonitoring|Anomalous Requests"
msgstr ""
@@ -25702,9 +26593,6 @@ msgstr ""
msgid "ThreatMonitoring|Operations Per Second"
msgstr ""
-msgid "ThreatMonitoring|Overview"
-msgstr ""
-
msgid "ThreatMonitoring|Packet Activity"
msgstr ""
@@ -25723,6 +26611,9 @@ msgstr "Es ist ein Fehler aufgetreten. Umgebungen konnten nicht abgerufen werden
msgid "ThreatMonitoring|Something went wrong, unable to fetch statistics"
msgstr ""
+msgid "ThreatMonitoring|Statistics"
+msgstr ""
+
msgid "ThreatMonitoring|The firewall is not installed or has been disabled. To view this data, ensure the web application firewall is installed and enabled for your cluster."
msgstr ""
@@ -26114,6 +27005,9 @@ msgstr ""
msgid "To update Snippets with multiple files, you must use the `files` parameter"
msgstr ""
+msgid "To use Gitpod you must first enable the feature in the integrations section of your %{user_prefs}."
+msgstr ""
+
msgid "To view all %{scannedResourcesCount} scanned URLs, please download the CSV file"
msgstr ""
@@ -26147,9 +27041,6 @@ msgstr ""
msgid "Toggle Sidebar"
msgstr "Seitenleiste ein-/ausblenden"
-msgid "Toggle all threads"
-msgstr ""
-
msgid "Toggle backtrace"
msgstr ""
@@ -26174,9 +27065,6 @@ msgstr ""
msgid "Toggle navigation"
msgstr "Navigation umschalten"
-msgid "Toggle project"
-msgstr ""
-
msgid "Toggle sidebar"
msgstr "Seitenleiste ein-/ausblenden"
@@ -26216,6 +27104,9 @@ msgstr "Zu viele Namespaces aktiviert. Sie müssen sie über die Konsole oder di
msgid "Too many projects enabled. You will need to manage them via the console or the API."
msgstr "Zu viele Projekte aktviert. Sie müssen sie über die Konsole oder die API verwalten."
+msgid "Too much data"
+msgstr ""
+
msgid "Topics (optional)"
msgstr ""
@@ -26234,6 +27125,9 @@ msgstr ""
msgid "Total cores (CPUs)"
msgstr ""
+msgid "Total days to completion"
+msgstr ""
+
msgid "Total issues"
msgstr ""
@@ -26330,6 +27224,9 @@ msgstr "Baumstrukturansicht"
msgid "Trending"
msgstr "Beliebt"
+msgid "Trials|Create a new group to start your GitLab Gold trial."
+msgstr ""
+
msgid "Trials|Go back to GitLab"
msgstr ""
@@ -26339,6 +27236,15 @@ msgstr ""
msgid "Trials|You can always resume this process by selecting your avatar and choosing 'Start a Gold trial'"
msgstr ""
+msgid "Trials|You can apply your trial to a new group or an existing group."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group or your personal account."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group, an existing group, or your personal account."
+msgstr ""
+
msgid "Trials|You won't get a free trial right now but you can always resume this process by clicking on your avatar and choosing 'Start a free trial'"
msgstr ""
@@ -26408,6 +27314,9 @@ msgstr ""
msgid "Try using a different search term to find the file you are looking for."
msgstr ""
+msgid "Trying to communicate with your device. Plug it in (if needed) and press the button on the device now."
+msgstr ""
+
msgid "Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now."
msgstr ""
@@ -26495,6 +27404,12 @@ msgstr ""
msgid "URL or request ID"
msgstr ""
+msgid "USER %{user} WILL BE REMOVED! Are you sure?"
+msgstr ""
+
+msgid "USER WILL BE BLOCKED! Are you sure?"
+msgstr ""
+
msgid "UTC"
msgstr ""
@@ -26552,9 +27467,6 @@ msgstr "Der Diff konnten nicht geladen werden. %{button_try_again}"
msgid "Unable to load the merge request widget. Try reloading the page."
msgstr "Das Merge-Request-Widget konnte nicht geladen werden. Versuchen Sie die Seite neu zu laden."
-msgid "Unable to resolve"
-msgstr ""
-
msgid "Unable to save iteration. Please try again"
msgstr ""
@@ -26603,6 +27515,9 @@ msgstr ""
msgid "Undo ignore"
msgstr ""
+msgid "Unexpected error"
+msgstr ""
+
msgid "Unfortunately, your email message to GitLab could not be processed."
msgstr "Leider konnte deine E-Mail an GitLab nicht verarbeitet werden."
@@ -26636,6 +27551,9 @@ msgstr ""
msgid "Unknown response text"
msgstr ""
+msgid "Unless otherwise agreed to in writing with GitLab, by clicking \"Upload License\" you agree that your use of GitLab Software is subject to the %{eula_link_start}Terms of Service%{eula_link_end}."
+msgstr ""
+
msgid "Unlimited"
msgstr ""
@@ -27002,9 +27920,6 @@ msgstr ""
msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
msgstr "Nutze den Service-Desk, um dich direkt in GitLab via E-Mail mit deinen Benutzer(inne)n zu verbinden (z. B. um Kunden-Support anzubieten)"
-msgid "Use a hardware device to add the second factor of authentication."
-msgstr ""
-
msgid "Use an one time password authenticator on your mobile device or computer to enable two-factor authentication (2FA)."
msgstr ""
@@ -27278,13 +28193,13 @@ msgstr ""
msgid "Users"
msgstr "Benutzer(innen)"
-msgid "Users in License:"
+msgid "Users in License"
msgstr ""
-msgid "Users or groups set as approvers in the project's or merge request's settings."
+msgid "Users in License:"
msgstr ""
-msgid "Users outside of license"
+msgid "Users or groups set as approvers in the project's or merge request's settings."
msgstr ""
msgid "Users over License:"
@@ -27302,9 +28217,6 @@ msgstr ""
msgid "Users with a Guest role or those who don't belong to a Project or Group will not use a seat from your license."
msgstr ""
-msgid "Users with a Guest role or those who don't belong to any projects or groups don't count towards seats in use."
-msgstr ""
-
msgid "UsersSelect|%{name} + %{length} more"
msgstr ""
@@ -27344,9 +28256,6 @@ msgstr ""
msgid "Validations failed."
msgstr ""
-msgid "Validity"
-msgstr ""
-
msgid "Value"
msgstr ""
@@ -27365,6 +28274,9 @@ msgstr ""
msgid "Value Stream Name"
msgstr ""
+msgid "ValueStreamAnalyticsStage|We don't have enough data to show this stage."
+msgstr ""
+
msgid "ValueStreamAnalytics|%{days}d"
msgstr ""
@@ -27621,6 +28533,9 @@ msgstr ""
msgid "VisualReviewApp|Steps 1 and 2 (and sometimes 3) are performed once by the developer before requesting feedback. Steps 3 (if necessary), 4 is performed by the reviewer each time they perform a review."
msgstr ""
+msgid "Visualization"
+msgstr ""
+
msgid "Vulnerabilities"
msgstr ""
@@ -27648,34 +28563,31 @@ msgstr ""
msgid "VulnerabilityChart|Severity"
msgstr ""
-msgid "VulnerabilityManagement|A true-positive and will fix"
-msgstr ""
-
-msgid "VulnerabilityManagement|Change status"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Confirm"
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|Confirmed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Detected %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|A true-positive and will fix"
msgstr ""
-msgid "VulnerabilityManagement|Dismiss"
+msgid "VulnerabilityManagement|Change status"
msgstr ""
-msgid "VulnerabilityManagement|Dismissed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
msgstr ""
-msgid "VulnerabilityManagement|Resolved"
+msgid "VulnerabilityManagement|Detected"
msgstr ""
-msgid "VulnerabilityManagement|Resolved %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Needs triage"
msgstr ""
msgid "VulnerabilityManagement|Something went wrong while trying to delete the comment. Please try again later."
@@ -27726,6 +28638,9 @@ msgstr ""
msgid "Vulnerability|%{scannerName} (version %{scannerVersion})"
msgstr ""
+msgid "Vulnerability|Activity"
+msgstr ""
+
msgid "Vulnerability|Class"
msgstr "Klasse"
@@ -27738,6 +28653,9 @@ msgstr ""
msgid "Vulnerability|Description"
msgstr "Beschreibung"
+msgid "Vulnerability|Detected"
+msgstr ""
+
msgid "Vulnerability|Evidence"
msgstr ""
@@ -27801,6 +28719,9 @@ msgstr ""
msgid "Warning: Displaying this diagram might cause performance issues on this page."
msgstr ""
+msgid "We are currently unable to fetch data for the pipeline header."
+msgstr ""
+
msgid "We are currently unable to fetch data for this graph."
msgstr ""
@@ -27840,6 +28761,12 @@ 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 will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
+msgstr ""
+
+msgid "We would like to inform you that your subscription GitLab Enterprise Edition %{plan_name} is nearing its user limit. You have %{active_user_count} active users, which is almost at the user limit of %{maximum_user_count}."
+msgstr ""
+
msgid "We've found no vulnerabilities"
msgstr ""
@@ -27855,6 +28782,12 @@ msgstr ""
msgid "Web terminal"
msgstr "Web-Terminal"
+msgid "WebAuthn Devices (%{length})"
+msgstr ""
+
+msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
+msgstr ""
+
msgid "WebIDE|Merge request"
msgstr ""
@@ -27993,15 +28926,9 @@ msgstr ""
msgid "Welcome to the guided GitLab tour"
msgstr ""
-msgid "Welcome to your Issue Board!"
-msgstr ""
-
msgid "Welcome to your issue board!"
msgstr ""
-msgid "We’ve been making changes to %{featureName} and we’d love your feedback %{linkStart}in this issue%{linkEnd} to help us improve the experience."
-msgstr ""
-
msgid "What are you searching for?"
msgstr ""
@@ -28020,6 +28947,9 @@ msgstr ""
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"
+msgid "When enabled, any user visiting %{host} and creating an account will have to be explicitly approved by the admin before they can login. This setting is effective only if sign-ups are enabled."
+msgstr ""
+
msgid "When enabled, any user visiting %{host} will be able to create an account."
msgstr ""
@@ -28244,6 +29174,9 @@ msgstr ""
msgid "With requirements, you can set criteria to check your products against."
msgstr ""
+msgid "With test cases, you can define conditions for your project to meet in determining quality"
+msgstr ""
+
msgid "Withdraw Access Request"
msgstr "Zugriffsanfrage widerrufen"
@@ -28259,6 +29192,9 @@ msgstr ""
msgid "Workflow Help"
msgstr ""
+msgid "Would you like to create a new branch?"
+msgstr ""
+
msgid "Write"
msgstr ""
@@ -28280,6 +29216,9 @@ msgstr ""
msgid "Wrong extern UID provided. Make sure Auth0 is configured correctly."
msgstr ""
+msgid "YYYY-MM-DD"
+msgstr ""
+
msgid "Yes"
msgstr "Ja"
@@ -28337,8 +29276,8 @@ msgstr ""
msgid "You are going to remove the fork relationship from %{project_full_name}. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "You are going to transfer %{project_full_name} to another owner. Are you ABSOLUTELY sure?"
-msgstr "Du bist dabei %{project_full_name} einem/einer andere(n) Besitzer(in) zu übergeben. Bist du dir WIRKLICH sicher?"
+msgid "You are going to transfer %{project_full_name} to another namespace. Are you ABSOLUTELY sure?"
+msgstr ""
msgid "You are going to turn off the confidentiality. This means %{strongStart}everyone%{strongEnd} will be able to see and leave a comment on this %{issuableType}."
msgstr ""
@@ -28397,9 +29336,6 @@ msgstr ""
msgid "You can always edit this later"
msgstr ""
-msgid "You can apply your Trial to your Personal account or create a New Group."
-msgstr ""
-
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings"
msgstr ""
@@ -28421,12 +29357,18 @@ msgstr "Du kannst ganz einfach einen Runner auf einem Kubernetes-Cluster install
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
+msgid "You can find more information about GitLab subscriptions in %{subscriptions_doc_link}."
+msgstr ""
+
msgid "You can generate an access token scoped to this project for each application to use the GitLab API."
msgstr ""
msgid "You can get started by cloning the repository or start adding files to it with one of the following options."
msgstr ""
+msgid "You can group test cases using labels. To learn about the future direction of this feature, visit %{linkStart}Quality Management direction page%{linkEnd}."
+msgstr ""
+
msgid "You can invite a new member to %{project_name} or invite another group."
msgstr ""
@@ -28442,6 +29384,9 @@ msgstr "Du kannst das Diagramm mit den Pfeiltasten bewegen."
msgid "You can notify the app / group or a project by sending them an email notification"
msgstr ""
+msgid "You can now close this window."
+msgstr ""
+
msgid "You can now export your security dashboard to a CSV report."
msgstr ""
@@ -28490,9 +29435,6 @@ msgstr ""
msgid "You can test your .gitlab-ci.yml in %{linkStart}CI Lint%{linkEnd}."
msgstr "Du kannst deine .gitlab-ci.yml mit %{linkStart}CI Lint%{linkEnd} testen."
-msgid "You can try again using %{begin_link}basic search%{end_link}"
-msgstr ""
-
msgid "You cannot access the raw file. Please wait a minute."
msgstr ""
@@ -28544,6 +29486,9 @@ msgstr "Du verfügst nicht über die erforderlichen Berechtigungen um die Einste
msgid "You don't have any U2F devices registered yet."
msgstr ""
+msgid "You don't have any WebAuthn devices registered yet."
+msgstr ""
+
msgid "You don't have any active chat names."
msgstr ""
@@ -28631,6 +29576,9 @@ msgstr ""
msgid "You must accept our Terms of Service and privacy policy in order to register an account"
msgstr "Du musst unsere Nutzungsbedingungen und Datenschutzerklärung akzeptieren, um ein Konto registrieren zu können"
+msgid "You must be logged in to search across all of GitLab"
+msgstr ""
+
msgid "You must disassociate %{domain} from all clusters it is attached to before deletion."
msgstr ""
@@ -28670,7 +29618,7 @@ msgstr "Du brauchst eine Genehmigung."
msgid "You need to be logged in."
msgstr ""
-msgid "You need to register a two-factor authentication app before you can set up a U2F device."
+msgid "You need to register a two-factor authentication app before you can set up a device."
msgstr ""
msgid "You need to set terms to be enforced"
@@ -28688,6 +29636,9 @@ msgstr ""
msgid "You reached %{usage_in_percent} of %{namespace_name}'s storage capacity (%{used_storage} of %{storage_limit})"
msgstr ""
+msgid "You successfully declined the invitation"
+msgstr ""
+
msgid "You tried to fork %{link_to_the_project} but it failed for the following reason:"
msgstr ""
@@ -28853,10 +29804,13 @@ msgstr ""
msgid "Your U2F device did not send a valid JSON response."
msgstr ""
-msgid "Your U2F device needs to be set up. Plug it in (if not already) and click the button on the left."
+msgid "Your U2F device was registered!"
+msgstr ""
+
+msgid "Your WebAuthn device did not send a valid JSON response."
msgstr ""
-msgid "Your U2F device was registered!"
+msgid "Your WebAuthn device was registered!"
msgstr ""
msgid "Your access request to the %{source_type} has been withdrawn."
@@ -28880,6 +29834,9 @@ msgstr "Deine autorisierten Anwendungen"
msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
msgstr ""
+msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
+msgstr ""
+
msgid "Your changes can be committed to %{branch_name} because a merge request is open."
msgstr "Deine Änderungen können an %{branch_name} committet werden, da eine Merge-Request geöffnet ist."
@@ -28916,6 +29873,12 @@ msgstr ""
msgid "Your deployment services will be broken, you will need to manually fix the services after renaming."
msgstr ""
+msgid "Your device is not compatible with GitLab. Please try another device"
+msgstr ""
+
+msgid "Your device needs to be set up. Plug it in (if needed) and click the button on the left."
+msgstr ""
+
msgid "Your device was successfully set up! Give it a name and register it with the GitLab server."
msgstr ""
@@ -29029,9 +29992,6 @@ msgstr[1] "etwa %d Stunden"
msgid "access:"
msgstr ""
-msgid "activated"
-msgstr ""
-
msgid "added %{created_at_timeago}"
msgstr ""
@@ -29104,9 +30064,21 @@ msgstr "von"
msgid "by %{user}"
msgstr ""
+msgid "cannot be a date in the past"
+msgstr ""
+
msgid "cannot be changed if a personal project has container registry tags."
msgstr ""
+msgid "cannot be changed if shared runners are enabled"
+msgstr ""
+
+msgid "cannot be enabled because parent group does not allow it"
+msgstr ""
+
+msgid "cannot be enabled because parent group has shared Runners disabled"
+msgstr ""
+
msgid "cannot be enabled unless all domains have TLS certificates"
msgstr ""
@@ -29152,7 +30124,7 @@ msgstr "%{linkStartTag}Lerne mehr über Abhängigkeitsüberprüfung%{linkEndTag}
msgid "ciReport|%{linkStartTag}Learn more about SAST %{linkEndTag}"
msgstr "%{linkStartTag}Lerne mehr über SAST%{linkEndTag}"
-msgid "ciReport|%{linkStartTag}Learn more about Secret Scanning %{linkEndTag}"
+msgid "ciReport|%{linkStartTag}Learn more about Secret Detection %{linkEndTag}"
msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about codequality reports %{linkEndTag}"
@@ -29467,9 +30439,6 @@ msgstr ""
msgid "error"
msgstr ""
-msgid "error code:"
-msgstr ""
-
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr "%{slash_command} aktualisiert die geschätzte Zeit mit dem aktuellsten Befehl."
@@ -29491,6 +30460,9 @@ msgstr ""
msgid "failed to dismiss associated finding(id=%{finding_id}): %{message}"
msgstr ""
+msgid "failed to revert associated finding(id=%{finding_id}) to detected"
+msgstr ""
+
msgid "file"
msgid_plural "files"
msgstr[0] ""
@@ -30033,6 +31005,9 @@ msgstr ""
msgid "must be a root namespace"
msgstr ""
+msgid "must be a valid IPv4 or IPv6 address"
+msgstr ""
+
msgid "must be greater than start date"
msgstr "muss nach dem Anfangsdatum liegen"
@@ -30069,6 +31044,9 @@ msgstr "keine Beiträge"
msgid "no expiration"
msgstr ""
+msgid "no name set"
+msgstr ""
+
msgid "no one can merge"
msgstr "Niemand kann mergen"
@@ -30247,9 +31225,6 @@ msgstr ""
msgid "security Reports|There was an error creating the merge request"
msgstr "Fehler während der Merge-Request-Erstellung"
-msgid "settings saved, but not activated"
-msgstr "Einstellungen gespeichert, aber nicht aktiviert"
-
msgid "severity|Critical"
msgstr "Kritisch"
@@ -30376,9 +31351,6 @@ msgstr ""
msgid "toggle collapse"
msgstr ""
-msgid "toggle dropdown"
-msgstr ""
-
msgid "triggered"
msgstr "ausgelöst"
@@ -30406,6 +31378,9 @@ msgstr ""
msgid "user avatar"
msgstr "Benutzeravatar"
+msgid "user preferences"
+msgstr ""
+
msgid "username"
msgstr "Benutzername"
diff --git a/locale/el_GR/gitlab.po b/locale/el_GR/gitlab.po
index 3bdebf175bc..d64c5723522 100644
--- a/locale/el_GR/gitlab.po
+++ b/locale/el_GR/gitlab.po
@@ -14,7 +14,10 @@ msgstr ""
"X-Crowdin-Language: el\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 6\n"
-"PO-Revision-Date: 2020-09-04 23:07\n"
+"PO-Revision-Date: 2020-10-02 18:47\n"
+
+msgid " %{project_name}#%{issue_iid} &middot; opened %{issue_created} by %{author}"
+msgstr ""
msgid " %{start} to %{end}"
msgstr ""
@@ -74,6 +77,16 @@ msgstr ""
msgid "\"el\" parameter is required for createInstance()"
msgstr ""
+msgid "%d Approval"
+msgid_plural "%d Approvals"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d Package"
+msgid_plural "%d Packages"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d Scanned URL"
msgid_plural "%d Scanned URLs"
msgstr[0] ""
@@ -137,6 +150,11 @@ msgstr[1] ""
msgid "%d commits"
msgstr ""
+msgid "%d completed issue"
+msgid_plural "%d completed issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d contribution"
msgid_plural "%d contributions"
msgstr[0] ""
@@ -147,6 +165,11 @@ msgid_plural "%d days"
msgstr[0] ""
msgstr[1] ""
+msgid "%d day until tags are automatically removed"
+msgid_plural "%d days until tags are automatically removed"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d error"
msgid_plural "%d errors"
msgstr[0] ""
@@ -237,6 +260,16 @@ msgid_plural "%d more comments"
msgstr[0] ""
msgstr[1] ""
+msgid "%d open issue"
+msgid_plural "%d open issues"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d pending comment"
+msgid_plural "%d pending comments"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d personal project will be removed and cannot be restored."
msgid_plural "%d personal projects will be removed and cannot be restored."
msgstr[0] ""
@@ -252,6 +285,11 @@ msgid_plural "%d projects"
msgstr[0] ""
msgstr[1] ""
+msgid "%d project selected"
+msgid_plural "%d projects selected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d request with warnings"
msgid_plural "%d requests with warnings"
msgstr[0] ""
@@ -272,6 +310,11 @@ msgid_plural "%d tags"
msgstr[0] ""
msgstr[1] ""
+msgid "%d tag per image name"
+msgid_plural "%d tags per image name"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d unassigned issue"
msgid_plural "%d unassigned issues"
msgstr[0] ""
@@ -292,6 +335,11 @@ msgid_plural "%d vulnerabilities dismissed"
msgstr[0] ""
msgstr[1] ""
+msgid "%d warning found:"
+msgid_plural "%d warnings found:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%s additional commit has been omitted to prevent performance issues."
msgid_plural "%s additional commits have been omitted to prevent performance issues."
msgstr[0] ""
@@ -330,6 +378,9 @@ msgstr ""
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr ""
+msgid "%{completedCount} completed weight"
+msgstr ""
+
msgid "%{completedWeight} of %{totalWeight} weight completed"
msgstr ""
@@ -378,14 +429,12 @@ msgid_plural "%{count} participants"
msgstr[0] ""
msgstr[1] ""
-msgid "%{count} pending comment"
-msgid_plural "%{count} pending comments"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
+msgid "%{count} total weight"
+msgstr ""
+
msgid "%{dashboard_path} could not be found."
msgstr ""
@@ -440,6 +489,9 @@ msgstr ""
msgid "%{group_name} uses group managed accounts. You need to create a new GitLab account which will be managed by %{group_name}."
msgstr ""
+msgid "%{group_name}&%{epic_iid} &middot; opened %{epic_created} by %{author}"
+msgstr ""
+
msgid "%{host} sign-in from new location"
msgstr ""
@@ -452,7 +504,7 @@ msgstr ""
msgid "%{issuableType} will be removed! Are you sure?"
msgstr ""
-msgid "%{issuesSize} issues with a limit of %{maxIssueCount}"
+msgid "%{issuesCount} issues with a limit of %{maxIssueCount}"
msgstr ""
msgid "%{issuesSize} with a limit of %{maxIssueCount}"
@@ -485,7 +537,7 @@ msgstr ""
msgid "%{labelStart}Namespace:%{labelEnd} %{namespace}"
msgstr ""
-msgid "%{labelStart}Report Type:%{labelEnd} %{reportType}"
+msgid "%{labelStart}Scan Type:%{labelEnd} %{reportType}"
msgstr ""
msgid "%{labelStart}Scanner:%{labelEnd} %{scanner}"
@@ -682,9 +734,6 @@ msgid_plural "%{securityScanner} results are not available because a pipeline ha
msgstr[0] ""
msgstr[1] ""
-msgid "%{service_title} %{message}."
-msgstr ""
-
msgid "%{size} GiB"
msgstr ""
@@ -773,6 +822,12 @@ msgstr ""
msgid "%{timebox_name} should belong either to a project or a group."
msgstr ""
+msgid "%{timebox_type} does not support burnup charts"
+msgstr ""
+
+msgid "%{timebox_type} must have a start and due date"
+msgstr ""
+
msgid "%{title} %{operator} %{threshold}"
msgstr ""
@@ -797,7 +852,7 @@ msgstr ""
msgid "%{total} open issue weight"
msgstr ""
-msgid "%{total} open issues"
+msgid "%{total} warnings found: showing first %{warningsDisplayed}"
msgstr ""
msgid "%{usage_ping_link_start}Learn more%{usage_ping_link_end} about what information is shared with GitLab Inc."
@@ -830,9 +885,6 @@ msgstr ""
msgid "&lt; 1 hour"
msgstr ""
-msgid "&lt;no name set&gt;"
-msgstr ""
-
msgid "&lt;no scopes selected&gt;"
msgstr ""
@@ -863,6 +915,9 @@ msgstr ""
msgid "'%{name}' Value Stream created"
msgstr ""
+msgid "'%{name}' Value Stream deleted"
+msgstr ""
+
msgid "'%{name}' stage already exists"
msgstr ""
@@ -922,6 +977,9 @@ msgstr ""
msgid "+ %{numberOfHiddenAssignees} more"
msgstr ""
+msgid "+ %{numberOfHiddenReviewers} more"
+msgstr ""
+
msgid "+%d more"
msgid_plural "+%d more"
msgstr[0] ""
@@ -982,6 +1040,11 @@ msgid_plural "%d Days"
msgstr[0] ""
msgstr[1] ""
+msgid "1 Issue"
+msgid_plural "%d Issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "1 closed issue"
msgid_plural "%{issues} closed issues"
msgstr[0] ""
@@ -997,6 +1060,11 @@ msgid_plural "%d days"
msgstr[0] ""
msgstr[1] ""
+msgid "1 deploy key"
+msgid_plural "%d deploy keys"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1099,6 +1167,9 @@ msgstr ""
msgid ":%{startLine} to %{endLine}"
msgstr ""
+msgid "A %{incident_docs_start}modified issue%{incident_docs_end} to guide the resolution of incidents."
+msgstr ""
+
msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr ""
@@ -1111,6 +1182,9 @@ msgstr ""
msgid "A GitBook site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
+msgid "A Gitpod configured Webapplication in Spring and Java"
+msgstr ""
+
msgid "A Hexo site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
@@ -1282,9 +1356,15 @@ msgstr ""
msgid "Access expiration date"
msgstr ""
+msgid "Access expires"
+msgstr ""
+
msgid "Access forbidden. Check your access level."
msgstr ""
+msgid "Access granted"
+msgstr ""
+
msgid "Access requests"
msgstr ""
@@ -1294,6 +1374,9 @@ msgstr ""
msgid "Access to Pages websites are controlled based on the user's membership to a given project. By checking this box, users will be required to be logged in to have access to all Pages websites in your instance."
msgstr ""
+msgid "AccessDropdown|Deploy Keys"
+msgstr ""
+
msgid "AccessDropdown|Groups"
msgstr ""
@@ -1411,12 +1494,6 @@ msgstr ""
msgid "Active Sessions"
msgstr ""
-msgid "Active Users:"
-msgstr ""
-
-msgid "Active users"
-msgstr ""
-
msgid "Activity"
msgstr ""
@@ -1584,9 +1661,6 @@ msgstr ""
msgid "Add label(s)"
msgstr ""
-msgid "Add license"
-msgstr ""
-
msgid "Add list"
msgstr ""
@@ -1761,21 +1835,51 @@ msgstr ""
msgid "AdminArea|Bots"
msgstr ""
+msgid "AdminArea|Components"
+msgstr ""
+
msgid "AdminArea|Developer"
msgstr ""
+msgid "AdminArea|Features"
+msgstr ""
+
+msgid "AdminArea|Groups: %{number_of_groups}"
+msgstr ""
+
msgid "AdminArea|Guest"
msgstr ""
msgid "AdminArea|Included Free in license"
msgstr ""
+msgid "AdminArea|Latest groups"
+msgstr ""
+
+msgid "AdminArea|Latest projects"
+msgstr ""
+
+msgid "AdminArea|Latest users"
+msgstr ""
+
msgid "AdminArea|Maintainer"
msgstr ""
+msgid "AdminArea|New group"
+msgstr ""
+
+msgid "AdminArea|New project"
+msgstr ""
+
+msgid "AdminArea|New user"
+msgstr ""
+
msgid "AdminArea|Owner"
msgstr ""
+msgid "AdminArea|Projects: %{number_of_projects}"
+msgstr ""
+
msgid "AdminArea|Reporter"
msgstr ""
@@ -1803,6 +1907,9 @@ msgstr ""
msgid "AdminArea|Users without a Group and Project"
msgstr ""
+msgid "AdminArea|Users: %{number_of_users}"
+msgstr ""
+
msgid "AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running."
msgstr ""
@@ -1821,9 +1928,6 @@ msgstr ""
msgid "AdminProjects|Delete Project %{projectName}?"
msgstr ""
-msgid "AdminProjects|Delete project"
-msgstr ""
-
msgid "AdminSettings|Apply integration settings to all Projects"
msgstr ""
@@ -2061,21 +2165,30 @@ msgstr ""
msgid "AdminUsers|Without projects"
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 ""
msgid "AdminUsers|You cannot remove your own admin rights."
msgstr ""
+msgid "AdminUsers|You must transfer ownership or delete the groups owned by this user before you can delete their account"
+msgstr ""
+
msgid "Administration"
msgstr ""
msgid "Advanced"
msgstr ""
+msgid "Advanced Search"
+msgstr ""
+
+msgid "Advanced Search with Elasticsearch"
+msgstr ""
+
msgid "Advanced Settings"
msgstr ""
@@ -2153,6 +2266,9 @@ msgstr ""
msgid "AlertManagement|Edit"
msgstr ""
+msgid "AlertManagement|Environment"
+msgstr ""
+
msgid "AlertManagement|Events"
msgstr ""
@@ -2165,6 +2281,9 @@ msgstr ""
msgid "AlertManagement|Issue"
msgstr ""
+msgid "AlertManagement|Key"
+msgstr ""
+
msgid "AlertManagement|Low"
msgstr ""
@@ -2258,6 +2377,9 @@ msgstr ""
msgid "AlertManagement|Unknown"
msgstr ""
+msgid "AlertManagement|Value"
+msgstr ""
+
msgid "AlertManagement|View alerts in Opsgenie"
msgstr ""
@@ -2417,6 +2539,9 @@ msgstr ""
msgid "All projects"
msgstr ""
+msgid "All projects selected"
+msgstr ""
+
msgid "All security scans are enabled because %{linkStart}Auto DevOps%{linkEnd} is enabled on this project"
msgstr ""
@@ -2504,6 +2629,9 @@ msgstr ""
msgid "Almost there"
msgstr ""
+msgid "Already blocked"
+msgstr ""
+
msgid "Also called \"Issuer\" or \"Relying party trust identifier\""
msgstr ""
@@ -2558,6 +2686,9 @@ msgstr ""
msgid "An error has occurred"
msgstr ""
+msgid "An error occured while making the changes: %{error}"
+msgstr ""
+
msgid "An error occurred adding a draft to the thread."
msgstr ""
@@ -2585,12 +2716,6 @@ msgstr ""
msgid "An error occurred when toggling the notification subscription"
msgstr ""
-msgid "An error occurred when trying to resolve a comment. Please try again."
-msgstr ""
-
-msgid "An error occurred when trying to resolve a discussion. Please try again."
-msgstr ""
-
msgid "An error occurred when updating the issue weight"
msgstr ""
@@ -2606,12 +2731,6 @@ msgstr ""
msgid "An error occurred while checking group path. Please refresh and try again."
msgstr ""
-msgid "An error occurred while committing your changes."
-msgstr ""
-
-msgid "An error occurred while creating the list. Please try again."
-msgstr ""
-
msgid "An error occurred while decoding the file."
msgstr ""
@@ -2684,25 +2803,19 @@ msgstr ""
msgid "An error occurred while fetching the Service Desk address."
msgstr ""
-msgid "An error occurred while fetching the board issues. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the board lists. Please reload the page."
msgstr ""
msgid "An error occurred while fetching the board lists. Please try again."
msgstr ""
-msgid "An error occurred while fetching the board swimlanes. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the builds."
msgstr ""
msgid "An error occurred while fetching the job log."
msgstr ""
-msgid "An error occurred while fetching the job trace."
+msgid "An error occurred while fetching the job logs."
msgstr ""
msgid "An error occurred while fetching the job."
@@ -2849,9 +2962,6 @@ msgstr ""
msgid "An error occurred while saving assignees"
msgstr ""
-msgid "An error occurred while saving the template. Please check if the template exists."
-msgstr ""
-
msgid "An error occurred while searching for milestones"
msgstr ""
@@ -2870,10 +2980,10 @@ msgstr ""
msgid "An error occurred while updating approvers"
msgstr ""
-msgid "An error occurred while updating the comment"
+msgid "An error occurred while updating labels."
msgstr ""
-msgid "An error occurred while updating the list. Please try again."
+msgid "An error occurred while updating the comment"
msgstr ""
msgid "An error occurred while validating group path"
@@ -2927,6 +3037,9 @@ msgstr ""
msgid "An unknown error occurred while loading this graph."
msgstr ""
+msgid "An unknown error occurred."
+msgstr ""
+
msgid "Analytics"
msgstr ""
@@ -2960,10 +3073,10 @@ msgstr ""
msgid "Any"
msgstr ""
-msgid "Any Author"
+msgid "Any %{header}"
msgstr ""
-msgid "Any Status"
+msgid "Any Author"
msgstr ""
msgid "Any branch"
@@ -3017,6 +3130,9 @@ msgstr ""
msgid "Application ID"
msgstr ""
+msgid "Application limits saved successfully"
+msgstr ""
+
msgid "Application settings saved successfully"
msgstr ""
@@ -3226,6 +3342,9 @@ msgstr ""
msgid "Are you sure you want to close this blocked issue?"
msgstr ""
+msgid "Are you sure you want to delete \"%{name}\" Value Stream?"
+msgstr ""
+
msgid "Are you sure you want to delete %{name}?"
msgstr ""
@@ -3235,6 +3354,9 @@ msgstr ""
msgid "Are you sure you want to delete this %{typeOfComment}?"
msgstr ""
+msgid "Are you sure you want to delete this SSH key?"
+msgstr ""
+
msgid "Are you sure you want to delete this board?"
msgstr ""
@@ -3259,6 +3381,11 @@ msgstr ""
msgid "Are you sure you want to erase this build?"
msgstr ""
+msgid "Are you sure you want to import %d repository?"
+msgid_plural "Are you sure you want to import %d repositories?"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Are you sure you want to lose unsaved changes?"
msgstr ""
@@ -3268,15 +3395,15 @@ msgstr ""
msgid "Are you sure you want to merge immediately?"
msgstr ""
-msgid "Are you sure you want to permanently delete this license?"
-msgstr ""
-
msgid "Are you sure you want to re-deploy this environment?"
msgstr ""
msgid "Are you sure you want to regenerate the public key? You will have to update the public key on the remote server before mirroring will work again."
msgstr ""
+msgid "Are you sure you want to reindex?"
+msgstr ""
+
msgid "Are you sure you want to remove %{group_name}?"
msgstr ""
@@ -3304,6 +3431,9 @@ msgstr ""
msgid "Are you sure you want to revoke this nickname?"
msgstr ""
+msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
+msgstr ""
+
msgid "Are you sure you want to stop this environment?"
msgstr ""
@@ -3325,6 +3455,9 @@ msgstr ""
msgid "Are you sure? The device will be signed out of GitLab and all remember me tokens revoked."
msgstr ""
+msgid "Are you sure? This will invalidate your registered applications and U2F / WebAuthn devices."
+msgstr ""
+
msgid "Are you sure? This will invalidate your registered applications and U2F devices."
msgstr ""
@@ -3343,9 +3476,6 @@ msgstr ""
msgid "Artifacts"
msgstr ""
-msgid "As U2F devices are only supported by a few browsers, we require that you set up a two-factor authentication app before a U2F device. That way you'll always be able to log in - even when you're using an unsupported browser."
-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 ""
@@ -3539,6 +3669,9 @@ msgstr ""
msgid "AuditLogs|Target"
msgstr ""
+msgid "AuditLogs|This month"
+msgstr ""
+
msgid "AuditLogs|User Events"
msgstr ""
@@ -3578,6 +3711,9 @@ msgstr ""
msgid "Authentication via U2F device failed."
msgstr ""
+msgid "Authentication via WebAuthn device failed."
+msgstr ""
+
msgid "Author"
msgstr ""
@@ -3845,15 +3981,6 @@ msgstr ""
msgid "BambooService|You must set up automatic revision labeling and a repository trigger in Bamboo."
msgstr ""
-msgid "BatchComments|Delete all pending comments"
-msgstr ""
-
-msgid "BatchComments|Discard review?"
-msgstr ""
-
-msgid "BatchComments|You're about to discard your review which will delete all of your pending comments. The deleted comments %{strong_start}cannot%{strong_end} be restored."
-msgstr ""
-
msgid "Be careful. Changing the project's namespace can have unintended side effects."
msgstr ""
@@ -3875,6 +4002,9 @@ msgstr ""
msgid "Bi-weekly code coverage"
msgstr ""
+msgid "Billable Users:"
+msgstr ""
+
msgid "Billing"
msgstr ""
@@ -3884,7 +4014,7 @@ msgstr ""
msgid "BillingPlans|@%{user_name} you are currently using the %{plan_name} plan."
msgstr ""
-msgid "BillingPlans|Congratulations, your new trial is activated"
+msgid "BillingPlans|Congratulations, your free trial is activated."
msgstr ""
msgid "BillingPlans|If you would like to downgrade your plan please contact %{support_link_start}Customer Support%{support_link_end}."
@@ -3947,6 +4077,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Block user"
+msgstr ""
+
msgid "Blocked"
msgstr ""
@@ -3962,31 +4095,37 @@ msgstr ""
msgid "Blog"
msgstr ""
-msgid "Board name"
-msgstr ""
-
msgid "Board scope"
msgstr ""
msgid "Board scope affects which issues are displayed for anyone who visits this board"
msgstr ""
-msgid "BoardBlankState|Add default lists"
+msgid "Boards"
msgstr ""
-msgid "BoardBlankState|Add the following default lists to your Issue Board with one click:"
+msgid "Boards and Board Lists"
msgstr ""
-msgid "BoardBlankState|Nevermind, I'll use my own"
+msgid "Boards|An error occurred while creating the issue. Please try again."
msgstr ""
-msgid "BoardBlankState|Starting out with the default set of lists will get you right on the way to making the most of your board."
+msgid "Boards|An error occurred while creating the list. Please try again."
msgstr ""
-msgid "Boards"
+msgid "Boards|An error occurred while fetching issues. Please reload the page."
msgstr ""
-msgid "Boards and Board Lists"
+msgid "Boards|An error occurred while fetching the board issues. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching the board swimlanes. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while moving the issue. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while updating the list. Please try again."
msgstr ""
msgid "Boards|Collapse"
@@ -4013,7 +4152,7 @@ msgstr ""
msgid "Branch %{branch_name} was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr ""
-msgid "Branch has changed"
+msgid "Branch changed"
msgstr ""
msgid "Branch is already taken"
@@ -4319,6 +4458,9 @@ msgstr ""
msgid "CLOSED (MOVED)"
msgstr ""
+msgid "CODEOWNERS rule violation"
+msgstr ""
+
msgid "CONTRIBUTING"
msgstr ""
@@ -4349,9 +4491,6 @@ msgstr ""
msgid "Can't create snippet: %{err}"
msgstr ""
-msgid "Can't edit as source branch was deleted"
-msgstr ""
-
msgid "Can't fetch content for the blob: %{err}"
msgstr ""
@@ -4364,9 +4503,6 @@ msgstr ""
msgid "Can't load mermaid module: %{err}"
msgstr ""
-msgid "Can't remove group members without group managed account"
-msgstr ""
-
msgid "Can't scan the code?"
msgstr ""
@@ -4409,6 +4545,9 @@ msgstr ""
msgid "Cannot create the abuse report. This user has been blocked."
msgstr ""
+msgid "Cannot enable shared runners because parent group does not allow it"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -4514,6 +4653,15 @@ msgstr ""
msgid "Change your password or recover your current one"
msgstr ""
+msgid "ChangeReviewer|Reviewer changed from %{old} to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Reviewer changed to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Unassigned"
+msgstr ""
+
msgid "ChangeTypeActionLabel|Pick into branch"
msgstr ""
@@ -4553,6 +4701,9 @@ msgstr ""
msgid "Changes the title to \"%{title_param}\"."
msgstr ""
+msgid "Changes were successfully made."
+msgstr ""
+
msgid "Changes won't take place until the index is %{link_start}recreated%{link_end}."
msgstr ""
@@ -4958,6 +5109,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove variable"
+msgstr ""
+
msgid "CiVariables|Remove variable row"
msgstr ""
@@ -5036,9 +5190,6 @@ msgstr ""
msgid "Clear due date"
msgstr ""
-msgid "Clear input"
-msgstr ""
-
msgid "Clear recent searches"
msgstr ""
@@ -5087,6 +5238,9 @@ msgstr ""
msgid "Client authentication key password"
msgstr ""
+msgid "Client request timeout"
+msgstr ""
+
msgid "Clients"
msgstr ""
@@ -5171,6 +5325,27 @@ msgstr ""
msgid "Cluster type must be specificed for Stages::ClusterEndpointInserter"
msgstr ""
+msgid "ClusterAgents|Configuration"
+msgstr ""
+
+msgid "ClusterAgents|Connect your cluster with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate Kubernetes with a GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Name"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Agent also requires %{linkStart}enabling the Agent Server%{linkEnd}"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Kubernetes Agent allows an Infrastructure as Code, GitOps approach to integrating Kubernetes clusters with GitLab. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "ClusterAgent|This feature is only available for premium plans"
msgstr ""
@@ -5240,10 +5415,10 @@ msgstr ""
msgid "ClusterIntegration|All installed applications and related resources"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster."
+msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{linkStart}More information%{linkEnd}"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{startLink}More information%{endLink}"
+msgid "ClusterIntegration|Allow GitLab to manage namespaces and service accounts for this cluster."
msgstr ""
msgid "ClusterIntegration|Alternatively, "
@@ -5264,6 +5439,9 @@ msgstr ""
msgid "ClusterIntegration|An error occurred while trying to fetch zone machine types: %{error}"
msgstr ""
+msgid "ClusterIntegration|An unknown error occurred while attempting to connect to Kubernetes."
+msgstr ""
+
msgid "ClusterIntegration|Any project namespaces"
msgstr ""
@@ -5279,6 +5457,9 @@ msgstr ""
msgid "ClusterIntegration|Authenticate with Amazon Web Services"
msgstr ""
+msgid "ClusterIntegration|Authentication Error"
+msgstr ""
+
msgid "ClusterIntegration|Base domain"
msgstr ""
@@ -5297,13 +5478,22 @@ msgstr ""
msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}security group %{externalLinkIcon} %{endLink} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
+msgid "ClusterIntegration|Check your CA certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Check your cluster status"
+msgstr ""
+
+msgid "ClusterIntegration|Check your token"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}subnets %{externalLinkIcon} %{endLink} in your VPC where your worker nodes will run."
+msgid "ClusterIntegration|Choose the %{linkStart}security group %{linkEnd} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
msgstr ""
-msgid "ClusterIntegration|Choose the worker node %{startLink}instance type %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Choose the %{linkStart}subnets %{linkEnd} in your VPC where your worker nodes will run."
+msgstr ""
+
+msgid "ClusterIntegration|Choose the worker node %{linkStart}instance type%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Choose which applications to install on your Kubernetes cluster."
@@ -5315,10 +5505,7 @@ msgstr ""
msgid "ClusterIntegration|Clear cluster cache"
msgstr ""
-msgid "ClusterIntegration|Clear the local cache of namespace and service accounts. This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
-msgstr ""
-
-msgid "ClusterIntegration|Cluster being created"
+msgid "ClusterIntegration|Clear the local cache of namespace and service accounts."
msgstr ""
msgid "ClusterIntegration|Cluster management project (alpha)"
@@ -5330,15 +5517,21 @@ msgstr ""
msgid "ClusterIntegration|Cluster_applications artifact too big. Maximum allowable size: %{human_size}"
msgstr ""
-msgid "ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters."
+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|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}"
+msgid "ClusterIntegration|Clusters connected with a certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Connect cluster with certificate"
msgstr ""
msgid "ClusterIntegration|Connect existing cluster"
msgstr ""
+msgid "ClusterIntegration|Connection Error"
+msgstr ""
+
msgid "ClusterIntegration|Copy API URL"
msgstr ""
@@ -5414,6 +5607,12 @@ msgstr ""
msgid "ClusterIntegration|Deletes all GitLab resources attached to this cluster during removal"
msgstr ""
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared."
+msgstr ""
+
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared. %{linkStart}More information%{linkEnd}"
+msgstr ""
+
msgid "ClusterIntegration|Did you know?"
msgstr ""
@@ -5483,6 +5682,9 @@ msgstr ""
msgid "ClusterIntegration|Fluentd is an open source data collector, which lets you unify the data collection and consumption for a better use and understanding of data. It requires at least one of the following logs to be successfully installed."
msgstr ""
+msgid "ClusterIntegration|GitLab Agent managed clusters"
+msgstr ""
+
msgid "ClusterIntegration|GitLab Container Network Policies"
msgstr ""
@@ -5495,6 +5697,12 @@ msgstr ""
msgid "ClusterIntegration|GitLab Runner connects to the repository and executes CI/CD jobs, pushing results back and deploying applications to production."
msgstr ""
+msgid "ClusterIntegration|GitLab failed to authenticate."
+msgstr ""
+
+msgid "ClusterIntegration|GitLab failed to connect to the cluster."
+msgstr ""
+
msgid "ClusterIntegration|GitLab-managed cluster"
msgstr ""
@@ -5516,6 +5724,9 @@ msgstr ""
msgid "ClusterIntegration|Group cluster"
msgstr ""
+msgid "ClusterIntegration|HTTP Error"
+msgstr ""
+
msgid "ClusterIntegration|Helm Tiller"
msgstr ""
@@ -5549,7 +5760,10 @@ msgstr ""
msgid "ClusterIntegration|Instance type"
msgstr ""
-msgid "ClusterIntegration|Integrate Kubernetes cluster automation"
+msgid "ClusterIntegration|Integrate Kubernetes with a cluster certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Integrate with a cluster certificate"
msgstr ""
msgid "ClusterIntegration|Issuer Email"
@@ -5585,9 +5799,6 @@ msgstr ""
msgid "ClusterIntegration|Knative extends Kubernetes to provide a set of middleware components that are essential to build modern, source-centric, and container-based applications that can run anywhere: on premises, in the cloud, or even in a third-party data center."
msgstr ""
-msgid "ClusterIntegration|Kubernetes cluster"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes cluster is being created..."
msgstr ""
@@ -5600,9 +5811,6 @@ msgstr ""
msgid "ClusterIntegration|Kubernetes clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr ""
-msgid "ClusterIntegration|Kubernetes clusters can be used to deploy applications and to provide Review Apps for this project"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes version"
msgstr ""
@@ -5615,7 +5823,7 @@ msgstr ""
msgid "ClusterIntegration|Learn more about %{help_link_start}zones%{help_link_end}."
msgstr ""
-msgid "ClusterIntegration|Learn more about %{startLink}Regions %{externalLinkIcon}%{endLink}."
+msgid "ClusterIntegration|Learn more about %{linkStart}Regions%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Learn more about Kubernetes"
@@ -5660,12 +5868,18 @@ msgstr ""
msgid "ClusterIntegration|Machine type"
msgstr ""
+msgid "ClusterIntegration|Make sure your API endpoint is correct"
+msgstr ""
+
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create Kubernetes clusters"
msgstr ""
msgid "ClusterIntegration|Manage your Kubernetes cluster by visiting %{provider_link}"
msgstr ""
+msgid "ClusterIntegration|Namespace per environment"
+msgstr ""
+
msgid "ClusterIntegration|No IAM Roles found"
msgstr ""
@@ -5711,6 +5925,9 @@ msgstr ""
msgid "ClusterIntegration|No zones matched your search"
msgstr ""
+msgid "ClusterIntegration|Node calculations use the Kubernetes Metrics API. Make sure your cluster has metrics installed"
+msgstr ""
+
msgid "ClusterIntegration|Number of nodes"
msgstr ""
@@ -5753,6 +5970,9 @@ msgstr ""
msgid "ClusterIntegration|RBAC-enabled cluster"
msgstr ""
+msgid "ClusterIntegration|Read our %{linkStart}help page%{linkEnd} on Kubernetes cluster integration."
+msgstr ""
+
msgid "ClusterIntegration|Read our %{link_start}help page%{link_end} on Kubernetes cluster integration."
msgstr ""
@@ -5855,7 +6075,7 @@ msgstr ""
msgid "ClusterIntegration|Select a VPC to choose a subnet"
msgstr ""
-msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{linkStart}Amazon Web Services %{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select a network to choose a subnetwork"
@@ -5888,7 +6108,7 @@ msgstr ""
msgid "ClusterIntegration|Select project to choose zone"
msgstr ""
-msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select zone"
@@ -5978,9 +6198,18 @@ msgstr ""
msgid "ClusterIntegration|There was a problem authenticating with your cluster. Please ensure your CA Certificate and Token are valid."
msgstr ""
+msgid "ClusterIntegration|There was an HTTP error when connecting to your cluster."
+msgstr ""
+
msgid "ClusterIntegration|This account must have permissions to create a Kubernetes cluster in the %{link_to_container_project} specified below"
msgstr ""
+msgid "ClusterIntegration|This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
+msgstr ""
+
+msgid "ClusterIntegration|This is necessary to clear existing environment-namespace associations from clusters previously managed by GitLab."
+msgstr ""
+
msgid "ClusterIntegration|This option will allow you to install applications on RBAC clusters."
msgstr ""
@@ -6005,9 +6234,21 @@ msgstr ""
msgid "ClusterIntegration|To use a new project, first create one on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}."
msgstr ""
+msgid "ClusterIntegration|Troubleshooting tips:"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Authenticate"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Connect"
+msgstr ""
+
msgid "ClusterIntegration|Uninstall %{appTitle}"
msgstr ""
+msgid "ClusterIntegration|Unknown Error"
+msgstr ""
+
msgid "ClusterIntegration|Update %{appTitle}"
msgstr ""
@@ -6068,7 +6309,7 @@ msgstr ""
msgid "ClusterIntegration|Your cluster API is unreachable. Please ensure your API URL is correct."
msgstr ""
-msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Zone"
@@ -6188,6 +6429,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse all threads"
+msgstr ""
+
msgid "Collapse approvers"
msgstr ""
@@ -6337,7 +6581,7 @@ msgstr ""
msgid "Commit…"
msgstr ""
-msgid "Company"
+msgid "Community forum"
msgstr ""
msgid "Company name"
@@ -6346,6 +6590,9 @@ msgstr ""
msgid "Compare"
msgstr ""
+msgid "Compare %{oldCommitId}...%{newCommitId}"
+msgstr ""
+
msgid "Compare Git revisions"
msgstr ""
@@ -6361,6 +6608,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare submodule commit revisions"
+msgstr ""
+
msgid "Compare with previous version"
msgstr ""
@@ -6496,6 +6746,9 @@ msgstr ""
msgid "Configure the way a user creates a new account."
msgstr ""
+msgid "Configure which lists are shown for anyone who visits this board"
+msgstr ""
+
msgid "Confirm"
msgstr ""
@@ -6721,6 +6974,9 @@ msgstr[1] ""
msgid "ContainerRegistry|Set cleanup policy"
msgstr ""
+msgid "ContainerRegistry|Some tags were not deleted"
+msgstr ""
+
msgid "ContainerRegistry|Something went wrong while fetching the cleanup policy."
msgstr ""
@@ -6760,6 +7016,9 @@ msgstr ""
msgid "ContainerRegistry|Tags with names matching this regex pattern will %{italicStart}expire:%{italicEnd}"
msgstr ""
+msgid "ContainerRegistry|The cleanup policy timed out before it could delete all tags. An administrator can %{adminLinkStart}manually run cleanup now%{adminLinkEnd} or you can wait for the cleanup policy to automatically run again. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "ContainerRegistry|The last tag related to this image was recently removed. This empty image and any associated data will be automatically removed as part of the regular Garbage Collection process. If you have any questions, contact your administrator."
msgstr ""
@@ -6892,6 +7151,9 @@ msgstr ""
msgid "Contributions per group member"
msgstr ""
+msgid "Contributor"
+msgstr ""
+
msgid "Contributors"
msgstr ""
@@ -7021,6 +7283,9 @@ msgstr ""
msgid "Could not change HEAD: branch '%{branch}' does not exist"
msgstr ""
+msgid "Could not commit. An unexpected error occurred."
+msgstr ""
+
msgid "Could not connect to FogBugz, check your URL"
msgstr ""
@@ -7060,6 +7325,9 @@ msgstr ""
msgid "Could not find iteration"
msgstr ""
+msgid "Could not load instance counts. Please refresh the page to try again."
+msgstr ""
+
msgid "Could not remove the trigger."
msgstr ""
@@ -7084,10 +7352,10 @@ msgstr ""
msgid "Could not save prometheus manual configuration"
msgstr ""
-msgid "Could not udpdate wiki page"
+msgid "Could not update the LDAP settings"
msgstr ""
-msgid "Could not update the LDAP settings"
+msgid "Could not update wiki page"
msgstr ""
msgid "Could not upload your designs as one or more files uploaded are not supported."
@@ -7745,6 +8013,9 @@ msgstr ""
msgid "DastProfiles|Are you sure you want to delete this profile?"
msgstr ""
+msgid "DastProfiles|Could not create site validation token. Please refresh the page, or try again later."
+msgstr ""
+
msgid "DastProfiles|Could not create the scanner profile. Please try again."
msgstr ""
@@ -7769,6 +8040,12 @@ msgstr ""
msgid "DastProfiles|Could not fetch site profiles. Please refresh the page, or try again later."
msgstr ""
+msgid "DastProfiles|Could not retrieve site validation status. Please refresh the page, or try again later."
+msgstr ""
+
+msgid "DastProfiles|Could not update the scanner profile. Please try again."
+msgstr ""
+
msgid "DastProfiles|Could not update the site profile. Please try again."
msgstr ""
@@ -7784,7 +8061,7 @@ msgstr ""
msgid "DastProfiles|Download validation text file"
msgstr ""
-msgid "DastProfiles|Edit feature will come soon. Please create a new profile if changes needed"
+msgid "DastProfiles|Edit scanner profile"
msgstr ""
msgid "DastProfiles|Edit site profile"
@@ -7817,6 +8094,9 @@ msgstr ""
msgid "DastProfiles|No profiles created yet"
msgstr ""
+msgid "DastProfiles|Passive"
+msgstr ""
+
msgid "DastProfiles|Please enter a valid URL format, ex: http://www.example.com/home"
msgstr ""
@@ -7832,6 +8112,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan mode"
+msgstr ""
+
msgid "DastProfiles|Scanner Profile"
msgstr ""
@@ -7871,10 +8154,10 @@ msgstr ""
msgid "DastProfiles|Text file validation"
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
+msgid "DastProfiles|The maximum number of minutes allowed for the spider to traverse the site."
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the spider to traverse the site."
+msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
msgstr ""
msgid "DastProfiles|Validate"
@@ -7907,6 +8190,9 @@ msgstr ""
msgid "Date picker"
msgstr ""
+msgid "Date range"
+msgstr ""
+
msgid "Date range cannot exceed %{maxDateRange} days."
msgstr ""
@@ -7931,6 +8217,9 @@ msgstr ""
msgid "Days to merge"
msgstr ""
+msgid "Dear Administrator,"
+msgstr ""
+
msgid "Debug"
msgstr ""
@@ -8042,12 +8331,18 @@ msgstr ""
msgid "Delete"
msgstr ""
+msgid "Delete %{name}"
+msgstr ""
+
msgid "Delete Comment"
msgstr ""
msgid "Delete Snippet"
msgstr ""
+msgid "Delete Value Stream"
+msgstr ""
+
msgid "Delete account"
msgstr ""
@@ -8069,9 +8364,6 @@ msgstr ""
msgid "Delete label: %{label_name} ?"
msgstr ""
-msgid "Delete license"
-msgstr ""
-
msgid "Delete list"
msgstr ""
@@ -8147,15 +8439,6 @@ msgstr ""
msgid "Deleting a project places it into a read-only state until %{date}, at which point the project will be permanently deleted. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "Deleting the license failed."
-msgstr ""
-
-msgid "Deleting the license failed. The license was not found."
-msgstr ""
-
-msgid "Deleting the license failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "Deleting the project will delete its repository and all related resources including issues, merge requests etc."
msgstr ""
@@ -8651,7 +8934,10 @@ msgstr ""
msgid "DesignManagement|The maximum number of designs allowed to be uploaded is %{upload_limit}. Please try again."
msgstr ""
-msgid "DesignManagement|To upload designs, you'll need to enable LFS. %{requirements_link_start}More information%{requirements_link_end}"
+msgid "DesignManagement|There was an error moving your designs. Please upload your designs below."
+msgstr ""
+
+msgid "DesignManagement|To upload designs, you'll need to enable LFS and have admin enable hashed storage. %{requirements_link_start}More information%{requirements_link_end}"
msgstr ""
msgid "DesignManagement|Unresolve thread"
@@ -8663,6 +8949,9 @@ msgstr ""
msgid "DesignManagement|Upload skipped."
msgstr ""
+msgid "DesignManagement|Your designs are being copied and are on their way… Please refresh to update."
+msgstr ""
+
msgid "DesignManagement|and %{moreCount} more."
msgstr ""
@@ -8720,6 +9009,9 @@ msgstr ""
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
+msgid "Direct member"
+msgstr ""
+
msgid "Direction"
msgstr ""
@@ -8768,9 +9060,6 @@ msgstr ""
msgid "Discard draft"
msgstr ""
-msgid "Discard review"
-msgstr ""
-
msgid "DiscordService|Discord Notifications"
msgstr ""
@@ -8839,10 +9128,10 @@ msgstr ""
msgid "Dismiss Merge Request promotion"
msgstr ""
-msgid "Dismiss Selected"
+msgid "Dismiss Value Stream Analytics introduction box"
msgstr ""
-msgid "Dismiss Value Stream Analytics introduction box"
+msgid "Dismiss selected"
msgstr ""
msgid "Dismiss trial promotion"
@@ -8893,9 +9182,6 @@ msgstr ""
msgid "Documents reindexed: %{processed_documents} (%{percentage}%%)"
msgstr ""
-msgid "Doing"
-msgstr ""
-
msgid "Domain"
msgstr ""
@@ -9091,9 +9377,6 @@ msgstr ""
msgid "Edit environment"
msgstr ""
-msgid "Edit file"
-msgstr ""
-
msgid "Edit files in the editor and commit changes here"
msgstr ""
@@ -9106,6 +9389,12 @@ msgstr ""
msgid "Edit identity for %{user_name}"
msgstr ""
+msgid "Edit in Web IDE"
+msgstr ""
+
+msgid "Edit in single-file editor"
+msgstr ""
+
msgid "Edit issues"
msgstr ""
@@ -9133,10 +9422,10 @@ msgstr ""
msgid "Editing"
msgstr ""
-msgid "Elasticsearch"
+msgid "Elasticsearch AWS IAM credentials"
msgstr ""
-msgid "Elasticsearch AWS IAM credentials"
+msgid "Elasticsearch HTTP client timeout value in seconds."
msgstr ""
msgid "Elasticsearch indexing restrictions"
@@ -9145,9 +9434,6 @@ msgstr ""
msgid "Elasticsearch indexing started"
msgstr ""
-msgid "Elasticsearch integration. Elasticsearch AWS IAM."
-msgstr ""
-
msgid "Elasticsearch reindexing is already in progress"
msgstr ""
@@ -9175,9 +9461,6 @@ msgstr ""
msgid "Email Notification"
msgstr ""
-msgid "Email address"
-msgstr ""
-
msgid "Email could not be sent"
msgstr ""
@@ -9241,6 +9524,9 @@ msgstr ""
msgid "Emails sent from Service Desk will have this name"
msgstr ""
+msgid "Emails sent to %{email} will still be supported"
+msgstr ""
+
msgid "Emails separated by comma"
msgstr ""
@@ -9274,9 +9560,18 @@ msgstr ""
msgid "Enable"
msgstr ""
+msgid "Enable %{link_start}Gitpod%{link_end} integration to launch a development environment in your browser directly from GitLab."
+msgstr ""
+
msgid "Enable Auto DevOps"
msgstr ""
+msgid "Enable Gitpod"
+msgstr ""
+
+msgid "Enable Gitpod?"
+msgstr ""
+
msgid "Enable HTML emails"
msgstr ""
@@ -9406,9 +9701,6 @@ msgstr ""
msgid "Encountered an error while rendering: %{err}"
msgstr ""
-msgid "End date"
-msgstr ""
-
msgid "Ends at (UTC)"
msgstr ""
@@ -9568,7 +9860,7 @@ msgstr ""
msgid "EnvironmentsDashboard|The environments dashboard provides a summary of each project's environments' status, including pipeline and alert statuses."
msgstr ""
-msgid "EnvironmentsDashboard|This dashboard displays a maximum of 7 projects and 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
+msgid "EnvironmentsDashboard|This dashboard displays 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
msgstr ""
msgid "Environments|An error occurred while canceling the auto stop, please try again"
@@ -9889,6 +10181,9 @@ msgstr ""
msgid "Error deleting project. Check logs for error details."
msgstr ""
+msgid "Error fetching burnup chart data"
+msgstr ""
+
msgid "Error fetching diverging counts for branches. Please try again."
msgstr ""
@@ -9967,6 +10262,9 @@ msgstr ""
msgid "Error occurred when saving assignees"
msgstr ""
+msgid "Error occurred when saving reviewers"
+msgstr ""
+
msgid "Error occurred when toggling the notification subscription"
msgstr ""
@@ -10219,10 +10517,13 @@ msgstr ""
msgid "Expand all"
msgstr ""
-msgid "Expand approvers"
+msgid "Expand all files"
msgstr ""
-msgid "Expand dropdown"
+msgid "Expand all threads"
+msgstr ""
+
+msgid "Expand approvers"
msgstr ""
msgid "Expand milestones"
@@ -10393,6 +10694,9 @@ msgstr ""
msgid "Failed to create Merge Request. Please try again."
msgstr ""
+msgid "Failed to create To-Do for the design."
+msgstr ""
+
msgid "Failed to create a branch for this issue. Please try again."
msgstr ""
@@ -10432,6 +10736,12 @@ msgstr ""
msgid "Failed to load authors. Please try again."
msgstr ""
+msgid "Failed to load branches. Please try again."
+msgstr ""
+
+msgid "Failed to load deploy keys."
+msgstr ""
+
msgid "Failed to load emoji list."
msgstr ""
@@ -10447,6 +10757,9 @@ msgstr ""
msgid "Failed to load groups & users."
msgstr ""
+msgid "Failed to load groups, users and deploy keys."
+msgstr ""
+
msgid "Failed to load labels. Please try again."
msgstr ""
@@ -10456,6 +10769,12 @@ msgstr ""
msgid "Failed to load related branches"
msgstr ""
+msgid "Failed to load sidebar confidential toggle"
+msgstr ""
+
+msgid "Failed to load sidebar lock status"
+msgstr ""
+
msgid "Failed to load stacktrace."
msgstr ""
@@ -10483,6 +10802,9 @@ msgstr ""
msgid "Failed to publish issue on status page."
msgstr ""
+msgid "Failed to remove To-Do for the design."
+msgstr ""
+
msgid "Failed to remove a Zoom meeting"
msgstr ""
@@ -10525,6 +10847,9 @@ msgstr ""
msgid "Failed to signing using smartcard authentication"
msgstr ""
+msgid "Failed to toggle To-Do for the design."
+msgstr ""
+
msgid "Failed to update branch!"
msgstr ""
@@ -10638,7 +10963,7 @@ msgstr ""
msgid "FeatureFlags|Edit User List"
msgstr ""
-msgid "FeatureFlags|Enable features for specific users and specific environments by defining feature flag strategies."
+msgid "FeatureFlags|Enable features for specific users and environments by configuring feature flag strategies."
msgstr ""
msgid "FeatureFlags|Environment Spec"
@@ -10698,7 +11023,7 @@ msgstr ""
msgid "FeatureFlags|Include additional user IDs"
msgstr ""
-msgid "FeatureFlags|Install a %{docs_link_anchored_start}compatible client library%{docs_link_anchored_end} and specify the API URL, application name, and instance ID during the configuration setup. %{docs_link_start}More Information%{docs_link_end}"
+msgid "FeatureFlags|Install a %{docsLinkAnchoredStart}compatible client library%{docsLinkAnchoredEnd} and specify the API URL, application name, and instance ID during the configuration setup. %{docsLinkStart}More Information%{docsLinkEnd}"
msgstr ""
msgid "FeatureFlags|Instance ID"
@@ -10710,6 +11035,9 @@ msgstr ""
msgid "FeatureFlags|Loading feature flags"
msgstr ""
+msgid "FeatureFlags|Loading user lists"
+msgstr ""
+
msgid "FeatureFlags|More information"
msgstr ""
@@ -10728,7 +11056,7 @@ msgstr ""
msgid "FeatureFlags|New feature flag"
msgstr ""
-msgid "FeatureFlags|New list"
+msgid "FeatureFlags|New user list"
msgstr ""
msgid "FeatureFlags|Percent of users"
@@ -10767,6 +11095,9 @@ msgstr ""
msgid "FeatureFlags|There was an error fetching the feature flags."
msgstr ""
+msgid "FeatureFlags|There was an error fetching the user lists."
+msgstr ""
+
msgid "FeatureFlags|There was an error retrieving user lists"
msgstr ""
@@ -10782,6 +11113,9 @@ msgstr ""
msgid "FeatureFlags|User List"
msgstr ""
+msgid "FeatureFlags|User Lists"
+msgstr ""
+
msgid "FeatureFlag|List"
msgstr ""
@@ -10809,15 +11143,6 @@ msgstr ""
msgid "Fetching incoming email"
msgstr ""
-msgid "Fetching licenses failed."
-msgstr ""
-
-msgid "Fetching licenses failed. The request endpoint was not found."
-msgstr ""
-
-msgid "Fetching licenses failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "File"
msgstr ""
@@ -10920,12 +11245,21 @@ msgstr ""
msgid "Filter by status"
msgstr ""
+msgid "Filter by test cases that are currently archived."
+msgstr ""
+
+msgid "Filter by test cases that are currently opened."
+msgstr ""
+
msgid "Filter by two-factor authentication"
msgstr ""
msgid "Filter by user"
msgstr ""
+msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
+msgstr ""
+
msgid "Filter pipelines"
msgstr ""
@@ -10941,7 +11275,7 @@ msgstr ""
msgid "Filter results..."
msgstr ""
-msgid "Filter your projects by name"
+msgid "Filter your repositories by name"
msgstr ""
msgid "Filter..."
@@ -10950,7 +11284,7 @@ msgstr ""
msgid "Find File"
msgstr ""
-msgid "Find bugs in your code with coverage-guided fuzzing"
+msgid "Find bugs in your code with coverage-guided fuzzing."
msgstr ""
msgid "Find by path"
@@ -10977,9 +11311,6 @@ msgstr ""
msgid "Finish editing this message first!"
msgstr ""
-msgid "Finish review"
-msgstr ""
-
msgid "Finish setting up your dedicated account for %{group_name}."
msgstr ""
@@ -11049,6 +11380,9 @@ msgstr ""
msgid "Footer message"
msgstr ""
+msgid "For a faster browsing experience, some files are collapsed by default."
+msgstr ""
+
msgid "For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
@@ -11058,6 +11392,9 @@ msgstr ""
msgid "For more info, read the documentation."
msgstr ""
+msgid "For more information on how the number of active users is calculated, see the %{self_managed_subscriptions_doc_link} documentation."
+msgstr ""
+
msgid "For more information, go to the "
msgstr ""
@@ -11196,6 +11533,9 @@ msgstr ""
msgid "Generate new token"
msgstr ""
+msgid "Generic package file size in bytes"
+msgstr ""
+
msgid "Geo"
msgstr ""
@@ -11457,6 +11797,9 @@ msgstr ""
msgid "Geo|Please refer to Geo Troubleshooting."
msgstr ""
+msgid "Geo|Primary node"
+msgstr ""
+
msgid "Geo|Project"
msgstr ""
@@ -11499,6 +11842,9 @@ msgstr ""
msgid "Geo|Review replication status, and resynchronize and reverify items with the primary node."
msgstr ""
+msgid "Geo|Secondary node"
+msgstr ""
+
msgid "Geo|Status"
msgstr ""
@@ -11538,6 +11884,9 @@ msgstr ""
msgid "Geo|URL must be a valid url (ex: https://gitlab.com)"
msgstr ""
+msgid "Geo|Undefined"
+msgstr ""
+
msgid "Geo|Unknown state"
msgstr ""
@@ -11613,10 +11962,16 @@ msgstr ""
msgid "GitHub import"
msgstr ""
+msgid "GitLab"
+msgstr ""
+
msgid "GitLab / Unsubscribe"
msgstr ""
-msgid "GitLab Enterprise Edition %{plan}"
+msgid "GitLab API"
+msgstr ""
+
+msgid "GitLab Billing Team."
msgstr ""
msgid "GitLab Group Runners can execute code for all the projects in this group."
@@ -11628,12 +11983,18 @@ msgstr ""
msgid "GitLab Issue"
msgstr ""
+msgid "GitLab Pages"
+msgstr ""
+
msgid "GitLab Service Desk is a simple way to allow people to create issues in your GitLab instance without needing their own user account. It provides a unique email address for end users to create issues in a project, and replies can be sent either through the GitLab interface or by email. End users will only see the thread through email."
msgstr ""
msgid "GitLab Shared Runners execute code of different projects on the same Runner unless you configure GitLab Runner Autoscale with MaxBuilds 1 (which it is on GitLab.com)."
msgstr ""
+msgid "GitLab Shell"
+msgstr ""
+
msgid "GitLab Support Bot"
msgstr ""
@@ -11643,7 +12004,7 @@ msgstr ""
msgid "GitLab User"
msgstr ""
-msgid "GitLab allows you to continue using your license even if you exceed the number of seats you purchased. You will be required to pay for these seats when you renew your license."
+msgid "GitLab Workhorse"
msgstr ""
msgid "GitLab commit"
@@ -11811,6 +12172,21 @@ msgstr ""
msgid "Gitlab Pages"
msgstr ""
+msgid "Gitpod"
+msgstr ""
+
+msgid "Gitpod|Add the URL to your Gitpod instance configured to read your GitLab projects."
+msgstr ""
+
+msgid "Gitpod|Enable Gitpod integration"
+msgstr ""
+
+msgid "Gitpod|Gitpod URL"
+msgstr ""
+
+msgid "Gitpod|e.g. https://gitpod.example.com"
+msgstr ""
+
msgid "Given access %{time_ago}"
msgstr ""
@@ -12318,9 +12694,6 @@ msgstr ""
msgid "GroupSAML|Valid SAML Response"
msgstr ""
-msgid "GroupSAML|With group managed accounts enabled, all the users without a group managed account will be excluded from the group."
-msgstr ""
-
msgid "GroupSAML|With prohibit outer forks flag enabled group members will be able to fork project only inside your group."
msgstr ""
@@ -12534,10 +12907,10 @@ msgstr ""
msgid "GroupsNew|Create group"
msgstr ""
-msgid "GroupsNew|GitLab group export"
+msgid "GroupsNew|Import"
msgstr ""
-msgid "GroupsNew|Import"
+msgid "GroupsNew|Import a GitLab group export file"
msgstr ""
msgid "GroupsNew|Import group"
@@ -12680,6 +13053,9 @@ msgid_plural "Hide charts"
msgstr[0] ""
msgstr[1] ""
+msgid "Hide comments on this file"
+msgstr ""
+
msgid "Hide details"
msgstr ""
@@ -12724,6 +13100,15 @@ msgstr ""
msgid "Highest role:"
msgstr ""
+msgid "HighlightBar|Alert events:"
+msgstr ""
+
+msgid "HighlightBar|Alert start time:"
+msgstr ""
+
+msgid "HighlightBar|Original alert:"
+msgstr ""
+
msgid "History"
msgstr ""
@@ -12901,6 +13286,9 @@ msgstr ""
msgid "If enabled, access to projects will be validated on an external service using their classification label."
msgstr ""
+msgid "If the number of active users exceeds the user limit, you will be charged for the number of %{users_over_license_link} at your next license reconciliation."
+msgstr ""
+
msgid "If there is no previous license or if the previous license has expired, some GitLab functionality will be blocked until a new, valid license is uploaded."
msgstr ""
@@ -12940,9 +13328,6 @@ msgstr ""
msgid "If your HTTP repository is not publicly accessible, add your credentials."
msgstr ""
-msgid "Iglu registry URL (optional)"
-msgstr ""
-
msgid "Ignore"
msgstr ""
@@ -12979,6 +13364,16 @@ msgstr ""
msgid "Import"
msgstr ""
+msgid "Import %d compatible repository"
+msgid_plural "Import %d compatible repositories"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Import %d repository"
+msgid_plural "Import %d repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Import CSV"
msgstr ""
@@ -12988,15 +13383,9 @@ msgstr ""
msgid "Import all compatible projects"
msgstr ""
-msgid "Import all compatible repositories"
-msgstr ""
-
msgid "Import all projects"
msgstr ""
-msgid "Import all repositories"
-msgstr ""
-
msgid "Import an exported GitLab project"
msgstr ""
@@ -13084,6 +13473,9 @@ msgstr ""
msgid "ImportProjects|Error importing repository %{project_safe_import_url} into %{project_full_path} - %{message}"
msgstr ""
+msgid "ImportProjects|Import repositories"
+msgstr ""
+
msgid "ImportProjects|Importing the project failed"
msgstr ""
@@ -13096,7 +13488,7 @@ msgstr ""
msgid "ImportProjects|Requesting your %{provider} repositories failed"
msgstr ""
-msgid "ImportProjects|Select the projects you want to import"
+msgid "ImportProjects|Select the repositories you want to import"
msgstr ""
msgid "ImportProjects|The remote data could not be imported."
@@ -13132,9 +13524,6 @@ msgstr ""
msgid "In order to enable Service Desk for your instance, you must first set up incoming email."
msgstr ""
-msgid "In order to gather accurate feature usage data, it can take 1 to 2 weeks to see your index."
-msgstr ""
-
msgid "In order to personalize your experience with GitLab%{br_tag}we would like to know a bit more about you."
msgstr ""
@@ -13165,18 +13554,30 @@ msgstr ""
msgid "IncidentManagement|Create incident"
msgstr ""
+msgid "IncidentManagement|Critical - S1"
+msgstr ""
+
msgid "IncidentManagement|Date created"
msgstr ""
msgid "IncidentManagement|Display your incidents in a dedicated view"
msgstr ""
+msgid "IncidentManagement|High - S2"
+msgstr ""
+
msgid "IncidentManagement|Incident"
msgstr ""
msgid "IncidentManagement|Incidents"
msgstr ""
+msgid "IncidentManagement|Low - S4"
+msgstr ""
+
+msgid "IncidentManagement|Medium - S3"
+msgstr ""
+
msgid "IncidentManagement|No incidents to display."
msgstr ""
@@ -13189,6 +13590,9 @@ msgstr ""
msgid "IncidentManagement|Published to status page"
msgstr ""
+msgid "IncidentManagement|Severity"
+msgstr ""
+
msgid "IncidentManagement|There are no closed incidents"
msgstr ""
@@ -13198,6 +13602,9 @@ msgstr ""
msgid "IncidentManagement|Unassigned"
msgstr ""
+msgid "IncidentManagement|Unknown"
+msgstr ""
+
msgid "IncidentManagement|Unpublished"
msgstr ""
@@ -13219,6 +13626,15 @@ msgstr ""
msgid "Incidents"
msgstr ""
+msgid "Incident|Alert details"
+msgstr ""
+
+msgid "Incident|Summary"
+msgstr ""
+
+msgid "Incident|There was an issue loading alert data. Please try again."
+msgstr ""
+
msgid "Include a Terms of Service agreement and Privacy Policy that all users must accept."
msgstr ""
@@ -13279,6 +13695,9 @@ msgstr ""
msgid "Information about additional Pages templates and how to install them can be found in our %{pages_getting_started_guide}."
msgstr ""
+msgid "Inherited"
+msgstr ""
+
msgid "Inherited:"
msgstr ""
@@ -13359,7 +13778,22 @@ msgstr ""
msgid "Instance administrators group already exists"
msgstr ""
-msgid "Instance license"
+msgid "InstanceStatistics|Groups"
+msgstr ""
+
+msgid "InstanceStatistics|Issues"
+msgstr ""
+
+msgid "InstanceStatistics|Merge Requests"
+msgstr ""
+
+msgid "InstanceStatistics|Pipelines"
+msgstr ""
+
+msgid "InstanceStatistics|Projects"
+msgstr ""
+
+msgid "InstanceStatistics|Users"
msgstr ""
msgid "Integration"
@@ -13371,6 +13805,12 @@ msgstr ""
msgid "Integrations"
msgstr ""
+msgid "Integrations|%{integration} settings saved and active."
+msgstr ""
+
+msgid "Integrations|%{integration} settings saved, but not active."
+msgstr ""
+
msgid "Integrations|All details"
msgstr ""
@@ -13380,6 +13820,12 @@ msgstr ""
msgid "Integrations|Comment settings:"
msgstr ""
+msgid "Integrations|Connection failed. Please check your settings."
+msgstr ""
+
+msgid "Integrations|Connection successful."
+msgstr ""
+
msgid "Integrations|Default settings are inherited from the group level."
msgstr ""
@@ -13395,6 +13841,15 @@ msgstr ""
msgid "Integrations|Includes commit title and branch"
msgstr ""
+msgid "Integrations|Projects using custom settings will not be impacted unless the project owner chooses to use instance-level defaults."
+msgstr ""
+
+msgid "Integrations|Save settings?"
+msgstr ""
+
+msgid "Integrations|Saving will update the default settings for all projects that are not using custom settings."
+msgstr ""
+
msgid "Integrations|Standard"
msgstr ""
@@ -13527,6 +13982,9 @@ msgstr ""
msgid "Invitation"
msgstr ""
+msgid "Invitation declined"
+msgstr ""
+
msgid "Invite"
msgstr ""
@@ -13578,6 +14036,42 @@ 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|%{linkStart}Read more%{linkEnd} about role permissions"
+msgstr ""
+
+msgid "InviteMembersModal|Access expiration date (optional)"
+msgstr ""
+
+msgid "InviteMembersModal|Cancel"
+msgstr ""
+
+msgid "InviteMembersModal|Choose a role permission"
+msgstr ""
+
+msgid "InviteMembersModal|GitLab member or Email address"
+msgstr ""
+
+msgid "InviteMembersModal|Invite"
+msgstr ""
+
+msgid "InviteMembersModal|Invite team members"
+msgstr ""
+
+msgid "InviteMembersModal|Search for members to invite"
+msgstr ""
+
+msgid "InviteMembersModal|User not invited. Feature coming soon!"
+msgstr ""
+
+msgid "InviteMembersModal|Users were succesfully added"
+msgstr ""
+
+msgid "InviteMembersModal|You're inviting members to the %{group_name} group"
+msgstr ""
+
+msgid "InviteMembers|Invite team members"
+msgstr ""
+
msgid "Invited"
msgstr ""
@@ -13632,10 +14126,13 @@ msgstr ""
msgid "Issue cannot be found."
msgstr ""
+msgid "Issue created from vulnerability %{vulnerability_link}"
+msgstr ""
+
msgid "Issue events"
msgstr ""
-msgid "Issue first depoloyed to production"
+msgid "Issue first deployed to production"
msgstr ""
msgid "Issue label"
@@ -13713,6 +14210,9 @@ msgstr ""
msgid "IssueTracker|Custom issue tracker"
msgstr ""
+msgid "IssueTracker|EWM work items tracker"
+msgstr ""
+
msgid "IssueTracker|Redmine issue tracker"
msgstr ""
@@ -13779,6 +14279,9 @@ msgstr ""
msgid "It looks like you have some draft commits in this branch."
msgstr ""
+msgid "It may be several days before you see feature usage data."
+msgstr ""
+
msgid "It must have a header row and at least two columns: the first column is the issue title and the second column is the issue description. The separator is automatically detected."
msgstr ""
@@ -14061,13 +14564,13 @@ msgstr ""
msgid "Join Zoom meeting"
msgstr ""
-msgid "Jul"
+msgid "Joined %{time_ago}"
msgstr ""
-msgid "July"
+msgid "Jul"
msgstr ""
-msgid "Jump to first unresolved thread"
+msgid "July"
msgstr ""
msgid "Jump to next unresolved thread"
@@ -14103,6 +14606,9 @@ msgstr ""
msgid "Keyboard shortcuts"
msgstr ""
+msgid "KeyboardKey|Ctrl+"
+msgstr ""
+
msgid "Keys"
msgstr ""
@@ -14151,6 +14657,9 @@ msgstr ""
msgid "LDAP Synchronization"
msgstr ""
+msgid "LDAP group settings"
+msgstr ""
+
msgid "LDAP settings"
msgstr ""
@@ -14160,6 +14669,9 @@ msgstr ""
msgid "LDAP sync in progress. This could take a few minutes. Refresh the page to see the changes."
msgstr ""
+msgid "LDAP synchronizations"
+msgstr ""
+
msgid "LFS"
msgstr ""
@@ -14240,7 +14752,16 @@ msgid_plural "Last %d days"
msgstr[0] ""
msgstr[1] ""
-msgid "Last %{days} days"
+msgid "Last 2 weeks"
+msgstr ""
+
+msgid "Last 30 days"
+msgstr ""
+
+msgid "Last 60 days"
+msgstr ""
+
+msgid "Last 90 days"
msgstr ""
msgid "Last Accessed On"
@@ -14318,6 +14839,9 @@ msgstr ""
msgid "Last used on:"
msgstr ""
+msgid "Last week"
+msgstr ""
+
msgid "LastCommit|authored"
msgstr ""
@@ -14333,6 +14857,9 @@ msgstr ""
msgid "Latest pipeline for the most recent commit on this branch"
msgstr ""
+msgid "Launch a ready-to-code development environment for your project."
+msgstr ""
+
msgid "Lead"
msgstr ""
@@ -14713,6 +15240,9 @@ msgstr ""
msgid "List of all merge commits"
msgstr ""
+msgid "List options"
+msgstr ""
+
msgid "List settings"
msgstr ""
@@ -14725,9 +15255,6 @@ msgstr ""
msgid "List your Bitbucket Server repositories"
msgstr ""
-msgid "Lists"
-msgstr ""
-
msgid "Live preview"
msgstr ""
@@ -14974,6 +15501,12 @@ msgstr ""
msgid "Mark as done"
msgstr ""
+msgid "Mark as draft"
+msgstr ""
+
+msgid "Mark as ready"
+msgstr ""
+
msgid "Mark as resolved"
msgstr ""
@@ -14995,6 +15528,24 @@ msgstr ""
msgid "Markdown is supported"
msgstr ""
+msgid "MarkdownEditor|Add a link (%{modifierKey}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add a link (%{modifier_key}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifierKey}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifier_key}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifierKey}I)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifier_key}I)"
+msgstr ""
+
msgid "Marked For Deletion At - %{deletion_time}"
msgstr ""
@@ -15079,7 +15630,25 @@ msgstr ""
msgid "Max access level"
msgstr ""
-msgid "Max seats used"
+msgid "Max role"
+msgstr ""
+
+msgid "Max size 15 MB"
+msgstr ""
+
+msgid "Maximum Conan package file size in bytes"
+msgstr ""
+
+msgid "Maximum Maven package file size in bytes"
+msgstr ""
+
+msgid "Maximum NPM package file size in bytes"
+msgstr ""
+
+msgid "Maximum NuGet package file size in bytes"
+msgstr ""
+
+msgid "Maximum PyPI package file size in bytes"
msgstr ""
msgid "Maximum Users:"
@@ -15211,6 +15780,18 @@ msgstr ""
msgid "Members with access to %{strong_start}%{group_name}%{strong_end}"
msgstr ""
+msgid "Members|%{time} by %{user}"
+msgstr ""
+
+msgid "Members|Expired"
+msgstr ""
+
+msgid "Members|No expiration set"
+msgstr ""
+
+msgid "Members|in %{time}"
+msgstr ""
+
msgid "Memory Usage"
msgstr ""
@@ -15397,9 +15978,6 @@ msgstr ""
msgid "MergeRequests|Thread will be unresolved"
msgstr ""
-msgid "MergeRequests|Toggle comments for this file"
-msgstr ""
-
msgid "MergeRequests|View file @ %{commitId}"
msgstr ""
@@ -15460,6 +16038,9 @@ msgstr ""
msgid "Merging immediately isn't recommended as it may negatively impact the existing merge train. Read the %{docsLinkStart}documentation%{docsLinkEnd} for more information."
msgstr ""
+msgid "Message"
+msgstr ""
+
msgid "Messages"
msgstr ""
@@ -15845,18 +16426,12 @@ msgid_plural "Milestones"
msgstr[0] ""
msgstr[1] ""
-msgid "Milestone does not support burnup charts"
-msgstr ""
-
msgid "Milestone lists not available with your current license"
msgstr ""
msgid "Milestone lists show all issues from the selected milestone."
msgstr ""
-msgid "Milestone must have a start and due date"
-msgstr ""
-
msgid "MilestoneSidebar|Closed:"
msgstr ""
@@ -16223,6 +16798,9 @@ msgstr ""
msgid "Namespace"
msgstr ""
+msgid "Namespace ID:"
+msgstr ""
+
msgid "Namespace is empty"
msgstr ""
@@ -16307,6 +16885,9 @@ msgstr ""
msgid "NetworkPolicies|Allow all outbound traffic from %{selector} to %{ruleSelector} on %{ports}"
msgstr ""
+msgid "NetworkPolicies|Are you sure you want to delete this policy? This action cannot be undone."
+msgstr ""
+
msgid "NetworkPolicies|Choose whether to enforce this policy."
msgstr ""
@@ -16316,12 +16897,21 @@ msgstr ""
msgid "NetworkPolicies|Define this policy's location, conditions and actions."
msgstr ""
+msgid "NetworkPolicies|Delete policy"
+msgstr ""
+
+msgid "NetworkPolicies|Delete policy: %{policy}"
+msgstr ""
+
msgid "NetworkPolicies|Deny all traffic"
msgstr ""
msgid "NetworkPolicies|Description"
msgstr ""
+msgid "NetworkPolicies|Edit policy"
+msgstr ""
+
msgid "NetworkPolicies|Editor mode"
msgstr ""
@@ -16349,6 +16939,9 @@ msgstr ""
msgid "NetworkPolicies|Name"
msgstr ""
+msgid "NetworkPolicies|Namespace"
+msgstr ""
+
msgid "NetworkPolicies|Network Policy"
msgstr ""
@@ -16400,6 +16993,9 @@ msgstr ""
msgid "NetworkPolicies|Rules"
msgstr ""
+msgid "NetworkPolicies|Save changes"
+msgstr ""
+
msgid "NetworkPolicies|Something went wrong, failed to update policy"
msgstr ""
@@ -16412,6 +17008,9 @@ msgstr ""
msgid "NetworkPolicies|Traffic that does not match any rule will be blocked."
msgstr ""
+msgid "NetworkPolicies|Unable to parse policy"
+msgstr ""
+
msgid "NetworkPolicies|YAML editor"
msgstr ""
@@ -16525,6 +17124,9 @@ msgstr ""
msgid "New Snippet"
msgstr ""
+msgid "New Test Case"
+msgstr ""
+
msgid "New User"
msgstr ""
@@ -16624,6 +17226,9 @@ msgstr ""
msgid "New tag"
msgstr ""
+msgid "New test case"
+msgstr ""
+
msgid "New users set to external"
msgstr ""
@@ -16696,7 +17301,7 @@ msgstr ""
msgid "No changes"
msgstr ""
-msgid "No changes between %{ref_start}%{source_branch}%{ref_end} and %{ref_start}%{target_branch}%{ref_end}"
+msgid "No changes between %{sourceBranch} and %{targetBranch}"
msgstr ""
msgid "No child epics match applied filters"
@@ -16711,6 +17316,9 @@ msgstr ""
msgid "No containers available"
msgstr ""
+msgid "No content to show"
+msgstr ""
+
msgid "No contributions"
msgstr ""
@@ -16786,9 +17394,6 @@ msgstr ""
msgid "No license. All rights reserved"
msgstr ""
-msgid "No licenses found."
-msgstr ""
-
msgid "No matches found"
msgstr ""
@@ -16801,6 +17406,9 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No members found"
+msgstr ""
+
msgid "No merge requests found"
msgstr ""
@@ -16822,6 +17430,9 @@ msgstr ""
msgid "No parent group"
msgstr ""
+msgid "No plan"
+msgstr ""
+
msgid "No pods available"
msgstr ""
@@ -16918,6 +17529,12 @@ msgstr ""
msgid "Not Implemented"
msgstr ""
+msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+msgstr ""
+
+msgid "Not all browsers support WebAuthn. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even from an unsupported browser."
+msgstr ""
+
msgid "Not all data has been processed yet, the accuracy of the chart for the selected timeframe is limited."
msgstr ""
@@ -17014,6 +17631,9 @@ msgstr ""
msgid "Notification settings saved"
msgstr ""
+msgid "NotificationEvent|Change reviewer merge request"
+msgstr ""
+
msgid "NotificationEvent|Close issue"
msgstr ""
@@ -17176,10 +17796,7 @@ msgstr ""
msgid "On track"
msgstr ""
-msgid "OnDemandScans|Attached branch"
-msgstr ""
-
-msgid "OnDemandScans|Attached branch is where the scan job runs."
+msgid "OnDemandScans|Could not fetch scanner profiles. Please refresh the page, or try again later."
msgstr ""
msgid "OnDemandScans|Could not fetch site profiles. Please refresh the page, or try again later."
@@ -17188,6 +17805,9 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
+msgid "OnDemandScans|Create a new scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Create a new site profile"
msgstr ""
@@ -17200,6 +17820,9 @@ msgstr ""
msgid "OnDemandScans|New on-demand DAST scan"
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 ""
@@ -17209,16 +17832,10 @@ msgstr ""
msgid "OnDemandScans|On-demand scans run outside the DevOps cycle and find vulnerabilities in your projects. %{learnMoreLinkStart}Learn more%{learnMoreLinkEnd}"
msgstr ""
-msgid "OnDemandScans|Only a passive scan can be performed on demand."
-msgstr ""
-
-msgid "OnDemandScans|Passive"
-msgstr ""
-
msgid "OnDemandScans|Run scan"
msgstr ""
-msgid "OnDemandScans|Scan mode"
+msgid "OnDemandScans|Scanner profile"
msgstr ""
msgid "OnDemandScans|Scanner settings"
@@ -17230,9 +17847,15 @@ msgstr ""
msgid "OnDemandScans|Select one of the existing profiles"
msgstr ""
+msgid "OnDemandScans|Site profile"
+msgstr ""
+
msgid "OnDemandScans|Site profiles"
msgstr ""
+msgid "OnDemandScans|Use existing scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Use existing site profile"
msgstr ""
@@ -17331,9 +17954,6 @@ msgstr ""
msgid "Open Selection"
msgstr ""
-msgid "Open Web IDE"
-msgstr ""
-
msgid "Open comment type dropdown"
msgstr ""
@@ -17439,6 +18059,9 @@ msgstr ""
msgid "Origin"
msgstr ""
+msgid "Orphaned member"
+msgstr ""
+
msgid "Other Labels"
msgstr ""
@@ -17454,6 +18077,9 @@ msgstr ""
msgid "Other visibility settings have been disabled by the administrator."
msgstr ""
+msgid "Our documentation includes an example DevOps Score report."
+msgstr ""
+
msgid "Out-of-compliance with this project's policies and should be removed"
msgstr ""
@@ -17478,6 +18104,9 @@ msgstr ""
msgid "Overwrite diverged branches"
msgstr ""
+msgid "Owned by %{image_tag}"
+msgstr ""
+
msgid "Owned by anyone"
msgstr ""
@@ -17499,6 +18128,9 @@ msgstr ""
msgid "Package deleted successfully"
msgstr ""
+msgid "Package file size limits"
+msgstr ""
+
msgid "Package recipe already exists"
msgstr ""
@@ -17514,9 +18146,6 @@ msgstr ""
msgid "Package type must be PyPi"
msgstr ""
-msgid "Package was removed"
-msgstr ""
-
msgid "PackageRegistry|%{name} version %{version} was created %{datetime}"
msgstr ""
@@ -17658,12 +18287,18 @@ msgstr ""
msgid "PackageRegistry|NuGet Command"
msgstr ""
+msgid "PackageRegistry|Package Registry"
+msgstr ""
+
msgid "PackageRegistry|Pip Command"
msgstr ""
msgid "PackageRegistry|Pipeline %{link} triggered %{datetime} by %{author}"
msgstr ""
+msgid "PackageRegistry|Publish and share packages for a variety of common package managers. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "PackageRegistry|Published to the %{project} Package Registry %{datetime}"
msgstr ""
@@ -17763,6 +18398,9 @@ msgstr ""
msgid "Page not found"
msgstr ""
+msgid "Page settings"
+msgstr ""
+
msgid "Page was successfully deleted"
msgstr ""
@@ -17904,7 +18542,7 @@ msgstr ""
msgid "Paste issue link"
msgstr ""
-msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Don't use your private SSH key."
+msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Do not paste your private SSH key, as that can compromise your identity."
msgstr ""
msgid "Patch to apply"
@@ -17931,6 +18569,9 @@ msgstr ""
msgid "Pending"
msgstr ""
+msgid "Pending comments"
+msgstr ""
+
msgid "People without permission will never get a notification and won't be able to comment."
msgstr ""
@@ -18129,6 +18770,9 @@ msgstr ""
msgid "Pipelines|Build with confidence"
msgstr ""
+msgid "Pipelines|By revoking a trigger you will break any processes making use of it. Are you sure?"
+msgstr ""
+
msgid "Pipelines|CI Lint"
msgstr ""
@@ -18141,6 +18785,15 @@ msgstr ""
msgid "Pipelines|Continuous Integration can help catch bugs by running your tests automatically, while Continuous Deployment can help you deliver code to your product environment."
msgstr ""
+msgid "Pipelines|Copy trigger token"
+msgstr ""
+
+msgid "Pipelines|Description"
+msgstr ""
+
+msgid "Pipelines|Edit"
+msgstr ""
+
msgid "Pipelines|Get started with Pipelines"
msgstr ""
@@ -18156,15 +18809,27 @@ msgstr ""
msgid "Pipelines|It is recommended the code is reviewed thoroughly before running this pipeline with the parent project's CI resource."
msgstr ""
+msgid "Pipelines|Last Used"
+msgstr ""
+
msgid "Pipelines|Loading Pipelines"
msgstr ""
msgid "Pipelines|More Information"
msgstr ""
+msgid "Pipelines|No triggers have been created yet. Add one using the form above."
+msgstr ""
+
+msgid "Pipelines|Owner"
+msgstr ""
+
msgid "Pipelines|Project cache successfully reset."
msgstr ""
+msgid "Pipelines|Revoke"
+msgstr ""
+
msgid "Pipelines|Run Pipeline"
msgstr ""
@@ -18189,6 +18854,15 @@ msgstr ""
msgid "Pipelines|This project is not currently set up to run pipelines."
msgstr ""
+msgid "Pipelines|Token"
+msgstr ""
+
+msgid "Pipelines|Trigger user has insufficient permissions to project"
+msgstr ""
+
+msgid "Pipelines|invalid"
+msgstr ""
+
msgid "Pipelines|parent"
msgstr ""
@@ -18447,10 +19121,10 @@ msgstr ""
msgid "Please provide attributes to update"
msgstr ""
-msgid "Please refer to %{docs_url}"
+msgid "Please reach out if you have any questions and we'll be happy to assist."
msgstr ""
-msgid "Please retype the email address."
+msgid "Please refer to %{docs_url}"
msgstr ""
msgid "Please select"
@@ -18480,6 +19154,9 @@ msgstr ""
msgid "Please set a new password before proceeding."
msgstr ""
+msgid "Please share your feedback about %{featureName} %{linkStart}in this issue%{linkEnd} to help us improve the experience."
+msgstr ""
+
msgid "Please solve the reCAPTCHA"
msgstr ""
@@ -18783,6 +19460,9 @@ msgstr ""
msgid "Profiles| You are going to change the username %{currentUsernameBold} to %{newUsernameBold}. Profile and projects will be redirected to the %{newUsername} namespace but this redirect will expire once the %{currentUsername} namespace is registered by another user or group. Please update your Git repository remotes as soon as possible."
msgstr ""
+msgid "Profiles|%{provider} Active"
+msgstr ""
+
msgid "Profiles|@username"
msgstr ""
@@ -18834,7 +19514,7 @@ msgstr ""
msgid "Profiles|Commit email"
msgstr ""
-msgid "Profiles|Connect"
+msgid "Profiles|Connect %{provider}"
msgstr ""
msgid "Profiles|Connected Accounts"
@@ -18858,6 +19538,9 @@ msgstr ""
msgid "Profiles|Disconnect"
msgstr ""
+msgid "Profiles|Disconnect %{provider}"
+msgstr ""
+
msgid "Profiles|Do not show on profile"
msgstr ""
@@ -18882,7 +19565,7 @@ msgstr ""
msgid "Profiles|Full name"
msgstr ""
-msgid "Profiles|Give your individual key a title. This will be publically visible."
+msgid "Profiles|Give your individual key a title."
msgstr ""
msgid "Profiles|Include private contributions on my profile"
@@ -18972,7 +19655,7 @@ msgstr ""
msgid "Profiles|The maximum file size allowed is 200KB."
msgstr ""
-msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it?"
+msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it? It will be publicly visible."
msgstr ""
msgid "Profiles|This email will be displayed on your public profile"
@@ -19047,6 +19730,9 @@ msgstr ""
msgid "Profiles|You don't have access to delete this user."
msgstr ""
+msgid "Profiles|You must transfer ownership or delete groups you are an owner of before you can delete your account"
+msgstr ""
+
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
@@ -19635,6 +20321,9 @@ msgstr ""
msgid "ProjectTemplates|GitLab Cluster Management"
msgstr ""
+msgid "ProjectTemplates|Gitpod/Spring Petclinic"
+msgstr ""
+
msgid "ProjectTemplates|Go Micro"
msgstr ""
@@ -20244,6 +20933,9 @@ msgstr ""
msgid "Publish to status page"
msgstr ""
+msgid "Published"
+msgstr ""
+
msgid "Published on status page"
msgstr ""
@@ -20361,9 +21053,15 @@ msgstr ""
msgid "Quick range"
msgstr ""
+msgid "Quickly and easily edit multiple files in your project."
+msgstr ""
+
msgid "README"
msgstr ""
+msgid "Rails"
+msgstr ""
+
msgid "Rake Tasks Help"
msgstr ""
@@ -20483,10 +21181,13 @@ msgstr ""
msgid "Register Two-Factor Authenticator"
msgstr ""
-msgid "Register U2F device"
+msgid "Register Universal Two-Factor (U2F) Device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register WebAuthn Device"
+msgstr ""
+
+msgid "Register device"
msgstr ""
msgid "Register for GitLab"
@@ -20498,9 +21199,6 @@ msgstr ""
msgid "Register with two-factor app"
msgstr ""
-msgid "Registration"
-msgstr ""
-
msgid "Registration|Checkout"
msgstr ""
@@ -20617,9 +21315,6 @@ msgstr ""
msgid "Release|Something went wrong while saving the release details"
msgstr ""
-msgid "Remediated: needs review"
-msgstr ""
-
msgid "Remediations"
msgstr ""
@@ -20725,6 +21420,9 @@ msgstr ""
msgid "Remove priority"
msgstr ""
+msgid "Remove report"
+msgstr ""
+
msgid "Remove secondary node"
msgstr ""
@@ -20737,6 +21435,12 @@ msgstr ""
msgid "Remove time estimate"
msgstr ""
+msgid "Remove user & report"
+msgstr ""
+
+msgid "Remove user from group"
+msgstr ""
+
msgid "Removed"
msgstr ""
@@ -20818,9 +21522,6 @@ msgstr ""
msgid "Removes time estimate."
msgstr ""
-msgid "Removing license…"
-msgstr ""
-
msgid "Removing this group also removes all child projects, including archived projects, and their resources."
msgstr ""
@@ -20905,6 +21606,9 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
+msgid "Reported by %{reporter}"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -20991,6 +21695,27 @@ msgstr ""
msgid "Repositories"
msgstr ""
+msgid "Repositories Analytics"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download Historic Test Coverage Data"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download historic test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Historic Test Coverage Data is available in raw format (.csv) for further analysis."
+msgstr ""
+
+msgid "RepositoriesAnalytics|Test Code Coverage"
+msgstr ""
+
+msgid "RepositoriesAnalytics|There was an error fetching the projects."
+msgstr ""
+
msgid "Repository"
msgstr ""
@@ -21069,9 +21794,15 @@ msgstr ""
msgid "Request parameter %{param} is missing."
msgstr ""
+msgid "Request review from"
+msgstr ""
+
msgid "Request to link SAML account must be authorized"
msgstr ""
+msgid "Requested"
+msgstr ""
+
msgid "Requested %{time_ago}"
msgstr ""
@@ -21090,6 +21821,9 @@ msgstr ""
msgid "Requests to these domain(s)/address(es) on the local network will be allowed when local requests from hooks and services are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 or 127.0.0.0/28 are supported. Domain wildcards are not supported currently. Use comma, semicolon, or newline to separate multiple entries. The allowlist can hold a maximum of 1000 entries. Domains should use IDNA encoding. Ex: example.com, 192.168.1.1, 127.0.0.0/28, xn--itlab-j1a.com."
msgstr ""
+msgid "Require admin approval for new sign-ups"
+msgstr ""
+
msgid "Require all users in this group to setup Two-factor authentication"
msgstr ""
@@ -21217,9 +21951,6 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
-msgid "Resolved by %{resolvedByName}"
-msgstr ""
-
msgid "Resolves IP addresses once and uses them to submit requests"
msgstr ""
@@ -21339,6 +22070,14 @@ msgstr ""
msgid "ReviewApp|Enable Review App"
msgstr ""
+msgid "Reviewer"
+msgid_plural "%d Reviewers"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Reviewer(s)"
+msgstr ""
+
msgid "Reviewing"
msgstr ""
@@ -21378,6 +22117,9 @@ msgstr ""
msgid "Rook"
msgstr ""
+msgid "Ruby"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -21456,6 +22198,63 @@ msgstr ""
msgid "Runners page."
msgstr ""
+msgid "Runners|Active"
+msgstr ""
+
+msgid "Runners|Architecture"
+msgstr ""
+
+msgid "Runners|Can run untagged jobs"
+msgstr ""
+
+msgid "Runners|Description"
+msgstr ""
+
+msgid "Runners|Group"
+msgstr ""
+
+msgid "Runners|IP Address"
+msgstr ""
+
+msgid "Runners|Last contact"
+msgstr ""
+
+msgid "Runners|Locked to this project"
+msgstr ""
+
+msgid "Runners|Maximum job timeout"
+msgstr ""
+
+msgid "Runners|Name"
+msgstr ""
+
+msgid "Runners|Platform"
+msgstr ""
+
+msgid "Runners|Property Name"
+msgstr ""
+
+msgid "Runners|Protected"
+msgstr ""
+
+msgid "Runners|Revision"
+msgstr ""
+
+msgid "Runners|Shared"
+msgstr ""
+
+msgid "Runners|Specific"
+msgstr ""
+
+msgid "Runners|Tags"
+msgstr ""
+
+msgid "Runners|Value"
+msgstr ""
+
+msgid "Runners|Version"
+msgstr ""
+
msgid "Runners|You have used %{quotaUsed} out of %{quotaLimit} of your shared Runners pipeline minutes."
msgstr ""
@@ -21468,6 +22267,9 @@ msgstr ""
msgid "Runs a number of housekeeping tasks within the current repository, such as compressing file revisions and removing unreachable objects."
msgstr ""
+msgid "SAML"
+msgstr ""
+
msgid "SAML SSO"
msgstr ""
@@ -21519,6 +22321,9 @@ msgstr ""
msgid "Save"
msgstr ""
+msgid "Save %{name} size limits"
+msgstr ""
+
msgid "Save Changes"
msgstr ""
@@ -21549,9 +22354,6 @@ msgstr ""
msgid "Save space and find tags in the Container Registry more easily. Enable the cleanup policy to remove stale tags and keep only the ones you need."
msgstr ""
-msgid "Save template"
-msgstr ""
-
msgid "Save variables"
msgstr ""
@@ -21594,9 +22396,6 @@ msgstr ""
msgid "Scope"
msgstr ""
-msgid "Scope not supported with disabled 'users_search' feature!"
-msgstr ""
-
msgid "Scoped issue boards"
msgstr ""
@@ -21723,9 +22522,6 @@ msgstr ""
msgid "Search requirements"
msgstr ""
-msgid "Search results…"
-msgstr ""
-
msgid "Search users"
msgstr ""
@@ -21798,6 +22594,11 @@ msgid_plural "SearchResults|commits"
msgstr[0] ""
msgstr[1] ""
+msgid "SearchResults|epic"
+msgid_plural "SearchResults|epics"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "SearchResults|issue"
msgid_plural "SearchResults|issues"
msgstr[0] ""
@@ -21842,10 +22643,10 @@ msgstr ""
msgid "Seat Link is disabled, and cannot be configured through this form."
msgstr ""
-msgid "Seats currently in use"
+msgid "Seats usage data as of %{last_enqueue_time}"
msgstr ""
-msgid "Seats in license"
+msgid "Seats usage data is updated every day at 12:00pm UTC"
msgstr ""
msgid "Secondary"
@@ -21899,6 +22700,9 @@ msgstr ""
msgid "SecurityConfiguration|Available for on-demand DAST"
msgstr ""
+msgid "SecurityConfiguration|By default, all analyzers are applied in order to cover all languages across your project, and only run if the language is detected in the Merge Request."
+msgstr ""
+
msgid "SecurityConfiguration|Configure"
msgstr ""
@@ -21929,16 +22733,19 @@ msgstr ""
msgid "SecurityConfiguration|Manage"
msgstr ""
+msgid "SecurityConfiguration|More information"
+msgstr ""
+
msgid "SecurityConfiguration|Not enabled"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|Security Control"
+msgid "SecurityConfiguration|SAST Configuration"
msgstr ""
-msgid "SecurityConfiguration|See documentation"
+msgid "SecurityConfiguration|Security Control"
msgstr ""
msgid "SecurityConfiguration|Status"
@@ -21950,6 +22757,9 @@ msgstr ""
msgid "SecurityConfiguration|Using custom settings. You won't receive automatic updates on this variable. %{anchorStart}Restore to default%{anchorEnd}"
msgstr ""
+msgid "SecurityConfiguration|View history"
+msgstr ""
+
msgid "SecurityConfiguration|You can quickly enable all security scanning tools by enabling %{linkStart}Auto DevOps%{linkEnd}."
msgstr ""
@@ -22028,9 +22838,6 @@ msgstr ""
msgid "SecurityReports|Learn more about setting up your dashboard"
msgstr ""
-msgid "SecurityReports|Load more vulnerabilities"
-msgstr ""
-
msgid "SecurityReports|Monitor vulnerabilities in your code"
msgstr ""
@@ -22310,7 +23117,7 @@ msgstr ""
msgid "Select status"
msgstr ""
-msgid "Select strategy activation method"
+msgid "Select strategy activation method."
msgstr ""
msgid "Select subscription"
@@ -22325,7 +23132,7 @@ msgstr ""
msgid "Select the custom project template source group."
msgstr ""
-msgid "Select timeframe"
+msgid "Select the environment scope for this feature flag."
msgstr ""
msgid "Select timezone"
@@ -22574,6 +23381,9 @@ msgstr ""
msgid "Set iteration"
msgstr ""
+msgid "Set limit to 0 to allow any file size."
+msgstr ""
+
msgid "Set max session time for web terminal."
msgstr ""
@@ -22652,10 +23462,13 @@ msgstr ""
msgid "Set up a %{type} Runner manually"
msgstr ""
+msgid "Set up a hardware device as a second factor to sign in."
+msgstr ""
+
msgid "Set up assertions/attributes/claims (email, first_name, last_name) and NameID according to %{docsLinkStart}the documentation %{icon}%{docsLinkEnd}"
msgstr ""
-msgid "Set up new U2F device"
+msgid "Set up new device"
msgstr ""
msgid "Set up new password"
@@ -22724,6 +23537,9 @@ msgstr ""
msgid "Sets weight to %{weight}."
msgstr ""
+msgid "Setting this to 0 means using the system default timeout value."
+msgstr ""
+
msgid "Settings"
msgstr ""
@@ -22739,6 +23555,15 @@ msgstr ""
msgid "Severity"
msgstr ""
+msgid "SeverityWidget|Severity"
+msgstr ""
+
+msgid "SeverityWidget|Severity: %{severity}"
+msgstr ""
+
+msgid "SeverityWidget|There was an error while updating severity."
+msgstr ""
+
msgid "Shards (%{shards})"
msgstr ""
@@ -22784,6 +23609,9 @@ msgstr ""
msgid "Show all requirements."
msgstr ""
+msgid "Show all test cases."
+msgstr ""
+
msgid "Show archived projects"
msgstr ""
@@ -22796,6 +23624,9 @@ msgstr ""
msgid "Show comments"
msgstr ""
+msgid "Show comments on this file"
+msgstr ""
+
msgid "Show comments only"
msgstr ""
@@ -22841,6 +23672,12 @@ msgstr ""
msgid "Show parent subgroups"
msgstr ""
+msgid "Show the Closed list"
+msgstr ""
+
+msgid "Show the Open list"
+msgstr ""
+
msgid "Show whitespace changes"
msgstr ""
@@ -22884,9 +23721,6 @@ msgstr ""
msgid "Sidebar|Assign health status"
msgstr ""
-msgid "Sidebar|Change weight"
-msgstr ""
-
msgid "Sidebar|Health status"
msgstr ""
@@ -23070,6 +23904,9 @@ msgstr ""
msgid "Snippets|Add another file %{num}/%{total}"
msgstr ""
+msgid "Snippets|Authored %{time_ago} by %{author}"
+msgstr ""
+
msgid "Snippets|Delete file"
msgstr ""
@@ -23097,6 +23934,9 @@ msgstr ""
msgid "Solution"
msgstr ""
+msgid "Some changes are not shown"
+msgstr ""
+
msgid "Some child epics may be hidden due to applied filters"
msgstr ""
@@ -23463,6 +24303,12 @@ msgstr ""
msgid "Source (branch or tag)"
msgstr ""
+msgid "Source Branch"
+msgstr ""
+
+msgid "Source branch: %{source_branch_open}%{source_branch}%{source_branch_close}"
+msgstr ""
+
msgid "Source code"
msgstr ""
@@ -23628,9 +24474,6 @@ msgstr ""
msgid "Start and due date"
msgstr ""
-msgid "Start by choosing a group to see how your team is spending time. You can then drill down to the project level."
-msgstr ""
-
msgid "Start by choosing a group to start exploring the merge requests in that group. You can then proceed to filter by projects, labels, milestones and authors."
msgstr ""
@@ -23712,18 +24555,27 @@ msgstr ""
msgid "StaticSiteEditor|3. Assign a person to review and accept the merge request."
msgstr ""
+msgid "StaticSiteEditor|A link to view the merge request will appear once ready."
+msgstr ""
+
msgid "StaticSiteEditor|An error occurred while submitting your changes."
msgstr ""
msgid "StaticSiteEditor|Branch could not be created."
msgstr ""
+msgid "StaticSiteEditor|Copy update"
+msgstr ""
+
msgid "StaticSiteEditor|Could not commit the content changes."
msgstr ""
msgid "StaticSiteEditor|Could not create merge request."
msgstr ""
+msgid "StaticSiteEditor|Creating your merge request"
+msgstr ""
+
msgid "StaticSiteEditor|Incompatible file content"
msgstr ""
@@ -23745,6 +24597,9 @@ msgstr ""
msgid "StaticSiteEditor|View documentation"
msgstr ""
+msgid "StaticSiteEditor|You can set an assignee to get your changes reviewed and deployed once your merge request is created."
+msgstr ""
+
msgid "StaticSiteEditor|Your merge request has been created"
msgstr ""
@@ -23874,15 +24729,15 @@ msgstr ""
msgid "Submit %{humanized_resource_name}"
msgstr ""
-msgid "Submit Changes"
-msgstr ""
-
msgid "Submit a review"
msgstr ""
msgid "Submit as spam"
msgstr ""
+msgid "Submit changes"
+msgstr ""
+
msgid "Submit feedback"
msgstr ""
@@ -24036,6 +24891,9 @@ msgstr ""
msgid "Successfully deleted U2F device."
msgstr ""
+msgid "Successfully deleted WebAuthn device."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -24354,9 +25212,6 @@ msgstr ""
msgid "Template to append to all Service Desk issues"
msgstr ""
-msgid "Template was successfully saved."
-msgstr ""
-
msgid "Templates"
msgstr ""
@@ -24435,10 +25290,28 @@ msgid_plural "Test coverage: %d hits"
msgstr[0] ""
msgstr[1] ""
-msgid "Test failed."
+msgid "Test settings"
msgstr ""
-msgid "Test settings and save changes"
+msgid "TestCases|New Test Case"
+msgstr ""
+
+msgid "TestCases|New test case"
+msgstr ""
+
+msgid "TestCases|Search test cases"
+msgstr ""
+
+msgid "TestCases|Something went wrong while creating a test case."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching count of test cases."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching test cases list."
+msgstr ""
+
+msgid "TestCases|Submit test case"
msgstr ""
msgid "TestHooks|Ensure one of your projects has merge requests."
@@ -24504,6 +25377,9 @@ msgstr ""
msgid "Thank you for signing up for your free trial! You will get additional instructions in your inbox shortly."
msgstr ""
+msgid "Thank you for your business."
+msgstr ""
+
msgid "Thank you for your feedback!"
msgstr ""
@@ -24563,9 +25439,6 @@ msgstr ""
msgid "The URL to use for connecting to Elasticsearch. Use a comma-separated list to support clustering (e.g., \"http://localhost:9200, http://localhost:9201\")."
msgstr ""
-msgid "The Web IDE offers advanced syntax highlighting capabilities and more."
-msgstr ""
-
msgid "The X509 Certificate to use when mutual TLS is required to communicate with the external authorization service. If left blank, the server certificate is still validated when accessing over HTTPS."
msgstr ""
@@ -24676,6 +25549,9 @@ msgstr ""
msgid "The form contains the following error:"
msgstr ""
+msgid "The form contains the following warning:"
+msgstr ""
+
msgid "The global settings require you to enable Two-Factor Authentication for your account."
msgstr ""
@@ -24790,9 +25666,6 @@ msgstr ""
msgid "The private key to use when a client certificate is provided. This value is encrypted at rest."
msgstr ""
-msgid "The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The project can be accessed by any logged in user."
msgstr ""
@@ -24829,7 +25702,7 @@ msgstr ""
msgid "The remote repository is being updated..."
msgstr ""
-msgid "The repository can be commited to, and issues, comments and other entities can be created."
+msgid "The repository can be committed to, and issues, comments and other entities can be created."
msgstr ""
msgid "The repository for this project does not exist."
@@ -24883,9 +25756,6 @@ msgstr ""
msgid "The time taken by each data entry gathered by that stage."
msgstr ""
-msgid "The total stage shows the time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The update action will time out after %{number_of_minutes} minutes. For big repositories, use a clone/push combination."
msgstr ""
@@ -24949,6 +25819,9 @@ msgstr ""
msgid "There are no archived requirements"
msgstr ""
+msgid "There are no archived test cases"
+msgstr ""
+
msgid "There are no changes"
msgstr ""
@@ -24988,6 +25861,9 @@ msgstr ""
msgid "There are no open requirements"
msgstr ""
+msgid "There are no open test cases"
+msgstr ""
+
msgid "There are no packages yet"
msgstr ""
@@ -25000,6 +25876,9 @@ msgstr ""
msgid "There is a limit of %{ci_project_subscriptions_limit} subscriptions from or to a project."
msgstr ""
+msgid "There is already a To-Do for this design."
+msgstr ""
+
msgid "There is already a repository with that name on disk"
msgstr ""
@@ -25018,6 +25897,9 @@ msgstr ""
msgid "There was a problem communicating with your device."
msgstr ""
+msgid "There was a problem fetching branches."
+msgstr ""
+
msgid "There was a problem fetching groups."
msgstr ""
@@ -25246,9 +26128,15 @@ msgstr ""
msgid "This action can lead to data loss. To prevent accidental actions we ask you to confirm your intention."
msgstr ""
+msgid "This action cannot be undone, and will permanently delete the %{key} SSH key"
+msgstr ""
+
msgid "This action cannot be undone. You will lose the project's repository and all content: issues, merge requests, etc."
msgstr ""
+msgid "This action has been performed too many times. Try again later."
+msgstr ""
+
msgid "This action will %{strongOpen}permanently delete%{strongClose} %{codeOpen}%{project}%{codeClose} %{strongOpen}immediately%{strongClose}, including its repositories and all content: issues, merge requests, etc."
msgstr ""
@@ -25276,9 +26164,6 @@ msgstr ""
msgid "This board's scope is reduced"
msgstr ""
-msgid "This branch has changed since you started editing. Would you like to create a new branch?"
-msgstr ""
-
msgid "This chart could not be displayed"
msgstr ""
@@ -25405,15 +26290,9 @@ msgstr ""
msgid "This is a security log of important events involving your account."
msgstr ""
-msgid "This is the author's first Merge Request to this project."
-msgstr ""
-
msgid "This is the highest peak of users on your installation since the license started."
msgstr ""
-msgid "This is the maximum number of users that have existed at the same time since the license started. This is the minimum number of seats you will need to buy when you renew your license."
-msgstr ""
-
msgid "This is the number of currently active users on your installation, and this is the minimum number you need to purchase when you renew your license."
msgstr ""
@@ -25645,6 +26524,15 @@ msgstr ""
msgid "This user has no identities"
msgstr ""
+msgid "This user has previously committed to the %{name} project."
+msgstr ""
+
+msgid "This user has the %{access} role in the %{name} project."
+msgstr ""
+
+msgid "This user is the author of this %{noteable}."
+msgstr ""
+
msgid "This user will be the author of all events in the activity feed that are the result of an update, like new branches being created or new commits being pushed to existing branches."
msgstr ""
@@ -25675,6 +26563,9 @@ msgstr ""
msgid "Threat Monitoring"
msgstr ""
+msgid "ThreatMonitoring|All Environments"
+msgstr ""
+
msgid "ThreatMonitoring|Anomalous Requests"
msgstr ""
@@ -25702,9 +26593,6 @@ msgstr ""
msgid "ThreatMonitoring|Operations Per Second"
msgstr ""
-msgid "ThreatMonitoring|Overview"
-msgstr ""
-
msgid "ThreatMonitoring|Packet Activity"
msgstr ""
@@ -25723,6 +26611,9 @@ msgstr ""
msgid "ThreatMonitoring|Something went wrong, unable to fetch statistics"
msgstr ""
+msgid "ThreatMonitoring|Statistics"
+msgstr ""
+
msgid "ThreatMonitoring|The firewall is not installed or has been disabled. To view this data, ensure the web application firewall is installed and enabled for your cluster."
msgstr ""
@@ -26114,6 +27005,9 @@ msgstr ""
msgid "To update Snippets with multiple files, you must use the `files` parameter"
msgstr ""
+msgid "To use Gitpod you must first enable the feature in the integrations section of your %{user_prefs}."
+msgstr ""
+
msgid "To view all %{scannedResourcesCount} scanned URLs, please download the CSV file"
msgstr ""
@@ -26147,9 +27041,6 @@ msgstr ""
msgid "Toggle Sidebar"
msgstr ""
-msgid "Toggle all threads"
-msgstr ""
-
msgid "Toggle backtrace"
msgstr ""
@@ -26174,9 +27065,6 @@ msgstr ""
msgid "Toggle navigation"
msgstr ""
-msgid "Toggle project"
-msgstr ""
-
msgid "Toggle sidebar"
msgstr ""
@@ -26216,6 +27104,9 @@ msgstr ""
msgid "Too many projects enabled. You will need to manage them via the console or the API."
msgstr ""
+msgid "Too much data"
+msgstr ""
+
msgid "Topics (optional)"
msgstr ""
@@ -26234,6 +27125,9 @@ msgstr ""
msgid "Total cores (CPUs)"
msgstr ""
+msgid "Total days to completion"
+msgstr ""
+
msgid "Total issues"
msgstr ""
@@ -26330,6 +27224,9 @@ msgstr ""
msgid "Trending"
msgstr ""
+msgid "Trials|Create a new group to start your GitLab Gold trial."
+msgstr ""
+
msgid "Trials|Go back to GitLab"
msgstr ""
@@ -26339,6 +27236,15 @@ msgstr ""
msgid "Trials|You can always resume this process by selecting your avatar and choosing 'Start a Gold trial'"
msgstr ""
+msgid "Trials|You can apply your trial to a new group or an existing group."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group or your personal account."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group, an existing group, or your personal account."
+msgstr ""
+
msgid "Trials|You won't get a free trial right now but you can always resume this process by clicking on your avatar and choosing 'Start a free trial'"
msgstr ""
@@ -26408,6 +27314,9 @@ msgstr ""
msgid "Try using a different search term to find the file you are looking for."
msgstr ""
+msgid "Trying to communicate with your device. Plug it in (if needed) and press the button on the device now."
+msgstr ""
+
msgid "Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now."
msgstr ""
@@ -26495,6 +27404,12 @@ msgstr ""
msgid "URL or request ID"
msgstr ""
+msgid "USER %{user} WILL BE REMOVED! Are you sure?"
+msgstr ""
+
+msgid "USER WILL BE BLOCKED! Are you sure?"
+msgstr ""
+
msgid "UTC"
msgstr ""
@@ -26552,9 +27467,6 @@ msgstr ""
msgid "Unable to load the merge request widget. Try reloading the page."
msgstr ""
-msgid "Unable to resolve"
-msgstr ""
-
msgid "Unable to save iteration. Please try again"
msgstr ""
@@ -26603,6 +27515,9 @@ msgstr ""
msgid "Undo ignore"
msgstr ""
+msgid "Unexpected error"
+msgstr ""
+
msgid "Unfortunately, your email message to GitLab could not be processed."
msgstr ""
@@ -26636,6 +27551,9 @@ msgstr ""
msgid "Unknown response text"
msgstr ""
+msgid "Unless otherwise agreed to in writing with GitLab, by clicking \"Upload License\" you agree that your use of GitLab Software is subject to the %{eula_link_start}Terms of Service%{eula_link_end}."
+msgstr ""
+
msgid "Unlimited"
msgstr ""
@@ -27002,9 +27920,6 @@ msgstr ""
msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
msgstr ""
-msgid "Use a hardware device to add the second factor of authentication."
-msgstr ""
-
msgid "Use an one time password authenticator on your mobile device or computer to enable two-factor authentication (2FA)."
msgstr ""
@@ -27278,13 +28193,13 @@ msgstr ""
msgid "Users"
msgstr ""
-msgid "Users in License:"
+msgid "Users in License"
msgstr ""
-msgid "Users or groups set as approvers in the project's or merge request's settings."
+msgid "Users in License:"
msgstr ""
-msgid "Users outside of license"
+msgid "Users or groups set as approvers in the project's or merge request's settings."
msgstr ""
msgid "Users over License:"
@@ -27302,9 +28217,6 @@ msgstr ""
msgid "Users with a Guest role or those who don't belong to a Project or Group will not use a seat from your license."
msgstr ""
-msgid "Users with a Guest role or those who don't belong to any projects or groups don't count towards seats in use."
-msgstr ""
-
msgid "UsersSelect|%{name} + %{length} more"
msgstr ""
@@ -27344,9 +28256,6 @@ msgstr ""
msgid "Validations failed."
msgstr ""
-msgid "Validity"
-msgstr ""
-
msgid "Value"
msgstr ""
@@ -27365,6 +28274,9 @@ msgstr ""
msgid "Value Stream Name"
msgstr ""
+msgid "ValueStreamAnalyticsStage|We don't have enough data to show this stage."
+msgstr ""
+
msgid "ValueStreamAnalytics|%{days}d"
msgstr ""
@@ -27621,6 +28533,9 @@ msgstr ""
msgid "VisualReviewApp|Steps 1 and 2 (and sometimes 3) are performed once by the developer before requesting feedback. Steps 3 (if necessary), 4 is performed by the reviewer each time they perform a review."
msgstr ""
+msgid "Visualization"
+msgstr ""
+
msgid "Vulnerabilities"
msgstr ""
@@ -27648,34 +28563,31 @@ msgstr ""
msgid "VulnerabilityChart|Severity"
msgstr ""
-msgid "VulnerabilityManagement|A true-positive and will fix"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Change status"
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|Confirm"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Confirmed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
-msgstr ""
-
-msgid "VulnerabilityManagement|Detected %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|A true-positive and will fix"
msgstr ""
-msgid "VulnerabilityManagement|Dismiss"
+msgid "VulnerabilityManagement|Change status"
msgstr ""
-msgid "VulnerabilityManagement|Dismissed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
msgstr ""
-msgid "VulnerabilityManagement|Resolved"
+msgid "VulnerabilityManagement|Detected"
msgstr ""
-msgid "VulnerabilityManagement|Resolved %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Needs triage"
msgstr ""
msgid "VulnerabilityManagement|Something went wrong while trying to delete the comment. Please try again later."
@@ -27726,6 +28638,9 @@ msgstr ""
msgid "Vulnerability|%{scannerName} (version %{scannerVersion})"
msgstr ""
+msgid "Vulnerability|Activity"
+msgstr ""
+
msgid "Vulnerability|Class"
msgstr ""
@@ -27738,6 +28653,9 @@ msgstr ""
msgid "Vulnerability|Description"
msgstr ""
+msgid "Vulnerability|Detected"
+msgstr ""
+
msgid "Vulnerability|Evidence"
msgstr ""
@@ -27801,6 +28719,9 @@ msgstr ""
msgid "Warning: Displaying this diagram might cause performance issues on this page."
msgstr ""
+msgid "We are currently unable to fetch data for the pipeline header."
+msgstr ""
+
msgid "We are currently unable to fetch data for this graph."
msgstr ""
@@ -27840,6 +28761,12 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
+msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
+msgstr ""
+
+msgid "We would like to inform you that your subscription GitLab Enterprise Edition %{plan_name} is nearing its user limit. You have %{active_user_count} active users, which is almost at the user limit of %{maximum_user_count}."
+msgstr ""
+
msgid "We've found no vulnerabilities"
msgstr ""
@@ -27855,6 +28782,12 @@ msgstr ""
msgid "Web terminal"
msgstr ""
+msgid "WebAuthn Devices (%{length})"
+msgstr ""
+
+msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
+msgstr ""
+
msgid "WebIDE|Merge request"
msgstr ""
@@ -27993,15 +28926,9 @@ msgstr ""
msgid "Welcome to the guided GitLab tour"
msgstr ""
-msgid "Welcome to your Issue Board!"
-msgstr ""
-
msgid "Welcome to your issue board!"
msgstr ""
-msgid "We’ve been making changes to %{featureName} and we’d love your feedback %{linkStart}in this issue%{linkEnd} to help us improve the experience."
-msgstr ""
-
msgid "What are you searching for?"
msgstr ""
@@ -28020,6 +28947,9 @@ msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
msgstr ""
+msgid "When enabled, any user visiting %{host} and creating an account will have to be explicitly approved by the admin before they can login. This setting is effective only if sign-ups are enabled."
+msgstr ""
+
msgid "When enabled, any user visiting %{host} will be able to create an account."
msgstr ""
@@ -28244,6 +29174,9 @@ msgstr ""
msgid "With requirements, you can set criteria to check your products against."
msgstr ""
+msgid "With test cases, you can define conditions for your project to meet in determining quality"
+msgstr ""
+
msgid "Withdraw Access Request"
msgstr ""
@@ -28259,6 +29192,9 @@ msgstr ""
msgid "Workflow Help"
msgstr ""
+msgid "Would you like to create a new branch?"
+msgstr ""
+
msgid "Write"
msgstr ""
@@ -28280,6 +29216,9 @@ msgstr ""
msgid "Wrong extern UID provided. Make sure Auth0 is configured correctly."
msgstr ""
+msgid "YYYY-MM-DD"
+msgstr ""
+
msgid "Yes"
msgstr ""
@@ -28337,7 +29276,7 @@ msgstr ""
msgid "You are going to remove the fork relationship from %{project_full_name}. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "You are going to transfer %{project_full_name} to another owner. Are you ABSOLUTELY sure?"
+msgid "You are going to transfer %{project_full_name} to another namespace. Are you ABSOLUTELY sure?"
msgstr ""
msgid "You are going to turn off the confidentiality. This means %{strongStart}everyone%{strongEnd} will be able to see and leave a comment on this %{issuableType}."
@@ -28397,9 +29336,6 @@ msgstr ""
msgid "You can always edit this later"
msgstr ""
-msgid "You can apply your Trial to your Personal account or create a New Group."
-msgstr ""
-
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings"
msgstr ""
@@ -28421,12 +29357,18 @@ msgstr ""
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
+msgid "You can find more information about GitLab subscriptions in %{subscriptions_doc_link}."
+msgstr ""
+
msgid "You can generate an access token scoped to this project for each application to use the GitLab API."
msgstr ""
msgid "You can get started by cloning the repository or start adding files to it with one of the following options."
msgstr ""
+msgid "You can group test cases using labels. To learn about the future direction of this feature, visit %{linkStart}Quality Management direction page%{linkEnd}."
+msgstr ""
+
msgid "You can invite a new member to %{project_name} or invite another group."
msgstr ""
@@ -28442,6 +29384,9 @@ msgstr ""
msgid "You can notify the app / group or a project by sending them an email notification"
msgstr ""
+msgid "You can now close this window."
+msgstr ""
+
msgid "You can now export your security dashboard to a CSV report."
msgstr ""
@@ -28490,9 +29435,6 @@ msgstr ""
msgid "You can test your .gitlab-ci.yml in %{linkStart}CI Lint%{linkEnd}."
msgstr ""
-msgid "You can try again using %{begin_link}basic search%{end_link}"
-msgstr ""
-
msgid "You cannot access the raw file. Please wait a minute."
msgstr ""
@@ -28544,6 +29486,9 @@ msgstr ""
msgid "You don't have any U2F devices registered yet."
msgstr ""
+msgid "You don't have any WebAuthn devices registered yet."
+msgstr ""
+
msgid "You don't have any active chat names."
msgstr ""
@@ -28631,6 +29576,9 @@ msgstr ""
msgid "You must accept our Terms of Service and privacy policy in order to register an account"
msgstr ""
+msgid "You must be logged in to search across all of GitLab"
+msgstr ""
+
msgid "You must disassociate %{domain} from all clusters it is attached to before deletion."
msgstr ""
@@ -28670,7 +29618,7 @@ msgstr ""
msgid "You need to be logged in."
msgstr ""
-msgid "You need to register a two-factor authentication app before you can set up a U2F device."
+msgid "You need to register a two-factor authentication app before you can set up a device."
msgstr ""
msgid "You need to set terms to be enforced"
@@ -28688,6 +29636,9 @@ msgstr ""
msgid "You reached %{usage_in_percent} of %{namespace_name}'s storage capacity (%{used_storage} of %{storage_limit})"
msgstr ""
+msgid "You successfully declined the invitation"
+msgstr ""
+
msgid "You tried to fork %{link_to_the_project} but it failed for the following reason:"
msgstr ""
@@ -28853,10 +29804,13 @@ msgstr ""
msgid "Your U2F device did not send a valid JSON response."
msgstr ""
-msgid "Your U2F device needs to be set up. Plug it in (if not already) and click the button on the left."
+msgid "Your U2F device was registered!"
msgstr ""
-msgid "Your U2F device was registered!"
+msgid "Your WebAuthn device did not send a valid JSON response."
+msgstr ""
+
+msgid "Your WebAuthn device was registered!"
msgstr ""
msgid "Your access request to the %{source_type} has been withdrawn."
@@ -28880,6 +29834,9 @@ msgstr ""
msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
msgstr ""
+msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
+msgstr ""
+
msgid "Your changes can be committed to %{branch_name} because a merge request is open."
msgstr ""
@@ -28916,6 +29873,12 @@ msgstr ""
msgid "Your deployment services will be broken, you will need to manually fix the services after renaming."
msgstr ""
+msgid "Your device is not compatible with GitLab. Please try another device"
+msgstr ""
+
+msgid "Your device needs to be set up. Plug it in (if needed) and click the button on the left."
+msgstr ""
+
msgid "Your device was successfully set up! Give it a name and register it with the GitLab server."
msgstr ""
@@ -29029,9 +29992,6 @@ msgstr[1] ""
msgid "access:"
msgstr ""
-msgid "activated"
-msgstr ""
-
msgid "added %{created_at_timeago}"
msgstr ""
@@ -29104,9 +30064,21 @@ msgstr ""
msgid "by %{user}"
msgstr ""
+msgid "cannot be a date in the past"
+msgstr ""
+
msgid "cannot be changed if a personal project has container registry tags."
msgstr ""
+msgid "cannot be changed if shared runners are enabled"
+msgstr ""
+
+msgid "cannot be enabled because parent group does not allow it"
+msgstr ""
+
+msgid "cannot be enabled because parent group has shared Runners disabled"
+msgstr ""
+
msgid "cannot be enabled unless all domains have TLS certificates"
msgstr ""
@@ -29152,7 +30124,7 @@ msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about SAST %{linkEndTag}"
msgstr ""
-msgid "ciReport|%{linkStartTag}Learn more about Secret Scanning %{linkEndTag}"
+msgid "ciReport|%{linkStartTag}Learn more about Secret Detection %{linkEndTag}"
msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about codequality reports %{linkEndTag}"
@@ -29467,9 +30439,6 @@ msgstr ""
msgid "error"
msgstr ""
-msgid "error code:"
-msgstr ""
-
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr ""
@@ -29491,6 +30460,9 @@ msgstr ""
msgid "failed to dismiss associated finding(id=%{finding_id}): %{message}"
msgstr ""
+msgid "failed to revert associated finding(id=%{finding_id}) to detected"
+msgstr ""
+
msgid "file"
msgid_plural "files"
msgstr[0] ""
@@ -30033,6 +31005,9 @@ msgstr ""
msgid "must be a root namespace"
msgstr ""
+msgid "must be a valid IPv4 or IPv6 address"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -30069,6 +31044,9 @@ msgstr ""
msgid "no expiration"
msgstr ""
+msgid "no name set"
+msgstr ""
+
msgid "no one can merge"
msgstr ""
@@ -30247,9 +31225,6 @@ msgstr ""
msgid "security Reports|There was an error creating the merge request"
msgstr ""
-msgid "settings saved, but not activated"
-msgstr ""
-
msgid "severity|Critical"
msgstr ""
@@ -30376,9 +31351,6 @@ msgstr ""
msgid "toggle collapse"
msgstr ""
-msgid "toggle dropdown"
-msgstr ""
-
msgid "triggered"
msgstr ""
@@ -30406,6 +31378,9 @@ msgstr ""
msgid "user avatar"
msgstr ""
+msgid "user preferences"
+msgstr ""
+
msgid "username"
msgstr ""
diff --git a/locale/eo/gitlab.po b/locale/eo/gitlab.po
index 20ef5246c1d..7e549a92ffb 100644
--- a/locale/eo/gitlab.po
+++ b/locale/eo/gitlab.po
@@ -14,7 +14,10 @@ msgstr ""
"X-Crowdin-Language: eo\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 6\n"
-"PO-Revision-Date: 2020-09-04 23:03\n"
+"PO-Revision-Date: 2020-10-02 18:43\n"
+
+msgid " %{project_name}#%{issue_iid} &middot; opened %{issue_created} by %{author}"
+msgstr ""
msgid " %{start} to %{end}"
msgstr ""
@@ -74,6 +77,16 @@ msgstr ""
msgid "\"el\" parameter is required for createInstance()"
msgstr ""
+msgid "%d Approval"
+msgid_plural "%d Approvals"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d Package"
+msgid_plural "%d Packages"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d Scanned URL"
msgid_plural "%d Scanned URLs"
msgstr[0] ""
@@ -137,6 +150,11 @@ msgstr[1] ""
msgid "%d commits"
msgstr ""
+msgid "%d completed issue"
+msgid_plural "%d completed issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d contribution"
msgid_plural "%d contributions"
msgstr[0] ""
@@ -147,6 +165,11 @@ msgid_plural "%d days"
msgstr[0] ""
msgstr[1] ""
+msgid "%d day until tags are automatically removed"
+msgid_plural "%d days until tags are automatically removed"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d error"
msgid_plural "%d errors"
msgstr[0] ""
@@ -237,6 +260,16 @@ msgid_plural "%d more comments"
msgstr[0] ""
msgstr[1] ""
+msgid "%d open issue"
+msgid_plural "%d open issues"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d pending comment"
+msgid_plural "%d pending comments"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d personal project will be removed and cannot be restored."
msgid_plural "%d personal projects will be removed and cannot be restored."
msgstr[0] ""
@@ -252,6 +285,11 @@ msgid_plural "%d projects"
msgstr[0] ""
msgstr[1] ""
+msgid "%d project selected"
+msgid_plural "%d projects selected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d request with warnings"
msgid_plural "%d requests with warnings"
msgstr[0] ""
@@ -272,6 +310,11 @@ msgid_plural "%d tags"
msgstr[0] ""
msgstr[1] ""
+msgid "%d tag per image name"
+msgid_plural "%d tags per image name"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d unassigned issue"
msgid_plural "%d unassigned issues"
msgstr[0] ""
@@ -292,6 +335,11 @@ msgid_plural "%d vulnerabilities dismissed"
msgstr[0] ""
msgstr[1] ""
+msgid "%d warning found:"
+msgid_plural "%d warnings found:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%s additional commit has been omitted to prevent performance issues."
msgid_plural "%s additional commits have been omitted to prevent performance issues."
msgstr[0] "%s enmetado estis transsaltita, por ne troÅarÄi la sistemon."
@@ -330,6 +378,9 @@ msgstr ""
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr ""
+msgid "%{completedCount} completed weight"
+msgstr ""
+
msgid "%{completedWeight} of %{totalWeight} weight completed"
msgstr ""
@@ -378,14 +429,12 @@ msgid_plural "%{count} participants"
msgstr[0] ""
msgstr[1] ""
-msgid "%{count} pending comment"
-msgid_plural "%{count} pending comments"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
+msgid "%{count} total weight"
+msgstr ""
+
msgid "%{dashboard_path} could not be found."
msgstr ""
@@ -440,6 +489,9 @@ msgstr ""
msgid "%{group_name} uses group managed accounts. You need to create a new GitLab account which will be managed by %{group_name}."
msgstr ""
+msgid "%{group_name}&%{epic_iid} &middot; opened %{epic_created} by %{author}"
+msgstr ""
+
msgid "%{host} sign-in from new location"
msgstr ""
@@ -452,7 +504,7 @@ msgstr ""
msgid "%{issuableType} will be removed! Are you sure?"
msgstr ""
-msgid "%{issuesSize} issues with a limit of %{maxIssueCount}"
+msgid "%{issuesCount} issues with a limit of %{maxIssueCount}"
msgstr ""
msgid "%{issuesSize} with a limit of %{maxIssueCount}"
@@ -485,7 +537,7 @@ msgstr ""
msgid "%{labelStart}Namespace:%{labelEnd} %{namespace}"
msgstr ""
-msgid "%{labelStart}Report Type:%{labelEnd} %{reportType}"
+msgid "%{labelStart}Scan Type:%{labelEnd} %{reportType}"
msgstr ""
msgid "%{labelStart}Scanner:%{labelEnd} %{scanner}"
@@ -682,9 +734,6 @@ msgid_plural "%{securityScanner} results are not available because a pipeline ha
msgstr[0] ""
msgstr[1] ""
-msgid "%{service_title} %{message}."
-msgstr ""
-
msgid "%{size} GiB"
msgstr ""
@@ -773,6 +822,12 @@ msgstr ""
msgid "%{timebox_name} should belong either to a project or a group."
msgstr ""
+msgid "%{timebox_type} does not support burnup charts"
+msgstr ""
+
+msgid "%{timebox_type} must have a start and due date"
+msgstr ""
+
msgid "%{title} %{operator} %{threshold}"
msgstr ""
@@ -797,7 +852,7 @@ msgstr ""
msgid "%{total} open issue weight"
msgstr ""
-msgid "%{total} open issues"
+msgid "%{total} warnings found: showing first %{warningsDisplayed}"
msgstr ""
msgid "%{usage_ping_link_start}Learn more%{usage_ping_link_end} about what information is shared with GitLab Inc."
@@ -830,9 +885,6 @@ msgstr ""
msgid "&lt; 1 hour"
msgstr ""
-msgid "&lt;no name set&gt;"
-msgstr ""
-
msgid "&lt;no scopes selected&gt;"
msgstr ""
@@ -863,6 +915,9 @@ msgstr ""
msgid "'%{name}' Value Stream created"
msgstr ""
+msgid "'%{name}' Value Stream deleted"
+msgstr ""
+
msgid "'%{name}' stage already exists"
msgstr ""
@@ -922,6 +977,9 @@ msgstr ""
msgid "+ %{numberOfHiddenAssignees} more"
msgstr ""
+msgid "+ %{numberOfHiddenReviewers} more"
+msgstr ""
+
msgid "+%d more"
msgid_plural "+%d more"
msgstr[0] ""
@@ -982,6 +1040,11 @@ msgid_plural "%d Days"
msgstr[0] ""
msgstr[1] ""
+msgid "1 Issue"
+msgid_plural "%d Issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "1 closed issue"
msgid_plural "%{issues} closed issues"
msgstr[0] ""
@@ -997,6 +1060,11 @@ msgid_plural "%d days"
msgstr[0] ""
msgstr[1] ""
+msgid "1 deploy key"
+msgid_plural "%d deploy keys"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1099,6 +1167,9 @@ msgstr ""
msgid ":%{startLine} to %{endLine}"
msgstr ""
+msgid "A %{incident_docs_start}modified issue%{incident_docs_end} to guide the resolution of incidents."
+msgstr ""
+
msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr ""
@@ -1111,6 +1182,9 @@ msgstr ""
msgid "A GitBook site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
+msgid "A Gitpod configured Webapplication in Spring and Java"
+msgstr ""
+
msgid "A Hexo site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
@@ -1282,9 +1356,15 @@ msgstr ""
msgid "Access expiration date"
msgstr ""
+msgid "Access expires"
+msgstr ""
+
msgid "Access forbidden. Check your access level."
msgstr ""
+msgid "Access granted"
+msgstr ""
+
msgid "Access requests"
msgstr ""
@@ -1294,6 +1374,9 @@ msgstr ""
msgid "Access to Pages websites are controlled based on the user's membership to a given project. By checking this box, users will be required to be logged in to have access to all Pages websites in your instance."
msgstr ""
+msgid "AccessDropdown|Deploy Keys"
+msgstr ""
+
msgid "AccessDropdown|Groups"
msgstr ""
@@ -1411,12 +1494,6 @@ msgstr ""
msgid "Active Sessions"
msgstr ""
-msgid "Active Users:"
-msgstr ""
-
-msgid "Active users"
-msgstr ""
-
msgid "Activity"
msgstr "Aktiveco"
@@ -1584,9 +1661,6 @@ msgstr ""
msgid "Add label(s)"
msgstr ""
-msgid "Add license"
-msgstr ""
-
msgid "Add list"
msgstr ""
@@ -1761,21 +1835,51 @@ msgstr ""
msgid "AdminArea|Bots"
msgstr ""
+msgid "AdminArea|Components"
+msgstr ""
+
msgid "AdminArea|Developer"
msgstr ""
+msgid "AdminArea|Features"
+msgstr ""
+
+msgid "AdminArea|Groups: %{number_of_groups}"
+msgstr ""
+
msgid "AdminArea|Guest"
msgstr ""
msgid "AdminArea|Included Free in license"
msgstr ""
+msgid "AdminArea|Latest groups"
+msgstr ""
+
+msgid "AdminArea|Latest projects"
+msgstr ""
+
+msgid "AdminArea|Latest users"
+msgstr ""
+
msgid "AdminArea|Maintainer"
msgstr ""
+msgid "AdminArea|New group"
+msgstr ""
+
+msgid "AdminArea|New project"
+msgstr ""
+
+msgid "AdminArea|New user"
+msgstr ""
+
msgid "AdminArea|Owner"
msgstr ""
+msgid "AdminArea|Projects: %{number_of_projects}"
+msgstr ""
+
msgid "AdminArea|Reporter"
msgstr ""
@@ -1803,6 +1907,9 @@ msgstr ""
msgid "AdminArea|Users without a Group and Project"
msgstr ""
+msgid "AdminArea|Users: %{number_of_users}"
+msgstr ""
+
msgid "AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running."
msgstr ""
@@ -1821,9 +1928,6 @@ msgstr ""
msgid "AdminProjects|Delete Project %{projectName}?"
msgstr ""
-msgid "AdminProjects|Delete project"
-msgstr ""
-
msgid "AdminSettings|Apply integration settings to all Projects"
msgstr ""
@@ -2061,21 +2165,30 @@ msgstr ""
msgid "AdminUsers|Without projects"
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 ""
msgid "AdminUsers|You cannot remove your own admin rights."
msgstr ""
+msgid "AdminUsers|You must transfer ownership or delete the groups owned by this user before you can delete their account"
+msgstr ""
+
msgid "Administration"
msgstr ""
msgid "Advanced"
msgstr ""
+msgid "Advanced Search"
+msgstr ""
+
+msgid "Advanced Search with Elasticsearch"
+msgstr ""
+
msgid "Advanced Settings"
msgstr ""
@@ -2153,6 +2266,9 @@ msgstr ""
msgid "AlertManagement|Edit"
msgstr ""
+msgid "AlertManagement|Environment"
+msgstr ""
+
msgid "AlertManagement|Events"
msgstr ""
@@ -2165,6 +2281,9 @@ msgstr ""
msgid "AlertManagement|Issue"
msgstr ""
+msgid "AlertManagement|Key"
+msgstr ""
+
msgid "AlertManagement|Low"
msgstr ""
@@ -2258,6 +2377,9 @@ msgstr ""
msgid "AlertManagement|Unknown"
msgstr ""
+msgid "AlertManagement|Value"
+msgstr ""
+
msgid "AlertManagement|View alerts in Opsgenie"
msgstr ""
@@ -2417,6 +2539,9 @@ msgstr ""
msgid "All projects"
msgstr ""
+msgid "All projects selected"
+msgstr ""
+
msgid "All security scans are enabled because %{linkStart}Auto DevOps%{linkEnd} is enabled on this project"
msgstr ""
@@ -2504,6 +2629,9 @@ msgstr ""
msgid "Almost there"
msgstr ""
+msgid "Already blocked"
+msgstr ""
+
msgid "Also called \"Issuer\" or \"Relying party trust identifier\""
msgstr ""
@@ -2558,6 +2686,9 @@ msgstr ""
msgid "An error has occurred"
msgstr ""
+msgid "An error occured while making the changes: %{error}"
+msgstr ""
+
msgid "An error occurred adding a draft to the thread."
msgstr ""
@@ -2585,12 +2716,6 @@ msgstr ""
msgid "An error occurred when toggling the notification subscription"
msgstr ""
-msgid "An error occurred when trying to resolve a comment. Please try again."
-msgstr ""
-
-msgid "An error occurred when trying to resolve a discussion. Please try again."
-msgstr ""
-
msgid "An error occurred when updating the issue weight"
msgstr ""
@@ -2606,12 +2731,6 @@ msgstr ""
msgid "An error occurred while checking group path. Please refresh and try again."
msgstr ""
-msgid "An error occurred while committing your changes."
-msgstr ""
-
-msgid "An error occurred while creating the list. Please try again."
-msgstr ""
-
msgid "An error occurred while decoding the file."
msgstr ""
@@ -2684,25 +2803,19 @@ msgstr ""
msgid "An error occurred while fetching the Service Desk address."
msgstr ""
-msgid "An error occurred while fetching the board issues. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the board lists. Please reload the page."
msgstr ""
msgid "An error occurred while fetching the board lists. Please try again."
msgstr ""
-msgid "An error occurred while fetching the board swimlanes. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the builds."
msgstr ""
msgid "An error occurred while fetching the job log."
msgstr ""
-msgid "An error occurred while fetching the job trace."
+msgid "An error occurred while fetching the job logs."
msgstr ""
msgid "An error occurred while fetching the job."
@@ -2849,9 +2962,6 @@ msgstr ""
msgid "An error occurred while saving assignees"
msgstr ""
-msgid "An error occurred while saving the template. Please check if the template exists."
-msgstr ""
-
msgid "An error occurred while searching for milestones"
msgstr ""
@@ -2870,10 +2980,10 @@ msgstr ""
msgid "An error occurred while updating approvers"
msgstr ""
-msgid "An error occurred while updating the comment"
+msgid "An error occurred while updating labels."
msgstr ""
-msgid "An error occurred while updating the list. Please try again."
+msgid "An error occurred while updating the comment"
msgstr ""
msgid "An error occurred while validating group path"
@@ -2927,6 +3037,9 @@ msgstr ""
msgid "An unknown error occurred while loading this graph."
msgstr ""
+msgid "An unknown error occurred."
+msgstr ""
+
msgid "Analytics"
msgstr ""
@@ -2960,10 +3073,10 @@ msgstr ""
msgid "Any"
msgstr ""
-msgid "Any Author"
+msgid "Any %{header}"
msgstr ""
-msgid "Any Status"
+msgid "Any Author"
msgstr ""
msgid "Any branch"
@@ -3017,6 +3130,9 @@ msgstr ""
msgid "Application ID"
msgstr ""
+msgid "Application limits saved successfully"
+msgstr ""
+
msgid "Application settings saved successfully"
msgstr ""
@@ -3226,6 +3342,9 @@ msgstr ""
msgid "Are you sure you want to close this blocked issue?"
msgstr ""
+msgid "Are you sure you want to delete \"%{name}\" Value Stream?"
+msgstr ""
+
msgid "Are you sure you want to delete %{name}?"
msgstr ""
@@ -3235,6 +3354,9 @@ msgstr ""
msgid "Are you sure you want to delete this %{typeOfComment}?"
msgstr ""
+msgid "Are you sure you want to delete this SSH key?"
+msgstr ""
+
msgid "Are you sure you want to delete this board?"
msgstr ""
@@ -3259,6 +3381,11 @@ msgstr ""
msgid "Are you sure you want to erase this build?"
msgstr ""
+msgid "Are you sure you want to import %d repository?"
+msgid_plural "Are you sure you want to import %d repositories?"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Are you sure you want to lose unsaved changes?"
msgstr ""
@@ -3268,15 +3395,15 @@ msgstr ""
msgid "Are you sure you want to merge immediately?"
msgstr ""
-msgid "Are you sure you want to permanently delete this license?"
-msgstr ""
-
msgid "Are you sure you want to re-deploy this environment?"
msgstr ""
msgid "Are you sure you want to regenerate the public key? You will have to update the public key on the remote server before mirroring will work again."
msgstr ""
+msgid "Are you sure you want to reindex?"
+msgstr ""
+
msgid "Are you sure you want to remove %{group_name}?"
msgstr ""
@@ -3304,6 +3431,9 @@ msgstr ""
msgid "Are you sure you want to revoke this nickname?"
msgstr ""
+msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
+msgstr ""
+
msgid "Are you sure you want to stop this environment?"
msgstr ""
@@ -3325,6 +3455,9 @@ msgstr ""
msgid "Are you sure? The device will be signed out of GitLab and all remember me tokens revoked."
msgstr ""
+msgid "Are you sure? This will invalidate your registered applications and U2F / WebAuthn devices."
+msgstr ""
+
msgid "Are you sure? This will invalidate your registered applications and U2F devices."
msgstr ""
@@ -3343,9 +3476,6 @@ msgstr ""
msgid "Artifacts"
msgstr ""
-msgid "As U2F devices are only supported by a few browsers, we require that you set up a two-factor authentication app before a U2F device. That way you'll always be able to log in - even when you're using an unsupported browser."
-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 ""
@@ -3539,6 +3669,9 @@ msgstr ""
msgid "AuditLogs|Target"
msgstr ""
+msgid "AuditLogs|This month"
+msgstr ""
+
msgid "AuditLogs|User Events"
msgstr ""
@@ -3578,6 +3711,9 @@ msgstr ""
msgid "Authentication via U2F device failed."
msgstr ""
+msgid "Authentication via WebAuthn device failed."
+msgstr ""
+
msgid "Author"
msgstr ""
@@ -3845,15 +3981,6 @@ msgstr ""
msgid "BambooService|You must set up automatic revision labeling and a repository trigger in Bamboo."
msgstr ""
-msgid "BatchComments|Delete all pending comments"
-msgstr ""
-
-msgid "BatchComments|Discard review?"
-msgstr ""
-
-msgid "BatchComments|You're about to discard your review which will delete all of your pending comments. The deleted comments %{strong_start}cannot%{strong_end} be restored."
-msgstr ""
-
msgid "Be careful. Changing the project's namespace can have unintended side effects."
msgstr ""
@@ -3875,6 +4002,9 @@ msgstr ""
msgid "Bi-weekly code coverage"
msgstr ""
+msgid "Billable Users:"
+msgstr ""
+
msgid "Billing"
msgstr ""
@@ -3884,7 +4014,7 @@ msgstr ""
msgid "BillingPlans|@%{user_name} you are currently using the %{plan_name} plan."
msgstr ""
-msgid "BillingPlans|Congratulations, your new trial is activated"
+msgid "BillingPlans|Congratulations, your free trial is activated."
msgstr ""
msgid "BillingPlans|If you would like to downgrade your plan please contact %{support_link_start}Customer Support%{support_link_end}."
@@ -3947,6 +4077,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Block user"
+msgstr ""
+
msgid "Blocked"
msgstr ""
@@ -3962,31 +4095,37 @@ msgstr ""
msgid "Blog"
msgstr ""
-msgid "Board name"
-msgstr ""
-
msgid "Board scope"
msgstr ""
msgid "Board scope affects which issues are displayed for anyone who visits this board"
msgstr ""
-msgid "BoardBlankState|Add default lists"
+msgid "Boards"
msgstr ""
-msgid "BoardBlankState|Add the following default lists to your Issue Board with one click:"
+msgid "Boards and Board Lists"
msgstr ""
-msgid "BoardBlankState|Nevermind, I'll use my own"
+msgid "Boards|An error occurred while creating the issue. Please try again."
msgstr ""
-msgid "BoardBlankState|Starting out with the default set of lists will get you right on the way to making the most of your board."
+msgid "Boards|An error occurred while creating the list. Please try again."
msgstr ""
-msgid "Boards"
+msgid "Boards|An error occurred while fetching issues. Please reload the page."
msgstr ""
-msgid "Boards and Board Lists"
+msgid "Boards|An error occurred while fetching the board issues. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching the board swimlanes. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while moving the issue. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while updating the list. Please try again."
msgstr ""
msgid "Boards|Collapse"
@@ -4013,7 +4152,7 @@ msgstr ""
msgid "Branch %{branch_name} was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr ""
-msgid "Branch has changed"
+msgid "Branch changed"
msgstr ""
msgid "Branch is already taken"
@@ -4319,6 +4458,9 @@ msgstr ""
msgid "CLOSED (MOVED)"
msgstr ""
+msgid "CODEOWNERS rule violation"
+msgstr ""
+
msgid "CONTRIBUTING"
msgstr ""
@@ -4349,9 +4491,6 @@ msgstr ""
msgid "Can't create snippet: %{err}"
msgstr ""
-msgid "Can't edit as source branch was deleted"
-msgstr ""
-
msgid "Can't fetch content for the blob: %{err}"
msgstr ""
@@ -4364,9 +4503,6 @@ msgstr ""
msgid "Can't load mermaid module: %{err}"
msgstr ""
-msgid "Can't remove group members without group managed account"
-msgstr ""
-
msgid "Can't scan the code?"
msgstr ""
@@ -4409,6 +4545,9 @@ msgstr ""
msgid "Cannot create the abuse report. This user has been blocked."
msgstr ""
+msgid "Cannot enable shared runners because parent group does not allow it"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -4514,6 +4653,15 @@ msgstr ""
msgid "Change your password or recover your current one"
msgstr ""
+msgid "ChangeReviewer|Reviewer changed from %{old} to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Reviewer changed to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Unassigned"
+msgstr ""
+
msgid "ChangeTypeActionLabel|Pick into branch"
msgstr "Elekti en branĉon"
@@ -4553,6 +4701,9 @@ msgstr ""
msgid "Changes the title to \"%{title_param}\"."
msgstr ""
+msgid "Changes were successfully made."
+msgstr ""
+
msgid "Changes won't take place until the index is %{link_start}recreated%{link_end}."
msgstr ""
@@ -4958,6 +5109,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove variable"
+msgstr ""
+
msgid "CiVariables|Remove variable row"
msgstr ""
@@ -5036,9 +5190,6 @@ msgstr ""
msgid "Clear due date"
msgstr ""
-msgid "Clear input"
-msgstr ""
-
msgid "Clear recent searches"
msgstr ""
@@ -5087,6 +5238,9 @@ msgstr ""
msgid "Client authentication key password"
msgstr ""
+msgid "Client request timeout"
+msgstr ""
+
msgid "Clients"
msgstr ""
@@ -5171,6 +5325,27 @@ msgstr ""
msgid "Cluster type must be specificed for Stages::ClusterEndpointInserter"
msgstr ""
+msgid "ClusterAgents|Configuration"
+msgstr ""
+
+msgid "ClusterAgents|Connect your cluster with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate Kubernetes with a GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Name"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Agent also requires %{linkStart}enabling the Agent Server%{linkEnd}"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Kubernetes Agent allows an Infrastructure as Code, GitOps approach to integrating Kubernetes clusters with GitLab. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "ClusterAgent|This feature is only available for premium plans"
msgstr ""
@@ -5240,10 +5415,10 @@ msgstr ""
msgid "ClusterIntegration|All installed applications and related resources"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster."
+msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{linkStart}More information%{linkEnd}"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{startLink}More information%{endLink}"
+msgid "ClusterIntegration|Allow GitLab to manage namespaces and service accounts for this cluster."
msgstr ""
msgid "ClusterIntegration|Alternatively, "
@@ -5264,6 +5439,9 @@ msgstr ""
msgid "ClusterIntegration|An error occurred while trying to fetch zone machine types: %{error}"
msgstr ""
+msgid "ClusterIntegration|An unknown error occurred while attempting to connect to Kubernetes."
+msgstr ""
+
msgid "ClusterIntegration|Any project namespaces"
msgstr ""
@@ -5279,6 +5457,9 @@ msgstr ""
msgid "ClusterIntegration|Authenticate with Amazon Web Services"
msgstr ""
+msgid "ClusterIntegration|Authentication Error"
+msgstr ""
+
msgid "ClusterIntegration|Base domain"
msgstr ""
@@ -5297,13 +5478,22 @@ msgstr ""
msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}security group %{externalLinkIcon} %{endLink} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
+msgid "ClusterIntegration|Check your CA certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Check your cluster status"
+msgstr ""
+
+msgid "ClusterIntegration|Check your token"
+msgstr ""
+
+msgid "ClusterIntegration|Choose the %{linkStart}security group %{linkEnd} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}subnets %{externalLinkIcon} %{endLink} in your VPC where your worker nodes will run."
+msgid "ClusterIntegration|Choose the %{linkStart}subnets %{linkEnd} in your VPC where your worker nodes will run."
msgstr ""
-msgid "ClusterIntegration|Choose the worker node %{startLink}instance type %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Choose the worker node %{linkStart}instance type%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Choose which applications to install on your Kubernetes cluster."
@@ -5315,10 +5505,7 @@ msgstr ""
msgid "ClusterIntegration|Clear cluster cache"
msgstr ""
-msgid "ClusterIntegration|Clear the local cache of namespace and service accounts. This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
-msgstr ""
-
-msgid "ClusterIntegration|Cluster being created"
+msgid "ClusterIntegration|Clear the local cache of namespace and service accounts."
msgstr ""
msgid "ClusterIntegration|Cluster management project (alpha)"
@@ -5330,15 +5517,21 @@ msgstr ""
msgid "ClusterIntegration|Cluster_applications artifact too big. Maximum allowable size: %{human_size}"
msgstr ""
-msgid "ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters."
+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|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}"
+msgid "ClusterIntegration|Clusters connected with a certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Connect cluster with certificate"
msgstr ""
msgid "ClusterIntegration|Connect existing cluster"
msgstr ""
+msgid "ClusterIntegration|Connection Error"
+msgstr ""
+
msgid "ClusterIntegration|Copy API URL"
msgstr ""
@@ -5414,6 +5607,12 @@ msgstr ""
msgid "ClusterIntegration|Deletes all GitLab resources attached to this cluster during removal"
msgstr ""
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared."
+msgstr ""
+
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared. %{linkStart}More information%{linkEnd}"
+msgstr ""
+
msgid "ClusterIntegration|Did you know?"
msgstr ""
@@ -5483,6 +5682,9 @@ msgstr ""
msgid "ClusterIntegration|Fluentd is an open source data collector, which lets you unify the data collection and consumption for a better use and understanding of data. It requires at least one of the following logs to be successfully installed."
msgstr ""
+msgid "ClusterIntegration|GitLab Agent managed clusters"
+msgstr ""
+
msgid "ClusterIntegration|GitLab Container Network Policies"
msgstr ""
@@ -5495,6 +5697,12 @@ msgstr ""
msgid "ClusterIntegration|GitLab Runner connects to the repository and executes CI/CD jobs, pushing results back and deploying applications to production."
msgstr ""
+msgid "ClusterIntegration|GitLab failed to authenticate."
+msgstr ""
+
+msgid "ClusterIntegration|GitLab failed to connect to the cluster."
+msgstr ""
+
msgid "ClusterIntegration|GitLab-managed cluster"
msgstr ""
@@ -5516,6 +5724,9 @@ msgstr ""
msgid "ClusterIntegration|Group cluster"
msgstr ""
+msgid "ClusterIntegration|HTTP Error"
+msgstr ""
+
msgid "ClusterIntegration|Helm Tiller"
msgstr ""
@@ -5549,7 +5760,10 @@ msgstr ""
msgid "ClusterIntegration|Instance type"
msgstr ""
-msgid "ClusterIntegration|Integrate Kubernetes cluster automation"
+msgid "ClusterIntegration|Integrate Kubernetes with a cluster certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Integrate with a cluster certificate"
msgstr ""
msgid "ClusterIntegration|Issuer Email"
@@ -5585,9 +5799,6 @@ msgstr ""
msgid "ClusterIntegration|Knative extends Kubernetes to provide a set of middleware components that are essential to build modern, source-centric, and container-based applications that can run anywhere: on premises, in the cloud, or even in a third-party data center."
msgstr ""
-msgid "ClusterIntegration|Kubernetes cluster"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes cluster is being created..."
msgstr ""
@@ -5600,9 +5811,6 @@ msgstr ""
msgid "ClusterIntegration|Kubernetes clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr ""
-msgid "ClusterIntegration|Kubernetes clusters can be used to deploy applications and to provide Review Apps for this project"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes version"
msgstr ""
@@ -5615,7 +5823,7 @@ msgstr ""
msgid "ClusterIntegration|Learn more about %{help_link_start}zones%{help_link_end}."
msgstr ""
-msgid "ClusterIntegration|Learn more about %{startLink}Regions %{externalLinkIcon}%{endLink}."
+msgid "ClusterIntegration|Learn more about %{linkStart}Regions%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Learn more about Kubernetes"
@@ -5660,12 +5868,18 @@ msgstr ""
msgid "ClusterIntegration|Machine type"
msgstr ""
+msgid "ClusterIntegration|Make sure your API endpoint is correct"
+msgstr ""
+
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create Kubernetes clusters"
msgstr ""
msgid "ClusterIntegration|Manage your Kubernetes cluster by visiting %{provider_link}"
msgstr ""
+msgid "ClusterIntegration|Namespace per environment"
+msgstr ""
+
msgid "ClusterIntegration|No IAM Roles found"
msgstr ""
@@ -5711,6 +5925,9 @@ msgstr ""
msgid "ClusterIntegration|No zones matched your search"
msgstr ""
+msgid "ClusterIntegration|Node calculations use the Kubernetes Metrics API. Make sure your cluster has metrics installed"
+msgstr ""
+
msgid "ClusterIntegration|Number of nodes"
msgstr ""
@@ -5753,6 +5970,9 @@ msgstr ""
msgid "ClusterIntegration|RBAC-enabled cluster"
msgstr ""
+msgid "ClusterIntegration|Read our %{linkStart}help page%{linkEnd} on Kubernetes cluster integration."
+msgstr ""
+
msgid "ClusterIntegration|Read our %{link_start}help page%{link_end} on Kubernetes cluster integration."
msgstr ""
@@ -5855,7 +6075,7 @@ msgstr ""
msgid "ClusterIntegration|Select a VPC to choose a subnet"
msgstr ""
-msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{linkStart}Amazon Web Services %{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select a network to choose a subnetwork"
@@ -5888,7 +6108,7 @@ msgstr ""
msgid "ClusterIntegration|Select project to choose zone"
msgstr ""
-msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select zone"
@@ -5978,9 +6198,18 @@ msgstr ""
msgid "ClusterIntegration|There was a problem authenticating with your cluster. Please ensure your CA Certificate and Token are valid."
msgstr ""
+msgid "ClusterIntegration|There was an HTTP error when connecting to your cluster."
+msgstr ""
+
msgid "ClusterIntegration|This account must have permissions to create a Kubernetes cluster in the %{link_to_container_project} specified below"
msgstr ""
+msgid "ClusterIntegration|This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
+msgstr ""
+
+msgid "ClusterIntegration|This is necessary to clear existing environment-namespace associations from clusters previously managed by GitLab."
+msgstr ""
+
msgid "ClusterIntegration|This option will allow you to install applications on RBAC clusters."
msgstr ""
@@ -6005,9 +6234,21 @@ msgstr ""
msgid "ClusterIntegration|To use a new project, first create one on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}."
msgstr ""
+msgid "ClusterIntegration|Troubleshooting tips:"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Authenticate"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Connect"
+msgstr ""
+
msgid "ClusterIntegration|Uninstall %{appTitle}"
msgstr ""
+msgid "ClusterIntegration|Unknown Error"
+msgstr ""
+
msgid "ClusterIntegration|Update %{appTitle}"
msgstr ""
@@ -6068,7 +6309,7 @@ msgstr ""
msgid "ClusterIntegration|Your cluster API is unreachable. Please ensure your API URL is correct."
msgstr ""
-msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Zone"
@@ -6188,6 +6429,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse all threads"
+msgstr ""
+
msgid "Collapse approvers"
msgstr ""
@@ -6337,7 +6581,7 @@ msgstr "Enmetita de"
msgid "Commit…"
msgstr ""
-msgid "Company"
+msgid "Community forum"
msgstr ""
msgid "Company name"
@@ -6346,6 +6590,9 @@ msgstr ""
msgid "Compare"
msgstr "Kompari"
+msgid "Compare %{oldCommitId}...%{newCommitId}"
+msgstr ""
+
msgid "Compare Git revisions"
msgstr ""
@@ -6361,6 +6608,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare submodule commit revisions"
+msgstr ""
+
msgid "Compare with previous version"
msgstr ""
@@ -6496,6 +6746,9 @@ msgstr ""
msgid "Configure the way a user creates a new account."
msgstr ""
+msgid "Configure which lists are shown for anyone who visits this board"
+msgstr ""
+
msgid "Confirm"
msgstr ""
@@ -6721,6 +6974,9 @@ msgstr[1] ""
msgid "ContainerRegistry|Set cleanup policy"
msgstr ""
+msgid "ContainerRegistry|Some tags were not deleted"
+msgstr ""
+
msgid "ContainerRegistry|Something went wrong while fetching the cleanup policy."
msgstr ""
@@ -6760,6 +7016,9 @@ msgstr ""
msgid "ContainerRegistry|Tags with names matching this regex pattern will %{italicStart}expire:%{italicEnd}"
msgstr ""
+msgid "ContainerRegistry|The cleanup policy timed out before it could delete all tags. An administrator can %{adminLinkStart}manually run cleanup now%{adminLinkEnd} or you can wait for the cleanup policy to automatically run again. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "ContainerRegistry|The last tag related to this image was recently removed. This empty image and any associated data will be automatically removed as part of the regular Garbage Collection process. If you have any questions, contact your administrator."
msgstr ""
@@ -6892,6 +7151,9 @@ msgstr ""
msgid "Contributions per group member"
msgstr ""
+msgid "Contributor"
+msgstr ""
+
msgid "Contributors"
msgstr "Kontribuantoj"
@@ -7021,6 +7283,9 @@ msgstr ""
msgid "Could not change HEAD: branch '%{branch}' does not exist"
msgstr ""
+msgid "Could not commit. An unexpected error occurred."
+msgstr ""
+
msgid "Could not connect to FogBugz, check your URL"
msgstr ""
@@ -7060,6 +7325,9 @@ msgstr ""
msgid "Could not find iteration"
msgstr ""
+msgid "Could not load instance counts. Please refresh the page to try again."
+msgstr ""
+
msgid "Could not remove the trigger."
msgstr ""
@@ -7084,10 +7352,10 @@ msgstr ""
msgid "Could not save prometheus manual configuration"
msgstr ""
-msgid "Could not udpdate wiki page"
+msgid "Could not update the LDAP settings"
msgstr ""
-msgid "Could not update the LDAP settings"
+msgid "Could not update wiki page"
msgstr ""
msgid "Could not upload your designs as one or more files uploaded are not supported."
@@ -7745,6 +8013,9 @@ msgstr ""
msgid "DastProfiles|Are you sure you want to delete this profile?"
msgstr ""
+msgid "DastProfiles|Could not create site validation token. Please refresh the page, or try again later."
+msgstr ""
+
msgid "DastProfiles|Could not create the scanner profile. Please try again."
msgstr ""
@@ -7769,6 +8040,12 @@ msgstr ""
msgid "DastProfiles|Could not fetch site profiles. Please refresh the page, or try again later."
msgstr ""
+msgid "DastProfiles|Could not retrieve site validation status. Please refresh the page, or try again later."
+msgstr ""
+
+msgid "DastProfiles|Could not update the scanner profile. Please try again."
+msgstr ""
+
msgid "DastProfiles|Could not update the site profile. Please try again."
msgstr ""
@@ -7784,7 +8061,7 @@ msgstr ""
msgid "DastProfiles|Download validation text file"
msgstr ""
-msgid "DastProfiles|Edit feature will come soon. Please create a new profile if changes needed"
+msgid "DastProfiles|Edit scanner profile"
msgstr ""
msgid "DastProfiles|Edit site profile"
@@ -7817,6 +8094,9 @@ msgstr ""
msgid "DastProfiles|No profiles created yet"
msgstr ""
+msgid "DastProfiles|Passive"
+msgstr ""
+
msgid "DastProfiles|Please enter a valid URL format, ex: http://www.example.com/home"
msgstr ""
@@ -7832,6 +8112,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan mode"
+msgstr ""
+
msgid "DastProfiles|Scanner Profile"
msgstr ""
@@ -7871,10 +8154,10 @@ msgstr ""
msgid "DastProfiles|Text file validation"
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
+msgid "DastProfiles|The maximum number of minutes allowed for the spider to traverse the site."
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the spider to traverse the site."
+msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
msgstr ""
msgid "DastProfiles|Validate"
@@ -7907,6 +8190,9 @@ msgstr ""
msgid "Date picker"
msgstr ""
+msgid "Date range"
+msgstr ""
+
msgid "Date range cannot exceed %{maxDateRange} days."
msgstr ""
@@ -7931,6 +8217,9 @@ msgstr ""
msgid "Days to merge"
msgstr ""
+msgid "Dear Administrator,"
+msgstr ""
+
msgid "Debug"
msgstr ""
@@ -8042,12 +8331,18 @@ msgstr ""
msgid "Delete"
msgstr "Forigi"
+msgid "Delete %{name}"
+msgstr ""
+
msgid "Delete Comment"
msgstr ""
msgid "Delete Snippet"
msgstr ""
+msgid "Delete Value Stream"
+msgstr ""
+
msgid "Delete account"
msgstr ""
@@ -8069,9 +8364,6 @@ msgstr ""
msgid "Delete label: %{label_name} ?"
msgstr ""
-msgid "Delete license"
-msgstr ""
-
msgid "Delete list"
msgstr ""
@@ -8147,15 +8439,6 @@ msgstr ""
msgid "Deleting a project places it into a read-only state until %{date}, at which point the project will be permanently deleted. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "Deleting the license failed."
-msgstr ""
-
-msgid "Deleting the license failed. The license was not found."
-msgstr ""
-
-msgid "Deleting the license failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "Deleting the project will delete its repository and all related resources including issues, merge requests etc."
msgstr ""
@@ -8651,7 +8934,10 @@ msgstr ""
msgid "DesignManagement|The maximum number of designs allowed to be uploaded is %{upload_limit}. Please try again."
msgstr ""
-msgid "DesignManagement|To upload designs, you'll need to enable LFS. %{requirements_link_start}More information%{requirements_link_end}"
+msgid "DesignManagement|There was an error moving your designs. Please upload your designs below."
+msgstr ""
+
+msgid "DesignManagement|To upload designs, you'll need to enable LFS and have admin enable hashed storage. %{requirements_link_start}More information%{requirements_link_end}"
msgstr ""
msgid "DesignManagement|Unresolve thread"
@@ -8663,6 +8949,9 @@ msgstr ""
msgid "DesignManagement|Upload skipped."
msgstr ""
+msgid "DesignManagement|Your designs are being copied and are on their way… Please refresh to update."
+msgstr ""
+
msgid "DesignManagement|and %{moreCount} more."
msgstr ""
@@ -8720,6 +9009,9 @@ msgstr ""
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
+msgid "Direct member"
+msgstr ""
+
msgid "Direction"
msgstr ""
@@ -8768,9 +9060,6 @@ msgstr ""
msgid "Discard draft"
msgstr ""
-msgid "Discard review"
-msgstr ""
-
msgid "DiscordService|Discord Notifications"
msgstr ""
@@ -8839,10 +9128,10 @@ msgstr ""
msgid "Dismiss Merge Request promotion"
msgstr ""
-msgid "Dismiss Selected"
+msgid "Dismiss Value Stream Analytics introduction box"
msgstr ""
-msgid "Dismiss Value Stream Analytics introduction box"
+msgid "Dismiss selected"
msgstr ""
msgid "Dismiss trial promotion"
@@ -8893,9 +9182,6 @@ msgstr ""
msgid "Documents reindexed: %{processed_documents} (%{percentage}%%)"
msgstr ""
-msgid "Doing"
-msgstr ""
-
msgid "Domain"
msgstr ""
@@ -9091,9 +9377,6 @@ msgstr ""
msgid "Edit environment"
msgstr ""
-msgid "Edit file"
-msgstr ""
-
msgid "Edit files in the editor and commit changes here"
msgstr ""
@@ -9106,6 +9389,12 @@ msgstr ""
msgid "Edit identity for %{user_name}"
msgstr ""
+msgid "Edit in Web IDE"
+msgstr ""
+
+msgid "Edit in single-file editor"
+msgstr ""
+
msgid "Edit issues"
msgstr ""
@@ -9133,10 +9422,10 @@ msgstr ""
msgid "Editing"
msgstr ""
-msgid "Elasticsearch"
+msgid "Elasticsearch AWS IAM credentials"
msgstr ""
-msgid "Elasticsearch AWS IAM credentials"
+msgid "Elasticsearch HTTP client timeout value in seconds."
msgstr ""
msgid "Elasticsearch indexing restrictions"
@@ -9145,9 +9434,6 @@ msgstr ""
msgid "Elasticsearch indexing started"
msgstr ""
-msgid "Elasticsearch integration. Elasticsearch AWS IAM."
-msgstr ""
-
msgid "Elasticsearch reindexing is already in progress"
msgstr ""
@@ -9175,9 +9461,6 @@ msgstr ""
msgid "Email Notification"
msgstr ""
-msgid "Email address"
-msgstr ""
-
msgid "Email could not be sent"
msgstr ""
@@ -9241,6 +9524,9 @@ msgstr ""
msgid "Emails sent from Service Desk will have this name"
msgstr ""
+msgid "Emails sent to %{email} will still be supported"
+msgstr ""
+
msgid "Emails separated by comma"
msgstr ""
@@ -9274,9 +9560,18 @@ msgstr ""
msgid "Enable"
msgstr ""
+msgid "Enable %{link_start}Gitpod%{link_end} integration to launch a development environment in your browser directly from GitLab."
+msgstr ""
+
msgid "Enable Auto DevOps"
msgstr ""
+msgid "Enable Gitpod"
+msgstr ""
+
+msgid "Enable Gitpod?"
+msgstr ""
+
msgid "Enable HTML emails"
msgstr ""
@@ -9406,9 +9701,6 @@ msgstr ""
msgid "Encountered an error while rendering: %{err}"
msgstr ""
-msgid "End date"
-msgstr ""
-
msgid "Ends at (UTC)"
msgstr ""
@@ -9568,7 +9860,7 @@ msgstr ""
msgid "EnvironmentsDashboard|The environments dashboard provides a summary of each project's environments' status, including pipeline and alert statuses."
msgstr ""
-msgid "EnvironmentsDashboard|This dashboard displays a maximum of 7 projects and 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
+msgid "EnvironmentsDashboard|This dashboard displays 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
msgstr ""
msgid "Environments|An error occurred while canceling the auto stop, please try again"
@@ -9889,6 +10181,9 @@ msgstr ""
msgid "Error deleting project. Check logs for error details."
msgstr ""
+msgid "Error fetching burnup chart data"
+msgstr ""
+
msgid "Error fetching diverging counts for branches. Please try again."
msgstr ""
@@ -9967,6 +10262,9 @@ msgstr ""
msgid "Error occurred when saving assignees"
msgstr ""
+msgid "Error occurred when saving reviewers"
+msgstr ""
+
msgid "Error occurred when toggling the notification subscription"
msgstr ""
@@ -10219,10 +10517,13 @@ msgstr ""
msgid "Expand all"
msgstr ""
-msgid "Expand approvers"
+msgid "Expand all files"
msgstr ""
-msgid "Expand dropdown"
+msgid "Expand all threads"
+msgstr ""
+
+msgid "Expand approvers"
msgstr ""
msgid "Expand milestones"
@@ -10393,6 +10694,9 @@ msgstr ""
msgid "Failed to create Merge Request. Please try again."
msgstr ""
+msgid "Failed to create To-Do for the design."
+msgstr ""
+
msgid "Failed to create a branch for this issue. Please try again."
msgstr ""
@@ -10432,6 +10736,12 @@ msgstr ""
msgid "Failed to load authors. Please try again."
msgstr ""
+msgid "Failed to load branches. Please try again."
+msgstr ""
+
+msgid "Failed to load deploy keys."
+msgstr ""
+
msgid "Failed to load emoji list."
msgstr ""
@@ -10447,6 +10757,9 @@ msgstr ""
msgid "Failed to load groups & users."
msgstr ""
+msgid "Failed to load groups, users and deploy keys."
+msgstr ""
+
msgid "Failed to load labels. Please try again."
msgstr ""
@@ -10456,6 +10769,12 @@ msgstr ""
msgid "Failed to load related branches"
msgstr ""
+msgid "Failed to load sidebar confidential toggle"
+msgstr ""
+
+msgid "Failed to load sidebar lock status"
+msgstr ""
+
msgid "Failed to load stacktrace."
msgstr ""
@@ -10483,6 +10802,9 @@ msgstr ""
msgid "Failed to publish issue on status page."
msgstr ""
+msgid "Failed to remove To-Do for the design."
+msgstr ""
+
msgid "Failed to remove a Zoom meeting"
msgstr ""
@@ -10525,6 +10847,9 @@ msgstr ""
msgid "Failed to signing using smartcard authentication"
msgstr ""
+msgid "Failed to toggle To-Do for the design."
+msgstr ""
+
msgid "Failed to update branch!"
msgstr ""
@@ -10638,7 +10963,7 @@ msgstr ""
msgid "FeatureFlags|Edit User List"
msgstr ""
-msgid "FeatureFlags|Enable features for specific users and specific environments by defining feature flag strategies."
+msgid "FeatureFlags|Enable features for specific users and environments by configuring feature flag strategies."
msgstr ""
msgid "FeatureFlags|Environment Spec"
@@ -10698,7 +11023,7 @@ msgstr ""
msgid "FeatureFlags|Include additional user IDs"
msgstr ""
-msgid "FeatureFlags|Install a %{docs_link_anchored_start}compatible client library%{docs_link_anchored_end} and specify the API URL, application name, and instance ID during the configuration setup. %{docs_link_start}More Information%{docs_link_end}"
+msgid "FeatureFlags|Install a %{docsLinkAnchoredStart}compatible client library%{docsLinkAnchoredEnd} and specify the API URL, application name, and instance ID during the configuration setup. %{docsLinkStart}More Information%{docsLinkEnd}"
msgstr ""
msgid "FeatureFlags|Instance ID"
@@ -10710,6 +11035,9 @@ msgstr ""
msgid "FeatureFlags|Loading feature flags"
msgstr ""
+msgid "FeatureFlags|Loading user lists"
+msgstr ""
+
msgid "FeatureFlags|More information"
msgstr ""
@@ -10728,7 +11056,7 @@ msgstr ""
msgid "FeatureFlags|New feature flag"
msgstr ""
-msgid "FeatureFlags|New list"
+msgid "FeatureFlags|New user list"
msgstr ""
msgid "FeatureFlags|Percent of users"
@@ -10767,6 +11095,9 @@ msgstr ""
msgid "FeatureFlags|There was an error fetching the feature flags."
msgstr ""
+msgid "FeatureFlags|There was an error fetching the user lists."
+msgstr ""
+
msgid "FeatureFlags|There was an error retrieving user lists"
msgstr ""
@@ -10782,6 +11113,9 @@ msgstr ""
msgid "FeatureFlags|User List"
msgstr ""
+msgid "FeatureFlags|User Lists"
+msgstr ""
+
msgid "FeatureFlag|List"
msgstr ""
@@ -10809,15 +11143,6 @@ msgstr ""
msgid "Fetching incoming email"
msgstr ""
-msgid "Fetching licenses failed."
-msgstr ""
-
-msgid "Fetching licenses failed. The request endpoint was not found."
-msgstr ""
-
-msgid "Fetching licenses failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "File"
msgstr ""
@@ -10920,12 +11245,21 @@ msgstr ""
msgid "Filter by status"
msgstr ""
+msgid "Filter by test cases that are currently archived."
+msgstr ""
+
+msgid "Filter by test cases that are currently opened."
+msgstr ""
+
msgid "Filter by two-factor authentication"
msgstr ""
msgid "Filter by user"
msgstr ""
+msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
+msgstr ""
+
msgid "Filter pipelines"
msgstr ""
@@ -10941,7 +11275,7 @@ msgstr ""
msgid "Filter results..."
msgstr ""
-msgid "Filter your projects by name"
+msgid "Filter your repositories by name"
msgstr ""
msgid "Filter..."
@@ -10950,7 +11284,7 @@ msgstr ""
msgid "Find File"
msgstr ""
-msgid "Find bugs in your code with coverage-guided fuzzing"
+msgid "Find bugs in your code with coverage-guided fuzzing."
msgstr ""
msgid "Find by path"
@@ -10977,9 +11311,6 @@ msgstr ""
msgid "Finish editing this message first!"
msgstr ""
-msgid "Finish review"
-msgstr ""
-
msgid "Finish setting up your dedicated account for %{group_name}."
msgstr ""
@@ -11049,6 +11380,9 @@ msgstr ""
msgid "Footer message"
msgstr ""
+msgid "For a faster browsing experience, some files are collapsed by default."
+msgstr ""
+
msgid "For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
@@ -11058,6 +11392,9 @@ msgstr ""
msgid "For more info, read the documentation."
msgstr ""
+msgid "For more information on how the number of active users is calculated, see the %{self_managed_subscriptions_doc_link} documentation."
+msgstr ""
+
msgid "For more information, go to the "
msgstr ""
@@ -11196,6 +11533,9 @@ msgstr ""
msgid "Generate new token"
msgstr ""
+msgid "Generic package file size in bytes"
+msgstr ""
+
msgid "Geo"
msgstr ""
@@ -11457,6 +11797,9 @@ msgstr ""
msgid "Geo|Please refer to Geo Troubleshooting."
msgstr ""
+msgid "Geo|Primary node"
+msgstr ""
+
msgid "Geo|Project"
msgstr ""
@@ -11499,6 +11842,9 @@ msgstr ""
msgid "Geo|Review replication status, and resynchronize and reverify items with the primary node."
msgstr ""
+msgid "Geo|Secondary node"
+msgstr ""
+
msgid "Geo|Status"
msgstr ""
@@ -11538,6 +11884,9 @@ msgstr ""
msgid "Geo|URL must be a valid url (ex: https://gitlab.com)"
msgstr ""
+msgid "Geo|Undefined"
+msgstr ""
+
msgid "Geo|Unknown state"
msgstr ""
@@ -11613,10 +11962,16 @@ msgstr ""
msgid "GitHub import"
msgstr ""
+msgid "GitLab"
+msgstr ""
+
msgid "GitLab / Unsubscribe"
msgstr ""
-msgid "GitLab Enterprise Edition %{plan}"
+msgid "GitLab API"
+msgstr ""
+
+msgid "GitLab Billing Team."
msgstr ""
msgid "GitLab Group Runners can execute code for all the projects in this group."
@@ -11628,12 +11983,18 @@ msgstr ""
msgid "GitLab Issue"
msgstr ""
+msgid "GitLab Pages"
+msgstr ""
+
msgid "GitLab Service Desk is a simple way to allow people to create issues in your GitLab instance without needing their own user account. It provides a unique email address for end users to create issues in a project, and replies can be sent either through the GitLab interface or by email. End users will only see the thread through email."
msgstr ""
msgid "GitLab Shared Runners execute code of different projects on the same Runner unless you configure GitLab Runner Autoscale with MaxBuilds 1 (which it is on GitLab.com)."
msgstr ""
+msgid "GitLab Shell"
+msgstr ""
+
msgid "GitLab Support Bot"
msgstr ""
@@ -11643,7 +12004,7 @@ msgstr ""
msgid "GitLab User"
msgstr ""
-msgid "GitLab allows you to continue using your license even if you exceed the number of seats you purchased. You will be required to pay for these seats when you renew your license."
+msgid "GitLab Workhorse"
msgstr ""
msgid "GitLab commit"
@@ -11811,6 +12172,21 @@ msgstr ""
msgid "Gitlab Pages"
msgstr ""
+msgid "Gitpod"
+msgstr ""
+
+msgid "Gitpod|Add the URL to your Gitpod instance configured to read your GitLab projects."
+msgstr ""
+
+msgid "Gitpod|Enable Gitpod integration"
+msgstr ""
+
+msgid "Gitpod|Gitpod URL"
+msgstr ""
+
+msgid "Gitpod|e.g. https://gitpod.example.com"
+msgstr ""
+
msgid "Given access %{time_ago}"
msgstr ""
@@ -12318,9 +12694,6 @@ msgstr ""
msgid "GroupSAML|Valid SAML Response"
msgstr ""
-msgid "GroupSAML|With group managed accounts enabled, all the users without a group managed account will be excluded from the group."
-msgstr ""
-
msgid "GroupSAML|With prohibit outer forks flag enabled group members will be able to fork project only inside your group."
msgstr ""
@@ -12534,10 +12907,10 @@ msgstr ""
msgid "GroupsNew|Create group"
msgstr ""
-msgid "GroupsNew|GitLab group export"
+msgid "GroupsNew|Import"
msgstr ""
-msgid "GroupsNew|Import"
+msgid "GroupsNew|Import a GitLab group export file"
msgstr ""
msgid "GroupsNew|Import group"
@@ -12680,6 +13053,9 @@ msgid_plural "Hide charts"
msgstr[0] ""
msgstr[1] ""
+msgid "Hide comments on this file"
+msgstr ""
+
msgid "Hide details"
msgstr ""
@@ -12724,6 +13100,15 @@ msgstr ""
msgid "Highest role:"
msgstr ""
+msgid "HighlightBar|Alert events:"
+msgstr ""
+
+msgid "HighlightBar|Alert start time:"
+msgstr ""
+
+msgid "HighlightBar|Original alert:"
+msgstr ""
+
msgid "History"
msgstr ""
@@ -12901,6 +13286,9 @@ msgstr ""
msgid "If enabled, access to projects will be validated on an external service using their classification label."
msgstr ""
+msgid "If the number of active users exceeds the user limit, you will be charged for the number of %{users_over_license_link} at your next license reconciliation."
+msgstr ""
+
msgid "If there is no previous license or if the previous license has expired, some GitLab functionality will be blocked until a new, valid license is uploaded."
msgstr ""
@@ -12940,9 +13328,6 @@ msgstr ""
msgid "If your HTTP repository is not publicly accessible, add your credentials."
msgstr ""
-msgid "Iglu registry URL (optional)"
-msgstr ""
-
msgid "Ignore"
msgstr ""
@@ -12979,6 +13364,16 @@ msgstr ""
msgid "Import"
msgstr ""
+msgid "Import %d compatible repository"
+msgid_plural "Import %d compatible repositories"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Import %d repository"
+msgid_plural "Import %d repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Import CSV"
msgstr ""
@@ -12988,15 +13383,9 @@ msgstr ""
msgid "Import all compatible projects"
msgstr ""
-msgid "Import all compatible repositories"
-msgstr ""
-
msgid "Import all projects"
msgstr ""
-msgid "Import all repositories"
-msgstr ""
-
msgid "Import an exported GitLab project"
msgstr ""
@@ -13084,6 +13473,9 @@ msgstr ""
msgid "ImportProjects|Error importing repository %{project_safe_import_url} into %{project_full_path} - %{message}"
msgstr ""
+msgid "ImportProjects|Import repositories"
+msgstr ""
+
msgid "ImportProjects|Importing the project failed"
msgstr ""
@@ -13096,7 +13488,7 @@ msgstr ""
msgid "ImportProjects|Requesting your %{provider} repositories failed"
msgstr ""
-msgid "ImportProjects|Select the projects you want to import"
+msgid "ImportProjects|Select the repositories you want to import"
msgstr ""
msgid "ImportProjects|The remote data could not be imported."
@@ -13132,9 +13524,6 @@ msgstr ""
msgid "In order to enable Service Desk for your instance, you must first set up incoming email."
msgstr ""
-msgid "In order to gather accurate feature usage data, it can take 1 to 2 weeks to see your index."
-msgstr ""
-
msgid "In order to personalize your experience with GitLab%{br_tag}we would like to know a bit more about you."
msgstr ""
@@ -13165,18 +13554,30 @@ msgstr ""
msgid "IncidentManagement|Create incident"
msgstr ""
+msgid "IncidentManagement|Critical - S1"
+msgstr ""
+
msgid "IncidentManagement|Date created"
msgstr ""
msgid "IncidentManagement|Display your incidents in a dedicated view"
msgstr ""
+msgid "IncidentManagement|High - S2"
+msgstr ""
+
msgid "IncidentManagement|Incident"
msgstr ""
msgid "IncidentManagement|Incidents"
msgstr ""
+msgid "IncidentManagement|Low - S4"
+msgstr ""
+
+msgid "IncidentManagement|Medium - S3"
+msgstr ""
+
msgid "IncidentManagement|No incidents to display."
msgstr ""
@@ -13189,6 +13590,9 @@ msgstr ""
msgid "IncidentManagement|Published to status page"
msgstr ""
+msgid "IncidentManagement|Severity"
+msgstr ""
+
msgid "IncidentManagement|There are no closed incidents"
msgstr ""
@@ -13198,6 +13602,9 @@ msgstr ""
msgid "IncidentManagement|Unassigned"
msgstr ""
+msgid "IncidentManagement|Unknown"
+msgstr ""
+
msgid "IncidentManagement|Unpublished"
msgstr ""
@@ -13219,6 +13626,15 @@ msgstr ""
msgid "Incidents"
msgstr ""
+msgid "Incident|Alert details"
+msgstr ""
+
+msgid "Incident|Summary"
+msgstr ""
+
+msgid "Incident|There was an issue loading alert data. Please try again."
+msgstr ""
+
msgid "Include a Terms of Service agreement and Privacy Policy that all users must accept."
msgstr ""
@@ -13279,6 +13695,9 @@ msgstr ""
msgid "Information about additional Pages templates and how to install them can be found in our %{pages_getting_started_guide}."
msgstr ""
+msgid "Inherited"
+msgstr ""
+
msgid "Inherited:"
msgstr ""
@@ -13359,7 +13778,22 @@ msgstr ""
msgid "Instance administrators group already exists"
msgstr ""
-msgid "Instance license"
+msgid "InstanceStatistics|Groups"
+msgstr ""
+
+msgid "InstanceStatistics|Issues"
+msgstr ""
+
+msgid "InstanceStatistics|Merge Requests"
+msgstr ""
+
+msgid "InstanceStatistics|Pipelines"
+msgstr ""
+
+msgid "InstanceStatistics|Projects"
+msgstr ""
+
+msgid "InstanceStatistics|Users"
msgstr ""
msgid "Integration"
@@ -13371,6 +13805,12 @@ msgstr ""
msgid "Integrations"
msgstr ""
+msgid "Integrations|%{integration} settings saved and active."
+msgstr ""
+
+msgid "Integrations|%{integration} settings saved, but not active."
+msgstr ""
+
msgid "Integrations|All details"
msgstr ""
@@ -13380,6 +13820,12 @@ msgstr ""
msgid "Integrations|Comment settings:"
msgstr ""
+msgid "Integrations|Connection failed. Please check your settings."
+msgstr ""
+
+msgid "Integrations|Connection successful."
+msgstr ""
+
msgid "Integrations|Default settings are inherited from the group level."
msgstr ""
@@ -13395,6 +13841,15 @@ msgstr ""
msgid "Integrations|Includes commit title and branch"
msgstr ""
+msgid "Integrations|Projects using custom settings will not be impacted unless the project owner chooses to use instance-level defaults."
+msgstr ""
+
+msgid "Integrations|Save settings?"
+msgstr ""
+
+msgid "Integrations|Saving will update the default settings for all projects that are not using custom settings."
+msgstr ""
+
msgid "Integrations|Standard"
msgstr ""
@@ -13527,6 +13982,9 @@ msgstr ""
msgid "Invitation"
msgstr ""
+msgid "Invitation declined"
+msgstr ""
+
msgid "Invite"
msgstr ""
@@ -13578,6 +14036,42 @@ 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|%{linkStart}Read more%{linkEnd} about role permissions"
+msgstr ""
+
+msgid "InviteMembersModal|Access expiration date (optional)"
+msgstr ""
+
+msgid "InviteMembersModal|Cancel"
+msgstr ""
+
+msgid "InviteMembersModal|Choose a role permission"
+msgstr ""
+
+msgid "InviteMembersModal|GitLab member or Email address"
+msgstr ""
+
+msgid "InviteMembersModal|Invite"
+msgstr ""
+
+msgid "InviteMembersModal|Invite team members"
+msgstr ""
+
+msgid "InviteMembersModal|Search for members to invite"
+msgstr ""
+
+msgid "InviteMembersModal|User not invited. Feature coming soon!"
+msgstr ""
+
+msgid "InviteMembersModal|Users were succesfully added"
+msgstr ""
+
+msgid "InviteMembersModal|You're inviting members to the %{group_name} group"
+msgstr ""
+
+msgid "InviteMembers|Invite team members"
+msgstr ""
+
msgid "Invited"
msgstr ""
@@ -13632,10 +14126,13 @@ msgstr ""
msgid "Issue cannot be found."
msgstr ""
+msgid "Issue created from vulnerability %{vulnerability_link}"
+msgstr ""
+
msgid "Issue events"
msgstr ""
-msgid "Issue first depoloyed to production"
+msgid "Issue first deployed to production"
msgstr ""
msgid "Issue label"
@@ -13713,6 +14210,9 @@ msgstr ""
msgid "IssueTracker|Custom issue tracker"
msgstr ""
+msgid "IssueTracker|EWM work items tracker"
+msgstr ""
+
msgid "IssueTracker|Redmine issue tracker"
msgstr ""
@@ -13779,6 +14279,9 @@ msgstr ""
msgid "It looks like you have some draft commits in this branch."
msgstr ""
+msgid "It may be several days before you see feature usage data."
+msgstr ""
+
msgid "It must have a header row and at least two columns: the first column is the issue title and the second column is the issue description. The separator is automatically detected."
msgstr ""
@@ -14061,13 +14564,13 @@ msgstr ""
msgid "Join Zoom meeting"
msgstr ""
-msgid "Jul"
+msgid "Joined %{time_ago}"
msgstr ""
-msgid "July"
+msgid "Jul"
msgstr ""
-msgid "Jump to first unresolved thread"
+msgid "July"
msgstr ""
msgid "Jump to next unresolved thread"
@@ -14103,6 +14606,9 @@ msgstr ""
msgid "Keyboard shortcuts"
msgstr ""
+msgid "KeyboardKey|Ctrl+"
+msgstr ""
+
msgid "Keys"
msgstr ""
@@ -14151,6 +14657,9 @@ msgstr ""
msgid "LDAP Synchronization"
msgstr ""
+msgid "LDAP group settings"
+msgstr ""
+
msgid "LDAP settings"
msgstr ""
@@ -14160,6 +14669,9 @@ msgstr ""
msgid "LDAP sync in progress. This could take a few minutes. Refresh the page to see the changes."
msgstr ""
+msgid "LDAP synchronizations"
+msgstr ""
+
msgid "LFS"
msgstr ""
@@ -14240,7 +14752,16 @@ msgid_plural "Last %d days"
msgstr[0] "La lasta %d tago"
msgstr[1] "La lastaj %d tagoj"
-msgid "Last %{days} days"
+msgid "Last 2 weeks"
+msgstr ""
+
+msgid "Last 30 days"
+msgstr ""
+
+msgid "Last 60 days"
+msgstr ""
+
+msgid "Last 90 days"
msgstr ""
msgid "Last Accessed On"
@@ -14318,6 +14839,9 @@ msgstr ""
msgid "Last used on:"
msgstr ""
+msgid "Last week"
+msgstr ""
+
msgid "LastCommit|authored"
msgstr ""
@@ -14333,6 +14857,9 @@ msgstr ""
msgid "Latest pipeline for the most recent commit on this branch"
msgstr ""
+msgid "Launch a ready-to-code development environment for your project."
+msgstr ""
+
msgid "Lead"
msgstr ""
@@ -14713,6 +15240,9 @@ msgstr ""
msgid "List of all merge commits"
msgstr ""
+msgid "List options"
+msgstr ""
+
msgid "List settings"
msgstr ""
@@ -14725,9 +15255,6 @@ msgstr ""
msgid "List your Bitbucket Server repositories"
msgstr ""
-msgid "Lists"
-msgstr ""
-
msgid "Live preview"
msgstr ""
@@ -14974,6 +15501,12 @@ msgstr ""
msgid "Mark as done"
msgstr ""
+msgid "Mark as draft"
+msgstr ""
+
+msgid "Mark as ready"
+msgstr ""
+
msgid "Mark as resolved"
msgstr ""
@@ -14995,6 +15528,24 @@ msgstr ""
msgid "Markdown is supported"
msgstr ""
+msgid "MarkdownEditor|Add a link (%{modifierKey}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add a link (%{modifier_key}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifierKey}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifier_key}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifierKey}I)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifier_key}I)"
+msgstr ""
+
msgid "Marked For Deletion At - %{deletion_time}"
msgstr ""
@@ -15079,7 +15630,25 @@ msgstr ""
msgid "Max access level"
msgstr ""
-msgid "Max seats used"
+msgid "Max role"
+msgstr ""
+
+msgid "Max size 15 MB"
+msgstr ""
+
+msgid "Maximum Conan package file size in bytes"
+msgstr ""
+
+msgid "Maximum Maven package file size in bytes"
+msgstr ""
+
+msgid "Maximum NPM package file size in bytes"
+msgstr ""
+
+msgid "Maximum NuGet package file size in bytes"
+msgstr ""
+
+msgid "Maximum PyPI package file size in bytes"
msgstr ""
msgid "Maximum Users:"
@@ -15211,6 +15780,18 @@ msgstr ""
msgid "Members with access to %{strong_start}%{group_name}%{strong_end}"
msgstr ""
+msgid "Members|%{time} by %{user}"
+msgstr ""
+
+msgid "Members|Expired"
+msgstr ""
+
+msgid "Members|No expiration set"
+msgstr ""
+
+msgid "Members|in %{time}"
+msgstr ""
+
msgid "Memory Usage"
msgstr ""
@@ -15397,9 +15978,6 @@ msgstr ""
msgid "MergeRequests|Thread will be unresolved"
msgstr ""
-msgid "MergeRequests|Toggle comments for this file"
-msgstr ""
-
msgid "MergeRequests|View file @ %{commitId}"
msgstr ""
@@ -15460,6 +16038,9 @@ msgstr ""
msgid "Merging immediately isn't recommended as it may negatively impact the existing merge train. Read the %{docsLinkStart}documentation%{docsLinkEnd} for more information."
msgstr ""
+msgid "Message"
+msgstr ""
+
msgid "Messages"
msgstr ""
@@ -15845,18 +16426,12 @@ msgid_plural "Milestones"
msgstr[0] ""
msgstr[1] ""
-msgid "Milestone does not support burnup charts"
-msgstr ""
-
msgid "Milestone lists not available with your current license"
msgstr ""
msgid "Milestone lists show all issues from the selected milestone."
msgstr ""
-msgid "Milestone must have a start and due date"
-msgstr ""
-
msgid "MilestoneSidebar|Closed:"
msgstr ""
@@ -16223,6 +16798,9 @@ msgstr ""
msgid "Namespace"
msgstr ""
+msgid "Namespace ID:"
+msgstr ""
+
msgid "Namespace is empty"
msgstr ""
@@ -16307,6 +16885,9 @@ msgstr ""
msgid "NetworkPolicies|Allow all outbound traffic from %{selector} to %{ruleSelector} on %{ports}"
msgstr ""
+msgid "NetworkPolicies|Are you sure you want to delete this policy? This action cannot be undone."
+msgstr ""
+
msgid "NetworkPolicies|Choose whether to enforce this policy."
msgstr ""
@@ -16316,12 +16897,21 @@ msgstr ""
msgid "NetworkPolicies|Define this policy's location, conditions and actions."
msgstr ""
+msgid "NetworkPolicies|Delete policy"
+msgstr ""
+
+msgid "NetworkPolicies|Delete policy: %{policy}"
+msgstr ""
+
msgid "NetworkPolicies|Deny all traffic"
msgstr ""
msgid "NetworkPolicies|Description"
msgstr ""
+msgid "NetworkPolicies|Edit policy"
+msgstr ""
+
msgid "NetworkPolicies|Editor mode"
msgstr ""
@@ -16349,6 +16939,9 @@ msgstr ""
msgid "NetworkPolicies|Name"
msgstr ""
+msgid "NetworkPolicies|Namespace"
+msgstr ""
+
msgid "NetworkPolicies|Network Policy"
msgstr ""
@@ -16400,6 +16993,9 @@ msgstr ""
msgid "NetworkPolicies|Rules"
msgstr ""
+msgid "NetworkPolicies|Save changes"
+msgstr ""
+
msgid "NetworkPolicies|Something went wrong, failed to update policy"
msgstr ""
@@ -16412,6 +17008,9 @@ msgstr ""
msgid "NetworkPolicies|Traffic that does not match any rule will be blocked."
msgstr ""
+msgid "NetworkPolicies|Unable to parse policy"
+msgstr ""
+
msgid "NetworkPolicies|YAML editor"
msgstr ""
@@ -16525,6 +17124,9 @@ msgstr ""
msgid "New Snippet"
msgstr ""
+msgid "New Test Case"
+msgstr ""
+
msgid "New User"
msgstr ""
@@ -16624,6 +17226,9 @@ msgstr ""
msgid "New tag"
msgstr "Nova etikedo"
+msgid "New test case"
+msgstr ""
+
msgid "New users set to external"
msgstr ""
@@ -16696,7 +17301,7 @@ msgstr ""
msgid "No changes"
msgstr ""
-msgid "No changes between %{ref_start}%{source_branch}%{ref_end} and %{ref_start}%{target_branch}%{ref_end}"
+msgid "No changes between %{sourceBranch} and %{targetBranch}"
msgstr ""
msgid "No child epics match applied filters"
@@ -16711,6 +17316,9 @@ msgstr ""
msgid "No containers available"
msgstr ""
+msgid "No content to show"
+msgstr ""
+
msgid "No contributions"
msgstr ""
@@ -16786,9 +17394,6 @@ msgstr ""
msgid "No license. All rights reserved"
msgstr ""
-msgid "No licenses found."
-msgstr ""
-
msgid "No matches found"
msgstr ""
@@ -16801,6 +17406,9 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No members found"
+msgstr ""
+
msgid "No merge requests found"
msgstr ""
@@ -16822,6 +17430,9 @@ msgstr ""
msgid "No parent group"
msgstr ""
+msgid "No plan"
+msgstr ""
+
msgid "No pods available"
msgstr ""
@@ -16918,6 +17529,12 @@ msgstr ""
msgid "Not Implemented"
msgstr ""
+msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+msgstr ""
+
+msgid "Not all browsers support WebAuthn. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even from an unsupported browser."
+msgstr ""
+
msgid "Not all data has been processed yet, the accuracy of the chart for the selected timeframe is limited."
msgstr ""
@@ -17014,6 +17631,9 @@ msgstr ""
msgid "Notification settings saved"
msgstr ""
+msgid "NotificationEvent|Change reviewer merge request"
+msgstr ""
+
msgid "NotificationEvent|Close issue"
msgstr "Fermi problemon"
@@ -17176,10 +17796,7 @@ msgstr ""
msgid "On track"
msgstr ""
-msgid "OnDemandScans|Attached branch"
-msgstr ""
-
-msgid "OnDemandScans|Attached branch is where the scan job runs."
+msgid "OnDemandScans|Could not fetch scanner profiles. Please refresh the page, or try again later."
msgstr ""
msgid "OnDemandScans|Could not fetch site profiles. Please refresh the page, or try again later."
@@ -17188,6 +17805,9 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
+msgid "OnDemandScans|Create a new scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Create a new site profile"
msgstr ""
@@ -17200,6 +17820,9 @@ msgstr ""
msgid "OnDemandScans|New on-demand DAST scan"
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 ""
@@ -17209,16 +17832,10 @@ msgstr ""
msgid "OnDemandScans|On-demand scans run outside the DevOps cycle and find vulnerabilities in your projects. %{learnMoreLinkStart}Learn more%{learnMoreLinkEnd}"
msgstr ""
-msgid "OnDemandScans|Only a passive scan can be performed on demand."
-msgstr ""
-
-msgid "OnDemandScans|Passive"
-msgstr ""
-
msgid "OnDemandScans|Run scan"
msgstr ""
-msgid "OnDemandScans|Scan mode"
+msgid "OnDemandScans|Scanner profile"
msgstr ""
msgid "OnDemandScans|Scanner settings"
@@ -17230,9 +17847,15 @@ msgstr ""
msgid "OnDemandScans|Select one of the existing profiles"
msgstr ""
+msgid "OnDemandScans|Site profile"
+msgstr ""
+
msgid "OnDemandScans|Site profiles"
msgstr ""
+msgid "OnDemandScans|Use existing scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Use existing site profile"
msgstr ""
@@ -17331,9 +17954,6 @@ msgstr ""
msgid "Open Selection"
msgstr ""
-msgid "Open Web IDE"
-msgstr ""
-
msgid "Open comment type dropdown"
msgstr ""
@@ -17439,6 +18059,9 @@ msgstr ""
msgid "Origin"
msgstr ""
+msgid "Orphaned member"
+msgstr ""
+
msgid "Other Labels"
msgstr ""
@@ -17454,6 +18077,9 @@ msgstr ""
msgid "Other visibility settings have been disabled by the administrator."
msgstr ""
+msgid "Our documentation includes an example DevOps Score report."
+msgstr ""
+
msgid "Out-of-compliance with this project's policies and should be removed"
msgstr ""
@@ -17478,6 +18104,9 @@ msgstr ""
msgid "Overwrite diverged branches"
msgstr ""
+msgid "Owned by %{image_tag}"
+msgstr ""
+
msgid "Owned by anyone"
msgstr ""
@@ -17499,6 +18128,9 @@ msgstr ""
msgid "Package deleted successfully"
msgstr ""
+msgid "Package file size limits"
+msgstr ""
+
msgid "Package recipe already exists"
msgstr ""
@@ -17514,9 +18146,6 @@ msgstr ""
msgid "Package type must be PyPi"
msgstr ""
-msgid "Package was removed"
-msgstr ""
-
msgid "PackageRegistry|%{name} version %{version} was created %{datetime}"
msgstr ""
@@ -17658,12 +18287,18 @@ msgstr ""
msgid "PackageRegistry|NuGet Command"
msgstr ""
+msgid "PackageRegistry|Package Registry"
+msgstr ""
+
msgid "PackageRegistry|Pip Command"
msgstr ""
msgid "PackageRegistry|Pipeline %{link} triggered %{datetime} by %{author}"
msgstr ""
+msgid "PackageRegistry|Publish and share packages for a variety of common package managers. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "PackageRegistry|Published to the %{project} Package Registry %{datetime}"
msgstr ""
@@ -17763,6 +18398,9 @@ msgstr ""
msgid "Page not found"
msgstr ""
+msgid "Page settings"
+msgstr ""
+
msgid "Page was successfully deleted"
msgstr ""
@@ -17904,7 +18542,7 @@ msgstr ""
msgid "Paste issue link"
msgstr ""
-msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Don't use your private SSH key."
+msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Do not paste your private SSH key, as that can compromise your identity."
msgstr ""
msgid "Patch to apply"
@@ -17931,6 +18569,9 @@ msgstr ""
msgid "Pending"
msgstr ""
+msgid "Pending comments"
+msgstr ""
+
msgid "People without permission will never get a notification and won't be able to comment."
msgstr ""
@@ -18129,6 +18770,9 @@ msgstr ""
msgid "Pipelines|Build with confidence"
msgstr ""
+msgid "Pipelines|By revoking a trigger you will break any processes making use of it. Are you sure?"
+msgstr ""
+
msgid "Pipelines|CI Lint"
msgstr ""
@@ -18141,6 +18785,15 @@ msgstr ""
msgid "Pipelines|Continuous Integration can help catch bugs by running your tests automatically, while Continuous Deployment can help you deliver code to your product environment."
msgstr ""
+msgid "Pipelines|Copy trigger token"
+msgstr ""
+
+msgid "Pipelines|Description"
+msgstr ""
+
+msgid "Pipelines|Edit"
+msgstr ""
+
msgid "Pipelines|Get started with Pipelines"
msgstr ""
@@ -18156,15 +18809,27 @@ msgstr ""
msgid "Pipelines|It is recommended the code is reviewed thoroughly before running this pipeline with the parent project's CI resource."
msgstr ""
+msgid "Pipelines|Last Used"
+msgstr ""
+
msgid "Pipelines|Loading Pipelines"
msgstr ""
msgid "Pipelines|More Information"
msgstr ""
+msgid "Pipelines|No triggers have been created yet. Add one using the form above."
+msgstr ""
+
+msgid "Pipelines|Owner"
+msgstr ""
+
msgid "Pipelines|Project cache successfully reset."
msgstr ""
+msgid "Pipelines|Revoke"
+msgstr ""
+
msgid "Pipelines|Run Pipeline"
msgstr ""
@@ -18189,6 +18854,15 @@ msgstr ""
msgid "Pipelines|This project is not currently set up to run pipelines."
msgstr ""
+msgid "Pipelines|Token"
+msgstr ""
+
+msgid "Pipelines|Trigger user has insufficient permissions to project"
+msgstr ""
+
+msgid "Pipelines|invalid"
+msgstr ""
+
msgid "Pipelines|parent"
msgstr ""
@@ -18447,10 +19121,10 @@ msgstr ""
msgid "Please provide attributes to update"
msgstr ""
-msgid "Please refer to %{docs_url}"
+msgid "Please reach out if you have any questions and we'll be happy to assist."
msgstr ""
-msgid "Please retype the email address."
+msgid "Please refer to %{docs_url}"
msgstr ""
msgid "Please select"
@@ -18480,6 +19154,9 @@ msgstr ""
msgid "Please set a new password before proceeding."
msgstr ""
+msgid "Please share your feedback about %{featureName} %{linkStart}in this issue%{linkEnd} to help us improve the experience."
+msgstr ""
+
msgid "Please solve the reCAPTCHA"
msgstr ""
@@ -18783,6 +19460,9 @@ msgstr ""
msgid "Profiles| You are going to change the username %{currentUsernameBold} to %{newUsernameBold}. Profile and projects will be redirected to the %{newUsername} namespace but this redirect will expire once the %{currentUsername} namespace is registered by another user or group. Please update your Git repository remotes as soon as possible."
msgstr ""
+msgid "Profiles|%{provider} Active"
+msgstr ""
+
msgid "Profiles|@username"
msgstr ""
@@ -18834,7 +19514,7 @@ msgstr ""
msgid "Profiles|Commit email"
msgstr ""
-msgid "Profiles|Connect"
+msgid "Profiles|Connect %{provider}"
msgstr ""
msgid "Profiles|Connected Accounts"
@@ -18858,6 +19538,9 @@ msgstr ""
msgid "Profiles|Disconnect"
msgstr ""
+msgid "Profiles|Disconnect %{provider}"
+msgstr ""
+
msgid "Profiles|Do not show on profile"
msgstr ""
@@ -18882,7 +19565,7 @@ msgstr ""
msgid "Profiles|Full name"
msgstr ""
-msgid "Profiles|Give your individual key a title. This will be publically visible."
+msgid "Profiles|Give your individual key a title."
msgstr ""
msgid "Profiles|Include private contributions on my profile"
@@ -18972,7 +19655,7 @@ msgstr ""
msgid "Profiles|The maximum file size allowed is 200KB."
msgstr ""
-msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it?"
+msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it? It will be publicly visible."
msgstr ""
msgid "Profiles|This email will be displayed on your public profile"
@@ -19047,6 +19730,9 @@ msgstr ""
msgid "Profiles|You don't have access to delete this user."
msgstr ""
+msgid "Profiles|You must transfer ownership or delete groups you are an owner of before you can delete your account"
+msgstr ""
+
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
@@ -19635,6 +20321,9 @@ msgstr ""
msgid "ProjectTemplates|GitLab Cluster Management"
msgstr ""
+msgid "ProjectTemplates|Gitpod/Spring Petclinic"
+msgstr ""
+
msgid "ProjectTemplates|Go Micro"
msgstr ""
@@ -20244,6 +20933,9 @@ msgstr ""
msgid "Publish to status page"
msgstr ""
+msgid "Published"
+msgstr ""
+
msgid "Published on status page"
msgstr ""
@@ -20361,9 +21053,15 @@ msgstr ""
msgid "Quick range"
msgstr ""
+msgid "Quickly and easily edit multiple files in your project."
+msgstr ""
+
msgid "README"
msgstr ""
+msgid "Rails"
+msgstr ""
+
msgid "Rake Tasks Help"
msgstr ""
@@ -20483,10 +21181,13 @@ msgstr ""
msgid "Register Two-Factor Authenticator"
msgstr ""
-msgid "Register U2F device"
+msgid "Register Universal Two-Factor (U2F) Device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register WebAuthn Device"
+msgstr ""
+
+msgid "Register device"
msgstr ""
msgid "Register for GitLab"
@@ -20498,9 +21199,6 @@ msgstr ""
msgid "Register with two-factor app"
msgstr ""
-msgid "Registration"
-msgstr ""
-
msgid "Registration|Checkout"
msgstr ""
@@ -20617,9 +21315,6 @@ msgstr ""
msgid "Release|Something went wrong while saving the release details"
msgstr ""
-msgid "Remediated: needs review"
-msgstr ""
-
msgid "Remediations"
msgstr ""
@@ -20725,6 +21420,9 @@ msgstr ""
msgid "Remove priority"
msgstr ""
+msgid "Remove report"
+msgstr ""
+
msgid "Remove secondary node"
msgstr ""
@@ -20737,6 +21435,12 @@ msgstr ""
msgid "Remove time estimate"
msgstr ""
+msgid "Remove user & report"
+msgstr ""
+
+msgid "Remove user from group"
+msgstr ""
+
msgid "Removed"
msgstr ""
@@ -20818,9 +21522,6 @@ msgstr ""
msgid "Removes time estimate."
msgstr ""
-msgid "Removing license…"
-msgstr ""
-
msgid "Removing this group also removes all child projects, including archived projects, and their resources."
msgstr ""
@@ -20905,6 +21606,9 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
+msgid "Reported by %{reporter}"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -20991,6 +21695,27 @@ msgstr ""
msgid "Repositories"
msgstr ""
+msgid "Repositories Analytics"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download Historic Test Coverage Data"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download historic test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Historic Test Coverage Data is available in raw format (.csv) for further analysis."
+msgstr ""
+
+msgid "RepositoriesAnalytics|Test Code Coverage"
+msgstr ""
+
+msgid "RepositoriesAnalytics|There was an error fetching the projects."
+msgstr ""
+
msgid "Repository"
msgstr ""
@@ -21069,9 +21794,15 @@ msgstr ""
msgid "Request parameter %{param} is missing."
msgstr ""
+msgid "Request review from"
+msgstr ""
+
msgid "Request to link SAML account must be authorized"
msgstr ""
+msgid "Requested"
+msgstr ""
+
msgid "Requested %{time_ago}"
msgstr ""
@@ -21090,6 +21821,9 @@ msgstr ""
msgid "Requests to these domain(s)/address(es) on the local network will be allowed when local requests from hooks and services are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 or 127.0.0.0/28 are supported. Domain wildcards are not supported currently. Use comma, semicolon, or newline to separate multiple entries. The allowlist can hold a maximum of 1000 entries. Domains should use IDNA encoding. Ex: example.com, 192.168.1.1, 127.0.0.0/28, xn--itlab-j1a.com."
msgstr ""
+msgid "Require admin approval for new sign-ups"
+msgstr ""
+
msgid "Require all users in this group to setup Two-factor authentication"
msgstr ""
@@ -21217,9 +21951,6 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
-msgid "Resolved by %{resolvedByName}"
-msgstr ""
-
msgid "Resolves IP addresses once and uses them to submit requests"
msgstr ""
@@ -21339,6 +22070,14 @@ msgstr ""
msgid "ReviewApp|Enable Review App"
msgstr ""
+msgid "Reviewer"
+msgid_plural "%d Reviewers"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Reviewer(s)"
+msgstr ""
+
msgid "Reviewing"
msgstr ""
@@ -21378,6 +22117,9 @@ msgstr ""
msgid "Rook"
msgstr ""
+msgid "Ruby"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -21456,6 +22198,63 @@ msgstr ""
msgid "Runners page."
msgstr ""
+msgid "Runners|Active"
+msgstr ""
+
+msgid "Runners|Architecture"
+msgstr ""
+
+msgid "Runners|Can run untagged jobs"
+msgstr ""
+
+msgid "Runners|Description"
+msgstr ""
+
+msgid "Runners|Group"
+msgstr ""
+
+msgid "Runners|IP Address"
+msgstr ""
+
+msgid "Runners|Last contact"
+msgstr ""
+
+msgid "Runners|Locked to this project"
+msgstr ""
+
+msgid "Runners|Maximum job timeout"
+msgstr ""
+
+msgid "Runners|Name"
+msgstr ""
+
+msgid "Runners|Platform"
+msgstr ""
+
+msgid "Runners|Property Name"
+msgstr ""
+
+msgid "Runners|Protected"
+msgstr ""
+
+msgid "Runners|Revision"
+msgstr ""
+
+msgid "Runners|Shared"
+msgstr ""
+
+msgid "Runners|Specific"
+msgstr ""
+
+msgid "Runners|Tags"
+msgstr ""
+
+msgid "Runners|Value"
+msgstr ""
+
+msgid "Runners|Version"
+msgstr ""
+
msgid "Runners|You have used %{quotaUsed} out of %{quotaLimit} of your shared Runners pipeline minutes."
msgstr ""
@@ -21468,6 +22267,9 @@ msgstr ""
msgid "Runs a number of housekeeping tasks within the current repository, such as compressing file revisions and removing unreachable objects."
msgstr ""
+msgid "SAML"
+msgstr ""
+
msgid "SAML SSO"
msgstr ""
@@ -21519,6 +22321,9 @@ msgstr ""
msgid "Save"
msgstr ""
+msgid "Save %{name} size limits"
+msgstr ""
+
msgid "Save Changes"
msgstr ""
@@ -21549,9 +22354,6 @@ msgstr "Konservi ĉenstablan planon"
msgid "Save space and find tags in the Container Registry more easily. Enable the cleanup policy to remove stale tags and keep only the ones you need."
msgstr ""
-msgid "Save template"
-msgstr ""
-
msgid "Save variables"
msgstr ""
@@ -21594,9 +22396,6 @@ msgstr "Planado de la ĉenstabloj"
msgid "Scope"
msgstr ""
-msgid "Scope not supported with disabled 'users_search' feature!"
-msgstr ""
-
msgid "Scoped issue boards"
msgstr ""
@@ -21723,9 +22522,6 @@ msgstr ""
msgid "Search requirements"
msgstr ""
-msgid "Search results…"
-msgstr ""
-
msgid "Search users"
msgstr ""
@@ -21798,6 +22594,11 @@ msgid_plural "SearchResults|commits"
msgstr[0] ""
msgstr[1] ""
+msgid "SearchResults|epic"
+msgid_plural "SearchResults|epics"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "SearchResults|issue"
msgid_plural "SearchResults|issues"
msgstr[0] ""
@@ -21842,10 +22643,10 @@ msgstr ""
msgid "Seat Link is disabled, and cannot be configured through this form."
msgstr ""
-msgid "Seats currently in use"
+msgid "Seats usage data as of %{last_enqueue_time}"
msgstr ""
-msgid "Seats in license"
+msgid "Seats usage data is updated every day at 12:00pm UTC"
msgstr ""
msgid "Secondary"
@@ -21899,6 +22700,9 @@ msgstr ""
msgid "SecurityConfiguration|Available for on-demand DAST"
msgstr ""
+msgid "SecurityConfiguration|By default, all analyzers are applied in order to cover all languages across your project, and only run if the language is detected in the Merge Request."
+msgstr ""
+
msgid "SecurityConfiguration|Configure"
msgstr ""
@@ -21929,16 +22733,19 @@ msgstr ""
msgid "SecurityConfiguration|Manage"
msgstr ""
+msgid "SecurityConfiguration|More information"
+msgstr ""
+
msgid "SecurityConfiguration|Not enabled"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|Security Control"
+msgid "SecurityConfiguration|SAST Configuration"
msgstr ""
-msgid "SecurityConfiguration|See documentation"
+msgid "SecurityConfiguration|Security Control"
msgstr ""
msgid "SecurityConfiguration|Status"
@@ -21950,6 +22757,9 @@ msgstr ""
msgid "SecurityConfiguration|Using custom settings. You won't receive automatic updates on this variable. %{anchorStart}Restore to default%{anchorEnd}"
msgstr ""
+msgid "SecurityConfiguration|View history"
+msgstr ""
+
msgid "SecurityConfiguration|You can quickly enable all security scanning tools by enabling %{linkStart}Auto DevOps%{linkEnd}."
msgstr ""
@@ -22028,9 +22838,6 @@ msgstr ""
msgid "SecurityReports|Learn more about setting up your dashboard"
msgstr ""
-msgid "SecurityReports|Load more vulnerabilities"
-msgstr ""
-
msgid "SecurityReports|Monitor vulnerabilities in your code"
msgstr ""
@@ -22310,7 +23117,7 @@ msgstr ""
msgid "Select status"
msgstr ""
-msgid "Select strategy activation method"
+msgid "Select strategy activation method."
msgstr ""
msgid "Select subscription"
@@ -22325,7 +23132,7 @@ msgstr ""
msgid "Select the custom project template source group."
msgstr ""
-msgid "Select timeframe"
+msgid "Select the environment scope for this feature flag."
msgstr ""
msgid "Select timezone"
@@ -22574,6 +23381,9 @@ msgstr ""
msgid "Set iteration"
msgstr ""
+msgid "Set limit to 0 to allow any file size."
+msgstr ""
+
msgid "Set max session time for web terminal."
msgstr ""
@@ -22652,10 +23462,13 @@ msgstr ""
msgid "Set up a %{type} Runner manually"
msgstr ""
+msgid "Set up a hardware device as a second factor to sign in."
+msgstr ""
+
msgid "Set up assertions/attributes/claims (email, first_name, last_name) and NameID according to %{docsLinkStart}the documentation %{icon}%{docsLinkEnd}"
msgstr ""
-msgid "Set up new U2F device"
+msgid "Set up new device"
msgstr ""
msgid "Set up new password"
@@ -22724,6 +23537,9 @@ msgstr ""
msgid "Sets weight to %{weight}."
msgstr ""
+msgid "Setting this to 0 means using the system default timeout value."
+msgstr ""
+
msgid "Settings"
msgstr ""
@@ -22739,6 +23555,15 @@ msgstr ""
msgid "Severity"
msgstr ""
+msgid "SeverityWidget|Severity"
+msgstr ""
+
+msgid "SeverityWidget|Severity: %{severity}"
+msgstr ""
+
+msgid "SeverityWidget|There was an error while updating severity."
+msgstr ""
+
msgid "Shards (%{shards})"
msgstr ""
@@ -22784,6 +23609,9 @@ msgstr ""
msgid "Show all requirements."
msgstr ""
+msgid "Show all test cases."
+msgstr ""
+
msgid "Show archived projects"
msgstr ""
@@ -22796,6 +23624,9 @@ msgstr ""
msgid "Show comments"
msgstr ""
+msgid "Show comments on this file"
+msgstr ""
+
msgid "Show comments only"
msgstr ""
@@ -22841,6 +23672,12 @@ msgstr ""
msgid "Show parent subgroups"
msgstr ""
+msgid "Show the Closed list"
+msgstr ""
+
+msgid "Show the Open list"
+msgstr ""
+
msgid "Show whitespace changes"
msgstr ""
@@ -22884,9 +23721,6 @@ msgstr ""
msgid "Sidebar|Assign health status"
msgstr ""
-msgid "Sidebar|Change weight"
-msgstr ""
-
msgid "Sidebar|Health status"
msgstr ""
@@ -23070,6 +23904,9 @@ msgstr ""
msgid "Snippets|Add another file %{num}/%{total}"
msgstr ""
+msgid "Snippets|Authored %{time_ago} by %{author}"
+msgstr ""
+
msgid "Snippets|Delete file"
msgstr ""
@@ -23097,6 +23934,9 @@ msgstr ""
msgid "Solution"
msgstr ""
+msgid "Some changes are not shown"
+msgstr ""
+
msgid "Some child epics may be hidden due to applied filters"
msgstr ""
@@ -23463,6 +24303,12 @@ msgstr ""
msgid "Source (branch or tag)"
msgstr ""
+msgid "Source Branch"
+msgstr ""
+
+msgid "Source branch: %{source_branch_open}%{source_branch}%{source_branch_close}"
+msgstr ""
+
msgid "Source code"
msgstr "Kodo"
@@ -23628,9 +24474,6 @@ msgstr ""
msgid "Start and due date"
msgstr ""
-msgid "Start by choosing a group to see how your team is spending time. You can then drill down to the project level."
-msgstr ""
-
msgid "Start by choosing a group to start exploring the merge requests in that group. You can then proceed to filter by projects, labels, milestones and authors."
msgstr ""
@@ -23712,18 +24555,27 @@ msgstr ""
msgid "StaticSiteEditor|3. Assign a person to review and accept the merge request."
msgstr ""
+msgid "StaticSiteEditor|A link to view the merge request will appear once ready."
+msgstr ""
+
msgid "StaticSiteEditor|An error occurred while submitting your changes."
msgstr ""
msgid "StaticSiteEditor|Branch could not be created."
msgstr ""
+msgid "StaticSiteEditor|Copy update"
+msgstr ""
+
msgid "StaticSiteEditor|Could not commit the content changes."
msgstr ""
msgid "StaticSiteEditor|Could not create merge request."
msgstr ""
+msgid "StaticSiteEditor|Creating your merge request"
+msgstr ""
+
msgid "StaticSiteEditor|Incompatible file content"
msgstr ""
@@ -23745,6 +24597,9 @@ msgstr ""
msgid "StaticSiteEditor|View documentation"
msgstr ""
+msgid "StaticSiteEditor|You can set an assignee to get your changes reviewed and deployed once your merge request is created."
+msgstr ""
+
msgid "StaticSiteEditor|Your merge request has been created"
msgstr ""
@@ -23874,15 +24729,15 @@ msgstr ""
msgid "Submit %{humanized_resource_name}"
msgstr ""
-msgid "Submit Changes"
-msgstr ""
-
msgid "Submit a review"
msgstr ""
msgid "Submit as spam"
msgstr ""
+msgid "Submit changes"
+msgstr ""
+
msgid "Submit feedback"
msgstr ""
@@ -24036,6 +24891,9 @@ msgstr ""
msgid "Successfully deleted U2F device."
msgstr ""
+msgid "Successfully deleted WebAuthn device."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -24354,9 +25212,6 @@ msgstr ""
msgid "Template to append to all Service Desk issues"
msgstr ""
-msgid "Template was successfully saved."
-msgstr ""
-
msgid "Templates"
msgstr ""
@@ -24435,10 +25290,28 @@ msgid_plural "Test coverage: %d hits"
msgstr[0] ""
msgstr[1] ""
-msgid "Test failed."
+msgid "Test settings"
msgstr ""
-msgid "Test settings and save changes"
+msgid "TestCases|New Test Case"
+msgstr ""
+
+msgid "TestCases|New test case"
+msgstr ""
+
+msgid "TestCases|Search test cases"
+msgstr ""
+
+msgid "TestCases|Something went wrong while creating a test case."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching count of test cases."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching test cases list."
+msgstr ""
+
+msgid "TestCases|Submit test case"
msgstr ""
msgid "TestHooks|Ensure one of your projects has merge requests."
@@ -24504,6 +25377,9 @@ msgstr ""
msgid "Thank you for signing up for your free trial! You will get additional instructions in your inbox shortly."
msgstr ""
+msgid "Thank you for your business."
+msgstr ""
+
msgid "Thank you for your feedback!"
msgstr ""
@@ -24563,9 +25439,6 @@ msgstr ""
msgid "The URL to use for connecting to Elasticsearch. Use a comma-separated list to support clustering (e.g., \"http://localhost:9200, http://localhost:9201\")."
msgstr ""
-msgid "The Web IDE offers advanced syntax highlighting capabilities and more."
-msgstr ""
-
msgid "The X509 Certificate to use when mutual TLS is required to communicate with the external authorization service. If left blank, the server certificate is still validated when accessing over HTTPS."
msgstr ""
@@ -24676,6 +25549,9 @@ msgstr "La rilato de disbranĉigo estis forigita."
msgid "The form contains the following error:"
msgstr ""
+msgid "The form contains the following warning:"
+msgstr ""
+
msgid "The global settings require you to enable Two-Factor Authentication for your account."
msgstr ""
@@ -24790,9 +25666,6 @@ msgstr "La etapo de la plano montras la tempon de la antaÅ­a Åtupo Äis la alpu
msgid "The private key to use when a client certificate is provided. This value is encrypted at rest."
msgstr ""
-msgid "The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr "La etapo de eldonado montras la tutan tempon de la kreado de problemo Äis la disponigado en la publika versio. La datenoj aldoniÄos aÅ­tomate post kiam vi kompletigos plenan ciklon de ideo Äis realaĵo."
-
msgid "The project can be accessed by any logged in user."
msgstr "Ĉiu ensalutita uzanto havas atingon al la projekto"
@@ -24829,7 +25702,7 @@ msgstr ""
msgid "The remote repository is being updated..."
msgstr ""
-msgid "The repository can be commited to, and issues, comments and other entities can be created."
+msgid "The repository can be committed to, and issues, comments and other entities can be created."
msgstr ""
msgid "The repository for this project does not exist."
@@ -24883,9 +25756,6 @@ msgstr "La etapo de testado montras kiom da tempo necesas al „GitLab CI“ por
msgid "The time taken by each data entry gathered by that stage."
msgstr "La tempo, kiu estas necesa por ĉiu dateno kolektita de la etapo."
-msgid "The total stage shows the time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The update action will time out after %{number_of_minutes} minutes. For big repositories, use a clone/push combination."
msgstr ""
@@ -24949,6 +25819,9 @@ msgstr ""
msgid "There are no archived requirements"
msgstr ""
+msgid "There are no archived test cases"
+msgstr ""
+
msgid "There are no changes"
msgstr ""
@@ -24988,6 +25861,9 @@ msgstr ""
msgid "There are no open requirements"
msgstr ""
+msgid "There are no open test cases"
+msgstr ""
+
msgid "There are no packages yet"
msgstr ""
@@ -25000,6 +25876,9 @@ msgstr ""
msgid "There is a limit of %{ci_project_subscriptions_limit} subscriptions from or to a project."
msgstr ""
+msgid "There is already a To-Do for this design."
+msgstr ""
+
msgid "There is already a repository with that name on disk"
msgstr ""
@@ -25018,6 +25897,9 @@ msgstr ""
msgid "There was a problem communicating with your device."
msgstr ""
+msgid "There was a problem fetching branches."
+msgstr ""
+
msgid "There was a problem fetching groups."
msgstr ""
@@ -25246,9 +26128,15 @@ msgstr ""
msgid "This action can lead to data loss. To prevent accidental actions we ask you to confirm your intention."
msgstr ""
+msgid "This action cannot be undone, and will permanently delete the %{key} SSH key"
+msgstr ""
+
msgid "This action cannot be undone. You will lose the project's repository and all content: issues, merge requests, etc."
msgstr ""
+msgid "This action has been performed too many times. Try again later."
+msgstr ""
+
msgid "This action will %{strongOpen}permanently delete%{strongClose} %{codeOpen}%{project}%{codeClose} %{strongOpen}immediately%{strongClose}, including its repositories and all content: issues, merge requests, etc."
msgstr ""
@@ -25276,9 +26164,6 @@ msgstr ""
msgid "This board's scope is reduced"
msgstr ""
-msgid "This branch has changed since you started editing. Would you like to create a new branch?"
-msgstr ""
-
msgid "This chart could not be displayed"
msgstr ""
@@ -25405,15 +26290,9 @@ msgstr ""
msgid "This is a security log of important events involving your account."
msgstr ""
-msgid "This is the author's first Merge Request to this project."
-msgstr ""
-
msgid "This is the highest peak of users on your installation since the license started."
msgstr ""
-msgid "This is the maximum number of users that have existed at the same time since the license started. This is the minimum number of seats you will need to buy when you renew your license."
-msgstr ""
-
msgid "This is the number of currently active users on your installation, and this is the minimum number you need to purchase when you renew your license."
msgstr ""
@@ -25645,6 +26524,15 @@ msgstr ""
msgid "This user has no identities"
msgstr ""
+msgid "This user has previously committed to the %{name} project."
+msgstr ""
+
+msgid "This user has the %{access} role in the %{name} project."
+msgstr ""
+
+msgid "This user is the author of this %{noteable}."
+msgstr ""
+
msgid "This user will be the author of all events in the activity feed that are the result of an update, like new branches being created or new commits being pushed to existing branches."
msgstr ""
@@ -25675,6 +26563,9 @@ msgstr ""
msgid "Threat Monitoring"
msgstr ""
+msgid "ThreatMonitoring|All Environments"
+msgstr ""
+
msgid "ThreatMonitoring|Anomalous Requests"
msgstr ""
@@ -25702,9 +26593,6 @@ msgstr ""
msgid "ThreatMonitoring|Operations Per Second"
msgstr ""
-msgid "ThreatMonitoring|Overview"
-msgstr ""
-
msgid "ThreatMonitoring|Packet Activity"
msgstr ""
@@ -25723,6 +26611,9 @@ msgstr ""
msgid "ThreatMonitoring|Something went wrong, unable to fetch statistics"
msgstr ""
+msgid "ThreatMonitoring|Statistics"
+msgstr ""
+
msgid "ThreatMonitoring|The firewall is not installed or has been disabled. To view this data, ensure the web application firewall is installed and enabled for your cluster."
msgstr ""
@@ -26114,6 +27005,9 @@ msgstr ""
msgid "To update Snippets with multiple files, you must use the `files` parameter"
msgstr ""
+msgid "To use Gitpod you must first enable the feature in the integrations section of your %{user_prefs}."
+msgstr ""
+
msgid "To view all %{scannedResourcesCount} scanned URLs, please download the CSV file"
msgstr ""
@@ -26147,9 +27041,6 @@ msgstr ""
msgid "Toggle Sidebar"
msgstr ""
-msgid "Toggle all threads"
-msgstr ""
-
msgid "Toggle backtrace"
msgstr ""
@@ -26174,9 +27065,6 @@ msgstr ""
msgid "Toggle navigation"
msgstr ""
-msgid "Toggle project"
-msgstr ""
-
msgid "Toggle sidebar"
msgstr ""
@@ -26216,6 +27104,9 @@ msgstr ""
msgid "Too many projects enabled. You will need to manage them via the console or the API."
msgstr ""
+msgid "Too much data"
+msgstr ""
+
msgid "Topics (optional)"
msgstr ""
@@ -26234,6 +27125,9 @@ msgstr ""
msgid "Total cores (CPUs)"
msgstr ""
+msgid "Total days to completion"
+msgstr ""
+
msgid "Total issues"
msgstr ""
@@ -26330,6 +27224,9 @@ msgstr ""
msgid "Trending"
msgstr ""
+msgid "Trials|Create a new group to start your GitLab Gold trial."
+msgstr ""
+
msgid "Trials|Go back to GitLab"
msgstr ""
@@ -26339,6 +27236,15 @@ msgstr ""
msgid "Trials|You can always resume this process by selecting your avatar and choosing 'Start a Gold trial'"
msgstr ""
+msgid "Trials|You can apply your trial to a new group or an existing group."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group or your personal account."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group, an existing group, or your personal account."
+msgstr ""
+
msgid "Trials|You won't get a free trial right now but you can always resume this process by clicking on your avatar and choosing 'Start a free trial'"
msgstr ""
@@ -26408,6 +27314,9 @@ msgstr ""
msgid "Try using a different search term to find the file you are looking for."
msgstr ""
+msgid "Trying to communicate with your device. Plug it in (if needed) and press the button on the device now."
+msgstr ""
+
msgid "Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now."
msgstr ""
@@ -26495,6 +27404,12 @@ msgstr ""
msgid "URL or request ID"
msgstr ""
+msgid "USER %{user} WILL BE REMOVED! Are you sure?"
+msgstr ""
+
+msgid "USER WILL BE BLOCKED! Are you sure?"
+msgstr ""
+
msgid "UTC"
msgstr ""
@@ -26552,9 +27467,6 @@ msgstr ""
msgid "Unable to load the merge request widget. Try reloading the page."
msgstr ""
-msgid "Unable to resolve"
-msgstr ""
-
msgid "Unable to save iteration. Please try again"
msgstr ""
@@ -26603,6 +27515,9 @@ msgstr ""
msgid "Undo ignore"
msgstr ""
+msgid "Unexpected error"
+msgstr ""
+
msgid "Unfortunately, your email message to GitLab could not be processed."
msgstr ""
@@ -26636,6 +27551,9 @@ msgstr ""
msgid "Unknown response text"
msgstr ""
+msgid "Unless otherwise agreed to in writing with GitLab, by clicking \"Upload License\" you agree that your use of GitLab Software is subject to the %{eula_link_start}Terms of Service%{eula_link_end}."
+msgstr ""
+
msgid "Unlimited"
msgstr ""
@@ -27002,9 +27920,6 @@ msgstr ""
msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
msgstr ""
-msgid "Use a hardware device to add the second factor of authentication."
-msgstr ""
-
msgid "Use an one time password authenticator on your mobile device or computer to enable two-factor authentication (2FA)."
msgstr ""
@@ -27278,13 +28193,13 @@ msgstr ""
msgid "Users"
msgstr ""
-msgid "Users in License:"
+msgid "Users in License"
msgstr ""
-msgid "Users or groups set as approvers in the project's or merge request's settings."
+msgid "Users in License:"
msgstr ""
-msgid "Users outside of license"
+msgid "Users or groups set as approvers in the project's or merge request's settings."
msgstr ""
msgid "Users over License:"
@@ -27302,9 +28217,6 @@ msgstr ""
msgid "Users with a Guest role or those who don't belong to a Project or Group will not use a seat from your license."
msgstr ""
-msgid "Users with a Guest role or those who don't belong to any projects or groups don't count towards seats in use."
-msgstr ""
-
msgid "UsersSelect|%{name} + %{length} more"
msgstr ""
@@ -27344,9 +28256,6 @@ msgstr ""
msgid "Validations failed."
msgstr ""
-msgid "Validity"
-msgstr ""
-
msgid "Value"
msgstr ""
@@ -27365,6 +28274,9 @@ msgstr ""
msgid "Value Stream Name"
msgstr ""
+msgid "ValueStreamAnalyticsStage|We don't have enough data to show this stage."
+msgstr ""
+
msgid "ValueStreamAnalytics|%{days}d"
msgstr ""
@@ -27621,6 +28533,9 @@ msgstr ""
msgid "VisualReviewApp|Steps 1 and 2 (and sometimes 3) are performed once by the developer before requesting feedback. Steps 3 (if necessary), 4 is performed by the reviewer each time they perform a review."
msgstr ""
+msgid "Visualization"
+msgstr ""
+
msgid "Vulnerabilities"
msgstr ""
@@ -27648,34 +28563,31 @@ msgstr ""
msgid "VulnerabilityChart|Severity"
msgstr ""
-msgid "VulnerabilityManagement|A true-positive and will fix"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Change status"
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|Confirm"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Confirmed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
-msgstr ""
-
-msgid "VulnerabilityManagement|Detected %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|A true-positive and will fix"
msgstr ""
-msgid "VulnerabilityManagement|Dismiss"
+msgid "VulnerabilityManagement|Change status"
msgstr ""
-msgid "VulnerabilityManagement|Dismissed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
msgstr ""
-msgid "VulnerabilityManagement|Resolved"
+msgid "VulnerabilityManagement|Detected"
msgstr ""
-msgid "VulnerabilityManagement|Resolved %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Needs triage"
msgstr ""
msgid "VulnerabilityManagement|Something went wrong while trying to delete the comment. Please try again later."
@@ -27726,6 +28638,9 @@ msgstr ""
msgid "Vulnerability|%{scannerName} (version %{scannerVersion})"
msgstr ""
+msgid "Vulnerability|Activity"
+msgstr ""
+
msgid "Vulnerability|Class"
msgstr ""
@@ -27738,6 +28653,9 @@ msgstr ""
msgid "Vulnerability|Description"
msgstr ""
+msgid "Vulnerability|Detected"
+msgstr ""
+
msgid "Vulnerability|Evidence"
msgstr ""
@@ -27801,6 +28719,9 @@ msgstr ""
msgid "Warning: Displaying this diagram might cause performance issues on this page."
msgstr ""
+msgid "We are currently unable to fetch data for the pipeline header."
+msgstr ""
+
msgid "We are currently unable to fetch data for this graph."
msgstr ""
@@ -27840,6 +28761,12 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
+msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
+msgstr ""
+
+msgid "We would like to inform you that your subscription GitLab Enterprise Edition %{plan_name} is nearing its user limit. You have %{active_user_count} active users, which is almost at the user limit of %{maximum_user_count}."
+msgstr ""
+
msgid "We've found no vulnerabilities"
msgstr ""
@@ -27855,6 +28782,12 @@ msgstr ""
msgid "Web terminal"
msgstr ""
+msgid "WebAuthn Devices (%{length})"
+msgstr ""
+
+msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
+msgstr ""
+
msgid "WebIDE|Merge request"
msgstr ""
@@ -27993,15 +28926,9 @@ msgstr ""
msgid "Welcome to the guided GitLab tour"
msgstr ""
-msgid "Welcome to your Issue Board!"
-msgstr ""
-
msgid "Welcome to your issue board!"
msgstr ""
-msgid "We’ve been making changes to %{featureName} and we’d love your feedback %{linkStart}in this issue%{linkEnd} to help us improve the experience."
-msgstr ""
-
msgid "What are you searching for?"
msgstr ""
@@ -28020,6 +28947,9 @@ msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
msgstr ""
+msgid "When enabled, any user visiting %{host} and creating an account will have to be explicitly approved by the admin before they can login. This setting is effective only if sign-ups are enabled."
+msgstr ""
+
msgid "When enabled, any user visiting %{host} will be able to create an account."
msgstr ""
@@ -28244,6 +29174,9 @@ msgstr ""
msgid "With requirements, you can set criteria to check your products against."
msgstr ""
+msgid "With test cases, you can define conditions for your project to meet in determining quality"
+msgstr ""
+
msgid "Withdraw Access Request"
msgstr "Nuligi la peton pri atingeblo"
@@ -28259,6 +29192,9 @@ msgstr ""
msgid "Workflow Help"
msgstr ""
+msgid "Would you like to create a new branch?"
+msgstr ""
+
msgid "Write"
msgstr ""
@@ -28280,6 +29216,9 @@ msgstr ""
msgid "Wrong extern UID provided. Make sure Auth0 is configured correctly."
msgstr ""
+msgid "YYYY-MM-DD"
+msgstr ""
+
msgid "Yes"
msgstr ""
@@ -28337,7 +29276,7 @@ msgstr ""
msgid "You are going to remove the fork relationship from %{project_full_name}. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "You are going to transfer %{project_full_name} to another owner. Are you ABSOLUTELY sure?"
+msgid "You are going to transfer %{project_full_name} to another namespace. Are you ABSOLUTELY sure?"
msgstr ""
msgid "You are going to turn off the confidentiality. This means %{strongStart}everyone%{strongEnd} will be able to see and leave a comment on this %{issuableType}."
@@ -28397,9 +29336,6 @@ msgstr ""
msgid "You can always edit this later"
msgstr ""
-msgid "You can apply your Trial to your Personal account or create a New Group."
-msgstr ""
-
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings"
msgstr ""
@@ -28421,12 +29357,18 @@ msgstr ""
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
+msgid "You can find more information about GitLab subscriptions in %{subscriptions_doc_link}."
+msgstr ""
+
msgid "You can generate an access token scoped to this project for each application to use the GitLab API."
msgstr ""
msgid "You can get started by cloning the repository or start adding files to it with one of the following options."
msgstr ""
+msgid "You can group test cases using labels. To learn about the future direction of this feature, visit %{linkStart}Quality Management direction page%{linkEnd}."
+msgstr ""
+
msgid "You can invite a new member to %{project_name} or invite another group."
msgstr ""
@@ -28442,6 +29384,9 @@ msgstr ""
msgid "You can notify the app / group or a project by sending them an email notification"
msgstr ""
+msgid "You can now close this window."
+msgstr ""
+
msgid "You can now export your security dashboard to a CSV report."
msgstr ""
@@ -28490,9 +29435,6 @@ msgstr ""
msgid "You can test your .gitlab-ci.yml in %{linkStart}CI Lint%{linkEnd}."
msgstr ""
-msgid "You can try again using %{begin_link}basic search%{end_link}"
-msgstr ""
-
msgid "You cannot access the raw file. Please wait a minute."
msgstr ""
@@ -28544,6 +29486,9 @@ msgstr ""
msgid "You don't have any U2F devices registered yet."
msgstr ""
+msgid "You don't have any WebAuthn devices registered yet."
+msgstr ""
+
msgid "You don't have any active chat names."
msgstr ""
@@ -28631,6 +29576,9 @@ msgstr ""
msgid "You must accept our Terms of Service and privacy policy in order to register an account"
msgstr ""
+msgid "You must be logged in to search across all of GitLab"
+msgstr ""
+
msgid "You must disassociate %{domain} from all clusters it is attached to before deletion."
msgstr ""
@@ -28670,7 +29618,7 @@ msgstr "VI bezonas permeson."
msgid "You need to be logged in."
msgstr ""
-msgid "You need to register a two-factor authentication app before you can set up a U2F device."
+msgid "You need to register a two-factor authentication app before you can set up a device."
msgstr ""
msgid "You need to set terms to be enforced"
@@ -28688,6 +29636,9 @@ msgstr ""
msgid "You reached %{usage_in_percent} of %{namespace_name}'s storage capacity (%{used_storage} of %{storage_limit})"
msgstr ""
+msgid "You successfully declined the invitation"
+msgstr ""
+
msgid "You tried to fork %{link_to_the_project} but it failed for the following reason:"
msgstr ""
@@ -28853,10 +29804,13 @@ msgstr ""
msgid "Your U2F device did not send a valid JSON response."
msgstr ""
-msgid "Your U2F device needs to be set up. Plug it in (if not already) and click the button on the left."
+msgid "Your U2F device was registered!"
msgstr ""
-msgid "Your U2F device was registered!"
+msgid "Your WebAuthn device did not send a valid JSON response."
+msgstr ""
+
+msgid "Your WebAuthn device was registered!"
msgstr ""
msgid "Your access request to the %{source_type} has been withdrawn."
@@ -28880,6 +29834,9 @@ msgstr ""
msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
msgstr ""
+msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
+msgstr ""
+
msgid "Your changes can be committed to %{branch_name} because a merge request is open."
msgstr ""
@@ -28916,6 +29873,12 @@ msgstr ""
msgid "Your deployment services will be broken, you will need to manually fix the services after renaming."
msgstr ""
+msgid "Your device is not compatible with GitLab. Please try another device"
+msgstr ""
+
+msgid "Your device needs to be set up. Plug it in (if needed) and click the button on the left."
+msgstr ""
+
msgid "Your device was successfully set up! Give it a name and register it with the GitLab server."
msgstr ""
@@ -29029,9 +29992,6 @@ msgstr[1] ""
msgid "access:"
msgstr ""
-msgid "activated"
-msgstr ""
-
msgid "added %{created_at_timeago}"
msgstr ""
@@ -29104,9 +30064,21 @@ msgstr ""
msgid "by %{user}"
msgstr ""
+msgid "cannot be a date in the past"
+msgstr ""
+
msgid "cannot be changed if a personal project has container registry tags."
msgstr ""
+msgid "cannot be changed if shared runners are enabled"
+msgstr ""
+
+msgid "cannot be enabled because parent group does not allow it"
+msgstr ""
+
+msgid "cannot be enabled because parent group has shared Runners disabled"
+msgstr ""
+
msgid "cannot be enabled unless all domains have TLS certificates"
msgstr ""
@@ -29152,7 +30124,7 @@ msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about SAST %{linkEndTag}"
msgstr ""
-msgid "ciReport|%{linkStartTag}Learn more about Secret Scanning %{linkEndTag}"
+msgid "ciReport|%{linkStartTag}Learn more about Secret Detection %{linkEndTag}"
msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about codequality reports %{linkEndTag}"
@@ -29467,9 +30439,6 @@ msgstr ""
msgid "error"
msgstr ""
-msgid "error code:"
-msgstr ""
-
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr ""
@@ -29491,6 +30460,9 @@ msgstr ""
msgid "failed to dismiss associated finding(id=%{finding_id}): %{message}"
msgstr ""
+msgid "failed to revert associated finding(id=%{finding_id}) to detected"
+msgstr ""
+
msgid "file"
msgid_plural "files"
msgstr[0] ""
@@ -30033,6 +31005,9 @@ msgstr ""
msgid "must be a root namespace"
msgstr ""
+msgid "must be a valid IPv4 or IPv6 address"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -30069,6 +31044,9 @@ msgstr ""
msgid "no expiration"
msgstr ""
+msgid "no name set"
+msgstr ""
+
msgid "no one can merge"
msgstr ""
@@ -30247,9 +31225,6 @@ msgstr ""
msgid "security Reports|There was an error creating the merge request"
msgstr ""
-msgid "settings saved, but not activated"
-msgstr ""
-
msgid "severity|Critical"
msgstr ""
@@ -30376,9 +31351,6 @@ msgstr ""
msgid "toggle collapse"
msgstr ""
-msgid "toggle dropdown"
-msgstr ""
-
msgid "triggered"
msgstr ""
@@ -30406,6 +31378,9 @@ msgstr ""
msgid "user avatar"
msgstr ""
+msgid "user preferences"
+msgstr ""
+
msgid "username"
msgstr ""
diff --git a/locale/es/gitlab.po b/locale/es/gitlab.po
index f4c7a90431d..d39cf6a2784 100644
--- a/locale/es/gitlab.po
+++ b/locale/es/gitlab.po
@@ -14,7 +14,10 @@ msgstr ""
"X-Crowdin-Language: es-ES\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 6\n"
-"PO-Revision-Date: 2020-09-04 23:06\n"
+"PO-Revision-Date: 2020-10-02 18:46\n"
+
+msgid " %{project_name}#%{issue_iid} &middot; opened %{issue_created} by %{author}"
+msgstr ""
msgid " %{start} to %{end}"
msgstr " %{start} hasta %{end}"
@@ -74,6 +77,16 @@ msgstr "\"%{path}\" no existía en \"%{ref}\""
msgid "\"el\" parameter is required for createInstance()"
msgstr ""
+msgid "%d Approval"
+msgid_plural "%d Approvals"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d Package"
+msgid_plural "%d Packages"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d Scanned URL"
msgid_plural "%d Scanned URLs"
msgstr[0] "%d URL analizada"
@@ -137,6 +150,11 @@ msgstr[1] "%d commits,"
msgid "%d commits"
msgstr "%d commits"
+msgid "%d completed issue"
+msgid_plural "%d completed issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d contribution"
msgid_plural "%d contributions"
msgstr[0] "%d colaboración"
@@ -147,6 +165,11 @@ msgid_plural "%d days"
msgstr[0] "%d día"
msgstr[1] "%d días"
+msgid "%d day until tags are automatically removed"
+msgid_plural "%d days until tags are automatically removed"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d error"
msgid_plural "%d errors"
msgstr[0] "%d error"
@@ -237,6 +260,16 @@ msgid_plural "%d more comments"
msgstr[0] "%d comentarios más"
msgstr[1] "%d comentarios más"
+msgid "%d open issue"
+msgid_plural "%d open issues"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d pending comment"
+msgid_plural "%d pending comments"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d personal project will be removed and cannot be restored."
msgid_plural "%d personal projects will be removed and cannot be restored."
msgstr[0] "Se eliminará el proyecto personal %d y no podrá ser restaurado"
@@ -252,6 +285,11 @@ msgid_plural "%d projects"
msgstr[0] "%d proyecto"
msgstr[1] "%d proyectos"
+msgid "%d project selected"
+msgid_plural "%d projects selected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d request with warnings"
msgid_plural "%d requests with warnings"
msgstr[0] "%d solicitud con advertencias"
@@ -272,6 +310,11 @@ msgid_plural "%d tags"
msgstr[0] "%d etiqueta"
msgstr[1] "%d etiquetas"
+msgid "%d tag per image name"
+msgid_plural "%d tags per image name"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d unassigned issue"
msgid_plural "%d unassigned issues"
msgstr[0] "%d incidencia sin asignar"
@@ -292,6 +335,11 @@ msgid_plural "%d vulnerabilities dismissed"
msgstr[0] "%d vulnerabilidad descartada"
msgstr[1] "%d vulnerabilidades descartadas"
+msgid "%d warning found:"
+msgid_plural "%d warnings found:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%s additional commit has been omitted to prevent performance issues."
msgid_plural "%s additional commits have been omitted to prevent performance issues."
msgstr[0] "%s cambio adicional ha sido omitido para evitar problemas de rendimiento."
@@ -330,6 +378,9 @@ msgstr ""
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr "%{commit_author_link} escribió %{commit_timeago}"
+msgid "%{completedCount} completed weight"
+msgstr ""
+
msgid "%{completedWeight} of %{totalWeight} weight completed"
msgstr "%{completedWeight} de %{totalWeight} del peso completado"
@@ -378,14 +429,12 @@ msgid_plural "%{count} participants"
msgstr[0] "%{count} participante"
msgstr[1] "%{count} participantes"
-msgid "%{count} pending comment"
-msgid_plural "%{count} pending comments"
-msgstr[0] "%{count} comentario pendiente"
-msgstr[1] "%{count} comentarios pendientes"
-
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr "%{count} %{pluralized_subject} relacionados: %{links}"
+msgid "%{count} total weight"
+msgstr ""
+
msgid "%{dashboard_path} could not be found."
msgstr "%{dashboard_path} no se ha encontrado."
@@ -440,6 +489,9 @@ msgstr ""
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} utiliza cuentas administradas de grupo. Debe crear una nueva cuenta de GitLab que será administrada por %{group_name}."
+msgid "%{group_name}&%{epic_iid} &middot; opened %{epic_created} by %{author}"
+msgstr ""
+
msgid "%{host} sign-in from new location"
msgstr "%{host} inicia sesión desde una nueva ubicación"
@@ -452,8 +504,8 @@ msgstr ""
msgid "%{issuableType} will be removed! Are you sure?"
msgstr "¡Va a eliminar %{issuableType}! ¿Está seguro de que desea realizar esta acción?"
-msgid "%{issuesSize} issues with a limit of %{maxIssueCount}"
-msgstr "%{issuesSize} incidencias con un límite de %{maxIssueCount}"
+msgid "%{issuesCount} issues with a limit of %{maxIssueCount}"
+msgstr ""
msgid "%{issuesSize} with a limit of %{maxIssueCount}"
msgstr ""
@@ -485,8 +537,8 @@ msgstr "%{labelStart}Método:%{labelEnd} %{method}"
msgid "%{labelStart}Namespace:%{labelEnd} %{namespace}"
msgstr "%{labelStart}Espacio de nombres:%{labelEnd} %{namespace}"
-msgid "%{labelStart}Report Type:%{labelEnd} %{reportType}"
-msgstr "%{labelStart}Tipo de informe:%{labelEnd} %{reportType}"
+msgid "%{labelStart}Scan Type:%{labelEnd} %{reportType}"
+msgstr ""
msgid "%{labelStart}Scanner:%{labelEnd} %{scanner}"
msgstr "%{labelStart}Escáner:%{labelEnd} %{scanner}"
@@ -682,9 +734,6 @@ msgid_plural "%{securityScanner} results are not available because a pipeline ha
msgstr[0] ""
msgstr[1] ""
-msgid "%{service_title} %{message}."
-msgstr "%{service_title} %{message}."
-
msgid "%{size} GiB"
msgstr "%{size} Gb"
@@ -773,6 +822,12 @@ msgstr "%{text} esta disponible"
msgid "%{timebox_name} should belong either to a project or a group."
msgstr ""
+msgid "%{timebox_type} does not support burnup charts"
+msgstr ""
+
+msgid "%{timebox_type} must have a start and due date"
+msgstr ""
+
msgid "%{title} %{operator} %{threshold}"
msgstr "%{title} %{operator} %{threshold}"
@@ -797,8 +852,8 @@ msgstr ""
msgid "%{total} open issue weight"
msgstr "%{total} incidencias abiertas"
-msgid "%{total} open issues"
-msgstr "%{total} incidencias abiertas"
+msgid "%{total} warnings found: showing first %{warningsDisplayed}"
+msgstr ""
msgid "%{usage_ping_link_start}Learn more%{usage_ping_link_end} about what information is shared with GitLab Inc."
msgstr "%{usage_ping_link_start}Más información%{usage_ping_link_end} acerca de lo que se comparte en GitLab Inc."
@@ -830,9 +885,6 @@ msgstr "%{webhooks_link_start}%{webhook_type}%{link_end} le permiten enviar noti
msgid "&lt; 1 hour"
msgstr ""
-msgid "&lt;no name set&gt;"
-msgstr ""
-
msgid "&lt;no scopes selected&gt;"
msgstr ""
@@ -863,6 +915,9 @@ msgstr "'%{level}' no es un nivel de visibilidad válido"
msgid "'%{name}' Value Stream created"
msgstr ""
+msgid "'%{name}' Value Stream deleted"
+msgstr ""
+
msgid "'%{name}' stage already exists"
msgstr "La etapa '%{name}' ya existe"
@@ -922,6 +977,9 @@ msgstr "+ %{moreCount} más"
msgid "+ %{numberOfHiddenAssignees} more"
msgstr "+ %{numberOfHiddenAssignees} más"
+msgid "+ %{numberOfHiddenReviewers} more"
+msgstr ""
+
msgid "+%d more"
msgid_plural "+%d more"
msgstr[0] "+%d más"
@@ -982,6 +1040,11 @@ msgid_plural "%d Days"
msgstr[0] "1 Día"
msgstr[1] "%d Días"
+msgid "1 Issue"
+msgid_plural "%d Issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "1 closed issue"
msgid_plural "%{issues} closed issues"
msgstr[0] "1 incidencia cerrada"
@@ -997,6 +1060,11 @@ msgid_plural "%d days"
msgstr[0] "1 día"
msgstr[1] "%d días"
+msgid "1 deploy key"
+msgid_plural "%d deploy keys"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] "1 grupo"
@@ -1099,6 +1167,9 @@ msgstr "8 horas"
msgid ":%{startLine} to %{endLine}"
msgstr ""
+msgid "A %{incident_docs_start}modified issue%{incident_docs_end} to guide the resolution of incidents."
+msgstr ""
+
msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr "Un ejecutor es un proceso que ejecuta un trabajo. Puede configurar tantos ejecutores como usted necesite."
@@ -1111,6 +1182,9 @@ msgstr ""
msgid "A GitBook site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr "Un sitio basado en GitBook que utiliza Netlify como herramienta de CI/CD en lugar de GitLab, pero con las demás excelentes características de GitLab."
+msgid "A Gitpod configured Webapplication in Spring and Java"
+msgstr ""
+
msgid "A Hexo site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr "Un sitio basado en Hexo que usa Netlify como herramienta de CI/CD en lugar de GitLab, pero con las demás excelentes características de GitLab."
@@ -1282,9 +1356,15 @@ msgstr "¡Acceso denegado! Por favor, verifique que puede agregar las claves de
msgid "Access expiration date"
msgstr "Fecha de expiración del acceso"
+msgid "Access expires"
+msgstr ""
+
msgid "Access forbidden. Check your access level."
msgstr "Acceso denegado. Por favor, compruebe su nivel de acceso."
+msgid "Access granted"
+msgstr ""
+
msgid "Access requests"
msgstr ""
@@ -1294,6 +1374,9 @@ msgstr "El acceso a '%{classification_label}' no está permitido"
msgid "Access to Pages websites are controlled based on the user's membership to a given project. By checking this box, users will be required to be logged in to have access to all Pages websites in your instance."
msgstr ""
+msgid "AccessDropdown|Deploy Keys"
+msgstr ""
+
msgid "AccessDropdown|Groups"
msgstr "Grupos"
@@ -1411,12 +1494,6 @@ msgstr "Activo %{type} (%{token_length})"
msgid "Active Sessions"
msgstr "Sesiones activas"
-msgid "Active Users:"
-msgstr "Usuarios activos:"
-
-msgid "Active users"
-msgstr "Usuarios activos"
-
msgid "Activity"
msgstr "Actividad"
@@ -1584,9 +1661,6 @@ msgstr ""
msgid "Add label(s)"
msgstr "Añadir etiqueta(s)"
-msgid "Add license"
-msgstr "Añadir licencia"
-
msgid "Add list"
msgstr "Añadir lista"
@@ -1761,21 +1835,51 @@ msgstr "Usuarios bloqueados"
msgid "AdminArea|Bots"
msgstr "Bots"
+msgid "AdminArea|Components"
+msgstr ""
+
msgid "AdminArea|Developer"
msgstr "Desarrollador"
+msgid "AdminArea|Features"
+msgstr ""
+
+msgid "AdminArea|Groups: %{number_of_groups}"
+msgstr ""
+
msgid "AdminArea|Guest"
msgstr "Invitado"
msgid "AdminArea|Included Free in license"
msgstr "AdminArea|Incluido gratis en la licencia"
+msgid "AdminArea|Latest groups"
+msgstr ""
+
+msgid "AdminArea|Latest projects"
+msgstr ""
+
+msgid "AdminArea|Latest users"
+msgstr ""
+
msgid "AdminArea|Maintainer"
msgstr "Mantenedor"
+msgid "AdminArea|New group"
+msgstr ""
+
+msgid "AdminArea|New project"
+msgstr ""
+
+msgid "AdminArea|New user"
+msgstr ""
+
msgid "AdminArea|Owner"
msgstr "Propietario"
+msgid "AdminArea|Projects: %{number_of_projects}"
+msgstr ""
+
msgid "AdminArea|Reporter"
msgstr "Reportador"
@@ -1803,6 +1907,9 @@ msgstr "Usuarios con el rol más alto"
msgid "AdminArea|Users without a Group and Project"
msgstr "Usuarios sin grupo y proyecto"
+msgid "AdminArea|Users: %{number_of_users}"
+msgstr ""
+
msgid "AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running."
msgstr "Está a punto de detener todos los trabajos. Esto detendrá todos los trabajos que se están ejecutando actualmente."
@@ -1821,9 +1928,6 @@ msgstr "Eliminar"
msgid "AdminProjects|Delete Project %{projectName}?"
msgstr "¿Eliminar el proyecto %{projectName}?"
-msgid "AdminProjects|Delete project"
-msgstr "Eliminar proyecto"
-
msgid "AdminSettings|Apply integration settings to all Projects"
msgstr "Aplicar la configuración de integración a todos los proyectos"
@@ -2061,21 +2165,30 @@ msgstr "Cuando el usuario vuelve a iniciar sesión, su cuenta se activará como
msgid "AdminUsers|Without projects"
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 %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
-msgstr "Está a punto de eliminar permanentemente al usuario %{username}. Las incidencias, los merge requests y los grupos enlazados a ellos serán transferidos a un \"usuario fantasma\" de sistema. Para evitar la pérdida de datos, considere %{strong_start}bloquear el usuario%{strong_end} en su lugar. Una vez que %{strong_start}elimine el usuario%{strong_end}, no podrá deshacer o recuperar esta acción."
+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 %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
-msgstr "Está a punto de eliminar permanentemente el usuario %{username}. Esto eliminará todas las incidencias, merge requests y todos los grupos vinculados al mismo. Para evitar la pérdida de datos, considere utilizar la característica %{strong_start}bloquear usuario%{strong_end} en su lugar. Una vez %{strong_start}eliminado un usuario%{strong_end}, no se puede deshacer o volver recuperar esta acción."
+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 ""
msgid "AdminUsers|You cannot remove your own admin rights."
msgstr ""
+msgid "AdminUsers|You must transfer ownership or delete the groups owned by this user before you can delete their account"
+msgstr ""
+
msgid "Administration"
msgstr "‫Administración"
msgid "Advanced"
msgstr "Avanzado"
+msgid "Advanced Search"
+msgstr ""
+
+msgid "Advanced Search with Elasticsearch"
+msgstr ""
+
msgid "Advanced Settings"
msgstr "Configuración avanzada"
@@ -2153,6 +2266,9 @@ msgstr ""
msgid "AlertManagement|Edit"
msgstr "Editar"
+msgid "AlertManagement|Environment"
+msgstr ""
+
msgid "AlertManagement|Events"
msgstr "Eventos"
@@ -2165,6 +2281,9 @@ msgstr "Información"
msgid "AlertManagement|Issue"
msgstr ""
+msgid "AlertManagement|Key"
+msgstr ""
+
msgid "AlertManagement|Low"
msgstr "Bajo"
@@ -2258,6 +2377,9 @@ msgstr "Activado"
msgid "AlertManagement|Unknown"
msgstr "Desconocido"
+msgid "AlertManagement|Value"
+msgstr ""
+
msgid "AlertManagement|View alerts in Opsgenie"
msgstr ""
@@ -2417,6 +2539,9 @@ msgstr "Todas las rutas son relativas a la URL de GitLab. Por favor, no incluya
msgid "All projects"
msgstr "Todos los proyectos"
+msgid "All projects selected"
+msgstr ""
+
msgid "All security scans are enabled because %{linkStart}Auto DevOps%{linkEnd} is enabled on this project"
msgstr "Todas las exploraciones de seguridad están habilitadas porque %{linkStart}Auto DevOps%{linkEnd} está habilitado en este proyecto"
@@ -2504,6 +2629,9 @@ msgstr "Le permite agregar y administrar clusters de Kubernetes."
msgid "Almost there"
msgstr "¡Ya queda poco!"
+msgid "Already blocked"
+msgstr ""
+
msgid "Also called \"Issuer\" or \"Relying party trust identifier\""
msgstr "También llamado \"emisor\" o \"identificador de confianza\""
@@ -2558,6 +2686,9 @@ msgstr "Se agregará a un campo de usuario de Gitlab el nombre completo del usua
msgid "An error has occurred"
msgstr "Se ha producido un error"
+msgid "An error occured while making the changes: %{error}"
+msgstr ""
+
msgid "An error occurred adding a draft to the thread."
msgstr "Se ha producido un error al agregar un borrador a la discusión."
@@ -2585,12 +2716,6 @@ msgstr "Ha ocurrido un error visualizando el blob"
msgid "An error occurred when toggling the notification subscription"
msgstr "Se produjo un error al activar/desactivar la suscripción de notificación"
-msgid "An error occurred when trying to resolve a comment. Please try again."
-msgstr "Se ha producido un error al intentar resolver un comentario. Por favor, inténtelo de nuevo."
-
-msgid "An error occurred when trying to resolve a discussion. Please try again."
-msgstr "Se ha producido un error al intentar resolver una discusión. Por favor, inténtelo de nuevo."
-
msgid "An error occurred when updating the issue weight"
msgstr "Se ha producido un error al actualizar el tamaño de la incidencia"
@@ -2606,12 +2731,6 @@ msgstr "Se ha producido un error al añadir el título formateado para la tarea
msgid "An error occurred while checking group path. Please refresh and try again."
msgstr "Se ha producido un error durante la comprobación de ruta del grupo. Por favor, actualice y vuelva a intentarlo."
-msgid "An error occurred while committing your changes."
-msgstr "Se ha producido un error al hacer commit de sus cambios."
-
-msgid "An error occurred while creating the list. Please try again."
-msgstr ""
-
msgid "An error occurred while decoding the file."
msgstr "Se ha producido un error mientras al cargar el archivo."
@@ -2684,26 +2803,20 @@ msgstr "Se ha producido un error al obtener los informes de terraform."
msgid "An error occurred while fetching the Service Desk address."
msgstr "Se ha producido un error al obtener la dirección de Service Desk."
-msgid "An error occurred while fetching the board issues. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the board lists. Please reload the page."
msgstr ""
msgid "An error occurred while fetching the board lists. Please try again."
msgstr "Se ha producido un error al obtener la lista de tableros. Por favor vuelva a intentarlo."
-msgid "An error occurred while fetching the board swimlanes. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the builds."
msgstr "Se ha producido un error al obtener el resultado de los trabajo de las construcción."
msgid "An error occurred while fetching the job log."
msgstr "Se ha producido un error al obtener el log del trabajo."
-msgid "An error occurred while fetching the job trace."
-msgstr "Se ha producido un error al obtener el log del trabajo."
+msgid "An error occurred while fetching the job logs."
+msgstr ""
msgid "An error occurred while fetching the job."
msgstr "Se ha producido un error al obtener el trabajo."
@@ -2849,9 +2962,6 @@ msgstr "Se ha producido un error al guardar el estado de LDAP. Por favor, intén
msgid "An error occurred while saving assignees"
msgstr "Se ha producido un error al guardar las asignaciones"
-msgid "An error occurred while saving the template. Please check if the template exists."
-msgstr "Se ha producido un error al guardar la plantilla. Por favor, compruebe si la plantilla existe."
-
msgid "An error occurred while searching for milestones"
msgstr "Se ha producido un error durante la búsqueda de hitos"
@@ -2870,12 +2980,12 @@ msgstr "Se ha producido un error al cancelar la suscripción a las notificacione
msgid "An error occurred while updating approvers"
msgstr "Se ha producido un error al actualizar los aprobadores"
+msgid "An error occurred while updating labels."
+msgstr ""
+
msgid "An error occurred while updating the comment"
msgstr "Se ha producido un error al actualizar el comentario"
-msgid "An error occurred while updating the list. Please try again."
-msgstr ""
-
msgid "An error occurred while validating group path"
msgstr "Se ha producido un error al validar la ruta del grupo"
@@ -2927,6 +3037,9 @@ msgstr "Se ha producido un error inesperado al detener el Terminal Web."
msgid "An unknown error occurred while loading this graph."
msgstr "Se ha producido un error desconocido mientras se cargaba este gráfico."
+msgid "An unknown error occurred."
+msgstr ""
+
msgid "Analytics"
msgstr "Analíticas"
@@ -2960,12 +3073,12 @@ msgstr "Verificación de correo no deseado"
msgid "Any"
msgstr "Cualquiera"
+msgid "Any %{header}"
+msgstr ""
+
msgid "Any Author"
msgstr "Cualquier autor"
-msgid "Any Status"
-msgstr ""
-
msgid "Any branch"
msgstr "Cualquier rama"
@@ -3017,6 +3130,9 @@ msgstr "Aplicación"
msgid "Application ID"
msgstr "ID de la aplicación"
+msgid "Application limits saved successfully"
+msgstr ""
+
msgid "Application settings saved successfully"
msgstr "Se ha guardado correctamente la configuración de la aplicación"
@@ -3226,6 +3342,9 @@ msgstr "¿Está seguro de que desea cancelar la edición de este comentario?"
msgid "Are you sure you want to close this blocked issue?"
msgstr "¿Está seguro de que desea cerrar esta incidencia bloqueada?"
+msgid "Are you sure you want to delete \"%{name}\" Value Stream?"
+msgstr ""
+
msgid "Are you sure you want to delete %{name}?"
msgstr "¿Estás seguro de que deseas eliminar %{name}?"
@@ -3235,6 +3354,9 @@ msgstr "¿Está seguro de que desea eliminar estos artefactos?"
msgid "Are you sure you want to delete this %{typeOfComment}?"
msgstr "¿Esta seguro de que desea eliminar esto %{typeOfComment}?"
+msgid "Are you sure you want to delete this SSH key?"
+msgstr ""
+
msgid "Are you sure you want to delete this board?"
msgstr "¿Está seguro de que desea eliminar esta tablero?"
@@ -3259,6 +3381,11 @@ msgstr "¿Está seguro de que desea descartar este comentario?"
msgid "Are you sure you want to erase this build?"
msgstr "¿Estás seguro de que quieres borrar esta versión?"
+msgid "Are you sure you want to import %d repository?"
+msgid_plural "Are you sure you want to import %d repositories?"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Are you sure you want to lose unsaved changes?"
msgstr "¿Estás seguro de que deseas descartar los cambios no guardados?"
@@ -3268,15 +3395,15 @@ msgstr "¿Estás seguro que quiere perder la información de su incidencia?"
msgid "Are you sure you want to merge immediately?"
msgstr "¿Está seguro de que quiere hacer merge inmediatamente?"
-msgid "Are you sure you want to permanently delete this license?"
-msgstr "¿Está seguro de que desea eliminar de forma permanente esta licencia?"
-
msgid "Are you sure you want to re-deploy this environment?"
msgstr "¿Está seguro de que desea volver a desplegar este entorno?"
msgid "Are you sure you want to regenerate the public key? You will have to update the public key on the remote server before mirroring will work again."
msgstr "¿Seguro que quiere regenerar la clave pública? Deberá actualizar la clave pública en el servidor remoto antes de que la duplicación funcione nuevamente."
+msgid "Are you sure you want to reindex?"
+msgstr ""
+
msgid "Are you sure you want to remove %{group_name}?"
msgstr "¿Está seguro que desea eliminar %{group_name}?"
@@ -3304,6 +3431,9 @@ msgstr "¿Está seguro de que desea revocar este token %{type}? Esta acción no
msgid "Are you sure you want to revoke this nickname?"
msgstr "¿Está seguro que desea revocar este nick?"
+msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
+msgstr ""
+
msgid "Are you sure you want to stop this environment?"
msgstr "¿Está seguro de que desea detener este entorno?"
@@ -3325,6 +3455,9 @@ msgstr "¿Está seguro? Eliminar esta clave GPG no afecta a los commits ya firma
msgid "Are you sure? The device will be signed out of GitLab and all remember me tokens revoked."
msgstr ""
+msgid "Are you sure? This will invalidate your registered applications and U2F / WebAuthn devices."
+msgstr ""
+
msgid "Are you sure? This will invalidate your registered applications and U2F devices."
msgstr "¿Está seguro?. Al hacer esto invalidará sus aplicaciones registradas y sus dispositivos U2F."
@@ -3343,9 +3476,6 @@ msgstr "El artefacto se ha eliminado correctamente."
msgid "Artifacts"
msgstr "Artefactos"
-msgid "As U2F devices are only supported by a few browsers, we require that you set up a two-factor authentication app before a U2F device. That way you'll always be able to log in - even when you're using an unsupported browser."
-msgstr "Dado que los dispositivos U2F solo son compatibles con algunos navegadores, requerimos que configure una aplicación de autenticación de dos factores antes que un dispositivo U2F. De esta forma, siempre podrá iniciar sesión, incluso cuando utilice un navegador no compatible."
-
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 ""
@@ -3539,6 +3669,9 @@ msgstr "Eventos del proyecto"
msgid "AuditLogs|Target"
msgstr "Destino"
+msgid "AuditLogs|This month"
+msgstr ""
+
msgid "AuditLogs|User Events"
msgstr "Eventos de usuario"
@@ -3578,6 +3711,9 @@ msgstr "Método de autenticación actualizado"
msgid "Authentication via U2F device failed."
msgstr "Se ha producido un error en la autenticación a través del dispositivo U2F."
+msgid "Authentication via WebAuthn device failed."
+msgstr ""
+
msgid "Author"
msgstr "Autor"
@@ -3845,15 +3981,6 @@ msgstr "La URL raíz de Bamboo, por ejemplo, https://bamboo.example.com"
msgid "BambooService|You must set up automatic revision labeling and a repository trigger in Bamboo."
msgstr "Debe configurar el etiquetado automático de revisión y un disparador del repositorio en Bamboo."
-msgid "BatchComments|Delete all pending comments"
-msgstr "Borrar todos los comentarios pendientes"
-
-msgid "BatchComments|Discard review?"
-msgstr "¿Descartar revisión?"
-
-msgid "BatchComments|You're about to discard your review which will delete all of your pending comments. The deleted comments %{strong_start}cannot%{strong_end} be restored."
-msgstr "Está a punto de descartar su revisión, lo que eliminará todos sus comentarios pendientes. Los comentarios eliminados %{strong_start} no pueden %{strong_end} volver a restaurarse."
-
msgid "Be careful. Changing the project's namespace can have unintended side effects."
msgstr "Tenga cuidado. Cambiar el espacio de nombres del proyecto puede tener efectos secundarios no deseados."
@@ -3875,6 +4002,9 @@ msgstr "A continuación encontrará todos los grupos públicos."
msgid "Bi-weekly code coverage"
msgstr "Cobertura de código quincenal"
+msgid "Billable Users:"
+msgstr ""
+
msgid "Billing"
msgstr "Facturación"
@@ -3884,8 +4014,8 @@ msgstr "actualmente %{group_name} está en el plan %{plan_name}."
msgid "BillingPlans|@%{user_name} you are currently using the %{plan_name} plan."
msgstr "actualmente, @%{user_name} está utilizando el plan %{plan_name}."
-msgid "BillingPlans|Congratulations, your new trial is activated"
-msgstr "Enhorabuena, su plan de prueba está activado"
+msgid "BillingPlans|Congratulations, your free trial is activated."
+msgstr ""
msgid "BillingPlans|If you would like to downgrade your plan please contact %{support_link_start}Customer Support%{support_link_end}."
msgstr "Si deseas cambiar su plan, por favor, póngase en contacto con %{support_link_start}Atención al cliente%{support_link_end}."
@@ -3947,6 +4077,9 @@ msgstr "Importar desde Bitbucket"
msgid "Blame"
msgstr ""
+msgid "Block user"
+msgstr ""
+
msgid "Blocked"
msgstr "Bloqueado"
@@ -3962,33 +4095,39 @@ msgstr ""
msgid "Blog"
msgstr "Blog"
-msgid "Board name"
-msgstr "Nombre del tablero"
-
msgid "Board scope"
msgstr "Alcance del panel de control"
msgid "Board scope affects which issues are displayed for anyone who visits this board"
msgstr "El alcance del panel de control afecta qué problemas se muestran para cualquiera persona que visite este panel"
-msgid "BoardBlankState|Add default lists"
-msgstr "Añadir listas por defecto"
-
-msgid "BoardBlankState|Add the following default lists to your Issue Board with one click:"
-msgstr "Agregue las siguientes listas predeterminadas a su tablero de incidencias con un solo clic:"
-
-msgid "BoardBlankState|Nevermind, I'll use my own"
-msgstr "No importa, voy a utilizar el mío"
-
-msgid "BoardBlankState|Starting out with the default set of lists will get you right on the way to making the most of your board."
-msgstr "Comenzar con el conjunto de listas por defecto, lo pondrá en el camino correcto para aprovechar al máximo su tablero."
-
msgid "Boards"
msgstr "Tableros"
msgid "Boards and Board Lists"
msgstr "Tableros y listas de tableros"
+msgid "Boards|An error occurred while creating the issue. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while creating the list. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching issues. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching the board issues. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching the board swimlanes. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while moving the issue. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while updating the list. Please try again."
+msgstr ""
+
msgid "Boards|Collapse"
msgstr "Contraer"
@@ -4013,8 +4152,8 @@ msgstr "No se encontró la rama %{branchName} en el repositorio de este proyecto
msgid "Branch %{branch_name} was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr ""
-msgid "Branch has changed"
-msgstr "La rama ha cambiado"
+msgid "Branch changed"
+msgstr ""
msgid "Branch is already taken"
msgstr "La rama ya existe"
@@ -4319,6 +4458,9 @@ msgstr "CERRADO"
msgid "CLOSED (MOVED)"
msgstr "CERRADO (MOVIDO)"
+msgid "CODEOWNERS rule violation"
+msgstr ""
+
msgid "CONTRIBUTING"
msgstr "CONTRIBUTING"
@@ -4349,9 +4491,6 @@ msgstr ""
msgid "Can't create snippet: %{err}"
msgstr "No se puede crear el fragmento de código: %{err}"
-msgid "Can't edit as source branch was deleted"
-msgstr ""
-
msgid "Can't fetch content for the blob: %{err}"
msgstr ""
@@ -4364,9 +4503,6 @@ msgstr "No se puede encontrar la variable: ZiteReader"
msgid "Can't load mermaid module: %{err}"
msgstr "No se puede cargar el módulo de Mermaid: %{err}"
-msgid "Can't remove group members without group managed account"
-msgstr "No se pueden eliminar miembros del grupo sin una cuenta administrada por grupo"
-
msgid "Can't scan the code?"
msgstr "¿No puede escanear el código?"
@@ -4409,6 +4545,9 @@ msgstr "No se puede crear el informe de abuso. El usuario ha sido eliminado."
msgid "Cannot create the abuse report. This user has been blocked."
msgstr "No se puede crear el informe de abuso. Este usuario ha sido bloqueado."
+msgid "Cannot enable shared runners because parent group does not allow it"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -4514,6 +4653,15 @@ msgstr "Cambia su contraseña"
msgid "Change your password or recover your current one"
msgstr "Cambia o recuperar su contraseña"
+msgid "ChangeReviewer|Reviewer changed from %{old} to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Reviewer changed to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Unassigned"
+msgstr ""
+
msgid "ChangeTypeActionLabel|Pick into branch"
msgstr "Escoger en la rama"
@@ -4553,6 +4701,9 @@ msgstr "Cambios eliminados. Haga clic para mostrar."
msgid "Changes the title to \"%{title_param}\"."
msgstr "Cambia el título a \"%{title_param}\"."
+msgid "Changes were successfully made."
+msgstr ""
+
msgid "Changes won't take place until the index is %{link_start}recreated%{link_end}."
msgstr "No se realizarán los cambios hasta que el índice sea %{link_start}recreado%{link_end}."
@@ -4958,6 +5109,9 @@ msgstr "Máscara"
msgid "CiVariables|Protected"
msgstr "Protegido"
+msgid "CiVariables|Remove variable"
+msgstr ""
+
msgid "CiVariables|Remove variable row"
msgstr "Eliminar fila de variables"
@@ -5036,9 +5190,6 @@ msgstr "Borrar los filtros del gráfico"
msgid "Clear due date"
msgstr "Borrar fecha de vencimiento"
-msgid "Clear input"
-msgstr "Limpiar entrada"
-
msgid "Clear recent searches"
msgstr "Borrar el historial de búsquedas recientes"
@@ -5087,6 +5238,9 @@ msgstr "Clave de autenticación del cliente"
msgid "Client authentication key password"
msgstr "Contraseña de clave de autenticación del cliente"
+msgid "Client request timeout"
+msgstr ""
+
msgid "Clients"
msgstr "Clientes"
@@ -5171,6 +5325,27 @@ msgstr "Nivel de clúster"
msgid "Cluster type must be specificed for Stages::ClusterEndpointInserter"
msgstr ""
+msgid "ClusterAgents|Configuration"
+msgstr ""
+
+msgid "ClusterAgents|Connect your cluster with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate Kubernetes with a GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Name"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Agent also requires %{linkStart}enabling the Agent Server%{linkEnd}"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Kubernetes Agent allows an Infrastructure as Code, GitOps approach to integrating Kubernetes clusters with GitLab. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "ClusterAgent|This feature is only available for premium plans"
msgstr ""
@@ -5240,11 +5415,11 @@ msgstr "Todos los datos serán eliminados y no se podrán restaurar."
msgid "ClusterIntegration|All installed applications and related resources"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster."
-msgstr "Permitir que GitLab administre el espacio de nombres y las cuentas de servicio para este cluster."
+msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{linkStart}More information%{linkEnd}"
+msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{startLink}More information%{endLink}"
-msgstr "Permitir que GitLab administre el espacio de nombres y las cuentas de servicio para este clúster. %{startLink}Más información%{endLink}"
+msgid "ClusterIntegration|Allow GitLab to manage namespaces and service accounts for this cluster."
+msgstr ""
msgid "ClusterIntegration|Alternatively, "
msgstr ""
@@ -5264,6 +5439,9 @@ msgstr "Se ha producido un error al intentar recuperar los proyectos: %{error}"
msgid "ClusterIntegration|An error occurred while trying to fetch zone machine types: %{error}"
msgstr "Se ha producido un error al intentar obtener los tipos de máquina de las zonas: %{error}"
+msgid "ClusterIntegration|An unknown error occurred while attempting to connect to Kubernetes."
+msgstr ""
+
msgid "ClusterIntegration|Any project namespaces"
msgstr ""
@@ -5279,6 +5457,9 @@ msgstr "Autenticar con AWS"
msgid "ClusterIntegration|Authenticate with Amazon Web Services"
msgstr "Autenticar con Amazon Web Services"
+msgid "ClusterIntegration|Authentication Error"
+msgstr ""
+
msgid "ClusterIntegration|Base domain"
msgstr "Dominio base"
@@ -5297,14 +5478,23 @@ msgstr ""
msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
msgstr "paquete de certificado de autoridad (formato PEM)"
-msgid "ClusterIntegration|Choose the %{startLink}security group %{externalLinkIcon} %{endLink} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
+msgid "ClusterIntegration|Check your CA certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Check your cluster status"
+msgstr ""
+
+msgid "ClusterIntegration|Check your token"
+msgstr ""
+
+msgid "ClusterIntegration|Choose the %{linkStart}security group %{linkEnd} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}subnets %{externalLinkIcon} %{endLink} in your VPC where your worker nodes will run."
+msgid "ClusterIntegration|Choose the %{linkStart}subnets %{linkEnd} in your VPC where your worker nodes will run."
msgstr ""
-msgid "ClusterIntegration|Choose the worker node %{startLink}instance type %{externalLinkIcon} %{endLink}."
-msgstr "Seleccione el nodo de trabajo %{startLink}tipo de instancia %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Choose the worker node %{linkStart}instance type%{linkEnd}."
+msgstr ""
msgid "ClusterIntegration|Choose which applications to install on your Kubernetes cluster."
msgstr ""
@@ -5315,12 +5505,9 @@ msgstr "Seleccione cuál de los entornos de su proyecto utilizará este clúster
msgid "ClusterIntegration|Clear cluster cache"
msgstr "Limpiar la caché de cluster"
-msgid "ClusterIntegration|Clear the local cache of namespace and service accounts. This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
+msgid "ClusterIntegration|Clear the local cache of namespace and service accounts."
msgstr ""
-msgid "ClusterIntegration|Cluster being created"
-msgstr "Se está creando el clúster"
-
msgid "ClusterIntegration|Cluster management project (alpha)"
msgstr "Proyecto de administración de cluster (alpha)"
@@ -5330,15 +5517,21 @@ msgstr "Se requiere el nombre del clúster."
msgid "ClusterIntegration|Cluster_applications artifact too big. Maximum allowable size: %{human_size}"
msgstr ""
-msgid "ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters."
-msgstr "Los clusters se utilizan al seleccionar el ancestro más cercano en un ámbito de entorno coincidente. Por ejemplo, los grupos de proyectos anularán los grupos de clusters."
-
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|Clusters connected with a certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Connect cluster with certificate"
+msgstr ""
+
msgid "ClusterIntegration|Connect existing cluster"
msgstr ""
+msgid "ClusterIntegration|Connection Error"
+msgstr ""
+
msgid "ClusterIntegration|Copy API URL"
msgstr "Copiar la URL del API"
@@ -5414,6 +5607,12 @@ msgstr ""
msgid "ClusterIntegration|Deletes all GitLab resources attached to this cluster during removal"
msgstr "Elimina todos los recursos de GitLab adjuntos a este clúster durante la eliminación"
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared."
+msgstr ""
+
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared. %{linkStart}More information%{linkEnd}"
+msgstr ""
+
msgid "ClusterIntegration|Did you know?"
msgstr "¿Sabía usted?"
@@ -5483,6 +5682,9 @@ msgstr "Fluentd"
msgid "ClusterIntegration|Fluentd is an open source data collector, which lets you unify the data collection and consumption for a better use and understanding of data. It requires at least one of the following logs to be successfully installed."
msgstr ""
+msgid "ClusterIntegration|GitLab Agent managed clusters"
+msgstr ""
+
msgid "ClusterIntegration|GitLab Container Network Policies"
msgstr ""
@@ -5495,6 +5697,12 @@ msgstr "GitLab Runner"
msgid "ClusterIntegration|GitLab Runner connects to the repository and executes CI/CD jobs, pushing results back and deploying applications to production."
msgstr "Los ejecutores de GitLab se conectan al repositorio de código de este proyecto y ejecutan los trabajos de CI/CD, devolviendo los resultados e desplegando las aplicaciones a producción."
+msgid "ClusterIntegration|GitLab failed to authenticate."
+msgstr ""
+
+msgid "ClusterIntegration|GitLab failed to connect to the cluster."
+msgstr ""
+
msgid "ClusterIntegration|GitLab-managed cluster"
msgstr "Cluster de GitLab administrado"
@@ -5516,6 +5724,9 @@ msgstr "Proyecto Google Kubernetes Engine"
msgid "ClusterIntegration|Group cluster"
msgstr "ClusterIntegration|Grupo de clúster"
+msgid "ClusterIntegration|HTTP Error"
+msgstr ""
+
msgid "ClusterIntegration|Helm Tiller"
msgstr "Helm Tiller"
@@ -5549,8 +5760,11 @@ msgstr "Instancia del clúster"
msgid "ClusterIntegration|Instance type"
msgstr "Tipo de instancia"
-msgid "ClusterIntegration|Integrate Kubernetes cluster automation"
-msgstr "Integrar la automatización del clúster de Kubernetes"
+msgid "ClusterIntegration|Integrate Kubernetes with a cluster certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Integrate with a cluster certificate"
+msgstr ""
msgid "ClusterIntegration|Issuer Email"
msgstr "Correo electrónico del emisor"
@@ -5585,9 +5799,6 @@ msgstr "Se actualizó correctamente el nombre de dominio de Knative."
msgid "ClusterIntegration|Knative extends Kubernetes to provide a set of middleware components that are essential to build modern, source-centric, and container-based applications that can run anywhere: on premises, in the cloud, or even in a third-party data center."
msgstr "Knative extiende Kubernetes para proporcionar un conjunto de componentes de middleware que son esenciales para construir aplicaciones modernas y basadas en contenedores que pueden ejecutarse en cualquier lugar: en su propio centro de datos, en la nube o incluso en un centro de datos de terceros."
-msgid "ClusterIntegration|Kubernetes cluster"
-msgstr "cluster de Kubernetes"
-
msgid "ClusterIntegration|Kubernetes cluster is being created..."
msgstr "Se está creando el clúster de Kubernetes..."
@@ -5600,9 +5811,6 @@ msgstr "El cluster Kubernetes se ha creado correctamente."
msgid "ClusterIntegration|Kubernetes clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr "ClusterIntegration | Los clústeres de Kubernetes le permiten utilizar aplicaciones de revisión, desplegar sus aplicaciones, ejecutar sus pipelines y mucho más de una manera sencilla."
-msgid "ClusterIntegration|Kubernetes clusters can be used to deploy applications and to provide Review Apps for this project"
-msgstr "Los clústeres de Kubernetes se pueden utilizar para desplegar aplicaciones y proporcionar aplicaciones de revisión para este proyecto"
-
msgid "ClusterIntegration|Kubernetes version"
msgstr "Versión de Kubernetes"
@@ -5615,8 +5823,8 @@ msgstr "Aprenda más sobre los tipos de %{help_link_start_machine_type}instancia
msgid "ClusterIntegration|Learn more about %{help_link_start}zones%{help_link_end}."
msgstr "Conozca más sobre las %{help_link_start}zonas%{help_link_end}."
-msgid "ClusterIntegration|Learn more about %{startLink}Regions %{externalLinkIcon}%{endLink}."
-msgstr "Obtenga más información sobre las %{startLink}Regiones %{externalLinkIcon}%{endLink}."
+msgid "ClusterIntegration|Learn more about %{linkStart}Regions%{linkEnd}."
+msgstr ""
msgid "ClusterIntegration|Learn more about Kubernetes"
msgstr "Más información sobre Kubernetes"
@@ -5660,12 +5868,18 @@ msgstr ""
msgid "ClusterIntegration|Machine type"
msgstr "Tipo de máquina"
+msgid "ClusterIntegration|Make sure your API endpoint is correct"
+msgstr ""
+
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create Kubernetes clusters"
msgstr "Asegúrese de que su cuenta %{link_to_requirements} cumple con los requisitos para crear clusters de Kubernetes"
msgid "ClusterIntegration|Manage your Kubernetes cluster by visiting %{provider_link}"
msgstr "Administre su cluster de Kubernetes visitando %{provider_link}"
+msgid "ClusterIntegration|Namespace per environment"
+msgstr ""
+
msgid "ClusterIntegration|No IAM Roles found"
msgstr "No se han encontrado roles de IAM"
@@ -5711,6 +5925,9 @@ msgstr "No se han encontrado subredes"
msgid "ClusterIntegration|No zones matched your search"
msgstr "No hay zonas que coincidan con su búsqueda"
+msgid "ClusterIntegration|Node calculations use the Kubernetes Metrics API. Make sure your cluster has metrics installed"
+msgstr ""
+
msgid "ClusterIntegration|Number of nodes"
msgstr "Número de nodos"
@@ -5753,6 +5970,9 @@ msgstr "ARN del rol de provision"
msgid "ClusterIntegration|RBAC-enabled cluster"
msgstr "Cluster RBAC habilitado"
+msgid "ClusterIntegration|Read our %{linkStart}help page%{linkEnd} on Kubernetes cluster integration."
+msgstr ""
+
msgid "ClusterIntegration|Read our %{link_start}help page%{link_end} on Kubernetes cluster integration."
msgstr "Lea nuestra %{link_start}página de ayuda%{link_end} sobre la integración de clusters de Kubernetes."
@@ -5855,8 +6075,8 @@ msgstr "Seleccione una VPC para elegir un grupo de seguridad"
msgid "ClusterIntegration|Select a VPC to choose a subnet"
msgstr "Seleccione una VPC para elegir una subred"
-msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
-msgstr "Seleccione una VPC para utilizar los recursos de su clúster de EKS. Para utilizar una nueva VPC, cree una en %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{linkStart}Amazon Web Services %{linkEnd}."
+msgstr ""
msgid "ClusterIntegration|Select a network to choose a subnetwork"
msgstr "Seleccione una red para elegir una subred"
@@ -5888,7 +6108,7 @@ msgstr "Seleccione el proyecto y la zona para elegir el tipo de máquina"
msgid "ClusterIntegration|Select project to choose zone"
msgstr "Seleccione un proyecto para elegir la zona"
-msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select zone"
@@ -5978,9 +6198,18 @@ msgstr ""
msgid "ClusterIntegration|There was a problem authenticating with your cluster. Please ensure your CA Certificate and Token are valid."
msgstr "Se ha producido un error durante la autenticación con su cluster. Por favor, asegúrese de que su la CA de su certificado y su token son válidos."
+msgid "ClusterIntegration|There was an HTTP error when connecting to your cluster."
+msgstr ""
+
msgid "ClusterIntegration|This account must have permissions to create a Kubernetes cluster in the %{link_to_container_project} specified below"
msgstr "Esta cuenta debe tener permisos para crear un clúster de Kubernetes en el %{link_to_container_project} especificado a continuación"
+msgid "ClusterIntegration|This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
+msgstr ""
+
+msgid "ClusterIntegration|This is necessary to clear existing environment-namespace associations from clusters previously managed by GitLab."
+msgstr ""
+
msgid "ClusterIntegration|This option will allow you to install applications on RBAC clusters."
msgstr "Esta opción le permitirá instalar aplicaciones en clústeres RBAC."
@@ -6005,9 +6234,21 @@ msgstr "Para eliminar la integración, escriba %{clusterName} para confirmar:"
msgid "ClusterIntegration|To use a new project, first create one on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}."
msgstr ""
+msgid "ClusterIntegration|Troubleshooting tips:"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Authenticate"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Connect"
+msgstr ""
+
msgid "ClusterIntegration|Uninstall %{appTitle}"
msgstr "ClusterIntegration | Desinstalar %{appTitle}"
+msgid "ClusterIntegration|Unknown Error"
+msgstr ""
+
msgid "ClusterIntegration|Update %{appTitle}"
msgstr "Actualizar %{appTitle}"
@@ -6068,7 +6309,7 @@ msgstr "Su cuenta debe tener %{link_to_kubernetes_engine}"
msgid "ClusterIntegration|Your cluster API is unreachable. Please ensure your API URL is correct."
msgstr "La API de su cluster está inaccesible. Por favor, asegúrese de que la URL del API es correcta."
-msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Zone"
@@ -6188,6 +6429,9 @@ msgstr ""
msgid "Collapse"
msgstr "Contraer"
+msgid "Collapse all threads"
+msgstr ""
+
msgid "Collapse approvers"
msgstr "Contraer aprobadores"
@@ -6337,8 +6581,8 @@ msgstr "Enviado por"
msgid "Commit…"
msgstr "Commit..."
-msgid "Company"
-msgstr "Empresa"
+msgid "Community forum"
+msgstr ""
msgid "Company name"
msgstr "Nombre de la empresa"
@@ -6346,6 +6590,9 @@ msgstr "Nombre de la empresa"
msgid "Compare"
msgstr "Comparar"
+msgid "Compare %{oldCommitId}...%{newCommitId}"
+msgstr ""
+
msgid "Compare Git revisions"
msgstr "Comparar revisiones de Git"
@@ -6361,6 +6608,9 @@ msgstr "Comparar los cambios con el último commit"
msgid "Compare changes with the merge request target branch"
msgstr "Comparar los cambios con la rama de destino del merge request"
+msgid "Compare submodule commit revisions"
+msgstr ""
+
msgid "Compare with previous version"
msgstr "Comparar con la versión anterior"
@@ -6496,6 +6746,9 @@ msgstr "Configurar la %{link} integración."
msgid "Configure the way a user creates a new account."
msgstr "Configure la forma en la que un usuario crea una cuenta nueva."
+msgid "Configure which lists are shown for anyone who visits this board"
+msgstr ""
+
msgid "Confirm"
msgstr "Confirmar"
@@ -6721,6 +6974,9 @@ msgstr[1] "Eliminar etiquetas"
msgid "ContainerRegistry|Set cleanup policy"
msgstr ""
+msgid "ContainerRegistry|Some tags were not deleted"
+msgstr ""
+
msgid "ContainerRegistry|Something went wrong while fetching the cleanup policy."
msgstr ""
@@ -6760,6 +7016,9 @@ msgstr ""
msgid "ContainerRegistry|Tags with names matching this regex pattern will %{italicStart}expire:%{italicEnd}"
msgstr ""
+msgid "ContainerRegistry|The cleanup policy timed out before it could delete all tags. An administrator can %{adminLinkStart}manually run cleanup now%{adminLinkEnd} or you can wait for the cleanup policy to automatically run again. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "ContainerRegistry|The last tag related to this image was recently removed. This empty image and any associated data will be automatically removed as part of the regular Garbage Collection process. If you have any questions, contact your administrator."
msgstr "La última etiqueta relacionada con esta imagen fue eliminada recientemente. Esta imagen vacía y cualquier dato asociado se eliminarán automáticamente como parte del proceso llamado \"Garbage Collection\". Si tienes alguna pregunta, póngase en contacto con su administrador."
@@ -6892,6 +7151,9 @@ msgstr ""
msgid "Contributions per group member"
msgstr "Contribuciones por cada miembro de un grupo"
+msgid "Contributor"
+msgstr ""
+
msgid "Contributors"
msgstr "Contribuidores"
@@ -7021,6 +7283,9 @@ msgstr "No se puede autorizar el nick del chat. Por favor, inténtelo de nuevo"
msgid "Could not change HEAD: branch '%{branch}' does not exist"
msgstr "No se pudo cambiar HEAD: el branch '%{branch}' no existe"
+msgid "Could not commit. An unexpected error occurred."
+msgstr ""
+
msgid "Could not connect to FogBugz, check your URL"
msgstr "No se puede conectar a FogBugz, por favor, compruebe su URL"
@@ -7060,6 +7325,9 @@ msgstr "No se pudo encontrar el diseño."
msgid "Could not find iteration"
msgstr ""
+msgid "Could not load instance counts. Please refresh the page to try again."
+msgstr ""
+
msgid "Could not remove the trigger."
msgstr "No es posible eliminar el disparador."
@@ -7084,12 +7352,12 @@ msgstr "Se ha producido un error al guardar el ID del proyecto"
msgid "Could not save prometheus manual configuration"
msgstr "Se ha producido un error al guardar la configuración manual de Prometheus"
-msgid "Could not udpdate wiki page"
-msgstr ""
-
msgid "Could not update the LDAP settings"
msgstr "No se pudo actualizar la configuración de LDAP"
+msgid "Could not update wiki page"
+msgstr ""
+
msgid "Could not upload your designs as one or more files uploaded are not supported."
msgstr ""
@@ -7745,6 +8013,9 @@ msgstr "No se puede agregar %{invalidProjects}. Este panel de control está disp
msgid "DastProfiles|Are you sure you want to delete this profile?"
msgstr ""
+msgid "DastProfiles|Could not create site validation token. Please refresh the page, or try again later."
+msgstr ""
+
msgid "DastProfiles|Could not create the scanner profile. Please try again."
msgstr ""
@@ -7769,6 +8040,12 @@ msgstr ""
msgid "DastProfiles|Could not fetch site profiles. Please refresh the page, or try again later."
msgstr ""
+msgid "DastProfiles|Could not retrieve site validation status. Please refresh the page, or try again later."
+msgstr ""
+
+msgid "DastProfiles|Could not update the scanner profile. Please try again."
+msgstr ""
+
msgid "DastProfiles|Could not update the site profile. Please try again."
msgstr ""
@@ -7784,7 +8061,7 @@ msgstr ""
msgid "DastProfiles|Download validation text file"
msgstr ""
-msgid "DastProfiles|Edit feature will come soon. Please create a new profile if changes needed"
+msgid "DastProfiles|Edit scanner profile"
msgstr ""
msgid "DastProfiles|Edit site profile"
@@ -7817,6 +8094,9 @@ msgstr ""
msgid "DastProfiles|No profiles created yet"
msgstr ""
+msgid "DastProfiles|Passive"
+msgstr ""
+
msgid "DastProfiles|Please enter a valid URL format, ex: http://www.example.com/home"
msgstr ""
@@ -7832,6 +8112,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan mode"
+msgstr ""
+
msgid "DastProfiles|Scanner Profile"
msgstr ""
@@ -7871,10 +8154,10 @@ msgstr ""
msgid "DastProfiles|Text file validation"
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
+msgid "DastProfiles|The maximum number of minutes allowed for the spider to traverse the site."
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the spider to traverse the site."
+msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
msgstr ""
msgid "DastProfiles|Validate"
@@ -7907,6 +8190,9 @@ msgstr "Fecha"
msgid "Date picker"
msgstr "Selector de fecha"
+msgid "Date range"
+msgstr ""
+
msgid "Date range cannot exceed %{maxDateRange} days."
msgstr ""
@@ -7931,6 +8217,9 @@ msgstr "Días"
msgid "Days to merge"
msgstr "Días para hacer merge"
+msgid "Dear Administrator,"
+msgstr ""
+
msgid "Debug"
msgstr "Depurar"
@@ -8042,12 +8331,18 @@ msgstr "retrasado"
msgid "Delete"
msgstr "Eliminar"
+msgid "Delete %{name}"
+msgstr ""
+
msgid "Delete Comment"
msgstr "Eliminar el comentario"
msgid "Delete Snippet"
msgstr "Eliminar fragmento de código"
+msgid "Delete Value Stream"
+msgstr ""
+
msgid "Delete account"
msgstr ""
@@ -8069,9 +8364,6 @@ msgstr "Eliminar etiqueta"
msgid "Delete label: %{label_name} ?"
msgstr "¿Eliminar la etiqueta: %{label_name}?"
-msgid "Delete license"
-msgstr "Eliminar la licencia"
-
msgid "Delete list"
msgstr "Eliminar lista"
@@ -8147,15 +8439,6 @@ msgstr "Eliminando"
msgid "Deleting a project places it into a read-only state until %{date}, at which point the project will be permanently deleted. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "Deleting the license failed."
-msgstr "Se ha producido un error al eliminar la licencia."
-
-msgid "Deleting the license failed. The license was not found."
-msgstr "Se ha producido un error al eliminar la licencia. No se encontró ninguna licencia."
-
-msgid "Deleting the license failed. You are not permitted to perform this action."
-msgstr "Se ha producido un error al eliminar la licencia. No tiene permiso para realizar esta acción."
-
msgid "Deleting the project will delete its repository and all related resources including issues, merge requests etc."
msgstr ""
@@ -8651,7 +8934,10 @@ msgstr "Seleccionar todo"
msgid "DesignManagement|The maximum number of designs allowed to be uploaded is %{upload_limit}. Please try again."
msgstr "El número máximo de diseños permitidos que se pueden cargar es %{upload_limit}. Por favor, inténtalo de nuevo."
-msgid "DesignManagement|To upload designs, you'll need to enable LFS. %{requirements_link_start}More information%{requirements_link_end}"
+msgid "DesignManagement|There was an error moving your designs. Please upload your designs below."
+msgstr ""
+
+msgid "DesignManagement|To upload designs, you'll need to enable LFS and have admin enable hashed storage. %{requirements_link_start}More information%{requirements_link_end}"
msgstr ""
msgid "DesignManagement|Unresolve thread"
@@ -8663,6 +8949,9 @@ msgstr "Subir diseños"
msgid "DesignManagement|Upload skipped."
msgstr ""
+msgid "DesignManagement|Your designs are being copied and are on their way… Please refresh to update."
+msgstr ""
+
msgid "DesignManagement|and %{moreCount} more."
msgstr "y %{moreCount} más."
@@ -8720,6 +9009,9 @@ msgstr ""
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr "Se ha producido un error mientras se obtienen las líneas del diff."
+msgid "Direct member"
+msgstr ""
+
msgid "Direction"
msgstr "Dirección"
@@ -8768,9 +9060,6 @@ msgstr "¿Descartar los cambios en %{path}?"
msgid "Discard draft"
msgstr "Descartar borrador"
-msgid "Discard review"
-msgstr "Descartar la revisión"
-
msgid "DiscordService|Discord Notifications"
msgstr "Notificaciones de Discord"
@@ -8839,12 +9128,12 @@ msgstr ""
msgid "Dismiss Merge Request promotion"
msgstr "Ocultar la promoción del merge request"
-msgid "Dismiss Selected"
-msgstr "Descartar seleccionado"
-
msgid "Dismiss Value Stream Analytics introduction box"
msgstr ""
+msgid "Dismiss selected"
+msgstr ""
+
msgid "Dismiss trial promotion"
msgstr "Ocultar el cuadro de introducción del periodo de prueba"
@@ -8893,9 +9182,6 @@ msgstr "Documentación para los proveedores de identidad más populares"
msgid "Documents reindexed: %{processed_documents} (%{percentage}%%)"
msgstr ""
-msgid "Doing"
-msgstr "En proceso"
-
msgid "Domain"
msgstr "Dominio"
@@ -9091,9 +9377,6 @@ msgstr "Editar descripción"
msgid "Edit environment"
msgstr "Editar el entorno"
-msgid "Edit file"
-msgstr "Editar archivo"
-
msgid "Edit files in the editor and commit changes here"
msgstr "Editar los archivos en el editor y confirmar los cambios aquí"
@@ -9106,6 +9389,12 @@ msgstr "Editar grupo: %{group_name}"
msgid "Edit identity for %{user_name}"
msgstr "Editar la identidad para %{user_name}"
+msgid "Edit in Web IDE"
+msgstr ""
+
+msgid "Edit in single-file editor"
+msgstr ""
+
msgid "Edit issues"
msgstr "Editar incidencias"
@@ -9133,21 +9422,18 @@ msgstr "Editado %{timeago}"
msgid "Editing"
msgstr "Editando"
-msgid "Elasticsearch"
-msgstr "Elasticsearch"
-
msgid "Elasticsearch AWS IAM credentials"
msgstr "Credenciales IAM de AWS Elasticsearch"
+msgid "Elasticsearch HTTP client timeout value in seconds."
+msgstr ""
+
msgid "Elasticsearch indexing restrictions"
msgstr "Restricciones en la indexación de Elasticsearch"
msgid "Elasticsearch indexing started"
msgstr "Comenzó la indexación de Elasticsearch"
-msgid "Elasticsearch integration. Elasticsearch AWS IAM."
-msgstr "Integración de Elastisearch. Elasticsearch AWS IAM."
-
msgid "Elasticsearch reindexing is already in progress"
msgstr ""
@@ -9175,9 +9461,6 @@ msgstr ""
msgid "Email Notification"
msgstr "Notificación por correo electrónico"
-msgid "Email address"
-msgstr "Correo electrónico"
-
msgid "Email could not be sent"
msgstr "No se ha podido enviar el correo electrónico"
@@ -9241,6 +9524,9 @@ msgstr "Correos electrónicos"
msgid "Emails sent from Service Desk will have this name"
msgstr "Los correos electrónicos enviados desde Service Desk tendrán este nombre"
+msgid "Emails sent to %{email} will still be supported"
+msgstr ""
+
msgid "Emails separated by comma"
msgstr "Correos electrónicos separados por comas"
@@ -9274,9 +9560,18 @@ msgstr "Archivo vacío"
msgid "Enable"
msgstr "Habilitar"
+msgid "Enable %{link_start}Gitpod%{link_end} integration to launch a development environment in your browser directly from GitLab."
+msgstr ""
+
msgid "Enable Auto DevOps"
msgstr "Activar Auto DevOps"
+msgid "Enable Gitpod"
+msgstr ""
+
+msgid "Enable Gitpod?"
+msgstr ""
+
msgid "Enable HTML emails"
msgstr "Habilitar correos HTML"
@@ -9406,9 +9701,6 @@ msgstr "Habilitar esta opción solo hará que las funciones con licencia EE estÃ
msgid "Encountered an error while rendering: %{err}"
msgstr "Se ha producido un error al renderizar: %{err}"
-msgid "End date"
-msgstr "Fecha de finalización"
-
msgid "Ends at (UTC)"
msgstr "Finaliza a las (UTC)"
@@ -9568,7 +9860,7 @@ msgstr "Eliminar"
msgid "EnvironmentsDashboard|The environments dashboard provides a summary of each project's environments' status, including pipeline and alert statuses."
msgstr "El panel de control de entornos proporciona un resumen detallado del estado de los entornos de cada proyecto, incluidos los estados de alerta y de los pipelines."
-msgid "EnvironmentsDashboard|This dashboard displays a maximum of 7 projects and 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
+msgid "EnvironmentsDashboard|This dashboard displays 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
msgstr ""
msgid "Environments|An error occurred while canceling the auto stop, please try again"
@@ -9889,6 +10181,9 @@ msgstr ""
msgid "Error deleting project. Check logs for error details."
msgstr ""
+msgid "Error fetching burnup chart data"
+msgstr ""
+
msgid "Error fetching diverging counts for branches. Please try again."
msgstr ""
@@ -9967,6 +10262,9 @@ msgstr "Se ha producido un error al obtener los datos de la barra lateral"
msgid "Error occurred when saving assignees"
msgstr "Se ha producido un error mientras se guardaban los asignados"
+msgid "Error occurred when saving reviewers"
+msgstr ""
+
msgid "Error occurred when toggling the notification subscription"
msgstr "Se ha producido un error al activar/desactivar la suscripción de las notificaciones"
@@ -10219,12 +10517,15 @@ msgstr "Expandir"
msgid "Expand all"
msgstr "Expandir todo"
+msgid "Expand all files"
+msgstr ""
+
+msgid "Expand all threads"
+msgstr ""
+
msgid "Expand approvers"
msgstr "Expandir aprobadores"
-msgid "Expand dropdown"
-msgstr "Expandir el menú desplegable"
-
msgid "Expand milestones"
msgstr ""
@@ -10393,6 +10694,9 @@ msgstr "Se ha producido un error al verificar las branchs relacionadas."
msgid "Failed to create Merge Request. Please try again."
msgstr "No es posible realizar el merge request. Por favor, inténtelo de nuevo."
+msgid "Failed to create To-Do for the design."
+msgstr ""
+
msgid "Failed to create a branch for this issue. Please try again."
msgstr "Se ha producido un erro al crear una rama para esta incidencia. Por favor, inténtalo de nuevo."
@@ -10432,6 +10736,12 @@ msgstr ""
msgid "Failed to load authors. Please try again."
msgstr ""
+msgid "Failed to load branches. Please try again."
+msgstr ""
+
+msgid "Failed to load deploy keys."
+msgstr ""
+
msgid "Failed to load emoji list."
msgstr "Se ha producido un error al cargar la lista de emojis."
@@ -10447,6 +10757,9 @@ msgstr ""
msgid "Failed to load groups & users."
msgstr "Se ha producido un error al cargar grupos y usuarios."
+msgid "Failed to load groups, users and deploy keys."
+msgstr ""
+
msgid "Failed to load labels. Please try again."
msgstr "Se ha producido un error al cargar las etiquetas. Por favor, inténtelo de nuevo."
@@ -10456,6 +10769,12 @@ msgstr "Se ha producido un error al cargar los hitos. Por favor, inténtelo de n
msgid "Failed to load related branches"
msgstr "Se ha producido un error al cargar ramas relacionadas"
+msgid "Failed to load sidebar confidential toggle"
+msgstr ""
+
+msgid "Failed to load sidebar lock status"
+msgstr ""
+
msgid "Failed to load stacktrace."
msgstr "Se ha producido un error al cargar el stacktrace."
@@ -10483,6 +10802,9 @@ msgstr "Se ha producido un error al proteger el entorno"
msgid "Failed to publish issue on status page."
msgstr ""
+msgid "Failed to remove To-Do for the design."
+msgstr ""
+
msgid "Failed to remove a Zoom meeting"
msgstr "Se ha producido un error al eliminar una reunión de Zoom"
@@ -10525,6 +10847,9 @@ msgstr ""
msgid "Failed to signing using smartcard authentication"
msgstr "Se ha producido un error al inciar sesión utilizando la autenticación mediante una tarjeta inteligente"
+msgid "Failed to toggle To-Do for the design."
+msgstr ""
+
msgid "Failed to update branch!"
msgstr "¡Se ha producido un error al actualizar la rama!"
@@ -10638,7 +10963,7 @@ msgstr "Editar Feature Flag"
msgid "FeatureFlags|Edit User List"
msgstr ""
-msgid "FeatureFlags|Enable features for specific users and specific environments by defining feature flag strategies."
+msgid "FeatureFlags|Enable features for specific users and environments by configuring feature flag strategies."
msgstr ""
msgid "FeatureFlags|Environment Spec"
@@ -10698,8 +11023,8 @@ msgstr "Desactivar Flag para %{scope}"
msgid "FeatureFlags|Include additional user IDs"
msgstr "Incluye IDs de usuario adicionales"
-msgid "FeatureFlags|Install a %{docs_link_anchored_start}compatible client library%{docs_link_anchored_end} and specify the API URL, application name, and instance ID during the configuration setup. %{docs_link_start}More Information%{docs_link_end}"
-msgstr "Instale un %{docs_link_anchored_start}cliente compatible con la biblioteca de%{docs_link_anchored_end} y especifique la URL de la API, el nombre de la aplicación y él ID de la instancia durante el proceso de configuración.%{docs_link_start}Más información%{docs_link_end}"
+msgid "FeatureFlags|Install a %{docsLinkAnchoredStart}compatible client library%{docsLinkAnchoredEnd} and specify the API URL, application name, and instance ID during the configuration setup. %{docsLinkStart}More Information%{docsLinkEnd}"
+msgstr ""
msgid "FeatureFlags|Instance ID"
msgstr "ID de instancia"
@@ -10710,6 +11035,9 @@ msgstr "Detalles de la lista"
msgid "FeatureFlags|Loading feature flags"
msgstr ""
+msgid "FeatureFlags|Loading user lists"
+msgstr ""
+
msgid "FeatureFlags|More information"
msgstr "Más información"
@@ -10728,8 +11056,8 @@ msgstr ""
msgid "FeatureFlags|New feature flag"
msgstr ""
-msgid "FeatureFlags|New list"
-msgstr "Nueva lista"
+msgid "FeatureFlags|New user list"
+msgstr ""
msgid "FeatureFlags|Percent of users"
msgstr ""
@@ -10767,6 +11095,9 @@ msgstr "Entornos de destino"
msgid "FeatureFlags|There was an error fetching the feature flags."
msgstr "Se ha producido un error al obtener las Feature Flag."
+msgid "FeatureFlags|There was an error fetching the user lists."
+msgstr ""
+
msgid "FeatureFlags|There was an error retrieving user lists"
msgstr ""
@@ -10782,6 +11113,9 @@ msgstr "IDs de usuarios"
msgid "FeatureFlags|User List"
msgstr ""
+msgid "FeatureFlags|User Lists"
+msgstr ""
+
msgid "FeatureFlag|List"
msgstr "Lista"
@@ -10809,15 +11143,6 @@ msgstr "Febrero"
msgid "Fetching incoming email"
msgstr "Obteniendo el correo entrante"
-msgid "Fetching licenses failed."
-msgstr "Se ha producido un error al obtener las licencias."
-
-msgid "Fetching licenses failed. The request endpoint was not found."
-msgstr "Se ha producido un error al obtener las licencias. No es posible encontrar el endpoint de la solicitud."
-
-msgid "Fetching licenses failed. You are not permitted to perform this action."
-msgstr "Se ha producido un error al obtener las licencias. No está autorizado a realizar esta acción."
-
msgid "File"
msgstr "Archivo"
@@ -10920,12 +11245,21 @@ msgstr ""
msgid "Filter by status"
msgstr "Filtrar por estado"
+msgid "Filter by test cases that are currently archived."
+msgstr ""
+
+msgid "Filter by test cases that are currently opened."
+msgstr ""
+
msgid "Filter by two-factor authentication"
msgstr "Filtrar por autenticación de dos factores"
msgid "Filter by user"
msgstr "Filtrar por usuario"
+msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
+msgstr ""
+
msgid "Filter pipelines"
msgstr ""
@@ -10941,8 +11275,8 @@ msgstr "Filtrar resultados por proyecto"
msgid "Filter results..."
msgstr "Filtrar resultados..."
-msgid "Filter your projects by name"
-msgstr "Filtra sus proyectos por nombre"
+msgid "Filter your repositories by name"
+msgstr ""
msgid "Filter..."
msgstr "Filtrar..."
@@ -10950,7 +11284,7 @@ msgstr "Filtrar..."
msgid "Find File"
msgstr ""
-msgid "Find bugs in your code with coverage-guided fuzzing"
+msgid "Find bugs in your code with coverage-guided fuzzing."
msgstr ""
msgid "Find by path"
@@ -10977,9 +11311,6 @@ msgstr "Huellas digitales"
msgid "Finish editing this message first!"
msgstr "¡Termine la edición de este mensaje primero!"
-msgid "Finish review"
-msgstr "Finalizar revisión"
-
msgid "Finish setting up your dedicated account for %{group_name}."
msgstr ""
@@ -11049,6 +11380,9 @@ msgstr "Color de la fuente"
msgid "Footer message"
msgstr "Mensaje a pie de página"
+msgid "For a faster browsing experience, some files are collapsed by default."
+msgstr ""
+
msgid "For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
@@ -11058,6 +11392,9 @@ msgstr "Para los proyectos internos, cualquier usuario que haya iniciado sesión
msgid "For more info, read the documentation."
msgstr "Para más información, por favor lea la documentación."
+msgid "For more information on how the number of active users is calculated, see the %{self_managed_subscriptions_doc_link} documentation."
+msgstr ""
+
msgid "For more information, go to the "
msgstr "Para obtener más información, vaya a "
@@ -11196,6 +11533,9 @@ msgstr "Generar nueva exportación"
msgid "Generate new token"
msgstr ""
+msgid "Generic package file size in bytes"
+msgstr ""
+
msgid "Geo"
msgstr "Geo"
@@ -11457,6 +11797,9 @@ msgstr "Pendiente de verificación"
msgid "Geo|Please refer to Geo Troubleshooting."
msgstr "Por favor, consulte la sección de solución de problemas de Geo."
+msgid "Geo|Primary node"
+msgstr ""
+
msgid "Geo|Project"
msgstr "Proyecto"
@@ -11499,6 +11842,9 @@ msgstr "Volver a comprobar todo"
msgid "Geo|Review replication status, and resynchronize and reverify items with the primary node."
msgstr ""
+msgid "Geo|Secondary node"
+msgstr ""
+
msgid "Geo|Status"
msgstr "Estado"
@@ -11538,6 +11884,9 @@ msgstr "La URL no puede estar en blanco"
msgid "Geo|URL must be a valid url (ex: https://gitlab.com)"
msgstr "La URL debe ser una URL válida (ej: https://gitlab.com)"
+msgid "Geo|Undefined"
+msgstr ""
+
msgid "Geo|Unknown state"
msgstr "Estado desconocido"
@@ -11613,11 +11962,17 @@ msgstr ""
msgid "GitHub import"
msgstr "Importar desde GitHub"
+msgid "GitLab"
+msgstr ""
+
msgid "GitLab / Unsubscribe"
msgstr "GitLab / Darse de baja"
-msgid "GitLab Enterprise Edition %{plan}"
-msgstr "GitLab Enterprise Edition %{plan}"
+msgid "GitLab API"
+msgstr ""
+
+msgid "GitLab Billing Team."
+msgstr ""
msgid "GitLab Group Runners can execute code for all the projects in this group."
msgstr "El grupo de ejecutores de GitLab puede ejecutar código para todos los proyectos en este grupo."
@@ -11628,12 +11983,18 @@ msgstr "Importar desde GitLab"
msgid "GitLab Issue"
msgstr "Incidencia de GitLab"
+msgid "GitLab Pages"
+msgstr ""
+
msgid "GitLab Service Desk is a simple way to allow people to create issues in your GitLab instance without needing their own user account. It provides a unique email address for end users to create issues in a project, and replies can be sent either through the GitLab interface or by email. End users will only see the thread through email."
msgstr ""
msgid "GitLab Shared Runners execute code of different projects on the same Runner unless you configure GitLab Runner Autoscale with MaxBuilds 1 (which it is on GitLab.com)."
msgstr "Los ejecutores compartidos de GitLab ejecutan el código de diferentes proyectos en el mismo ejecutor a menos que configure el auto escalado de os ejecutores de GitLab con MaxBuilds 1 (que se encuentra en GitLab.com)."
+msgid "GitLab Shell"
+msgstr ""
+
msgid "GitLab Support Bot"
msgstr "Bot de soporte de GitLab"
@@ -11643,8 +12004,8 @@ msgstr "Miembro del equipo de GitLab"
msgid "GitLab User"
msgstr "Usuario de GitLab"
-msgid "GitLab allows you to continue using your license even if you exceed the number of seats you purchased. You will be required to pay for these seats when you renew your license."
-msgstr "GitLab le permite continuar usando su licencia incluso si excede la cantidad puestos que compró. Deberá por pagar estos puestos cuando renueve su licencia."
+msgid "GitLab Workhorse"
+msgstr ""
msgid "GitLab commit"
msgstr "GitLab commit"
@@ -11811,6 +12172,21 @@ msgstr "Importar desde Gitea"
msgid "Gitlab Pages"
msgstr "GitLab Pages"
+msgid "Gitpod"
+msgstr ""
+
+msgid "Gitpod|Add the URL to your Gitpod instance configured to read your GitLab projects."
+msgstr ""
+
+msgid "Gitpod|Enable Gitpod integration"
+msgstr ""
+
+msgid "Gitpod|Gitpod URL"
+msgstr ""
+
+msgid "Gitpod|e.g. https://gitpod.example.com"
+msgstr ""
+
msgid "Given access %{time_ago}"
msgstr "Acceso concedido %{time_ago}"
@@ -12318,9 +12694,6 @@ msgstr "Activar la autenticación SAML"
msgid "GroupSAML|Valid SAML Response"
msgstr "Respuesta SAML válida"
-msgid "GroupSAML|With group managed accounts enabled, all the users without a group managed account will be excluded from the group."
-msgstr "Con las cuentas administradas de grupo habilitadas, todos los usuarios sin una cuenta administrada de grupo serán excluidos del mismo."
-
msgid "GroupSAML|With prohibit outer forks flag enabled group members will be able to fork project only inside your group."
msgstr ""
@@ -12534,10 +12907,10 @@ msgstr ""
msgid "GroupsNew|Create group"
msgstr ""
-msgid "GroupsNew|GitLab group export"
+msgid "GroupsNew|Import"
msgstr ""
-msgid "GroupsNew|Import"
+msgid "GroupsNew|Import a GitLab group export file"
msgstr ""
msgid "GroupsNew|Import group"
@@ -12680,6 +13053,9 @@ msgid_plural "Hide charts"
msgstr[0] "Ocultar gráfico"
msgstr[1] "Ocultar gráficos"
+msgid "Hide comments on this file"
+msgstr ""
+
msgid "Hide details"
msgstr "Ocultar detalles"
@@ -12724,6 +13100,15 @@ msgstr "Mayor número de solicitudes por minuto para cada ruta sin procesar, por
msgid "Highest role:"
msgstr "Rol más alto:"
+msgid "HighlightBar|Alert events:"
+msgstr ""
+
+msgid "HighlightBar|Alert start time:"
+msgstr ""
+
+msgid "HighlightBar|Original alert:"
+msgstr ""
+
msgid "History"
msgstr "Historial"
@@ -12901,6 +13286,9 @@ msgstr ""
msgid "If enabled, access to projects will be validated on an external service using their classification label."
msgstr "Si está habilitado, el acceso a los proyectos se validará en un servicio externo utilizando su etiqueta de clasificación."
+msgid "If the number of active users exceeds the user limit, you will be charged for the number of %{users_over_license_link} at your next license reconciliation."
+msgstr ""
+
msgid "If there is no previous license or if the previous license has expired, some GitLab functionality will be blocked until a new, valid license is uploaded."
msgstr ""
@@ -12940,9 +13328,6 @@ msgstr ""
msgid "If your HTTP repository is not publicly accessible, add your credentials."
msgstr "Si su repositorio HTTP no es accesible públicamente, añada sus credenciales."
-msgid "Iglu registry URL (optional)"
-msgstr "URL del registro de Iglu (opcional)"
-
msgid "Ignore"
msgstr "Ignorar"
@@ -12979,6 +13364,16 @@ msgstr "La suplantación ha sido deshabilitada"
msgid "Import"
msgstr "Importar"
+msgid "Import %d compatible repository"
+msgid_plural "Import %d compatible repositories"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Import %d repository"
+msgid_plural "Import %d repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Import CSV"
msgstr "Importar CSV"
@@ -12988,15 +13383,9 @@ msgstr "Importar proyectos desde Gitea"
msgid "Import all compatible projects"
msgstr "Importar todos los proyectos compatibles"
-msgid "Import all compatible repositories"
-msgstr "Importar todos los repositorios compatibles"
-
msgid "Import all projects"
msgstr "Importar todos los proyectos"
-msgid "Import all repositories"
-msgstr "Importar todos los repositorios"
-
msgid "Import an exported GitLab project"
msgstr "Importar un proyecto exportado desde GitLab"
@@ -13084,6 +13473,9 @@ msgstr "URL de importación bloqueada: %{message}"
msgid "ImportProjects|Error importing repository %{project_safe_import_url} into %{project_full_path} - %{message}"
msgstr "Error al importar el repositorio %{project_safe_import_url} en %{project_full_path} - %{message}"
+msgid "ImportProjects|Import repositories"
+msgstr ""
+
msgid "ImportProjects|Importing the project failed"
msgstr "Se ha producido un error al importar el proyecto"
@@ -13096,8 +13488,8 @@ msgstr ""
msgid "ImportProjects|Requesting your %{provider} repositories failed"
msgstr "Solicitando a su %{provider} los repositorios fallados"
-msgid "ImportProjects|Select the projects you want to import"
-msgstr "Seleccione los proyectos que desea importar"
+msgid "ImportProjects|Select the repositories you want to import"
+msgstr ""
msgid "ImportProjects|The remote data could not be imported."
msgstr "No se pudieron importar los datos remotos."
@@ -13132,9 +13524,6 @@ msgstr "En %{time_to_now}"
msgid "In order to enable Service Desk for your instance, you must first set up incoming email."
msgstr ""
-msgid "In order to gather accurate feature usage data, it can take 1 to 2 weeks to see your index."
-msgstr "Con el fin de recopilar datos precisos sobre los datos de uso, es posible que tarde de 1 a 2 semanas en poder ver su índice."
-
msgid "In order to personalize your experience with GitLab%{br_tag}we would like to know a bit more about you."
msgstr ""
@@ -13165,18 +13554,30 @@ msgstr ""
msgid "IncidentManagement|Create incident"
msgstr ""
+msgid "IncidentManagement|Critical - S1"
+msgstr ""
+
msgid "IncidentManagement|Date created"
msgstr ""
msgid "IncidentManagement|Display your incidents in a dedicated view"
msgstr ""
+msgid "IncidentManagement|High - S2"
+msgstr ""
+
msgid "IncidentManagement|Incident"
msgstr ""
msgid "IncidentManagement|Incidents"
msgstr ""
+msgid "IncidentManagement|Low - S4"
+msgstr ""
+
+msgid "IncidentManagement|Medium - S3"
+msgstr ""
+
msgid "IncidentManagement|No incidents to display."
msgstr ""
@@ -13189,6 +13590,9 @@ msgstr ""
msgid "IncidentManagement|Published to status page"
msgstr ""
+msgid "IncidentManagement|Severity"
+msgstr ""
+
msgid "IncidentManagement|There are no closed incidents"
msgstr ""
@@ -13198,6 +13602,9 @@ msgstr ""
msgid "IncidentManagement|Unassigned"
msgstr ""
+msgid "IncidentManagement|Unknown"
+msgstr ""
+
msgid "IncidentManagement|Unpublished"
msgstr ""
@@ -13219,6 +13626,15 @@ msgstr ""
msgid "Incidents"
msgstr "Incidentes"
+msgid "Incident|Alert details"
+msgstr ""
+
+msgid "Incident|Summary"
+msgstr ""
+
+msgid "Incident|There was an issue loading alert data. Please try again."
+msgstr ""
+
msgid "Include a Terms of Service agreement and Privacy Policy that all users must accept."
msgstr "Incluya un acuerdo de términos de servicio y una política de privacidad que todos los usuarios deben aceptar."
@@ -13279,6 +13695,9 @@ msgstr "Informa a los usuarios que no hayan cargado las claves SSH que no pueden
msgid "Information about additional Pages templates and how to install them can be found in our %{pages_getting_started_guide}."
msgstr "Puede encontrar información sobre plantillas de Pages adicionales y cómo instalarlas en nuestro %{pages_getting_started_guide}."
+msgid "Inherited"
+msgstr ""
+
msgid "Inherited:"
msgstr "Heredado:"
@@ -13359,8 +13778,23 @@ msgstr ""
msgid "Instance administrators group already exists"
msgstr "Ya existe el grupo de administrador de instancias"
-msgid "Instance license"
-msgstr "Licencia de la instancia"
+msgid "InstanceStatistics|Groups"
+msgstr ""
+
+msgid "InstanceStatistics|Issues"
+msgstr ""
+
+msgid "InstanceStatistics|Merge Requests"
+msgstr ""
+
+msgid "InstanceStatistics|Pipelines"
+msgstr ""
+
+msgid "InstanceStatistics|Projects"
+msgstr ""
+
+msgid "InstanceStatistics|Users"
+msgstr ""
msgid "Integration"
msgstr "Integración"
@@ -13371,6 +13805,12 @@ msgstr "Ajustes de integración"
msgid "Integrations"
msgstr "Integraciones"
+msgid "Integrations|%{integration} settings saved and active."
+msgstr ""
+
+msgid "Integrations|%{integration} settings saved, but not active."
+msgstr ""
+
msgid "Integrations|All details"
msgstr "Todos los detalles"
@@ -13380,6 +13820,12 @@ msgstr "Detalles del comentario:"
msgid "Integrations|Comment settings:"
msgstr "Configuración de los comentarios:"
+msgid "Integrations|Connection failed. Please check your settings."
+msgstr ""
+
+msgid "Integrations|Connection successful."
+msgstr ""
+
msgid "Integrations|Default settings are inherited from the group level."
msgstr ""
@@ -13395,6 +13841,15 @@ msgstr ""
msgid "Integrations|Includes commit title and branch"
msgstr ""
+msgid "Integrations|Projects using custom settings will not be impacted unless the project owner chooses to use instance-level defaults."
+msgstr ""
+
+msgid "Integrations|Save settings?"
+msgstr ""
+
+msgid "Integrations|Saving will update the default settings for all projects that are not using custom settings."
+msgstr ""
+
msgid "Integrations|Standard"
msgstr "Estándar"
@@ -13527,6 +13982,9 @@ msgstr "Yaml no válido"
msgid "Invitation"
msgstr "Invitación"
+msgid "Invitation declined"
+msgstr ""
+
msgid "Invite"
msgstr "Invitar"
@@ -13578,6 +14036,42 @@ 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|%{linkStart}Read more%{linkEnd} about role permissions"
+msgstr ""
+
+msgid "InviteMembersModal|Access expiration date (optional)"
+msgstr ""
+
+msgid "InviteMembersModal|Cancel"
+msgstr ""
+
+msgid "InviteMembersModal|Choose a role permission"
+msgstr ""
+
+msgid "InviteMembersModal|GitLab member or Email address"
+msgstr ""
+
+msgid "InviteMembersModal|Invite"
+msgstr ""
+
+msgid "InviteMembersModal|Invite team members"
+msgstr ""
+
+msgid "InviteMembersModal|Search for members to invite"
+msgstr ""
+
+msgid "InviteMembersModal|User not invited. Feature coming soon!"
+msgstr ""
+
+msgid "InviteMembersModal|Users were succesfully added"
+msgstr ""
+
+msgid "InviteMembersModal|You're inviting members to the %{group_name} group"
+msgstr ""
+
+msgid "InviteMembers|Invite team members"
+msgstr ""
+
msgid "Invited"
msgstr ""
@@ -13632,10 +14126,13 @@ msgstr ""
msgid "Issue cannot be found."
msgstr "Incidencia no encontrada."
+msgid "Issue created from vulnerability %{vulnerability_link}"
+msgstr ""
+
msgid "Issue events"
msgstr "Eventos de incidencia"
-msgid "Issue first depoloyed to production"
+msgid "Issue first deployed to production"
msgstr ""
msgid "Issue label"
@@ -13713,6 +14210,9 @@ msgstr "Gestor de incidencias Bugzilla"
msgid "IssueTracker|Custom issue tracker"
msgstr "Gestor de incidencias personalizado"
+msgid "IssueTracker|EWM work items tracker"
+msgstr ""
+
msgid "IssueTracker|Redmine issue tracker"
msgstr "Gestor de incidencias Redmine"
@@ -13779,6 +14279,9 @@ msgstr "Título"
msgid "It looks like you have some draft commits in this branch."
msgstr ""
+msgid "It may be several days before you see feature usage data."
+msgstr ""
+
msgid "It must have a header row and at least two columns: the first column is the issue title and the second column is the issue description. The separator is automatically detected."
msgstr ""
@@ -14061,15 +14564,15 @@ msgstr "con"
msgid "Join Zoom meeting"
msgstr "Unirse a la reunión de Zoom"
+msgid "Joined %{time_ago}"
+msgstr ""
+
msgid "Jul"
msgstr "Jul"
msgid "July"
msgstr "Julio"
-msgid "Jump to first unresolved thread"
-msgstr "Saltar al primer hilo sin resolver"
-
msgid "Jump to next unresolved thread"
msgstr "Saltar al siguiente hilo sin resolver"
@@ -14103,6 +14606,9 @@ msgstr "Clave: %{key}"
msgid "Keyboard shortcuts"
msgstr "Atajos de teclado"
+msgid "KeyboardKey|Ctrl+"
+msgstr ""
+
msgid "Keys"
msgstr ""
@@ -14151,6 +14657,9 @@ msgstr "LDAP"
msgid "LDAP Synchronization"
msgstr ""
+msgid "LDAP group settings"
+msgstr ""
+
msgid "LDAP settings"
msgstr "Configuración LDAP"
@@ -14160,6 +14669,9 @@ msgstr "Configuración de LDAP actualizada"
msgid "LDAP sync in progress. This could take a few minutes. Refresh the page to see the changes."
msgstr "Sincronización LDAP en curso. Esto podría tardar unos minutos. Por favor, actualice la página para ver los cambios."
+msgid "LDAP synchronizations"
+msgstr ""
+
msgid "LFS"
msgstr "LFS"
@@ -14240,8 +14752,17 @@ msgid_plural "Last %d days"
msgstr[0] "Último %d día"
msgstr[1] "Últimos %d días"
-msgid "Last %{days} days"
-msgstr "Últimos %{days} días"
+msgid "Last 2 weeks"
+msgstr ""
+
+msgid "Last 30 days"
+msgstr ""
+
+msgid "Last 60 days"
+msgstr ""
+
+msgid "Last 90 days"
+msgstr ""
msgid "Last Accessed On"
msgstr "Último acceso el"
@@ -14318,6 +14839,9 @@ msgstr "Utilizado por última vez"
msgid "Last used on:"
msgstr "Utilizado por última vez en:"
+msgid "Last week"
+msgstr ""
+
msgid "LastCommit|authored"
msgstr "Autor"
@@ -14333,6 +14857,9 @@ msgstr "Últimos cambios"
msgid "Latest pipeline for the most recent commit on this branch"
msgstr "Último pipeline para el commit más reciente en esta rama"
+msgid "Launch a ready-to-code development environment for your project."
+msgstr ""
+
msgid "Lead"
msgstr ""
@@ -14713,6 +15240,9 @@ msgstr "Lista de repositorios disponibles"
msgid "List of all merge commits"
msgstr ""
+msgid "List options"
+msgstr ""
+
msgid "List settings"
msgstr ""
@@ -14725,9 +15255,6 @@ msgstr "Vista de lista"
msgid "List your Bitbucket Server repositories"
msgstr "Listar sus repositorios de Bitbucket Server"
-msgid "Lists"
-msgstr ""
-
msgid "Live preview"
msgstr "Vista previa"
@@ -14974,6 +15501,12 @@ msgstr "Marcar la tarea pendiente como hecha"
msgid "Mark as done"
msgstr "Marcar como completado"
+msgid "Mark as draft"
+msgstr ""
+
+msgid "Mark as ready"
+msgstr ""
+
msgid "Mark as resolved"
msgstr "Marcar como resuelto"
@@ -14995,6 +15528,24 @@ msgstr "Markdown habilitado"
msgid "Markdown is supported"
msgstr "Compatible con la sintaxis de Markdown"
+msgid "MarkdownEditor|Add a link (%{modifierKey}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add a link (%{modifier_key}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifierKey}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifier_key}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifierKey}I)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifier_key}I)"
+msgstr ""
+
msgid "Marked For Deletion At - %{deletion_time}"
msgstr ""
@@ -15079,8 +15630,26 @@ msgstr ""
msgid "Max access level"
msgstr "Nivel de acceso máximo"
-msgid "Max seats used"
-msgstr "Máximo de puestos utilizados"
+msgid "Max role"
+msgstr ""
+
+msgid "Max size 15 MB"
+msgstr ""
+
+msgid "Maximum Conan package file size in bytes"
+msgstr ""
+
+msgid "Maximum Maven package file size in bytes"
+msgstr ""
+
+msgid "Maximum NPM package file size in bytes"
+msgstr ""
+
+msgid "Maximum NuGet package file size in bytes"
+msgstr ""
+
+msgid "Maximum PyPI package file size in bytes"
+msgstr ""
msgid "Maximum Users:"
msgstr "Número máximo de usuarios:"
@@ -15211,6 +15780,18 @@ msgstr ""
msgid "Members with access to %{strong_start}%{group_name}%{strong_end}"
msgstr "Miembros con acceso a %{strong_start}%{group_name}%{strong_end}"
+msgid "Members|%{time} by %{user}"
+msgstr ""
+
+msgid "Members|Expired"
+msgstr ""
+
+msgid "Members|No expiration set"
+msgstr ""
+
+msgid "Members|in %{time}"
+msgstr ""
+
msgid "Memory Usage"
msgstr "Uso de memoria"
@@ -15397,9 +15978,6 @@ msgstr "El hilo será resuelto"
msgid "MergeRequests|Thread will be unresolved"
msgstr "El hilo no se resolverá"
-msgid "MergeRequests|Toggle comments for this file"
-msgstr "Alternar los comentarios para este archivo"
-
msgid "MergeRequests|View file @ %{commitId}"
msgstr "Ver el archivo @ %{commitId}"
@@ -15460,6 +16038,9 @@ msgstr ""
msgid "Merging immediately isn't recommended as it may negatively impact the existing merge train. Read the %{docsLinkStart}documentation%{docsLinkEnd} for more information."
msgstr ""
+msgid "Message"
+msgstr ""
+
msgid "Messages"
msgstr "Mensajes"
@@ -15845,18 +16426,12 @@ msgid_plural "Milestones"
msgstr[0] "Hito"
msgstr[1] "Hitos"
-msgid "Milestone does not support burnup charts"
-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 lists show all issues from the selected milestone."
msgstr "Las listas de hitos muestran todas las incidencias desde el hito seleccionado."
-msgid "Milestone must have a start and due date"
-msgstr ""
-
msgid "MilestoneSidebar|Closed:"
msgstr "Cerrado:"
@@ -16223,6 +16798,9 @@ msgstr "Nombre:"
msgid "Namespace"
msgstr ""
+msgid "Namespace ID:"
+msgstr ""
+
msgid "Namespace is empty"
msgstr "Espacio de nombres está vacía"
@@ -16307,6 +16885,9 @@ msgstr ""
msgid "NetworkPolicies|Allow all outbound traffic from %{selector} to %{ruleSelector} on %{ports}"
msgstr ""
+msgid "NetworkPolicies|Are you sure you want to delete this policy? This action cannot be undone."
+msgstr ""
+
msgid "NetworkPolicies|Choose whether to enforce this policy."
msgstr ""
@@ -16316,12 +16897,21 @@ msgstr ""
msgid "NetworkPolicies|Define this policy's location, conditions and actions."
msgstr ""
+msgid "NetworkPolicies|Delete policy"
+msgstr ""
+
+msgid "NetworkPolicies|Delete policy: %{policy}"
+msgstr ""
+
msgid "NetworkPolicies|Deny all traffic"
msgstr ""
msgid "NetworkPolicies|Description"
msgstr ""
+msgid "NetworkPolicies|Edit policy"
+msgstr ""
+
msgid "NetworkPolicies|Editor mode"
msgstr ""
@@ -16349,6 +16939,9 @@ msgstr "Última modificación"
msgid "NetworkPolicies|Name"
msgstr "Nombre"
+msgid "NetworkPolicies|Namespace"
+msgstr ""
+
msgid "NetworkPolicies|Network Policy"
msgstr ""
@@ -16400,6 +16993,9 @@ msgstr ""
msgid "NetworkPolicies|Rules"
msgstr ""
+msgid "NetworkPolicies|Save changes"
+msgstr ""
+
msgid "NetworkPolicies|Something went wrong, failed to update policy"
msgstr "Algo salió mal, se ha producido un error al actualizar la política"
@@ -16412,6 +17008,9 @@ msgstr ""
msgid "NetworkPolicies|Traffic that does not match any rule will be blocked."
msgstr ""
+msgid "NetworkPolicies|Unable to parse policy"
+msgstr ""
+
msgid "NetworkPolicies|YAML editor"
msgstr ""
@@ -16525,6 +17124,9 @@ msgstr ""
msgid "New Snippet"
msgstr "Nuevo fragmento de código"
+msgid "New Test Case"
+msgstr ""
+
msgid "New User"
msgstr ""
@@ -16624,6 +17226,9 @@ msgstr "Nuevo sub-grupo"
msgid "New tag"
msgstr "Nueva etiqueta"
+msgid "New test case"
+msgstr ""
+
msgid "New users set to external"
msgstr "Nuevos usuarios configurados como externos"
@@ -16696,8 +17301,8 @@ msgstr "No se han encontrado ramas"
msgid "No changes"
msgstr "Sin cambios"
-msgid "No changes between %{ref_start}%{source_branch}%{ref_end} and %{ref_start}%{target_branch}%{ref_end}"
-msgstr "No hay cambios entre %{ref_start}%{source_branch}%{ref_end} y %{ref_start}%{target_branch}%{ref_end}"
+msgid "No changes between %{sourceBranch} and %{targetBranch}"
+msgstr ""
msgid "No child epics match applied filters"
msgstr ""
@@ -16711,6 +17316,9 @@ msgstr "¡No ha sido posible realizar la conexión con un servidor de Gitaly, po
msgid "No containers available"
msgstr "No hay contenedores disponibles"
+msgid "No content to show"
+msgstr ""
+
msgid "No contributions"
msgstr "Sin contribuciones"
@@ -16786,9 +17394,6 @@ msgstr "No hay etiquetas con ese nombre o descripción"
msgid "No license. All rights reserved"
msgstr "Sin licencia. Todos los derechos reservados"
-msgid "No licenses found."
-msgstr "No se encontraron licencias."
-
msgid "No matches found"
msgstr "No hay coincidencias"
@@ -16801,6 +17406,9 @@ msgstr "No se han encontrado resultados"
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No members found"
+msgstr ""
+
msgid "No merge requests found"
msgstr "No se han encontrado merge requests"
@@ -16822,6 +17430,9 @@ msgstr ""
msgid "No parent group"
msgstr "Ningún grupo padre"
+msgid "No plan"
+msgstr ""
+
msgid "No pods available"
msgstr "No hay pods disponibles"
@@ -16918,6 +17529,12 @@ msgstr "Ninguno"
msgid "Not Implemented"
msgstr "¡No se ha implementado!"
+msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+msgstr ""
+
+msgid "Not all browsers support WebAuthn. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even from an unsupported browser."
+msgstr ""
+
msgid "Not all data has been processed yet, the accuracy of the chart for the selected timeframe is limited."
msgstr "Todavía no se han procesado todos los datos, la precisión del gráfico para el período de tiempo seleccionado es limitada."
@@ -17014,6 +17631,9 @@ msgstr "Configuración de las notificaciones - %{notification_title}"
msgid "Notification settings saved"
msgstr "Configuración de las notificaciones guardada"
+msgid "NotificationEvent|Change reviewer merge request"
+msgstr ""
+
msgid "NotificationEvent|Close issue"
msgstr "Cerrar incidencia"
@@ -17176,10 +17796,7 @@ msgstr ""
msgid "On track"
msgstr ""
-msgid "OnDemandScans|Attached branch"
-msgstr ""
-
-msgid "OnDemandScans|Attached branch is where the scan job runs."
+msgid "OnDemandScans|Could not fetch scanner profiles. Please refresh the page, or try again later."
msgstr ""
msgid "OnDemandScans|Could not fetch site profiles. Please refresh the page, or try again later."
@@ -17188,6 +17805,9 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
+msgid "OnDemandScans|Create a new scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Create a new site profile"
msgstr ""
@@ -17200,6 +17820,9 @@ msgstr ""
msgid "OnDemandScans|New on-demand DAST scan"
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 ""
@@ -17209,16 +17832,10 @@ msgstr "Escaneos bajo demanda"
msgid "OnDemandScans|On-demand scans run outside the DevOps cycle and find vulnerabilities in your projects. %{learnMoreLinkStart}Learn more%{learnMoreLinkEnd}"
msgstr ""
-msgid "OnDemandScans|Only a passive scan can be performed on demand."
-msgstr ""
-
-msgid "OnDemandScans|Passive"
-msgstr ""
-
msgid "OnDemandScans|Run scan"
msgstr ""
-msgid "OnDemandScans|Scan mode"
+msgid "OnDemandScans|Scanner profile"
msgstr ""
msgid "OnDemandScans|Scanner settings"
@@ -17230,9 +17847,15 @@ msgstr ""
msgid "OnDemandScans|Select one of the existing profiles"
msgstr ""
+msgid "OnDemandScans|Site profile"
+msgstr ""
+
msgid "OnDemandScans|Site profiles"
msgstr ""
+msgid "OnDemandScans|Use existing scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Use existing site profile"
msgstr ""
@@ -17331,9 +17954,6 @@ msgstr "Abrir"
msgid "Open Selection"
msgstr "Abrir la selección"
-msgid "Open Web IDE"
-msgstr ""
-
msgid "Open comment type dropdown"
msgstr ""
@@ -17439,6 +18059,9 @@ msgstr "O puede seleccionar alguno de los colores sugeridos a continuación"
msgid "Origin"
msgstr "Origin"
+msgid "Orphaned member"
+msgstr ""
+
msgid "Other Labels"
msgstr "Otras etiquetas"
@@ -17454,6 +18077,9 @@ msgstr ""
msgid "Other visibility settings have been disabled by the administrator."
msgstr "Otros ajustes de visibilidad han sido desactivados por el administrador."
+msgid "Our documentation includes an example DevOps Score report."
+msgstr ""
+
msgid "Out-of-compliance with this project's policies and should be removed"
msgstr ""
@@ -17478,6 +18104,9 @@ msgstr "Resumen"
msgid "Overwrite diverged branches"
msgstr "Sobreescribir ramas divergentes"
+msgid "Owned by %{image_tag}"
+msgstr ""
+
msgid "Owned by anyone"
msgstr "Propiedad de cualquier persona"
@@ -17499,6 +18128,9 @@ msgstr "El paquete ya existe"
msgid "Package deleted successfully"
msgstr "Paquete eliminado correctamente"
+msgid "Package file size limits"
+msgstr ""
+
msgid "Package recipe already exists"
msgstr "La receta del paquete ya existe"
@@ -17514,9 +18146,6 @@ msgstr "El tipo de paquete debe ser NuGet"
msgid "Package type must be PyPi"
msgstr "El tipo de paquete debe ser PyPi"
-msgid "Package was removed"
-msgstr "El paquete ha sido eliminado"
-
msgid "PackageRegistry|%{name} version %{version} was created %{datetime}"
msgstr ""
@@ -17658,12 +18287,18 @@ msgstr "NuGet"
msgid "PackageRegistry|NuGet Command"
msgstr "Comando NuGet"
+msgid "PackageRegistry|Package Registry"
+msgstr ""
+
msgid "PackageRegistry|Pip Command"
msgstr "Comando Pip"
msgid "PackageRegistry|Pipeline %{link} triggered %{datetime} by %{author}"
msgstr ""
+msgid "PackageRegistry|Publish and share packages for a variety of common package managers. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "PackageRegistry|Published to the %{project} Package Registry %{datetime}"
msgstr ""
@@ -17763,6 +18398,9 @@ msgstr "Paquetes y registros"
msgid "Page not found"
msgstr "Página no encontrada"
+msgid "Page settings"
+msgstr ""
+
msgid "Page was successfully deleted"
msgstr "Página eliminada correctamente"
@@ -17904,8 +18542,8 @@ msgstr "Pegar el enlace de la tarea épica"
msgid "Paste issue link"
msgstr "Pegar el enlace de la incidencia"
-msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Don't use your private SSH key."
-msgstr "Pegue su clave pública SSH, que generalmente está contenida en el archivo ~/.ssh/id_ed25519.pub o en el archivo '~/ .ssh/id_rsa.pub' y comienza con 'ssh-rsa'. No utilice su clave SSH privada."
+msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Do not paste your private SSH key, as that can compromise your identity."
+msgstr ""
msgid "Patch to apply"
msgstr "Parche a aplicar"
@@ -17931,6 +18569,9 @@ msgstr "Los runers pausados no aceptan nuevos trabajos"
msgid "Pending"
msgstr "Pendiente"
+msgid "Pending comments"
+msgstr ""
+
msgid "People without permission will never get a notification and won't be able to comment."
msgstr "Las personas no autorizadas nunca recibirán una notificación y no podrán comentar."
@@ -18129,6 +18770,9 @@ msgstr ""
msgid "Pipelines|Build with confidence"
msgstr "Construir con confianza"
+msgid "Pipelines|By revoking a trigger you will break any processes making use of it. Are you sure?"
+msgstr ""
+
msgid "Pipelines|CI Lint"
msgstr "CI Lint"
@@ -18141,6 +18785,15 @@ msgstr "Limpiar la caché de los runners"
msgid "Pipelines|Continuous Integration can help catch bugs by running your tests automatically, while Continuous Deployment can help you deliver code to your product environment."
msgstr "La integración continua le puede ayudar a capturar errores en su producto mediante la ejecución de pruebas automáticas, mientras que el despliegue continuo le puede ayudar a llevar el código al entorno de su producto."
+msgid "Pipelines|Copy trigger token"
+msgstr ""
+
+msgid "Pipelines|Description"
+msgstr ""
+
+msgid "Pipelines|Edit"
+msgstr ""
+
msgid "Pipelines|Get started with Pipelines"
msgstr "Comenzar a utilizar los pipelines"
@@ -18156,15 +18809,27 @@ msgstr ""
msgid "Pipelines|It is recommended the code is reviewed thoroughly before running this pipeline with the parent project's CI resource."
msgstr ""
+msgid "Pipelines|Last Used"
+msgstr ""
+
msgid "Pipelines|Loading Pipelines"
msgstr "Cargar pipelines"
msgid "Pipelines|More Information"
msgstr ""
+msgid "Pipelines|No triggers have been created yet. Add one using the form above."
+msgstr ""
+
+msgid "Pipelines|Owner"
+msgstr ""
+
msgid "Pipelines|Project cache successfully reset."
msgstr "Caché del proyecto restablecida correctamente."
+msgid "Pipelines|Revoke"
+msgstr ""
+
msgid "Pipelines|Run Pipeline"
msgstr "Ejecutar Pipeline"
@@ -18189,6 +18854,15 @@ msgstr ""
msgid "Pipelines|This project is not currently set up to run pipelines."
msgstr "Este proyecto no está configurado para ejecutar pipelines."
+msgid "Pipelines|Token"
+msgstr ""
+
+msgid "Pipelines|Trigger user has insufficient permissions to project"
+msgstr ""
+
+msgid "Pipelines|invalid"
+msgstr ""
+
msgid "Pipelines|parent"
msgstr "padre"
@@ -18447,11 +19121,11 @@ msgstr "Por favor proporcione una dirección de correo electrónico válida."
msgid "Please provide attributes to update"
msgstr ""
-msgid "Please refer to %{docs_url}"
+msgid "Please reach out if you have any questions and we'll be happy to assist."
msgstr ""
-msgid "Please retype the email address."
-msgstr "Por favor, vuelva a introducir la dirección de correo electrónico."
+msgid "Please refer to %{docs_url}"
+msgstr ""
msgid "Please select"
msgstr "Por favor, seleccione"
@@ -18480,6 +19154,9 @@ msgstr "Por favor seleccione por lo menos un filtro para ver los resultados"
msgid "Please set a new password before proceeding."
msgstr "Por favor, establezca una nueva contraseña antes de continuar."
+msgid "Please share your feedback about %{featureName} %{linkStart}in this issue%{linkEnd} to help us improve the experience."
+msgstr ""
+
msgid "Please solve the reCAPTCHA"
msgstr "Por favor resuelva el reCAPTCHA"
@@ -18783,6 +19460,9 @@ msgstr "Está a punto de eliminar permanentemente %{yourAccount}, y todas las in
msgid "Profiles| You are going to change the username %{currentUsernameBold} to %{newUsernameBold}. Profile and projects will be redirected to the %{newUsername} namespace but this redirect will expire once the %{currentUsername} namespace is registered by another user or group. Please update your Git repository remotes as soon as possible."
msgstr "Está a punto de renombrar el usuario %{currentUsernameBold} a %{newUsernameBold}. El perfil del usuario y los proyectos serán redirigidos al espacio de nombres %{newUsername} pero este redireccionamiento caducará una vez que otro usuario o grupo registre el %{currentUsername}. Por favor, actualice los remotos de su repositorio Git tan pronto como sea posible."
+msgid "Profiles|%{provider} Active"
+msgstr ""
+
msgid "Profiles|@username"
msgstr "@nombredeusuario"
@@ -18834,8 +19514,8 @@ msgstr "Haga clic en el icono para activar el inicio de sesión con uno de los s
msgid "Profiles|Commit email"
msgstr "Dirección de correo electrónico para los commits"
-msgid "Profiles|Connect"
-msgstr "Conectar"
+msgid "Profiles|Connect %{provider}"
+msgstr ""
msgid "Profiles|Connected Accounts"
msgstr "Cuentas conectadas"
@@ -18858,6 +19538,9 @@ msgstr "La eliminación de su cuenta tiene los siguientes efectos:"
msgid "Profiles|Disconnect"
msgstr "Desconectar"
+msgid "Profiles|Disconnect %{provider}"
+msgstr ""
+
msgid "Profiles|Do not show on profile"
msgstr "No mostrar en el perfil"
@@ -18882,7 +19565,7 @@ msgstr ""
msgid "Profiles|Full name"
msgstr "Nombre completo"
-msgid "Profiles|Give your individual key a title. This will be publically visible."
+msgid "Profiles|Give your individual key a title."
msgstr ""
msgid "Profiles|Include private contributions on my profile"
@@ -18972,8 +19655,8 @@ msgstr ""
msgid "Profiles|The maximum file size allowed is 200KB."
msgstr "El tamaño máximo de archivo permitido es 200KB."
-msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it?"
-msgstr "No se parece a una clave SSH pública, ¿está seguro de que desea agregarla?"
+msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it? It will be publicly visible."
+msgstr ""
msgid "Profiles|This email will be displayed on your public profile"
msgstr "Esta dirección de correo electrónico se mostrará en su perfil público"
@@ -19047,6 +19730,9 @@ msgstr "Puede subir directamente su avatar aquí o modificarlo en %{gravatar_lin
msgid "Profiles|You don't have access to delete this user."
msgstr "No tienes acceso para eliminar este usuario."
+msgid "Profiles|You must transfer ownership or delete groups you are an owner of before you can delete your account"
+msgstr ""
+
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr "Debes transferir o eliminar estos grupos antes de que puedas eliminar tu cuenta."
@@ -19635,6 +20321,9 @@ msgstr "Android"
msgid "ProjectTemplates|GitLab Cluster Management"
msgstr ""
+msgid "ProjectTemplates|Gitpod/Spring Petclinic"
+msgstr ""
+
msgid "ProjectTemplates|Go Micro"
msgstr "Go Micro"
@@ -20244,6 +20933,9 @@ msgstr ""
msgid "Publish to status page"
msgstr ""
+msgid "Published"
+msgstr ""
+
msgid "Published on status page"
msgstr ""
@@ -20361,9 +21053,15 @@ msgstr "Se pueden utilizar acciones rápidas en la descripción de las incidenci
msgid "Quick range"
msgstr "Rango rápido"
+msgid "Quickly and easily edit multiple files in your project."
+msgstr ""
+
msgid "README"
msgstr "README"
+msgid "Rails"
+msgstr ""
+
msgid "Rake Tasks Help"
msgstr ""
@@ -20483,12 +21181,15 @@ msgstr "Registrarse / Iniciar sesión"
msgid "Register Two-Factor Authenticator"
msgstr "Registrar un dispositivo de autenticación de dos factores"
-msgid "Register U2F device"
-msgstr "Registrar dispositivo U2F"
-
msgid "Register Universal Two-Factor (U2F) Device"
msgstr "Registrar un dispositivo universal de autenticación de dos factores (U2F)"
+msgid "Register WebAuthn Device"
+msgstr ""
+
+msgid "Register device"
+msgstr ""
+
msgid "Register for GitLab"
msgstr "Regístrese en GitLab"
@@ -20498,9 +21199,6 @@ msgstr "Registrarse ahora"
msgid "Register with two-factor app"
msgstr "Registrarse con la aplicación de dos factores"
-msgid "Registration"
-msgstr "Registro"
-
msgid "Registration|Checkout"
msgstr ""
@@ -20617,9 +21315,6 @@ msgstr "Se ha producido un error al obtener los detalles de la versión"
msgid "Release|Something went wrong while saving the release details"
msgstr "Se ha producido un error al guardar los detalles de la versión"
-msgid "Remediated: needs review"
-msgstr "Solucionado: necesita revisión"
-
msgid "Remediations"
msgstr "Remediaciones"
@@ -20725,6 +21420,9 @@ msgstr "Eliminar nodo principal"
msgid "Remove priority"
msgstr "Eliminar prioridad"
+msgid "Remove report"
+msgstr ""
+
msgid "Remove secondary node"
msgstr "Eliminar nodo secundario"
@@ -20737,6 +21435,12 @@ msgstr "Eliminar la etapa"
msgid "Remove time estimate"
msgstr "Eliminar el tiempo estimado"
+msgid "Remove user & report"
+msgstr ""
+
+msgid "Remove user from group"
+msgstr ""
+
msgid "Removed"
msgstr "Eliminado"
@@ -20818,9 +21522,6 @@ msgstr "Elimina la fecha de vencimiento."
msgid "Removes time estimate."
msgstr "Elimina el tiempo estimado."
-msgid "Removing license…"
-msgstr "Eliminando la licencia…"
-
msgid "Removing this group also removes all child projects, including archived projects, and their resources."
msgstr ""
@@ -20905,6 +21606,9 @@ msgstr "Informar de un abuso al administrador"
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr "Denunciado %{timeAgo} por %{reportedBy}"
+msgid "Reported by %{reporter}"
+msgstr ""
+
msgid "Reporting"
msgstr "Informes"
@@ -20991,6 +21695,27 @@ msgstr "no hay cambios en los resultados de las pruebas"
msgid "Repositories"
msgstr ""
+msgid "Repositories Analytics"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download Historic Test Coverage Data"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download historic test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Historic Test Coverage Data is available in raw format (.csv) for further analysis."
+msgstr ""
+
+msgid "RepositoriesAnalytics|Test Code Coverage"
+msgstr ""
+
+msgid "RepositoriesAnalytics|There was an error fetching the projects."
+msgstr ""
+
msgid "Repository"
msgstr "Repositorio"
@@ -21069,9 +21794,15 @@ msgstr ""
msgid "Request parameter %{param} is missing."
msgstr ""
+msgid "Request review from"
+msgstr ""
+
msgid "Request to link SAML account must be authorized"
msgstr "La solicitud para vincular la cuenta SAML debe ser autorizada"
+msgid "Requested"
+msgstr ""
+
msgid "Requested %{time_ago}"
msgstr "Solicitado %{time_ago}"
@@ -21090,6 +21821,9 @@ msgstr ""
msgid "Requests to these domain(s)/address(es) on the local network will be allowed when local requests from hooks and services are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 or 127.0.0.0/28 are supported. Domain wildcards are not supported currently. Use comma, semicolon, or newline to separate multiple entries. The allowlist can hold a maximum of 1000 entries. Domains should use IDNA encoding. Ex: example.com, 192.168.1.1, 127.0.0.0/28, xn--itlab-j1a.com."
msgstr ""
+msgid "Require admin approval for new sign-ups"
+msgstr ""
+
msgid "Require all users in this group to setup Two-factor authentication"
msgstr "Requerir que todos los usuarios en este grupo configuren la autenticación de dos factores"
@@ -21217,9 +21951,6 @@ msgstr "Resuelto por"
msgid "Resolved by %{name}"
msgstr "Resuelto por %{name}"
-msgid "Resolved by %{resolvedByName}"
-msgstr "Resuelto por %{resolvedByName}"
-
msgid "Resolves IP addresses once and uses them to submit requests"
msgstr "Resuelve las direcciones IP una vez y las utiliza para enviar peticiones"
@@ -21339,6 +22070,14 @@ msgstr ""
msgid "ReviewApp|Enable Review App"
msgstr ""
+msgid "Reviewer"
+msgid_plural "%d Reviewers"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Reviewer(s)"
+msgstr ""
+
msgid "Reviewing"
msgstr "Revisando"
@@ -21378,6 +22117,9 @@ msgstr "Restaurar"
msgid "Rook"
msgstr ""
+msgid "Ruby"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -21456,6 +22198,63 @@ msgstr "Ejecutores actualmente en línea: %{active_runners_count}"
msgid "Runners page."
msgstr "Página de ejecutores."
+msgid "Runners|Active"
+msgstr ""
+
+msgid "Runners|Architecture"
+msgstr ""
+
+msgid "Runners|Can run untagged jobs"
+msgstr ""
+
+msgid "Runners|Description"
+msgstr ""
+
+msgid "Runners|Group"
+msgstr ""
+
+msgid "Runners|IP Address"
+msgstr ""
+
+msgid "Runners|Last contact"
+msgstr ""
+
+msgid "Runners|Locked to this project"
+msgstr ""
+
+msgid "Runners|Maximum job timeout"
+msgstr ""
+
+msgid "Runners|Name"
+msgstr ""
+
+msgid "Runners|Platform"
+msgstr ""
+
+msgid "Runners|Property Name"
+msgstr ""
+
+msgid "Runners|Protected"
+msgstr ""
+
+msgid "Runners|Revision"
+msgstr ""
+
+msgid "Runners|Shared"
+msgstr ""
+
+msgid "Runners|Specific"
+msgstr ""
+
+msgid "Runners|Tags"
+msgstr ""
+
+msgid "Runners|Value"
+msgstr ""
+
+msgid "Runners|Version"
+msgstr ""
+
msgid "Runners|You have used %{quotaUsed} out of %{quotaLimit} of your shared Runners pipeline minutes."
msgstr ""
@@ -21468,6 +22267,9 @@ msgstr "Ejecutando…"
msgid "Runs a number of housekeeping tasks within the current repository, such as compressing file revisions and removing unreachable objects."
msgstr "Ejecuta una serie de tareas de mantenimiento dentro del repositorio actual, como comprimir las revisiones de los archivos y eliminar objetos no disponibles."
+msgid "SAML"
+msgstr ""
+
msgid "SAML SSO"
msgstr "SAML SSO"
@@ -21519,6 +22321,9 @@ msgstr "Sábado"
msgid "Save"
msgstr "Guardar"
+msgid "Save %{name} size limits"
+msgstr ""
+
msgid "Save Changes"
msgstr "Guardar cambios"
@@ -21549,9 +22354,6 @@ msgstr "Guardar programación del pipeline"
msgid "Save space and find tags in the Container Registry more easily. Enable the cleanup policy to remove stale tags and keep only the ones you need."
msgstr ""
-msgid "Save template"
-msgstr "Guardar plantilla"
-
msgid "Save variables"
msgstr "Guardar variables"
@@ -21594,9 +22396,6 @@ msgstr "Programación de Pipelines"
msgid "Scope"
msgstr "Alcance"
-msgid "Scope not supported with disabled 'users_search' feature!"
-msgstr "¡El alcance no es compatible con la función 'users_search' deshabilitada!"
-
msgid "Scoped issue boards"
msgstr "Tableros de incidencias con alcance limitado"
@@ -21723,9 +22522,6 @@ msgstr "Buscar proyectos..."
msgid "Search requirements"
msgstr "Requisitos de búsqueda"
-msgid "Search results…"
-msgstr ""
-
msgid "Search users"
msgstr "Buscar usuarios"
@@ -21798,6 +22594,11 @@ msgid_plural "SearchResults|commits"
msgstr[0] "commit"
msgstr[1] "commits"
+msgid "SearchResults|epic"
+msgid_plural "SearchResults|epics"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "SearchResults|issue"
msgid_plural "SearchResults|issues"
msgstr[0] "incidencia"
@@ -21842,11 +22643,11 @@ msgstr ""
msgid "Seat Link is disabled, and cannot be configured through this form."
msgstr ""
-msgid "Seats currently in use"
-msgstr "Puestos actualmente en uso"
+msgid "Seats usage data as of %{last_enqueue_time}"
+msgstr ""
-msgid "Seats in license"
-msgstr "Puestos en la licencia"
+msgid "Seats usage data is updated every day at 12:00pm UTC"
+msgstr ""
msgid "Secondary"
msgstr "Secundario"
@@ -21899,6 +22700,9 @@ msgstr ""
msgid "SecurityConfiguration|Available for on-demand DAST"
msgstr ""
+msgid "SecurityConfiguration|By default, all analyzers are applied in order to cover all languages across your project, and only run if the language is detected in the Merge Request."
+msgstr ""
+
msgid "SecurityConfiguration|Configure"
msgstr ""
@@ -21929,18 +22733,21 @@ msgstr "Documentación de características para %{featureName}"
msgid "SecurityConfiguration|Manage"
msgstr ""
+msgid "SecurityConfiguration|More information"
+msgstr ""
+
msgid "SecurityConfiguration|Not enabled"
msgstr ""
+msgid "SecurityConfiguration|SAST Analyzers"
+msgstr ""
+
msgid "SecurityConfiguration|SAST Configuration"
msgstr ""
msgid "SecurityConfiguration|Security Control"
msgstr "Control de seguridad"
-msgid "SecurityConfiguration|See documentation"
-msgstr ""
-
msgid "SecurityConfiguration|Status"
msgstr "Estado"
@@ -21950,6 +22757,9 @@ msgstr "Pruebas y cumplimiento"
msgid "SecurityConfiguration|Using custom settings. You won't receive automatic updates on this variable. %{anchorStart}Restore to default%{anchorEnd}"
msgstr ""
+msgid "SecurityConfiguration|View history"
+msgstr ""
+
msgid "SecurityConfiguration|You can quickly enable all security scanning tools by enabling %{linkStart}Auto DevOps%{linkEnd}."
msgstr ""
@@ -22028,9 +22838,6 @@ msgstr ""
msgid "SecurityReports|Learn more about setting up your dashboard"
msgstr ""
-msgid "SecurityReports|Load more vulnerabilities"
-msgstr "Cargar más vulnerabilidades"
-
msgid "SecurityReports|Monitor vulnerabilities in your code"
msgstr "Monitorizar vulnerabilidades en su código"
@@ -22310,7 +23117,7 @@ msgstr ""
msgid "Select status"
msgstr "Seleccionar estado"
-msgid "Select strategy activation method"
+msgid "Select strategy activation method."
msgstr ""
msgid "Select subscription"
@@ -22325,8 +23132,8 @@ msgstr "Seleccione la rama que desea establecer como predeterminada para este pr
msgid "Select the custom project template source group."
msgstr "Seleccione el grupo de origen de plantilla de proyecto personalizado."
-msgid "Select timeframe"
-msgstr "Seleccione el período de tiempo"
+msgid "Select the environment scope for this feature flag."
+msgstr ""
msgid "Select timezone"
msgstr ""
@@ -22574,6 +23381,9 @@ msgstr ""
msgid "Set iteration"
msgstr "Establecer iteración"
+msgid "Set limit to 0 to allow any file size."
+msgstr ""
+
msgid "Set max session time for web terminal."
msgstr "Establecer el tiempo máximo de sesión para el terminal de web."
@@ -22652,11 +23462,14 @@ msgstr "Configurar un %{type} ejecutor automáticamente"
msgid "Set up a %{type} Runner manually"
msgstr "Configurar un %{type} ejecutor manualmente"
+msgid "Set up a hardware device as a second factor to sign in."
+msgstr ""
+
msgid "Set up assertions/attributes/claims (email, first_name, last_name) and NameID according to %{docsLinkStart}the documentation %{icon}%{docsLinkEnd}"
msgstr "Configure las afirmaciones/atributos/reclamaciones (correo electrónico, first_name, last_name) y el NameID según %{docsLinkStart}la documentación %{icon}%{docsLinkEnd}"
-msgid "Set up new U2F device"
-msgstr "Configurar nuevo dispositivo U2F"
+msgid "Set up new device"
+msgstr ""
msgid "Set up new password"
msgstr "Establecer una nueva contraseña"
@@ -22724,6 +23537,9 @@ msgstr "Establece el tiempo estimado a %{time_estimate}."
msgid "Sets weight to %{weight}."
msgstr "Establecer el peso a %{weight}."
+msgid "Setting this to 0 means using the system default timeout value."
+msgstr ""
+
msgid "Settings"
msgstr "Configuración"
@@ -22739,6 +23555,15 @@ msgstr ""
msgid "Severity"
msgstr ""
+msgid "SeverityWidget|Severity"
+msgstr ""
+
+msgid "SeverityWidget|Severity: %{severity}"
+msgstr ""
+
+msgid "SeverityWidget|There was an error while updating severity."
+msgstr ""
+
msgid "Shards (%{shards})"
msgstr ""
@@ -22784,6 +23609,9 @@ msgstr "Mostrar todos los miembros"
msgid "Show all requirements."
msgstr ""
+msgid "Show all test cases."
+msgstr ""
+
msgid "Show archived projects"
msgstr "Mostrar proyectos archivados"
@@ -22796,6 +23624,9 @@ msgstr "Mostrar comando"
msgid "Show comments"
msgstr "Mostrar los comentarios"
+msgid "Show comments on this file"
+msgstr ""
+
msgid "Show comments only"
msgstr "Mostrar solo los comentarios"
@@ -22841,6 +23672,12 @@ msgstr "Mostrar páginas padre"
msgid "Show parent subgroups"
msgstr "Mostrar subgrupos padre"
+msgid "Show the Closed list"
+msgstr ""
+
+msgid "Show the Open list"
+msgstr ""
+
msgid "Show whitespace changes"
msgstr "Mostrar los espacios en blanco de los cambios"
@@ -22884,9 +23721,6 @@ msgstr "En paralelo"
msgid "Sidebar|Assign health status"
msgstr "Asignar estado de salud"
-msgid "Sidebar|Change weight"
-msgstr "Cambiar peso"
-
msgid "Sidebar|Health status"
msgstr "Estado de salud"
@@ -23070,6 +23904,9 @@ msgstr "No hay fragmentos de código que mostrar."
msgid "Snippets|Add another file %{num}/%{total}"
msgstr ""
+msgid "Snippets|Authored %{time_ago} by %{author}"
+msgstr ""
+
msgid "Snippets|Delete file"
msgstr ""
@@ -23097,6 +23934,9 @@ msgstr "Snowplow"
msgid "Solution"
msgstr "Solución"
+msgid "Some changes are not shown"
+msgstr ""
+
msgid "Some child epics may be hidden due to applied filters"
msgstr ""
@@ -23463,6 +24303,12 @@ msgstr "Fuente"
msgid "Source (branch or tag)"
msgstr "Origen (rama o tag)"
+msgid "Source Branch"
+msgstr ""
+
+msgid "Source branch: %{source_branch_open}%{source_branch}%{source_branch_close}"
+msgstr ""
+
msgid "Source code"
msgstr "Código fuente"
@@ -23628,9 +24474,6 @@ msgstr "Comenzar una revisión"
msgid "Start and due date"
msgstr "Fechas de inicio y de fin"
-msgid "Start by choosing a group to see how your team is spending time. You can then drill down to the project level."
-msgstr "Comience eligiendo un grupo para ver cómo su equipo gasta el tiempo. Posteriormente podrá profundizar hasta llegar al nivel del proyecto."
-
msgid "Start by choosing a group to start exploring the merge requests in that group. You can then proceed to filter by projects, labels, milestones and authors."
msgstr "Comience eligiendo un grupo para explorar los merge requests en ese grupo. Posteriormente puede proceder a filtrar por proyectos, etiquetas, hitos, autores y asignados."
@@ -23712,18 +24555,27 @@ msgstr ""
msgid "StaticSiteEditor|3. Assign a person to review and accept the merge request."
msgstr ""
+msgid "StaticSiteEditor|A link to view the merge request will appear once ready."
+msgstr ""
+
msgid "StaticSiteEditor|An error occurred while submitting your changes."
msgstr ""
msgid "StaticSiteEditor|Branch could not be created."
msgstr ""
+msgid "StaticSiteEditor|Copy update"
+msgstr ""
+
msgid "StaticSiteEditor|Could not commit the content changes."
msgstr ""
msgid "StaticSiteEditor|Could not create merge request."
msgstr ""
+msgid "StaticSiteEditor|Creating your merge request"
+msgstr ""
+
msgid "StaticSiteEditor|Incompatible file content"
msgstr ""
@@ -23745,6 +24597,9 @@ msgstr ""
msgid "StaticSiteEditor|View documentation"
msgstr "Ver la documentación"
+msgid "StaticSiteEditor|You can set an assignee to get your changes reviewed and deployed once your merge request is created."
+msgstr ""
+
msgid "StaticSiteEditor|Your merge request has been created"
msgstr ""
@@ -23874,15 +24729,15 @@ msgstr ""
msgid "Submit %{humanized_resource_name}"
msgstr "Enviar %{humanized_resource_name}"
-msgid "Submit Changes"
-msgstr "Enviar los cambios"
-
msgid "Submit a review"
msgstr "Enviar una revisión"
msgid "Submit as spam"
msgstr "Enviar como correo no deseado"
+msgid "Submit changes"
+msgstr ""
+
msgid "Submit feedback"
msgstr "Enviar comentarios"
@@ -24036,6 +24891,9 @@ msgstr "Desactivado correctamente"
msgid "Successfully deleted U2F device."
msgstr "Dispositivo U2F eliminado con éxito."
+msgid "Successfully deleted WebAuthn device."
+msgstr ""
+
msgid "Successfully removed email."
msgstr "Correo electrónico eliminado con éxito."
@@ -24354,9 +25212,6 @@ msgstr "Plantilla"
msgid "Template to append to all Service Desk issues"
msgstr ""
-msgid "Template was successfully saved."
-msgstr "La plantilla se guardó correctamente."
-
msgid "Templates"
msgstr "Plantillas"
@@ -24435,11 +25290,29 @@ msgid_plural "Test coverage: %d hits"
msgstr[0] "Cobertura de la prueba: %d"
msgstr[1] "Cobertura de la prueba: %d"
-msgid "Test failed."
-msgstr "Prueba fallida."
+msgid "Test settings"
+msgstr ""
+
+msgid "TestCases|New Test Case"
+msgstr ""
+
+msgid "TestCases|New test case"
+msgstr ""
+
+msgid "TestCases|Search test cases"
+msgstr ""
+
+msgid "TestCases|Something went wrong while creating a test case."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching count of test cases."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching test cases list."
+msgstr ""
-msgid "Test settings and save changes"
-msgstr "Probar los ajustes y los guardar cambios"
+msgid "TestCases|Submit test case"
+msgstr ""
msgid "TestHooks|Ensure one of your projects has merge requests."
msgstr "Asegúrese de que uno de sus proyectos tenga merge requests."
@@ -24504,6 +25377,9 @@ msgstr "Pruebas"
msgid "Thank you for signing up for your free trial! You will get additional instructions in your inbox shortly."
msgstr "¡Gracias por registrarse en la versión de prueba! En breve recibirá instrucciones adicionales en su bandeja de entrada."
+msgid "Thank you for your business."
+msgstr ""
+
msgid "Thank you for your feedback!"
msgstr "¡Gracias por sus comentarios!"
@@ -24563,9 +25439,6 @@ msgstr ""
msgid "The URL to use for connecting to Elasticsearch. Use a comma-separated list to support clustering (e.g., \"http://localhost:9200, http://localhost:9201\")."
msgstr "La URL a utilizar para conectarse a Elasticsearch. Utilice una lista separada por comas para soportar clustering (por ejemplo, \"http://localhost:9200, http://localhost:9201\")."
-msgid "The Web IDE offers advanced syntax highlighting capabilities and more."
-msgstr ""
-
msgid "The X509 Certificate to use when mutual TLS is required to communicate with the external authorization service. If left blank, the server certificate is still validated when accessing over HTTPS."
msgstr "Un certificado X.509 se utiliza cuando se require una comunicación TLS con un servicio de autorización externo. Si se deja en blanco, el certificado utilizado desde el servidor es validado cuando se accedes a través del protocolo HTTPS."
@@ -24676,6 +25549,9 @@ msgstr "La relación con la bifurcación se ha eliminado."
msgid "The form contains the following error:"
msgstr ""
+msgid "The form contains the following warning:"
+msgstr ""
+
msgid "The global settings require you to enable Two-Factor Authentication for your account."
msgstr "La configuración global requiere que habilite la autenticación de dos factores para su cuenta."
@@ -24790,9 +25666,6 @@ msgstr "La etapa de planificación muestra el tiempo desde el paso anterior hast
msgid "The private key to use when a client certificate is provided. This value is encrypted at rest."
msgstr "La clave privada que se utiliza cuando se proporciona un certificado cliente. Este valor está encriptado."
-msgid "The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr "La etapa de producción muestra el tiempo total que tarda entre la creación de una incidencia y el despliegue del código a producción. Los datos se añadirán automáticamente una vez haya finalizado por completo el ciclo de idea a producción."
-
msgid "The project can be accessed by any logged in user."
msgstr "El proyecto puede ser accedido por cualquier usuario conectado."
@@ -24829,7 +25702,7 @@ msgstr "La replica ha tardado demasiado tiempo en completarse."
msgid "The remote repository is being updated..."
msgstr "Se está actualizando el repositorio remoto..."
-msgid "The repository can be commited to, and issues, comments and other entities can be created."
+msgid "The repository can be committed to, and issues, comments and other entities can be created."
msgstr ""
msgid "The repository for this project does not exist."
@@ -24883,9 +25756,6 @@ msgstr "La etapa de pruebas muestra el tiempo que GitLab CI toma para ejecutar c
msgid "The time taken by each data entry gathered by that stage."
msgstr "El tiempo utilizado por cada entrada de datos obtenido por esa etapa."
-msgid "The total stage shows the time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The update action will time out after %{number_of_minutes} minutes. For big repositories, use a clone/push combination."
msgstr "El proceso de actualización finalizará después de %{number_of_minutes} minutos. Para repositorios grandes, utilice una combinación de clone y push."
@@ -24949,6 +25819,9 @@ msgstr "Aún no hay proyectos archivados"
msgid "There are no archived requirements"
msgstr ""
+msgid "There are no archived test cases"
+msgstr ""
+
msgid "There are no changes"
msgstr "No hay cambios"
@@ -24988,6 +25861,9 @@ msgstr "No hay merge requests abiertos"
msgid "There are no open requirements"
msgstr "No hay requisitos abiertos"
+msgid "There are no open test cases"
+msgstr ""
+
msgid "There are no packages yet"
msgstr "Todavía no hay paquetes"
@@ -25000,6 +25876,9 @@ msgstr "Todavía no hay variables."
msgid "There is a limit of %{ci_project_subscriptions_limit} subscriptions from or to a project."
msgstr ""
+msgid "There is already a To-Do for this design."
+msgstr ""
+
msgid "There is already a repository with that name on disk"
msgstr "Ya hay un repositorio con ese nombre en el disco"
@@ -25018,6 +25897,9 @@ msgstr ""
msgid "There was a problem communicating with your device."
msgstr "Se ha producido un problema al conectarse con su dispositivo."
+msgid "There was a problem fetching branches."
+msgstr ""
+
msgid "There was a problem fetching groups."
msgstr ""
@@ -25246,9 +26128,15 @@ msgstr ""
msgid "This action can lead to data loss. To prevent accidental actions we ask you to confirm your intention."
msgstr "Esta acción puede provocar la pérdida de datos. Para prevenir acciones accidentales, le pedimos que confirme su intención."
+msgid "This action cannot be undone, and will permanently delete the %{key} SSH key"
+msgstr ""
+
msgid "This action cannot be undone. You will lose the project's repository and all content: issues, merge requests, etc."
msgstr ""
+msgid "This action has been performed too many times. Try again later."
+msgstr ""
+
msgid "This action will %{strongOpen}permanently delete%{strongClose} %{codeOpen}%{project}%{codeClose} %{strongOpen}immediately%{strongClose}, including its repositories and all content: issues, merge requests, etc."
msgstr ""
@@ -25276,9 +26164,6 @@ msgstr "Este bloque es auto-referencial"
msgid "This board's scope is reduced"
msgstr "El alcance de este tablero es limitado"
-msgid "This branch has changed since you started editing. Would you like to create a new branch?"
-msgstr "Esta rama ha cambiado desde que se comenzó a editar. ¿Le gustaría crear una nueva rama?"
-
msgid "This chart could not be displayed"
msgstr "No se puede mostrar este gráfico"
@@ -25405,15 +26290,9 @@ msgstr "Esta es una lista de dispositivos desde los que ha iniciado sesión. Cie
msgid "This is a security log of important events involving your account."
msgstr "Este es un registro de seguridad de eventos importantes relacionados con su cuenta."
-msgid "This is the author's first Merge Request to this project."
-msgstr "Este es el primer Merge Request del autor a este proyecto."
-
msgid "This is the highest peak of users on your installation since the license started."
msgstr ""
-msgid "This is the maximum number of users that have existed at the same time since the license started. This is the minimum number of seats you will need to buy when you renew your license."
-msgstr "Este es el número máximo de usuarios que han existido al mismo tiempo desde que se habilitó la licencia. Este es el número mínimo de puestos que deberá comprar cuando renueve su licencia."
-
msgid "This is the number of currently active users on your installation, and this is the minimum number you need to purchase when you renew your license."
msgstr ""
@@ -25645,6 +26524,15 @@ msgstr "Este usuario no tiene ningún %{type} activo."
msgid "This user has no identities"
msgstr "El usuario no tiene ninguna identidad"
+msgid "This user has previously committed to the %{name} project."
+msgstr ""
+
+msgid "This user has the %{access} role in the %{name} project."
+msgstr ""
+
+msgid "This user is the author of this %{noteable}."
+msgstr ""
+
msgid "This user will be the author of all events in the activity feed that are the result of an update, like new branches being created or new commits being pushed to existing branches."
msgstr ""
@@ -25675,6 +26563,9 @@ msgstr ""
msgid "Threat Monitoring"
msgstr "Threat Monitoring"
+msgid "ThreatMonitoring|All Environments"
+msgstr ""
+
msgid "ThreatMonitoring|Anomalous Requests"
msgstr "Peticiones anómalas"
@@ -25702,9 +26593,6 @@ msgstr "No se han detectado entornos"
msgid "ThreatMonitoring|Operations Per Second"
msgstr "Operaciones por segundo"
-msgid "ThreatMonitoring|Overview"
-msgstr "Vista general"
-
msgid "ThreatMonitoring|Packet Activity"
msgstr "Actividad del paquete"
@@ -25723,6 +26611,9 @@ msgstr ""
msgid "ThreatMonitoring|Something went wrong, unable to fetch statistics"
msgstr ""
+msgid "ThreatMonitoring|Statistics"
+msgstr ""
+
msgid "ThreatMonitoring|The firewall is not installed or has been disabled. To view this data, ensure the web application firewall is installed and enabled for your cluster."
msgstr ""
@@ -26114,6 +27005,9 @@ msgstr ""
msgid "To update Snippets with multiple files, you must use the `files` parameter"
msgstr ""
+msgid "To use Gitpod you must first enable the feature in the integrations section of your %{user_prefs}."
+msgstr ""
+
msgid "To view all %{scannedResourcesCount} scanned URLs, please download the CSV file"
msgstr ""
@@ -26147,9 +27041,6 @@ msgstr ""
msgid "Toggle Sidebar"
msgstr "Ocultar barra lateral"
-msgid "Toggle all threads"
-msgstr ""
-
msgid "Toggle backtrace"
msgstr ""
@@ -26174,9 +27065,6 @@ msgstr ""
msgid "Toggle navigation"
msgstr "Alternar navegación"
-msgid "Toggle project"
-msgstr "Alternar proyecto"
-
msgid "Toggle sidebar"
msgstr "Ocultar/mostrar barra lateral"
@@ -26216,6 +27104,9 @@ msgstr "Demasiados espacios de nombres habilitados. Necesitará administrarlos a
msgid "Too many projects enabled. You will need to manage them via the console or the API."
msgstr "Demasiados proyectos habilitados. Necesitará administrarlos a través de la consola o mediante el API."
+msgid "Too much data"
+msgstr ""
+
msgid "Topics (optional)"
msgstr ""
@@ -26234,6 +27125,9 @@ msgstr "Tamaño total de los artefactos: %{total_size}"
msgid "Total cores (CPUs)"
msgstr "Núcleos totales (CPUs)"
+msgid "Total days to completion"
+msgstr ""
+
msgid "Total issues"
msgstr "Total de incidencias"
@@ -26330,6 +27224,9 @@ msgstr "Vista de árbol"
msgid "Trending"
msgstr "Tendencia"
+msgid "Trials|Create a new group to start your GitLab Gold trial."
+msgstr ""
+
msgid "Trials|Go back to GitLab"
msgstr "Volver a GitLab"
@@ -26339,6 +27236,15 @@ msgstr "Saltar periodo de prueba (Continuar con cuenta gratuita)"
msgid "Trials|You can always resume this process by selecting your avatar and choosing 'Start a Gold trial'"
msgstr ""
+msgid "Trials|You can apply your trial to a new group or an existing group."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group or your personal account."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group, an existing group, or your personal account."
+msgstr ""
+
msgid "Trials|You won't get a free trial right now but you can always resume this process by clicking on your avatar and choosing 'Start a free trial'"
msgstr ""
@@ -26408,6 +27314,9 @@ msgstr ""
msgid "Try using a different search term to find the file you are looking for."
msgstr "Intente usar un término de búsqueda diferente para encontrar el archivo que está buscando."
+msgid "Trying to communicate with your device. Plug it in (if needed) and press the button on the device now."
+msgstr ""
+
msgid "Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now."
msgstr "Intentando comunicarse con su dispositivo. Conéctelo (si aún no lo ha hecho) y presione el botón en el dispositivo ahora."
@@ -26495,6 +27404,12 @@ msgstr "URL del almacenamiento externo que servirá los objetos estáticos del r
msgid "URL or request ID"
msgstr "URL o ID de solicitud"
+msgid "USER %{user} WILL BE REMOVED! Are you sure?"
+msgstr ""
+
+msgid "USER WILL BE BLOCKED! Are you sure?"
+msgstr ""
+
msgid "UTC"
msgstr "UTC"
@@ -26552,9 +27467,6 @@ msgstr "No se puede cargar el fichero diff. %{button_try_again}"
msgid "Unable to load the merge request widget. Try reloading the page."
msgstr ""
-msgid "Unable to resolve"
-msgstr "No se puede resolver"
-
msgid "Unable to save iteration. Please try again"
msgstr ""
@@ -26603,6 +27515,9 @@ msgstr "Deshacer ignorar"
msgid "Undo ignore"
msgstr "Deshacer ignorar"
+msgid "Unexpected error"
+msgstr ""
+
msgid "Unfortunately, your email message to GitLab could not be processed."
msgstr "Desafortunadamente, su mensaje de correo electrónico a GitLab no pudo ser procesado."
@@ -26636,6 +27551,9 @@ msgstr "Formato desconocido"
msgid "Unknown response text"
msgstr "Texto de respuesta desconocido"
+msgid "Unless otherwise agreed to in writing with GitLab, by clicking \"Upload License\" you agree that your use of GitLab Software is subject to the %{eula_link_start}Terms of Service%{eula_link_end}."
+msgstr ""
+
msgid "Unlimited"
msgstr "Ilimitado"
@@ -27002,9 +27920,6 @@ msgstr ""
msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
msgstr "Utilice la herramienta Service Desk para conectarse con sus usuarios (por ejemplo, para ofrecer soporte al cliente) a través del correo electrónico directamente desde dentro de GitLab"
-msgid "Use a hardware device to add the second factor of authentication."
-msgstr "Utilice un dispositivo de hardware para agregar un segundo factor de autenticación."
-
msgid "Use an one time password authenticator on your mobile device or computer to enable two-factor authentication (2FA)."
msgstr "Utilice un autenticador de contraseña de un único uso en su dispositivo móvil u ordenador para habilitar la autenticación de dos factores (2FA)."
@@ -27278,15 +28193,15 @@ msgstr "Nombre de usuario o email"
msgid "Users"
msgstr "Usuarios"
+msgid "Users in License"
+msgstr ""
+
msgid "Users in License:"
msgstr "Usuarios en la licencia:"
msgid "Users or groups set as approvers in the project's or merge request's settings."
msgstr ""
-msgid "Users outside of license"
-msgstr "Usuarios fuera de la licencia"
-
msgid "Users over License:"
msgstr ""
@@ -27302,9 +28217,6 @@ msgstr "Usuarios añadidos con éxito."
msgid "Users with a Guest role or those who don't belong to a Project or Group will not use a seat from your license."
msgstr ""
-msgid "Users with a Guest role or those who don't belong to any projects or groups don't count towards seats in use."
-msgstr "Los usuarios con un rol de Invitado o de aquellos que no pertenecen a cualquiera de los proyectos o grupos no cuentan a efectos de puestos en uso."
-
msgid "UsersSelect|%{name} + %{length} more"
msgstr "%{name} + %{length} más"
@@ -27344,9 +28256,6 @@ msgstr "Valide su archivo de configuración de GitLab CI"
msgid "Validations failed."
msgstr "La validación ha fallado."
-msgid "Validity"
-msgstr "Validez"
-
msgid "Value"
msgstr "Valor"
@@ -27365,6 +28274,9 @@ msgstr ""
msgid "Value Stream Name"
msgstr ""
+msgid "ValueStreamAnalyticsStage|We don't have enough data to show this stage."
+msgstr ""
+
msgid "ValueStreamAnalytics|%{days}d"
msgstr ""
@@ -27621,6 +28533,9 @@ msgstr "Revisión"
msgid "VisualReviewApp|Steps 1 and 2 (and sometimes 3) are performed once by the developer before requesting feedback. Steps 3 (if necessary), 4 is performed by the reviewer each time they perform a review."
msgstr ""
+msgid "Visualization"
+msgstr ""
+
msgid "Vulnerabilities"
msgstr "Vulnerabilidades"
@@ -27648,35 +28563,32 @@ msgstr "%{formattedStartDate} hasta hoy"
msgid "VulnerabilityChart|Severity"
msgstr "Gravedad"
-msgid "VulnerabilityManagement|A true-positive and will fix"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Change status"
-msgstr "Cambiar estado"
-
-msgid "VulnerabilityManagement|Confirm"
-msgstr "Confirmar"
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
+msgstr ""
-msgid "VulnerabilityManagement|Confirmed %{timeago} by %{user}"
-msgstr "Confirmado %{timeago} por %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
+msgstr ""
-msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Detected %{timeago} in pipeline %{pipelineLink}"
-msgstr "Detectado %{timeago} en el pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|A true-positive and will fix"
+msgstr ""
-msgid "VulnerabilityManagement|Dismiss"
-msgstr "Descartar"
+msgid "VulnerabilityManagement|Change status"
+msgstr "Cambiar estado"
-msgid "VulnerabilityManagement|Dismissed %{timeago} by %{user}"
-msgstr "Descartado %{timeago} por %{user}"
+msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
+msgstr ""
-msgid "VulnerabilityManagement|Resolved"
-msgstr "Resuelta"
+msgid "VulnerabilityManagement|Detected"
+msgstr ""
-msgid "VulnerabilityManagement|Resolved %{timeago} by %{user}"
-msgstr "Resuelto %{timeago} por %{user}"
+msgid "VulnerabilityManagement|Needs triage"
+msgstr ""
msgid "VulnerabilityManagement|Something went wrong while trying to delete the comment. Please try again later."
msgstr ""
@@ -27726,6 +28638,9 @@ msgstr "Resueltas"
msgid "Vulnerability|%{scannerName} (version %{scannerVersion})"
msgstr "%{scannerName} (versión %{scannerVersion})"
+msgid "Vulnerability|Activity"
+msgstr ""
+
msgid "Vulnerability|Class"
msgstr "Clase"
@@ -27738,6 +28653,9 @@ msgstr ""
msgid "Vulnerability|Description"
msgstr "Descripción"
+msgid "Vulnerability|Detected"
+msgstr ""
+
msgid "Vulnerability|Evidence"
msgstr "Evidencia"
@@ -27801,6 +28719,9 @@ msgstr "Advertencia:"
msgid "Warning: Displaying this diagram might cause performance issues on this page."
msgstr ""
+msgid "We are currently unable to fetch data for the pipeline header."
+msgstr ""
+
msgid "We are currently unable to fetch data for this graph."
msgstr ""
@@ -27840,6 +28761,12 @@ 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 will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
+msgstr ""
+
+msgid "We would like to inform you that your subscription GitLab Enterprise Edition %{plan_name} is nearing its user limit. You have %{active_user_count} active users, which is almost at the user limit of %{maximum_user_count}."
+msgstr ""
+
msgid "We've found no vulnerabilities"
msgstr "No hemos encontrado vulnerabilidades"
@@ -27855,6 +28782,12 @@ msgstr "Terminal web"
msgid "Web terminal"
msgstr "Terminal web"
+msgid "WebAuthn Devices (%{length})"
+msgstr ""
+
+msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
+msgstr ""
+
msgid "WebIDE|Merge request"
msgstr ""
@@ -27993,15 +28926,9 @@ msgstr "¡Bienvenido a GitLab %{first_name}!"
msgid "Welcome to the guided GitLab tour"
msgstr "Bienvenido a la visita guiada de GitLab"
-msgid "Welcome to your Issue Board!"
-msgstr "¡Bienvenido a su tablón de incidencias!"
-
msgid "Welcome to your issue board!"
msgstr ""
-msgid "We’ve been making changes to %{featureName} and we’d love your feedback %{linkStart}in this issue%{linkEnd} to help us improve the experience."
-msgstr ""
-
msgid "What are you searching for?"
msgstr "¿Qué está buscando?"
@@ -28020,6 +28947,9 @@ msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
msgstr "Cuando un ejecutor está bloqueado, no se puede asignar a otros proyectos"
+msgid "When enabled, any user visiting %{host} and creating an account will have to be explicitly approved by the admin before they can login. This setting is effective only if sign-ups are enabled."
+msgstr ""
+
msgid "When enabled, any user visiting %{host} will be able to create an account."
msgstr ""
@@ -28244,6 +29174,9 @@ msgstr "Se desplegará a"
msgid "With requirements, you can set criteria to check your products against."
msgstr ""
+msgid "With test cases, you can define conditions for your project to meet in determining quality"
+msgstr ""
+
msgid "Withdraw Access Request"
msgstr "Retirar Solicitud de Acceso"
@@ -28259,6 +29192,9 @@ msgstr "Límite de trabajo en progreso"
msgid "Workflow Help"
msgstr ""
+msgid "Would you like to create a new branch?"
+msgstr ""
+
msgid "Write"
msgstr "Escritura"
@@ -28280,6 +29216,9 @@ msgstr "Escribe sus notas de la versión o arrastrar sus archivos aquí…"
msgid "Wrong extern UID provided. Make sure Auth0 is configured correctly."
msgstr "UID externo incorrecto. Por favor, asegúrese de que Auth0 está configurado correctamente."
+msgid "YYYY-MM-DD"
+msgstr ""
+
msgid "Yes"
msgstr "Si"
@@ -28337,8 +29276,8 @@ msgstr ""
msgid "You are going to remove the fork relationship from %{project_full_name}. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "You are going to transfer %{project_full_name} to another owner. Are you ABSOLUTELY sure?"
-msgstr "Va a transferir %{project_full_name} a otro propietario. ¿Está TOTALMENTE seguro?"
+msgid "You are going to transfer %{project_full_name} to another namespace. Are you ABSOLUTELY sure?"
+msgstr ""
msgid "You are going to turn off the confidentiality. This means %{strongStart}everyone%{strongEnd} will be able to see and leave a comment on this %{issuableType}."
msgstr ""
@@ -28397,9 +29336,6 @@ msgstr "También puede subir archivos existentes desde su ordenador utilizando l
msgid "You can always edit this later"
msgstr "Siempre puede editar esto más tarde"
-msgid "You can apply your Trial to your Personal account or create a New Group."
-msgstr "Puedes aplicar su version de prueba a su cuenta personal o crear un grupo nuevo."
-
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings"
msgstr ""
@@ -28421,12 +29357,18 @@ msgstr "Puede instalar fácilmente un ejecutor en un clúster de Kubernetes. %{l
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
+msgid "You can find more information about GitLab subscriptions in %{subscriptions_doc_link}."
+msgstr ""
+
msgid "You can generate an access token scoped to this project for each application to use the GitLab API."
msgstr ""
msgid "You can get started by cloning the repository or start adding files to it with one of the following options."
msgstr ""
+msgid "You can group test cases using labels. To learn about the future direction of this feature, visit %{linkStart}Quality Management direction page%{linkEnd}."
+msgstr ""
+
msgid "You can invite a new member to %{project_name} or invite another group."
msgstr ""
@@ -28442,6 +29384,9 @@ msgstr "Puede moverse por el gráfico usando las teclas de flecha."
msgid "You can notify the app / group or a project by sending them an email notification"
msgstr ""
+msgid "You can now close this window."
+msgstr ""
+
msgid "You can now export your security dashboard to a CSV report."
msgstr ""
@@ -28490,9 +29435,6 @@ msgstr "Puede especificar el nivel de la notificación por grupo o por proyecto.
msgid "You can test your .gitlab-ci.yml in %{linkStart}CI Lint%{linkEnd}."
msgstr "Puede probar su archivo .gitlab-ci.yml en %{linkStart}CI Lint%{linkEnd}."
-msgid "You can try again using %{begin_link}basic search%{end_link}"
-msgstr "Puede volver a intentarlo utilizando la %{begin_link}búsqueda básica%{end_link}"
-
msgid "You cannot access the raw file. Please wait a minute."
msgstr "No puede acceder al archivo sin formato. Por favor, espere un minuto."
@@ -28544,6 +29486,9 @@ msgstr "No tiene los permisos necesarios para sobreescribir la configuración de
msgid "You don't have any U2F devices registered yet."
msgstr "No tiene ningún dispositivo U2F registrado."
+msgid "You don't have any WebAuthn devices registered yet."
+msgstr ""
+
msgid "You don't have any active chat names."
msgstr "No tiene ningún nick de chat activo."
@@ -28631,6 +29576,9 @@ msgstr "Puede cerrar el hito ahora."
msgid "You must accept our Terms of Service and privacy policy in order to register an account"
msgstr "Debe aceptar nuestros Términos de servicio y la política de privacidad para poder registrar una cuenta"
+msgid "You must be logged in to search across all of GitLab"
+msgstr ""
+
msgid "You must disassociate %{domain} from all clusters it is attached to before deletion."
msgstr ""
@@ -28670,8 +29618,8 @@ msgstr "Necesitas permisos."
msgid "You need to be logged in."
msgstr "Es necesario haber iniciado una sesión."
-msgid "You need to register a two-factor authentication app before you can set up a U2F device."
-msgstr "Necesita registrar una aplicación de autenticación de dos factores antes de poder configurar un dispositivo U2F."
+msgid "You need to register a two-factor authentication app before you can set up a device."
+msgstr ""
msgid "You need to set terms to be enforced"
msgstr ""
@@ -28688,6 +29636,9 @@ msgstr "Necesita subir un archivo de Google Takeout."
msgid "You reached %{usage_in_percent} of %{namespace_name}'s storage capacity (%{used_storage} of %{storage_limit})"
msgstr ""
+msgid "You successfully declined the invitation"
+msgstr ""
+
msgid "You tried to fork %{link_to_the_project} but it failed for the following reason:"
msgstr "Trató de hacer un fork de %{link_to_the_project} pero falló por la siguiente razón:"
@@ -28853,12 +29804,15 @@ msgstr "Su lista de tareas pendientes"
msgid "Your U2F device did not send a valid JSON response."
msgstr "Su dispositivo U2F no envió una respuesta JSON válida."
-msgid "Your U2F device needs to be set up. Plug it in (if not already) and click the button on the left."
-msgstr "Es necesario configurar su dispositivo U2F. Conéctelo (si no lo ha hecho ya) y haha clic en el botón situado a la izquierda."
-
msgid "Your U2F device was registered!"
msgstr "¡Se ha registrado su dispositivo U2F!"
+msgid "Your WebAuthn device did not send a valid JSON response."
+msgstr ""
+
+msgid "Your WebAuthn device was registered!"
+msgstr ""
+
msgid "Your access request to the %{source_type} has been withdrawn."
msgstr "Su solicitud de acceso a %{source_type} ha sido retirada."
@@ -28880,6 +29834,9 @@ msgstr "Sus aplicaciones autorizadas"
msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
msgstr "Su navegador no soporta U2F. Por favor, utilice la versión de escritorio de Google Chrome (versión 41 o posterior)."
+msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
+msgstr ""
+
msgid "Your changes can be committed to %{branch_name} because a merge request is open."
msgstr "Puede hacer commit de sus cambios a %{branch_name} porque hay un merge request abierto."
@@ -28916,6 +29873,12 @@ msgstr ""
msgid "Your deployment services will be broken, you will need to manually fix the services after renaming."
msgstr "Se interrumpirán sus servicios de despliegue, tendrá que arreglarlos manualmente después del cambio de nombre."
+msgid "Your device is not compatible with GitLab. Please try another device"
+msgstr ""
+
+msgid "Your device needs to be set up. Plug it in (if needed) and click the button on the left."
+msgstr ""
+
msgid "Your device was successfully set up! Give it a name and register it with the GitLab server."
msgstr "¡El dispositivo se ha configurado correctamente!. Por favor, asígnele un nombre y regístrelo con el servidor de GitLab."
@@ -29029,9 +29992,6 @@ msgstr[1] "alrededor de %d horas"
msgid "access:"
msgstr ""
-msgid "activated"
-msgstr "activado"
-
msgid "added %{created_at_timeago}"
msgstr "añadido %{created_at_timeago}"
@@ -29104,9 +30064,21 @@ msgstr "por"
msgid "by %{user}"
msgstr "por %{user}"
+msgid "cannot be a date in the past"
+msgstr ""
+
msgid "cannot be changed if a personal project has container registry tags."
msgstr "no se puede modificar si un proyecto personal ya contiene etiquetas de registro de contenedor."
+msgid "cannot be changed if shared runners are enabled"
+msgstr ""
+
+msgid "cannot be enabled because parent group does not allow it"
+msgstr ""
+
+msgid "cannot be enabled because parent group has shared Runners disabled"
+msgstr ""
+
msgid "cannot be enabled unless all domains have TLS certificates"
msgstr "no se puede habilitar a menos que todos los dominios tengan certificados TLS"
@@ -29152,7 +30124,7 @@ msgstr "%{linkStartTag}Aprenda más sobre el análisis de dependencias %{linkEnd
msgid "ciReport|%{linkStartTag}Learn more about SAST %{linkEndTag}"
msgstr "%{linkStartTag}Aprenda más sobre SAST %{linkEndTag}"
-msgid "ciReport|%{linkStartTag}Learn more about Secret Scanning %{linkEndTag}"
+msgid "ciReport|%{linkStartTag}Learn more about Secret Detection %{linkEndTag}"
msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about codequality reports %{linkEndTag}"
@@ -29467,9 +30439,6 @@ msgstr ""
msgid "error"
msgstr "error"
-msgid "error code:"
-msgstr "código de error:"
-
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr "%{slash_command} actualizará la hora estimada con el último comando."
@@ -29491,6 +30460,9 @@ msgstr "fallido"
msgid "failed to dismiss associated finding(id=%{finding_id}): %{message}"
msgstr "no se puede descartar el hallazgo asociado (id =%{finding_id}): %{message}"
+msgid "failed to revert associated finding(id=%{finding_id}) to detected"
+msgstr ""
+
msgid "file"
msgid_plural "files"
msgstr[0] "archivo"
@@ -30033,6 +31005,9 @@ msgstr ""
msgid "must be a root namespace"
msgstr ""
+msgid "must be a valid IPv4 or IPv6 address"
+msgstr ""
+
msgid "must be greater than start date"
msgstr "debe ser mayor que la fecha de inicio"
@@ -30069,6 +31044,9 @@ msgstr "sin colaboraciones"
msgid "no expiration"
msgstr "Sin fecha de caducidad"
+msgid "no name set"
+msgstr ""
+
msgid "no one can merge"
msgstr "nadie puede hacer merge"
@@ -30247,9 +31225,6 @@ msgstr "satisfecho"
msgid "security Reports|There was an error creating the merge request"
msgstr "Se ha producido un error al crear el merge request"
-msgid "settings saved, but not activated"
-msgstr ""
-
msgid "severity|Critical"
msgstr "Crítica"
@@ -30376,9 +31351,6 @@ msgstr "para listar"
msgid "toggle collapse"
msgstr ""
-msgid "toggle dropdown"
-msgstr ""
-
msgid "triggered"
msgstr "disparado"
@@ -30406,6 +31378,9 @@ msgstr "subidos"
msgid "user avatar"
msgstr "avatar del usuario"
+msgid "user preferences"
+msgstr ""
+
msgid "username"
msgstr "usuario"
diff --git a/locale/et_EE/gitlab.po b/locale/et_EE/gitlab.po
index 7be776f2840..17e0c8aede0 100644
--- a/locale/et_EE/gitlab.po
+++ b/locale/et_EE/gitlab.po
@@ -14,7 +14,10 @@ msgstr ""
"X-Crowdin-Language: et\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 6\n"
-"PO-Revision-Date: 2020-09-04 23:03\n"
+"PO-Revision-Date: 2020-10-02 18:42\n"
+
+msgid " %{project_name}#%{issue_iid} &middot; opened %{issue_created} by %{author}"
+msgstr ""
msgid " %{start} to %{end}"
msgstr ""
@@ -74,6 +77,16 @@ msgstr ""
msgid "\"el\" parameter is required for createInstance()"
msgstr ""
+msgid "%d Approval"
+msgid_plural "%d Approvals"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d Package"
+msgid_plural "%d Packages"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d Scanned URL"
msgid_plural "%d Scanned URLs"
msgstr[0] ""
@@ -137,6 +150,11 @@ msgstr[1] ""
msgid "%d commits"
msgstr ""
+msgid "%d completed issue"
+msgid_plural "%d completed issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d contribution"
msgid_plural "%d contributions"
msgstr[0] ""
@@ -147,6 +165,11 @@ msgid_plural "%d days"
msgstr[0] ""
msgstr[1] ""
+msgid "%d day until tags are automatically removed"
+msgid_plural "%d days until tags are automatically removed"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d error"
msgid_plural "%d errors"
msgstr[0] ""
@@ -237,6 +260,16 @@ msgid_plural "%d more comments"
msgstr[0] ""
msgstr[1] ""
+msgid "%d open issue"
+msgid_plural "%d open issues"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d pending comment"
+msgid_plural "%d pending comments"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d personal project will be removed and cannot be restored."
msgid_plural "%d personal projects will be removed and cannot be restored."
msgstr[0] ""
@@ -252,6 +285,11 @@ msgid_plural "%d projects"
msgstr[0] ""
msgstr[1] ""
+msgid "%d project selected"
+msgid_plural "%d projects selected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d request with warnings"
msgid_plural "%d requests with warnings"
msgstr[0] ""
@@ -272,6 +310,11 @@ msgid_plural "%d tags"
msgstr[0] ""
msgstr[1] ""
+msgid "%d tag per image name"
+msgid_plural "%d tags per image name"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d unassigned issue"
msgid_plural "%d unassigned issues"
msgstr[0] ""
@@ -292,6 +335,11 @@ msgid_plural "%d vulnerabilities dismissed"
msgstr[0] ""
msgstr[1] ""
+msgid "%d warning found:"
+msgid_plural "%d warnings found:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%s additional commit has been omitted to prevent performance issues."
msgid_plural "%s additional commits have been omitted to prevent performance issues."
msgstr[0] ""
@@ -330,6 +378,9 @@ msgstr ""
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr ""
+msgid "%{completedCount} completed weight"
+msgstr ""
+
msgid "%{completedWeight} of %{totalWeight} weight completed"
msgstr ""
@@ -378,14 +429,12 @@ msgid_plural "%{count} participants"
msgstr[0] ""
msgstr[1] ""
-msgid "%{count} pending comment"
-msgid_plural "%{count} pending comments"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
+msgid "%{count} total weight"
+msgstr ""
+
msgid "%{dashboard_path} could not be found."
msgstr ""
@@ -440,6 +489,9 @@ msgstr ""
msgid "%{group_name} uses group managed accounts. You need to create a new GitLab account which will be managed by %{group_name}."
msgstr ""
+msgid "%{group_name}&%{epic_iid} &middot; opened %{epic_created} by %{author}"
+msgstr ""
+
msgid "%{host} sign-in from new location"
msgstr ""
@@ -452,7 +504,7 @@ msgstr ""
msgid "%{issuableType} will be removed! Are you sure?"
msgstr ""
-msgid "%{issuesSize} issues with a limit of %{maxIssueCount}"
+msgid "%{issuesCount} issues with a limit of %{maxIssueCount}"
msgstr ""
msgid "%{issuesSize} with a limit of %{maxIssueCount}"
@@ -485,7 +537,7 @@ msgstr ""
msgid "%{labelStart}Namespace:%{labelEnd} %{namespace}"
msgstr ""
-msgid "%{labelStart}Report Type:%{labelEnd} %{reportType}"
+msgid "%{labelStart}Scan Type:%{labelEnd} %{reportType}"
msgstr ""
msgid "%{labelStart}Scanner:%{labelEnd} %{scanner}"
@@ -682,9 +734,6 @@ msgid_plural "%{securityScanner} results are not available because a pipeline ha
msgstr[0] ""
msgstr[1] ""
-msgid "%{service_title} %{message}."
-msgstr ""
-
msgid "%{size} GiB"
msgstr ""
@@ -773,6 +822,12 @@ msgstr ""
msgid "%{timebox_name} should belong either to a project or a group."
msgstr ""
+msgid "%{timebox_type} does not support burnup charts"
+msgstr ""
+
+msgid "%{timebox_type} must have a start and due date"
+msgstr ""
+
msgid "%{title} %{operator} %{threshold}"
msgstr ""
@@ -797,7 +852,7 @@ msgstr ""
msgid "%{total} open issue weight"
msgstr ""
-msgid "%{total} open issues"
+msgid "%{total} warnings found: showing first %{warningsDisplayed}"
msgstr ""
msgid "%{usage_ping_link_start}Learn more%{usage_ping_link_end} about what information is shared with GitLab Inc."
@@ -830,9 +885,6 @@ msgstr ""
msgid "&lt; 1 hour"
msgstr ""
-msgid "&lt;no name set&gt;"
-msgstr ""
-
msgid "&lt;no scopes selected&gt;"
msgstr ""
@@ -863,6 +915,9 @@ msgstr ""
msgid "'%{name}' Value Stream created"
msgstr ""
+msgid "'%{name}' Value Stream deleted"
+msgstr ""
+
msgid "'%{name}' stage already exists"
msgstr ""
@@ -922,6 +977,9 @@ msgstr ""
msgid "+ %{numberOfHiddenAssignees} more"
msgstr ""
+msgid "+ %{numberOfHiddenReviewers} more"
+msgstr ""
+
msgid "+%d more"
msgid_plural "+%d more"
msgstr[0] ""
@@ -982,6 +1040,11 @@ msgid_plural "%d Days"
msgstr[0] ""
msgstr[1] ""
+msgid "1 Issue"
+msgid_plural "%d Issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "1 closed issue"
msgid_plural "%{issues} closed issues"
msgstr[0] ""
@@ -997,6 +1060,11 @@ msgid_plural "%d days"
msgstr[0] ""
msgstr[1] ""
+msgid "1 deploy key"
+msgid_plural "%d deploy keys"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1099,6 +1167,9 @@ msgstr ""
msgid ":%{startLine} to %{endLine}"
msgstr ""
+msgid "A %{incident_docs_start}modified issue%{incident_docs_end} to guide the resolution of incidents."
+msgstr ""
+
msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr ""
@@ -1111,6 +1182,9 @@ msgstr ""
msgid "A GitBook site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
+msgid "A Gitpod configured Webapplication in Spring and Java"
+msgstr ""
+
msgid "A Hexo site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
@@ -1282,9 +1356,15 @@ msgstr ""
msgid "Access expiration date"
msgstr ""
+msgid "Access expires"
+msgstr ""
+
msgid "Access forbidden. Check your access level."
msgstr ""
+msgid "Access granted"
+msgstr ""
+
msgid "Access requests"
msgstr ""
@@ -1294,6 +1374,9 @@ msgstr ""
msgid "Access to Pages websites are controlled based on the user's membership to a given project. By checking this box, users will be required to be logged in to have access to all Pages websites in your instance."
msgstr ""
+msgid "AccessDropdown|Deploy Keys"
+msgstr ""
+
msgid "AccessDropdown|Groups"
msgstr ""
@@ -1411,12 +1494,6 @@ msgstr ""
msgid "Active Sessions"
msgstr ""
-msgid "Active Users:"
-msgstr ""
-
-msgid "Active users"
-msgstr ""
-
msgid "Activity"
msgstr ""
@@ -1584,9 +1661,6 @@ msgstr ""
msgid "Add label(s)"
msgstr ""
-msgid "Add license"
-msgstr ""
-
msgid "Add list"
msgstr ""
@@ -1761,21 +1835,51 @@ msgstr ""
msgid "AdminArea|Bots"
msgstr ""
+msgid "AdminArea|Components"
+msgstr ""
+
msgid "AdminArea|Developer"
msgstr ""
+msgid "AdminArea|Features"
+msgstr ""
+
+msgid "AdminArea|Groups: %{number_of_groups}"
+msgstr ""
+
msgid "AdminArea|Guest"
msgstr ""
msgid "AdminArea|Included Free in license"
msgstr ""
+msgid "AdminArea|Latest groups"
+msgstr ""
+
+msgid "AdminArea|Latest projects"
+msgstr ""
+
+msgid "AdminArea|Latest users"
+msgstr ""
+
msgid "AdminArea|Maintainer"
msgstr ""
+msgid "AdminArea|New group"
+msgstr ""
+
+msgid "AdminArea|New project"
+msgstr ""
+
+msgid "AdminArea|New user"
+msgstr ""
+
msgid "AdminArea|Owner"
msgstr ""
+msgid "AdminArea|Projects: %{number_of_projects}"
+msgstr ""
+
msgid "AdminArea|Reporter"
msgstr ""
@@ -1803,6 +1907,9 @@ msgstr ""
msgid "AdminArea|Users without a Group and Project"
msgstr ""
+msgid "AdminArea|Users: %{number_of_users}"
+msgstr ""
+
msgid "AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running."
msgstr ""
@@ -1821,9 +1928,6 @@ msgstr ""
msgid "AdminProjects|Delete Project %{projectName}?"
msgstr ""
-msgid "AdminProjects|Delete project"
-msgstr ""
-
msgid "AdminSettings|Apply integration settings to all Projects"
msgstr ""
@@ -2061,21 +2165,30 @@ msgstr ""
msgid "AdminUsers|Without projects"
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 ""
msgid "AdminUsers|You cannot remove your own admin rights."
msgstr ""
+msgid "AdminUsers|You must transfer ownership or delete the groups owned by this user before you can delete their account"
+msgstr ""
+
msgid "Administration"
msgstr ""
msgid "Advanced"
msgstr ""
+msgid "Advanced Search"
+msgstr ""
+
+msgid "Advanced Search with Elasticsearch"
+msgstr ""
+
msgid "Advanced Settings"
msgstr ""
@@ -2153,6 +2266,9 @@ msgstr ""
msgid "AlertManagement|Edit"
msgstr ""
+msgid "AlertManagement|Environment"
+msgstr ""
+
msgid "AlertManagement|Events"
msgstr ""
@@ -2165,6 +2281,9 @@ msgstr ""
msgid "AlertManagement|Issue"
msgstr ""
+msgid "AlertManagement|Key"
+msgstr ""
+
msgid "AlertManagement|Low"
msgstr ""
@@ -2258,6 +2377,9 @@ msgstr ""
msgid "AlertManagement|Unknown"
msgstr ""
+msgid "AlertManagement|Value"
+msgstr ""
+
msgid "AlertManagement|View alerts in Opsgenie"
msgstr ""
@@ -2417,6 +2539,9 @@ msgstr ""
msgid "All projects"
msgstr ""
+msgid "All projects selected"
+msgstr ""
+
msgid "All security scans are enabled because %{linkStart}Auto DevOps%{linkEnd} is enabled on this project"
msgstr ""
@@ -2504,6 +2629,9 @@ msgstr ""
msgid "Almost there"
msgstr ""
+msgid "Already blocked"
+msgstr ""
+
msgid "Also called \"Issuer\" or \"Relying party trust identifier\""
msgstr ""
@@ -2558,6 +2686,9 @@ msgstr ""
msgid "An error has occurred"
msgstr ""
+msgid "An error occured while making the changes: %{error}"
+msgstr ""
+
msgid "An error occurred adding a draft to the thread."
msgstr ""
@@ -2585,12 +2716,6 @@ msgstr ""
msgid "An error occurred when toggling the notification subscription"
msgstr ""
-msgid "An error occurred when trying to resolve a comment. Please try again."
-msgstr ""
-
-msgid "An error occurred when trying to resolve a discussion. Please try again."
-msgstr ""
-
msgid "An error occurred when updating the issue weight"
msgstr ""
@@ -2606,12 +2731,6 @@ msgstr ""
msgid "An error occurred while checking group path. Please refresh and try again."
msgstr ""
-msgid "An error occurred while committing your changes."
-msgstr ""
-
-msgid "An error occurred while creating the list. Please try again."
-msgstr ""
-
msgid "An error occurred while decoding the file."
msgstr ""
@@ -2684,25 +2803,19 @@ msgstr ""
msgid "An error occurred while fetching the Service Desk address."
msgstr ""
-msgid "An error occurred while fetching the board issues. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the board lists. Please reload the page."
msgstr ""
msgid "An error occurred while fetching the board lists. Please try again."
msgstr ""
-msgid "An error occurred while fetching the board swimlanes. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the builds."
msgstr ""
msgid "An error occurred while fetching the job log."
msgstr ""
-msgid "An error occurred while fetching the job trace."
+msgid "An error occurred while fetching the job logs."
msgstr ""
msgid "An error occurred while fetching the job."
@@ -2849,9 +2962,6 @@ msgstr ""
msgid "An error occurred while saving assignees"
msgstr ""
-msgid "An error occurred while saving the template. Please check if the template exists."
-msgstr ""
-
msgid "An error occurred while searching for milestones"
msgstr ""
@@ -2870,10 +2980,10 @@ msgstr ""
msgid "An error occurred while updating approvers"
msgstr ""
-msgid "An error occurred while updating the comment"
+msgid "An error occurred while updating labels."
msgstr ""
-msgid "An error occurred while updating the list. Please try again."
+msgid "An error occurred while updating the comment"
msgstr ""
msgid "An error occurred while validating group path"
@@ -2927,6 +3037,9 @@ msgstr ""
msgid "An unknown error occurred while loading this graph."
msgstr ""
+msgid "An unknown error occurred."
+msgstr ""
+
msgid "Analytics"
msgstr ""
@@ -2960,10 +3073,10 @@ msgstr ""
msgid "Any"
msgstr ""
-msgid "Any Author"
+msgid "Any %{header}"
msgstr ""
-msgid "Any Status"
+msgid "Any Author"
msgstr ""
msgid "Any branch"
@@ -3017,6 +3130,9 @@ msgstr ""
msgid "Application ID"
msgstr ""
+msgid "Application limits saved successfully"
+msgstr ""
+
msgid "Application settings saved successfully"
msgstr ""
@@ -3226,6 +3342,9 @@ msgstr ""
msgid "Are you sure you want to close this blocked issue?"
msgstr ""
+msgid "Are you sure you want to delete \"%{name}\" Value Stream?"
+msgstr ""
+
msgid "Are you sure you want to delete %{name}?"
msgstr ""
@@ -3235,6 +3354,9 @@ msgstr ""
msgid "Are you sure you want to delete this %{typeOfComment}?"
msgstr ""
+msgid "Are you sure you want to delete this SSH key?"
+msgstr ""
+
msgid "Are you sure you want to delete this board?"
msgstr ""
@@ -3259,6 +3381,11 @@ msgstr ""
msgid "Are you sure you want to erase this build?"
msgstr ""
+msgid "Are you sure you want to import %d repository?"
+msgid_plural "Are you sure you want to import %d repositories?"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Are you sure you want to lose unsaved changes?"
msgstr ""
@@ -3268,15 +3395,15 @@ msgstr ""
msgid "Are you sure you want to merge immediately?"
msgstr ""
-msgid "Are you sure you want to permanently delete this license?"
-msgstr ""
-
msgid "Are you sure you want to re-deploy this environment?"
msgstr ""
msgid "Are you sure you want to regenerate the public key? You will have to update the public key on the remote server before mirroring will work again."
msgstr ""
+msgid "Are you sure you want to reindex?"
+msgstr ""
+
msgid "Are you sure you want to remove %{group_name}?"
msgstr ""
@@ -3304,6 +3431,9 @@ msgstr ""
msgid "Are you sure you want to revoke this nickname?"
msgstr ""
+msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
+msgstr ""
+
msgid "Are you sure you want to stop this environment?"
msgstr ""
@@ -3325,6 +3455,9 @@ msgstr ""
msgid "Are you sure? The device will be signed out of GitLab and all remember me tokens revoked."
msgstr ""
+msgid "Are you sure? This will invalidate your registered applications and U2F / WebAuthn devices."
+msgstr ""
+
msgid "Are you sure? This will invalidate your registered applications and U2F devices."
msgstr ""
@@ -3343,9 +3476,6 @@ msgstr ""
msgid "Artifacts"
msgstr ""
-msgid "As U2F devices are only supported by a few browsers, we require that you set up a two-factor authentication app before a U2F device. That way you'll always be able to log in - even when you're using an unsupported browser."
-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 ""
@@ -3539,6 +3669,9 @@ msgstr ""
msgid "AuditLogs|Target"
msgstr ""
+msgid "AuditLogs|This month"
+msgstr ""
+
msgid "AuditLogs|User Events"
msgstr ""
@@ -3578,6 +3711,9 @@ msgstr ""
msgid "Authentication via U2F device failed."
msgstr ""
+msgid "Authentication via WebAuthn device failed."
+msgstr ""
+
msgid "Author"
msgstr ""
@@ -3845,15 +3981,6 @@ msgstr ""
msgid "BambooService|You must set up automatic revision labeling and a repository trigger in Bamboo."
msgstr ""
-msgid "BatchComments|Delete all pending comments"
-msgstr ""
-
-msgid "BatchComments|Discard review?"
-msgstr ""
-
-msgid "BatchComments|You're about to discard your review which will delete all of your pending comments. The deleted comments %{strong_start}cannot%{strong_end} be restored."
-msgstr ""
-
msgid "Be careful. Changing the project's namespace can have unintended side effects."
msgstr ""
@@ -3875,6 +4002,9 @@ msgstr ""
msgid "Bi-weekly code coverage"
msgstr ""
+msgid "Billable Users:"
+msgstr ""
+
msgid "Billing"
msgstr ""
@@ -3884,7 +4014,7 @@ msgstr ""
msgid "BillingPlans|@%{user_name} you are currently using the %{plan_name} plan."
msgstr ""
-msgid "BillingPlans|Congratulations, your new trial is activated"
+msgid "BillingPlans|Congratulations, your free trial is activated."
msgstr ""
msgid "BillingPlans|If you would like to downgrade your plan please contact %{support_link_start}Customer Support%{support_link_end}."
@@ -3947,6 +4077,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Block user"
+msgstr ""
+
msgid "Blocked"
msgstr ""
@@ -3962,31 +4095,37 @@ msgstr ""
msgid "Blog"
msgstr ""
-msgid "Board name"
-msgstr ""
-
msgid "Board scope"
msgstr ""
msgid "Board scope affects which issues are displayed for anyone who visits this board"
msgstr ""
-msgid "BoardBlankState|Add default lists"
+msgid "Boards"
msgstr ""
-msgid "BoardBlankState|Add the following default lists to your Issue Board with one click:"
+msgid "Boards and Board Lists"
msgstr ""
-msgid "BoardBlankState|Nevermind, I'll use my own"
+msgid "Boards|An error occurred while creating the issue. Please try again."
msgstr ""
-msgid "BoardBlankState|Starting out with the default set of lists will get you right on the way to making the most of your board."
+msgid "Boards|An error occurred while creating the list. Please try again."
msgstr ""
-msgid "Boards"
+msgid "Boards|An error occurred while fetching issues. Please reload the page."
msgstr ""
-msgid "Boards and Board Lists"
+msgid "Boards|An error occurred while fetching the board issues. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching the board swimlanes. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while moving the issue. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while updating the list. Please try again."
msgstr ""
msgid "Boards|Collapse"
@@ -4013,7 +4152,7 @@ msgstr ""
msgid "Branch %{branch_name} was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr ""
-msgid "Branch has changed"
+msgid "Branch changed"
msgstr ""
msgid "Branch is already taken"
@@ -4319,6 +4458,9 @@ msgstr ""
msgid "CLOSED (MOVED)"
msgstr ""
+msgid "CODEOWNERS rule violation"
+msgstr ""
+
msgid "CONTRIBUTING"
msgstr ""
@@ -4349,9 +4491,6 @@ msgstr ""
msgid "Can't create snippet: %{err}"
msgstr ""
-msgid "Can't edit as source branch was deleted"
-msgstr ""
-
msgid "Can't fetch content for the blob: %{err}"
msgstr ""
@@ -4364,9 +4503,6 @@ msgstr ""
msgid "Can't load mermaid module: %{err}"
msgstr ""
-msgid "Can't remove group members without group managed account"
-msgstr ""
-
msgid "Can't scan the code?"
msgstr ""
@@ -4409,6 +4545,9 @@ msgstr ""
msgid "Cannot create the abuse report. This user has been blocked."
msgstr ""
+msgid "Cannot enable shared runners because parent group does not allow it"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -4514,6 +4653,15 @@ msgstr ""
msgid "Change your password or recover your current one"
msgstr ""
+msgid "ChangeReviewer|Reviewer changed from %{old} to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Reviewer changed to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Unassigned"
+msgstr ""
+
msgid "ChangeTypeActionLabel|Pick into branch"
msgstr ""
@@ -4553,6 +4701,9 @@ msgstr ""
msgid "Changes the title to \"%{title_param}\"."
msgstr ""
+msgid "Changes were successfully made."
+msgstr ""
+
msgid "Changes won't take place until the index is %{link_start}recreated%{link_end}."
msgstr ""
@@ -4958,6 +5109,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove variable"
+msgstr ""
+
msgid "CiVariables|Remove variable row"
msgstr ""
@@ -5036,9 +5190,6 @@ msgstr ""
msgid "Clear due date"
msgstr ""
-msgid "Clear input"
-msgstr ""
-
msgid "Clear recent searches"
msgstr ""
@@ -5087,6 +5238,9 @@ msgstr ""
msgid "Client authentication key password"
msgstr ""
+msgid "Client request timeout"
+msgstr ""
+
msgid "Clients"
msgstr ""
@@ -5171,6 +5325,27 @@ msgstr ""
msgid "Cluster type must be specificed for Stages::ClusterEndpointInserter"
msgstr ""
+msgid "ClusterAgents|Configuration"
+msgstr ""
+
+msgid "ClusterAgents|Connect your cluster with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate Kubernetes with a GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Name"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Agent also requires %{linkStart}enabling the Agent Server%{linkEnd}"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Kubernetes Agent allows an Infrastructure as Code, GitOps approach to integrating Kubernetes clusters with GitLab. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "ClusterAgent|This feature is only available for premium plans"
msgstr ""
@@ -5240,10 +5415,10 @@ msgstr ""
msgid "ClusterIntegration|All installed applications and related resources"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster."
+msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{linkStart}More information%{linkEnd}"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{startLink}More information%{endLink}"
+msgid "ClusterIntegration|Allow GitLab to manage namespaces and service accounts for this cluster."
msgstr ""
msgid "ClusterIntegration|Alternatively, "
@@ -5264,6 +5439,9 @@ msgstr ""
msgid "ClusterIntegration|An error occurred while trying to fetch zone machine types: %{error}"
msgstr ""
+msgid "ClusterIntegration|An unknown error occurred while attempting to connect to Kubernetes."
+msgstr ""
+
msgid "ClusterIntegration|Any project namespaces"
msgstr ""
@@ -5279,6 +5457,9 @@ msgstr ""
msgid "ClusterIntegration|Authenticate with Amazon Web Services"
msgstr ""
+msgid "ClusterIntegration|Authentication Error"
+msgstr ""
+
msgid "ClusterIntegration|Base domain"
msgstr ""
@@ -5297,13 +5478,22 @@ msgstr ""
msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}security group %{externalLinkIcon} %{endLink} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
+msgid "ClusterIntegration|Check your CA certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Check your cluster status"
+msgstr ""
+
+msgid "ClusterIntegration|Check your token"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}subnets %{externalLinkIcon} %{endLink} in your VPC where your worker nodes will run."
+msgid "ClusterIntegration|Choose the %{linkStart}security group %{linkEnd} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
msgstr ""
-msgid "ClusterIntegration|Choose the worker node %{startLink}instance type %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Choose the %{linkStart}subnets %{linkEnd} in your VPC where your worker nodes will run."
+msgstr ""
+
+msgid "ClusterIntegration|Choose the worker node %{linkStart}instance type%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Choose which applications to install on your Kubernetes cluster."
@@ -5315,10 +5505,7 @@ msgstr ""
msgid "ClusterIntegration|Clear cluster cache"
msgstr ""
-msgid "ClusterIntegration|Clear the local cache of namespace and service accounts. This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
-msgstr ""
-
-msgid "ClusterIntegration|Cluster being created"
+msgid "ClusterIntegration|Clear the local cache of namespace and service accounts."
msgstr ""
msgid "ClusterIntegration|Cluster management project (alpha)"
@@ -5330,15 +5517,21 @@ msgstr ""
msgid "ClusterIntegration|Cluster_applications artifact too big. Maximum allowable size: %{human_size}"
msgstr ""
-msgid "ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters."
+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|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}"
+msgid "ClusterIntegration|Clusters connected with a certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Connect cluster with certificate"
msgstr ""
msgid "ClusterIntegration|Connect existing cluster"
msgstr ""
+msgid "ClusterIntegration|Connection Error"
+msgstr ""
+
msgid "ClusterIntegration|Copy API URL"
msgstr ""
@@ -5414,6 +5607,12 @@ msgstr ""
msgid "ClusterIntegration|Deletes all GitLab resources attached to this cluster during removal"
msgstr ""
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared."
+msgstr ""
+
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared. %{linkStart}More information%{linkEnd}"
+msgstr ""
+
msgid "ClusterIntegration|Did you know?"
msgstr ""
@@ -5483,6 +5682,9 @@ msgstr ""
msgid "ClusterIntegration|Fluentd is an open source data collector, which lets you unify the data collection and consumption for a better use and understanding of data. It requires at least one of the following logs to be successfully installed."
msgstr ""
+msgid "ClusterIntegration|GitLab Agent managed clusters"
+msgstr ""
+
msgid "ClusterIntegration|GitLab Container Network Policies"
msgstr ""
@@ -5495,6 +5697,12 @@ msgstr ""
msgid "ClusterIntegration|GitLab Runner connects to the repository and executes CI/CD jobs, pushing results back and deploying applications to production."
msgstr ""
+msgid "ClusterIntegration|GitLab failed to authenticate."
+msgstr ""
+
+msgid "ClusterIntegration|GitLab failed to connect to the cluster."
+msgstr ""
+
msgid "ClusterIntegration|GitLab-managed cluster"
msgstr ""
@@ -5516,6 +5724,9 @@ msgstr ""
msgid "ClusterIntegration|Group cluster"
msgstr ""
+msgid "ClusterIntegration|HTTP Error"
+msgstr ""
+
msgid "ClusterIntegration|Helm Tiller"
msgstr ""
@@ -5549,7 +5760,10 @@ msgstr ""
msgid "ClusterIntegration|Instance type"
msgstr ""
-msgid "ClusterIntegration|Integrate Kubernetes cluster automation"
+msgid "ClusterIntegration|Integrate Kubernetes with a cluster certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Integrate with a cluster certificate"
msgstr ""
msgid "ClusterIntegration|Issuer Email"
@@ -5585,9 +5799,6 @@ msgstr ""
msgid "ClusterIntegration|Knative extends Kubernetes to provide a set of middleware components that are essential to build modern, source-centric, and container-based applications that can run anywhere: on premises, in the cloud, or even in a third-party data center."
msgstr ""
-msgid "ClusterIntegration|Kubernetes cluster"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes cluster is being created..."
msgstr ""
@@ -5600,9 +5811,6 @@ msgstr ""
msgid "ClusterIntegration|Kubernetes clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr ""
-msgid "ClusterIntegration|Kubernetes clusters can be used to deploy applications and to provide Review Apps for this project"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes version"
msgstr ""
@@ -5615,7 +5823,7 @@ msgstr ""
msgid "ClusterIntegration|Learn more about %{help_link_start}zones%{help_link_end}."
msgstr ""
-msgid "ClusterIntegration|Learn more about %{startLink}Regions %{externalLinkIcon}%{endLink}."
+msgid "ClusterIntegration|Learn more about %{linkStart}Regions%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Learn more about Kubernetes"
@@ -5660,12 +5868,18 @@ msgstr ""
msgid "ClusterIntegration|Machine type"
msgstr ""
+msgid "ClusterIntegration|Make sure your API endpoint is correct"
+msgstr ""
+
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create Kubernetes clusters"
msgstr ""
msgid "ClusterIntegration|Manage your Kubernetes cluster by visiting %{provider_link}"
msgstr ""
+msgid "ClusterIntegration|Namespace per environment"
+msgstr ""
+
msgid "ClusterIntegration|No IAM Roles found"
msgstr ""
@@ -5711,6 +5925,9 @@ msgstr ""
msgid "ClusterIntegration|No zones matched your search"
msgstr ""
+msgid "ClusterIntegration|Node calculations use the Kubernetes Metrics API. Make sure your cluster has metrics installed"
+msgstr ""
+
msgid "ClusterIntegration|Number of nodes"
msgstr ""
@@ -5753,6 +5970,9 @@ msgstr ""
msgid "ClusterIntegration|RBAC-enabled cluster"
msgstr ""
+msgid "ClusterIntegration|Read our %{linkStart}help page%{linkEnd} on Kubernetes cluster integration."
+msgstr ""
+
msgid "ClusterIntegration|Read our %{link_start}help page%{link_end} on Kubernetes cluster integration."
msgstr ""
@@ -5855,7 +6075,7 @@ msgstr ""
msgid "ClusterIntegration|Select a VPC to choose a subnet"
msgstr ""
-msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{linkStart}Amazon Web Services %{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select a network to choose a subnetwork"
@@ -5888,7 +6108,7 @@ msgstr ""
msgid "ClusterIntegration|Select project to choose zone"
msgstr ""
-msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select zone"
@@ -5978,9 +6198,18 @@ msgstr ""
msgid "ClusterIntegration|There was a problem authenticating with your cluster. Please ensure your CA Certificate and Token are valid."
msgstr ""
+msgid "ClusterIntegration|There was an HTTP error when connecting to your cluster."
+msgstr ""
+
msgid "ClusterIntegration|This account must have permissions to create a Kubernetes cluster in the %{link_to_container_project} specified below"
msgstr ""
+msgid "ClusterIntegration|This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
+msgstr ""
+
+msgid "ClusterIntegration|This is necessary to clear existing environment-namespace associations from clusters previously managed by GitLab."
+msgstr ""
+
msgid "ClusterIntegration|This option will allow you to install applications on RBAC clusters."
msgstr ""
@@ -6005,9 +6234,21 @@ msgstr ""
msgid "ClusterIntegration|To use a new project, first create one on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}."
msgstr ""
+msgid "ClusterIntegration|Troubleshooting tips:"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Authenticate"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Connect"
+msgstr ""
+
msgid "ClusterIntegration|Uninstall %{appTitle}"
msgstr ""
+msgid "ClusterIntegration|Unknown Error"
+msgstr ""
+
msgid "ClusterIntegration|Update %{appTitle}"
msgstr ""
@@ -6068,7 +6309,7 @@ msgstr ""
msgid "ClusterIntegration|Your cluster API is unreachable. Please ensure your API URL is correct."
msgstr ""
-msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Zone"
@@ -6188,6 +6429,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse all threads"
+msgstr ""
+
msgid "Collapse approvers"
msgstr ""
@@ -6337,7 +6581,7 @@ msgstr ""
msgid "Commit…"
msgstr ""
-msgid "Company"
+msgid "Community forum"
msgstr ""
msgid "Company name"
@@ -6346,6 +6590,9 @@ msgstr ""
msgid "Compare"
msgstr ""
+msgid "Compare %{oldCommitId}...%{newCommitId}"
+msgstr ""
+
msgid "Compare Git revisions"
msgstr ""
@@ -6361,6 +6608,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare submodule commit revisions"
+msgstr ""
+
msgid "Compare with previous version"
msgstr ""
@@ -6496,6 +6746,9 @@ msgstr ""
msgid "Configure the way a user creates a new account."
msgstr ""
+msgid "Configure which lists are shown for anyone who visits this board"
+msgstr ""
+
msgid "Confirm"
msgstr ""
@@ -6721,6 +6974,9 @@ msgstr[1] ""
msgid "ContainerRegistry|Set cleanup policy"
msgstr ""
+msgid "ContainerRegistry|Some tags were not deleted"
+msgstr ""
+
msgid "ContainerRegistry|Something went wrong while fetching the cleanup policy."
msgstr ""
@@ -6760,6 +7016,9 @@ msgstr ""
msgid "ContainerRegistry|Tags with names matching this regex pattern will %{italicStart}expire:%{italicEnd}"
msgstr ""
+msgid "ContainerRegistry|The cleanup policy timed out before it could delete all tags. An administrator can %{adminLinkStart}manually run cleanup now%{adminLinkEnd} or you can wait for the cleanup policy to automatically run again. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "ContainerRegistry|The last tag related to this image was recently removed. This empty image and any associated data will be automatically removed as part of the regular Garbage Collection process. If you have any questions, contact your administrator."
msgstr ""
@@ -6892,6 +7151,9 @@ msgstr ""
msgid "Contributions per group member"
msgstr ""
+msgid "Contributor"
+msgstr ""
+
msgid "Contributors"
msgstr ""
@@ -7021,6 +7283,9 @@ msgstr ""
msgid "Could not change HEAD: branch '%{branch}' does not exist"
msgstr ""
+msgid "Could not commit. An unexpected error occurred."
+msgstr ""
+
msgid "Could not connect to FogBugz, check your URL"
msgstr ""
@@ -7060,6 +7325,9 @@ msgstr ""
msgid "Could not find iteration"
msgstr ""
+msgid "Could not load instance counts. Please refresh the page to try again."
+msgstr ""
+
msgid "Could not remove the trigger."
msgstr ""
@@ -7084,10 +7352,10 @@ msgstr ""
msgid "Could not save prometheus manual configuration"
msgstr ""
-msgid "Could not udpdate wiki page"
+msgid "Could not update the LDAP settings"
msgstr ""
-msgid "Could not update the LDAP settings"
+msgid "Could not update wiki page"
msgstr ""
msgid "Could not upload your designs as one or more files uploaded are not supported."
@@ -7745,6 +8013,9 @@ msgstr ""
msgid "DastProfiles|Are you sure you want to delete this profile?"
msgstr ""
+msgid "DastProfiles|Could not create site validation token. Please refresh the page, or try again later."
+msgstr ""
+
msgid "DastProfiles|Could not create the scanner profile. Please try again."
msgstr ""
@@ -7769,6 +8040,12 @@ msgstr ""
msgid "DastProfiles|Could not fetch site profiles. Please refresh the page, or try again later."
msgstr ""
+msgid "DastProfiles|Could not retrieve site validation status. Please refresh the page, or try again later."
+msgstr ""
+
+msgid "DastProfiles|Could not update the scanner profile. Please try again."
+msgstr ""
+
msgid "DastProfiles|Could not update the site profile. Please try again."
msgstr ""
@@ -7784,7 +8061,7 @@ msgstr ""
msgid "DastProfiles|Download validation text file"
msgstr ""
-msgid "DastProfiles|Edit feature will come soon. Please create a new profile if changes needed"
+msgid "DastProfiles|Edit scanner profile"
msgstr ""
msgid "DastProfiles|Edit site profile"
@@ -7817,6 +8094,9 @@ msgstr ""
msgid "DastProfiles|No profiles created yet"
msgstr ""
+msgid "DastProfiles|Passive"
+msgstr ""
+
msgid "DastProfiles|Please enter a valid URL format, ex: http://www.example.com/home"
msgstr ""
@@ -7832,6 +8112,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan mode"
+msgstr ""
+
msgid "DastProfiles|Scanner Profile"
msgstr ""
@@ -7871,10 +8154,10 @@ msgstr ""
msgid "DastProfiles|Text file validation"
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
+msgid "DastProfiles|The maximum number of minutes allowed for the spider to traverse the site."
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the spider to traverse the site."
+msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
msgstr ""
msgid "DastProfiles|Validate"
@@ -7907,6 +8190,9 @@ msgstr ""
msgid "Date picker"
msgstr ""
+msgid "Date range"
+msgstr ""
+
msgid "Date range cannot exceed %{maxDateRange} days."
msgstr ""
@@ -7931,6 +8217,9 @@ msgstr ""
msgid "Days to merge"
msgstr ""
+msgid "Dear Administrator,"
+msgstr ""
+
msgid "Debug"
msgstr ""
@@ -8042,12 +8331,18 @@ msgstr ""
msgid "Delete"
msgstr ""
+msgid "Delete %{name}"
+msgstr ""
+
msgid "Delete Comment"
msgstr ""
msgid "Delete Snippet"
msgstr ""
+msgid "Delete Value Stream"
+msgstr ""
+
msgid "Delete account"
msgstr ""
@@ -8069,9 +8364,6 @@ msgstr ""
msgid "Delete label: %{label_name} ?"
msgstr ""
-msgid "Delete license"
-msgstr ""
-
msgid "Delete list"
msgstr ""
@@ -8147,15 +8439,6 @@ msgstr ""
msgid "Deleting a project places it into a read-only state until %{date}, at which point the project will be permanently deleted. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "Deleting the license failed."
-msgstr ""
-
-msgid "Deleting the license failed. The license was not found."
-msgstr ""
-
-msgid "Deleting the license failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "Deleting the project will delete its repository and all related resources including issues, merge requests etc."
msgstr ""
@@ -8651,7 +8934,10 @@ msgstr ""
msgid "DesignManagement|The maximum number of designs allowed to be uploaded is %{upload_limit}. Please try again."
msgstr ""
-msgid "DesignManagement|To upload designs, you'll need to enable LFS. %{requirements_link_start}More information%{requirements_link_end}"
+msgid "DesignManagement|There was an error moving your designs. Please upload your designs below."
+msgstr ""
+
+msgid "DesignManagement|To upload designs, you'll need to enable LFS and have admin enable hashed storage. %{requirements_link_start}More information%{requirements_link_end}"
msgstr ""
msgid "DesignManagement|Unresolve thread"
@@ -8663,6 +8949,9 @@ msgstr ""
msgid "DesignManagement|Upload skipped."
msgstr ""
+msgid "DesignManagement|Your designs are being copied and are on their way… Please refresh to update."
+msgstr ""
+
msgid "DesignManagement|and %{moreCount} more."
msgstr ""
@@ -8720,6 +9009,9 @@ msgstr ""
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
+msgid "Direct member"
+msgstr ""
+
msgid "Direction"
msgstr ""
@@ -8768,9 +9060,6 @@ msgstr ""
msgid "Discard draft"
msgstr ""
-msgid "Discard review"
-msgstr ""
-
msgid "DiscordService|Discord Notifications"
msgstr ""
@@ -8839,10 +9128,10 @@ msgstr ""
msgid "Dismiss Merge Request promotion"
msgstr ""
-msgid "Dismiss Selected"
+msgid "Dismiss Value Stream Analytics introduction box"
msgstr ""
-msgid "Dismiss Value Stream Analytics introduction box"
+msgid "Dismiss selected"
msgstr ""
msgid "Dismiss trial promotion"
@@ -8893,9 +9182,6 @@ msgstr ""
msgid "Documents reindexed: %{processed_documents} (%{percentage}%%)"
msgstr ""
-msgid "Doing"
-msgstr ""
-
msgid "Domain"
msgstr ""
@@ -9091,9 +9377,6 @@ msgstr ""
msgid "Edit environment"
msgstr ""
-msgid "Edit file"
-msgstr ""
-
msgid "Edit files in the editor and commit changes here"
msgstr ""
@@ -9106,6 +9389,12 @@ msgstr ""
msgid "Edit identity for %{user_name}"
msgstr ""
+msgid "Edit in Web IDE"
+msgstr ""
+
+msgid "Edit in single-file editor"
+msgstr ""
+
msgid "Edit issues"
msgstr ""
@@ -9133,10 +9422,10 @@ msgstr ""
msgid "Editing"
msgstr ""
-msgid "Elasticsearch"
+msgid "Elasticsearch AWS IAM credentials"
msgstr ""
-msgid "Elasticsearch AWS IAM credentials"
+msgid "Elasticsearch HTTP client timeout value in seconds."
msgstr ""
msgid "Elasticsearch indexing restrictions"
@@ -9145,9 +9434,6 @@ msgstr ""
msgid "Elasticsearch indexing started"
msgstr ""
-msgid "Elasticsearch integration. Elasticsearch AWS IAM."
-msgstr ""
-
msgid "Elasticsearch reindexing is already in progress"
msgstr ""
@@ -9175,9 +9461,6 @@ msgstr ""
msgid "Email Notification"
msgstr ""
-msgid "Email address"
-msgstr ""
-
msgid "Email could not be sent"
msgstr ""
@@ -9241,6 +9524,9 @@ msgstr ""
msgid "Emails sent from Service Desk will have this name"
msgstr ""
+msgid "Emails sent to %{email} will still be supported"
+msgstr ""
+
msgid "Emails separated by comma"
msgstr ""
@@ -9274,9 +9560,18 @@ msgstr ""
msgid "Enable"
msgstr ""
+msgid "Enable %{link_start}Gitpod%{link_end} integration to launch a development environment in your browser directly from GitLab."
+msgstr ""
+
msgid "Enable Auto DevOps"
msgstr ""
+msgid "Enable Gitpod"
+msgstr ""
+
+msgid "Enable Gitpod?"
+msgstr ""
+
msgid "Enable HTML emails"
msgstr ""
@@ -9406,9 +9701,6 @@ msgstr ""
msgid "Encountered an error while rendering: %{err}"
msgstr ""
-msgid "End date"
-msgstr ""
-
msgid "Ends at (UTC)"
msgstr ""
@@ -9568,7 +9860,7 @@ msgstr ""
msgid "EnvironmentsDashboard|The environments dashboard provides a summary of each project's environments' status, including pipeline and alert statuses."
msgstr ""
-msgid "EnvironmentsDashboard|This dashboard displays a maximum of 7 projects and 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
+msgid "EnvironmentsDashboard|This dashboard displays 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
msgstr ""
msgid "Environments|An error occurred while canceling the auto stop, please try again"
@@ -9889,6 +10181,9 @@ msgstr ""
msgid "Error deleting project. Check logs for error details."
msgstr ""
+msgid "Error fetching burnup chart data"
+msgstr ""
+
msgid "Error fetching diverging counts for branches. Please try again."
msgstr ""
@@ -9967,6 +10262,9 @@ msgstr ""
msgid "Error occurred when saving assignees"
msgstr ""
+msgid "Error occurred when saving reviewers"
+msgstr ""
+
msgid "Error occurred when toggling the notification subscription"
msgstr ""
@@ -10219,10 +10517,13 @@ msgstr ""
msgid "Expand all"
msgstr ""
-msgid "Expand approvers"
+msgid "Expand all files"
msgstr ""
-msgid "Expand dropdown"
+msgid "Expand all threads"
+msgstr ""
+
+msgid "Expand approvers"
msgstr ""
msgid "Expand milestones"
@@ -10393,6 +10694,9 @@ msgstr ""
msgid "Failed to create Merge Request. Please try again."
msgstr ""
+msgid "Failed to create To-Do for the design."
+msgstr ""
+
msgid "Failed to create a branch for this issue. Please try again."
msgstr ""
@@ -10432,6 +10736,12 @@ msgstr ""
msgid "Failed to load authors. Please try again."
msgstr ""
+msgid "Failed to load branches. Please try again."
+msgstr ""
+
+msgid "Failed to load deploy keys."
+msgstr ""
+
msgid "Failed to load emoji list."
msgstr ""
@@ -10447,6 +10757,9 @@ msgstr ""
msgid "Failed to load groups & users."
msgstr ""
+msgid "Failed to load groups, users and deploy keys."
+msgstr ""
+
msgid "Failed to load labels. Please try again."
msgstr ""
@@ -10456,6 +10769,12 @@ msgstr ""
msgid "Failed to load related branches"
msgstr ""
+msgid "Failed to load sidebar confidential toggle"
+msgstr ""
+
+msgid "Failed to load sidebar lock status"
+msgstr ""
+
msgid "Failed to load stacktrace."
msgstr ""
@@ -10483,6 +10802,9 @@ msgstr ""
msgid "Failed to publish issue on status page."
msgstr ""
+msgid "Failed to remove To-Do for the design."
+msgstr ""
+
msgid "Failed to remove a Zoom meeting"
msgstr ""
@@ -10525,6 +10847,9 @@ msgstr ""
msgid "Failed to signing using smartcard authentication"
msgstr ""
+msgid "Failed to toggle To-Do for the design."
+msgstr ""
+
msgid "Failed to update branch!"
msgstr ""
@@ -10638,7 +10963,7 @@ msgstr ""
msgid "FeatureFlags|Edit User List"
msgstr ""
-msgid "FeatureFlags|Enable features for specific users and specific environments by defining feature flag strategies."
+msgid "FeatureFlags|Enable features for specific users and environments by configuring feature flag strategies."
msgstr ""
msgid "FeatureFlags|Environment Spec"
@@ -10698,7 +11023,7 @@ msgstr ""
msgid "FeatureFlags|Include additional user IDs"
msgstr ""
-msgid "FeatureFlags|Install a %{docs_link_anchored_start}compatible client library%{docs_link_anchored_end} and specify the API URL, application name, and instance ID during the configuration setup. %{docs_link_start}More Information%{docs_link_end}"
+msgid "FeatureFlags|Install a %{docsLinkAnchoredStart}compatible client library%{docsLinkAnchoredEnd} and specify the API URL, application name, and instance ID during the configuration setup. %{docsLinkStart}More Information%{docsLinkEnd}"
msgstr ""
msgid "FeatureFlags|Instance ID"
@@ -10710,6 +11035,9 @@ msgstr ""
msgid "FeatureFlags|Loading feature flags"
msgstr ""
+msgid "FeatureFlags|Loading user lists"
+msgstr ""
+
msgid "FeatureFlags|More information"
msgstr ""
@@ -10728,7 +11056,7 @@ msgstr ""
msgid "FeatureFlags|New feature flag"
msgstr ""
-msgid "FeatureFlags|New list"
+msgid "FeatureFlags|New user list"
msgstr ""
msgid "FeatureFlags|Percent of users"
@@ -10767,6 +11095,9 @@ msgstr ""
msgid "FeatureFlags|There was an error fetching the feature flags."
msgstr ""
+msgid "FeatureFlags|There was an error fetching the user lists."
+msgstr ""
+
msgid "FeatureFlags|There was an error retrieving user lists"
msgstr ""
@@ -10782,6 +11113,9 @@ msgstr ""
msgid "FeatureFlags|User List"
msgstr ""
+msgid "FeatureFlags|User Lists"
+msgstr ""
+
msgid "FeatureFlag|List"
msgstr ""
@@ -10809,15 +11143,6 @@ msgstr ""
msgid "Fetching incoming email"
msgstr ""
-msgid "Fetching licenses failed."
-msgstr ""
-
-msgid "Fetching licenses failed. The request endpoint was not found."
-msgstr ""
-
-msgid "Fetching licenses failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "File"
msgstr ""
@@ -10920,12 +11245,21 @@ msgstr ""
msgid "Filter by status"
msgstr ""
+msgid "Filter by test cases that are currently archived."
+msgstr ""
+
+msgid "Filter by test cases that are currently opened."
+msgstr ""
+
msgid "Filter by two-factor authentication"
msgstr ""
msgid "Filter by user"
msgstr ""
+msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
+msgstr ""
+
msgid "Filter pipelines"
msgstr ""
@@ -10941,7 +11275,7 @@ msgstr ""
msgid "Filter results..."
msgstr ""
-msgid "Filter your projects by name"
+msgid "Filter your repositories by name"
msgstr ""
msgid "Filter..."
@@ -10950,7 +11284,7 @@ msgstr ""
msgid "Find File"
msgstr ""
-msgid "Find bugs in your code with coverage-guided fuzzing"
+msgid "Find bugs in your code with coverage-guided fuzzing."
msgstr ""
msgid "Find by path"
@@ -10977,9 +11311,6 @@ msgstr ""
msgid "Finish editing this message first!"
msgstr ""
-msgid "Finish review"
-msgstr ""
-
msgid "Finish setting up your dedicated account for %{group_name}."
msgstr ""
@@ -11049,6 +11380,9 @@ msgstr ""
msgid "Footer message"
msgstr ""
+msgid "For a faster browsing experience, some files are collapsed by default."
+msgstr ""
+
msgid "For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
@@ -11058,6 +11392,9 @@ msgstr ""
msgid "For more info, read the documentation."
msgstr ""
+msgid "For more information on how the number of active users is calculated, see the %{self_managed_subscriptions_doc_link} documentation."
+msgstr ""
+
msgid "For more information, go to the "
msgstr ""
@@ -11196,6 +11533,9 @@ msgstr ""
msgid "Generate new token"
msgstr ""
+msgid "Generic package file size in bytes"
+msgstr ""
+
msgid "Geo"
msgstr ""
@@ -11457,6 +11797,9 @@ msgstr ""
msgid "Geo|Please refer to Geo Troubleshooting."
msgstr ""
+msgid "Geo|Primary node"
+msgstr ""
+
msgid "Geo|Project"
msgstr ""
@@ -11499,6 +11842,9 @@ msgstr ""
msgid "Geo|Review replication status, and resynchronize and reverify items with the primary node."
msgstr ""
+msgid "Geo|Secondary node"
+msgstr ""
+
msgid "Geo|Status"
msgstr ""
@@ -11538,6 +11884,9 @@ msgstr ""
msgid "Geo|URL must be a valid url (ex: https://gitlab.com)"
msgstr ""
+msgid "Geo|Undefined"
+msgstr ""
+
msgid "Geo|Unknown state"
msgstr ""
@@ -11613,10 +11962,16 @@ msgstr ""
msgid "GitHub import"
msgstr ""
+msgid "GitLab"
+msgstr ""
+
msgid "GitLab / Unsubscribe"
msgstr ""
-msgid "GitLab Enterprise Edition %{plan}"
+msgid "GitLab API"
+msgstr ""
+
+msgid "GitLab Billing Team."
msgstr ""
msgid "GitLab Group Runners can execute code for all the projects in this group."
@@ -11628,12 +11983,18 @@ msgstr ""
msgid "GitLab Issue"
msgstr ""
+msgid "GitLab Pages"
+msgstr ""
+
msgid "GitLab Service Desk is a simple way to allow people to create issues in your GitLab instance without needing their own user account. It provides a unique email address for end users to create issues in a project, and replies can be sent either through the GitLab interface or by email. End users will only see the thread through email."
msgstr ""
msgid "GitLab Shared Runners execute code of different projects on the same Runner unless you configure GitLab Runner Autoscale with MaxBuilds 1 (which it is on GitLab.com)."
msgstr ""
+msgid "GitLab Shell"
+msgstr ""
+
msgid "GitLab Support Bot"
msgstr ""
@@ -11643,7 +12004,7 @@ msgstr ""
msgid "GitLab User"
msgstr ""
-msgid "GitLab allows you to continue using your license even if you exceed the number of seats you purchased. You will be required to pay for these seats when you renew your license."
+msgid "GitLab Workhorse"
msgstr ""
msgid "GitLab commit"
@@ -11811,6 +12172,21 @@ msgstr ""
msgid "Gitlab Pages"
msgstr ""
+msgid "Gitpod"
+msgstr ""
+
+msgid "Gitpod|Add the URL to your Gitpod instance configured to read your GitLab projects."
+msgstr ""
+
+msgid "Gitpod|Enable Gitpod integration"
+msgstr ""
+
+msgid "Gitpod|Gitpod URL"
+msgstr ""
+
+msgid "Gitpod|e.g. https://gitpod.example.com"
+msgstr ""
+
msgid "Given access %{time_ago}"
msgstr ""
@@ -12318,9 +12694,6 @@ msgstr ""
msgid "GroupSAML|Valid SAML Response"
msgstr ""
-msgid "GroupSAML|With group managed accounts enabled, all the users without a group managed account will be excluded from the group."
-msgstr ""
-
msgid "GroupSAML|With prohibit outer forks flag enabled group members will be able to fork project only inside your group."
msgstr ""
@@ -12534,10 +12907,10 @@ msgstr ""
msgid "GroupsNew|Create group"
msgstr ""
-msgid "GroupsNew|GitLab group export"
+msgid "GroupsNew|Import"
msgstr ""
-msgid "GroupsNew|Import"
+msgid "GroupsNew|Import a GitLab group export file"
msgstr ""
msgid "GroupsNew|Import group"
@@ -12680,6 +13053,9 @@ msgid_plural "Hide charts"
msgstr[0] ""
msgstr[1] ""
+msgid "Hide comments on this file"
+msgstr ""
+
msgid "Hide details"
msgstr ""
@@ -12724,6 +13100,15 @@ msgstr ""
msgid "Highest role:"
msgstr ""
+msgid "HighlightBar|Alert events:"
+msgstr ""
+
+msgid "HighlightBar|Alert start time:"
+msgstr ""
+
+msgid "HighlightBar|Original alert:"
+msgstr ""
+
msgid "History"
msgstr ""
@@ -12901,6 +13286,9 @@ msgstr ""
msgid "If enabled, access to projects will be validated on an external service using their classification label."
msgstr ""
+msgid "If the number of active users exceeds the user limit, you will be charged for the number of %{users_over_license_link} at your next license reconciliation."
+msgstr ""
+
msgid "If there is no previous license or if the previous license has expired, some GitLab functionality will be blocked until a new, valid license is uploaded."
msgstr ""
@@ -12940,9 +13328,6 @@ msgstr ""
msgid "If your HTTP repository is not publicly accessible, add your credentials."
msgstr ""
-msgid "Iglu registry URL (optional)"
-msgstr ""
-
msgid "Ignore"
msgstr ""
@@ -12979,6 +13364,16 @@ msgstr ""
msgid "Import"
msgstr ""
+msgid "Import %d compatible repository"
+msgid_plural "Import %d compatible repositories"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Import %d repository"
+msgid_plural "Import %d repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Import CSV"
msgstr ""
@@ -12988,15 +13383,9 @@ msgstr ""
msgid "Import all compatible projects"
msgstr ""
-msgid "Import all compatible repositories"
-msgstr ""
-
msgid "Import all projects"
msgstr ""
-msgid "Import all repositories"
-msgstr ""
-
msgid "Import an exported GitLab project"
msgstr ""
@@ -13084,6 +13473,9 @@ msgstr ""
msgid "ImportProjects|Error importing repository %{project_safe_import_url} into %{project_full_path} - %{message}"
msgstr ""
+msgid "ImportProjects|Import repositories"
+msgstr ""
+
msgid "ImportProjects|Importing the project failed"
msgstr ""
@@ -13096,7 +13488,7 @@ msgstr ""
msgid "ImportProjects|Requesting your %{provider} repositories failed"
msgstr ""
-msgid "ImportProjects|Select the projects you want to import"
+msgid "ImportProjects|Select the repositories you want to import"
msgstr ""
msgid "ImportProjects|The remote data could not be imported."
@@ -13132,9 +13524,6 @@ msgstr ""
msgid "In order to enable Service Desk for your instance, you must first set up incoming email."
msgstr ""
-msgid "In order to gather accurate feature usage data, it can take 1 to 2 weeks to see your index."
-msgstr ""
-
msgid "In order to personalize your experience with GitLab%{br_tag}we would like to know a bit more about you."
msgstr ""
@@ -13165,18 +13554,30 @@ msgstr ""
msgid "IncidentManagement|Create incident"
msgstr ""
+msgid "IncidentManagement|Critical - S1"
+msgstr ""
+
msgid "IncidentManagement|Date created"
msgstr ""
msgid "IncidentManagement|Display your incidents in a dedicated view"
msgstr ""
+msgid "IncidentManagement|High - S2"
+msgstr ""
+
msgid "IncidentManagement|Incident"
msgstr ""
msgid "IncidentManagement|Incidents"
msgstr ""
+msgid "IncidentManagement|Low - S4"
+msgstr ""
+
+msgid "IncidentManagement|Medium - S3"
+msgstr ""
+
msgid "IncidentManagement|No incidents to display."
msgstr ""
@@ -13189,6 +13590,9 @@ msgstr ""
msgid "IncidentManagement|Published to status page"
msgstr ""
+msgid "IncidentManagement|Severity"
+msgstr ""
+
msgid "IncidentManagement|There are no closed incidents"
msgstr ""
@@ -13198,6 +13602,9 @@ msgstr ""
msgid "IncidentManagement|Unassigned"
msgstr ""
+msgid "IncidentManagement|Unknown"
+msgstr ""
+
msgid "IncidentManagement|Unpublished"
msgstr ""
@@ -13219,6 +13626,15 @@ msgstr ""
msgid "Incidents"
msgstr ""
+msgid "Incident|Alert details"
+msgstr ""
+
+msgid "Incident|Summary"
+msgstr ""
+
+msgid "Incident|There was an issue loading alert data. Please try again."
+msgstr ""
+
msgid "Include a Terms of Service agreement and Privacy Policy that all users must accept."
msgstr ""
@@ -13279,6 +13695,9 @@ msgstr ""
msgid "Information about additional Pages templates and how to install them can be found in our %{pages_getting_started_guide}."
msgstr ""
+msgid "Inherited"
+msgstr ""
+
msgid "Inherited:"
msgstr ""
@@ -13359,7 +13778,22 @@ msgstr ""
msgid "Instance administrators group already exists"
msgstr ""
-msgid "Instance license"
+msgid "InstanceStatistics|Groups"
+msgstr ""
+
+msgid "InstanceStatistics|Issues"
+msgstr ""
+
+msgid "InstanceStatistics|Merge Requests"
+msgstr ""
+
+msgid "InstanceStatistics|Pipelines"
+msgstr ""
+
+msgid "InstanceStatistics|Projects"
+msgstr ""
+
+msgid "InstanceStatistics|Users"
msgstr ""
msgid "Integration"
@@ -13371,6 +13805,12 @@ msgstr ""
msgid "Integrations"
msgstr ""
+msgid "Integrations|%{integration} settings saved and active."
+msgstr ""
+
+msgid "Integrations|%{integration} settings saved, but not active."
+msgstr ""
+
msgid "Integrations|All details"
msgstr ""
@@ -13380,6 +13820,12 @@ msgstr ""
msgid "Integrations|Comment settings:"
msgstr ""
+msgid "Integrations|Connection failed. Please check your settings."
+msgstr ""
+
+msgid "Integrations|Connection successful."
+msgstr ""
+
msgid "Integrations|Default settings are inherited from the group level."
msgstr ""
@@ -13395,6 +13841,15 @@ msgstr ""
msgid "Integrations|Includes commit title and branch"
msgstr ""
+msgid "Integrations|Projects using custom settings will not be impacted unless the project owner chooses to use instance-level defaults."
+msgstr ""
+
+msgid "Integrations|Save settings?"
+msgstr ""
+
+msgid "Integrations|Saving will update the default settings for all projects that are not using custom settings."
+msgstr ""
+
msgid "Integrations|Standard"
msgstr ""
@@ -13527,6 +13982,9 @@ msgstr ""
msgid "Invitation"
msgstr ""
+msgid "Invitation declined"
+msgstr ""
+
msgid "Invite"
msgstr ""
@@ -13578,6 +14036,42 @@ 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|%{linkStart}Read more%{linkEnd} about role permissions"
+msgstr ""
+
+msgid "InviteMembersModal|Access expiration date (optional)"
+msgstr ""
+
+msgid "InviteMembersModal|Cancel"
+msgstr ""
+
+msgid "InviteMembersModal|Choose a role permission"
+msgstr ""
+
+msgid "InviteMembersModal|GitLab member or Email address"
+msgstr ""
+
+msgid "InviteMembersModal|Invite"
+msgstr ""
+
+msgid "InviteMembersModal|Invite team members"
+msgstr ""
+
+msgid "InviteMembersModal|Search for members to invite"
+msgstr ""
+
+msgid "InviteMembersModal|User not invited. Feature coming soon!"
+msgstr ""
+
+msgid "InviteMembersModal|Users were succesfully added"
+msgstr ""
+
+msgid "InviteMembersModal|You're inviting members to the %{group_name} group"
+msgstr ""
+
+msgid "InviteMembers|Invite team members"
+msgstr ""
+
msgid "Invited"
msgstr ""
@@ -13632,10 +14126,13 @@ msgstr ""
msgid "Issue cannot be found."
msgstr ""
+msgid "Issue created from vulnerability %{vulnerability_link}"
+msgstr ""
+
msgid "Issue events"
msgstr ""
-msgid "Issue first depoloyed to production"
+msgid "Issue first deployed to production"
msgstr ""
msgid "Issue label"
@@ -13713,6 +14210,9 @@ msgstr ""
msgid "IssueTracker|Custom issue tracker"
msgstr ""
+msgid "IssueTracker|EWM work items tracker"
+msgstr ""
+
msgid "IssueTracker|Redmine issue tracker"
msgstr ""
@@ -13779,6 +14279,9 @@ msgstr ""
msgid "It looks like you have some draft commits in this branch."
msgstr ""
+msgid "It may be several days before you see feature usage data."
+msgstr ""
+
msgid "It must have a header row and at least two columns: the first column is the issue title and the second column is the issue description. The separator is automatically detected."
msgstr ""
@@ -14061,13 +14564,13 @@ msgstr ""
msgid "Join Zoom meeting"
msgstr ""
-msgid "Jul"
+msgid "Joined %{time_ago}"
msgstr ""
-msgid "July"
+msgid "Jul"
msgstr ""
-msgid "Jump to first unresolved thread"
+msgid "July"
msgstr ""
msgid "Jump to next unresolved thread"
@@ -14103,6 +14606,9 @@ msgstr ""
msgid "Keyboard shortcuts"
msgstr ""
+msgid "KeyboardKey|Ctrl+"
+msgstr ""
+
msgid "Keys"
msgstr ""
@@ -14151,6 +14657,9 @@ msgstr ""
msgid "LDAP Synchronization"
msgstr ""
+msgid "LDAP group settings"
+msgstr ""
+
msgid "LDAP settings"
msgstr ""
@@ -14160,6 +14669,9 @@ msgstr ""
msgid "LDAP sync in progress. This could take a few minutes. Refresh the page to see the changes."
msgstr ""
+msgid "LDAP synchronizations"
+msgstr ""
+
msgid "LFS"
msgstr ""
@@ -14240,7 +14752,16 @@ msgid_plural "Last %d days"
msgstr[0] ""
msgstr[1] ""
-msgid "Last %{days} days"
+msgid "Last 2 weeks"
+msgstr ""
+
+msgid "Last 30 days"
+msgstr ""
+
+msgid "Last 60 days"
+msgstr ""
+
+msgid "Last 90 days"
msgstr ""
msgid "Last Accessed On"
@@ -14318,6 +14839,9 @@ msgstr ""
msgid "Last used on:"
msgstr ""
+msgid "Last week"
+msgstr ""
+
msgid "LastCommit|authored"
msgstr ""
@@ -14333,6 +14857,9 @@ msgstr ""
msgid "Latest pipeline for the most recent commit on this branch"
msgstr ""
+msgid "Launch a ready-to-code development environment for your project."
+msgstr ""
+
msgid "Lead"
msgstr ""
@@ -14713,6 +15240,9 @@ msgstr ""
msgid "List of all merge commits"
msgstr ""
+msgid "List options"
+msgstr ""
+
msgid "List settings"
msgstr ""
@@ -14725,9 +15255,6 @@ msgstr ""
msgid "List your Bitbucket Server repositories"
msgstr ""
-msgid "Lists"
-msgstr ""
-
msgid "Live preview"
msgstr ""
@@ -14974,6 +15501,12 @@ msgstr ""
msgid "Mark as done"
msgstr ""
+msgid "Mark as draft"
+msgstr ""
+
+msgid "Mark as ready"
+msgstr ""
+
msgid "Mark as resolved"
msgstr ""
@@ -14995,6 +15528,24 @@ msgstr ""
msgid "Markdown is supported"
msgstr ""
+msgid "MarkdownEditor|Add a link (%{modifierKey}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add a link (%{modifier_key}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifierKey}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifier_key}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifierKey}I)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifier_key}I)"
+msgstr ""
+
msgid "Marked For Deletion At - %{deletion_time}"
msgstr ""
@@ -15079,7 +15630,25 @@ msgstr ""
msgid "Max access level"
msgstr ""
-msgid "Max seats used"
+msgid "Max role"
+msgstr ""
+
+msgid "Max size 15 MB"
+msgstr ""
+
+msgid "Maximum Conan package file size in bytes"
+msgstr ""
+
+msgid "Maximum Maven package file size in bytes"
+msgstr ""
+
+msgid "Maximum NPM package file size in bytes"
+msgstr ""
+
+msgid "Maximum NuGet package file size in bytes"
+msgstr ""
+
+msgid "Maximum PyPI package file size in bytes"
msgstr ""
msgid "Maximum Users:"
@@ -15211,6 +15780,18 @@ msgstr ""
msgid "Members with access to %{strong_start}%{group_name}%{strong_end}"
msgstr ""
+msgid "Members|%{time} by %{user}"
+msgstr ""
+
+msgid "Members|Expired"
+msgstr ""
+
+msgid "Members|No expiration set"
+msgstr ""
+
+msgid "Members|in %{time}"
+msgstr ""
+
msgid "Memory Usage"
msgstr ""
@@ -15397,9 +15978,6 @@ msgstr ""
msgid "MergeRequests|Thread will be unresolved"
msgstr ""
-msgid "MergeRequests|Toggle comments for this file"
-msgstr ""
-
msgid "MergeRequests|View file @ %{commitId}"
msgstr ""
@@ -15460,6 +16038,9 @@ msgstr ""
msgid "Merging immediately isn't recommended as it may negatively impact the existing merge train. Read the %{docsLinkStart}documentation%{docsLinkEnd} for more information."
msgstr ""
+msgid "Message"
+msgstr ""
+
msgid "Messages"
msgstr ""
@@ -15845,18 +16426,12 @@ msgid_plural "Milestones"
msgstr[0] ""
msgstr[1] ""
-msgid "Milestone does not support burnup charts"
-msgstr ""
-
msgid "Milestone lists not available with your current license"
msgstr ""
msgid "Milestone lists show all issues from the selected milestone."
msgstr ""
-msgid "Milestone must have a start and due date"
-msgstr ""
-
msgid "MilestoneSidebar|Closed:"
msgstr ""
@@ -16223,6 +16798,9 @@ msgstr ""
msgid "Namespace"
msgstr ""
+msgid "Namespace ID:"
+msgstr ""
+
msgid "Namespace is empty"
msgstr ""
@@ -16307,6 +16885,9 @@ msgstr ""
msgid "NetworkPolicies|Allow all outbound traffic from %{selector} to %{ruleSelector} on %{ports}"
msgstr ""
+msgid "NetworkPolicies|Are you sure you want to delete this policy? This action cannot be undone."
+msgstr ""
+
msgid "NetworkPolicies|Choose whether to enforce this policy."
msgstr ""
@@ -16316,12 +16897,21 @@ msgstr ""
msgid "NetworkPolicies|Define this policy's location, conditions and actions."
msgstr ""
+msgid "NetworkPolicies|Delete policy"
+msgstr ""
+
+msgid "NetworkPolicies|Delete policy: %{policy}"
+msgstr ""
+
msgid "NetworkPolicies|Deny all traffic"
msgstr ""
msgid "NetworkPolicies|Description"
msgstr ""
+msgid "NetworkPolicies|Edit policy"
+msgstr ""
+
msgid "NetworkPolicies|Editor mode"
msgstr ""
@@ -16349,6 +16939,9 @@ msgstr ""
msgid "NetworkPolicies|Name"
msgstr ""
+msgid "NetworkPolicies|Namespace"
+msgstr ""
+
msgid "NetworkPolicies|Network Policy"
msgstr ""
@@ -16400,6 +16993,9 @@ msgstr ""
msgid "NetworkPolicies|Rules"
msgstr ""
+msgid "NetworkPolicies|Save changes"
+msgstr ""
+
msgid "NetworkPolicies|Something went wrong, failed to update policy"
msgstr ""
@@ -16412,6 +17008,9 @@ msgstr ""
msgid "NetworkPolicies|Traffic that does not match any rule will be blocked."
msgstr ""
+msgid "NetworkPolicies|Unable to parse policy"
+msgstr ""
+
msgid "NetworkPolicies|YAML editor"
msgstr ""
@@ -16525,6 +17124,9 @@ msgstr ""
msgid "New Snippet"
msgstr ""
+msgid "New Test Case"
+msgstr ""
+
msgid "New User"
msgstr ""
@@ -16624,6 +17226,9 @@ msgstr ""
msgid "New tag"
msgstr ""
+msgid "New test case"
+msgstr ""
+
msgid "New users set to external"
msgstr ""
@@ -16696,7 +17301,7 @@ msgstr ""
msgid "No changes"
msgstr ""
-msgid "No changes between %{ref_start}%{source_branch}%{ref_end} and %{ref_start}%{target_branch}%{ref_end}"
+msgid "No changes between %{sourceBranch} and %{targetBranch}"
msgstr ""
msgid "No child epics match applied filters"
@@ -16711,6 +17316,9 @@ msgstr ""
msgid "No containers available"
msgstr ""
+msgid "No content to show"
+msgstr ""
+
msgid "No contributions"
msgstr ""
@@ -16786,9 +17394,6 @@ msgstr ""
msgid "No license. All rights reserved"
msgstr ""
-msgid "No licenses found."
-msgstr ""
-
msgid "No matches found"
msgstr ""
@@ -16801,6 +17406,9 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No members found"
+msgstr ""
+
msgid "No merge requests found"
msgstr ""
@@ -16822,6 +17430,9 @@ msgstr ""
msgid "No parent group"
msgstr ""
+msgid "No plan"
+msgstr ""
+
msgid "No pods available"
msgstr ""
@@ -16918,6 +17529,12 @@ msgstr ""
msgid "Not Implemented"
msgstr ""
+msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+msgstr ""
+
+msgid "Not all browsers support WebAuthn. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even from an unsupported browser."
+msgstr ""
+
msgid "Not all data has been processed yet, the accuracy of the chart for the selected timeframe is limited."
msgstr ""
@@ -17014,6 +17631,9 @@ msgstr ""
msgid "Notification settings saved"
msgstr ""
+msgid "NotificationEvent|Change reviewer merge request"
+msgstr ""
+
msgid "NotificationEvent|Close issue"
msgstr ""
@@ -17176,10 +17796,7 @@ msgstr ""
msgid "On track"
msgstr ""
-msgid "OnDemandScans|Attached branch"
-msgstr ""
-
-msgid "OnDemandScans|Attached branch is where the scan job runs."
+msgid "OnDemandScans|Could not fetch scanner profiles. Please refresh the page, or try again later."
msgstr ""
msgid "OnDemandScans|Could not fetch site profiles. Please refresh the page, or try again later."
@@ -17188,6 +17805,9 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
+msgid "OnDemandScans|Create a new scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Create a new site profile"
msgstr ""
@@ -17200,6 +17820,9 @@ msgstr ""
msgid "OnDemandScans|New on-demand DAST scan"
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 ""
@@ -17209,16 +17832,10 @@ msgstr ""
msgid "OnDemandScans|On-demand scans run outside the DevOps cycle and find vulnerabilities in your projects. %{learnMoreLinkStart}Learn more%{learnMoreLinkEnd}"
msgstr ""
-msgid "OnDemandScans|Only a passive scan can be performed on demand."
-msgstr ""
-
-msgid "OnDemandScans|Passive"
-msgstr ""
-
msgid "OnDemandScans|Run scan"
msgstr ""
-msgid "OnDemandScans|Scan mode"
+msgid "OnDemandScans|Scanner profile"
msgstr ""
msgid "OnDemandScans|Scanner settings"
@@ -17230,9 +17847,15 @@ msgstr ""
msgid "OnDemandScans|Select one of the existing profiles"
msgstr ""
+msgid "OnDemandScans|Site profile"
+msgstr ""
+
msgid "OnDemandScans|Site profiles"
msgstr ""
+msgid "OnDemandScans|Use existing scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Use existing site profile"
msgstr ""
@@ -17331,9 +17954,6 @@ msgstr ""
msgid "Open Selection"
msgstr ""
-msgid "Open Web IDE"
-msgstr ""
-
msgid "Open comment type dropdown"
msgstr ""
@@ -17439,6 +18059,9 @@ msgstr ""
msgid "Origin"
msgstr ""
+msgid "Orphaned member"
+msgstr ""
+
msgid "Other Labels"
msgstr ""
@@ -17454,6 +18077,9 @@ msgstr ""
msgid "Other visibility settings have been disabled by the administrator."
msgstr ""
+msgid "Our documentation includes an example DevOps Score report."
+msgstr ""
+
msgid "Out-of-compliance with this project's policies and should be removed"
msgstr ""
@@ -17478,6 +18104,9 @@ msgstr ""
msgid "Overwrite diverged branches"
msgstr ""
+msgid "Owned by %{image_tag}"
+msgstr ""
+
msgid "Owned by anyone"
msgstr ""
@@ -17499,6 +18128,9 @@ msgstr ""
msgid "Package deleted successfully"
msgstr ""
+msgid "Package file size limits"
+msgstr ""
+
msgid "Package recipe already exists"
msgstr ""
@@ -17514,9 +18146,6 @@ msgstr ""
msgid "Package type must be PyPi"
msgstr ""
-msgid "Package was removed"
-msgstr ""
-
msgid "PackageRegistry|%{name} version %{version} was created %{datetime}"
msgstr ""
@@ -17658,12 +18287,18 @@ msgstr ""
msgid "PackageRegistry|NuGet Command"
msgstr ""
+msgid "PackageRegistry|Package Registry"
+msgstr ""
+
msgid "PackageRegistry|Pip Command"
msgstr ""
msgid "PackageRegistry|Pipeline %{link} triggered %{datetime} by %{author}"
msgstr ""
+msgid "PackageRegistry|Publish and share packages for a variety of common package managers. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "PackageRegistry|Published to the %{project} Package Registry %{datetime}"
msgstr ""
@@ -17763,6 +18398,9 @@ msgstr ""
msgid "Page not found"
msgstr ""
+msgid "Page settings"
+msgstr ""
+
msgid "Page was successfully deleted"
msgstr ""
@@ -17904,7 +18542,7 @@ msgstr ""
msgid "Paste issue link"
msgstr ""
-msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Don't use your private SSH key."
+msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Do not paste your private SSH key, as that can compromise your identity."
msgstr ""
msgid "Patch to apply"
@@ -17931,6 +18569,9 @@ msgstr ""
msgid "Pending"
msgstr ""
+msgid "Pending comments"
+msgstr ""
+
msgid "People without permission will never get a notification and won't be able to comment."
msgstr ""
@@ -18129,6 +18770,9 @@ msgstr ""
msgid "Pipelines|Build with confidence"
msgstr ""
+msgid "Pipelines|By revoking a trigger you will break any processes making use of it. Are you sure?"
+msgstr ""
+
msgid "Pipelines|CI Lint"
msgstr ""
@@ -18141,6 +18785,15 @@ msgstr ""
msgid "Pipelines|Continuous Integration can help catch bugs by running your tests automatically, while Continuous Deployment can help you deliver code to your product environment."
msgstr ""
+msgid "Pipelines|Copy trigger token"
+msgstr ""
+
+msgid "Pipelines|Description"
+msgstr ""
+
+msgid "Pipelines|Edit"
+msgstr ""
+
msgid "Pipelines|Get started with Pipelines"
msgstr ""
@@ -18156,15 +18809,27 @@ msgstr ""
msgid "Pipelines|It is recommended the code is reviewed thoroughly before running this pipeline with the parent project's CI resource."
msgstr ""
+msgid "Pipelines|Last Used"
+msgstr ""
+
msgid "Pipelines|Loading Pipelines"
msgstr ""
msgid "Pipelines|More Information"
msgstr ""
+msgid "Pipelines|No triggers have been created yet. Add one using the form above."
+msgstr ""
+
+msgid "Pipelines|Owner"
+msgstr ""
+
msgid "Pipelines|Project cache successfully reset."
msgstr ""
+msgid "Pipelines|Revoke"
+msgstr ""
+
msgid "Pipelines|Run Pipeline"
msgstr ""
@@ -18189,6 +18854,15 @@ msgstr ""
msgid "Pipelines|This project is not currently set up to run pipelines."
msgstr ""
+msgid "Pipelines|Token"
+msgstr ""
+
+msgid "Pipelines|Trigger user has insufficient permissions to project"
+msgstr ""
+
+msgid "Pipelines|invalid"
+msgstr ""
+
msgid "Pipelines|parent"
msgstr ""
@@ -18447,10 +19121,10 @@ msgstr ""
msgid "Please provide attributes to update"
msgstr ""
-msgid "Please refer to %{docs_url}"
+msgid "Please reach out if you have any questions and we'll be happy to assist."
msgstr ""
-msgid "Please retype the email address."
+msgid "Please refer to %{docs_url}"
msgstr ""
msgid "Please select"
@@ -18480,6 +19154,9 @@ msgstr ""
msgid "Please set a new password before proceeding."
msgstr ""
+msgid "Please share your feedback about %{featureName} %{linkStart}in this issue%{linkEnd} to help us improve the experience."
+msgstr ""
+
msgid "Please solve the reCAPTCHA"
msgstr ""
@@ -18783,6 +19460,9 @@ msgstr ""
msgid "Profiles| You are going to change the username %{currentUsernameBold} to %{newUsernameBold}. Profile and projects will be redirected to the %{newUsername} namespace but this redirect will expire once the %{currentUsername} namespace is registered by another user or group. Please update your Git repository remotes as soon as possible."
msgstr ""
+msgid "Profiles|%{provider} Active"
+msgstr ""
+
msgid "Profiles|@username"
msgstr ""
@@ -18834,7 +19514,7 @@ msgstr ""
msgid "Profiles|Commit email"
msgstr ""
-msgid "Profiles|Connect"
+msgid "Profiles|Connect %{provider}"
msgstr ""
msgid "Profiles|Connected Accounts"
@@ -18858,6 +19538,9 @@ msgstr ""
msgid "Profiles|Disconnect"
msgstr ""
+msgid "Profiles|Disconnect %{provider}"
+msgstr ""
+
msgid "Profiles|Do not show on profile"
msgstr ""
@@ -18882,7 +19565,7 @@ msgstr ""
msgid "Profiles|Full name"
msgstr ""
-msgid "Profiles|Give your individual key a title. This will be publically visible."
+msgid "Profiles|Give your individual key a title."
msgstr ""
msgid "Profiles|Include private contributions on my profile"
@@ -18972,7 +19655,7 @@ msgstr ""
msgid "Profiles|The maximum file size allowed is 200KB."
msgstr ""
-msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it?"
+msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it? It will be publicly visible."
msgstr ""
msgid "Profiles|This email will be displayed on your public profile"
@@ -19047,6 +19730,9 @@ msgstr ""
msgid "Profiles|You don't have access to delete this user."
msgstr ""
+msgid "Profiles|You must transfer ownership or delete groups you are an owner of before you can delete your account"
+msgstr ""
+
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
@@ -19635,6 +20321,9 @@ msgstr ""
msgid "ProjectTemplates|GitLab Cluster Management"
msgstr ""
+msgid "ProjectTemplates|Gitpod/Spring Petclinic"
+msgstr ""
+
msgid "ProjectTemplates|Go Micro"
msgstr ""
@@ -20244,6 +20933,9 @@ msgstr ""
msgid "Publish to status page"
msgstr ""
+msgid "Published"
+msgstr ""
+
msgid "Published on status page"
msgstr ""
@@ -20361,9 +21053,15 @@ msgstr ""
msgid "Quick range"
msgstr ""
+msgid "Quickly and easily edit multiple files in your project."
+msgstr ""
+
msgid "README"
msgstr ""
+msgid "Rails"
+msgstr ""
+
msgid "Rake Tasks Help"
msgstr ""
@@ -20483,10 +21181,13 @@ msgstr ""
msgid "Register Two-Factor Authenticator"
msgstr ""
-msgid "Register U2F device"
+msgid "Register Universal Two-Factor (U2F) Device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register WebAuthn Device"
+msgstr ""
+
+msgid "Register device"
msgstr ""
msgid "Register for GitLab"
@@ -20498,9 +21199,6 @@ msgstr ""
msgid "Register with two-factor app"
msgstr ""
-msgid "Registration"
-msgstr ""
-
msgid "Registration|Checkout"
msgstr ""
@@ -20617,9 +21315,6 @@ msgstr ""
msgid "Release|Something went wrong while saving the release details"
msgstr ""
-msgid "Remediated: needs review"
-msgstr ""
-
msgid "Remediations"
msgstr ""
@@ -20725,6 +21420,9 @@ msgstr ""
msgid "Remove priority"
msgstr ""
+msgid "Remove report"
+msgstr ""
+
msgid "Remove secondary node"
msgstr ""
@@ -20737,6 +21435,12 @@ msgstr ""
msgid "Remove time estimate"
msgstr ""
+msgid "Remove user & report"
+msgstr ""
+
+msgid "Remove user from group"
+msgstr ""
+
msgid "Removed"
msgstr ""
@@ -20818,9 +21522,6 @@ msgstr ""
msgid "Removes time estimate."
msgstr ""
-msgid "Removing license…"
-msgstr ""
-
msgid "Removing this group also removes all child projects, including archived projects, and their resources."
msgstr ""
@@ -20905,6 +21606,9 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
+msgid "Reported by %{reporter}"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -20991,6 +21695,27 @@ msgstr ""
msgid "Repositories"
msgstr ""
+msgid "Repositories Analytics"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download Historic Test Coverage Data"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download historic test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Historic Test Coverage Data is available in raw format (.csv) for further analysis."
+msgstr ""
+
+msgid "RepositoriesAnalytics|Test Code Coverage"
+msgstr ""
+
+msgid "RepositoriesAnalytics|There was an error fetching the projects."
+msgstr ""
+
msgid "Repository"
msgstr ""
@@ -21069,9 +21794,15 @@ msgstr ""
msgid "Request parameter %{param} is missing."
msgstr ""
+msgid "Request review from"
+msgstr ""
+
msgid "Request to link SAML account must be authorized"
msgstr ""
+msgid "Requested"
+msgstr ""
+
msgid "Requested %{time_ago}"
msgstr ""
@@ -21090,6 +21821,9 @@ msgstr ""
msgid "Requests to these domain(s)/address(es) on the local network will be allowed when local requests from hooks and services are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 or 127.0.0.0/28 are supported. Domain wildcards are not supported currently. Use comma, semicolon, or newline to separate multiple entries. The allowlist can hold a maximum of 1000 entries. Domains should use IDNA encoding. Ex: example.com, 192.168.1.1, 127.0.0.0/28, xn--itlab-j1a.com."
msgstr ""
+msgid "Require admin approval for new sign-ups"
+msgstr ""
+
msgid "Require all users in this group to setup Two-factor authentication"
msgstr ""
@@ -21217,9 +21951,6 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
-msgid "Resolved by %{resolvedByName}"
-msgstr ""
-
msgid "Resolves IP addresses once and uses them to submit requests"
msgstr ""
@@ -21339,6 +22070,14 @@ msgstr ""
msgid "ReviewApp|Enable Review App"
msgstr ""
+msgid "Reviewer"
+msgid_plural "%d Reviewers"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Reviewer(s)"
+msgstr ""
+
msgid "Reviewing"
msgstr ""
@@ -21378,6 +22117,9 @@ msgstr ""
msgid "Rook"
msgstr ""
+msgid "Ruby"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -21456,6 +22198,63 @@ msgstr ""
msgid "Runners page."
msgstr ""
+msgid "Runners|Active"
+msgstr ""
+
+msgid "Runners|Architecture"
+msgstr ""
+
+msgid "Runners|Can run untagged jobs"
+msgstr ""
+
+msgid "Runners|Description"
+msgstr ""
+
+msgid "Runners|Group"
+msgstr ""
+
+msgid "Runners|IP Address"
+msgstr ""
+
+msgid "Runners|Last contact"
+msgstr ""
+
+msgid "Runners|Locked to this project"
+msgstr ""
+
+msgid "Runners|Maximum job timeout"
+msgstr ""
+
+msgid "Runners|Name"
+msgstr ""
+
+msgid "Runners|Platform"
+msgstr ""
+
+msgid "Runners|Property Name"
+msgstr ""
+
+msgid "Runners|Protected"
+msgstr ""
+
+msgid "Runners|Revision"
+msgstr ""
+
+msgid "Runners|Shared"
+msgstr ""
+
+msgid "Runners|Specific"
+msgstr ""
+
+msgid "Runners|Tags"
+msgstr ""
+
+msgid "Runners|Value"
+msgstr ""
+
+msgid "Runners|Version"
+msgstr ""
+
msgid "Runners|You have used %{quotaUsed} out of %{quotaLimit} of your shared Runners pipeline minutes."
msgstr ""
@@ -21468,6 +22267,9 @@ msgstr ""
msgid "Runs a number of housekeeping tasks within the current repository, such as compressing file revisions and removing unreachable objects."
msgstr ""
+msgid "SAML"
+msgstr ""
+
msgid "SAML SSO"
msgstr ""
@@ -21519,6 +22321,9 @@ msgstr ""
msgid "Save"
msgstr ""
+msgid "Save %{name} size limits"
+msgstr ""
+
msgid "Save Changes"
msgstr ""
@@ -21549,9 +22354,6 @@ msgstr ""
msgid "Save space and find tags in the Container Registry more easily. Enable the cleanup policy to remove stale tags and keep only the ones you need."
msgstr ""
-msgid "Save template"
-msgstr ""
-
msgid "Save variables"
msgstr ""
@@ -21594,9 +22396,6 @@ msgstr ""
msgid "Scope"
msgstr ""
-msgid "Scope not supported with disabled 'users_search' feature!"
-msgstr ""
-
msgid "Scoped issue boards"
msgstr ""
@@ -21723,9 +22522,6 @@ msgstr ""
msgid "Search requirements"
msgstr ""
-msgid "Search results…"
-msgstr ""
-
msgid "Search users"
msgstr ""
@@ -21798,6 +22594,11 @@ msgid_plural "SearchResults|commits"
msgstr[0] ""
msgstr[1] ""
+msgid "SearchResults|epic"
+msgid_plural "SearchResults|epics"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "SearchResults|issue"
msgid_plural "SearchResults|issues"
msgstr[0] ""
@@ -21842,10 +22643,10 @@ msgstr ""
msgid "Seat Link is disabled, and cannot be configured through this form."
msgstr ""
-msgid "Seats currently in use"
+msgid "Seats usage data as of %{last_enqueue_time}"
msgstr ""
-msgid "Seats in license"
+msgid "Seats usage data is updated every day at 12:00pm UTC"
msgstr ""
msgid "Secondary"
@@ -21899,6 +22700,9 @@ msgstr ""
msgid "SecurityConfiguration|Available for on-demand DAST"
msgstr ""
+msgid "SecurityConfiguration|By default, all analyzers are applied in order to cover all languages across your project, and only run if the language is detected in the Merge Request."
+msgstr ""
+
msgid "SecurityConfiguration|Configure"
msgstr ""
@@ -21929,16 +22733,19 @@ msgstr ""
msgid "SecurityConfiguration|Manage"
msgstr ""
+msgid "SecurityConfiguration|More information"
+msgstr ""
+
msgid "SecurityConfiguration|Not enabled"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|Security Control"
+msgid "SecurityConfiguration|SAST Configuration"
msgstr ""
-msgid "SecurityConfiguration|See documentation"
+msgid "SecurityConfiguration|Security Control"
msgstr ""
msgid "SecurityConfiguration|Status"
@@ -21950,6 +22757,9 @@ msgstr ""
msgid "SecurityConfiguration|Using custom settings. You won't receive automatic updates on this variable. %{anchorStart}Restore to default%{anchorEnd}"
msgstr ""
+msgid "SecurityConfiguration|View history"
+msgstr ""
+
msgid "SecurityConfiguration|You can quickly enable all security scanning tools by enabling %{linkStart}Auto DevOps%{linkEnd}."
msgstr ""
@@ -22028,9 +22838,6 @@ msgstr ""
msgid "SecurityReports|Learn more about setting up your dashboard"
msgstr ""
-msgid "SecurityReports|Load more vulnerabilities"
-msgstr ""
-
msgid "SecurityReports|Monitor vulnerabilities in your code"
msgstr ""
@@ -22310,7 +23117,7 @@ msgstr ""
msgid "Select status"
msgstr ""
-msgid "Select strategy activation method"
+msgid "Select strategy activation method."
msgstr ""
msgid "Select subscription"
@@ -22325,7 +23132,7 @@ msgstr ""
msgid "Select the custom project template source group."
msgstr ""
-msgid "Select timeframe"
+msgid "Select the environment scope for this feature flag."
msgstr ""
msgid "Select timezone"
@@ -22574,6 +23381,9 @@ msgstr ""
msgid "Set iteration"
msgstr ""
+msgid "Set limit to 0 to allow any file size."
+msgstr ""
+
msgid "Set max session time for web terminal."
msgstr ""
@@ -22652,10 +23462,13 @@ msgstr ""
msgid "Set up a %{type} Runner manually"
msgstr ""
+msgid "Set up a hardware device as a second factor to sign in."
+msgstr ""
+
msgid "Set up assertions/attributes/claims (email, first_name, last_name) and NameID according to %{docsLinkStart}the documentation %{icon}%{docsLinkEnd}"
msgstr ""
-msgid "Set up new U2F device"
+msgid "Set up new device"
msgstr ""
msgid "Set up new password"
@@ -22724,6 +23537,9 @@ msgstr ""
msgid "Sets weight to %{weight}."
msgstr ""
+msgid "Setting this to 0 means using the system default timeout value."
+msgstr ""
+
msgid "Settings"
msgstr ""
@@ -22739,6 +23555,15 @@ msgstr ""
msgid "Severity"
msgstr ""
+msgid "SeverityWidget|Severity"
+msgstr ""
+
+msgid "SeverityWidget|Severity: %{severity}"
+msgstr ""
+
+msgid "SeverityWidget|There was an error while updating severity."
+msgstr ""
+
msgid "Shards (%{shards})"
msgstr ""
@@ -22784,6 +23609,9 @@ msgstr ""
msgid "Show all requirements."
msgstr ""
+msgid "Show all test cases."
+msgstr ""
+
msgid "Show archived projects"
msgstr ""
@@ -22796,6 +23624,9 @@ msgstr ""
msgid "Show comments"
msgstr ""
+msgid "Show comments on this file"
+msgstr ""
+
msgid "Show comments only"
msgstr ""
@@ -22841,6 +23672,12 @@ msgstr ""
msgid "Show parent subgroups"
msgstr ""
+msgid "Show the Closed list"
+msgstr ""
+
+msgid "Show the Open list"
+msgstr ""
+
msgid "Show whitespace changes"
msgstr ""
@@ -22884,9 +23721,6 @@ msgstr ""
msgid "Sidebar|Assign health status"
msgstr ""
-msgid "Sidebar|Change weight"
-msgstr ""
-
msgid "Sidebar|Health status"
msgstr ""
@@ -23070,6 +23904,9 @@ msgstr ""
msgid "Snippets|Add another file %{num}/%{total}"
msgstr ""
+msgid "Snippets|Authored %{time_ago} by %{author}"
+msgstr ""
+
msgid "Snippets|Delete file"
msgstr ""
@@ -23097,6 +23934,9 @@ msgstr ""
msgid "Solution"
msgstr ""
+msgid "Some changes are not shown"
+msgstr ""
+
msgid "Some child epics may be hidden due to applied filters"
msgstr ""
@@ -23463,6 +24303,12 @@ msgstr ""
msgid "Source (branch or tag)"
msgstr ""
+msgid "Source Branch"
+msgstr ""
+
+msgid "Source branch: %{source_branch_open}%{source_branch}%{source_branch_close}"
+msgstr ""
+
msgid "Source code"
msgstr ""
@@ -23628,9 +24474,6 @@ msgstr ""
msgid "Start and due date"
msgstr ""
-msgid "Start by choosing a group to see how your team is spending time. You can then drill down to the project level."
-msgstr ""
-
msgid "Start by choosing a group to start exploring the merge requests in that group. You can then proceed to filter by projects, labels, milestones and authors."
msgstr ""
@@ -23712,18 +24555,27 @@ msgstr ""
msgid "StaticSiteEditor|3. Assign a person to review and accept the merge request."
msgstr ""
+msgid "StaticSiteEditor|A link to view the merge request will appear once ready."
+msgstr ""
+
msgid "StaticSiteEditor|An error occurred while submitting your changes."
msgstr ""
msgid "StaticSiteEditor|Branch could not be created."
msgstr ""
+msgid "StaticSiteEditor|Copy update"
+msgstr ""
+
msgid "StaticSiteEditor|Could not commit the content changes."
msgstr ""
msgid "StaticSiteEditor|Could not create merge request."
msgstr ""
+msgid "StaticSiteEditor|Creating your merge request"
+msgstr ""
+
msgid "StaticSiteEditor|Incompatible file content"
msgstr ""
@@ -23745,6 +24597,9 @@ msgstr ""
msgid "StaticSiteEditor|View documentation"
msgstr ""
+msgid "StaticSiteEditor|You can set an assignee to get your changes reviewed and deployed once your merge request is created."
+msgstr ""
+
msgid "StaticSiteEditor|Your merge request has been created"
msgstr ""
@@ -23874,15 +24729,15 @@ msgstr ""
msgid "Submit %{humanized_resource_name}"
msgstr ""
-msgid "Submit Changes"
-msgstr ""
-
msgid "Submit a review"
msgstr ""
msgid "Submit as spam"
msgstr ""
+msgid "Submit changes"
+msgstr ""
+
msgid "Submit feedback"
msgstr ""
@@ -24036,6 +24891,9 @@ msgstr ""
msgid "Successfully deleted U2F device."
msgstr ""
+msgid "Successfully deleted WebAuthn device."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -24354,9 +25212,6 @@ msgstr ""
msgid "Template to append to all Service Desk issues"
msgstr ""
-msgid "Template was successfully saved."
-msgstr ""
-
msgid "Templates"
msgstr ""
@@ -24435,10 +25290,28 @@ msgid_plural "Test coverage: %d hits"
msgstr[0] ""
msgstr[1] ""
-msgid "Test failed."
+msgid "Test settings"
msgstr ""
-msgid "Test settings and save changes"
+msgid "TestCases|New Test Case"
+msgstr ""
+
+msgid "TestCases|New test case"
+msgstr ""
+
+msgid "TestCases|Search test cases"
+msgstr ""
+
+msgid "TestCases|Something went wrong while creating a test case."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching count of test cases."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching test cases list."
+msgstr ""
+
+msgid "TestCases|Submit test case"
msgstr ""
msgid "TestHooks|Ensure one of your projects has merge requests."
@@ -24504,6 +25377,9 @@ msgstr ""
msgid "Thank you for signing up for your free trial! You will get additional instructions in your inbox shortly."
msgstr ""
+msgid "Thank you for your business."
+msgstr ""
+
msgid "Thank you for your feedback!"
msgstr ""
@@ -24563,9 +25439,6 @@ msgstr ""
msgid "The URL to use for connecting to Elasticsearch. Use a comma-separated list to support clustering (e.g., \"http://localhost:9200, http://localhost:9201\")."
msgstr ""
-msgid "The Web IDE offers advanced syntax highlighting capabilities and more."
-msgstr ""
-
msgid "The X509 Certificate to use when mutual TLS is required to communicate with the external authorization service. If left blank, the server certificate is still validated when accessing over HTTPS."
msgstr ""
@@ -24676,6 +25549,9 @@ msgstr ""
msgid "The form contains the following error:"
msgstr ""
+msgid "The form contains the following warning:"
+msgstr ""
+
msgid "The global settings require you to enable Two-Factor Authentication for your account."
msgstr ""
@@ -24790,9 +25666,6 @@ msgstr ""
msgid "The private key to use when a client certificate is provided. This value is encrypted at rest."
msgstr ""
-msgid "The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The project can be accessed by any logged in user."
msgstr ""
@@ -24829,7 +25702,7 @@ msgstr ""
msgid "The remote repository is being updated..."
msgstr ""
-msgid "The repository can be commited to, and issues, comments and other entities can be created."
+msgid "The repository can be committed to, and issues, comments and other entities can be created."
msgstr ""
msgid "The repository for this project does not exist."
@@ -24883,9 +25756,6 @@ msgstr ""
msgid "The time taken by each data entry gathered by that stage."
msgstr ""
-msgid "The total stage shows the time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The update action will time out after %{number_of_minutes} minutes. For big repositories, use a clone/push combination."
msgstr ""
@@ -24949,6 +25819,9 @@ msgstr ""
msgid "There are no archived requirements"
msgstr ""
+msgid "There are no archived test cases"
+msgstr ""
+
msgid "There are no changes"
msgstr ""
@@ -24988,6 +25861,9 @@ msgstr ""
msgid "There are no open requirements"
msgstr ""
+msgid "There are no open test cases"
+msgstr ""
+
msgid "There are no packages yet"
msgstr ""
@@ -25000,6 +25876,9 @@ msgstr ""
msgid "There is a limit of %{ci_project_subscriptions_limit} subscriptions from or to a project."
msgstr ""
+msgid "There is already a To-Do for this design."
+msgstr ""
+
msgid "There is already a repository with that name on disk"
msgstr ""
@@ -25018,6 +25897,9 @@ msgstr ""
msgid "There was a problem communicating with your device."
msgstr ""
+msgid "There was a problem fetching branches."
+msgstr ""
+
msgid "There was a problem fetching groups."
msgstr ""
@@ -25246,9 +26128,15 @@ msgstr ""
msgid "This action can lead to data loss. To prevent accidental actions we ask you to confirm your intention."
msgstr ""
+msgid "This action cannot be undone, and will permanently delete the %{key} SSH key"
+msgstr ""
+
msgid "This action cannot be undone. You will lose the project's repository and all content: issues, merge requests, etc."
msgstr ""
+msgid "This action has been performed too many times. Try again later."
+msgstr ""
+
msgid "This action will %{strongOpen}permanently delete%{strongClose} %{codeOpen}%{project}%{codeClose} %{strongOpen}immediately%{strongClose}, including its repositories and all content: issues, merge requests, etc."
msgstr ""
@@ -25276,9 +26164,6 @@ msgstr ""
msgid "This board's scope is reduced"
msgstr ""
-msgid "This branch has changed since you started editing. Would you like to create a new branch?"
-msgstr ""
-
msgid "This chart could not be displayed"
msgstr ""
@@ -25405,15 +26290,9 @@ msgstr ""
msgid "This is a security log of important events involving your account."
msgstr ""
-msgid "This is the author's first Merge Request to this project."
-msgstr ""
-
msgid "This is the highest peak of users on your installation since the license started."
msgstr ""
-msgid "This is the maximum number of users that have existed at the same time since the license started. This is the minimum number of seats you will need to buy when you renew your license."
-msgstr ""
-
msgid "This is the number of currently active users on your installation, and this is the minimum number you need to purchase when you renew your license."
msgstr ""
@@ -25645,6 +26524,15 @@ msgstr ""
msgid "This user has no identities"
msgstr ""
+msgid "This user has previously committed to the %{name} project."
+msgstr ""
+
+msgid "This user has the %{access} role in the %{name} project."
+msgstr ""
+
+msgid "This user is the author of this %{noteable}."
+msgstr ""
+
msgid "This user will be the author of all events in the activity feed that are the result of an update, like new branches being created or new commits being pushed to existing branches."
msgstr ""
@@ -25675,6 +26563,9 @@ msgstr ""
msgid "Threat Monitoring"
msgstr ""
+msgid "ThreatMonitoring|All Environments"
+msgstr ""
+
msgid "ThreatMonitoring|Anomalous Requests"
msgstr ""
@@ -25702,9 +26593,6 @@ msgstr ""
msgid "ThreatMonitoring|Operations Per Second"
msgstr ""
-msgid "ThreatMonitoring|Overview"
-msgstr ""
-
msgid "ThreatMonitoring|Packet Activity"
msgstr ""
@@ -25723,6 +26611,9 @@ msgstr ""
msgid "ThreatMonitoring|Something went wrong, unable to fetch statistics"
msgstr ""
+msgid "ThreatMonitoring|Statistics"
+msgstr ""
+
msgid "ThreatMonitoring|The firewall is not installed or has been disabled. To view this data, ensure the web application firewall is installed and enabled for your cluster."
msgstr ""
@@ -26114,6 +27005,9 @@ msgstr ""
msgid "To update Snippets with multiple files, you must use the `files` parameter"
msgstr ""
+msgid "To use Gitpod you must first enable the feature in the integrations section of your %{user_prefs}."
+msgstr ""
+
msgid "To view all %{scannedResourcesCount} scanned URLs, please download the CSV file"
msgstr ""
@@ -26147,9 +27041,6 @@ msgstr ""
msgid "Toggle Sidebar"
msgstr ""
-msgid "Toggle all threads"
-msgstr ""
-
msgid "Toggle backtrace"
msgstr ""
@@ -26174,9 +27065,6 @@ msgstr ""
msgid "Toggle navigation"
msgstr ""
-msgid "Toggle project"
-msgstr ""
-
msgid "Toggle sidebar"
msgstr ""
@@ -26216,6 +27104,9 @@ msgstr ""
msgid "Too many projects enabled. You will need to manage them via the console or the API."
msgstr ""
+msgid "Too much data"
+msgstr ""
+
msgid "Topics (optional)"
msgstr ""
@@ -26234,6 +27125,9 @@ msgstr ""
msgid "Total cores (CPUs)"
msgstr ""
+msgid "Total days to completion"
+msgstr ""
+
msgid "Total issues"
msgstr ""
@@ -26330,6 +27224,9 @@ msgstr ""
msgid "Trending"
msgstr ""
+msgid "Trials|Create a new group to start your GitLab Gold trial."
+msgstr ""
+
msgid "Trials|Go back to GitLab"
msgstr ""
@@ -26339,6 +27236,15 @@ msgstr ""
msgid "Trials|You can always resume this process by selecting your avatar and choosing 'Start a Gold trial'"
msgstr ""
+msgid "Trials|You can apply your trial to a new group or an existing group."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group or your personal account."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group, an existing group, or your personal account."
+msgstr ""
+
msgid "Trials|You won't get a free trial right now but you can always resume this process by clicking on your avatar and choosing 'Start a free trial'"
msgstr ""
@@ -26408,6 +27314,9 @@ msgstr ""
msgid "Try using a different search term to find the file you are looking for."
msgstr ""
+msgid "Trying to communicate with your device. Plug it in (if needed) and press the button on the device now."
+msgstr ""
+
msgid "Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now."
msgstr ""
@@ -26495,6 +27404,12 @@ msgstr ""
msgid "URL or request ID"
msgstr ""
+msgid "USER %{user} WILL BE REMOVED! Are you sure?"
+msgstr ""
+
+msgid "USER WILL BE BLOCKED! Are you sure?"
+msgstr ""
+
msgid "UTC"
msgstr ""
@@ -26552,9 +27467,6 @@ msgstr ""
msgid "Unable to load the merge request widget. Try reloading the page."
msgstr ""
-msgid "Unable to resolve"
-msgstr ""
-
msgid "Unable to save iteration. Please try again"
msgstr ""
@@ -26603,6 +27515,9 @@ msgstr ""
msgid "Undo ignore"
msgstr ""
+msgid "Unexpected error"
+msgstr ""
+
msgid "Unfortunately, your email message to GitLab could not be processed."
msgstr ""
@@ -26636,6 +27551,9 @@ msgstr ""
msgid "Unknown response text"
msgstr ""
+msgid "Unless otherwise agreed to in writing with GitLab, by clicking \"Upload License\" you agree that your use of GitLab Software is subject to the %{eula_link_start}Terms of Service%{eula_link_end}."
+msgstr ""
+
msgid "Unlimited"
msgstr ""
@@ -27002,9 +27920,6 @@ msgstr ""
msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
msgstr ""
-msgid "Use a hardware device to add the second factor of authentication."
-msgstr ""
-
msgid "Use an one time password authenticator on your mobile device or computer to enable two-factor authentication (2FA)."
msgstr ""
@@ -27278,13 +28193,13 @@ msgstr ""
msgid "Users"
msgstr ""
-msgid "Users in License:"
+msgid "Users in License"
msgstr ""
-msgid "Users or groups set as approvers in the project's or merge request's settings."
+msgid "Users in License:"
msgstr ""
-msgid "Users outside of license"
+msgid "Users or groups set as approvers in the project's or merge request's settings."
msgstr ""
msgid "Users over License:"
@@ -27302,9 +28217,6 @@ msgstr ""
msgid "Users with a Guest role or those who don't belong to a Project or Group will not use a seat from your license."
msgstr ""
-msgid "Users with a Guest role or those who don't belong to any projects or groups don't count towards seats in use."
-msgstr ""
-
msgid "UsersSelect|%{name} + %{length} more"
msgstr ""
@@ -27344,9 +28256,6 @@ msgstr ""
msgid "Validations failed."
msgstr ""
-msgid "Validity"
-msgstr ""
-
msgid "Value"
msgstr ""
@@ -27365,6 +28274,9 @@ msgstr ""
msgid "Value Stream Name"
msgstr ""
+msgid "ValueStreamAnalyticsStage|We don't have enough data to show this stage."
+msgstr ""
+
msgid "ValueStreamAnalytics|%{days}d"
msgstr ""
@@ -27621,6 +28533,9 @@ msgstr ""
msgid "VisualReviewApp|Steps 1 and 2 (and sometimes 3) are performed once by the developer before requesting feedback. Steps 3 (if necessary), 4 is performed by the reviewer each time they perform a review."
msgstr ""
+msgid "Visualization"
+msgstr ""
+
msgid "Vulnerabilities"
msgstr ""
@@ -27648,34 +28563,31 @@ msgstr ""
msgid "VulnerabilityChart|Severity"
msgstr ""
-msgid "VulnerabilityManagement|A true-positive and will fix"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Change status"
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|Confirm"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Confirmed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
-msgstr ""
-
-msgid "VulnerabilityManagement|Detected %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|A true-positive and will fix"
msgstr ""
-msgid "VulnerabilityManagement|Dismiss"
+msgid "VulnerabilityManagement|Change status"
msgstr ""
-msgid "VulnerabilityManagement|Dismissed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
msgstr ""
-msgid "VulnerabilityManagement|Resolved"
+msgid "VulnerabilityManagement|Detected"
msgstr ""
-msgid "VulnerabilityManagement|Resolved %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Needs triage"
msgstr ""
msgid "VulnerabilityManagement|Something went wrong while trying to delete the comment. Please try again later."
@@ -27726,6 +28638,9 @@ msgstr ""
msgid "Vulnerability|%{scannerName} (version %{scannerVersion})"
msgstr ""
+msgid "Vulnerability|Activity"
+msgstr ""
+
msgid "Vulnerability|Class"
msgstr ""
@@ -27738,6 +28653,9 @@ msgstr ""
msgid "Vulnerability|Description"
msgstr ""
+msgid "Vulnerability|Detected"
+msgstr ""
+
msgid "Vulnerability|Evidence"
msgstr ""
@@ -27801,6 +28719,9 @@ msgstr ""
msgid "Warning: Displaying this diagram might cause performance issues on this page."
msgstr ""
+msgid "We are currently unable to fetch data for the pipeline header."
+msgstr ""
+
msgid "We are currently unable to fetch data for this graph."
msgstr ""
@@ -27840,6 +28761,12 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
+msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
+msgstr ""
+
+msgid "We would like to inform you that your subscription GitLab Enterprise Edition %{plan_name} is nearing its user limit. You have %{active_user_count} active users, which is almost at the user limit of %{maximum_user_count}."
+msgstr ""
+
msgid "We've found no vulnerabilities"
msgstr ""
@@ -27855,6 +28782,12 @@ msgstr ""
msgid "Web terminal"
msgstr ""
+msgid "WebAuthn Devices (%{length})"
+msgstr ""
+
+msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
+msgstr ""
+
msgid "WebIDE|Merge request"
msgstr ""
@@ -27993,15 +28926,9 @@ msgstr ""
msgid "Welcome to the guided GitLab tour"
msgstr ""
-msgid "Welcome to your Issue Board!"
-msgstr ""
-
msgid "Welcome to your issue board!"
msgstr ""
-msgid "We’ve been making changes to %{featureName} and we’d love your feedback %{linkStart}in this issue%{linkEnd} to help us improve the experience."
-msgstr ""
-
msgid "What are you searching for?"
msgstr ""
@@ -28020,6 +28947,9 @@ msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
msgstr ""
+msgid "When enabled, any user visiting %{host} and creating an account will have to be explicitly approved by the admin before they can login. This setting is effective only if sign-ups are enabled."
+msgstr ""
+
msgid "When enabled, any user visiting %{host} will be able to create an account."
msgstr ""
@@ -28244,6 +29174,9 @@ msgstr ""
msgid "With requirements, you can set criteria to check your products against."
msgstr ""
+msgid "With test cases, you can define conditions for your project to meet in determining quality"
+msgstr ""
+
msgid "Withdraw Access Request"
msgstr ""
@@ -28259,6 +29192,9 @@ msgstr ""
msgid "Workflow Help"
msgstr ""
+msgid "Would you like to create a new branch?"
+msgstr ""
+
msgid "Write"
msgstr ""
@@ -28280,6 +29216,9 @@ msgstr ""
msgid "Wrong extern UID provided. Make sure Auth0 is configured correctly."
msgstr ""
+msgid "YYYY-MM-DD"
+msgstr ""
+
msgid "Yes"
msgstr ""
@@ -28337,7 +29276,7 @@ msgstr ""
msgid "You are going to remove the fork relationship from %{project_full_name}. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "You are going to transfer %{project_full_name} to another owner. Are you ABSOLUTELY sure?"
+msgid "You are going to transfer %{project_full_name} to another namespace. Are you ABSOLUTELY sure?"
msgstr ""
msgid "You are going to turn off the confidentiality. This means %{strongStart}everyone%{strongEnd} will be able to see and leave a comment on this %{issuableType}."
@@ -28397,9 +29336,6 @@ msgstr ""
msgid "You can always edit this later"
msgstr ""
-msgid "You can apply your Trial to your Personal account or create a New Group."
-msgstr ""
-
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings"
msgstr ""
@@ -28421,12 +29357,18 @@ msgstr ""
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
+msgid "You can find more information about GitLab subscriptions in %{subscriptions_doc_link}."
+msgstr ""
+
msgid "You can generate an access token scoped to this project for each application to use the GitLab API."
msgstr ""
msgid "You can get started by cloning the repository or start adding files to it with one of the following options."
msgstr ""
+msgid "You can group test cases using labels. To learn about the future direction of this feature, visit %{linkStart}Quality Management direction page%{linkEnd}."
+msgstr ""
+
msgid "You can invite a new member to %{project_name} or invite another group."
msgstr ""
@@ -28442,6 +29384,9 @@ msgstr ""
msgid "You can notify the app / group or a project by sending them an email notification"
msgstr ""
+msgid "You can now close this window."
+msgstr ""
+
msgid "You can now export your security dashboard to a CSV report."
msgstr ""
@@ -28490,9 +29435,6 @@ msgstr ""
msgid "You can test your .gitlab-ci.yml in %{linkStart}CI Lint%{linkEnd}."
msgstr ""
-msgid "You can try again using %{begin_link}basic search%{end_link}"
-msgstr ""
-
msgid "You cannot access the raw file. Please wait a minute."
msgstr ""
@@ -28544,6 +29486,9 @@ msgstr ""
msgid "You don't have any U2F devices registered yet."
msgstr ""
+msgid "You don't have any WebAuthn devices registered yet."
+msgstr ""
+
msgid "You don't have any active chat names."
msgstr ""
@@ -28631,6 +29576,9 @@ msgstr ""
msgid "You must accept our Terms of Service and privacy policy in order to register an account"
msgstr ""
+msgid "You must be logged in to search across all of GitLab"
+msgstr ""
+
msgid "You must disassociate %{domain} from all clusters it is attached to before deletion."
msgstr ""
@@ -28670,7 +29618,7 @@ msgstr ""
msgid "You need to be logged in."
msgstr ""
-msgid "You need to register a two-factor authentication app before you can set up a U2F device."
+msgid "You need to register a two-factor authentication app before you can set up a device."
msgstr ""
msgid "You need to set terms to be enforced"
@@ -28688,6 +29636,9 @@ msgstr ""
msgid "You reached %{usage_in_percent} of %{namespace_name}'s storage capacity (%{used_storage} of %{storage_limit})"
msgstr ""
+msgid "You successfully declined the invitation"
+msgstr ""
+
msgid "You tried to fork %{link_to_the_project} but it failed for the following reason:"
msgstr ""
@@ -28853,10 +29804,13 @@ msgstr ""
msgid "Your U2F device did not send a valid JSON response."
msgstr ""
-msgid "Your U2F device needs to be set up. Plug it in (if not already) and click the button on the left."
+msgid "Your U2F device was registered!"
msgstr ""
-msgid "Your U2F device was registered!"
+msgid "Your WebAuthn device did not send a valid JSON response."
+msgstr ""
+
+msgid "Your WebAuthn device was registered!"
msgstr ""
msgid "Your access request to the %{source_type} has been withdrawn."
@@ -28880,6 +29834,9 @@ msgstr ""
msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
msgstr ""
+msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
+msgstr ""
+
msgid "Your changes can be committed to %{branch_name} because a merge request is open."
msgstr ""
@@ -28916,6 +29873,12 @@ msgstr ""
msgid "Your deployment services will be broken, you will need to manually fix the services after renaming."
msgstr ""
+msgid "Your device is not compatible with GitLab. Please try another device"
+msgstr ""
+
+msgid "Your device needs to be set up. Plug it in (if needed) and click the button on the left."
+msgstr ""
+
msgid "Your device was successfully set up! Give it a name and register it with the GitLab server."
msgstr ""
@@ -29029,9 +29992,6 @@ msgstr[1] ""
msgid "access:"
msgstr ""
-msgid "activated"
-msgstr ""
-
msgid "added %{created_at_timeago}"
msgstr ""
@@ -29104,9 +30064,21 @@ msgstr ""
msgid "by %{user}"
msgstr ""
+msgid "cannot be a date in the past"
+msgstr ""
+
msgid "cannot be changed if a personal project has container registry tags."
msgstr ""
+msgid "cannot be changed if shared runners are enabled"
+msgstr ""
+
+msgid "cannot be enabled because parent group does not allow it"
+msgstr ""
+
+msgid "cannot be enabled because parent group has shared Runners disabled"
+msgstr ""
+
msgid "cannot be enabled unless all domains have TLS certificates"
msgstr ""
@@ -29152,7 +30124,7 @@ msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about SAST %{linkEndTag}"
msgstr ""
-msgid "ciReport|%{linkStartTag}Learn more about Secret Scanning %{linkEndTag}"
+msgid "ciReport|%{linkStartTag}Learn more about Secret Detection %{linkEndTag}"
msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about codequality reports %{linkEndTag}"
@@ -29467,9 +30439,6 @@ msgstr ""
msgid "error"
msgstr ""
-msgid "error code:"
-msgstr ""
-
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr ""
@@ -29491,6 +30460,9 @@ msgstr ""
msgid "failed to dismiss associated finding(id=%{finding_id}): %{message}"
msgstr ""
+msgid "failed to revert associated finding(id=%{finding_id}) to detected"
+msgstr ""
+
msgid "file"
msgid_plural "files"
msgstr[0] ""
@@ -30033,6 +31005,9 @@ msgstr ""
msgid "must be a root namespace"
msgstr ""
+msgid "must be a valid IPv4 or IPv6 address"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -30069,6 +31044,9 @@ msgstr ""
msgid "no expiration"
msgstr ""
+msgid "no name set"
+msgstr ""
+
msgid "no one can merge"
msgstr ""
@@ -30247,9 +31225,6 @@ msgstr ""
msgid "security Reports|There was an error creating the merge request"
msgstr ""
-msgid "settings saved, but not activated"
-msgstr ""
-
msgid "severity|Critical"
msgstr ""
@@ -30376,9 +31351,6 @@ msgstr ""
msgid "toggle collapse"
msgstr ""
-msgid "toggle dropdown"
-msgstr ""
-
msgid "triggered"
msgstr ""
@@ -30406,6 +31378,9 @@ msgstr ""
msgid "user avatar"
msgstr ""
+msgid "user preferences"
+msgstr ""
+
msgid "username"
msgstr ""
diff --git a/locale/fa_IR/gitlab.po b/locale/fa_IR/gitlab.po
index 6cefc3c8791..ba109409ec6 100644
--- a/locale/fa_IR/gitlab.po
+++ b/locale/fa_IR/gitlab.po
@@ -14,7 +14,10 @@ msgstr ""
"X-Crowdin-Language: fa\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 6\n"
-"PO-Revision-Date: 2020-09-04 23:02\n"
+"PO-Revision-Date: 2020-10-02 18:42\n"
+
+msgid " %{project_name}#%{issue_iid} &middot; opened %{issue_created} by %{author}"
+msgstr ""
msgid " %{start} to %{end}"
msgstr ""
@@ -74,6 +77,16 @@ msgstr ""
msgid "\"el\" parameter is required for createInstance()"
msgstr ""
+msgid "%d Approval"
+msgid_plural "%d Approvals"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d Package"
+msgid_plural "%d Packages"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d Scanned URL"
msgid_plural "%d Scanned URLs"
msgstr[0] ""
@@ -137,6 +150,11 @@ msgstr[1] ""
msgid "%d commits"
msgstr ""
+msgid "%d completed issue"
+msgid_plural "%d completed issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d contribution"
msgid_plural "%d contributions"
msgstr[0] ""
@@ -147,6 +165,11 @@ msgid_plural "%d days"
msgstr[0] ""
msgstr[1] ""
+msgid "%d day until tags are automatically removed"
+msgid_plural "%d days until tags are automatically removed"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d error"
msgid_plural "%d errors"
msgstr[0] ""
@@ -237,6 +260,16 @@ msgid_plural "%d more comments"
msgstr[0] ""
msgstr[1] ""
+msgid "%d open issue"
+msgid_plural "%d open issues"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d pending comment"
+msgid_plural "%d pending comments"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d personal project will be removed and cannot be restored."
msgid_plural "%d personal projects will be removed and cannot be restored."
msgstr[0] ""
@@ -252,6 +285,11 @@ msgid_plural "%d projects"
msgstr[0] ""
msgstr[1] ""
+msgid "%d project selected"
+msgid_plural "%d projects selected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d request with warnings"
msgid_plural "%d requests with warnings"
msgstr[0] ""
@@ -272,6 +310,11 @@ msgid_plural "%d tags"
msgstr[0] ""
msgstr[1] ""
+msgid "%d tag per image name"
+msgid_plural "%d tags per image name"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d unassigned issue"
msgid_plural "%d unassigned issues"
msgstr[0] ""
@@ -292,6 +335,11 @@ msgid_plural "%d vulnerabilities dismissed"
msgstr[0] ""
msgstr[1] ""
+msgid "%d warning found:"
+msgid_plural "%d warnings found:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%s additional commit has been omitted to prevent performance issues."
msgid_plural "%s additional commits have been omitted to prevent performance issues."
msgstr[0] ""
@@ -330,6 +378,9 @@ msgstr ""
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr ""
+msgid "%{completedCount} completed weight"
+msgstr ""
+
msgid "%{completedWeight} of %{totalWeight} weight completed"
msgstr ""
@@ -378,14 +429,12 @@ msgid_plural "%{count} participants"
msgstr[0] ""
msgstr[1] ""
-msgid "%{count} pending comment"
-msgid_plural "%{count} pending comments"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
+msgid "%{count} total weight"
+msgstr ""
+
msgid "%{dashboard_path} could not be found."
msgstr ""
@@ -440,6 +489,9 @@ msgstr ""
msgid "%{group_name} uses group managed accounts. You need to create a new GitLab account which will be managed by %{group_name}."
msgstr ""
+msgid "%{group_name}&%{epic_iid} &middot; opened %{epic_created} by %{author}"
+msgstr ""
+
msgid "%{host} sign-in from new location"
msgstr ""
@@ -452,7 +504,7 @@ msgstr ""
msgid "%{issuableType} will be removed! Are you sure?"
msgstr ""
-msgid "%{issuesSize} issues with a limit of %{maxIssueCount}"
+msgid "%{issuesCount} issues with a limit of %{maxIssueCount}"
msgstr ""
msgid "%{issuesSize} with a limit of %{maxIssueCount}"
@@ -485,7 +537,7 @@ msgstr ""
msgid "%{labelStart}Namespace:%{labelEnd} %{namespace}"
msgstr ""
-msgid "%{labelStart}Report Type:%{labelEnd} %{reportType}"
+msgid "%{labelStart}Scan Type:%{labelEnd} %{reportType}"
msgstr ""
msgid "%{labelStart}Scanner:%{labelEnd} %{scanner}"
@@ -682,9 +734,6 @@ msgid_plural "%{securityScanner} results are not available because a pipeline ha
msgstr[0] ""
msgstr[1] ""
-msgid "%{service_title} %{message}."
-msgstr ""
-
msgid "%{size} GiB"
msgstr ""
@@ -773,6 +822,12 @@ msgstr ""
msgid "%{timebox_name} should belong either to a project or a group."
msgstr ""
+msgid "%{timebox_type} does not support burnup charts"
+msgstr ""
+
+msgid "%{timebox_type} must have a start and due date"
+msgstr ""
+
msgid "%{title} %{operator} %{threshold}"
msgstr ""
@@ -797,7 +852,7 @@ msgstr ""
msgid "%{total} open issue weight"
msgstr ""
-msgid "%{total} open issues"
+msgid "%{total} warnings found: showing first %{warningsDisplayed}"
msgstr ""
msgid "%{usage_ping_link_start}Learn more%{usage_ping_link_end} about what information is shared with GitLab Inc."
@@ -830,9 +885,6 @@ msgstr ""
msgid "&lt; 1 hour"
msgstr ""
-msgid "&lt;no name set&gt;"
-msgstr ""
-
msgid "&lt;no scopes selected&gt;"
msgstr ""
@@ -863,6 +915,9 @@ msgstr ""
msgid "'%{name}' Value Stream created"
msgstr ""
+msgid "'%{name}' Value Stream deleted"
+msgstr ""
+
msgid "'%{name}' stage already exists"
msgstr ""
@@ -922,6 +977,9 @@ msgstr ""
msgid "+ %{numberOfHiddenAssignees} more"
msgstr ""
+msgid "+ %{numberOfHiddenReviewers} more"
+msgstr ""
+
msgid "+%d more"
msgid_plural "+%d more"
msgstr[0] ""
@@ -982,6 +1040,11 @@ msgid_plural "%d Days"
msgstr[0] ""
msgstr[1] ""
+msgid "1 Issue"
+msgid_plural "%d Issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "1 closed issue"
msgid_plural "%{issues} closed issues"
msgstr[0] ""
@@ -997,6 +1060,11 @@ msgid_plural "%d days"
msgstr[0] ""
msgstr[1] ""
+msgid "1 deploy key"
+msgid_plural "%d deploy keys"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1099,6 +1167,9 @@ msgstr ""
msgid ":%{startLine} to %{endLine}"
msgstr ""
+msgid "A %{incident_docs_start}modified issue%{incident_docs_end} to guide the resolution of incidents."
+msgstr ""
+
msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr ""
@@ -1111,6 +1182,9 @@ msgstr ""
msgid "A GitBook site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
+msgid "A Gitpod configured Webapplication in Spring and Java"
+msgstr ""
+
msgid "A Hexo site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
@@ -1282,9 +1356,15 @@ msgstr ""
msgid "Access expiration date"
msgstr ""
+msgid "Access expires"
+msgstr ""
+
msgid "Access forbidden. Check your access level."
msgstr ""
+msgid "Access granted"
+msgstr ""
+
msgid "Access requests"
msgstr ""
@@ -1294,6 +1374,9 @@ msgstr ""
msgid "Access to Pages websites are controlled based on the user's membership to a given project. By checking this box, users will be required to be logged in to have access to all Pages websites in your instance."
msgstr ""
+msgid "AccessDropdown|Deploy Keys"
+msgstr ""
+
msgid "AccessDropdown|Groups"
msgstr ""
@@ -1411,12 +1494,6 @@ msgstr ""
msgid "Active Sessions"
msgstr ""
-msgid "Active Users:"
-msgstr ""
-
-msgid "Active users"
-msgstr ""
-
msgid "Activity"
msgstr ""
@@ -1584,9 +1661,6 @@ msgstr ""
msgid "Add label(s)"
msgstr ""
-msgid "Add license"
-msgstr ""
-
msgid "Add list"
msgstr ""
@@ -1761,21 +1835,51 @@ msgstr ""
msgid "AdminArea|Bots"
msgstr ""
+msgid "AdminArea|Components"
+msgstr ""
+
msgid "AdminArea|Developer"
msgstr ""
+msgid "AdminArea|Features"
+msgstr ""
+
+msgid "AdminArea|Groups: %{number_of_groups}"
+msgstr ""
+
msgid "AdminArea|Guest"
msgstr ""
msgid "AdminArea|Included Free in license"
msgstr ""
+msgid "AdminArea|Latest groups"
+msgstr ""
+
+msgid "AdminArea|Latest projects"
+msgstr ""
+
+msgid "AdminArea|Latest users"
+msgstr ""
+
msgid "AdminArea|Maintainer"
msgstr ""
+msgid "AdminArea|New group"
+msgstr ""
+
+msgid "AdminArea|New project"
+msgstr ""
+
+msgid "AdminArea|New user"
+msgstr ""
+
msgid "AdminArea|Owner"
msgstr ""
+msgid "AdminArea|Projects: %{number_of_projects}"
+msgstr ""
+
msgid "AdminArea|Reporter"
msgstr ""
@@ -1803,6 +1907,9 @@ msgstr ""
msgid "AdminArea|Users without a Group and Project"
msgstr ""
+msgid "AdminArea|Users: %{number_of_users}"
+msgstr ""
+
msgid "AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running."
msgstr ""
@@ -1821,9 +1928,6 @@ msgstr ""
msgid "AdminProjects|Delete Project %{projectName}?"
msgstr ""
-msgid "AdminProjects|Delete project"
-msgstr ""
-
msgid "AdminSettings|Apply integration settings to all Projects"
msgstr ""
@@ -2061,21 +2165,30 @@ msgstr ""
msgid "AdminUsers|Without projects"
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 ""
msgid "AdminUsers|You cannot remove your own admin rights."
msgstr ""
+msgid "AdminUsers|You must transfer ownership or delete the groups owned by this user before you can delete their account"
+msgstr ""
+
msgid "Administration"
msgstr ""
msgid "Advanced"
msgstr ""
+msgid "Advanced Search"
+msgstr ""
+
+msgid "Advanced Search with Elasticsearch"
+msgstr ""
+
msgid "Advanced Settings"
msgstr ""
@@ -2153,6 +2266,9 @@ msgstr ""
msgid "AlertManagement|Edit"
msgstr ""
+msgid "AlertManagement|Environment"
+msgstr ""
+
msgid "AlertManagement|Events"
msgstr ""
@@ -2165,6 +2281,9 @@ msgstr ""
msgid "AlertManagement|Issue"
msgstr ""
+msgid "AlertManagement|Key"
+msgstr ""
+
msgid "AlertManagement|Low"
msgstr ""
@@ -2258,6 +2377,9 @@ msgstr ""
msgid "AlertManagement|Unknown"
msgstr ""
+msgid "AlertManagement|Value"
+msgstr ""
+
msgid "AlertManagement|View alerts in Opsgenie"
msgstr ""
@@ -2417,6 +2539,9 @@ msgstr ""
msgid "All projects"
msgstr ""
+msgid "All projects selected"
+msgstr ""
+
msgid "All security scans are enabled because %{linkStart}Auto DevOps%{linkEnd} is enabled on this project"
msgstr ""
@@ -2504,6 +2629,9 @@ msgstr ""
msgid "Almost there"
msgstr ""
+msgid "Already blocked"
+msgstr ""
+
msgid "Also called \"Issuer\" or \"Relying party trust identifier\""
msgstr ""
@@ -2558,6 +2686,9 @@ msgstr ""
msgid "An error has occurred"
msgstr ""
+msgid "An error occured while making the changes: %{error}"
+msgstr ""
+
msgid "An error occurred adding a draft to the thread."
msgstr ""
@@ -2585,12 +2716,6 @@ msgstr ""
msgid "An error occurred when toggling the notification subscription"
msgstr ""
-msgid "An error occurred when trying to resolve a comment. Please try again."
-msgstr ""
-
-msgid "An error occurred when trying to resolve a discussion. Please try again."
-msgstr ""
-
msgid "An error occurred when updating the issue weight"
msgstr ""
@@ -2606,12 +2731,6 @@ msgstr ""
msgid "An error occurred while checking group path. Please refresh and try again."
msgstr ""
-msgid "An error occurred while committing your changes."
-msgstr ""
-
-msgid "An error occurred while creating the list. Please try again."
-msgstr ""
-
msgid "An error occurred while decoding the file."
msgstr ""
@@ -2684,25 +2803,19 @@ msgstr ""
msgid "An error occurred while fetching the Service Desk address."
msgstr ""
-msgid "An error occurred while fetching the board issues. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the board lists. Please reload the page."
msgstr ""
msgid "An error occurred while fetching the board lists. Please try again."
msgstr ""
-msgid "An error occurred while fetching the board swimlanes. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the builds."
msgstr ""
msgid "An error occurred while fetching the job log."
msgstr ""
-msgid "An error occurred while fetching the job trace."
+msgid "An error occurred while fetching the job logs."
msgstr ""
msgid "An error occurred while fetching the job."
@@ -2849,9 +2962,6 @@ msgstr ""
msgid "An error occurred while saving assignees"
msgstr ""
-msgid "An error occurred while saving the template. Please check if the template exists."
-msgstr ""
-
msgid "An error occurred while searching for milestones"
msgstr ""
@@ -2870,10 +2980,10 @@ msgstr ""
msgid "An error occurred while updating approvers"
msgstr ""
-msgid "An error occurred while updating the comment"
+msgid "An error occurred while updating labels."
msgstr ""
-msgid "An error occurred while updating the list. Please try again."
+msgid "An error occurred while updating the comment"
msgstr ""
msgid "An error occurred while validating group path"
@@ -2927,6 +3037,9 @@ msgstr ""
msgid "An unknown error occurred while loading this graph."
msgstr ""
+msgid "An unknown error occurred."
+msgstr ""
+
msgid "Analytics"
msgstr ""
@@ -2960,10 +3073,10 @@ msgstr ""
msgid "Any"
msgstr ""
-msgid "Any Author"
+msgid "Any %{header}"
msgstr ""
-msgid "Any Status"
+msgid "Any Author"
msgstr ""
msgid "Any branch"
@@ -3017,6 +3130,9 @@ msgstr ""
msgid "Application ID"
msgstr ""
+msgid "Application limits saved successfully"
+msgstr ""
+
msgid "Application settings saved successfully"
msgstr ""
@@ -3226,6 +3342,9 @@ msgstr ""
msgid "Are you sure you want to close this blocked issue?"
msgstr ""
+msgid "Are you sure you want to delete \"%{name}\" Value Stream?"
+msgstr ""
+
msgid "Are you sure you want to delete %{name}?"
msgstr ""
@@ -3235,6 +3354,9 @@ msgstr ""
msgid "Are you sure you want to delete this %{typeOfComment}?"
msgstr ""
+msgid "Are you sure you want to delete this SSH key?"
+msgstr ""
+
msgid "Are you sure you want to delete this board?"
msgstr ""
@@ -3259,6 +3381,11 @@ msgstr ""
msgid "Are you sure you want to erase this build?"
msgstr ""
+msgid "Are you sure you want to import %d repository?"
+msgid_plural "Are you sure you want to import %d repositories?"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Are you sure you want to lose unsaved changes?"
msgstr ""
@@ -3268,15 +3395,15 @@ msgstr ""
msgid "Are you sure you want to merge immediately?"
msgstr ""
-msgid "Are you sure you want to permanently delete this license?"
-msgstr ""
-
msgid "Are you sure you want to re-deploy this environment?"
msgstr ""
msgid "Are you sure you want to regenerate the public key? You will have to update the public key on the remote server before mirroring will work again."
msgstr ""
+msgid "Are you sure you want to reindex?"
+msgstr ""
+
msgid "Are you sure you want to remove %{group_name}?"
msgstr ""
@@ -3304,6 +3431,9 @@ msgstr ""
msgid "Are you sure you want to revoke this nickname?"
msgstr ""
+msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
+msgstr ""
+
msgid "Are you sure you want to stop this environment?"
msgstr ""
@@ -3325,6 +3455,9 @@ msgstr ""
msgid "Are you sure? The device will be signed out of GitLab and all remember me tokens revoked."
msgstr ""
+msgid "Are you sure? This will invalidate your registered applications and U2F / WebAuthn devices."
+msgstr ""
+
msgid "Are you sure? This will invalidate your registered applications and U2F devices."
msgstr ""
@@ -3343,9 +3476,6 @@ msgstr ""
msgid "Artifacts"
msgstr ""
-msgid "As U2F devices are only supported by a few browsers, we require that you set up a two-factor authentication app before a U2F device. That way you'll always be able to log in - even when you're using an unsupported browser."
-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 ""
@@ -3539,6 +3669,9 @@ msgstr ""
msgid "AuditLogs|Target"
msgstr ""
+msgid "AuditLogs|This month"
+msgstr ""
+
msgid "AuditLogs|User Events"
msgstr ""
@@ -3578,6 +3711,9 @@ msgstr ""
msgid "Authentication via U2F device failed."
msgstr ""
+msgid "Authentication via WebAuthn device failed."
+msgstr ""
+
msgid "Author"
msgstr ""
@@ -3845,15 +3981,6 @@ msgstr ""
msgid "BambooService|You must set up automatic revision labeling and a repository trigger in Bamboo."
msgstr ""
-msgid "BatchComments|Delete all pending comments"
-msgstr ""
-
-msgid "BatchComments|Discard review?"
-msgstr ""
-
-msgid "BatchComments|You're about to discard your review which will delete all of your pending comments. The deleted comments %{strong_start}cannot%{strong_end} be restored."
-msgstr ""
-
msgid "Be careful. Changing the project's namespace can have unintended side effects."
msgstr ""
@@ -3875,6 +4002,9 @@ msgstr ""
msgid "Bi-weekly code coverage"
msgstr ""
+msgid "Billable Users:"
+msgstr ""
+
msgid "Billing"
msgstr ""
@@ -3884,7 +4014,7 @@ msgstr ""
msgid "BillingPlans|@%{user_name} you are currently using the %{plan_name} plan."
msgstr ""
-msgid "BillingPlans|Congratulations, your new trial is activated"
+msgid "BillingPlans|Congratulations, your free trial is activated."
msgstr ""
msgid "BillingPlans|If you would like to downgrade your plan please contact %{support_link_start}Customer Support%{support_link_end}."
@@ -3947,6 +4077,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Block user"
+msgstr ""
+
msgid "Blocked"
msgstr ""
@@ -3962,31 +4095,37 @@ msgstr ""
msgid "Blog"
msgstr ""
-msgid "Board name"
-msgstr ""
-
msgid "Board scope"
msgstr ""
msgid "Board scope affects which issues are displayed for anyone who visits this board"
msgstr ""
-msgid "BoardBlankState|Add default lists"
+msgid "Boards"
msgstr ""
-msgid "BoardBlankState|Add the following default lists to your Issue Board with one click:"
+msgid "Boards and Board Lists"
msgstr ""
-msgid "BoardBlankState|Nevermind, I'll use my own"
+msgid "Boards|An error occurred while creating the issue. Please try again."
msgstr ""
-msgid "BoardBlankState|Starting out with the default set of lists will get you right on the way to making the most of your board."
+msgid "Boards|An error occurred while creating the list. Please try again."
msgstr ""
-msgid "Boards"
+msgid "Boards|An error occurred while fetching issues. Please reload the page."
msgstr ""
-msgid "Boards and Board Lists"
+msgid "Boards|An error occurred while fetching the board issues. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching the board swimlanes. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while moving the issue. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while updating the list. Please try again."
msgstr ""
msgid "Boards|Collapse"
@@ -4013,7 +4152,7 @@ msgstr ""
msgid "Branch %{branch_name} was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr ""
-msgid "Branch has changed"
+msgid "Branch changed"
msgstr ""
msgid "Branch is already taken"
@@ -4319,6 +4458,9 @@ msgstr ""
msgid "CLOSED (MOVED)"
msgstr ""
+msgid "CODEOWNERS rule violation"
+msgstr ""
+
msgid "CONTRIBUTING"
msgstr ""
@@ -4349,9 +4491,6 @@ msgstr ""
msgid "Can't create snippet: %{err}"
msgstr ""
-msgid "Can't edit as source branch was deleted"
-msgstr ""
-
msgid "Can't fetch content for the blob: %{err}"
msgstr ""
@@ -4364,9 +4503,6 @@ msgstr ""
msgid "Can't load mermaid module: %{err}"
msgstr ""
-msgid "Can't remove group members without group managed account"
-msgstr ""
-
msgid "Can't scan the code?"
msgstr ""
@@ -4409,6 +4545,9 @@ msgstr ""
msgid "Cannot create the abuse report. This user has been blocked."
msgstr ""
+msgid "Cannot enable shared runners because parent group does not allow it"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -4514,6 +4653,15 @@ msgstr ""
msgid "Change your password or recover your current one"
msgstr ""
+msgid "ChangeReviewer|Reviewer changed from %{old} to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Reviewer changed to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Unassigned"
+msgstr ""
+
msgid "ChangeTypeActionLabel|Pick into branch"
msgstr ""
@@ -4553,6 +4701,9 @@ msgstr ""
msgid "Changes the title to \"%{title_param}\"."
msgstr ""
+msgid "Changes were successfully made."
+msgstr ""
+
msgid "Changes won't take place until the index is %{link_start}recreated%{link_end}."
msgstr ""
@@ -4958,6 +5109,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove variable"
+msgstr ""
+
msgid "CiVariables|Remove variable row"
msgstr ""
@@ -5036,9 +5190,6 @@ msgstr ""
msgid "Clear due date"
msgstr ""
-msgid "Clear input"
-msgstr ""
-
msgid "Clear recent searches"
msgstr ""
@@ -5087,6 +5238,9 @@ msgstr ""
msgid "Client authentication key password"
msgstr ""
+msgid "Client request timeout"
+msgstr ""
+
msgid "Clients"
msgstr ""
@@ -5171,6 +5325,27 @@ msgstr ""
msgid "Cluster type must be specificed for Stages::ClusterEndpointInserter"
msgstr ""
+msgid "ClusterAgents|Configuration"
+msgstr ""
+
+msgid "ClusterAgents|Connect your cluster with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate Kubernetes with a GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Name"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Agent also requires %{linkStart}enabling the Agent Server%{linkEnd}"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Kubernetes Agent allows an Infrastructure as Code, GitOps approach to integrating Kubernetes clusters with GitLab. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "ClusterAgent|This feature is only available for premium plans"
msgstr ""
@@ -5240,10 +5415,10 @@ msgstr ""
msgid "ClusterIntegration|All installed applications and related resources"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster."
+msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{linkStart}More information%{linkEnd}"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{startLink}More information%{endLink}"
+msgid "ClusterIntegration|Allow GitLab to manage namespaces and service accounts for this cluster."
msgstr ""
msgid "ClusterIntegration|Alternatively, "
@@ -5264,6 +5439,9 @@ msgstr ""
msgid "ClusterIntegration|An error occurred while trying to fetch zone machine types: %{error}"
msgstr ""
+msgid "ClusterIntegration|An unknown error occurred while attempting to connect to Kubernetes."
+msgstr ""
+
msgid "ClusterIntegration|Any project namespaces"
msgstr ""
@@ -5279,6 +5457,9 @@ msgstr ""
msgid "ClusterIntegration|Authenticate with Amazon Web Services"
msgstr ""
+msgid "ClusterIntegration|Authentication Error"
+msgstr ""
+
msgid "ClusterIntegration|Base domain"
msgstr ""
@@ -5297,13 +5478,22 @@ msgstr ""
msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}security group %{externalLinkIcon} %{endLink} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
+msgid "ClusterIntegration|Check your CA certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Check your cluster status"
+msgstr ""
+
+msgid "ClusterIntegration|Check your token"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}subnets %{externalLinkIcon} %{endLink} in your VPC where your worker nodes will run."
+msgid "ClusterIntegration|Choose the %{linkStart}security group %{linkEnd} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
msgstr ""
-msgid "ClusterIntegration|Choose the worker node %{startLink}instance type %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Choose the %{linkStart}subnets %{linkEnd} in your VPC where your worker nodes will run."
+msgstr ""
+
+msgid "ClusterIntegration|Choose the worker node %{linkStart}instance type%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Choose which applications to install on your Kubernetes cluster."
@@ -5315,10 +5505,7 @@ msgstr ""
msgid "ClusterIntegration|Clear cluster cache"
msgstr ""
-msgid "ClusterIntegration|Clear the local cache of namespace and service accounts. This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
-msgstr ""
-
-msgid "ClusterIntegration|Cluster being created"
+msgid "ClusterIntegration|Clear the local cache of namespace and service accounts."
msgstr ""
msgid "ClusterIntegration|Cluster management project (alpha)"
@@ -5330,15 +5517,21 @@ msgstr ""
msgid "ClusterIntegration|Cluster_applications artifact too big. Maximum allowable size: %{human_size}"
msgstr ""
-msgid "ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters."
+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|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}"
+msgid "ClusterIntegration|Clusters connected with a certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Connect cluster with certificate"
msgstr ""
msgid "ClusterIntegration|Connect existing cluster"
msgstr ""
+msgid "ClusterIntegration|Connection Error"
+msgstr ""
+
msgid "ClusterIntegration|Copy API URL"
msgstr ""
@@ -5414,6 +5607,12 @@ msgstr ""
msgid "ClusterIntegration|Deletes all GitLab resources attached to this cluster during removal"
msgstr ""
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared."
+msgstr ""
+
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared. %{linkStart}More information%{linkEnd}"
+msgstr ""
+
msgid "ClusterIntegration|Did you know?"
msgstr ""
@@ -5483,6 +5682,9 @@ msgstr ""
msgid "ClusterIntegration|Fluentd is an open source data collector, which lets you unify the data collection and consumption for a better use and understanding of data. It requires at least one of the following logs to be successfully installed."
msgstr ""
+msgid "ClusterIntegration|GitLab Agent managed clusters"
+msgstr ""
+
msgid "ClusterIntegration|GitLab Container Network Policies"
msgstr ""
@@ -5495,6 +5697,12 @@ msgstr ""
msgid "ClusterIntegration|GitLab Runner connects to the repository and executes CI/CD jobs, pushing results back and deploying applications to production."
msgstr ""
+msgid "ClusterIntegration|GitLab failed to authenticate."
+msgstr ""
+
+msgid "ClusterIntegration|GitLab failed to connect to the cluster."
+msgstr ""
+
msgid "ClusterIntegration|GitLab-managed cluster"
msgstr ""
@@ -5516,6 +5724,9 @@ msgstr ""
msgid "ClusterIntegration|Group cluster"
msgstr ""
+msgid "ClusterIntegration|HTTP Error"
+msgstr ""
+
msgid "ClusterIntegration|Helm Tiller"
msgstr ""
@@ -5549,7 +5760,10 @@ msgstr ""
msgid "ClusterIntegration|Instance type"
msgstr ""
-msgid "ClusterIntegration|Integrate Kubernetes cluster automation"
+msgid "ClusterIntegration|Integrate Kubernetes with a cluster certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Integrate with a cluster certificate"
msgstr ""
msgid "ClusterIntegration|Issuer Email"
@@ -5585,9 +5799,6 @@ msgstr ""
msgid "ClusterIntegration|Knative extends Kubernetes to provide a set of middleware components that are essential to build modern, source-centric, and container-based applications that can run anywhere: on premises, in the cloud, or even in a third-party data center."
msgstr ""
-msgid "ClusterIntegration|Kubernetes cluster"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes cluster is being created..."
msgstr ""
@@ -5600,9 +5811,6 @@ msgstr ""
msgid "ClusterIntegration|Kubernetes clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr ""
-msgid "ClusterIntegration|Kubernetes clusters can be used to deploy applications and to provide Review Apps for this project"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes version"
msgstr ""
@@ -5615,7 +5823,7 @@ msgstr ""
msgid "ClusterIntegration|Learn more about %{help_link_start}zones%{help_link_end}."
msgstr ""
-msgid "ClusterIntegration|Learn more about %{startLink}Regions %{externalLinkIcon}%{endLink}."
+msgid "ClusterIntegration|Learn more about %{linkStart}Regions%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Learn more about Kubernetes"
@@ -5660,12 +5868,18 @@ msgstr ""
msgid "ClusterIntegration|Machine type"
msgstr ""
+msgid "ClusterIntegration|Make sure your API endpoint is correct"
+msgstr ""
+
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create Kubernetes clusters"
msgstr ""
msgid "ClusterIntegration|Manage your Kubernetes cluster by visiting %{provider_link}"
msgstr ""
+msgid "ClusterIntegration|Namespace per environment"
+msgstr ""
+
msgid "ClusterIntegration|No IAM Roles found"
msgstr ""
@@ -5711,6 +5925,9 @@ msgstr ""
msgid "ClusterIntegration|No zones matched your search"
msgstr ""
+msgid "ClusterIntegration|Node calculations use the Kubernetes Metrics API. Make sure your cluster has metrics installed"
+msgstr ""
+
msgid "ClusterIntegration|Number of nodes"
msgstr ""
@@ -5753,6 +5970,9 @@ msgstr ""
msgid "ClusterIntegration|RBAC-enabled cluster"
msgstr ""
+msgid "ClusterIntegration|Read our %{linkStart}help page%{linkEnd} on Kubernetes cluster integration."
+msgstr ""
+
msgid "ClusterIntegration|Read our %{link_start}help page%{link_end} on Kubernetes cluster integration."
msgstr ""
@@ -5855,7 +6075,7 @@ msgstr ""
msgid "ClusterIntegration|Select a VPC to choose a subnet"
msgstr ""
-msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{linkStart}Amazon Web Services %{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select a network to choose a subnetwork"
@@ -5888,7 +6108,7 @@ msgstr ""
msgid "ClusterIntegration|Select project to choose zone"
msgstr ""
-msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select zone"
@@ -5978,9 +6198,18 @@ msgstr ""
msgid "ClusterIntegration|There was a problem authenticating with your cluster. Please ensure your CA Certificate and Token are valid."
msgstr ""
+msgid "ClusterIntegration|There was an HTTP error when connecting to your cluster."
+msgstr ""
+
msgid "ClusterIntegration|This account must have permissions to create a Kubernetes cluster in the %{link_to_container_project} specified below"
msgstr ""
+msgid "ClusterIntegration|This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
+msgstr ""
+
+msgid "ClusterIntegration|This is necessary to clear existing environment-namespace associations from clusters previously managed by GitLab."
+msgstr ""
+
msgid "ClusterIntegration|This option will allow you to install applications on RBAC clusters."
msgstr ""
@@ -6005,9 +6234,21 @@ msgstr ""
msgid "ClusterIntegration|To use a new project, first create one on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}."
msgstr ""
+msgid "ClusterIntegration|Troubleshooting tips:"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Authenticate"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Connect"
+msgstr ""
+
msgid "ClusterIntegration|Uninstall %{appTitle}"
msgstr ""
+msgid "ClusterIntegration|Unknown Error"
+msgstr ""
+
msgid "ClusterIntegration|Update %{appTitle}"
msgstr ""
@@ -6068,7 +6309,7 @@ msgstr ""
msgid "ClusterIntegration|Your cluster API is unreachable. Please ensure your API URL is correct."
msgstr ""
-msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Zone"
@@ -6188,6 +6429,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse all threads"
+msgstr ""
+
msgid "Collapse approvers"
msgstr ""
@@ -6337,7 +6581,7 @@ msgstr ""
msgid "Commit…"
msgstr ""
-msgid "Company"
+msgid "Community forum"
msgstr ""
msgid "Company name"
@@ -6346,6 +6590,9 @@ msgstr ""
msgid "Compare"
msgstr ""
+msgid "Compare %{oldCommitId}...%{newCommitId}"
+msgstr ""
+
msgid "Compare Git revisions"
msgstr ""
@@ -6361,6 +6608,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare submodule commit revisions"
+msgstr ""
+
msgid "Compare with previous version"
msgstr ""
@@ -6496,6 +6746,9 @@ msgstr ""
msgid "Configure the way a user creates a new account."
msgstr ""
+msgid "Configure which lists are shown for anyone who visits this board"
+msgstr ""
+
msgid "Confirm"
msgstr ""
@@ -6721,6 +6974,9 @@ msgstr[1] ""
msgid "ContainerRegistry|Set cleanup policy"
msgstr ""
+msgid "ContainerRegistry|Some tags were not deleted"
+msgstr ""
+
msgid "ContainerRegistry|Something went wrong while fetching the cleanup policy."
msgstr ""
@@ -6760,6 +7016,9 @@ msgstr ""
msgid "ContainerRegistry|Tags with names matching this regex pattern will %{italicStart}expire:%{italicEnd}"
msgstr ""
+msgid "ContainerRegistry|The cleanup policy timed out before it could delete all tags. An administrator can %{adminLinkStart}manually run cleanup now%{adminLinkEnd} or you can wait for the cleanup policy to automatically run again. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "ContainerRegistry|The last tag related to this image was recently removed. This empty image and any associated data will be automatically removed as part of the regular Garbage Collection process. If you have any questions, contact your administrator."
msgstr ""
@@ -6892,6 +7151,9 @@ msgstr ""
msgid "Contributions per group member"
msgstr ""
+msgid "Contributor"
+msgstr ""
+
msgid "Contributors"
msgstr ""
@@ -7021,6 +7283,9 @@ msgstr ""
msgid "Could not change HEAD: branch '%{branch}' does not exist"
msgstr ""
+msgid "Could not commit. An unexpected error occurred."
+msgstr ""
+
msgid "Could not connect to FogBugz, check your URL"
msgstr ""
@@ -7060,6 +7325,9 @@ msgstr ""
msgid "Could not find iteration"
msgstr ""
+msgid "Could not load instance counts. Please refresh the page to try again."
+msgstr ""
+
msgid "Could not remove the trigger."
msgstr ""
@@ -7084,10 +7352,10 @@ msgstr ""
msgid "Could not save prometheus manual configuration"
msgstr ""
-msgid "Could not udpdate wiki page"
+msgid "Could not update the LDAP settings"
msgstr ""
-msgid "Could not update the LDAP settings"
+msgid "Could not update wiki page"
msgstr ""
msgid "Could not upload your designs as one or more files uploaded are not supported."
@@ -7745,6 +8013,9 @@ msgstr ""
msgid "DastProfiles|Are you sure you want to delete this profile?"
msgstr ""
+msgid "DastProfiles|Could not create site validation token. Please refresh the page, or try again later."
+msgstr ""
+
msgid "DastProfiles|Could not create the scanner profile. Please try again."
msgstr ""
@@ -7769,6 +8040,12 @@ msgstr ""
msgid "DastProfiles|Could not fetch site profiles. Please refresh the page, or try again later."
msgstr ""
+msgid "DastProfiles|Could not retrieve site validation status. Please refresh the page, or try again later."
+msgstr ""
+
+msgid "DastProfiles|Could not update the scanner profile. Please try again."
+msgstr ""
+
msgid "DastProfiles|Could not update the site profile. Please try again."
msgstr ""
@@ -7784,7 +8061,7 @@ msgstr ""
msgid "DastProfiles|Download validation text file"
msgstr ""
-msgid "DastProfiles|Edit feature will come soon. Please create a new profile if changes needed"
+msgid "DastProfiles|Edit scanner profile"
msgstr ""
msgid "DastProfiles|Edit site profile"
@@ -7817,6 +8094,9 @@ msgstr ""
msgid "DastProfiles|No profiles created yet"
msgstr ""
+msgid "DastProfiles|Passive"
+msgstr ""
+
msgid "DastProfiles|Please enter a valid URL format, ex: http://www.example.com/home"
msgstr ""
@@ -7832,6 +8112,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan mode"
+msgstr ""
+
msgid "DastProfiles|Scanner Profile"
msgstr ""
@@ -7871,10 +8154,10 @@ msgstr ""
msgid "DastProfiles|Text file validation"
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
+msgid "DastProfiles|The maximum number of minutes allowed for the spider to traverse the site."
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the spider to traverse the site."
+msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
msgstr ""
msgid "DastProfiles|Validate"
@@ -7907,6 +8190,9 @@ msgstr ""
msgid "Date picker"
msgstr ""
+msgid "Date range"
+msgstr ""
+
msgid "Date range cannot exceed %{maxDateRange} days."
msgstr ""
@@ -7931,6 +8217,9 @@ msgstr ""
msgid "Days to merge"
msgstr ""
+msgid "Dear Administrator,"
+msgstr ""
+
msgid "Debug"
msgstr ""
@@ -8042,12 +8331,18 @@ msgstr ""
msgid "Delete"
msgstr ""
+msgid "Delete %{name}"
+msgstr ""
+
msgid "Delete Comment"
msgstr ""
msgid "Delete Snippet"
msgstr ""
+msgid "Delete Value Stream"
+msgstr ""
+
msgid "Delete account"
msgstr ""
@@ -8069,9 +8364,6 @@ msgstr ""
msgid "Delete label: %{label_name} ?"
msgstr ""
-msgid "Delete license"
-msgstr ""
-
msgid "Delete list"
msgstr ""
@@ -8147,15 +8439,6 @@ msgstr ""
msgid "Deleting a project places it into a read-only state until %{date}, at which point the project will be permanently deleted. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "Deleting the license failed."
-msgstr ""
-
-msgid "Deleting the license failed. The license was not found."
-msgstr ""
-
-msgid "Deleting the license failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "Deleting the project will delete its repository and all related resources including issues, merge requests etc."
msgstr ""
@@ -8651,7 +8934,10 @@ msgstr ""
msgid "DesignManagement|The maximum number of designs allowed to be uploaded is %{upload_limit}. Please try again."
msgstr ""
-msgid "DesignManagement|To upload designs, you'll need to enable LFS. %{requirements_link_start}More information%{requirements_link_end}"
+msgid "DesignManagement|There was an error moving your designs. Please upload your designs below."
+msgstr ""
+
+msgid "DesignManagement|To upload designs, you'll need to enable LFS and have admin enable hashed storage. %{requirements_link_start}More information%{requirements_link_end}"
msgstr ""
msgid "DesignManagement|Unresolve thread"
@@ -8663,6 +8949,9 @@ msgstr ""
msgid "DesignManagement|Upload skipped."
msgstr ""
+msgid "DesignManagement|Your designs are being copied and are on their way… Please refresh to update."
+msgstr ""
+
msgid "DesignManagement|and %{moreCount} more."
msgstr ""
@@ -8720,6 +9009,9 @@ msgstr ""
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
+msgid "Direct member"
+msgstr ""
+
msgid "Direction"
msgstr ""
@@ -8768,9 +9060,6 @@ msgstr ""
msgid "Discard draft"
msgstr ""
-msgid "Discard review"
-msgstr ""
-
msgid "DiscordService|Discord Notifications"
msgstr ""
@@ -8839,10 +9128,10 @@ msgstr ""
msgid "Dismiss Merge Request promotion"
msgstr ""
-msgid "Dismiss Selected"
+msgid "Dismiss Value Stream Analytics introduction box"
msgstr ""
-msgid "Dismiss Value Stream Analytics introduction box"
+msgid "Dismiss selected"
msgstr ""
msgid "Dismiss trial promotion"
@@ -8893,9 +9182,6 @@ msgstr ""
msgid "Documents reindexed: %{processed_documents} (%{percentage}%%)"
msgstr ""
-msgid "Doing"
-msgstr ""
-
msgid "Domain"
msgstr ""
@@ -9091,9 +9377,6 @@ msgstr ""
msgid "Edit environment"
msgstr ""
-msgid "Edit file"
-msgstr ""
-
msgid "Edit files in the editor and commit changes here"
msgstr ""
@@ -9106,6 +9389,12 @@ msgstr ""
msgid "Edit identity for %{user_name}"
msgstr ""
+msgid "Edit in Web IDE"
+msgstr ""
+
+msgid "Edit in single-file editor"
+msgstr ""
+
msgid "Edit issues"
msgstr ""
@@ -9133,10 +9422,10 @@ msgstr ""
msgid "Editing"
msgstr ""
-msgid "Elasticsearch"
+msgid "Elasticsearch AWS IAM credentials"
msgstr ""
-msgid "Elasticsearch AWS IAM credentials"
+msgid "Elasticsearch HTTP client timeout value in seconds."
msgstr ""
msgid "Elasticsearch indexing restrictions"
@@ -9145,9 +9434,6 @@ msgstr ""
msgid "Elasticsearch indexing started"
msgstr ""
-msgid "Elasticsearch integration. Elasticsearch AWS IAM."
-msgstr ""
-
msgid "Elasticsearch reindexing is already in progress"
msgstr ""
@@ -9175,9 +9461,6 @@ msgstr ""
msgid "Email Notification"
msgstr ""
-msgid "Email address"
-msgstr ""
-
msgid "Email could not be sent"
msgstr ""
@@ -9241,6 +9524,9 @@ msgstr ""
msgid "Emails sent from Service Desk will have this name"
msgstr ""
+msgid "Emails sent to %{email} will still be supported"
+msgstr ""
+
msgid "Emails separated by comma"
msgstr ""
@@ -9274,9 +9560,18 @@ msgstr ""
msgid "Enable"
msgstr ""
+msgid "Enable %{link_start}Gitpod%{link_end} integration to launch a development environment in your browser directly from GitLab."
+msgstr ""
+
msgid "Enable Auto DevOps"
msgstr ""
+msgid "Enable Gitpod"
+msgstr ""
+
+msgid "Enable Gitpod?"
+msgstr ""
+
msgid "Enable HTML emails"
msgstr ""
@@ -9406,9 +9701,6 @@ msgstr ""
msgid "Encountered an error while rendering: %{err}"
msgstr ""
-msgid "End date"
-msgstr ""
-
msgid "Ends at (UTC)"
msgstr ""
@@ -9568,7 +9860,7 @@ msgstr ""
msgid "EnvironmentsDashboard|The environments dashboard provides a summary of each project's environments' status, including pipeline and alert statuses."
msgstr ""
-msgid "EnvironmentsDashboard|This dashboard displays a maximum of 7 projects and 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
+msgid "EnvironmentsDashboard|This dashboard displays 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
msgstr ""
msgid "Environments|An error occurred while canceling the auto stop, please try again"
@@ -9889,6 +10181,9 @@ msgstr ""
msgid "Error deleting project. Check logs for error details."
msgstr ""
+msgid "Error fetching burnup chart data"
+msgstr ""
+
msgid "Error fetching diverging counts for branches. Please try again."
msgstr ""
@@ -9967,6 +10262,9 @@ msgstr ""
msgid "Error occurred when saving assignees"
msgstr ""
+msgid "Error occurred when saving reviewers"
+msgstr ""
+
msgid "Error occurred when toggling the notification subscription"
msgstr ""
@@ -10219,10 +10517,13 @@ msgstr ""
msgid "Expand all"
msgstr ""
-msgid "Expand approvers"
+msgid "Expand all files"
msgstr ""
-msgid "Expand dropdown"
+msgid "Expand all threads"
+msgstr ""
+
+msgid "Expand approvers"
msgstr ""
msgid "Expand milestones"
@@ -10393,6 +10694,9 @@ msgstr ""
msgid "Failed to create Merge Request. Please try again."
msgstr ""
+msgid "Failed to create To-Do for the design."
+msgstr ""
+
msgid "Failed to create a branch for this issue. Please try again."
msgstr ""
@@ -10432,6 +10736,12 @@ msgstr ""
msgid "Failed to load authors. Please try again."
msgstr ""
+msgid "Failed to load branches. Please try again."
+msgstr ""
+
+msgid "Failed to load deploy keys."
+msgstr ""
+
msgid "Failed to load emoji list."
msgstr ""
@@ -10447,6 +10757,9 @@ msgstr ""
msgid "Failed to load groups & users."
msgstr ""
+msgid "Failed to load groups, users and deploy keys."
+msgstr ""
+
msgid "Failed to load labels. Please try again."
msgstr ""
@@ -10456,6 +10769,12 @@ msgstr ""
msgid "Failed to load related branches"
msgstr ""
+msgid "Failed to load sidebar confidential toggle"
+msgstr ""
+
+msgid "Failed to load sidebar lock status"
+msgstr ""
+
msgid "Failed to load stacktrace."
msgstr ""
@@ -10483,6 +10802,9 @@ msgstr ""
msgid "Failed to publish issue on status page."
msgstr ""
+msgid "Failed to remove To-Do for the design."
+msgstr ""
+
msgid "Failed to remove a Zoom meeting"
msgstr ""
@@ -10525,6 +10847,9 @@ msgstr ""
msgid "Failed to signing using smartcard authentication"
msgstr ""
+msgid "Failed to toggle To-Do for the design."
+msgstr ""
+
msgid "Failed to update branch!"
msgstr ""
@@ -10638,7 +10963,7 @@ msgstr ""
msgid "FeatureFlags|Edit User List"
msgstr ""
-msgid "FeatureFlags|Enable features for specific users and specific environments by defining feature flag strategies."
+msgid "FeatureFlags|Enable features for specific users and environments by configuring feature flag strategies."
msgstr ""
msgid "FeatureFlags|Environment Spec"
@@ -10698,7 +11023,7 @@ msgstr ""
msgid "FeatureFlags|Include additional user IDs"
msgstr ""
-msgid "FeatureFlags|Install a %{docs_link_anchored_start}compatible client library%{docs_link_anchored_end} and specify the API URL, application name, and instance ID during the configuration setup. %{docs_link_start}More Information%{docs_link_end}"
+msgid "FeatureFlags|Install a %{docsLinkAnchoredStart}compatible client library%{docsLinkAnchoredEnd} and specify the API URL, application name, and instance ID during the configuration setup. %{docsLinkStart}More Information%{docsLinkEnd}"
msgstr ""
msgid "FeatureFlags|Instance ID"
@@ -10710,6 +11035,9 @@ msgstr ""
msgid "FeatureFlags|Loading feature flags"
msgstr ""
+msgid "FeatureFlags|Loading user lists"
+msgstr ""
+
msgid "FeatureFlags|More information"
msgstr ""
@@ -10728,7 +11056,7 @@ msgstr ""
msgid "FeatureFlags|New feature flag"
msgstr ""
-msgid "FeatureFlags|New list"
+msgid "FeatureFlags|New user list"
msgstr ""
msgid "FeatureFlags|Percent of users"
@@ -10767,6 +11095,9 @@ msgstr ""
msgid "FeatureFlags|There was an error fetching the feature flags."
msgstr ""
+msgid "FeatureFlags|There was an error fetching the user lists."
+msgstr ""
+
msgid "FeatureFlags|There was an error retrieving user lists"
msgstr ""
@@ -10782,6 +11113,9 @@ msgstr ""
msgid "FeatureFlags|User List"
msgstr ""
+msgid "FeatureFlags|User Lists"
+msgstr ""
+
msgid "FeatureFlag|List"
msgstr ""
@@ -10809,15 +11143,6 @@ msgstr ""
msgid "Fetching incoming email"
msgstr ""
-msgid "Fetching licenses failed."
-msgstr ""
-
-msgid "Fetching licenses failed. The request endpoint was not found."
-msgstr ""
-
-msgid "Fetching licenses failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "File"
msgstr ""
@@ -10920,12 +11245,21 @@ msgstr ""
msgid "Filter by status"
msgstr ""
+msgid "Filter by test cases that are currently archived."
+msgstr ""
+
+msgid "Filter by test cases that are currently opened."
+msgstr ""
+
msgid "Filter by two-factor authentication"
msgstr ""
msgid "Filter by user"
msgstr ""
+msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
+msgstr ""
+
msgid "Filter pipelines"
msgstr ""
@@ -10941,7 +11275,7 @@ msgstr ""
msgid "Filter results..."
msgstr ""
-msgid "Filter your projects by name"
+msgid "Filter your repositories by name"
msgstr ""
msgid "Filter..."
@@ -10950,7 +11284,7 @@ msgstr ""
msgid "Find File"
msgstr ""
-msgid "Find bugs in your code with coverage-guided fuzzing"
+msgid "Find bugs in your code with coverage-guided fuzzing."
msgstr ""
msgid "Find by path"
@@ -10977,9 +11311,6 @@ msgstr ""
msgid "Finish editing this message first!"
msgstr ""
-msgid "Finish review"
-msgstr ""
-
msgid "Finish setting up your dedicated account for %{group_name}."
msgstr ""
@@ -11049,6 +11380,9 @@ msgstr ""
msgid "Footer message"
msgstr ""
+msgid "For a faster browsing experience, some files are collapsed by default."
+msgstr ""
+
msgid "For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
@@ -11058,6 +11392,9 @@ msgstr ""
msgid "For more info, read the documentation."
msgstr ""
+msgid "For more information on how the number of active users is calculated, see the %{self_managed_subscriptions_doc_link} documentation."
+msgstr ""
+
msgid "For more information, go to the "
msgstr ""
@@ -11196,6 +11533,9 @@ msgstr ""
msgid "Generate new token"
msgstr ""
+msgid "Generic package file size in bytes"
+msgstr ""
+
msgid "Geo"
msgstr ""
@@ -11457,6 +11797,9 @@ msgstr ""
msgid "Geo|Please refer to Geo Troubleshooting."
msgstr ""
+msgid "Geo|Primary node"
+msgstr ""
+
msgid "Geo|Project"
msgstr ""
@@ -11499,6 +11842,9 @@ msgstr ""
msgid "Geo|Review replication status, and resynchronize and reverify items with the primary node."
msgstr ""
+msgid "Geo|Secondary node"
+msgstr ""
+
msgid "Geo|Status"
msgstr ""
@@ -11538,6 +11884,9 @@ msgstr ""
msgid "Geo|URL must be a valid url (ex: https://gitlab.com)"
msgstr ""
+msgid "Geo|Undefined"
+msgstr ""
+
msgid "Geo|Unknown state"
msgstr ""
@@ -11613,10 +11962,16 @@ msgstr ""
msgid "GitHub import"
msgstr ""
+msgid "GitLab"
+msgstr ""
+
msgid "GitLab / Unsubscribe"
msgstr ""
-msgid "GitLab Enterprise Edition %{plan}"
+msgid "GitLab API"
+msgstr ""
+
+msgid "GitLab Billing Team."
msgstr ""
msgid "GitLab Group Runners can execute code for all the projects in this group."
@@ -11628,12 +11983,18 @@ msgstr ""
msgid "GitLab Issue"
msgstr ""
+msgid "GitLab Pages"
+msgstr ""
+
msgid "GitLab Service Desk is a simple way to allow people to create issues in your GitLab instance without needing their own user account. It provides a unique email address for end users to create issues in a project, and replies can be sent either through the GitLab interface or by email. End users will only see the thread through email."
msgstr ""
msgid "GitLab Shared Runners execute code of different projects on the same Runner unless you configure GitLab Runner Autoscale with MaxBuilds 1 (which it is on GitLab.com)."
msgstr ""
+msgid "GitLab Shell"
+msgstr ""
+
msgid "GitLab Support Bot"
msgstr ""
@@ -11643,7 +12004,7 @@ msgstr ""
msgid "GitLab User"
msgstr ""
-msgid "GitLab allows you to continue using your license even if you exceed the number of seats you purchased. You will be required to pay for these seats when you renew your license."
+msgid "GitLab Workhorse"
msgstr ""
msgid "GitLab commit"
@@ -11811,6 +12172,21 @@ msgstr ""
msgid "Gitlab Pages"
msgstr ""
+msgid "Gitpod"
+msgstr ""
+
+msgid "Gitpod|Add the URL to your Gitpod instance configured to read your GitLab projects."
+msgstr ""
+
+msgid "Gitpod|Enable Gitpod integration"
+msgstr ""
+
+msgid "Gitpod|Gitpod URL"
+msgstr ""
+
+msgid "Gitpod|e.g. https://gitpod.example.com"
+msgstr ""
+
msgid "Given access %{time_ago}"
msgstr ""
@@ -12318,9 +12694,6 @@ msgstr ""
msgid "GroupSAML|Valid SAML Response"
msgstr ""
-msgid "GroupSAML|With group managed accounts enabled, all the users without a group managed account will be excluded from the group."
-msgstr ""
-
msgid "GroupSAML|With prohibit outer forks flag enabled group members will be able to fork project only inside your group."
msgstr ""
@@ -12534,10 +12907,10 @@ msgstr ""
msgid "GroupsNew|Create group"
msgstr ""
-msgid "GroupsNew|GitLab group export"
+msgid "GroupsNew|Import"
msgstr ""
-msgid "GroupsNew|Import"
+msgid "GroupsNew|Import a GitLab group export file"
msgstr ""
msgid "GroupsNew|Import group"
@@ -12680,6 +13053,9 @@ msgid_plural "Hide charts"
msgstr[0] ""
msgstr[1] ""
+msgid "Hide comments on this file"
+msgstr ""
+
msgid "Hide details"
msgstr ""
@@ -12724,6 +13100,15 @@ msgstr ""
msgid "Highest role:"
msgstr ""
+msgid "HighlightBar|Alert events:"
+msgstr ""
+
+msgid "HighlightBar|Alert start time:"
+msgstr ""
+
+msgid "HighlightBar|Original alert:"
+msgstr ""
+
msgid "History"
msgstr ""
@@ -12901,6 +13286,9 @@ msgstr ""
msgid "If enabled, access to projects will be validated on an external service using their classification label."
msgstr ""
+msgid "If the number of active users exceeds the user limit, you will be charged for the number of %{users_over_license_link} at your next license reconciliation."
+msgstr ""
+
msgid "If there is no previous license or if the previous license has expired, some GitLab functionality will be blocked until a new, valid license is uploaded."
msgstr ""
@@ -12940,9 +13328,6 @@ msgstr ""
msgid "If your HTTP repository is not publicly accessible, add your credentials."
msgstr ""
-msgid "Iglu registry URL (optional)"
-msgstr ""
-
msgid "Ignore"
msgstr ""
@@ -12979,6 +13364,16 @@ msgstr ""
msgid "Import"
msgstr ""
+msgid "Import %d compatible repository"
+msgid_plural "Import %d compatible repositories"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Import %d repository"
+msgid_plural "Import %d repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Import CSV"
msgstr ""
@@ -12988,15 +13383,9 @@ msgstr ""
msgid "Import all compatible projects"
msgstr ""
-msgid "Import all compatible repositories"
-msgstr ""
-
msgid "Import all projects"
msgstr ""
-msgid "Import all repositories"
-msgstr ""
-
msgid "Import an exported GitLab project"
msgstr ""
@@ -13084,6 +13473,9 @@ msgstr ""
msgid "ImportProjects|Error importing repository %{project_safe_import_url} into %{project_full_path} - %{message}"
msgstr ""
+msgid "ImportProjects|Import repositories"
+msgstr ""
+
msgid "ImportProjects|Importing the project failed"
msgstr ""
@@ -13096,7 +13488,7 @@ msgstr ""
msgid "ImportProjects|Requesting your %{provider} repositories failed"
msgstr ""
-msgid "ImportProjects|Select the projects you want to import"
+msgid "ImportProjects|Select the repositories you want to import"
msgstr ""
msgid "ImportProjects|The remote data could not be imported."
@@ -13132,9 +13524,6 @@ msgstr ""
msgid "In order to enable Service Desk for your instance, you must first set up incoming email."
msgstr ""
-msgid "In order to gather accurate feature usage data, it can take 1 to 2 weeks to see your index."
-msgstr ""
-
msgid "In order to personalize your experience with GitLab%{br_tag}we would like to know a bit more about you."
msgstr ""
@@ -13165,18 +13554,30 @@ msgstr ""
msgid "IncidentManagement|Create incident"
msgstr ""
+msgid "IncidentManagement|Critical - S1"
+msgstr ""
+
msgid "IncidentManagement|Date created"
msgstr ""
msgid "IncidentManagement|Display your incidents in a dedicated view"
msgstr ""
+msgid "IncidentManagement|High - S2"
+msgstr ""
+
msgid "IncidentManagement|Incident"
msgstr ""
msgid "IncidentManagement|Incidents"
msgstr ""
+msgid "IncidentManagement|Low - S4"
+msgstr ""
+
+msgid "IncidentManagement|Medium - S3"
+msgstr ""
+
msgid "IncidentManagement|No incidents to display."
msgstr ""
@@ -13189,6 +13590,9 @@ msgstr ""
msgid "IncidentManagement|Published to status page"
msgstr ""
+msgid "IncidentManagement|Severity"
+msgstr ""
+
msgid "IncidentManagement|There are no closed incidents"
msgstr ""
@@ -13198,6 +13602,9 @@ msgstr ""
msgid "IncidentManagement|Unassigned"
msgstr ""
+msgid "IncidentManagement|Unknown"
+msgstr ""
+
msgid "IncidentManagement|Unpublished"
msgstr ""
@@ -13219,6 +13626,15 @@ msgstr ""
msgid "Incidents"
msgstr ""
+msgid "Incident|Alert details"
+msgstr ""
+
+msgid "Incident|Summary"
+msgstr ""
+
+msgid "Incident|There was an issue loading alert data. Please try again."
+msgstr ""
+
msgid "Include a Terms of Service agreement and Privacy Policy that all users must accept."
msgstr ""
@@ -13279,6 +13695,9 @@ msgstr ""
msgid "Information about additional Pages templates and how to install them can be found in our %{pages_getting_started_guide}."
msgstr ""
+msgid "Inherited"
+msgstr ""
+
msgid "Inherited:"
msgstr ""
@@ -13359,7 +13778,22 @@ msgstr ""
msgid "Instance administrators group already exists"
msgstr ""
-msgid "Instance license"
+msgid "InstanceStatistics|Groups"
+msgstr ""
+
+msgid "InstanceStatistics|Issues"
+msgstr ""
+
+msgid "InstanceStatistics|Merge Requests"
+msgstr ""
+
+msgid "InstanceStatistics|Pipelines"
+msgstr ""
+
+msgid "InstanceStatistics|Projects"
+msgstr ""
+
+msgid "InstanceStatistics|Users"
msgstr ""
msgid "Integration"
@@ -13371,6 +13805,12 @@ msgstr ""
msgid "Integrations"
msgstr ""
+msgid "Integrations|%{integration} settings saved and active."
+msgstr ""
+
+msgid "Integrations|%{integration} settings saved, but not active."
+msgstr ""
+
msgid "Integrations|All details"
msgstr ""
@@ -13380,6 +13820,12 @@ msgstr ""
msgid "Integrations|Comment settings:"
msgstr ""
+msgid "Integrations|Connection failed. Please check your settings."
+msgstr ""
+
+msgid "Integrations|Connection successful."
+msgstr ""
+
msgid "Integrations|Default settings are inherited from the group level."
msgstr ""
@@ -13395,6 +13841,15 @@ msgstr ""
msgid "Integrations|Includes commit title and branch"
msgstr ""
+msgid "Integrations|Projects using custom settings will not be impacted unless the project owner chooses to use instance-level defaults."
+msgstr ""
+
+msgid "Integrations|Save settings?"
+msgstr ""
+
+msgid "Integrations|Saving will update the default settings for all projects that are not using custom settings."
+msgstr ""
+
msgid "Integrations|Standard"
msgstr ""
@@ -13527,6 +13982,9 @@ msgstr ""
msgid "Invitation"
msgstr ""
+msgid "Invitation declined"
+msgstr ""
+
msgid "Invite"
msgstr ""
@@ -13578,6 +14036,42 @@ 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|%{linkStart}Read more%{linkEnd} about role permissions"
+msgstr ""
+
+msgid "InviteMembersModal|Access expiration date (optional)"
+msgstr ""
+
+msgid "InviteMembersModal|Cancel"
+msgstr ""
+
+msgid "InviteMembersModal|Choose a role permission"
+msgstr ""
+
+msgid "InviteMembersModal|GitLab member or Email address"
+msgstr ""
+
+msgid "InviteMembersModal|Invite"
+msgstr ""
+
+msgid "InviteMembersModal|Invite team members"
+msgstr ""
+
+msgid "InviteMembersModal|Search for members to invite"
+msgstr ""
+
+msgid "InviteMembersModal|User not invited. Feature coming soon!"
+msgstr ""
+
+msgid "InviteMembersModal|Users were succesfully added"
+msgstr ""
+
+msgid "InviteMembersModal|You're inviting members to the %{group_name} group"
+msgstr ""
+
+msgid "InviteMembers|Invite team members"
+msgstr ""
+
msgid "Invited"
msgstr ""
@@ -13632,10 +14126,13 @@ msgstr ""
msgid "Issue cannot be found."
msgstr ""
+msgid "Issue created from vulnerability %{vulnerability_link}"
+msgstr ""
+
msgid "Issue events"
msgstr ""
-msgid "Issue first depoloyed to production"
+msgid "Issue first deployed to production"
msgstr ""
msgid "Issue label"
@@ -13713,6 +14210,9 @@ msgstr ""
msgid "IssueTracker|Custom issue tracker"
msgstr ""
+msgid "IssueTracker|EWM work items tracker"
+msgstr ""
+
msgid "IssueTracker|Redmine issue tracker"
msgstr ""
@@ -13779,6 +14279,9 @@ msgstr ""
msgid "It looks like you have some draft commits in this branch."
msgstr ""
+msgid "It may be several days before you see feature usage data."
+msgstr ""
+
msgid "It must have a header row and at least two columns: the first column is the issue title and the second column is the issue description. The separator is automatically detected."
msgstr ""
@@ -14061,13 +14564,13 @@ msgstr ""
msgid "Join Zoom meeting"
msgstr ""
-msgid "Jul"
+msgid "Joined %{time_ago}"
msgstr ""
-msgid "July"
+msgid "Jul"
msgstr ""
-msgid "Jump to first unresolved thread"
+msgid "July"
msgstr ""
msgid "Jump to next unresolved thread"
@@ -14103,6 +14606,9 @@ msgstr ""
msgid "Keyboard shortcuts"
msgstr ""
+msgid "KeyboardKey|Ctrl+"
+msgstr ""
+
msgid "Keys"
msgstr ""
@@ -14151,6 +14657,9 @@ msgstr ""
msgid "LDAP Synchronization"
msgstr ""
+msgid "LDAP group settings"
+msgstr ""
+
msgid "LDAP settings"
msgstr ""
@@ -14160,6 +14669,9 @@ msgstr ""
msgid "LDAP sync in progress. This could take a few minutes. Refresh the page to see the changes."
msgstr ""
+msgid "LDAP synchronizations"
+msgstr ""
+
msgid "LFS"
msgstr ""
@@ -14240,7 +14752,16 @@ msgid_plural "Last %d days"
msgstr[0] ""
msgstr[1] ""
-msgid "Last %{days} days"
+msgid "Last 2 weeks"
+msgstr ""
+
+msgid "Last 30 days"
+msgstr ""
+
+msgid "Last 60 days"
+msgstr ""
+
+msgid "Last 90 days"
msgstr ""
msgid "Last Accessed On"
@@ -14318,6 +14839,9 @@ msgstr ""
msgid "Last used on:"
msgstr ""
+msgid "Last week"
+msgstr ""
+
msgid "LastCommit|authored"
msgstr ""
@@ -14333,6 +14857,9 @@ msgstr ""
msgid "Latest pipeline for the most recent commit on this branch"
msgstr ""
+msgid "Launch a ready-to-code development environment for your project."
+msgstr ""
+
msgid "Lead"
msgstr ""
@@ -14713,6 +15240,9 @@ msgstr ""
msgid "List of all merge commits"
msgstr ""
+msgid "List options"
+msgstr ""
+
msgid "List settings"
msgstr ""
@@ -14725,9 +15255,6 @@ msgstr ""
msgid "List your Bitbucket Server repositories"
msgstr ""
-msgid "Lists"
-msgstr ""
-
msgid "Live preview"
msgstr ""
@@ -14974,6 +15501,12 @@ msgstr ""
msgid "Mark as done"
msgstr ""
+msgid "Mark as draft"
+msgstr ""
+
+msgid "Mark as ready"
+msgstr ""
+
msgid "Mark as resolved"
msgstr ""
@@ -14995,6 +15528,24 @@ msgstr ""
msgid "Markdown is supported"
msgstr ""
+msgid "MarkdownEditor|Add a link (%{modifierKey}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add a link (%{modifier_key}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifierKey}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifier_key}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifierKey}I)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifier_key}I)"
+msgstr ""
+
msgid "Marked For Deletion At - %{deletion_time}"
msgstr ""
@@ -15079,7 +15630,25 @@ msgstr ""
msgid "Max access level"
msgstr ""
-msgid "Max seats used"
+msgid "Max role"
+msgstr ""
+
+msgid "Max size 15 MB"
+msgstr ""
+
+msgid "Maximum Conan package file size in bytes"
+msgstr ""
+
+msgid "Maximum Maven package file size in bytes"
+msgstr ""
+
+msgid "Maximum NPM package file size in bytes"
+msgstr ""
+
+msgid "Maximum NuGet package file size in bytes"
+msgstr ""
+
+msgid "Maximum PyPI package file size in bytes"
msgstr ""
msgid "Maximum Users:"
@@ -15211,6 +15780,18 @@ msgstr ""
msgid "Members with access to %{strong_start}%{group_name}%{strong_end}"
msgstr ""
+msgid "Members|%{time} by %{user}"
+msgstr ""
+
+msgid "Members|Expired"
+msgstr ""
+
+msgid "Members|No expiration set"
+msgstr ""
+
+msgid "Members|in %{time}"
+msgstr ""
+
msgid "Memory Usage"
msgstr ""
@@ -15397,9 +15978,6 @@ msgstr ""
msgid "MergeRequests|Thread will be unresolved"
msgstr ""
-msgid "MergeRequests|Toggle comments for this file"
-msgstr ""
-
msgid "MergeRequests|View file @ %{commitId}"
msgstr ""
@@ -15460,6 +16038,9 @@ msgstr ""
msgid "Merging immediately isn't recommended as it may negatively impact the existing merge train. Read the %{docsLinkStart}documentation%{docsLinkEnd} for more information."
msgstr ""
+msgid "Message"
+msgstr ""
+
msgid "Messages"
msgstr ""
@@ -15845,18 +16426,12 @@ msgid_plural "Milestones"
msgstr[0] ""
msgstr[1] ""
-msgid "Milestone does not support burnup charts"
-msgstr ""
-
msgid "Milestone lists not available with your current license"
msgstr ""
msgid "Milestone lists show all issues from the selected milestone."
msgstr ""
-msgid "Milestone must have a start and due date"
-msgstr ""
-
msgid "MilestoneSidebar|Closed:"
msgstr ""
@@ -16223,6 +16798,9 @@ msgstr ""
msgid "Namespace"
msgstr ""
+msgid "Namespace ID:"
+msgstr ""
+
msgid "Namespace is empty"
msgstr ""
@@ -16307,6 +16885,9 @@ msgstr ""
msgid "NetworkPolicies|Allow all outbound traffic from %{selector} to %{ruleSelector} on %{ports}"
msgstr ""
+msgid "NetworkPolicies|Are you sure you want to delete this policy? This action cannot be undone."
+msgstr ""
+
msgid "NetworkPolicies|Choose whether to enforce this policy."
msgstr ""
@@ -16316,12 +16897,21 @@ msgstr ""
msgid "NetworkPolicies|Define this policy's location, conditions and actions."
msgstr ""
+msgid "NetworkPolicies|Delete policy"
+msgstr ""
+
+msgid "NetworkPolicies|Delete policy: %{policy}"
+msgstr ""
+
msgid "NetworkPolicies|Deny all traffic"
msgstr ""
msgid "NetworkPolicies|Description"
msgstr ""
+msgid "NetworkPolicies|Edit policy"
+msgstr ""
+
msgid "NetworkPolicies|Editor mode"
msgstr ""
@@ -16349,6 +16939,9 @@ msgstr ""
msgid "NetworkPolicies|Name"
msgstr ""
+msgid "NetworkPolicies|Namespace"
+msgstr ""
+
msgid "NetworkPolicies|Network Policy"
msgstr ""
@@ -16400,6 +16993,9 @@ msgstr ""
msgid "NetworkPolicies|Rules"
msgstr ""
+msgid "NetworkPolicies|Save changes"
+msgstr ""
+
msgid "NetworkPolicies|Something went wrong, failed to update policy"
msgstr ""
@@ -16412,6 +17008,9 @@ msgstr ""
msgid "NetworkPolicies|Traffic that does not match any rule will be blocked."
msgstr ""
+msgid "NetworkPolicies|Unable to parse policy"
+msgstr ""
+
msgid "NetworkPolicies|YAML editor"
msgstr ""
@@ -16525,6 +17124,9 @@ msgstr ""
msgid "New Snippet"
msgstr ""
+msgid "New Test Case"
+msgstr ""
+
msgid "New User"
msgstr ""
@@ -16624,6 +17226,9 @@ msgstr ""
msgid "New tag"
msgstr ""
+msgid "New test case"
+msgstr ""
+
msgid "New users set to external"
msgstr ""
@@ -16696,7 +17301,7 @@ msgstr ""
msgid "No changes"
msgstr ""
-msgid "No changes between %{ref_start}%{source_branch}%{ref_end} and %{ref_start}%{target_branch}%{ref_end}"
+msgid "No changes between %{sourceBranch} and %{targetBranch}"
msgstr ""
msgid "No child epics match applied filters"
@@ -16711,6 +17316,9 @@ msgstr ""
msgid "No containers available"
msgstr ""
+msgid "No content to show"
+msgstr ""
+
msgid "No contributions"
msgstr ""
@@ -16786,9 +17394,6 @@ msgstr ""
msgid "No license. All rights reserved"
msgstr ""
-msgid "No licenses found."
-msgstr ""
-
msgid "No matches found"
msgstr ""
@@ -16801,6 +17406,9 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No members found"
+msgstr ""
+
msgid "No merge requests found"
msgstr ""
@@ -16822,6 +17430,9 @@ msgstr ""
msgid "No parent group"
msgstr ""
+msgid "No plan"
+msgstr ""
+
msgid "No pods available"
msgstr ""
@@ -16918,6 +17529,12 @@ msgstr ""
msgid "Not Implemented"
msgstr ""
+msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+msgstr ""
+
+msgid "Not all browsers support WebAuthn. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even from an unsupported browser."
+msgstr ""
+
msgid "Not all data has been processed yet, the accuracy of the chart for the selected timeframe is limited."
msgstr ""
@@ -17014,6 +17631,9 @@ msgstr ""
msgid "Notification settings saved"
msgstr ""
+msgid "NotificationEvent|Change reviewer merge request"
+msgstr ""
+
msgid "NotificationEvent|Close issue"
msgstr ""
@@ -17176,10 +17796,7 @@ msgstr ""
msgid "On track"
msgstr ""
-msgid "OnDemandScans|Attached branch"
-msgstr ""
-
-msgid "OnDemandScans|Attached branch is where the scan job runs."
+msgid "OnDemandScans|Could not fetch scanner profiles. Please refresh the page, or try again later."
msgstr ""
msgid "OnDemandScans|Could not fetch site profiles. Please refresh the page, or try again later."
@@ -17188,6 +17805,9 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
+msgid "OnDemandScans|Create a new scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Create a new site profile"
msgstr ""
@@ -17200,6 +17820,9 @@ msgstr ""
msgid "OnDemandScans|New on-demand DAST scan"
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 ""
@@ -17209,16 +17832,10 @@ msgstr ""
msgid "OnDemandScans|On-demand scans run outside the DevOps cycle and find vulnerabilities in your projects. %{learnMoreLinkStart}Learn more%{learnMoreLinkEnd}"
msgstr ""
-msgid "OnDemandScans|Only a passive scan can be performed on demand."
-msgstr ""
-
-msgid "OnDemandScans|Passive"
-msgstr ""
-
msgid "OnDemandScans|Run scan"
msgstr ""
-msgid "OnDemandScans|Scan mode"
+msgid "OnDemandScans|Scanner profile"
msgstr ""
msgid "OnDemandScans|Scanner settings"
@@ -17230,9 +17847,15 @@ msgstr ""
msgid "OnDemandScans|Select one of the existing profiles"
msgstr ""
+msgid "OnDemandScans|Site profile"
+msgstr ""
+
msgid "OnDemandScans|Site profiles"
msgstr ""
+msgid "OnDemandScans|Use existing scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Use existing site profile"
msgstr ""
@@ -17331,9 +17954,6 @@ msgstr ""
msgid "Open Selection"
msgstr ""
-msgid "Open Web IDE"
-msgstr ""
-
msgid "Open comment type dropdown"
msgstr ""
@@ -17439,6 +18059,9 @@ msgstr ""
msgid "Origin"
msgstr ""
+msgid "Orphaned member"
+msgstr ""
+
msgid "Other Labels"
msgstr ""
@@ -17454,6 +18077,9 @@ msgstr ""
msgid "Other visibility settings have been disabled by the administrator."
msgstr ""
+msgid "Our documentation includes an example DevOps Score report."
+msgstr ""
+
msgid "Out-of-compliance with this project's policies and should be removed"
msgstr ""
@@ -17478,6 +18104,9 @@ msgstr ""
msgid "Overwrite diverged branches"
msgstr ""
+msgid "Owned by %{image_tag}"
+msgstr ""
+
msgid "Owned by anyone"
msgstr ""
@@ -17499,6 +18128,9 @@ msgstr ""
msgid "Package deleted successfully"
msgstr ""
+msgid "Package file size limits"
+msgstr ""
+
msgid "Package recipe already exists"
msgstr ""
@@ -17514,9 +18146,6 @@ msgstr ""
msgid "Package type must be PyPi"
msgstr ""
-msgid "Package was removed"
-msgstr ""
-
msgid "PackageRegistry|%{name} version %{version} was created %{datetime}"
msgstr ""
@@ -17658,12 +18287,18 @@ msgstr ""
msgid "PackageRegistry|NuGet Command"
msgstr ""
+msgid "PackageRegistry|Package Registry"
+msgstr ""
+
msgid "PackageRegistry|Pip Command"
msgstr ""
msgid "PackageRegistry|Pipeline %{link} triggered %{datetime} by %{author}"
msgstr ""
+msgid "PackageRegistry|Publish and share packages for a variety of common package managers. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "PackageRegistry|Published to the %{project} Package Registry %{datetime}"
msgstr ""
@@ -17763,6 +18398,9 @@ msgstr ""
msgid "Page not found"
msgstr ""
+msgid "Page settings"
+msgstr ""
+
msgid "Page was successfully deleted"
msgstr ""
@@ -17904,7 +18542,7 @@ msgstr ""
msgid "Paste issue link"
msgstr ""
-msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Don't use your private SSH key."
+msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Do not paste your private SSH key, as that can compromise your identity."
msgstr ""
msgid "Patch to apply"
@@ -17931,6 +18569,9 @@ msgstr ""
msgid "Pending"
msgstr ""
+msgid "Pending comments"
+msgstr ""
+
msgid "People without permission will never get a notification and won't be able to comment."
msgstr ""
@@ -18129,6 +18770,9 @@ msgstr ""
msgid "Pipelines|Build with confidence"
msgstr ""
+msgid "Pipelines|By revoking a trigger you will break any processes making use of it. Are you sure?"
+msgstr ""
+
msgid "Pipelines|CI Lint"
msgstr ""
@@ -18141,6 +18785,15 @@ msgstr ""
msgid "Pipelines|Continuous Integration can help catch bugs by running your tests automatically, while Continuous Deployment can help you deliver code to your product environment."
msgstr ""
+msgid "Pipelines|Copy trigger token"
+msgstr ""
+
+msgid "Pipelines|Description"
+msgstr ""
+
+msgid "Pipelines|Edit"
+msgstr ""
+
msgid "Pipelines|Get started with Pipelines"
msgstr ""
@@ -18156,15 +18809,27 @@ msgstr ""
msgid "Pipelines|It is recommended the code is reviewed thoroughly before running this pipeline with the parent project's CI resource."
msgstr ""
+msgid "Pipelines|Last Used"
+msgstr ""
+
msgid "Pipelines|Loading Pipelines"
msgstr ""
msgid "Pipelines|More Information"
msgstr ""
+msgid "Pipelines|No triggers have been created yet. Add one using the form above."
+msgstr ""
+
+msgid "Pipelines|Owner"
+msgstr ""
+
msgid "Pipelines|Project cache successfully reset."
msgstr ""
+msgid "Pipelines|Revoke"
+msgstr ""
+
msgid "Pipelines|Run Pipeline"
msgstr ""
@@ -18189,6 +18854,15 @@ msgstr ""
msgid "Pipelines|This project is not currently set up to run pipelines."
msgstr ""
+msgid "Pipelines|Token"
+msgstr ""
+
+msgid "Pipelines|Trigger user has insufficient permissions to project"
+msgstr ""
+
+msgid "Pipelines|invalid"
+msgstr ""
+
msgid "Pipelines|parent"
msgstr ""
@@ -18447,10 +19121,10 @@ msgstr ""
msgid "Please provide attributes to update"
msgstr ""
-msgid "Please refer to %{docs_url}"
+msgid "Please reach out if you have any questions and we'll be happy to assist."
msgstr ""
-msgid "Please retype the email address."
+msgid "Please refer to %{docs_url}"
msgstr ""
msgid "Please select"
@@ -18480,6 +19154,9 @@ msgstr ""
msgid "Please set a new password before proceeding."
msgstr ""
+msgid "Please share your feedback about %{featureName} %{linkStart}in this issue%{linkEnd} to help us improve the experience."
+msgstr ""
+
msgid "Please solve the reCAPTCHA"
msgstr ""
@@ -18783,6 +19460,9 @@ msgstr ""
msgid "Profiles| You are going to change the username %{currentUsernameBold} to %{newUsernameBold}. Profile and projects will be redirected to the %{newUsername} namespace but this redirect will expire once the %{currentUsername} namespace is registered by another user or group. Please update your Git repository remotes as soon as possible."
msgstr ""
+msgid "Profiles|%{provider} Active"
+msgstr ""
+
msgid "Profiles|@username"
msgstr ""
@@ -18834,7 +19514,7 @@ msgstr ""
msgid "Profiles|Commit email"
msgstr ""
-msgid "Profiles|Connect"
+msgid "Profiles|Connect %{provider}"
msgstr ""
msgid "Profiles|Connected Accounts"
@@ -18858,6 +19538,9 @@ msgstr ""
msgid "Profiles|Disconnect"
msgstr ""
+msgid "Profiles|Disconnect %{provider}"
+msgstr ""
+
msgid "Profiles|Do not show on profile"
msgstr ""
@@ -18882,7 +19565,7 @@ msgstr ""
msgid "Profiles|Full name"
msgstr ""
-msgid "Profiles|Give your individual key a title. This will be publically visible."
+msgid "Profiles|Give your individual key a title."
msgstr ""
msgid "Profiles|Include private contributions on my profile"
@@ -18972,7 +19655,7 @@ msgstr ""
msgid "Profiles|The maximum file size allowed is 200KB."
msgstr ""
-msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it?"
+msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it? It will be publicly visible."
msgstr ""
msgid "Profiles|This email will be displayed on your public profile"
@@ -19047,6 +19730,9 @@ msgstr ""
msgid "Profiles|You don't have access to delete this user."
msgstr ""
+msgid "Profiles|You must transfer ownership or delete groups you are an owner of before you can delete your account"
+msgstr ""
+
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
@@ -19635,6 +20321,9 @@ msgstr ""
msgid "ProjectTemplates|GitLab Cluster Management"
msgstr ""
+msgid "ProjectTemplates|Gitpod/Spring Petclinic"
+msgstr ""
+
msgid "ProjectTemplates|Go Micro"
msgstr ""
@@ -20244,6 +20933,9 @@ msgstr ""
msgid "Publish to status page"
msgstr ""
+msgid "Published"
+msgstr ""
+
msgid "Published on status page"
msgstr ""
@@ -20361,9 +21053,15 @@ msgstr ""
msgid "Quick range"
msgstr ""
+msgid "Quickly and easily edit multiple files in your project."
+msgstr ""
+
msgid "README"
msgstr ""
+msgid "Rails"
+msgstr ""
+
msgid "Rake Tasks Help"
msgstr ""
@@ -20483,10 +21181,13 @@ msgstr ""
msgid "Register Two-Factor Authenticator"
msgstr ""
-msgid "Register U2F device"
+msgid "Register Universal Two-Factor (U2F) Device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register WebAuthn Device"
+msgstr ""
+
+msgid "Register device"
msgstr ""
msgid "Register for GitLab"
@@ -20498,9 +21199,6 @@ msgstr ""
msgid "Register with two-factor app"
msgstr ""
-msgid "Registration"
-msgstr ""
-
msgid "Registration|Checkout"
msgstr ""
@@ -20617,9 +21315,6 @@ msgstr ""
msgid "Release|Something went wrong while saving the release details"
msgstr ""
-msgid "Remediated: needs review"
-msgstr ""
-
msgid "Remediations"
msgstr ""
@@ -20725,6 +21420,9 @@ msgstr ""
msgid "Remove priority"
msgstr ""
+msgid "Remove report"
+msgstr ""
+
msgid "Remove secondary node"
msgstr ""
@@ -20737,6 +21435,12 @@ msgstr ""
msgid "Remove time estimate"
msgstr ""
+msgid "Remove user & report"
+msgstr ""
+
+msgid "Remove user from group"
+msgstr ""
+
msgid "Removed"
msgstr ""
@@ -20818,9 +21522,6 @@ msgstr ""
msgid "Removes time estimate."
msgstr ""
-msgid "Removing license…"
-msgstr ""
-
msgid "Removing this group also removes all child projects, including archived projects, and their resources."
msgstr ""
@@ -20905,6 +21606,9 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
+msgid "Reported by %{reporter}"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -20991,6 +21695,27 @@ msgstr ""
msgid "Repositories"
msgstr ""
+msgid "Repositories Analytics"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download Historic Test Coverage Data"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download historic test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Historic Test Coverage Data is available in raw format (.csv) for further analysis."
+msgstr ""
+
+msgid "RepositoriesAnalytics|Test Code Coverage"
+msgstr ""
+
+msgid "RepositoriesAnalytics|There was an error fetching the projects."
+msgstr ""
+
msgid "Repository"
msgstr ""
@@ -21069,9 +21794,15 @@ msgstr ""
msgid "Request parameter %{param} is missing."
msgstr ""
+msgid "Request review from"
+msgstr ""
+
msgid "Request to link SAML account must be authorized"
msgstr ""
+msgid "Requested"
+msgstr ""
+
msgid "Requested %{time_ago}"
msgstr ""
@@ -21090,6 +21821,9 @@ msgstr ""
msgid "Requests to these domain(s)/address(es) on the local network will be allowed when local requests from hooks and services are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 or 127.0.0.0/28 are supported. Domain wildcards are not supported currently. Use comma, semicolon, or newline to separate multiple entries. The allowlist can hold a maximum of 1000 entries. Domains should use IDNA encoding. Ex: example.com, 192.168.1.1, 127.0.0.0/28, xn--itlab-j1a.com."
msgstr ""
+msgid "Require admin approval for new sign-ups"
+msgstr ""
+
msgid "Require all users in this group to setup Two-factor authentication"
msgstr ""
@@ -21217,9 +21951,6 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
-msgid "Resolved by %{resolvedByName}"
-msgstr ""
-
msgid "Resolves IP addresses once and uses them to submit requests"
msgstr ""
@@ -21339,6 +22070,14 @@ msgstr ""
msgid "ReviewApp|Enable Review App"
msgstr ""
+msgid "Reviewer"
+msgid_plural "%d Reviewers"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Reviewer(s)"
+msgstr ""
+
msgid "Reviewing"
msgstr ""
@@ -21378,6 +22117,9 @@ msgstr ""
msgid "Rook"
msgstr ""
+msgid "Ruby"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -21456,6 +22198,63 @@ msgstr ""
msgid "Runners page."
msgstr ""
+msgid "Runners|Active"
+msgstr ""
+
+msgid "Runners|Architecture"
+msgstr ""
+
+msgid "Runners|Can run untagged jobs"
+msgstr ""
+
+msgid "Runners|Description"
+msgstr ""
+
+msgid "Runners|Group"
+msgstr ""
+
+msgid "Runners|IP Address"
+msgstr ""
+
+msgid "Runners|Last contact"
+msgstr ""
+
+msgid "Runners|Locked to this project"
+msgstr ""
+
+msgid "Runners|Maximum job timeout"
+msgstr ""
+
+msgid "Runners|Name"
+msgstr ""
+
+msgid "Runners|Platform"
+msgstr ""
+
+msgid "Runners|Property Name"
+msgstr ""
+
+msgid "Runners|Protected"
+msgstr ""
+
+msgid "Runners|Revision"
+msgstr ""
+
+msgid "Runners|Shared"
+msgstr ""
+
+msgid "Runners|Specific"
+msgstr ""
+
+msgid "Runners|Tags"
+msgstr ""
+
+msgid "Runners|Value"
+msgstr ""
+
+msgid "Runners|Version"
+msgstr ""
+
msgid "Runners|You have used %{quotaUsed} out of %{quotaLimit} of your shared Runners pipeline minutes."
msgstr ""
@@ -21468,6 +22267,9 @@ msgstr ""
msgid "Runs a number of housekeeping tasks within the current repository, such as compressing file revisions and removing unreachable objects."
msgstr ""
+msgid "SAML"
+msgstr ""
+
msgid "SAML SSO"
msgstr ""
@@ -21519,6 +22321,9 @@ msgstr ""
msgid "Save"
msgstr ""
+msgid "Save %{name} size limits"
+msgstr ""
+
msgid "Save Changes"
msgstr ""
@@ -21549,9 +22354,6 @@ msgstr ""
msgid "Save space and find tags in the Container Registry more easily. Enable the cleanup policy to remove stale tags and keep only the ones you need."
msgstr ""
-msgid "Save template"
-msgstr ""
-
msgid "Save variables"
msgstr ""
@@ -21594,9 +22396,6 @@ msgstr ""
msgid "Scope"
msgstr ""
-msgid "Scope not supported with disabled 'users_search' feature!"
-msgstr ""
-
msgid "Scoped issue boards"
msgstr ""
@@ -21723,9 +22522,6 @@ msgstr ""
msgid "Search requirements"
msgstr ""
-msgid "Search results…"
-msgstr ""
-
msgid "Search users"
msgstr ""
@@ -21798,6 +22594,11 @@ msgid_plural "SearchResults|commits"
msgstr[0] ""
msgstr[1] ""
+msgid "SearchResults|epic"
+msgid_plural "SearchResults|epics"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "SearchResults|issue"
msgid_plural "SearchResults|issues"
msgstr[0] ""
@@ -21842,10 +22643,10 @@ msgstr ""
msgid "Seat Link is disabled, and cannot be configured through this form."
msgstr ""
-msgid "Seats currently in use"
+msgid "Seats usage data as of %{last_enqueue_time}"
msgstr ""
-msgid "Seats in license"
+msgid "Seats usage data is updated every day at 12:00pm UTC"
msgstr ""
msgid "Secondary"
@@ -21899,6 +22700,9 @@ msgstr ""
msgid "SecurityConfiguration|Available for on-demand DAST"
msgstr ""
+msgid "SecurityConfiguration|By default, all analyzers are applied in order to cover all languages across your project, and only run if the language is detected in the Merge Request."
+msgstr ""
+
msgid "SecurityConfiguration|Configure"
msgstr ""
@@ -21929,16 +22733,19 @@ msgstr ""
msgid "SecurityConfiguration|Manage"
msgstr ""
+msgid "SecurityConfiguration|More information"
+msgstr ""
+
msgid "SecurityConfiguration|Not enabled"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|Security Control"
+msgid "SecurityConfiguration|SAST Configuration"
msgstr ""
-msgid "SecurityConfiguration|See documentation"
+msgid "SecurityConfiguration|Security Control"
msgstr ""
msgid "SecurityConfiguration|Status"
@@ -21950,6 +22757,9 @@ msgstr ""
msgid "SecurityConfiguration|Using custom settings. You won't receive automatic updates on this variable. %{anchorStart}Restore to default%{anchorEnd}"
msgstr ""
+msgid "SecurityConfiguration|View history"
+msgstr ""
+
msgid "SecurityConfiguration|You can quickly enable all security scanning tools by enabling %{linkStart}Auto DevOps%{linkEnd}."
msgstr ""
@@ -22028,9 +22838,6 @@ msgstr ""
msgid "SecurityReports|Learn more about setting up your dashboard"
msgstr ""
-msgid "SecurityReports|Load more vulnerabilities"
-msgstr ""
-
msgid "SecurityReports|Monitor vulnerabilities in your code"
msgstr ""
@@ -22310,7 +23117,7 @@ msgstr ""
msgid "Select status"
msgstr ""
-msgid "Select strategy activation method"
+msgid "Select strategy activation method."
msgstr ""
msgid "Select subscription"
@@ -22325,7 +23132,7 @@ msgstr ""
msgid "Select the custom project template source group."
msgstr ""
-msgid "Select timeframe"
+msgid "Select the environment scope for this feature flag."
msgstr ""
msgid "Select timezone"
@@ -22574,6 +23381,9 @@ msgstr ""
msgid "Set iteration"
msgstr ""
+msgid "Set limit to 0 to allow any file size."
+msgstr ""
+
msgid "Set max session time for web terminal."
msgstr ""
@@ -22652,10 +23462,13 @@ msgstr ""
msgid "Set up a %{type} Runner manually"
msgstr ""
+msgid "Set up a hardware device as a second factor to sign in."
+msgstr ""
+
msgid "Set up assertions/attributes/claims (email, first_name, last_name) and NameID according to %{docsLinkStart}the documentation %{icon}%{docsLinkEnd}"
msgstr ""
-msgid "Set up new U2F device"
+msgid "Set up new device"
msgstr ""
msgid "Set up new password"
@@ -22724,6 +23537,9 @@ msgstr ""
msgid "Sets weight to %{weight}."
msgstr ""
+msgid "Setting this to 0 means using the system default timeout value."
+msgstr ""
+
msgid "Settings"
msgstr ""
@@ -22739,6 +23555,15 @@ msgstr ""
msgid "Severity"
msgstr ""
+msgid "SeverityWidget|Severity"
+msgstr ""
+
+msgid "SeverityWidget|Severity: %{severity}"
+msgstr ""
+
+msgid "SeverityWidget|There was an error while updating severity."
+msgstr ""
+
msgid "Shards (%{shards})"
msgstr ""
@@ -22784,6 +23609,9 @@ msgstr ""
msgid "Show all requirements."
msgstr ""
+msgid "Show all test cases."
+msgstr ""
+
msgid "Show archived projects"
msgstr ""
@@ -22796,6 +23624,9 @@ msgstr ""
msgid "Show comments"
msgstr ""
+msgid "Show comments on this file"
+msgstr ""
+
msgid "Show comments only"
msgstr ""
@@ -22841,6 +23672,12 @@ msgstr ""
msgid "Show parent subgroups"
msgstr ""
+msgid "Show the Closed list"
+msgstr ""
+
+msgid "Show the Open list"
+msgstr ""
+
msgid "Show whitespace changes"
msgstr ""
@@ -22884,9 +23721,6 @@ msgstr ""
msgid "Sidebar|Assign health status"
msgstr ""
-msgid "Sidebar|Change weight"
-msgstr ""
-
msgid "Sidebar|Health status"
msgstr ""
@@ -23070,6 +23904,9 @@ msgstr ""
msgid "Snippets|Add another file %{num}/%{total}"
msgstr ""
+msgid "Snippets|Authored %{time_ago} by %{author}"
+msgstr ""
+
msgid "Snippets|Delete file"
msgstr ""
@@ -23097,6 +23934,9 @@ msgstr ""
msgid "Solution"
msgstr ""
+msgid "Some changes are not shown"
+msgstr ""
+
msgid "Some child epics may be hidden due to applied filters"
msgstr ""
@@ -23463,6 +24303,12 @@ msgstr ""
msgid "Source (branch or tag)"
msgstr ""
+msgid "Source Branch"
+msgstr ""
+
+msgid "Source branch: %{source_branch_open}%{source_branch}%{source_branch_close}"
+msgstr ""
+
msgid "Source code"
msgstr ""
@@ -23628,9 +24474,6 @@ msgstr ""
msgid "Start and due date"
msgstr ""
-msgid "Start by choosing a group to see how your team is spending time. You can then drill down to the project level."
-msgstr ""
-
msgid "Start by choosing a group to start exploring the merge requests in that group. You can then proceed to filter by projects, labels, milestones and authors."
msgstr ""
@@ -23712,18 +24555,27 @@ msgstr ""
msgid "StaticSiteEditor|3. Assign a person to review and accept the merge request."
msgstr ""
+msgid "StaticSiteEditor|A link to view the merge request will appear once ready."
+msgstr ""
+
msgid "StaticSiteEditor|An error occurred while submitting your changes."
msgstr ""
msgid "StaticSiteEditor|Branch could not be created."
msgstr ""
+msgid "StaticSiteEditor|Copy update"
+msgstr ""
+
msgid "StaticSiteEditor|Could not commit the content changes."
msgstr ""
msgid "StaticSiteEditor|Could not create merge request."
msgstr ""
+msgid "StaticSiteEditor|Creating your merge request"
+msgstr ""
+
msgid "StaticSiteEditor|Incompatible file content"
msgstr ""
@@ -23745,6 +24597,9 @@ msgstr ""
msgid "StaticSiteEditor|View documentation"
msgstr ""
+msgid "StaticSiteEditor|You can set an assignee to get your changes reviewed and deployed once your merge request is created."
+msgstr ""
+
msgid "StaticSiteEditor|Your merge request has been created"
msgstr ""
@@ -23874,15 +24729,15 @@ msgstr ""
msgid "Submit %{humanized_resource_name}"
msgstr ""
-msgid "Submit Changes"
-msgstr ""
-
msgid "Submit a review"
msgstr ""
msgid "Submit as spam"
msgstr ""
+msgid "Submit changes"
+msgstr ""
+
msgid "Submit feedback"
msgstr ""
@@ -24036,6 +24891,9 @@ msgstr ""
msgid "Successfully deleted U2F device."
msgstr ""
+msgid "Successfully deleted WebAuthn device."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -24354,9 +25212,6 @@ msgstr ""
msgid "Template to append to all Service Desk issues"
msgstr ""
-msgid "Template was successfully saved."
-msgstr ""
-
msgid "Templates"
msgstr ""
@@ -24435,10 +25290,28 @@ msgid_plural "Test coverage: %d hits"
msgstr[0] ""
msgstr[1] ""
-msgid "Test failed."
+msgid "Test settings"
msgstr ""
-msgid "Test settings and save changes"
+msgid "TestCases|New Test Case"
+msgstr ""
+
+msgid "TestCases|New test case"
+msgstr ""
+
+msgid "TestCases|Search test cases"
+msgstr ""
+
+msgid "TestCases|Something went wrong while creating a test case."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching count of test cases."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching test cases list."
+msgstr ""
+
+msgid "TestCases|Submit test case"
msgstr ""
msgid "TestHooks|Ensure one of your projects has merge requests."
@@ -24504,6 +25377,9 @@ msgstr ""
msgid "Thank you for signing up for your free trial! You will get additional instructions in your inbox shortly."
msgstr ""
+msgid "Thank you for your business."
+msgstr ""
+
msgid "Thank you for your feedback!"
msgstr ""
@@ -24563,9 +25439,6 @@ msgstr ""
msgid "The URL to use for connecting to Elasticsearch. Use a comma-separated list to support clustering (e.g., \"http://localhost:9200, http://localhost:9201\")."
msgstr ""
-msgid "The Web IDE offers advanced syntax highlighting capabilities and more."
-msgstr ""
-
msgid "The X509 Certificate to use when mutual TLS is required to communicate with the external authorization service. If left blank, the server certificate is still validated when accessing over HTTPS."
msgstr ""
@@ -24676,6 +25549,9 @@ msgstr ""
msgid "The form contains the following error:"
msgstr ""
+msgid "The form contains the following warning:"
+msgstr ""
+
msgid "The global settings require you to enable Two-Factor Authentication for your account."
msgstr ""
@@ -24790,9 +25666,6 @@ msgstr ""
msgid "The private key to use when a client certificate is provided. This value is encrypted at rest."
msgstr ""
-msgid "The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The project can be accessed by any logged in user."
msgstr ""
@@ -24829,7 +25702,7 @@ msgstr ""
msgid "The remote repository is being updated..."
msgstr ""
-msgid "The repository can be commited to, and issues, comments and other entities can be created."
+msgid "The repository can be committed to, and issues, comments and other entities can be created."
msgstr ""
msgid "The repository for this project does not exist."
@@ -24883,9 +25756,6 @@ msgstr ""
msgid "The time taken by each data entry gathered by that stage."
msgstr ""
-msgid "The total stage shows the time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The update action will time out after %{number_of_minutes} minutes. For big repositories, use a clone/push combination."
msgstr ""
@@ -24949,6 +25819,9 @@ msgstr ""
msgid "There are no archived requirements"
msgstr ""
+msgid "There are no archived test cases"
+msgstr ""
+
msgid "There are no changes"
msgstr ""
@@ -24988,6 +25861,9 @@ msgstr ""
msgid "There are no open requirements"
msgstr ""
+msgid "There are no open test cases"
+msgstr ""
+
msgid "There are no packages yet"
msgstr ""
@@ -25000,6 +25876,9 @@ msgstr ""
msgid "There is a limit of %{ci_project_subscriptions_limit} subscriptions from or to a project."
msgstr ""
+msgid "There is already a To-Do for this design."
+msgstr ""
+
msgid "There is already a repository with that name on disk"
msgstr ""
@@ -25018,6 +25897,9 @@ msgstr ""
msgid "There was a problem communicating with your device."
msgstr ""
+msgid "There was a problem fetching branches."
+msgstr ""
+
msgid "There was a problem fetching groups."
msgstr ""
@@ -25246,9 +26128,15 @@ msgstr ""
msgid "This action can lead to data loss. To prevent accidental actions we ask you to confirm your intention."
msgstr ""
+msgid "This action cannot be undone, and will permanently delete the %{key} SSH key"
+msgstr ""
+
msgid "This action cannot be undone. You will lose the project's repository and all content: issues, merge requests, etc."
msgstr ""
+msgid "This action has been performed too many times. Try again later."
+msgstr ""
+
msgid "This action will %{strongOpen}permanently delete%{strongClose} %{codeOpen}%{project}%{codeClose} %{strongOpen}immediately%{strongClose}, including its repositories and all content: issues, merge requests, etc."
msgstr ""
@@ -25276,9 +26164,6 @@ msgstr ""
msgid "This board's scope is reduced"
msgstr ""
-msgid "This branch has changed since you started editing. Would you like to create a new branch?"
-msgstr ""
-
msgid "This chart could not be displayed"
msgstr ""
@@ -25405,15 +26290,9 @@ msgstr ""
msgid "This is a security log of important events involving your account."
msgstr ""
-msgid "This is the author's first Merge Request to this project."
-msgstr ""
-
msgid "This is the highest peak of users on your installation since the license started."
msgstr ""
-msgid "This is the maximum number of users that have existed at the same time since the license started. This is the minimum number of seats you will need to buy when you renew your license."
-msgstr ""
-
msgid "This is the number of currently active users on your installation, and this is the minimum number you need to purchase when you renew your license."
msgstr ""
@@ -25645,6 +26524,15 @@ msgstr ""
msgid "This user has no identities"
msgstr ""
+msgid "This user has previously committed to the %{name} project."
+msgstr ""
+
+msgid "This user has the %{access} role in the %{name} project."
+msgstr ""
+
+msgid "This user is the author of this %{noteable}."
+msgstr ""
+
msgid "This user will be the author of all events in the activity feed that are the result of an update, like new branches being created or new commits being pushed to existing branches."
msgstr ""
@@ -25675,6 +26563,9 @@ msgstr ""
msgid "Threat Monitoring"
msgstr ""
+msgid "ThreatMonitoring|All Environments"
+msgstr ""
+
msgid "ThreatMonitoring|Anomalous Requests"
msgstr ""
@@ -25702,9 +26593,6 @@ msgstr ""
msgid "ThreatMonitoring|Operations Per Second"
msgstr ""
-msgid "ThreatMonitoring|Overview"
-msgstr ""
-
msgid "ThreatMonitoring|Packet Activity"
msgstr ""
@@ -25723,6 +26611,9 @@ msgstr ""
msgid "ThreatMonitoring|Something went wrong, unable to fetch statistics"
msgstr ""
+msgid "ThreatMonitoring|Statistics"
+msgstr ""
+
msgid "ThreatMonitoring|The firewall is not installed or has been disabled. To view this data, ensure the web application firewall is installed and enabled for your cluster."
msgstr ""
@@ -26114,6 +27005,9 @@ msgstr ""
msgid "To update Snippets with multiple files, you must use the `files` parameter"
msgstr ""
+msgid "To use Gitpod you must first enable the feature in the integrations section of your %{user_prefs}."
+msgstr ""
+
msgid "To view all %{scannedResourcesCount} scanned URLs, please download the CSV file"
msgstr ""
@@ -26147,9 +27041,6 @@ msgstr ""
msgid "Toggle Sidebar"
msgstr ""
-msgid "Toggle all threads"
-msgstr ""
-
msgid "Toggle backtrace"
msgstr ""
@@ -26174,9 +27065,6 @@ msgstr ""
msgid "Toggle navigation"
msgstr ""
-msgid "Toggle project"
-msgstr ""
-
msgid "Toggle sidebar"
msgstr ""
@@ -26216,6 +27104,9 @@ msgstr ""
msgid "Too many projects enabled. You will need to manage them via the console or the API."
msgstr ""
+msgid "Too much data"
+msgstr ""
+
msgid "Topics (optional)"
msgstr ""
@@ -26234,6 +27125,9 @@ msgstr ""
msgid "Total cores (CPUs)"
msgstr ""
+msgid "Total days to completion"
+msgstr ""
+
msgid "Total issues"
msgstr ""
@@ -26330,6 +27224,9 @@ msgstr ""
msgid "Trending"
msgstr ""
+msgid "Trials|Create a new group to start your GitLab Gold trial."
+msgstr ""
+
msgid "Trials|Go back to GitLab"
msgstr ""
@@ -26339,6 +27236,15 @@ msgstr ""
msgid "Trials|You can always resume this process by selecting your avatar and choosing 'Start a Gold trial'"
msgstr ""
+msgid "Trials|You can apply your trial to a new group or an existing group."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group or your personal account."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group, an existing group, or your personal account."
+msgstr ""
+
msgid "Trials|You won't get a free trial right now but you can always resume this process by clicking on your avatar and choosing 'Start a free trial'"
msgstr ""
@@ -26408,6 +27314,9 @@ msgstr ""
msgid "Try using a different search term to find the file you are looking for."
msgstr ""
+msgid "Trying to communicate with your device. Plug it in (if needed) and press the button on the device now."
+msgstr ""
+
msgid "Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now."
msgstr ""
@@ -26495,6 +27404,12 @@ msgstr ""
msgid "URL or request ID"
msgstr ""
+msgid "USER %{user} WILL BE REMOVED! Are you sure?"
+msgstr ""
+
+msgid "USER WILL BE BLOCKED! Are you sure?"
+msgstr ""
+
msgid "UTC"
msgstr ""
@@ -26552,9 +27467,6 @@ msgstr ""
msgid "Unable to load the merge request widget. Try reloading the page."
msgstr ""
-msgid "Unable to resolve"
-msgstr ""
-
msgid "Unable to save iteration. Please try again"
msgstr ""
@@ -26603,6 +27515,9 @@ msgstr ""
msgid "Undo ignore"
msgstr ""
+msgid "Unexpected error"
+msgstr ""
+
msgid "Unfortunately, your email message to GitLab could not be processed."
msgstr ""
@@ -26636,6 +27551,9 @@ msgstr ""
msgid "Unknown response text"
msgstr ""
+msgid "Unless otherwise agreed to in writing with GitLab, by clicking \"Upload License\" you agree that your use of GitLab Software is subject to the %{eula_link_start}Terms of Service%{eula_link_end}."
+msgstr ""
+
msgid "Unlimited"
msgstr ""
@@ -27002,9 +27920,6 @@ msgstr ""
msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
msgstr ""
-msgid "Use a hardware device to add the second factor of authentication."
-msgstr ""
-
msgid "Use an one time password authenticator on your mobile device or computer to enable two-factor authentication (2FA)."
msgstr ""
@@ -27278,13 +28193,13 @@ msgstr ""
msgid "Users"
msgstr ""
-msgid "Users in License:"
+msgid "Users in License"
msgstr ""
-msgid "Users or groups set as approvers in the project's or merge request's settings."
+msgid "Users in License:"
msgstr ""
-msgid "Users outside of license"
+msgid "Users or groups set as approvers in the project's or merge request's settings."
msgstr ""
msgid "Users over License:"
@@ -27302,9 +28217,6 @@ msgstr ""
msgid "Users with a Guest role or those who don't belong to a Project or Group will not use a seat from your license."
msgstr ""
-msgid "Users with a Guest role or those who don't belong to any projects or groups don't count towards seats in use."
-msgstr ""
-
msgid "UsersSelect|%{name} + %{length} more"
msgstr ""
@@ -27344,9 +28256,6 @@ msgstr ""
msgid "Validations failed."
msgstr ""
-msgid "Validity"
-msgstr ""
-
msgid "Value"
msgstr ""
@@ -27365,6 +28274,9 @@ msgstr ""
msgid "Value Stream Name"
msgstr ""
+msgid "ValueStreamAnalyticsStage|We don't have enough data to show this stage."
+msgstr ""
+
msgid "ValueStreamAnalytics|%{days}d"
msgstr ""
@@ -27621,6 +28533,9 @@ msgstr ""
msgid "VisualReviewApp|Steps 1 and 2 (and sometimes 3) are performed once by the developer before requesting feedback. Steps 3 (if necessary), 4 is performed by the reviewer each time they perform a review."
msgstr ""
+msgid "Visualization"
+msgstr ""
+
msgid "Vulnerabilities"
msgstr ""
@@ -27648,34 +28563,31 @@ msgstr ""
msgid "VulnerabilityChart|Severity"
msgstr ""
-msgid "VulnerabilityManagement|A true-positive and will fix"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Change status"
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|Confirm"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Confirmed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
-msgstr ""
-
-msgid "VulnerabilityManagement|Detected %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|A true-positive and will fix"
msgstr ""
-msgid "VulnerabilityManagement|Dismiss"
+msgid "VulnerabilityManagement|Change status"
msgstr ""
-msgid "VulnerabilityManagement|Dismissed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
msgstr ""
-msgid "VulnerabilityManagement|Resolved"
+msgid "VulnerabilityManagement|Detected"
msgstr ""
-msgid "VulnerabilityManagement|Resolved %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Needs triage"
msgstr ""
msgid "VulnerabilityManagement|Something went wrong while trying to delete the comment. Please try again later."
@@ -27726,6 +28638,9 @@ msgstr ""
msgid "Vulnerability|%{scannerName} (version %{scannerVersion})"
msgstr ""
+msgid "Vulnerability|Activity"
+msgstr ""
+
msgid "Vulnerability|Class"
msgstr ""
@@ -27738,6 +28653,9 @@ msgstr ""
msgid "Vulnerability|Description"
msgstr ""
+msgid "Vulnerability|Detected"
+msgstr ""
+
msgid "Vulnerability|Evidence"
msgstr ""
@@ -27801,6 +28719,9 @@ msgstr ""
msgid "Warning: Displaying this diagram might cause performance issues on this page."
msgstr ""
+msgid "We are currently unable to fetch data for the pipeline header."
+msgstr ""
+
msgid "We are currently unable to fetch data for this graph."
msgstr ""
@@ -27840,6 +28761,12 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
+msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
+msgstr ""
+
+msgid "We would like to inform you that your subscription GitLab Enterprise Edition %{plan_name} is nearing its user limit. You have %{active_user_count} active users, which is almost at the user limit of %{maximum_user_count}."
+msgstr ""
+
msgid "We've found no vulnerabilities"
msgstr ""
@@ -27855,6 +28782,12 @@ msgstr ""
msgid "Web terminal"
msgstr ""
+msgid "WebAuthn Devices (%{length})"
+msgstr ""
+
+msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
+msgstr ""
+
msgid "WebIDE|Merge request"
msgstr ""
@@ -27993,15 +28926,9 @@ msgstr ""
msgid "Welcome to the guided GitLab tour"
msgstr ""
-msgid "Welcome to your Issue Board!"
-msgstr ""
-
msgid "Welcome to your issue board!"
msgstr ""
-msgid "We’ve been making changes to %{featureName} and we’d love your feedback %{linkStart}in this issue%{linkEnd} to help us improve the experience."
-msgstr ""
-
msgid "What are you searching for?"
msgstr ""
@@ -28020,6 +28947,9 @@ msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
msgstr ""
+msgid "When enabled, any user visiting %{host} and creating an account will have to be explicitly approved by the admin before they can login. This setting is effective only if sign-ups are enabled."
+msgstr ""
+
msgid "When enabled, any user visiting %{host} will be able to create an account."
msgstr ""
@@ -28244,6 +29174,9 @@ msgstr ""
msgid "With requirements, you can set criteria to check your products against."
msgstr ""
+msgid "With test cases, you can define conditions for your project to meet in determining quality"
+msgstr ""
+
msgid "Withdraw Access Request"
msgstr ""
@@ -28259,6 +29192,9 @@ msgstr ""
msgid "Workflow Help"
msgstr ""
+msgid "Would you like to create a new branch?"
+msgstr ""
+
msgid "Write"
msgstr ""
@@ -28280,6 +29216,9 @@ msgstr ""
msgid "Wrong extern UID provided. Make sure Auth0 is configured correctly."
msgstr ""
+msgid "YYYY-MM-DD"
+msgstr ""
+
msgid "Yes"
msgstr ""
@@ -28337,7 +29276,7 @@ msgstr ""
msgid "You are going to remove the fork relationship from %{project_full_name}. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "You are going to transfer %{project_full_name} to another owner. Are you ABSOLUTELY sure?"
+msgid "You are going to transfer %{project_full_name} to another namespace. Are you ABSOLUTELY sure?"
msgstr ""
msgid "You are going to turn off the confidentiality. This means %{strongStart}everyone%{strongEnd} will be able to see and leave a comment on this %{issuableType}."
@@ -28397,9 +29336,6 @@ msgstr ""
msgid "You can always edit this later"
msgstr ""
-msgid "You can apply your Trial to your Personal account or create a New Group."
-msgstr ""
-
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings"
msgstr ""
@@ -28421,12 +29357,18 @@ msgstr ""
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
+msgid "You can find more information about GitLab subscriptions in %{subscriptions_doc_link}."
+msgstr ""
+
msgid "You can generate an access token scoped to this project for each application to use the GitLab API."
msgstr ""
msgid "You can get started by cloning the repository or start adding files to it with one of the following options."
msgstr ""
+msgid "You can group test cases using labels. To learn about the future direction of this feature, visit %{linkStart}Quality Management direction page%{linkEnd}."
+msgstr ""
+
msgid "You can invite a new member to %{project_name} or invite another group."
msgstr ""
@@ -28442,6 +29384,9 @@ msgstr ""
msgid "You can notify the app / group or a project by sending them an email notification"
msgstr ""
+msgid "You can now close this window."
+msgstr ""
+
msgid "You can now export your security dashboard to a CSV report."
msgstr ""
@@ -28490,9 +29435,6 @@ msgstr ""
msgid "You can test your .gitlab-ci.yml in %{linkStart}CI Lint%{linkEnd}."
msgstr ""
-msgid "You can try again using %{begin_link}basic search%{end_link}"
-msgstr ""
-
msgid "You cannot access the raw file. Please wait a minute."
msgstr ""
@@ -28544,6 +29486,9 @@ msgstr ""
msgid "You don't have any U2F devices registered yet."
msgstr ""
+msgid "You don't have any WebAuthn devices registered yet."
+msgstr ""
+
msgid "You don't have any active chat names."
msgstr ""
@@ -28631,6 +29576,9 @@ msgstr ""
msgid "You must accept our Terms of Service and privacy policy in order to register an account"
msgstr ""
+msgid "You must be logged in to search across all of GitLab"
+msgstr ""
+
msgid "You must disassociate %{domain} from all clusters it is attached to before deletion."
msgstr ""
@@ -28670,7 +29618,7 @@ msgstr ""
msgid "You need to be logged in."
msgstr ""
-msgid "You need to register a two-factor authentication app before you can set up a U2F device."
+msgid "You need to register a two-factor authentication app before you can set up a device."
msgstr ""
msgid "You need to set terms to be enforced"
@@ -28688,6 +29636,9 @@ msgstr ""
msgid "You reached %{usage_in_percent} of %{namespace_name}'s storage capacity (%{used_storage} of %{storage_limit})"
msgstr ""
+msgid "You successfully declined the invitation"
+msgstr ""
+
msgid "You tried to fork %{link_to_the_project} but it failed for the following reason:"
msgstr ""
@@ -28853,10 +29804,13 @@ msgstr ""
msgid "Your U2F device did not send a valid JSON response."
msgstr ""
-msgid "Your U2F device needs to be set up. Plug it in (if not already) and click the button on the left."
+msgid "Your U2F device was registered!"
msgstr ""
-msgid "Your U2F device was registered!"
+msgid "Your WebAuthn device did not send a valid JSON response."
+msgstr ""
+
+msgid "Your WebAuthn device was registered!"
msgstr ""
msgid "Your access request to the %{source_type} has been withdrawn."
@@ -28880,6 +29834,9 @@ msgstr ""
msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
msgstr ""
+msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
+msgstr ""
+
msgid "Your changes can be committed to %{branch_name} because a merge request is open."
msgstr ""
@@ -28916,6 +29873,12 @@ msgstr ""
msgid "Your deployment services will be broken, you will need to manually fix the services after renaming."
msgstr ""
+msgid "Your device is not compatible with GitLab. Please try another device"
+msgstr ""
+
+msgid "Your device needs to be set up. Plug it in (if needed) and click the button on the left."
+msgstr ""
+
msgid "Your device was successfully set up! Give it a name and register it with the GitLab server."
msgstr ""
@@ -29029,9 +29992,6 @@ msgstr[1] ""
msgid "access:"
msgstr ""
-msgid "activated"
-msgstr ""
-
msgid "added %{created_at_timeago}"
msgstr ""
@@ -29104,9 +30064,21 @@ msgstr ""
msgid "by %{user}"
msgstr ""
+msgid "cannot be a date in the past"
+msgstr ""
+
msgid "cannot be changed if a personal project has container registry tags."
msgstr ""
+msgid "cannot be changed if shared runners are enabled"
+msgstr ""
+
+msgid "cannot be enabled because parent group does not allow it"
+msgstr ""
+
+msgid "cannot be enabled because parent group has shared Runners disabled"
+msgstr ""
+
msgid "cannot be enabled unless all domains have TLS certificates"
msgstr ""
@@ -29152,7 +30124,7 @@ msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about SAST %{linkEndTag}"
msgstr ""
-msgid "ciReport|%{linkStartTag}Learn more about Secret Scanning %{linkEndTag}"
+msgid "ciReport|%{linkStartTag}Learn more about Secret Detection %{linkEndTag}"
msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about codequality reports %{linkEndTag}"
@@ -29467,9 +30439,6 @@ msgstr ""
msgid "error"
msgstr ""
-msgid "error code:"
-msgstr ""
-
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr ""
@@ -29491,6 +30460,9 @@ msgstr ""
msgid "failed to dismiss associated finding(id=%{finding_id}): %{message}"
msgstr ""
+msgid "failed to revert associated finding(id=%{finding_id}) to detected"
+msgstr ""
+
msgid "file"
msgid_plural "files"
msgstr[0] ""
@@ -30033,6 +31005,9 @@ msgstr ""
msgid "must be a root namespace"
msgstr ""
+msgid "must be a valid IPv4 or IPv6 address"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -30069,6 +31044,9 @@ msgstr ""
msgid "no expiration"
msgstr ""
+msgid "no name set"
+msgstr ""
+
msgid "no one can merge"
msgstr ""
@@ -30247,9 +31225,6 @@ msgstr ""
msgid "security Reports|There was an error creating the merge request"
msgstr ""
-msgid "settings saved, but not activated"
-msgstr ""
-
msgid "severity|Critical"
msgstr ""
@@ -30376,9 +31351,6 @@ msgstr ""
msgid "toggle collapse"
msgstr ""
-msgid "toggle dropdown"
-msgstr ""
-
msgid "triggered"
msgstr ""
@@ -30406,6 +31378,9 @@ msgstr ""
msgid "user avatar"
msgstr ""
+msgid "user preferences"
+msgstr ""
+
msgid "username"
msgstr ""
diff --git a/locale/fi_FI/gitlab.po b/locale/fi_FI/gitlab.po
index 3250cc6c127..806b45b525c 100644
--- a/locale/fi_FI/gitlab.po
+++ b/locale/fi_FI/gitlab.po
@@ -14,7 +14,10 @@ msgstr ""
"X-Crowdin-Language: fi\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 6\n"
-"PO-Revision-Date: 2020-09-04 23:07\n"
+"PO-Revision-Date: 2020-10-02 18:47\n"
+
+msgid " %{project_name}#%{issue_iid} &middot; opened %{issue_created} by %{author}"
+msgstr ""
msgid " %{start} to %{end}"
msgstr ""
@@ -74,6 +77,16 @@ msgstr ""
msgid "\"el\" parameter is required for createInstance()"
msgstr ""
+msgid "%d Approval"
+msgid_plural "%d Approvals"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d Package"
+msgid_plural "%d Packages"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d Scanned URL"
msgid_plural "%d Scanned URLs"
msgstr[0] ""
@@ -137,6 +150,11 @@ msgstr[1] ""
msgid "%d commits"
msgstr ""
+msgid "%d completed issue"
+msgid_plural "%d completed issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d contribution"
msgid_plural "%d contributions"
msgstr[0] ""
@@ -147,6 +165,11 @@ msgid_plural "%d days"
msgstr[0] ""
msgstr[1] ""
+msgid "%d day until tags are automatically removed"
+msgid_plural "%d days until tags are automatically removed"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d error"
msgid_plural "%d errors"
msgstr[0] ""
@@ -237,6 +260,16 @@ msgid_plural "%d more comments"
msgstr[0] ""
msgstr[1] ""
+msgid "%d open issue"
+msgid_plural "%d open issues"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d pending comment"
+msgid_plural "%d pending comments"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d personal project will be removed and cannot be restored."
msgid_plural "%d personal projects will be removed and cannot be restored."
msgstr[0] ""
@@ -252,6 +285,11 @@ msgid_plural "%d projects"
msgstr[0] ""
msgstr[1] ""
+msgid "%d project selected"
+msgid_plural "%d projects selected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d request with warnings"
msgid_plural "%d requests with warnings"
msgstr[0] ""
@@ -272,6 +310,11 @@ msgid_plural "%d tags"
msgstr[0] ""
msgstr[1] ""
+msgid "%d tag per image name"
+msgid_plural "%d tags per image name"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d unassigned issue"
msgid_plural "%d unassigned issues"
msgstr[0] ""
@@ -292,6 +335,11 @@ msgid_plural "%d vulnerabilities dismissed"
msgstr[0] ""
msgstr[1] ""
+msgid "%d warning found:"
+msgid_plural "%d warnings found:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%s additional commit has been omitted to prevent performance issues."
msgid_plural "%s additional commits have been omitted to prevent performance issues."
msgstr[0] ""
@@ -330,6 +378,9 @@ msgstr ""
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr ""
+msgid "%{completedCount} completed weight"
+msgstr ""
+
msgid "%{completedWeight} of %{totalWeight} weight completed"
msgstr ""
@@ -378,14 +429,12 @@ msgid_plural "%{count} participants"
msgstr[0] ""
msgstr[1] ""
-msgid "%{count} pending comment"
-msgid_plural "%{count} pending comments"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
+msgid "%{count} total weight"
+msgstr ""
+
msgid "%{dashboard_path} could not be found."
msgstr ""
@@ -440,6 +489,9 @@ msgstr ""
msgid "%{group_name} uses group managed accounts. You need to create a new GitLab account which will be managed by %{group_name}."
msgstr ""
+msgid "%{group_name}&%{epic_iid} &middot; opened %{epic_created} by %{author}"
+msgstr ""
+
msgid "%{host} sign-in from new location"
msgstr ""
@@ -452,7 +504,7 @@ msgstr ""
msgid "%{issuableType} will be removed! Are you sure?"
msgstr ""
-msgid "%{issuesSize} issues with a limit of %{maxIssueCount}"
+msgid "%{issuesCount} issues with a limit of %{maxIssueCount}"
msgstr ""
msgid "%{issuesSize} with a limit of %{maxIssueCount}"
@@ -485,7 +537,7 @@ msgstr ""
msgid "%{labelStart}Namespace:%{labelEnd} %{namespace}"
msgstr ""
-msgid "%{labelStart}Report Type:%{labelEnd} %{reportType}"
+msgid "%{labelStart}Scan Type:%{labelEnd} %{reportType}"
msgstr ""
msgid "%{labelStart}Scanner:%{labelEnd} %{scanner}"
@@ -682,9 +734,6 @@ msgid_plural "%{securityScanner} results are not available because a pipeline ha
msgstr[0] ""
msgstr[1] ""
-msgid "%{service_title} %{message}."
-msgstr ""
-
msgid "%{size} GiB"
msgstr ""
@@ -773,6 +822,12 @@ msgstr ""
msgid "%{timebox_name} should belong either to a project or a group."
msgstr ""
+msgid "%{timebox_type} does not support burnup charts"
+msgstr ""
+
+msgid "%{timebox_type} must have a start and due date"
+msgstr ""
+
msgid "%{title} %{operator} %{threshold}"
msgstr ""
@@ -797,7 +852,7 @@ msgstr ""
msgid "%{total} open issue weight"
msgstr ""
-msgid "%{total} open issues"
+msgid "%{total} warnings found: showing first %{warningsDisplayed}"
msgstr ""
msgid "%{usage_ping_link_start}Learn more%{usage_ping_link_end} about what information is shared with GitLab Inc."
@@ -830,9 +885,6 @@ msgstr ""
msgid "&lt; 1 hour"
msgstr ""
-msgid "&lt;no name set&gt;"
-msgstr ""
-
msgid "&lt;no scopes selected&gt;"
msgstr ""
@@ -863,6 +915,9 @@ msgstr ""
msgid "'%{name}' Value Stream created"
msgstr ""
+msgid "'%{name}' Value Stream deleted"
+msgstr ""
+
msgid "'%{name}' stage already exists"
msgstr ""
@@ -922,6 +977,9 @@ msgstr ""
msgid "+ %{numberOfHiddenAssignees} more"
msgstr ""
+msgid "+ %{numberOfHiddenReviewers} more"
+msgstr ""
+
msgid "+%d more"
msgid_plural "+%d more"
msgstr[0] ""
@@ -982,6 +1040,11 @@ msgid_plural "%d Days"
msgstr[0] ""
msgstr[1] ""
+msgid "1 Issue"
+msgid_plural "%d Issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "1 closed issue"
msgid_plural "%{issues} closed issues"
msgstr[0] ""
@@ -997,6 +1060,11 @@ msgid_plural "%d days"
msgstr[0] ""
msgstr[1] ""
+msgid "1 deploy key"
+msgid_plural "%d deploy keys"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1099,6 +1167,9 @@ msgstr ""
msgid ":%{startLine} to %{endLine}"
msgstr ""
+msgid "A %{incident_docs_start}modified issue%{incident_docs_end} to guide the resolution of incidents."
+msgstr ""
+
msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr ""
@@ -1111,6 +1182,9 @@ msgstr ""
msgid "A GitBook site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
+msgid "A Gitpod configured Webapplication in Spring and Java"
+msgstr ""
+
msgid "A Hexo site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
@@ -1282,9 +1356,15 @@ msgstr ""
msgid "Access expiration date"
msgstr ""
+msgid "Access expires"
+msgstr ""
+
msgid "Access forbidden. Check your access level."
msgstr ""
+msgid "Access granted"
+msgstr ""
+
msgid "Access requests"
msgstr ""
@@ -1294,6 +1374,9 @@ msgstr ""
msgid "Access to Pages websites are controlled based on the user's membership to a given project. By checking this box, users will be required to be logged in to have access to all Pages websites in your instance."
msgstr ""
+msgid "AccessDropdown|Deploy Keys"
+msgstr ""
+
msgid "AccessDropdown|Groups"
msgstr ""
@@ -1411,12 +1494,6 @@ msgstr ""
msgid "Active Sessions"
msgstr ""
-msgid "Active Users:"
-msgstr ""
-
-msgid "Active users"
-msgstr ""
-
msgid "Activity"
msgstr ""
@@ -1584,9 +1661,6 @@ msgstr ""
msgid "Add label(s)"
msgstr ""
-msgid "Add license"
-msgstr ""
-
msgid "Add list"
msgstr ""
@@ -1761,21 +1835,51 @@ msgstr ""
msgid "AdminArea|Bots"
msgstr ""
+msgid "AdminArea|Components"
+msgstr ""
+
msgid "AdminArea|Developer"
msgstr ""
+msgid "AdminArea|Features"
+msgstr ""
+
+msgid "AdminArea|Groups: %{number_of_groups}"
+msgstr ""
+
msgid "AdminArea|Guest"
msgstr ""
msgid "AdminArea|Included Free in license"
msgstr ""
+msgid "AdminArea|Latest groups"
+msgstr ""
+
+msgid "AdminArea|Latest projects"
+msgstr ""
+
+msgid "AdminArea|Latest users"
+msgstr ""
+
msgid "AdminArea|Maintainer"
msgstr ""
+msgid "AdminArea|New group"
+msgstr ""
+
+msgid "AdminArea|New project"
+msgstr ""
+
+msgid "AdminArea|New user"
+msgstr ""
+
msgid "AdminArea|Owner"
msgstr ""
+msgid "AdminArea|Projects: %{number_of_projects}"
+msgstr ""
+
msgid "AdminArea|Reporter"
msgstr ""
@@ -1803,6 +1907,9 @@ msgstr ""
msgid "AdminArea|Users without a Group and Project"
msgstr ""
+msgid "AdminArea|Users: %{number_of_users}"
+msgstr ""
+
msgid "AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running."
msgstr ""
@@ -1821,9 +1928,6 @@ msgstr ""
msgid "AdminProjects|Delete Project %{projectName}?"
msgstr ""
-msgid "AdminProjects|Delete project"
-msgstr ""
-
msgid "AdminSettings|Apply integration settings to all Projects"
msgstr ""
@@ -2061,21 +2165,30 @@ msgstr ""
msgid "AdminUsers|Without projects"
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 ""
msgid "AdminUsers|You cannot remove your own admin rights."
msgstr ""
+msgid "AdminUsers|You must transfer ownership or delete the groups owned by this user before you can delete their account"
+msgstr ""
+
msgid "Administration"
msgstr ""
msgid "Advanced"
msgstr ""
+msgid "Advanced Search"
+msgstr ""
+
+msgid "Advanced Search with Elasticsearch"
+msgstr ""
+
msgid "Advanced Settings"
msgstr ""
@@ -2153,6 +2266,9 @@ msgstr ""
msgid "AlertManagement|Edit"
msgstr ""
+msgid "AlertManagement|Environment"
+msgstr ""
+
msgid "AlertManagement|Events"
msgstr ""
@@ -2165,6 +2281,9 @@ msgstr ""
msgid "AlertManagement|Issue"
msgstr ""
+msgid "AlertManagement|Key"
+msgstr ""
+
msgid "AlertManagement|Low"
msgstr ""
@@ -2258,6 +2377,9 @@ msgstr ""
msgid "AlertManagement|Unknown"
msgstr ""
+msgid "AlertManagement|Value"
+msgstr ""
+
msgid "AlertManagement|View alerts in Opsgenie"
msgstr ""
@@ -2417,6 +2539,9 @@ msgstr ""
msgid "All projects"
msgstr ""
+msgid "All projects selected"
+msgstr ""
+
msgid "All security scans are enabled because %{linkStart}Auto DevOps%{linkEnd} is enabled on this project"
msgstr ""
@@ -2504,6 +2629,9 @@ msgstr ""
msgid "Almost there"
msgstr ""
+msgid "Already blocked"
+msgstr ""
+
msgid "Also called \"Issuer\" or \"Relying party trust identifier\""
msgstr ""
@@ -2558,6 +2686,9 @@ msgstr ""
msgid "An error has occurred"
msgstr ""
+msgid "An error occured while making the changes: %{error}"
+msgstr ""
+
msgid "An error occurred adding a draft to the thread."
msgstr ""
@@ -2585,12 +2716,6 @@ msgstr ""
msgid "An error occurred when toggling the notification subscription"
msgstr ""
-msgid "An error occurred when trying to resolve a comment. Please try again."
-msgstr ""
-
-msgid "An error occurred when trying to resolve a discussion. Please try again."
-msgstr ""
-
msgid "An error occurred when updating the issue weight"
msgstr ""
@@ -2606,12 +2731,6 @@ msgstr ""
msgid "An error occurred while checking group path. Please refresh and try again."
msgstr ""
-msgid "An error occurred while committing your changes."
-msgstr ""
-
-msgid "An error occurred while creating the list. Please try again."
-msgstr ""
-
msgid "An error occurred while decoding the file."
msgstr ""
@@ -2684,25 +2803,19 @@ msgstr ""
msgid "An error occurred while fetching the Service Desk address."
msgstr ""
-msgid "An error occurred while fetching the board issues. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the board lists. Please reload the page."
msgstr ""
msgid "An error occurred while fetching the board lists. Please try again."
msgstr ""
-msgid "An error occurred while fetching the board swimlanes. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the builds."
msgstr ""
msgid "An error occurred while fetching the job log."
msgstr ""
-msgid "An error occurred while fetching the job trace."
+msgid "An error occurred while fetching the job logs."
msgstr ""
msgid "An error occurred while fetching the job."
@@ -2849,9 +2962,6 @@ msgstr ""
msgid "An error occurred while saving assignees"
msgstr ""
-msgid "An error occurred while saving the template. Please check if the template exists."
-msgstr ""
-
msgid "An error occurred while searching for milestones"
msgstr ""
@@ -2870,10 +2980,10 @@ msgstr ""
msgid "An error occurred while updating approvers"
msgstr ""
-msgid "An error occurred while updating the comment"
+msgid "An error occurred while updating labels."
msgstr ""
-msgid "An error occurred while updating the list. Please try again."
+msgid "An error occurred while updating the comment"
msgstr ""
msgid "An error occurred while validating group path"
@@ -2927,6 +3037,9 @@ msgstr ""
msgid "An unknown error occurred while loading this graph."
msgstr ""
+msgid "An unknown error occurred."
+msgstr ""
+
msgid "Analytics"
msgstr ""
@@ -2960,10 +3073,10 @@ msgstr ""
msgid "Any"
msgstr ""
-msgid "Any Author"
+msgid "Any %{header}"
msgstr ""
-msgid "Any Status"
+msgid "Any Author"
msgstr ""
msgid "Any branch"
@@ -3017,6 +3130,9 @@ msgstr ""
msgid "Application ID"
msgstr ""
+msgid "Application limits saved successfully"
+msgstr ""
+
msgid "Application settings saved successfully"
msgstr ""
@@ -3226,6 +3342,9 @@ msgstr ""
msgid "Are you sure you want to close this blocked issue?"
msgstr ""
+msgid "Are you sure you want to delete \"%{name}\" Value Stream?"
+msgstr ""
+
msgid "Are you sure you want to delete %{name}?"
msgstr ""
@@ -3235,6 +3354,9 @@ msgstr ""
msgid "Are you sure you want to delete this %{typeOfComment}?"
msgstr ""
+msgid "Are you sure you want to delete this SSH key?"
+msgstr ""
+
msgid "Are you sure you want to delete this board?"
msgstr ""
@@ -3259,6 +3381,11 @@ msgstr ""
msgid "Are you sure you want to erase this build?"
msgstr ""
+msgid "Are you sure you want to import %d repository?"
+msgid_plural "Are you sure you want to import %d repositories?"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Are you sure you want to lose unsaved changes?"
msgstr ""
@@ -3268,15 +3395,15 @@ msgstr ""
msgid "Are you sure you want to merge immediately?"
msgstr ""
-msgid "Are you sure you want to permanently delete this license?"
-msgstr ""
-
msgid "Are you sure you want to re-deploy this environment?"
msgstr ""
msgid "Are you sure you want to regenerate the public key? You will have to update the public key on the remote server before mirroring will work again."
msgstr ""
+msgid "Are you sure you want to reindex?"
+msgstr ""
+
msgid "Are you sure you want to remove %{group_name}?"
msgstr ""
@@ -3304,6 +3431,9 @@ msgstr ""
msgid "Are you sure you want to revoke this nickname?"
msgstr ""
+msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
+msgstr ""
+
msgid "Are you sure you want to stop this environment?"
msgstr ""
@@ -3325,6 +3455,9 @@ msgstr ""
msgid "Are you sure? The device will be signed out of GitLab and all remember me tokens revoked."
msgstr ""
+msgid "Are you sure? This will invalidate your registered applications and U2F / WebAuthn devices."
+msgstr ""
+
msgid "Are you sure? This will invalidate your registered applications and U2F devices."
msgstr ""
@@ -3343,9 +3476,6 @@ msgstr ""
msgid "Artifacts"
msgstr ""
-msgid "As U2F devices are only supported by a few browsers, we require that you set up a two-factor authentication app before a U2F device. That way you'll always be able to log in - even when you're using an unsupported browser."
-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 ""
@@ -3539,6 +3669,9 @@ msgstr ""
msgid "AuditLogs|Target"
msgstr ""
+msgid "AuditLogs|This month"
+msgstr ""
+
msgid "AuditLogs|User Events"
msgstr ""
@@ -3578,6 +3711,9 @@ msgstr ""
msgid "Authentication via U2F device failed."
msgstr ""
+msgid "Authentication via WebAuthn device failed."
+msgstr ""
+
msgid "Author"
msgstr ""
@@ -3845,15 +3981,6 @@ msgstr ""
msgid "BambooService|You must set up automatic revision labeling and a repository trigger in Bamboo."
msgstr ""
-msgid "BatchComments|Delete all pending comments"
-msgstr ""
-
-msgid "BatchComments|Discard review?"
-msgstr ""
-
-msgid "BatchComments|You're about to discard your review which will delete all of your pending comments. The deleted comments %{strong_start}cannot%{strong_end} be restored."
-msgstr ""
-
msgid "Be careful. Changing the project's namespace can have unintended side effects."
msgstr ""
@@ -3875,6 +4002,9 @@ msgstr ""
msgid "Bi-weekly code coverage"
msgstr ""
+msgid "Billable Users:"
+msgstr ""
+
msgid "Billing"
msgstr ""
@@ -3884,7 +4014,7 @@ msgstr ""
msgid "BillingPlans|@%{user_name} you are currently using the %{plan_name} plan."
msgstr ""
-msgid "BillingPlans|Congratulations, your new trial is activated"
+msgid "BillingPlans|Congratulations, your free trial is activated."
msgstr ""
msgid "BillingPlans|If you would like to downgrade your plan please contact %{support_link_start}Customer Support%{support_link_end}."
@@ -3947,6 +4077,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Block user"
+msgstr ""
+
msgid "Blocked"
msgstr ""
@@ -3962,31 +4095,37 @@ msgstr ""
msgid "Blog"
msgstr ""
-msgid "Board name"
-msgstr ""
-
msgid "Board scope"
msgstr ""
msgid "Board scope affects which issues are displayed for anyone who visits this board"
msgstr ""
-msgid "BoardBlankState|Add default lists"
+msgid "Boards"
msgstr ""
-msgid "BoardBlankState|Add the following default lists to your Issue Board with one click:"
+msgid "Boards and Board Lists"
msgstr ""
-msgid "BoardBlankState|Nevermind, I'll use my own"
+msgid "Boards|An error occurred while creating the issue. Please try again."
msgstr ""
-msgid "BoardBlankState|Starting out with the default set of lists will get you right on the way to making the most of your board."
+msgid "Boards|An error occurred while creating the list. Please try again."
msgstr ""
-msgid "Boards"
+msgid "Boards|An error occurred while fetching issues. Please reload the page."
msgstr ""
-msgid "Boards and Board Lists"
+msgid "Boards|An error occurred while fetching the board issues. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching the board swimlanes. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while moving the issue. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while updating the list. Please try again."
msgstr ""
msgid "Boards|Collapse"
@@ -4013,7 +4152,7 @@ msgstr ""
msgid "Branch %{branch_name} was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr ""
-msgid "Branch has changed"
+msgid "Branch changed"
msgstr ""
msgid "Branch is already taken"
@@ -4319,6 +4458,9 @@ msgstr ""
msgid "CLOSED (MOVED)"
msgstr ""
+msgid "CODEOWNERS rule violation"
+msgstr ""
+
msgid "CONTRIBUTING"
msgstr ""
@@ -4349,9 +4491,6 @@ msgstr ""
msgid "Can't create snippet: %{err}"
msgstr ""
-msgid "Can't edit as source branch was deleted"
-msgstr ""
-
msgid "Can't fetch content for the blob: %{err}"
msgstr ""
@@ -4364,9 +4503,6 @@ msgstr ""
msgid "Can't load mermaid module: %{err}"
msgstr ""
-msgid "Can't remove group members without group managed account"
-msgstr ""
-
msgid "Can't scan the code?"
msgstr ""
@@ -4409,6 +4545,9 @@ msgstr ""
msgid "Cannot create the abuse report. This user has been blocked."
msgstr ""
+msgid "Cannot enable shared runners because parent group does not allow it"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -4514,6 +4653,15 @@ msgstr ""
msgid "Change your password or recover your current one"
msgstr ""
+msgid "ChangeReviewer|Reviewer changed from %{old} to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Reviewer changed to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Unassigned"
+msgstr ""
+
msgid "ChangeTypeActionLabel|Pick into branch"
msgstr ""
@@ -4553,6 +4701,9 @@ msgstr ""
msgid "Changes the title to \"%{title_param}\"."
msgstr ""
+msgid "Changes were successfully made."
+msgstr ""
+
msgid "Changes won't take place until the index is %{link_start}recreated%{link_end}."
msgstr ""
@@ -4958,6 +5109,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove variable"
+msgstr ""
+
msgid "CiVariables|Remove variable row"
msgstr ""
@@ -5036,9 +5190,6 @@ msgstr ""
msgid "Clear due date"
msgstr ""
-msgid "Clear input"
-msgstr ""
-
msgid "Clear recent searches"
msgstr ""
@@ -5087,6 +5238,9 @@ msgstr ""
msgid "Client authentication key password"
msgstr ""
+msgid "Client request timeout"
+msgstr ""
+
msgid "Clients"
msgstr ""
@@ -5171,6 +5325,27 @@ msgstr ""
msgid "Cluster type must be specificed for Stages::ClusterEndpointInserter"
msgstr ""
+msgid "ClusterAgents|Configuration"
+msgstr ""
+
+msgid "ClusterAgents|Connect your cluster with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate Kubernetes with a GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Name"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Agent also requires %{linkStart}enabling the Agent Server%{linkEnd}"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Kubernetes Agent allows an Infrastructure as Code, GitOps approach to integrating Kubernetes clusters with GitLab. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "ClusterAgent|This feature is only available for premium plans"
msgstr ""
@@ -5240,10 +5415,10 @@ msgstr ""
msgid "ClusterIntegration|All installed applications and related resources"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster."
+msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{linkStart}More information%{linkEnd}"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{startLink}More information%{endLink}"
+msgid "ClusterIntegration|Allow GitLab to manage namespaces and service accounts for this cluster."
msgstr ""
msgid "ClusterIntegration|Alternatively, "
@@ -5264,6 +5439,9 @@ msgstr ""
msgid "ClusterIntegration|An error occurred while trying to fetch zone machine types: %{error}"
msgstr ""
+msgid "ClusterIntegration|An unknown error occurred while attempting to connect to Kubernetes."
+msgstr ""
+
msgid "ClusterIntegration|Any project namespaces"
msgstr ""
@@ -5279,6 +5457,9 @@ msgstr ""
msgid "ClusterIntegration|Authenticate with Amazon Web Services"
msgstr ""
+msgid "ClusterIntegration|Authentication Error"
+msgstr ""
+
msgid "ClusterIntegration|Base domain"
msgstr ""
@@ -5297,13 +5478,22 @@ msgstr ""
msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}security group %{externalLinkIcon} %{endLink} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
+msgid "ClusterIntegration|Check your CA certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Check your cluster status"
+msgstr ""
+
+msgid "ClusterIntegration|Check your token"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}subnets %{externalLinkIcon} %{endLink} in your VPC where your worker nodes will run."
+msgid "ClusterIntegration|Choose the %{linkStart}security group %{linkEnd} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
msgstr ""
-msgid "ClusterIntegration|Choose the worker node %{startLink}instance type %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Choose the %{linkStart}subnets %{linkEnd} in your VPC where your worker nodes will run."
+msgstr ""
+
+msgid "ClusterIntegration|Choose the worker node %{linkStart}instance type%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Choose which applications to install on your Kubernetes cluster."
@@ -5315,10 +5505,7 @@ msgstr ""
msgid "ClusterIntegration|Clear cluster cache"
msgstr ""
-msgid "ClusterIntegration|Clear the local cache of namespace and service accounts. This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
-msgstr ""
-
-msgid "ClusterIntegration|Cluster being created"
+msgid "ClusterIntegration|Clear the local cache of namespace and service accounts."
msgstr ""
msgid "ClusterIntegration|Cluster management project (alpha)"
@@ -5330,15 +5517,21 @@ msgstr ""
msgid "ClusterIntegration|Cluster_applications artifact too big. Maximum allowable size: %{human_size}"
msgstr ""
-msgid "ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters."
+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|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}"
+msgid "ClusterIntegration|Clusters connected with a certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Connect cluster with certificate"
msgstr ""
msgid "ClusterIntegration|Connect existing cluster"
msgstr ""
+msgid "ClusterIntegration|Connection Error"
+msgstr ""
+
msgid "ClusterIntegration|Copy API URL"
msgstr ""
@@ -5414,6 +5607,12 @@ msgstr ""
msgid "ClusterIntegration|Deletes all GitLab resources attached to this cluster during removal"
msgstr ""
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared."
+msgstr ""
+
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared. %{linkStart}More information%{linkEnd}"
+msgstr ""
+
msgid "ClusterIntegration|Did you know?"
msgstr ""
@@ -5483,6 +5682,9 @@ msgstr ""
msgid "ClusterIntegration|Fluentd is an open source data collector, which lets you unify the data collection and consumption for a better use and understanding of data. It requires at least one of the following logs to be successfully installed."
msgstr ""
+msgid "ClusterIntegration|GitLab Agent managed clusters"
+msgstr ""
+
msgid "ClusterIntegration|GitLab Container Network Policies"
msgstr ""
@@ -5495,6 +5697,12 @@ msgstr ""
msgid "ClusterIntegration|GitLab Runner connects to the repository and executes CI/CD jobs, pushing results back and deploying applications to production."
msgstr ""
+msgid "ClusterIntegration|GitLab failed to authenticate."
+msgstr ""
+
+msgid "ClusterIntegration|GitLab failed to connect to the cluster."
+msgstr ""
+
msgid "ClusterIntegration|GitLab-managed cluster"
msgstr ""
@@ -5516,6 +5724,9 @@ msgstr ""
msgid "ClusterIntegration|Group cluster"
msgstr ""
+msgid "ClusterIntegration|HTTP Error"
+msgstr ""
+
msgid "ClusterIntegration|Helm Tiller"
msgstr ""
@@ -5549,7 +5760,10 @@ msgstr ""
msgid "ClusterIntegration|Instance type"
msgstr ""
-msgid "ClusterIntegration|Integrate Kubernetes cluster automation"
+msgid "ClusterIntegration|Integrate Kubernetes with a cluster certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Integrate with a cluster certificate"
msgstr ""
msgid "ClusterIntegration|Issuer Email"
@@ -5585,9 +5799,6 @@ msgstr ""
msgid "ClusterIntegration|Knative extends Kubernetes to provide a set of middleware components that are essential to build modern, source-centric, and container-based applications that can run anywhere: on premises, in the cloud, or even in a third-party data center."
msgstr ""
-msgid "ClusterIntegration|Kubernetes cluster"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes cluster is being created..."
msgstr ""
@@ -5600,9 +5811,6 @@ msgstr ""
msgid "ClusterIntegration|Kubernetes clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr ""
-msgid "ClusterIntegration|Kubernetes clusters can be used to deploy applications and to provide Review Apps for this project"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes version"
msgstr ""
@@ -5615,7 +5823,7 @@ msgstr ""
msgid "ClusterIntegration|Learn more about %{help_link_start}zones%{help_link_end}."
msgstr ""
-msgid "ClusterIntegration|Learn more about %{startLink}Regions %{externalLinkIcon}%{endLink}."
+msgid "ClusterIntegration|Learn more about %{linkStart}Regions%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Learn more about Kubernetes"
@@ -5660,12 +5868,18 @@ msgstr ""
msgid "ClusterIntegration|Machine type"
msgstr ""
+msgid "ClusterIntegration|Make sure your API endpoint is correct"
+msgstr ""
+
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create Kubernetes clusters"
msgstr ""
msgid "ClusterIntegration|Manage your Kubernetes cluster by visiting %{provider_link}"
msgstr ""
+msgid "ClusterIntegration|Namespace per environment"
+msgstr ""
+
msgid "ClusterIntegration|No IAM Roles found"
msgstr ""
@@ -5711,6 +5925,9 @@ msgstr ""
msgid "ClusterIntegration|No zones matched your search"
msgstr ""
+msgid "ClusterIntegration|Node calculations use the Kubernetes Metrics API. Make sure your cluster has metrics installed"
+msgstr ""
+
msgid "ClusterIntegration|Number of nodes"
msgstr ""
@@ -5753,6 +5970,9 @@ msgstr ""
msgid "ClusterIntegration|RBAC-enabled cluster"
msgstr ""
+msgid "ClusterIntegration|Read our %{linkStart}help page%{linkEnd} on Kubernetes cluster integration."
+msgstr ""
+
msgid "ClusterIntegration|Read our %{link_start}help page%{link_end} on Kubernetes cluster integration."
msgstr ""
@@ -5855,7 +6075,7 @@ msgstr ""
msgid "ClusterIntegration|Select a VPC to choose a subnet"
msgstr ""
-msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{linkStart}Amazon Web Services %{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select a network to choose a subnetwork"
@@ -5888,7 +6108,7 @@ msgstr ""
msgid "ClusterIntegration|Select project to choose zone"
msgstr ""
-msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select zone"
@@ -5978,9 +6198,18 @@ msgstr ""
msgid "ClusterIntegration|There was a problem authenticating with your cluster. Please ensure your CA Certificate and Token are valid."
msgstr ""
+msgid "ClusterIntegration|There was an HTTP error when connecting to your cluster."
+msgstr ""
+
msgid "ClusterIntegration|This account must have permissions to create a Kubernetes cluster in the %{link_to_container_project} specified below"
msgstr ""
+msgid "ClusterIntegration|This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
+msgstr ""
+
+msgid "ClusterIntegration|This is necessary to clear existing environment-namespace associations from clusters previously managed by GitLab."
+msgstr ""
+
msgid "ClusterIntegration|This option will allow you to install applications on RBAC clusters."
msgstr ""
@@ -6005,9 +6234,21 @@ msgstr ""
msgid "ClusterIntegration|To use a new project, first create one on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}."
msgstr ""
+msgid "ClusterIntegration|Troubleshooting tips:"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Authenticate"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Connect"
+msgstr ""
+
msgid "ClusterIntegration|Uninstall %{appTitle}"
msgstr ""
+msgid "ClusterIntegration|Unknown Error"
+msgstr ""
+
msgid "ClusterIntegration|Update %{appTitle}"
msgstr ""
@@ -6068,7 +6309,7 @@ msgstr ""
msgid "ClusterIntegration|Your cluster API is unreachable. Please ensure your API URL is correct."
msgstr ""
-msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Zone"
@@ -6188,6 +6429,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse all threads"
+msgstr ""
+
msgid "Collapse approvers"
msgstr ""
@@ -6337,7 +6581,7 @@ msgstr ""
msgid "Commit…"
msgstr ""
-msgid "Company"
+msgid "Community forum"
msgstr ""
msgid "Company name"
@@ -6346,6 +6590,9 @@ msgstr ""
msgid "Compare"
msgstr ""
+msgid "Compare %{oldCommitId}...%{newCommitId}"
+msgstr ""
+
msgid "Compare Git revisions"
msgstr ""
@@ -6361,6 +6608,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare submodule commit revisions"
+msgstr ""
+
msgid "Compare with previous version"
msgstr ""
@@ -6496,6 +6746,9 @@ msgstr ""
msgid "Configure the way a user creates a new account."
msgstr ""
+msgid "Configure which lists are shown for anyone who visits this board"
+msgstr ""
+
msgid "Confirm"
msgstr ""
@@ -6721,6 +6974,9 @@ msgstr[1] ""
msgid "ContainerRegistry|Set cleanup policy"
msgstr ""
+msgid "ContainerRegistry|Some tags were not deleted"
+msgstr ""
+
msgid "ContainerRegistry|Something went wrong while fetching the cleanup policy."
msgstr ""
@@ -6760,6 +7016,9 @@ msgstr ""
msgid "ContainerRegistry|Tags with names matching this regex pattern will %{italicStart}expire:%{italicEnd}"
msgstr ""
+msgid "ContainerRegistry|The cleanup policy timed out before it could delete all tags. An administrator can %{adminLinkStart}manually run cleanup now%{adminLinkEnd} or you can wait for the cleanup policy to automatically run again. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "ContainerRegistry|The last tag related to this image was recently removed. This empty image and any associated data will be automatically removed as part of the regular Garbage Collection process. If you have any questions, contact your administrator."
msgstr ""
@@ -6892,6 +7151,9 @@ msgstr ""
msgid "Contributions per group member"
msgstr ""
+msgid "Contributor"
+msgstr ""
+
msgid "Contributors"
msgstr ""
@@ -7021,6 +7283,9 @@ msgstr ""
msgid "Could not change HEAD: branch '%{branch}' does not exist"
msgstr ""
+msgid "Could not commit. An unexpected error occurred."
+msgstr ""
+
msgid "Could not connect to FogBugz, check your URL"
msgstr ""
@@ -7060,6 +7325,9 @@ msgstr ""
msgid "Could not find iteration"
msgstr ""
+msgid "Could not load instance counts. Please refresh the page to try again."
+msgstr ""
+
msgid "Could not remove the trigger."
msgstr ""
@@ -7084,10 +7352,10 @@ msgstr ""
msgid "Could not save prometheus manual configuration"
msgstr ""
-msgid "Could not udpdate wiki page"
+msgid "Could not update the LDAP settings"
msgstr ""
-msgid "Could not update the LDAP settings"
+msgid "Could not update wiki page"
msgstr ""
msgid "Could not upload your designs as one or more files uploaded are not supported."
@@ -7745,6 +8013,9 @@ msgstr ""
msgid "DastProfiles|Are you sure you want to delete this profile?"
msgstr ""
+msgid "DastProfiles|Could not create site validation token. Please refresh the page, or try again later."
+msgstr ""
+
msgid "DastProfiles|Could not create the scanner profile. Please try again."
msgstr ""
@@ -7769,6 +8040,12 @@ msgstr ""
msgid "DastProfiles|Could not fetch site profiles. Please refresh the page, or try again later."
msgstr ""
+msgid "DastProfiles|Could not retrieve site validation status. Please refresh the page, or try again later."
+msgstr ""
+
+msgid "DastProfiles|Could not update the scanner profile. Please try again."
+msgstr ""
+
msgid "DastProfiles|Could not update the site profile. Please try again."
msgstr ""
@@ -7784,7 +8061,7 @@ msgstr ""
msgid "DastProfiles|Download validation text file"
msgstr ""
-msgid "DastProfiles|Edit feature will come soon. Please create a new profile if changes needed"
+msgid "DastProfiles|Edit scanner profile"
msgstr ""
msgid "DastProfiles|Edit site profile"
@@ -7817,6 +8094,9 @@ msgstr ""
msgid "DastProfiles|No profiles created yet"
msgstr ""
+msgid "DastProfiles|Passive"
+msgstr ""
+
msgid "DastProfiles|Please enter a valid URL format, ex: http://www.example.com/home"
msgstr ""
@@ -7832,6 +8112,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan mode"
+msgstr ""
+
msgid "DastProfiles|Scanner Profile"
msgstr ""
@@ -7871,10 +8154,10 @@ msgstr ""
msgid "DastProfiles|Text file validation"
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
+msgid "DastProfiles|The maximum number of minutes allowed for the spider to traverse the site."
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the spider to traverse the site."
+msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
msgstr ""
msgid "DastProfiles|Validate"
@@ -7907,6 +8190,9 @@ msgstr ""
msgid "Date picker"
msgstr ""
+msgid "Date range"
+msgstr ""
+
msgid "Date range cannot exceed %{maxDateRange} days."
msgstr ""
@@ -7931,6 +8217,9 @@ msgstr ""
msgid "Days to merge"
msgstr ""
+msgid "Dear Administrator,"
+msgstr ""
+
msgid "Debug"
msgstr ""
@@ -8042,12 +8331,18 @@ msgstr ""
msgid "Delete"
msgstr ""
+msgid "Delete %{name}"
+msgstr ""
+
msgid "Delete Comment"
msgstr ""
msgid "Delete Snippet"
msgstr ""
+msgid "Delete Value Stream"
+msgstr ""
+
msgid "Delete account"
msgstr ""
@@ -8069,9 +8364,6 @@ msgstr ""
msgid "Delete label: %{label_name} ?"
msgstr ""
-msgid "Delete license"
-msgstr ""
-
msgid "Delete list"
msgstr ""
@@ -8147,15 +8439,6 @@ msgstr ""
msgid "Deleting a project places it into a read-only state until %{date}, at which point the project will be permanently deleted. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "Deleting the license failed."
-msgstr ""
-
-msgid "Deleting the license failed. The license was not found."
-msgstr ""
-
-msgid "Deleting the license failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "Deleting the project will delete its repository and all related resources including issues, merge requests etc."
msgstr ""
@@ -8651,7 +8934,10 @@ msgstr ""
msgid "DesignManagement|The maximum number of designs allowed to be uploaded is %{upload_limit}. Please try again."
msgstr ""
-msgid "DesignManagement|To upload designs, you'll need to enable LFS. %{requirements_link_start}More information%{requirements_link_end}"
+msgid "DesignManagement|There was an error moving your designs. Please upload your designs below."
+msgstr ""
+
+msgid "DesignManagement|To upload designs, you'll need to enable LFS and have admin enable hashed storage. %{requirements_link_start}More information%{requirements_link_end}"
msgstr ""
msgid "DesignManagement|Unresolve thread"
@@ -8663,6 +8949,9 @@ msgstr ""
msgid "DesignManagement|Upload skipped."
msgstr ""
+msgid "DesignManagement|Your designs are being copied and are on their way… Please refresh to update."
+msgstr ""
+
msgid "DesignManagement|and %{moreCount} more."
msgstr ""
@@ -8720,6 +9009,9 @@ msgstr ""
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
+msgid "Direct member"
+msgstr ""
+
msgid "Direction"
msgstr ""
@@ -8768,9 +9060,6 @@ msgstr ""
msgid "Discard draft"
msgstr ""
-msgid "Discard review"
-msgstr ""
-
msgid "DiscordService|Discord Notifications"
msgstr ""
@@ -8839,10 +9128,10 @@ msgstr ""
msgid "Dismiss Merge Request promotion"
msgstr ""
-msgid "Dismiss Selected"
+msgid "Dismiss Value Stream Analytics introduction box"
msgstr ""
-msgid "Dismiss Value Stream Analytics introduction box"
+msgid "Dismiss selected"
msgstr ""
msgid "Dismiss trial promotion"
@@ -8893,9 +9182,6 @@ msgstr ""
msgid "Documents reindexed: %{processed_documents} (%{percentage}%%)"
msgstr ""
-msgid "Doing"
-msgstr ""
-
msgid "Domain"
msgstr ""
@@ -9091,9 +9377,6 @@ msgstr ""
msgid "Edit environment"
msgstr ""
-msgid "Edit file"
-msgstr ""
-
msgid "Edit files in the editor and commit changes here"
msgstr ""
@@ -9106,6 +9389,12 @@ msgstr ""
msgid "Edit identity for %{user_name}"
msgstr ""
+msgid "Edit in Web IDE"
+msgstr ""
+
+msgid "Edit in single-file editor"
+msgstr ""
+
msgid "Edit issues"
msgstr ""
@@ -9133,10 +9422,10 @@ msgstr ""
msgid "Editing"
msgstr ""
-msgid "Elasticsearch"
+msgid "Elasticsearch AWS IAM credentials"
msgstr ""
-msgid "Elasticsearch AWS IAM credentials"
+msgid "Elasticsearch HTTP client timeout value in seconds."
msgstr ""
msgid "Elasticsearch indexing restrictions"
@@ -9145,9 +9434,6 @@ msgstr ""
msgid "Elasticsearch indexing started"
msgstr ""
-msgid "Elasticsearch integration. Elasticsearch AWS IAM."
-msgstr ""
-
msgid "Elasticsearch reindexing is already in progress"
msgstr ""
@@ -9175,9 +9461,6 @@ msgstr ""
msgid "Email Notification"
msgstr ""
-msgid "Email address"
-msgstr ""
-
msgid "Email could not be sent"
msgstr ""
@@ -9241,6 +9524,9 @@ msgstr ""
msgid "Emails sent from Service Desk will have this name"
msgstr ""
+msgid "Emails sent to %{email} will still be supported"
+msgstr ""
+
msgid "Emails separated by comma"
msgstr ""
@@ -9274,9 +9560,18 @@ msgstr ""
msgid "Enable"
msgstr ""
+msgid "Enable %{link_start}Gitpod%{link_end} integration to launch a development environment in your browser directly from GitLab."
+msgstr ""
+
msgid "Enable Auto DevOps"
msgstr ""
+msgid "Enable Gitpod"
+msgstr ""
+
+msgid "Enable Gitpod?"
+msgstr ""
+
msgid "Enable HTML emails"
msgstr ""
@@ -9406,9 +9701,6 @@ msgstr ""
msgid "Encountered an error while rendering: %{err}"
msgstr ""
-msgid "End date"
-msgstr ""
-
msgid "Ends at (UTC)"
msgstr ""
@@ -9568,7 +9860,7 @@ msgstr ""
msgid "EnvironmentsDashboard|The environments dashboard provides a summary of each project's environments' status, including pipeline and alert statuses."
msgstr ""
-msgid "EnvironmentsDashboard|This dashboard displays a maximum of 7 projects and 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
+msgid "EnvironmentsDashboard|This dashboard displays 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
msgstr ""
msgid "Environments|An error occurred while canceling the auto stop, please try again"
@@ -9889,6 +10181,9 @@ msgstr ""
msgid "Error deleting project. Check logs for error details."
msgstr ""
+msgid "Error fetching burnup chart data"
+msgstr ""
+
msgid "Error fetching diverging counts for branches. Please try again."
msgstr ""
@@ -9967,6 +10262,9 @@ msgstr ""
msgid "Error occurred when saving assignees"
msgstr ""
+msgid "Error occurred when saving reviewers"
+msgstr ""
+
msgid "Error occurred when toggling the notification subscription"
msgstr ""
@@ -10219,10 +10517,13 @@ msgstr ""
msgid "Expand all"
msgstr ""
-msgid "Expand approvers"
+msgid "Expand all files"
msgstr ""
-msgid "Expand dropdown"
+msgid "Expand all threads"
+msgstr ""
+
+msgid "Expand approvers"
msgstr ""
msgid "Expand milestones"
@@ -10393,6 +10694,9 @@ msgstr ""
msgid "Failed to create Merge Request. Please try again."
msgstr ""
+msgid "Failed to create To-Do for the design."
+msgstr ""
+
msgid "Failed to create a branch for this issue. Please try again."
msgstr ""
@@ -10432,6 +10736,12 @@ msgstr ""
msgid "Failed to load authors. Please try again."
msgstr ""
+msgid "Failed to load branches. Please try again."
+msgstr ""
+
+msgid "Failed to load deploy keys."
+msgstr ""
+
msgid "Failed to load emoji list."
msgstr ""
@@ -10447,6 +10757,9 @@ msgstr ""
msgid "Failed to load groups & users."
msgstr ""
+msgid "Failed to load groups, users and deploy keys."
+msgstr ""
+
msgid "Failed to load labels. Please try again."
msgstr ""
@@ -10456,6 +10769,12 @@ msgstr ""
msgid "Failed to load related branches"
msgstr ""
+msgid "Failed to load sidebar confidential toggle"
+msgstr ""
+
+msgid "Failed to load sidebar lock status"
+msgstr ""
+
msgid "Failed to load stacktrace."
msgstr ""
@@ -10483,6 +10802,9 @@ msgstr ""
msgid "Failed to publish issue on status page."
msgstr ""
+msgid "Failed to remove To-Do for the design."
+msgstr ""
+
msgid "Failed to remove a Zoom meeting"
msgstr ""
@@ -10525,6 +10847,9 @@ msgstr ""
msgid "Failed to signing using smartcard authentication"
msgstr ""
+msgid "Failed to toggle To-Do for the design."
+msgstr ""
+
msgid "Failed to update branch!"
msgstr ""
@@ -10638,7 +10963,7 @@ msgstr ""
msgid "FeatureFlags|Edit User List"
msgstr ""
-msgid "FeatureFlags|Enable features for specific users and specific environments by defining feature flag strategies."
+msgid "FeatureFlags|Enable features for specific users and environments by configuring feature flag strategies."
msgstr ""
msgid "FeatureFlags|Environment Spec"
@@ -10698,7 +11023,7 @@ msgstr ""
msgid "FeatureFlags|Include additional user IDs"
msgstr ""
-msgid "FeatureFlags|Install a %{docs_link_anchored_start}compatible client library%{docs_link_anchored_end} and specify the API URL, application name, and instance ID during the configuration setup. %{docs_link_start}More Information%{docs_link_end}"
+msgid "FeatureFlags|Install a %{docsLinkAnchoredStart}compatible client library%{docsLinkAnchoredEnd} and specify the API URL, application name, and instance ID during the configuration setup. %{docsLinkStart}More Information%{docsLinkEnd}"
msgstr ""
msgid "FeatureFlags|Instance ID"
@@ -10710,6 +11035,9 @@ msgstr ""
msgid "FeatureFlags|Loading feature flags"
msgstr ""
+msgid "FeatureFlags|Loading user lists"
+msgstr ""
+
msgid "FeatureFlags|More information"
msgstr ""
@@ -10728,7 +11056,7 @@ msgstr ""
msgid "FeatureFlags|New feature flag"
msgstr ""
-msgid "FeatureFlags|New list"
+msgid "FeatureFlags|New user list"
msgstr ""
msgid "FeatureFlags|Percent of users"
@@ -10767,6 +11095,9 @@ msgstr ""
msgid "FeatureFlags|There was an error fetching the feature flags."
msgstr ""
+msgid "FeatureFlags|There was an error fetching the user lists."
+msgstr ""
+
msgid "FeatureFlags|There was an error retrieving user lists"
msgstr ""
@@ -10782,6 +11113,9 @@ msgstr ""
msgid "FeatureFlags|User List"
msgstr ""
+msgid "FeatureFlags|User Lists"
+msgstr ""
+
msgid "FeatureFlag|List"
msgstr ""
@@ -10809,15 +11143,6 @@ msgstr ""
msgid "Fetching incoming email"
msgstr ""
-msgid "Fetching licenses failed."
-msgstr ""
-
-msgid "Fetching licenses failed. The request endpoint was not found."
-msgstr ""
-
-msgid "Fetching licenses failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "File"
msgstr ""
@@ -10920,12 +11245,21 @@ msgstr ""
msgid "Filter by status"
msgstr ""
+msgid "Filter by test cases that are currently archived."
+msgstr ""
+
+msgid "Filter by test cases that are currently opened."
+msgstr ""
+
msgid "Filter by two-factor authentication"
msgstr ""
msgid "Filter by user"
msgstr ""
+msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
+msgstr ""
+
msgid "Filter pipelines"
msgstr ""
@@ -10941,7 +11275,7 @@ msgstr ""
msgid "Filter results..."
msgstr ""
-msgid "Filter your projects by name"
+msgid "Filter your repositories by name"
msgstr ""
msgid "Filter..."
@@ -10950,7 +11284,7 @@ msgstr ""
msgid "Find File"
msgstr ""
-msgid "Find bugs in your code with coverage-guided fuzzing"
+msgid "Find bugs in your code with coverage-guided fuzzing."
msgstr ""
msgid "Find by path"
@@ -10977,9 +11311,6 @@ msgstr ""
msgid "Finish editing this message first!"
msgstr ""
-msgid "Finish review"
-msgstr ""
-
msgid "Finish setting up your dedicated account for %{group_name}."
msgstr ""
@@ -11049,6 +11380,9 @@ msgstr ""
msgid "Footer message"
msgstr ""
+msgid "For a faster browsing experience, some files are collapsed by default."
+msgstr ""
+
msgid "For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
@@ -11058,6 +11392,9 @@ msgstr ""
msgid "For more info, read the documentation."
msgstr ""
+msgid "For more information on how the number of active users is calculated, see the %{self_managed_subscriptions_doc_link} documentation."
+msgstr ""
+
msgid "For more information, go to the "
msgstr ""
@@ -11196,6 +11533,9 @@ msgstr ""
msgid "Generate new token"
msgstr ""
+msgid "Generic package file size in bytes"
+msgstr ""
+
msgid "Geo"
msgstr ""
@@ -11457,6 +11797,9 @@ msgstr ""
msgid "Geo|Please refer to Geo Troubleshooting."
msgstr ""
+msgid "Geo|Primary node"
+msgstr ""
+
msgid "Geo|Project"
msgstr ""
@@ -11499,6 +11842,9 @@ msgstr ""
msgid "Geo|Review replication status, and resynchronize and reverify items with the primary node."
msgstr ""
+msgid "Geo|Secondary node"
+msgstr ""
+
msgid "Geo|Status"
msgstr ""
@@ -11538,6 +11884,9 @@ msgstr ""
msgid "Geo|URL must be a valid url (ex: https://gitlab.com)"
msgstr ""
+msgid "Geo|Undefined"
+msgstr ""
+
msgid "Geo|Unknown state"
msgstr ""
@@ -11613,10 +11962,16 @@ msgstr ""
msgid "GitHub import"
msgstr ""
+msgid "GitLab"
+msgstr ""
+
msgid "GitLab / Unsubscribe"
msgstr ""
-msgid "GitLab Enterprise Edition %{plan}"
+msgid "GitLab API"
+msgstr ""
+
+msgid "GitLab Billing Team."
msgstr ""
msgid "GitLab Group Runners can execute code for all the projects in this group."
@@ -11628,12 +11983,18 @@ msgstr ""
msgid "GitLab Issue"
msgstr ""
+msgid "GitLab Pages"
+msgstr ""
+
msgid "GitLab Service Desk is a simple way to allow people to create issues in your GitLab instance without needing their own user account. It provides a unique email address for end users to create issues in a project, and replies can be sent either through the GitLab interface or by email. End users will only see the thread through email."
msgstr ""
msgid "GitLab Shared Runners execute code of different projects on the same Runner unless you configure GitLab Runner Autoscale with MaxBuilds 1 (which it is on GitLab.com)."
msgstr ""
+msgid "GitLab Shell"
+msgstr ""
+
msgid "GitLab Support Bot"
msgstr ""
@@ -11643,7 +12004,7 @@ msgstr ""
msgid "GitLab User"
msgstr ""
-msgid "GitLab allows you to continue using your license even if you exceed the number of seats you purchased. You will be required to pay for these seats when you renew your license."
+msgid "GitLab Workhorse"
msgstr ""
msgid "GitLab commit"
@@ -11811,6 +12172,21 @@ msgstr ""
msgid "Gitlab Pages"
msgstr ""
+msgid "Gitpod"
+msgstr ""
+
+msgid "Gitpod|Add the URL to your Gitpod instance configured to read your GitLab projects."
+msgstr ""
+
+msgid "Gitpod|Enable Gitpod integration"
+msgstr ""
+
+msgid "Gitpod|Gitpod URL"
+msgstr ""
+
+msgid "Gitpod|e.g. https://gitpod.example.com"
+msgstr ""
+
msgid "Given access %{time_ago}"
msgstr ""
@@ -12318,9 +12694,6 @@ msgstr ""
msgid "GroupSAML|Valid SAML Response"
msgstr ""
-msgid "GroupSAML|With group managed accounts enabled, all the users without a group managed account will be excluded from the group."
-msgstr ""
-
msgid "GroupSAML|With prohibit outer forks flag enabled group members will be able to fork project only inside your group."
msgstr ""
@@ -12534,10 +12907,10 @@ msgstr ""
msgid "GroupsNew|Create group"
msgstr ""
-msgid "GroupsNew|GitLab group export"
+msgid "GroupsNew|Import"
msgstr ""
-msgid "GroupsNew|Import"
+msgid "GroupsNew|Import a GitLab group export file"
msgstr ""
msgid "GroupsNew|Import group"
@@ -12680,6 +13053,9 @@ msgid_plural "Hide charts"
msgstr[0] ""
msgstr[1] ""
+msgid "Hide comments on this file"
+msgstr ""
+
msgid "Hide details"
msgstr ""
@@ -12724,6 +13100,15 @@ msgstr ""
msgid "Highest role:"
msgstr ""
+msgid "HighlightBar|Alert events:"
+msgstr ""
+
+msgid "HighlightBar|Alert start time:"
+msgstr ""
+
+msgid "HighlightBar|Original alert:"
+msgstr ""
+
msgid "History"
msgstr ""
@@ -12901,6 +13286,9 @@ msgstr ""
msgid "If enabled, access to projects will be validated on an external service using their classification label."
msgstr ""
+msgid "If the number of active users exceeds the user limit, you will be charged for the number of %{users_over_license_link} at your next license reconciliation."
+msgstr ""
+
msgid "If there is no previous license or if the previous license has expired, some GitLab functionality will be blocked until a new, valid license is uploaded."
msgstr ""
@@ -12940,9 +13328,6 @@ msgstr ""
msgid "If your HTTP repository is not publicly accessible, add your credentials."
msgstr ""
-msgid "Iglu registry URL (optional)"
-msgstr ""
-
msgid "Ignore"
msgstr ""
@@ -12979,6 +13364,16 @@ msgstr ""
msgid "Import"
msgstr ""
+msgid "Import %d compatible repository"
+msgid_plural "Import %d compatible repositories"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Import %d repository"
+msgid_plural "Import %d repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Import CSV"
msgstr ""
@@ -12988,15 +13383,9 @@ msgstr ""
msgid "Import all compatible projects"
msgstr ""
-msgid "Import all compatible repositories"
-msgstr ""
-
msgid "Import all projects"
msgstr ""
-msgid "Import all repositories"
-msgstr ""
-
msgid "Import an exported GitLab project"
msgstr ""
@@ -13084,6 +13473,9 @@ msgstr ""
msgid "ImportProjects|Error importing repository %{project_safe_import_url} into %{project_full_path} - %{message}"
msgstr ""
+msgid "ImportProjects|Import repositories"
+msgstr ""
+
msgid "ImportProjects|Importing the project failed"
msgstr ""
@@ -13096,7 +13488,7 @@ msgstr ""
msgid "ImportProjects|Requesting your %{provider} repositories failed"
msgstr ""
-msgid "ImportProjects|Select the projects you want to import"
+msgid "ImportProjects|Select the repositories you want to import"
msgstr ""
msgid "ImportProjects|The remote data could not be imported."
@@ -13132,9 +13524,6 @@ msgstr ""
msgid "In order to enable Service Desk for your instance, you must first set up incoming email."
msgstr ""
-msgid "In order to gather accurate feature usage data, it can take 1 to 2 weeks to see your index."
-msgstr ""
-
msgid "In order to personalize your experience with GitLab%{br_tag}we would like to know a bit more about you."
msgstr ""
@@ -13165,18 +13554,30 @@ msgstr ""
msgid "IncidentManagement|Create incident"
msgstr ""
+msgid "IncidentManagement|Critical - S1"
+msgstr ""
+
msgid "IncidentManagement|Date created"
msgstr ""
msgid "IncidentManagement|Display your incidents in a dedicated view"
msgstr ""
+msgid "IncidentManagement|High - S2"
+msgstr ""
+
msgid "IncidentManagement|Incident"
msgstr ""
msgid "IncidentManagement|Incidents"
msgstr ""
+msgid "IncidentManagement|Low - S4"
+msgstr ""
+
+msgid "IncidentManagement|Medium - S3"
+msgstr ""
+
msgid "IncidentManagement|No incidents to display."
msgstr ""
@@ -13189,6 +13590,9 @@ msgstr ""
msgid "IncidentManagement|Published to status page"
msgstr ""
+msgid "IncidentManagement|Severity"
+msgstr ""
+
msgid "IncidentManagement|There are no closed incidents"
msgstr ""
@@ -13198,6 +13602,9 @@ msgstr ""
msgid "IncidentManagement|Unassigned"
msgstr ""
+msgid "IncidentManagement|Unknown"
+msgstr ""
+
msgid "IncidentManagement|Unpublished"
msgstr ""
@@ -13219,6 +13626,15 @@ msgstr ""
msgid "Incidents"
msgstr ""
+msgid "Incident|Alert details"
+msgstr ""
+
+msgid "Incident|Summary"
+msgstr ""
+
+msgid "Incident|There was an issue loading alert data. Please try again."
+msgstr ""
+
msgid "Include a Terms of Service agreement and Privacy Policy that all users must accept."
msgstr ""
@@ -13279,6 +13695,9 @@ msgstr ""
msgid "Information about additional Pages templates and how to install them can be found in our %{pages_getting_started_guide}."
msgstr ""
+msgid "Inherited"
+msgstr ""
+
msgid "Inherited:"
msgstr ""
@@ -13359,7 +13778,22 @@ msgstr ""
msgid "Instance administrators group already exists"
msgstr ""
-msgid "Instance license"
+msgid "InstanceStatistics|Groups"
+msgstr ""
+
+msgid "InstanceStatistics|Issues"
+msgstr ""
+
+msgid "InstanceStatistics|Merge Requests"
+msgstr ""
+
+msgid "InstanceStatistics|Pipelines"
+msgstr ""
+
+msgid "InstanceStatistics|Projects"
+msgstr ""
+
+msgid "InstanceStatistics|Users"
msgstr ""
msgid "Integration"
@@ -13371,6 +13805,12 @@ msgstr ""
msgid "Integrations"
msgstr ""
+msgid "Integrations|%{integration} settings saved and active."
+msgstr ""
+
+msgid "Integrations|%{integration} settings saved, but not active."
+msgstr ""
+
msgid "Integrations|All details"
msgstr ""
@@ -13380,6 +13820,12 @@ msgstr ""
msgid "Integrations|Comment settings:"
msgstr ""
+msgid "Integrations|Connection failed. Please check your settings."
+msgstr ""
+
+msgid "Integrations|Connection successful."
+msgstr ""
+
msgid "Integrations|Default settings are inherited from the group level."
msgstr ""
@@ -13395,6 +13841,15 @@ msgstr ""
msgid "Integrations|Includes commit title and branch"
msgstr ""
+msgid "Integrations|Projects using custom settings will not be impacted unless the project owner chooses to use instance-level defaults."
+msgstr ""
+
+msgid "Integrations|Save settings?"
+msgstr ""
+
+msgid "Integrations|Saving will update the default settings for all projects that are not using custom settings."
+msgstr ""
+
msgid "Integrations|Standard"
msgstr ""
@@ -13527,6 +13982,9 @@ msgstr ""
msgid "Invitation"
msgstr ""
+msgid "Invitation declined"
+msgstr ""
+
msgid "Invite"
msgstr ""
@@ -13578,6 +14036,42 @@ 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|%{linkStart}Read more%{linkEnd} about role permissions"
+msgstr ""
+
+msgid "InviteMembersModal|Access expiration date (optional)"
+msgstr ""
+
+msgid "InviteMembersModal|Cancel"
+msgstr ""
+
+msgid "InviteMembersModal|Choose a role permission"
+msgstr ""
+
+msgid "InviteMembersModal|GitLab member or Email address"
+msgstr ""
+
+msgid "InviteMembersModal|Invite"
+msgstr ""
+
+msgid "InviteMembersModal|Invite team members"
+msgstr ""
+
+msgid "InviteMembersModal|Search for members to invite"
+msgstr ""
+
+msgid "InviteMembersModal|User not invited. Feature coming soon!"
+msgstr ""
+
+msgid "InviteMembersModal|Users were succesfully added"
+msgstr ""
+
+msgid "InviteMembersModal|You're inviting members to the %{group_name} group"
+msgstr ""
+
+msgid "InviteMembers|Invite team members"
+msgstr ""
+
msgid "Invited"
msgstr ""
@@ -13632,10 +14126,13 @@ msgstr ""
msgid "Issue cannot be found."
msgstr ""
+msgid "Issue created from vulnerability %{vulnerability_link}"
+msgstr ""
+
msgid "Issue events"
msgstr ""
-msgid "Issue first depoloyed to production"
+msgid "Issue first deployed to production"
msgstr ""
msgid "Issue label"
@@ -13713,6 +14210,9 @@ msgstr ""
msgid "IssueTracker|Custom issue tracker"
msgstr ""
+msgid "IssueTracker|EWM work items tracker"
+msgstr ""
+
msgid "IssueTracker|Redmine issue tracker"
msgstr ""
@@ -13779,6 +14279,9 @@ msgstr ""
msgid "It looks like you have some draft commits in this branch."
msgstr ""
+msgid "It may be several days before you see feature usage data."
+msgstr ""
+
msgid "It must have a header row and at least two columns: the first column is the issue title and the second column is the issue description. The separator is automatically detected."
msgstr ""
@@ -14061,13 +14564,13 @@ msgstr ""
msgid "Join Zoom meeting"
msgstr ""
-msgid "Jul"
+msgid "Joined %{time_ago}"
msgstr ""
-msgid "July"
+msgid "Jul"
msgstr ""
-msgid "Jump to first unresolved thread"
+msgid "July"
msgstr ""
msgid "Jump to next unresolved thread"
@@ -14103,6 +14606,9 @@ msgstr ""
msgid "Keyboard shortcuts"
msgstr ""
+msgid "KeyboardKey|Ctrl+"
+msgstr ""
+
msgid "Keys"
msgstr ""
@@ -14151,6 +14657,9 @@ msgstr ""
msgid "LDAP Synchronization"
msgstr ""
+msgid "LDAP group settings"
+msgstr ""
+
msgid "LDAP settings"
msgstr ""
@@ -14160,6 +14669,9 @@ msgstr ""
msgid "LDAP sync in progress. This could take a few minutes. Refresh the page to see the changes."
msgstr ""
+msgid "LDAP synchronizations"
+msgstr ""
+
msgid "LFS"
msgstr ""
@@ -14240,7 +14752,16 @@ msgid_plural "Last %d days"
msgstr[0] ""
msgstr[1] ""
-msgid "Last %{days} days"
+msgid "Last 2 weeks"
+msgstr ""
+
+msgid "Last 30 days"
+msgstr ""
+
+msgid "Last 60 days"
+msgstr ""
+
+msgid "Last 90 days"
msgstr ""
msgid "Last Accessed On"
@@ -14318,6 +14839,9 @@ msgstr ""
msgid "Last used on:"
msgstr ""
+msgid "Last week"
+msgstr ""
+
msgid "LastCommit|authored"
msgstr ""
@@ -14333,6 +14857,9 @@ msgstr ""
msgid "Latest pipeline for the most recent commit on this branch"
msgstr ""
+msgid "Launch a ready-to-code development environment for your project."
+msgstr ""
+
msgid "Lead"
msgstr ""
@@ -14713,6 +15240,9 @@ msgstr ""
msgid "List of all merge commits"
msgstr ""
+msgid "List options"
+msgstr ""
+
msgid "List settings"
msgstr ""
@@ -14725,9 +15255,6 @@ msgstr ""
msgid "List your Bitbucket Server repositories"
msgstr ""
-msgid "Lists"
-msgstr ""
-
msgid "Live preview"
msgstr ""
@@ -14974,6 +15501,12 @@ msgstr ""
msgid "Mark as done"
msgstr ""
+msgid "Mark as draft"
+msgstr ""
+
+msgid "Mark as ready"
+msgstr ""
+
msgid "Mark as resolved"
msgstr ""
@@ -14995,6 +15528,24 @@ msgstr ""
msgid "Markdown is supported"
msgstr ""
+msgid "MarkdownEditor|Add a link (%{modifierKey}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add a link (%{modifier_key}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifierKey}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifier_key}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifierKey}I)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifier_key}I)"
+msgstr ""
+
msgid "Marked For Deletion At - %{deletion_time}"
msgstr ""
@@ -15079,7 +15630,25 @@ msgstr ""
msgid "Max access level"
msgstr ""
-msgid "Max seats used"
+msgid "Max role"
+msgstr ""
+
+msgid "Max size 15 MB"
+msgstr ""
+
+msgid "Maximum Conan package file size in bytes"
+msgstr ""
+
+msgid "Maximum Maven package file size in bytes"
+msgstr ""
+
+msgid "Maximum NPM package file size in bytes"
+msgstr ""
+
+msgid "Maximum NuGet package file size in bytes"
+msgstr ""
+
+msgid "Maximum PyPI package file size in bytes"
msgstr ""
msgid "Maximum Users:"
@@ -15211,6 +15780,18 @@ msgstr ""
msgid "Members with access to %{strong_start}%{group_name}%{strong_end}"
msgstr ""
+msgid "Members|%{time} by %{user}"
+msgstr ""
+
+msgid "Members|Expired"
+msgstr ""
+
+msgid "Members|No expiration set"
+msgstr ""
+
+msgid "Members|in %{time}"
+msgstr ""
+
msgid "Memory Usage"
msgstr ""
@@ -15397,9 +15978,6 @@ msgstr ""
msgid "MergeRequests|Thread will be unresolved"
msgstr ""
-msgid "MergeRequests|Toggle comments for this file"
-msgstr ""
-
msgid "MergeRequests|View file @ %{commitId}"
msgstr ""
@@ -15460,6 +16038,9 @@ msgstr ""
msgid "Merging immediately isn't recommended as it may negatively impact the existing merge train. Read the %{docsLinkStart}documentation%{docsLinkEnd} for more information."
msgstr ""
+msgid "Message"
+msgstr ""
+
msgid "Messages"
msgstr ""
@@ -15845,18 +16426,12 @@ msgid_plural "Milestones"
msgstr[0] ""
msgstr[1] ""
-msgid "Milestone does not support burnup charts"
-msgstr ""
-
msgid "Milestone lists not available with your current license"
msgstr ""
msgid "Milestone lists show all issues from the selected milestone."
msgstr ""
-msgid "Milestone must have a start and due date"
-msgstr ""
-
msgid "MilestoneSidebar|Closed:"
msgstr ""
@@ -16223,6 +16798,9 @@ msgstr ""
msgid "Namespace"
msgstr ""
+msgid "Namespace ID:"
+msgstr ""
+
msgid "Namespace is empty"
msgstr ""
@@ -16307,6 +16885,9 @@ msgstr ""
msgid "NetworkPolicies|Allow all outbound traffic from %{selector} to %{ruleSelector} on %{ports}"
msgstr ""
+msgid "NetworkPolicies|Are you sure you want to delete this policy? This action cannot be undone."
+msgstr ""
+
msgid "NetworkPolicies|Choose whether to enforce this policy."
msgstr ""
@@ -16316,12 +16897,21 @@ msgstr ""
msgid "NetworkPolicies|Define this policy's location, conditions and actions."
msgstr ""
+msgid "NetworkPolicies|Delete policy"
+msgstr ""
+
+msgid "NetworkPolicies|Delete policy: %{policy}"
+msgstr ""
+
msgid "NetworkPolicies|Deny all traffic"
msgstr ""
msgid "NetworkPolicies|Description"
msgstr ""
+msgid "NetworkPolicies|Edit policy"
+msgstr ""
+
msgid "NetworkPolicies|Editor mode"
msgstr ""
@@ -16349,6 +16939,9 @@ msgstr ""
msgid "NetworkPolicies|Name"
msgstr ""
+msgid "NetworkPolicies|Namespace"
+msgstr ""
+
msgid "NetworkPolicies|Network Policy"
msgstr ""
@@ -16400,6 +16993,9 @@ msgstr ""
msgid "NetworkPolicies|Rules"
msgstr ""
+msgid "NetworkPolicies|Save changes"
+msgstr ""
+
msgid "NetworkPolicies|Something went wrong, failed to update policy"
msgstr ""
@@ -16412,6 +17008,9 @@ msgstr ""
msgid "NetworkPolicies|Traffic that does not match any rule will be blocked."
msgstr ""
+msgid "NetworkPolicies|Unable to parse policy"
+msgstr ""
+
msgid "NetworkPolicies|YAML editor"
msgstr ""
@@ -16525,6 +17124,9 @@ msgstr ""
msgid "New Snippet"
msgstr ""
+msgid "New Test Case"
+msgstr ""
+
msgid "New User"
msgstr ""
@@ -16624,6 +17226,9 @@ msgstr ""
msgid "New tag"
msgstr ""
+msgid "New test case"
+msgstr ""
+
msgid "New users set to external"
msgstr ""
@@ -16696,7 +17301,7 @@ msgstr ""
msgid "No changes"
msgstr ""
-msgid "No changes between %{ref_start}%{source_branch}%{ref_end} and %{ref_start}%{target_branch}%{ref_end}"
+msgid "No changes between %{sourceBranch} and %{targetBranch}"
msgstr ""
msgid "No child epics match applied filters"
@@ -16711,6 +17316,9 @@ msgstr ""
msgid "No containers available"
msgstr ""
+msgid "No content to show"
+msgstr ""
+
msgid "No contributions"
msgstr ""
@@ -16786,9 +17394,6 @@ msgstr ""
msgid "No license. All rights reserved"
msgstr ""
-msgid "No licenses found."
-msgstr ""
-
msgid "No matches found"
msgstr ""
@@ -16801,6 +17406,9 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No members found"
+msgstr ""
+
msgid "No merge requests found"
msgstr ""
@@ -16822,6 +17430,9 @@ msgstr ""
msgid "No parent group"
msgstr ""
+msgid "No plan"
+msgstr ""
+
msgid "No pods available"
msgstr ""
@@ -16918,6 +17529,12 @@ msgstr ""
msgid "Not Implemented"
msgstr ""
+msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+msgstr ""
+
+msgid "Not all browsers support WebAuthn. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even from an unsupported browser."
+msgstr ""
+
msgid "Not all data has been processed yet, the accuracy of the chart for the selected timeframe is limited."
msgstr ""
@@ -17014,6 +17631,9 @@ msgstr ""
msgid "Notification settings saved"
msgstr ""
+msgid "NotificationEvent|Change reviewer merge request"
+msgstr ""
+
msgid "NotificationEvent|Close issue"
msgstr ""
@@ -17176,10 +17796,7 @@ msgstr ""
msgid "On track"
msgstr ""
-msgid "OnDemandScans|Attached branch"
-msgstr ""
-
-msgid "OnDemandScans|Attached branch is where the scan job runs."
+msgid "OnDemandScans|Could not fetch scanner profiles. Please refresh the page, or try again later."
msgstr ""
msgid "OnDemandScans|Could not fetch site profiles. Please refresh the page, or try again later."
@@ -17188,6 +17805,9 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
+msgid "OnDemandScans|Create a new scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Create a new site profile"
msgstr ""
@@ -17200,6 +17820,9 @@ msgstr ""
msgid "OnDemandScans|New on-demand DAST scan"
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 ""
@@ -17209,16 +17832,10 @@ msgstr ""
msgid "OnDemandScans|On-demand scans run outside the DevOps cycle and find vulnerabilities in your projects. %{learnMoreLinkStart}Learn more%{learnMoreLinkEnd}"
msgstr ""
-msgid "OnDemandScans|Only a passive scan can be performed on demand."
-msgstr ""
-
-msgid "OnDemandScans|Passive"
-msgstr ""
-
msgid "OnDemandScans|Run scan"
msgstr ""
-msgid "OnDemandScans|Scan mode"
+msgid "OnDemandScans|Scanner profile"
msgstr ""
msgid "OnDemandScans|Scanner settings"
@@ -17230,9 +17847,15 @@ msgstr ""
msgid "OnDemandScans|Select one of the existing profiles"
msgstr ""
+msgid "OnDemandScans|Site profile"
+msgstr ""
+
msgid "OnDemandScans|Site profiles"
msgstr ""
+msgid "OnDemandScans|Use existing scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Use existing site profile"
msgstr ""
@@ -17331,9 +17954,6 @@ msgstr ""
msgid "Open Selection"
msgstr ""
-msgid "Open Web IDE"
-msgstr ""
-
msgid "Open comment type dropdown"
msgstr ""
@@ -17439,6 +18059,9 @@ msgstr ""
msgid "Origin"
msgstr ""
+msgid "Orphaned member"
+msgstr ""
+
msgid "Other Labels"
msgstr ""
@@ -17454,6 +18077,9 @@ msgstr ""
msgid "Other visibility settings have been disabled by the administrator."
msgstr ""
+msgid "Our documentation includes an example DevOps Score report."
+msgstr ""
+
msgid "Out-of-compliance with this project's policies and should be removed"
msgstr ""
@@ -17478,6 +18104,9 @@ msgstr ""
msgid "Overwrite diverged branches"
msgstr ""
+msgid "Owned by %{image_tag}"
+msgstr ""
+
msgid "Owned by anyone"
msgstr ""
@@ -17499,6 +18128,9 @@ msgstr ""
msgid "Package deleted successfully"
msgstr ""
+msgid "Package file size limits"
+msgstr ""
+
msgid "Package recipe already exists"
msgstr ""
@@ -17514,9 +18146,6 @@ msgstr ""
msgid "Package type must be PyPi"
msgstr ""
-msgid "Package was removed"
-msgstr ""
-
msgid "PackageRegistry|%{name} version %{version} was created %{datetime}"
msgstr ""
@@ -17658,12 +18287,18 @@ msgstr ""
msgid "PackageRegistry|NuGet Command"
msgstr ""
+msgid "PackageRegistry|Package Registry"
+msgstr ""
+
msgid "PackageRegistry|Pip Command"
msgstr ""
msgid "PackageRegistry|Pipeline %{link} triggered %{datetime} by %{author}"
msgstr ""
+msgid "PackageRegistry|Publish and share packages for a variety of common package managers. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "PackageRegistry|Published to the %{project} Package Registry %{datetime}"
msgstr ""
@@ -17763,6 +18398,9 @@ msgstr ""
msgid "Page not found"
msgstr ""
+msgid "Page settings"
+msgstr ""
+
msgid "Page was successfully deleted"
msgstr ""
@@ -17904,7 +18542,7 @@ msgstr ""
msgid "Paste issue link"
msgstr ""
-msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Don't use your private SSH key."
+msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Do not paste your private SSH key, as that can compromise your identity."
msgstr ""
msgid "Patch to apply"
@@ -17931,6 +18569,9 @@ msgstr ""
msgid "Pending"
msgstr ""
+msgid "Pending comments"
+msgstr ""
+
msgid "People without permission will never get a notification and won't be able to comment."
msgstr ""
@@ -18129,6 +18770,9 @@ msgstr ""
msgid "Pipelines|Build with confidence"
msgstr ""
+msgid "Pipelines|By revoking a trigger you will break any processes making use of it. Are you sure?"
+msgstr ""
+
msgid "Pipelines|CI Lint"
msgstr ""
@@ -18141,6 +18785,15 @@ msgstr ""
msgid "Pipelines|Continuous Integration can help catch bugs by running your tests automatically, while Continuous Deployment can help you deliver code to your product environment."
msgstr ""
+msgid "Pipelines|Copy trigger token"
+msgstr ""
+
+msgid "Pipelines|Description"
+msgstr ""
+
+msgid "Pipelines|Edit"
+msgstr ""
+
msgid "Pipelines|Get started with Pipelines"
msgstr ""
@@ -18156,15 +18809,27 @@ msgstr ""
msgid "Pipelines|It is recommended the code is reviewed thoroughly before running this pipeline with the parent project's CI resource."
msgstr ""
+msgid "Pipelines|Last Used"
+msgstr ""
+
msgid "Pipelines|Loading Pipelines"
msgstr ""
msgid "Pipelines|More Information"
msgstr ""
+msgid "Pipelines|No triggers have been created yet. Add one using the form above."
+msgstr ""
+
+msgid "Pipelines|Owner"
+msgstr ""
+
msgid "Pipelines|Project cache successfully reset."
msgstr ""
+msgid "Pipelines|Revoke"
+msgstr ""
+
msgid "Pipelines|Run Pipeline"
msgstr ""
@@ -18189,6 +18854,15 @@ msgstr ""
msgid "Pipelines|This project is not currently set up to run pipelines."
msgstr ""
+msgid "Pipelines|Token"
+msgstr ""
+
+msgid "Pipelines|Trigger user has insufficient permissions to project"
+msgstr ""
+
+msgid "Pipelines|invalid"
+msgstr ""
+
msgid "Pipelines|parent"
msgstr ""
@@ -18447,10 +19121,10 @@ msgstr ""
msgid "Please provide attributes to update"
msgstr ""
-msgid "Please refer to %{docs_url}"
+msgid "Please reach out if you have any questions and we'll be happy to assist."
msgstr ""
-msgid "Please retype the email address."
+msgid "Please refer to %{docs_url}"
msgstr ""
msgid "Please select"
@@ -18480,6 +19154,9 @@ msgstr ""
msgid "Please set a new password before proceeding."
msgstr ""
+msgid "Please share your feedback about %{featureName} %{linkStart}in this issue%{linkEnd} to help us improve the experience."
+msgstr ""
+
msgid "Please solve the reCAPTCHA"
msgstr ""
@@ -18783,6 +19460,9 @@ msgstr ""
msgid "Profiles| You are going to change the username %{currentUsernameBold} to %{newUsernameBold}. Profile and projects will be redirected to the %{newUsername} namespace but this redirect will expire once the %{currentUsername} namespace is registered by another user or group. Please update your Git repository remotes as soon as possible."
msgstr ""
+msgid "Profiles|%{provider} Active"
+msgstr ""
+
msgid "Profiles|@username"
msgstr ""
@@ -18834,7 +19514,7 @@ msgstr ""
msgid "Profiles|Commit email"
msgstr ""
-msgid "Profiles|Connect"
+msgid "Profiles|Connect %{provider}"
msgstr ""
msgid "Profiles|Connected Accounts"
@@ -18858,6 +19538,9 @@ msgstr ""
msgid "Profiles|Disconnect"
msgstr ""
+msgid "Profiles|Disconnect %{provider}"
+msgstr ""
+
msgid "Profiles|Do not show on profile"
msgstr ""
@@ -18882,7 +19565,7 @@ msgstr ""
msgid "Profiles|Full name"
msgstr ""
-msgid "Profiles|Give your individual key a title. This will be publically visible."
+msgid "Profiles|Give your individual key a title."
msgstr ""
msgid "Profiles|Include private contributions on my profile"
@@ -18972,7 +19655,7 @@ msgstr ""
msgid "Profiles|The maximum file size allowed is 200KB."
msgstr ""
-msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it?"
+msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it? It will be publicly visible."
msgstr ""
msgid "Profiles|This email will be displayed on your public profile"
@@ -19047,6 +19730,9 @@ msgstr ""
msgid "Profiles|You don't have access to delete this user."
msgstr ""
+msgid "Profiles|You must transfer ownership or delete groups you are an owner of before you can delete your account"
+msgstr ""
+
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
@@ -19635,6 +20321,9 @@ msgstr ""
msgid "ProjectTemplates|GitLab Cluster Management"
msgstr ""
+msgid "ProjectTemplates|Gitpod/Spring Petclinic"
+msgstr ""
+
msgid "ProjectTemplates|Go Micro"
msgstr ""
@@ -20244,6 +20933,9 @@ msgstr ""
msgid "Publish to status page"
msgstr ""
+msgid "Published"
+msgstr ""
+
msgid "Published on status page"
msgstr ""
@@ -20361,9 +21053,15 @@ msgstr ""
msgid "Quick range"
msgstr ""
+msgid "Quickly and easily edit multiple files in your project."
+msgstr ""
+
msgid "README"
msgstr ""
+msgid "Rails"
+msgstr ""
+
msgid "Rake Tasks Help"
msgstr ""
@@ -20483,10 +21181,13 @@ msgstr ""
msgid "Register Two-Factor Authenticator"
msgstr ""
-msgid "Register U2F device"
+msgid "Register Universal Two-Factor (U2F) Device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register WebAuthn Device"
+msgstr ""
+
+msgid "Register device"
msgstr ""
msgid "Register for GitLab"
@@ -20498,9 +21199,6 @@ msgstr ""
msgid "Register with two-factor app"
msgstr ""
-msgid "Registration"
-msgstr ""
-
msgid "Registration|Checkout"
msgstr ""
@@ -20617,9 +21315,6 @@ msgstr ""
msgid "Release|Something went wrong while saving the release details"
msgstr ""
-msgid "Remediated: needs review"
-msgstr ""
-
msgid "Remediations"
msgstr ""
@@ -20725,6 +21420,9 @@ msgstr ""
msgid "Remove priority"
msgstr ""
+msgid "Remove report"
+msgstr ""
+
msgid "Remove secondary node"
msgstr ""
@@ -20737,6 +21435,12 @@ msgstr ""
msgid "Remove time estimate"
msgstr ""
+msgid "Remove user & report"
+msgstr ""
+
+msgid "Remove user from group"
+msgstr ""
+
msgid "Removed"
msgstr ""
@@ -20818,9 +21522,6 @@ msgstr ""
msgid "Removes time estimate."
msgstr ""
-msgid "Removing license…"
-msgstr ""
-
msgid "Removing this group also removes all child projects, including archived projects, and their resources."
msgstr ""
@@ -20905,6 +21606,9 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
+msgid "Reported by %{reporter}"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -20991,6 +21695,27 @@ msgstr ""
msgid "Repositories"
msgstr ""
+msgid "Repositories Analytics"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download Historic Test Coverage Data"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download historic test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Historic Test Coverage Data is available in raw format (.csv) for further analysis."
+msgstr ""
+
+msgid "RepositoriesAnalytics|Test Code Coverage"
+msgstr ""
+
+msgid "RepositoriesAnalytics|There was an error fetching the projects."
+msgstr ""
+
msgid "Repository"
msgstr ""
@@ -21069,9 +21794,15 @@ msgstr ""
msgid "Request parameter %{param} is missing."
msgstr ""
+msgid "Request review from"
+msgstr ""
+
msgid "Request to link SAML account must be authorized"
msgstr ""
+msgid "Requested"
+msgstr ""
+
msgid "Requested %{time_ago}"
msgstr ""
@@ -21090,6 +21821,9 @@ msgstr ""
msgid "Requests to these domain(s)/address(es) on the local network will be allowed when local requests from hooks and services are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 or 127.0.0.0/28 are supported. Domain wildcards are not supported currently. Use comma, semicolon, or newline to separate multiple entries. The allowlist can hold a maximum of 1000 entries. Domains should use IDNA encoding. Ex: example.com, 192.168.1.1, 127.0.0.0/28, xn--itlab-j1a.com."
msgstr ""
+msgid "Require admin approval for new sign-ups"
+msgstr ""
+
msgid "Require all users in this group to setup Two-factor authentication"
msgstr ""
@@ -21217,9 +21951,6 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
-msgid "Resolved by %{resolvedByName}"
-msgstr ""
-
msgid "Resolves IP addresses once and uses them to submit requests"
msgstr ""
@@ -21339,6 +22070,14 @@ msgstr ""
msgid "ReviewApp|Enable Review App"
msgstr ""
+msgid "Reviewer"
+msgid_plural "%d Reviewers"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Reviewer(s)"
+msgstr ""
+
msgid "Reviewing"
msgstr ""
@@ -21378,6 +22117,9 @@ msgstr ""
msgid "Rook"
msgstr ""
+msgid "Ruby"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -21456,6 +22198,63 @@ msgstr ""
msgid "Runners page."
msgstr ""
+msgid "Runners|Active"
+msgstr ""
+
+msgid "Runners|Architecture"
+msgstr ""
+
+msgid "Runners|Can run untagged jobs"
+msgstr ""
+
+msgid "Runners|Description"
+msgstr ""
+
+msgid "Runners|Group"
+msgstr ""
+
+msgid "Runners|IP Address"
+msgstr ""
+
+msgid "Runners|Last contact"
+msgstr ""
+
+msgid "Runners|Locked to this project"
+msgstr ""
+
+msgid "Runners|Maximum job timeout"
+msgstr ""
+
+msgid "Runners|Name"
+msgstr ""
+
+msgid "Runners|Platform"
+msgstr ""
+
+msgid "Runners|Property Name"
+msgstr ""
+
+msgid "Runners|Protected"
+msgstr ""
+
+msgid "Runners|Revision"
+msgstr ""
+
+msgid "Runners|Shared"
+msgstr ""
+
+msgid "Runners|Specific"
+msgstr ""
+
+msgid "Runners|Tags"
+msgstr ""
+
+msgid "Runners|Value"
+msgstr ""
+
+msgid "Runners|Version"
+msgstr ""
+
msgid "Runners|You have used %{quotaUsed} out of %{quotaLimit} of your shared Runners pipeline minutes."
msgstr ""
@@ -21468,6 +22267,9 @@ msgstr ""
msgid "Runs a number of housekeeping tasks within the current repository, such as compressing file revisions and removing unreachable objects."
msgstr ""
+msgid "SAML"
+msgstr ""
+
msgid "SAML SSO"
msgstr ""
@@ -21519,6 +22321,9 @@ msgstr ""
msgid "Save"
msgstr ""
+msgid "Save %{name} size limits"
+msgstr ""
+
msgid "Save Changes"
msgstr ""
@@ -21549,9 +22354,6 @@ msgstr ""
msgid "Save space and find tags in the Container Registry more easily. Enable the cleanup policy to remove stale tags and keep only the ones you need."
msgstr ""
-msgid "Save template"
-msgstr ""
-
msgid "Save variables"
msgstr ""
@@ -21594,9 +22396,6 @@ msgstr ""
msgid "Scope"
msgstr ""
-msgid "Scope not supported with disabled 'users_search' feature!"
-msgstr ""
-
msgid "Scoped issue boards"
msgstr ""
@@ -21723,9 +22522,6 @@ msgstr ""
msgid "Search requirements"
msgstr ""
-msgid "Search results…"
-msgstr ""
-
msgid "Search users"
msgstr ""
@@ -21798,6 +22594,11 @@ msgid_plural "SearchResults|commits"
msgstr[0] ""
msgstr[1] ""
+msgid "SearchResults|epic"
+msgid_plural "SearchResults|epics"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "SearchResults|issue"
msgid_plural "SearchResults|issues"
msgstr[0] ""
@@ -21842,10 +22643,10 @@ msgstr ""
msgid "Seat Link is disabled, and cannot be configured through this form."
msgstr ""
-msgid "Seats currently in use"
+msgid "Seats usage data as of %{last_enqueue_time}"
msgstr ""
-msgid "Seats in license"
+msgid "Seats usage data is updated every day at 12:00pm UTC"
msgstr ""
msgid "Secondary"
@@ -21899,6 +22700,9 @@ msgstr ""
msgid "SecurityConfiguration|Available for on-demand DAST"
msgstr ""
+msgid "SecurityConfiguration|By default, all analyzers are applied in order to cover all languages across your project, and only run if the language is detected in the Merge Request."
+msgstr ""
+
msgid "SecurityConfiguration|Configure"
msgstr ""
@@ -21929,16 +22733,19 @@ msgstr ""
msgid "SecurityConfiguration|Manage"
msgstr ""
+msgid "SecurityConfiguration|More information"
+msgstr ""
+
msgid "SecurityConfiguration|Not enabled"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|Security Control"
+msgid "SecurityConfiguration|SAST Configuration"
msgstr ""
-msgid "SecurityConfiguration|See documentation"
+msgid "SecurityConfiguration|Security Control"
msgstr ""
msgid "SecurityConfiguration|Status"
@@ -21950,6 +22757,9 @@ msgstr ""
msgid "SecurityConfiguration|Using custom settings. You won't receive automatic updates on this variable. %{anchorStart}Restore to default%{anchorEnd}"
msgstr ""
+msgid "SecurityConfiguration|View history"
+msgstr ""
+
msgid "SecurityConfiguration|You can quickly enable all security scanning tools by enabling %{linkStart}Auto DevOps%{linkEnd}."
msgstr ""
@@ -22028,9 +22838,6 @@ msgstr ""
msgid "SecurityReports|Learn more about setting up your dashboard"
msgstr ""
-msgid "SecurityReports|Load more vulnerabilities"
-msgstr ""
-
msgid "SecurityReports|Monitor vulnerabilities in your code"
msgstr ""
@@ -22310,7 +23117,7 @@ msgstr ""
msgid "Select status"
msgstr ""
-msgid "Select strategy activation method"
+msgid "Select strategy activation method."
msgstr ""
msgid "Select subscription"
@@ -22325,7 +23132,7 @@ msgstr ""
msgid "Select the custom project template source group."
msgstr ""
-msgid "Select timeframe"
+msgid "Select the environment scope for this feature flag."
msgstr ""
msgid "Select timezone"
@@ -22574,6 +23381,9 @@ msgstr ""
msgid "Set iteration"
msgstr ""
+msgid "Set limit to 0 to allow any file size."
+msgstr ""
+
msgid "Set max session time for web terminal."
msgstr ""
@@ -22652,10 +23462,13 @@ msgstr ""
msgid "Set up a %{type} Runner manually"
msgstr ""
+msgid "Set up a hardware device as a second factor to sign in."
+msgstr ""
+
msgid "Set up assertions/attributes/claims (email, first_name, last_name) and NameID according to %{docsLinkStart}the documentation %{icon}%{docsLinkEnd}"
msgstr ""
-msgid "Set up new U2F device"
+msgid "Set up new device"
msgstr ""
msgid "Set up new password"
@@ -22724,6 +23537,9 @@ msgstr ""
msgid "Sets weight to %{weight}."
msgstr ""
+msgid "Setting this to 0 means using the system default timeout value."
+msgstr ""
+
msgid "Settings"
msgstr ""
@@ -22739,6 +23555,15 @@ msgstr ""
msgid "Severity"
msgstr ""
+msgid "SeverityWidget|Severity"
+msgstr ""
+
+msgid "SeverityWidget|Severity: %{severity}"
+msgstr ""
+
+msgid "SeverityWidget|There was an error while updating severity."
+msgstr ""
+
msgid "Shards (%{shards})"
msgstr ""
@@ -22784,6 +23609,9 @@ msgstr ""
msgid "Show all requirements."
msgstr ""
+msgid "Show all test cases."
+msgstr ""
+
msgid "Show archived projects"
msgstr ""
@@ -22796,6 +23624,9 @@ msgstr ""
msgid "Show comments"
msgstr ""
+msgid "Show comments on this file"
+msgstr ""
+
msgid "Show comments only"
msgstr ""
@@ -22841,6 +23672,12 @@ msgstr ""
msgid "Show parent subgroups"
msgstr ""
+msgid "Show the Closed list"
+msgstr ""
+
+msgid "Show the Open list"
+msgstr ""
+
msgid "Show whitespace changes"
msgstr ""
@@ -22884,9 +23721,6 @@ msgstr ""
msgid "Sidebar|Assign health status"
msgstr ""
-msgid "Sidebar|Change weight"
-msgstr ""
-
msgid "Sidebar|Health status"
msgstr ""
@@ -23070,6 +23904,9 @@ msgstr ""
msgid "Snippets|Add another file %{num}/%{total}"
msgstr ""
+msgid "Snippets|Authored %{time_ago} by %{author}"
+msgstr ""
+
msgid "Snippets|Delete file"
msgstr ""
@@ -23097,6 +23934,9 @@ msgstr ""
msgid "Solution"
msgstr ""
+msgid "Some changes are not shown"
+msgstr ""
+
msgid "Some child epics may be hidden due to applied filters"
msgstr ""
@@ -23463,6 +24303,12 @@ msgstr ""
msgid "Source (branch or tag)"
msgstr ""
+msgid "Source Branch"
+msgstr ""
+
+msgid "Source branch: %{source_branch_open}%{source_branch}%{source_branch_close}"
+msgstr ""
+
msgid "Source code"
msgstr ""
@@ -23628,9 +24474,6 @@ msgstr ""
msgid "Start and due date"
msgstr ""
-msgid "Start by choosing a group to see how your team is spending time. You can then drill down to the project level."
-msgstr ""
-
msgid "Start by choosing a group to start exploring the merge requests in that group. You can then proceed to filter by projects, labels, milestones and authors."
msgstr ""
@@ -23712,18 +24555,27 @@ msgstr ""
msgid "StaticSiteEditor|3. Assign a person to review and accept the merge request."
msgstr ""
+msgid "StaticSiteEditor|A link to view the merge request will appear once ready."
+msgstr ""
+
msgid "StaticSiteEditor|An error occurred while submitting your changes."
msgstr ""
msgid "StaticSiteEditor|Branch could not be created."
msgstr ""
+msgid "StaticSiteEditor|Copy update"
+msgstr ""
+
msgid "StaticSiteEditor|Could not commit the content changes."
msgstr ""
msgid "StaticSiteEditor|Could not create merge request."
msgstr ""
+msgid "StaticSiteEditor|Creating your merge request"
+msgstr ""
+
msgid "StaticSiteEditor|Incompatible file content"
msgstr ""
@@ -23745,6 +24597,9 @@ msgstr ""
msgid "StaticSiteEditor|View documentation"
msgstr ""
+msgid "StaticSiteEditor|You can set an assignee to get your changes reviewed and deployed once your merge request is created."
+msgstr ""
+
msgid "StaticSiteEditor|Your merge request has been created"
msgstr ""
@@ -23874,15 +24729,15 @@ msgstr ""
msgid "Submit %{humanized_resource_name}"
msgstr ""
-msgid "Submit Changes"
-msgstr ""
-
msgid "Submit a review"
msgstr ""
msgid "Submit as spam"
msgstr ""
+msgid "Submit changes"
+msgstr ""
+
msgid "Submit feedback"
msgstr ""
@@ -24036,6 +24891,9 @@ msgstr ""
msgid "Successfully deleted U2F device."
msgstr ""
+msgid "Successfully deleted WebAuthn device."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -24354,9 +25212,6 @@ msgstr ""
msgid "Template to append to all Service Desk issues"
msgstr ""
-msgid "Template was successfully saved."
-msgstr ""
-
msgid "Templates"
msgstr ""
@@ -24435,10 +25290,28 @@ msgid_plural "Test coverage: %d hits"
msgstr[0] ""
msgstr[1] ""
-msgid "Test failed."
+msgid "Test settings"
msgstr ""
-msgid "Test settings and save changes"
+msgid "TestCases|New Test Case"
+msgstr ""
+
+msgid "TestCases|New test case"
+msgstr ""
+
+msgid "TestCases|Search test cases"
+msgstr ""
+
+msgid "TestCases|Something went wrong while creating a test case."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching count of test cases."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching test cases list."
+msgstr ""
+
+msgid "TestCases|Submit test case"
msgstr ""
msgid "TestHooks|Ensure one of your projects has merge requests."
@@ -24504,6 +25377,9 @@ msgstr ""
msgid "Thank you for signing up for your free trial! You will get additional instructions in your inbox shortly."
msgstr ""
+msgid "Thank you for your business."
+msgstr ""
+
msgid "Thank you for your feedback!"
msgstr ""
@@ -24563,9 +25439,6 @@ msgstr ""
msgid "The URL to use for connecting to Elasticsearch. Use a comma-separated list to support clustering (e.g., \"http://localhost:9200, http://localhost:9201\")."
msgstr ""
-msgid "The Web IDE offers advanced syntax highlighting capabilities and more."
-msgstr ""
-
msgid "The X509 Certificate to use when mutual TLS is required to communicate with the external authorization service. If left blank, the server certificate is still validated when accessing over HTTPS."
msgstr ""
@@ -24676,6 +25549,9 @@ msgstr ""
msgid "The form contains the following error:"
msgstr ""
+msgid "The form contains the following warning:"
+msgstr ""
+
msgid "The global settings require you to enable Two-Factor Authentication for your account."
msgstr ""
@@ -24790,9 +25666,6 @@ msgstr ""
msgid "The private key to use when a client certificate is provided. This value is encrypted at rest."
msgstr ""
-msgid "The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The project can be accessed by any logged in user."
msgstr ""
@@ -24829,7 +25702,7 @@ msgstr ""
msgid "The remote repository is being updated..."
msgstr ""
-msgid "The repository can be commited to, and issues, comments and other entities can be created."
+msgid "The repository can be committed to, and issues, comments and other entities can be created."
msgstr ""
msgid "The repository for this project does not exist."
@@ -24883,9 +25756,6 @@ msgstr ""
msgid "The time taken by each data entry gathered by that stage."
msgstr ""
-msgid "The total stage shows the time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The update action will time out after %{number_of_minutes} minutes. For big repositories, use a clone/push combination."
msgstr ""
@@ -24949,6 +25819,9 @@ msgstr ""
msgid "There are no archived requirements"
msgstr ""
+msgid "There are no archived test cases"
+msgstr ""
+
msgid "There are no changes"
msgstr ""
@@ -24988,6 +25861,9 @@ msgstr ""
msgid "There are no open requirements"
msgstr ""
+msgid "There are no open test cases"
+msgstr ""
+
msgid "There are no packages yet"
msgstr ""
@@ -25000,6 +25876,9 @@ msgstr ""
msgid "There is a limit of %{ci_project_subscriptions_limit} subscriptions from or to a project."
msgstr ""
+msgid "There is already a To-Do for this design."
+msgstr ""
+
msgid "There is already a repository with that name on disk"
msgstr ""
@@ -25018,6 +25897,9 @@ msgstr ""
msgid "There was a problem communicating with your device."
msgstr ""
+msgid "There was a problem fetching branches."
+msgstr ""
+
msgid "There was a problem fetching groups."
msgstr ""
@@ -25246,9 +26128,15 @@ msgstr ""
msgid "This action can lead to data loss. To prevent accidental actions we ask you to confirm your intention."
msgstr ""
+msgid "This action cannot be undone, and will permanently delete the %{key} SSH key"
+msgstr ""
+
msgid "This action cannot be undone. You will lose the project's repository and all content: issues, merge requests, etc."
msgstr ""
+msgid "This action has been performed too many times. Try again later."
+msgstr ""
+
msgid "This action will %{strongOpen}permanently delete%{strongClose} %{codeOpen}%{project}%{codeClose} %{strongOpen}immediately%{strongClose}, including its repositories and all content: issues, merge requests, etc."
msgstr ""
@@ -25276,9 +26164,6 @@ msgstr ""
msgid "This board's scope is reduced"
msgstr ""
-msgid "This branch has changed since you started editing. Would you like to create a new branch?"
-msgstr ""
-
msgid "This chart could not be displayed"
msgstr ""
@@ -25405,15 +26290,9 @@ msgstr ""
msgid "This is a security log of important events involving your account."
msgstr ""
-msgid "This is the author's first Merge Request to this project."
-msgstr ""
-
msgid "This is the highest peak of users on your installation since the license started."
msgstr ""
-msgid "This is the maximum number of users that have existed at the same time since the license started. This is the minimum number of seats you will need to buy when you renew your license."
-msgstr ""
-
msgid "This is the number of currently active users on your installation, and this is the minimum number you need to purchase when you renew your license."
msgstr ""
@@ -25645,6 +26524,15 @@ msgstr ""
msgid "This user has no identities"
msgstr ""
+msgid "This user has previously committed to the %{name} project."
+msgstr ""
+
+msgid "This user has the %{access} role in the %{name} project."
+msgstr ""
+
+msgid "This user is the author of this %{noteable}."
+msgstr ""
+
msgid "This user will be the author of all events in the activity feed that are the result of an update, like new branches being created or new commits being pushed to existing branches."
msgstr ""
@@ -25675,6 +26563,9 @@ msgstr ""
msgid "Threat Monitoring"
msgstr ""
+msgid "ThreatMonitoring|All Environments"
+msgstr ""
+
msgid "ThreatMonitoring|Anomalous Requests"
msgstr ""
@@ -25702,9 +26593,6 @@ msgstr ""
msgid "ThreatMonitoring|Operations Per Second"
msgstr ""
-msgid "ThreatMonitoring|Overview"
-msgstr ""
-
msgid "ThreatMonitoring|Packet Activity"
msgstr ""
@@ -25723,6 +26611,9 @@ msgstr ""
msgid "ThreatMonitoring|Something went wrong, unable to fetch statistics"
msgstr ""
+msgid "ThreatMonitoring|Statistics"
+msgstr ""
+
msgid "ThreatMonitoring|The firewall is not installed or has been disabled. To view this data, ensure the web application firewall is installed and enabled for your cluster."
msgstr ""
@@ -26114,6 +27005,9 @@ msgstr ""
msgid "To update Snippets with multiple files, you must use the `files` parameter"
msgstr ""
+msgid "To use Gitpod you must first enable the feature in the integrations section of your %{user_prefs}."
+msgstr ""
+
msgid "To view all %{scannedResourcesCount} scanned URLs, please download the CSV file"
msgstr ""
@@ -26147,9 +27041,6 @@ msgstr ""
msgid "Toggle Sidebar"
msgstr ""
-msgid "Toggle all threads"
-msgstr ""
-
msgid "Toggle backtrace"
msgstr ""
@@ -26174,9 +27065,6 @@ msgstr ""
msgid "Toggle navigation"
msgstr ""
-msgid "Toggle project"
-msgstr ""
-
msgid "Toggle sidebar"
msgstr ""
@@ -26216,6 +27104,9 @@ msgstr ""
msgid "Too many projects enabled. You will need to manage them via the console or the API."
msgstr ""
+msgid "Too much data"
+msgstr ""
+
msgid "Topics (optional)"
msgstr ""
@@ -26234,6 +27125,9 @@ msgstr ""
msgid "Total cores (CPUs)"
msgstr ""
+msgid "Total days to completion"
+msgstr ""
+
msgid "Total issues"
msgstr ""
@@ -26330,6 +27224,9 @@ msgstr ""
msgid "Trending"
msgstr ""
+msgid "Trials|Create a new group to start your GitLab Gold trial."
+msgstr ""
+
msgid "Trials|Go back to GitLab"
msgstr ""
@@ -26339,6 +27236,15 @@ msgstr ""
msgid "Trials|You can always resume this process by selecting your avatar and choosing 'Start a Gold trial'"
msgstr ""
+msgid "Trials|You can apply your trial to a new group or an existing group."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group or your personal account."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group, an existing group, or your personal account."
+msgstr ""
+
msgid "Trials|You won't get a free trial right now but you can always resume this process by clicking on your avatar and choosing 'Start a free trial'"
msgstr ""
@@ -26408,6 +27314,9 @@ msgstr ""
msgid "Try using a different search term to find the file you are looking for."
msgstr ""
+msgid "Trying to communicate with your device. Plug it in (if needed) and press the button on the device now."
+msgstr ""
+
msgid "Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now."
msgstr ""
@@ -26495,6 +27404,12 @@ msgstr ""
msgid "URL or request ID"
msgstr ""
+msgid "USER %{user} WILL BE REMOVED! Are you sure?"
+msgstr ""
+
+msgid "USER WILL BE BLOCKED! Are you sure?"
+msgstr ""
+
msgid "UTC"
msgstr ""
@@ -26552,9 +27467,6 @@ msgstr ""
msgid "Unable to load the merge request widget. Try reloading the page."
msgstr ""
-msgid "Unable to resolve"
-msgstr ""
-
msgid "Unable to save iteration. Please try again"
msgstr ""
@@ -26603,6 +27515,9 @@ msgstr ""
msgid "Undo ignore"
msgstr ""
+msgid "Unexpected error"
+msgstr ""
+
msgid "Unfortunately, your email message to GitLab could not be processed."
msgstr ""
@@ -26636,6 +27551,9 @@ msgstr ""
msgid "Unknown response text"
msgstr ""
+msgid "Unless otherwise agreed to in writing with GitLab, by clicking \"Upload License\" you agree that your use of GitLab Software is subject to the %{eula_link_start}Terms of Service%{eula_link_end}."
+msgstr ""
+
msgid "Unlimited"
msgstr ""
@@ -27002,9 +27920,6 @@ msgstr ""
msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
msgstr ""
-msgid "Use a hardware device to add the second factor of authentication."
-msgstr ""
-
msgid "Use an one time password authenticator on your mobile device or computer to enable two-factor authentication (2FA)."
msgstr ""
@@ -27278,13 +28193,13 @@ msgstr ""
msgid "Users"
msgstr ""
-msgid "Users in License:"
+msgid "Users in License"
msgstr ""
-msgid "Users or groups set as approvers in the project's or merge request's settings."
+msgid "Users in License:"
msgstr ""
-msgid "Users outside of license"
+msgid "Users or groups set as approvers in the project's or merge request's settings."
msgstr ""
msgid "Users over License:"
@@ -27302,9 +28217,6 @@ msgstr ""
msgid "Users with a Guest role or those who don't belong to a Project or Group will not use a seat from your license."
msgstr ""
-msgid "Users with a Guest role or those who don't belong to any projects or groups don't count towards seats in use."
-msgstr ""
-
msgid "UsersSelect|%{name} + %{length} more"
msgstr ""
@@ -27344,9 +28256,6 @@ msgstr ""
msgid "Validations failed."
msgstr ""
-msgid "Validity"
-msgstr ""
-
msgid "Value"
msgstr ""
@@ -27365,6 +28274,9 @@ msgstr ""
msgid "Value Stream Name"
msgstr ""
+msgid "ValueStreamAnalyticsStage|We don't have enough data to show this stage."
+msgstr ""
+
msgid "ValueStreamAnalytics|%{days}d"
msgstr ""
@@ -27621,6 +28533,9 @@ msgstr ""
msgid "VisualReviewApp|Steps 1 and 2 (and sometimes 3) are performed once by the developer before requesting feedback. Steps 3 (if necessary), 4 is performed by the reviewer each time they perform a review."
msgstr ""
+msgid "Visualization"
+msgstr ""
+
msgid "Vulnerabilities"
msgstr ""
@@ -27648,34 +28563,31 @@ msgstr ""
msgid "VulnerabilityChart|Severity"
msgstr ""
-msgid "VulnerabilityManagement|A true-positive and will fix"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Change status"
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|Confirm"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Confirmed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
-msgstr ""
-
-msgid "VulnerabilityManagement|Detected %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|A true-positive and will fix"
msgstr ""
-msgid "VulnerabilityManagement|Dismiss"
+msgid "VulnerabilityManagement|Change status"
msgstr ""
-msgid "VulnerabilityManagement|Dismissed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
msgstr ""
-msgid "VulnerabilityManagement|Resolved"
+msgid "VulnerabilityManagement|Detected"
msgstr ""
-msgid "VulnerabilityManagement|Resolved %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Needs triage"
msgstr ""
msgid "VulnerabilityManagement|Something went wrong while trying to delete the comment. Please try again later."
@@ -27726,6 +28638,9 @@ msgstr ""
msgid "Vulnerability|%{scannerName} (version %{scannerVersion})"
msgstr ""
+msgid "Vulnerability|Activity"
+msgstr ""
+
msgid "Vulnerability|Class"
msgstr ""
@@ -27738,6 +28653,9 @@ msgstr ""
msgid "Vulnerability|Description"
msgstr ""
+msgid "Vulnerability|Detected"
+msgstr ""
+
msgid "Vulnerability|Evidence"
msgstr ""
@@ -27801,6 +28719,9 @@ msgstr ""
msgid "Warning: Displaying this diagram might cause performance issues on this page."
msgstr ""
+msgid "We are currently unable to fetch data for the pipeline header."
+msgstr ""
+
msgid "We are currently unable to fetch data for this graph."
msgstr ""
@@ -27840,6 +28761,12 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
+msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
+msgstr ""
+
+msgid "We would like to inform you that your subscription GitLab Enterprise Edition %{plan_name} is nearing its user limit. You have %{active_user_count} active users, which is almost at the user limit of %{maximum_user_count}."
+msgstr ""
+
msgid "We've found no vulnerabilities"
msgstr ""
@@ -27855,6 +28782,12 @@ msgstr ""
msgid "Web terminal"
msgstr ""
+msgid "WebAuthn Devices (%{length})"
+msgstr ""
+
+msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
+msgstr ""
+
msgid "WebIDE|Merge request"
msgstr ""
@@ -27993,15 +28926,9 @@ msgstr ""
msgid "Welcome to the guided GitLab tour"
msgstr ""
-msgid "Welcome to your Issue Board!"
-msgstr ""
-
msgid "Welcome to your issue board!"
msgstr ""
-msgid "We’ve been making changes to %{featureName} and we’d love your feedback %{linkStart}in this issue%{linkEnd} to help us improve the experience."
-msgstr ""
-
msgid "What are you searching for?"
msgstr ""
@@ -28020,6 +28947,9 @@ msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
msgstr ""
+msgid "When enabled, any user visiting %{host} and creating an account will have to be explicitly approved by the admin before they can login. This setting is effective only if sign-ups are enabled."
+msgstr ""
+
msgid "When enabled, any user visiting %{host} will be able to create an account."
msgstr ""
@@ -28244,6 +29174,9 @@ msgstr ""
msgid "With requirements, you can set criteria to check your products against."
msgstr ""
+msgid "With test cases, you can define conditions for your project to meet in determining quality"
+msgstr ""
+
msgid "Withdraw Access Request"
msgstr ""
@@ -28259,6 +29192,9 @@ msgstr ""
msgid "Workflow Help"
msgstr ""
+msgid "Would you like to create a new branch?"
+msgstr ""
+
msgid "Write"
msgstr ""
@@ -28280,6 +29216,9 @@ msgstr ""
msgid "Wrong extern UID provided. Make sure Auth0 is configured correctly."
msgstr ""
+msgid "YYYY-MM-DD"
+msgstr ""
+
msgid "Yes"
msgstr ""
@@ -28337,7 +29276,7 @@ msgstr ""
msgid "You are going to remove the fork relationship from %{project_full_name}. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "You are going to transfer %{project_full_name} to another owner. Are you ABSOLUTELY sure?"
+msgid "You are going to transfer %{project_full_name} to another namespace. Are you ABSOLUTELY sure?"
msgstr ""
msgid "You are going to turn off the confidentiality. This means %{strongStart}everyone%{strongEnd} will be able to see and leave a comment on this %{issuableType}."
@@ -28397,9 +29336,6 @@ msgstr ""
msgid "You can always edit this later"
msgstr ""
-msgid "You can apply your Trial to your Personal account or create a New Group."
-msgstr ""
-
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings"
msgstr ""
@@ -28421,12 +29357,18 @@ msgstr ""
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
+msgid "You can find more information about GitLab subscriptions in %{subscriptions_doc_link}."
+msgstr ""
+
msgid "You can generate an access token scoped to this project for each application to use the GitLab API."
msgstr ""
msgid "You can get started by cloning the repository or start adding files to it with one of the following options."
msgstr ""
+msgid "You can group test cases using labels. To learn about the future direction of this feature, visit %{linkStart}Quality Management direction page%{linkEnd}."
+msgstr ""
+
msgid "You can invite a new member to %{project_name} or invite another group."
msgstr ""
@@ -28442,6 +29384,9 @@ msgstr ""
msgid "You can notify the app / group or a project by sending them an email notification"
msgstr ""
+msgid "You can now close this window."
+msgstr ""
+
msgid "You can now export your security dashboard to a CSV report."
msgstr ""
@@ -28490,9 +29435,6 @@ msgstr ""
msgid "You can test your .gitlab-ci.yml in %{linkStart}CI Lint%{linkEnd}."
msgstr ""
-msgid "You can try again using %{begin_link}basic search%{end_link}"
-msgstr ""
-
msgid "You cannot access the raw file. Please wait a minute."
msgstr ""
@@ -28544,6 +29486,9 @@ msgstr ""
msgid "You don't have any U2F devices registered yet."
msgstr ""
+msgid "You don't have any WebAuthn devices registered yet."
+msgstr ""
+
msgid "You don't have any active chat names."
msgstr ""
@@ -28631,6 +29576,9 @@ msgstr ""
msgid "You must accept our Terms of Service and privacy policy in order to register an account"
msgstr ""
+msgid "You must be logged in to search across all of GitLab"
+msgstr ""
+
msgid "You must disassociate %{domain} from all clusters it is attached to before deletion."
msgstr ""
@@ -28670,7 +29618,7 @@ msgstr ""
msgid "You need to be logged in."
msgstr ""
-msgid "You need to register a two-factor authentication app before you can set up a U2F device."
+msgid "You need to register a two-factor authentication app before you can set up a device."
msgstr ""
msgid "You need to set terms to be enforced"
@@ -28688,6 +29636,9 @@ msgstr ""
msgid "You reached %{usage_in_percent} of %{namespace_name}'s storage capacity (%{used_storage} of %{storage_limit})"
msgstr ""
+msgid "You successfully declined the invitation"
+msgstr ""
+
msgid "You tried to fork %{link_to_the_project} but it failed for the following reason:"
msgstr ""
@@ -28853,10 +29804,13 @@ msgstr ""
msgid "Your U2F device did not send a valid JSON response."
msgstr ""
-msgid "Your U2F device needs to be set up. Plug it in (if not already) and click the button on the left."
+msgid "Your U2F device was registered!"
msgstr ""
-msgid "Your U2F device was registered!"
+msgid "Your WebAuthn device did not send a valid JSON response."
+msgstr ""
+
+msgid "Your WebAuthn device was registered!"
msgstr ""
msgid "Your access request to the %{source_type} has been withdrawn."
@@ -28880,6 +29834,9 @@ msgstr ""
msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
msgstr ""
+msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
+msgstr ""
+
msgid "Your changes can be committed to %{branch_name} because a merge request is open."
msgstr ""
@@ -28916,6 +29873,12 @@ msgstr ""
msgid "Your deployment services will be broken, you will need to manually fix the services after renaming."
msgstr ""
+msgid "Your device is not compatible with GitLab. Please try another device"
+msgstr ""
+
+msgid "Your device needs to be set up. Plug it in (if needed) and click the button on the left."
+msgstr ""
+
msgid "Your device was successfully set up! Give it a name and register it with the GitLab server."
msgstr ""
@@ -29029,9 +29992,6 @@ msgstr[1] ""
msgid "access:"
msgstr ""
-msgid "activated"
-msgstr ""
-
msgid "added %{created_at_timeago}"
msgstr ""
@@ -29104,9 +30064,21 @@ msgstr ""
msgid "by %{user}"
msgstr ""
+msgid "cannot be a date in the past"
+msgstr ""
+
msgid "cannot be changed if a personal project has container registry tags."
msgstr ""
+msgid "cannot be changed if shared runners are enabled"
+msgstr ""
+
+msgid "cannot be enabled because parent group does not allow it"
+msgstr ""
+
+msgid "cannot be enabled because parent group has shared Runners disabled"
+msgstr ""
+
msgid "cannot be enabled unless all domains have TLS certificates"
msgstr ""
@@ -29152,7 +30124,7 @@ msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about SAST %{linkEndTag}"
msgstr ""
-msgid "ciReport|%{linkStartTag}Learn more about Secret Scanning %{linkEndTag}"
+msgid "ciReport|%{linkStartTag}Learn more about Secret Detection %{linkEndTag}"
msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about codequality reports %{linkEndTag}"
@@ -29467,9 +30439,6 @@ msgstr ""
msgid "error"
msgstr ""
-msgid "error code:"
-msgstr ""
-
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr ""
@@ -29491,6 +30460,9 @@ msgstr ""
msgid "failed to dismiss associated finding(id=%{finding_id}): %{message}"
msgstr ""
+msgid "failed to revert associated finding(id=%{finding_id}) to detected"
+msgstr ""
+
msgid "file"
msgid_plural "files"
msgstr[0] ""
@@ -30033,6 +31005,9 @@ msgstr ""
msgid "must be a root namespace"
msgstr ""
+msgid "must be a valid IPv4 or IPv6 address"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -30069,6 +31044,9 @@ msgstr ""
msgid "no expiration"
msgstr ""
+msgid "no name set"
+msgstr ""
+
msgid "no one can merge"
msgstr ""
@@ -30247,9 +31225,6 @@ msgstr ""
msgid "security Reports|There was an error creating the merge request"
msgstr ""
-msgid "settings saved, but not activated"
-msgstr ""
-
msgid "severity|Critical"
msgstr ""
@@ -30376,9 +31351,6 @@ msgstr ""
msgid "toggle collapse"
msgstr ""
-msgid "toggle dropdown"
-msgstr ""
-
msgid "triggered"
msgstr ""
@@ -30406,6 +31378,9 @@ msgstr ""
msgid "user avatar"
msgstr ""
+msgid "user preferences"
+msgstr ""
+
msgid "username"
msgstr ""
diff --git a/locale/fil_PH/gitlab.po b/locale/fil_PH/gitlab.po
index 260e9dfc16f..5a5807e7364 100644
--- a/locale/fil_PH/gitlab.po
+++ b/locale/fil_PH/gitlab.po
@@ -14,7 +14,10 @@ msgstr ""
"X-Crowdin-Language: fil\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 6\n"
-"PO-Revision-Date: 2020-09-04 23:04\n"
+"PO-Revision-Date: 2020-10-02 18:43\n"
+
+msgid " %{project_name}#%{issue_iid} &middot; opened %{issue_created} by %{author}"
+msgstr ""
msgid " %{start} to %{end}"
msgstr ""
@@ -74,6 +77,16 @@ msgstr ""
msgid "\"el\" parameter is required for createInstance()"
msgstr ""
+msgid "%d Approval"
+msgid_plural "%d Approvals"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d Package"
+msgid_plural "%d Packages"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d Scanned URL"
msgid_plural "%d Scanned URLs"
msgstr[0] ""
@@ -137,6 +150,11 @@ msgstr[1] ""
msgid "%d commits"
msgstr ""
+msgid "%d completed issue"
+msgid_plural "%d completed issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d contribution"
msgid_plural "%d contributions"
msgstr[0] ""
@@ -147,6 +165,11 @@ msgid_plural "%d days"
msgstr[0] ""
msgstr[1] ""
+msgid "%d day until tags are automatically removed"
+msgid_plural "%d days until tags are automatically removed"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d error"
msgid_plural "%d errors"
msgstr[0] ""
@@ -237,6 +260,16 @@ msgid_plural "%d more comments"
msgstr[0] ""
msgstr[1] ""
+msgid "%d open issue"
+msgid_plural "%d open issues"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d pending comment"
+msgid_plural "%d pending comments"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d personal project will be removed and cannot be restored."
msgid_plural "%d personal projects will be removed and cannot be restored."
msgstr[0] ""
@@ -252,6 +285,11 @@ msgid_plural "%d projects"
msgstr[0] ""
msgstr[1] ""
+msgid "%d project selected"
+msgid_plural "%d projects selected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d request with warnings"
msgid_plural "%d requests with warnings"
msgstr[0] ""
@@ -272,6 +310,11 @@ msgid_plural "%d tags"
msgstr[0] ""
msgstr[1] ""
+msgid "%d tag per image name"
+msgid_plural "%d tags per image name"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d unassigned issue"
msgid_plural "%d unassigned issues"
msgstr[0] ""
@@ -292,6 +335,11 @@ msgid_plural "%d vulnerabilities dismissed"
msgstr[0] ""
msgstr[1] ""
+msgid "%d warning found:"
+msgid_plural "%d warnings found:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%s additional commit has been omitted to prevent performance issues."
msgid_plural "%s additional commits have been omitted to prevent performance issues."
msgstr[0] ""
@@ -330,6 +378,9 @@ msgstr ""
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr ""
+msgid "%{completedCount} completed weight"
+msgstr ""
+
msgid "%{completedWeight} of %{totalWeight} weight completed"
msgstr ""
@@ -378,14 +429,12 @@ msgid_plural "%{count} participants"
msgstr[0] ""
msgstr[1] ""
-msgid "%{count} pending comment"
-msgid_plural "%{count} pending comments"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
+msgid "%{count} total weight"
+msgstr ""
+
msgid "%{dashboard_path} could not be found."
msgstr ""
@@ -440,6 +489,9 @@ msgstr ""
msgid "%{group_name} uses group managed accounts. You need to create a new GitLab account which will be managed by %{group_name}."
msgstr ""
+msgid "%{group_name}&%{epic_iid} &middot; opened %{epic_created} by %{author}"
+msgstr ""
+
msgid "%{host} sign-in from new location"
msgstr ""
@@ -452,7 +504,7 @@ msgstr ""
msgid "%{issuableType} will be removed! Are you sure?"
msgstr ""
-msgid "%{issuesSize} issues with a limit of %{maxIssueCount}"
+msgid "%{issuesCount} issues with a limit of %{maxIssueCount}"
msgstr ""
msgid "%{issuesSize} with a limit of %{maxIssueCount}"
@@ -485,7 +537,7 @@ msgstr ""
msgid "%{labelStart}Namespace:%{labelEnd} %{namespace}"
msgstr ""
-msgid "%{labelStart}Report Type:%{labelEnd} %{reportType}"
+msgid "%{labelStart}Scan Type:%{labelEnd} %{reportType}"
msgstr ""
msgid "%{labelStart}Scanner:%{labelEnd} %{scanner}"
@@ -682,9 +734,6 @@ msgid_plural "%{securityScanner} results are not available because a pipeline ha
msgstr[0] ""
msgstr[1] ""
-msgid "%{service_title} %{message}."
-msgstr ""
-
msgid "%{size} GiB"
msgstr ""
@@ -773,6 +822,12 @@ msgstr ""
msgid "%{timebox_name} should belong either to a project or a group."
msgstr ""
+msgid "%{timebox_type} does not support burnup charts"
+msgstr ""
+
+msgid "%{timebox_type} must have a start and due date"
+msgstr ""
+
msgid "%{title} %{operator} %{threshold}"
msgstr ""
@@ -797,7 +852,7 @@ msgstr ""
msgid "%{total} open issue weight"
msgstr ""
-msgid "%{total} open issues"
+msgid "%{total} warnings found: showing first %{warningsDisplayed}"
msgstr ""
msgid "%{usage_ping_link_start}Learn more%{usage_ping_link_end} about what information is shared with GitLab Inc."
@@ -830,9 +885,6 @@ msgstr ""
msgid "&lt; 1 hour"
msgstr ""
-msgid "&lt;no name set&gt;"
-msgstr ""
-
msgid "&lt;no scopes selected&gt;"
msgstr ""
@@ -863,6 +915,9 @@ msgstr ""
msgid "'%{name}' Value Stream created"
msgstr ""
+msgid "'%{name}' Value Stream deleted"
+msgstr ""
+
msgid "'%{name}' stage already exists"
msgstr ""
@@ -922,6 +977,9 @@ msgstr ""
msgid "+ %{numberOfHiddenAssignees} more"
msgstr ""
+msgid "+ %{numberOfHiddenReviewers} more"
+msgstr ""
+
msgid "+%d more"
msgid_plural "+%d more"
msgstr[0] ""
@@ -982,6 +1040,11 @@ msgid_plural "%d Days"
msgstr[0] ""
msgstr[1] ""
+msgid "1 Issue"
+msgid_plural "%d Issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "1 closed issue"
msgid_plural "%{issues} closed issues"
msgstr[0] ""
@@ -997,6 +1060,11 @@ msgid_plural "%d days"
msgstr[0] ""
msgstr[1] ""
+msgid "1 deploy key"
+msgid_plural "%d deploy keys"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1099,6 +1167,9 @@ msgstr ""
msgid ":%{startLine} to %{endLine}"
msgstr ""
+msgid "A %{incident_docs_start}modified issue%{incident_docs_end} to guide the resolution of incidents."
+msgstr ""
+
msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr ""
@@ -1111,6 +1182,9 @@ msgstr ""
msgid "A GitBook site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
+msgid "A Gitpod configured Webapplication in Spring and Java"
+msgstr ""
+
msgid "A Hexo site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
@@ -1282,9 +1356,15 @@ msgstr ""
msgid "Access expiration date"
msgstr ""
+msgid "Access expires"
+msgstr ""
+
msgid "Access forbidden. Check your access level."
msgstr ""
+msgid "Access granted"
+msgstr ""
+
msgid "Access requests"
msgstr ""
@@ -1294,6 +1374,9 @@ msgstr ""
msgid "Access to Pages websites are controlled based on the user's membership to a given project. By checking this box, users will be required to be logged in to have access to all Pages websites in your instance."
msgstr ""
+msgid "AccessDropdown|Deploy Keys"
+msgstr ""
+
msgid "AccessDropdown|Groups"
msgstr ""
@@ -1411,12 +1494,6 @@ msgstr ""
msgid "Active Sessions"
msgstr ""
-msgid "Active Users:"
-msgstr ""
-
-msgid "Active users"
-msgstr ""
-
msgid "Activity"
msgstr ""
@@ -1584,9 +1661,6 @@ msgstr ""
msgid "Add label(s)"
msgstr ""
-msgid "Add license"
-msgstr ""
-
msgid "Add list"
msgstr ""
@@ -1761,21 +1835,51 @@ msgstr ""
msgid "AdminArea|Bots"
msgstr ""
+msgid "AdminArea|Components"
+msgstr ""
+
msgid "AdminArea|Developer"
msgstr ""
+msgid "AdminArea|Features"
+msgstr ""
+
+msgid "AdminArea|Groups: %{number_of_groups}"
+msgstr ""
+
msgid "AdminArea|Guest"
msgstr ""
msgid "AdminArea|Included Free in license"
msgstr ""
+msgid "AdminArea|Latest groups"
+msgstr ""
+
+msgid "AdminArea|Latest projects"
+msgstr ""
+
+msgid "AdminArea|Latest users"
+msgstr ""
+
msgid "AdminArea|Maintainer"
msgstr ""
+msgid "AdminArea|New group"
+msgstr ""
+
+msgid "AdminArea|New project"
+msgstr ""
+
+msgid "AdminArea|New user"
+msgstr ""
+
msgid "AdminArea|Owner"
msgstr ""
+msgid "AdminArea|Projects: %{number_of_projects}"
+msgstr ""
+
msgid "AdminArea|Reporter"
msgstr ""
@@ -1803,6 +1907,9 @@ msgstr ""
msgid "AdminArea|Users without a Group and Project"
msgstr ""
+msgid "AdminArea|Users: %{number_of_users}"
+msgstr ""
+
msgid "AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running."
msgstr ""
@@ -1821,9 +1928,6 @@ msgstr ""
msgid "AdminProjects|Delete Project %{projectName}?"
msgstr ""
-msgid "AdminProjects|Delete project"
-msgstr ""
-
msgid "AdminSettings|Apply integration settings to all Projects"
msgstr ""
@@ -2061,21 +2165,30 @@ msgstr ""
msgid "AdminUsers|Without projects"
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 ""
msgid "AdminUsers|You cannot remove your own admin rights."
msgstr ""
+msgid "AdminUsers|You must transfer ownership or delete the groups owned by this user before you can delete their account"
+msgstr ""
+
msgid "Administration"
msgstr ""
msgid "Advanced"
msgstr ""
+msgid "Advanced Search"
+msgstr ""
+
+msgid "Advanced Search with Elasticsearch"
+msgstr ""
+
msgid "Advanced Settings"
msgstr ""
@@ -2153,6 +2266,9 @@ msgstr ""
msgid "AlertManagement|Edit"
msgstr ""
+msgid "AlertManagement|Environment"
+msgstr ""
+
msgid "AlertManagement|Events"
msgstr ""
@@ -2165,6 +2281,9 @@ msgstr ""
msgid "AlertManagement|Issue"
msgstr ""
+msgid "AlertManagement|Key"
+msgstr ""
+
msgid "AlertManagement|Low"
msgstr ""
@@ -2258,6 +2377,9 @@ msgstr ""
msgid "AlertManagement|Unknown"
msgstr ""
+msgid "AlertManagement|Value"
+msgstr ""
+
msgid "AlertManagement|View alerts in Opsgenie"
msgstr ""
@@ -2417,6 +2539,9 @@ msgstr ""
msgid "All projects"
msgstr ""
+msgid "All projects selected"
+msgstr ""
+
msgid "All security scans are enabled because %{linkStart}Auto DevOps%{linkEnd} is enabled on this project"
msgstr ""
@@ -2504,6 +2629,9 @@ msgstr ""
msgid "Almost there"
msgstr ""
+msgid "Already blocked"
+msgstr ""
+
msgid "Also called \"Issuer\" or \"Relying party trust identifier\""
msgstr ""
@@ -2558,6 +2686,9 @@ msgstr ""
msgid "An error has occurred"
msgstr ""
+msgid "An error occured while making the changes: %{error}"
+msgstr ""
+
msgid "An error occurred adding a draft to the thread."
msgstr ""
@@ -2585,12 +2716,6 @@ msgstr ""
msgid "An error occurred when toggling the notification subscription"
msgstr ""
-msgid "An error occurred when trying to resolve a comment. Please try again."
-msgstr ""
-
-msgid "An error occurred when trying to resolve a discussion. Please try again."
-msgstr ""
-
msgid "An error occurred when updating the issue weight"
msgstr ""
@@ -2606,12 +2731,6 @@ msgstr ""
msgid "An error occurred while checking group path. Please refresh and try again."
msgstr ""
-msgid "An error occurred while committing your changes."
-msgstr ""
-
-msgid "An error occurred while creating the list. Please try again."
-msgstr ""
-
msgid "An error occurred while decoding the file."
msgstr ""
@@ -2684,25 +2803,19 @@ msgstr ""
msgid "An error occurred while fetching the Service Desk address."
msgstr ""
-msgid "An error occurred while fetching the board issues. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the board lists. Please reload the page."
msgstr ""
msgid "An error occurred while fetching the board lists. Please try again."
msgstr ""
-msgid "An error occurred while fetching the board swimlanes. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the builds."
msgstr ""
msgid "An error occurred while fetching the job log."
msgstr ""
-msgid "An error occurred while fetching the job trace."
+msgid "An error occurred while fetching the job logs."
msgstr ""
msgid "An error occurred while fetching the job."
@@ -2849,9 +2962,6 @@ msgstr ""
msgid "An error occurred while saving assignees"
msgstr ""
-msgid "An error occurred while saving the template. Please check if the template exists."
-msgstr ""
-
msgid "An error occurred while searching for milestones"
msgstr ""
@@ -2870,10 +2980,10 @@ msgstr ""
msgid "An error occurred while updating approvers"
msgstr ""
-msgid "An error occurred while updating the comment"
+msgid "An error occurred while updating labels."
msgstr ""
-msgid "An error occurred while updating the list. Please try again."
+msgid "An error occurred while updating the comment"
msgstr ""
msgid "An error occurred while validating group path"
@@ -2927,6 +3037,9 @@ msgstr ""
msgid "An unknown error occurred while loading this graph."
msgstr ""
+msgid "An unknown error occurred."
+msgstr ""
+
msgid "Analytics"
msgstr ""
@@ -2960,10 +3073,10 @@ msgstr ""
msgid "Any"
msgstr ""
-msgid "Any Author"
+msgid "Any %{header}"
msgstr ""
-msgid "Any Status"
+msgid "Any Author"
msgstr ""
msgid "Any branch"
@@ -3017,6 +3130,9 @@ msgstr ""
msgid "Application ID"
msgstr ""
+msgid "Application limits saved successfully"
+msgstr ""
+
msgid "Application settings saved successfully"
msgstr ""
@@ -3226,6 +3342,9 @@ msgstr ""
msgid "Are you sure you want to close this blocked issue?"
msgstr ""
+msgid "Are you sure you want to delete \"%{name}\" Value Stream?"
+msgstr ""
+
msgid "Are you sure you want to delete %{name}?"
msgstr ""
@@ -3235,6 +3354,9 @@ msgstr ""
msgid "Are you sure you want to delete this %{typeOfComment}?"
msgstr ""
+msgid "Are you sure you want to delete this SSH key?"
+msgstr ""
+
msgid "Are you sure you want to delete this board?"
msgstr ""
@@ -3259,6 +3381,11 @@ msgstr ""
msgid "Are you sure you want to erase this build?"
msgstr ""
+msgid "Are you sure you want to import %d repository?"
+msgid_plural "Are you sure you want to import %d repositories?"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Are you sure you want to lose unsaved changes?"
msgstr ""
@@ -3268,15 +3395,15 @@ msgstr ""
msgid "Are you sure you want to merge immediately?"
msgstr ""
-msgid "Are you sure you want to permanently delete this license?"
-msgstr ""
-
msgid "Are you sure you want to re-deploy this environment?"
msgstr ""
msgid "Are you sure you want to regenerate the public key? You will have to update the public key on the remote server before mirroring will work again."
msgstr ""
+msgid "Are you sure you want to reindex?"
+msgstr ""
+
msgid "Are you sure you want to remove %{group_name}?"
msgstr ""
@@ -3304,6 +3431,9 @@ msgstr ""
msgid "Are you sure you want to revoke this nickname?"
msgstr ""
+msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
+msgstr ""
+
msgid "Are you sure you want to stop this environment?"
msgstr ""
@@ -3325,6 +3455,9 @@ msgstr ""
msgid "Are you sure? The device will be signed out of GitLab and all remember me tokens revoked."
msgstr ""
+msgid "Are you sure? This will invalidate your registered applications and U2F / WebAuthn devices."
+msgstr ""
+
msgid "Are you sure? This will invalidate your registered applications and U2F devices."
msgstr ""
@@ -3343,9 +3476,6 @@ msgstr ""
msgid "Artifacts"
msgstr ""
-msgid "As U2F devices are only supported by a few browsers, we require that you set up a two-factor authentication app before a U2F device. That way you'll always be able to log in - even when you're using an unsupported browser."
-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 ""
@@ -3539,6 +3669,9 @@ msgstr ""
msgid "AuditLogs|Target"
msgstr ""
+msgid "AuditLogs|This month"
+msgstr ""
+
msgid "AuditLogs|User Events"
msgstr ""
@@ -3578,6 +3711,9 @@ msgstr ""
msgid "Authentication via U2F device failed."
msgstr ""
+msgid "Authentication via WebAuthn device failed."
+msgstr ""
+
msgid "Author"
msgstr ""
@@ -3845,15 +3981,6 @@ msgstr ""
msgid "BambooService|You must set up automatic revision labeling and a repository trigger in Bamboo."
msgstr ""
-msgid "BatchComments|Delete all pending comments"
-msgstr ""
-
-msgid "BatchComments|Discard review?"
-msgstr ""
-
-msgid "BatchComments|You're about to discard your review which will delete all of your pending comments. The deleted comments %{strong_start}cannot%{strong_end} be restored."
-msgstr ""
-
msgid "Be careful. Changing the project's namespace can have unintended side effects."
msgstr ""
@@ -3875,6 +4002,9 @@ msgstr ""
msgid "Bi-weekly code coverage"
msgstr ""
+msgid "Billable Users:"
+msgstr ""
+
msgid "Billing"
msgstr ""
@@ -3884,7 +4014,7 @@ msgstr ""
msgid "BillingPlans|@%{user_name} you are currently using the %{plan_name} plan."
msgstr ""
-msgid "BillingPlans|Congratulations, your new trial is activated"
+msgid "BillingPlans|Congratulations, your free trial is activated."
msgstr ""
msgid "BillingPlans|If you would like to downgrade your plan please contact %{support_link_start}Customer Support%{support_link_end}."
@@ -3947,6 +4077,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Block user"
+msgstr ""
+
msgid "Blocked"
msgstr ""
@@ -3962,31 +4095,37 @@ msgstr ""
msgid "Blog"
msgstr ""
-msgid "Board name"
-msgstr ""
-
msgid "Board scope"
msgstr ""
msgid "Board scope affects which issues are displayed for anyone who visits this board"
msgstr ""
-msgid "BoardBlankState|Add default lists"
+msgid "Boards"
msgstr ""
-msgid "BoardBlankState|Add the following default lists to your Issue Board with one click:"
+msgid "Boards and Board Lists"
msgstr ""
-msgid "BoardBlankState|Nevermind, I'll use my own"
+msgid "Boards|An error occurred while creating the issue. Please try again."
msgstr ""
-msgid "BoardBlankState|Starting out with the default set of lists will get you right on the way to making the most of your board."
+msgid "Boards|An error occurred while creating the list. Please try again."
msgstr ""
-msgid "Boards"
+msgid "Boards|An error occurred while fetching issues. Please reload the page."
msgstr ""
-msgid "Boards and Board Lists"
+msgid "Boards|An error occurred while fetching the board issues. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching the board swimlanes. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while moving the issue. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while updating the list. Please try again."
msgstr ""
msgid "Boards|Collapse"
@@ -4013,7 +4152,7 @@ msgstr ""
msgid "Branch %{branch_name} was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr ""
-msgid "Branch has changed"
+msgid "Branch changed"
msgstr ""
msgid "Branch is already taken"
@@ -4319,6 +4458,9 @@ msgstr ""
msgid "CLOSED (MOVED)"
msgstr ""
+msgid "CODEOWNERS rule violation"
+msgstr ""
+
msgid "CONTRIBUTING"
msgstr ""
@@ -4349,9 +4491,6 @@ msgstr ""
msgid "Can't create snippet: %{err}"
msgstr ""
-msgid "Can't edit as source branch was deleted"
-msgstr ""
-
msgid "Can't fetch content for the blob: %{err}"
msgstr ""
@@ -4364,9 +4503,6 @@ msgstr ""
msgid "Can't load mermaid module: %{err}"
msgstr ""
-msgid "Can't remove group members without group managed account"
-msgstr ""
-
msgid "Can't scan the code?"
msgstr ""
@@ -4409,6 +4545,9 @@ msgstr ""
msgid "Cannot create the abuse report. This user has been blocked."
msgstr ""
+msgid "Cannot enable shared runners because parent group does not allow it"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -4514,6 +4653,15 @@ msgstr ""
msgid "Change your password or recover your current one"
msgstr ""
+msgid "ChangeReviewer|Reviewer changed from %{old} to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Reviewer changed to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Unassigned"
+msgstr ""
+
msgid "ChangeTypeActionLabel|Pick into branch"
msgstr ""
@@ -4553,6 +4701,9 @@ msgstr ""
msgid "Changes the title to \"%{title_param}\"."
msgstr ""
+msgid "Changes were successfully made."
+msgstr ""
+
msgid "Changes won't take place until the index is %{link_start}recreated%{link_end}."
msgstr ""
@@ -4958,6 +5109,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove variable"
+msgstr ""
+
msgid "CiVariables|Remove variable row"
msgstr ""
@@ -5036,9 +5190,6 @@ msgstr ""
msgid "Clear due date"
msgstr ""
-msgid "Clear input"
-msgstr ""
-
msgid "Clear recent searches"
msgstr ""
@@ -5087,6 +5238,9 @@ msgstr ""
msgid "Client authentication key password"
msgstr ""
+msgid "Client request timeout"
+msgstr ""
+
msgid "Clients"
msgstr ""
@@ -5171,6 +5325,27 @@ msgstr ""
msgid "Cluster type must be specificed for Stages::ClusterEndpointInserter"
msgstr ""
+msgid "ClusterAgents|Configuration"
+msgstr ""
+
+msgid "ClusterAgents|Connect your cluster with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate Kubernetes with a GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Name"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Agent also requires %{linkStart}enabling the Agent Server%{linkEnd}"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Kubernetes Agent allows an Infrastructure as Code, GitOps approach to integrating Kubernetes clusters with GitLab. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "ClusterAgent|This feature is only available for premium plans"
msgstr ""
@@ -5240,10 +5415,10 @@ msgstr ""
msgid "ClusterIntegration|All installed applications and related resources"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster."
+msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{linkStart}More information%{linkEnd}"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{startLink}More information%{endLink}"
+msgid "ClusterIntegration|Allow GitLab to manage namespaces and service accounts for this cluster."
msgstr ""
msgid "ClusterIntegration|Alternatively, "
@@ -5264,6 +5439,9 @@ msgstr ""
msgid "ClusterIntegration|An error occurred while trying to fetch zone machine types: %{error}"
msgstr ""
+msgid "ClusterIntegration|An unknown error occurred while attempting to connect to Kubernetes."
+msgstr ""
+
msgid "ClusterIntegration|Any project namespaces"
msgstr ""
@@ -5279,6 +5457,9 @@ msgstr ""
msgid "ClusterIntegration|Authenticate with Amazon Web Services"
msgstr ""
+msgid "ClusterIntegration|Authentication Error"
+msgstr ""
+
msgid "ClusterIntegration|Base domain"
msgstr ""
@@ -5297,13 +5478,22 @@ msgstr ""
msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}security group %{externalLinkIcon} %{endLink} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
+msgid "ClusterIntegration|Check your CA certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Check your cluster status"
+msgstr ""
+
+msgid "ClusterIntegration|Check your token"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}subnets %{externalLinkIcon} %{endLink} in your VPC where your worker nodes will run."
+msgid "ClusterIntegration|Choose the %{linkStart}security group %{linkEnd} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
msgstr ""
-msgid "ClusterIntegration|Choose the worker node %{startLink}instance type %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Choose the %{linkStart}subnets %{linkEnd} in your VPC where your worker nodes will run."
+msgstr ""
+
+msgid "ClusterIntegration|Choose the worker node %{linkStart}instance type%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Choose which applications to install on your Kubernetes cluster."
@@ -5315,10 +5505,7 @@ msgstr ""
msgid "ClusterIntegration|Clear cluster cache"
msgstr ""
-msgid "ClusterIntegration|Clear the local cache of namespace and service accounts. This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
-msgstr ""
-
-msgid "ClusterIntegration|Cluster being created"
+msgid "ClusterIntegration|Clear the local cache of namespace and service accounts."
msgstr ""
msgid "ClusterIntegration|Cluster management project (alpha)"
@@ -5330,15 +5517,21 @@ msgstr ""
msgid "ClusterIntegration|Cluster_applications artifact too big. Maximum allowable size: %{human_size}"
msgstr ""
-msgid "ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters."
+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|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}"
+msgid "ClusterIntegration|Clusters connected with a certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Connect cluster with certificate"
msgstr ""
msgid "ClusterIntegration|Connect existing cluster"
msgstr ""
+msgid "ClusterIntegration|Connection Error"
+msgstr ""
+
msgid "ClusterIntegration|Copy API URL"
msgstr ""
@@ -5414,6 +5607,12 @@ msgstr ""
msgid "ClusterIntegration|Deletes all GitLab resources attached to this cluster during removal"
msgstr ""
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared."
+msgstr ""
+
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared. %{linkStart}More information%{linkEnd}"
+msgstr ""
+
msgid "ClusterIntegration|Did you know?"
msgstr ""
@@ -5483,6 +5682,9 @@ msgstr ""
msgid "ClusterIntegration|Fluentd is an open source data collector, which lets you unify the data collection and consumption for a better use and understanding of data. It requires at least one of the following logs to be successfully installed."
msgstr ""
+msgid "ClusterIntegration|GitLab Agent managed clusters"
+msgstr ""
+
msgid "ClusterIntegration|GitLab Container Network Policies"
msgstr ""
@@ -5495,6 +5697,12 @@ msgstr ""
msgid "ClusterIntegration|GitLab Runner connects to the repository and executes CI/CD jobs, pushing results back and deploying applications to production."
msgstr ""
+msgid "ClusterIntegration|GitLab failed to authenticate."
+msgstr ""
+
+msgid "ClusterIntegration|GitLab failed to connect to the cluster."
+msgstr ""
+
msgid "ClusterIntegration|GitLab-managed cluster"
msgstr ""
@@ -5516,6 +5724,9 @@ msgstr ""
msgid "ClusterIntegration|Group cluster"
msgstr ""
+msgid "ClusterIntegration|HTTP Error"
+msgstr ""
+
msgid "ClusterIntegration|Helm Tiller"
msgstr ""
@@ -5549,7 +5760,10 @@ msgstr ""
msgid "ClusterIntegration|Instance type"
msgstr ""
-msgid "ClusterIntegration|Integrate Kubernetes cluster automation"
+msgid "ClusterIntegration|Integrate Kubernetes with a cluster certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Integrate with a cluster certificate"
msgstr ""
msgid "ClusterIntegration|Issuer Email"
@@ -5585,9 +5799,6 @@ msgstr ""
msgid "ClusterIntegration|Knative extends Kubernetes to provide a set of middleware components that are essential to build modern, source-centric, and container-based applications that can run anywhere: on premises, in the cloud, or even in a third-party data center."
msgstr ""
-msgid "ClusterIntegration|Kubernetes cluster"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes cluster is being created..."
msgstr ""
@@ -5600,9 +5811,6 @@ msgstr ""
msgid "ClusterIntegration|Kubernetes clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr ""
-msgid "ClusterIntegration|Kubernetes clusters can be used to deploy applications and to provide Review Apps for this project"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes version"
msgstr ""
@@ -5615,7 +5823,7 @@ msgstr ""
msgid "ClusterIntegration|Learn more about %{help_link_start}zones%{help_link_end}."
msgstr ""
-msgid "ClusterIntegration|Learn more about %{startLink}Regions %{externalLinkIcon}%{endLink}."
+msgid "ClusterIntegration|Learn more about %{linkStart}Regions%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Learn more about Kubernetes"
@@ -5660,12 +5868,18 @@ msgstr ""
msgid "ClusterIntegration|Machine type"
msgstr ""
+msgid "ClusterIntegration|Make sure your API endpoint is correct"
+msgstr ""
+
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create Kubernetes clusters"
msgstr ""
msgid "ClusterIntegration|Manage your Kubernetes cluster by visiting %{provider_link}"
msgstr ""
+msgid "ClusterIntegration|Namespace per environment"
+msgstr ""
+
msgid "ClusterIntegration|No IAM Roles found"
msgstr ""
@@ -5711,6 +5925,9 @@ msgstr ""
msgid "ClusterIntegration|No zones matched your search"
msgstr ""
+msgid "ClusterIntegration|Node calculations use the Kubernetes Metrics API. Make sure your cluster has metrics installed"
+msgstr ""
+
msgid "ClusterIntegration|Number of nodes"
msgstr ""
@@ -5753,6 +5970,9 @@ msgstr ""
msgid "ClusterIntegration|RBAC-enabled cluster"
msgstr ""
+msgid "ClusterIntegration|Read our %{linkStart}help page%{linkEnd} on Kubernetes cluster integration."
+msgstr ""
+
msgid "ClusterIntegration|Read our %{link_start}help page%{link_end} on Kubernetes cluster integration."
msgstr ""
@@ -5855,7 +6075,7 @@ msgstr ""
msgid "ClusterIntegration|Select a VPC to choose a subnet"
msgstr ""
-msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{linkStart}Amazon Web Services %{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select a network to choose a subnetwork"
@@ -5888,7 +6108,7 @@ msgstr ""
msgid "ClusterIntegration|Select project to choose zone"
msgstr ""
-msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select zone"
@@ -5978,9 +6198,18 @@ msgstr ""
msgid "ClusterIntegration|There was a problem authenticating with your cluster. Please ensure your CA Certificate and Token are valid."
msgstr ""
+msgid "ClusterIntegration|There was an HTTP error when connecting to your cluster."
+msgstr ""
+
msgid "ClusterIntegration|This account must have permissions to create a Kubernetes cluster in the %{link_to_container_project} specified below"
msgstr ""
+msgid "ClusterIntegration|This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
+msgstr ""
+
+msgid "ClusterIntegration|This is necessary to clear existing environment-namespace associations from clusters previously managed by GitLab."
+msgstr ""
+
msgid "ClusterIntegration|This option will allow you to install applications on RBAC clusters."
msgstr ""
@@ -6005,9 +6234,21 @@ msgstr ""
msgid "ClusterIntegration|To use a new project, first create one on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}."
msgstr ""
+msgid "ClusterIntegration|Troubleshooting tips:"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Authenticate"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Connect"
+msgstr ""
+
msgid "ClusterIntegration|Uninstall %{appTitle}"
msgstr ""
+msgid "ClusterIntegration|Unknown Error"
+msgstr ""
+
msgid "ClusterIntegration|Update %{appTitle}"
msgstr ""
@@ -6068,7 +6309,7 @@ msgstr ""
msgid "ClusterIntegration|Your cluster API is unreachable. Please ensure your API URL is correct."
msgstr ""
-msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Zone"
@@ -6188,6 +6429,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse all threads"
+msgstr ""
+
msgid "Collapse approvers"
msgstr ""
@@ -6337,7 +6581,7 @@ msgstr ""
msgid "Commit…"
msgstr ""
-msgid "Company"
+msgid "Community forum"
msgstr ""
msgid "Company name"
@@ -6346,6 +6590,9 @@ msgstr ""
msgid "Compare"
msgstr ""
+msgid "Compare %{oldCommitId}...%{newCommitId}"
+msgstr ""
+
msgid "Compare Git revisions"
msgstr ""
@@ -6361,6 +6608,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare submodule commit revisions"
+msgstr ""
+
msgid "Compare with previous version"
msgstr ""
@@ -6496,6 +6746,9 @@ msgstr ""
msgid "Configure the way a user creates a new account."
msgstr ""
+msgid "Configure which lists are shown for anyone who visits this board"
+msgstr ""
+
msgid "Confirm"
msgstr ""
@@ -6721,6 +6974,9 @@ msgstr[1] ""
msgid "ContainerRegistry|Set cleanup policy"
msgstr ""
+msgid "ContainerRegistry|Some tags were not deleted"
+msgstr ""
+
msgid "ContainerRegistry|Something went wrong while fetching the cleanup policy."
msgstr ""
@@ -6760,6 +7016,9 @@ msgstr ""
msgid "ContainerRegistry|Tags with names matching this regex pattern will %{italicStart}expire:%{italicEnd}"
msgstr ""
+msgid "ContainerRegistry|The cleanup policy timed out before it could delete all tags. An administrator can %{adminLinkStart}manually run cleanup now%{adminLinkEnd} or you can wait for the cleanup policy to automatically run again. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "ContainerRegistry|The last tag related to this image was recently removed. This empty image and any associated data will be automatically removed as part of the regular Garbage Collection process. If you have any questions, contact your administrator."
msgstr ""
@@ -6892,6 +7151,9 @@ msgstr ""
msgid "Contributions per group member"
msgstr ""
+msgid "Contributor"
+msgstr ""
+
msgid "Contributors"
msgstr ""
@@ -7021,6 +7283,9 @@ msgstr ""
msgid "Could not change HEAD: branch '%{branch}' does not exist"
msgstr ""
+msgid "Could not commit. An unexpected error occurred."
+msgstr ""
+
msgid "Could not connect to FogBugz, check your URL"
msgstr ""
@@ -7060,6 +7325,9 @@ msgstr ""
msgid "Could not find iteration"
msgstr ""
+msgid "Could not load instance counts. Please refresh the page to try again."
+msgstr ""
+
msgid "Could not remove the trigger."
msgstr ""
@@ -7084,10 +7352,10 @@ msgstr ""
msgid "Could not save prometheus manual configuration"
msgstr ""
-msgid "Could not udpdate wiki page"
+msgid "Could not update the LDAP settings"
msgstr ""
-msgid "Could not update the LDAP settings"
+msgid "Could not update wiki page"
msgstr ""
msgid "Could not upload your designs as one or more files uploaded are not supported."
@@ -7745,6 +8013,9 @@ msgstr ""
msgid "DastProfiles|Are you sure you want to delete this profile?"
msgstr ""
+msgid "DastProfiles|Could not create site validation token. Please refresh the page, or try again later."
+msgstr ""
+
msgid "DastProfiles|Could not create the scanner profile. Please try again."
msgstr ""
@@ -7769,6 +8040,12 @@ msgstr ""
msgid "DastProfiles|Could not fetch site profiles. Please refresh the page, or try again later."
msgstr ""
+msgid "DastProfiles|Could not retrieve site validation status. Please refresh the page, or try again later."
+msgstr ""
+
+msgid "DastProfiles|Could not update the scanner profile. Please try again."
+msgstr ""
+
msgid "DastProfiles|Could not update the site profile. Please try again."
msgstr ""
@@ -7784,7 +8061,7 @@ msgstr ""
msgid "DastProfiles|Download validation text file"
msgstr ""
-msgid "DastProfiles|Edit feature will come soon. Please create a new profile if changes needed"
+msgid "DastProfiles|Edit scanner profile"
msgstr ""
msgid "DastProfiles|Edit site profile"
@@ -7817,6 +8094,9 @@ msgstr ""
msgid "DastProfiles|No profiles created yet"
msgstr ""
+msgid "DastProfiles|Passive"
+msgstr ""
+
msgid "DastProfiles|Please enter a valid URL format, ex: http://www.example.com/home"
msgstr ""
@@ -7832,6 +8112,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan mode"
+msgstr ""
+
msgid "DastProfiles|Scanner Profile"
msgstr ""
@@ -7871,10 +8154,10 @@ msgstr ""
msgid "DastProfiles|Text file validation"
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
+msgid "DastProfiles|The maximum number of minutes allowed for the spider to traverse the site."
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the spider to traverse the site."
+msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
msgstr ""
msgid "DastProfiles|Validate"
@@ -7907,6 +8190,9 @@ msgstr ""
msgid "Date picker"
msgstr ""
+msgid "Date range"
+msgstr ""
+
msgid "Date range cannot exceed %{maxDateRange} days."
msgstr ""
@@ -7931,6 +8217,9 @@ msgstr ""
msgid "Days to merge"
msgstr ""
+msgid "Dear Administrator,"
+msgstr ""
+
msgid "Debug"
msgstr ""
@@ -8042,12 +8331,18 @@ msgstr ""
msgid "Delete"
msgstr ""
+msgid "Delete %{name}"
+msgstr ""
+
msgid "Delete Comment"
msgstr ""
msgid "Delete Snippet"
msgstr ""
+msgid "Delete Value Stream"
+msgstr ""
+
msgid "Delete account"
msgstr ""
@@ -8069,9 +8364,6 @@ msgstr ""
msgid "Delete label: %{label_name} ?"
msgstr ""
-msgid "Delete license"
-msgstr ""
-
msgid "Delete list"
msgstr ""
@@ -8147,15 +8439,6 @@ msgstr ""
msgid "Deleting a project places it into a read-only state until %{date}, at which point the project will be permanently deleted. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "Deleting the license failed."
-msgstr ""
-
-msgid "Deleting the license failed. The license was not found."
-msgstr ""
-
-msgid "Deleting the license failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "Deleting the project will delete its repository and all related resources including issues, merge requests etc."
msgstr ""
@@ -8651,7 +8934,10 @@ msgstr ""
msgid "DesignManagement|The maximum number of designs allowed to be uploaded is %{upload_limit}. Please try again."
msgstr ""
-msgid "DesignManagement|To upload designs, you'll need to enable LFS. %{requirements_link_start}More information%{requirements_link_end}"
+msgid "DesignManagement|There was an error moving your designs. Please upload your designs below."
+msgstr ""
+
+msgid "DesignManagement|To upload designs, you'll need to enable LFS and have admin enable hashed storage. %{requirements_link_start}More information%{requirements_link_end}"
msgstr ""
msgid "DesignManagement|Unresolve thread"
@@ -8663,6 +8949,9 @@ msgstr ""
msgid "DesignManagement|Upload skipped."
msgstr ""
+msgid "DesignManagement|Your designs are being copied and are on their way… Please refresh to update."
+msgstr ""
+
msgid "DesignManagement|and %{moreCount} more."
msgstr ""
@@ -8720,6 +9009,9 @@ msgstr ""
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
+msgid "Direct member"
+msgstr ""
+
msgid "Direction"
msgstr ""
@@ -8768,9 +9060,6 @@ msgstr ""
msgid "Discard draft"
msgstr ""
-msgid "Discard review"
-msgstr ""
-
msgid "DiscordService|Discord Notifications"
msgstr ""
@@ -8839,10 +9128,10 @@ msgstr ""
msgid "Dismiss Merge Request promotion"
msgstr ""
-msgid "Dismiss Selected"
+msgid "Dismiss Value Stream Analytics introduction box"
msgstr ""
-msgid "Dismiss Value Stream Analytics introduction box"
+msgid "Dismiss selected"
msgstr ""
msgid "Dismiss trial promotion"
@@ -8893,9 +9182,6 @@ msgstr ""
msgid "Documents reindexed: %{processed_documents} (%{percentage}%%)"
msgstr ""
-msgid "Doing"
-msgstr ""
-
msgid "Domain"
msgstr ""
@@ -9091,9 +9377,6 @@ msgstr ""
msgid "Edit environment"
msgstr ""
-msgid "Edit file"
-msgstr ""
-
msgid "Edit files in the editor and commit changes here"
msgstr ""
@@ -9106,6 +9389,12 @@ msgstr ""
msgid "Edit identity for %{user_name}"
msgstr ""
+msgid "Edit in Web IDE"
+msgstr ""
+
+msgid "Edit in single-file editor"
+msgstr ""
+
msgid "Edit issues"
msgstr ""
@@ -9133,10 +9422,10 @@ msgstr ""
msgid "Editing"
msgstr ""
-msgid "Elasticsearch"
+msgid "Elasticsearch AWS IAM credentials"
msgstr ""
-msgid "Elasticsearch AWS IAM credentials"
+msgid "Elasticsearch HTTP client timeout value in seconds."
msgstr ""
msgid "Elasticsearch indexing restrictions"
@@ -9145,9 +9434,6 @@ msgstr ""
msgid "Elasticsearch indexing started"
msgstr ""
-msgid "Elasticsearch integration. Elasticsearch AWS IAM."
-msgstr ""
-
msgid "Elasticsearch reindexing is already in progress"
msgstr ""
@@ -9175,9 +9461,6 @@ msgstr ""
msgid "Email Notification"
msgstr ""
-msgid "Email address"
-msgstr ""
-
msgid "Email could not be sent"
msgstr ""
@@ -9241,6 +9524,9 @@ msgstr ""
msgid "Emails sent from Service Desk will have this name"
msgstr ""
+msgid "Emails sent to %{email} will still be supported"
+msgstr ""
+
msgid "Emails separated by comma"
msgstr ""
@@ -9274,9 +9560,18 @@ msgstr ""
msgid "Enable"
msgstr ""
+msgid "Enable %{link_start}Gitpod%{link_end} integration to launch a development environment in your browser directly from GitLab."
+msgstr ""
+
msgid "Enable Auto DevOps"
msgstr ""
+msgid "Enable Gitpod"
+msgstr ""
+
+msgid "Enable Gitpod?"
+msgstr ""
+
msgid "Enable HTML emails"
msgstr ""
@@ -9406,9 +9701,6 @@ msgstr ""
msgid "Encountered an error while rendering: %{err}"
msgstr ""
-msgid "End date"
-msgstr ""
-
msgid "Ends at (UTC)"
msgstr ""
@@ -9568,7 +9860,7 @@ msgstr ""
msgid "EnvironmentsDashboard|The environments dashboard provides a summary of each project's environments' status, including pipeline and alert statuses."
msgstr ""
-msgid "EnvironmentsDashboard|This dashboard displays a maximum of 7 projects and 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
+msgid "EnvironmentsDashboard|This dashboard displays 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
msgstr ""
msgid "Environments|An error occurred while canceling the auto stop, please try again"
@@ -9889,6 +10181,9 @@ msgstr ""
msgid "Error deleting project. Check logs for error details."
msgstr ""
+msgid "Error fetching burnup chart data"
+msgstr ""
+
msgid "Error fetching diverging counts for branches. Please try again."
msgstr ""
@@ -9967,6 +10262,9 @@ msgstr ""
msgid "Error occurred when saving assignees"
msgstr ""
+msgid "Error occurred when saving reviewers"
+msgstr ""
+
msgid "Error occurred when toggling the notification subscription"
msgstr ""
@@ -10219,10 +10517,13 @@ msgstr ""
msgid "Expand all"
msgstr ""
-msgid "Expand approvers"
+msgid "Expand all files"
msgstr ""
-msgid "Expand dropdown"
+msgid "Expand all threads"
+msgstr ""
+
+msgid "Expand approvers"
msgstr ""
msgid "Expand milestones"
@@ -10393,6 +10694,9 @@ msgstr ""
msgid "Failed to create Merge Request. Please try again."
msgstr ""
+msgid "Failed to create To-Do for the design."
+msgstr ""
+
msgid "Failed to create a branch for this issue. Please try again."
msgstr ""
@@ -10432,6 +10736,12 @@ msgstr ""
msgid "Failed to load authors. Please try again."
msgstr ""
+msgid "Failed to load branches. Please try again."
+msgstr ""
+
+msgid "Failed to load deploy keys."
+msgstr ""
+
msgid "Failed to load emoji list."
msgstr ""
@@ -10447,6 +10757,9 @@ msgstr ""
msgid "Failed to load groups & users."
msgstr ""
+msgid "Failed to load groups, users and deploy keys."
+msgstr ""
+
msgid "Failed to load labels. Please try again."
msgstr ""
@@ -10456,6 +10769,12 @@ msgstr ""
msgid "Failed to load related branches"
msgstr ""
+msgid "Failed to load sidebar confidential toggle"
+msgstr ""
+
+msgid "Failed to load sidebar lock status"
+msgstr ""
+
msgid "Failed to load stacktrace."
msgstr ""
@@ -10483,6 +10802,9 @@ msgstr ""
msgid "Failed to publish issue on status page."
msgstr ""
+msgid "Failed to remove To-Do for the design."
+msgstr ""
+
msgid "Failed to remove a Zoom meeting"
msgstr ""
@@ -10525,6 +10847,9 @@ msgstr ""
msgid "Failed to signing using smartcard authentication"
msgstr ""
+msgid "Failed to toggle To-Do for the design."
+msgstr ""
+
msgid "Failed to update branch!"
msgstr ""
@@ -10638,7 +10963,7 @@ msgstr ""
msgid "FeatureFlags|Edit User List"
msgstr ""
-msgid "FeatureFlags|Enable features for specific users and specific environments by defining feature flag strategies."
+msgid "FeatureFlags|Enable features for specific users and environments by configuring feature flag strategies."
msgstr ""
msgid "FeatureFlags|Environment Spec"
@@ -10698,7 +11023,7 @@ msgstr ""
msgid "FeatureFlags|Include additional user IDs"
msgstr ""
-msgid "FeatureFlags|Install a %{docs_link_anchored_start}compatible client library%{docs_link_anchored_end} and specify the API URL, application name, and instance ID during the configuration setup. %{docs_link_start}More Information%{docs_link_end}"
+msgid "FeatureFlags|Install a %{docsLinkAnchoredStart}compatible client library%{docsLinkAnchoredEnd} and specify the API URL, application name, and instance ID during the configuration setup. %{docsLinkStart}More Information%{docsLinkEnd}"
msgstr ""
msgid "FeatureFlags|Instance ID"
@@ -10710,6 +11035,9 @@ msgstr ""
msgid "FeatureFlags|Loading feature flags"
msgstr ""
+msgid "FeatureFlags|Loading user lists"
+msgstr ""
+
msgid "FeatureFlags|More information"
msgstr ""
@@ -10728,7 +11056,7 @@ msgstr ""
msgid "FeatureFlags|New feature flag"
msgstr ""
-msgid "FeatureFlags|New list"
+msgid "FeatureFlags|New user list"
msgstr ""
msgid "FeatureFlags|Percent of users"
@@ -10767,6 +11095,9 @@ msgstr ""
msgid "FeatureFlags|There was an error fetching the feature flags."
msgstr ""
+msgid "FeatureFlags|There was an error fetching the user lists."
+msgstr ""
+
msgid "FeatureFlags|There was an error retrieving user lists"
msgstr ""
@@ -10782,6 +11113,9 @@ msgstr ""
msgid "FeatureFlags|User List"
msgstr ""
+msgid "FeatureFlags|User Lists"
+msgstr ""
+
msgid "FeatureFlag|List"
msgstr ""
@@ -10809,15 +11143,6 @@ msgstr ""
msgid "Fetching incoming email"
msgstr ""
-msgid "Fetching licenses failed."
-msgstr ""
-
-msgid "Fetching licenses failed. The request endpoint was not found."
-msgstr ""
-
-msgid "Fetching licenses failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "File"
msgstr ""
@@ -10920,12 +11245,21 @@ msgstr ""
msgid "Filter by status"
msgstr ""
+msgid "Filter by test cases that are currently archived."
+msgstr ""
+
+msgid "Filter by test cases that are currently opened."
+msgstr ""
+
msgid "Filter by two-factor authentication"
msgstr ""
msgid "Filter by user"
msgstr ""
+msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
+msgstr ""
+
msgid "Filter pipelines"
msgstr ""
@@ -10941,7 +11275,7 @@ msgstr ""
msgid "Filter results..."
msgstr ""
-msgid "Filter your projects by name"
+msgid "Filter your repositories by name"
msgstr ""
msgid "Filter..."
@@ -10950,7 +11284,7 @@ msgstr ""
msgid "Find File"
msgstr ""
-msgid "Find bugs in your code with coverage-guided fuzzing"
+msgid "Find bugs in your code with coverage-guided fuzzing."
msgstr ""
msgid "Find by path"
@@ -10977,9 +11311,6 @@ msgstr ""
msgid "Finish editing this message first!"
msgstr ""
-msgid "Finish review"
-msgstr ""
-
msgid "Finish setting up your dedicated account for %{group_name}."
msgstr ""
@@ -11049,6 +11380,9 @@ msgstr ""
msgid "Footer message"
msgstr ""
+msgid "For a faster browsing experience, some files are collapsed by default."
+msgstr ""
+
msgid "For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
@@ -11058,6 +11392,9 @@ msgstr ""
msgid "For more info, read the documentation."
msgstr ""
+msgid "For more information on how the number of active users is calculated, see the %{self_managed_subscriptions_doc_link} documentation."
+msgstr ""
+
msgid "For more information, go to the "
msgstr ""
@@ -11196,6 +11533,9 @@ msgstr ""
msgid "Generate new token"
msgstr ""
+msgid "Generic package file size in bytes"
+msgstr ""
+
msgid "Geo"
msgstr ""
@@ -11457,6 +11797,9 @@ msgstr ""
msgid "Geo|Please refer to Geo Troubleshooting."
msgstr ""
+msgid "Geo|Primary node"
+msgstr ""
+
msgid "Geo|Project"
msgstr ""
@@ -11499,6 +11842,9 @@ msgstr ""
msgid "Geo|Review replication status, and resynchronize and reverify items with the primary node."
msgstr ""
+msgid "Geo|Secondary node"
+msgstr ""
+
msgid "Geo|Status"
msgstr ""
@@ -11538,6 +11884,9 @@ msgstr ""
msgid "Geo|URL must be a valid url (ex: https://gitlab.com)"
msgstr ""
+msgid "Geo|Undefined"
+msgstr ""
+
msgid "Geo|Unknown state"
msgstr ""
@@ -11613,10 +11962,16 @@ msgstr ""
msgid "GitHub import"
msgstr ""
+msgid "GitLab"
+msgstr ""
+
msgid "GitLab / Unsubscribe"
msgstr ""
-msgid "GitLab Enterprise Edition %{plan}"
+msgid "GitLab API"
+msgstr ""
+
+msgid "GitLab Billing Team."
msgstr ""
msgid "GitLab Group Runners can execute code for all the projects in this group."
@@ -11628,12 +11983,18 @@ msgstr ""
msgid "GitLab Issue"
msgstr ""
+msgid "GitLab Pages"
+msgstr ""
+
msgid "GitLab Service Desk is a simple way to allow people to create issues in your GitLab instance without needing their own user account. It provides a unique email address for end users to create issues in a project, and replies can be sent either through the GitLab interface or by email. End users will only see the thread through email."
msgstr ""
msgid "GitLab Shared Runners execute code of different projects on the same Runner unless you configure GitLab Runner Autoscale with MaxBuilds 1 (which it is on GitLab.com)."
msgstr ""
+msgid "GitLab Shell"
+msgstr ""
+
msgid "GitLab Support Bot"
msgstr ""
@@ -11643,7 +12004,7 @@ msgstr ""
msgid "GitLab User"
msgstr ""
-msgid "GitLab allows you to continue using your license even if you exceed the number of seats you purchased. You will be required to pay for these seats when you renew your license."
+msgid "GitLab Workhorse"
msgstr ""
msgid "GitLab commit"
@@ -11811,6 +12172,21 @@ msgstr ""
msgid "Gitlab Pages"
msgstr ""
+msgid "Gitpod"
+msgstr ""
+
+msgid "Gitpod|Add the URL to your Gitpod instance configured to read your GitLab projects."
+msgstr ""
+
+msgid "Gitpod|Enable Gitpod integration"
+msgstr ""
+
+msgid "Gitpod|Gitpod URL"
+msgstr ""
+
+msgid "Gitpod|e.g. https://gitpod.example.com"
+msgstr ""
+
msgid "Given access %{time_ago}"
msgstr ""
@@ -12318,9 +12694,6 @@ msgstr ""
msgid "GroupSAML|Valid SAML Response"
msgstr ""
-msgid "GroupSAML|With group managed accounts enabled, all the users without a group managed account will be excluded from the group."
-msgstr ""
-
msgid "GroupSAML|With prohibit outer forks flag enabled group members will be able to fork project only inside your group."
msgstr ""
@@ -12534,10 +12907,10 @@ msgstr ""
msgid "GroupsNew|Create group"
msgstr ""
-msgid "GroupsNew|GitLab group export"
+msgid "GroupsNew|Import"
msgstr ""
-msgid "GroupsNew|Import"
+msgid "GroupsNew|Import a GitLab group export file"
msgstr ""
msgid "GroupsNew|Import group"
@@ -12680,6 +13053,9 @@ msgid_plural "Hide charts"
msgstr[0] ""
msgstr[1] ""
+msgid "Hide comments on this file"
+msgstr ""
+
msgid "Hide details"
msgstr ""
@@ -12724,6 +13100,15 @@ msgstr ""
msgid "Highest role:"
msgstr ""
+msgid "HighlightBar|Alert events:"
+msgstr ""
+
+msgid "HighlightBar|Alert start time:"
+msgstr ""
+
+msgid "HighlightBar|Original alert:"
+msgstr ""
+
msgid "History"
msgstr ""
@@ -12901,6 +13286,9 @@ msgstr ""
msgid "If enabled, access to projects will be validated on an external service using their classification label."
msgstr ""
+msgid "If the number of active users exceeds the user limit, you will be charged for the number of %{users_over_license_link} at your next license reconciliation."
+msgstr ""
+
msgid "If there is no previous license or if the previous license has expired, some GitLab functionality will be blocked until a new, valid license is uploaded."
msgstr ""
@@ -12940,9 +13328,6 @@ msgstr ""
msgid "If your HTTP repository is not publicly accessible, add your credentials."
msgstr ""
-msgid "Iglu registry URL (optional)"
-msgstr ""
-
msgid "Ignore"
msgstr ""
@@ -12979,6 +13364,16 @@ msgstr ""
msgid "Import"
msgstr ""
+msgid "Import %d compatible repository"
+msgid_plural "Import %d compatible repositories"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Import %d repository"
+msgid_plural "Import %d repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Import CSV"
msgstr ""
@@ -12988,15 +13383,9 @@ msgstr ""
msgid "Import all compatible projects"
msgstr ""
-msgid "Import all compatible repositories"
-msgstr ""
-
msgid "Import all projects"
msgstr ""
-msgid "Import all repositories"
-msgstr ""
-
msgid "Import an exported GitLab project"
msgstr ""
@@ -13084,6 +13473,9 @@ msgstr ""
msgid "ImportProjects|Error importing repository %{project_safe_import_url} into %{project_full_path} - %{message}"
msgstr ""
+msgid "ImportProjects|Import repositories"
+msgstr ""
+
msgid "ImportProjects|Importing the project failed"
msgstr ""
@@ -13096,7 +13488,7 @@ msgstr ""
msgid "ImportProjects|Requesting your %{provider} repositories failed"
msgstr ""
-msgid "ImportProjects|Select the projects you want to import"
+msgid "ImportProjects|Select the repositories you want to import"
msgstr ""
msgid "ImportProjects|The remote data could not be imported."
@@ -13132,9 +13524,6 @@ msgstr ""
msgid "In order to enable Service Desk for your instance, you must first set up incoming email."
msgstr ""
-msgid "In order to gather accurate feature usage data, it can take 1 to 2 weeks to see your index."
-msgstr ""
-
msgid "In order to personalize your experience with GitLab%{br_tag}we would like to know a bit more about you."
msgstr ""
@@ -13165,18 +13554,30 @@ msgstr ""
msgid "IncidentManagement|Create incident"
msgstr ""
+msgid "IncidentManagement|Critical - S1"
+msgstr ""
+
msgid "IncidentManagement|Date created"
msgstr ""
msgid "IncidentManagement|Display your incidents in a dedicated view"
msgstr ""
+msgid "IncidentManagement|High - S2"
+msgstr ""
+
msgid "IncidentManagement|Incident"
msgstr ""
msgid "IncidentManagement|Incidents"
msgstr ""
+msgid "IncidentManagement|Low - S4"
+msgstr ""
+
+msgid "IncidentManagement|Medium - S3"
+msgstr ""
+
msgid "IncidentManagement|No incidents to display."
msgstr ""
@@ -13189,6 +13590,9 @@ msgstr ""
msgid "IncidentManagement|Published to status page"
msgstr ""
+msgid "IncidentManagement|Severity"
+msgstr ""
+
msgid "IncidentManagement|There are no closed incidents"
msgstr ""
@@ -13198,6 +13602,9 @@ msgstr ""
msgid "IncidentManagement|Unassigned"
msgstr ""
+msgid "IncidentManagement|Unknown"
+msgstr ""
+
msgid "IncidentManagement|Unpublished"
msgstr ""
@@ -13219,6 +13626,15 @@ msgstr ""
msgid "Incidents"
msgstr ""
+msgid "Incident|Alert details"
+msgstr ""
+
+msgid "Incident|Summary"
+msgstr ""
+
+msgid "Incident|There was an issue loading alert data. Please try again."
+msgstr ""
+
msgid "Include a Terms of Service agreement and Privacy Policy that all users must accept."
msgstr ""
@@ -13279,6 +13695,9 @@ msgstr ""
msgid "Information about additional Pages templates and how to install them can be found in our %{pages_getting_started_guide}."
msgstr ""
+msgid "Inherited"
+msgstr ""
+
msgid "Inherited:"
msgstr ""
@@ -13359,7 +13778,22 @@ msgstr ""
msgid "Instance administrators group already exists"
msgstr ""
-msgid "Instance license"
+msgid "InstanceStatistics|Groups"
+msgstr ""
+
+msgid "InstanceStatistics|Issues"
+msgstr ""
+
+msgid "InstanceStatistics|Merge Requests"
+msgstr ""
+
+msgid "InstanceStatistics|Pipelines"
+msgstr ""
+
+msgid "InstanceStatistics|Projects"
+msgstr ""
+
+msgid "InstanceStatistics|Users"
msgstr ""
msgid "Integration"
@@ -13371,6 +13805,12 @@ msgstr ""
msgid "Integrations"
msgstr ""
+msgid "Integrations|%{integration} settings saved and active."
+msgstr ""
+
+msgid "Integrations|%{integration} settings saved, but not active."
+msgstr ""
+
msgid "Integrations|All details"
msgstr ""
@@ -13380,6 +13820,12 @@ msgstr ""
msgid "Integrations|Comment settings:"
msgstr ""
+msgid "Integrations|Connection failed. Please check your settings."
+msgstr ""
+
+msgid "Integrations|Connection successful."
+msgstr ""
+
msgid "Integrations|Default settings are inherited from the group level."
msgstr ""
@@ -13395,6 +13841,15 @@ msgstr ""
msgid "Integrations|Includes commit title and branch"
msgstr ""
+msgid "Integrations|Projects using custom settings will not be impacted unless the project owner chooses to use instance-level defaults."
+msgstr ""
+
+msgid "Integrations|Save settings?"
+msgstr ""
+
+msgid "Integrations|Saving will update the default settings for all projects that are not using custom settings."
+msgstr ""
+
msgid "Integrations|Standard"
msgstr ""
@@ -13527,6 +13982,9 @@ msgstr ""
msgid "Invitation"
msgstr ""
+msgid "Invitation declined"
+msgstr ""
+
msgid "Invite"
msgstr ""
@@ -13578,6 +14036,42 @@ 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|%{linkStart}Read more%{linkEnd} about role permissions"
+msgstr ""
+
+msgid "InviteMembersModal|Access expiration date (optional)"
+msgstr ""
+
+msgid "InviteMembersModal|Cancel"
+msgstr ""
+
+msgid "InviteMembersModal|Choose a role permission"
+msgstr ""
+
+msgid "InviteMembersModal|GitLab member or Email address"
+msgstr ""
+
+msgid "InviteMembersModal|Invite"
+msgstr ""
+
+msgid "InviteMembersModal|Invite team members"
+msgstr ""
+
+msgid "InviteMembersModal|Search for members to invite"
+msgstr ""
+
+msgid "InviteMembersModal|User not invited. Feature coming soon!"
+msgstr ""
+
+msgid "InviteMembersModal|Users were succesfully added"
+msgstr ""
+
+msgid "InviteMembersModal|You're inviting members to the %{group_name} group"
+msgstr ""
+
+msgid "InviteMembers|Invite team members"
+msgstr ""
+
msgid "Invited"
msgstr ""
@@ -13632,10 +14126,13 @@ msgstr ""
msgid "Issue cannot be found."
msgstr ""
+msgid "Issue created from vulnerability %{vulnerability_link}"
+msgstr ""
+
msgid "Issue events"
msgstr ""
-msgid "Issue first depoloyed to production"
+msgid "Issue first deployed to production"
msgstr ""
msgid "Issue label"
@@ -13713,6 +14210,9 @@ msgstr ""
msgid "IssueTracker|Custom issue tracker"
msgstr ""
+msgid "IssueTracker|EWM work items tracker"
+msgstr ""
+
msgid "IssueTracker|Redmine issue tracker"
msgstr ""
@@ -13779,6 +14279,9 @@ msgstr ""
msgid "It looks like you have some draft commits in this branch."
msgstr ""
+msgid "It may be several days before you see feature usage data."
+msgstr ""
+
msgid "It must have a header row and at least two columns: the first column is the issue title and the second column is the issue description. The separator is automatically detected."
msgstr ""
@@ -14061,13 +14564,13 @@ msgstr ""
msgid "Join Zoom meeting"
msgstr ""
-msgid "Jul"
+msgid "Joined %{time_ago}"
msgstr ""
-msgid "July"
+msgid "Jul"
msgstr ""
-msgid "Jump to first unresolved thread"
+msgid "July"
msgstr ""
msgid "Jump to next unresolved thread"
@@ -14103,6 +14606,9 @@ msgstr ""
msgid "Keyboard shortcuts"
msgstr ""
+msgid "KeyboardKey|Ctrl+"
+msgstr ""
+
msgid "Keys"
msgstr ""
@@ -14151,6 +14657,9 @@ msgstr ""
msgid "LDAP Synchronization"
msgstr ""
+msgid "LDAP group settings"
+msgstr ""
+
msgid "LDAP settings"
msgstr ""
@@ -14160,6 +14669,9 @@ msgstr ""
msgid "LDAP sync in progress. This could take a few minutes. Refresh the page to see the changes."
msgstr ""
+msgid "LDAP synchronizations"
+msgstr ""
+
msgid "LFS"
msgstr ""
@@ -14240,7 +14752,16 @@ msgid_plural "Last %d days"
msgstr[0] ""
msgstr[1] ""
-msgid "Last %{days} days"
+msgid "Last 2 weeks"
+msgstr ""
+
+msgid "Last 30 days"
+msgstr ""
+
+msgid "Last 60 days"
+msgstr ""
+
+msgid "Last 90 days"
msgstr ""
msgid "Last Accessed On"
@@ -14318,6 +14839,9 @@ msgstr ""
msgid "Last used on:"
msgstr ""
+msgid "Last week"
+msgstr ""
+
msgid "LastCommit|authored"
msgstr ""
@@ -14333,6 +14857,9 @@ msgstr ""
msgid "Latest pipeline for the most recent commit on this branch"
msgstr ""
+msgid "Launch a ready-to-code development environment for your project."
+msgstr ""
+
msgid "Lead"
msgstr ""
@@ -14713,6 +15240,9 @@ msgstr ""
msgid "List of all merge commits"
msgstr ""
+msgid "List options"
+msgstr ""
+
msgid "List settings"
msgstr ""
@@ -14725,9 +15255,6 @@ msgstr ""
msgid "List your Bitbucket Server repositories"
msgstr ""
-msgid "Lists"
-msgstr ""
-
msgid "Live preview"
msgstr ""
@@ -14974,6 +15501,12 @@ msgstr ""
msgid "Mark as done"
msgstr ""
+msgid "Mark as draft"
+msgstr ""
+
+msgid "Mark as ready"
+msgstr ""
+
msgid "Mark as resolved"
msgstr ""
@@ -14995,6 +15528,24 @@ msgstr ""
msgid "Markdown is supported"
msgstr ""
+msgid "MarkdownEditor|Add a link (%{modifierKey}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add a link (%{modifier_key}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifierKey}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifier_key}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifierKey}I)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifier_key}I)"
+msgstr ""
+
msgid "Marked For Deletion At - %{deletion_time}"
msgstr ""
@@ -15079,7 +15630,25 @@ msgstr ""
msgid "Max access level"
msgstr ""
-msgid "Max seats used"
+msgid "Max role"
+msgstr ""
+
+msgid "Max size 15 MB"
+msgstr ""
+
+msgid "Maximum Conan package file size in bytes"
+msgstr ""
+
+msgid "Maximum Maven package file size in bytes"
+msgstr ""
+
+msgid "Maximum NPM package file size in bytes"
+msgstr ""
+
+msgid "Maximum NuGet package file size in bytes"
+msgstr ""
+
+msgid "Maximum PyPI package file size in bytes"
msgstr ""
msgid "Maximum Users:"
@@ -15211,6 +15780,18 @@ msgstr ""
msgid "Members with access to %{strong_start}%{group_name}%{strong_end}"
msgstr ""
+msgid "Members|%{time} by %{user}"
+msgstr ""
+
+msgid "Members|Expired"
+msgstr ""
+
+msgid "Members|No expiration set"
+msgstr ""
+
+msgid "Members|in %{time}"
+msgstr ""
+
msgid "Memory Usage"
msgstr ""
@@ -15397,9 +15978,6 @@ msgstr ""
msgid "MergeRequests|Thread will be unresolved"
msgstr ""
-msgid "MergeRequests|Toggle comments for this file"
-msgstr ""
-
msgid "MergeRequests|View file @ %{commitId}"
msgstr ""
@@ -15460,6 +16038,9 @@ msgstr ""
msgid "Merging immediately isn't recommended as it may negatively impact the existing merge train. Read the %{docsLinkStart}documentation%{docsLinkEnd} for more information."
msgstr ""
+msgid "Message"
+msgstr ""
+
msgid "Messages"
msgstr ""
@@ -15845,18 +16426,12 @@ msgid_plural "Milestones"
msgstr[0] ""
msgstr[1] ""
-msgid "Milestone does not support burnup charts"
-msgstr ""
-
msgid "Milestone lists not available with your current license"
msgstr ""
msgid "Milestone lists show all issues from the selected milestone."
msgstr ""
-msgid "Milestone must have a start and due date"
-msgstr ""
-
msgid "MilestoneSidebar|Closed:"
msgstr ""
@@ -16223,6 +16798,9 @@ msgstr ""
msgid "Namespace"
msgstr ""
+msgid "Namespace ID:"
+msgstr ""
+
msgid "Namespace is empty"
msgstr ""
@@ -16307,6 +16885,9 @@ msgstr ""
msgid "NetworkPolicies|Allow all outbound traffic from %{selector} to %{ruleSelector} on %{ports}"
msgstr ""
+msgid "NetworkPolicies|Are you sure you want to delete this policy? This action cannot be undone."
+msgstr ""
+
msgid "NetworkPolicies|Choose whether to enforce this policy."
msgstr ""
@@ -16316,12 +16897,21 @@ msgstr ""
msgid "NetworkPolicies|Define this policy's location, conditions and actions."
msgstr ""
+msgid "NetworkPolicies|Delete policy"
+msgstr ""
+
+msgid "NetworkPolicies|Delete policy: %{policy}"
+msgstr ""
+
msgid "NetworkPolicies|Deny all traffic"
msgstr ""
msgid "NetworkPolicies|Description"
msgstr ""
+msgid "NetworkPolicies|Edit policy"
+msgstr ""
+
msgid "NetworkPolicies|Editor mode"
msgstr ""
@@ -16349,6 +16939,9 @@ msgstr ""
msgid "NetworkPolicies|Name"
msgstr ""
+msgid "NetworkPolicies|Namespace"
+msgstr ""
+
msgid "NetworkPolicies|Network Policy"
msgstr ""
@@ -16400,6 +16993,9 @@ msgstr ""
msgid "NetworkPolicies|Rules"
msgstr ""
+msgid "NetworkPolicies|Save changes"
+msgstr ""
+
msgid "NetworkPolicies|Something went wrong, failed to update policy"
msgstr ""
@@ -16412,6 +17008,9 @@ msgstr ""
msgid "NetworkPolicies|Traffic that does not match any rule will be blocked."
msgstr ""
+msgid "NetworkPolicies|Unable to parse policy"
+msgstr ""
+
msgid "NetworkPolicies|YAML editor"
msgstr ""
@@ -16525,6 +17124,9 @@ msgstr ""
msgid "New Snippet"
msgstr ""
+msgid "New Test Case"
+msgstr ""
+
msgid "New User"
msgstr ""
@@ -16624,6 +17226,9 @@ msgstr ""
msgid "New tag"
msgstr ""
+msgid "New test case"
+msgstr ""
+
msgid "New users set to external"
msgstr ""
@@ -16696,7 +17301,7 @@ msgstr ""
msgid "No changes"
msgstr ""
-msgid "No changes between %{ref_start}%{source_branch}%{ref_end} and %{ref_start}%{target_branch}%{ref_end}"
+msgid "No changes between %{sourceBranch} and %{targetBranch}"
msgstr ""
msgid "No child epics match applied filters"
@@ -16711,6 +17316,9 @@ msgstr ""
msgid "No containers available"
msgstr ""
+msgid "No content to show"
+msgstr ""
+
msgid "No contributions"
msgstr ""
@@ -16786,9 +17394,6 @@ msgstr ""
msgid "No license. All rights reserved"
msgstr ""
-msgid "No licenses found."
-msgstr ""
-
msgid "No matches found"
msgstr ""
@@ -16801,6 +17406,9 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No members found"
+msgstr ""
+
msgid "No merge requests found"
msgstr ""
@@ -16822,6 +17430,9 @@ msgstr ""
msgid "No parent group"
msgstr ""
+msgid "No plan"
+msgstr ""
+
msgid "No pods available"
msgstr ""
@@ -16918,6 +17529,12 @@ msgstr ""
msgid "Not Implemented"
msgstr ""
+msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+msgstr ""
+
+msgid "Not all browsers support WebAuthn. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even from an unsupported browser."
+msgstr ""
+
msgid "Not all data has been processed yet, the accuracy of the chart for the selected timeframe is limited."
msgstr ""
@@ -17014,6 +17631,9 @@ msgstr ""
msgid "Notification settings saved"
msgstr ""
+msgid "NotificationEvent|Change reviewer merge request"
+msgstr ""
+
msgid "NotificationEvent|Close issue"
msgstr ""
@@ -17176,10 +17796,7 @@ msgstr ""
msgid "On track"
msgstr ""
-msgid "OnDemandScans|Attached branch"
-msgstr ""
-
-msgid "OnDemandScans|Attached branch is where the scan job runs."
+msgid "OnDemandScans|Could not fetch scanner profiles. Please refresh the page, or try again later."
msgstr ""
msgid "OnDemandScans|Could not fetch site profiles. Please refresh the page, or try again later."
@@ -17188,6 +17805,9 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
+msgid "OnDemandScans|Create a new scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Create a new site profile"
msgstr ""
@@ -17200,6 +17820,9 @@ msgstr ""
msgid "OnDemandScans|New on-demand DAST scan"
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 ""
@@ -17209,16 +17832,10 @@ msgstr ""
msgid "OnDemandScans|On-demand scans run outside the DevOps cycle and find vulnerabilities in your projects. %{learnMoreLinkStart}Learn more%{learnMoreLinkEnd}"
msgstr ""
-msgid "OnDemandScans|Only a passive scan can be performed on demand."
-msgstr ""
-
-msgid "OnDemandScans|Passive"
-msgstr ""
-
msgid "OnDemandScans|Run scan"
msgstr ""
-msgid "OnDemandScans|Scan mode"
+msgid "OnDemandScans|Scanner profile"
msgstr ""
msgid "OnDemandScans|Scanner settings"
@@ -17230,9 +17847,15 @@ msgstr ""
msgid "OnDemandScans|Select one of the existing profiles"
msgstr ""
+msgid "OnDemandScans|Site profile"
+msgstr ""
+
msgid "OnDemandScans|Site profiles"
msgstr ""
+msgid "OnDemandScans|Use existing scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Use existing site profile"
msgstr ""
@@ -17331,9 +17954,6 @@ msgstr ""
msgid "Open Selection"
msgstr ""
-msgid "Open Web IDE"
-msgstr ""
-
msgid "Open comment type dropdown"
msgstr ""
@@ -17439,6 +18059,9 @@ msgstr ""
msgid "Origin"
msgstr ""
+msgid "Orphaned member"
+msgstr ""
+
msgid "Other Labels"
msgstr ""
@@ -17454,6 +18077,9 @@ msgstr ""
msgid "Other visibility settings have been disabled by the administrator."
msgstr ""
+msgid "Our documentation includes an example DevOps Score report."
+msgstr ""
+
msgid "Out-of-compliance with this project's policies and should be removed"
msgstr ""
@@ -17478,6 +18104,9 @@ msgstr ""
msgid "Overwrite diverged branches"
msgstr ""
+msgid "Owned by %{image_tag}"
+msgstr ""
+
msgid "Owned by anyone"
msgstr ""
@@ -17499,6 +18128,9 @@ msgstr ""
msgid "Package deleted successfully"
msgstr ""
+msgid "Package file size limits"
+msgstr ""
+
msgid "Package recipe already exists"
msgstr ""
@@ -17514,9 +18146,6 @@ msgstr ""
msgid "Package type must be PyPi"
msgstr ""
-msgid "Package was removed"
-msgstr ""
-
msgid "PackageRegistry|%{name} version %{version} was created %{datetime}"
msgstr ""
@@ -17658,12 +18287,18 @@ msgstr ""
msgid "PackageRegistry|NuGet Command"
msgstr ""
+msgid "PackageRegistry|Package Registry"
+msgstr ""
+
msgid "PackageRegistry|Pip Command"
msgstr ""
msgid "PackageRegistry|Pipeline %{link} triggered %{datetime} by %{author}"
msgstr ""
+msgid "PackageRegistry|Publish and share packages for a variety of common package managers. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "PackageRegistry|Published to the %{project} Package Registry %{datetime}"
msgstr ""
@@ -17763,6 +18398,9 @@ msgstr ""
msgid "Page not found"
msgstr ""
+msgid "Page settings"
+msgstr ""
+
msgid "Page was successfully deleted"
msgstr ""
@@ -17904,7 +18542,7 @@ msgstr ""
msgid "Paste issue link"
msgstr ""
-msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Don't use your private SSH key."
+msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Do not paste your private SSH key, as that can compromise your identity."
msgstr ""
msgid "Patch to apply"
@@ -17931,6 +18569,9 @@ msgstr ""
msgid "Pending"
msgstr ""
+msgid "Pending comments"
+msgstr ""
+
msgid "People without permission will never get a notification and won't be able to comment."
msgstr ""
@@ -18129,6 +18770,9 @@ msgstr ""
msgid "Pipelines|Build with confidence"
msgstr ""
+msgid "Pipelines|By revoking a trigger you will break any processes making use of it. Are you sure?"
+msgstr ""
+
msgid "Pipelines|CI Lint"
msgstr ""
@@ -18141,6 +18785,15 @@ msgstr ""
msgid "Pipelines|Continuous Integration can help catch bugs by running your tests automatically, while Continuous Deployment can help you deliver code to your product environment."
msgstr ""
+msgid "Pipelines|Copy trigger token"
+msgstr ""
+
+msgid "Pipelines|Description"
+msgstr ""
+
+msgid "Pipelines|Edit"
+msgstr ""
+
msgid "Pipelines|Get started with Pipelines"
msgstr ""
@@ -18156,15 +18809,27 @@ msgstr ""
msgid "Pipelines|It is recommended the code is reviewed thoroughly before running this pipeline with the parent project's CI resource."
msgstr ""
+msgid "Pipelines|Last Used"
+msgstr ""
+
msgid "Pipelines|Loading Pipelines"
msgstr ""
msgid "Pipelines|More Information"
msgstr ""
+msgid "Pipelines|No triggers have been created yet. Add one using the form above."
+msgstr ""
+
+msgid "Pipelines|Owner"
+msgstr ""
+
msgid "Pipelines|Project cache successfully reset."
msgstr ""
+msgid "Pipelines|Revoke"
+msgstr ""
+
msgid "Pipelines|Run Pipeline"
msgstr ""
@@ -18189,6 +18854,15 @@ msgstr ""
msgid "Pipelines|This project is not currently set up to run pipelines."
msgstr ""
+msgid "Pipelines|Token"
+msgstr ""
+
+msgid "Pipelines|Trigger user has insufficient permissions to project"
+msgstr ""
+
+msgid "Pipelines|invalid"
+msgstr ""
+
msgid "Pipelines|parent"
msgstr ""
@@ -18447,10 +19121,10 @@ msgstr ""
msgid "Please provide attributes to update"
msgstr ""
-msgid "Please refer to %{docs_url}"
+msgid "Please reach out if you have any questions and we'll be happy to assist."
msgstr ""
-msgid "Please retype the email address."
+msgid "Please refer to %{docs_url}"
msgstr ""
msgid "Please select"
@@ -18480,6 +19154,9 @@ msgstr ""
msgid "Please set a new password before proceeding."
msgstr ""
+msgid "Please share your feedback about %{featureName} %{linkStart}in this issue%{linkEnd} to help us improve the experience."
+msgstr ""
+
msgid "Please solve the reCAPTCHA"
msgstr ""
@@ -18783,6 +19460,9 @@ msgstr ""
msgid "Profiles| You are going to change the username %{currentUsernameBold} to %{newUsernameBold}. Profile and projects will be redirected to the %{newUsername} namespace but this redirect will expire once the %{currentUsername} namespace is registered by another user or group. Please update your Git repository remotes as soon as possible."
msgstr ""
+msgid "Profiles|%{provider} Active"
+msgstr ""
+
msgid "Profiles|@username"
msgstr ""
@@ -18834,7 +19514,7 @@ msgstr ""
msgid "Profiles|Commit email"
msgstr ""
-msgid "Profiles|Connect"
+msgid "Profiles|Connect %{provider}"
msgstr ""
msgid "Profiles|Connected Accounts"
@@ -18858,6 +19538,9 @@ msgstr ""
msgid "Profiles|Disconnect"
msgstr ""
+msgid "Profiles|Disconnect %{provider}"
+msgstr ""
+
msgid "Profiles|Do not show on profile"
msgstr ""
@@ -18882,7 +19565,7 @@ msgstr ""
msgid "Profiles|Full name"
msgstr ""
-msgid "Profiles|Give your individual key a title. This will be publically visible."
+msgid "Profiles|Give your individual key a title."
msgstr ""
msgid "Profiles|Include private contributions on my profile"
@@ -18972,7 +19655,7 @@ msgstr ""
msgid "Profiles|The maximum file size allowed is 200KB."
msgstr ""
-msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it?"
+msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it? It will be publicly visible."
msgstr ""
msgid "Profiles|This email will be displayed on your public profile"
@@ -19047,6 +19730,9 @@ msgstr ""
msgid "Profiles|You don't have access to delete this user."
msgstr ""
+msgid "Profiles|You must transfer ownership or delete groups you are an owner of before you can delete your account"
+msgstr ""
+
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
@@ -19635,6 +20321,9 @@ msgstr ""
msgid "ProjectTemplates|GitLab Cluster Management"
msgstr ""
+msgid "ProjectTemplates|Gitpod/Spring Petclinic"
+msgstr ""
+
msgid "ProjectTemplates|Go Micro"
msgstr ""
@@ -20244,6 +20933,9 @@ msgstr ""
msgid "Publish to status page"
msgstr ""
+msgid "Published"
+msgstr ""
+
msgid "Published on status page"
msgstr ""
@@ -20361,9 +21053,15 @@ msgstr ""
msgid "Quick range"
msgstr ""
+msgid "Quickly and easily edit multiple files in your project."
+msgstr ""
+
msgid "README"
msgstr ""
+msgid "Rails"
+msgstr ""
+
msgid "Rake Tasks Help"
msgstr ""
@@ -20483,10 +21181,13 @@ msgstr ""
msgid "Register Two-Factor Authenticator"
msgstr ""
-msgid "Register U2F device"
+msgid "Register Universal Two-Factor (U2F) Device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register WebAuthn Device"
+msgstr ""
+
+msgid "Register device"
msgstr ""
msgid "Register for GitLab"
@@ -20498,9 +21199,6 @@ msgstr ""
msgid "Register with two-factor app"
msgstr ""
-msgid "Registration"
-msgstr ""
-
msgid "Registration|Checkout"
msgstr ""
@@ -20617,9 +21315,6 @@ msgstr ""
msgid "Release|Something went wrong while saving the release details"
msgstr ""
-msgid "Remediated: needs review"
-msgstr ""
-
msgid "Remediations"
msgstr ""
@@ -20725,6 +21420,9 @@ msgstr ""
msgid "Remove priority"
msgstr ""
+msgid "Remove report"
+msgstr ""
+
msgid "Remove secondary node"
msgstr ""
@@ -20737,6 +21435,12 @@ msgstr ""
msgid "Remove time estimate"
msgstr ""
+msgid "Remove user & report"
+msgstr ""
+
+msgid "Remove user from group"
+msgstr ""
+
msgid "Removed"
msgstr ""
@@ -20818,9 +21522,6 @@ msgstr ""
msgid "Removes time estimate."
msgstr ""
-msgid "Removing license…"
-msgstr ""
-
msgid "Removing this group also removes all child projects, including archived projects, and their resources."
msgstr ""
@@ -20905,6 +21606,9 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
+msgid "Reported by %{reporter}"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -20991,6 +21695,27 @@ msgstr ""
msgid "Repositories"
msgstr ""
+msgid "Repositories Analytics"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download Historic Test Coverage Data"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download historic test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Historic Test Coverage Data is available in raw format (.csv) for further analysis."
+msgstr ""
+
+msgid "RepositoriesAnalytics|Test Code Coverage"
+msgstr ""
+
+msgid "RepositoriesAnalytics|There was an error fetching the projects."
+msgstr ""
+
msgid "Repository"
msgstr ""
@@ -21069,9 +21794,15 @@ msgstr ""
msgid "Request parameter %{param} is missing."
msgstr ""
+msgid "Request review from"
+msgstr ""
+
msgid "Request to link SAML account must be authorized"
msgstr ""
+msgid "Requested"
+msgstr ""
+
msgid "Requested %{time_ago}"
msgstr ""
@@ -21090,6 +21821,9 @@ msgstr ""
msgid "Requests to these domain(s)/address(es) on the local network will be allowed when local requests from hooks and services are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 or 127.0.0.0/28 are supported. Domain wildcards are not supported currently. Use comma, semicolon, or newline to separate multiple entries. The allowlist can hold a maximum of 1000 entries. Domains should use IDNA encoding. Ex: example.com, 192.168.1.1, 127.0.0.0/28, xn--itlab-j1a.com."
msgstr ""
+msgid "Require admin approval for new sign-ups"
+msgstr ""
+
msgid "Require all users in this group to setup Two-factor authentication"
msgstr ""
@@ -21217,9 +21951,6 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
-msgid "Resolved by %{resolvedByName}"
-msgstr ""
-
msgid "Resolves IP addresses once and uses them to submit requests"
msgstr ""
@@ -21339,6 +22070,14 @@ msgstr ""
msgid "ReviewApp|Enable Review App"
msgstr ""
+msgid "Reviewer"
+msgid_plural "%d Reviewers"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Reviewer(s)"
+msgstr ""
+
msgid "Reviewing"
msgstr ""
@@ -21378,6 +22117,9 @@ msgstr ""
msgid "Rook"
msgstr ""
+msgid "Ruby"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -21456,6 +22198,63 @@ msgstr ""
msgid "Runners page."
msgstr ""
+msgid "Runners|Active"
+msgstr ""
+
+msgid "Runners|Architecture"
+msgstr ""
+
+msgid "Runners|Can run untagged jobs"
+msgstr ""
+
+msgid "Runners|Description"
+msgstr ""
+
+msgid "Runners|Group"
+msgstr ""
+
+msgid "Runners|IP Address"
+msgstr ""
+
+msgid "Runners|Last contact"
+msgstr ""
+
+msgid "Runners|Locked to this project"
+msgstr ""
+
+msgid "Runners|Maximum job timeout"
+msgstr ""
+
+msgid "Runners|Name"
+msgstr ""
+
+msgid "Runners|Platform"
+msgstr ""
+
+msgid "Runners|Property Name"
+msgstr ""
+
+msgid "Runners|Protected"
+msgstr ""
+
+msgid "Runners|Revision"
+msgstr ""
+
+msgid "Runners|Shared"
+msgstr ""
+
+msgid "Runners|Specific"
+msgstr ""
+
+msgid "Runners|Tags"
+msgstr ""
+
+msgid "Runners|Value"
+msgstr ""
+
+msgid "Runners|Version"
+msgstr ""
+
msgid "Runners|You have used %{quotaUsed} out of %{quotaLimit} of your shared Runners pipeline minutes."
msgstr ""
@@ -21468,6 +22267,9 @@ msgstr ""
msgid "Runs a number of housekeeping tasks within the current repository, such as compressing file revisions and removing unreachable objects."
msgstr ""
+msgid "SAML"
+msgstr ""
+
msgid "SAML SSO"
msgstr ""
@@ -21519,6 +22321,9 @@ msgstr ""
msgid "Save"
msgstr ""
+msgid "Save %{name} size limits"
+msgstr ""
+
msgid "Save Changes"
msgstr ""
@@ -21549,9 +22354,6 @@ msgstr ""
msgid "Save space and find tags in the Container Registry more easily. Enable the cleanup policy to remove stale tags and keep only the ones you need."
msgstr ""
-msgid "Save template"
-msgstr ""
-
msgid "Save variables"
msgstr ""
@@ -21594,9 +22396,6 @@ msgstr ""
msgid "Scope"
msgstr ""
-msgid "Scope not supported with disabled 'users_search' feature!"
-msgstr ""
-
msgid "Scoped issue boards"
msgstr ""
@@ -21723,9 +22522,6 @@ msgstr ""
msgid "Search requirements"
msgstr ""
-msgid "Search results…"
-msgstr ""
-
msgid "Search users"
msgstr ""
@@ -21798,6 +22594,11 @@ msgid_plural "SearchResults|commits"
msgstr[0] ""
msgstr[1] ""
+msgid "SearchResults|epic"
+msgid_plural "SearchResults|epics"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "SearchResults|issue"
msgid_plural "SearchResults|issues"
msgstr[0] ""
@@ -21842,10 +22643,10 @@ msgstr ""
msgid "Seat Link is disabled, and cannot be configured through this form."
msgstr ""
-msgid "Seats currently in use"
+msgid "Seats usage data as of %{last_enqueue_time}"
msgstr ""
-msgid "Seats in license"
+msgid "Seats usage data is updated every day at 12:00pm UTC"
msgstr ""
msgid "Secondary"
@@ -21899,6 +22700,9 @@ msgstr ""
msgid "SecurityConfiguration|Available for on-demand DAST"
msgstr ""
+msgid "SecurityConfiguration|By default, all analyzers are applied in order to cover all languages across your project, and only run if the language is detected in the Merge Request."
+msgstr ""
+
msgid "SecurityConfiguration|Configure"
msgstr ""
@@ -21929,16 +22733,19 @@ msgstr ""
msgid "SecurityConfiguration|Manage"
msgstr ""
+msgid "SecurityConfiguration|More information"
+msgstr ""
+
msgid "SecurityConfiguration|Not enabled"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|Security Control"
+msgid "SecurityConfiguration|SAST Configuration"
msgstr ""
-msgid "SecurityConfiguration|See documentation"
+msgid "SecurityConfiguration|Security Control"
msgstr ""
msgid "SecurityConfiguration|Status"
@@ -21950,6 +22757,9 @@ msgstr ""
msgid "SecurityConfiguration|Using custom settings. You won't receive automatic updates on this variable. %{anchorStart}Restore to default%{anchorEnd}"
msgstr ""
+msgid "SecurityConfiguration|View history"
+msgstr ""
+
msgid "SecurityConfiguration|You can quickly enable all security scanning tools by enabling %{linkStart}Auto DevOps%{linkEnd}."
msgstr ""
@@ -22028,9 +22838,6 @@ msgstr ""
msgid "SecurityReports|Learn more about setting up your dashboard"
msgstr ""
-msgid "SecurityReports|Load more vulnerabilities"
-msgstr ""
-
msgid "SecurityReports|Monitor vulnerabilities in your code"
msgstr ""
@@ -22310,7 +23117,7 @@ msgstr ""
msgid "Select status"
msgstr ""
-msgid "Select strategy activation method"
+msgid "Select strategy activation method."
msgstr ""
msgid "Select subscription"
@@ -22325,7 +23132,7 @@ msgstr ""
msgid "Select the custom project template source group."
msgstr ""
-msgid "Select timeframe"
+msgid "Select the environment scope for this feature flag."
msgstr ""
msgid "Select timezone"
@@ -22574,6 +23381,9 @@ msgstr ""
msgid "Set iteration"
msgstr ""
+msgid "Set limit to 0 to allow any file size."
+msgstr ""
+
msgid "Set max session time for web terminal."
msgstr ""
@@ -22652,10 +23462,13 @@ msgstr ""
msgid "Set up a %{type} Runner manually"
msgstr ""
+msgid "Set up a hardware device as a second factor to sign in."
+msgstr ""
+
msgid "Set up assertions/attributes/claims (email, first_name, last_name) and NameID according to %{docsLinkStart}the documentation %{icon}%{docsLinkEnd}"
msgstr ""
-msgid "Set up new U2F device"
+msgid "Set up new device"
msgstr ""
msgid "Set up new password"
@@ -22724,6 +23537,9 @@ msgstr ""
msgid "Sets weight to %{weight}."
msgstr ""
+msgid "Setting this to 0 means using the system default timeout value."
+msgstr ""
+
msgid "Settings"
msgstr ""
@@ -22739,6 +23555,15 @@ msgstr ""
msgid "Severity"
msgstr ""
+msgid "SeverityWidget|Severity"
+msgstr ""
+
+msgid "SeverityWidget|Severity: %{severity}"
+msgstr ""
+
+msgid "SeverityWidget|There was an error while updating severity."
+msgstr ""
+
msgid "Shards (%{shards})"
msgstr ""
@@ -22784,6 +23609,9 @@ msgstr ""
msgid "Show all requirements."
msgstr ""
+msgid "Show all test cases."
+msgstr ""
+
msgid "Show archived projects"
msgstr ""
@@ -22796,6 +23624,9 @@ msgstr ""
msgid "Show comments"
msgstr ""
+msgid "Show comments on this file"
+msgstr ""
+
msgid "Show comments only"
msgstr ""
@@ -22841,6 +23672,12 @@ msgstr ""
msgid "Show parent subgroups"
msgstr ""
+msgid "Show the Closed list"
+msgstr ""
+
+msgid "Show the Open list"
+msgstr ""
+
msgid "Show whitespace changes"
msgstr ""
@@ -22884,9 +23721,6 @@ msgstr ""
msgid "Sidebar|Assign health status"
msgstr ""
-msgid "Sidebar|Change weight"
-msgstr ""
-
msgid "Sidebar|Health status"
msgstr ""
@@ -23070,6 +23904,9 @@ msgstr ""
msgid "Snippets|Add another file %{num}/%{total}"
msgstr ""
+msgid "Snippets|Authored %{time_ago} by %{author}"
+msgstr ""
+
msgid "Snippets|Delete file"
msgstr ""
@@ -23097,6 +23934,9 @@ msgstr ""
msgid "Solution"
msgstr ""
+msgid "Some changes are not shown"
+msgstr ""
+
msgid "Some child epics may be hidden due to applied filters"
msgstr ""
@@ -23463,6 +24303,12 @@ msgstr ""
msgid "Source (branch or tag)"
msgstr ""
+msgid "Source Branch"
+msgstr ""
+
+msgid "Source branch: %{source_branch_open}%{source_branch}%{source_branch_close}"
+msgstr ""
+
msgid "Source code"
msgstr ""
@@ -23628,9 +24474,6 @@ msgstr ""
msgid "Start and due date"
msgstr ""
-msgid "Start by choosing a group to see how your team is spending time. You can then drill down to the project level."
-msgstr ""
-
msgid "Start by choosing a group to start exploring the merge requests in that group. You can then proceed to filter by projects, labels, milestones and authors."
msgstr ""
@@ -23712,18 +24555,27 @@ msgstr ""
msgid "StaticSiteEditor|3. Assign a person to review and accept the merge request."
msgstr ""
+msgid "StaticSiteEditor|A link to view the merge request will appear once ready."
+msgstr ""
+
msgid "StaticSiteEditor|An error occurred while submitting your changes."
msgstr ""
msgid "StaticSiteEditor|Branch could not be created."
msgstr ""
+msgid "StaticSiteEditor|Copy update"
+msgstr ""
+
msgid "StaticSiteEditor|Could not commit the content changes."
msgstr ""
msgid "StaticSiteEditor|Could not create merge request."
msgstr ""
+msgid "StaticSiteEditor|Creating your merge request"
+msgstr ""
+
msgid "StaticSiteEditor|Incompatible file content"
msgstr ""
@@ -23745,6 +24597,9 @@ msgstr ""
msgid "StaticSiteEditor|View documentation"
msgstr ""
+msgid "StaticSiteEditor|You can set an assignee to get your changes reviewed and deployed once your merge request is created."
+msgstr ""
+
msgid "StaticSiteEditor|Your merge request has been created"
msgstr ""
@@ -23874,15 +24729,15 @@ msgstr ""
msgid "Submit %{humanized_resource_name}"
msgstr ""
-msgid "Submit Changes"
-msgstr ""
-
msgid "Submit a review"
msgstr ""
msgid "Submit as spam"
msgstr ""
+msgid "Submit changes"
+msgstr ""
+
msgid "Submit feedback"
msgstr ""
@@ -24036,6 +24891,9 @@ msgstr ""
msgid "Successfully deleted U2F device."
msgstr ""
+msgid "Successfully deleted WebAuthn device."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -24354,9 +25212,6 @@ msgstr ""
msgid "Template to append to all Service Desk issues"
msgstr ""
-msgid "Template was successfully saved."
-msgstr ""
-
msgid "Templates"
msgstr ""
@@ -24435,10 +25290,28 @@ msgid_plural "Test coverage: %d hits"
msgstr[0] ""
msgstr[1] ""
-msgid "Test failed."
+msgid "Test settings"
msgstr ""
-msgid "Test settings and save changes"
+msgid "TestCases|New Test Case"
+msgstr ""
+
+msgid "TestCases|New test case"
+msgstr ""
+
+msgid "TestCases|Search test cases"
+msgstr ""
+
+msgid "TestCases|Something went wrong while creating a test case."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching count of test cases."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching test cases list."
+msgstr ""
+
+msgid "TestCases|Submit test case"
msgstr ""
msgid "TestHooks|Ensure one of your projects has merge requests."
@@ -24504,6 +25377,9 @@ msgstr ""
msgid "Thank you for signing up for your free trial! You will get additional instructions in your inbox shortly."
msgstr ""
+msgid "Thank you for your business."
+msgstr ""
+
msgid "Thank you for your feedback!"
msgstr ""
@@ -24563,9 +25439,6 @@ msgstr ""
msgid "The URL to use for connecting to Elasticsearch. Use a comma-separated list to support clustering (e.g., \"http://localhost:9200, http://localhost:9201\")."
msgstr ""
-msgid "The Web IDE offers advanced syntax highlighting capabilities and more."
-msgstr ""
-
msgid "The X509 Certificate to use when mutual TLS is required to communicate with the external authorization service. If left blank, the server certificate is still validated when accessing over HTTPS."
msgstr ""
@@ -24676,6 +25549,9 @@ msgstr ""
msgid "The form contains the following error:"
msgstr ""
+msgid "The form contains the following warning:"
+msgstr ""
+
msgid "The global settings require you to enable Two-Factor Authentication for your account."
msgstr ""
@@ -24790,9 +25666,6 @@ msgstr ""
msgid "The private key to use when a client certificate is provided. This value is encrypted at rest."
msgstr ""
-msgid "The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The project can be accessed by any logged in user."
msgstr ""
@@ -24829,7 +25702,7 @@ msgstr ""
msgid "The remote repository is being updated..."
msgstr ""
-msgid "The repository can be commited to, and issues, comments and other entities can be created."
+msgid "The repository can be committed to, and issues, comments and other entities can be created."
msgstr ""
msgid "The repository for this project does not exist."
@@ -24883,9 +25756,6 @@ msgstr ""
msgid "The time taken by each data entry gathered by that stage."
msgstr ""
-msgid "The total stage shows the time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The update action will time out after %{number_of_minutes} minutes. For big repositories, use a clone/push combination."
msgstr ""
@@ -24949,6 +25819,9 @@ msgstr ""
msgid "There are no archived requirements"
msgstr ""
+msgid "There are no archived test cases"
+msgstr ""
+
msgid "There are no changes"
msgstr ""
@@ -24988,6 +25861,9 @@ msgstr ""
msgid "There are no open requirements"
msgstr ""
+msgid "There are no open test cases"
+msgstr ""
+
msgid "There are no packages yet"
msgstr ""
@@ -25000,6 +25876,9 @@ msgstr ""
msgid "There is a limit of %{ci_project_subscriptions_limit} subscriptions from or to a project."
msgstr ""
+msgid "There is already a To-Do for this design."
+msgstr ""
+
msgid "There is already a repository with that name on disk"
msgstr ""
@@ -25018,6 +25897,9 @@ msgstr ""
msgid "There was a problem communicating with your device."
msgstr ""
+msgid "There was a problem fetching branches."
+msgstr ""
+
msgid "There was a problem fetching groups."
msgstr ""
@@ -25246,9 +26128,15 @@ msgstr ""
msgid "This action can lead to data loss. To prevent accidental actions we ask you to confirm your intention."
msgstr ""
+msgid "This action cannot be undone, and will permanently delete the %{key} SSH key"
+msgstr ""
+
msgid "This action cannot be undone. You will lose the project's repository and all content: issues, merge requests, etc."
msgstr ""
+msgid "This action has been performed too many times. Try again later."
+msgstr ""
+
msgid "This action will %{strongOpen}permanently delete%{strongClose} %{codeOpen}%{project}%{codeClose} %{strongOpen}immediately%{strongClose}, including its repositories and all content: issues, merge requests, etc."
msgstr ""
@@ -25276,9 +26164,6 @@ msgstr ""
msgid "This board's scope is reduced"
msgstr ""
-msgid "This branch has changed since you started editing. Would you like to create a new branch?"
-msgstr ""
-
msgid "This chart could not be displayed"
msgstr ""
@@ -25405,15 +26290,9 @@ msgstr ""
msgid "This is a security log of important events involving your account."
msgstr ""
-msgid "This is the author's first Merge Request to this project."
-msgstr ""
-
msgid "This is the highest peak of users on your installation since the license started."
msgstr ""
-msgid "This is the maximum number of users that have existed at the same time since the license started. This is the minimum number of seats you will need to buy when you renew your license."
-msgstr ""
-
msgid "This is the number of currently active users on your installation, and this is the minimum number you need to purchase when you renew your license."
msgstr ""
@@ -25645,6 +26524,15 @@ msgstr ""
msgid "This user has no identities"
msgstr ""
+msgid "This user has previously committed to the %{name} project."
+msgstr ""
+
+msgid "This user has the %{access} role in the %{name} project."
+msgstr ""
+
+msgid "This user is the author of this %{noteable}."
+msgstr ""
+
msgid "This user will be the author of all events in the activity feed that are the result of an update, like new branches being created or new commits being pushed to existing branches."
msgstr ""
@@ -25675,6 +26563,9 @@ msgstr ""
msgid "Threat Monitoring"
msgstr ""
+msgid "ThreatMonitoring|All Environments"
+msgstr ""
+
msgid "ThreatMonitoring|Anomalous Requests"
msgstr ""
@@ -25702,9 +26593,6 @@ msgstr ""
msgid "ThreatMonitoring|Operations Per Second"
msgstr ""
-msgid "ThreatMonitoring|Overview"
-msgstr ""
-
msgid "ThreatMonitoring|Packet Activity"
msgstr ""
@@ -25723,6 +26611,9 @@ msgstr ""
msgid "ThreatMonitoring|Something went wrong, unable to fetch statistics"
msgstr ""
+msgid "ThreatMonitoring|Statistics"
+msgstr ""
+
msgid "ThreatMonitoring|The firewall is not installed or has been disabled. To view this data, ensure the web application firewall is installed and enabled for your cluster."
msgstr ""
@@ -26114,6 +27005,9 @@ msgstr ""
msgid "To update Snippets with multiple files, you must use the `files` parameter"
msgstr ""
+msgid "To use Gitpod you must first enable the feature in the integrations section of your %{user_prefs}."
+msgstr ""
+
msgid "To view all %{scannedResourcesCount} scanned URLs, please download the CSV file"
msgstr ""
@@ -26147,9 +27041,6 @@ msgstr ""
msgid "Toggle Sidebar"
msgstr ""
-msgid "Toggle all threads"
-msgstr ""
-
msgid "Toggle backtrace"
msgstr ""
@@ -26174,9 +27065,6 @@ msgstr ""
msgid "Toggle navigation"
msgstr ""
-msgid "Toggle project"
-msgstr ""
-
msgid "Toggle sidebar"
msgstr ""
@@ -26216,6 +27104,9 @@ msgstr ""
msgid "Too many projects enabled. You will need to manage them via the console or the API."
msgstr ""
+msgid "Too much data"
+msgstr ""
+
msgid "Topics (optional)"
msgstr ""
@@ -26234,6 +27125,9 @@ msgstr ""
msgid "Total cores (CPUs)"
msgstr ""
+msgid "Total days to completion"
+msgstr ""
+
msgid "Total issues"
msgstr ""
@@ -26330,6 +27224,9 @@ msgstr ""
msgid "Trending"
msgstr ""
+msgid "Trials|Create a new group to start your GitLab Gold trial."
+msgstr ""
+
msgid "Trials|Go back to GitLab"
msgstr ""
@@ -26339,6 +27236,15 @@ msgstr ""
msgid "Trials|You can always resume this process by selecting your avatar and choosing 'Start a Gold trial'"
msgstr ""
+msgid "Trials|You can apply your trial to a new group or an existing group."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group or your personal account."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group, an existing group, or your personal account."
+msgstr ""
+
msgid "Trials|You won't get a free trial right now but you can always resume this process by clicking on your avatar and choosing 'Start a free trial'"
msgstr ""
@@ -26408,6 +27314,9 @@ msgstr ""
msgid "Try using a different search term to find the file you are looking for."
msgstr ""
+msgid "Trying to communicate with your device. Plug it in (if needed) and press the button on the device now."
+msgstr ""
+
msgid "Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now."
msgstr ""
@@ -26495,6 +27404,12 @@ msgstr ""
msgid "URL or request ID"
msgstr ""
+msgid "USER %{user} WILL BE REMOVED! Are you sure?"
+msgstr ""
+
+msgid "USER WILL BE BLOCKED! Are you sure?"
+msgstr ""
+
msgid "UTC"
msgstr ""
@@ -26552,9 +27467,6 @@ msgstr ""
msgid "Unable to load the merge request widget. Try reloading the page."
msgstr ""
-msgid "Unable to resolve"
-msgstr ""
-
msgid "Unable to save iteration. Please try again"
msgstr ""
@@ -26603,6 +27515,9 @@ msgstr ""
msgid "Undo ignore"
msgstr ""
+msgid "Unexpected error"
+msgstr ""
+
msgid "Unfortunately, your email message to GitLab could not be processed."
msgstr ""
@@ -26636,6 +27551,9 @@ msgstr ""
msgid "Unknown response text"
msgstr ""
+msgid "Unless otherwise agreed to in writing with GitLab, by clicking \"Upload License\" you agree that your use of GitLab Software is subject to the %{eula_link_start}Terms of Service%{eula_link_end}."
+msgstr ""
+
msgid "Unlimited"
msgstr ""
@@ -27002,9 +27920,6 @@ msgstr ""
msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
msgstr ""
-msgid "Use a hardware device to add the second factor of authentication."
-msgstr ""
-
msgid "Use an one time password authenticator on your mobile device or computer to enable two-factor authentication (2FA)."
msgstr ""
@@ -27278,13 +28193,13 @@ msgstr ""
msgid "Users"
msgstr ""
-msgid "Users in License:"
+msgid "Users in License"
msgstr ""
-msgid "Users or groups set as approvers in the project's or merge request's settings."
+msgid "Users in License:"
msgstr ""
-msgid "Users outside of license"
+msgid "Users or groups set as approvers in the project's or merge request's settings."
msgstr ""
msgid "Users over License:"
@@ -27302,9 +28217,6 @@ msgstr ""
msgid "Users with a Guest role or those who don't belong to a Project or Group will not use a seat from your license."
msgstr ""
-msgid "Users with a Guest role or those who don't belong to any projects or groups don't count towards seats in use."
-msgstr ""
-
msgid "UsersSelect|%{name} + %{length} more"
msgstr ""
@@ -27344,9 +28256,6 @@ msgstr ""
msgid "Validations failed."
msgstr ""
-msgid "Validity"
-msgstr ""
-
msgid "Value"
msgstr ""
@@ -27365,6 +28274,9 @@ msgstr ""
msgid "Value Stream Name"
msgstr ""
+msgid "ValueStreamAnalyticsStage|We don't have enough data to show this stage."
+msgstr ""
+
msgid "ValueStreamAnalytics|%{days}d"
msgstr ""
@@ -27621,6 +28533,9 @@ msgstr ""
msgid "VisualReviewApp|Steps 1 and 2 (and sometimes 3) are performed once by the developer before requesting feedback. Steps 3 (if necessary), 4 is performed by the reviewer each time they perform a review."
msgstr ""
+msgid "Visualization"
+msgstr ""
+
msgid "Vulnerabilities"
msgstr ""
@@ -27648,34 +28563,31 @@ msgstr ""
msgid "VulnerabilityChart|Severity"
msgstr ""
-msgid "VulnerabilityManagement|A true-positive and will fix"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Change status"
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|Confirm"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Confirmed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
-msgstr ""
-
-msgid "VulnerabilityManagement|Detected %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|A true-positive and will fix"
msgstr ""
-msgid "VulnerabilityManagement|Dismiss"
+msgid "VulnerabilityManagement|Change status"
msgstr ""
-msgid "VulnerabilityManagement|Dismissed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
msgstr ""
-msgid "VulnerabilityManagement|Resolved"
+msgid "VulnerabilityManagement|Detected"
msgstr ""
-msgid "VulnerabilityManagement|Resolved %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Needs triage"
msgstr ""
msgid "VulnerabilityManagement|Something went wrong while trying to delete the comment. Please try again later."
@@ -27726,6 +28638,9 @@ msgstr ""
msgid "Vulnerability|%{scannerName} (version %{scannerVersion})"
msgstr ""
+msgid "Vulnerability|Activity"
+msgstr ""
+
msgid "Vulnerability|Class"
msgstr ""
@@ -27738,6 +28653,9 @@ msgstr ""
msgid "Vulnerability|Description"
msgstr ""
+msgid "Vulnerability|Detected"
+msgstr ""
+
msgid "Vulnerability|Evidence"
msgstr ""
@@ -27801,6 +28719,9 @@ msgstr ""
msgid "Warning: Displaying this diagram might cause performance issues on this page."
msgstr ""
+msgid "We are currently unable to fetch data for the pipeline header."
+msgstr ""
+
msgid "We are currently unable to fetch data for this graph."
msgstr ""
@@ -27840,6 +28761,12 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
+msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
+msgstr ""
+
+msgid "We would like to inform you that your subscription GitLab Enterprise Edition %{plan_name} is nearing its user limit. You have %{active_user_count} active users, which is almost at the user limit of %{maximum_user_count}."
+msgstr ""
+
msgid "We've found no vulnerabilities"
msgstr ""
@@ -27855,6 +28782,12 @@ msgstr ""
msgid "Web terminal"
msgstr ""
+msgid "WebAuthn Devices (%{length})"
+msgstr ""
+
+msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
+msgstr ""
+
msgid "WebIDE|Merge request"
msgstr ""
@@ -27993,15 +28926,9 @@ msgstr ""
msgid "Welcome to the guided GitLab tour"
msgstr ""
-msgid "Welcome to your Issue Board!"
-msgstr ""
-
msgid "Welcome to your issue board!"
msgstr ""
-msgid "We’ve been making changes to %{featureName} and we’d love your feedback %{linkStart}in this issue%{linkEnd} to help us improve the experience."
-msgstr ""
-
msgid "What are you searching for?"
msgstr ""
@@ -28020,6 +28947,9 @@ msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
msgstr ""
+msgid "When enabled, any user visiting %{host} and creating an account will have to be explicitly approved by the admin before they can login. This setting is effective only if sign-ups are enabled."
+msgstr ""
+
msgid "When enabled, any user visiting %{host} will be able to create an account."
msgstr ""
@@ -28244,6 +29174,9 @@ msgstr ""
msgid "With requirements, you can set criteria to check your products against."
msgstr ""
+msgid "With test cases, you can define conditions for your project to meet in determining quality"
+msgstr ""
+
msgid "Withdraw Access Request"
msgstr ""
@@ -28259,6 +29192,9 @@ msgstr ""
msgid "Workflow Help"
msgstr ""
+msgid "Would you like to create a new branch?"
+msgstr ""
+
msgid "Write"
msgstr ""
@@ -28280,6 +29216,9 @@ msgstr ""
msgid "Wrong extern UID provided. Make sure Auth0 is configured correctly."
msgstr ""
+msgid "YYYY-MM-DD"
+msgstr ""
+
msgid "Yes"
msgstr ""
@@ -28337,7 +29276,7 @@ msgstr ""
msgid "You are going to remove the fork relationship from %{project_full_name}. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "You are going to transfer %{project_full_name} to another owner. Are you ABSOLUTELY sure?"
+msgid "You are going to transfer %{project_full_name} to another namespace. Are you ABSOLUTELY sure?"
msgstr ""
msgid "You are going to turn off the confidentiality. This means %{strongStart}everyone%{strongEnd} will be able to see and leave a comment on this %{issuableType}."
@@ -28397,9 +29336,6 @@ msgstr ""
msgid "You can always edit this later"
msgstr ""
-msgid "You can apply your Trial to your Personal account or create a New Group."
-msgstr ""
-
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings"
msgstr ""
@@ -28421,12 +29357,18 @@ msgstr ""
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
+msgid "You can find more information about GitLab subscriptions in %{subscriptions_doc_link}."
+msgstr ""
+
msgid "You can generate an access token scoped to this project for each application to use the GitLab API."
msgstr ""
msgid "You can get started by cloning the repository or start adding files to it with one of the following options."
msgstr ""
+msgid "You can group test cases using labels. To learn about the future direction of this feature, visit %{linkStart}Quality Management direction page%{linkEnd}."
+msgstr ""
+
msgid "You can invite a new member to %{project_name} or invite another group."
msgstr ""
@@ -28442,6 +29384,9 @@ msgstr ""
msgid "You can notify the app / group or a project by sending them an email notification"
msgstr ""
+msgid "You can now close this window."
+msgstr ""
+
msgid "You can now export your security dashboard to a CSV report."
msgstr ""
@@ -28490,9 +29435,6 @@ msgstr ""
msgid "You can test your .gitlab-ci.yml in %{linkStart}CI Lint%{linkEnd}."
msgstr ""
-msgid "You can try again using %{begin_link}basic search%{end_link}"
-msgstr ""
-
msgid "You cannot access the raw file. Please wait a minute."
msgstr ""
@@ -28544,6 +29486,9 @@ msgstr ""
msgid "You don't have any U2F devices registered yet."
msgstr ""
+msgid "You don't have any WebAuthn devices registered yet."
+msgstr ""
+
msgid "You don't have any active chat names."
msgstr ""
@@ -28631,6 +29576,9 @@ msgstr ""
msgid "You must accept our Terms of Service and privacy policy in order to register an account"
msgstr ""
+msgid "You must be logged in to search across all of GitLab"
+msgstr ""
+
msgid "You must disassociate %{domain} from all clusters it is attached to before deletion."
msgstr ""
@@ -28670,7 +29618,7 @@ msgstr ""
msgid "You need to be logged in."
msgstr ""
-msgid "You need to register a two-factor authentication app before you can set up a U2F device."
+msgid "You need to register a two-factor authentication app before you can set up a device."
msgstr ""
msgid "You need to set terms to be enforced"
@@ -28688,6 +29636,9 @@ msgstr ""
msgid "You reached %{usage_in_percent} of %{namespace_name}'s storage capacity (%{used_storage} of %{storage_limit})"
msgstr ""
+msgid "You successfully declined the invitation"
+msgstr ""
+
msgid "You tried to fork %{link_to_the_project} but it failed for the following reason:"
msgstr ""
@@ -28853,10 +29804,13 @@ msgstr ""
msgid "Your U2F device did not send a valid JSON response."
msgstr ""
-msgid "Your U2F device needs to be set up. Plug it in (if not already) and click the button on the left."
+msgid "Your U2F device was registered!"
msgstr ""
-msgid "Your U2F device was registered!"
+msgid "Your WebAuthn device did not send a valid JSON response."
+msgstr ""
+
+msgid "Your WebAuthn device was registered!"
msgstr ""
msgid "Your access request to the %{source_type} has been withdrawn."
@@ -28880,6 +29834,9 @@ msgstr ""
msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
msgstr ""
+msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
+msgstr ""
+
msgid "Your changes can be committed to %{branch_name} because a merge request is open."
msgstr ""
@@ -28916,6 +29873,12 @@ msgstr ""
msgid "Your deployment services will be broken, you will need to manually fix the services after renaming."
msgstr ""
+msgid "Your device is not compatible with GitLab. Please try another device"
+msgstr ""
+
+msgid "Your device needs to be set up. Plug it in (if needed) and click the button on the left."
+msgstr ""
+
msgid "Your device was successfully set up! Give it a name and register it with the GitLab server."
msgstr ""
@@ -29029,9 +29992,6 @@ msgstr[1] ""
msgid "access:"
msgstr ""
-msgid "activated"
-msgstr ""
-
msgid "added %{created_at_timeago}"
msgstr ""
@@ -29104,9 +30064,21 @@ msgstr ""
msgid "by %{user}"
msgstr ""
+msgid "cannot be a date in the past"
+msgstr ""
+
msgid "cannot be changed if a personal project has container registry tags."
msgstr ""
+msgid "cannot be changed if shared runners are enabled"
+msgstr ""
+
+msgid "cannot be enabled because parent group does not allow it"
+msgstr ""
+
+msgid "cannot be enabled because parent group has shared Runners disabled"
+msgstr ""
+
msgid "cannot be enabled unless all domains have TLS certificates"
msgstr ""
@@ -29152,7 +30124,7 @@ msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about SAST %{linkEndTag}"
msgstr ""
-msgid "ciReport|%{linkStartTag}Learn more about Secret Scanning %{linkEndTag}"
+msgid "ciReport|%{linkStartTag}Learn more about Secret Detection %{linkEndTag}"
msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about codequality reports %{linkEndTag}"
@@ -29467,9 +30439,6 @@ msgstr ""
msgid "error"
msgstr ""
-msgid "error code:"
-msgstr ""
-
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr ""
@@ -29491,6 +30460,9 @@ msgstr ""
msgid "failed to dismiss associated finding(id=%{finding_id}): %{message}"
msgstr ""
+msgid "failed to revert associated finding(id=%{finding_id}) to detected"
+msgstr ""
+
msgid "file"
msgid_plural "files"
msgstr[0] ""
@@ -30033,6 +31005,9 @@ msgstr ""
msgid "must be a root namespace"
msgstr ""
+msgid "must be a valid IPv4 or IPv6 address"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -30069,6 +31044,9 @@ msgstr ""
msgid "no expiration"
msgstr ""
+msgid "no name set"
+msgstr ""
+
msgid "no one can merge"
msgstr ""
@@ -30247,9 +31225,6 @@ msgstr ""
msgid "security Reports|There was an error creating the merge request"
msgstr ""
-msgid "settings saved, but not activated"
-msgstr ""
-
msgid "severity|Critical"
msgstr ""
@@ -30376,9 +31351,6 @@ msgstr ""
msgid "toggle collapse"
msgstr ""
-msgid "toggle dropdown"
-msgstr ""
-
msgid "triggered"
msgstr ""
@@ -30406,6 +31378,9 @@ msgstr ""
msgid "user avatar"
msgstr ""
+msgid "user preferences"
+msgstr ""
+
msgid "username"
msgstr ""
diff --git a/locale/fr/gitlab.po b/locale/fr/gitlab.po
index 5ce2bc4a322..4bb8cfa9a60 100644
--- a/locale/fr/gitlab.po
+++ b/locale/fr/gitlab.po
@@ -14,7 +14,10 @@ msgstr ""
"X-Crowdin-Language: fr\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 6\n"
-"PO-Revision-Date: 2020-09-04 23:06\n"
+"PO-Revision-Date: 2020-10-02 18:45\n"
+
+msgid " %{project_name}#%{issue_iid} &middot; opened %{issue_created} by %{author}"
+msgstr ""
msgid " %{start} to %{end}"
msgstr " %{start} à %{end}"
@@ -74,6 +77,16 @@ msgstr "\"%{path}\" n'existait pas sur \"%{ref}\""
msgid "\"el\" parameter is required for createInstance()"
msgstr ""
+msgid "%d Approval"
+msgid_plural "%d Approvals"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d Package"
+msgid_plural "%d Packages"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d Scanned URL"
msgid_plural "%d Scanned URLs"
msgstr[0] ""
@@ -137,6 +150,11 @@ msgstr[1] "%d commits,"
msgid "%d commits"
msgstr "%d commits"
+msgid "%d completed issue"
+msgid_plural "%d completed issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d contribution"
msgid_plural "%d contributions"
msgstr[0] "%d contribution"
@@ -147,6 +165,11 @@ msgid_plural "%d days"
msgstr[0] ""
msgstr[1] ""
+msgid "%d day until tags are automatically removed"
+msgid_plural "%d days until tags are automatically removed"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d error"
msgid_plural "%d errors"
msgstr[0] ""
@@ -237,6 +260,16 @@ msgid_plural "%d more comments"
msgstr[0] ""
msgstr[1] ""
+msgid "%d open issue"
+msgid_plural "%d open issues"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d pending comment"
+msgid_plural "%d pending comments"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d personal project will be removed and cannot be restored."
msgid_plural "%d personal projects will be removed and cannot be restored."
msgstr[0] ""
@@ -252,6 +285,11 @@ msgid_plural "%d projects"
msgstr[0] ""
msgstr[1] ""
+msgid "%d project selected"
+msgid_plural "%d projects selected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d request with warnings"
msgid_plural "%d requests with warnings"
msgstr[0] ""
@@ -272,6 +310,11 @@ msgid_plural "%d tags"
msgstr[0] ""
msgstr[1] ""
+msgid "%d tag per image name"
+msgid_plural "%d tags per image name"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d unassigned issue"
msgid_plural "%d unassigned issues"
msgstr[0] ""
@@ -292,6 +335,11 @@ msgid_plural "%d vulnerabilities dismissed"
msgstr[0] ""
msgstr[1] ""
+msgid "%d warning found:"
+msgid_plural "%d warnings found:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%s additional commit has been omitted to prevent performance issues."
msgid_plural "%s additional commits have been omitted to prevent performance issues."
msgstr[0] "%s commit supplémentaire a été ignoré afin d’éviter de causer des problèmes de performance."
@@ -330,6 +378,9 @@ msgstr ""
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr "%{commit_author_link} a créé %{commit_timeago}"
+msgid "%{completedCount} completed weight"
+msgstr ""
+
msgid "%{completedWeight} of %{totalWeight} weight completed"
msgstr ""
@@ -378,14 +429,12 @@ msgid_plural "%{count} participants"
msgstr[0] "%{count} participant·e"
msgstr[1] "%{count} participant·e·s"
-msgid "%{count} pending comment"
-msgid_plural "%{count} pending comments"
-msgstr[0] "%{count} commentaire en attente"
-msgstr[1] "%{count} commentaires en attente"
-
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
+msgid "%{count} total weight"
+msgstr ""
+
msgid "%{dashboard_path} could not be found."
msgstr ""
@@ -440,6 +489,9 @@ msgstr ""
msgid "%{group_name} uses group managed accounts. You need to create a new GitLab account which will be managed by %{group_name}."
msgstr ""
+msgid "%{group_name}&%{epic_iid} &middot; opened %{epic_created} by %{author}"
+msgstr ""
+
msgid "%{host} sign-in from new location"
msgstr ""
@@ -452,7 +504,7 @@ msgstr ""
msgid "%{issuableType} will be removed! Are you sure?"
msgstr "%{issuableType} sera supprimé ! Êtesâ€vous sûr ?"
-msgid "%{issuesSize} issues with a limit of %{maxIssueCount}"
+msgid "%{issuesCount} issues with a limit of %{maxIssueCount}"
msgstr ""
msgid "%{issuesSize} with a limit of %{maxIssueCount}"
@@ -485,7 +537,7 @@ msgstr ""
msgid "%{labelStart}Namespace:%{labelEnd} %{namespace}"
msgstr ""
-msgid "%{labelStart}Report Type:%{labelEnd} %{reportType}"
+msgid "%{labelStart}Scan Type:%{labelEnd} %{reportType}"
msgstr ""
msgid "%{labelStart}Scanner:%{labelEnd} %{scanner}"
@@ -682,9 +734,6 @@ msgid_plural "%{securityScanner} results are not available because a pipeline ha
msgstr[0] ""
msgstr[1] ""
-msgid "%{service_title} %{message}."
-msgstr ""
-
msgid "%{size} GiB"
msgstr ""
@@ -773,6 +822,12 @@ msgstr "%{text} est disponible"
msgid "%{timebox_name} should belong either to a project or a group."
msgstr ""
+msgid "%{timebox_type} does not support burnup charts"
+msgstr ""
+
+msgid "%{timebox_type} must have a start and due date"
+msgstr ""
+
msgid "%{title} %{operator} %{threshold}"
msgstr ""
@@ -797,7 +852,7 @@ msgstr ""
msgid "%{total} open issue weight"
msgstr ""
-msgid "%{total} open issues"
+msgid "%{total} warnings found: showing first %{warningsDisplayed}"
msgstr ""
msgid "%{usage_ping_link_start}Learn more%{usage_ping_link_end} about what information is shared with GitLab Inc."
@@ -830,9 +885,6 @@ msgstr ""
msgid "&lt; 1 hour"
msgstr ""
-msgid "&lt;no name set&gt;"
-msgstr ""
-
msgid "&lt;no scopes selected&gt;"
msgstr ""
@@ -863,6 +915,9 @@ msgstr ""
msgid "'%{name}' Value Stream created"
msgstr ""
+msgid "'%{name}' Value Stream deleted"
+msgstr ""
+
msgid "'%{name}' stage already exists"
msgstr ""
@@ -922,6 +977,9 @@ msgstr "+ %{moreCount} de plus"
msgid "+ %{numberOfHiddenAssignees} more"
msgstr ""
+msgid "+ %{numberOfHiddenReviewers} more"
+msgstr ""
+
msgid "+%d more"
msgid_plural "+%d more"
msgstr[0] ""
@@ -982,6 +1040,11 @@ msgid_plural "%d Days"
msgstr[0] "un jour"
msgstr[1] "%d jours"
+msgid "1 Issue"
+msgid_plural "%d Issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "1 closed issue"
msgid_plural "%{issues} closed issues"
msgstr[0] ""
@@ -997,6 +1060,11 @@ msgid_plural "%d days"
msgstr[0] ""
msgstr[1] ""
+msgid "1 deploy key"
+msgid_plural "%d deploy keys"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] "Un groupe"
@@ -1099,6 +1167,9 @@ msgstr ""
msgid ":%{startLine} to %{endLine}"
msgstr ""
+msgid "A %{incident_docs_start}modified issue%{incident_docs_end} to guide the resolution of incidents."
+msgstr ""
+
msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr "Un « exécuteur » est un processus qui exécute une tâche. Vous pouvez configurer autant d’exécuteurs que nécessaire."
@@ -1111,6 +1182,9 @@ msgstr ""
msgid "A GitBook site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr "Un site GitBook qui utilise Netlify comme intégration et livraison continues (CI/CD) au lieu de GitLab, mais en gardant toutes les autres fonctionnalités géniales de GitLab."
+msgid "A Gitpod configured Webapplication in Spring and Java"
+msgstr ""
+
msgid "A Hexo site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr "Un site Hexo qui utilise Netlify comme intégration et livraison continues (CI/CD) au lieu de GitLab, mais en gardant toutes les autres fonctionnalités géniales de GitLab."
@@ -1282,9 +1356,15 @@ msgstr "Accès refusé ! Veuillez vérifier que vous pouvez ajouter des clefs
msgid "Access expiration date"
msgstr "Date d’expiration de l’accès"
+msgid "Access expires"
+msgstr ""
+
msgid "Access forbidden. Check your access level."
msgstr ""
+msgid "Access granted"
+msgstr ""
+
msgid "Access requests"
msgstr ""
@@ -1294,6 +1374,9 @@ msgstr "Accès à « %{classification_label} » non autorisé"
msgid "Access to Pages websites are controlled based on the user's membership to a given project. By checking this box, users will be required to be logged in to have access to all Pages websites in your instance."
msgstr ""
+msgid "AccessDropdown|Deploy Keys"
+msgstr ""
+
msgid "AccessDropdown|Groups"
msgstr ""
@@ -1411,12 +1494,6 @@ msgstr ""
msgid "Active Sessions"
msgstr "Sessions actives"
-msgid "Active Users:"
-msgstr ""
-
-msgid "Active users"
-msgstr ""
-
msgid "Activity"
msgstr "Activité"
@@ -1584,9 +1661,6 @@ msgstr ""
msgid "Add label(s)"
msgstr ""
-msgid "Add license"
-msgstr "Ajouter une licence"
-
msgid "Add list"
msgstr ""
@@ -1663,7 +1737,7 @@ msgid "AddMember|No users specified."
msgstr ""
msgid "AddMember|Too many users specified (limit is %{user_limit})"
-msgstr ""
+msgstr "Trop d'utilisateurs spécifiés (la limite est %{user_limit})"
msgid "Added"
msgstr ""
@@ -1761,21 +1835,51 @@ msgstr ""
msgid "AdminArea|Bots"
msgstr ""
+msgid "AdminArea|Components"
+msgstr ""
+
msgid "AdminArea|Developer"
msgstr ""
+msgid "AdminArea|Features"
+msgstr ""
+
+msgid "AdminArea|Groups: %{number_of_groups}"
+msgstr ""
+
msgid "AdminArea|Guest"
msgstr ""
msgid "AdminArea|Included Free in license"
msgstr ""
+msgid "AdminArea|Latest groups"
+msgstr ""
+
+msgid "AdminArea|Latest projects"
+msgstr ""
+
+msgid "AdminArea|Latest users"
+msgstr ""
+
msgid "AdminArea|Maintainer"
msgstr ""
+msgid "AdminArea|New group"
+msgstr ""
+
+msgid "AdminArea|New project"
+msgstr ""
+
+msgid "AdminArea|New user"
+msgstr ""
+
msgid "AdminArea|Owner"
msgstr ""
+msgid "AdminArea|Projects: %{number_of_projects}"
+msgstr ""
+
msgid "AdminArea|Reporter"
msgstr ""
@@ -1803,14 +1907,17 @@ msgstr ""
msgid "AdminArea|Users without a Group and Project"
msgstr ""
+msgid "AdminArea|Users: %{number_of_users}"
+msgstr ""
+
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 en cours seront interrompues."
msgid "AdminDashboard|Error loading the statistics. Please try again"
-msgstr ""
+msgstr "Erreur lors du chargement des statistiques. Veuillez réessayer"
msgid "AdminNote|Note"
-msgstr ""
+msgstr "Note"
msgid "AdminProjects| You’re about to permanently delete the project %{projectName}, its repository, and all related resources including issues, merge requests, etc.. Once you confirm and press %{strong_start}Delete project%{strong_end}, it cannot be undone or recovered."
msgstr "Vous êtes sur le point de supprimer définitivement le projet %{projectName}, son dépôt et toutes les ressources qui lui sont liées, y compris les tickets, les demandes de fusion, etc. Après sa confirmation par un clic sur « %{strong_start}supprimer le projet%{strong_end} », l’action ne peut être annulée ni faire l’objet d’une restauration."
@@ -1821,9 +1928,6 @@ msgstr "Supprimer"
msgid "AdminProjects|Delete Project %{projectName}?"
msgstr "Supprimer le projet %{projectName} ?"
-msgid "AdminProjects|Delete project"
-msgstr "Supprimer le projet"
-
msgid "AdminSettings|Apply integration settings to all Projects"
msgstr ""
@@ -2061,21 +2165,30 @@ msgstr ""
msgid "AdminUsers|Without projects"
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 ""
msgid "AdminUsers|You cannot remove your own admin rights."
msgstr ""
+msgid "AdminUsers|You must transfer ownership or delete the groups owned by this user before you can delete their account"
+msgstr ""
+
msgid "Administration"
msgstr ""
msgid "Advanced"
msgstr ""
+msgid "Advanced Search"
+msgstr ""
+
+msgid "Advanced Search with Elasticsearch"
+msgstr ""
+
msgid "Advanced Settings"
msgstr ""
@@ -2153,6 +2266,9 @@ msgstr ""
msgid "AlertManagement|Edit"
msgstr ""
+msgid "AlertManagement|Environment"
+msgstr ""
+
msgid "AlertManagement|Events"
msgstr ""
@@ -2165,6 +2281,9 @@ msgstr ""
msgid "AlertManagement|Issue"
msgstr ""
+msgid "AlertManagement|Key"
+msgstr ""
+
msgid "AlertManagement|Low"
msgstr ""
@@ -2258,6 +2377,9 @@ msgstr ""
msgid "AlertManagement|Unknown"
msgstr ""
+msgid "AlertManagement|Value"
+msgstr ""
+
msgid "AlertManagement|View alerts in Opsgenie"
msgstr ""
@@ -2417,6 +2539,9 @@ msgstr ""
msgid "All projects"
msgstr ""
+msgid "All projects selected"
+msgstr ""
+
msgid "All security scans are enabled because %{linkStart}Auto DevOps%{linkEnd} is enabled on this project"
msgstr ""
@@ -2504,6 +2629,9 @@ msgstr "Vous permet d’ajouter et de gérer des grappes de serveurs Kubernetes.
msgid "Almost there"
msgstr ""
+msgid "Already blocked"
+msgstr ""
+
msgid "Also called \"Issuer\" or \"Relying party trust identifier\""
msgstr "Également appelé « émetteur » ou « identifiant du tiers de confiance »"
@@ -2558,6 +2686,9 @@ msgstr "Un champ utilisateur Gitlab vide ajoutera le nom complet de l’utilisat
msgid "An error has occurred"
msgstr "Une erreur est survenue"
+msgid "An error occured while making the changes: %{error}"
+msgstr ""
+
msgid "An error occurred adding a draft to the thread."
msgstr ""
@@ -2585,12 +2716,6 @@ msgstr "Une erreur s’est produite lors de la prévisualisation du blob"
msgid "An error occurred when toggling the notification subscription"
msgstr "Une erreur s’est produite lors de l’activation ou la désactivation de l’abonnement aux notifications"
-msgid "An error occurred when trying to resolve a comment. Please try again."
-msgstr ""
-
-msgid "An error occurred when trying to resolve a discussion. Please try again."
-msgstr ""
-
msgid "An error occurred when updating the issue weight"
msgstr "Une erreur est survenue lors de la mise à jour du poids du ticket"
@@ -2606,12 +2731,6 @@ msgstr ""
msgid "An error occurred while checking group path. Please refresh and try again."
msgstr ""
-msgid "An error occurred while committing your changes."
-msgstr ""
-
-msgid "An error occurred while creating the list. Please try again."
-msgstr ""
-
msgid "An error occurred while decoding the file."
msgstr ""
@@ -2684,25 +2803,19 @@ msgstr ""
msgid "An error occurred while fetching the Service Desk address."
msgstr ""
-msgid "An error occurred while fetching the board issues. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the board lists. Please reload the page."
msgstr ""
msgid "An error occurred while fetching the board lists. Please try again."
msgstr ""
-msgid "An error occurred while fetching the board swimlanes. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the builds."
msgstr ""
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."
-msgid "An error occurred while fetching the job trace."
+msgid "An error occurred while fetching the job logs."
msgstr ""
msgid "An error occurred while fetching the job."
@@ -2849,9 +2962,6 @@ msgstr "Une erreur est survenue lors de l’enregistrement du statut d’outrepa
msgid "An error occurred while saving assignees"
msgstr "Une erreur s’est produite lors de l’enregistrement des destinataires"
-msgid "An error occurred while saving the template. Please check if the template exists."
-msgstr ""
-
msgid "An error occurred while searching for milestones"
msgstr ""
@@ -2870,12 +2980,12 @@ msgstr "Une erreur est survenue lors du désabonnement aux notifications."
msgid "An error occurred while updating approvers"
msgstr ""
+msgid "An error occurred while updating labels."
+msgstr ""
+
msgid "An error occurred while updating the comment"
msgstr "Une erreur est survenue lors de la mise à jour du commentaire"
-msgid "An error occurred while updating the list. Please try again."
-msgstr ""
-
msgid "An error occurred while validating group path"
msgstr ""
@@ -2927,6 +3037,9 @@ msgstr ""
msgid "An unknown error occurred while loading this graph."
msgstr ""
+msgid "An unknown error occurred."
+msgstr ""
+
msgid "Analytics"
msgstr "Analyse"
@@ -2960,10 +3073,10 @@ msgstr "Vérification antiâ€pourriel"
msgid "Any"
msgstr "Tout"
-msgid "Any Author"
+msgid "Any %{header}"
msgstr ""
-msgid "Any Status"
+msgid "Any Author"
msgstr ""
msgid "Any branch"
@@ -3017,6 +3130,9 @@ msgstr "Application"
msgid "Application ID"
msgstr "Identifiant de l’application"
+msgid "Application limits saved successfully"
+msgstr ""
+
msgid "Application settings saved successfully"
msgstr ""
@@ -3226,6 +3342,9 @@ msgstr ""
msgid "Are you sure you want to close this blocked issue?"
msgstr ""
+msgid "Are you sure you want to delete \"%{name}\" Value Stream?"
+msgstr ""
+
msgid "Are you sure you want to delete %{name}?"
msgstr ""
@@ -3235,6 +3354,9 @@ msgstr ""
msgid "Are you sure you want to delete this %{typeOfComment}?"
msgstr ""
+msgid "Are you sure you want to delete this SSH key?"
+msgstr ""
+
msgid "Are you sure you want to delete this board?"
msgstr ""
@@ -3259,6 +3381,11 @@ msgstr ""
msgid "Are you sure you want to erase this build?"
msgstr "Êtesâ€vous sûr(e) de vouloir supprimer cette construction ?"
+msgid "Are you sure you want to import %d repository?"
+msgid_plural "Are you sure you want to import %d repositories?"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Are you sure you want to lose unsaved changes?"
msgstr "Êtesâ€vous vraiment prêt(e) à perdre les modifications non enregistrées ?"
@@ -3268,15 +3395,15 @@ msgstr ""
msgid "Are you sure you want to merge immediately?"
msgstr ""
-msgid "Are you sure you want to permanently delete this license?"
-msgstr ""
-
msgid "Are you sure you want to re-deploy this environment?"
msgstr ""
msgid "Are you sure you want to regenerate the public key? You will have to update the public key on the remote server before mirroring will work again."
msgstr "Êtesâ€vous sûr de vouloir générer une nouvelle paire de clefs ? Vous devrez copier la nouvelle clef publique sur le serveur distant pour que la mise en miroir refonctionne."
+msgid "Are you sure you want to reindex?"
+msgstr ""
+
msgid "Are you sure you want to remove %{group_name}?"
msgstr "Voulezâ€vous vraiment supprimer %{group_name} ?"
@@ -3304,6 +3431,9 @@ msgstr ""
msgid "Are you sure you want to revoke this nickname?"
msgstr ""
+msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
+msgstr ""
+
msgid "Are you sure you want to stop this environment?"
msgstr "Êtesâ€vous sûr(e) de vouloir arrêter cet environnement ?"
@@ -3325,6 +3455,9 @@ msgstr ""
msgid "Are you sure? The device will be signed out of GitLab and all remember me tokens revoked."
msgstr ""
+msgid "Are you sure? This will invalidate your registered applications and U2F / WebAuthn devices."
+msgstr ""
+
msgid "Are you sure? This will invalidate your registered applications and U2F devices."
msgstr ""
@@ -3343,9 +3476,6 @@ msgstr ""
msgid "Artifacts"
msgstr "Artéfacts"
-msgid "As U2F devices are only supported by a few browsers, we require that you set up a two-factor authentication app before a U2F device. That way you'll always be able to log in - even when you're using an unsupported browser."
-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 ""
@@ -3539,6 +3669,9 @@ msgstr ""
msgid "AuditLogs|Target"
msgstr ""
+msgid "AuditLogs|This month"
+msgstr ""
+
msgid "AuditLogs|User Events"
msgstr ""
@@ -3578,6 +3711,9 @@ msgstr ""
msgid "Authentication via U2F device failed."
msgstr ""
+msgid "Authentication via WebAuthn device failed."
+msgstr ""
+
msgid "Author"
msgstr "Auteur·e"
@@ -3845,15 +3981,6 @@ msgstr ""
msgid "BambooService|You must set up automatic revision labeling and a repository trigger in Bamboo."
msgstr ""
-msgid "BatchComments|Delete all pending comments"
-msgstr "Supprimer tous les commentaires en attente"
-
-msgid "BatchComments|Discard review?"
-msgstr "Abandonner la revue de code ?"
-
-msgid "BatchComments|You're about to discard your review which will delete all of your pending comments. The deleted comments %{strong_start}cannot%{strong_end} be restored."
-msgstr "Vous êtes sur le point d’abonner votre revue de code, ce qui entraînera la suppression de l’ensemble de vos commentaires en attente. Les commentaires supprimés %{strong_start}ne peuvent pas%{strong_end} être restaurés."
-
msgid "Be careful. Changing the project's namespace can have unintended side effects."
msgstr ""
@@ -3875,6 +4002,9 @@ msgstr "Vous trouverez ciâ€dessous tous les groupes publics."
msgid "Bi-weekly code coverage"
msgstr ""
+msgid "Billable Users:"
+msgstr ""
+
msgid "Billing"
msgstr "Facturation"
@@ -3884,7 +4014,7 @@ msgstr ""
msgid "BillingPlans|@%{user_name} you are currently using the %{plan_name} plan."
msgstr ""
-msgid "BillingPlans|Congratulations, your new trial is activated"
+msgid "BillingPlans|Congratulations, your free trial is activated."
msgstr ""
msgid "BillingPlans|If you would like to downgrade your plan please contact %{support_link_start}Customer Support%{support_link_end}."
@@ -3947,6 +4077,9 @@ msgstr "Importation de Bitbucket"
msgid "Blame"
msgstr ""
+msgid "Block user"
+msgstr ""
+
msgid "Blocked"
msgstr ""
@@ -3962,31 +4095,37 @@ msgstr ""
msgid "Blog"
msgstr "Blog"
-msgid "Board name"
-msgstr ""
-
msgid "Board scope"
msgstr ""
msgid "Board scope affects which issues are displayed for anyone who visits this board"
msgstr ""
-msgid "BoardBlankState|Add default lists"
+msgid "Boards"
+msgstr "Tableaux"
+
+msgid "Boards and Board Lists"
msgstr ""
-msgid "BoardBlankState|Add the following default lists to your Issue Board with one click:"
+msgid "Boards|An error occurred while creating the issue. Please try again."
msgstr ""
-msgid "BoardBlankState|Nevermind, I'll use my own"
+msgid "Boards|An error occurred while creating the list. Please try again."
msgstr ""
-msgid "BoardBlankState|Starting out with the default set of lists will get you right on the way to making the most of your board."
+msgid "Boards|An error occurred while fetching issues. Please reload the page."
msgstr ""
-msgid "Boards"
-msgstr "Tableaux"
+msgid "Boards|An error occurred while fetching the board issues. Please reload the page."
+msgstr ""
-msgid "Boards and Board Lists"
+msgid "Boards|An error occurred while fetching the board swimlanes. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while moving the issue. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while updating the list. Please try again."
msgstr ""
msgid "Boards|Collapse"
@@ -4013,8 +4152,8 @@ msgstr "La branche %{branchName} n’a pas été trouvée dans le dépôt de ce
msgid "Branch %{branch_name} was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr ""
-msgid "Branch has changed"
-msgstr "La branche a été modifiée"
+msgid "Branch changed"
+msgstr ""
msgid "Branch is already taken"
msgstr "Ce nom de branche existe déjà"
@@ -4319,6 +4458,9 @@ msgstr ""
msgid "CLOSED (MOVED)"
msgstr ""
+msgid "CODEOWNERS rule violation"
+msgstr ""
+
msgid "CONTRIBUTING"
msgstr ""
@@ -4349,9 +4491,6 @@ msgstr ""
msgid "Can't create snippet: %{err}"
msgstr ""
-msgid "Can't edit as source branch was deleted"
-msgstr ""
-
msgid "Can't fetch content for the blob: %{err}"
msgstr ""
@@ -4364,9 +4503,6 @@ msgstr ""
msgid "Can't load mermaid module: %{err}"
msgstr ""
-msgid "Can't remove group members without group managed account"
-msgstr ""
-
msgid "Can't scan the code?"
msgstr ""
@@ -4409,6 +4545,9 @@ msgstr ""
msgid "Cannot create the abuse report. This user has been blocked."
msgstr ""
+msgid "Cannot enable shared runners because parent group does not allow it"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -4514,6 +4653,15 @@ msgstr ""
msgid "Change your password or recover your current one"
msgstr ""
+msgid "ChangeReviewer|Reviewer changed from %{old} to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Reviewer changed to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Unassigned"
+msgstr ""
+
msgid "ChangeTypeActionLabel|Pick into branch"
msgstr "Picorer dans la branche"
@@ -4553,6 +4701,9 @@ msgstr ""
msgid "Changes the title to \"%{title_param}\"."
msgstr ""
+msgid "Changes were successfully made."
+msgstr ""
+
msgid "Changes won't take place until the index is %{link_start}recreated%{link_end}."
msgstr ""
@@ -4958,6 +5109,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove variable"
+msgstr ""
+
msgid "CiVariables|Remove variable row"
msgstr "Supprimer cette variable"
@@ -5036,9 +5190,6 @@ msgstr ""
msgid "Clear due date"
msgstr ""
-msgid "Clear input"
-msgstr ""
-
msgid "Clear recent searches"
msgstr ""
@@ -5087,6 +5238,9 @@ msgstr "Clef d’authentification du client"
msgid "Client authentication key password"
msgstr "Mot de passe de la clef d’authentification client"
+msgid "Client request timeout"
+msgstr ""
+
msgid "Clients"
msgstr "Clients"
@@ -5171,6 +5325,27 @@ msgstr ""
msgid "Cluster type must be specificed for Stages::ClusterEndpointInserter"
msgstr ""
+msgid "ClusterAgents|Configuration"
+msgstr ""
+
+msgid "ClusterAgents|Connect your cluster with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate Kubernetes with a GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Name"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Agent also requires %{linkStart}enabling the Agent Server%{linkEnd}"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Kubernetes Agent allows an Infrastructure as Code, GitOps approach to integrating Kubernetes clusters with GitLab. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "ClusterAgent|This feature is only available for premium plans"
msgstr ""
@@ -5240,10 +5415,10 @@ msgstr ""
msgid "ClusterIntegration|All installed applications and related resources"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster."
+msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{linkStart}More information%{linkEnd}"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{startLink}More information%{endLink}"
+msgid "ClusterIntegration|Allow GitLab to manage namespaces and service accounts for this cluster."
msgstr ""
msgid "ClusterIntegration|Alternatively, "
@@ -5264,6 +5439,9 @@ msgstr ""
msgid "ClusterIntegration|An error occurred while trying to fetch zone machine types: %{error}"
msgstr ""
+msgid "ClusterIntegration|An unknown error occurred while attempting to connect to Kubernetes."
+msgstr ""
+
msgid "ClusterIntegration|Any project namespaces"
msgstr ""
@@ -5279,6 +5457,9 @@ msgstr ""
msgid "ClusterIntegration|Authenticate with Amazon Web Services"
msgstr ""
+msgid "ClusterIntegration|Authentication Error"
+msgstr ""
+
msgid "ClusterIntegration|Base domain"
msgstr ""
@@ -5297,13 +5478,22 @@ msgstr ""
msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
msgstr "Ensemble de certificats des autorités de certification (format PEM)"
-msgid "ClusterIntegration|Choose the %{startLink}security group %{externalLinkIcon} %{endLink} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
+msgid "ClusterIntegration|Check your CA certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Check your cluster status"
+msgstr ""
+
+msgid "ClusterIntegration|Check your token"
+msgstr ""
+
+msgid "ClusterIntegration|Choose the %{linkStart}security group %{linkEnd} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}subnets %{externalLinkIcon} %{endLink} in your VPC where your worker nodes will run."
+msgid "ClusterIntegration|Choose the %{linkStart}subnets %{linkEnd} in your VPC where your worker nodes will run."
msgstr ""
-msgid "ClusterIntegration|Choose the worker node %{startLink}instance type %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Choose the worker node %{linkStart}instance type%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Choose which applications to install on your Kubernetes cluster."
@@ -5315,10 +5505,7 @@ msgstr "Choisissez lequel de vos environnements utilisera cette grappe de serveu
msgid "ClusterIntegration|Clear cluster cache"
msgstr ""
-msgid "ClusterIntegration|Clear the local cache of namespace and service accounts. This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
-msgstr ""
-
-msgid "ClusterIntegration|Cluster being created"
+msgid "ClusterIntegration|Clear the local cache of namespace and service accounts."
msgstr ""
msgid "ClusterIntegration|Cluster management project (alpha)"
@@ -5330,15 +5517,21 @@ msgstr ""
msgid "ClusterIntegration|Cluster_applications artifact too big. Maximum allowable size: %{human_size}"
msgstr ""
-msgid "ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters."
+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|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}"
+msgid "ClusterIntegration|Clusters connected with a certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Connect cluster with certificate"
msgstr ""
msgid "ClusterIntegration|Connect existing cluster"
msgstr ""
+msgid "ClusterIntegration|Connection Error"
+msgstr ""
+
msgid "ClusterIntegration|Copy API URL"
msgstr "Copier l’URL de l’API"
@@ -5414,6 +5607,12 @@ msgstr ""
msgid "ClusterIntegration|Deletes all GitLab resources attached to this cluster during removal"
msgstr ""
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared."
+msgstr ""
+
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared. %{linkStart}More information%{linkEnd}"
+msgstr ""
+
msgid "ClusterIntegration|Did you know?"
msgstr "Le saviezâ€vous ?"
@@ -5483,6 +5682,9 @@ msgstr ""
msgid "ClusterIntegration|Fluentd is an open source data collector, which lets you unify the data collection and consumption for a better use and understanding of data. It requires at least one of the following logs to be successfully installed."
msgstr ""
+msgid "ClusterIntegration|GitLab Agent managed clusters"
+msgstr ""
+
msgid "ClusterIntegration|GitLab Container Network Policies"
msgstr ""
@@ -5495,6 +5697,12 @@ msgstr "Exécuteur GitLab"
msgid "ClusterIntegration|GitLab Runner connects to the repository and executes CI/CD jobs, pushing results back and deploying applications to production."
msgstr ""
+msgid "ClusterIntegration|GitLab failed to authenticate."
+msgstr ""
+
+msgid "ClusterIntegration|GitLab failed to connect to the cluster."
+msgstr ""
+
msgid "ClusterIntegration|GitLab-managed cluster"
msgstr ""
@@ -5516,6 +5724,9 @@ msgstr "Projet Google Kubernetes Engine"
msgid "ClusterIntegration|Group cluster"
msgstr "Groupe de la grappe de serveurs"
+msgid "ClusterIntegration|HTTP Error"
+msgstr ""
+
msgid "ClusterIntegration|Helm Tiller"
msgstr "Helm Tiller"
@@ -5549,8 +5760,11 @@ msgstr ""
msgid "ClusterIntegration|Instance type"
msgstr ""
-msgid "ClusterIntegration|Integrate Kubernetes cluster automation"
-msgstr "Intégrez l’automatisation de la grappe de serveurs Kubernetes"
+msgid "ClusterIntegration|Integrate Kubernetes with a cluster certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Integrate with a cluster certificate"
+msgstr ""
msgid "ClusterIntegration|Issuer Email"
msgstr ""
@@ -5585,9 +5799,6 @@ msgstr ""
msgid "ClusterIntegration|Knative extends Kubernetes to provide a set of middleware components that are essential to build modern, source-centric, and container-based applications that can run anywhere: on premises, in the cloud, or even in a third-party data center."
msgstr ""
-msgid "ClusterIntegration|Kubernetes cluster"
-msgstr "Grappe de serveurs Kubernetes"
-
msgid "ClusterIntegration|Kubernetes cluster is being created..."
msgstr ""
@@ -5600,9 +5811,6 @@ msgstr ""
msgid "ClusterIntegration|Kubernetes clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr "Les grappes de serveurs Kubernetes vous permettent d’utiliser des applications de revue de code, de déployer vos applications, d’exécuter vos pipelines et bien plus encore, et ce, de manière très simple."
-msgid "ClusterIntegration|Kubernetes clusters can be used to deploy applications and to provide Review Apps for this project"
-msgstr "Les grappes de serveurs Kubernetes peuvent être utilisées pour déployer des applications et fournir des applications de revue Review Apps pour ce projet"
-
msgid "ClusterIntegration|Kubernetes version"
msgstr ""
@@ -5615,7 +5823,7 @@ msgstr "En savoir plus sur les %{help_link_start_machine_type}types de machine
msgid "ClusterIntegration|Learn more about %{help_link_start}zones%{help_link_end}."
msgstr "En savoir plus sur %{help_link_start}les zones%{help_link_end}."
-msgid "ClusterIntegration|Learn more about %{startLink}Regions %{externalLinkIcon}%{endLink}."
+msgid "ClusterIntegration|Learn more about %{linkStart}Regions%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Learn more about Kubernetes"
@@ -5660,12 +5868,18 @@ msgstr ""
msgid "ClusterIntegration|Machine type"
msgstr "Type de machine"
+msgid "ClusterIntegration|Make sure your API endpoint is correct"
+msgstr ""
+
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create Kubernetes clusters"
msgstr "Assurezâ€vous que votre compte %{link_to_requirements} pour créer des grappes de serveurs Kubernetes"
msgid "ClusterIntegration|Manage your Kubernetes cluster by visiting %{provider_link}"
msgstr ""
+msgid "ClusterIntegration|Namespace per environment"
+msgstr ""
+
msgid "ClusterIntegration|No IAM Roles found"
msgstr ""
@@ -5711,6 +5925,9 @@ msgstr ""
msgid "ClusterIntegration|No zones matched your search"
msgstr "Aucune zone ne correspond à votre recherche"
+msgid "ClusterIntegration|Node calculations use the Kubernetes Metrics API. Make sure your cluster has metrics installed"
+msgstr ""
+
msgid "ClusterIntegration|Number of nodes"
msgstr "Nombre de nœuds"
@@ -5753,6 +5970,9 @@ msgstr ""
msgid "ClusterIntegration|RBAC-enabled cluster"
msgstr "Grappe de serveurs avec contrôle d’accès par rôle"
+msgid "ClusterIntegration|Read our %{linkStart}help page%{linkEnd} on Kubernetes cluster integration."
+msgstr ""
+
msgid "ClusterIntegration|Read our %{link_start}help page%{link_end} on Kubernetes cluster integration."
msgstr ""
@@ -5855,7 +6075,7 @@ msgstr ""
msgid "ClusterIntegration|Select a VPC to choose a subnet"
msgstr ""
-msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{linkStart}Amazon Web Services %{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select a network to choose a subnetwork"
@@ -5888,7 +6108,7 @@ msgstr "Sélectionnez le projet et la zone afin de choisir le type de machine"
msgid "ClusterIntegration|Select project to choose zone"
msgstr "Sélectionnez le projet afin de choisir la zone"
-msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select zone"
@@ -5978,9 +6198,18 @@ msgstr ""
msgid "ClusterIntegration|There was a problem authenticating with your cluster. Please ensure your CA Certificate and Token are valid."
msgstr ""
+msgid "ClusterIntegration|There was an HTTP error when connecting to your cluster."
+msgstr ""
+
msgid "ClusterIntegration|This account must have permissions to create a Kubernetes cluster in the %{link_to_container_project} specified below"
msgstr "Ce compte doit disposer des autorisations pour créer une grappe de serveurs Kubernetes dans le %{link_to_container_project} spécifié ciâ€dessous"
+msgid "ClusterIntegration|This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
+msgstr ""
+
+msgid "ClusterIntegration|This is necessary to clear existing environment-namespace associations from clusters previously managed by GitLab."
+msgstr ""
+
msgid "ClusterIntegration|This option will allow you to install applications on RBAC clusters."
msgstr "Cette option vous permettra d’installer des applications sur des grappes de serveurs avec contrôle d’accès basé sur le rôle (RBAC)."
@@ -6005,9 +6234,21 @@ msgstr ""
msgid "ClusterIntegration|To use a new project, first create one on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}."
msgstr ""
+msgid "ClusterIntegration|Troubleshooting tips:"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Authenticate"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Connect"
+msgstr ""
+
msgid "ClusterIntegration|Uninstall %{appTitle}"
msgstr ""
+msgid "ClusterIntegration|Unknown Error"
+msgstr ""
+
msgid "ClusterIntegration|Update %{appTitle}"
msgstr ""
@@ -6068,7 +6309,7 @@ msgstr "Votre compte doit disposer de %{link_to_kubernetes_engine}"
msgid "ClusterIntegration|Your cluster API is unreachable. Please ensure your API URL is correct."
msgstr ""
-msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Zone"
@@ -6188,6 +6429,9 @@ msgstr ""
msgid "Collapse"
msgstr "Réduire"
+msgid "Collapse all threads"
+msgstr ""
+
msgid "Collapse approvers"
msgstr ""
@@ -6337,7 +6581,7 @@ msgstr "Commit de"
msgid "Commit…"
msgstr "Commit…"
-msgid "Company"
+msgid "Community forum"
msgstr ""
msgid "Company name"
@@ -6346,6 +6590,9 @@ msgstr ""
msgid "Compare"
msgstr "Comparer"
+msgid "Compare %{oldCommitId}...%{newCommitId}"
+msgstr ""
+
msgid "Compare Git revisions"
msgstr "Comparer les révisions Git"
@@ -6361,6 +6608,9 @@ msgstr "Comparer les changements avec le dernier commit"
msgid "Compare changes with the merge request target branch"
msgstr "Comparer les modifications avec la branche cible de la demande de fusion"
+msgid "Compare submodule commit revisions"
+msgstr ""
+
msgid "Compare with previous version"
msgstr ""
@@ -6496,6 +6746,9 @@ msgstr "Configurez l’intégration de %{link}."
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 which lists are shown for anyone who visits this board"
+msgstr ""
+
msgid "Confirm"
msgstr ""
@@ -6721,6 +6974,9 @@ msgstr[1] ""
msgid "ContainerRegistry|Set cleanup policy"
msgstr ""
+msgid "ContainerRegistry|Some tags were not deleted"
+msgstr ""
+
msgid "ContainerRegistry|Something went wrong while fetching the cleanup policy."
msgstr ""
@@ -6760,6 +7016,9 @@ msgstr ""
msgid "ContainerRegistry|Tags with names matching this regex pattern will %{italicStart}expire:%{italicEnd}"
msgstr ""
+msgid "ContainerRegistry|The cleanup policy timed out before it could delete all tags. An administrator can %{adminLinkStart}manually run cleanup now%{adminLinkEnd} or you can wait for the cleanup policy to automatically run again. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "ContainerRegistry|The last tag related to this image was recently removed. This empty image and any associated data will be automatically removed as part of the regular Garbage Collection process. If you have any questions, contact your administrator."
msgstr ""
@@ -6892,6 +7151,9 @@ msgstr ""
msgid "Contributions per group member"
msgstr "Contributions par membre du groupe"
+msgid "Contributor"
+msgstr ""
+
msgid "Contributors"
msgstr "Contributeurs"
@@ -7021,6 +7283,9 @@ msgstr ""
msgid "Could not change HEAD: branch '%{branch}' does not exist"
msgstr ""
+msgid "Could not commit. An unexpected error occurred."
+msgstr ""
+
msgid "Could not connect to FogBugz, check your URL"
msgstr ""
@@ -7060,6 +7325,9 @@ msgstr ""
msgid "Could not find iteration"
msgstr ""
+msgid "Could not load instance counts. Please refresh the page to try again."
+msgstr ""
+
msgid "Could not remove the trigger."
msgstr ""
@@ -7084,10 +7352,10 @@ msgstr ""
msgid "Could not save prometheus manual configuration"
msgstr ""
-msgid "Could not udpdate wiki page"
+msgid "Could not update the LDAP settings"
msgstr ""
-msgid "Could not update the LDAP settings"
+msgid "Could not update wiki page"
msgstr ""
msgid "Could not upload your designs as one or more files uploaded are not supported."
@@ -7745,6 +8013,9 @@ msgstr ""
msgid "DastProfiles|Are you sure you want to delete this profile?"
msgstr ""
+msgid "DastProfiles|Could not create site validation token. Please refresh the page, or try again later."
+msgstr ""
+
msgid "DastProfiles|Could not create the scanner profile. Please try again."
msgstr ""
@@ -7769,6 +8040,12 @@ msgstr ""
msgid "DastProfiles|Could not fetch site profiles. Please refresh the page, or try again later."
msgstr ""
+msgid "DastProfiles|Could not retrieve site validation status. Please refresh the page, or try again later."
+msgstr ""
+
+msgid "DastProfiles|Could not update the scanner profile. Please try again."
+msgstr ""
+
msgid "DastProfiles|Could not update the site profile. Please try again."
msgstr ""
@@ -7784,7 +8061,7 @@ msgstr ""
msgid "DastProfiles|Download validation text file"
msgstr ""
-msgid "DastProfiles|Edit feature will come soon. Please create a new profile if changes needed"
+msgid "DastProfiles|Edit scanner profile"
msgstr ""
msgid "DastProfiles|Edit site profile"
@@ -7817,6 +8094,9 @@ msgstr ""
msgid "DastProfiles|No profiles created yet"
msgstr ""
+msgid "DastProfiles|Passive"
+msgstr ""
+
msgid "DastProfiles|Please enter a valid URL format, ex: http://www.example.com/home"
msgstr ""
@@ -7832,6 +8112,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan mode"
+msgstr ""
+
msgid "DastProfiles|Scanner Profile"
msgstr ""
@@ -7871,10 +8154,10 @@ msgstr ""
msgid "DastProfiles|Text file validation"
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
+msgid "DastProfiles|The maximum number of minutes allowed for the spider to traverse the site."
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the spider to traverse the site."
+msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
msgstr ""
msgid "DastProfiles|Validate"
@@ -7907,6 +8190,9 @@ msgstr ""
msgid "Date picker"
msgstr "Sélecteur de date"
+msgid "Date range"
+msgstr ""
+
msgid "Date range cannot exceed %{maxDateRange} days."
msgstr ""
@@ -7931,6 +8217,9 @@ msgstr ""
msgid "Days to merge"
msgstr ""
+msgid "Dear Administrator,"
+msgstr ""
+
msgid "Debug"
msgstr "Déboguer"
@@ -8042,12 +8331,18 @@ msgstr "différé"
msgid "Delete"
msgstr "Supprimer"
+msgid "Delete %{name}"
+msgstr ""
+
msgid "Delete Comment"
msgstr ""
msgid "Delete Snippet"
msgstr "Supprimer L’extrait de code"
+msgid "Delete Value Stream"
+msgstr ""
+
msgid "Delete account"
msgstr ""
@@ -8069,9 +8364,6 @@ msgstr ""
msgid "Delete label: %{label_name} ?"
msgstr ""
-msgid "Delete license"
-msgstr ""
-
msgid "Delete list"
msgstr "Supprimer la liste"
@@ -8147,15 +8439,6 @@ msgstr ""
msgid "Deleting a project places it into a read-only state until %{date}, at which point the project will be permanently deleted. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "Deleting the license failed."
-msgstr ""
-
-msgid "Deleting the license failed. The license was not found."
-msgstr ""
-
-msgid "Deleting the license failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "Deleting the project will delete its repository and all related resources including issues, merge requests etc."
msgstr ""
@@ -8651,7 +8934,10 @@ msgstr ""
msgid "DesignManagement|The maximum number of designs allowed to be uploaded is %{upload_limit}. Please try again."
msgstr ""
-msgid "DesignManagement|To upload designs, you'll need to enable LFS. %{requirements_link_start}More information%{requirements_link_end}"
+msgid "DesignManagement|There was an error moving your designs. Please upload your designs below."
+msgstr ""
+
+msgid "DesignManagement|To upload designs, you'll need to enable LFS and have admin enable hashed storage. %{requirements_link_start}More information%{requirements_link_end}"
msgstr ""
msgid "DesignManagement|Unresolve thread"
@@ -8663,6 +8949,9 @@ msgstr ""
msgid "DesignManagement|Upload skipped."
msgstr ""
+msgid "DesignManagement|Your designs are being copied and are on their way… Please refresh to update."
+msgstr ""
+
msgid "DesignManagement|and %{moreCount} more."
msgstr ""
@@ -8720,6 +9009,9 @@ msgstr ""
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr "Quelque chose s’est mal passé lors de la rapatriement des lignes du diff."
+msgid "Direct member"
+msgstr ""
+
msgid "Direction"
msgstr "Direction"
@@ -8768,9 +9060,6 @@ msgstr "Rejeter les modifications de %{path} ?"
msgid "Discard draft"
msgstr "Abandonner le brouillon"
-msgid "Discard review"
-msgstr "Rejeter la revue de code"
-
msgid "DiscordService|Discord Notifications"
msgstr ""
@@ -8839,10 +9128,10 @@ msgstr ""
msgid "Dismiss Merge Request promotion"
msgstr "Rejeter la promotion de la demande de fusion"
-msgid "Dismiss Selected"
+msgid "Dismiss Value Stream Analytics introduction box"
msgstr ""
-msgid "Dismiss Value Stream Analytics introduction box"
+msgid "Dismiss selected"
msgstr ""
msgid "Dismiss trial promotion"
@@ -8893,9 +9182,6 @@ msgstr "Documentation des principaux fournisseurs d’identité"
msgid "Documents reindexed: %{processed_documents} (%{percentage}%%)"
msgstr ""
-msgid "Doing"
-msgstr ""
-
msgid "Domain"
msgstr "Domaine"
@@ -9091,9 +9377,6 @@ msgstr ""
msgid "Edit environment"
msgstr ""
-msgid "Edit file"
-msgstr ""
-
msgid "Edit files in the editor and commit changes here"
msgstr "Modifier les fichiers dans l’éditeur et valider les modifications ici"
@@ -9106,6 +9389,12 @@ msgstr "Modifier le groupe : %{group_name}"
msgid "Edit identity for %{user_name}"
msgstr "Modifier l’identité de %{user_name}"
+msgid "Edit in Web IDE"
+msgstr ""
+
+msgid "Edit in single-file editor"
+msgstr ""
+
msgid "Edit issues"
msgstr ""
@@ -9133,21 +9422,18 @@ msgstr ""
msgid "Editing"
msgstr ""
-msgid "Elasticsearch"
-msgstr "Elasticsearch"
-
msgid "Elasticsearch AWS IAM credentials"
msgstr ""
+msgid "Elasticsearch HTTP client timeout value in seconds."
+msgstr ""
+
msgid "Elasticsearch indexing restrictions"
msgstr ""
msgid "Elasticsearch indexing started"
msgstr ""
-msgid "Elasticsearch integration. Elasticsearch AWS IAM."
-msgstr "Intégration d’Elasticsearch. Elasticsearch AWS IAM."
-
msgid "Elasticsearch reindexing is already in progress"
msgstr ""
@@ -9175,9 +9461,6 @@ msgstr ""
msgid "Email Notification"
msgstr ""
-msgid "Email address"
-msgstr ""
-
msgid "Email could not be sent"
msgstr ""
@@ -9241,6 +9524,9 @@ msgstr "Courriels"
msgid "Emails sent from Service Desk will have this name"
msgstr ""
+msgid "Emails sent to %{email} will still be supported"
+msgstr ""
+
msgid "Emails separated by comma"
msgstr ""
@@ -9274,9 +9560,18 @@ msgstr ""
msgid "Enable"
msgstr "Activer"
+msgid "Enable %{link_start}Gitpod%{link_end} integration to launch a development environment in your browser directly from GitLab."
+msgstr ""
+
msgid "Enable Auto DevOps"
msgstr "Activer Auto DevOps"
+msgid "Enable Gitpod"
+msgstr ""
+
+msgid "Enable Gitpod?"
+msgstr ""
+
msgid "Enable HTML emails"
msgstr ""
@@ -9406,9 +9701,6 @@ msgstr ""
msgid "Encountered an error while rendering: %{err}"
msgstr ""
-msgid "End date"
-msgstr ""
-
msgid "Ends at (UTC)"
msgstr "Se termine à (UTC)"
@@ -9568,7 +9860,7 @@ msgstr ""
msgid "EnvironmentsDashboard|The environments dashboard provides a summary of each project's environments' status, including pipeline and alert statuses."
msgstr ""
-msgid "EnvironmentsDashboard|This dashboard displays a maximum of 7 projects and 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
+msgid "EnvironmentsDashboard|This dashboard displays 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
msgstr ""
msgid "Environments|An error occurred while canceling the auto stop, please try again"
@@ -9889,6 +10181,9 @@ msgstr ""
msgid "Error deleting project. Check logs for error details."
msgstr ""
+msgid "Error fetching burnup chart data"
+msgstr ""
+
msgid "Error fetching diverging counts for branches. Please try again."
msgstr ""
@@ -9967,6 +10262,9 @@ msgstr ""
msgid "Error occurred when saving assignees"
msgstr ""
+msgid "Error occurred when saving reviewers"
+msgstr ""
+
msgid "Error occurred when toggling the notification subscription"
msgstr "Une erreur s’est produite lors de l’activation ou de la désactivation de l’abonnement aux notifications"
@@ -10219,10 +10517,13 @@ msgstr "Étendre"
msgid "Expand all"
msgstr "Tout étendre"
-msgid "Expand approvers"
+msgid "Expand all files"
msgstr ""
-msgid "Expand dropdown"
+msgid "Expand all threads"
+msgstr ""
+
+msgid "Expand approvers"
msgstr ""
msgid "Expand milestones"
@@ -10393,6 +10694,9 @@ msgstr "Échec de la vérification des branches liées."
msgid "Failed to create Merge Request. Please try again."
msgstr ""
+msgid "Failed to create To-Do for the design."
+msgstr ""
+
msgid "Failed to create a branch for this issue. Please try again."
msgstr ""
@@ -10432,6 +10736,12 @@ msgstr ""
msgid "Failed to load authors. Please try again."
msgstr ""
+msgid "Failed to load branches. Please try again."
+msgstr ""
+
+msgid "Failed to load deploy keys."
+msgstr ""
+
msgid "Failed to load emoji list."
msgstr "Impossible de charger la liste des émojis."
@@ -10447,6 +10757,9 @@ msgstr ""
msgid "Failed to load groups & users."
msgstr ""
+msgid "Failed to load groups, users and deploy keys."
+msgstr ""
+
msgid "Failed to load labels. Please try again."
msgstr ""
@@ -10456,6 +10769,12 @@ msgstr ""
msgid "Failed to load related branches"
msgstr ""
+msgid "Failed to load sidebar confidential toggle"
+msgstr ""
+
+msgid "Failed to load sidebar lock status"
+msgstr ""
+
msgid "Failed to load stacktrace."
msgstr ""
@@ -10483,6 +10802,9 @@ msgstr ""
msgid "Failed to publish issue on status page."
msgstr ""
+msgid "Failed to remove To-Do for the design."
+msgstr ""
+
msgid "Failed to remove a Zoom meeting"
msgstr ""
@@ -10525,6 +10847,9 @@ msgstr ""
msgid "Failed to signing using smartcard authentication"
msgstr "Échec de la signature via authentification par carte à puce"
+msgid "Failed to toggle To-Do for the design."
+msgstr ""
+
msgid "Failed to update branch!"
msgstr ""
@@ -10638,7 +10963,7 @@ msgstr "Modifier l’indicateur de fonctionnalité"
msgid "FeatureFlags|Edit User List"
msgstr ""
-msgid "FeatureFlags|Enable features for specific users and specific environments by defining feature flag strategies."
+msgid "FeatureFlags|Enable features for specific users and environments by configuring feature flag strategies."
msgstr ""
msgid "FeatureFlags|Environment Spec"
@@ -10698,7 +11023,7 @@ msgstr ""
msgid "FeatureFlags|Include additional user IDs"
msgstr ""
-msgid "FeatureFlags|Install a %{docs_link_anchored_start}compatible client library%{docs_link_anchored_end} and specify the API URL, application name, and instance ID during the configuration setup. %{docs_link_start}More Information%{docs_link_end}"
+msgid "FeatureFlags|Install a %{docsLinkAnchoredStart}compatible client library%{docsLinkAnchoredEnd} and specify the API URL, application name, and instance ID during the configuration setup. %{docsLinkStart}More Information%{docsLinkEnd}"
msgstr ""
msgid "FeatureFlags|Instance ID"
@@ -10710,6 +11035,9 @@ msgstr ""
msgid "FeatureFlags|Loading feature flags"
msgstr ""
+msgid "FeatureFlags|Loading user lists"
+msgstr ""
+
msgid "FeatureFlags|More information"
msgstr ""
@@ -10728,7 +11056,7 @@ msgstr ""
msgid "FeatureFlags|New feature flag"
msgstr ""
-msgid "FeatureFlags|New list"
+msgid "FeatureFlags|New user list"
msgstr ""
msgid "FeatureFlags|Percent of users"
@@ -10767,6 +11095,9 @@ msgstr ""
msgid "FeatureFlags|There was an error fetching the feature flags."
msgstr ""
+msgid "FeatureFlags|There was an error fetching the user lists."
+msgstr ""
+
msgid "FeatureFlags|There was an error retrieving user lists"
msgstr ""
@@ -10782,6 +11113,9 @@ msgstr ""
msgid "FeatureFlags|User List"
msgstr ""
+msgid "FeatureFlags|User Lists"
+msgstr ""
+
msgid "FeatureFlag|List"
msgstr ""
@@ -10809,15 +11143,6 @@ msgstr "février"
msgid "Fetching incoming email"
msgstr ""
-msgid "Fetching licenses failed."
-msgstr ""
-
-msgid "Fetching licenses failed. The request endpoint was not found."
-msgstr ""
-
-msgid "Fetching licenses failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "File"
msgstr ""
@@ -10920,12 +11245,21 @@ msgstr ""
msgid "Filter by status"
msgstr ""
+msgid "Filter by test cases that are currently archived."
+msgstr ""
+
+msgid "Filter by test cases that are currently opened."
+msgstr ""
+
msgid "Filter by two-factor authentication"
msgstr ""
msgid "Filter by user"
msgstr ""
+msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
+msgstr ""
+
msgid "Filter pipelines"
msgstr ""
@@ -10941,7 +11275,7 @@ msgstr ""
msgid "Filter results..."
msgstr ""
-msgid "Filter your projects by name"
+msgid "Filter your repositories by name"
msgstr ""
msgid "Filter..."
@@ -10950,7 +11284,7 @@ msgstr "Filtrer…"
msgid "Find File"
msgstr ""
-msgid "Find bugs in your code with coverage-guided fuzzing"
+msgid "Find bugs in your code with coverage-guided fuzzing."
msgstr ""
msgid "Find by path"
@@ -10977,9 +11311,6 @@ msgstr "Empreintes"
msgid "Finish editing this message first!"
msgstr ""
-msgid "Finish review"
-msgstr "Terminer la revue de code"
-
msgid "Finish setting up your dedicated account for %{group_name}."
msgstr ""
@@ -11049,6 +11380,9 @@ msgstr "Couleur de la police"
msgid "Footer message"
msgstr "Message de pied de page"
+msgid "For a faster browsing experience, some files are collapsed by default."
+msgstr ""
+
msgid "For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
@@ -11058,6 +11392,9 @@ msgstr "Pour les projets internes, tout utilisateur connecté peut afficher les
msgid "For more info, read the documentation."
msgstr ""
+msgid "For more information on how the number of active users is calculated, see the %{self_managed_subscriptions_doc_link} documentation."
+msgstr ""
+
msgid "For more information, go to the "
msgstr "Pour plus d’informations, consultez "
@@ -11196,6 +11533,9 @@ msgstr ""
msgid "Generate new token"
msgstr ""
+msgid "Generic package file size in bytes"
+msgstr ""
+
msgid "Geo"
msgstr "Geo"
@@ -11457,6 +11797,9 @@ msgstr "En attente de vérification"
msgid "Geo|Please refer to Geo Troubleshooting."
msgstr ""
+msgid "Geo|Primary node"
+msgstr ""
+
msgid "Geo|Project"
msgstr ""
@@ -11499,6 +11842,9 @@ msgstr ""
msgid "Geo|Review replication status, and resynchronize and reverify items with the primary node."
msgstr ""
+msgid "Geo|Secondary node"
+msgstr ""
+
msgid "Geo|Status"
msgstr "Statut"
@@ -11538,6 +11884,9 @@ msgstr ""
msgid "Geo|URL must be a valid url (ex: https://gitlab.com)"
msgstr ""
+msgid "Geo|Undefined"
+msgstr ""
+
msgid "Geo|Unknown state"
msgstr "État inconnu"
@@ -11613,10 +11962,16 @@ msgstr ""
msgid "GitHub import"
msgstr "Importation de GitHub"
+msgid "GitLab"
+msgstr ""
+
msgid "GitLab / Unsubscribe"
msgstr ""
-msgid "GitLab Enterprise Edition %{plan}"
+msgid "GitLab API"
+msgstr ""
+
+msgid "GitLab Billing Team."
msgstr ""
msgid "GitLab Group Runners can execute code for all the projects in this group."
@@ -11628,12 +11983,18 @@ msgstr "Importation depuis GitLab"
msgid "GitLab Issue"
msgstr ""
+msgid "GitLab Pages"
+msgstr ""
+
msgid "GitLab Service Desk is a simple way to allow people to create issues in your GitLab instance without needing their own user account. It provides a unique email address for end users to create issues in a project, and replies can be sent either through the GitLab interface or by email. End users will only see the thread through email."
msgstr ""
msgid "GitLab Shared Runners execute code of different projects on the same Runner unless you configure GitLab Runner Autoscale with MaxBuilds 1 (which it is on GitLab.com)."
msgstr ""
+msgid "GitLab Shell"
+msgstr ""
+
msgid "GitLab Support Bot"
msgstr ""
@@ -11643,7 +12004,7 @@ msgstr ""
msgid "GitLab User"
msgstr "Utilisateur GitLab"
-msgid "GitLab allows you to continue using your license even if you exceed the number of seats you purchased. You will be required to pay for these seats when you renew your license."
+msgid "GitLab Workhorse"
msgstr ""
msgid "GitLab commit"
@@ -11811,6 +12172,21 @@ msgstr "Importation depuis Gitea"
msgid "Gitlab Pages"
msgstr ""
+msgid "Gitpod"
+msgstr ""
+
+msgid "Gitpod|Add the URL to your Gitpod instance configured to read your GitLab projects."
+msgstr ""
+
+msgid "Gitpod|Enable Gitpod integration"
+msgstr ""
+
+msgid "Gitpod|Gitpod URL"
+msgstr ""
+
+msgid "Gitpod|e.g. https://gitpod.example.com"
+msgstr ""
+
msgid "Given access %{time_ago}"
msgstr ""
@@ -12318,9 +12694,6 @@ msgstr ""
msgid "GroupSAML|Valid SAML Response"
msgstr ""
-msgid "GroupSAML|With group managed accounts enabled, all the users without a group managed account will be excluded from the group."
-msgstr ""
-
msgid "GroupSAML|With prohibit outer forks flag enabled group members will be able to fork project only inside your group."
msgstr ""
@@ -12534,10 +12907,10 @@ msgstr ""
msgid "GroupsNew|Create group"
msgstr ""
-msgid "GroupsNew|GitLab group export"
+msgid "GroupsNew|Import"
msgstr ""
-msgid "GroupsNew|Import"
+msgid "GroupsNew|Import a GitLab group export file"
msgstr ""
msgid "GroupsNew|Import group"
@@ -12680,6 +13053,9 @@ msgid_plural "Hide charts"
msgstr[0] ""
msgstr[1] ""
+msgid "Hide comments on this file"
+msgstr ""
+
msgid "Hide details"
msgstr ""
@@ -12724,6 +13100,15 @@ msgstr ""
msgid "Highest role:"
msgstr ""
+msgid "HighlightBar|Alert events:"
+msgstr ""
+
+msgid "HighlightBar|Alert start time:"
+msgstr ""
+
+msgid "HighlightBar|Original alert:"
+msgstr ""
+
msgid "History"
msgstr "Historique"
@@ -12901,6 +13286,9 @@ msgstr ""
msgid "If enabled, access to projects will be validated on an external service using their classification label."
msgstr "Si activé, l’accès aux projets sera validé sur un service externe en se basant sur leurs étiquettes de classification respectives."
+msgid "If the number of active users exceeds the user limit, you will be charged for the number of %{users_over_license_link} at your next license reconciliation."
+msgstr ""
+
msgid "If there is no previous license or if the previous license has expired, some GitLab functionality will be blocked until a new, valid license is uploaded."
msgstr ""
@@ -12940,9 +13328,6 @@ msgstr ""
msgid "If your HTTP repository is not publicly accessible, add your credentials."
msgstr ""
-msgid "Iglu registry URL (optional)"
-msgstr ""
-
msgid "Ignore"
msgstr ""
@@ -12979,6 +13364,16 @@ msgstr ""
msgid "Import"
msgstr "Importer"
+msgid "Import %d compatible repository"
+msgid_plural "Import %d compatible repositories"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Import %d repository"
+msgid_plural "Import %d repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Import CSV"
msgstr ""
@@ -12988,15 +13383,9 @@ msgstr "Importe des projets depuis Gitea"
msgid "Import all compatible projects"
msgstr "Importer tous les projets compatibles"
-msgid "Import all compatible repositories"
-msgstr ""
-
msgid "Import all projects"
msgstr "Importer tous les projets"
-msgid "Import all repositories"
-msgstr "Importer tous les dépôts"
-
msgid "Import an exported GitLab project"
msgstr "Importer un projet GitLab exporté"
@@ -13084,6 +13473,9 @@ msgstr ""
msgid "ImportProjects|Error importing repository %{project_safe_import_url} into %{project_full_path} - %{message}"
msgstr ""
+msgid "ImportProjects|Import repositories"
+msgstr ""
+
msgid "ImportProjects|Importing the project failed"
msgstr ""
@@ -13096,7 +13488,7 @@ msgstr ""
msgid "ImportProjects|Requesting your %{provider} repositories failed"
msgstr ""
-msgid "ImportProjects|Select the projects you want to import"
+msgid "ImportProjects|Select the repositories you want to import"
msgstr ""
msgid "ImportProjects|The remote data could not be imported."
@@ -13132,9 +13524,6 @@ msgstr ""
msgid "In order to enable Service Desk for your instance, you must first set up incoming email."
msgstr ""
-msgid "In order to gather accurate feature usage data, it can take 1 to 2 weeks to see your index."
-msgstr ""
-
msgid "In order to personalize your experience with GitLab%{br_tag}we would like to know a bit more about you."
msgstr ""
@@ -13165,18 +13554,30 @@ msgstr ""
msgid "IncidentManagement|Create incident"
msgstr ""
+msgid "IncidentManagement|Critical - S1"
+msgstr ""
+
msgid "IncidentManagement|Date created"
msgstr ""
msgid "IncidentManagement|Display your incidents in a dedicated view"
msgstr ""
+msgid "IncidentManagement|High - S2"
+msgstr ""
+
msgid "IncidentManagement|Incident"
msgstr ""
msgid "IncidentManagement|Incidents"
msgstr ""
+msgid "IncidentManagement|Low - S4"
+msgstr ""
+
+msgid "IncidentManagement|Medium - S3"
+msgstr ""
+
msgid "IncidentManagement|No incidents to display."
msgstr ""
@@ -13189,6 +13590,9 @@ msgstr ""
msgid "IncidentManagement|Published to status page"
msgstr ""
+msgid "IncidentManagement|Severity"
+msgstr ""
+
msgid "IncidentManagement|There are no closed incidents"
msgstr ""
@@ -13198,6 +13602,9 @@ msgstr ""
msgid "IncidentManagement|Unassigned"
msgstr ""
+msgid "IncidentManagement|Unknown"
+msgstr ""
+
msgid "IncidentManagement|Unpublished"
msgstr ""
@@ -13219,6 +13626,15 @@ msgstr ""
msgid "Incidents"
msgstr ""
+msgid "Incident|Alert details"
+msgstr ""
+
+msgid "Incident|Summary"
+msgstr ""
+
+msgid "Incident|There was an issue loading alert data. Please try again."
+msgstr ""
+
msgid "Include a Terms of Service agreement and Privacy Policy that all users must accept."
msgstr "Inclure un accord sur les conditions générales d’utilisation et la politique de confidentialité que tous les utilisateurs doivent accepter."
@@ -13279,6 +13695,9 @@ msgstr ""
msgid "Information about additional Pages templates and how to install them can be found in our %{pages_getting_started_guide}."
msgstr ""
+msgid "Inherited"
+msgstr ""
+
msgid "Inherited:"
msgstr ""
@@ -13359,7 +13778,22 @@ msgstr ""
msgid "Instance administrators group already exists"
msgstr ""
-msgid "Instance license"
+msgid "InstanceStatistics|Groups"
+msgstr ""
+
+msgid "InstanceStatistics|Issues"
+msgstr ""
+
+msgid "InstanceStatistics|Merge Requests"
+msgstr ""
+
+msgid "InstanceStatistics|Pipelines"
+msgstr ""
+
+msgid "InstanceStatistics|Projects"
+msgstr ""
+
+msgid "InstanceStatistics|Users"
msgstr ""
msgid "Integration"
@@ -13371,6 +13805,12 @@ msgstr ""
msgid "Integrations"
msgstr "Intégrations"
+msgid "Integrations|%{integration} settings saved and active."
+msgstr ""
+
+msgid "Integrations|%{integration} settings saved, but not active."
+msgstr ""
+
msgid "Integrations|All details"
msgstr ""
@@ -13380,6 +13820,12 @@ msgstr ""
msgid "Integrations|Comment settings:"
msgstr ""
+msgid "Integrations|Connection failed. Please check your settings."
+msgstr ""
+
+msgid "Integrations|Connection successful."
+msgstr ""
+
msgid "Integrations|Default settings are inherited from the group level."
msgstr ""
@@ -13395,6 +13841,15 @@ msgstr ""
msgid "Integrations|Includes commit title and branch"
msgstr ""
+msgid "Integrations|Projects using custom settings will not be impacted unless the project owner chooses to use instance-level defaults."
+msgstr ""
+
+msgid "Integrations|Save settings?"
+msgstr ""
+
+msgid "Integrations|Saving will update the default settings for all projects that are not using custom settings."
+msgstr ""
+
msgid "Integrations|Standard"
msgstr ""
@@ -13527,6 +13982,9 @@ msgstr ""
msgid "Invitation"
msgstr ""
+msgid "Invitation declined"
+msgstr ""
+
msgid "Invite"
msgstr "Inviter"
@@ -13578,6 +14036,42 @@ 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|%{linkStart}Read more%{linkEnd} about role permissions"
+msgstr ""
+
+msgid "InviteMembersModal|Access expiration date (optional)"
+msgstr ""
+
+msgid "InviteMembersModal|Cancel"
+msgstr ""
+
+msgid "InviteMembersModal|Choose a role permission"
+msgstr ""
+
+msgid "InviteMembersModal|GitLab member or Email address"
+msgstr ""
+
+msgid "InviteMembersModal|Invite"
+msgstr ""
+
+msgid "InviteMembersModal|Invite team members"
+msgstr ""
+
+msgid "InviteMembersModal|Search for members to invite"
+msgstr ""
+
+msgid "InviteMembersModal|User not invited. Feature coming soon!"
+msgstr ""
+
+msgid "InviteMembersModal|Users were succesfully added"
+msgstr ""
+
+msgid "InviteMembersModal|You're inviting members to the %{group_name} group"
+msgstr ""
+
+msgid "InviteMembers|Invite team members"
+msgstr ""
+
msgid "Invited"
msgstr ""
@@ -13632,10 +14126,13 @@ msgstr ""
msgid "Issue cannot be found."
msgstr ""
+msgid "Issue created from vulnerability %{vulnerability_link}"
+msgstr ""
+
msgid "Issue events"
msgstr "Événements du ticket"
-msgid "Issue first depoloyed to production"
+msgid "Issue first deployed to production"
msgstr ""
msgid "Issue label"
@@ -13713,6 +14210,9 @@ msgstr ""
msgid "IssueTracker|Custom issue tracker"
msgstr ""
+msgid "IssueTracker|EWM work items tracker"
+msgstr ""
+
msgid "IssueTracker|Redmine issue tracker"
msgstr ""
@@ -13779,6 +14279,9 @@ msgstr ""
msgid "It looks like you have some draft commits in this branch."
msgstr ""
+msgid "It may be several days before you see feature usage data."
+msgstr ""
+
msgid "It must have a header row and at least two columns: the first column is the issue title and the second column is the issue description. The separator is automatically detected."
msgstr ""
@@ -14061,15 +14564,15 @@ msgstr ""
msgid "Join Zoom meeting"
msgstr ""
+msgid "Joined %{time_ago}"
+msgstr ""
+
msgid "Jul"
msgstr "juill."
msgid "July"
msgstr "juillet"
-msgid "Jump to first unresolved thread"
-msgstr ""
-
msgid "Jump to next unresolved thread"
msgstr ""
@@ -14103,6 +14606,9 @@ msgstr ""
msgid "Keyboard shortcuts"
msgstr ""
+msgid "KeyboardKey|Ctrl+"
+msgstr ""
+
msgid "Keys"
msgstr ""
@@ -14151,6 +14657,9 @@ msgstr ""
msgid "LDAP Synchronization"
msgstr ""
+msgid "LDAP group settings"
+msgstr ""
+
msgid "LDAP settings"
msgstr ""
@@ -14160,6 +14669,9 @@ msgstr ""
msgid "LDAP sync in progress. This could take a few minutes. Refresh the page to see the changes."
msgstr ""
+msgid "LDAP synchronizations"
+msgstr ""
+
msgid "LFS"
msgstr "LFS"
@@ -14240,7 +14752,16 @@ msgid_plural "Last %d days"
msgstr[0] "Le dernier %d jour"
msgstr[1] "Les %d derniers jours"
-msgid "Last %{days} days"
+msgid "Last 2 weeks"
+msgstr ""
+
+msgid "Last 30 days"
+msgstr ""
+
+msgid "Last 60 days"
+msgstr ""
+
+msgid "Last 90 days"
msgstr ""
msgid "Last Accessed On"
@@ -14318,6 +14839,9 @@ msgstr ""
msgid "Last used on:"
msgstr ""
+msgid "Last week"
+msgstr ""
+
msgid "LastCommit|authored"
msgstr ""
@@ -14333,6 +14857,9 @@ msgstr "Derniers changements"
msgid "Latest pipeline for the most recent commit on this branch"
msgstr ""
+msgid "Launch a ready-to-code development environment for your project."
+msgstr ""
+
msgid "Lead"
msgstr ""
@@ -14713,6 +15240,9 @@ msgstr "Lister les dépôts disponibles"
msgid "List of all merge commits"
msgstr ""
+msgid "List options"
+msgstr ""
+
msgid "List settings"
msgstr ""
@@ -14725,9 +15255,6 @@ msgstr "Vue en liste"
msgid "List your Bitbucket Server repositories"
msgstr "Lister vos dépôts BitBucket Server"
-msgid "Lists"
-msgstr ""
-
msgid "Live preview"
msgstr "Prévisualisation"
@@ -14974,6 +15501,12 @@ msgstr ""
msgid "Mark as done"
msgstr ""
+msgid "Mark as draft"
+msgstr ""
+
+msgid "Mark as ready"
+msgstr ""
+
msgid "Mark as resolved"
msgstr ""
@@ -14995,6 +15528,24 @@ msgstr "Markdown activé"
msgid "Markdown is supported"
msgstr ""
+msgid "MarkdownEditor|Add a link (%{modifierKey}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add a link (%{modifier_key}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifierKey}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifier_key}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifierKey}I)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifier_key}I)"
+msgstr ""
+
msgid "Marked For Deletion At - %{deletion_time}"
msgstr ""
@@ -15079,7 +15630,25 @@ msgstr ""
msgid "Max access level"
msgstr "Niveau d’accès maximum"
-msgid "Max seats used"
+msgid "Max role"
+msgstr ""
+
+msgid "Max size 15 MB"
+msgstr ""
+
+msgid "Maximum Conan package file size in bytes"
+msgstr ""
+
+msgid "Maximum Maven package file size in bytes"
+msgstr ""
+
+msgid "Maximum NPM package file size in bytes"
+msgstr ""
+
+msgid "Maximum NuGet package file size in bytes"
+msgstr ""
+
+msgid "Maximum PyPI package file size in bytes"
msgstr ""
msgid "Maximum Users:"
@@ -15211,6 +15780,18 @@ msgstr ""
msgid "Members with access to %{strong_start}%{group_name}%{strong_end}"
msgstr ""
+msgid "Members|%{time} by %{user}"
+msgstr ""
+
+msgid "Members|Expired"
+msgstr ""
+
+msgid "Members|No expiration set"
+msgstr ""
+
+msgid "Members|in %{time}"
+msgstr ""
+
msgid "Memory Usage"
msgstr ""
@@ -15397,9 +15978,6 @@ msgstr ""
msgid "MergeRequests|Thread will be unresolved"
msgstr ""
-msgid "MergeRequests|Toggle comments for this file"
-msgstr "Activer/désactiver les commentaires pour ce fichier"
-
msgid "MergeRequests|View file @ %{commitId}"
msgstr "Afficher le fichier au commit %{commitId}"
@@ -15460,6 +16038,9 @@ msgstr ""
msgid "Merging immediately isn't recommended as it may negatively impact the existing merge train. Read the %{docsLinkStart}documentation%{docsLinkEnd} for more information."
msgstr ""
+msgid "Message"
+msgstr ""
+
msgid "Messages"
msgstr "Messages"
@@ -15845,18 +16426,12 @@ msgid_plural "Milestones"
msgstr[0] ""
msgstr[1] ""
-msgid "Milestone does not support burnup charts"
-msgstr ""
-
msgid "Milestone lists not available with your current license"
msgstr "La liste des jalons n’est pas disponible avec votre licence actuelle"
msgid "Milestone lists show all issues from the selected milestone."
msgstr "Les listes de jalon affichent tous les tickets à partir du jalon sélectionné."
-msgid "Milestone must have a start and due date"
-msgstr ""
-
msgid "MilestoneSidebar|Closed:"
msgstr ""
@@ -16223,6 +16798,9 @@ msgstr "Nom :"
msgid "Namespace"
msgstr ""
+msgid "Namespace ID:"
+msgstr ""
+
msgid "Namespace is empty"
msgstr ""
@@ -16307,6 +16885,9 @@ msgstr ""
msgid "NetworkPolicies|Allow all outbound traffic from %{selector} to %{ruleSelector} on %{ports}"
msgstr ""
+msgid "NetworkPolicies|Are you sure you want to delete this policy? This action cannot be undone."
+msgstr ""
+
msgid "NetworkPolicies|Choose whether to enforce this policy."
msgstr ""
@@ -16316,12 +16897,21 @@ msgstr ""
msgid "NetworkPolicies|Define this policy's location, conditions and actions."
msgstr ""
+msgid "NetworkPolicies|Delete policy"
+msgstr ""
+
+msgid "NetworkPolicies|Delete policy: %{policy}"
+msgstr ""
+
msgid "NetworkPolicies|Deny all traffic"
msgstr ""
msgid "NetworkPolicies|Description"
msgstr ""
+msgid "NetworkPolicies|Edit policy"
+msgstr ""
+
msgid "NetworkPolicies|Editor mode"
msgstr ""
@@ -16349,6 +16939,9 @@ msgstr ""
msgid "NetworkPolicies|Name"
msgstr ""
+msgid "NetworkPolicies|Namespace"
+msgstr ""
+
msgid "NetworkPolicies|Network Policy"
msgstr ""
@@ -16400,6 +16993,9 @@ msgstr ""
msgid "NetworkPolicies|Rules"
msgstr ""
+msgid "NetworkPolicies|Save changes"
+msgstr ""
+
msgid "NetworkPolicies|Something went wrong, failed to update policy"
msgstr ""
@@ -16412,6 +17008,9 @@ msgstr ""
msgid "NetworkPolicies|Traffic that does not match any rule will be blocked."
msgstr ""
+msgid "NetworkPolicies|Unable to parse policy"
+msgstr ""
+
msgid "NetworkPolicies|YAML editor"
msgstr ""
@@ -16525,6 +17124,9 @@ msgstr ""
msgid "New Snippet"
msgstr "Nouvel extrait de code"
+msgid "New Test Case"
+msgstr ""
+
msgid "New User"
msgstr ""
@@ -16624,6 +17226,9 @@ msgstr "Nouveau sousâ€groupe"
msgid "New tag"
msgstr "Nouvelle étiquette"
+msgid "New test case"
+msgstr ""
+
msgid "New users set to external"
msgstr ""
@@ -16696,7 +17301,7 @@ msgstr "Aucune branche trouvée"
msgid "No changes"
msgstr "Aucun changement"
-msgid "No changes between %{ref_start}%{source_branch}%{ref_end} and %{ref_start}%{target_branch}%{ref_end}"
+msgid "No changes between %{sourceBranch} and %{targetBranch}"
msgstr ""
msgid "No child epics match applied filters"
@@ -16711,6 +17316,9 @@ msgstr "Aucune connexion n’a pu être établie avec un serveur Gitaly, veuille
msgid "No containers available"
msgstr ""
+msgid "No content to show"
+msgstr ""
+
msgid "No contributions"
msgstr ""
@@ -16786,9 +17394,6 @@ msgstr "Aucune étiquette avec un tel nom ou une telle description"
msgid "No license. All rights reserved"
msgstr "Aucune licence. Tous droits réservés"
-msgid "No licenses found."
-msgstr ""
-
msgid "No matches found"
msgstr ""
@@ -16801,6 +17406,9 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No members found"
+msgstr ""
+
msgid "No merge requests found"
msgstr "Aucune demande de fusion trouvée"
@@ -16822,6 +17430,9 @@ msgstr ""
msgid "No parent group"
msgstr ""
+msgid "No plan"
+msgstr ""
+
msgid "No pods available"
msgstr ""
@@ -16918,6 +17529,12 @@ msgstr "Aucun·e"
msgid "Not Implemented"
msgstr ""
+msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+msgstr ""
+
+msgid "Not all browsers support WebAuthn. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even from an unsupported browser."
+msgstr ""
+
msgid "Not all data has been processed yet, the accuracy of the chart for the selected timeframe is limited."
msgstr ""
@@ -17014,6 +17631,9 @@ msgstr ""
msgid "Notification settings saved"
msgstr ""
+msgid "NotificationEvent|Change reviewer merge request"
+msgstr ""
+
msgid "NotificationEvent|Close issue"
msgstr "Clore le ticket"
@@ -17176,10 +17796,7 @@ msgstr ""
msgid "On track"
msgstr ""
-msgid "OnDemandScans|Attached branch"
-msgstr ""
-
-msgid "OnDemandScans|Attached branch is where the scan job runs."
+msgid "OnDemandScans|Could not fetch scanner profiles. Please refresh the page, or try again later."
msgstr ""
msgid "OnDemandScans|Could not fetch site profiles. Please refresh the page, or try again later."
@@ -17188,6 +17805,9 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
+msgid "OnDemandScans|Create a new scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Create a new site profile"
msgstr ""
@@ -17200,6 +17820,9 @@ msgstr ""
msgid "OnDemandScans|New on-demand DAST scan"
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 ""
@@ -17209,16 +17832,10 @@ msgstr ""
msgid "OnDemandScans|On-demand scans run outside the DevOps cycle and find vulnerabilities in your projects. %{learnMoreLinkStart}Learn more%{learnMoreLinkEnd}"
msgstr ""
-msgid "OnDemandScans|Only a passive scan can be performed on demand."
-msgstr ""
-
-msgid "OnDemandScans|Passive"
-msgstr ""
-
msgid "OnDemandScans|Run scan"
msgstr ""
-msgid "OnDemandScans|Scan mode"
+msgid "OnDemandScans|Scanner profile"
msgstr ""
msgid "OnDemandScans|Scanner settings"
@@ -17230,9 +17847,15 @@ msgstr ""
msgid "OnDemandScans|Select one of the existing profiles"
msgstr ""
+msgid "OnDemandScans|Site profile"
+msgstr ""
+
msgid "OnDemandScans|Site profiles"
msgstr ""
+msgid "OnDemandScans|Use existing scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Use existing site profile"
msgstr ""
@@ -17331,9 +17954,6 @@ msgstr "Ouvrir"
msgid "Open Selection"
msgstr ""
-msgid "Open Web IDE"
-msgstr ""
-
msgid "Open comment type dropdown"
msgstr ""
@@ -17439,6 +18059,9 @@ msgstr "Ou vous pouvez choisir l’une des couleurs suggérées ciâ€dessous"
msgid "Origin"
msgstr ""
+msgid "Orphaned member"
+msgstr ""
+
msgid "Other Labels"
msgstr "Autres étiquettes"
@@ -17454,6 +18077,9 @@ msgstr ""
msgid "Other visibility settings have been disabled by the administrator."
msgstr ""
+msgid "Our documentation includes an example DevOps Score report."
+msgstr ""
+
msgid "Out-of-compliance with this project's policies and should be removed"
msgstr ""
@@ -17478,6 +18104,9 @@ msgstr "Vue d’ensemble"
msgid "Overwrite diverged branches"
msgstr "Écraser les branches divergentes"
+msgid "Owned by %{image_tag}"
+msgstr ""
+
msgid "Owned by anyone"
msgstr ""
@@ -17499,6 +18128,9 @@ msgstr ""
msgid "Package deleted successfully"
msgstr ""
+msgid "Package file size limits"
+msgstr ""
+
msgid "Package recipe already exists"
msgstr ""
@@ -17514,9 +18146,6 @@ msgstr ""
msgid "Package type must be PyPi"
msgstr ""
-msgid "Package was removed"
-msgstr "Le paquet a été supprimé"
-
msgid "PackageRegistry|%{name} version %{version} was created %{datetime}"
msgstr ""
@@ -17658,12 +18287,18 @@ msgstr ""
msgid "PackageRegistry|NuGet Command"
msgstr ""
+msgid "PackageRegistry|Package Registry"
+msgstr ""
+
msgid "PackageRegistry|Pip Command"
msgstr ""
msgid "PackageRegistry|Pipeline %{link} triggered %{datetime} by %{author}"
msgstr ""
+msgid "PackageRegistry|Publish and share packages for a variety of common package managers. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "PackageRegistry|Published to the %{project} Package Registry %{datetime}"
msgstr ""
@@ -17763,6 +18398,9 @@ msgstr ""
msgid "Page not found"
msgstr ""
+msgid "Page settings"
+msgstr ""
+
msgid "Page was successfully deleted"
msgstr ""
@@ -17904,7 +18542,7 @@ msgstr ""
msgid "Paste issue link"
msgstr ""
-msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Don't use your private SSH key."
+msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Do not paste your private SSH key, as that can compromise your identity."
msgstr ""
msgid "Patch to apply"
@@ -17931,6 +18569,9 @@ msgstr "Les exécuteurs en pause n’acceptent pas de nouvelles tâches"
msgid "Pending"
msgstr "En attente"
+msgid "Pending comments"
+msgstr ""
+
msgid "People without permission will never get a notification and won't be able to comment."
msgstr "Les personnes sans autorisation ne recevront jamais de notifications et ne pourront pas commenter."
@@ -18129,6 +18770,9 @@ msgstr ""
msgid "Pipelines|Build with confidence"
msgstr "Construire en toute confiance"
+msgid "Pipelines|By revoking a trigger you will break any processes making use of it. Are you sure?"
+msgstr ""
+
msgid "Pipelines|CI Lint"
msgstr "CI Lint"
@@ -18141,6 +18785,15 @@ msgstr "Vider les caches des exécuteurs"
msgid "Pipelines|Continuous Integration can help catch bugs by running your tests automatically, while Continuous Deployment can help you deliver code to your product environment."
msgstr "L’intégration continue peut aider à détecter les bogues en exécutant vos tests automatiquement, tandis que la livraison continue peut vous aider à déployer du code dans votre environnement de production."
+msgid "Pipelines|Copy trigger token"
+msgstr ""
+
+msgid "Pipelines|Description"
+msgstr ""
+
+msgid "Pipelines|Edit"
+msgstr ""
+
msgid "Pipelines|Get started with Pipelines"
msgstr "Premiers pas avec les pipelines"
@@ -18156,15 +18809,27 @@ msgstr ""
msgid "Pipelines|It is recommended the code is reviewed thoroughly before running this pipeline with the parent project's CI resource."
msgstr ""
+msgid "Pipelines|Last Used"
+msgstr ""
+
msgid "Pipelines|Loading Pipelines"
msgstr "Chargement des pipelines"
msgid "Pipelines|More Information"
msgstr ""
+msgid "Pipelines|No triggers have been created yet. Add one using the form above."
+msgstr ""
+
+msgid "Pipelines|Owner"
+msgstr ""
+
msgid "Pipelines|Project cache successfully reset."
msgstr "Réinitialisation du cache de projet réussie."
+msgid "Pipelines|Revoke"
+msgstr ""
+
msgid "Pipelines|Run Pipeline"
msgstr "Exécuter un pipeline"
@@ -18189,6 +18854,15 @@ msgstr ""
msgid "Pipelines|This project is not currently set up to run pipelines."
msgstr "Ce projet n’est actuellement pas configuré pour exécuter des pipelines."
+msgid "Pipelines|Token"
+msgstr ""
+
+msgid "Pipelines|Trigger user has insufficient permissions to project"
+msgstr ""
+
+msgid "Pipelines|invalid"
+msgstr ""
+
msgid "Pipelines|parent"
msgstr ""
@@ -18447,10 +19121,10 @@ msgstr ""
msgid "Please provide attributes to update"
msgstr ""
-msgid "Please refer to %{docs_url}"
+msgid "Please reach out if you have any questions and we'll be happy to assist."
msgstr ""
-msgid "Please retype the email address."
+msgid "Please refer to %{docs_url}"
msgstr ""
msgid "Please select"
@@ -18480,6 +19154,9 @@ msgstr "Veuillez sélectionner au moins un filtre pour voir les résultats"
msgid "Please set a new password before proceeding."
msgstr ""
+msgid "Please share your feedback about %{featureName} %{linkStart}in this issue%{linkEnd} to help us improve the experience."
+msgstr ""
+
msgid "Please solve the reCAPTCHA"
msgstr "Veuillez résoudre le reCAPTCHA"
@@ -18783,6 +19460,9 @@ msgstr "Vous êtes sur le point de supprimer définitivement %{yourAccount}, ain
msgid "Profiles| You are going to change the username %{currentUsernameBold} to %{newUsernameBold}. Profile and projects will be redirected to the %{newUsername} namespace but this redirect will expire once the %{currentUsername} namespace is registered by another user or group. Please update your Git repository remotes as soon as possible."
msgstr "Vous êtes sur le point de changer le nom d’utilisateur %{currentUsernameBold} en %{newUsernameBold}. Le profil et les projets seront redirigés vers l’espace de noms %{newUsername}, mais cette redirection expire si un nouvel utilisateur ou un nouveau groupe est créé avec l’ancien nom %{currentUsername}. Veuillez mettre à jour vos dépôts Git dès que possible."
+msgid "Profiles|%{provider} Active"
+msgstr ""
+
msgid "Profiles|@username"
msgstr ""
@@ -18834,7 +19514,7 @@ msgstr ""
msgid "Profiles|Commit email"
msgstr ""
-msgid "Profiles|Connect"
+msgid "Profiles|Connect %{provider}"
msgstr ""
msgid "Profiles|Connected Accounts"
@@ -18858,6 +19538,9 @@ msgstr "Supprimer un compte aura les conséquences suivantes :"
msgid "Profiles|Disconnect"
msgstr ""
+msgid "Profiles|Disconnect %{provider}"
+msgstr ""
+
msgid "Profiles|Do not show on profile"
msgstr "Ne pas montrer sur le profil"
@@ -18882,7 +19565,7 @@ msgstr ""
msgid "Profiles|Full name"
msgstr ""
-msgid "Profiles|Give your individual key a title. This will be publically visible."
+msgid "Profiles|Give your individual key a title."
msgstr ""
msgid "Profiles|Include private contributions on my profile"
@@ -18972,8 +19655,8 @@ msgstr ""
msgid "Profiles|The maximum file size allowed is 200KB."
msgstr "La taille de fichier maximale autorisée est de 200 Kio."
-msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it?"
-msgstr "Ceci ne ressemble pas à une clef SSH publique, êtesâ€vous sûr(e) de vouloir l’ajouter ?"
+msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it? It will be publicly visible."
+msgstr ""
msgid "Profiles|This email will be displayed on your public profile"
msgstr ""
@@ -19047,6 +19730,9 @@ msgstr "Vous pouvez téléverser votre avatar ici ou le changer en %{gravatar_li
msgid "Profiles|You don't have access to delete this user."
msgstr "Vous n’avez pas les autorisations suffisantes pour supprimer cet utilisateur ou cette utilisatrice."
+msgid "Profiles|You must transfer ownership or delete groups you are an owner of before you can delete your account"
+msgstr ""
+
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr "Vous devez transférer la propriété ou supprimer ces groupes avant de pouvoir supprimer votre compte."
@@ -19635,6 +20321,9 @@ msgstr ""
msgid "ProjectTemplates|GitLab Cluster Management"
msgstr ""
+msgid "ProjectTemplates|Gitpod/Spring Petclinic"
+msgstr ""
+
msgid "ProjectTemplates|Go Micro"
msgstr ""
@@ -20244,6 +20933,9 @@ msgstr ""
msgid "Publish to status page"
msgstr ""
+msgid "Published"
+msgstr ""
+
msgid "Published on status page"
msgstr ""
@@ -20361,9 +21053,15 @@ msgstr "Les actions rapides peuvent être utilisées dans la description des tic
msgid "Quick range"
msgstr ""
+msgid "Quickly and easily edit multiple files in your project."
+msgstr ""
+
msgid "README"
msgstr ""
+msgid "Rails"
+msgstr ""
+
msgid "Rake Tasks Help"
msgstr ""
@@ -20483,10 +21181,13 @@ msgstr "Inscription / Connexion"
msgid "Register Two-Factor Authenticator"
msgstr ""
-msgid "Register U2F device"
+msgid "Register Universal Two-Factor (U2F) Device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register WebAuthn Device"
+msgstr ""
+
+msgid "Register device"
msgstr ""
msgid "Register for GitLab"
@@ -20498,9 +21199,6 @@ msgstr ""
msgid "Register with two-factor app"
msgstr ""
-msgid "Registration"
-msgstr ""
-
msgid "Registration|Checkout"
msgstr ""
@@ -20617,9 +21315,6 @@ msgstr ""
msgid "Release|Something went wrong while saving the release details"
msgstr ""
-msgid "Remediated: needs review"
-msgstr ""
-
msgid "Remediations"
msgstr ""
@@ -20725,6 +21420,9 @@ msgstr ""
msgid "Remove priority"
msgstr "Supprimer la priorité"
+msgid "Remove report"
+msgstr ""
+
msgid "Remove secondary node"
msgstr ""
@@ -20737,6 +21435,12 @@ msgstr ""
msgid "Remove time estimate"
msgstr ""
+msgid "Remove user & report"
+msgstr ""
+
+msgid "Remove user from group"
+msgstr ""
+
msgid "Removed"
msgstr ""
@@ -20818,9 +21522,6 @@ msgstr ""
msgid "Removes time estimate."
msgstr ""
-msgid "Removing license…"
-msgstr ""
-
msgid "Removing this group also removes all child projects, including archived projects, and their resources."
msgstr ""
@@ -20905,6 +21606,9 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
+msgid "Reported by %{reporter}"
+msgstr ""
+
msgid "Reporting"
msgstr "Rapports"
@@ -20991,6 +21695,27 @@ msgstr "aucun résultat de test modifié"
msgid "Repositories"
msgstr ""
+msgid "Repositories Analytics"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download Historic Test Coverage Data"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download historic test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Historic Test Coverage Data is available in raw format (.csv) for further analysis."
+msgstr ""
+
+msgid "RepositoriesAnalytics|Test Code Coverage"
+msgstr ""
+
+msgid "RepositoriesAnalytics|There was an error fetching the projects."
+msgstr ""
+
msgid "Repository"
msgstr "Dépôt"
@@ -21069,9 +21794,15 @@ msgstr ""
msgid "Request parameter %{param} is missing."
msgstr ""
+msgid "Request review from"
+msgstr ""
+
msgid "Request to link SAML account must be authorized"
msgstr ""
+msgid "Requested"
+msgstr ""
+
msgid "Requested %{time_ago}"
msgstr ""
@@ -21090,6 +21821,9 @@ msgstr "Profils de requêtes"
msgid "Requests to these domain(s)/address(es) on the local network will be allowed when local requests from hooks and services are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 or 127.0.0.0/28 are supported. Domain wildcards are not supported currently. Use comma, semicolon, or newline to separate multiple entries. The allowlist can hold a maximum of 1000 entries. Domains should use IDNA encoding. Ex: example.com, 192.168.1.1, 127.0.0.0/28, xn--itlab-j1a.com."
msgstr ""
+msgid "Require admin approval for new sign-ups"
+msgstr ""
+
msgid "Require all users in this group to setup Two-factor authentication"
msgstr "Exiger de tous les utilisateurs de ce groupe la configuration de l’authentification à double facteur"
@@ -21217,9 +21951,6 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
-msgid "Resolved by %{resolvedByName}"
-msgstr ""
-
msgid "Resolves IP addresses once and uses them to submit requests"
msgstr ""
@@ -21339,6 +22070,14 @@ msgstr ""
msgid "ReviewApp|Enable Review App"
msgstr ""
+msgid "Reviewer"
+msgid_plural "%d Reviewers"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Reviewer(s)"
+msgstr ""
+
msgid "Reviewing"
msgstr "Examen"
@@ -21378,6 +22117,9 @@ msgstr ""
msgid "Rook"
msgstr ""
+msgid "Ruby"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -21456,6 +22198,63 @@ msgstr "Exécuteurs actuellement en ligne : %{active_runners_count}"
msgid "Runners page."
msgstr "Page des exécuteurs."
+msgid "Runners|Active"
+msgstr ""
+
+msgid "Runners|Architecture"
+msgstr ""
+
+msgid "Runners|Can run untagged jobs"
+msgstr ""
+
+msgid "Runners|Description"
+msgstr ""
+
+msgid "Runners|Group"
+msgstr ""
+
+msgid "Runners|IP Address"
+msgstr ""
+
+msgid "Runners|Last contact"
+msgstr ""
+
+msgid "Runners|Locked to this project"
+msgstr ""
+
+msgid "Runners|Maximum job timeout"
+msgstr ""
+
+msgid "Runners|Name"
+msgstr ""
+
+msgid "Runners|Platform"
+msgstr ""
+
+msgid "Runners|Property Name"
+msgstr ""
+
+msgid "Runners|Protected"
+msgstr ""
+
+msgid "Runners|Revision"
+msgstr ""
+
+msgid "Runners|Shared"
+msgstr ""
+
+msgid "Runners|Specific"
+msgstr ""
+
+msgid "Runners|Tags"
+msgstr ""
+
+msgid "Runners|Value"
+msgstr ""
+
+msgid "Runners|Version"
+msgstr ""
+
msgid "Runners|You have used %{quotaUsed} out of %{quotaLimit} of your shared Runners pipeline minutes."
msgstr ""
@@ -21468,6 +22267,9 @@ msgstr ""
msgid "Runs a number of housekeeping tasks within the current repository, such as compressing file revisions and removing unreachable objects."
msgstr ""
+msgid "SAML"
+msgstr ""
+
msgid "SAML SSO"
msgstr "Authentification unique SAML"
@@ -21519,6 +22321,9 @@ msgstr ""
msgid "Save"
msgstr "Enregistrer"
+msgid "Save %{name} size limits"
+msgstr ""
+
msgid "Save Changes"
msgstr ""
@@ -21549,9 +22354,6 @@ msgstr "Sauvegarder la planification du pipeline"
msgid "Save space and find tags in the Container Registry more easily. Enable the cleanup policy to remove stale tags and keep only the ones you need."
msgstr ""
-msgid "Save template"
-msgstr ""
-
msgid "Save variables"
msgstr "Enregistrer les variables"
@@ -21594,9 +22396,6 @@ msgstr "Planification des pipelines"
msgid "Scope"
msgstr "Portée"
-msgid "Scope not supported with disabled 'users_search' feature!"
-msgstr ""
-
msgid "Scoped issue boards"
msgstr "Tableaux de tickets à portée limitée"
@@ -21723,9 +22522,6 @@ msgstr ""
msgid "Search requirements"
msgstr ""
-msgid "Search results…"
-msgstr ""
-
msgid "Search users"
msgstr "Rechercher des utilisateurs et utilisatrices"
@@ -21798,6 +22594,11 @@ msgid_plural "SearchResults|commits"
msgstr[0] ""
msgstr[1] ""
+msgid "SearchResults|epic"
+msgid_plural "SearchResults|epics"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "SearchResults|issue"
msgid_plural "SearchResults|issues"
msgstr[0] ""
@@ -21842,10 +22643,10 @@ msgstr ""
msgid "Seat Link is disabled, and cannot be configured through this form."
msgstr ""
-msgid "Seats currently in use"
+msgid "Seats usage data as of %{last_enqueue_time}"
msgstr ""
-msgid "Seats in license"
+msgid "Seats usage data is updated every day at 12:00pm UTC"
msgstr ""
msgid "Secondary"
@@ -21899,6 +22700,9 @@ msgstr ""
msgid "SecurityConfiguration|Available for on-demand DAST"
msgstr ""
+msgid "SecurityConfiguration|By default, all analyzers are applied in order to cover all languages across your project, and only run if the language is detected in the Merge Request."
+msgstr ""
+
msgid "SecurityConfiguration|Configure"
msgstr ""
@@ -21929,16 +22733,19 @@ msgstr ""
msgid "SecurityConfiguration|Manage"
msgstr ""
+msgid "SecurityConfiguration|More information"
+msgstr ""
+
msgid "SecurityConfiguration|Not enabled"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|Security Control"
+msgid "SecurityConfiguration|SAST Configuration"
msgstr ""
-msgid "SecurityConfiguration|See documentation"
+msgid "SecurityConfiguration|Security Control"
msgstr ""
msgid "SecurityConfiguration|Status"
@@ -21950,6 +22757,9 @@ msgstr ""
msgid "SecurityConfiguration|Using custom settings. You won't receive automatic updates on this variable. %{anchorStart}Restore to default%{anchorEnd}"
msgstr ""
+msgid "SecurityConfiguration|View history"
+msgstr ""
+
msgid "SecurityConfiguration|You can quickly enable all security scanning tools by enabling %{linkStart}Auto DevOps%{linkEnd}."
msgstr ""
@@ -22028,9 +22838,6 @@ msgstr ""
msgid "SecurityReports|Learn more about setting up your dashboard"
msgstr ""
-msgid "SecurityReports|Load more vulnerabilities"
-msgstr ""
-
msgid "SecurityReports|Monitor vulnerabilities in your code"
msgstr ""
@@ -22310,7 +23117,7 @@ msgstr ""
msgid "Select status"
msgstr ""
-msgid "Select strategy activation method"
+msgid "Select strategy activation method."
msgstr ""
msgid "Select subscription"
@@ -22325,7 +23132,7 @@ msgstr "Sélectionnez la branche que vous souhaitez définir comme branche par d
msgid "Select the custom project template source group."
msgstr "Sélectionnez le groupe source de modèles de projet personnalisés."
-msgid "Select timeframe"
+msgid "Select the environment scope for this feature flag."
msgstr ""
msgid "Select timezone"
@@ -22574,6 +23381,9 @@ msgstr "Définir un dépôt de modèles au niveau de l’instance"
msgid "Set iteration"
msgstr ""
+msgid "Set limit to 0 to allow any file size."
+msgstr ""
+
msgid "Set max session time for web terminal."
msgstr "Définissez le temps maximal de la session pour le terminal Web."
@@ -22652,10 +23462,13 @@ msgstr ""
msgid "Set up a %{type} Runner manually"
msgstr "Configurer manuellement un exécuteur %{type}"
+msgid "Set up a hardware device as a second factor to sign in."
+msgstr ""
+
msgid "Set up assertions/attributes/claims (email, first_name, last_name) and NameID according to %{docsLinkStart}the documentation %{icon}%{docsLinkEnd}"
msgstr "Configure les assertions, attributs et revendications (courriel, prénom et nom), ainsi que le NameID, conformément à %{docsLinkStart}la documentation %{icon}%{docsLinkEnd}"
-msgid "Set up new U2F device"
+msgid "Set up new device"
msgstr ""
msgid "Set up new password"
@@ -22724,6 +23537,9 @@ msgstr ""
msgid "Sets weight to %{weight}."
msgstr ""
+msgid "Setting this to 0 means using the system default timeout value."
+msgstr ""
+
msgid "Settings"
msgstr "Paramètres"
@@ -22739,6 +23555,15 @@ msgstr ""
msgid "Severity"
msgstr ""
+msgid "SeverityWidget|Severity"
+msgstr ""
+
+msgid "SeverityWidget|Severity: %{severity}"
+msgstr ""
+
+msgid "SeverityWidget|There was an error while updating severity."
+msgstr ""
+
msgid "Shards (%{shards})"
msgstr ""
@@ -22784,6 +23609,9 @@ msgstr ""
msgid "Show all requirements."
msgstr ""
+msgid "Show all test cases."
+msgstr ""
+
msgid "Show archived projects"
msgstr ""
@@ -22796,6 +23624,9 @@ msgstr "Afficher la commande"
msgid "Show comments"
msgstr ""
+msgid "Show comments on this file"
+msgstr ""
+
msgid "Show comments only"
msgstr ""
@@ -22841,6 +23672,12 @@ msgstr "Afficher les pages parentes"
msgid "Show parent subgroups"
msgstr "Afficher les sousâ€groupes parents"
+msgid "Show the Closed list"
+msgstr ""
+
+msgid "Show the Open list"
+msgstr ""
+
msgid "Show whitespace changes"
msgstr "Afficher les modifications des espaces"
@@ -22884,9 +23721,6 @@ msgstr "côte à côte"
msgid "Sidebar|Assign health status"
msgstr ""
-msgid "Sidebar|Change weight"
-msgstr "Changer le poids"
-
msgid "Sidebar|Health status"
msgstr ""
@@ -23070,6 +23904,9 @@ msgstr ""
msgid "Snippets|Add another file %{num}/%{total}"
msgstr ""
+msgid "Snippets|Authored %{time_ago} by %{author}"
+msgstr ""
+
msgid "Snippets|Delete file"
msgstr ""
@@ -23097,6 +23934,9 @@ msgstr ""
msgid "Solution"
msgstr ""
+msgid "Some changes are not shown"
+msgstr ""
+
msgid "Some child epics may be hidden due to applied filters"
msgstr ""
@@ -23463,6 +24303,12 @@ msgstr "Source"
msgid "Source (branch or tag)"
msgstr "Source (branche ou étiquette)"
+msgid "Source Branch"
+msgstr ""
+
+msgid "Source branch: %{source_branch_open}%{source_branch}%{source_branch_close}"
+msgstr ""
+
msgid "Source code"
msgstr "Code source"
@@ -23628,9 +24474,6 @@ msgstr "Démarrer une revue de code"
msgid "Start and due date"
msgstr "Dates de début et d’échéance"
-msgid "Start by choosing a group to see how your team is spending time. You can then drill down to the project level."
-msgstr ""
-
msgid "Start by choosing a group to start exploring the merge requests in that group. You can then proceed to filter by projects, labels, milestones and authors."
msgstr ""
@@ -23712,18 +24555,27 @@ msgstr ""
msgid "StaticSiteEditor|3. Assign a person to review and accept the merge request."
msgstr ""
+msgid "StaticSiteEditor|A link to view the merge request will appear once ready."
+msgstr ""
+
msgid "StaticSiteEditor|An error occurred while submitting your changes."
msgstr ""
msgid "StaticSiteEditor|Branch could not be created."
msgstr ""
+msgid "StaticSiteEditor|Copy update"
+msgstr ""
+
msgid "StaticSiteEditor|Could not commit the content changes."
msgstr ""
msgid "StaticSiteEditor|Could not create merge request."
msgstr ""
+msgid "StaticSiteEditor|Creating your merge request"
+msgstr ""
+
msgid "StaticSiteEditor|Incompatible file content"
msgstr ""
@@ -23745,6 +24597,9 @@ msgstr ""
msgid "StaticSiteEditor|View documentation"
msgstr ""
+msgid "StaticSiteEditor|You can set an assignee to get your changes reviewed and deployed once your merge request is created."
+msgstr ""
+
msgid "StaticSiteEditor|Your merge request has been created"
msgstr ""
@@ -23874,15 +24729,15 @@ msgstr ""
msgid "Submit %{humanized_resource_name}"
msgstr ""
-msgid "Submit Changes"
-msgstr ""
-
msgid "Submit a review"
msgstr ""
msgid "Submit as spam"
msgstr "Soumettre comme indésirable"
+msgid "Submit changes"
+msgstr ""
+
msgid "Submit feedback"
msgstr ""
@@ -24036,6 +24891,9 @@ msgstr ""
msgid "Successfully deleted U2F device."
msgstr ""
+msgid "Successfully deleted WebAuthn device."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -24354,9 +25212,6 @@ msgstr "Modèle"
msgid "Template to append to all Service Desk issues"
msgstr ""
-msgid "Template was successfully saved."
-msgstr ""
-
msgid "Templates"
msgstr "Modèles "
@@ -24435,10 +25290,28 @@ msgid_plural "Test coverage: %d hits"
msgstr[0] ""
msgstr[1] ""
-msgid "Test failed."
+msgid "Test settings"
msgstr ""
-msgid "Test settings and save changes"
+msgid "TestCases|New Test Case"
+msgstr ""
+
+msgid "TestCases|New test case"
+msgstr ""
+
+msgid "TestCases|Search test cases"
+msgstr ""
+
+msgid "TestCases|Something went wrong while creating a test case."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching count of test cases."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching test cases list."
+msgstr ""
+
+msgid "TestCases|Submit test case"
msgstr ""
msgid "TestHooks|Ensure one of your projects has merge requests."
@@ -24504,6 +25377,9 @@ msgstr ""
msgid "Thank you for signing up for your free trial! You will get additional instructions in your inbox shortly."
msgstr ""
+msgid "Thank you for your business."
+msgstr ""
+
msgid "Thank you for your feedback!"
msgstr ""
@@ -24563,9 +25439,6 @@ msgstr ""
msgid "The URL to use for connecting to Elasticsearch. Use a comma-separated list to support clustering (e.g., \"http://localhost:9200, http://localhost:9201\")."
msgstr ""
-msgid "The Web IDE offers advanced syntax highlighting capabilities and more."
-msgstr ""
-
msgid "The X509 Certificate to use when mutual TLS is required to communicate with the external authorization service. If left blank, the server certificate is still validated when accessing over HTTPS."
msgstr "Le certificat X.509 à utiliser lorsque l’authentification TLS mutuelle est requise pour communiquer avec le service d’autorisation externe. Si ce champ est vide, le certificat du serveur est tout de même validé lors de l’accès via HTTPS."
@@ -24676,6 +25549,9 @@ msgstr "La relation de divergence a été supprimée."
msgid "The form contains the following error:"
msgstr ""
+msgid "The form contains the following warning:"
+msgstr ""
+
msgid "The global settings require you to enable Two-Factor Authentication for your account."
msgstr ""
@@ -24790,9 +25666,6 @@ msgstr "L’étape de planification montre le temps entre l’étape précédent
msgid "The private key to use when a client certificate is provided. This value is encrypted at rest."
msgstr "La clef privée à utiliser lorsqu’un certificat client est fourni. Cette valeur est chiffrée au repos."
-msgid "The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr "L’étape de mise en production montre le temps nécessaire entre la création d’un ticket et le déploiement du code en production. Les données seront automatiquement ajoutées une fois que vous aurez complété le cycle complet, depuis l’idée jusqu’à la mise en production."
-
msgid "The project can be accessed by any logged in user."
msgstr "Votre projet est accessible à tous les utilisateur et utilisatrices authentifiés."
@@ -24829,7 +25702,7 @@ msgstr ""
msgid "The remote repository is being updated..."
msgstr ""
-msgid "The repository can be commited to, and issues, comments and other entities can be created."
+msgid "The repository can be committed to, and issues, comments and other entities can be created."
msgstr ""
msgid "The repository for this project does not exist."
@@ -24883,9 +25756,6 @@ msgstr "L’étape de test montre le temps que que met l’intégration continue
msgid "The time taken by each data entry gathered by that stage."
msgstr "Le temps pris par chaque entrée récoltée durant cette étape."
-msgid "The total stage shows the time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The update action will time out after %{number_of_minutes} minutes. For big repositories, use a clone/push combination."
msgstr "L’action de mise à jour expirera au bout de %{number_of_minutes} minutes. Pour les gros dépôts, utilisez une combinaison de clone et push."
@@ -24949,6 +25819,9 @@ msgstr "Il n’y a pas encore de projets archivés"
msgid "There are no archived requirements"
msgstr ""
+msgid "There are no archived test cases"
+msgstr ""
+
msgid "There are no changes"
msgstr ""
@@ -24988,6 +25861,9 @@ msgstr ""
msgid "There are no open requirements"
msgstr ""
+msgid "There are no open test cases"
+msgstr ""
+
msgid "There are no packages yet"
msgstr ""
@@ -25000,6 +25876,9 @@ msgstr ""
msgid "There is a limit of %{ci_project_subscriptions_limit} subscriptions from or to a project."
msgstr ""
+msgid "There is already a To-Do for this design."
+msgstr ""
+
msgid "There is already a repository with that name on disk"
msgstr ""
@@ -25018,6 +25897,9 @@ msgstr ""
msgid "There was a problem communicating with your device."
msgstr ""
+msgid "There was a problem fetching branches."
+msgstr ""
+
msgid "There was a problem fetching groups."
msgstr ""
@@ -25246,9 +26128,15 @@ msgstr ""
msgid "This action can lead to data loss. To prevent accidental actions we ask you to confirm your intention."
msgstr ""
+msgid "This action cannot be undone, and will permanently delete the %{key} SSH key"
+msgstr ""
+
msgid "This action cannot be undone. You will lose the project's repository and all content: issues, merge requests, etc."
msgstr ""
+msgid "This action has been performed too many times. Try again later."
+msgstr ""
+
msgid "This action will %{strongOpen}permanently delete%{strongClose} %{codeOpen}%{project}%{codeClose} %{strongOpen}immediately%{strongClose}, including its repositories and all content: issues, merge requests, etc."
msgstr ""
@@ -25276,9 +26164,6 @@ msgstr ""
msgid "This board's scope is reduced"
msgstr "La portée de ce tableau est réduite"
-msgid "This branch has changed since you started editing. Would you like to create a new branch?"
-msgstr "Cette branche a changé depuis que vous y avez apporté des modifications. Souhaitezâ€vous créer une nouvelle branche ?"
-
msgid "This chart could not be displayed"
msgstr ""
@@ -25405,15 +26290,9 @@ msgstr ""
msgid "This is a security log of important events involving your account."
msgstr ""
-msgid "This is the author's first Merge Request to this project."
-msgstr "C’est la première demande de fusion de cet auteur pour ce projet."
-
msgid "This is the highest peak of users on your installation since the license started."
msgstr ""
-msgid "This is the maximum number of users that have existed at the same time since the license started. This is the minimum number of seats you will need to buy when you renew your license."
-msgstr ""
-
msgid "This is the number of currently active users on your installation, and this is the minimum number you need to purchase when you renew your license."
msgstr ""
@@ -25645,6 +26524,15 @@ msgstr ""
msgid "This user has no identities"
msgstr "Cet utilisateur ou cette utilisatrice n’a aucune identité"
+msgid "This user has previously committed to the %{name} project."
+msgstr ""
+
+msgid "This user has the %{access} role in the %{name} project."
+msgstr ""
+
+msgid "This user is the author of this %{noteable}."
+msgstr ""
+
msgid "This user will be the author of all events in the activity feed that are the result of an update, like new branches being created or new commits being pushed to existing branches."
msgstr "Cet utilisateur sera l’auteur de tous les événements du flux d’activité résultant d’une mise à jour, comme la création de nouvelles branches ou les nouveaux commits poussés vers des branches existantes."
@@ -25675,6 +26563,9 @@ msgstr ""
msgid "Threat Monitoring"
msgstr ""
+msgid "ThreatMonitoring|All Environments"
+msgstr ""
+
msgid "ThreatMonitoring|Anomalous Requests"
msgstr ""
@@ -25702,9 +26593,6 @@ msgstr ""
msgid "ThreatMonitoring|Operations Per Second"
msgstr ""
-msgid "ThreatMonitoring|Overview"
-msgstr ""
-
msgid "ThreatMonitoring|Packet Activity"
msgstr ""
@@ -25723,6 +26611,9 @@ msgstr ""
msgid "ThreatMonitoring|Something went wrong, unable to fetch statistics"
msgstr ""
+msgid "ThreatMonitoring|Statistics"
+msgstr ""
+
msgid "ThreatMonitoring|The firewall is not installed or has been disabled. To view this data, ensure the web application firewall is installed and enabled for your cluster."
msgstr ""
@@ -26114,6 +27005,9 @@ msgstr ""
msgid "To update Snippets with multiple files, you must use the `files` parameter"
msgstr ""
+msgid "To use Gitpod you must first enable the feature in the integrations section of your %{user_prefs}."
+msgstr ""
+
msgid "To view all %{scannedResourcesCount} scanned URLs, please download the CSV file"
msgstr ""
@@ -26147,9 +27041,6 @@ msgstr ""
msgid "Toggle Sidebar"
msgstr "Afficher/masquer la barre latérale"
-msgid "Toggle all threads"
-msgstr ""
-
msgid "Toggle backtrace"
msgstr ""
@@ -26174,9 +27065,6 @@ msgstr ""
msgid "Toggle navigation"
msgstr "Activer/désactiver la navigation"
-msgid "Toggle project"
-msgstr ""
-
msgid "Toggle sidebar"
msgstr "Afficher/masquer la barre latérale"
@@ -26216,6 +27104,9 @@ msgstr ""
msgid "Too many projects enabled. You will need to manage them via the console or the API."
msgstr ""
+msgid "Too much data"
+msgstr ""
+
msgid "Topics (optional)"
msgstr ""
@@ -26234,6 +27125,9 @@ msgstr ""
msgid "Total cores (CPUs)"
msgstr ""
+msgid "Total days to completion"
+msgstr ""
+
msgid "Total issues"
msgstr ""
@@ -26330,6 +27224,9 @@ msgstr "Vue arborescente"
msgid "Trending"
msgstr "Tendance"
+msgid "Trials|Create a new group to start your GitLab Gold trial."
+msgstr ""
+
msgid "Trials|Go back to GitLab"
msgstr ""
@@ -26339,6 +27236,15 @@ msgstr ""
msgid "Trials|You can always resume this process by selecting your avatar and choosing 'Start a Gold trial'"
msgstr ""
+msgid "Trials|You can apply your trial to a new group or an existing group."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group or your personal account."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group, an existing group, or your personal account."
+msgstr ""
+
msgid "Trials|You won't get a free trial right now but you can always resume this process by clicking on your avatar and choosing 'Start a free trial'"
msgstr ""
@@ -26408,6 +27314,9 @@ msgstr ""
msgid "Try using a different search term to find the file you are looking for."
msgstr ""
+msgid "Trying to communicate with your device. Plug it in (if needed) and press the button on the device now."
+msgstr ""
+
msgid "Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now."
msgstr ""
@@ -26495,6 +27404,12 @@ msgstr ""
msgid "URL or request ID"
msgstr ""
+msgid "USER %{user} WILL BE REMOVED! Are you sure?"
+msgstr ""
+
+msgid "USER WILL BE BLOCKED! Are you sure?"
+msgstr ""
+
msgid "UTC"
msgstr ""
@@ -26552,9 +27467,6 @@ msgstr "Impossible de charger le diff. %{button_try_again}"
msgid "Unable to load the merge request widget. Try reloading the page."
msgstr ""
-msgid "Unable to resolve"
-msgstr ""
-
msgid "Unable to save iteration. Please try again"
msgstr ""
@@ -26603,6 +27515,9 @@ msgstr ""
msgid "Undo ignore"
msgstr ""
+msgid "Unexpected error"
+msgstr ""
+
msgid "Unfortunately, your email message to GitLab could not be processed."
msgstr ""
@@ -26636,6 +27551,9 @@ msgstr ""
msgid "Unknown response text"
msgstr ""
+msgid "Unless otherwise agreed to in writing with GitLab, by clicking \"Upload License\" you agree that your use of GitLab Software is subject to the %{eula_link_start}Terms of Service%{eula_link_end}."
+msgstr ""
+
msgid "Unlimited"
msgstr ""
@@ -27002,9 +27920,6 @@ msgstr ""
msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
msgstr "Le service d’assistance (Service Desk) permet d’interagir avec vos utilisateurs (p. ex., pour offrir un support client) par courriel depuis GitLab"
-msgid "Use a hardware device to add the second factor of authentication."
-msgstr ""
-
msgid "Use an one time password authenticator on your mobile device or computer to enable two-factor authentication (2FA)."
msgstr ""
@@ -27021,7 +27936,7 @@ msgid "Use one line per URI"
msgstr "Utilisez une ligne par URI"
msgid "Use template"
-msgstr "Utiliser un modèle"
+msgstr "Utiliser ce modèle"
msgid "Use the following registration token during setup:"
msgstr "Utiliser le jeton d’inscription suivant pendant l’installation :"
@@ -27278,13 +28193,13 @@ msgstr ""
msgid "Users"
msgstr "Utilisateurs et utilisatrices"
-msgid "Users in License:"
+msgid "Users in License"
msgstr ""
-msgid "Users or groups set as approvers in the project's or merge request's settings."
+msgid "Users in License:"
msgstr ""
-msgid "Users outside of license"
+msgid "Users or groups set as approvers in the project's or merge request's settings."
msgstr ""
msgid "Users over License:"
@@ -27302,9 +28217,6 @@ msgstr ""
msgid "Users with a Guest role or those who don't belong to a Project or Group will not use a seat from your license."
msgstr ""
-msgid "Users with a Guest role or those who don't belong to any projects or groups don't count towards seats in use."
-msgstr ""
-
msgid "UsersSelect|%{name} + %{length} more"
msgstr ""
@@ -27344,9 +28256,6 @@ msgstr ""
msgid "Validations failed."
msgstr ""
-msgid "Validity"
-msgstr ""
-
msgid "Value"
msgstr ""
@@ -27365,6 +28274,9 @@ msgstr ""
msgid "Value Stream Name"
msgstr ""
+msgid "ValueStreamAnalyticsStage|We don't have enough data to show this stage."
+msgstr ""
+
msgid "ValueStreamAnalytics|%{days}d"
msgstr ""
@@ -27621,6 +28533,9 @@ msgstr ""
msgid "VisualReviewApp|Steps 1 and 2 (and sometimes 3) are performed once by the developer before requesting feedback. Steps 3 (if necessary), 4 is performed by the reviewer each time they perform a review."
msgstr ""
+msgid "Visualization"
+msgstr ""
+
msgid "Vulnerabilities"
msgstr ""
@@ -27648,34 +28563,31 @@ msgstr ""
msgid "VulnerabilityChart|Severity"
msgstr ""
-msgid "VulnerabilityManagement|A true-positive and will fix"
-msgstr ""
-
-msgid "VulnerabilityManagement|Change status"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Confirm"
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|Confirmed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Detected %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|A true-positive and will fix"
msgstr ""
-msgid "VulnerabilityManagement|Dismiss"
+msgid "VulnerabilityManagement|Change status"
msgstr ""
-msgid "VulnerabilityManagement|Dismissed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
msgstr ""
-msgid "VulnerabilityManagement|Resolved"
+msgid "VulnerabilityManagement|Detected"
msgstr ""
-msgid "VulnerabilityManagement|Resolved %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Needs triage"
msgstr ""
msgid "VulnerabilityManagement|Something went wrong while trying to delete the comment. Please try again later."
@@ -27726,6 +28638,9 @@ msgstr ""
msgid "Vulnerability|%{scannerName} (version %{scannerVersion})"
msgstr ""
+msgid "Vulnerability|Activity"
+msgstr ""
+
msgid "Vulnerability|Class"
msgstr "Classe"
@@ -27738,6 +28653,9 @@ msgstr ""
msgid "Vulnerability|Description"
msgstr "Description"
+msgid "Vulnerability|Detected"
+msgstr ""
+
msgid "Vulnerability|Evidence"
msgstr ""
@@ -27801,6 +28719,9 @@ msgstr ""
msgid "Warning: Displaying this diagram might cause performance issues on this page."
msgstr ""
+msgid "We are currently unable to fetch data for the pipeline header."
+msgstr ""
+
msgid "We are currently unable to fetch data for this graph."
msgstr ""
@@ -27840,6 +28761,12 @@ msgstr ""
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 will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
+msgstr ""
+
+msgid "We would like to inform you that your subscription GitLab Enterprise Edition %{plan_name} is nearing its user limit. You have %{active_user_count} active users, which is almost at the user limit of %{maximum_user_count}."
+msgstr ""
+
msgid "We've found no vulnerabilities"
msgstr ""
@@ -27855,6 +28782,12 @@ msgstr ""
msgid "Web terminal"
msgstr "Terminal Web"
+msgid "WebAuthn Devices (%{length})"
+msgstr ""
+
+msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
+msgstr ""
+
msgid "WebIDE|Merge request"
msgstr ""
@@ -27993,15 +28926,9 @@ msgstr ""
msgid "Welcome to the guided GitLab tour"
msgstr ""
-msgid "Welcome to your Issue Board!"
-msgstr ""
-
msgid "Welcome to your issue board!"
msgstr ""
-msgid "We’ve been making changes to %{featureName} and we’d love your feedback %{linkStart}in this issue%{linkEnd} to help us improve the experience."
-msgstr ""
-
msgid "What are you searching for?"
msgstr ""
@@ -28020,6 +28947,9 @@ msgstr ""
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"
+msgid "When enabled, any user visiting %{host} and creating an account will have to be explicitly approved by the admin before they can login. This setting is effective only if sign-ups are enabled."
+msgstr ""
+
msgid "When enabled, any user visiting %{host} will be able to create an account."
msgstr ""
@@ -28244,6 +29174,9 @@ msgstr ""
msgid "With requirements, you can set criteria to check your products against."
msgstr ""
+msgid "With test cases, you can define conditions for your project to meet in determining quality"
+msgstr ""
+
msgid "Withdraw Access Request"
msgstr "Retirer la demande d’accès"
@@ -28259,6 +29192,9 @@ msgstr ""
msgid "Workflow Help"
msgstr ""
+msgid "Would you like to create a new branch?"
+msgstr ""
+
msgid "Write"
msgstr ""
@@ -28280,6 +29216,9 @@ msgstr ""
msgid "Wrong extern UID provided. Make sure Auth0 is configured correctly."
msgstr ""
+msgid "YYYY-MM-DD"
+msgstr ""
+
msgid "Yes"
msgstr "Oui"
@@ -28337,8 +29276,8 @@ msgstr ""
msgid "You are going to remove the fork relationship from %{project_full_name}. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "You are going to transfer %{project_full_name} to another owner. Are you ABSOLUTELY sure?"
-msgstr "Vous allez transférer %{project_full_name} à un nouveau ou une nouvelle propriétaire. Êtesâ€vous VRAIMENT sûr(e) ?"
+msgid "You are going to transfer %{project_full_name} to another namespace. Are you ABSOLUTELY sure?"
+msgstr ""
msgid "You are going to turn off the confidentiality. This means %{strongStart}everyone%{strongEnd} will be able to see and leave a comment on this %{issuableType}."
msgstr ""
@@ -28397,9 +29336,6 @@ msgstr ""
msgid "You can always edit this later"
msgstr ""
-msgid "You can apply your Trial to your Personal account or create a New Group."
-msgstr ""
-
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings"
msgstr ""
@@ -28421,12 +29357,18 @@ msgstr "Vous pouvez facilement installer un Exécuteur sur un cluster Kubernetes
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
+msgid "You can find more information about GitLab subscriptions in %{subscriptions_doc_link}."
+msgstr ""
+
msgid "You can generate an access token scoped to this project for each application to use the GitLab API."
msgstr ""
msgid "You can get started by cloning the repository or start adding files to it with one of the following options."
msgstr ""
+msgid "You can group test cases using labels. To learn about the future direction of this feature, visit %{linkStart}Quality Management direction page%{linkEnd}."
+msgstr ""
+
msgid "You can invite a new member to %{project_name} or invite another group."
msgstr ""
@@ -28442,6 +29384,9 @@ msgstr "Vous pouvez vous déplacer dans le graphique en utilisant les touches fl
msgid "You can notify the app / group or a project by sending them an email notification"
msgstr ""
+msgid "You can now close this window."
+msgstr ""
+
msgid "You can now export your security dashboard to a CSV report."
msgstr ""
@@ -28490,9 +29435,6 @@ msgstr ""
msgid "You can test your .gitlab-ci.yml in %{linkStart}CI Lint%{linkEnd}."
msgstr "Vous pouvez tester votre fichier « .gitlab-ci.yml » avec %{linkStart}CI Lint%{linkEnd}."
-msgid "You can try again using %{begin_link}basic search%{end_link}"
-msgstr ""
-
msgid "You cannot access the raw file. Please wait a minute."
msgstr ""
@@ -28544,6 +29486,9 @@ msgstr "Vous ne disposez pas des autorisations appropriées pour outrepasser les
msgid "You don't have any U2F devices registered yet."
msgstr ""
+msgid "You don't have any WebAuthn devices registered yet."
+msgstr ""
+
msgid "You don't have any active chat names."
msgstr ""
@@ -28631,6 +29576,9 @@ msgstr ""
msgid "You must accept our Terms of Service and privacy policy in order to register an account"
msgstr "Vous devez accepter les conditions générales d’utilisation et la politique de confidentialité afin de pouvoir vous créer un compte"
+msgid "You must be logged in to search across all of GitLab"
+msgstr ""
+
msgid "You must disassociate %{domain} from all clusters it is attached to before deletion."
msgstr ""
@@ -28670,7 +29618,7 @@ msgstr "Vous avez besoin d’une autorisation."
msgid "You need to be logged in."
msgstr ""
-msgid "You need to register a two-factor authentication app before you can set up a U2F device."
+msgid "You need to register a two-factor authentication app before you can set up a device."
msgstr ""
msgid "You need to set terms to be enforced"
@@ -28688,6 +29636,9 @@ msgstr ""
msgid "You reached %{usage_in_percent} of %{namespace_name}'s storage capacity (%{used_storage} of %{storage_limit})"
msgstr ""
+msgid "You successfully declined the invitation"
+msgstr ""
+
msgid "You tried to fork %{link_to_the_project} but it failed for the following reason:"
msgstr ""
@@ -28853,10 +29804,13 @@ msgstr ""
msgid "Your U2F device did not send a valid JSON response."
msgstr ""
-msgid "Your U2F device needs to be set up. Plug it in (if not already) and click the button on the left."
+msgid "Your U2F device was registered!"
msgstr ""
-msgid "Your U2F device was registered!"
+msgid "Your WebAuthn device did not send a valid JSON response."
+msgstr ""
+
+msgid "Your WebAuthn device was registered!"
msgstr ""
msgid "Your access request to the %{source_type} has been withdrawn."
@@ -28880,6 +29834,9 @@ msgstr "Vos applications autorisées"
msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
msgstr ""
+msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
+msgstr ""
+
msgid "Your changes can be committed to %{branch_name} because a merge request is open."
msgstr "Vos modifications peuvent être validées sur %{branch_name} car une demande de fusion est ouverte."
@@ -28916,6 +29873,12 @@ msgstr ""
msgid "Your deployment services will be broken, you will need to manually fix the services after renaming."
msgstr ""
+msgid "Your device is not compatible with GitLab. Please try another device"
+msgstr ""
+
+msgid "Your device needs to be set up. Plug it in (if needed) and click the button on the left."
+msgstr ""
+
msgid "Your device was successfully set up! Give it a name and register it with the GitLab server."
msgstr ""
@@ -29029,9 +29992,6 @@ msgstr[1] ""
msgid "access:"
msgstr ""
-msgid "activated"
-msgstr ""
-
msgid "added %{created_at_timeago}"
msgstr ""
@@ -29104,9 +30064,21 @@ msgstr "par"
msgid "by %{user}"
msgstr ""
+msgid "cannot be a date in the past"
+msgstr ""
+
msgid "cannot be changed if a personal project has container registry tags."
msgstr ""
+msgid "cannot be changed if shared runners are enabled"
+msgstr ""
+
+msgid "cannot be enabled because parent group does not allow it"
+msgstr ""
+
+msgid "cannot be enabled because parent group has shared Runners disabled"
+msgstr ""
+
msgid "cannot be enabled unless all domains have TLS certificates"
msgstr ""
@@ -29152,7 +30124,7 @@ msgstr "%{linkStartTag}En savoir plus sur l’analyse des dépendances%{linkEndT
msgid "ciReport|%{linkStartTag}Learn more about SAST %{linkEndTag}"
msgstr "%{linkStartTag}En savoir plus sur SAST %{linkEndTag}"
-msgid "ciReport|%{linkStartTag}Learn more about Secret Scanning %{linkEndTag}"
+msgid "ciReport|%{linkStartTag}Learn more about Secret Detection %{linkEndTag}"
msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about codequality reports %{linkEndTag}"
@@ -29467,9 +30439,6 @@ msgstr ""
msgid "error"
msgstr ""
-msgid "error code:"
-msgstr ""
-
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr "%{slash_command} mettra à jour la durée estimée avec la dernière commande."
@@ -29491,6 +30460,9 @@ msgstr ""
msgid "failed to dismiss associated finding(id=%{finding_id}): %{message}"
msgstr ""
+msgid "failed to revert associated finding(id=%{finding_id}) to detected"
+msgstr ""
+
msgid "file"
msgid_plural "files"
msgstr[0] ""
@@ -29863,7 +30835,7 @@ msgid "mrWidget|Jump to first unresolved thread"
msgstr ""
msgid "mrWidget|Loading deployment statistics"
-msgstr "mrWidget | Chargement des statistiques de déploiement"
+msgstr "Chargement des statistiques de déploiement"
msgid "mrWidget|Mark as ready"
msgstr ""
@@ -30033,6 +31005,9 @@ msgstr ""
msgid "must be a root namespace"
msgstr ""
+msgid "must be a valid IPv4 or IPv6 address"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -30069,6 +31044,9 @@ msgstr ""
msgid "no expiration"
msgstr ""
+msgid "no name set"
+msgstr ""
+
msgid "no one can merge"
msgstr ""
@@ -30247,9 +31225,6 @@ msgstr ""
msgid "security Reports|There was an error creating the merge request"
msgstr ""
-msgid "settings saved, but not activated"
-msgstr ""
-
msgid "severity|Critical"
msgstr ""
@@ -30376,9 +31351,6 @@ msgstr ""
msgid "toggle collapse"
msgstr ""
-msgid "toggle dropdown"
-msgstr ""
-
msgid "triggered"
msgstr ""
@@ -30406,6 +31378,9 @@ msgstr ""
msgid "user avatar"
msgstr ""
+msgid "user preferences"
+msgstr ""
+
msgid "username"
msgstr "nom d’utilisateur"
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 68e3e1b26a9..2eff8d1365f 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -8,8 +8,6 @@ msgid ""
msgstr ""
"Project-Id-Version: gitlab 1.0.0\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2020-09-17 11:26-0400\n"
-"PO-Revision-Date: 2020-09-17 11:26-0400\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
@@ -79,6 +77,16 @@ msgstr ""
msgid "\"el\" parameter is required for createInstance()"
msgstr ""
+msgid "%d Approval"
+msgid_plural "%d Approvals"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d Package"
+msgid_plural "%d Packages"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d Scanned URL"
msgid_plural "%d Scanned URLs"
msgstr[0] ""
@@ -157,6 +165,11 @@ msgid_plural "%d days"
msgstr[0] ""
msgstr[1] ""
+msgid "%d day until tags are automatically removed"
+msgid_plural "%d days until tags are automatically removed"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d error"
msgid_plural "%d errors"
msgstr[0] ""
@@ -172,6 +185,11 @@ msgid_plural "%d failed"
msgstr[0] ""
msgstr[1] ""
+msgid "%d failed security job"
+msgid_plural "%d failed security jobs"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d fixed test result"
msgid_plural "%d fixed test results"
msgstr[0] ""
@@ -252,6 +270,11 @@ msgid_plural "%d open issues"
msgstr[0] ""
msgstr[1] ""
+msgid "%d pending comment"
+msgid_plural "%d pending comments"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d personal project will be removed and cannot be restored."
msgid_plural "%d personal projects will be removed and cannot be restored."
msgstr[0] ""
@@ -267,6 +290,11 @@ msgid_plural "%d projects"
msgstr[0] ""
msgstr[1] ""
+msgid "%d project selected"
+msgid_plural "%d projects selected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d request with warnings"
msgid_plural "%d requests with warnings"
msgstr[0] ""
@@ -287,6 +315,11 @@ msgid_plural "%d tags"
msgstr[0] ""
msgstr[1] ""
+msgid "%d tag per image name"
+msgid_plural "%d tags per image name"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d unassigned issue"
msgid_plural "%d unassigned issues"
msgstr[0] ""
@@ -401,11 +434,6 @@ msgid_plural "%{count} participants"
msgstr[0] ""
msgstr[1] ""
-msgid "%{count} pending comment"
-msgid_plural "%{count} pending comments"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
@@ -424,6 +452,12 @@ msgstr ""
msgid "%{description}- Sentry event: %{errorUrl}- First seen: %{firstSeen}- Last seen: %{lastSeen} %{countLabel}: %{count}%{userCountLabel}: %{userCount}"
msgstr ""
+msgid "%{doc_link_start}Advanced search%{doc_link_end} is disabled since %{ref_elem} is not the default branch; %{default_branch_link_start}search on %{default_branch} instead%{default_branch_link_end}."
+msgstr ""
+
+msgid "%{doc_link_start}Advanced search%{doc_link_end} is enabled."
+msgstr ""
+
msgid "%{due_date} (Past due)"
msgstr ""
@@ -466,6 +500,15 @@ msgstr ""
msgid "%{group_name} uses group managed accounts. You need to create a new GitLab account which will be managed by %{group_name}."
msgstr ""
+msgid "%{group_name}&%{epic_iid} &middot; opened %{epic_created} by %{author}"
+msgstr ""
+
+msgid "%{hook_type} was deleted"
+msgstr ""
+
+msgid "%{hook_type} was scheduled for deletion"
+msgstr ""
+
msgid "%{host} sign-in from new location"
msgstr ""
@@ -511,7 +554,7 @@ msgstr ""
msgid "%{labelStart}Namespace:%{labelEnd} %{namespace}"
msgstr ""
-msgid "%{labelStart}Report Type:%{labelEnd} %{reportType}"
+msgid "%{labelStart}Scan Type:%{labelEnd} %{reportType}"
msgstr ""
msgid "%{labelStart}Scanner:%{labelEnd} %{scanner}"
@@ -592,9 +635,6 @@ msgstr ""
msgid "%{name_with_link} has run out of Shared Runner Pipeline minutes so no new jobs or pipelines in its projects will run."
msgstr ""
-msgid "%{namespace_name} is now read-only. You cannot: %{base_message}"
-msgstr ""
-
msgid "%{name} contained %{resultsString}"
msgstr ""
@@ -708,6 +748,9 @@ msgid_plural "%{securityScanner} results are not available because a pipeline ha
msgstr[0] ""
msgstr[1] ""
+msgid "%{size} %{unit}"
+msgstr ""
+
msgid "%{size} GiB"
msgstr ""
@@ -859,9 +902,6 @@ msgstr ""
msgid "&lt; 1 hour"
msgstr ""
-msgid "&lt;no name set&gt;"
-msgstr ""
-
msgid "&lt;no scopes selected&gt;"
msgstr ""
@@ -924,9 +964,6 @@ msgstr ""
msgid "(deleted)"
msgstr ""
-msgid "(external source)"
-msgstr ""
-
msgid "(line: %{startLine})"
msgstr ""
@@ -954,6 +991,9 @@ msgstr ""
msgid "+ %{numberOfHiddenAssignees} more"
msgstr ""
+msgid "+ %{numberOfHiddenReviewers} more"
+msgstr ""
+
msgid "+%d more"
msgid_plural "+%d more"
msgstr[0] ""
@@ -962,6 +1002,18 @@ msgstr[1] ""
msgid "+%{approvers} more approvers"
msgstr ""
+msgid "+%{more_assignees_count}"
+msgstr ""
+
+msgid "+%{more_assignees_count} more assignees"
+msgstr ""
+
+msgid "+%{more_reviewers_count}"
+msgstr ""
+
+msgid "+%{more_reviewers_count} more reviewers"
+msgstr ""
+
msgid "+%{tags} more"
msgstr ""
@@ -999,6 +1051,9 @@ msgstr ""
msgid "0 for unlimited, only effective with remote storage enabled."
msgstr ""
+msgid "0t1DgySidms"
+msgstr ""
+
msgid "1 %{type} addition"
msgid_plural "%{count} %{type} additions"
msgstr[0] ""
@@ -1014,6 +1069,11 @@ msgid_plural "%d Days"
msgstr[0] ""
msgstr[1] ""
+msgid "1 Issue"
+msgid_plural "%d Issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "1 closed issue"
msgid_plural "%{issues} closed issues"
msgstr[0] ""
@@ -1029,6 +1089,11 @@ msgid_plural "%d days"
msgstr[0] ""
msgstr[1] ""
+msgid "1 deploy key"
+msgid_plural "%d deploy keys"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1146,6 +1211,9 @@ msgstr ""
msgid "A GitBook site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
+msgid "A Gitpod configured Webapplication in Spring and Java"
+msgstr ""
+
msgid "A Hexo site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
@@ -1257,6 +1325,9 @@ msgstr ""
msgid "ACTION REQUIRED: Something went wrong while obtaining the Let's Encrypt certificate for GitLab Pages domain '%{domain}'"
msgstr ""
+msgid "API Fuzzing"
+msgstr ""
+
msgid "API Help"
msgstr ""
@@ -1317,9 +1388,15 @@ msgstr ""
msgid "Access expiration date"
msgstr ""
+msgid "Access expires"
+msgstr ""
+
msgid "Access forbidden. Check your access level."
msgstr ""
+msgid "Access granted"
+msgstr ""
+
msgid "Access requests"
msgstr ""
@@ -1329,6 +1406,9 @@ msgstr ""
msgid "Access to Pages websites are controlled based on the user's membership to a given project. By checking this box, users will be required to be logged in to have access to all Pages websites in your instance."
msgstr ""
+msgid "AccessDropdown|Deploy Keys"
+msgstr ""
+
msgid "AccessDropdown|Groups"
msgstr ""
@@ -1446,12 +1526,6 @@ msgstr ""
msgid "Active Sessions"
msgstr ""
-msgid "Active Users:"
-msgstr ""
-
-msgid "Active users"
-msgstr ""
-
msgid "Activity"
msgstr ""
@@ -1553,6 +1627,9 @@ msgstr ""
msgid "Add a task list"
msgstr ""
+msgid "Add a to do"
+msgstr ""
+
msgid "Add additional text to appear in all email communications. %{character_limit} character limit"
msgstr ""
@@ -1706,7 +1783,7 @@ msgstr ""
msgid "Added %{label_references} %{label_text}."
msgstr ""
-msgid "Added a To Do."
+msgid "Added a to do."
msgstr ""
msgid "Added an issue to an epic."
@@ -1742,10 +1819,10 @@ msgstr ""
msgid "Adds %{labels} %{label_text}."
msgstr ""
-msgid "Adds a To Do."
+msgid "Adds a Zoom meeting"
msgstr ""
-msgid "Adds a Zoom meeting"
+msgid "Adds a to do."
msgstr ""
msgid "Adds an issue to an epic."
@@ -1970,6 +2047,21 @@ msgstr ""
msgid "AdminStatistics|Snippets"
msgstr ""
+msgid "AdminUsers|(Admin)"
+msgstr ""
+
+msgid "AdminUsers|(Blocked)"
+msgstr ""
+
+msgid "AdminUsers|(Deactivated)"
+msgstr ""
+
+msgid "AdminUsers|(Internal)"
+msgstr ""
+
+msgid "AdminUsers|(Pending approval)"
+msgstr ""
+
msgid "AdminUsers|2FA Disabled"
msgstr ""
@@ -1979,6 +2071,12 @@ msgstr ""
msgid "AdminUsers|Access"
msgstr ""
+msgid "AdminUsers|Access Git repositories"
+msgstr ""
+
+msgid "AdminUsers|Access the API"
+msgstr ""
+
msgid "AdminUsers|Active"
msgstr ""
@@ -1991,12 +2089,30 @@ msgstr ""
msgid "AdminUsers|Admins"
msgstr ""
+msgid "AdminUsers|Approve"
+msgstr ""
+
+msgid "AdminUsers|Approve user"
+msgstr ""
+
+msgid "AdminUsers|Approved users can:"
+msgstr ""
+
+msgid "AdminUsers|Are you sure?"
+msgstr ""
+
msgid "AdminUsers|Automatically marked as default internal user"
msgstr ""
+msgid "AdminUsers|Be added to groups and projects"
+msgstr ""
+
msgid "AdminUsers|Block"
msgstr ""
+msgid "AdminUsers|Block this user"
+msgstr ""
+
msgid "AdminUsers|Block user"
msgstr ""
@@ -2051,6 +2167,9 @@ msgstr ""
msgid "AdminUsers|It's you!"
msgstr ""
+msgid "AdminUsers|Log in"
+msgstr ""
+
msgid "AdminUsers|New user"
msgstr ""
@@ -2060,6 +2179,9 @@ msgstr ""
msgid "AdminUsers|Owned groups will be left"
msgstr ""
+msgid "AdminUsers|Pending approval"
+msgstr ""
+
msgid "AdminUsers|Personal projects will be left"
msgstr ""
@@ -2105,6 +2227,9 @@ msgstr ""
msgid "AdminUsers|The user will not receive any notifications"
msgstr ""
+msgid "AdminUsers|This user has requested access"
+msgstr ""
+
msgid "AdminUsers|To confirm, type %{projectName}"
msgstr ""
@@ -2126,7 +2251,10 @@ 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 %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 ""
+
+msgid "AdminUsers|You can always unblock their account, their data will remain intact."
msgstr ""
msgid "AdminUsers|You cannot remove your own admin rights."
@@ -2153,22 +2281,19 @@ msgstr ""
msgid "Advanced permissions, Large File Storage and Two-Factor authentication settings."
msgstr ""
-msgid "Advanced search functionality"
-msgstr ""
-
msgid "After a successful password update you will be redirected to login screen."
msgstr ""
msgid "After a successful password update, you will be redirected to the login page where you can log in with your new password."
msgstr ""
-msgid "After that, you will not to be able to use merge approvals or code quality as well as many other features."
+msgid "After that, you will not be able to use merge approvals or code quality as well as many other features."
msgstr ""
-msgid "After that, you will not to be able to use merge approvals or epics as well as many other features."
+msgid "After that, you will not be able to use merge approvals or epics as well as many other features."
msgstr ""
-msgid "After that, you will not to be able to use merge approvals or epics as well as many security features."
+msgid "After that, you will not be able to use merge approvals or epics as well as many security features."
msgstr ""
msgid "Alert"
@@ -2224,16 +2349,19 @@ msgstr ""
msgid "AlertManagement|Edit"
msgstr ""
+msgid "AlertManagement|Environment"
+msgstr ""
+
msgid "AlertManagement|Events"
msgstr ""
msgid "AlertManagement|High"
msgstr ""
-msgid "AlertManagement|Info"
+msgid "AlertManagement|Incident"
msgstr ""
-msgid "AlertManagement|Issue"
+msgid "AlertManagement|Info"
msgstr ""
msgid "AlertManagement|Key"
@@ -2359,10 +2487,10 @@ msgstr ""
msgid "AlertSettings|Add URL and auth key to your Prometheus config file"
msgstr ""
-msgid "AlertSettings|Alert test payload"
+msgid "AlertSettings|Add new integrations"
msgstr ""
-msgid "AlertSettings|Alerts endpoint successfully activated."
+msgid "AlertSettings|Alert test payload"
msgstr ""
msgid "AlertSettings|Authorization key"
@@ -2380,13 +2508,16 @@ msgstr ""
msgid "AlertSettings|External Prometheus"
msgstr ""
-msgid "AlertSettings|Generic"
+msgid "AlertSettings|HTTP Endpoint"
msgstr ""
-msgid "AlertSettings|Integrations"
+msgid "AlertSettings|HTTP endpoint"
msgstr ""
-msgid "AlertSettings|Learn more about our %{linkStart}upcoming integrations%{linkEnd}"
+msgid "AlertSettings|Integration"
+msgstr ""
+
+msgid "AlertSettings|Learn more about our improvements for %{linkStart}integrations%{linkEnd}"
msgstr ""
msgid "AlertSettings|Opsgenie"
@@ -2410,7 +2541,7 @@ msgstr ""
msgid "AlertSettings|Test failed. Do you still want to save your changes anyway?"
msgstr ""
-msgid "AlertSettings|There was an error updating the alert settings"
+msgid "AlertSettings|There was an error updating the alert settings."
msgstr ""
msgid "AlertSettings|There was an error while trying to reset the key. Please refresh the page to try again."
@@ -2428,7 +2559,7 @@ msgstr ""
msgid "AlertSettings|You must provide this URL and authorization key to authorize an external service to send alerts to GitLab. You can provide this URL and key to multiple services. After configuring an external service, alerts from your service will display on the GitLab %{linkStart}Alerts%{linkEnd} page."
msgstr ""
-msgid "AlertSettings|Your changes were successfully updated."
+msgid "AlertSettings|Your integration was successfully updated."
msgstr ""
msgid "Alerts"
@@ -2437,6 +2568,27 @@ msgstr ""
msgid "Alerts endpoint"
msgstr ""
+msgid "AlertsIntegrations|Alerts will be created through this integration"
+msgstr ""
+
+msgid "AlertsIntegrations|Alerts will not be created through this integration"
+msgstr ""
+
+msgid "AlertsIntegrations|Current integrations"
+msgstr ""
+
+msgid "AlertsIntegrations|HTTP endpoint"
+msgstr ""
+
+msgid "AlertsIntegrations|Integration Name"
+msgstr ""
+
+msgid "AlertsIntegrations|No integrations have been added yet"
+msgstr ""
+
+msgid "AlertsIntegrations|Prometheus"
+msgstr ""
+
msgid "Algorithm"
msgstr ""
@@ -2494,13 +2646,13 @@ msgstr ""
msgid "All projects"
msgstr ""
-msgid "All security scans are enabled because %{linkStart}Auto DevOps%{linkEnd} is enabled on this project"
+msgid "All projects selected"
msgstr ""
-msgid "All threads resolved"
+msgid "All security scans are enabled because %{linkStart}Auto DevOps%{linkEnd} is enabled on this project"
msgstr ""
-msgid "All users"
+msgid "All threads resolved"
msgstr ""
msgid "All users must have a name."
@@ -2527,6 +2679,9 @@ msgstr ""
msgid "Allow owners to manually add users outside of LDAP"
msgstr ""
+msgid "Allow projects and subgroups to override the group setting"
+msgstr ""
+
msgid "Allow projects within this group to use Git LFS"
msgstr ""
@@ -2548,6 +2703,9 @@ msgstr ""
msgid "Allow requests to the local network from web hooks and services"
msgstr ""
+msgid "Allow subgroups to set up their own two-factor authentication rules"
+msgstr ""
+
msgid "Allow this key to push to repository as well? (Default only allows pull access.)"
msgstr ""
@@ -2575,6 +2733,9 @@ msgstr ""
msgid "Allowed to fail"
msgstr ""
+msgid "Allows projects or subgroups in this group to override the global setting."
+msgstr ""
+
msgid "Allows you to add and manage Kubernetes clusters."
msgstr ""
@@ -2635,9 +2796,15 @@ msgstr ""
msgid "An empty GitLab User field will add the FogBugz user's full name (e.g. \"By John Smith\") in the description of all issues and comments. It will also associate and/or assign these issues and comments with the project creator."
msgstr ""
+msgid "An empty index will be created if one does not already exist"
+msgstr ""
+
msgid "An error has occurred"
msgstr ""
+msgid "An error occured while making the changes: %{error}"
+msgstr ""
+
msgid "An error occurred adding a draft to the thread."
msgstr ""
@@ -2662,13 +2829,10 @@ msgstr ""
msgid "An error occurred previewing the blob"
msgstr ""
-msgid "An error occurred when toggling the notification subscription"
-msgstr ""
-
-msgid "An error occurred when trying to resolve a comment. Please try again."
+msgid "An error occurred when removing the label."
msgstr ""
-msgid "An error occurred when trying to resolve a discussion. Please try again."
+msgid "An error occurred when toggling the notification subscription"
msgstr ""
msgid "An error occurred when updating the issue weight"
@@ -2686,12 +2850,6 @@ msgstr ""
msgid "An error occurred while checking group path. Please refresh and try again."
msgstr ""
-msgid "An error occurred while creating the issue. Please try again."
-msgstr ""
-
-msgid "An error occurred while creating the list. Please try again."
-msgstr ""
-
msgid "An error occurred while decoding the file."
msgstr ""
@@ -2764,18 +2922,9 @@ msgstr ""
msgid "An error occurred while fetching the Service Desk address."
msgstr ""
-msgid "An error occurred while fetching the board issues. Please reload the page."
-msgstr ""
-
-msgid "An error occurred while fetching the board lists. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the board lists. Please try again."
msgstr ""
-msgid "An error occurred while fetching the board swimlanes. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the builds."
msgstr ""
@@ -2878,18 +3027,12 @@ msgstr ""
msgid "An error occurred while loading the pipelines jobs."
msgstr ""
-msgid "An error occurred while loading the subscription details."
-msgstr ""
-
msgid "An error occurred while making the request."
msgstr ""
msgid "An error occurred while moving the issue."
msgstr ""
-msgid "An error occurred while moving the issue. Please try again."
-msgstr ""
-
msgid "An error occurred while parsing recent searches"
msgstr ""
@@ -2908,6 +3051,9 @@ msgstr ""
msgid "An error occurred while rendering the editor"
msgstr ""
+msgid "An error occurred while rendering the linter"
+msgstr ""
+
msgid "An error occurred while reordering issues."
msgstr ""
@@ -2932,9 +3078,6 @@ msgstr ""
msgid "An error occurred while saving assignees"
msgstr ""
-msgid "An error occurred while saving the template. Please check if the template exists."
-msgstr ""
-
msgid "An error occurred while searching for milestones"
msgstr ""
@@ -2953,13 +3096,13 @@ msgstr ""
msgid "An error occurred while updating approvers"
msgstr ""
-msgid "An error occurred while updating labels."
+msgid "An error occurred while updating configuration."
msgstr ""
-msgid "An error occurred while updating the comment"
+msgid "An error occurred while updating labels."
msgstr ""
-msgid "An error occurred while updating the list. Please try again."
+msgid "An error occurred while updating the comment"
msgstr ""
msgid "An error occurred while validating group path"
@@ -3013,6 +3156,9 @@ msgstr ""
msgid "An unknown error occurred while loading this graph."
msgstr ""
+msgid "An unknown error occurred."
+msgstr ""
+
msgid "Analytics"
msgstr ""
@@ -3046,10 +3192,10 @@ msgstr ""
msgid "Any"
msgstr ""
-msgid "Any Author"
+msgid "Any %{header}"
msgstr ""
-msgid "Any Status"
+msgid "Any Author"
msgstr ""
msgid "Any branch"
@@ -3282,6 +3428,9 @@ msgstr ""
msgid "Archive project"
msgstr ""
+msgid "Archive test case"
+msgstr ""
+
msgid "Archived"
msgstr ""
@@ -3327,6 +3476,9 @@ msgstr ""
msgid "Are you sure you want to delete this %{typeOfComment}?"
msgstr ""
+msgid "Are you sure you want to delete this SSH key?"
+msgstr ""
+
msgid "Are you sure you want to delete this board?"
msgstr ""
@@ -3446,12 +3598,6 @@ msgstr ""
msgid "Artifacts"
msgstr ""
-msgid "As U2F devices are only supported by a few browsers, we require that you set up a two-factor authentication app before a U2F device. That way you'll always be able to log in - even when you're using an unsupported browser."
-msgstr ""
-
-msgid "As WebAuthn devices are only supported by a few browsers, we require that you set up a two-factor authentication app before a WebAuthn device. That way you'll always be able to log in - even when you're using an unsupported browser."
-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 ""
@@ -3533,6 +3679,9 @@ msgstr ""
msgid "Assigned to %{assignee_name}"
msgstr ""
+msgid "Assigned to %{name}"
+msgstr ""
+
msgid "Assigned to me"
msgstr ""
@@ -3645,6 +3794,9 @@ msgstr ""
msgid "AuditLogs|Target"
msgstr ""
+msgid "AuditLogs|This month"
+msgstr ""
+
msgid "AuditLogs|User Events"
msgstr ""
@@ -3681,7 +3833,10 @@ msgstr ""
msgid "Authentication method updated"
msgstr ""
-msgid "Authentication via %{method} device failed."
+msgid "Authentication via U2F device failed."
+msgstr ""
+
+msgid "Authentication via WebAuthn device failed."
msgstr ""
msgid "Author"
@@ -3771,7 +3926,13 @@ msgstr ""
msgid "AutoDevOps|Learn more in the %{link_to_documentation}"
msgstr ""
-msgid "AutoDevOps|The Auto DevOps pipeline has been enabled and will be used if no alternative CI configuration file is found. %{more_information_link}"
+msgid "AutoDevOps|The Auto DevOps pipeline has been enabled and will be used if no alternative CI configuration file is found."
+msgstr ""
+
+msgid "AutoRemediation|If you're using dependency and/or container scanning, and auto-fix is enabled, auto-fix automatically creates merge requests with fixes to vulnerabilities."
+msgstr ""
+
+msgid "AutoRemediation|Introducing GitLab auto-fix"
msgstr ""
msgid "Autocomplete"
@@ -3810,6 +3971,9 @@ msgstr ""
msgid "Available"
msgstr ""
+msgid "Available ID"
+msgstr ""
+
msgid "Available Runners: %{runners}"
msgstr ""
@@ -3867,9 +4031,6 @@ msgstr ""
msgid "Badges|Badge image preview"
msgstr ""
-msgid "Badges|Delete badge"
-msgstr ""
-
msgid "Badges|Delete badge?"
msgstr ""
@@ -3951,13 +4112,10 @@ msgstr ""
msgid "BambooService|You must set up automatic revision labeling and a repository trigger in Bamboo."
msgstr ""
-msgid "BatchComments|Delete all pending comments"
-msgstr ""
-
-msgid "BatchComments|Discard review?"
+msgid "Based on"
msgstr ""
-msgid "BatchComments|You're about to discard your review which will delete all of your pending comments. The deleted comments %{strong_start}cannot%{strong_end} be restored."
+msgid "Basic Sample Data template with Issues, Merge Requests and Milestones."
msgstr ""
msgid "Be careful. Changing the project's namespace can have unintended side effects."
@@ -3981,6 +4139,9 @@ msgstr ""
msgid "Bi-weekly code coverage"
msgstr ""
+msgid "Billable Users:"
+msgstr ""
+
msgid "Billing"
msgstr ""
@@ -3990,7 +4151,7 @@ msgstr ""
msgid "BillingPlans|@%{user_name} you are currently using the %{plan_name} plan."
msgstr ""
-msgid "BillingPlans|Congratulations, your new trial is activated"
+msgid "BillingPlans|Congratulations, your free trial is activated."
msgstr ""
msgid "BillingPlans|If you would like to downgrade your plan please contact %{support_link_start}Customer Support%{support_link_end}."
@@ -4041,6 +4202,18 @@ msgstr ""
msgid "BillingPlan|Upgrade"
msgstr ""
+msgid "Billing|An error occurred while loading billable members list"
+msgstr ""
+
+msgid "Billing|No users to display."
+msgstr ""
+
+msgid "Billing|Updated live"
+msgstr ""
+
+msgid "Billing|Users occupying seats in %{namespaceName} Group (%{total})"
+msgstr ""
+
msgid "Bitbucket Server Import"
msgstr ""
@@ -4071,31 +4244,40 @@ msgstr ""
msgid "Blog"
msgstr ""
-msgid "Board name"
-msgstr ""
-
msgid "Board scope"
msgstr ""
msgid "Board scope affects which issues are displayed for anyone who visits this board"
msgstr ""
-msgid "BoardBlankState|Add default lists"
+msgid "Boards"
msgstr ""
-msgid "BoardBlankState|Add the following default lists to your Issue Board with one click:"
+msgid "Boards and Board Lists"
msgstr ""
-msgid "BoardBlankState|Nevermind, I'll use my own"
+msgid "Boards|An error occurred while creating the issue. Please try again."
msgstr ""
-msgid "BoardBlankState|Starting out with the default set of lists will get you right on the way to making the most of your board."
+msgid "Boards|An error occurred while creating the list. Please try again."
msgstr ""
-msgid "Boards"
+msgid "Boards|An error occurred while fetching issues. Please reload the page."
msgstr ""
-msgid "Boards and Board Lists"
+msgid "Boards|An error occurred while fetching the board issues. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching the board lists. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching the board swimlanes. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while moving the issue. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while updating the list. Please try again."
msgstr ""
msgid "Boards|Collapse"
@@ -4110,6 +4292,9 @@ msgstr ""
msgid "Boards|View scope"
msgstr ""
+msgid "Board|Load more issues"
+msgstr ""
+
msgid "Both project and dashboard_path are required"
msgstr ""
@@ -4122,6 +4307,9 @@ msgstr ""
msgid "Branch %{branch_name} was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr ""
+msgid "Branch already exists"
+msgstr ""
+
msgid "Branch changed"
msgstr ""
@@ -4266,6 +4454,9 @@ msgstr ""
msgid "Branches|protected"
msgstr ""
+msgid "Brief title about the change"
+msgstr ""
+
msgid "Broadcast Message was successfully created."
msgstr ""
@@ -4302,9 +4493,21 @@ msgstr ""
msgid "Bulk request concurrency"
msgstr ""
+msgid "BulkImport|expected an associated Group but has an associated Project"
+msgstr ""
+
+msgid "BulkImport|expected an associated Project but has an associated Group"
+msgstr ""
+
+msgid "BulkImport|must be a group"
+msgstr ""
+
msgid "Burndown chart"
msgstr ""
+msgid "Burndown charts are now fixed. This means that removing issues from a milestone after it has expired won't affect the chart. You can view the old chart using the %{strongStart}Legacy burndown chart%{strongEnd} button."
+msgstr ""
+
msgid "BurndownChartLabel|Open issue weight"
msgstr ""
@@ -4335,7 +4538,7 @@ msgstr ""
msgid "By URL"
msgstr ""
-msgid "By clicking Register, I agree that I have read and accepted the GitLab %{linkStart}Terms of Use and Privacy Policy%{linkEnd}"
+msgid "By clicking Register, I agree that I have read and accepted the %{company_name} %{linkStart}Terms of Use and Privacy Policy%{linkEnd}"
msgstr ""
msgid "By default GitLab sends emails in HTML and plain text formats so mail clients can choose what format to use. Disable this option if you only want to send emails in plain text format."
@@ -4461,9 +4664,6 @@ msgstr ""
msgid "Can't create snippet: %{err}"
msgstr ""
-msgid "Can't edit as source branch was deleted"
-msgstr ""
-
msgid "Can't fetch content for the blob: %{err}"
msgstr ""
@@ -4476,9 +4676,6 @@ msgstr ""
msgid "Can't load mermaid module: %{err}"
msgstr ""
-msgid "Can't remove group members without group managed account"
-msgstr ""
-
msgid "Can't scan the code?"
msgstr ""
@@ -4521,6 +4718,12 @@ msgstr ""
msgid "Cannot create the abuse report. This user has been blocked."
msgstr ""
+msgid "Cannot enable shared runners because parent group does not allow it"
+msgstr ""
+
+msgid "Cannot find user key."
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -4626,6 +4829,15 @@ msgstr ""
msgid "Change your password or recover your current one"
msgstr ""
+msgid "ChangeReviewer|Reviewer changed from %{old} to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Reviewer changed to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Unassigned"
+msgstr ""
+
msgid "ChangeTypeActionLabel|Pick into branch"
msgstr ""
@@ -5073,6 +5285,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove variable"
+msgstr ""
+
msgid "CiVariables|Remove variable row"
msgstr ""
@@ -5286,6 +5501,27 @@ msgstr ""
msgid "Cluster type must be specificed for Stages::ClusterEndpointInserter"
msgstr ""
+msgid "ClusterAgents|Configuration"
+msgstr ""
+
+msgid "ClusterAgents|Connect your cluster with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate Kubernetes with a GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Name"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Agent also requires %{linkStart}enabling the Agent Server%{linkEnd}"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Kubernetes Agent allows an Infrastructure as Code, GitOps approach to integrating Kubernetes clusters with GitLab. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "ClusterAgent|This feature is only available for premium plans"
msgstr ""
@@ -5355,10 +5591,10 @@ msgstr ""
msgid "ClusterIntegration|All installed applications and related resources"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster."
+msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{linkStart}More information%{linkEnd}"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{startLink}More information%{endLink}"
+msgid "ClusterIntegration|Allow GitLab to manage namespaces and service accounts for this cluster."
msgstr ""
msgid "ClusterIntegration|Alternatively, "
@@ -5379,6 +5615,9 @@ msgstr ""
msgid "ClusterIntegration|An error occurred while trying to fetch zone machine types: %{error}"
msgstr ""
+msgid "ClusterIntegration|An unknown error occurred while attempting to connect to Kubernetes."
+msgstr ""
+
msgid "ClusterIntegration|Any project namespaces"
msgstr ""
@@ -5394,6 +5633,9 @@ msgstr ""
msgid "ClusterIntegration|Authenticate with Amazon Web Services"
msgstr ""
+msgid "ClusterIntegration|Authentication Error"
+msgstr ""
+
msgid "ClusterIntegration|Base domain"
msgstr ""
@@ -5412,13 +5654,22 @@ msgstr ""
msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}security group %{externalLinkIcon} %{endLink} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
+msgid "ClusterIntegration|Check your CA certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Check your cluster status"
+msgstr ""
+
+msgid "ClusterIntegration|Check your token"
+msgstr ""
+
+msgid "ClusterIntegration|Choose the %{linkStart}security group %{linkEnd} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}subnets %{externalLinkIcon} %{endLink} in your VPC where your worker nodes will run."
+msgid "ClusterIntegration|Choose the %{linkStart}subnets %{linkEnd} in your VPC where your worker nodes will run."
msgstr ""
-msgid "ClusterIntegration|Choose the worker node %{startLink}instance type %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Choose the worker node %{linkStart}instance type%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Choose which applications to install on your Kubernetes cluster."
@@ -5430,10 +5681,7 @@ msgstr ""
msgid "ClusterIntegration|Clear cluster cache"
msgstr ""
-msgid "ClusterIntegration|Clear the local cache of namespace and service accounts. This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
-msgstr ""
-
-msgid "ClusterIntegration|Cluster being created"
+msgid "ClusterIntegration|Clear the local cache of namespace and service accounts."
msgstr ""
msgid "ClusterIntegration|Cluster management project (alpha)"
@@ -5445,15 +5693,21 @@ msgstr ""
msgid "ClusterIntegration|Cluster_applications artifact too big. Maximum allowable size: %{human_size}"
msgstr ""
-msgid "ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters."
+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|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}"
+msgid "ClusterIntegration|Clusters connected with a certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Connect cluster with certificate"
msgstr ""
msgid "ClusterIntegration|Connect existing cluster"
msgstr ""
+msgid "ClusterIntegration|Connection Error"
+msgstr ""
+
msgid "ClusterIntegration|Copy API URL"
msgstr ""
@@ -5529,6 +5783,12 @@ msgstr ""
msgid "ClusterIntegration|Deletes all GitLab resources attached to this cluster during removal"
msgstr ""
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared."
+msgstr ""
+
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared. %{linkStart}More information%{linkEnd}"
+msgstr ""
+
msgid "ClusterIntegration|Did you know?"
msgstr ""
@@ -5598,6 +5858,9 @@ msgstr ""
msgid "ClusterIntegration|Fluentd is an open source data collector, which lets you unify the data collection and consumption for a better use and understanding of data. It requires at least one of the following logs to be successfully installed."
msgstr ""
+msgid "ClusterIntegration|GitLab Agent managed clusters"
+msgstr ""
+
msgid "ClusterIntegration|GitLab Container Network Policies"
msgstr ""
@@ -5610,6 +5873,12 @@ msgstr ""
msgid "ClusterIntegration|GitLab Runner connects to the repository and executes CI/CD jobs, pushing results back and deploying applications to production."
msgstr ""
+msgid "ClusterIntegration|GitLab failed to authenticate."
+msgstr ""
+
+msgid "ClusterIntegration|GitLab failed to connect to the cluster."
+msgstr ""
+
msgid "ClusterIntegration|GitLab-managed cluster"
msgstr ""
@@ -5631,6 +5900,9 @@ msgstr ""
msgid "ClusterIntegration|Group cluster"
msgstr ""
+msgid "ClusterIntegration|HTTP Error"
+msgstr ""
+
msgid "ClusterIntegration|Helm Tiller"
msgstr ""
@@ -5664,7 +5936,10 @@ msgstr ""
msgid "ClusterIntegration|Instance type"
msgstr ""
-msgid "ClusterIntegration|Integrate Kubernetes cluster automation"
+msgid "ClusterIntegration|Integrate Kubernetes with a cluster certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Integrate with a cluster certificate"
msgstr ""
msgid "ClusterIntegration|Issuer Email"
@@ -5700,9 +5975,6 @@ msgstr ""
msgid "ClusterIntegration|Knative extends Kubernetes to provide a set of middleware components that are essential to build modern, source-centric, and container-based applications that can run anywhere: on premises, in the cloud, or even in a third-party data center."
msgstr ""
-msgid "ClusterIntegration|Kubernetes cluster"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes cluster is being created..."
msgstr ""
@@ -5715,9 +5987,6 @@ msgstr ""
msgid "ClusterIntegration|Kubernetes clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr ""
-msgid "ClusterIntegration|Kubernetes clusters can be used to deploy applications and to provide Review Apps for this project"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes version"
msgstr ""
@@ -5730,7 +5999,7 @@ msgstr ""
msgid "ClusterIntegration|Learn more about %{help_link_start}zones%{help_link_end}."
msgstr ""
-msgid "ClusterIntegration|Learn more about %{startLink}Regions %{externalLinkIcon}%{endLink}."
+msgid "ClusterIntegration|Learn more about %{linkStart}Regions%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Learn more about Kubernetes"
@@ -5775,12 +6044,18 @@ msgstr ""
msgid "ClusterIntegration|Machine type"
msgstr ""
+msgid "ClusterIntegration|Make sure your API endpoint is correct"
+msgstr ""
+
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create Kubernetes clusters"
msgstr ""
msgid "ClusterIntegration|Manage your Kubernetes cluster by visiting %{provider_link}"
msgstr ""
+msgid "ClusterIntegration|Namespace per environment"
+msgstr ""
+
msgid "ClusterIntegration|No IAM Roles found"
msgstr ""
@@ -5826,6 +6101,9 @@ msgstr ""
msgid "ClusterIntegration|No zones matched your search"
msgstr ""
+msgid "ClusterIntegration|Node calculations use the Kubernetes Metrics API. Make sure your cluster has metrics installed"
+msgstr ""
+
msgid "ClusterIntegration|Number of nodes"
msgstr ""
@@ -5868,6 +6146,9 @@ msgstr ""
msgid "ClusterIntegration|RBAC-enabled cluster"
msgstr ""
+msgid "ClusterIntegration|Read our %{linkStart}help page%{linkEnd} on Kubernetes cluster integration."
+msgstr ""
+
msgid "ClusterIntegration|Read our %{link_start}help page%{link_end} on Kubernetes cluster integration."
msgstr ""
@@ -5970,7 +6251,7 @@ msgstr ""
msgid "ClusterIntegration|Select a VPC to choose a subnet"
msgstr ""
-msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{linkStart}Amazon Web Services %{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select a network to choose a subnetwork"
@@ -6003,7 +6284,7 @@ msgstr ""
msgid "ClusterIntegration|Select project to choose zone"
msgstr ""
-msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select zone"
@@ -6093,9 +6374,18 @@ msgstr ""
msgid "ClusterIntegration|There was a problem authenticating with your cluster. Please ensure your CA Certificate and Token are valid."
msgstr ""
+msgid "ClusterIntegration|There was an HTTP error when connecting to your cluster."
+msgstr ""
+
msgid "ClusterIntegration|This account must have permissions to create a Kubernetes cluster in the %{link_to_container_project} specified below"
msgstr ""
+msgid "ClusterIntegration|This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
+msgstr ""
+
+msgid "ClusterIntegration|This is necessary to clear existing environment-namespace associations from clusters previously managed by GitLab."
+msgstr ""
+
msgid "ClusterIntegration|This option will allow you to install applications on RBAC clusters."
msgstr ""
@@ -6120,9 +6410,21 @@ msgstr ""
msgid "ClusterIntegration|To use a new project, first create one on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}."
msgstr ""
+msgid "ClusterIntegration|Troubleshooting tips:"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Authenticate"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Connect"
+msgstr ""
+
msgid "ClusterIntegration|Uninstall %{appTitle}"
msgstr ""
+msgid "ClusterIntegration|Unknown Error"
+msgstr ""
+
msgid "ClusterIntegration|Update %{appTitle}"
msgstr ""
@@ -6183,7 +6485,7 @@ msgstr ""
msgid "ClusterIntegration|Your cluster API is unreachable. Please ensure your API URL is correct."
msgstr ""
-msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Zone"
@@ -6303,6 +6605,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse all threads"
+msgstr ""
+
msgid "Collapse approvers"
msgstr ""
@@ -6321,9 +6626,6 @@ msgstr ""
msgid "ComboSearch is not defined"
msgstr ""
-msgid "Coming soon"
-msgstr ""
-
msgid "Comma-separated, e.g. '1.1.1.1, 2.2.2.0/24'"
msgstr ""
@@ -6617,6 +6919,9 @@ msgstr ""
msgid "Configure the way a user creates a new account."
msgstr ""
+msgid "Configure which lists are shown for anyone who visits this board"
+msgstr ""
+
msgid "Confirm"
msgstr ""
@@ -6632,7 +6937,7 @@ msgstr ""
msgid "ConfluenceService|Confluence Workspace"
msgstr ""
-msgid "ConfluenceService|Connect a Confluence Cloud Workspace to your GitLab project"
+msgid "ConfluenceService|Connect a Confluence Cloud Workspace to GitLab"
msgstr ""
msgid "ConfluenceService|Enabling the Confluence Workspace will disable the default GitLab Wiki. Your GitLab Wiki data will be saved and you can always re-enable it later by turning off this integration"
@@ -6683,6 +6988,9 @@ msgstr ""
msgid "Connection timeout"
msgstr ""
+msgid "Consistency guarantee method"
+msgstr ""
+
msgid "Contact sales to upgrade"
msgstr ""
@@ -6750,6 +7058,9 @@ msgstr ""
msgid "ContainerRegistry|Cleanup policy:"
msgstr ""
+msgid "ContainerRegistry|Cleanup timed out before it could delete all tags"
+msgstr ""
+
msgid "ContainerRegistry|Configuration digest: %{digest}"
msgstr ""
@@ -6842,6 +7153,9 @@ msgstr[1] ""
msgid "ContainerRegistry|Set cleanup policy"
msgstr ""
+msgid "ContainerRegistry|Some tags were not deleted"
+msgstr ""
+
msgid "ContainerRegistry|Something went wrong while fetching the cleanup policy."
msgstr ""
@@ -6881,6 +7195,9 @@ msgstr ""
msgid "ContainerRegistry|Tags with names matching this regex pattern will %{italicStart}expire:%{italicEnd}"
msgstr ""
+msgid "ContainerRegistry|The cleanup policy timed out before it could delete all tags. An administrator can %{adminLinkStart}manually run cleanup now%{adminLinkEnd} or you can wait for the cleanup policy to automatically run again. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "ContainerRegistry|The last tag related to this image was recently removed. This empty image and any associated data will be automatically removed as part of the regular Garbage Collection process. If you have any questions, contact your administrator."
msgstr ""
@@ -7121,6 +7438,9 @@ msgstr ""
msgid "Copy the code below to implement tracking in your application:"
msgstr ""
+msgid "Copy this value"
+msgstr ""
+
msgid "Copy to clipboard"
msgstr ""
@@ -7181,12 +7501,21 @@ msgstr ""
msgid "Could not delete wiki page"
msgstr ""
+msgid "Could not draw the lines for job relationships"
+msgstr ""
+
msgid "Could not find design."
msgstr ""
msgid "Could not find iteration"
msgstr ""
+msgid "Could not load instance counts. Please refresh the page to try again."
+msgstr ""
+
+msgid "Could not load the user chart. Please refresh the page to try again."
+msgstr ""
+
msgid "Could not remove the trigger."
msgstr ""
@@ -7220,6 +7549,9 @@ msgstr ""
msgid "Could not upload your designs as one or more files uploaded are not supported."
msgstr ""
+msgid "Couldn't calculate number of %{issuables}."
+msgstr ""
+
msgid "Country"
msgstr ""
@@ -7869,6 +8201,15 @@ msgstr ""
msgid "Dashboard|Unable to add %{invalidProjects}. This dashboard is available for public projects, and private projects in groups with a Silver plan."
msgstr ""
+msgid "DastProfiles|A passive scan monitors all HTTP messages (requests and responses) sent to the target. An active scan attacks the target to find potential vulnerabilities."
+msgstr ""
+
+msgid "DastProfiles|AJAX spider"
+msgstr ""
+
+msgid "DastProfiles|Active"
+msgstr ""
+
msgid "DastProfiles|Are you sure you want to delete this profile?"
msgstr ""
@@ -7908,6 +8249,12 @@ msgstr ""
msgid "DastProfiles|Could not update the site profile. Please try again."
msgstr ""
+msgid "DastProfiles|Debug messages"
+msgstr ""
+
+msgid "DastProfiles|Delete profile"
+msgstr ""
+
msgid "DastProfiles|Do you want to discard this scanner profile?"
msgstr ""
@@ -7929,6 +8276,12 @@ msgstr ""
msgid "DastProfiles|Error Details"
msgstr ""
+msgid "DastProfiles|Hide debug messages"
+msgstr ""
+
+msgid "DastProfiles|Include debug messages in the DAST console output."
+msgstr ""
+
msgid "DastProfiles|Manage Profiles"
msgstr ""
@@ -7965,6 +8318,9 @@ msgstr ""
msgid "DastProfiles|Profile name"
msgstr ""
+msgid "DastProfiles|Run the AJAX spider, in addition to the traditional spider, to crawl the target site."
+msgstr ""
+
msgid "DastProfiles|Save commonly used configurations for target sites and scan specifications as profiles. Use these with an on-demand scan."
msgstr ""
@@ -7980,6 +8336,9 @@ msgstr ""
msgid "DastProfiles|Scanner Profiles"
msgstr ""
+msgid "DastProfiles|Show debug messages"
+msgstr ""
+
msgid "DastProfiles|Site Profile"
msgstr ""
@@ -8019,6 +8378,9 @@ msgstr ""
msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
msgstr ""
+msgid "DastProfiles|Turn on AJAX spider"
+msgstr ""
+
msgid "DastProfiles|Validate"
msgstr ""
@@ -8031,6 +8393,12 @@ msgstr ""
msgid "DastProfiles|Validation failed, please make sure that you follow the steps above with the choosen method."
msgstr ""
+msgid "DastProfiles|Validation failed. Please try again."
+msgstr ""
+
+msgid "DastProfiles|Validation is in progress..."
+msgstr ""
+
msgid "DastProfiles|Validation must be turned off to change the target URL"
msgstr ""
@@ -8076,6 +8444,9 @@ msgstr ""
msgid "Days to merge"
msgstr ""
+msgid "Dear Administrator,"
+msgstr ""
+
msgid "Debug"
msgstr ""
@@ -8193,9 +8564,6 @@ msgstr ""
msgid "Delete Comment"
msgstr ""
-msgid "Delete Snippet"
-msgstr ""
-
msgid "Delete Value Stream"
msgstr ""
@@ -8205,6 +8573,9 @@ msgstr ""
msgid "Delete artifacts"
msgstr ""
+msgid "Delete badge"
+msgstr ""
+
msgid "Delete board"
msgstr ""
@@ -8220,9 +8591,6 @@ msgstr ""
msgid "Delete label: %{label_name} ?"
msgstr ""
-msgid "Delete list"
-msgstr ""
-
msgid "Delete pipeline"
msgstr ""
@@ -8361,18 +8729,27 @@ msgstr ""
msgid "Dependencies|Job failed to generate the dependency list"
msgstr ""
+msgid "Dependencies|Learn more about dependency paths"
+msgstr ""
+
msgid "Dependencies|License"
msgstr ""
msgid "Dependencies|Location"
msgstr ""
+msgid "Dependencies|Location and dependency path"
+msgstr ""
+
msgid "Dependencies|Packager"
msgstr ""
msgid "Dependencies|The %{codeStartTag}dependency_scanning%{codeEndTag} job has failed and cannot generate the list. Please ensure the job is running properly and run the pipeline again."
msgstr ""
+msgid "Dependencies|The component dependency path is based on the lock file. There may be several paths. In these cases, the longest path is displayed."
+msgstr ""
+
msgid "Dependencies|There may be multiple paths"
msgstr ""
@@ -8448,9 +8825,6 @@ msgstr ""
msgid "Deploy to..."
msgstr ""
-msgid "DeployBoard|Matching on the %{appLabel} label has been removed for deploy boards. To see all instances on your board, you must update your chart and redeploy."
-msgstr ""
-
msgid "DeployFreeze|Freeze end"
msgstr ""
@@ -8616,6 +8990,12 @@ msgstr ""
msgid "Deployed to"
msgstr ""
+msgid "Deployed-after"
+msgstr ""
+
+msgid "Deployed-before"
+msgstr ""
+
msgid "Deploying to"
msgstr ""
@@ -8790,6 +9170,9 @@ msgstr ""
msgid "DesignManagement|The maximum number of designs allowed to be uploaded is %{upload_limit}. Please try again."
msgstr ""
+msgid "DesignManagement|There was an error moving your designs. Please upload your designs below."
+msgstr ""
+
msgid "DesignManagement|To upload designs, you'll need to enable LFS and have admin enable hashed storage. %{requirements_link_start}More information%{requirements_link_end}"
msgstr ""
@@ -8802,6 +9185,9 @@ msgstr ""
msgid "DesignManagement|Upload skipped."
msgstr ""
+msgid "DesignManagement|Your designs are being copied and are on their way… Please refresh to update."
+msgstr ""
+
msgid "DesignManagement|and %{moreCount} more."
msgstr ""
@@ -8859,6 +9245,9 @@ msgstr ""
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
+msgid "Direct member"
+msgstr ""
+
msgid "Direction"
msgstr ""
@@ -8877,7 +9266,7 @@ msgstr ""
msgid "Disable public access to Pages sites"
msgstr ""
-msgid "Disable shared Runners"
+msgid "Disable shared runners"
msgstr ""
msgid "Disable two-factor authentication"
@@ -8907,9 +9296,6 @@ msgstr ""
msgid "Discard draft"
msgstr ""
-msgid "Discard review"
-msgstr ""
-
msgid "DiscordService|Discord Notifications"
msgstr ""
@@ -8978,10 +9364,10 @@ msgstr ""
msgid "Dismiss Merge Request promotion"
msgstr ""
-msgid "Dismiss Selected"
+msgid "Dismiss Value Stream Analytics introduction box"
msgstr ""
-msgid "Dismiss Value Stream Analytics introduction box"
+msgid "Dismiss selected"
msgstr ""
msgid "Dismiss trial promotion"
@@ -9029,10 +9415,10 @@ msgstr ""
msgid "Documentation for popular identity providers"
msgstr ""
-msgid "Documents reindexed: %{processed_documents} (%{percentage}%%)"
+msgid "Documentation pages URL"
msgstr ""
-msgid "Doing"
+msgid "Documents reindexed: %{processed_documents} (%{percentage}%%)"
msgstr ""
msgid "Domain"
@@ -9089,9 +9475,6 @@ msgstr ""
msgid "Download as CSV"
msgstr ""
-msgid "Download asset"
-msgstr ""
-
msgid "Download codes"
msgstr ""
@@ -9230,10 +9613,10 @@ msgstr ""
msgid "Edit environment"
msgstr ""
-msgid "Edit file"
+msgid "Edit files in the editor and commit changes here"
msgstr ""
-msgid "Edit files in the editor and commit changes here"
+msgid "Edit fork in Web IDE"
msgstr ""
msgid "Edit group: %{group_name}"
@@ -9242,6 +9625,12 @@ msgstr ""
msgid "Edit identity for %{user_name}"
msgstr ""
+msgid "Edit in Web IDE"
+msgstr ""
+
+msgid "Edit in single-file editor"
+msgstr ""
+
msgid "Edit issues"
msgstr ""
@@ -9254,15 +9643,24 @@ msgstr ""
msgid "Edit stage"
msgstr ""
+msgid "Edit this file only."
+msgstr ""
+
msgid "Edit this release"
msgstr ""
+msgid "Edit title and description"
+msgstr ""
+
msgid "Edit wiki page"
msgstr ""
msgid "Edit your most recent comment in a thread (from an empty textarea)"
msgstr ""
+msgid "Edited"
+msgstr ""
+
msgid "Edited %{timeago}"
msgstr ""
@@ -9371,6 +9769,9 @@ msgstr ""
msgid "Emails sent from Service Desk will have this name"
msgstr ""
+msgid "Emails sent to %{email} will still be supported"
+msgstr ""
+
msgid "Emails separated by comma"
msgstr ""
@@ -9404,7 +9805,7 @@ msgstr ""
msgid "Enable"
msgstr ""
-msgid "Enable %{gitpod_link} integration to launch a development environment in your browser directly from GitLab."
+msgid "Enable %{link_start}Gitpod%{link_end} integration to launch a development environment in your browser directly from GitLab."
msgstr ""
msgid "Enable Auto DevOps"
@@ -9500,7 +9901,13 @@ msgstr ""
msgid "Enable reCAPTCHA or Akismet and set IP limits. For reCAPTCHA, we currently only support %{recaptcha_v2_link_start}v2%{recaptcha_v2_link_end}"
msgstr ""
-msgid "Enable shared Runners"
+msgid "Enable shared runners"
+msgstr ""
+
+msgid "Enable shared runners for all projects and subgroups in this group."
+msgstr ""
+
+msgid "Enable shared runners for this group"
msgstr ""
msgid "Enable snowplow tracking"
@@ -9545,6 +9952,9 @@ msgstr ""
msgid "Encountered an error while rendering: %{err}"
msgstr ""
+msgid "End Time"
+msgstr ""
+
msgid "Ends at (UTC)"
msgstr ""
@@ -10106,6 +10516,9 @@ msgstr ""
msgid "Error occurred when saving assignees"
msgstr ""
+msgid "Error occurred when saving reviewers"
+msgstr ""
+
msgid "Error occurred when toggling the notification subscription"
msgstr ""
@@ -10331,6 +10744,9 @@ msgstr ""
msgid "Except policy:"
msgstr ""
+msgid "Excess storage"
+msgstr ""
+
msgid "Excluding merge commits. Limited to %{limit} commits."
msgstr ""
@@ -10361,6 +10777,9 @@ msgstr ""
msgid "Expand all files"
msgstr ""
+msgid "Expand all threads"
+msgstr ""
+
msgid "Expand approvers"
msgstr ""
@@ -10577,6 +10996,9 @@ msgstr ""
msgid "Failed to load branches. Please try again."
msgstr ""
+msgid "Failed to load deploy keys."
+msgstr ""
+
msgid "Failed to load emoji list."
msgstr ""
@@ -10592,6 +11014,9 @@ msgstr ""
msgid "Failed to load groups & users."
msgstr ""
+msgid "Failed to load groups, users and deploy keys."
+msgstr ""
+
msgid "Failed to load labels. Please try again."
msgstr ""
@@ -10601,6 +11026,12 @@ msgstr ""
msgid "Failed to load related branches"
msgstr ""
+msgid "Failed to load sidebar confidential toggle"
+msgstr ""
+
+msgid "Failed to load sidebar lock status"
+msgstr ""
+
msgid "Failed to load stacktrace."
msgstr ""
@@ -10741,6 +11172,18 @@ msgid_plural "FeatureFlags|%d users"
msgstr[0] ""
msgstr[1] ""
+msgid "FeatureFlags|%{percent} by available ID"
+msgstr ""
+
+msgid "FeatureFlags|%{percent} by session ID"
+msgstr ""
+
+msgid "FeatureFlags|%{percent} by user ID"
+msgstr ""
+
+msgid "FeatureFlags|%{percent} randomly"
+msgstr ""
+
msgid "FeatureFlags|* (All Environments)"
msgstr ""
@@ -10771,6 +11214,9 @@ msgstr ""
msgid "FeatureFlags|Configure feature flags"
msgstr ""
+msgid "FeatureFlags|Consider using the more flexible \"Percent rollout\" strategy instead."
+msgstr ""
+
msgid "FeatureFlags|Create feature flag"
msgstr ""
@@ -10822,6 +11268,9 @@ msgstr ""
msgid "FeatureFlags|Feature flags allow you to configure your code into different flavors by dynamically toggling certain functionality."
msgstr ""
+msgid "FeatureFlags|Feature flags limit reached (%{featureFlagsLimit}). Delete one or more feature flags before adding new ones."
+msgstr ""
+
msgid "FeatureFlags|Flag becomes read only soon"
msgstr ""
@@ -10861,6 +11310,9 @@ msgstr ""
msgid "FeatureFlags|Loading feature flags"
msgstr ""
+msgid "FeatureFlags|Loading user lists"
+msgstr ""
+
msgid "FeatureFlags|More information"
msgstr ""
@@ -10879,12 +11331,15 @@ msgstr ""
msgid "FeatureFlags|New feature flag"
msgstr ""
-msgid "FeatureFlags|New list"
+msgid "FeatureFlags|New user list"
msgstr ""
msgid "FeatureFlags|Percent of users"
msgstr ""
+msgid "FeatureFlags|Percent rollout"
+msgstr ""
+
msgid "FeatureFlags|Percent rollout (logged in users)"
msgstr ""
@@ -10918,6 +11373,9 @@ msgstr ""
msgid "FeatureFlags|There was an error fetching the feature flags."
msgstr ""
+msgid "FeatureFlags|There was an error fetching the user lists."
+msgstr ""
+
msgid "FeatureFlags|There was an error retrieving user lists"
msgstr ""
@@ -10933,6 +11391,9 @@ msgstr ""
msgid "FeatureFlags|User List"
msgstr ""
+msgid "FeatureFlags|User Lists"
+msgstr ""
+
msgid "FeatureFlag|List"
msgstr ""
@@ -10942,6 +11403,9 @@ msgstr ""
msgid "FeatureFlag|Select a user list"
msgstr ""
+msgid "FeatureFlag|Select the environment scope for this feature flag"
+msgstr ""
+
msgid "FeatureFlag|There are no configured user lists"
msgstr ""
@@ -11008,6 +11472,9 @@ msgstr ""
msgid "File upload error."
msgstr ""
+msgid "Filename"
+msgstr ""
+
msgid "Files"
msgstr ""
@@ -11074,6 +11541,9 @@ msgstr ""
msgid "Filter by user"
msgstr ""
+msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
+msgstr ""
+
msgid "Filter pipelines"
msgstr ""
@@ -11098,7 +11568,10 @@ msgstr ""
msgid "Find File"
msgstr ""
-msgid "Find bugs in your code with coverage-guided fuzzing"
+msgid "Find bugs in your code with API fuzzing."
+msgstr ""
+
+msgid "Find bugs in your code with coverage-guided fuzzing."
msgstr ""
msgid "Find by path"
@@ -11125,18 +11598,12 @@ msgstr ""
msgid "Finish editing this message first!"
msgstr ""
-msgid "Finish review"
-msgstr ""
-
msgid "Finish setting up your dedicated account for %{group_name}."
msgstr ""
msgid "Finished"
msgstr ""
-msgid "First Name is too long (maximum is %{max_length} characters)."
-msgstr ""
-
msgid "First Seen"
msgstr ""
@@ -11146,9 +11613,15 @@ msgstr ""
msgid "First name"
msgstr ""
+msgid "First name is too long (maximum is %{max_length} characters)."
+msgstr ""
+
msgid "First seen"
msgstr ""
+msgid "Fixed burndown chart"
+msgstr ""
+
msgid "Fixed date"
msgstr ""
@@ -11209,6 +11682,9 @@ msgstr ""
msgid "For more info, read the documentation."
msgstr ""
+msgid "For more information on how the number of active users is calculated, see the %{self_managed_subscriptions_doc_link} documentation."
+msgstr ""
+
msgid "For more information, go to the "
msgstr ""
@@ -11746,7 +12222,7 @@ msgstr ""
msgid "Git LFS is not enabled on this GitLab server, contact your admin."
msgstr ""
-msgid "Git LFS objects will be synced in pull mirrors if LFS is %{docs_link_start}enabled for the project%{docs_link_end}. They will %{strong_open}not%{strong_close} be synced in push mirrors."
+msgid "Git LFS objects will be synced if LFS is %{docs_link_start}enabled for the project%{docs_link_end}. Push mirrors will %{strong_open}not%{strong_close} sync LFS objects over SSH."
msgstr ""
msgid "Git LFS status:"
@@ -11785,6 +12261,9 @@ msgstr ""
msgid "GitLab API"
msgstr ""
+msgid "GitLab Billing Team."
+msgstr ""
+
msgid "GitLab Group Runners can execute code for all the projects in this group."
msgstr ""
@@ -11800,9 +12279,6 @@ msgstr ""
msgid "GitLab Service Desk is a simple way to allow people to create issues in your GitLab instance without needing their own user account. It provides a unique email address for end users to create issues in a project, and replies can be sent either through the GitLab interface or by email. End users will only see the thread through email."
msgstr ""
-msgid "GitLab Shared Runners execute code of different projects on the same Runner unless you configure GitLab Runner Autoscale with MaxBuilds 1 (which it is on GitLab.com)."
-msgstr ""
-
msgid "GitLab Shell"
msgstr ""
@@ -12139,6 +12615,9 @@ msgstr ""
msgid "Go to your snippets"
msgstr ""
+msgid "Goal of the changes and what reviewers should be aware of"
+msgstr ""
+
msgid "Google Cloud Platform"
msgstr ""
@@ -12244,7 +12723,7 @@ msgstr ""
msgid "Group avatar"
msgstr ""
-msgid "Group by:"
+msgid "Group by"
msgstr ""
msgid "Group description"
@@ -12505,9 +12984,6 @@ msgstr ""
msgid "GroupSAML|Valid SAML Response"
msgstr ""
-msgid "GroupSAML|With group managed accounts enabled, all the users without a group managed account will be excluded from the group."
-msgstr ""
-
msgid "GroupSAML|With prohibit outer forks flag enabled group members will be able to fork project only inside your group."
msgstr ""
@@ -12867,6 +13343,9 @@ msgid_plural "Hide charts"
msgstr[0] ""
msgstr[1] ""
+msgid "Hide comments on this file"
+msgstr ""
+
msgid "Hide details"
msgstr ""
@@ -12920,6 +13399,9 @@ msgstr ""
msgid "HighlightBar|Original alert:"
msgstr ""
+msgid "HighlightBar|Time to SLA:"
+msgstr ""
+
msgid "History"
msgstr ""
@@ -12974,9 +13456,6 @@ msgstr ""
msgid "However, you are already a member of this %{member_source}. Sign in using a different account to accept the invitation."
msgstr ""
-msgid "I accept the %{terms_link_start}Terms of Service and Privacy Policy%{terms_link_end}"
-msgstr ""
-
msgid "I accept the %{terms_link}"
msgstr ""
@@ -13097,6 +13576,12 @@ msgstr ""
msgid "If enabled, access to projects will be validated on an external service using their classification label."
msgstr ""
+msgid "If the YouTube URL is https://www.youtube.com/watch?v=0t1DgySidms then the video ID is %{id}"
+msgstr ""
+
+msgid "If the number of active users exceeds the user limit, you will be charged for the number of %{users_over_license_link} at your next license reconciliation."
+msgstr ""
+
msgid "If there is no previous license or if the previous license has expired, some GitLab functionality will be blocked until a new, valid license is uploaded."
msgstr ""
@@ -13118,9 +13603,6 @@ msgstr ""
msgid "If you lose your recovery codes you can generate new ones, invalidating all previous codes."
msgstr ""
-msgid "If you reach 100%% storage capacity, you will not be able to: %{base_message}"
-msgstr ""
-
msgid "If you recently signed in and recognize the IP address, you may disregard this email."
msgstr ""
@@ -13142,10 +13624,10 @@ msgstr ""
msgid "Ignored"
msgstr ""
-msgid "Image Details"
+msgid "Image URL"
msgstr ""
-msgid "Image URL"
+msgid "Image details"
msgstr ""
msgid "ImageDiffViewer|2-up"
@@ -13227,6 +13709,9 @@ msgstr ""
msgid "Import project"
msgstr ""
+msgid "Import project from"
+msgstr ""
+
msgid "Import project members"
msgstr ""
@@ -13347,6 +13832,12 @@ msgstr ""
msgid "Incident Management Limits"
msgstr ""
+msgid "IncidentManagement|%{hours} hours, %{minutes} minutes remaining"
+msgstr ""
+
+msgid "IncidentManagement|%{minutes} minutes remaining"
+msgstr ""
+
msgid "IncidentManagement|All"
msgstr ""
@@ -13407,6 +13898,9 @@ msgstr ""
msgid "IncidentManagement|There was an error displaying the incidents."
msgstr ""
+msgid "IncidentManagement|Time to SLA"
+msgstr ""
+
msgid "IncidentManagement|Unassigned"
msgstr ""
@@ -13416,12 +13910,18 @@ msgstr ""
msgid "IncidentManagement|Unpublished"
msgstr ""
+msgid "IncidentSettings|Activate \"time to SLA\" countdown timer"
+msgstr ""
+
msgid "IncidentSettings|Alert integration"
msgstr ""
msgid "IncidentSettings|Grafana integration"
msgstr ""
+msgid "IncidentSettings|Incident settings"
+msgstr ""
+
msgid "IncidentSettings|Incidents"
msgstr ""
@@ -13431,6 +13931,30 @@ msgstr ""
msgid "IncidentSettings|Set up integrations with external tools to help better manage incidents."
msgstr ""
+msgid "IncidentSettings|Time limit"
+msgstr ""
+
+msgid "IncidentSettings|Time limit must be a multiple of 15 minutes"
+msgstr ""
+
+msgid "IncidentSettings|Time limit must be a valid number"
+msgstr ""
+
+msgid "IncidentSettings|Time limit must be greater than 0"
+msgstr ""
+
+msgid "IncidentSettings|When activated, this will apply to all new incidents within the project"
+msgstr ""
+
+msgid "IncidentSettings|You may choose to introduce a countdown timer in incident issues to better track Service Level Agreements (SLAs). The timer is automatically started when the incident is created, and sets a time limit for the incident to be resolved in. When activated, \"time to SLA\" countdown will appear on all new incidents."
+msgstr ""
+
+msgid "IncidentSettings|hours"
+msgstr ""
+
+msgid "IncidentSettings|minutes"
+msgstr ""
+
msgid "Incidents"
msgstr ""
@@ -13443,6 +13967,9 @@ msgstr ""
msgid "Incident|There was an issue loading alert data. Please try again."
msgstr ""
+msgid "Incident|There was an issue loading incident data. Please try again."
+msgstr ""
+
msgid "Include a Terms of Service agreement and Privacy Policy that all users must accept."
msgstr ""
@@ -13503,6 +14030,9 @@ msgstr ""
msgid "Information about additional Pages templates and how to install them can be found in our %{pages_getting_started_guide}."
msgstr ""
+msgid "Inherited"
+msgstr ""
+
msgid "Inherited:"
msgstr ""
@@ -13515,27 +14045,33 @@ msgstr ""
msgid "Input your repository URL"
msgstr ""
-msgid "Insert"
-msgstr ""
-
msgid "Insert a code block"
msgstr ""
msgid "Insert a quote"
msgstr ""
+msgid "Insert a video"
+msgstr ""
+
msgid "Insert an image"
msgstr ""
msgid "Insert code"
msgstr ""
+msgid "Insert image"
+msgstr ""
+
msgid "Insert inline code"
msgstr ""
msgid "Insert suggestion"
msgstr ""
+msgid "Insert video"
+msgstr ""
+
msgid "Insights"
msgstr ""
@@ -13583,6 +14119,54 @@ msgstr ""
msgid "Instance administrators group already exists"
msgstr ""
+msgid "InstanceAnalytics|Canceled"
+msgstr ""
+
+msgid "InstanceAnalytics|Could not load the pipelines chart. Please refresh the page to try again."
+msgstr ""
+
+msgid "InstanceAnalytics|Failed"
+msgstr ""
+
+msgid "InstanceAnalytics|Items"
+msgstr ""
+
+msgid "InstanceAnalytics|Month"
+msgstr ""
+
+msgid "InstanceAnalytics|Pipelines"
+msgstr ""
+
+msgid "InstanceAnalytics|Skipped"
+msgstr ""
+
+msgid "InstanceAnalytics|Succeeded"
+msgstr ""
+
+msgid "InstanceAnalytics|There is no data available."
+msgstr ""
+
+msgid "InstanceAnalytics|Total"
+msgstr ""
+
+msgid "InstanceStatistics|Groups"
+msgstr ""
+
+msgid "InstanceStatistics|Issues"
+msgstr ""
+
+msgid "InstanceStatistics|Merge Requests"
+msgstr ""
+
+msgid "InstanceStatistics|Pipelines"
+msgstr ""
+
+msgid "InstanceStatistics|Projects"
+msgstr ""
+
+msgid "InstanceStatistics|Users"
+msgstr ""
+
msgid "Integration"
msgstr ""
@@ -13628,18 +14212,39 @@ msgstr ""
msgid "Integrations|Includes commit title and branch"
msgstr ""
+msgid "Integrations|Projects using custom settings will not be impacted unless the project owner chooses to use instance-level defaults."
+msgstr ""
+
+msgid "Integrations|Return to GitLab for Jira"
+msgstr ""
+
+msgid "Integrations|Save settings?"
+msgstr ""
+
+msgid "Integrations|Saving will update the default settings for all projects that are not using custom settings."
+msgstr ""
+
msgid "Integrations|Standard"
msgstr ""
+msgid "Integrations|Update your projects on Packagist, the main Composer repository"
+msgstr ""
+
msgid "Integrations|Use custom settings"
msgstr ""
msgid "Integrations|Use default settings"
msgstr ""
+msgid "Integrations|Use the GitLab Slack application"
+msgstr ""
+
msgid "Integrations|When a Jira issue is mentioned in a commit or merge request a remote link and comment (if enabled) will be created."
msgstr ""
+msgid "Integrations|You can now close this window and return to the GitLab for Jira application."
+msgstr ""
+
msgid "Interested parties can even contribute by pushing commits if they want to."
msgstr ""
@@ -13658,6 +14263,9 @@ msgstr ""
msgid "Internal users"
msgstr ""
+msgid "Internal users cannot be deactivated"
+msgstr ""
+
msgid "Interval Pattern"
msgstr ""
@@ -13682,9 +14290,6 @@ msgstr ""
msgid "Invalid URL"
msgstr ""
-msgid "Invalid board"
-msgstr ""
-
msgid "Invalid container_name"
msgstr ""
@@ -13760,6 +14365,9 @@ msgstr ""
msgid "Invitation"
msgstr ""
+msgid "Invitation declined"
+msgstr ""
+
msgid "Invite"
msgstr ""
@@ -13811,6 +14419,96 @@ 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|%{linkStart}Read more%{linkEnd} about role permissions"
+msgstr ""
+
+msgid "InviteMembersModal|Access expiration date (optional)"
+msgstr ""
+
+msgid "InviteMembersModal|Cancel"
+msgstr ""
+
+msgid "InviteMembersModal|Choose a role permission"
+msgstr ""
+
+msgid "InviteMembersModal|GitLab member or Email address"
+msgstr ""
+
+msgid "InviteMembersModal|Invite"
+msgstr ""
+
+msgid "InviteMembersModal|Invite team members"
+msgstr ""
+
+msgid "InviteMembersModal|Search for members to invite"
+msgstr ""
+
+msgid "InviteMembersModal|User not invited. Feature coming soon!"
+msgstr ""
+
+msgid "InviteMembersModal|Users were succesfully added"
+msgstr ""
+
+msgid "InviteMembersModal|You're inviting members to the %{group_name} group"
+msgstr ""
+
+msgid "InviteMembers|Invite team members"
+msgstr ""
+
+msgid "InviteMember|Oops, this feature isn't ready yet"
+msgstr ""
+
+msgid "InviteMember|See who can invite members for you"
+msgstr ""
+
+msgid "InviteMember|Until then, ask an owner to invite new project members for you"
+msgstr ""
+
+msgid "InviteMember|We're working to allow everyone to invite new members, making it easier for teams to get started with GitLab"
+msgstr ""
+
+msgid "InviteReminderEmail|%{inviter} is still waiting for you to join GitLab"
+msgstr ""
+
+msgid "InviteReminderEmail|%{inviter} is waiting for you to join GitLab"
+msgstr ""
+
+msgid "InviteReminderEmail|%{inviter} is waiting for you to join the %{strong_start}%{project_or_group_name}%{strong_end} %{project_or_group} as a %{role}."
+msgstr ""
+
+msgid "InviteReminderEmail|%{inviter}'s invitation to GitLab is pending"
+msgstr ""
+
+msgid "InviteReminderEmail|Accept invitation"
+msgstr ""
+
+msgid "InviteReminderEmail|Accept invitation: %{invite_url}"
+msgstr ""
+
+msgid "InviteReminderEmail|Decline invitation"
+msgstr ""
+
+msgid "InviteReminderEmail|Decline invitation: %{decline_url}"
+msgstr ""
+
+msgid "InviteReminderEmail|Hey there %{wave_emoji}"
+msgstr ""
+
+msgid "InviteReminderEmail|Hey there!"
+msgstr ""
+
+msgid "InviteReminderEmail|In case you missed it..."
+msgstr ""
+
+msgid "InviteReminderEmail|Invitation pending"
+msgstr ""
+
+msgid "InviteReminderEmail|It's been %{invitation_age} days since %{inviter} invited you to join the %{strong_start}%{project_or_group_name}%{strong_end} %{project_or_group} as a %{role}. What would you like to do?"
+msgstr ""
+
+msgid "InviteReminderEmail|This is a friendly reminder that %{inviter} invited you to join the %{strong_start}%{project_or_group_name}%{strong_end} %{project_or_group} as a %{role}."
+msgstr ""
+
msgid "Invited"
msgstr ""
@@ -13865,6 +14563,9 @@ msgstr ""
msgid "Issue cannot be found."
msgstr ""
+msgid "Issue created from vulnerability %{vulnerability_link}"
+msgstr ""
+
msgid "Issue events"
msgstr ""
@@ -14309,9 +15010,6 @@ msgstr ""
msgid "July"
msgstr ""
-msgid "Jump to first unresolved thread"
-msgstr ""
-
msgid "Jump to next unresolved thread"
msgstr ""
@@ -14330,6 +15028,9 @@ msgstr ""
msgid "Keep divergent refs"
msgstr ""
+msgid "Keep editing"
+msgstr ""
+
msgid "Kerberos access denied"
msgstr ""
@@ -14348,6 +15049,12 @@ msgstr ""
msgid "KeyboardKey|Ctrl+"
msgstr ""
+msgid "KeyboardShortcuts|Global Shortcuts"
+msgstr ""
+
+msgid "KeyboardShortcuts|Toggle the Performance Bar"
+msgstr ""
+
msgid "Keys"
msgstr ""
@@ -14396,6 +15103,9 @@ msgstr ""
msgid "LDAP Synchronization"
msgstr ""
+msgid "LDAP group settings"
+msgstr ""
+
msgid "LDAP settings"
msgstr ""
@@ -14405,6 +15115,9 @@ msgstr ""
msgid "LDAP sync in progress. This could take a few minutes. Refresh the page to see the changes."
msgstr ""
+msgid "LDAP synchronizations"
+msgstr ""
+
msgid "LFS"
msgstr ""
@@ -14471,9 +15184,6 @@ msgstr ""
msgid "Labels|Promoting %{labelTitle} will make it available for all projects inside %{groupName}. Existing project labels with the same title will be merged. If a group label with the same title exists, it will also be merged. This action cannot be reversed."
msgstr ""
-msgid "Labels|and %{count} more"
-msgstr ""
-
msgid "Language"
msgstr ""
@@ -14485,9 +15195,6 @@ msgid_plural "Last %d days"
msgstr[0] ""
msgstr[1] ""
-msgid "Last %{days} days"
-msgstr ""
-
msgid "Last 2 weeks"
msgstr ""
@@ -14503,9 +15210,6 @@ msgstr ""
msgid "Last Accessed On"
msgstr ""
-msgid "Last Name is too long (maximum is %{max_length} characters)."
-msgstr ""
-
msgid "Last Pipeline"
msgstr ""
@@ -14539,6 +15243,9 @@ msgstr ""
msgid "Last name"
msgstr ""
+msgid "Last name is too long (maximum is %{max_length} characters)."
+msgstr ""
+
msgid "Last reply by"
msgstr ""
@@ -14617,6 +15324,9 @@ msgstr ""
msgid "Learn more"
msgstr ""
+msgid "Learn more about %{username}"
+msgstr ""
+
msgid "Learn more about Auto DevOps"
msgstr ""
@@ -14692,6 +15402,9 @@ msgstr ""
msgid "Leave zen mode"
msgstr ""
+msgid "Legacy burndown chart"
+msgstr ""
+
msgid "Let's Encrypt does not accept emails on example.com"
msgstr ""
@@ -14976,6 +15689,9 @@ msgstr ""
msgid "List of all merge commits"
msgstr ""
+msgid "List options"
+msgstr ""
+
msgid "List settings"
msgstr ""
@@ -14988,9 +15704,6 @@ msgstr ""
msgid "List your Bitbucket Server repositories"
msgstr ""
-msgid "Lists"
-msgstr ""
-
msgid "Live preview"
msgstr ""
@@ -15231,10 +15944,13 @@ msgstr ""
msgid "March"
msgstr ""
-msgid "Mark To Do as done"
+msgid "Mark as done"
msgstr ""
-msgid "Mark as done"
+msgid "Mark as draft"
+msgstr ""
+
+msgid "Mark as ready"
msgstr ""
msgid "Mark as resolved"
@@ -15246,6 +15962,9 @@ msgstr ""
msgid "Mark this issue as related to another issue"
msgstr ""
+msgid "Mark to do as done"
+msgstr ""
+
msgid "Markdown"
msgstr ""
@@ -15279,9 +15998,6 @@ msgstr ""
msgid "Marked For Deletion At - %{deletion_time}"
msgstr ""
-msgid "Marked To Do as done."
-msgstr ""
-
msgid "Marked this %{noun} as Work In Progress."
msgstr ""
@@ -15291,7 +16007,7 @@ msgstr ""
msgid "Marked this issue as related to %{issue_ref}."
msgstr ""
-msgid "Marks To Do as done."
+msgid "Marked to do as done."
msgstr ""
msgid "Marks this %{noun} as Work In Progress."
@@ -15303,6 +16019,9 @@ msgstr ""
msgid "Marks this issue as related to %{issue_ref}."
msgstr ""
+msgid "Marks to do as done."
+msgstr ""
+
msgid "Mask variable"
msgstr ""
@@ -15360,9 +16079,15 @@ msgstr ""
msgid "Max access level"
msgstr ""
+msgid "Max role"
+msgstr ""
+
msgid "Max size 15 MB"
msgstr ""
+msgid "MaxBuilds"
+msgstr ""
+
msgid "Maximum Conan package file size in bytes"
msgstr ""
@@ -15507,6 +16232,63 @@ msgstr ""
msgid "Members with access to %{strong_start}%{group_name}%{strong_end}"
msgstr ""
+msgid "Members|%{time} by %{user}"
+msgstr ""
+
+msgid "Members|An error occurred while updating the member's role, please try again."
+msgstr ""
+
+msgid "Members|Are you sure you want to deny %{usersName}'s request to join \"%{source}\""
+msgstr ""
+
+msgid "Members|Are you sure you want to leave \"%{source}\"?"
+msgstr ""
+
+msgid "Members|Are you sure you want to remove \"%{groupName}\"?"
+msgstr ""
+
+msgid "Members|Are you sure you want to remove %{usersName} from \"%{source}\""
+msgstr ""
+
+msgid "Members|Are you sure you want to remove this orphaned member from \"%{source}\""
+msgstr ""
+
+msgid "Members|Are you sure you want to revoke the invitation for %{inviteEmail} to join \"%{source}\""
+msgstr ""
+
+msgid "Members|Are you sure you want to withdraw your access request for \"%{source}\""
+msgstr ""
+
+msgid "Members|Expired"
+msgstr ""
+
+msgid "Members|Leave \"%{source}\""
+msgstr ""
+
+msgid "Members|No expiration set"
+msgstr ""
+
+msgid "Members|Remove \"%{groupName}\""
+msgstr ""
+
+msgid "Members|Remove group"
+msgstr ""
+
+msgid "Members|Role updated successfully."
+msgstr ""
+
+msgid "Members|in %{time}"
+msgstr ""
+
+msgid "Member|Deny access"
+msgstr ""
+
+msgid "Member|Remove member"
+msgstr ""
+
+msgid "Member|Revoke invite"
+msgstr ""
+
msgid "Memory Usage"
msgstr ""
@@ -15693,9 +16475,6 @@ msgstr ""
msgid "MergeRequests|Thread will be unresolved"
msgstr ""
-msgid "MergeRequests|Toggle comments for this file"
-msgstr ""
-
msgid "MergeRequests|View file @ %{commitId}"
msgstr ""
@@ -16525,6 +17304,30 @@ msgstr ""
msgid "Namespace:"
msgstr ""
+msgid "NamespaceStorageSize|%{namespace_name} contains a locked project"
+msgstr ""
+
+msgid "NamespaceStorageSize|%{namespace_name} is now read-only. You cannot: %{base_message}"
+msgstr ""
+
+msgid "NamespaceStorageSize|If you reach 100%% storage capacity, you will not be able to: %{base_message}"
+msgstr ""
+
+msgid "NamespaceStorageSize|Please purchase additional storage to unlock your projects over the free 10GB project limit. You can't %{base_message}"
+msgstr ""
+
+msgid "NamespaceStorageSize|You have consumed all of your additional storage, please purchase more to unlock your projects over the free 10GB limit. You can't %{base_message}"
+msgstr ""
+
+msgid "NamespaceStorageSize|You have reached %{usage_in_percent} of %{namespace_name}'s storage capacity (%{used_storage} of %{storage_limit})"
+msgstr ""
+
+msgid "NamespaceStorageSize|You have reached the free storage limit of 10GB on %{locked_project_count} projects. To unlock them, please purchase additional storage"
+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 ""
+
msgid "Namespaces"
msgstr ""
@@ -16657,6 +17460,9 @@ msgstr ""
msgid "NetworkPolicies|Name"
msgstr ""
+msgid "NetworkPolicies|Namespace"
+msgstr ""
+
msgid "NetworkPolicies|Network Policy"
msgstr ""
@@ -16723,6 +17529,9 @@ msgstr ""
msgid "NetworkPolicies|Traffic that does not match any rule will be blocked."
msgstr ""
+msgid "NetworkPolicies|Unable to parse policy"
+msgstr ""
+
msgid "NetworkPolicies|YAML editor"
msgstr ""
@@ -17118,6 +17927,9 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No members found"
+msgstr ""
+
msgid "No merge requests found"
msgstr ""
@@ -17235,9 +18047,18 @@ msgstr ""
msgid "None"
msgstr ""
+msgid "None of the group milestones have the same project as the release"
+msgstr ""
+
msgid "Not Implemented"
msgstr ""
+msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+msgstr ""
+
+msgid "Not all browsers support WebAuthn. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even from an unsupported browser."
+msgstr ""
+
msgid "Not all data has been processed yet, the accuracy of the chart for the selected timeframe is limited."
msgstr ""
@@ -17334,6 +18155,9 @@ msgstr ""
msgid "Notification settings saved"
msgstr ""
+msgid "NotificationEvent|Change reviewer merge request"
+msgstr ""
+
msgid "NotificationEvent|Close issue"
msgstr ""
@@ -17493,13 +18317,10 @@ msgstr ""
msgid "Omnibus Protected Paths throttle is active, and takes priority over these settings. From 12.4, Omnibus throttle is deprecated and will be removed in a future release. Please read the %{relative_url_link_start}Migrating Protected Paths documentation%{relative_url_link_end}."
msgstr ""
-msgid "On track"
-msgstr ""
-
-msgid "OnDemandScans|Attached branch"
+msgid "On"
msgstr ""
-msgid "OnDemandScans|Attached branch is where the scan job runs."
+msgid "On track"
msgstr ""
msgid "OnDemandScans|Could not fetch scanner profiles. Please refresh the page, or try again later."
@@ -17538,19 +18359,10 @@ msgstr ""
msgid "OnDemandScans|On-demand scans run outside the DevOps cycle and find vulnerabilities in your projects. %{learnMoreLinkStart}Learn more%{learnMoreLinkEnd}"
msgstr ""
-msgid "OnDemandScans|Only a passive scan can be performed on demand."
-msgstr ""
-
-msgid "OnDemandScans|Passive"
-msgstr ""
-
msgid "OnDemandScans|Run scan"
msgstr ""
-msgid "OnDemandScans|Scan mode"
-msgstr ""
-
-msgid "OnDemandScans|Scanner settings"
+msgid "OnDemandScans|Scanner profile"
msgstr ""
msgid "OnDemandScans|Schedule or run scans immediately against target sites. Currently available on-demand scan type: DAST. %{helpLinkStart}More information%{helpLinkEnd}"
@@ -17559,7 +18371,7 @@ msgstr ""
msgid "OnDemandScans|Select one of the existing profiles"
msgstr ""
-msgid "OnDemandScans|Site profiles"
+msgid "OnDemandScans|Site profile"
msgstr ""
msgid "OnDemandScans|Use existing scanner profile"
@@ -17663,9 +18475,6 @@ msgstr ""
msgid "Open Selection"
msgstr ""
-msgid "Open Web IDE"
-msgstr ""
-
msgid "Open comment type dropdown"
msgstr ""
@@ -17684,9 +18493,6 @@ msgstr ""
msgid "Open issues"
msgstr ""
-msgid "Open projects"
-msgstr ""
-
msgid "Open raw"
msgstr ""
@@ -17771,6 +18577,9 @@ msgstr ""
msgid "Origin"
msgstr ""
+msgid "Orphaned member"
+msgstr ""
+
msgid "Other Labels"
msgstr ""
@@ -17813,6 +18622,9 @@ msgstr ""
msgid "Overwrite diverged branches"
msgstr ""
+msgid "Owned by %{image_tag}"
+msgstr ""
+
msgid "Owned by anyone"
msgstr ""
@@ -17852,9 +18664,6 @@ msgstr ""
msgid "Package type must be PyPi"
msgstr ""
-msgid "Package was removed"
-msgstr ""
-
msgid "PackageRegistry|%{name} version %{version} was created %{datetime}"
msgstr ""
@@ -17867,6 +18676,9 @@ msgstr ""
msgid "PackageRegistry|Add NuGet Source"
msgstr ""
+msgid "PackageRegistry|Add composer registry"
+msgstr ""
+
msgid "PackageRegistry|App group: %{group}"
msgstr ""
@@ -17963,7 +18775,7 @@ msgstr ""
msgid "PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}pom.xml%{codeEnd} file."
msgstr ""
-msgid "PackageRegistry|Is your favorite package manager missing? We'd love your help in building first-class support for it into GitLab! %{contributionLinkStart}Visit the contribution documentation%{contributionLinkEnd} to learn more about how to build support for new package managers into GitLab. Below is a list of package managers that are on our radar."
+msgid "PackageRegistry|Install package version"
msgstr ""
msgid "PackageRegistry|Learn how to %{noPackagesLinkStart}publish and share your packages%{noPackagesLinkEnd} with GitLab."
@@ -17987,25 +18799,28 @@ msgstr ""
msgid "PackageRegistry|NPM"
msgstr ""
-msgid "PackageRegistry|No upcoming issues"
-msgstr ""
-
msgid "PackageRegistry|NuGet"
msgstr ""
msgid "PackageRegistry|NuGet Command"
msgstr ""
+msgid "PackageRegistry|Package Registry"
+msgstr ""
+
msgid "PackageRegistry|Pip Command"
msgstr ""
msgid "PackageRegistry|Pipeline %{link} triggered %{datetime} by %{author}"
msgstr ""
+msgid "PackageRegistry|Publish and share packages for a variety of common package managers. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "PackageRegistry|Published to the %{project} Package Registry %{datetime}"
msgstr ""
-msgid "PackageRegistry|PyPi"
+msgid "PackageRegistry|PyPI"
msgstr ""
msgid "PackageRegistry|Recipe: %{recipe}"
@@ -18029,9 +18844,6 @@ msgstr ""
msgid "PackageRegistry|There are no packages yet"
msgstr ""
-msgid "PackageRegistry|There are no upcoming issues to display."
-msgstr ""
-
msgid "PackageRegistry|There was a problem fetching the details for this package."
msgstr ""
@@ -18047,9 +18859,6 @@ msgstr ""
msgid "PackageRegistry|Unable to load package"
msgstr ""
-msgid "PackageRegistry|Upcoming package managers"
-msgstr ""
-
msgid "PackageRegistry|You are about to delete %{name}, this operation is irreversible, are you sure?"
msgstr ""
@@ -18059,12 +18868,6 @@ msgstr ""
msgid "PackageRegistry|You may also need to setup authentication using an auth token. %{linkStart}See the documentation%{linkEnd} to find out more."
msgstr ""
-msgid "PackageRegistry|composer.json registry include"
-msgstr ""
-
-msgid "PackageRegistry|composer.json require package include"
-msgstr ""
-
msgid "PackageRegistry|npm command"
msgstr ""
@@ -18089,7 +18892,7 @@ msgstr ""
msgid "PackageType|NuGet"
msgstr ""
-msgid "PackageType|PyPi"
+msgid "PackageType|PyPI"
msgstr ""
msgid "Packages"
@@ -18245,7 +19048,7 @@ msgstr ""
msgid "Paste issue link"
msgstr ""
-msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Don't use your private SSH key."
+msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Do not paste your private SSH key, as that can compromise your identity."
msgstr ""
msgid "Patch to apply"
@@ -18272,13 +19075,16 @@ msgstr ""
msgid "Pending"
msgstr ""
+msgid "Pending comments"
+msgstr ""
+
msgid "People without permission will never get a notification and won't be able to comment."
msgstr ""
msgid "People without permission will never get a notification."
msgstr ""
-msgid "Percent of users"
+msgid "Percent rollout must be a whole number between 0 and 100"
msgstr ""
msgid "Percentage"
@@ -18290,9 +19096,6 @@ msgstr ""
msgid "Perform common operations on GitLab project"
msgstr ""
-msgid "Performance and resource management"
-msgstr ""
-
msgid "Performance optimization"
msgstr ""
@@ -18470,6 +19273,9 @@ msgstr ""
msgid "Pipelines|Build with confidence"
msgstr ""
+msgid "Pipelines|By revoking a trigger you will break any processes making use of it. Are you sure?"
+msgstr ""
+
msgid "Pipelines|CI Lint"
msgstr ""
@@ -18482,6 +19288,15 @@ msgstr ""
msgid "Pipelines|Continuous Integration can help catch bugs by running your tests automatically, while Continuous Deployment can help you deliver code to your product environment."
msgstr ""
+msgid "Pipelines|Copy trigger token"
+msgstr ""
+
+msgid "Pipelines|Description"
+msgstr ""
+
+msgid "Pipelines|Edit"
+msgstr ""
+
msgid "Pipelines|Get started with Pipelines"
msgstr ""
@@ -18497,15 +19312,27 @@ msgstr ""
msgid "Pipelines|It is recommended the code is reviewed thoroughly before running this pipeline with the parent project's CI resource."
msgstr ""
+msgid "Pipelines|Last Used"
+msgstr ""
+
msgid "Pipelines|Loading Pipelines"
msgstr ""
msgid "Pipelines|More Information"
msgstr ""
+msgid "Pipelines|No triggers have been created yet. Add one using the form above."
+msgstr ""
+
+msgid "Pipelines|Owner"
+msgstr ""
+
msgid "Pipelines|Project cache successfully reset."
msgstr ""
+msgid "Pipelines|Revoke"
+msgstr ""
+
msgid "Pipelines|Run Pipeline"
msgstr ""
@@ -18530,6 +19357,15 @@ msgstr ""
msgid "Pipelines|This project is not currently set up to run pipelines."
msgstr ""
+msgid "Pipelines|Token"
+msgstr ""
+
+msgid "Pipelines|Trigger user has insufficient permissions to project"
+msgstr ""
+
+msgid "Pipelines|invalid"
+msgstr ""
+
msgid "Pipelines|parent"
msgstr ""
@@ -18782,12 +19618,18 @@ msgstr ""
msgid "Please provide a valid URL"
msgstr ""
+msgid "Please provide a valid YouTube URL or ID"
+msgstr ""
+
msgid "Please provide a valid email address."
msgstr ""
msgid "Please provide attributes to update"
msgstr ""
+msgid "Please reach out if you have any questions and we'll be happy to assist."
+msgstr ""
+
msgid "Please refer to %{docs_url}"
msgstr ""
@@ -18818,6 +19660,9 @@ msgstr ""
msgid "Please set a new password before proceeding."
msgstr ""
+msgid "Please share your feedback about %{featureName} %{linkStart}in this issue%{linkEnd} to help us improve the experience."
+msgstr ""
+
msgid "Please solve the reCAPTCHA"
msgstr ""
@@ -19226,7 +20071,7 @@ msgstr ""
msgid "Profiles|Full name"
msgstr ""
-msgid "Profiles|Give your individual key a title. This will be publically visible."
+msgid "Profiles|Give your individual key a title."
msgstr ""
msgid "Profiles|Include private contributions on my profile"
@@ -19316,7 +20161,7 @@ msgstr ""
msgid "Profiles|The maximum file size allowed is 200KB."
msgstr ""
-msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it?"
+msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it? It will be publicly visible."
msgstr ""
msgid "Profiles|This email will be displayed on your public profile"
@@ -19676,7 +20521,7 @@ msgstr ""
msgid "ProjectService|Event will be triggered when a confidential issue is created/updated/closed"
msgstr ""
-msgid "ProjectService|Event will be triggered when a deployment finishes"
+msgid "ProjectService|Event will be triggered when a deployment starts or finishes"
msgstr ""
msgid "ProjectService|Event will be triggered when a merge request is created/updated/merged"
@@ -19979,9 +20824,15 @@ msgstr ""
msgid "ProjectTemplates|Android"
msgstr ""
+msgid "ProjectTemplates|Basic"
+msgstr ""
+
msgid "ProjectTemplates|GitLab Cluster Management"
msgstr ""
+msgid "ProjectTemplates|Gitpod/Spring Petclinic"
+msgstr ""
+
msgid "ProjectTemplates|Go Micro"
msgstr ""
@@ -20030,6 +20881,9 @@ msgstr ""
msgid "ProjectTemplates|SalesforceDX"
msgstr ""
+msgid "ProjectTemplates|Serenity Valley"
+msgstr ""
+
msgid "ProjectTemplates|Serverless Framework/JS"
msgstr ""
@@ -20486,6 +21340,9 @@ msgstr ""
msgid "ProtectedBranch|Code owner approval"
msgstr ""
+msgid "ProtectedBranch|Does not apply to users allowed to push."
+msgstr ""
+
msgid "ProtectedBranch|Protect"
msgstr ""
@@ -20591,6 +21448,9 @@ msgstr ""
msgid "Publish to status page"
msgstr ""
+msgid "Published"
+msgstr ""
+
msgid "Published on status page"
msgstr ""
@@ -20609,6 +21469,9 @@ msgstr ""
msgid "Purchase more minutes"
msgstr ""
+msgid "Purchase more storage"
+msgstr ""
+
msgid "Push"
msgstr ""
@@ -20720,6 +21583,9 @@ msgstr ""
msgid "Rake Tasks Help"
msgstr ""
+msgid "Random"
+msgstr ""
+
msgid "Raw blob request rate limit per minute"
msgstr ""
@@ -20801,6 +21667,9 @@ msgstr ""
msgid "Refresh"
msgstr ""
+msgid "Refresh the page and try again."
+msgstr ""
+
msgid "Refreshing in a second to show the updated status..."
msgid_plural "Refreshing in %d seconds to show the updated status..."
msgstr[0] ""
@@ -20970,9 +21839,6 @@ msgstr ""
msgid "Release|Something went wrong while saving the release details"
msgstr ""
-msgid "Remediated: needs review"
-msgstr ""
-
msgid "Remediations"
msgstr ""
@@ -21060,6 +21926,9 @@ msgstr ""
msgid "Remove limit"
msgstr ""
+msgid "Remove list"
+msgstr ""
+
msgid "Remove member"
msgstr ""
@@ -21204,6 +22073,9 @@ msgstr ""
msgid "Reopen milestone"
msgstr ""
+msgid "Reopen test case"
+msgstr ""
+
msgid "Reopen this %{quick_action_target}"
msgstr ""
@@ -21231,6 +22103,9 @@ msgstr ""
msgid "Replication"
msgstr ""
+msgid "Replication details"
+msgstr ""
+
msgid "Replication enabled"
msgstr ""
@@ -21356,6 +22231,9 @@ msgstr ""
msgid "Repositories Analytics"
msgstr ""
+msgid "RepositoriesAnalytics|Coverage"
+msgstr ""
+
msgid "RepositoriesAnalytics|Download Historic Test Coverage Data"
msgstr ""
@@ -21368,9 +22246,24 @@ msgstr ""
msgid "RepositoriesAnalytics|Historic Test Coverage Data is available in raw format (.csv) for further analysis."
msgstr ""
+msgid "RepositoriesAnalytics|Last Update"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Number of Coverages"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Please select a project or multiple projects to display their most recent test coverage data."
+msgstr ""
+
+msgid "RepositoriesAnalytics|Please select projects to display."
+msgstr ""
+
msgid "RepositoriesAnalytics|Test Code Coverage"
msgstr ""
+msgid "RepositoriesAnalytics|There was an error fetching the projects."
+msgstr ""
+
msgid "Repository"
msgstr ""
@@ -21449,9 +22342,15 @@ msgstr ""
msgid "Request parameter %{param} is missing."
msgstr ""
+msgid "Request review from"
+msgstr ""
+
msgid "Request to link SAML account must be authorized"
msgstr ""
+msgid "Requested"
+msgstr ""
+
msgid "Requested %{time_ago}"
msgstr ""
@@ -21470,7 +22369,10 @@ msgstr ""
msgid "Requests to these domain(s)/address(es) on the local network will be allowed when local requests from hooks and services are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 or 127.0.0.0/28 are supported. Domain wildcards are not supported currently. Use comma, semicolon, or newline to separate multiple entries. The allowlist can hold a maximum of 1000 entries. Domains should use IDNA encoding. Ex: example.com, 192.168.1.1, 127.0.0.0/28, xn--itlab-j1a.com."
msgstr ""
-msgid "Require all users in this group to setup Two-factor authentication"
+msgid "Require admin approval for new sign-ups"
+msgstr ""
+
+msgid "Require all users in this group to setup two-factor authentication"
msgstr ""
msgid "Require all users to accept Terms of Service and Privacy Policy when they access GitLab."
@@ -21503,6 +22405,9 @@ msgstr ""
msgid "Requirement %{reference} has been updated"
msgstr ""
+msgid "Requirement title"
+msgstr ""
+
msgid "Requirement title cannot have more than %{limit} characters."
msgstr ""
@@ -21597,9 +22502,6 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
-msgid "Resolved by %{resolvedByName}"
-msgstr ""
-
msgid "Resolves IP addresses once and uses them to submit requests"
msgstr ""
@@ -21707,6 +22609,9 @@ msgstr ""
msgid "Review App|View latest app"
msgstr ""
+msgid "Review requested from %{name}"
+msgstr ""
+
msgid "Review the process for configuring service providers in your identity provider — in this case, GitLab is the \"service provider\" or \"relying party\"."
msgstr ""
@@ -21719,6 +22624,14 @@ msgstr ""
msgid "ReviewApp|Enable Review App"
msgstr ""
+msgid "Reviewer"
+msgid_plural "%d Reviewers"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Reviewer(s)"
+msgstr ""
+
msgid "Reviewing"
msgstr ""
@@ -21908,6 +22821,9 @@ msgstr ""
msgid "Runs a number of housekeeping tasks within the current repository, such as compressing file revisions and removing unreachable objects."
msgstr ""
+msgid "SAML"
+msgstr ""
+
msgid "SAML SSO"
msgstr ""
@@ -21953,6 +22869,12 @@ msgstr ""
msgid "SSL Verification:"
msgstr ""
+msgid "Sample Data"
+msgstr ""
+
+msgid "Satisfied"
+msgstr ""
+
msgid "Saturday"
msgstr ""
@@ -22004,6 +22926,9 @@ msgstr ""
msgid "Saving project."
msgstr ""
+msgid "Scanner"
+msgstr ""
+
msgid "Schedule a new pipeline"
msgstr ""
@@ -22034,9 +22959,6 @@ msgstr ""
msgid "Scope"
msgstr ""
-msgid "Scope not supported with disabled 'users_search' feature!"
-msgstr ""
-
msgid "Scoped issue boards"
msgstr ""
@@ -22163,12 +23085,6 @@ msgstr ""
msgid "Search requirements"
msgstr ""
-msgid "Search results…"
-msgstr ""
-
-msgid "Search test cases"
-msgstr ""
-
msgid "Search users"
msgstr ""
@@ -22241,6 +23157,11 @@ msgid_plural "SearchResults|commits"
msgstr[0] ""
msgstr[1] ""
+msgid "SearchResults|epic"
+msgid_plural "SearchResults|epics"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "SearchResults|issue"
msgid_plural "SearchResults|issues"
msgstr[0] ""
@@ -22285,6 +23206,12 @@ msgstr ""
msgid "Seat Link is disabled, and cannot be configured through this form."
msgstr ""
+msgid "Seats usage data as of %{last_enqueue_time} (Updated daily)"
+msgstr ""
+
+msgid "Seats usage data is updated every day at 12:00pm UTC"
+msgstr ""
+
msgid "Secondary"
msgstr ""
@@ -22324,10 +23251,10 @@ msgstr ""
msgid "SecurityApprovals|One or more of the security scanners must be enabled. %{linkStart}More information%{linkEnd}"
msgstr ""
-msgid "SecurityApprovals|Requires approval for vulnerabilties of Critical, High, or Unknown severity. %{linkStart}More information%{linkEnd}"
+msgid "SecurityApprovals|Requires approval for Denied licenses. %{linkStart}More information%{linkEnd}"
msgstr ""
-msgid "SecurityApprovals|Requires license policy rules for licenses of Allowed, or Denied. %{linkStart}More information%{linkEnd}"
+msgid "SecurityApprovals|Requires approval for vulnerabilities of Critical, High, or Unknown severity. %{linkStart}More information%{linkEnd}"
msgstr ""
msgid "SecurityConfiguration|An error occurred while creating the merge request."
@@ -22336,6 +23263,9 @@ msgstr ""
msgid "SecurityConfiguration|Available for on-demand DAST"
msgstr ""
+msgid "SecurityConfiguration|By default, all analyzers are applied in order to cover all languages across your project, and only run if the language is detected in the Merge Request."
+msgstr ""
+
msgid "SecurityConfiguration|Configure"
msgstr ""
@@ -22366,16 +23296,19 @@ msgstr ""
msgid "SecurityConfiguration|Manage"
msgstr ""
+msgid "SecurityConfiguration|More information"
+msgstr ""
+
msgid "SecurityConfiguration|Not enabled"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|Security Control"
+msgid "SecurityConfiguration|SAST Configuration"
msgstr ""
-msgid "SecurityConfiguration|See documentation"
+msgid "SecurityConfiguration|Security Control"
msgstr ""
msgid "SecurityConfiguration|Status"
@@ -22450,6 +23383,9 @@ msgstr ""
msgid "SecurityReports|Error fetching the vulnerability list. Please check your network connection and try again."
msgstr ""
+msgid "SecurityReports|Failed to get security report information. Please reload the page or try again later."
+msgstr ""
+
msgid "SecurityReports|False positive"
msgstr ""
@@ -22468,9 +23404,6 @@ msgstr ""
msgid "SecurityReports|Learn more about setting up your dashboard"
msgstr ""
-msgid "SecurityReports|Load more vulnerabilities"
-msgstr ""
-
msgid "SecurityReports|Monitor vulnerabilities in your code"
msgstr ""
@@ -22516,6 +23449,12 @@ msgstr ""
msgid "SecurityReports|Security reports can only be accessed by authorized users."
msgstr ""
+msgid "SecurityReports|Security reports help page link"
+msgstr ""
+
+msgid "SecurityReports|Security scans have run. Go to the %{linkStart}pipelines tab%{linkEnd} to download the security reports"
+msgstr ""
+
msgid "SecurityReports|Select a project to add by using the project search field above."
msgstr ""
@@ -22555,6 +23494,11 @@ msgstr ""
msgid "SecurityReports|There was an error deleting the comment."
msgstr ""
+msgid "SecurityReports|There was an error dismissing %d vulnerability. Please try again later."
+msgid_plural "SecurityReports|There was an error dismissing %d vulnerabilities. Please try again later."
+msgstr[0] ""
+msgstr[1] ""
+
msgid "SecurityReports|There was an error dismissing the vulnerabilities."
msgstr ""
@@ -22735,6 +23679,9 @@ msgstr ""
msgid "Select required regulatory standard"
msgstr ""
+msgid "Select reviewer(s)"
+msgstr ""
+
msgid "Select shards to replicate"
msgstr ""
@@ -22750,7 +23697,7 @@ msgstr ""
msgid "Select status"
msgstr ""
-msgid "Select strategy activation method."
+msgid "Select strategy activation method"
msgstr ""
msgid "Select subscription"
@@ -22765,12 +23712,6 @@ msgstr ""
msgid "Select the custom project template source group."
msgstr ""
-msgid "Select the environment scope for this feature flag."
-msgstr ""
-
-msgid "Select timeframe"
-msgstr ""
-
msgid "Select timezone"
msgstr ""
@@ -22864,6 +23805,9 @@ msgstr ""
msgid "September"
msgstr ""
+msgid "Serenity Valley Sample Data template."
+msgstr ""
+
msgid "SeriesFinalConjunction|and"
msgstr ""
@@ -22978,6 +23922,9 @@ msgstr ""
msgid "Service URL"
msgstr ""
+msgid "Session ID"
+msgstr ""
+
msgid "Session duration (minutes)"
msgstr ""
@@ -23098,6 +24045,9 @@ msgstr ""
msgid "Set up a %{type} Runner manually"
msgstr ""
+msgid "Set up a hardware device as a second factor to sign in."
+msgstr ""
+
msgid "Set up assertions/attributes/claims (email, first_name, last_name) and NameID according to %{docsLinkStart}the documentation %{icon}%{docsLinkEnd}"
msgstr ""
@@ -23110,6 +24060,9 @@ msgstr ""
msgid "Set up pipeline subscriptions for this project."
msgstr ""
+msgid "Set up shared runner availability"
+msgstr ""
+
msgid "Set up your project to automatically push and/or pull changes to/from another repository. Branches, tags, and commits will be synced automatically."
msgstr ""
@@ -23215,6 +24168,15 @@ msgstr ""
msgid "Shared projects"
msgstr ""
+msgid "Shared runners"
+msgstr ""
+
+msgid "Shared runners are disabled for the parent group"
+msgstr ""
+
+msgid "Shared runners disabled on group level"
+msgstr ""
+
msgid "Shared runners help link"
msgstr ""
@@ -23257,6 +24219,9 @@ msgstr ""
msgid "Show comments"
msgstr ""
+msgid "Show comments on this file"
+msgstr ""
+
msgid "Show comments only"
msgstr ""
@@ -23302,6 +24267,12 @@ msgstr ""
msgid "Show parent subgroups"
msgstr ""
+msgid "Show the Closed list"
+msgstr ""
+
+msgid "Show the Open list"
+msgstr ""
+
msgid "Show whitespace changes"
msgstr ""
@@ -23369,6 +24340,9 @@ msgstr ""
msgid "Sign in to \"%{group_name}\""
msgstr ""
+msgid "Sign in to GitLab"
+msgstr ""
+
msgid "Sign in using smart card"
msgstr ""
@@ -23405,9 +24379,6 @@ msgstr ""
msgid "SignUp|Last Name is too long (maximum is %{max_length} characters)."
msgstr ""
-msgid "SignUp|Name is too long (maximum is %{max_length} characters)."
-msgstr ""
-
msgid "SignUp|Username is too long (maximum is %{max_length} characters)."
msgstr ""
@@ -23417,6 +24388,9 @@ msgstr ""
msgid "Signed in"
msgstr ""
+msgid "Signed in to GitLab as %{user_link}"
+msgstr ""
+
msgid "Signed in with %{authentication} authentication"
msgstr ""
@@ -23528,27 +24502,18 @@ msgstr ""
msgid "Snippets|Add another file %{num}/%{total}"
msgstr ""
-msgid "Snippets|Authored %{time_ago} by %{author}"
-msgstr ""
-
msgid "Snippets|Delete file"
msgstr ""
msgid "Snippets|Description (optional)"
msgstr ""
-msgid "Snippets|File"
-msgstr ""
-
msgid "Snippets|Files"
msgstr ""
msgid "Snippets|Give your file a name to add code highlighting, e.g. example.rb for Ruby"
msgstr ""
-msgid "Snippets|Optionally add a description about what your snippet does or how to use it..."
-msgstr ""
-
msgid "Snippets|Optionally add a description about what your snippet does or how to use it…"
msgstr ""
@@ -23627,9 +24592,6 @@ msgstr ""
msgid "Something went wrong while creating a requirement."
msgstr ""
-msgid "Something went wrong while creating a test case."
-msgstr ""
-
msgid "Something went wrong while deleting description changes. Please try again."
msgstr ""
@@ -23654,9 +24616,6 @@ msgstr ""
msgid "Something went wrong while fetching comments. Please try again."
msgstr ""
-msgid "Something went wrong while fetching count of test cases."
-msgstr ""
-
msgid "Something went wrong while fetching description changes. Please try again."
msgstr ""
@@ -23681,9 +24640,6 @@ msgstr ""
msgid "Something went wrong while fetching requirements list."
msgstr ""
-msgid "Something went wrong while fetching test cases list."
-msgstr ""
-
msgid "Something went wrong while fetching the environments for this merge request. Please try again."
msgstr ""
@@ -23792,6 +24748,9 @@ msgstr ""
msgid "SortOptions|Access level, descending"
msgstr ""
+msgid "SortOptions|Blocking"
+msgstr ""
+
msgid "SortOptions|Created date"
msgstr ""
@@ -23942,9 +24901,6 @@ msgstr ""
msgid "Source branch: %{source_branch_open}%{source_branch}%{source_branch_close}"
msgstr ""
-msgid "Source code"
-msgstr ""
-
msgid "Source code (%{fileExtension})"
msgstr ""
@@ -24086,6 +25042,9 @@ msgstr ""
msgid "Start Date"
msgstr ""
+msgid "Start Time"
+msgstr ""
+
msgid "Start Web Terminal"
msgstr ""
@@ -24107,9 +25066,6 @@ msgstr ""
msgid "Start and due date"
msgstr ""
-msgid "Start by choosing a group to see how your team is spending time. You can then drill down to the project level."
-msgstr ""
-
msgid "Start by choosing a group to start exploring the merge requests in that group. You can then proceed to filter by projects, labels, milestones and authors."
msgstr ""
@@ -24191,18 +25147,27 @@ msgstr ""
msgid "StaticSiteEditor|3. Assign a person to review and accept the merge request."
msgstr ""
+msgid "StaticSiteEditor|A link to view the merge request will appear once ready."
+msgstr ""
+
msgid "StaticSiteEditor|An error occurred while submitting your changes."
msgstr ""
msgid "StaticSiteEditor|Branch could not be created."
msgstr ""
+msgid "StaticSiteEditor|Copy update"
+msgstr ""
+
msgid "StaticSiteEditor|Could not commit the content changes."
msgstr ""
msgid "StaticSiteEditor|Could not create merge request."
msgstr ""
+msgid "StaticSiteEditor|Creating your merge request"
+msgstr ""
+
msgid "StaticSiteEditor|Incompatible file content"
msgstr ""
@@ -24224,6 +25189,9 @@ msgstr ""
msgid "StaticSiteEditor|View documentation"
msgstr ""
+msgid "StaticSiteEditor|You can set an assignee to get your changes reviewed and deployed once your merge request is created."
+msgstr ""
+
msgid "StaticSiteEditor|Your merge request has been created"
msgstr ""
@@ -24356,10 +25324,10 @@ msgstr ""
msgid "Submit a review"
msgstr ""
-msgid "Submit as spam"
+msgid "Submit changes"
msgstr ""
-msgid "Submit changes"
+msgid "Submit changes..."
msgstr ""
msgid "Submit feedback"
@@ -24374,10 +25342,10 @@ msgstr ""
msgid "Submit search"
msgstr ""
-msgid "Submit test case"
+msgid "Submit the current review."
msgstr ""
-msgid "Submit the current review."
+msgid "Submit your changes"
msgstr ""
msgid "Submitted the current review."
@@ -24422,6 +25390,12 @@ msgstr ""
msgid "Subscription successfully deleted."
msgstr ""
+msgid "SubscriptionTable|An error occurred while loading billable members list"
+msgstr ""
+
+msgid "SubscriptionTable|An error occurred while loading the subscription details."
+msgstr ""
+
msgid "SubscriptionTable|Billing"
msgstr ""
@@ -24506,6 +25480,9 @@ msgstr ""
msgid "Successfully activated"
msgstr ""
+msgid "Successfully approved"
+msgstr ""
+
msgid "Successfully blocked"
msgstr ""
@@ -24920,6 +25897,42 @@ msgstr[1] ""
msgid "Test settings"
msgstr ""
+msgid "TestCases|New Test Case"
+msgstr ""
+
+msgid "TestCases|New test case"
+msgstr ""
+
+msgid "TestCases|Search test cases"
+msgstr ""
+
+msgid "TestCases|Something went wrong while adding test case to Todo."
+msgstr ""
+
+msgid "TestCases|Something went wrong while creating a test case."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching count of test cases."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching test case."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching test cases list."
+msgstr ""
+
+msgid "TestCases|Something went wrong while marking test case todo as done."
+msgstr ""
+
+msgid "TestCases|Something went wrong while updating the test case labels."
+msgstr ""
+
+msgid "TestCases|Something went wrong while updating the test case."
+msgstr ""
+
+msgid "TestCases|Submit test case"
+msgstr ""
+
msgid "TestHooks|Ensure one of your projects has merge requests."
msgstr ""
@@ -24983,6 +25996,9 @@ msgstr ""
msgid "Thank you for signing up for your free trial! You will get additional instructions in your inbox shortly."
msgstr ""
+msgid "Thank you for your business."
+msgstr ""
+
msgid "Thank you for your feedback!"
msgstr ""
@@ -24998,7 +26014,7 @@ msgstr ""
msgid "Thanks! Don't show me this again"
msgstr ""
-msgid "That's it, well done!%{celebrate}"
+msgid "That's it, well done!"
msgstr ""
msgid "The \"%{group_path}\" group allows you to sign in with your Single Sign-On Account"
@@ -25021,9 +26037,6 @@ msgstr ""
msgid "The CSV export will be created in the background. Once finished, it will be sent to %{strong_open}%{email}%{strong_close} in an attachment."
msgstr ""
-msgid "The Git LFS objects will %{strong_open}not%{strong_close} be synced."
-msgstr ""
-
msgid "The GitLab user to which the Jira user %{jiraDisplayName} will be mapped"
msgstr ""
@@ -25036,13 +26049,16 @@ msgstr ""
msgid "The Prometheus server responded with \"bad request\". Please check your queries are correct and are supported in your Prometheus version. %{documentationLink}"
msgstr ""
+msgid "The Security Dashboard shows the results of the last successful pipeline run on the default branch."
+msgstr ""
+
msgid "The URL defined on the primary node that secondary nodes should use to contact it."
msgstr ""
-msgid "The URL to use for connecting to Elasticsearch. Use a comma-separated list to support clustering (e.g., \"http://localhost:9200, http://localhost:9201\")."
+msgid "The URL defined on the primary node that secondary nodes should use to contact it. %{linkStart}More information%{linkEnd}"
msgstr ""
-msgid "The Web IDE offers advanced syntax highlighting capabilities and more."
+msgid "The URL to use for connecting to Elasticsearch. Use a comma-separated list to support clustering (e.g., \"http://localhost:9200, http://localhost:9201\")."
msgstr ""
msgid "The X509 Certificate to use when mutual TLS is required to communicate with the external authorization service. If left blank, the server certificate is still validated when accessing over HTTPS."
@@ -25332,6 +26348,9 @@ msgstr ""
msgid "The roadmap shows the progress of your epics along a timeline"
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 schedule time must be in the future!"
msgstr ""
@@ -25383,6 +26402,9 @@ msgstr ""
msgid "The user map is a mapping of the FogBugz users that participated on your projects to the way their email address and usernames will be imported into GitLab. You can change this by populating the table below."
msgstr ""
+msgid "The user you are trying to approve is not pending an approval"
+msgstr ""
+
msgid "The user you are trying to deactivate has been active in the past %{minimum_inactive_days} days and cannot be deactivated"
msgstr ""
@@ -25491,6 +26513,9 @@ msgstr ""
msgid "There is no chart data available."
msgstr ""
+msgid "There is no data available."
+msgstr ""
+
msgid "There is no data available. Please change your selection."
msgstr ""
@@ -25734,6 +26759,9 @@ msgstr ""
msgid "This action can lead to data loss. To prevent accidental actions we ask you to confirm your intention."
msgstr ""
+msgid "This action cannot be undone, and will permanently delete the %{key} SSH key"
+msgstr ""
+
msgid "This action cannot be undone. You will lose the project's repository and all content: issues, merge requests, etc."
msgstr ""
@@ -25758,9 +26786,15 @@ msgstr ""
msgid "This application will be able to:"
msgstr ""
+msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of 15MB. %{written_count} of %{count} issues have been included. Consider re-exporting with a narrower selection of issues."
+msgstr ""
+
msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of 15MB. %{written_count} of %{issues_count} issues have been included. Consider re-exporting with a narrower selection of issues."
msgstr ""
+msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of 15MB. %{written_count} of %{merge_requests_count} issues have been included. Consider re-exporting with a narrower selection of issues."
+msgstr ""
+
msgid "This block is self-referential"
msgstr ""
@@ -25893,6 +26927,9 @@ msgstr ""
msgid "This is a security log of important events involving your account."
msgstr ""
+msgid "This is a self-managed instance of GitLab."
+msgstr ""
+
msgid "This is the highest peak of users on your installation since the license started."
msgstr ""
@@ -26130,7 +27167,7 @@ msgstr ""
msgid "This user has previously committed to the %{name} project."
msgstr ""
-msgid "This user is a %{access} of the %{name} project."
+msgid "This user has the %{access} role in the %{name} project."
msgstr ""
msgid "This user is the author of this %{noteable}."
@@ -26166,6 +27203,9 @@ msgstr ""
msgid "Threat Monitoring"
msgstr ""
+msgid "ThreatMonitoring|All Environments"
+msgstr ""
+
msgid "ThreatMonitoring|Anomalous Requests"
msgstr ""
@@ -26193,9 +27233,6 @@ msgstr ""
msgid "ThreatMonitoring|Operations Per Second"
msgstr ""
-msgid "ThreatMonitoring|Overview"
-msgstr ""
-
msgid "ThreatMonitoring|Packet Activity"
msgstr ""
@@ -26214,6 +27251,9 @@ msgstr ""
msgid "ThreatMonitoring|Something went wrong, unable to fetch statistics"
msgstr ""
+msgid "ThreatMonitoring|Statistics"
+msgstr ""
+
msgid "ThreatMonitoring|The firewall is not installed or has been disabled. To view this data, ensure the web application firewall is installed and enabled for your cluster."
msgstr ""
@@ -26451,6 +27491,12 @@ msgstr ""
msgid "Timeago|right now"
msgstr ""
+msgid "Timeline|Turn timeline view off"
+msgstr ""
+
+msgid "Timeline|Turn timeline view on"
+msgstr ""
+
msgid "Timeout"
msgstr ""
@@ -26641,9 +27687,6 @@ msgstr ""
msgid "Toggle Sidebar"
msgstr ""
-msgid "Toggle all threads"
-msgstr ""
-
msgid "Toggle backtrace"
msgstr ""
@@ -26668,7 +27711,7 @@ msgstr ""
msgid "Toggle navigation"
msgstr ""
-msgid "Toggle project"
+msgid "Toggle project select"
msgstr ""
msgid "Toggle sidebar"
@@ -26743,6 +27786,9 @@ msgstr ""
msgid "Total test time for all commits/merges"
msgstr ""
+msgid "Total users"
+msgstr ""
+
msgid "Total weight"
msgstr ""
@@ -26929,6 +27975,9 @@ msgstr ""
msgid "Tuesday"
msgstr ""
+msgid "Tuning settings"
+msgstr ""
+
msgid "Turn Off"
msgstr ""
@@ -27073,15 +28122,15 @@ msgstr ""
msgid "Unable to load the merge request widget. Try reloading the page."
msgstr ""
-msgid "Unable to resolve"
-msgstr ""
-
msgid "Unable to save iteration. Please try again"
msgstr ""
msgid "Unable to save your changes. Please try again."
msgstr ""
+msgid "Unable to save your preference"
+msgstr ""
+
msgid "Unable to schedule a pipeline to run immediately"
msgstr ""
@@ -27445,10 +28494,13 @@ msgstr ""
msgid "UsageQuota|%{help_link_start}Shared runners%{help_link_end} are disabled, so there are no limits set on pipeline usage"
msgstr ""
+msgid "UsageQuota|%{percentageLeft} of purchased storage is available"
+msgstr ""
+
msgid "UsageQuota|Artifacts"
msgstr ""
-msgid "UsageQuota|Build Artifacts"
+msgid "UsageQuota|Artifacts is a sum of build and pipeline artifacts."
msgstr ""
msgid "UsageQuota|Buy additional minutes"
@@ -27466,6 +28518,12 @@ msgstr ""
msgid "UsageQuota|LFS Storage"
msgstr ""
+msgid "UsageQuota|Learn more about excess storage usage"
+msgstr ""
+
+msgid "UsageQuota|Learn more about usage quotas"
+msgstr ""
+
msgid "UsageQuota|Packages"
msgstr ""
@@ -27475,6 +28533,9 @@ msgstr ""
msgid "UsageQuota|Purchase more storage"
msgstr ""
+msgid "UsageQuota|Purchased storage available"
+msgstr ""
+
msgid "UsageQuota|Repositories"
msgstr ""
@@ -27487,9 +28548,24 @@ msgstr ""
msgid "UsageQuota|Storage"
msgstr ""
+msgid "UsageQuota|This namespace contains locked projects"
+msgstr ""
+
msgid "UsageQuota|This namespace has no projects which use shared runners"
msgstr ""
+msgid "UsageQuota|This project is at risk of being locked."
+msgstr ""
+
+msgid "UsageQuota|This project is locked."
+msgstr ""
+
+msgid "UsageQuota|Total excess storage used"
+msgstr ""
+
+msgid "UsageQuota|Total namespace storage used"
+msgstr ""
+
msgid "UsageQuota|Unlimited"
msgstr ""
@@ -27511,15 +28587,27 @@ msgstr ""
msgid "UsageQuota|Usage since"
msgstr ""
+msgid "UsageQuota|When you purchase additional storage, we automatically unlock projects that were locked when you reached the %{actualRepositorySizeLimit} limit."
+msgstr ""
+
msgid "UsageQuota|Wiki"
msgstr ""
msgid "UsageQuota|Wikis"
msgstr ""
+msgid "UsageQuota|You have consumed all of your additional storage, please purchase more to unlock your projects over the free %{actualRepositorySizeLimit} limit."
+msgstr ""
+
+msgid "UsageQuota|You have reached the free storage limit of %{actualRepositorySizeLimit} on %{projectsLockedText}. To unlock them, please purchase additional storage."
+msgstr ""
+
msgid "UsageQuota|You used: %{usage} %{limit}"
msgstr ""
+msgid "UsageQuota|Your purchased storage is running low. To avoid locked projects, please purchase more storage."
+msgstr ""
+
msgid "UsageQuota|out of %{formattedLimit} of your namespace storage"
msgstr ""
@@ -27529,9 +28617,6 @@ msgstr ""
msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
msgstr ""
-msgid "Use a hardware device to add the second factor of authentication."
-msgstr ""
-
msgid "Use an one time password authenticator on your mobile device or computer to enable two-factor authentication (2FA)."
msgstr ""
@@ -27577,10 +28662,7 @@ msgstr ""
msgid "User %{username} was successfully removed."
msgstr ""
-msgid "User IDs"
-msgstr ""
-
-msgid "User List"
+msgid "User ID"
msgstr ""
msgid "User OAuth applications"
@@ -27700,6 +28782,9 @@ msgstr ""
msgid "UserProfile|Blocked user"
msgstr ""
+msgid "UserProfile|Bot activity"
+msgstr ""
+
msgid "UserProfile|Contributed projects"
msgstr ""
@@ -27805,6 +28890,9 @@ msgstr ""
msgid "Users"
msgstr ""
+msgid "Users in License"
+msgstr ""
+
msgid "Users in License:"
msgstr ""
@@ -28193,6 +29281,12 @@ msgstr ""
msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
msgstr ""
+msgid "VulnerabilityManagement|Detected"
+msgstr ""
+
+msgid "VulnerabilityManagement|Needs triage"
+msgstr ""
+
msgid "VulnerabilityManagement|Something went wrong while trying to delete the comment. Please try again later."
msgstr ""
@@ -28241,13 +29335,22 @@ msgstr ""
msgid "Vulnerability|%{scannerName} (version %{scannerVersion})"
msgstr ""
+msgid "Vulnerability|Activity"
+msgstr ""
+
msgid "Vulnerability|Class"
msgstr ""
msgid "Vulnerability|Comments"
msgstr ""
-msgid "Vulnerability|Crash Address"
+msgid "Vulnerability|Crash address"
+msgstr ""
+
+msgid "Vulnerability|Crash state"
+msgstr ""
+
+msgid "Vulnerability|Crash type"
msgstr ""
msgid "Vulnerability|Description"
@@ -28319,6 +29422,9 @@ msgstr ""
msgid "Warning: Displaying this diagram might cause performance issues on this page."
msgstr ""
+msgid "We are currently unable to fetch data for the pipeline header."
+msgstr ""
+
msgid "We are currently unable to fetch data for this graph."
msgstr ""
@@ -28358,6 +29464,12 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
+msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
+msgstr ""
+
+msgid "We would like to inform you that your subscription GitLab Enterprise Edition %{plan_name} is nearing its user limit. You have %{active_user_count} active users, which is almost at the user limit of %{maximum_user_count}."
+msgstr ""
+
msgid "We've found no vulnerabilities"
msgstr ""
@@ -28442,13 +29554,13 @@ msgstr ""
msgid "Webhooks|Tag push events"
msgstr ""
-msgid "Webhooks|This URL will be triggered by a push to the repository"
+msgid "Webhooks|This URL is triggered when a deployment starts, finishes, fails, or is canceled"
msgstr ""
-msgid "Webhooks|This URL will be triggered when a confidential issue is created/updated/merged"
+msgid "Webhooks|This URL will be triggered by a push to the repository"
msgstr ""
-msgid "Webhooks|This URL will be triggered when a deployment is finished/failed/canceled"
+msgid "Webhooks|This URL will be triggered when a confidential issue is created/updated/merged"
msgstr ""
msgid "Webhooks|This URL will be triggered when a merge request is created/updated/merged"
@@ -28517,21 +29629,18 @@ msgstr ""
msgid "Welcome to the guided GitLab tour"
msgstr ""
-msgid "Welcome to your Issue Board!"
-msgstr ""
-
msgid "Welcome to your issue board!"
msgstr ""
-msgid "We’ve been making changes to %{featureName} and we’d love your feedback %{linkStart}in this issue%{linkEnd} to help us improve the experience."
-msgstr ""
-
msgid "What are you searching for?"
msgstr ""
msgid "What describes you best?"
msgstr ""
+msgid "What is squashing?"
+msgstr ""
+
msgid "What's new at GitLab"
msgstr ""
@@ -28544,6 +29653,9 @@ msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
msgstr ""
+msgid "When enabled, any user visiting %{host} and creating an account will have to be explicitly approved by an admin before they can sign in. This setting is effective only if sign-ups are enabled."
+msgstr ""
+
msgid "When enabled, any user visiting %{host} will be able to create an account."
msgstr ""
@@ -28783,10 +29895,10 @@ msgstr ""
msgid "Work in progress Limit"
msgstr ""
-msgid "Workflow Help"
+msgid "Would you like to create a new branch?"
msgstr ""
-msgid "Would you like to create a new branch?"
+msgid "Would you like to try auto-generating a branch name?"
msgstr ""
msgid "Write"
@@ -28810,6 +29922,9 @@ msgstr ""
msgid "Wrong extern UID provided. Make sure Auth0 is configured correctly."
msgstr ""
+msgid "YYYY-MM-DD"
+msgstr ""
+
msgid "Yes"
msgstr ""
@@ -28876,6 +29991,9 @@ msgstr ""
msgid "You are going to turn on the confidentiality. This means that only team members with %{strongStart}at least Reporter access%{strongEnd} are able to see and leave comments on the %{issuableType}."
msgstr ""
+msgid "You are not allowed to approve a user"
+msgstr ""
+
msgid "You are not allowed to push into this branch. Create another branch or open a merge request."
msgstr ""
@@ -28897,6 +30015,9 @@ msgstr ""
msgid "You are receiving this message because you are a GitLab administrator for %{url}."
msgstr ""
+msgid "You are signed into GitLab as %{user_link}"
+msgstr ""
+
msgid "You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico."
msgstr ""
@@ -28948,6 +30069,9 @@ msgstr ""
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
+msgid "You can find more information about GitLab subscriptions in %{subscriptions_doc_link}."
+msgstr ""
+
msgid "You can generate an access token scoped to this project for each application to use the GitLab API."
msgstr ""
@@ -28972,6 +30096,9 @@ msgstr ""
msgid "You can notify the app / group or a project by sending them an email notification"
msgstr ""
+msgid "You can now close this window."
+msgstr ""
+
msgid "You can now export your security dashboard to a CSV report."
msgstr ""
@@ -29020,9 +30147,6 @@ msgstr ""
msgid "You can test your .gitlab-ci.yml in %{linkStart}CI Lint%{linkEnd}."
msgstr ""
-msgid "You can try again using %{begin_link}basic search%{end_link}"
-msgstr ""
-
msgid "You cannot access the raw file. Please wait a minute."
msgstr ""
@@ -29161,9 +30285,6 @@ msgstr ""
msgid "You may close the milestone now."
msgstr ""
-msgid "You must accept our Terms of Service and privacy policy in order to register an account"
-msgstr ""
-
msgid "You must be logged in to search across all of GitLab"
msgstr ""
@@ -29221,7 +30342,7 @@ msgstr ""
msgid "You need to upload a Google Takeout archive."
msgstr ""
-msgid "You reached %{usage_in_percent} of %{namespace_name}'s storage capacity (%{used_storage} of %{storage_limit})"
+msgid "You successfully declined the invitation"
msgstr ""
msgid "You tried to fork %{link_to_the_project} but it failed for the following reason:"
@@ -29323,19 +30444,22 @@ msgstr ""
msgid "YouTube"
msgstr ""
+msgid "YouTube URL or ID"
+msgstr ""
+
msgid "Your %{host} account was signed in to from a new location"
msgstr ""
msgid "Your %{strong}%{plan_name}%{strong_close} subscription for %{strong}%{namespace_name}%{strong_close} will expire on %{strong}%{expires_on}%{strong_close}."
msgstr ""
-msgid "Your %{strong}%{plan_name}%{strong_close} subscription will expire on %{strong}%{expires_on}%{strong_close}. After that, you will not to be able to create issues or merge requests as well as many other features."
+msgid "Your %{strong}%{plan_name}%{strong_close} subscription will expire on %{strong}%{expires_on}%{strong_close}. After that, you will not be able to create issues or merge requests as well as many other features."
msgstr ""
msgid "Your CSV export has started. It will be emailed to %{email} when complete."
msgstr ""
-msgid "Your CSV export of %{issues_count} from project %{project_link} has been added to this email as an attachment."
+msgid "Your CSV export of %{count} from project %{project_link} has been added to this email as an attachment."
msgstr ""
msgid "Your CSV export of %{written_count} from project %{project_name} (%{project_url}) has been added to this email as an attachment."
@@ -29646,15 +30770,21 @@ msgstr ""
msgid "by"
msgstr ""
-msgid "by %{user}"
-msgstr ""
-
msgid "cannot be a date in the past"
msgstr ""
msgid "cannot be changed if a personal project has container registry tags."
msgstr ""
+msgid "cannot be changed if shared runners are enabled"
+msgstr ""
+
+msgid "cannot be enabled because parent group does not allow it"
+msgstr ""
+
+msgid "cannot be enabled because parent group has shared Runners disabled"
+msgstr ""
+
msgid "cannot be enabled unless all domains have TLS certificates"
msgstr ""
@@ -29814,9 +30944,6 @@ msgstr ""
msgid "ciReport|Investigate this vulnerability by creating an issue"
msgstr ""
-msgid "ciReport|Learn more about interacting with security reports"
-msgstr ""
-
msgid "ciReport|Load performance test metrics: "
msgstr ""
@@ -30036,6 +31163,9 @@ msgstr ""
msgid "failed to dismiss associated finding(id=%{finding_id}): %{message}"
msgstr ""
+msgid "failed to revert associated finding(id=%{finding_id}) to detected"
+msgstr ""
+
msgid "file"
msgid_plural "files"
msgstr[0] ""
@@ -30135,7 +31265,7 @@ msgstr ""
msgid "is blocked by"
msgstr ""
-msgid "is enabled."
+msgid "is forbidden by a top-level group"
msgstr ""
msgid "is invalid because there is downstream lock"
@@ -30153,6 +31283,9 @@ msgstr ""
msgid "is not a valid X509 certificate."
msgstr ""
+msgid "is not allowed since the group is not top-level group."
+msgstr ""
+
msgid "is not allowed. Try again with a different email address, or contact your GitLab admin."
msgstr ""
@@ -30171,6 +31304,9 @@ msgstr ""
msgid "is too long (%{current_value}). The maximum size is %{max_size}."
msgstr ""
+msgid "is too long (maximum is %{count} characters)"
+msgstr ""
+
msgid "is too long (maximum is 100 entries)"
msgstr ""
@@ -30269,6 +31405,9 @@ msgstr ""
msgid "missing"
msgstr ""
+msgid "more information"
+msgstr ""
+
msgid "most recent deployment"
msgstr ""
@@ -30578,6 +31717,9 @@ msgstr ""
msgid "must be a root namespace"
msgstr ""
+msgid "must be a valid IPv4 or IPv6 address"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -30614,6 +31756,9 @@ msgstr ""
msgid "no expiration"
msgstr ""
+msgid "no name set"
+msgstr ""
+
msgid "no one can merge"
msgstr ""
@@ -30736,9 +31881,6 @@ msgstr ""
msgid "projects"
msgstr ""
-msgid "push to your repository, create pipelines, create issues or add comments. To reduce storage capacity, delete unused repositories, artifacts, wikis, issues, and pipelines."
-msgstr ""
-
msgid "quick actions"
msgstr ""
@@ -30751,9 +31893,6 @@ msgstr ""
msgid "relates to"
msgstr ""
-msgid "released %{time}"
-msgstr ""
-
msgid "remaining"
msgstr ""
@@ -30918,9 +32057,6 @@ msgstr ""
msgid "toggle collapse"
msgstr ""
-msgid "toggle dropdown"
-msgstr ""
-
msgid "triggered"
msgstr ""
@@ -31014,9 +32150,6 @@ msgstr ""
msgid "wiki page"
msgstr ""
-msgid "will be released %{time}"
-msgstr ""
-
msgid "with %{additions} additions, %{deletions} deletions."
msgstr ""
diff --git a/locale/gl_ES/gitlab.po b/locale/gl_ES/gitlab.po
index 3411a3e3908..31532eed94d 100644
--- a/locale/gl_ES/gitlab.po
+++ b/locale/gl_ES/gitlab.po
@@ -14,34 +14,37 @@ msgstr ""
"X-Crowdin-Language: gl\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 6\n"
-"PO-Revision-Date: 2020-09-04 23:02\n"
+"PO-Revision-Date: 2020-10-02 18:41\n"
-msgid " %{start} to %{end}"
+msgid " %{project_name}#%{issue_iid} &middot; opened %{issue_created} by %{author}"
msgstr ""
+msgid " %{start} to %{end}"
+msgstr " %{start} a %{end}"
+
msgid " (from %{timeoutSource})"
-msgstr ""
+msgstr " (a partir de %{timeoutSource})"
msgid " Collected %{time}"
-msgstr ""
+msgstr " Recollido %{time}"
msgid " Please sign in."
-msgstr ""
+msgstr " Por favor, inicie a sesión."
msgid " Try to %{action} this file again."
-msgstr ""
+msgstr " Probe a %{action} este ficheiro de novo."
msgid " You need to do this before %{grace_period_deadline}."
-msgstr ""
+msgstr " Debe facelo antes do %{grace_period_deadline}."
msgid " and"
msgstr " e"
msgid " and "
-msgstr ""
+msgstr " e "
msgid " and %{sliced}"
-msgstr ""
+msgstr " e %{sliced}"
msgid " degraded on %d point"
msgid_plural " degraded on %d points"
@@ -66,7 +69,7 @@ msgid " or %{emphasisStart}&epic id%{emphasisEnd}"
msgstr ""
msgid " or references (e.g. path/to/project!merge_request_id)"
-msgstr ""
+msgstr " ou referencias (ex.: ruta/do/proxecto!merge_request_id)"
msgid "\"%{path}\" did not exist on \"%{ref}\""
msgstr ""
@@ -74,6 +77,16 @@ msgstr ""
msgid "\"el\" parameter is required for createInstance()"
msgstr ""
+msgid "%d Approval"
+msgid_plural "%d Approvals"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d Package"
+msgid_plural "%d Packages"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d Scanned URL"
msgid_plural "%d Scanned URLs"
msgstr[0] ""
@@ -137,6 +150,11 @@ msgstr[1] ""
msgid "%d commits"
msgstr ""
+msgid "%d completed issue"
+msgid_plural "%d completed issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d contribution"
msgid_plural "%d contributions"
msgstr[0] ""
@@ -147,6 +165,11 @@ msgid_plural "%d days"
msgstr[0] ""
msgstr[1] ""
+msgid "%d day until tags are automatically removed"
+msgid_plural "%d days until tags are automatically removed"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d error"
msgid_plural "%d errors"
msgstr[0] ""
@@ -237,6 +260,16 @@ msgid_plural "%d more comments"
msgstr[0] ""
msgstr[1] ""
+msgid "%d open issue"
+msgid_plural "%d open issues"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d pending comment"
+msgid_plural "%d pending comments"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d personal project will be removed and cannot be restored."
msgid_plural "%d personal projects will be removed and cannot be restored."
msgstr[0] ""
@@ -252,6 +285,11 @@ msgid_plural "%d projects"
msgstr[0] ""
msgstr[1] ""
+msgid "%d project selected"
+msgid_plural "%d projects selected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d request with warnings"
msgid_plural "%d requests with warnings"
msgstr[0] ""
@@ -272,6 +310,11 @@ msgid_plural "%d tags"
msgstr[0] ""
msgstr[1] ""
+msgid "%d tag per image name"
+msgid_plural "%d tags per image name"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d unassigned issue"
msgid_plural "%d unassigned issues"
msgstr[0] ""
@@ -292,6 +335,11 @@ msgid_plural "%d vulnerabilities dismissed"
msgstr[0] ""
msgstr[1] ""
+msgid "%d warning found:"
+msgid_plural "%d warnings found:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%s additional commit has been omitted to prevent performance issues."
msgid_plural "%s additional commits have been omitted to prevent performance issues."
msgstr[0] ""
@@ -330,6 +378,9 @@ msgstr ""
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr ""
+msgid "%{completedCount} completed weight"
+msgstr ""
+
msgid "%{completedWeight} of %{totalWeight} weight completed"
msgstr ""
@@ -378,14 +429,12 @@ msgid_plural "%{count} participants"
msgstr[0] ""
msgstr[1] ""
-msgid "%{count} pending comment"
-msgid_plural "%{count} pending comments"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
+msgid "%{count} total weight"
+msgstr ""
+
msgid "%{dashboard_path} could not be found."
msgstr ""
@@ -440,6 +489,9 @@ msgstr ""
msgid "%{group_name} uses group managed accounts. You need to create a new GitLab account which will be managed by %{group_name}."
msgstr ""
+msgid "%{group_name}&%{epic_iid} &middot; opened %{epic_created} by %{author}"
+msgstr ""
+
msgid "%{host} sign-in from new location"
msgstr ""
@@ -452,7 +504,7 @@ msgstr ""
msgid "%{issuableType} will be removed! Are you sure?"
msgstr ""
-msgid "%{issuesSize} issues with a limit of %{maxIssueCount}"
+msgid "%{issuesCount} issues with a limit of %{maxIssueCount}"
msgstr ""
msgid "%{issuesSize} with a limit of %{maxIssueCount}"
@@ -485,7 +537,7 @@ msgstr ""
msgid "%{labelStart}Namespace:%{labelEnd} %{namespace}"
msgstr ""
-msgid "%{labelStart}Report Type:%{labelEnd} %{reportType}"
+msgid "%{labelStart}Scan Type:%{labelEnd} %{reportType}"
msgstr ""
msgid "%{labelStart}Scanner:%{labelEnd} %{scanner}"
@@ -682,9 +734,6 @@ msgid_plural "%{securityScanner} results are not available because a pipeline ha
msgstr[0] ""
msgstr[1] ""
-msgid "%{service_title} %{message}."
-msgstr ""
-
msgid "%{size} GiB"
msgstr ""
@@ -773,6 +822,12 @@ msgstr ""
msgid "%{timebox_name} should belong either to a project or a group."
msgstr ""
+msgid "%{timebox_type} does not support burnup charts"
+msgstr ""
+
+msgid "%{timebox_type} must have a start and due date"
+msgstr ""
+
msgid "%{title} %{operator} %{threshold}"
msgstr ""
@@ -797,7 +852,7 @@ msgstr ""
msgid "%{total} open issue weight"
msgstr ""
-msgid "%{total} open issues"
+msgid "%{total} warnings found: showing first %{warningsDisplayed}"
msgstr ""
msgid "%{usage_ping_link_start}Learn more%{usage_ping_link_end} about what information is shared with GitLab Inc."
@@ -830,9 +885,6 @@ msgstr ""
msgid "&lt; 1 hour"
msgstr ""
-msgid "&lt;no name set&gt;"
-msgstr ""
-
msgid "&lt;no scopes selected&gt;"
msgstr ""
@@ -863,6 +915,9 @@ msgstr ""
msgid "'%{name}' Value Stream created"
msgstr ""
+msgid "'%{name}' Value Stream deleted"
+msgstr ""
+
msgid "'%{name}' stage already exists"
msgstr ""
@@ -922,6 +977,9 @@ msgstr ""
msgid "+ %{numberOfHiddenAssignees} more"
msgstr ""
+msgid "+ %{numberOfHiddenReviewers} more"
+msgstr ""
+
msgid "+%d more"
msgid_plural "+%d more"
msgstr[0] ""
@@ -982,6 +1040,11 @@ msgid_plural "%d Days"
msgstr[0] ""
msgstr[1] ""
+msgid "1 Issue"
+msgid_plural "%d Issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "1 closed issue"
msgid_plural "%{issues} closed issues"
msgstr[0] ""
@@ -997,6 +1060,11 @@ msgid_plural "%d days"
msgstr[0] ""
msgstr[1] ""
+msgid "1 deploy key"
+msgid_plural "%d deploy keys"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1099,6 +1167,9 @@ msgstr ""
msgid ":%{startLine} to %{endLine}"
msgstr ""
+msgid "A %{incident_docs_start}modified issue%{incident_docs_end} to guide the resolution of incidents."
+msgstr ""
+
msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr ""
@@ -1111,6 +1182,9 @@ msgstr ""
msgid "A GitBook site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
+msgid "A Gitpod configured Webapplication in Spring and Java"
+msgstr ""
+
msgid "A Hexo site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
@@ -1282,9 +1356,15 @@ msgstr ""
msgid "Access expiration date"
msgstr ""
+msgid "Access expires"
+msgstr ""
+
msgid "Access forbidden. Check your access level."
msgstr ""
+msgid "Access granted"
+msgstr ""
+
msgid "Access requests"
msgstr ""
@@ -1294,6 +1374,9 @@ msgstr ""
msgid "Access to Pages websites are controlled based on the user's membership to a given project. By checking this box, users will be required to be logged in to have access to all Pages websites in your instance."
msgstr ""
+msgid "AccessDropdown|Deploy Keys"
+msgstr ""
+
msgid "AccessDropdown|Groups"
msgstr ""
@@ -1411,12 +1494,6 @@ msgstr ""
msgid "Active Sessions"
msgstr ""
-msgid "Active Users:"
-msgstr ""
-
-msgid "Active users"
-msgstr ""
-
msgid "Activity"
msgstr ""
@@ -1584,9 +1661,6 @@ msgstr ""
msgid "Add label(s)"
msgstr ""
-msgid "Add license"
-msgstr ""
-
msgid "Add list"
msgstr ""
@@ -1761,21 +1835,51 @@ msgstr ""
msgid "AdminArea|Bots"
msgstr ""
+msgid "AdminArea|Components"
+msgstr ""
+
msgid "AdminArea|Developer"
msgstr ""
+msgid "AdminArea|Features"
+msgstr ""
+
+msgid "AdminArea|Groups: %{number_of_groups}"
+msgstr ""
+
msgid "AdminArea|Guest"
msgstr ""
msgid "AdminArea|Included Free in license"
msgstr ""
+msgid "AdminArea|Latest groups"
+msgstr ""
+
+msgid "AdminArea|Latest projects"
+msgstr ""
+
+msgid "AdminArea|Latest users"
+msgstr ""
+
msgid "AdminArea|Maintainer"
msgstr ""
+msgid "AdminArea|New group"
+msgstr ""
+
+msgid "AdminArea|New project"
+msgstr ""
+
+msgid "AdminArea|New user"
+msgstr ""
+
msgid "AdminArea|Owner"
msgstr ""
+msgid "AdminArea|Projects: %{number_of_projects}"
+msgstr ""
+
msgid "AdminArea|Reporter"
msgstr ""
@@ -1803,6 +1907,9 @@ msgstr ""
msgid "AdminArea|Users without a Group and Project"
msgstr ""
+msgid "AdminArea|Users: %{number_of_users}"
+msgstr ""
+
msgid "AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running."
msgstr ""
@@ -1821,9 +1928,6 @@ msgstr ""
msgid "AdminProjects|Delete Project %{projectName}?"
msgstr ""
-msgid "AdminProjects|Delete project"
-msgstr ""
-
msgid "AdminSettings|Apply integration settings to all Projects"
msgstr ""
@@ -2061,21 +2165,30 @@ msgstr ""
msgid "AdminUsers|Without projects"
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 ""
msgid "AdminUsers|You cannot remove your own admin rights."
msgstr ""
+msgid "AdminUsers|You must transfer ownership or delete the groups owned by this user before you can delete their account"
+msgstr ""
+
msgid "Administration"
msgstr ""
msgid "Advanced"
msgstr ""
+msgid "Advanced Search"
+msgstr ""
+
+msgid "Advanced Search with Elasticsearch"
+msgstr ""
+
msgid "Advanced Settings"
msgstr ""
@@ -2153,6 +2266,9 @@ msgstr ""
msgid "AlertManagement|Edit"
msgstr ""
+msgid "AlertManagement|Environment"
+msgstr ""
+
msgid "AlertManagement|Events"
msgstr ""
@@ -2165,6 +2281,9 @@ msgstr ""
msgid "AlertManagement|Issue"
msgstr ""
+msgid "AlertManagement|Key"
+msgstr ""
+
msgid "AlertManagement|Low"
msgstr ""
@@ -2258,6 +2377,9 @@ msgstr ""
msgid "AlertManagement|Unknown"
msgstr ""
+msgid "AlertManagement|Value"
+msgstr ""
+
msgid "AlertManagement|View alerts in Opsgenie"
msgstr ""
@@ -2417,6 +2539,9 @@ msgstr ""
msgid "All projects"
msgstr ""
+msgid "All projects selected"
+msgstr ""
+
msgid "All security scans are enabled because %{linkStart}Auto DevOps%{linkEnd} is enabled on this project"
msgstr ""
@@ -2504,6 +2629,9 @@ msgstr ""
msgid "Almost there"
msgstr ""
+msgid "Already blocked"
+msgstr ""
+
msgid "Also called \"Issuer\" or \"Relying party trust identifier\""
msgstr ""
@@ -2558,6 +2686,9 @@ msgstr ""
msgid "An error has occurred"
msgstr ""
+msgid "An error occured while making the changes: %{error}"
+msgstr ""
+
msgid "An error occurred adding a draft to the thread."
msgstr ""
@@ -2585,12 +2716,6 @@ msgstr ""
msgid "An error occurred when toggling the notification subscription"
msgstr ""
-msgid "An error occurred when trying to resolve a comment. Please try again."
-msgstr ""
-
-msgid "An error occurred when trying to resolve a discussion. Please try again."
-msgstr ""
-
msgid "An error occurred when updating the issue weight"
msgstr ""
@@ -2606,12 +2731,6 @@ msgstr ""
msgid "An error occurred while checking group path. Please refresh and try again."
msgstr ""
-msgid "An error occurred while committing your changes."
-msgstr ""
-
-msgid "An error occurred while creating the list. Please try again."
-msgstr ""
-
msgid "An error occurred while decoding the file."
msgstr ""
@@ -2684,25 +2803,19 @@ msgstr ""
msgid "An error occurred while fetching the Service Desk address."
msgstr ""
-msgid "An error occurred while fetching the board issues. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the board lists. Please reload the page."
msgstr ""
msgid "An error occurred while fetching the board lists. Please try again."
msgstr ""
-msgid "An error occurred while fetching the board swimlanes. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the builds."
msgstr ""
msgid "An error occurred while fetching the job log."
msgstr ""
-msgid "An error occurred while fetching the job trace."
+msgid "An error occurred while fetching the job logs."
msgstr ""
msgid "An error occurred while fetching the job."
@@ -2849,9 +2962,6 @@ msgstr ""
msgid "An error occurred while saving assignees"
msgstr ""
-msgid "An error occurred while saving the template. Please check if the template exists."
-msgstr ""
-
msgid "An error occurred while searching for milestones"
msgstr ""
@@ -2870,10 +2980,10 @@ msgstr ""
msgid "An error occurred while updating approvers"
msgstr ""
-msgid "An error occurred while updating the comment"
+msgid "An error occurred while updating labels."
msgstr ""
-msgid "An error occurred while updating the list. Please try again."
+msgid "An error occurred while updating the comment"
msgstr ""
msgid "An error occurred while validating group path"
@@ -2927,6 +3037,9 @@ msgstr ""
msgid "An unknown error occurred while loading this graph."
msgstr ""
+msgid "An unknown error occurred."
+msgstr ""
+
msgid "Analytics"
msgstr ""
@@ -2960,10 +3073,10 @@ msgstr ""
msgid "Any"
msgstr ""
-msgid "Any Author"
+msgid "Any %{header}"
msgstr ""
-msgid "Any Status"
+msgid "Any Author"
msgstr ""
msgid "Any branch"
@@ -3017,6 +3130,9 @@ msgstr ""
msgid "Application ID"
msgstr ""
+msgid "Application limits saved successfully"
+msgstr ""
+
msgid "Application settings saved successfully"
msgstr ""
@@ -3226,6 +3342,9 @@ msgstr ""
msgid "Are you sure you want to close this blocked issue?"
msgstr ""
+msgid "Are you sure you want to delete \"%{name}\" Value Stream?"
+msgstr ""
+
msgid "Are you sure you want to delete %{name}?"
msgstr ""
@@ -3235,6 +3354,9 @@ msgstr ""
msgid "Are you sure you want to delete this %{typeOfComment}?"
msgstr ""
+msgid "Are you sure you want to delete this SSH key?"
+msgstr ""
+
msgid "Are you sure you want to delete this board?"
msgstr ""
@@ -3259,6 +3381,11 @@ msgstr ""
msgid "Are you sure you want to erase this build?"
msgstr ""
+msgid "Are you sure you want to import %d repository?"
+msgid_plural "Are you sure you want to import %d repositories?"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Are you sure you want to lose unsaved changes?"
msgstr ""
@@ -3268,15 +3395,15 @@ msgstr ""
msgid "Are you sure you want to merge immediately?"
msgstr ""
-msgid "Are you sure you want to permanently delete this license?"
-msgstr ""
-
msgid "Are you sure you want to re-deploy this environment?"
msgstr ""
msgid "Are you sure you want to regenerate the public key? You will have to update the public key on the remote server before mirroring will work again."
msgstr ""
+msgid "Are you sure you want to reindex?"
+msgstr ""
+
msgid "Are you sure you want to remove %{group_name}?"
msgstr ""
@@ -3304,6 +3431,9 @@ msgstr ""
msgid "Are you sure you want to revoke this nickname?"
msgstr ""
+msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
+msgstr ""
+
msgid "Are you sure you want to stop this environment?"
msgstr ""
@@ -3325,6 +3455,9 @@ msgstr ""
msgid "Are you sure? The device will be signed out of GitLab and all remember me tokens revoked."
msgstr ""
+msgid "Are you sure? This will invalidate your registered applications and U2F / WebAuthn devices."
+msgstr ""
+
msgid "Are you sure? This will invalidate your registered applications and U2F devices."
msgstr ""
@@ -3343,9 +3476,6 @@ msgstr ""
msgid "Artifacts"
msgstr ""
-msgid "As U2F devices are only supported by a few browsers, we require that you set up a two-factor authentication app before a U2F device. That way you'll always be able to log in - even when you're using an unsupported browser."
-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 ""
@@ -3539,6 +3669,9 @@ msgstr ""
msgid "AuditLogs|Target"
msgstr ""
+msgid "AuditLogs|This month"
+msgstr ""
+
msgid "AuditLogs|User Events"
msgstr ""
@@ -3578,6 +3711,9 @@ msgstr ""
msgid "Authentication via U2F device failed."
msgstr ""
+msgid "Authentication via WebAuthn device failed."
+msgstr ""
+
msgid "Author"
msgstr ""
@@ -3845,15 +3981,6 @@ msgstr ""
msgid "BambooService|You must set up automatic revision labeling and a repository trigger in Bamboo."
msgstr ""
-msgid "BatchComments|Delete all pending comments"
-msgstr ""
-
-msgid "BatchComments|Discard review?"
-msgstr ""
-
-msgid "BatchComments|You're about to discard your review which will delete all of your pending comments. The deleted comments %{strong_start}cannot%{strong_end} be restored."
-msgstr ""
-
msgid "Be careful. Changing the project's namespace can have unintended side effects."
msgstr ""
@@ -3875,6 +4002,9 @@ msgstr ""
msgid "Bi-weekly code coverage"
msgstr ""
+msgid "Billable Users:"
+msgstr ""
+
msgid "Billing"
msgstr ""
@@ -3884,7 +4014,7 @@ msgstr ""
msgid "BillingPlans|@%{user_name} you are currently using the %{plan_name} plan."
msgstr ""
-msgid "BillingPlans|Congratulations, your new trial is activated"
+msgid "BillingPlans|Congratulations, your free trial is activated."
msgstr ""
msgid "BillingPlans|If you would like to downgrade your plan please contact %{support_link_start}Customer Support%{support_link_end}."
@@ -3947,6 +4077,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Block user"
+msgstr ""
+
msgid "Blocked"
msgstr ""
@@ -3962,31 +4095,37 @@ msgstr ""
msgid "Blog"
msgstr ""
-msgid "Board name"
-msgstr ""
-
msgid "Board scope"
msgstr ""
msgid "Board scope affects which issues are displayed for anyone who visits this board"
msgstr ""
-msgid "BoardBlankState|Add default lists"
+msgid "Boards"
msgstr ""
-msgid "BoardBlankState|Add the following default lists to your Issue Board with one click:"
+msgid "Boards and Board Lists"
msgstr ""
-msgid "BoardBlankState|Nevermind, I'll use my own"
+msgid "Boards|An error occurred while creating the issue. Please try again."
msgstr ""
-msgid "BoardBlankState|Starting out with the default set of lists will get you right on the way to making the most of your board."
+msgid "Boards|An error occurred while creating the list. Please try again."
msgstr ""
-msgid "Boards"
+msgid "Boards|An error occurred while fetching issues. Please reload the page."
msgstr ""
-msgid "Boards and Board Lists"
+msgid "Boards|An error occurred while fetching the board issues. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching the board swimlanes. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while moving the issue. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while updating the list. Please try again."
msgstr ""
msgid "Boards|Collapse"
@@ -4013,7 +4152,7 @@ msgstr ""
msgid "Branch %{branch_name} was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr ""
-msgid "Branch has changed"
+msgid "Branch changed"
msgstr ""
msgid "Branch is already taken"
@@ -4319,6 +4458,9 @@ msgstr ""
msgid "CLOSED (MOVED)"
msgstr ""
+msgid "CODEOWNERS rule violation"
+msgstr ""
+
msgid "CONTRIBUTING"
msgstr ""
@@ -4349,9 +4491,6 @@ msgstr ""
msgid "Can't create snippet: %{err}"
msgstr ""
-msgid "Can't edit as source branch was deleted"
-msgstr ""
-
msgid "Can't fetch content for the blob: %{err}"
msgstr ""
@@ -4364,9 +4503,6 @@ msgstr ""
msgid "Can't load mermaid module: %{err}"
msgstr ""
-msgid "Can't remove group members without group managed account"
-msgstr ""
-
msgid "Can't scan the code?"
msgstr ""
@@ -4409,6 +4545,9 @@ msgstr ""
msgid "Cannot create the abuse report. This user has been blocked."
msgstr ""
+msgid "Cannot enable shared runners because parent group does not allow it"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -4514,6 +4653,15 @@ msgstr ""
msgid "Change your password or recover your current one"
msgstr ""
+msgid "ChangeReviewer|Reviewer changed from %{old} to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Reviewer changed to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Unassigned"
+msgstr ""
+
msgid "ChangeTypeActionLabel|Pick into branch"
msgstr ""
@@ -4553,6 +4701,9 @@ msgstr ""
msgid "Changes the title to \"%{title_param}\"."
msgstr ""
+msgid "Changes were successfully made."
+msgstr ""
+
msgid "Changes won't take place until the index is %{link_start}recreated%{link_end}."
msgstr ""
@@ -4958,6 +5109,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove variable"
+msgstr ""
+
msgid "CiVariables|Remove variable row"
msgstr ""
@@ -5036,9 +5190,6 @@ msgstr ""
msgid "Clear due date"
msgstr ""
-msgid "Clear input"
-msgstr ""
-
msgid "Clear recent searches"
msgstr ""
@@ -5087,6 +5238,9 @@ msgstr ""
msgid "Client authentication key password"
msgstr ""
+msgid "Client request timeout"
+msgstr ""
+
msgid "Clients"
msgstr ""
@@ -5171,6 +5325,27 @@ msgstr ""
msgid "Cluster type must be specificed for Stages::ClusterEndpointInserter"
msgstr ""
+msgid "ClusterAgents|Configuration"
+msgstr ""
+
+msgid "ClusterAgents|Connect your cluster with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate Kubernetes with a GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Name"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Agent also requires %{linkStart}enabling the Agent Server%{linkEnd}"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Kubernetes Agent allows an Infrastructure as Code, GitOps approach to integrating Kubernetes clusters with GitLab. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "ClusterAgent|This feature is only available for premium plans"
msgstr ""
@@ -5240,10 +5415,10 @@ msgstr ""
msgid "ClusterIntegration|All installed applications and related resources"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster."
+msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{linkStart}More information%{linkEnd}"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{startLink}More information%{endLink}"
+msgid "ClusterIntegration|Allow GitLab to manage namespaces and service accounts for this cluster."
msgstr ""
msgid "ClusterIntegration|Alternatively, "
@@ -5264,6 +5439,9 @@ msgstr ""
msgid "ClusterIntegration|An error occurred while trying to fetch zone machine types: %{error}"
msgstr ""
+msgid "ClusterIntegration|An unknown error occurred while attempting to connect to Kubernetes."
+msgstr ""
+
msgid "ClusterIntegration|Any project namespaces"
msgstr ""
@@ -5279,6 +5457,9 @@ msgstr ""
msgid "ClusterIntegration|Authenticate with Amazon Web Services"
msgstr ""
+msgid "ClusterIntegration|Authentication Error"
+msgstr ""
+
msgid "ClusterIntegration|Base domain"
msgstr ""
@@ -5297,13 +5478,22 @@ msgstr ""
msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}security group %{externalLinkIcon} %{endLink} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
+msgid "ClusterIntegration|Check your CA certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Check your cluster status"
+msgstr ""
+
+msgid "ClusterIntegration|Check your token"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}subnets %{externalLinkIcon} %{endLink} in your VPC where your worker nodes will run."
+msgid "ClusterIntegration|Choose the %{linkStart}security group %{linkEnd} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
msgstr ""
-msgid "ClusterIntegration|Choose the worker node %{startLink}instance type %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Choose the %{linkStart}subnets %{linkEnd} in your VPC where your worker nodes will run."
+msgstr ""
+
+msgid "ClusterIntegration|Choose the worker node %{linkStart}instance type%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Choose which applications to install on your Kubernetes cluster."
@@ -5315,10 +5505,7 @@ msgstr ""
msgid "ClusterIntegration|Clear cluster cache"
msgstr ""
-msgid "ClusterIntegration|Clear the local cache of namespace and service accounts. This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
-msgstr ""
-
-msgid "ClusterIntegration|Cluster being created"
+msgid "ClusterIntegration|Clear the local cache of namespace and service accounts."
msgstr ""
msgid "ClusterIntegration|Cluster management project (alpha)"
@@ -5330,15 +5517,21 @@ msgstr ""
msgid "ClusterIntegration|Cluster_applications artifact too big. Maximum allowable size: %{human_size}"
msgstr ""
-msgid "ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters."
+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|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}"
+msgid "ClusterIntegration|Clusters connected with a certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Connect cluster with certificate"
msgstr ""
msgid "ClusterIntegration|Connect existing cluster"
msgstr ""
+msgid "ClusterIntegration|Connection Error"
+msgstr ""
+
msgid "ClusterIntegration|Copy API URL"
msgstr ""
@@ -5414,6 +5607,12 @@ msgstr ""
msgid "ClusterIntegration|Deletes all GitLab resources attached to this cluster during removal"
msgstr ""
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared."
+msgstr ""
+
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared. %{linkStart}More information%{linkEnd}"
+msgstr ""
+
msgid "ClusterIntegration|Did you know?"
msgstr ""
@@ -5483,6 +5682,9 @@ msgstr ""
msgid "ClusterIntegration|Fluentd is an open source data collector, which lets you unify the data collection and consumption for a better use and understanding of data. It requires at least one of the following logs to be successfully installed."
msgstr ""
+msgid "ClusterIntegration|GitLab Agent managed clusters"
+msgstr ""
+
msgid "ClusterIntegration|GitLab Container Network Policies"
msgstr ""
@@ -5495,6 +5697,12 @@ msgstr ""
msgid "ClusterIntegration|GitLab Runner connects to the repository and executes CI/CD jobs, pushing results back and deploying applications to production."
msgstr ""
+msgid "ClusterIntegration|GitLab failed to authenticate."
+msgstr ""
+
+msgid "ClusterIntegration|GitLab failed to connect to the cluster."
+msgstr ""
+
msgid "ClusterIntegration|GitLab-managed cluster"
msgstr ""
@@ -5516,6 +5724,9 @@ msgstr ""
msgid "ClusterIntegration|Group cluster"
msgstr ""
+msgid "ClusterIntegration|HTTP Error"
+msgstr ""
+
msgid "ClusterIntegration|Helm Tiller"
msgstr ""
@@ -5549,7 +5760,10 @@ msgstr ""
msgid "ClusterIntegration|Instance type"
msgstr ""
-msgid "ClusterIntegration|Integrate Kubernetes cluster automation"
+msgid "ClusterIntegration|Integrate Kubernetes with a cluster certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Integrate with a cluster certificate"
msgstr ""
msgid "ClusterIntegration|Issuer Email"
@@ -5585,9 +5799,6 @@ msgstr ""
msgid "ClusterIntegration|Knative extends Kubernetes to provide a set of middleware components that are essential to build modern, source-centric, and container-based applications that can run anywhere: on premises, in the cloud, or even in a third-party data center."
msgstr ""
-msgid "ClusterIntegration|Kubernetes cluster"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes cluster is being created..."
msgstr ""
@@ -5600,9 +5811,6 @@ msgstr ""
msgid "ClusterIntegration|Kubernetes clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr ""
-msgid "ClusterIntegration|Kubernetes clusters can be used to deploy applications and to provide Review Apps for this project"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes version"
msgstr ""
@@ -5615,7 +5823,7 @@ msgstr ""
msgid "ClusterIntegration|Learn more about %{help_link_start}zones%{help_link_end}."
msgstr ""
-msgid "ClusterIntegration|Learn more about %{startLink}Regions %{externalLinkIcon}%{endLink}."
+msgid "ClusterIntegration|Learn more about %{linkStart}Regions%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Learn more about Kubernetes"
@@ -5660,12 +5868,18 @@ msgstr ""
msgid "ClusterIntegration|Machine type"
msgstr ""
+msgid "ClusterIntegration|Make sure your API endpoint is correct"
+msgstr ""
+
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create Kubernetes clusters"
msgstr ""
msgid "ClusterIntegration|Manage your Kubernetes cluster by visiting %{provider_link}"
msgstr ""
+msgid "ClusterIntegration|Namespace per environment"
+msgstr ""
+
msgid "ClusterIntegration|No IAM Roles found"
msgstr ""
@@ -5711,6 +5925,9 @@ msgstr ""
msgid "ClusterIntegration|No zones matched your search"
msgstr ""
+msgid "ClusterIntegration|Node calculations use the Kubernetes Metrics API. Make sure your cluster has metrics installed"
+msgstr ""
+
msgid "ClusterIntegration|Number of nodes"
msgstr ""
@@ -5753,6 +5970,9 @@ msgstr ""
msgid "ClusterIntegration|RBAC-enabled cluster"
msgstr ""
+msgid "ClusterIntegration|Read our %{linkStart}help page%{linkEnd} on Kubernetes cluster integration."
+msgstr ""
+
msgid "ClusterIntegration|Read our %{link_start}help page%{link_end} on Kubernetes cluster integration."
msgstr ""
@@ -5855,7 +6075,7 @@ msgstr ""
msgid "ClusterIntegration|Select a VPC to choose a subnet"
msgstr ""
-msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{linkStart}Amazon Web Services %{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select a network to choose a subnetwork"
@@ -5888,7 +6108,7 @@ msgstr ""
msgid "ClusterIntegration|Select project to choose zone"
msgstr ""
-msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select zone"
@@ -5978,9 +6198,18 @@ msgstr ""
msgid "ClusterIntegration|There was a problem authenticating with your cluster. Please ensure your CA Certificate and Token are valid."
msgstr ""
+msgid "ClusterIntegration|There was an HTTP error when connecting to your cluster."
+msgstr ""
+
msgid "ClusterIntegration|This account must have permissions to create a Kubernetes cluster in the %{link_to_container_project} specified below"
msgstr ""
+msgid "ClusterIntegration|This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
+msgstr ""
+
+msgid "ClusterIntegration|This is necessary to clear existing environment-namespace associations from clusters previously managed by GitLab."
+msgstr ""
+
msgid "ClusterIntegration|This option will allow you to install applications on RBAC clusters."
msgstr ""
@@ -6005,9 +6234,21 @@ msgstr ""
msgid "ClusterIntegration|To use a new project, first create one on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}."
msgstr ""
+msgid "ClusterIntegration|Troubleshooting tips:"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Authenticate"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Connect"
+msgstr ""
+
msgid "ClusterIntegration|Uninstall %{appTitle}"
msgstr ""
+msgid "ClusterIntegration|Unknown Error"
+msgstr ""
+
msgid "ClusterIntegration|Update %{appTitle}"
msgstr ""
@@ -6068,7 +6309,7 @@ msgstr ""
msgid "ClusterIntegration|Your cluster API is unreachable. Please ensure your API URL is correct."
msgstr ""
-msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Zone"
@@ -6188,6 +6429,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse all threads"
+msgstr ""
+
msgid "Collapse approvers"
msgstr ""
@@ -6337,7 +6581,7 @@ msgstr ""
msgid "Commit…"
msgstr ""
-msgid "Company"
+msgid "Community forum"
msgstr ""
msgid "Company name"
@@ -6346,6 +6590,9 @@ msgstr ""
msgid "Compare"
msgstr ""
+msgid "Compare %{oldCommitId}...%{newCommitId}"
+msgstr ""
+
msgid "Compare Git revisions"
msgstr ""
@@ -6361,6 +6608,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare submodule commit revisions"
+msgstr ""
+
msgid "Compare with previous version"
msgstr ""
@@ -6496,6 +6746,9 @@ msgstr ""
msgid "Configure the way a user creates a new account."
msgstr ""
+msgid "Configure which lists are shown for anyone who visits this board"
+msgstr ""
+
msgid "Confirm"
msgstr ""
@@ -6721,6 +6974,9 @@ msgstr[1] ""
msgid "ContainerRegistry|Set cleanup policy"
msgstr ""
+msgid "ContainerRegistry|Some tags were not deleted"
+msgstr ""
+
msgid "ContainerRegistry|Something went wrong while fetching the cleanup policy."
msgstr ""
@@ -6760,6 +7016,9 @@ msgstr ""
msgid "ContainerRegistry|Tags with names matching this regex pattern will %{italicStart}expire:%{italicEnd}"
msgstr ""
+msgid "ContainerRegistry|The cleanup policy timed out before it could delete all tags. An administrator can %{adminLinkStart}manually run cleanup now%{adminLinkEnd} or you can wait for the cleanup policy to automatically run again. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "ContainerRegistry|The last tag related to this image was recently removed. This empty image and any associated data will be automatically removed as part of the regular Garbage Collection process. If you have any questions, contact your administrator."
msgstr ""
@@ -6892,6 +7151,9 @@ msgstr ""
msgid "Contributions per group member"
msgstr ""
+msgid "Contributor"
+msgstr ""
+
msgid "Contributors"
msgstr ""
@@ -7021,6 +7283,9 @@ msgstr ""
msgid "Could not change HEAD: branch '%{branch}' does not exist"
msgstr ""
+msgid "Could not commit. An unexpected error occurred."
+msgstr ""
+
msgid "Could not connect to FogBugz, check your URL"
msgstr ""
@@ -7060,6 +7325,9 @@ msgstr ""
msgid "Could not find iteration"
msgstr ""
+msgid "Could not load instance counts. Please refresh the page to try again."
+msgstr ""
+
msgid "Could not remove the trigger."
msgstr ""
@@ -7084,10 +7352,10 @@ msgstr ""
msgid "Could not save prometheus manual configuration"
msgstr ""
-msgid "Could not udpdate wiki page"
+msgid "Could not update the LDAP settings"
msgstr ""
-msgid "Could not update the LDAP settings"
+msgid "Could not update wiki page"
msgstr ""
msgid "Could not upload your designs as one or more files uploaded are not supported."
@@ -7745,6 +8013,9 @@ msgstr ""
msgid "DastProfiles|Are you sure you want to delete this profile?"
msgstr ""
+msgid "DastProfiles|Could not create site validation token. Please refresh the page, or try again later."
+msgstr ""
+
msgid "DastProfiles|Could not create the scanner profile. Please try again."
msgstr ""
@@ -7769,6 +8040,12 @@ msgstr ""
msgid "DastProfiles|Could not fetch site profiles. Please refresh the page, or try again later."
msgstr ""
+msgid "DastProfiles|Could not retrieve site validation status. Please refresh the page, or try again later."
+msgstr ""
+
+msgid "DastProfiles|Could not update the scanner profile. Please try again."
+msgstr ""
+
msgid "DastProfiles|Could not update the site profile. Please try again."
msgstr ""
@@ -7784,7 +8061,7 @@ msgstr ""
msgid "DastProfiles|Download validation text file"
msgstr ""
-msgid "DastProfiles|Edit feature will come soon. Please create a new profile if changes needed"
+msgid "DastProfiles|Edit scanner profile"
msgstr ""
msgid "DastProfiles|Edit site profile"
@@ -7817,6 +8094,9 @@ msgstr ""
msgid "DastProfiles|No profiles created yet"
msgstr ""
+msgid "DastProfiles|Passive"
+msgstr ""
+
msgid "DastProfiles|Please enter a valid URL format, ex: http://www.example.com/home"
msgstr ""
@@ -7832,6 +8112,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan mode"
+msgstr ""
+
msgid "DastProfiles|Scanner Profile"
msgstr ""
@@ -7871,10 +8154,10 @@ msgstr ""
msgid "DastProfiles|Text file validation"
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
+msgid "DastProfiles|The maximum number of minutes allowed for the spider to traverse the site."
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the spider to traverse the site."
+msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
msgstr ""
msgid "DastProfiles|Validate"
@@ -7907,6 +8190,9 @@ msgstr ""
msgid "Date picker"
msgstr ""
+msgid "Date range"
+msgstr ""
+
msgid "Date range cannot exceed %{maxDateRange} days."
msgstr ""
@@ -7931,6 +8217,9 @@ msgstr ""
msgid "Days to merge"
msgstr ""
+msgid "Dear Administrator,"
+msgstr ""
+
msgid "Debug"
msgstr ""
@@ -8042,12 +8331,18 @@ msgstr ""
msgid "Delete"
msgstr ""
+msgid "Delete %{name}"
+msgstr ""
+
msgid "Delete Comment"
msgstr ""
msgid "Delete Snippet"
msgstr ""
+msgid "Delete Value Stream"
+msgstr ""
+
msgid "Delete account"
msgstr ""
@@ -8069,9 +8364,6 @@ msgstr ""
msgid "Delete label: %{label_name} ?"
msgstr ""
-msgid "Delete license"
-msgstr ""
-
msgid "Delete list"
msgstr ""
@@ -8147,15 +8439,6 @@ msgstr ""
msgid "Deleting a project places it into a read-only state until %{date}, at which point the project will be permanently deleted. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "Deleting the license failed."
-msgstr ""
-
-msgid "Deleting the license failed. The license was not found."
-msgstr ""
-
-msgid "Deleting the license failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "Deleting the project will delete its repository and all related resources including issues, merge requests etc."
msgstr ""
@@ -8651,7 +8934,10 @@ msgstr ""
msgid "DesignManagement|The maximum number of designs allowed to be uploaded is %{upload_limit}. Please try again."
msgstr ""
-msgid "DesignManagement|To upload designs, you'll need to enable LFS. %{requirements_link_start}More information%{requirements_link_end}"
+msgid "DesignManagement|There was an error moving your designs. Please upload your designs below."
+msgstr ""
+
+msgid "DesignManagement|To upload designs, you'll need to enable LFS and have admin enable hashed storage. %{requirements_link_start}More information%{requirements_link_end}"
msgstr ""
msgid "DesignManagement|Unresolve thread"
@@ -8663,6 +8949,9 @@ msgstr ""
msgid "DesignManagement|Upload skipped."
msgstr ""
+msgid "DesignManagement|Your designs are being copied and are on their way… Please refresh to update."
+msgstr ""
+
msgid "DesignManagement|and %{moreCount} more."
msgstr ""
@@ -8720,6 +9009,9 @@ msgstr ""
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
+msgid "Direct member"
+msgstr ""
+
msgid "Direction"
msgstr ""
@@ -8768,9 +9060,6 @@ msgstr ""
msgid "Discard draft"
msgstr ""
-msgid "Discard review"
-msgstr ""
-
msgid "DiscordService|Discord Notifications"
msgstr ""
@@ -8839,10 +9128,10 @@ msgstr ""
msgid "Dismiss Merge Request promotion"
msgstr ""
-msgid "Dismiss Selected"
+msgid "Dismiss Value Stream Analytics introduction box"
msgstr ""
-msgid "Dismiss Value Stream Analytics introduction box"
+msgid "Dismiss selected"
msgstr ""
msgid "Dismiss trial promotion"
@@ -8893,9 +9182,6 @@ msgstr ""
msgid "Documents reindexed: %{processed_documents} (%{percentage}%%)"
msgstr ""
-msgid "Doing"
-msgstr ""
-
msgid "Domain"
msgstr ""
@@ -9091,9 +9377,6 @@ msgstr ""
msgid "Edit environment"
msgstr ""
-msgid "Edit file"
-msgstr ""
-
msgid "Edit files in the editor and commit changes here"
msgstr ""
@@ -9106,6 +9389,12 @@ msgstr ""
msgid "Edit identity for %{user_name}"
msgstr ""
+msgid "Edit in Web IDE"
+msgstr ""
+
+msgid "Edit in single-file editor"
+msgstr ""
+
msgid "Edit issues"
msgstr ""
@@ -9133,10 +9422,10 @@ msgstr ""
msgid "Editing"
msgstr ""
-msgid "Elasticsearch"
+msgid "Elasticsearch AWS IAM credentials"
msgstr ""
-msgid "Elasticsearch AWS IAM credentials"
+msgid "Elasticsearch HTTP client timeout value in seconds."
msgstr ""
msgid "Elasticsearch indexing restrictions"
@@ -9145,9 +9434,6 @@ msgstr ""
msgid "Elasticsearch indexing started"
msgstr ""
-msgid "Elasticsearch integration. Elasticsearch AWS IAM."
-msgstr ""
-
msgid "Elasticsearch reindexing is already in progress"
msgstr ""
@@ -9175,9 +9461,6 @@ msgstr ""
msgid "Email Notification"
msgstr ""
-msgid "Email address"
-msgstr ""
-
msgid "Email could not be sent"
msgstr ""
@@ -9241,6 +9524,9 @@ msgstr ""
msgid "Emails sent from Service Desk will have this name"
msgstr ""
+msgid "Emails sent to %{email} will still be supported"
+msgstr ""
+
msgid "Emails separated by comma"
msgstr ""
@@ -9274,9 +9560,18 @@ msgstr ""
msgid "Enable"
msgstr ""
+msgid "Enable %{link_start}Gitpod%{link_end} integration to launch a development environment in your browser directly from GitLab."
+msgstr ""
+
msgid "Enable Auto DevOps"
msgstr ""
+msgid "Enable Gitpod"
+msgstr ""
+
+msgid "Enable Gitpod?"
+msgstr ""
+
msgid "Enable HTML emails"
msgstr ""
@@ -9406,9 +9701,6 @@ msgstr ""
msgid "Encountered an error while rendering: %{err}"
msgstr ""
-msgid "End date"
-msgstr ""
-
msgid "Ends at (UTC)"
msgstr ""
@@ -9568,7 +9860,7 @@ msgstr ""
msgid "EnvironmentsDashboard|The environments dashboard provides a summary of each project's environments' status, including pipeline and alert statuses."
msgstr ""
-msgid "EnvironmentsDashboard|This dashboard displays a maximum of 7 projects and 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
+msgid "EnvironmentsDashboard|This dashboard displays 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
msgstr ""
msgid "Environments|An error occurred while canceling the auto stop, please try again"
@@ -9889,6 +10181,9 @@ msgstr ""
msgid "Error deleting project. Check logs for error details."
msgstr ""
+msgid "Error fetching burnup chart data"
+msgstr ""
+
msgid "Error fetching diverging counts for branches. Please try again."
msgstr ""
@@ -9967,6 +10262,9 @@ msgstr ""
msgid "Error occurred when saving assignees"
msgstr ""
+msgid "Error occurred when saving reviewers"
+msgstr ""
+
msgid "Error occurred when toggling the notification subscription"
msgstr ""
@@ -10219,10 +10517,13 @@ msgstr ""
msgid "Expand all"
msgstr ""
-msgid "Expand approvers"
+msgid "Expand all files"
msgstr ""
-msgid "Expand dropdown"
+msgid "Expand all threads"
+msgstr ""
+
+msgid "Expand approvers"
msgstr ""
msgid "Expand milestones"
@@ -10393,6 +10694,9 @@ msgstr ""
msgid "Failed to create Merge Request. Please try again."
msgstr ""
+msgid "Failed to create To-Do for the design."
+msgstr ""
+
msgid "Failed to create a branch for this issue. Please try again."
msgstr ""
@@ -10432,6 +10736,12 @@ msgstr ""
msgid "Failed to load authors. Please try again."
msgstr ""
+msgid "Failed to load branches. Please try again."
+msgstr ""
+
+msgid "Failed to load deploy keys."
+msgstr ""
+
msgid "Failed to load emoji list."
msgstr ""
@@ -10447,6 +10757,9 @@ msgstr ""
msgid "Failed to load groups & users."
msgstr ""
+msgid "Failed to load groups, users and deploy keys."
+msgstr ""
+
msgid "Failed to load labels. Please try again."
msgstr ""
@@ -10456,6 +10769,12 @@ msgstr ""
msgid "Failed to load related branches"
msgstr ""
+msgid "Failed to load sidebar confidential toggle"
+msgstr ""
+
+msgid "Failed to load sidebar lock status"
+msgstr ""
+
msgid "Failed to load stacktrace."
msgstr ""
@@ -10483,6 +10802,9 @@ msgstr ""
msgid "Failed to publish issue on status page."
msgstr ""
+msgid "Failed to remove To-Do for the design."
+msgstr ""
+
msgid "Failed to remove a Zoom meeting"
msgstr ""
@@ -10525,6 +10847,9 @@ msgstr ""
msgid "Failed to signing using smartcard authentication"
msgstr ""
+msgid "Failed to toggle To-Do for the design."
+msgstr ""
+
msgid "Failed to update branch!"
msgstr ""
@@ -10638,7 +10963,7 @@ msgstr ""
msgid "FeatureFlags|Edit User List"
msgstr ""
-msgid "FeatureFlags|Enable features for specific users and specific environments by defining feature flag strategies."
+msgid "FeatureFlags|Enable features for specific users and environments by configuring feature flag strategies."
msgstr ""
msgid "FeatureFlags|Environment Spec"
@@ -10698,7 +11023,7 @@ msgstr ""
msgid "FeatureFlags|Include additional user IDs"
msgstr ""
-msgid "FeatureFlags|Install a %{docs_link_anchored_start}compatible client library%{docs_link_anchored_end} and specify the API URL, application name, and instance ID during the configuration setup. %{docs_link_start}More Information%{docs_link_end}"
+msgid "FeatureFlags|Install a %{docsLinkAnchoredStart}compatible client library%{docsLinkAnchoredEnd} and specify the API URL, application name, and instance ID during the configuration setup. %{docsLinkStart}More Information%{docsLinkEnd}"
msgstr ""
msgid "FeatureFlags|Instance ID"
@@ -10710,6 +11035,9 @@ msgstr ""
msgid "FeatureFlags|Loading feature flags"
msgstr ""
+msgid "FeatureFlags|Loading user lists"
+msgstr ""
+
msgid "FeatureFlags|More information"
msgstr ""
@@ -10728,7 +11056,7 @@ msgstr ""
msgid "FeatureFlags|New feature flag"
msgstr ""
-msgid "FeatureFlags|New list"
+msgid "FeatureFlags|New user list"
msgstr ""
msgid "FeatureFlags|Percent of users"
@@ -10767,6 +11095,9 @@ msgstr ""
msgid "FeatureFlags|There was an error fetching the feature flags."
msgstr ""
+msgid "FeatureFlags|There was an error fetching the user lists."
+msgstr ""
+
msgid "FeatureFlags|There was an error retrieving user lists"
msgstr ""
@@ -10782,6 +11113,9 @@ msgstr ""
msgid "FeatureFlags|User List"
msgstr ""
+msgid "FeatureFlags|User Lists"
+msgstr ""
+
msgid "FeatureFlag|List"
msgstr ""
@@ -10809,15 +11143,6 @@ msgstr ""
msgid "Fetching incoming email"
msgstr ""
-msgid "Fetching licenses failed."
-msgstr ""
-
-msgid "Fetching licenses failed. The request endpoint was not found."
-msgstr ""
-
-msgid "Fetching licenses failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "File"
msgstr ""
@@ -10920,12 +11245,21 @@ msgstr ""
msgid "Filter by status"
msgstr ""
+msgid "Filter by test cases that are currently archived."
+msgstr ""
+
+msgid "Filter by test cases that are currently opened."
+msgstr ""
+
msgid "Filter by two-factor authentication"
msgstr ""
msgid "Filter by user"
msgstr ""
+msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
+msgstr ""
+
msgid "Filter pipelines"
msgstr ""
@@ -10941,7 +11275,7 @@ msgstr ""
msgid "Filter results..."
msgstr ""
-msgid "Filter your projects by name"
+msgid "Filter your repositories by name"
msgstr ""
msgid "Filter..."
@@ -10950,7 +11284,7 @@ msgstr ""
msgid "Find File"
msgstr ""
-msgid "Find bugs in your code with coverage-guided fuzzing"
+msgid "Find bugs in your code with coverage-guided fuzzing."
msgstr ""
msgid "Find by path"
@@ -10977,9 +11311,6 @@ msgstr ""
msgid "Finish editing this message first!"
msgstr ""
-msgid "Finish review"
-msgstr ""
-
msgid "Finish setting up your dedicated account for %{group_name}."
msgstr ""
@@ -11049,6 +11380,9 @@ msgstr ""
msgid "Footer message"
msgstr ""
+msgid "For a faster browsing experience, some files are collapsed by default."
+msgstr ""
+
msgid "For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
@@ -11058,6 +11392,9 @@ msgstr ""
msgid "For more info, read the documentation."
msgstr ""
+msgid "For more information on how the number of active users is calculated, see the %{self_managed_subscriptions_doc_link} documentation."
+msgstr ""
+
msgid "For more information, go to the "
msgstr ""
@@ -11196,6 +11533,9 @@ msgstr ""
msgid "Generate new token"
msgstr ""
+msgid "Generic package file size in bytes"
+msgstr ""
+
msgid "Geo"
msgstr ""
@@ -11457,6 +11797,9 @@ msgstr ""
msgid "Geo|Please refer to Geo Troubleshooting."
msgstr ""
+msgid "Geo|Primary node"
+msgstr ""
+
msgid "Geo|Project"
msgstr ""
@@ -11499,6 +11842,9 @@ msgstr ""
msgid "Geo|Review replication status, and resynchronize and reverify items with the primary node."
msgstr ""
+msgid "Geo|Secondary node"
+msgstr ""
+
msgid "Geo|Status"
msgstr ""
@@ -11538,6 +11884,9 @@ msgstr ""
msgid "Geo|URL must be a valid url (ex: https://gitlab.com)"
msgstr ""
+msgid "Geo|Undefined"
+msgstr ""
+
msgid "Geo|Unknown state"
msgstr ""
@@ -11613,10 +11962,16 @@ msgstr ""
msgid "GitHub import"
msgstr ""
+msgid "GitLab"
+msgstr ""
+
msgid "GitLab / Unsubscribe"
msgstr ""
-msgid "GitLab Enterprise Edition %{plan}"
+msgid "GitLab API"
+msgstr ""
+
+msgid "GitLab Billing Team."
msgstr ""
msgid "GitLab Group Runners can execute code for all the projects in this group."
@@ -11628,12 +11983,18 @@ msgstr ""
msgid "GitLab Issue"
msgstr ""
+msgid "GitLab Pages"
+msgstr ""
+
msgid "GitLab Service Desk is a simple way to allow people to create issues in your GitLab instance without needing their own user account. It provides a unique email address for end users to create issues in a project, and replies can be sent either through the GitLab interface or by email. End users will only see the thread through email."
msgstr ""
msgid "GitLab Shared Runners execute code of different projects on the same Runner unless you configure GitLab Runner Autoscale with MaxBuilds 1 (which it is on GitLab.com)."
msgstr ""
+msgid "GitLab Shell"
+msgstr ""
+
msgid "GitLab Support Bot"
msgstr ""
@@ -11643,7 +12004,7 @@ msgstr ""
msgid "GitLab User"
msgstr ""
-msgid "GitLab allows you to continue using your license even if you exceed the number of seats you purchased. You will be required to pay for these seats when you renew your license."
+msgid "GitLab Workhorse"
msgstr ""
msgid "GitLab commit"
@@ -11811,6 +12172,21 @@ msgstr ""
msgid "Gitlab Pages"
msgstr ""
+msgid "Gitpod"
+msgstr ""
+
+msgid "Gitpod|Add the URL to your Gitpod instance configured to read your GitLab projects."
+msgstr ""
+
+msgid "Gitpod|Enable Gitpod integration"
+msgstr ""
+
+msgid "Gitpod|Gitpod URL"
+msgstr ""
+
+msgid "Gitpod|e.g. https://gitpod.example.com"
+msgstr ""
+
msgid "Given access %{time_ago}"
msgstr ""
@@ -12318,9 +12694,6 @@ msgstr ""
msgid "GroupSAML|Valid SAML Response"
msgstr ""
-msgid "GroupSAML|With group managed accounts enabled, all the users without a group managed account will be excluded from the group."
-msgstr ""
-
msgid "GroupSAML|With prohibit outer forks flag enabled group members will be able to fork project only inside your group."
msgstr ""
@@ -12534,10 +12907,10 @@ msgstr ""
msgid "GroupsNew|Create group"
msgstr ""
-msgid "GroupsNew|GitLab group export"
+msgid "GroupsNew|Import"
msgstr ""
-msgid "GroupsNew|Import"
+msgid "GroupsNew|Import a GitLab group export file"
msgstr ""
msgid "GroupsNew|Import group"
@@ -12680,6 +13053,9 @@ msgid_plural "Hide charts"
msgstr[0] ""
msgstr[1] ""
+msgid "Hide comments on this file"
+msgstr ""
+
msgid "Hide details"
msgstr ""
@@ -12724,6 +13100,15 @@ msgstr ""
msgid "Highest role:"
msgstr ""
+msgid "HighlightBar|Alert events:"
+msgstr ""
+
+msgid "HighlightBar|Alert start time:"
+msgstr ""
+
+msgid "HighlightBar|Original alert:"
+msgstr ""
+
msgid "History"
msgstr ""
@@ -12901,6 +13286,9 @@ msgstr ""
msgid "If enabled, access to projects will be validated on an external service using their classification label."
msgstr ""
+msgid "If the number of active users exceeds the user limit, you will be charged for the number of %{users_over_license_link} at your next license reconciliation."
+msgstr ""
+
msgid "If there is no previous license or if the previous license has expired, some GitLab functionality will be blocked until a new, valid license is uploaded."
msgstr ""
@@ -12940,9 +13328,6 @@ msgstr ""
msgid "If your HTTP repository is not publicly accessible, add your credentials."
msgstr ""
-msgid "Iglu registry URL (optional)"
-msgstr ""
-
msgid "Ignore"
msgstr ""
@@ -12979,6 +13364,16 @@ msgstr ""
msgid "Import"
msgstr ""
+msgid "Import %d compatible repository"
+msgid_plural "Import %d compatible repositories"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Import %d repository"
+msgid_plural "Import %d repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Import CSV"
msgstr ""
@@ -12988,15 +13383,9 @@ msgstr ""
msgid "Import all compatible projects"
msgstr ""
-msgid "Import all compatible repositories"
-msgstr ""
-
msgid "Import all projects"
msgstr ""
-msgid "Import all repositories"
-msgstr ""
-
msgid "Import an exported GitLab project"
msgstr ""
@@ -13084,6 +13473,9 @@ msgstr ""
msgid "ImportProjects|Error importing repository %{project_safe_import_url} into %{project_full_path} - %{message}"
msgstr ""
+msgid "ImportProjects|Import repositories"
+msgstr ""
+
msgid "ImportProjects|Importing the project failed"
msgstr ""
@@ -13096,7 +13488,7 @@ msgstr ""
msgid "ImportProjects|Requesting your %{provider} repositories failed"
msgstr ""
-msgid "ImportProjects|Select the projects you want to import"
+msgid "ImportProjects|Select the repositories you want to import"
msgstr ""
msgid "ImportProjects|The remote data could not be imported."
@@ -13132,9 +13524,6 @@ msgstr ""
msgid "In order to enable Service Desk for your instance, you must first set up incoming email."
msgstr ""
-msgid "In order to gather accurate feature usage data, it can take 1 to 2 weeks to see your index."
-msgstr ""
-
msgid "In order to personalize your experience with GitLab%{br_tag}we would like to know a bit more about you."
msgstr ""
@@ -13165,18 +13554,30 @@ msgstr ""
msgid "IncidentManagement|Create incident"
msgstr ""
+msgid "IncidentManagement|Critical - S1"
+msgstr ""
+
msgid "IncidentManagement|Date created"
msgstr ""
msgid "IncidentManagement|Display your incidents in a dedicated view"
msgstr ""
+msgid "IncidentManagement|High - S2"
+msgstr ""
+
msgid "IncidentManagement|Incident"
msgstr ""
msgid "IncidentManagement|Incidents"
msgstr ""
+msgid "IncidentManagement|Low - S4"
+msgstr ""
+
+msgid "IncidentManagement|Medium - S3"
+msgstr ""
+
msgid "IncidentManagement|No incidents to display."
msgstr ""
@@ -13189,6 +13590,9 @@ msgstr ""
msgid "IncidentManagement|Published to status page"
msgstr ""
+msgid "IncidentManagement|Severity"
+msgstr ""
+
msgid "IncidentManagement|There are no closed incidents"
msgstr ""
@@ -13198,6 +13602,9 @@ msgstr ""
msgid "IncidentManagement|Unassigned"
msgstr ""
+msgid "IncidentManagement|Unknown"
+msgstr ""
+
msgid "IncidentManagement|Unpublished"
msgstr ""
@@ -13219,6 +13626,15 @@ msgstr ""
msgid "Incidents"
msgstr ""
+msgid "Incident|Alert details"
+msgstr ""
+
+msgid "Incident|Summary"
+msgstr ""
+
+msgid "Incident|There was an issue loading alert data. Please try again."
+msgstr ""
+
msgid "Include a Terms of Service agreement and Privacy Policy that all users must accept."
msgstr ""
@@ -13279,6 +13695,9 @@ msgstr ""
msgid "Information about additional Pages templates and how to install them can be found in our %{pages_getting_started_guide}."
msgstr ""
+msgid "Inherited"
+msgstr ""
+
msgid "Inherited:"
msgstr ""
@@ -13359,7 +13778,22 @@ msgstr ""
msgid "Instance administrators group already exists"
msgstr ""
-msgid "Instance license"
+msgid "InstanceStatistics|Groups"
+msgstr ""
+
+msgid "InstanceStatistics|Issues"
+msgstr ""
+
+msgid "InstanceStatistics|Merge Requests"
+msgstr ""
+
+msgid "InstanceStatistics|Pipelines"
+msgstr ""
+
+msgid "InstanceStatistics|Projects"
+msgstr ""
+
+msgid "InstanceStatistics|Users"
msgstr ""
msgid "Integration"
@@ -13371,6 +13805,12 @@ msgstr ""
msgid "Integrations"
msgstr ""
+msgid "Integrations|%{integration} settings saved and active."
+msgstr ""
+
+msgid "Integrations|%{integration} settings saved, but not active."
+msgstr ""
+
msgid "Integrations|All details"
msgstr ""
@@ -13380,6 +13820,12 @@ msgstr ""
msgid "Integrations|Comment settings:"
msgstr ""
+msgid "Integrations|Connection failed. Please check your settings."
+msgstr ""
+
+msgid "Integrations|Connection successful."
+msgstr ""
+
msgid "Integrations|Default settings are inherited from the group level."
msgstr ""
@@ -13395,6 +13841,15 @@ msgstr ""
msgid "Integrations|Includes commit title and branch"
msgstr ""
+msgid "Integrations|Projects using custom settings will not be impacted unless the project owner chooses to use instance-level defaults."
+msgstr ""
+
+msgid "Integrations|Save settings?"
+msgstr ""
+
+msgid "Integrations|Saving will update the default settings for all projects that are not using custom settings."
+msgstr ""
+
msgid "Integrations|Standard"
msgstr ""
@@ -13527,6 +13982,9 @@ msgstr ""
msgid "Invitation"
msgstr ""
+msgid "Invitation declined"
+msgstr ""
+
msgid "Invite"
msgstr ""
@@ -13578,6 +14036,42 @@ 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|%{linkStart}Read more%{linkEnd} about role permissions"
+msgstr ""
+
+msgid "InviteMembersModal|Access expiration date (optional)"
+msgstr ""
+
+msgid "InviteMembersModal|Cancel"
+msgstr ""
+
+msgid "InviteMembersModal|Choose a role permission"
+msgstr ""
+
+msgid "InviteMembersModal|GitLab member or Email address"
+msgstr ""
+
+msgid "InviteMembersModal|Invite"
+msgstr ""
+
+msgid "InviteMembersModal|Invite team members"
+msgstr ""
+
+msgid "InviteMembersModal|Search for members to invite"
+msgstr ""
+
+msgid "InviteMembersModal|User not invited. Feature coming soon!"
+msgstr ""
+
+msgid "InviteMembersModal|Users were succesfully added"
+msgstr ""
+
+msgid "InviteMembersModal|You're inviting members to the %{group_name} group"
+msgstr ""
+
+msgid "InviteMembers|Invite team members"
+msgstr ""
+
msgid "Invited"
msgstr ""
@@ -13632,10 +14126,13 @@ msgstr ""
msgid "Issue cannot be found."
msgstr ""
+msgid "Issue created from vulnerability %{vulnerability_link}"
+msgstr ""
+
msgid "Issue events"
msgstr ""
-msgid "Issue first depoloyed to production"
+msgid "Issue first deployed to production"
msgstr ""
msgid "Issue label"
@@ -13713,6 +14210,9 @@ msgstr ""
msgid "IssueTracker|Custom issue tracker"
msgstr ""
+msgid "IssueTracker|EWM work items tracker"
+msgstr ""
+
msgid "IssueTracker|Redmine issue tracker"
msgstr ""
@@ -13779,6 +14279,9 @@ msgstr ""
msgid "It looks like you have some draft commits in this branch."
msgstr ""
+msgid "It may be several days before you see feature usage data."
+msgstr ""
+
msgid "It must have a header row and at least two columns: the first column is the issue title and the second column is the issue description. The separator is automatically detected."
msgstr ""
@@ -14061,13 +14564,13 @@ msgstr ""
msgid "Join Zoom meeting"
msgstr ""
-msgid "Jul"
+msgid "Joined %{time_ago}"
msgstr ""
-msgid "July"
+msgid "Jul"
msgstr ""
-msgid "Jump to first unresolved thread"
+msgid "July"
msgstr ""
msgid "Jump to next unresolved thread"
@@ -14103,6 +14606,9 @@ msgstr ""
msgid "Keyboard shortcuts"
msgstr ""
+msgid "KeyboardKey|Ctrl+"
+msgstr ""
+
msgid "Keys"
msgstr ""
@@ -14151,6 +14657,9 @@ msgstr ""
msgid "LDAP Synchronization"
msgstr ""
+msgid "LDAP group settings"
+msgstr ""
+
msgid "LDAP settings"
msgstr ""
@@ -14160,6 +14669,9 @@ msgstr ""
msgid "LDAP sync in progress. This could take a few minutes. Refresh the page to see the changes."
msgstr ""
+msgid "LDAP synchronizations"
+msgstr ""
+
msgid "LFS"
msgstr ""
@@ -14240,7 +14752,16 @@ msgid_plural "Last %d days"
msgstr[0] ""
msgstr[1] ""
-msgid "Last %{days} days"
+msgid "Last 2 weeks"
+msgstr ""
+
+msgid "Last 30 days"
+msgstr ""
+
+msgid "Last 60 days"
+msgstr ""
+
+msgid "Last 90 days"
msgstr ""
msgid "Last Accessed On"
@@ -14318,6 +14839,9 @@ msgstr ""
msgid "Last used on:"
msgstr ""
+msgid "Last week"
+msgstr ""
+
msgid "LastCommit|authored"
msgstr ""
@@ -14333,6 +14857,9 @@ msgstr ""
msgid "Latest pipeline for the most recent commit on this branch"
msgstr ""
+msgid "Launch a ready-to-code development environment for your project."
+msgstr ""
+
msgid "Lead"
msgstr ""
@@ -14713,6 +15240,9 @@ msgstr ""
msgid "List of all merge commits"
msgstr ""
+msgid "List options"
+msgstr ""
+
msgid "List settings"
msgstr ""
@@ -14725,9 +15255,6 @@ msgstr ""
msgid "List your Bitbucket Server repositories"
msgstr ""
-msgid "Lists"
-msgstr ""
-
msgid "Live preview"
msgstr ""
@@ -14974,6 +15501,12 @@ msgstr ""
msgid "Mark as done"
msgstr ""
+msgid "Mark as draft"
+msgstr ""
+
+msgid "Mark as ready"
+msgstr ""
+
msgid "Mark as resolved"
msgstr ""
@@ -14995,6 +15528,24 @@ msgstr ""
msgid "Markdown is supported"
msgstr ""
+msgid "MarkdownEditor|Add a link (%{modifierKey}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add a link (%{modifier_key}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifierKey}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifier_key}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifierKey}I)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifier_key}I)"
+msgstr ""
+
msgid "Marked For Deletion At - %{deletion_time}"
msgstr ""
@@ -15079,7 +15630,25 @@ msgstr ""
msgid "Max access level"
msgstr ""
-msgid "Max seats used"
+msgid "Max role"
+msgstr ""
+
+msgid "Max size 15 MB"
+msgstr ""
+
+msgid "Maximum Conan package file size in bytes"
+msgstr ""
+
+msgid "Maximum Maven package file size in bytes"
+msgstr ""
+
+msgid "Maximum NPM package file size in bytes"
+msgstr ""
+
+msgid "Maximum NuGet package file size in bytes"
+msgstr ""
+
+msgid "Maximum PyPI package file size in bytes"
msgstr ""
msgid "Maximum Users:"
@@ -15211,6 +15780,18 @@ msgstr ""
msgid "Members with access to %{strong_start}%{group_name}%{strong_end}"
msgstr ""
+msgid "Members|%{time} by %{user}"
+msgstr ""
+
+msgid "Members|Expired"
+msgstr ""
+
+msgid "Members|No expiration set"
+msgstr ""
+
+msgid "Members|in %{time}"
+msgstr ""
+
msgid "Memory Usage"
msgstr ""
@@ -15397,9 +15978,6 @@ msgstr ""
msgid "MergeRequests|Thread will be unresolved"
msgstr ""
-msgid "MergeRequests|Toggle comments for this file"
-msgstr ""
-
msgid "MergeRequests|View file @ %{commitId}"
msgstr ""
@@ -15460,6 +16038,9 @@ msgstr ""
msgid "Merging immediately isn't recommended as it may negatively impact the existing merge train. Read the %{docsLinkStart}documentation%{docsLinkEnd} for more information."
msgstr ""
+msgid "Message"
+msgstr ""
+
msgid "Messages"
msgstr ""
@@ -15845,18 +16426,12 @@ msgid_plural "Milestones"
msgstr[0] ""
msgstr[1] ""
-msgid "Milestone does not support burnup charts"
-msgstr ""
-
msgid "Milestone lists not available with your current license"
msgstr ""
msgid "Milestone lists show all issues from the selected milestone."
msgstr ""
-msgid "Milestone must have a start and due date"
-msgstr ""
-
msgid "MilestoneSidebar|Closed:"
msgstr ""
@@ -16223,6 +16798,9 @@ msgstr ""
msgid "Namespace"
msgstr ""
+msgid "Namespace ID:"
+msgstr ""
+
msgid "Namespace is empty"
msgstr ""
@@ -16307,6 +16885,9 @@ msgstr ""
msgid "NetworkPolicies|Allow all outbound traffic from %{selector} to %{ruleSelector} on %{ports}"
msgstr ""
+msgid "NetworkPolicies|Are you sure you want to delete this policy? This action cannot be undone."
+msgstr ""
+
msgid "NetworkPolicies|Choose whether to enforce this policy."
msgstr ""
@@ -16316,12 +16897,21 @@ msgstr ""
msgid "NetworkPolicies|Define this policy's location, conditions and actions."
msgstr ""
+msgid "NetworkPolicies|Delete policy"
+msgstr ""
+
+msgid "NetworkPolicies|Delete policy: %{policy}"
+msgstr ""
+
msgid "NetworkPolicies|Deny all traffic"
msgstr ""
msgid "NetworkPolicies|Description"
msgstr ""
+msgid "NetworkPolicies|Edit policy"
+msgstr ""
+
msgid "NetworkPolicies|Editor mode"
msgstr ""
@@ -16349,6 +16939,9 @@ msgstr ""
msgid "NetworkPolicies|Name"
msgstr ""
+msgid "NetworkPolicies|Namespace"
+msgstr ""
+
msgid "NetworkPolicies|Network Policy"
msgstr ""
@@ -16400,6 +16993,9 @@ msgstr ""
msgid "NetworkPolicies|Rules"
msgstr ""
+msgid "NetworkPolicies|Save changes"
+msgstr ""
+
msgid "NetworkPolicies|Something went wrong, failed to update policy"
msgstr ""
@@ -16412,6 +17008,9 @@ msgstr ""
msgid "NetworkPolicies|Traffic that does not match any rule will be blocked."
msgstr ""
+msgid "NetworkPolicies|Unable to parse policy"
+msgstr ""
+
msgid "NetworkPolicies|YAML editor"
msgstr ""
@@ -16525,6 +17124,9 @@ msgstr ""
msgid "New Snippet"
msgstr ""
+msgid "New Test Case"
+msgstr ""
+
msgid "New User"
msgstr ""
@@ -16624,6 +17226,9 @@ msgstr ""
msgid "New tag"
msgstr ""
+msgid "New test case"
+msgstr ""
+
msgid "New users set to external"
msgstr ""
@@ -16696,7 +17301,7 @@ msgstr ""
msgid "No changes"
msgstr ""
-msgid "No changes between %{ref_start}%{source_branch}%{ref_end} and %{ref_start}%{target_branch}%{ref_end}"
+msgid "No changes between %{sourceBranch} and %{targetBranch}"
msgstr ""
msgid "No child epics match applied filters"
@@ -16711,6 +17316,9 @@ msgstr ""
msgid "No containers available"
msgstr ""
+msgid "No content to show"
+msgstr ""
+
msgid "No contributions"
msgstr ""
@@ -16786,9 +17394,6 @@ msgstr ""
msgid "No license. All rights reserved"
msgstr ""
-msgid "No licenses found."
-msgstr ""
-
msgid "No matches found"
msgstr ""
@@ -16801,6 +17406,9 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No members found"
+msgstr ""
+
msgid "No merge requests found"
msgstr ""
@@ -16822,6 +17430,9 @@ msgstr ""
msgid "No parent group"
msgstr ""
+msgid "No plan"
+msgstr ""
+
msgid "No pods available"
msgstr ""
@@ -16918,6 +17529,12 @@ msgstr ""
msgid "Not Implemented"
msgstr ""
+msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+msgstr ""
+
+msgid "Not all browsers support WebAuthn. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even from an unsupported browser."
+msgstr ""
+
msgid "Not all data has been processed yet, the accuracy of the chart for the selected timeframe is limited."
msgstr ""
@@ -17014,6 +17631,9 @@ msgstr ""
msgid "Notification settings saved"
msgstr ""
+msgid "NotificationEvent|Change reviewer merge request"
+msgstr ""
+
msgid "NotificationEvent|Close issue"
msgstr ""
@@ -17176,10 +17796,7 @@ msgstr ""
msgid "On track"
msgstr ""
-msgid "OnDemandScans|Attached branch"
-msgstr ""
-
-msgid "OnDemandScans|Attached branch is where the scan job runs."
+msgid "OnDemandScans|Could not fetch scanner profiles. Please refresh the page, or try again later."
msgstr ""
msgid "OnDemandScans|Could not fetch site profiles. Please refresh the page, or try again later."
@@ -17188,6 +17805,9 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
+msgid "OnDemandScans|Create a new scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Create a new site profile"
msgstr ""
@@ -17200,6 +17820,9 @@ msgstr ""
msgid "OnDemandScans|New on-demand DAST scan"
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 ""
@@ -17209,16 +17832,10 @@ msgstr ""
msgid "OnDemandScans|On-demand scans run outside the DevOps cycle and find vulnerabilities in your projects. %{learnMoreLinkStart}Learn more%{learnMoreLinkEnd}"
msgstr ""
-msgid "OnDemandScans|Only a passive scan can be performed on demand."
-msgstr ""
-
-msgid "OnDemandScans|Passive"
-msgstr ""
-
msgid "OnDemandScans|Run scan"
msgstr ""
-msgid "OnDemandScans|Scan mode"
+msgid "OnDemandScans|Scanner profile"
msgstr ""
msgid "OnDemandScans|Scanner settings"
@@ -17230,9 +17847,15 @@ msgstr ""
msgid "OnDemandScans|Select one of the existing profiles"
msgstr ""
+msgid "OnDemandScans|Site profile"
+msgstr ""
+
msgid "OnDemandScans|Site profiles"
msgstr ""
+msgid "OnDemandScans|Use existing scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Use existing site profile"
msgstr ""
@@ -17331,9 +17954,6 @@ msgstr ""
msgid "Open Selection"
msgstr ""
-msgid "Open Web IDE"
-msgstr ""
-
msgid "Open comment type dropdown"
msgstr ""
@@ -17439,6 +18059,9 @@ msgstr ""
msgid "Origin"
msgstr ""
+msgid "Orphaned member"
+msgstr ""
+
msgid "Other Labels"
msgstr ""
@@ -17454,6 +18077,9 @@ msgstr ""
msgid "Other visibility settings have been disabled by the administrator."
msgstr ""
+msgid "Our documentation includes an example DevOps Score report."
+msgstr ""
+
msgid "Out-of-compliance with this project's policies and should be removed"
msgstr ""
@@ -17478,6 +18104,9 @@ msgstr ""
msgid "Overwrite diverged branches"
msgstr ""
+msgid "Owned by %{image_tag}"
+msgstr ""
+
msgid "Owned by anyone"
msgstr ""
@@ -17499,6 +18128,9 @@ msgstr ""
msgid "Package deleted successfully"
msgstr ""
+msgid "Package file size limits"
+msgstr ""
+
msgid "Package recipe already exists"
msgstr ""
@@ -17514,9 +18146,6 @@ msgstr ""
msgid "Package type must be PyPi"
msgstr ""
-msgid "Package was removed"
-msgstr ""
-
msgid "PackageRegistry|%{name} version %{version} was created %{datetime}"
msgstr ""
@@ -17658,12 +18287,18 @@ msgstr ""
msgid "PackageRegistry|NuGet Command"
msgstr ""
+msgid "PackageRegistry|Package Registry"
+msgstr ""
+
msgid "PackageRegistry|Pip Command"
msgstr ""
msgid "PackageRegistry|Pipeline %{link} triggered %{datetime} by %{author}"
msgstr ""
+msgid "PackageRegistry|Publish and share packages for a variety of common package managers. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "PackageRegistry|Published to the %{project} Package Registry %{datetime}"
msgstr ""
@@ -17763,6 +18398,9 @@ msgstr ""
msgid "Page not found"
msgstr ""
+msgid "Page settings"
+msgstr ""
+
msgid "Page was successfully deleted"
msgstr ""
@@ -17904,7 +18542,7 @@ msgstr ""
msgid "Paste issue link"
msgstr ""
-msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Don't use your private SSH key."
+msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Do not paste your private SSH key, as that can compromise your identity."
msgstr ""
msgid "Patch to apply"
@@ -17931,6 +18569,9 @@ msgstr ""
msgid "Pending"
msgstr ""
+msgid "Pending comments"
+msgstr ""
+
msgid "People without permission will never get a notification and won't be able to comment."
msgstr ""
@@ -18129,6 +18770,9 @@ msgstr ""
msgid "Pipelines|Build with confidence"
msgstr ""
+msgid "Pipelines|By revoking a trigger you will break any processes making use of it. Are you sure?"
+msgstr ""
+
msgid "Pipelines|CI Lint"
msgstr ""
@@ -18141,6 +18785,15 @@ msgstr ""
msgid "Pipelines|Continuous Integration can help catch bugs by running your tests automatically, while Continuous Deployment can help you deliver code to your product environment."
msgstr ""
+msgid "Pipelines|Copy trigger token"
+msgstr ""
+
+msgid "Pipelines|Description"
+msgstr ""
+
+msgid "Pipelines|Edit"
+msgstr ""
+
msgid "Pipelines|Get started with Pipelines"
msgstr ""
@@ -18156,15 +18809,27 @@ msgstr ""
msgid "Pipelines|It is recommended the code is reviewed thoroughly before running this pipeline with the parent project's CI resource."
msgstr ""
+msgid "Pipelines|Last Used"
+msgstr ""
+
msgid "Pipelines|Loading Pipelines"
msgstr ""
msgid "Pipelines|More Information"
msgstr ""
+msgid "Pipelines|No triggers have been created yet. Add one using the form above."
+msgstr ""
+
+msgid "Pipelines|Owner"
+msgstr ""
+
msgid "Pipelines|Project cache successfully reset."
msgstr ""
+msgid "Pipelines|Revoke"
+msgstr ""
+
msgid "Pipelines|Run Pipeline"
msgstr ""
@@ -18189,6 +18854,15 @@ msgstr ""
msgid "Pipelines|This project is not currently set up to run pipelines."
msgstr ""
+msgid "Pipelines|Token"
+msgstr ""
+
+msgid "Pipelines|Trigger user has insufficient permissions to project"
+msgstr ""
+
+msgid "Pipelines|invalid"
+msgstr ""
+
msgid "Pipelines|parent"
msgstr ""
@@ -18447,10 +19121,10 @@ msgstr ""
msgid "Please provide attributes to update"
msgstr ""
-msgid "Please refer to %{docs_url}"
+msgid "Please reach out if you have any questions and we'll be happy to assist."
msgstr ""
-msgid "Please retype the email address."
+msgid "Please refer to %{docs_url}"
msgstr ""
msgid "Please select"
@@ -18480,6 +19154,9 @@ msgstr ""
msgid "Please set a new password before proceeding."
msgstr ""
+msgid "Please share your feedback about %{featureName} %{linkStart}in this issue%{linkEnd} to help us improve the experience."
+msgstr ""
+
msgid "Please solve the reCAPTCHA"
msgstr ""
@@ -18783,6 +19460,9 @@ msgstr ""
msgid "Profiles| You are going to change the username %{currentUsernameBold} to %{newUsernameBold}. Profile and projects will be redirected to the %{newUsername} namespace but this redirect will expire once the %{currentUsername} namespace is registered by another user or group. Please update your Git repository remotes as soon as possible."
msgstr ""
+msgid "Profiles|%{provider} Active"
+msgstr ""
+
msgid "Profiles|@username"
msgstr ""
@@ -18834,7 +19514,7 @@ msgstr ""
msgid "Profiles|Commit email"
msgstr ""
-msgid "Profiles|Connect"
+msgid "Profiles|Connect %{provider}"
msgstr ""
msgid "Profiles|Connected Accounts"
@@ -18858,6 +19538,9 @@ msgstr ""
msgid "Profiles|Disconnect"
msgstr ""
+msgid "Profiles|Disconnect %{provider}"
+msgstr ""
+
msgid "Profiles|Do not show on profile"
msgstr ""
@@ -18882,7 +19565,7 @@ msgstr ""
msgid "Profiles|Full name"
msgstr ""
-msgid "Profiles|Give your individual key a title. This will be publically visible."
+msgid "Profiles|Give your individual key a title."
msgstr ""
msgid "Profiles|Include private contributions on my profile"
@@ -18972,7 +19655,7 @@ msgstr ""
msgid "Profiles|The maximum file size allowed is 200KB."
msgstr ""
-msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it?"
+msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it? It will be publicly visible."
msgstr ""
msgid "Profiles|This email will be displayed on your public profile"
@@ -19047,6 +19730,9 @@ msgstr ""
msgid "Profiles|You don't have access to delete this user."
msgstr ""
+msgid "Profiles|You must transfer ownership or delete groups you are an owner of before you can delete your account"
+msgstr ""
+
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
@@ -19635,6 +20321,9 @@ msgstr ""
msgid "ProjectTemplates|GitLab Cluster Management"
msgstr ""
+msgid "ProjectTemplates|Gitpod/Spring Petclinic"
+msgstr ""
+
msgid "ProjectTemplates|Go Micro"
msgstr ""
@@ -20244,6 +20933,9 @@ msgstr ""
msgid "Publish to status page"
msgstr ""
+msgid "Published"
+msgstr ""
+
msgid "Published on status page"
msgstr ""
@@ -20361,9 +21053,15 @@ msgstr ""
msgid "Quick range"
msgstr ""
+msgid "Quickly and easily edit multiple files in your project."
+msgstr ""
+
msgid "README"
msgstr ""
+msgid "Rails"
+msgstr ""
+
msgid "Rake Tasks Help"
msgstr ""
@@ -20483,10 +21181,13 @@ msgstr ""
msgid "Register Two-Factor Authenticator"
msgstr ""
-msgid "Register U2F device"
+msgid "Register Universal Two-Factor (U2F) Device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register WebAuthn Device"
+msgstr ""
+
+msgid "Register device"
msgstr ""
msgid "Register for GitLab"
@@ -20498,9 +21199,6 @@ msgstr ""
msgid "Register with two-factor app"
msgstr ""
-msgid "Registration"
-msgstr ""
-
msgid "Registration|Checkout"
msgstr ""
@@ -20617,9 +21315,6 @@ msgstr ""
msgid "Release|Something went wrong while saving the release details"
msgstr ""
-msgid "Remediated: needs review"
-msgstr ""
-
msgid "Remediations"
msgstr ""
@@ -20725,6 +21420,9 @@ msgstr ""
msgid "Remove priority"
msgstr ""
+msgid "Remove report"
+msgstr ""
+
msgid "Remove secondary node"
msgstr ""
@@ -20737,6 +21435,12 @@ msgstr ""
msgid "Remove time estimate"
msgstr ""
+msgid "Remove user & report"
+msgstr ""
+
+msgid "Remove user from group"
+msgstr ""
+
msgid "Removed"
msgstr ""
@@ -20818,9 +21522,6 @@ msgstr ""
msgid "Removes time estimate."
msgstr ""
-msgid "Removing license…"
-msgstr ""
-
msgid "Removing this group also removes all child projects, including archived projects, and their resources."
msgstr ""
@@ -20905,6 +21606,9 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
+msgid "Reported by %{reporter}"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -20991,6 +21695,27 @@ msgstr ""
msgid "Repositories"
msgstr ""
+msgid "Repositories Analytics"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download Historic Test Coverage Data"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download historic test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Historic Test Coverage Data is available in raw format (.csv) for further analysis."
+msgstr ""
+
+msgid "RepositoriesAnalytics|Test Code Coverage"
+msgstr ""
+
+msgid "RepositoriesAnalytics|There was an error fetching the projects."
+msgstr ""
+
msgid "Repository"
msgstr ""
@@ -21069,9 +21794,15 @@ msgstr ""
msgid "Request parameter %{param} is missing."
msgstr ""
+msgid "Request review from"
+msgstr ""
+
msgid "Request to link SAML account must be authorized"
msgstr ""
+msgid "Requested"
+msgstr ""
+
msgid "Requested %{time_ago}"
msgstr ""
@@ -21090,6 +21821,9 @@ msgstr ""
msgid "Requests to these domain(s)/address(es) on the local network will be allowed when local requests from hooks and services are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 or 127.0.0.0/28 are supported. Domain wildcards are not supported currently. Use comma, semicolon, or newline to separate multiple entries. The allowlist can hold a maximum of 1000 entries. Domains should use IDNA encoding. Ex: example.com, 192.168.1.1, 127.0.0.0/28, xn--itlab-j1a.com."
msgstr ""
+msgid "Require admin approval for new sign-ups"
+msgstr ""
+
msgid "Require all users in this group to setup Two-factor authentication"
msgstr ""
@@ -21217,9 +21951,6 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
-msgid "Resolved by %{resolvedByName}"
-msgstr ""
-
msgid "Resolves IP addresses once and uses them to submit requests"
msgstr ""
@@ -21339,6 +22070,14 @@ msgstr ""
msgid "ReviewApp|Enable Review App"
msgstr ""
+msgid "Reviewer"
+msgid_plural "%d Reviewers"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Reviewer(s)"
+msgstr ""
+
msgid "Reviewing"
msgstr ""
@@ -21378,6 +22117,9 @@ msgstr ""
msgid "Rook"
msgstr ""
+msgid "Ruby"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -21456,6 +22198,63 @@ msgstr ""
msgid "Runners page."
msgstr ""
+msgid "Runners|Active"
+msgstr ""
+
+msgid "Runners|Architecture"
+msgstr ""
+
+msgid "Runners|Can run untagged jobs"
+msgstr ""
+
+msgid "Runners|Description"
+msgstr ""
+
+msgid "Runners|Group"
+msgstr ""
+
+msgid "Runners|IP Address"
+msgstr ""
+
+msgid "Runners|Last contact"
+msgstr ""
+
+msgid "Runners|Locked to this project"
+msgstr ""
+
+msgid "Runners|Maximum job timeout"
+msgstr ""
+
+msgid "Runners|Name"
+msgstr ""
+
+msgid "Runners|Platform"
+msgstr ""
+
+msgid "Runners|Property Name"
+msgstr ""
+
+msgid "Runners|Protected"
+msgstr ""
+
+msgid "Runners|Revision"
+msgstr ""
+
+msgid "Runners|Shared"
+msgstr ""
+
+msgid "Runners|Specific"
+msgstr ""
+
+msgid "Runners|Tags"
+msgstr ""
+
+msgid "Runners|Value"
+msgstr ""
+
+msgid "Runners|Version"
+msgstr ""
+
msgid "Runners|You have used %{quotaUsed} out of %{quotaLimit} of your shared Runners pipeline minutes."
msgstr ""
@@ -21468,6 +22267,9 @@ msgstr ""
msgid "Runs a number of housekeeping tasks within the current repository, such as compressing file revisions and removing unreachable objects."
msgstr ""
+msgid "SAML"
+msgstr ""
+
msgid "SAML SSO"
msgstr ""
@@ -21519,6 +22321,9 @@ msgstr ""
msgid "Save"
msgstr ""
+msgid "Save %{name} size limits"
+msgstr ""
+
msgid "Save Changes"
msgstr ""
@@ -21549,9 +22354,6 @@ msgstr ""
msgid "Save space and find tags in the Container Registry more easily. Enable the cleanup policy to remove stale tags and keep only the ones you need."
msgstr ""
-msgid "Save template"
-msgstr ""
-
msgid "Save variables"
msgstr ""
@@ -21594,9 +22396,6 @@ msgstr ""
msgid "Scope"
msgstr ""
-msgid "Scope not supported with disabled 'users_search' feature!"
-msgstr ""
-
msgid "Scoped issue boards"
msgstr ""
@@ -21723,9 +22522,6 @@ msgstr ""
msgid "Search requirements"
msgstr ""
-msgid "Search results…"
-msgstr ""
-
msgid "Search users"
msgstr ""
@@ -21798,6 +22594,11 @@ msgid_plural "SearchResults|commits"
msgstr[0] ""
msgstr[1] ""
+msgid "SearchResults|epic"
+msgid_plural "SearchResults|epics"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "SearchResults|issue"
msgid_plural "SearchResults|issues"
msgstr[0] ""
@@ -21842,10 +22643,10 @@ msgstr ""
msgid "Seat Link is disabled, and cannot be configured through this form."
msgstr ""
-msgid "Seats currently in use"
+msgid "Seats usage data as of %{last_enqueue_time}"
msgstr ""
-msgid "Seats in license"
+msgid "Seats usage data is updated every day at 12:00pm UTC"
msgstr ""
msgid "Secondary"
@@ -21899,6 +22700,9 @@ msgstr ""
msgid "SecurityConfiguration|Available for on-demand DAST"
msgstr ""
+msgid "SecurityConfiguration|By default, all analyzers are applied in order to cover all languages across your project, and only run if the language is detected in the Merge Request."
+msgstr ""
+
msgid "SecurityConfiguration|Configure"
msgstr ""
@@ -21929,16 +22733,19 @@ msgstr ""
msgid "SecurityConfiguration|Manage"
msgstr ""
+msgid "SecurityConfiguration|More information"
+msgstr ""
+
msgid "SecurityConfiguration|Not enabled"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|Security Control"
+msgid "SecurityConfiguration|SAST Configuration"
msgstr ""
-msgid "SecurityConfiguration|See documentation"
+msgid "SecurityConfiguration|Security Control"
msgstr ""
msgid "SecurityConfiguration|Status"
@@ -21950,6 +22757,9 @@ msgstr ""
msgid "SecurityConfiguration|Using custom settings. You won't receive automatic updates on this variable. %{anchorStart}Restore to default%{anchorEnd}"
msgstr ""
+msgid "SecurityConfiguration|View history"
+msgstr ""
+
msgid "SecurityConfiguration|You can quickly enable all security scanning tools by enabling %{linkStart}Auto DevOps%{linkEnd}."
msgstr ""
@@ -22028,9 +22838,6 @@ msgstr ""
msgid "SecurityReports|Learn more about setting up your dashboard"
msgstr ""
-msgid "SecurityReports|Load more vulnerabilities"
-msgstr ""
-
msgid "SecurityReports|Monitor vulnerabilities in your code"
msgstr ""
@@ -22310,7 +23117,7 @@ msgstr ""
msgid "Select status"
msgstr ""
-msgid "Select strategy activation method"
+msgid "Select strategy activation method."
msgstr ""
msgid "Select subscription"
@@ -22325,7 +23132,7 @@ msgstr ""
msgid "Select the custom project template source group."
msgstr ""
-msgid "Select timeframe"
+msgid "Select the environment scope for this feature flag."
msgstr ""
msgid "Select timezone"
@@ -22574,6 +23381,9 @@ msgstr ""
msgid "Set iteration"
msgstr ""
+msgid "Set limit to 0 to allow any file size."
+msgstr ""
+
msgid "Set max session time for web terminal."
msgstr ""
@@ -22652,10 +23462,13 @@ msgstr ""
msgid "Set up a %{type} Runner manually"
msgstr ""
+msgid "Set up a hardware device as a second factor to sign in."
+msgstr ""
+
msgid "Set up assertions/attributes/claims (email, first_name, last_name) and NameID according to %{docsLinkStart}the documentation %{icon}%{docsLinkEnd}"
msgstr ""
-msgid "Set up new U2F device"
+msgid "Set up new device"
msgstr ""
msgid "Set up new password"
@@ -22724,6 +23537,9 @@ msgstr ""
msgid "Sets weight to %{weight}."
msgstr ""
+msgid "Setting this to 0 means using the system default timeout value."
+msgstr ""
+
msgid "Settings"
msgstr ""
@@ -22739,6 +23555,15 @@ msgstr ""
msgid "Severity"
msgstr ""
+msgid "SeverityWidget|Severity"
+msgstr ""
+
+msgid "SeverityWidget|Severity: %{severity}"
+msgstr ""
+
+msgid "SeverityWidget|There was an error while updating severity."
+msgstr ""
+
msgid "Shards (%{shards})"
msgstr ""
@@ -22784,6 +23609,9 @@ msgstr ""
msgid "Show all requirements."
msgstr ""
+msgid "Show all test cases."
+msgstr ""
+
msgid "Show archived projects"
msgstr ""
@@ -22796,6 +23624,9 @@ msgstr ""
msgid "Show comments"
msgstr ""
+msgid "Show comments on this file"
+msgstr ""
+
msgid "Show comments only"
msgstr ""
@@ -22841,6 +23672,12 @@ msgstr ""
msgid "Show parent subgroups"
msgstr ""
+msgid "Show the Closed list"
+msgstr ""
+
+msgid "Show the Open list"
+msgstr ""
+
msgid "Show whitespace changes"
msgstr ""
@@ -22884,9 +23721,6 @@ msgstr ""
msgid "Sidebar|Assign health status"
msgstr ""
-msgid "Sidebar|Change weight"
-msgstr ""
-
msgid "Sidebar|Health status"
msgstr ""
@@ -23070,6 +23904,9 @@ msgstr ""
msgid "Snippets|Add another file %{num}/%{total}"
msgstr ""
+msgid "Snippets|Authored %{time_ago} by %{author}"
+msgstr ""
+
msgid "Snippets|Delete file"
msgstr ""
@@ -23097,6 +23934,9 @@ msgstr ""
msgid "Solution"
msgstr ""
+msgid "Some changes are not shown"
+msgstr ""
+
msgid "Some child epics may be hidden due to applied filters"
msgstr ""
@@ -23463,6 +24303,12 @@ msgstr ""
msgid "Source (branch or tag)"
msgstr ""
+msgid "Source Branch"
+msgstr ""
+
+msgid "Source branch: %{source_branch_open}%{source_branch}%{source_branch_close}"
+msgstr ""
+
msgid "Source code"
msgstr ""
@@ -23628,9 +24474,6 @@ msgstr ""
msgid "Start and due date"
msgstr ""
-msgid "Start by choosing a group to see how your team is spending time. You can then drill down to the project level."
-msgstr ""
-
msgid "Start by choosing a group to start exploring the merge requests in that group. You can then proceed to filter by projects, labels, milestones and authors."
msgstr ""
@@ -23712,18 +24555,27 @@ msgstr ""
msgid "StaticSiteEditor|3. Assign a person to review and accept the merge request."
msgstr ""
+msgid "StaticSiteEditor|A link to view the merge request will appear once ready."
+msgstr ""
+
msgid "StaticSiteEditor|An error occurred while submitting your changes."
msgstr ""
msgid "StaticSiteEditor|Branch could not be created."
msgstr ""
+msgid "StaticSiteEditor|Copy update"
+msgstr ""
+
msgid "StaticSiteEditor|Could not commit the content changes."
msgstr ""
msgid "StaticSiteEditor|Could not create merge request."
msgstr ""
+msgid "StaticSiteEditor|Creating your merge request"
+msgstr ""
+
msgid "StaticSiteEditor|Incompatible file content"
msgstr ""
@@ -23745,6 +24597,9 @@ msgstr ""
msgid "StaticSiteEditor|View documentation"
msgstr ""
+msgid "StaticSiteEditor|You can set an assignee to get your changes reviewed and deployed once your merge request is created."
+msgstr ""
+
msgid "StaticSiteEditor|Your merge request has been created"
msgstr ""
@@ -23874,15 +24729,15 @@ msgstr ""
msgid "Submit %{humanized_resource_name}"
msgstr ""
-msgid "Submit Changes"
-msgstr ""
-
msgid "Submit a review"
msgstr ""
msgid "Submit as spam"
msgstr ""
+msgid "Submit changes"
+msgstr ""
+
msgid "Submit feedback"
msgstr ""
@@ -24036,6 +24891,9 @@ msgstr ""
msgid "Successfully deleted U2F device."
msgstr ""
+msgid "Successfully deleted WebAuthn device."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -24354,9 +25212,6 @@ msgstr ""
msgid "Template to append to all Service Desk issues"
msgstr ""
-msgid "Template was successfully saved."
-msgstr ""
-
msgid "Templates"
msgstr ""
@@ -24435,10 +25290,28 @@ msgid_plural "Test coverage: %d hits"
msgstr[0] ""
msgstr[1] ""
-msgid "Test failed."
+msgid "Test settings"
+msgstr ""
+
+msgid "TestCases|New Test Case"
+msgstr ""
+
+msgid "TestCases|New test case"
+msgstr ""
+
+msgid "TestCases|Search test cases"
+msgstr ""
+
+msgid "TestCases|Something went wrong while creating a test case."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching count of test cases."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching test cases list."
msgstr ""
-msgid "Test settings and save changes"
+msgid "TestCases|Submit test case"
msgstr ""
msgid "TestHooks|Ensure one of your projects has merge requests."
@@ -24504,6 +25377,9 @@ msgstr ""
msgid "Thank you for signing up for your free trial! You will get additional instructions in your inbox shortly."
msgstr ""
+msgid "Thank you for your business."
+msgstr ""
+
msgid "Thank you for your feedback!"
msgstr ""
@@ -24563,9 +25439,6 @@ msgstr ""
msgid "The URL to use for connecting to Elasticsearch. Use a comma-separated list to support clustering (e.g., \"http://localhost:9200, http://localhost:9201\")."
msgstr ""
-msgid "The Web IDE offers advanced syntax highlighting capabilities and more."
-msgstr ""
-
msgid "The X509 Certificate to use when mutual TLS is required to communicate with the external authorization service. If left blank, the server certificate is still validated when accessing over HTTPS."
msgstr ""
@@ -24676,6 +25549,9 @@ msgstr ""
msgid "The form contains the following error:"
msgstr ""
+msgid "The form contains the following warning:"
+msgstr ""
+
msgid "The global settings require you to enable Two-Factor Authentication for your account."
msgstr ""
@@ -24790,9 +25666,6 @@ msgstr ""
msgid "The private key to use when a client certificate is provided. This value is encrypted at rest."
msgstr ""
-msgid "The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The project can be accessed by any logged in user."
msgstr ""
@@ -24829,7 +25702,7 @@ msgstr ""
msgid "The remote repository is being updated..."
msgstr ""
-msgid "The repository can be commited to, and issues, comments and other entities can be created."
+msgid "The repository can be committed to, and issues, comments and other entities can be created."
msgstr ""
msgid "The repository for this project does not exist."
@@ -24883,9 +25756,6 @@ msgstr ""
msgid "The time taken by each data entry gathered by that stage."
msgstr ""
-msgid "The total stage shows the time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The update action will time out after %{number_of_minutes} minutes. For big repositories, use a clone/push combination."
msgstr ""
@@ -24949,6 +25819,9 @@ msgstr ""
msgid "There are no archived requirements"
msgstr ""
+msgid "There are no archived test cases"
+msgstr ""
+
msgid "There are no changes"
msgstr ""
@@ -24988,6 +25861,9 @@ msgstr ""
msgid "There are no open requirements"
msgstr ""
+msgid "There are no open test cases"
+msgstr ""
+
msgid "There are no packages yet"
msgstr ""
@@ -25000,6 +25876,9 @@ msgstr ""
msgid "There is a limit of %{ci_project_subscriptions_limit} subscriptions from or to a project."
msgstr ""
+msgid "There is already a To-Do for this design."
+msgstr ""
+
msgid "There is already a repository with that name on disk"
msgstr ""
@@ -25018,6 +25897,9 @@ msgstr ""
msgid "There was a problem communicating with your device."
msgstr ""
+msgid "There was a problem fetching branches."
+msgstr ""
+
msgid "There was a problem fetching groups."
msgstr ""
@@ -25246,9 +26128,15 @@ msgstr ""
msgid "This action can lead to data loss. To prevent accidental actions we ask you to confirm your intention."
msgstr ""
+msgid "This action cannot be undone, and will permanently delete the %{key} SSH key"
+msgstr ""
+
msgid "This action cannot be undone. You will lose the project's repository and all content: issues, merge requests, etc."
msgstr ""
+msgid "This action has been performed too many times. Try again later."
+msgstr ""
+
msgid "This action will %{strongOpen}permanently delete%{strongClose} %{codeOpen}%{project}%{codeClose} %{strongOpen}immediately%{strongClose}, including its repositories and all content: issues, merge requests, etc."
msgstr ""
@@ -25276,9 +26164,6 @@ msgstr ""
msgid "This board's scope is reduced"
msgstr ""
-msgid "This branch has changed since you started editing. Would you like to create a new branch?"
-msgstr ""
-
msgid "This chart could not be displayed"
msgstr ""
@@ -25405,15 +26290,9 @@ msgstr ""
msgid "This is a security log of important events involving your account."
msgstr ""
-msgid "This is the author's first Merge Request to this project."
-msgstr ""
-
msgid "This is the highest peak of users on your installation since the license started."
msgstr ""
-msgid "This is the maximum number of users that have existed at the same time since the license started. This is the minimum number of seats you will need to buy when you renew your license."
-msgstr ""
-
msgid "This is the number of currently active users on your installation, and this is the minimum number you need to purchase when you renew your license."
msgstr ""
@@ -25645,6 +26524,15 @@ msgstr ""
msgid "This user has no identities"
msgstr ""
+msgid "This user has previously committed to the %{name} project."
+msgstr ""
+
+msgid "This user has the %{access} role in the %{name} project."
+msgstr ""
+
+msgid "This user is the author of this %{noteable}."
+msgstr ""
+
msgid "This user will be the author of all events in the activity feed that are the result of an update, like new branches being created or new commits being pushed to existing branches."
msgstr ""
@@ -25675,6 +26563,9 @@ msgstr ""
msgid "Threat Monitoring"
msgstr ""
+msgid "ThreatMonitoring|All Environments"
+msgstr ""
+
msgid "ThreatMonitoring|Anomalous Requests"
msgstr ""
@@ -25702,9 +26593,6 @@ msgstr ""
msgid "ThreatMonitoring|Operations Per Second"
msgstr ""
-msgid "ThreatMonitoring|Overview"
-msgstr ""
-
msgid "ThreatMonitoring|Packet Activity"
msgstr ""
@@ -25723,6 +26611,9 @@ msgstr ""
msgid "ThreatMonitoring|Something went wrong, unable to fetch statistics"
msgstr ""
+msgid "ThreatMonitoring|Statistics"
+msgstr ""
+
msgid "ThreatMonitoring|The firewall is not installed or has been disabled. To view this data, ensure the web application firewall is installed and enabled for your cluster."
msgstr ""
@@ -26114,6 +27005,9 @@ msgstr ""
msgid "To update Snippets with multiple files, you must use the `files` parameter"
msgstr ""
+msgid "To use Gitpod you must first enable the feature in the integrations section of your %{user_prefs}."
+msgstr ""
+
msgid "To view all %{scannedResourcesCount} scanned URLs, please download the CSV file"
msgstr ""
@@ -26147,9 +27041,6 @@ msgstr ""
msgid "Toggle Sidebar"
msgstr ""
-msgid "Toggle all threads"
-msgstr ""
-
msgid "Toggle backtrace"
msgstr ""
@@ -26174,9 +27065,6 @@ msgstr ""
msgid "Toggle navigation"
msgstr ""
-msgid "Toggle project"
-msgstr ""
-
msgid "Toggle sidebar"
msgstr ""
@@ -26216,6 +27104,9 @@ msgstr ""
msgid "Too many projects enabled. You will need to manage them via the console or the API."
msgstr ""
+msgid "Too much data"
+msgstr ""
+
msgid "Topics (optional)"
msgstr ""
@@ -26234,6 +27125,9 @@ msgstr ""
msgid "Total cores (CPUs)"
msgstr ""
+msgid "Total days to completion"
+msgstr ""
+
msgid "Total issues"
msgstr ""
@@ -26330,6 +27224,9 @@ msgstr ""
msgid "Trending"
msgstr ""
+msgid "Trials|Create a new group to start your GitLab Gold trial."
+msgstr ""
+
msgid "Trials|Go back to GitLab"
msgstr ""
@@ -26339,6 +27236,15 @@ msgstr ""
msgid "Trials|You can always resume this process by selecting your avatar and choosing 'Start a Gold trial'"
msgstr ""
+msgid "Trials|You can apply your trial to a new group or an existing group."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group or your personal account."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group, an existing group, or your personal account."
+msgstr ""
+
msgid "Trials|You won't get a free trial right now but you can always resume this process by clicking on your avatar and choosing 'Start a free trial'"
msgstr ""
@@ -26408,6 +27314,9 @@ msgstr ""
msgid "Try using a different search term to find the file you are looking for."
msgstr ""
+msgid "Trying to communicate with your device. Plug it in (if needed) and press the button on the device now."
+msgstr ""
+
msgid "Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now."
msgstr ""
@@ -26495,6 +27404,12 @@ msgstr ""
msgid "URL or request ID"
msgstr ""
+msgid "USER %{user} WILL BE REMOVED! Are you sure?"
+msgstr ""
+
+msgid "USER WILL BE BLOCKED! Are you sure?"
+msgstr ""
+
msgid "UTC"
msgstr ""
@@ -26552,9 +27467,6 @@ msgstr ""
msgid "Unable to load the merge request widget. Try reloading the page."
msgstr ""
-msgid "Unable to resolve"
-msgstr ""
-
msgid "Unable to save iteration. Please try again"
msgstr ""
@@ -26603,6 +27515,9 @@ msgstr ""
msgid "Undo ignore"
msgstr ""
+msgid "Unexpected error"
+msgstr ""
+
msgid "Unfortunately, your email message to GitLab could not be processed."
msgstr ""
@@ -26636,6 +27551,9 @@ msgstr ""
msgid "Unknown response text"
msgstr ""
+msgid "Unless otherwise agreed to in writing with GitLab, by clicking \"Upload License\" you agree that your use of GitLab Software is subject to the %{eula_link_start}Terms of Service%{eula_link_end}."
+msgstr ""
+
msgid "Unlimited"
msgstr ""
@@ -27002,9 +27920,6 @@ msgstr ""
msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
msgstr ""
-msgid "Use a hardware device to add the second factor of authentication."
-msgstr ""
-
msgid "Use an one time password authenticator on your mobile device or computer to enable two-factor authentication (2FA)."
msgstr ""
@@ -27278,13 +28193,13 @@ msgstr ""
msgid "Users"
msgstr ""
-msgid "Users in License:"
+msgid "Users in License"
msgstr ""
-msgid "Users or groups set as approvers in the project's or merge request's settings."
+msgid "Users in License:"
msgstr ""
-msgid "Users outside of license"
+msgid "Users or groups set as approvers in the project's or merge request's settings."
msgstr ""
msgid "Users over License:"
@@ -27302,9 +28217,6 @@ msgstr ""
msgid "Users with a Guest role or those who don't belong to a Project or Group will not use a seat from your license."
msgstr ""
-msgid "Users with a Guest role or those who don't belong to any projects or groups don't count towards seats in use."
-msgstr ""
-
msgid "UsersSelect|%{name} + %{length} more"
msgstr ""
@@ -27344,9 +28256,6 @@ msgstr ""
msgid "Validations failed."
msgstr ""
-msgid "Validity"
-msgstr ""
-
msgid "Value"
msgstr ""
@@ -27365,6 +28274,9 @@ msgstr ""
msgid "Value Stream Name"
msgstr ""
+msgid "ValueStreamAnalyticsStage|We don't have enough data to show this stage."
+msgstr ""
+
msgid "ValueStreamAnalytics|%{days}d"
msgstr ""
@@ -27621,6 +28533,9 @@ msgstr ""
msgid "VisualReviewApp|Steps 1 and 2 (and sometimes 3) are performed once by the developer before requesting feedback. Steps 3 (if necessary), 4 is performed by the reviewer each time they perform a review."
msgstr ""
+msgid "Visualization"
+msgstr ""
+
msgid "Vulnerabilities"
msgstr ""
@@ -27648,34 +28563,31 @@ msgstr ""
msgid "VulnerabilityChart|Severity"
msgstr ""
-msgid "VulnerabilityManagement|A true-positive and will fix"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Change status"
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|Confirm"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Confirmed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
-msgstr ""
-
-msgid "VulnerabilityManagement|Detected %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|A true-positive and will fix"
msgstr ""
-msgid "VulnerabilityManagement|Dismiss"
+msgid "VulnerabilityManagement|Change status"
msgstr ""
-msgid "VulnerabilityManagement|Dismissed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
msgstr ""
-msgid "VulnerabilityManagement|Resolved"
+msgid "VulnerabilityManagement|Detected"
msgstr ""
-msgid "VulnerabilityManagement|Resolved %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Needs triage"
msgstr ""
msgid "VulnerabilityManagement|Something went wrong while trying to delete the comment. Please try again later."
@@ -27726,6 +28638,9 @@ msgstr ""
msgid "Vulnerability|%{scannerName} (version %{scannerVersion})"
msgstr ""
+msgid "Vulnerability|Activity"
+msgstr ""
+
msgid "Vulnerability|Class"
msgstr ""
@@ -27738,6 +28653,9 @@ msgstr ""
msgid "Vulnerability|Description"
msgstr ""
+msgid "Vulnerability|Detected"
+msgstr ""
+
msgid "Vulnerability|Evidence"
msgstr ""
@@ -27801,6 +28719,9 @@ msgstr ""
msgid "Warning: Displaying this diagram might cause performance issues on this page."
msgstr ""
+msgid "We are currently unable to fetch data for the pipeline header."
+msgstr ""
+
msgid "We are currently unable to fetch data for this graph."
msgstr ""
@@ -27840,6 +28761,12 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
+msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
+msgstr ""
+
+msgid "We would like to inform you that your subscription GitLab Enterprise Edition %{plan_name} is nearing its user limit. You have %{active_user_count} active users, which is almost at the user limit of %{maximum_user_count}."
+msgstr ""
+
msgid "We've found no vulnerabilities"
msgstr ""
@@ -27855,6 +28782,12 @@ msgstr ""
msgid "Web terminal"
msgstr ""
+msgid "WebAuthn Devices (%{length})"
+msgstr ""
+
+msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
+msgstr ""
+
msgid "WebIDE|Merge request"
msgstr ""
@@ -27993,15 +28926,9 @@ msgstr ""
msgid "Welcome to the guided GitLab tour"
msgstr ""
-msgid "Welcome to your Issue Board!"
-msgstr ""
-
msgid "Welcome to your issue board!"
msgstr ""
-msgid "We’ve been making changes to %{featureName} and we’d love your feedback %{linkStart}in this issue%{linkEnd} to help us improve the experience."
-msgstr ""
-
msgid "What are you searching for?"
msgstr ""
@@ -28020,6 +28947,9 @@ msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
msgstr ""
+msgid "When enabled, any user visiting %{host} and creating an account will have to be explicitly approved by the admin before they can login. This setting is effective only if sign-ups are enabled."
+msgstr ""
+
msgid "When enabled, any user visiting %{host} will be able to create an account."
msgstr ""
@@ -28244,6 +29174,9 @@ msgstr ""
msgid "With requirements, you can set criteria to check your products against."
msgstr ""
+msgid "With test cases, you can define conditions for your project to meet in determining quality"
+msgstr ""
+
msgid "Withdraw Access Request"
msgstr ""
@@ -28259,6 +29192,9 @@ msgstr ""
msgid "Workflow Help"
msgstr ""
+msgid "Would you like to create a new branch?"
+msgstr ""
+
msgid "Write"
msgstr ""
@@ -28280,6 +29216,9 @@ msgstr ""
msgid "Wrong extern UID provided. Make sure Auth0 is configured correctly."
msgstr ""
+msgid "YYYY-MM-DD"
+msgstr ""
+
msgid "Yes"
msgstr ""
@@ -28337,7 +29276,7 @@ msgstr ""
msgid "You are going to remove the fork relationship from %{project_full_name}. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "You are going to transfer %{project_full_name} to another owner. Are you ABSOLUTELY sure?"
+msgid "You are going to transfer %{project_full_name} to another namespace. Are you ABSOLUTELY sure?"
msgstr ""
msgid "You are going to turn off the confidentiality. This means %{strongStart}everyone%{strongEnd} will be able to see and leave a comment on this %{issuableType}."
@@ -28397,9 +29336,6 @@ msgstr ""
msgid "You can always edit this later"
msgstr ""
-msgid "You can apply your Trial to your Personal account or create a New Group."
-msgstr ""
-
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings"
msgstr ""
@@ -28421,12 +29357,18 @@ msgstr ""
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
+msgid "You can find more information about GitLab subscriptions in %{subscriptions_doc_link}."
+msgstr ""
+
msgid "You can generate an access token scoped to this project for each application to use the GitLab API."
msgstr ""
msgid "You can get started by cloning the repository or start adding files to it with one of the following options."
msgstr ""
+msgid "You can group test cases using labels. To learn about the future direction of this feature, visit %{linkStart}Quality Management direction page%{linkEnd}."
+msgstr ""
+
msgid "You can invite a new member to %{project_name} or invite another group."
msgstr ""
@@ -28442,6 +29384,9 @@ msgstr ""
msgid "You can notify the app / group or a project by sending them an email notification"
msgstr ""
+msgid "You can now close this window."
+msgstr ""
+
msgid "You can now export your security dashboard to a CSV report."
msgstr ""
@@ -28490,9 +29435,6 @@ msgstr ""
msgid "You can test your .gitlab-ci.yml in %{linkStart}CI Lint%{linkEnd}."
msgstr ""
-msgid "You can try again using %{begin_link}basic search%{end_link}"
-msgstr ""
-
msgid "You cannot access the raw file. Please wait a minute."
msgstr ""
@@ -28544,6 +29486,9 @@ msgstr ""
msgid "You don't have any U2F devices registered yet."
msgstr ""
+msgid "You don't have any WebAuthn devices registered yet."
+msgstr ""
+
msgid "You don't have any active chat names."
msgstr ""
@@ -28631,6 +29576,9 @@ msgstr ""
msgid "You must accept our Terms of Service and privacy policy in order to register an account"
msgstr ""
+msgid "You must be logged in to search across all of GitLab"
+msgstr ""
+
msgid "You must disassociate %{domain} from all clusters it is attached to before deletion."
msgstr ""
@@ -28670,7 +29618,7 @@ msgstr ""
msgid "You need to be logged in."
msgstr ""
-msgid "You need to register a two-factor authentication app before you can set up a U2F device."
+msgid "You need to register a two-factor authentication app before you can set up a device."
msgstr ""
msgid "You need to set terms to be enforced"
@@ -28688,6 +29636,9 @@ msgstr ""
msgid "You reached %{usage_in_percent} of %{namespace_name}'s storage capacity (%{used_storage} of %{storage_limit})"
msgstr ""
+msgid "You successfully declined the invitation"
+msgstr ""
+
msgid "You tried to fork %{link_to_the_project} but it failed for the following reason:"
msgstr ""
@@ -28853,10 +29804,13 @@ msgstr ""
msgid "Your U2F device did not send a valid JSON response."
msgstr ""
-msgid "Your U2F device needs to be set up. Plug it in (if not already) and click the button on the left."
+msgid "Your U2F device was registered!"
+msgstr ""
+
+msgid "Your WebAuthn device did not send a valid JSON response."
msgstr ""
-msgid "Your U2F device was registered!"
+msgid "Your WebAuthn device was registered!"
msgstr ""
msgid "Your access request to the %{source_type} has been withdrawn."
@@ -28880,6 +29834,9 @@ msgstr ""
msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
msgstr ""
+msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
+msgstr ""
+
msgid "Your changes can be committed to %{branch_name} because a merge request is open."
msgstr ""
@@ -28916,6 +29873,12 @@ msgstr ""
msgid "Your deployment services will be broken, you will need to manually fix the services after renaming."
msgstr ""
+msgid "Your device is not compatible with GitLab. Please try another device"
+msgstr ""
+
+msgid "Your device needs to be set up. Plug it in (if needed) and click the button on the left."
+msgstr ""
+
msgid "Your device was successfully set up! Give it a name and register it with the GitLab server."
msgstr ""
@@ -29029,9 +29992,6 @@ msgstr[1] ""
msgid "access:"
msgstr ""
-msgid "activated"
-msgstr ""
-
msgid "added %{created_at_timeago}"
msgstr ""
@@ -29104,9 +30064,21 @@ msgstr ""
msgid "by %{user}"
msgstr ""
+msgid "cannot be a date in the past"
+msgstr ""
+
msgid "cannot be changed if a personal project has container registry tags."
msgstr ""
+msgid "cannot be changed if shared runners are enabled"
+msgstr ""
+
+msgid "cannot be enabled because parent group does not allow it"
+msgstr ""
+
+msgid "cannot be enabled because parent group has shared Runners disabled"
+msgstr ""
+
msgid "cannot be enabled unless all domains have TLS certificates"
msgstr ""
@@ -29152,7 +30124,7 @@ msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about SAST %{linkEndTag}"
msgstr ""
-msgid "ciReport|%{linkStartTag}Learn more about Secret Scanning %{linkEndTag}"
+msgid "ciReport|%{linkStartTag}Learn more about Secret Detection %{linkEndTag}"
msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about codequality reports %{linkEndTag}"
@@ -29467,9 +30439,6 @@ msgstr ""
msgid "error"
msgstr ""
-msgid "error code:"
-msgstr ""
-
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr ""
@@ -29491,6 +30460,9 @@ msgstr ""
msgid "failed to dismiss associated finding(id=%{finding_id}): %{message}"
msgstr ""
+msgid "failed to revert associated finding(id=%{finding_id}) to detected"
+msgstr ""
+
msgid "file"
msgid_plural "files"
msgstr[0] ""
@@ -30033,6 +31005,9 @@ msgstr ""
msgid "must be a root namespace"
msgstr ""
+msgid "must be a valid IPv4 or IPv6 address"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -30069,6 +31044,9 @@ msgstr ""
msgid "no expiration"
msgstr ""
+msgid "no name set"
+msgstr ""
+
msgid "no one can merge"
msgstr ""
@@ -30247,9 +31225,6 @@ msgstr ""
msgid "security Reports|There was an error creating the merge request"
msgstr ""
-msgid "settings saved, but not activated"
-msgstr ""
-
msgid "severity|Critical"
msgstr ""
@@ -30376,9 +31351,6 @@ msgstr ""
msgid "toggle collapse"
msgstr ""
-msgid "toggle dropdown"
-msgstr ""
-
msgid "triggered"
msgstr ""
@@ -30406,6 +31378,9 @@ msgstr ""
msgid "user avatar"
msgstr ""
+msgid "user preferences"
+msgstr ""
+
msgid "username"
msgstr ""
diff --git a/locale/he_IL/gitlab.po b/locale/he_IL/gitlab.po
index 42292a6f74b..aadad4d67cd 100644
--- a/locale/he_IL/gitlab.po
+++ b/locale/he_IL/gitlab.po
@@ -14,7 +14,10 @@ msgstr ""
"X-Crowdin-Language: he\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 6\n"
-"PO-Revision-Date: 2020-09-04 23:08\n"
+"PO-Revision-Date: 2020-10-02 18:47\n"
+
+msgid " %{project_name}#%{issue_iid} &middot; opened %{issue_created} by %{author}"
+msgstr ""
msgid " %{start} to %{end}"
msgstr ""
@@ -78,6 +81,20 @@ msgstr ""
msgid "\"el\" parameter is required for createInstance()"
msgstr ""
+msgid "%d Approval"
+msgid_plural "%d Approvals"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
+msgid "%d Package"
+msgid_plural "%d Packages"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%d Scanned URL"
msgid_plural "%d Scanned URLs"
msgstr[0] ""
@@ -165,6 +182,13 @@ msgstr[3] ""
msgid "%d commits"
msgstr ""
+msgid "%d completed issue"
+msgid_plural "%d completed issues"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%d contribution"
msgid_plural "%d contributions"
msgstr[0] ""
@@ -179,6 +203,13 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "%d day until tags are automatically removed"
+msgid_plural "%d days until tags are automatically removed"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%d error"
msgid_plural "%d errors"
msgstr[0] ""
@@ -305,6 +336,20 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "%d open issue"
+msgid_plural "%d open issues"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
+msgid "%d pending comment"
+msgid_plural "%d pending comments"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%d personal project will be removed and cannot be restored."
msgid_plural "%d personal projects will be removed and cannot be restored."
msgstr[0] ""
@@ -326,6 +371,13 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "%d project selected"
+msgid_plural "%d projects selected"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%d request with warnings"
msgid_plural "%d requests with warnings"
msgstr[0] ""
@@ -354,6 +406,13 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "%d tag per image name"
+msgid_plural "%d tags per image name"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%d unassigned issue"
msgid_plural "%d unassigned issues"
msgstr[0] ""
@@ -382,6 +441,13 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "%d warning found:"
+msgid_plural "%d warnings found:"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%s additional commit has been omitted to prevent performance issues."
msgid_plural "%s additional commits have been omitted to prevent performance issues."
msgstr[0] ""
@@ -422,6 +488,9 @@ msgstr ""
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr ""
+msgid "%{completedCount} completed weight"
+msgstr ""
+
msgid "%{completedWeight} of %{totalWeight} weight completed"
msgstr ""
@@ -476,16 +545,12 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "%{count} pending comment"
-msgid_plural "%{count} pending comments"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
+msgid "%{count} total weight"
+msgstr ""
+
msgid "%{dashboard_path} could not be found."
msgstr ""
@@ -540,6 +605,9 @@ msgstr ""
msgid "%{group_name} uses group managed accounts. You need to create a new GitLab account which will be managed by %{group_name}."
msgstr ""
+msgid "%{group_name}&%{epic_iid} &middot; opened %{epic_created} by %{author}"
+msgstr ""
+
msgid "%{host} sign-in from new location"
msgstr ""
@@ -552,7 +620,7 @@ msgstr ""
msgid "%{issuableType} will be removed! Are you sure?"
msgstr ""
-msgid "%{issuesSize} issues with a limit of %{maxIssueCount}"
+msgid "%{issuesCount} issues with a limit of %{maxIssueCount}"
msgstr ""
msgid "%{issuesSize} with a limit of %{maxIssueCount}"
@@ -585,7 +653,7 @@ msgstr ""
msgid "%{labelStart}Namespace:%{labelEnd} %{namespace}"
msgstr ""
-msgid "%{labelStart}Report Type:%{labelEnd} %{reportType}"
+msgid "%{labelStart}Scan Type:%{labelEnd} %{reportType}"
msgstr ""
msgid "%{labelStart}Scanner:%{labelEnd} %{scanner}"
@@ -796,9 +864,6 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "%{service_title} %{message}."
-msgstr ""
-
msgid "%{size} GiB"
msgstr ""
@@ -897,6 +962,12 @@ msgstr ""
msgid "%{timebox_name} should belong either to a project or a group."
msgstr ""
+msgid "%{timebox_type} does not support burnup charts"
+msgstr ""
+
+msgid "%{timebox_type} must have a start and due date"
+msgstr ""
+
msgid "%{title} %{operator} %{threshold}"
msgstr ""
@@ -921,7 +992,7 @@ msgstr ""
msgid "%{total} open issue weight"
msgstr ""
-msgid "%{total} open issues"
+msgid "%{total} warnings found: showing first %{warningsDisplayed}"
msgstr ""
msgid "%{usage_ping_link_start}Learn more%{usage_ping_link_end} about what information is shared with GitLab Inc."
@@ -954,9 +1025,6 @@ msgstr ""
msgid "&lt; 1 hour"
msgstr ""
-msgid "&lt;no name set&gt;"
-msgstr ""
-
msgid "&lt;no scopes selected&gt;"
msgstr ""
@@ -987,6 +1055,9 @@ msgstr ""
msgid "'%{name}' Value Stream created"
msgstr ""
+msgid "'%{name}' Value Stream deleted"
+msgstr ""
+
msgid "'%{name}' stage already exists"
msgstr ""
@@ -1048,6 +1119,9 @@ msgstr ""
msgid "+ %{numberOfHiddenAssignees} more"
msgstr ""
+msgid "+ %{numberOfHiddenReviewers} more"
+msgstr ""
+
msgid "+%d more"
msgid_plural "+%d more"
msgstr[0] ""
@@ -1120,6 +1194,13 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "1 Issue"
+msgid_plural "%d Issues"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "1 closed issue"
msgid_plural "%{issues} closed issues"
msgstr[0] ""
@@ -1141,6 +1222,13 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "1 deploy key"
+msgid_plural "%d deploy keys"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1261,6 +1349,9 @@ msgstr ""
msgid ":%{startLine} to %{endLine}"
msgstr ""
+msgid "A %{incident_docs_start}modified issue%{incident_docs_end} to guide the resolution of incidents."
+msgstr ""
+
msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr ""
@@ -1273,6 +1364,9 @@ msgstr ""
msgid "A GitBook site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
+msgid "A Gitpod configured Webapplication in Spring and Java"
+msgstr ""
+
msgid "A Hexo site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
@@ -1444,9 +1538,15 @@ msgstr ""
msgid "Access expiration date"
msgstr ""
+msgid "Access expires"
+msgstr ""
+
msgid "Access forbidden. Check your access level."
msgstr ""
+msgid "Access granted"
+msgstr ""
+
msgid "Access requests"
msgstr ""
@@ -1456,6 +1556,9 @@ msgstr ""
msgid "Access to Pages websites are controlled based on the user's membership to a given project. By checking this box, users will be required to be logged in to have access to all Pages websites in your instance."
msgstr ""
+msgid "AccessDropdown|Deploy Keys"
+msgstr ""
+
msgid "AccessDropdown|Groups"
msgstr ""
@@ -1573,12 +1676,6 @@ msgstr ""
msgid "Active Sessions"
msgstr ""
-msgid "Active Users:"
-msgstr ""
-
-msgid "Active users"
-msgstr ""
-
msgid "Activity"
msgstr ""
@@ -1748,9 +1845,6 @@ msgstr ""
msgid "Add label(s)"
msgstr ""
-msgid "Add license"
-msgstr "הוספת רישיון"
-
msgid "Add list"
msgstr ""
@@ -1925,21 +2019,51 @@ msgstr ""
msgid "AdminArea|Bots"
msgstr ""
+msgid "AdminArea|Components"
+msgstr ""
+
msgid "AdminArea|Developer"
msgstr ""
+msgid "AdminArea|Features"
+msgstr ""
+
+msgid "AdminArea|Groups: %{number_of_groups}"
+msgstr ""
+
msgid "AdminArea|Guest"
msgstr ""
msgid "AdminArea|Included Free in license"
msgstr ""
+msgid "AdminArea|Latest groups"
+msgstr ""
+
+msgid "AdminArea|Latest projects"
+msgstr ""
+
+msgid "AdminArea|Latest users"
+msgstr ""
+
msgid "AdminArea|Maintainer"
msgstr ""
+msgid "AdminArea|New group"
+msgstr ""
+
+msgid "AdminArea|New project"
+msgstr ""
+
+msgid "AdminArea|New user"
+msgstr ""
+
msgid "AdminArea|Owner"
msgstr ""
+msgid "AdminArea|Projects: %{number_of_projects}"
+msgstr ""
+
msgid "AdminArea|Reporter"
msgstr ""
@@ -1967,6 +2091,9 @@ msgstr ""
msgid "AdminArea|Users without a Group and Project"
msgstr ""
+msgid "AdminArea|Users: %{number_of_users}"
+msgstr ""
+
msgid "AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running."
msgstr ""
@@ -1985,9 +2112,6 @@ msgstr ""
msgid "AdminProjects|Delete Project %{projectName}?"
msgstr ""
-msgid "AdminProjects|Delete project"
-msgstr ""
-
msgid "AdminSettings|Apply integration settings to all Projects"
msgstr ""
@@ -2225,21 +2349,30 @@ msgstr ""
msgid "AdminUsers|Without projects"
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 ""
msgid "AdminUsers|You cannot remove your own admin rights."
msgstr ""
+msgid "AdminUsers|You must transfer ownership or delete the groups owned by this user before you can delete their account"
+msgstr ""
+
msgid "Administration"
msgstr ""
msgid "Advanced"
msgstr ""
+msgid "Advanced Search"
+msgstr ""
+
+msgid "Advanced Search with Elasticsearch"
+msgstr ""
+
msgid "Advanced Settings"
msgstr ""
@@ -2319,6 +2452,9 @@ msgstr ""
msgid "AlertManagement|Edit"
msgstr ""
+msgid "AlertManagement|Environment"
+msgstr ""
+
msgid "AlertManagement|Events"
msgstr ""
@@ -2331,6 +2467,9 @@ msgstr ""
msgid "AlertManagement|Issue"
msgstr ""
+msgid "AlertManagement|Key"
+msgstr ""
+
msgid "AlertManagement|Low"
msgstr ""
@@ -2424,6 +2563,9 @@ msgstr ""
msgid "AlertManagement|Unknown"
msgstr ""
+msgid "AlertManagement|Value"
+msgstr ""
+
msgid "AlertManagement|View alerts in Opsgenie"
msgstr ""
@@ -2583,6 +2725,9 @@ msgstr ""
msgid "All projects"
msgstr ""
+msgid "All projects selected"
+msgstr ""
+
msgid "All security scans are enabled because %{linkStart}Auto DevOps%{linkEnd} is enabled on this project"
msgstr ""
@@ -2670,6 +2815,9 @@ msgstr ""
msgid "Almost there"
msgstr ""
+msgid "Already blocked"
+msgstr ""
+
msgid "Also called \"Issuer\" or \"Relying party trust identifier\""
msgstr ""
@@ -2724,6 +2872,9 @@ msgstr ""
msgid "An error has occurred"
msgstr ""
+msgid "An error occured while making the changes: %{error}"
+msgstr ""
+
msgid "An error occurred adding a draft to the thread."
msgstr ""
@@ -2751,12 +2902,6 @@ msgstr ""
msgid "An error occurred when toggling the notification subscription"
msgstr ""
-msgid "An error occurred when trying to resolve a comment. Please try again."
-msgstr ""
-
-msgid "An error occurred when trying to resolve a discussion. Please try again."
-msgstr ""
-
msgid "An error occurred when updating the issue weight"
msgstr ""
@@ -2772,12 +2917,6 @@ msgstr ""
msgid "An error occurred while checking group path. Please refresh and try again."
msgstr ""
-msgid "An error occurred while committing your changes."
-msgstr ""
-
-msgid "An error occurred while creating the list. Please try again."
-msgstr ""
-
msgid "An error occurred while decoding the file."
msgstr ""
@@ -2850,25 +2989,19 @@ msgstr ""
msgid "An error occurred while fetching the Service Desk address."
msgstr ""
-msgid "An error occurred while fetching the board issues. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the board lists. Please reload the page."
msgstr ""
msgid "An error occurred while fetching the board lists. Please try again."
msgstr ""
-msgid "An error occurred while fetching the board swimlanes. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the builds."
msgstr ""
msgid "An error occurred while fetching the job log."
msgstr ""
-msgid "An error occurred while fetching the job trace."
+msgid "An error occurred while fetching the job logs."
msgstr ""
msgid "An error occurred while fetching the job."
@@ -3015,9 +3148,6 @@ msgstr ""
msgid "An error occurred while saving assignees"
msgstr ""
-msgid "An error occurred while saving the template. Please check if the template exists."
-msgstr ""
-
msgid "An error occurred while searching for milestones"
msgstr ""
@@ -3036,10 +3166,10 @@ msgstr ""
msgid "An error occurred while updating approvers"
msgstr ""
-msgid "An error occurred while updating the comment"
+msgid "An error occurred while updating labels."
msgstr ""
-msgid "An error occurred while updating the list. Please try again."
+msgid "An error occurred while updating the comment"
msgstr ""
msgid "An error occurred while validating group path"
@@ -3093,6 +3223,9 @@ msgstr ""
msgid "An unknown error occurred while loading this graph."
msgstr ""
+msgid "An unknown error occurred."
+msgstr ""
+
msgid "Analytics"
msgstr ""
@@ -3126,10 +3259,10 @@ msgstr ""
msgid "Any"
msgstr ""
-msgid "Any Author"
+msgid "Any %{header}"
msgstr ""
-msgid "Any Status"
+msgid "Any Author"
msgstr ""
msgid "Any branch"
@@ -3183,6 +3316,9 @@ msgstr ""
msgid "Application ID"
msgstr ""
+msgid "Application limits saved successfully"
+msgstr ""
+
msgid "Application settings saved successfully"
msgstr ""
@@ -3400,6 +3536,9 @@ msgstr ""
msgid "Are you sure you want to close this blocked issue?"
msgstr ""
+msgid "Are you sure you want to delete \"%{name}\" Value Stream?"
+msgstr ""
+
msgid "Are you sure you want to delete %{name}?"
msgstr ""
@@ -3409,6 +3548,9 @@ msgstr ""
msgid "Are you sure you want to delete this %{typeOfComment}?"
msgstr ""
+msgid "Are you sure you want to delete this SSH key?"
+msgstr ""
+
msgid "Are you sure you want to delete this board?"
msgstr ""
@@ -3433,6 +3575,13 @@ msgstr ""
msgid "Are you sure you want to erase this build?"
msgstr ""
+msgid "Are you sure you want to import %d repository?"
+msgid_plural "Are you sure you want to import %d repositories?"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "Are you sure you want to lose unsaved changes?"
msgstr ""
@@ -3442,15 +3591,15 @@ msgstr ""
msgid "Are you sure you want to merge immediately?"
msgstr ""
-msgid "Are you sure you want to permanently delete this license?"
-msgstr ""
-
msgid "Are you sure you want to re-deploy this environment?"
msgstr ""
msgid "Are you sure you want to regenerate the public key? You will have to update the public key on the remote server before mirroring will work again."
msgstr ""
+msgid "Are you sure you want to reindex?"
+msgstr ""
+
msgid "Are you sure you want to remove %{group_name}?"
msgstr ""
@@ -3478,6 +3627,9 @@ msgstr ""
msgid "Are you sure you want to revoke this nickname?"
msgstr ""
+msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
+msgstr ""
+
msgid "Are you sure you want to stop this environment?"
msgstr ""
@@ -3499,6 +3651,9 @@ msgstr ""
msgid "Are you sure? The device will be signed out of GitLab and all remember me tokens revoked."
msgstr ""
+msgid "Are you sure? This will invalidate your registered applications and U2F / WebAuthn devices."
+msgstr ""
+
msgid "Are you sure? This will invalidate your registered applications and U2F devices."
msgstr ""
@@ -3517,9 +3672,6 @@ msgstr ""
msgid "Artifacts"
msgstr ""
-msgid "As U2F devices are only supported by a few browsers, we require that you set up a two-factor authentication app before a U2F device. That way you'll always be able to log in - even when you're using an unsupported browser."
-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 ""
@@ -3717,6 +3869,9 @@ msgstr ""
msgid "AuditLogs|Target"
msgstr ""
+msgid "AuditLogs|This month"
+msgstr ""
+
msgid "AuditLogs|User Events"
msgstr ""
@@ -3756,6 +3911,9 @@ msgstr ""
msgid "Authentication via U2F device failed."
msgstr ""
+msgid "Authentication via WebAuthn device failed."
+msgstr ""
+
msgid "Author"
msgstr ""
@@ -4023,15 +4181,6 @@ msgstr ""
msgid "BambooService|You must set up automatic revision labeling and a repository trigger in Bamboo."
msgstr ""
-msgid "BatchComments|Delete all pending comments"
-msgstr ""
-
-msgid "BatchComments|Discard review?"
-msgstr ""
-
-msgid "BatchComments|You're about to discard your review which will delete all of your pending comments. The deleted comments %{strong_start}cannot%{strong_end} be restored."
-msgstr ""
-
msgid "Be careful. Changing the project's namespace can have unintended side effects."
msgstr ""
@@ -4053,6 +4202,9 @@ msgstr ""
msgid "Bi-weekly code coverage"
msgstr ""
+msgid "Billable Users:"
+msgstr ""
+
msgid "Billing"
msgstr ""
@@ -4062,7 +4214,7 @@ msgstr ""
msgid "BillingPlans|@%{user_name} you are currently using the %{plan_name} plan."
msgstr ""
-msgid "BillingPlans|Congratulations, your new trial is activated"
+msgid "BillingPlans|Congratulations, your free trial is activated."
msgstr ""
msgid "BillingPlans|If you would like to downgrade your plan please contact %{support_link_start}Customer Support%{support_link_end}."
@@ -4125,6 +4277,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Block user"
+msgstr ""
+
msgid "Blocked"
msgstr ""
@@ -4140,31 +4295,37 @@ msgstr ""
msgid "Blog"
msgstr ""
-msgid "Board name"
-msgstr ""
-
msgid "Board scope"
msgstr ""
msgid "Board scope affects which issues are displayed for anyone who visits this board"
msgstr ""
-msgid "BoardBlankState|Add default lists"
+msgid "Boards"
msgstr ""
-msgid "BoardBlankState|Add the following default lists to your Issue Board with one click:"
+msgid "Boards and Board Lists"
msgstr ""
-msgid "BoardBlankState|Nevermind, I'll use my own"
+msgid "Boards|An error occurred while creating the issue. Please try again."
msgstr ""
-msgid "BoardBlankState|Starting out with the default set of lists will get you right on the way to making the most of your board."
+msgid "Boards|An error occurred while creating the list. Please try again."
msgstr ""
-msgid "Boards"
+msgid "Boards|An error occurred while fetching issues. Please reload the page."
msgstr ""
-msgid "Boards and Board Lists"
+msgid "Boards|An error occurred while fetching the board issues. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching the board swimlanes. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while moving the issue. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while updating the list. Please try again."
msgstr ""
msgid "Boards|Collapse"
@@ -4191,7 +4352,7 @@ msgstr ""
msgid "Branch %{branch_name} was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr ""
-msgid "Branch has changed"
+msgid "Branch changed"
msgstr ""
msgid "Branch is already taken"
@@ -4497,6 +4658,9 @@ msgstr ""
msgid "CLOSED (MOVED)"
msgstr ""
+msgid "CODEOWNERS rule violation"
+msgstr ""
+
msgid "CONTRIBUTING"
msgstr ""
@@ -4527,9 +4691,6 @@ msgstr ""
msgid "Can't create snippet: %{err}"
msgstr ""
-msgid "Can't edit as source branch was deleted"
-msgstr ""
-
msgid "Can't fetch content for the blob: %{err}"
msgstr ""
@@ -4542,9 +4703,6 @@ msgstr ""
msgid "Can't load mermaid module: %{err}"
msgstr ""
-msgid "Can't remove group members without group managed account"
-msgstr ""
-
msgid "Can't scan the code?"
msgstr ""
@@ -4587,6 +4745,9 @@ msgstr ""
msgid "Cannot create the abuse report. This user has been blocked."
msgstr ""
+msgid "Cannot enable shared runners because parent group does not allow it"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -4692,6 +4853,15 @@ msgstr ""
msgid "Change your password or recover your current one"
msgstr ""
+msgid "ChangeReviewer|Reviewer changed from %{old} to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Reviewer changed to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Unassigned"
+msgstr ""
+
msgid "ChangeTypeActionLabel|Pick into branch"
msgstr ""
@@ -4731,6 +4901,9 @@ msgstr ""
msgid "Changes the title to \"%{title_param}\"."
msgstr ""
+msgid "Changes were successfully made."
+msgstr ""
+
msgid "Changes won't take place until the index is %{link_start}recreated%{link_end}."
msgstr ""
@@ -5136,6 +5309,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove variable"
+msgstr ""
+
msgid "CiVariables|Remove variable row"
msgstr ""
@@ -5214,9 +5390,6 @@ msgstr ""
msgid "Clear due date"
msgstr ""
-msgid "Clear input"
-msgstr ""
-
msgid "Clear recent searches"
msgstr ""
@@ -5265,6 +5438,9 @@ msgstr ""
msgid "Client authentication key password"
msgstr ""
+msgid "Client request timeout"
+msgstr ""
+
msgid "Clients"
msgstr ""
@@ -5349,6 +5525,27 @@ msgstr ""
msgid "Cluster type must be specificed for Stages::ClusterEndpointInserter"
msgstr ""
+msgid "ClusterAgents|Configuration"
+msgstr ""
+
+msgid "ClusterAgents|Connect your cluster with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate Kubernetes with a GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Name"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Agent also requires %{linkStart}enabling the Agent Server%{linkEnd}"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Kubernetes Agent allows an Infrastructure as Code, GitOps approach to integrating Kubernetes clusters with GitLab. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "ClusterAgent|This feature is only available for premium plans"
msgstr ""
@@ -5418,10 +5615,10 @@ msgstr ""
msgid "ClusterIntegration|All installed applications and related resources"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster."
+msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{linkStart}More information%{linkEnd}"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{startLink}More information%{endLink}"
+msgid "ClusterIntegration|Allow GitLab to manage namespaces and service accounts for this cluster."
msgstr ""
msgid "ClusterIntegration|Alternatively, "
@@ -5442,6 +5639,9 @@ msgstr ""
msgid "ClusterIntegration|An error occurred while trying to fetch zone machine types: %{error}"
msgstr ""
+msgid "ClusterIntegration|An unknown error occurred while attempting to connect to Kubernetes."
+msgstr ""
+
msgid "ClusterIntegration|Any project namespaces"
msgstr ""
@@ -5457,6 +5657,9 @@ msgstr ""
msgid "ClusterIntegration|Authenticate with Amazon Web Services"
msgstr ""
+msgid "ClusterIntegration|Authentication Error"
+msgstr ""
+
msgid "ClusterIntegration|Base domain"
msgstr ""
@@ -5475,13 +5678,22 @@ msgstr ""
msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}security group %{externalLinkIcon} %{endLink} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
+msgid "ClusterIntegration|Check your CA certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Check your cluster status"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}subnets %{externalLinkIcon} %{endLink} in your VPC where your worker nodes will run."
+msgid "ClusterIntegration|Check your token"
msgstr ""
-msgid "ClusterIntegration|Choose the worker node %{startLink}instance type %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Choose the %{linkStart}security group %{linkEnd} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
+msgstr ""
+
+msgid "ClusterIntegration|Choose the %{linkStart}subnets %{linkEnd} in your VPC where your worker nodes will run."
+msgstr ""
+
+msgid "ClusterIntegration|Choose the worker node %{linkStart}instance type%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Choose which applications to install on your Kubernetes cluster."
@@ -5493,10 +5705,7 @@ msgstr ""
msgid "ClusterIntegration|Clear cluster cache"
msgstr ""
-msgid "ClusterIntegration|Clear the local cache of namespace and service accounts. This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
-msgstr ""
-
-msgid "ClusterIntegration|Cluster being created"
+msgid "ClusterIntegration|Clear the local cache of namespace and service accounts."
msgstr ""
msgid "ClusterIntegration|Cluster management project (alpha)"
@@ -5508,15 +5717,21 @@ msgstr ""
msgid "ClusterIntegration|Cluster_applications artifact too big. Maximum allowable size: %{human_size}"
msgstr ""
-msgid "ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters."
+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|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}"
+msgid "ClusterIntegration|Clusters connected with a certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Connect cluster with certificate"
msgstr ""
msgid "ClusterIntegration|Connect existing cluster"
msgstr ""
+msgid "ClusterIntegration|Connection Error"
+msgstr ""
+
msgid "ClusterIntegration|Copy API URL"
msgstr ""
@@ -5592,6 +5807,12 @@ msgstr ""
msgid "ClusterIntegration|Deletes all GitLab resources attached to this cluster during removal"
msgstr ""
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared."
+msgstr ""
+
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared. %{linkStart}More information%{linkEnd}"
+msgstr ""
+
msgid "ClusterIntegration|Did you know?"
msgstr ""
@@ -5661,6 +5882,9 @@ msgstr ""
msgid "ClusterIntegration|Fluentd is an open source data collector, which lets you unify the data collection and consumption for a better use and understanding of data. It requires at least one of the following logs to be successfully installed."
msgstr ""
+msgid "ClusterIntegration|GitLab Agent managed clusters"
+msgstr ""
+
msgid "ClusterIntegration|GitLab Container Network Policies"
msgstr ""
@@ -5673,6 +5897,12 @@ msgstr ""
msgid "ClusterIntegration|GitLab Runner connects to the repository and executes CI/CD jobs, pushing results back and deploying applications to production."
msgstr ""
+msgid "ClusterIntegration|GitLab failed to authenticate."
+msgstr ""
+
+msgid "ClusterIntegration|GitLab failed to connect to the cluster."
+msgstr ""
+
msgid "ClusterIntegration|GitLab-managed cluster"
msgstr ""
@@ -5694,6 +5924,9 @@ msgstr ""
msgid "ClusterIntegration|Group cluster"
msgstr ""
+msgid "ClusterIntegration|HTTP Error"
+msgstr ""
+
msgid "ClusterIntegration|Helm Tiller"
msgstr ""
@@ -5727,7 +5960,10 @@ msgstr ""
msgid "ClusterIntegration|Instance type"
msgstr ""
-msgid "ClusterIntegration|Integrate Kubernetes cluster automation"
+msgid "ClusterIntegration|Integrate Kubernetes with a cluster certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Integrate with a cluster certificate"
msgstr ""
msgid "ClusterIntegration|Issuer Email"
@@ -5763,9 +5999,6 @@ msgstr ""
msgid "ClusterIntegration|Knative extends Kubernetes to provide a set of middleware components that are essential to build modern, source-centric, and container-based applications that can run anywhere: on premises, in the cloud, or even in a third-party data center."
msgstr ""
-msgid "ClusterIntegration|Kubernetes cluster"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes cluster is being created..."
msgstr ""
@@ -5778,9 +6011,6 @@ msgstr ""
msgid "ClusterIntegration|Kubernetes clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr ""
-msgid "ClusterIntegration|Kubernetes clusters can be used to deploy applications and to provide Review Apps for this project"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes version"
msgstr ""
@@ -5793,7 +6023,7 @@ msgstr ""
msgid "ClusterIntegration|Learn more about %{help_link_start}zones%{help_link_end}."
msgstr ""
-msgid "ClusterIntegration|Learn more about %{startLink}Regions %{externalLinkIcon}%{endLink}."
+msgid "ClusterIntegration|Learn more about %{linkStart}Regions%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Learn more about Kubernetes"
@@ -5838,12 +6068,18 @@ msgstr ""
msgid "ClusterIntegration|Machine type"
msgstr ""
+msgid "ClusterIntegration|Make sure your API endpoint is correct"
+msgstr ""
+
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create Kubernetes clusters"
msgstr ""
msgid "ClusterIntegration|Manage your Kubernetes cluster by visiting %{provider_link}"
msgstr ""
+msgid "ClusterIntegration|Namespace per environment"
+msgstr ""
+
msgid "ClusterIntegration|No IAM Roles found"
msgstr ""
@@ -5889,6 +6125,9 @@ msgstr ""
msgid "ClusterIntegration|No zones matched your search"
msgstr ""
+msgid "ClusterIntegration|Node calculations use the Kubernetes Metrics API. Make sure your cluster has metrics installed"
+msgstr ""
+
msgid "ClusterIntegration|Number of nodes"
msgstr ""
@@ -5931,6 +6170,9 @@ msgstr ""
msgid "ClusterIntegration|RBAC-enabled cluster"
msgstr ""
+msgid "ClusterIntegration|Read our %{linkStart}help page%{linkEnd} on Kubernetes cluster integration."
+msgstr ""
+
msgid "ClusterIntegration|Read our %{link_start}help page%{link_end} on Kubernetes cluster integration."
msgstr ""
@@ -6033,7 +6275,7 @@ msgstr ""
msgid "ClusterIntegration|Select a VPC to choose a subnet"
msgstr ""
-msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{linkStart}Amazon Web Services %{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select a network to choose a subnetwork"
@@ -6066,7 +6308,7 @@ msgstr ""
msgid "ClusterIntegration|Select project to choose zone"
msgstr ""
-msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select zone"
@@ -6156,9 +6398,18 @@ msgstr ""
msgid "ClusterIntegration|There was a problem authenticating with your cluster. Please ensure your CA Certificate and Token are valid."
msgstr ""
+msgid "ClusterIntegration|There was an HTTP error when connecting to your cluster."
+msgstr ""
+
msgid "ClusterIntegration|This account must have permissions to create a Kubernetes cluster in the %{link_to_container_project} specified below"
msgstr ""
+msgid "ClusterIntegration|This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
+msgstr ""
+
+msgid "ClusterIntegration|This is necessary to clear existing environment-namespace associations from clusters previously managed by GitLab."
+msgstr ""
+
msgid "ClusterIntegration|This option will allow you to install applications on RBAC clusters."
msgstr ""
@@ -6183,9 +6434,21 @@ msgstr ""
msgid "ClusterIntegration|To use a new project, first create one on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}."
msgstr ""
+msgid "ClusterIntegration|Troubleshooting tips:"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Authenticate"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Connect"
+msgstr ""
+
msgid "ClusterIntegration|Uninstall %{appTitle}"
msgstr ""
+msgid "ClusterIntegration|Unknown Error"
+msgstr ""
+
msgid "ClusterIntegration|Update %{appTitle}"
msgstr ""
@@ -6246,7 +6509,7 @@ msgstr ""
msgid "ClusterIntegration|Your cluster API is unreachable. Please ensure your API URL is correct."
msgstr ""
-msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Zone"
@@ -6366,6 +6629,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse all threads"
+msgstr ""
+
msgid "Collapse approvers"
msgstr ""
@@ -6517,7 +6783,7 @@ msgstr ""
msgid "Commit…"
msgstr ""
-msgid "Company"
+msgid "Community forum"
msgstr ""
msgid "Company name"
@@ -6526,6 +6792,9 @@ msgstr ""
msgid "Compare"
msgstr ""
+msgid "Compare %{oldCommitId}...%{newCommitId}"
+msgstr ""
+
msgid "Compare Git revisions"
msgstr ""
@@ -6541,6 +6810,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare submodule commit revisions"
+msgstr ""
+
msgid "Compare with previous version"
msgstr ""
@@ -6676,6 +6948,9 @@ msgstr ""
msgid "Configure the way a user creates a new account."
msgstr ""
+msgid "Configure which lists are shown for anyone who visits this board"
+msgstr ""
+
msgid "Confirm"
msgstr ""
@@ -6907,6 +7182,9 @@ msgstr[3] ""
msgid "ContainerRegistry|Set cleanup policy"
msgstr ""
+msgid "ContainerRegistry|Some tags were not deleted"
+msgstr ""
+
msgid "ContainerRegistry|Something went wrong while fetching the cleanup policy."
msgstr ""
@@ -6946,6 +7224,9 @@ msgstr ""
msgid "ContainerRegistry|Tags with names matching this regex pattern will %{italicStart}expire:%{italicEnd}"
msgstr ""
+msgid "ContainerRegistry|The cleanup policy timed out before it could delete all tags. An administrator can %{adminLinkStart}manually run cleanup now%{adminLinkEnd} or you can wait for the cleanup policy to automatically run again. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "ContainerRegistry|The last tag related to this image was recently removed. This empty image and any associated data will be automatically removed as part of the regular Garbage Collection process. If you have any questions, contact your administrator."
msgstr ""
@@ -7078,6 +7359,9 @@ msgstr ""
msgid "Contributions per group member"
msgstr ""
+msgid "Contributor"
+msgstr ""
+
msgid "Contributors"
msgstr ""
@@ -7207,6 +7491,9 @@ msgstr ""
msgid "Could not change HEAD: branch '%{branch}' does not exist"
msgstr ""
+msgid "Could not commit. An unexpected error occurred."
+msgstr ""
+
msgid "Could not connect to FogBugz, check your URL"
msgstr ""
@@ -7246,6 +7533,9 @@ msgstr ""
msgid "Could not find iteration"
msgstr ""
+msgid "Could not load instance counts. Please refresh the page to try again."
+msgstr ""
+
msgid "Could not remove the trigger."
msgstr ""
@@ -7270,10 +7560,10 @@ msgstr ""
msgid "Could not save prometheus manual configuration"
msgstr ""
-msgid "Could not udpdate wiki page"
+msgid "Could not update the LDAP settings"
msgstr ""
-msgid "Could not update the LDAP settings"
+msgid "Could not update wiki page"
msgstr ""
msgid "Could not upload your designs as one or more files uploaded are not supported."
@@ -7935,6 +8225,9 @@ msgstr ""
msgid "DastProfiles|Are you sure you want to delete this profile?"
msgstr ""
+msgid "DastProfiles|Could not create site validation token. Please refresh the page, or try again later."
+msgstr ""
+
msgid "DastProfiles|Could not create the scanner profile. Please try again."
msgstr ""
@@ -7959,6 +8252,12 @@ msgstr ""
msgid "DastProfiles|Could not fetch site profiles. Please refresh the page, or try again later."
msgstr ""
+msgid "DastProfiles|Could not retrieve site validation status. Please refresh the page, or try again later."
+msgstr ""
+
+msgid "DastProfiles|Could not update the scanner profile. Please try again."
+msgstr ""
+
msgid "DastProfiles|Could not update the site profile. Please try again."
msgstr ""
@@ -7974,7 +8273,7 @@ msgstr ""
msgid "DastProfiles|Download validation text file"
msgstr ""
-msgid "DastProfiles|Edit feature will come soon. Please create a new profile if changes needed"
+msgid "DastProfiles|Edit scanner profile"
msgstr ""
msgid "DastProfiles|Edit site profile"
@@ -8007,6 +8306,9 @@ msgstr ""
msgid "DastProfiles|No profiles created yet"
msgstr ""
+msgid "DastProfiles|Passive"
+msgstr ""
+
msgid "DastProfiles|Please enter a valid URL format, ex: http://www.example.com/home"
msgstr ""
@@ -8022,6 +8324,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan mode"
+msgstr ""
+
msgid "DastProfiles|Scanner Profile"
msgstr ""
@@ -8061,10 +8366,10 @@ msgstr ""
msgid "DastProfiles|Text file validation"
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
+msgid "DastProfiles|The maximum number of minutes allowed for the spider to traverse the site."
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the spider to traverse the site."
+msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
msgstr ""
msgid "DastProfiles|Validate"
@@ -8097,6 +8402,9 @@ msgstr ""
msgid "Date picker"
msgstr ""
+msgid "Date range"
+msgstr ""
+
msgid "Date range cannot exceed %{maxDateRange} days."
msgstr ""
@@ -8121,6 +8429,9 @@ msgstr ""
msgid "Days to merge"
msgstr ""
+msgid "Dear Administrator,"
+msgstr ""
+
msgid "Debug"
msgstr ""
@@ -8232,12 +8543,18 @@ msgstr ""
msgid "Delete"
msgstr ""
+msgid "Delete %{name}"
+msgstr ""
+
msgid "Delete Comment"
msgstr ""
msgid "Delete Snippet"
msgstr ""
+msgid "Delete Value Stream"
+msgstr ""
+
msgid "Delete account"
msgstr ""
@@ -8259,9 +8576,6 @@ msgstr ""
msgid "Delete label: %{label_name} ?"
msgstr ""
-msgid "Delete license"
-msgstr ""
-
msgid "Delete list"
msgstr ""
@@ -8337,15 +8651,6 @@ msgstr ""
msgid "Deleting a project places it into a read-only state until %{date}, at which point the project will be permanently deleted. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "Deleting the license failed."
-msgstr ""
-
-msgid "Deleting the license failed. The license was not found."
-msgstr ""
-
-msgid "Deleting the license failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "Deleting the project will delete its repository and all related resources including issues, merge requests etc."
msgstr ""
@@ -8853,7 +9158,10 @@ msgstr ""
msgid "DesignManagement|The maximum number of designs allowed to be uploaded is %{upload_limit}. Please try again."
msgstr ""
-msgid "DesignManagement|To upload designs, you'll need to enable LFS. %{requirements_link_start}More information%{requirements_link_end}"
+msgid "DesignManagement|There was an error moving your designs. Please upload your designs below."
+msgstr ""
+
+msgid "DesignManagement|To upload designs, you'll need to enable LFS and have admin enable hashed storage. %{requirements_link_start}More information%{requirements_link_end}"
msgstr ""
msgid "DesignManagement|Unresolve thread"
@@ -8865,6 +9173,9 @@ msgstr ""
msgid "DesignManagement|Upload skipped."
msgstr ""
+msgid "DesignManagement|Your designs are being copied and are on their way… Please refresh to update."
+msgstr ""
+
msgid "DesignManagement|and %{moreCount} more."
msgstr ""
@@ -8922,6 +9233,9 @@ msgstr ""
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
+msgid "Direct member"
+msgstr ""
+
msgid "Direction"
msgstr ""
@@ -8970,9 +9284,6 @@ msgstr ""
msgid "Discard draft"
msgstr ""
-msgid "Discard review"
-msgstr ""
-
msgid "DiscordService|Discord Notifications"
msgstr ""
@@ -9043,10 +9354,10 @@ msgstr ""
msgid "Dismiss Merge Request promotion"
msgstr ""
-msgid "Dismiss Selected"
+msgid "Dismiss Value Stream Analytics introduction box"
msgstr ""
-msgid "Dismiss Value Stream Analytics introduction box"
+msgid "Dismiss selected"
msgstr ""
msgid "Dismiss trial promotion"
@@ -9097,9 +9408,6 @@ msgstr ""
msgid "Documents reindexed: %{processed_documents} (%{percentage}%%)"
msgstr ""
-msgid "Doing"
-msgstr ""
-
msgid "Domain"
msgstr ""
@@ -9295,9 +9603,6 @@ msgstr ""
msgid "Edit environment"
msgstr ""
-msgid "Edit file"
-msgstr ""
-
msgid "Edit files in the editor and commit changes here"
msgstr ""
@@ -9310,6 +9615,12 @@ msgstr ""
msgid "Edit identity for %{user_name}"
msgstr ""
+msgid "Edit in Web IDE"
+msgstr ""
+
+msgid "Edit in single-file editor"
+msgstr ""
+
msgid "Edit issues"
msgstr ""
@@ -9337,10 +9648,10 @@ msgstr ""
msgid "Editing"
msgstr ""
-msgid "Elasticsearch"
+msgid "Elasticsearch AWS IAM credentials"
msgstr ""
-msgid "Elasticsearch AWS IAM credentials"
+msgid "Elasticsearch HTTP client timeout value in seconds."
msgstr ""
msgid "Elasticsearch indexing restrictions"
@@ -9349,9 +9660,6 @@ msgstr ""
msgid "Elasticsearch indexing started"
msgstr ""
-msgid "Elasticsearch integration. Elasticsearch AWS IAM."
-msgstr ""
-
msgid "Elasticsearch reindexing is already in progress"
msgstr ""
@@ -9379,9 +9687,6 @@ msgstr ""
msgid "Email Notification"
msgstr ""
-msgid "Email address"
-msgstr ""
-
msgid "Email could not be sent"
msgstr ""
@@ -9445,6 +9750,9 @@ msgstr ""
msgid "Emails sent from Service Desk will have this name"
msgstr ""
+msgid "Emails sent to %{email} will still be supported"
+msgstr ""
+
msgid "Emails separated by comma"
msgstr ""
@@ -9478,9 +9786,18 @@ msgstr ""
msgid "Enable"
msgstr ""
+msgid "Enable %{link_start}Gitpod%{link_end} integration to launch a development environment in your browser directly from GitLab."
+msgstr ""
+
msgid "Enable Auto DevOps"
msgstr ""
+msgid "Enable Gitpod"
+msgstr ""
+
+msgid "Enable Gitpod?"
+msgstr ""
+
msgid "Enable HTML emails"
msgstr ""
@@ -9610,9 +9927,6 @@ msgstr ""
msgid "Encountered an error while rendering: %{err}"
msgstr ""
-msgid "End date"
-msgstr ""
-
msgid "Ends at (UTC)"
msgstr ""
@@ -9772,7 +10086,7 @@ msgstr ""
msgid "EnvironmentsDashboard|The environments dashboard provides a summary of each project's environments' status, including pipeline and alert statuses."
msgstr ""
-msgid "EnvironmentsDashboard|This dashboard displays a maximum of 7 projects and 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
+msgid "EnvironmentsDashboard|This dashboard displays 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
msgstr ""
msgid "Environments|An error occurred while canceling the auto stop, please try again"
@@ -10093,6 +10407,9 @@ msgstr ""
msgid "Error deleting project. Check logs for error details."
msgstr ""
+msgid "Error fetching burnup chart data"
+msgstr ""
+
msgid "Error fetching diverging counts for branches. Please try again."
msgstr ""
@@ -10171,6 +10488,9 @@ msgstr ""
msgid "Error occurred when saving assignees"
msgstr ""
+msgid "Error occurred when saving reviewers"
+msgstr ""
+
msgid "Error occurred when toggling the notification subscription"
msgstr ""
@@ -10423,10 +10743,13 @@ msgstr ""
msgid "Expand all"
msgstr ""
-msgid "Expand approvers"
+msgid "Expand all files"
+msgstr ""
+
+msgid "Expand all threads"
msgstr ""
-msgid "Expand dropdown"
+msgid "Expand approvers"
msgstr ""
msgid "Expand milestones"
@@ -10597,6 +10920,9 @@ msgstr ""
msgid "Failed to create Merge Request. Please try again."
msgstr ""
+msgid "Failed to create To-Do for the design."
+msgstr ""
+
msgid "Failed to create a branch for this issue. Please try again."
msgstr ""
@@ -10636,6 +10962,12 @@ msgstr ""
msgid "Failed to load authors. Please try again."
msgstr ""
+msgid "Failed to load branches. Please try again."
+msgstr ""
+
+msgid "Failed to load deploy keys."
+msgstr ""
+
msgid "Failed to load emoji list."
msgstr ""
@@ -10651,6 +10983,9 @@ msgstr ""
msgid "Failed to load groups & users."
msgstr ""
+msgid "Failed to load groups, users and deploy keys."
+msgstr ""
+
msgid "Failed to load labels. Please try again."
msgstr ""
@@ -10660,6 +10995,12 @@ msgstr ""
msgid "Failed to load related branches"
msgstr ""
+msgid "Failed to load sidebar confidential toggle"
+msgstr ""
+
+msgid "Failed to load sidebar lock status"
+msgstr ""
+
msgid "Failed to load stacktrace."
msgstr ""
@@ -10687,6 +11028,9 @@ msgstr ""
msgid "Failed to publish issue on status page."
msgstr ""
+msgid "Failed to remove To-Do for the design."
+msgstr ""
+
msgid "Failed to remove a Zoom meeting"
msgstr ""
@@ -10729,6 +11073,9 @@ msgstr ""
msgid "Failed to signing using smartcard authentication"
msgstr ""
+msgid "Failed to toggle To-Do for the design."
+msgstr ""
+
msgid "Failed to update branch!"
msgstr ""
@@ -10844,7 +11191,7 @@ msgstr ""
msgid "FeatureFlags|Edit User List"
msgstr ""
-msgid "FeatureFlags|Enable features for specific users and specific environments by defining feature flag strategies."
+msgid "FeatureFlags|Enable features for specific users and environments by configuring feature flag strategies."
msgstr ""
msgid "FeatureFlags|Environment Spec"
@@ -10904,7 +11251,7 @@ msgstr ""
msgid "FeatureFlags|Include additional user IDs"
msgstr ""
-msgid "FeatureFlags|Install a %{docs_link_anchored_start}compatible client library%{docs_link_anchored_end} and specify the API URL, application name, and instance ID during the configuration setup. %{docs_link_start}More Information%{docs_link_end}"
+msgid "FeatureFlags|Install a %{docsLinkAnchoredStart}compatible client library%{docsLinkAnchoredEnd} and specify the API URL, application name, and instance ID during the configuration setup. %{docsLinkStart}More Information%{docsLinkEnd}"
msgstr ""
msgid "FeatureFlags|Instance ID"
@@ -10916,6 +11263,9 @@ msgstr ""
msgid "FeatureFlags|Loading feature flags"
msgstr ""
+msgid "FeatureFlags|Loading user lists"
+msgstr ""
+
msgid "FeatureFlags|More information"
msgstr ""
@@ -10934,7 +11284,7 @@ msgstr ""
msgid "FeatureFlags|New feature flag"
msgstr ""
-msgid "FeatureFlags|New list"
+msgid "FeatureFlags|New user list"
msgstr ""
msgid "FeatureFlags|Percent of users"
@@ -10973,6 +11323,9 @@ msgstr ""
msgid "FeatureFlags|There was an error fetching the feature flags."
msgstr ""
+msgid "FeatureFlags|There was an error fetching the user lists."
+msgstr ""
+
msgid "FeatureFlags|There was an error retrieving user lists"
msgstr ""
@@ -10988,6 +11341,9 @@ msgstr ""
msgid "FeatureFlags|User List"
msgstr ""
+msgid "FeatureFlags|User Lists"
+msgstr ""
+
msgid "FeatureFlag|List"
msgstr ""
@@ -11015,15 +11371,6 @@ msgstr ""
msgid "Fetching incoming email"
msgstr ""
-msgid "Fetching licenses failed."
-msgstr ""
-
-msgid "Fetching licenses failed. The request endpoint was not found."
-msgstr ""
-
-msgid "Fetching licenses failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "File"
msgstr ""
@@ -11126,12 +11473,21 @@ msgstr ""
msgid "Filter by status"
msgstr ""
+msgid "Filter by test cases that are currently archived."
+msgstr ""
+
+msgid "Filter by test cases that are currently opened."
+msgstr ""
+
msgid "Filter by two-factor authentication"
msgstr ""
msgid "Filter by user"
msgstr ""
+msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
+msgstr ""
+
msgid "Filter pipelines"
msgstr ""
@@ -11147,7 +11503,7 @@ msgstr ""
msgid "Filter results..."
msgstr ""
-msgid "Filter your projects by name"
+msgid "Filter your repositories by name"
msgstr ""
msgid "Filter..."
@@ -11156,7 +11512,7 @@ msgstr ""
msgid "Find File"
msgstr ""
-msgid "Find bugs in your code with coverage-guided fuzzing"
+msgid "Find bugs in your code with coverage-guided fuzzing."
msgstr ""
msgid "Find by path"
@@ -11183,9 +11539,6 @@ msgstr ""
msgid "Finish editing this message first!"
msgstr ""
-msgid "Finish review"
-msgstr ""
-
msgid "Finish setting up your dedicated account for %{group_name}."
msgstr ""
@@ -11255,6 +11608,9 @@ msgstr ""
msgid "Footer message"
msgstr ""
+msgid "For a faster browsing experience, some files are collapsed by default."
+msgstr ""
+
msgid "For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
@@ -11264,6 +11620,9 @@ msgstr ""
msgid "For more info, read the documentation."
msgstr ""
+msgid "For more information on how the number of active users is calculated, see the %{self_managed_subscriptions_doc_link} documentation."
+msgstr ""
+
msgid "For more information, go to the "
msgstr ""
@@ -11402,6 +11761,9 @@ msgstr ""
msgid "Generate new token"
msgstr ""
+msgid "Generic package file size in bytes"
+msgstr ""
+
msgid "Geo"
msgstr ""
@@ -11663,6 +12025,9 @@ msgstr ""
msgid "Geo|Please refer to Geo Troubleshooting."
msgstr ""
+msgid "Geo|Primary node"
+msgstr ""
+
msgid "Geo|Project"
msgstr ""
@@ -11705,6 +12070,9 @@ msgstr ""
msgid "Geo|Review replication status, and resynchronize and reverify items with the primary node."
msgstr ""
+msgid "Geo|Secondary node"
+msgstr ""
+
msgid "Geo|Status"
msgstr ""
@@ -11744,6 +12112,9 @@ msgstr ""
msgid "Geo|URL must be a valid url (ex: https://gitlab.com)"
msgstr ""
+msgid "Geo|Undefined"
+msgstr ""
+
msgid "Geo|Unknown state"
msgstr ""
@@ -11819,10 +12190,16 @@ msgstr ""
msgid "GitHub import"
msgstr ""
+msgid "GitLab"
+msgstr ""
+
msgid "GitLab / Unsubscribe"
msgstr ""
-msgid "GitLab Enterprise Edition %{plan}"
+msgid "GitLab API"
+msgstr ""
+
+msgid "GitLab Billing Team."
msgstr ""
msgid "GitLab Group Runners can execute code for all the projects in this group."
@@ -11834,12 +12211,18 @@ msgstr ""
msgid "GitLab Issue"
msgstr ""
+msgid "GitLab Pages"
+msgstr ""
+
msgid "GitLab Service Desk is a simple way to allow people to create issues in your GitLab instance without needing their own user account. It provides a unique email address for end users to create issues in a project, and replies can be sent either through the GitLab interface or by email. End users will only see the thread through email."
msgstr ""
msgid "GitLab Shared Runners execute code of different projects on the same Runner unless you configure GitLab Runner Autoscale with MaxBuilds 1 (which it is on GitLab.com)."
msgstr ""
+msgid "GitLab Shell"
+msgstr ""
+
msgid "GitLab Support Bot"
msgstr ""
@@ -11849,7 +12232,7 @@ msgstr ""
msgid "GitLab User"
msgstr ""
-msgid "GitLab allows you to continue using your license even if you exceed the number of seats you purchased. You will be required to pay for these seats when you renew your license."
+msgid "GitLab Workhorse"
msgstr ""
msgid "GitLab commit"
@@ -12017,6 +12400,21 @@ msgstr ""
msgid "Gitlab Pages"
msgstr ""
+msgid "Gitpod"
+msgstr ""
+
+msgid "Gitpod|Add the URL to your Gitpod instance configured to read your GitLab projects."
+msgstr ""
+
+msgid "Gitpod|Enable Gitpod integration"
+msgstr ""
+
+msgid "Gitpod|Gitpod URL"
+msgstr ""
+
+msgid "Gitpod|e.g. https://gitpod.example.com"
+msgstr ""
+
msgid "Given access %{time_ago}"
msgstr ""
@@ -12524,9 +12922,6 @@ msgstr ""
msgid "GroupSAML|Valid SAML Response"
msgstr ""
-msgid "GroupSAML|With group managed accounts enabled, all the users without a group managed account will be excluded from the group."
-msgstr ""
-
msgid "GroupSAML|With prohibit outer forks flag enabled group members will be able to fork project only inside your group."
msgstr ""
@@ -12740,10 +13135,10 @@ msgstr ""
msgid "GroupsNew|Create group"
msgstr ""
-msgid "GroupsNew|GitLab group export"
+msgid "GroupsNew|Import"
msgstr ""
-msgid "GroupsNew|Import"
+msgid "GroupsNew|Import a GitLab group export file"
msgstr ""
msgid "GroupsNew|Import group"
@@ -12888,6 +13283,9 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "Hide comments on this file"
+msgstr ""
+
msgid "Hide details"
msgstr ""
@@ -12934,6 +13332,15 @@ msgstr ""
msgid "Highest role:"
msgstr ""
+msgid "HighlightBar|Alert events:"
+msgstr ""
+
+msgid "HighlightBar|Alert start time:"
+msgstr ""
+
+msgid "HighlightBar|Original alert:"
+msgstr ""
+
msgid "History"
msgstr ""
@@ -13111,6 +13518,9 @@ msgstr ""
msgid "If enabled, access to projects will be validated on an external service using their classification label."
msgstr ""
+msgid "If the number of active users exceeds the user limit, you will be charged for the number of %{users_over_license_link} at your next license reconciliation."
+msgstr ""
+
msgid "If there is no previous license or if the previous license has expired, some GitLab functionality will be blocked until a new, valid license is uploaded."
msgstr ""
@@ -13150,9 +13560,6 @@ msgstr ""
msgid "If your HTTP repository is not publicly accessible, add your credentials."
msgstr ""
-msgid "Iglu registry URL (optional)"
-msgstr ""
-
msgid "Ignore"
msgstr ""
@@ -13189,6 +13596,20 @@ msgstr ""
msgid "Import"
msgstr ""
+msgid "Import %d compatible repository"
+msgid_plural "Import %d compatible repositories"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
+msgid "Import %d repository"
+msgid_plural "Import %d repositories"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "Import CSV"
msgstr ""
@@ -13198,15 +13619,9 @@ msgstr ""
msgid "Import all compatible projects"
msgstr ""
-msgid "Import all compatible repositories"
-msgstr ""
-
msgid "Import all projects"
msgstr ""
-msgid "Import all repositories"
-msgstr ""
-
msgid "Import an exported GitLab project"
msgstr ""
@@ -13294,6 +13709,9 @@ msgstr ""
msgid "ImportProjects|Error importing repository %{project_safe_import_url} into %{project_full_path} - %{message}"
msgstr ""
+msgid "ImportProjects|Import repositories"
+msgstr ""
+
msgid "ImportProjects|Importing the project failed"
msgstr ""
@@ -13306,7 +13724,7 @@ msgstr ""
msgid "ImportProjects|Requesting your %{provider} repositories failed"
msgstr ""
-msgid "ImportProjects|Select the projects you want to import"
+msgid "ImportProjects|Select the repositories you want to import"
msgstr ""
msgid "ImportProjects|The remote data could not be imported."
@@ -13342,9 +13760,6 @@ msgstr ""
msgid "In order to enable Service Desk for your instance, you must first set up incoming email."
msgstr ""
-msgid "In order to gather accurate feature usage data, it can take 1 to 2 weeks to see your index."
-msgstr ""
-
msgid "In order to personalize your experience with GitLab%{br_tag}we would like to know a bit more about you."
msgstr ""
@@ -13375,18 +13790,30 @@ msgstr ""
msgid "IncidentManagement|Create incident"
msgstr ""
+msgid "IncidentManagement|Critical - S1"
+msgstr ""
+
msgid "IncidentManagement|Date created"
msgstr ""
msgid "IncidentManagement|Display your incidents in a dedicated view"
msgstr ""
+msgid "IncidentManagement|High - S2"
+msgstr ""
+
msgid "IncidentManagement|Incident"
msgstr ""
msgid "IncidentManagement|Incidents"
msgstr ""
+msgid "IncidentManagement|Low - S4"
+msgstr ""
+
+msgid "IncidentManagement|Medium - S3"
+msgstr ""
+
msgid "IncidentManagement|No incidents to display."
msgstr ""
@@ -13399,6 +13826,9 @@ msgstr ""
msgid "IncidentManagement|Published to status page"
msgstr ""
+msgid "IncidentManagement|Severity"
+msgstr ""
+
msgid "IncidentManagement|There are no closed incidents"
msgstr ""
@@ -13408,6 +13838,9 @@ msgstr ""
msgid "IncidentManagement|Unassigned"
msgstr ""
+msgid "IncidentManagement|Unknown"
+msgstr ""
+
msgid "IncidentManagement|Unpublished"
msgstr ""
@@ -13429,6 +13862,15 @@ msgstr ""
msgid "Incidents"
msgstr ""
+msgid "Incident|Alert details"
+msgstr ""
+
+msgid "Incident|Summary"
+msgstr ""
+
+msgid "Incident|There was an issue loading alert data. Please try again."
+msgstr ""
+
msgid "Include a Terms of Service agreement and Privacy Policy that all users must accept."
msgstr ""
@@ -13489,6 +13931,9 @@ msgstr ""
msgid "Information about additional Pages templates and how to install them can be found in our %{pages_getting_started_guide}."
msgstr ""
+msgid "Inherited"
+msgstr ""
+
msgid "Inherited:"
msgstr ""
@@ -13571,7 +14016,22 @@ msgstr ""
msgid "Instance administrators group already exists"
msgstr ""
-msgid "Instance license"
+msgid "InstanceStatistics|Groups"
+msgstr ""
+
+msgid "InstanceStatistics|Issues"
+msgstr ""
+
+msgid "InstanceStatistics|Merge Requests"
+msgstr ""
+
+msgid "InstanceStatistics|Pipelines"
+msgstr ""
+
+msgid "InstanceStatistics|Projects"
+msgstr ""
+
+msgid "InstanceStatistics|Users"
msgstr ""
msgid "Integration"
@@ -13583,6 +14043,12 @@ msgstr ""
msgid "Integrations"
msgstr ""
+msgid "Integrations|%{integration} settings saved and active."
+msgstr ""
+
+msgid "Integrations|%{integration} settings saved, but not active."
+msgstr ""
+
msgid "Integrations|All details"
msgstr ""
@@ -13592,6 +14058,12 @@ msgstr ""
msgid "Integrations|Comment settings:"
msgstr ""
+msgid "Integrations|Connection failed. Please check your settings."
+msgstr ""
+
+msgid "Integrations|Connection successful."
+msgstr ""
+
msgid "Integrations|Default settings are inherited from the group level."
msgstr ""
@@ -13607,6 +14079,15 @@ msgstr ""
msgid "Integrations|Includes commit title and branch"
msgstr ""
+msgid "Integrations|Projects using custom settings will not be impacted unless the project owner chooses to use instance-level defaults."
+msgstr ""
+
+msgid "Integrations|Save settings?"
+msgstr ""
+
+msgid "Integrations|Saving will update the default settings for all projects that are not using custom settings."
+msgstr ""
+
msgid "Integrations|Standard"
msgstr ""
@@ -13739,6 +14220,9 @@ msgstr ""
msgid "Invitation"
msgstr ""
+msgid "Invitation declined"
+msgstr ""
+
msgid "Invite"
msgstr ""
@@ -13790,6 +14274,42 @@ 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|%{linkStart}Read more%{linkEnd} about role permissions"
+msgstr ""
+
+msgid "InviteMembersModal|Access expiration date (optional)"
+msgstr ""
+
+msgid "InviteMembersModal|Cancel"
+msgstr ""
+
+msgid "InviteMembersModal|Choose a role permission"
+msgstr ""
+
+msgid "InviteMembersModal|GitLab member or Email address"
+msgstr ""
+
+msgid "InviteMembersModal|Invite"
+msgstr ""
+
+msgid "InviteMembersModal|Invite team members"
+msgstr ""
+
+msgid "InviteMembersModal|Search for members to invite"
+msgstr ""
+
+msgid "InviteMembersModal|User not invited. Feature coming soon!"
+msgstr ""
+
+msgid "InviteMembersModal|Users were succesfully added"
+msgstr ""
+
+msgid "InviteMembersModal|You're inviting members to the %{group_name} group"
+msgstr ""
+
+msgid "InviteMembers|Invite team members"
+msgstr ""
+
msgid "Invited"
msgstr ""
@@ -13844,10 +14364,13 @@ msgstr ""
msgid "Issue cannot be found."
msgstr ""
+msgid "Issue created from vulnerability %{vulnerability_link}"
+msgstr ""
+
msgid "Issue events"
msgstr ""
-msgid "Issue first depoloyed to production"
+msgid "Issue first deployed to production"
msgstr ""
msgid "Issue label"
@@ -13925,6 +14448,9 @@ msgstr ""
msgid "IssueTracker|Custom issue tracker"
msgstr ""
+msgid "IssueTracker|EWM work items tracker"
+msgstr ""
+
msgid "IssueTracker|Redmine issue tracker"
msgstr ""
@@ -13991,6 +14517,9 @@ msgstr ""
msgid "It looks like you have some draft commits in this branch."
msgstr ""
+msgid "It may be several days before you see feature usage data."
+msgstr ""
+
msgid "It must have a header row and at least two columns: the first column is the issue title and the second column is the issue description. The separator is automatically detected."
msgstr ""
@@ -14273,13 +14802,13 @@ msgstr ""
msgid "Join Zoom meeting"
msgstr ""
-msgid "Jul"
+msgid "Joined %{time_ago}"
msgstr ""
-msgid "July"
+msgid "Jul"
msgstr ""
-msgid "Jump to first unresolved thread"
+msgid "July"
msgstr ""
msgid "Jump to next unresolved thread"
@@ -14315,6 +14844,9 @@ msgstr ""
msgid "Keyboard shortcuts"
msgstr ""
+msgid "KeyboardKey|Ctrl+"
+msgstr ""
+
msgid "Keys"
msgstr ""
@@ -14363,6 +14895,9 @@ msgstr ""
msgid "LDAP Synchronization"
msgstr ""
+msgid "LDAP group settings"
+msgstr ""
+
msgid "LDAP settings"
msgstr ""
@@ -14372,6 +14907,9 @@ msgstr ""
msgid "LDAP sync in progress. This could take a few minutes. Refresh the page to see the changes."
msgstr ""
+msgid "LDAP synchronizations"
+msgstr ""
+
msgid "LFS"
msgstr ""
@@ -14454,7 +14992,16 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "Last %{days} days"
+msgid "Last 2 weeks"
+msgstr ""
+
+msgid "Last 30 days"
+msgstr ""
+
+msgid "Last 60 days"
+msgstr ""
+
+msgid "Last 90 days"
msgstr ""
msgid "Last Accessed On"
@@ -14532,6 +15079,9 @@ msgstr ""
msgid "Last used on:"
msgstr ""
+msgid "Last week"
+msgstr ""
+
msgid "LastCommit|authored"
msgstr ""
@@ -14547,6 +15097,9 @@ msgstr ""
msgid "Latest pipeline for the most recent commit on this branch"
msgstr ""
+msgid "Launch a ready-to-code development environment for your project."
+msgstr ""
+
msgid "Lead"
msgstr ""
@@ -14941,6 +15494,9 @@ msgstr ""
msgid "List of all merge commits"
msgstr ""
+msgid "List options"
+msgstr ""
+
msgid "List settings"
msgstr ""
@@ -14953,9 +15509,6 @@ msgstr ""
msgid "List your Bitbucket Server repositories"
msgstr ""
-msgid "Lists"
-msgstr ""
-
msgid "Live preview"
msgstr ""
@@ -15202,6 +15755,12 @@ msgstr ""
msgid "Mark as done"
msgstr ""
+msgid "Mark as draft"
+msgstr ""
+
+msgid "Mark as ready"
+msgstr ""
+
msgid "Mark as resolved"
msgstr ""
@@ -15223,6 +15782,24 @@ msgstr ""
msgid "Markdown is supported"
msgstr ""
+msgid "MarkdownEditor|Add a link (%{modifierKey}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add a link (%{modifier_key}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifierKey}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifier_key}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifierKey}I)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifier_key}I)"
+msgstr ""
+
msgid "Marked For Deletion At - %{deletion_time}"
msgstr ""
@@ -15307,7 +15884,25 @@ msgstr ""
msgid "Max access level"
msgstr ""
-msgid "Max seats used"
+msgid "Max role"
+msgstr ""
+
+msgid "Max size 15 MB"
+msgstr ""
+
+msgid "Maximum Conan package file size in bytes"
+msgstr ""
+
+msgid "Maximum Maven package file size in bytes"
+msgstr ""
+
+msgid "Maximum NPM package file size in bytes"
+msgstr ""
+
+msgid "Maximum NuGet package file size in bytes"
+msgstr ""
+
+msgid "Maximum PyPI package file size in bytes"
msgstr ""
msgid "Maximum Users:"
@@ -15439,6 +16034,18 @@ msgstr ""
msgid "Members with access to %{strong_start}%{group_name}%{strong_end}"
msgstr ""
+msgid "Members|%{time} by %{user}"
+msgstr ""
+
+msgid "Members|Expired"
+msgstr ""
+
+msgid "Members|No expiration set"
+msgstr ""
+
+msgid "Members|in %{time}"
+msgstr ""
+
msgid "Memory Usage"
msgstr ""
@@ -15625,9 +16232,6 @@ msgstr ""
msgid "MergeRequests|Thread will be unresolved"
msgstr ""
-msgid "MergeRequests|Toggle comments for this file"
-msgstr ""
-
msgid "MergeRequests|View file @ %{commitId}"
msgstr ""
@@ -15688,6 +16292,9 @@ msgstr ""
msgid "Merging immediately isn't recommended as it may negatively impact the existing merge train. Read the %{docsLinkStart}documentation%{docsLinkEnd} for more information."
msgstr ""
+msgid "Message"
+msgstr ""
+
msgid "Messages"
msgstr ""
@@ -16077,18 +16684,12 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "Milestone does not support burnup charts"
-msgstr ""
-
msgid "Milestone lists not available with your current license"
msgstr ""
msgid "Milestone lists show all issues from the selected milestone."
msgstr ""
-msgid "Milestone must have a start and due date"
-msgstr ""
-
msgid "MilestoneSidebar|Closed:"
msgstr ""
@@ -16455,6 +17056,9 @@ msgstr ""
msgid "Namespace"
msgstr ""
+msgid "Namespace ID:"
+msgstr ""
+
msgid "Namespace is empty"
msgstr ""
@@ -16539,6 +17143,9 @@ msgstr ""
msgid "NetworkPolicies|Allow all outbound traffic from %{selector} to %{ruleSelector} on %{ports}"
msgstr ""
+msgid "NetworkPolicies|Are you sure you want to delete this policy? This action cannot be undone."
+msgstr ""
+
msgid "NetworkPolicies|Choose whether to enforce this policy."
msgstr ""
@@ -16548,12 +17155,21 @@ msgstr ""
msgid "NetworkPolicies|Define this policy's location, conditions and actions."
msgstr ""
+msgid "NetworkPolicies|Delete policy"
+msgstr ""
+
+msgid "NetworkPolicies|Delete policy: %{policy}"
+msgstr ""
+
msgid "NetworkPolicies|Deny all traffic"
msgstr ""
msgid "NetworkPolicies|Description"
msgstr ""
+msgid "NetworkPolicies|Edit policy"
+msgstr ""
+
msgid "NetworkPolicies|Editor mode"
msgstr ""
@@ -16581,6 +17197,9 @@ msgstr ""
msgid "NetworkPolicies|Name"
msgstr ""
+msgid "NetworkPolicies|Namespace"
+msgstr ""
+
msgid "NetworkPolicies|Network Policy"
msgstr ""
@@ -16632,6 +17251,9 @@ msgstr ""
msgid "NetworkPolicies|Rules"
msgstr ""
+msgid "NetworkPolicies|Save changes"
+msgstr ""
+
msgid "NetworkPolicies|Something went wrong, failed to update policy"
msgstr ""
@@ -16644,6 +17266,9 @@ msgstr ""
msgid "NetworkPolicies|Traffic that does not match any rule will be blocked."
msgstr ""
+msgid "NetworkPolicies|Unable to parse policy"
+msgstr ""
+
msgid "NetworkPolicies|YAML editor"
msgstr ""
@@ -16759,6 +17384,9 @@ msgstr ""
msgid "New Snippet"
msgstr ""
+msgid "New Test Case"
+msgstr ""
+
msgid "New User"
msgstr ""
@@ -16858,6 +17486,9 @@ msgstr ""
msgid "New tag"
msgstr ""
+msgid "New test case"
+msgstr ""
+
msgid "New users set to external"
msgstr ""
@@ -16930,7 +17561,7 @@ msgstr ""
msgid "No changes"
msgstr ""
-msgid "No changes between %{ref_start}%{source_branch}%{ref_end} and %{ref_start}%{target_branch}%{ref_end}"
+msgid "No changes between %{sourceBranch} and %{targetBranch}"
msgstr ""
msgid "No child epics match applied filters"
@@ -16945,6 +17576,9 @@ msgstr ""
msgid "No containers available"
msgstr ""
+msgid "No content to show"
+msgstr ""
+
msgid "No contributions"
msgstr ""
@@ -17020,9 +17654,6 @@ msgstr ""
msgid "No license. All rights reserved"
msgstr ""
-msgid "No licenses found."
-msgstr ""
-
msgid "No matches found"
msgstr ""
@@ -17035,6 +17666,9 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No members found"
+msgstr ""
+
msgid "No merge requests found"
msgstr ""
@@ -17056,6 +17690,9 @@ msgstr ""
msgid "No parent group"
msgstr ""
+msgid "No plan"
+msgstr ""
+
msgid "No pods available"
msgstr ""
@@ -17152,6 +17789,12 @@ msgstr ""
msgid "Not Implemented"
msgstr ""
+msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+msgstr ""
+
+msgid "Not all browsers support WebAuthn. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even from an unsupported browser."
+msgstr ""
+
msgid "Not all data has been processed yet, the accuracy of the chart for the selected timeframe is limited."
msgstr ""
@@ -17248,6 +17891,9 @@ msgstr ""
msgid "Notification settings saved"
msgstr ""
+msgid "NotificationEvent|Change reviewer merge request"
+msgstr ""
+
msgid "NotificationEvent|Close issue"
msgstr ""
@@ -17410,10 +18056,7 @@ msgstr ""
msgid "On track"
msgstr ""
-msgid "OnDemandScans|Attached branch"
-msgstr ""
-
-msgid "OnDemandScans|Attached branch is where the scan job runs."
+msgid "OnDemandScans|Could not fetch scanner profiles. Please refresh the page, or try again later."
msgstr ""
msgid "OnDemandScans|Could not fetch site profiles. Please refresh the page, or try again later."
@@ -17422,6 +18065,9 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
+msgid "OnDemandScans|Create a new scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Create a new site profile"
msgstr ""
@@ -17434,6 +18080,9 @@ msgstr ""
msgid "OnDemandScans|New on-demand DAST scan"
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 ""
@@ -17443,16 +18092,10 @@ msgstr ""
msgid "OnDemandScans|On-demand scans run outside the DevOps cycle and find vulnerabilities in your projects. %{learnMoreLinkStart}Learn more%{learnMoreLinkEnd}"
msgstr ""
-msgid "OnDemandScans|Only a passive scan can be performed on demand."
-msgstr ""
-
-msgid "OnDemandScans|Passive"
-msgstr ""
-
msgid "OnDemandScans|Run scan"
msgstr ""
-msgid "OnDemandScans|Scan mode"
+msgid "OnDemandScans|Scanner profile"
msgstr ""
msgid "OnDemandScans|Scanner settings"
@@ -17464,9 +18107,15 @@ msgstr ""
msgid "OnDemandScans|Select one of the existing profiles"
msgstr ""
+msgid "OnDemandScans|Site profile"
+msgstr ""
+
msgid "OnDemandScans|Site profiles"
msgstr ""
+msgid "OnDemandScans|Use existing scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Use existing site profile"
msgstr ""
@@ -17567,9 +18216,6 @@ msgstr ""
msgid "Open Selection"
msgstr ""
-msgid "Open Web IDE"
-msgstr ""
-
msgid "Open comment type dropdown"
msgstr ""
@@ -17675,6 +18321,9 @@ msgstr ""
msgid "Origin"
msgstr ""
+msgid "Orphaned member"
+msgstr ""
+
msgid "Other Labels"
msgstr ""
@@ -17690,6 +18339,9 @@ msgstr ""
msgid "Other visibility settings have been disabled by the administrator."
msgstr ""
+msgid "Our documentation includes an example DevOps Score report."
+msgstr ""
+
msgid "Out-of-compliance with this project's policies and should be removed"
msgstr ""
@@ -17714,6 +18366,9 @@ msgstr ""
msgid "Overwrite diverged branches"
msgstr ""
+msgid "Owned by %{image_tag}"
+msgstr ""
+
msgid "Owned by anyone"
msgstr ""
@@ -17735,6 +18390,9 @@ msgstr ""
msgid "Package deleted successfully"
msgstr ""
+msgid "Package file size limits"
+msgstr ""
+
msgid "Package recipe already exists"
msgstr ""
@@ -17750,9 +18408,6 @@ msgstr ""
msgid "Package type must be PyPi"
msgstr ""
-msgid "Package was removed"
-msgstr ""
-
msgid "PackageRegistry|%{name} version %{version} was created %{datetime}"
msgstr ""
@@ -17894,12 +18549,18 @@ msgstr ""
msgid "PackageRegistry|NuGet Command"
msgstr ""
+msgid "PackageRegistry|Package Registry"
+msgstr ""
+
msgid "PackageRegistry|Pip Command"
msgstr ""
msgid "PackageRegistry|Pipeline %{link} triggered %{datetime} by %{author}"
msgstr ""
+msgid "PackageRegistry|Publish and share packages for a variety of common package managers. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "PackageRegistry|Published to the %{project} Package Registry %{datetime}"
msgstr ""
@@ -17999,6 +18660,9 @@ msgstr ""
msgid "Page not found"
msgstr ""
+msgid "Page settings"
+msgstr ""
+
msgid "Page was successfully deleted"
msgstr ""
@@ -18140,7 +18804,7 @@ msgstr ""
msgid "Paste issue link"
msgstr ""
-msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Don't use your private SSH key."
+msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Do not paste your private SSH key, as that can compromise your identity."
msgstr ""
msgid "Patch to apply"
@@ -18167,6 +18831,9 @@ msgstr ""
msgid "Pending"
msgstr ""
+msgid "Pending comments"
+msgstr ""
+
msgid "People without permission will never get a notification and won't be able to comment."
msgstr ""
@@ -18365,6 +19032,9 @@ msgstr ""
msgid "Pipelines|Build with confidence"
msgstr ""
+msgid "Pipelines|By revoking a trigger you will break any processes making use of it. Are you sure?"
+msgstr ""
+
msgid "Pipelines|CI Lint"
msgstr ""
@@ -18377,6 +19047,15 @@ msgstr ""
msgid "Pipelines|Continuous Integration can help catch bugs by running your tests automatically, while Continuous Deployment can help you deliver code to your product environment."
msgstr ""
+msgid "Pipelines|Copy trigger token"
+msgstr ""
+
+msgid "Pipelines|Description"
+msgstr ""
+
+msgid "Pipelines|Edit"
+msgstr ""
+
msgid "Pipelines|Get started with Pipelines"
msgstr ""
@@ -18392,15 +19071,27 @@ msgstr ""
msgid "Pipelines|It is recommended the code is reviewed thoroughly before running this pipeline with the parent project's CI resource."
msgstr ""
+msgid "Pipelines|Last Used"
+msgstr ""
+
msgid "Pipelines|Loading Pipelines"
msgstr ""
msgid "Pipelines|More Information"
msgstr ""
+msgid "Pipelines|No triggers have been created yet. Add one using the form above."
+msgstr ""
+
+msgid "Pipelines|Owner"
+msgstr ""
+
msgid "Pipelines|Project cache successfully reset."
msgstr ""
+msgid "Pipelines|Revoke"
+msgstr ""
+
msgid "Pipelines|Run Pipeline"
msgstr ""
@@ -18425,6 +19116,15 @@ msgstr ""
msgid "Pipelines|This project is not currently set up to run pipelines."
msgstr ""
+msgid "Pipelines|Token"
+msgstr ""
+
+msgid "Pipelines|Trigger user has insufficient permissions to project"
+msgstr ""
+
+msgid "Pipelines|invalid"
+msgstr ""
+
msgid "Pipelines|parent"
msgstr ""
@@ -18683,10 +19383,10 @@ msgstr ""
msgid "Please provide attributes to update"
msgstr ""
-msgid "Please refer to %{docs_url}"
+msgid "Please reach out if you have any questions and we'll be happy to assist."
msgstr ""
-msgid "Please retype the email address."
+msgid "Please refer to %{docs_url}"
msgstr ""
msgid "Please select"
@@ -18716,6 +19416,9 @@ msgstr ""
msgid "Please set a new password before proceeding."
msgstr ""
+msgid "Please share your feedback about %{featureName} %{linkStart}in this issue%{linkEnd} to help us improve the experience."
+msgstr ""
+
msgid "Please solve the reCAPTCHA"
msgstr ""
@@ -19019,6 +19722,9 @@ msgstr ""
msgid "Profiles| You are going to change the username %{currentUsernameBold} to %{newUsernameBold}. Profile and projects will be redirected to the %{newUsername} namespace but this redirect will expire once the %{currentUsername} namespace is registered by another user or group. Please update your Git repository remotes as soon as possible."
msgstr ""
+msgid "Profiles|%{provider} Active"
+msgstr ""
+
msgid "Profiles|@username"
msgstr ""
@@ -19070,7 +19776,7 @@ msgstr ""
msgid "Profiles|Commit email"
msgstr ""
-msgid "Profiles|Connect"
+msgid "Profiles|Connect %{provider}"
msgstr ""
msgid "Profiles|Connected Accounts"
@@ -19094,6 +19800,9 @@ msgstr ""
msgid "Profiles|Disconnect"
msgstr ""
+msgid "Profiles|Disconnect %{provider}"
+msgstr ""
+
msgid "Profiles|Do not show on profile"
msgstr ""
@@ -19118,7 +19827,7 @@ msgstr ""
msgid "Profiles|Full name"
msgstr ""
-msgid "Profiles|Give your individual key a title. This will be publically visible."
+msgid "Profiles|Give your individual key a title."
msgstr ""
msgid "Profiles|Include private contributions on my profile"
@@ -19208,7 +19917,7 @@ msgstr ""
msgid "Profiles|The maximum file size allowed is 200KB."
msgstr ""
-msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it?"
+msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it? It will be publicly visible."
msgstr ""
msgid "Profiles|This email will be displayed on your public profile"
@@ -19283,6 +19992,9 @@ msgstr ""
msgid "Profiles|You don't have access to delete this user."
msgstr ""
+msgid "Profiles|You must transfer ownership or delete groups you are an owner of before you can delete your account"
+msgstr ""
+
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
@@ -19871,6 +20583,9 @@ msgstr ""
msgid "ProjectTemplates|GitLab Cluster Management"
msgstr ""
+msgid "ProjectTemplates|Gitpod/Spring Petclinic"
+msgstr ""
+
msgid "ProjectTemplates|Go Micro"
msgstr ""
@@ -20480,6 +21195,9 @@ msgstr ""
msgid "Publish to status page"
msgstr ""
+msgid "Published"
+msgstr ""
+
msgid "Published on status page"
msgstr ""
@@ -20597,9 +21315,15 @@ msgstr ""
msgid "Quick range"
msgstr ""
+msgid "Quickly and easily edit multiple files in your project."
+msgstr ""
+
msgid "README"
msgstr ""
+msgid "Rails"
+msgstr ""
+
msgid "Rake Tasks Help"
msgstr ""
@@ -20721,10 +21445,13 @@ msgstr ""
msgid "Register Two-Factor Authenticator"
msgstr ""
-msgid "Register U2F device"
+msgid "Register Universal Two-Factor (U2F) Device"
+msgstr ""
+
+msgid "Register WebAuthn Device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register device"
msgstr ""
msgid "Register for GitLab"
@@ -20736,9 +21463,6 @@ msgstr ""
msgid "Register with two-factor app"
msgstr ""
-msgid "Registration"
-msgstr ""
-
msgid "Registration|Checkout"
msgstr ""
@@ -20857,9 +21581,6 @@ msgstr ""
msgid "Release|Something went wrong while saving the release details"
msgstr ""
-msgid "Remediated: needs review"
-msgstr ""
-
msgid "Remediations"
msgstr ""
@@ -20965,6 +21686,9 @@ msgstr ""
msgid "Remove priority"
msgstr ""
+msgid "Remove report"
+msgstr ""
+
msgid "Remove secondary node"
msgstr ""
@@ -20977,6 +21701,12 @@ msgstr ""
msgid "Remove time estimate"
msgstr ""
+msgid "Remove user & report"
+msgstr ""
+
+msgid "Remove user from group"
+msgstr ""
+
msgid "Removed"
msgstr ""
@@ -21058,9 +21788,6 @@ msgstr ""
msgid "Removes time estimate."
msgstr ""
-msgid "Removing license…"
-msgstr ""
-
msgid "Removing this group also removes all child projects, including archived projects, and their resources."
msgstr ""
@@ -21145,6 +21872,9 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
+msgid "Reported by %{reporter}"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -21233,6 +21963,27 @@ msgstr ""
msgid "Repositories"
msgstr ""
+msgid "Repositories Analytics"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download Historic Test Coverage Data"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download historic test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Historic Test Coverage Data is available in raw format (.csv) for further analysis."
+msgstr ""
+
+msgid "RepositoriesAnalytics|Test Code Coverage"
+msgstr ""
+
+msgid "RepositoriesAnalytics|There was an error fetching the projects."
+msgstr ""
+
msgid "Repository"
msgstr ""
@@ -21311,9 +22062,15 @@ msgstr ""
msgid "Request parameter %{param} is missing."
msgstr ""
+msgid "Request review from"
+msgstr ""
+
msgid "Request to link SAML account must be authorized"
msgstr ""
+msgid "Requested"
+msgstr ""
+
msgid "Requested %{time_ago}"
msgstr ""
@@ -21332,6 +22089,9 @@ msgstr ""
msgid "Requests to these domain(s)/address(es) on the local network will be allowed when local requests from hooks and services are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 or 127.0.0.0/28 are supported. Domain wildcards are not supported currently. Use comma, semicolon, or newline to separate multiple entries. The allowlist can hold a maximum of 1000 entries. Domains should use IDNA encoding. Ex: example.com, 192.168.1.1, 127.0.0.0/28, xn--itlab-j1a.com."
msgstr ""
+msgid "Require admin approval for new sign-ups"
+msgstr ""
+
msgid "Require all users in this group to setup Two-factor authentication"
msgstr ""
@@ -21463,9 +22223,6 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
-msgid "Resolved by %{resolvedByName}"
-msgstr ""
-
msgid "Resolves IP addresses once and uses them to submit requests"
msgstr ""
@@ -21587,6 +22344,16 @@ msgstr ""
msgid "ReviewApp|Enable Review App"
msgstr ""
+msgid "Reviewer"
+msgid_plural "%d Reviewers"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
+msgid "Reviewer(s)"
+msgstr ""
+
msgid "Reviewing"
msgstr ""
@@ -21626,6 +22393,9 @@ msgstr ""
msgid "Rook"
msgstr ""
+msgid "Ruby"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -21704,6 +22474,63 @@ msgstr ""
msgid "Runners page."
msgstr ""
+msgid "Runners|Active"
+msgstr ""
+
+msgid "Runners|Architecture"
+msgstr ""
+
+msgid "Runners|Can run untagged jobs"
+msgstr ""
+
+msgid "Runners|Description"
+msgstr ""
+
+msgid "Runners|Group"
+msgstr ""
+
+msgid "Runners|IP Address"
+msgstr ""
+
+msgid "Runners|Last contact"
+msgstr ""
+
+msgid "Runners|Locked to this project"
+msgstr ""
+
+msgid "Runners|Maximum job timeout"
+msgstr ""
+
+msgid "Runners|Name"
+msgstr ""
+
+msgid "Runners|Platform"
+msgstr ""
+
+msgid "Runners|Property Name"
+msgstr ""
+
+msgid "Runners|Protected"
+msgstr ""
+
+msgid "Runners|Revision"
+msgstr ""
+
+msgid "Runners|Shared"
+msgstr ""
+
+msgid "Runners|Specific"
+msgstr ""
+
+msgid "Runners|Tags"
+msgstr ""
+
+msgid "Runners|Value"
+msgstr ""
+
+msgid "Runners|Version"
+msgstr ""
+
msgid "Runners|You have used %{quotaUsed} out of %{quotaLimit} of your shared Runners pipeline minutes."
msgstr ""
@@ -21716,6 +22543,9 @@ msgstr ""
msgid "Runs a number of housekeeping tasks within the current repository, such as compressing file revisions and removing unreachable objects."
msgstr ""
+msgid "SAML"
+msgstr ""
+
msgid "SAML SSO"
msgstr ""
@@ -21767,6 +22597,9 @@ msgstr ""
msgid "Save"
msgstr ""
+msgid "Save %{name} size limits"
+msgstr ""
+
msgid "Save Changes"
msgstr ""
@@ -21797,9 +22630,6 @@ msgstr ""
msgid "Save space and find tags in the Container Registry more easily. Enable the cleanup policy to remove stale tags and keep only the ones you need."
msgstr ""
-msgid "Save template"
-msgstr ""
-
msgid "Save variables"
msgstr ""
@@ -21842,9 +22672,6 @@ msgstr ""
msgid "Scope"
msgstr ""
-msgid "Scope not supported with disabled 'users_search' feature!"
-msgstr ""
-
msgid "Scoped issue boards"
msgstr ""
@@ -21971,9 +22798,6 @@ msgstr ""
msgid "Search requirements"
msgstr ""
-msgid "Search results…"
-msgstr ""
-
msgid "Search users"
msgstr ""
@@ -22052,6 +22876,13 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "SearchResults|epic"
+msgid_plural "SearchResults|epics"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "SearchResults|issue"
msgid_plural "SearchResults|issues"
msgstr[0] ""
@@ -22110,10 +22941,10 @@ msgstr ""
msgid "Seat Link is disabled, and cannot be configured through this form."
msgstr ""
-msgid "Seats currently in use"
+msgid "Seats usage data as of %{last_enqueue_time}"
msgstr ""
-msgid "Seats in license"
+msgid "Seats usage data is updated every day at 12:00pm UTC"
msgstr ""
msgid "Secondary"
@@ -22167,6 +22998,9 @@ msgstr ""
msgid "SecurityConfiguration|Available for on-demand DAST"
msgstr ""
+msgid "SecurityConfiguration|By default, all analyzers are applied in order to cover all languages across your project, and only run if the language is detected in the Merge Request."
+msgstr ""
+
msgid "SecurityConfiguration|Configure"
msgstr ""
@@ -22197,16 +23031,19 @@ msgstr ""
msgid "SecurityConfiguration|Manage"
msgstr ""
+msgid "SecurityConfiguration|More information"
+msgstr ""
+
msgid "SecurityConfiguration|Not enabled"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|Security Control"
+msgid "SecurityConfiguration|SAST Configuration"
msgstr ""
-msgid "SecurityConfiguration|See documentation"
+msgid "SecurityConfiguration|Security Control"
msgstr ""
msgid "SecurityConfiguration|Status"
@@ -22218,6 +23055,9 @@ msgstr ""
msgid "SecurityConfiguration|Using custom settings. You won't receive automatic updates on this variable. %{anchorStart}Restore to default%{anchorEnd}"
msgstr ""
+msgid "SecurityConfiguration|View history"
+msgstr ""
+
msgid "SecurityConfiguration|You can quickly enable all security scanning tools by enabling %{linkStart}Auto DevOps%{linkEnd}."
msgstr ""
@@ -22296,9 +23136,6 @@ msgstr ""
msgid "SecurityReports|Learn more about setting up your dashboard"
msgstr ""
-msgid "SecurityReports|Load more vulnerabilities"
-msgstr ""
-
msgid "SecurityReports|Monitor vulnerabilities in your code"
msgstr ""
@@ -22578,7 +23415,7 @@ msgstr ""
msgid "Select status"
msgstr ""
-msgid "Select strategy activation method"
+msgid "Select strategy activation method."
msgstr ""
msgid "Select subscription"
@@ -22593,7 +23430,7 @@ msgstr ""
msgid "Select the custom project template source group."
msgstr ""
-msgid "Select timeframe"
+msgid "Select the environment scope for this feature flag."
msgstr ""
msgid "Select timezone"
@@ -22842,6 +23679,9 @@ msgstr ""
msgid "Set iteration"
msgstr ""
+msgid "Set limit to 0 to allow any file size."
+msgstr ""
+
msgid "Set max session time for web terminal."
msgstr ""
@@ -22920,10 +23760,13 @@ msgstr ""
msgid "Set up a %{type} Runner manually"
msgstr ""
+msgid "Set up a hardware device as a second factor to sign in."
+msgstr ""
+
msgid "Set up assertions/attributes/claims (email, first_name, last_name) and NameID according to %{docsLinkStart}the documentation %{icon}%{docsLinkEnd}"
msgstr ""
-msgid "Set up new U2F device"
+msgid "Set up new device"
msgstr ""
msgid "Set up new password"
@@ -22992,6 +23835,9 @@ msgstr ""
msgid "Sets weight to %{weight}."
msgstr ""
+msgid "Setting this to 0 means using the system default timeout value."
+msgstr ""
+
msgid "Settings"
msgstr ""
@@ -23007,6 +23853,15 @@ msgstr ""
msgid "Severity"
msgstr ""
+msgid "SeverityWidget|Severity"
+msgstr ""
+
+msgid "SeverityWidget|Severity: %{severity}"
+msgstr ""
+
+msgid "SeverityWidget|There was an error while updating severity."
+msgstr ""
+
msgid "Shards (%{shards})"
msgstr ""
@@ -23052,6 +23907,9 @@ msgstr ""
msgid "Show all requirements."
msgstr ""
+msgid "Show all test cases."
+msgstr ""
+
msgid "Show archived projects"
msgstr ""
@@ -23064,6 +23922,9 @@ msgstr ""
msgid "Show comments"
msgstr ""
+msgid "Show comments on this file"
+msgstr ""
+
msgid "Show comments only"
msgstr ""
@@ -23109,6 +23970,12 @@ msgstr ""
msgid "Show parent subgroups"
msgstr ""
+msgid "Show the Closed list"
+msgstr ""
+
+msgid "Show the Open list"
+msgstr ""
+
msgid "Show whitespace changes"
msgstr ""
@@ -23156,9 +24023,6 @@ msgstr ""
msgid "Sidebar|Assign health status"
msgstr ""
-msgid "Sidebar|Change weight"
-msgstr ""
-
msgid "Sidebar|Health status"
msgstr ""
@@ -23342,6 +24206,9 @@ msgstr ""
msgid "Snippets|Add another file %{num}/%{total}"
msgstr ""
+msgid "Snippets|Authored %{time_ago} by %{author}"
+msgstr ""
+
msgid "Snippets|Delete file"
msgstr ""
@@ -23369,6 +24236,9 @@ msgstr ""
msgid "Solution"
msgstr ""
+msgid "Some changes are not shown"
+msgstr ""
+
msgid "Some child epics may be hidden due to applied filters"
msgstr ""
@@ -23735,6 +24605,12 @@ msgstr ""
msgid "Source (branch or tag)"
msgstr ""
+msgid "Source Branch"
+msgstr ""
+
+msgid "Source branch: %{source_branch_open}%{source_branch}%{source_branch_close}"
+msgstr ""
+
msgid "Source code"
msgstr ""
@@ -23900,9 +24776,6 @@ msgstr ""
msgid "Start and due date"
msgstr ""
-msgid "Start by choosing a group to see how your team is spending time. You can then drill down to the project level."
-msgstr ""
-
msgid "Start by choosing a group to start exploring the merge requests in that group. You can then proceed to filter by projects, labels, milestones and authors."
msgstr ""
@@ -23984,18 +24857,27 @@ msgstr ""
msgid "StaticSiteEditor|3. Assign a person to review and accept the merge request."
msgstr ""
+msgid "StaticSiteEditor|A link to view the merge request will appear once ready."
+msgstr ""
+
msgid "StaticSiteEditor|An error occurred while submitting your changes."
msgstr ""
msgid "StaticSiteEditor|Branch could not be created."
msgstr ""
+msgid "StaticSiteEditor|Copy update"
+msgstr ""
+
msgid "StaticSiteEditor|Could not commit the content changes."
msgstr ""
msgid "StaticSiteEditor|Could not create merge request."
msgstr ""
+msgid "StaticSiteEditor|Creating your merge request"
+msgstr ""
+
msgid "StaticSiteEditor|Incompatible file content"
msgstr ""
@@ -24017,6 +24899,9 @@ msgstr ""
msgid "StaticSiteEditor|View documentation"
msgstr ""
+msgid "StaticSiteEditor|You can set an assignee to get your changes reviewed and deployed once your merge request is created."
+msgstr ""
+
msgid "StaticSiteEditor|Your merge request has been created"
msgstr ""
@@ -24146,15 +25031,15 @@ msgstr ""
msgid "Submit %{humanized_resource_name}"
msgstr ""
-msgid "Submit Changes"
-msgstr ""
-
msgid "Submit a review"
msgstr ""
msgid "Submit as spam"
msgstr ""
+msgid "Submit changes"
+msgstr ""
+
msgid "Submit feedback"
msgstr ""
@@ -24308,6 +25193,9 @@ msgstr ""
msgid "Successfully deleted U2F device."
msgstr ""
+msgid "Successfully deleted WebAuthn device."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -24626,9 +25514,6 @@ msgstr ""
msgid "Template to append to all Service Desk issues"
msgstr ""
-msgid "Template was successfully saved."
-msgstr ""
-
msgid "Templates"
msgstr ""
@@ -24713,10 +25598,28 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "Test failed."
+msgid "Test settings"
+msgstr ""
+
+msgid "TestCases|New Test Case"
+msgstr ""
+
+msgid "TestCases|New test case"
+msgstr ""
+
+msgid "TestCases|Search test cases"
+msgstr ""
+
+msgid "TestCases|Something went wrong while creating a test case."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching count of test cases."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching test cases list."
msgstr ""
-msgid "Test settings and save changes"
+msgid "TestCases|Submit test case"
msgstr ""
msgid "TestHooks|Ensure one of your projects has merge requests."
@@ -24782,6 +25685,9 @@ msgstr ""
msgid "Thank you for signing up for your free trial! You will get additional instructions in your inbox shortly."
msgstr ""
+msgid "Thank you for your business."
+msgstr ""
+
msgid "Thank you for your feedback!"
msgstr ""
@@ -24843,9 +25749,6 @@ msgstr ""
msgid "The URL to use for connecting to Elasticsearch. Use a comma-separated list to support clustering (e.g., \"http://localhost:9200, http://localhost:9201\")."
msgstr ""
-msgid "The Web IDE offers advanced syntax highlighting capabilities and more."
-msgstr ""
-
msgid "The X509 Certificate to use when mutual TLS is required to communicate with the external authorization service. If left blank, the server certificate is still validated when accessing over HTTPS."
msgstr ""
@@ -24958,6 +25861,9 @@ msgstr ""
msgid "The form contains the following error:"
msgstr ""
+msgid "The form contains the following warning:"
+msgstr ""
+
msgid "The global settings require you to enable Two-Factor Authentication for your account."
msgstr ""
@@ -25072,9 +25978,6 @@ msgstr ""
msgid "The private key to use when a client certificate is provided. This value is encrypted at rest."
msgstr ""
-msgid "The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The project can be accessed by any logged in user."
msgstr ""
@@ -25111,7 +26014,7 @@ msgstr ""
msgid "The remote repository is being updated..."
msgstr ""
-msgid "The repository can be commited to, and issues, comments and other entities can be created."
+msgid "The repository can be committed to, and issues, comments and other entities can be created."
msgstr ""
msgid "The repository for this project does not exist."
@@ -25165,9 +26068,6 @@ msgstr ""
msgid "The time taken by each data entry gathered by that stage."
msgstr ""
-msgid "The total stage shows the time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The update action will time out after %{number_of_minutes} minutes. For big repositories, use a clone/push combination."
msgstr ""
@@ -25231,6 +26131,9 @@ msgstr ""
msgid "There are no archived requirements"
msgstr ""
+msgid "There are no archived test cases"
+msgstr ""
+
msgid "There are no changes"
msgstr ""
@@ -25270,6 +26173,9 @@ msgstr ""
msgid "There are no open requirements"
msgstr ""
+msgid "There are no open test cases"
+msgstr ""
+
msgid "There are no packages yet"
msgstr ""
@@ -25282,6 +26188,9 @@ msgstr ""
msgid "There is a limit of %{ci_project_subscriptions_limit} subscriptions from or to a project."
msgstr ""
+msgid "There is already a To-Do for this design."
+msgstr ""
+
msgid "There is already a repository with that name on disk"
msgstr ""
@@ -25300,6 +26209,9 @@ msgstr ""
msgid "There was a problem communicating with your device."
msgstr ""
+msgid "There was a problem fetching branches."
+msgstr ""
+
msgid "There was a problem fetching groups."
msgstr ""
@@ -25528,9 +26440,15 @@ msgstr ""
msgid "This action can lead to data loss. To prevent accidental actions we ask you to confirm your intention."
msgstr ""
+msgid "This action cannot be undone, and will permanently delete the %{key} SSH key"
+msgstr ""
+
msgid "This action cannot be undone. You will lose the project's repository and all content: issues, merge requests, etc."
msgstr ""
+msgid "This action has been performed too many times. Try again later."
+msgstr ""
+
msgid "This action will %{strongOpen}permanently delete%{strongClose} %{codeOpen}%{project}%{codeClose} %{strongOpen}immediately%{strongClose}, including its repositories and all content: issues, merge requests, etc."
msgstr ""
@@ -25558,9 +26476,6 @@ msgstr ""
msgid "This board's scope is reduced"
msgstr ""
-msgid "This branch has changed since you started editing. Would you like to create a new branch?"
-msgstr ""
-
msgid "This chart could not be displayed"
msgstr ""
@@ -25687,15 +26602,9 @@ msgstr ""
msgid "This is a security log of important events involving your account."
msgstr ""
-msgid "This is the author's first Merge Request to this project."
-msgstr ""
-
msgid "This is the highest peak of users on your installation since the license started."
msgstr ""
-msgid "This is the maximum number of users that have existed at the same time since the license started. This is the minimum number of seats you will need to buy when you renew your license."
-msgstr ""
-
msgid "This is the number of currently active users on your installation, and this is the minimum number you need to purchase when you renew your license."
msgstr ""
@@ -25927,6 +26836,15 @@ msgstr ""
msgid "This user has no identities"
msgstr ""
+msgid "This user has previously committed to the %{name} project."
+msgstr ""
+
+msgid "This user has the %{access} role in the %{name} project."
+msgstr ""
+
+msgid "This user is the author of this %{noteable}."
+msgstr ""
+
msgid "This user will be the author of all events in the activity feed that are the result of an update, like new branches being created or new commits being pushed to existing branches."
msgstr ""
@@ -25957,6 +26875,9 @@ msgstr ""
msgid "Threat Monitoring"
msgstr ""
+msgid "ThreatMonitoring|All Environments"
+msgstr ""
+
msgid "ThreatMonitoring|Anomalous Requests"
msgstr ""
@@ -25984,9 +26905,6 @@ msgstr ""
msgid "ThreatMonitoring|Operations Per Second"
msgstr ""
-msgid "ThreatMonitoring|Overview"
-msgstr ""
-
msgid "ThreatMonitoring|Packet Activity"
msgstr ""
@@ -26005,6 +26923,9 @@ msgstr ""
msgid "ThreatMonitoring|Something went wrong, unable to fetch statistics"
msgstr ""
+msgid "ThreatMonitoring|Statistics"
+msgstr ""
+
msgid "ThreatMonitoring|The firewall is not installed or has been disabled. To view this data, ensure the web application firewall is installed and enabled for your cluster."
msgstr ""
@@ -26400,6 +27321,9 @@ msgstr ""
msgid "To update Snippets with multiple files, you must use the `files` parameter"
msgstr ""
+msgid "To use Gitpod you must first enable the feature in the integrations section of your %{user_prefs}."
+msgstr ""
+
msgid "To view all %{scannedResourcesCount} scanned URLs, please download the CSV file"
msgstr ""
@@ -26433,9 +27357,6 @@ msgstr ""
msgid "Toggle Sidebar"
msgstr ""
-msgid "Toggle all threads"
-msgstr ""
-
msgid "Toggle backtrace"
msgstr ""
@@ -26460,9 +27381,6 @@ msgstr ""
msgid "Toggle navigation"
msgstr ""
-msgid "Toggle project"
-msgstr ""
-
msgid "Toggle sidebar"
msgstr ""
@@ -26502,6 +27420,9 @@ msgstr ""
msgid "Too many projects enabled. You will need to manage them via the console or the API."
msgstr ""
+msgid "Too much data"
+msgstr ""
+
msgid "Topics (optional)"
msgstr ""
@@ -26520,6 +27441,9 @@ msgstr ""
msgid "Total cores (CPUs)"
msgstr ""
+msgid "Total days to completion"
+msgstr ""
+
msgid "Total issues"
msgstr ""
@@ -26616,6 +27540,9 @@ msgstr ""
msgid "Trending"
msgstr ""
+msgid "Trials|Create a new group to start your GitLab Gold trial."
+msgstr ""
+
msgid "Trials|Go back to GitLab"
msgstr ""
@@ -26625,6 +27552,15 @@ msgstr ""
msgid "Trials|You can always resume this process by selecting your avatar and choosing 'Start a Gold trial'"
msgstr ""
+msgid "Trials|You can apply your trial to a new group or an existing group."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group or your personal account."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group, an existing group, or your personal account."
+msgstr ""
+
msgid "Trials|You won't get a free trial right now but you can always resume this process by clicking on your avatar and choosing 'Start a free trial'"
msgstr ""
@@ -26694,6 +27630,9 @@ msgstr ""
msgid "Try using a different search term to find the file you are looking for."
msgstr ""
+msgid "Trying to communicate with your device. Plug it in (if needed) and press the button on the device now."
+msgstr ""
+
msgid "Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now."
msgstr ""
@@ -26781,6 +27720,12 @@ msgstr ""
msgid "URL or request ID"
msgstr ""
+msgid "USER %{user} WILL BE REMOVED! Are you sure?"
+msgstr ""
+
+msgid "USER WILL BE BLOCKED! Are you sure?"
+msgstr ""
+
msgid "UTC"
msgstr ""
@@ -26838,9 +27783,6 @@ msgstr ""
msgid "Unable to load the merge request widget. Try reloading the page."
msgstr ""
-msgid "Unable to resolve"
-msgstr ""
-
msgid "Unable to save iteration. Please try again"
msgstr ""
@@ -26889,6 +27831,9 @@ msgstr ""
msgid "Undo ignore"
msgstr ""
+msgid "Unexpected error"
+msgstr ""
+
msgid "Unfortunately, your email message to GitLab could not be processed."
msgstr ""
@@ -26922,6 +27867,9 @@ msgstr ""
msgid "Unknown response text"
msgstr ""
+msgid "Unless otherwise agreed to in writing with GitLab, by clicking \"Upload License\" you agree that your use of GitLab Software is subject to the %{eula_link_start}Terms of Service%{eula_link_end}."
+msgstr ""
+
msgid "Unlimited"
msgstr ""
@@ -27288,9 +28236,6 @@ msgstr ""
msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
msgstr ""
-msgid "Use a hardware device to add the second factor of authentication."
-msgstr ""
-
msgid "Use an one time password authenticator on your mobile device or computer to enable two-factor authentication (2FA)."
msgstr ""
@@ -27564,13 +28509,13 @@ msgstr ""
msgid "Users"
msgstr ""
-msgid "Users in License:"
+msgid "Users in License"
msgstr ""
-msgid "Users or groups set as approvers in the project's or merge request's settings."
+msgid "Users in License:"
msgstr ""
-msgid "Users outside of license"
+msgid "Users or groups set as approvers in the project's or merge request's settings."
msgstr ""
msgid "Users over License:"
@@ -27588,9 +28533,6 @@ msgstr ""
msgid "Users with a Guest role or those who don't belong to a Project or Group will not use a seat from your license."
msgstr ""
-msgid "Users with a Guest role or those who don't belong to any projects or groups don't count towards seats in use."
-msgstr ""
-
msgid "UsersSelect|%{name} + %{length} more"
msgstr ""
@@ -27630,9 +28572,6 @@ msgstr ""
msgid "Validations failed."
msgstr ""
-msgid "Validity"
-msgstr ""
-
msgid "Value"
msgstr ""
@@ -27651,6 +28590,9 @@ msgstr ""
msgid "Value Stream Name"
msgstr ""
+msgid "ValueStreamAnalyticsStage|We don't have enough data to show this stage."
+msgstr ""
+
msgid "ValueStreamAnalytics|%{days}d"
msgstr ""
@@ -27911,6 +28853,9 @@ msgstr ""
msgid "VisualReviewApp|Steps 1 and 2 (and sometimes 3) are performed once by the developer before requesting feedback. Steps 3 (if necessary), 4 is performed by the reviewer each time they perform a review."
msgstr ""
+msgid "Visualization"
+msgstr ""
+
msgid "Vulnerabilities"
msgstr ""
@@ -27938,34 +28883,31 @@ msgstr ""
msgid "VulnerabilityChart|Severity"
msgstr ""
-msgid "VulnerabilityManagement|A true-positive and will fix"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Change status"
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|Confirm"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Confirmed %{timeago} by %{user}"
-msgstr ""
-
-msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Detected %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|A true-positive and will fix"
msgstr ""
-msgid "VulnerabilityManagement|Dismiss"
+msgid "VulnerabilityManagement|Change status"
msgstr ""
-msgid "VulnerabilityManagement|Dismissed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
msgstr ""
-msgid "VulnerabilityManagement|Resolved"
+msgid "VulnerabilityManagement|Detected"
msgstr ""
-msgid "VulnerabilityManagement|Resolved %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Needs triage"
msgstr ""
msgid "VulnerabilityManagement|Something went wrong while trying to delete the comment. Please try again later."
@@ -28016,6 +28958,9 @@ msgstr ""
msgid "Vulnerability|%{scannerName} (version %{scannerVersion})"
msgstr ""
+msgid "Vulnerability|Activity"
+msgstr ""
+
msgid "Vulnerability|Class"
msgstr ""
@@ -28028,6 +28973,9 @@ msgstr ""
msgid "Vulnerability|Description"
msgstr ""
+msgid "Vulnerability|Detected"
+msgstr ""
+
msgid "Vulnerability|Evidence"
msgstr ""
@@ -28091,6 +29039,9 @@ msgstr ""
msgid "Warning: Displaying this diagram might cause performance issues on this page."
msgstr ""
+msgid "We are currently unable to fetch data for the pipeline header."
+msgstr ""
+
msgid "We are currently unable to fetch data for this graph."
msgstr ""
@@ -28130,6 +29081,12 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
+msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
+msgstr ""
+
+msgid "We would like to inform you that your subscription GitLab Enterprise Edition %{plan_name} is nearing its user limit. You have %{active_user_count} active users, which is almost at the user limit of %{maximum_user_count}."
+msgstr ""
+
msgid "We've found no vulnerabilities"
msgstr ""
@@ -28145,6 +29102,12 @@ msgstr ""
msgid "Web terminal"
msgstr ""
+msgid "WebAuthn Devices (%{length})"
+msgstr ""
+
+msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
+msgstr ""
+
msgid "WebIDE|Merge request"
msgstr ""
@@ -28283,15 +29246,9 @@ msgstr ""
msgid "Welcome to the guided GitLab tour"
msgstr ""
-msgid "Welcome to your Issue Board!"
-msgstr ""
-
msgid "Welcome to your issue board!"
msgstr ""
-msgid "We’ve been making changes to %{featureName} and we’d love your feedback %{linkStart}in this issue%{linkEnd} to help us improve the experience."
-msgstr ""
-
msgid "What are you searching for?"
msgstr ""
@@ -28310,6 +29267,9 @@ msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
msgstr ""
+msgid "When enabled, any user visiting %{host} and creating an account will have to be explicitly approved by the admin before they can login. This setting is effective only if sign-ups are enabled."
+msgstr ""
+
msgid "When enabled, any user visiting %{host} will be able to create an account."
msgstr ""
@@ -28536,6 +29496,9 @@ msgstr ""
msgid "With requirements, you can set criteria to check your products against."
msgstr ""
+msgid "With test cases, you can define conditions for your project to meet in determining quality"
+msgstr ""
+
msgid "Withdraw Access Request"
msgstr ""
@@ -28551,6 +29514,9 @@ msgstr ""
msgid "Workflow Help"
msgstr ""
+msgid "Would you like to create a new branch?"
+msgstr ""
+
msgid "Write"
msgstr ""
@@ -28572,6 +29538,9 @@ msgstr ""
msgid "Wrong extern UID provided. Make sure Auth0 is configured correctly."
msgstr ""
+msgid "YYYY-MM-DD"
+msgstr ""
+
msgid "Yes"
msgstr ""
@@ -28629,7 +29598,7 @@ msgstr ""
msgid "You are going to remove the fork relationship from %{project_full_name}. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "You are going to transfer %{project_full_name} to another owner. Are you ABSOLUTELY sure?"
+msgid "You are going to transfer %{project_full_name} to another namespace. Are you ABSOLUTELY sure?"
msgstr ""
msgid "You are going to turn off the confidentiality. This means %{strongStart}everyone%{strongEnd} will be able to see and leave a comment on this %{issuableType}."
@@ -28689,9 +29658,6 @@ msgstr ""
msgid "You can always edit this later"
msgstr ""
-msgid "You can apply your Trial to your Personal account or create a New Group."
-msgstr ""
-
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings"
msgstr ""
@@ -28713,12 +29679,18 @@ msgstr ""
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
+msgid "You can find more information about GitLab subscriptions in %{subscriptions_doc_link}."
+msgstr ""
+
msgid "You can generate an access token scoped to this project for each application to use the GitLab API."
msgstr ""
msgid "You can get started by cloning the repository or start adding files to it with one of the following options."
msgstr ""
+msgid "You can group test cases using labels. To learn about the future direction of this feature, visit %{linkStart}Quality Management direction page%{linkEnd}."
+msgstr ""
+
msgid "You can invite a new member to %{project_name} or invite another group."
msgstr ""
@@ -28734,6 +29706,9 @@ msgstr ""
msgid "You can notify the app / group or a project by sending them an email notification"
msgstr ""
+msgid "You can now close this window."
+msgstr ""
+
msgid "You can now export your security dashboard to a CSV report."
msgstr ""
@@ -28782,9 +29757,6 @@ msgstr ""
msgid "You can test your .gitlab-ci.yml in %{linkStart}CI Lint%{linkEnd}."
msgstr ""
-msgid "You can try again using %{begin_link}basic search%{end_link}"
-msgstr ""
-
msgid "You cannot access the raw file. Please wait a minute."
msgstr ""
@@ -28836,6 +29808,9 @@ msgstr ""
msgid "You don't have any U2F devices registered yet."
msgstr ""
+msgid "You don't have any WebAuthn devices registered yet."
+msgstr ""
+
msgid "You don't have any active chat names."
msgstr ""
@@ -28923,6 +29898,9 @@ msgstr ""
msgid "You must accept our Terms of Service and privacy policy in order to register an account"
msgstr ""
+msgid "You must be logged in to search across all of GitLab"
+msgstr ""
+
msgid "You must disassociate %{domain} from all clusters it is attached to before deletion."
msgstr ""
@@ -28962,7 +29940,7 @@ msgstr ""
msgid "You need to be logged in."
msgstr ""
-msgid "You need to register a two-factor authentication app before you can set up a U2F device."
+msgid "You need to register a two-factor authentication app before you can set up a device."
msgstr ""
msgid "You need to set terms to be enforced"
@@ -28980,6 +29958,9 @@ msgstr ""
msgid "You reached %{usage_in_percent} of %{namespace_name}'s storage capacity (%{used_storage} of %{storage_limit})"
msgstr ""
+msgid "You successfully declined the invitation"
+msgstr ""
+
msgid "You tried to fork %{link_to_the_project} but it failed for the following reason:"
msgstr ""
@@ -29145,10 +30126,13 @@ msgstr ""
msgid "Your U2F device did not send a valid JSON response."
msgstr ""
-msgid "Your U2F device needs to be set up. Plug it in (if not already) and click the button on the left."
+msgid "Your U2F device was registered!"
msgstr ""
-msgid "Your U2F device was registered!"
+msgid "Your WebAuthn device did not send a valid JSON response."
+msgstr ""
+
+msgid "Your WebAuthn device was registered!"
msgstr ""
msgid "Your access request to the %{source_type} has been withdrawn."
@@ -29172,6 +30156,9 @@ msgstr ""
msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
msgstr ""
+msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
+msgstr ""
+
msgid "Your changes can be committed to %{branch_name} because a merge request is open."
msgstr ""
@@ -29208,6 +30195,12 @@ msgstr ""
msgid "Your deployment services will be broken, you will need to manually fix the services after renaming."
msgstr ""
+msgid "Your device is not compatible with GitLab. Please try another device"
+msgstr ""
+
+msgid "Your device needs to be set up. Plug it in (if needed) and click the button on the left."
+msgstr ""
+
msgid "Your device was successfully set up! Give it a name and register it with the GitLab server."
msgstr ""
@@ -29323,9 +30316,6 @@ msgstr[3] ""
msgid "access:"
msgstr ""
-msgid "activated"
-msgstr ""
-
msgid "added %{created_at_timeago}"
msgstr ""
@@ -29398,9 +30388,21 @@ msgstr ""
msgid "by %{user}"
msgstr ""
+msgid "cannot be a date in the past"
+msgstr ""
+
msgid "cannot be changed if a personal project has container registry tags."
msgstr ""
+msgid "cannot be changed if shared runners are enabled"
+msgstr ""
+
+msgid "cannot be enabled because parent group does not allow it"
+msgstr ""
+
+msgid "cannot be enabled because parent group has shared Runners disabled"
+msgstr ""
+
msgid "cannot be enabled unless all domains have TLS certificates"
msgstr ""
@@ -29446,7 +30448,7 @@ msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about SAST %{linkEndTag}"
msgstr ""
-msgid "ciReport|%{linkStartTag}Learn more about Secret Scanning %{linkEndTag}"
+msgid "ciReport|%{linkStartTag}Learn more about Secret Detection %{linkEndTag}"
msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about codequality reports %{linkEndTag}"
@@ -29767,9 +30769,6 @@ msgstr ""
msgid "error"
msgstr ""
-msgid "error code:"
-msgstr ""
-
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr ""
@@ -29791,6 +30790,9 @@ msgstr ""
msgid "failed to dismiss associated finding(id=%{finding_id}): %{message}"
msgstr ""
+msgid "failed to revert associated finding(id=%{finding_id}) to detected"
+msgstr ""
+
msgid "file"
msgid_plural "files"
msgstr[0] ""
@@ -30341,6 +31343,9 @@ msgstr ""
msgid "must be a root namespace"
msgstr ""
+msgid "must be a valid IPv4 or IPv6 address"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -30377,6 +31382,9 @@ msgstr ""
msgid "no expiration"
msgstr ""
+msgid "no name set"
+msgstr ""
+
msgid "no one can merge"
msgstr ""
@@ -30565,9 +31573,6 @@ msgstr ""
msgid "security Reports|There was an error creating the merge request"
msgstr ""
-msgid "settings saved, but not activated"
-msgstr ""
-
msgid "severity|Critical"
msgstr ""
@@ -30694,9 +31699,6 @@ msgstr ""
msgid "toggle collapse"
msgstr ""
-msgid "toggle dropdown"
-msgstr ""
-
msgid "triggered"
msgstr ""
@@ -30724,6 +31726,9 @@ msgstr ""
msgid "user avatar"
msgstr ""
+msgid "user preferences"
+msgstr ""
+
msgid "username"
msgstr ""
diff --git a/locale/hi_IN/gitlab.po b/locale/hi_IN/gitlab.po
index bc24877a3b1..a0a439ef7ff 100644
--- a/locale/hi_IN/gitlab.po
+++ b/locale/hi_IN/gitlab.po
@@ -14,7 +14,10 @@ msgstr ""
"X-Crowdin-Language: hi\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 6\n"
-"PO-Revision-Date: 2020-09-04 23:03\n"
+"PO-Revision-Date: 2020-10-02 18:42\n"
+
+msgid " %{project_name}#%{issue_iid} &middot; opened %{issue_created} by %{author}"
+msgstr ""
msgid " %{start} to %{end}"
msgstr ""
@@ -74,6 +77,16 @@ msgstr ""
msgid "\"el\" parameter is required for createInstance()"
msgstr ""
+msgid "%d Approval"
+msgid_plural "%d Approvals"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d Package"
+msgid_plural "%d Packages"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d Scanned URL"
msgid_plural "%d Scanned URLs"
msgstr[0] ""
@@ -137,6 +150,11 @@ msgstr[1] ""
msgid "%d commits"
msgstr ""
+msgid "%d completed issue"
+msgid_plural "%d completed issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d contribution"
msgid_plural "%d contributions"
msgstr[0] ""
@@ -147,6 +165,11 @@ msgid_plural "%d days"
msgstr[0] ""
msgstr[1] ""
+msgid "%d day until tags are automatically removed"
+msgid_plural "%d days until tags are automatically removed"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d error"
msgid_plural "%d errors"
msgstr[0] ""
@@ -237,6 +260,16 @@ msgid_plural "%d more comments"
msgstr[0] ""
msgstr[1] ""
+msgid "%d open issue"
+msgid_plural "%d open issues"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d pending comment"
+msgid_plural "%d pending comments"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d personal project will be removed and cannot be restored."
msgid_plural "%d personal projects will be removed and cannot be restored."
msgstr[0] ""
@@ -252,6 +285,11 @@ msgid_plural "%d projects"
msgstr[0] ""
msgstr[1] ""
+msgid "%d project selected"
+msgid_plural "%d projects selected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d request with warnings"
msgid_plural "%d requests with warnings"
msgstr[0] ""
@@ -272,6 +310,11 @@ msgid_plural "%d tags"
msgstr[0] ""
msgstr[1] ""
+msgid "%d tag per image name"
+msgid_plural "%d tags per image name"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d unassigned issue"
msgid_plural "%d unassigned issues"
msgstr[0] ""
@@ -292,6 +335,11 @@ msgid_plural "%d vulnerabilities dismissed"
msgstr[0] ""
msgstr[1] ""
+msgid "%d warning found:"
+msgid_plural "%d warnings found:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%s additional commit has been omitted to prevent performance issues."
msgid_plural "%s additional commits have been omitted to prevent performance issues."
msgstr[0] ""
@@ -330,6 +378,9 @@ msgstr ""
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr ""
+msgid "%{completedCount} completed weight"
+msgstr ""
+
msgid "%{completedWeight} of %{totalWeight} weight completed"
msgstr ""
@@ -378,14 +429,12 @@ msgid_plural "%{count} participants"
msgstr[0] ""
msgstr[1] ""
-msgid "%{count} pending comment"
-msgid_plural "%{count} pending comments"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
+msgid "%{count} total weight"
+msgstr ""
+
msgid "%{dashboard_path} could not be found."
msgstr ""
@@ -440,6 +489,9 @@ msgstr ""
msgid "%{group_name} uses group managed accounts. You need to create a new GitLab account which will be managed by %{group_name}."
msgstr ""
+msgid "%{group_name}&%{epic_iid} &middot; opened %{epic_created} by %{author}"
+msgstr ""
+
msgid "%{host} sign-in from new location"
msgstr ""
@@ -452,7 +504,7 @@ msgstr ""
msgid "%{issuableType} will be removed! Are you sure?"
msgstr ""
-msgid "%{issuesSize} issues with a limit of %{maxIssueCount}"
+msgid "%{issuesCount} issues with a limit of %{maxIssueCount}"
msgstr ""
msgid "%{issuesSize} with a limit of %{maxIssueCount}"
@@ -485,7 +537,7 @@ msgstr ""
msgid "%{labelStart}Namespace:%{labelEnd} %{namespace}"
msgstr ""
-msgid "%{labelStart}Report Type:%{labelEnd} %{reportType}"
+msgid "%{labelStart}Scan Type:%{labelEnd} %{reportType}"
msgstr ""
msgid "%{labelStart}Scanner:%{labelEnd} %{scanner}"
@@ -682,9 +734,6 @@ msgid_plural "%{securityScanner} results are not available because a pipeline ha
msgstr[0] ""
msgstr[1] ""
-msgid "%{service_title} %{message}."
-msgstr ""
-
msgid "%{size} GiB"
msgstr ""
@@ -773,6 +822,12 @@ msgstr ""
msgid "%{timebox_name} should belong either to a project or a group."
msgstr ""
+msgid "%{timebox_type} does not support burnup charts"
+msgstr ""
+
+msgid "%{timebox_type} must have a start and due date"
+msgstr ""
+
msgid "%{title} %{operator} %{threshold}"
msgstr ""
@@ -797,7 +852,7 @@ msgstr ""
msgid "%{total} open issue weight"
msgstr ""
-msgid "%{total} open issues"
+msgid "%{total} warnings found: showing first %{warningsDisplayed}"
msgstr ""
msgid "%{usage_ping_link_start}Learn more%{usage_ping_link_end} about what information is shared with GitLab Inc."
@@ -830,9 +885,6 @@ msgstr ""
msgid "&lt; 1 hour"
msgstr ""
-msgid "&lt;no name set&gt;"
-msgstr ""
-
msgid "&lt;no scopes selected&gt;"
msgstr ""
@@ -863,6 +915,9 @@ msgstr ""
msgid "'%{name}' Value Stream created"
msgstr ""
+msgid "'%{name}' Value Stream deleted"
+msgstr ""
+
msgid "'%{name}' stage already exists"
msgstr ""
@@ -922,6 +977,9 @@ msgstr ""
msgid "+ %{numberOfHiddenAssignees} more"
msgstr ""
+msgid "+ %{numberOfHiddenReviewers} more"
+msgstr ""
+
msgid "+%d more"
msgid_plural "+%d more"
msgstr[0] ""
@@ -982,6 +1040,11 @@ msgid_plural "%d Days"
msgstr[0] ""
msgstr[1] ""
+msgid "1 Issue"
+msgid_plural "%d Issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "1 closed issue"
msgid_plural "%{issues} closed issues"
msgstr[0] ""
@@ -997,6 +1060,11 @@ msgid_plural "%d days"
msgstr[0] ""
msgstr[1] ""
+msgid "1 deploy key"
+msgid_plural "%d deploy keys"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1099,6 +1167,9 @@ msgstr ""
msgid ":%{startLine} to %{endLine}"
msgstr ""
+msgid "A %{incident_docs_start}modified issue%{incident_docs_end} to guide the resolution of incidents."
+msgstr ""
+
msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr ""
@@ -1111,6 +1182,9 @@ msgstr ""
msgid "A GitBook site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
+msgid "A Gitpod configured Webapplication in Spring and Java"
+msgstr ""
+
msgid "A Hexo site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
@@ -1282,9 +1356,15 @@ msgstr ""
msgid "Access expiration date"
msgstr ""
+msgid "Access expires"
+msgstr ""
+
msgid "Access forbidden. Check your access level."
msgstr ""
+msgid "Access granted"
+msgstr ""
+
msgid "Access requests"
msgstr ""
@@ -1294,6 +1374,9 @@ msgstr ""
msgid "Access to Pages websites are controlled based on the user's membership to a given project. By checking this box, users will be required to be logged in to have access to all Pages websites in your instance."
msgstr ""
+msgid "AccessDropdown|Deploy Keys"
+msgstr ""
+
msgid "AccessDropdown|Groups"
msgstr ""
@@ -1411,12 +1494,6 @@ msgstr ""
msgid "Active Sessions"
msgstr ""
-msgid "Active Users:"
-msgstr ""
-
-msgid "Active users"
-msgstr ""
-
msgid "Activity"
msgstr ""
@@ -1584,9 +1661,6 @@ msgstr ""
msgid "Add label(s)"
msgstr ""
-msgid "Add license"
-msgstr ""
-
msgid "Add list"
msgstr ""
@@ -1761,21 +1835,51 @@ msgstr ""
msgid "AdminArea|Bots"
msgstr ""
+msgid "AdminArea|Components"
+msgstr ""
+
msgid "AdminArea|Developer"
msgstr ""
+msgid "AdminArea|Features"
+msgstr ""
+
+msgid "AdminArea|Groups: %{number_of_groups}"
+msgstr ""
+
msgid "AdminArea|Guest"
msgstr ""
msgid "AdminArea|Included Free in license"
msgstr ""
+msgid "AdminArea|Latest groups"
+msgstr ""
+
+msgid "AdminArea|Latest projects"
+msgstr ""
+
+msgid "AdminArea|Latest users"
+msgstr ""
+
msgid "AdminArea|Maintainer"
msgstr ""
+msgid "AdminArea|New group"
+msgstr ""
+
+msgid "AdminArea|New project"
+msgstr ""
+
+msgid "AdminArea|New user"
+msgstr ""
+
msgid "AdminArea|Owner"
msgstr ""
+msgid "AdminArea|Projects: %{number_of_projects}"
+msgstr ""
+
msgid "AdminArea|Reporter"
msgstr ""
@@ -1803,6 +1907,9 @@ msgstr ""
msgid "AdminArea|Users without a Group and Project"
msgstr ""
+msgid "AdminArea|Users: %{number_of_users}"
+msgstr ""
+
msgid "AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running."
msgstr ""
@@ -1821,9 +1928,6 @@ msgstr ""
msgid "AdminProjects|Delete Project %{projectName}?"
msgstr ""
-msgid "AdminProjects|Delete project"
-msgstr ""
-
msgid "AdminSettings|Apply integration settings to all Projects"
msgstr ""
@@ -2061,21 +2165,30 @@ msgstr ""
msgid "AdminUsers|Without projects"
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 ""
msgid "AdminUsers|You cannot remove your own admin rights."
msgstr ""
+msgid "AdminUsers|You must transfer ownership or delete the groups owned by this user before you can delete their account"
+msgstr ""
+
msgid "Administration"
msgstr ""
msgid "Advanced"
msgstr ""
+msgid "Advanced Search"
+msgstr ""
+
+msgid "Advanced Search with Elasticsearch"
+msgstr ""
+
msgid "Advanced Settings"
msgstr ""
@@ -2153,6 +2266,9 @@ msgstr ""
msgid "AlertManagement|Edit"
msgstr ""
+msgid "AlertManagement|Environment"
+msgstr ""
+
msgid "AlertManagement|Events"
msgstr ""
@@ -2165,6 +2281,9 @@ msgstr ""
msgid "AlertManagement|Issue"
msgstr ""
+msgid "AlertManagement|Key"
+msgstr ""
+
msgid "AlertManagement|Low"
msgstr ""
@@ -2258,6 +2377,9 @@ msgstr ""
msgid "AlertManagement|Unknown"
msgstr ""
+msgid "AlertManagement|Value"
+msgstr ""
+
msgid "AlertManagement|View alerts in Opsgenie"
msgstr ""
@@ -2417,6 +2539,9 @@ msgstr ""
msgid "All projects"
msgstr ""
+msgid "All projects selected"
+msgstr ""
+
msgid "All security scans are enabled because %{linkStart}Auto DevOps%{linkEnd} is enabled on this project"
msgstr ""
@@ -2504,6 +2629,9 @@ msgstr ""
msgid "Almost there"
msgstr ""
+msgid "Already blocked"
+msgstr ""
+
msgid "Also called \"Issuer\" or \"Relying party trust identifier\""
msgstr ""
@@ -2558,6 +2686,9 @@ msgstr ""
msgid "An error has occurred"
msgstr ""
+msgid "An error occured while making the changes: %{error}"
+msgstr ""
+
msgid "An error occurred adding a draft to the thread."
msgstr ""
@@ -2585,12 +2716,6 @@ msgstr ""
msgid "An error occurred when toggling the notification subscription"
msgstr ""
-msgid "An error occurred when trying to resolve a comment. Please try again."
-msgstr ""
-
-msgid "An error occurred when trying to resolve a discussion. Please try again."
-msgstr ""
-
msgid "An error occurred when updating the issue weight"
msgstr ""
@@ -2606,12 +2731,6 @@ msgstr ""
msgid "An error occurred while checking group path. Please refresh and try again."
msgstr ""
-msgid "An error occurred while committing your changes."
-msgstr ""
-
-msgid "An error occurred while creating the list. Please try again."
-msgstr ""
-
msgid "An error occurred while decoding the file."
msgstr ""
@@ -2684,25 +2803,19 @@ msgstr ""
msgid "An error occurred while fetching the Service Desk address."
msgstr ""
-msgid "An error occurred while fetching the board issues. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the board lists. Please reload the page."
msgstr ""
msgid "An error occurred while fetching the board lists. Please try again."
msgstr ""
-msgid "An error occurred while fetching the board swimlanes. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the builds."
msgstr ""
msgid "An error occurred while fetching the job log."
msgstr ""
-msgid "An error occurred while fetching the job trace."
+msgid "An error occurred while fetching the job logs."
msgstr ""
msgid "An error occurred while fetching the job."
@@ -2849,9 +2962,6 @@ msgstr ""
msgid "An error occurred while saving assignees"
msgstr ""
-msgid "An error occurred while saving the template. Please check if the template exists."
-msgstr ""
-
msgid "An error occurred while searching for milestones"
msgstr ""
@@ -2870,10 +2980,10 @@ msgstr ""
msgid "An error occurred while updating approvers"
msgstr ""
-msgid "An error occurred while updating the comment"
+msgid "An error occurred while updating labels."
msgstr ""
-msgid "An error occurred while updating the list. Please try again."
+msgid "An error occurred while updating the comment"
msgstr ""
msgid "An error occurred while validating group path"
@@ -2927,6 +3037,9 @@ msgstr ""
msgid "An unknown error occurred while loading this graph."
msgstr ""
+msgid "An unknown error occurred."
+msgstr ""
+
msgid "Analytics"
msgstr ""
@@ -2960,10 +3073,10 @@ msgstr ""
msgid "Any"
msgstr ""
-msgid "Any Author"
+msgid "Any %{header}"
msgstr ""
-msgid "Any Status"
+msgid "Any Author"
msgstr ""
msgid "Any branch"
@@ -3017,6 +3130,9 @@ msgstr ""
msgid "Application ID"
msgstr ""
+msgid "Application limits saved successfully"
+msgstr ""
+
msgid "Application settings saved successfully"
msgstr ""
@@ -3226,6 +3342,9 @@ msgstr ""
msgid "Are you sure you want to close this blocked issue?"
msgstr ""
+msgid "Are you sure you want to delete \"%{name}\" Value Stream?"
+msgstr ""
+
msgid "Are you sure you want to delete %{name}?"
msgstr ""
@@ -3235,6 +3354,9 @@ msgstr ""
msgid "Are you sure you want to delete this %{typeOfComment}?"
msgstr ""
+msgid "Are you sure you want to delete this SSH key?"
+msgstr ""
+
msgid "Are you sure you want to delete this board?"
msgstr ""
@@ -3259,6 +3381,11 @@ msgstr ""
msgid "Are you sure you want to erase this build?"
msgstr ""
+msgid "Are you sure you want to import %d repository?"
+msgid_plural "Are you sure you want to import %d repositories?"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Are you sure you want to lose unsaved changes?"
msgstr ""
@@ -3268,15 +3395,15 @@ msgstr ""
msgid "Are you sure you want to merge immediately?"
msgstr ""
-msgid "Are you sure you want to permanently delete this license?"
-msgstr ""
-
msgid "Are you sure you want to re-deploy this environment?"
msgstr ""
msgid "Are you sure you want to regenerate the public key? You will have to update the public key on the remote server before mirroring will work again."
msgstr ""
+msgid "Are you sure you want to reindex?"
+msgstr ""
+
msgid "Are you sure you want to remove %{group_name}?"
msgstr ""
@@ -3304,6 +3431,9 @@ msgstr ""
msgid "Are you sure you want to revoke this nickname?"
msgstr ""
+msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
+msgstr ""
+
msgid "Are you sure you want to stop this environment?"
msgstr ""
@@ -3325,6 +3455,9 @@ msgstr ""
msgid "Are you sure? The device will be signed out of GitLab and all remember me tokens revoked."
msgstr ""
+msgid "Are you sure? This will invalidate your registered applications and U2F / WebAuthn devices."
+msgstr ""
+
msgid "Are you sure? This will invalidate your registered applications and U2F devices."
msgstr ""
@@ -3343,9 +3476,6 @@ msgstr ""
msgid "Artifacts"
msgstr ""
-msgid "As U2F devices are only supported by a few browsers, we require that you set up a two-factor authentication app before a U2F device. That way you'll always be able to log in - even when you're using an unsupported browser."
-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 ""
@@ -3539,6 +3669,9 @@ msgstr ""
msgid "AuditLogs|Target"
msgstr ""
+msgid "AuditLogs|This month"
+msgstr ""
+
msgid "AuditLogs|User Events"
msgstr ""
@@ -3578,6 +3711,9 @@ msgstr ""
msgid "Authentication via U2F device failed."
msgstr ""
+msgid "Authentication via WebAuthn device failed."
+msgstr ""
+
msgid "Author"
msgstr ""
@@ -3845,15 +3981,6 @@ msgstr ""
msgid "BambooService|You must set up automatic revision labeling and a repository trigger in Bamboo."
msgstr ""
-msgid "BatchComments|Delete all pending comments"
-msgstr ""
-
-msgid "BatchComments|Discard review?"
-msgstr ""
-
-msgid "BatchComments|You're about to discard your review which will delete all of your pending comments. The deleted comments %{strong_start}cannot%{strong_end} be restored."
-msgstr ""
-
msgid "Be careful. Changing the project's namespace can have unintended side effects."
msgstr ""
@@ -3875,6 +4002,9 @@ msgstr ""
msgid "Bi-weekly code coverage"
msgstr ""
+msgid "Billable Users:"
+msgstr ""
+
msgid "Billing"
msgstr ""
@@ -3884,7 +4014,7 @@ msgstr ""
msgid "BillingPlans|@%{user_name} you are currently using the %{plan_name} plan."
msgstr ""
-msgid "BillingPlans|Congratulations, your new trial is activated"
+msgid "BillingPlans|Congratulations, your free trial is activated."
msgstr ""
msgid "BillingPlans|If you would like to downgrade your plan please contact %{support_link_start}Customer Support%{support_link_end}."
@@ -3947,6 +4077,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Block user"
+msgstr ""
+
msgid "Blocked"
msgstr ""
@@ -3962,31 +4095,37 @@ msgstr ""
msgid "Blog"
msgstr ""
-msgid "Board name"
-msgstr ""
-
msgid "Board scope"
msgstr ""
msgid "Board scope affects which issues are displayed for anyone who visits this board"
msgstr ""
-msgid "BoardBlankState|Add default lists"
+msgid "Boards"
msgstr ""
-msgid "BoardBlankState|Add the following default lists to your Issue Board with one click:"
+msgid "Boards and Board Lists"
msgstr ""
-msgid "BoardBlankState|Nevermind, I'll use my own"
+msgid "Boards|An error occurred while creating the issue. Please try again."
msgstr ""
-msgid "BoardBlankState|Starting out with the default set of lists will get you right on the way to making the most of your board."
+msgid "Boards|An error occurred while creating the list. Please try again."
msgstr ""
-msgid "Boards"
+msgid "Boards|An error occurred while fetching issues. Please reload the page."
msgstr ""
-msgid "Boards and Board Lists"
+msgid "Boards|An error occurred while fetching the board issues. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching the board swimlanes. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while moving the issue. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while updating the list. Please try again."
msgstr ""
msgid "Boards|Collapse"
@@ -4013,7 +4152,7 @@ msgstr ""
msgid "Branch %{branch_name} was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr ""
-msgid "Branch has changed"
+msgid "Branch changed"
msgstr ""
msgid "Branch is already taken"
@@ -4319,6 +4458,9 @@ msgstr ""
msgid "CLOSED (MOVED)"
msgstr ""
+msgid "CODEOWNERS rule violation"
+msgstr ""
+
msgid "CONTRIBUTING"
msgstr ""
@@ -4349,9 +4491,6 @@ msgstr ""
msgid "Can't create snippet: %{err}"
msgstr ""
-msgid "Can't edit as source branch was deleted"
-msgstr ""
-
msgid "Can't fetch content for the blob: %{err}"
msgstr ""
@@ -4364,9 +4503,6 @@ msgstr ""
msgid "Can't load mermaid module: %{err}"
msgstr ""
-msgid "Can't remove group members without group managed account"
-msgstr ""
-
msgid "Can't scan the code?"
msgstr ""
@@ -4409,6 +4545,9 @@ msgstr ""
msgid "Cannot create the abuse report. This user has been blocked."
msgstr ""
+msgid "Cannot enable shared runners because parent group does not allow it"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -4514,6 +4653,15 @@ msgstr ""
msgid "Change your password or recover your current one"
msgstr ""
+msgid "ChangeReviewer|Reviewer changed from %{old} to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Reviewer changed to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Unassigned"
+msgstr ""
+
msgid "ChangeTypeActionLabel|Pick into branch"
msgstr ""
@@ -4553,6 +4701,9 @@ msgstr ""
msgid "Changes the title to \"%{title_param}\"."
msgstr ""
+msgid "Changes were successfully made."
+msgstr ""
+
msgid "Changes won't take place until the index is %{link_start}recreated%{link_end}."
msgstr ""
@@ -4958,6 +5109,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove variable"
+msgstr ""
+
msgid "CiVariables|Remove variable row"
msgstr ""
@@ -5036,9 +5190,6 @@ msgstr ""
msgid "Clear due date"
msgstr ""
-msgid "Clear input"
-msgstr ""
-
msgid "Clear recent searches"
msgstr ""
@@ -5087,6 +5238,9 @@ msgstr ""
msgid "Client authentication key password"
msgstr ""
+msgid "Client request timeout"
+msgstr ""
+
msgid "Clients"
msgstr ""
@@ -5171,6 +5325,27 @@ msgstr ""
msgid "Cluster type must be specificed for Stages::ClusterEndpointInserter"
msgstr ""
+msgid "ClusterAgents|Configuration"
+msgstr ""
+
+msgid "ClusterAgents|Connect your cluster with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate Kubernetes with a GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Name"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Agent also requires %{linkStart}enabling the Agent Server%{linkEnd}"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Kubernetes Agent allows an Infrastructure as Code, GitOps approach to integrating Kubernetes clusters with GitLab. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "ClusterAgent|This feature is only available for premium plans"
msgstr ""
@@ -5240,10 +5415,10 @@ msgstr ""
msgid "ClusterIntegration|All installed applications and related resources"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster."
+msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{linkStart}More information%{linkEnd}"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{startLink}More information%{endLink}"
+msgid "ClusterIntegration|Allow GitLab to manage namespaces and service accounts for this cluster."
msgstr ""
msgid "ClusterIntegration|Alternatively, "
@@ -5264,6 +5439,9 @@ msgstr ""
msgid "ClusterIntegration|An error occurred while trying to fetch zone machine types: %{error}"
msgstr ""
+msgid "ClusterIntegration|An unknown error occurred while attempting to connect to Kubernetes."
+msgstr ""
+
msgid "ClusterIntegration|Any project namespaces"
msgstr ""
@@ -5279,6 +5457,9 @@ msgstr ""
msgid "ClusterIntegration|Authenticate with Amazon Web Services"
msgstr ""
+msgid "ClusterIntegration|Authentication Error"
+msgstr ""
+
msgid "ClusterIntegration|Base domain"
msgstr ""
@@ -5297,13 +5478,22 @@ msgstr ""
msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}security group %{externalLinkIcon} %{endLink} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
+msgid "ClusterIntegration|Check your CA certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Check your cluster status"
+msgstr ""
+
+msgid "ClusterIntegration|Check your token"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}subnets %{externalLinkIcon} %{endLink} in your VPC where your worker nodes will run."
+msgid "ClusterIntegration|Choose the %{linkStart}security group %{linkEnd} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
msgstr ""
-msgid "ClusterIntegration|Choose the worker node %{startLink}instance type %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Choose the %{linkStart}subnets %{linkEnd} in your VPC where your worker nodes will run."
+msgstr ""
+
+msgid "ClusterIntegration|Choose the worker node %{linkStart}instance type%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Choose which applications to install on your Kubernetes cluster."
@@ -5315,10 +5505,7 @@ msgstr ""
msgid "ClusterIntegration|Clear cluster cache"
msgstr ""
-msgid "ClusterIntegration|Clear the local cache of namespace and service accounts. This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
-msgstr ""
-
-msgid "ClusterIntegration|Cluster being created"
+msgid "ClusterIntegration|Clear the local cache of namespace and service accounts."
msgstr ""
msgid "ClusterIntegration|Cluster management project (alpha)"
@@ -5330,15 +5517,21 @@ msgstr ""
msgid "ClusterIntegration|Cluster_applications artifact too big. Maximum allowable size: %{human_size}"
msgstr ""
-msgid "ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters."
+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|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}"
+msgid "ClusterIntegration|Clusters connected with a certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Connect cluster with certificate"
msgstr ""
msgid "ClusterIntegration|Connect existing cluster"
msgstr ""
+msgid "ClusterIntegration|Connection Error"
+msgstr ""
+
msgid "ClusterIntegration|Copy API URL"
msgstr ""
@@ -5414,6 +5607,12 @@ msgstr ""
msgid "ClusterIntegration|Deletes all GitLab resources attached to this cluster during removal"
msgstr ""
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared."
+msgstr ""
+
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared. %{linkStart}More information%{linkEnd}"
+msgstr ""
+
msgid "ClusterIntegration|Did you know?"
msgstr ""
@@ -5483,6 +5682,9 @@ msgstr ""
msgid "ClusterIntegration|Fluentd is an open source data collector, which lets you unify the data collection and consumption for a better use and understanding of data. It requires at least one of the following logs to be successfully installed."
msgstr ""
+msgid "ClusterIntegration|GitLab Agent managed clusters"
+msgstr ""
+
msgid "ClusterIntegration|GitLab Container Network Policies"
msgstr ""
@@ -5495,6 +5697,12 @@ msgstr ""
msgid "ClusterIntegration|GitLab Runner connects to the repository and executes CI/CD jobs, pushing results back and deploying applications to production."
msgstr ""
+msgid "ClusterIntegration|GitLab failed to authenticate."
+msgstr ""
+
+msgid "ClusterIntegration|GitLab failed to connect to the cluster."
+msgstr ""
+
msgid "ClusterIntegration|GitLab-managed cluster"
msgstr ""
@@ -5516,6 +5724,9 @@ msgstr ""
msgid "ClusterIntegration|Group cluster"
msgstr ""
+msgid "ClusterIntegration|HTTP Error"
+msgstr ""
+
msgid "ClusterIntegration|Helm Tiller"
msgstr ""
@@ -5549,7 +5760,10 @@ msgstr ""
msgid "ClusterIntegration|Instance type"
msgstr ""
-msgid "ClusterIntegration|Integrate Kubernetes cluster automation"
+msgid "ClusterIntegration|Integrate Kubernetes with a cluster certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Integrate with a cluster certificate"
msgstr ""
msgid "ClusterIntegration|Issuer Email"
@@ -5585,9 +5799,6 @@ msgstr ""
msgid "ClusterIntegration|Knative extends Kubernetes to provide a set of middleware components that are essential to build modern, source-centric, and container-based applications that can run anywhere: on premises, in the cloud, or even in a third-party data center."
msgstr ""
-msgid "ClusterIntegration|Kubernetes cluster"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes cluster is being created..."
msgstr ""
@@ -5600,9 +5811,6 @@ msgstr ""
msgid "ClusterIntegration|Kubernetes clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr ""
-msgid "ClusterIntegration|Kubernetes clusters can be used to deploy applications and to provide Review Apps for this project"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes version"
msgstr ""
@@ -5615,7 +5823,7 @@ msgstr ""
msgid "ClusterIntegration|Learn more about %{help_link_start}zones%{help_link_end}."
msgstr ""
-msgid "ClusterIntegration|Learn more about %{startLink}Regions %{externalLinkIcon}%{endLink}."
+msgid "ClusterIntegration|Learn more about %{linkStart}Regions%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Learn more about Kubernetes"
@@ -5660,12 +5868,18 @@ msgstr ""
msgid "ClusterIntegration|Machine type"
msgstr ""
+msgid "ClusterIntegration|Make sure your API endpoint is correct"
+msgstr ""
+
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create Kubernetes clusters"
msgstr ""
msgid "ClusterIntegration|Manage your Kubernetes cluster by visiting %{provider_link}"
msgstr ""
+msgid "ClusterIntegration|Namespace per environment"
+msgstr ""
+
msgid "ClusterIntegration|No IAM Roles found"
msgstr ""
@@ -5711,6 +5925,9 @@ msgstr ""
msgid "ClusterIntegration|No zones matched your search"
msgstr ""
+msgid "ClusterIntegration|Node calculations use the Kubernetes Metrics API. Make sure your cluster has metrics installed"
+msgstr ""
+
msgid "ClusterIntegration|Number of nodes"
msgstr ""
@@ -5753,6 +5970,9 @@ msgstr ""
msgid "ClusterIntegration|RBAC-enabled cluster"
msgstr ""
+msgid "ClusterIntegration|Read our %{linkStart}help page%{linkEnd} on Kubernetes cluster integration."
+msgstr ""
+
msgid "ClusterIntegration|Read our %{link_start}help page%{link_end} on Kubernetes cluster integration."
msgstr ""
@@ -5855,7 +6075,7 @@ msgstr ""
msgid "ClusterIntegration|Select a VPC to choose a subnet"
msgstr ""
-msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{linkStart}Amazon Web Services %{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select a network to choose a subnetwork"
@@ -5888,7 +6108,7 @@ msgstr ""
msgid "ClusterIntegration|Select project to choose zone"
msgstr ""
-msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select zone"
@@ -5978,9 +6198,18 @@ msgstr ""
msgid "ClusterIntegration|There was a problem authenticating with your cluster. Please ensure your CA Certificate and Token are valid."
msgstr ""
+msgid "ClusterIntegration|There was an HTTP error when connecting to your cluster."
+msgstr ""
+
msgid "ClusterIntegration|This account must have permissions to create a Kubernetes cluster in the %{link_to_container_project} specified below"
msgstr ""
+msgid "ClusterIntegration|This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
+msgstr ""
+
+msgid "ClusterIntegration|This is necessary to clear existing environment-namespace associations from clusters previously managed by GitLab."
+msgstr ""
+
msgid "ClusterIntegration|This option will allow you to install applications on RBAC clusters."
msgstr ""
@@ -6005,9 +6234,21 @@ msgstr ""
msgid "ClusterIntegration|To use a new project, first create one on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}."
msgstr ""
+msgid "ClusterIntegration|Troubleshooting tips:"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Authenticate"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Connect"
+msgstr ""
+
msgid "ClusterIntegration|Uninstall %{appTitle}"
msgstr ""
+msgid "ClusterIntegration|Unknown Error"
+msgstr ""
+
msgid "ClusterIntegration|Update %{appTitle}"
msgstr ""
@@ -6068,7 +6309,7 @@ msgstr ""
msgid "ClusterIntegration|Your cluster API is unreachable. Please ensure your API URL is correct."
msgstr ""
-msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Zone"
@@ -6188,6 +6429,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse all threads"
+msgstr ""
+
msgid "Collapse approvers"
msgstr ""
@@ -6337,7 +6581,7 @@ msgstr ""
msgid "Commit…"
msgstr ""
-msgid "Company"
+msgid "Community forum"
msgstr ""
msgid "Company name"
@@ -6346,6 +6590,9 @@ msgstr ""
msgid "Compare"
msgstr ""
+msgid "Compare %{oldCommitId}...%{newCommitId}"
+msgstr ""
+
msgid "Compare Git revisions"
msgstr ""
@@ -6361,6 +6608,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare submodule commit revisions"
+msgstr ""
+
msgid "Compare with previous version"
msgstr ""
@@ -6496,6 +6746,9 @@ msgstr ""
msgid "Configure the way a user creates a new account."
msgstr ""
+msgid "Configure which lists are shown for anyone who visits this board"
+msgstr ""
+
msgid "Confirm"
msgstr ""
@@ -6721,6 +6974,9 @@ msgstr[1] ""
msgid "ContainerRegistry|Set cleanup policy"
msgstr ""
+msgid "ContainerRegistry|Some tags were not deleted"
+msgstr ""
+
msgid "ContainerRegistry|Something went wrong while fetching the cleanup policy."
msgstr ""
@@ -6760,6 +7016,9 @@ msgstr ""
msgid "ContainerRegistry|Tags with names matching this regex pattern will %{italicStart}expire:%{italicEnd}"
msgstr ""
+msgid "ContainerRegistry|The cleanup policy timed out before it could delete all tags. An administrator can %{adminLinkStart}manually run cleanup now%{adminLinkEnd} or you can wait for the cleanup policy to automatically run again. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "ContainerRegistry|The last tag related to this image was recently removed. This empty image and any associated data will be automatically removed as part of the regular Garbage Collection process. If you have any questions, contact your administrator."
msgstr ""
@@ -6892,6 +7151,9 @@ msgstr ""
msgid "Contributions per group member"
msgstr ""
+msgid "Contributor"
+msgstr ""
+
msgid "Contributors"
msgstr ""
@@ -7021,6 +7283,9 @@ msgstr ""
msgid "Could not change HEAD: branch '%{branch}' does not exist"
msgstr ""
+msgid "Could not commit. An unexpected error occurred."
+msgstr ""
+
msgid "Could not connect to FogBugz, check your URL"
msgstr ""
@@ -7060,6 +7325,9 @@ msgstr ""
msgid "Could not find iteration"
msgstr ""
+msgid "Could not load instance counts. Please refresh the page to try again."
+msgstr ""
+
msgid "Could not remove the trigger."
msgstr ""
@@ -7084,10 +7352,10 @@ msgstr ""
msgid "Could not save prometheus manual configuration"
msgstr ""
-msgid "Could not udpdate wiki page"
+msgid "Could not update the LDAP settings"
msgstr ""
-msgid "Could not update the LDAP settings"
+msgid "Could not update wiki page"
msgstr ""
msgid "Could not upload your designs as one or more files uploaded are not supported."
@@ -7745,6 +8013,9 @@ msgstr ""
msgid "DastProfiles|Are you sure you want to delete this profile?"
msgstr ""
+msgid "DastProfiles|Could not create site validation token. Please refresh the page, or try again later."
+msgstr ""
+
msgid "DastProfiles|Could not create the scanner profile. Please try again."
msgstr ""
@@ -7769,6 +8040,12 @@ msgstr ""
msgid "DastProfiles|Could not fetch site profiles. Please refresh the page, or try again later."
msgstr ""
+msgid "DastProfiles|Could not retrieve site validation status. Please refresh the page, or try again later."
+msgstr ""
+
+msgid "DastProfiles|Could not update the scanner profile. Please try again."
+msgstr ""
+
msgid "DastProfiles|Could not update the site profile. Please try again."
msgstr ""
@@ -7784,7 +8061,7 @@ msgstr ""
msgid "DastProfiles|Download validation text file"
msgstr ""
-msgid "DastProfiles|Edit feature will come soon. Please create a new profile if changes needed"
+msgid "DastProfiles|Edit scanner profile"
msgstr ""
msgid "DastProfiles|Edit site profile"
@@ -7817,6 +8094,9 @@ msgstr ""
msgid "DastProfiles|No profiles created yet"
msgstr ""
+msgid "DastProfiles|Passive"
+msgstr ""
+
msgid "DastProfiles|Please enter a valid URL format, ex: http://www.example.com/home"
msgstr ""
@@ -7832,6 +8112,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan mode"
+msgstr ""
+
msgid "DastProfiles|Scanner Profile"
msgstr ""
@@ -7871,10 +8154,10 @@ msgstr ""
msgid "DastProfiles|Text file validation"
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
+msgid "DastProfiles|The maximum number of minutes allowed for the spider to traverse the site."
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the spider to traverse the site."
+msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
msgstr ""
msgid "DastProfiles|Validate"
@@ -7907,6 +8190,9 @@ msgstr ""
msgid "Date picker"
msgstr ""
+msgid "Date range"
+msgstr ""
+
msgid "Date range cannot exceed %{maxDateRange} days."
msgstr ""
@@ -7931,6 +8217,9 @@ msgstr ""
msgid "Days to merge"
msgstr ""
+msgid "Dear Administrator,"
+msgstr ""
+
msgid "Debug"
msgstr ""
@@ -8042,12 +8331,18 @@ msgstr ""
msgid "Delete"
msgstr ""
+msgid "Delete %{name}"
+msgstr ""
+
msgid "Delete Comment"
msgstr ""
msgid "Delete Snippet"
msgstr ""
+msgid "Delete Value Stream"
+msgstr ""
+
msgid "Delete account"
msgstr ""
@@ -8069,9 +8364,6 @@ msgstr ""
msgid "Delete label: %{label_name} ?"
msgstr ""
-msgid "Delete license"
-msgstr ""
-
msgid "Delete list"
msgstr ""
@@ -8147,15 +8439,6 @@ msgstr ""
msgid "Deleting a project places it into a read-only state until %{date}, at which point the project will be permanently deleted. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "Deleting the license failed."
-msgstr ""
-
-msgid "Deleting the license failed. The license was not found."
-msgstr ""
-
-msgid "Deleting the license failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "Deleting the project will delete its repository and all related resources including issues, merge requests etc."
msgstr ""
@@ -8651,7 +8934,10 @@ msgstr ""
msgid "DesignManagement|The maximum number of designs allowed to be uploaded is %{upload_limit}. Please try again."
msgstr ""
-msgid "DesignManagement|To upload designs, you'll need to enable LFS. %{requirements_link_start}More information%{requirements_link_end}"
+msgid "DesignManagement|There was an error moving your designs. Please upload your designs below."
+msgstr ""
+
+msgid "DesignManagement|To upload designs, you'll need to enable LFS and have admin enable hashed storage. %{requirements_link_start}More information%{requirements_link_end}"
msgstr ""
msgid "DesignManagement|Unresolve thread"
@@ -8663,6 +8949,9 @@ msgstr ""
msgid "DesignManagement|Upload skipped."
msgstr ""
+msgid "DesignManagement|Your designs are being copied and are on their way… Please refresh to update."
+msgstr ""
+
msgid "DesignManagement|and %{moreCount} more."
msgstr ""
@@ -8720,6 +9009,9 @@ msgstr ""
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
+msgid "Direct member"
+msgstr ""
+
msgid "Direction"
msgstr ""
@@ -8768,9 +9060,6 @@ msgstr ""
msgid "Discard draft"
msgstr ""
-msgid "Discard review"
-msgstr ""
-
msgid "DiscordService|Discord Notifications"
msgstr ""
@@ -8839,10 +9128,10 @@ msgstr ""
msgid "Dismiss Merge Request promotion"
msgstr ""
-msgid "Dismiss Selected"
+msgid "Dismiss Value Stream Analytics introduction box"
msgstr ""
-msgid "Dismiss Value Stream Analytics introduction box"
+msgid "Dismiss selected"
msgstr ""
msgid "Dismiss trial promotion"
@@ -8893,9 +9182,6 @@ msgstr ""
msgid "Documents reindexed: %{processed_documents} (%{percentage}%%)"
msgstr ""
-msgid "Doing"
-msgstr ""
-
msgid "Domain"
msgstr ""
@@ -9091,9 +9377,6 @@ msgstr ""
msgid "Edit environment"
msgstr ""
-msgid "Edit file"
-msgstr ""
-
msgid "Edit files in the editor and commit changes here"
msgstr ""
@@ -9106,6 +9389,12 @@ msgstr ""
msgid "Edit identity for %{user_name}"
msgstr ""
+msgid "Edit in Web IDE"
+msgstr ""
+
+msgid "Edit in single-file editor"
+msgstr ""
+
msgid "Edit issues"
msgstr ""
@@ -9133,10 +9422,10 @@ msgstr ""
msgid "Editing"
msgstr ""
-msgid "Elasticsearch"
+msgid "Elasticsearch AWS IAM credentials"
msgstr ""
-msgid "Elasticsearch AWS IAM credentials"
+msgid "Elasticsearch HTTP client timeout value in seconds."
msgstr ""
msgid "Elasticsearch indexing restrictions"
@@ -9145,9 +9434,6 @@ msgstr ""
msgid "Elasticsearch indexing started"
msgstr ""
-msgid "Elasticsearch integration. Elasticsearch AWS IAM."
-msgstr ""
-
msgid "Elasticsearch reindexing is already in progress"
msgstr ""
@@ -9175,9 +9461,6 @@ msgstr ""
msgid "Email Notification"
msgstr ""
-msgid "Email address"
-msgstr ""
-
msgid "Email could not be sent"
msgstr ""
@@ -9241,6 +9524,9 @@ msgstr ""
msgid "Emails sent from Service Desk will have this name"
msgstr ""
+msgid "Emails sent to %{email} will still be supported"
+msgstr ""
+
msgid "Emails separated by comma"
msgstr ""
@@ -9274,9 +9560,18 @@ msgstr ""
msgid "Enable"
msgstr ""
+msgid "Enable %{link_start}Gitpod%{link_end} integration to launch a development environment in your browser directly from GitLab."
+msgstr ""
+
msgid "Enable Auto DevOps"
msgstr ""
+msgid "Enable Gitpod"
+msgstr ""
+
+msgid "Enable Gitpod?"
+msgstr ""
+
msgid "Enable HTML emails"
msgstr ""
@@ -9406,9 +9701,6 @@ msgstr ""
msgid "Encountered an error while rendering: %{err}"
msgstr ""
-msgid "End date"
-msgstr ""
-
msgid "Ends at (UTC)"
msgstr ""
@@ -9568,7 +9860,7 @@ msgstr ""
msgid "EnvironmentsDashboard|The environments dashboard provides a summary of each project's environments' status, including pipeline and alert statuses."
msgstr ""
-msgid "EnvironmentsDashboard|This dashboard displays a maximum of 7 projects and 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
+msgid "EnvironmentsDashboard|This dashboard displays 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
msgstr ""
msgid "Environments|An error occurred while canceling the auto stop, please try again"
@@ -9889,6 +10181,9 @@ msgstr ""
msgid "Error deleting project. Check logs for error details."
msgstr ""
+msgid "Error fetching burnup chart data"
+msgstr ""
+
msgid "Error fetching diverging counts for branches. Please try again."
msgstr ""
@@ -9967,6 +10262,9 @@ msgstr ""
msgid "Error occurred when saving assignees"
msgstr ""
+msgid "Error occurred when saving reviewers"
+msgstr ""
+
msgid "Error occurred when toggling the notification subscription"
msgstr ""
@@ -10219,10 +10517,13 @@ msgstr ""
msgid "Expand all"
msgstr ""
-msgid "Expand approvers"
+msgid "Expand all files"
msgstr ""
-msgid "Expand dropdown"
+msgid "Expand all threads"
+msgstr ""
+
+msgid "Expand approvers"
msgstr ""
msgid "Expand milestones"
@@ -10393,6 +10694,9 @@ msgstr ""
msgid "Failed to create Merge Request. Please try again."
msgstr ""
+msgid "Failed to create To-Do for the design."
+msgstr ""
+
msgid "Failed to create a branch for this issue. Please try again."
msgstr ""
@@ -10432,6 +10736,12 @@ msgstr ""
msgid "Failed to load authors. Please try again."
msgstr ""
+msgid "Failed to load branches. Please try again."
+msgstr ""
+
+msgid "Failed to load deploy keys."
+msgstr ""
+
msgid "Failed to load emoji list."
msgstr ""
@@ -10447,6 +10757,9 @@ msgstr ""
msgid "Failed to load groups & users."
msgstr ""
+msgid "Failed to load groups, users and deploy keys."
+msgstr ""
+
msgid "Failed to load labels. Please try again."
msgstr ""
@@ -10456,6 +10769,12 @@ msgstr ""
msgid "Failed to load related branches"
msgstr ""
+msgid "Failed to load sidebar confidential toggle"
+msgstr ""
+
+msgid "Failed to load sidebar lock status"
+msgstr ""
+
msgid "Failed to load stacktrace."
msgstr ""
@@ -10483,6 +10802,9 @@ msgstr ""
msgid "Failed to publish issue on status page."
msgstr ""
+msgid "Failed to remove To-Do for the design."
+msgstr ""
+
msgid "Failed to remove a Zoom meeting"
msgstr ""
@@ -10525,6 +10847,9 @@ msgstr ""
msgid "Failed to signing using smartcard authentication"
msgstr ""
+msgid "Failed to toggle To-Do for the design."
+msgstr ""
+
msgid "Failed to update branch!"
msgstr ""
@@ -10638,7 +10963,7 @@ msgstr ""
msgid "FeatureFlags|Edit User List"
msgstr ""
-msgid "FeatureFlags|Enable features for specific users and specific environments by defining feature flag strategies."
+msgid "FeatureFlags|Enable features for specific users and environments by configuring feature flag strategies."
msgstr ""
msgid "FeatureFlags|Environment Spec"
@@ -10698,7 +11023,7 @@ msgstr ""
msgid "FeatureFlags|Include additional user IDs"
msgstr ""
-msgid "FeatureFlags|Install a %{docs_link_anchored_start}compatible client library%{docs_link_anchored_end} and specify the API URL, application name, and instance ID during the configuration setup. %{docs_link_start}More Information%{docs_link_end}"
+msgid "FeatureFlags|Install a %{docsLinkAnchoredStart}compatible client library%{docsLinkAnchoredEnd} and specify the API URL, application name, and instance ID during the configuration setup. %{docsLinkStart}More Information%{docsLinkEnd}"
msgstr ""
msgid "FeatureFlags|Instance ID"
@@ -10710,6 +11035,9 @@ msgstr ""
msgid "FeatureFlags|Loading feature flags"
msgstr ""
+msgid "FeatureFlags|Loading user lists"
+msgstr ""
+
msgid "FeatureFlags|More information"
msgstr ""
@@ -10728,7 +11056,7 @@ msgstr ""
msgid "FeatureFlags|New feature flag"
msgstr ""
-msgid "FeatureFlags|New list"
+msgid "FeatureFlags|New user list"
msgstr ""
msgid "FeatureFlags|Percent of users"
@@ -10767,6 +11095,9 @@ msgstr ""
msgid "FeatureFlags|There was an error fetching the feature flags."
msgstr ""
+msgid "FeatureFlags|There was an error fetching the user lists."
+msgstr ""
+
msgid "FeatureFlags|There was an error retrieving user lists"
msgstr ""
@@ -10782,6 +11113,9 @@ msgstr ""
msgid "FeatureFlags|User List"
msgstr ""
+msgid "FeatureFlags|User Lists"
+msgstr ""
+
msgid "FeatureFlag|List"
msgstr ""
@@ -10809,15 +11143,6 @@ msgstr ""
msgid "Fetching incoming email"
msgstr ""
-msgid "Fetching licenses failed."
-msgstr ""
-
-msgid "Fetching licenses failed. The request endpoint was not found."
-msgstr ""
-
-msgid "Fetching licenses failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "File"
msgstr ""
@@ -10920,12 +11245,21 @@ msgstr ""
msgid "Filter by status"
msgstr ""
+msgid "Filter by test cases that are currently archived."
+msgstr ""
+
+msgid "Filter by test cases that are currently opened."
+msgstr ""
+
msgid "Filter by two-factor authentication"
msgstr ""
msgid "Filter by user"
msgstr ""
+msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
+msgstr ""
+
msgid "Filter pipelines"
msgstr ""
@@ -10941,7 +11275,7 @@ msgstr ""
msgid "Filter results..."
msgstr ""
-msgid "Filter your projects by name"
+msgid "Filter your repositories by name"
msgstr ""
msgid "Filter..."
@@ -10950,7 +11284,7 @@ msgstr ""
msgid "Find File"
msgstr ""
-msgid "Find bugs in your code with coverage-guided fuzzing"
+msgid "Find bugs in your code with coverage-guided fuzzing."
msgstr ""
msgid "Find by path"
@@ -10977,9 +11311,6 @@ msgstr ""
msgid "Finish editing this message first!"
msgstr ""
-msgid "Finish review"
-msgstr ""
-
msgid "Finish setting up your dedicated account for %{group_name}."
msgstr ""
@@ -11049,6 +11380,9 @@ msgstr ""
msgid "Footer message"
msgstr ""
+msgid "For a faster browsing experience, some files are collapsed by default."
+msgstr ""
+
msgid "For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
@@ -11058,6 +11392,9 @@ msgstr ""
msgid "For more info, read the documentation."
msgstr ""
+msgid "For more information on how the number of active users is calculated, see the %{self_managed_subscriptions_doc_link} documentation."
+msgstr ""
+
msgid "For more information, go to the "
msgstr ""
@@ -11196,6 +11533,9 @@ msgstr ""
msgid "Generate new token"
msgstr ""
+msgid "Generic package file size in bytes"
+msgstr ""
+
msgid "Geo"
msgstr ""
@@ -11457,6 +11797,9 @@ msgstr ""
msgid "Geo|Please refer to Geo Troubleshooting."
msgstr ""
+msgid "Geo|Primary node"
+msgstr ""
+
msgid "Geo|Project"
msgstr ""
@@ -11499,6 +11842,9 @@ msgstr ""
msgid "Geo|Review replication status, and resynchronize and reverify items with the primary node."
msgstr ""
+msgid "Geo|Secondary node"
+msgstr ""
+
msgid "Geo|Status"
msgstr ""
@@ -11538,6 +11884,9 @@ msgstr ""
msgid "Geo|URL must be a valid url (ex: https://gitlab.com)"
msgstr ""
+msgid "Geo|Undefined"
+msgstr ""
+
msgid "Geo|Unknown state"
msgstr ""
@@ -11613,10 +11962,16 @@ msgstr ""
msgid "GitHub import"
msgstr ""
+msgid "GitLab"
+msgstr ""
+
msgid "GitLab / Unsubscribe"
msgstr ""
-msgid "GitLab Enterprise Edition %{plan}"
+msgid "GitLab API"
+msgstr ""
+
+msgid "GitLab Billing Team."
msgstr ""
msgid "GitLab Group Runners can execute code for all the projects in this group."
@@ -11628,12 +11983,18 @@ msgstr ""
msgid "GitLab Issue"
msgstr ""
+msgid "GitLab Pages"
+msgstr ""
+
msgid "GitLab Service Desk is a simple way to allow people to create issues in your GitLab instance without needing their own user account. It provides a unique email address for end users to create issues in a project, and replies can be sent either through the GitLab interface or by email. End users will only see the thread through email."
msgstr ""
msgid "GitLab Shared Runners execute code of different projects on the same Runner unless you configure GitLab Runner Autoscale with MaxBuilds 1 (which it is on GitLab.com)."
msgstr ""
+msgid "GitLab Shell"
+msgstr ""
+
msgid "GitLab Support Bot"
msgstr ""
@@ -11643,7 +12004,7 @@ msgstr ""
msgid "GitLab User"
msgstr ""
-msgid "GitLab allows you to continue using your license even if you exceed the number of seats you purchased. You will be required to pay for these seats when you renew your license."
+msgid "GitLab Workhorse"
msgstr ""
msgid "GitLab commit"
@@ -11811,6 +12172,21 @@ msgstr ""
msgid "Gitlab Pages"
msgstr ""
+msgid "Gitpod"
+msgstr ""
+
+msgid "Gitpod|Add the URL to your Gitpod instance configured to read your GitLab projects."
+msgstr ""
+
+msgid "Gitpod|Enable Gitpod integration"
+msgstr ""
+
+msgid "Gitpod|Gitpod URL"
+msgstr ""
+
+msgid "Gitpod|e.g. https://gitpod.example.com"
+msgstr ""
+
msgid "Given access %{time_ago}"
msgstr ""
@@ -12318,9 +12694,6 @@ msgstr ""
msgid "GroupSAML|Valid SAML Response"
msgstr ""
-msgid "GroupSAML|With group managed accounts enabled, all the users without a group managed account will be excluded from the group."
-msgstr ""
-
msgid "GroupSAML|With prohibit outer forks flag enabled group members will be able to fork project only inside your group."
msgstr ""
@@ -12534,10 +12907,10 @@ msgstr ""
msgid "GroupsNew|Create group"
msgstr ""
-msgid "GroupsNew|GitLab group export"
+msgid "GroupsNew|Import"
msgstr ""
-msgid "GroupsNew|Import"
+msgid "GroupsNew|Import a GitLab group export file"
msgstr ""
msgid "GroupsNew|Import group"
@@ -12680,6 +13053,9 @@ msgid_plural "Hide charts"
msgstr[0] ""
msgstr[1] ""
+msgid "Hide comments on this file"
+msgstr ""
+
msgid "Hide details"
msgstr ""
@@ -12724,6 +13100,15 @@ msgstr ""
msgid "Highest role:"
msgstr ""
+msgid "HighlightBar|Alert events:"
+msgstr ""
+
+msgid "HighlightBar|Alert start time:"
+msgstr ""
+
+msgid "HighlightBar|Original alert:"
+msgstr ""
+
msgid "History"
msgstr ""
@@ -12901,6 +13286,9 @@ msgstr ""
msgid "If enabled, access to projects will be validated on an external service using their classification label."
msgstr ""
+msgid "If the number of active users exceeds the user limit, you will be charged for the number of %{users_over_license_link} at your next license reconciliation."
+msgstr ""
+
msgid "If there is no previous license or if the previous license has expired, some GitLab functionality will be blocked until a new, valid license is uploaded."
msgstr ""
@@ -12940,9 +13328,6 @@ msgstr ""
msgid "If your HTTP repository is not publicly accessible, add your credentials."
msgstr ""
-msgid "Iglu registry URL (optional)"
-msgstr ""
-
msgid "Ignore"
msgstr ""
@@ -12979,6 +13364,16 @@ msgstr ""
msgid "Import"
msgstr ""
+msgid "Import %d compatible repository"
+msgid_plural "Import %d compatible repositories"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Import %d repository"
+msgid_plural "Import %d repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Import CSV"
msgstr ""
@@ -12988,15 +13383,9 @@ msgstr ""
msgid "Import all compatible projects"
msgstr ""
-msgid "Import all compatible repositories"
-msgstr ""
-
msgid "Import all projects"
msgstr ""
-msgid "Import all repositories"
-msgstr ""
-
msgid "Import an exported GitLab project"
msgstr ""
@@ -13084,6 +13473,9 @@ msgstr ""
msgid "ImportProjects|Error importing repository %{project_safe_import_url} into %{project_full_path} - %{message}"
msgstr ""
+msgid "ImportProjects|Import repositories"
+msgstr ""
+
msgid "ImportProjects|Importing the project failed"
msgstr ""
@@ -13096,7 +13488,7 @@ msgstr ""
msgid "ImportProjects|Requesting your %{provider} repositories failed"
msgstr ""
-msgid "ImportProjects|Select the projects you want to import"
+msgid "ImportProjects|Select the repositories you want to import"
msgstr ""
msgid "ImportProjects|The remote data could not be imported."
@@ -13132,9 +13524,6 @@ msgstr ""
msgid "In order to enable Service Desk for your instance, you must first set up incoming email."
msgstr ""
-msgid "In order to gather accurate feature usage data, it can take 1 to 2 weeks to see your index."
-msgstr ""
-
msgid "In order to personalize your experience with GitLab%{br_tag}we would like to know a bit more about you."
msgstr ""
@@ -13165,18 +13554,30 @@ msgstr ""
msgid "IncidentManagement|Create incident"
msgstr ""
+msgid "IncidentManagement|Critical - S1"
+msgstr ""
+
msgid "IncidentManagement|Date created"
msgstr ""
msgid "IncidentManagement|Display your incidents in a dedicated view"
msgstr ""
+msgid "IncidentManagement|High - S2"
+msgstr ""
+
msgid "IncidentManagement|Incident"
msgstr ""
msgid "IncidentManagement|Incidents"
msgstr ""
+msgid "IncidentManagement|Low - S4"
+msgstr ""
+
+msgid "IncidentManagement|Medium - S3"
+msgstr ""
+
msgid "IncidentManagement|No incidents to display."
msgstr ""
@@ -13189,6 +13590,9 @@ msgstr ""
msgid "IncidentManagement|Published to status page"
msgstr ""
+msgid "IncidentManagement|Severity"
+msgstr ""
+
msgid "IncidentManagement|There are no closed incidents"
msgstr ""
@@ -13198,6 +13602,9 @@ msgstr ""
msgid "IncidentManagement|Unassigned"
msgstr ""
+msgid "IncidentManagement|Unknown"
+msgstr ""
+
msgid "IncidentManagement|Unpublished"
msgstr ""
@@ -13219,6 +13626,15 @@ msgstr ""
msgid "Incidents"
msgstr ""
+msgid "Incident|Alert details"
+msgstr ""
+
+msgid "Incident|Summary"
+msgstr ""
+
+msgid "Incident|There was an issue loading alert data. Please try again."
+msgstr ""
+
msgid "Include a Terms of Service agreement and Privacy Policy that all users must accept."
msgstr ""
@@ -13279,6 +13695,9 @@ msgstr ""
msgid "Information about additional Pages templates and how to install them can be found in our %{pages_getting_started_guide}."
msgstr ""
+msgid "Inherited"
+msgstr ""
+
msgid "Inherited:"
msgstr ""
@@ -13359,7 +13778,22 @@ msgstr ""
msgid "Instance administrators group already exists"
msgstr ""
-msgid "Instance license"
+msgid "InstanceStatistics|Groups"
+msgstr ""
+
+msgid "InstanceStatistics|Issues"
+msgstr ""
+
+msgid "InstanceStatistics|Merge Requests"
+msgstr ""
+
+msgid "InstanceStatistics|Pipelines"
+msgstr ""
+
+msgid "InstanceStatistics|Projects"
+msgstr ""
+
+msgid "InstanceStatistics|Users"
msgstr ""
msgid "Integration"
@@ -13371,6 +13805,12 @@ msgstr ""
msgid "Integrations"
msgstr ""
+msgid "Integrations|%{integration} settings saved and active."
+msgstr ""
+
+msgid "Integrations|%{integration} settings saved, but not active."
+msgstr ""
+
msgid "Integrations|All details"
msgstr ""
@@ -13380,6 +13820,12 @@ msgstr ""
msgid "Integrations|Comment settings:"
msgstr ""
+msgid "Integrations|Connection failed. Please check your settings."
+msgstr ""
+
+msgid "Integrations|Connection successful."
+msgstr ""
+
msgid "Integrations|Default settings are inherited from the group level."
msgstr ""
@@ -13395,6 +13841,15 @@ msgstr ""
msgid "Integrations|Includes commit title and branch"
msgstr ""
+msgid "Integrations|Projects using custom settings will not be impacted unless the project owner chooses to use instance-level defaults."
+msgstr ""
+
+msgid "Integrations|Save settings?"
+msgstr ""
+
+msgid "Integrations|Saving will update the default settings for all projects that are not using custom settings."
+msgstr ""
+
msgid "Integrations|Standard"
msgstr ""
@@ -13527,6 +13982,9 @@ msgstr ""
msgid "Invitation"
msgstr ""
+msgid "Invitation declined"
+msgstr ""
+
msgid "Invite"
msgstr ""
@@ -13578,6 +14036,42 @@ 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|%{linkStart}Read more%{linkEnd} about role permissions"
+msgstr ""
+
+msgid "InviteMembersModal|Access expiration date (optional)"
+msgstr ""
+
+msgid "InviteMembersModal|Cancel"
+msgstr ""
+
+msgid "InviteMembersModal|Choose a role permission"
+msgstr ""
+
+msgid "InviteMembersModal|GitLab member or Email address"
+msgstr ""
+
+msgid "InviteMembersModal|Invite"
+msgstr ""
+
+msgid "InviteMembersModal|Invite team members"
+msgstr ""
+
+msgid "InviteMembersModal|Search for members to invite"
+msgstr ""
+
+msgid "InviteMembersModal|User not invited. Feature coming soon!"
+msgstr ""
+
+msgid "InviteMembersModal|Users were succesfully added"
+msgstr ""
+
+msgid "InviteMembersModal|You're inviting members to the %{group_name} group"
+msgstr ""
+
+msgid "InviteMembers|Invite team members"
+msgstr ""
+
msgid "Invited"
msgstr ""
@@ -13632,10 +14126,13 @@ msgstr ""
msgid "Issue cannot be found."
msgstr ""
+msgid "Issue created from vulnerability %{vulnerability_link}"
+msgstr ""
+
msgid "Issue events"
msgstr ""
-msgid "Issue first depoloyed to production"
+msgid "Issue first deployed to production"
msgstr ""
msgid "Issue label"
@@ -13713,6 +14210,9 @@ msgstr ""
msgid "IssueTracker|Custom issue tracker"
msgstr ""
+msgid "IssueTracker|EWM work items tracker"
+msgstr ""
+
msgid "IssueTracker|Redmine issue tracker"
msgstr ""
@@ -13779,6 +14279,9 @@ msgstr ""
msgid "It looks like you have some draft commits in this branch."
msgstr ""
+msgid "It may be several days before you see feature usage data."
+msgstr ""
+
msgid "It must have a header row and at least two columns: the first column is the issue title and the second column is the issue description. The separator is automatically detected."
msgstr ""
@@ -14061,13 +14564,13 @@ msgstr ""
msgid "Join Zoom meeting"
msgstr ""
-msgid "Jul"
+msgid "Joined %{time_ago}"
msgstr ""
-msgid "July"
+msgid "Jul"
msgstr ""
-msgid "Jump to first unresolved thread"
+msgid "July"
msgstr ""
msgid "Jump to next unresolved thread"
@@ -14103,6 +14606,9 @@ msgstr ""
msgid "Keyboard shortcuts"
msgstr ""
+msgid "KeyboardKey|Ctrl+"
+msgstr ""
+
msgid "Keys"
msgstr ""
@@ -14151,6 +14657,9 @@ msgstr ""
msgid "LDAP Synchronization"
msgstr ""
+msgid "LDAP group settings"
+msgstr ""
+
msgid "LDAP settings"
msgstr ""
@@ -14160,6 +14669,9 @@ msgstr ""
msgid "LDAP sync in progress. This could take a few minutes. Refresh the page to see the changes."
msgstr ""
+msgid "LDAP synchronizations"
+msgstr ""
+
msgid "LFS"
msgstr ""
@@ -14240,7 +14752,16 @@ msgid_plural "Last %d days"
msgstr[0] ""
msgstr[1] ""
-msgid "Last %{days} days"
+msgid "Last 2 weeks"
+msgstr ""
+
+msgid "Last 30 days"
+msgstr ""
+
+msgid "Last 60 days"
+msgstr ""
+
+msgid "Last 90 days"
msgstr ""
msgid "Last Accessed On"
@@ -14318,6 +14839,9 @@ msgstr ""
msgid "Last used on:"
msgstr ""
+msgid "Last week"
+msgstr ""
+
msgid "LastCommit|authored"
msgstr ""
@@ -14333,6 +14857,9 @@ msgstr ""
msgid "Latest pipeline for the most recent commit on this branch"
msgstr ""
+msgid "Launch a ready-to-code development environment for your project."
+msgstr ""
+
msgid "Lead"
msgstr ""
@@ -14713,6 +15240,9 @@ msgstr ""
msgid "List of all merge commits"
msgstr ""
+msgid "List options"
+msgstr ""
+
msgid "List settings"
msgstr ""
@@ -14725,9 +15255,6 @@ msgstr ""
msgid "List your Bitbucket Server repositories"
msgstr ""
-msgid "Lists"
-msgstr ""
-
msgid "Live preview"
msgstr ""
@@ -14974,6 +15501,12 @@ msgstr ""
msgid "Mark as done"
msgstr ""
+msgid "Mark as draft"
+msgstr ""
+
+msgid "Mark as ready"
+msgstr ""
+
msgid "Mark as resolved"
msgstr ""
@@ -14995,6 +15528,24 @@ msgstr ""
msgid "Markdown is supported"
msgstr ""
+msgid "MarkdownEditor|Add a link (%{modifierKey}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add a link (%{modifier_key}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifierKey}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifier_key}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifierKey}I)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifier_key}I)"
+msgstr ""
+
msgid "Marked For Deletion At - %{deletion_time}"
msgstr ""
@@ -15079,7 +15630,25 @@ msgstr ""
msgid "Max access level"
msgstr ""
-msgid "Max seats used"
+msgid "Max role"
+msgstr ""
+
+msgid "Max size 15 MB"
+msgstr ""
+
+msgid "Maximum Conan package file size in bytes"
+msgstr ""
+
+msgid "Maximum Maven package file size in bytes"
+msgstr ""
+
+msgid "Maximum NPM package file size in bytes"
+msgstr ""
+
+msgid "Maximum NuGet package file size in bytes"
+msgstr ""
+
+msgid "Maximum PyPI package file size in bytes"
msgstr ""
msgid "Maximum Users:"
@@ -15211,6 +15780,18 @@ msgstr ""
msgid "Members with access to %{strong_start}%{group_name}%{strong_end}"
msgstr ""
+msgid "Members|%{time} by %{user}"
+msgstr ""
+
+msgid "Members|Expired"
+msgstr ""
+
+msgid "Members|No expiration set"
+msgstr ""
+
+msgid "Members|in %{time}"
+msgstr ""
+
msgid "Memory Usage"
msgstr ""
@@ -15397,9 +15978,6 @@ msgstr ""
msgid "MergeRequests|Thread will be unresolved"
msgstr ""
-msgid "MergeRequests|Toggle comments for this file"
-msgstr ""
-
msgid "MergeRequests|View file @ %{commitId}"
msgstr ""
@@ -15460,6 +16038,9 @@ msgstr ""
msgid "Merging immediately isn't recommended as it may negatively impact the existing merge train. Read the %{docsLinkStart}documentation%{docsLinkEnd} for more information."
msgstr ""
+msgid "Message"
+msgstr ""
+
msgid "Messages"
msgstr ""
@@ -15845,18 +16426,12 @@ msgid_plural "Milestones"
msgstr[0] ""
msgstr[1] ""
-msgid "Milestone does not support burnup charts"
-msgstr ""
-
msgid "Milestone lists not available with your current license"
msgstr ""
msgid "Milestone lists show all issues from the selected milestone."
msgstr ""
-msgid "Milestone must have a start and due date"
-msgstr ""
-
msgid "MilestoneSidebar|Closed:"
msgstr ""
@@ -16223,6 +16798,9 @@ msgstr ""
msgid "Namespace"
msgstr ""
+msgid "Namespace ID:"
+msgstr ""
+
msgid "Namespace is empty"
msgstr ""
@@ -16307,6 +16885,9 @@ msgstr ""
msgid "NetworkPolicies|Allow all outbound traffic from %{selector} to %{ruleSelector} on %{ports}"
msgstr ""
+msgid "NetworkPolicies|Are you sure you want to delete this policy? This action cannot be undone."
+msgstr ""
+
msgid "NetworkPolicies|Choose whether to enforce this policy."
msgstr ""
@@ -16316,12 +16897,21 @@ msgstr ""
msgid "NetworkPolicies|Define this policy's location, conditions and actions."
msgstr ""
+msgid "NetworkPolicies|Delete policy"
+msgstr ""
+
+msgid "NetworkPolicies|Delete policy: %{policy}"
+msgstr ""
+
msgid "NetworkPolicies|Deny all traffic"
msgstr ""
msgid "NetworkPolicies|Description"
msgstr ""
+msgid "NetworkPolicies|Edit policy"
+msgstr ""
+
msgid "NetworkPolicies|Editor mode"
msgstr ""
@@ -16349,6 +16939,9 @@ msgstr ""
msgid "NetworkPolicies|Name"
msgstr ""
+msgid "NetworkPolicies|Namespace"
+msgstr ""
+
msgid "NetworkPolicies|Network Policy"
msgstr ""
@@ -16400,6 +16993,9 @@ msgstr ""
msgid "NetworkPolicies|Rules"
msgstr ""
+msgid "NetworkPolicies|Save changes"
+msgstr ""
+
msgid "NetworkPolicies|Something went wrong, failed to update policy"
msgstr ""
@@ -16412,6 +17008,9 @@ msgstr ""
msgid "NetworkPolicies|Traffic that does not match any rule will be blocked."
msgstr ""
+msgid "NetworkPolicies|Unable to parse policy"
+msgstr ""
+
msgid "NetworkPolicies|YAML editor"
msgstr ""
@@ -16525,6 +17124,9 @@ msgstr ""
msgid "New Snippet"
msgstr ""
+msgid "New Test Case"
+msgstr ""
+
msgid "New User"
msgstr ""
@@ -16624,6 +17226,9 @@ msgstr ""
msgid "New tag"
msgstr ""
+msgid "New test case"
+msgstr ""
+
msgid "New users set to external"
msgstr ""
@@ -16696,7 +17301,7 @@ msgstr ""
msgid "No changes"
msgstr ""
-msgid "No changes between %{ref_start}%{source_branch}%{ref_end} and %{ref_start}%{target_branch}%{ref_end}"
+msgid "No changes between %{sourceBranch} and %{targetBranch}"
msgstr ""
msgid "No child epics match applied filters"
@@ -16711,6 +17316,9 @@ msgstr ""
msgid "No containers available"
msgstr ""
+msgid "No content to show"
+msgstr ""
+
msgid "No contributions"
msgstr ""
@@ -16786,9 +17394,6 @@ msgstr ""
msgid "No license. All rights reserved"
msgstr ""
-msgid "No licenses found."
-msgstr ""
-
msgid "No matches found"
msgstr ""
@@ -16801,6 +17406,9 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No members found"
+msgstr ""
+
msgid "No merge requests found"
msgstr ""
@@ -16822,6 +17430,9 @@ msgstr ""
msgid "No parent group"
msgstr ""
+msgid "No plan"
+msgstr ""
+
msgid "No pods available"
msgstr ""
@@ -16918,6 +17529,12 @@ msgstr ""
msgid "Not Implemented"
msgstr ""
+msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+msgstr ""
+
+msgid "Not all browsers support WebAuthn. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even from an unsupported browser."
+msgstr ""
+
msgid "Not all data has been processed yet, the accuracy of the chart for the selected timeframe is limited."
msgstr ""
@@ -17014,6 +17631,9 @@ msgstr ""
msgid "Notification settings saved"
msgstr ""
+msgid "NotificationEvent|Change reviewer merge request"
+msgstr ""
+
msgid "NotificationEvent|Close issue"
msgstr ""
@@ -17176,10 +17796,7 @@ msgstr ""
msgid "On track"
msgstr ""
-msgid "OnDemandScans|Attached branch"
-msgstr ""
-
-msgid "OnDemandScans|Attached branch is where the scan job runs."
+msgid "OnDemandScans|Could not fetch scanner profiles. Please refresh the page, or try again later."
msgstr ""
msgid "OnDemandScans|Could not fetch site profiles. Please refresh the page, or try again later."
@@ -17188,6 +17805,9 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
+msgid "OnDemandScans|Create a new scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Create a new site profile"
msgstr ""
@@ -17200,6 +17820,9 @@ msgstr ""
msgid "OnDemandScans|New on-demand DAST scan"
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 ""
@@ -17209,16 +17832,10 @@ msgstr ""
msgid "OnDemandScans|On-demand scans run outside the DevOps cycle and find vulnerabilities in your projects. %{learnMoreLinkStart}Learn more%{learnMoreLinkEnd}"
msgstr ""
-msgid "OnDemandScans|Only a passive scan can be performed on demand."
-msgstr ""
-
-msgid "OnDemandScans|Passive"
-msgstr ""
-
msgid "OnDemandScans|Run scan"
msgstr ""
-msgid "OnDemandScans|Scan mode"
+msgid "OnDemandScans|Scanner profile"
msgstr ""
msgid "OnDemandScans|Scanner settings"
@@ -17230,9 +17847,15 @@ msgstr ""
msgid "OnDemandScans|Select one of the existing profiles"
msgstr ""
+msgid "OnDemandScans|Site profile"
+msgstr ""
+
msgid "OnDemandScans|Site profiles"
msgstr ""
+msgid "OnDemandScans|Use existing scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Use existing site profile"
msgstr ""
@@ -17331,9 +17954,6 @@ msgstr ""
msgid "Open Selection"
msgstr ""
-msgid "Open Web IDE"
-msgstr ""
-
msgid "Open comment type dropdown"
msgstr ""
@@ -17439,6 +18059,9 @@ msgstr ""
msgid "Origin"
msgstr ""
+msgid "Orphaned member"
+msgstr ""
+
msgid "Other Labels"
msgstr ""
@@ -17454,6 +18077,9 @@ msgstr ""
msgid "Other visibility settings have been disabled by the administrator."
msgstr ""
+msgid "Our documentation includes an example DevOps Score report."
+msgstr ""
+
msgid "Out-of-compliance with this project's policies and should be removed"
msgstr ""
@@ -17478,6 +18104,9 @@ msgstr ""
msgid "Overwrite diverged branches"
msgstr ""
+msgid "Owned by %{image_tag}"
+msgstr ""
+
msgid "Owned by anyone"
msgstr ""
@@ -17499,6 +18128,9 @@ msgstr ""
msgid "Package deleted successfully"
msgstr ""
+msgid "Package file size limits"
+msgstr ""
+
msgid "Package recipe already exists"
msgstr ""
@@ -17514,9 +18146,6 @@ msgstr ""
msgid "Package type must be PyPi"
msgstr ""
-msgid "Package was removed"
-msgstr ""
-
msgid "PackageRegistry|%{name} version %{version} was created %{datetime}"
msgstr ""
@@ -17658,12 +18287,18 @@ msgstr ""
msgid "PackageRegistry|NuGet Command"
msgstr ""
+msgid "PackageRegistry|Package Registry"
+msgstr ""
+
msgid "PackageRegistry|Pip Command"
msgstr ""
msgid "PackageRegistry|Pipeline %{link} triggered %{datetime} by %{author}"
msgstr ""
+msgid "PackageRegistry|Publish and share packages for a variety of common package managers. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "PackageRegistry|Published to the %{project} Package Registry %{datetime}"
msgstr ""
@@ -17763,6 +18398,9 @@ msgstr ""
msgid "Page not found"
msgstr ""
+msgid "Page settings"
+msgstr ""
+
msgid "Page was successfully deleted"
msgstr ""
@@ -17904,7 +18542,7 @@ msgstr ""
msgid "Paste issue link"
msgstr ""
-msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Don't use your private SSH key."
+msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Do not paste your private SSH key, as that can compromise your identity."
msgstr ""
msgid "Patch to apply"
@@ -17931,6 +18569,9 @@ msgstr ""
msgid "Pending"
msgstr ""
+msgid "Pending comments"
+msgstr ""
+
msgid "People without permission will never get a notification and won't be able to comment."
msgstr ""
@@ -18129,6 +18770,9 @@ msgstr ""
msgid "Pipelines|Build with confidence"
msgstr ""
+msgid "Pipelines|By revoking a trigger you will break any processes making use of it. Are you sure?"
+msgstr ""
+
msgid "Pipelines|CI Lint"
msgstr ""
@@ -18141,6 +18785,15 @@ msgstr ""
msgid "Pipelines|Continuous Integration can help catch bugs by running your tests automatically, while Continuous Deployment can help you deliver code to your product environment."
msgstr ""
+msgid "Pipelines|Copy trigger token"
+msgstr ""
+
+msgid "Pipelines|Description"
+msgstr ""
+
+msgid "Pipelines|Edit"
+msgstr ""
+
msgid "Pipelines|Get started with Pipelines"
msgstr ""
@@ -18156,15 +18809,27 @@ msgstr ""
msgid "Pipelines|It is recommended the code is reviewed thoroughly before running this pipeline with the parent project's CI resource."
msgstr ""
+msgid "Pipelines|Last Used"
+msgstr ""
+
msgid "Pipelines|Loading Pipelines"
msgstr ""
msgid "Pipelines|More Information"
msgstr ""
+msgid "Pipelines|No triggers have been created yet. Add one using the form above."
+msgstr ""
+
+msgid "Pipelines|Owner"
+msgstr ""
+
msgid "Pipelines|Project cache successfully reset."
msgstr ""
+msgid "Pipelines|Revoke"
+msgstr ""
+
msgid "Pipelines|Run Pipeline"
msgstr ""
@@ -18189,6 +18854,15 @@ msgstr ""
msgid "Pipelines|This project is not currently set up to run pipelines."
msgstr ""
+msgid "Pipelines|Token"
+msgstr ""
+
+msgid "Pipelines|Trigger user has insufficient permissions to project"
+msgstr ""
+
+msgid "Pipelines|invalid"
+msgstr ""
+
msgid "Pipelines|parent"
msgstr ""
@@ -18447,10 +19121,10 @@ msgstr ""
msgid "Please provide attributes to update"
msgstr ""
-msgid "Please refer to %{docs_url}"
+msgid "Please reach out if you have any questions and we'll be happy to assist."
msgstr ""
-msgid "Please retype the email address."
+msgid "Please refer to %{docs_url}"
msgstr ""
msgid "Please select"
@@ -18480,6 +19154,9 @@ msgstr ""
msgid "Please set a new password before proceeding."
msgstr ""
+msgid "Please share your feedback about %{featureName} %{linkStart}in this issue%{linkEnd} to help us improve the experience."
+msgstr ""
+
msgid "Please solve the reCAPTCHA"
msgstr ""
@@ -18783,6 +19460,9 @@ msgstr ""
msgid "Profiles| You are going to change the username %{currentUsernameBold} to %{newUsernameBold}. Profile and projects will be redirected to the %{newUsername} namespace but this redirect will expire once the %{currentUsername} namespace is registered by another user or group. Please update your Git repository remotes as soon as possible."
msgstr ""
+msgid "Profiles|%{provider} Active"
+msgstr ""
+
msgid "Profiles|@username"
msgstr ""
@@ -18834,7 +19514,7 @@ msgstr ""
msgid "Profiles|Commit email"
msgstr ""
-msgid "Profiles|Connect"
+msgid "Profiles|Connect %{provider}"
msgstr ""
msgid "Profiles|Connected Accounts"
@@ -18858,6 +19538,9 @@ msgstr ""
msgid "Profiles|Disconnect"
msgstr ""
+msgid "Profiles|Disconnect %{provider}"
+msgstr ""
+
msgid "Profiles|Do not show on profile"
msgstr ""
@@ -18882,7 +19565,7 @@ msgstr ""
msgid "Profiles|Full name"
msgstr ""
-msgid "Profiles|Give your individual key a title. This will be publically visible."
+msgid "Profiles|Give your individual key a title."
msgstr ""
msgid "Profiles|Include private contributions on my profile"
@@ -18972,7 +19655,7 @@ msgstr ""
msgid "Profiles|The maximum file size allowed is 200KB."
msgstr ""
-msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it?"
+msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it? It will be publicly visible."
msgstr ""
msgid "Profiles|This email will be displayed on your public profile"
@@ -19047,6 +19730,9 @@ msgstr ""
msgid "Profiles|You don't have access to delete this user."
msgstr ""
+msgid "Profiles|You must transfer ownership or delete groups you are an owner of before you can delete your account"
+msgstr ""
+
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
@@ -19635,6 +20321,9 @@ msgstr ""
msgid "ProjectTemplates|GitLab Cluster Management"
msgstr ""
+msgid "ProjectTemplates|Gitpod/Spring Petclinic"
+msgstr ""
+
msgid "ProjectTemplates|Go Micro"
msgstr ""
@@ -20244,6 +20933,9 @@ msgstr ""
msgid "Publish to status page"
msgstr ""
+msgid "Published"
+msgstr ""
+
msgid "Published on status page"
msgstr ""
@@ -20361,9 +21053,15 @@ msgstr ""
msgid "Quick range"
msgstr ""
+msgid "Quickly and easily edit multiple files in your project."
+msgstr ""
+
msgid "README"
msgstr ""
+msgid "Rails"
+msgstr ""
+
msgid "Rake Tasks Help"
msgstr ""
@@ -20483,10 +21181,13 @@ msgstr ""
msgid "Register Two-Factor Authenticator"
msgstr ""
-msgid "Register U2F device"
+msgid "Register Universal Two-Factor (U2F) Device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register WebAuthn Device"
+msgstr ""
+
+msgid "Register device"
msgstr ""
msgid "Register for GitLab"
@@ -20498,9 +21199,6 @@ msgstr ""
msgid "Register with two-factor app"
msgstr ""
-msgid "Registration"
-msgstr ""
-
msgid "Registration|Checkout"
msgstr ""
@@ -20617,9 +21315,6 @@ msgstr ""
msgid "Release|Something went wrong while saving the release details"
msgstr ""
-msgid "Remediated: needs review"
-msgstr ""
-
msgid "Remediations"
msgstr ""
@@ -20725,6 +21420,9 @@ msgstr ""
msgid "Remove priority"
msgstr ""
+msgid "Remove report"
+msgstr ""
+
msgid "Remove secondary node"
msgstr ""
@@ -20737,6 +21435,12 @@ msgstr ""
msgid "Remove time estimate"
msgstr ""
+msgid "Remove user & report"
+msgstr ""
+
+msgid "Remove user from group"
+msgstr ""
+
msgid "Removed"
msgstr ""
@@ -20818,9 +21522,6 @@ msgstr ""
msgid "Removes time estimate."
msgstr ""
-msgid "Removing license…"
-msgstr ""
-
msgid "Removing this group also removes all child projects, including archived projects, and their resources."
msgstr ""
@@ -20905,6 +21606,9 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
+msgid "Reported by %{reporter}"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -20991,6 +21695,27 @@ msgstr ""
msgid "Repositories"
msgstr ""
+msgid "Repositories Analytics"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download Historic Test Coverage Data"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download historic test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Historic Test Coverage Data is available in raw format (.csv) for further analysis."
+msgstr ""
+
+msgid "RepositoriesAnalytics|Test Code Coverage"
+msgstr ""
+
+msgid "RepositoriesAnalytics|There was an error fetching the projects."
+msgstr ""
+
msgid "Repository"
msgstr ""
@@ -21069,9 +21794,15 @@ msgstr ""
msgid "Request parameter %{param} is missing."
msgstr ""
+msgid "Request review from"
+msgstr ""
+
msgid "Request to link SAML account must be authorized"
msgstr ""
+msgid "Requested"
+msgstr ""
+
msgid "Requested %{time_ago}"
msgstr ""
@@ -21090,6 +21821,9 @@ msgstr ""
msgid "Requests to these domain(s)/address(es) on the local network will be allowed when local requests from hooks and services are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 or 127.0.0.0/28 are supported. Domain wildcards are not supported currently. Use comma, semicolon, or newline to separate multiple entries. The allowlist can hold a maximum of 1000 entries. Domains should use IDNA encoding. Ex: example.com, 192.168.1.1, 127.0.0.0/28, xn--itlab-j1a.com."
msgstr ""
+msgid "Require admin approval for new sign-ups"
+msgstr ""
+
msgid "Require all users in this group to setup Two-factor authentication"
msgstr ""
@@ -21217,9 +21951,6 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
-msgid "Resolved by %{resolvedByName}"
-msgstr ""
-
msgid "Resolves IP addresses once and uses them to submit requests"
msgstr ""
@@ -21339,6 +22070,14 @@ msgstr ""
msgid "ReviewApp|Enable Review App"
msgstr ""
+msgid "Reviewer"
+msgid_plural "%d Reviewers"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Reviewer(s)"
+msgstr ""
+
msgid "Reviewing"
msgstr ""
@@ -21378,6 +22117,9 @@ msgstr ""
msgid "Rook"
msgstr ""
+msgid "Ruby"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -21456,6 +22198,63 @@ msgstr ""
msgid "Runners page."
msgstr ""
+msgid "Runners|Active"
+msgstr ""
+
+msgid "Runners|Architecture"
+msgstr ""
+
+msgid "Runners|Can run untagged jobs"
+msgstr ""
+
+msgid "Runners|Description"
+msgstr ""
+
+msgid "Runners|Group"
+msgstr ""
+
+msgid "Runners|IP Address"
+msgstr ""
+
+msgid "Runners|Last contact"
+msgstr ""
+
+msgid "Runners|Locked to this project"
+msgstr ""
+
+msgid "Runners|Maximum job timeout"
+msgstr ""
+
+msgid "Runners|Name"
+msgstr ""
+
+msgid "Runners|Platform"
+msgstr ""
+
+msgid "Runners|Property Name"
+msgstr ""
+
+msgid "Runners|Protected"
+msgstr ""
+
+msgid "Runners|Revision"
+msgstr ""
+
+msgid "Runners|Shared"
+msgstr ""
+
+msgid "Runners|Specific"
+msgstr ""
+
+msgid "Runners|Tags"
+msgstr ""
+
+msgid "Runners|Value"
+msgstr ""
+
+msgid "Runners|Version"
+msgstr ""
+
msgid "Runners|You have used %{quotaUsed} out of %{quotaLimit} of your shared Runners pipeline minutes."
msgstr ""
@@ -21468,6 +22267,9 @@ msgstr ""
msgid "Runs a number of housekeeping tasks within the current repository, such as compressing file revisions and removing unreachable objects."
msgstr ""
+msgid "SAML"
+msgstr ""
+
msgid "SAML SSO"
msgstr ""
@@ -21519,6 +22321,9 @@ msgstr ""
msgid "Save"
msgstr ""
+msgid "Save %{name} size limits"
+msgstr ""
+
msgid "Save Changes"
msgstr ""
@@ -21549,9 +22354,6 @@ msgstr ""
msgid "Save space and find tags in the Container Registry more easily. Enable the cleanup policy to remove stale tags and keep only the ones you need."
msgstr ""
-msgid "Save template"
-msgstr ""
-
msgid "Save variables"
msgstr ""
@@ -21594,9 +22396,6 @@ msgstr ""
msgid "Scope"
msgstr ""
-msgid "Scope not supported with disabled 'users_search' feature!"
-msgstr ""
-
msgid "Scoped issue boards"
msgstr ""
@@ -21723,9 +22522,6 @@ msgstr ""
msgid "Search requirements"
msgstr ""
-msgid "Search results…"
-msgstr ""
-
msgid "Search users"
msgstr ""
@@ -21798,6 +22594,11 @@ msgid_plural "SearchResults|commits"
msgstr[0] ""
msgstr[1] ""
+msgid "SearchResults|epic"
+msgid_plural "SearchResults|epics"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "SearchResults|issue"
msgid_plural "SearchResults|issues"
msgstr[0] ""
@@ -21842,10 +22643,10 @@ msgstr ""
msgid "Seat Link is disabled, and cannot be configured through this form."
msgstr ""
-msgid "Seats currently in use"
+msgid "Seats usage data as of %{last_enqueue_time}"
msgstr ""
-msgid "Seats in license"
+msgid "Seats usage data is updated every day at 12:00pm UTC"
msgstr ""
msgid "Secondary"
@@ -21899,6 +22700,9 @@ msgstr ""
msgid "SecurityConfiguration|Available for on-demand DAST"
msgstr ""
+msgid "SecurityConfiguration|By default, all analyzers are applied in order to cover all languages across your project, and only run if the language is detected in the Merge Request."
+msgstr ""
+
msgid "SecurityConfiguration|Configure"
msgstr ""
@@ -21929,16 +22733,19 @@ msgstr ""
msgid "SecurityConfiguration|Manage"
msgstr ""
+msgid "SecurityConfiguration|More information"
+msgstr ""
+
msgid "SecurityConfiguration|Not enabled"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|Security Control"
+msgid "SecurityConfiguration|SAST Configuration"
msgstr ""
-msgid "SecurityConfiguration|See documentation"
+msgid "SecurityConfiguration|Security Control"
msgstr ""
msgid "SecurityConfiguration|Status"
@@ -21950,6 +22757,9 @@ msgstr ""
msgid "SecurityConfiguration|Using custom settings. You won't receive automatic updates on this variable. %{anchorStart}Restore to default%{anchorEnd}"
msgstr ""
+msgid "SecurityConfiguration|View history"
+msgstr ""
+
msgid "SecurityConfiguration|You can quickly enable all security scanning tools by enabling %{linkStart}Auto DevOps%{linkEnd}."
msgstr ""
@@ -22028,9 +22838,6 @@ msgstr ""
msgid "SecurityReports|Learn more about setting up your dashboard"
msgstr ""
-msgid "SecurityReports|Load more vulnerabilities"
-msgstr ""
-
msgid "SecurityReports|Monitor vulnerabilities in your code"
msgstr ""
@@ -22310,7 +23117,7 @@ msgstr ""
msgid "Select status"
msgstr ""
-msgid "Select strategy activation method"
+msgid "Select strategy activation method."
msgstr ""
msgid "Select subscription"
@@ -22325,7 +23132,7 @@ msgstr ""
msgid "Select the custom project template source group."
msgstr ""
-msgid "Select timeframe"
+msgid "Select the environment scope for this feature flag."
msgstr ""
msgid "Select timezone"
@@ -22574,6 +23381,9 @@ msgstr ""
msgid "Set iteration"
msgstr ""
+msgid "Set limit to 0 to allow any file size."
+msgstr ""
+
msgid "Set max session time for web terminal."
msgstr ""
@@ -22652,10 +23462,13 @@ msgstr ""
msgid "Set up a %{type} Runner manually"
msgstr ""
+msgid "Set up a hardware device as a second factor to sign in."
+msgstr ""
+
msgid "Set up assertions/attributes/claims (email, first_name, last_name) and NameID according to %{docsLinkStart}the documentation %{icon}%{docsLinkEnd}"
msgstr ""
-msgid "Set up new U2F device"
+msgid "Set up new device"
msgstr ""
msgid "Set up new password"
@@ -22724,6 +23537,9 @@ msgstr ""
msgid "Sets weight to %{weight}."
msgstr ""
+msgid "Setting this to 0 means using the system default timeout value."
+msgstr ""
+
msgid "Settings"
msgstr ""
@@ -22739,6 +23555,15 @@ msgstr ""
msgid "Severity"
msgstr ""
+msgid "SeverityWidget|Severity"
+msgstr ""
+
+msgid "SeverityWidget|Severity: %{severity}"
+msgstr ""
+
+msgid "SeverityWidget|There was an error while updating severity."
+msgstr ""
+
msgid "Shards (%{shards})"
msgstr ""
@@ -22784,6 +23609,9 @@ msgstr ""
msgid "Show all requirements."
msgstr ""
+msgid "Show all test cases."
+msgstr ""
+
msgid "Show archived projects"
msgstr ""
@@ -22796,6 +23624,9 @@ msgstr ""
msgid "Show comments"
msgstr ""
+msgid "Show comments on this file"
+msgstr ""
+
msgid "Show comments only"
msgstr ""
@@ -22841,6 +23672,12 @@ msgstr ""
msgid "Show parent subgroups"
msgstr ""
+msgid "Show the Closed list"
+msgstr ""
+
+msgid "Show the Open list"
+msgstr ""
+
msgid "Show whitespace changes"
msgstr ""
@@ -22884,9 +23721,6 @@ msgstr ""
msgid "Sidebar|Assign health status"
msgstr ""
-msgid "Sidebar|Change weight"
-msgstr ""
-
msgid "Sidebar|Health status"
msgstr ""
@@ -23070,6 +23904,9 @@ msgstr ""
msgid "Snippets|Add another file %{num}/%{total}"
msgstr ""
+msgid "Snippets|Authored %{time_ago} by %{author}"
+msgstr ""
+
msgid "Snippets|Delete file"
msgstr ""
@@ -23097,6 +23934,9 @@ msgstr ""
msgid "Solution"
msgstr ""
+msgid "Some changes are not shown"
+msgstr ""
+
msgid "Some child epics may be hidden due to applied filters"
msgstr ""
@@ -23463,6 +24303,12 @@ msgstr ""
msgid "Source (branch or tag)"
msgstr ""
+msgid "Source Branch"
+msgstr ""
+
+msgid "Source branch: %{source_branch_open}%{source_branch}%{source_branch_close}"
+msgstr ""
+
msgid "Source code"
msgstr ""
@@ -23628,9 +24474,6 @@ msgstr ""
msgid "Start and due date"
msgstr ""
-msgid "Start by choosing a group to see how your team is spending time. You can then drill down to the project level."
-msgstr ""
-
msgid "Start by choosing a group to start exploring the merge requests in that group. You can then proceed to filter by projects, labels, milestones and authors."
msgstr ""
@@ -23712,18 +24555,27 @@ msgstr ""
msgid "StaticSiteEditor|3. Assign a person to review and accept the merge request."
msgstr ""
+msgid "StaticSiteEditor|A link to view the merge request will appear once ready."
+msgstr ""
+
msgid "StaticSiteEditor|An error occurred while submitting your changes."
msgstr ""
msgid "StaticSiteEditor|Branch could not be created."
msgstr ""
+msgid "StaticSiteEditor|Copy update"
+msgstr ""
+
msgid "StaticSiteEditor|Could not commit the content changes."
msgstr ""
msgid "StaticSiteEditor|Could not create merge request."
msgstr ""
+msgid "StaticSiteEditor|Creating your merge request"
+msgstr ""
+
msgid "StaticSiteEditor|Incompatible file content"
msgstr ""
@@ -23745,6 +24597,9 @@ msgstr ""
msgid "StaticSiteEditor|View documentation"
msgstr ""
+msgid "StaticSiteEditor|You can set an assignee to get your changes reviewed and deployed once your merge request is created."
+msgstr ""
+
msgid "StaticSiteEditor|Your merge request has been created"
msgstr ""
@@ -23874,15 +24729,15 @@ msgstr ""
msgid "Submit %{humanized_resource_name}"
msgstr ""
-msgid "Submit Changes"
-msgstr ""
-
msgid "Submit a review"
msgstr ""
msgid "Submit as spam"
msgstr ""
+msgid "Submit changes"
+msgstr ""
+
msgid "Submit feedback"
msgstr ""
@@ -24036,6 +24891,9 @@ msgstr ""
msgid "Successfully deleted U2F device."
msgstr ""
+msgid "Successfully deleted WebAuthn device."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -24354,9 +25212,6 @@ msgstr ""
msgid "Template to append to all Service Desk issues"
msgstr ""
-msgid "Template was successfully saved."
-msgstr ""
-
msgid "Templates"
msgstr ""
@@ -24435,10 +25290,28 @@ msgid_plural "Test coverage: %d hits"
msgstr[0] ""
msgstr[1] ""
-msgid "Test failed."
+msgid "Test settings"
msgstr ""
-msgid "Test settings and save changes"
+msgid "TestCases|New Test Case"
+msgstr ""
+
+msgid "TestCases|New test case"
+msgstr ""
+
+msgid "TestCases|Search test cases"
+msgstr ""
+
+msgid "TestCases|Something went wrong while creating a test case."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching count of test cases."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching test cases list."
+msgstr ""
+
+msgid "TestCases|Submit test case"
msgstr ""
msgid "TestHooks|Ensure one of your projects has merge requests."
@@ -24504,6 +25377,9 @@ msgstr ""
msgid "Thank you for signing up for your free trial! You will get additional instructions in your inbox shortly."
msgstr ""
+msgid "Thank you for your business."
+msgstr ""
+
msgid "Thank you for your feedback!"
msgstr ""
@@ -24563,9 +25439,6 @@ msgstr ""
msgid "The URL to use for connecting to Elasticsearch. Use a comma-separated list to support clustering (e.g., \"http://localhost:9200, http://localhost:9201\")."
msgstr ""
-msgid "The Web IDE offers advanced syntax highlighting capabilities and more."
-msgstr ""
-
msgid "The X509 Certificate to use when mutual TLS is required to communicate with the external authorization service. If left blank, the server certificate is still validated when accessing over HTTPS."
msgstr ""
@@ -24676,6 +25549,9 @@ msgstr ""
msgid "The form contains the following error:"
msgstr ""
+msgid "The form contains the following warning:"
+msgstr ""
+
msgid "The global settings require you to enable Two-Factor Authentication for your account."
msgstr ""
@@ -24790,9 +25666,6 @@ msgstr ""
msgid "The private key to use when a client certificate is provided. This value is encrypted at rest."
msgstr ""
-msgid "The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The project can be accessed by any logged in user."
msgstr ""
@@ -24829,7 +25702,7 @@ msgstr ""
msgid "The remote repository is being updated..."
msgstr ""
-msgid "The repository can be commited to, and issues, comments and other entities can be created."
+msgid "The repository can be committed to, and issues, comments and other entities can be created."
msgstr ""
msgid "The repository for this project does not exist."
@@ -24883,9 +25756,6 @@ msgstr ""
msgid "The time taken by each data entry gathered by that stage."
msgstr ""
-msgid "The total stage shows the time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The update action will time out after %{number_of_minutes} minutes. For big repositories, use a clone/push combination."
msgstr ""
@@ -24949,6 +25819,9 @@ msgstr ""
msgid "There are no archived requirements"
msgstr ""
+msgid "There are no archived test cases"
+msgstr ""
+
msgid "There are no changes"
msgstr ""
@@ -24988,6 +25861,9 @@ msgstr ""
msgid "There are no open requirements"
msgstr ""
+msgid "There are no open test cases"
+msgstr ""
+
msgid "There are no packages yet"
msgstr ""
@@ -25000,6 +25876,9 @@ msgstr ""
msgid "There is a limit of %{ci_project_subscriptions_limit} subscriptions from or to a project."
msgstr ""
+msgid "There is already a To-Do for this design."
+msgstr ""
+
msgid "There is already a repository with that name on disk"
msgstr ""
@@ -25018,6 +25897,9 @@ msgstr ""
msgid "There was a problem communicating with your device."
msgstr ""
+msgid "There was a problem fetching branches."
+msgstr ""
+
msgid "There was a problem fetching groups."
msgstr ""
@@ -25246,9 +26128,15 @@ msgstr ""
msgid "This action can lead to data loss. To prevent accidental actions we ask you to confirm your intention."
msgstr ""
+msgid "This action cannot be undone, and will permanently delete the %{key} SSH key"
+msgstr ""
+
msgid "This action cannot be undone. You will lose the project's repository and all content: issues, merge requests, etc."
msgstr ""
+msgid "This action has been performed too many times. Try again later."
+msgstr ""
+
msgid "This action will %{strongOpen}permanently delete%{strongClose} %{codeOpen}%{project}%{codeClose} %{strongOpen}immediately%{strongClose}, including its repositories and all content: issues, merge requests, etc."
msgstr ""
@@ -25276,9 +26164,6 @@ msgstr ""
msgid "This board's scope is reduced"
msgstr ""
-msgid "This branch has changed since you started editing. Would you like to create a new branch?"
-msgstr ""
-
msgid "This chart could not be displayed"
msgstr ""
@@ -25405,15 +26290,9 @@ msgstr ""
msgid "This is a security log of important events involving your account."
msgstr ""
-msgid "This is the author's first Merge Request to this project."
-msgstr ""
-
msgid "This is the highest peak of users on your installation since the license started."
msgstr ""
-msgid "This is the maximum number of users that have existed at the same time since the license started. This is the minimum number of seats you will need to buy when you renew your license."
-msgstr ""
-
msgid "This is the number of currently active users on your installation, and this is the minimum number you need to purchase when you renew your license."
msgstr ""
@@ -25645,6 +26524,15 @@ msgstr ""
msgid "This user has no identities"
msgstr ""
+msgid "This user has previously committed to the %{name} project."
+msgstr ""
+
+msgid "This user has the %{access} role in the %{name} project."
+msgstr ""
+
+msgid "This user is the author of this %{noteable}."
+msgstr ""
+
msgid "This user will be the author of all events in the activity feed that are the result of an update, like new branches being created or new commits being pushed to existing branches."
msgstr ""
@@ -25675,6 +26563,9 @@ msgstr ""
msgid "Threat Monitoring"
msgstr ""
+msgid "ThreatMonitoring|All Environments"
+msgstr ""
+
msgid "ThreatMonitoring|Anomalous Requests"
msgstr ""
@@ -25702,9 +26593,6 @@ msgstr ""
msgid "ThreatMonitoring|Operations Per Second"
msgstr ""
-msgid "ThreatMonitoring|Overview"
-msgstr ""
-
msgid "ThreatMonitoring|Packet Activity"
msgstr ""
@@ -25723,6 +26611,9 @@ msgstr ""
msgid "ThreatMonitoring|Something went wrong, unable to fetch statistics"
msgstr ""
+msgid "ThreatMonitoring|Statistics"
+msgstr ""
+
msgid "ThreatMonitoring|The firewall is not installed or has been disabled. To view this data, ensure the web application firewall is installed and enabled for your cluster."
msgstr ""
@@ -26114,6 +27005,9 @@ msgstr ""
msgid "To update Snippets with multiple files, you must use the `files` parameter"
msgstr ""
+msgid "To use Gitpod you must first enable the feature in the integrations section of your %{user_prefs}."
+msgstr ""
+
msgid "To view all %{scannedResourcesCount} scanned URLs, please download the CSV file"
msgstr ""
@@ -26147,9 +27041,6 @@ msgstr ""
msgid "Toggle Sidebar"
msgstr ""
-msgid "Toggle all threads"
-msgstr ""
-
msgid "Toggle backtrace"
msgstr ""
@@ -26174,9 +27065,6 @@ msgstr ""
msgid "Toggle navigation"
msgstr ""
-msgid "Toggle project"
-msgstr ""
-
msgid "Toggle sidebar"
msgstr ""
@@ -26216,6 +27104,9 @@ msgstr ""
msgid "Too many projects enabled. You will need to manage them via the console or the API."
msgstr ""
+msgid "Too much data"
+msgstr ""
+
msgid "Topics (optional)"
msgstr ""
@@ -26234,6 +27125,9 @@ msgstr ""
msgid "Total cores (CPUs)"
msgstr ""
+msgid "Total days to completion"
+msgstr ""
+
msgid "Total issues"
msgstr ""
@@ -26330,6 +27224,9 @@ msgstr ""
msgid "Trending"
msgstr ""
+msgid "Trials|Create a new group to start your GitLab Gold trial."
+msgstr ""
+
msgid "Trials|Go back to GitLab"
msgstr ""
@@ -26339,6 +27236,15 @@ msgstr ""
msgid "Trials|You can always resume this process by selecting your avatar and choosing 'Start a Gold trial'"
msgstr ""
+msgid "Trials|You can apply your trial to a new group or an existing group."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group or your personal account."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group, an existing group, or your personal account."
+msgstr ""
+
msgid "Trials|You won't get a free trial right now but you can always resume this process by clicking on your avatar and choosing 'Start a free trial'"
msgstr ""
@@ -26408,6 +27314,9 @@ msgstr ""
msgid "Try using a different search term to find the file you are looking for."
msgstr ""
+msgid "Trying to communicate with your device. Plug it in (if needed) and press the button on the device now."
+msgstr ""
+
msgid "Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now."
msgstr ""
@@ -26495,6 +27404,12 @@ msgstr ""
msgid "URL or request ID"
msgstr ""
+msgid "USER %{user} WILL BE REMOVED! Are you sure?"
+msgstr ""
+
+msgid "USER WILL BE BLOCKED! Are you sure?"
+msgstr ""
+
msgid "UTC"
msgstr ""
@@ -26552,9 +27467,6 @@ msgstr ""
msgid "Unable to load the merge request widget. Try reloading the page."
msgstr ""
-msgid "Unable to resolve"
-msgstr ""
-
msgid "Unable to save iteration. Please try again"
msgstr ""
@@ -26603,6 +27515,9 @@ msgstr ""
msgid "Undo ignore"
msgstr ""
+msgid "Unexpected error"
+msgstr ""
+
msgid "Unfortunately, your email message to GitLab could not be processed."
msgstr ""
@@ -26636,6 +27551,9 @@ msgstr ""
msgid "Unknown response text"
msgstr ""
+msgid "Unless otherwise agreed to in writing with GitLab, by clicking \"Upload License\" you agree that your use of GitLab Software is subject to the %{eula_link_start}Terms of Service%{eula_link_end}."
+msgstr ""
+
msgid "Unlimited"
msgstr ""
@@ -27002,9 +27920,6 @@ msgstr ""
msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
msgstr ""
-msgid "Use a hardware device to add the second factor of authentication."
-msgstr ""
-
msgid "Use an one time password authenticator on your mobile device or computer to enable two-factor authentication (2FA)."
msgstr ""
@@ -27278,13 +28193,13 @@ msgstr ""
msgid "Users"
msgstr ""
-msgid "Users in License:"
+msgid "Users in License"
msgstr ""
-msgid "Users or groups set as approvers in the project's or merge request's settings."
+msgid "Users in License:"
msgstr ""
-msgid "Users outside of license"
+msgid "Users or groups set as approvers in the project's or merge request's settings."
msgstr ""
msgid "Users over License:"
@@ -27302,9 +28217,6 @@ msgstr ""
msgid "Users with a Guest role or those who don't belong to a Project or Group will not use a seat from your license."
msgstr ""
-msgid "Users with a Guest role or those who don't belong to any projects or groups don't count towards seats in use."
-msgstr ""
-
msgid "UsersSelect|%{name} + %{length} more"
msgstr ""
@@ -27344,9 +28256,6 @@ msgstr ""
msgid "Validations failed."
msgstr ""
-msgid "Validity"
-msgstr ""
-
msgid "Value"
msgstr ""
@@ -27365,6 +28274,9 @@ msgstr ""
msgid "Value Stream Name"
msgstr ""
+msgid "ValueStreamAnalyticsStage|We don't have enough data to show this stage."
+msgstr ""
+
msgid "ValueStreamAnalytics|%{days}d"
msgstr ""
@@ -27621,6 +28533,9 @@ msgstr ""
msgid "VisualReviewApp|Steps 1 and 2 (and sometimes 3) are performed once by the developer before requesting feedback. Steps 3 (if necessary), 4 is performed by the reviewer each time they perform a review."
msgstr ""
+msgid "Visualization"
+msgstr ""
+
msgid "Vulnerabilities"
msgstr ""
@@ -27648,34 +28563,31 @@ msgstr ""
msgid "VulnerabilityChart|Severity"
msgstr ""
-msgid "VulnerabilityManagement|A true-positive and will fix"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Change status"
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|Confirm"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Confirmed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
-msgstr ""
-
-msgid "VulnerabilityManagement|Detected %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|A true-positive and will fix"
msgstr ""
-msgid "VulnerabilityManagement|Dismiss"
+msgid "VulnerabilityManagement|Change status"
msgstr ""
-msgid "VulnerabilityManagement|Dismissed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
msgstr ""
-msgid "VulnerabilityManagement|Resolved"
+msgid "VulnerabilityManagement|Detected"
msgstr ""
-msgid "VulnerabilityManagement|Resolved %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Needs triage"
msgstr ""
msgid "VulnerabilityManagement|Something went wrong while trying to delete the comment. Please try again later."
@@ -27726,6 +28638,9 @@ msgstr ""
msgid "Vulnerability|%{scannerName} (version %{scannerVersion})"
msgstr ""
+msgid "Vulnerability|Activity"
+msgstr ""
+
msgid "Vulnerability|Class"
msgstr ""
@@ -27738,6 +28653,9 @@ msgstr ""
msgid "Vulnerability|Description"
msgstr ""
+msgid "Vulnerability|Detected"
+msgstr ""
+
msgid "Vulnerability|Evidence"
msgstr ""
@@ -27801,6 +28719,9 @@ msgstr ""
msgid "Warning: Displaying this diagram might cause performance issues on this page."
msgstr ""
+msgid "We are currently unable to fetch data for the pipeline header."
+msgstr ""
+
msgid "We are currently unable to fetch data for this graph."
msgstr ""
@@ -27840,6 +28761,12 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
+msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
+msgstr ""
+
+msgid "We would like to inform you that your subscription GitLab Enterprise Edition %{plan_name} is nearing its user limit. You have %{active_user_count} active users, which is almost at the user limit of %{maximum_user_count}."
+msgstr ""
+
msgid "We've found no vulnerabilities"
msgstr ""
@@ -27855,6 +28782,12 @@ msgstr ""
msgid "Web terminal"
msgstr ""
+msgid "WebAuthn Devices (%{length})"
+msgstr ""
+
+msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
+msgstr ""
+
msgid "WebIDE|Merge request"
msgstr ""
@@ -27993,15 +28926,9 @@ msgstr ""
msgid "Welcome to the guided GitLab tour"
msgstr ""
-msgid "Welcome to your Issue Board!"
-msgstr ""
-
msgid "Welcome to your issue board!"
msgstr ""
-msgid "We’ve been making changes to %{featureName} and we’d love your feedback %{linkStart}in this issue%{linkEnd} to help us improve the experience."
-msgstr ""
-
msgid "What are you searching for?"
msgstr ""
@@ -28020,6 +28947,9 @@ msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
msgstr ""
+msgid "When enabled, any user visiting %{host} and creating an account will have to be explicitly approved by the admin before they can login. This setting is effective only if sign-ups are enabled."
+msgstr ""
+
msgid "When enabled, any user visiting %{host} will be able to create an account."
msgstr ""
@@ -28244,6 +29174,9 @@ msgstr ""
msgid "With requirements, you can set criteria to check your products against."
msgstr ""
+msgid "With test cases, you can define conditions for your project to meet in determining quality"
+msgstr ""
+
msgid "Withdraw Access Request"
msgstr ""
@@ -28259,6 +29192,9 @@ msgstr ""
msgid "Workflow Help"
msgstr ""
+msgid "Would you like to create a new branch?"
+msgstr ""
+
msgid "Write"
msgstr ""
@@ -28280,6 +29216,9 @@ msgstr ""
msgid "Wrong extern UID provided. Make sure Auth0 is configured correctly."
msgstr ""
+msgid "YYYY-MM-DD"
+msgstr ""
+
msgid "Yes"
msgstr ""
@@ -28337,7 +29276,7 @@ msgstr ""
msgid "You are going to remove the fork relationship from %{project_full_name}. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "You are going to transfer %{project_full_name} to another owner. Are you ABSOLUTELY sure?"
+msgid "You are going to transfer %{project_full_name} to another namespace. Are you ABSOLUTELY sure?"
msgstr ""
msgid "You are going to turn off the confidentiality. This means %{strongStart}everyone%{strongEnd} will be able to see and leave a comment on this %{issuableType}."
@@ -28397,9 +29336,6 @@ msgstr ""
msgid "You can always edit this later"
msgstr ""
-msgid "You can apply your Trial to your Personal account or create a New Group."
-msgstr ""
-
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings"
msgstr ""
@@ -28421,12 +29357,18 @@ msgstr ""
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
+msgid "You can find more information about GitLab subscriptions in %{subscriptions_doc_link}."
+msgstr ""
+
msgid "You can generate an access token scoped to this project for each application to use the GitLab API."
msgstr ""
msgid "You can get started by cloning the repository or start adding files to it with one of the following options."
msgstr ""
+msgid "You can group test cases using labels. To learn about the future direction of this feature, visit %{linkStart}Quality Management direction page%{linkEnd}."
+msgstr ""
+
msgid "You can invite a new member to %{project_name} or invite another group."
msgstr ""
@@ -28442,6 +29384,9 @@ msgstr ""
msgid "You can notify the app / group or a project by sending them an email notification"
msgstr ""
+msgid "You can now close this window."
+msgstr ""
+
msgid "You can now export your security dashboard to a CSV report."
msgstr ""
@@ -28490,9 +29435,6 @@ msgstr ""
msgid "You can test your .gitlab-ci.yml in %{linkStart}CI Lint%{linkEnd}."
msgstr ""
-msgid "You can try again using %{begin_link}basic search%{end_link}"
-msgstr ""
-
msgid "You cannot access the raw file. Please wait a minute."
msgstr ""
@@ -28544,6 +29486,9 @@ msgstr ""
msgid "You don't have any U2F devices registered yet."
msgstr ""
+msgid "You don't have any WebAuthn devices registered yet."
+msgstr ""
+
msgid "You don't have any active chat names."
msgstr ""
@@ -28631,6 +29576,9 @@ msgstr ""
msgid "You must accept our Terms of Service and privacy policy in order to register an account"
msgstr ""
+msgid "You must be logged in to search across all of GitLab"
+msgstr ""
+
msgid "You must disassociate %{domain} from all clusters it is attached to before deletion."
msgstr ""
@@ -28670,7 +29618,7 @@ msgstr ""
msgid "You need to be logged in."
msgstr ""
-msgid "You need to register a two-factor authentication app before you can set up a U2F device."
+msgid "You need to register a two-factor authentication app before you can set up a device."
msgstr ""
msgid "You need to set terms to be enforced"
@@ -28688,6 +29636,9 @@ msgstr ""
msgid "You reached %{usage_in_percent} of %{namespace_name}'s storage capacity (%{used_storage} of %{storage_limit})"
msgstr ""
+msgid "You successfully declined the invitation"
+msgstr ""
+
msgid "You tried to fork %{link_to_the_project} but it failed for the following reason:"
msgstr ""
@@ -28853,10 +29804,13 @@ msgstr ""
msgid "Your U2F device did not send a valid JSON response."
msgstr ""
-msgid "Your U2F device needs to be set up. Plug it in (if not already) and click the button on the left."
+msgid "Your U2F device was registered!"
msgstr ""
-msgid "Your U2F device was registered!"
+msgid "Your WebAuthn device did not send a valid JSON response."
+msgstr ""
+
+msgid "Your WebAuthn device was registered!"
msgstr ""
msgid "Your access request to the %{source_type} has been withdrawn."
@@ -28880,6 +29834,9 @@ msgstr ""
msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
msgstr ""
+msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
+msgstr ""
+
msgid "Your changes can be committed to %{branch_name} because a merge request is open."
msgstr ""
@@ -28916,6 +29873,12 @@ msgstr ""
msgid "Your deployment services will be broken, you will need to manually fix the services after renaming."
msgstr ""
+msgid "Your device is not compatible with GitLab. Please try another device"
+msgstr ""
+
+msgid "Your device needs to be set up. Plug it in (if needed) and click the button on the left."
+msgstr ""
+
msgid "Your device was successfully set up! Give it a name and register it with the GitLab server."
msgstr ""
@@ -29029,9 +29992,6 @@ msgstr[1] ""
msgid "access:"
msgstr ""
-msgid "activated"
-msgstr ""
-
msgid "added %{created_at_timeago}"
msgstr ""
@@ -29104,9 +30064,21 @@ msgstr ""
msgid "by %{user}"
msgstr ""
+msgid "cannot be a date in the past"
+msgstr ""
+
msgid "cannot be changed if a personal project has container registry tags."
msgstr ""
+msgid "cannot be changed if shared runners are enabled"
+msgstr ""
+
+msgid "cannot be enabled because parent group does not allow it"
+msgstr ""
+
+msgid "cannot be enabled because parent group has shared Runners disabled"
+msgstr ""
+
msgid "cannot be enabled unless all domains have TLS certificates"
msgstr ""
@@ -29152,7 +30124,7 @@ msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about SAST %{linkEndTag}"
msgstr ""
-msgid "ciReport|%{linkStartTag}Learn more about Secret Scanning %{linkEndTag}"
+msgid "ciReport|%{linkStartTag}Learn more about Secret Detection %{linkEndTag}"
msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about codequality reports %{linkEndTag}"
@@ -29467,9 +30439,6 @@ msgstr ""
msgid "error"
msgstr ""
-msgid "error code:"
-msgstr ""
-
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr ""
@@ -29491,6 +30460,9 @@ msgstr ""
msgid "failed to dismiss associated finding(id=%{finding_id}): %{message}"
msgstr ""
+msgid "failed to revert associated finding(id=%{finding_id}) to detected"
+msgstr ""
+
msgid "file"
msgid_plural "files"
msgstr[0] ""
@@ -30033,6 +31005,9 @@ msgstr ""
msgid "must be a root namespace"
msgstr ""
+msgid "must be a valid IPv4 or IPv6 address"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -30069,6 +31044,9 @@ msgstr ""
msgid "no expiration"
msgstr ""
+msgid "no name set"
+msgstr ""
+
msgid "no one can merge"
msgstr ""
@@ -30247,9 +31225,6 @@ msgstr ""
msgid "security Reports|There was an error creating the merge request"
msgstr ""
-msgid "settings saved, but not activated"
-msgstr ""
-
msgid "severity|Critical"
msgstr ""
@@ -30376,9 +31351,6 @@ msgstr ""
msgid "toggle collapse"
msgstr ""
-msgid "toggle dropdown"
-msgstr ""
-
msgid "triggered"
msgstr ""
@@ -30406,6 +31378,9 @@ msgstr ""
msgid "user avatar"
msgstr ""
+msgid "user preferences"
+msgstr ""
+
msgid "username"
msgstr ""
diff --git a/locale/hr_HR/gitlab.po b/locale/hr_HR/gitlab.po
index 78881fdfc91..b8e5aaec69e 100644
--- a/locale/hr_HR/gitlab.po
+++ b/locale/hr_HR/gitlab.po
@@ -14,7 +14,10 @@ msgstr ""
"X-Crowdin-Language: hr\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 6\n"
-"PO-Revision-Date: 2020-09-04 23:03\n"
+"PO-Revision-Date: 2020-10-02 18:42\n"
+
+msgid " %{project_name}#%{issue_iid} &middot; opened %{issue_created} by %{author}"
+msgstr ""
msgid " %{start} to %{end}"
msgstr ""
@@ -76,6 +79,18 @@ msgstr ""
msgid "\"el\" parameter is required for createInstance()"
msgstr ""
+msgid "%d Approval"
+msgid_plural "%d Approvals"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
+msgid "%d Package"
+msgid_plural "%d Packages"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "%d Scanned URL"
msgid_plural "%d Scanned URLs"
msgstr[0] ""
@@ -151,6 +166,12 @@ msgstr[2] ""
msgid "%d commits"
msgstr ""
+msgid "%d completed issue"
+msgid_plural "%d completed issues"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "%d contribution"
msgid_plural "%d contributions"
msgstr[0] ""
@@ -163,6 +184,12 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgid "%d day until tags are automatically removed"
+msgid_plural "%d days until tags are automatically removed"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "%d error"
msgid_plural "%d errors"
msgstr[0] ""
@@ -271,6 +298,18 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgid "%d open issue"
+msgid_plural "%d open issues"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
+msgid "%d pending comment"
+msgid_plural "%d pending comments"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "%d personal project will be removed and cannot be restored."
msgid_plural "%d personal projects will be removed and cannot be restored."
msgstr[0] ""
@@ -289,6 +328,12 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgid "%d project selected"
+msgid_plural "%d projects selected"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "%d request with warnings"
msgid_plural "%d requests with warnings"
msgstr[0] ""
@@ -313,6 +358,12 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgid "%d tag per image name"
+msgid_plural "%d tags per image name"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "%d unassigned issue"
msgid_plural "%d unassigned issues"
msgstr[0] ""
@@ -337,6 +388,12 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgid "%d warning found:"
+msgid_plural "%d warnings found:"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "%s additional commit has been omitted to prevent performance issues."
msgid_plural "%s additional commits have been omitted to prevent performance issues."
msgstr[0] ""
@@ -376,6 +433,9 @@ msgstr ""
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr ""
+msgid "%{completedCount} completed weight"
+msgstr ""
+
msgid "%{completedWeight} of %{totalWeight} weight completed"
msgstr ""
@@ -427,15 +487,12 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
-msgid "%{count} pending comment"
-msgid_plural "%{count} pending comments"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
+msgid "%{count} total weight"
+msgstr ""
+
msgid "%{dashboard_path} could not be found."
msgstr ""
@@ -490,6 +547,9 @@ msgstr ""
msgid "%{group_name} uses group managed accounts. You need to create a new GitLab account which will be managed by %{group_name}."
msgstr ""
+msgid "%{group_name}&%{epic_iid} &middot; opened %{epic_created} by %{author}"
+msgstr ""
+
msgid "%{host} sign-in from new location"
msgstr ""
@@ -502,7 +562,7 @@ msgstr ""
msgid "%{issuableType} will be removed! Are you sure?"
msgstr ""
-msgid "%{issuesSize} issues with a limit of %{maxIssueCount}"
+msgid "%{issuesCount} issues with a limit of %{maxIssueCount}"
msgstr ""
msgid "%{issuesSize} with a limit of %{maxIssueCount}"
@@ -535,7 +595,7 @@ msgstr ""
msgid "%{labelStart}Namespace:%{labelEnd} %{namespace}"
msgstr ""
-msgid "%{labelStart}Report Type:%{labelEnd} %{reportType}"
+msgid "%{labelStart}Scan Type:%{labelEnd} %{reportType}"
msgstr ""
msgid "%{labelStart}Scanner:%{labelEnd} %{scanner}"
@@ -739,9 +799,6 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
-msgid "%{service_title} %{message}."
-msgstr ""
-
msgid "%{size} GiB"
msgstr ""
@@ -835,6 +892,12 @@ msgstr ""
msgid "%{timebox_name} should belong either to a project or a group."
msgstr ""
+msgid "%{timebox_type} does not support burnup charts"
+msgstr ""
+
+msgid "%{timebox_type} must have a start and due date"
+msgstr ""
+
msgid "%{title} %{operator} %{threshold}"
msgstr ""
@@ -859,7 +922,7 @@ msgstr ""
msgid "%{total} open issue weight"
msgstr ""
-msgid "%{total} open issues"
+msgid "%{total} warnings found: showing first %{warningsDisplayed}"
msgstr ""
msgid "%{usage_ping_link_start}Learn more%{usage_ping_link_end} about what information is shared with GitLab Inc."
@@ -892,9 +955,6 @@ msgstr ""
msgid "&lt; 1 hour"
msgstr ""
-msgid "&lt;no name set&gt;"
-msgstr ""
-
msgid "&lt;no scopes selected&gt;"
msgstr ""
@@ -925,6 +985,9 @@ msgstr ""
msgid "'%{name}' Value Stream created"
msgstr ""
+msgid "'%{name}' Value Stream deleted"
+msgstr ""
+
msgid "'%{name}' stage already exists"
msgstr ""
@@ -985,6 +1048,9 @@ msgstr ""
msgid "+ %{numberOfHiddenAssignees} more"
msgstr ""
+msgid "+ %{numberOfHiddenReviewers} more"
+msgstr ""
+
msgid "+%d more"
msgid_plural "+%d more"
msgstr[0] ""
@@ -1051,6 +1117,12 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgid "1 Issue"
+msgid_plural "%d Issues"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "1 closed issue"
msgid_plural "%{issues} closed issues"
msgstr[0] ""
@@ -1069,6 +1141,12 @@ msgstr[0] "1 dan"
msgstr[1] "%d dana"
msgstr[2] "%d dana"
+msgid "1 deploy key"
+msgid_plural "%d deploy keys"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1180,6 +1258,9 @@ msgstr ""
msgid ":%{startLine} to %{endLine}"
msgstr ""
+msgid "A %{incident_docs_start}modified issue%{incident_docs_end} to guide the resolution of incidents."
+msgstr ""
+
msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr ""
@@ -1192,6 +1273,9 @@ msgstr ""
msgid "A GitBook site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
+msgid "A Gitpod configured Webapplication in Spring and Java"
+msgstr ""
+
msgid "A Hexo site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
@@ -1363,9 +1447,15 @@ msgstr ""
msgid "Access expiration date"
msgstr ""
+msgid "Access expires"
+msgstr ""
+
msgid "Access forbidden. Check your access level."
msgstr ""
+msgid "Access granted"
+msgstr ""
+
msgid "Access requests"
msgstr ""
@@ -1375,6 +1465,9 @@ msgstr ""
msgid "Access to Pages websites are controlled based on the user's membership to a given project. By checking this box, users will be required to be logged in to have access to all Pages websites in your instance."
msgstr ""
+msgid "AccessDropdown|Deploy Keys"
+msgstr ""
+
msgid "AccessDropdown|Groups"
msgstr ""
@@ -1492,12 +1585,6 @@ msgstr ""
msgid "Active Sessions"
msgstr ""
-msgid "Active Users:"
-msgstr ""
-
-msgid "Active users"
-msgstr ""
-
msgid "Activity"
msgstr ""
@@ -1666,9 +1753,6 @@ msgstr ""
msgid "Add label(s)"
msgstr ""
-msgid "Add license"
-msgstr ""
-
msgid "Add list"
msgstr ""
@@ -1843,21 +1927,51 @@ msgstr ""
msgid "AdminArea|Bots"
msgstr ""
+msgid "AdminArea|Components"
+msgstr ""
+
msgid "AdminArea|Developer"
msgstr ""
+msgid "AdminArea|Features"
+msgstr ""
+
+msgid "AdminArea|Groups: %{number_of_groups}"
+msgstr ""
+
msgid "AdminArea|Guest"
msgstr ""
msgid "AdminArea|Included Free in license"
msgstr ""
+msgid "AdminArea|Latest groups"
+msgstr ""
+
+msgid "AdminArea|Latest projects"
+msgstr ""
+
+msgid "AdminArea|Latest users"
+msgstr ""
+
msgid "AdminArea|Maintainer"
msgstr ""
+msgid "AdminArea|New group"
+msgstr ""
+
+msgid "AdminArea|New project"
+msgstr ""
+
+msgid "AdminArea|New user"
+msgstr ""
+
msgid "AdminArea|Owner"
msgstr ""
+msgid "AdminArea|Projects: %{number_of_projects}"
+msgstr ""
+
msgid "AdminArea|Reporter"
msgstr ""
@@ -1885,6 +1999,9 @@ msgstr ""
msgid "AdminArea|Users without a Group and Project"
msgstr ""
+msgid "AdminArea|Users: %{number_of_users}"
+msgstr ""
+
msgid "AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running."
msgstr ""
@@ -1903,9 +2020,6 @@ msgstr ""
msgid "AdminProjects|Delete Project %{projectName}?"
msgstr ""
-msgid "AdminProjects|Delete project"
-msgstr ""
-
msgid "AdminSettings|Apply integration settings to all Projects"
msgstr ""
@@ -2143,21 +2257,30 @@ msgstr ""
msgid "AdminUsers|Without projects"
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 ""
msgid "AdminUsers|You cannot remove your own admin rights."
msgstr ""
+msgid "AdminUsers|You must transfer ownership or delete the groups owned by this user before you can delete their account"
+msgstr ""
+
msgid "Administration"
msgstr ""
msgid "Advanced"
msgstr ""
+msgid "Advanced Search"
+msgstr ""
+
+msgid "Advanced Search with Elasticsearch"
+msgstr ""
+
msgid "Advanced Settings"
msgstr ""
@@ -2236,6 +2359,9 @@ msgstr ""
msgid "AlertManagement|Edit"
msgstr ""
+msgid "AlertManagement|Environment"
+msgstr ""
+
msgid "AlertManagement|Events"
msgstr ""
@@ -2248,6 +2374,9 @@ msgstr ""
msgid "AlertManagement|Issue"
msgstr ""
+msgid "AlertManagement|Key"
+msgstr ""
+
msgid "AlertManagement|Low"
msgstr ""
@@ -2341,6 +2470,9 @@ msgstr ""
msgid "AlertManagement|Unknown"
msgstr ""
+msgid "AlertManagement|Value"
+msgstr ""
+
msgid "AlertManagement|View alerts in Opsgenie"
msgstr ""
@@ -2500,6 +2632,9 @@ msgstr ""
msgid "All projects"
msgstr ""
+msgid "All projects selected"
+msgstr ""
+
msgid "All security scans are enabled because %{linkStart}Auto DevOps%{linkEnd} is enabled on this project"
msgstr ""
@@ -2587,6 +2722,9 @@ msgstr ""
msgid "Almost there"
msgstr ""
+msgid "Already blocked"
+msgstr ""
+
msgid "Also called \"Issuer\" or \"Relying party trust identifier\""
msgstr ""
@@ -2641,6 +2779,9 @@ msgstr ""
msgid "An error has occurred"
msgstr ""
+msgid "An error occured while making the changes: %{error}"
+msgstr ""
+
msgid "An error occurred adding a draft to the thread."
msgstr ""
@@ -2668,12 +2809,6 @@ msgstr ""
msgid "An error occurred when toggling the notification subscription"
msgstr ""
-msgid "An error occurred when trying to resolve a comment. Please try again."
-msgstr ""
-
-msgid "An error occurred when trying to resolve a discussion. Please try again."
-msgstr ""
-
msgid "An error occurred when updating the issue weight"
msgstr ""
@@ -2689,12 +2824,6 @@ msgstr ""
msgid "An error occurred while checking group path. Please refresh and try again."
msgstr ""
-msgid "An error occurred while committing your changes."
-msgstr ""
-
-msgid "An error occurred while creating the list. Please try again."
-msgstr ""
-
msgid "An error occurred while decoding the file."
msgstr ""
@@ -2767,25 +2896,19 @@ msgstr ""
msgid "An error occurred while fetching the Service Desk address."
msgstr ""
-msgid "An error occurred while fetching the board issues. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the board lists. Please reload the page."
msgstr ""
msgid "An error occurred while fetching the board lists. Please try again."
msgstr ""
-msgid "An error occurred while fetching the board swimlanes. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the builds."
msgstr ""
msgid "An error occurred while fetching the job log."
msgstr ""
-msgid "An error occurred while fetching the job trace."
+msgid "An error occurred while fetching the job logs."
msgstr ""
msgid "An error occurred while fetching the job."
@@ -2932,9 +3055,6 @@ msgstr ""
msgid "An error occurred while saving assignees"
msgstr ""
-msgid "An error occurred while saving the template. Please check if the template exists."
-msgstr ""
-
msgid "An error occurred while searching for milestones"
msgstr ""
@@ -2953,10 +3073,10 @@ msgstr ""
msgid "An error occurred while updating approvers"
msgstr ""
-msgid "An error occurred while updating the comment"
+msgid "An error occurred while updating labels."
msgstr ""
-msgid "An error occurred while updating the list. Please try again."
+msgid "An error occurred while updating the comment"
msgstr ""
msgid "An error occurred while validating group path"
@@ -3010,6 +3130,9 @@ msgstr ""
msgid "An unknown error occurred while loading this graph."
msgstr ""
+msgid "An unknown error occurred."
+msgstr ""
+
msgid "Analytics"
msgstr ""
@@ -3043,10 +3166,10 @@ msgstr ""
msgid "Any"
msgstr ""
-msgid "Any Author"
+msgid "Any %{header}"
msgstr ""
-msgid "Any Status"
+msgid "Any Author"
msgstr ""
msgid "Any branch"
@@ -3100,6 +3223,9 @@ msgstr ""
msgid "Application ID"
msgstr ""
+msgid "Application limits saved successfully"
+msgstr ""
+
msgid "Application settings saved successfully"
msgstr ""
@@ -3313,6 +3439,9 @@ msgstr ""
msgid "Are you sure you want to close this blocked issue?"
msgstr ""
+msgid "Are you sure you want to delete \"%{name}\" Value Stream?"
+msgstr ""
+
msgid "Are you sure you want to delete %{name}?"
msgstr ""
@@ -3322,6 +3451,9 @@ msgstr ""
msgid "Are you sure you want to delete this %{typeOfComment}?"
msgstr ""
+msgid "Are you sure you want to delete this SSH key?"
+msgstr ""
+
msgid "Are you sure you want to delete this board?"
msgstr ""
@@ -3346,6 +3478,12 @@ msgstr ""
msgid "Are you sure you want to erase this build?"
msgstr ""
+msgid "Are you sure you want to import %d repository?"
+msgid_plural "Are you sure you want to import %d repositories?"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "Are you sure you want to lose unsaved changes?"
msgstr ""
@@ -3355,15 +3493,15 @@ msgstr ""
msgid "Are you sure you want to merge immediately?"
msgstr ""
-msgid "Are you sure you want to permanently delete this license?"
-msgstr ""
-
msgid "Are you sure you want to re-deploy this environment?"
msgstr ""
msgid "Are you sure you want to regenerate the public key? You will have to update the public key on the remote server before mirroring will work again."
msgstr ""
+msgid "Are you sure you want to reindex?"
+msgstr ""
+
msgid "Are you sure you want to remove %{group_name}?"
msgstr ""
@@ -3391,6 +3529,9 @@ msgstr ""
msgid "Are you sure you want to revoke this nickname?"
msgstr ""
+msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
+msgstr ""
+
msgid "Are you sure you want to stop this environment?"
msgstr ""
@@ -3412,6 +3553,9 @@ msgstr ""
msgid "Are you sure? The device will be signed out of GitLab and all remember me tokens revoked."
msgstr ""
+msgid "Are you sure? This will invalidate your registered applications and U2F / WebAuthn devices."
+msgstr ""
+
msgid "Are you sure? This will invalidate your registered applications and U2F devices."
msgstr ""
@@ -3430,9 +3574,6 @@ msgstr ""
msgid "Artifacts"
msgstr ""
-msgid "As U2F devices are only supported by a few browsers, we require that you set up a two-factor authentication app before a U2F device. That way you'll always be able to log in - even when you're using an unsupported browser."
-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 ""
@@ -3628,6 +3769,9 @@ msgstr ""
msgid "AuditLogs|Target"
msgstr ""
+msgid "AuditLogs|This month"
+msgstr ""
+
msgid "AuditLogs|User Events"
msgstr ""
@@ -3667,6 +3811,9 @@ msgstr ""
msgid "Authentication via U2F device failed."
msgstr ""
+msgid "Authentication via WebAuthn device failed."
+msgstr ""
+
msgid "Author"
msgstr ""
@@ -3934,15 +4081,6 @@ msgstr ""
msgid "BambooService|You must set up automatic revision labeling and a repository trigger in Bamboo."
msgstr ""
-msgid "BatchComments|Delete all pending comments"
-msgstr ""
-
-msgid "BatchComments|Discard review?"
-msgstr ""
-
-msgid "BatchComments|You're about to discard your review which will delete all of your pending comments. The deleted comments %{strong_start}cannot%{strong_end} be restored."
-msgstr ""
-
msgid "Be careful. Changing the project's namespace can have unintended side effects."
msgstr ""
@@ -3964,6 +4102,9 @@ msgstr ""
msgid "Bi-weekly code coverage"
msgstr ""
+msgid "Billable Users:"
+msgstr ""
+
msgid "Billing"
msgstr ""
@@ -3973,7 +4114,7 @@ msgstr ""
msgid "BillingPlans|@%{user_name} you are currently using the %{plan_name} plan."
msgstr ""
-msgid "BillingPlans|Congratulations, your new trial is activated"
+msgid "BillingPlans|Congratulations, your free trial is activated."
msgstr ""
msgid "BillingPlans|If you would like to downgrade your plan please contact %{support_link_start}Customer Support%{support_link_end}."
@@ -4036,6 +4177,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Block user"
+msgstr ""
+
msgid "Blocked"
msgstr ""
@@ -4051,31 +4195,37 @@ msgstr ""
msgid "Blog"
msgstr ""
-msgid "Board name"
-msgstr ""
-
msgid "Board scope"
msgstr ""
msgid "Board scope affects which issues are displayed for anyone who visits this board"
msgstr ""
-msgid "BoardBlankState|Add default lists"
+msgid "Boards"
msgstr ""
-msgid "BoardBlankState|Add the following default lists to your Issue Board with one click:"
+msgid "Boards and Board Lists"
msgstr ""
-msgid "BoardBlankState|Nevermind, I'll use my own"
+msgid "Boards|An error occurred while creating the issue. Please try again."
msgstr ""
-msgid "BoardBlankState|Starting out with the default set of lists will get you right on the way to making the most of your board."
+msgid "Boards|An error occurred while creating the list. Please try again."
msgstr ""
-msgid "Boards"
+msgid "Boards|An error occurred while fetching issues. Please reload the page."
msgstr ""
-msgid "Boards and Board Lists"
+msgid "Boards|An error occurred while fetching the board issues. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching the board swimlanes. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while moving the issue. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while updating the list. Please try again."
msgstr ""
msgid "Boards|Collapse"
@@ -4102,7 +4252,7 @@ msgstr ""
msgid "Branch %{branch_name} was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr ""
-msgid "Branch has changed"
+msgid "Branch changed"
msgstr ""
msgid "Branch is already taken"
@@ -4408,6 +4558,9 @@ msgstr ""
msgid "CLOSED (MOVED)"
msgstr ""
+msgid "CODEOWNERS rule violation"
+msgstr ""
+
msgid "CONTRIBUTING"
msgstr ""
@@ -4438,9 +4591,6 @@ msgstr ""
msgid "Can't create snippet: %{err}"
msgstr ""
-msgid "Can't edit as source branch was deleted"
-msgstr ""
-
msgid "Can't fetch content for the blob: %{err}"
msgstr ""
@@ -4453,9 +4603,6 @@ msgstr ""
msgid "Can't load mermaid module: %{err}"
msgstr ""
-msgid "Can't remove group members without group managed account"
-msgstr ""
-
msgid "Can't scan the code?"
msgstr ""
@@ -4498,6 +4645,9 @@ msgstr ""
msgid "Cannot create the abuse report. This user has been blocked."
msgstr ""
+msgid "Cannot enable shared runners because parent group does not allow it"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -4603,6 +4753,15 @@ msgstr ""
msgid "Change your password or recover your current one"
msgstr ""
+msgid "ChangeReviewer|Reviewer changed from %{old} to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Reviewer changed to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Unassigned"
+msgstr ""
+
msgid "ChangeTypeActionLabel|Pick into branch"
msgstr ""
@@ -4642,6 +4801,9 @@ msgstr ""
msgid "Changes the title to \"%{title_param}\"."
msgstr ""
+msgid "Changes were successfully made."
+msgstr ""
+
msgid "Changes won't take place until the index is %{link_start}recreated%{link_end}."
msgstr ""
@@ -5047,6 +5209,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove variable"
+msgstr ""
+
msgid "CiVariables|Remove variable row"
msgstr ""
@@ -5125,9 +5290,6 @@ msgstr ""
msgid "Clear due date"
msgstr ""
-msgid "Clear input"
-msgstr ""
-
msgid "Clear recent searches"
msgstr ""
@@ -5176,6 +5338,9 @@ msgstr ""
msgid "Client authentication key password"
msgstr ""
+msgid "Client request timeout"
+msgstr ""
+
msgid "Clients"
msgstr ""
@@ -5260,6 +5425,27 @@ msgstr ""
msgid "Cluster type must be specificed for Stages::ClusterEndpointInserter"
msgstr ""
+msgid "ClusterAgents|Configuration"
+msgstr ""
+
+msgid "ClusterAgents|Connect your cluster with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate Kubernetes with a GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Name"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Agent also requires %{linkStart}enabling the Agent Server%{linkEnd}"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Kubernetes Agent allows an Infrastructure as Code, GitOps approach to integrating Kubernetes clusters with GitLab. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "ClusterAgent|This feature is only available for premium plans"
msgstr ""
@@ -5329,10 +5515,10 @@ msgstr ""
msgid "ClusterIntegration|All installed applications and related resources"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster."
+msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{linkStart}More information%{linkEnd}"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{startLink}More information%{endLink}"
+msgid "ClusterIntegration|Allow GitLab to manage namespaces and service accounts for this cluster."
msgstr ""
msgid "ClusterIntegration|Alternatively, "
@@ -5353,6 +5539,9 @@ msgstr ""
msgid "ClusterIntegration|An error occurred while trying to fetch zone machine types: %{error}"
msgstr ""
+msgid "ClusterIntegration|An unknown error occurred while attempting to connect to Kubernetes."
+msgstr ""
+
msgid "ClusterIntegration|Any project namespaces"
msgstr ""
@@ -5368,6 +5557,9 @@ msgstr ""
msgid "ClusterIntegration|Authenticate with Amazon Web Services"
msgstr ""
+msgid "ClusterIntegration|Authentication Error"
+msgstr ""
+
msgid "ClusterIntegration|Base domain"
msgstr ""
@@ -5386,13 +5578,22 @@ msgstr ""
msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}security group %{externalLinkIcon} %{endLink} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
+msgid "ClusterIntegration|Check your CA certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Check your cluster status"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}subnets %{externalLinkIcon} %{endLink} in your VPC where your worker nodes will run."
+msgid "ClusterIntegration|Check your token"
msgstr ""
-msgid "ClusterIntegration|Choose the worker node %{startLink}instance type %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Choose the %{linkStart}security group %{linkEnd} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
+msgstr ""
+
+msgid "ClusterIntegration|Choose the %{linkStart}subnets %{linkEnd} in your VPC where your worker nodes will run."
+msgstr ""
+
+msgid "ClusterIntegration|Choose the worker node %{linkStart}instance type%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Choose which applications to install on your Kubernetes cluster."
@@ -5404,10 +5605,7 @@ msgstr ""
msgid "ClusterIntegration|Clear cluster cache"
msgstr ""
-msgid "ClusterIntegration|Clear the local cache of namespace and service accounts. This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
-msgstr ""
-
-msgid "ClusterIntegration|Cluster being created"
+msgid "ClusterIntegration|Clear the local cache of namespace and service accounts."
msgstr ""
msgid "ClusterIntegration|Cluster management project (alpha)"
@@ -5419,15 +5617,21 @@ msgstr ""
msgid "ClusterIntegration|Cluster_applications artifact too big. Maximum allowable size: %{human_size}"
msgstr ""
-msgid "ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters."
+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|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}"
+msgid "ClusterIntegration|Clusters connected with a certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Connect cluster with certificate"
msgstr ""
msgid "ClusterIntegration|Connect existing cluster"
msgstr ""
+msgid "ClusterIntegration|Connection Error"
+msgstr ""
+
msgid "ClusterIntegration|Copy API URL"
msgstr ""
@@ -5503,6 +5707,12 @@ msgstr ""
msgid "ClusterIntegration|Deletes all GitLab resources attached to this cluster during removal"
msgstr ""
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared."
+msgstr ""
+
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared. %{linkStart}More information%{linkEnd}"
+msgstr ""
+
msgid "ClusterIntegration|Did you know?"
msgstr ""
@@ -5572,6 +5782,9 @@ msgstr ""
msgid "ClusterIntegration|Fluentd is an open source data collector, which lets you unify the data collection and consumption for a better use and understanding of data. It requires at least one of the following logs to be successfully installed."
msgstr ""
+msgid "ClusterIntegration|GitLab Agent managed clusters"
+msgstr ""
+
msgid "ClusterIntegration|GitLab Container Network Policies"
msgstr ""
@@ -5584,6 +5797,12 @@ msgstr ""
msgid "ClusterIntegration|GitLab Runner connects to the repository and executes CI/CD jobs, pushing results back and deploying applications to production."
msgstr ""
+msgid "ClusterIntegration|GitLab failed to authenticate."
+msgstr ""
+
+msgid "ClusterIntegration|GitLab failed to connect to the cluster."
+msgstr ""
+
msgid "ClusterIntegration|GitLab-managed cluster"
msgstr ""
@@ -5605,6 +5824,9 @@ msgstr ""
msgid "ClusterIntegration|Group cluster"
msgstr ""
+msgid "ClusterIntegration|HTTP Error"
+msgstr ""
+
msgid "ClusterIntegration|Helm Tiller"
msgstr ""
@@ -5638,7 +5860,10 @@ msgstr ""
msgid "ClusterIntegration|Instance type"
msgstr ""
-msgid "ClusterIntegration|Integrate Kubernetes cluster automation"
+msgid "ClusterIntegration|Integrate Kubernetes with a cluster certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Integrate with a cluster certificate"
msgstr ""
msgid "ClusterIntegration|Issuer Email"
@@ -5674,9 +5899,6 @@ msgstr ""
msgid "ClusterIntegration|Knative extends Kubernetes to provide a set of middleware components that are essential to build modern, source-centric, and container-based applications that can run anywhere: on premises, in the cloud, or even in a third-party data center."
msgstr ""
-msgid "ClusterIntegration|Kubernetes cluster"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes cluster is being created..."
msgstr ""
@@ -5689,9 +5911,6 @@ msgstr ""
msgid "ClusterIntegration|Kubernetes clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr ""
-msgid "ClusterIntegration|Kubernetes clusters can be used to deploy applications and to provide Review Apps for this project"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes version"
msgstr ""
@@ -5704,7 +5923,7 @@ msgstr ""
msgid "ClusterIntegration|Learn more about %{help_link_start}zones%{help_link_end}."
msgstr ""
-msgid "ClusterIntegration|Learn more about %{startLink}Regions %{externalLinkIcon}%{endLink}."
+msgid "ClusterIntegration|Learn more about %{linkStart}Regions%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Learn more about Kubernetes"
@@ -5749,12 +5968,18 @@ msgstr ""
msgid "ClusterIntegration|Machine type"
msgstr ""
+msgid "ClusterIntegration|Make sure your API endpoint is correct"
+msgstr ""
+
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create Kubernetes clusters"
msgstr ""
msgid "ClusterIntegration|Manage your Kubernetes cluster by visiting %{provider_link}"
msgstr ""
+msgid "ClusterIntegration|Namespace per environment"
+msgstr ""
+
msgid "ClusterIntegration|No IAM Roles found"
msgstr ""
@@ -5800,6 +6025,9 @@ msgstr ""
msgid "ClusterIntegration|No zones matched your search"
msgstr ""
+msgid "ClusterIntegration|Node calculations use the Kubernetes Metrics API. Make sure your cluster has metrics installed"
+msgstr ""
+
msgid "ClusterIntegration|Number of nodes"
msgstr ""
@@ -5842,6 +6070,9 @@ msgstr ""
msgid "ClusterIntegration|RBAC-enabled cluster"
msgstr ""
+msgid "ClusterIntegration|Read our %{linkStart}help page%{linkEnd} on Kubernetes cluster integration."
+msgstr ""
+
msgid "ClusterIntegration|Read our %{link_start}help page%{link_end} on Kubernetes cluster integration."
msgstr ""
@@ -5944,7 +6175,7 @@ msgstr ""
msgid "ClusterIntegration|Select a VPC to choose a subnet"
msgstr ""
-msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{linkStart}Amazon Web Services %{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select a network to choose a subnetwork"
@@ -5977,7 +6208,7 @@ msgstr ""
msgid "ClusterIntegration|Select project to choose zone"
msgstr ""
-msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select zone"
@@ -6067,9 +6298,18 @@ msgstr ""
msgid "ClusterIntegration|There was a problem authenticating with your cluster. Please ensure your CA Certificate and Token are valid."
msgstr ""
+msgid "ClusterIntegration|There was an HTTP error when connecting to your cluster."
+msgstr ""
+
msgid "ClusterIntegration|This account must have permissions to create a Kubernetes cluster in the %{link_to_container_project} specified below"
msgstr ""
+msgid "ClusterIntegration|This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
+msgstr ""
+
+msgid "ClusterIntegration|This is necessary to clear existing environment-namespace associations from clusters previously managed by GitLab."
+msgstr ""
+
msgid "ClusterIntegration|This option will allow you to install applications on RBAC clusters."
msgstr ""
@@ -6094,9 +6334,21 @@ msgstr ""
msgid "ClusterIntegration|To use a new project, first create one on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}."
msgstr ""
+msgid "ClusterIntegration|Troubleshooting tips:"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Authenticate"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Connect"
+msgstr ""
+
msgid "ClusterIntegration|Uninstall %{appTitle}"
msgstr ""
+msgid "ClusterIntegration|Unknown Error"
+msgstr ""
+
msgid "ClusterIntegration|Update %{appTitle}"
msgstr ""
@@ -6157,7 +6409,7 @@ msgstr ""
msgid "ClusterIntegration|Your cluster API is unreachable. Please ensure your API URL is correct."
msgstr ""
-msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Zone"
@@ -6277,6 +6529,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse all threads"
+msgstr ""
+
msgid "Collapse approvers"
msgstr ""
@@ -6427,7 +6682,7 @@ msgstr ""
msgid "Commit…"
msgstr ""
-msgid "Company"
+msgid "Community forum"
msgstr ""
msgid "Company name"
@@ -6436,6 +6691,9 @@ msgstr ""
msgid "Compare"
msgstr ""
+msgid "Compare %{oldCommitId}...%{newCommitId}"
+msgstr ""
+
msgid "Compare Git revisions"
msgstr ""
@@ -6451,6 +6709,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare submodule commit revisions"
+msgstr ""
+
msgid "Compare with previous version"
msgstr ""
@@ -6586,6 +6847,9 @@ msgstr ""
msgid "Configure the way a user creates a new account."
msgstr ""
+msgid "Configure which lists are shown for anyone who visits this board"
+msgstr ""
+
msgid "Confirm"
msgstr ""
@@ -6814,6 +7078,9 @@ msgstr[2] ""
msgid "ContainerRegistry|Set cleanup policy"
msgstr ""
+msgid "ContainerRegistry|Some tags were not deleted"
+msgstr ""
+
msgid "ContainerRegistry|Something went wrong while fetching the cleanup policy."
msgstr ""
@@ -6853,6 +7120,9 @@ msgstr ""
msgid "ContainerRegistry|Tags with names matching this regex pattern will %{italicStart}expire:%{italicEnd}"
msgstr ""
+msgid "ContainerRegistry|The cleanup policy timed out before it could delete all tags. An administrator can %{adminLinkStart}manually run cleanup now%{adminLinkEnd} or you can wait for the cleanup policy to automatically run again. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "ContainerRegistry|The last tag related to this image was recently removed. This empty image and any associated data will be automatically removed as part of the regular Garbage Collection process. If you have any questions, contact your administrator."
msgstr ""
@@ -6985,6 +7255,9 @@ msgstr ""
msgid "Contributions per group member"
msgstr ""
+msgid "Contributor"
+msgstr ""
+
msgid "Contributors"
msgstr ""
@@ -7114,6 +7387,9 @@ msgstr ""
msgid "Could not change HEAD: branch '%{branch}' does not exist"
msgstr ""
+msgid "Could not commit. An unexpected error occurred."
+msgstr ""
+
msgid "Could not connect to FogBugz, check your URL"
msgstr ""
@@ -7153,6 +7429,9 @@ msgstr ""
msgid "Could not find iteration"
msgstr ""
+msgid "Could not load instance counts. Please refresh the page to try again."
+msgstr ""
+
msgid "Could not remove the trigger."
msgstr ""
@@ -7177,10 +7456,10 @@ msgstr ""
msgid "Could not save prometheus manual configuration"
msgstr ""
-msgid "Could not udpdate wiki page"
+msgid "Could not update the LDAP settings"
msgstr ""
-msgid "Could not update the LDAP settings"
+msgid "Could not update wiki page"
msgstr ""
msgid "Could not upload your designs as one or more files uploaded are not supported."
@@ -7840,6 +8119,9 @@ msgstr ""
msgid "DastProfiles|Are you sure you want to delete this profile?"
msgstr ""
+msgid "DastProfiles|Could not create site validation token. Please refresh the page, or try again later."
+msgstr ""
+
msgid "DastProfiles|Could not create the scanner profile. Please try again."
msgstr ""
@@ -7864,6 +8146,12 @@ msgstr ""
msgid "DastProfiles|Could not fetch site profiles. Please refresh the page, or try again later."
msgstr ""
+msgid "DastProfiles|Could not retrieve site validation status. Please refresh the page, or try again later."
+msgstr ""
+
+msgid "DastProfiles|Could not update the scanner profile. Please try again."
+msgstr ""
+
msgid "DastProfiles|Could not update the site profile. Please try again."
msgstr ""
@@ -7879,7 +8167,7 @@ msgstr ""
msgid "DastProfiles|Download validation text file"
msgstr ""
-msgid "DastProfiles|Edit feature will come soon. Please create a new profile if changes needed"
+msgid "DastProfiles|Edit scanner profile"
msgstr ""
msgid "DastProfiles|Edit site profile"
@@ -7912,6 +8200,9 @@ msgstr ""
msgid "DastProfiles|No profiles created yet"
msgstr ""
+msgid "DastProfiles|Passive"
+msgstr ""
+
msgid "DastProfiles|Please enter a valid URL format, ex: http://www.example.com/home"
msgstr ""
@@ -7927,6 +8218,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan mode"
+msgstr ""
+
msgid "DastProfiles|Scanner Profile"
msgstr ""
@@ -7966,10 +8260,10 @@ msgstr ""
msgid "DastProfiles|Text file validation"
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
+msgid "DastProfiles|The maximum number of minutes allowed for the spider to traverse the site."
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the spider to traverse the site."
+msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
msgstr ""
msgid "DastProfiles|Validate"
@@ -8002,6 +8296,9 @@ msgstr ""
msgid "Date picker"
msgstr ""
+msgid "Date range"
+msgstr ""
+
msgid "Date range cannot exceed %{maxDateRange} days."
msgstr ""
@@ -8026,6 +8323,9 @@ msgstr ""
msgid "Days to merge"
msgstr ""
+msgid "Dear Administrator,"
+msgstr ""
+
msgid "Debug"
msgstr ""
@@ -8137,12 +8437,18 @@ msgstr ""
msgid "Delete"
msgstr ""
+msgid "Delete %{name}"
+msgstr ""
+
msgid "Delete Comment"
msgstr ""
msgid "Delete Snippet"
msgstr ""
+msgid "Delete Value Stream"
+msgstr ""
+
msgid "Delete account"
msgstr ""
@@ -8164,9 +8470,6 @@ msgstr ""
msgid "Delete label: %{label_name} ?"
msgstr ""
-msgid "Delete license"
-msgstr ""
-
msgid "Delete list"
msgstr ""
@@ -8242,15 +8545,6 @@ msgstr ""
msgid "Deleting a project places it into a read-only state until %{date}, at which point the project will be permanently deleted. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "Deleting the license failed."
-msgstr ""
-
-msgid "Deleting the license failed. The license was not found."
-msgstr ""
-
-msgid "Deleting the license failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "Deleting the project will delete its repository and all related resources including issues, merge requests etc."
msgstr ""
@@ -8752,7 +9046,10 @@ msgstr ""
msgid "DesignManagement|The maximum number of designs allowed to be uploaded is %{upload_limit}. Please try again."
msgstr ""
-msgid "DesignManagement|To upload designs, you'll need to enable LFS. %{requirements_link_start}More information%{requirements_link_end}"
+msgid "DesignManagement|There was an error moving your designs. Please upload your designs below."
+msgstr ""
+
+msgid "DesignManagement|To upload designs, you'll need to enable LFS and have admin enable hashed storage. %{requirements_link_start}More information%{requirements_link_end}"
msgstr ""
msgid "DesignManagement|Unresolve thread"
@@ -8764,6 +9061,9 @@ msgstr ""
msgid "DesignManagement|Upload skipped."
msgstr ""
+msgid "DesignManagement|Your designs are being copied and are on their way… Please refresh to update."
+msgstr ""
+
msgid "DesignManagement|and %{moreCount} more."
msgstr ""
@@ -8821,6 +9121,9 @@ msgstr ""
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
+msgid "Direct member"
+msgstr ""
+
msgid "Direction"
msgstr ""
@@ -8869,9 +9172,6 @@ msgstr ""
msgid "Discard draft"
msgstr ""
-msgid "Discard review"
-msgstr ""
-
msgid "DiscordService|Discord Notifications"
msgstr ""
@@ -8941,10 +9241,10 @@ msgstr ""
msgid "Dismiss Merge Request promotion"
msgstr ""
-msgid "Dismiss Selected"
+msgid "Dismiss Value Stream Analytics introduction box"
msgstr ""
-msgid "Dismiss Value Stream Analytics introduction box"
+msgid "Dismiss selected"
msgstr ""
msgid "Dismiss trial promotion"
@@ -8995,9 +9295,6 @@ msgstr ""
msgid "Documents reindexed: %{processed_documents} (%{percentage}%%)"
msgstr ""
-msgid "Doing"
-msgstr ""
-
msgid "Domain"
msgstr ""
@@ -9193,9 +9490,6 @@ msgstr ""
msgid "Edit environment"
msgstr ""
-msgid "Edit file"
-msgstr ""
-
msgid "Edit files in the editor and commit changes here"
msgstr ""
@@ -9208,6 +9502,12 @@ msgstr ""
msgid "Edit identity for %{user_name}"
msgstr ""
+msgid "Edit in Web IDE"
+msgstr ""
+
+msgid "Edit in single-file editor"
+msgstr ""
+
msgid "Edit issues"
msgstr ""
@@ -9235,10 +9535,10 @@ msgstr ""
msgid "Editing"
msgstr ""
-msgid "Elasticsearch"
+msgid "Elasticsearch AWS IAM credentials"
msgstr ""
-msgid "Elasticsearch AWS IAM credentials"
+msgid "Elasticsearch HTTP client timeout value in seconds."
msgstr ""
msgid "Elasticsearch indexing restrictions"
@@ -9247,9 +9547,6 @@ msgstr ""
msgid "Elasticsearch indexing started"
msgstr ""
-msgid "Elasticsearch integration. Elasticsearch AWS IAM."
-msgstr ""
-
msgid "Elasticsearch reindexing is already in progress"
msgstr ""
@@ -9277,9 +9574,6 @@ msgstr ""
msgid "Email Notification"
msgstr ""
-msgid "Email address"
-msgstr ""
-
msgid "Email could not be sent"
msgstr ""
@@ -9343,6 +9637,9 @@ msgstr ""
msgid "Emails sent from Service Desk will have this name"
msgstr ""
+msgid "Emails sent to %{email} will still be supported"
+msgstr ""
+
msgid "Emails separated by comma"
msgstr ""
@@ -9376,9 +9673,18 @@ msgstr ""
msgid "Enable"
msgstr ""
+msgid "Enable %{link_start}Gitpod%{link_end} integration to launch a development environment in your browser directly from GitLab."
+msgstr ""
+
msgid "Enable Auto DevOps"
msgstr ""
+msgid "Enable Gitpod"
+msgstr ""
+
+msgid "Enable Gitpod?"
+msgstr ""
+
msgid "Enable HTML emails"
msgstr ""
@@ -9508,9 +9814,6 @@ msgstr ""
msgid "Encountered an error while rendering: %{err}"
msgstr ""
-msgid "End date"
-msgstr ""
-
msgid "Ends at (UTC)"
msgstr ""
@@ -9670,7 +9973,7 @@ msgstr ""
msgid "EnvironmentsDashboard|The environments dashboard provides a summary of each project's environments' status, including pipeline and alert statuses."
msgstr ""
-msgid "EnvironmentsDashboard|This dashboard displays a maximum of 7 projects and 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
+msgid "EnvironmentsDashboard|This dashboard displays 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
msgstr ""
msgid "Environments|An error occurred while canceling the auto stop, please try again"
@@ -9991,6 +10294,9 @@ msgstr ""
msgid "Error deleting project. Check logs for error details."
msgstr ""
+msgid "Error fetching burnup chart data"
+msgstr ""
+
msgid "Error fetching diverging counts for branches. Please try again."
msgstr ""
@@ -10069,6 +10375,9 @@ msgstr ""
msgid "Error occurred when saving assignees"
msgstr ""
+msgid "Error occurred when saving reviewers"
+msgstr ""
+
msgid "Error occurred when toggling the notification subscription"
msgstr ""
@@ -10321,10 +10630,13 @@ msgstr ""
msgid "Expand all"
msgstr ""
-msgid "Expand approvers"
+msgid "Expand all files"
+msgstr ""
+
+msgid "Expand all threads"
msgstr ""
-msgid "Expand dropdown"
+msgid "Expand approvers"
msgstr ""
msgid "Expand milestones"
@@ -10495,6 +10807,9 @@ msgstr ""
msgid "Failed to create Merge Request. Please try again."
msgstr ""
+msgid "Failed to create To-Do for the design."
+msgstr ""
+
msgid "Failed to create a branch for this issue. Please try again."
msgstr ""
@@ -10534,6 +10849,12 @@ msgstr ""
msgid "Failed to load authors. Please try again."
msgstr ""
+msgid "Failed to load branches. Please try again."
+msgstr ""
+
+msgid "Failed to load deploy keys."
+msgstr ""
+
msgid "Failed to load emoji list."
msgstr ""
@@ -10549,6 +10870,9 @@ msgstr ""
msgid "Failed to load groups & users."
msgstr ""
+msgid "Failed to load groups, users and deploy keys."
+msgstr ""
+
msgid "Failed to load labels. Please try again."
msgstr ""
@@ -10558,6 +10882,12 @@ msgstr ""
msgid "Failed to load related branches"
msgstr ""
+msgid "Failed to load sidebar confidential toggle"
+msgstr ""
+
+msgid "Failed to load sidebar lock status"
+msgstr ""
+
msgid "Failed to load stacktrace."
msgstr ""
@@ -10585,6 +10915,9 @@ msgstr ""
msgid "Failed to publish issue on status page."
msgstr ""
+msgid "Failed to remove To-Do for the design."
+msgstr ""
+
msgid "Failed to remove a Zoom meeting"
msgstr ""
@@ -10627,6 +10960,9 @@ msgstr ""
msgid "Failed to signing using smartcard authentication"
msgstr ""
+msgid "Failed to toggle To-Do for the design."
+msgstr ""
+
msgid "Failed to update branch!"
msgstr ""
@@ -10741,7 +11077,7 @@ msgstr ""
msgid "FeatureFlags|Edit User List"
msgstr ""
-msgid "FeatureFlags|Enable features for specific users and specific environments by defining feature flag strategies."
+msgid "FeatureFlags|Enable features for specific users and environments by configuring feature flag strategies."
msgstr ""
msgid "FeatureFlags|Environment Spec"
@@ -10801,7 +11137,7 @@ msgstr ""
msgid "FeatureFlags|Include additional user IDs"
msgstr ""
-msgid "FeatureFlags|Install a %{docs_link_anchored_start}compatible client library%{docs_link_anchored_end} and specify the API URL, application name, and instance ID during the configuration setup. %{docs_link_start}More Information%{docs_link_end}"
+msgid "FeatureFlags|Install a %{docsLinkAnchoredStart}compatible client library%{docsLinkAnchoredEnd} and specify the API URL, application name, and instance ID during the configuration setup. %{docsLinkStart}More Information%{docsLinkEnd}"
msgstr ""
msgid "FeatureFlags|Instance ID"
@@ -10813,6 +11149,9 @@ msgstr ""
msgid "FeatureFlags|Loading feature flags"
msgstr ""
+msgid "FeatureFlags|Loading user lists"
+msgstr ""
+
msgid "FeatureFlags|More information"
msgstr ""
@@ -10831,7 +11170,7 @@ msgstr ""
msgid "FeatureFlags|New feature flag"
msgstr ""
-msgid "FeatureFlags|New list"
+msgid "FeatureFlags|New user list"
msgstr ""
msgid "FeatureFlags|Percent of users"
@@ -10870,6 +11209,9 @@ msgstr ""
msgid "FeatureFlags|There was an error fetching the feature flags."
msgstr ""
+msgid "FeatureFlags|There was an error fetching the user lists."
+msgstr ""
+
msgid "FeatureFlags|There was an error retrieving user lists"
msgstr ""
@@ -10885,6 +11227,9 @@ msgstr ""
msgid "FeatureFlags|User List"
msgstr ""
+msgid "FeatureFlags|User Lists"
+msgstr ""
+
msgid "FeatureFlag|List"
msgstr ""
@@ -10912,15 +11257,6 @@ msgstr ""
msgid "Fetching incoming email"
msgstr ""
-msgid "Fetching licenses failed."
-msgstr ""
-
-msgid "Fetching licenses failed. The request endpoint was not found."
-msgstr ""
-
-msgid "Fetching licenses failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "File"
msgstr ""
@@ -11023,12 +11359,21 @@ msgstr ""
msgid "Filter by status"
msgstr ""
+msgid "Filter by test cases that are currently archived."
+msgstr ""
+
+msgid "Filter by test cases that are currently opened."
+msgstr ""
+
msgid "Filter by two-factor authentication"
msgstr ""
msgid "Filter by user"
msgstr ""
+msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
+msgstr ""
+
msgid "Filter pipelines"
msgstr ""
@@ -11044,7 +11389,7 @@ msgstr ""
msgid "Filter results..."
msgstr ""
-msgid "Filter your projects by name"
+msgid "Filter your repositories by name"
msgstr ""
msgid "Filter..."
@@ -11053,7 +11398,7 @@ msgstr ""
msgid "Find File"
msgstr ""
-msgid "Find bugs in your code with coverage-guided fuzzing"
+msgid "Find bugs in your code with coverage-guided fuzzing."
msgstr ""
msgid "Find by path"
@@ -11080,9 +11425,6 @@ msgstr ""
msgid "Finish editing this message first!"
msgstr ""
-msgid "Finish review"
-msgstr ""
-
msgid "Finish setting up your dedicated account for %{group_name}."
msgstr ""
@@ -11152,6 +11494,9 @@ msgstr ""
msgid "Footer message"
msgstr ""
+msgid "For a faster browsing experience, some files are collapsed by default."
+msgstr ""
+
msgid "For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
@@ -11161,6 +11506,9 @@ msgstr ""
msgid "For more info, read the documentation."
msgstr ""
+msgid "For more information on how the number of active users is calculated, see the %{self_managed_subscriptions_doc_link} documentation."
+msgstr ""
+
msgid "For more information, go to the "
msgstr ""
@@ -11299,6 +11647,9 @@ msgstr ""
msgid "Generate new token"
msgstr ""
+msgid "Generic package file size in bytes"
+msgstr ""
+
msgid "Geo"
msgstr ""
@@ -11560,6 +11911,9 @@ msgstr ""
msgid "Geo|Please refer to Geo Troubleshooting."
msgstr ""
+msgid "Geo|Primary node"
+msgstr ""
+
msgid "Geo|Project"
msgstr ""
@@ -11602,6 +11956,9 @@ msgstr ""
msgid "Geo|Review replication status, and resynchronize and reverify items with the primary node."
msgstr ""
+msgid "Geo|Secondary node"
+msgstr ""
+
msgid "Geo|Status"
msgstr ""
@@ -11641,6 +11998,9 @@ msgstr ""
msgid "Geo|URL must be a valid url (ex: https://gitlab.com)"
msgstr ""
+msgid "Geo|Undefined"
+msgstr ""
+
msgid "Geo|Unknown state"
msgstr ""
@@ -11716,10 +12076,16 @@ msgstr ""
msgid "GitHub import"
msgstr ""
+msgid "GitLab"
+msgstr ""
+
msgid "GitLab / Unsubscribe"
msgstr ""
-msgid "GitLab Enterprise Edition %{plan}"
+msgid "GitLab API"
+msgstr ""
+
+msgid "GitLab Billing Team."
msgstr ""
msgid "GitLab Group Runners can execute code for all the projects in this group."
@@ -11731,12 +12097,18 @@ msgstr ""
msgid "GitLab Issue"
msgstr ""
+msgid "GitLab Pages"
+msgstr ""
+
msgid "GitLab Service Desk is a simple way to allow people to create issues in your GitLab instance without needing their own user account. It provides a unique email address for end users to create issues in a project, and replies can be sent either through the GitLab interface or by email. End users will only see the thread through email."
msgstr ""
msgid "GitLab Shared Runners execute code of different projects on the same Runner unless you configure GitLab Runner Autoscale with MaxBuilds 1 (which it is on GitLab.com)."
msgstr ""
+msgid "GitLab Shell"
+msgstr ""
+
msgid "GitLab Support Bot"
msgstr ""
@@ -11746,7 +12118,7 @@ msgstr ""
msgid "GitLab User"
msgstr ""
-msgid "GitLab allows you to continue using your license even if you exceed the number of seats you purchased. You will be required to pay for these seats when you renew your license."
+msgid "GitLab Workhorse"
msgstr ""
msgid "GitLab commit"
@@ -11914,6 +12286,21 @@ msgstr ""
msgid "Gitlab Pages"
msgstr ""
+msgid "Gitpod"
+msgstr ""
+
+msgid "Gitpod|Add the URL to your Gitpod instance configured to read your GitLab projects."
+msgstr ""
+
+msgid "Gitpod|Enable Gitpod integration"
+msgstr ""
+
+msgid "Gitpod|Gitpod URL"
+msgstr ""
+
+msgid "Gitpod|e.g. https://gitpod.example.com"
+msgstr ""
+
msgid "Given access %{time_ago}"
msgstr ""
@@ -12421,9 +12808,6 @@ msgstr ""
msgid "GroupSAML|Valid SAML Response"
msgstr ""
-msgid "GroupSAML|With group managed accounts enabled, all the users without a group managed account will be excluded from the group."
-msgstr ""
-
msgid "GroupSAML|With prohibit outer forks flag enabled group members will be able to fork project only inside your group."
msgstr ""
@@ -12637,10 +13021,10 @@ msgstr ""
msgid "GroupsNew|Create group"
msgstr ""
-msgid "GroupsNew|GitLab group export"
+msgid "GroupsNew|Import"
msgstr ""
-msgid "GroupsNew|Import"
+msgid "GroupsNew|Import a GitLab group export file"
msgstr ""
msgid "GroupsNew|Import group"
@@ -12784,6 +13168,9 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgid "Hide comments on this file"
+msgstr ""
+
msgid "Hide details"
msgstr ""
@@ -12829,6 +13216,15 @@ msgstr ""
msgid "Highest role:"
msgstr ""
+msgid "HighlightBar|Alert events:"
+msgstr ""
+
+msgid "HighlightBar|Alert start time:"
+msgstr ""
+
+msgid "HighlightBar|Original alert:"
+msgstr ""
+
msgid "History"
msgstr ""
@@ -13006,6 +13402,9 @@ msgstr ""
msgid "If enabled, access to projects will be validated on an external service using their classification label."
msgstr ""
+msgid "If the number of active users exceeds the user limit, you will be charged for the number of %{users_over_license_link} at your next license reconciliation."
+msgstr ""
+
msgid "If there is no previous license or if the previous license has expired, some GitLab functionality will be blocked until a new, valid license is uploaded."
msgstr ""
@@ -13045,9 +13444,6 @@ msgstr ""
msgid "If your HTTP repository is not publicly accessible, add your credentials."
msgstr ""
-msgid "Iglu registry URL (optional)"
-msgstr ""
-
msgid "Ignore"
msgstr ""
@@ -13084,6 +13480,18 @@ msgstr ""
msgid "Import"
msgstr ""
+msgid "Import %d compatible repository"
+msgid_plural "Import %d compatible repositories"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
+msgid "Import %d repository"
+msgid_plural "Import %d repositories"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "Import CSV"
msgstr ""
@@ -13093,15 +13501,9 @@ msgstr ""
msgid "Import all compatible projects"
msgstr ""
-msgid "Import all compatible repositories"
-msgstr ""
-
msgid "Import all projects"
msgstr ""
-msgid "Import all repositories"
-msgstr ""
-
msgid "Import an exported GitLab project"
msgstr ""
@@ -13189,6 +13591,9 @@ msgstr ""
msgid "ImportProjects|Error importing repository %{project_safe_import_url} into %{project_full_path} - %{message}"
msgstr ""
+msgid "ImportProjects|Import repositories"
+msgstr ""
+
msgid "ImportProjects|Importing the project failed"
msgstr ""
@@ -13201,7 +13606,7 @@ msgstr ""
msgid "ImportProjects|Requesting your %{provider} repositories failed"
msgstr ""
-msgid "ImportProjects|Select the projects you want to import"
+msgid "ImportProjects|Select the repositories you want to import"
msgstr ""
msgid "ImportProjects|The remote data could not be imported."
@@ -13237,9 +13642,6 @@ msgstr ""
msgid "In order to enable Service Desk for your instance, you must first set up incoming email."
msgstr ""
-msgid "In order to gather accurate feature usage data, it can take 1 to 2 weeks to see your index."
-msgstr ""
-
msgid "In order to personalize your experience with GitLab%{br_tag}we would like to know a bit more about you."
msgstr ""
@@ -13270,18 +13672,30 @@ msgstr ""
msgid "IncidentManagement|Create incident"
msgstr ""
+msgid "IncidentManagement|Critical - S1"
+msgstr ""
+
msgid "IncidentManagement|Date created"
msgstr ""
msgid "IncidentManagement|Display your incidents in a dedicated view"
msgstr ""
+msgid "IncidentManagement|High - S2"
+msgstr ""
+
msgid "IncidentManagement|Incident"
msgstr ""
msgid "IncidentManagement|Incidents"
msgstr ""
+msgid "IncidentManagement|Low - S4"
+msgstr ""
+
+msgid "IncidentManagement|Medium - S3"
+msgstr ""
+
msgid "IncidentManagement|No incidents to display."
msgstr ""
@@ -13294,6 +13708,9 @@ msgstr ""
msgid "IncidentManagement|Published to status page"
msgstr ""
+msgid "IncidentManagement|Severity"
+msgstr ""
+
msgid "IncidentManagement|There are no closed incidents"
msgstr ""
@@ -13303,6 +13720,9 @@ msgstr ""
msgid "IncidentManagement|Unassigned"
msgstr ""
+msgid "IncidentManagement|Unknown"
+msgstr ""
+
msgid "IncidentManagement|Unpublished"
msgstr ""
@@ -13324,6 +13744,15 @@ msgstr ""
msgid "Incidents"
msgstr ""
+msgid "Incident|Alert details"
+msgstr ""
+
+msgid "Incident|Summary"
+msgstr ""
+
+msgid "Incident|There was an issue loading alert data. Please try again."
+msgstr ""
+
msgid "Include a Terms of Service agreement and Privacy Policy that all users must accept."
msgstr ""
@@ -13384,6 +13813,9 @@ msgstr ""
msgid "Information about additional Pages templates and how to install them can be found in our %{pages_getting_started_guide}."
msgstr ""
+msgid "Inherited"
+msgstr ""
+
msgid "Inherited:"
msgstr ""
@@ -13465,7 +13897,22 @@ msgstr ""
msgid "Instance administrators group already exists"
msgstr ""
-msgid "Instance license"
+msgid "InstanceStatistics|Groups"
+msgstr ""
+
+msgid "InstanceStatistics|Issues"
+msgstr ""
+
+msgid "InstanceStatistics|Merge Requests"
+msgstr ""
+
+msgid "InstanceStatistics|Pipelines"
+msgstr ""
+
+msgid "InstanceStatistics|Projects"
+msgstr ""
+
+msgid "InstanceStatistics|Users"
msgstr ""
msgid "Integration"
@@ -13477,6 +13924,12 @@ msgstr ""
msgid "Integrations"
msgstr ""
+msgid "Integrations|%{integration} settings saved and active."
+msgstr ""
+
+msgid "Integrations|%{integration} settings saved, but not active."
+msgstr ""
+
msgid "Integrations|All details"
msgstr ""
@@ -13486,6 +13939,12 @@ msgstr ""
msgid "Integrations|Comment settings:"
msgstr ""
+msgid "Integrations|Connection failed. Please check your settings."
+msgstr ""
+
+msgid "Integrations|Connection successful."
+msgstr ""
+
msgid "Integrations|Default settings are inherited from the group level."
msgstr ""
@@ -13501,6 +13960,15 @@ msgstr ""
msgid "Integrations|Includes commit title and branch"
msgstr ""
+msgid "Integrations|Projects using custom settings will not be impacted unless the project owner chooses to use instance-level defaults."
+msgstr ""
+
+msgid "Integrations|Save settings?"
+msgstr ""
+
+msgid "Integrations|Saving will update the default settings for all projects that are not using custom settings."
+msgstr ""
+
msgid "Integrations|Standard"
msgstr ""
@@ -13633,6 +14101,9 @@ msgstr ""
msgid "Invitation"
msgstr ""
+msgid "Invitation declined"
+msgstr ""
+
msgid "Invite"
msgstr ""
@@ -13684,6 +14155,42 @@ 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|%{linkStart}Read more%{linkEnd} about role permissions"
+msgstr ""
+
+msgid "InviteMembersModal|Access expiration date (optional)"
+msgstr ""
+
+msgid "InviteMembersModal|Cancel"
+msgstr ""
+
+msgid "InviteMembersModal|Choose a role permission"
+msgstr ""
+
+msgid "InviteMembersModal|GitLab member or Email address"
+msgstr ""
+
+msgid "InviteMembersModal|Invite"
+msgstr ""
+
+msgid "InviteMembersModal|Invite team members"
+msgstr ""
+
+msgid "InviteMembersModal|Search for members to invite"
+msgstr ""
+
+msgid "InviteMembersModal|User not invited. Feature coming soon!"
+msgstr ""
+
+msgid "InviteMembersModal|Users were succesfully added"
+msgstr ""
+
+msgid "InviteMembersModal|You're inviting members to the %{group_name} group"
+msgstr ""
+
+msgid "InviteMembers|Invite team members"
+msgstr ""
+
msgid "Invited"
msgstr ""
@@ -13738,10 +14245,13 @@ msgstr ""
msgid "Issue cannot be found."
msgstr ""
+msgid "Issue created from vulnerability %{vulnerability_link}"
+msgstr ""
+
msgid "Issue events"
msgstr ""
-msgid "Issue first depoloyed to production"
+msgid "Issue first deployed to production"
msgstr ""
msgid "Issue label"
@@ -13819,6 +14329,9 @@ msgstr ""
msgid "IssueTracker|Custom issue tracker"
msgstr ""
+msgid "IssueTracker|EWM work items tracker"
+msgstr ""
+
msgid "IssueTracker|Redmine issue tracker"
msgstr ""
@@ -13885,6 +14398,9 @@ msgstr ""
msgid "It looks like you have some draft commits in this branch."
msgstr ""
+msgid "It may be several days before you see feature usage data."
+msgstr ""
+
msgid "It must have a header row and at least two columns: the first column is the issue title and the second column is the issue description. The separator is automatically detected."
msgstr ""
@@ -14167,13 +14683,13 @@ msgstr ""
msgid "Join Zoom meeting"
msgstr ""
-msgid "Jul"
+msgid "Joined %{time_ago}"
msgstr ""
-msgid "July"
+msgid "Jul"
msgstr ""
-msgid "Jump to first unresolved thread"
+msgid "July"
msgstr ""
msgid "Jump to next unresolved thread"
@@ -14209,6 +14725,9 @@ msgstr ""
msgid "Keyboard shortcuts"
msgstr ""
+msgid "KeyboardKey|Ctrl+"
+msgstr ""
+
msgid "Keys"
msgstr ""
@@ -14257,6 +14776,9 @@ msgstr ""
msgid "LDAP Synchronization"
msgstr ""
+msgid "LDAP group settings"
+msgstr ""
+
msgid "LDAP settings"
msgstr ""
@@ -14266,6 +14788,9 @@ msgstr ""
msgid "LDAP sync in progress. This could take a few minutes. Refresh the page to see the changes."
msgstr ""
+msgid "LDAP synchronizations"
+msgstr ""
+
msgid "LFS"
msgstr ""
@@ -14347,7 +14872,16 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
-msgid "Last %{days} days"
+msgid "Last 2 weeks"
+msgstr ""
+
+msgid "Last 30 days"
+msgstr ""
+
+msgid "Last 60 days"
+msgstr ""
+
+msgid "Last 90 days"
msgstr ""
msgid "Last Accessed On"
@@ -14425,6 +14959,9 @@ msgstr ""
msgid "Last used on:"
msgstr ""
+msgid "Last week"
+msgstr ""
+
msgid "LastCommit|authored"
msgstr ""
@@ -14440,6 +14977,9 @@ msgstr ""
msgid "Latest pipeline for the most recent commit on this branch"
msgstr ""
+msgid "Launch a ready-to-code development environment for your project."
+msgstr ""
+
msgid "Lead"
msgstr ""
@@ -14827,6 +15367,9 @@ msgstr ""
msgid "List of all merge commits"
msgstr ""
+msgid "List options"
+msgstr ""
+
msgid "List settings"
msgstr ""
@@ -14839,9 +15382,6 @@ msgstr ""
msgid "List your Bitbucket Server repositories"
msgstr ""
-msgid "Lists"
-msgstr ""
-
msgid "Live preview"
msgstr ""
@@ -15088,6 +15628,12 @@ msgstr ""
msgid "Mark as done"
msgstr ""
+msgid "Mark as draft"
+msgstr ""
+
+msgid "Mark as ready"
+msgstr ""
+
msgid "Mark as resolved"
msgstr ""
@@ -15109,6 +15655,24 @@ msgstr ""
msgid "Markdown is supported"
msgstr ""
+msgid "MarkdownEditor|Add a link (%{modifierKey}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add a link (%{modifier_key}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifierKey}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifier_key}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifierKey}I)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifier_key}I)"
+msgstr ""
+
msgid "Marked For Deletion At - %{deletion_time}"
msgstr ""
@@ -15193,7 +15757,25 @@ msgstr ""
msgid "Max access level"
msgstr ""
-msgid "Max seats used"
+msgid "Max role"
+msgstr ""
+
+msgid "Max size 15 MB"
+msgstr ""
+
+msgid "Maximum Conan package file size in bytes"
+msgstr ""
+
+msgid "Maximum Maven package file size in bytes"
+msgstr ""
+
+msgid "Maximum NPM package file size in bytes"
+msgstr ""
+
+msgid "Maximum NuGet package file size in bytes"
+msgstr ""
+
+msgid "Maximum PyPI package file size in bytes"
msgstr ""
msgid "Maximum Users:"
@@ -15325,6 +15907,18 @@ msgstr ""
msgid "Members with access to %{strong_start}%{group_name}%{strong_end}"
msgstr ""
+msgid "Members|%{time} by %{user}"
+msgstr ""
+
+msgid "Members|Expired"
+msgstr ""
+
+msgid "Members|No expiration set"
+msgstr ""
+
+msgid "Members|in %{time}"
+msgstr ""
+
msgid "Memory Usage"
msgstr ""
@@ -15511,9 +16105,6 @@ msgstr ""
msgid "MergeRequests|Thread will be unresolved"
msgstr ""
-msgid "MergeRequests|Toggle comments for this file"
-msgstr ""
-
msgid "MergeRequests|View file @ %{commitId}"
msgstr ""
@@ -15574,6 +16165,9 @@ msgstr ""
msgid "Merging immediately isn't recommended as it may negatively impact the existing merge train. Read the %{docsLinkStart}documentation%{docsLinkEnd} for more information."
msgstr ""
+msgid "Message"
+msgstr ""
+
msgid "Messages"
msgstr ""
@@ -15961,18 +16555,12 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
-msgid "Milestone does not support burnup charts"
-msgstr ""
-
msgid "Milestone lists not available with your current license"
msgstr ""
msgid "Milestone lists show all issues from the selected milestone."
msgstr ""
-msgid "Milestone must have a start and due date"
-msgstr ""
-
msgid "MilestoneSidebar|Closed:"
msgstr ""
@@ -16339,6 +16927,9 @@ msgstr ""
msgid "Namespace"
msgstr ""
+msgid "Namespace ID:"
+msgstr ""
+
msgid "Namespace is empty"
msgstr ""
@@ -16423,6 +17014,9 @@ msgstr ""
msgid "NetworkPolicies|Allow all outbound traffic from %{selector} to %{ruleSelector} on %{ports}"
msgstr ""
+msgid "NetworkPolicies|Are you sure you want to delete this policy? This action cannot be undone."
+msgstr ""
+
msgid "NetworkPolicies|Choose whether to enforce this policy."
msgstr ""
@@ -16432,12 +17026,21 @@ msgstr ""
msgid "NetworkPolicies|Define this policy's location, conditions and actions."
msgstr ""
+msgid "NetworkPolicies|Delete policy"
+msgstr ""
+
+msgid "NetworkPolicies|Delete policy: %{policy}"
+msgstr ""
+
msgid "NetworkPolicies|Deny all traffic"
msgstr ""
msgid "NetworkPolicies|Description"
msgstr ""
+msgid "NetworkPolicies|Edit policy"
+msgstr ""
+
msgid "NetworkPolicies|Editor mode"
msgstr ""
@@ -16465,6 +17068,9 @@ msgstr ""
msgid "NetworkPolicies|Name"
msgstr ""
+msgid "NetworkPolicies|Namespace"
+msgstr ""
+
msgid "NetworkPolicies|Network Policy"
msgstr ""
@@ -16516,6 +17122,9 @@ msgstr ""
msgid "NetworkPolicies|Rules"
msgstr ""
+msgid "NetworkPolicies|Save changes"
+msgstr ""
+
msgid "NetworkPolicies|Something went wrong, failed to update policy"
msgstr ""
@@ -16528,6 +17137,9 @@ msgstr ""
msgid "NetworkPolicies|Traffic that does not match any rule will be blocked."
msgstr ""
+msgid "NetworkPolicies|Unable to parse policy"
+msgstr ""
+
msgid "NetworkPolicies|YAML editor"
msgstr ""
@@ -16642,6 +17254,9 @@ msgstr ""
msgid "New Snippet"
msgstr ""
+msgid "New Test Case"
+msgstr ""
+
msgid "New User"
msgstr ""
@@ -16741,6 +17356,9 @@ msgstr ""
msgid "New tag"
msgstr ""
+msgid "New test case"
+msgstr ""
+
msgid "New users set to external"
msgstr ""
@@ -16813,7 +17431,7 @@ msgstr ""
msgid "No changes"
msgstr ""
-msgid "No changes between %{ref_start}%{source_branch}%{ref_end} and %{ref_start}%{target_branch}%{ref_end}"
+msgid "No changes between %{sourceBranch} and %{targetBranch}"
msgstr ""
msgid "No child epics match applied filters"
@@ -16828,6 +17446,9 @@ msgstr ""
msgid "No containers available"
msgstr ""
+msgid "No content to show"
+msgstr ""
+
msgid "No contributions"
msgstr ""
@@ -16903,9 +17524,6 @@ msgstr ""
msgid "No license. All rights reserved"
msgstr ""
-msgid "No licenses found."
-msgstr ""
-
msgid "No matches found"
msgstr ""
@@ -16918,6 +17536,9 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No members found"
+msgstr ""
+
msgid "No merge requests found"
msgstr ""
@@ -16939,6 +17560,9 @@ msgstr ""
msgid "No parent group"
msgstr ""
+msgid "No plan"
+msgstr ""
+
msgid "No pods available"
msgstr ""
@@ -17035,6 +17659,12 @@ msgstr ""
msgid "Not Implemented"
msgstr ""
+msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+msgstr ""
+
+msgid "Not all browsers support WebAuthn. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even from an unsupported browser."
+msgstr ""
+
msgid "Not all data has been processed yet, the accuracy of the chart for the selected timeframe is limited."
msgstr ""
@@ -17131,6 +17761,9 @@ msgstr ""
msgid "Notification settings saved"
msgstr ""
+msgid "NotificationEvent|Change reviewer merge request"
+msgstr ""
+
msgid "NotificationEvent|Close issue"
msgstr ""
@@ -17293,10 +17926,7 @@ msgstr ""
msgid "On track"
msgstr ""
-msgid "OnDemandScans|Attached branch"
-msgstr ""
-
-msgid "OnDemandScans|Attached branch is where the scan job runs."
+msgid "OnDemandScans|Could not fetch scanner profiles. Please refresh the page, or try again later."
msgstr ""
msgid "OnDemandScans|Could not fetch site profiles. Please refresh the page, or try again later."
@@ -17305,6 +17935,9 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
+msgid "OnDemandScans|Create a new scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Create a new site profile"
msgstr ""
@@ -17317,6 +17950,9 @@ msgstr ""
msgid "OnDemandScans|New on-demand DAST scan"
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 ""
@@ -17326,16 +17962,10 @@ msgstr ""
msgid "OnDemandScans|On-demand scans run outside the DevOps cycle and find vulnerabilities in your projects. %{learnMoreLinkStart}Learn more%{learnMoreLinkEnd}"
msgstr ""
-msgid "OnDemandScans|Only a passive scan can be performed on demand."
-msgstr ""
-
-msgid "OnDemandScans|Passive"
-msgstr ""
-
msgid "OnDemandScans|Run scan"
msgstr ""
-msgid "OnDemandScans|Scan mode"
+msgid "OnDemandScans|Scanner profile"
msgstr ""
msgid "OnDemandScans|Scanner settings"
@@ -17347,9 +17977,15 @@ msgstr ""
msgid "OnDemandScans|Select one of the existing profiles"
msgstr ""
+msgid "OnDemandScans|Site profile"
+msgstr ""
+
msgid "OnDemandScans|Site profiles"
msgstr ""
+msgid "OnDemandScans|Use existing scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Use existing site profile"
msgstr ""
@@ -17449,9 +18085,6 @@ msgstr ""
msgid "Open Selection"
msgstr ""
-msgid "Open Web IDE"
-msgstr ""
-
msgid "Open comment type dropdown"
msgstr ""
@@ -17557,6 +18190,9 @@ msgstr ""
msgid "Origin"
msgstr ""
+msgid "Orphaned member"
+msgstr ""
+
msgid "Other Labels"
msgstr ""
@@ -17572,6 +18208,9 @@ msgstr ""
msgid "Other visibility settings have been disabled by the administrator."
msgstr ""
+msgid "Our documentation includes an example DevOps Score report."
+msgstr ""
+
msgid "Out-of-compliance with this project's policies and should be removed"
msgstr ""
@@ -17596,6 +18235,9 @@ msgstr ""
msgid "Overwrite diverged branches"
msgstr ""
+msgid "Owned by %{image_tag}"
+msgstr ""
+
msgid "Owned by anyone"
msgstr ""
@@ -17617,6 +18259,9 @@ msgstr ""
msgid "Package deleted successfully"
msgstr ""
+msgid "Package file size limits"
+msgstr ""
+
msgid "Package recipe already exists"
msgstr ""
@@ -17632,9 +18277,6 @@ msgstr ""
msgid "Package type must be PyPi"
msgstr ""
-msgid "Package was removed"
-msgstr ""
-
msgid "PackageRegistry|%{name} version %{version} was created %{datetime}"
msgstr ""
@@ -17776,12 +18418,18 @@ msgstr ""
msgid "PackageRegistry|NuGet Command"
msgstr ""
+msgid "PackageRegistry|Package Registry"
+msgstr ""
+
msgid "PackageRegistry|Pip Command"
msgstr ""
msgid "PackageRegistry|Pipeline %{link} triggered %{datetime} by %{author}"
msgstr ""
+msgid "PackageRegistry|Publish and share packages for a variety of common package managers. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "PackageRegistry|Published to the %{project} Package Registry %{datetime}"
msgstr ""
@@ -17881,6 +18529,9 @@ msgstr ""
msgid "Page not found"
msgstr ""
+msgid "Page settings"
+msgstr ""
+
msgid "Page was successfully deleted"
msgstr ""
@@ -18022,7 +18673,7 @@ msgstr ""
msgid "Paste issue link"
msgstr ""
-msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Don't use your private SSH key."
+msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Do not paste your private SSH key, as that can compromise your identity."
msgstr ""
msgid "Patch to apply"
@@ -18049,6 +18700,9 @@ msgstr ""
msgid "Pending"
msgstr ""
+msgid "Pending comments"
+msgstr ""
+
msgid "People without permission will never get a notification and won't be able to comment."
msgstr ""
@@ -18247,6 +18901,9 @@ msgstr ""
msgid "Pipelines|Build with confidence"
msgstr ""
+msgid "Pipelines|By revoking a trigger you will break any processes making use of it. Are you sure?"
+msgstr ""
+
msgid "Pipelines|CI Lint"
msgstr ""
@@ -18259,6 +18916,15 @@ msgstr ""
msgid "Pipelines|Continuous Integration can help catch bugs by running your tests automatically, while Continuous Deployment can help you deliver code to your product environment."
msgstr ""
+msgid "Pipelines|Copy trigger token"
+msgstr ""
+
+msgid "Pipelines|Description"
+msgstr ""
+
+msgid "Pipelines|Edit"
+msgstr ""
+
msgid "Pipelines|Get started with Pipelines"
msgstr ""
@@ -18274,15 +18940,27 @@ msgstr ""
msgid "Pipelines|It is recommended the code is reviewed thoroughly before running this pipeline with the parent project's CI resource."
msgstr ""
+msgid "Pipelines|Last Used"
+msgstr ""
+
msgid "Pipelines|Loading Pipelines"
msgstr ""
msgid "Pipelines|More Information"
msgstr ""
+msgid "Pipelines|No triggers have been created yet. Add one using the form above."
+msgstr ""
+
+msgid "Pipelines|Owner"
+msgstr ""
+
msgid "Pipelines|Project cache successfully reset."
msgstr ""
+msgid "Pipelines|Revoke"
+msgstr ""
+
msgid "Pipelines|Run Pipeline"
msgstr ""
@@ -18307,6 +18985,15 @@ msgstr ""
msgid "Pipelines|This project is not currently set up to run pipelines."
msgstr ""
+msgid "Pipelines|Token"
+msgstr ""
+
+msgid "Pipelines|Trigger user has insufficient permissions to project"
+msgstr ""
+
+msgid "Pipelines|invalid"
+msgstr ""
+
msgid "Pipelines|parent"
msgstr ""
@@ -18565,10 +19252,10 @@ msgstr ""
msgid "Please provide attributes to update"
msgstr ""
-msgid "Please refer to %{docs_url}"
+msgid "Please reach out if you have any questions and we'll be happy to assist."
msgstr ""
-msgid "Please retype the email address."
+msgid "Please refer to %{docs_url}"
msgstr ""
msgid "Please select"
@@ -18598,6 +19285,9 @@ msgstr ""
msgid "Please set a new password before proceeding."
msgstr ""
+msgid "Please share your feedback about %{featureName} %{linkStart}in this issue%{linkEnd} to help us improve the experience."
+msgstr ""
+
msgid "Please solve the reCAPTCHA"
msgstr ""
@@ -18901,6 +19591,9 @@ msgstr ""
msgid "Profiles| You are going to change the username %{currentUsernameBold} to %{newUsernameBold}. Profile and projects will be redirected to the %{newUsername} namespace but this redirect will expire once the %{currentUsername} namespace is registered by another user or group. Please update your Git repository remotes as soon as possible."
msgstr ""
+msgid "Profiles|%{provider} Active"
+msgstr ""
+
msgid "Profiles|@username"
msgstr ""
@@ -18952,7 +19645,7 @@ msgstr ""
msgid "Profiles|Commit email"
msgstr ""
-msgid "Profiles|Connect"
+msgid "Profiles|Connect %{provider}"
msgstr ""
msgid "Profiles|Connected Accounts"
@@ -18976,6 +19669,9 @@ msgstr ""
msgid "Profiles|Disconnect"
msgstr ""
+msgid "Profiles|Disconnect %{provider}"
+msgstr ""
+
msgid "Profiles|Do not show on profile"
msgstr ""
@@ -19000,7 +19696,7 @@ msgstr ""
msgid "Profiles|Full name"
msgstr ""
-msgid "Profiles|Give your individual key a title. This will be publically visible."
+msgid "Profiles|Give your individual key a title."
msgstr ""
msgid "Profiles|Include private contributions on my profile"
@@ -19090,7 +19786,7 @@ msgstr ""
msgid "Profiles|The maximum file size allowed is 200KB."
msgstr ""
-msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it?"
+msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it? It will be publicly visible."
msgstr ""
msgid "Profiles|This email will be displayed on your public profile"
@@ -19165,6 +19861,9 @@ msgstr ""
msgid "Profiles|You don't have access to delete this user."
msgstr ""
+msgid "Profiles|You must transfer ownership or delete groups you are an owner of before you can delete your account"
+msgstr ""
+
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
@@ -19753,6 +20452,9 @@ msgstr ""
msgid "ProjectTemplates|GitLab Cluster Management"
msgstr ""
+msgid "ProjectTemplates|Gitpod/Spring Petclinic"
+msgstr ""
+
msgid "ProjectTemplates|Go Micro"
msgstr ""
@@ -20362,6 +21064,9 @@ msgstr ""
msgid "Publish to status page"
msgstr ""
+msgid "Published"
+msgstr ""
+
msgid "Published on status page"
msgstr ""
@@ -20479,9 +21184,15 @@ msgstr ""
msgid "Quick range"
msgstr ""
+msgid "Quickly and easily edit multiple files in your project."
+msgstr ""
+
msgid "README"
msgstr ""
+msgid "Rails"
+msgstr ""
+
msgid "Rake Tasks Help"
msgstr ""
@@ -20602,10 +21313,13 @@ msgstr ""
msgid "Register Two-Factor Authenticator"
msgstr ""
-msgid "Register U2F device"
+msgid "Register Universal Two-Factor (U2F) Device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register WebAuthn Device"
+msgstr ""
+
+msgid "Register device"
msgstr ""
msgid "Register for GitLab"
@@ -20617,9 +21331,6 @@ msgstr ""
msgid "Register with two-factor app"
msgstr ""
-msgid "Registration"
-msgstr ""
-
msgid "Registration|Checkout"
msgstr ""
@@ -20737,9 +21448,6 @@ msgstr ""
msgid "Release|Something went wrong while saving the release details"
msgstr ""
-msgid "Remediated: needs review"
-msgstr ""
-
msgid "Remediations"
msgstr ""
@@ -20845,6 +21553,9 @@ msgstr ""
msgid "Remove priority"
msgstr ""
+msgid "Remove report"
+msgstr ""
+
msgid "Remove secondary node"
msgstr ""
@@ -20857,6 +21568,12 @@ msgstr ""
msgid "Remove time estimate"
msgstr ""
+msgid "Remove user & report"
+msgstr ""
+
+msgid "Remove user from group"
+msgstr ""
+
msgid "Removed"
msgstr ""
@@ -20938,9 +21655,6 @@ msgstr ""
msgid "Removes time estimate."
msgstr ""
-msgid "Removing license…"
-msgstr ""
-
msgid "Removing this group also removes all child projects, including archived projects, and their resources."
msgstr ""
@@ -21025,6 +21739,9 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
+msgid "Reported by %{reporter}"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -21112,6 +21829,27 @@ msgstr ""
msgid "Repositories"
msgstr ""
+msgid "Repositories Analytics"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download Historic Test Coverage Data"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download historic test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Historic Test Coverage Data is available in raw format (.csv) for further analysis."
+msgstr ""
+
+msgid "RepositoriesAnalytics|Test Code Coverage"
+msgstr ""
+
+msgid "RepositoriesAnalytics|There was an error fetching the projects."
+msgstr ""
+
msgid "Repository"
msgstr ""
@@ -21190,9 +21928,15 @@ msgstr ""
msgid "Request parameter %{param} is missing."
msgstr ""
+msgid "Request review from"
+msgstr ""
+
msgid "Request to link SAML account must be authorized"
msgstr ""
+msgid "Requested"
+msgstr ""
+
msgid "Requested %{time_ago}"
msgstr ""
@@ -21211,6 +21955,9 @@ msgstr ""
msgid "Requests to these domain(s)/address(es) on the local network will be allowed when local requests from hooks and services are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 or 127.0.0.0/28 are supported. Domain wildcards are not supported currently. Use comma, semicolon, or newline to separate multiple entries. The allowlist can hold a maximum of 1000 entries. Domains should use IDNA encoding. Ex: example.com, 192.168.1.1, 127.0.0.0/28, xn--itlab-j1a.com."
msgstr ""
+msgid "Require admin approval for new sign-ups"
+msgstr ""
+
msgid "Require all users in this group to setup Two-factor authentication"
msgstr ""
@@ -21340,9 +22087,6 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
-msgid "Resolved by %{resolvedByName}"
-msgstr ""
-
msgid "Resolves IP addresses once and uses them to submit requests"
msgstr ""
@@ -21463,6 +22207,15 @@ msgstr ""
msgid "ReviewApp|Enable Review App"
msgstr ""
+msgid "Reviewer"
+msgid_plural "%d Reviewers"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
+msgid "Reviewer(s)"
+msgstr ""
+
msgid "Reviewing"
msgstr ""
@@ -21502,6 +22255,9 @@ msgstr ""
msgid "Rook"
msgstr ""
+msgid "Ruby"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -21580,6 +22336,63 @@ msgstr ""
msgid "Runners page."
msgstr ""
+msgid "Runners|Active"
+msgstr ""
+
+msgid "Runners|Architecture"
+msgstr ""
+
+msgid "Runners|Can run untagged jobs"
+msgstr ""
+
+msgid "Runners|Description"
+msgstr ""
+
+msgid "Runners|Group"
+msgstr ""
+
+msgid "Runners|IP Address"
+msgstr ""
+
+msgid "Runners|Last contact"
+msgstr ""
+
+msgid "Runners|Locked to this project"
+msgstr ""
+
+msgid "Runners|Maximum job timeout"
+msgstr ""
+
+msgid "Runners|Name"
+msgstr ""
+
+msgid "Runners|Platform"
+msgstr ""
+
+msgid "Runners|Property Name"
+msgstr ""
+
+msgid "Runners|Protected"
+msgstr ""
+
+msgid "Runners|Revision"
+msgstr ""
+
+msgid "Runners|Shared"
+msgstr ""
+
+msgid "Runners|Specific"
+msgstr ""
+
+msgid "Runners|Tags"
+msgstr ""
+
+msgid "Runners|Value"
+msgstr ""
+
+msgid "Runners|Version"
+msgstr ""
+
msgid "Runners|You have used %{quotaUsed} out of %{quotaLimit} of your shared Runners pipeline minutes."
msgstr ""
@@ -21592,6 +22405,9 @@ msgstr ""
msgid "Runs a number of housekeeping tasks within the current repository, such as compressing file revisions and removing unreachable objects."
msgstr ""
+msgid "SAML"
+msgstr ""
+
msgid "SAML SSO"
msgstr ""
@@ -21643,6 +22459,9 @@ msgstr ""
msgid "Save"
msgstr ""
+msgid "Save %{name} size limits"
+msgstr ""
+
msgid "Save Changes"
msgstr ""
@@ -21673,9 +22492,6 @@ msgstr ""
msgid "Save space and find tags in the Container Registry more easily. Enable the cleanup policy to remove stale tags and keep only the ones you need."
msgstr ""
-msgid "Save template"
-msgstr ""
-
msgid "Save variables"
msgstr ""
@@ -21718,9 +22534,6 @@ msgstr ""
msgid "Scope"
msgstr ""
-msgid "Scope not supported with disabled 'users_search' feature!"
-msgstr ""
-
msgid "Scoped issue boards"
msgstr ""
@@ -21847,9 +22660,6 @@ msgstr ""
msgid "Search requirements"
msgstr ""
-msgid "Search results…"
-msgstr ""
-
msgid "Search users"
msgstr ""
@@ -21925,6 +22735,12 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgid "SearchResults|epic"
+msgid_plural "SearchResults|epics"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "SearchResults|issue"
msgid_plural "SearchResults|issues"
msgstr[0] ""
@@ -21976,10 +22792,10 @@ msgstr ""
msgid "Seat Link is disabled, and cannot be configured through this form."
msgstr ""
-msgid "Seats currently in use"
+msgid "Seats usage data as of %{last_enqueue_time}"
msgstr ""
-msgid "Seats in license"
+msgid "Seats usage data is updated every day at 12:00pm UTC"
msgstr ""
msgid "Secondary"
@@ -22033,6 +22849,9 @@ msgstr ""
msgid "SecurityConfiguration|Available for on-demand DAST"
msgstr ""
+msgid "SecurityConfiguration|By default, all analyzers are applied in order to cover all languages across your project, and only run if the language is detected in the Merge Request."
+msgstr ""
+
msgid "SecurityConfiguration|Configure"
msgstr ""
@@ -22063,16 +22882,19 @@ msgstr ""
msgid "SecurityConfiguration|Manage"
msgstr ""
+msgid "SecurityConfiguration|More information"
+msgstr ""
+
msgid "SecurityConfiguration|Not enabled"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|Security Control"
+msgid "SecurityConfiguration|SAST Configuration"
msgstr ""
-msgid "SecurityConfiguration|See documentation"
+msgid "SecurityConfiguration|Security Control"
msgstr ""
msgid "SecurityConfiguration|Status"
@@ -22084,6 +22906,9 @@ msgstr ""
msgid "SecurityConfiguration|Using custom settings. You won't receive automatic updates on this variable. %{anchorStart}Restore to default%{anchorEnd}"
msgstr ""
+msgid "SecurityConfiguration|View history"
+msgstr ""
+
msgid "SecurityConfiguration|You can quickly enable all security scanning tools by enabling %{linkStart}Auto DevOps%{linkEnd}."
msgstr ""
@@ -22162,9 +22987,6 @@ msgstr ""
msgid "SecurityReports|Learn more about setting up your dashboard"
msgstr ""
-msgid "SecurityReports|Load more vulnerabilities"
-msgstr ""
-
msgid "SecurityReports|Monitor vulnerabilities in your code"
msgstr ""
@@ -22444,7 +23266,7 @@ msgstr ""
msgid "Select status"
msgstr ""
-msgid "Select strategy activation method"
+msgid "Select strategy activation method."
msgstr ""
msgid "Select subscription"
@@ -22459,7 +23281,7 @@ msgstr ""
msgid "Select the custom project template source group."
msgstr ""
-msgid "Select timeframe"
+msgid "Select the environment scope for this feature flag."
msgstr ""
msgid "Select timezone"
@@ -22708,6 +23530,9 @@ msgstr ""
msgid "Set iteration"
msgstr ""
+msgid "Set limit to 0 to allow any file size."
+msgstr ""
+
msgid "Set max session time for web terminal."
msgstr ""
@@ -22786,10 +23611,13 @@ msgstr ""
msgid "Set up a %{type} Runner manually"
msgstr ""
+msgid "Set up a hardware device as a second factor to sign in."
+msgstr ""
+
msgid "Set up assertions/attributes/claims (email, first_name, last_name) and NameID according to %{docsLinkStart}the documentation %{icon}%{docsLinkEnd}"
msgstr ""
-msgid "Set up new U2F device"
+msgid "Set up new device"
msgstr ""
msgid "Set up new password"
@@ -22858,6 +23686,9 @@ msgstr ""
msgid "Sets weight to %{weight}."
msgstr ""
+msgid "Setting this to 0 means using the system default timeout value."
+msgstr ""
+
msgid "Settings"
msgstr ""
@@ -22873,6 +23704,15 @@ msgstr ""
msgid "Severity"
msgstr ""
+msgid "SeverityWidget|Severity"
+msgstr ""
+
+msgid "SeverityWidget|Severity: %{severity}"
+msgstr ""
+
+msgid "SeverityWidget|There was an error while updating severity."
+msgstr ""
+
msgid "Shards (%{shards})"
msgstr ""
@@ -22918,6 +23758,9 @@ msgstr ""
msgid "Show all requirements."
msgstr ""
+msgid "Show all test cases."
+msgstr ""
+
msgid "Show archived projects"
msgstr ""
@@ -22930,6 +23773,9 @@ msgstr ""
msgid "Show comments"
msgstr ""
+msgid "Show comments on this file"
+msgstr ""
+
msgid "Show comments only"
msgstr ""
@@ -22975,6 +23821,12 @@ msgstr ""
msgid "Show parent subgroups"
msgstr ""
+msgid "Show the Closed list"
+msgstr ""
+
+msgid "Show the Open list"
+msgstr ""
+
msgid "Show whitespace changes"
msgstr ""
@@ -23020,9 +23872,6 @@ msgstr ""
msgid "Sidebar|Assign health status"
msgstr ""
-msgid "Sidebar|Change weight"
-msgstr ""
-
msgid "Sidebar|Health status"
msgstr ""
@@ -23206,6 +24055,9 @@ msgstr ""
msgid "Snippets|Add another file %{num}/%{total}"
msgstr ""
+msgid "Snippets|Authored %{time_ago} by %{author}"
+msgstr ""
+
msgid "Snippets|Delete file"
msgstr ""
@@ -23233,6 +24085,9 @@ msgstr ""
msgid "Solution"
msgstr ""
+msgid "Some changes are not shown"
+msgstr ""
+
msgid "Some child epics may be hidden due to applied filters"
msgstr ""
@@ -23599,6 +24454,12 @@ msgstr ""
msgid "Source (branch or tag)"
msgstr ""
+msgid "Source Branch"
+msgstr ""
+
+msgid "Source branch: %{source_branch_open}%{source_branch}%{source_branch_close}"
+msgstr ""
+
msgid "Source code"
msgstr ""
@@ -23764,9 +24625,6 @@ msgstr ""
msgid "Start and due date"
msgstr ""
-msgid "Start by choosing a group to see how your team is spending time. You can then drill down to the project level."
-msgstr ""
-
msgid "Start by choosing a group to start exploring the merge requests in that group. You can then proceed to filter by projects, labels, milestones and authors."
msgstr ""
@@ -23848,18 +24706,27 @@ msgstr ""
msgid "StaticSiteEditor|3. Assign a person to review and accept the merge request."
msgstr ""
+msgid "StaticSiteEditor|A link to view the merge request will appear once ready."
+msgstr ""
+
msgid "StaticSiteEditor|An error occurred while submitting your changes."
msgstr ""
msgid "StaticSiteEditor|Branch could not be created."
msgstr ""
+msgid "StaticSiteEditor|Copy update"
+msgstr ""
+
msgid "StaticSiteEditor|Could not commit the content changes."
msgstr ""
msgid "StaticSiteEditor|Could not create merge request."
msgstr ""
+msgid "StaticSiteEditor|Creating your merge request"
+msgstr ""
+
msgid "StaticSiteEditor|Incompatible file content"
msgstr ""
@@ -23881,6 +24748,9 @@ msgstr ""
msgid "StaticSiteEditor|View documentation"
msgstr ""
+msgid "StaticSiteEditor|You can set an assignee to get your changes reviewed and deployed once your merge request is created."
+msgstr ""
+
msgid "StaticSiteEditor|Your merge request has been created"
msgstr ""
@@ -24010,15 +24880,15 @@ msgstr ""
msgid "Submit %{humanized_resource_name}"
msgstr ""
-msgid "Submit Changes"
-msgstr ""
-
msgid "Submit a review"
msgstr ""
msgid "Submit as spam"
msgstr ""
+msgid "Submit changes"
+msgstr ""
+
msgid "Submit feedback"
msgstr ""
@@ -24172,6 +25042,9 @@ msgstr ""
msgid "Successfully deleted U2F device."
msgstr ""
+msgid "Successfully deleted WebAuthn device."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -24490,9 +25363,6 @@ msgstr ""
msgid "Template to append to all Service Desk issues"
msgstr ""
-msgid "Template was successfully saved."
-msgstr ""
-
msgid "Templates"
msgstr ""
@@ -24574,10 +25444,28 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
-msgid "Test failed."
+msgid "Test settings"
+msgstr ""
+
+msgid "TestCases|New Test Case"
+msgstr ""
+
+msgid "TestCases|New test case"
+msgstr ""
+
+msgid "TestCases|Search test cases"
msgstr ""
-msgid "Test settings and save changes"
+msgid "TestCases|Something went wrong while creating a test case."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching count of test cases."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching test cases list."
+msgstr ""
+
+msgid "TestCases|Submit test case"
msgstr ""
msgid "TestHooks|Ensure one of your projects has merge requests."
@@ -24643,6 +25531,9 @@ msgstr ""
msgid "Thank you for signing up for your free trial! You will get additional instructions in your inbox shortly."
msgstr ""
+msgid "Thank you for your business."
+msgstr ""
+
msgid "Thank you for your feedback!"
msgstr ""
@@ -24703,9 +25594,6 @@ msgstr ""
msgid "The URL to use for connecting to Elasticsearch. Use a comma-separated list to support clustering (e.g., \"http://localhost:9200, http://localhost:9201\")."
msgstr ""
-msgid "The Web IDE offers advanced syntax highlighting capabilities and more."
-msgstr ""
-
msgid "The X509 Certificate to use when mutual TLS is required to communicate with the external authorization service. If left blank, the server certificate is still validated when accessing over HTTPS."
msgstr ""
@@ -24817,6 +25705,9 @@ msgstr ""
msgid "The form contains the following error:"
msgstr ""
+msgid "The form contains the following warning:"
+msgstr ""
+
msgid "The global settings require you to enable Two-Factor Authentication for your account."
msgstr ""
@@ -24931,9 +25822,6 @@ msgstr ""
msgid "The private key to use when a client certificate is provided. This value is encrypted at rest."
msgstr ""
-msgid "The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The project can be accessed by any logged in user."
msgstr ""
@@ -24970,7 +25858,7 @@ msgstr ""
msgid "The remote repository is being updated..."
msgstr ""
-msgid "The repository can be commited to, and issues, comments and other entities can be created."
+msgid "The repository can be committed to, and issues, comments and other entities can be created."
msgstr ""
msgid "The repository for this project does not exist."
@@ -25024,9 +25912,6 @@ msgstr ""
msgid "The time taken by each data entry gathered by that stage."
msgstr ""
-msgid "The total stage shows the time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The update action will time out after %{number_of_minutes} minutes. For big repositories, use a clone/push combination."
msgstr ""
@@ -25090,6 +25975,9 @@ msgstr ""
msgid "There are no archived requirements"
msgstr ""
+msgid "There are no archived test cases"
+msgstr ""
+
msgid "There are no changes"
msgstr ""
@@ -25129,6 +26017,9 @@ msgstr ""
msgid "There are no open requirements"
msgstr ""
+msgid "There are no open test cases"
+msgstr ""
+
msgid "There are no packages yet"
msgstr ""
@@ -25141,6 +26032,9 @@ msgstr ""
msgid "There is a limit of %{ci_project_subscriptions_limit} subscriptions from or to a project."
msgstr ""
+msgid "There is already a To-Do for this design."
+msgstr ""
+
msgid "There is already a repository with that name on disk"
msgstr ""
@@ -25159,6 +26053,9 @@ msgstr ""
msgid "There was a problem communicating with your device."
msgstr ""
+msgid "There was a problem fetching branches."
+msgstr ""
+
msgid "There was a problem fetching groups."
msgstr ""
@@ -25387,9 +26284,15 @@ msgstr ""
msgid "This action can lead to data loss. To prevent accidental actions we ask you to confirm your intention."
msgstr ""
+msgid "This action cannot be undone, and will permanently delete the %{key} SSH key"
+msgstr ""
+
msgid "This action cannot be undone. You will lose the project's repository and all content: issues, merge requests, etc."
msgstr ""
+msgid "This action has been performed too many times. Try again later."
+msgstr ""
+
msgid "This action will %{strongOpen}permanently delete%{strongClose} %{codeOpen}%{project}%{codeClose} %{strongOpen}immediately%{strongClose}, including its repositories and all content: issues, merge requests, etc."
msgstr ""
@@ -25417,9 +26320,6 @@ msgstr ""
msgid "This board's scope is reduced"
msgstr ""
-msgid "This branch has changed since you started editing. Would you like to create a new branch?"
-msgstr ""
-
msgid "This chart could not be displayed"
msgstr ""
@@ -25546,15 +26446,9 @@ msgstr ""
msgid "This is a security log of important events involving your account."
msgstr ""
-msgid "This is the author's first Merge Request to this project."
-msgstr ""
-
msgid "This is the highest peak of users on your installation since the license started."
msgstr ""
-msgid "This is the maximum number of users that have existed at the same time since the license started. This is the minimum number of seats you will need to buy when you renew your license."
-msgstr ""
-
msgid "This is the number of currently active users on your installation, and this is the minimum number you need to purchase when you renew your license."
msgstr ""
@@ -25786,6 +26680,15 @@ msgstr ""
msgid "This user has no identities"
msgstr ""
+msgid "This user has previously committed to the %{name} project."
+msgstr ""
+
+msgid "This user has the %{access} role in the %{name} project."
+msgstr ""
+
+msgid "This user is the author of this %{noteable}."
+msgstr ""
+
msgid "This user will be the author of all events in the activity feed that are the result of an update, like new branches being created or new commits being pushed to existing branches."
msgstr ""
@@ -25816,6 +26719,9 @@ msgstr ""
msgid "Threat Monitoring"
msgstr ""
+msgid "ThreatMonitoring|All Environments"
+msgstr ""
+
msgid "ThreatMonitoring|Anomalous Requests"
msgstr ""
@@ -25843,9 +26749,6 @@ msgstr ""
msgid "ThreatMonitoring|Operations Per Second"
msgstr ""
-msgid "ThreatMonitoring|Overview"
-msgstr ""
-
msgid "ThreatMonitoring|Packet Activity"
msgstr ""
@@ -25864,6 +26767,9 @@ msgstr ""
msgid "ThreatMonitoring|Something went wrong, unable to fetch statistics"
msgstr ""
+msgid "ThreatMonitoring|Statistics"
+msgstr ""
+
msgid "ThreatMonitoring|The firewall is not installed or has been disabled. To view this data, ensure the web application firewall is installed and enabled for your cluster."
msgstr ""
@@ -26257,6 +27163,9 @@ msgstr ""
msgid "To update Snippets with multiple files, you must use the `files` parameter"
msgstr ""
+msgid "To use Gitpod you must first enable the feature in the integrations section of your %{user_prefs}."
+msgstr ""
+
msgid "To view all %{scannedResourcesCount} scanned URLs, please download the CSV file"
msgstr ""
@@ -26290,9 +27199,6 @@ msgstr ""
msgid "Toggle Sidebar"
msgstr ""
-msgid "Toggle all threads"
-msgstr ""
-
msgid "Toggle backtrace"
msgstr ""
@@ -26317,9 +27223,6 @@ msgstr ""
msgid "Toggle navigation"
msgstr ""
-msgid "Toggle project"
-msgstr ""
-
msgid "Toggle sidebar"
msgstr ""
@@ -26359,6 +27262,9 @@ msgstr ""
msgid "Too many projects enabled. You will need to manage them via the console or the API."
msgstr ""
+msgid "Too much data"
+msgstr ""
+
msgid "Topics (optional)"
msgstr ""
@@ -26377,6 +27283,9 @@ msgstr ""
msgid "Total cores (CPUs)"
msgstr ""
+msgid "Total days to completion"
+msgstr ""
+
msgid "Total issues"
msgstr ""
@@ -26473,6 +27382,9 @@ msgstr ""
msgid "Trending"
msgstr ""
+msgid "Trials|Create a new group to start your GitLab Gold trial."
+msgstr ""
+
msgid "Trials|Go back to GitLab"
msgstr ""
@@ -26482,6 +27394,15 @@ msgstr ""
msgid "Trials|You can always resume this process by selecting your avatar and choosing 'Start a Gold trial'"
msgstr ""
+msgid "Trials|You can apply your trial to a new group or an existing group."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group or your personal account."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group, an existing group, or your personal account."
+msgstr ""
+
msgid "Trials|You won't get a free trial right now but you can always resume this process by clicking on your avatar and choosing 'Start a free trial'"
msgstr ""
@@ -26551,6 +27472,9 @@ msgstr ""
msgid "Try using a different search term to find the file you are looking for."
msgstr ""
+msgid "Trying to communicate with your device. Plug it in (if needed) and press the button on the device now."
+msgstr ""
+
msgid "Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now."
msgstr ""
@@ -26638,6 +27562,12 @@ msgstr ""
msgid "URL or request ID"
msgstr ""
+msgid "USER %{user} WILL BE REMOVED! Are you sure?"
+msgstr ""
+
+msgid "USER WILL BE BLOCKED! Are you sure?"
+msgstr ""
+
msgid "UTC"
msgstr ""
@@ -26695,9 +27625,6 @@ msgstr ""
msgid "Unable to load the merge request widget. Try reloading the page."
msgstr ""
-msgid "Unable to resolve"
-msgstr ""
-
msgid "Unable to save iteration. Please try again"
msgstr ""
@@ -26746,6 +27673,9 @@ msgstr ""
msgid "Undo ignore"
msgstr ""
+msgid "Unexpected error"
+msgstr ""
+
msgid "Unfortunately, your email message to GitLab could not be processed."
msgstr ""
@@ -26779,6 +27709,9 @@ msgstr ""
msgid "Unknown response text"
msgstr ""
+msgid "Unless otherwise agreed to in writing with GitLab, by clicking \"Upload License\" you agree that your use of GitLab Software is subject to the %{eula_link_start}Terms of Service%{eula_link_end}."
+msgstr ""
+
msgid "Unlimited"
msgstr ""
@@ -27145,9 +28078,6 @@ msgstr ""
msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
msgstr ""
-msgid "Use a hardware device to add the second factor of authentication."
-msgstr ""
-
msgid "Use an one time password authenticator on your mobile device or computer to enable two-factor authentication (2FA)."
msgstr ""
@@ -27421,13 +28351,13 @@ msgstr ""
msgid "Users"
msgstr ""
-msgid "Users in License:"
+msgid "Users in License"
msgstr ""
-msgid "Users or groups set as approvers in the project's or merge request's settings."
+msgid "Users in License:"
msgstr ""
-msgid "Users outside of license"
+msgid "Users or groups set as approvers in the project's or merge request's settings."
msgstr ""
msgid "Users over License:"
@@ -27445,9 +28375,6 @@ msgstr ""
msgid "Users with a Guest role or those who don't belong to a Project or Group will not use a seat from your license."
msgstr ""
-msgid "Users with a Guest role or those who don't belong to any projects or groups don't count towards seats in use."
-msgstr ""
-
msgid "UsersSelect|%{name} + %{length} more"
msgstr ""
@@ -27487,9 +28414,6 @@ msgstr ""
msgid "Validations failed."
msgstr ""
-msgid "Validity"
-msgstr ""
-
msgid "Value"
msgstr ""
@@ -27508,6 +28432,9 @@ msgstr ""
msgid "Value Stream Name"
msgstr ""
+msgid "ValueStreamAnalyticsStage|We don't have enough data to show this stage."
+msgstr ""
+
msgid "ValueStreamAnalytics|%{days}d"
msgstr ""
@@ -27766,6 +28693,9 @@ msgstr ""
msgid "VisualReviewApp|Steps 1 and 2 (and sometimes 3) are performed once by the developer before requesting feedback. Steps 3 (if necessary), 4 is performed by the reviewer each time they perform a review."
msgstr ""
+msgid "Visualization"
+msgstr ""
+
msgid "Vulnerabilities"
msgstr ""
@@ -27793,34 +28723,31 @@ msgstr ""
msgid "VulnerabilityChart|Severity"
msgstr ""
-msgid "VulnerabilityManagement|A true-positive and will fix"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Change status"
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|Confirm"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Confirmed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
-msgstr ""
-
-msgid "VulnerabilityManagement|Detected %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|A true-positive and will fix"
msgstr ""
-msgid "VulnerabilityManagement|Dismiss"
+msgid "VulnerabilityManagement|Change status"
msgstr ""
-msgid "VulnerabilityManagement|Dismissed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
msgstr ""
-msgid "VulnerabilityManagement|Resolved"
+msgid "VulnerabilityManagement|Detected"
msgstr ""
-msgid "VulnerabilityManagement|Resolved %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Needs triage"
msgstr ""
msgid "VulnerabilityManagement|Something went wrong while trying to delete the comment. Please try again later."
@@ -27871,6 +28798,9 @@ msgstr ""
msgid "Vulnerability|%{scannerName} (version %{scannerVersion})"
msgstr ""
+msgid "Vulnerability|Activity"
+msgstr ""
+
msgid "Vulnerability|Class"
msgstr ""
@@ -27883,6 +28813,9 @@ msgstr ""
msgid "Vulnerability|Description"
msgstr ""
+msgid "Vulnerability|Detected"
+msgstr ""
+
msgid "Vulnerability|Evidence"
msgstr ""
@@ -27946,6 +28879,9 @@ msgstr ""
msgid "Warning: Displaying this diagram might cause performance issues on this page."
msgstr ""
+msgid "We are currently unable to fetch data for the pipeline header."
+msgstr ""
+
msgid "We are currently unable to fetch data for this graph."
msgstr ""
@@ -27985,6 +28921,12 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
+msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
+msgstr ""
+
+msgid "We would like to inform you that your subscription GitLab Enterprise Edition %{plan_name} is nearing its user limit. You have %{active_user_count} active users, which is almost at the user limit of %{maximum_user_count}."
+msgstr ""
+
msgid "We've found no vulnerabilities"
msgstr ""
@@ -28000,6 +28942,12 @@ msgstr ""
msgid "Web terminal"
msgstr ""
+msgid "WebAuthn Devices (%{length})"
+msgstr ""
+
+msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
+msgstr ""
+
msgid "WebIDE|Merge request"
msgstr ""
@@ -28138,15 +29086,9 @@ msgstr ""
msgid "Welcome to the guided GitLab tour"
msgstr ""
-msgid "Welcome to your Issue Board!"
-msgstr ""
-
msgid "Welcome to your issue board!"
msgstr ""
-msgid "We’ve been making changes to %{featureName} and we’d love your feedback %{linkStart}in this issue%{linkEnd} to help us improve the experience."
-msgstr ""
-
msgid "What are you searching for?"
msgstr ""
@@ -28165,6 +29107,9 @@ msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
msgstr ""
+msgid "When enabled, any user visiting %{host} and creating an account will have to be explicitly approved by the admin before they can login. This setting is effective only if sign-ups are enabled."
+msgstr ""
+
msgid "When enabled, any user visiting %{host} will be able to create an account."
msgstr ""
@@ -28390,6 +29335,9 @@ msgstr ""
msgid "With requirements, you can set criteria to check your products against."
msgstr ""
+msgid "With test cases, you can define conditions for your project to meet in determining quality"
+msgstr ""
+
msgid "Withdraw Access Request"
msgstr ""
@@ -28405,6 +29353,9 @@ msgstr ""
msgid "Workflow Help"
msgstr ""
+msgid "Would you like to create a new branch?"
+msgstr ""
+
msgid "Write"
msgstr ""
@@ -28426,6 +29377,9 @@ msgstr ""
msgid "Wrong extern UID provided. Make sure Auth0 is configured correctly."
msgstr ""
+msgid "YYYY-MM-DD"
+msgstr ""
+
msgid "Yes"
msgstr ""
@@ -28483,7 +29437,7 @@ msgstr ""
msgid "You are going to remove the fork relationship from %{project_full_name}. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "You are going to transfer %{project_full_name} to another owner. Are you ABSOLUTELY sure?"
+msgid "You are going to transfer %{project_full_name} to another namespace. Are you ABSOLUTELY sure?"
msgstr ""
msgid "You are going to turn off the confidentiality. This means %{strongStart}everyone%{strongEnd} will be able to see and leave a comment on this %{issuableType}."
@@ -28543,9 +29497,6 @@ msgstr ""
msgid "You can always edit this later"
msgstr ""
-msgid "You can apply your Trial to your Personal account or create a New Group."
-msgstr ""
-
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings"
msgstr ""
@@ -28567,12 +29518,18 @@ msgstr ""
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
+msgid "You can find more information about GitLab subscriptions in %{subscriptions_doc_link}."
+msgstr ""
+
msgid "You can generate an access token scoped to this project for each application to use the GitLab API."
msgstr ""
msgid "You can get started by cloning the repository or start adding files to it with one of the following options."
msgstr ""
+msgid "You can group test cases using labels. To learn about the future direction of this feature, visit %{linkStart}Quality Management direction page%{linkEnd}."
+msgstr ""
+
msgid "You can invite a new member to %{project_name} or invite another group."
msgstr ""
@@ -28588,6 +29545,9 @@ msgstr ""
msgid "You can notify the app / group or a project by sending them an email notification"
msgstr ""
+msgid "You can now close this window."
+msgstr ""
+
msgid "You can now export your security dashboard to a CSV report."
msgstr ""
@@ -28636,9 +29596,6 @@ msgstr ""
msgid "You can test your .gitlab-ci.yml in %{linkStart}CI Lint%{linkEnd}."
msgstr ""
-msgid "You can try again using %{begin_link}basic search%{end_link}"
-msgstr ""
-
msgid "You cannot access the raw file. Please wait a minute."
msgstr ""
@@ -28690,6 +29647,9 @@ msgstr ""
msgid "You don't have any U2F devices registered yet."
msgstr ""
+msgid "You don't have any WebAuthn devices registered yet."
+msgstr ""
+
msgid "You don't have any active chat names."
msgstr ""
@@ -28777,6 +29737,9 @@ msgstr ""
msgid "You must accept our Terms of Service and privacy policy in order to register an account"
msgstr ""
+msgid "You must be logged in to search across all of GitLab"
+msgstr ""
+
msgid "You must disassociate %{domain} from all clusters it is attached to before deletion."
msgstr ""
@@ -28816,7 +29779,7 @@ msgstr ""
msgid "You need to be logged in."
msgstr ""
-msgid "You need to register a two-factor authentication app before you can set up a U2F device."
+msgid "You need to register a two-factor authentication app before you can set up a device."
msgstr ""
msgid "You need to set terms to be enforced"
@@ -28834,6 +29797,9 @@ msgstr ""
msgid "You reached %{usage_in_percent} of %{namespace_name}'s storage capacity (%{used_storage} of %{storage_limit})"
msgstr ""
+msgid "You successfully declined the invitation"
+msgstr ""
+
msgid "You tried to fork %{link_to_the_project} but it failed for the following reason:"
msgstr ""
@@ -28999,10 +29965,13 @@ msgstr ""
msgid "Your U2F device did not send a valid JSON response."
msgstr ""
-msgid "Your U2F device needs to be set up. Plug it in (if not already) and click the button on the left."
+msgid "Your U2F device was registered!"
+msgstr ""
+
+msgid "Your WebAuthn device did not send a valid JSON response."
msgstr ""
-msgid "Your U2F device was registered!"
+msgid "Your WebAuthn device was registered!"
msgstr ""
msgid "Your access request to the %{source_type} has been withdrawn."
@@ -29026,6 +29995,9 @@ msgstr ""
msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
msgstr ""
+msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
+msgstr ""
+
msgid "Your changes can be committed to %{branch_name} because a merge request is open."
msgstr ""
@@ -29062,6 +30034,12 @@ msgstr ""
msgid "Your deployment services will be broken, you will need to manually fix the services after renaming."
msgstr ""
+msgid "Your device is not compatible with GitLab. Please try another device"
+msgstr ""
+
+msgid "Your device needs to be set up. Plug it in (if needed) and click the button on the left."
+msgstr ""
+
msgid "Your device was successfully set up! Give it a name and register it with the GitLab server."
msgstr ""
@@ -29176,9 +30154,6 @@ msgstr[2] "približno %d sati"
msgid "access:"
msgstr ""
-msgid "activated"
-msgstr ""
-
msgid "added %{created_at_timeago}"
msgstr ""
@@ -29251,9 +30226,21 @@ msgstr ""
msgid "by %{user}"
msgstr ""
+msgid "cannot be a date in the past"
+msgstr ""
+
msgid "cannot be changed if a personal project has container registry tags."
msgstr ""
+msgid "cannot be changed if shared runners are enabled"
+msgstr ""
+
+msgid "cannot be enabled because parent group does not allow it"
+msgstr ""
+
+msgid "cannot be enabled because parent group has shared Runners disabled"
+msgstr ""
+
msgid "cannot be enabled unless all domains have TLS certificates"
msgstr ""
@@ -29299,7 +30286,7 @@ msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about SAST %{linkEndTag}"
msgstr ""
-msgid "ciReport|%{linkStartTag}Learn more about Secret Scanning %{linkEndTag}"
+msgid "ciReport|%{linkStartTag}Learn more about Secret Detection %{linkEndTag}"
msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about codequality reports %{linkEndTag}"
@@ -29617,9 +30604,6 @@ msgstr ""
msgid "error"
msgstr ""
-msgid "error code:"
-msgstr ""
-
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr ""
@@ -29641,6 +30625,9 @@ msgstr ""
msgid "failed to dismiss associated finding(id=%{finding_id}): %{message}"
msgstr ""
+msgid "failed to revert associated finding(id=%{finding_id}) to detected"
+msgstr ""
+
msgid "file"
msgid_plural "files"
msgstr[0] ""
@@ -30187,6 +31174,9 @@ msgstr ""
msgid "must be a root namespace"
msgstr ""
+msgid "must be a valid IPv4 or IPv6 address"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -30223,6 +31213,9 @@ msgstr ""
msgid "no expiration"
msgstr ""
+msgid "no name set"
+msgstr ""
+
msgid "no one can merge"
msgstr ""
@@ -30406,9 +31399,6 @@ msgstr ""
msgid "security Reports|There was an error creating the merge request"
msgstr ""
-msgid "settings saved, but not activated"
-msgstr ""
-
msgid "severity|Critical"
msgstr ""
@@ -30535,9 +31525,6 @@ msgstr ""
msgid "toggle collapse"
msgstr ""
-msgid "toggle dropdown"
-msgstr ""
-
msgid "triggered"
msgstr ""
@@ -30565,6 +31552,9 @@ msgstr ""
msgid "user avatar"
msgstr ""
+msgid "user preferences"
+msgstr ""
+
msgid "username"
msgstr ""
diff --git a/locale/hu_HU/gitlab.po b/locale/hu_HU/gitlab.po
index 9839d034892..e0a6239f240 100644
--- a/locale/hu_HU/gitlab.po
+++ b/locale/hu_HU/gitlab.po
@@ -14,7 +14,10 @@ msgstr ""
"X-Crowdin-Language: hu\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 6\n"
-"PO-Revision-Date: 2020-09-04 23:08\n"
+"PO-Revision-Date: 2020-10-02 18:47\n"
+
+msgid " %{project_name}#%{issue_iid} &middot; opened %{issue_created} by %{author}"
+msgstr ""
msgid " %{start} to %{end}"
msgstr ""
@@ -74,6 +77,16 @@ msgstr ""
msgid "\"el\" parameter is required for createInstance()"
msgstr ""
+msgid "%d Approval"
+msgid_plural "%d Approvals"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d Package"
+msgid_plural "%d Packages"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d Scanned URL"
msgid_plural "%d Scanned URLs"
msgstr[0] ""
@@ -137,6 +150,11 @@ msgstr[1] ""
msgid "%d commits"
msgstr ""
+msgid "%d completed issue"
+msgid_plural "%d completed issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d contribution"
msgid_plural "%d contributions"
msgstr[0] ""
@@ -147,6 +165,11 @@ msgid_plural "%d days"
msgstr[0] ""
msgstr[1] ""
+msgid "%d day until tags are automatically removed"
+msgid_plural "%d days until tags are automatically removed"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d error"
msgid_plural "%d errors"
msgstr[0] ""
@@ -237,6 +260,16 @@ msgid_plural "%d more comments"
msgstr[0] ""
msgstr[1] ""
+msgid "%d open issue"
+msgid_plural "%d open issues"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d pending comment"
+msgid_plural "%d pending comments"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d personal project will be removed and cannot be restored."
msgid_plural "%d personal projects will be removed and cannot be restored."
msgstr[0] ""
@@ -252,6 +285,11 @@ msgid_plural "%d projects"
msgstr[0] ""
msgstr[1] ""
+msgid "%d project selected"
+msgid_plural "%d projects selected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d request with warnings"
msgid_plural "%d requests with warnings"
msgstr[0] ""
@@ -272,6 +310,11 @@ msgid_plural "%d tags"
msgstr[0] ""
msgstr[1] ""
+msgid "%d tag per image name"
+msgid_plural "%d tags per image name"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d unassigned issue"
msgid_plural "%d unassigned issues"
msgstr[0] ""
@@ -292,6 +335,11 @@ msgid_plural "%d vulnerabilities dismissed"
msgstr[0] ""
msgstr[1] ""
+msgid "%d warning found:"
+msgid_plural "%d warnings found:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%s additional commit has been omitted to prevent performance issues."
msgid_plural "%s additional commits have been omitted to prevent performance issues."
msgstr[0] ""
@@ -330,6 +378,9 @@ msgstr ""
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr ""
+msgid "%{completedCount} completed weight"
+msgstr ""
+
msgid "%{completedWeight} of %{totalWeight} weight completed"
msgstr ""
@@ -378,14 +429,12 @@ msgid_plural "%{count} participants"
msgstr[0] ""
msgstr[1] ""
-msgid "%{count} pending comment"
-msgid_plural "%{count} pending comments"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
+msgid "%{count} total weight"
+msgstr ""
+
msgid "%{dashboard_path} could not be found."
msgstr ""
@@ -440,6 +489,9 @@ msgstr ""
msgid "%{group_name} uses group managed accounts. You need to create a new GitLab account which will be managed by %{group_name}."
msgstr ""
+msgid "%{group_name}&%{epic_iid} &middot; opened %{epic_created} by %{author}"
+msgstr ""
+
msgid "%{host} sign-in from new location"
msgstr ""
@@ -452,7 +504,7 @@ msgstr ""
msgid "%{issuableType} will be removed! Are you sure?"
msgstr ""
-msgid "%{issuesSize} issues with a limit of %{maxIssueCount}"
+msgid "%{issuesCount} issues with a limit of %{maxIssueCount}"
msgstr ""
msgid "%{issuesSize} with a limit of %{maxIssueCount}"
@@ -485,7 +537,7 @@ msgstr ""
msgid "%{labelStart}Namespace:%{labelEnd} %{namespace}"
msgstr ""
-msgid "%{labelStart}Report Type:%{labelEnd} %{reportType}"
+msgid "%{labelStart}Scan Type:%{labelEnd} %{reportType}"
msgstr ""
msgid "%{labelStart}Scanner:%{labelEnd} %{scanner}"
@@ -682,9 +734,6 @@ msgid_plural "%{securityScanner} results are not available because a pipeline ha
msgstr[0] ""
msgstr[1] ""
-msgid "%{service_title} %{message}."
-msgstr ""
-
msgid "%{size} GiB"
msgstr ""
@@ -773,6 +822,12 @@ msgstr ""
msgid "%{timebox_name} should belong either to a project or a group."
msgstr ""
+msgid "%{timebox_type} does not support burnup charts"
+msgstr ""
+
+msgid "%{timebox_type} must have a start and due date"
+msgstr ""
+
msgid "%{title} %{operator} %{threshold}"
msgstr ""
@@ -797,7 +852,7 @@ msgstr ""
msgid "%{total} open issue weight"
msgstr ""
-msgid "%{total} open issues"
+msgid "%{total} warnings found: showing first %{warningsDisplayed}"
msgstr ""
msgid "%{usage_ping_link_start}Learn more%{usage_ping_link_end} about what information is shared with GitLab Inc."
@@ -830,9 +885,6 @@ msgstr ""
msgid "&lt; 1 hour"
msgstr ""
-msgid "&lt;no name set&gt;"
-msgstr ""
-
msgid "&lt;no scopes selected&gt;"
msgstr ""
@@ -863,6 +915,9 @@ msgstr ""
msgid "'%{name}' Value Stream created"
msgstr ""
+msgid "'%{name}' Value Stream deleted"
+msgstr ""
+
msgid "'%{name}' stage already exists"
msgstr ""
@@ -922,6 +977,9 @@ msgstr ""
msgid "+ %{numberOfHiddenAssignees} more"
msgstr ""
+msgid "+ %{numberOfHiddenReviewers} more"
+msgstr ""
+
msgid "+%d more"
msgid_plural "+%d more"
msgstr[0] ""
@@ -982,6 +1040,11 @@ msgid_plural "%d Days"
msgstr[0] ""
msgstr[1] ""
+msgid "1 Issue"
+msgid_plural "%d Issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "1 closed issue"
msgid_plural "%{issues} closed issues"
msgstr[0] ""
@@ -997,6 +1060,11 @@ msgid_plural "%d days"
msgstr[0] ""
msgstr[1] ""
+msgid "1 deploy key"
+msgid_plural "%d deploy keys"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1099,6 +1167,9 @@ msgstr ""
msgid ":%{startLine} to %{endLine}"
msgstr ""
+msgid "A %{incident_docs_start}modified issue%{incident_docs_end} to guide the resolution of incidents."
+msgstr ""
+
msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr ""
@@ -1111,6 +1182,9 @@ msgstr ""
msgid "A GitBook site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
+msgid "A Gitpod configured Webapplication in Spring and Java"
+msgstr ""
+
msgid "A Hexo site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
@@ -1282,9 +1356,15 @@ msgstr ""
msgid "Access expiration date"
msgstr ""
+msgid "Access expires"
+msgstr ""
+
msgid "Access forbidden. Check your access level."
msgstr ""
+msgid "Access granted"
+msgstr ""
+
msgid "Access requests"
msgstr ""
@@ -1294,6 +1374,9 @@ msgstr ""
msgid "Access to Pages websites are controlled based on the user's membership to a given project. By checking this box, users will be required to be logged in to have access to all Pages websites in your instance."
msgstr ""
+msgid "AccessDropdown|Deploy Keys"
+msgstr ""
+
msgid "AccessDropdown|Groups"
msgstr ""
@@ -1411,12 +1494,6 @@ msgstr ""
msgid "Active Sessions"
msgstr ""
-msgid "Active Users:"
-msgstr ""
-
-msgid "Active users"
-msgstr ""
-
msgid "Activity"
msgstr ""
@@ -1584,9 +1661,6 @@ msgstr ""
msgid "Add label(s)"
msgstr ""
-msgid "Add license"
-msgstr ""
-
msgid "Add list"
msgstr ""
@@ -1761,21 +1835,51 @@ msgstr ""
msgid "AdminArea|Bots"
msgstr ""
+msgid "AdminArea|Components"
+msgstr ""
+
msgid "AdminArea|Developer"
msgstr ""
+msgid "AdminArea|Features"
+msgstr ""
+
+msgid "AdminArea|Groups: %{number_of_groups}"
+msgstr ""
+
msgid "AdminArea|Guest"
msgstr ""
msgid "AdminArea|Included Free in license"
msgstr ""
+msgid "AdminArea|Latest groups"
+msgstr ""
+
+msgid "AdminArea|Latest projects"
+msgstr ""
+
+msgid "AdminArea|Latest users"
+msgstr ""
+
msgid "AdminArea|Maintainer"
msgstr ""
+msgid "AdminArea|New group"
+msgstr ""
+
+msgid "AdminArea|New project"
+msgstr ""
+
+msgid "AdminArea|New user"
+msgstr ""
+
msgid "AdminArea|Owner"
msgstr ""
+msgid "AdminArea|Projects: %{number_of_projects}"
+msgstr ""
+
msgid "AdminArea|Reporter"
msgstr ""
@@ -1803,6 +1907,9 @@ msgstr ""
msgid "AdminArea|Users without a Group and Project"
msgstr ""
+msgid "AdminArea|Users: %{number_of_users}"
+msgstr ""
+
msgid "AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running."
msgstr ""
@@ -1821,9 +1928,6 @@ msgstr ""
msgid "AdminProjects|Delete Project %{projectName}?"
msgstr ""
-msgid "AdminProjects|Delete project"
-msgstr ""
-
msgid "AdminSettings|Apply integration settings to all Projects"
msgstr ""
@@ -2061,21 +2165,30 @@ msgstr ""
msgid "AdminUsers|Without projects"
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 ""
msgid "AdminUsers|You cannot remove your own admin rights."
msgstr ""
+msgid "AdminUsers|You must transfer ownership or delete the groups owned by this user before you can delete their account"
+msgstr ""
+
msgid "Administration"
msgstr ""
msgid "Advanced"
msgstr ""
+msgid "Advanced Search"
+msgstr ""
+
+msgid "Advanced Search with Elasticsearch"
+msgstr ""
+
msgid "Advanced Settings"
msgstr ""
@@ -2153,6 +2266,9 @@ msgstr ""
msgid "AlertManagement|Edit"
msgstr ""
+msgid "AlertManagement|Environment"
+msgstr ""
+
msgid "AlertManagement|Events"
msgstr ""
@@ -2165,6 +2281,9 @@ msgstr ""
msgid "AlertManagement|Issue"
msgstr ""
+msgid "AlertManagement|Key"
+msgstr ""
+
msgid "AlertManagement|Low"
msgstr ""
@@ -2258,6 +2377,9 @@ msgstr ""
msgid "AlertManagement|Unknown"
msgstr ""
+msgid "AlertManagement|Value"
+msgstr ""
+
msgid "AlertManagement|View alerts in Opsgenie"
msgstr ""
@@ -2417,6 +2539,9 @@ msgstr ""
msgid "All projects"
msgstr ""
+msgid "All projects selected"
+msgstr ""
+
msgid "All security scans are enabled because %{linkStart}Auto DevOps%{linkEnd} is enabled on this project"
msgstr ""
@@ -2504,6 +2629,9 @@ msgstr ""
msgid "Almost there"
msgstr ""
+msgid "Already blocked"
+msgstr ""
+
msgid "Also called \"Issuer\" or \"Relying party trust identifier\""
msgstr ""
@@ -2558,6 +2686,9 @@ msgstr ""
msgid "An error has occurred"
msgstr ""
+msgid "An error occured while making the changes: %{error}"
+msgstr ""
+
msgid "An error occurred adding a draft to the thread."
msgstr ""
@@ -2585,12 +2716,6 @@ msgstr ""
msgid "An error occurred when toggling the notification subscription"
msgstr ""
-msgid "An error occurred when trying to resolve a comment. Please try again."
-msgstr ""
-
-msgid "An error occurred when trying to resolve a discussion. Please try again."
-msgstr ""
-
msgid "An error occurred when updating the issue weight"
msgstr ""
@@ -2606,12 +2731,6 @@ msgstr ""
msgid "An error occurred while checking group path. Please refresh and try again."
msgstr ""
-msgid "An error occurred while committing your changes."
-msgstr ""
-
-msgid "An error occurred while creating the list. Please try again."
-msgstr ""
-
msgid "An error occurred while decoding the file."
msgstr ""
@@ -2684,25 +2803,19 @@ msgstr ""
msgid "An error occurred while fetching the Service Desk address."
msgstr ""
-msgid "An error occurred while fetching the board issues. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the board lists. Please reload the page."
msgstr ""
msgid "An error occurred while fetching the board lists. Please try again."
msgstr ""
-msgid "An error occurred while fetching the board swimlanes. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the builds."
msgstr ""
msgid "An error occurred while fetching the job log."
msgstr ""
-msgid "An error occurred while fetching the job trace."
+msgid "An error occurred while fetching the job logs."
msgstr ""
msgid "An error occurred while fetching the job."
@@ -2849,9 +2962,6 @@ msgstr ""
msgid "An error occurred while saving assignees"
msgstr ""
-msgid "An error occurred while saving the template. Please check if the template exists."
-msgstr ""
-
msgid "An error occurred while searching for milestones"
msgstr ""
@@ -2870,10 +2980,10 @@ msgstr ""
msgid "An error occurred while updating approvers"
msgstr ""
-msgid "An error occurred while updating the comment"
+msgid "An error occurred while updating labels."
msgstr ""
-msgid "An error occurred while updating the list. Please try again."
+msgid "An error occurred while updating the comment"
msgstr ""
msgid "An error occurred while validating group path"
@@ -2927,6 +3037,9 @@ msgstr ""
msgid "An unknown error occurred while loading this graph."
msgstr ""
+msgid "An unknown error occurred."
+msgstr ""
+
msgid "Analytics"
msgstr ""
@@ -2960,10 +3073,10 @@ msgstr ""
msgid "Any"
msgstr ""
-msgid "Any Author"
+msgid "Any %{header}"
msgstr ""
-msgid "Any Status"
+msgid "Any Author"
msgstr ""
msgid "Any branch"
@@ -3017,6 +3130,9 @@ msgstr ""
msgid "Application ID"
msgstr ""
+msgid "Application limits saved successfully"
+msgstr ""
+
msgid "Application settings saved successfully"
msgstr ""
@@ -3226,6 +3342,9 @@ msgstr ""
msgid "Are you sure you want to close this blocked issue?"
msgstr ""
+msgid "Are you sure you want to delete \"%{name}\" Value Stream?"
+msgstr ""
+
msgid "Are you sure you want to delete %{name}?"
msgstr ""
@@ -3235,6 +3354,9 @@ msgstr ""
msgid "Are you sure you want to delete this %{typeOfComment}?"
msgstr ""
+msgid "Are you sure you want to delete this SSH key?"
+msgstr ""
+
msgid "Are you sure you want to delete this board?"
msgstr ""
@@ -3259,6 +3381,11 @@ msgstr ""
msgid "Are you sure you want to erase this build?"
msgstr ""
+msgid "Are you sure you want to import %d repository?"
+msgid_plural "Are you sure you want to import %d repositories?"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Are you sure you want to lose unsaved changes?"
msgstr ""
@@ -3268,15 +3395,15 @@ msgstr ""
msgid "Are you sure you want to merge immediately?"
msgstr ""
-msgid "Are you sure you want to permanently delete this license?"
-msgstr ""
-
msgid "Are you sure you want to re-deploy this environment?"
msgstr ""
msgid "Are you sure you want to regenerate the public key? You will have to update the public key on the remote server before mirroring will work again."
msgstr ""
+msgid "Are you sure you want to reindex?"
+msgstr ""
+
msgid "Are you sure you want to remove %{group_name}?"
msgstr ""
@@ -3304,6 +3431,9 @@ msgstr ""
msgid "Are you sure you want to revoke this nickname?"
msgstr ""
+msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
+msgstr ""
+
msgid "Are you sure you want to stop this environment?"
msgstr ""
@@ -3325,6 +3455,9 @@ msgstr ""
msgid "Are you sure? The device will be signed out of GitLab and all remember me tokens revoked."
msgstr ""
+msgid "Are you sure? This will invalidate your registered applications and U2F / WebAuthn devices."
+msgstr ""
+
msgid "Are you sure? This will invalidate your registered applications and U2F devices."
msgstr ""
@@ -3343,9 +3476,6 @@ msgstr ""
msgid "Artifacts"
msgstr ""
-msgid "As U2F devices are only supported by a few browsers, we require that you set up a two-factor authentication app before a U2F device. That way you'll always be able to log in - even when you're using an unsupported browser."
-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 ""
@@ -3539,6 +3669,9 @@ msgstr ""
msgid "AuditLogs|Target"
msgstr ""
+msgid "AuditLogs|This month"
+msgstr ""
+
msgid "AuditLogs|User Events"
msgstr ""
@@ -3578,6 +3711,9 @@ msgstr ""
msgid "Authentication via U2F device failed."
msgstr ""
+msgid "Authentication via WebAuthn device failed."
+msgstr ""
+
msgid "Author"
msgstr ""
@@ -3845,15 +3981,6 @@ msgstr ""
msgid "BambooService|You must set up automatic revision labeling and a repository trigger in Bamboo."
msgstr ""
-msgid "BatchComments|Delete all pending comments"
-msgstr ""
-
-msgid "BatchComments|Discard review?"
-msgstr ""
-
-msgid "BatchComments|You're about to discard your review which will delete all of your pending comments. The deleted comments %{strong_start}cannot%{strong_end} be restored."
-msgstr ""
-
msgid "Be careful. Changing the project's namespace can have unintended side effects."
msgstr ""
@@ -3875,6 +4002,9 @@ msgstr ""
msgid "Bi-weekly code coverage"
msgstr ""
+msgid "Billable Users:"
+msgstr ""
+
msgid "Billing"
msgstr ""
@@ -3884,7 +4014,7 @@ msgstr ""
msgid "BillingPlans|@%{user_name} you are currently using the %{plan_name} plan."
msgstr ""
-msgid "BillingPlans|Congratulations, your new trial is activated"
+msgid "BillingPlans|Congratulations, your free trial is activated."
msgstr ""
msgid "BillingPlans|If you would like to downgrade your plan please contact %{support_link_start}Customer Support%{support_link_end}."
@@ -3947,6 +4077,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Block user"
+msgstr ""
+
msgid "Blocked"
msgstr ""
@@ -3962,31 +4095,37 @@ msgstr ""
msgid "Blog"
msgstr ""
-msgid "Board name"
-msgstr ""
-
msgid "Board scope"
msgstr ""
msgid "Board scope affects which issues are displayed for anyone who visits this board"
msgstr ""
-msgid "BoardBlankState|Add default lists"
+msgid "Boards"
msgstr ""
-msgid "BoardBlankState|Add the following default lists to your Issue Board with one click:"
+msgid "Boards and Board Lists"
msgstr ""
-msgid "BoardBlankState|Nevermind, I'll use my own"
+msgid "Boards|An error occurred while creating the issue. Please try again."
msgstr ""
-msgid "BoardBlankState|Starting out with the default set of lists will get you right on the way to making the most of your board."
+msgid "Boards|An error occurred while creating the list. Please try again."
msgstr ""
-msgid "Boards"
+msgid "Boards|An error occurred while fetching issues. Please reload the page."
msgstr ""
-msgid "Boards and Board Lists"
+msgid "Boards|An error occurred while fetching the board issues. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching the board swimlanes. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while moving the issue. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while updating the list. Please try again."
msgstr ""
msgid "Boards|Collapse"
@@ -4013,7 +4152,7 @@ msgstr ""
msgid "Branch %{branch_name} was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr ""
-msgid "Branch has changed"
+msgid "Branch changed"
msgstr ""
msgid "Branch is already taken"
@@ -4319,6 +4458,9 @@ msgstr ""
msgid "CLOSED (MOVED)"
msgstr ""
+msgid "CODEOWNERS rule violation"
+msgstr ""
+
msgid "CONTRIBUTING"
msgstr ""
@@ -4349,9 +4491,6 @@ msgstr ""
msgid "Can't create snippet: %{err}"
msgstr ""
-msgid "Can't edit as source branch was deleted"
-msgstr ""
-
msgid "Can't fetch content for the blob: %{err}"
msgstr ""
@@ -4364,9 +4503,6 @@ msgstr ""
msgid "Can't load mermaid module: %{err}"
msgstr ""
-msgid "Can't remove group members without group managed account"
-msgstr ""
-
msgid "Can't scan the code?"
msgstr ""
@@ -4409,6 +4545,9 @@ msgstr ""
msgid "Cannot create the abuse report. This user has been blocked."
msgstr ""
+msgid "Cannot enable shared runners because parent group does not allow it"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -4514,6 +4653,15 @@ msgstr ""
msgid "Change your password or recover your current one"
msgstr ""
+msgid "ChangeReviewer|Reviewer changed from %{old} to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Reviewer changed to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Unassigned"
+msgstr ""
+
msgid "ChangeTypeActionLabel|Pick into branch"
msgstr ""
@@ -4553,6 +4701,9 @@ msgstr ""
msgid "Changes the title to \"%{title_param}\"."
msgstr ""
+msgid "Changes were successfully made."
+msgstr ""
+
msgid "Changes won't take place until the index is %{link_start}recreated%{link_end}."
msgstr ""
@@ -4958,6 +5109,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove variable"
+msgstr ""
+
msgid "CiVariables|Remove variable row"
msgstr ""
@@ -5036,9 +5190,6 @@ msgstr ""
msgid "Clear due date"
msgstr ""
-msgid "Clear input"
-msgstr ""
-
msgid "Clear recent searches"
msgstr ""
@@ -5087,6 +5238,9 @@ msgstr ""
msgid "Client authentication key password"
msgstr ""
+msgid "Client request timeout"
+msgstr ""
+
msgid "Clients"
msgstr ""
@@ -5171,6 +5325,27 @@ msgstr ""
msgid "Cluster type must be specificed for Stages::ClusterEndpointInserter"
msgstr ""
+msgid "ClusterAgents|Configuration"
+msgstr ""
+
+msgid "ClusterAgents|Connect your cluster with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate Kubernetes with a GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Name"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Agent also requires %{linkStart}enabling the Agent Server%{linkEnd}"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Kubernetes Agent allows an Infrastructure as Code, GitOps approach to integrating Kubernetes clusters with GitLab. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "ClusterAgent|This feature is only available for premium plans"
msgstr ""
@@ -5240,10 +5415,10 @@ msgstr ""
msgid "ClusterIntegration|All installed applications and related resources"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster."
+msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{linkStart}More information%{linkEnd}"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{startLink}More information%{endLink}"
+msgid "ClusterIntegration|Allow GitLab to manage namespaces and service accounts for this cluster."
msgstr ""
msgid "ClusterIntegration|Alternatively, "
@@ -5264,6 +5439,9 @@ msgstr ""
msgid "ClusterIntegration|An error occurred while trying to fetch zone machine types: %{error}"
msgstr ""
+msgid "ClusterIntegration|An unknown error occurred while attempting to connect to Kubernetes."
+msgstr ""
+
msgid "ClusterIntegration|Any project namespaces"
msgstr ""
@@ -5279,6 +5457,9 @@ msgstr ""
msgid "ClusterIntegration|Authenticate with Amazon Web Services"
msgstr ""
+msgid "ClusterIntegration|Authentication Error"
+msgstr ""
+
msgid "ClusterIntegration|Base domain"
msgstr ""
@@ -5297,13 +5478,22 @@ msgstr ""
msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}security group %{externalLinkIcon} %{endLink} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
+msgid "ClusterIntegration|Check your CA certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Check your cluster status"
+msgstr ""
+
+msgid "ClusterIntegration|Check your token"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}subnets %{externalLinkIcon} %{endLink} in your VPC where your worker nodes will run."
+msgid "ClusterIntegration|Choose the %{linkStart}security group %{linkEnd} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
msgstr ""
-msgid "ClusterIntegration|Choose the worker node %{startLink}instance type %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Choose the %{linkStart}subnets %{linkEnd} in your VPC where your worker nodes will run."
+msgstr ""
+
+msgid "ClusterIntegration|Choose the worker node %{linkStart}instance type%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Choose which applications to install on your Kubernetes cluster."
@@ -5315,10 +5505,7 @@ msgstr ""
msgid "ClusterIntegration|Clear cluster cache"
msgstr ""
-msgid "ClusterIntegration|Clear the local cache of namespace and service accounts. This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
-msgstr ""
-
-msgid "ClusterIntegration|Cluster being created"
+msgid "ClusterIntegration|Clear the local cache of namespace and service accounts."
msgstr ""
msgid "ClusterIntegration|Cluster management project (alpha)"
@@ -5330,15 +5517,21 @@ msgstr ""
msgid "ClusterIntegration|Cluster_applications artifact too big. Maximum allowable size: %{human_size}"
msgstr ""
-msgid "ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters."
+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|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}"
+msgid "ClusterIntegration|Clusters connected with a certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Connect cluster with certificate"
msgstr ""
msgid "ClusterIntegration|Connect existing cluster"
msgstr ""
+msgid "ClusterIntegration|Connection Error"
+msgstr ""
+
msgid "ClusterIntegration|Copy API URL"
msgstr ""
@@ -5414,6 +5607,12 @@ msgstr ""
msgid "ClusterIntegration|Deletes all GitLab resources attached to this cluster during removal"
msgstr ""
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared."
+msgstr ""
+
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared. %{linkStart}More information%{linkEnd}"
+msgstr ""
+
msgid "ClusterIntegration|Did you know?"
msgstr ""
@@ -5483,6 +5682,9 @@ msgstr ""
msgid "ClusterIntegration|Fluentd is an open source data collector, which lets you unify the data collection and consumption for a better use and understanding of data. It requires at least one of the following logs to be successfully installed."
msgstr ""
+msgid "ClusterIntegration|GitLab Agent managed clusters"
+msgstr ""
+
msgid "ClusterIntegration|GitLab Container Network Policies"
msgstr ""
@@ -5495,6 +5697,12 @@ msgstr ""
msgid "ClusterIntegration|GitLab Runner connects to the repository and executes CI/CD jobs, pushing results back and deploying applications to production."
msgstr ""
+msgid "ClusterIntegration|GitLab failed to authenticate."
+msgstr ""
+
+msgid "ClusterIntegration|GitLab failed to connect to the cluster."
+msgstr ""
+
msgid "ClusterIntegration|GitLab-managed cluster"
msgstr ""
@@ -5516,6 +5724,9 @@ msgstr ""
msgid "ClusterIntegration|Group cluster"
msgstr ""
+msgid "ClusterIntegration|HTTP Error"
+msgstr ""
+
msgid "ClusterIntegration|Helm Tiller"
msgstr ""
@@ -5549,7 +5760,10 @@ msgstr ""
msgid "ClusterIntegration|Instance type"
msgstr ""
-msgid "ClusterIntegration|Integrate Kubernetes cluster automation"
+msgid "ClusterIntegration|Integrate Kubernetes with a cluster certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Integrate with a cluster certificate"
msgstr ""
msgid "ClusterIntegration|Issuer Email"
@@ -5585,9 +5799,6 @@ msgstr ""
msgid "ClusterIntegration|Knative extends Kubernetes to provide a set of middleware components that are essential to build modern, source-centric, and container-based applications that can run anywhere: on premises, in the cloud, or even in a third-party data center."
msgstr ""
-msgid "ClusterIntegration|Kubernetes cluster"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes cluster is being created..."
msgstr ""
@@ -5600,9 +5811,6 @@ msgstr ""
msgid "ClusterIntegration|Kubernetes clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr ""
-msgid "ClusterIntegration|Kubernetes clusters can be used to deploy applications and to provide Review Apps for this project"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes version"
msgstr ""
@@ -5615,7 +5823,7 @@ msgstr ""
msgid "ClusterIntegration|Learn more about %{help_link_start}zones%{help_link_end}."
msgstr ""
-msgid "ClusterIntegration|Learn more about %{startLink}Regions %{externalLinkIcon}%{endLink}."
+msgid "ClusterIntegration|Learn more about %{linkStart}Regions%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Learn more about Kubernetes"
@@ -5660,12 +5868,18 @@ msgstr ""
msgid "ClusterIntegration|Machine type"
msgstr ""
+msgid "ClusterIntegration|Make sure your API endpoint is correct"
+msgstr ""
+
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create Kubernetes clusters"
msgstr ""
msgid "ClusterIntegration|Manage your Kubernetes cluster by visiting %{provider_link}"
msgstr ""
+msgid "ClusterIntegration|Namespace per environment"
+msgstr ""
+
msgid "ClusterIntegration|No IAM Roles found"
msgstr ""
@@ -5711,6 +5925,9 @@ msgstr ""
msgid "ClusterIntegration|No zones matched your search"
msgstr ""
+msgid "ClusterIntegration|Node calculations use the Kubernetes Metrics API. Make sure your cluster has metrics installed"
+msgstr ""
+
msgid "ClusterIntegration|Number of nodes"
msgstr ""
@@ -5753,6 +5970,9 @@ msgstr ""
msgid "ClusterIntegration|RBAC-enabled cluster"
msgstr ""
+msgid "ClusterIntegration|Read our %{linkStart}help page%{linkEnd} on Kubernetes cluster integration."
+msgstr ""
+
msgid "ClusterIntegration|Read our %{link_start}help page%{link_end} on Kubernetes cluster integration."
msgstr ""
@@ -5855,7 +6075,7 @@ msgstr ""
msgid "ClusterIntegration|Select a VPC to choose a subnet"
msgstr ""
-msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{linkStart}Amazon Web Services %{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select a network to choose a subnetwork"
@@ -5888,7 +6108,7 @@ msgstr ""
msgid "ClusterIntegration|Select project to choose zone"
msgstr ""
-msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select zone"
@@ -5978,9 +6198,18 @@ msgstr ""
msgid "ClusterIntegration|There was a problem authenticating with your cluster. Please ensure your CA Certificate and Token are valid."
msgstr ""
+msgid "ClusterIntegration|There was an HTTP error when connecting to your cluster."
+msgstr ""
+
msgid "ClusterIntegration|This account must have permissions to create a Kubernetes cluster in the %{link_to_container_project} specified below"
msgstr ""
+msgid "ClusterIntegration|This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
+msgstr ""
+
+msgid "ClusterIntegration|This is necessary to clear existing environment-namespace associations from clusters previously managed by GitLab."
+msgstr ""
+
msgid "ClusterIntegration|This option will allow you to install applications on RBAC clusters."
msgstr ""
@@ -6005,9 +6234,21 @@ msgstr ""
msgid "ClusterIntegration|To use a new project, first create one on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}."
msgstr ""
+msgid "ClusterIntegration|Troubleshooting tips:"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Authenticate"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Connect"
+msgstr ""
+
msgid "ClusterIntegration|Uninstall %{appTitle}"
msgstr ""
+msgid "ClusterIntegration|Unknown Error"
+msgstr ""
+
msgid "ClusterIntegration|Update %{appTitle}"
msgstr ""
@@ -6068,7 +6309,7 @@ msgstr ""
msgid "ClusterIntegration|Your cluster API is unreachable. Please ensure your API URL is correct."
msgstr ""
-msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Zone"
@@ -6188,6 +6429,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse all threads"
+msgstr ""
+
msgid "Collapse approvers"
msgstr ""
@@ -6337,7 +6581,7 @@ msgstr ""
msgid "Commit…"
msgstr ""
-msgid "Company"
+msgid "Community forum"
msgstr ""
msgid "Company name"
@@ -6346,6 +6590,9 @@ msgstr ""
msgid "Compare"
msgstr ""
+msgid "Compare %{oldCommitId}...%{newCommitId}"
+msgstr ""
+
msgid "Compare Git revisions"
msgstr ""
@@ -6361,6 +6608,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare submodule commit revisions"
+msgstr ""
+
msgid "Compare with previous version"
msgstr ""
@@ -6496,6 +6746,9 @@ msgstr ""
msgid "Configure the way a user creates a new account."
msgstr ""
+msgid "Configure which lists are shown for anyone who visits this board"
+msgstr ""
+
msgid "Confirm"
msgstr ""
@@ -6721,6 +6974,9 @@ msgstr[1] ""
msgid "ContainerRegistry|Set cleanup policy"
msgstr ""
+msgid "ContainerRegistry|Some tags were not deleted"
+msgstr ""
+
msgid "ContainerRegistry|Something went wrong while fetching the cleanup policy."
msgstr ""
@@ -6760,6 +7016,9 @@ msgstr ""
msgid "ContainerRegistry|Tags with names matching this regex pattern will %{italicStart}expire:%{italicEnd}"
msgstr ""
+msgid "ContainerRegistry|The cleanup policy timed out before it could delete all tags. An administrator can %{adminLinkStart}manually run cleanup now%{adminLinkEnd} or you can wait for the cleanup policy to automatically run again. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "ContainerRegistry|The last tag related to this image was recently removed. This empty image and any associated data will be automatically removed as part of the regular Garbage Collection process. If you have any questions, contact your administrator."
msgstr ""
@@ -6892,6 +7151,9 @@ msgstr ""
msgid "Contributions per group member"
msgstr ""
+msgid "Contributor"
+msgstr ""
+
msgid "Contributors"
msgstr ""
@@ -7021,6 +7283,9 @@ msgstr ""
msgid "Could not change HEAD: branch '%{branch}' does not exist"
msgstr ""
+msgid "Could not commit. An unexpected error occurred."
+msgstr ""
+
msgid "Could not connect to FogBugz, check your URL"
msgstr ""
@@ -7060,6 +7325,9 @@ msgstr ""
msgid "Could not find iteration"
msgstr ""
+msgid "Could not load instance counts. Please refresh the page to try again."
+msgstr ""
+
msgid "Could not remove the trigger."
msgstr ""
@@ -7084,10 +7352,10 @@ msgstr ""
msgid "Could not save prometheus manual configuration"
msgstr ""
-msgid "Could not udpdate wiki page"
+msgid "Could not update the LDAP settings"
msgstr ""
-msgid "Could not update the LDAP settings"
+msgid "Could not update wiki page"
msgstr ""
msgid "Could not upload your designs as one or more files uploaded are not supported."
@@ -7745,6 +8013,9 @@ msgstr ""
msgid "DastProfiles|Are you sure you want to delete this profile?"
msgstr ""
+msgid "DastProfiles|Could not create site validation token. Please refresh the page, or try again later."
+msgstr ""
+
msgid "DastProfiles|Could not create the scanner profile. Please try again."
msgstr ""
@@ -7769,6 +8040,12 @@ msgstr ""
msgid "DastProfiles|Could not fetch site profiles. Please refresh the page, or try again later."
msgstr ""
+msgid "DastProfiles|Could not retrieve site validation status. Please refresh the page, or try again later."
+msgstr ""
+
+msgid "DastProfiles|Could not update the scanner profile. Please try again."
+msgstr ""
+
msgid "DastProfiles|Could not update the site profile. Please try again."
msgstr ""
@@ -7784,7 +8061,7 @@ msgstr ""
msgid "DastProfiles|Download validation text file"
msgstr ""
-msgid "DastProfiles|Edit feature will come soon. Please create a new profile if changes needed"
+msgid "DastProfiles|Edit scanner profile"
msgstr ""
msgid "DastProfiles|Edit site profile"
@@ -7817,6 +8094,9 @@ msgstr ""
msgid "DastProfiles|No profiles created yet"
msgstr ""
+msgid "DastProfiles|Passive"
+msgstr ""
+
msgid "DastProfiles|Please enter a valid URL format, ex: http://www.example.com/home"
msgstr ""
@@ -7832,6 +8112,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan mode"
+msgstr ""
+
msgid "DastProfiles|Scanner Profile"
msgstr ""
@@ -7871,10 +8154,10 @@ msgstr ""
msgid "DastProfiles|Text file validation"
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
+msgid "DastProfiles|The maximum number of minutes allowed for the spider to traverse the site."
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the spider to traverse the site."
+msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
msgstr ""
msgid "DastProfiles|Validate"
@@ -7907,6 +8190,9 @@ msgstr ""
msgid "Date picker"
msgstr ""
+msgid "Date range"
+msgstr ""
+
msgid "Date range cannot exceed %{maxDateRange} days."
msgstr ""
@@ -7931,6 +8217,9 @@ msgstr ""
msgid "Days to merge"
msgstr ""
+msgid "Dear Administrator,"
+msgstr ""
+
msgid "Debug"
msgstr ""
@@ -8042,12 +8331,18 @@ msgstr ""
msgid "Delete"
msgstr ""
+msgid "Delete %{name}"
+msgstr ""
+
msgid "Delete Comment"
msgstr ""
msgid "Delete Snippet"
msgstr ""
+msgid "Delete Value Stream"
+msgstr ""
+
msgid "Delete account"
msgstr ""
@@ -8069,9 +8364,6 @@ msgstr ""
msgid "Delete label: %{label_name} ?"
msgstr ""
-msgid "Delete license"
-msgstr ""
-
msgid "Delete list"
msgstr ""
@@ -8147,15 +8439,6 @@ msgstr ""
msgid "Deleting a project places it into a read-only state until %{date}, at which point the project will be permanently deleted. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "Deleting the license failed."
-msgstr ""
-
-msgid "Deleting the license failed. The license was not found."
-msgstr ""
-
-msgid "Deleting the license failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "Deleting the project will delete its repository and all related resources including issues, merge requests etc."
msgstr ""
@@ -8651,7 +8934,10 @@ msgstr ""
msgid "DesignManagement|The maximum number of designs allowed to be uploaded is %{upload_limit}. Please try again."
msgstr ""
-msgid "DesignManagement|To upload designs, you'll need to enable LFS. %{requirements_link_start}More information%{requirements_link_end}"
+msgid "DesignManagement|There was an error moving your designs. Please upload your designs below."
+msgstr ""
+
+msgid "DesignManagement|To upload designs, you'll need to enable LFS and have admin enable hashed storage. %{requirements_link_start}More information%{requirements_link_end}"
msgstr ""
msgid "DesignManagement|Unresolve thread"
@@ -8663,6 +8949,9 @@ msgstr ""
msgid "DesignManagement|Upload skipped."
msgstr ""
+msgid "DesignManagement|Your designs are being copied and are on their way… Please refresh to update."
+msgstr ""
+
msgid "DesignManagement|and %{moreCount} more."
msgstr ""
@@ -8720,6 +9009,9 @@ msgstr ""
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
+msgid "Direct member"
+msgstr ""
+
msgid "Direction"
msgstr ""
@@ -8768,9 +9060,6 @@ msgstr ""
msgid "Discard draft"
msgstr ""
-msgid "Discard review"
-msgstr ""
-
msgid "DiscordService|Discord Notifications"
msgstr ""
@@ -8839,10 +9128,10 @@ msgstr ""
msgid "Dismiss Merge Request promotion"
msgstr ""
-msgid "Dismiss Selected"
+msgid "Dismiss Value Stream Analytics introduction box"
msgstr ""
-msgid "Dismiss Value Stream Analytics introduction box"
+msgid "Dismiss selected"
msgstr ""
msgid "Dismiss trial promotion"
@@ -8893,9 +9182,6 @@ msgstr ""
msgid "Documents reindexed: %{processed_documents} (%{percentage}%%)"
msgstr ""
-msgid "Doing"
-msgstr ""
-
msgid "Domain"
msgstr ""
@@ -9091,9 +9377,6 @@ msgstr ""
msgid "Edit environment"
msgstr ""
-msgid "Edit file"
-msgstr ""
-
msgid "Edit files in the editor and commit changes here"
msgstr ""
@@ -9106,6 +9389,12 @@ msgstr ""
msgid "Edit identity for %{user_name}"
msgstr ""
+msgid "Edit in Web IDE"
+msgstr ""
+
+msgid "Edit in single-file editor"
+msgstr ""
+
msgid "Edit issues"
msgstr ""
@@ -9133,10 +9422,10 @@ msgstr ""
msgid "Editing"
msgstr ""
-msgid "Elasticsearch"
+msgid "Elasticsearch AWS IAM credentials"
msgstr ""
-msgid "Elasticsearch AWS IAM credentials"
+msgid "Elasticsearch HTTP client timeout value in seconds."
msgstr ""
msgid "Elasticsearch indexing restrictions"
@@ -9145,9 +9434,6 @@ msgstr ""
msgid "Elasticsearch indexing started"
msgstr ""
-msgid "Elasticsearch integration. Elasticsearch AWS IAM."
-msgstr ""
-
msgid "Elasticsearch reindexing is already in progress"
msgstr ""
@@ -9175,9 +9461,6 @@ msgstr ""
msgid "Email Notification"
msgstr ""
-msgid "Email address"
-msgstr ""
-
msgid "Email could not be sent"
msgstr ""
@@ -9241,6 +9524,9 @@ msgstr ""
msgid "Emails sent from Service Desk will have this name"
msgstr ""
+msgid "Emails sent to %{email} will still be supported"
+msgstr ""
+
msgid "Emails separated by comma"
msgstr ""
@@ -9274,9 +9560,18 @@ msgstr ""
msgid "Enable"
msgstr ""
+msgid "Enable %{link_start}Gitpod%{link_end} integration to launch a development environment in your browser directly from GitLab."
+msgstr ""
+
msgid "Enable Auto DevOps"
msgstr ""
+msgid "Enable Gitpod"
+msgstr ""
+
+msgid "Enable Gitpod?"
+msgstr ""
+
msgid "Enable HTML emails"
msgstr ""
@@ -9406,9 +9701,6 @@ msgstr ""
msgid "Encountered an error while rendering: %{err}"
msgstr ""
-msgid "End date"
-msgstr ""
-
msgid "Ends at (UTC)"
msgstr ""
@@ -9568,7 +9860,7 @@ msgstr ""
msgid "EnvironmentsDashboard|The environments dashboard provides a summary of each project's environments' status, including pipeline and alert statuses."
msgstr ""
-msgid "EnvironmentsDashboard|This dashboard displays a maximum of 7 projects and 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
+msgid "EnvironmentsDashboard|This dashboard displays 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
msgstr ""
msgid "Environments|An error occurred while canceling the auto stop, please try again"
@@ -9889,6 +10181,9 @@ msgstr ""
msgid "Error deleting project. Check logs for error details."
msgstr ""
+msgid "Error fetching burnup chart data"
+msgstr ""
+
msgid "Error fetching diverging counts for branches. Please try again."
msgstr ""
@@ -9967,6 +10262,9 @@ msgstr ""
msgid "Error occurred when saving assignees"
msgstr ""
+msgid "Error occurred when saving reviewers"
+msgstr ""
+
msgid "Error occurred when toggling the notification subscription"
msgstr ""
@@ -10219,10 +10517,13 @@ msgstr ""
msgid "Expand all"
msgstr ""
-msgid "Expand approvers"
+msgid "Expand all files"
msgstr ""
-msgid "Expand dropdown"
+msgid "Expand all threads"
+msgstr ""
+
+msgid "Expand approvers"
msgstr ""
msgid "Expand milestones"
@@ -10393,6 +10694,9 @@ msgstr ""
msgid "Failed to create Merge Request. Please try again."
msgstr ""
+msgid "Failed to create To-Do for the design."
+msgstr ""
+
msgid "Failed to create a branch for this issue. Please try again."
msgstr ""
@@ -10432,6 +10736,12 @@ msgstr ""
msgid "Failed to load authors. Please try again."
msgstr ""
+msgid "Failed to load branches. Please try again."
+msgstr ""
+
+msgid "Failed to load deploy keys."
+msgstr ""
+
msgid "Failed to load emoji list."
msgstr ""
@@ -10447,6 +10757,9 @@ msgstr ""
msgid "Failed to load groups & users."
msgstr ""
+msgid "Failed to load groups, users and deploy keys."
+msgstr ""
+
msgid "Failed to load labels. Please try again."
msgstr ""
@@ -10456,6 +10769,12 @@ msgstr ""
msgid "Failed to load related branches"
msgstr ""
+msgid "Failed to load sidebar confidential toggle"
+msgstr ""
+
+msgid "Failed to load sidebar lock status"
+msgstr ""
+
msgid "Failed to load stacktrace."
msgstr ""
@@ -10483,6 +10802,9 @@ msgstr ""
msgid "Failed to publish issue on status page."
msgstr ""
+msgid "Failed to remove To-Do for the design."
+msgstr ""
+
msgid "Failed to remove a Zoom meeting"
msgstr ""
@@ -10525,6 +10847,9 @@ msgstr ""
msgid "Failed to signing using smartcard authentication"
msgstr ""
+msgid "Failed to toggle To-Do for the design."
+msgstr ""
+
msgid "Failed to update branch!"
msgstr ""
@@ -10638,7 +10963,7 @@ msgstr ""
msgid "FeatureFlags|Edit User List"
msgstr ""
-msgid "FeatureFlags|Enable features for specific users and specific environments by defining feature flag strategies."
+msgid "FeatureFlags|Enable features for specific users and environments by configuring feature flag strategies."
msgstr ""
msgid "FeatureFlags|Environment Spec"
@@ -10698,7 +11023,7 @@ msgstr ""
msgid "FeatureFlags|Include additional user IDs"
msgstr ""
-msgid "FeatureFlags|Install a %{docs_link_anchored_start}compatible client library%{docs_link_anchored_end} and specify the API URL, application name, and instance ID during the configuration setup. %{docs_link_start}More Information%{docs_link_end}"
+msgid "FeatureFlags|Install a %{docsLinkAnchoredStart}compatible client library%{docsLinkAnchoredEnd} and specify the API URL, application name, and instance ID during the configuration setup. %{docsLinkStart}More Information%{docsLinkEnd}"
msgstr ""
msgid "FeatureFlags|Instance ID"
@@ -10710,6 +11035,9 @@ msgstr ""
msgid "FeatureFlags|Loading feature flags"
msgstr ""
+msgid "FeatureFlags|Loading user lists"
+msgstr ""
+
msgid "FeatureFlags|More information"
msgstr ""
@@ -10728,7 +11056,7 @@ msgstr ""
msgid "FeatureFlags|New feature flag"
msgstr ""
-msgid "FeatureFlags|New list"
+msgid "FeatureFlags|New user list"
msgstr ""
msgid "FeatureFlags|Percent of users"
@@ -10767,6 +11095,9 @@ msgstr ""
msgid "FeatureFlags|There was an error fetching the feature flags."
msgstr ""
+msgid "FeatureFlags|There was an error fetching the user lists."
+msgstr ""
+
msgid "FeatureFlags|There was an error retrieving user lists"
msgstr ""
@@ -10782,6 +11113,9 @@ msgstr ""
msgid "FeatureFlags|User List"
msgstr ""
+msgid "FeatureFlags|User Lists"
+msgstr ""
+
msgid "FeatureFlag|List"
msgstr ""
@@ -10809,15 +11143,6 @@ msgstr ""
msgid "Fetching incoming email"
msgstr ""
-msgid "Fetching licenses failed."
-msgstr ""
-
-msgid "Fetching licenses failed. The request endpoint was not found."
-msgstr ""
-
-msgid "Fetching licenses failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "File"
msgstr ""
@@ -10920,12 +11245,21 @@ msgstr ""
msgid "Filter by status"
msgstr ""
+msgid "Filter by test cases that are currently archived."
+msgstr ""
+
+msgid "Filter by test cases that are currently opened."
+msgstr ""
+
msgid "Filter by two-factor authentication"
msgstr ""
msgid "Filter by user"
msgstr ""
+msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
+msgstr ""
+
msgid "Filter pipelines"
msgstr ""
@@ -10941,7 +11275,7 @@ msgstr ""
msgid "Filter results..."
msgstr ""
-msgid "Filter your projects by name"
+msgid "Filter your repositories by name"
msgstr ""
msgid "Filter..."
@@ -10950,7 +11284,7 @@ msgstr ""
msgid "Find File"
msgstr ""
-msgid "Find bugs in your code with coverage-guided fuzzing"
+msgid "Find bugs in your code with coverage-guided fuzzing."
msgstr ""
msgid "Find by path"
@@ -10977,9 +11311,6 @@ msgstr ""
msgid "Finish editing this message first!"
msgstr ""
-msgid "Finish review"
-msgstr ""
-
msgid "Finish setting up your dedicated account for %{group_name}."
msgstr ""
@@ -11049,6 +11380,9 @@ msgstr ""
msgid "Footer message"
msgstr ""
+msgid "For a faster browsing experience, some files are collapsed by default."
+msgstr ""
+
msgid "For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
@@ -11058,6 +11392,9 @@ msgstr ""
msgid "For more info, read the documentation."
msgstr ""
+msgid "For more information on how the number of active users is calculated, see the %{self_managed_subscriptions_doc_link} documentation."
+msgstr ""
+
msgid "For more information, go to the "
msgstr ""
@@ -11196,6 +11533,9 @@ msgstr ""
msgid "Generate new token"
msgstr ""
+msgid "Generic package file size in bytes"
+msgstr ""
+
msgid "Geo"
msgstr ""
@@ -11457,6 +11797,9 @@ msgstr ""
msgid "Geo|Please refer to Geo Troubleshooting."
msgstr ""
+msgid "Geo|Primary node"
+msgstr ""
+
msgid "Geo|Project"
msgstr ""
@@ -11499,6 +11842,9 @@ msgstr ""
msgid "Geo|Review replication status, and resynchronize and reverify items with the primary node."
msgstr ""
+msgid "Geo|Secondary node"
+msgstr ""
+
msgid "Geo|Status"
msgstr ""
@@ -11538,6 +11884,9 @@ msgstr ""
msgid "Geo|URL must be a valid url (ex: https://gitlab.com)"
msgstr ""
+msgid "Geo|Undefined"
+msgstr ""
+
msgid "Geo|Unknown state"
msgstr ""
@@ -11613,10 +11962,16 @@ msgstr ""
msgid "GitHub import"
msgstr ""
+msgid "GitLab"
+msgstr ""
+
msgid "GitLab / Unsubscribe"
msgstr ""
-msgid "GitLab Enterprise Edition %{plan}"
+msgid "GitLab API"
+msgstr ""
+
+msgid "GitLab Billing Team."
msgstr ""
msgid "GitLab Group Runners can execute code for all the projects in this group."
@@ -11628,12 +11983,18 @@ msgstr ""
msgid "GitLab Issue"
msgstr ""
+msgid "GitLab Pages"
+msgstr ""
+
msgid "GitLab Service Desk is a simple way to allow people to create issues in your GitLab instance without needing their own user account. It provides a unique email address for end users to create issues in a project, and replies can be sent either through the GitLab interface or by email. End users will only see the thread through email."
msgstr ""
msgid "GitLab Shared Runners execute code of different projects on the same Runner unless you configure GitLab Runner Autoscale with MaxBuilds 1 (which it is on GitLab.com)."
msgstr ""
+msgid "GitLab Shell"
+msgstr ""
+
msgid "GitLab Support Bot"
msgstr ""
@@ -11643,7 +12004,7 @@ msgstr ""
msgid "GitLab User"
msgstr ""
-msgid "GitLab allows you to continue using your license even if you exceed the number of seats you purchased. You will be required to pay for these seats when you renew your license."
+msgid "GitLab Workhorse"
msgstr ""
msgid "GitLab commit"
@@ -11811,6 +12172,21 @@ msgstr ""
msgid "Gitlab Pages"
msgstr ""
+msgid "Gitpod"
+msgstr ""
+
+msgid "Gitpod|Add the URL to your Gitpod instance configured to read your GitLab projects."
+msgstr ""
+
+msgid "Gitpod|Enable Gitpod integration"
+msgstr ""
+
+msgid "Gitpod|Gitpod URL"
+msgstr ""
+
+msgid "Gitpod|e.g. https://gitpod.example.com"
+msgstr ""
+
msgid "Given access %{time_ago}"
msgstr ""
@@ -12318,9 +12694,6 @@ msgstr ""
msgid "GroupSAML|Valid SAML Response"
msgstr ""
-msgid "GroupSAML|With group managed accounts enabled, all the users without a group managed account will be excluded from the group."
-msgstr ""
-
msgid "GroupSAML|With prohibit outer forks flag enabled group members will be able to fork project only inside your group."
msgstr ""
@@ -12534,10 +12907,10 @@ msgstr ""
msgid "GroupsNew|Create group"
msgstr ""
-msgid "GroupsNew|GitLab group export"
+msgid "GroupsNew|Import"
msgstr ""
-msgid "GroupsNew|Import"
+msgid "GroupsNew|Import a GitLab group export file"
msgstr ""
msgid "GroupsNew|Import group"
@@ -12680,6 +13053,9 @@ msgid_plural "Hide charts"
msgstr[0] ""
msgstr[1] ""
+msgid "Hide comments on this file"
+msgstr ""
+
msgid "Hide details"
msgstr ""
@@ -12724,6 +13100,15 @@ msgstr ""
msgid "Highest role:"
msgstr ""
+msgid "HighlightBar|Alert events:"
+msgstr ""
+
+msgid "HighlightBar|Alert start time:"
+msgstr ""
+
+msgid "HighlightBar|Original alert:"
+msgstr ""
+
msgid "History"
msgstr ""
@@ -12901,6 +13286,9 @@ msgstr ""
msgid "If enabled, access to projects will be validated on an external service using their classification label."
msgstr ""
+msgid "If the number of active users exceeds the user limit, you will be charged for the number of %{users_over_license_link} at your next license reconciliation."
+msgstr ""
+
msgid "If there is no previous license or if the previous license has expired, some GitLab functionality will be blocked until a new, valid license is uploaded."
msgstr ""
@@ -12940,9 +13328,6 @@ msgstr ""
msgid "If your HTTP repository is not publicly accessible, add your credentials."
msgstr ""
-msgid "Iglu registry URL (optional)"
-msgstr ""
-
msgid "Ignore"
msgstr ""
@@ -12979,6 +13364,16 @@ msgstr ""
msgid "Import"
msgstr ""
+msgid "Import %d compatible repository"
+msgid_plural "Import %d compatible repositories"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Import %d repository"
+msgid_plural "Import %d repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Import CSV"
msgstr ""
@@ -12988,15 +13383,9 @@ msgstr ""
msgid "Import all compatible projects"
msgstr ""
-msgid "Import all compatible repositories"
-msgstr ""
-
msgid "Import all projects"
msgstr ""
-msgid "Import all repositories"
-msgstr ""
-
msgid "Import an exported GitLab project"
msgstr ""
@@ -13084,6 +13473,9 @@ msgstr ""
msgid "ImportProjects|Error importing repository %{project_safe_import_url} into %{project_full_path} - %{message}"
msgstr ""
+msgid "ImportProjects|Import repositories"
+msgstr ""
+
msgid "ImportProjects|Importing the project failed"
msgstr ""
@@ -13096,7 +13488,7 @@ msgstr ""
msgid "ImportProjects|Requesting your %{provider} repositories failed"
msgstr ""
-msgid "ImportProjects|Select the projects you want to import"
+msgid "ImportProjects|Select the repositories you want to import"
msgstr ""
msgid "ImportProjects|The remote data could not be imported."
@@ -13132,9 +13524,6 @@ msgstr ""
msgid "In order to enable Service Desk for your instance, you must first set up incoming email."
msgstr ""
-msgid "In order to gather accurate feature usage data, it can take 1 to 2 weeks to see your index."
-msgstr ""
-
msgid "In order to personalize your experience with GitLab%{br_tag}we would like to know a bit more about you."
msgstr ""
@@ -13165,18 +13554,30 @@ msgstr ""
msgid "IncidentManagement|Create incident"
msgstr ""
+msgid "IncidentManagement|Critical - S1"
+msgstr ""
+
msgid "IncidentManagement|Date created"
msgstr ""
msgid "IncidentManagement|Display your incidents in a dedicated view"
msgstr ""
+msgid "IncidentManagement|High - S2"
+msgstr ""
+
msgid "IncidentManagement|Incident"
msgstr ""
msgid "IncidentManagement|Incidents"
msgstr ""
+msgid "IncidentManagement|Low - S4"
+msgstr ""
+
+msgid "IncidentManagement|Medium - S3"
+msgstr ""
+
msgid "IncidentManagement|No incidents to display."
msgstr ""
@@ -13189,6 +13590,9 @@ msgstr ""
msgid "IncidentManagement|Published to status page"
msgstr ""
+msgid "IncidentManagement|Severity"
+msgstr ""
+
msgid "IncidentManagement|There are no closed incidents"
msgstr ""
@@ -13198,6 +13602,9 @@ msgstr ""
msgid "IncidentManagement|Unassigned"
msgstr ""
+msgid "IncidentManagement|Unknown"
+msgstr ""
+
msgid "IncidentManagement|Unpublished"
msgstr ""
@@ -13219,6 +13626,15 @@ msgstr ""
msgid "Incidents"
msgstr ""
+msgid "Incident|Alert details"
+msgstr ""
+
+msgid "Incident|Summary"
+msgstr ""
+
+msgid "Incident|There was an issue loading alert data. Please try again."
+msgstr ""
+
msgid "Include a Terms of Service agreement and Privacy Policy that all users must accept."
msgstr ""
@@ -13279,6 +13695,9 @@ msgstr ""
msgid "Information about additional Pages templates and how to install them can be found in our %{pages_getting_started_guide}."
msgstr ""
+msgid "Inherited"
+msgstr ""
+
msgid "Inherited:"
msgstr ""
@@ -13359,7 +13778,22 @@ msgstr ""
msgid "Instance administrators group already exists"
msgstr ""
-msgid "Instance license"
+msgid "InstanceStatistics|Groups"
+msgstr ""
+
+msgid "InstanceStatistics|Issues"
+msgstr ""
+
+msgid "InstanceStatistics|Merge Requests"
+msgstr ""
+
+msgid "InstanceStatistics|Pipelines"
+msgstr ""
+
+msgid "InstanceStatistics|Projects"
+msgstr ""
+
+msgid "InstanceStatistics|Users"
msgstr ""
msgid "Integration"
@@ -13371,6 +13805,12 @@ msgstr ""
msgid "Integrations"
msgstr ""
+msgid "Integrations|%{integration} settings saved and active."
+msgstr ""
+
+msgid "Integrations|%{integration} settings saved, but not active."
+msgstr ""
+
msgid "Integrations|All details"
msgstr ""
@@ -13380,6 +13820,12 @@ msgstr ""
msgid "Integrations|Comment settings:"
msgstr ""
+msgid "Integrations|Connection failed. Please check your settings."
+msgstr ""
+
+msgid "Integrations|Connection successful."
+msgstr ""
+
msgid "Integrations|Default settings are inherited from the group level."
msgstr ""
@@ -13395,6 +13841,15 @@ msgstr ""
msgid "Integrations|Includes commit title and branch"
msgstr ""
+msgid "Integrations|Projects using custom settings will not be impacted unless the project owner chooses to use instance-level defaults."
+msgstr ""
+
+msgid "Integrations|Save settings?"
+msgstr ""
+
+msgid "Integrations|Saving will update the default settings for all projects that are not using custom settings."
+msgstr ""
+
msgid "Integrations|Standard"
msgstr ""
@@ -13527,6 +13982,9 @@ msgstr ""
msgid "Invitation"
msgstr ""
+msgid "Invitation declined"
+msgstr ""
+
msgid "Invite"
msgstr ""
@@ -13578,6 +14036,42 @@ 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|%{linkStart}Read more%{linkEnd} about role permissions"
+msgstr ""
+
+msgid "InviteMembersModal|Access expiration date (optional)"
+msgstr ""
+
+msgid "InviteMembersModal|Cancel"
+msgstr ""
+
+msgid "InviteMembersModal|Choose a role permission"
+msgstr ""
+
+msgid "InviteMembersModal|GitLab member or Email address"
+msgstr ""
+
+msgid "InviteMembersModal|Invite"
+msgstr ""
+
+msgid "InviteMembersModal|Invite team members"
+msgstr ""
+
+msgid "InviteMembersModal|Search for members to invite"
+msgstr ""
+
+msgid "InviteMembersModal|User not invited. Feature coming soon!"
+msgstr ""
+
+msgid "InviteMembersModal|Users were succesfully added"
+msgstr ""
+
+msgid "InviteMembersModal|You're inviting members to the %{group_name} group"
+msgstr ""
+
+msgid "InviteMembers|Invite team members"
+msgstr ""
+
msgid "Invited"
msgstr ""
@@ -13632,10 +14126,13 @@ msgstr ""
msgid "Issue cannot be found."
msgstr ""
+msgid "Issue created from vulnerability %{vulnerability_link}"
+msgstr ""
+
msgid "Issue events"
msgstr ""
-msgid "Issue first depoloyed to production"
+msgid "Issue first deployed to production"
msgstr ""
msgid "Issue label"
@@ -13713,6 +14210,9 @@ msgstr ""
msgid "IssueTracker|Custom issue tracker"
msgstr ""
+msgid "IssueTracker|EWM work items tracker"
+msgstr ""
+
msgid "IssueTracker|Redmine issue tracker"
msgstr ""
@@ -13779,6 +14279,9 @@ msgstr ""
msgid "It looks like you have some draft commits in this branch."
msgstr ""
+msgid "It may be several days before you see feature usage data."
+msgstr ""
+
msgid "It must have a header row and at least two columns: the first column is the issue title and the second column is the issue description. The separator is automatically detected."
msgstr ""
@@ -14061,13 +14564,13 @@ msgstr ""
msgid "Join Zoom meeting"
msgstr ""
-msgid "Jul"
+msgid "Joined %{time_ago}"
msgstr ""
-msgid "July"
+msgid "Jul"
msgstr ""
-msgid "Jump to first unresolved thread"
+msgid "July"
msgstr ""
msgid "Jump to next unresolved thread"
@@ -14103,6 +14606,9 @@ msgstr ""
msgid "Keyboard shortcuts"
msgstr ""
+msgid "KeyboardKey|Ctrl+"
+msgstr ""
+
msgid "Keys"
msgstr ""
@@ -14151,6 +14657,9 @@ msgstr ""
msgid "LDAP Synchronization"
msgstr ""
+msgid "LDAP group settings"
+msgstr ""
+
msgid "LDAP settings"
msgstr ""
@@ -14160,6 +14669,9 @@ msgstr ""
msgid "LDAP sync in progress. This could take a few minutes. Refresh the page to see the changes."
msgstr ""
+msgid "LDAP synchronizations"
+msgstr ""
+
msgid "LFS"
msgstr ""
@@ -14240,7 +14752,16 @@ msgid_plural "Last %d days"
msgstr[0] ""
msgstr[1] ""
-msgid "Last %{days} days"
+msgid "Last 2 weeks"
+msgstr ""
+
+msgid "Last 30 days"
+msgstr ""
+
+msgid "Last 60 days"
+msgstr ""
+
+msgid "Last 90 days"
msgstr ""
msgid "Last Accessed On"
@@ -14318,6 +14839,9 @@ msgstr ""
msgid "Last used on:"
msgstr ""
+msgid "Last week"
+msgstr ""
+
msgid "LastCommit|authored"
msgstr ""
@@ -14333,6 +14857,9 @@ msgstr ""
msgid "Latest pipeline for the most recent commit on this branch"
msgstr ""
+msgid "Launch a ready-to-code development environment for your project."
+msgstr ""
+
msgid "Lead"
msgstr ""
@@ -14713,6 +15240,9 @@ msgstr ""
msgid "List of all merge commits"
msgstr ""
+msgid "List options"
+msgstr ""
+
msgid "List settings"
msgstr ""
@@ -14725,9 +15255,6 @@ msgstr ""
msgid "List your Bitbucket Server repositories"
msgstr ""
-msgid "Lists"
-msgstr ""
-
msgid "Live preview"
msgstr ""
@@ -14974,6 +15501,12 @@ msgstr ""
msgid "Mark as done"
msgstr ""
+msgid "Mark as draft"
+msgstr ""
+
+msgid "Mark as ready"
+msgstr ""
+
msgid "Mark as resolved"
msgstr ""
@@ -14995,6 +15528,24 @@ msgstr ""
msgid "Markdown is supported"
msgstr ""
+msgid "MarkdownEditor|Add a link (%{modifierKey}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add a link (%{modifier_key}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifierKey}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifier_key}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifierKey}I)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifier_key}I)"
+msgstr ""
+
msgid "Marked For Deletion At - %{deletion_time}"
msgstr ""
@@ -15079,7 +15630,25 @@ msgstr ""
msgid "Max access level"
msgstr ""
-msgid "Max seats used"
+msgid "Max role"
+msgstr ""
+
+msgid "Max size 15 MB"
+msgstr ""
+
+msgid "Maximum Conan package file size in bytes"
+msgstr ""
+
+msgid "Maximum Maven package file size in bytes"
+msgstr ""
+
+msgid "Maximum NPM package file size in bytes"
+msgstr ""
+
+msgid "Maximum NuGet package file size in bytes"
+msgstr ""
+
+msgid "Maximum PyPI package file size in bytes"
msgstr ""
msgid "Maximum Users:"
@@ -15211,6 +15780,18 @@ msgstr ""
msgid "Members with access to %{strong_start}%{group_name}%{strong_end}"
msgstr ""
+msgid "Members|%{time} by %{user}"
+msgstr ""
+
+msgid "Members|Expired"
+msgstr ""
+
+msgid "Members|No expiration set"
+msgstr ""
+
+msgid "Members|in %{time}"
+msgstr ""
+
msgid "Memory Usage"
msgstr ""
@@ -15397,9 +15978,6 @@ msgstr ""
msgid "MergeRequests|Thread will be unresolved"
msgstr ""
-msgid "MergeRequests|Toggle comments for this file"
-msgstr ""
-
msgid "MergeRequests|View file @ %{commitId}"
msgstr ""
@@ -15460,6 +16038,9 @@ msgstr ""
msgid "Merging immediately isn't recommended as it may negatively impact the existing merge train. Read the %{docsLinkStart}documentation%{docsLinkEnd} for more information."
msgstr ""
+msgid "Message"
+msgstr ""
+
msgid "Messages"
msgstr ""
@@ -15845,18 +16426,12 @@ msgid_plural "Milestones"
msgstr[0] ""
msgstr[1] ""
-msgid "Milestone does not support burnup charts"
-msgstr ""
-
msgid "Milestone lists not available with your current license"
msgstr ""
msgid "Milestone lists show all issues from the selected milestone."
msgstr ""
-msgid "Milestone must have a start and due date"
-msgstr ""
-
msgid "MilestoneSidebar|Closed:"
msgstr ""
@@ -16223,6 +16798,9 @@ msgstr ""
msgid "Namespace"
msgstr ""
+msgid "Namespace ID:"
+msgstr ""
+
msgid "Namespace is empty"
msgstr ""
@@ -16307,6 +16885,9 @@ msgstr ""
msgid "NetworkPolicies|Allow all outbound traffic from %{selector} to %{ruleSelector} on %{ports}"
msgstr ""
+msgid "NetworkPolicies|Are you sure you want to delete this policy? This action cannot be undone."
+msgstr ""
+
msgid "NetworkPolicies|Choose whether to enforce this policy."
msgstr ""
@@ -16316,12 +16897,21 @@ msgstr ""
msgid "NetworkPolicies|Define this policy's location, conditions and actions."
msgstr ""
+msgid "NetworkPolicies|Delete policy"
+msgstr ""
+
+msgid "NetworkPolicies|Delete policy: %{policy}"
+msgstr ""
+
msgid "NetworkPolicies|Deny all traffic"
msgstr ""
msgid "NetworkPolicies|Description"
msgstr ""
+msgid "NetworkPolicies|Edit policy"
+msgstr ""
+
msgid "NetworkPolicies|Editor mode"
msgstr ""
@@ -16349,6 +16939,9 @@ msgstr ""
msgid "NetworkPolicies|Name"
msgstr ""
+msgid "NetworkPolicies|Namespace"
+msgstr ""
+
msgid "NetworkPolicies|Network Policy"
msgstr ""
@@ -16400,6 +16993,9 @@ msgstr ""
msgid "NetworkPolicies|Rules"
msgstr ""
+msgid "NetworkPolicies|Save changes"
+msgstr ""
+
msgid "NetworkPolicies|Something went wrong, failed to update policy"
msgstr ""
@@ -16412,6 +17008,9 @@ msgstr ""
msgid "NetworkPolicies|Traffic that does not match any rule will be blocked."
msgstr ""
+msgid "NetworkPolicies|Unable to parse policy"
+msgstr ""
+
msgid "NetworkPolicies|YAML editor"
msgstr ""
@@ -16525,6 +17124,9 @@ msgstr ""
msgid "New Snippet"
msgstr ""
+msgid "New Test Case"
+msgstr ""
+
msgid "New User"
msgstr ""
@@ -16624,6 +17226,9 @@ msgstr ""
msgid "New tag"
msgstr ""
+msgid "New test case"
+msgstr ""
+
msgid "New users set to external"
msgstr ""
@@ -16696,7 +17301,7 @@ msgstr ""
msgid "No changes"
msgstr ""
-msgid "No changes between %{ref_start}%{source_branch}%{ref_end} and %{ref_start}%{target_branch}%{ref_end}"
+msgid "No changes between %{sourceBranch} and %{targetBranch}"
msgstr ""
msgid "No child epics match applied filters"
@@ -16711,6 +17316,9 @@ msgstr ""
msgid "No containers available"
msgstr ""
+msgid "No content to show"
+msgstr ""
+
msgid "No contributions"
msgstr ""
@@ -16786,9 +17394,6 @@ msgstr ""
msgid "No license. All rights reserved"
msgstr ""
-msgid "No licenses found."
-msgstr ""
-
msgid "No matches found"
msgstr ""
@@ -16801,6 +17406,9 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No members found"
+msgstr ""
+
msgid "No merge requests found"
msgstr ""
@@ -16822,6 +17430,9 @@ msgstr ""
msgid "No parent group"
msgstr ""
+msgid "No plan"
+msgstr ""
+
msgid "No pods available"
msgstr ""
@@ -16918,6 +17529,12 @@ msgstr ""
msgid "Not Implemented"
msgstr ""
+msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+msgstr ""
+
+msgid "Not all browsers support WebAuthn. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even from an unsupported browser."
+msgstr ""
+
msgid "Not all data has been processed yet, the accuracy of the chart for the selected timeframe is limited."
msgstr ""
@@ -17014,6 +17631,9 @@ msgstr ""
msgid "Notification settings saved"
msgstr ""
+msgid "NotificationEvent|Change reviewer merge request"
+msgstr ""
+
msgid "NotificationEvent|Close issue"
msgstr ""
@@ -17176,10 +17796,7 @@ msgstr ""
msgid "On track"
msgstr ""
-msgid "OnDemandScans|Attached branch"
-msgstr ""
-
-msgid "OnDemandScans|Attached branch is where the scan job runs."
+msgid "OnDemandScans|Could not fetch scanner profiles. Please refresh the page, or try again later."
msgstr ""
msgid "OnDemandScans|Could not fetch site profiles. Please refresh the page, or try again later."
@@ -17188,6 +17805,9 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
+msgid "OnDemandScans|Create a new scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Create a new site profile"
msgstr ""
@@ -17200,6 +17820,9 @@ msgstr ""
msgid "OnDemandScans|New on-demand DAST scan"
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 ""
@@ -17209,16 +17832,10 @@ msgstr ""
msgid "OnDemandScans|On-demand scans run outside the DevOps cycle and find vulnerabilities in your projects. %{learnMoreLinkStart}Learn more%{learnMoreLinkEnd}"
msgstr ""
-msgid "OnDemandScans|Only a passive scan can be performed on demand."
-msgstr ""
-
-msgid "OnDemandScans|Passive"
-msgstr ""
-
msgid "OnDemandScans|Run scan"
msgstr ""
-msgid "OnDemandScans|Scan mode"
+msgid "OnDemandScans|Scanner profile"
msgstr ""
msgid "OnDemandScans|Scanner settings"
@@ -17230,9 +17847,15 @@ msgstr ""
msgid "OnDemandScans|Select one of the existing profiles"
msgstr ""
+msgid "OnDemandScans|Site profile"
+msgstr ""
+
msgid "OnDemandScans|Site profiles"
msgstr ""
+msgid "OnDemandScans|Use existing scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Use existing site profile"
msgstr ""
@@ -17331,9 +17954,6 @@ msgstr ""
msgid "Open Selection"
msgstr ""
-msgid "Open Web IDE"
-msgstr ""
-
msgid "Open comment type dropdown"
msgstr ""
@@ -17439,6 +18059,9 @@ msgstr ""
msgid "Origin"
msgstr ""
+msgid "Orphaned member"
+msgstr ""
+
msgid "Other Labels"
msgstr ""
@@ -17454,6 +18077,9 @@ msgstr ""
msgid "Other visibility settings have been disabled by the administrator."
msgstr ""
+msgid "Our documentation includes an example DevOps Score report."
+msgstr ""
+
msgid "Out-of-compliance with this project's policies and should be removed"
msgstr ""
@@ -17478,6 +18104,9 @@ msgstr ""
msgid "Overwrite diverged branches"
msgstr ""
+msgid "Owned by %{image_tag}"
+msgstr ""
+
msgid "Owned by anyone"
msgstr ""
@@ -17499,6 +18128,9 @@ msgstr ""
msgid "Package deleted successfully"
msgstr ""
+msgid "Package file size limits"
+msgstr ""
+
msgid "Package recipe already exists"
msgstr ""
@@ -17514,9 +18146,6 @@ msgstr ""
msgid "Package type must be PyPi"
msgstr ""
-msgid "Package was removed"
-msgstr ""
-
msgid "PackageRegistry|%{name} version %{version} was created %{datetime}"
msgstr ""
@@ -17658,12 +18287,18 @@ msgstr ""
msgid "PackageRegistry|NuGet Command"
msgstr ""
+msgid "PackageRegistry|Package Registry"
+msgstr ""
+
msgid "PackageRegistry|Pip Command"
msgstr ""
msgid "PackageRegistry|Pipeline %{link} triggered %{datetime} by %{author}"
msgstr ""
+msgid "PackageRegistry|Publish and share packages for a variety of common package managers. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "PackageRegistry|Published to the %{project} Package Registry %{datetime}"
msgstr ""
@@ -17763,6 +18398,9 @@ msgstr ""
msgid "Page not found"
msgstr ""
+msgid "Page settings"
+msgstr ""
+
msgid "Page was successfully deleted"
msgstr ""
@@ -17904,7 +18542,7 @@ msgstr ""
msgid "Paste issue link"
msgstr ""
-msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Don't use your private SSH key."
+msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Do not paste your private SSH key, as that can compromise your identity."
msgstr ""
msgid "Patch to apply"
@@ -17931,6 +18569,9 @@ msgstr ""
msgid "Pending"
msgstr ""
+msgid "Pending comments"
+msgstr ""
+
msgid "People without permission will never get a notification and won't be able to comment."
msgstr ""
@@ -18129,6 +18770,9 @@ msgstr ""
msgid "Pipelines|Build with confidence"
msgstr ""
+msgid "Pipelines|By revoking a trigger you will break any processes making use of it. Are you sure?"
+msgstr ""
+
msgid "Pipelines|CI Lint"
msgstr ""
@@ -18141,6 +18785,15 @@ msgstr ""
msgid "Pipelines|Continuous Integration can help catch bugs by running your tests automatically, while Continuous Deployment can help you deliver code to your product environment."
msgstr ""
+msgid "Pipelines|Copy trigger token"
+msgstr ""
+
+msgid "Pipelines|Description"
+msgstr ""
+
+msgid "Pipelines|Edit"
+msgstr ""
+
msgid "Pipelines|Get started with Pipelines"
msgstr ""
@@ -18156,15 +18809,27 @@ msgstr ""
msgid "Pipelines|It is recommended the code is reviewed thoroughly before running this pipeline with the parent project's CI resource."
msgstr ""
+msgid "Pipelines|Last Used"
+msgstr ""
+
msgid "Pipelines|Loading Pipelines"
msgstr ""
msgid "Pipelines|More Information"
msgstr ""
+msgid "Pipelines|No triggers have been created yet. Add one using the form above."
+msgstr ""
+
+msgid "Pipelines|Owner"
+msgstr ""
+
msgid "Pipelines|Project cache successfully reset."
msgstr ""
+msgid "Pipelines|Revoke"
+msgstr ""
+
msgid "Pipelines|Run Pipeline"
msgstr ""
@@ -18189,6 +18854,15 @@ msgstr ""
msgid "Pipelines|This project is not currently set up to run pipelines."
msgstr ""
+msgid "Pipelines|Token"
+msgstr ""
+
+msgid "Pipelines|Trigger user has insufficient permissions to project"
+msgstr ""
+
+msgid "Pipelines|invalid"
+msgstr ""
+
msgid "Pipelines|parent"
msgstr ""
@@ -18447,10 +19121,10 @@ msgstr ""
msgid "Please provide attributes to update"
msgstr ""
-msgid "Please refer to %{docs_url}"
+msgid "Please reach out if you have any questions and we'll be happy to assist."
msgstr ""
-msgid "Please retype the email address."
+msgid "Please refer to %{docs_url}"
msgstr ""
msgid "Please select"
@@ -18480,6 +19154,9 @@ msgstr ""
msgid "Please set a new password before proceeding."
msgstr ""
+msgid "Please share your feedback about %{featureName} %{linkStart}in this issue%{linkEnd} to help us improve the experience."
+msgstr ""
+
msgid "Please solve the reCAPTCHA"
msgstr ""
@@ -18783,6 +19460,9 @@ msgstr ""
msgid "Profiles| You are going to change the username %{currentUsernameBold} to %{newUsernameBold}. Profile and projects will be redirected to the %{newUsername} namespace but this redirect will expire once the %{currentUsername} namespace is registered by another user or group. Please update your Git repository remotes as soon as possible."
msgstr ""
+msgid "Profiles|%{provider} Active"
+msgstr ""
+
msgid "Profiles|@username"
msgstr ""
@@ -18834,7 +19514,7 @@ msgstr ""
msgid "Profiles|Commit email"
msgstr ""
-msgid "Profiles|Connect"
+msgid "Profiles|Connect %{provider}"
msgstr ""
msgid "Profiles|Connected Accounts"
@@ -18858,6 +19538,9 @@ msgstr ""
msgid "Profiles|Disconnect"
msgstr ""
+msgid "Profiles|Disconnect %{provider}"
+msgstr ""
+
msgid "Profiles|Do not show on profile"
msgstr ""
@@ -18882,7 +19565,7 @@ msgstr ""
msgid "Profiles|Full name"
msgstr ""
-msgid "Profiles|Give your individual key a title. This will be publically visible."
+msgid "Profiles|Give your individual key a title."
msgstr ""
msgid "Profiles|Include private contributions on my profile"
@@ -18972,7 +19655,7 @@ msgstr ""
msgid "Profiles|The maximum file size allowed is 200KB."
msgstr ""
-msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it?"
+msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it? It will be publicly visible."
msgstr ""
msgid "Profiles|This email will be displayed on your public profile"
@@ -19047,6 +19730,9 @@ msgstr ""
msgid "Profiles|You don't have access to delete this user."
msgstr ""
+msgid "Profiles|You must transfer ownership or delete groups you are an owner of before you can delete your account"
+msgstr ""
+
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
@@ -19635,6 +20321,9 @@ msgstr ""
msgid "ProjectTemplates|GitLab Cluster Management"
msgstr ""
+msgid "ProjectTemplates|Gitpod/Spring Petclinic"
+msgstr ""
+
msgid "ProjectTemplates|Go Micro"
msgstr ""
@@ -20244,6 +20933,9 @@ msgstr ""
msgid "Publish to status page"
msgstr ""
+msgid "Published"
+msgstr ""
+
msgid "Published on status page"
msgstr ""
@@ -20361,9 +21053,15 @@ msgstr ""
msgid "Quick range"
msgstr ""
+msgid "Quickly and easily edit multiple files in your project."
+msgstr ""
+
msgid "README"
msgstr ""
+msgid "Rails"
+msgstr ""
+
msgid "Rake Tasks Help"
msgstr ""
@@ -20483,10 +21181,13 @@ msgstr ""
msgid "Register Two-Factor Authenticator"
msgstr ""
-msgid "Register U2F device"
+msgid "Register Universal Two-Factor (U2F) Device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register WebAuthn Device"
+msgstr ""
+
+msgid "Register device"
msgstr ""
msgid "Register for GitLab"
@@ -20498,9 +21199,6 @@ msgstr ""
msgid "Register with two-factor app"
msgstr ""
-msgid "Registration"
-msgstr ""
-
msgid "Registration|Checkout"
msgstr ""
@@ -20617,9 +21315,6 @@ msgstr ""
msgid "Release|Something went wrong while saving the release details"
msgstr ""
-msgid "Remediated: needs review"
-msgstr ""
-
msgid "Remediations"
msgstr ""
@@ -20725,6 +21420,9 @@ msgstr ""
msgid "Remove priority"
msgstr ""
+msgid "Remove report"
+msgstr ""
+
msgid "Remove secondary node"
msgstr ""
@@ -20737,6 +21435,12 @@ msgstr ""
msgid "Remove time estimate"
msgstr ""
+msgid "Remove user & report"
+msgstr ""
+
+msgid "Remove user from group"
+msgstr ""
+
msgid "Removed"
msgstr ""
@@ -20818,9 +21522,6 @@ msgstr ""
msgid "Removes time estimate."
msgstr ""
-msgid "Removing license…"
-msgstr ""
-
msgid "Removing this group also removes all child projects, including archived projects, and their resources."
msgstr ""
@@ -20905,6 +21606,9 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
+msgid "Reported by %{reporter}"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -20991,6 +21695,27 @@ msgstr ""
msgid "Repositories"
msgstr ""
+msgid "Repositories Analytics"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download Historic Test Coverage Data"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download historic test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Historic Test Coverage Data is available in raw format (.csv) for further analysis."
+msgstr ""
+
+msgid "RepositoriesAnalytics|Test Code Coverage"
+msgstr ""
+
+msgid "RepositoriesAnalytics|There was an error fetching the projects."
+msgstr ""
+
msgid "Repository"
msgstr ""
@@ -21069,9 +21794,15 @@ msgstr ""
msgid "Request parameter %{param} is missing."
msgstr ""
+msgid "Request review from"
+msgstr ""
+
msgid "Request to link SAML account must be authorized"
msgstr ""
+msgid "Requested"
+msgstr ""
+
msgid "Requested %{time_ago}"
msgstr ""
@@ -21090,6 +21821,9 @@ msgstr ""
msgid "Requests to these domain(s)/address(es) on the local network will be allowed when local requests from hooks and services are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 or 127.0.0.0/28 are supported. Domain wildcards are not supported currently. Use comma, semicolon, or newline to separate multiple entries. The allowlist can hold a maximum of 1000 entries. Domains should use IDNA encoding. Ex: example.com, 192.168.1.1, 127.0.0.0/28, xn--itlab-j1a.com."
msgstr ""
+msgid "Require admin approval for new sign-ups"
+msgstr ""
+
msgid "Require all users in this group to setup Two-factor authentication"
msgstr ""
@@ -21217,9 +21951,6 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
-msgid "Resolved by %{resolvedByName}"
-msgstr ""
-
msgid "Resolves IP addresses once and uses them to submit requests"
msgstr ""
@@ -21339,6 +22070,14 @@ msgstr ""
msgid "ReviewApp|Enable Review App"
msgstr ""
+msgid "Reviewer"
+msgid_plural "%d Reviewers"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Reviewer(s)"
+msgstr ""
+
msgid "Reviewing"
msgstr ""
@@ -21378,6 +22117,9 @@ msgstr ""
msgid "Rook"
msgstr ""
+msgid "Ruby"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -21456,6 +22198,63 @@ msgstr ""
msgid "Runners page."
msgstr ""
+msgid "Runners|Active"
+msgstr ""
+
+msgid "Runners|Architecture"
+msgstr ""
+
+msgid "Runners|Can run untagged jobs"
+msgstr ""
+
+msgid "Runners|Description"
+msgstr ""
+
+msgid "Runners|Group"
+msgstr ""
+
+msgid "Runners|IP Address"
+msgstr ""
+
+msgid "Runners|Last contact"
+msgstr ""
+
+msgid "Runners|Locked to this project"
+msgstr ""
+
+msgid "Runners|Maximum job timeout"
+msgstr ""
+
+msgid "Runners|Name"
+msgstr ""
+
+msgid "Runners|Platform"
+msgstr ""
+
+msgid "Runners|Property Name"
+msgstr ""
+
+msgid "Runners|Protected"
+msgstr ""
+
+msgid "Runners|Revision"
+msgstr ""
+
+msgid "Runners|Shared"
+msgstr ""
+
+msgid "Runners|Specific"
+msgstr ""
+
+msgid "Runners|Tags"
+msgstr ""
+
+msgid "Runners|Value"
+msgstr ""
+
+msgid "Runners|Version"
+msgstr ""
+
msgid "Runners|You have used %{quotaUsed} out of %{quotaLimit} of your shared Runners pipeline minutes."
msgstr ""
@@ -21468,6 +22267,9 @@ msgstr ""
msgid "Runs a number of housekeeping tasks within the current repository, such as compressing file revisions and removing unreachable objects."
msgstr ""
+msgid "SAML"
+msgstr ""
+
msgid "SAML SSO"
msgstr ""
@@ -21519,6 +22321,9 @@ msgstr ""
msgid "Save"
msgstr ""
+msgid "Save %{name} size limits"
+msgstr ""
+
msgid "Save Changes"
msgstr ""
@@ -21549,9 +22354,6 @@ msgstr ""
msgid "Save space and find tags in the Container Registry more easily. Enable the cleanup policy to remove stale tags and keep only the ones you need."
msgstr ""
-msgid "Save template"
-msgstr ""
-
msgid "Save variables"
msgstr ""
@@ -21594,9 +22396,6 @@ msgstr ""
msgid "Scope"
msgstr ""
-msgid "Scope not supported with disabled 'users_search' feature!"
-msgstr ""
-
msgid "Scoped issue boards"
msgstr ""
@@ -21723,9 +22522,6 @@ msgstr ""
msgid "Search requirements"
msgstr ""
-msgid "Search results…"
-msgstr ""
-
msgid "Search users"
msgstr ""
@@ -21798,6 +22594,11 @@ msgid_plural "SearchResults|commits"
msgstr[0] ""
msgstr[1] ""
+msgid "SearchResults|epic"
+msgid_plural "SearchResults|epics"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "SearchResults|issue"
msgid_plural "SearchResults|issues"
msgstr[0] ""
@@ -21842,10 +22643,10 @@ msgstr ""
msgid "Seat Link is disabled, and cannot be configured through this form."
msgstr ""
-msgid "Seats currently in use"
+msgid "Seats usage data as of %{last_enqueue_time}"
msgstr ""
-msgid "Seats in license"
+msgid "Seats usage data is updated every day at 12:00pm UTC"
msgstr ""
msgid "Secondary"
@@ -21899,6 +22700,9 @@ msgstr ""
msgid "SecurityConfiguration|Available for on-demand DAST"
msgstr ""
+msgid "SecurityConfiguration|By default, all analyzers are applied in order to cover all languages across your project, and only run if the language is detected in the Merge Request."
+msgstr ""
+
msgid "SecurityConfiguration|Configure"
msgstr ""
@@ -21929,16 +22733,19 @@ msgstr ""
msgid "SecurityConfiguration|Manage"
msgstr ""
+msgid "SecurityConfiguration|More information"
+msgstr ""
+
msgid "SecurityConfiguration|Not enabled"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|Security Control"
+msgid "SecurityConfiguration|SAST Configuration"
msgstr ""
-msgid "SecurityConfiguration|See documentation"
+msgid "SecurityConfiguration|Security Control"
msgstr ""
msgid "SecurityConfiguration|Status"
@@ -21950,6 +22757,9 @@ msgstr ""
msgid "SecurityConfiguration|Using custom settings. You won't receive automatic updates on this variable. %{anchorStart}Restore to default%{anchorEnd}"
msgstr ""
+msgid "SecurityConfiguration|View history"
+msgstr ""
+
msgid "SecurityConfiguration|You can quickly enable all security scanning tools by enabling %{linkStart}Auto DevOps%{linkEnd}."
msgstr ""
@@ -22028,9 +22838,6 @@ msgstr ""
msgid "SecurityReports|Learn more about setting up your dashboard"
msgstr ""
-msgid "SecurityReports|Load more vulnerabilities"
-msgstr ""
-
msgid "SecurityReports|Monitor vulnerabilities in your code"
msgstr ""
@@ -22310,7 +23117,7 @@ msgstr ""
msgid "Select status"
msgstr ""
-msgid "Select strategy activation method"
+msgid "Select strategy activation method."
msgstr ""
msgid "Select subscription"
@@ -22325,7 +23132,7 @@ msgstr ""
msgid "Select the custom project template source group."
msgstr ""
-msgid "Select timeframe"
+msgid "Select the environment scope for this feature flag."
msgstr ""
msgid "Select timezone"
@@ -22574,6 +23381,9 @@ msgstr ""
msgid "Set iteration"
msgstr ""
+msgid "Set limit to 0 to allow any file size."
+msgstr ""
+
msgid "Set max session time for web terminal."
msgstr ""
@@ -22652,10 +23462,13 @@ msgstr ""
msgid "Set up a %{type} Runner manually"
msgstr ""
+msgid "Set up a hardware device as a second factor to sign in."
+msgstr ""
+
msgid "Set up assertions/attributes/claims (email, first_name, last_name) and NameID according to %{docsLinkStart}the documentation %{icon}%{docsLinkEnd}"
msgstr ""
-msgid "Set up new U2F device"
+msgid "Set up new device"
msgstr ""
msgid "Set up new password"
@@ -22724,6 +23537,9 @@ msgstr ""
msgid "Sets weight to %{weight}."
msgstr ""
+msgid "Setting this to 0 means using the system default timeout value."
+msgstr ""
+
msgid "Settings"
msgstr ""
@@ -22739,6 +23555,15 @@ msgstr ""
msgid "Severity"
msgstr ""
+msgid "SeverityWidget|Severity"
+msgstr ""
+
+msgid "SeverityWidget|Severity: %{severity}"
+msgstr ""
+
+msgid "SeverityWidget|There was an error while updating severity."
+msgstr ""
+
msgid "Shards (%{shards})"
msgstr ""
@@ -22784,6 +23609,9 @@ msgstr ""
msgid "Show all requirements."
msgstr ""
+msgid "Show all test cases."
+msgstr ""
+
msgid "Show archived projects"
msgstr ""
@@ -22796,6 +23624,9 @@ msgstr ""
msgid "Show comments"
msgstr ""
+msgid "Show comments on this file"
+msgstr ""
+
msgid "Show comments only"
msgstr ""
@@ -22841,6 +23672,12 @@ msgstr ""
msgid "Show parent subgroups"
msgstr ""
+msgid "Show the Closed list"
+msgstr ""
+
+msgid "Show the Open list"
+msgstr ""
+
msgid "Show whitespace changes"
msgstr ""
@@ -22884,9 +23721,6 @@ msgstr ""
msgid "Sidebar|Assign health status"
msgstr ""
-msgid "Sidebar|Change weight"
-msgstr ""
-
msgid "Sidebar|Health status"
msgstr ""
@@ -23070,6 +23904,9 @@ msgstr ""
msgid "Snippets|Add another file %{num}/%{total}"
msgstr ""
+msgid "Snippets|Authored %{time_ago} by %{author}"
+msgstr ""
+
msgid "Snippets|Delete file"
msgstr ""
@@ -23097,6 +23934,9 @@ msgstr ""
msgid "Solution"
msgstr ""
+msgid "Some changes are not shown"
+msgstr ""
+
msgid "Some child epics may be hidden due to applied filters"
msgstr ""
@@ -23463,6 +24303,12 @@ msgstr ""
msgid "Source (branch or tag)"
msgstr ""
+msgid "Source Branch"
+msgstr ""
+
+msgid "Source branch: %{source_branch_open}%{source_branch}%{source_branch_close}"
+msgstr ""
+
msgid "Source code"
msgstr ""
@@ -23628,9 +24474,6 @@ msgstr ""
msgid "Start and due date"
msgstr ""
-msgid "Start by choosing a group to see how your team is spending time. You can then drill down to the project level."
-msgstr ""
-
msgid "Start by choosing a group to start exploring the merge requests in that group. You can then proceed to filter by projects, labels, milestones and authors."
msgstr ""
@@ -23712,18 +24555,27 @@ msgstr ""
msgid "StaticSiteEditor|3. Assign a person to review and accept the merge request."
msgstr ""
+msgid "StaticSiteEditor|A link to view the merge request will appear once ready."
+msgstr ""
+
msgid "StaticSiteEditor|An error occurred while submitting your changes."
msgstr ""
msgid "StaticSiteEditor|Branch could not be created."
msgstr ""
+msgid "StaticSiteEditor|Copy update"
+msgstr ""
+
msgid "StaticSiteEditor|Could not commit the content changes."
msgstr ""
msgid "StaticSiteEditor|Could not create merge request."
msgstr ""
+msgid "StaticSiteEditor|Creating your merge request"
+msgstr ""
+
msgid "StaticSiteEditor|Incompatible file content"
msgstr ""
@@ -23745,6 +24597,9 @@ msgstr ""
msgid "StaticSiteEditor|View documentation"
msgstr ""
+msgid "StaticSiteEditor|You can set an assignee to get your changes reviewed and deployed once your merge request is created."
+msgstr ""
+
msgid "StaticSiteEditor|Your merge request has been created"
msgstr ""
@@ -23874,15 +24729,15 @@ msgstr ""
msgid "Submit %{humanized_resource_name}"
msgstr ""
-msgid "Submit Changes"
-msgstr ""
-
msgid "Submit a review"
msgstr ""
msgid "Submit as spam"
msgstr ""
+msgid "Submit changes"
+msgstr ""
+
msgid "Submit feedback"
msgstr ""
@@ -24036,6 +24891,9 @@ msgstr ""
msgid "Successfully deleted U2F device."
msgstr ""
+msgid "Successfully deleted WebAuthn device."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -24354,9 +25212,6 @@ msgstr ""
msgid "Template to append to all Service Desk issues"
msgstr ""
-msgid "Template was successfully saved."
-msgstr ""
-
msgid "Templates"
msgstr ""
@@ -24435,10 +25290,28 @@ msgid_plural "Test coverage: %d hits"
msgstr[0] ""
msgstr[1] ""
-msgid "Test failed."
+msgid "Test settings"
msgstr ""
-msgid "Test settings and save changes"
+msgid "TestCases|New Test Case"
+msgstr ""
+
+msgid "TestCases|New test case"
+msgstr ""
+
+msgid "TestCases|Search test cases"
+msgstr ""
+
+msgid "TestCases|Something went wrong while creating a test case."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching count of test cases."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching test cases list."
+msgstr ""
+
+msgid "TestCases|Submit test case"
msgstr ""
msgid "TestHooks|Ensure one of your projects has merge requests."
@@ -24504,6 +25377,9 @@ msgstr ""
msgid "Thank you for signing up for your free trial! You will get additional instructions in your inbox shortly."
msgstr ""
+msgid "Thank you for your business."
+msgstr ""
+
msgid "Thank you for your feedback!"
msgstr ""
@@ -24563,9 +25439,6 @@ msgstr ""
msgid "The URL to use for connecting to Elasticsearch. Use a comma-separated list to support clustering (e.g., \"http://localhost:9200, http://localhost:9201\")."
msgstr ""
-msgid "The Web IDE offers advanced syntax highlighting capabilities and more."
-msgstr ""
-
msgid "The X509 Certificate to use when mutual TLS is required to communicate with the external authorization service. If left blank, the server certificate is still validated when accessing over HTTPS."
msgstr ""
@@ -24676,6 +25549,9 @@ msgstr ""
msgid "The form contains the following error:"
msgstr ""
+msgid "The form contains the following warning:"
+msgstr ""
+
msgid "The global settings require you to enable Two-Factor Authentication for your account."
msgstr ""
@@ -24790,9 +25666,6 @@ msgstr ""
msgid "The private key to use when a client certificate is provided. This value is encrypted at rest."
msgstr ""
-msgid "The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The project can be accessed by any logged in user."
msgstr ""
@@ -24829,7 +25702,7 @@ msgstr ""
msgid "The remote repository is being updated..."
msgstr ""
-msgid "The repository can be commited to, and issues, comments and other entities can be created."
+msgid "The repository can be committed to, and issues, comments and other entities can be created."
msgstr ""
msgid "The repository for this project does not exist."
@@ -24883,9 +25756,6 @@ msgstr ""
msgid "The time taken by each data entry gathered by that stage."
msgstr ""
-msgid "The total stage shows the time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The update action will time out after %{number_of_minutes} minutes. For big repositories, use a clone/push combination."
msgstr ""
@@ -24949,6 +25819,9 @@ msgstr ""
msgid "There are no archived requirements"
msgstr ""
+msgid "There are no archived test cases"
+msgstr ""
+
msgid "There are no changes"
msgstr ""
@@ -24988,6 +25861,9 @@ msgstr ""
msgid "There are no open requirements"
msgstr ""
+msgid "There are no open test cases"
+msgstr ""
+
msgid "There are no packages yet"
msgstr ""
@@ -25000,6 +25876,9 @@ msgstr ""
msgid "There is a limit of %{ci_project_subscriptions_limit} subscriptions from or to a project."
msgstr ""
+msgid "There is already a To-Do for this design."
+msgstr ""
+
msgid "There is already a repository with that name on disk"
msgstr ""
@@ -25018,6 +25897,9 @@ msgstr ""
msgid "There was a problem communicating with your device."
msgstr ""
+msgid "There was a problem fetching branches."
+msgstr ""
+
msgid "There was a problem fetching groups."
msgstr ""
@@ -25246,9 +26128,15 @@ msgstr ""
msgid "This action can lead to data loss. To prevent accidental actions we ask you to confirm your intention."
msgstr ""
+msgid "This action cannot be undone, and will permanently delete the %{key} SSH key"
+msgstr ""
+
msgid "This action cannot be undone. You will lose the project's repository and all content: issues, merge requests, etc."
msgstr ""
+msgid "This action has been performed too many times. Try again later."
+msgstr ""
+
msgid "This action will %{strongOpen}permanently delete%{strongClose} %{codeOpen}%{project}%{codeClose} %{strongOpen}immediately%{strongClose}, including its repositories and all content: issues, merge requests, etc."
msgstr ""
@@ -25276,9 +26164,6 @@ msgstr ""
msgid "This board's scope is reduced"
msgstr ""
-msgid "This branch has changed since you started editing. Would you like to create a new branch?"
-msgstr ""
-
msgid "This chart could not be displayed"
msgstr ""
@@ -25405,15 +26290,9 @@ msgstr ""
msgid "This is a security log of important events involving your account."
msgstr ""
-msgid "This is the author's first Merge Request to this project."
-msgstr ""
-
msgid "This is the highest peak of users on your installation since the license started."
msgstr ""
-msgid "This is the maximum number of users that have existed at the same time since the license started. This is the minimum number of seats you will need to buy when you renew your license."
-msgstr ""
-
msgid "This is the number of currently active users on your installation, and this is the minimum number you need to purchase when you renew your license."
msgstr ""
@@ -25645,6 +26524,15 @@ msgstr ""
msgid "This user has no identities"
msgstr ""
+msgid "This user has previously committed to the %{name} project."
+msgstr ""
+
+msgid "This user has the %{access} role in the %{name} project."
+msgstr ""
+
+msgid "This user is the author of this %{noteable}."
+msgstr ""
+
msgid "This user will be the author of all events in the activity feed that are the result of an update, like new branches being created or new commits being pushed to existing branches."
msgstr ""
@@ -25675,6 +26563,9 @@ msgstr ""
msgid "Threat Monitoring"
msgstr ""
+msgid "ThreatMonitoring|All Environments"
+msgstr ""
+
msgid "ThreatMonitoring|Anomalous Requests"
msgstr ""
@@ -25702,9 +26593,6 @@ msgstr ""
msgid "ThreatMonitoring|Operations Per Second"
msgstr ""
-msgid "ThreatMonitoring|Overview"
-msgstr ""
-
msgid "ThreatMonitoring|Packet Activity"
msgstr ""
@@ -25723,6 +26611,9 @@ msgstr ""
msgid "ThreatMonitoring|Something went wrong, unable to fetch statistics"
msgstr ""
+msgid "ThreatMonitoring|Statistics"
+msgstr ""
+
msgid "ThreatMonitoring|The firewall is not installed or has been disabled. To view this data, ensure the web application firewall is installed and enabled for your cluster."
msgstr ""
@@ -26114,6 +27005,9 @@ msgstr ""
msgid "To update Snippets with multiple files, you must use the `files` parameter"
msgstr ""
+msgid "To use Gitpod you must first enable the feature in the integrations section of your %{user_prefs}."
+msgstr ""
+
msgid "To view all %{scannedResourcesCount} scanned URLs, please download the CSV file"
msgstr ""
@@ -26147,9 +27041,6 @@ msgstr ""
msgid "Toggle Sidebar"
msgstr ""
-msgid "Toggle all threads"
-msgstr ""
-
msgid "Toggle backtrace"
msgstr ""
@@ -26174,9 +27065,6 @@ msgstr ""
msgid "Toggle navigation"
msgstr ""
-msgid "Toggle project"
-msgstr ""
-
msgid "Toggle sidebar"
msgstr ""
@@ -26216,6 +27104,9 @@ msgstr ""
msgid "Too many projects enabled. You will need to manage them via the console or the API."
msgstr ""
+msgid "Too much data"
+msgstr ""
+
msgid "Topics (optional)"
msgstr ""
@@ -26234,6 +27125,9 @@ msgstr ""
msgid "Total cores (CPUs)"
msgstr ""
+msgid "Total days to completion"
+msgstr ""
+
msgid "Total issues"
msgstr ""
@@ -26330,6 +27224,9 @@ msgstr ""
msgid "Trending"
msgstr ""
+msgid "Trials|Create a new group to start your GitLab Gold trial."
+msgstr ""
+
msgid "Trials|Go back to GitLab"
msgstr ""
@@ -26339,6 +27236,15 @@ msgstr ""
msgid "Trials|You can always resume this process by selecting your avatar and choosing 'Start a Gold trial'"
msgstr ""
+msgid "Trials|You can apply your trial to a new group or an existing group."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group or your personal account."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group, an existing group, or your personal account."
+msgstr ""
+
msgid "Trials|You won't get a free trial right now but you can always resume this process by clicking on your avatar and choosing 'Start a free trial'"
msgstr ""
@@ -26408,6 +27314,9 @@ msgstr ""
msgid "Try using a different search term to find the file you are looking for."
msgstr ""
+msgid "Trying to communicate with your device. Plug it in (if needed) and press the button on the device now."
+msgstr ""
+
msgid "Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now."
msgstr ""
@@ -26495,6 +27404,12 @@ msgstr ""
msgid "URL or request ID"
msgstr ""
+msgid "USER %{user} WILL BE REMOVED! Are you sure?"
+msgstr ""
+
+msgid "USER WILL BE BLOCKED! Are you sure?"
+msgstr ""
+
msgid "UTC"
msgstr ""
@@ -26552,9 +27467,6 @@ msgstr ""
msgid "Unable to load the merge request widget. Try reloading the page."
msgstr ""
-msgid "Unable to resolve"
-msgstr ""
-
msgid "Unable to save iteration. Please try again"
msgstr ""
@@ -26603,6 +27515,9 @@ msgstr ""
msgid "Undo ignore"
msgstr ""
+msgid "Unexpected error"
+msgstr ""
+
msgid "Unfortunately, your email message to GitLab could not be processed."
msgstr ""
@@ -26636,6 +27551,9 @@ msgstr ""
msgid "Unknown response text"
msgstr ""
+msgid "Unless otherwise agreed to in writing with GitLab, by clicking \"Upload License\" you agree that your use of GitLab Software is subject to the %{eula_link_start}Terms of Service%{eula_link_end}."
+msgstr ""
+
msgid "Unlimited"
msgstr ""
@@ -27002,9 +27920,6 @@ msgstr ""
msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
msgstr ""
-msgid "Use a hardware device to add the second factor of authentication."
-msgstr ""
-
msgid "Use an one time password authenticator on your mobile device or computer to enable two-factor authentication (2FA)."
msgstr ""
@@ -27278,13 +28193,13 @@ msgstr ""
msgid "Users"
msgstr ""
-msgid "Users in License:"
+msgid "Users in License"
msgstr ""
-msgid "Users or groups set as approvers in the project's or merge request's settings."
+msgid "Users in License:"
msgstr ""
-msgid "Users outside of license"
+msgid "Users or groups set as approvers in the project's or merge request's settings."
msgstr ""
msgid "Users over License:"
@@ -27302,9 +28217,6 @@ msgstr ""
msgid "Users with a Guest role or those who don't belong to a Project or Group will not use a seat from your license."
msgstr ""
-msgid "Users with a Guest role or those who don't belong to any projects or groups don't count towards seats in use."
-msgstr ""
-
msgid "UsersSelect|%{name} + %{length} more"
msgstr ""
@@ -27344,9 +28256,6 @@ msgstr ""
msgid "Validations failed."
msgstr ""
-msgid "Validity"
-msgstr ""
-
msgid "Value"
msgstr ""
@@ -27365,6 +28274,9 @@ msgstr ""
msgid "Value Stream Name"
msgstr ""
+msgid "ValueStreamAnalyticsStage|We don't have enough data to show this stage."
+msgstr ""
+
msgid "ValueStreamAnalytics|%{days}d"
msgstr ""
@@ -27621,6 +28533,9 @@ msgstr ""
msgid "VisualReviewApp|Steps 1 and 2 (and sometimes 3) are performed once by the developer before requesting feedback. Steps 3 (if necessary), 4 is performed by the reviewer each time they perform a review."
msgstr ""
+msgid "Visualization"
+msgstr ""
+
msgid "Vulnerabilities"
msgstr ""
@@ -27648,34 +28563,31 @@ msgstr ""
msgid "VulnerabilityChart|Severity"
msgstr ""
-msgid "VulnerabilityManagement|A true-positive and will fix"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Change status"
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|Confirm"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Confirmed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
-msgstr ""
-
-msgid "VulnerabilityManagement|Detected %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|A true-positive and will fix"
msgstr ""
-msgid "VulnerabilityManagement|Dismiss"
+msgid "VulnerabilityManagement|Change status"
msgstr ""
-msgid "VulnerabilityManagement|Dismissed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
msgstr ""
-msgid "VulnerabilityManagement|Resolved"
+msgid "VulnerabilityManagement|Detected"
msgstr ""
-msgid "VulnerabilityManagement|Resolved %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Needs triage"
msgstr ""
msgid "VulnerabilityManagement|Something went wrong while trying to delete the comment. Please try again later."
@@ -27726,6 +28638,9 @@ msgstr ""
msgid "Vulnerability|%{scannerName} (version %{scannerVersion})"
msgstr ""
+msgid "Vulnerability|Activity"
+msgstr ""
+
msgid "Vulnerability|Class"
msgstr ""
@@ -27738,6 +28653,9 @@ msgstr ""
msgid "Vulnerability|Description"
msgstr ""
+msgid "Vulnerability|Detected"
+msgstr ""
+
msgid "Vulnerability|Evidence"
msgstr ""
@@ -27801,6 +28719,9 @@ msgstr ""
msgid "Warning: Displaying this diagram might cause performance issues on this page."
msgstr ""
+msgid "We are currently unable to fetch data for the pipeline header."
+msgstr ""
+
msgid "We are currently unable to fetch data for this graph."
msgstr ""
@@ -27840,6 +28761,12 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
+msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
+msgstr ""
+
+msgid "We would like to inform you that your subscription GitLab Enterprise Edition %{plan_name} is nearing its user limit. You have %{active_user_count} active users, which is almost at the user limit of %{maximum_user_count}."
+msgstr ""
+
msgid "We've found no vulnerabilities"
msgstr ""
@@ -27855,6 +28782,12 @@ msgstr ""
msgid "Web terminal"
msgstr ""
+msgid "WebAuthn Devices (%{length})"
+msgstr ""
+
+msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
+msgstr ""
+
msgid "WebIDE|Merge request"
msgstr ""
@@ -27993,15 +28926,9 @@ msgstr ""
msgid "Welcome to the guided GitLab tour"
msgstr ""
-msgid "Welcome to your Issue Board!"
-msgstr ""
-
msgid "Welcome to your issue board!"
msgstr ""
-msgid "We’ve been making changes to %{featureName} and we’d love your feedback %{linkStart}in this issue%{linkEnd} to help us improve the experience."
-msgstr ""
-
msgid "What are you searching for?"
msgstr ""
@@ -28020,6 +28947,9 @@ msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
msgstr ""
+msgid "When enabled, any user visiting %{host} and creating an account will have to be explicitly approved by the admin before they can login. This setting is effective only if sign-ups are enabled."
+msgstr ""
+
msgid "When enabled, any user visiting %{host} will be able to create an account."
msgstr ""
@@ -28244,6 +29174,9 @@ msgstr ""
msgid "With requirements, you can set criteria to check your products against."
msgstr ""
+msgid "With test cases, you can define conditions for your project to meet in determining quality"
+msgstr ""
+
msgid "Withdraw Access Request"
msgstr ""
@@ -28259,6 +29192,9 @@ msgstr ""
msgid "Workflow Help"
msgstr ""
+msgid "Would you like to create a new branch?"
+msgstr ""
+
msgid "Write"
msgstr ""
@@ -28280,6 +29216,9 @@ msgstr ""
msgid "Wrong extern UID provided. Make sure Auth0 is configured correctly."
msgstr ""
+msgid "YYYY-MM-DD"
+msgstr ""
+
msgid "Yes"
msgstr ""
@@ -28337,7 +29276,7 @@ msgstr ""
msgid "You are going to remove the fork relationship from %{project_full_name}. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "You are going to transfer %{project_full_name} to another owner. Are you ABSOLUTELY sure?"
+msgid "You are going to transfer %{project_full_name} to another namespace. Are you ABSOLUTELY sure?"
msgstr ""
msgid "You are going to turn off the confidentiality. This means %{strongStart}everyone%{strongEnd} will be able to see and leave a comment on this %{issuableType}."
@@ -28397,9 +29336,6 @@ msgstr ""
msgid "You can always edit this later"
msgstr ""
-msgid "You can apply your Trial to your Personal account or create a New Group."
-msgstr ""
-
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings"
msgstr ""
@@ -28421,12 +29357,18 @@ msgstr ""
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
+msgid "You can find more information about GitLab subscriptions in %{subscriptions_doc_link}."
+msgstr ""
+
msgid "You can generate an access token scoped to this project for each application to use the GitLab API."
msgstr ""
msgid "You can get started by cloning the repository or start adding files to it with one of the following options."
msgstr ""
+msgid "You can group test cases using labels. To learn about the future direction of this feature, visit %{linkStart}Quality Management direction page%{linkEnd}."
+msgstr ""
+
msgid "You can invite a new member to %{project_name} or invite another group."
msgstr ""
@@ -28442,6 +29384,9 @@ msgstr ""
msgid "You can notify the app / group or a project by sending them an email notification"
msgstr ""
+msgid "You can now close this window."
+msgstr ""
+
msgid "You can now export your security dashboard to a CSV report."
msgstr ""
@@ -28490,9 +29435,6 @@ msgstr ""
msgid "You can test your .gitlab-ci.yml in %{linkStart}CI Lint%{linkEnd}."
msgstr ""
-msgid "You can try again using %{begin_link}basic search%{end_link}"
-msgstr ""
-
msgid "You cannot access the raw file. Please wait a minute."
msgstr ""
@@ -28544,6 +29486,9 @@ msgstr ""
msgid "You don't have any U2F devices registered yet."
msgstr ""
+msgid "You don't have any WebAuthn devices registered yet."
+msgstr ""
+
msgid "You don't have any active chat names."
msgstr ""
@@ -28631,6 +29576,9 @@ msgstr ""
msgid "You must accept our Terms of Service and privacy policy in order to register an account"
msgstr ""
+msgid "You must be logged in to search across all of GitLab"
+msgstr ""
+
msgid "You must disassociate %{domain} from all clusters it is attached to before deletion."
msgstr ""
@@ -28670,7 +29618,7 @@ msgstr ""
msgid "You need to be logged in."
msgstr ""
-msgid "You need to register a two-factor authentication app before you can set up a U2F device."
+msgid "You need to register a two-factor authentication app before you can set up a device."
msgstr ""
msgid "You need to set terms to be enforced"
@@ -28688,6 +29636,9 @@ msgstr ""
msgid "You reached %{usage_in_percent} of %{namespace_name}'s storage capacity (%{used_storage} of %{storage_limit})"
msgstr ""
+msgid "You successfully declined the invitation"
+msgstr ""
+
msgid "You tried to fork %{link_to_the_project} but it failed for the following reason:"
msgstr ""
@@ -28853,10 +29804,13 @@ msgstr ""
msgid "Your U2F device did not send a valid JSON response."
msgstr ""
-msgid "Your U2F device needs to be set up. Plug it in (if not already) and click the button on the left."
+msgid "Your U2F device was registered!"
msgstr ""
-msgid "Your U2F device was registered!"
+msgid "Your WebAuthn device did not send a valid JSON response."
+msgstr ""
+
+msgid "Your WebAuthn device was registered!"
msgstr ""
msgid "Your access request to the %{source_type} has been withdrawn."
@@ -28880,6 +29834,9 @@ msgstr ""
msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
msgstr ""
+msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
+msgstr ""
+
msgid "Your changes can be committed to %{branch_name} because a merge request is open."
msgstr ""
@@ -28916,6 +29873,12 @@ msgstr ""
msgid "Your deployment services will be broken, you will need to manually fix the services after renaming."
msgstr ""
+msgid "Your device is not compatible with GitLab. Please try another device"
+msgstr ""
+
+msgid "Your device needs to be set up. Plug it in (if needed) and click the button on the left."
+msgstr ""
+
msgid "Your device was successfully set up! Give it a name and register it with the GitLab server."
msgstr ""
@@ -29029,9 +29992,6 @@ msgstr[1] ""
msgid "access:"
msgstr ""
-msgid "activated"
-msgstr ""
-
msgid "added %{created_at_timeago}"
msgstr ""
@@ -29104,9 +30064,21 @@ msgstr ""
msgid "by %{user}"
msgstr ""
+msgid "cannot be a date in the past"
+msgstr ""
+
msgid "cannot be changed if a personal project has container registry tags."
msgstr ""
+msgid "cannot be changed if shared runners are enabled"
+msgstr ""
+
+msgid "cannot be enabled because parent group does not allow it"
+msgstr ""
+
+msgid "cannot be enabled because parent group has shared Runners disabled"
+msgstr ""
+
msgid "cannot be enabled unless all domains have TLS certificates"
msgstr ""
@@ -29152,7 +30124,7 @@ msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about SAST %{linkEndTag}"
msgstr ""
-msgid "ciReport|%{linkStartTag}Learn more about Secret Scanning %{linkEndTag}"
+msgid "ciReport|%{linkStartTag}Learn more about Secret Detection %{linkEndTag}"
msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about codequality reports %{linkEndTag}"
@@ -29467,9 +30439,6 @@ msgstr ""
msgid "error"
msgstr ""
-msgid "error code:"
-msgstr ""
-
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr ""
@@ -29491,6 +30460,9 @@ msgstr ""
msgid "failed to dismiss associated finding(id=%{finding_id}): %{message}"
msgstr ""
+msgid "failed to revert associated finding(id=%{finding_id}) to detected"
+msgstr ""
+
msgid "file"
msgid_plural "files"
msgstr[0] ""
@@ -30033,6 +31005,9 @@ msgstr ""
msgid "must be a root namespace"
msgstr ""
+msgid "must be a valid IPv4 or IPv6 address"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -30069,6 +31044,9 @@ msgstr ""
msgid "no expiration"
msgstr ""
+msgid "no name set"
+msgstr ""
+
msgid "no one can merge"
msgstr ""
@@ -30247,9 +31225,6 @@ msgstr ""
msgid "security Reports|There was an error creating the merge request"
msgstr ""
-msgid "settings saved, but not activated"
-msgstr ""
-
msgid "severity|Critical"
msgstr ""
@@ -30376,9 +31351,6 @@ msgstr ""
msgid "toggle collapse"
msgstr ""
-msgid "toggle dropdown"
-msgstr ""
-
msgid "triggered"
msgstr ""
@@ -30406,6 +31378,9 @@ msgstr ""
msgid "user avatar"
msgstr ""
+msgid "user preferences"
+msgstr ""
+
msgid "username"
msgstr ""
diff --git a/locale/id_ID/gitlab.po b/locale/id_ID/gitlab.po
index 0b74ca0ab39..9376db3055f 100644
--- a/locale/id_ID/gitlab.po
+++ b/locale/id_ID/gitlab.po
@@ -14,7 +14,10 @@ msgstr ""
"X-Crowdin-Language: id\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 6\n"
-"PO-Revision-Date: 2020-09-04 23:02\n"
+"PO-Revision-Date: 2020-10-02 18:41\n"
+
+msgid " %{project_name}#%{issue_iid} &middot; opened %{issue_created} by %{author}"
+msgstr ""
msgid " %{start} to %{end}"
msgstr ""
@@ -72,6 +75,14 @@ msgstr ""
msgid "\"el\" parameter is required for createInstance()"
msgstr ""
+msgid "%d Approval"
+msgid_plural "%d Approvals"
+msgstr[0] ""
+
+msgid "%d Package"
+msgid_plural "%d Packages"
+msgstr[0] ""
+
msgid "%d Scanned URL"
msgid_plural "%d Scanned URLs"
msgstr[0] ""
@@ -123,6 +134,10 @@ msgstr[0] ""
msgid "%d commits"
msgstr ""
+msgid "%d completed issue"
+msgid_plural "%d completed issues"
+msgstr[0] ""
+
msgid "%d contribution"
msgid_plural "%d contributions"
msgstr[0] ""
@@ -131,6 +146,10 @@ msgid "%d day"
msgid_plural "%d days"
msgstr[0] ""
+msgid "%d day until tags are automatically removed"
+msgid_plural "%d days until tags are automatically removed"
+msgstr[0] ""
+
msgid "%d error"
msgid_plural "%d errors"
msgstr[0] ""
@@ -203,6 +222,14 @@ msgid "%d more comment"
msgid_plural "%d more comments"
msgstr[0] ""
+msgid "%d open issue"
+msgid_plural "%d open issues"
+msgstr[0] ""
+
+msgid "%d pending comment"
+msgid_plural "%d pending comments"
+msgstr[0] ""
+
msgid "%d personal project will be removed and cannot be restored."
msgid_plural "%d personal projects will be removed and cannot be restored."
msgstr[0] ""
@@ -215,6 +242,10 @@ msgid "%d project"
msgid_plural "%d projects"
msgstr[0] ""
+msgid "%d project selected"
+msgid_plural "%d projects selected"
+msgstr[0] ""
+
msgid "%d request with warnings"
msgid_plural "%d requests with warnings"
msgstr[0] ""
@@ -231,6 +262,10 @@ msgid "%d tag"
msgid_plural "%d tags"
msgstr[0] ""
+msgid "%d tag per image name"
+msgid_plural "%d tags per image name"
+msgstr[0] ""
+
msgid "%d unassigned issue"
msgid_plural "%d unassigned issues"
msgstr[0] ""
@@ -247,6 +282,10 @@ msgid "%d vulnerability dismissed"
msgid_plural "%d vulnerabilities dismissed"
msgstr[0] ""
+msgid "%d warning found:"
+msgid_plural "%d warnings found:"
+msgstr[0] ""
+
msgid "%s additional commit has been omitted to prevent performance issues."
msgid_plural "%s additional commits have been omitted to prevent performance issues."
msgstr[0] ""
@@ -284,6 +323,9 @@ msgstr ""
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr ""
+msgid "%{completedCount} completed weight"
+msgstr ""
+
msgid "%{completedWeight} of %{totalWeight} weight completed"
msgstr ""
@@ -329,13 +371,12 @@ msgid "%{count} participant"
msgid_plural "%{count} participants"
msgstr[0] ""
-msgid "%{count} pending comment"
-msgid_plural "%{count} pending comments"
-msgstr[0] ""
-
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
+msgid "%{count} total weight"
+msgstr ""
+
msgid "%{dashboard_path} could not be found."
msgstr ""
@@ -390,6 +431,9 @@ msgstr ""
msgid "%{group_name} uses group managed accounts. You need to create a new GitLab account which will be managed by %{group_name}."
msgstr ""
+msgid "%{group_name}&%{epic_iid} &middot; opened %{epic_created} by %{author}"
+msgstr ""
+
msgid "%{host} sign-in from new location"
msgstr ""
@@ -402,7 +446,7 @@ msgstr ""
msgid "%{issuableType} will be removed! Are you sure?"
msgstr ""
-msgid "%{issuesSize} issues with a limit of %{maxIssueCount}"
+msgid "%{issuesCount} issues with a limit of %{maxIssueCount}"
msgstr ""
msgid "%{issuesSize} with a limit of %{maxIssueCount}"
@@ -435,7 +479,7 @@ msgstr ""
msgid "%{labelStart}Namespace:%{labelEnd} %{namespace}"
msgstr ""
-msgid "%{labelStart}Report Type:%{labelEnd} %{reportType}"
+msgid "%{labelStart}Scan Type:%{labelEnd} %{reportType}"
msgstr ""
msgid "%{labelStart}Scanner:%{labelEnd} %{scanner}"
@@ -625,9 +669,6 @@ msgid "%{securityScanner} result is not available because a pipeline has not bee
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] ""
-msgid "%{service_title} %{message}."
-msgstr ""
-
msgid "%{size} GiB"
msgstr ""
@@ -711,6 +752,12 @@ msgstr ""
msgid "%{timebox_name} should belong either to a project or a group."
msgstr ""
+msgid "%{timebox_type} does not support burnup charts"
+msgstr ""
+
+msgid "%{timebox_type} must have a start and due date"
+msgstr ""
+
msgid "%{title} %{operator} %{threshold}"
msgstr ""
@@ -735,7 +782,7 @@ msgstr ""
msgid "%{total} open issue weight"
msgstr ""
-msgid "%{total} open issues"
+msgid "%{total} warnings found: showing first %{warningsDisplayed}"
msgstr ""
msgid "%{usage_ping_link_start}Learn more%{usage_ping_link_end} about what information is shared with GitLab Inc."
@@ -768,9 +815,6 @@ msgstr ""
msgid "&lt; 1 hour"
msgstr ""
-msgid "&lt;no name set&gt;"
-msgstr ""
-
msgid "&lt;no scopes selected&gt;"
msgstr ""
@@ -801,6 +845,9 @@ msgstr ""
msgid "'%{name}' Value Stream created"
msgstr ""
+msgid "'%{name}' Value Stream deleted"
+msgstr ""
+
msgid "'%{name}' stage already exists"
msgstr ""
@@ -859,6 +906,9 @@ msgstr ""
msgid "+ %{numberOfHiddenAssignees} more"
msgstr ""
+msgid "+ %{numberOfHiddenReviewers} more"
+msgstr ""
+
msgid "+%d more"
msgid_plural "+%d more"
msgstr[0] ""
@@ -913,6 +963,10 @@ msgid "1 Day"
msgid_plural "%d Days"
msgstr[0] ""
+msgid "1 Issue"
+msgid_plural "%d Issues"
+msgstr[0] ""
+
msgid "1 closed issue"
msgid_plural "%{issues} closed issues"
msgstr[0] ""
@@ -925,6 +979,10 @@ msgid "1 day"
msgid_plural "%d days"
msgstr[0] ""
+msgid "1 deploy key"
+msgid_plural "%d deploy keys"
+msgstr[0] ""
+
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1018,6 +1076,9 @@ msgstr ""
msgid ":%{startLine} to %{endLine}"
msgstr ""
+msgid "A %{incident_docs_start}modified issue%{incident_docs_end} to guide the resolution of incidents."
+msgstr ""
+
msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr ""
@@ -1030,6 +1091,9 @@ msgstr ""
msgid "A GitBook site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
+msgid "A Gitpod configured Webapplication in Spring and Java"
+msgstr ""
+
msgid "A Hexo site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
@@ -1201,9 +1265,15 @@ msgstr ""
msgid "Access expiration date"
msgstr ""
+msgid "Access expires"
+msgstr ""
+
msgid "Access forbidden. Check your access level."
msgstr ""
+msgid "Access granted"
+msgstr ""
+
msgid "Access requests"
msgstr ""
@@ -1213,6 +1283,9 @@ msgstr ""
msgid "Access to Pages websites are controlled based on the user's membership to a given project. By checking this box, users will be required to be logged in to have access to all Pages websites in your instance."
msgstr ""
+msgid "AccessDropdown|Deploy Keys"
+msgstr ""
+
msgid "AccessDropdown|Groups"
msgstr ""
@@ -1330,12 +1403,6 @@ msgstr ""
msgid "Active Sessions"
msgstr ""
-msgid "Active Users:"
-msgstr ""
-
-msgid "Active users"
-msgstr ""
-
msgid "Activity"
msgstr ""
@@ -1502,9 +1569,6 @@ msgstr ""
msgid "Add label(s)"
msgstr ""
-msgid "Add license"
-msgstr ""
-
msgid "Add list"
msgstr ""
@@ -1679,21 +1743,51 @@ msgstr ""
msgid "AdminArea|Bots"
msgstr ""
+msgid "AdminArea|Components"
+msgstr ""
+
msgid "AdminArea|Developer"
msgstr ""
+msgid "AdminArea|Features"
+msgstr ""
+
+msgid "AdminArea|Groups: %{number_of_groups}"
+msgstr ""
+
msgid "AdminArea|Guest"
msgstr ""
msgid "AdminArea|Included Free in license"
msgstr ""
+msgid "AdminArea|Latest groups"
+msgstr ""
+
+msgid "AdminArea|Latest projects"
+msgstr ""
+
+msgid "AdminArea|Latest users"
+msgstr ""
+
msgid "AdminArea|Maintainer"
msgstr ""
+msgid "AdminArea|New group"
+msgstr ""
+
+msgid "AdminArea|New project"
+msgstr ""
+
+msgid "AdminArea|New user"
+msgstr ""
+
msgid "AdminArea|Owner"
msgstr ""
+msgid "AdminArea|Projects: %{number_of_projects}"
+msgstr ""
+
msgid "AdminArea|Reporter"
msgstr ""
@@ -1721,6 +1815,9 @@ msgstr ""
msgid "AdminArea|Users without a Group and Project"
msgstr ""
+msgid "AdminArea|Users: %{number_of_users}"
+msgstr ""
+
msgid "AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running."
msgstr ""
@@ -1739,9 +1836,6 @@ msgstr ""
msgid "AdminProjects|Delete Project %{projectName}?"
msgstr ""
-msgid "AdminProjects|Delete project"
-msgstr ""
-
msgid "AdminSettings|Apply integration settings to all Projects"
msgstr ""
@@ -1979,21 +2073,30 @@ msgstr ""
msgid "AdminUsers|Without projects"
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 ""
msgid "AdminUsers|You cannot remove your own admin rights."
msgstr ""
+msgid "AdminUsers|You must transfer ownership or delete the groups owned by this user before you can delete their account"
+msgstr ""
+
msgid "Administration"
msgstr ""
msgid "Advanced"
msgstr ""
+msgid "Advanced Search"
+msgstr ""
+
+msgid "Advanced Search with Elasticsearch"
+msgstr ""
+
msgid "Advanced Settings"
msgstr ""
@@ -2070,6 +2173,9 @@ msgstr ""
msgid "AlertManagement|Edit"
msgstr ""
+msgid "AlertManagement|Environment"
+msgstr ""
+
msgid "AlertManagement|Events"
msgstr ""
@@ -2082,6 +2188,9 @@ msgstr ""
msgid "AlertManagement|Issue"
msgstr ""
+msgid "AlertManagement|Key"
+msgstr ""
+
msgid "AlertManagement|Low"
msgstr ""
@@ -2175,6 +2284,9 @@ msgstr ""
msgid "AlertManagement|Unknown"
msgstr ""
+msgid "AlertManagement|Value"
+msgstr ""
+
msgid "AlertManagement|View alerts in Opsgenie"
msgstr ""
@@ -2334,6 +2446,9 @@ msgstr ""
msgid "All projects"
msgstr ""
+msgid "All projects selected"
+msgstr ""
+
msgid "All security scans are enabled because %{linkStart}Auto DevOps%{linkEnd} is enabled on this project"
msgstr ""
@@ -2421,6 +2536,9 @@ msgstr ""
msgid "Almost there"
msgstr ""
+msgid "Already blocked"
+msgstr ""
+
msgid "Also called \"Issuer\" or \"Relying party trust identifier\""
msgstr ""
@@ -2475,6 +2593,9 @@ msgstr ""
msgid "An error has occurred"
msgstr ""
+msgid "An error occured while making the changes: %{error}"
+msgstr ""
+
msgid "An error occurred adding a draft to the thread."
msgstr ""
@@ -2502,12 +2623,6 @@ msgstr ""
msgid "An error occurred when toggling the notification subscription"
msgstr ""
-msgid "An error occurred when trying to resolve a comment. Please try again."
-msgstr ""
-
-msgid "An error occurred when trying to resolve a discussion. Please try again."
-msgstr ""
-
msgid "An error occurred when updating the issue weight"
msgstr ""
@@ -2523,12 +2638,6 @@ msgstr ""
msgid "An error occurred while checking group path. Please refresh and try again."
msgstr ""
-msgid "An error occurred while committing your changes."
-msgstr ""
-
-msgid "An error occurred while creating the list. Please try again."
-msgstr ""
-
msgid "An error occurred while decoding the file."
msgstr ""
@@ -2601,25 +2710,19 @@ msgstr ""
msgid "An error occurred while fetching the Service Desk address."
msgstr ""
-msgid "An error occurred while fetching the board issues. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the board lists. Please reload the page."
msgstr ""
msgid "An error occurred while fetching the board lists. Please try again."
msgstr ""
-msgid "An error occurred while fetching the board swimlanes. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the builds."
msgstr ""
msgid "An error occurred while fetching the job log."
msgstr ""
-msgid "An error occurred while fetching the job trace."
+msgid "An error occurred while fetching the job logs."
msgstr ""
msgid "An error occurred while fetching the job."
@@ -2766,9 +2869,6 @@ msgstr ""
msgid "An error occurred while saving assignees"
msgstr ""
-msgid "An error occurred while saving the template. Please check if the template exists."
-msgstr ""
-
msgid "An error occurred while searching for milestones"
msgstr ""
@@ -2787,10 +2887,10 @@ msgstr ""
msgid "An error occurred while updating approvers"
msgstr ""
-msgid "An error occurred while updating the comment"
+msgid "An error occurred while updating labels."
msgstr ""
-msgid "An error occurred while updating the list. Please try again."
+msgid "An error occurred while updating the comment"
msgstr ""
msgid "An error occurred while validating group path"
@@ -2844,6 +2944,9 @@ msgstr ""
msgid "An unknown error occurred while loading this graph."
msgstr ""
+msgid "An unknown error occurred."
+msgstr ""
+
msgid "Analytics"
msgstr ""
@@ -2877,10 +2980,10 @@ msgstr ""
msgid "Any"
msgstr ""
-msgid "Any Author"
+msgid "Any %{header}"
msgstr ""
-msgid "Any Status"
+msgid "Any Author"
msgstr ""
msgid "Any branch"
@@ -2934,6 +3037,9 @@ msgstr ""
msgid "Application ID"
msgstr ""
+msgid "Application limits saved successfully"
+msgstr ""
+
msgid "Application settings saved successfully"
msgstr ""
@@ -3139,6 +3245,9 @@ msgstr ""
msgid "Are you sure you want to close this blocked issue?"
msgstr ""
+msgid "Are you sure you want to delete \"%{name}\" Value Stream?"
+msgstr ""
+
msgid "Are you sure you want to delete %{name}?"
msgstr ""
@@ -3148,6 +3257,9 @@ msgstr ""
msgid "Are you sure you want to delete this %{typeOfComment}?"
msgstr ""
+msgid "Are you sure you want to delete this SSH key?"
+msgstr ""
+
msgid "Are you sure you want to delete this board?"
msgstr ""
@@ -3172,6 +3284,10 @@ msgstr ""
msgid "Are you sure you want to erase this build?"
msgstr ""
+msgid "Are you sure you want to import %d repository?"
+msgid_plural "Are you sure you want to import %d repositories?"
+msgstr[0] ""
+
msgid "Are you sure you want to lose unsaved changes?"
msgstr ""
@@ -3181,15 +3297,15 @@ msgstr ""
msgid "Are you sure you want to merge immediately?"
msgstr ""
-msgid "Are you sure you want to permanently delete this license?"
-msgstr ""
-
msgid "Are you sure you want to re-deploy this environment?"
msgstr ""
msgid "Are you sure you want to regenerate the public key? You will have to update the public key on the remote server before mirroring will work again."
msgstr ""
+msgid "Are you sure you want to reindex?"
+msgstr ""
+
msgid "Are you sure you want to remove %{group_name}?"
msgstr ""
@@ -3217,6 +3333,9 @@ msgstr ""
msgid "Are you sure you want to revoke this nickname?"
msgstr ""
+msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
+msgstr ""
+
msgid "Are you sure you want to stop this environment?"
msgstr ""
@@ -3238,6 +3357,9 @@ msgstr ""
msgid "Are you sure? The device will be signed out of GitLab and all remember me tokens revoked."
msgstr ""
+msgid "Are you sure? This will invalidate your registered applications and U2F / WebAuthn devices."
+msgstr ""
+
msgid "Are you sure? This will invalidate your registered applications and U2F devices."
msgstr ""
@@ -3256,9 +3378,6 @@ msgstr ""
msgid "Artifacts"
msgstr ""
-msgid "As U2F devices are only supported by a few browsers, we require that you set up a two-factor authentication app before a U2F device. That way you'll always be able to log in - even when you're using an unsupported browser."
-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 ""
@@ -3450,6 +3569,9 @@ msgstr ""
msgid "AuditLogs|Target"
msgstr ""
+msgid "AuditLogs|This month"
+msgstr ""
+
msgid "AuditLogs|User Events"
msgstr ""
@@ -3489,6 +3611,9 @@ msgstr ""
msgid "Authentication via U2F device failed."
msgstr ""
+msgid "Authentication via WebAuthn device failed."
+msgstr ""
+
msgid "Author"
msgstr ""
@@ -3756,15 +3881,6 @@ msgstr ""
msgid "BambooService|You must set up automatic revision labeling and a repository trigger in Bamboo."
msgstr ""
-msgid "BatchComments|Delete all pending comments"
-msgstr ""
-
-msgid "BatchComments|Discard review?"
-msgstr ""
-
-msgid "BatchComments|You're about to discard your review which will delete all of your pending comments. The deleted comments %{strong_start}cannot%{strong_end} be restored."
-msgstr ""
-
msgid "Be careful. Changing the project's namespace can have unintended side effects."
msgstr ""
@@ -3786,6 +3902,9 @@ msgstr ""
msgid "Bi-weekly code coverage"
msgstr ""
+msgid "Billable Users:"
+msgstr ""
+
msgid "Billing"
msgstr ""
@@ -3795,7 +3914,7 @@ msgstr ""
msgid "BillingPlans|@%{user_name} you are currently using the %{plan_name} plan."
msgstr ""
-msgid "BillingPlans|Congratulations, your new trial is activated"
+msgid "BillingPlans|Congratulations, your free trial is activated."
msgstr ""
msgid "BillingPlans|If you would like to downgrade your plan please contact %{support_link_start}Customer Support%{support_link_end}."
@@ -3858,6 +3977,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Block user"
+msgstr ""
+
msgid "Blocked"
msgstr ""
@@ -3873,31 +3995,37 @@ msgstr ""
msgid "Blog"
msgstr ""
-msgid "Board name"
-msgstr ""
-
msgid "Board scope"
msgstr ""
msgid "Board scope affects which issues are displayed for anyone who visits this board"
msgstr ""
-msgid "BoardBlankState|Add default lists"
+msgid "Boards"
+msgstr ""
+
+msgid "Boards and Board Lists"
msgstr ""
-msgid "BoardBlankState|Add the following default lists to your Issue Board with one click:"
+msgid "Boards|An error occurred while creating the issue. Please try again."
msgstr ""
-msgid "BoardBlankState|Nevermind, I'll use my own"
+msgid "Boards|An error occurred while creating the list. Please try again."
msgstr ""
-msgid "BoardBlankState|Starting out with the default set of lists will get you right on the way to making the most of your board."
+msgid "Boards|An error occurred while fetching issues. Please reload the page."
msgstr ""
-msgid "Boards"
+msgid "Boards|An error occurred while fetching the board issues. Please reload the page."
msgstr ""
-msgid "Boards and Board Lists"
+msgid "Boards|An error occurred while fetching the board swimlanes. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while moving the issue. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while updating the list. Please try again."
msgstr ""
msgid "Boards|Collapse"
@@ -3924,7 +4052,7 @@ msgstr ""
msgid "Branch %{branch_name} was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr ""
-msgid "Branch has changed"
+msgid "Branch changed"
msgstr ""
msgid "Branch is already taken"
@@ -4230,6 +4358,9 @@ msgstr ""
msgid "CLOSED (MOVED)"
msgstr ""
+msgid "CODEOWNERS rule violation"
+msgstr ""
+
msgid "CONTRIBUTING"
msgstr ""
@@ -4260,9 +4391,6 @@ msgstr ""
msgid "Can't create snippet: %{err}"
msgstr ""
-msgid "Can't edit as source branch was deleted"
-msgstr ""
-
msgid "Can't fetch content for the blob: %{err}"
msgstr ""
@@ -4275,9 +4403,6 @@ msgstr ""
msgid "Can't load mermaid module: %{err}"
msgstr ""
-msgid "Can't remove group members without group managed account"
-msgstr ""
-
msgid "Can't scan the code?"
msgstr ""
@@ -4320,6 +4445,9 @@ msgstr ""
msgid "Cannot create the abuse report. This user has been blocked."
msgstr ""
+msgid "Cannot enable shared runners because parent group does not allow it"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -4425,6 +4553,15 @@ msgstr ""
msgid "Change your password or recover your current one"
msgstr ""
+msgid "ChangeReviewer|Reviewer changed from %{old} to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Reviewer changed to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Unassigned"
+msgstr ""
+
msgid "ChangeTypeActionLabel|Pick into branch"
msgstr ""
@@ -4464,6 +4601,9 @@ msgstr ""
msgid "Changes the title to \"%{title_param}\"."
msgstr ""
+msgid "Changes were successfully made."
+msgstr ""
+
msgid "Changes won't take place until the index is %{link_start}recreated%{link_end}."
msgstr ""
@@ -4869,6 +5009,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove variable"
+msgstr ""
+
msgid "CiVariables|Remove variable row"
msgstr ""
@@ -4947,9 +5090,6 @@ msgstr ""
msgid "Clear due date"
msgstr ""
-msgid "Clear input"
-msgstr ""
-
msgid "Clear recent searches"
msgstr ""
@@ -4998,6 +5138,9 @@ msgstr ""
msgid "Client authentication key password"
msgstr ""
+msgid "Client request timeout"
+msgstr ""
+
msgid "Clients"
msgstr ""
@@ -5082,6 +5225,27 @@ msgstr ""
msgid "Cluster type must be specificed for Stages::ClusterEndpointInserter"
msgstr ""
+msgid "ClusterAgents|Configuration"
+msgstr ""
+
+msgid "ClusterAgents|Connect your cluster with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate Kubernetes with a GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Name"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Agent also requires %{linkStart}enabling the Agent Server%{linkEnd}"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Kubernetes Agent allows an Infrastructure as Code, GitOps approach to integrating Kubernetes clusters with GitLab. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "ClusterAgent|This feature is only available for premium plans"
msgstr ""
@@ -5151,10 +5315,10 @@ msgstr ""
msgid "ClusterIntegration|All installed applications and related resources"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster."
+msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{linkStart}More information%{linkEnd}"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{startLink}More information%{endLink}"
+msgid "ClusterIntegration|Allow GitLab to manage namespaces and service accounts for this cluster."
msgstr ""
msgid "ClusterIntegration|Alternatively, "
@@ -5175,6 +5339,9 @@ msgstr ""
msgid "ClusterIntegration|An error occurred while trying to fetch zone machine types: %{error}"
msgstr ""
+msgid "ClusterIntegration|An unknown error occurred while attempting to connect to Kubernetes."
+msgstr ""
+
msgid "ClusterIntegration|Any project namespaces"
msgstr ""
@@ -5190,6 +5357,9 @@ msgstr ""
msgid "ClusterIntegration|Authenticate with Amazon Web Services"
msgstr ""
+msgid "ClusterIntegration|Authentication Error"
+msgstr ""
+
msgid "ClusterIntegration|Base domain"
msgstr ""
@@ -5208,13 +5378,22 @@ msgstr ""
msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}security group %{externalLinkIcon} %{endLink} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
+msgid "ClusterIntegration|Check your CA certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Check your cluster status"
+msgstr ""
+
+msgid "ClusterIntegration|Check your token"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}subnets %{externalLinkIcon} %{endLink} in your VPC where your worker nodes will run."
+msgid "ClusterIntegration|Choose the %{linkStart}security group %{linkEnd} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
msgstr ""
-msgid "ClusterIntegration|Choose the worker node %{startLink}instance type %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Choose the %{linkStart}subnets %{linkEnd} in your VPC where your worker nodes will run."
+msgstr ""
+
+msgid "ClusterIntegration|Choose the worker node %{linkStart}instance type%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Choose which applications to install on your Kubernetes cluster."
@@ -5226,10 +5405,7 @@ msgstr ""
msgid "ClusterIntegration|Clear cluster cache"
msgstr ""
-msgid "ClusterIntegration|Clear the local cache of namespace and service accounts. This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
-msgstr ""
-
-msgid "ClusterIntegration|Cluster being created"
+msgid "ClusterIntegration|Clear the local cache of namespace and service accounts."
msgstr ""
msgid "ClusterIntegration|Cluster management project (alpha)"
@@ -5241,15 +5417,21 @@ msgstr ""
msgid "ClusterIntegration|Cluster_applications artifact too big. Maximum allowable size: %{human_size}"
msgstr ""
-msgid "ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters."
+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|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}"
+msgid "ClusterIntegration|Clusters connected with a certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Connect cluster with certificate"
msgstr ""
msgid "ClusterIntegration|Connect existing cluster"
msgstr ""
+msgid "ClusterIntegration|Connection Error"
+msgstr ""
+
msgid "ClusterIntegration|Copy API URL"
msgstr ""
@@ -5325,6 +5507,12 @@ msgstr ""
msgid "ClusterIntegration|Deletes all GitLab resources attached to this cluster during removal"
msgstr ""
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared."
+msgstr ""
+
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared. %{linkStart}More information%{linkEnd}"
+msgstr ""
+
msgid "ClusterIntegration|Did you know?"
msgstr ""
@@ -5394,6 +5582,9 @@ msgstr ""
msgid "ClusterIntegration|Fluentd is an open source data collector, which lets you unify the data collection and consumption for a better use and understanding of data. It requires at least one of the following logs to be successfully installed."
msgstr ""
+msgid "ClusterIntegration|GitLab Agent managed clusters"
+msgstr ""
+
msgid "ClusterIntegration|GitLab Container Network Policies"
msgstr ""
@@ -5406,6 +5597,12 @@ msgstr ""
msgid "ClusterIntegration|GitLab Runner connects to the repository and executes CI/CD jobs, pushing results back and deploying applications to production."
msgstr ""
+msgid "ClusterIntegration|GitLab failed to authenticate."
+msgstr ""
+
+msgid "ClusterIntegration|GitLab failed to connect to the cluster."
+msgstr ""
+
msgid "ClusterIntegration|GitLab-managed cluster"
msgstr ""
@@ -5427,6 +5624,9 @@ msgstr ""
msgid "ClusterIntegration|Group cluster"
msgstr ""
+msgid "ClusterIntegration|HTTP Error"
+msgstr ""
+
msgid "ClusterIntegration|Helm Tiller"
msgstr ""
@@ -5460,7 +5660,10 @@ msgstr ""
msgid "ClusterIntegration|Instance type"
msgstr ""
-msgid "ClusterIntegration|Integrate Kubernetes cluster automation"
+msgid "ClusterIntegration|Integrate Kubernetes with a cluster certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Integrate with a cluster certificate"
msgstr ""
msgid "ClusterIntegration|Issuer Email"
@@ -5496,9 +5699,6 @@ msgstr ""
msgid "ClusterIntegration|Knative extends Kubernetes to provide a set of middleware components that are essential to build modern, source-centric, and container-based applications that can run anywhere: on premises, in the cloud, or even in a third-party data center."
msgstr ""
-msgid "ClusterIntegration|Kubernetes cluster"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes cluster is being created..."
msgstr ""
@@ -5511,9 +5711,6 @@ msgstr ""
msgid "ClusterIntegration|Kubernetes clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr ""
-msgid "ClusterIntegration|Kubernetes clusters can be used to deploy applications and to provide Review Apps for this project"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes version"
msgstr ""
@@ -5526,7 +5723,7 @@ msgstr ""
msgid "ClusterIntegration|Learn more about %{help_link_start}zones%{help_link_end}."
msgstr ""
-msgid "ClusterIntegration|Learn more about %{startLink}Regions %{externalLinkIcon}%{endLink}."
+msgid "ClusterIntegration|Learn more about %{linkStart}Regions%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Learn more about Kubernetes"
@@ -5571,12 +5768,18 @@ msgstr ""
msgid "ClusterIntegration|Machine type"
msgstr ""
+msgid "ClusterIntegration|Make sure your API endpoint is correct"
+msgstr ""
+
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create Kubernetes clusters"
msgstr ""
msgid "ClusterIntegration|Manage your Kubernetes cluster by visiting %{provider_link}"
msgstr ""
+msgid "ClusterIntegration|Namespace per environment"
+msgstr ""
+
msgid "ClusterIntegration|No IAM Roles found"
msgstr ""
@@ -5622,6 +5825,9 @@ msgstr ""
msgid "ClusterIntegration|No zones matched your search"
msgstr ""
+msgid "ClusterIntegration|Node calculations use the Kubernetes Metrics API. Make sure your cluster has metrics installed"
+msgstr ""
+
msgid "ClusterIntegration|Number of nodes"
msgstr ""
@@ -5664,6 +5870,9 @@ msgstr ""
msgid "ClusterIntegration|RBAC-enabled cluster"
msgstr ""
+msgid "ClusterIntegration|Read our %{linkStart}help page%{linkEnd} on Kubernetes cluster integration."
+msgstr ""
+
msgid "ClusterIntegration|Read our %{link_start}help page%{link_end} on Kubernetes cluster integration."
msgstr ""
@@ -5766,7 +5975,7 @@ msgstr ""
msgid "ClusterIntegration|Select a VPC to choose a subnet"
msgstr ""
-msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{linkStart}Amazon Web Services %{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select a network to choose a subnetwork"
@@ -5799,7 +6008,7 @@ msgstr ""
msgid "ClusterIntegration|Select project to choose zone"
msgstr ""
-msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select zone"
@@ -5889,9 +6098,18 @@ msgstr ""
msgid "ClusterIntegration|There was a problem authenticating with your cluster. Please ensure your CA Certificate and Token are valid."
msgstr ""
+msgid "ClusterIntegration|There was an HTTP error when connecting to your cluster."
+msgstr ""
+
msgid "ClusterIntegration|This account must have permissions to create a Kubernetes cluster in the %{link_to_container_project} specified below"
msgstr ""
+msgid "ClusterIntegration|This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
+msgstr ""
+
+msgid "ClusterIntegration|This is necessary to clear existing environment-namespace associations from clusters previously managed by GitLab."
+msgstr ""
+
msgid "ClusterIntegration|This option will allow you to install applications on RBAC clusters."
msgstr ""
@@ -5916,9 +6134,21 @@ msgstr ""
msgid "ClusterIntegration|To use a new project, first create one on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}."
msgstr ""
+msgid "ClusterIntegration|Troubleshooting tips:"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Authenticate"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Connect"
+msgstr ""
+
msgid "ClusterIntegration|Uninstall %{appTitle}"
msgstr ""
+msgid "ClusterIntegration|Unknown Error"
+msgstr ""
+
msgid "ClusterIntegration|Update %{appTitle}"
msgstr ""
@@ -5979,7 +6209,7 @@ msgstr ""
msgid "ClusterIntegration|Your cluster API is unreachable. Please ensure your API URL is correct."
msgstr ""
-msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Zone"
@@ -6099,6 +6329,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse all threads"
+msgstr ""
+
msgid "Collapse approvers"
msgstr ""
@@ -6247,7 +6480,7 @@ msgstr ""
msgid "Commit…"
msgstr ""
-msgid "Company"
+msgid "Community forum"
msgstr ""
msgid "Company name"
@@ -6256,6 +6489,9 @@ msgstr ""
msgid "Compare"
msgstr ""
+msgid "Compare %{oldCommitId}...%{newCommitId}"
+msgstr ""
+
msgid "Compare Git revisions"
msgstr ""
@@ -6271,6 +6507,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare submodule commit revisions"
+msgstr ""
+
msgid "Compare with previous version"
msgstr ""
@@ -6406,6 +6645,9 @@ msgstr ""
msgid "Configure the way a user creates a new account."
msgstr ""
+msgid "Configure which lists are shown for anyone who visits this board"
+msgstr ""
+
msgid "Confirm"
msgstr ""
@@ -6628,6 +6870,9 @@ msgstr[0] ""
msgid "ContainerRegistry|Set cleanup policy"
msgstr ""
+msgid "ContainerRegistry|Some tags were not deleted"
+msgstr ""
+
msgid "ContainerRegistry|Something went wrong while fetching the cleanup policy."
msgstr ""
@@ -6667,6 +6912,9 @@ msgstr ""
msgid "ContainerRegistry|Tags with names matching this regex pattern will %{italicStart}expire:%{italicEnd}"
msgstr ""
+msgid "ContainerRegistry|The cleanup policy timed out before it could delete all tags. An administrator can %{adminLinkStart}manually run cleanup now%{adminLinkEnd} or you can wait for the cleanup policy to automatically run again. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "ContainerRegistry|The last tag related to this image was recently removed. This empty image and any associated data will be automatically removed as part of the regular Garbage Collection process. If you have any questions, contact your administrator."
msgstr ""
@@ -6799,6 +7047,9 @@ msgstr ""
msgid "Contributions per group member"
msgstr ""
+msgid "Contributor"
+msgstr ""
+
msgid "Contributors"
msgstr ""
@@ -6928,6 +7179,9 @@ msgstr ""
msgid "Could not change HEAD: branch '%{branch}' does not exist"
msgstr ""
+msgid "Could not commit. An unexpected error occurred."
+msgstr ""
+
msgid "Could not connect to FogBugz, check your URL"
msgstr ""
@@ -6967,6 +7221,9 @@ msgstr ""
msgid "Could not find iteration"
msgstr ""
+msgid "Could not load instance counts. Please refresh the page to try again."
+msgstr ""
+
msgid "Could not remove the trigger."
msgstr ""
@@ -6991,10 +7248,10 @@ msgstr ""
msgid "Could not save prometheus manual configuration"
msgstr ""
-msgid "Could not udpdate wiki page"
+msgid "Could not update the LDAP settings"
msgstr ""
-msgid "Could not update the LDAP settings"
+msgid "Could not update wiki page"
msgstr ""
msgid "Could not upload your designs as one or more files uploaded are not supported."
@@ -7650,6 +7907,9 @@ msgstr ""
msgid "DastProfiles|Are you sure you want to delete this profile?"
msgstr ""
+msgid "DastProfiles|Could not create site validation token. Please refresh the page, or try again later."
+msgstr ""
+
msgid "DastProfiles|Could not create the scanner profile. Please try again."
msgstr ""
@@ -7674,6 +7934,12 @@ msgstr ""
msgid "DastProfiles|Could not fetch site profiles. Please refresh the page, or try again later."
msgstr ""
+msgid "DastProfiles|Could not retrieve site validation status. Please refresh the page, or try again later."
+msgstr ""
+
+msgid "DastProfiles|Could not update the scanner profile. Please try again."
+msgstr ""
+
msgid "DastProfiles|Could not update the site profile. Please try again."
msgstr ""
@@ -7689,7 +7955,7 @@ msgstr ""
msgid "DastProfiles|Download validation text file"
msgstr ""
-msgid "DastProfiles|Edit feature will come soon. Please create a new profile if changes needed"
+msgid "DastProfiles|Edit scanner profile"
msgstr ""
msgid "DastProfiles|Edit site profile"
@@ -7722,6 +7988,9 @@ msgstr ""
msgid "DastProfiles|No profiles created yet"
msgstr ""
+msgid "DastProfiles|Passive"
+msgstr ""
+
msgid "DastProfiles|Please enter a valid URL format, ex: http://www.example.com/home"
msgstr ""
@@ -7737,6 +8006,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan mode"
+msgstr ""
+
msgid "DastProfiles|Scanner Profile"
msgstr ""
@@ -7776,10 +8048,10 @@ msgstr ""
msgid "DastProfiles|Text file validation"
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
+msgid "DastProfiles|The maximum number of minutes allowed for the spider to traverse the site."
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the spider to traverse the site."
+msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
msgstr ""
msgid "DastProfiles|Validate"
@@ -7812,6 +8084,9 @@ msgstr ""
msgid "Date picker"
msgstr ""
+msgid "Date range"
+msgstr ""
+
msgid "Date range cannot exceed %{maxDateRange} days."
msgstr ""
@@ -7836,6 +8111,9 @@ msgstr ""
msgid "Days to merge"
msgstr ""
+msgid "Dear Administrator,"
+msgstr ""
+
msgid "Debug"
msgstr ""
@@ -7947,12 +8225,18 @@ msgstr ""
msgid "Delete"
msgstr ""
+msgid "Delete %{name}"
+msgstr ""
+
msgid "Delete Comment"
msgstr ""
msgid "Delete Snippet"
msgstr ""
+msgid "Delete Value Stream"
+msgstr ""
+
msgid "Delete account"
msgstr ""
@@ -7974,9 +8258,6 @@ msgstr ""
msgid "Delete label: %{label_name} ?"
msgstr ""
-msgid "Delete license"
-msgstr ""
-
msgid "Delete list"
msgstr ""
@@ -8052,15 +8333,6 @@ msgstr ""
msgid "Deleting a project places it into a read-only state until %{date}, at which point the project will be permanently deleted. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "Deleting the license failed."
-msgstr ""
-
-msgid "Deleting the license failed. The license was not found."
-msgstr ""
-
-msgid "Deleting the license failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "Deleting the project will delete its repository and all related resources including issues, merge requests etc."
msgstr ""
@@ -8550,7 +8822,10 @@ msgstr ""
msgid "DesignManagement|The maximum number of designs allowed to be uploaded is %{upload_limit}. Please try again."
msgstr ""
-msgid "DesignManagement|To upload designs, you'll need to enable LFS. %{requirements_link_start}More information%{requirements_link_end}"
+msgid "DesignManagement|There was an error moving your designs. Please upload your designs below."
+msgstr ""
+
+msgid "DesignManagement|To upload designs, you'll need to enable LFS and have admin enable hashed storage. %{requirements_link_start}More information%{requirements_link_end}"
msgstr ""
msgid "DesignManagement|Unresolve thread"
@@ -8562,6 +8837,9 @@ msgstr ""
msgid "DesignManagement|Upload skipped."
msgstr ""
+msgid "DesignManagement|Your designs are being copied and are on their way… Please refresh to update."
+msgstr ""
+
msgid "DesignManagement|and %{moreCount} more."
msgstr ""
@@ -8619,6 +8897,9 @@ msgstr ""
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
+msgid "Direct member"
+msgstr ""
+
msgid "Direction"
msgstr ""
@@ -8667,9 +8948,6 @@ msgstr ""
msgid "Discard draft"
msgstr ""
-msgid "Discard review"
-msgstr ""
-
msgid "DiscordService|Discord Notifications"
msgstr ""
@@ -8737,10 +9015,10 @@ msgstr ""
msgid "Dismiss Merge Request promotion"
msgstr ""
-msgid "Dismiss Selected"
+msgid "Dismiss Value Stream Analytics introduction box"
msgstr ""
-msgid "Dismiss Value Stream Analytics introduction box"
+msgid "Dismiss selected"
msgstr ""
msgid "Dismiss trial promotion"
@@ -8791,9 +9069,6 @@ msgstr ""
msgid "Documents reindexed: %{processed_documents} (%{percentage}%%)"
msgstr ""
-msgid "Doing"
-msgstr ""
-
msgid "Domain"
msgstr ""
@@ -8989,9 +9264,6 @@ msgstr ""
msgid "Edit environment"
msgstr ""
-msgid "Edit file"
-msgstr ""
-
msgid "Edit files in the editor and commit changes here"
msgstr ""
@@ -9004,6 +9276,12 @@ msgstr ""
msgid "Edit identity for %{user_name}"
msgstr ""
+msgid "Edit in Web IDE"
+msgstr ""
+
+msgid "Edit in single-file editor"
+msgstr ""
+
msgid "Edit issues"
msgstr ""
@@ -9031,10 +9309,10 @@ msgstr ""
msgid "Editing"
msgstr ""
-msgid "Elasticsearch"
+msgid "Elasticsearch AWS IAM credentials"
msgstr ""
-msgid "Elasticsearch AWS IAM credentials"
+msgid "Elasticsearch HTTP client timeout value in seconds."
msgstr ""
msgid "Elasticsearch indexing restrictions"
@@ -9043,9 +9321,6 @@ msgstr ""
msgid "Elasticsearch indexing started"
msgstr ""
-msgid "Elasticsearch integration. Elasticsearch AWS IAM."
-msgstr ""
-
msgid "Elasticsearch reindexing is already in progress"
msgstr ""
@@ -9073,9 +9348,6 @@ msgstr ""
msgid "Email Notification"
msgstr ""
-msgid "Email address"
-msgstr ""
-
msgid "Email could not be sent"
msgstr ""
@@ -9139,6 +9411,9 @@ msgstr ""
msgid "Emails sent from Service Desk will have this name"
msgstr ""
+msgid "Emails sent to %{email} will still be supported"
+msgstr ""
+
msgid "Emails separated by comma"
msgstr ""
@@ -9172,9 +9447,18 @@ msgstr ""
msgid "Enable"
msgstr ""
+msgid "Enable %{link_start}Gitpod%{link_end} integration to launch a development environment in your browser directly from GitLab."
+msgstr ""
+
msgid "Enable Auto DevOps"
msgstr ""
+msgid "Enable Gitpod"
+msgstr ""
+
+msgid "Enable Gitpod?"
+msgstr ""
+
msgid "Enable HTML emails"
msgstr ""
@@ -9304,9 +9588,6 @@ msgstr ""
msgid "Encountered an error while rendering: %{err}"
msgstr ""
-msgid "End date"
-msgstr ""
-
msgid "Ends at (UTC)"
msgstr ""
@@ -9466,7 +9747,7 @@ msgstr ""
msgid "EnvironmentsDashboard|The environments dashboard provides a summary of each project's environments' status, including pipeline and alert statuses."
msgstr ""
-msgid "EnvironmentsDashboard|This dashboard displays a maximum of 7 projects and 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
+msgid "EnvironmentsDashboard|This dashboard displays 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
msgstr ""
msgid "Environments|An error occurred while canceling the auto stop, please try again"
@@ -9787,6 +10068,9 @@ msgstr ""
msgid "Error deleting project. Check logs for error details."
msgstr ""
+msgid "Error fetching burnup chart data"
+msgstr ""
+
msgid "Error fetching diverging counts for branches. Please try again."
msgstr ""
@@ -9865,6 +10149,9 @@ msgstr ""
msgid "Error occurred when saving assignees"
msgstr ""
+msgid "Error occurred when saving reviewers"
+msgstr ""
+
msgid "Error occurred when toggling the notification subscription"
msgstr ""
@@ -10117,10 +10404,13 @@ msgstr ""
msgid "Expand all"
msgstr ""
-msgid "Expand approvers"
+msgid "Expand all files"
msgstr ""
-msgid "Expand dropdown"
+msgid "Expand all threads"
+msgstr ""
+
+msgid "Expand approvers"
msgstr ""
msgid "Expand milestones"
@@ -10291,6 +10581,9 @@ msgstr ""
msgid "Failed to create Merge Request. Please try again."
msgstr ""
+msgid "Failed to create To-Do for the design."
+msgstr ""
+
msgid "Failed to create a branch for this issue. Please try again."
msgstr ""
@@ -10330,6 +10623,12 @@ msgstr ""
msgid "Failed to load authors. Please try again."
msgstr ""
+msgid "Failed to load branches. Please try again."
+msgstr ""
+
+msgid "Failed to load deploy keys."
+msgstr ""
+
msgid "Failed to load emoji list."
msgstr ""
@@ -10345,6 +10644,9 @@ msgstr ""
msgid "Failed to load groups & users."
msgstr ""
+msgid "Failed to load groups, users and deploy keys."
+msgstr ""
+
msgid "Failed to load labels. Please try again."
msgstr ""
@@ -10354,6 +10656,12 @@ msgstr ""
msgid "Failed to load related branches"
msgstr ""
+msgid "Failed to load sidebar confidential toggle"
+msgstr ""
+
+msgid "Failed to load sidebar lock status"
+msgstr ""
+
msgid "Failed to load stacktrace."
msgstr ""
@@ -10381,6 +10689,9 @@ msgstr ""
msgid "Failed to publish issue on status page."
msgstr ""
+msgid "Failed to remove To-Do for the design."
+msgstr ""
+
msgid "Failed to remove a Zoom meeting"
msgstr ""
@@ -10423,6 +10734,9 @@ msgstr ""
msgid "Failed to signing using smartcard authentication"
msgstr ""
+msgid "Failed to toggle To-Do for the design."
+msgstr ""
+
msgid "Failed to update branch!"
msgstr ""
@@ -10535,7 +10849,7 @@ msgstr ""
msgid "FeatureFlags|Edit User List"
msgstr ""
-msgid "FeatureFlags|Enable features for specific users and specific environments by defining feature flag strategies."
+msgid "FeatureFlags|Enable features for specific users and environments by configuring feature flag strategies."
msgstr ""
msgid "FeatureFlags|Environment Spec"
@@ -10595,7 +10909,7 @@ msgstr ""
msgid "FeatureFlags|Include additional user IDs"
msgstr ""
-msgid "FeatureFlags|Install a %{docs_link_anchored_start}compatible client library%{docs_link_anchored_end} and specify the API URL, application name, and instance ID during the configuration setup. %{docs_link_start}More Information%{docs_link_end}"
+msgid "FeatureFlags|Install a %{docsLinkAnchoredStart}compatible client library%{docsLinkAnchoredEnd} and specify the API URL, application name, and instance ID during the configuration setup. %{docsLinkStart}More Information%{docsLinkEnd}"
msgstr ""
msgid "FeatureFlags|Instance ID"
@@ -10607,6 +10921,9 @@ msgstr ""
msgid "FeatureFlags|Loading feature flags"
msgstr ""
+msgid "FeatureFlags|Loading user lists"
+msgstr ""
+
msgid "FeatureFlags|More information"
msgstr ""
@@ -10625,7 +10942,7 @@ msgstr ""
msgid "FeatureFlags|New feature flag"
msgstr ""
-msgid "FeatureFlags|New list"
+msgid "FeatureFlags|New user list"
msgstr ""
msgid "FeatureFlags|Percent of users"
@@ -10664,6 +10981,9 @@ msgstr ""
msgid "FeatureFlags|There was an error fetching the feature flags."
msgstr ""
+msgid "FeatureFlags|There was an error fetching the user lists."
+msgstr ""
+
msgid "FeatureFlags|There was an error retrieving user lists"
msgstr ""
@@ -10679,6 +10999,9 @@ msgstr ""
msgid "FeatureFlags|User List"
msgstr ""
+msgid "FeatureFlags|User Lists"
+msgstr ""
+
msgid "FeatureFlag|List"
msgstr ""
@@ -10706,15 +11029,6 @@ msgstr ""
msgid "Fetching incoming email"
msgstr ""
-msgid "Fetching licenses failed."
-msgstr ""
-
-msgid "Fetching licenses failed. The request endpoint was not found."
-msgstr ""
-
-msgid "Fetching licenses failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "File"
msgstr ""
@@ -10817,12 +11131,21 @@ msgstr ""
msgid "Filter by status"
msgstr ""
+msgid "Filter by test cases that are currently archived."
+msgstr ""
+
+msgid "Filter by test cases that are currently opened."
+msgstr ""
+
msgid "Filter by two-factor authentication"
msgstr ""
msgid "Filter by user"
msgstr ""
+msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
+msgstr ""
+
msgid "Filter pipelines"
msgstr ""
@@ -10838,7 +11161,7 @@ msgstr ""
msgid "Filter results..."
msgstr ""
-msgid "Filter your projects by name"
+msgid "Filter your repositories by name"
msgstr ""
msgid "Filter..."
@@ -10847,7 +11170,7 @@ msgstr ""
msgid "Find File"
msgstr ""
-msgid "Find bugs in your code with coverage-guided fuzzing"
+msgid "Find bugs in your code with coverage-guided fuzzing."
msgstr ""
msgid "Find by path"
@@ -10874,9 +11197,6 @@ msgstr ""
msgid "Finish editing this message first!"
msgstr ""
-msgid "Finish review"
-msgstr ""
-
msgid "Finish setting up your dedicated account for %{group_name}."
msgstr ""
@@ -10946,6 +11266,9 @@ msgstr ""
msgid "Footer message"
msgstr ""
+msgid "For a faster browsing experience, some files are collapsed by default."
+msgstr ""
+
msgid "For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
@@ -10955,6 +11278,9 @@ msgstr ""
msgid "For more info, read the documentation."
msgstr ""
+msgid "For more information on how the number of active users is calculated, see the %{self_managed_subscriptions_doc_link} documentation."
+msgstr ""
+
msgid "For more information, go to the "
msgstr ""
@@ -11093,6 +11419,9 @@ msgstr ""
msgid "Generate new token"
msgstr ""
+msgid "Generic package file size in bytes"
+msgstr ""
+
msgid "Geo"
msgstr ""
@@ -11354,6 +11683,9 @@ msgstr ""
msgid "Geo|Please refer to Geo Troubleshooting."
msgstr ""
+msgid "Geo|Primary node"
+msgstr ""
+
msgid "Geo|Project"
msgstr ""
@@ -11396,6 +11728,9 @@ msgstr ""
msgid "Geo|Review replication status, and resynchronize and reverify items with the primary node."
msgstr ""
+msgid "Geo|Secondary node"
+msgstr ""
+
msgid "Geo|Status"
msgstr ""
@@ -11435,6 +11770,9 @@ msgstr ""
msgid "Geo|URL must be a valid url (ex: https://gitlab.com)"
msgstr ""
+msgid "Geo|Undefined"
+msgstr ""
+
msgid "Geo|Unknown state"
msgstr ""
@@ -11510,10 +11848,16 @@ msgstr ""
msgid "GitHub import"
msgstr ""
+msgid "GitLab"
+msgstr ""
+
msgid "GitLab / Unsubscribe"
msgstr ""
-msgid "GitLab Enterprise Edition %{plan}"
+msgid "GitLab API"
+msgstr ""
+
+msgid "GitLab Billing Team."
msgstr ""
msgid "GitLab Group Runners can execute code for all the projects in this group."
@@ -11525,12 +11869,18 @@ msgstr ""
msgid "GitLab Issue"
msgstr ""
+msgid "GitLab Pages"
+msgstr ""
+
msgid "GitLab Service Desk is a simple way to allow people to create issues in your GitLab instance without needing their own user account. It provides a unique email address for end users to create issues in a project, and replies can be sent either through the GitLab interface or by email. End users will only see the thread through email."
msgstr ""
msgid "GitLab Shared Runners execute code of different projects on the same Runner unless you configure GitLab Runner Autoscale with MaxBuilds 1 (which it is on GitLab.com)."
msgstr ""
+msgid "GitLab Shell"
+msgstr ""
+
msgid "GitLab Support Bot"
msgstr ""
@@ -11540,7 +11890,7 @@ msgstr ""
msgid "GitLab User"
msgstr ""
-msgid "GitLab allows you to continue using your license even if you exceed the number of seats you purchased. You will be required to pay for these seats when you renew your license."
+msgid "GitLab Workhorse"
msgstr ""
msgid "GitLab commit"
@@ -11708,6 +12058,21 @@ msgstr ""
msgid "Gitlab Pages"
msgstr ""
+msgid "Gitpod"
+msgstr ""
+
+msgid "Gitpod|Add the URL to your Gitpod instance configured to read your GitLab projects."
+msgstr ""
+
+msgid "Gitpod|Enable Gitpod integration"
+msgstr ""
+
+msgid "Gitpod|Gitpod URL"
+msgstr ""
+
+msgid "Gitpod|e.g. https://gitpod.example.com"
+msgstr ""
+
msgid "Given access %{time_ago}"
msgstr ""
@@ -12215,9 +12580,6 @@ msgstr ""
msgid "GroupSAML|Valid SAML Response"
msgstr ""
-msgid "GroupSAML|With group managed accounts enabled, all the users without a group managed account will be excluded from the group."
-msgstr ""
-
msgid "GroupSAML|With prohibit outer forks flag enabled group members will be able to fork project only inside your group."
msgstr ""
@@ -12431,10 +12793,10 @@ msgstr ""
msgid "GroupsNew|Create group"
msgstr ""
-msgid "GroupsNew|GitLab group export"
+msgid "GroupsNew|Import"
msgstr ""
-msgid "GroupsNew|Import"
+msgid "GroupsNew|Import a GitLab group export file"
msgstr ""
msgid "GroupsNew|Import group"
@@ -12576,6 +12938,9 @@ msgid "Hide chart"
msgid_plural "Hide charts"
msgstr[0] ""
+msgid "Hide comments on this file"
+msgstr ""
+
msgid "Hide details"
msgstr ""
@@ -12619,6 +12984,15 @@ msgstr ""
msgid "Highest role:"
msgstr ""
+msgid "HighlightBar|Alert events:"
+msgstr ""
+
+msgid "HighlightBar|Alert start time:"
+msgstr ""
+
+msgid "HighlightBar|Original alert:"
+msgstr ""
+
msgid "History"
msgstr ""
@@ -12796,6 +13170,9 @@ msgstr ""
msgid "If enabled, access to projects will be validated on an external service using their classification label."
msgstr ""
+msgid "If the number of active users exceeds the user limit, you will be charged for the number of %{users_over_license_link} at your next license reconciliation."
+msgstr ""
+
msgid "If there is no previous license or if the previous license has expired, some GitLab functionality will be blocked until a new, valid license is uploaded."
msgstr ""
@@ -12835,9 +13212,6 @@ msgstr ""
msgid "If your HTTP repository is not publicly accessible, add your credentials."
msgstr ""
-msgid "Iglu registry URL (optional)"
-msgstr ""
-
msgid "Ignore"
msgstr ""
@@ -12874,6 +13248,14 @@ msgstr ""
msgid "Import"
msgstr ""
+msgid "Import %d compatible repository"
+msgid_plural "Import %d compatible repositories"
+msgstr[0] ""
+
+msgid "Import %d repository"
+msgid_plural "Import %d repositories"
+msgstr[0] ""
+
msgid "Import CSV"
msgstr ""
@@ -12883,15 +13265,9 @@ msgstr ""
msgid "Import all compatible projects"
msgstr ""
-msgid "Import all compatible repositories"
-msgstr ""
-
msgid "Import all projects"
msgstr ""
-msgid "Import all repositories"
-msgstr ""
-
msgid "Import an exported GitLab project"
msgstr ""
@@ -12979,6 +13355,9 @@ msgstr ""
msgid "ImportProjects|Error importing repository %{project_safe_import_url} into %{project_full_path} - %{message}"
msgstr ""
+msgid "ImportProjects|Import repositories"
+msgstr ""
+
msgid "ImportProjects|Importing the project failed"
msgstr ""
@@ -12991,7 +13370,7 @@ msgstr ""
msgid "ImportProjects|Requesting your %{provider} repositories failed"
msgstr ""
-msgid "ImportProjects|Select the projects you want to import"
+msgid "ImportProjects|Select the repositories you want to import"
msgstr ""
msgid "ImportProjects|The remote data could not be imported."
@@ -13027,9 +13406,6 @@ msgstr ""
msgid "In order to enable Service Desk for your instance, you must first set up incoming email."
msgstr ""
-msgid "In order to gather accurate feature usage data, it can take 1 to 2 weeks to see your index."
-msgstr ""
-
msgid "In order to personalize your experience with GitLab%{br_tag}we would like to know a bit more about you."
msgstr ""
@@ -13060,18 +13436,30 @@ msgstr ""
msgid "IncidentManagement|Create incident"
msgstr ""
+msgid "IncidentManagement|Critical - S1"
+msgstr ""
+
msgid "IncidentManagement|Date created"
msgstr ""
msgid "IncidentManagement|Display your incidents in a dedicated view"
msgstr ""
+msgid "IncidentManagement|High - S2"
+msgstr ""
+
msgid "IncidentManagement|Incident"
msgstr ""
msgid "IncidentManagement|Incidents"
msgstr ""
+msgid "IncidentManagement|Low - S4"
+msgstr ""
+
+msgid "IncidentManagement|Medium - S3"
+msgstr ""
+
msgid "IncidentManagement|No incidents to display."
msgstr ""
@@ -13084,6 +13472,9 @@ msgstr ""
msgid "IncidentManagement|Published to status page"
msgstr ""
+msgid "IncidentManagement|Severity"
+msgstr ""
+
msgid "IncidentManagement|There are no closed incidents"
msgstr ""
@@ -13093,6 +13484,9 @@ msgstr ""
msgid "IncidentManagement|Unassigned"
msgstr ""
+msgid "IncidentManagement|Unknown"
+msgstr ""
+
msgid "IncidentManagement|Unpublished"
msgstr ""
@@ -13114,6 +13508,15 @@ msgstr ""
msgid "Incidents"
msgstr ""
+msgid "Incident|Alert details"
+msgstr ""
+
+msgid "Incident|Summary"
+msgstr ""
+
+msgid "Incident|There was an issue loading alert data. Please try again."
+msgstr ""
+
msgid "Include a Terms of Service agreement and Privacy Policy that all users must accept."
msgstr ""
@@ -13174,6 +13577,9 @@ msgstr ""
msgid "Information about additional Pages templates and how to install them can be found in our %{pages_getting_started_guide}."
msgstr ""
+msgid "Inherited"
+msgstr ""
+
msgid "Inherited:"
msgstr ""
@@ -13253,7 +13659,22 @@ msgstr ""
msgid "Instance administrators group already exists"
msgstr ""
-msgid "Instance license"
+msgid "InstanceStatistics|Groups"
+msgstr ""
+
+msgid "InstanceStatistics|Issues"
+msgstr ""
+
+msgid "InstanceStatistics|Merge Requests"
+msgstr ""
+
+msgid "InstanceStatistics|Pipelines"
+msgstr ""
+
+msgid "InstanceStatistics|Projects"
+msgstr ""
+
+msgid "InstanceStatistics|Users"
msgstr ""
msgid "Integration"
@@ -13265,6 +13686,12 @@ msgstr ""
msgid "Integrations"
msgstr ""
+msgid "Integrations|%{integration} settings saved and active."
+msgstr ""
+
+msgid "Integrations|%{integration} settings saved, but not active."
+msgstr ""
+
msgid "Integrations|All details"
msgstr ""
@@ -13274,6 +13701,12 @@ msgstr ""
msgid "Integrations|Comment settings:"
msgstr ""
+msgid "Integrations|Connection failed. Please check your settings."
+msgstr ""
+
+msgid "Integrations|Connection successful."
+msgstr ""
+
msgid "Integrations|Default settings are inherited from the group level."
msgstr ""
@@ -13289,6 +13722,15 @@ msgstr ""
msgid "Integrations|Includes commit title and branch"
msgstr ""
+msgid "Integrations|Projects using custom settings will not be impacted unless the project owner chooses to use instance-level defaults."
+msgstr ""
+
+msgid "Integrations|Save settings?"
+msgstr ""
+
+msgid "Integrations|Saving will update the default settings for all projects that are not using custom settings."
+msgstr ""
+
msgid "Integrations|Standard"
msgstr ""
@@ -13421,6 +13863,9 @@ msgstr ""
msgid "Invitation"
msgstr ""
+msgid "Invitation declined"
+msgstr ""
+
msgid "Invite"
msgstr ""
@@ -13472,6 +13917,42 @@ 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|%{linkStart}Read more%{linkEnd} about role permissions"
+msgstr ""
+
+msgid "InviteMembersModal|Access expiration date (optional)"
+msgstr ""
+
+msgid "InviteMembersModal|Cancel"
+msgstr ""
+
+msgid "InviteMembersModal|Choose a role permission"
+msgstr ""
+
+msgid "InviteMembersModal|GitLab member or Email address"
+msgstr ""
+
+msgid "InviteMembersModal|Invite"
+msgstr ""
+
+msgid "InviteMembersModal|Invite team members"
+msgstr ""
+
+msgid "InviteMembersModal|Search for members to invite"
+msgstr ""
+
+msgid "InviteMembersModal|User not invited. Feature coming soon!"
+msgstr ""
+
+msgid "InviteMembersModal|Users were succesfully added"
+msgstr ""
+
+msgid "InviteMembersModal|You're inviting members to the %{group_name} group"
+msgstr ""
+
+msgid "InviteMembers|Invite team members"
+msgstr ""
+
msgid "Invited"
msgstr ""
@@ -13526,10 +14007,13 @@ msgstr ""
msgid "Issue cannot be found."
msgstr ""
+msgid "Issue created from vulnerability %{vulnerability_link}"
+msgstr ""
+
msgid "Issue events"
msgstr ""
-msgid "Issue first depoloyed to production"
+msgid "Issue first deployed to production"
msgstr ""
msgid "Issue label"
@@ -13607,6 +14091,9 @@ msgstr ""
msgid "IssueTracker|Custom issue tracker"
msgstr ""
+msgid "IssueTracker|EWM work items tracker"
+msgstr ""
+
msgid "IssueTracker|Redmine issue tracker"
msgstr ""
@@ -13673,6 +14160,9 @@ msgstr ""
msgid "It looks like you have some draft commits in this branch."
msgstr ""
+msgid "It may be several days before you see feature usage data."
+msgstr ""
+
msgid "It must have a header row and at least two columns: the first column is the issue title and the second column is the issue description. The separator is automatically detected."
msgstr ""
@@ -13955,13 +14445,13 @@ msgstr ""
msgid "Join Zoom meeting"
msgstr ""
-msgid "Jul"
+msgid "Joined %{time_ago}"
msgstr ""
-msgid "July"
+msgid "Jul"
msgstr ""
-msgid "Jump to first unresolved thread"
+msgid "July"
msgstr ""
msgid "Jump to next unresolved thread"
@@ -13997,6 +14487,9 @@ msgstr ""
msgid "Keyboard shortcuts"
msgstr ""
+msgid "KeyboardKey|Ctrl+"
+msgstr ""
+
msgid "Keys"
msgstr ""
@@ -14045,6 +14538,9 @@ msgstr ""
msgid "LDAP Synchronization"
msgstr ""
+msgid "LDAP group settings"
+msgstr ""
+
msgid "LDAP settings"
msgstr ""
@@ -14054,6 +14550,9 @@ msgstr ""
msgid "LDAP sync in progress. This could take a few minutes. Refresh the page to see the changes."
msgstr ""
+msgid "LDAP synchronizations"
+msgstr ""
+
msgid "LFS"
msgstr ""
@@ -14133,7 +14632,16 @@ msgid "Last %d day"
msgid_plural "Last %d days"
msgstr[0] ""
-msgid "Last %{days} days"
+msgid "Last 2 weeks"
+msgstr ""
+
+msgid "Last 30 days"
+msgstr ""
+
+msgid "Last 60 days"
+msgstr ""
+
+msgid "Last 90 days"
msgstr ""
msgid "Last Accessed On"
@@ -14211,6 +14719,9 @@ msgstr ""
msgid "Last used on:"
msgstr ""
+msgid "Last week"
+msgstr ""
+
msgid "LastCommit|authored"
msgstr ""
@@ -14226,6 +14737,9 @@ msgstr ""
msgid "Latest pipeline for the most recent commit on this branch"
msgstr ""
+msgid "Launch a ready-to-code development environment for your project."
+msgstr ""
+
msgid "Lead"
msgstr ""
@@ -14599,6 +15113,9 @@ msgstr ""
msgid "List of all merge commits"
msgstr ""
+msgid "List options"
+msgstr ""
+
msgid "List settings"
msgstr ""
@@ -14611,9 +15128,6 @@ msgstr ""
msgid "List your Bitbucket Server repositories"
msgstr ""
-msgid "Lists"
-msgstr ""
-
msgid "Live preview"
msgstr ""
@@ -14860,6 +15374,12 @@ msgstr ""
msgid "Mark as done"
msgstr ""
+msgid "Mark as draft"
+msgstr ""
+
+msgid "Mark as ready"
+msgstr ""
+
msgid "Mark as resolved"
msgstr ""
@@ -14881,6 +15401,24 @@ msgstr ""
msgid "Markdown is supported"
msgstr ""
+msgid "MarkdownEditor|Add a link (%{modifierKey}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add a link (%{modifier_key}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifierKey}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifier_key}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifierKey}I)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifier_key}I)"
+msgstr ""
+
msgid "Marked For Deletion At - %{deletion_time}"
msgstr ""
@@ -14965,7 +15503,25 @@ msgstr ""
msgid "Max access level"
msgstr ""
-msgid "Max seats used"
+msgid "Max role"
+msgstr ""
+
+msgid "Max size 15 MB"
+msgstr ""
+
+msgid "Maximum Conan package file size in bytes"
+msgstr ""
+
+msgid "Maximum Maven package file size in bytes"
+msgstr ""
+
+msgid "Maximum NPM package file size in bytes"
+msgstr ""
+
+msgid "Maximum NuGet package file size in bytes"
+msgstr ""
+
+msgid "Maximum PyPI package file size in bytes"
msgstr ""
msgid "Maximum Users:"
@@ -15097,6 +15653,18 @@ msgstr ""
msgid "Members with access to %{strong_start}%{group_name}%{strong_end}"
msgstr ""
+msgid "Members|%{time} by %{user}"
+msgstr ""
+
+msgid "Members|Expired"
+msgstr ""
+
+msgid "Members|No expiration set"
+msgstr ""
+
+msgid "Members|in %{time}"
+msgstr ""
+
msgid "Memory Usage"
msgstr ""
@@ -15283,9 +15851,6 @@ msgstr ""
msgid "MergeRequests|Thread will be unresolved"
msgstr ""
-msgid "MergeRequests|Toggle comments for this file"
-msgstr ""
-
msgid "MergeRequests|View file @ %{commitId}"
msgstr ""
@@ -15346,6 +15911,9 @@ msgstr ""
msgid "Merging immediately isn't recommended as it may negatively impact the existing merge train. Read the %{docsLinkStart}documentation%{docsLinkEnd} for more information."
msgstr ""
+msgid "Message"
+msgstr ""
+
msgid "Messages"
msgstr ""
@@ -15729,18 +16297,12 @@ msgid "Milestone"
msgid_plural "Milestones"
msgstr[0] ""
-msgid "Milestone does not support burnup charts"
-msgstr ""
-
msgid "Milestone lists not available with your current license"
msgstr ""
msgid "Milestone lists show all issues from the selected milestone."
msgstr ""
-msgid "Milestone must have a start and due date"
-msgstr ""
-
msgid "MilestoneSidebar|Closed:"
msgstr ""
@@ -16107,6 +16669,9 @@ msgstr ""
msgid "Namespace"
msgstr ""
+msgid "Namespace ID:"
+msgstr ""
+
msgid "Namespace is empty"
msgstr ""
@@ -16191,6 +16756,9 @@ msgstr ""
msgid "NetworkPolicies|Allow all outbound traffic from %{selector} to %{ruleSelector} on %{ports}"
msgstr ""
+msgid "NetworkPolicies|Are you sure you want to delete this policy? This action cannot be undone."
+msgstr ""
+
msgid "NetworkPolicies|Choose whether to enforce this policy."
msgstr ""
@@ -16200,12 +16768,21 @@ msgstr ""
msgid "NetworkPolicies|Define this policy's location, conditions and actions."
msgstr ""
+msgid "NetworkPolicies|Delete policy"
+msgstr ""
+
+msgid "NetworkPolicies|Delete policy: %{policy}"
+msgstr ""
+
msgid "NetworkPolicies|Deny all traffic"
msgstr ""
msgid "NetworkPolicies|Description"
msgstr ""
+msgid "NetworkPolicies|Edit policy"
+msgstr ""
+
msgid "NetworkPolicies|Editor mode"
msgstr ""
@@ -16233,6 +16810,9 @@ msgstr ""
msgid "NetworkPolicies|Name"
msgstr ""
+msgid "NetworkPolicies|Namespace"
+msgstr ""
+
msgid "NetworkPolicies|Network Policy"
msgstr ""
@@ -16284,6 +16864,9 @@ msgstr ""
msgid "NetworkPolicies|Rules"
msgstr ""
+msgid "NetworkPolicies|Save changes"
+msgstr ""
+
msgid "NetworkPolicies|Something went wrong, failed to update policy"
msgstr ""
@@ -16296,6 +16879,9 @@ msgstr ""
msgid "NetworkPolicies|Traffic that does not match any rule will be blocked."
msgstr ""
+msgid "NetworkPolicies|Unable to parse policy"
+msgstr ""
+
msgid "NetworkPolicies|YAML editor"
msgstr ""
@@ -16408,6 +16994,9 @@ msgstr ""
msgid "New Snippet"
msgstr ""
+msgid "New Test Case"
+msgstr ""
+
msgid "New User"
msgstr ""
@@ -16507,6 +17096,9 @@ msgstr ""
msgid "New tag"
msgstr ""
+msgid "New test case"
+msgstr ""
+
msgid "New users set to external"
msgstr ""
@@ -16579,7 +17171,7 @@ msgstr ""
msgid "No changes"
msgstr ""
-msgid "No changes between %{ref_start}%{source_branch}%{ref_end} and %{ref_start}%{target_branch}%{ref_end}"
+msgid "No changes between %{sourceBranch} and %{targetBranch}"
msgstr ""
msgid "No child epics match applied filters"
@@ -16594,6 +17186,9 @@ msgstr ""
msgid "No containers available"
msgstr ""
+msgid "No content to show"
+msgstr ""
+
msgid "No contributions"
msgstr ""
@@ -16669,9 +17264,6 @@ msgstr ""
msgid "No license. All rights reserved"
msgstr ""
-msgid "No licenses found."
-msgstr ""
-
msgid "No matches found"
msgstr ""
@@ -16684,6 +17276,9 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No members found"
+msgstr ""
+
msgid "No merge requests found"
msgstr ""
@@ -16705,6 +17300,9 @@ msgstr ""
msgid "No parent group"
msgstr ""
+msgid "No plan"
+msgstr ""
+
msgid "No pods available"
msgstr ""
@@ -16801,6 +17399,12 @@ msgstr ""
msgid "Not Implemented"
msgstr ""
+msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+msgstr ""
+
+msgid "Not all browsers support WebAuthn. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even from an unsupported browser."
+msgstr ""
+
msgid "Not all data has been processed yet, the accuracy of the chart for the selected timeframe is limited."
msgstr ""
@@ -16897,6 +17501,9 @@ msgstr ""
msgid "Notification settings saved"
msgstr ""
+msgid "NotificationEvent|Change reviewer merge request"
+msgstr ""
+
msgid "NotificationEvent|Close issue"
msgstr ""
@@ -17059,10 +17666,7 @@ msgstr ""
msgid "On track"
msgstr ""
-msgid "OnDemandScans|Attached branch"
-msgstr ""
-
-msgid "OnDemandScans|Attached branch is where the scan job runs."
+msgid "OnDemandScans|Could not fetch scanner profiles. Please refresh the page, or try again later."
msgstr ""
msgid "OnDemandScans|Could not fetch site profiles. Please refresh the page, or try again later."
@@ -17071,6 +17675,9 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
+msgid "OnDemandScans|Create a new scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Create a new site profile"
msgstr ""
@@ -17083,6 +17690,9 @@ msgstr ""
msgid "OnDemandScans|New on-demand DAST scan"
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 ""
@@ -17092,16 +17702,10 @@ msgstr ""
msgid "OnDemandScans|On-demand scans run outside the DevOps cycle and find vulnerabilities in your projects. %{learnMoreLinkStart}Learn more%{learnMoreLinkEnd}"
msgstr ""
-msgid "OnDemandScans|Only a passive scan can be performed on demand."
-msgstr ""
-
-msgid "OnDemandScans|Passive"
-msgstr ""
-
msgid "OnDemandScans|Run scan"
msgstr ""
-msgid "OnDemandScans|Scan mode"
+msgid "OnDemandScans|Scanner profile"
msgstr ""
msgid "OnDemandScans|Scanner settings"
@@ -17113,9 +17717,15 @@ msgstr ""
msgid "OnDemandScans|Select one of the existing profiles"
msgstr ""
+msgid "OnDemandScans|Site profile"
+msgstr ""
+
msgid "OnDemandScans|Site profiles"
msgstr ""
+msgid "OnDemandScans|Use existing scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Use existing site profile"
msgstr ""
@@ -17213,9 +17823,6 @@ msgstr ""
msgid "Open Selection"
msgstr ""
-msgid "Open Web IDE"
-msgstr ""
-
msgid "Open comment type dropdown"
msgstr ""
@@ -17321,6 +17928,9 @@ msgstr ""
msgid "Origin"
msgstr ""
+msgid "Orphaned member"
+msgstr ""
+
msgid "Other Labels"
msgstr ""
@@ -17336,6 +17946,9 @@ msgstr ""
msgid "Other visibility settings have been disabled by the administrator."
msgstr ""
+msgid "Our documentation includes an example DevOps Score report."
+msgstr ""
+
msgid "Out-of-compliance with this project's policies and should be removed"
msgstr ""
@@ -17360,6 +17973,9 @@ msgstr ""
msgid "Overwrite diverged branches"
msgstr ""
+msgid "Owned by %{image_tag}"
+msgstr ""
+
msgid "Owned by anyone"
msgstr ""
@@ -17381,6 +17997,9 @@ msgstr ""
msgid "Package deleted successfully"
msgstr ""
+msgid "Package file size limits"
+msgstr ""
+
msgid "Package recipe already exists"
msgstr ""
@@ -17396,9 +18015,6 @@ msgstr ""
msgid "Package type must be PyPi"
msgstr ""
-msgid "Package was removed"
-msgstr ""
-
msgid "PackageRegistry|%{name} version %{version} was created %{datetime}"
msgstr ""
@@ -17540,12 +18156,18 @@ msgstr ""
msgid "PackageRegistry|NuGet Command"
msgstr ""
+msgid "PackageRegistry|Package Registry"
+msgstr ""
+
msgid "PackageRegistry|Pip Command"
msgstr ""
msgid "PackageRegistry|Pipeline %{link} triggered %{datetime} by %{author}"
msgstr ""
+msgid "PackageRegistry|Publish and share packages for a variety of common package managers. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "PackageRegistry|Published to the %{project} Package Registry %{datetime}"
msgstr ""
@@ -17645,6 +18267,9 @@ msgstr ""
msgid "Page not found"
msgstr ""
+msgid "Page settings"
+msgstr ""
+
msgid "Page was successfully deleted"
msgstr ""
@@ -17786,7 +18411,7 @@ msgstr ""
msgid "Paste issue link"
msgstr ""
-msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Don't use your private SSH key."
+msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Do not paste your private SSH key, as that can compromise your identity."
msgstr ""
msgid "Patch to apply"
@@ -17813,6 +18438,9 @@ msgstr ""
msgid "Pending"
msgstr ""
+msgid "Pending comments"
+msgstr ""
+
msgid "People without permission will never get a notification and won't be able to comment."
msgstr ""
@@ -18011,6 +18639,9 @@ msgstr ""
msgid "Pipelines|Build with confidence"
msgstr ""
+msgid "Pipelines|By revoking a trigger you will break any processes making use of it. Are you sure?"
+msgstr ""
+
msgid "Pipelines|CI Lint"
msgstr ""
@@ -18023,6 +18654,15 @@ msgstr ""
msgid "Pipelines|Continuous Integration can help catch bugs by running your tests automatically, while Continuous Deployment can help you deliver code to your product environment."
msgstr ""
+msgid "Pipelines|Copy trigger token"
+msgstr ""
+
+msgid "Pipelines|Description"
+msgstr ""
+
+msgid "Pipelines|Edit"
+msgstr ""
+
msgid "Pipelines|Get started with Pipelines"
msgstr ""
@@ -18038,15 +18678,27 @@ msgstr ""
msgid "Pipelines|It is recommended the code is reviewed thoroughly before running this pipeline with the parent project's CI resource."
msgstr ""
+msgid "Pipelines|Last Used"
+msgstr ""
+
msgid "Pipelines|Loading Pipelines"
msgstr ""
msgid "Pipelines|More Information"
msgstr ""
+msgid "Pipelines|No triggers have been created yet. Add one using the form above."
+msgstr ""
+
+msgid "Pipelines|Owner"
+msgstr ""
+
msgid "Pipelines|Project cache successfully reset."
msgstr ""
+msgid "Pipelines|Revoke"
+msgstr ""
+
msgid "Pipelines|Run Pipeline"
msgstr ""
@@ -18071,6 +18723,15 @@ msgstr ""
msgid "Pipelines|This project is not currently set up to run pipelines."
msgstr ""
+msgid "Pipelines|Token"
+msgstr ""
+
+msgid "Pipelines|Trigger user has insufficient permissions to project"
+msgstr ""
+
+msgid "Pipelines|invalid"
+msgstr ""
+
msgid "Pipelines|parent"
msgstr ""
@@ -18329,10 +18990,10 @@ msgstr ""
msgid "Please provide attributes to update"
msgstr ""
-msgid "Please refer to %{docs_url}"
+msgid "Please reach out if you have any questions and we'll be happy to assist."
msgstr ""
-msgid "Please retype the email address."
+msgid "Please refer to %{docs_url}"
msgstr ""
msgid "Please select"
@@ -18362,6 +19023,9 @@ msgstr ""
msgid "Please set a new password before proceeding."
msgstr ""
+msgid "Please share your feedback about %{featureName} %{linkStart}in this issue%{linkEnd} to help us improve the experience."
+msgstr ""
+
msgid "Please solve the reCAPTCHA"
msgstr ""
@@ -18665,6 +19329,9 @@ msgstr ""
msgid "Profiles| You are going to change the username %{currentUsernameBold} to %{newUsernameBold}. Profile and projects will be redirected to the %{newUsername} namespace but this redirect will expire once the %{currentUsername} namespace is registered by another user or group. Please update your Git repository remotes as soon as possible."
msgstr ""
+msgid "Profiles|%{provider} Active"
+msgstr ""
+
msgid "Profiles|@username"
msgstr ""
@@ -18716,7 +19383,7 @@ msgstr ""
msgid "Profiles|Commit email"
msgstr ""
-msgid "Profiles|Connect"
+msgid "Profiles|Connect %{provider}"
msgstr ""
msgid "Profiles|Connected Accounts"
@@ -18740,6 +19407,9 @@ msgstr ""
msgid "Profiles|Disconnect"
msgstr ""
+msgid "Profiles|Disconnect %{provider}"
+msgstr ""
+
msgid "Profiles|Do not show on profile"
msgstr ""
@@ -18764,7 +19434,7 @@ msgstr ""
msgid "Profiles|Full name"
msgstr ""
-msgid "Profiles|Give your individual key a title. This will be publically visible."
+msgid "Profiles|Give your individual key a title."
msgstr ""
msgid "Profiles|Include private contributions on my profile"
@@ -18854,7 +19524,7 @@ msgstr ""
msgid "Profiles|The maximum file size allowed is 200KB."
msgstr ""
-msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it?"
+msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it? It will be publicly visible."
msgstr ""
msgid "Profiles|This email will be displayed on your public profile"
@@ -18929,6 +19599,9 @@ msgstr ""
msgid "Profiles|You don't have access to delete this user."
msgstr ""
+msgid "Profiles|You must transfer ownership or delete groups you are an owner of before you can delete your account"
+msgstr ""
+
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
@@ -19517,6 +20190,9 @@ msgstr ""
msgid "ProjectTemplates|GitLab Cluster Management"
msgstr ""
+msgid "ProjectTemplates|Gitpod/Spring Petclinic"
+msgstr ""
+
msgid "ProjectTemplates|Go Micro"
msgstr ""
@@ -20126,6 +20802,9 @@ msgstr ""
msgid "Publish to status page"
msgstr ""
+msgid "Published"
+msgstr ""
+
msgid "Published on status page"
msgstr ""
@@ -20243,9 +20922,15 @@ msgstr ""
msgid "Quick range"
msgstr ""
+msgid "Quickly and easily edit multiple files in your project."
+msgstr ""
+
msgid "README"
msgstr ""
+msgid "Rails"
+msgstr ""
+
msgid "Rake Tasks Help"
msgstr ""
@@ -20364,10 +21049,13 @@ msgstr ""
msgid "Register Two-Factor Authenticator"
msgstr ""
-msgid "Register U2F device"
+msgid "Register Universal Two-Factor (U2F) Device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register WebAuthn Device"
+msgstr ""
+
+msgid "Register device"
msgstr ""
msgid "Register for GitLab"
@@ -20379,9 +21067,6 @@ msgstr ""
msgid "Register with two-factor app"
msgstr ""
-msgid "Registration"
-msgstr ""
-
msgid "Registration|Checkout"
msgstr ""
@@ -20497,9 +21182,6 @@ msgstr ""
msgid "Release|Something went wrong while saving the release details"
msgstr ""
-msgid "Remediated: needs review"
-msgstr ""
-
msgid "Remediations"
msgstr ""
@@ -20605,6 +21287,9 @@ msgstr ""
msgid "Remove priority"
msgstr ""
+msgid "Remove report"
+msgstr ""
+
msgid "Remove secondary node"
msgstr ""
@@ -20617,6 +21302,12 @@ msgstr ""
msgid "Remove time estimate"
msgstr ""
+msgid "Remove user & report"
+msgstr ""
+
+msgid "Remove user from group"
+msgstr ""
+
msgid "Removed"
msgstr ""
@@ -20698,9 +21389,6 @@ msgstr ""
msgid "Removes time estimate."
msgstr ""
-msgid "Removing license…"
-msgstr ""
-
msgid "Removing this group also removes all child projects, including archived projects, and their resources."
msgstr ""
@@ -20785,6 +21473,9 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
+msgid "Reported by %{reporter}"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -20870,6 +21561,27 @@ msgstr ""
msgid "Repositories"
msgstr ""
+msgid "Repositories Analytics"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download Historic Test Coverage Data"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download historic test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Historic Test Coverage Data is available in raw format (.csv) for further analysis."
+msgstr ""
+
+msgid "RepositoriesAnalytics|Test Code Coverage"
+msgstr ""
+
+msgid "RepositoriesAnalytics|There was an error fetching the projects."
+msgstr ""
+
msgid "Repository"
msgstr ""
@@ -20948,9 +21660,15 @@ msgstr ""
msgid "Request parameter %{param} is missing."
msgstr ""
+msgid "Request review from"
+msgstr ""
+
msgid "Request to link SAML account must be authorized"
msgstr ""
+msgid "Requested"
+msgstr ""
+
msgid "Requested %{time_ago}"
msgstr ""
@@ -20969,6 +21687,9 @@ msgstr ""
msgid "Requests to these domain(s)/address(es) on the local network will be allowed when local requests from hooks and services are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 or 127.0.0.0/28 are supported. Domain wildcards are not supported currently. Use comma, semicolon, or newline to separate multiple entries. The allowlist can hold a maximum of 1000 entries. Domains should use IDNA encoding. Ex: example.com, 192.168.1.1, 127.0.0.0/28, xn--itlab-j1a.com."
msgstr ""
+msgid "Require admin approval for new sign-ups"
+msgstr ""
+
msgid "Require all users in this group to setup Two-factor authentication"
msgstr ""
@@ -21094,9 +21815,6 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
-msgid "Resolved by %{resolvedByName}"
-msgstr ""
-
msgid "Resolves IP addresses once and uses them to submit requests"
msgstr ""
@@ -21215,6 +21933,13 @@ msgstr ""
msgid "ReviewApp|Enable Review App"
msgstr ""
+msgid "Reviewer"
+msgid_plural "%d Reviewers"
+msgstr[0] ""
+
+msgid "Reviewer(s)"
+msgstr ""
+
msgid "Reviewing"
msgstr ""
@@ -21254,6 +21979,9 @@ msgstr ""
msgid "Rook"
msgstr ""
+msgid "Ruby"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -21332,6 +22060,63 @@ msgstr ""
msgid "Runners page."
msgstr ""
+msgid "Runners|Active"
+msgstr ""
+
+msgid "Runners|Architecture"
+msgstr ""
+
+msgid "Runners|Can run untagged jobs"
+msgstr ""
+
+msgid "Runners|Description"
+msgstr ""
+
+msgid "Runners|Group"
+msgstr ""
+
+msgid "Runners|IP Address"
+msgstr ""
+
+msgid "Runners|Last contact"
+msgstr ""
+
+msgid "Runners|Locked to this project"
+msgstr ""
+
+msgid "Runners|Maximum job timeout"
+msgstr ""
+
+msgid "Runners|Name"
+msgstr ""
+
+msgid "Runners|Platform"
+msgstr ""
+
+msgid "Runners|Property Name"
+msgstr ""
+
+msgid "Runners|Protected"
+msgstr ""
+
+msgid "Runners|Revision"
+msgstr ""
+
+msgid "Runners|Shared"
+msgstr ""
+
+msgid "Runners|Specific"
+msgstr ""
+
+msgid "Runners|Tags"
+msgstr ""
+
+msgid "Runners|Value"
+msgstr ""
+
+msgid "Runners|Version"
+msgstr ""
+
msgid "Runners|You have used %{quotaUsed} out of %{quotaLimit} of your shared Runners pipeline minutes."
msgstr ""
@@ -21344,6 +22129,9 @@ msgstr ""
msgid "Runs a number of housekeeping tasks within the current repository, such as compressing file revisions and removing unreachable objects."
msgstr ""
+msgid "SAML"
+msgstr ""
+
msgid "SAML SSO"
msgstr ""
@@ -21395,6 +22183,9 @@ msgstr ""
msgid "Save"
msgstr ""
+msgid "Save %{name} size limits"
+msgstr ""
+
msgid "Save Changes"
msgstr ""
@@ -21425,9 +22216,6 @@ msgstr ""
msgid "Save space and find tags in the Container Registry more easily. Enable the cleanup policy to remove stale tags and keep only the ones you need."
msgstr ""
-msgid "Save template"
-msgstr ""
-
msgid "Save variables"
msgstr ""
@@ -21470,9 +22258,6 @@ msgstr ""
msgid "Scope"
msgstr ""
-msgid "Scope not supported with disabled 'users_search' feature!"
-msgstr ""
-
msgid "Scoped issue boards"
msgstr ""
@@ -21599,9 +22384,6 @@ msgstr ""
msgid "Search requirements"
msgstr ""
-msgid "Search results…"
-msgstr ""
-
msgid "Search users"
msgstr ""
@@ -21671,6 +22453,10 @@ msgid "SearchResults|commit"
msgid_plural "SearchResults|commits"
msgstr[0] ""
+msgid "SearchResults|epic"
+msgid_plural "SearchResults|epics"
+msgstr[0] ""
+
msgid "SearchResults|issue"
msgid_plural "SearchResults|issues"
msgstr[0] ""
@@ -21708,10 +22494,10 @@ msgstr ""
msgid "Seat Link is disabled, and cannot be configured through this form."
msgstr ""
-msgid "Seats currently in use"
+msgid "Seats usage data as of %{last_enqueue_time}"
msgstr ""
-msgid "Seats in license"
+msgid "Seats usage data is updated every day at 12:00pm UTC"
msgstr ""
msgid "Secondary"
@@ -21765,6 +22551,9 @@ msgstr ""
msgid "SecurityConfiguration|Available for on-demand DAST"
msgstr ""
+msgid "SecurityConfiguration|By default, all analyzers are applied in order to cover all languages across your project, and only run if the language is detected in the Merge Request."
+msgstr ""
+
msgid "SecurityConfiguration|Configure"
msgstr ""
@@ -21795,16 +22584,19 @@ msgstr ""
msgid "SecurityConfiguration|Manage"
msgstr ""
+msgid "SecurityConfiguration|More information"
+msgstr ""
+
msgid "SecurityConfiguration|Not enabled"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|Security Control"
+msgid "SecurityConfiguration|SAST Configuration"
msgstr ""
-msgid "SecurityConfiguration|See documentation"
+msgid "SecurityConfiguration|Security Control"
msgstr ""
msgid "SecurityConfiguration|Status"
@@ -21816,6 +22608,9 @@ msgstr ""
msgid "SecurityConfiguration|Using custom settings. You won't receive automatic updates on this variable. %{anchorStart}Restore to default%{anchorEnd}"
msgstr ""
+msgid "SecurityConfiguration|View history"
+msgstr ""
+
msgid "SecurityConfiguration|You can quickly enable all security scanning tools by enabling %{linkStart}Auto DevOps%{linkEnd}."
msgstr ""
@@ -21894,9 +22689,6 @@ msgstr ""
msgid "SecurityReports|Learn more about setting up your dashboard"
msgstr ""
-msgid "SecurityReports|Load more vulnerabilities"
-msgstr ""
-
msgid "SecurityReports|Monitor vulnerabilities in your code"
msgstr ""
@@ -22176,7 +22968,7 @@ msgstr ""
msgid "Select status"
msgstr ""
-msgid "Select strategy activation method"
+msgid "Select strategy activation method."
msgstr ""
msgid "Select subscription"
@@ -22191,7 +22983,7 @@ msgstr ""
msgid "Select the custom project template source group."
msgstr ""
-msgid "Select timeframe"
+msgid "Select the environment scope for this feature flag."
msgstr ""
msgid "Select timezone"
@@ -22440,6 +23232,9 @@ msgstr ""
msgid "Set iteration"
msgstr ""
+msgid "Set limit to 0 to allow any file size."
+msgstr ""
+
msgid "Set max session time for web terminal."
msgstr ""
@@ -22518,10 +23313,13 @@ msgstr ""
msgid "Set up a %{type} Runner manually"
msgstr ""
+msgid "Set up a hardware device as a second factor to sign in."
+msgstr ""
+
msgid "Set up assertions/attributes/claims (email, first_name, last_name) and NameID according to %{docsLinkStart}the documentation %{icon}%{docsLinkEnd}"
msgstr ""
-msgid "Set up new U2F device"
+msgid "Set up new device"
msgstr ""
msgid "Set up new password"
@@ -22590,6 +23388,9 @@ msgstr ""
msgid "Sets weight to %{weight}."
msgstr ""
+msgid "Setting this to 0 means using the system default timeout value."
+msgstr ""
+
msgid "Settings"
msgstr ""
@@ -22605,6 +23406,15 @@ msgstr ""
msgid "Severity"
msgstr ""
+msgid "SeverityWidget|Severity"
+msgstr ""
+
+msgid "SeverityWidget|Severity: %{severity}"
+msgstr ""
+
+msgid "SeverityWidget|There was an error while updating severity."
+msgstr ""
+
msgid "Shards (%{shards})"
msgstr ""
@@ -22650,6 +23460,9 @@ msgstr ""
msgid "Show all requirements."
msgstr ""
+msgid "Show all test cases."
+msgstr ""
+
msgid "Show archived projects"
msgstr ""
@@ -22662,6 +23475,9 @@ msgstr ""
msgid "Show comments"
msgstr ""
+msgid "Show comments on this file"
+msgstr ""
+
msgid "Show comments only"
msgstr ""
@@ -22707,6 +23523,12 @@ msgstr ""
msgid "Show parent subgroups"
msgstr ""
+msgid "Show the Closed list"
+msgstr ""
+
+msgid "Show the Open list"
+msgstr ""
+
msgid "Show whitespace changes"
msgstr ""
@@ -22748,9 +23570,6 @@ msgstr ""
msgid "Sidebar|Assign health status"
msgstr ""
-msgid "Sidebar|Change weight"
-msgstr ""
-
msgid "Sidebar|Health status"
msgstr ""
@@ -22934,6 +23753,9 @@ msgstr ""
msgid "Snippets|Add another file %{num}/%{total}"
msgstr ""
+msgid "Snippets|Authored %{time_ago} by %{author}"
+msgstr ""
+
msgid "Snippets|Delete file"
msgstr ""
@@ -22961,6 +23783,9 @@ msgstr ""
msgid "Solution"
msgstr ""
+msgid "Some changes are not shown"
+msgstr ""
+
msgid "Some child epics may be hidden due to applied filters"
msgstr ""
@@ -23327,6 +24152,12 @@ msgstr ""
msgid "Source (branch or tag)"
msgstr ""
+msgid "Source Branch"
+msgstr ""
+
+msgid "Source branch: %{source_branch_open}%{source_branch}%{source_branch_close}"
+msgstr ""
+
msgid "Source code"
msgstr ""
@@ -23492,9 +24323,6 @@ msgstr ""
msgid "Start and due date"
msgstr ""
-msgid "Start by choosing a group to see how your team is spending time. You can then drill down to the project level."
-msgstr ""
-
msgid "Start by choosing a group to start exploring the merge requests in that group. You can then proceed to filter by projects, labels, milestones and authors."
msgstr ""
@@ -23576,18 +24404,27 @@ msgstr ""
msgid "StaticSiteEditor|3. Assign a person to review and accept the merge request."
msgstr ""
+msgid "StaticSiteEditor|A link to view the merge request will appear once ready."
+msgstr ""
+
msgid "StaticSiteEditor|An error occurred while submitting your changes."
msgstr ""
msgid "StaticSiteEditor|Branch could not be created."
msgstr ""
+msgid "StaticSiteEditor|Copy update"
+msgstr ""
+
msgid "StaticSiteEditor|Could not commit the content changes."
msgstr ""
msgid "StaticSiteEditor|Could not create merge request."
msgstr ""
+msgid "StaticSiteEditor|Creating your merge request"
+msgstr ""
+
msgid "StaticSiteEditor|Incompatible file content"
msgstr ""
@@ -23609,6 +24446,9 @@ msgstr ""
msgid "StaticSiteEditor|View documentation"
msgstr ""
+msgid "StaticSiteEditor|You can set an assignee to get your changes reviewed and deployed once your merge request is created."
+msgstr ""
+
msgid "StaticSiteEditor|Your merge request has been created"
msgstr ""
@@ -23738,15 +24578,15 @@ msgstr ""
msgid "Submit %{humanized_resource_name}"
msgstr ""
-msgid "Submit Changes"
-msgstr ""
-
msgid "Submit a review"
msgstr ""
msgid "Submit as spam"
msgstr ""
+msgid "Submit changes"
+msgstr ""
+
msgid "Submit feedback"
msgstr ""
@@ -23900,6 +24740,9 @@ msgstr ""
msgid "Successfully deleted U2F device."
msgstr ""
+msgid "Successfully deleted WebAuthn device."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -24218,9 +25061,6 @@ msgstr ""
msgid "Template to append to all Service Desk issues"
msgstr ""
-msgid "Template was successfully saved."
-msgstr ""
-
msgid "Templates"
msgstr ""
@@ -24296,10 +25136,28 @@ msgid "Test coverage: %d hit"
msgid_plural "Test coverage: %d hits"
msgstr[0] ""
-msgid "Test failed."
+msgid "Test settings"
+msgstr ""
+
+msgid "TestCases|New Test Case"
+msgstr ""
+
+msgid "TestCases|New test case"
+msgstr ""
+
+msgid "TestCases|Search test cases"
+msgstr ""
+
+msgid "TestCases|Something went wrong while creating a test case."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching count of test cases."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching test cases list."
msgstr ""
-msgid "Test settings and save changes"
+msgid "TestCases|Submit test case"
msgstr ""
msgid "TestHooks|Ensure one of your projects has merge requests."
@@ -24365,6 +25223,9 @@ msgstr ""
msgid "Thank you for signing up for your free trial! You will get additional instructions in your inbox shortly."
msgstr ""
+msgid "Thank you for your business."
+msgstr ""
+
msgid "Thank you for your feedback!"
msgstr ""
@@ -24423,9 +25284,6 @@ msgstr ""
msgid "The URL to use for connecting to Elasticsearch. Use a comma-separated list to support clustering (e.g., \"http://localhost:9200, http://localhost:9201\")."
msgstr ""
-msgid "The Web IDE offers advanced syntax highlighting capabilities and more."
-msgstr ""
-
msgid "The X509 Certificate to use when mutual TLS is required to communicate with the external authorization service. If left blank, the server certificate is still validated when accessing over HTTPS."
msgstr ""
@@ -24535,6 +25393,9 @@ msgstr ""
msgid "The form contains the following error:"
msgstr ""
+msgid "The form contains the following warning:"
+msgstr ""
+
msgid "The global settings require you to enable Two-Factor Authentication for your account."
msgstr ""
@@ -24649,9 +25510,6 @@ msgstr ""
msgid "The private key to use when a client certificate is provided. This value is encrypted at rest."
msgstr ""
-msgid "The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The project can be accessed by any logged in user."
msgstr ""
@@ -24688,7 +25546,7 @@ msgstr ""
msgid "The remote repository is being updated..."
msgstr ""
-msgid "The repository can be commited to, and issues, comments and other entities can be created."
+msgid "The repository can be committed to, and issues, comments and other entities can be created."
msgstr ""
msgid "The repository for this project does not exist."
@@ -24742,9 +25600,6 @@ msgstr ""
msgid "The time taken by each data entry gathered by that stage."
msgstr ""
-msgid "The total stage shows the time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The update action will time out after %{number_of_minutes} minutes. For big repositories, use a clone/push combination."
msgstr ""
@@ -24808,6 +25663,9 @@ msgstr ""
msgid "There are no archived requirements"
msgstr ""
+msgid "There are no archived test cases"
+msgstr ""
+
msgid "There are no changes"
msgstr ""
@@ -24847,6 +25705,9 @@ msgstr ""
msgid "There are no open requirements"
msgstr ""
+msgid "There are no open test cases"
+msgstr ""
+
msgid "There are no packages yet"
msgstr ""
@@ -24859,6 +25720,9 @@ msgstr ""
msgid "There is a limit of %{ci_project_subscriptions_limit} subscriptions from or to a project."
msgstr ""
+msgid "There is already a To-Do for this design."
+msgstr ""
+
msgid "There is already a repository with that name on disk"
msgstr ""
@@ -24877,6 +25741,9 @@ msgstr ""
msgid "There was a problem communicating with your device."
msgstr ""
+msgid "There was a problem fetching branches."
+msgstr ""
+
msgid "There was a problem fetching groups."
msgstr ""
@@ -25105,9 +25972,15 @@ msgstr ""
msgid "This action can lead to data loss. To prevent accidental actions we ask you to confirm your intention."
msgstr ""
+msgid "This action cannot be undone, and will permanently delete the %{key} SSH key"
+msgstr ""
+
msgid "This action cannot be undone. You will lose the project's repository and all content: issues, merge requests, etc."
msgstr ""
+msgid "This action has been performed too many times. Try again later."
+msgstr ""
+
msgid "This action will %{strongOpen}permanently delete%{strongClose} %{codeOpen}%{project}%{codeClose} %{strongOpen}immediately%{strongClose}, including its repositories and all content: issues, merge requests, etc."
msgstr ""
@@ -25135,9 +26008,6 @@ msgstr ""
msgid "This board's scope is reduced"
msgstr ""
-msgid "This branch has changed since you started editing. Would you like to create a new branch?"
-msgstr ""
-
msgid "This chart could not be displayed"
msgstr ""
@@ -25264,15 +26134,9 @@ msgstr ""
msgid "This is a security log of important events involving your account."
msgstr ""
-msgid "This is the author's first Merge Request to this project."
-msgstr ""
-
msgid "This is the highest peak of users on your installation since the license started."
msgstr ""
-msgid "This is the maximum number of users that have existed at the same time since the license started. This is the minimum number of seats you will need to buy when you renew your license."
-msgstr ""
-
msgid "This is the number of currently active users on your installation, and this is the minimum number you need to purchase when you renew your license."
msgstr ""
@@ -25504,6 +26368,15 @@ msgstr ""
msgid "This user has no identities"
msgstr ""
+msgid "This user has previously committed to the %{name} project."
+msgstr ""
+
+msgid "This user has the %{access} role in the %{name} project."
+msgstr ""
+
+msgid "This user is the author of this %{noteable}."
+msgstr ""
+
msgid "This user will be the author of all events in the activity feed that are the result of an update, like new branches being created or new commits being pushed to existing branches."
msgstr ""
@@ -25534,6 +26407,9 @@ msgstr ""
msgid "Threat Monitoring"
msgstr ""
+msgid "ThreatMonitoring|All Environments"
+msgstr ""
+
msgid "ThreatMonitoring|Anomalous Requests"
msgstr ""
@@ -25561,9 +26437,6 @@ msgstr ""
msgid "ThreatMonitoring|Operations Per Second"
msgstr ""
-msgid "ThreatMonitoring|Overview"
-msgstr ""
-
msgid "ThreatMonitoring|Packet Activity"
msgstr ""
@@ -25582,6 +26455,9 @@ msgstr ""
msgid "ThreatMonitoring|Something went wrong, unable to fetch statistics"
msgstr ""
+msgid "ThreatMonitoring|Statistics"
+msgstr ""
+
msgid "ThreatMonitoring|The firewall is not installed or has been disabled. To view this data, ensure the web application firewall is installed and enabled for your cluster."
msgstr ""
@@ -25971,6 +26847,9 @@ msgstr ""
msgid "To update Snippets with multiple files, you must use the `files` parameter"
msgstr ""
+msgid "To use Gitpod you must first enable the feature in the integrations section of your %{user_prefs}."
+msgstr ""
+
msgid "To view all %{scannedResourcesCount} scanned URLs, please download the CSV file"
msgstr ""
@@ -26004,9 +26883,6 @@ msgstr ""
msgid "Toggle Sidebar"
msgstr ""
-msgid "Toggle all threads"
-msgstr ""
-
msgid "Toggle backtrace"
msgstr ""
@@ -26031,9 +26907,6 @@ msgstr ""
msgid "Toggle navigation"
msgstr ""
-msgid "Toggle project"
-msgstr ""
-
msgid "Toggle sidebar"
msgstr ""
@@ -26073,6 +26946,9 @@ msgstr ""
msgid "Too many projects enabled. You will need to manage them via the console or the API."
msgstr ""
+msgid "Too much data"
+msgstr ""
+
msgid "Topics (optional)"
msgstr ""
@@ -26091,6 +26967,9 @@ msgstr ""
msgid "Total cores (CPUs)"
msgstr ""
+msgid "Total days to completion"
+msgstr ""
+
msgid "Total issues"
msgstr ""
@@ -26187,6 +27066,9 @@ msgstr ""
msgid "Trending"
msgstr ""
+msgid "Trials|Create a new group to start your GitLab Gold trial."
+msgstr ""
+
msgid "Trials|Go back to GitLab"
msgstr ""
@@ -26196,6 +27078,15 @@ msgstr ""
msgid "Trials|You can always resume this process by selecting your avatar and choosing 'Start a Gold trial'"
msgstr ""
+msgid "Trials|You can apply your trial to a new group or an existing group."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group or your personal account."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group, an existing group, or your personal account."
+msgstr ""
+
msgid "Trials|You won't get a free trial right now but you can always resume this process by clicking on your avatar and choosing 'Start a free trial'"
msgstr ""
@@ -26265,6 +27156,9 @@ msgstr ""
msgid "Try using a different search term to find the file you are looking for."
msgstr ""
+msgid "Trying to communicate with your device. Plug it in (if needed) and press the button on the device now."
+msgstr ""
+
msgid "Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now."
msgstr ""
@@ -26352,6 +27246,12 @@ msgstr ""
msgid "URL or request ID"
msgstr ""
+msgid "USER %{user} WILL BE REMOVED! Are you sure?"
+msgstr ""
+
+msgid "USER WILL BE BLOCKED! Are you sure?"
+msgstr ""
+
msgid "UTC"
msgstr ""
@@ -26409,9 +27309,6 @@ msgstr ""
msgid "Unable to load the merge request widget. Try reloading the page."
msgstr ""
-msgid "Unable to resolve"
-msgstr ""
-
msgid "Unable to save iteration. Please try again"
msgstr ""
@@ -26460,6 +27357,9 @@ msgstr ""
msgid "Undo ignore"
msgstr ""
+msgid "Unexpected error"
+msgstr ""
+
msgid "Unfortunately, your email message to GitLab could not be processed."
msgstr ""
@@ -26493,6 +27393,9 @@ msgstr ""
msgid "Unknown response text"
msgstr ""
+msgid "Unless otherwise agreed to in writing with GitLab, by clicking \"Upload License\" you agree that your use of GitLab Software is subject to the %{eula_link_start}Terms of Service%{eula_link_end}."
+msgstr ""
+
msgid "Unlimited"
msgstr ""
@@ -26859,9 +27762,6 @@ msgstr ""
msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
msgstr ""
-msgid "Use a hardware device to add the second factor of authentication."
-msgstr ""
-
msgid "Use an one time password authenticator on your mobile device or computer to enable two-factor authentication (2FA)."
msgstr ""
@@ -27135,13 +28035,13 @@ msgstr ""
msgid "Users"
msgstr ""
-msgid "Users in License:"
+msgid "Users in License"
msgstr ""
-msgid "Users or groups set as approvers in the project's or merge request's settings."
+msgid "Users in License:"
msgstr ""
-msgid "Users outside of license"
+msgid "Users or groups set as approvers in the project's or merge request's settings."
msgstr ""
msgid "Users over License:"
@@ -27159,9 +28059,6 @@ msgstr ""
msgid "Users with a Guest role or those who don't belong to a Project or Group will not use a seat from your license."
msgstr ""
-msgid "Users with a Guest role or those who don't belong to any projects or groups don't count towards seats in use."
-msgstr ""
-
msgid "UsersSelect|%{name} + %{length} more"
msgstr ""
@@ -27201,9 +28098,6 @@ msgstr ""
msgid "Validations failed."
msgstr ""
-msgid "Validity"
-msgstr ""
-
msgid "Value"
msgstr ""
@@ -27222,6 +28116,9 @@ msgstr ""
msgid "Value Stream Name"
msgstr ""
+msgid "ValueStreamAnalyticsStage|We don't have enough data to show this stage."
+msgstr ""
+
msgid "ValueStreamAnalytics|%{days}d"
msgstr ""
@@ -27476,6 +28373,9 @@ msgstr ""
msgid "VisualReviewApp|Steps 1 and 2 (and sometimes 3) are performed once by the developer before requesting feedback. Steps 3 (if necessary), 4 is performed by the reviewer each time they perform a review."
msgstr ""
+msgid "Visualization"
+msgstr ""
+
msgid "Vulnerabilities"
msgstr ""
@@ -27503,34 +28403,31 @@ msgstr ""
msgid "VulnerabilityChart|Severity"
msgstr ""
-msgid "VulnerabilityManagement|A true-positive and will fix"
-msgstr ""
-
-msgid "VulnerabilityManagement|Change status"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Confirm"
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|Confirmed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Detected %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|A true-positive and will fix"
msgstr ""
-msgid "VulnerabilityManagement|Dismiss"
+msgid "VulnerabilityManagement|Change status"
msgstr ""
-msgid "VulnerabilityManagement|Dismissed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
msgstr ""
-msgid "VulnerabilityManagement|Resolved"
+msgid "VulnerabilityManagement|Detected"
msgstr ""
-msgid "VulnerabilityManagement|Resolved %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Needs triage"
msgstr ""
msgid "VulnerabilityManagement|Something went wrong while trying to delete the comment. Please try again later."
@@ -27581,6 +28478,9 @@ msgstr ""
msgid "Vulnerability|%{scannerName} (version %{scannerVersion})"
msgstr ""
+msgid "Vulnerability|Activity"
+msgstr ""
+
msgid "Vulnerability|Class"
msgstr ""
@@ -27593,6 +28493,9 @@ msgstr ""
msgid "Vulnerability|Description"
msgstr ""
+msgid "Vulnerability|Detected"
+msgstr ""
+
msgid "Vulnerability|Evidence"
msgstr ""
@@ -27656,6 +28559,9 @@ msgstr ""
msgid "Warning: Displaying this diagram might cause performance issues on this page."
msgstr ""
+msgid "We are currently unable to fetch data for the pipeline header."
+msgstr ""
+
msgid "We are currently unable to fetch data for this graph."
msgstr ""
@@ -27695,6 +28601,12 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
+msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
+msgstr ""
+
+msgid "We would like to inform you that your subscription GitLab Enterprise Edition %{plan_name} is nearing its user limit. You have %{active_user_count} active users, which is almost at the user limit of %{maximum_user_count}."
+msgstr ""
+
msgid "We've found no vulnerabilities"
msgstr ""
@@ -27710,6 +28622,12 @@ msgstr ""
msgid "Web terminal"
msgstr ""
+msgid "WebAuthn Devices (%{length})"
+msgstr ""
+
+msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
+msgstr ""
+
msgid "WebIDE|Merge request"
msgstr ""
@@ -27848,15 +28766,9 @@ msgstr ""
msgid "Welcome to the guided GitLab tour"
msgstr ""
-msgid "Welcome to your Issue Board!"
-msgstr ""
-
msgid "Welcome to your issue board!"
msgstr ""
-msgid "We’ve been making changes to %{featureName} and we’d love your feedback %{linkStart}in this issue%{linkEnd} to help us improve the experience."
-msgstr ""
-
msgid "What are you searching for?"
msgstr ""
@@ -27875,6 +28787,9 @@ msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
msgstr ""
+msgid "When enabled, any user visiting %{host} and creating an account will have to be explicitly approved by the admin before they can login. This setting is effective only if sign-ups are enabled."
+msgstr ""
+
msgid "When enabled, any user visiting %{host} will be able to create an account."
msgstr ""
@@ -28098,6 +29013,9 @@ msgstr ""
msgid "With requirements, you can set criteria to check your products against."
msgstr ""
+msgid "With test cases, you can define conditions for your project to meet in determining quality"
+msgstr ""
+
msgid "Withdraw Access Request"
msgstr ""
@@ -28113,6 +29031,9 @@ msgstr ""
msgid "Workflow Help"
msgstr ""
+msgid "Would you like to create a new branch?"
+msgstr ""
+
msgid "Write"
msgstr ""
@@ -28134,6 +29055,9 @@ msgstr ""
msgid "Wrong extern UID provided. Make sure Auth0 is configured correctly."
msgstr ""
+msgid "YYYY-MM-DD"
+msgstr ""
+
msgid "Yes"
msgstr ""
@@ -28191,7 +29115,7 @@ msgstr ""
msgid "You are going to remove the fork relationship from %{project_full_name}. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "You are going to transfer %{project_full_name} to another owner. Are you ABSOLUTELY sure?"
+msgid "You are going to transfer %{project_full_name} to another namespace. Are you ABSOLUTELY sure?"
msgstr ""
msgid "You are going to turn off the confidentiality. This means %{strongStart}everyone%{strongEnd} will be able to see and leave a comment on this %{issuableType}."
@@ -28251,9 +29175,6 @@ msgstr ""
msgid "You can always edit this later"
msgstr ""
-msgid "You can apply your Trial to your Personal account or create a New Group."
-msgstr ""
-
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings"
msgstr ""
@@ -28275,12 +29196,18 @@ msgstr ""
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
+msgid "You can find more information about GitLab subscriptions in %{subscriptions_doc_link}."
+msgstr ""
+
msgid "You can generate an access token scoped to this project for each application to use the GitLab API."
msgstr ""
msgid "You can get started by cloning the repository or start adding files to it with one of the following options."
msgstr ""
+msgid "You can group test cases using labels. To learn about the future direction of this feature, visit %{linkStart}Quality Management direction page%{linkEnd}."
+msgstr ""
+
msgid "You can invite a new member to %{project_name} or invite another group."
msgstr ""
@@ -28296,6 +29223,9 @@ msgstr ""
msgid "You can notify the app / group or a project by sending them an email notification"
msgstr ""
+msgid "You can now close this window."
+msgstr ""
+
msgid "You can now export your security dashboard to a CSV report."
msgstr ""
@@ -28344,9 +29274,6 @@ msgstr ""
msgid "You can test your .gitlab-ci.yml in %{linkStart}CI Lint%{linkEnd}."
msgstr ""
-msgid "You can try again using %{begin_link}basic search%{end_link}"
-msgstr ""
-
msgid "You cannot access the raw file. Please wait a minute."
msgstr ""
@@ -28398,6 +29325,9 @@ msgstr ""
msgid "You don't have any U2F devices registered yet."
msgstr ""
+msgid "You don't have any WebAuthn devices registered yet."
+msgstr ""
+
msgid "You don't have any active chat names."
msgstr ""
@@ -28485,6 +29415,9 @@ msgstr ""
msgid "You must accept our Terms of Service and privacy policy in order to register an account"
msgstr ""
+msgid "You must be logged in to search across all of GitLab"
+msgstr ""
+
msgid "You must disassociate %{domain} from all clusters it is attached to before deletion."
msgstr ""
@@ -28524,7 +29457,7 @@ msgstr ""
msgid "You need to be logged in."
msgstr ""
-msgid "You need to register a two-factor authentication app before you can set up a U2F device."
+msgid "You need to register a two-factor authentication app before you can set up a device."
msgstr ""
msgid "You need to set terms to be enforced"
@@ -28542,6 +29475,9 @@ msgstr ""
msgid "You reached %{usage_in_percent} of %{namespace_name}'s storage capacity (%{used_storage} of %{storage_limit})"
msgstr ""
+msgid "You successfully declined the invitation"
+msgstr ""
+
msgid "You tried to fork %{link_to_the_project} but it failed for the following reason:"
msgstr ""
@@ -28707,10 +29643,13 @@ msgstr ""
msgid "Your U2F device did not send a valid JSON response."
msgstr ""
-msgid "Your U2F device needs to be set up. Plug it in (if not already) and click the button on the left."
+msgid "Your U2F device was registered!"
msgstr ""
-msgid "Your U2F device was registered!"
+msgid "Your WebAuthn device did not send a valid JSON response."
+msgstr ""
+
+msgid "Your WebAuthn device was registered!"
msgstr ""
msgid "Your access request to the %{source_type} has been withdrawn."
@@ -28734,6 +29673,9 @@ msgstr ""
msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
msgstr ""
+msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
+msgstr ""
+
msgid "Your changes can be committed to %{branch_name} because a merge request is open."
msgstr ""
@@ -28770,6 +29712,12 @@ msgstr ""
msgid "Your deployment services will be broken, you will need to manually fix the services after renaming."
msgstr ""
+msgid "Your device is not compatible with GitLab. Please try another device"
+msgstr ""
+
+msgid "Your device needs to be set up. Plug it in (if needed) and click the button on the left."
+msgstr ""
+
msgid "Your device was successfully set up! Give it a name and register it with the GitLab server."
msgstr ""
@@ -28882,9 +29830,6 @@ msgstr[0] ""
msgid "access:"
msgstr ""
-msgid "activated"
-msgstr ""
-
msgid "added %{created_at_timeago}"
msgstr ""
@@ -28957,9 +29902,21 @@ msgstr ""
msgid "by %{user}"
msgstr ""
+msgid "cannot be a date in the past"
+msgstr ""
+
msgid "cannot be changed if a personal project has container registry tags."
msgstr ""
+msgid "cannot be changed if shared runners are enabled"
+msgstr ""
+
+msgid "cannot be enabled because parent group does not allow it"
+msgstr ""
+
+msgid "cannot be enabled because parent group has shared Runners disabled"
+msgstr ""
+
msgid "cannot be enabled unless all domains have TLS certificates"
msgstr ""
@@ -29005,7 +29962,7 @@ msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about SAST %{linkEndTag}"
msgstr ""
-msgid "ciReport|%{linkStartTag}Learn more about Secret Scanning %{linkEndTag}"
+msgid "ciReport|%{linkStartTag}Learn more about Secret Detection %{linkEndTag}"
msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about codequality reports %{linkEndTag}"
@@ -29317,9 +30274,6 @@ msgstr ""
msgid "error"
msgstr ""
-msgid "error code:"
-msgstr ""
-
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr ""
@@ -29341,6 +30295,9 @@ msgstr ""
msgid "failed to dismiss associated finding(id=%{finding_id}): %{message}"
msgstr ""
+msgid "failed to revert associated finding(id=%{finding_id}) to detected"
+msgstr ""
+
msgid "file"
msgid_plural "files"
msgstr[0] ""
@@ -29879,6 +30836,9 @@ msgstr ""
msgid "must be a root namespace"
msgstr ""
+msgid "must be a valid IPv4 or IPv6 address"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -29915,6 +30875,9 @@ msgstr ""
msgid "no expiration"
msgstr ""
+msgid "no name set"
+msgstr ""
+
msgid "no one can merge"
msgstr ""
@@ -30088,9 +31051,6 @@ msgstr ""
msgid "security Reports|There was an error creating the merge request"
msgstr ""
-msgid "settings saved, but not activated"
-msgstr ""
-
msgid "severity|Critical"
msgstr ""
@@ -30217,9 +31177,6 @@ msgstr ""
msgid "toggle collapse"
msgstr ""
-msgid "toggle dropdown"
-msgstr ""
-
msgid "triggered"
msgstr ""
@@ -30247,6 +31204,9 @@ msgstr ""
msgid "user avatar"
msgstr ""
+msgid "user preferences"
+msgstr ""
+
msgid "username"
msgstr ""
diff --git a/locale/ig_NG/gitlab.po b/locale/ig_NG/gitlab.po
index c796e999887..1dc3320936a 100644
--- a/locale/ig_NG/gitlab.po
+++ b/locale/ig_NG/gitlab.po
@@ -14,7 +14,10 @@ msgstr ""
"X-Crowdin-Language: ig\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 6\n"
-"PO-Revision-Date: 2020-09-04 23:05\n"
+"PO-Revision-Date: 2020-10-02 18:45\n"
+
+msgid " %{project_name}#%{issue_iid} &middot; opened %{issue_created} by %{author}"
+msgstr ""
msgid " %{start} to %{end}"
msgstr ""
@@ -72,6 +75,14 @@ msgstr ""
msgid "\"el\" parameter is required for createInstance()"
msgstr ""
+msgid "%d Approval"
+msgid_plural "%d Approvals"
+msgstr[0] ""
+
+msgid "%d Package"
+msgid_plural "%d Packages"
+msgstr[0] ""
+
msgid "%d Scanned URL"
msgid_plural "%d Scanned URLs"
msgstr[0] ""
@@ -123,6 +134,10 @@ msgstr[0] ""
msgid "%d commits"
msgstr ""
+msgid "%d completed issue"
+msgid_plural "%d completed issues"
+msgstr[0] ""
+
msgid "%d contribution"
msgid_plural "%d contributions"
msgstr[0] ""
@@ -131,6 +146,10 @@ msgid "%d day"
msgid_plural "%d days"
msgstr[0] ""
+msgid "%d day until tags are automatically removed"
+msgid_plural "%d days until tags are automatically removed"
+msgstr[0] ""
+
msgid "%d error"
msgid_plural "%d errors"
msgstr[0] ""
@@ -203,6 +222,14 @@ msgid "%d more comment"
msgid_plural "%d more comments"
msgstr[0] ""
+msgid "%d open issue"
+msgid_plural "%d open issues"
+msgstr[0] ""
+
+msgid "%d pending comment"
+msgid_plural "%d pending comments"
+msgstr[0] ""
+
msgid "%d personal project will be removed and cannot be restored."
msgid_plural "%d personal projects will be removed and cannot be restored."
msgstr[0] ""
@@ -215,6 +242,10 @@ msgid "%d project"
msgid_plural "%d projects"
msgstr[0] ""
+msgid "%d project selected"
+msgid_plural "%d projects selected"
+msgstr[0] ""
+
msgid "%d request with warnings"
msgid_plural "%d requests with warnings"
msgstr[0] ""
@@ -231,6 +262,10 @@ msgid "%d tag"
msgid_plural "%d tags"
msgstr[0] ""
+msgid "%d tag per image name"
+msgid_plural "%d tags per image name"
+msgstr[0] ""
+
msgid "%d unassigned issue"
msgid_plural "%d unassigned issues"
msgstr[0] ""
@@ -247,6 +282,10 @@ msgid "%d vulnerability dismissed"
msgid_plural "%d vulnerabilities dismissed"
msgstr[0] ""
+msgid "%d warning found:"
+msgid_plural "%d warnings found:"
+msgstr[0] ""
+
msgid "%s additional commit has been omitted to prevent performance issues."
msgid_plural "%s additional commits have been omitted to prevent performance issues."
msgstr[0] ""
@@ -284,6 +323,9 @@ msgstr ""
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr ""
+msgid "%{completedCount} completed weight"
+msgstr ""
+
msgid "%{completedWeight} of %{totalWeight} weight completed"
msgstr ""
@@ -329,13 +371,12 @@ msgid "%{count} participant"
msgid_plural "%{count} participants"
msgstr[0] ""
-msgid "%{count} pending comment"
-msgid_plural "%{count} pending comments"
-msgstr[0] ""
-
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
+msgid "%{count} total weight"
+msgstr ""
+
msgid "%{dashboard_path} could not be found."
msgstr ""
@@ -390,6 +431,9 @@ msgstr ""
msgid "%{group_name} uses group managed accounts. You need to create a new GitLab account which will be managed by %{group_name}."
msgstr ""
+msgid "%{group_name}&%{epic_iid} &middot; opened %{epic_created} by %{author}"
+msgstr ""
+
msgid "%{host} sign-in from new location"
msgstr ""
@@ -402,7 +446,7 @@ msgstr ""
msgid "%{issuableType} will be removed! Are you sure?"
msgstr ""
-msgid "%{issuesSize} issues with a limit of %{maxIssueCount}"
+msgid "%{issuesCount} issues with a limit of %{maxIssueCount}"
msgstr ""
msgid "%{issuesSize} with a limit of %{maxIssueCount}"
@@ -435,7 +479,7 @@ msgstr ""
msgid "%{labelStart}Namespace:%{labelEnd} %{namespace}"
msgstr ""
-msgid "%{labelStart}Report Type:%{labelEnd} %{reportType}"
+msgid "%{labelStart}Scan Type:%{labelEnd} %{reportType}"
msgstr ""
msgid "%{labelStart}Scanner:%{labelEnd} %{scanner}"
@@ -625,9 +669,6 @@ msgid "%{securityScanner} result is not available because a pipeline has not bee
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] ""
-msgid "%{service_title} %{message}."
-msgstr ""
-
msgid "%{size} GiB"
msgstr ""
@@ -711,6 +752,12 @@ msgstr ""
msgid "%{timebox_name} should belong either to a project or a group."
msgstr ""
+msgid "%{timebox_type} does not support burnup charts"
+msgstr ""
+
+msgid "%{timebox_type} must have a start and due date"
+msgstr ""
+
msgid "%{title} %{operator} %{threshold}"
msgstr ""
@@ -735,7 +782,7 @@ msgstr ""
msgid "%{total} open issue weight"
msgstr ""
-msgid "%{total} open issues"
+msgid "%{total} warnings found: showing first %{warningsDisplayed}"
msgstr ""
msgid "%{usage_ping_link_start}Learn more%{usage_ping_link_end} about what information is shared with GitLab Inc."
@@ -768,9 +815,6 @@ msgstr ""
msgid "&lt; 1 hour"
msgstr ""
-msgid "&lt;no name set&gt;"
-msgstr ""
-
msgid "&lt;no scopes selected&gt;"
msgstr ""
@@ -801,6 +845,9 @@ msgstr ""
msgid "'%{name}' Value Stream created"
msgstr ""
+msgid "'%{name}' Value Stream deleted"
+msgstr ""
+
msgid "'%{name}' stage already exists"
msgstr ""
@@ -859,6 +906,9 @@ msgstr ""
msgid "+ %{numberOfHiddenAssignees} more"
msgstr ""
+msgid "+ %{numberOfHiddenReviewers} more"
+msgstr ""
+
msgid "+%d more"
msgid_plural "+%d more"
msgstr[0] ""
@@ -913,6 +963,10 @@ msgid "1 Day"
msgid_plural "%d Days"
msgstr[0] ""
+msgid "1 Issue"
+msgid_plural "%d Issues"
+msgstr[0] ""
+
msgid "1 closed issue"
msgid_plural "%{issues} closed issues"
msgstr[0] ""
@@ -925,6 +979,10 @@ msgid "1 day"
msgid_plural "%d days"
msgstr[0] ""
+msgid "1 deploy key"
+msgid_plural "%d deploy keys"
+msgstr[0] ""
+
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1018,6 +1076,9 @@ msgstr ""
msgid ":%{startLine} to %{endLine}"
msgstr ""
+msgid "A %{incident_docs_start}modified issue%{incident_docs_end} to guide the resolution of incidents."
+msgstr ""
+
msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr ""
@@ -1030,6 +1091,9 @@ msgstr ""
msgid "A GitBook site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
+msgid "A Gitpod configured Webapplication in Spring and Java"
+msgstr ""
+
msgid "A Hexo site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
@@ -1201,9 +1265,15 @@ msgstr ""
msgid "Access expiration date"
msgstr ""
+msgid "Access expires"
+msgstr ""
+
msgid "Access forbidden. Check your access level."
msgstr ""
+msgid "Access granted"
+msgstr ""
+
msgid "Access requests"
msgstr ""
@@ -1213,6 +1283,9 @@ msgstr ""
msgid "Access to Pages websites are controlled based on the user's membership to a given project. By checking this box, users will be required to be logged in to have access to all Pages websites in your instance."
msgstr ""
+msgid "AccessDropdown|Deploy Keys"
+msgstr ""
+
msgid "AccessDropdown|Groups"
msgstr ""
@@ -1330,12 +1403,6 @@ msgstr ""
msgid "Active Sessions"
msgstr ""
-msgid "Active Users:"
-msgstr ""
-
-msgid "Active users"
-msgstr ""
-
msgid "Activity"
msgstr ""
@@ -1502,9 +1569,6 @@ msgstr ""
msgid "Add label(s)"
msgstr ""
-msgid "Add license"
-msgstr ""
-
msgid "Add list"
msgstr ""
@@ -1679,21 +1743,51 @@ msgstr ""
msgid "AdminArea|Bots"
msgstr ""
+msgid "AdminArea|Components"
+msgstr ""
+
msgid "AdminArea|Developer"
msgstr ""
+msgid "AdminArea|Features"
+msgstr ""
+
+msgid "AdminArea|Groups: %{number_of_groups}"
+msgstr ""
+
msgid "AdminArea|Guest"
msgstr ""
msgid "AdminArea|Included Free in license"
msgstr ""
+msgid "AdminArea|Latest groups"
+msgstr ""
+
+msgid "AdminArea|Latest projects"
+msgstr ""
+
+msgid "AdminArea|Latest users"
+msgstr ""
+
msgid "AdminArea|Maintainer"
msgstr ""
+msgid "AdminArea|New group"
+msgstr ""
+
+msgid "AdminArea|New project"
+msgstr ""
+
+msgid "AdminArea|New user"
+msgstr ""
+
msgid "AdminArea|Owner"
msgstr ""
+msgid "AdminArea|Projects: %{number_of_projects}"
+msgstr ""
+
msgid "AdminArea|Reporter"
msgstr ""
@@ -1721,6 +1815,9 @@ msgstr ""
msgid "AdminArea|Users without a Group and Project"
msgstr ""
+msgid "AdminArea|Users: %{number_of_users}"
+msgstr ""
+
msgid "AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running."
msgstr ""
@@ -1739,9 +1836,6 @@ msgstr ""
msgid "AdminProjects|Delete Project %{projectName}?"
msgstr ""
-msgid "AdminProjects|Delete project"
-msgstr ""
-
msgid "AdminSettings|Apply integration settings to all Projects"
msgstr ""
@@ -1979,21 +2073,30 @@ msgstr ""
msgid "AdminUsers|Without projects"
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 ""
msgid "AdminUsers|You cannot remove your own admin rights."
msgstr ""
+msgid "AdminUsers|You must transfer ownership or delete the groups owned by this user before you can delete their account"
+msgstr ""
+
msgid "Administration"
msgstr ""
msgid "Advanced"
msgstr ""
+msgid "Advanced Search"
+msgstr ""
+
+msgid "Advanced Search with Elasticsearch"
+msgstr ""
+
msgid "Advanced Settings"
msgstr ""
@@ -2070,6 +2173,9 @@ msgstr ""
msgid "AlertManagement|Edit"
msgstr ""
+msgid "AlertManagement|Environment"
+msgstr ""
+
msgid "AlertManagement|Events"
msgstr ""
@@ -2082,6 +2188,9 @@ msgstr ""
msgid "AlertManagement|Issue"
msgstr ""
+msgid "AlertManagement|Key"
+msgstr ""
+
msgid "AlertManagement|Low"
msgstr ""
@@ -2175,6 +2284,9 @@ msgstr ""
msgid "AlertManagement|Unknown"
msgstr ""
+msgid "AlertManagement|Value"
+msgstr ""
+
msgid "AlertManagement|View alerts in Opsgenie"
msgstr ""
@@ -2334,6 +2446,9 @@ msgstr ""
msgid "All projects"
msgstr ""
+msgid "All projects selected"
+msgstr ""
+
msgid "All security scans are enabled because %{linkStart}Auto DevOps%{linkEnd} is enabled on this project"
msgstr ""
@@ -2421,6 +2536,9 @@ msgstr ""
msgid "Almost there"
msgstr ""
+msgid "Already blocked"
+msgstr ""
+
msgid "Also called \"Issuer\" or \"Relying party trust identifier\""
msgstr ""
@@ -2475,6 +2593,9 @@ msgstr ""
msgid "An error has occurred"
msgstr ""
+msgid "An error occured while making the changes: %{error}"
+msgstr ""
+
msgid "An error occurred adding a draft to the thread."
msgstr ""
@@ -2502,12 +2623,6 @@ msgstr ""
msgid "An error occurred when toggling the notification subscription"
msgstr ""
-msgid "An error occurred when trying to resolve a comment. Please try again."
-msgstr ""
-
-msgid "An error occurred when trying to resolve a discussion. Please try again."
-msgstr ""
-
msgid "An error occurred when updating the issue weight"
msgstr ""
@@ -2523,12 +2638,6 @@ msgstr ""
msgid "An error occurred while checking group path. Please refresh and try again."
msgstr ""
-msgid "An error occurred while committing your changes."
-msgstr ""
-
-msgid "An error occurred while creating the list. Please try again."
-msgstr ""
-
msgid "An error occurred while decoding the file."
msgstr ""
@@ -2601,25 +2710,19 @@ msgstr ""
msgid "An error occurred while fetching the Service Desk address."
msgstr ""
-msgid "An error occurred while fetching the board issues. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the board lists. Please reload the page."
msgstr ""
msgid "An error occurred while fetching the board lists. Please try again."
msgstr ""
-msgid "An error occurred while fetching the board swimlanes. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the builds."
msgstr ""
msgid "An error occurred while fetching the job log."
msgstr ""
-msgid "An error occurred while fetching the job trace."
+msgid "An error occurred while fetching the job logs."
msgstr ""
msgid "An error occurred while fetching the job."
@@ -2766,9 +2869,6 @@ msgstr ""
msgid "An error occurred while saving assignees"
msgstr ""
-msgid "An error occurred while saving the template. Please check if the template exists."
-msgstr ""
-
msgid "An error occurred while searching for milestones"
msgstr ""
@@ -2787,10 +2887,10 @@ msgstr ""
msgid "An error occurred while updating approvers"
msgstr ""
-msgid "An error occurred while updating the comment"
+msgid "An error occurred while updating labels."
msgstr ""
-msgid "An error occurred while updating the list. Please try again."
+msgid "An error occurred while updating the comment"
msgstr ""
msgid "An error occurred while validating group path"
@@ -2844,6 +2944,9 @@ msgstr ""
msgid "An unknown error occurred while loading this graph."
msgstr ""
+msgid "An unknown error occurred."
+msgstr ""
+
msgid "Analytics"
msgstr ""
@@ -2877,10 +2980,10 @@ msgstr ""
msgid "Any"
msgstr ""
-msgid "Any Author"
+msgid "Any %{header}"
msgstr ""
-msgid "Any Status"
+msgid "Any Author"
msgstr ""
msgid "Any branch"
@@ -2934,6 +3037,9 @@ msgstr ""
msgid "Application ID"
msgstr ""
+msgid "Application limits saved successfully"
+msgstr ""
+
msgid "Application settings saved successfully"
msgstr ""
@@ -3139,6 +3245,9 @@ msgstr ""
msgid "Are you sure you want to close this blocked issue?"
msgstr ""
+msgid "Are you sure you want to delete \"%{name}\" Value Stream?"
+msgstr ""
+
msgid "Are you sure you want to delete %{name}?"
msgstr ""
@@ -3148,6 +3257,9 @@ msgstr ""
msgid "Are you sure you want to delete this %{typeOfComment}?"
msgstr ""
+msgid "Are you sure you want to delete this SSH key?"
+msgstr ""
+
msgid "Are you sure you want to delete this board?"
msgstr ""
@@ -3172,6 +3284,10 @@ msgstr ""
msgid "Are you sure you want to erase this build?"
msgstr ""
+msgid "Are you sure you want to import %d repository?"
+msgid_plural "Are you sure you want to import %d repositories?"
+msgstr[0] ""
+
msgid "Are you sure you want to lose unsaved changes?"
msgstr ""
@@ -3181,15 +3297,15 @@ msgstr ""
msgid "Are you sure you want to merge immediately?"
msgstr ""
-msgid "Are you sure you want to permanently delete this license?"
-msgstr ""
-
msgid "Are you sure you want to re-deploy this environment?"
msgstr ""
msgid "Are you sure you want to regenerate the public key? You will have to update the public key on the remote server before mirroring will work again."
msgstr ""
+msgid "Are you sure you want to reindex?"
+msgstr ""
+
msgid "Are you sure you want to remove %{group_name}?"
msgstr ""
@@ -3217,6 +3333,9 @@ msgstr ""
msgid "Are you sure you want to revoke this nickname?"
msgstr ""
+msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
+msgstr ""
+
msgid "Are you sure you want to stop this environment?"
msgstr ""
@@ -3238,6 +3357,9 @@ msgstr ""
msgid "Are you sure? The device will be signed out of GitLab and all remember me tokens revoked."
msgstr ""
+msgid "Are you sure? This will invalidate your registered applications and U2F / WebAuthn devices."
+msgstr ""
+
msgid "Are you sure? This will invalidate your registered applications and U2F devices."
msgstr ""
@@ -3256,9 +3378,6 @@ msgstr ""
msgid "Artifacts"
msgstr ""
-msgid "As U2F devices are only supported by a few browsers, we require that you set up a two-factor authentication app before a U2F device. That way you'll always be able to log in - even when you're using an unsupported browser."
-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 ""
@@ -3450,6 +3569,9 @@ msgstr ""
msgid "AuditLogs|Target"
msgstr ""
+msgid "AuditLogs|This month"
+msgstr ""
+
msgid "AuditLogs|User Events"
msgstr ""
@@ -3489,6 +3611,9 @@ msgstr ""
msgid "Authentication via U2F device failed."
msgstr ""
+msgid "Authentication via WebAuthn device failed."
+msgstr ""
+
msgid "Author"
msgstr ""
@@ -3756,15 +3881,6 @@ msgstr ""
msgid "BambooService|You must set up automatic revision labeling and a repository trigger in Bamboo."
msgstr ""
-msgid "BatchComments|Delete all pending comments"
-msgstr ""
-
-msgid "BatchComments|Discard review?"
-msgstr ""
-
-msgid "BatchComments|You're about to discard your review which will delete all of your pending comments. The deleted comments %{strong_start}cannot%{strong_end} be restored."
-msgstr ""
-
msgid "Be careful. Changing the project's namespace can have unintended side effects."
msgstr ""
@@ -3786,6 +3902,9 @@ msgstr ""
msgid "Bi-weekly code coverage"
msgstr ""
+msgid "Billable Users:"
+msgstr ""
+
msgid "Billing"
msgstr ""
@@ -3795,7 +3914,7 @@ msgstr ""
msgid "BillingPlans|@%{user_name} you are currently using the %{plan_name} plan."
msgstr ""
-msgid "BillingPlans|Congratulations, your new trial is activated"
+msgid "BillingPlans|Congratulations, your free trial is activated."
msgstr ""
msgid "BillingPlans|If you would like to downgrade your plan please contact %{support_link_start}Customer Support%{support_link_end}."
@@ -3858,6 +3977,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Block user"
+msgstr ""
+
msgid "Blocked"
msgstr ""
@@ -3873,31 +3995,37 @@ msgstr ""
msgid "Blog"
msgstr ""
-msgid "Board name"
-msgstr ""
-
msgid "Board scope"
msgstr ""
msgid "Board scope affects which issues are displayed for anyone who visits this board"
msgstr ""
-msgid "BoardBlankState|Add default lists"
+msgid "Boards"
+msgstr ""
+
+msgid "Boards and Board Lists"
msgstr ""
-msgid "BoardBlankState|Add the following default lists to your Issue Board with one click:"
+msgid "Boards|An error occurred while creating the issue. Please try again."
msgstr ""
-msgid "BoardBlankState|Nevermind, I'll use my own"
+msgid "Boards|An error occurred while creating the list. Please try again."
msgstr ""
-msgid "BoardBlankState|Starting out with the default set of lists will get you right on the way to making the most of your board."
+msgid "Boards|An error occurred while fetching issues. Please reload the page."
msgstr ""
-msgid "Boards"
+msgid "Boards|An error occurred while fetching the board issues. Please reload the page."
msgstr ""
-msgid "Boards and Board Lists"
+msgid "Boards|An error occurred while fetching the board swimlanes. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while moving the issue. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while updating the list. Please try again."
msgstr ""
msgid "Boards|Collapse"
@@ -3924,7 +4052,7 @@ msgstr ""
msgid "Branch %{branch_name} was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr ""
-msgid "Branch has changed"
+msgid "Branch changed"
msgstr ""
msgid "Branch is already taken"
@@ -4230,6 +4358,9 @@ msgstr ""
msgid "CLOSED (MOVED)"
msgstr ""
+msgid "CODEOWNERS rule violation"
+msgstr ""
+
msgid "CONTRIBUTING"
msgstr ""
@@ -4260,9 +4391,6 @@ msgstr ""
msgid "Can't create snippet: %{err}"
msgstr ""
-msgid "Can't edit as source branch was deleted"
-msgstr ""
-
msgid "Can't fetch content for the blob: %{err}"
msgstr ""
@@ -4275,9 +4403,6 @@ msgstr ""
msgid "Can't load mermaid module: %{err}"
msgstr ""
-msgid "Can't remove group members without group managed account"
-msgstr ""
-
msgid "Can't scan the code?"
msgstr ""
@@ -4320,6 +4445,9 @@ msgstr ""
msgid "Cannot create the abuse report. This user has been blocked."
msgstr ""
+msgid "Cannot enable shared runners because parent group does not allow it"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -4425,6 +4553,15 @@ msgstr ""
msgid "Change your password or recover your current one"
msgstr ""
+msgid "ChangeReviewer|Reviewer changed from %{old} to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Reviewer changed to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Unassigned"
+msgstr ""
+
msgid "ChangeTypeActionLabel|Pick into branch"
msgstr ""
@@ -4464,6 +4601,9 @@ msgstr ""
msgid "Changes the title to \"%{title_param}\"."
msgstr ""
+msgid "Changes were successfully made."
+msgstr ""
+
msgid "Changes won't take place until the index is %{link_start}recreated%{link_end}."
msgstr ""
@@ -4869,6 +5009,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove variable"
+msgstr ""
+
msgid "CiVariables|Remove variable row"
msgstr ""
@@ -4947,9 +5090,6 @@ msgstr ""
msgid "Clear due date"
msgstr ""
-msgid "Clear input"
-msgstr ""
-
msgid "Clear recent searches"
msgstr ""
@@ -4998,6 +5138,9 @@ msgstr ""
msgid "Client authentication key password"
msgstr ""
+msgid "Client request timeout"
+msgstr ""
+
msgid "Clients"
msgstr ""
@@ -5082,6 +5225,27 @@ msgstr ""
msgid "Cluster type must be specificed for Stages::ClusterEndpointInserter"
msgstr ""
+msgid "ClusterAgents|Configuration"
+msgstr ""
+
+msgid "ClusterAgents|Connect your cluster with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate Kubernetes with a GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Name"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Agent also requires %{linkStart}enabling the Agent Server%{linkEnd}"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Kubernetes Agent allows an Infrastructure as Code, GitOps approach to integrating Kubernetes clusters with GitLab. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "ClusterAgent|This feature is only available for premium plans"
msgstr ""
@@ -5151,10 +5315,10 @@ msgstr ""
msgid "ClusterIntegration|All installed applications and related resources"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster."
+msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{linkStart}More information%{linkEnd}"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{startLink}More information%{endLink}"
+msgid "ClusterIntegration|Allow GitLab to manage namespaces and service accounts for this cluster."
msgstr ""
msgid "ClusterIntegration|Alternatively, "
@@ -5175,6 +5339,9 @@ msgstr ""
msgid "ClusterIntegration|An error occurred while trying to fetch zone machine types: %{error}"
msgstr ""
+msgid "ClusterIntegration|An unknown error occurred while attempting to connect to Kubernetes."
+msgstr ""
+
msgid "ClusterIntegration|Any project namespaces"
msgstr ""
@@ -5190,6 +5357,9 @@ msgstr ""
msgid "ClusterIntegration|Authenticate with Amazon Web Services"
msgstr ""
+msgid "ClusterIntegration|Authentication Error"
+msgstr ""
+
msgid "ClusterIntegration|Base domain"
msgstr ""
@@ -5208,13 +5378,22 @@ msgstr ""
msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}security group %{externalLinkIcon} %{endLink} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
+msgid "ClusterIntegration|Check your CA certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Check your cluster status"
+msgstr ""
+
+msgid "ClusterIntegration|Check your token"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}subnets %{externalLinkIcon} %{endLink} in your VPC where your worker nodes will run."
+msgid "ClusterIntegration|Choose the %{linkStart}security group %{linkEnd} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
msgstr ""
-msgid "ClusterIntegration|Choose the worker node %{startLink}instance type %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Choose the %{linkStart}subnets %{linkEnd} in your VPC where your worker nodes will run."
+msgstr ""
+
+msgid "ClusterIntegration|Choose the worker node %{linkStart}instance type%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Choose which applications to install on your Kubernetes cluster."
@@ -5226,10 +5405,7 @@ msgstr ""
msgid "ClusterIntegration|Clear cluster cache"
msgstr ""
-msgid "ClusterIntegration|Clear the local cache of namespace and service accounts. This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
-msgstr ""
-
-msgid "ClusterIntegration|Cluster being created"
+msgid "ClusterIntegration|Clear the local cache of namespace and service accounts."
msgstr ""
msgid "ClusterIntegration|Cluster management project (alpha)"
@@ -5241,15 +5417,21 @@ msgstr ""
msgid "ClusterIntegration|Cluster_applications artifact too big. Maximum allowable size: %{human_size}"
msgstr ""
-msgid "ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters."
+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|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}"
+msgid "ClusterIntegration|Clusters connected with a certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Connect cluster with certificate"
msgstr ""
msgid "ClusterIntegration|Connect existing cluster"
msgstr ""
+msgid "ClusterIntegration|Connection Error"
+msgstr ""
+
msgid "ClusterIntegration|Copy API URL"
msgstr ""
@@ -5325,6 +5507,12 @@ msgstr ""
msgid "ClusterIntegration|Deletes all GitLab resources attached to this cluster during removal"
msgstr ""
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared."
+msgstr ""
+
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared. %{linkStart}More information%{linkEnd}"
+msgstr ""
+
msgid "ClusterIntegration|Did you know?"
msgstr ""
@@ -5394,6 +5582,9 @@ msgstr ""
msgid "ClusterIntegration|Fluentd is an open source data collector, which lets you unify the data collection and consumption for a better use and understanding of data. It requires at least one of the following logs to be successfully installed."
msgstr ""
+msgid "ClusterIntegration|GitLab Agent managed clusters"
+msgstr ""
+
msgid "ClusterIntegration|GitLab Container Network Policies"
msgstr ""
@@ -5406,6 +5597,12 @@ msgstr ""
msgid "ClusterIntegration|GitLab Runner connects to the repository and executes CI/CD jobs, pushing results back and deploying applications to production."
msgstr ""
+msgid "ClusterIntegration|GitLab failed to authenticate."
+msgstr ""
+
+msgid "ClusterIntegration|GitLab failed to connect to the cluster."
+msgstr ""
+
msgid "ClusterIntegration|GitLab-managed cluster"
msgstr ""
@@ -5427,6 +5624,9 @@ msgstr ""
msgid "ClusterIntegration|Group cluster"
msgstr ""
+msgid "ClusterIntegration|HTTP Error"
+msgstr ""
+
msgid "ClusterIntegration|Helm Tiller"
msgstr ""
@@ -5460,7 +5660,10 @@ msgstr ""
msgid "ClusterIntegration|Instance type"
msgstr ""
-msgid "ClusterIntegration|Integrate Kubernetes cluster automation"
+msgid "ClusterIntegration|Integrate Kubernetes with a cluster certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Integrate with a cluster certificate"
msgstr ""
msgid "ClusterIntegration|Issuer Email"
@@ -5496,9 +5699,6 @@ msgstr ""
msgid "ClusterIntegration|Knative extends Kubernetes to provide a set of middleware components that are essential to build modern, source-centric, and container-based applications that can run anywhere: on premises, in the cloud, or even in a third-party data center."
msgstr ""
-msgid "ClusterIntegration|Kubernetes cluster"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes cluster is being created..."
msgstr ""
@@ -5511,9 +5711,6 @@ msgstr ""
msgid "ClusterIntegration|Kubernetes clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr ""
-msgid "ClusterIntegration|Kubernetes clusters can be used to deploy applications and to provide Review Apps for this project"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes version"
msgstr ""
@@ -5526,7 +5723,7 @@ msgstr ""
msgid "ClusterIntegration|Learn more about %{help_link_start}zones%{help_link_end}."
msgstr ""
-msgid "ClusterIntegration|Learn more about %{startLink}Regions %{externalLinkIcon}%{endLink}."
+msgid "ClusterIntegration|Learn more about %{linkStart}Regions%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Learn more about Kubernetes"
@@ -5571,12 +5768,18 @@ msgstr ""
msgid "ClusterIntegration|Machine type"
msgstr ""
+msgid "ClusterIntegration|Make sure your API endpoint is correct"
+msgstr ""
+
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create Kubernetes clusters"
msgstr ""
msgid "ClusterIntegration|Manage your Kubernetes cluster by visiting %{provider_link}"
msgstr ""
+msgid "ClusterIntegration|Namespace per environment"
+msgstr ""
+
msgid "ClusterIntegration|No IAM Roles found"
msgstr ""
@@ -5622,6 +5825,9 @@ msgstr ""
msgid "ClusterIntegration|No zones matched your search"
msgstr ""
+msgid "ClusterIntegration|Node calculations use the Kubernetes Metrics API. Make sure your cluster has metrics installed"
+msgstr ""
+
msgid "ClusterIntegration|Number of nodes"
msgstr ""
@@ -5664,6 +5870,9 @@ msgstr ""
msgid "ClusterIntegration|RBAC-enabled cluster"
msgstr ""
+msgid "ClusterIntegration|Read our %{linkStart}help page%{linkEnd} on Kubernetes cluster integration."
+msgstr ""
+
msgid "ClusterIntegration|Read our %{link_start}help page%{link_end} on Kubernetes cluster integration."
msgstr ""
@@ -5766,7 +5975,7 @@ msgstr ""
msgid "ClusterIntegration|Select a VPC to choose a subnet"
msgstr ""
-msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{linkStart}Amazon Web Services %{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select a network to choose a subnetwork"
@@ -5799,7 +6008,7 @@ msgstr ""
msgid "ClusterIntegration|Select project to choose zone"
msgstr ""
-msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select zone"
@@ -5889,9 +6098,18 @@ msgstr ""
msgid "ClusterIntegration|There was a problem authenticating with your cluster. Please ensure your CA Certificate and Token are valid."
msgstr ""
+msgid "ClusterIntegration|There was an HTTP error when connecting to your cluster."
+msgstr ""
+
msgid "ClusterIntegration|This account must have permissions to create a Kubernetes cluster in the %{link_to_container_project} specified below"
msgstr ""
+msgid "ClusterIntegration|This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
+msgstr ""
+
+msgid "ClusterIntegration|This is necessary to clear existing environment-namespace associations from clusters previously managed by GitLab."
+msgstr ""
+
msgid "ClusterIntegration|This option will allow you to install applications on RBAC clusters."
msgstr ""
@@ -5916,9 +6134,21 @@ msgstr ""
msgid "ClusterIntegration|To use a new project, first create one on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}."
msgstr ""
+msgid "ClusterIntegration|Troubleshooting tips:"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Authenticate"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Connect"
+msgstr ""
+
msgid "ClusterIntegration|Uninstall %{appTitle}"
msgstr ""
+msgid "ClusterIntegration|Unknown Error"
+msgstr ""
+
msgid "ClusterIntegration|Update %{appTitle}"
msgstr ""
@@ -5979,7 +6209,7 @@ msgstr ""
msgid "ClusterIntegration|Your cluster API is unreachable. Please ensure your API URL is correct."
msgstr ""
-msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Zone"
@@ -6099,6 +6329,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse all threads"
+msgstr ""
+
msgid "Collapse approvers"
msgstr ""
@@ -6247,7 +6480,7 @@ msgstr ""
msgid "Commit…"
msgstr ""
-msgid "Company"
+msgid "Community forum"
msgstr ""
msgid "Company name"
@@ -6256,6 +6489,9 @@ msgstr ""
msgid "Compare"
msgstr ""
+msgid "Compare %{oldCommitId}...%{newCommitId}"
+msgstr ""
+
msgid "Compare Git revisions"
msgstr ""
@@ -6271,6 +6507,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare submodule commit revisions"
+msgstr ""
+
msgid "Compare with previous version"
msgstr ""
@@ -6406,6 +6645,9 @@ msgstr ""
msgid "Configure the way a user creates a new account."
msgstr ""
+msgid "Configure which lists are shown for anyone who visits this board"
+msgstr ""
+
msgid "Confirm"
msgstr ""
@@ -6628,6 +6870,9 @@ msgstr[0] ""
msgid "ContainerRegistry|Set cleanup policy"
msgstr ""
+msgid "ContainerRegistry|Some tags were not deleted"
+msgstr ""
+
msgid "ContainerRegistry|Something went wrong while fetching the cleanup policy."
msgstr ""
@@ -6667,6 +6912,9 @@ msgstr ""
msgid "ContainerRegistry|Tags with names matching this regex pattern will %{italicStart}expire:%{italicEnd}"
msgstr ""
+msgid "ContainerRegistry|The cleanup policy timed out before it could delete all tags. An administrator can %{adminLinkStart}manually run cleanup now%{adminLinkEnd} or you can wait for the cleanup policy to automatically run again. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "ContainerRegistry|The last tag related to this image was recently removed. This empty image and any associated data will be automatically removed as part of the regular Garbage Collection process. If you have any questions, contact your administrator."
msgstr ""
@@ -6799,6 +7047,9 @@ msgstr ""
msgid "Contributions per group member"
msgstr ""
+msgid "Contributor"
+msgstr ""
+
msgid "Contributors"
msgstr ""
@@ -6928,6 +7179,9 @@ msgstr ""
msgid "Could not change HEAD: branch '%{branch}' does not exist"
msgstr ""
+msgid "Could not commit. An unexpected error occurred."
+msgstr ""
+
msgid "Could not connect to FogBugz, check your URL"
msgstr ""
@@ -6967,6 +7221,9 @@ msgstr ""
msgid "Could not find iteration"
msgstr ""
+msgid "Could not load instance counts. Please refresh the page to try again."
+msgstr ""
+
msgid "Could not remove the trigger."
msgstr ""
@@ -6991,10 +7248,10 @@ msgstr ""
msgid "Could not save prometheus manual configuration"
msgstr ""
-msgid "Could not udpdate wiki page"
+msgid "Could not update the LDAP settings"
msgstr ""
-msgid "Could not update the LDAP settings"
+msgid "Could not update wiki page"
msgstr ""
msgid "Could not upload your designs as one or more files uploaded are not supported."
@@ -7650,6 +7907,9 @@ msgstr ""
msgid "DastProfiles|Are you sure you want to delete this profile?"
msgstr ""
+msgid "DastProfiles|Could not create site validation token. Please refresh the page, or try again later."
+msgstr ""
+
msgid "DastProfiles|Could not create the scanner profile. Please try again."
msgstr ""
@@ -7674,6 +7934,12 @@ msgstr ""
msgid "DastProfiles|Could not fetch site profiles. Please refresh the page, or try again later."
msgstr ""
+msgid "DastProfiles|Could not retrieve site validation status. Please refresh the page, or try again later."
+msgstr ""
+
+msgid "DastProfiles|Could not update the scanner profile. Please try again."
+msgstr ""
+
msgid "DastProfiles|Could not update the site profile. Please try again."
msgstr ""
@@ -7689,7 +7955,7 @@ msgstr ""
msgid "DastProfiles|Download validation text file"
msgstr ""
-msgid "DastProfiles|Edit feature will come soon. Please create a new profile if changes needed"
+msgid "DastProfiles|Edit scanner profile"
msgstr ""
msgid "DastProfiles|Edit site profile"
@@ -7722,6 +7988,9 @@ msgstr ""
msgid "DastProfiles|No profiles created yet"
msgstr ""
+msgid "DastProfiles|Passive"
+msgstr ""
+
msgid "DastProfiles|Please enter a valid URL format, ex: http://www.example.com/home"
msgstr ""
@@ -7737,6 +8006,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan mode"
+msgstr ""
+
msgid "DastProfiles|Scanner Profile"
msgstr ""
@@ -7776,10 +8048,10 @@ msgstr ""
msgid "DastProfiles|Text file validation"
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
+msgid "DastProfiles|The maximum number of minutes allowed for the spider to traverse the site."
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the spider to traverse the site."
+msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
msgstr ""
msgid "DastProfiles|Validate"
@@ -7812,6 +8084,9 @@ msgstr ""
msgid "Date picker"
msgstr ""
+msgid "Date range"
+msgstr ""
+
msgid "Date range cannot exceed %{maxDateRange} days."
msgstr ""
@@ -7836,6 +8111,9 @@ msgstr ""
msgid "Days to merge"
msgstr ""
+msgid "Dear Administrator,"
+msgstr ""
+
msgid "Debug"
msgstr ""
@@ -7947,12 +8225,18 @@ msgstr ""
msgid "Delete"
msgstr ""
+msgid "Delete %{name}"
+msgstr ""
+
msgid "Delete Comment"
msgstr ""
msgid "Delete Snippet"
msgstr ""
+msgid "Delete Value Stream"
+msgstr ""
+
msgid "Delete account"
msgstr ""
@@ -7974,9 +8258,6 @@ msgstr ""
msgid "Delete label: %{label_name} ?"
msgstr ""
-msgid "Delete license"
-msgstr ""
-
msgid "Delete list"
msgstr ""
@@ -8052,15 +8333,6 @@ msgstr ""
msgid "Deleting a project places it into a read-only state until %{date}, at which point the project will be permanently deleted. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "Deleting the license failed."
-msgstr ""
-
-msgid "Deleting the license failed. The license was not found."
-msgstr ""
-
-msgid "Deleting the license failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "Deleting the project will delete its repository and all related resources including issues, merge requests etc."
msgstr ""
@@ -8550,7 +8822,10 @@ msgstr ""
msgid "DesignManagement|The maximum number of designs allowed to be uploaded is %{upload_limit}. Please try again."
msgstr ""
-msgid "DesignManagement|To upload designs, you'll need to enable LFS. %{requirements_link_start}More information%{requirements_link_end}"
+msgid "DesignManagement|There was an error moving your designs. Please upload your designs below."
+msgstr ""
+
+msgid "DesignManagement|To upload designs, you'll need to enable LFS and have admin enable hashed storage. %{requirements_link_start}More information%{requirements_link_end}"
msgstr ""
msgid "DesignManagement|Unresolve thread"
@@ -8562,6 +8837,9 @@ msgstr ""
msgid "DesignManagement|Upload skipped."
msgstr ""
+msgid "DesignManagement|Your designs are being copied and are on their way… Please refresh to update."
+msgstr ""
+
msgid "DesignManagement|and %{moreCount} more."
msgstr ""
@@ -8619,6 +8897,9 @@ msgstr ""
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
+msgid "Direct member"
+msgstr ""
+
msgid "Direction"
msgstr ""
@@ -8667,9 +8948,6 @@ msgstr ""
msgid "Discard draft"
msgstr ""
-msgid "Discard review"
-msgstr ""
-
msgid "DiscordService|Discord Notifications"
msgstr ""
@@ -8737,10 +9015,10 @@ msgstr ""
msgid "Dismiss Merge Request promotion"
msgstr ""
-msgid "Dismiss Selected"
+msgid "Dismiss Value Stream Analytics introduction box"
msgstr ""
-msgid "Dismiss Value Stream Analytics introduction box"
+msgid "Dismiss selected"
msgstr ""
msgid "Dismiss trial promotion"
@@ -8791,9 +9069,6 @@ msgstr ""
msgid "Documents reindexed: %{processed_documents} (%{percentage}%%)"
msgstr ""
-msgid "Doing"
-msgstr ""
-
msgid "Domain"
msgstr ""
@@ -8989,9 +9264,6 @@ msgstr ""
msgid "Edit environment"
msgstr ""
-msgid "Edit file"
-msgstr ""
-
msgid "Edit files in the editor and commit changes here"
msgstr ""
@@ -9004,6 +9276,12 @@ msgstr ""
msgid "Edit identity for %{user_name}"
msgstr ""
+msgid "Edit in Web IDE"
+msgstr ""
+
+msgid "Edit in single-file editor"
+msgstr ""
+
msgid "Edit issues"
msgstr ""
@@ -9031,10 +9309,10 @@ msgstr ""
msgid "Editing"
msgstr ""
-msgid "Elasticsearch"
+msgid "Elasticsearch AWS IAM credentials"
msgstr ""
-msgid "Elasticsearch AWS IAM credentials"
+msgid "Elasticsearch HTTP client timeout value in seconds."
msgstr ""
msgid "Elasticsearch indexing restrictions"
@@ -9043,9 +9321,6 @@ msgstr ""
msgid "Elasticsearch indexing started"
msgstr ""
-msgid "Elasticsearch integration. Elasticsearch AWS IAM."
-msgstr ""
-
msgid "Elasticsearch reindexing is already in progress"
msgstr ""
@@ -9073,9 +9348,6 @@ msgstr ""
msgid "Email Notification"
msgstr ""
-msgid "Email address"
-msgstr ""
-
msgid "Email could not be sent"
msgstr ""
@@ -9139,6 +9411,9 @@ msgstr ""
msgid "Emails sent from Service Desk will have this name"
msgstr ""
+msgid "Emails sent to %{email} will still be supported"
+msgstr ""
+
msgid "Emails separated by comma"
msgstr ""
@@ -9172,9 +9447,18 @@ msgstr ""
msgid "Enable"
msgstr ""
+msgid "Enable %{link_start}Gitpod%{link_end} integration to launch a development environment in your browser directly from GitLab."
+msgstr ""
+
msgid "Enable Auto DevOps"
msgstr ""
+msgid "Enable Gitpod"
+msgstr ""
+
+msgid "Enable Gitpod?"
+msgstr ""
+
msgid "Enable HTML emails"
msgstr ""
@@ -9304,9 +9588,6 @@ msgstr ""
msgid "Encountered an error while rendering: %{err}"
msgstr ""
-msgid "End date"
-msgstr ""
-
msgid "Ends at (UTC)"
msgstr ""
@@ -9466,7 +9747,7 @@ msgstr ""
msgid "EnvironmentsDashboard|The environments dashboard provides a summary of each project's environments' status, including pipeline and alert statuses."
msgstr ""
-msgid "EnvironmentsDashboard|This dashboard displays a maximum of 7 projects and 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
+msgid "EnvironmentsDashboard|This dashboard displays 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
msgstr ""
msgid "Environments|An error occurred while canceling the auto stop, please try again"
@@ -9787,6 +10068,9 @@ msgstr ""
msgid "Error deleting project. Check logs for error details."
msgstr ""
+msgid "Error fetching burnup chart data"
+msgstr ""
+
msgid "Error fetching diverging counts for branches. Please try again."
msgstr ""
@@ -9865,6 +10149,9 @@ msgstr ""
msgid "Error occurred when saving assignees"
msgstr ""
+msgid "Error occurred when saving reviewers"
+msgstr ""
+
msgid "Error occurred when toggling the notification subscription"
msgstr ""
@@ -10117,10 +10404,13 @@ msgstr ""
msgid "Expand all"
msgstr ""
-msgid "Expand approvers"
+msgid "Expand all files"
msgstr ""
-msgid "Expand dropdown"
+msgid "Expand all threads"
+msgstr ""
+
+msgid "Expand approvers"
msgstr ""
msgid "Expand milestones"
@@ -10291,6 +10581,9 @@ msgstr ""
msgid "Failed to create Merge Request. Please try again."
msgstr ""
+msgid "Failed to create To-Do for the design."
+msgstr ""
+
msgid "Failed to create a branch for this issue. Please try again."
msgstr ""
@@ -10330,6 +10623,12 @@ msgstr ""
msgid "Failed to load authors. Please try again."
msgstr ""
+msgid "Failed to load branches. Please try again."
+msgstr ""
+
+msgid "Failed to load deploy keys."
+msgstr ""
+
msgid "Failed to load emoji list."
msgstr ""
@@ -10345,6 +10644,9 @@ msgstr ""
msgid "Failed to load groups & users."
msgstr ""
+msgid "Failed to load groups, users and deploy keys."
+msgstr ""
+
msgid "Failed to load labels. Please try again."
msgstr ""
@@ -10354,6 +10656,12 @@ msgstr ""
msgid "Failed to load related branches"
msgstr ""
+msgid "Failed to load sidebar confidential toggle"
+msgstr ""
+
+msgid "Failed to load sidebar lock status"
+msgstr ""
+
msgid "Failed to load stacktrace."
msgstr ""
@@ -10381,6 +10689,9 @@ msgstr ""
msgid "Failed to publish issue on status page."
msgstr ""
+msgid "Failed to remove To-Do for the design."
+msgstr ""
+
msgid "Failed to remove a Zoom meeting"
msgstr ""
@@ -10423,6 +10734,9 @@ msgstr ""
msgid "Failed to signing using smartcard authentication"
msgstr ""
+msgid "Failed to toggle To-Do for the design."
+msgstr ""
+
msgid "Failed to update branch!"
msgstr ""
@@ -10535,7 +10849,7 @@ msgstr ""
msgid "FeatureFlags|Edit User List"
msgstr ""
-msgid "FeatureFlags|Enable features for specific users and specific environments by defining feature flag strategies."
+msgid "FeatureFlags|Enable features for specific users and environments by configuring feature flag strategies."
msgstr ""
msgid "FeatureFlags|Environment Spec"
@@ -10595,7 +10909,7 @@ msgstr ""
msgid "FeatureFlags|Include additional user IDs"
msgstr ""
-msgid "FeatureFlags|Install a %{docs_link_anchored_start}compatible client library%{docs_link_anchored_end} and specify the API URL, application name, and instance ID during the configuration setup. %{docs_link_start}More Information%{docs_link_end}"
+msgid "FeatureFlags|Install a %{docsLinkAnchoredStart}compatible client library%{docsLinkAnchoredEnd} and specify the API URL, application name, and instance ID during the configuration setup. %{docsLinkStart}More Information%{docsLinkEnd}"
msgstr ""
msgid "FeatureFlags|Instance ID"
@@ -10607,6 +10921,9 @@ msgstr ""
msgid "FeatureFlags|Loading feature flags"
msgstr ""
+msgid "FeatureFlags|Loading user lists"
+msgstr ""
+
msgid "FeatureFlags|More information"
msgstr ""
@@ -10625,7 +10942,7 @@ msgstr ""
msgid "FeatureFlags|New feature flag"
msgstr ""
-msgid "FeatureFlags|New list"
+msgid "FeatureFlags|New user list"
msgstr ""
msgid "FeatureFlags|Percent of users"
@@ -10664,6 +10981,9 @@ msgstr ""
msgid "FeatureFlags|There was an error fetching the feature flags."
msgstr ""
+msgid "FeatureFlags|There was an error fetching the user lists."
+msgstr ""
+
msgid "FeatureFlags|There was an error retrieving user lists"
msgstr ""
@@ -10679,6 +10999,9 @@ msgstr ""
msgid "FeatureFlags|User List"
msgstr ""
+msgid "FeatureFlags|User Lists"
+msgstr ""
+
msgid "FeatureFlag|List"
msgstr ""
@@ -10706,15 +11029,6 @@ msgstr ""
msgid "Fetching incoming email"
msgstr ""
-msgid "Fetching licenses failed."
-msgstr ""
-
-msgid "Fetching licenses failed. The request endpoint was not found."
-msgstr ""
-
-msgid "Fetching licenses failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "File"
msgstr ""
@@ -10817,12 +11131,21 @@ msgstr ""
msgid "Filter by status"
msgstr ""
+msgid "Filter by test cases that are currently archived."
+msgstr ""
+
+msgid "Filter by test cases that are currently opened."
+msgstr ""
+
msgid "Filter by two-factor authentication"
msgstr ""
msgid "Filter by user"
msgstr ""
+msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
+msgstr ""
+
msgid "Filter pipelines"
msgstr ""
@@ -10838,7 +11161,7 @@ msgstr ""
msgid "Filter results..."
msgstr ""
-msgid "Filter your projects by name"
+msgid "Filter your repositories by name"
msgstr ""
msgid "Filter..."
@@ -10847,7 +11170,7 @@ msgstr ""
msgid "Find File"
msgstr ""
-msgid "Find bugs in your code with coverage-guided fuzzing"
+msgid "Find bugs in your code with coverage-guided fuzzing."
msgstr ""
msgid "Find by path"
@@ -10874,9 +11197,6 @@ msgstr ""
msgid "Finish editing this message first!"
msgstr ""
-msgid "Finish review"
-msgstr ""
-
msgid "Finish setting up your dedicated account for %{group_name}."
msgstr ""
@@ -10946,6 +11266,9 @@ msgstr ""
msgid "Footer message"
msgstr ""
+msgid "For a faster browsing experience, some files are collapsed by default."
+msgstr ""
+
msgid "For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
@@ -10955,6 +11278,9 @@ msgstr ""
msgid "For more info, read the documentation."
msgstr ""
+msgid "For more information on how the number of active users is calculated, see the %{self_managed_subscriptions_doc_link} documentation."
+msgstr ""
+
msgid "For more information, go to the "
msgstr ""
@@ -11093,6 +11419,9 @@ msgstr ""
msgid "Generate new token"
msgstr ""
+msgid "Generic package file size in bytes"
+msgstr ""
+
msgid "Geo"
msgstr ""
@@ -11354,6 +11683,9 @@ msgstr ""
msgid "Geo|Please refer to Geo Troubleshooting."
msgstr ""
+msgid "Geo|Primary node"
+msgstr ""
+
msgid "Geo|Project"
msgstr ""
@@ -11396,6 +11728,9 @@ msgstr ""
msgid "Geo|Review replication status, and resynchronize and reverify items with the primary node."
msgstr ""
+msgid "Geo|Secondary node"
+msgstr ""
+
msgid "Geo|Status"
msgstr ""
@@ -11435,6 +11770,9 @@ msgstr ""
msgid "Geo|URL must be a valid url (ex: https://gitlab.com)"
msgstr ""
+msgid "Geo|Undefined"
+msgstr ""
+
msgid "Geo|Unknown state"
msgstr ""
@@ -11510,10 +11848,16 @@ msgstr ""
msgid "GitHub import"
msgstr ""
+msgid "GitLab"
+msgstr ""
+
msgid "GitLab / Unsubscribe"
msgstr ""
-msgid "GitLab Enterprise Edition %{plan}"
+msgid "GitLab API"
+msgstr ""
+
+msgid "GitLab Billing Team."
msgstr ""
msgid "GitLab Group Runners can execute code for all the projects in this group."
@@ -11525,12 +11869,18 @@ msgstr ""
msgid "GitLab Issue"
msgstr ""
+msgid "GitLab Pages"
+msgstr ""
+
msgid "GitLab Service Desk is a simple way to allow people to create issues in your GitLab instance without needing their own user account. It provides a unique email address for end users to create issues in a project, and replies can be sent either through the GitLab interface or by email. End users will only see the thread through email."
msgstr ""
msgid "GitLab Shared Runners execute code of different projects on the same Runner unless you configure GitLab Runner Autoscale with MaxBuilds 1 (which it is on GitLab.com)."
msgstr ""
+msgid "GitLab Shell"
+msgstr ""
+
msgid "GitLab Support Bot"
msgstr ""
@@ -11540,7 +11890,7 @@ msgstr ""
msgid "GitLab User"
msgstr ""
-msgid "GitLab allows you to continue using your license even if you exceed the number of seats you purchased. You will be required to pay for these seats when you renew your license."
+msgid "GitLab Workhorse"
msgstr ""
msgid "GitLab commit"
@@ -11708,6 +12058,21 @@ msgstr ""
msgid "Gitlab Pages"
msgstr ""
+msgid "Gitpod"
+msgstr ""
+
+msgid "Gitpod|Add the URL to your Gitpod instance configured to read your GitLab projects."
+msgstr ""
+
+msgid "Gitpod|Enable Gitpod integration"
+msgstr ""
+
+msgid "Gitpod|Gitpod URL"
+msgstr ""
+
+msgid "Gitpod|e.g. https://gitpod.example.com"
+msgstr ""
+
msgid "Given access %{time_ago}"
msgstr ""
@@ -12215,9 +12580,6 @@ msgstr ""
msgid "GroupSAML|Valid SAML Response"
msgstr ""
-msgid "GroupSAML|With group managed accounts enabled, all the users without a group managed account will be excluded from the group."
-msgstr ""
-
msgid "GroupSAML|With prohibit outer forks flag enabled group members will be able to fork project only inside your group."
msgstr ""
@@ -12431,10 +12793,10 @@ msgstr ""
msgid "GroupsNew|Create group"
msgstr ""
-msgid "GroupsNew|GitLab group export"
+msgid "GroupsNew|Import"
msgstr ""
-msgid "GroupsNew|Import"
+msgid "GroupsNew|Import a GitLab group export file"
msgstr ""
msgid "GroupsNew|Import group"
@@ -12576,6 +12938,9 @@ msgid "Hide chart"
msgid_plural "Hide charts"
msgstr[0] ""
+msgid "Hide comments on this file"
+msgstr ""
+
msgid "Hide details"
msgstr ""
@@ -12619,6 +12984,15 @@ msgstr ""
msgid "Highest role:"
msgstr ""
+msgid "HighlightBar|Alert events:"
+msgstr ""
+
+msgid "HighlightBar|Alert start time:"
+msgstr ""
+
+msgid "HighlightBar|Original alert:"
+msgstr ""
+
msgid "History"
msgstr ""
@@ -12796,6 +13170,9 @@ msgstr ""
msgid "If enabled, access to projects will be validated on an external service using their classification label."
msgstr ""
+msgid "If the number of active users exceeds the user limit, you will be charged for the number of %{users_over_license_link} at your next license reconciliation."
+msgstr ""
+
msgid "If there is no previous license or if the previous license has expired, some GitLab functionality will be blocked until a new, valid license is uploaded."
msgstr ""
@@ -12835,9 +13212,6 @@ msgstr ""
msgid "If your HTTP repository is not publicly accessible, add your credentials."
msgstr ""
-msgid "Iglu registry URL (optional)"
-msgstr ""
-
msgid "Ignore"
msgstr ""
@@ -12874,6 +13248,14 @@ msgstr ""
msgid "Import"
msgstr ""
+msgid "Import %d compatible repository"
+msgid_plural "Import %d compatible repositories"
+msgstr[0] ""
+
+msgid "Import %d repository"
+msgid_plural "Import %d repositories"
+msgstr[0] ""
+
msgid "Import CSV"
msgstr ""
@@ -12883,15 +13265,9 @@ msgstr ""
msgid "Import all compatible projects"
msgstr ""
-msgid "Import all compatible repositories"
-msgstr ""
-
msgid "Import all projects"
msgstr ""
-msgid "Import all repositories"
-msgstr ""
-
msgid "Import an exported GitLab project"
msgstr ""
@@ -12979,6 +13355,9 @@ msgstr ""
msgid "ImportProjects|Error importing repository %{project_safe_import_url} into %{project_full_path} - %{message}"
msgstr ""
+msgid "ImportProjects|Import repositories"
+msgstr ""
+
msgid "ImportProjects|Importing the project failed"
msgstr ""
@@ -12991,7 +13370,7 @@ msgstr ""
msgid "ImportProjects|Requesting your %{provider} repositories failed"
msgstr ""
-msgid "ImportProjects|Select the projects you want to import"
+msgid "ImportProjects|Select the repositories you want to import"
msgstr ""
msgid "ImportProjects|The remote data could not be imported."
@@ -13027,9 +13406,6 @@ msgstr ""
msgid "In order to enable Service Desk for your instance, you must first set up incoming email."
msgstr ""
-msgid "In order to gather accurate feature usage data, it can take 1 to 2 weeks to see your index."
-msgstr ""
-
msgid "In order to personalize your experience with GitLab%{br_tag}we would like to know a bit more about you."
msgstr ""
@@ -13060,18 +13436,30 @@ msgstr ""
msgid "IncidentManagement|Create incident"
msgstr ""
+msgid "IncidentManagement|Critical - S1"
+msgstr ""
+
msgid "IncidentManagement|Date created"
msgstr ""
msgid "IncidentManagement|Display your incidents in a dedicated view"
msgstr ""
+msgid "IncidentManagement|High - S2"
+msgstr ""
+
msgid "IncidentManagement|Incident"
msgstr ""
msgid "IncidentManagement|Incidents"
msgstr ""
+msgid "IncidentManagement|Low - S4"
+msgstr ""
+
+msgid "IncidentManagement|Medium - S3"
+msgstr ""
+
msgid "IncidentManagement|No incidents to display."
msgstr ""
@@ -13084,6 +13472,9 @@ msgstr ""
msgid "IncidentManagement|Published to status page"
msgstr ""
+msgid "IncidentManagement|Severity"
+msgstr ""
+
msgid "IncidentManagement|There are no closed incidents"
msgstr ""
@@ -13093,6 +13484,9 @@ msgstr ""
msgid "IncidentManagement|Unassigned"
msgstr ""
+msgid "IncidentManagement|Unknown"
+msgstr ""
+
msgid "IncidentManagement|Unpublished"
msgstr ""
@@ -13114,6 +13508,15 @@ msgstr ""
msgid "Incidents"
msgstr ""
+msgid "Incident|Alert details"
+msgstr ""
+
+msgid "Incident|Summary"
+msgstr ""
+
+msgid "Incident|There was an issue loading alert data. Please try again."
+msgstr ""
+
msgid "Include a Terms of Service agreement and Privacy Policy that all users must accept."
msgstr ""
@@ -13174,6 +13577,9 @@ msgstr ""
msgid "Information about additional Pages templates and how to install them can be found in our %{pages_getting_started_guide}."
msgstr ""
+msgid "Inherited"
+msgstr ""
+
msgid "Inherited:"
msgstr ""
@@ -13253,7 +13659,22 @@ msgstr ""
msgid "Instance administrators group already exists"
msgstr ""
-msgid "Instance license"
+msgid "InstanceStatistics|Groups"
+msgstr ""
+
+msgid "InstanceStatistics|Issues"
+msgstr ""
+
+msgid "InstanceStatistics|Merge Requests"
+msgstr ""
+
+msgid "InstanceStatistics|Pipelines"
+msgstr ""
+
+msgid "InstanceStatistics|Projects"
+msgstr ""
+
+msgid "InstanceStatistics|Users"
msgstr ""
msgid "Integration"
@@ -13265,6 +13686,12 @@ msgstr ""
msgid "Integrations"
msgstr ""
+msgid "Integrations|%{integration} settings saved and active."
+msgstr ""
+
+msgid "Integrations|%{integration} settings saved, but not active."
+msgstr ""
+
msgid "Integrations|All details"
msgstr ""
@@ -13274,6 +13701,12 @@ msgstr ""
msgid "Integrations|Comment settings:"
msgstr ""
+msgid "Integrations|Connection failed. Please check your settings."
+msgstr ""
+
+msgid "Integrations|Connection successful."
+msgstr ""
+
msgid "Integrations|Default settings are inherited from the group level."
msgstr ""
@@ -13289,6 +13722,15 @@ msgstr ""
msgid "Integrations|Includes commit title and branch"
msgstr ""
+msgid "Integrations|Projects using custom settings will not be impacted unless the project owner chooses to use instance-level defaults."
+msgstr ""
+
+msgid "Integrations|Save settings?"
+msgstr ""
+
+msgid "Integrations|Saving will update the default settings for all projects that are not using custom settings."
+msgstr ""
+
msgid "Integrations|Standard"
msgstr ""
@@ -13421,6 +13863,9 @@ msgstr ""
msgid "Invitation"
msgstr ""
+msgid "Invitation declined"
+msgstr ""
+
msgid "Invite"
msgstr ""
@@ -13472,6 +13917,42 @@ 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|%{linkStart}Read more%{linkEnd} about role permissions"
+msgstr ""
+
+msgid "InviteMembersModal|Access expiration date (optional)"
+msgstr ""
+
+msgid "InviteMembersModal|Cancel"
+msgstr ""
+
+msgid "InviteMembersModal|Choose a role permission"
+msgstr ""
+
+msgid "InviteMembersModal|GitLab member or Email address"
+msgstr ""
+
+msgid "InviteMembersModal|Invite"
+msgstr ""
+
+msgid "InviteMembersModal|Invite team members"
+msgstr ""
+
+msgid "InviteMembersModal|Search for members to invite"
+msgstr ""
+
+msgid "InviteMembersModal|User not invited. Feature coming soon!"
+msgstr ""
+
+msgid "InviteMembersModal|Users were succesfully added"
+msgstr ""
+
+msgid "InviteMembersModal|You're inviting members to the %{group_name} group"
+msgstr ""
+
+msgid "InviteMembers|Invite team members"
+msgstr ""
+
msgid "Invited"
msgstr ""
@@ -13526,10 +14007,13 @@ msgstr ""
msgid "Issue cannot be found."
msgstr ""
+msgid "Issue created from vulnerability %{vulnerability_link}"
+msgstr ""
+
msgid "Issue events"
msgstr ""
-msgid "Issue first depoloyed to production"
+msgid "Issue first deployed to production"
msgstr ""
msgid "Issue label"
@@ -13607,6 +14091,9 @@ msgstr ""
msgid "IssueTracker|Custom issue tracker"
msgstr ""
+msgid "IssueTracker|EWM work items tracker"
+msgstr ""
+
msgid "IssueTracker|Redmine issue tracker"
msgstr ""
@@ -13673,6 +14160,9 @@ msgstr ""
msgid "It looks like you have some draft commits in this branch."
msgstr ""
+msgid "It may be several days before you see feature usage data."
+msgstr ""
+
msgid "It must have a header row and at least two columns: the first column is the issue title and the second column is the issue description. The separator is automatically detected."
msgstr ""
@@ -13955,13 +14445,13 @@ msgstr ""
msgid "Join Zoom meeting"
msgstr ""
-msgid "Jul"
+msgid "Joined %{time_ago}"
msgstr ""
-msgid "July"
+msgid "Jul"
msgstr ""
-msgid "Jump to first unresolved thread"
+msgid "July"
msgstr ""
msgid "Jump to next unresolved thread"
@@ -13997,6 +14487,9 @@ msgstr ""
msgid "Keyboard shortcuts"
msgstr ""
+msgid "KeyboardKey|Ctrl+"
+msgstr ""
+
msgid "Keys"
msgstr ""
@@ -14045,6 +14538,9 @@ msgstr ""
msgid "LDAP Synchronization"
msgstr ""
+msgid "LDAP group settings"
+msgstr ""
+
msgid "LDAP settings"
msgstr ""
@@ -14054,6 +14550,9 @@ msgstr ""
msgid "LDAP sync in progress. This could take a few minutes. Refresh the page to see the changes."
msgstr ""
+msgid "LDAP synchronizations"
+msgstr ""
+
msgid "LFS"
msgstr ""
@@ -14133,7 +14632,16 @@ msgid "Last %d day"
msgid_plural "Last %d days"
msgstr[0] ""
-msgid "Last %{days} days"
+msgid "Last 2 weeks"
+msgstr ""
+
+msgid "Last 30 days"
+msgstr ""
+
+msgid "Last 60 days"
+msgstr ""
+
+msgid "Last 90 days"
msgstr ""
msgid "Last Accessed On"
@@ -14211,6 +14719,9 @@ msgstr ""
msgid "Last used on:"
msgstr ""
+msgid "Last week"
+msgstr ""
+
msgid "LastCommit|authored"
msgstr ""
@@ -14226,6 +14737,9 @@ msgstr ""
msgid "Latest pipeline for the most recent commit on this branch"
msgstr ""
+msgid "Launch a ready-to-code development environment for your project."
+msgstr ""
+
msgid "Lead"
msgstr ""
@@ -14599,6 +15113,9 @@ msgstr ""
msgid "List of all merge commits"
msgstr ""
+msgid "List options"
+msgstr ""
+
msgid "List settings"
msgstr ""
@@ -14611,9 +15128,6 @@ msgstr ""
msgid "List your Bitbucket Server repositories"
msgstr ""
-msgid "Lists"
-msgstr ""
-
msgid "Live preview"
msgstr ""
@@ -14860,6 +15374,12 @@ msgstr ""
msgid "Mark as done"
msgstr ""
+msgid "Mark as draft"
+msgstr ""
+
+msgid "Mark as ready"
+msgstr ""
+
msgid "Mark as resolved"
msgstr ""
@@ -14881,6 +15401,24 @@ msgstr ""
msgid "Markdown is supported"
msgstr ""
+msgid "MarkdownEditor|Add a link (%{modifierKey}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add a link (%{modifier_key}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifierKey}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifier_key}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifierKey}I)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifier_key}I)"
+msgstr ""
+
msgid "Marked For Deletion At - %{deletion_time}"
msgstr ""
@@ -14965,7 +15503,25 @@ msgstr ""
msgid "Max access level"
msgstr ""
-msgid "Max seats used"
+msgid "Max role"
+msgstr ""
+
+msgid "Max size 15 MB"
+msgstr ""
+
+msgid "Maximum Conan package file size in bytes"
+msgstr ""
+
+msgid "Maximum Maven package file size in bytes"
+msgstr ""
+
+msgid "Maximum NPM package file size in bytes"
+msgstr ""
+
+msgid "Maximum NuGet package file size in bytes"
+msgstr ""
+
+msgid "Maximum PyPI package file size in bytes"
msgstr ""
msgid "Maximum Users:"
@@ -15097,6 +15653,18 @@ msgstr ""
msgid "Members with access to %{strong_start}%{group_name}%{strong_end}"
msgstr ""
+msgid "Members|%{time} by %{user}"
+msgstr ""
+
+msgid "Members|Expired"
+msgstr ""
+
+msgid "Members|No expiration set"
+msgstr ""
+
+msgid "Members|in %{time}"
+msgstr ""
+
msgid "Memory Usage"
msgstr ""
@@ -15283,9 +15851,6 @@ msgstr ""
msgid "MergeRequests|Thread will be unresolved"
msgstr ""
-msgid "MergeRequests|Toggle comments for this file"
-msgstr ""
-
msgid "MergeRequests|View file @ %{commitId}"
msgstr ""
@@ -15346,6 +15911,9 @@ msgstr ""
msgid "Merging immediately isn't recommended as it may negatively impact the existing merge train. Read the %{docsLinkStart}documentation%{docsLinkEnd} for more information."
msgstr ""
+msgid "Message"
+msgstr ""
+
msgid "Messages"
msgstr ""
@@ -15729,18 +16297,12 @@ msgid "Milestone"
msgid_plural "Milestones"
msgstr[0] ""
-msgid "Milestone does not support burnup charts"
-msgstr ""
-
msgid "Milestone lists not available with your current license"
msgstr ""
msgid "Milestone lists show all issues from the selected milestone."
msgstr ""
-msgid "Milestone must have a start and due date"
-msgstr ""
-
msgid "MilestoneSidebar|Closed:"
msgstr ""
@@ -16107,6 +16669,9 @@ msgstr ""
msgid "Namespace"
msgstr ""
+msgid "Namespace ID:"
+msgstr ""
+
msgid "Namespace is empty"
msgstr ""
@@ -16191,6 +16756,9 @@ msgstr ""
msgid "NetworkPolicies|Allow all outbound traffic from %{selector} to %{ruleSelector} on %{ports}"
msgstr ""
+msgid "NetworkPolicies|Are you sure you want to delete this policy? This action cannot be undone."
+msgstr ""
+
msgid "NetworkPolicies|Choose whether to enforce this policy."
msgstr ""
@@ -16200,12 +16768,21 @@ msgstr ""
msgid "NetworkPolicies|Define this policy's location, conditions and actions."
msgstr ""
+msgid "NetworkPolicies|Delete policy"
+msgstr ""
+
+msgid "NetworkPolicies|Delete policy: %{policy}"
+msgstr ""
+
msgid "NetworkPolicies|Deny all traffic"
msgstr ""
msgid "NetworkPolicies|Description"
msgstr ""
+msgid "NetworkPolicies|Edit policy"
+msgstr ""
+
msgid "NetworkPolicies|Editor mode"
msgstr ""
@@ -16233,6 +16810,9 @@ msgstr ""
msgid "NetworkPolicies|Name"
msgstr ""
+msgid "NetworkPolicies|Namespace"
+msgstr ""
+
msgid "NetworkPolicies|Network Policy"
msgstr ""
@@ -16284,6 +16864,9 @@ msgstr ""
msgid "NetworkPolicies|Rules"
msgstr ""
+msgid "NetworkPolicies|Save changes"
+msgstr ""
+
msgid "NetworkPolicies|Something went wrong, failed to update policy"
msgstr ""
@@ -16296,6 +16879,9 @@ msgstr ""
msgid "NetworkPolicies|Traffic that does not match any rule will be blocked."
msgstr ""
+msgid "NetworkPolicies|Unable to parse policy"
+msgstr ""
+
msgid "NetworkPolicies|YAML editor"
msgstr ""
@@ -16408,6 +16994,9 @@ msgstr ""
msgid "New Snippet"
msgstr ""
+msgid "New Test Case"
+msgstr ""
+
msgid "New User"
msgstr ""
@@ -16507,6 +17096,9 @@ msgstr ""
msgid "New tag"
msgstr ""
+msgid "New test case"
+msgstr ""
+
msgid "New users set to external"
msgstr ""
@@ -16579,7 +17171,7 @@ msgstr ""
msgid "No changes"
msgstr ""
-msgid "No changes between %{ref_start}%{source_branch}%{ref_end} and %{ref_start}%{target_branch}%{ref_end}"
+msgid "No changes between %{sourceBranch} and %{targetBranch}"
msgstr ""
msgid "No child epics match applied filters"
@@ -16594,6 +17186,9 @@ msgstr ""
msgid "No containers available"
msgstr ""
+msgid "No content to show"
+msgstr ""
+
msgid "No contributions"
msgstr ""
@@ -16669,9 +17264,6 @@ msgstr ""
msgid "No license. All rights reserved"
msgstr ""
-msgid "No licenses found."
-msgstr ""
-
msgid "No matches found"
msgstr ""
@@ -16684,6 +17276,9 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No members found"
+msgstr ""
+
msgid "No merge requests found"
msgstr ""
@@ -16705,6 +17300,9 @@ msgstr ""
msgid "No parent group"
msgstr ""
+msgid "No plan"
+msgstr ""
+
msgid "No pods available"
msgstr ""
@@ -16801,6 +17399,12 @@ msgstr ""
msgid "Not Implemented"
msgstr ""
+msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+msgstr ""
+
+msgid "Not all browsers support WebAuthn. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even from an unsupported browser."
+msgstr ""
+
msgid "Not all data has been processed yet, the accuracy of the chart for the selected timeframe is limited."
msgstr ""
@@ -16897,6 +17501,9 @@ msgstr ""
msgid "Notification settings saved"
msgstr ""
+msgid "NotificationEvent|Change reviewer merge request"
+msgstr ""
+
msgid "NotificationEvent|Close issue"
msgstr ""
@@ -17059,10 +17666,7 @@ msgstr ""
msgid "On track"
msgstr ""
-msgid "OnDemandScans|Attached branch"
-msgstr ""
-
-msgid "OnDemandScans|Attached branch is where the scan job runs."
+msgid "OnDemandScans|Could not fetch scanner profiles. Please refresh the page, or try again later."
msgstr ""
msgid "OnDemandScans|Could not fetch site profiles. Please refresh the page, or try again later."
@@ -17071,6 +17675,9 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
+msgid "OnDemandScans|Create a new scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Create a new site profile"
msgstr ""
@@ -17083,6 +17690,9 @@ msgstr ""
msgid "OnDemandScans|New on-demand DAST scan"
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 ""
@@ -17092,16 +17702,10 @@ msgstr ""
msgid "OnDemandScans|On-demand scans run outside the DevOps cycle and find vulnerabilities in your projects. %{learnMoreLinkStart}Learn more%{learnMoreLinkEnd}"
msgstr ""
-msgid "OnDemandScans|Only a passive scan can be performed on demand."
-msgstr ""
-
-msgid "OnDemandScans|Passive"
-msgstr ""
-
msgid "OnDemandScans|Run scan"
msgstr ""
-msgid "OnDemandScans|Scan mode"
+msgid "OnDemandScans|Scanner profile"
msgstr ""
msgid "OnDemandScans|Scanner settings"
@@ -17113,9 +17717,15 @@ msgstr ""
msgid "OnDemandScans|Select one of the existing profiles"
msgstr ""
+msgid "OnDemandScans|Site profile"
+msgstr ""
+
msgid "OnDemandScans|Site profiles"
msgstr ""
+msgid "OnDemandScans|Use existing scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Use existing site profile"
msgstr ""
@@ -17213,9 +17823,6 @@ msgstr ""
msgid "Open Selection"
msgstr ""
-msgid "Open Web IDE"
-msgstr ""
-
msgid "Open comment type dropdown"
msgstr ""
@@ -17321,6 +17928,9 @@ msgstr ""
msgid "Origin"
msgstr ""
+msgid "Orphaned member"
+msgstr ""
+
msgid "Other Labels"
msgstr ""
@@ -17336,6 +17946,9 @@ msgstr ""
msgid "Other visibility settings have been disabled by the administrator."
msgstr ""
+msgid "Our documentation includes an example DevOps Score report."
+msgstr ""
+
msgid "Out-of-compliance with this project's policies and should be removed"
msgstr ""
@@ -17360,6 +17973,9 @@ msgstr ""
msgid "Overwrite diverged branches"
msgstr ""
+msgid "Owned by %{image_tag}"
+msgstr ""
+
msgid "Owned by anyone"
msgstr ""
@@ -17381,6 +17997,9 @@ msgstr ""
msgid "Package deleted successfully"
msgstr ""
+msgid "Package file size limits"
+msgstr ""
+
msgid "Package recipe already exists"
msgstr ""
@@ -17396,9 +18015,6 @@ msgstr ""
msgid "Package type must be PyPi"
msgstr ""
-msgid "Package was removed"
-msgstr ""
-
msgid "PackageRegistry|%{name} version %{version} was created %{datetime}"
msgstr ""
@@ -17540,12 +18156,18 @@ msgstr ""
msgid "PackageRegistry|NuGet Command"
msgstr ""
+msgid "PackageRegistry|Package Registry"
+msgstr ""
+
msgid "PackageRegistry|Pip Command"
msgstr ""
msgid "PackageRegistry|Pipeline %{link} triggered %{datetime} by %{author}"
msgstr ""
+msgid "PackageRegistry|Publish and share packages for a variety of common package managers. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "PackageRegistry|Published to the %{project} Package Registry %{datetime}"
msgstr ""
@@ -17645,6 +18267,9 @@ msgstr ""
msgid "Page not found"
msgstr ""
+msgid "Page settings"
+msgstr ""
+
msgid "Page was successfully deleted"
msgstr ""
@@ -17786,7 +18411,7 @@ msgstr ""
msgid "Paste issue link"
msgstr ""
-msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Don't use your private SSH key."
+msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Do not paste your private SSH key, as that can compromise your identity."
msgstr ""
msgid "Patch to apply"
@@ -17813,6 +18438,9 @@ msgstr ""
msgid "Pending"
msgstr ""
+msgid "Pending comments"
+msgstr ""
+
msgid "People without permission will never get a notification and won't be able to comment."
msgstr ""
@@ -18011,6 +18639,9 @@ msgstr ""
msgid "Pipelines|Build with confidence"
msgstr ""
+msgid "Pipelines|By revoking a trigger you will break any processes making use of it. Are you sure?"
+msgstr ""
+
msgid "Pipelines|CI Lint"
msgstr ""
@@ -18023,6 +18654,15 @@ msgstr ""
msgid "Pipelines|Continuous Integration can help catch bugs by running your tests automatically, while Continuous Deployment can help you deliver code to your product environment."
msgstr ""
+msgid "Pipelines|Copy trigger token"
+msgstr ""
+
+msgid "Pipelines|Description"
+msgstr ""
+
+msgid "Pipelines|Edit"
+msgstr ""
+
msgid "Pipelines|Get started with Pipelines"
msgstr ""
@@ -18038,15 +18678,27 @@ msgstr ""
msgid "Pipelines|It is recommended the code is reviewed thoroughly before running this pipeline with the parent project's CI resource."
msgstr ""
+msgid "Pipelines|Last Used"
+msgstr ""
+
msgid "Pipelines|Loading Pipelines"
msgstr ""
msgid "Pipelines|More Information"
msgstr ""
+msgid "Pipelines|No triggers have been created yet. Add one using the form above."
+msgstr ""
+
+msgid "Pipelines|Owner"
+msgstr ""
+
msgid "Pipelines|Project cache successfully reset."
msgstr ""
+msgid "Pipelines|Revoke"
+msgstr ""
+
msgid "Pipelines|Run Pipeline"
msgstr ""
@@ -18071,6 +18723,15 @@ msgstr ""
msgid "Pipelines|This project is not currently set up to run pipelines."
msgstr ""
+msgid "Pipelines|Token"
+msgstr ""
+
+msgid "Pipelines|Trigger user has insufficient permissions to project"
+msgstr ""
+
+msgid "Pipelines|invalid"
+msgstr ""
+
msgid "Pipelines|parent"
msgstr ""
@@ -18329,10 +18990,10 @@ msgstr ""
msgid "Please provide attributes to update"
msgstr ""
-msgid "Please refer to %{docs_url}"
+msgid "Please reach out if you have any questions and we'll be happy to assist."
msgstr ""
-msgid "Please retype the email address."
+msgid "Please refer to %{docs_url}"
msgstr ""
msgid "Please select"
@@ -18362,6 +19023,9 @@ msgstr ""
msgid "Please set a new password before proceeding."
msgstr ""
+msgid "Please share your feedback about %{featureName} %{linkStart}in this issue%{linkEnd} to help us improve the experience."
+msgstr ""
+
msgid "Please solve the reCAPTCHA"
msgstr ""
@@ -18665,6 +19329,9 @@ msgstr ""
msgid "Profiles| You are going to change the username %{currentUsernameBold} to %{newUsernameBold}. Profile and projects will be redirected to the %{newUsername} namespace but this redirect will expire once the %{currentUsername} namespace is registered by another user or group. Please update your Git repository remotes as soon as possible."
msgstr ""
+msgid "Profiles|%{provider} Active"
+msgstr ""
+
msgid "Profiles|@username"
msgstr ""
@@ -18716,7 +19383,7 @@ msgstr ""
msgid "Profiles|Commit email"
msgstr ""
-msgid "Profiles|Connect"
+msgid "Profiles|Connect %{provider}"
msgstr ""
msgid "Profiles|Connected Accounts"
@@ -18740,6 +19407,9 @@ msgstr ""
msgid "Profiles|Disconnect"
msgstr ""
+msgid "Profiles|Disconnect %{provider}"
+msgstr ""
+
msgid "Profiles|Do not show on profile"
msgstr ""
@@ -18764,7 +19434,7 @@ msgstr ""
msgid "Profiles|Full name"
msgstr ""
-msgid "Profiles|Give your individual key a title. This will be publically visible."
+msgid "Profiles|Give your individual key a title."
msgstr ""
msgid "Profiles|Include private contributions on my profile"
@@ -18854,7 +19524,7 @@ msgstr ""
msgid "Profiles|The maximum file size allowed is 200KB."
msgstr ""
-msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it?"
+msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it? It will be publicly visible."
msgstr ""
msgid "Profiles|This email will be displayed on your public profile"
@@ -18929,6 +19599,9 @@ msgstr ""
msgid "Profiles|You don't have access to delete this user."
msgstr ""
+msgid "Profiles|You must transfer ownership or delete groups you are an owner of before you can delete your account"
+msgstr ""
+
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
@@ -19517,6 +20190,9 @@ msgstr ""
msgid "ProjectTemplates|GitLab Cluster Management"
msgstr ""
+msgid "ProjectTemplates|Gitpod/Spring Petclinic"
+msgstr ""
+
msgid "ProjectTemplates|Go Micro"
msgstr ""
@@ -20126,6 +20802,9 @@ msgstr ""
msgid "Publish to status page"
msgstr ""
+msgid "Published"
+msgstr ""
+
msgid "Published on status page"
msgstr ""
@@ -20243,9 +20922,15 @@ msgstr ""
msgid "Quick range"
msgstr ""
+msgid "Quickly and easily edit multiple files in your project."
+msgstr ""
+
msgid "README"
msgstr ""
+msgid "Rails"
+msgstr ""
+
msgid "Rake Tasks Help"
msgstr ""
@@ -20364,10 +21049,13 @@ msgstr ""
msgid "Register Two-Factor Authenticator"
msgstr ""
-msgid "Register U2F device"
+msgid "Register Universal Two-Factor (U2F) Device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register WebAuthn Device"
+msgstr ""
+
+msgid "Register device"
msgstr ""
msgid "Register for GitLab"
@@ -20379,9 +21067,6 @@ msgstr ""
msgid "Register with two-factor app"
msgstr ""
-msgid "Registration"
-msgstr ""
-
msgid "Registration|Checkout"
msgstr ""
@@ -20497,9 +21182,6 @@ msgstr ""
msgid "Release|Something went wrong while saving the release details"
msgstr ""
-msgid "Remediated: needs review"
-msgstr ""
-
msgid "Remediations"
msgstr ""
@@ -20605,6 +21287,9 @@ msgstr ""
msgid "Remove priority"
msgstr ""
+msgid "Remove report"
+msgstr ""
+
msgid "Remove secondary node"
msgstr ""
@@ -20617,6 +21302,12 @@ msgstr ""
msgid "Remove time estimate"
msgstr ""
+msgid "Remove user & report"
+msgstr ""
+
+msgid "Remove user from group"
+msgstr ""
+
msgid "Removed"
msgstr ""
@@ -20698,9 +21389,6 @@ msgstr ""
msgid "Removes time estimate."
msgstr ""
-msgid "Removing license…"
-msgstr ""
-
msgid "Removing this group also removes all child projects, including archived projects, and their resources."
msgstr ""
@@ -20785,6 +21473,9 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
+msgid "Reported by %{reporter}"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -20870,6 +21561,27 @@ msgstr ""
msgid "Repositories"
msgstr ""
+msgid "Repositories Analytics"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download Historic Test Coverage Data"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download historic test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Historic Test Coverage Data is available in raw format (.csv) for further analysis."
+msgstr ""
+
+msgid "RepositoriesAnalytics|Test Code Coverage"
+msgstr ""
+
+msgid "RepositoriesAnalytics|There was an error fetching the projects."
+msgstr ""
+
msgid "Repository"
msgstr ""
@@ -20948,9 +21660,15 @@ msgstr ""
msgid "Request parameter %{param} is missing."
msgstr ""
+msgid "Request review from"
+msgstr ""
+
msgid "Request to link SAML account must be authorized"
msgstr ""
+msgid "Requested"
+msgstr ""
+
msgid "Requested %{time_ago}"
msgstr ""
@@ -20969,6 +21687,9 @@ msgstr ""
msgid "Requests to these domain(s)/address(es) on the local network will be allowed when local requests from hooks and services are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 or 127.0.0.0/28 are supported. Domain wildcards are not supported currently. Use comma, semicolon, or newline to separate multiple entries. The allowlist can hold a maximum of 1000 entries. Domains should use IDNA encoding. Ex: example.com, 192.168.1.1, 127.0.0.0/28, xn--itlab-j1a.com."
msgstr ""
+msgid "Require admin approval for new sign-ups"
+msgstr ""
+
msgid "Require all users in this group to setup Two-factor authentication"
msgstr ""
@@ -21094,9 +21815,6 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
-msgid "Resolved by %{resolvedByName}"
-msgstr ""
-
msgid "Resolves IP addresses once and uses them to submit requests"
msgstr ""
@@ -21215,6 +21933,13 @@ msgstr ""
msgid "ReviewApp|Enable Review App"
msgstr ""
+msgid "Reviewer"
+msgid_plural "%d Reviewers"
+msgstr[0] ""
+
+msgid "Reviewer(s)"
+msgstr ""
+
msgid "Reviewing"
msgstr ""
@@ -21254,6 +21979,9 @@ msgstr ""
msgid "Rook"
msgstr ""
+msgid "Ruby"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -21332,6 +22060,63 @@ msgstr ""
msgid "Runners page."
msgstr ""
+msgid "Runners|Active"
+msgstr ""
+
+msgid "Runners|Architecture"
+msgstr ""
+
+msgid "Runners|Can run untagged jobs"
+msgstr ""
+
+msgid "Runners|Description"
+msgstr ""
+
+msgid "Runners|Group"
+msgstr ""
+
+msgid "Runners|IP Address"
+msgstr ""
+
+msgid "Runners|Last contact"
+msgstr ""
+
+msgid "Runners|Locked to this project"
+msgstr ""
+
+msgid "Runners|Maximum job timeout"
+msgstr ""
+
+msgid "Runners|Name"
+msgstr ""
+
+msgid "Runners|Platform"
+msgstr ""
+
+msgid "Runners|Property Name"
+msgstr ""
+
+msgid "Runners|Protected"
+msgstr ""
+
+msgid "Runners|Revision"
+msgstr ""
+
+msgid "Runners|Shared"
+msgstr ""
+
+msgid "Runners|Specific"
+msgstr ""
+
+msgid "Runners|Tags"
+msgstr ""
+
+msgid "Runners|Value"
+msgstr ""
+
+msgid "Runners|Version"
+msgstr ""
+
msgid "Runners|You have used %{quotaUsed} out of %{quotaLimit} of your shared Runners pipeline minutes."
msgstr ""
@@ -21344,6 +22129,9 @@ msgstr ""
msgid "Runs a number of housekeeping tasks within the current repository, such as compressing file revisions and removing unreachable objects."
msgstr ""
+msgid "SAML"
+msgstr ""
+
msgid "SAML SSO"
msgstr ""
@@ -21395,6 +22183,9 @@ msgstr ""
msgid "Save"
msgstr ""
+msgid "Save %{name} size limits"
+msgstr ""
+
msgid "Save Changes"
msgstr ""
@@ -21425,9 +22216,6 @@ msgstr ""
msgid "Save space and find tags in the Container Registry more easily. Enable the cleanup policy to remove stale tags and keep only the ones you need."
msgstr ""
-msgid "Save template"
-msgstr ""
-
msgid "Save variables"
msgstr ""
@@ -21470,9 +22258,6 @@ msgstr ""
msgid "Scope"
msgstr ""
-msgid "Scope not supported with disabled 'users_search' feature!"
-msgstr ""
-
msgid "Scoped issue boards"
msgstr ""
@@ -21599,9 +22384,6 @@ msgstr ""
msgid "Search requirements"
msgstr ""
-msgid "Search results…"
-msgstr ""
-
msgid "Search users"
msgstr ""
@@ -21671,6 +22453,10 @@ msgid "SearchResults|commit"
msgid_plural "SearchResults|commits"
msgstr[0] ""
+msgid "SearchResults|epic"
+msgid_plural "SearchResults|epics"
+msgstr[0] ""
+
msgid "SearchResults|issue"
msgid_plural "SearchResults|issues"
msgstr[0] ""
@@ -21708,10 +22494,10 @@ msgstr ""
msgid "Seat Link is disabled, and cannot be configured through this form."
msgstr ""
-msgid "Seats currently in use"
+msgid "Seats usage data as of %{last_enqueue_time}"
msgstr ""
-msgid "Seats in license"
+msgid "Seats usage data is updated every day at 12:00pm UTC"
msgstr ""
msgid "Secondary"
@@ -21765,6 +22551,9 @@ msgstr ""
msgid "SecurityConfiguration|Available for on-demand DAST"
msgstr ""
+msgid "SecurityConfiguration|By default, all analyzers are applied in order to cover all languages across your project, and only run if the language is detected in the Merge Request."
+msgstr ""
+
msgid "SecurityConfiguration|Configure"
msgstr ""
@@ -21795,16 +22584,19 @@ msgstr ""
msgid "SecurityConfiguration|Manage"
msgstr ""
+msgid "SecurityConfiguration|More information"
+msgstr ""
+
msgid "SecurityConfiguration|Not enabled"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|Security Control"
+msgid "SecurityConfiguration|SAST Configuration"
msgstr ""
-msgid "SecurityConfiguration|See documentation"
+msgid "SecurityConfiguration|Security Control"
msgstr ""
msgid "SecurityConfiguration|Status"
@@ -21816,6 +22608,9 @@ msgstr ""
msgid "SecurityConfiguration|Using custom settings. You won't receive automatic updates on this variable. %{anchorStart}Restore to default%{anchorEnd}"
msgstr ""
+msgid "SecurityConfiguration|View history"
+msgstr ""
+
msgid "SecurityConfiguration|You can quickly enable all security scanning tools by enabling %{linkStart}Auto DevOps%{linkEnd}."
msgstr ""
@@ -21894,9 +22689,6 @@ msgstr ""
msgid "SecurityReports|Learn more about setting up your dashboard"
msgstr ""
-msgid "SecurityReports|Load more vulnerabilities"
-msgstr ""
-
msgid "SecurityReports|Monitor vulnerabilities in your code"
msgstr ""
@@ -22176,7 +22968,7 @@ msgstr ""
msgid "Select status"
msgstr ""
-msgid "Select strategy activation method"
+msgid "Select strategy activation method."
msgstr ""
msgid "Select subscription"
@@ -22191,7 +22983,7 @@ msgstr ""
msgid "Select the custom project template source group."
msgstr ""
-msgid "Select timeframe"
+msgid "Select the environment scope for this feature flag."
msgstr ""
msgid "Select timezone"
@@ -22440,6 +23232,9 @@ msgstr ""
msgid "Set iteration"
msgstr ""
+msgid "Set limit to 0 to allow any file size."
+msgstr ""
+
msgid "Set max session time for web terminal."
msgstr ""
@@ -22518,10 +23313,13 @@ msgstr ""
msgid "Set up a %{type} Runner manually"
msgstr ""
+msgid "Set up a hardware device as a second factor to sign in."
+msgstr ""
+
msgid "Set up assertions/attributes/claims (email, first_name, last_name) and NameID according to %{docsLinkStart}the documentation %{icon}%{docsLinkEnd}"
msgstr ""
-msgid "Set up new U2F device"
+msgid "Set up new device"
msgstr ""
msgid "Set up new password"
@@ -22590,6 +23388,9 @@ msgstr ""
msgid "Sets weight to %{weight}."
msgstr ""
+msgid "Setting this to 0 means using the system default timeout value."
+msgstr ""
+
msgid "Settings"
msgstr ""
@@ -22605,6 +23406,15 @@ msgstr ""
msgid "Severity"
msgstr ""
+msgid "SeverityWidget|Severity"
+msgstr ""
+
+msgid "SeverityWidget|Severity: %{severity}"
+msgstr ""
+
+msgid "SeverityWidget|There was an error while updating severity."
+msgstr ""
+
msgid "Shards (%{shards})"
msgstr ""
@@ -22650,6 +23460,9 @@ msgstr ""
msgid "Show all requirements."
msgstr ""
+msgid "Show all test cases."
+msgstr ""
+
msgid "Show archived projects"
msgstr ""
@@ -22662,6 +23475,9 @@ msgstr ""
msgid "Show comments"
msgstr ""
+msgid "Show comments on this file"
+msgstr ""
+
msgid "Show comments only"
msgstr ""
@@ -22707,6 +23523,12 @@ msgstr ""
msgid "Show parent subgroups"
msgstr ""
+msgid "Show the Closed list"
+msgstr ""
+
+msgid "Show the Open list"
+msgstr ""
+
msgid "Show whitespace changes"
msgstr ""
@@ -22748,9 +23570,6 @@ msgstr ""
msgid "Sidebar|Assign health status"
msgstr ""
-msgid "Sidebar|Change weight"
-msgstr ""
-
msgid "Sidebar|Health status"
msgstr ""
@@ -22934,6 +23753,9 @@ msgstr ""
msgid "Snippets|Add another file %{num}/%{total}"
msgstr ""
+msgid "Snippets|Authored %{time_ago} by %{author}"
+msgstr ""
+
msgid "Snippets|Delete file"
msgstr ""
@@ -22961,6 +23783,9 @@ msgstr ""
msgid "Solution"
msgstr ""
+msgid "Some changes are not shown"
+msgstr ""
+
msgid "Some child epics may be hidden due to applied filters"
msgstr ""
@@ -23327,6 +24152,12 @@ msgstr ""
msgid "Source (branch or tag)"
msgstr ""
+msgid "Source Branch"
+msgstr ""
+
+msgid "Source branch: %{source_branch_open}%{source_branch}%{source_branch_close}"
+msgstr ""
+
msgid "Source code"
msgstr ""
@@ -23492,9 +24323,6 @@ msgstr ""
msgid "Start and due date"
msgstr ""
-msgid "Start by choosing a group to see how your team is spending time. You can then drill down to the project level."
-msgstr ""
-
msgid "Start by choosing a group to start exploring the merge requests in that group. You can then proceed to filter by projects, labels, milestones and authors."
msgstr ""
@@ -23576,18 +24404,27 @@ msgstr ""
msgid "StaticSiteEditor|3. Assign a person to review and accept the merge request."
msgstr ""
+msgid "StaticSiteEditor|A link to view the merge request will appear once ready."
+msgstr ""
+
msgid "StaticSiteEditor|An error occurred while submitting your changes."
msgstr ""
msgid "StaticSiteEditor|Branch could not be created."
msgstr ""
+msgid "StaticSiteEditor|Copy update"
+msgstr ""
+
msgid "StaticSiteEditor|Could not commit the content changes."
msgstr ""
msgid "StaticSiteEditor|Could not create merge request."
msgstr ""
+msgid "StaticSiteEditor|Creating your merge request"
+msgstr ""
+
msgid "StaticSiteEditor|Incompatible file content"
msgstr ""
@@ -23609,6 +24446,9 @@ msgstr ""
msgid "StaticSiteEditor|View documentation"
msgstr ""
+msgid "StaticSiteEditor|You can set an assignee to get your changes reviewed and deployed once your merge request is created."
+msgstr ""
+
msgid "StaticSiteEditor|Your merge request has been created"
msgstr ""
@@ -23738,15 +24578,15 @@ msgstr ""
msgid "Submit %{humanized_resource_name}"
msgstr ""
-msgid "Submit Changes"
-msgstr ""
-
msgid "Submit a review"
msgstr ""
msgid "Submit as spam"
msgstr ""
+msgid "Submit changes"
+msgstr ""
+
msgid "Submit feedback"
msgstr ""
@@ -23900,6 +24740,9 @@ msgstr ""
msgid "Successfully deleted U2F device."
msgstr ""
+msgid "Successfully deleted WebAuthn device."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -24218,9 +25061,6 @@ msgstr ""
msgid "Template to append to all Service Desk issues"
msgstr ""
-msgid "Template was successfully saved."
-msgstr ""
-
msgid "Templates"
msgstr ""
@@ -24296,10 +25136,28 @@ msgid "Test coverage: %d hit"
msgid_plural "Test coverage: %d hits"
msgstr[0] ""
-msgid "Test failed."
+msgid "Test settings"
+msgstr ""
+
+msgid "TestCases|New Test Case"
+msgstr ""
+
+msgid "TestCases|New test case"
+msgstr ""
+
+msgid "TestCases|Search test cases"
+msgstr ""
+
+msgid "TestCases|Something went wrong while creating a test case."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching count of test cases."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching test cases list."
msgstr ""
-msgid "Test settings and save changes"
+msgid "TestCases|Submit test case"
msgstr ""
msgid "TestHooks|Ensure one of your projects has merge requests."
@@ -24365,6 +25223,9 @@ msgstr ""
msgid "Thank you for signing up for your free trial! You will get additional instructions in your inbox shortly."
msgstr ""
+msgid "Thank you for your business."
+msgstr ""
+
msgid "Thank you for your feedback!"
msgstr ""
@@ -24423,9 +25284,6 @@ msgstr ""
msgid "The URL to use for connecting to Elasticsearch. Use a comma-separated list to support clustering (e.g., \"http://localhost:9200, http://localhost:9201\")."
msgstr ""
-msgid "The Web IDE offers advanced syntax highlighting capabilities and more."
-msgstr ""
-
msgid "The X509 Certificate to use when mutual TLS is required to communicate with the external authorization service. If left blank, the server certificate is still validated when accessing over HTTPS."
msgstr ""
@@ -24535,6 +25393,9 @@ msgstr ""
msgid "The form contains the following error:"
msgstr ""
+msgid "The form contains the following warning:"
+msgstr ""
+
msgid "The global settings require you to enable Two-Factor Authentication for your account."
msgstr ""
@@ -24649,9 +25510,6 @@ msgstr ""
msgid "The private key to use when a client certificate is provided. This value is encrypted at rest."
msgstr ""
-msgid "The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The project can be accessed by any logged in user."
msgstr ""
@@ -24688,7 +25546,7 @@ msgstr ""
msgid "The remote repository is being updated..."
msgstr ""
-msgid "The repository can be commited to, and issues, comments and other entities can be created."
+msgid "The repository can be committed to, and issues, comments and other entities can be created."
msgstr ""
msgid "The repository for this project does not exist."
@@ -24742,9 +25600,6 @@ msgstr ""
msgid "The time taken by each data entry gathered by that stage."
msgstr ""
-msgid "The total stage shows the time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The update action will time out after %{number_of_minutes} minutes. For big repositories, use a clone/push combination."
msgstr ""
@@ -24808,6 +25663,9 @@ msgstr ""
msgid "There are no archived requirements"
msgstr ""
+msgid "There are no archived test cases"
+msgstr ""
+
msgid "There are no changes"
msgstr ""
@@ -24847,6 +25705,9 @@ msgstr ""
msgid "There are no open requirements"
msgstr ""
+msgid "There are no open test cases"
+msgstr ""
+
msgid "There are no packages yet"
msgstr ""
@@ -24859,6 +25720,9 @@ msgstr ""
msgid "There is a limit of %{ci_project_subscriptions_limit} subscriptions from or to a project."
msgstr ""
+msgid "There is already a To-Do for this design."
+msgstr ""
+
msgid "There is already a repository with that name on disk"
msgstr ""
@@ -24877,6 +25741,9 @@ msgstr ""
msgid "There was a problem communicating with your device."
msgstr ""
+msgid "There was a problem fetching branches."
+msgstr ""
+
msgid "There was a problem fetching groups."
msgstr ""
@@ -25105,9 +25972,15 @@ msgstr ""
msgid "This action can lead to data loss. To prevent accidental actions we ask you to confirm your intention."
msgstr ""
+msgid "This action cannot be undone, and will permanently delete the %{key} SSH key"
+msgstr ""
+
msgid "This action cannot be undone. You will lose the project's repository and all content: issues, merge requests, etc."
msgstr ""
+msgid "This action has been performed too many times. Try again later."
+msgstr ""
+
msgid "This action will %{strongOpen}permanently delete%{strongClose} %{codeOpen}%{project}%{codeClose} %{strongOpen}immediately%{strongClose}, including its repositories and all content: issues, merge requests, etc."
msgstr ""
@@ -25135,9 +26008,6 @@ msgstr ""
msgid "This board's scope is reduced"
msgstr ""
-msgid "This branch has changed since you started editing. Would you like to create a new branch?"
-msgstr ""
-
msgid "This chart could not be displayed"
msgstr ""
@@ -25264,15 +26134,9 @@ msgstr ""
msgid "This is a security log of important events involving your account."
msgstr ""
-msgid "This is the author's first Merge Request to this project."
-msgstr ""
-
msgid "This is the highest peak of users on your installation since the license started."
msgstr ""
-msgid "This is the maximum number of users that have existed at the same time since the license started. This is the minimum number of seats you will need to buy when you renew your license."
-msgstr ""
-
msgid "This is the number of currently active users on your installation, and this is the minimum number you need to purchase when you renew your license."
msgstr ""
@@ -25504,6 +26368,15 @@ msgstr ""
msgid "This user has no identities"
msgstr ""
+msgid "This user has previously committed to the %{name} project."
+msgstr ""
+
+msgid "This user has the %{access} role in the %{name} project."
+msgstr ""
+
+msgid "This user is the author of this %{noteable}."
+msgstr ""
+
msgid "This user will be the author of all events in the activity feed that are the result of an update, like new branches being created or new commits being pushed to existing branches."
msgstr ""
@@ -25534,6 +26407,9 @@ msgstr ""
msgid "Threat Monitoring"
msgstr ""
+msgid "ThreatMonitoring|All Environments"
+msgstr ""
+
msgid "ThreatMonitoring|Anomalous Requests"
msgstr ""
@@ -25561,9 +26437,6 @@ msgstr ""
msgid "ThreatMonitoring|Operations Per Second"
msgstr ""
-msgid "ThreatMonitoring|Overview"
-msgstr ""
-
msgid "ThreatMonitoring|Packet Activity"
msgstr ""
@@ -25582,6 +26455,9 @@ msgstr ""
msgid "ThreatMonitoring|Something went wrong, unable to fetch statistics"
msgstr ""
+msgid "ThreatMonitoring|Statistics"
+msgstr ""
+
msgid "ThreatMonitoring|The firewall is not installed or has been disabled. To view this data, ensure the web application firewall is installed and enabled for your cluster."
msgstr ""
@@ -25971,6 +26847,9 @@ msgstr ""
msgid "To update Snippets with multiple files, you must use the `files` parameter"
msgstr ""
+msgid "To use Gitpod you must first enable the feature in the integrations section of your %{user_prefs}."
+msgstr ""
+
msgid "To view all %{scannedResourcesCount} scanned URLs, please download the CSV file"
msgstr ""
@@ -26004,9 +26883,6 @@ msgstr ""
msgid "Toggle Sidebar"
msgstr ""
-msgid "Toggle all threads"
-msgstr ""
-
msgid "Toggle backtrace"
msgstr ""
@@ -26031,9 +26907,6 @@ msgstr ""
msgid "Toggle navigation"
msgstr ""
-msgid "Toggle project"
-msgstr ""
-
msgid "Toggle sidebar"
msgstr ""
@@ -26073,6 +26946,9 @@ msgstr ""
msgid "Too many projects enabled. You will need to manage them via the console or the API."
msgstr ""
+msgid "Too much data"
+msgstr ""
+
msgid "Topics (optional)"
msgstr ""
@@ -26091,6 +26967,9 @@ msgstr ""
msgid "Total cores (CPUs)"
msgstr ""
+msgid "Total days to completion"
+msgstr ""
+
msgid "Total issues"
msgstr ""
@@ -26187,6 +27066,9 @@ msgstr ""
msgid "Trending"
msgstr ""
+msgid "Trials|Create a new group to start your GitLab Gold trial."
+msgstr ""
+
msgid "Trials|Go back to GitLab"
msgstr ""
@@ -26196,6 +27078,15 @@ msgstr ""
msgid "Trials|You can always resume this process by selecting your avatar and choosing 'Start a Gold trial'"
msgstr ""
+msgid "Trials|You can apply your trial to a new group or an existing group."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group or your personal account."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group, an existing group, or your personal account."
+msgstr ""
+
msgid "Trials|You won't get a free trial right now but you can always resume this process by clicking on your avatar and choosing 'Start a free trial'"
msgstr ""
@@ -26265,6 +27156,9 @@ msgstr ""
msgid "Try using a different search term to find the file you are looking for."
msgstr ""
+msgid "Trying to communicate with your device. Plug it in (if needed) and press the button on the device now."
+msgstr ""
+
msgid "Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now."
msgstr ""
@@ -26352,6 +27246,12 @@ msgstr ""
msgid "URL or request ID"
msgstr ""
+msgid "USER %{user} WILL BE REMOVED! Are you sure?"
+msgstr ""
+
+msgid "USER WILL BE BLOCKED! Are you sure?"
+msgstr ""
+
msgid "UTC"
msgstr ""
@@ -26409,9 +27309,6 @@ msgstr ""
msgid "Unable to load the merge request widget. Try reloading the page."
msgstr ""
-msgid "Unable to resolve"
-msgstr ""
-
msgid "Unable to save iteration. Please try again"
msgstr ""
@@ -26460,6 +27357,9 @@ msgstr ""
msgid "Undo ignore"
msgstr ""
+msgid "Unexpected error"
+msgstr ""
+
msgid "Unfortunately, your email message to GitLab could not be processed."
msgstr ""
@@ -26493,6 +27393,9 @@ msgstr ""
msgid "Unknown response text"
msgstr ""
+msgid "Unless otherwise agreed to in writing with GitLab, by clicking \"Upload License\" you agree that your use of GitLab Software is subject to the %{eula_link_start}Terms of Service%{eula_link_end}."
+msgstr ""
+
msgid "Unlimited"
msgstr ""
@@ -26859,9 +27762,6 @@ msgstr ""
msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
msgstr ""
-msgid "Use a hardware device to add the second factor of authentication."
-msgstr ""
-
msgid "Use an one time password authenticator on your mobile device or computer to enable two-factor authentication (2FA)."
msgstr ""
@@ -27135,13 +28035,13 @@ msgstr ""
msgid "Users"
msgstr ""
-msgid "Users in License:"
+msgid "Users in License"
msgstr ""
-msgid "Users or groups set as approvers in the project's or merge request's settings."
+msgid "Users in License:"
msgstr ""
-msgid "Users outside of license"
+msgid "Users or groups set as approvers in the project's or merge request's settings."
msgstr ""
msgid "Users over License:"
@@ -27159,9 +28059,6 @@ msgstr ""
msgid "Users with a Guest role or those who don't belong to a Project or Group will not use a seat from your license."
msgstr ""
-msgid "Users with a Guest role or those who don't belong to any projects or groups don't count towards seats in use."
-msgstr ""
-
msgid "UsersSelect|%{name} + %{length} more"
msgstr ""
@@ -27201,9 +28098,6 @@ msgstr ""
msgid "Validations failed."
msgstr ""
-msgid "Validity"
-msgstr ""
-
msgid "Value"
msgstr ""
@@ -27222,6 +28116,9 @@ msgstr ""
msgid "Value Stream Name"
msgstr ""
+msgid "ValueStreamAnalyticsStage|We don't have enough data to show this stage."
+msgstr ""
+
msgid "ValueStreamAnalytics|%{days}d"
msgstr ""
@@ -27476,6 +28373,9 @@ msgstr ""
msgid "VisualReviewApp|Steps 1 and 2 (and sometimes 3) are performed once by the developer before requesting feedback. Steps 3 (if necessary), 4 is performed by the reviewer each time they perform a review."
msgstr ""
+msgid "Visualization"
+msgstr ""
+
msgid "Vulnerabilities"
msgstr ""
@@ -27503,34 +28403,31 @@ msgstr ""
msgid "VulnerabilityChart|Severity"
msgstr ""
-msgid "VulnerabilityManagement|A true-positive and will fix"
-msgstr ""
-
-msgid "VulnerabilityManagement|Change status"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Confirm"
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|Confirmed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Detected %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|A true-positive and will fix"
msgstr ""
-msgid "VulnerabilityManagement|Dismiss"
+msgid "VulnerabilityManagement|Change status"
msgstr ""
-msgid "VulnerabilityManagement|Dismissed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
msgstr ""
-msgid "VulnerabilityManagement|Resolved"
+msgid "VulnerabilityManagement|Detected"
msgstr ""
-msgid "VulnerabilityManagement|Resolved %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Needs triage"
msgstr ""
msgid "VulnerabilityManagement|Something went wrong while trying to delete the comment. Please try again later."
@@ -27581,6 +28478,9 @@ msgstr ""
msgid "Vulnerability|%{scannerName} (version %{scannerVersion})"
msgstr ""
+msgid "Vulnerability|Activity"
+msgstr ""
+
msgid "Vulnerability|Class"
msgstr ""
@@ -27593,6 +28493,9 @@ msgstr ""
msgid "Vulnerability|Description"
msgstr ""
+msgid "Vulnerability|Detected"
+msgstr ""
+
msgid "Vulnerability|Evidence"
msgstr ""
@@ -27656,6 +28559,9 @@ msgstr ""
msgid "Warning: Displaying this diagram might cause performance issues on this page."
msgstr ""
+msgid "We are currently unable to fetch data for the pipeline header."
+msgstr ""
+
msgid "We are currently unable to fetch data for this graph."
msgstr ""
@@ -27695,6 +28601,12 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
+msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
+msgstr ""
+
+msgid "We would like to inform you that your subscription GitLab Enterprise Edition %{plan_name} is nearing its user limit. You have %{active_user_count} active users, which is almost at the user limit of %{maximum_user_count}."
+msgstr ""
+
msgid "We've found no vulnerabilities"
msgstr ""
@@ -27710,6 +28622,12 @@ msgstr ""
msgid "Web terminal"
msgstr ""
+msgid "WebAuthn Devices (%{length})"
+msgstr ""
+
+msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
+msgstr ""
+
msgid "WebIDE|Merge request"
msgstr ""
@@ -27848,15 +28766,9 @@ msgstr ""
msgid "Welcome to the guided GitLab tour"
msgstr ""
-msgid "Welcome to your Issue Board!"
-msgstr ""
-
msgid "Welcome to your issue board!"
msgstr ""
-msgid "We’ve been making changes to %{featureName} and we’d love your feedback %{linkStart}in this issue%{linkEnd} to help us improve the experience."
-msgstr ""
-
msgid "What are you searching for?"
msgstr ""
@@ -27875,6 +28787,9 @@ msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
msgstr ""
+msgid "When enabled, any user visiting %{host} and creating an account will have to be explicitly approved by the admin before they can login. This setting is effective only if sign-ups are enabled."
+msgstr ""
+
msgid "When enabled, any user visiting %{host} will be able to create an account."
msgstr ""
@@ -28098,6 +29013,9 @@ msgstr ""
msgid "With requirements, you can set criteria to check your products against."
msgstr ""
+msgid "With test cases, you can define conditions for your project to meet in determining quality"
+msgstr ""
+
msgid "Withdraw Access Request"
msgstr ""
@@ -28113,6 +29031,9 @@ msgstr ""
msgid "Workflow Help"
msgstr ""
+msgid "Would you like to create a new branch?"
+msgstr ""
+
msgid "Write"
msgstr ""
@@ -28134,6 +29055,9 @@ msgstr ""
msgid "Wrong extern UID provided. Make sure Auth0 is configured correctly."
msgstr ""
+msgid "YYYY-MM-DD"
+msgstr ""
+
msgid "Yes"
msgstr ""
@@ -28191,7 +29115,7 @@ msgstr ""
msgid "You are going to remove the fork relationship from %{project_full_name}. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "You are going to transfer %{project_full_name} to another owner. Are you ABSOLUTELY sure?"
+msgid "You are going to transfer %{project_full_name} to another namespace. Are you ABSOLUTELY sure?"
msgstr ""
msgid "You are going to turn off the confidentiality. This means %{strongStart}everyone%{strongEnd} will be able to see and leave a comment on this %{issuableType}."
@@ -28251,9 +29175,6 @@ msgstr ""
msgid "You can always edit this later"
msgstr ""
-msgid "You can apply your Trial to your Personal account or create a New Group."
-msgstr ""
-
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings"
msgstr ""
@@ -28275,12 +29196,18 @@ msgstr ""
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
+msgid "You can find more information about GitLab subscriptions in %{subscriptions_doc_link}."
+msgstr ""
+
msgid "You can generate an access token scoped to this project for each application to use the GitLab API."
msgstr ""
msgid "You can get started by cloning the repository or start adding files to it with one of the following options."
msgstr ""
+msgid "You can group test cases using labels. To learn about the future direction of this feature, visit %{linkStart}Quality Management direction page%{linkEnd}."
+msgstr ""
+
msgid "You can invite a new member to %{project_name} or invite another group."
msgstr ""
@@ -28296,6 +29223,9 @@ msgstr ""
msgid "You can notify the app / group or a project by sending them an email notification"
msgstr ""
+msgid "You can now close this window."
+msgstr ""
+
msgid "You can now export your security dashboard to a CSV report."
msgstr ""
@@ -28344,9 +29274,6 @@ msgstr ""
msgid "You can test your .gitlab-ci.yml in %{linkStart}CI Lint%{linkEnd}."
msgstr ""
-msgid "You can try again using %{begin_link}basic search%{end_link}"
-msgstr ""
-
msgid "You cannot access the raw file. Please wait a minute."
msgstr ""
@@ -28398,6 +29325,9 @@ msgstr ""
msgid "You don't have any U2F devices registered yet."
msgstr ""
+msgid "You don't have any WebAuthn devices registered yet."
+msgstr ""
+
msgid "You don't have any active chat names."
msgstr ""
@@ -28485,6 +29415,9 @@ msgstr ""
msgid "You must accept our Terms of Service and privacy policy in order to register an account"
msgstr ""
+msgid "You must be logged in to search across all of GitLab"
+msgstr ""
+
msgid "You must disassociate %{domain} from all clusters it is attached to before deletion."
msgstr ""
@@ -28524,7 +29457,7 @@ msgstr ""
msgid "You need to be logged in."
msgstr ""
-msgid "You need to register a two-factor authentication app before you can set up a U2F device."
+msgid "You need to register a two-factor authentication app before you can set up a device."
msgstr ""
msgid "You need to set terms to be enforced"
@@ -28542,6 +29475,9 @@ msgstr ""
msgid "You reached %{usage_in_percent} of %{namespace_name}'s storage capacity (%{used_storage} of %{storage_limit})"
msgstr ""
+msgid "You successfully declined the invitation"
+msgstr ""
+
msgid "You tried to fork %{link_to_the_project} but it failed for the following reason:"
msgstr ""
@@ -28707,10 +29643,13 @@ msgstr ""
msgid "Your U2F device did not send a valid JSON response."
msgstr ""
-msgid "Your U2F device needs to be set up. Plug it in (if not already) and click the button on the left."
+msgid "Your U2F device was registered!"
msgstr ""
-msgid "Your U2F device was registered!"
+msgid "Your WebAuthn device did not send a valid JSON response."
+msgstr ""
+
+msgid "Your WebAuthn device was registered!"
msgstr ""
msgid "Your access request to the %{source_type} has been withdrawn."
@@ -28734,6 +29673,9 @@ msgstr ""
msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
msgstr ""
+msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
+msgstr ""
+
msgid "Your changes can be committed to %{branch_name} because a merge request is open."
msgstr ""
@@ -28770,6 +29712,12 @@ msgstr ""
msgid "Your deployment services will be broken, you will need to manually fix the services after renaming."
msgstr ""
+msgid "Your device is not compatible with GitLab. Please try another device"
+msgstr ""
+
+msgid "Your device needs to be set up. Plug it in (if needed) and click the button on the left."
+msgstr ""
+
msgid "Your device was successfully set up! Give it a name and register it with the GitLab server."
msgstr ""
@@ -28882,9 +29830,6 @@ msgstr[0] ""
msgid "access:"
msgstr ""
-msgid "activated"
-msgstr ""
-
msgid "added %{created_at_timeago}"
msgstr ""
@@ -28957,9 +29902,21 @@ msgstr ""
msgid "by %{user}"
msgstr ""
+msgid "cannot be a date in the past"
+msgstr ""
+
msgid "cannot be changed if a personal project has container registry tags."
msgstr ""
+msgid "cannot be changed if shared runners are enabled"
+msgstr ""
+
+msgid "cannot be enabled because parent group does not allow it"
+msgstr ""
+
+msgid "cannot be enabled because parent group has shared Runners disabled"
+msgstr ""
+
msgid "cannot be enabled unless all domains have TLS certificates"
msgstr ""
@@ -29005,7 +29962,7 @@ msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about SAST %{linkEndTag}"
msgstr ""
-msgid "ciReport|%{linkStartTag}Learn more about Secret Scanning %{linkEndTag}"
+msgid "ciReport|%{linkStartTag}Learn more about Secret Detection %{linkEndTag}"
msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about codequality reports %{linkEndTag}"
@@ -29317,9 +30274,6 @@ msgstr ""
msgid "error"
msgstr ""
-msgid "error code:"
-msgstr ""
-
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr ""
@@ -29341,6 +30295,9 @@ msgstr ""
msgid "failed to dismiss associated finding(id=%{finding_id}): %{message}"
msgstr ""
+msgid "failed to revert associated finding(id=%{finding_id}) to detected"
+msgstr ""
+
msgid "file"
msgid_plural "files"
msgstr[0] ""
@@ -29879,6 +30836,9 @@ msgstr ""
msgid "must be a root namespace"
msgstr ""
+msgid "must be a valid IPv4 or IPv6 address"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -29915,6 +30875,9 @@ msgstr ""
msgid "no expiration"
msgstr ""
+msgid "no name set"
+msgstr ""
+
msgid "no one can merge"
msgstr ""
@@ -30088,9 +31051,6 @@ msgstr ""
msgid "security Reports|There was an error creating the merge request"
msgstr ""
-msgid "settings saved, but not activated"
-msgstr ""
-
msgid "severity|Critical"
msgstr ""
@@ -30217,9 +31177,6 @@ msgstr ""
msgid "toggle collapse"
msgstr ""
-msgid "toggle dropdown"
-msgstr ""
-
msgid "triggered"
msgstr ""
@@ -30247,6 +31204,9 @@ msgstr ""
msgid "user avatar"
msgstr ""
+msgid "user preferences"
+msgstr ""
+
msgid "username"
msgstr ""
diff --git a/locale/is_IS/gitlab.po b/locale/is_IS/gitlab.po
index 2c405448b0e..1563d7edcd4 100644
--- a/locale/is_IS/gitlab.po
+++ b/locale/is_IS/gitlab.po
@@ -14,7 +14,10 @@ msgstr ""
"X-Crowdin-Language: is\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 6\n"
-"PO-Revision-Date: 2020-09-04 23:02\n"
+"PO-Revision-Date: 2020-10-02 18:41\n"
+
+msgid " %{project_name}#%{issue_iid} &middot; opened %{issue_created} by %{author}"
+msgstr ""
msgid " %{start} to %{end}"
msgstr ""
@@ -74,6 +77,16 @@ msgstr ""
msgid "\"el\" parameter is required for createInstance()"
msgstr ""
+msgid "%d Approval"
+msgid_plural "%d Approvals"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d Package"
+msgid_plural "%d Packages"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d Scanned URL"
msgid_plural "%d Scanned URLs"
msgstr[0] ""
@@ -137,6 +150,11 @@ msgstr[1] ""
msgid "%d commits"
msgstr ""
+msgid "%d completed issue"
+msgid_plural "%d completed issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d contribution"
msgid_plural "%d contributions"
msgstr[0] ""
@@ -147,6 +165,11 @@ msgid_plural "%d days"
msgstr[0] ""
msgstr[1] ""
+msgid "%d day until tags are automatically removed"
+msgid_plural "%d days until tags are automatically removed"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d error"
msgid_plural "%d errors"
msgstr[0] ""
@@ -237,6 +260,16 @@ msgid_plural "%d more comments"
msgstr[0] ""
msgstr[1] ""
+msgid "%d open issue"
+msgid_plural "%d open issues"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d pending comment"
+msgid_plural "%d pending comments"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d personal project will be removed and cannot be restored."
msgid_plural "%d personal projects will be removed and cannot be restored."
msgstr[0] ""
@@ -252,6 +285,11 @@ msgid_plural "%d projects"
msgstr[0] ""
msgstr[1] ""
+msgid "%d project selected"
+msgid_plural "%d projects selected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d request with warnings"
msgid_plural "%d requests with warnings"
msgstr[0] ""
@@ -272,6 +310,11 @@ msgid_plural "%d tags"
msgstr[0] ""
msgstr[1] ""
+msgid "%d tag per image name"
+msgid_plural "%d tags per image name"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d unassigned issue"
msgid_plural "%d unassigned issues"
msgstr[0] ""
@@ -292,6 +335,11 @@ msgid_plural "%d vulnerabilities dismissed"
msgstr[0] ""
msgstr[1] ""
+msgid "%d warning found:"
+msgid_plural "%d warnings found:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%s additional commit has been omitted to prevent performance issues."
msgid_plural "%s additional commits have been omitted to prevent performance issues."
msgstr[0] ""
@@ -330,6 +378,9 @@ msgstr ""
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr ""
+msgid "%{completedCount} completed weight"
+msgstr ""
+
msgid "%{completedWeight} of %{totalWeight} weight completed"
msgstr ""
@@ -378,14 +429,12 @@ msgid_plural "%{count} participants"
msgstr[0] ""
msgstr[1] ""
-msgid "%{count} pending comment"
-msgid_plural "%{count} pending comments"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
+msgid "%{count} total weight"
+msgstr ""
+
msgid "%{dashboard_path} could not be found."
msgstr ""
@@ -440,6 +489,9 @@ msgstr ""
msgid "%{group_name} uses group managed accounts. You need to create a new GitLab account which will be managed by %{group_name}."
msgstr ""
+msgid "%{group_name}&%{epic_iid} &middot; opened %{epic_created} by %{author}"
+msgstr ""
+
msgid "%{host} sign-in from new location"
msgstr ""
@@ -452,7 +504,7 @@ msgstr ""
msgid "%{issuableType} will be removed! Are you sure?"
msgstr ""
-msgid "%{issuesSize} issues with a limit of %{maxIssueCount}"
+msgid "%{issuesCount} issues with a limit of %{maxIssueCount}"
msgstr ""
msgid "%{issuesSize} with a limit of %{maxIssueCount}"
@@ -485,7 +537,7 @@ msgstr ""
msgid "%{labelStart}Namespace:%{labelEnd} %{namespace}"
msgstr ""
-msgid "%{labelStart}Report Type:%{labelEnd} %{reportType}"
+msgid "%{labelStart}Scan Type:%{labelEnd} %{reportType}"
msgstr ""
msgid "%{labelStart}Scanner:%{labelEnd} %{scanner}"
@@ -682,9 +734,6 @@ msgid_plural "%{securityScanner} results are not available because a pipeline ha
msgstr[0] ""
msgstr[1] ""
-msgid "%{service_title} %{message}."
-msgstr ""
-
msgid "%{size} GiB"
msgstr ""
@@ -773,6 +822,12 @@ msgstr ""
msgid "%{timebox_name} should belong either to a project or a group."
msgstr ""
+msgid "%{timebox_type} does not support burnup charts"
+msgstr ""
+
+msgid "%{timebox_type} must have a start and due date"
+msgstr ""
+
msgid "%{title} %{operator} %{threshold}"
msgstr ""
@@ -797,7 +852,7 @@ msgstr ""
msgid "%{total} open issue weight"
msgstr ""
-msgid "%{total} open issues"
+msgid "%{total} warnings found: showing first %{warningsDisplayed}"
msgstr ""
msgid "%{usage_ping_link_start}Learn more%{usage_ping_link_end} about what information is shared with GitLab Inc."
@@ -830,9 +885,6 @@ msgstr ""
msgid "&lt; 1 hour"
msgstr ""
-msgid "&lt;no name set&gt;"
-msgstr ""
-
msgid "&lt;no scopes selected&gt;"
msgstr ""
@@ -863,6 +915,9 @@ msgstr ""
msgid "'%{name}' Value Stream created"
msgstr ""
+msgid "'%{name}' Value Stream deleted"
+msgstr ""
+
msgid "'%{name}' stage already exists"
msgstr ""
@@ -922,6 +977,9 @@ msgstr ""
msgid "+ %{numberOfHiddenAssignees} more"
msgstr ""
+msgid "+ %{numberOfHiddenReviewers} more"
+msgstr ""
+
msgid "+%d more"
msgid_plural "+%d more"
msgstr[0] ""
@@ -982,6 +1040,11 @@ msgid_plural "%d Days"
msgstr[0] ""
msgstr[1] ""
+msgid "1 Issue"
+msgid_plural "%d Issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "1 closed issue"
msgid_plural "%{issues} closed issues"
msgstr[0] ""
@@ -997,6 +1060,11 @@ msgid_plural "%d days"
msgstr[0] ""
msgstr[1] ""
+msgid "1 deploy key"
+msgid_plural "%d deploy keys"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1099,6 +1167,9 @@ msgstr ""
msgid ":%{startLine} to %{endLine}"
msgstr ""
+msgid "A %{incident_docs_start}modified issue%{incident_docs_end} to guide the resolution of incidents."
+msgstr ""
+
msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr ""
@@ -1111,6 +1182,9 @@ msgstr ""
msgid "A GitBook site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
+msgid "A Gitpod configured Webapplication in Spring and Java"
+msgstr ""
+
msgid "A Hexo site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
@@ -1282,9 +1356,15 @@ msgstr ""
msgid "Access expiration date"
msgstr ""
+msgid "Access expires"
+msgstr ""
+
msgid "Access forbidden. Check your access level."
msgstr ""
+msgid "Access granted"
+msgstr ""
+
msgid "Access requests"
msgstr ""
@@ -1294,6 +1374,9 @@ msgstr ""
msgid "Access to Pages websites are controlled based on the user's membership to a given project. By checking this box, users will be required to be logged in to have access to all Pages websites in your instance."
msgstr ""
+msgid "AccessDropdown|Deploy Keys"
+msgstr ""
+
msgid "AccessDropdown|Groups"
msgstr ""
@@ -1411,12 +1494,6 @@ msgstr ""
msgid "Active Sessions"
msgstr ""
-msgid "Active Users:"
-msgstr ""
-
-msgid "Active users"
-msgstr ""
-
msgid "Activity"
msgstr ""
@@ -1584,9 +1661,6 @@ msgstr ""
msgid "Add label(s)"
msgstr ""
-msgid "Add license"
-msgstr ""
-
msgid "Add list"
msgstr ""
@@ -1761,21 +1835,51 @@ msgstr ""
msgid "AdminArea|Bots"
msgstr ""
+msgid "AdminArea|Components"
+msgstr ""
+
msgid "AdminArea|Developer"
msgstr ""
+msgid "AdminArea|Features"
+msgstr ""
+
+msgid "AdminArea|Groups: %{number_of_groups}"
+msgstr ""
+
msgid "AdminArea|Guest"
msgstr ""
msgid "AdminArea|Included Free in license"
msgstr ""
+msgid "AdminArea|Latest groups"
+msgstr ""
+
+msgid "AdminArea|Latest projects"
+msgstr ""
+
+msgid "AdminArea|Latest users"
+msgstr ""
+
msgid "AdminArea|Maintainer"
msgstr ""
+msgid "AdminArea|New group"
+msgstr ""
+
+msgid "AdminArea|New project"
+msgstr ""
+
+msgid "AdminArea|New user"
+msgstr ""
+
msgid "AdminArea|Owner"
msgstr ""
+msgid "AdminArea|Projects: %{number_of_projects}"
+msgstr ""
+
msgid "AdminArea|Reporter"
msgstr ""
@@ -1803,6 +1907,9 @@ msgstr ""
msgid "AdminArea|Users without a Group and Project"
msgstr ""
+msgid "AdminArea|Users: %{number_of_users}"
+msgstr ""
+
msgid "AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running."
msgstr ""
@@ -1821,9 +1928,6 @@ msgstr ""
msgid "AdminProjects|Delete Project %{projectName}?"
msgstr ""
-msgid "AdminProjects|Delete project"
-msgstr ""
-
msgid "AdminSettings|Apply integration settings to all Projects"
msgstr ""
@@ -2061,21 +2165,30 @@ msgstr ""
msgid "AdminUsers|Without projects"
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 ""
msgid "AdminUsers|You cannot remove your own admin rights."
msgstr ""
+msgid "AdminUsers|You must transfer ownership or delete the groups owned by this user before you can delete their account"
+msgstr ""
+
msgid "Administration"
msgstr ""
msgid "Advanced"
msgstr ""
+msgid "Advanced Search"
+msgstr ""
+
+msgid "Advanced Search with Elasticsearch"
+msgstr ""
+
msgid "Advanced Settings"
msgstr ""
@@ -2153,6 +2266,9 @@ msgstr ""
msgid "AlertManagement|Edit"
msgstr ""
+msgid "AlertManagement|Environment"
+msgstr ""
+
msgid "AlertManagement|Events"
msgstr ""
@@ -2165,6 +2281,9 @@ msgstr ""
msgid "AlertManagement|Issue"
msgstr ""
+msgid "AlertManagement|Key"
+msgstr ""
+
msgid "AlertManagement|Low"
msgstr ""
@@ -2258,6 +2377,9 @@ msgstr ""
msgid "AlertManagement|Unknown"
msgstr ""
+msgid "AlertManagement|Value"
+msgstr ""
+
msgid "AlertManagement|View alerts in Opsgenie"
msgstr ""
@@ -2417,6 +2539,9 @@ msgstr ""
msgid "All projects"
msgstr ""
+msgid "All projects selected"
+msgstr ""
+
msgid "All security scans are enabled because %{linkStart}Auto DevOps%{linkEnd} is enabled on this project"
msgstr ""
@@ -2504,6 +2629,9 @@ msgstr ""
msgid "Almost there"
msgstr ""
+msgid "Already blocked"
+msgstr ""
+
msgid "Also called \"Issuer\" or \"Relying party trust identifier\""
msgstr ""
@@ -2558,6 +2686,9 @@ msgstr ""
msgid "An error has occurred"
msgstr ""
+msgid "An error occured while making the changes: %{error}"
+msgstr ""
+
msgid "An error occurred adding a draft to the thread."
msgstr ""
@@ -2585,12 +2716,6 @@ msgstr ""
msgid "An error occurred when toggling the notification subscription"
msgstr ""
-msgid "An error occurred when trying to resolve a comment. Please try again."
-msgstr ""
-
-msgid "An error occurred when trying to resolve a discussion. Please try again."
-msgstr ""
-
msgid "An error occurred when updating the issue weight"
msgstr ""
@@ -2606,12 +2731,6 @@ msgstr ""
msgid "An error occurred while checking group path. Please refresh and try again."
msgstr ""
-msgid "An error occurred while committing your changes."
-msgstr ""
-
-msgid "An error occurred while creating the list. Please try again."
-msgstr ""
-
msgid "An error occurred while decoding the file."
msgstr ""
@@ -2684,25 +2803,19 @@ msgstr ""
msgid "An error occurred while fetching the Service Desk address."
msgstr ""
-msgid "An error occurred while fetching the board issues. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the board lists. Please reload the page."
msgstr ""
msgid "An error occurred while fetching the board lists. Please try again."
msgstr ""
-msgid "An error occurred while fetching the board swimlanes. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the builds."
msgstr ""
msgid "An error occurred while fetching the job log."
msgstr ""
-msgid "An error occurred while fetching the job trace."
+msgid "An error occurred while fetching the job logs."
msgstr ""
msgid "An error occurred while fetching the job."
@@ -2849,9 +2962,6 @@ msgstr ""
msgid "An error occurred while saving assignees"
msgstr ""
-msgid "An error occurred while saving the template. Please check if the template exists."
-msgstr ""
-
msgid "An error occurred while searching for milestones"
msgstr ""
@@ -2870,10 +2980,10 @@ msgstr ""
msgid "An error occurred while updating approvers"
msgstr ""
-msgid "An error occurred while updating the comment"
+msgid "An error occurred while updating labels."
msgstr ""
-msgid "An error occurred while updating the list. Please try again."
+msgid "An error occurred while updating the comment"
msgstr ""
msgid "An error occurred while validating group path"
@@ -2927,6 +3037,9 @@ msgstr ""
msgid "An unknown error occurred while loading this graph."
msgstr ""
+msgid "An unknown error occurred."
+msgstr ""
+
msgid "Analytics"
msgstr ""
@@ -2960,10 +3073,10 @@ msgstr ""
msgid "Any"
msgstr ""
-msgid "Any Author"
+msgid "Any %{header}"
msgstr ""
-msgid "Any Status"
+msgid "Any Author"
msgstr ""
msgid "Any branch"
@@ -3017,6 +3130,9 @@ msgstr ""
msgid "Application ID"
msgstr ""
+msgid "Application limits saved successfully"
+msgstr ""
+
msgid "Application settings saved successfully"
msgstr ""
@@ -3226,6 +3342,9 @@ msgstr ""
msgid "Are you sure you want to close this blocked issue?"
msgstr ""
+msgid "Are you sure you want to delete \"%{name}\" Value Stream?"
+msgstr ""
+
msgid "Are you sure you want to delete %{name}?"
msgstr ""
@@ -3235,6 +3354,9 @@ msgstr ""
msgid "Are you sure you want to delete this %{typeOfComment}?"
msgstr ""
+msgid "Are you sure you want to delete this SSH key?"
+msgstr ""
+
msgid "Are you sure you want to delete this board?"
msgstr ""
@@ -3259,6 +3381,11 @@ msgstr ""
msgid "Are you sure you want to erase this build?"
msgstr ""
+msgid "Are you sure you want to import %d repository?"
+msgid_plural "Are you sure you want to import %d repositories?"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Are you sure you want to lose unsaved changes?"
msgstr ""
@@ -3268,15 +3395,15 @@ msgstr ""
msgid "Are you sure you want to merge immediately?"
msgstr ""
-msgid "Are you sure you want to permanently delete this license?"
-msgstr ""
-
msgid "Are you sure you want to re-deploy this environment?"
msgstr ""
msgid "Are you sure you want to regenerate the public key? You will have to update the public key on the remote server before mirroring will work again."
msgstr ""
+msgid "Are you sure you want to reindex?"
+msgstr ""
+
msgid "Are you sure you want to remove %{group_name}?"
msgstr ""
@@ -3304,6 +3431,9 @@ msgstr ""
msgid "Are you sure you want to revoke this nickname?"
msgstr ""
+msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
+msgstr ""
+
msgid "Are you sure you want to stop this environment?"
msgstr ""
@@ -3325,6 +3455,9 @@ msgstr ""
msgid "Are you sure? The device will be signed out of GitLab and all remember me tokens revoked."
msgstr ""
+msgid "Are you sure? This will invalidate your registered applications and U2F / WebAuthn devices."
+msgstr ""
+
msgid "Are you sure? This will invalidate your registered applications and U2F devices."
msgstr ""
@@ -3343,9 +3476,6 @@ msgstr ""
msgid "Artifacts"
msgstr ""
-msgid "As U2F devices are only supported by a few browsers, we require that you set up a two-factor authentication app before a U2F device. That way you'll always be able to log in - even when you're using an unsupported browser."
-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 ""
@@ -3539,6 +3669,9 @@ msgstr ""
msgid "AuditLogs|Target"
msgstr ""
+msgid "AuditLogs|This month"
+msgstr ""
+
msgid "AuditLogs|User Events"
msgstr ""
@@ -3578,6 +3711,9 @@ msgstr ""
msgid "Authentication via U2F device failed."
msgstr ""
+msgid "Authentication via WebAuthn device failed."
+msgstr ""
+
msgid "Author"
msgstr ""
@@ -3845,15 +3981,6 @@ msgstr ""
msgid "BambooService|You must set up automatic revision labeling and a repository trigger in Bamboo."
msgstr ""
-msgid "BatchComments|Delete all pending comments"
-msgstr ""
-
-msgid "BatchComments|Discard review?"
-msgstr ""
-
-msgid "BatchComments|You're about to discard your review which will delete all of your pending comments. The deleted comments %{strong_start}cannot%{strong_end} be restored."
-msgstr ""
-
msgid "Be careful. Changing the project's namespace can have unintended side effects."
msgstr ""
@@ -3875,6 +4002,9 @@ msgstr ""
msgid "Bi-weekly code coverage"
msgstr ""
+msgid "Billable Users:"
+msgstr ""
+
msgid "Billing"
msgstr ""
@@ -3884,7 +4014,7 @@ msgstr ""
msgid "BillingPlans|@%{user_name} you are currently using the %{plan_name} plan."
msgstr ""
-msgid "BillingPlans|Congratulations, your new trial is activated"
+msgid "BillingPlans|Congratulations, your free trial is activated."
msgstr ""
msgid "BillingPlans|If you would like to downgrade your plan please contact %{support_link_start}Customer Support%{support_link_end}."
@@ -3947,6 +4077,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Block user"
+msgstr ""
+
msgid "Blocked"
msgstr ""
@@ -3962,31 +4095,37 @@ msgstr ""
msgid "Blog"
msgstr ""
-msgid "Board name"
-msgstr ""
-
msgid "Board scope"
msgstr ""
msgid "Board scope affects which issues are displayed for anyone who visits this board"
msgstr ""
-msgid "BoardBlankState|Add default lists"
+msgid "Boards"
msgstr ""
-msgid "BoardBlankState|Add the following default lists to your Issue Board with one click:"
+msgid "Boards and Board Lists"
msgstr ""
-msgid "BoardBlankState|Nevermind, I'll use my own"
+msgid "Boards|An error occurred while creating the issue. Please try again."
msgstr ""
-msgid "BoardBlankState|Starting out with the default set of lists will get you right on the way to making the most of your board."
+msgid "Boards|An error occurred while creating the list. Please try again."
msgstr ""
-msgid "Boards"
+msgid "Boards|An error occurred while fetching issues. Please reload the page."
msgstr ""
-msgid "Boards and Board Lists"
+msgid "Boards|An error occurred while fetching the board issues. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching the board swimlanes. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while moving the issue. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while updating the list. Please try again."
msgstr ""
msgid "Boards|Collapse"
@@ -4013,7 +4152,7 @@ msgstr ""
msgid "Branch %{branch_name} was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr ""
-msgid "Branch has changed"
+msgid "Branch changed"
msgstr ""
msgid "Branch is already taken"
@@ -4319,6 +4458,9 @@ msgstr ""
msgid "CLOSED (MOVED)"
msgstr ""
+msgid "CODEOWNERS rule violation"
+msgstr ""
+
msgid "CONTRIBUTING"
msgstr ""
@@ -4349,9 +4491,6 @@ msgstr ""
msgid "Can't create snippet: %{err}"
msgstr ""
-msgid "Can't edit as source branch was deleted"
-msgstr ""
-
msgid "Can't fetch content for the blob: %{err}"
msgstr ""
@@ -4364,9 +4503,6 @@ msgstr ""
msgid "Can't load mermaid module: %{err}"
msgstr ""
-msgid "Can't remove group members without group managed account"
-msgstr ""
-
msgid "Can't scan the code?"
msgstr ""
@@ -4409,6 +4545,9 @@ msgstr ""
msgid "Cannot create the abuse report. This user has been blocked."
msgstr ""
+msgid "Cannot enable shared runners because parent group does not allow it"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -4514,6 +4653,15 @@ msgstr ""
msgid "Change your password or recover your current one"
msgstr ""
+msgid "ChangeReviewer|Reviewer changed from %{old} to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Reviewer changed to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Unassigned"
+msgstr ""
+
msgid "ChangeTypeActionLabel|Pick into branch"
msgstr ""
@@ -4553,6 +4701,9 @@ msgstr ""
msgid "Changes the title to \"%{title_param}\"."
msgstr ""
+msgid "Changes were successfully made."
+msgstr ""
+
msgid "Changes won't take place until the index is %{link_start}recreated%{link_end}."
msgstr ""
@@ -4958,6 +5109,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove variable"
+msgstr ""
+
msgid "CiVariables|Remove variable row"
msgstr ""
@@ -5036,9 +5190,6 @@ msgstr ""
msgid "Clear due date"
msgstr ""
-msgid "Clear input"
-msgstr ""
-
msgid "Clear recent searches"
msgstr ""
@@ -5087,6 +5238,9 @@ msgstr ""
msgid "Client authentication key password"
msgstr ""
+msgid "Client request timeout"
+msgstr ""
+
msgid "Clients"
msgstr ""
@@ -5171,6 +5325,27 @@ msgstr ""
msgid "Cluster type must be specificed for Stages::ClusterEndpointInserter"
msgstr ""
+msgid "ClusterAgents|Configuration"
+msgstr ""
+
+msgid "ClusterAgents|Connect your cluster with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate Kubernetes with a GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Name"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Agent also requires %{linkStart}enabling the Agent Server%{linkEnd}"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Kubernetes Agent allows an Infrastructure as Code, GitOps approach to integrating Kubernetes clusters with GitLab. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "ClusterAgent|This feature is only available for premium plans"
msgstr ""
@@ -5240,10 +5415,10 @@ msgstr ""
msgid "ClusterIntegration|All installed applications and related resources"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster."
+msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{linkStart}More information%{linkEnd}"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{startLink}More information%{endLink}"
+msgid "ClusterIntegration|Allow GitLab to manage namespaces and service accounts for this cluster."
msgstr ""
msgid "ClusterIntegration|Alternatively, "
@@ -5264,6 +5439,9 @@ msgstr ""
msgid "ClusterIntegration|An error occurred while trying to fetch zone machine types: %{error}"
msgstr ""
+msgid "ClusterIntegration|An unknown error occurred while attempting to connect to Kubernetes."
+msgstr ""
+
msgid "ClusterIntegration|Any project namespaces"
msgstr ""
@@ -5279,6 +5457,9 @@ msgstr ""
msgid "ClusterIntegration|Authenticate with Amazon Web Services"
msgstr ""
+msgid "ClusterIntegration|Authentication Error"
+msgstr ""
+
msgid "ClusterIntegration|Base domain"
msgstr ""
@@ -5297,13 +5478,22 @@ msgstr ""
msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}security group %{externalLinkIcon} %{endLink} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
+msgid "ClusterIntegration|Check your CA certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Check your cluster status"
+msgstr ""
+
+msgid "ClusterIntegration|Check your token"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}subnets %{externalLinkIcon} %{endLink} in your VPC where your worker nodes will run."
+msgid "ClusterIntegration|Choose the %{linkStart}security group %{linkEnd} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
msgstr ""
-msgid "ClusterIntegration|Choose the worker node %{startLink}instance type %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Choose the %{linkStart}subnets %{linkEnd} in your VPC where your worker nodes will run."
+msgstr ""
+
+msgid "ClusterIntegration|Choose the worker node %{linkStart}instance type%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Choose which applications to install on your Kubernetes cluster."
@@ -5315,10 +5505,7 @@ msgstr ""
msgid "ClusterIntegration|Clear cluster cache"
msgstr ""
-msgid "ClusterIntegration|Clear the local cache of namespace and service accounts. This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
-msgstr ""
-
-msgid "ClusterIntegration|Cluster being created"
+msgid "ClusterIntegration|Clear the local cache of namespace and service accounts."
msgstr ""
msgid "ClusterIntegration|Cluster management project (alpha)"
@@ -5330,15 +5517,21 @@ msgstr ""
msgid "ClusterIntegration|Cluster_applications artifact too big. Maximum allowable size: %{human_size}"
msgstr ""
-msgid "ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters."
+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|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}"
+msgid "ClusterIntegration|Clusters connected with a certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Connect cluster with certificate"
msgstr ""
msgid "ClusterIntegration|Connect existing cluster"
msgstr ""
+msgid "ClusterIntegration|Connection Error"
+msgstr ""
+
msgid "ClusterIntegration|Copy API URL"
msgstr ""
@@ -5414,6 +5607,12 @@ msgstr ""
msgid "ClusterIntegration|Deletes all GitLab resources attached to this cluster during removal"
msgstr ""
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared."
+msgstr ""
+
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared. %{linkStart}More information%{linkEnd}"
+msgstr ""
+
msgid "ClusterIntegration|Did you know?"
msgstr ""
@@ -5483,6 +5682,9 @@ msgstr ""
msgid "ClusterIntegration|Fluentd is an open source data collector, which lets you unify the data collection and consumption for a better use and understanding of data. It requires at least one of the following logs to be successfully installed."
msgstr ""
+msgid "ClusterIntegration|GitLab Agent managed clusters"
+msgstr ""
+
msgid "ClusterIntegration|GitLab Container Network Policies"
msgstr ""
@@ -5495,6 +5697,12 @@ msgstr ""
msgid "ClusterIntegration|GitLab Runner connects to the repository and executes CI/CD jobs, pushing results back and deploying applications to production."
msgstr ""
+msgid "ClusterIntegration|GitLab failed to authenticate."
+msgstr ""
+
+msgid "ClusterIntegration|GitLab failed to connect to the cluster."
+msgstr ""
+
msgid "ClusterIntegration|GitLab-managed cluster"
msgstr ""
@@ -5516,6 +5724,9 @@ msgstr ""
msgid "ClusterIntegration|Group cluster"
msgstr ""
+msgid "ClusterIntegration|HTTP Error"
+msgstr ""
+
msgid "ClusterIntegration|Helm Tiller"
msgstr ""
@@ -5549,7 +5760,10 @@ msgstr ""
msgid "ClusterIntegration|Instance type"
msgstr ""
-msgid "ClusterIntegration|Integrate Kubernetes cluster automation"
+msgid "ClusterIntegration|Integrate Kubernetes with a cluster certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Integrate with a cluster certificate"
msgstr ""
msgid "ClusterIntegration|Issuer Email"
@@ -5585,9 +5799,6 @@ msgstr ""
msgid "ClusterIntegration|Knative extends Kubernetes to provide a set of middleware components that are essential to build modern, source-centric, and container-based applications that can run anywhere: on premises, in the cloud, or even in a third-party data center."
msgstr ""
-msgid "ClusterIntegration|Kubernetes cluster"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes cluster is being created..."
msgstr ""
@@ -5600,9 +5811,6 @@ msgstr ""
msgid "ClusterIntegration|Kubernetes clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr ""
-msgid "ClusterIntegration|Kubernetes clusters can be used to deploy applications and to provide Review Apps for this project"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes version"
msgstr ""
@@ -5615,7 +5823,7 @@ msgstr ""
msgid "ClusterIntegration|Learn more about %{help_link_start}zones%{help_link_end}."
msgstr ""
-msgid "ClusterIntegration|Learn more about %{startLink}Regions %{externalLinkIcon}%{endLink}."
+msgid "ClusterIntegration|Learn more about %{linkStart}Regions%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Learn more about Kubernetes"
@@ -5660,12 +5868,18 @@ msgstr ""
msgid "ClusterIntegration|Machine type"
msgstr ""
+msgid "ClusterIntegration|Make sure your API endpoint is correct"
+msgstr ""
+
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create Kubernetes clusters"
msgstr ""
msgid "ClusterIntegration|Manage your Kubernetes cluster by visiting %{provider_link}"
msgstr ""
+msgid "ClusterIntegration|Namespace per environment"
+msgstr ""
+
msgid "ClusterIntegration|No IAM Roles found"
msgstr ""
@@ -5711,6 +5925,9 @@ msgstr ""
msgid "ClusterIntegration|No zones matched your search"
msgstr ""
+msgid "ClusterIntegration|Node calculations use the Kubernetes Metrics API. Make sure your cluster has metrics installed"
+msgstr ""
+
msgid "ClusterIntegration|Number of nodes"
msgstr ""
@@ -5753,6 +5970,9 @@ msgstr ""
msgid "ClusterIntegration|RBAC-enabled cluster"
msgstr ""
+msgid "ClusterIntegration|Read our %{linkStart}help page%{linkEnd} on Kubernetes cluster integration."
+msgstr ""
+
msgid "ClusterIntegration|Read our %{link_start}help page%{link_end} on Kubernetes cluster integration."
msgstr ""
@@ -5855,7 +6075,7 @@ msgstr ""
msgid "ClusterIntegration|Select a VPC to choose a subnet"
msgstr ""
-msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{linkStart}Amazon Web Services %{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select a network to choose a subnetwork"
@@ -5888,7 +6108,7 @@ msgstr ""
msgid "ClusterIntegration|Select project to choose zone"
msgstr ""
-msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select zone"
@@ -5978,9 +6198,18 @@ msgstr ""
msgid "ClusterIntegration|There was a problem authenticating with your cluster. Please ensure your CA Certificate and Token are valid."
msgstr ""
+msgid "ClusterIntegration|There was an HTTP error when connecting to your cluster."
+msgstr ""
+
msgid "ClusterIntegration|This account must have permissions to create a Kubernetes cluster in the %{link_to_container_project} specified below"
msgstr ""
+msgid "ClusterIntegration|This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
+msgstr ""
+
+msgid "ClusterIntegration|This is necessary to clear existing environment-namespace associations from clusters previously managed by GitLab."
+msgstr ""
+
msgid "ClusterIntegration|This option will allow you to install applications on RBAC clusters."
msgstr ""
@@ -6005,9 +6234,21 @@ msgstr ""
msgid "ClusterIntegration|To use a new project, first create one on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}."
msgstr ""
+msgid "ClusterIntegration|Troubleshooting tips:"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Authenticate"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Connect"
+msgstr ""
+
msgid "ClusterIntegration|Uninstall %{appTitle}"
msgstr ""
+msgid "ClusterIntegration|Unknown Error"
+msgstr ""
+
msgid "ClusterIntegration|Update %{appTitle}"
msgstr ""
@@ -6068,7 +6309,7 @@ msgstr ""
msgid "ClusterIntegration|Your cluster API is unreachable. Please ensure your API URL is correct."
msgstr ""
-msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Zone"
@@ -6188,6 +6429,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse all threads"
+msgstr ""
+
msgid "Collapse approvers"
msgstr ""
@@ -6337,7 +6581,7 @@ msgstr ""
msgid "Commit…"
msgstr ""
-msgid "Company"
+msgid "Community forum"
msgstr ""
msgid "Company name"
@@ -6346,6 +6590,9 @@ msgstr ""
msgid "Compare"
msgstr ""
+msgid "Compare %{oldCommitId}...%{newCommitId}"
+msgstr ""
+
msgid "Compare Git revisions"
msgstr ""
@@ -6361,6 +6608,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare submodule commit revisions"
+msgstr ""
+
msgid "Compare with previous version"
msgstr ""
@@ -6496,6 +6746,9 @@ msgstr ""
msgid "Configure the way a user creates a new account."
msgstr ""
+msgid "Configure which lists are shown for anyone who visits this board"
+msgstr ""
+
msgid "Confirm"
msgstr ""
@@ -6721,6 +6974,9 @@ msgstr[1] ""
msgid "ContainerRegistry|Set cleanup policy"
msgstr ""
+msgid "ContainerRegistry|Some tags were not deleted"
+msgstr ""
+
msgid "ContainerRegistry|Something went wrong while fetching the cleanup policy."
msgstr ""
@@ -6760,6 +7016,9 @@ msgstr ""
msgid "ContainerRegistry|Tags with names matching this regex pattern will %{italicStart}expire:%{italicEnd}"
msgstr ""
+msgid "ContainerRegistry|The cleanup policy timed out before it could delete all tags. An administrator can %{adminLinkStart}manually run cleanup now%{adminLinkEnd} or you can wait for the cleanup policy to automatically run again. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "ContainerRegistry|The last tag related to this image was recently removed. This empty image and any associated data will be automatically removed as part of the regular Garbage Collection process. If you have any questions, contact your administrator."
msgstr ""
@@ -6892,6 +7151,9 @@ msgstr ""
msgid "Contributions per group member"
msgstr ""
+msgid "Contributor"
+msgstr ""
+
msgid "Contributors"
msgstr ""
@@ -7021,6 +7283,9 @@ msgstr ""
msgid "Could not change HEAD: branch '%{branch}' does not exist"
msgstr ""
+msgid "Could not commit. An unexpected error occurred."
+msgstr ""
+
msgid "Could not connect to FogBugz, check your URL"
msgstr ""
@@ -7060,6 +7325,9 @@ msgstr ""
msgid "Could not find iteration"
msgstr ""
+msgid "Could not load instance counts. Please refresh the page to try again."
+msgstr ""
+
msgid "Could not remove the trigger."
msgstr ""
@@ -7084,10 +7352,10 @@ msgstr ""
msgid "Could not save prometheus manual configuration"
msgstr ""
-msgid "Could not udpdate wiki page"
+msgid "Could not update the LDAP settings"
msgstr ""
-msgid "Could not update the LDAP settings"
+msgid "Could not update wiki page"
msgstr ""
msgid "Could not upload your designs as one or more files uploaded are not supported."
@@ -7745,6 +8013,9 @@ msgstr ""
msgid "DastProfiles|Are you sure you want to delete this profile?"
msgstr ""
+msgid "DastProfiles|Could not create site validation token. Please refresh the page, or try again later."
+msgstr ""
+
msgid "DastProfiles|Could not create the scanner profile. Please try again."
msgstr ""
@@ -7769,6 +8040,12 @@ msgstr ""
msgid "DastProfiles|Could not fetch site profiles. Please refresh the page, or try again later."
msgstr ""
+msgid "DastProfiles|Could not retrieve site validation status. Please refresh the page, or try again later."
+msgstr ""
+
+msgid "DastProfiles|Could not update the scanner profile. Please try again."
+msgstr ""
+
msgid "DastProfiles|Could not update the site profile. Please try again."
msgstr ""
@@ -7784,7 +8061,7 @@ msgstr ""
msgid "DastProfiles|Download validation text file"
msgstr ""
-msgid "DastProfiles|Edit feature will come soon. Please create a new profile if changes needed"
+msgid "DastProfiles|Edit scanner profile"
msgstr ""
msgid "DastProfiles|Edit site profile"
@@ -7817,6 +8094,9 @@ msgstr ""
msgid "DastProfiles|No profiles created yet"
msgstr ""
+msgid "DastProfiles|Passive"
+msgstr ""
+
msgid "DastProfiles|Please enter a valid URL format, ex: http://www.example.com/home"
msgstr ""
@@ -7832,6 +8112,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan mode"
+msgstr ""
+
msgid "DastProfiles|Scanner Profile"
msgstr ""
@@ -7871,10 +8154,10 @@ msgstr ""
msgid "DastProfiles|Text file validation"
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
+msgid "DastProfiles|The maximum number of minutes allowed for the spider to traverse the site."
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the spider to traverse the site."
+msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
msgstr ""
msgid "DastProfiles|Validate"
@@ -7907,6 +8190,9 @@ msgstr ""
msgid "Date picker"
msgstr ""
+msgid "Date range"
+msgstr ""
+
msgid "Date range cannot exceed %{maxDateRange} days."
msgstr ""
@@ -7931,6 +8217,9 @@ msgstr ""
msgid "Days to merge"
msgstr ""
+msgid "Dear Administrator,"
+msgstr ""
+
msgid "Debug"
msgstr ""
@@ -8042,12 +8331,18 @@ msgstr ""
msgid "Delete"
msgstr ""
+msgid "Delete %{name}"
+msgstr ""
+
msgid "Delete Comment"
msgstr ""
msgid "Delete Snippet"
msgstr ""
+msgid "Delete Value Stream"
+msgstr ""
+
msgid "Delete account"
msgstr ""
@@ -8069,9 +8364,6 @@ msgstr ""
msgid "Delete label: %{label_name} ?"
msgstr ""
-msgid "Delete license"
-msgstr ""
-
msgid "Delete list"
msgstr ""
@@ -8147,15 +8439,6 @@ msgstr ""
msgid "Deleting a project places it into a read-only state until %{date}, at which point the project will be permanently deleted. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "Deleting the license failed."
-msgstr ""
-
-msgid "Deleting the license failed. The license was not found."
-msgstr ""
-
-msgid "Deleting the license failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "Deleting the project will delete its repository and all related resources including issues, merge requests etc."
msgstr ""
@@ -8651,7 +8934,10 @@ msgstr ""
msgid "DesignManagement|The maximum number of designs allowed to be uploaded is %{upload_limit}. Please try again."
msgstr ""
-msgid "DesignManagement|To upload designs, you'll need to enable LFS. %{requirements_link_start}More information%{requirements_link_end}"
+msgid "DesignManagement|There was an error moving your designs. Please upload your designs below."
+msgstr ""
+
+msgid "DesignManagement|To upload designs, you'll need to enable LFS and have admin enable hashed storage. %{requirements_link_start}More information%{requirements_link_end}"
msgstr ""
msgid "DesignManagement|Unresolve thread"
@@ -8663,6 +8949,9 @@ msgstr ""
msgid "DesignManagement|Upload skipped."
msgstr ""
+msgid "DesignManagement|Your designs are being copied and are on their way… Please refresh to update."
+msgstr ""
+
msgid "DesignManagement|and %{moreCount} more."
msgstr ""
@@ -8720,6 +9009,9 @@ msgstr ""
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
+msgid "Direct member"
+msgstr ""
+
msgid "Direction"
msgstr ""
@@ -8768,9 +9060,6 @@ msgstr ""
msgid "Discard draft"
msgstr ""
-msgid "Discard review"
-msgstr ""
-
msgid "DiscordService|Discord Notifications"
msgstr ""
@@ -8839,10 +9128,10 @@ msgstr ""
msgid "Dismiss Merge Request promotion"
msgstr ""
-msgid "Dismiss Selected"
+msgid "Dismiss Value Stream Analytics introduction box"
msgstr ""
-msgid "Dismiss Value Stream Analytics introduction box"
+msgid "Dismiss selected"
msgstr ""
msgid "Dismiss trial promotion"
@@ -8893,9 +9182,6 @@ msgstr ""
msgid "Documents reindexed: %{processed_documents} (%{percentage}%%)"
msgstr ""
-msgid "Doing"
-msgstr ""
-
msgid "Domain"
msgstr ""
@@ -9091,9 +9377,6 @@ msgstr ""
msgid "Edit environment"
msgstr ""
-msgid "Edit file"
-msgstr ""
-
msgid "Edit files in the editor and commit changes here"
msgstr ""
@@ -9106,6 +9389,12 @@ msgstr ""
msgid "Edit identity for %{user_name}"
msgstr ""
+msgid "Edit in Web IDE"
+msgstr ""
+
+msgid "Edit in single-file editor"
+msgstr ""
+
msgid "Edit issues"
msgstr ""
@@ -9133,10 +9422,10 @@ msgstr ""
msgid "Editing"
msgstr ""
-msgid "Elasticsearch"
+msgid "Elasticsearch AWS IAM credentials"
msgstr ""
-msgid "Elasticsearch AWS IAM credentials"
+msgid "Elasticsearch HTTP client timeout value in seconds."
msgstr ""
msgid "Elasticsearch indexing restrictions"
@@ -9145,9 +9434,6 @@ msgstr ""
msgid "Elasticsearch indexing started"
msgstr ""
-msgid "Elasticsearch integration. Elasticsearch AWS IAM."
-msgstr ""
-
msgid "Elasticsearch reindexing is already in progress"
msgstr ""
@@ -9175,9 +9461,6 @@ msgstr ""
msgid "Email Notification"
msgstr ""
-msgid "Email address"
-msgstr ""
-
msgid "Email could not be sent"
msgstr ""
@@ -9241,6 +9524,9 @@ msgstr ""
msgid "Emails sent from Service Desk will have this name"
msgstr ""
+msgid "Emails sent to %{email} will still be supported"
+msgstr ""
+
msgid "Emails separated by comma"
msgstr ""
@@ -9274,9 +9560,18 @@ msgstr ""
msgid "Enable"
msgstr ""
+msgid "Enable %{link_start}Gitpod%{link_end} integration to launch a development environment in your browser directly from GitLab."
+msgstr ""
+
msgid "Enable Auto DevOps"
msgstr ""
+msgid "Enable Gitpod"
+msgstr ""
+
+msgid "Enable Gitpod?"
+msgstr ""
+
msgid "Enable HTML emails"
msgstr ""
@@ -9406,9 +9701,6 @@ msgstr ""
msgid "Encountered an error while rendering: %{err}"
msgstr ""
-msgid "End date"
-msgstr ""
-
msgid "Ends at (UTC)"
msgstr ""
@@ -9568,7 +9860,7 @@ msgstr ""
msgid "EnvironmentsDashboard|The environments dashboard provides a summary of each project's environments' status, including pipeline and alert statuses."
msgstr ""
-msgid "EnvironmentsDashboard|This dashboard displays a maximum of 7 projects and 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
+msgid "EnvironmentsDashboard|This dashboard displays 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
msgstr ""
msgid "Environments|An error occurred while canceling the auto stop, please try again"
@@ -9889,6 +10181,9 @@ msgstr ""
msgid "Error deleting project. Check logs for error details."
msgstr ""
+msgid "Error fetching burnup chart data"
+msgstr ""
+
msgid "Error fetching diverging counts for branches. Please try again."
msgstr ""
@@ -9967,6 +10262,9 @@ msgstr ""
msgid "Error occurred when saving assignees"
msgstr ""
+msgid "Error occurred when saving reviewers"
+msgstr ""
+
msgid "Error occurred when toggling the notification subscription"
msgstr ""
@@ -10219,10 +10517,13 @@ msgstr ""
msgid "Expand all"
msgstr ""
-msgid "Expand approvers"
+msgid "Expand all files"
msgstr ""
-msgid "Expand dropdown"
+msgid "Expand all threads"
+msgstr ""
+
+msgid "Expand approvers"
msgstr ""
msgid "Expand milestones"
@@ -10393,6 +10694,9 @@ msgstr ""
msgid "Failed to create Merge Request. Please try again."
msgstr ""
+msgid "Failed to create To-Do for the design."
+msgstr ""
+
msgid "Failed to create a branch for this issue. Please try again."
msgstr ""
@@ -10432,6 +10736,12 @@ msgstr ""
msgid "Failed to load authors. Please try again."
msgstr ""
+msgid "Failed to load branches. Please try again."
+msgstr ""
+
+msgid "Failed to load deploy keys."
+msgstr ""
+
msgid "Failed to load emoji list."
msgstr ""
@@ -10447,6 +10757,9 @@ msgstr ""
msgid "Failed to load groups & users."
msgstr ""
+msgid "Failed to load groups, users and deploy keys."
+msgstr ""
+
msgid "Failed to load labels. Please try again."
msgstr ""
@@ -10456,6 +10769,12 @@ msgstr ""
msgid "Failed to load related branches"
msgstr ""
+msgid "Failed to load sidebar confidential toggle"
+msgstr ""
+
+msgid "Failed to load sidebar lock status"
+msgstr ""
+
msgid "Failed to load stacktrace."
msgstr ""
@@ -10483,6 +10802,9 @@ msgstr ""
msgid "Failed to publish issue on status page."
msgstr ""
+msgid "Failed to remove To-Do for the design."
+msgstr ""
+
msgid "Failed to remove a Zoom meeting"
msgstr ""
@@ -10525,6 +10847,9 @@ msgstr ""
msgid "Failed to signing using smartcard authentication"
msgstr ""
+msgid "Failed to toggle To-Do for the design."
+msgstr ""
+
msgid "Failed to update branch!"
msgstr ""
@@ -10638,7 +10963,7 @@ msgstr ""
msgid "FeatureFlags|Edit User List"
msgstr ""
-msgid "FeatureFlags|Enable features for specific users and specific environments by defining feature flag strategies."
+msgid "FeatureFlags|Enable features for specific users and environments by configuring feature flag strategies."
msgstr ""
msgid "FeatureFlags|Environment Spec"
@@ -10698,7 +11023,7 @@ msgstr ""
msgid "FeatureFlags|Include additional user IDs"
msgstr ""
-msgid "FeatureFlags|Install a %{docs_link_anchored_start}compatible client library%{docs_link_anchored_end} and specify the API URL, application name, and instance ID during the configuration setup. %{docs_link_start}More Information%{docs_link_end}"
+msgid "FeatureFlags|Install a %{docsLinkAnchoredStart}compatible client library%{docsLinkAnchoredEnd} and specify the API URL, application name, and instance ID during the configuration setup. %{docsLinkStart}More Information%{docsLinkEnd}"
msgstr ""
msgid "FeatureFlags|Instance ID"
@@ -10710,6 +11035,9 @@ msgstr ""
msgid "FeatureFlags|Loading feature flags"
msgstr ""
+msgid "FeatureFlags|Loading user lists"
+msgstr ""
+
msgid "FeatureFlags|More information"
msgstr ""
@@ -10728,7 +11056,7 @@ msgstr ""
msgid "FeatureFlags|New feature flag"
msgstr ""
-msgid "FeatureFlags|New list"
+msgid "FeatureFlags|New user list"
msgstr ""
msgid "FeatureFlags|Percent of users"
@@ -10767,6 +11095,9 @@ msgstr ""
msgid "FeatureFlags|There was an error fetching the feature flags."
msgstr ""
+msgid "FeatureFlags|There was an error fetching the user lists."
+msgstr ""
+
msgid "FeatureFlags|There was an error retrieving user lists"
msgstr ""
@@ -10782,6 +11113,9 @@ msgstr ""
msgid "FeatureFlags|User List"
msgstr ""
+msgid "FeatureFlags|User Lists"
+msgstr ""
+
msgid "FeatureFlag|List"
msgstr ""
@@ -10809,15 +11143,6 @@ msgstr ""
msgid "Fetching incoming email"
msgstr ""
-msgid "Fetching licenses failed."
-msgstr ""
-
-msgid "Fetching licenses failed. The request endpoint was not found."
-msgstr ""
-
-msgid "Fetching licenses failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "File"
msgstr ""
@@ -10920,12 +11245,21 @@ msgstr ""
msgid "Filter by status"
msgstr ""
+msgid "Filter by test cases that are currently archived."
+msgstr ""
+
+msgid "Filter by test cases that are currently opened."
+msgstr ""
+
msgid "Filter by two-factor authentication"
msgstr ""
msgid "Filter by user"
msgstr ""
+msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
+msgstr ""
+
msgid "Filter pipelines"
msgstr ""
@@ -10941,7 +11275,7 @@ msgstr ""
msgid "Filter results..."
msgstr ""
-msgid "Filter your projects by name"
+msgid "Filter your repositories by name"
msgstr ""
msgid "Filter..."
@@ -10950,7 +11284,7 @@ msgstr ""
msgid "Find File"
msgstr ""
-msgid "Find bugs in your code with coverage-guided fuzzing"
+msgid "Find bugs in your code with coverage-guided fuzzing."
msgstr ""
msgid "Find by path"
@@ -10977,9 +11311,6 @@ msgstr ""
msgid "Finish editing this message first!"
msgstr ""
-msgid "Finish review"
-msgstr ""
-
msgid "Finish setting up your dedicated account for %{group_name}."
msgstr ""
@@ -11049,6 +11380,9 @@ msgstr ""
msgid "Footer message"
msgstr ""
+msgid "For a faster browsing experience, some files are collapsed by default."
+msgstr ""
+
msgid "For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
@@ -11058,6 +11392,9 @@ msgstr ""
msgid "For more info, read the documentation."
msgstr ""
+msgid "For more information on how the number of active users is calculated, see the %{self_managed_subscriptions_doc_link} documentation."
+msgstr ""
+
msgid "For more information, go to the "
msgstr ""
@@ -11196,6 +11533,9 @@ msgstr ""
msgid "Generate new token"
msgstr ""
+msgid "Generic package file size in bytes"
+msgstr ""
+
msgid "Geo"
msgstr ""
@@ -11457,6 +11797,9 @@ msgstr ""
msgid "Geo|Please refer to Geo Troubleshooting."
msgstr ""
+msgid "Geo|Primary node"
+msgstr ""
+
msgid "Geo|Project"
msgstr ""
@@ -11499,6 +11842,9 @@ msgstr ""
msgid "Geo|Review replication status, and resynchronize and reverify items with the primary node."
msgstr ""
+msgid "Geo|Secondary node"
+msgstr ""
+
msgid "Geo|Status"
msgstr ""
@@ -11538,6 +11884,9 @@ msgstr ""
msgid "Geo|URL must be a valid url (ex: https://gitlab.com)"
msgstr ""
+msgid "Geo|Undefined"
+msgstr ""
+
msgid "Geo|Unknown state"
msgstr ""
@@ -11613,10 +11962,16 @@ msgstr ""
msgid "GitHub import"
msgstr ""
+msgid "GitLab"
+msgstr ""
+
msgid "GitLab / Unsubscribe"
msgstr ""
-msgid "GitLab Enterprise Edition %{plan}"
+msgid "GitLab API"
+msgstr ""
+
+msgid "GitLab Billing Team."
msgstr ""
msgid "GitLab Group Runners can execute code for all the projects in this group."
@@ -11628,12 +11983,18 @@ msgstr ""
msgid "GitLab Issue"
msgstr ""
+msgid "GitLab Pages"
+msgstr ""
+
msgid "GitLab Service Desk is a simple way to allow people to create issues in your GitLab instance without needing their own user account. It provides a unique email address for end users to create issues in a project, and replies can be sent either through the GitLab interface or by email. End users will only see the thread through email."
msgstr ""
msgid "GitLab Shared Runners execute code of different projects on the same Runner unless you configure GitLab Runner Autoscale with MaxBuilds 1 (which it is on GitLab.com)."
msgstr ""
+msgid "GitLab Shell"
+msgstr ""
+
msgid "GitLab Support Bot"
msgstr ""
@@ -11643,7 +12004,7 @@ msgstr ""
msgid "GitLab User"
msgstr ""
-msgid "GitLab allows you to continue using your license even if you exceed the number of seats you purchased. You will be required to pay for these seats when you renew your license."
+msgid "GitLab Workhorse"
msgstr ""
msgid "GitLab commit"
@@ -11811,6 +12172,21 @@ msgstr ""
msgid "Gitlab Pages"
msgstr ""
+msgid "Gitpod"
+msgstr ""
+
+msgid "Gitpod|Add the URL to your Gitpod instance configured to read your GitLab projects."
+msgstr ""
+
+msgid "Gitpod|Enable Gitpod integration"
+msgstr ""
+
+msgid "Gitpod|Gitpod URL"
+msgstr ""
+
+msgid "Gitpod|e.g. https://gitpod.example.com"
+msgstr ""
+
msgid "Given access %{time_ago}"
msgstr ""
@@ -12318,9 +12694,6 @@ msgstr ""
msgid "GroupSAML|Valid SAML Response"
msgstr ""
-msgid "GroupSAML|With group managed accounts enabled, all the users without a group managed account will be excluded from the group."
-msgstr ""
-
msgid "GroupSAML|With prohibit outer forks flag enabled group members will be able to fork project only inside your group."
msgstr ""
@@ -12534,10 +12907,10 @@ msgstr ""
msgid "GroupsNew|Create group"
msgstr ""
-msgid "GroupsNew|GitLab group export"
+msgid "GroupsNew|Import"
msgstr ""
-msgid "GroupsNew|Import"
+msgid "GroupsNew|Import a GitLab group export file"
msgstr ""
msgid "GroupsNew|Import group"
@@ -12680,6 +13053,9 @@ msgid_plural "Hide charts"
msgstr[0] ""
msgstr[1] ""
+msgid "Hide comments on this file"
+msgstr ""
+
msgid "Hide details"
msgstr ""
@@ -12724,6 +13100,15 @@ msgstr ""
msgid "Highest role:"
msgstr ""
+msgid "HighlightBar|Alert events:"
+msgstr ""
+
+msgid "HighlightBar|Alert start time:"
+msgstr ""
+
+msgid "HighlightBar|Original alert:"
+msgstr ""
+
msgid "History"
msgstr ""
@@ -12901,6 +13286,9 @@ msgstr ""
msgid "If enabled, access to projects will be validated on an external service using their classification label."
msgstr ""
+msgid "If the number of active users exceeds the user limit, you will be charged for the number of %{users_over_license_link} at your next license reconciliation."
+msgstr ""
+
msgid "If there is no previous license or if the previous license has expired, some GitLab functionality will be blocked until a new, valid license is uploaded."
msgstr ""
@@ -12940,9 +13328,6 @@ msgstr ""
msgid "If your HTTP repository is not publicly accessible, add your credentials."
msgstr ""
-msgid "Iglu registry URL (optional)"
-msgstr ""
-
msgid "Ignore"
msgstr ""
@@ -12979,6 +13364,16 @@ msgstr ""
msgid "Import"
msgstr ""
+msgid "Import %d compatible repository"
+msgid_plural "Import %d compatible repositories"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Import %d repository"
+msgid_plural "Import %d repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Import CSV"
msgstr ""
@@ -12988,15 +13383,9 @@ msgstr ""
msgid "Import all compatible projects"
msgstr ""
-msgid "Import all compatible repositories"
-msgstr ""
-
msgid "Import all projects"
msgstr ""
-msgid "Import all repositories"
-msgstr ""
-
msgid "Import an exported GitLab project"
msgstr ""
@@ -13084,6 +13473,9 @@ msgstr ""
msgid "ImportProjects|Error importing repository %{project_safe_import_url} into %{project_full_path} - %{message}"
msgstr ""
+msgid "ImportProjects|Import repositories"
+msgstr ""
+
msgid "ImportProjects|Importing the project failed"
msgstr ""
@@ -13096,7 +13488,7 @@ msgstr ""
msgid "ImportProjects|Requesting your %{provider} repositories failed"
msgstr ""
-msgid "ImportProjects|Select the projects you want to import"
+msgid "ImportProjects|Select the repositories you want to import"
msgstr ""
msgid "ImportProjects|The remote data could not be imported."
@@ -13132,9 +13524,6 @@ msgstr ""
msgid "In order to enable Service Desk for your instance, you must first set up incoming email."
msgstr ""
-msgid "In order to gather accurate feature usage data, it can take 1 to 2 weeks to see your index."
-msgstr ""
-
msgid "In order to personalize your experience with GitLab%{br_tag}we would like to know a bit more about you."
msgstr ""
@@ -13165,18 +13554,30 @@ msgstr ""
msgid "IncidentManagement|Create incident"
msgstr ""
+msgid "IncidentManagement|Critical - S1"
+msgstr ""
+
msgid "IncidentManagement|Date created"
msgstr ""
msgid "IncidentManagement|Display your incidents in a dedicated view"
msgstr ""
+msgid "IncidentManagement|High - S2"
+msgstr ""
+
msgid "IncidentManagement|Incident"
msgstr ""
msgid "IncidentManagement|Incidents"
msgstr ""
+msgid "IncidentManagement|Low - S4"
+msgstr ""
+
+msgid "IncidentManagement|Medium - S3"
+msgstr ""
+
msgid "IncidentManagement|No incidents to display."
msgstr ""
@@ -13189,6 +13590,9 @@ msgstr ""
msgid "IncidentManagement|Published to status page"
msgstr ""
+msgid "IncidentManagement|Severity"
+msgstr ""
+
msgid "IncidentManagement|There are no closed incidents"
msgstr ""
@@ -13198,6 +13602,9 @@ msgstr ""
msgid "IncidentManagement|Unassigned"
msgstr ""
+msgid "IncidentManagement|Unknown"
+msgstr ""
+
msgid "IncidentManagement|Unpublished"
msgstr ""
@@ -13219,6 +13626,15 @@ msgstr ""
msgid "Incidents"
msgstr ""
+msgid "Incident|Alert details"
+msgstr ""
+
+msgid "Incident|Summary"
+msgstr ""
+
+msgid "Incident|There was an issue loading alert data. Please try again."
+msgstr ""
+
msgid "Include a Terms of Service agreement and Privacy Policy that all users must accept."
msgstr ""
@@ -13279,6 +13695,9 @@ msgstr ""
msgid "Information about additional Pages templates and how to install them can be found in our %{pages_getting_started_guide}."
msgstr ""
+msgid "Inherited"
+msgstr ""
+
msgid "Inherited:"
msgstr ""
@@ -13359,7 +13778,22 @@ msgstr ""
msgid "Instance administrators group already exists"
msgstr ""
-msgid "Instance license"
+msgid "InstanceStatistics|Groups"
+msgstr ""
+
+msgid "InstanceStatistics|Issues"
+msgstr ""
+
+msgid "InstanceStatistics|Merge Requests"
+msgstr ""
+
+msgid "InstanceStatistics|Pipelines"
+msgstr ""
+
+msgid "InstanceStatistics|Projects"
+msgstr ""
+
+msgid "InstanceStatistics|Users"
msgstr ""
msgid "Integration"
@@ -13371,6 +13805,12 @@ msgstr ""
msgid "Integrations"
msgstr ""
+msgid "Integrations|%{integration} settings saved and active."
+msgstr ""
+
+msgid "Integrations|%{integration} settings saved, but not active."
+msgstr ""
+
msgid "Integrations|All details"
msgstr ""
@@ -13380,6 +13820,12 @@ msgstr ""
msgid "Integrations|Comment settings:"
msgstr ""
+msgid "Integrations|Connection failed. Please check your settings."
+msgstr ""
+
+msgid "Integrations|Connection successful."
+msgstr ""
+
msgid "Integrations|Default settings are inherited from the group level."
msgstr ""
@@ -13395,6 +13841,15 @@ msgstr ""
msgid "Integrations|Includes commit title and branch"
msgstr ""
+msgid "Integrations|Projects using custom settings will not be impacted unless the project owner chooses to use instance-level defaults."
+msgstr ""
+
+msgid "Integrations|Save settings?"
+msgstr ""
+
+msgid "Integrations|Saving will update the default settings for all projects that are not using custom settings."
+msgstr ""
+
msgid "Integrations|Standard"
msgstr ""
@@ -13527,6 +13982,9 @@ msgstr ""
msgid "Invitation"
msgstr ""
+msgid "Invitation declined"
+msgstr ""
+
msgid "Invite"
msgstr ""
@@ -13578,6 +14036,42 @@ 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|%{linkStart}Read more%{linkEnd} about role permissions"
+msgstr ""
+
+msgid "InviteMembersModal|Access expiration date (optional)"
+msgstr ""
+
+msgid "InviteMembersModal|Cancel"
+msgstr ""
+
+msgid "InviteMembersModal|Choose a role permission"
+msgstr ""
+
+msgid "InviteMembersModal|GitLab member or Email address"
+msgstr ""
+
+msgid "InviteMembersModal|Invite"
+msgstr ""
+
+msgid "InviteMembersModal|Invite team members"
+msgstr ""
+
+msgid "InviteMembersModal|Search for members to invite"
+msgstr ""
+
+msgid "InviteMembersModal|User not invited. Feature coming soon!"
+msgstr ""
+
+msgid "InviteMembersModal|Users were succesfully added"
+msgstr ""
+
+msgid "InviteMembersModal|You're inviting members to the %{group_name} group"
+msgstr ""
+
+msgid "InviteMembers|Invite team members"
+msgstr ""
+
msgid "Invited"
msgstr ""
@@ -13632,10 +14126,13 @@ msgstr ""
msgid "Issue cannot be found."
msgstr ""
+msgid "Issue created from vulnerability %{vulnerability_link}"
+msgstr ""
+
msgid "Issue events"
msgstr ""
-msgid "Issue first depoloyed to production"
+msgid "Issue first deployed to production"
msgstr ""
msgid "Issue label"
@@ -13713,6 +14210,9 @@ msgstr ""
msgid "IssueTracker|Custom issue tracker"
msgstr ""
+msgid "IssueTracker|EWM work items tracker"
+msgstr ""
+
msgid "IssueTracker|Redmine issue tracker"
msgstr ""
@@ -13779,6 +14279,9 @@ msgstr ""
msgid "It looks like you have some draft commits in this branch."
msgstr ""
+msgid "It may be several days before you see feature usage data."
+msgstr ""
+
msgid "It must have a header row and at least two columns: the first column is the issue title and the second column is the issue description. The separator is automatically detected."
msgstr ""
@@ -14061,13 +14564,13 @@ msgstr ""
msgid "Join Zoom meeting"
msgstr ""
-msgid "Jul"
+msgid "Joined %{time_ago}"
msgstr ""
-msgid "July"
+msgid "Jul"
msgstr ""
-msgid "Jump to first unresolved thread"
+msgid "July"
msgstr ""
msgid "Jump to next unresolved thread"
@@ -14103,6 +14606,9 @@ msgstr ""
msgid "Keyboard shortcuts"
msgstr ""
+msgid "KeyboardKey|Ctrl+"
+msgstr ""
+
msgid "Keys"
msgstr ""
@@ -14151,6 +14657,9 @@ msgstr ""
msgid "LDAP Synchronization"
msgstr ""
+msgid "LDAP group settings"
+msgstr ""
+
msgid "LDAP settings"
msgstr ""
@@ -14160,6 +14669,9 @@ msgstr ""
msgid "LDAP sync in progress. This could take a few minutes. Refresh the page to see the changes."
msgstr ""
+msgid "LDAP synchronizations"
+msgstr ""
+
msgid "LFS"
msgstr ""
@@ -14240,7 +14752,16 @@ msgid_plural "Last %d days"
msgstr[0] ""
msgstr[1] ""
-msgid "Last %{days} days"
+msgid "Last 2 weeks"
+msgstr ""
+
+msgid "Last 30 days"
+msgstr ""
+
+msgid "Last 60 days"
+msgstr ""
+
+msgid "Last 90 days"
msgstr ""
msgid "Last Accessed On"
@@ -14318,6 +14839,9 @@ msgstr ""
msgid "Last used on:"
msgstr ""
+msgid "Last week"
+msgstr ""
+
msgid "LastCommit|authored"
msgstr ""
@@ -14333,6 +14857,9 @@ msgstr ""
msgid "Latest pipeline for the most recent commit on this branch"
msgstr ""
+msgid "Launch a ready-to-code development environment for your project."
+msgstr ""
+
msgid "Lead"
msgstr ""
@@ -14713,6 +15240,9 @@ msgstr ""
msgid "List of all merge commits"
msgstr ""
+msgid "List options"
+msgstr ""
+
msgid "List settings"
msgstr ""
@@ -14725,9 +15255,6 @@ msgstr ""
msgid "List your Bitbucket Server repositories"
msgstr ""
-msgid "Lists"
-msgstr ""
-
msgid "Live preview"
msgstr ""
@@ -14974,6 +15501,12 @@ msgstr ""
msgid "Mark as done"
msgstr ""
+msgid "Mark as draft"
+msgstr ""
+
+msgid "Mark as ready"
+msgstr ""
+
msgid "Mark as resolved"
msgstr ""
@@ -14995,6 +15528,24 @@ msgstr ""
msgid "Markdown is supported"
msgstr ""
+msgid "MarkdownEditor|Add a link (%{modifierKey}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add a link (%{modifier_key}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifierKey}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifier_key}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifierKey}I)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifier_key}I)"
+msgstr ""
+
msgid "Marked For Deletion At - %{deletion_time}"
msgstr ""
@@ -15079,7 +15630,25 @@ msgstr ""
msgid "Max access level"
msgstr ""
-msgid "Max seats used"
+msgid "Max role"
+msgstr ""
+
+msgid "Max size 15 MB"
+msgstr ""
+
+msgid "Maximum Conan package file size in bytes"
+msgstr ""
+
+msgid "Maximum Maven package file size in bytes"
+msgstr ""
+
+msgid "Maximum NPM package file size in bytes"
+msgstr ""
+
+msgid "Maximum NuGet package file size in bytes"
+msgstr ""
+
+msgid "Maximum PyPI package file size in bytes"
msgstr ""
msgid "Maximum Users:"
@@ -15211,6 +15780,18 @@ msgstr ""
msgid "Members with access to %{strong_start}%{group_name}%{strong_end}"
msgstr ""
+msgid "Members|%{time} by %{user}"
+msgstr ""
+
+msgid "Members|Expired"
+msgstr ""
+
+msgid "Members|No expiration set"
+msgstr ""
+
+msgid "Members|in %{time}"
+msgstr ""
+
msgid "Memory Usage"
msgstr ""
@@ -15397,9 +15978,6 @@ msgstr ""
msgid "MergeRequests|Thread will be unresolved"
msgstr ""
-msgid "MergeRequests|Toggle comments for this file"
-msgstr ""
-
msgid "MergeRequests|View file @ %{commitId}"
msgstr ""
@@ -15460,6 +16038,9 @@ msgstr ""
msgid "Merging immediately isn't recommended as it may negatively impact the existing merge train. Read the %{docsLinkStart}documentation%{docsLinkEnd} for more information."
msgstr ""
+msgid "Message"
+msgstr ""
+
msgid "Messages"
msgstr ""
@@ -15845,18 +16426,12 @@ msgid_plural "Milestones"
msgstr[0] ""
msgstr[1] ""
-msgid "Milestone does not support burnup charts"
-msgstr ""
-
msgid "Milestone lists not available with your current license"
msgstr ""
msgid "Milestone lists show all issues from the selected milestone."
msgstr ""
-msgid "Milestone must have a start and due date"
-msgstr ""
-
msgid "MilestoneSidebar|Closed:"
msgstr ""
@@ -16223,6 +16798,9 @@ msgstr ""
msgid "Namespace"
msgstr ""
+msgid "Namespace ID:"
+msgstr ""
+
msgid "Namespace is empty"
msgstr ""
@@ -16307,6 +16885,9 @@ msgstr ""
msgid "NetworkPolicies|Allow all outbound traffic from %{selector} to %{ruleSelector} on %{ports}"
msgstr ""
+msgid "NetworkPolicies|Are you sure you want to delete this policy? This action cannot be undone."
+msgstr ""
+
msgid "NetworkPolicies|Choose whether to enforce this policy."
msgstr ""
@@ -16316,12 +16897,21 @@ msgstr ""
msgid "NetworkPolicies|Define this policy's location, conditions and actions."
msgstr ""
+msgid "NetworkPolicies|Delete policy"
+msgstr ""
+
+msgid "NetworkPolicies|Delete policy: %{policy}"
+msgstr ""
+
msgid "NetworkPolicies|Deny all traffic"
msgstr ""
msgid "NetworkPolicies|Description"
msgstr ""
+msgid "NetworkPolicies|Edit policy"
+msgstr ""
+
msgid "NetworkPolicies|Editor mode"
msgstr ""
@@ -16349,6 +16939,9 @@ msgstr ""
msgid "NetworkPolicies|Name"
msgstr ""
+msgid "NetworkPolicies|Namespace"
+msgstr ""
+
msgid "NetworkPolicies|Network Policy"
msgstr ""
@@ -16400,6 +16993,9 @@ msgstr ""
msgid "NetworkPolicies|Rules"
msgstr ""
+msgid "NetworkPolicies|Save changes"
+msgstr ""
+
msgid "NetworkPolicies|Something went wrong, failed to update policy"
msgstr ""
@@ -16412,6 +17008,9 @@ msgstr ""
msgid "NetworkPolicies|Traffic that does not match any rule will be blocked."
msgstr ""
+msgid "NetworkPolicies|Unable to parse policy"
+msgstr ""
+
msgid "NetworkPolicies|YAML editor"
msgstr ""
@@ -16525,6 +17124,9 @@ msgstr ""
msgid "New Snippet"
msgstr ""
+msgid "New Test Case"
+msgstr ""
+
msgid "New User"
msgstr ""
@@ -16624,6 +17226,9 @@ msgstr ""
msgid "New tag"
msgstr ""
+msgid "New test case"
+msgstr ""
+
msgid "New users set to external"
msgstr ""
@@ -16696,7 +17301,7 @@ msgstr ""
msgid "No changes"
msgstr ""
-msgid "No changes between %{ref_start}%{source_branch}%{ref_end} and %{ref_start}%{target_branch}%{ref_end}"
+msgid "No changes between %{sourceBranch} and %{targetBranch}"
msgstr ""
msgid "No child epics match applied filters"
@@ -16711,6 +17316,9 @@ msgstr ""
msgid "No containers available"
msgstr ""
+msgid "No content to show"
+msgstr ""
+
msgid "No contributions"
msgstr ""
@@ -16786,9 +17394,6 @@ msgstr ""
msgid "No license. All rights reserved"
msgstr ""
-msgid "No licenses found."
-msgstr ""
-
msgid "No matches found"
msgstr ""
@@ -16801,6 +17406,9 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No members found"
+msgstr ""
+
msgid "No merge requests found"
msgstr ""
@@ -16822,6 +17430,9 @@ msgstr ""
msgid "No parent group"
msgstr ""
+msgid "No plan"
+msgstr ""
+
msgid "No pods available"
msgstr ""
@@ -16918,6 +17529,12 @@ msgstr ""
msgid "Not Implemented"
msgstr ""
+msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+msgstr ""
+
+msgid "Not all browsers support WebAuthn. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even from an unsupported browser."
+msgstr ""
+
msgid "Not all data has been processed yet, the accuracy of the chart for the selected timeframe is limited."
msgstr ""
@@ -17014,6 +17631,9 @@ msgstr ""
msgid "Notification settings saved"
msgstr ""
+msgid "NotificationEvent|Change reviewer merge request"
+msgstr ""
+
msgid "NotificationEvent|Close issue"
msgstr ""
@@ -17176,10 +17796,7 @@ msgstr ""
msgid "On track"
msgstr ""
-msgid "OnDemandScans|Attached branch"
-msgstr ""
-
-msgid "OnDemandScans|Attached branch is where the scan job runs."
+msgid "OnDemandScans|Could not fetch scanner profiles. Please refresh the page, or try again later."
msgstr ""
msgid "OnDemandScans|Could not fetch site profiles. Please refresh the page, or try again later."
@@ -17188,6 +17805,9 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
+msgid "OnDemandScans|Create a new scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Create a new site profile"
msgstr ""
@@ -17200,6 +17820,9 @@ msgstr ""
msgid "OnDemandScans|New on-demand DAST scan"
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 ""
@@ -17209,16 +17832,10 @@ msgstr ""
msgid "OnDemandScans|On-demand scans run outside the DevOps cycle and find vulnerabilities in your projects. %{learnMoreLinkStart}Learn more%{learnMoreLinkEnd}"
msgstr ""
-msgid "OnDemandScans|Only a passive scan can be performed on demand."
-msgstr ""
-
-msgid "OnDemandScans|Passive"
-msgstr ""
-
msgid "OnDemandScans|Run scan"
msgstr ""
-msgid "OnDemandScans|Scan mode"
+msgid "OnDemandScans|Scanner profile"
msgstr ""
msgid "OnDemandScans|Scanner settings"
@@ -17230,9 +17847,15 @@ msgstr ""
msgid "OnDemandScans|Select one of the existing profiles"
msgstr ""
+msgid "OnDemandScans|Site profile"
+msgstr ""
+
msgid "OnDemandScans|Site profiles"
msgstr ""
+msgid "OnDemandScans|Use existing scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Use existing site profile"
msgstr ""
@@ -17331,9 +17954,6 @@ msgstr ""
msgid "Open Selection"
msgstr ""
-msgid "Open Web IDE"
-msgstr ""
-
msgid "Open comment type dropdown"
msgstr ""
@@ -17439,6 +18059,9 @@ msgstr ""
msgid "Origin"
msgstr ""
+msgid "Orphaned member"
+msgstr ""
+
msgid "Other Labels"
msgstr ""
@@ -17454,6 +18077,9 @@ msgstr ""
msgid "Other visibility settings have been disabled by the administrator."
msgstr ""
+msgid "Our documentation includes an example DevOps Score report."
+msgstr ""
+
msgid "Out-of-compliance with this project's policies and should be removed"
msgstr ""
@@ -17478,6 +18104,9 @@ msgstr ""
msgid "Overwrite diverged branches"
msgstr ""
+msgid "Owned by %{image_tag}"
+msgstr ""
+
msgid "Owned by anyone"
msgstr ""
@@ -17499,6 +18128,9 @@ msgstr ""
msgid "Package deleted successfully"
msgstr ""
+msgid "Package file size limits"
+msgstr ""
+
msgid "Package recipe already exists"
msgstr ""
@@ -17514,9 +18146,6 @@ msgstr ""
msgid "Package type must be PyPi"
msgstr ""
-msgid "Package was removed"
-msgstr ""
-
msgid "PackageRegistry|%{name} version %{version} was created %{datetime}"
msgstr ""
@@ -17658,12 +18287,18 @@ msgstr ""
msgid "PackageRegistry|NuGet Command"
msgstr ""
+msgid "PackageRegistry|Package Registry"
+msgstr ""
+
msgid "PackageRegistry|Pip Command"
msgstr ""
msgid "PackageRegistry|Pipeline %{link} triggered %{datetime} by %{author}"
msgstr ""
+msgid "PackageRegistry|Publish and share packages for a variety of common package managers. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "PackageRegistry|Published to the %{project} Package Registry %{datetime}"
msgstr ""
@@ -17763,6 +18398,9 @@ msgstr ""
msgid "Page not found"
msgstr ""
+msgid "Page settings"
+msgstr ""
+
msgid "Page was successfully deleted"
msgstr ""
@@ -17904,7 +18542,7 @@ msgstr ""
msgid "Paste issue link"
msgstr ""
-msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Don't use your private SSH key."
+msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Do not paste your private SSH key, as that can compromise your identity."
msgstr ""
msgid "Patch to apply"
@@ -17931,6 +18569,9 @@ msgstr ""
msgid "Pending"
msgstr ""
+msgid "Pending comments"
+msgstr ""
+
msgid "People without permission will never get a notification and won't be able to comment."
msgstr ""
@@ -18129,6 +18770,9 @@ msgstr ""
msgid "Pipelines|Build with confidence"
msgstr ""
+msgid "Pipelines|By revoking a trigger you will break any processes making use of it. Are you sure?"
+msgstr ""
+
msgid "Pipelines|CI Lint"
msgstr ""
@@ -18141,6 +18785,15 @@ msgstr ""
msgid "Pipelines|Continuous Integration can help catch bugs by running your tests automatically, while Continuous Deployment can help you deliver code to your product environment."
msgstr ""
+msgid "Pipelines|Copy trigger token"
+msgstr ""
+
+msgid "Pipelines|Description"
+msgstr ""
+
+msgid "Pipelines|Edit"
+msgstr ""
+
msgid "Pipelines|Get started with Pipelines"
msgstr ""
@@ -18156,15 +18809,27 @@ msgstr ""
msgid "Pipelines|It is recommended the code is reviewed thoroughly before running this pipeline with the parent project's CI resource."
msgstr ""
+msgid "Pipelines|Last Used"
+msgstr ""
+
msgid "Pipelines|Loading Pipelines"
msgstr ""
msgid "Pipelines|More Information"
msgstr ""
+msgid "Pipelines|No triggers have been created yet. Add one using the form above."
+msgstr ""
+
+msgid "Pipelines|Owner"
+msgstr ""
+
msgid "Pipelines|Project cache successfully reset."
msgstr ""
+msgid "Pipelines|Revoke"
+msgstr ""
+
msgid "Pipelines|Run Pipeline"
msgstr ""
@@ -18189,6 +18854,15 @@ msgstr ""
msgid "Pipelines|This project is not currently set up to run pipelines."
msgstr ""
+msgid "Pipelines|Token"
+msgstr ""
+
+msgid "Pipelines|Trigger user has insufficient permissions to project"
+msgstr ""
+
+msgid "Pipelines|invalid"
+msgstr ""
+
msgid "Pipelines|parent"
msgstr ""
@@ -18447,10 +19121,10 @@ msgstr ""
msgid "Please provide attributes to update"
msgstr ""
-msgid "Please refer to %{docs_url}"
+msgid "Please reach out if you have any questions and we'll be happy to assist."
msgstr ""
-msgid "Please retype the email address."
+msgid "Please refer to %{docs_url}"
msgstr ""
msgid "Please select"
@@ -18480,6 +19154,9 @@ msgstr ""
msgid "Please set a new password before proceeding."
msgstr ""
+msgid "Please share your feedback about %{featureName} %{linkStart}in this issue%{linkEnd} to help us improve the experience."
+msgstr ""
+
msgid "Please solve the reCAPTCHA"
msgstr ""
@@ -18783,6 +19460,9 @@ msgstr ""
msgid "Profiles| You are going to change the username %{currentUsernameBold} to %{newUsernameBold}. Profile and projects will be redirected to the %{newUsername} namespace but this redirect will expire once the %{currentUsername} namespace is registered by another user or group. Please update your Git repository remotes as soon as possible."
msgstr ""
+msgid "Profiles|%{provider} Active"
+msgstr ""
+
msgid "Profiles|@username"
msgstr ""
@@ -18834,7 +19514,7 @@ msgstr ""
msgid "Profiles|Commit email"
msgstr ""
-msgid "Profiles|Connect"
+msgid "Profiles|Connect %{provider}"
msgstr ""
msgid "Profiles|Connected Accounts"
@@ -18858,6 +19538,9 @@ msgstr ""
msgid "Profiles|Disconnect"
msgstr ""
+msgid "Profiles|Disconnect %{provider}"
+msgstr ""
+
msgid "Profiles|Do not show on profile"
msgstr ""
@@ -18882,7 +19565,7 @@ msgstr ""
msgid "Profiles|Full name"
msgstr ""
-msgid "Profiles|Give your individual key a title. This will be publically visible."
+msgid "Profiles|Give your individual key a title."
msgstr ""
msgid "Profiles|Include private contributions on my profile"
@@ -18972,7 +19655,7 @@ msgstr ""
msgid "Profiles|The maximum file size allowed is 200KB."
msgstr ""
-msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it?"
+msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it? It will be publicly visible."
msgstr ""
msgid "Profiles|This email will be displayed on your public profile"
@@ -19047,6 +19730,9 @@ msgstr ""
msgid "Profiles|You don't have access to delete this user."
msgstr ""
+msgid "Profiles|You must transfer ownership or delete groups you are an owner of before you can delete your account"
+msgstr ""
+
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
@@ -19635,6 +20321,9 @@ msgstr ""
msgid "ProjectTemplates|GitLab Cluster Management"
msgstr ""
+msgid "ProjectTemplates|Gitpod/Spring Petclinic"
+msgstr ""
+
msgid "ProjectTemplates|Go Micro"
msgstr ""
@@ -20244,6 +20933,9 @@ msgstr ""
msgid "Publish to status page"
msgstr ""
+msgid "Published"
+msgstr ""
+
msgid "Published on status page"
msgstr ""
@@ -20361,9 +21053,15 @@ msgstr ""
msgid "Quick range"
msgstr ""
+msgid "Quickly and easily edit multiple files in your project."
+msgstr ""
+
msgid "README"
msgstr ""
+msgid "Rails"
+msgstr ""
+
msgid "Rake Tasks Help"
msgstr ""
@@ -20483,10 +21181,13 @@ msgstr ""
msgid "Register Two-Factor Authenticator"
msgstr ""
-msgid "Register U2F device"
+msgid "Register Universal Two-Factor (U2F) Device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register WebAuthn Device"
+msgstr ""
+
+msgid "Register device"
msgstr ""
msgid "Register for GitLab"
@@ -20498,9 +21199,6 @@ msgstr ""
msgid "Register with two-factor app"
msgstr ""
-msgid "Registration"
-msgstr ""
-
msgid "Registration|Checkout"
msgstr ""
@@ -20617,9 +21315,6 @@ msgstr ""
msgid "Release|Something went wrong while saving the release details"
msgstr ""
-msgid "Remediated: needs review"
-msgstr ""
-
msgid "Remediations"
msgstr ""
@@ -20725,6 +21420,9 @@ msgstr ""
msgid "Remove priority"
msgstr ""
+msgid "Remove report"
+msgstr ""
+
msgid "Remove secondary node"
msgstr ""
@@ -20737,6 +21435,12 @@ msgstr ""
msgid "Remove time estimate"
msgstr ""
+msgid "Remove user & report"
+msgstr ""
+
+msgid "Remove user from group"
+msgstr ""
+
msgid "Removed"
msgstr ""
@@ -20818,9 +21522,6 @@ msgstr ""
msgid "Removes time estimate."
msgstr ""
-msgid "Removing license…"
-msgstr ""
-
msgid "Removing this group also removes all child projects, including archived projects, and their resources."
msgstr ""
@@ -20905,6 +21606,9 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
+msgid "Reported by %{reporter}"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -20991,6 +21695,27 @@ msgstr ""
msgid "Repositories"
msgstr ""
+msgid "Repositories Analytics"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download Historic Test Coverage Data"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download historic test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Historic Test Coverage Data is available in raw format (.csv) for further analysis."
+msgstr ""
+
+msgid "RepositoriesAnalytics|Test Code Coverage"
+msgstr ""
+
+msgid "RepositoriesAnalytics|There was an error fetching the projects."
+msgstr ""
+
msgid "Repository"
msgstr ""
@@ -21069,9 +21794,15 @@ msgstr ""
msgid "Request parameter %{param} is missing."
msgstr ""
+msgid "Request review from"
+msgstr ""
+
msgid "Request to link SAML account must be authorized"
msgstr ""
+msgid "Requested"
+msgstr ""
+
msgid "Requested %{time_ago}"
msgstr ""
@@ -21090,6 +21821,9 @@ msgstr ""
msgid "Requests to these domain(s)/address(es) on the local network will be allowed when local requests from hooks and services are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 or 127.0.0.0/28 are supported. Domain wildcards are not supported currently. Use comma, semicolon, or newline to separate multiple entries. The allowlist can hold a maximum of 1000 entries. Domains should use IDNA encoding. Ex: example.com, 192.168.1.1, 127.0.0.0/28, xn--itlab-j1a.com."
msgstr ""
+msgid "Require admin approval for new sign-ups"
+msgstr ""
+
msgid "Require all users in this group to setup Two-factor authentication"
msgstr ""
@@ -21217,9 +21951,6 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
-msgid "Resolved by %{resolvedByName}"
-msgstr ""
-
msgid "Resolves IP addresses once and uses them to submit requests"
msgstr ""
@@ -21339,6 +22070,14 @@ msgstr ""
msgid "ReviewApp|Enable Review App"
msgstr ""
+msgid "Reviewer"
+msgid_plural "%d Reviewers"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Reviewer(s)"
+msgstr ""
+
msgid "Reviewing"
msgstr ""
@@ -21378,6 +22117,9 @@ msgstr ""
msgid "Rook"
msgstr ""
+msgid "Ruby"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -21456,6 +22198,63 @@ msgstr ""
msgid "Runners page."
msgstr ""
+msgid "Runners|Active"
+msgstr ""
+
+msgid "Runners|Architecture"
+msgstr ""
+
+msgid "Runners|Can run untagged jobs"
+msgstr ""
+
+msgid "Runners|Description"
+msgstr ""
+
+msgid "Runners|Group"
+msgstr ""
+
+msgid "Runners|IP Address"
+msgstr ""
+
+msgid "Runners|Last contact"
+msgstr ""
+
+msgid "Runners|Locked to this project"
+msgstr ""
+
+msgid "Runners|Maximum job timeout"
+msgstr ""
+
+msgid "Runners|Name"
+msgstr ""
+
+msgid "Runners|Platform"
+msgstr ""
+
+msgid "Runners|Property Name"
+msgstr ""
+
+msgid "Runners|Protected"
+msgstr ""
+
+msgid "Runners|Revision"
+msgstr ""
+
+msgid "Runners|Shared"
+msgstr ""
+
+msgid "Runners|Specific"
+msgstr ""
+
+msgid "Runners|Tags"
+msgstr ""
+
+msgid "Runners|Value"
+msgstr ""
+
+msgid "Runners|Version"
+msgstr ""
+
msgid "Runners|You have used %{quotaUsed} out of %{quotaLimit} of your shared Runners pipeline minutes."
msgstr ""
@@ -21468,6 +22267,9 @@ msgstr ""
msgid "Runs a number of housekeeping tasks within the current repository, such as compressing file revisions and removing unreachable objects."
msgstr ""
+msgid "SAML"
+msgstr ""
+
msgid "SAML SSO"
msgstr ""
@@ -21519,6 +22321,9 @@ msgstr ""
msgid "Save"
msgstr ""
+msgid "Save %{name} size limits"
+msgstr ""
+
msgid "Save Changes"
msgstr ""
@@ -21549,9 +22354,6 @@ msgstr ""
msgid "Save space and find tags in the Container Registry more easily. Enable the cleanup policy to remove stale tags and keep only the ones you need."
msgstr ""
-msgid "Save template"
-msgstr ""
-
msgid "Save variables"
msgstr ""
@@ -21594,9 +22396,6 @@ msgstr ""
msgid "Scope"
msgstr ""
-msgid "Scope not supported with disabled 'users_search' feature!"
-msgstr ""
-
msgid "Scoped issue boards"
msgstr ""
@@ -21723,9 +22522,6 @@ msgstr ""
msgid "Search requirements"
msgstr ""
-msgid "Search results…"
-msgstr ""
-
msgid "Search users"
msgstr ""
@@ -21798,6 +22594,11 @@ msgid_plural "SearchResults|commits"
msgstr[0] ""
msgstr[1] ""
+msgid "SearchResults|epic"
+msgid_plural "SearchResults|epics"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "SearchResults|issue"
msgid_plural "SearchResults|issues"
msgstr[0] ""
@@ -21842,10 +22643,10 @@ msgstr ""
msgid "Seat Link is disabled, and cannot be configured through this form."
msgstr ""
-msgid "Seats currently in use"
+msgid "Seats usage data as of %{last_enqueue_time}"
msgstr ""
-msgid "Seats in license"
+msgid "Seats usage data is updated every day at 12:00pm UTC"
msgstr ""
msgid "Secondary"
@@ -21899,6 +22700,9 @@ msgstr ""
msgid "SecurityConfiguration|Available for on-demand DAST"
msgstr ""
+msgid "SecurityConfiguration|By default, all analyzers are applied in order to cover all languages across your project, and only run if the language is detected in the Merge Request."
+msgstr ""
+
msgid "SecurityConfiguration|Configure"
msgstr ""
@@ -21929,16 +22733,19 @@ msgstr ""
msgid "SecurityConfiguration|Manage"
msgstr ""
+msgid "SecurityConfiguration|More information"
+msgstr ""
+
msgid "SecurityConfiguration|Not enabled"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|Security Control"
+msgid "SecurityConfiguration|SAST Configuration"
msgstr ""
-msgid "SecurityConfiguration|See documentation"
+msgid "SecurityConfiguration|Security Control"
msgstr ""
msgid "SecurityConfiguration|Status"
@@ -21950,6 +22757,9 @@ msgstr ""
msgid "SecurityConfiguration|Using custom settings. You won't receive automatic updates on this variable. %{anchorStart}Restore to default%{anchorEnd}"
msgstr ""
+msgid "SecurityConfiguration|View history"
+msgstr ""
+
msgid "SecurityConfiguration|You can quickly enable all security scanning tools by enabling %{linkStart}Auto DevOps%{linkEnd}."
msgstr ""
@@ -22028,9 +22838,6 @@ msgstr ""
msgid "SecurityReports|Learn more about setting up your dashboard"
msgstr ""
-msgid "SecurityReports|Load more vulnerabilities"
-msgstr ""
-
msgid "SecurityReports|Monitor vulnerabilities in your code"
msgstr ""
@@ -22310,7 +23117,7 @@ msgstr ""
msgid "Select status"
msgstr ""
-msgid "Select strategy activation method"
+msgid "Select strategy activation method."
msgstr ""
msgid "Select subscription"
@@ -22325,7 +23132,7 @@ msgstr ""
msgid "Select the custom project template source group."
msgstr ""
-msgid "Select timeframe"
+msgid "Select the environment scope for this feature flag."
msgstr ""
msgid "Select timezone"
@@ -22574,6 +23381,9 @@ msgstr ""
msgid "Set iteration"
msgstr ""
+msgid "Set limit to 0 to allow any file size."
+msgstr ""
+
msgid "Set max session time for web terminal."
msgstr ""
@@ -22652,10 +23462,13 @@ msgstr ""
msgid "Set up a %{type} Runner manually"
msgstr ""
+msgid "Set up a hardware device as a second factor to sign in."
+msgstr ""
+
msgid "Set up assertions/attributes/claims (email, first_name, last_name) and NameID according to %{docsLinkStart}the documentation %{icon}%{docsLinkEnd}"
msgstr ""
-msgid "Set up new U2F device"
+msgid "Set up new device"
msgstr ""
msgid "Set up new password"
@@ -22724,6 +23537,9 @@ msgstr ""
msgid "Sets weight to %{weight}."
msgstr ""
+msgid "Setting this to 0 means using the system default timeout value."
+msgstr ""
+
msgid "Settings"
msgstr ""
@@ -22739,6 +23555,15 @@ msgstr ""
msgid "Severity"
msgstr ""
+msgid "SeverityWidget|Severity"
+msgstr ""
+
+msgid "SeverityWidget|Severity: %{severity}"
+msgstr ""
+
+msgid "SeverityWidget|There was an error while updating severity."
+msgstr ""
+
msgid "Shards (%{shards})"
msgstr ""
@@ -22784,6 +23609,9 @@ msgstr ""
msgid "Show all requirements."
msgstr ""
+msgid "Show all test cases."
+msgstr ""
+
msgid "Show archived projects"
msgstr ""
@@ -22796,6 +23624,9 @@ msgstr ""
msgid "Show comments"
msgstr ""
+msgid "Show comments on this file"
+msgstr ""
+
msgid "Show comments only"
msgstr ""
@@ -22841,6 +23672,12 @@ msgstr ""
msgid "Show parent subgroups"
msgstr ""
+msgid "Show the Closed list"
+msgstr ""
+
+msgid "Show the Open list"
+msgstr ""
+
msgid "Show whitespace changes"
msgstr ""
@@ -22884,9 +23721,6 @@ msgstr ""
msgid "Sidebar|Assign health status"
msgstr ""
-msgid "Sidebar|Change weight"
-msgstr ""
-
msgid "Sidebar|Health status"
msgstr ""
@@ -23070,6 +23904,9 @@ msgstr ""
msgid "Snippets|Add another file %{num}/%{total}"
msgstr ""
+msgid "Snippets|Authored %{time_ago} by %{author}"
+msgstr ""
+
msgid "Snippets|Delete file"
msgstr ""
@@ -23097,6 +23934,9 @@ msgstr ""
msgid "Solution"
msgstr ""
+msgid "Some changes are not shown"
+msgstr ""
+
msgid "Some child epics may be hidden due to applied filters"
msgstr ""
@@ -23463,6 +24303,12 @@ msgstr ""
msgid "Source (branch or tag)"
msgstr ""
+msgid "Source Branch"
+msgstr ""
+
+msgid "Source branch: %{source_branch_open}%{source_branch}%{source_branch_close}"
+msgstr ""
+
msgid "Source code"
msgstr ""
@@ -23628,9 +24474,6 @@ msgstr ""
msgid "Start and due date"
msgstr ""
-msgid "Start by choosing a group to see how your team is spending time. You can then drill down to the project level."
-msgstr ""
-
msgid "Start by choosing a group to start exploring the merge requests in that group. You can then proceed to filter by projects, labels, milestones and authors."
msgstr ""
@@ -23712,18 +24555,27 @@ msgstr ""
msgid "StaticSiteEditor|3. Assign a person to review and accept the merge request."
msgstr ""
+msgid "StaticSiteEditor|A link to view the merge request will appear once ready."
+msgstr ""
+
msgid "StaticSiteEditor|An error occurred while submitting your changes."
msgstr ""
msgid "StaticSiteEditor|Branch could not be created."
msgstr ""
+msgid "StaticSiteEditor|Copy update"
+msgstr ""
+
msgid "StaticSiteEditor|Could not commit the content changes."
msgstr ""
msgid "StaticSiteEditor|Could not create merge request."
msgstr ""
+msgid "StaticSiteEditor|Creating your merge request"
+msgstr ""
+
msgid "StaticSiteEditor|Incompatible file content"
msgstr ""
@@ -23745,6 +24597,9 @@ msgstr ""
msgid "StaticSiteEditor|View documentation"
msgstr ""
+msgid "StaticSiteEditor|You can set an assignee to get your changes reviewed and deployed once your merge request is created."
+msgstr ""
+
msgid "StaticSiteEditor|Your merge request has been created"
msgstr ""
@@ -23874,15 +24729,15 @@ msgstr ""
msgid "Submit %{humanized_resource_name}"
msgstr ""
-msgid "Submit Changes"
-msgstr ""
-
msgid "Submit a review"
msgstr ""
msgid "Submit as spam"
msgstr ""
+msgid "Submit changes"
+msgstr ""
+
msgid "Submit feedback"
msgstr ""
@@ -24036,6 +24891,9 @@ msgstr ""
msgid "Successfully deleted U2F device."
msgstr ""
+msgid "Successfully deleted WebAuthn device."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -24354,9 +25212,6 @@ msgstr ""
msgid "Template to append to all Service Desk issues"
msgstr ""
-msgid "Template was successfully saved."
-msgstr ""
-
msgid "Templates"
msgstr ""
@@ -24435,10 +25290,28 @@ msgid_plural "Test coverage: %d hits"
msgstr[0] ""
msgstr[1] ""
-msgid "Test failed."
+msgid "Test settings"
msgstr ""
-msgid "Test settings and save changes"
+msgid "TestCases|New Test Case"
+msgstr ""
+
+msgid "TestCases|New test case"
+msgstr ""
+
+msgid "TestCases|Search test cases"
+msgstr ""
+
+msgid "TestCases|Something went wrong while creating a test case."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching count of test cases."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching test cases list."
+msgstr ""
+
+msgid "TestCases|Submit test case"
msgstr ""
msgid "TestHooks|Ensure one of your projects has merge requests."
@@ -24504,6 +25377,9 @@ msgstr ""
msgid "Thank you for signing up for your free trial! You will get additional instructions in your inbox shortly."
msgstr ""
+msgid "Thank you for your business."
+msgstr ""
+
msgid "Thank you for your feedback!"
msgstr ""
@@ -24563,9 +25439,6 @@ msgstr ""
msgid "The URL to use for connecting to Elasticsearch. Use a comma-separated list to support clustering (e.g., \"http://localhost:9200, http://localhost:9201\")."
msgstr ""
-msgid "The Web IDE offers advanced syntax highlighting capabilities and more."
-msgstr ""
-
msgid "The X509 Certificate to use when mutual TLS is required to communicate with the external authorization service. If left blank, the server certificate is still validated when accessing over HTTPS."
msgstr ""
@@ -24676,6 +25549,9 @@ msgstr ""
msgid "The form contains the following error:"
msgstr ""
+msgid "The form contains the following warning:"
+msgstr ""
+
msgid "The global settings require you to enable Two-Factor Authentication for your account."
msgstr ""
@@ -24790,9 +25666,6 @@ msgstr ""
msgid "The private key to use when a client certificate is provided. This value is encrypted at rest."
msgstr ""
-msgid "The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The project can be accessed by any logged in user."
msgstr ""
@@ -24829,7 +25702,7 @@ msgstr ""
msgid "The remote repository is being updated..."
msgstr ""
-msgid "The repository can be commited to, and issues, comments and other entities can be created."
+msgid "The repository can be committed to, and issues, comments and other entities can be created."
msgstr ""
msgid "The repository for this project does not exist."
@@ -24883,9 +25756,6 @@ msgstr ""
msgid "The time taken by each data entry gathered by that stage."
msgstr ""
-msgid "The total stage shows the time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The update action will time out after %{number_of_minutes} minutes. For big repositories, use a clone/push combination."
msgstr ""
@@ -24949,6 +25819,9 @@ msgstr ""
msgid "There are no archived requirements"
msgstr ""
+msgid "There are no archived test cases"
+msgstr ""
+
msgid "There are no changes"
msgstr ""
@@ -24988,6 +25861,9 @@ msgstr ""
msgid "There are no open requirements"
msgstr ""
+msgid "There are no open test cases"
+msgstr ""
+
msgid "There are no packages yet"
msgstr ""
@@ -25000,6 +25876,9 @@ msgstr ""
msgid "There is a limit of %{ci_project_subscriptions_limit} subscriptions from or to a project."
msgstr ""
+msgid "There is already a To-Do for this design."
+msgstr ""
+
msgid "There is already a repository with that name on disk"
msgstr ""
@@ -25018,6 +25897,9 @@ msgstr ""
msgid "There was a problem communicating with your device."
msgstr ""
+msgid "There was a problem fetching branches."
+msgstr ""
+
msgid "There was a problem fetching groups."
msgstr ""
@@ -25246,9 +26128,15 @@ msgstr ""
msgid "This action can lead to data loss. To prevent accidental actions we ask you to confirm your intention."
msgstr ""
+msgid "This action cannot be undone, and will permanently delete the %{key} SSH key"
+msgstr ""
+
msgid "This action cannot be undone. You will lose the project's repository and all content: issues, merge requests, etc."
msgstr ""
+msgid "This action has been performed too many times. Try again later."
+msgstr ""
+
msgid "This action will %{strongOpen}permanently delete%{strongClose} %{codeOpen}%{project}%{codeClose} %{strongOpen}immediately%{strongClose}, including its repositories and all content: issues, merge requests, etc."
msgstr ""
@@ -25276,9 +26164,6 @@ msgstr ""
msgid "This board's scope is reduced"
msgstr ""
-msgid "This branch has changed since you started editing. Would you like to create a new branch?"
-msgstr ""
-
msgid "This chart could not be displayed"
msgstr ""
@@ -25405,15 +26290,9 @@ msgstr ""
msgid "This is a security log of important events involving your account."
msgstr ""
-msgid "This is the author's first Merge Request to this project."
-msgstr ""
-
msgid "This is the highest peak of users on your installation since the license started."
msgstr ""
-msgid "This is the maximum number of users that have existed at the same time since the license started. This is the minimum number of seats you will need to buy when you renew your license."
-msgstr ""
-
msgid "This is the number of currently active users on your installation, and this is the minimum number you need to purchase when you renew your license."
msgstr ""
@@ -25645,6 +26524,15 @@ msgstr ""
msgid "This user has no identities"
msgstr ""
+msgid "This user has previously committed to the %{name} project."
+msgstr ""
+
+msgid "This user has the %{access} role in the %{name} project."
+msgstr ""
+
+msgid "This user is the author of this %{noteable}."
+msgstr ""
+
msgid "This user will be the author of all events in the activity feed that are the result of an update, like new branches being created or new commits being pushed to existing branches."
msgstr ""
@@ -25675,6 +26563,9 @@ msgstr ""
msgid "Threat Monitoring"
msgstr ""
+msgid "ThreatMonitoring|All Environments"
+msgstr ""
+
msgid "ThreatMonitoring|Anomalous Requests"
msgstr ""
@@ -25702,9 +26593,6 @@ msgstr ""
msgid "ThreatMonitoring|Operations Per Second"
msgstr ""
-msgid "ThreatMonitoring|Overview"
-msgstr ""
-
msgid "ThreatMonitoring|Packet Activity"
msgstr ""
@@ -25723,6 +26611,9 @@ msgstr ""
msgid "ThreatMonitoring|Something went wrong, unable to fetch statistics"
msgstr ""
+msgid "ThreatMonitoring|Statistics"
+msgstr ""
+
msgid "ThreatMonitoring|The firewall is not installed or has been disabled. To view this data, ensure the web application firewall is installed and enabled for your cluster."
msgstr ""
@@ -26114,6 +27005,9 @@ msgstr ""
msgid "To update Snippets with multiple files, you must use the `files` parameter"
msgstr ""
+msgid "To use Gitpod you must first enable the feature in the integrations section of your %{user_prefs}."
+msgstr ""
+
msgid "To view all %{scannedResourcesCount} scanned URLs, please download the CSV file"
msgstr ""
@@ -26147,9 +27041,6 @@ msgstr ""
msgid "Toggle Sidebar"
msgstr ""
-msgid "Toggle all threads"
-msgstr ""
-
msgid "Toggle backtrace"
msgstr ""
@@ -26174,9 +27065,6 @@ msgstr ""
msgid "Toggle navigation"
msgstr ""
-msgid "Toggle project"
-msgstr ""
-
msgid "Toggle sidebar"
msgstr ""
@@ -26216,6 +27104,9 @@ msgstr ""
msgid "Too many projects enabled. You will need to manage them via the console or the API."
msgstr ""
+msgid "Too much data"
+msgstr ""
+
msgid "Topics (optional)"
msgstr ""
@@ -26234,6 +27125,9 @@ msgstr ""
msgid "Total cores (CPUs)"
msgstr ""
+msgid "Total days to completion"
+msgstr ""
+
msgid "Total issues"
msgstr ""
@@ -26330,6 +27224,9 @@ msgstr ""
msgid "Trending"
msgstr ""
+msgid "Trials|Create a new group to start your GitLab Gold trial."
+msgstr ""
+
msgid "Trials|Go back to GitLab"
msgstr ""
@@ -26339,6 +27236,15 @@ msgstr ""
msgid "Trials|You can always resume this process by selecting your avatar and choosing 'Start a Gold trial'"
msgstr ""
+msgid "Trials|You can apply your trial to a new group or an existing group."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group or your personal account."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group, an existing group, or your personal account."
+msgstr ""
+
msgid "Trials|You won't get a free trial right now but you can always resume this process by clicking on your avatar and choosing 'Start a free trial'"
msgstr ""
@@ -26408,6 +27314,9 @@ msgstr ""
msgid "Try using a different search term to find the file you are looking for."
msgstr ""
+msgid "Trying to communicate with your device. Plug it in (if needed) and press the button on the device now."
+msgstr ""
+
msgid "Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now."
msgstr ""
@@ -26495,6 +27404,12 @@ msgstr ""
msgid "URL or request ID"
msgstr ""
+msgid "USER %{user} WILL BE REMOVED! Are you sure?"
+msgstr ""
+
+msgid "USER WILL BE BLOCKED! Are you sure?"
+msgstr ""
+
msgid "UTC"
msgstr ""
@@ -26552,9 +27467,6 @@ msgstr ""
msgid "Unable to load the merge request widget. Try reloading the page."
msgstr ""
-msgid "Unable to resolve"
-msgstr ""
-
msgid "Unable to save iteration. Please try again"
msgstr ""
@@ -26603,6 +27515,9 @@ msgstr ""
msgid "Undo ignore"
msgstr ""
+msgid "Unexpected error"
+msgstr ""
+
msgid "Unfortunately, your email message to GitLab could not be processed."
msgstr ""
@@ -26636,6 +27551,9 @@ msgstr ""
msgid "Unknown response text"
msgstr ""
+msgid "Unless otherwise agreed to in writing with GitLab, by clicking \"Upload License\" you agree that your use of GitLab Software is subject to the %{eula_link_start}Terms of Service%{eula_link_end}."
+msgstr ""
+
msgid "Unlimited"
msgstr ""
@@ -27002,9 +27920,6 @@ msgstr ""
msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
msgstr ""
-msgid "Use a hardware device to add the second factor of authentication."
-msgstr ""
-
msgid "Use an one time password authenticator on your mobile device or computer to enable two-factor authentication (2FA)."
msgstr ""
@@ -27278,13 +28193,13 @@ msgstr ""
msgid "Users"
msgstr ""
-msgid "Users in License:"
+msgid "Users in License"
msgstr ""
-msgid "Users or groups set as approvers in the project's or merge request's settings."
+msgid "Users in License:"
msgstr ""
-msgid "Users outside of license"
+msgid "Users or groups set as approvers in the project's or merge request's settings."
msgstr ""
msgid "Users over License:"
@@ -27302,9 +28217,6 @@ msgstr ""
msgid "Users with a Guest role or those who don't belong to a Project or Group will not use a seat from your license."
msgstr ""
-msgid "Users with a Guest role or those who don't belong to any projects or groups don't count towards seats in use."
-msgstr ""
-
msgid "UsersSelect|%{name} + %{length} more"
msgstr ""
@@ -27344,9 +28256,6 @@ msgstr ""
msgid "Validations failed."
msgstr ""
-msgid "Validity"
-msgstr ""
-
msgid "Value"
msgstr ""
@@ -27365,6 +28274,9 @@ msgstr ""
msgid "Value Stream Name"
msgstr ""
+msgid "ValueStreamAnalyticsStage|We don't have enough data to show this stage."
+msgstr ""
+
msgid "ValueStreamAnalytics|%{days}d"
msgstr ""
@@ -27621,6 +28533,9 @@ msgstr ""
msgid "VisualReviewApp|Steps 1 and 2 (and sometimes 3) are performed once by the developer before requesting feedback. Steps 3 (if necessary), 4 is performed by the reviewer each time they perform a review."
msgstr ""
+msgid "Visualization"
+msgstr ""
+
msgid "Vulnerabilities"
msgstr ""
@@ -27648,34 +28563,31 @@ msgstr ""
msgid "VulnerabilityChart|Severity"
msgstr ""
-msgid "VulnerabilityManagement|A true-positive and will fix"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Change status"
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|Confirm"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Confirmed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
-msgstr ""
-
-msgid "VulnerabilityManagement|Detected %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|A true-positive and will fix"
msgstr ""
-msgid "VulnerabilityManagement|Dismiss"
+msgid "VulnerabilityManagement|Change status"
msgstr ""
-msgid "VulnerabilityManagement|Dismissed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
msgstr ""
-msgid "VulnerabilityManagement|Resolved"
+msgid "VulnerabilityManagement|Detected"
msgstr ""
-msgid "VulnerabilityManagement|Resolved %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Needs triage"
msgstr ""
msgid "VulnerabilityManagement|Something went wrong while trying to delete the comment. Please try again later."
@@ -27726,6 +28638,9 @@ msgstr ""
msgid "Vulnerability|%{scannerName} (version %{scannerVersion})"
msgstr ""
+msgid "Vulnerability|Activity"
+msgstr ""
+
msgid "Vulnerability|Class"
msgstr ""
@@ -27738,6 +28653,9 @@ msgstr ""
msgid "Vulnerability|Description"
msgstr ""
+msgid "Vulnerability|Detected"
+msgstr ""
+
msgid "Vulnerability|Evidence"
msgstr ""
@@ -27801,6 +28719,9 @@ msgstr ""
msgid "Warning: Displaying this diagram might cause performance issues on this page."
msgstr ""
+msgid "We are currently unable to fetch data for the pipeline header."
+msgstr ""
+
msgid "We are currently unable to fetch data for this graph."
msgstr ""
@@ -27840,6 +28761,12 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
+msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
+msgstr ""
+
+msgid "We would like to inform you that your subscription GitLab Enterprise Edition %{plan_name} is nearing its user limit. You have %{active_user_count} active users, which is almost at the user limit of %{maximum_user_count}."
+msgstr ""
+
msgid "We've found no vulnerabilities"
msgstr ""
@@ -27855,6 +28782,12 @@ msgstr ""
msgid "Web terminal"
msgstr ""
+msgid "WebAuthn Devices (%{length})"
+msgstr ""
+
+msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
+msgstr ""
+
msgid "WebIDE|Merge request"
msgstr ""
@@ -27993,15 +28926,9 @@ msgstr ""
msgid "Welcome to the guided GitLab tour"
msgstr ""
-msgid "Welcome to your Issue Board!"
-msgstr ""
-
msgid "Welcome to your issue board!"
msgstr ""
-msgid "We’ve been making changes to %{featureName} and we’d love your feedback %{linkStart}in this issue%{linkEnd} to help us improve the experience."
-msgstr ""
-
msgid "What are you searching for?"
msgstr ""
@@ -28020,6 +28947,9 @@ msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
msgstr ""
+msgid "When enabled, any user visiting %{host} and creating an account will have to be explicitly approved by the admin before they can login. This setting is effective only if sign-ups are enabled."
+msgstr ""
+
msgid "When enabled, any user visiting %{host} will be able to create an account."
msgstr ""
@@ -28244,6 +29174,9 @@ msgstr ""
msgid "With requirements, you can set criteria to check your products against."
msgstr ""
+msgid "With test cases, you can define conditions for your project to meet in determining quality"
+msgstr ""
+
msgid "Withdraw Access Request"
msgstr ""
@@ -28259,6 +29192,9 @@ msgstr ""
msgid "Workflow Help"
msgstr ""
+msgid "Would you like to create a new branch?"
+msgstr ""
+
msgid "Write"
msgstr ""
@@ -28280,6 +29216,9 @@ msgstr ""
msgid "Wrong extern UID provided. Make sure Auth0 is configured correctly."
msgstr ""
+msgid "YYYY-MM-DD"
+msgstr ""
+
msgid "Yes"
msgstr ""
@@ -28337,7 +29276,7 @@ msgstr ""
msgid "You are going to remove the fork relationship from %{project_full_name}. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "You are going to transfer %{project_full_name} to another owner. Are you ABSOLUTELY sure?"
+msgid "You are going to transfer %{project_full_name} to another namespace. Are you ABSOLUTELY sure?"
msgstr ""
msgid "You are going to turn off the confidentiality. This means %{strongStart}everyone%{strongEnd} will be able to see and leave a comment on this %{issuableType}."
@@ -28397,9 +29336,6 @@ msgstr ""
msgid "You can always edit this later"
msgstr ""
-msgid "You can apply your Trial to your Personal account or create a New Group."
-msgstr ""
-
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings"
msgstr ""
@@ -28421,12 +29357,18 @@ msgstr ""
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
+msgid "You can find more information about GitLab subscriptions in %{subscriptions_doc_link}."
+msgstr ""
+
msgid "You can generate an access token scoped to this project for each application to use the GitLab API."
msgstr ""
msgid "You can get started by cloning the repository or start adding files to it with one of the following options."
msgstr ""
+msgid "You can group test cases using labels. To learn about the future direction of this feature, visit %{linkStart}Quality Management direction page%{linkEnd}."
+msgstr ""
+
msgid "You can invite a new member to %{project_name} or invite another group."
msgstr ""
@@ -28442,6 +29384,9 @@ msgstr ""
msgid "You can notify the app / group or a project by sending them an email notification"
msgstr ""
+msgid "You can now close this window."
+msgstr ""
+
msgid "You can now export your security dashboard to a CSV report."
msgstr ""
@@ -28490,9 +29435,6 @@ msgstr ""
msgid "You can test your .gitlab-ci.yml in %{linkStart}CI Lint%{linkEnd}."
msgstr ""
-msgid "You can try again using %{begin_link}basic search%{end_link}"
-msgstr ""
-
msgid "You cannot access the raw file. Please wait a minute."
msgstr ""
@@ -28544,6 +29486,9 @@ msgstr ""
msgid "You don't have any U2F devices registered yet."
msgstr ""
+msgid "You don't have any WebAuthn devices registered yet."
+msgstr ""
+
msgid "You don't have any active chat names."
msgstr ""
@@ -28631,6 +29576,9 @@ msgstr ""
msgid "You must accept our Terms of Service and privacy policy in order to register an account"
msgstr ""
+msgid "You must be logged in to search across all of GitLab"
+msgstr ""
+
msgid "You must disassociate %{domain} from all clusters it is attached to before deletion."
msgstr ""
@@ -28670,7 +29618,7 @@ msgstr ""
msgid "You need to be logged in."
msgstr ""
-msgid "You need to register a two-factor authentication app before you can set up a U2F device."
+msgid "You need to register a two-factor authentication app before you can set up a device."
msgstr ""
msgid "You need to set terms to be enforced"
@@ -28688,6 +29636,9 @@ msgstr ""
msgid "You reached %{usage_in_percent} of %{namespace_name}'s storage capacity (%{used_storage} of %{storage_limit})"
msgstr ""
+msgid "You successfully declined the invitation"
+msgstr ""
+
msgid "You tried to fork %{link_to_the_project} but it failed for the following reason:"
msgstr ""
@@ -28853,10 +29804,13 @@ msgstr ""
msgid "Your U2F device did not send a valid JSON response."
msgstr ""
-msgid "Your U2F device needs to be set up. Plug it in (if not already) and click the button on the left."
+msgid "Your U2F device was registered!"
msgstr ""
-msgid "Your U2F device was registered!"
+msgid "Your WebAuthn device did not send a valid JSON response."
+msgstr ""
+
+msgid "Your WebAuthn device was registered!"
msgstr ""
msgid "Your access request to the %{source_type} has been withdrawn."
@@ -28880,6 +29834,9 @@ msgstr ""
msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
msgstr ""
+msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
+msgstr ""
+
msgid "Your changes can be committed to %{branch_name} because a merge request is open."
msgstr ""
@@ -28916,6 +29873,12 @@ msgstr ""
msgid "Your deployment services will be broken, you will need to manually fix the services after renaming."
msgstr ""
+msgid "Your device is not compatible with GitLab. Please try another device"
+msgstr ""
+
+msgid "Your device needs to be set up. Plug it in (if needed) and click the button on the left."
+msgstr ""
+
msgid "Your device was successfully set up! Give it a name and register it with the GitLab server."
msgstr ""
@@ -29029,9 +29992,6 @@ msgstr[1] ""
msgid "access:"
msgstr ""
-msgid "activated"
-msgstr ""
-
msgid "added %{created_at_timeago}"
msgstr ""
@@ -29104,9 +30064,21 @@ msgstr ""
msgid "by %{user}"
msgstr ""
+msgid "cannot be a date in the past"
+msgstr ""
+
msgid "cannot be changed if a personal project has container registry tags."
msgstr ""
+msgid "cannot be changed if shared runners are enabled"
+msgstr ""
+
+msgid "cannot be enabled because parent group does not allow it"
+msgstr ""
+
+msgid "cannot be enabled because parent group has shared Runners disabled"
+msgstr ""
+
msgid "cannot be enabled unless all domains have TLS certificates"
msgstr ""
@@ -29152,7 +30124,7 @@ msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about SAST %{linkEndTag}"
msgstr ""
-msgid "ciReport|%{linkStartTag}Learn more about Secret Scanning %{linkEndTag}"
+msgid "ciReport|%{linkStartTag}Learn more about Secret Detection %{linkEndTag}"
msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about codequality reports %{linkEndTag}"
@@ -29467,9 +30439,6 @@ msgstr ""
msgid "error"
msgstr ""
-msgid "error code:"
-msgstr ""
-
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr ""
@@ -29491,6 +30460,9 @@ msgstr ""
msgid "failed to dismiss associated finding(id=%{finding_id}): %{message}"
msgstr ""
+msgid "failed to revert associated finding(id=%{finding_id}) to detected"
+msgstr ""
+
msgid "file"
msgid_plural "files"
msgstr[0] ""
@@ -30033,6 +31005,9 @@ msgstr ""
msgid "must be a root namespace"
msgstr ""
+msgid "must be a valid IPv4 or IPv6 address"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -30069,6 +31044,9 @@ msgstr ""
msgid "no expiration"
msgstr ""
+msgid "no name set"
+msgstr ""
+
msgid "no one can merge"
msgstr ""
@@ -30247,9 +31225,6 @@ msgstr ""
msgid "security Reports|There was an error creating the merge request"
msgstr ""
-msgid "settings saved, but not activated"
-msgstr ""
-
msgid "severity|Critical"
msgstr ""
@@ -30376,9 +31351,6 @@ msgstr ""
msgid "toggle collapse"
msgstr ""
-msgid "toggle dropdown"
-msgstr ""
-
msgid "triggered"
msgstr ""
@@ -30406,6 +31378,9 @@ msgstr ""
msgid "user avatar"
msgstr ""
+msgid "user preferences"
+msgstr ""
+
msgid "username"
msgstr ""
diff --git a/locale/it/gitlab.po b/locale/it/gitlab.po
index fb8bdcfa4e5..01eeae42c99 100644
--- a/locale/it/gitlab.po
+++ b/locale/it/gitlab.po
@@ -14,7 +14,10 @@ msgstr ""
"X-Crowdin-Language: it\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 6\n"
-"PO-Revision-Date: 2020-09-04 23:08\n"
+"PO-Revision-Date: 2020-10-02 18:47\n"
+
+msgid " %{project_name}#%{issue_iid} &middot; opened %{issue_created} by %{author}"
+msgstr ""
msgid " %{start} to %{end}"
msgstr ""
@@ -74,6 +77,16 @@ msgstr ""
msgid "\"el\" parameter is required for createInstance()"
msgstr ""
+msgid "%d Approval"
+msgid_plural "%d Approvals"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d Package"
+msgid_plural "%d Packages"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d Scanned URL"
msgid_plural "%d Scanned URLs"
msgstr[0] ""
@@ -137,6 +150,11 @@ msgstr[1] "%d commit,"
msgid "%d commits"
msgstr "%d commit"
+msgid "%d completed issue"
+msgid_plural "%d completed issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d contribution"
msgid_plural "%d contributions"
msgstr[0] "%d contribution"
@@ -147,6 +165,11 @@ msgid_plural "%d days"
msgstr[0] ""
msgstr[1] ""
+msgid "%d day until tags are automatically removed"
+msgid_plural "%d days until tags are automatically removed"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d error"
msgid_plural "%d errors"
msgstr[0] ""
@@ -237,6 +260,16 @@ msgid_plural "%d more comments"
msgstr[0] "%d altro commento"
msgstr[1] "Altri %d commenti"
+msgid "%d open issue"
+msgid_plural "%d open issues"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d pending comment"
+msgid_plural "%d pending comments"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d personal project will be removed and cannot be restored."
msgid_plural "%d personal projects will be removed and cannot be restored."
msgstr[0] ""
@@ -252,6 +285,11 @@ msgid_plural "%d projects"
msgstr[0] ""
msgstr[1] ""
+msgid "%d project selected"
+msgid_plural "%d projects selected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d request with warnings"
msgid_plural "%d requests with warnings"
msgstr[0] ""
@@ -272,6 +310,11 @@ msgid_plural "%d tags"
msgstr[0] ""
msgstr[1] ""
+msgid "%d tag per image name"
+msgid_plural "%d tags per image name"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d unassigned issue"
msgid_plural "%d unassigned issues"
msgstr[0] ""
@@ -292,6 +335,11 @@ msgid_plural "%d vulnerabilities dismissed"
msgstr[0] ""
msgstr[1] ""
+msgid "%d warning found:"
+msgid_plural "%d warnings found:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%s additional commit has been omitted to prevent performance issues."
msgid_plural "%s additional commits have been omitted to prevent performance issues."
msgstr[0] "%s commit aggiuntivo è stato omesso per evitare degradi di prestazioni negli issues."
@@ -330,6 +378,9 @@ msgstr ""
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr "%{commit_author_link} fatto %{commit_timeago}"
+msgid "%{completedCount} completed weight"
+msgstr ""
+
msgid "%{completedWeight} of %{totalWeight} weight completed"
msgstr ""
@@ -378,14 +429,12 @@ msgid_plural "%{count} participants"
msgstr[0] "%{count} partecipante"
msgstr[1] "%{count} partecipanti"
-msgid "%{count} pending comment"
-msgid_plural "%{count} pending comments"
-msgstr[0] "%{count} commento in attesa"
-msgstr[1] "%{count} commenti in attesa"
-
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
+msgid "%{count} total weight"
+msgstr ""
+
msgid "%{dashboard_path} could not be found."
msgstr ""
@@ -440,6 +489,9 @@ msgstr ""
msgid "%{group_name} uses group managed accounts. You need to create a new GitLab account which will be managed by %{group_name}."
msgstr ""
+msgid "%{group_name}&%{epic_iid} &middot; opened %{epic_created} by %{author}"
+msgstr ""
+
msgid "%{host} sign-in from new location"
msgstr ""
@@ -452,7 +504,7 @@ msgstr ""
msgid "%{issuableType} will be removed! Are you sure?"
msgstr "%{issuableType} sarà rimosso! Sei sicuro?"
-msgid "%{issuesSize} issues with a limit of %{maxIssueCount}"
+msgid "%{issuesCount} issues with a limit of %{maxIssueCount}"
msgstr ""
msgid "%{issuesSize} with a limit of %{maxIssueCount}"
@@ -485,7 +537,7 @@ msgstr ""
msgid "%{labelStart}Namespace:%{labelEnd} %{namespace}"
msgstr ""
-msgid "%{labelStart}Report Type:%{labelEnd} %{reportType}"
+msgid "%{labelStart}Scan Type:%{labelEnd} %{reportType}"
msgstr ""
msgid "%{labelStart}Scanner:%{labelEnd} %{scanner}"
@@ -682,9 +734,6 @@ msgid_plural "%{securityScanner} results are not available because a pipeline ha
msgstr[0] ""
msgstr[1] ""
-msgid "%{service_title} %{message}."
-msgstr ""
-
msgid "%{size} GiB"
msgstr "%{size} GiB"
@@ -773,6 +822,12 @@ msgstr "%{text} è disponibile"
msgid "%{timebox_name} should belong either to a project or a group."
msgstr ""
+msgid "%{timebox_type} does not support burnup charts"
+msgstr ""
+
+msgid "%{timebox_type} must have a start and due date"
+msgstr ""
+
msgid "%{title} %{operator} %{threshold}"
msgstr ""
@@ -797,7 +852,7 @@ msgstr ""
msgid "%{total} open issue weight"
msgstr ""
-msgid "%{total} open issues"
+msgid "%{total} warnings found: showing first %{warningsDisplayed}"
msgstr ""
msgid "%{usage_ping_link_start}Learn more%{usage_ping_link_end} about what information is shared with GitLab Inc."
@@ -830,9 +885,6 @@ msgstr ""
msgid "&lt; 1 hour"
msgstr ""
-msgid "&lt;no name set&gt;"
-msgstr ""
-
msgid "&lt;no scopes selected&gt;"
msgstr ""
@@ -863,6 +915,9 @@ msgstr "'%{level}' non è un livello di visibilità valido"
msgid "'%{name}' Value Stream created"
msgstr ""
+msgid "'%{name}' Value Stream deleted"
+msgstr ""
+
msgid "'%{name}' stage already exists"
msgstr ""
@@ -922,6 +977,9 @@ msgstr "+ %{moreCount} più"
msgid "+ %{numberOfHiddenAssignees} more"
msgstr ""
+msgid "+ %{numberOfHiddenReviewers} more"
+msgstr ""
+
msgid "+%d more"
msgid_plural "+%d more"
msgstr[0] ""
@@ -982,6 +1040,11 @@ msgid_plural "%d Days"
msgstr[0] "1 Giorno"
msgstr[1] "%d Giorni"
+msgid "1 Issue"
+msgid_plural "%d Issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "1 closed issue"
msgid_plural "%{issues} closed issues"
msgstr[0] "1 issue chiuso"
@@ -997,6 +1060,11 @@ msgid_plural "%d days"
msgstr[0] ""
msgstr[1] ""
+msgid "1 deploy key"
+msgid_plural "%d deploy keys"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] "1 gruppo"
@@ -1099,6 +1167,9 @@ msgstr "8 ore"
msgid ":%{startLine} to %{endLine}"
msgstr ""
+msgid "A %{incident_docs_start}modified issue%{incident_docs_end} to guide the resolution of incidents."
+msgstr ""
+
msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr ""
@@ -1111,6 +1182,9 @@ msgstr ""
msgid "A GitBook site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
+msgid "A Gitpod configured Webapplication in Spring and Java"
+msgstr ""
+
msgid "A Hexo site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
@@ -1282,9 +1356,15 @@ msgstr ""
msgid "Access expiration date"
msgstr ""
+msgid "Access expires"
+msgstr ""
+
msgid "Access forbidden. Check your access level."
msgstr ""
+msgid "Access granted"
+msgstr ""
+
msgid "Access requests"
msgstr ""
@@ -1294,6 +1374,9 @@ msgstr ""
msgid "Access to Pages websites are controlled based on the user's membership to a given project. By checking this box, users will be required to be logged in to have access to all Pages websites in your instance."
msgstr ""
+msgid "AccessDropdown|Deploy Keys"
+msgstr ""
+
msgid "AccessDropdown|Groups"
msgstr ""
@@ -1411,12 +1494,6 @@ msgstr ""
msgid "Active Sessions"
msgstr ""
-msgid "Active Users:"
-msgstr ""
-
-msgid "Active users"
-msgstr ""
-
msgid "Activity"
msgstr "Attività"
@@ -1584,9 +1661,6 @@ msgstr ""
msgid "Add label(s)"
msgstr ""
-msgid "Add license"
-msgstr ""
-
msgid "Add list"
msgstr ""
@@ -1761,21 +1835,51 @@ msgstr ""
msgid "AdminArea|Bots"
msgstr ""
+msgid "AdminArea|Components"
+msgstr ""
+
msgid "AdminArea|Developer"
msgstr ""
+msgid "AdminArea|Features"
+msgstr ""
+
+msgid "AdminArea|Groups: %{number_of_groups}"
+msgstr ""
+
msgid "AdminArea|Guest"
msgstr ""
msgid "AdminArea|Included Free in license"
msgstr ""
+msgid "AdminArea|Latest groups"
+msgstr ""
+
+msgid "AdminArea|Latest projects"
+msgstr ""
+
+msgid "AdminArea|Latest users"
+msgstr ""
+
msgid "AdminArea|Maintainer"
msgstr ""
+msgid "AdminArea|New group"
+msgstr ""
+
+msgid "AdminArea|New project"
+msgstr ""
+
+msgid "AdminArea|New user"
+msgstr ""
+
msgid "AdminArea|Owner"
msgstr ""
+msgid "AdminArea|Projects: %{number_of_projects}"
+msgstr ""
+
msgid "AdminArea|Reporter"
msgstr ""
@@ -1803,6 +1907,9 @@ msgstr ""
msgid "AdminArea|Users without a Group and Project"
msgstr ""
+msgid "AdminArea|Users: %{number_of_users}"
+msgstr ""
+
msgid "AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running."
msgstr ""
@@ -1821,9 +1928,6 @@ msgstr ""
msgid "AdminProjects|Delete Project %{projectName}?"
msgstr ""
-msgid "AdminProjects|Delete project"
-msgstr ""
-
msgid "AdminSettings|Apply integration settings to all Projects"
msgstr ""
@@ -2061,21 +2165,30 @@ msgstr ""
msgid "AdminUsers|Without projects"
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 ""
msgid "AdminUsers|You cannot remove your own admin rights."
msgstr ""
+msgid "AdminUsers|You must transfer ownership or delete the groups owned by this user before you can delete their account"
+msgstr ""
+
msgid "Administration"
msgstr ""
msgid "Advanced"
msgstr ""
+msgid "Advanced Search"
+msgstr ""
+
+msgid "Advanced Search with Elasticsearch"
+msgstr ""
+
msgid "Advanced Settings"
msgstr ""
@@ -2153,6 +2266,9 @@ msgstr ""
msgid "AlertManagement|Edit"
msgstr ""
+msgid "AlertManagement|Environment"
+msgstr ""
+
msgid "AlertManagement|Events"
msgstr ""
@@ -2165,6 +2281,9 @@ msgstr ""
msgid "AlertManagement|Issue"
msgstr ""
+msgid "AlertManagement|Key"
+msgstr ""
+
msgid "AlertManagement|Low"
msgstr ""
@@ -2258,6 +2377,9 @@ msgstr ""
msgid "AlertManagement|Unknown"
msgstr ""
+msgid "AlertManagement|Value"
+msgstr ""
+
msgid "AlertManagement|View alerts in Opsgenie"
msgstr ""
@@ -2417,6 +2539,9 @@ msgstr ""
msgid "All projects"
msgstr ""
+msgid "All projects selected"
+msgstr ""
+
msgid "All security scans are enabled because %{linkStart}Auto DevOps%{linkEnd} is enabled on this project"
msgstr ""
@@ -2504,6 +2629,9 @@ msgstr ""
msgid "Almost there"
msgstr ""
+msgid "Already blocked"
+msgstr ""
+
msgid "Also called \"Issuer\" or \"Relying party trust identifier\""
msgstr ""
@@ -2558,6 +2686,9 @@ msgstr ""
msgid "An error has occurred"
msgstr ""
+msgid "An error occured while making the changes: %{error}"
+msgstr ""
+
msgid "An error occurred adding a draft to the thread."
msgstr ""
@@ -2585,12 +2716,6 @@ msgstr ""
msgid "An error occurred when toggling the notification subscription"
msgstr "Errore durante l'attivazione/disattivazione della sottoscrizione per l'iscrizione"
-msgid "An error occurred when trying to resolve a comment. Please try again."
-msgstr ""
-
-msgid "An error occurred when trying to resolve a discussion. Please try again."
-msgstr ""
-
msgid "An error occurred when updating the issue weight"
msgstr ""
@@ -2606,12 +2731,6 @@ msgstr ""
msgid "An error occurred while checking group path. Please refresh and try again."
msgstr ""
-msgid "An error occurred while committing your changes."
-msgstr ""
-
-msgid "An error occurred while creating the list. Please try again."
-msgstr ""
-
msgid "An error occurred while decoding the file."
msgstr ""
@@ -2684,25 +2803,19 @@ msgstr ""
msgid "An error occurred while fetching the Service Desk address."
msgstr ""
-msgid "An error occurred while fetching the board issues. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the board lists. Please reload the page."
msgstr ""
msgid "An error occurred while fetching the board lists. Please try again."
msgstr ""
-msgid "An error occurred while fetching the board swimlanes. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the builds."
msgstr ""
msgid "An error occurred while fetching the job log."
msgstr ""
-msgid "An error occurred while fetching the job trace."
+msgid "An error occurred while fetching the job logs."
msgstr ""
msgid "An error occurred while fetching the job."
@@ -2849,9 +2962,6 @@ msgstr ""
msgid "An error occurred while saving assignees"
msgstr ""
-msgid "An error occurred while saving the template. Please check if the template exists."
-msgstr ""
-
msgid "An error occurred while searching for milestones"
msgstr ""
@@ -2870,10 +2980,10 @@ msgstr ""
msgid "An error occurred while updating approvers"
msgstr ""
-msgid "An error occurred while updating the comment"
+msgid "An error occurred while updating labels."
msgstr ""
-msgid "An error occurred while updating the list. Please try again."
+msgid "An error occurred while updating the comment"
msgstr ""
msgid "An error occurred while validating group path"
@@ -2927,6 +3037,9 @@ msgstr ""
msgid "An unknown error occurred while loading this graph."
msgstr ""
+msgid "An unknown error occurred."
+msgstr ""
+
msgid "Analytics"
msgstr ""
@@ -2960,10 +3073,10 @@ msgstr ""
msgid "Any"
msgstr ""
-msgid "Any Author"
+msgid "Any %{header}"
msgstr ""
-msgid "Any Status"
+msgid "Any Author"
msgstr ""
msgid "Any branch"
@@ -3017,6 +3130,9 @@ msgstr ""
msgid "Application ID"
msgstr ""
+msgid "Application limits saved successfully"
+msgstr ""
+
msgid "Application settings saved successfully"
msgstr ""
@@ -3226,6 +3342,9 @@ msgstr ""
msgid "Are you sure you want to close this blocked issue?"
msgstr ""
+msgid "Are you sure you want to delete \"%{name}\" Value Stream?"
+msgstr ""
+
msgid "Are you sure you want to delete %{name}?"
msgstr ""
@@ -3235,6 +3354,9 @@ msgstr ""
msgid "Are you sure you want to delete this %{typeOfComment}?"
msgstr ""
+msgid "Are you sure you want to delete this SSH key?"
+msgstr ""
+
msgid "Are you sure you want to delete this board?"
msgstr ""
@@ -3259,6 +3381,11 @@ msgstr ""
msgid "Are you sure you want to erase this build?"
msgstr ""
+msgid "Are you sure you want to import %d repository?"
+msgid_plural "Are you sure you want to import %d repositories?"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Are you sure you want to lose unsaved changes?"
msgstr ""
@@ -3268,15 +3395,15 @@ msgstr ""
msgid "Are you sure you want to merge immediately?"
msgstr ""
-msgid "Are you sure you want to permanently delete this license?"
-msgstr ""
-
msgid "Are you sure you want to re-deploy this environment?"
msgstr ""
msgid "Are you sure you want to regenerate the public key? You will have to update the public key on the remote server before mirroring will work again."
msgstr ""
+msgid "Are you sure you want to reindex?"
+msgstr ""
+
msgid "Are you sure you want to remove %{group_name}?"
msgstr ""
@@ -3304,6 +3431,9 @@ msgstr ""
msgid "Are you sure you want to revoke this nickname?"
msgstr ""
+msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
+msgstr ""
+
msgid "Are you sure you want to stop this environment?"
msgstr ""
@@ -3325,6 +3455,9 @@ msgstr ""
msgid "Are you sure? The device will be signed out of GitLab and all remember me tokens revoked."
msgstr ""
+msgid "Are you sure? This will invalidate your registered applications and U2F / WebAuthn devices."
+msgstr ""
+
msgid "Are you sure? This will invalidate your registered applications and U2F devices."
msgstr ""
@@ -3343,9 +3476,6 @@ msgstr ""
msgid "Artifacts"
msgstr "Artefatti"
-msgid "As U2F devices are only supported by a few browsers, we require that you set up a two-factor authentication app before a U2F device. That way you'll always be able to log in - even when you're using an unsupported browser."
-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 ""
@@ -3539,6 +3669,9 @@ msgstr ""
msgid "AuditLogs|Target"
msgstr ""
+msgid "AuditLogs|This month"
+msgstr ""
+
msgid "AuditLogs|User Events"
msgstr ""
@@ -3578,6 +3711,9 @@ msgstr ""
msgid "Authentication via U2F device failed."
msgstr ""
+msgid "Authentication via WebAuthn device failed."
+msgstr ""
+
msgid "Author"
msgstr "Autore"
@@ -3845,15 +3981,6 @@ msgstr ""
msgid "BambooService|You must set up automatic revision labeling and a repository trigger in Bamboo."
msgstr ""
-msgid "BatchComments|Delete all pending comments"
-msgstr ""
-
-msgid "BatchComments|Discard review?"
-msgstr ""
-
-msgid "BatchComments|You're about to discard your review which will delete all of your pending comments. The deleted comments %{strong_start}cannot%{strong_end} be restored."
-msgstr ""
-
msgid "Be careful. Changing the project's namespace can have unintended side effects."
msgstr ""
@@ -3875,6 +4002,9 @@ msgstr ""
msgid "Bi-weekly code coverage"
msgstr ""
+msgid "Billable Users:"
+msgstr ""
+
msgid "Billing"
msgstr ""
@@ -3884,7 +4014,7 @@ msgstr ""
msgid "BillingPlans|@%{user_name} you are currently using the %{plan_name} plan."
msgstr ""
-msgid "BillingPlans|Congratulations, your new trial is activated"
+msgid "BillingPlans|Congratulations, your free trial is activated."
msgstr ""
msgid "BillingPlans|If you would like to downgrade your plan please contact %{support_link_start}Customer Support%{support_link_end}."
@@ -3947,6 +4077,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Block user"
+msgstr ""
+
msgid "Blocked"
msgstr ""
@@ -3962,31 +4095,37 @@ msgstr ""
msgid "Blog"
msgstr ""
-msgid "Board name"
-msgstr ""
-
msgid "Board scope"
msgstr ""
msgid "Board scope affects which issues are displayed for anyone who visits this board"
msgstr ""
-msgid "BoardBlankState|Add default lists"
+msgid "Boards"
msgstr ""
-msgid "BoardBlankState|Add the following default lists to your Issue Board with one click:"
+msgid "Boards and Board Lists"
msgstr ""
-msgid "BoardBlankState|Nevermind, I'll use my own"
+msgid "Boards|An error occurred while creating the issue. Please try again."
msgstr ""
-msgid "BoardBlankState|Starting out with the default set of lists will get you right on the way to making the most of your board."
+msgid "Boards|An error occurred while creating the list. Please try again."
msgstr ""
-msgid "Boards"
+msgid "Boards|An error occurred while fetching issues. Please reload the page."
msgstr ""
-msgid "Boards and Board Lists"
+msgid "Boards|An error occurred while fetching the board issues. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching the board swimlanes. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while moving the issue. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while updating the list. Please try again."
msgstr ""
msgid "Boards|Collapse"
@@ -4013,8 +4152,8 @@ msgstr ""
msgid "Branch %{branch_name} was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr ""
-msgid "Branch has changed"
-msgstr "La branche è cambiata"
+msgid "Branch changed"
+msgstr ""
msgid "Branch is already taken"
msgstr "La Branch esiste già"
@@ -4319,6 +4458,9 @@ msgstr ""
msgid "CLOSED (MOVED)"
msgstr ""
+msgid "CODEOWNERS rule violation"
+msgstr ""
+
msgid "CONTRIBUTING"
msgstr ""
@@ -4349,9 +4491,6 @@ msgstr ""
msgid "Can't create snippet: %{err}"
msgstr ""
-msgid "Can't edit as source branch was deleted"
-msgstr ""
-
msgid "Can't fetch content for the blob: %{err}"
msgstr ""
@@ -4364,9 +4503,6 @@ msgstr ""
msgid "Can't load mermaid module: %{err}"
msgstr ""
-msgid "Can't remove group members without group managed account"
-msgstr ""
-
msgid "Can't scan the code?"
msgstr ""
@@ -4409,6 +4545,9 @@ msgstr ""
msgid "Cannot create the abuse report. This user has been blocked."
msgstr ""
+msgid "Cannot enable shared runners because parent group does not allow it"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -4514,6 +4653,15 @@ msgstr ""
msgid "Change your password or recover your current one"
msgstr ""
+msgid "ChangeReviewer|Reviewer changed from %{old} to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Reviewer changed to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Unassigned"
+msgstr ""
+
msgid "ChangeTypeActionLabel|Pick into branch"
msgstr "Preleva nella branch"
@@ -4553,6 +4701,9 @@ msgstr ""
msgid "Changes the title to \"%{title_param}\"."
msgstr ""
+msgid "Changes were successfully made."
+msgstr ""
+
msgid "Changes won't take place until the index is %{link_start}recreated%{link_end}."
msgstr ""
@@ -4958,6 +5109,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove variable"
+msgstr ""
+
msgid "CiVariables|Remove variable row"
msgstr ""
@@ -5036,9 +5190,6 @@ msgstr ""
msgid "Clear due date"
msgstr ""
-msgid "Clear input"
-msgstr ""
-
msgid "Clear recent searches"
msgstr ""
@@ -5087,6 +5238,9 @@ msgstr ""
msgid "Client authentication key password"
msgstr ""
+msgid "Client request timeout"
+msgstr ""
+
msgid "Clients"
msgstr ""
@@ -5171,6 +5325,27 @@ msgstr ""
msgid "Cluster type must be specificed for Stages::ClusterEndpointInserter"
msgstr ""
+msgid "ClusterAgents|Configuration"
+msgstr ""
+
+msgid "ClusterAgents|Connect your cluster with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate Kubernetes with a GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Name"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Agent also requires %{linkStart}enabling the Agent Server%{linkEnd}"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Kubernetes Agent allows an Infrastructure as Code, GitOps approach to integrating Kubernetes clusters with GitLab. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "ClusterAgent|This feature is only available for premium plans"
msgstr ""
@@ -5240,10 +5415,10 @@ msgstr ""
msgid "ClusterIntegration|All installed applications and related resources"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster."
+msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{linkStart}More information%{linkEnd}"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{startLink}More information%{endLink}"
+msgid "ClusterIntegration|Allow GitLab to manage namespaces and service accounts for this cluster."
msgstr ""
msgid "ClusterIntegration|Alternatively, "
@@ -5264,6 +5439,9 @@ msgstr ""
msgid "ClusterIntegration|An error occurred while trying to fetch zone machine types: %{error}"
msgstr ""
+msgid "ClusterIntegration|An unknown error occurred while attempting to connect to Kubernetes."
+msgstr ""
+
msgid "ClusterIntegration|Any project namespaces"
msgstr ""
@@ -5279,6 +5457,9 @@ msgstr ""
msgid "ClusterIntegration|Authenticate with Amazon Web Services"
msgstr ""
+msgid "ClusterIntegration|Authentication Error"
+msgstr ""
+
msgid "ClusterIntegration|Base domain"
msgstr ""
@@ -5297,13 +5478,22 @@ msgstr ""
msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
msgstr "Certificate Authority bundle (formato PEM)"
-msgid "ClusterIntegration|Choose the %{startLink}security group %{externalLinkIcon} %{endLink} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
+msgid "ClusterIntegration|Check your CA certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Check your cluster status"
+msgstr ""
+
+msgid "ClusterIntegration|Check your token"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}subnets %{externalLinkIcon} %{endLink} in your VPC where your worker nodes will run."
+msgid "ClusterIntegration|Choose the %{linkStart}security group %{linkEnd} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
msgstr ""
-msgid "ClusterIntegration|Choose the worker node %{startLink}instance type %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Choose the %{linkStart}subnets %{linkEnd} in your VPC where your worker nodes will run."
+msgstr ""
+
+msgid "ClusterIntegration|Choose the worker node %{linkStart}instance type%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Choose which applications to install on your Kubernetes cluster."
@@ -5315,10 +5505,7 @@ msgstr ""
msgid "ClusterIntegration|Clear cluster cache"
msgstr ""
-msgid "ClusterIntegration|Clear the local cache of namespace and service accounts. This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
-msgstr ""
-
-msgid "ClusterIntegration|Cluster being created"
+msgid "ClusterIntegration|Clear the local cache of namespace and service accounts."
msgstr ""
msgid "ClusterIntegration|Cluster management project (alpha)"
@@ -5330,15 +5517,21 @@ msgstr ""
msgid "ClusterIntegration|Cluster_applications artifact too big. Maximum allowable size: %{human_size}"
msgstr ""
-msgid "ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters."
+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|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}"
+msgid "ClusterIntegration|Clusters connected with a certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Connect cluster with certificate"
msgstr ""
msgid "ClusterIntegration|Connect existing cluster"
msgstr ""
+msgid "ClusterIntegration|Connection Error"
+msgstr ""
+
msgid "ClusterIntegration|Copy API URL"
msgstr "Copia URL API"
@@ -5414,6 +5607,12 @@ msgstr ""
msgid "ClusterIntegration|Deletes all GitLab resources attached to this cluster during removal"
msgstr ""
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared."
+msgstr ""
+
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared. %{linkStart}More information%{linkEnd}"
+msgstr ""
+
msgid "ClusterIntegration|Did you know?"
msgstr ""
@@ -5483,6 +5682,9 @@ msgstr ""
msgid "ClusterIntegration|Fluentd is an open source data collector, which lets you unify the data collection and consumption for a better use and understanding of data. It requires at least one of the following logs to be successfully installed."
msgstr ""
+msgid "ClusterIntegration|GitLab Agent managed clusters"
+msgstr ""
+
msgid "ClusterIntegration|GitLab Container Network Policies"
msgstr ""
@@ -5495,6 +5697,12 @@ msgstr "Gitlab Runner"
msgid "ClusterIntegration|GitLab Runner connects to the repository and executes CI/CD jobs, pushing results back and deploying applications to production."
msgstr ""
+msgid "ClusterIntegration|GitLab failed to authenticate."
+msgstr ""
+
+msgid "ClusterIntegration|GitLab failed to connect to the cluster."
+msgstr ""
+
msgid "ClusterIntegration|GitLab-managed cluster"
msgstr ""
@@ -5516,6 +5724,9 @@ msgstr ""
msgid "ClusterIntegration|Group cluster"
msgstr ""
+msgid "ClusterIntegration|HTTP Error"
+msgstr ""
+
msgid "ClusterIntegration|Helm Tiller"
msgstr "Helm Tiller"
@@ -5549,7 +5760,10 @@ msgstr ""
msgid "ClusterIntegration|Instance type"
msgstr ""
-msgid "ClusterIntegration|Integrate Kubernetes cluster automation"
+msgid "ClusterIntegration|Integrate Kubernetes with a cluster certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Integrate with a cluster certificate"
msgstr ""
msgid "ClusterIntegration|Issuer Email"
@@ -5585,9 +5799,6 @@ msgstr ""
msgid "ClusterIntegration|Knative extends Kubernetes to provide a set of middleware components that are essential to build modern, source-centric, and container-based applications that can run anywhere: on premises, in the cloud, or even in a third-party data center."
msgstr ""
-msgid "ClusterIntegration|Kubernetes cluster"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes cluster is being created..."
msgstr ""
@@ -5600,9 +5811,6 @@ msgstr ""
msgid "ClusterIntegration|Kubernetes clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr ""
-msgid "ClusterIntegration|Kubernetes clusters can be used to deploy applications and to provide Review Apps for this project"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes version"
msgstr ""
@@ -5615,7 +5823,7 @@ msgstr ""
msgid "ClusterIntegration|Learn more about %{help_link_start}zones%{help_link_end}."
msgstr ""
-msgid "ClusterIntegration|Learn more about %{startLink}Regions %{externalLinkIcon}%{endLink}."
+msgid "ClusterIntegration|Learn more about %{linkStart}Regions%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Learn more about Kubernetes"
@@ -5660,12 +5868,18 @@ msgstr ""
msgid "ClusterIntegration|Machine type"
msgstr "Tipo di macchina"
+msgid "ClusterIntegration|Make sure your API endpoint is correct"
+msgstr ""
+
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create Kubernetes clusters"
msgstr ""
msgid "ClusterIntegration|Manage your Kubernetes cluster by visiting %{provider_link}"
msgstr ""
+msgid "ClusterIntegration|Namespace per environment"
+msgstr ""
+
msgid "ClusterIntegration|No IAM Roles found"
msgstr ""
@@ -5711,6 +5925,9 @@ msgstr ""
msgid "ClusterIntegration|No zones matched your search"
msgstr ""
+msgid "ClusterIntegration|Node calculations use the Kubernetes Metrics API. Make sure your cluster has metrics installed"
+msgstr ""
+
msgid "ClusterIntegration|Number of nodes"
msgstr "Numero di nodi"
@@ -5753,6 +5970,9 @@ msgstr ""
msgid "ClusterIntegration|RBAC-enabled cluster"
msgstr ""
+msgid "ClusterIntegration|Read our %{linkStart}help page%{linkEnd} on Kubernetes cluster integration."
+msgstr ""
+
msgid "ClusterIntegration|Read our %{link_start}help page%{link_end} on Kubernetes cluster integration."
msgstr ""
@@ -5855,7 +6075,7 @@ msgstr ""
msgid "ClusterIntegration|Select a VPC to choose a subnet"
msgstr ""
-msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{linkStart}Amazon Web Services %{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select a network to choose a subnetwork"
@@ -5888,7 +6108,7 @@ msgstr ""
msgid "ClusterIntegration|Select project to choose zone"
msgstr ""
-msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select zone"
@@ -5978,9 +6198,18 @@ msgstr ""
msgid "ClusterIntegration|There was a problem authenticating with your cluster. Please ensure your CA Certificate and Token are valid."
msgstr ""
+msgid "ClusterIntegration|There was an HTTP error when connecting to your cluster."
+msgstr ""
+
msgid "ClusterIntegration|This account must have permissions to create a Kubernetes cluster in the %{link_to_container_project} specified below"
msgstr ""
+msgid "ClusterIntegration|This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
+msgstr ""
+
+msgid "ClusterIntegration|This is necessary to clear existing environment-namespace associations from clusters previously managed by GitLab."
+msgstr ""
+
msgid "ClusterIntegration|This option will allow you to install applications on RBAC clusters."
msgstr ""
@@ -6005,9 +6234,21 @@ msgstr ""
msgid "ClusterIntegration|To use a new project, first create one on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}."
msgstr ""
+msgid "ClusterIntegration|Troubleshooting tips:"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Authenticate"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Connect"
+msgstr ""
+
msgid "ClusterIntegration|Uninstall %{appTitle}"
msgstr ""
+msgid "ClusterIntegration|Unknown Error"
+msgstr ""
+
msgid "ClusterIntegration|Update %{appTitle}"
msgstr ""
@@ -6068,7 +6309,7 @@ msgstr ""
msgid "ClusterIntegration|Your cluster API is unreachable. Please ensure your API URL is correct."
msgstr ""
-msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Zone"
@@ -6188,6 +6429,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse all threads"
+msgstr ""
+
msgid "Collapse approvers"
msgstr ""
@@ -6337,7 +6581,7 @@ msgstr "Committato da "
msgid "Commit…"
msgstr ""
-msgid "Company"
+msgid "Community forum"
msgstr ""
msgid "Company name"
@@ -6346,6 +6590,9 @@ msgstr ""
msgid "Compare"
msgstr "Confronta"
+msgid "Compare %{oldCommitId}...%{newCommitId}"
+msgstr ""
+
msgid "Compare Git revisions"
msgstr ""
@@ -6361,6 +6608,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare submodule commit revisions"
+msgstr ""
+
msgid "Compare with previous version"
msgstr ""
@@ -6496,6 +6746,9 @@ msgstr ""
msgid "Configure the way a user creates a new account."
msgstr ""
+msgid "Configure which lists are shown for anyone who visits this board"
+msgstr ""
+
msgid "Confirm"
msgstr ""
@@ -6721,6 +6974,9 @@ msgstr[1] ""
msgid "ContainerRegistry|Set cleanup policy"
msgstr ""
+msgid "ContainerRegistry|Some tags were not deleted"
+msgstr ""
+
msgid "ContainerRegistry|Something went wrong while fetching the cleanup policy."
msgstr ""
@@ -6760,6 +7016,9 @@ msgstr ""
msgid "ContainerRegistry|Tags with names matching this regex pattern will %{italicStart}expire:%{italicEnd}"
msgstr ""
+msgid "ContainerRegistry|The cleanup policy timed out before it could delete all tags. An administrator can %{adminLinkStart}manually run cleanup now%{adminLinkEnd} or you can wait for the cleanup policy to automatically run again. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "ContainerRegistry|The last tag related to this image was recently removed. This empty image and any associated data will be automatically removed as part of the regular Garbage Collection process. If you have any questions, contact your administrator."
msgstr ""
@@ -6892,6 +7151,9 @@ msgstr ""
msgid "Contributions per group member"
msgstr ""
+msgid "Contributor"
+msgstr ""
+
msgid "Contributors"
msgstr "Collaboratori"
@@ -7021,6 +7283,9 @@ msgstr ""
msgid "Could not change HEAD: branch '%{branch}' does not exist"
msgstr ""
+msgid "Could not commit. An unexpected error occurred."
+msgstr ""
+
msgid "Could not connect to FogBugz, check your URL"
msgstr ""
@@ -7060,6 +7325,9 @@ msgstr ""
msgid "Could not find iteration"
msgstr ""
+msgid "Could not load instance counts. Please refresh the page to try again."
+msgstr ""
+
msgid "Could not remove the trigger."
msgstr ""
@@ -7084,10 +7352,10 @@ msgstr ""
msgid "Could not save prometheus manual configuration"
msgstr ""
-msgid "Could not udpdate wiki page"
+msgid "Could not update the LDAP settings"
msgstr ""
-msgid "Could not update the LDAP settings"
+msgid "Could not update wiki page"
msgstr ""
msgid "Could not upload your designs as one or more files uploaded are not supported."
@@ -7745,6 +8013,9 @@ msgstr ""
msgid "DastProfiles|Are you sure you want to delete this profile?"
msgstr ""
+msgid "DastProfiles|Could not create site validation token. Please refresh the page, or try again later."
+msgstr ""
+
msgid "DastProfiles|Could not create the scanner profile. Please try again."
msgstr ""
@@ -7769,6 +8040,12 @@ msgstr ""
msgid "DastProfiles|Could not fetch site profiles. Please refresh the page, or try again later."
msgstr ""
+msgid "DastProfiles|Could not retrieve site validation status. Please refresh the page, or try again later."
+msgstr ""
+
+msgid "DastProfiles|Could not update the scanner profile. Please try again."
+msgstr ""
+
msgid "DastProfiles|Could not update the site profile. Please try again."
msgstr ""
@@ -7784,7 +8061,7 @@ msgstr ""
msgid "DastProfiles|Download validation text file"
msgstr ""
-msgid "DastProfiles|Edit feature will come soon. Please create a new profile if changes needed"
+msgid "DastProfiles|Edit scanner profile"
msgstr ""
msgid "DastProfiles|Edit site profile"
@@ -7817,6 +8094,9 @@ msgstr ""
msgid "DastProfiles|No profiles created yet"
msgstr ""
+msgid "DastProfiles|Passive"
+msgstr ""
+
msgid "DastProfiles|Please enter a valid URL format, ex: http://www.example.com/home"
msgstr ""
@@ -7832,6 +8112,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan mode"
+msgstr ""
+
msgid "DastProfiles|Scanner Profile"
msgstr ""
@@ -7871,10 +8154,10 @@ msgstr ""
msgid "DastProfiles|Text file validation"
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
+msgid "DastProfiles|The maximum number of minutes allowed for the spider to traverse the site."
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the spider to traverse the site."
+msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
msgstr ""
msgid "DastProfiles|Validate"
@@ -7907,6 +8190,9 @@ msgstr ""
msgid "Date picker"
msgstr ""
+msgid "Date range"
+msgstr ""
+
msgid "Date range cannot exceed %{maxDateRange} days."
msgstr ""
@@ -7931,6 +8217,9 @@ msgstr ""
msgid "Days to merge"
msgstr ""
+msgid "Dear Administrator,"
+msgstr ""
+
msgid "Debug"
msgstr ""
@@ -8042,12 +8331,18 @@ msgstr ""
msgid "Delete"
msgstr "Elimina"
+msgid "Delete %{name}"
+msgstr ""
+
msgid "Delete Comment"
msgstr ""
msgid "Delete Snippet"
msgstr ""
+msgid "Delete Value Stream"
+msgstr ""
+
msgid "Delete account"
msgstr ""
@@ -8069,9 +8364,6 @@ msgstr ""
msgid "Delete label: %{label_name} ?"
msgstr ""
-msgid "Delete license"
-msgstr ""
-
msgid "Delete list"
msgstr ""
@@ -8147,15 +8439,6 @@ msgstr ""
msgid "Deleting a project places it into a read-only state until %{date}, at which point the project will be permanently deleted. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "Deleting the license failed."
-msgstr ""
-
-msgid "Deleting the license failed. The license was not found."
-msgstr ""
-
-msgid "Deleting the license failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "Deleting the project will delete its repository and all related resources including issues, merge requests etc."
msgstr ""
@@ -8651,7 +8934,10 @@ msgstr ""
msgid "DesignManagement|The maximum number of designs allowed to be uploaded is %{upload_limit}. Please try again."
msgstr ""
-msgid "DesignManagement|To upload designs, you'll need to enable LFS. %{requirements_link_start}More information%{requirements_link_end}"
+msgid "DesignManagement|There was an error moving your designs. Please upload your designs below."
+msgstr ""
+
+msgid "DesignManagement|To upload designs, you'll need to enable LFS and have admin enable hashed storage. %{requirements_link_start}More information%{requirements_link_end}"
msgstr ""
msgid "DesignManagement|Unresolve thread"
@@ -8663,6 +8949,9 @@ msgstr ""
msgid "DesignManagement|Upload skipped."
msgstr ""
+msgid "DesignManagement|Your designs are being copied and are on their way… Please refresh to update."
+msgstr ""
+
msgid "DesignManagement|and %{moreCount} more."
msgstr ""
@@ -8720,6 +9009,9 @@ msgstr ""
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
+msgid "Direct member"
+msgstr ""
+
msgid "Direction"
msgstr ""
@@ -8768,9 +9060,6 @@ msgstr ""
msgid "Discard draft"
msgstr ""
-msgid "Discard review"
-msgstr ""
-
msgid "DiscordService|Discord Notifications"
msgstr ""
@@ -8839,10 +9128,10 @@ msgstr ""
msgid "Dismiss Merge Request promotion"
msgstr ""
-msgid "Dismiss Selected"
+msgid "Dismiss Value Stream Analytics introduction box"
msgstr ""
-msgid "Dismiss Value Stream Analytics introduction box"
+msgid "Dismiss selected"
msgstr ""
msgid "Dismiss trial promotion"
@@ -8893,9 +9182,6 @@ msgstr ""
msgid "Documents reindexed: %{processed_documents} (%{percentage}%%)"
msgstr ""
-msgid "Doing"
-msgstr ""
-
msgid "Domain"
msgstr ""
@@ -9091,9 +9377,6 @@ msgstr ""
msgid "Edit environment"
msgstr ""
-msgid "Edit file"
-msgstr ""
-
msgid "Edit files in the editor and commit changes here"
msgstr ""
@@ -9106,6 +9389,12 @@ msgstr ""
msgid "Edit identity for %{user_name}"
msgstr ""
+msgid "Edit in Web IDE"
+msgstr ""
+
+msgid "Edit in single-file editor"
+msgstr ""
+
msgid "Edit issues"
msgstr ""
@@ -9133,10 +9422,10 @@ msgstr ""
msgid "Editing"
msgstr ""
-msgid "Elasticsearch"
+msgid "Elasticsearch AWS IAM credentials"
msgstr ""
-msgid "Elasticsearch AWS IAM credentials"
+msgid "Elasticsearch HTTP client timeout value in seconds."
msgstr ""
msgid "Elasticsearch indexing restrictions"
@@ -9145,9 +9434,6 @@ msgstr ""
msgid "Elasticsearch indexing started"
msgstr ""
-msgid "Elasticsearch integration. Elasticsearch AWS IAM."
-msgstr ""
-
msgid "Elasticsearch reindexing is already in progress"
msgstr ""
@@ -9175,9 +9461,6 @@ msgstr ""
msgid "Email Notification"
msgstr ""
-msgid "Email address"
-msgstr ""
-
msgid "Email could not be sent"
msgstr ""
@@ -9241,6 +9524,9 @@ msgstr "E-mail"
msgid "Emails sent from Service Desk will have this name"
msgstr ""
+msgid "Emails sent to %{email} will still be supported"
+msgstr ""
+
msgid "Emails separated by comma"
msgstr ""
@@ -9274,9 +9560,18 @@ msgstr ""
msgid "Enable"
msgstr ""
+msgid "Enable %{link_start}Gitpod%{link_end} integration to launch a development environment in your browser directly from GitLab."
+msgstr ""
+
msgid "Enable Auto DevOps"
msgstr ""
+msgid "Enable Gitpod"
+msgstr ""
+
+msgid "Enable Gitpod?"
+msgstr ""
+
msgid "Enable HTML emails"
msgstr ""
@@ -9406,9 +9701,6 @@ msgstr ""
msgid "Encountered an error while rendering: %{err}"
msgstr ""
-msgid "End date"
-msgstr ""
-
msgid "Ends at (UTC)"
msgstr ""
@@ -9568,7 +9860,7 @@ msgstr ""
msgid "EnvironmentsDashboard|The environments dashboard provides a summary of each project's environments' status, including pipeline and alert statuses."
msgstr ""
-msgid "EnvironmentsDashboard|This dashboard displays a maximum of 7 projects and 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
+msgid "EnvironmentsDashboard|This dashboard displays 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
msgstr ""
msgid "Environments|An error occurred while canceling the auto stop, please try again"
@@ -9889,6 +10181,9 @@ msgstr ""
msgid "Error deleting project. Check logs for error details."
msgstr ""
+msgid "Error fetching burnup chart data"
+msgstr ""
+
msgid "Error fetching diverging counts for branches. Please try again."
msgstr ""
@@ -9967,6 +10262,9 @@ msgstr ""
msgid "Error occurred when saving assignees"
msgstr ""
+msgid "Error occurred when saving reviewers"
+msgstr ""
+
msgid "Error occurred when toggling the notification subscription"
msgstr "Errore durante l'attivazione/disattivazione della sottoscrizione per l'iscrizione"
@@ -10219,10 +10517,13 @@ msgstr ""
msgid "Expand all"
msgstr ""
-msgid "Expand approvers"
+msgid "Expand all files"
msgstr ""
-msgid "Expand dropdown"
+msgid "Expand all threads"
+msgstr ""
+
+msgid "Expand approvers"
msgstr ""
msgid "Expand milestones"
@@ -10393,6 +10694,9 @@ msgstr ""
msgid "Failed to create Merge Request. Please try again."
msgstr ""
+msgid "Failed to create To-Do for the design."
+msgstr ""
+
msgid "Failed to create a branch for this issue. Please try again."
msgstr ""
@@ -10432,6 +10736,12 @@ msgstr ""
msgid "Failed to load authors. Please try again."
msgstr ""
+msgid "Failed to load branches. Please try again."
+msgstr ""
+
+msgid "Failed to load deploy keys."
+msgstr ""
+
msgid "Failed to load emoji list."
msgstr ""
@@ -10447,6 +10757,9 @@ msgstr ""
msgid "Failed to load groups & users."
msgstr ""
+msgid "Failed to load groups, users and deploy keys."
+msgstr ""
+
msgid "Failed to load labels. Please try again."
msgstr ""
@@ -10456,6 +10769,12 @@ msgstr ""
msgid "Failed to load related branches"
msgstr ""
+msgid "Failed to load sidebar confidential toggle"
+msgstr ""
+
+msgid "Failed to load sidebar lock status"
+msgstr ""
+
msgid "Failed to load stacktrace."
msgstr ""
@@ -10483,6 +10802,9 @@ msgstr ""
msgid "Failed to publish issue on status page."
msgstr ""
+msgid "Failed to remove To-Do for the design."
+msgstr ""
+
msgid "Failed to remove a Zoom meeting"
msgstr ""
@@ -10525,6 +10847,9 @@ msgstr ""
msgid "Failed to signing using smartcard authentication"
msgstr ""
+msgid "Failed to toggle To-Do for the design."
+msgstr ""
+
msgid "Failed to update branch!"
msgstr ""
@@ -10638,7 +10963,7 @@ msgstr ""
msgid "FeatureFlags|Edit User List"
msgstr ""
-msgid "FeatureFlags|Enable features for specific users and specific environments by defining feature flag strategies."
+msgid "FeatureFlags|Enable features for specific users and environments by configuring feature flag strategies."
msgstr ""
msgid "FeatureFlags|Environment Spec"
@@ -10698,7 +11023,7 @@ msgstr ""
msgid "FeatureFlags|Include additional user IDs"
msgstr ""
-msgid "FeatureFlags|Install a %{docs_link_anchored_start}compatible client library%{docs_link_anchored_end} and specify the API URL, application name, and instance ID during the configuration setup. %{docs_link_start}More Information%{docs_link_end}"
+msgid "FeatureFlags|Install a %{docsLinkAnchoredStart}compatible client library%{docsLinkAnchoredEnd} and specify the API URL, application name, and instance ID during the configuration setup. %{docsLinkStart}More Information%{docsLinkEnd}"
msgstr ""
msgid "FeatureFlags|Instance ID"
@@ -10710,6 +11035,9 @@ msgstr ""
msgid "FeatureFlags|Loading feature flags"
msgstr ""
+msgid "FeatureFlags|Loading user lists"
+msgstr ""
+
msgid "FeatureFlags|More information"
msgstr ""
@@ -10728,7 +11056,7 @@ msgstr ""
msgid "FeatureFlags|New feature flag"
msgstr ""
-msgid "FeatureFlags|New list"
+msgid "FeatureFlags|New user list"
msgstr ""
msgid "FeatureFlags|Percent of users"
@@ -10767,6 +11095,9 @@ msgstr ""
msgid "FeatureFlags|There was an error fetching the feature flags."
msgstr ""
+msgid "FeatureFlags|There was an error fetching the user lists."
+msgstr ""
+
msgid "FeatureFlags|There was an error retrieving user lists"
msgstr ""
@@ -10782,6 +11113,9 @@ msgstr ""
msgid "FeatureFlags|User List"
msgstr ""
+msgid "FeatureFlags|User Lists"
+msgstr ""
+
msgid "FeatureFlag|List"
msgstr ""
@@ -10809,15 +11143,6 @@ msgstr "Febbraio"
msgid "Fetching incoming email"
msgstr ""
-msgid "Fetching licenses failed."
-msgstr ""
-
-msgid "Fetching licenses failed. The request endpoint was not found."
-msgstr ""
-
-msgid "Fetching licenses failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "File"
msgstr ""
@@ -10920,12 +11245,21 @@ msgstr ""
msgid "Filter by status"
msgstr ""
+msgid "Filter by test cases that are currently archived."
+msgstr ""
+
+msgid "Filter by test cases that are currently opened."
+msgstr ""
+
msgid "Filter by two-factor authentication"
msgstr ""
msgid "Filter by user"
msgstr ""
+msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
+msgstr ""
+
msgid "Filter pipelines"
msgstr ""
@@ -10941,7 +11275,7 @@ msgstr ""
msgid "Filter results..."
msgstr ""
-msgid "Filter your projects by name"
+msgid "Filter your repositories by name"
msgstr ""
msgid "Filter..."
@@ -10950,7 +11284,7 @@ msgstr ""
msgid "Find File"
msgstr ""
-msgid "Find bugs in your code with coverage-guided fuzzing"
+msgid "Find bugs in your code with coverage-guided fuzzing."
msgstr ""
msgid "Find by path"
@@ -10977,9 +11311,6 @@ msgstr ""
msgid "Finish editing this message first!"
msgstr ""
-msgid "Finish review"
-msgstr ""
-
msgid "Finish setting up your dedicated account for %{group_name}."
msgstr ""
@@ -11049,6 +11380,9 @@ msgstr ""
msgid "Footer message"
msgstr ""
+msgid "For a faster browsing experience, some files are collapsed by default."
+msgstr ""
+
msgid "For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
@@ -11058,6 +11392,9 @@ msgstr ""
msgid "For more info, read the documentation."
msgstr ""
+msgid "For more information on how the number of active users is calculated, see the %{self_managed_subscriptions_doc_link} documentation."
+msgstr ""
+
msgid "For more information, go to the "
msgstr ""
@@ -11196,6 +11533,9 @@ msgstr ""
msgid "Generate new token"
msgstr ""
+msgid "Generic package file size in bytes"
+msgstr ""
+
msgid "Geo"
msgstr ""
@@ -11457,6 +11797,9 @@ msgstr ""
msgid "Geo|Please refer to Geo Troubleshooting."
msgstr ""
+msgid "Geo|Primary node"
+msgstr ""
+
msgid "Geo|Project"
msgstr ""
@@ -11499,6 +11842,9 @@ msgstr ""
msgid "Geo|Review replication status, and resynchronize and reverify items with the primary node."
msgstr ""
+msgid "Geo|Secondary node"
+msgstr ""
+
msgid "Geo|Status"
msgstr ""
@@ -11538,6 +11884,9 @@ msgstr ""
msgid "Geo|URL must be a valid url (ex: https://gitlab.com)"
msgstr ""
+msgid "Geo|Undefined"
+msgstr ""
+
msgid "Geo|Unknown state"
msgstr ""
@@ -11613,10 +11962,16 @@ msgstr ""
msgid "GitHub import"
msgstr ""
+msgid "GitLab"
+msgstr ""
+
msgid "GitLab / Unsubscribe"
msgstr ""
-msgid "GitLab Enterprise Edition %{plan}"
+msgid "GitLab API"
+msgstr ""
+
+msgid "GitLab Billing Team."
msgstr ""
msgid "GitLab Group Runners can execute code for all the projects in this group."
@@ -11628,12 +11983,18 @@ msgstr ""
msgid "GitLab Issue"
msgstr ""
+msgid "GitLab Pages"
+msgstr ""
+
msgid "GitLab Service Desk is a simple way to allow people to create issues in your GitLab instance without needing their own user account. It provides a unique email address for end users to create issues in a project, and replies can be sent either through the GitLab interface or by email. End users will only see the thread through email."
msgstr ""
msgid "GitLab Shared Runners execute code of different projects on the same Runner unless you configure GitLab Runner Autoscale with MaxBuilds 1 (which it is on GitLab.com)."
msgstr ""
+msgid "GitLab Shell"
+msgstr ""
+
msgid "GitLab Support Bot"
msgstr ""
@@ -11643,7 +12004,7 @@ msgstr ""
msgid "GitLab User"
msgstr ""
-msgid "GitLab allows you to continue using your license even if you exceed the number of seats you purchased. You will be required to pay for these seats when you renew your license."
+msgid "GitLab Workhorse"
msgstr ""
msgid "GitLab commit"
@@ -11811,6 +12172,21 @@ msgstr ""
msgid "Gitlab Pages"
msgstr ""
+msgid "Gitpod"
+msgstr ""
+
+msgid "Gitpod|Add the URL to your Gitpod instance configured to read your GitLab projects."
+msgstr ""
+
+msgid "Gitpod|Enable Gitpod integration"
+msgstr ""
+
+msgid "Gitpod|Gitpod URL"
+msgstr ""
+
+msgid "Gitpod|e.g. https://gitpod.example.com"
+msgstr ""
+
msgid "Given access %{time_ago}"
msgstr ""
@@ -12318,9 +12694,6 @@ msgstr ""
msgid "GroupSAML|Valid SAML Response"
msgstr ""
-msgid "GroupSAML|With group managed accounts enabled, all the users without a group managed account will be excluded from the group."
-msgstr ""
-
msgid "GroupSAML|With prohibit outer forks flag enabled group members will be able to fork project only inside your group."
msgstr ""
@@ -12534,10 +12907,10 @@ msgstr ""
msgid "GroupsNew|Create group"
msgstr ""
-msgid "GroupsNew|GitLab group export"
+msgid "GroupsNew|Import"
msgstr ""
-msgid "GroupsNew|Import"
+msgid "GroupsNew|Import a GitLab group export file"
msgstr ""
msgid "GroupsNew|Import group"
@@ -12680,6 +13053,9 @@ msgid_plural "Hide charts"
msgstr[0] ""
msgstr[1] ""
+msgid "Hide comments on this file"
+msgstr ""
+
msgid "Hide details"
msgstr ""
@@ -12724,6 +13100,15 @@ msgstr ""
msgid "Highest role:"
msgstr ""
+msgid "HighlightBar|Alert events:"
+msgstr ""
+
+msgid "HighlightBar|Alert start time:"
+msgstr ""
+
+msgid "HighlightBar|Original alert:"
+msgstr ""
+
msgid "History"
msgstr "Cronologia"
@@ -12901,6 +13286,9 @@ msgstr ""
msgid "If enabled, access to projects will be validated on an external service using their classification label."
msgstr ""
+msgid "If the number of active users exceeds the user limit, you will be charged for the number of %{users_over_license_link} at your next license reconciliation."
+msgstr ""
+
msgid "If there is no previous license or if the previous license has expired, some GitLab functionality will be blocked until a new, valid license is uploaded."
msgstr ""
@@ -12940,9 +13328,6 @@ msgstr ""
msgid "If your HTTP repository is not publicly accessible, add your credentials."
msgstr ""
-msgid "Iglu registry URL (optional)"
-msgstr ""
-
msgid "Ignore"
msgstr ""
@@ -12979,6 +13364,16 @@ msgstr ""
msgid "Import"
msgstr ""
+msgid "Import %d compatible repository"
+msgid_plural "Import %d compatible repositories"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Import %d repository"
+msgid_plural "Import %d repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Import CSV"
msgstr ""
@@ -12988,15 +13383,9 @@ msgstr ""
msgid "Import all compatible projects"
msgstr ""
-msgid "Import all compatible repositories"
-msgstr ""
-
msgid "Import all projects"
msgstr ""
-msgid "Import all repositories"
-msgstr ""
-
msgid "Import an exported GitLab project"
msgstr ""
@@ -13084,6 +13473,9 @@ msgstr ""
msgid "ImportProjects|Error importing repository %{project_safe_import_url} into %{project_full_path} - %{message}"
msgstr ""
+msgid "ImportProjects|Import repositories"
+msgstr ""
+
msgid "ImportProjects|Importing the project failed"
msgstr ""
@@ -13096,7 +13488,7 @@ msgstr ""
msgid "ImportProjects|Requesting your %{provider} repositories failed"
msgstr ""
-msgid "ImportProjects|Select the projects you want to import"
+msgid "ImportProjects|Select the repositories you want to import"
msgstr ""
msgid "ImportProjects|The remote data could not be imported."
@@ -13132,9 +13524,6 @@ msgstr ""
msgid "In order to enable Service Desk for your instance, you must first set up incoming email."
msgstr ""
-msgid "In order to gather accurate feature usage data, it can take 1 to 2 weeks to see your index."
-msgstr ""
-
msgid "In order to personalize your experience with GitLab%{br_tag}we would like to know a bit more about you."
msgstr ""
@@ -13165,18 +13554,30 @@ msgstr ""
msgid "IncidentManagement|Create incident"
msgstr ""
+msgid "IncidentManagement|Critical - S1"
+msgstr ""
+
msgid "IncidentManagement|Date created"
msgstr ""
msgid "IncidentManagement|Display your incidents in a dedicated view"
msgstr ""
+msgid "IncidentManagement|High - S2"
+msgstr ""
+
msgid "IncidentManagement|Incident"
msgstr ""
msgid "IncidentManagement|Incidents"
msgstr ""
+msgid "IncidentManagement|Low - S4"
+msgstr ""
+
+msgid "IncidentManagement|Medium - S3"
+msgstr ""
+
msgid "IncidentManagement|No incidents to display."
msgstr ""
@@ -13189,6 +13590,9 @@ msgstr ""
msgid "IncidentManagement|Published to status page"
msgstr ""
+msgid "IncidentManagement|Severity"
+msgstr ""
+
msgid "IncidentManagement|There are no closed incidents"
msgstr ""
@@ -13198,6 +13602,9 @@ msgstr ""
msgid "IncidentManagement|Unassigned"
msgstr ""
+msgid "IncidentManagement|Unknown"
+msgstr ""
+
msgid "IncidentManagement|Unpublished"
msgstr ""
@@ -13219,6 +13626,15 @@ msgstr ""
msgid "Incidents"
msgstr ""
+msgid "Incident|Alert details"
+msgstr ""
+
+msgid "Incident|Summary"
+msgstr ""
+
+msgid "Incident|There was an issue loading alert data. Please try again."
+msgstr ""
+
msgid "Include a Terms of Service agreement and Privacy Policy that all users must accept."
msgstr ""
@@ -13279,6 +13695,9 @@ msgstr ""
msgid "Information about additional Pages templates and how to install them can be found in our %{pages_getting_started_guide}."
msgstr ""
+msgid "Inherited"
+msgstr ""
+
msgid "Inherited:"
msgstr ""
@@ -13359,7 +13778,22 @@ msgstr ""
msgid "Instance administrators group already exists"
msgstr ""
-msgid "Instance license"
+msgid "InstanceStatistics|Groups"
+msgstr ""
+
+msgid "InstanceStatistics|Issues"
+msgstr ""
+
+msgid "InstanceStatistics|Merge Requests"
+msgstr ""
+
+msgid "InstanceStatistics|Pipelines"
+msgstr ""
+
+msgid "InstanceStatistics|Projects"
+msgstr ""
+
+msgid "InstanceStatistics|Users"
msgstr ""
msgid "Integration"
@@ -13371,6 +13805,12 @@ msgstr ""
msgid "Integrations"
msgstr ""
+msgid "Integrations|%{integration} settings saved and active."
+msgstr ""
+
+msgid "Integrations|%{integration} settings saved, but not active."
+msgstr ""
+
msgid "Integrations|All details"
msgstr ""
@@ -13380,6 +13820,12 @@ msgstr ""
msgid "Integrations|Comment settings:"
msgstr ""
+msgid "Integrations|Connection failed. Please check your settings."
+msgstr ""
+
+msgid "Integrations|Connection successful."
+msgstr ""
+
msgid "Integrations|Default settings are inherited from the group level."
msgstr ""
@@ -13395,6 +13841,15 @@ msgstr ""
msgid "Integrations|Includes commit title and branch"
msgstr ""
+msgid "Integrations|Projects using custom settings will not be impacted unless the project owner chooses to use instance-level defaults."
+msgstr ""
+
+msgid "Integrations|Save settings?"
+msgstr ""
+
+msgid "Integrations|Saving will update the default settings for all projects that are not using custom settings."
+msgstr ""
+
msgid "Integrations|Standard"
msgstr ""
@@ -13527,6 +13982,9 @@ msgstr ""
msgid "Invitation"
msgstr ""
+msgid "Invitation declined"
+msgstr ""
+
msgid "Invite"
msgstr ""
@@ -13578,6 +14036,42 @@ 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|%{linkStart}Read more%{linkEnd} about role permissions"
+msgstr ""
+
+msgid "InviteMembersModal|Access expiration date (optional)"
+msgstr ""
+
+msgid "InviteMembersModal|Cancel"
+msgstr ""
+
+msgid "InviteMembersModal|Choose a role permission"
+msgstr ""
+
+msgid "InviteMembersModal|GitLab member or Email address"
+msgstr ""
+
+msgid "InviteMembersModal|Invite"
+msgstr ""
+
+msgid "InviteMembersModal|Invite team members"
+msgstr ""
+
+msgid "InviteMembersModal|Search for members to invite"
+msgstr ""
+
+msgid "InviteMembersModal|User not invited. Feature coming soon!"
+msgstr ""
+
+msgid "InviteMembersModal|Users were succesfully added"
+msgstr ""
+
+msgid "InviteMembersModal|You're inviting members to the %{group_name} group"
+msgstr ""
+
+msgid "InviteMembers|Invite team members"
+msgstr ""
+
msgid "Invited"
msgstr ""
@@ -13632,10 +14126,13 @@ msgstr ""
msgid "Issue cannot be found."
msgstr ""
+msgid "Issue created from vulnerability %{vulnerability_link}"
+msgstr ""
+
msgid "Issue events"
msgstr ""
-msgid "Issue first depoloyed to production"
+msgid "Issue first deployed to production"
msgstr ""
msgid "Issue label"
@@ -13713,6 +14210,9 @@ msgstr ""
msgid "IssueTracker|Custom issue tracker"
msgstr ""
+msgid "IssueTracker|EWM work items tracker"
+msgstr ""
+
msgid "IssueTracker|Redmine issue tracker"
msgstr ""
@@ -13779,6 +14279,9 @@ msgstr ""
msgid "It looks like you have some draft commits in this branch."
msgstr ""
+msgid "It may be several days before you see feature usage data."
+msgstr ""
+
msgid "It must have a header row and at least two columns: the first column is the issue title and the second column is the issue description. The separator is automatically detected."
msgstr ""
@@ -14061,15 +14564,15 @@ msgstr ""
msgid "Join Zoom meeting"
msgstr ""
+msgid "Joined %{time_ago}"
+msgstr ""
+
msgid "Jul"
msgstr "Lug"
msgid "July"
msgstr "Luglio"
-msgid "Jump to first unresolved thread"
-msgstr ""
-
msgid "Jump to next unresolved thread"
msgstr ""
@@ -14103,6 +14606,9 @@ msgstr ""
msgid "Keyboard shortcuts"
msgstr ""
+msgid "KeyboardKey|Ctrl+"
+msgstr ""
+
msgid "Keys"
msgstr ""
@@ -14151,6 +14657,9 @@ msgstr ""
msgid "LDAP Synchronization"
msgstr ""
+msgid "LDAP group settings"
+msgstr ""
+
msgid "LDAP settings"
msgstr ""
@@ -14160,6 +14669,9 @@ msgstr ""
msgid "LDAP sync in progress. This could take a few minutes. Refresh the page to see the changes."
msgstr ""
+msgid "LDAP synchronizations"
+msgstr ""
+
msgid "LFS"
msgstr ""
@@ -14240,7 +14752,16 @@ msgid_plural "Last %d days"
msgstr[0] "L'ultimo %d giorno"
msgstr[1] "Gli ultimi %d giorni"
-msgid "Last %{days} days"
+msgid "Last 2 weeks"
+msgstr ""
+
+msgid "Last 30 days"
+msgstr ""
+
+msgid "Last 60 days"
+msgstr ""
+
+msgid "Last 90 days"
msgstr ""
msgid "Last Accessed On"
@@ -14318,6 +14839,9 @@ msgstr ""
msgid "Last used on:"
msgstr ""
+msgid "Last week"
+msgstr ""
+
msgid "LastCommit|authored"
msgstr ""
@@ -14333,6 +14857,9 @@ msgstr ""
msgid "Latest pipeline for the most recent commit on this branch"
msgstr ""
+msgid "Launch a ready-to-code development environment for your project."
+msgstr ""
+
msgid "Lead"
msgstr ""
@@ -14713,6 +15240,9 @@ msgstr ""
msgid "List of all merge commits"
msgstr ""
+msgid "List options"
+msgstr ""
+
msgid "List settings"
msgstr ""
@@ -14725,9 +15255,6 @@ msgstr ""
msgid "List your Bitbucket Server repositories"
msgstr ""
-msgid "Lists"
-msgstr ""
-
msgid "Live preview"
msgstr ""
@@ -14974,6 +15501,12 @@ msgstr ""
msgid "Mark as done"
msgstr ""
+msgid "Mark as draft"
+msgstr ""
+
+msgid "Mark as ready"
+msgstr ""
+
msgid "Mark as resolved"
msgstr ""
@@ -14995,6 +15528,24 @@ msgstr ""
msgid "Markdown is supported"
msgstr ""
+msgid "MarkdownEditor|Add a link (%{modifierKey}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add a link (%{modifier_key}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifierKey}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifier_key}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifierKey}I)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifier_key}I)"
+msgstr ""
+
msgid "Marked For Deletion At - %{deletion_time}"
msgstr ""
@@ -15079,7 +15630,25 @@ msgstr ""
msgid "Max access level"
msgstr ""
-msgid "Max seats used"
+msgid "Max role"
+msgstr ""
+
+msgid "Max size 15 MB"
+msgstr ""
+
+msgid "Maximum Conan package file size in bytes"
+msgstr ""
+
+msgid "Maximum Maven package file size in bytes"
+msgstr ""
+
+msgid "Maximum NPM package file size in bytes"
+msgstr ""
+
+msgid "Maximum NuGet package file size in bytes"
+msgstr ""
+
+msgid "Maximum PyPI package file size in bytes"
msgstr ""
msgid "Maximum Users:"
@@ -15211,6 +15780,18 @@ msgstr ""
msgid "Members with access to %{strong_start}%{group_name}%{strong_end}"
msgstr ""
+msgid "Members|%{time} by %{user}"
+msgstr ""
+
+msgid "Members|Expired"
+msgstr ""
+
+msgid "Members|No expiration set"
+msgstr ""
+
+msgid "Members|in %{time}"
+msgstr ""
+
msgid "Memory Usage"
msgstr ""
@@ -15397,9 +15978,6 @@ msgstr ""
msgid "MergeRequests|Thread will be unresolved"
msgstr ""
-msgid "MergeRequests|Toggle comments for this file"
-msgstr ""
-
msgid "MergeRequests|View file @ %{commitId}"
msgstr ""
@@ -15460,6 +16038,9 @@ msgstr ""
msgid "Merging immediately isn't recommended as it may negatively impact the existing merge train. Read the %{docsLinkStart}documentation%{docsLinkEnd} for more information."
msgstr ""
+msgid "Message"
+msgstr ""
+
msgid "Messages"
msgstr "Messaggi"
@@ -15845,18 +16426,12 @@ msgid_plural "Milestones"
msgstr[0] ""
msgstr[1] ""
-msgid "Milestone does not support burnup charts"
-msgstr ""
-
msgid "Milestone lists not available with your current license"
msgstr ""
msgid "Milestone lists show all issues from the selected milestone."
msgstr ""
-msgid "Milestone must have a start and due date"
-msgstr ""
-
msgid "MilestoneSidebar|Closed:"
msgstr ""
@@ -16223,6 +16798,9 @@ msgstr ""
msgid "Namespace"
msgstr ""
+msgid "Namespace ID:"
+msgstr ""
+
msgid "Namespace is empty"
msgstr ""
@@ -16307,6 +16885,9 @@ msgstr ""
msgid "NetworkPolicies|Allow all outbound traffic from %{selector} to %{ruleSelector} on %{ports}"
msgstr ""
+msgid "NetworkPolicies|Are you sure you want to delete this policy? This action cannot be undone."
+msgstr ""
+
msgid "NetworkPolicies|Choose whether to enforce this policy."
msgstr ""
@@ -16316,12 +16897,21 @@ msgstr ""
msgid "NetworkPolicies|Define this policy's location, conditions and actions."
msgstr ""
+msgid "NetworkPolicies|Delete policy"
+msgstr ""
+
+msgid "NetworkPolicies|Delete policy: %{policy}"
+msgstr ""
+
msgid "NetworkPolicies|Deny all traffic"
msgstr ""
msgid "NetworkPolicies|Description"
msgstr ""
+msgid "NetworkPolicies|Edit policy"
+msgstr ""
+
msgid "NetworkPolicies|Editor mode"
msgstr ""
@@ -16349,6 +16939,9 @@ msgstr ""
msgid "NetworkPolicies|Name"
msgstr ""
+msgid "NetworkPolicies|Namespace"
+msgstr ""
+
msgid "NetworkPolicies|Network Policy"
msgstr ""
@@ -16400,6 +16993,9 @@ msgstr ""
msgid "NetworkPolicies|Rules"
msgstr ""
+msgid "NetworkPolicies|Save changes"
+msgstr ""
+
msgid "NetworkPolicies|Something went wrong, failed to update policy"
msgstr ""
@@ -16412,6 +17008,9 @@ msgstr ""
msgid "NetworkPolicies|Traffic that does not match any rule will be blocked."
msgstr ""
+msgid "NetworkPolicies|Unable to parse policy"
+msgstr ""
+
msgid "NetworkPolicies|YAML editor"
msgstr ""
@@ -16525,6 +17124,9 @@ msgstr ""
msgid "New Snippet"
msgstr ""
+msgid "New Test Case"
+msgstr ""
+
msgid "New User"
msgstr ""
@@ -16624,6 +17226,9 @@ msgstr "Nuovo sottogruppo"
msgid "New tag"
msgstr "Nuovo tag"
+msgid "New test case"
+msgstr ""
+
msgid "New users set to external"
msgstr ""
@@ -16696,7 +17301,7 @@ msgstr ""
msgid "No changes"
msgstr ""
-msgid "No changes between %{ref_start}%{source_branch}%{ref_end} and %{ref_start}%{target_branch}%{ref_end}"
+msgid "No changes between %{sourceBranch} and %{targetBranch}"
msgstr ""
msgid "No child epics match applied filters"
@@ -16711,6 +17316,9 @@ msgstr ""
msgid "No containers available"
msgstr ""
+msgid "No content to show"
+msgstr ""
+
msgid "No contributions"
msgstr ""
@@ -16786,9 +17394,6 @@ msgstr ""
msgid "No license. All rights reserved"
msgstr ""
-msgid "No licenses found."
-msgstr ""
-
msgid "No matches found"
msgstr ""
@@ -16801,6 +17406,9 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No members found"
+msgstr ""
+
msgid "No merge requests found"
msgstr ""
@@ -16822,6 +17430,9 @@ msgstr ""
msgid "No parent group"
msgstr ""
+msgid "No plan"
+msgstr ""
+
msgid "No pods available"
msgstr ""
@@ -16918,6 +17529,12 @@ msgstr "Nessuno"
msgid "Not Implemented"
msgstr ""
+msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+msgstr ""
+
+msgid "Not all browsers support WebAuthn. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even from an unsupported browser."
+msgstr ""
+
msgid "Not all data has been processed yet, the accuracy of the chart for the selected timeframe is limited."
msgstr ""
@@ -17014,6 +17631,9 @@ msgstr ""
msgid "Notification settings saved"
msgstr ""
+msgid "NotificationEvent|Change reviewer merge request"
+msgstr ""
+
msgid "NotificationEvent|Close issue"
msgstr "Chiudi issue"
@@ -17176,10 +17796,7 @@ msgstr ""
msgid "On track"
msgstr ""
-msgid "OnDemandScans|Attached branch"
-msgstr ""
-
-msgid "OnDemandScans|Attached branch is where the scan job runs."
+msgid "OnDemandScans|Could not fetch scanner profiles. Please refresh the page, or try again later."
msgstr ""
msgid "OnDemandScans|Could not fetch site profiles. Please refresh the page, or try again later."
@@ -17188,6 +17805,9 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
+msgid "OnDemandScans|Create a new scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Create a new site profile"
msgstr ""
@@ -17200,6 +17820,9 @@ msgstr ""
msgid "OnDemandScans|New on-demand DAST scan"
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 ""
@@ -17209,16 +17832,10 @@ msgstr ""
msgid "OnDemandScans|On-demand scans run outside the DevOps cycle and find vulnerabilities in your projects. %{learnMoreLinkStart}Learn more%{learnMoreLinkEnd}"
msgstr ""
-msgid "OnDemandScans|Only a passive scan can be performed on demand."
-msgstr ""
-
-msgid "OnDemandScans|Passive"
-msgstr ""
-
msgid "OnDemandScans|Run scan"
msgstr ""
-msgid "OnDemandScans|Scan mode"
+msgid "OnDemandScans|Scanner profile"
msgstr ""
msgid "OnDemandScans|Scanner settings"
@@ -17230,9 +17847,15 @@ msgstr ""
msgid "OnDemandScans|Select one of the existing profiles"
msgstr ""
+msgid "OnDemandScans|Site profile"
+msgstr ""
+
msgid "OnDemandScans|Site profiles"
msgstr ""
+msgid "OnDemandScans|Use existing scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Use existing site profile"
msgstr ""
@@ -17331,9 +17954,6 @@ msgstr ""
msgid "Open Selection"
msgstr ""
-msgid "Open Web IDE"
-msgstr ""
-
msgid "Open comment type dropdown"
msgstr ""
@@ -17439,6 +18059,9 @@ msgstr ""
msgid "Origin"
msgstr ""
+msgid "Orphaned member"
+msgstr ""
+
msgid "Other Labels"
msgstr ""
@@ -17454,6 +18077,9 @@ msgstr ""
msgid "Other visibility settings have been disabled by the administrator."
msgstr ""
+msgid "Our documentation includes an example DevOps Score report."
+msgstr ""
+
msgid "Out-of-compliance with this project's policies and should be removed"
msgstr ""
@@ -17478,6 +18104,9 @@ msgstr "Panoramica"
msgid "Overwrite diverged branches"
msgstr ""
+msgid "Owned by %{image_tag}"
+msgstr ""
+
msgid "Owned by anyone"
msgstr ""
@@ -17499,6 +18128,9 @@ msgstr ""
msgid "Package deleted successfully"
msgstr ""
+msgid "Package file size limits"
+msgstr ""
+
msgid "Package recipe already exists"
msgstr ""
@@ -17514,9 +18146,6 @@ msgstr ""
msgid "Package type must be PyPi"
msgstr ""
-msgid "Package was removed"
-msgstr ""
-
msgid "PackageRegistry|%{name} version %{version} was created %{datetime}"
msgstr ""
@@ -17658,12 +18287,18 @@ msgstr ""
msgid "PackageRegistry|NuGet Command"
msgstr ""
+msgid "PackageRegistry|Package Registry"
+msgstr ""
+
msgid "PackageRegistry|Pip Command"
msgstr ""
msgid "PackageRegistry|Pipeline %{link} triggered %{datetime} by %{author}"
msgstr ""
+msgid "PackageRegistry|Publish and share packages for a variety of common package managers. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "PackageRegistry|Published to the %{project} Package Registry %{datetime}"
msgstr ""
@@ -17763,6 +18398,9 @@ msgstr ""
msgid "Page not found"
msgstr ""
+msgid "Page settings"
+msgstr ""
+
msgid "Page was successfully deleted"
msgstr ""
@@ -17904,7 +18542,7 @@ msgstr ""
msgid "Paste issue link"
msgstr ""
-msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Don't use your private SSH key."
+msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Do not paste your private SSH key, as that can compromise your identity."
msgstr ""
msgid "Patch to apply"
@@ -17931,6 +18569,9 @@ msgstr ""
msgid "Pending"
msgstr ""
+msgid "Pending comments"
+msgstr ""
+
msgid "People without permission will never get a notification and won't be able to comment."
msgstr ""
@@ -18129,6 +18770,9 @@ msgstr ""
msgid "Pipelines|Build with confidence"
msgstr ""
+msgid "Pipelines|By revoking a trigger you will break any processes making use of it. Are you sure?"
+msgstr ""
+
msgid "Pipelines|CI Lint"
msgstr ""
@@ -18141,6 +18785,15 @@ msgstr ""
msgid "Pipelines|Continuous Integration can help catch bugs by running your tests automatically, while Continuous Deployment can help you deliver code to your product environment."
msgstr ""
+msgid "Pipelines|Copy trigger token"
+msgstr ""
+
+msgid "Pipelines|Description"
+msgstr ""
+
+msgid "Pipelines|Edit"
+msgstr ""
+
msgid "Pipelines|Get started with Pipelines"
msgstr ""
@@ -18156,15 +18809,27 @@ msgstr ""
msgid "Pipelines|It is recommended the code is reviewed thoroughly before running this pipeline with the parent project's CI resource."
msgstr ""
+msgid "Pipelines|Last Used"
+msgstr ""
+
msgid "Pipelines|Loading Pipelines"
msgstr ""
msgid "Pipelines|More Information"
msgstr ""
+msgid "Pipelines|No triggers have been created yet. Add one using the form above."
+msgstr ""
+
+msgid "Pipelines|Owner"
+msgstr ""
+
msgid "Pipelines|Project cache successfully reset."
msgstr ""
+msgid "Pipelines|Revoke"
+msgstr ""
+
msgid "Pipelines|Run Pipeline"
msgstr ""
@@ -18189,6 +18854,15 @@ msgstr ""
msgid "Pipelines|This project is not currently set up to run pipelines."
msgstr ""
+msgid "Pipelines|Token"
+msgstr ""
+
+msgid "Pipelines|Trigger user has insufficient permissions to project"
+msgstr ""
+
+msgid "Pipelines|invalid"
+msgstr ""
+
msgid "Pipelines|parent"
msgstr ""
@@ -18447,10 +19121,10 @@ msgstr ""
msgid "Please provide attributes to update"
msgstr ""
-msgid "Please refer to %{docs_url}"
+msgid "Please reach out if you have any questions and we'll be happy to assist."
msgstr ""
-msgid "Please retype the email address."
+msgid "Please refer to %{docs_url}"
msgstr ""
msgid "Please select"
@@ -18480,6 +19154,9 @@ msgstr ""
msgid "Please set a new password before proceeding."
msgstr ""
+msgid "Please share your feedback about %{featureName} %{linkStart}in this issue%{linkEnd} to help us improve the experience."
+msgstr ""
+
msgid "Please solve the reCAPTCHA"
msgstr ""
@@ -18783,6 +19460,9 @@ msgstr ""
msgid "Profiles| You are going to change the username %{currentUsernameBold} to %{newUsernameBold}. Profile and projects will be redirected to the %{newUsername} namespace but this redirect will expire once the %{currentUsername} namespace is registered by another user or group. Please update your Git repository remotes as soon as possible."
msgstr "Profiles| Stai per cambiare il nome utente %{currentUsernameBold} in %{newUsernameBold}. Profilo e progetti verranno reindirizzati allo spazio dei nomi %{newUsername} ma questo reindirizzamento scadrà quando lo spazio dei nomi %{currentUsername} viene registrato da un altro utente o gruppo. Per favore aggiorna i remote repository di Git il prima possibile."
+msgid "Profiles|%{provider} Active"
+msgstr ""
+
msgid "Profiles|@username"
msgstr ""
@@ -18834,7 +19514,7 @@ msgstr ""
msgid "Profiles|Commit email"
msgstr ""
-msgid "Profiles|Connect"
+msgid "Profiles|Connect %{provider}"
msgstr ""
msgid "Profiles|Connected Accounts"
@@ -18858,6 +19538,9 @@ msgstr ""
msgid "Profiles|Disconnect"
msgstr ""
+msgid "Profiles|Disconnect %{provider}"
+msgstr ""
+
msgid "Profiles|Do not show on profile"
msgstr ""
@@ -18882,7 +19565,7 @@ msgstr ""
msgid "Profiles|Full name"
msgstr ""
-msgid "Profiles|Give your individual key a title. This will be publically visible."
+msgid "Profiles|Give your individual key a title."
msgstr ""
msgid "Profiles|Include private contributions on my profile"
@@ -18972,7 +19655,7 @@ msgstr ""
msgid "Profiles|The maximum file size allowed is 200KB."
msgstr ""
-msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it?"
+msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it? It will be publicly visible."
msgstr ""
msgid "Profiles|This email will be displayed on your public profile"
@@ -19047,6 +19730,9 @@ msgstr ""
msgid "Profiles|You don't have access to delete this user."
msgstr "Non hai i permessi per eliminare questo utente."
+msgid "Profiles|You must transfer ownership or delete groups you are an owner of before you can delete your account"
+msgstr ""
+
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr "Devi trasferire la proprietà o eliminare questi gruppi prima che tu possa eliminare l'account."
@@ -19635,6 +20321,9 @@ msgstr ""
msgid "ProjectTemplates|GitLab Cluster Management"
msgstr ""
+msgid "ProjectTemplates|Gitpod/Spring Petclinic"
+msgstr ""
+
msgid "ProjectTemplates|Go Micro"
msgstr ""
@@ -20244,6 +20933,9 @@ msgstr ""
msgid "Publish to status page"
msgstr ""
+msgid "Published"
+msgstr ""
+
msgid "Published on status page"
msgstr ""
@@ -20361,9 +21053,15 @@ msgstr ""
msgid "Quick range"
msgstr ""
+msgid "Quickly and easily edit multiple files in your project."
+msgstr ""
+
msgid "README"
msgstr ""
+msgid "Rails"
+msgstr ""
+
msgid "Rake Tasks Help"
msgstr ""
@@ -20483,10 +21181,13 @@ msgstr ""
msgid "Register Two-Factor Authenticator"
msgstr ""
-msgid "Register U2F device"
+msgid "Register Universal Two-Factor (U2F) Device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register WebAuthn Device"
+msgstr ""
+
+msgid "Register device"
msgstr ""
msgid "Register for GitLab"
@@ -20498,9 +21199,6 @@ msgstr ""
msgid "Register with two-factor app"
msgstr ""
-msgid "Registration"
-msgstr ""
-
msgid "Registration|Checkout"
msgstr ""
@@ -20617,9 +21315,6 @@ msgstr ""
msgid "Release|Something went wrong while saving the release details"
msgstr ""
-msgid "Remediated: needs review"
-msgstr ""
-
msgid "Remediations"
msgstr ""
@@ -20725,6 +21420,9 @@ msgstr ""
msgid "Remove priority"
msgstr ""
+msgid "Remove report"
+msgstr ""
+
msgid "Remove secondary node"
msgstr ""
@@ -20737,6 +21435,12 @@ msgstr ""
msgid "Remove time estimate"
msgstr ""
+msgid "Remove user & report"
+msgstr ""
+
+msgid "Remove user from group"
+msgstr ""
+
msgid "Removed"
msgstr ""
@@ -20818,9 +21522,6 @@ msgstr ""
msgid "Removes time estimate."
msgstr ""
-msgid "Removing license…"
-msgstr ""
-
msgid "Removing this group also removes all child projects, including archived projects, and their resources."
msgstr ""
@@ -20905,6 +21606,9 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
+msgid "Reported by %{reporter}"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -20991,6 +21695,27 @@ msgstr ""
msgid "Repositories"
msgstr ""
+msgid "Repositories Analytics"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download Historic Test Coverage Data"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download historic test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Historic Test Coverage Data is available in raw format (.csv) for further analysis."
+msgstr ""
+
+msgid "RepositoriesAnalytics|Test Code Coverage"
+msgstr ""
+
+msgid "RepositoriesAnalytics|There was an error fetching the projects."
+msgstr ""
+
msgid "Repository"
msgstr ""
@@ -21069,9 +21794,15 @@ msgstr ""
msgid "Request parameter %{param} is missing."
msgstr ""
+msgid "Request review from"
+msgstr ""
+
msgid "Request to link SAML account must be authorized"
msgstr ""
+msgid "Requested"
+msgstr ""
+
msgid "Requested %{time_ago}"
msgstr ""
@@ -21090,6 +21821,9 @@ msgstr ""
msgid "Requests to these domain(s)/address(es) on the local network will be allowed when local requests from hooks and services are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 or 127.0.0.0/28 are supported. Domain wildcards are not supported currently. Use comma, semicolon, or newline to separate multiple entries. The allowlist can hold a maximum of 1000 entries. Domains should use IDNA encoding. Ex: example.com, 192.168.1.1, 127.0.0.0/28, xn--itlab-j1a.com."
msgstr ""
+msgid "Require admin approval for new sign-ups"
+msgstr ""
+
msgid "Require all users in this group to setup Two-factor authentication"
msgstr ""
@@ -21217,9 +21951,6 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
-msgid "Resolved by %{resolvedByName}"
-msgstr ""
-
msgid "Resolves IP addresses once and uses them to submit requests"
msgstr ""
@@ -21339,6 +22070,14 @@ msgstr ""
msgid "ReviewApp|Enable Review App"
msgstr ""
+msgid "Reviewer"
+msgid_plural "%d Reviewers"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Reviewer(s)"
+msgstr ""
+
msgid "Reviewing"
msgstr ""
@@ -21378,6 +22117,9 @@ msgstr ""
msgid "Rook"
msgstr ""
+msgid "Ruby"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -21456,6 +22198,63 @@ msgstr ""
msgid "Runners page."
msgstr ""
+msgid "Runners|Active"
+msgstr ""
+
+msgid "Runners|Architecture"
+msgstr ""
+
+msgid "Runners|Can run untagged jobs"
+msgstr ""
+
+msgid "Runners|Description"
+msgstr ""
+
+msgid "Runners|Group"
+msgstr ""
+
+msgid "Runners|IP Address"
+msgstr ""
+
+msgid "Runners|Last contact"
+msgstr ""
+
+msgid "Runners|Locked to this project"
+msgstr ""
+
+msgid "Runners|Maximum job timeout"
+msgstr ""
+
+msgid "Runners|Name"
+msgstr ""
+
+msgid "Runners|Platform"
+msgstr ""
+
+msgid "Runners|Property Name"
+msgstr ""
+
+msgid "Runners|Protected"
+msgstr ""
+
+msgid "Runners|Revision"
+msgstr ""
+
+msgid "Runners|Shared"
+msgstr ""
+
+msgid "Runners|Specific"
+msgstr ""
+
+msgid "Runners|Tags"
+msgstr ""
+
+msgid "Runners|Value"
+msgstr ""
+
+msgid "Runners|Version"
+msgstr ""
+
msgid "Runners|You have used %{quotaUsed} out of %{quotaLimit} of your shared Runners pipeline minutes."
msgstr ""
@@ -21468,6 +22267,9 @@ msgstr ""
msgid "Runs a number of housekeeping tasks within the current repository, such as compressing file revisions and removing unreachable objects."
msgstr ""
+msgid "SAML"
+msgstr ""
+
msgid "SAML SSO"
msgstr ""
@@ -21519,6 +22321,9 @@ msgstr ""
msgid "Save"
msgstr ""
+msgid "Save %{name} size limits"
+msgstr ""
+
msgid "Save Changes"
msgstr ""
@@ -21549,9 +22354,6 @@ msgstr "Salva pianificazione pipeline"
msgid "Save space and find tags in the Container Registry more easily. Enable the cleanup policy to remove stale tags and keep only the ones you need."
msgstr ""
-msgid "Save template"
-msgstr ""
-
msgid "Save variables"
msgstr ""
@@ -21594,9 +22396,6 @@ msgstr "Pianificazione pipelines"
msgid "Scope"
msgstr ""
-msgid "Scope not supported with disabled 'users_search' feature!"
-msgstr ""
-
msgid "Scoped issue boards"
msgstr ""
@@ -21723,9 +22522,6 @@ msgstr ""
msgid "Search requirements"
msgstr ""
-msgid "Search results…"
-msgstr ""
-
msgid "Search users"
msgstr ""
@@ -21798,6 +22594,11 @@ msgid_plural "SearchResults|commits"
msgstr[0] ""
msgstr[1] ""
+msgid "SearchResults|epic"
+msgid_plural "SearchResults|epics"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "SearchResults|issue"
msgid_plural "SearchResults|issues"
msgstr[0] ""
@@ -21842,10 +22643,10 @@ msgstr ""
msgid "Seat Link is disabled, and cannot be configured through this form."
msgstr ""
-msgid "Seats currently in use"
+msgid "Seats usage data as of %{last_enqueue_time}"
msgstr ""
-msgid "Seats in license"
+msgid "Seats usage data is updated every day at 12:00pm UTC"
msgstr ""
msgid "Secondary"
@@ -21899,6 +22700,9 @@ msgstr ""
msgid "SecurityConfiguration|Available for on-demand DAST"
msgstr ""
+msgid "SecurityConfiguration|By default, all analyzers are applied in order to cover all languages across your project, and only run if the language is detected in the Merge Request."
+msgstr ""
+
msgid "SecurityConfiguration|Configure"
msgstr ""
@@ -21929,16 +22733,19 @@ msgstr ""
msgid "SecurityConfiguration|Manage"
msgstr ""
+msgid "SecurityConfiguration|More information"
+msgstr ""
+
msgid "SecurityConfiguration|Not enabled"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|Security Control"
+msgid "SecurityConfiguration|SAST Configuration"
msgstr ""
-msgid "SecurityConfiguration|See documentation"
+msgid "SecurityConfiguration|Security Control"
msgstr ""
msgid "SecurityConfiguration|Status"
@@ -21950,6 +22757,9 @@ msgstr ""
msgid "SecurityConfiguration|Using custom settings. You won't receive automatic updates on this variable. %{anchorStart}Restore to default%{anchorEnd}"
msgstr ""
+msgid "SecurityConfiguration|View history"
+msgstr ""
+
msgid "SecurityConfiguration|You can quickly enable all security scanning tools by enabling %{linkStart}Auto DevOps%{linkEnd}."
msgstr ""
@@ -22028,9 +22838,6 @@ msgstr ""
msgid "SecurityReports|Learn more about setting up your dashboard"
msgstr ""
-msgid "SecurityReports|Load more vulnerabilities"
-msgstr ""
-
msgid "SecurityReports|Monitor vulnerabilities in your code"
msgstr ""
@@ -22310,7 +23117,7 @@ msgstr ""
msgid "Select status"
msgstr ""
-msgid "Select strategy activation method"
+msgid "Select strategy activation method."
msgstr ""
msgid "Select subscription"
@@ -22325,7 +23132,7 @@ msgstr "Seleziona il ramo che vuoi impostare come predefinito per questo progett
msgid "Select the custom project template source group."
msgstr ""
-msgid "Select timeframe"
+msgid "Select the environment scope for this feature flag."
msgstr ""
msgid "Select timezone"
@@ -22574,6 +23381,9 @@ msgstr ""
msgid "Set iteration"
msgstr ""
+msgid "Set limit to 0 to allow any file size."
+msgstr ""
+
msgid "Set max session time for web terminal."
msgstr ""
@@ -22652,10 +23462,13 @@ msgstr ""
msgid "Set up a %{type} Runner manually"
msgstr ""
+msgid "Set up a hardware device as a second factor to sign in."
+msgstr ""
+
msgid "Set up assertions/attributes/claims (email, first_name, last_name) and NameID according to %{docsLinkStart}the documentation %{icon}%{docsLinkEnd}"
msgstr ""
-msgid "Set up new U2F device"
+msgid "Set up new device"
msgstr ""
msgid "Set up new password"
@@ -22724,6 +23537,9 @@ msgstr ""
msgid "Sets weight to %{weight}."
msgstr ""
+msgid "Setting this to 0 means using the system default timeout value."
+msgstr ""
+
msgid "Settings"
msgstr "Impostazioni"
@@ -22739,6 +23555,15 @@ msgstr ""
msgid "Severity"
msgstr ""
+msgid "SeverityWidget|Severity"
+msgstr ""
+
+msgid "SeverityWidget|Severity: %{severity}"
+msgstr ""
+
+msgid "SeverityWidget|There was an error while updating severity."
+msgstr ""
+
msgid "Shards (%{shards})"
msgstr ""
@@ -22784,6 +23609,9 @@ msgstr ""
msgid "Show all requirements."
msgstr ""
+msgid "Show all test cases."
+msgstr ""
+
msgid "Show archived projects"
msgstr ""
@@ -22796,6 +23624,9 @@ msgstr ""
msgid "Show comments"
msgstr ""
+msgid "Show comments on this file"
+msgstr ""
+
msgid "Show comments only"
msgstr ""
@@ -22841,6 +23672,12 @@ msgstr ""
msgid "Show parent subgroups"
msgstr ""
+msgid "Show the Closed list"
+msgstr ""
+
+msgid "Show the Open list"
+msgstr ""
+
msgid "Show whitespace changes"
msgstr ""
@@ -22884,9 +23721,6 @@ msgstr ""
msgid "Sidebar|Assign health status"
msgstr ""
-msgid "Sidebar|Change weight"
-msgstr ""
-
msgid "Sidebar|Health status"
msgstr ""
@@ -23070,6 +23904,9 @@ msgstr ""
msgid "Snippets|Add another file %{num}/%{total}"
msgstr ""
+msgid "Snippets|Authored %{time_ago} by %{author}"
+msgstr ""
+
msgid "Snippets|Delete file"
msgstr ""
@@ -23097,6 +23934,9 @@ msgstr ""
msgid "Solution"
msgstr ""
+msgid "Some changes are not shown"
+msgstr ""
+
msgid "Some child epics may be hidden due to applied filters"
msgstr ""
@@ -23463,6 +24303,12 @@ msgstr ""
msgid "Source (branch or tag)"
msgstr ""
+msgid "Source Branch"
+msgstr ""
+
+msgid "Source branch: %{source_branch_open}%{source_branch}%{source_branch_close}"
+msgstr ""
+
msgid "Source code"
msgstr "Codice Sorgente"
@@ -23628,9 +24474,6 @@ msgstr ""
msgid "Start and due date"
msgstr ""
-msgid "Start by choosing a group to see how your team is spending time. You can then drill down to the project level."
-msgstr ""
-
msgid "Start by choosing a group to start exploring the merge requests in that group. You can then proceed to filter by projects, labels, milestones and authors."
msgstr ""
@@ -23712,18 +24555,27 @@ msgstr ""
msgid "StaticSiteEditor|3. Assign a person to review and accept the merge request."
msgstr ""
+msgid "StaticSiteEditor|A link to view the merge request will appear once ready."
+msgstr ""
+
msgid "StaticSiteEditor|An error occurred while submitting your changes."
msgstr ""
msgid "StaticSiteEditor|Branch could not be created."
msgstr ""
+msgid "StaticSiteEditor|Copy update"
+msgstr ""
+
msgid "StaticSiteEditor|Could not commit the content changes."
msgstr ""
msgid "StaticSiteEditor|Could not create merge request."
msgstr ""
+msgid "StaticSiteEditor|Creating your merge request"
+msgstr ""
+
msgid "StaticSiteEditor|Incompatible file content"
msgstr ""
@@ -23745,6 +24597,9 @@ msgstr ""
msgid "StaticSiteEditor|View documentation"
msgstr ""
+msgid "StaticSiteEditor|You can set an assignee to get your changes reviewed and deployed once your merge request is created."
+msgstr ""
+
msgid "StaticSiteEditor|Your merge request has been created"
msgstr ""
@@ -23874,15 +24729,15 @@ msgstr ""
msgid "Submit %{humanized_resource_name}"
msgstr ""
-msgid "Submit Changes"
-msgstr ""
-
msgid "Submit a review"
msgstr ""
msgid "Submit as spam"
msgstr ""
+msgid "Submit changes"
+msgstr ""
+
msgid "Submit feedback"
msgstr ""
@@ -24036,6 +24891,9 @@ msgstr ""
msgid "Successfully deleted U2F device."
msgstr ""
+msgid "Successfully deleted WebAuthn device."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -24354,9 +25212,6 @@ msgstr ""
msgid "Template to append to all Service Desk issues"
msgstr ""
-msgid "Template was successfully saved."
-msgstr ""
-
msgid "Templates"
msgstr ""
@@ -24435,10 +25290,28 @@ msgid_plural "Test coverage: %d hits"
msgstr[0] ""
msgstr[1] ""
-msgid "Test failed."
+msgid "Test settings"
msgstr ""
-msgid "Test settings and save changes"
+msgid "TestCases|New Test Case"
+msgstr ""
+
+msgid "TestCases|New test case"
+msgstr ""
+
+msgid "TestCases|Search test cases"
+msgstr ""
+
+msgid "TestCases|Something went wrong while creating a test case."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching count of test cases."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching test cases list."
+msgstr ""
+
+msgid "TestCases|Submit test case"
msgstr ""
msgid "TestHooks|Ensure one of your projects has merge requests."
@@ -24504,6 +25377,9 @@ msgstr ""
msgid "Thank you for signing up for your free trial! You will get additional instructions in your inbox shortly."
msgstr ""
+msgid "Thank you for your business."
+msgstr ""
+
msgid "Thank you for your feedback!"
msgstr ""
@@ -24563,9 +25439,6 @@ msgstr ""
msgid "The URL to use for connecting to Elasticsearch. Use a comma-separated list to support clustering (e.g., \"http://localhost:9200, http://localhost:9201\")."
msgstr ""
-msgid "The Web IDE offers advanced syntax highlighting capabilities and more."
-msgstr ""
-
msgid "The X509 Certificate to use when mutual TLS is required to communicate with the external authorization service. If left blank, the server certificate is still validated when accessing over HTTPS."
msgstr ""
@@ -24676,6 +25549,9 @@ msgstr "La relazione del fork è stata rimossa"
msgid "The form contains the following error:"
msgstr ""
+msgid "The form contains the following warning:"
+msgstr ""
+
msgid "The global settings require you to enable Two-Factor Authentication for your account."
msgstr ""
@@ -24790,9 +25666,6 @@ msgstr "Lo stadio di pianificazione mostra il tempo trascorso dal primo commit a
msgid "The private key to use when a client certificate is provided. This value is encrypted at rest."
msgstr ""
-msgid "The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr "Lo stadio di produzione mostra il tempo totale che trascorre tra la creazione di un issue il suo rilascio (inteso come codice) in produzione. Questo dato sarà disponibile automaticamente nel momento in cui avrai completato l'intero processo ideale del ciclo di produzione"
-
msgid "The project can be accessed by any logged in user."
msgstr "Qualunque utente autenticato può accedere a questo progetto."
@@ -24829,7 +25702,7 @@ msgstr ""
msgid "The remote repository is being updated..."
msgstr ""
-msgid "The repository can be commited to, and issues, comments and other entities can be created."
+msgid "The repository can be committed to, and issues, comments and other entities can be created."
msgstr ""
msgid "The repository for this project does not exist."
@@ -24883,9 +25756,6 @@ msgstr "Lo stadio di test mostra il tempo che ogni Pipeline impiega per essere e
msgid "The time taken by each data entry gathered by that stage."
msgstr "Il tempo aggregato relativo eventi/data entry raccolto in quello stadio."
-msgid "The total stage shows the time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The update action will time out after %{number_of_minutes} minutes. For big repositories, use a clone/push combination."
msgstr ""
@@ -24949,6 +25819,9 @@ msgstr ""
msgid "There are no archived requirements"
msgstr ""
+msgid "There are no archived test cases"
+msgstr ""
+
msgid "There are no changes"
msgstr ""
@@ -24988,6 +25861,9 @@ msgstr ""
msgid "There are no open requirements"
msgstr ""
+msgid "There are no open test cases"
+msgstr ""
+
msgid "There are no packages yet"
msgstr ""
@@ -25000,6 +25876,9 @@ msgstr ""
msgid "There is a limit of %{ci_project_subscriptions_limit} subscriptions from or to a project."
msgstr ""
+msgid "There is already a To-Do for this design."
+msgstr ""
+
msgid "There is already a repository with that name on disk"
msgstr ""
@@ -25018,6 +25897,9 @@ msgstr ""
msgid "There was a problem communicating with your device."
msgstr ""
+msgid "There was a problem fetching branches."
+msgstr ""
+
msgid "There was a problem fetching groups."
msgstr ""
@@ -25246,9 +26128,15 @@ msgstr ""
msgid "This action can lead to data loss. To prevent accidental actions we ask you to confirm your intention."
msgstr ""
+msgid "This action cannot be undone, and will permanently delete the %{key} SSH key"
+msgstr ""
+
msgid "This action cannot be undone. You will lose the project's repository and all content: issues, merge requests, etc."
msgstr ""
+msgid "This action has been performed too many times. Try again later."
+msgstr ""
+
msgid "This action will %{strongOpen}permanently delete%{strongClose} %{codeOpen}%{project}%{codeClose} %{strongOpen}immediately%{strongClose}, including its repositories and all content: issues, merge requests, etc."
msgstr ""
@@ -25276,9 +26164,6 @@ msgstr ""
msgid "This board's scope is reduced"
msgstr ""
-msgid "This branch has changed since you started editing. Would you like to create a new branch?"
-msgstr ""
-
msgid "This chart could not be displayed"
msgstr ""
@@ -25405,15 +26290,9 @@ msgstr ""
msgid "This is a security log of important events involving your account."
msgstr ""
-msgid "This is the author's first Merge Request to this project."
-msgstr ""
-
msgid "This is the highest peak of users on your installation since the license started."
msgstr ""
-msgid "This is the maximum number of users that have existed at the same time since the license started. This is the minimum number of seats you will need to buy when you renew your license."
-msgstr ""
-
msgid "This is the number of currently active users on your installation, and this is the minimum number you need to purchase when you renew your license."
msgstr ""
@@ -25645,6 +26524,15 @@ msgstr ""
msgid "This user has no identities"
msgstr ""
+msgid "This user has previously committed to the %{name} project."
+msgstr ""
+
+msgid "This user has the %{access} role in the %{name} project."
+msgstr ""
+
+msgid "This user is the author of this %{noteable}."
+msgstr ""
+
msgid "This user will be the author of all events in the activity feed that are the result of an update, like new branches being created or new commits being pushed to existing branches."
msgstr ""
@@ -25675,6 +26563,9 @@ msgstr ""
msgid "Threat Monitoring"
msgstr ""
+msgid "ThreatMonitoring|All Environments"
+msgstr ""
+
msgid "ThreatMonitoring|Anomalous Requests"
msgstr ""
@@ -25702,9 +26593,6 @@ msgstr ""
msgid "ThreatMonitoring|Operations Per Second"
msgstr ""
-msgid "ThreatMonitoring|Overview"
-msgstr ""
-
msgid "ThreatMonitoring|Packet Activity"
msgstr ""
@@ -25723,6 +26611,9 @@ msgstr ""
msgid "ThreatMonitoring|Something went wrong, unable to fetch statistics"
msgstr ""
+msgid "ThreatMonitoring|Statistics"
+msgstr ""
+
msgid "ThreatMonitoring|The firewall is not installed or has been disabled. To view this data, ensure the web application firewall is installed and enabled for your cluster."
msgstr ""
@@ -26114,6 +27005,9 @@ msgstr ""
msgid "To update Snippets with multiple files, you must use the `files` parameter"
msgstr ""
+msgid "To use Gitpod you must first enable the feature in the integrations section of your %{user_prefs}."
+msgstr ""
+
msgid "To view all %{scannedResourcesCount} scanned URLs, please download the CSV file"
msgstr ""
@@ -26147,9 +27041,6 @@ msgstr ""
msgid "Toggle Sidebar"
msgstr ""
-msgid "Toggle all threads"
-msgstr ""
-
msgid "Toggle backtrace"
msgstr ""
@@ -26174,9 +27065,6 @@ msgstr ""
msgid "Toggle navigation"
msgstr ""
-msgid "Toggle project"
-msgstr ""
-
msgid "Toggle sidebar"
msgstr ""
@@ -26216,6 +27104,9 @@ msgstr ""
msgid "Too many projects enabled. You will need to manage them via the console or the API."
msgstr ""
+msgid "Too much data"
+msgstr ""
+
msgid "Topics (optional)"
msgstr ""
@@ -26234,6 +27125,9 @@ msgstr ""
msgid "Total cores (CPUs)"
msgstr ""
+msgid "Total days to completion"
+msgstr ""
+
msgid "Total issues"
msgstr ""
@@ -26330,6 +27224,9 @@ msgstr ""
msgid "Trending"
msgstr ""
+msgid "Trials|Create a new group to start your GitLab Gold trial."
+msgstr ""
+
msgid "Trials|Go back to GitLab"
msgstr ""
@@ -26339,6 +27236,15 @@ msgstr ""
msgid "Trials|You can always resume this process by selecting your avatar and choosing 'Start a Gold trial'"
msgstr ""
+msgid "Trials|You can apply your trial to a new group or an existing group."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group or your personal account."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group, an existing group, or your personal account."
+msgstr ""
+
msgid "Trials|You won't get a free trial right now but you can always resume this process by clicking on your avatar and choosing 'Start a free trial'"
msgstr ""
@@ -26408,6 +27314,9 @@ msgstr ""
msgid "Try using a different search term to find the file you are looking for."
msgstr ""
+msgid "Trying to communicate with your device. Plug it in (if needed) and press the button on the device now."
+msgstr ""
+
msgid "Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now."
msgstr ""
@@ -26495,6 +27404,12 @@ msgstr ""
msgid "URL or request ID"
msgstr ""
+msgid "USER %{user} WILL BE REMOVED! Are you sure?"
+msgstr ""
+
+msgid "USER WILL BE BLOCKED! Are you sure?"
+msgstr ""
+
msgid "UTC"
msgstr ""
@@ -26552,9 +27467,6 @@ msgstr ""
msgid "Unable to load the merge request widget. Try reloading the page."
msgstr ""
-msgid "Unable to resolve"
-msgstr ""
-
msgid "Unable to save iteration. Please try again"
msgstr ""
@@ -26603,6 +27515,9 @@ msgstr ""
msgid "Undo ignore"
msgstr ""
+msgid "Unexpected error"
+msgstr ""
+
msgid "Unfortunately, your email message to GitLab could not be processed."
msgstr ""
@@ -26636,6 +27551,9 @@ msgstr ""
msgid "Unknown response text"
msgstr ""
+msgid "Unless otherwise agreed to in writing with GitLab, by clicking \"Upload License\" you agree that your use of GitLab Software is subject to the %{eula_link_start}Terms of Service%{eula_link_end}."
+msgstr ""
+
msgid "Unlimited"
msgstr ""
@@ -27002,9 +27920,6 @@ msgstr ""
msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
msgstr ""
-msgid "Use a hardware device to add the second factor of authentication."
-msgstr ""
-
msgid "Use an one time password authenticator on your mobile device or computer to enable two-factor authentication (2FA)."
msgstr ""
@@ -27278,13 +28193,13 @@ msgstr ""
msgid "Users"
msgstr ""
-msgid "Users in License:"
+msgid "Users in License"
msgstr ""
-msgid "Users or groups set as approvers in the project's or merge request's settings."
+msgid "Users in License:"
msgstr ""
-msgid "Users outside of license"
+msgid "Users or groups set as approvers in the project's or merge request's settings."
msgstr ""
msgid "Users over License:"
@@ -27302,9 +28217,6 @@ msgstr ""
msgid "Users with a Guest role or those who don't belong to a Project or Group will not use a seat from your license."
msgstr ""
-msgid "Users with a Guest role or those who don't belong to any projects or groups don't count towards seats in use."
-msgstr ""
-
msgid "UsersSelect|%{name} + %{length} more"
msgstr ""
@@ -27344,9 +28256,6 @@ msgstr ""
msgid "Validations failed."
msgstr ""
-msgid "Validity"
-msgstr ""
-
msgid "Value"
msgstr ""
@@ -27365,6 +28274,9 @@ msgstr ""
msgid "Value Stream Name"
msgstr ""
+msgid "ValueStreamAnalyticsStage|We don't have enough data to show this stage."
+msgstr ""
+
msgid "ValueStreamAnalytics|%{days}d"
msgstr ""
@@ -27621,6 +28533,9 @@ msgstr ""
msgid "VisualReviewApp|Steps 1 and 2 (and sometimes 3) are performed once by the developer before requesting feedback. Steps 3 (if necessary), 4 is performed by the reviewer each time they perform a review."
msgstr ""
+msgid "Visualization"
+msgstr ""
+
msgid "Vulnerabilities"
msgstr ""
@@ -27648,34 +28563,31 @@ msgstr ""
msgid "VulnerabilityChart|Severity"
msgstr ""
-msgid "VulnerabilityManagement|A true-positive and will fix"
-msgstr ""
-
-msgid "VulnerabilityManagement|Change status"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Confirm"
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|Confirmed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Detected %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|A true-positive and will fix"
msgstr ""
-msgid "VulnerabilityManagement|Dismiss"
+msgid "VulnerabilityManagement|Change status"
msgstr ""
-msgid "VulnerabilityManagement|Dismissed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
msgstr ""
-msgid "VulnerabilityManagement|Resolved"
+msgid "VulnerabilityManagement|Detected"
msgstr ""
-msgid "VulnerabilityManagement|Resolved %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Needs triage"
msgstr ""
msgid "VulnerabilityManagement|Something went wrong while trying to delete the comment. Please try again later."
@@ -27726,6 +28638,9 @@ msgstr ""
msgid "Vulnerability|%{scannerName} (version %{scannerVersion})"
msgstr ""
+msgid "Vulnerability|Activity"
+msgstr ""
+
msgid "Vulnerability|Class"
msgstr ""
@@ -27738,6 +28653,9 @@ msgstr ""
msgid "Vulnerability|Description"
msgstr ""
+msgid "Vulnerability|Detected"
+msgstr ""
+
msgid "Vulnerability|Evidence"
msgstr ""
@@ -27801,6 +28719,9 @@ msgstr ""
msgid "Warning: Displaying this diagram might cause performance issues on this page."
msgstr ""
+msgid "We are currently unable to fetch data for the pipeline header."
+msgstr ""
+
msgid "We are currently unable to fetch data for this graph."
msgstr ""
@@ -27840,6 +28761,12 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
+msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
+msgstr ""
+
+msgid "We would like to inform you that your subscription GitLab Enterprise Edition %{plan_name} is nearing its user limit. You have %{active_user_count} active users, which is almost at the user limit of %{maximum_user_count}."
+msgstr ""
+
msgid "We've found no vulnerabilities"
msgstr ""
@@ -27855,6 +28782,12 @@ msgstr ""
msgid "Web terminal"
msgstr ""
+msgid "WebAuthn Devices (%{length})"
+msgstr ""
+
+msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
+msgstr ""
+
msgid "WebIDE|Merge request"
msgstr ""
@@ -27993,15 +28926,9 @@ msgstr ""
msgid "Welcome to the guided GitLab tour"
msgstr ""
-msgid "Welcome to your Issue Board!"
-msgstr ""
-
msgid "Welcome to your issue board!"
msgstr ""
-msgid "We’ve been making changes to %{featureName} and we’d love your feedback %{linkStart}in this issue%{linkEnd} to help us improve the experience."
-msgstr ""
-
msgid "What are you searching for?"
msgstr ""
@@ -28020,6 +28947,9 @@ msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
msgstr ""
+msgid "When enabled, any user visiting %{host} and creating an account will have to be explicitly approved by the admin before they can login. This setting is effective only if sign-ups are enabled."
+msgstr ""
+
msgid "When enabled, any user visiting %{host} will be able to create an account."
msgstr ""
@@ -28244,6 +29174,9 @@ msgstr ""
msgid "With requirements, you can set criteria to check your products against."
msgstr ""
+msgid "With test cases, you can define conditions for your project to meet in determining quality"
+msgstr ""
+
msgid "Withdraw Access Request"
msgstr "Ritira richiesta d'accesso"
@@ -28259,6 +29192,9 @@ msgstr ""
msgid "Workflow Help"
msgstr ""
+msgid "Would you like to create a new branch?"
+msgstr ""
+
msgid "Write"
msgstr ""
@@ -28280,6 +29216,9 @@ msgstr ""
msgid "Wrong extern UID provided. Make sure Auth0 is configured correctly."
msgstr ""
+msgid "YYYY-MM-DD"
+msgstr ""
+
msgid "Yes"
msgstr ""
@@ -28337,7 +29276,7 @@ msgstr ""
msgid "You are going to remove the fork relationship from %{project_full_name}. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "You are going to transfer %{project_full_name} to another owner. Are you ABSOLUTELY sure?"
+msgid "You are going to transfer %{project_full_name} to another namespace. Are you ABSOLUTELY sure?"
msgstr ""
msgid "You are going to turn off the confidentiality. This means %{strongStart}everyone%{strongEnd} will be able to see and leave a comment on this %{issuableType}."
@@ -28397,9 +29336,6 @@ msgstr ""
msgid "You can always edit this later"
msgstr ""
-msgid "You can apply your Trial to your Personal account or create a New Group."
-msgstr ""
-
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings"
msgstr ""
@@ -28421,12 +29357,18 @@ msgstr ""
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
+msgid "You can find more information about GitLab subscriptions in %{subscriptions_doc_link}."
+msgstr ""
+
msgid "You can generate an access token scoped to this project for each application to use the GitLab API."
msgstr ""
msgid "You can get started by cloning the repository or start adding files to it with one of the following options."
msgstr ""
+msgid "You can group test cases using labels. To learn about the future direction of this feature, visit %{linkStart}Quality Management direction page%{linkEnd}."
+msgstr ""
+
msgid "You can invite a new member to %{project_name} or invite another group."
msgstr ""
@@ -28442,6 +29384,9 @@ msgstr ""
msgid "You can notify the app / group or a project by sending them an email notification"
msgstr ""
+msgid "You can now close this window."
+msgstr ""
+
msgid "You can now export your security dashboard to a CSV report."
msgstr ""
@@ -28490,9 +29435,6 @@ msgstr ""
msgid "You can test your .gitlab-ci.yml in %{linkStart}CI Lint%{linkEnd}."
msgstr ""
-msgid "You can try again using %{begin_link}basic search%{end_link}"
-msgstr ""
-
msgid "You cannot access the raw file. Please wait a minute."
msgstr ""
@@ -28544,6 +29486,9 @@ msgstr ""
msgid "You don't have any U2F devices registered yet."
msgstr ""
+msgid "You don't have any WebAuthn devices registered yet."
+msgstr ""
+
msgid "You don't have any active chat names."
msgstr ""
@@ -28631,6 +29576,9 @@ msgstr ""
msgid "You must accept our Terms of Service and privacy policy in order to register an account"
msgstr ""
+msgid "You must be logged in to search across all of GitLab"
+msgstr ""
+
msgid "You must disassociate %{domain} from all clusters it is attached to before deletion."
msgstr ""
@@ -28670,7 +29618,7 @@ msgstr "Necessiti del permesso."
msgid "You need to be logged in."
msgstr ""
-msgid "You need to register a two-factor authentication app before you can set up a U2F device."
+msgid "You need to register a two-factor authentication app before you can set up a device."
msgstr ""
msgid "You need to set terms to be enforced"
@@ -28688,6 +29636,9 @@ msgstr ""
msgid "You reached %{usage_in_percent} of %{namespace_name}'s storage capacity (%{used_storage} of %{storage_limit})"
msgstr ""
+msgid "You successfully declined the invitation"
+msgstr ""
+
msgid "You tried to fork %{link_to_the_project} but it failed for the following reason:"
msgstr ""
@@ -28853,10 +29804,13 @@ msgstr ""
msgid "Your U2F device did not send a valid JSON response."
msgstr ""
-msgid "Your U2F device needs to be set up. Plug it in (if not already) and click the button on the left."
+msgid "Your U2F device was registered!"
msgstr ""
-msgid "Your U2F device was registered!"
+msgid "Your WebAuthn device did not send a valid JSON response."
+msgstr ""
+
+msgid "Your WebAuthn device was registered!"
msgstr ""
msgid "Your access request to the %{source_type} has been withdrawn."
@@ -28880,6 +29834,9 @@ msgstr ""
msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
msgstr ""
+msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
+msgstr ""
+
msgid "Your changes can be committed to %{branch_name} because a merge request is open."
msgstr ""
@@ -28916,6 +29873,12 @@ msgstr ""
msgid "Your deployment services will be broken, you will need to manually fix the services after renaming."
msgstr ""
+msgid "Your device is not compatible with GitLab. Please try another device"
+msgstr ""
+
+msgid "Your device needs to be set up. Plug it in (if needed) and click the button on the left."
+msgstr ""
+
msgid "Your device was successfully set up! Give it a name and register it with the GitLab server."
msgstr ""
@@ -29029,9 +29992,6 @@ msgstr[1] ""
msgid "access:"
msgstr ""
-msgid "activated"
-msgstr ""
-
msgid "added %{created_at_timeago}"
msgstr ""
@@ -29104,9 +30064,21 @@ msgstr ""
msgid "by %{user}"
msgstr ""
+msgid "cannot be a date in the past"
+msgstr ""
+
msgid "cannot be changed if a personal project has container registry tags."
msgstr ""
+msgid "cannot be changed if shared runners are enabled"
+msgstr ""
+
+msgid "cannot be enabled because parent group does not allow it"
+msgstr ""
+
+msgid "cannot be enabled because parent group has shared Runners disabled"
+msgstr ""
+
msgid "cannot be enabled unless all domains have TLS certificates"
msgstr ""
@@ -29152,7 +30124,7 @@ msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about SAST %{linkEndTag}"
msgstr ""
-msgid "ciReport|%{linkStartTag}Learn more about Secret Scanning %{linkEndTag}"
+msgid "ciReport|%{linkStartTag}Learn more about Secret Detection %{linkEndTag}"
msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about codequality reports %{linkEndTag}"
@@ -29467,9 +30439,6 @@ msgstr ""
msgid "error"
msgstr ""
-msgid "error code:"
-msgstr ""
-
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr ""
@@ -29491,6 +30460,9 @@ msgstr ""
msgid "failed to dismiss associated finding(id=%{finding_id}): %{message}"
msgstr ""
+msgid "failed to revert associated finding(id=%{finding_id}) to detected"
+msgstr ""
+
msgid "file"
msgid_plural "files"
msgstr[0] ""
@@ -30033,6 +31005,9 @@ msgstr ""
msgid "must be a root namespace"
msgstr ""
+msgid "must be a valid IPv4 or IPv6 address"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -30069,6 +31044,9 @@ msgstr ""
msgid "no expiration"
msgstr ""
+msgid "no name set"
+msgstr ""
+
msgid "no one can merge"
msgstr ""
@@ -30247,9 +31225,6 @@ msgstr ""
msgid "security Reports|There was an error creating the merge request"
msgstr ""
-msgid "settings saved, but not activated"
-msgstr ""
-
msgid "severity|Critical"
msgstr ""
@@ -30376,9 +31351,6 @@ msgstr ""
msgid "toggle collapse"
msgstr ""
-msgid "toggle dropdown"
-msgstr ""
-
msgid "triggered"
msgstr ""
@@ -30406,6 +31378,9 @@ msgstr ""
msgid "user avatar"
msgstr ""
+msgid "user preferences"
+msgstr ""
+
msgid "username"
msgstr ""
diff --git a/locale/ja/gitlab.po b/locale/ja/gitlab.po
index 623830d58b6..08307978560 100644
--- a/locale/ja/gitlab.po
+++ b/locale/ja/gitlab.po
@@ -14,7 +14,10 @@ msgstr ""
"X-Crowdin-Language: ja\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 6\n"
-"PO-Revision-Date: 2020-09-04 23:08\n"
+"PO-Revision-Date: 2020-10-02 18:48\n"
+
+msgid " %{project_name}#%{issue_iid} &middot; opened %{issue_created} by %{author}"
+msgstr ""
msgid " %{start} to %{end}"
msgstr " %{start} ã‹ã‚‰ %{end} "
@@ -72,6 +75,14 @@ msgstr "「%{path}ã€ã¯ã€Œ%{ref}ã€ã«å­˜åœ¨ã—ã¾ã›ã‚“ã§ã—ãŸ"
msgid "\"el\" parameter is required for createInstance()"
msgstr ""
+msgid "%d Approval"
+msgid_plural "%d Approvals"
+msgstr[0] "%d 件ã®æ‰¿èª"
+
+msgid "%d Package"
+msgid_plural "%d Packages"
+msgstr[0] "%d 件ã®ãƒ‘ッケージ"
+
msgid "%d Scanned URL"
msgid_plural "%d Scanned URLs"
msgstr[0] ""
@@ -98,7 +109,7 @@ msgstr[0] "%d 件ã®å­ã‚¨ãƒ”ック"
msgid "%d code quality issue"
msgid_plural "%d code quality issues"
-msgstr[0] ""
+msgstr[0] "%d 件ã®ã‚³ãƒ¼ãƒ‰å“質ã®èª²é¡Œ"
msgid "%d comment"
msgid_plural "%d comments"
@@ -106,7 +117,7 @@ msgstr[0] "%d 件ã®ã‚³ãƒ¡ãƒ³ãƒˆ"
msgid "%d comment on this commit"
msgid_plural "%d comments on this commit"
-msgstr[0] ""
+msgstr[0] "ã“ã®ã‚³ãƒŸãƒƒãƒˆã¸ã®%d 件ã®ã‚³ãƒ¡ãƒ³ãƒˆ"
msgid "%d commit"
msgid_plural "%d commits"
@@ -123,6 +134,10 @@ msgstr[0] "%d個ã®ã‚³ãƒŸãƒƒãƒˆ,"
msgid "%d commits"
msgstr "%d個ã®ã‚³ãƒŸãƒƒãƒˆ"
+msgid "%d completed issue"
+msgid_plural "%d completed issues"
+msgstr[0] ""
+
msgid "%d contribution"
msgid_plural "%d contributions"
msgstr[0] "貢献 %d件"
@@ -131,6 +146,10 @@ msgid "%d day"
msgid_plural "%d days"
msgstr[0] "%d æ—¥"
+msgid "%d day until tags are automatically removed"
+msgid_plural "%d days until tags are automatically removed"
+msgstr[0] ""
+
msgid "%d error"
msgid_plural "%d errors"
msgstr[0] "%d 件ã®ã‚¨ãƒ©ãƒ¼"
@@ -153,7 +172,7 @@ msgstr[0] ""
msgid "%d hour"
msgid_plural "%d hours"
-msgstr[0] ""
+msgstr[0] "%d 時間"
msgid "%d inaccessible merge request"
msgid_plural "%d inaccessible merge requests"
@@ -165,7 +184,7 @@ msgstr[0] "%d個ã®èª²é¡Œ"
msgid "%d issue in this group"
msgid_plural "%d issues in this group"
-msgstr[0] ""
+msgstr[0] "ã“ã®ã‚°ãƒ«ãƒ¼ãƒ—ã«%d件ã®èª²é¡Œ"
msgid "%d issue selected"
msgid_plural "%d issues selected"
@@ -173,7 +192,7 @@ msgstr[0] "%d個ã®èª²é¡Œã‚’é¸æŠžæ¸ˆã¿"
msgid "%d issue successfully imported with the label"
msgid_plural "%d issues successfully imported with the label"
-msgstr[0] ""
+msgstr[0] "%d 件ã®èª²é¡Œã‚’ラベル付ãã§ã‚¤ãƒ³ãƒãƒ¼ãƒˆã—ã¾ã—ãŸ"
msgid "%d layer"
msgid_plural "%d layers"
@@ -203,6 +222,14 @@ msgid "%d more comment"
msgid_plural "%d more comments"
msgstr[0] "%d 件以上ã®ã‚³ãƒ¡ãƒ³ãƒˆ"
+msgid "%d open issue"
+msgid_plural "%d open issues"
+msgstr[0] ""
+
+msgid "%d pending comment"
+msgid_plural "%d pending comments"
+msgstr[0] ""
+
msgid "%d personal project will be removed and cannot be restored."
msgid_plural "%d personal projects will be removed and cannot be restored."
msgstr[0] ""
@@ -215,6 +242,10 @@ msgid "%d project"
msgid_plural "%d projects"
msgstr[0] "%d件ã®ãƒ—ロジェクト"
+msgid "%d project selected"
+msgid_plural "%d projects selected"
+msgstr[0] ""
+
msgid "%d request with warnings"
msgid_plural "%d requests with warnings"
msgstr[0] "%d件ã®ãƒªã‚¯ã‚¨ã‚¹ãƒˆã«è­¦å‘Šã‚ã‚Š"
@@ -231,6 +262,10 @@ msgid "%d tag"
msgid_plural "%d tags"
msgstr[0] "%d ã‚¿ã‚°"
+msgid "%d tag per image name"
+msgid_plural "%d tags per image name"
+msgstr[0] ""
+
msgid "%d unassigned issue"
msgid_plural "%d unassigned issues"
msgstr[0] ""
@@ -247,6 +282,10 @@ msgid "%d vulnerability dismissed"
msgid_plural "%d vulnerabilities dismissed"
msgstr[0] ""
+msgid "%d warning found:"
+msgid_plural "%d warnings found:"
+msgstr[0] ""
+
msgid "%s additional commit has been omitted to prevent performance issues."
msgid_plural "%s additional commits have been omitted to prevent performance issues."
msgstr[0] "パフォーマンス低下をé¿ã‘ã‚‹ãŸã‚ %s 個ã®ã‚³ãƒŸãƒƒãƒˆã‚’çœç•¥ã—ã¾ã—ãŸã€‚"
@@ -284,6 +323,9 @@ msgstr ""
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr "%{commit_author_link} ㌠%{commit_timeago} ã«ã‚³ãƒŸãƒƒãƒˆã—ã¾ã—ãŸ"
+msgid "%{completedCount} completed weight"
+msgstr ""
+
msgid "%{completedWeight} of %{totalWeight} weight completed"
msgstr ""
@@ -310,7 +352,7 @@ msgid "%{count} files touched"
msgstr "%{count} ファイルãŒå¤‰æ›´ã•ã‚Œã¾ã—ãŸ"
msgid "%{count} more"
-msgstr "%{count} 以上"
+msgstr "他 %{count} 件"
msgid "%{count} more assignees"
msgstr "%{count} 人以上ã®æ‹…当者"
@@ -329,21 +371,20 @@ msgid "%{count} participant"
msgid_plural "%{count} participants"
msgstr[0] "%{count} 人ã®å‚加者"
-msgid "%{count} pending comment"
-msgid_plural "%{count} pending comments"
-msgstr[0] "ä¿ç•™ä¸­ã®ã‚³ãƒ¡ãƒ³ãƒˆ%{count} 件"
-
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr "%{count} 件ã®é–¢é€£ã—㟠%{pluralized_subject}: %{links}"
-msgid "%{dashboard_path} could not be found."
+msgid "%{count} total weight"
msgstr ""
+msgid "%{dashboard_path} could not be found."
+msgstr "%{dashboard_path} ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“ã§ã—ãŸã€‚"
+
msgid "%{days} days until tags are automatically removed"
msgstr "ã‚¿ã‚°ãŒè‡ªå‹•çš„ã«å‰Šé™¤ã•ã‚Œã‚‹ã¾ã§%{days} æ—¥"
msgid "%{deployLinkStart}Use a template to deploy to ECS%{deployLinkEnd}, or use a docker image to %{commandsLinkStart}run AWS commands in GitLab CI/CD%{commandsLinkEnd}."
-msgstr ""
+msgstr "%{deployLinkStart}テンプレートを使用ã—ã¦ECS%{deployLinkEnd}ã«ãƒ‡ãƒ—ロイã™ã‚‹ã‹ã€ %{commandsLinkStart}ã« docker イメージを使用ã—ã¦GitLab CI/CD%{commandsLinkEnd} ã§AWSコマンドを実行ã—ã¾ã™ã€‚"
msgid "%{description}- Sentry event: %{errorUrl}- First seen: %{firstSeen}- Last seen: %{lastSeen} %{countLabel}: %{count}%{userCountLabel}: %{userCount}"
msgstr "%{description}- Sentry イベント: %{errorUrl}- 最åˆã«æ¤œå‡ºã•ã‚ŒãŸã‚¤ãƒ™ãƒ³ãƒˆ: %{firstSeen}- 最後ã«æ¤œå‡ºã•ã‚ŒãŸã‚¤ãƒ™ãƒ³ãƒˆ: %{lastSeen} %{countLabel}: %{count}%{userCountLabel}: %{userCount}"
@@ -376,7 +417,7 @@ msgid "%{firstLabel} +%{labelCount} more"
msgstr "%{firstLabel} +%{labelCount} ã®è©³ç´°"
msgid "%{firstMilestoneName} + %{numberOfOtherMilestones} more"
-msgstr ""
+msgstr "%{firstMilestoneName} +他 %{numberOfOtherMilestones} 件"
msgid "%{global_id} is not a valid ID for %{expected_type}."
msgstr ""
@@ -385,14 +426,17 @@ msgid "%{group_docs_link_start}Groups%{group_docs_link_end} allow you to manage
msgstr "%{group_docs_link_start}グループ%{group_docs_link_end}を使用ã™ã‚‹ã¨ã€è¤‡æ•°ã®ãƒ—ロジェクトを管ç†ã—ã¦å…±åŒä½œæ¥­ã‚’è¡Œã†ã“ã¨ãŒã§ãã¾ã™ã€‚グループã®ãƒ¡ãƒ³ãƒãƒ¼ã¯ã€æ‰€å±žã™ã‚‹ãƒ—ロジェクトã®ã™ã¹ã¦ã«ã‚¢ã‚¯ã‚»ã‚¹ã§ãã¾ã™ã€‚"
msgid "%{group_name} group members"
-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アカウントを作æˆã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚"
-msgid "%{host} sign-in from new location"
+msgid "%{group_name}&%{epic_iid} &middot; opened %{epic_created} by %{author}"
msgstr ""
+msgid "%{host} sign-in from new location"
+msgstr "æ–°ã—ã„場所%{host} ã‹ã‚‰ã®ãƒ­ã‚°ã‚¤ãƒ³"
+
msgid "%{icon}You are about to add %{usersTag} people to the discussion. They will all receive a notification."
msgstr ""
@@ -402,17 +446,17 @@ msgstr ""
msgid "%{issuableType} will be removed! Are you sure?"
msgstr "%{issuableType}を削除ã—ã¾ã™ï¼ã‚ˆã‚ã—ã„ã§ã™ã‹ï¼Ÿ"
-msgid "%{issuesSize} issues with a limit of %{maxIssueCount}"
+msgid "%{issuesCount} issues with a limit of %{maxIssueCount}"
msgstr ""
msgid "%{issuesSize} with a limit of %{maxIssueCount}"
msgstr ""
msgid "%{labelStart}Class:%{labelEnd} %{class}"
-msgstr ""
+msgstr "%{labelStart}クラス:%{labelEnd} %{class}"
msgid "%{labelStart}Crash Address:%{labelEnd} %{crash_address}"
-msgstr ""
+msgstr "%{labelStart}クラッシュアドレス:%{labelEnd} %{crash_address}"
msgid "%{labelStart}Crash State:%{labelEnd} %{stacktrace_snippet}"
msgstr ""
@@ -435,7 +479,7 @@ msgstr ""
msgid "%{labelStart}Namespace:%{labelEnd} %{namespace}"
msgstr ""
-msgid "%{labelStart}Report Type:%{labelEnd} %{reportType}"
+msgid "%{labelStart}Scan Type:%{labelEnd} %{reportType}"
msgstr ""
msgid "%{labelStart}Scanner:%{labelEnd} %{scanner}"
@@ -466,16 +510,16 @@ msgid "%{level_name} is not allowed since the fork source project has lower visi
msgstr "%{level_name} ã¯è¨±å¯ã•ã‚Œã¾ã›ã‚“。フォークã—ãŸã‚½ãƒ¼ã‚¹ãƒ—ロジェクトã¯ã‚ˆã‚Šå¯è¦–性ãŒä½Žã„ã‹ã‚‰ã§ã™ã€‚"
msgid "%{link_start}Learn more%{link_end} about what information is shared with GitLab Inc."
-msgstr ""
+msgstr "GitLab Inc. ã«ã©ã®ã‚ˆã†ãªæƒ…報を共有ã™ã‚‹ã‹ã«ã¤ã„ã¦ã¯ %{link_start}ã“ã¡ã‚‰%{link_end} ã‚’å‚ç…§ã—ã¦ãã ã•ã„。"
msgid "%{link_start}Read more%{link_end} about role permissions"
msgstr "ロールã®æ¨©é™ã«ã¤ã„ã¦%{link_start}ã‚‚ã£ã¨èª­ã‚€%{link_end}"
msgid "%{link_start}Remove the %{draft_or_wip_snippet} prefix%{link_end} from the title to allow this merge request to be merged when it's ready."
-msgstr ""
+msgstr "タイトルã‹ã‚‰ %{link_start} %{draft_or_wip_snippet} ã®ãƒ—レフィックス %{link_end} を削除ã—ã¦ã€æº–å‚™ãŒã§ã次第マージリクエストをマージã§ãるよã†ã«ã™ã‚‹ã€‚"
msgid "%{link_start}Start the title with %{draft_snippet} or %{wip_snippet}%{link_end} to prevent a merge request that is a work in progress from being merged before it's ready."
-msgstr ""
+msgstr "タイトルã®å…ˆé ­ã« %{link_start} %{draft_snippet} ã¾ãŸã¯ %{wip_snippet}%{link_end} を書ã„ã¦ã€ä½œæ¥­ä¸­ã®ãƒžãƒ¼ã‚¸ãƒªã‚¯ã‚¨ã‚¹ãƒˆãŒæº–å‚™ãŒã§ãã‚‹ã¾ã§ãƒžãƒ¼ã‚¸ã•ã‚Œãªã„よã†ã«ã—ã¾ã™ã€‚"
msgid "%{listToShow}, and %{awardsListLength} more."
msgstr "%{listToShow}ã€ãã—ã¦ã•ã‚‰ã« %{awardsListLength} 個。"
@@ -484,13 +528,13 @@ msgid "%{loadingIcon} Started"
msgstr "%{loadingIcon} 開始"
msgid "%{location} is missing required keys: %{keys}"
-msgstr ""
+msgstr "%{location} ã«å¿…è¦ãªã‚­ãƒ¼ãŒã‚ã‚Šã¾ã›ã‚“: %{keys}"
msgid "%{lock_path} is locked by GitLab User %{lock_user_id}"
msgstr "%{lock_path} ã¯GitLab ユーザー %{lock_user_id} ã«ã‚ˆã£ã¦ãƒ­ãƒƒã‚¯ã•ã‚Œã¦ã„ã¾ã™"
msgid "%{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd} and %{quickActionsDocsLinkStart}quick actions%{quickActionsDocsLinkEnd} are supported"
-msgstr ""
+msgstr "%{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd} 㨠%{quickActionsDocsLinkStart}クイックアクション%{quickActionsDocsLinkEnd} をサãƒãƒ¼ãƒˆã—ã¦ã„ã¾ã™"
msgid "%{mergeLength}/%{usersLength} can merge"
msgstr "%{mergeLength}/%{usersLength} 人ãŒãƒžãƒ¼ã‚¸ã§ãã¾ã™"
@@ -505,13 +549,13 @@ msgid "%{milestone} (expired)"
msgstr ""
msgid "%{milliseconds}ms"
-msgstr ""
+msgstr "%{milliseconds} ミリ秒"
msgid "%{mrText}, this issue will be closed automatically."
msgstr "%{mrText} ã€ã“ã®èª²é¡Œã¯è‡ªå‹•çš„ã«ã‚¯ãƒ­ãƒ¼ã‚ºã—ã¾ã™ã€‚"
msgid "%{name_with_link} has %{percent} or less Shared Runner Pipeline minutes remaining. Once it runs out, no new jobs or pipelines in its projects will run."
-msgstr ""
+msgstr "%{name_with_link} 㯠%{percent}ã¾ãŸã¯ãれ以下ã®å…±æœ‰ãƒ©ãƒ³ãƒŠãƒ¼ãƒ‘イプライン分ãŒæ®‹ã£ã¦ã„ã¾ã™ã€‚ã“ã‚ŒãŒãªããªã‚‹ã¨ã€ãã®ãƒ—ロジェクトã®æ–°ã—ã„ジョブやパイプラインã¯å®Ÿè¡Œã•ã‚Œãªããªã‚Šã¾ã™ã€‚"
msgid "%{name_with_link} has run out of Shared Runner Pipeline minutes so no new jobs or pipelines in its projects will run."
msgstr ""
@@ -554,7 +598,7 @@ msgid "%{openedEpics} open, %{closedEpics} closed"
msgstr "%{openedEpics} オープン, %{closedEpics} 完了"
msgid "%{openedIssues} open, %{closedIssues} closed"
-msgstr ""
+msgstr "%{openedIssues} オープン, %{closedIssues} 完了"
msgid "%{percentage}%% weight completed"
msgstr ""
@@ -569,7 +613,7 @@ msgid "%{placeholder} is not a valid color scheme"
msgstr ""
msgid "%{placeholder} is not a valid theme"
-msgstr ""
+msgstr "%{placeholder} 㯠有効ãªãƒ†ãƒ¼ãƒžã§ã¯ã‚ã‚Šã¾ã›ã‚“。"
msgid "%{primary} (%{secondary})"
msgstr "%{primary} (%{secondary})"
@@ -582,7 +626,7 @@ msgid_plural "%{releases} releases"
msgstr[0] "%{releases} リリース"
msgid "%{remaining_approvals} left"
-msgstr ""
+msgstr "残り%{remaining_approvals}"
msgid "%{reportType} %{status} detected %{criticalStart}%{critical} critical%{criticalEnd} and %{highStart}%{high} high%{highEnd} severity vulnerabilities out of %{total}."
msgstr ""
@@ -625,9 +669,6 @@ msgid "%{securityScanner} result is not available because a pipeline has not bee
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] ""
-msgid "%{service_title} %{message}."
-msgstr ""
-
msgid "%{size} GiB"
msgstr "%{size} GiB"
@@ -676,11 +717,11 @@ msgid "%{strong_start}%{human_size}%{strong_end} Files"
msgstr "%{strong_start}%{human_size}%{strong_end} ファイル"
msgid "%{strong_start}%{human_size}%{strong_end} Storage"
-msgstr ""
+msgstr "%{strong_start}%{human_size}%{strong_end} ストレージ"
msgid "%{strong_start}%{release_count}%{strong_end} Release"
msgid_plural "%{strong_start}%{release_count}%{strong_end} Releases"
-msgstr[0] ""
+msgstr[0] "%{strong_start}%{release_count}%{strong_end} リリース"
msgid "%{strong_start}%{tag_count}%{strong_end} Tag"
msgid_plural "%{strong_start}%{tag_count}%{strong_end} Tags"
@@ -711,6 +752,12 @@ msgstr "%{text} ãŒåˆ©ç”¨ã§ãã¾ã™ã€‚"
msgid "%{timebox_name} should belong either to a project or a group."
msgstr ""
+msgid "%{timebox_type} does not support burnup charts"
+msgstr ""
+
+msgid "%{timebox_type} must have a start and due date"
+msgstr ""
+
msgid "%{title} %{operator} %{threshold}"
msgstr "%{title} %{operator} %{threshold}"
@@ -735,8 +782,8 @@ msgstr ""
msgid "%{total} open issue weight"
msgstr "%{total} 件ã®èª²é¡Œ"
-msgid "%{total} open issues"
-msgstr "%{total} 件ã®èª²é¡Œ"
+msgid "%{total} warnings found: showing first %{warningsDisplayed}"
+msgstr ""
msgid "%{usage_ping_link_start}Learn more%{usage_ping_link_end} about what information is shared with GitLab Inc."
msgstr "GitLab Inc. ã¨ã©ã®ã‚ˆã†ãªæƒ…報を共有ã™ã‚‹ã‹ã«ã¤ã„ã¦ã¯ %{usage_ping_link_start} ã“ã¡ã‚‰%{usage_ping_link_end} ã‚’å‚ç…§ã—ã¦ãã ã•ã„。"
@@ -768,9 +815,6 @@ msgstr ""
msgid "&lt; 1 hour"
msgstr ""
-msgid "&lt;no name set&gt;"
-msgstr ""
-
msgid "&lt;no scopes selected&gt;"
msgstr ""
@@ -801,6 +845,9 @@ msgstr "'%{level}' ã¯æœ‰åŠ¹ãªå¯è¦–レベルã§ã¯ã‚ã‚Šã¾ã›ã‚“"
msgid "'%{name}' Value Stream created"
msgstr ""
+msgid "'%{name}' Value Stream deleted"
+msgstr ""
+
msgid "'%{name}' stage already exists"
msgstr "'%{name}'ステージã¯ã™ã§ã«ã‚ã‚Šã¾ã™"
@@ -859,6 +906,9 @@ msgstr "+ 他 %{moreCount} 件"
msgid "+ %{numberOfHiddenAssignees} more"
msgstr "+ %{numberOfHiddenAssignees} 以上"
+msgid "+ %{numberOfHiddenReviewers} more"
+msgstr ""
+
msgid "+%d more"
msgid_plural "+%d more"
msgstr[0] "%d 以上"
@@ -913,6 +963,10 @@ msgid "1 Day"
msgid_plural "%d Days"
msgstr[0] "%d æ—¥"
+msgid "1 Issue"
+msgid_plural "%d Issues"
+msgstr[0] ""
+
msgid "1 closed issue"
msgid_plural "%{issues} closed issues"
msgstr[0] "%{issues}件ã®ã‚¯ãƒ­ãƒ¼ã‚ºã•ã‚ŒãŸèª²é¡Œ"
@@ -925,6 +979,10 @@ msgid "1 day"
msgid_plural "%d days"
msgstr[0] "%d æ—¥"
+msgid "1 deploy key"
+msgid_plural "%d deploy keys"
+msgstr[0] ""
+
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] "%dグループ"
@@ -1018,6 +1076,9 @@ msgstr "8 時間"
msgid ":%{startLine} to %{endLine}"
msgstr ""
+msgid "A %{incident_docs_start}modified issue%{incident_docs_end} to guide the resolution of incidents."
+msgstr ""
+
msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr "「Runnerã€ã¯ã‚¸ãƒ§ãƒ–を実行ã™ã‚‹ãƒ—ロセスã§ã™ã€‚å¿…è¦ãªæ•°ã® Runner ã‚’ä»»æ„ã«ã‚»ãƒƒãƒˆã‚¢ãƒƒãƒ—ã§ãã¾ã™ã€‚"
@@ -1030,6 +1091,9 @@ msgstr ""
msgid "A GitBook site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr "GitLab ã®ä»£ã‚ã‚Šã« Netlify for CI/CD を使用ã—ã¦ã„ã‚‹ GitBook サイトã§ã™ãŒã€GitLab ã«ã¯ãªã„優れãŸæ©Ÿèƒ½ã‚‚å‚™ãˆã¦ã„ã¾ã™ã€‚"
+msgid "A Gitpod configured Webapplication in Spring and Java"
+msgstr ""
+
msgid "A Hexo site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr "GitLab ã®ä»£ã‚ã‚Šã« Netlify for CI/CD を使用ã—ã¦ã„ã‚‹ Hexo サイトã§ã™ãŒã€GitLab ã«ã¯ãªã„優れãŸæ©Ÿèƒ½ã‚‚å‚™ãˆã¦ã„ã¾ã™ã€‚"
@@ -1058,10 +1122,10 @@ msgid "A deleted user"
msgstr "削除ã•ã‚ŒãŸãƒ¦ãƒ¼ã‚¶ãƒ¼"
msgid "A file has been changed."
-msgstr ""
+msgstr "ファイルãŒå¤‰æ›´ã•ã‚Œã¾ã—ãŸã€‚"
msgid "A file was not found."
-msgstr ""
+msgstr "ファイルãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“ã§ã—ãŸã€‚"
msgid "A file with '%{file_name}' already exists in %{branch} branch"
msgstr "ファイル '%{file_name}' ã¯æ—¢ã« %{branch} ブランãƒã«å­˜åœ¨ã—ã¾ã™"
@@ -1201,9 +1265,15 @@ msgstr "アクセスãŒæ‹’å¦ã•ã‚Œã¾ã—ãŸï¼ã“ã®ãƒªãƒã‚¸ãƒˆãƒªã«ãƒ‡ãƒ—ロ
msgid "Access expiration date"
msgstr "アクセス有効期é™"
+msgid "Access expires"
+msgstr ""
+
msgid "Access forbidden. Check your access level."
msgstr "アクセスã¯ç¦æ­¢ã•ã‚Œã¦ã„ã¾ã™ã€‚アクセスレベルを確èªã—ã¦ãã ã•ã„。"
+msgid "Access granted"
+msgstr ""
+
msgid "Access requests"
msgstr ""
@@ -1213,6 +1283,9 @@ msgstr "'%{classification_label}'ã¸ã®ã‚¢ã‚¯ã‚»ã‚¹ã¯è¨±å¯ã•ã‚Œã¦ã„ã¾ã›ã‚
msgid "Access to Pages websites are controlled based on the user's membership to a given project. By checking this box, users will be required to be logged in to have access to all Pages websites in your instance."
msgstr "Pages ã® Webサイトã¸ã®ã‚¢ã‚¯ã‚»ã‚¹ã¯ã€ãƒ—ロジェクトã§ä¸Žãˆã‚‰ã‚ŒãŸãƒ¦ãƒ¼ã‚¶ãƒ¼ã®ãƒ¡ãƒ³ãƒãƒ¼ã‚·ãƒƒãƒ—ã«æˆ»ã¥ã„ã¦ã‚³ãƒ³ãƒˆãƒ­ãƒ¼ãƒ«ã•ã‚Œã¾ã™ã€‚ã“ã®ãƒœãƒƒã‚¯ã‚¹ã‚’ãƒã‚§ãƒƒã‚¯ã—ãŸå ´åˆã€ãƒ¦ãƒ¼ã‚¶ãƒ¼ã¯ã‚ãªãŸã®ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹å†…ã® Pages Webサイトã«ã‚¢ã‚¯ã‚»ã‚¹ã™ã‚‹ãŸã‚ã«ã€ãƒ­ã‚°ã‚¤ãƒ³ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚ "
+msgid "AccessDropdown|Deploy Keys"
+msgstr ""
+
msgid "AccessDropdown|Groups"
msgstr "グループ"
@@ -1330,12 +1403,6 @@ msgstr ""
msgid "Active Sessions"
msgstr "アクティブ セッション"
-msgid "Active Users:"
-msgstr "アクティブユーザー"
-
-msgid "Active users"
-msgstr ""
-
msgid "Activity"
msgstr "アクティビティー"
@@ -1422,7 +1489,7 @@ msgid "Add a link"
msgstr "リンクを追加"
msgid "Add a new issue"
-msgstr ""
+msgstr "æ–°ã—ã„課題を作æˆã™ã‚‹"
msgid "Add a numbered list"
msgstr "番å·ä»˜ãリストを追加"
@@ -1455,7 +1522,7 @@ msgid "Add approval rule"
msgstr "承èªãƒ«ãƒ¼ãƒ«ã®è¿½åŠ "
msgid "Add approvers"
-msgstr ""
+msgstr "承èªè€…を追加"
msgid "Add bold text"
msgstr "太字ã®ãƒ†ã‚­ã‚¹ãƒˆã‚’追加"
@@ -1502,9 +1569,6 @@ msgstr ""
msgid "Add label(s)"
msgstr "ラベルを追加"
-msgid "Add license"
-msgstr "ライセンスを追加"
-
msgid "Add list"
msgstr "リストを追加"
@@ -1644,7 +1708,7 @@ msgid "Admin Area"
msgstr "管ç†è€…エリア"
msgid "Admin Note"
-msgstr ""
+msgstr "管ç†è€…メモ"
msgid "Admin Notifications"
msgstr ""
@@ -1679,21 +1743,51 @@ msgstr "ブロックã•ã‚ŒãŸãƒ¦ãƒ¼ã‚¶ãƒ¼"
msgid "AdminArea|Bots"
msgstr "ボット"
+msgid "AdminArea|Components"
+msgstr ""
+
msgid "AdminArea|Developer"
msgstr "開発者"
+msgid "AdminArea|Features"
+msgstr ""
+
+msgid "AdminArea|Groups: %{number_of_groups}"
+msgstr ""
+
msgid "AdminArea|Guest"
msgstr "ゲスト"
msgid "AdminArea|Included Free in license"
msgstr "ライセンスã«ç„¡æ–™ã§å«ã¾ã‚Œã¦ã„ã¾ã™"
+msgid "AdminArea|Latest groups"
+msgstr ""
+
+msgid "AdminArea|Latest projects"
+msgstr ""
+
+msgid "AdminArea|Latest users"
+msgstr ""
+
msgid "AdminArea|Maintainer"
msgstr "メンテナー"
+msgid "AdminArea|New group"
+msgstr ""
+
+msgid "AdminArea|New project"
+msgstr ""
+
+msgid "AdminArea|New user"
+msgstr ""
+
msgid "AdminArea|Owner"
msgstr "オーナー"
+msgid "AdminArea|Projects: %{number_of_projects}"
+msgstr ""
+
msgid "AdminArea|Reporter"
msgstr "レãƒãƒ¼ã‚¿ãƒ¼"
@@ -1721,6 +1815,9 @@ msgstr "最高ä½ã®ãƒ¦ãƒ¼ã‚¶ãƒ¼"
msgid "AdminArea|Users without a Group and Project"
msgstr "グループã¨ãƒ—ロジェクトã®ãªã„ユーザー"
+msgid "AdminArea|Users: %{number_of_users}"
+msgstr ""
+
msgid "AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running."
msgstr "å…¨ã¦ã®ã‚¸ãƒ§ãƒ–ã‚’åœæ­¢ã—ã¾ã™ã€‚ã“ã‚Œã«ã‚ˆã‚Šç¾åœ¨å®Ÿè¡Œä¸­ã®ã‚¸ãƒ§ãƒ–ã¯åœæ­¢ã•ã‚Œã¾ã™ã€‚"
@@ -1739,9 +1836,6 @@ msgstr "削除"
msgid "AdminProjects|Delete Project %{projectName}?"
msgstr "プロジェクト %{projectName} を削除ã—ã¾ã™ã‹?"
-msgid "AdminProjects|Delete project"
-msgstr "プロジェクトã®å‰Šé™¤"
-
msgid "AdminSettings|Apply integration settings to all Projects"
msgstr "ã™ã¹ã¦ã®ãƒ—ロジェクトã«çµ±åˆè¨­å®šã‚’é©ç”¨"
@@ -1761,7 +1855,7 @@ msgid "AdminSettings|Go to General Settings"
msgstr "一般設定ã«ç§»å‹•"
msgid "AdminSettings|Integrations configured here will automatically apply to all projects on this instance."
-msgstr ""
+msgstr "ã“ã“ã§è¨­å®šã—ãŸçµ±åˆã¯ã€ã“ã®ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ã®ã™ã¹ã¦ã®ãƒ—ロジェクトã«è‡ªå‹•çš„ã«é©ç”¨ã•ã‚Œã¾ã™ã€‚"
msgid "AdminSettings|Moved to integrations"
msgstr ""
@@ -1782,7 +1876,7 @@ msgid "AdminSettings|Service Templates will soon be deprecated."
msgstr ""
msgid "AdminSettings|Service template allows you to set default values for integrations"
-msgstr ""
+msgstr "Serviceテンプレートã¯ã€çµ±åˆã®ãƒ‡ãƒ•ã‚©ãƒ«ãƒˆå€¤ã‚’設定ã™ã‚‹ãŸã‚ã«ä½¿ç”¨ã—ã¾ã™"
msgid "AdminSettings|Set an instance-wide auto included %{link_start}pipeline configuration%{link_end}. This pipeline configuration will be run after the project's own configuration."
msgstr "インスタンス全体ã«è‡ªå‹•èª­ã¿è¾¼ã¿ã•ã‚Œã‚‹ %{link_start}パイプライン設定%{link_end} を設定ã—ã¾ã™ã€‚ã“ã®ãƒ‘イプライン設定ã¯ãƒ—ロジェクト独自ã®è¨­å®šã®å¾Œã«å®Ÿè¡Œã•ã‚Œã¾ã™ã€‚"
@@ -1979,21 +2073,30 @@ msgstr "ã“ã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ãŒå†ã³ãƒ­ã‚°ã‚¤ãƒ³ã™ã‚‹ã¨ã€ã‚¢ã‚«ã‚¦ãƒ³ãƒˆã¯æœ‰
msgid "AdminUsers|Without projects"
msgstr "プロジェクトãªã—"
-msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
-msgstr "ã‚ãªãŸã¯ãƒ¦ãƒ¼ã‚¶ãƒ¼ %{username} を完全ã«å‰Šé™¤ã—よã†ã¨ã—ã¦ã„ã¾ã™ã€‚ã“ã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ã«ãƒªãƒ³ã‚¯ã—ã¦ã„ã‚‹ã€èª²é¡Œã€ãƒžãƒ¼ã‚¸ãƒªã‚¯ã‚¨ã‚¹ãƒˆã€ãŠã‚ˆã³ã‚°ãƒ«ãƒ¼ãƒ—ã¯ã€ã‚·ã‚¹ãƒ†ãƒ å…¨ä½“ã®ã€ŒGhost ユーザーã€ã«è»¢é€ã•ã‚Œã¾ã™ã€‚データã®æ失をé¿ã‘ã‚‹ãŸã‚ã«ã€å‰Šé™¤ã®ä»£ã‚ã‚Šã«%{strong_end} ユーザーã®ãƒ–ロック機能%{strong_start}を使用ã™ã‚‹ã“ã¨ã‚’検討ã—ã¦ãã ã•ã„。%{strong_end}] ユーザーã®å‰Šé™¤ %{strong_start}を実行ã—ãŸå¾Œã§ã€å…ƒã«æˆ»ã™ã“ã¨ã¯ã§ãã¾ã›ã‚“。ã¾ãŸå¾©å…ƒã‚‚ã§ãã¾ã›ã‚“。"
+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 %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
-msgstr "ã‚ãªãŸã¯ãƒ¦ãƒ¼ã‚¶ãƒ¼ %{username} を完全ã«å‰Šé™¤ã—よã†ã¨ã—ã¦ã„ã¾ã™ã€‚ユーザーã«ãƒªãƒ³ã‚¯ã—ã¦ã„ã‚‹ã€èª²é¡Œã€ãƒžãƒ¼ã‚¸ãƒªã‚¯ã‚¨ã‚¹ãƒˆã€ãŠã‚ˆã³ã‚°ãƒ«ãƒ¼ãƒ—ã¯å‰Šé™¤ã•ã‚Œã¦ã—ã¾ã„ã¾ã™ã€‚データã®æ失をé¿ã‘ã‚‹ãŸã‚ã«ã€å‰Šé™¤ã®ä»£ã‚ã‚Šã«%{strong_start}ユーザーã®ãƒ–ロック機能%{strong_end}を使用ã™ã‚‹ã“ã¨ã‚’検討ã—ã¦ãã ã•ã„。%{strong_start}ユーザーã®å‰Šé™¤%{strong_end}を実施後ã«ã€å…ƒã«æˆ»ã™ã“ã¨ã¯ã§ãã¾ã›ã‚“ã€ã¾ãŸå¾©å…ƒã‚‚ã§ãã¾ã›ã‚“。"
+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 ""
msgid "AdminUsers|You cannot remove your own admin rights."
msgstr ""
+msgid "AdminUsers|You must transfer ownership or delete the groups owned by this user before you can delete their account"
+msgstr ""
+
msgid "Administration"
msgstr "管ç†"
msgid "Advanced"
msgstr "高度ãªè¨­å®š"
+msgid "Advanced Search"
+msgstr ""
+
+msgid "Advanced Search with Elasticsearch"
+msgstr ""
+
msgid "Advanced Settings"
msgstr "高度ãªè¨­å®š"
@@ -2070,6 +2173,9 @@ msgstr ""
msgid "AlertManagement|Edit"
msgstr ""
+msgid "AlertManagement|Environment"
+msgstr ""
+
msgid "AlertManagement|Events"
msgstr "イベント"
@@ -2082,6 +2188,9 @@ msgstr ""
msgid "AlertManagement|Issue"
msgstr ""
+msgid "AlertManagement|Key"
+msgstr ""
+
msgid "AlertManagement|Low"
msgstr ""
@@ -2175,6 +2284,9 @@ msgstr ""
msgid "AlertManagement|Unknown"
msgstr ""
+msgid "AlertManagement|Value"
+msgstr ""
+
msgid "AlertManagement|View alerts in Opsgenie"
msgstr ""
@@ -2284,7 +2396,7 @@ msgid "All"
msgstr "ã™ã¹ã¦"
msgid "All %{replicableType} are being scheduled for %{action}"
-msgstr ""
+msgstr "%{replicableType} ã¯ã™ã¹ã¦ã€%{action}ã«ã‚¹ã‚±ã‚¸ãƒ¥ãƒ¼ãƒ«ã•ã‚Œã¦ã„ã¾ã™"
msgid "All (default)"
msgstr "å…¨ã¦(デフォルト)"
@@ -2334,6 +2446,9 @@ msgstr "ã™ã¹ã¦ã®ãƒ‘スã¯GitLab URL㮠相対パスã§ã™ã€‚ %{relative_url_
msgid "All projects"
msgstr "ã™ã¹ã¦ã®ãƒ—ロジェクト"
+msgid "All projects selected"
+msgstr ""
+
msgid "All security scans are enabled because %{linkStart}Auto DevOps%{linkEnd} is enabled on this project"
msgstr "ã“ã®ãƒ—ロジェクト㧠%{linkStart} Auto DevOps %{linkEnd} ãŒæœ‰åŠ¹ã«ãªã£ã¦ã„ã‚‹ãŸã‚ã€ã™ã¹ã¦ã®ã‚»ã‚­ãƒ¥ãƒªãƒ†ã‚£ã‚¹ã‚­ãƒ£ãƒ³ãŒæœ‰åŠ¹ã«ãªã£ã¦ã„ã¾ã™"
@@ -2421,6 +2536,9 @@ msgstr "Kubernetes クラスターを追加ãŠã‚ˆã³ç®¡ç†ã§ãã¾ã™ã€‚"
msgid "Almost there"
msgstr "ã‚‚ã†å°‘ã—ã§å®Œäº†ã§ã™ï¼"
+msgid "Already blocked"
+msgstr ""
+
msgid "Also called \"Issuer\" or \"Relying party trust identifier\""
msgstr "\"Issuer\" ã¾ãŸã¯ \"Relying party trust identifier\" ã¨ã‚‚呼ã°ã‚Œã¾ã™"
@@ -2475,6 +2593,9 @@ msgstr "GitLab ユーザフィールドãŒç©ºã®å ´åˆã€ã™ã¹ã¦ã®å•é¡Œã¨ã‚
msgid "An error has occurred"
msgstr "エラーãŒç™ºç”Ÿã—ã¾ã—ãŸ"
+msgid "An error occured while making the changes: %{error}"
+msgstr ""
+
msgid "An error occurred adding a draft to the thread."
msgstr "ã“ã®ã‚¹ãƒ¬ãƒƒãƒ‰ã«ä¸‹æ›¸ãを追加ã™ã‚‹éš›ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚"
@@ -2502,12 +2623,6 @@ msgstr "Blobã®ãƒ—レビュー中ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸ"
msgid "An error occurred when toggling the notification subscription"
msgstr "通知購読ã®åˆ‡ã‚Šæ›¿ãˆæ™‚ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸ"
-msgid "An error occurred when trying to resolve a comment. Please try again."
-msgstr "コメントã®è§£æ±ºä¸­ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚ã‚‚ã†ä¸€åº¦ã‚„ã‚Šç›´ã—ã¦ãã ã•ã„。"
-
-msgid "An error occurred when trying to resolve a discussion. Please try again."
-msgstr "検討ã®è§£æ±ºä¸­ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚ã‚‚ã†ä¸€åº¦ã‚„ã‚Šç›´ã—ã¦ãã ã•ã„。"
-
msgid "An error occurred when updating the issue weight"
msgstr "課題ã®ã‚¦ã‚¨ã‚¤ãƒˆæ›´æ–°æ™‚ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸ"
@@ -2523,12 +2638,6 @@ msgstr ""
msgid "An error occurred while checking group path. Please refresh and try again."
msgstr ""
-msgid "An error occurred while committing your changes."
-msgstr "変更ã®ã‚³ãƒŸãƒƒãƒˆä¸­ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚"
-
-msgid "An error occurred while creating the list. Please try again."
-msgstr ""
-
msgid "An error occurred while decoding the file."
msgstr ""
@@ -2601,26 +2710,20 @@ msgstr ""
msgid "An error occurred while fetching the Service Desk address."
msgstr "サービスデスクアドレスã®å–得中ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚"
-msgid "An error occurred while fetching the board issues. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the board lists. Please reload the page."
msgstr ""
msgid "An error occurred while fetching the board lists. Please try again."
msgstr "ボードリストã®å–得中ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚ã‚‚ã†ä¸€åº¦ã‚„ã‚Šç›´ã—ã¦ãã ã•ã„。"
-msgid "An error occurred while fetching the board swimlanes. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the builds."
msgstr "ビルドã®ãƒ•ã‚§ãƒƒãƒä¸­ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚"
msgid "An error occurred while fetching the job log."
msgstr "ã“ã®ã‚¸ãƒ§ãƒ–ã®ãƒ­ã‚°ã‚’フェッãƒã™ã‚‹é–“ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚"
-msgid "An error occurred while fetching the job trace."
-msgstr "ジョブトレースã®å–得中ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚"
+msgid "An error occurred while fetching the job logs."
+msgstr ""
msgid "An error occurred while fetching the job."
msgstr "ã“ã®ã‚¸ãƒ§ãƒ–ã®å–å¾—ã§ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚"
@@ -2766,9 +2869,6 @@ msgstr "LDAP ã®ã‚ªãƒ¼ãƒãƒ¼ãƒ©ã‚¤ãƒ‰çŠ¶æ…‹ã‚’ä¿å­˜ã™ã‚‹ã¨ãã«ã‚¨ãƒ©ãƒ¼ãŒç
msgid "An error occurred while saving assignees"
msgstr "担当者ã®ç™»éŒ²ä¸­ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸ"
-msgid "An error occurred while saving the template. Please check if the template exists."
-msgstr "テンプレートã®ä¿å­˜ä¸­ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚テンプレートãŒå­˜åœ¨ã™ã‚‹ã‹ç¢ºèªã—ã¦ãã ã•ã„。"
-
msgid "An error occurred while searching for milestones"
msgstr ""
@@ -2787,12 +2887,12 @@ msgstr "通知ã®è³¼èª­ã‚’解除中ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚"
msgid "An error occurred while updating approvers"
msgstr "承èªè€…ã®æ›´æ–°ä¸­ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚"
+msgid "An error occurred while updating labels."
+msgstr ""
+
msgid "An error occurred while updating the comment"
msgstr "コメントを更新中ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚"
-msgid "An error occurred while updating the list. Please try again."
-msgstr ""
-
msgid "An error occurred while validating group path"
msgstr "グループパスã®æ¤œè¨¼ä¸­ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸ"
@@ -2844,6 +2944,9 @@ msgstr "Web ターミナルã®åœæ­¢ä¸­ã«äºˆæœŸã—ãªã„エラーãŒç™ºç”Ÿã—ã
msgid "An unknown error occurred while loading this graph."
msgstr ""
+msgid "An unknown error occurred."
+msgstr ""
+
msgid "Analytics"
msgstr "分æž"
@@ -2877,10 +2980,10 @@ msgstr "スパム対策ã®æ¤œè¨¼"
msgid "Any"
msgstr "ä»»æ„ã®"
-msgid "Any Author"
+msgid "Any %{header}"
msgstr ""
-msgid "Any Status"
+msgid "Any Author"
msgstr ""
msgid "Any branch"
@@ -2934,6 +3037,9 @@ msgstr "アプリケーション"
msgid "Application ID"
msgstr "アプリケーション ID"
+msgid "Application limits saved successfully"
+msgstr ""
+
msgid "Application settings saved successfully"
msgstr "アプリケーション設定ã¯æ­£å¸¸ã«ä¿å­˜ã•ã‚Œã¾ã—ãŸ"
@@ -3098,7 +3204,7 @@ msgid "Architecture not found for OS"
msgstr ""
msgid "Archive"
-msgstr ""
+msgstr "アーカイブ"
msgid "Archive jobs"
msgstr "アーカイブジョブ"
@@ -3107,7 +3213,7 @@ msgid "Archive project"
msgstr "プロジェクトをアーカイブ"
msgid "Archived"
-msgstr ""
+msgstr "アーカイブ済ã¿"
msgid "Archived in this version"
msgstr ""
@@ -3139,6 +3245,9 @@ msgstr "ã“ã®ã‚³ãƒ¡ãƒ³ãƒˆã®ç·¨é›†ã‚’キャンセルã—ã¦ã‚‚よã‚ã—ã„ã§ã™
msgid "Are you sure you want to close this blocked issue?"
msgstr "ã“ã®ãƒ–ロックã•ã‚Œã¦ã„る課題をクローズã—ã¦ã‚‚よã‚ã—ã„ã§ã™ã‹ï¼Ÿ"
+msgid "Are you sure you want to delete \"%{name}\" Value Stream?"
+msgstr ""
+
msgid "Are you sure you want to delete %{name}?"
msgstr ""
@@ -3148,6 +3257,9 @@ msgstr "ã“れらã®ã‚¢ãƒ¼ãƒ†ã‚£ãƒ•ã‚¡ã‚¯ãƒˆã‚’削除ã—ã¦ã‚‚よã‚ã—ã„ã§ã™
msgid "Are you sure you want to delete this %{typeOfComment}?"
msgstr "本当ã«ã“ã® %{typeOfComment} を削除ã—ã¾ã™ã‹ï¼Ÿ"
+msgid "Are you sure you want to delete this SSH key?"
+msgstr ""
+
msgid "Are you sure you want to delete this board?"
msgstr "本当ã«ã“ã®ãƒœãƒ¼ãƒ‰ã‚’削除ã—ã¾ã™ã‹?"
@@ -3172,6 +3284,10 @@ msgstr ""
msgid "Are you sure you want to erase this build?"
msgstr "ã“ã®ãƒ“ルドを削除ã—ã¦ã‚‚よã‚ã—ã„ã§ã™ã‹ï¼Ÿ"
+msgid "Are you sure you want to import %d repository?"
+msgid_plural "Are you sure you want to import %d repositories?"
+msgstr[0] ""
+
msgid "Are you sure you want to lose unsaved changes?"
msgstr "変更ãŒä¿å­˜ã•ã‚Œã¦ã„ã¾ã›ã‚“ãŒç ´æ£„ã—ã¦ã‚‚よã‚ã—ã„ã§ã™ã‹ï¼Ÿ"
@@ -3181,15 +3297,15 @@ msgstr "本当ã«èª²é¡Œæƒ…報を削除ã—ã¾ã™ã‹?"
msgid "Are you sure you want to merge immediately?"
msgstr "本当ã«ã™ãã«ãƒžãƒ¼ã‚¸ã—ã¾ã™ã‹ï¼Ÿ"
-msgid "Are you sure you want to permanently delete this license?"
-msgstr "ã“ã®ãƒ©ã‚¤ã‚»ãƒ³ã‚¹ã‚’完全ã«å‰Šé™¤ã—ã¦ã‚‚よã‚ã—ã„ã§ã™ã‹ï¼Ÿ"
-
msgid "Are you sure you want to re-deploy this environment?"
msgstr ""
msgid "Are you sure you want to regenerate the public key? You will have to update the public key on the remote server before mirroring will work again."
msgstr "公開éµã‚’å†ç”Ÿæˆã—ã¦ã‚‚よã‚ã—ã„ã§ã™ã‹? ミラーリングを行ã†å‰ã«ãƒªãƒ¢ãƒ¼ãƒˆã‚µãƒ¼ãƒãƒ¼ã®å…¬é–‹éµã‚’æ›´æ–°ã—ãªã‘ã‚Œã°ãªã‚Šã¾ã›ã‚“。"
+msgid "Are you sure you want to reindex?"
+msgstr ""
+
msgid "Are you sure you want to remove %{group_name}?"
msgstr "ã“ã® %{group_name} を削除ã—ã¦ã‚ˆã‚ã—ã„ã§ã™ã‹ï¼Ÿ"
@@ -3217,6 +3333,9 @@ msgstr ""
msgid "Are you sure you want to revoke this nickname?"
msgstr "ã“ã®ãƒ‹ãƒƒã‚¯ãƒãƒ¼ãƒ ã‚’å–り消ã—ã¦ã‚‚よã‚ã—ã„ã§ã™ã‹ï¼Ÿ"
+msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
+msgstr ""
+
msgid "Are you sure you want to stop this environment?"
msgstr "ã“ã®ç’°å¢ƒã‚’åœæ­¢ã—ã¦ã‚‚よã‚ã—ã„ã§ã™ã‹ï¼Ÿ"
@@ -3238,6 +3357,9 @@ msgstr "本当ã«ã‚ˆã‚ã—ã„ã§ã™ã‹ï¼Ÿã“ã®GPGキーを削除ã—ã¦ã‚‚ã€ã™
msgid "Are you sure? The device will be signed out of GitLab and all remember me tokens revoked."
msgstr ""
+msgid "Are you sure? This will invalidate your registered applications and U2F / WebAuthn devices."
+msgstr ""
+
msgid "Are you sure? This will invalidate your registered applications and U2F devices."
msgstr "本当ã«å®Ÿè¡Œã—ã¾ã™ã‹? ã“ã‚Œã¯ç™»éŒ²ã•ã‚ŒãŸã‚¢ãƒ—リケーション㨠U2Fデãƒã‚¤ã‚¹ã‚’無効ã«ã—ã¾ã™ã€‚"
@@ -3256,9 +3378,6 @@ msgstr "アーティファクトã¯æ­£å¸¸ã«å‰Šé™¤ã•ã‚Œã¾ã—ãŸã€‚"
msgid "Artifacts"
msgstr "アーティファクト"
-msgid "As U2F devices are only supported by a few browsers, we require that you set up a two-factor authentication app before a U2F device. That way you'll always be able to log in - even when you're using an unsupported browser."
-msgstr "U2Fデãƒã‚¤ã‚¹ã¯ã„ãã¤ã‹ã®ãƒ–ラウザã§ã—ã‹ã‚µãƒãƒ¼ãƒˆã•ã‚Œã¦ã„ãªã„ãŸã‚ã€U2Fデãƒã‚¤ã‚¹ã®å‰ã«2è¦ç´ èªè¨¼ã‚¢ãƒ—リを設定ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚ ãã†ã™ã‚Œã°ã€ã‚µãƒãƒ¼ãƒˆã•ã‚Œã¦ã„ãªã„ブラウザを使用ã—ã¦ã„ã‚‹å ´åˆã§ã‚‚ã€å¸¸ã«ãƒ­ã‚°ã‚¤ãƒ³ã§ãるよã†ã«ãªã‚Šã¾ã™ã€‚"
-
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 ""
@@ -3450,6 +3569,9 @@ msgstr ""
msgid "AuditLogs|Target"
msgstr ""
+msgid "AuditLogs|This month"
+msgstr ""
+
msgid "AuditLogs|User Events"
msgstr ""
@@ -3489,6 +3611,9 @@ msgstr "èªè¨¼æ–¹æ³•ã‚’æ›´æ–°ã—ã¾ã—ãŸ"
msgid "Authentication via U2F device failed."
msgstr "U2Fデãƒã‚¤ã‚¹ã«ã‚ˆã‚‹èªè¨¼ã«å¤±æ•—ã—ã¾ã—ãŸã€‚"
+msgid "Authentication via WebAuthn device failed."
+msgstr ""
+
msgid "Author"
msgstr "作æˆè€…"
@@ -3756,15 +3881,6 @@ msgstr "Bamboo ã®ãƒ«ãƒ¼ãƒˆURL 例: https://bamboo.example.com"
msgid "BambooService|You must set up automatic revision labeling and a repository trigger in Bamboo."
msgstr "Bambooã§è‡ªå‹•ãƒªãƒ“ジョンラベリングã¨ãƒªãƒã‚¸ãƒˆãƒªãƒˆãƒªã‚¬ãƒ¼ã‚’設定ã—ãªã‘ã‚Œã°ãªã‚Šã¾ã›ã‚“。"
-msgid "BatchComments|Delete all pending comments"
-msgstr "ä¿ç•™ä¸­ã®ã‚³ãƒ¡ãƒ³ãƒˆã‚’ã™ã¹ã¦å‰Šé™¤"
-
-msgid "BatchComments|Discard review?"
-msgstr "レビューを破棄ã—ã¾ã™ã‹ï¼Ÿ"
-
-msgid "BatchComments|You're about to discard your review which will delete all of your pending comments. The deleted comments %{strong_start}cannot%{strong_end} be restored."
-msgstr "ã‚ãªãŸã¯ãƒ¬ãƒ“ューを破棄ã—よã†ã¨ã—ã¦ã„ã¾ã™ã€‚ペンディング中ã®ã‚³ãƒ¡ãƒ³ãƒˆã¯ã™ã¹ã¦ç ´æ£„ã•ã‚Œã¾ã™ã€‚破棄ã•ã‚ŒãŸã‚³ãƒ¡ãƒ³ãƒˆã¯%{strong_start}復元ã§ãã¾ã›ã‚“%{strong_end}。"
-
msgid "Be careful. Changing the project's namespace can have unintended side effects."
msgstr "ã”注æ„ãã ã•ã„。プロジェクトã®åå‰ç©ºé–“を変更ã™ã‚‹ã¨ã€æ„図ã—ãªã„副作用ãŒç™ºç”Ÿã™ã‚‹ã“ã¨ãŒã‚ã‚Šã¾ã™ã€‚"
@@ -3786,6 +3902,9 @@ msgstr "以下ã«å…¬é–‹ã•ã‚Œã¦ã„る全グループを表示ã—ã¾ã™ã€‚"
msgid "Bi-weekly code coverage"
msgstr ""
+msgid "Billable Users:"
+msgstr ""
+
msgid "Billing"
msgstr "請求"
@@ -3795,8 +3914,8 @@ msgstr "%{group_name} ã®ç¾åœ¨ã®ãƒ—ラン㯠%{plan_name} ã§ã™ã€‚"
msgid "BillingPlans|@%{user_name} you are currently using the %{plan_name} plan."
msgstr "@%{user_name} ã‚ãªãŸã®ç¾åœ¨ã®ãƒ—ランã¯%{plan_name} ã§ã™ã€‚"
-msgid "BillingPlans|Congratulations, your new trial is activated"
-msgstr "ãŠã‚ã§ã¨ã†ã”ã–ã„ã¾ã™ã€æ–°ã—ã„試用版ãŒæœ‰åŠ¹ã«ãªã‚Šã¾ã—ãŸ"
+msgid "BillingPlans|Congratulations, your free trial is activated."
+msgstr ""
msgid "BillingPlans|If you would like to downgrade your plan please contact %{support_link_start}Customer Support%{support_link_end}."
msgstr "プランをダウングレードを希望ã™ã‚‹å ´åˆã€ %{support_link_start} カスタマーサãƒãƒ¼ãƒˆ%{support_link_end} ã¾ã§ã”連絡ãã ã•ã„。"
@@ -3858,6 +3977,9 @@ msgstr "Bitbucket インãƒãƒ¼ãƒˆ"
msgid "Blame"
msgstr ""
+msgid "Block user"
+msgstr ""
+
msgid "Blocked"
msgstr "ブロック中"
@@ -3873,31 +3995,37 @@ msgstr "ブロック"
msgid "Blog"
msgstr "ブログ"
-msgid "Board name"
-msgstr "ボードå"
-
msgid "Board scope"
msgstr "ボードスコープ"
msgid "Board scope affects which issues are displayed for anyone who visits this board"
msgstr "ボードã®ç¯„囲ã¯ã€ã“ã®ãƒœãƒ¼ãƒ‰ã«ã‚¢ã‚¯ã‚»ã‚¹ã—ãŸä»»æ„ã®äººã«è¡¨ç¤ºã•ã‚Œã‚‹ã€èª²é¡Œã«å½±éŸ¿ã—ã¾ã™"
-msgid "BoardBlankState|Add default lists"
-msgstr "デフォルトリストを追加"
+msgid "Boards"
+msgstr "ボード"
+
+msgid "Boards and Board Lists"
+msgstr ""
-msgid "BoardBlankState|Add the following default lists to your Issue Board with one click:"
-msgstr "1クリックã§èª²é¡Œãƒœãƒ¼ãƒ‰ã«ä»¥ä¸‹ã®ãƒ‡ãƒ•ã‚©ãƒ«ãƒˆãƒªã‚¹ãƒˆã‚’追加ã—ã¾ã™ã€‚"
+msgid "Boards|An error occurred while creating the issue. Please try again."
+msgstr ""
-msgid "BoardBlankState|Nevermind, I'll use my own"
-msgstr "æ°—ã«ã—ãªã„ã€è‡ªåˆ†ã®ã‚‚ã®ã‚’使用ã—ã¾ã™"
+msgid "Boards|An error occurred while creating the list. Please try again."
+msgstr ""
-msgid "BoardBlankState|Starting out with the default set of lists will get you right on the way to making the most of your board."
-msgstr "デフォルトã®ãƒªã‚¹ãƒˆã‚»ãƒƒãƒˆã‹ã‚‰å§‹ã‚ã‚‹ã¨ã€ãƒœãƒ¼ãƒ‰ã‚’最大é™ã«æ´»ç”¨ã™ã‚‹ãŸã‚ã®æ­£ã—ã„æ–¹ã§åˆ©ç”¨ã§ãã¾ã™ã€‚"
+msgid "Boards|An error occurred while fetching issues. Please reload the page."
+msgstr ""
-msgid "Boards"
-msgstr "ボード"
+msgid "Boards|An error occurred while fetching the board issues. Please reload the page."
+msgstr ""
-msgid "Boards and Board Lists"
+msgid "Boards|An error occurred while fetching the board swimlanes. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while moving the issue. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while updating the list. Please try again."
msgstr ""
msgid "Boards|Collapse"
@@ -3924,8 +4052,8 @@ msgstr "%{branchName} ブランãƒã¯ã“ã®ãƒ—ロジェクトã®ãƒªãƒã‚¸ãƒˆãƒªã
msgid "Branch %{branch_name} was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr ""
-msgid "Branch has changed"
-msgstr "ブランãƒãŒå¤‰æ›´ã•ã‚Œã¾ã—ãŸ"
+msgid "Branch changed"
+msgstr ""
msgid "Branch is already taken"
msgstr "ブランãƒã¯æ—¢ã«ä½¿ç”¨ã•ã‚Œã¦ã„ã¾ã™"
@@ -4230,6 +4358,9 @@ msgstr "クローズ"
msgid "CLOSED (MOVED)"
msgstr "完了(移動済ã¿)"
+msgid "CODEOWNERS rule violation"
+msgstr ""
+
msgid "CONTRIBUTING"
msgstr "CONTRIBUTING"
@@ -4260,9 +4391,6 @@ msgstr ""
msgid "Can't create snippet: %{err}"
msgstr ""
-msgid "Can't edit as source branch was deleted"
-msgstr ""
-
msgid "Can't fetch content for the blob: %{err}"
msgstr ""
@@ -4275,9 +4403,6 @@ msgstr "ZiteReader 変数ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“"
msgid "Can't load mermaid module: %{err}"
msgstr ""
-msgid "Can't remove group members without group managed account"
-msgstr "グループ管ç†ã‚¢ã‚«ã‚¦ãƒ³ãƒˆãŒãªã„ã¨ã‚°ãƒ«ãƒ¼ãƒ—メンãƒãƒ¼ã¯å‰Šé™¤ã§ãã¾ã›ã‚“"
-
msgid "Can't scan the code?"
msgstr "コードをスキャンã§ãã¾ã™ã‹ï¼Ÿ"
@@ -4320,6 +4445,9 @@ msgstr "ä¸æ­£åˆ©ç”¨ãƒ¬ãƒãƒ¼ãƒˆã¯ä½œæˆã§ãã¾ã›ã‚“。ã“ã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ã¯
msgid "Cannot create the abuse report. This user has been blocked."
msgstr "ä¸æ­£åˆ©ç”¨ãƒ¬ãƒãƒ¼ãƒˆã‚’作æˆã§ãã¾ã›ã‚“。ã“ã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ã¯ãƒ–ロックã•ã‚Œã¦ã„ã¾ã™ã€‚"
+msgid "Cannot enable shared runners because parent group does not allow it"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr "複数ã®Jiraインãƒãƒ¼ãƒˆã‚’åŒæ™‚ã«å®Ÿè¡Œã§ãã¾ã›ã‚“"
@@ -4425,6 +4553,15 @@ msgstr "パスワードを変更ã—ã¦ãã ã•ã„"
msgid "Change your password or recover your current one"
msgstr "パスワードを変更ã™ã‚‹ã‹ã€ç¾åœ¨ã®ãƒ‘スワードを入力ã—ã¦ãã ã•ã„"
+msgid "ChangeReviewer|Reviewer changed from %{old} to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Reviewer changed to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Unassigned"
+msgstr ""
+
msgid "ChangeTypeActionLabel|Pick into branch"
msgstr "ピック先ブランãƒ:"
@@ -4464,6 +4601,9 @@ msgstr "変更ã¯æŠ‘制ã•ã‚Œã¾ã—ãŸã€‚クリックã—ã¦è¡¨ç¤º"
msgid "Changes the title to \"%{title_param}\"."
msgstr "タイトルを \"%{title_param}\" ã«å¤‰æ›´ã—ã¾ã™ã€‚"
+msgid "Changes were successfully made."
+msgstr ""
+
msgid "Changes won't take place until the index is %{link_start}recreated%{link_end}."
msgstr "インデックス㌠%{link_start} å†ç”Ÿæˆã•ã‚Œã‚‹ %{link_end}ã¾ã§å¤‰æ›´ã¯è¡Œã‚ã‚Œã¾ã›ã‚“。"
@@ -4579,7 +4719,7 @@ msgid "Checkout|%{startDate} - %{endDate}"
msgstr "%{startDate} ã‹ã‚‰ %{endDate} ã¾ã§"
msgid "Checkout|(x%{numberOfUsers})"
-msgstr ""
+msgstr "(x%{numberOfUsers})"
msgid "Checkout|Billing address"
msgstr "請求先ä½æ‰€"
@@ -4663,16 +4803,16 @@ msgid "Checkout|Please select a state"
msgstr ""
msgid "Checkout|Select"
-msgstr ""
+msgstr "é¸æŠž"
msgid "Checkout|State"
-msgstr ""
+msgstr "都é“府県ã¾ãŸã¯å·ž"
msgid "Checkout|Street address"
msgstr ""
msgid "Checkout|Submitting the credit card form failed with code %{errorCode}: %{errorMessage}"
-msgstr ""
+msgstr "クレジットカードã®ãƒ•ã‚©ãƒ¼ãƒ ã®ã‚³ãƒ¼ãƒ‰ %{errorCode} ã®é€ä¿¡ã«å¤±æ•—ã—ã¾ã—ãŸã€‚: %{errorMessage}"
msgid "Checkout|Subscription details"
msgstr "サブスクリプションã®è©³ç´°"
@@ -4869,6 +5009,9 @@ msgstr "マスク"
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove variable"
+msgstr ""
+
msgid "CiVariables|Remove variable row"
msgstr "環境変数を削除"
@@ -4947,9 +5090,6 @@ msgstr "ãƒãƒ£ãƒ¼ãƒˆãƒ•ã‚£ãƒ«ã‚¿ãƒ¼ã‚’解除"
msgid "Clear due date"
msgstr ""
-msgid "Clear input"
-msgstr "入力をクリア"
-
msgid "Clear recent searches"
msgstr "最近検索をクリアー"
@@ -4998,6 +5138,9 @@ msgstr "クライアントèªè¨¼ã‚­ãƒ¼"
msgid "Client authentication key password"
msgstr "クライアントèªè¨¼ã‚­ãƒ¼ã®ãƒ‘スワード"
+msgid "Client request timeout"
+msgstr ""
+
msgid "Clients"
msgstr "クライアント"
@@ -5082,6 +5225,27 @@ msgstr ""
msgid "Cluster type must be specificed for Stages::ClusterEndpointInserter"
msgstr ""
+msgid "ClusterAgents|Configuration"
+msgstr ""
+
+msgid "ClusterAgents|Connect your cluster with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate Kubernetes with a GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Name"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Agent also requires %{linkStart}enabling the Agent Server%{linkEnd}"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Kubernetes Agent allows an Infrastructure as Code, GitOps approach to integrating Kubernetes clusters with GitLab. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "ClusterAgent|This feature is only available for premium plans"
msgstr ""
@@ -5151,11 +5315,11 @@ msgstr "ã™ã¹ã¦ã®ãƒ‡ãƒ¼ã‚¿ã‚’削除ã—ã€å¾©å…ƒã§ãã¾ã›ã‚“。"
msgid "ClusterIntegration|All installed applications and related resources"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster."
-msgstr "ã“ã®ã‚¯ãƒ©ã‚¹ã‚¿ãƒ¼ã®åå‰ç©ºé–“ã¨ã‚µãƒ¼ãƒ“スアカウントã®ç®¡ç†ã‚’GitLabã«è¨±å¯ã™ã‚‹ã€‚"
+msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{linkStart}More information%{linkEnd}"
+msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{startLink}More information%{endLink}"
-msgstr "GitLab ãŒã“ã®ã‚¯ãƒ©ã‚¹ã‚¿ãƒ¼ã®åå‰ç©ºé–“ã¨ã‚µãƒ¼ãƒ“スアカウントを管ç†ã§ãるよã†ã«ã—ã¾ã™ã€‚ %{startLink}詳細ã¯ã“ã¡ã‚‰%{endLink}"
+msgid "ClusterIntegration|Allow GitLab to manage namespaces and service accounts for this cluster."
+msgstr ""
msgid "ClusterIntegration|Alternatively, "
msgstr ""
@@ -5175,6 +5339,9 @@ msgstr "プロジェクトã®å–得中ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸ:%{error}
msgid "ClusterIntegration|An error occurred while trying to fetch zone machine types: %{error}"
msgstr "ゾーンã®ãƒžã‚·ãƒ³ã‚¿ã‚¤ãƒ—ã®å–得中ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸ:%{error}"
+msgid "ClusterIntegration|An unknown error occurred while attempting to connect to Kubernetes."
+msgstr ""
+
msgid "ClusterIntegration|Any project namespaces"
msgstr ""
@@ -5190,6 +5357,9 @@ msgstr "AWSã§èªè¨¼ã™ã‚‹"
msgid "ClusterIntegration|Authenticate with Amazon Web Services"
msgstr "Amazon Web Servicesã§èªè¨¼ã™ã‚‹"
+msgid "ClusterIntegration|Authentication Error"
+msgstr ""
+
msgid "ClusterIntegration|Base domain"
msgstr "ベースドメイン"
@@ -5208,14 +5378,23 @@ msgstr ""
msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
msgstr "èªè¨¼å±€ãƒãƒ³ãƒ‰ãƒ« (PEMå½¢å¼)"
-msgid "ClusterIntegration|Choose the %{startLink}security group %{externalLinkIcon} %{endLink} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
-msgstr "%{startLink}セキュリティグループ%{externalLinkIcon}%{endLink}ã‚’é¸æŠžã—ã¦ã€ãƒ¯ãƒ¼ã‚«ãƒ¼ãƒŽãƒ¼ãƒ‰ã‚µãƒ–ãƒãƒƒãƒˆã§ä½œæˆã•ã‚ŒãŸEKS管ç†ã®Elastic Network Interfacesã«é©ç”¨ã—ã¾ã™ã€‚"
+msgid "ClusterIntegration|Check your CA certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Check your cluster status"
+msgstr ""
+
+msgid "ClusterIntegration|Check your token"
+msgstr ""
+
+msgid "ClusterIntegration|Choose the %{linkStart}security group %{linkEnd} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
+msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}subnets %{externalLinkIcon} %{endLink} in your VPC where your worker nodes will run."
-msgstr "ワーカーノードãŒå®Ÿè¡Œã•ã‚Œã‚‹VPCã§%{startLink} サブãƒãƒƒãƒˆ%{externalLinkIcon} %{endLink}ã‚’é¸æŠžã—ã¾ã™ã€‚"
+msgid "ClusterIntegration|Choose the %{linkStart}subnets %{linkEnd} in your VPC where your worker nodes will run."
+msgstr ""
-msgid "ClusterIntegration|Choose the worker node %{startLink}instance type %{externalLinkIcon} %{endLink}."
-msgstr "ワーカーノード%{startLink}インスタンスタイプ%{externalLinkIcon} %{endLink}ã‚’é¸æŠžã—ã¾ã™ã€‚"
+msgid "ClusterIntegration|Choose the worker node %{linkStart}instance type%{linkEnd}."
+msgstr ""
msgid "ClusterIntegration|Choose which applications to install on your Kubernetes cluster."
msgstr ""
@@ -5226,10 +5405,7 @@ msgstr "ã“ã®ã‚¯ãƒ©ã‚¹ã‚¿ã‚’使用ã™ã‚‹ç’°å¢ƒã‚’é¸æŠžã—ã¦ãã ã•ã„。"
msgid "ClusterIntegration|Clear cluster cache"
msgstr "クラスターã®ã‚­ãƒ£ãƒƒã‚·ãƒ¥ã‚’削除"
-msgid "ClusterIntegration|Clear the local cache of namespace and service accounts. This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
-msgstr "åå‰ç©ºé–“ãŠã‚ˆã³ã‚µãƒ¼ãƒ“スアカウントã®ãƒ­ãƒ¼ã‚«ãƒ«ã‚­ãƒ£ãƒƒã‚·ãƒ¥ã‚’クリアã—ã¾ã™ã€‚ã“ã‚Œã¯ã‚¤ãƒ³ãƒ†ã‚°ãƒ¬ãƒ¼ã‚·ãƒ§ãƒ³ãŒåŒæœŸã•ã‚Œã¦ã„ãªã„å ´åˆã«å¿…è¦ã§ã™ã€‚キャッシュã¯ã€ãƒãƒ¼ãƒ ã‚¹ãƒšãƒ¼ã‚¹ãŠã‚ˆã³ã‚µãƒ¼ãƒ“スアカウントを必è¦ã¨ã™ã‚‹æ¬¡å›žã®CIジョブ中ã«å†ä½œæˆã•ã‚Œã¾ã™ã€‚"
-
-msgid "ClusterIntegration|Cluster being created"
+msgid "ClusterIntegration|Clear the local cache of namespace and service accounts."
msgstr ""
msgid "ClusterIntegration|Cluster management project (alpha)"
@@ -5241,15 +5417,21 @@ msgstr "クラスターåãŒå¿…è¦ã§ã™ã€‚"
msgid "ClusterIntegration|Cluster_applications artifact too big. Maximum allowable size: %{human_size}"
msgstr "クラスターアプリケーションã®ã‚¢ãƒ¼ãƒ†ã‚£ãƒ•ã‚¡ã‚¯ãƒˆãŒå¤§ãã™ãŽã¾ã™ã€‚最大許容サイズ: %{human_size}"
-msgid "ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters."
-msgstr "クラスタã¯ã€ç’°å¢ƒã‚¹ã‚³ãƒ¼ãƒ—ãŒä¸€è‡´ã™ã‚‹æœ€ã‚‚è¿‘ã„先祖をé¸æŠžã™ã‚‹ã“ã¨ã«ã‚ˆã£ã¦åˆ©ç”¨ã•ã‚Œã¾ã™ã€‚ ãŸã¨ãˆã°ã€ãƒ—ロジェクトクラスタã¯ã‚°ãƒ«ãƒ¼ãƒ—クラスタを上書ãã—ã¾ã™ã€‚"
-
msgid "ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters. %{linkStart}More information%{linkEnd}"
msgstr ""
+msgid "ClusterIntegration|Clusters connected with a certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Connect cluster with certificate"
+msgstr ""
+
msgid "ClusterIntegration|Connect existing cluster"
msgstr ""
+msgid "ClusterIntegration|Connection Error"
+msgstr ""
+
msgid "ClusterIntegration|Copy API URL"
msgstr "API URLをコピー"
@@ -5325,6 +5507,12 @@ msgstr ""
msgid "ClusterIntegration|Deletes all GitLab resources attached to this cluster during removal"
msgstr "削除中ã«ã“ã®ã‚¯ãƒ©ã‚¹ã‚¿ãƒ¼ã«ã‚¢ã‚¿ãƒƒãƒã•ã‚ŒãŸã™ã¹ã¦ã®GitLabリソースを削除ã—ã¾ã™"
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared."
+msgstr ""
+
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared. %{linkStart}More information%{linkEnd}"
+msgstr ""
+
msgid "ClusterIntegration|Did you know?"
msgstr "ã”存知ã§ã™ã‹ï¼Ÿ"
@@ -5394,6 +5582,9 @@ msgstr ""
msgid "ClusterIntegration|Fluentd is an open source data collector, which lets you unify the data collection and consumption for a better use and understanding of data. It requires at least one of the following logs to be successfully installed."
msgstr ""
+msgid "ClusterIntegration|GitLab Agent managed clusters"
+msgstr ""
+
msgid "ClusterIntegration|GitLab Container Network Policies"
msgstr ""
@@ -5406,6 +5597,12 @@ msgstr "GitLab Runner"
msgid "ClusterIntegration|GitLab Runner connects to the repository and executes CI/CD jobs, pushing results back and deploying applications to production."
msgstr "GitLab Runner ã¯ã“ã®ãƒªãƒã‚¸ãƒˆãƒªã«æŽ¥ç¶šã—ã€CI / CD ジョブを実行ã—ã€çµæžœã‚’プッシュãƒãƒƒã‚¯ã—ã€ã‚¢ãƒ—リケーションを本番環境ã«ãƒ‡ãƒ—ロイã—ã¾ã™ã€‚"
+msgid "ClusterIntegration|GitLab failed to authenticate."
+msgstr ""
+
+msgid "ClusterIntegration|GitLab failed to connect to the cluster."
+msgstr ""
+
msgid "ClusterIntegration|GitLab-managed cluster"
msgstr "GitLabマãƒãƒ¼ã‚¸ãƒ‰ã‚¯ãƒ©ã‚¹ã‚¿ãƒ¼"
@@ -5427,6 +5624,9 @@ msgstr "Google Kubernetes Engine プロジェクト"
msgid "ClusterIntegration|Group cluster"
msgstr "グループクラスター"
+msgid "ClusterIntegration|HTTP Error"
+msgstr ""
+
msgid "ClusterIntegration|Helm Tiller"
msgstr "Helm Tiller"
@@ -5460,8 +5660,11 @@ msgstr "インスタンスクラスター"
msgid "ClusterIntegration|Instance type"
msgstr "インスタンスタイプ"
-msgid "ClusterIntegration|Integrate Kubernetes cluster automation"
-msgstr "Kubernetes クラスターを自動統åˆ"
+msgid "ClusterIntegration|Integrate Kubernetes with a cluster certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Integrate with a cluster certificate"
+msgstr ""
msgid "ClusterIntegration|Issuer Email"
msgstr "発行者メール"
@@ -5496,9 +5699,6 @@ msgstr "Knativeドメインåを正常ã«æ›´æ–°ã—ã¾ã—ãŸã€‚"
msgid "ClusterIntegration|Knative extends Kubernetes to provide a set of middleware components that are essential to build modern, source-centric, and container-based applications that can run anywhere: on premises, in the cloud, or even in a third-party data center."
msgstr "Knativeã¯Kubernetesã‚’æ‹¡å¼µã—ã¦ã€ã‚ªãƒ³ãƒ—レミスã€ã‚¯ãƒ©ã‚¦ãƒ‰ã€ã•ã‚‰ã«ã¯ã‚µãƒ¼ãƒ‰ãƒ‘ーティã®ãƒ‡ãƒ¼ã‚¿ã‚»ãƒ³ã‚¿ãƒ¼ãªã©ã€ã©ã“ã§ã‚‚実行å¯èƒ½ãªæœ€æ–°ã®ã‚½ãƒ¼ã‚¹ä¸­å¿ƒã®ã‚³ãƒ³ãƒ†ãƒŠãƒ™ãƒ¼ã‚¹ã®ã‚¢ãƒ—リケーションを構築ã™ã‚‹ãŸã‚ã«ä¸å¯æ¬ ãªãƒŸãƒ‰ãƒ«ã‚¦ã‚§ã‚¢ã‚³ãƒ³ãƒãƒ¼ãƒãƒ³ãƒˆã®ã‚»ãƒƒãƒˆã‚’æä¾›ã—ã¾ã™ã€‚"
-msgid "ClusterIntegration|Kubernetes cluster"
-msgstr "Kubernetes クラスター"
-
msgid "ClusterIntegration|Kubernetes cluster is being created..."
msgstr "Kubernetesクラスターを作æˆã—ã¦ã„ã¾ã™..."
@@ -5511,9 +5711,6 @@ msgstr "Kubernetes クラスターãŒæ­£å¸¸ã«ä½œæˆã•ã‚Œã¾ã—ãŸã€‚"
msgid "ClusterIntegration|Kubernetes clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr "Kubernetes クラスター㯠Review Apps ã®ä½¿ç”¨ã€ã‚¢ãƒ—リケーションã®ãƒ‡ãƒ—ロイã€ãƒ‘イプラインã®å®Ÿè¡Œã‚„より簡å˜ãªå‡¦ç†ã‚’è¡Œã†è¨±å¯ã‚’求ã‚ã¦ã„ã¾ã™ã€‚"
-msgid "ClusterIntegration|Kubernetes clusters can be used to deploy applications and to provide Review Apps for this project"
-msgstr "Kubernetes クラスターã¯ã€ã“ã®ãƒ—ロジェクトã«ã‚¢ãƒ—リケーションã®ãƒ‡ãƒ—ロイや Review Apps ã®ç’°å¢ƒã‚’æä¾›ã™ã‚‹ã®ã«ä½¿ç”¨ã§ãã¾ã™ã€‚"
-
msgid "ClusterIntegration|Kubernetes version"
msgstr "Kubernetesãƒãƒ¼ã‚¸ãƒ§ãƒ³"
@@ -5526,8 +5723,8 @@ msgstr "%{help_link_start_machine_type}マシンタイプ%{help_link_end}ã¨%{he
msgid "ClusterIntegration|Learn more about %{help_link_start}zones%{help_link_end}."
msgstr "%{help_link_start}ゾーン%{help_link_end}ã®è©³ç´°ã€‚"
-msgid "ClusterIntegration|Learn more about %{startLink}Regions %{externalLinkIcon}%{endLink}."
-msgstr "詳細ã«ã¤ã„ã¦ã¯%{startLink} リージョン%{externalLinkIcon}%{endLink}ã‚’å‚ç…§ã—ã¦ãã ã•ã„。"
+msgid "ClusterIntegration|Learn more about %{linkStart}Regions%{linkEnd}."
+msgstr ""
msgid "ClusterIntegration|Learn more about Kubernetes"
msgstr "Kubernetes ã®è©³ç´°"
@@ -5571,12 +5768,18 @@ msgstr ""
msgid "ClusterIntegration|Machine type"
msgstr "マシンタイプ"
+msgid "ClusterIntegration|Make sure your API endpoint is correct"
+msgstr ""
+
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create Kubernetes clusters"
msgstr "Kubernetes クラスター を作æˆã™ã‚‹ã«ã¯ã€ã‚¢ã‚«ã‚¦ãƒ³ãƒˆã® %{link_to_requirements} を確èªã—ã¦ãã ã•ã„"
msgid "ClusterIntegration|Manage your Kubernetes cluster by visiting %{provider_link}"
msgstr "%{provider_link} ã«ã‚¢ã‚¯ã‚»ã‚¹ã—㦠Kubernetes クラスターを管ç†"
+msgid "ClusterIntegration|Namespace per environment"
+msgstr ""
+
msgid "ClusterIntegration|No IAM Roles found"
msgstr "IAM ロールãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“"
@@ -5622,6 +5825,9 @@ msgstr "サブãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“"
msgid "ClusterIntegration|No zones matched your search"
msgstr "検索æ¡ä»¶ã«ä¸€è‡´ã™ã‚‹ã‚¾ãƒ¼ãƒ³ã¯ã‚ã‚Šã¾ã›ã‚“"
+msgid "ClusterIntegration|Node calculations use the Kubernetes Metrics API. Make sure your cluster has metrics installed"
+msgstr ""
+
msgid "ClusterIntegration|Number of nodes"
msgstr "ノード数"
@@ -5664,6 +5870,9 @@ msgstr "プロビジョニングロールARN"
msgid "ClusterIntegration|RBAC-enabled cluster"
msgstr "RBAC 有効クラスター"
+msgid "ClusterIntegration|Read our %{linkStart}help page%{linkEnd} on Kubernetes cluster integration."
+msgstr ""
+
msgid "ClusterIntegration|Read our %{link_start}help page%{link_end} on Kubernetes cluster integration."
msgstr "çµ±åˆKubernetesクラスターã«ã¤ã„ã¦ã¯ã€%{link_start}ヘルプページ%{link_end}ã‚’ã”覧ãã ã•ã„。"
@@ -5766,8 +5975,8 @@ msgstr "VPC ã‚’é¸æŠžã—ã¦ã‚»ã‚­ãƒ¥ãƒªãƒ†ã‚£ã‚°ãƒ«ãƒ¼ãƒ—ã‚’é¸æŠž"
msgid "ClusterIntegration|Select a VPC to choose a subnet"
msgstr "VPC ã‚’é¸æŠžã—ã¦ã‚µãƒ–ãƒãƒƒãƒˆã‚’é¸æŠž"
-msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
-msgstr "EKSクラスターリソースã«ä½¿ç”¨ã™ã‚‹VPCã‚’é¸æŠžã—ã¾ã™ã€‚ æ–°ã—ã„VPCを使用ã™ã‚‹ã«ã¯ã€ã¾ãš%{startLink} Amazon Web Services%{externalLinkIcon}%{endLink}ã§ä½œæˆã—ã¾ã™ã€‚"
+msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{linkStart}Amazon Web Services %{linkEnd}."
+msgstr ""
msgid "ClusterIntegration|Select a network to choose a subnetwork"
msgstr "ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ã‚’é¸æŠžã—ã¦ã‚µãƒ–ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ã‚’é¸æŠž"
@@ -5799,8 +6008,8 @@ msgstr "プロジェクトã¨ã‚¾ãƒ¼ãƒ³ã‚’é¸æŠžã—ã¦ãƒžã‚·ãƒ³ã‚¿ã‚¤ãƒ—ã‚’é¸æŠž
msgid "ClusterIntegration|Select project to choose zone"
msgstr "プロジェクトをé¸æŠžã—ã¦ã‚¾ãƒ¼ãƒ³ã‚’é¸æŠž"
-msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
-msgstr "EC2ノードã®ä½œæˆã«ä½¿ç”¨ã•ã‚Œã‚‹ã‚­ãƒ¼ãƒšã‚¢åã‚’é¸æŠžã—ã¾ã™ã€‚ æ–°ã—ã„キーペアåを使用ã™ã‚‹ã«ã¯ã€ã¾ãš%{startLink} Amazon Web Services%{externalLinkIcon}%{endLink}ã§ã‚­ãƒ¼ãƒšã‚¢ã‚’作æˆã—ã¾ã™ã€‚"
+msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
+msgstr ""
msgid "ClusterIntegration|Select zone"
msgstr "ゾーンをé¸æŠž"
@@ -5889,9 +6098,18 @@ msgstr ""
msgid "ClusterIntegration|There was a problem authenticating with your cluster. Please ensure your CA Certificate and Token are valid."
msgstr "クラスターã¨ã®èªè¨¼ã«å•é¡ŒãŒã‚ã‚Šã¾ã—ãŸã€‚ CA証明書ã¨ãƒˆãƒ¼ã‚¯ãƒ³ãŒæœ‰åŠ¹ã§ã‚ã‚‹ã“ã¨ã‚’確èªã—ã¦ãã ã•ã„。"
+msgid "ClusterIntegration|There was an HTTP error when connecting to your cluster."
+msgstr ""
+
msgid "ClusterIntegration|This account must have permissions to create a Kubernetes cluster in the %{link_to_container_project} specified below"
msgstr "ã“ã®ã‚¢ã‚«ã‚¦ãƒ³ãƒˆã¯ %{link_to_container_project} 㧠Kubernetes クラスターを作æˆã™ã‚‹ã®ã«ä»¥ä¸‹ã®æ¨©é™ãŒå¿…è¦ã§ã™"
+msgid "ClusterIntegration|This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
+msgstr ""
+
+msgid "ClusterIntegration|This is necessary to clear existing environment-namespace associations from clusters previously managed by GitLab."
+msgstr ""
+
msgid "ClusterIntegration|This option will allow you to install applications on RBAC clusters."
msgstr "ã“ã®ã‚ªãƒ—ションを使用ã™ã‚‹ã¨ã€ã‚ãªãŸã¯ã‚¢ãƒ—リケーションを RBAC クラスター上ã«ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã§ãã¾ã™ã€‚"
@@ -5916,9 +6134,21 @@ msgstr "インテグレーションを削除ã™ã‚‹ã«ã¯ã€ %{clusterName} ã‚’å…
msgid "ClusterIntegration|To use a new project, first create one on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}."
msgstr ""
+msgid "ClusterIntegration|Troubleshooting tips:"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Authenticate"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Connect"
+msgstr ""
+
msgid "ClusterIntegration|Uninstall %{appTitle}"
msgstr "%{appTitle} をアンインストール"
+msgid "ClusterIntegration|Unknown Error"
+msgstr ""
+
msgid "ClusterIntegration|Update %{appTitle}"
msgstr ""
@@ -5979,7 +6209,7 @@ msgstr "アカウント㫠%{link_to_kubernetes_engine} ãŒå¿…è¦ã§ã™ã€‚"
msgid "ClusterIntegration|Your cluster API is unreachable. Please ensure your API URL is correct."
msgstr "クラスターAPIã«åˆ°é”ã§ãã¾ã›ã‚“。API URLãŒæ­£ã—ã„ã“ã¨ã‚’確èªã—ã¦ãã ã•ã„。"
-msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Zone"
@@ -5989,7 +6219,7 @@ msgid "ClusterIntegration|access to Google Kubernetes Engine"
msgstr "Google Kubernetes Engineã«ã‚¢ã‚¯ã‚»ã‚¹"
msgid "ClusterIntegration|can be used instead of a custom domain. "
-msgstr ""
+msgstr "をカスタムドメインã®ä»£ã‚ã‚Šã«ä½¿ç”¨ã§ãã¾ã™ã€‚ "
msgid "ClusterIntegration|installed via %{linkStart}Cloud Run%{linkEnd}"
msgstr ""
@@ -6099,6 +6329,9 @@ msgstr ""
msgid "Collapse"
msgstr "折りãŸãŸã‚€"
+msgid "Collapse all threads"
+msgstr ""
+
msgid "Collapse approvers"
msgstr "承èªè€…ã‚’éžè¡¨ç¤ºã«ã™ã‚‹"
@@ -6247,8 +6480,8 @@ msgstr "コミット担当者: "
msgid "Commit…"
msgstr "コミット"
-msgid "Company"
-msgstr "会社"
+msgid "Community forum"
+msgstr ""
msgid "Company name"
msgstr "会社å"
@@ -6256,6 +6489,9 @@ msgstr "会社å"
msgid "Compare"
msgstr "比較"
+msgid "Compare %{oldCommitId}...%{newCommitId}"
+msgstr ""
+
msgid "Compare Git revisions"
msgstr "Git リビジョンを比較"
@@ -6271,6 +6507,9 @@ msgstr "最後ã®ã‚³ãƒŸãƒƒãƒˆã¨å¤‰æ›´ã‚’比較"
msgid "Compare changes with the merge request target branch"
msgstr "マージリクエストã®ã‚¿ãƒ¼ã‚²ãƒƒãƒˆãƒ–ランãƒã¨ã®å¤‰æ›´ã‚’比較ã™ã‚‹"
+msgid "Compare submodule commit revisions"
+msgstr ""
+
msgid "Compare with previous version"
msgstr "以å‰ã®ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã¨æ¯”較"
@@ -6392,7 +6631,7 @@ msgid "Configure limits on the number of inbound alerts able to be sent to a pro
msgstr "プロジェクトã«é€ä¿¡ã§ãるインãƒã‚¦ãƒ³ãƒ‰ã‚¢ãƒ©ãƒ¼ãƒˆã®æ•°ã«åˆ¶é™ã‚’設定ã—ã¾ã™ã€‚"
msgid "Configure paths to be protected by Rack Attack."
-msgstr ""
+msgstr "Rack 攻撃を防御ã™ã‚‹ãƒ‘スを設定ã—ã¾ã™ã€‚"
msgid "Configure repository mirroring."
msgstr "リãƒã‚¸ãƒˆãƒªã®ãƒŸãƒ©ãƒ¼ãƒªãƒ³ã‚°ã‚’設定ã—ã¾ã™ã€‚"
@@ -6406,6 +6645,9 @@ msgstr "%{link} ã®çµ±åˆã‚’設定ã—ã¾ã™ 。"
msgid "Configure the way a user creates a new account."
msgstr "ユーザーãŒæ–°ã—ã„アカウントを作æˆã™ã‚‹æ–¹æ³•ã‚’設定ã—ã¾ã™ã€‚"
+msgid "Configure which lists are shown for anyone who visits this board"
+msgstr ""
+
msgid "Confirm"
msgstr "確èª"
@@ -6449,7 +6691,7 @@ msgid "Connect your external repositories, and CI/CD pipelines will run for new
msgstr "外部リãƒã‚¸ãƒˆãƒªã«æŽ¥ç¶šã—ã¦ã€æ–°ã—ã„コミットãŒã‚ã‚‹ã¨CI/CDパイプラインを実行ã—ã¾ã™ã€‚CI/CDã®æ©Ÿèƒ½ãŒæœ‰åŠ¹ã§ã‚ã‚‹ã¨ãã®ã¿ã€GitLabプロジェクトã¯ä½œæˆã•ã‚Œã¾ã™ã€‚"
msgid "Connected"
-msgstr ""
+msgstr "接続済"
msgid "Connecting"
msgstr "接続中"
@@ -6485,7 +6727,7 @@ msgid "Container Scanning"
msgstr "コンテナã®ã‚¹ã‚­ãƒ£ãƒ³"
msgid "Container does not exist"
-msgstr ""
+msgstr "コンテナãŒã‚ã‚Šã¾ã›ã‚“"
msgid "Container registry images"
msgstr "コンテナレジストリã®ã‚¤ãƒ¡ãƒ¼ã‚¸"
@@ -6497,7 +6739,7 @@ msgid "Container repositories"
msgstr ""
msgid "Container repositories sync capacity"
-msgstr ""
+msgstr "コンテナリãƒã‚¸ãƒˆãƒªã®åŒæœŸå®¹é‡"
msgid "Container repository"
msgstr ""
@@ -6595,7 +6837,7 @@ msgid "ContainerRegistry|Invalid tag: missing manifest digest"
msgstr ""
msgid "ContainerRegistry|Login"
-msgstr ""
+msgstr "ログイン"
msgid "ContainerRegistry|Manifest digest: %{digest}"
msgstr ""
@@ -6626,10 +6868,13 @@ msgid_plural "ContainerRegistry|Remove tags"
msgstr[0] "ã‚¿ã‚°ã®å‰Šé™¤"
msgid "ContainerRegistry|Set cleanup policy"
+msgstr "クリーンアップãƒãƒªã‚·ãƒ¼ã®è¨­å®š"
+
+msgid "ContainerRegistry|Some tags were not deleted"
msgstr ""
msgid "ContainerRegistry|Something went wrong while fetching the cleanup policy."
-msgstr ""
+msgstr "クリーンアップãƒãƒªã‚·ãƒ¼ã®å–得中ã«å•é¡ŒãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚"
msgid "ContainerRegistry|Something went wrong while fetching the repository list."
msgstr ""
@@ -6667,6 +6912,9 @@ msgstr ""
msgid "ContainerRegistry|Tags with names matching this regex pattern will %{italicStart}expire:%{italicEnd}"
msgstr ""
+msgid "ContainerRegistry|The cleanup policy timed out before it could delete all tags. An administrator can %{adminLinkStart}manually run cleanup now%{adminLinkEnd} or you can wait for the cleanup policy to automatically run again. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "ContainerRegistry|The last tag related to this image was recently removed. This empty image and any associated data will be automatically removed as part of the regular Garbage Collection process. If you have any questions, contact your administrator."
msgstr "ã“ã®ç”»åƒã«é–¢é€£ã™ã‚‹æœ€å¾Œã®ã‚¿ã‚°ãŒæœ€è¿‘削除ã•ã‚Œã¾ã—ãŸã€‚ã“ã®ç©ºã®ç”»åƒã¨ãã‚Œã«é–¢é€£ã—ãŸãƒ‡ãƒ¼ã‚¿ã¯ã€é€šå¸¸ã®ã‚¬ãƒ™ãƒ¼ã‚¸ã‚³ãƒ¬ã‚¯ã‚·ãƒ§ãƒ³ãƒ—ロセスã®ä¸€éƒ¨ã¨ã—ã¦è‡ªå‹•çš„ã«å‰Šé™¤ã•ã‚Œã¾ã™ã€‚質å•ãŒã‚ã‚‹å ´åˆã¯ã€ç®¡ç†è€…ã«ãŠå•ã„åˆã‚ã›ãã ã•ã„。"
@@ -6799,6 +7047,9 @@ msgstr ""
msgid "Contributions per group member"
msgstr "グループメンãƒãƒ¼ã®è²¢çŒ®åº¦"
+msgid "Contributor"
+msgstr ""
+
msgid "Contributors"
msgstr "貢献者"
@@ -6869,7 +7120,7 @@ msgid "Copy environment"
msgstr "環境をコピー"
msgid "Copy evidence SHA"
-msgstr ""
+msgstr "証拠 SHA をコピー"
msgid "Copy file contents"
msgstr "ファイルã®å†…容をコピー"
@@ -6928,6 +7179,9 @@ msgstr "ãƒãƒ£ãƒƒãƒˆã®ãƒ‹ãƒƒã‚¯ãƒãƒ¼ãƒ ã‚’承èªã§ãã¾ã›ã‚“ã§ã—ãŸã€‚ã‚‚
msgid "Could not change HEAD: branch '%{branch}' does not exist"
msgstr "HEADを変更ã§ãã¾ã›ã‚“ã§ã—ãŸï¼š'%{branch}'ブランムãŒå­˜åœ¨ã—ã¾ã›ã‚“ã§ã—ãŸã€‚"
+msgid "Could not commit. An unexpected error occurred."
+msgstr ""
+
msgid "Could not connect to FogBugz, check your URL"
msgstr "FogBugz ã«æŽ¥ç¶šã§ãã¾ã›ã‚“ã€URL を確èªã—ã¦ãã ã•ã„"
@@ -6967,6 +7221,9 @@ msgstr ""
msgid "Could not find iteration"
msgstr ""
+msgid "Could not load instance counts. Please refresh the page to try again."
+msgstr ""
+
msgid "Could not remove the trigger."
msgstr "トリガーを除去ã§ãã¾ã›ã‚“ã§ã—ãŸã€‚"
@@ -6991,10 +7248,10 @@ msgstr "プロジェクトIDã‚’ä¿å­˜ã§ãã¾ã›ã‚“ã§ã—ãŸ"
msgid "Could not save prometheus manual configuration"
msgstr "プロメテウスã®ãƒžãƒ‹ãƒ¥ã‚¢ãƒ«è¨­å®šã‚’ä¿å­˜ã§ãã¾ã›ã‚“ã§ã—ãŸ"
-msgid "Could not udpdate wiki page"
+msgid "Could not update the LDAP settings"
msgstr ""
-msgid "Could not update the LDAP settings"
+msgid "Could not update wiki page"
msgstr ""
msgid "Could not upload your designs as one or more files uploaded are not supported."
@@ -7650,6 +7907,9 @@ msgstr "%{invalidProjects} を追加ã§ãã¾ã›ã‚“。ダッシュボードãŒåˆ
msgid "DastProfiles|Are you sure you want to delete this profile?"
msgstr ""
+msgid "DastProfiles|Could not create site validation token. Please refresh the page, or try again later."
+msgstr ""
+
msgid "DastProfiles|Could not create the scanner profile. Please try again."
msgstr ""
@@ -7674,6 +7934,12 @@ msgstr ""
msgid "DastProfiles|Could not fetch site profiles. Please refresh the page, or try again later."
msgstr ""
+msgid "DastProfiles|Could not retrieve site validation status. Please refresh the page, or try again later."
+msgstr ""
+
+msgid "DastProfiles|Could not update the scanner profile. Please try again."
+msgstr ""
+
msgid "DastProfiles|Could not update the site profile. Please try again."
msgstr ""
@@ -7689,7 +7955,7 @@ msgstr ""
msgid "DastProfiles|Download validation text file"
msgstr ""
-msgid "DastProfiles|Edit feature will come soon. Please create a new profile if changes needed"
+msgid "DastProfiles|Edit scanner profile"
msgstr ""
msgid "DastProfiles|Edit site profile"
@@ -7722,6 +7988,9 @@ msgstr ""
msgid "DastProfiles|No profiles created yet"
msgstr ""
+msgid "DastProfiles|Passive"
+msgstr ""
+
msgid "DastProfiles|Please enter a valid URL format, ex: http://www.example.com/home"
msgstr ""
@@ -7737,6 +8006,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan mode"
+msgstr ""
+
msgid "DastProfiles|Scanner Profile"
msgstr ""
@@ -7776,10 +8048,10 @@ msgstr ""
msgid "DastProfiles|Text file validation"
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
+msgid "DastProfiles|The maximum number of minutes allowed for the spider to traverse the site."
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the spider to traverse the site."
+msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
msgstr ""
msgid "DastProfiles|Validate"
@@ -7812,6 +8084,9 @@ msgstr "日付"
msgid "Date picker"
msgstr "日付é¸æŠž"
+msgid "Date range"
+msgstr ""
+
msgid "Date range cannot exceed %{maxDateRange} days."
msgstr "日付範囲㯠%{maxDateRange} 日を超ãˆã‚‰ã‚Œã¾ã›ã‚“。"
@@ -7836,6 +8111,9 @@ msgstr "æ—¥"
msgid "Days to merge"
msgstr "マージã¾ã§ã®æ—¥æ•°"
+msgid "Dear Administrator,"
+msgstr ""
+
msgid "Debug"
msgstr "デãƒãƒƒã‚°"
@@ -7947,12 +8225,18 @@ msgstr "予約済ã¿"
msgid "Delete"
msgstr "削除"
+msgid "Delete %{name}"
+msgstr ""
+
msgid "Delete Comment"
msgstr "コメントを削除"
msgid "Delete Snippet"
msgstr "スニペットを削除"
+msgid "Delete Value Stream"
+msgstr ""
+
msgid "Delete account"
msgstr ""
@@ -7974,9 +8258,6 @@ msgstr ""
msgid "Delete label: %{label_name} ?"
msgstr ""
-msgid "Delete license"
-msgstr "ライセンスを削除"
-
msgid "Delete list"
msgstr "リストを削除ã™ã‚‹"
@@ -8052,15 +8333,6 @@ msgstr ""
msgid "Deleting a project places it into a read-only state until %{date}, at which point the project will be permanently deleted. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "Deleting the license failed."
-msgstr "ライセンスã®å‰Šé™¤ã«å¤±æ•—ã—ã¾ã—ãŸã€‚"
-
-msgid "Deleting the license failed. The license was not found."
-msgstr "ライセンスã®å‰Šé™¤ã«å¤±æ•—ã—ã¾ã—ãŸã€‚ライセンスãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“ã§ã—ãŸã€‚"
-
-msgid "Deleting the license failed. You are not permitted to perform this action."
-msgstr "ライセンスã®å‰Šé™¤ã«å¤±æ•—ã—ã¾ã—ãŸã€‚ã‚ãªãŸã¯ãƒ©ã‚¤ã‚»ãƒ³ã‚¹ã®å‰Šé™¤ã‚’許å¯ã•ã‚Œã¦ã„ã¾ã›ã‚“。"
-
msgid "Deleting the project will delete its repository and all related resources including issues, merge requests etc."
msgstr ""
@@ -8550,7 +8822,10 @@ msgstr "å…¨é¸æŠž"
msgid "DesignManagement|The maximum number of designs allowed to be uploaded is %{upload_limit}. Please try again."
msgstr "デザインã¯æœ€å¤§ã§ %{upload_limit} ã¾ã§ã‚¢ãƒƒãƒ—ロードã§ãã¾ã™ã€‚ã‚‚ã†ä¸€åº¦ã‚„ã‚Šç›´ã—ã¦ãã ã•ã„。"
-msgid "DesignManagement|To upload designs, you'll need to enable LFS. %{requirements_link_start}More information%{requirements_link_end}"
+msgid "DesignManagement|There was an error moving your designs. Please upload your designs below."
+msgstr ""
+
+msgid "DesignManagement|To upload designs, you'll need to enable LFS and have admin enable hashed storage. %{requirements_link_start}More information%{requirements_link_end}"
msgstr ""
msgid "DesignManagement|Unresolve thread"
@@ -8562,6 +8837,9 @@ msgstr ""
msgid "DesignManagement|Upload skipped."
msgstr ""
+msgid "DesignManagement|Your designs are being copied and are on their way… Please refresh to update."
+msgstr ""
+
msgid "DesignManagement|and %{moreCount} more."
msgstr ""
@@ -8619,6 +8897,9 @@ msgstr ""
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr "差分行をå–得中ã«ä½•ã‹å•é¡ŒãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚"
+msgid "Direct member"
+msgstr ""
+
msgid "Direction"
msgstr "æ–¹å‘"
@@ -8667,9 +8948,6 @@ msgstr "%{path} ã®å¤‰æ›´ã‚’破棄ã—ã¾ã™ã‹ï¼Ÿ"
msgid "Discard draft"
msgstr "下書ãを破棄"
-msgid "Discard review"
-msgstr "レビューを破棄"
-
msgid "DiscordService|Discord Notifications"
msgstr "Discord 通知"
@@ -8737,12 +9015,12 @@ msgstr ""
msgid "Dismiss Merge Request promotion"
msgstr "マージリクエストã®æ˜‡æ ¼ã‚’å´ä¸‹ã—ã¾ã™"
-msgid "Dismiss Selected"
-msgstr ""
-
msgid "Dismiss Value Stream Analytics introduction box"
msgstr "ãƒãƒªãƒ¥ãƒ¼ã‚¹ãƒˆãƒªãƒ¼ãƒ åˆ†æžã®ç´¹ä»‹ã‚’é–‰ã˜ã‚‹"
+msgid "Dismiss selected"
+msgstr ""
+
msgid "Dismiss trial promotion"
msgstr "トライアルプロモーションを閉ã˜ã‚‹"
@@ -8791,9 +9069,6 @@ msgstr "一般的㪠ID プロãƒã‚¤ãƒ€ã®ãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆ"
msgid "Documents reindexed: %{processed_documents} (%{percentage}%%)"
msgstr ""
-msgid "Doing"
-msgstr "ã‚„ã‚‹ã“ã¨"
-
msgid "Domain"
msgstr "ドメイン"
@@ -8989,9 +9264,6 @@ msgstr "説明を編集"
msgid "Edit environment"
msgstr "環境を編集"
-msgid "Edit file"
-msgstr "ファイルã®ç·¨é›†"
-
msgid "Edit files in the editor and commit changes here"
msgstr "エディターã§ãƒ•ã‚¡ã‚¤ãƒ«ã‚’編集ã—ã€ã“ã“ã§å¤‰æ›´ã‚’コミットã—ã¾ã™"
@@ -9004,6 +9276,12 @@ msgstr "グループを編集:%{group_name}"
msgid "Edit identity for %{user_name}"
msgstr "%{user_name} ã® ID を編集ã™ã‚‹"
+msgid "Edit in Web IDE"
+msgstr ""
+
+msgid "Edit in single-file editor"
+msgstr ""
+
msgid "Edit issues"
msgstr "課題を編集"
@@ -9031,21 +9309,18 @@ msgstr ""
msgid "Editing"
msgstr "編集中"
-msgid "Elasticsearch"
-msgstr "Elasticsearch"
-
msgid "Elasticsearch AWS IAM credentials"
msgstr "Elasticsearch AWS IAMèªè¨¼æƒ…å ±"
+msgid "Elasticsearch HTTP client timeout value in seconds."
+msgstr ""
+
msgid "Elasticsearch indexing restrictions"
msgstr "Elasticsearchã®ã‚¤ãƒ³ãƒ‡ãƒƒã‚¯ã‚¹ä½œæˆã®åˆ¶é™"
msgid "Elasticsearch indexing started"
msgstr "Elasticsearchã®ã‚¤ãƒ³ãƒ‡ãƒƒã‚¯ã‚¹ä½œæˆã‚’開始ã—ã¾ã—ãŸ"
-msgid "Elasticsearch integration. Elasticsearch AWS IAM."
-msgstr "Elasticsearch ã®çµ±åˆã€‚Elasticsearch AWS IAM。"
-
msgid "Elasticsearch reindexing is already in progress"
msgstr ""
@@ -9073,9 +9348,6 @@ msgstr ""
msgid "Email Notification"
msgstr ""
-msgid "Email address"
-msgstr "メールアドレス"
-
msgid "Email could not be sent"
msgstr ""
@@ -9139,6 +9411,9 @@ msgstr "メール"
msgid "Emails sent from Service Desk will have this name"
msgstr ""
+msgid "Emails sent to %{email} will still be supported"
+msgstr ""
+
msgid "Emails separated by comma"
msgstr "Eメール (コンマ区切り)"
@@ -9172,9 +9447,18 @@ msgstr "空ã®ãƒ•ã‚¡ã‚¤ãƒ«"
msgid "Enable"
msgstr "有効化ã™ã‚‹"
+msgid "Enable %{link_start}Gitpod%{link_end} integration to launch a development environment in your browser directly from GitLab."
+msgstr ""
+
msgid "Enable Auto DevOps"
msgstr "Auto DevOps を有効ã«ã™ã‚‹"
+msgid "Enable Gitpod"
+msgstr ""
+
+msgid "Enable Gitpod?"
+msgstr ""
+
msgid "Enable HTML emails"
msgstr "HTML メールã®æœ‰åŠ¹åŒ–"
@@ -9304,9 +9588,6 @@ msgstr "ã“れを有効ã«ã™ã‚‹ã¨ã€ãƒ—ロジェクトåå‰ç©ºé–“ã®è¨ˆç”»ã«
msgid "Encountered an error while rendering: %{err}"
msgstr ""
-msgid "End date"
-msgstr "終了日"
-
msgid "Ends at (UTC)"
msgstr "終了時刻 (UTC)"
@@ -9466,7 +9747,7 @@ msgstr "削除"
msgid "EnvironmentsDashboard|The environments dashboard provides a summary of each project's environments' status, including pipeline and alert statuses."
msgstr "環境情報ダッシュボードã¯å„プロジェクトã®ç’°å¢ƒæƒ…å ±(パイプラインやアラート状態å«ã‚€) を表示ã—ã¾ã™ã€‚"
-msgid "EnvironmentsDashboard|This dashboard displays a maximum of 7 projects and 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
+msgid "EnvironmentsDashboard|This dashboard displays 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
msgstr ""
msgid "Environments|An error occurred while canceling the auto stop, please try again"
@@ -9787,6 +10068,9 @@ msgstr ""
msgid "Error deleting project. Check logs for error details."
msgstr "プロジェクトã®å‰Šé™¤ã§ã‚¨ãƒ©ãƒ¼ãŒã‚ã‚Šã¾ã™ã€‚エラーã®è©³ç´°ã«ã¤ã„ã¦ã¯ãƒ­ã‚°ã‚’確èªã—ã¦ãã ã•ã„。"
+msgid "Error fetching burnup chart data"
+msgstr ""
+
msgid "Error fetching diverging counts for branches. Please try again."
msgstr "ブランãƒã®åˆ†å²ã‚«ã‚¦ãƒ³ãƒˆå–å¾—ã«å¤±æ•—ã—ã¾ã—ãŸã€‚ã‚‚ã†ä¸€åº¦ã‚„ã‚Šç›´ã—ã¦ãã ã•ã„。"
@@ -9865,6 +10149,9 @@ msgstr "サイドãƒãƒ¼ãƒ‡ãƒ¼ã‚¿ã®å–得中ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚
msgid "Error occurred when saving assignees"
msgstr "担当者ã®ä¿å­˜ä¸­ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸ"
+msgid "Error occurred when saving reviewers"
+msgstr ""
+
msgid "Error occurred when toggling the notification subscription"
msgstr "通知購読ã®åˆ‡ã‚Šæ›¿ãˆã§ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚"
@@ -10117,12 +10404,15 @@ msgstr "展開"
msgid "Expand all"
msgstr "ã™ã¹ã¦å±•é–‹"
+msgid "Expand all files"
+msgstr ""
+
+msgid "Expand all threads"
+msgstr ""
+
msgid "Expand approvers"
msgstr "承èªè€…を展開"
-msgid "Expand dropdown"
-msgstr "ドロップダウンã®å±•é–‹"
-
msgid "Expand milestones"
msgstr ""
@@ -10291,6 +10581,9 @@ msgstr "関連ã™ã‚‹ãƒ–ランãƒã®ç¢ºèªã«å¤±æ•—ã—ã¾ã—ãŸã€‚"
msgid "Failed to create Merge Request. Please try again."
msgstr "マージリクエストã®ä½œæˆã«å¤±æ•—ã—ã¾ã—ãŸã€‚ã‚‚ã†ä¸€åº¦ãŠè©¦ã—ãã ã•ã„。"
+msgid "Failed to create To-Do for the design."
+msgstr ""
+
msgid "Failed to create a branch for this issue. Please try again."
msgstr "ã“ã®èª²é¡Œã®ãŸã‚ã®ãƒ–ランãƒã®ä½œæˆã«å¤±æ•—ã—ã¾ã—ãŸã€‚ã‚‚ã†ä¸€åº¦ã‚„ã‚Šç›´ã—ã¦ãã ã•ã„。"
@@ -10330,6 +10623,12 @@ msgstr ""
msgid "Failed to load authors. Please try again."
msgstr ""
+msgid "Failed to load branches. Please try again."
+msgstr ""
+
+msgid "Failed to load deploy keys."
+msgstr ""
+
msgid "Failed to load emoji list."
msgstr "絵文字リストã®ãƒ­ãƒ¼ãƒ‰ã«å¤±æ•—ã—ã¾ã—ãŸã€‚"
@@ -10345,6 +10644,9 @@ msgstr ""
msgid "Failed to load groups & users."
msgstr "グループã¨ãƒ¦ãƒ¼ã‚¶ãƒ¼ã®èª­ã¿è¾¼ã¿ã«å¤±æ•—ã—ã¾ã—ãŸ"
+msgid "Failed to load groups, users and deploy keys."
+msgstr ""
+
msgid "Failed to load labels. Please try again."
msgstr ""
@@ -10354,6 +10656,12 @@ msgstr ""
msgid "Failed to load related branches"
msgstr "関連ã™ã‚‹ãƒ–ランãƒã®èª­ã¿è¾¼ã¿ã«å¤±æ•—ã—ã¾ã—ãŸ"
+msgid "Failed to load sidebar confidential toggle"
+msgstr ""
+
+msgid "Failed to load sidebar lock status"
+msgstr ""
+
msgid "Failed to load stacktrace."
msgstr "スタックトレースã®ãƒ­ãƒ¼ãƒ‰ã«å¤±æ•—ã—ã¾ã—ãŸã€‚"
@@ -10381,6 +10689,9 @@ msgstr "ã“ã®ç’°å¢ƒã‚’ä¿è­·ã§ãã¾ã›ã‚“ã§ã—ãŸ"
msgid "Failed to publish issue on status page."
msgstr ""
+msgid "Failed to remove To-Do for the design."
+msgstr ""
+
msgid "Failed to remove a Zoom meeting"
msgstr "Zoom ミーティングã®å‰Šé™¤ã«å¤±æ•—ã—ã¾ã—ãŸ"
@@ -10423,6 +10734,9 @@ msgstr ""
msgid "Failed to signing using smartcard authentication"
msgstr "スマートカードèªè¨¼ã‚’使用ã—ã¦ã®ç½²åã«å¤±æ•—ã—ã¾ã—ãŸã€‚"
+msgid "Failed to toggle To-Do for the design."
+msgstr ""
+
msgid "Failed to update branch!"
msgstr "ブランãƒã®æ›´æ–°ã«å¤±æ•—ã—ã¾ã—ãŸ"
@@ -10535,7 +10849,7 @@ msgstr "機能フラグを編集"
msgid "FeatureFlags|Edit User List"
msgstr ""
-msgid "FeatureFlags|Enable features for specific users and specific environments by defining feature flag strategies."
+msgid "FeatureFlags|Enable features for specific users and environments by configuring feature flag strategies."
msgstr ""
msgid "FeatureFlags|Environment Spec"
@@ -10595,8 +10909,8 @@ msgstr "%{scope} ã®éžã‚¢ã‚¯ãƒ†ã‚£ãƒ–フラグ"
msgid "FeatureFlags|Include additional user IDs"
msgstr "追加ã®ãƒ¦ãƒ¼ã‚¶ãƒ¼IDã‚’å«ã‚ã‚‹"
-msgid "FeatureFlags|Install a %{docs_link_anchored_start}compatible client library%{docs_link_anchored_end} and specify the API URL, application name, and instance ID during the configuration setup. %{docs_link_start}More Information%{docs_link_end}"
-msgstr "%{docs_link_anchored_start}互æ›æ€§ã®ã‚るクライアントライブラリ%{docs_link_anchored_end}をインストールã—ã€æ§‹æˆã®ã‚»ãƒƒãƒˆã‚¢ãƒƒãƒ—中ã«API URLã€ã‚¢ãƒ—リケーションåã€ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹IDを指定ã—ã¾ã™ã€‚%{docs_link_start}詳細ãªæƒ…å ±%{docs_link_end}"
+msgid "FeatureFlags|Install a %{docsLinkAnchoredStart}compatible client library%{docsLinkAnchoredEnd} and specify the API URL, application name, and instance ID during the configuration setup. %{docsLinkStart}More Information%{docsLinkEnd}"
+msgstr ""
msgid "FeatureFlags|Instance ID"
msgstr "インスタンス ID"
@@ -10607,6 +10921,9 @@ msgstr ""
msgid "FeatureFlags|Loading feature flags"
msgstr "機能フラグを読ã¿è¾¼ã‚“ã§ã„ã¾ã™"
+msgid "FeatureFlags|Loading user lists"
+msgstr ""
+
msgid "FeatureFlags|More information"
msgstr "詳細情報"
@@ -10625,7 +10942,7 @@ msgstr ""
msgid "FeatureFlags|New feature flag"
msgstr "æ–°ã—ã„機能フラグ"
-msgid "FeatureFlags|New list"
+msgid "FeatureFlags|New user list"
msgstr ""
msgid "FeatureFlags|Percent of users"
@@ -10664,6 +10981,9 @@ msgstr "ターゲット環境"
msgid "FeatureFlags|There was an error fetching the feature flags."
msgstr "機能フラグã®å–得中ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚"
+msgid "FeatureFlags|There was an error fetching the user lists."
+msgstr ""
+
msgid "FeatureFlags|There was an error retrieving user lists"
msgstr ""
@@ -10679,6 +10999,9 @@ msgstr "ユーザーID"
msgid "FeatureFlags|User List"
msgstr ""
+msgid "FeatureFlags|User Lists"
+msgstr ""
+
msgid "FeatureFlag|List"
msgstr ""
@@ -10706,15 +11029,6 @@ msgstr "2月"
msgid "Fetching incoming email"
msgstr "å—信メールをå–å¾—"
-msgid "Fetching licenses failed."
-msgstr "ライセンスã®å–得を失敗ã—ã¾ã—ãŸã€‚"
-
-msgid "Fetching licenses failed. The request endpoint was not found."
-msgstr "ライセンスã®å–å¾—ã«å¤±æ•—ã—ã¾ã—ãŸã€‚è¦æ±‚エンドãƒã‚¤ãƒ³ãƒˆãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“。"
-
-msgid "Fetching licenses failed. You are not permitted to perform this action."
-msgstr "ライセンスã®å–å¾—ã«å¤±æ•—ã—ã¾ã—ãŸã€‚ã‚ãªãŸã¯ã“ã‚Œã®å®Ÿè¡Œã‚’許å¯ã•ã‚Œã¦ã„ã¾ã›ã‚“。"
-
msgid "File"
msgstr ""
@@ -10817,12 +11131,21 @@ msgstr ""
msgid "Filter by status"
msgstr ""
+msgid "Filter by test cases that are currently archived."
+msgstr ""
+
+msgid "Filter by test cases that are currently opened."
+msgstr ""
+
msgid "Filter by two-factor authentication"
msgstr "2è¦ç´ èªè¨¼ã§çµžã‚Šè¾¼ã¿"
msgid "Filter by user"
msgstr "ユーザーã§ãƒ•ã‚£ãƒ«ã‚¿ãƒ¼"
+msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
+msgstr ""
+
msgid "Filter pipelines"
msgstr ""
@@ -10838,8 +11161,8 @@ msgstr "プロジェクトã§çµžã‚Šè¾¼ã¿"
msgid "Filter results..."
msgstr ""
-msgid "Filter your projects by name"
-msgstr "åå‰ã§ã‚ãªãŸã®ãƒ—ロジェクトをフィルタ"
+msgid "Filter your repositories by name"
+msgstr ""
msgid "Filter..."
msgstr "フィルター..."
@@ -10847,7 +11170,7 @@ msgstr "フィルター..."
msgid "Find File"
msgstr ""
-msgid "Find bugs in your code with coverage-guided fuzzing"
+msgid "Find bugs in your code with coverage-guided fuzzing."
msgstr ""
msgid "Find by path"
@@ -10874,9 +11197,6 @@ msgstr "フィンガープリント"
msgid "Finish editing this message first!"
msgstr "å…ˆã«ã“ã®ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã®ç·¨é›†ã‚’終ãˆã¦ãã ã•ã„。"
-msgid "Finish review"
-msgstr "レビューを完了ã™ã‚‹"
-
msgid "Finish setting up your dedicated account for %{group_name}."
msgstr ""
@@ -10946,6 +11266,9 @@ msgstr "フォントã®è‰²"
msgid "Footer message"
msgstr "フッターメッセージ"
+msgid "For a faster browsing experience, some files are collapsed by default."
+msgstr ""
+
msgid "For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
@@ -10955,6 +11278,9 @@ msgstr "内部プロジェクトã®å ´åˆã€ãƒ­ã‚°ã‚¤ãƒ³ã—ã¦ã„ã‚‹ã™ã¹ã¦ã®
msgid "For more info, read the documentation."
msgstr "詳細ã«ã¤ã„ã¦ã¯ã€ãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆã‚’読んã§ãã ã•ã„。"
+msgid "For more information on how the number of active users is calculated, see the %{self_managed_subscriptions_doc_link} documentation."
+msgstr ""
+
msgid "For more information, go to the "
msgstr ""
@@ -11093,6 +11419,9 @@ msgstr "æ–°ã—ㄠエクスãƒãƒ¼ãƒˆã‚’生æˆ"
msgid "Generate new token"
msgstr ""
+msgid "Generic package file size in bytes"
+msgstr ""
+
msgid "Geo"
msgstr "Geo"
@@ -11354,6 +11683,9 @@ msgstr "確èªã‚’ä¿ç•™ä¸­"
msgid "Geo|Please refer to Geo Troubleshooting."
msgstr "Geo ã®ãƒˆãƒ©ãƒ–ルシューティングをå‚ç…§ã—ã¦ãã ã•ã„。"
+msgid "Geo|Primary node"
+msgstr ""
+
msgid "Geo|Project"
msgstr "プロジェクト"
@@ -11396,6 +11728,9 @@ msgstr ""
msgid "Geo|Review replication status, and resynchronize and reverify items with the primary node."
msgstr ""
+msgid "Geo|Secondary node"
+msgstr ""
+
msgid "Geo|Status"
msgstr "状態"
@@ -11435,6 +11770,9 @@ msgstr ""
msgid "Geo|URL must be a valid url (ex: https://gitlab.com)"
msgstr ""
+msgid "Geo|Undefined"
+msgstr ""
+
msgid "Geo|Unknown state"
msgstr "ä¸æ˜ŽãªçŠ¶æ…‹"
@@ -11510,11 +11848,17 @@ msgstr "GitHub APIã®åˆ¶é™ã‚’超ãˆã¾ã—ãŸã€‚ %{reset_time} 後ã«å†è©¦è¡Œã
msgid "GitHub import"
msgstr "GitHub インãƒãƒ¼ãƒˆ"
+msgid "GitLab"
+msgstr ""
+
msgid "GitLab / Unsubscribe"
msgstr "GitLab / 購読解除"
-msgid "GitLab Enterprise Edition %{plan}"
-msgstr "GitLab エンタープライズエディション %{plan}"
+msgid "GitLab API"
+msgstr ""
+
+msgid "GitLab Billing Team."
+msgstr ""
msgid "GitLab Group Runners can execute code for all the projects in this group."
msgstr "GitLab グループ Runner ã¯ã“ã®ã‚°ãƒ«ãƒ¼ãƒ—内ã®å…¨ã¦ã®ãƒ—ロジェクトã®ã‚³ãƒ¼ãƒ‰ã‚’実行ã§ãã¾ã™ã€‚"
@@ -11525,12 +11869,18 @@ msgstr "GitLab インãƒãƒ¼ãƒˆ"
msgid "GitLab Issue"
msgstr "GitLab 課題"
+msgid "GitLab Pages"
+msgstr ""
+
msgid "GitLab Service Desk is a simple way to allow people to create issues in your GitLab instance without needing their own user account. It provides a unique email address for end users to create issues in a project, and replies can be sent either through the GitLab interface or by email. End users will only see the thread through email."
msgstr ""
msgid "GitLab Shared Runners execute code of different projects on the same Runner unless you configure GitLab Runner Autoscale with MaxBuilds 1 (which it is on GitLab.com)."
msgstr "GitLab Shared Runnerã¯ã€GitLab Runnerã®ã‚ªãƒ¼ãƒˆã‚¹ã‚±ãƒ¼ãƒ«è¨­å®šã§MaxBuildsã‚’1 (GitLab.com上ã§ã¯ã“ã®è¨­å®š)ã—ãªã„é™ã‚Šã€åŒã˜Runnerã§åˆ¥ã®ãƒ—ロジェクトã®ã‚³ãƒ¼ãƒ‰ã‚’実行ã—ã¾ã™ã€‚"
+msgid "GitLab Shell"
+msgstr ""
+
msgid "GitLab Support Bot"
msgstr ""
@@ -11540,8 +11890,8 @@ msgstr ""
msgid "GitLab User"
msgstr "GitLab ユーザー"
-msgid "GitLab allows you to continue using your license even if you exceed the number of seats you purchased. You will be required to pay for these seats when you renew your license."
-msgstr "GitLabã§ã¯ã€è³¼å…¥ã—ãŸã‚·ãƒ¼ãƒˆæ•°ã‚’超ãˆã¦ã‚‚ライセンスを使用ã—続ã‘ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚ライセンス更新時ã«ã€ã“れらã®ã‚·ãƒ¼ãƒˆã®æ–™é‡‘を支払ã†å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚"
+msgid "GitLab Workhorse"
+msgstr ""
msgid "GitLab commit"
msgstr "GitLab ã®ã‚³ãƒŸãƒƒãƒˆ"
@@ -11708,6 +12058,21 @@ msgstr "Gitea インãƒãƒ¼ãƒˆ"
msgid "Gitlab Pages"
msgstr "Gitlab Pages"
+msgid "Gitpod"
+msgstr ""
+
+msgid "Gitpod|Add the URL to your Gitpod instance configured to read your GitLab projects."
+msgstr ""
+
+msgid "Gitpod|Enable Gitpod integration"
+msgstr ""
+
+msgid "Gitpod|Gitpod URL"
+msgstr ""
+
+msgid "Gitpod|e.g. https://gitpod.example.com"
+msgstr ""
+
msgid "Given access %{time_ago}"
msgstr "%{time_ago} ã«ã‚¢ã‚¯ã‚»ã‚¹è¨±å¯"
@@ -11865,7 +12230,7 @@ msgid "Got it"
msgstr "了解"
msgid "Got it!"
-msgstr "入手ã—ã¾ã—ょã†ï¼"
+msgstr "了解!"
msgid "Grafana URL"
msgstr "Grafana ã® URL"
@@ -12215,9 +12580,6 @@ msgstr "SAMLèªè¨¼ã‚’切り替ãˆ"
msgid "GroupSAML|Valid SAML Response"
msgstr "妥当ãªSAMLレスãƒãƒ³ã‚¹"
-msgid "GroupSAML|With group managed accounts enabled, all the users without a group managed account will be excluded from the group."
-msgstr "グループ管ç†ã‚¢ã‚«ã‚¦ãƒ³ãƒˆã‚’有効ã«ã™ã‚‹ã¨ã€ã‚°ãƒ«ãƒ¼ãƒ—管ç†ã‚¢ã‚«ã‚¦ãƒ³ãƒˆã‚’æŒãŸãªã„ã™ã¹ã¦ã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ãŒã“ã®ã‚°ãƒ«ãƒ¼ãƒ—ã‹ã‚‰é™¤å¤–ã•ã‚Œã¾ã™ã€‚"
-
msgid "GroupSAML|With prohibit outer forks flag enabled group members will be able to fork project only inside your group."
msgstr ""
@@ -12431,10 +12793,10 @@ msgstr ""
msgid "GroupsNew|Create group"
msgstr ""
-msgid "GroupsNew|GitLab group export"
+msgid "GroupsNew|Import"
msgstr ""
-msgid "GroupsNew|Import"
+msgid "GroupsNew|Import a GitLab group export file"
msgstr ""
msgid "GroupsNew|Import group"
@@ -12576,6 +12938,9 @@ msgid "Hide chart"
msgid_plural "Hide charts"
msgstr[0] ""
+msgid "Hide comments on this file"
+msgstr ""
+
msgid "Hide details"
msgstr ""
@@ -12619,6 +12984,15 @@ msgstr "å„rawパスã®1分ã‚ãŸã‚Šã®æœ€å¤§ãƒªã‚¯ã‚¨ã‚¹ãƒˆæ•°ã€‚デフォルãƒ
msgid "Highest role:"
msgstr "最高ä½:"
+msgid "HighlightBar|Alert events:"
+msgstr ""
+
+msgid "HighlightBar|Alert start time:"
+msgstr ""
+
+msgid "HighlightBar|Original alert:"
+msgstr ""
+
msgid "History"
msgstr "履歴"
@@ -12796,6 +13170,9 @@ msgstr ""
msgid "If enabled, access to projects will be validated on an external service using their classification label."
msgstr "有効ã«è¨­å®šã—ãŸå ´åˆã€å¤–部サービスã‹ã‚‰ãƒ—ロジェクトã¸ã®ã‚¢ã‚¯ã‚»ã‚¹ãŒåˆ†é¡žãƒ©ãƒ™ãƒ«ã‚’使用ã—ã¦åˆ¶å¾¡ã•ã‚Œã¾ã™ã€‚"
+msgid "If the number of active users exceeds the user limit, you will be charged for the number of %{users_over_license_link} at your next license reconciliation."
+msgstr ""
+
msgid "If there is no previous license or if the previous license has expired, some GitLab functionality will be blocked until a new, valid license is uploaded."
msgstr "以å‰ã®ãƒ©ã‚¤ã‚»ãƒ³ã‚¹ãŒãªã„å ´åˆã‚„ã€ä»¥å‰ã®ãƒ©ã‚¤ã‚»ãƒ³ã‚¹ã®æœ‰åŠ¹æœŸé™ãŒåˆ‡ã‚Œã¦ã„ã‚‹å ´åˆã¯ã€æ–°ã—ã„有効ãªãƒ©ã‚¤ã‚»ãƒ³ã‚¹ãŒã‚¢ãƒƒãƒ—ロードã•ã‚Œã‚‹ã¾ã§ GitLab ã®ä¸€éƒ¨ã®æ©Ÿèƒ½ãŒãƒ–ロックã•ã‚Œã¾ã™ã€‚"
@@ -12835,9 +13212,6 @@ msgstr ""
msgid "If your HTTP repository is not publicly accessible, add your credentials."
msgstr "HTTPリãƒã‚¸ãƒˆãƒªã®ã‚¢ã‚¯ã‚»ã‚¹ãŒåˆ¶é™ã•ã‚Œã¦ã„ã‚‹å ´åˆã€èªè¨¼æƒ…報を追加ã—ã¦ãã ã•ã„。"
-msgid "Iglu registry URL (optional)"
-msgstr "IgluレジストリーURL(オプション)"
-
msgid "Ignore"
msgstr "無視ã™ã‚‹"
@@ -12874,6 +13248,14 @@ msgstr "代ç†ã¯ç„¡åŠ¹ã«ãªã£ã¦ã„ã¾ã™"
msgid "Import"
msgstr "インãƒãƒ¼ãƒˆ"
+msgid "Import %d compatible repository"
+msgid_plural "Import %d compatible repositories"
+msgstr[0] ""
+
+msgid "Import %d repository"
+msgid_plural "Import %d repositories"
+msgstr[0] ""
+
msgid "Import CSV"
msgstr "CSV ã®å–ã‚Šè¾¼ã¿"
@@ -12883,15 +13265,9 @@ msgstr "Gitea ã‹ã‚‰ãƒ—ロジェクトã®ã‚¤ãƒ³ãƒãƒ¼ãƒˆ"
msgid "Import all compatible projects"
msgstr "å…¨ã¦ã®äº’æ›æ€§ã®ã‚るプロジェクトã®ã‚¤ãƒ³ãƒãƒ¼ãƒˆ"
-msgid "Import all compatible repositories"
-msgstr ""
-
msgid "Import all projects"
msgstr "全プロジェクトã®ã‚¤ãƒ³ãƒãƒ¼ãƒˆ"
-msgid "Import all repositories"
-msgstr "ã™ã¹ã¦ã®ãƒªãƒã‚¸ãƒˆãƒªã‚’インãƒãƒ¼ãƒˆ"
-
msgid "Import an exported GitLab project"
msgstr "エクスãƒãƒ¼ãƒˆã—㟠GItLab プロジェクトã®ã‚¤ãƒ³ãƒãƒ¼ãƒˆ"
@@ -12979,6 +13355,9 @@ msgstr "ブロックã•ã‚ŒãŸã‚¤ãƒ³ãƒãƒ¼ãƒˆURL: %{message}"
msgid "ImportProjects|Error importing repository %{project_safe_import_url} into %{project_full_path} - %{message}"
msgstr "%{project_safe_import_url} リãƒã‚¸ãƒˆãƒªã‹ã‚‰ %{project_full_path} ã¸ã®ã‚¤ãƒ³ãƒãƒ¼ãƒˆã‚¨ãƒ©ãƒ¼- %{message}"
+msgid "ImportProjects|Import repositories"
+msgstr ""
+
msgid "ImportProjects|Importing the project failed"
msgstr "プロジェクトã®ã‚¤ãƒ³ãƒãƒ¼ãƒˆã«å¤±æ•—ã—ã¾ã—ãŸ"
@@ -12991,8 +13370,8 @@ msgstr ""
msgid "ImportProjects|Requesting your %{provider} repositories failed"
msgstr "%{provider} リãƒã‚¸ãƒˆãƒªã®è¦æ±‚ã«å¤±æ•—ã—ã¾ã—ãŸ"
-msgid "ImportProjects|Select the projects you want to import"
-msgstr "ã‚ãªãŸãŒã‚¤ãƒ³ãƒãƒ¼ãƒˆã—ãŸã„プロジェクトをé¸æŠžã—ã¾ã™"
+msgid "ImportProjects|Select the repositories you want to import"
+msgstr ""
msgid "ImportProjects|The remote data could not be imported."
msgstr "リモートデータをインãƒãƒ¼ãƒˆã§ãã¾ã›ã‚“ã§ã—ãŸã€‚"
@@ -13027,9 +13406,6 @@ msgstr ""
msgid "In order to enable Service Desk for your instance, you must first set up incoming email."
msgstr ""
-msgid "In order to gather accurate feature usage data, it can take 1 to 2 weeks to see your index."
-msgstr "正確ãªæ©Ÿèƒ½ã®ä½¿ç”¨çŠ¶æ³ã‚’åŽé›†ã™ã‚‹ãŸã‚ã«ã€ã‚¤ãƒ³ãƒ‡ãƒƒã‚¯ã‚¹ã‚’確èªã™ã‚‹ã®ã«1〜2週間ã‹ã‹ã‚‹ã“ã¨ãŒã‚ã‚Šã¾ã™ã€‚"
-
msgid "In order to personalize your experience with GitLab%{br_tag}we would like to know a bit more about you."
msgstr ""
@@ -13060,18 +13436,30 @@ msgstr ""
msgid "IncidentManagement|Create incident"
msgstr ""
+msgid "IncidentManagement|Critical - S1"
+msgstr ""
+
msgid "IncidentManagement|Date created"
msgstr ""
msgid "IncidentManagement|Display your incidents in a dedicated view"
msgstr ""
+msgid "IncidentManagement|High - S2"
+msgstr ""
+
msgid "IncidentManagement|Incident"
msgstr ""
msgid "IncidentManagement|Incidents"
msgstr ""
+msgid "IncidentManagement|Low - S4"
+msgstr ""
+
+msgid "IncidentManagement|Medium - S3"
+msgstr ""
+
msgid "IncidentManagement|No incidents to display."
msgstr ""
@@ -13084,6 +13472,9 @@ msgstr ""
msgid "IncidentManagement|Published to status page"
msgstr ""
+msgid "IncidentManagement|Severity"
+msgstr ""
+
msgid "IncidentManagement|There are no closed incidents"
msgstr ""
@@ -13093,6 +13484,9 @@ msgstr ""
msgid "IncidentManagement|Unassigned"
msgstr ""
+msgid "IncidentManagement|Unknown"
+msgstr ""
+
msgid "IncidentManagement|Unpublished"
msgstr ""
@@ -13114,6 +13508,15 @@ msgstr ""
msgid "Incidents"
msgstr "インシデント"
+msgid "Incident|Alert details"
+msgstr ""
+
+msgid "Incident|Summary"
+msgstr ""
+
+msgid "Incident|There was an issue loading alert data. Please try again."
+msgstr ""
+
msgid "Include a Terms of Service agreement and Privacy Policy that all users must accept."
msgstr "ã™ã¹ã¦ã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ãŒåŒæ„ã—ãªã‘ã‚Œã°ãªã‚‰ãªã„利用è¦ç´„ã¨ãƒ—ライãƒã‚·ãƒ¼ãƒãƒªã‚·ãƒ¼ã‚’å«ã‚ã¾ã™ã€‚"
@@ -13174,6 +13577,9 @@ msgstr "SSHキーをアップロードã—ã¦ã„ãªã„ユーザーã«ã€è¿½åŠ ã•
msgid "Information about additional Pages templates and how to install them can be found in our %{pages_getting_started_guide}."
msgstr "追加ã®Pagesテンプレートã«é–¢ã™ã‚‹æƒ…å ±ã¨ãれらをインストールã™ã‚‹æ–¹æ³•ã«ã¤ã„ã¦ã¯ã€ç§ãŸã¡ã® %{pages_getting_started_guide} ã‚’å‚ç…§ã—ã¦ãã ã•ã„。"
+msgid "Inherited"
+msgstr ""
+
msgid "Inherited:"
msgstr "継承ã•ã‚Œã¾ã—ãŸï¼š"
@@ -13253,8 +13659,23 @@ msgstr ""
msgid "Instance administrators group already exists"
msgstr "インスタンス管ç†è€…グループã¯æ—¢ã«å­˜åœ¨ã—ã¾ã™"
-msgid "Instance license"
-msgstr "インスタンス ã®ãƒ©ã‚¤ã‚»ãƒ³ã‚¹"
+msgid "InstanceStatistics|Groups"
+msgstr ""
+
+msgid "InstanceStatistics|Issues"
+msgstr ""
+
+msgid "InstanceStatistics|Merge Requests"
+msgstr ""
+
+msgid "InstanceStatistics|Pipelines"
+msgstr ""
+
+msgid "InstanceStatistics|Projects"
+msgstr ""
+
+msgid "InstanceStatistics|Users"
+msgstr ""
msgid "Integration"
msgstr ""
@@ -13265,6 +13686,12 @@ msgstr ""
msgid "Integrations"
msgstr "インテグレーション"
+msgid "Integrations|%{integration} settings saved and active."
+msgstr ""
+
+msgid "Integrations|%{integration} settings saved, but not active."
+msgstr ""
+
msgid "Integrations|All details"
msgstr ""
@@ -13274,6 +13701,12 @@ msgstr ""
msgid "Integrations|Comment settings:"
msgstr ""
+msgid "Integrations|Connection failed. Please check your settings."
+msgstr ""
+
+msgid "Integrations|Connection successful."
+msgstr ""
+
msgid "Integrations|Default settings are inherited from the group level."
msgstr ""
@@ -13289,6 +13722,15 @@ msgstr ""
msgid "Integrations|Includes commit title and branch"
msgstr ""
+msgid "Integrations|Projects using custom settings will not be impacted unless the project owner chooses to use instance-level defaults."
+msgstr ""
+
+msgid "Integrations|Save settings?"
+msgstr ""
+
+msgid "Integrations|Saving will update the default settings for all projects that are not using custom settings."
+msgstr ""
+
msgid "Integrations|Standard"
msgstr ""
@@ -13421,6 +13863,9 @@ msgstr ""
msgid "Invitation"
msgstr "招待状"
+msgid "Invitation declined"
+msgstr ""
+
msgid "Invite"
msgstr "招待"
@@ -13472,6 +13917,42 @@ 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|%{linkStart}Read more%{linkEnd} about role permissions"
+msgstr ""
+
+msgid "InviteMembersModal|Access expiration date (optional)"
+msgstr ""
+
+msgid "InviteMembersModal|Cancel"
+msgstr ""
+
+msgid "InviteMembersModal|Choose a role permission"
+msgstr ""
+
+msgid "InviteMembersModal|GitLab member or Email address"
+msgstr ""
+
+msgid "InviteMembersModal|Invite"
+msgstr ""
+
+msgid "InviteMembersModal|Invite team members"
+msgstr ""
+
+msgid "InviteMembersModal|Search for members to invite"
+msgstr ""
+
+msgid "InviteMembersModal|User not invited. Feature coming soon!"
+msgstr ""
+
+msgid "InviteMembersModal|Users were succesfully added"
+msgstr ""
+
+msgid "InviteMembersModal|You're inviting members to the %{group_name} group"
+msgstr ""
+
+msgid "InviteMembers|Invite team members"
+msgstr ""
+
msgid "Invited"
msgstr ""
@@ -13526,10 +14007,13 @@ msgstr ""
msgid "Issue cannot be found."
msgstr "課題を見ã¤ã‘ã‚‹ã“ã¨ãŒã§ãã¾ã›ã‚“"
+msgid "Issue created from vulnerability %{vulnerability_link}"
+msgstr ""
+
msgid "Issue events"
msgstr "課題イベント"
-msgid "Issue first depoloyed to production"
+msgid "Issue first deployed to production"
msgstr ""
msgid "Issue label"
@@ -13607,6 +14091,9 @@ msgstr "Bugzilla課題トラッカー"
msgid "IssueTracker|Custom issue tracker"
msgstr "カスタム課題トラッカー"
+msgid "IssueTracker|EWM work items tracker"
+msgstr ""
+
msgid "IssueTracker|Redmine issue tracker"
msgstr "Redmine 課題トラッカー"
@@ -13673,6 +14160,9 @@ msgstr "タイトル"
msgid "It looks like you have some draft commits in this branch."
msgstr ""
+msgid "It may be several days before you see feature usage data."
+msgstr ""
+
msgid "It must have a header row and at least two columns: the first column is the issue title and the second column is the issue description. The separator is automatically detected."
msgstr "ヘッダー行ã¨å°‘ãªãã¨ã‚‚2ã¤ã®åˆ—ãŒå¿…è¦ã§ã™ã€‚最åˆã®åˆ—ã¯èª²é¡Œã®ã‚¿ã‚¤ãƒˆãƒ«ã€2番目ã®åˆ—ã¯èª²é¡Œã®èª¬æ˜Žã§ã™ã€‚区切り文字ã¯è‡ªå‹•çš„ã«æ¤œå‡ºã•ã‚Œã¾ã™ã€‚"
@@ -13955,15 +14445,15 @@ msgstr "ソースブランãƒ:"
msgid "Join Zoom meeting"
msgstr "Zoom ミーティングã«å‚加ã™ã‚‹"
+msgid "Joined %{time_ago}"
+msgstr ""
+
msgid "Jul"
msgstr "7月"
msgid "July"
msgstr "7月"
-msgid "Jump to first unresolved thread"
-msgstr ""
-
msgid "Jump to next unresolved thread"
msgstr ""
@@ -13997,6 +14487,9 @@ msgstr "キー: %{key}"
msgid "Keyboard shortcuts"
msgstr ""
+msgid "KeyboardKey|Ctrl+"
+msgstr ""
+
msgid "Keys"
msgstr ""
@@ -14045,6 +14538,9 @@ msgstr "LDAP"
msgid "LDAP Synchronization"
msgstr ""
+msgid "LDAP group settings"
+msgstr ""
+
msgid "LDAP settings"
msgstr "LDAP 設定"
@@ -14054,6 +14550,9 @@ msgstr ""
msgid "LDAP sync in progress. This could take a few minutes. Refresh the page to see the changes."
msgstr "LDAP åŒæœŸãŒé€²è¡Œä¸­ã§ã™ã€‚ã“ã‚Œã«ã¯æ•°åˆ†ã‹ã‹ã‚‹ã“ã¨ãŒã‚ã‚Šã¾ã™ã€‚ページを更新ã—ã¦å¤‰æ›´å†…容を確èªã—ã¦ãã ã•ã„。"
+msgid "LDAP synchronizations"
+msgstr ""
+
msgid "LFS"
msgstr "LFS"
@@ -14133,8 +14632,17 @@ msgid "Last %d day"
msgid_plural "Last %d days"
msgstr[0] "éŽåŽ»%d日間"
-msgid "Last %{days} days"
-msgstr "éŽåŽ»%{days} 日間"
+msgid "Last 2 weeks"
+msgstr ""
+
+msgid "Last 30 days"
+msgstr ""
+
+msgid "Last 60 days"
+msgstr ""
+
+msgid "Last 90 days"
+msgstr ""
msgid "Last Accessed On"
msgstr "最終アクセス"
@@ -14211,6 +14719,9 @@ msgstr "å‰å›žä½¿ç”¨"
msgid "Last used on:"
msgstr "最終使用日: "
+msgid "Last week"
+msgstr ""
+
msgid "LastCommit|authored"
msgstr ""
@@ -14226,6 +14737,9 @@ msgstr "最新ã®å¤‰æ›´"
msgid "Latest pipeline for the most recent commit on this branch"
msgstr "ã“ã®ãƒ–ランãƒã§ã®ç›´è¿‘ã®ã‚³ãƒŸãƒƒãƒˆã®æœ€æ–°ã®ãƒ‘イプライン"
+msgid "Launch a ready-to-code development environment for your project."
+msgstr ""
+
msgid "Lead"
msgstr "リード"
@@ -14599,6 +15113,9 @@ msgstr "利用å¯èƒ½ãªãƒªãƒã‚¸ãƒˆãƒªã®ä¸€è¦§"
msgid "List of all merge commits"
msgstr ""
+msgid "List options"
+msgstr ""
+
msgid "List settings"
msgstr ""
@@ -14611,9 +15128,6 @@ msgstr "一覧表示"
msgid "List your Bitbucket Server repositories"
msgstr "ã‚ãªãŸã®ã€Bitbucket Server ã®ãƒªãƒã‚¸ãƒˆãƒªã‚’一覧表示ã™ã‚‹"
-msgid "Lists"
-msgstr ""
-
msgid "Live preview"
msgstr "ライブプレビュー"
@@ -14633,7 +15147,7 @@ msgid "Loading files, directories, and submodules in the path %{path} for commit
msgstr "コミットå‚ç…§ %{ref} 㮠パス %{path} ã«ãŠã‘るファイルã€ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã€ãŠã‚ˆã³ã‚µãƒ–モジュールを読ã¿è¾¼ã‚“ã§ã„ã¾ã™"
msgid "Loading functions timed out. Please reload the page to try again."
-msgstr "ロード機能ãŒã‚¿ã‚¤ãƒ ã‚¢ã‚¦ãƒˆã—ã¾ã—ãŸã€‚ã‚‚ã†ä¸€åº¦ã€ãƒšãƒ¼ã‚¸ã‚’リロードã—ã¦ãã ã•ã„。"
+msgstr "Fcuntionã®èª­ã¿è¾¼ã¿ãŒã‚¿ã‚¤ãƒ ã‚¢ã‚¦ãƒˆã—ã¾ã—ãŸã€‚ã‚‚ã†ä¸€åº¦ã€ãƒšãƒ¼ã‚¸ã‚’リロードã—ã¦ãã ã•ã„。"
msgid "Loading issues"
msgstr "課題ã®ãƒ­ãƒ¼ãƒ‰"
@@ -14860,6 +15374,12 @@ msgstr "Todo を完了ã«ã™ã‚‹"
msgid "Mark as done"
msgstr "完了ã«ã™ã‚‹"
+msgid "Mark as draft"
+msgstr ""
+
+msgid "Mark as ready"
+msgstr ""
+
msgid "Mark as resolved"
msgstr "解決済ã«ã™ã‚‹"
@@ -14881,6 +15401,24 @@ msgstr "マークダウンを使用ã§ãã¾ã™"
msgid "Markdown is supported"
msgstr "マークダウンをサãƒãƒ¼ãƒˆã—ã¦ã„ã¾ã™ã€‚"
+msgid "MarkdownEditor|Add a link (%{modifierKey}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add a link (%{modifier_key}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifierKey}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifier_key}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifierKey}I)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifier_key}I)"
+msgstr ""
+
msgid "Marked For Deletion At - %{deletion_time}"
msgstr ""
@@ -14965,8 +15503,26 @@ msgstr ""
msgid "Max access level"
msgstr "最大アクセスレベル"
-msgid "Max seats used"
-msgstr "最大使用シート数"
+msgid "Max role"
+msgstr ""
+
+msgid "Max size 15 MB"
+msgstr ""
+
+msgid "Maximum Conan package file size in bytes"
+msgstr ""
+
+msgid "Maximum Maven package file size in bytes"
+msgstr ""
+
+msgid "Maximum NPM package file size in bytes"
+msgstr ""
+
+msgid "Maximum NuGet package file size in bytes"
+msgstr ""
+
+msgid "Maximum PyPI package file size in bytes"
+msgstr ""
msgid "Maximum Users:"
msgstr ""
@@ -15097,6 +15653,18 @@ msgstr ""
msgid "Members with access to %{strong_start}%{group_name}%{strong_end}"
msgstr "%{strong_start}%{group_name}%{strong_end} ã¸ã‚¢ã‚¯ã‚»ã‚¹ã§ãるメンãƒãƒ¼"
+msgid "Members|%{time} by %{user}"
+msgstr ""
+
+msgid "Members|Expired"
+msgstr ""
+
+msgid "Members|No expiration set"
+msgstr ""
+
+msgid "Members|in %{time}"
+msgstr ""
+
msgid "Memory Usage"
msgstr "メモリ使用é‡"
@@ -15283,9 +15851,6 @@ msgstr "スレッドを解決ã—ã¾ã™"
msgid "MergeRequests|Thread will be unresolved"
msgstr "スレッドを未解決ã«ã—ã¾ã™"
-msgid "MergeRequests|Toggle comments for this file"
-msgstr "ã“ã®ãƒ•ã‚¡ã‚¤ãƒ«ã®ã‚³ãƒ¡ãƒ³ãƒˆã‚’切り替ãˆã¾ã™"
-
msgid "MergeRequests|View file @ %{commitId}"
msgstr "%{commitId} ã®ãƒ•ã‚¡ã‚¤ãƒ«ã‚’表示"
@@ -15346,6 +15911,9 @@ msgstr "パイプラインãŒæˆåŠŸã—ãŸã¨ãã«ã“ã®ãƒžãƒ¼ã‚¸ãƒªã‚¯ã‚¨ã‚¹ãƒˆ
msgid "Merging immediately isn't recommended as it may negatively impact the existing merge train. Read the %{docsLinkStart}documentation%{docsLinkEnd} for more information."
msgstr "既存ã®ãƒžãƒ¼ã‚¸ãƒˆãƒ¬ã‚¤ãƒ³ã«æ‚ªå½±éŸ¿ã‚’与ãˆã‚‹å¯èƒ½æ€§ãŒã‚ã‚‹ãŸã‚ã€ç›´ã¡ã«ãƒžãƒ¼ã‚¸ã™ã‚‹ã“ã¨ã¯å‹§ã‚られã¾ã›ã‚“。詳細ã«ã¤ã„ã¦ã¯ã€ %{docsLinkStart}ドキュメント%{docsLinkEnd} ã‚’ãŠèª­ã¿ãã ã•ã„。"
+msgid "Message"
+msgstr ""
+
msgid "Messages"
msgstr "メッセージ"
@@ -15729,18 +16297,12 @@ msgid "Milestone"
msgid_plural "Milestones"
msgstr[0] "マイルストーン"
-msgid "Milestone does not support burnup charts"
-msgstr ""
-
msgid "Milestone lists not available with your current license"
msgstr "ç¾åœ¨ã®ãƒ©ã‚¤ã‚»ãƒ³ã‚¹ã§ã¯ マイルストーンリストを利用ã§ãã¾ã›ã‚“"
msgid "Milestone lists show all issues from the selected milestone."
msgstr "マイルストーンリストã«ã¯ã€é¸æŠžã—ãŸãƒžã‚¤ãƒ«ã‚¹ãƒˆãƒ¼ãƒ³ã®ã™ã¹ã¦ã®èª²é¡Œã‚’表示ã—ã¾ã™ã€‚"
-msgid "Milestone must have a start and due date"
-msgstr ""
-
msgid "MilestoneSidebar|Closed:"
msgstr ""
@@ -16107,6 +16669,9 @@ msgstr "åå‰:"
msgid "Namespace"
msgstr ""
+msgid "Namespace ID:"
+msgstr ""
+
msgid "Namespace is empty"
msgstr ""
@@ -16191,6 +16756,9 @@ msgstr ""
msgid "NetworkPolicies|Allow all outbound traffic from %{selector} to %{ruleSelector} on %{ports}"
msgstr ""
+msgid "NetworkPolicies|Are you sure you want to delete this policy? This action cannot be undone."
+msgstr ""
+
msgid "NetworkPolicies|Choose whether to enforce this policy."
msgstr ""
@@ -16200,12 +16768,21 @@ msgstr ""
msgid "NetworkPolicies|Define this policy's location, conditions and actions."
msgstr ""
+msgid "NetworkPolicies|Delete policy"
+msgstr ""
+
+msgid "NetworkPolicies|Delete policy: %{policy}"
+msgstr ""
+
msgid "NetworkPolicies|Deny all traffic"
msgstr ""
msgid "NetworkPolicies|Description"
msgstr ""
+msgid "NetworkPolicies|Edit policy"
+msgstr ""
+
msgid "NetworkPolicies|Editor mode"
msgstr ""
@@ -16233,6 +16810,9 @@ msgstr ""
msgid "NetworkPolicies|Name"
msgstr ""
+msgid "NetworkPolicies|Namespace"
+msgstr ""
+
msgid "NetworkPolicies|Network Policy"
msgstr ""
@@ -16284,6 +16864,9 @@ msgstr ""
msgid "NetworkPolicies|Rules"
msgstr ""
+msgid "NetworkPolicies|Save changes"
+msgstr ""
+
msgid "NetworkPolicies|Something went wrong, failed to update policy"
msgstr ""
@@ -16296,6 +16879,9 @@ msgstr ""
msgid "NetworkPolicies|Traffic that does not match any rule will be blocked."
msgstr ""
+msgid "NetworkPolicies|Unable to parse policy"
+msgstr ""
+
msgid "NetworkPolicies|YAML editor"
msgstr ""
@@ -16351,7 +16937,7 @@ msgid "New Application"
msgstr "æ–°ã—ã„アプリケーション"
msgid "New Branch"
-msgstr ""
+msgstr "æ–°è¦ãƒ–ランãƒ"
msgid "New Deploy Key"
msgstr ""
@@ -16360,10 +16946,10 @@ msgid "New Environment"
msgstr "æ–°ã—ã„環境"
msgid "New Epic"
-msgstr ""
+msgstr "æ–°ã—ã„エピック"
msgid "New File"
-msgstr ""
+msgstr "æ–°è¦ãƒ•ã‚¡ã‚¤ãƒ«"
msgid "New Group"
msgstr "æ–°ã—ã„グループ"
@@ -16408,6 +16994,9 @@ msgstr ""
msgid "New Snippet"
msgstr "æ–°è¦ã‚¹ãƒ‹ãƒšãƒƒãƒˆ"
+msgid "New Test Case"
+msgstr ""
+
msgid "New User"
msgstr ""
@@ -16507,6 +17096,9 @@ msgstr "æ–°è¦ã‚µãƒ–グループ"
msgid "New tag"
msgstr "æ–°è¦ã‚¿ã‚°"
+msgid "New test case"
+msgstr ""
+
msgid "New users set to external"
msgstr "æ–°è¦ãƒ¦ãƒ¼ã‚¶ãƒ¼ã‚’外部ユーザーã«è¨­å®š"
@@ -16579,8 +17171,8 @@ msgstr "ブランãƒãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“。"
msgid "No changes"
msgstr "変更ãªã—"
-msgid "No changes between %{ref_start}%{source_branch}%{ref_end} and %{ref_start}%{target_branch}%{ref_end}"
-msgstr "%{ref_start}%{source_branch}%{ref_end} 㨠%{ref_start}%{target_branch}%{ref_end} ã®é–“ã«å¤‰æ›´ãŒã‚ã‚Šã¾ã›ã‚“。"
+msgid "No changes between %{sourceBranch} and %{targetBranch}"
+msgstr ""
msgid "No child epics match applied filters"
msgstr "é©ç”¨ã•ã‚ŒãŸãƒ•ã‚£ãƒ«ã‚¿ãƒ¼ã¨ä¸€è‡´ã™ã‚‹å­ã‚¨ãƒ”ックã¯ã‚ã‚Šã¾ã›ã‚“"
@@ -16594,6 +17186,9 @@ msgstr "Gitaly サーãƒãƒ¼ã«æŽ¥ç¶šã§ãã¾ã›ã‚“ã§ã—ãŸã€‚ログを確èªã
msgid "No containers available"
msgstr "コンテナãŒã‚ã‚Šã¾ã›ã‚“"
+msgid "No content to show"
+msgstr ""
+
msgid "No contributions"
msgstr "貢献ãªã—"
@@ -16669,9 +17264,6 @@ msgstr "ãã®åå‰ã¾ãŸã¯èª¬æ˜Žã®ãƒ©ãƒ™ãƒ«ãŒã‚ã‚Šã¾ã›ã‚“"
msgid "No license. All rights reserved"
msgstr "ライセンス表記ãŒã‚ã‚Šã¾ã›ã‚“。全ã¦ã®æ¨©åˆ©ã‚’ä¿æœ‰ã—ã¦ã„ã¾ã™ã€‚"
-msgid "No licenses found."
-msgstr "ライセンスãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“。"
-
msgid "No matches found"
msgstr "一致ã™ã‚‹é …ç›®ãŒã‚ã‚Šã¾ã›ã‚“"
@@ -16684,6 +17276,9 @@ msgstr "一致ã™ã‚‹çµæžœãŒã‚ã‚Šã¾ã›ã‚“"
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No members found"
+msgstr ""
+
msgid "No merge requests found"
msgstr "マージリクエストã¯è¦‹ã¤ã‹ã‚Šã¾ã›ã‚“ã§ã—ãŸ"
@@ -16705,6 +17300,9 @@ msgstr ""
msgid "No parent group"
msgstr "親グループã¯ã‚ã‚Šã¾ã›ã‚“"
+msgid "No plan"
+msgstr ""
+
msgid "No pods available"
msgstr "利用å¯èƒ½ãªãƒãƒƒãƒ‰ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“"
@@ -16801,6 +17399,12 @@ msgstr "ãªã—"
msgid "Not Implemented"
msgstr "未実装"
+msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+msgstr ""
+
+msgid "Not all browsers support WebAuthn. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even from an unsupported browser."
+msgstr ""
+
msgid "Not all data has been processed yet, the accuracy of the chart for the selected timeframe is limited."
msgstr "ã™ã¹ã¦ã®ãƒ‡ãƒ¼ã‚¿ãŒã¾ã å‡¦ç†ã§ãã¦ã„ã¾ã›ã‚“。ãã®ãŸã‚ã€é¸æŠžã—ãŸæ™‚間範囲ã®ãƒãƒ£ãƒ¼ãƒˆã®ç²¾åº¦ã¯åˆ¶é™ã•ã‚Œã¦ã„ã¾ã™ã€‚"
@@ -16897,6 +17501,9 @@ msgstr "通知設定 - %{notification_title}"
msgid "Notification settings saved"
msgstr "通知設定ãŒä¿å­˜ã•ã‚Œã¾ã—ãŸ"
+msgid "NotificationEvent|Change reviewer merge request"
+msgstr ""
+
msgid "NotificationEvent|Close issue"
msgstr "課題をクローズ"
@@ -17059,10 +17666,7 @@ msgstr ""
msgid "On track"
msgstr ""
-msgid "OnDemandScans|Attached branch"
-msgstr ""
-
-msgid "OnDemandScans|Attached branch is where the scan job runs."
+msgid "OnDemandScans|Could not fetch scanner profiles. Please refresh the page, or try again later."
msgstr ""
msgid "OnDemandScans|Could not fetch site profiles. Please refresh the page, or try again later."
@@ -17071,6 +17675,9 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
+msgid "OnDemandScans|Create a new scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Create a new site profile"
msgstr ""
@@ -17083,6 +17690,9 @@ msgstr ""
msgid "OnDemandScans|New on-demand DAST scan"
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 ""
@@ -17092,16 +17702,10 @@ msgstr ""
msgid "OnDemandScans|On-demand scans run outside the DevOps cycle and find vulnerabilities in your projects. %{learnMoreLinkStart}Learn more%{learnMoreLinkEnd}"
msgstr ""
-msgid "OnDemandScans|Only a passive scan can be performed on demand."
-msgstr ""
-
-msgid "OnDemandScans|Passive"
-msgstr ""
-
msgid "OnDemandScans|Run scan"
msgstr ""
-msgid "OnDemandScans|Scan mode"
+msgid "OnDemandScans|Scanner profile"
msgstr ""
msgid "OnDemandScans|Scanner settings"
@@ -17113,9 +17717,15 @@ msgstr ""
msgid "OnDemandScans|Select one of the existing profiles"
msgstr ""
+msgid "OnDemandScans|Site profile"
+msgstr ""
+
msgid "OnDemandScans|Site profiles"
msgstr ""
+msgid "OnDemandScans|Use existing scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Use existing site profile"
msgstr ""
@@ -17213,9 +17823,6 @@ msgstr "未解決(Open)"
msgid "Open Selection"
msgstr "é¸æŠžæ¸ˆã¿ã®ã‚‚ã®ã‚’é–‹ã"
-msgid "Open Web IDE"
-msgstr ""
-
msgid "Open comment type dropdown"
msgstr "コメントタイプドロップダウンを開ã"
@@ -17321,6 +17928,9 @@ msgstr "ã¾ãŸã¯ã€ä¸‹è¨˜ã®ã„ãšã‚Œã‹ã®è‰²ã‚’é¸æŠžã§ãã¾ã™"
msgid "Origin"
msgstr "Origin"
+msgid "Orphaned member"
+msgstr ""
+
msgid "Other Labels"
msgstr "ãã®ä»–ã®ãƒ©ãƒ™ãƒ«"
@@ -17336,6 +17946,9 @@ msgstr ""
msgid "Other visibility settings have been disabled by the administrator."
msgstr "管ç†è€…ã«ã‚ˆã£ã¦ãã®ä»–ã®è¡¨ç¤ºè¨­å®šãŒç„¡åŠ¹ã«ã•ã‚Œã¦ã„ã¾ã™ã€‚"
+msgid "Our documentation includes an example DevOps Score report."
+msgstr ""
+
msgid "Out-of-compliance with this project's policies and should be removed"
msgstr ""
@@ -17360,6 +17973,9 @@ msgstr "概è¦"
msgid "Overwrite diverged branches"
msgstr "分å²ã—ãŸãƒ–ランãƒã®ä¸Šæ›¸ã"
+msgid "Owned by %{image_tag}"
+msgstr ""
+
msgid "Owned by anyone"
msgstr "誰ã‹ãŒæ‰€æœ‰"
@@ -17381,6 +17997,9 @@ msgstr "パッケージã¯ã™ã§ã«ã‚ã‚Šã¾ã™"
msgid "Package deleted successfully"
msgstr "パッケージã¯æ­£å¸¸ã«å‰Šé™¤ã•ã‚Œã¾ã—ãŸ"
+msgid "Package file size limits"
+msgstr ""
+
msgid "Package recipe already exists"
msgstr "パッケージã®ãƒ¬ã‚·ãƒ”ã¯æ—¢ã«å­˜åœ¨ã—ã¦ã„ã¾ã™"
@@ -17396,9 +18015,6 @@ msgstr ""
msgid "Package type must be PyPi"
msgstr ""
-msgid "Package was removed"
-msgstr "パッケージãŒå‰Šé™¤ã•ã‚Œã¾ã—ãŸ"
-
msgid "PackageRegistry|%{name} version %{version} was created %{datetime}"
msgstr ""
@@ -17540,12 +18156,18 @@ msgstr "NuGet"
msgid "PackageRegistry|NuGet Command"
msgstr "NuGet コマンド"
+msgid "PackageRegistry|Package Registry"
+msgstr ""
+
msgid "PackageRegistry|Pip Command"
msgstr "pip コマンド"
msgid "PackageRegistry|Pipeline %{link} triggered %{datetime} by %{author}"
msgstr ""
+msgid "PackageRegistry|Publish and share packages for a variety of common package managers. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "PackageRegistry|Published to the %{project} Package Registry %{datetime}"
msgstr ""
@@ -17645,6 +18267,9 @@ msgstr ""
msgid "Page not found"
msgstr "ページãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“"
+msgid "Page settings"
+msgstr ""
+
msgid "Page was successfully deleted"
msgstr "ページã¯æ­£å¸¸ã«å‰Šé™¤ã•ã‚Œã¾ã—ãŸ"
@@ -17786,8 +18411,8 @@ msgstr "エピックリンクã®è²¼ã‚Šä»˜ã‘"
msgid "Paste issue link"
msgstr "課題リンクã®è²¼ã‚Šä»˜ã‘"
-msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Don't use your private SSH key."
-msgstr "ã‚ãªãŸã® SSH 公開éµã‚’貼り付ã‘ã¾ã™ã€‚ã“ã®éµã¯é€šå¸¸ã€ãƒ•ã‚¡ã‚¤ãƒ«~/.ssh/id_ed25519.pub' ã¾ãŸã¯ '~/.ssh/id_rsa.pub' 内ã«ã‚ã‚Šã€'ssh-ed25519' ã¾ãŸã¯ 'ssh-rsa' ã¨ã„ã†æ–‡å­—列ã‹ã‚‰å§‹ã¾ã‚Šã¾ã™ã€‚SSH ã®ç§˜å¯†éµã‚’使用ã—ãªã„よã†ã«ã—ã¦ãã ã•ã„。"
+msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Do not paste your private SSH key, as that can compromise your identity."
+msgstr ""
msgid "Patch to apply"
msgstr ""
@@ -17813,6 +18438,9 @@ msgstr "一時åœæ­¢ã—ãŸãƒ©ãƒ³ãƒŠãƒ¼ã¯æ–°ã—ã„ジョブをå—ã‘入れãªã„
msgid "Pending"
msgstr "ä¿ç•™ä¸­"
+msgid "Pending comments"
+msgstr ""
+
msgid "People without permission will never get a notification and won't be able to comment."
msgstr "権é™ã®ãªã„ユーザーã¯ä¸€åˆ‡é€šçŸ¥ã‚’å—ã‘ã‚‹ã“ã¨ãŒãªãã€ã¾ãŸã‚³ãƒ¡ãƒ³ãƒˆã™ã‚‹ã“ã¨ã‚‚ã§ãã¾ã›ã‚“。"
@@ -18011,6 +18639,9 @@ msgstr ""
msgid "Pipelines|Build with confidence"
msgstr "ä¿¡é ¼ã®ã‚るビルド"
+msgid "Pipelines|By revoking a trigger you will break any processes making use of it. Are you sure?"
+msgstr ""
+
msgid "Pipelines|CI Lint"
msgstr "CI Lint"
@@ -18023,6 +18654,15 @@ msgstr "Runner ã®ã‚­ãƒ£ãƒƒã‚·ãƒ¥ã‚’削除"
msgid "Pipelines|Continuous Integration can help catch bugs by running your tests automatically, while Continuous Deployment can help you deliver code to your product environment."
msgstr "継続的インテグレーションã¯ã€ãƒ†ã‚¹ãƒˆã‚’自動的ã«å®Ÿè¡Œã™ã‚‹ã“ã¨ã§ãƒã‚°ã‚’検出ã—ã€ç¶™ç¶šçš„デプロイã¯æœ¬ç•ªç’°å¢ƒã«ã‚³ãƒ¼ãƒ‰ã‚’é…ç½®ã™ã‚‹ã®ã«å½¹ç«‹ã¡ã¾ã™ã€‚"
+msgid "Pipelines|Copy trigger token"
+msgstr ""
+
+msgid "Pipelines|Description"
+msgstr ""
+
+msgid "Pipelines|Edit"
+msgstr ""
+
msgid "Pipelines|Get started with Pipelines"
msgstr "パイプラインã®åˆ©ç”¨ã‚’開始ã™ã‚‹"
@@ -18038,15 +18678,27 @@ msgstr ""
msgid "Pipelines|It is recommended the code is reviewed thoroughly before running this pipeline with the parent project's CI resource."
msgstr ""
+msgid "Pipelines|Last Used"
+msgstr ""
+
msgid "Pipelines|Loading Pipelines"
msgstr "パイプラインを読ã¿è¾¼ã¿ä¸­"
msgid "Pipelines|More Information"
msgstr ""
+msgid "Pipelines|No triggers have been created yet. Add one using the form above."
+msgstr ""
+
+msgid "Pipelines|Owner"
+msgstr ""
+
msgid "Pipelines|Project cache successfully reset."
msgstr "プロジェクトã®ã‚­ãƒ£ãƒƒã‚·ãƒ¥ã‚’正常ã«ãƒªã‚»ãƒƒãƒˆã—ã¾ã—ãŸã€‚"
+msgid "Pipelines|Revoke"
+msgstr ""
+
msgid "Pipelines|Run Pipeline"
msgstr "パイプライン実行"
@@ -18071,6 +18723,15 @@ msgstr ""
msgid "Pipelines|This project is not currently set up to run pipelines."
msgstr "ã“ã®ãƒ—ロジェクトã¯ç¾åœ¨ãƒ‘イプラインを実行ã™ã‚‹ã‚ˆã†ã«è¨­å®šã•ã‚Œã¦ã„ã¾ã›ã‚“。"
+msgid "Pipelines|Token"
+msgstr ""
+
+msgid "Pipelines|Trigger user has insufficient permissions to project"
+msgstr ""
+
+msgid "Pipelines|invalid"
+msgstr ""
+
msgid "Pipelines|parent"
msgstr "親"
@@ -18282,7 +18943,7 @@ msgid "Please create a username with only alphanumeric characters."
msgstr "ユーザーåã¯è‹±æ•°å­—ã®ã¿ã§ä½œæˆã—ã¦ãã ã•ã„。"
msgid "Please create an index before enabling indexing"
-msgstr ""
+msgstr "インデックスを有効ã«ã™ã‚‹å‰ã«ã‚¤ãƒ³ãƒ‡ãƒƒã‚¯ã‚¹ã‚’作æˆã—ã¦ãã ã•ã„"
msgid "Please enable and migrate to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}"
msgstr "セキュリティ上ã®å•é¡Œå›žé¿ã¨ãƒ‡ãƒ¼ã‚¿æ•´åˆæ€§ã®ç¢ºä¿ã®ãŸã‚ã€ãƒãƒƒã‚·ãƒ¥åŒ–ã•ã‚ŒãŸã‚¹ãƒˆãƒ¬ãƒ¼ã‚¸ã‚’有効化ã—ã€ç§»è¡Œã—ã¦ãã ã•ã„。 %{migrate_link}"
@@ -18329,11 +18990,11 @@ msgstr "有効ãªãƒ¡ãƒ¼ãƒ«ã‚¢ãƒ‰ãƒ¬ã‚¹ã‚’入力ã—ã¦ãã ã•ã„"
msgid "Please provide attributes to update"
msgstr ""
-msgid "Please refer to %{docs_url}"
+msgid "Please reach out if you have any questions and we'll be happy to assist."
msgstr ""
-msgid "Please retype the email address."
-msgstr "メールアドレスをå†åº¦å…¥åŠ›ã—ã¦ãã ã•ã„。"
+msgid "Please refer to %{docs_url}"
+msgstr ""
msgid "Please select"
msgstr "é¸æŠžã—ã¦ãã ã•ã„"
@@ -18362,6 +19023,9 @@ msgstr "çµæžœã‚’表示ã™ã‚‹ã«ã¯ã€å°‘ãªãã¨ã‚‚1ã¤ã®ãƒ•ã‚£ãƒ«ã‚¿ãƒ¼ã‚’é
msgid "Please set a new password before proceeding."
msgstr "続ã‘ã‚‹å‰ã«æ–°ã—ã„パスワードを設定ã—ã¦ãã ã•ã„。"
+msgid "Please share your feedback about %{featureName} %{linkStart}in this issue%{linkEnd} to help us improve the experience."
+msgstr ""
+
msgid "Please solve the reCAPTCHA"
msgstr "reCAPTCHA を解決ã—ã¦ãã ã•ã„"
@@ -18665,6 +19329,9 @@ msgstr "ã‚ãªãŸã¯ %{yourAccount} ã¨ã€ã‚ãªãŸã®ã‚¢ã‚«ã‚¦ãƒ³ãƒˆã«ãƒªãƒ³ã‚
msgid "Profiles| You are going to change the username %{currentUsernameBold} to %{newUsernameBold}. Profile and projects will be redirected to the %{newUsername} namespace but this redirect will expire once the %{currentUsername} namespace is registered by another user or group. Please update your Git repository remotes as soon as possible."
msgstr "ユーザåã‚’ %{currentUsernameBold} ã‹ã‚‰ %{newUsernameBold} ã«å¤‰æ›´ã—よã†ã¨ã—ã¦ã„ã¾ã™ã€‚プロファイルã¨ãƒ—ロジェクト㯠%{newUsername} åå‰ç©ºé–“ã«ãƒªãƒ€ã‚¤ãƒ¬ã‚¯ãƒˆã•ã‚Œã¾ã™ã€‚ã—ã‹ã—〠%{currentUsername} åå‰ç©ºé–“ãŒåˆ¥ã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ã¾ãŸã¯ã‚°ãƒ«ãƒ¼ãƒ—ã«ã‚ˆã£ã¦ç™»éŒ²ã•ã‚Œã‚‹ã¨ã€ã“ã®ãƒªãƒ€ã‚¤ãƒ¬ã‚¯ãƒˆã¯æœŸé™åˆ‡ã‚Œã«ãªã‚Šã¾ã™ã€‚ Gitリãƒã‚¸ãƒˆãƒªã®ãƒªãƒ¢ãƒ¼ãƒˆã‚’ã§ãã‚‹ã ã‘æ—©ãæ›´æ–°ã—ã¦ãã ã•ã„。"
+msgid "Profiles|%{provider} Active"
+msgstr ""
+
msgid "Profiles|@username"
msgstr "@username"
@@ -18716,8 +19383,8 @@ msgstr "次ã®ã‚µãƒ¼ãƒ“スã®ä¸­ã‹ã‚‰ä¸€ã¤ã‚’é¸ã‚“ã§ã‚µã‚¤ãƒ³ã‚¤ãƒ³ã‚’開始
msgid "Profiles|Commit email"
msgstr "コミットメール"
-msgid "Profiles|Connect"
-msgstr "接続"
+msgid "Profiles|Connect %{provider}"
+msgstr ""
msgid "Profiles|Connected Accounts"
msgstr "接続ã—ãŸã‚¢ã‚«ã‚¦ãƒ³ãƒˆ"
@@ -18740,6 +19407,9 @@ msgstr "アカウントを削除ã™ã‚‹ã¨æ¬¡ã®ã‚ˆã†ãªå½±éŸ¿ãŒã‚ã‚Šã¾ã™:"
msgid "Profiles|Disconnect"
msgstr "接続断"
+msgid "Profiles|Disconnect %{provider}"
+msgstr ""
+
msgid "Profiles|Do not show on profile"
msgstr "プロフィールã«è¡¨ç¤ºã—ãªã„"
@@ -18764,7 +19434,7 @@ msgstr "フィードトークンを正常ã«ãƒªã‚»ãƒƒãƒˆã§ãã¾ã—ãŸ"
msgid "Profiles|Full name"
msgstr "フルãƒãƒ¼ãƒ "
-msgid "Profiles|Give your individual key a title. This will be publically visible."
+msgid "Profiles|Give your individual key a title."
msgstr ""
msgid "Profiles|Include private contributions on my profile"
@@ -18854,8 +19524,8 @@ msgstr "ã‚ãªãŸã®åå‰ã‚’æ›´æ–°ã™ã‚‹æ©Ÿèƒ½ã¯ã€ç®¡ç†è€…ã«ã‚ˆã£ã¦ç„¡åŠ¹
msgid "Profiles|The maximum file size allowed is 200KB."
msgstr "許å¯ã•ã‚Œã‚‹æœ€å¤§ãƒ•ã‚¡ã‚¤ãƒ«ã‚µã‚¤ã‚ºã¯200KBã§ã™ã€‚"
-msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it?"
-msgstr "ã“れ㯠SSH ã®å…¬é–‹éµã§ã¯ãªã„よã†ã§ã™ãŒã€æœ¬å½“ã«è¿½åŠ ã—ã¦ã‚‚よã‚ã—ã„ã§ã™ã‹ï¼Ÿ"
+msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it? It will be publicly visible."
+msgstr ""
msgid "Profiles|This email will be displayed on your public profile"
msgstr "ã“ã®ãƒ¡ãƒ¼ãƒ«ã‚’ã‚ãªãŸã®å…¬é–‹ãƒ—ロフィールã«è¡¨ç¤ºã—ã¾ã™"
@@ -18929,6 +19599,9 @@ msgstr "ã“ã“ã«ã‚ãªãŸã®ã‚¢ãƒã‚¿ãƒ¼ã‚’アップロードã™ã‚‹ã‹ã€ %{gra
msgid "Profiles|You don't have access to delete this user."
msgstr "ã“ã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ã‚’削除ã™ã‚‹æ¨©é™ãŒã‚ã‚Šã¾ã›ã‚“"
+msgid "Profiles|You must transfer ownership or delete groups you are an owner of before you can delete your account"
+msgstr ""
+
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr "アカウントを削除ã™ã‚‹å‰ã«ã“れらã®ã‚°ãƒ«ãƒ¼ãƒ—を削除ã€ã¾ãŸã¯æ‰€æœ‰æ¨©ã‚’譲渡ã—ã¦ãã ã•ã„。"
@@ -19517,6 +20190,9 @@ msgstr "Android"
msgid "ProjectTemplates|GitLab Cluster Management"
msgstr ""
+msgid "ProjectTemplates|Gitpod/Spring Petclinic"
+msgstr ""
+
msgid "ProjectTemplates|Go Micro"
msgstr "Go Micro"
@@ -20126,6 +20802,9 @@ msgstr ""
msgid "Publish to status page"
msgstr ""
+msgid "Published"
+msgstr ""
+
msgid "Published on status page"
msgstr ""
@@ -20243,9 +20922,15 @@ msgstr "クイックアクションã¯èª²é¡Œã®èª¬æ˜Žã¨ã‚³ãƒ¡ãƒ³ãƒˆæ¬„ã§ä½¿ç”¨
msgid "Quick range"
msgstr "クイックレンジ"
+msgid "Quickly and easily edit multiple files in your project."
+msgstr ""
+
msgid "README"
msgstr "README"
+msgid "Rails"
+msgstr ""
+
msgid "Rake Tasks Help"
msgstr ""
@@ -20364,12 +21049,15 @@ msgstr "登録 / サインイン"
msgid "Register Two-Factor Authenticator"
msgstr "2è¦ç´ èªè¨¼ã®ç™»éŒ²"
-msgid "Register U2F device"
-msgstr "U2F デãƒã‚¤ã‚¹ã‚’登録ã™ã‚‹"
-
msgid "Register Universal Two-Factor (U2F) Device"
msgstr "ユニãƒãƒ¼ã‚µãƒ«ãª2è¦ç´ èªè¨¼ãƒ‡ãƒã‚¤ã‚¹ã‚’登録ã™ã‚‹"
+msgid "Register WebAuthn Device"
+msgstr ""
+
+msgid "Register device"
+msgstr ""
+
msgid "Register for GitLab"
msgstr "GitLab ã«ç™»éŒ²ã™ã‚‹"
@@ -20379,9 +21067,6 @@ msgstr "今ã™ã登録"
msgid "Register with two-factor app"
msgstr "2è¦ç´ èªè¨¼ã‚¢ãƒ—リã§ç™»éŒ²"
-msgid "Registration"
-msgstr "登録"
-
msgid "Registration|Checkout"
msgstr ""
@@ -20497,9 +21182,6 @@ msgstr "リリースã®è©³ç´°ã‚’å–得中ã«å•é¡ŒãŒç™ºç”Ÿã—ã¾ã—ãŸ"
msgid "Release|Something went wrong while saving the release details"
msgstr "リリースã®è©³ç´°ã‚’ä¿å­˜ä¸­ã«å•é¡ŒãŒç™ºç”Ÿã—ã¾ã—ãŸ"
-msgid "Remediated: needs review"
-msgstr ""
-
msgid "Remediations"
msgstr ""
@@ -20605,6 +21287,9 @@ msgstr "プライマリノードã®å‰Šé™¤"
msgid "Remove priority"
msgstr "優先度を削除"
+msgid "Remove report"
+msgstr ""
+
msgid "Remove secondary node"
msgstr "セカンダリノードã®å‰Šé™¤"
@@ -20617,6 +21302,12 @@ msgstr "ステージã®å‰Šé™¤"
msgid "Remove time estimate"
msgstr "見ç©æ™‚間を削除"
+msgid "Remove user & report"
+msgstr ""
+
+msgid "Remove user from group"
+msgstr ""
+
msgid "Removed"
msgstr "除去ã—ã¾ã—ãŸ"
@@ -20698,9 +21389,6 @@ msgstr "期日を削除."
msgid "Removes time estimate."
msgstr "見ç©æ™‚間を削除."
-msgid "Removing license…"
-msgstr "ライセンスã®å‰Šé™¤ä¸­..."
-
msgid "Removing this group also removes all child projects, including archived projects, and their resources."
msgstr ""
@@ -20785,6 +21473,9 @@ msgstr "管ç†è€…ã«ä¸æ­£åˆ©ç”¨ã‚’報告"
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
+msgid "Reported by %{reporter}"
+msgstr ""
+
msgid "Reporting"
msgstr "レãƒãƒ¼ãƒˆ"
@@ -20870,6 +21561,27 @@ msgstr "テストçµæžœã«å¤‰æ›´ã‚ã‚Šã¾ã›ã‚“。"
msgid "Repositories"
msgstr ""
+msgid "Repositories Analytics"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download Historic Test Coverage Data"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download historic test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Historic Test Coverage Data is available in raw format (.csv) for further analysis."
+msgstr ""
+
+msgid "RepositoriesAnalytics|Test Code Coverage"
+msgstr ""
+
+msgid "RepositoriesAnalytics|There was an error fetching the projects."
+msgstr ""
+
msgid "Repository"
msgstr "リãƒã‚¸ãƒˆãƒª"
@@ -20948,9 +21660,15 @@ msgstr ""
msgid "Request parameter %{param} is missing."
msgstr "必須パラメーター %{param} ãŒã‚ã‚Šã¾ã›ã‚“。"
+msgid "Request review from"
+msgstr ""
+
msgid "Request to link SAML account must be authorized"
msgstr "SAMLアカウントをリンクã™ã‚‹ãƒªã‚¯ã‚¨ã‚¹ãƒˆã¯æ‰¿èªã•ã‚Œã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™"
+msgid "Requested"
+msgstr ""
+
msgid "Requested %{time_ago}"
msgstr "%{time_ago} ã«ãƒªã‚¯ã‚¨ã‚¹ãƒˆ"
@@ -20969,6 +21687,9 @@ msgstr "プロファイルã®è¦æ±‚"
msgid "Requests to these domain(s)/address(es) on the local network will be allowed when local requests from hooks and services are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 or 127.0.0.0/28 are supported. Domain wildcards are not supported currently. Use comma, semicolon, or newline to separate multiple entries. The allowlist can hold a maximum of 1000 entries. Domains should use IDNA encoding. Ex: example.com, 192.168.1.1, 127.0.0.0/28, xn--itlab-j1a.com."
msgstr ""
+msgid "Require admin approval for new sign-ups"
+msgstr ""
+
msgid "Require all users in this group to setup Two-factor authentication"
msgstr "ã“ã®ã‚°ãƒ«ãƒ¼ãƒ—内ã®ã™ã¹ã¦ã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ã«2è¦ç´ èªè¨¼ã®ã‚»ãƒƒãƒˆã‚¢ãƒƒãƒ—ã‚’è¦æ±‚ã™ã‚‹"
@@ -21094,9 +21815,6 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr "%{name} ã«ã‚ˆã£ã¦è§£æ±º"
-msgid "Resolved by %{resolvedByName}"
-msgstr "%{resolvedByName} ã«ã‚ˆã£ã¦è§£æ±º"
-
msgid "Resolves IP addresses once and uses them to submit requests"
msgstr "IPアドレスを一度解決ã—ã¦ã€ãれを使ã£ã¦ãƒªã‚¯ã‚¨ã‚¹ãƒˆã‚’é€ä¿¡ã—ã¾ã™"
@@ -21207,7 +21925,7 @@ msgid "Review the process for configuring service providers in your identity pro
msgstr "ã‚ãªãŸã® ID プロãƒã‚¤ãƒ€ãƒ¼ã®ã‚µãƒ¼ãƒ“スプロãƒã‚¤ãƒ€ãƒ¼ã‚’構æˆã™ã‚‹ãŸã‚ã®ãƒ—ロセスを確èªã—ã¾ã™ã€‚ ã“ã®ä¾‹ã§ã¯ã€GitLab ã¯ã€Œã‚µãƒ¼ãƒ“スプロãƒã‚¤ãƒ€ãƒ¼ã€ã¾ãŸã¯ã€Œè¨¼æ˜Žæ›¸åˆ©ç”¨è€…ã€ã€‚"
msgid "Review time"
-msgstr ""
+msgstr "レビュー時間"
msgid "Review time is defined as the time it takes from first comment until merged."
msgstr ""
@@ -21215,6 +21933,13 @@ msgstr ""
msgid "ReviewApp|Enable Review App"
msgstr ""
+msgid "Reviewer"
+msgid_plural "%d Reviewers"
+msgstr[0] ""
+
+msgid "Reviewer(s)"
+msgstr ""
+
msgid "Reviewing"
msgstr "レビュー中"
@@ -21254,6 +21979,9 @@ msgstr "ロールãƒãƒƒã‚¯"
msgid "Rook"
msgstr "Rook"
+msgid "Ruby"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -21332,6 +22060,63 @@ msgstr "ç¾åœ¨ã‚ªãƒ³ãƒ©ã‚¤ãƒ³ã®Runner: %{active_runners_count}"
msgid "Runners page."
msgstr "Runner ã®ãƒšãƒ¼ã‚¸ã€‚"
+msgid "Runners|Active"
+msgstr ""
+
+msgid "Runners|Architecture"
+msgstr ""
+
+msgid "Runners|Can run untagged jobs"
+msgstr ""
+
+msgid "Runners|Description"
+msgstr ""
+
+msgid "Runners|Group"
+msgstr ""
+
+msgid "Runners|IP Address"
+msgstr ""
+
+msgid "Runners|Last contact"
+msgstr ""
+
+msgid "Runners|Locked to this project"
+msgstr ""
+
+msgid "Runners|Maximum job timeout"
+msgstr ""
+
+msgid "Runners|Name"
+msgstr ""
+
+msgid "Runners|Platform"
+msgstr ""
+
+msgid "Runners|Property Name"
+msgstr ""
+
+msgid "Runners|Protected"
+msgstr ""
+
+msgid "Runners|Revision"
+msgstr ""
+
+msgid "Runners|Shared"
+msgstr ""
+
+msgid "Runners|Specific"
+msgstr ""
+
+msgid "Runners|Tags"
+msgstr ""
+
+msgid "Runners|Value"
+msgstr ""
+
+msgid "Runners|Version"
+msgstr ""
+
msgid "Runners|You have used %{quotaUsed} out of %{quotaLimit} of your shared Runners pipeline minutes."
msgstr "Runners |共有ランナーパイプラインã®%{quotaLimit} ã®ã†ã¡%{quotaUsed} を使用ã—ã¾ã—ãŸã€‚"
@@ -21344,6 +22129,9 @@ msgstr "実行中…"
msgid "Runs a number of housekeeping tasks within the current repository, such as compressing file revisions and removing unreachable objects."
msgstr "ç¾åœ¨ã®ãƒªãƒã‚¸ãƒˆãƒªå†…ã§ã€ãƒ•ã‚¡ã‚¤ãƒ«ãƒªãƒ“ジョンã®åœ§ç¸®ã‚„アクセスä¸å¯èƒ½ãªã‚ªãƒ–ジェクトã®é™¤åŽ»ã¨ã„ã£ãŸã€ã„ãã¤ã‹ã®ãƒã‚¦ã‚¹ã‚­ãƒ¼ãƒ”ングを実行ã—ã¾ã™ã€‚"
+msgid "SAML"
+msgstr ""
+
msgid "SAML SSO"
msgstr "SAML SSO"
@@ -21395,6 +22183,9 @@ msgstr "土曜日"
msgid "Save"
msgstr "ä¿å­˜"
+msgid "Save %{name} size limits"
+msgstr ""
+
msgid "Save Changes"
msgstr "変更をä¿å­˜"
@@ -21425,9 +22216,6 @@ msgstr "パイプラインスケジュールをä¿å­˜"
msgid "Save space and find tags in the Container Registry more easily. Enable the cleanup policy to remove stale tags and keep only the ones you need."
msgstr ""
-msgid "Save template"
-msgstr "テンプレートをä¿å­˜"
-
msgid "Save variables"
msgstr "変数をä¿å­˜ã™ã‚‹"
@@ -21470,9 +22258,6 @@ msgstr "パイプラインスケジューリング"
msgid "Scope"
msgstr "スコープ"
-msgid "Scope not supported with disabled 'users_search' feature!"
-msgstr "スコープã¯ã€ç„¡åŠ¹ãª 'users_search' 機能ã§ã‚µãƒãƒ¼ãƒˆã•ã‚Œã¦ã„ã¾ã›ã‚“。"
-
msgid "Scoped issue boards"
msgstr "スコープ付課題ボード"
@@ -21599,9 +22384,6 @@ msgstr "プロジェクトを検索..."
msgid "Search requirements"
msgstr ""
-msgid "Search results…"
-msgstr ""
-
msgid "Search users"
msgstr "ユーザーを検索"
@@ -21671,6 +22453,10 @@ msgid "SearchResults|commit"
msgid_plural "SearchResults|commits"
msgstr[0] "コミット"
+msgid "SearchResults|epic"
+msgid_plural "SearchResults|epics"
+msgstr[0] ""
+
msgid "SearchResults|issue"
msgid_plural "SearchResults|issues"
msgstr[0] "課題"
@@ -21708,10 +22494,10 @@ msgstr "シートリンク"
msgid "Seat Link is disabled, and cannot be configured through this form."
msgstr ""
-msgid "Seats currently in use"
-msgstr "ç¾åœ¨ä½¿ç”¨ä¸­ã®ã‚·ãƒ¼ãƒˆ"
+msgid "Seats usage data as of %{last_enqueue_time}"
+msgstr ""
-msgid "Seats in license"
+msgid "Seats usage data is updated every day at 12:00pm UTC"
msgstr ""
msgid "Secondary"
@@ -21765,6 +22551,9 @@ msgstr ""
msgid "SecurityConfiguration|Available for on-demand DAST"
msgstr ""
+msgid "SecurityConfiguration|By default, all analyzers are applied in order to cover all languages across your project, and only run if the language is detected in the Merge Request."
+msgstr ""
+
msgid "SecurityConfiguration|Configure"
msgstr ""
@@ -21795,16 +22584,19 @@ msgstr " %{featureName} ã®æ©Ÿèƒ½æ–‡æ›¸"
msgid "SecurityConfiguration|Manage"
msgstr ""
+msgid "SecurityConfiguration|More information"
+msgstr ""
+
msgid "SecurityConfiguration|Not enabled"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|Security Control"
+msgid "SecurityConfiguration|SAST Configuration"
msgstr ""
-msgid "SecurityConfiguration|See documentation"
+msgid "SecurityConfiguration|Security Control"
msgstr ""
msgid "SecurityConfiguration|Status"
@@ -21816,6 +22608,9 @@ msgstr ""
msgid "SecurityConfiguration|Using custom settings. You won't receive automatic updates on this variable. %{anchorStart}Restore to default%{anchorEnd}"
msgstr ""
+msgid "SecurityConfiguration|View history"
+msgstr ""
+
msgid "SecurityConfiguration|You can quickly enable all security scanning tools by enabling %{linkStart}Auto DevOps%{linkEnd}."
msgstr ""
@@ -21894,9 +22689,6 @@ msgstr ""
msgid "SecurityReports|Learn more about setting up your dashboard"
msgstr "ダッシュボードã®è¨­å®šã®è©³ç´°"
-msgid "SecurityReports|Load more vulnerabilities"
-msgstr ""
-
msgid "SecurityReports|Monitor vulnerabilities in your code"
msgstr ""
@@ -22176,7 +22968,7 @@ msgstr ""
msgid "Select status"
msgstr ""
-msgid "Select strategy activation method"
+msgid "Select strategy activation method."
msgstr ""
msgid "Select subscription"
@@ -22191,7 +22983,7 @@ msgstr "ã“ã®ãƒ—ロジェクトã®ãƒ‡ãƒ•ã‚©ãƒ«ãƒˆã¨ã—ã¦è¨­å®šã™ã‚‹ãƒ–ラン
msgid "Select the custom project template source group."
msgstr "カスタムã®ãƒ—ロジェクトテンプレートã®ã‚°ãƒ«ãƒ¼ãƒ—ã‚’é¸æŠžã—ã¾ã™ã€‚"
-msgid "Select timeframe"
+msgid "Select the environment scope for this feature flag."
msgstr ""
msgid "Select timezone"
@@ -22306,7 +23098,7 @@ msgid "Serverless domain"
msgstr "Severlessドメイン"
msgid "ServerlessDetails|Function invocation metrics require Prometheus to be installed first."
-msgstr "関数呼ã³å‡ºã—メトリクスã§ã¯ã€ Prometheus を最åˆã«ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚"
+msgstr "Function呼ã³å‡ºã—メトリクスã§ã¯ã€ Prometheus を最åˆã«ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚"
msgid "ServerlessDetails|Install Prometheus"
msgstr "Prometheus ã®ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«"
@@ -22357,7 +23149,7 @@ msgid "Serverless|Learn more about Serverless"
msgstr "Serverless ã«ã¤ã„ã¦"
msgid "Serverless|No functions available"
-msgstr "利用å¯èƒ½ãªæ©Ÿèƒ½ã¯ã‚ã‚Šã¾ã›ã‚“"
+msgstr "利用å¯èƒ½ãªfunctionã¯ã‚ã‚Šã¾ã›ã‚“"
msgid "Serverless|Sign up for First Look"
msgstr ""
@@ -22366,10 +23158,10 @@ msgid "Serverless|The deploy job has not finished."
msgstr "デプロイジョブãŒå®Œäº†ã—ã¦ã„ã¾ã›ã‚“。"
msgid "Serverless|The functions listed in the %{startTag}serverless.yml%{endTag} file don't match the namespace of your cluster."
-msgstr "%{startTag}serverless.yml%{endTag} ファイルã«ãƒªã‚¹ãƒˆã•ã‚Œã¦ã„る関数・機能ãŒã‚¯ãƒ©ã‚¹ã‚¿ãƒ¼ã®åå‰ç©ºé–“ã¨ä¸€è‡´ã—ã¾ã›ã‚“。"
+msgstr "%{startTag}serverless.yml%{endTag} ファイルã«ãƒªã‚¹ãƒˆã•ã‚Œã¦ã„ã‚‹FunctionãŒã‚¯ãƒ©ã‚¹ã‚¿ãƒ¼ã®åå‰ç©ºé–“ã¨ä¸€è‡´ã—ã¾ã›ã‚“。"
msgid "Serverless|There is currently no function data available from Knative. This could be for a variety of reasons including:"
-msgstr "ç¾åœ¨ Knative ã‹ã‚‰å…¥æ‰‹å¯èƒ½ãªæ©Ÿèƒ½ãƒ‡ãƒ¼ã‚¿ã¯ã‚ã‚Šã¾ã›ã‚“。ã“ã‚Œã¯ã„ãã¤ã‹ç†ç”±ãŒè€ƒãˆã‚‰ã‚Œã¾ã™:"
+msgstr "ç¾åœ¨ Knative ã‹ã‚‰å…¥æ‰‹å¯èƒ½ãªfunctionデータã¯ã‚ã‚Šã¾ã›ã‚“。ã“ã‚Œã¯ã„ãã¤ã‹ç†ç”±ãŒè€ƒãˆã‚‰ã‚Œã¾ã™:"
msgid "Serverless|We are continually striving to improve our Serverless functionality. As a Knative user, we would love to hear how we can make this experience better for you. Sign up for GitLab First Look today and we will be in touch shortly."
msgstr ""
@@ -22440,6 +23232,9 @@ msgstr "インスタンス全体レベルã®ãƒ†ãƒ³ãƒ—レートリãƒã‚¸ãƒˆãƒªã‚’
msgid "Set iteration"
msgstr ""
+msgid "Set limit to 0 to allow any file size."
+msgstr ""
+
msgid "Set max session time for web terminal."
msgstr "ウェブターミナルã®æœ€å¤§ã‚»ãƒƒã‚·ãƒ§ãƒ³ã‚¿ã‚¤ãƒ ã‚’設定ã™ã‚‹ã€‚"
@@ -22518,11 +23313,14 @@ msgstr "%{type} ã® Runner ã®è‡ªå‹•ã‚»ãƒƒãƒˆã‚¢ãƒƒãƒ—"
msgid "Set up a %{type} Runner manually"
msgstr "%{type} ã®Runnerã®ãƒžãƒ‹ãƒ¥ã‚¢ãƒ«ã‚»ãƒƒãƒˆã‚¢ãƒƒãƒ—"
+msgid "Set up a hardware device as a second factor to sign in."
+msgstr ""
+
msgid "Set up assertions/attributes/claims (email, first_name, last_name) and NameID according to %{docsLinkStart}the documentation %{icon}%{docsLinkEnd}"
msgstr "%{docsLinkStart}文書%{icon}%{docsLinkEnd}ã«å¾“ã£ã¦ã€ã‚¢ã‚µãƒ¼ã‚·ãƒ§ãƒ³/属性/資格情報 (email, first_name, last_name)ãŠã‚ˆã³NameIDを設定ã—ã¦ãã ã•ã„"
-msgid "Set up new U2F device"
-msgstr "æ–°ã—ã„U2Fデãƒã‚¤ã‚¹ã‚’セットアップ"
+msgid "Set up new device"
+msgstr ""
msgid "Set up new password"
msgstr "æ–°ã—ã„パスワードを設定"
@@ -22590,6 +23388,9 @@ msgstr "見ç©ã‚‚り時間を %{time_estimate} ã«è¨­å®šã€‚"
msgid "Sets weight to %{weight}."
msgstr "ウェイトを %{weight} ã«è¨­å®š"
+msgid "Setting this to 0 means using the system default timeout value."
+msgstr ""
+
msgid "Settings"
msgstr "設定"
@@ -22605,6 +23406,15 @@ msgstr ""
msgid "Severity"
msgstr ""
+msgid "SeverityWidget|Severity"
+msgstr ""
+
+msgid "SeverityWidget|Severity: %{severity}"
+msgstr ""
+
+msgid "SeverityWidget|There was an error while updating severity."
+msgstr ""
+
msgid "Shards (%{shards})"
msgstr ""
@@ -22650,6 +23460,9 @@ msgstr "å…¨ã¦ã®ãƒ¡ãƒ³ãƒãƒ¼ã‚’表示"
msgid "Show all requirements."
msgstr ""
+msgid "Show all test cases."
+msgstr ""
+
msgid "Show archived projects"
msgstr "アーカイブã—ãŸãƒ—ロジェクトを表示"
@@ -22662,6 +23475,9 @@ msgstr "コマンドを表示"
msgid "Show comments"
msgstr "コメントã®è¡¨ç¤º"
+msgid "Show comments on this file"
+msgstr ""
+
msgid "Show comments only"
msgstr "コメントã®ã¿è¡¨ç¤º"
@@ -22707,6 +23523,12 @@ msgstr "親ページを表示"
msgid "Show parent subgroups"
msgstr "親ã®ã‚µãƒ–グループを表示"
+msgid "Show the Closed list"
+msgstr ""
+
+msgid "Show the Open list"
+msgstr ""
+
msgid "Show whitespace changes"
msgstr "空白 (éžè¡¨ç¤ºæ–‡å­—) ã®å¤‰æ›´ã‚’表示ã™ã‚‹"
@@ -22748,9 +23570,6 @@ msgstr "並列"
msgid "Sidebar|Assign health status"
msgstr ""
-msgid "Sidebar|Change weight"
-msgstr "ウェイトを変更"
-
msgid "Sidebar|Health status"
msgstr ""
@@ -22934,6 +23753,9 @@ msgstr "表示ã™ã‚‹ã‚¹ãƒ‹ãƒšãƒƒãƒˆã¯ã‚ã‚Šã¾ã›ã‚“。"
msgid "Snippets|Add another file %{num}/%{total}"
msgstr ""
+msgid "Snippets|Authored %{time_ago} by %{author}"
+msgstr ""
+
msgid "Snippets|Delete file"
msgstr ""
@@ -22961,6 +23783,9 @@ msgstr "Snowplow"
msgid "Solution"
msgstr ""
+msgid "Some changes are not shown"
+msgstr ""
+
msgid "Some child epics may be hidden due to applied filters"
msgstr ""
@@ -23327,6 +24152,12 @@ msgstr "ソース"
msgid "Source (branch or tag)"
msgstr "ソース (ブランãƒã‹ã‚¿ã‚°)"
+msgid "Source Branch"
+msgstr ""
+
+msgid "Source branch: %{source_branch_open}%{source_branch}%{source_branch_close}"
+msgstr ""
+
msgid "Source code"
msgstr "ソースコード"
@@ -23492,9 +24323,6 @@ msgstr "レビューã®é–‹å§‹"
msgid "Start and due date"
msgstr "開始日ã¨çµ‚了日"
-msgid "Start by choosing a group to see how your team is spending time. You can then drill down to the project level."
-msgstr "グループをé¸æŠžã—ã¦ã€ãƒãƒ¼ãƒ ãŒã©ã®ã‚ˆã†ã«æ™‚間を費やã—ã¦ã„ã‚‹ã‹ã‚’確èªã™ã‚‹ã¨ã“ã‚ã‹ã‚‰å§‹ã‚ã¾ã—ょã†ã€‚ãã®å¾Œã€ãƒ—ロジェクトレベルã«ãƒ‰ãƒªãƒ«ãƒ€ã‚¦ãƒ³ã—ã¾ã™ã€‚"
-
msgid "Start by choosing a group to start exploring the merge requests in that group. You can then proceed to filter by projects, labels, milestones and authors."
msgstr ""
@@ -23576,18 +24404,27 @@ msgstr ""
msgid "StaticSiteEditor|3. Assign a person to review and accept the merge request."
msgstr ""
+msgid "StaticSiteEditor|A link to view the merge request will appear once ready."
+msgstr ""
+
msgid "StaticSiteEditor|An error occurred while submitting your changes."
msgstr ""
msgid "StaticSiteEditor|Branch could not be created."
msgstr ""
+msgid "StaticSiteEditor|Copy update"
+msgstr ""
+
msgid "StaticSiteEditor|Could not commit the content changes."
msgstr ""
msgid "StaticSiteEditor|Could not create merge request."
msgstr ""
+msgid "StaticSiteEditor|Creating your merge request"
+msgstr ""
+
msgid "StaticSiteEditor|Incompatible file content"
msgstr ""
@@ -23609,6 +24446,9 @@ msgstr ""
msgid "StaticSiteEditor|View documentation"
msgstr ""
+msgid "StaticSiteEditor|You can set an assignee to get your changes reviewed and deployed once your merge request is created."
+msgstr ""
+
msgid "StaticSiteEditor|Your merge request has been created"
msgstr ""
@@ -23670,7 +24510,7 @@ msgid "StatusPage|your status page frontend."
msgstr ""
msgid "Stay updated about the performance and health of your environment by configuring Prometheus to monitor your deployments."
-msgstr "Prometheus を設定ã™ã‚‹äº‹ã§ã‚ãªãŸã®ç’°å¢ƒã®ãƒ‘フォーマンスã¨å¥å…¨æ€§ã®æœ€æ–°çŠ¶æ…‹ã‚’å–得出æ¥ã¾ã™ã€‚"
+msgstr "Prometheus を設定ã™ã‚‹äº‹ã§ã‚ãªãŸã®ç’°å¢ƒã®ãƒ‘フォーマンスã¨å¥å…¨æ€§ã®æœ€æ–°çŠ¶æ…‹ã‚’å–å¾—ã§ãã¾ã™ã€‚"
msgid "Still, we recommend keeping a backup saved somewhere. Otherwise, if you ever need it and have lost it, you will need to request GitLab Inc. to send it to you again."
msgstr "ãã‚Œã§ã‚‚ã€ã©ã“ã‹ã«ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—ã‚’å–ã£ã¦ãŠãã“ã¨ã‚’ãŠå‹§ã‚ã—ã¾ã™ã€‚ãã†ã§ãªã‘ã‚Œã°ã€ã‚‚ã—紛失ã—ã¦ã—ã¾ã£ã¦å¿…è¦ã«ãªã£ãŸå ´åˆã¯ã€GitLab Inc. ã«å†é€ä¿¡ã‚’ä¾é ¼ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚"
@@ -23738,15 +24578,15 @@ msgstr ""
msgid "Submit %{humanized_resource_name}"
msgstr ""
-msgid "Submit Changes"
-msgstr ""
-
msgid "Submit a review"
msgstr "レビューをé€ä¿¡"
msgid "Submit as spam"
msgstr "スパムã¨ã—ã¦å ±å‘Š"
+msgid "Submit changes"
+msgstr ""
+
msgid "Submit feedback"
msgstr "フィードãƒãƒƒã‚¯ã‚’é€ä¿¡"
@@ -23900,6 +24740,9 @@ msgstr "éžæœ‰åŠ¹åŒ–ã«æˆåŠŸã—ã¾ã—ãŸ"
msgid "Successfully deleted U2F device."
msgstr "U2Fデãƒã‚¤ã‚¹ã‚’削除ã—ã¾ã—ãŸã€‚"
+msgid "Successfully deleted WebAuthn device."
+msgstr ""
+
msgid "Successfully removed email."
msgstr "メールを削除ã—ã¾ã—ãŸã€‚"
@@ -24218,9 +25061,6 @@ msgstr "テンプレート"
msgid "Template to append to all Service Desk issues"
msgstr "å…¨ã¦ã®ã‚µãƒ¼ãƒ“スデスク課題ã«è¿½åŠ ã™ã‚‹ãƒ†ãƒ³ãƒ—レート"
-msgid "Template was successfully saved."
-msgstr "テンプレートã®ä¿å­˜ã«æˆåŠŸã—ã¾ã—ãŸã€‚"
-
msgid "Templates"
msgstr "テンプレート"
@@ -24296,11 +25136,29 @@ msgid "Test coverage: %d hit"
msgid_plural "Test coverage: %d hits"
msgstr[0] ""
-msgid "Test failed."
-msgstr "テストãŒå¤±æ•—ã—ã¾ã—ãŸã€‚"
+msgid "Test settings"
+msgstr ""
+
+msgid "TestCases|New Test Case"
+msgstr ""
+
+msgid "TestCases|New test case"
+msgstr ""
+
+msgid "TestCases|Search test cases"
+msgstr ""
+
+msgid "TestCases|Something went wrong while creating a test case."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching count of test cases."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching test cases list."
+msgstr ""
-msgid "Test settings and save changes"
-msgstr "設定をテストã—ã¦ã€å¤‰æ›´ã‚’ä¿å­˜ã™ã‚‹"
+msgid "TestCases|Submit test case"
+msgstr ""
msgid "TestHooks|Ensure one of your projects has merge requests."
msgstr "å°‘ãã¨ã‚‚一ã¤ã®ãƒ—ロジェクトã«ãƒžãƒ¼ã‚¸ãƒªã‚¯ã‚¨ã‚¹ãƒˆãŒã‚ã‚‹ã“ã¨ã‚’確èªã—ã¦ãã ã•ã„。"
@@ -24365,6 +25223,9 @@ msgstr "テスト"
msgid "Thank you for signing up for your free trial! You will get additional instructions in your inbox shortly."
msgstr "無料トライアルライセンスã«ãŠç”³ã—è¾¼ã¿ã„ãŸã ãã‚ã‚ŠãŒã¨ã†ã”ã–ã„ã¾ã™ã€‚手順ã¯ç™»éŒ²ã•ã‚ŒãŸãƒ¡ãƒ¼ãƒ«ã‚¢ãƒ‰ãƒ¬ã‚¹ã«é€ä¿¡ã•ã‚Œã¾ã™ã€‚"
+msgid "Thank you for your business."
+msgstr ""
+
msgid "Thank you for your feedback!"
msgstr ""
@@ -24423,9 +25284,6 @@ msgstr ""
msgid "The URL to use for connecting to Elasticsearch. Use a comma-separated list to support clustering (e.g., \"http://localhost:9200, http://localhost:9201\")."
msgstr "Elasticsearchã¸ã®æŽ¥ç¶šã«ä½¿ç”¨ã™ã‚‹URL。クラスタリングをサãƒãƒ¼ãƒˆã™ã‚‹ã«ã¯ã€ã‚³ãƒ³ãƒžåŒºåˆ‡ã‚Šãƒªã‚¹ãƒˆã‚’使用ã—ã¾ã™(例: http://localhost:9200, http://localhost:9201)。"
-msgid "The Web IDE offers advanced syntax highlighting capabilities and more."
-msgstr ""
-
msgid "The X509 Certificate to use when mutual TLS is required to communicate with the external authorization service. If left blank, the server certificate is still validated when accessing over HTTPS."
msgstr "外部èªè¨¼ã‚µãƒ¼ãƒ“スã¨ã®é€šä¿¡ã«ç›¸äº’ TLS ãŒå¿…è¦ãªå ´åˆã«ä½¿ç”¨ã™ã‚‹ X509 証明書。空白ã®ã¾ã¾ã«ã™ã‚‹ã¨ã€HTTPS 経由ã§ã‚¢ã‚¯ã‚»ã‚¹ã™ã‚‹ã¨ãã«ã‚µãƒ¼ãƒè¨¼æ˜Žæ›¸ã®æ¤œè¨¼ãŒè¡Œã‚ã‚Œã¾ã™ã€‚"
@@ -24535,6 +25393,9 @@ msgstr "フォークã®ãƒªãƒ¬ãƒ¼ã‚·ãƒ§ãƒ³ãŒå‰Šé™¤ã•ã‚Œã¾ã—ãŸã€‚"
msgid "The form contains the following error:"
msgstr ""
+msgid "The form contains the following warning:"
+msgstr ""
+
msgid "The global settings require you to enable Two-Factor Authentication for your account."
msgstr "グローãƒãƒ«è¨­å®šã§ã¯ã€è‡ªåˆ†ã®ã‚¢ã‚«ã‚¦ãƒ³ãƒˆã«å¯¾ã—ã¦2è¦ç´ èªè¨¼ã‚’有効ã«ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚"
@@ -24649,9 +25510,6 @@ msgstr "計画ステージã§ã¯ã€èª²é¡Œã‚¹ãƒ†ãƒ¼ã‚¸ã«ç™»éŒ²ã•ã‚Œã¦ã‹ã‚‰ãƒ—
msgid "The private key to use when a client certificate is provided. This value is encrypted at rest."
msgstr "クライアント証明書ãŒæä¾›ã•ã‚Œã‚‹ã¨ãã«ä½¿ç”¨ã™ã‚‹ç§˜å¯†éµã€‚ã“ã®å€¤ã¯æš—å·åŒ–ã—ã¦ä¿å­˜ã•ã‚Œã¾ã™ã€‚"
-msgid "The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr "プロダクションステージã§ã¯ã€èª²é¡ŒãŒä½œæˆã•ã‚Œã¦ã‹ã‚‰ãƒ—ロダクションã¸ãƒ‡ãƒ—ロイã•ã‚Œã‚‹ã¾ã§ã®æ™‚é–“ãŒè¡¨ç¤ºã•ã‚Œã¾ã™ã€‚アイディアã®æ™‚点ã‹ã‚‰ãƒ—ロダクションã¾ã§ã®å…¨ã‚¹ãƒ†ãƒ¼ã‚¸ãŒå®Œäº†ã—ãŸã¨ãã«è‡ªå‹•çš„ã«è¿½åŠ ã•ã‚Œã¾ã™ã€‚"
-
msgid "The project can be accessed by any logged in user."
msgstr "プロジェクトã¯ã€ãƒ­ã‚°ã‚¤ãƒ³ãƒ¦ãƒ¼ã‚¶ãƒ¼ã§ã‚ã‚Œã°èª°ã§ã‚‚アクセスã§ãã¾ã™ã€‚"
@@ -24688,8 +25546,8 @@ msgstr "リモートミラーãŒå®Œäº†ã™ã‚‹ã¾ã§ã«æ™‚é–“ãŒã‹ã‹ã‚Šã¾ã™ã€‚
msgid "The remote repository is being updated..."
msgstr "リモートリãƒã‚¸ãƒˆãƒªã¯ç¾åœ¨ã€æ›´æ–°ä¸­ã§ã™ã€‚"
-msgid "The repository can be commited to, and issues, comments and other entities can be created."
-msgstr "ã“ã®ãƒªãƒã‚¸ãƒˆãƒªã«ã¯ã‚³ãƒŸãƒƒãƒˆã€èª²é¡Œã€ã‚³ãƒ¡ãƒ³ãƒˆã€ãã®ä»–ã®ã‚¨ãƒ³ãƒ†ã‚£ãƒ†ã‚£ã‚’作æˆã§ãã¾ã™ã€‚"
+msgid "The repository can be committed to, and issues, comments and other entities can be created."
+msgstr ""
msgid "The repository for this project does not exist."
msgstr "ã“ã®ãƒ—ロジェクトã«ãƒªãƒã‚¸ãƒˆãƒªã¯ã‚ã‚Šã¾ã›ã‚“。"
@@ -24742,9 +25600,6 @@ msgstr "テスティングステージã§ã¯ã€GitLab CI ãŒé–¢é€£ã™ã‚‹ãƒžãƒ¼ã‚
msgid "The time taken by each data entry gathered by that stage."
msgstr "ã“ã®ã‚¹ãƒ†ãƒ¼ã‚¸ã«åŽé›†ã•ã‚ŒãŸãƒ‡ãƒ¼ã‚¿æ¯Žã®æ™‚é–“"
-msgid "The total stage shows the time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The update action will time out after %{number_of_minutes} minutes. For big repositories, use a clone/push combination."
msgstr "アップデート㯠%{number_of_minutes} 分後ã«ã‚¿ã‚¤ãƒ ã‚¢ã‚¦ãƒˆã—ã¾ã™ã€‚大ããªãƒªãƒã‚¸ãƒˆãƒªã«ã¯ã€clone 㨠push を組ã¿åˆã‚ã›ã¦ä½¿ã£ã¦ãã ã•ã„。"
@@ -24808,6 +25663,9 @@ msgstr "アーカイブã•ã‚ŒãŸãƒ—ロジェクトã¯ã‚ã‚Šã¾ã›ã‚“"
msgid "There are no archived requirements"
msgstr ""
+msgid "There are no archived test cases"
+msgstr ""
+
msgid "There are no changes"
msgstr ""
@@ -24847,6 +25705,9 @@ msgstr "オープン中ã®ãƒžãƒ¼ã‚¸ãƒªã‚¯ã‚¨ã‚¹ãƒˆã¯ã‚ã‚Šã¾ã›ã‚“"
msgid "There are no open requirements"
msgstr "オープン中ã®è¦æ±‚事項ã¯ã‚ã‚Šã¾ã›ã‚“"
+msgid "There are no open test cases"
+msgstr ""
+
msgid "There are no packages yet"
msgstr "ã¾ã ãƒ‘ッケージãŒã‚ã‚Šã¾ã›ã‚“。"
@@ -24859,6 +25720,9 @@ msgstr ""
msgid "There is a limit of %{ci_project_subscriptions_limit} subscriptions from or to a project."
msgstr ""
+msgid "There is already a To-Do for this design."
+msgstr ""
+
msgid "There is already a repository with that name on disk"
msgstr "ãã®åå‰ã®ãƒªãƒã‚¸ãƒˆãƒªã¯ã™ã§ã«ãƒ‡ã‚£ã‚¹ã‚¯ä¸Šã«ã‚ã‚Šã¾ã™"
@@ -24877,6 +25741,9 @@ msgstr ""
msgid "There was a problem communicating with your device."
msgstr "ã‚ãªãŸã®ãƒ‡ãƒã‚¤ã‚¹ã¨ã®é–“ã«é€šä¿¡éšœå®³ãŒç™ºç”Ÿã—ã¦ã„ã¾ã™ã€‚"
+msgid "There was a problem fetching branches."
+msgstr ""
+
msgid "There was a problem fetching groups."
msgstr ""
@@ -25085,7 +25952,7 @@ msgid "This %{noteableTypeText} is locked."
msgstr ""
msgid "This %{viewer} could not be displayed because %{reason}. You can %{options} instead."
-msgstr "%{reason} ã®ãŸã‚ã€ã“ã® %{viewer} ã¯è¡¨ç¤ºã§ãã¾ã›ã‚“ã§ã—ãŸã€‚代ã‚ã‚Šã« %{options} ãŒä½¿ç”¨ã§ãã¾ã™ã€‚"
+msgstr ""
msgid "This Cron pattern is invalid"
msgstr ""
@@ -25105,9 +25972,15 @@ msgstr ""
msgid "This action can lead to data loss. To prevent accidental actions we ask you to confirm your intention."
msgstr "ã“ã®å‹•ä½œã«ã‚ˆã£ã¦ãƒ‡ãƒ¼ã‚¿ãŒå¤±ã‚れるå¯èƒ½æ€§ãŒã‚ã‚Šã¾ã™ã€‚çªç™ºçš„ãªäº‹æ…‹ã‚’防ããŸã‚ã«ã€ä¸€åº¦æ“作ã®æ„図を確èªã—ã¦ãã ã•ã„。ãŠé¡˜ã„ã—ã¾ã™ã€‚"
+msgid "This action cannot be undone, and will permanently delete the %{key} SSH key"
+msgstr ""
+
msgid "This action cannot be undone. You will lose the project's repository and all content: issues, merge requests, etc."
msgstr ""
+msgid "This action has been performed too many times. Try again later."
+msgstr ""
+
msgid "This action will %{strongOpen}permanently delete%{strongClose} %{codeOpen}%{project}%{codeClose} %{strongOpen}immediately%{strongClose}, including its repositories and all content: issues, merge requests, etc."
msgstr ""
@@ -25135,9 +26008,6 @@ msgstr "ã“ã®ãƒ–ロックã¯è‡ªå·±å‚ç…§ã—ã¦ã„ã¾ã™ã€‚"
msgid "This board's scope is reduced"
msgstr ""
-msgid "This branch has changed since you started editing. Would you like to create a new branch?"
-msgstr "編集を開始ã—ã¦ã‹ã‚‰ãƒ–ランãƒãŒæ›´æ–°ã•ã‚Œã¦ã„ã¾ã™ã€‚æ–°ã—ã„ブランãƒã‚’作æˆã—ã¾ã™ã‹ï¼Ÿ"
-
msgid "This chart could not be displayed"
msgstr "ã“ã®ãƒãƒ£ãƒ¼ãƒˆã¯è¡¨ç¤ºã§ãã¾ã›ã‚“"
@@ -25264,15 +26134,9 @@ msgstr "ã“ã‚Œã¯ã‚ãªãŸã®ã‚¢ã‚«ã‚¦ãƒ³ãƒˆã«ãƒ­ã‚°ã‚¤ãƒ³ã—ãŸãƒ‡ãƒã‚¤ã‚¹ã®
msgid "This is a security log of important events involving your account."
msgstr "ã“ã‚Œã¯ã‚ãªãŸã®ã‚¢ã‚«ã‚¦ãƒ³ãƒˆã«é–¢ã‚ã‚‹é‡è¦ãªã‚¤ãƒ™ãƒ³ãƒˆã®ã‚»ã‚­ãƒ¥ãƒªãƒ†ã‚£ãƒ­ã‚°ã§ã™ã€‚"
-msgid "This is the author's first Merge Request to this project."
-msgstr "ã“ã®ãƒ—ロジェクトã«å¯¾ã™ã‚‹ã€ä½œæˆè€…ã®æœ€åˆã®ãƒžãƒ¼ã‚¸ãƒªã‚¯ã‚¨ã‚¹ãƒˆã§ã™ã€‚"
-
msgid "This is the highest peak of users on your installation since the license started."
msgstr ""
-msgid "This is the maximum number of users that have existed at the same time since the license started. This is the minimum number of seats you will need to buy when you renew your license."
-msgstr "ã“ã‚Œã¯ãƒ©ã‚¤ã‚»ãƒ³ã‚¹ãŒé–‹å§‹ã•ã‚Œã¦ã‹ã‚‰åŒæ™‚ã«å­˜åœ¨ã—ãŸãƒ¦ãƒ¼ã‚¶ãƒ¼ã®æœ€å¤§æ•°ã§ã™ã€‚ã“ã‚Œã¯ã€æ¬¡å›žãƒ©ã‚¤ã‚»ãƒ³ã‚¹æ›´æ–°æ™‚ã«è³¼å…¥ã™ã‚‹å¿…è¦ãŒã‚る最å°ã®ã‚·ãƒ¼ãƒˆæ•°ã§ã™ã€‚"
-
msgid "This is the number of currently active users on your installation, and this is the minimum number you need to purchase when you renew your license."
msgstr ""
@@ -25504,6 +26368,15 @@ msgstr ""
msgid "This user has no identities"
msgstr "ã“ã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ã«ã¯ ID ãŒã‚ã‚Šã¾ã›ã‚“"
+msgid "This user has previously committed to the %{name} project."
+msgstr ""
+
+msgid "This user has the %{access} role in the %{name} project."
+msgstr ""
+
+msgid "This user is the author of this %{noteable}."
+msgstr ""
+
msgid "This user will be the author of all events in the activity feed that are the result of an update, like new branches being created or new commits being pushed to existing branches."
msgstr "ã“ã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ã¯ã€æ–°ã—ã作æˆã•ã‚ŒãŸãƒ–ランãƒã‚„既存ã®ãƒ–ランãƒã¸ã®æ–°è¦ã‚³ãƒŸãƒƒãƒˆãªã©ã®ã‚ˆã†ã«ã€æ›´æ–°ã®çµæžœã§ã‚るアクティビティーフィード内ã®ã™ã¹ã¦ã®ã‚¤ãƒ™ãƒ³ãƒˆã®ä½œæˆè€…ã«ãªã‚Šã¾ã™ã€‚"
@@ -25534,6 +26407,9 @@ msgstr ""
msgid "Threat Monitoring"
msgstr "è„…å¨ç›£è¦–"
+msgid "ThreatMonitoring|All Environments"
+msgstr ""
+
msgid "ThreatMonitoring|Anomalous Requests"
msgstr ""
@@ -25561,9 +26437,6 @@ msgstr ""
msgid "ThreatMonitoring|Operations Per Second"
msgstr "1秒ã‚ãŸã‚Šã®æ“作数"
-msgid "ThreatMonitoring|Overview"
-msgstr ""
-
msgid "ThreatMonitoring|Packet Activity"
msgstr ""
@@ -25582,6 +26455,9 @@ msgstr "å•é¡ŒãŒç™ºç”Ÿã—ãŸãŸã‚ã€ç’°å¢ƒã‚’å–å¾—ã§ãã¾ã›ã‚“"
msgid "ThreatMonitoring|Something went wrong, unable to fetch statistics"
msgstr ""
+msgid "ThreatMonitoring|Statistics"
+msgstr ""
+
msgid "ThreatMonitoring|The firewall is not installed or has been disabled. To view this data, ensure the web application firewall is installed and enabled for your cluster."
msgstr ""
@@ -25971,6 +26847,9 @@ msgstr ""
msgid "To update Snippets with multiple files, you must use the `files` parameter"
msgstr ""
+msgid "To use Gitpod you must first enable the feature in the integrations section of your %{user_prefs}."
+msgstr ""
+
msgid "To view all %{scannedResourcesCount} scanned URLs, please download the CSV file"
msgstr ""
@@ -26004,9 +26883,6 @@ msgstr ""
msgid "Toggle Sidebar"
msgstr "サイドãƒãƒ¼ã‚’切り替ãˆ"
-msgid "Toggle all threads"
-msgstr "ã™ã¹ã¦ã®ã‚¹ãƒ¬ãƒƒãƒ‰ã®åˆ‡ã‚Šæ›¿ãˆ"
-
msgid "Toggle backtrace"
msgstr "ãƒãƒƒã‚¯ãƒˆãƒ¬ãƒ¼ã‚¹ã‚’切り替ãˆ"
@@ -26031,9 +26907,6 @@ msgstr "絵文字リアクションをトグル"
msgid "Toggle navigation"
msgstr "案内ã®åˆ‡ã‚Šæ›¿ãˆ"
-msgid "Toggle project"
-msgstr "プロジェクト切り替ãˆ"
-
msgid "Toggle sidebar"
msgstr "サイドãƒãƒ¼ã‚’切り替ãˆ"
@@ -26073,6 +26946,9 @@ msgstr "有効ã«ãªã£ã¦ã„ã‚‹åå‰ç©ºé–“ãŒå¤šã™ãŽã¾ã™ã€‚コンソール
msgid "Too many projects enabled. You will need to manage them via the console or the API."
msgstr "有効ã«ãªã£ã¦ã„るプロジェクトãŒå¤šã™ãŽã¾ã™ã€‚コンソールã¾ãŸã¯APIを使用ã—ã¦ç®¡ç†ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚"
+msgid "Too much data"
+msgstr ""
+
msgid "Topics (optional)"
msgstr "トピック (ä»»æ„)"
@@ -26091,6 +26967,9 @@ msgstr "アーティファクトã®ã‚µã‚¤ã‚º(åˆè¨ˆ): %{total_size}"
msgid "Total cores (CPUs)"
msgstr ""
+msgid "Total days to completion"
+msgstr ""
+
msgid "Total issues"
msgstr "全課題"
@@ -26187,6 +27066,9 @@ msgstr "ツリービュー"
msgid "Trending"
msgstr "トレンド分æž"
+msgid "Trials|Create a new group to start your GitLab Gold trial."
+msgstr ""
+
msgid "Trials|Go back to GitLab"
msgstr ""
@@ -26196,6 +27078,15 @@ msgstr ""
msgid "Trials|You can always resume this process by selecting your avatar and choosing 'Start a Gold trial'"
msgstr ""
+msgid "Trials|You can apply your trial to a new group or an existing group."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group or your personal account."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group, an existing group, or your personal account."
+msgstr ""
+
msgid "Trials|You won't get a free trial right now but you can always resume this process by clicking on your avatar and choosing 'Start a free trial'"
msgstr ""
@@ -26265,6 +27156,9 @@ msgstr ""
msgid "Try using a different search term to find the file you are looking for."
msgstr "別ã®ç”¨èªžã§æ¤œç´¢ã—ã¦ã€æŽ¢ã—ã¦ã„るファイルを見ã¤ã‘ã¦ãã ã•ã„。"
+msgid "Trying to communicate with your device. Plug it in (if needed) and press the button on the device now."
+msgstr ""
+
msgid "Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now."
msgstr "デãƒã‚¤ã‚¹ã¨é€šä¿¡ã—よã†ã¨ã—ã¦ã„ã¾ã™ã€‚(ã¾ã æº–å‚™ã§ãã¦ã„ãªã„å ´åˆã¯) デãƒã‚¤ã‚¹ã‚’接続ã—ã¦ã€ãƒœã‚¿ãƒ³ã‚’押ã—ã¾ã™ã€‚"
@@ -26352,6 +27246,12 @@ msgstr "(アーカイブãªã©ã®)リãƒã‚¸ãƒˆãƒªã®é™çš„オブジェクトをä
msgid "URL or request ID"
msgstr "URL ã¾ãŸã¯ リクエストID"
+msgid "USER %{user} WILL BE REMOVED! Are you sure?"
+msgstr ""
+
+msgid "USER WILL BE BLOCKED! Are you sure?"
+msgstr ""
+
msgid "UTC"
msgstr ""
@@ -26409,9 +27309,6 @@ msgstr "差分を読ã¿è¾¼ã‚€ã“ã¨ãŒã§ãã¾ã›ã‚“。%{button_try_again}"
msgid "Unable to load the merge request widget. Try reloading the page."
msgstr "マージリクエストウィジェットをロードã§ãã¾ã›ã‚“。ページをå†èª­ã¿è¾¼ã¿ã—ã¦ãã ã•ã„。"
-msgid "Unable to resolve"
-msgstr "解決ä¸å¯"
-
msgid "Unable to save iteration. Please try again"
msgstr ""
@@ -26460,11 +27357,14 @@ msgstr ""
msgid "Undo ignore"
msgstr ""
+msgid "Unexpected error"
+msgstr ""
+
msgid "Unfortunately, your email message to GitLab could not be processed."
msgstr "残念ãªãŒã‚‰ã€GitLab ã¸ã®ãƒ¡ãƒ¼ãƒ«å‡¦ç†ã¯ã§ãã¾ã›ã‚“ã§ã—ãŸã€‚"
msgid "Uninstall"
-msgstr "アンインストール·"
+msgstr "アンインストール"
msgid "Uninstalling"
msgstr "アンインストール中"
@@ -26493,6 +27393,9 @@ msgstr "ä¸æ˜Žãªå½¢å¼ã§ã™"
msgid "Unknown response text"
msgstr "応答テキストãŒä¸æ˜Žã§ã™ã€‚"
+msgid "Unless otherwise agreed to in writing with GitLab, by clicking \"Upload License\" you agree that your use of GitLab Software is subject to the %{eula_link_start}Terms of Service%{eula_link_end}."
+msgstr ""
+
msgid "Unlimited"
msgstr "無制é™"
@@ -26859,9 +27762,6 @@ msgstr "%{link_start} スコープã®ãƒ©ãƒ™ãƒ«ã‚»ãƒƒãƒˆ%{link_end} を作æˆã™ã
msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
msgstr "サービスデスクを使用ã—ã¦ã€GitLab 内ã®ãƒ¡ãƒ¼ãƒ«ã§ãƒ¦ãƒ¼ã‚¶ã¨æŽ¥ç¶šï¼ˆä¾‹ï¼šé¡§å®¢ã‚µãƒãƒ¼ãƒˆï¼‰"
-msgid "Use a hardware device to add the second factor of authentication."
-msgstr "ãƒãƒ¼ãƒ‰ã‚¦ã‚§ã‚¢ãƒ‡ãƒã‚¤ã‚¹ã‚’使用ã—ã¦ã€2è¦ç´ èªè¨¼ã‚’追加ã—ã¾ã™ã€‚"
-
msgid "Use an one time password authenticator on your mobile device or computer to enable two-factor authentication (2FA)."
msgstr "モãƒã‚¤ãƒ«ãƒ‡ãƒã‚¤ã‚¹ã¾ãŸã¯ã‚³ãƒ³ãƒ”ュータã§ãƒ¯ãƒ³ã‚¿ã‚¤ãƒ ãƒ‘スワードèªè¨¼ã‚’使用ã—ã¦ã€2è¦ç´ èªè¨¼ã‚’有効ã«ã—ã¾ã™ã€‚"
@@ -27135,15 +28035,15 @@ msgstr "ユーザーåã¾ãŸã¯ãƒ¡ãƒ¼ãƒ«ã‚¢ãƒ‰ãƒ¬ã‚¹"
msgid "Users"
msgstr "ユーザー"
+msgid "Users in License"
+msgstr ""
+
msgid "Users in License:"
msgstr ""
msgid "Users or groups set as approvers in the project's or merge request's settings."
msgstr "プロジェクトã®è¨­å®šã¾ãŸã¯ãƒžãƒ¼ã‚¸ãƒªã‚¯ã‚¨ã‚¹ãƒˆã®è¨­å®šã§æ‰¿èªè€…ã¨ã—ã¦è¨­å®šã•ã‚ŒãŸãƒ¦ãƒ¼ã‚¶ãƒ¼ã¾ãŸã¯ã‚°ãƒ«ãƒ¼ãƒ—。"
-msgid "Users outside of license"
-msgstr "ライセンスã•ã‚Œã¦ã„ãªã„ユーザー"
-
msgid "Users over License:"
msgstr ""
@@ -27159,9 +28059,6 @@ msgstr "ユーザーを正常ã«è¿½åŠ ã§ãã¾ã—ãŸã€‚"
msgid "Users with a Guest role or those who don't belong to a Project or Group will not use a seat from your license."
msgstr ""
-msgid "Users with a Guest role or those who don't belong to any projects or groups don't count towards seats in use."
-msgstr "ゲストロールをæŒã¤ãƒ¦ãƒ¼ã‚¶ã€ã¾ãŸã¯ãƒ—ロジェクトやグループã«å±žã—ã¦ã„ãªã„ユーザã¯ã€ä½¿ç”¨ä¸­ã®ã‚·ãƒ¼ãƒˆã«ã‚«ã‚¦ãƒ³ãƒˆã•ã‚Œã¾ã›ã‚“。"
-
msgid "UsersSelect|%{name} + %{length} more"
msgstr "%{name} + %{length} 以上"
@@ -27201,9 +28098,6 @@ msgstr "GitLab CI構æˆãƒ•ã‚¡ã‚¤ãƒ«ã‚’検証"
msgid "Validations failed."
msgstr "検証ã«å¤±æ•—ã—ã¾ã—ãŸã€‚"
-msgid "Validity"
-msgstr "有効"
-
msgid "Value"
msgstr "値"
@@ -27222,6 +28116,9 @@ msgstr "ãƒãƒªãƒ¥ãƒ¼ã‚¹ãƒˆãƒªãƒ¼ãƒ åˆ†æžã§ã¯ã€ã‚ãªãŸã®ãƒ—ロジェクト
msgid "Value Stream Name"
msgstr ""
+msgid "ValueStreamAnalyticsStage|We don't have enough data to show this stage."
+msgstr ""
+
msgid "ValueStreamAnalytics|%{days}d"
msgstr ""
@@ -27330,7 +28227,7 @@ msgid "View full dashboard"
msgstr "ダッシュボードã®ãƒ•ãƒ«è¡¨ç¤º"
msgid "View full log"
-msgstr ""
+msgstr " ログã®å…¨ä½“表示"
msgid "View group labels"
msgstr "グループラベルを表示"
@@ -27476,6 +28373,9 @@ msgstr "レビュー"
msgid "VisualReviewApp|Steps 1 and 2 (and sometimes 3) are performed once by the developer before requesting feedback. Steps 3 (if necessary), 4 is performed by the reviewer each time they perform a review."
msgstr ""
+msgid "Visualization"
+msgstr ""
+
msgid "Vulnerabilities"
msgstr "脆弱性"
@@ -27503,34 +28403,31 @@ msgstr "%{formattedStartDate} ã‹ã‚‰ä»Šæ—¥ã¾ã§"
msgid "VulnerabilityChart|Severity"
msgstr "é‡è¦åº¦"
-msgid "VulnerabilityManagement|A true-positive and will fix"
-msgstr ""
-
-msgid "VulnerabilityManagement|Change status"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Confirm"
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|Confirmed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Detected %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|A true-positive and will fix"
msgstr ""
-msgid "VulnerabilityManagement|Dismiss"
+msgid "VulnerabilityManagement|Change status"
msgstr ""
-msgid "VulnerabilityManagement|Dismissed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
msgstr ""
-msgid "VulnerabilityManagement|Resolved"
+msgid "VulnerabilityManagement|Detected"
msgstr ""
-msgid "VulnerabilityManagement|Resolved %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Needs triage"
msgstr ""
msgid "VulnerabilityManagement|Something went wrong while trying to delete the comment. Please try again later."
@@ -27581,6 +28478,9 @@ msgstr ""
msgid "Vulnerability|%{scannerName} (version %{scannerVersion})"
msgstr "%{scannerName} (ãƒãƒ¼ã‚¸ãƒ§ãƒ³ %{scannerVersion})"
+msgid "Vulnerability|Activity"
+msgstr ""
+
msgid "Vulnerability|Class"
msgstr "クラス"
@@ -27593,6 +28493,9 @@ msgstr ""
msgid "Vulnerability|Description"
msgstr "説明"
+msgid "Vulnerability|Detected"
+msgstr ""
+
msgid "Vulnerability|Evidence"
msgstr ""
@@ -27656,6 +28559,9 @@ msgstr "警告:"
msgid "Warning: Displaying this diagram might cause performance issues on this page."
msgstr ""
+msgid "We are currently unable to fetch data for the pipeline header."
+msgstr ""
+
msgid "We are currently unable to fetch data for this graph."
msgstr ""
@@ -27695,6 +28601,12 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr "本人確èªã®ãŸã‚ã€ã‚ãªãŸãŒãƒ­ãƒœãƒƒãƒˆã§ãªã„ã“ã¨ã‚’確èªã—ã¦ãã ã•ã„。"
+msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
+msgstr ""
+
+msgid "We would like to inform you that your subscription GitLab Enterprise Edition %{plan_name} is nearing its user limit. You have %{active_user_count} active users, which is almost at the user limit of %{maximum_user_count}."
+msgstr ""
+
msgid "We've found no vulnerabilities"
msgstr "脆弱性ã¯ç™ºè¦‹ã•ã‚Œã¾ã›ã‚“ã§ã—ãŸ"
@@ -27710,6 +28622,12 @@ msgstr "Web端末"
msgid "Web terminal"
msgstr "ウェブターミナル"
+msgid "WebAuthn Devices (%{length})"
+msgstr ""
+
+msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
+msgstr ""
+
msgid "WebIDE|Merge request"
msgstr ""
@@ -27729,7 +28647,7 @@ msgid "Webhooks Help"
msgstr ""
msgid "Webhooks allow you to trigger a URL if, for example, new code is pushed or a new issue is created. You can configure webhooks to listen for specific events like pushes, issues or merge requests. Group webhooks will apply to all projects in a group, allowing you to standardize webhook functionality across your entire group."
-msgstr "Webhookã¯ã€ä¾‹ãˆã°æ–°ã—ã„コードãŒãƒ—ッシュã•ã‚ŒãŸã‚Šã€æ–°ã—ã„課題ãŒä½œæˆã•ã‚ŒãŸå ´åˆã«ã€URL を呼ã³ã ã™ã“ã¨ãŒã§ãã¾ã™ã€‚プッシュã€èª²é¡Œã¾ãŸã¯ãƒžãƒ¼ã‚¸ãƒªã‚¯ã‚¨ã‚¹ãƒˆã®ã‚ˆã†ãªã‚¤ãƒ™ãƒ³ãƒˆã‹ã‚‰ã©ã®ã‚¤ãƒ™ãƒ³ãƒˆã‚’監視ã™ã‚‹ã‹Webhookを設定ã§ãã¾ã™ã€‚グループウェブフックã¯ã‚°ãƒ«ãƒ¼ãƒ—内ã®ã™ã¹ã¦ã®ãƒ—ロジェクトã«é©ç”¨ã•ã‚Œã€ã‚°ãƒ«ãƒ¼ãƒ—全体ã§Webhookを標準化ã™ã‚‹ã“ã¨ãŒå‡ºæ¥ã¾ã™ã€‚"
+msgstr "Webhookã¯ã€ä¾‹ãˆã°æ–°ã—ã„コードãŒãƒ—ッシュã•ã‚ŒãŸã‚Šã€æ–°ã—ã„課題ãŒä½œæˆã•ã‚ŒãŸå ´åˆã«ã€URL を呼ã³ã ã™ã“ã¨ãŒã§ãã¾ã™ã€‚プッシュã€èª²é¡Œã¾ãŸã¯ãƒžãƒ¼ã‚¸ãƒªã‚¯ã‚¨ã‚¹ãƒˆã®ã‚ˆã†ãªã‚¤ãƒ™ãƒ³ãƒˆã‹ã‚‰ã©ã®ã‚¤ãƒ™ãƒ³ãƒˆã‚’監視ã™ã‚‹ã‹Webhookを設定ã§ãã¾ã™ã€‚グループウェブフックã¯ã‚°ãƒ«ãƒ¼ãƒ—内ã®ã™ã¹ã¦ã®ãƒ—ロジェクトã«é©ç”¨ã•ã‚Œã€ã‚°ãƒ«ãƒ¼ãƒ—全体ã§Webhookを標準化ã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚"
msgid "Webhooks have moved. They can now be found under the Settings menu."
msgstr "Webhook ã¯è¨­å®šãƒ¡ãƒ‹ãƒ¥ãƒ¼ã«ç§»å‹•ã—ã¾ã—ãŸã€‚"
@@ -27840,7 +28758,7 @@ msgid "Welcome to GitLab"
msgstr "GitLab ã¸ã‚ˆã†ã“ã"
msgid "Welcome to GitLab%{br_tag}%{name}!"
-msgstr ""
+msgstr "%{name}ã•ã‚“%{br_tag} GitLab ã¸ã‚ˆã†ã“ãï¼"
msgid "Welcome to GitLab, %{first_name}!"
msgstr ""
@@ -27848,14 +28766,8 @@ msgstr ""
msgid "Welcome to the guided GitLab tour"
msgstr ""
-msgid "Welcome to your Issue Board!"
-msgstr "課題ボードã¸ã‚ˆã†ã“ã"
-
msgid "Welcome to your issue board!"
-msgstr ""
-
-msgid "We’ve been making changes to %{featureName} and we’d love your feedback %{linkStart}in this issue%{linkEnd} to help us improve the experience."
-msgstr ""
+msgstr "課題ボードã¸ã‚ˆã†ã“ã"
msgid "What are you searching for?"
msgstr "何を探ã—ã¾ã™ã‹?"
@@ -27875,6 +28787,9 @@ msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
msgstr "Runner ãŒãƒ­ãƒƒã‚¯ã•ã‚Œã¦ã„ã‚‹å ´åˆã€ä»–ã®ãƒ—ロジェクトã«å‰²ã‚Šå½“ã¦ã‚‹ã“ã¨ãŒã§ãã¾ã›ã‚“"
+msgid "When enabled, any user visiting %{host} and creating an account will have to be explicitly approved by the admin before they can login. This setting is effective only if sign-ups are enabled."
+msgstr ""
+
msgid "When enabled, any user visiting %{host} will be able to create an account."
msgstr ""
@@ -28098,6 +29013,9 @@ msgstr "次ã®å ´æ‰€ã«ãƒ‡ãƒ—ロイã—ã¾ã™"
msgid "With requirements, you can set criteria to check your products against."
msgstr ""
+msgid "With test cases, you can define conditions for your project to meet in determining quality"
+msgstr ""
+
msgid "Withdraw Access Request"
msgstr "アクセスリクエストをå–り消ã™"
@@ -28111,6 +29029,9 @@ msgid "Work in progress Limit"
msgstr ""
msgid "Workflow Help"
+msgstr "ワークフローã®ãƒ˜ãƒ«ãƒ—"
+
+msgid "Would you like to create a new branch?"
msgstr ""
msgid "Write"
@@ -28134,6 +29055,9 @@ msgstr "リリースノートを書ãã‹ã€ã“ã“ã«ãƒ•ã‚¡ã‚¤ãƒ«ã‚’ドラッグ
msgid "Wrong extern UID provided. Make sure Auth0 is configured correctly."
msgstr "é–“é•ã£ãŸå¤–部UIDãŒæŒ‡å®šã•ã‚Œã¾ã—ãŸã€‚ Auth0ãŒæ­£ã—ã設定ã•ã‚Œã¦ã„ã‚‹ã“ã¨ã‚’確èªã—ã¦ãã ã•ã„。"
+msgid "YYYY-MM-DD"
+msgstr ""
+
msgid "Yes"
msgstr "ã¯ã„"
@@ -28191,8 +29115,8 @@ msgstr ""
msgid "You are going to remove the fork relationship from %{project_full_name}. Are you ABSOLUTELY sure?"
msgstr "%{project_full_name} プロジェクトã¨ã®ãƒ•ã‚©ãƒ¼ã‚¯ã®é–¢ä¿‚を削除ã—よã†ã¨ã—ã¦ã„ã¾ã™ã€‚本当ã«ã‚ˆã‚ã—ã„ã§ã™ã‹ï¼Ÿ"
-msgid "You are going to transfer %{project_full_name} to another owner. Are you ABSOLUTELY sure?"
-msgstr "%{project_full_name} を別ã®ã‚ªãƒ¼ãƒŠãƒ¼ã«å§”è­²ã—よã†ã¨ã—ã¦ã„ã¾ã™ã€‚本当ã«ã‚ˆã‚ã—ã„ã§ã™ã‹ï¼Ÿ"
+msgid "You are going to transfer %{project_full_name} to another namespace. Are you ABSOLUTELY sure?"
+msgstr ""
msgid "You are going to turn off the confidentiality. This means %{strongStart}everyone%{strongEnd} will be able to see and leave a comment on this %{issuableType}."
msgstr ""
@@ -28251,9 +29175,6 @@ msgstr "以下ã®æ‰‹é †ã«ãã£ã¦ã€ã‚ãªãŸã®ã‚³ãƒ³ãƒ”ューター上ã®æ—¢
msgid "You can always edit this later"
msgstr ""
-msgid "You can apply your Trial to your Personal account or create a New Group."
-msgstr "試用版を個人アカウントã«é©ç”¨ã™ã‚‹ã‹ã€æ–°ã—ã„グループを作æˆã§ãã¾ã™ã€‚"
-
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings"
msgstr ""
@@ -28275,12 +29196,18 @@ msgstr "Kubernetes クラスター㫠Runner ã‚’ç°¡å˜ã«ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã§ã
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr "グラフã®åˆ—をクリックã—ã¦ã€ãƒžãƒ¼ã‚¸æ—¥ã§ãƒ•ã‚£ãƒ«ã‚¿ãƒªãƒ³ã‚°ã§ãã¾ã™ã€‚"
+msgid "You can find more information about GitLab subscriptions in %{subscriptions_doc_link}."
+msgstr ""
+
msgid "You can generate an access token scoped to this project for each application to use the GitLab API."
msgstr ""
msgid "You can get started by cloning the repository or start adding files to it with one of the following options."
msgstr ""
+msgid "You can group test cases using labels. To learn about the future direction of this feature, visit %{linkStart}Quality Management direction page%{linkEnd}."
+msgstr ""
+
msgid "You can invite a new member to %{project_name} or invite another group."
msgstr ""
@@ -28296,6 +29223,9 @@ msgstr "矢å°ã‚­ãƒ¼ã‚’使用ã—ã¦ã‚°ãƒ©ãƒ•ã‚’移動ã™ã‚‹ã“ã¨ãŒã§ãã¾ã™
msgid "You can notify the app / group or a project by sending them an email notification"
msgstr ""
+msgid "You can now close this window."
+msgstr ""
+
msgid "You can now export your security dashboard to a CSV report."
msgstr "セキュリティダッシュボードをCSVレãƒãƒ¼ãƒˆã«ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆã§ãã¾ã™ã€‚"
@@ -28344,9 +29274,6 @@ msgstr "グループã”ã¨ã¾ãŸã¯ãƒ—ロジェクトã”ã¨ã«é€šçŸ¥ãƒ¬ãƒ™ãƒ«ã‚’
msgid "You can test your .gitlab-ci.yml in %{linkStart}CI Lint%{linkEnd}."
msgstr "%{linkStart} CI Lint %{linkEnd} ã§.gitlab-ci.ymlをテストã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚"
-msgid "You can try again using %{begin_link}basic search%{end_link}"
-msgstr "%{begin_link} 検索 %{end_link} を使用ã—ã¦å†ã³å®Ÿè¡Œã§ãã¾ã™"
-
msgid "You cannot access the raw file. Please wait a minute."
msgstr "ã“ã®ãƒ•ã‚¡ã‚¤ãƒ«ã«ç›´æŽ¥ã‚¢ã‚¯ã‚»ã‚¹ã§ãã¾ã›ã‚“。ã—ã°ã‚‰ããŠå¾…ã¡ãã ã•ã„。"
@@ -28398,6 +29325,9 @@ msgstr "LDAP グループã®åŒæœŸã®è¨­å®šã‚’上書ãã™ã‚‹ãŸã‚ã®é©åˆ‡ãªæ
msgid "You don't have any U2F devices registered yet."
msgstr "ã‚ãªãŸã¯ã¾ã 2è¦ç´ èªè¨¼ãƒ‡ãƒã‚¤ã‚¹ã‚’登録ã—ã¦ã„ã¾ã›ã‚“。"
+msgid "You don't have any WebAuthn devices registered yet."
+msgstr ""
+
msgid "You don't have any active chat names."
msgstr "アクティブãªãƒãƒ£ãƒƒãƒˆåãŒã‚ã‚Šã¾ã›ã‚“。"
@@ -28485,6 +29415,9 @@ msgstr "マイルストーンを終了ã§ãã¾ã™ã€‚"
msgid "You must accept our Terms of Service and privacy policy in order to register an account"
msgstr "アカウントを登録ã™ã‚‹ã«ã¯ã€åˆ©ç”¨è¦ç´„ã¨ãƒ—ライãƒã‚·ãƒ¼ãƒãƒªã‚·ãƒ¼ã«åŒæ„ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™"
+msgid "You must be logged in to search across all of GitLab"
+msgstr ""
+
msgid "You must disassociate %{domain} from all clusters it is attached to before deletion."
msgstr ""
@@ -28524,8 +29457,8 @@ msgstr "権é™ãŒå¿…è¦ã§ã™"
msgid "You need to be logged in."
msgstr "ログインã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™"
-msgid "You need to register a two-factor authentication app before you can set up a U2F device."
-msgstr "U2Fデãƒã‚¤ã‚¹ã‚’設定ã™ã‚‹å‰ã«ã€ã‚ãªãŸã¯2è¦ç´ èªè¨¼ã‚¢ãƒ—リを登録ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚"
+msgid "You need to register a two-factor authentication app before you can set up a device."
+msgstr ""
msgid "You need to set terms to be enforced"
msgstr ""
@@ -28542,6 +29475,9 @@ msgstr "Google テイクアウトアーカイブをアップロードã™ã‚‹å¿…è¦
msgid "You reached %{usage_in_percent} of %{namespace_name}'s storage capacity (%{used_storage} of %{storage_limit})"
msgstr ""
+msgid "You successfully declined the invitation"
+msgstr ""
+
msgid "You tried to fork %{link_to_the_project} but it failed for the following reason:"
msgstr "%{link_to_the_project} ã®ãƒ•ã‚©ãƒ¼ã‚¯ã¯ã€æ¬¡ã®ç†ç”±ã§å¤±æ•—ã—ã¾ã—ãŸã€‚:"
@@ -28707,12 +29643,15 @@ msgstr "ã‚ãªãŸã®To Doリスト"
msgid "Your U2F device did not send a valid JSON response."
msgstr "ã‚ãªãŸã®U2Fデãƒã‚¤ã‚¹ã¯ã€æœ‰åŠ¹ãªJSON応答をé€ä¿¡ã—ã¾ã›ã‚“ã§ã—ãŸã€‚"
-msgid "Your U2F device needs to be set up. Plug it in (if not already) and click the button on the left."
-msgstr "U2Fデãƒã‚¤ã‚¹ã‚’セットアップã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚(ã¾ã æŽ¥ç¶šã—ã¦ã„ãªã„å ´åˆã¯) å·®ã—込んã§æŽ¥ç¶šã—ã€å·¦ã®ãƒœã‚¿ãƒ³ã‚’クリックã—ã¾ã™ã€‚"
-
msgid "Your U2F device was registered!"
msgstr "ã‚ãªãŸã® U2F デãƒã‚¤ã‚¹ãŒç™»éŒ²ã•ã‚Œã¾ã—ãŸã€‚"
+msgid "Your WebAuthn device did not send a valid JSON response."
+msgstr ""
+
+msgid "Your WebAuthn device was registered!"
+msgstr ""
+
msgid "Your access request to the %{source_type} has been withdrawn."
msgstr "%{source_type} ã¸ã®ã‚¢ã‚¯ã‚»ã‚¹è¦æ±‚ã¯å–り消ã•ã‚Œã¾ã—ãŸã€‚"
@@ -28734,6 +29673,9 @@ msgstr "承èªã•ã‚ŒãŸã‚¢ãƒ—リケーション"
msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
msgstr "ã‚ãªãŸã®ãƒ–ラウザã¯U2Fをサãƒãƒ¼ãƒˆã—ã¦ã„ã¾ã›ã‚“。 Google Chromeデスクトップ (ãƒãƒ¼ã‚¸ãƒ§ãƒ³41以é™) を使用ã—ã¦ãã ã•ã„。"
+msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
+msgstr ""
+
msgid "Your changes can be committed to %{branch_name} because a merge request is open."
msgstr "マージリクエストãŒé–‹ã„ã¦ã„ã‚‹ãŸã‚ã€å¤‰æ›´ã¯ %{branch_name} ã«ã‚³ãƒŸãƒƒãƒˆã§ãã¾ã™ã€‚"
@@ -28762,7 +29704,7 @@ msgid "Your custom stage '%{title}' was created"
msgstr ""
msgid "Your dashboard has been copied. You can %{web_ide_link_start}edit it here%{web_ide_link_end}."
-msgstr ""
+msgstr "ダッシュボードをコピーã—ã¾ã—ãŸã€‚%{web_ide_link_start} ã“ã“ã§ç·¨é›† %{web_ide_link_end} ã§ãã¾ã™ã€‚"
msgid "Your dashboard has been updated. You can %{web_ide_link_start}edit it here%{web_ide_link_end}."
msgstr ""
@@ -28770,6 +29712,12 @@ msgstr ""
msgid "Your deployment services will be broken, you will need to manually fix the services after renaming."
msgstr "デプロイサービスãŒå£Šã‚Œã‚‹ã“ã¨ãŒã‚ã‚Šã¾ã™ã€‚åå‰ã‚’変更ã—ãŸå¾Œã§æ‰‹å‹•ã§ã‚µãƒ¼ãƒ“スを修正ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚"
+msgid "Your device is not compatible with GitLab. Please try another device"
+msgstr ""
+
+msgid "Your device needs to be set up. Plug it in (if needed) and click the button on the left."
+msgstr ""
+
msgid "Your device was successfully set up! Give it a name and register it with the GitLab server."
msgstr "ã‚ãªãŸã®ãƒ‡ãƒã‚¤ã‚¹ã¯æ­£å¸¸ã«è¨­å®šã•ã‚Œã¾ã—ãŸã€‚åå‰ã‚’付ã‘ã¦GitLabサーãƒãƒ¼ã«ç™»éŒ²ã—ã¾ã™ã€‚"
@@ -28882,9 +29830,6 @@ msgstr[0] "約 %d 時間"
msgid "access:"
msgstr ""
-msgid "activated"
-msgstr "有効化済ã¿"
-
msgid "added %{created_at_timeago}"
msgstr "%{created_at_timeago} を追加ã—ã¾ã—ãŸ"
@@ -28957,9 +29902,21 @@ msgstr "by"
msgid "by %{user}"
msgstr ""
+msgid "cannot be a date in the past"
+msgstr ""
+
msgid "cannot be changed if a personal project has container registry tags."
msgstr "個人用プロジェクトã«ã‚³ãƒ³ãƒ†ãƒŠãƒ¬ã‚¸ã‚¹ãƒˆãƒªã‚¿ã‚°ãŒã‚ã‚‹å ´åˆã€å¤‰æ›´ã§ãã¾ã›ã‚“。"
+msgid "cannot be changed if shared runners are enabled"
+msgstr ""
+
+msgid "cannot be enabled because parent group does not allow it"
+msgstr ""
+
+msgid "cannot be enabled because parent group has shared Runners disabled"
+msgstr ""
+
msgid "cannot be enabled unless all domains have TLS certificates"
msgstr "ã™ã¹ã¦ã®ãƒ‰ãƒ¡ã‚¤ãƒ³ã« TLS 証明書ãŒãªã„ã¨æœ‰åŠ¹ã«ã§ãã¾ã›ã‚“"
@@ -29005,7 +29962,7 @@ msgstr "%{linkStartTag}ä¾å­˜æ€§ã‚¹ã‚­ãƒ£ãƒ³ã®è©³ç´°%{linkEndTag}"
msgid "ciReport|%{linkStartTag}Learn more about SAST %{linkEndTag}"
msgstr "%{linkStartTag}SAST ã®è©³ç´°%{linkEndTag}"
-msgid "ciReport|%{linkStartTag}Learn more about Secret Scanning %{linkEndTag}"
+msgid "ciReport|%{linkStartTag}Learn more about Secret Detection %{linkEndTag}"
msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about codequality reports %{linkEndTag}"
@@ -29174,10 +30131,10 @@ msgid "ciReport|Static Application Security Testing (SAST) detects known vulnera
msgstr "é™çš„アプリケーションセキュリティテスト(SAST)ã¯ã€ã‚½ãƒ¼ã‚¹ã‚³ãƒ¼ãƒ‰ä¸­ã®æ—¢çŸ¥ã®è„†å¼±æ€§ã‚’検出ã—ã¾ã™ã€‚"
msgid "ciReport|TTFB P90"
-msgstr ""
+msgstr "TTFB P90"
msgid "ciReport|TTFB P95"
-msgstr ""
+msgstr "TTFB P95"
msgid "ciReport|There was an error creating the issue. Please try again."
msgstr "課題を作æˆä¸­ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚ã‚‚ã†ä¸€åº¦ã‚„ã‚Šç›´ã—ã¦ãã ã•ã„。"
@@ -29202,7 +30159,7 @@ msgid "ciReport|View full report"
msgstr "レãƒãƒ¼ãƒˆå…¨ä½“を見る"
msgid "closed issue"
-msgstr ""
+msgstr "クローズã—ãŸèª²é¡Œ"
msgid "comment"
msgstr "コメント"
@@ -29214,7 +30171,7 @@ msgid "commit %{commit_id}"
msgstr "コミット %{commit_id}"
msgid "committed"
-msgstr ""
+msgstr "コミット済ã¿"
msgid "connecting"
msgstr "接続中"
@@ -29269,7 +30226,7 @@ msgid "disabled"
msgstr "無効"
msgid "does not exist"
-msgstr ""
+msgstr "存在ã—ã¾ã›ã‚“"
msgid "does not have a supported extension. Only %{extension_list} are supported"
msgstr "サãƒãƒ¼ãƒˆã•ã‚Œã¦ã„ã‚‹æ‹¡å¼µå­ã§ã¯ã‚ã‚Šã¾ã›ã‚“。 %{extension_list} ã®æ‹¡å¼µå­ã ã‘ãŒã‚µãƒãƒ¼ãƒˆã•ã‚Œã¦ã„ã¾ã™"
@@ -29278,7 +30235,7 @@ msgid "done"
msgstr "完了"
msgid "download it"
-msgstr ""
+msgstr "ダウンロードã™ã‚‹"
msgid "draft"
msgid_plural "drafts"
@@ -29317,9 +30274,6 @@ msgstr ""
msgid "error"
msgstr "エラー"
-msgid "error code:"
-msgstr "エラー コード:"
-
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr "%{slash_command} コマンドã§è¦‹ç©æ™‚é–“ã‚’æ›´æ–°ã§ãã¾ã™ã€‚"
@@ -29341,6 +30295,9 @@ msgstr "失敗ã—ã¾ã—ãŸ"
msgid "failed to dismiss associated finding(id=%{finding_id}): %{message}"
msgstr "関連付ã‘られãŸæ¤œå‡ºçµæžœã‚’破棄ã§ãã¾ã›ã‚“ã§ã—ãŸ(id =%{finding_id}): %{message}"
+msgid "failed to revert associated finding(id=%{finding_id}) to detected"
+msgstr ""
+
msgid "file"
msgid_plural "files"
msgstr[0] "ファイル"
@@ -29565,7 +30522,7 @@ msgid "merged %{timeAgo}"
msgstr ""
msgid "metric_id must be unique across a project"
-msgstr ""
+msgstr "metric_id ã¯ãƒ—ロジェクト全体ã§ä¸€æ„ã§ãªã‘ã‚Œã°ãªã‚Šã¾ã›ã‚“"
msgid "missing"
msgstr "見ã¤ã‹ã‚Šã¾ã›ã‚“"
@@ -29879,6 +30836,9 @@ msgstr "パイプラインãŒæˆåŠŸã—ãŸã¨ãã«ãƒžãƒ¼ã‚¸ãƒˆãƒ¬ã‚¤ãƒ³ã‚’開始
msgid "must be a root namespace"
msgstr ""
+msgid "must be a valid IPv4 or IPv6 address"
+msgstr ""
+
msgid "must be greater than start date"
msgstr "開始日より後ã«ã—ã¦ãã ã•ã„。"
@@ -29915,6 +30875,9 @@ msgstr "貢献ãªã—"
msgid "no expiration"
msgstr "有効期é™ãªã—"
+msgid "no name set"
+msgstr ""
+
msgid "no one can merge"
msgstr "誰もマージã§ãã¾ã›ã‚“"
@@ -30088,9 +31051,6 @@ msgstr ""
msgid "security Reports|There was an error creating the merge request"
msgstr "マージリクエストã®ä½œæˆä¸­ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚"
-msgid "settings saved, but not activated"
-msgstr "設定ã¯ä¿å­˜ã•ã‚Œã¾ã—ãŸãŒã€æœ‰åŠ¹åŒ–ã•ã‚Œã¦ã„ã¾ã›ã‚“_"
-
msgid "severity|Critical"
msgstr "致命的"
@@ -30217,9 +31177,6 @@ msgstr "リストã¸"
msgid "toggle collapse"
msgstr "表示・éžè¡¨ç¤ºåˆ‡ã‚Šæ›¿ãˆ"
-msgid "toggle dropdown"
-msgstr "ドロップダウンã®åˆ‡æ›¿"
-
msgid "triggered"
msgstr "トリガーã•ã‚ŒãŸ"
@@ -30247,6 +31204,9 @@ msgstr ""
msgid "user avatar"
msgstr "ユーザーã®ã‚¢ãƒã‚¿ãƒ¼"
+msgid "user preferences"
+msgstr ""
+
msgid "username"
msgstr "ユーザーå"
diff --git a/locale/ka_GE/gitlab.po b/locale/ka_GE/gitlab.po
index acc3c40ab0d..1fd442a5ce1 100644
--- a/locale/ka_GE/gitlab.po
+++ b/locale/ka_GE/gitlab.po
@@ -14,7 +14,10 @@ msgstr ""
"X-Crowdin-Language: ka\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 6\n"
-"PO-Revision-Date: 2020-09-04 23:06\n"
+"PO-Revision-Date: 2020-10-02 18:46\n"
+
+msgid " %{project_name}#%{issue_iid} &middot; opened %{issue_created} by %{author}"
+msgstr ""
msgid " %{start} to %{end}"
msgstr ""
@@ -74,6 +77,16 @@ msgstr ""
msgid "\"el\" parameter is required for createInstance()"
msgstr ""
+msgid "%d Approval"
+msgid_plural "%d Approvals"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d Package"
+msgid_plural "%d Packages"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d Scanned URL"
msgid_plural "%d Scanned URLs"
msgstr[0] ""
@@ -137,6 +150,11 @@ msgstr[1] ""
msgid "%d commits"
msgstr ""
+msgid "%d completed issue"
+msgid_plural "%d completed issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d contribution"
msgid_plural "%d contributions"
msgstr[0] ""
@@ -147,6 +165,11 @@ msgid_plural "%d days"
msgstr[0] ""
msgstr[1] ""
+msgid "%d day until tags are automatically removed"
+msgid_plural "%d days until tags are automatically removed"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d error"
msgid_plural "%d errors"
msgstr[0] ""
@@ -237,6 +260,16 @@ msgid_plural "%d more comments"
msgstr[0] ""
msgstr[1] ""
+msgid "%d open issue"
+msgid_plural "%d open issues"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d pending comment"
+msgid_plural "%d pending comments"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d personal project will be removed and cannot be restored."
msgid_plural "%d personal projects will be removed and cannot be restored."
msgstr[0] ""
@@ -252,6 +285,11 @@ msgid_plural "%d projects"
msgstr[0] ""
msgstr[1] ""
+msgid "%d project selected"
+msgid_plural "%d projects selected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d request with warnings"
msgid_plural "%d requests with warnings"
msgstr[0] ""
@@ -272,6 +310,11 @@ msgid_plural "%d tags"
msgstr[0] ""
msgstr[1] ""
+msgid "%d tag per image name"
+msgid_plural "%d tags per image name"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d unassigned issue"
msgid_plural "%d unassigned issues"
msgstr[0] ""
@@ -292,6 +335,11 @@ msgid_plural "%d vulnerabilities dismissed"
msgstr[0] ""
msgstr[1] ""
+msgid "%d warning found:"
+msgid_plural "%d warnings found:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%s additional commit has been omitted to prevent performance issues."
msgid_plural "%s additional commits have been omitted to prevent performance issues."
msgstr[0] ""
@@ -330,6 +378,9 @@ msgstr ""
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr ""
+msgid "%{completedCount} completed weight"
+msgstr ""
+
msgid "%{completedWeight} of %{totalWeight} weight completed"
msgstr ""
@@ -378,14 +429,12 @@ msgid_plural "%{count} participants"
msgstr[0] ""
msgstr[1] ""
-msgid "%{count} pending comment"
-msgid_plural "%{count} pending comments"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
+msgid "%{count} total weight"
+msgstr ""
+
msgid "%{dashboard_path} could not be found."
msgstr ""
@@ -440,6 +489,9 @@ msgstr ""
msgid "%{group_name} uses group managed accounts. You need to create a new GitLab account which will be managed by %{group_name}."
msgstr ""
+msgid "%{group_name}&%{epic_iid} &middot; opened %{epic_created} by %{author}"
+msgstr ""
+
msgid "%{host} sign-in from new location"
msgstr ""
@@ -452,7 +504,7 @@ msgstr ""
msgid "%{issuableType} will be removed! Are you sure?"
msgstr ""
-msgid "%{issuesSize} issues with a limit of %{maxIssueCount}"
+msgid "%{issuesCount} issues with a limit of %{maxIssueCount}"
msgstr ""
msgid "%{issuesSize} with a limit of %{maxIssueCount}"
@@ -485,7 +537,7 @@ msgstr ""
msgid "%{labelStart}Namespace:%{labelEnd} %{namespace}"
msgstr ""
-msgid "%{labelStart}Report Type:%{labelEnd} %{reportType}"
+msgid "%{labelStart}Scan Type:%{labelEnd} %{reportType}"
msgstr ""
msgid "%{labelStart}Scanner:%{labelEnd} %{scanner}"
@@ -682,9 +734,6 @@ msgid_plural "%{securityScanner} results are not available because a pipeline ha
msgstr[0] ""
msgstr[1] ""
-msgid "%{service_title} %{message}."
-msgstr ""
-
msgid "%{size} GiB"
msgstr ""
@@ -773,6 +822,12 @@ msgstr ""
msgid "%{timebox_name} should belong either to a project or a group."
msgstr ""
+msgid "%{timebox_type} does not support burnup charts"
+msgstr ""
+
+msgid "%{timebox_type} must have a start and due date"
+msgstr ""
+
msgid "%{title} %{operator} %{threshold}"
msgstr ""
@@ -797,7 +852,7 @@ msgstr ""
msgid "%{total} open issue weight"
msgstr ""
-msgid "%{total} open issues"
+msgid "%{total} warnings found: showing first %{warningsDisplayed}"
msgstr ""
msgid "%{usage_ping_link_start}Learn more%{usage_ping_link_end} about what information is shared with GitLab Inc."
@@ -830,9 +885,6 @@ msgstr ""
msgid "&lt; 1 hour"
msgstr ""
-msgid "&lt;no name set&gt;"
-msgstr ""
-
msgid "&lt;no scopes selected&gt;"
msgstr ""
@@ -863,6 +915,9 @@ msgstr ""
msgid "'%{name}' Value Stream created"
msgstr ""
+msgid "'%{name}' Value Stream deleted"
+msgstr ""
+
msgid "'%{name}' stage already exists"
msgstr ""
@@ -922,6 +977,9 @@ msgstr ""
msgid "+ %{numberOfHiddenAssignees} more"
msgstr ""
+msgid "+ %{numberOfHiddenReviewers} more"
+msgstr ""
+
msgid "+%d more"
msgid_plural "+%d more"
msgstr[0] ""
@@ -982,6 +1040,11 @@ msgid_plural "%d Days"
msgstr[0] ""
msgstr[1] ""
+msgid "1 Issue"
+msgid_plural "%d Issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "1 closed issue"
msgid_plural "%{issues} closed issues"
msgstr[0] ""
@@ -997,6 +1060,11 @@ msgid_plural "%d days"
msgstr[0] ""
msgstr[1] ""
+msgid "1 deploy key"
+msgid_plural "%d deploy keys"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1099,6 +1167,9 @@ msgstr ""
msgid ":%{startLine} to %{endLine}"
msgstr ""
+msgid "A %{incident_docs_start}modified issue%{incident_docs_end} to guide the resolution of incidents."
+msgstr ""
+
msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr ""
@@ -1111,6 +1182,9 @@ msgstr ""
msgid "A GitBook site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
+msgid "A Gitpod configured Webapplication in Spring and Java"
+msgstr ""
+
msgid "A Hexo site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
@@ -1282,9 +1356,15 @@ msgstr ""
msgid "Access expiration date"
msgstr ""
+msgid "Access expires"
+msgstr ""
+
msgid "Access forbidden. Check your access level."
msgstr ""
+msgid "Access granted"
+msgstr ""
+
msgid "Access requests"
msgstr ""
@@ -1294,6 +1374,9 @@ msgstr ""
msgid "Access to Pages websites are controlled based on the user's membership to a given project. By checking this box, users will be required to be logged in to have access to all Pages websites in your instance."
msgstr ""
+msgid "AccessDropdown|Deploy Keys"
+msgstr ""
+
msgid "AccessDropdown|Groups"
msgstr ""
@@ -1411,12 +1494,6 @@ msgstr ""
msgid "Active Sessions"
msgstr ""
-msgid "Active Users:"
-msgstr ""
-
-msgid "Active users"
-msgstr ""
-
msgid "Activity"
msgstr ""
@@ -1584,9 +1661,6 @@ msgstr ""
msgid "Add label(s)"
msgstr ""
-msgid "Add license"
-msgstr ""
-
msgid "Add list"
msgstr ""
@@ -1761,21 +1835,51 @@ msgstr ""
msgid "AdminArea|Bots"
msgstr ""
+msgid "AdminArea|Components"
+msgstr ""
+
msgid "AdminArea|Developer"
msgstr ""
+msgid "AdminArea|Features"
+msgstr ""
+
+msgid "AdminArea|Groups: %{number_of_groups}"
+msgstr ""
+
msgid "AdminArea|Guest"
msgstr ""
msgid "AdminArea|Included Free in license"
msgstr ""
+msgid "AdminArea|Latest groups"
+msgstr ""
+
+msgid "AdminArea|Latest projects"
+msgstr ""
+
+msgid "AdminArea|Latest users"
+msgstr ""
+
msgid "AdminArea|Maintainer"
msgstr ""
+msgid "AdminArea|New group"
+msgstr ""
+
+msgid "AdminArea|New project"
+msgstr ""
+
+msgid "AdminArea|New user"
+msgstr ""
+
msgid "AdminArea|Owner"
msgstr ""
+msgid "AdminArea|Projects: %{number_of_projects}"
+msgstr ""
+
msgid "AdminArea|Reporter"
msgstr ""
@@ -1803,6 +1907,9 @@ msgstr ""
msgid "AdminArea|Users without a Group and Project"
msgstr ""
+msgid "AdminArea|Users: %{number_of_users}"
+msgstr ""
+
msgid "AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running."
msgstr ""
@@ -1821,9 +1928,6 @@ msgstr ""
msgid "AdminProjects|Delete Project %{projectName}?"
msgstr ""
-msgid "AdminProjects|Delete project"
-msgstr ""
-
msgid "AdminSettings|Apply integration settings to all Projects"
msgstr ""
@@ -2061,21 +2165,30 @@ msgstr ""
msgid "AdminUsers|Without projects"
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 ""
msgid "AdminUsers|You cannot remove your own admin rights."
msgstr ""
+msgid "AdminUsers|You must transfer ownership or delete the groups owned by this user before you can delete their account"
+msgstr ""
+
msgid "Administration"
msgstr ""
msgid "Advanced"
msgstr ""
+msgid "Advanced Search"
+msgstr ""
+
+msgid "Advanced Search with Elasticsearch"
+msgstr ""
+
msgid "Advanced Settings"
msgstr ""
@@ -2153,6 +2266,9 @@ msgstr ""
msgid "AlertManagement|Edit"
msgstr ""
+msgid "AlertManagement|Environment"
+msgstr ""
+
msgid "AlertManagement|Events"
msgstr ""
@@ -2165,6 +2281,9 @@ msgstr ""
msgid "AlertManagement|Issue"
msgstr ""
+msgid "AlertManagement|Key"
+msgstr ""
+
msgid "AlertManagement|Low"
msgstr ""
@@ -2258,6 +2377,9 @@ msgstr ""
msgid "AlertManagement|Unknown"
msgstr ""
+msgid "AlertManagement|Value"
+msgstr ""
+
msgid "AlertManagement|View alerts in Opsgenie"
msgstr ""
@@ -2417,6 +2539,9 @@ msgstr ""
msgid "All projects"
msgstr ""
+msgid "All projects selected"
+msgstr ""
+
msgid "All security scans are enabled because %{linkStart}Auto DevOps%{linkEnd} is enabled on this project"
msgstr ""
@@ -2504,6 +2629,9 @@ msgstr ""
msgid "Almost there"
msgstr ""
+msgid "Already blocked"
+msgstr ""
+
msgid "Also called \"Issuer\" or \"Relying party trust identifier\""
msgstr ""
@@ -2558,6 +2686,9 @@ msgstr ""
msgid "An error has occurred"
msgstr ""
+msgid "An error occured while making the changes: %{error}"
+msgstr ""
+
msgid "An error occurred adding a draft to the thread."
msgstr ""
@@ -2585,12 +2716,6 @@ msgstr ""
msgid "An error occurred when toggling the notification subscription"
msgstr ""
-msgid "An error occurred when trying to resolve a comment. Please try again."
-msgstr ""
-
-msgid "An error occurred when trying to resolve a discussion. Please try again."
-msgstr ""
-
msgid "An error occurred when updating the issue weight"
msgstr ""
@@ -2606,12 +2731,6 @@ msgstr ""
msgid "An error occurred while checking group path. Please refresh and try again."
msgstr ""
-msgid "An error occurred while committing your changes."
-msgstr ""
-
-msgid "An error occurred while creating the list. Please try again."
-msgstr ""
-
msgid "An error occurred while decoding the file."
msgstr ""
@@ -2684,25 +2803,19 @@ msgstr ""
msgid "An error occurred while fetching the Service Desk address."
msgstr ""
-msgid "An error occurred while fetching the board issues. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the board lists. Please reload the page."
msgstr ""
msgid "An error occurred while fetching the board lists. Please try again."
msgstr ""
-msgid "An error occurred while fetching the board swimlanes. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the builds."
msgstr ""
msgid "An error occurred while fetching the job log."
msgstr ""
-msgid "An error occurred while fetching the job trace."
+msgid "An error occurred while fetching the job logs."
msgstr ""
msgid "An error occurred while fetching the job."
@@ -2849,9 +2962,6 @@ msgstr ""
msgid "An error occurred while saving assignees"
msgstr ""
-msgid "An error occurred while saving the template. Please check if the template exists."
-msgstr ""
-
msgid "An error occurred while searching for milestones"
msgstr ""
@@ -2870,10 +2980,10 @@ msgstr ""
msgid "An error occurred while updating approvers"
msgstr ""
-msgid "An error occurred while updating the comment"
+msgid "An error occurred while updating labels."
msgstr ""
-msgid "An error occurred while updating the list. Please try again."
+msgid "An error occurred while updating the comment"
msgstr ""
msgid "An error occurred while validating group path"
@@ -2927,6 +3037,9 @@ msgstr ""
msgid "An unknown error occurred while loading this graph."
msgstr ""
+msgid "An unknown error occurred."
+msgstr ""
+
msgid "Analytics"
msgstr ""
@@ -2960,10 +3073,10 @@ msgstr ""
msgid "Any"
msgstr ""
-msgid "Any Author"
+msgid "Any %{header}"
msgstr ""
-msgid "Any Status"
+msgid "Any Author"
msgstr ""
msgid "Any branch"
@@ -3017,6 +3130,9 @@ msgstr ""
msgid "Application ID"
msgstr ""
+msgid "Application limits saved successfully"
+msgstr ""
+
msgid "Application settings saved successfully"
msgstr ""
@@ -3226,6 +3342,9 @@ msgstr ""
msgid "Are you sure you want to close this blocked issue?"
msgstr ""
+msgid "Are you sure you want to delete \"%{name}\" Value Stream?"
+msgstr ""
+
msgid "Are you sure you want to delete %{name}?"
msgstr ""
@@ -3235,6 +3354,9 @@ msgstr ""
msgid "Are you sure you want to delete this %{typeOfComment}?"
msgstr ""
+msgid "Are you sure you want to delete this SSH key?"
+msgstr ""
+
msgid "Are you sure you want to delete this board?"
msgstr ""
@@ -3259,6 +3381,11 @@ msgstr ""
msgid "Are you sure you want to erase this build?"
msgstr ""
+msgid "Are you sure you want to import %d repository?"
+msgid_plural "Are you sure you want to import %d repositories?"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Are you sure you want to lose unsaved changes?"
msgstr ""
@@ -3268,15 +3395,15 @@ msgstr ""
msgid "Are you sure you want to merge immediately?"
msgstr ""
-msgid "Are you sure you want to permanently delete this license?"
-msgstr ""
-
msgid "Are you sure you want to re-deploy this environment?"
msgstr ""
msgid "Are you sure you want to regenerate the public key? You will have to update the public key on the remote server before mirroring will work again."
msgstr ""
+msgid "Are you sure you want to reindex?"
+msgstr ""
+
msgid "Are you sure you want to remove %{group_name}?"
msgstr ""
@@ -3304,6 +3431,9 @@ msgstr ""
msgid "Are you sure you want to revoke this nickname?"
msgstr ""
+msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
+msgstr ""
+
msgid "Are you sure you want to stop this environment?"
msgstr ""
@@ -3325,6 +3455,9 @@ msgstr ""
msgid "Are you sure? The device will be signed out of GitLab and all remember me tokens revoked."
msgstr ""
+msgid "Are you sure? This will invalidate your registered applications and U2F / WebAuthn devices."
+msgstr ""
+
msgid "Are you sure? This will invalidate your registered applications and U2F devices."
msgstr ""
@@ -3343,9 +3476,6 @@ msgstr ""
msgid "Artifacts"
msgstr ""
-msgid "As U2F devices are only supported by a few browsers, we require that you set up a two-factor authentication app before a U2F device. That way you'll always be able to log in - even when you're using an unsupported browser."
-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 ""
@@ -3539,6 +3669,9 @@ msgstr ""
msgid "AuditLogs|Target"
msgstr ""
+msgid "AuditLogs|This month"
+msgstr ""
+
msgid "AuditLogs|User Events"
msgstr ""
@@ -3578,6 +3711,9 @@ msgstr ""
msgid "Authentication via U2F device failed."
msgstr ""
+msgid "Authentication via WebAuthn device failed."
+msgstr ""
+
msgid "Author"
msgstr ""
@@ -3845,15 +3981,6 @@ msgstr ""
msgid "BambooService|You must set up automatic revision labeling and a repository trigger in Bamboo."
msgstr ""
-msgid "BatchComments|Delete all pending comments"
-msgstr ""
-
-msgid "BatchComments|Discard review?"
-msgstr ""
-
-msgid "BatchComments|You're about to discard your review which will delete all of your pending comments. The deleted comments %{strong_start}cannot%{strong_end} be restored."
-msgstr ""
-
msgid "Be careful. Changing the project's namespace can have unintended side effects."
msgstr ""
@@ -3875,6 +4002,9 @@ msgstr ""
msgid "Bi-weekly code coverage"
msgstr ""
+msgid "Billable Users:"
+msgstr ""
+
msgid "Billing"
msgstr ""
@@ -3884,7 +4014,7 @@ msgstr ""
msgid "BillingPlans|@%{user_name} you are currently using the %{plan_name} plan."
msgstr ""
-msgid "BillingPlans|Congratulations, your new trial is activated"
+msgid "BillingPlans|Congratulations, your free trial is activated."
msgstr ""
msgid "BillingPlans|If you would like to downgrade your plan please contact %{support_link_start}Customer Support%{support_link_end}."
@@ -3947,6 +4077,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Block user"
+msgstr ""
+
msgid "Blocked"
msgstr ""
@@ -3962,31 +4095,37 @@ msgstr ""
msgid "Blog"
msgstr ""
-msgid "Board name"
-msgstr ""
-
msgid "Board scope"
msgstr ""
msgid "Board scope affects which issues are displayed for anyone who visits this board"
msgstr ""
-msgid "BoardBlankState|Add default lists"
+msgid "Boards"
msgstr ""
-msgid "BoardBlankState|Add the following default lists to your Issue Board with one click:"
+msgid "Boards and Board Lists"
msgstr ""
-msgid "BoardBlankState|Nevermind, I'll use my own"
+msgid "Boards|An error occurred while creating the issue. Please try again."
msgstr ""
-msgid "BoardBlankState|Starting out with the default set of lists will get you right on the way to making the most of your board."
+msgid "Boards|An error occurred while creating the list. Please try again."
msgstr ""
-msgid "Boards"
+msgid "Boards|An error occurred while fetching issues. Please reload the page."
msgstr ""
-msgid "Boards and Board Lists"
+msgid "Boards|An error occurred while fetching the board issues. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching the board swimlanes. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while moving the issue. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while updating the list. Please try again."
msgstr ""
msgid "Boards|Collapse"
@@ -4013,7 +4152,7 @@ msgstr ""
msgid "Branch %{branch_name} was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr ""
-msgid "Branch has changed"
+msgid "Branch changed"
msgstr ""
msgid "Branch is already taken"
@@ -4319,6 +4458,9 @@ msgstr ""
msgid "CLOSED (MOVED)"
msgstr ""
+msgid "CODEOWNERS rule violation"
+msgstr ""
+
msgid "CONTRIBUTING"
msgstr ""
@@ -4349,9 +4491,6 @@ msgstr ""
msgid "Can't create snippet: %{err}"
msgstr ""
-msgid "Can't edit as source branch was deleted"
-msgstr ""
-
msgid "Can't fetch content for the blob: %{err}"
msgstr ""
@@ -4364,9 +4503,6 @@ msgstr ""
msgid "Can't load mermaid module: %{err}"
msgstr ""
-msgid "Can't remove group members without group managed account"
-msgstr ""
-
msgid "Can't scan the code?"
msgstr ""
@@ -4409,6 +4545,9 @@ msgstr ""
msgid "Cannot create the abuse report. This user has been blocked."
msgstr ""
+msgid "Cannot enable shared runners because parent group does not allow it"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -4514,6 +4653,15 @@ msgstr ""
msgid "Change your password or recover your current one"
msgstr ""
+msgid "ChangeReviewer|Reviewer changed from %{old} to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Reviewer changed to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Unassigned"
+msgstr ""
+
msgid "ChangeTypeActionLabel|Pick into branch"
msgstr ""
@@ -4553,6 +4701,9 @@ msgstr ""
msgid "Changes the title to \"%{title_param}\"."
msgstr ""
+msgid "Changes were successfully made."
+msgstr ""
+
msgid "Changes won't take place until the index is %{link_start}recreated%{link_end}."
msgstr ""
@@ -4958,6 +5109,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove variable"
+msgstr ""
+
msgid "CiVariables|Remove variable row"
msgstr ""
@@ -5036,9 +5190,6 @@ msgstr ""
msgid "Clear due date"
msgstr ""
-msgid "Clear input"
-msgstr ""
-
msgid "Clear recent searches"
msgstr ""
@@ -5087,6 +5238,9 @@ msgstr ""
msgid "Client authentication key password"
msgstr ""
+msgid "Client request timeout"
+msgstr ""
+
msgid "Clients"
msgstr ""
@@ -5171,6 +5325,27 @@ msgstr ""
msgid "Cluster type must be specificed for Stages::ClusterEndpointInserter"
msgstr ""
+msgid "ClusterAgents|Configuration"
+msgstr ""
+
+msgid "ClusterAgents|Connect your cluster with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate Kubernetes with a GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Name"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Agent also requires %{linkStart}enabling the Agent Server%{linkEnd}"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Kubernetes Agent allows an Infrastructure as Code, GitOps approach to integrating Kubernetes clusters with GitLab. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "ClusterAgent|This feature is only available for premium plans"
msgstr ""
@@ -5240,10 +5415,10 @@ msgstr ""
msgid "ClusterIntegration|All installed applications and related resources"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster."
+msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{linkStart}More information%{linkEnd}"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{startLink}More information%{endLink}"
+msgid "ClusterIntegration|Allow GitLab to manage namespaces and service accounts for this cluster."
msgstr ""
msgid "ClusterIntegration|Alternatively, "
@@ -5264,6 +5439,9 @@ msgstr ""
msgid "ClusterIntegration|An error occurred while trying to fetch zone machine types: %{error}"
msgstr ""
+msgid "ClusterIntegration|An unknown error occurred while attempting to connect to Kubernetes."
+msgstr ""
+
msgid "ClusterIntegration|Any project namespaces"
msgstr ""
@@ -5279,6 +5457,9 @@ msgstr ""
msgid "ClusterIntegration|Authenticate with Amazon Web Services"
msgstr ""
+msgid "ClusterIntegration|Authentication Error"
+msgstr ""
+
msgid "ClusterIntegration|Base domain"
msgstr ""
@@ -5297,13 +5478,22 @@ msgstr ""
msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}security group %{externalLinkIcon} %{endLink} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
+msgid "ClusterIntegration|Check your CA certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Check your cluster status"
+msgstr ""
+
+msgid "ClusterIntegration|Check your token"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}subnets %{externalLinkIcon} %{endLink} in your VPC where your worker nodes will run."
+msgid "ClusterIntegration|Choose the %{linkStart}security group %{linkEnd} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
msgstr ""
-msgid "ClusterIntegration|Choose the worker node %{startLink}instance type %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Choose the %{linkStart}subnets %{linkEnd} in your VPC where your worker nodes will run."
+msgstr ""
+
+msgid "ClusterIntegration|Choose the worker node %{linkStart}instance type%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Choose which applications to install on your Kubernetes cluster."
@@ -5315,10 +5505,7 @@ msgstr ""
msgid "ClusterIntegration|Clear cluster cache"
msgstr ""
-msgid "ClusterIntegration|Clear the local cache of namespace and service accounts. This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
-msgstr ""
-
-msgid "ClusterIntegration|Cluster being created"
+msgid "ClusterIntegration|Clear the local cache of namespace and service accounts."
msgstr ""
msgid "ClusterIntegration|Cluster management project (alpha)"
@@ -5330,15 +5517,21 @@ msgstr ""
msgid "ClusterIntegration|Cluster_applications artifact too big. Maximum allowable size: %{human_size}"
msgstr ""
-msgid "ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters."
+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|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}"
+msgid "ClusterIntegration|Clusters connected with a certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Connect cluster with certificate"
msgstr ""
msgid "ClusterIntegration|Connect existing cluster"
msgstr ""
+msgid "ClusterIntegration|Connection Error"
+msgstr ""
+
msgid "ClusterIntegration|Copy API URL"
msgstr ""
@@ -5414,6 +5607,12 @@ msgstr ""
msgid "ClusterIntegration|Deletes all GitLab resources attached to this cluster during removal"
msgstr ""
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared."
+msgstr ""
+
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared. %{linkStart}More information%{linkEnd}"
+msgstr ""
+
msgid "ClusterIntegration|Did you know?"
msgstr ""
@@ -5483,6 +5682,9 @@ msgstr ""
msgid "ClusterIntegration|Fluentd is an open source data collector, which lets you unify the data collection and consumption for a better use and understanding of data. It requires at least one of the following logs to be successfully installed."
msgstr ""
+msgid "ClusterIntegration|GitLab Agent managed clusters"
+msgstr ""
+
msgid "ClusterIntegration|GitLab Container Network Policies"
msgstr ""
@@ -5495,6 +5697,12 @@ msgstr ""
msgid "ClusterIntegration|GitLab Runner connects to the repository and executes CI/CD jobs, pushing results back and deploying applications to production."
msgstr ""
+msgid "ClusterIntegration|GitLab failed to authenticate."
+msgstr ""
+
+msgid "ClusterIntegration|GitLab failed to connect to the cluster."
+msgstr ""
+
msgid "ClusterIntegration|GitLab-managed cluster"
msgstr ""
@@ -5516,6 +5724,9 @@ msgstr ""
msgid "ClusterIntegration|Group cluster"
msgstr ""
+msgid "ClusterIntegration|HTTP Error"
+msgstr ""
+
msgid "ClusterIntegration|Helm Tiller"
msgstr ""
@@ -5549,7 +5760,10 @@ msgstr ""
msgid "ClusterIntegration|Instance type"
msgstr ""
-msgid "ClusterIntegration|Integrate Kubernetes cluster automation"
+msgid "ClusterIntegration|Integrate Kubernetes with a cluster certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Integrate with a cluster certificate"
msgstr ""
msgid "ClusterIntegration|Issuer Email"
@@ -5585,9 +5799,6 @@ msgstr ""
msgid "ClusterIntegration|Knative extends Kubernetes to provide a set of middleware components that are essential to build modern, source-centric, and container-based applications that can run anywhere: on premises, in the cloud, or even in a third-party data center."
msgstr ""
-msgid "ClusterIntegration|Kubernetes cluster"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes cluster is being created..."
msgstr ""
@@ -5600,9 +5811,6 @@ msgstr ""
msgid "ClusterIntegration|Kubernetes clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr ""
-msgid "ClusterIntegration|Kubernetes clusters can be used to deploy applications and to provide Review Apps for this project"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes version"
msgstr ""
@@ -5615,7 +5823,7 @@ msgstr ""
msgid "ClusterIntegration|Learn more about %{help_link_start}zones%{help_link_end}."
msgstr ""
-msgid "ClusterIntegration|Learn more about %{startLink}Regions %{externalLinkIcon}%{endLink}."
+msgid "ClusterIntegration|Learn more about %{linkStart}Regions%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Learn more about Kubernetes"
@@ -5660,12 +5868,18 @@ msgstr ""
msgid "ClusterIntegration|Machine type"
msgstr ""
+msgid "ClusterIntegration|Make sure your API endpoint is correct"
+msgstr ""
+
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create Kubernetes clusters"
msgstr ""
msgid "ClusterIntegration|Manage your Kubernetes cluster by visiting %{provider_link}"
msgstr ""
+msgid "ClusterIntegration|Namespace per environment"
+msgstr ""
+
msgid "ClusterIntegration|No IAM Roles found"
msgstr ""
@@ -5711,6 +5925,9 @@ msgstr ""
msgid "ClusterIntegration|No zones matched your search"
msgstr ""
+msgid "ClusterIntegration|Node calculations use the Kubernetes Metrics API. Make sure your cluster has metrics installed"
+msgstr ""
+
msgid "ClusterIntegration|Number of nodes"
msgstr ""
@@ -5753,6 +5970,9 @@ msgstr ""
msgid "ClusterIntegration|RBAC-enabled cluster"
msgstr ""
+msgid "ClusterIntegration|Read our %{linkStart}help page%{linkEnd} on Kubernetes cluster integration."
+msgstr ""
+
msgid "ClusterIntegration|Read our %{link_start}help page%{link_end} on Kubernetes cluster integration."
msgstr ""
@@ -5855,7 +6075,7 @@ msgstr ""
msgid "ClusterIntegration|Select a VPC to choose a subnet"
msgstr ""
-msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{linkStart}Amazon Web Services %{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select a network to choose a subnetwork"
@@ -5888,7 +6108,7 @@ msgstr ""
msgid "ClusterIntegration|Select project to choose zone"
msgstr ""
-msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select zone"
@@ -5978,9 +6198,18 @@ msgstr ""
msgid "ClusterIntegration|There was a problem authenticating with your cluster. Please ensure your CA Certificate and Token are valid."
msgstr ""
+msgid "ClusterIntegration|There was an HTTP error when connecting to your cluster."
+msgstr ""
+
msgid "ClusterIntegration|This account must have permissions to create a Kubernetes cluster in the %{link_to_container_project} specified below"
msgstr ""
+msgid "ClusterIntegration|This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
+msgstr ""
+
+msgid "ClusterIntegration|This is necessary to clear existing environment-namespace associations from clusters previously managed by GitLab."
+msgstr ""
+
msgid "ClusterIntegration|This option will allow you to install applications on RBAC clusters."
msgstr ""
@@ -6005,9 +6234,21 @@ msgstr ""
msgid "ClusterIntegration|To use a new project, first create one on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}."
msgstr ""
+msgid "ClusterIntegration|Troubleshooting tips:"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Authenticate"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Connect"
+msgstr ""
+
msgid "ClusterIntegration|Uninstall %{appTitle}"
msgstr ""
+msgid "ClusterIntegration|Unknown Error"
+msgstr ""
+
msgid "ClusterIntegration|Update %{appTitle}"
msgstr ""
@@ -6068,7 +6309,7 @@ msgstr ""
msgid "ClusterIntegration|Your cluster API is unreachable. Please ensure your API URL is correct."
msgstr ""
-msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Zone"
@@ -6188,6 +6429,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse all threads"
+msgstr ""
+
msgid "Collapse approvers"
msgstr ""
@@ -6337,7 +6581,7 @@ msgstr ""
msgid "Commit…"
msgstr ""
-msgid "Company"
+msgid "Community forum"
msgstr ""
msgid "Company name"
@@ -6346,6 +6590,9 @@ msgstr ""
msgid "Compare"
msgstr ""
+msgid "Compare %{oldCommitId}...%{newCommitId}"
+msgstr ""
+
msgid "Compare Git revisions"
msgstr ""
@@ -6361,6 +6608,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare submodule commit revisions"
+msgstr ""
+
msgid "Compare with previous version"
msgstr ""
@@ -6496,6 +6746,9 @@ msgstr ""
msgid "Configure the way a user creates a new account."
msgstr ""
+msgid "Configure which lists are shown for anyone who visits this board"
+msgstr ""
+
msgid "Confirm"
msgstr ""
@@ -6721,6 +6974,9 @@ msgstr[1] ""
msgid "ContainerRegistry|Set cleanup policy"
msgstr ""
+msgid "ContainerRegistry|Some tags were not deleted"
+msgstr ""
+
msgid "ContainerRegistry|Something went wrong while fetching the cleanup policy."
msgstr ""
@@ -6760,6 +7016,9 @@ msgstr ""
msgid "ContainerRegistry|Tags with names matching this regex pattern will %{italicStart}expire:%{italicEnd}"
msgstr ""
+msgid "ContainerRegistry|The cleanup policy timed out before it could delete all tags. An administrator can %{adminLinkStart}manually run cleanup now%{adminLinkEnd} or you can wait for the cleanup policy to automatically run again. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "ContainerRegistry|The last tag related to this image was recently removed. This empty image and any associated data will be automatically removed as part of the regular Garbage Collection process. If you have any questions, contact your administrator."
msgstr ""
@@ -6892,6 +7151,9 @@ msgstr ""
msgid "Contributions per group member"
msgstr ""
+msgid "Contributor"
+msgstr ""
+
msgid "Contributors"
msgstr ""
@@ -7021,6 +7283,9 @@ msgstr ""
msgid "Could not change HEAD: branch '%{branch}' does not exist"
msgstr ""
+msgid "Could not commit. An unexpected error occurred."
+msgstr ""
+
msgid "Could not connect to FogBugz, check your URL"
msgstr ""
@@ -7060,6 +7325,9 @@ msgstr ""
msgid "Could not find iteration"
msgstr ""
+msgid "Could not load instance counts. Please refresh the page to try again."
+msgstr ""
+
msgid "Could not remove the trigger."
msgstr ""
@@ -7084,10 +7352,10 @@ msgstr ""
msgid "Could not save prometheus manual configuration"
msgstr ""
-msgid "Could not udpdate wiki page"
+msgid "Could not update the LDAP settings"
msgstr ""
-msgid "Could not update the LDAP settings"
+msgid "Could not update wiki page"
msgstr ""
msgid "Could not upload your designs as one or more files uploaded are not supported."
@@ -7745,6 +8013,9 @@ msgstr ""
msgid "DastProfiles|Are you sure you want to delete this profile?"
msgstr ""
+msgid "DastProfiles|Could not create site validation token. Please refresh the page, or try again later."
+msgstr ""
+
msgid "DastProfiles|Could not create the scanner profile. Please try again."
msgstr ""
@@ -7769,6 +8040,12 @@ msgstr ""
msgid "DastProfiles|Could not fetch site profiles. Please refresh the page, or try again later."
msgstr ""
+msgid "DastProfiles|Could not retrieve site validation status. Please refresh the page, or try again later."
+msgstr ""
+
+msgid "DastProfiles|Could not update the scanner profile. Please try again."
+msgstr ""
+
msgid "DastProfiles|Could not update the site profile. Please try again."
msgstr ""
@@ -7784,7 +8061,7 @@ msgstr ""
msgid "DastProfiles|Download validation text file"
msgstr ""
-msgid "DastProfiles|Edit feature will come soon. Please create a new profile if changes needed"
+msgid "DastProfiles|Edit scanner profile"
msgstr ""
msgid "DastProfiles|Edit site profile"
@@ -7817,6 +8094,9 @@ msgstr ""
msgid "DastProfiles|No profiles created yet"
msgstr ""
+msgid "DastProfiles|Passive"
+msgstr ""
+
msgid "DastProfiles|Please enter a valid URL format, ex: http://www.example.com/home"
msgstr ""
@@ -7832,6 +8112,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan mode"
+msgstr ""
+
msgid "DastProfiles|Scanner Profile"
msgstr ""
@@ -7871,10 +8154,10 @@ msgstr ""
msgid "DastProfiles|Text file validation"
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
+msgid "DastProfiles|The maximum number of minutes allowed for the spider to traverse the site."
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the spider to traverse the site."
+msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
msgstr ""
msgid "DastProfiles|Validate"
@@ -7907,6 +8190,9 @@ msgstr ""
msgid "Date picker"
msgstr ""
+msgid "Date range"
+msgstr ""
+
msgid "Date range cannot exceed %{maxDateRange} days."
msgstr ""
@@ -7931,6 +8217,9 @@ msgstr ""
msgid "Days to merge"
msgstr ""
+msgid "Dear Administrator,"
+msgstr ""
+
msgid "Debug"
msgstr ""
@@ -8042,12 +8331,18 @@ msgstr ""
msgid "Delete"
msgstr ""
+msgid "Delete %{name}"
+msgstr ""
+
msgid "Delete Comment"
msgstr ""
msgid "Delete Snippet"
msgstr ""
+msgid "Delete Value Stream"
+msgstr ""
+
msgid "Delete account"
msgstr ""
@@ -8069,9 +8364,6 @@ msgstr ""
msgid "Delete label: %{label_name} ?"
msgstr ""
-msgid "Delete license"
-msgstr ""
-
msgid "Delete list"
msgstr ""
@@ -8147,15 +8439,6 @@ msgstr ""
msgid "Deleting a project places it into a read-only state until %{date}, at which point the project will be permanently deleted. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "Deleting the license failed."
-msgstr ""
-
-msgid "Deleting the license failed. The license was not found."
-msgstr ""
-
-msgid "Deleting the license failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "Deleting the project will delete its repository and all related resources including issues, merge requests etc."
msgstr ""
@@ -8651,7 +8934,10 @@ msgstr ""
msgid "DesignManagement|The maximum number of designs allowed to be uploaded is %{upload_limit}. Please try again."
msgstr ""
-msgid "DesignManagement|To upload designs, you'll need to enable LFS. %{requirements_link_start}More information%{requirements_link_end}"
+msgid "DesignManagement|There was an error moving your designs. Please upload your designs below."
+msgstr ""
+
+msgid "DesignManagement|To upload designs, you'll need to enable LFS and have admin enable hashed storage. %{requirements_link_start}More information%{requirements_link_end}"
msgstr ""
msgid "DesignManagement|Unresolve thread"
@@ -8663,6 +8949,9 @@ msgstr ""
msgid "DesignManagement|Upload skipped."
msgstr ""
+msgid "DesignManagement|Your designs are being copied and are on their way… Please refresh to update."
+msgstr ""
+
msgid "DesignManagement|and %{moreCount} more."
msgstr ""
@@ -8720,6 +9009,9 @@ msgstr ""
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
+msgid "Direct member"
+msgstr ""
+
msgid "Direction"
msgstr ""
@@ -8768,9 +9060,6 @@ msgstr ""
msgid "Discard draft"
msgstr ""
-msgid "Discard review"
-msgstr ""
-
msgid "DiscordService|Discord Notifications"
msgstr ""
@@ -8839,10 +9128,10 @@ msgstr ""
msgid "Dismiss Merge Request promotion"
msgstr ""
-msgid "Dismiss Selected"
+msgid "Dismiss Value Stream Analytics introduction box"
msgstr ""
-msgid "Dismiss Value Stream Analytics introduction box"
+msgid "Dismiss selected"
msgstr ""
msgid "Dismiss trial promotion"
@@ -8893,9 +9182,6 @@ msgstr ""
msgid "Documents reindexed: %{processed_documents} (%{percentage}%%)"
msgstr ""
-msgid "Doing"
-msgstr ""
-
msgid "Domain"
msgstr ""
@@ -9091,9 +9377,6 @@ msgstr ""
msgid "Edit environment"
msgstr ""
-msgid "Edit file"
-msgstr ""
-
msgid "Edit files in the editor and commit changes here"
msgstr ""
@@ -9106,6 +9389,12 @@ msgstr ""
msgid "Edit identity for %{user_name}"
msgstr ""
+msgid "Edit in Web IDE"
+msgstr ""
+
+msgid "Edit in single-file editor"
+msgstr ""
+
msgid "Edit issues"
msgstr ""
@@ -9133,10 +9422,10 @@ msgstr ""
msgid "Editing"
msgstr ""
-msgid "Elasticsearch"
+msgid "Elasticsearch AWS IAM credentials"
msgstr ""
-msgid "Elasticsearch AWS IAM credentials"
+msgid "Elasticsearch HTTP client timeout value in seconds."
msgstr ""
msgid "Elasticsearch indexing restrictions"
@@ -9145,9 +9434,6 @@ msgstr ""
msgid "Elasticsearch indexing started"
msgstr ""
-msgid "Elasticsearch integration. Elasticsearch AWS IAM."
-msgstr ""
-
msgid "Elasticsearch reindexing is already in progress"
msgstr ""
@@ -9175,9 +9461,6 @@ msgstr ""
msgid "Email Notification"
msgstr ""
-msgid "Email address"
-msgstr ""
-
msgid "Email could not be sent"
msgstr ""
@@ -9241,6 +9524,9 @@ msgstr ""
msgid "Emails sent from Service Desk will have this name"
msgstr ""
+msgid "Emails sent to %{email} will still be supported"
+msgstr ""
+
msgid "Emails separated by comma"
msgstr ""
@@ -9274,9 +9560,18 @@ msgstr ""
msgid "Enable"
msgstr ""
+msgid "Enable %{link_start}Gitpod%{link_end} integration to launch a development environment in your browser directly from GitLab."
+msgstr ""
+
msgid "Enable Auto DevOps"
msgstr ""
+msgid "Enable Gitpod"
+msgstr ""
+
+msgid "Enable Gitpod?"
+msgstr ""
+
msgid "Enable HTML emails"
msgstr ""
@@ -9406,9 +9701,6 @@ msgstr ""
msgid "Encountered an error while rendering: %{err}"
msgstr ""
-msgid "End date"
-msgstr ""
-
msgid "Ends at (UTC)"
msgstr ""
@@ -9568,7 +9860,7 @@ msgstr ""
msgid "EnvironmentsDashboard|The environments dashboard provides a summary of each project's environments' status, including pipeline and alert statuses."
msgstr ""
-msgid "EnvironmentsDashboard|This dashboard displays a maximum of 7 projects and 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
+msgid "EnvironmentsDashboard|This dashboard displays 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
msgstr ""
msgid "Environments|An error occurred while canceling the auto stop, please try again"
@@ -9889,6 +10181,9 @@ msgstr ""
msgid "Error deleting project. Check logs for error details."
msgstr ""
+msgid "Error fetching burnup chart data"
+msgstr ""
+
msgid "Error fetching diverging counts for branches. Please try again."
msgstr ""
@@ -9967,6 +10262,9 @@ msgstr ""
msgid "Error occurred when saving assignees"
msgstr ""
+msgid "Error occurred when saving reviewers"
+msgstr ""
+
msgid "Error occurred when toggling the notification subscription"
msgstr ""
@@ -10219,10 +10517,13 @@ msgstr ""
msgid "Expand all"
msgstr ""
-msgid "Expand approvers"
+msgid "Expand all files"
msgstr ""
-msgid "Expand dropdown"
+msgid "Expand all threads"
+msgstr ""
+
+msgid "Expand approvers"
msgstr ""
msgid "Expand milestones"
@@ -10393,6 +10694,9 @@ msgstr ""
msgid "Failed to create Merge Request. Please try again."
msgstr ""
+msgid "Failed to create To-Do for the design."
+msgstr ""
+
msgid "Failed to create a branch for this issue. Please try again."
msgstr ""
@@ -10432,6 +10736,12 @@ msgstr ""
msgid "Failed to load authors. Please try again."
msgstr ""
+msgid "Failed to load branches. Please try again."
+msgstr ""
+
+msgid "Failed to load deploy keys."
+msgstr ""
+
msgid "Failed to load emoji list."
msgstr ""
@@ -10447,6 +10757,9 @@ msgstr ""
msgid "Failed to load groups & users."
msgstr ""
+msgid "Failed to load groups, users and deploy keys."
+msgstr ""
+
msgid "Failed to load labels. Please try again."
msgstr ""
@@ -10456,6 +10769,12 @@ msgstr ""
msgid "Failed to load related branches"
msgstr ""
+msgid "Failed to load sidebar confidential toggle"
+msgstr ""
+
+msgid "Failed to load sidebar lock status"
+msgstr ""
+
msgid "Failed to load stacktrace."
msgstr ""
@@ -10483,6 +10802,9 @@ msgstr ""
msgid "Failed to publish issue on status page."
msgstr ""
+msgid "Failed to remove To-Do for the design."
+msgstr ""
+
msgid "Failed to remove a Zoom meeting"
msgstr ""
@@ -10525,6 +10847,9 @@ msgstr ""
msgid "Failed to signing using smartcard authentication"
msgstr ""
+msgid "Failed to toggle To-Do for the design."
+msgstr ""
+
msgid "Failed to update branch!"
msgstr ""
@@ -10638,7 +10963,7 @@ msgstr ""
msgid "FeatureFlags|Edit User List"
msgstr ""
-msgid "FeatureFlags|Enable features for specific users and specific environments by defining feature flag strategies."
+msgid "FeatureFlags|Enable features for specific users and environments by configuring feature flag strategies."
msgstr ""
msgid "FeatureFlags|Environment Spec"
@@ -10698,7 +11023,7 @@ msgstr ""
msgid "FeatureFlags|Include additional user IDs"
msgstr ""
-msgid "FeatureFlags|Install a %{docs_link_anchored_start}compatible client library%{docs_link_anchored_end} and specify the API URL, application name, and instance ID during the configuration setup. %{docs_link_start}More Information%{docs_link_end}"
+msgid "FeatureFlags|Install a %{docsLinkAnchoredStart}compatible client library%{docsLinkAnchoredEnd} and specify the API URL, application name, and instance ID during the configuration setup. %{docsLinkStart}More Information%{docsLinkEnd}"
msgstr ""
msgid "FeatureFlags|Instance ID"
@@ -10710,6 +11035,9 @@ msgstr ""
msgid "FeatureFlags|Loading feature flags"
msgstr ""
+msgid "FeatureFlags|Loading user lists"
+msgstr ""
+
msgid "FeatureFlags|More information"
msgstr ""
@@ -10728,7 +11056,7 @@ msgstr ""
msgid "FeatureFlags|New feature flag"
msgstr ""
-msgid "FeatureFlags|New list"
+msgid "FeatureFlags|New user list"
msgstr ""
msgid "FeatureFlags|Percent of users"
@@ -10767,6 +11095,9 @@ msgstr ""
msgid "FeatureFlags|There was an error fetching the feature flags."
msgstr ""
+msgid "FeatureFlags|There was an error fetching the user lists."
+msgstr ""
+
msgid "FeatureFlags|There was an error retrieving user lists"
msgstr ""
@@ -10782,6 +11113,9 @@ msgstr ""
msgid "FeatureFlags|User List"
msgstr ""
+msgid "FeatureFlags|User Lists"
+msgstr ""
+
msgid "FeatureFlag|List"
msgstr ""
@@ -10809,15 +11143,6 @@ msgstr ""
msgid "Fetching incoming email"
msgstr ""
-msgid "Fetching licenses failed."
-msgstr ""
-
-msgid "Fetching licenses failed. The request endpoint was not found."
-msgstr ""
-
-msgid "Fetching licenses failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "File"
msgstr ""
@@ -10920,12 +11245,21 @@ msgstr ""
msgid "Filter by status"
msgstr ""
+msgid "Filter by test cases that are currently archived."
+msgstr ""
+
+msgid "Filter by test cases that are currently opened."
+msgstr ""
+
msgid "Filter by two-factor authentication"
msgstr ""
msgid "Filter by user"
msgstr ""
+msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
+msgstr ""
+
msgid "Filter pipelines"
msgstr ""
@@ -10941,7 +11275,7 @@ msgstr ""
msgid "Filter results..."
msgstr ""
-msgid "Filter your projects by name"
+msgid "Filter your repositories by name"
msgstr ""
msgid "Filter..."
@@ -10950,7 +11284,7 @@ msgstr ""
msgid "Find File"
msgstr ""
-msgid "Find bugs in your code with coverage-guided fuzzing"
+msgid "Find bugs in your code with coverage-guided fuzzing."
msgstr ""
msgid "Find by path"
@@ -10977,9 +11311,6 @@ msgstr ""
msgid "Finish editing this message first!"
msgstr ""
-msgid "Finish review"
-msgstr ""
-
msgid "Finish setting up your dedicated account for %{group_name}."
msgstr ""
@@ -11049,6 +11380,9 @@ msgstr ""
msgid "Footer message"
msgstr ""
+msgid "For a faster browsing experience, some files are collapsed by default."
+msgstr ""
+
msgid "For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
@@ -11058,6 +11392,9 @@ msgstr ""
msgid "For more info, read the documentation."
msgstr ""
+msgid "For more information on how the number of active users is calculated, see the %{self_managed_subscriptions_doc_link} documentation."
+msgstr ""
+
msgid "For more information, go to the "
msgstr ""
@@ -11196,6 +11533,9 @@ msgstr ""
msgid "Generate new token"
msgstr ""
+msgid "Generic package file size in bytes"
+msgstr ""
+
msgid "Geo"
msgstr ""
@@ -11457,6 +11797,9 @@ msgstr ""
msgid "Geo|Please refer to Geo Troubleshooting."
msgstr ""
+msgid "Geo|Primary node"
+msgstr ""
+
msgid "Geo|Project"
msgstr ""
@@ -11499,6 +11842,9 @@ msgstr ""
msgid "Geo|Review replication status, and resynchronize and reverify items with the primary node."
msgstr ""
+msgid "Geo|Secondary node"
+msgstr ""
+
msgid "Geo|Status"
msgstr ""
@@ -11538,6 +11884,9 @@ msgstr ""
msgid "Geo|URL must be a valid url (ex: https://gitlab.com)"
msgstr ""
+msgid "Geo|Undefined"
+msgstr ""
+
msgid "Geo|Unknown state"
msgstr ""
@@ -11613,10 +11962,16 @@ msgstr ""
msgid "GitHub import"
msgstr ""
+msgid "GitLab"
+msgstr ""
+
msgid "GitLab / Unsubscribe"
msgstr ""
-msgid "GitLab Enterprise Edition %{plan}"
+msgid "GitLab API"
+msgstr ""
+
+msgid "GitLab Billing Team."
msgstr ""
msgid "GitLab Group Runners can execute code for all the projects in this group."
@@ -11628,12 +11983,18 @@ msgstr ""
msgid "GitLab Issue"
msgstr ""
+msgid "GitLab Pages"
+msgstr ""
+
msgid "GitLab Service Desk is a simple way to allow people to create issues in your GitLab instance without needing their own user account. It provides a unique email address for end users to create issues in a project, and replies can be sent either through the GitLab interface or by email. End users will only see the thread through email."
msgstr ""
msgid "GitLab Shared Runners execute code of different projects on the same Runner unless you configure GitLab Runner Autoscale with MaxBuilds 1 (which it is on GitLab.com)."
msgstr ""
+msgid "GitLab Shell"
+msgstr ""
+
msgid "GitLab Support Bot"
msgstr ""
@@ -11643,7 +12004,7 @@ msgstr ""
msgid "GitLab User"
msgstr ""
-msgid "GitLab allows you to continue using your license even if you exceed the number of seats you purchased. You will be required to pay for these seats when you renew your license."
+msgid "GitLab Workhorse"
msgstr ""
msgid "GitLab commit"
@@ -11811,6 +12172,21 @@ msgstr ""
msgid "Gitlab Pages"
msgstr ""
+msgid "Gitpod"
+msgstr ""
+
+msgid "Gitpod|Add the URL to your Gitpod instance configured to read your GitLab projects."
+msgstr ""
+
+msgid "Gitpod|Enable Gitpod integration"
+msgstr ""
+
+msgid "Gitpod|Gitpod URL"
+msgstr ""
+
+msgid "Gitpod|e.g. https://gitpod.example.com"
+msgstr ""
+
msgid "Given access %{time_ago}"
msgstr ""
@@ -12318,9 +12694,6 @@ msgstr ""
msgid "GroupSAML|Valid SAML Response"
msgstr ""
-msgid "GroupSAML|With group managed accounts enabled, all the users without a group managed account will be excluded from the group."
-msgstr ""
-
msgid "GroupSAML|With prohibit outer forks flag enabled group members will be able to fork project only inside your group."
msgstr ""
@@ -12534,10 +12907,10 @@ msgstr ""
msgid "GroupsNew|Create group"
msgstr ""
-msgid "GroupsNew|GitLab group export"
+msgid "GroupsNew|Import"
msgstr ""
-msgid "GroupsNew|Import"
+msgid "GroupsNew|Import a GitLab group export file"
msgstr ""
msgid "GroupsNew|Import group"
@@ -12680,6 +13053,9 @@ msgid_plural "Hide charts"
msgstr[0] ""
msgstr[1] ""
+msgid "Hide comments on this file"
+msgstr ""
+
msgid "Hide details"
msgstr ""
@@ -12724,6 +13100,15 @@ msgstr ""
msgid "Highest role:"
msgstr ""
+msgid "HighlightBar|Alert events:"
+msgstr ""
+
+msgid "HighlightBar|Alert start time:"
+msgstr ""
+
+msgid "HighlightBar|Original alert:"
+msgstr ""
+
msgid "History"
msgstr ""
@@ -12901,6 +13286,9 @@ msgstr ""
msgid "If enabled, access to projects will be validated on an external service using their classification label."
msgstr ""
+msgid "If the number of active users exceeds the user limit, you will be charged for the number of %{users_over_license_link} at your next license reconciliation."
+msgstr ""
+
msgid "If there is no previous license or if the previous license has expired, some GitLab functionality will be blocked until a new, valid license is uploaded."
msgstr ""
@@ -12940,9 +13328,6 @@ msgstr ""
msgid "If your HTTP repository is not publicly accessible, add your credentials."
msgstr ""
-msgid "Iglu registry URL (optional)"
-msgstr ""
-
msgid "Ignore"
msgstr ""
@@ -12979,6 +13364,16 @@ msgstr ""
msgid "Import"
msgstr ""
+msgid "Import %d compatible repository"
+msgid_plural "Import %d compatible repositories"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Import %d repository"
+msgid_plural "Import %d repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Import CSV"
msgstr ""
@@ -12988,15 +13383,9 @@ msgstr ""
msgid "Import all compatible projects"
msgstr ""
-msgid "Import all compatible repositories"
-msgstr ""
-
msgid "Import all projects"
msgstr ""
-msgid "Import all repositories"
-msgstr ""
-
msgid "Import an exported GitLab project"
msgstr ""
@@ -13084,6 +13473,9 @@ msgstr ""
msgid "ImportProjects|Error importing repository %{project_safe_import_url} into %{project_full_path} - %{message}"
msgstr ""
+msgid "ImportProjects|Import repositories"
+msgstr ""
+
msgid "ImportProjects|Importing the project failed"
msgstr ""
@@ -13096,7 +13488,7 @@ msgstr ""
msgid "ImportProjects|Requesting your %{provider} repositories failed"
msgstr ""
-msgid "ImportProjects|Select the projects you want to import"
+msgid "ImportProjects|Select the repositories you want to import"
msgstr ""
msgid "ImportProjects|The remote data could not be imported."
@@ -13132,9 +13524,6 @@ msgstr ""
msgid "In order to enable Service Desk for your instance, you must first set up incoming email."
msgstr ""
-msgid "In order to gather accurate feature usage data, it can take 1 to 2 weeks to see your index."
-msgstr ""
-
msgid "In order to personalize your experience with GitLab%{br_tag}we would like to know a bit more about you."
msgstr ""
@@ -13165,18 +13554,30 @@ msgstr ""
msgid "IncidentManagement|Create incident"
msgstr ""
+msgid "IncidentManagement|Critical - S1"
+msgstr ""
+
msgid "IncidentManagement|Date created"
msgstr ""
msgid "IncidentManagement|Display your incidents in a dedicated view"
msgstr ""
+msgid "IncidentManagement|High - S2"
+msgstr ""
+
msgid "IncidentManagement|Incident"
msgstr ""
msgid "IncidentManagement|Incidents"
msgstr ""
+msgid "IncidentManagement|Low - S4"
+msgstr ""
+
+msgid "IncidentManagement|Medium - S3"
+msgstr ""
+
msgid "IncidentManagement|No incidents to display."
msgstr ""
@@ -13189,6 +13590,9 @@ msgstr ""
msgid "IncidentManagement|Published to status page"
msgstr ""
+msgid "IncidentManagement|Severity"
+msgstr ""
+
msgid "IncidentManagement|There are no closed incidents"
msgstr ""
@@ -13198,6 +13602,9 @@ msgstr ""
msgid "IncidentManagement|Unassigned"
msgstr ""
+msgid "IncidentManagement|Unknown"
+msgstr ""
+
msgid "IncidentManagement|Unpublished"
msgstr ""
@@ -13219,6 +13626,15 @@ msgstr ""
msgid "Incidents"
msgstr ""
+msgid "Incident|Alert details"
+msgstr ""
+
+msgid "Incident|Summary"
+msgstr ""
+
+msgid "Incident|There was an issue loading alert data. Please try again."
+msgstr ""
+
msgid "Include a Terms of Service agreement and Privacy Policy that all users must accept."
msgstr ""
@@ -13279,6 +13695,9 @@ msgstr ""
msgid "Information about additional Pages templates and how to install them can be found in our %{pages_getting_started_guide}."
msgstr ""
+msgid "Inherited"
+msgstr ""
+
msgid "Inherited:"
msgstr ""
@@ -13359,7 +13778,22 @@ msgstr ""
msgid "Instance administrators group already exists"
msgstr ""
-msgid "Instance license"
+msgid "InstanceStatistics|Groups"
+msgstr ""
+
+msgid "InstanceStatistics|Issues"
+msgstr ""
+
+msgid "InstanceStatistics|Merge Requests"
+msgstr ""
+
+msgid "InstanceStatistics|Pipelines"
+msgstr ""
+
+msgid "InstanceStatistics|Projects"
+msgstr ""
+
+msgid "InstanceStatistics|Users"
msgstr ""
msgid "Integration"
@@ -13371,6 +13805,12 @@ msgstr ""
msgid "Integrations"
msgstr ""
+msgid "Integrations|%{integration} settings saved and active."
+msgstr ""
+
+msgid "Integrations|%{integration} settings saved, but not active."
+msgstr ""
+
msgid "Integrations|All details"
msgstr ""
@@ -13380,6 +13820,12 @@ msgstr ""
msgid "Integrations|Comment settings:"
msgstr ""
+msgid "Integrations|Connection failed. Please check your settings."
+msgstr ""
+
+msgid "Integrations|Connection successful."
+msgstr ""
+
msgid "Integrations|Default settings are inherited from the group level."
msgstr ""
@@ -13395,6 +13841,15 @@ msgstr ""
msgid "Integrations|Includes commit title and branch"
msgstr ""
+msgid "Integrations|Projects using custom settings will not be impacted unless the project owner chooses to use instance-level defaults."
+msgstr ""
+
+msgid "Integrations|Save settings?"
+msgstr ""
+
+msgid "Integrations|Saving will update the default settings for all projects that are not using custom settings."
+msgstr ""
+
msgid "Integrations|Standard"
msgstr ""
@@ -13527,6 +13982,9 @@ msgstr ""
msgid "Invitation"
msgstr ""
+msgid "Invitation declined"
+msgstr ""
+
msgid "Invite"
msgstr ""
@@ -13578,6 +14036,42 @@ 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|%{linkStart}Read more%{linkEnd} about role permissions"
+msgstr ""
+
+msgid "InviteMembersModal|Access expiration date (optional)"
+msgstr ""
+
+msgid "InviteMembersModal|Cancel"
+msgstr ""
+
+msgid "InviteMembersModal|Choose a role permission"
+msgstr ""
+
+msgid "InviteMembersModal|GitLab member or Email address"
+msgstr ""
+
+msgid "InviteMembersModal|Invite"
+msgstr ""
+
+msgid "InviteMembersModal|Invite team members"
+msgstr ""
+
+msgid "InviteMembersModal|Search for members to invite"
+msgstr ""
+
+msgid "InviteMembersModal|User not invited. Feature coming soon!"
+msgstr ""
+
+msgid "InviteMembersModal|Users were succesfully added"
+msgstr ""
+
+msgid "InviteMembersModal|You're inviting members to the %{group_name} group"
+msgstr ""
+
+msgid "InviteMembers|Invite team members"
+msgstr ""
+
msgid "Invited"
msgstr ""
@@ -13632,10 +14126,13 @@ msgstr ""
msgid "Issue cannot be found."
msgstr ""
+msgid "Issue created from vulnerability %{vulnerability_link}"
+msgstr ""
+
msgid "Issue events"
msgstr ""
-msgid "Issue first depoloyed to production"
+msgid "Issue first deployed to production"
msgstr ""
msgid "Issue label"
@@ -13713,6 +14210,9 @@ msgstr ""
msgid "IssueTracker|Custom issue tracker"
msgstr ""
+msgid "IssueTracker|EWM work items tracker"
+msgstr ""
+
msgid "IssueTracker|Redmine issue tracker"
msgstr ""
@@ -13779,6 +14279,9 @@ msgstr ""
msgid "It looks like you have some draft commits in this branch."
msgstr ""
+msgid "It may be several days before you see feature usage data."
+msgstr ""
+
msgid "It must have a header row and at least two columns: the first column is the issue title and the second column is the issue description. The separator is automatically detected."
msgstr ""
@@ -14061,13 +14564,13 @@ msgstr ""
msgid "Join Zoom meeting"
msgstr ""
-msgid "Jul"
+msgid "Joined %{time_ago}"
msgstr ""
-msgid "July"
+msgid "Jul"
msgstr ""
-msgid "Jump to first unresolved thread"
+msgid "July"
msgstr ""
msgid "Jump to next unresolved thread"
@@ -14103,6 +14606,9 @@ msgstr ""
msgid "Keyboard shortcuts"
msgstr ""
+msgid "KeyboardKey|Ctrl+"
+msgstr ""
+
msgid "Keys"
msgstr ""
@@ -14151,6 +14657,9 @@ msgstr ""
msgid "LDAP Synchronization"
msgstr ""
+msgid "LDAP group settings"
+msgstr ""
+
msgid "LDAP settings"
msgstr ""
@@ -14160,6 +14669,9 @@ msgstr ""
msgid "LDAP sync in progress. This could take a few minutes. Refresh the page to see the changes."
msgstr ""
+msgid "LDAP synchronizations"
+msgstr ""
+
msgid "LFS"
msgstr ""
@@ -14240,7 +14752,16 @@ msgid_plural "Last %d days"
msgstr[0] ""
msgstr[1] ""
-msgid "Last %{days} days"
+msgid "Last 2 weeks"
+msgstr ""
+
+msgid "Last 30 days"
+msgstr ""
+
+msgid "Last 60 days"
+msgstr ""
+
+msgid "Last 90 days"
msgstr ""
msgid "Last Accessed On"
@@ -14318,6 +14839,9 @@ msgstr ""
msgid "Last used on:"
msgstr ""
+msgid "Last week"
+msgstr ""
+
msgid "LastCommit|authored"
msgstr ""
@@ -14333,6 +14857,9 @@ msgstr ""
msgid "Latest pipeline for the most recent commit on this branch"
msgstr ""
+msgid "Launch a ready-to-code development environment for your project."
+msgstr ""
+
msgid "Lead"
msgstr ""
@@ -14713,6 +15240,9 @@ msgstr ""
msgid "List of all merge commits"
msgstr ""
+msgid "List options"
+msgstr ""
+
msgid "List settings"
msgstr ""
@@ -14725,9 +15255,6 @@ msgstr ""
msgid "List your Bitbucket Server repositories"
msgstr ""
-msgid "Lists"
-msgstr ""
-
msgid "Live preview"
msgstr ""
@@ -14974,6 +15501,12 @@ msgstr ""
msgid "Mark as done"
msgstr ""
+msgid "Mark as draft"
+msgstr ""
+
+msgid "Mark as ready"
+msgstr ""
+
msgid "Mark as resolved"
msgstr ""
@@ -14995,6 +15528,24 @@ msgstr ""
msgid "Markdown is supported"
msgstr ""
+msgid "MarkdownEditor|Add a link (%{modifierKey}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add a link (%{modifier_key}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifierKey}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifier_key}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifierKey}I)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifier_key}I)"
+msgstr ""
+
msgid "Marked For Deletion At - %{deletion_time}"
msgstr ""
@@ -15079,7 +15630,25 @@ msgstr ""
msgid "Max access level"
msgstr ""
-msgid "Max seats used"
+msgid "Max role"
+msgstr ""
+
+msgid "Max size 15 MB"
+msgstr ""
+
+msgid "Maximum Conan package file size in bytes"
+msgstr ""
+
+msgid "Maximum Maven package file size in bytes"
+msgstr ""
+
+msgid "Maximum NPM package file size in bytes"
+msgstr ""
+
+msgid "Maximum NuGet package file size in bytes"
+msgstr ""
+
+msgid "Maximum PyPI package file size in bytes"
msgstr ""
msgid "Maximum Users:"
@@ -15211,6 +15780,18 @@ msgstr ""
msgid "Members with access to %{strong_start}%{group_name}%{strong_end}"
msgstr ""
+msgid "Members|%{time} by %{user}"
+msgstr ""
+
+msgid "Members|Expired"
+msgstr ""
+
+msgid "Members|No expiration set"
+msgstr ""
+
+msgid "Members|in %{time}"
+msgstr ""
+
msgid "Memory Usage"
msgstr ""
@@ -15397,9 +15978,6 @@ msgstr ""
msgid "MergeRequests|Thread will be unresolved"
msgstr ""
-msgid "MergeRequests|Toggle comments for this file"
-msgstr ""
-
msgid "MergeRequests|View file @ %{commitId}"
msgstr ""
@@ -15460,6 +16038,9 @@ msgstr ""
msgid "Merging immediately isn't recommended as it may negatively impact the existing merge train. Read the %{docsLinkStart}documentation%{docsLinkEnd} for more information."
msgstr ""
+msgid "Message"
+msgstr ""
+
msgid "Messages"
msgstr ""
@@ -15845,18 +16426,12 @@ msgid_plural "Milestones"
msgstr[0] ""
msgstr[1] ""
-msgid "Milestone does not support burnup charts"
-msgstr ""
-
msgid "Milestone lists not available with your current license"
msgstr ""
msgid "Milestone lists show all issues from the selected milestone."
msgstr ""
-msgid "Milestone must have a start and due date"
-msgstr ""
-
msgid "MilestoneSidebar|Closed:"
msgstr ""
@@ -16223,6 +16798,9 @@ msgstr ""
msgid "Namespace"
msgstr ""
+msgid "Namespace ID:"
+msgstr ""
+
msgid "Namespace is empty"
msgstr ""
@@ -16307,6 +16885,9 @@ msgstr ""
msgid "NetworkPolicies|Allow all outbound traffic from %{selector} to %{ruleSelector} on %{ports}"
msgstr ""
+msgid "NetworkPolicies|Are you sure you want to delete this policy? This action cannot be undone."
+msgstr ""
+
msgid "NetworkPolicies|Choose whether to enforce this policy."
msgstr ""
@@ -16316,12 +16897,21 @@ msgstr ""
msgid "NetworkPolicies|Define this policy's location, conditions and actions."
msgstr ""
+msgid "NetworkPolicies|Delete policy"
+msgstr ""
+
+msgid "NetworkPolicies|Delete policy: %{policy}"
+msgstr ""
+
msgid "NetworkPolicies|Deny all traffic"
msgstr ""
msgid "NetworkPolicies|Description"
msgstr ""
+msgid "NetworkPolicies|Edit policy"
+msgstr ""
+
msgid "NetworkPolicies|Editor mode"
msgstr ""
@@ -16349,6 +16939,9 @@ msgstr ""
msgid "NetworkPolicies|Name"
msgstr ""
+msgid "NetworkPolicies|Namespace"
+msgstr ""
+
msgid "NetworkPolicies|Network Policy"
msgstr ""
@@ -16400,6 +16993,9 @@ msgstr ""
msgid "NetworkPolicies|Rules"
msgstr ""
+msgid "NetworkPolicies|Save changes"
+msgstr ""
+
msgid "NetworkPolicies|Something went wrong, failed to update policy"
msgstr ""
@@ -16412,6 +17008,9 @@ msgstr ""
msgid "NetworkPolicies|Traffic that does not match any rule will be blocked."
msgstr ""
+msgid "NetworkPolicies|Unable to parse policy"
+msgstr ""
+
msgid "NetworkPolicies|YAML editor"
msgstr ""
@@ -16525,6 +17124,9 @@ msgstr ""
msgid "New Snippet"
msgstr ""
+msgid "New Test Case"
+msgstr ""
+
msgid "New User"
msgstr ""
@@ -16624,6 +17226,9 @@ msgstr ""
msgid "New tag"
msgstr ""
+msgid "New test case"
+msgstr ""
+
msgid "New users set to external"
msgstr ""
@@ -16696,7 +17301,7 @@ msgstr ""
msgid "No changes"
msgstr ""
-msgid "No changes between %{ref_start}%{source_branch}%{ref_end} and %{ref_start}%{target_branch}%{ref_end}"
+msgid "No changes between %{sourceBranch} and %{targetBranch}"
msgstr ""
msgid "No child epics match applied filters"
@@ -16711,6 +17316,9 @@ msgstr ""
msgid "No containers available"
msgstr ""
+msgid "No content to show"
+msgstr ""
+
msgid "No contributions"
msgstr ""
@@ -16786,9 +17394,6 @@ msgstr ""
msgid "No license. All rights reserved"
msgstr ""
-msgid "No licenses found."
-msgstr ""
-
msgid "No matches found"
msgstr ""
@@ -16801,6 +17406,9 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No members found"
+msgstr ""
+
msgid "No merge requests found"
msgstr ""
@@ -16822,6 +17430,9 @@ msgstr ""
msgid "No parent group"
msgstr ""
+msgid "No plan"
+msgstr ""
+
msgid "No pods available"
msgstr ""
@@ -16918,6 +17529,12 @@ msgstr ""
msgid "Not Implemented"
msgstr ""
+msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+msgstr ""
+
+msgid "Not all browsers support WebAuthn. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even from an unsupported browser."
+msgstr ""
+
msgid "Not all data has been processed yet, the accuracy of the chart for the selected timeframe is limited."
msgstr ""
@@ -17014,6 +17631,9 @@ msgstr ""
msgid "Notification settings saved"
msgstr ""
+msgid "NotificationEvent|Change reviewer merge request"
+msgstr ""
+
msgid "NotificationEvent|Close issue"
msgstr ""
@@ -17176,10 +17796,7 @@ msgstr ""
msgid "On track"
msgstr ""
-msgid "OnDemandScans|Attached branch"
-msgstr ""
-
-msgid "OnDemandScans|Attached branch is where the scan job runs."
+msgid "OnDemandScans|Could not fetch scanner profiles. Please refresh the page, or try again later."
msgstr ""
msgid "OnDemandScans|Could not fetch site profiles. Please refresh the page, or try again later."
@@ -17188,6 +17805,9 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
+msgid "OnDemandScans|Create a new scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Create a new site profile"
msgstr ""
@@ -17200,6 +17820,9 @@ msgstr ""
msgid "OnDemandScans|New on-demand DAST scan"
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 ""
@@ -17209,16 +17832,10 @@ msgstr ""
msgid "OnDemandScans|On-demand scans run outside the DevOps cycle and find vulnerabilities in your projects. %{learnMoreLinkStart}Learn more%{learnMoreLinkEnd}"
msgstr ""
-msgid "OnDemandScans|Only a passive scan can be performed on demand."
-msgstr ""
-
-msgid "OnDemandScans|Passive"
-msgstr ""
-
msgid "OnDemandScans|Run scan"
msgstr ""
-msgid "OnDemandScans|Scan mode"
+msgid "OnDemandScans|Scanner profile"
msgstr ""
msgid "OnDemandScans|Scanner settings"
@@ -17230,9 +17847,15 @@ msgstr ""
msgid "OnDemandScans|Select one of the existing profiles"
msgstr ""
+msgid "OnDemandScans|Site profile"
+msgstr ""
+
msgid "OnDemandScans|Site profiles"
msgstr ""
+msgid "OnDemandScans|Use existing scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Use existing site profile"
msgstr ""
@@ -17331,9 +17954,6 @@ msgstr ""
msgid "Open Selection"
msgstr ""
-msgid "Open Web IDE"
-msgstr ""
-
msgid "Open comment type dropdown"
msgstr ""
@@ -17439,6 +18059,9 @@ msgstr ""
msgid "Origin"
msgstr ""
+msgid "Orphaned member"
+msgstr ""
+
msgid "Other Labels"
msgstr ""
@@ -17454,6 +18077,9 @@ msgstr ""
msgid "Other visibility settings have been disabled by the administrator."
msgstr ""
+msgid "Our documentation includes an example DevOps Score report."
+msgstr ""
+
msgid "Out-of-compliance with this project's policies and should be removed"
msgstr ""
@@ -17478,6 +18104,9 @@ msgstr ""
msgid "Overwrite diverged branches"
msgstr ""
+msgid "Owned by %{image_tag}"
+msgstr ""
+
msgid "Owned by anyone"
msgstr ""
@@ -17499,6 +18128,9 @@ msgstr ""
msgid "Package deleted successfully"
msgstr ""
+msgid "Package file size limits"
+msgstr ""
+
msgid "Package recipe already exists"
msgstr ""
@@ -17514,9 +18146,6 @@ msgstr ""
msgid "Package type must be PyPi"
msgstr ""
-msgid "Package was removed"
-msgstr ""
-
msgid "PackageRegistry|%{name} version %{version} was created %{datetime}"
msgstr ""
@@ -17658,12 +18287,18 @@ msgstr ""
msgid "PackageRegistry|NuGet Command"
msgstr ""
+msgid "PackageRegistry|Package Registry"
+msgstr ""
+
msgid "PackageRegistry|Pip Command"
msgstr ""
msgid "PackageRegistry|Pipeline %{link} triggered %{datetime} by %{author}"
msgstr ""
+msgid "PackageRegistry|Publish and share packages for a variety of common package managers. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "PackageRegistry|Published to the %{project} Package Registry %{datetime}"
msgstr ""
@@ -17763,6 +18398,9 @@ msgstr ""
msgid "Page not found"
msgstr ""
+msgid "Page settings"
+msgstr ""
+
msgid "Page was successfully deleted"
msgstr ""
@@ -17904,7 +18542,7 @@ msgstr ""
msgid "Paste issue link"
msgstr ""
-msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Don't use your private SSH key."
+msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Do not paste your private SSH key, as that can compromise your identity."
msgstr ""
msgid "Patch to apply"
@@ -17931,6 +18569,9 @@ msgstr ""
msgid "Pending"
msgstr ""
+msgid "Pending comments"
+msgstr ""
+
msgid "People without permission will never get a notification and won't be able to comment."
msgstr ""
@@ -18129,6 +18770,9 @@ msgstr ""
msgid "Pipelines|Build with confidence"
msgstr ""
+msgid "Pipelines|By revoking a trigger you will break any processes making use of it. Are you sure?"
+msgstr ""
+
msgid "Pipelines|CI Lint"
msgstr ""
@@ -18141,6 +18785,15 @@ msgstr ""
msgid "Pipelines|Continuous Integration can help catch bugs by running your tests automatically, while Continuous Deployment can help you deliver code to your product environment."
msgstr ""
+msgid "Pipelines|Copy trigger token"
+msgstr ""
+
+msgid "Pipelines|Description"
+msgstr ""
+
+msgid "Pipelines|Edit"
+msgstr ""
+
msgid "Pipelines|Get started with Pipelines"
msgstr ""
@@ -18156,15 +18809,27 @@ msgstr ""
msgid "Pipelines|It is recommended the code is reviewed thoroughly before running this pipeline with the parent project's CI resource."
msgstr ""
+msgid "Pipelines|Last Used"
+msgstr ""
+
msgid "Pipelines|Loading Pipelines"
msgstr ""
msgid "Pipelines|More Information"
msgstr ""
+msgid "Pipelines|No triggers have been created yet. Add one using the form above."
+msgstr ""
+
+msgid "Pipelines|Owner"
+msgstr ""
+
msgid "Pipelines|Project cache successfully reset."
msgstr ""
+msgid "Pipelines|Revoke"
+msgstr ""
+
msgid "Pipelines|Run Pipeline"
msgstr ""
@@ -18189,6 +18854,15 @@ msgstr ""
msgid "Pipelines|This project is not currently set up to run pipelines."
msgstr ""
+msgid "Pipelines|Token"
+msgstr ""
+
+msgid "Pipelines|Trigger user has insufficient permissions to project"
+msgstr ""
+
+msgid "Pipelines|invalid"
+msgstr ""
+
msgid "Pipelines|parent"
msgstr ""
@@ -18447,10 +19121,10 @@ msgstr ""
msgid "Please provide attributes to update"
msgstr ""
-msgid "Please refer to %{docs_url}"
+msgid "Please reach out if you have any questions and we'll be happy to assist."
msgstr ""
-msgid "Please retype the email address."
+msgid "Please refer to %{docs_url}"
msgstr ""
msgid "Please select"
@@ -18480,6 +19154,9 @@ msgstr ""
msgid "Please set a new password before proceeding."
msgstr ""
+msgid "Please share your feedback about %{featureName} %{linkStart}in this issue%{linkEnd} to help us improve the experience."
+msgstr ""
+
msgid "Please solve the reCAPTCHA"
msgstr ""
@@ -18783,6 +19460,9 @@ msgstr ""
msgid "Profiles| You are going to change the username %{currentUsernameBold} to %{newUsernameBold}. Profile and projects will be redirected to the %{newUsername} namespace but this redirect will expire once the %{currentUsername} namespace is registered by another user or group. Please update your Git repository remotes as soon as possible."
msgstr ""
+msgid "Profiles|%{provider} Active"
+msgstr ""
+
msgid "Profiles|@username"
msgstr ""
@@ -18834,7 +19514,7 @@ msgstr ""
msgid "Profiles|Commit email"
msgstr ""
-msgid "Profiles|Connect"
+msgid "Profiles|Connect %{provider}"
msgstr ""
msgid "Profiles|Connected Accounts"
@@ -18858,6 +19538,9 @@ msgstr ""
msgid "Profiles|Disconnect"
msgstr ""
+msgid "Profiles|Disconnect %{provider}"
+msgstr ""
+
msgid "Profiles|Do not show on profile"
msgstr ""
@@ -18882,7 +19565,7 @@ msgstr ""
msgid "Profiles|Full name"
msgstr ""
-msgid "Profiles|Give your individual key a title. This will be publically visible."
+msgid "Profiles|Give your individual key a title."
msgstr ""
msgid "Profiles|Include private contributions on my profile"
@@ -18972,7 +19655,7 @@ msgstr ""
msgid "Profiles|The maximum file size allowed is 200KB."
msgstr ""
-msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it?"
+msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it? It will be publicly visible."
msgstr ""
msgid "Profiles|This email will be displayed on your public profile"
@@ -19047,6 +19730,9 @@ msgstr ""
msgid "Profiles|You don't have access to delete this user."
msgstr ""
+msgid "Profiles|You must transfer ownership or delete groups you are an owner of before you can delete your account"
+msgstr ""
+
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
@@ -19635,6 +20321,9 @@ msgstr ""
msgid "ProjectTemplates|GitLab Cluster Management"
msgstr ""
+msgid "ProjectTemplates|Gitpod/Spring Petclinic"
+msgstr ""
+
msgid "ProjectTemplates|Go Micro"
msgstr ""
@@ -20244,6 +20933,9 @@ msgstr ""
msgid "Publish to status page"
msgstr ""
+msgid "Published"
+msgstr ""
+
msgid "Published on status page"
msgstr ""
@@ -20361,9 +21053,15 @@ msgstr ""
msgid "Quick range"
msgstr ""
+msgid "Quickly and easily edit multiple files in your project."
+msgstr ""
+
msgid "README"
msgstr ""
+msgid "Rails"
+msgstr ""
+
msgid "Rake Tasks Help"
msgstr ""
@@ -20483,10 +21181,13 @@ msgstr ""
msgid "Register Two-Factor Authenticator"
msgstr ""
-msgid "Register U2F device"
+msgid "Register Universal Two-Factor (U2F) Device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register WebAuthn Device"
+msgstr ""
+
+msgid "Register device"
msgstr ""
msgid "Register for GitLab"
@@ -20498,9 +21199,6 @@ msgstr ""
msgid "Register with two-factor app"
msgstr ""
-msgid "Registration"
-msgstr ""
-
msgid "Registration|Checkout"
msgstr ""
@@ -20617,9 +21315,6 @@ msgstr ""
msgid "Release|Something went wrong while saving the release details"
msgstr ""
-msgid "Remediated: needs review"
-msgstr ""
-
msgid "Remediations"
msgstr ""
@@ -20725,6 +21420,9 @@ msgstr ""
msgid "Remove priority"
msgstr ""
+msgid "Remove report"
+msgstr ""
+
msgid "Remove secondary node"
msgstr ""
@@ -20737,6 +21435,12 @@ msgstr ""
msgid "Remove time estimate"
msgstr ""
+msgid "Remove user & report"
+msgstr ""
+
+msgid "Remove user from group"
+msgstr ""
+
msgid "Removed"
msgstr ""
@@ -20818,9 +21522,6 @@ msgstr ""
msgid "Removes time estimate."
msgstr ""
-msgid "Removing license…"
-msgstr ""
-
msgid "Removing this group also removes all child projects, including archived projects, and their resources."
msgstr ""
@@ -20905,6 +21606,9 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
+msgid "Reported by %{reporter}"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -20991,6 +21695,27 @@ msgstr ""
msgid "Repositories"
msgstr ""
+msgid "Repositories Analytics"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download Historic Test Coverage Data"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download historic test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Historic Test Coverage Data is available in raw format (.csv) for further analysis."
+msgstr ""
+
+msgid "RepositoriesAnalytics|Test Code Coverage"
+msgstr ""
+
+msgid "RepositoriesAnalytics|There was an error fetching the projects."
+msgstr ""
+
msgid "Repository"
msgstr ""
@@ -21069,9 +21794,15 @@ msgstr ""
msgid "Request parameter %{param} is missing."
msgstr ""
+msgid "Request review from"
+msgstr ""
+
msgid "Request to link SAML account must be authorized"
msgstr ""
+msgid "Requested"
+msgstr ""
+
msgid "Requested %{time_ago}"
msgstr ""
@@ -21090,6 +21821,9 @@ msgstr ""
msgid "Requests to these domain(s)/address(es) on the local network will be allowed when local requests from hooks and services are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 or 127.0.0.0/28 are supported. Domain wildcards are not supported currently. Use comma, semicolon, or newline to separate multiple entries. The allowlist can hold a maximum of 1000 entries. Domains should use IDNA encoding. Ex: example.com, 192.168.1.1, 127.0.0.0/28, xn--itlab-j1a.com."
msgstr ""
+msgid "Require admin approval for new sign-ups"
+msgstr ""
+
msgid "Require all users in this group to setup Two-factor authentication"
msgstr ""
@@ -21217,9 +21951,6 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
-msgid "Resolved by %{resolvedByName}"
-msgstr ""
-
msgid "Resolves IP addresses once and uses them to submit requests"
msgstr ""
@@ -21339,6 +22070,14 @@ msgstr ""
msgid "ReviewApp|Enable Review App"
msgstr ""
+msgid "Reviewer"
+msgid_plural "%d Reviewers"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Reviewer(s)"
+msgstr ""
+
msgid "Reviewing"
msgstr ""
@@ -21378,6 +22117,9 @@ msgstr ""
msgid "Rook"
msgstr ""
+msgid "Ruby"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -21456,6 +22198,63 @@ msgstr ""
msgid "Runners page."
msgstr ""
+msgid "Runners|Active"
+msgstr ""
+
+msgid "Runners|Architecture"
+msgstr ""
+
+msgid "Runners|Can run untagged jobs"
+msgstr ""
+
+msgid "Runners|Description"
+msgstr ""
+
+msgid "Runners|Group"
+msgstr ""
+
+msgid "Runners|IP Address"
+msgstr ""
+
+msgid "Runners|Last contact"
+msgstr ""
+
+msgid "Runners|Locked to this project"
+msgstr ""
+
+msgid "Runners|Maximum job timeout"
+msgstr ""
+
+msgid "Runners|Name"
+msgstr ""
+
+msgid "Runners|Platform"
+msgstr ""
+
+msgid "Runners|Property Name"
+msgstr ""
+
+msgid "Runners|Protected"
+msgstr ""
+
+msgid "Runners|Revision"
+msgstr ""
+
+msgid "Runners|Shared"
+msgstr ""
+
+msgid "Runners|Specific"
+msgstr ""
+
+msgid "Runners|Tags"
+msgstr ""
+
+msgid "Runners|Value"
+msgstr ""
+
+msgid "Runners|Version"
+msgstr ""
+
msgid "Runners|You have used %{quotaUsed} out of %{quotaLimit} of your shared Runners pipeline minutes."
msgstr ""
@@ -21468,6 +22267,9 @@ msgstr ""
msgid "Runs a number of housekeeping tasks within the current repository, such as compressing file revisions and removing unreachable objects."
msgstr ""
+msgid "SAML"
+msgstr ""
+
msgid "SAML SSO"
msgstr ""
@@ -21519,6 +22321,9 @@ msgstr ""
msgid "Save"
msgstr ""
+msgid "Save %{name} size limits"
+msgstr ""
+
msgid "Save Changes"
msgstr ""
@@ -21549,9 +22354,6 @@ msgstr ""
msgid "Save space and find tags in the Container Registry more easily. Enable the cleanup policy to remove stale tags and keep only the ones you need."
msgstr ""
-msgid "Save template"
-msgstr ""
-
msgid "Save variables"
msgstr ""
@@ -21594,9 +22396,6 @@ msgstr ""
msgid "Scope"
msgstr ""
-msgid "Scope not supported with disabled 'users_search' feature!"
-msgstr ""
-
msgid "Scoped issue boards"
msgstr ""
@@ -21723,9 +22522,6 @@ msgstr ""
msgid "Search requirements"
msgstr ""
-msgid "Search results…"
-msgstr ""
-
msgid "Search users"
msgstr ""
@@ -21798,6 +22594,11 @@ msgid_plural "SearchResults|commits"
msgstr[0] ""
msgstr[1] ""
+msgid "SearchResults|epic"
+msgid_plural "SearchResults|epics"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "SearchResults|issue"
msgid_plural "SearchResults|issues"
msgstr[0] ""
@@ -21842,10 +22643,10 @@ msgstr ""
msgid "Seat Link is disabled, and cannot be configured through this form."
msgstr ""
-msgid "Seats currently in use"
+msgid "Seats usage data as of %{last_enqueue_time}"
msgstr ""
-msgid "Seats in license"
+msgid "Seats usage data is updated every day at 12:00pm UTC"
msgstr ""
msgid "Secondary"
@@ -21899,6 +22700,9 @@ msgstr ""
msgid "SecurityConfiguration|Available for on-demand DAST"
msgstr ""
+msgid "SecurityConfiguration|By default, all analyzers are applied in order to cover all languages across your project, and only run if the language is detected in the Merge Request."
+msgstr ""
+
msgid "SecurityConfiguration|Configure"
msgstr ""
@@ -21929,16 +22733,19 @@ msgstr ""
msgid "SecurityConfiguration|Manage"
msgstr ""
+msgid "SecurityConfiguration|More information"
+msgstr ""
+
msgid "SecurityConfiguration|Not enabled"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|Security Control"
+msgid "SecurityConfiguration|SAST Configuration"
msgstr ""
-msgid "SecurityConfiguration|See documentation"
+msgid "SecurityConfiguration|Security Control"
msgstr ""
msgid "SecurityConfiguration|Status"
@@ -21950,6 +22757,9 @@ msgstr ""
msgid "SecurityConfiguration|Using custom settings. You won't receive automatic updates on this variable. %{anchorStart}Restore to default%{anchorEnd}"
msgstr ""
+msgid "SecurityConfiguration|View history"
+msgstr ""
+
msgid "SecurityConfiguration|You can quickly enable all security scanning tools by enabling %{linkStart}Auto DevOps%{linkEnd}."
msgstr ""
@@ -22028,9 +22838,6 @@ msgstr ""
msgid "SecurityReports|Learn more about setting up your dashboard"
msgstr ""
-msgid "SecurityReports|Load more vulnerabilities"
-msgstr ""
-
msgid "SecurityReports|Monitor vulnerabilities in your code"
msgstr ""
@@ -22310,7 +23117,7 @@ msgstr ""
msgid "Select status"
msgstr ""
-msgid "Select strategy activation method"
+msgid "Select strategy activation method."
msgstr ""
msgid "Select subscription"
@@ -22325,7 +23132,7 @@ msgstr ""
msgid "Select the custom project template source group."
msgstr ""
-msgid "Select timeframe"
+msgid "Select the environment scope for this feature flag."
msgstr ""
msgid "Select timezone"
@@ -22574,6 +23381,9 @@ msgstr ""
msgid "Set iteration"
msgstr ""
+msgid "Set limit to 0 to allow any file size."
+msgstr ""
+
msgid "Set max session time for web terminal."
msgstr ""
@@ -22652,10 +23462,13 @@ msgstr ""
msgid "Set up a %{type} Runner manually"
msgstr ""
+msgid "Set up a hardware device as a second factor to sign in."
+msgstr ""
+
msgid "Set up assertions/attributes/claims (email, first_name, last_name) and NameID according to %{docsLinkStart}the documentation %{icon}%{docsLinkEnd}"
msgstr ""
-msgid "Set up new U2F device"
+msgid "Set up new device"
msgstr ""
msgid "Set up new password"
@@ -22724,6 +23537,9 @@ msgstr ""
msgid "Sets weight to %{weight}."
msgstr ""
+msgid "Setting this to 0 means using the system default timeout value."
+msgstr ""
+
msgid "Settings"
msgstr ""
@@ -22739,6 +23555,15 @@ msgstr ""
msgid "Severity"
msgstr ""
+msgid "SeverityWidget|Severity"
+msgstr ""
+
+msgid "SeverityWidget|Severity: %{severity}"
+msgstr ""
+
+msgid "SeverityWidget|There was an error while updating severity."
+msgstr ""
+
msgid "Shards (%{shards})"
msgstr ""
@@ -22784,6 +23609,9 @@ msgstr ""
msgid "Show all requirements."
msgstr ""
+msgid "Show all test cases."
+msgstr ""
+
msgid "Show archived projects"
msgstr ""
@@ -22796,6 +23624,9 @@ msgstr ""
msgid "Show comments"
msgstr ""
+msgid "Show comments on this file"
+msgstr ""
+
msgid "Show comments only"
msgstr ""
@@ -22841,6 +23672,12 @@ msgstr ""
msgid "Show parent subgroups"
msgstr ""
+msgid "Show the Closed list"
+msgstr ""
+
+msgid "Show the Open list"
+msgstr ""
+
msgid "Show whitespace changes"
msgstr ""
@@ -22884,9 +23721,6 @@ msgstr ""
msgid "Sidebar|Assign health status"
msgstr ""
-msgid "Sidebar|Change weight"
-msgstr ""
-
msgid "Sidebar|Health status"
msgstr ""
@@ -23070,6 +23904,9 @@ msgstr ""
msgid "Snippets|Add another file %{num}/%{total}"
msgstr ""
+msgid "Snippets|Authored %{time_ago} by %{author}"
+msgstr ""
+
msgid "Snippets|Delete file"
msgstr ""
@@ -23097,6 +23934,9 @@ msgstr ""
msgid "Solution"
msgstr ""
+msgid "Some changes are not shown"
+msgstr ""
+
msgid "Some child epics may be hidden due to applied filters"
msgstr ""
@@ -23463,6 +24303,12 @@ msgstr ""
msgid "Source (branch or tag)"
msgstr ""
+msgid "Source Branch"
+msgstr ""
+
+msgid "Source branch: %{source_branch_open}%{source_branch}%{source_branch_close}"
+msgstr ""
+
msgid "Source code"
msgstr ""
@@ -23628,9 +24474,6 @@ msgstr ""
msgid "Start and due date"
msgstr ""
-msgid "Start by choosing a group to see how your team is spending time. You can then drill down to the project level."
-msgstr ""
-
msgid "Start by choosing a group to start exploring the merge requests in that group. You can then proceed to filter by projects, labels, milestones and authors."
msgstr ""
@@ -23712,18 +24555,27 @@ msgstr ""
msgid "StaticSiteEditor|3. Assign a person to review and accept the merge request."
msgstr ""
+msgid "StaticSiteEditor|A link to view the merge request will appear once ready."
+msgstr ""
+
msgid "StaticSiteEditor|An error occurred while submitting your changes."
msgstr ""
msgid "StaticSiteEditor|Branch could not be created."
msgstr ""
+msgid "StaticSiteEditor|Copy update"
+msgstr ""
+
msgid "StaticSiteEditor|Could not commit the content changes."
msgstr ""
msgid "StaticSiteEditor|Could not create merge request."
msgstr ""
+msgid "StaticSiteEditor|Creating your merge request"
+msgstr ""
+
msgid "StaticSiteEditor|Incompatible file content"
msgstr ""
@@ -23745,6 +24597,9 @@ msgstr ""
msgid "StaticSiteEditor|View documentation"
msgstr ""
+msgid "StaticSiteEditor|You can set an assignee to get your changes reviewed and deployed once your merge request is created."
+msgstr ""
+
msgid "StaticSiteEditor|Your merge request has been created"
msgstr ""
@@ -23874,15 +24729,15 @@ msgstr ""
msgid "Submit %{humanized_resource_name}"
msgstr ""
-msgid "Submit Changes"
-msgstr ""
-
msgid "Submit a review"
msgstr ""
msgid "Submit as spam"
msgstr ""
+msgid "Submit changes"
+msgstr ""
+
msgid "Submit feedback"
msgstr ""
@@ -24036,6 +24891,9 @@ msgstr ""
msgid "Successfully deleted U2F device."
msgstr ""
+msgid "Successfully deleted WebAuthn device."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -24354,9 +25212,6 @@ msgstr ""
msgid "Template to append to all Service Desk issues"
msgstr ""
-msgid "Template was successfully saved."
-msgstr ""
-
msgid "Templates"
msgstr ""
@@ -24435,10 +25290,28 @@ msgid_plural "Test coverage: %d hits"
msgstr[0] ""
msgstr[1] ""
-msgid "Test failed."
+msgid "Test settings"
msgstr ""
-msgid "Test settings and save changes"
+msgid "TestCases|New Test Case"
+msgstr ""
+
+msgid "TestCases|New test case"
+msgstr ""
+
+msgid "TestCases|Search test cases"
+msgstr ""
+
+msgid "TestCases|Something went wrong while creating a test case."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching count of test cases."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching test cases list."
+msgstr ""
+
+msgid "TestCases|Submit test case"
msgstr ""
msgid "TestHooks|Ensure one of your projects has merge requests."
@@ -24504,6 +25377,9 @@ msgstr ""
msgid "Thank you for signing up for your free trial! You will get additional instructions in your inbox shortly."
msgstr ""
+msgid "Thank you for your business."
+msgstr ""
+
msgid "Thank you for your feedback!"
msgstr ""
@@ -24563,9 +25439,6 @@ msgstr ""
msgid "The URL to use for connecting to Elasticsearch. Use a comma-separated list to support clustering (e.g., \"http://localhost:9200, http://localhost:9201\")."
msgstr ""
-msgid "The Web IDE offers advanced syntax highlighting capabilities and more."
-msgstr ""
-
msgid "The X509 Certificate to use when mutual TLS is required to communicate with the external authorization service. If left blank, the server certificate is still validated when accessing over HTTPS."
msgstr ""
@@ -24676,6 +25549,9 @@ msgstr ""
msgid "The form contains the following error:"
msgstr ""
+msgid "The form contains the following warning:"
+msgstr ""
+
msgid "The global settings require you to enable Two-Factor Authentication for your account."
msgstr ""
@@ -24790,9 +25666,6 @@ msgstr ""
msgid "The private key to use when a client certificate is provided. This value is encrypted at rest."
msgstr ""
-msgid "The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The project can be accessed by any logged in user."
msgstr ""
@@ -24829,7 +25702,7 @@ msgstr ""
msgid "The remote repository is being updated..."
msgstr ""
-msgid "The repository can be commited to, and issues, comments and other entities can be created."
+msgid "The repository can be committed to, and issues, comments and other entities can be created."
msgstr ""
msgid "The repository for this project does not exist."
@@ -24883,9 +25756,6 @@ msgstr ""
msgid "The time taken by each data entry gathered by that stage."
msgstr ""
-msgid "The total stage shows the time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The update action will time out after %{number_of_minutes} minutes. For big repositories, use a clone/push combination."
msgstr ""
@@ -24949,6 +25819,9 @@ msgstr ""
msgid "There are no archived requirements"
msgstr ""
+msgid "There are no archived test cases"
+msgstr ""
+
msgid "There are no changes"
msgstr ""
@@ -24988,6 +25861,9 @@ msgstr ""
msgid "There are no open requirements"
msgstr ""
+msgid "There are no open test cases"
+msgstr ""
+
msgid "There are no packages yet"
msgstr ""
@@ -25000,6 +25876,9 @@ msgstr ""
msgid "There is a limit of %{ci_project_subscriptions_limit} subscriptions from or to a project."
msgstr ""
+msgid "There is already a To-Do for this design."
+msgstr ""
+
msgid "There is already a repository with that name on disk"
msgstr ""
@@ -25018,6 +25897,9 @@ msgstr ""
msgid "There was a problem communicating with your device."
msgstr ""
+msgid "There was a problem fetching branches."
+msgstr ""
+
msgid "There was a problem fetching groups."
msgstr ""
@@ -25246,9 +26128,15 @@ msgstr ""
msgid "This action can lead to data loss. To prevent accidental actions we ask you to confirm your intention."
msgstr ""
+msgid "This action cannot be undone, and will permanently delete the %{key} SSH key"
+msgstr ""
+
msgid "This action cannot be undone. You will lose the project's repository and all content: issues, merge requests, etc."
msgstr ""
+msgid "This action has been performed too many times. Try again later."
+msgstr ""
+
msgid "This action will %{strongOpen}permanently delete%{strongClose} %{codeOpen}%{project}%{codeClose} %{strongOpen}immediately%{strongClose}, including its repositories and all content: issues, merge requests, etc."
msgstr ""
@@ -25276,9 +26164,6 @@ msgstr ""
msgid "This board's scope is reduced"
msgstr ""
-msgid "This branch has changed since you started editing. Would you like to create a new branch?"
-msgstr ""
-
msgid "This chart could not be displayed"
msgstr ""
@@ -25405,15 +26290,9 @@ msgstr ""
msgid "This is a security log of important events involving your account."
msgstr ""
-msgid "This is the author's first Merge Request to this project."
-msgstr ""
-
msgid "This is the highest peak of users on your installation since the license started."
msgstr ""
-msgid "This is the maximum number of users that have existed at the same time since the license started. This is the minimum number of seats you will need to buy when you renew your license."
-msgstr ""
-
msgid "This is the number of currently active users on your installation, and this is the minimum number you need to purchase when you renew your license."
msgstr ""
@@ -25645,6 +26524,15 @@ msgstr ""
msgid "This user has no identities"
msgstr ""
+msgid "This user has previously committed to the %{name} project."
+msgstr ""
+
+msgid "This user has the %{access} role in the %{name} project."
+msgstr ""
+
+msgid "This user is the author of this %{noteable}."
+msgstr ""
+
msgid "This user will be the author of all events in the activity feed that are the result of an update, like new branches being created or new commits being pushed to existing branches."
msgstr ""
@@ -25675,6 +26563,9 @@ msgstr ""
msgid "Threat Monitoring"
msgstr ""
+msgid "ThreatMonitoring|All Environments"
+msgstr ""
+
msgid "ThreatMonitoring|Anomalous Requests"
msgstr ""
@@ -25702,9 +26593,6 @@ msgstr ""
msgid "ThreatMonitoring|Operations Per Second"
msgstr ""
-msgid "ThreatMonitoring|Overview"
-msgstr ""
-
msgid "ThreatMonitoring|Packet Activity"
msgstr ""
@@ -25723,6 +26611,9 @@ msgstr ""
msgid "ThreatMonitoring|Something went wrong, unable to fetch statistics"
msgstr ""
+msgid "ThreatMonitoring|Statistics"
+msgstr ""
+
msgid "ThreatMonitoring|The firewall is not installed or has been disabled. To view this data, ensure the web application firewall is installed and enabled for your cluster."
msgstr ""
@@ -26114,6 +27005,9 @@ msgstr ""
msgid "To update Snippets with multiple files, you must use the `files` parameter"
msgstr ""
+msgid "To use Gitpod you must first enable the feature in the integrations section of your %{user_prefs}."
+msgstr ""
+
msgid "To view all %{scannedResourcesCount} scanned URLs, please download the CSV file"
msgstr ""
@@ -26147,9 +27041,6 @@ msgstr ""
msgid "Toggle Sidebar"
msgstr ""
-msgid "Toggle all threads"
-msgstr ""
-
msgid "Toggle backtrace"
msgstr ""
@@ -26174,9 +27065,6 @@ msgstr ""
msgid "Toggle navigation"
msgstr ""
-msgid "Toggle project"
-msgstr ""
-
msgid "Toggle sidebar"
msgstr ""
@@ -26216,6 +27104,9 @@ msgstr ""
msgid "Too many projects enabled. You will need to manage them via the console or the API."
msgstr ""
+msgid "Too much data"
+msgstr ""
+
msgid "Topics (optional)"
msgstr ""
@@ -26234,6 +27125,9 @@ msgstr ""
msgid "Total cores (CPUs)"
msgstr ""
+msgid "Total days to completion"
+msgstr ""
+
msgid "Total issues"
msgstr ""
@@ -26330,6 +27224,9 @@ msgstr ""
msgid "Trending"
msgstr ""
+msgid "Trials|Create a new group to start your GitLab Gold trial."
+msgstr ""
+
msgid "Trials|Go back to GitLab"
msgstr ""
@@ -26339,6 +27236,15 @@ msgstr ""
msgid "Trials|You can always resume this process by selecting your avatar and choosing 'Start a Gold trial'"
msgstr ""
+msgid "Trials|You can apply your trial to a new group or an existing group."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group or your personal account."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group, an existing group, or your personal account."
+msgstr ""
+
msgid "Trials|You won't get a free trial right now but you can always resume this process by clicking on your avatar and choosing 'Start a free trial'"
msgstr ""
@@ -26408,6 +27314,9 @@ msgstr ""
msgid "Try using a different search term to find the file you are looking for."
msgstr ""
+msgid "Trying to communicate with your device. Plug it in (if needed) and press the button on the device now."
+msgstr ""
+
msgid "Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now."
msgstr ""
@@ -26495,6 +27404,12 @@ msgstr ""
msgid "URL or request ID"
msgstr ""
+msgid "USER %{user} WILL BE REMOVED! Are you sure?"
+msgstr ""
+
+msgid "USER WILL BE BLOCKED! Are you sure?"
+msgstr ""
+
msgid "UTC"
msgstr ""
@@ -26552,9 +27467,6 @@ msgstr ""
msgid "Unable to load the merge request widget. Try reloading the page."
msgstr ""
-msgid "Unable to resolve"
-msgstr ""
-
msgid "Unable to save iteration. Please try again"
msgstr ""
@@ -26603,6 +27515,9 @@ msgstr ""
msgid "Undo ignore"
msgstr ""
+msgid "Unexpected error"
+msgstr ""
+
msgid "Unfortunately, your email message to GitLab could not be processed."
msgstr ""
@@ -26636,6 +27551,9 @@ msgstr ""
msgid "Unknown response text"
msgstr ""
+msgid "Unless otherwise agreed to in writing with GitLab, by clicking \"Upload License\" you agree that your use of GitLab Software is subject to the %{eula_link_start}Terms of Service%{eula_link_end}."
+msgstr ""
+
msgid "Unlimited"
msgstr ""
@@ -27002,9 +27920,6 @@ msgstr ""
msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
msgstr ""
-msgid "Use a hardware device to add the second factor of authentication."
-msgstr ""
-
msgid "Use an one time password authenticator on your mobile device or computer to enable two-factor authentication (2FA)."
msgstr ""
@@ -27278,13 +28193,13 @@ msgstr ""
msgid "Users"
msgstr ""
-msgid "Users in License:"
+msgid "Users in License"
msgstr ""
-msgid "Users or groups set as approvers in the project's or merge request's settings."
+msgid "Users in License:"
msgstr ""
-msgid "Users outside of license"
+msgid "Users or groups set as approvers in the project's or merge request's settings."
msgstr ""
msgid "Users over License:"
@@ -27302,9 +28217,6 @@ msgstr ""
msgid "Users with a Guest role or those who don't belong to a Project or Group will not use a seat from your license."
msgstr ""
-msgid "Users with a Guest role or those who don't belong to any projects or groups don't count towards seats in use."
-msgstr ""
-
msgid "UsersSelect|%{name} + %{length} more"
msgstr ""
@@ -27344,9 +28256,6 @@ msgstr ""
msgid "Validations failed."
msgstr ""
-msgid "Validity"
-msgstr ""
-
msgid "Value"
msgstr ""
@@ -27365,6 +28274,9 @@ msgstr ""
msgid "Value Stream Name"
msgstr ""
+msgid "ValueStreamAnalyticsStage|We don't have enough data to show this stage."
+msgstr ""
+
msgid "ValueStreamAnalytics|%{days}d"
msgstr ""
@@ -27621,6 +28533,9 @@ msgstr ""
msgid "VisualReviewApp|Steps 1 and 2 (and sometimes 3) are performed once by the developer before requesting feedback. Steps 3 (if necessary), 4 is performed by the reviewer each time they perform a review."
msgstr ""
+msgid "Visualization"
+msgstr ""
+
msgid "Vulnerabilities"
msgstr ""
@@ -27648,34 +28563,31 @@ msgstr ""
msgid "VulnerabilityChart|Severity"
msgstr ""
-msgid "VulnerabilityManagement|A true-positive and will fix"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Change status"
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|Confirm"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Confirmed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
-msgstr ""
-
-msgid "VulnerabilityManagement|Detected %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|A true-positive and will fix"
msgstr ""
-msgid "VulnerabilityManagement|Dismiss"
+msgid "VulnerabilityManagement|Change status"
msgstr ""
-msgid "VulnerabilityManagement|Dismissed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
msgstr ""
-msgid "VulnerabilityManagement|Resolved"
+msgid "VulnerabilityManagement|Detected"
msgstr ""
-msgid "VulnerabilityManagement|Resolved %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Needs triage"
msgstr ""
msgid "VulnerabilityManagement|Something went wrong while trying to delete the comment. Please try again later."
@@ -27726,6 +28638,9 @@ msgstr ""
msgid "Vulnerability|%{scannerName} (version %{scannerVersion})"
msgstr ""
+msgid "Vulnerability|Activity"
+msgstr ""
+
msgid "Vulnerability|Class"
msgstr ""
@@ -27738,6 +28653,9 @@ msgstr ""
msgid "Vulnerability|Description"
msgstr ""
+msgid "Vulnerability|Detected"
+msgstr ""
+
msgid "Vulnerability|Evidence"
msgstr ""
@@ -27801,6 +28719,9 @@ msgstr ""
msgid "Warning: Displaying this diagram might cause performance issues on this page."
msgstr ""
+msgid "We are currently unable to fetch data for the pipeline header."
+msgstr ""
+
msgid "We are currently unable to fetch data for this graph."
msgstr ""
@@ -27840,6 +28761,12 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
+msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
+msgstr ""
+
+msgid "We would like to inform you that your subscription GitLab Enterprise Edition %{plan_name} is nearing its user limit. You have %{active_user_count} active users, which is almost at the user limit of %{maximum_user_count}."
+msgstr ""
+
msgid "We've found no vulnerabilities"
msgstr ""
@@ -27855,6 +28782,12 @@ msgstr ""
msgid "Web terminal"
msgstr ""
+msgid "WebAuthn Devices (%{length})"
+msgstr ""
+
+msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
+msgstr ""
+
msgid "WebIDE|Merge request"
msgstr ""
@@ -27993,15 +28926,9 @@ msgstr ""
msgid "Welcome to the guided GitLab tour"
msgstr ""
-msgid "Welcome to your Issue Board!"
-msgstr ""
-
msgid "Welcome to your issue board!"
msgstr ""
-msgid "We’ve been making changes to %{featureName} and we’d love your feedback %{linkStart}in this issue%{linkEnd} to help us improve the experience."
-msgstr ""
-
msgid "What are you searching for?"
msgstr ""
@@ -28020,6 +28947,9 @@ msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
msgstr ""
+msgid "When enabled, any user visiting %{host} and creating an account will have to be explicitly approved by the admin before they can login. This setting is effective only if sign-ups are enabled."
+msgstr ""
+
msgid "When enabled, any user visiting %{host} will be able to create an account."
msgstr ""
@@ -28244,6 +29174,9 @@ msgstr ""
msgid "With requirements, you can set criteria to check your products against."
msgstr ""
+msgid "With test cases, you can define conditions for your project to meet in determining quality"
+msgstr ""
+
msgid "Withdraw Access Request"
msgstr ""
@@ -28259,6 +29192,9 @@ msgstr ""
msgid "Workflow Help"
msgstr ""
+msgid "Would you like to create a new branch?"
+msgstr ""
+
msgid "Write"
msgstr ""
@@ -28280,6 +29216,9 @@ msgstr ""
msgid "Wrong extern UID provided. Make sure Auth0 is configured correctly."
msgstr ""
+msgid "YYYY-MM-DD"
+msgstr ""
+
msgid "Yes"
msgstr ""
@@ -28337,7 +29276,7 @@ msgstr ""
msgid "You are going to remove the fork relationship from %{project_full_name}. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "You are going to transfer %{project_full_name} to another owner. Are you ABSOLUTELY sure?"
+msgid "You are going to transfer %{project_full_name} to another namespace. Are you ABSOLUTELY sure?"
msgstr ""
msgid "You are going to turn off the confidentiality. This means %{strongStart}everyone%{strongEnd} will be able to see and leave a comment on this %{issuableType}."
@@ -28397,9 +29336,6 @@ msgstr ""
msgid "You can always edit this later"
msgstr ""
-msgid "You can apply your Trial to your Personal account or create a New Group."
-msgstr ""
-
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings"
msgstr ""
@@ -28421,12 +29357,18 @@ msgstr ""
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
+msgid "You can find more information about GitLab subscriptions in %{subscriptions_doc_link}."
+msgstr ""
+
msgid "You can generate an access token scoped to this project for each application to use the GitLab API."
msgstr ""
msgid "You can get started by cloning the repository or start adding files to it with one of the following options."
msgstr ""
+msgid "You can group test cases using labels. To learn about the future direction of this feature, visit %{linkStart}Quality Management direction page%{linkEnd}."
+msgstr ""
+
msgid "You can invite a new member to %{project_name} or invite another group."
msgstr ""
@@ -28442,6 +29384,9 @@ msgstr ""
msgid "You can notify the app / group or a project by sending them an email notification"
msgstr ""
+msgid "You can now close this window."
+msgstr ""
+
msgid "You can now export your security dashboard to a CSV report."
msgstr ""
@@ -28490,9 +29435,6 @@ msgstr ""
msgid "You can test your .gitlab-ci.yml in %{linkStart}CI Lint%{linkEnd}."
msgstr ""
-msgid "You can try again using %{begin_link}basic search%{end_link}"
-msgstr ""
-
msgid "You cannot access the raw file. Please wait a minute."
msgstr ""
@@ -28544,6 +29486,9 @@ msgstr ""
msgid "You don't have any U2F devices registered yet."
msgstr ""
+msgid "You don't have any WebAuthn devices registered yet."
+msgstr ""
+
msgid "You don't have any active chat names."
msgstr ""
@@ -28631,6 +29576,9 @@ msgstr ""
msgid "You must accept our Terms of Service and privacy policy in order to register an account"
msgstr ""
+msgid "You must be logged in to search across all of GitLab"
+msgstr ""
+
msgid "You must disassociate %{domain} from all clusters it is attached to before deletion."
msgstr ""
@@ -28670,7 +29618,7 @@ msgstr ""
msgid "You need to be logged in."
msgstr ""
-msgid "You need to register a two-factor authentication app before you can set up a U2F device."
+msgid "You need to register a two-factor authentication app before you can set up a device."
msgstr ""
msgid "You need to set terms to be enforced"
@@ -28688,6 +29636,9 @@ msgstr ""
msgid "You reached %{usage_in_percent} of %{namespace_name}'s storage capacity (%{used_storage} of %{storage_limit})"
msgstr ""
+msgid "You successfully declined the invitation"
+msgstr ""
+
msgid "You tried to fork %{link_to_the_project} but it failed for the following reason:"
msgstr ""
@@ -28853,10 +29804,13 @@ msgstr ""
msgid "Your U2F device did not send a valid JSON response."
msgstr ""
-msgid "Your U2F device needs to be set up. Plug it in (if not already) and click the button on the left."
+msgid "Your U2F device was registered!"
msgstr ""
-msgid "Your U2F device was registered!"
+msgid "Your WebAuthn device did not send a valid JSON response."
+msgstr ""
+
+msgid "Your WebAuthn device was registered!"
msgstr ""
msgid "Your access request to the %{source_type} has been withdrawn."
@@ -28880,6 +29834,9 @@ msgstr ""
msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
msgstr ""
+msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
+msgstr ""
+
msgid "Your changes can be committed to %{branch_name} because a merge request is open."
msgstr ""
@@ -28916,6 +29873,12 @@ msgstr ""
msgid "Your deployment services will be broken, you will need to manually fix the services after renaming."
msgstr ""
+msgid "Your device is not compatible with GitLab. Please try another device"
+msgstr ""
+
+msgid "Your device needs to be set up. Plug it in (if needed) and click the button on the left."
+msgstr ""
+
msgid "Your device was successfully set up! Give it a name and register it with the GitLab server."
msgstr ""
@@ -29029,9 +29992,6 @@ msgstr[1] ""
msgid "access:"
msgstr ""
-msgid "activated"
-msgstr ""
-
msgid "added %{created_at_timeago}"
msgstr ""
@@ -29104,9 +30064,21 @@ msgstr ""
msgid "by %{user}"
msgstr ""
+msgid "cannot be a date in the past"
+msgstr ""
+
msgid "cannot be changed if a personal project has container registry tags."
msgstr ""
+msgid "cannot be changed if shared runners are enabled"
+msgstr ""
+
+msgid "cannot be enabled because parent group does not allow it"
+msgstr ""
+
+msgid "cannot be enabled because parent group has shared Runners disabled"
+msgstr ""
+
msgid "cannot be enabled unless all domains have TLS certificates"
msgstr ""
@@ -29152,7 +30124,7 @@ msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about SAST %{linkEndTag}"
msgstr ""
-msgid "ciReport|%{linkStartTag}Learn more about Secret Scanning %{linkEndTag}"
+msgid "ciReport|%{linkStartTag}Learn more about Secret Detection %{linkEndTag}"
msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about codequality reports %{linkEndTag}"
@@ -29467,9 +30439,6 @@ msgstr ""
msgid "error"
msgstr ""
-msgid "error code:"
-msgstr ""
-
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr ""
@@ -29491,6 +30460,9 @@ msgstr ""
msgid "failed to dismiss associated finding(id=%{finding_id}): %{message}"
msgstr ""
+msgid "failed to revert associated finding(id=%{finding_id}) to detected"
+msgstr ""
+
msgid "file"
msgid_plural "files"
msgstr[0] ""
@@ -30033,6 +31005,9 @@ msgstr ""
msgid "must be a root namespace"
msgstr ""
+msgid "must be a valid IPv4 or IPv6 address"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -30069,6 +31044,9 @@ msgstr ""
msgid "no expiration"
msgstr ""
+msgid "no name set"
+msgstr ""
+
msgid "no one can merge"
msgstr ""
@@ -30247,9 +31225,6 @@ msgstr ""
msgid "security Reports|There was an error creating the merge request"
msgstr ""
-msgid "settings saved, but not activated"
-msgstr ""
-
msgid "severity|Critical"
msgstr ""
@@ -30376,9 +31351,6 @@ msgstr ""
msgid "toggle collapse"
msgstr ""
-msgid "toggle dropdown"
-msgstr ""
-
msgid "triggered"
msgstr ""
@@ -30406,6 +31378,9 @@ msgstr ""
msgid "user avatar"
msgstr ""
+msgid "user preferences"
+msgstr ""
+
msgid "username"
msgstr ""
diff --git a/locale/kab/gitlab.po b/locale/kab/gitlab.po
index 84e3b7064ba..1d417bb3609 100644
--- a/locale/kab/gitlab.po
+++ b/locale/kab/gitlab.po
@@ -14,7 +14,10 @@ msgstr ""
"X-Crowdin-Language: kab\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 6\n"
-"PO-Revision-Date: 2020-09-04 23:11\n"
+"PO-Revision-Date: 2020-10-02 18:51\n"
+
+msgid " %{project_name}#%{issue_iid} &middot; opened %{issue_created} by %{author}"
+msgstr ""
msgid " %{start} to %{end}"
msgstr ""
@@ -74,6 +77,16 @@ msgstr ""
msgid "\"el\" parameter is required for createInstance()"
msgstr ""
+msgid "%d Approval"
+msgid_plural "%d Approvals"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d Package"
+msgid_plural "%d Packages"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d Scanned URL"
msgid_plural "%d Scanned URLs"
msgstr[0] ""
@@ -137,6 +150,11 @@ msgstr[1] ""
msgid "%d commits"
msgstr ""
+msgid "%d completed issue"
+msgid_plural "%d completed issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d contribution"
msgid_plural "%d contributions"
msgstr[0] ""
@@ -147,6 +165,11 @@ msgid_plural "%d days"
msgstr[0] ""
msgstr[1] ""
+msgid "%d day until tags are automatically removed"
+msgid_plural "%d days until tags are automatically removed"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d error"
msgid_plural "%d errors"
msgstr[0] ""
@@ -237,6 +260,16 @@ msgid_plural "%d more comments"
msgstr[0] ""
msgstr[1] ""
+msgid "%d open issue"
+msgid_plural "%d open issues"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d pending comment"
+msgid_plural "%d pending comments"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d personal project will be removed and cannot be restored."
msgid_plural "%d personal projects will be removed and cannot be restored."
msgstr[0] ""
@@ -252,6 +285,11 @@ msgid_plural "%d projects"
msgstr[0] ""
msgstr[1] ""
+msgid "%d project selected"
+msgid_plural "%d projects selected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d request with warnings"
msgid_plural "%d requests with warnings"
msgstr[0] ""
@@ -272,6 +310,11 @@ msgid_plural "%d tags"
msgstr[0] ""
msgstr[1] ""
+msgid "%d tag per image name"
+msgid_plural "%d tags per image name"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d unassigned issue"
msgid_plural "%d unassigned issues"
msgstr[0] ""
@@ -292,6 +335,11 @@ msgid_plural "%d vulnerabilities dismissed"
msgstr[0] ""
msgstr[1] ""
+msgid "%d warning found:"
+msgid_plural "%d warnings found:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%s additional commit has been omitted to prevent performance issues."
msgid_plural "%s additional commits have been omitted to prevent performance issues."
msgstr[0] ""
@@ -330,6 +378,9 @@ msgstr ""
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr ""
+msgid "%{completedCount} completed weight"
+msgstr ""
+
msgid "%{completedWeight} of %{totalWeight} weight completed"
msgstr ""
@@ -378,14 +429,12 @@ msgid_plural "%{count} participants"
msgstr[0] ""
msgstr[1] ""
-msgid "%{count} pending comment"
-msgid_plural "%{count} pending comments"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
+msgid "%{count} total weight"
+msgstr ""
+
msgid "%{dashboard_path} could not be found."
msgstr ""
@@ -440,6 +489,9 @@ msgstr ""
msgid "%{group_name} uses group managed accounts. You need to create a new GitLab account which will be managed by %{group_name}."
msgstr ""
+msgid "%{group_name}&%{epic_iid} &middot; opened %{epic_created} by %{author}"
+msgstr ""
+
msgid "%{host} sign-in from new location"
msgstr ""
@@ -452,7 +504,7 @@ msgstr ""
msgid "%{issuableType} will be removed! Are you sure?"
msgstr ""
-msgid "%{issuesSize} issues with a limit of %{maxIssueCount}"
+msgid "%{issuesCount} issues with a limit of %{maxIssueCount}"
msgstr ""
msgid "%{issuesSize} with a limit of %{maxIssueCount}"
@@ -485,7 +537,7 @@ msgstr ""
msgid "%{labelStart}Namespace:%{labelEnd} %{namespace}"
msgstr ""
-msgid "%{labelStart}Report Type:%{labelEnd} %{reportType}"
+msgid "%{labelStart}Scan Type:%{labelEnd} %{reportType}"
msgstr ""
msgid "%{labelStart}Scanner:%{labelEnd} %{scanner}"
@@ -682,9 +734,6 @@ msgid_plural "%{securityScanner} results are not available because a pipeline ha
msgstr[0] ""
msgstr[1] ""
-msgid "%{service_title} %{message}."
-msgstr ""
-
msgid "%{size} GiB"
msgstr ""
@@ -773,6 +822,12 @@ msgstr ""
msgid "%{timebox_name} should belong either to a project or a group."
msgstr ""
+msgid "%{timebox_type} does not support burnup charts"
+msgstr ""
+
+msgid "%{timebox_type} must have a start and due date"
+msgstr ""
+
msgid "%{title} %{operator} %{threshold}"
msgstr ""
@@ -797,7 +852,7 @@ msgstr ""
msgid "%{total} open issue weight"
msgstr ""
-msgid "%{total} open issues"
+msgid "%{total} warnings found: showing first %{warningsDisplayed}"
msgstr ""
msgid "%{usage_ping_link_start}Learn more%{usage_ping_link_end} about what information is shared with GitLab Inc."
@@ -830,9 +885,6 @@ msgstr ""
msgid "&lt; 1 hour"
msgstr ""
-msgid "&lt;no name set&gt;"
-msgstr ""
-
msgid "&lt;no scopes selected&gt;"
msgstr ""
@@ -863,6 +915,9 @@ msgstr ""
msgid "'%{name}' Value Stream created"
msgstr ""
+msgid "'%{name}' Value Stream deleted"
+msgstr ""
+
msgid "'%{name}' stage already exists"
msgstr ""
@@ -922,6 +977,9 @@ msgstr ""
msgid "+ %{numberOfHiddenAssignees} more"
msgstr ""
+msgid "+ %{numberOfHiddenReviewers} more"
+msgstr ""
+
msgid "+%d more"
msgid_plural "+%d more"
msgstr[0] ""
@@ -982,6 +1040,11 @@ msgid_plural "%d Days"
msgstr[0] ""
msgstr[1] ""
+msgid "1 Issue"
+msgid_plural "%d Issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "1 closed issue"
msgid_plural "%{issues} closed issues"
msgstr[0] ""
@@ -997,6 +1060,11 @@ msgid_plural "%d days"
msgstr[0] ""
msgstr[1] ""
+msgid "1 deploy key"
+msgid_plural "%d deploy keys"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1099,6 +1167,9 @@ msgstr ""
msgid ":%{startLine} to %{endLine}"
msgstr ""
+msgid "A %{incident_docs_start}modified issue%{incident_docs_end} to guide the resolution of incidents."
+msgstr ""
+
msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr ""
@@ -1111,6 +1182,9 @@ msgstr ""
msgid "A GitBook site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
+msgid "A Gitpod configured Webapplication in Spring and Java"
+msgstr ""
+
msgid "A Hexo site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
@@ -1282,9 +1356,15 @@ msgstr ""
msgid "Access expiration date"
msgstr ""
+msgid "Access expires"
+msgstr ""
+
msgid "Access forbidden. Check your access level."
msgstr ""
+msgid "Access granted"
+msgstr ""
+
msgid "Access requests"
msgstr ""
@@ -1294,6 +1374,9 @@ msgstr ""
msgid "Access to Pages websites are controlled based on the user's membership to a given project. By checking this box, users will be required to be logged in to have access to all Pages websites in your instance."
msgstr ""
+msgid "AccessDropdown|Deploy Keys"
+msgstr ""
+
msgid "AccessDropdown|Groups"
msgstr ""
@@ -1411,12 +1494,6 @@ msgstr ""
msgid "Active Sessions"
msgstr ""
-msgid "Active Users:"
-msgstr ""
-
-msgid "Active users"
-msgstr ""
-
msgid "Activity"
msgstr ""
@@ -1584,9 +1661,6 @@ msgstr ""
msgid "Add label(s)"
msgstr ""
-msgid "Add license"
-msgstr ""
-
msgid "Add list"
msgstr ""
@@ -1761,21 +1835,51 @@ msgstr ""
msgid "AdminArea|Bots"
msgstr ""
+msgid "AdminArea|Components"
+msgstr ""
+
msgid "AdminArea|Developer"
msgstr ""
+msgid "AdminArea|Features"
+msgstr ""
+
+msgid "AdminArea|Groups: %{number_of_groups}"
+msgstr ""
+
msgid "AdminArea|Guest"
msgstr ""
msgid "AdminArea|Included Free in license"
msgstr ""
+msgid "AdminArea|Latest groups"
+msgstr ""
+
+msgid "AdminArea|Latest projects"
+msgstr ""
+
+msgid "AdminArea|Latest users"
+msgstr ""
+
msgid "AdminArea|Maintainer"
msgstr ""
+msgid "AdminArea|New group"
+msgstr ""
+
+msgid "AdminArea|New project"
+msgstr ""
+
+msgid "AdminArea|New user"
+msgstr ""
+
msgid "AdminArea|Owner"
msgstr ""
+msgid "AdminArea|Projects: %{number_of_projects}"
+msgstr ""
+
msgid "AdminArea|Reporter"
msgstr ""
@@ -1803,6 +1907,9 @@ msgstr ""
msgid "AdminArea|Users without a Group and Project"
msgstr ""
+msgid "AdminArea|Users: %{number_of_users}"
+msgstr ""
+
msgid "AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running."
msgstr ""
@@ -1821,9 +1928,6 @@ msgstr ""
msgid "AdminProjects|Delete Project %{projectName}?"
msgstr ""
-msgid "AdminProjects|Delete project"
-msgstr ""
-
msgid "AdminSettings|Apply integration settings to all Projects"
msgstr ""
@@ -2061,21 +2165,30 @@ msgstr ""
msgid "AdminUsers|Without projects"
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 ""
msgid "AdminUsers|You cannot remove your own admin rights."
msgstr ""
+msgid "AdminUsers|You must transfer ownership or delete the groups owned by this user before you can delete their account"
+msgstr ""
+
msgid "Administration"
msgstr ""
msgid "Advanced"
msgstr ""
+msgid "Advanced Search"
+msgstr ""
+
+msgid "Advanced Search with Elasticsearch"
+msgstr ""
+
msgid "Advanced Settings"
msgstr ""
@@ -2153,6 +2266,9 @@ msgstr ""
msgid "AlertManagement|Edit"
msgstr ""
+msgid "AlertManagement|Environment"
+msgstr ""
+
msgid "AlertManagement|Events"
msgstr ""
@@ -2165,6 +2281,9 @@ msgstr ""
msgid "AlertManagement|Issue"
msgstr ""
+msgid "AlertManagement|Key"
+msgstr ""
+
msgid "AlertManagement|Low"
msgstr ""
@@ -2258,6 +2377,9 @@ msgstr ""
msgid "AlertManagement|Unknown"
msgstr ""
+msgid "AlertManagement|Value"
+msgstr ""
+
msgid "AlertManagement|View alerts in Opsgenie"
msgstr ""
@@ -2417,6 +2539,9 @@ msgstr ""
msgid "All projects"
msgstr ""
+msgid "All projects selected"
+msgstr ""
+
msgid "All security scans are enabled because %{linkStart}Auto DevOps%{linkEnd} is enabled on this project"
msgstr ""
@@ -2504,6 +2629,9 @@ msgstr ""
msgid "Almost there"
msgstr ""
+msgid "Already blocked"
+msgstr ""
+
msgid "Also called \"Issuer\" or \"Relying party trust identifier\""
msgstr ""
@@ -2558,6 +2686,9 @@ msgstr ""
msgid "An error has occurred"
msgstr ""
+msgid "An error occured while making the changes: %{error}"
+msgstr ""
+
msgid "An error occurred adding a draft to the thread."
msgstr ""
@@ -2585,12 +2716,6 @@ msgstr ""
msgid "An error occurred when toggling the notification subscription"
msgstr ""
-msgid "An error occurred when trying to resolve a comment. Please try again."
-msgstr ""
-
-msgid "An error occurred when trying to resolve a discussion. Please try again."
-msgstr ""
-
msgid "An error occurred when updating the issue weight"
msgstr ""
@@ -2606,12 +2731,6 @@ msgstr ""
msgid "An error occurred while checking group path. Please refresh and try again."
msgstr ""
-msgid "An error occurred while committing your changes."
-msgstr ""
-
-msgid "An error occurred while creating the list. Please try again."
-msgstr ""
-
msgid "An error occurred while decoding the file."
msgstr ""
@@ -2684,25 +2803,19 @@ msgstr ""
msgid "An error occurred while fetching the Service Desk address."
msgstr ""
-msgid "An error occurred while fetching the board issues. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the board lists. Please reload the page."
msgstr ""
msgid "An error occurred while fetching the board lists. Please try again."
msgstr ""
-msgid "An error occurred while fetching the board swimlanes. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the builds."
msgstr ""
msgid "An error occurred while fetching the job log."
msgstr ""
-msgid "An error occurred while fetching the job trace."
+msgid "An error occurred while fetching the job logs."
msgstr ""
msgid "An error occurred while fetching the job."
@@ -2849,9 +2962,6 @@ msgstr ""
msgid "An error occurred while saving assignees"
msgstr ""
-msgid "An error occurred while saving the template. Please check if the template exists."
-msgstr ""
-
msgid "An error occurred while searching for milestones"
msgstr ""
@@ -2870,10 +2980,10 @@ msgstr ""
msgid "An error occurred while updating approvers"
msgstr ""
-msgid "An error occurred while updating the comment"
+msgid "An error occurred while updating labels."
msgstr ""
-msgid "An error occurred while updating the list. Please try again."
+msgid "An error occurred while updating the comment"
msgstr ""
msgid "An error occurred while validating group path"
@@ -2927,6 +3037,9 @@ msgstr ""
msgid "An unknown error occurred while loading this graph."
msgstr ""
+msgid "An unknown error occurred."
+msgstr ""
+
msgid "Analytics"
msgstr ""
@@ -2960,10 +3073,10 @@ msgstr ""
msgid "Any"
msgstr ""
-msgid "Any Author"
+msgid "Any %{header}"
msgstr ""
-msgid "Any Status"
+msgid "Any Author"
msgstr ""
msgid "Any branch"
@@ -3017,6 +3130,9 @@ msgstr ""
msgid "Application ID"
msgstr ""
+msgid "Application limits saved successfully"
+msgstr ""
+
msgid "Application settings saved successfully"
msgstr ""
@@ -3226,6 +3342,9 @@ msgstr ""
msgid "Are you sure you want to close this blocked issue?"
msgstr ""
+msgid "Are you sure you want to delete \"%{name}\" Value Stream?"
+msgstr ""
+
msgid "Are you sure you want to delete %{name}?"
msgstr ""
@@ -3235,6 +3354,9 @@ msgstr ""
msgid "Are you sure you want to delete this %{typeOfComment}?"
msgstr ""
+msgid "Are you sure you want to delete this SSH key?"
+msgstr ""
+
msgid "Are you sure you want to delete this board?"
msgstr ""
@@ -3259,6 +3381,11 @@ msgstr ""
msgid "Are you sure you want to erase this build?"
msgstr ""
+msgid "Are you sure you want to import %d repository?"
+msgid_plural "Are you sure you want to import %d repositories?"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Are you sure you want to lose unsaved changes?"
msgstr ""
@@ -3268,15 +3395,15 @@ msgstr ""
msgid "Are you sure you want to merge immediately?"
msgstr ""
-msgid "Are you sure you want to permanently delete this license?"
-msgstr ""
-
msgid "Are you sure you want to re-deploy this environment?"
msgstr ""
msgid "Are you sure you want to regenerate the public key? You will have to update the public key on the remote server before mirroring will work again."
msgstr ""
+msgid "Are you sure you want to reindex?"
+msgstr ""
+
msgid "Are you sure you want to remove %{group_name}?"
msgstr ""
@@ -3304,6 +3431,9 @@ msgstr ""
msgid "Are you sure you want to revoke this nickname?"
msgstr ""
+msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
+msgstr ""
+
msgid "Are you sure you want to stop this environment?"
msgstr ""
@@ -3325,6 +3455,9 @@ msgstr ""
msgid "Are you sure? The device will be signed out of GitLab and all remember me tokens revoked."
msgstr ""
+msgid "Are you sure? This will invalidate your registered applications and U2F / WebAuthn devices."
+msgstr ""
+
msgid "Are you sure? This will invalidate your registered applications and U2F devices."
msgstr ""
@@ -3343,9 +3476,6 @@ msgstr ""
msgid "Artifacts"
msgstr ""
-msgid "As U2F devices are only supported by a few browsers, we require that you set up a two-factor authentication app before a U2F device. That way you'll always be able to log in - even when you're using an unsupported browser."
-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 ""
@@ -3539,6 +3669,9 @@ msgstr ""
msgid "AuditLogs|Target"
msgstr ""
+msgid "AuditLogs|This month"
+msgstr ""
+
msgid "AuditLogs|User Events"
msgstr ""
@@ -3578,6 +3711,9 @@ msgstr ""
msgid "Authentication via U2F device failed."
msgstr ""
+msgid "Authentication via WebAuthn device failed."
+msgstr ""
+
msgid "Author"
msgstr ""
@@ -3845,15 +3981,6 @@ msgstr ""
msgid "BambooService|You must set up automatic revision labeling and a repository trigger in Bamboo."
msgstr ""
-msgid "BatchComments|Delete all pending comments"
-msgstr ""
-
-msgid "BatchComments|Discard review?"
-msgstr ""
-
-msgid "BatchComments|You're about to discard your review which will delete all of your pending comments. The deleted comments %{strong_start}cannot%{strong_end} be restored."
-msgstr ""
-
msgid "Be careful. Changing the project's namespace can have unintended side effects."
msgstr ""
@@ -3875,6 +4002,9 @@ msgstr ""
msgid "Bi-weekly code coverage"
msgstr ""
+msgid "Billable Users:"
+msgstr ""
+
msgid "Billing"
msgstr ""
@@ -3884,7 +4014,7 @@ msgstr ""
msgid "BillingPlans|@%{user_name} you are currently using the %{plan_name} plan."
msgstr ""
-msgid "BillingPlans|Congratulations, your new trial is activated"
+msgid "BillingPlans|Congratulations, your free trial is activated."
msgstr ""
msgid "BillingPlans|If you would like to downgrade your plan please contact %{support_link_start}Customer Support%{support_link_end}."
@@ -3947,6 +4077,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Block user"
+msgstr ""
+
msgid "Blocked"
msgstr ""
@@ -3962,31 +4095,37 @@ msgstr ""
msgid "Blog"
msgstr ""
-msgid "Board name"
-msgstr ""
-
msgid "Board scope"
msgstr ""
msgid "Board scope affects which issues are displayed for anyone who visits this board"
msgstr ""
-msgid "BoardBlankState|Add default lists"
+msgid "Boards"
msgstr ""
-msgid "BoardBlankState|Add the following default lists to your Issue Board with one click:"
+msgid "Boards and Board Lists"
msgstr ""
-msgid "BoardBlankState|Nevermind, I'll use my own"
+msgid "Boards|An error occurred while creating the issue. Please try again."
msgstr ""
-msgid "BoardBlankState|Starting out with the default set of lists will get you right on the way to making the most of your board."
+msgid "Boards|An error occurred while creating the list. Please try again."
msgstr ""
-msgid "Boards"
+msgid "Boards|An error occurred while fetching issues. Please reload the page."
msgstr ""
-msgid "Boards and Board Lists"
+msgid "Boards|An error occurred while fetching the board issues. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching the board swimlanes. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while moving the issue. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while updating the list. Please try again."
msgstr ""
msgid "Boards|Collapse"
@@ -4013,7 +4152,7 @@ msgstr ""
msgid "Branch %{branch_name} was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr ""
-msgid "Branch has changed"
+msgid "Branch changed"
msgstr ""
msgid "Branch is already taken"
@@ -4319,6 +4458,9 @@ msgstr ""
msgid "CLOSED (MOVED)"
msgstr ""
+msgid "CODEOWNERS rule violation"
+msgstr ""
+
msgid "CONTRIBUTING"
msgstr ""
@@ -4349,9 +4491,6 @@ msgstr ""
msgid "Can't create snippet: %{err}"
msgstr ""
-msgid "Can't edit as source branch was deleted"
-msgstr ""
-
msgid "Can't fetch content for the blob: %{err}"
msgstr ""
@@ -4364,9 +4503,6 @@ msgstr ""
msgid "Can't load mermaid module: %{err}"
msgstr ""
-msgid "Can't remove group members without group managed account"
-msgstr ""
-
msgid "Can't scan the code?"
msgstr ""
@@ -4409,6 +4545,9 @@ msgstr ""
msgid "Cannot create the abuse report. This user has been blocked."
msgstr ""
+msgid "Cannot enable shared runners because parent group does not allow it"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -4514,6 +4653,15 @@ msgstr ""
msgid "Change your password or recover your current one"
msgstr ""
+msgid "ChangeReviewer|Reviewer changed from %{old} to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Reviewer changed to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Unassigned"
+msgstr ""
+
msgid "ChangeTypeActionLabel|Pick into branch"
msgstr ""
@@ -4553,6 +4701,9 @@ msgstr ""
msgid "Changes the title to \"%{title_param}\"."
msgstr ""
+msgid "Changes were successfully made."
+msgstr ""
+
msgid "Changes won't take place until the index is %{link_start}recreated%{link_end}."
msgstr ""
@@ -4958,6 +5109,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove variable"
+msgstr ""
+
msgid "CiVariables|Remove variable row"
msgstr ""
@@ -5036,9 +5190,6 @@ msgstr ""
msgid "Clear due date"
msgstr ""
-msgid "Clear input"
-msgstr ""
-
msgid "Clear recent searches"
msgstr ""
@@ -5087,6 +5238,9 @@ msgstr ""
msgid "Client authentication key password"
msgstr ""
+msgid "Client request timeout"
+msgstr ""
+
msgid "Clients"
msgstr ""
@@ -5171,6 +5325,27 @@ msgstr ""
msgid "Cluster type must be specificed for Stages::ClusterEndpointInserter"
msgstr ""
+msgid "ClusterAgents|Configuration"
+msgstr ""
+
+msgid "ClusterAgents|Connect your cluster with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate Kubernetes with a GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Name"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Agent also requires %{linkStart}enabling the Agent Server%{linkEnd}"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Kubernetes Agent allows an Infrastructure as Code, GitOps approach to integrating Kubernetes clusters with GitLab. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "ClusterAgent|This feature is only available for premium plans"
msgstr ""
@@ -5240,10 +5415,10 @@ msgstr ""
msgid "ClusterIntegration|All installed applications and related resources"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster."
+msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{linkStart}More information%{linkEnd}"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{startLink}More information%{endLink}"
+msgid "ClusterIntegration|Allow GitLab to manage namespaces and service accounts for this cluster."
msgstr ""
msgid "ClusterIntegration|Alternatively, "
@@ -5264,6 +5439,9 @@ msgstr ""
msgid "ClusterIntegration|An error occurred while trying to fetch zone machine types: %{error}"
msgstr ""
+msgid "ClusterIntegration|An unknown error occurred while attempting to connect to Kubernetes."
+msgstr ""
+
msgid "ClusterIntegration|Any project namespaces"
msgstr ""
@@ -5279,6 +5457,9 @@ msgstr ""
msgid "ClusterIntegration|Authenticate with Amazon Web Services"
msgstr ""
+msgid "ClusterIntegration|Authentication Error"
+msgstr ""
+
msgid "ClusterIntegration|Base domain"
msgstr ""
@@ -5297,13 +5478,22 @@ msgstr ""
msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}security group %{externalLinkIcon} %{endLink} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
+msgid "ClusterIntegration|Check your CA certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Check your cluster status"
+msgstr ""
+
+msgid "ClusterIntegration|Check your token"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}subnets %{externalLinkIcon} %{endLink} in your VPC where your worker nodes will run."
+msgid "ClusterIntegration|Choose the %{linkStart}security group %{linkEnd} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
msgstr ""
-msgid "ClusterIntegration|Choose the worker node %{startLink}instance type %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Choose the %{linkStart}subnets %{linkEnd} in your VPC where your worker nodes will run."
+msgstr ""
+
+msgid "ClusterIntegration|Choose the worker node %{linkStart}instance type%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Choose which applications to install on your Kubernetes cluster."
@@ -5315,10 +5505,7 @@ msgstr ""
msgid "ClusterIntegration|Clear cluster cache"
msgstr ""
-msgid "ClusterIntegration|Clear the local cache of namespace and service accounts. This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
-msgstr ""
-
-msgid "ClusterIntegration|Cluster being created"
+msgid "ClusterIntegration|Clear the local cache of namespace and service accounts."
msgstr ""
msgid "ClusterIntegration|Cluster management project (alpha)"
@@ -5330,15 +5517,21 @@ msgstr ""
msgid "ClusterIntegration|Cluster_applications artifact too big. Maximum allowable size: %{human_size}"
msgstr ""
-msgid "ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters."
+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|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}"
+msgid "ClusterIntegration|Clusters connected with a certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Connect cluster with certificate"
msgstr ""
msgid "ClusterIntegration|Connect existing cluster"
msgstr ""
+msgid "ClusterIntegration|Connection Error"
+msgstr ""
+
msgid "ClusterIntegration|Copy API URL"
msgstr ""
@@ -5414,6 +5607,12 @@ msgstr ""
msgid "ClusterIntegration|Deletes all GitLab resources attached to this cluster during removal"
msgstr ""
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared."
+msgstr ""
+
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared. %{linkStart}More information%{linkEnd}"
+msgstr ""
+
msgid "ClusterIntegration|Did you know?"
msgstr ""
@@ -5483,6 +5682,9 @@ msgstr ""
msgid "ClusterIntegration|Fluentd is an open source data collector, which lets you unify the data collection and consumption for a better use and understanding of data. It requires at least one of the following logs to be successfully installed."
msgstr ""
+msgid "ClusterIntegration|GitLab Agent managed clusters"
+msgstr ""
+
msgid "ClusterIntegration|GitLab Container Network Policies"
msgstr ""
@@ -5495,6 +5697,12 @@ msgstr ""
msgid "ClusterIntegration|GitLab Runner connects to the repository and executes CI/CD jobs, pushing results back and deploying applications to production."
msgstr ""
+msgid "ClusterIntegration|GitLab failed to authenticate."
+msgstr ""
+
+msgid "ClusterIntegration|GitLab failed to connect to the cluster."
+msgstr ""
+
msgid "ClusterIntegration|GitLab-managed cluster"
msgstr ""
@@ -5516,6 +5724,9 @@ msgstr ""
msgid "ClusterIntegration|Group cluster"
msgstr ""
+msgid "ClusterIntegration|HTTP Error"
+msgstr ""
+
msgid "ClusterIntegration|Helm Tiller"
msgstr ""
@@ -5549,7 +5760,10 @@ msgstr ""
msgid "ClusterIntegration|Instance type"
msgstr ""
-msgid "ClusterIntegration|Integrate Kubernetes cluster automation"
+msgid "ClusterIntegration|Integrate Kubernetes with a cluster certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Integrate with a cluster certificate"
msgstr ""
msgid "ClusterIntegration|Issuer Email"
@@ -5585,9 +5799,6 @@ msgstr ""
msgid "ClusterIntegration|Knative extends Kubernetes to provide a set of middleware components that are essential to build modern, source-centric, and container-based applications that can run anywhere: on premises, in the cloud, or even in a third-party data center."
msgstr ""
-msgid "ClusterIntegration|Kubernetes cluster"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes cluster is being created..."
msgstr ""
@@ -5600,9 +5811,6 @@ msgstr ""
msgid "ClusterIntegration|Kubernetes clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr ""
-msgid "ClusterIntegration|Kubernetes clusters can be used to deploy applications and to provide Review Apps for this project"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes version"
msgstr ""
@@ -5615,7 +5823,7 @@ msgstr ""
msgid "ClusterIntegration|Learn more about %{help_link_start}zones%{help_link_end}."
msgstr ""
-msgid "ClusterIntegration|Learn more about %{startLink}Regions %{externalLinkIcon}%{endLink}."
+msgid "ClusterIntegration|Learn more about %{linkStart}Regions%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Learn more about Kubernetes"
@@ -5660,12 +5868,18 @@ msgstr ""
msgid "ClusterIntegration|Machine type"
msgstr ""
+msgid "ClusterIntegration|Make sure your API endpoint is correct"
+msgstr ""
+
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create Kubernetes clusters"
msgstr ""
msgid "ClusterIntegration|Manage your Kubernetes cluster by visiting %{provider_link}"
msgstr ""
+msgid "ClusterIntegration|Namespace per environment"
+msgstr ""
+
msgid "ClusterIntegration|No IAM Roles found"
msgstr ""
@@ -5711,6 +5925,9 @@ msgstr ""
msgid "ClusterIntegration|No zones matched your search"
msgstr ""
+msgid "ClusterIntegration|Node calculations use the Kubernetes Metrics API. Make sure your cluster has metrics installed"
+msgstr ""
+
msgid "ClusterIntegration|Number of nodes"
msgstr ""
@@ -5753,6 +5970,9 @@ msgstr ""
msgid "ClusterIntegration|RBAC-enabled cluster"
msgstr ""
+msgid "ClusterIntegration|Read our %{linkStart}help page%{linkEnd} on Kubernetes cluster integration."
+msgstr ""
+
msgid "ClusterIntegration|Read our %{link_start}help page%{link_end} on Kubernetes cluster integration."
msgstr ""
@@ -5855,7 +6075,7 @@ msgstr ""
msgid "ClusterIntegration|Select a VPC to choose a subnet"
msgstr ""
-msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{linkStart}Amazon Web Services %{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select a network to choose a subnetwork"
@@ -5888,7 +6108,7 @@ msgstr ""
msgid "ClusterIntegration|Select project to choose zone"
msgstr ""
-msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select zone"
@@ -5978,9 +6198,18 @@ msgstr ""
msgid "ClusterIntegration|There was a problem authenticating with your cluster. Please ensure your CA Certificate and Token are valid."
msgstr ""
+msgid "ClusterIntegration|There was an HTTP error when connecting to your cluster."
+msgstr ""
+
msgid "ClusterIntegration|This account must have permissions to create a Kubernetes cluster in the %{link_to_container_project} specified below"
msgstr ""
+msgid "ClusterIntegration|This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
+msgstr ""
+
+msgid "ClusterIntegration|This is necessary to clear existing environment-namespace associations from clusters previously managed by GitLab."
+msgstr ""
+
msgid "ClusterIntegration|This option will allow you to install applications on RBAC clusters."
msgstr ""
@@ -6005,9 +6234,21 @@ msgstr ""
msgid "ClusterIntegration|To use a new project, first create one on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}."
msgstr ""
+msgid "ClusterIntegration|Troubleshooting tips:"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Authenticate"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Connect"
+msgstr ""
+
msgid "ClusterIntegration|Uninstall %{appTitle}"
msgstr ""
+msgid "ClusterIntegration|Unknown Error"
+msgstr ""
+
msgid "ClusterIntegration|Update %{appTitle}"
msgstr ""
@@ -6068,7 +6309,7 @@ msgstr ""
msgid "ClusterIntegration|Your cluster API is unreachable. Please ensure your API URL is correct."
msgstr ""
-msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Zone"
@@ -6188,6 +6429,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse all threads"
+msgstr ""
+
msgid "Collapse approvers"
msgstr ""
@@ -6337,7 +6581,7 @@ msgstr ""
msgid "Commit…"
msgstr ""
-msgid "Company"
+msgid "Community forum"
msgstr ""
msgid "Company name"
@@ -6346,6 +6590,9 @@ msgstr ""
msgid "Compare"
msgstr ""
+msgid "Compare %{oldCommitId}...%{newCommitId}"
+msgstr ""
+
msgid "Compare Git revisions"
msgstr ""
@@ -6361,6 +6608,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare submodule commit revisions"
+msgstr ""
+
msgid "Compare with previous version"
msgstr ""
@@ -6496,6 +6746,9 @@ msgstr ""
msgid "Configure the way a user creates a new account."
msgstr ""
+msgid "Configure which lists are shown for anyone who visits this board"
+msgstr ""
+
msgid "Confirm"
msgstr ""
@@ -6721,6 +6974,9 @@ msgstr[1] ""
msgid "ContainerRegistry|Set cleanup policy"
msgstr ""
+msgid "ContainerRegistry|Some tags were not deleted"
+msgstr ""
+
msgid "ContainerRegistry|Something went wrong while fetching the cleanup policy."
msgstr ""
@@ -6760,6 +7016,9 @@ msgstr ""
msgid "ContainerRegistry|Tags with names matching this regex pattern will %{italicStart}expire:%{italicEnd}"
msgstr ""
+msgid "ContainerRegistry|The cleanup policy timed out before it could delete all tags. An administrator can %{adminLinkStart}manually run cleanup now%{adminLinkEnd} or you can wait for the cleanup policy to automatically run again. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "ContainerRegistry|The last tag related to this image was recently removed. This empty image and any associated data will be automatically removed as part of the regular Garbage Collection process. If you have any questions, contact your administrator."
msgstr ""
@@ -6892,6 +7151,9 @@ msgstr ""
msgid "Contributions per group member"
msgstr ""
+msgid "Contributor"
+msgstr ""
+
msgid "Contributors"
msgstr ""
@@ -7021,6 +7283,9 @@ msgstr ""
msgid "Could not change HEAD: branch '%{branch}' does not exist"
msgstr ""
+msgid "Could not commit. An unexpected error occurred."
+msgstr ""
+
msgid "Could not connect to FogBugz, check your URL"
msgstr ""
@@ -7060,6 +7325,9 @@ msgstr ""
msgid "Could not find iteration"
msgstr ""
+msgid "Could not load instance counts. Please refresh the page to try again."
+msgstr ""
+
msgid "Could not remove the trigger."
msgstr ""
@@ -7084,10 +7352,10 @@ msgstr ""
msgid "Could not save prometheus manual configuration"
msgstr ""
-msgid "Could not udpdate wiki page"
+msgid "Could not update the LDAP settings"
msgstr ""
-msgid "Could not update the LDAP settings"
+msgid "Could not update wiki page"
msgstr ""
msgid "Could not upload your designs as one or more files uploaded are not supported."
@@ -7745,6 +8013,9 @@ msgstr ""
msgid "DastProfiles|Are you sure you want to delete this profile?"
msgstr ""
+msgid "DastProfiles|Could not create site validation token. Please refresh the page, or try again later."
+msgstr ""
+
msgid "DastProfiles|Could not create the scanner profile. Please try again."
msgstr ""
@@ -7769,6 +8040,12 @@ msgstr ""
msgid "DastProfiles|Could not fetch site profiles. Please refresh the page, or try again later."
msgstr ""
+msgid "DastProfiles|Could not retrieve site validation status. Please refresh the page, or try again later."
+msgstr ""
+
+msgid "DastProfiles|Could not update the scanner profile. Please try again."
+msgstr ""
+
msgid "DastProfiles|Could not update the site profile. Please try again."
msgstr ""
@@ -7784,7 +8061,7 @@ msgstr ""
msgid "DastProfiles|Download validation text file"
msgstr ""
-msgid "DastProfiles|Edit feature will come soon. Please create a new profile if changes needed"
+msgid "DastProfiles|Edit scanner profile"
msgstr ""
msgid "DastProfiles|Edit site profile"
@@ -7817,6 +8094,9 @@ msgstr ""
msgid "DastProfiles|No profiles created yet"
msgstr ""
+msgid "DastProfiles|Passive"
+msgstr ""
+
msgid "DastProfiles|Please enter a valid URL format, ex: http://www.example.com/home"
msgstr ""
@@ -7832,6 +8112,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan mode"
+msgstr ""
+
msgid "DastProfiles|Scanner Profile"
msgstr ""
@@ -7871,10 +8154,10 @@ msgstr ""
msgid "DastProfiles|Text file validation"
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
+msgid "DastProfiles|The maximum number of minutes allowed for the spider to traverse the site."
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the spider to traverse the site."
+msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
msgstr ""
msgid "DastProfiles|Validate"
@@ -7907,6 +8190,9 @@ msgstr ""
msgid "Date picker"
msgstr ""
+msgid "Date range"
+msgstr ""
+
msgid "Date range cannot exceed %{maxDateRange} days."
msgstr ""
@@ -7931,6 +8217,9 @@ msgstr ""
msgid "Days to merge"
msgstr ""
+msgid "Dear Administrator,"
+msgstr ""
+
msgid "Debug"
msgstr ""
@@ -8042,12 +8331,18 @@ msgstr ""
msgid "Delete"
msgstr ""
+msgid "Delete %{name}"
+msgstr ""
+
msgid "Delete Comment"
msgstr ""
msgid "Delete Snippet"
msgstr ""
+msgid "Delete Value Stream"
+msgstr ""
+
msgid "Delete account"
msgstr ""
@@ -8069,9 +8364,6 @@ msgstr ""
msgid "Delete label: %{label_name} ?"
msgstr ""
-msgid "Delete license"
-msgstr ""
-
msgid "Delete list"
msgstr ""
@@ -8147,15 +8439,6 @@ msgstr ""
msgid "Deleting a project places it into a read-only state until %{date}, at which point the project will be permanently deleted. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "Deleting the license failed."
-msgstr ""
-
-msgid "Deleting the license failed. The license was not found."
-msgstr ""
-
-msgid "Deleting the license failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "Deleting the project will delete its repository and all related resources including issues, merge requests etc."
msgstr ""
@@ -8651,7 +8934,10 @@ msgstr ""
msgid "DesignManagement|The maximum number of designs allowed to be uploaded is %{upload_limit}. Please try again."
msgstr ""
-msgid "DesignManagement|To upload designs, you'll need to enable LFS. %{requirements_link_start}More information%{requirements_link_end}"
+msgid "DesignManagement|There was an error moving your designs. Please upload your designs below."
+msgstr ""
+
+msgid "DesignManagement|To upload designs, you'll need to enable LFS and have admin enable hashed storage. %{requirements_link_start}More information%{requirements_link_end}"
msgstr ""
msgid "DesignManagement|Unresolve thread"
@@ -8663,6 +8949,9 @@ msgstr ""
msgid "DesignManagement|Upload skipped."
msgstr ""
+msgid "DesignManagement|Your designs are being copied and are on their way… Please refresh to update."
+msgstr ""
+
msgid "DesignManagement|and %{moreCount} more."
msgstr ""
@@ -8720,6 +9009,9 @@ msgstr ""
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
+msgid "Direct member"
+msgstr ""
+
msgid "Direction"
msgstr ""
@@ -8768,9 +9060,6 @@ msgstr ""
msgid "Discard draft"
msgstr ""
-msgid "Discard review"
-msgstr ""
-
msgid "DiscordService|Discord Notifications"
msgstr ""
@@ -8839,10 +9128,10 @@ msgstr ""
msgid "Dismiss Merge Request promotion"
msgstr ""
-msgid "Dismiss Selected"
+msgid "Dismiss Value Stream Analytics introduction box"
msgstr ""
-msgid "Dismiss Value Stream Analytics introduction box"
+msgid "Dismiss selected"
msgstr ""
msgid "Dismiss trial promotion"
@@ -8893,9 +9182,6 @@ msgstr ""
msgid "Documents reindexed: %{processed_documents} (%{percentage}%%)"
msgstr ""
-msgid "Doing"
-msgstr ""
-
msgid "Domain"
msgstr ""
@@ -9091,9 +9377,6 @@ msgstr ""
msgid "Edit environment"
msgstr ""
-msgid "Edit file"
-msgstr ""
-
msgid "Edit files in the editor and commit changes here"
msgstr ""
@@ -9106,6 +9389,12 @@ msgstr ""
msgid "Edit identity for %{user_name}"
msgstr ""
+msgid "Edit in Web IDE"
+msgstr ""
+
+msgid "Edit in single-file editor"
+msgstr ""
+
msgid "Edit issues"
msgstr ""
@@ -9133,10 +9422,10 @@ msgstr ""
msgid "Editing"
msgstr ""
-msgid "Elasticsearch"
+msgid "Elasticsearch AWS IAM credentials"
msgstr ""
-msgid "Elasticsearch AWS IAM credentials"
+msgid "Elasticsearch HTTP client timeout value in seconds."
msgstr ""
msgid "Elasticsearch indexing restrictions"
@@ -9145,9 +9434,6 @@ msgstr ""
msgid "Elasticsearch indexing started"
msgstr ""
-msgid "Elasticsearch integration. Elasticsearch AWS IAM."
-msgstr ""
-
msgid "Elasticsearch reindexing is already in progress"
msgstr ""
@@ -9175,9 +9461,6 @@ msgstr ""
msgid "Email Notification"
msgstr ""
-msgid "Email address"
-msgstr ""
-
msgid "Email could not be sent"
msgstr ""
@@ -9241,6 +9524,9 @@ msgstr ""
msgid "Emails sent from Service Desk will have this name"
msgstr ""
+msgid "Emails sent to %{email} will still be supported"
+msgstr ""
+
msgid "Emails separated by comma"
msgstr ""
@@ -9274,9 +9560,18 @@ msgstr ""
msgid "Enable"
msgstr ""
+msgid "Enable %{link_start}Gitpod%{link_end} integration to launch a development environment in your browser directly from GitLab."
+msgstr ""
+
msgid "Enable Auto DevOps"
msgstr ""
+msgid "Enable Gitpod"
+msgstr ""
+
+msgid "Enable Gitpod?"
+msgstr ""
+
msgid "Enable HTML emails"
msgstr ""
@@ -9406,9 +9701,6 @@ msgstr ""
msgid "Encountered an error while rendering: %{err}"
msgstr ""
-msgid "End date"
-msgstr ""
-
msgid "Ends at (UTC)"
msgstr ""
@@ -9568,7 +9860,7 @@ msgstr ""
msgid "EnvironmentsDashboard|The environments dashboard provides a summary of each project's environments' status, including pipeline and alert statuses."
msgstr ""
-msgid "EnvironmentsDashboard|This dashboard displays a maximum of 7 projects and 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
+msgid "EnvironmentsDashboard|This dashboard displays 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
msgstr ""
msgid "Environments|An error occurred while canceling the auto stop, please try again"
@@ -9889,6 +10181,9 @@ msgstr ""
msgid "Error deleting project. Check logs for error details."
msgstr ""
+msgid "Error fetching burnup chart data"
+msgstr ""
+
msgid "Error fetching diverging counts for branches. Please try again."
msgstr ""
@@ -9967,6 +10262,9 @@ msgstr ""
msgid "Error occurred when saving assignees"
msgstr ""
+msgid "Error occurred when saving reviewers"
+msgstr ""
+
msgid "Error occurred when toggling the notification subscription"
msgstr ""
@@ -10219,10 +10517,13 @@ msgstr ""
msgid "Expand all"
msgstr ""
-msgid "Expand approvers"
+msgid "Expand all files"
msgstr ""
-msgid "Expand dropdown"
+msgid "Expand all threads"
+msgstr ""
+
+msgid "Expand approvers"
msgstr ""
msgid "Expand milestones"
@@ -10393,6 +10694,9 @@ msgstr ""
msgid "Failed to create Merge Request. Please try again."
msgstr ""
+msgid "Failed to create To-Do for the design."
+msgstr ""
+
msgid "Failed to create a branch for this issue. Please try again."
msgstr ""
@@ -10432,6 +10736,12 @@ msgstr ""
msgid "Failed to load authors. Please try again."
msgstr ""
+msgid "Failed to load branches. Please try again."
+msgstr ""
+
+msgid "Failed to load deploy keys."
+msgstr ""
+
msgid "Failed to load emoji list."
msgstr ""
@@ -10447,6 +10757,9 @@ msgstr ""
msgid "Failed to load groups & users."
msgstr ""
+msgid "Failed to load groups, users and deploy keys."
+msgstr ""
+
msgid "Failed to load labels. Please try again."
msgstr ""
@@ -10456,6 +10769,12 @@ msgstr ""
msgid "Failed to load related branches"
msgstr ""
+msgid "Failed to load sidebar confidential toggle"
+msgstr ""
+
+msgid "Failed to load sidebar lock status"
+msgstr ""
+
msgid "Failed to load stacktrace."
msgstr ""
@@ -10483,6 +10802,9 @@ msgstr ""
msgid "Failed to publish issue on status page."
msgstr ""
+msgid "Failed to remove To-Do for the design."
+msgstr ""
+
msgid "Failed to remove a Zoom meeting"
msgstr ""
@@ -10525,6 +10847,9 @@ msgstr ""
msgid "Failed to signing using smartcard authentication"
msgstr ""
+msgid "Failed to toggle To-Do for the design."
+msgstr ""
+
msgid "Failed to update branch!"
msgstr ""
@@ -10638,7 +10963,7 @@ msgstr ""
msgid "FeatureFlags|Edit User List"
msgstr ""
-msgid "FeatureFlags|Enable features for specific users and specific environments by defining feature flag strategies."
+msgid "FeatureFlags|Enable features for specific users and environments by configuring feature flag strategies."
msgstr ""
msgid "FeatureFlags|Environment Spec"
@@ -10698,7 +11023,7 @@ msgstr ""
msgid "FeatureFlags|Include additional user IDs"
msgstr ""
-msgid "FeatureFlags|Install a %{docs_link_anchored_start}compatible client library%{docs_link_anchored_end} and specify the API URL, application name, and instance ID during the configuration setup. %{docs_link_start}More Information%{docs_link_end}"
+msgid "FeatureFlags|Install a %{docsLinkAnchoredStart}compatible client library%{docsLinkAnchoredEnd} and specify the API URL, application name, and instance ID during the configuration setup. %{docsLinkStart}More Information%{docsLinkEnd}"
msgstr ""
msgid "FeatureFlags|Instance ID"
@@ -10710,6 +11035,9 @@ msgstr ""
msgid "FeatureFlags|Loading feature flags"
msgstr ""
+msgid "FeatureFlags|Loading user lists"
+msgstr ""
+
msgid "FeatureFlags|More information"
msgstr ""
@@ -10728,7 +11056,7 @@ msgstr ""
msgid "FeatureFlags|New feature flag"
msgstr ""
-msgid "FeatureFlags|New list"
+msgid "FeatureFlags|New user list"
msgstr ""
msgid "FeatureFlags|Percent of users"
@@ -10767,6 +11095,9 @@ msgstr ""
msgid "FeatureFlags|There was an error fetching the feature flags."
msgstr ""
+msgid "FeatureFlags|There was an error fetching the user lists."
+msgstr ""
+
msgid "FeatureFlags|There was an error retrieving user lists"
msgstr ""
@@ -10782,6 +11113,9 @@ msgstr ""
msgid "FeatureFlags|User List"
msgstr ""
+msgid "FeatureFlags|User Lists"
+msgstr ""
+
msgid "FeatureFlag|List"
msgstr ""
@@ -10809,15 +11143,6 @@ msgstr ""
msgid "Fetching incoming email"
msgstr ""
-msgid "Fetching licenses failed."
-msgstr ""
-
-msgid "Fetching licenses failed. The request endpoint was not found."
-msgstr ""
-
-msgid "Fetching licenses failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "File"
msgstr ""
@@ -10920,12 +11245,21 @@ msgstr ""
msgid "Filter by status"
msgstr ""
+msgid "Filter by test cases that are currently archived."
+msgstr ""
+
+msgid "Filter by test cases that are currently opened."
+msgstr ""
+
msgid "Filter by two-factor authentication"
msgstr ""
msgid "Filter by user"
msgstr ""
+msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
+msgstr ""
+
msgid "Filter pipelines"
msgstr ""
@@ -10941,7 +11275,7 @@ msgstr ""
msgid "Filter results..."
msgstr ""
-msgid "Filter your projects by name"
+msgid "Filter your repositories by name"
msgstr ""
msgid "Filter..."
@@ -10950,7 +11284,7 @@ msgstr ""
msgid "Find File"
msgstr ""
-msgid "Find bugs in your code with coverage-guided fuzzing"
+msgid "Find bugs in your code with coverage-guided fuzzing."
msgstr ""
msgid "Find by path"
@@ -10977,9 +11311,6 @@ msgstr ""
msgid "Finish editing this message first!"
msgstr ""
-msgid "Finish review"
-msgstr ""
-
msgid "Finish setting up your dedicated account for %{group_name}."
msgstr ""
@@ -11049,6 +11380,9 @@ msgstr ""
msgid "Footer message"
msgstr ""
+msgid "For a faster browsing experience, some files are collapsed by default."
+msgstr ""
+
msgid "For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
@@ -11058,6 +11392,9 @@ msgstr ""
msgid "For more info, read the documentation."
msgstr ""
+msgid "For more information on how the number of active users is calculated, see the %{self_managed_subscriptions_doc_link} documentation."
+msgstr ""
+
msgid "For more information, go to the "
msgstr ""
@@ -11196,6 +11533,9 @@ msgstr ""
msgid "Generate new token"
msgstr ""
+msgid "Generic package file size in bytes"
+msgstr ""
+
msgid "Geo"
msgstr ""
@@ -11457,6 +11797,9 @@ msgstr ""
msgid "Geo|Please refer to Geo Troubleshooting."
msgstr ""
+msgid "Geo|Primary node"
+msgstr ""
+
msgid "Geo|Project"
msgstr ""
@@ -11499,6 +11842,9 @@ msgstr ""
msgid "Geo|Review replication status, and resynchronize and reverify items with the primary node."
msgstr ""
+msgid "Geo|Secondary node"
+msgstr ""
+
msgid "Geo|Status"
msgstr ""
@@ -11538,6 +11884,9 @@ msgstr ""
msgid "Geo|URL must be a valid url (ex: https://gitlab.com)"
msgstr ""
+msgid "Geo|Undefined"
+msgstr ""
+
msgid "Geo|Unknown state"
msgstr ""
@@ -11613,10 +11962,16 @@ msgstr ""
msgid "GitHub import"
msgstr ""
+msgid "GitLab"
+msgstr ""
+
msgid "GitLab / Unsubscribe"
msgstr ""
-msgid "GitLab Enterprise Edition %{plan}"
+msgid "GitLab API"
+msgstr ""
+
+msgid "GitLab Billing Team."
msgstr ""
msgid "GitLab Group Runners can execute code for all the projects in this group."
@@ -11628,12 +11983,18 @@ msgstr ""
msgid "GitLab Issue"
msgstr ""
+msgid "GitLab Pages"
+msgstr ""
+
msgid "GitLab Service Desk is a simple way to allow people to create issues in your GitLab instance without needing their own user account. It provides a unique email address for end users to create issues in a project, and replies can be sent either through the GitLab interface or by email. End users will only see the thread through email."
msgstr ""
msgid "GitLab Shared Runners execute code of different projects on the same Runner unless you configure GitLab Runner Autoscale with MaxBuilds 1 (which it is on GitLab.com)."
msgstr ""
+msgid "GitLab Shell"
+msgstr ""
+
msgid "GitLab Support Bot"
msgstr ""
@@ -11643,7 +12004,7 @@ msgstr ""
msgid "GitLab User"
msgstr ""
-msgid "GitLab allows you to continue using your license even if you exceed the number of seats you purchased. You will be required to pay for these seats when you renew your license."
+msgid "GitLab Workhorse"
msgstr ""
msgid "GitLab commit"
@@ -11811,6 +12172,21 @@ msgstr ""
msgid "Gitlab Pages"
msgstr ""
+msgid "Gitpod"
+msgstr ""
+
+msgid "Gitpod|Add the URL to your Gitpod instance configured to read your GitLab projects."
+msgstr ""
+
+msgid "Gitpod|Enable Gitpod integration"
+msgstr ""
+
+msgid "Gitpod|Gitpod URL"
+msgstr ""
+
+msgid "Gitpod|e.g. https://gitpod.example.com"
+msgstr ""
+
msgid "Given access %{time_ago}"
msgstr ""
@@ -12318,9 +12694,6 @@ msgstr ""
msgid "GroupSAML|Valid SAML Response"
msgstr ""
-msgid "GroupSAML|With group managed accounts enabled, all the users without a group managed account will be excluded from the group."
-msgstr ""
-
msgid "GroupSAML|With prohibit outer forks flag enabled group members will be able to fork project only inside your group."
msgstr ""
@@ -12534,10 +12907,10 @@ msgstr ""
msgid "GroupsNew|Create group"
msgstr ""
-msgid "GroupsNew|GitLab group export"
+msgid "GroupsNew|Import"
msgstr ""
-msgid "GroupsNew|Import"
+msgid "GroupsNew|Import a GitLab group export file"
msgstr ""
msgid "GroupsNew|Import group"
@@ -12680,6 +13053,9 @@ msgid_plural "Hide charts"
msgstr[0] ""
msgstr[1] ""
+msgid "Hide comments on this file"
+msgstr ""
+
msgid "Hide details"
msgstr ""
@@ -12724,6 +13100,15 @@ msgstr ""
msgid "Highest role:"
msgstr ""
+msgid "HighlightBar|Alert events:"
+msgstr ""
+
+msgid "HighlightBar|Alert start time:"
+msgstr ""
+
+msgid "HighlightBar|Original alert:"
+msgstr ""
+
msgid "History"
msgstr ""
@@ -12901,6 +13286,9 @@ msgstr ""
msgid "If enabled, access to projects will be validated on an external service using their classification label."
msgstr ""
+msgid "If the number of active users exceeds the user limit, you will be charged for the number of %{users_over_license_link} at your next license reconciliation."
+msgstr ""
+
msgid "If there is no previous license or if the previous license has expired, some GitLab functionality will be blocked until a new, valid license is uploaded."
msgstr ""
@@ -12940,9 +13328,6 @@ msgstr ""
msgid "If your HTTP repository is not publicly accessible, add your credentials."
msgstr ""
-msgid "Iglu registry URL (optional)"
-msgstr ""
-
msgid "Ignore"
msgstr ""
@@ -12979,6 +13364,16 @@ msgstr ""
msgid "Import"
msgstr ""
+msgid "Import %d compatible repository"
+msgid_plural "Import %d compatible repositories"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Import %d repository"
+msgid_plural "Import %d repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Import CSV"
msgstr ""
@@ -12988,15 +13383,9 @@ msgstr ""
msgid "Import all compatible projects"
msgstr ""
-msgid "Import all compatible repositories"
-msgstr ""
-
msgid "Import all projects"
msgstr ""
-msgid "Import all repositories"
-msgstr ""
-
msgid "Import an exported GitLab project"
msgstr ""
@@ -13084,6 +13473,9 @@ msgstr ""
msgid "ImportProjects|Error importing repository %{project_safe_import_url} into %{project_full_path} - %{message}"
msgstr ""
+msgid "ImportProjects|Import repositories"
+msgstr ""
+
msgid "ImportProjects|Importing the project failed"
msgstr ""
@@ -13096,7 +13488,7 @@ msgstr ""
msgid "ImportProjects|Requesting your %{provider} repositories failed"
msgstr ""
-msgid "ImportProjects|Select the projects you want to import"
+msgid "ImportProjects|Select the repositories you want to import"
msgstr ""
msgid "ImportProjects|The remote data could not be imported."
@@ -13132,9 +13524,6 @@ msgstr ""
msgid "In order to enable Service Desk for your instance, you must first set up incoming email."
msgstr ""
-msgid "In order to gather accurate feature usage data, it can take 1 to 2 weeks to see your index."
-msgstr ""
-
msgid "In order to personalize your experience with GitLab%{br_tag}we would like to know a bit more about you."
msgstr ""
@@ -13165,18 +13554,30 @@ msgstr ""
msgid "IncidentManagement|Create incident"
msgstr ""
+msgid "IncidentManagement|Critical - S1"
+msgstr ""
+
msgid "IncidentManagement|Date created"
msgstr ""
msgid "IncidentManagement|Display your incidents in a dedicated view"
msgstr ""
+msgid "IncidentManagement|High - S2"
+msgstr ""
+
msgid "IncidentManagement|Incident"
msgstr ""
msgid "IncidentManagement|Incidents"
msgstr ""
+msgid "IncidentManagement|Low - S4"
+msgstr ""
+
+msgid "IncidentManagement|Medium - S3"
+msgstr ""
+
msgid "IncidentManagement|No incidents to display."
msgstr ""
@@ -13189,6 +13590,9 @@ msgstr ""
msgid "IncidentManagement|Published to status page"
msgstr ""
+msgid "IncidentManagement|Severity"
+msgstr ""
+
msgid "IncidentManagement|There are no closed incidents"
msgstr ""
@@ -13198,6 +13602,9 @@ msgstr ""
msgid "IncidentManagement|Unassigned"
msgstr ""
+msgid "IncidentManagement|Unknown"
+msgstr ""
+
msgid "IncidentManagement|Unpublished"
msgstr ""
@@ -13219,6 +13626,15 @@ msgstr ""
msgid "Incidents"
msgstr ""
+msgid "Incident|Alert details"
+msgstr ""
+
+msgid "Incident|Summary"
+msgstr ""
+
+msgid "Incident|There was an issue loading alert data. Please try again."
+msgstr ""
+
msgid "Include a Terms of Service agreement and Privacy Policy that all users must accept."
msgstr ""
@@ -13279,6 +13695,9 @@ msgstr ""
msgid "Information about additional Pages templates and how to install them can be found in our %{pages_getting_started_guide}."
msgstr ""
+msgid "Inherited"
+msgstr ""
+
msgid "Inherited:"
msgstr ""
@@ -13359,7 +13778,22 @@ msgstr ""
msgid "Instance administrators group already exists"
msgstr ""
-msgid "Instance license"
+msgid "InstanceStatistics|Groups"
+msgstr ""
+
+msgid "InstanceStatistics|Issues"
+msgstr ""
+
+msgid "InstanceStatistics|Merge Requests"
+msgstr ""
+
+msgid "InstanceStatistics|Pipelines"
+msgstr ""
+
+msgid "InstanceStatistics|Projects"
+msgstr ""
+
+msgid "InstanceStatistics|Users"
msgstr ""
msgid "Integration"
@@ -13371,6 +13805,12 @@ msgstr ""
msgid "Integrations"
msgstr ""
+msgid "Integrations|%{integration} settings saved and active."
+msgstr ""
+
+msgid "Integrations|%{integration} settings saved, but not active."
+msgstr ""
+
msgid "Integrations|All details"
msgstr ""
@@ -13380,6 +13820,12 @@ msgstr ""
msgid "Integrations|Comment settings:"
msgstr ""
+msgid "Integrations|Connection failed. Please check your settings."
+msgstr ""
+
+msgid "Integrations|Connection successful."
+msgstr ""
+
msgid "Integrations|Default settings are inherited from the group level."
msgstr ""
@@ -13395,6 +13841,15 @@ msgstr ""
msgid "Integrations|Includes commit title and branch"
msgstr ""
+msgid "Integrations|Projects using custom settings will not be impacted unless the project owner chooses to use instance-level defaults."
+msgstr ""
+
+msgid "Integrations|Save settings?"
+msgstr ""
+
+msgid "Integrations|Saving will update the default settings for all projects that are not using custom settings."
+msgstr ""
+
msgid "Integrations|Standard"
msgstr ""
@@ -13527,6 +13982,9 @@ msgstr ""
msgid "Invitation"
msgstr ""
+msgid "Invitation declined"
+msgstr ""
+
msgid "Invite"
msgstr ""
@@ -13578,6 +14036,42 @@ 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|%{linkStart}Read more%{linkEnd} about role permissions"
+msgstr ""
+
+msgid "InviteMembersModal|Access expiration date (optional)"
+msgstr ""
+
+msgid "InviteMembersModal|Cancel"
+msgstr ""
+
+msgid "InviteMembersModal|Choose a role permission"
+msgstr ""
+
+msgid "InviteMembersModal|GitLab member or Email address"
+msgstr ""
+
+msgid "InviteMembersModal|Invite"
+msgstr ""
+
+msgid "InviteMembersModal|Invite team members"
+msgstr ""
+
+msgid "InviteMembersModal|Search for members to invite"
+msgstr ""
+
+msgid "InviteMembersModal|User not invited. Feature coming soon!"
+msgstr ""
+
+msgid "InviteMembersModal|Users were succesfully added"
+msgstr ""
+
+msgid "InviteMembersModal|You're inviting members to the %{group_name} group"
+msgstr ""
+
+msgid "InviteMembers|Invite team members"
+msgstr ""
+
msgid "Invited"
msgstr ""
@@ -13632,10 +14126,13 @@ msgstr ""
msgid "Issue cannot be found."
msgstr ""
+msgid "Issue created from vulnerability %{vulnerability_link}"
+msgstr ""
+
msgid "Issue events"
msgstr ""
-msgid "Issue first depoloyed to production"
+msgid "Issue first deployed to production"
msgstr ""
msgid "Issue label"
@@ -13713,6 +14210,9 @@ msgstr ""
msgid "IssueTracker|Custom issue tracker"
msgstr ""
+msgid "IssueTracker|EWM work items tracker"
+msgstr ""
+
msgid "IssueTracker|Redmine issue tracker"
msgstr ""
@@ -13779,6 +14279,9 @@ msgstr ""
msgid "It looks like you have some draft commits in this branch."
msgstr ""
+msgid "It may be several days before you see feature usage data."
+msgstr ""
+
msgid "It must have a header row and at least two columns: the first column is the issue title and the second column is the issue description. The separator is automatically detected."
msgstr ""
@@ -14061,13 +14564,13 @@ msgstr ""
msgid "Join Zoom meeting"
msgstr ""
-msgid "Jul"
+msgid "Joined %{time_ago}"
msgstr ""
-msgid "July"
+msgid "Jul"
msgstr ""
-msgid "Jump to first unresolved thread"
+msgid "July"
msgstr ""
msgid "Jump to next unresolved thread"
@@ -14103,6 +14606,9 @@ msgstr ""
msgid "Keyboard shortcuts"
msgstr ""
+msgid "KeyboardKey|Ctrl+"
+msgstr ""
+
msgid "Keys"
msgstr ""
@@ -14151,6 +14657,9 @@ msgstr ""
msgid "LDAP Synchronization"
msgstr ""
+msgid "LDAP group settings"
+msgstr ""
+
msgid "LDAP settings"
msgstr ""
@@ -14160,6 +14669,9 @@ msgstr ""
msgid "LDAP sync in progress. This could take a few minutes. Refresh the page to see the changes."
msgstr ""
+msgid "LDAP synchronizations"
+msgstr ""
+
msgid "LFS"
msgstr ""
@@ -14240,7 +14752,16 @@ msgid_plural "Last %d days"
msgstr[0] ""
msgstr[1] ""
-msgid "Last %{days} days"
+msgid "Last 2 weeks"
+msgstr ""
+
+msgid "Last 30 days"
+msgstr ""
+
+msgid "Last 60 days"
+msgstr ""
+
+msgid "Last 90 days"
msgstr ""
msgid "Last Accessed On"
@@ -14318,6 +14839,9 @@ msgstr ""
msgid "Last used on:"
msgstr ""
+msgid "Last week"
+msgstr ""
+
msgid "LastCommit|authored"
msgstr ""
@@ -14333,6 +14857,9 @@ msgstr ""
msgid "Latest pipeline for the most recent commit on this branch"
msgstr ""
+msgid "Launch a ready-to-code development environment for your project."
+msgstr ""
+
msgid "Lead"
msgstr ""
@@ -14713,6 +15240,9 @@ msgstr ""
msgid "List of all merge commits"
msgstr ""
+msgid "List options"
+msgstr ""
+
msgid "List settings"
msgstr ""
@@ -14725,9 +15255,6 @@ msgstr ""
msgid "List your Bitbucket Server repositories"
msgstr ""
-msgid "Lists"
-msgstr ""
-
msgid "Live preview"
msgstr ""
@@ -14974,6 +15501,12 @@ msgstr ""
msgid "Mark as done"
msgstr ""
+msgid "Mark as draft"
+msgstr ""
+
+msgid "Mark as ready"
+msgstr ""
+
msgid "Mark as resolved"
msgstr ""
@@ -14995,6 +15528,24 @@ msgstr ""
msgid "Markdown is supported"
msgstr ""
+msgid "MarkdownEditor|Add a link (%{modifierKey}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add a link (%{modifier_key}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifierKey}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifier_key}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifierKey}I)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifier_key}I)"
+msgstr ""
+
msgid "Marked For Deletion At - %{deletion_time}"
msgstr ""
@@ -15079,7 +15630,25 @@ msgstr ""
msgid "Max access level"
msgstr ""
-msgid "Max seats used"
+msgid "Max role"
+msgstr ""
+
+msgid "Max size 15 MB"
+msgstr ""
+
+msgid "Maximum Conan package file size in bytes"
+msgstr ""
+
+msgid "Maximum Maven package file size in bytes"
+msgstr ""
+
+msgid "Maximum NPM package file size in bytes"
+msgstr ""
+
+msgid "Maximum NuGet package file size in bytes"
+msgstr ""
+
+msgid "Maximum PyPI package file size in bytes"
msgstr ""
msgid "Maximum Users:"
@@ -15211,6 +15780,18 @@ msgstr ""
msgid "Members with access to %{strong_start}%{group_name}%{strong_end}"
msgstr ""
+msgid "Members|%{time} by %{user}"
+msgstr ""
+
+msgid "Members|Expired"
+msgstr ""
+
+msgid "Members|No expiration set"
+msgstr ""
+
+msgid "Members|in %{time}"
+msgstr ""
+
msgid "Memory Usage"
msgstr ""
@@ -15397,9 +15978,6 @@ msgstr ""
msgid "MergeRequests|Thread will be unresolved"
msgstr ""
-msgid "MergeRequests|Toggle comments for this file"
-msgstr ""
-
msgid "MergeRequests|View file @ %{commitId}"
msgstr ""
@@ -15460,6 +16038,9 @@ msgstr ""
msgid "Merging immediately isn't recommended as it may negatively impact the existing merge train. Read the %{docsLinkStart}documentation%{docsLinkEnd} for more information."
msgstr ""
+msgid "Message"
+msgstr ""
+
msgid "Messages"
msgstr ""
@@ -15845,18 +16426,12 @@ msgid_plural "Milestones"
msgstr[0] ""
msgstr[1] ""
-msgid "Milestone does not support burnup charts"
-msgstr ""
-
msgid "Milestone lists not available with your current license"
msgstr ""
msgid "Milestone lists show all issues from the selected milestone."
msgstr ""
-msgid "Milestone must have a start and due date"
-msgstr ""
-
msgid "MilestoneSidebar|Closed:"
msgstr ""
@@ -16223,6 +16798,9 @@ msgstr ""
msgid "Namespace"
msgstr ""
+msgid "Namespace ID:"
+msgstr ""
+
msgid "Namespace is empty"
msgstr ""
@@ -16307,6 +16885,9 @@ msgstr ""
msgid "NetworkPolicies|Allow all outbound traffic from %{selector} to %{ruleSelector} on %{ports}"
msgstr ""
+msgid "NetworkPolicies|Are you sure you want to delete this policy? This action cannot be undone."
+msgstr ""
+
msgid "NetworkPolicies|Choose whether to enforce this policy."
msgstr ""
@@ -16316,12 +16897,21 @@ msgstr ""
msgid "NetworkPolicies|Define this policy's location, conditions and actions."
msgstr ""
+msgid "NetworkPolicies|Delete policy"
+msgstr ""
+
+msgid "NetworkPolicies|Delete policy: %{policy}"
+msgstr ""
+
msgid "NetworkPolicies|Deny all traffic"
msgstr ""
msgid "NetworkPolicies|Description"
msgstr ""
+msgid "NetworkPolicies|Edit policy"
+msgstr ""
+
msgid "NetworkPolicies|Editor mode"
msgstr ""
@@ -16349,6 +16939,9 @@ msgstr ""
msgid "NetworkPolicies|Name"
msgstr ""
+msgid "NetworkPolicies|Namespace"
+msgstr ""
+
msgid "NetworkPolicies|Network Policy"
msgstr ""
@@ -16400,6 +16993,9 @@ msgstr ""
msgid "NetworkPolicies|Rules"
msgstr ""
+msgid "NetworkPolicies|Save changes"
+msgstr ""
+
msgid "NetworkPolicies|Something went wrong, failed to update policy"
msgstr ""
@@ -16412,6 +17008,9 @@ msgstr ""
msgid "NetworkPolicies|Traffic that does not match any rule will be blocked."
msgstr ""
+msgid "NetworkPolicies|Unable to parse policy"
+msgstr ""
+
msgid "NetworkPolicies|YAML editor"
msgstr ""
@@ -16525,6 +17124,9 @@ msgstr ""
msgid "New Snippet"
msgstr ""
+msgid "New Test Case"
+msgstr ""
+
msgid "New User"
msgstr ""
@@ -16624,6 +17226,9 @@ msgstr ""
msgid "New tag"
msgstr ""
+msgid "New test case"
+msgstr ""
+
msgid "New users set to external"
msgstr ""
@@ -16696,7 +17301,7 @@ msgstr ""
msgid "No changes"
msgstr ""
-msgid "No changes between %{ref_start}%{source_branch}%{ref_end} and %{ref_start}%{target_branch}%{ref_end}"
+msgid "No changes between %{sourceBranch} and %{targetBranch}"
msgstr ""
msgid "No child epics match applied filters"
@@ -16711,6 +17316,9 @@ msgstr ""
msgid "No containers available"
msgstr ""
+msgid "No content to show"
+msgstr ""
+
msgid "No contributions"
msgstr ""
@@ -16786,9 +17394,6 @@ msgstr ""
msgid "No license. All rights reserved"
msgstr ""
-msgid "No licenses found."
-msgstr ""
-
msgid "No matches found"
msgstr ""
@@ -16801,6 +17406,9 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No members found"
+msgstr ""
+
msgid "No merge requests found"
msgstr ""
@@ -16822,6 +17430,9 @@ msgstr ""
msgid "No parent group"
msgstr ""
+msgid "No plan"
+msgstr ""
+
msgid "No pods available"
msgstr ""
@@ -16918,6 +17529,12 @@ msgstr ""
msgid "Not Implemented"
msgstr ""
+msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+msgstr ""
+
+msgid "Not all browsers support WebAuthn. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even from an unsupported browser."
+msgstr ""
+
msgid "Not all data has been processed yet, the accuracy of the chart for the selected timeframe is limited."
msgstr ""
@@ -17014,6 +17631,9 @@ msgstr ""
msgid "Notification settings saved"
msgstr ""
+msgid "NotificationEvent|Change reviewer merge request"
+msgstr ""
+
msgid "NotificationEvent|Close issue"
msgstr ""
@@ -17176,10 +17796,7 @@ msgstr ""
msgid "On track"
msgstr ""
-msgid "OnDemandScans|Attached branch"
-msgstr ""
-
-msgid "OnDemandScans|Attached branch is where the scan job runs."
+msgid "OnDemandScans|Could not fetch scanner profiles. Please refresh the page, or try again later."
msgstr ""
msgid "OnDemandScans|Could not fetch site profiles. Please refresh the page, or try again later."
@@ -17188,6 +17805,9 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
+msgid "OnDemandScans|Create a new scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Create a new site profile"
msgstr ""
@@ -17200,6 +17820,9 @@ msgstr ""
msgid "OnDemandScans|New on-demand DAST scan"
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 ""
@@ -17209,16 +17832,10 @@ msgstr ""
msgid "OnDemandScans|On-demand scans run outside the DevOps cycle and find vulnerabilities in your projects. %{learnMoreLinkStart}Learn more%{learnMoreLinkEnd}"
msgstr ""
-msgid "OnDemandScans|Only a passive scan can be performed on demand."
-msgstr ""
-
-msgid "OnDemandScans|Passive"
-msgstr ""
-
msgid "OnDemandScans|Run scan"
msgstr ""
-msgid "OnDemandScans|Scan mode"
+msgid "OnDemandScans|Scanner profile"
msgstr ""
msgid "OnDemandScans|Scanner settings"
@@ -17230,9 +17847,15 @@ msgstr ""
msgid "OnDemandScans|Select one of the existing profiles"
msgstr ""
+msgid "OnDemandScans|Site profile"
+msgstr ""
+
msgid "OnDemandScans|Site profiles"
msgstr ""
+msgid "OnDemandScans|Use existing scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Use existing site profile"
msgstr ""
@@ -17331,9 +17954,6 @@ msgstr ""
msgid "Open Selection"
msgstr ""
-msgid "Open Web IDE"
-msgstr ""
-
msgid "Open comment type dropdown"
msgstr ""
@@ -17439,6 +18059,9 @@ msgstr ""
msgid "Origin"
msgstr ""
+msgid "Orphaned member"
+msgstr ""
+
msgid "Other Labels"
msgstr ""
@@ -17454,6 +18077,9 @@ msgstr ""
msgid "Other visibility settings have been disabled by the administrator."
msgstr ""
+msgid "Our documentation includes an example DevOps Score report."
+msgstr ""
+
msgid "Out-of-compliance with this project's policies and should be removed"
msgstr ""
@@ -17478,6 +18104,9 @@ msgstr ""
msgid "Overwrite diverged branches"
msgstr ""
+msgid "Owned by %{image_tag}"
+msgstr ""
+
msgid "Owned by anyone"
msgstr ""
@@ -17499,6 +18128,9 @@ msgstr ""
msgid "Package deleted successfully"
msgstr ""
+msgid "Package file size limits"
+msgstr ""
+
msgid "Package recipe already exists"
msgstr ""
@@ -17514,9 +18146,6 @@ msgstr ""
msgid "Package type must be PyPi"
msgstr ""
-msgid "Package was removed"
-msgstr ""
-
msgid "PackageRegistry|%{name} version %{version} was created %{datetime}"
msgstr ""
@@ -17658,12 +18287,18 @@ msgstr ""
msgid "PackageRegistry|NuGet Command"
msgstr ""
+msgid "PackageRegistry|Package Registry"
+msgstr ""
+
msgid "PackageRegistry|Pip Command"
msgstr ""
msgid "PackageRegistry|Pipeline %{link} triggered %{datetime} by %{author}"
msgstr ""
+msgid "PackageRegistry|Publish and share packages for a variety of common package managers. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "PackageRegistry|Published to the %{project} Package Registry %{datetime}"
msgstr ""
@@ -17763,6 +18398,9 @@ msgstr ""
msgid "Page not found"
msgstr ""
+msgid "Page settings"
+msgstr ""
+
msgid "Page was successfully deleted"
msgstr ""
@@ -17904,7 +18542,7 @@ msgstr ""
msgid "Paste issue link"
msgstr ""
-msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Don't use your private SSH key."
+msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Do not paste your private SSH key, as that can compromise your identity."
msgstr ""
msgid "Patch to apply"
@@ -17931,6 +18569,9 @@ msgstr ""
msgid "Pending"
msgstr ""
+msgid "Pending comments"
+msgstr ""
+
msgid "People without permission will never get a notification and won't be able to comment."
msgstr ""
@@ -18129,6 +18770,9 @@ msgstr ""
msgid "Pipelines|Build with confidence"
msgstr ""
+msgid "Pipelines|By revoking a trigger you will break any processes making use of it. Are you sure?"
+msgstr ""
+
msgid "Pipelines|CI Lint"
msgstr ""
@@ -18141,6 +18785,15 @@ msgstr ""
msgid "Pipelines|Continuous Integration can help catch bugs by running your tests automatically, while Continuous Deployment can help you deliver code to your product environment."
msgstr ""
+msgid "Pipelines|Copy trigger token"
+msgstr ""
+
+msgid "Pipelines|Description"
+msgstr ""
+
+msgid "Pipelines|Edit"
+msgstr ""
+
msgid "Pipelines|Get started with Pipelines"
msgstr ""
@@ -18156,15 +18809,27 @@ msgstr ""
msgid "Pipelines|It is recommended the code is reviewed thoroughly before running this pipeline with the parent project's CI resource."
msgstr ""
+msgid "Pipelines|Last Used"
+msgstr ""
+
msgid "Pipelines|Loading Pipelines"
msgstr ""
msgid "Pipelines|More Information"
msgstr ""
+msgid "Pipelines|No triggers have been created yet. Add one using the form above."
+msgstr ""
+
+msgid "Pipelines|Owner"
+msgstr ""
+
msgid "Pipelines|Project cache successfully reset."
msgstr ""
+msgid "Pipelines|Revoke"
+msgstr ""
+
msgid "Pipelines|Run Pipeline"
msgstr ""
@@ -18189,6 +18854,15 @@ msgstr ""
msgid "Pipelines|This project is not currently set up to run pipelines."
msgstr ""
+msgid "Pipelines|Token"
+msgstr ""
+
+msgid "Pipelines|Trigger user has insufficient permissions to project"
+msgstr ""
+
+msgid "Pipelines|invalid"
+msgstr ""
+
msgid "Pipelines|parent"
msgstr ""
@@ -18447,10 +19121,10 @@ msgstr ""
msgid "Please provide attributes to update"
msgstr ""
-msgid "Please refer to %{docs_url}"
+msgid "Please reach out if you have any questions and we'll be happy to assist."
msgstr ""
-msgid "Please retype the email address."
+msgid "Please refer to %{docs_url}"
msgstr ""
msgid "Please select"
@@ -18480,6 +19154,9 @@ msgstr ""
msgid "Please set a new password before proceeding."
msgstr ""
+msgid "Please share your feedback about %{featureName} %{linkStart}in this issue%{linkEnd} to help us improve the experience."
+msgstr ""
+
msgid "Please solve the reCAPTCHA"
msgstr ""
@@ -18783,6 +19460,9 @@ msgstr ""
msgid "Profiles| You are going to change the username %{currentUsernameBold} to %{newUsernameBold}. Profile and projects will be redirected to the %{newUsername} namespace but this redirect will expire once the %{currentUsername} namespace is registered by another user or group. Please update your Git repository remotes as soon as possible."
msgstr ""
+msgid "Profiles|%{provider} Active"
+msgstr ""
+
msgid "Profiles|@username"
msgstr ""
@@ -18834,7 +19514,7 @@ msgstr ""
msgid "Profiles|Commit email"
msgstr ""
-msgid "Profiles|Connect"
+msgid "Profiles|Connect %{provider}"
msgstr ""
msgid "Profiles|Connected Accounts"
@@ -18858,6 +19538,9 @@ msgstr ""
msgid "Profiles|Disconnect"
msgstr ""
+msgid "Profiles|Disconnect %{provider}"
+msgstr ""
+
msgid "Profiles|Do not show on profile"
msgstr ""
@@ -18882,7 +19565,7 @@ msgstr ""
msgid "Profiles|Full name"
msgstr ""
-msgid "Profiles|Give your individual key a title. This will be publically visible."
+msgid "Profiles|Give your individual key a title."
msgstr ""
msgid "Profiles|Include private contributions on my profile"
@@ -18972,7 +19655,7 @@ msgstr ""
msgid "Profiles|The maximum file size allowed is 200KB."
msgstr ""
-msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it?"
+msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it? It will be publicly visible."
msgstr ""
msgid "Profiles|This email will be displayed on your public profile"
@@ -19047,6 +19730,9 @@ msgstr ""
msgid "Profiles|You don't have access to delete this user."
msgstr ""
+msgid "Profiles|You must transfer ownership or delete groups you are an owner of before you can delete your account"
+msgstr ""
+
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
@@ -19635,6 +20321,9 @@ msgstr ""
msgid "ProjectTemplates|GitLab Cluster Management"
msgstr ""
+msgid "ProjectTemplates|Gitpod/Spring Petclinic"
+msgstr ""
+
msgid "ProjectTemplates|Go Micro"
msgstr ""
@@ -20244,6 +20933,9 @@ msgstr ""
msgid "Publish to status page"
msgstr ""
+msgid "Published"
+msgstr ""
+
msgid "Published on status page"
msgstr ""
@@ -20361,9 +21053,15 @@ msgstr ""
msgid "Quick range"
msgstr ""
+msgid "Quickly and easily edit multiple files in your project."
+msgstr ""
+
msgid "README"
msgstr ""
+msgid "Rails"
+msgstr ""
+
msgid "Rake Tasks Help"
msgstr ""
@@ -20483,10 +21181,13 @@ msgstr ""
msgid "Register Two-Factor Authenticator"
msgstr ""
-msgid "Register U2F device"
+msgid "Register Universal Two-Factor (U2F) Device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register WebAuthn Device"
+msgstr ""
+
+msgid "Register device"
msgstr ""
msgid "Register for GitLab"
@@ -20498,9 +21199,6 @@ msgstr ""
msgid "Register with two-factor app"
msgstr ""
-msgid "Registration"
-msgstr ""
-
msgid "Registration|Checkout"
msgstr ""
@@ -20617,9 +21315,6 @@ msgstr ""
msgid "Release|Something went wrong while saving the release details"
msgstr ""
-msgid "Remediated: needs review"
-msgstr ""
-
msgid "Remediations"
msgstr ""
@@ -20725,6 +21420,9 @@ msgstr ""
msgid "Remove priority"
msgstr ""
+msgid "Remove report"
+msgstr ""
+
msgid "Remove secondary node"
msgstr ""
@@ -20737,6 +21435,12 @@ msgstr ""
msgid "Remove time estimate"
msgstr ""
+msgid "Remove user & report"
+msgstr ""
+
+msgid "Remove user from group"
+msgstr ""
+
msgid "Removed"
msgstr ""
@@ -20818,9 +21522,6 @@ msgstr ""
msgid "Removes time estimate."
msgstr ""
-msgid "Removing license…"
-msgstr ""
-
msgid "Removing this group also removes all child projects, including archived projects, and their resources."
msgstr ""
@@ -20905,6 +21606,9 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
+msgid "Reported by %{reporter}"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -20991,6 +21695,27 @@ msgstr ""
msgid "Repositories"
msgstr ""
+msgid "Repositories Analytics"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download Historic Test Coverage Data"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download historic test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Historic Test Coverage Data is available in raw format (.csv) for further analysis."
+msgstr ""
+
+msgid "RepositoriesAnalytics|Test Code Coverage"
+msgstr ""
+
+msgid "RepositoriesAnalytics|There was an error fetching the projects."
+msgstr ""
+
msgid "Repository"
msgstr ""
@@ -21069,9 +21794,15 @@ msgstr ""
msgid "Request parameter %{param} is missing."
msgstr ""
+msgid "Request review from"
+msgstr ""
+
msgid "Request to link SAML account must be authorized"
msgstr ""
+msgid "Requested"
+msgstr ""
+
msgid "Requested %{time_ago}"
msgstr ""
@@ -21090,6 +21821,9 @@ msgstr ""
msgid "Requests to these domain(s)/address(es) on the local network will be allowed when local requests from hooks and services are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 or 127.0.0.0/28 are supported. Domain wildcards are not supported currently. Use comma, semicolon, or newline to separate multiple entries. The allowlist can hold a maximum of 1000 entries. Domains should use IDNA encoding. Ex: example.com, 192.168.1.1, 127.0.0.0/28, xn--itlab-j1a.com."
msgstr ""
+msgid "Require admin approval for new sign-ups"
+msgstr ""
+
msgid "Require all users in this group to setup Two-factor authentication"
msgstr ""
@@ -21217,9 +21951,6 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
-msgid "Resolved by %{resolvedByName}"
-msgstr ""
-
msgid "Resolves IP addresses once and uses them to submit requests"
msgstr ""
@@ -21339,6 +22070,14 @@ msgstr ""
msgid "ReviewApp|Enable Review App"
msgstr ""
+msgid "Reviewer"
+msgid_plural "%d Reviewers"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Reviewer(s)"
+msgstr ""
+
msgid "Reviewing"
msgstr ""
@@ -21378,6 +22117,9 @@ msgstr ""
msgid "Rook"
msgstr ""
+msgid "Ruby"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -21456,6 +22198,63 @@ msgstr ""
msgid "Runners page."
msgstr ""
+msgid "Runners|Active"
+msgstr ""
+
+msgid "Runners|Architecture"
+msgstr ""
+
+msgid "Runners|Can run untagged jobs"
+msgstr ""
+
+msgid "Runners|Description"
+msgstr ""
+
+msgid "Runners|Group"
+msgstr ""
+
+msgid "Runners|IP Address"
+msgstr ""
+
+msgid "Runners|Last contact"
+msgstr ""
+
+msgid "Runners|Locked to this project"
+msgstr ""
+
+msgid "Runners|Maximum job timeout"
+msgstr ""
+
+msgid "Runners|Name"
+msgstr ""
+
+msgid "Runners|Platform"
+msgstr ""
+
+msgid "Runners|Property Name"
+msgstr ""
+
+msgid "Runners|Protected"
+msgstr ""
+
+msgid "Runners|Revision"
+msgstr ""
+
+msgid "Runners|Shared"
+msgstr ""
+
+msgid "Runners|Specific"
+msgstr ""
+
+msgid "Runners|Tags"
+msgstr ""
+
+msgid "Runners|Value"
+msgstr ""
+
+msgid "Runners|Version"
+msgstr ""
+
msgid "Runners|You have used %{quotaUsed} out of %{quotaLimit} of your shared Runners pipeline minutes."
msgstr ""
@@ -21468,6 +22267,9 @@ msgstr ""
msgid "Runs a number of housekeeping tasks within the current repository, such as compressing file revisions and removing unreachable objects."
msgstr ""
+msgid "SAML"
+msgstr ""
+
msgid "SAML SSO"
msgstr ""
@@ -21519,6 +22321,9 @@ msgstr ""
msgid "Save"
msgstr ""
+msgid "Save %{name} size limits"
+msgstr ""
+
msgid "Save Changes"
msgstr ""
@@ -21549,9 +22354,6 @@ msgstr ""
msgid "Save space and find tags in the Container Registry more easily. Enable the cleanup policy to remove stale tags and keep only the ones you need."
msgstr ""
-msgid "Save template"
-msgstr ""
-
msgid "Save variables"
msgstr ""
@@ -21594,9 +22396,6 @@ msgstr ""
msgid "Scope"
msgstr ""
-msgid "Scope not supported with disabled 'users_search' feature!"
-msgstr ""
-
msgid "Scoped issue boards"
msgstr ""
@@ -21723,9 +22522,6 @@ msgstr ""
msgid "Search requirements"
msgstr ""
-msgid "Search results…"
-msgstr ""
-
msgid "Search users"
msgstr ""
@@ -21798,6 +22594,11 @@ msgid_plural "SearchResults|commits"
msgstr[0] ""
msgstr[1] ""
+msgid "SearchResults|epic"
+msgid_plural "SearchResults|epics"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "SearchResults|issue"
msgid_plural "SearchResults|issues"
msgstr[0] ""
@@ -21842,10 +22643,10 @@ msgstr ""
msgid "Seat Link is disabled, and cannot be configured through this form."
msgstr ""
-msgid "Seats currently in use"
+msgid "Seats usage data as of %{last_enqueue_time}"
msgstr ""
-msgid "Seats in license"
+msgid "Seats usage data is updated every day at 12:00pm UTC"
msgstr ""
msgid "Secondary"
@@ -21899,6 +22700,9 @@ msgstr ""
msgid "SecurityConfiguration|Available for on-demand DAST"
msgstr ""
+msgid "SecurityConfiguration|By default, all analyzers are applied in order to cover all languages across your project, and only run if the language is detected in the Merge Request."
+msgstr ""
+
msgid "SecurityConfiguration|Configure"
msgstr ""
@@ -21929,16 +22733,19 @@ msgstr ""
msgid "SecurityConfiguration|Manage"
msgstr ""
+msgid "SecurityConfiguration|More information"
+msgstr ""
+
msgid "SecurityConfiguration|Not enabled"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|Security Control"
+msgid "SecurityConfiguration|SAST Configuration"
msgstr ""
-msgid "SecurityConfiguration|See documentation"
+msgid "SecurityConfiguration|Security Control"
msgstr ""
msgid "SecurityConfiguration|Status"
@@ -21950,6 +22757,9 @@ msgstr ""
msgid "SecurityConfiguration|Using custom settings. You won't receive automatic updates on this variable. %{anchorStart}Restore to default%{anchorEnd}"
msgstr ""
+msgid "SecurityConfiguration|View history"
+msgstr ""
+
msgid "SecurityConfiguration|You can quickly enable all security scanning tools by enabling %{linkStart}Auto DevOps%{linkEnd}."
msgstr ""
@@ -22028,9 +22838,6 @@ msgstr ""
msgid "SecurityReports|Learn more about setting up your dashboard"
msgstr ""
-msgid "SecurityReports|Load more vulnerabilities"
-msgstr ""
-
msgid "SecurityReports|Monitor vulnerabilities in your code"
msgstr ""
@@ -22310,7 +23117,7 @@ msgstr ""
msgid "Select status"
msgstr ""
-msgid "Select strategy activation method"
+msgid "Select strategy activation method."
msgstr ""
msgid "Select subscription"
@@ -22325,7 +23132,7 @@ msgstr ""
msgid "Select the custom project template source group."
msgstr ""
-msgid "Select timeframe"
+msgid "Select the environment scope for this feature flag."
msgstr ""
msgid "Select timezone"
@@ -22574,6 +23381,9 @@ msgstr ""
msgid "Set iteration"
msgstr ""
+msgid "Set limit to 0 to allow any file size."
+msgstr ""
+
msgid "Set max session time for web terminal."
msgstr ""
@@ -22652,10 +23462,13 @@ msgstr ""
msgid "Set up a %{type} Runner manually"
msgstr ""
+msgid "Set up a hardware device as a second factor to sign in."
+msgstr ""
+
msgid "Set up assertions/attributes/claims (email, first_name, last_name) and NameID according to %{docsLinkStart}the documentation %{icon}%{docsLinkEnd}"
msgstr ""
-msgid "Set up new U2F device"
+msgid "Set up new device"
msgstr ""
msgid "Set up new password"
@@ -22724,6 +23537,9 @@ msgstr ""
msgid "Sets weight to %{weight}."
msgstr ""
+msgid "Setting this to 0 means using the system default timeout value."
+msgstr ""
+
msgid "Settings"
msgstr ""
@@ -22739,6 +23555,15 @@ msgstr ""
msgid "Severity"
msgstr ""
+msgid "SeverityWidget|Severity"
+msgstr ""
+
+msgid "SeverityWidget|Severity: %{severity}"
+msgstr ""
+
+msgid "SeverityWidget|There was an error while updating severity."
+msgstr ""
+
msgid "Shards (%{shards})"
msgstr ""
@@ -22784,6 +23609,9 @@ msgstr ""
msgid "Show all requirements."
msgstr ""
+msgid "Show all test cases."
+msgstr ""
+
msgid "Show archived projects"
msgstr ""
@@ -22796,6 +23624,9 @@ msgstr ""
msgid "Show comments"
msgstr ""
+msgid "Show comments on this file"
+msgstr ""
+
msgid "Show comments only"
msgstr ""
@@ -22841,6 +23672,12 @@ msgstr ""
msgid "Show parent subgroups"
msgstr ""
+msgid "Show the Closed list"
+msgstr ""
+
+msgid "Show the Open list"
+msgstr ""
+
msgid "Show whitespace changes"
msgstr ""
@@ -22884,9 +23721,6 @@ msgstr ""
msgid "Sidebar|Assign health status"
msgstr ""
-msgid "Sidebar|Change weight"
-msgstr ""
-
msgid "Sidebar|Health status"
msgstr ""
@@ -23070,6 +23904,9 @@ msgstr ""
msgid "Snippets|Add another file %{num}/%{total}"
msgstr ""
+msgid "Snippets|Authored %{time_ago} by %{author}"
+msgstr ""
+
msgid "Snippets|Delete file"
msgstr ""
@@ -23097,6 +23934,9 @@ msgstr ""
msgid "Solution"
msgstr ""
+msgid "Some changes are not shown"
+msgstr ""
+
msgid "Some child epics may be hidden due to applied filters"
msgstr ""
@@ -23463,6 +24303,12 @@ msgstr ""
msgid "Source (branch or tag)"
msgstr ""
+msgid "Source Branch"
+msgstr ""
+
+msgid "Source branch: %{source_branch_open}%{source_branch}%{source_branch_close}"
+msgstr ""
+
msgid "Source code"
msgstr ""
@@ -23628,9 +24474,6 @@ msgstr ""
msgid "Start and due date"
msgstr ""
-msgid "Start by choosing a group to see how your team is spending time. You can then drill down to the project level."
-msgstr ""
-
msgid "Start by choosing a group to start exploring the merge requests in that group. You can then proceed to filter by projects, labels, milestones and authors."
msgstr ""
@@ -23712,18 +24555,27 @@ msgstr ""
msgid "StaticSiteEditor|3. Assign a person to review and accept the merge request."
msgstr ""
+msgid "StaticSiteEditor|A link to view the merge request will appear once ready."
+msgstr ""
+
msgid "StaticSiteEditor|An error occurred while submitting your changes."
msgstr ""
msgid "StaticSiteEditor|Branch could not be created."
msgstr ""
+msgid "StaticSiteEditor|Copy update"
+msgstr ""
+
msgid "StaticSiteEditor|Could not commit the content changes."
msgstr ""
msgid "StaticSiteEditor|Could not create merge request."
msgstr ""
+msgid "StaticSiteEditor|Creating your merge request"
+msgstr ""
+
msgid "StaticSiteEditor|Incompatible file content"
msgstr ""
@@ -23745,6 +24597,9 @@ msgstr ""
msgid "StaticSiteEditor|View documentation"
msgstr ""
+msgid "StaticSiteEditor|You can set an assignee to get your changes reviewed and deployed once your merge request is created."
+msgstr ""
+
msgid "StaticSiteEditor|Your merge request has been created"
msgstr ""
@@ -23874,15 +24729,15 @@ msgstr ""
msgid "Submit %{humanized_resource_name}"
msgstr ""
-msgid "Submit Changes"
-msgstr ""
-
msgid "Submit a review"
msgstr ""
msgid "Submit as spam"
msgstr ""
+msgid "Submit changes"
+msgstr ""
+
msgid "Submit feedback"
msgstr ""
@@ -24036,6 +24891,9 @@ msgstr ""
msgid "Successfully deleted U2F device."
msgstr ""
+msgid "Successfully deleted WebAuthn device."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -24354,9 +25212,6 @@ msgstr ""
msgid "Template to append to all Service Desk issues"
msgstr ""
-msgid "Template was successfully saved."
-msgstr ""
-
msgid "Templates"
msgstr ""
@@ -24435,10 +25290,28 @@ msgid_plural "Test coverage: %d hits"
msgstr[0] ""
msgstr[1] ""
-msgid "Test failed."
+msgid "Test settings"
msgstr ""
-msgid "Test settings and save changes"
+msgid "TestCases|New Test Case"
+msgstr ""
+
+msgid "TestCases|New test case"
+msgstr ""
+
+msgid "TestCases|Search test cases"
+msgstr ""
+
+msgid "TestCases|Something went wrong while creating a test case."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching count of test cases."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching test cases list."
+msgstr ""
+
+msgid "TestCases|Submit test case"
msgstr ""
msgid "TestHooks|Ensure one of your projects has merge requests."
@@ -24504,6 +25377,9 @@ msgstr ""
msgid "Thank you for signing up for your free trial! You will get additional instructions in your inbox shortly."
msgstr ""
+msgid "Thank you for your business."
+msgstr ""
+
msgid "Thank you for your feedback!"
msgstr ""
@@ -24563,9 +25439,6 @@ msgstr ""
msgid "The URL to use for connecting to Elasticsearch. Use a comma-separated list to support clustering (e.g., \"http://localhost:9200, http://localhost:9201\")."
msgstr ""
-msgid "The Web IDE offers advanced syntax highlighting capabilities and more."
-msgstr ""
-
msgid "The X509 Certificate to use when mutual TLS is required to communicate with the external authorization service. If left blank, the server certificate is still validated when accessing over HTTPS."
msgstr ""
@@ -24676,6 +25549,9 @@ msgstr ""
msgid "The form contains the following error:"
msgstr ""
+msgid "The form contains the following warning:"
+msgstr ""
+
msgid "The global settings require you to enable Two-Factor Authentication for your account."
msgstr ""
@@ -24790,9 +25666,6 @@ msgstr ""
msgid "The private key to use when a client certificate is provided. This value is encrypted at rest."
msgstr ""
-msgid "The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The project can be accessed by any logged in user."
msgstr ""
@@ -24829,7 +25702,7 @@ msgstr ""
msgid "The remote repository is being updated..."
msgstr ""
-msgid "The repository can be commited to, and issues, comments and other entities can be created."
+msgid "The repository can be committed to, and issues, comments and other entities can be created."
msgstr ""
msgid "The repository for this project does not exist."
@@ -24883,9 +25756,6 @@ msgstr ""
msgid "The time taken by each data entry gathered by that stage."
msgstr ""
-msgid "The total stage shows the time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The update action will time out after %{number_of_minutes} minutes. For big repositories, use a clone/push combination."
msgstr ""
@@ -24949,6 +25819,9 @@ msgstr ""
msgid "There are no archived requirements"
msgstr ""
+msgid "There are no archived test cases"
+msgstr ""
+
msgid "There are no changes"
msgstr ""
@@ -24988,6 +25861,9 @@ msgstr ""
msgid "There are no open requirements"
msgstr ""
+msgid "There are no open test cases"
+msgstr ""
+
msgid "There are no packages yet"
msgstr ""
@@ -25000,6 +25876,9 @@ msgstr ""
msgid "There is a limit of %{ci_project_subscriptions_limit} subscriptions from or to a project."
msgstr ""
+msgid "There is already a To-Do for this design."
+msgstr ""
+
msgid "There is already a repository with that name on disk"
msgstr ""
@@ -25018,6 +25897,9 @@ msgstr ""
msgid "There was a problem communicating with your device."
msgstr ""
+msgid "There was a problem fetching branches."
+msgstr ""
+
msgid "There was a problem fetching groups."
msgstr ""
@@ -25246,9 +26128,15 @@ msgstr ""
msgid "This action can lead to data loss. To prevent accidental actions we ask you to confirm your intention."
msgstr ""
+msgid "This action cannot be undone, and will permanently delete the %{key} SSH key"
+msgstr ""
+
msgid "This action cannot be undone. You will lose the project's repository and all content: issues, merge requests, etc."
msgstr ""
+msgid "This action has been performed too many times. Try again later."
+msgstr ""
+
msgid "This action will %{strongOpen}permanently delete%{strongClose} %{codeOpen}%{project}%{codeClose} %{strongOpen}immediately%{strongClose}, including its repositories and all content: issues, merge requests, etc."
msgstr ""
@@ -25276,9 +26164,6 @@ msgstr ""
msgid "This board's scope is reduced"
msgstr ""
-msgid "This branch has changed since you started editing. Would you like to create a new branch?"
-msgstr ""
-
msgid "This chart could not be displayed"
msgstr ""
@@ -25405,15 +26290,9 @@ msgstr ""
msgid "This is a security log of important events involving your account."
msgstr ""
-msgid "This is the author's first Merge Request to this project."
-msgstr ""
-
msgid "This is the highest peak of users on your installation since the license started."
msgstr ""
-msgid "This is the maximum number of users that have existed at the same time since the license started. This is the minimum number of seats you will need to buy when you renew your license."
-msgstr ""
-
msgid "This is the number of currently active users on your installation, and this is the minimum number you need to purchase when you renew your license."
msgstr ""
@@ -25645,6 +26524,15 @@ msgstr ""
msgid "This user has no identities"
msgstr ""
+msgid "This user has previously committed to the %{name} project."
+msgstr ""
+
+msgid "This user has the %{access} role in the %{name} project."
+msgstr ""
+
+msgid "This user is the author of this %{noteable}."
+msgstr ""
+
msgid "This user will be the author of all events in the activity feed that are the result of an update, like new branches being created or new commits being pushed to existing branches."
msgstr ""
@@ -25675,6 +26563,9 @@ msgstr ""
msgid "Threat Monitoring"
msgstr ""
+msgid "ThreatMonitoring|All Environments"
+msgstr ""
+
msgid "ThreatMonitoring|Anomalous Requests"
msgstr ""
@@ -25702,9 +26593,6 @@ msgstr ""
msgid "ThreatMonitoring|Operations Per Second"
msgstr ""
-msgid "ThreatMonitoring|Overview"
-msgstr ""
-
msgid "ThreatMonitoring|Packet Activity"
msgstr ""
@@ -25723,6 +26611,9 @@ msgstr ""
msgid "ThreatMonitoring|Something went wrong, unable to fetch statistics"
msgstr ""
+msgid "ThreatMonitoring|Statistics"
+msgstr ""
+
msgid "ThreatMonitoring|The firewall is not installed or has been disabled. To view this data, ensure the web application firewall is installed and enabled for your cluster."
msgstr ""
@@ -26114,6 +27005,9 @@ msgstr ""
msgid "To update Snippets with multiple files, you must use the `files` parameter"
msgstr ""
+msgid "To use Gitpod you must first enable the feature in the integrations section of your %{user_prefs}."
+msgstr ""
+
msgid "To view all %{scannedResourcesCount} scanned URLs, please download the CSV file"
msgstr ""
@@ -26147,9 +27041,6 @@ msgstr ""
msgid "Toggle Sidebar"
msgstr ""
-msgid "Toggle all threads"
-msgstr ""
-
msgid "Toggle backtrace"
msgstr ""
@@ -26174,9 +27065,6 @@ msgstr ""
msgid "Toggle navigation"
msgstr ""
-msgid "Toggle project"
-msgstr ""
-
msgid "Toggle sidebar"
msgstr ""
@@ -26216,6 +27104,9 @@ msgstr ""
msgid "Too many projects enabled. You will need to manage them via the console or the API."
msgstr ""
+msgid "Too much data"
+msgstr ""
+
msgid "Topics (optional)"
msgstr ""
@@ -26234,6 +27125,9 @@ msgstr ""
msgid "Total cores (CPUs)"
msgstr ""
+msgid "Total days to completion"
+msgstr ""
+
msgid "Total issues"
msgstr ""
@@ -26330,6 +27224,9 @@ msgstr ""
msgid "Trending"
msgstr ""
+msgid "Trials|Create a new group to start your GitLab Gold trial."
+msgstr ""
+
msgid "Trials|Go back to GitLab"
msgstr ""
@@ -26339,6 +27236,15 @@ msgstr ""
msgid "Trials|You can always resume this process by selecting your avatar and choosing 'Start a Gold trial'"
msgstr ""
+msgid "Trials|You can apply your trial to a new group or an existing group."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group or your personal account."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group, an existing group, or your personal account."
+msgstr ""
+
msgid "Trials|You won't get a free trial right now but you can always resume this process by clicking on your avatar and choosing 'Start a free trial'"
msgstr ""
@@ -26408,6 +27314,9 @@ msgstr ""
msgid "Try using a different search term to find the file you are looking for."
msgstr ""
+msgid "Trying to communicate with your device. Plug it in (if needed) and press the button on the device now."
+msgstr ""
+
msgid "Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now."
msgstr ""
@@ -26495,6 +27404,12 @@ msgstr ""
msgid "URL or request ID"
msgstr ""
+msgid "USER %{user} WILL BE REMOVED! Are you sure?"
+msgstr ""
+
+msgid "USER WILL BE BLOCKED! Are you sure?"
+msgstr ""
+
msgid "UTC"
msgstr ""
@@ -26552,9 +27467,6 @@ msgstr ""
msgid "Unable to load the merge request widget. Try reloading the page."
msgstr ""
-msgid "Unable to resolve"
-msgstr ""
-
msgid "Unable to save iteration. Please try again"
msgstr ""
@@ -26603,6 +27515,9 @@ msgstr ""
msgid "Undo ignore"
msgstr ""
+msgid "Unexpected error"
+msgstr ""
+
msgid "Unfortunately, your email message to GitLab could not be processed."
msgstr ""
@@ -26636,6 +27551,9 @@ msgstr ""
msgid "Unknown response text"
msgstr ""
+msgid "Unless otherwise agreed to in writing with GitLab, by clicking \"Upload License\" you agree that your use of GitLab Software is subject to the %{eula_link_start}Terms of Service%{eula_link_end}."
+msgstr ""
+
msgid "Unlimited"
msgstr ""
@@ -27002,9 +27920,6 @@ msgstr ""
msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
msgstr ""
-msgid "Use a hardware device to add the second factor of authentication."
-msgstr ""
-
msgid "Use an one time password authenticator on your mobile device or computer to enable two-factor authentication (2FA)."
msgstr ""
@@ -27278,13 +28193,13 @@ msgstr ""
msgid "Users"
msgstr ""
-msgid "Users in License:"
+msgid "Users in License"
msgstr ""
-msgid "Users or groups set as approvers in the project's or merge request's settings."
+msgid "Users in License:"
msgstr ""
-msgid "Users outside of license"
+msgid "Users or groups set as approvers in the project's or merge request's settings."
msgstr ""
msgid "Users over License:"
@@ -27302,9 +28217,6 @@ msgstr ""
msgid "Users with a Guest role or those who don't belong to a Project or Group will not use a seat from your license."
msgstr ""
-msgid "Users with a Guest role or those who don't belong to any projects or groups don't count towards seats in use."
-msgstr ""
-
msgid "UsersSelect|%{name} + %{length} more"
msgstr ""
@@ -27344,9 +28256,6 @@ msgstr ""
msgid "Validations failed."
msgstr ""
-msgid "Validity"
-msgstr ""
-
msgid "Value"
msgstr ""
@@ -27365,6 +28274,9 @@ msgstr ""
msgid "Value Stream Name"
msgstr ""
+msgid "ValueStreamAnalyticsStage|We don't have enough data to show this stage."
+msgstr ""
+
msgid "ValueStreamAnalytics|%{days}d"
msgstr ""
@@ -27621,6 +28533,9 @@ msgstr ""
msgid "VisualReviewApp|Steps 1 and 2 (and sometimes 3) are performed once by the developer before requesting feedback. Steps 3 (if necessary), 4 is performed by the reviewer each time they perform a review."
msgstr ""
+msgid "Visualization"
+msgstr ""
+
msgid "Vulnerabilities"
msgstr ""
@@ -27648,34 +28563,31 @@ msgstr ""
msgid "VulnerabilityChart|Severity"
msgstr ""
-msgid "VulnerabilityManagement|A true-positive and will fix"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Change status"
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|Confirm"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Confirmed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
-msgstr ""
-
-msgid "VulnerabilityManagement|Detected %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|A true-positive and will fix"
msgstr ""
-msgid "VulnerabilityManagement|Dismiss"
+msgid "VulnerabilityManagement|Change status"
msgstr ""
-msgid "VulnerabilityManagement|Dismissed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
msgstr ""
-msgid "VulnerabilityManagement|Resolved"
+msgid "VulnerabilityManagement|Detected"
msgstr ""
-msgid "VulnerabilityManagement|Resolved %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Needs triage"
msgstr ""
msgid "VulnerabilityManagement|Something went wrong while trying to delete the comment. Please try again later."
@@ -27726,6 +28638,9 @@ msgstr ""
msgid "Vulnerability|%{scannerName} (version %{scannerVersion})"
msgstr ""
+msgid "Vulnerability|Activity"
+msgstr ""
+
msgid "Vulnerability|Class"
msgstr ""
@@ -27738,6 +28653,9 @@ msgstr ""
msgid "Vulnerability|Description"
msgstr ""
+msgid "Vulnerability|Detected"
+msgstr ""
+
msgid "Vulnerability|Evidence"
msgstr ""
@@ -27801,6 +28719,9 @@ msgstr ""
msgid "Warning: Displaying this diagram might cause performance issues on this page."
msgstr ""
+msgid "We are currently unable to fetch data for the pipeline header."
+msgstr ""
+
msgid "We are currently unable to fetch data for this graph."
msgstr ""
@@ -27840,6 +28761,12 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
+msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
+msgstr ""
+
+msgid "We would like to inform you that your subscription GitLab Enterprise Edition %{plan_name} is nearing its user limit. You have %{active_user_count} active users, which is almost at the user limit of %{maximum_user_count}."
+msgstr ""
+
msgid "We've found no vulnerabilities"
msgstr ""
@@ -27855,6 +28782,12 @@ msgstr ""
msgid "Web terminal"
msgstr ""
+msgid "WebAuthn Devices (%{length})"
+msgstr ""
+
+msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
+msgstr ""
+
msgid "WebIDE|Merge request"
msgstr ""
@@ -27993,15 +28926,9 @@ msgstr ""
msgid "Welcome to the guided GitLab tour"
msgstr ""
-msgid "Welcome to your Issue Board!"
-msgstr ""
-
msgid "Welcome to your issue board!"
msgstr ""
-msgid "We’ve been making changes to %{featureName} and we’d love your feedback %{linkStart}in this issue%{linkEnd} to help us improve the experience."
-msgstr ""
-
msgid "What are you searching for?"
msgstr ""
@@ -28020,6 +28947,9 @@ msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
msgstr ""
+msgid "When enabled, any user visiting %{host} and creating an account will have to be explicitly approved by the admin before they can login. This setting is effective only if sign-ups are enabled."
+msgstr ""
+
msgid "When enabled, any user visiting %{host} will be able to create an account."
msgstr ""
@@ -28244,6 +29174,9 @@ msgstr ""
msgid "With requirements, you can set criteria to check your products against."
msgstr ""
+msgid "With test cases, you can define conditions for your project to meet in determining quality"
+msgstr ""
+
msgid "Withdraw Access Request"
msgstr ""
@@ -28259,6 +29192,9 @@ msgstr ""
msgid "Workflow Help"
msgstr ""
+msgid "Would you like to create a new branch?"
+msgstr ""
+
msgid "Write"
msgstr ""
@@ -28280,6 +29216,9 @@ msgstr ""
msgid "Wrong extern UID provided. Make sure Auth0 is configured correctly."
msgstr ""
+msgid "YYYY-MM-DD"
+msgstr ""
+
msgid "Yes"
msgstr ""
@@ -28337,7 +29276,7 @@ msgstr ""
msgid "You are going to remove the fork relationship from %{project_full_name}. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "You are going to transfer %{project_full_name} to another owner. Are you ABSOLUTELY sure?"
+msgid "You are going to transfer %{project_full_name} to another namespace. Are you ABSOLUTELY sure?"
msgstr ""
msgid "You are going to turn off the confidentiality. This means %{strongStart}everyone%{strongEnd} will be able to see and leave a comment on this %{issuableType}."
@@ -28397,9 +29336,6 @@ msgstr ""
msgid "You can always edit this later"
msgstr ""
-msgid "You can apply your Trial to your Personal account or create a New Group."
-msgstr ""
-
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings"
msgstr ""
@@ -28421,12 +29357,18 @@ msgstr ""
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
+msgid "You can find more information about GitLab subscriptions in %{subscriptions_doc_link}."
+msgstr ""
+
msgid "You can generate an access token scoped to this project for each application to use the GitLab API."
msgstr ""
msgid "You can get started by cloning the repository or start adding files to it with one of the following options."
msgstr ""
+msgid "You can group test cases using labels. To learn about the future direction of this feature, visit %{linkStart}Quality Management direction page%{linkEnd}."
+msgstr ""
+
msgid "You can invite a new member to %{project_name} or invite another group."
msgstr ""
@@ -28442,6 +29384,9 @@ msgstr ""
msgid "You can notify the app / group or a project by sending them an email notification"
msgstr ""
+msgid "You can now close this window."
+msgstr ""
+
msgid "You can now export your security dashboard to a CSV report."
msgstr ""
@@ -28490,9 +29435,6 @@ msgstr ""
msgid "You can test your .gitlab-ci.yml in %{linkStart}CI Lint%{linkEnd}."
msgstr ""
-msgid "You can try again using %{begin_link}basic search%{end_link}"
-msgstr ""
-
msgid "You cannot access the raw file. Please wait a minute."
msgstr ""
@@ -28544,6 +29486,9 @@ msgstr ""
msgid "You don't have any U2F devices registered yet."
msgstr ""
+msgid "You don't have any WebAuthn devices registered yet."
+msgstr ""
+
msgid "You don't have any active chat names."
msgstr ""
@@ -28631,6 +29576,9 @@ msgstr ""
msgid "You must accept our Terms of Service and privacy policy in order to register an account"
msgstr ""
+msgid "You must be logged in to search across all of GitLab"
+msgstr ""
+
msgid "You must disassociate %{domain} from all clusters it is attached to before deletion."
msgstr ""
@@ -28670,7 +29618,7 @@ msgstr ""
msgid "You need to be logged in."
msgstr ""
-msgid "You need to register a two-factor authentication app before you can set up a U2F device."
+msgid "You need to register a two-factor authentication app before you can set up a device."
msgstr ""
msgid "You need to set terms to be enforced"
@@ -28688,6 +29636,9 @@ msgstr ""
msgid "You reached %{usage_in_percent} of %{namespace_name}'s storage capacity (%{used_storage} of %{storage_limit})"
msgstr ""
+msgid "You successfully declined the invitation"
+msgstr ""
+
msgid "You tried to fork %{link_to_the_project} but it failed for the following reason:"
msgstr ""
@@ -28853,10 +29804,13 @@ msgstr ""
msgid "Your U2F device did not send a valid JSON response."
msgstr ""
-msgid "Your U2F device needs to be set up. Plug it in (if not already) and click the button on the left."
+msgid "Your U2F device was registered!"
msgstr ""
-msgid "Your U2F device was registered!"
+msgid "Your WebAuthn device did not send a valid JSON response."
+msgstr ""
+
+msgid "Your WebAuthn device was registered!"
msgstr ""
msgid "Your access request to the %{source_type} has been withdrawn."
@@ -28880,6 +29834,9 @@ msgstr ""
msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
msgstr ""
+msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
+msgstr ""
+
msgid "Your changes can be committed to %{branch_name} because a merge request is open."
msgstr ""
@@ -28916,6 +29873,12 @@ msgstr ""
msgid "Your deployment services will be broken, you will need to manually fix the services after renaming."
msgstr ""
+msgid "Your device is not compatible with GitLab. Please try another device"
+msgstr ""
+
+msgid "Your device needs to be set up. Plug it in (if needed) and click the button on the left."
+msgstr ""
+
msgid "Your device was successfully set up! Give it a name and register it with the GitLab server."
msgstr ""
@@ -29029,9 +29992,6 @@ msgstr[1] ""
msgid "access:"
msgstr ""
-msgid "activated"
-msgstr ""
-
msgid "added %{created_at_timeago}"
msgstr ""
@@ -29104,9 +30064,21 @@ msgstr ""
msgid "by %{user}"
msgstr ""
+msgid "cannot be a date in the past"
+msgstr ""
+
msgid "cannot be changed if a personal project has container registry tags."
msgstr ""
+msgid "cannot be changed if shared runners are enabled"
+msgstr ""
+
+msgid "cannot be enabled because parent group does not allow it"
+msgstr ""
+
+msgid "cannot be enabled because parent group has shared Runners disabled"
+msgstr ""
+
msgid "cannot be enabled unless all domains have TLS certificates"
msgstr ""
@@ -29152,7 +30124,7 @@ msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about SAST %{linkEndTag}"
msgstr ""
-msgid "ciReport|%{linkStartTag}Learn more about Secret Scanning %{linkEndTag}"
+msgid "ciReport|%{linkStartTag}Learn more about Secret Detection %{linkEndTag}"
msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about codequality reports %{linkEndTag}"
@@ -29467,9 +30439,6 @@ msgstr ""
msgid "error"
msgstr ""
-msgid "error code:"
-msgstr ""
-
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr ""
@@ -29491,6 +30460,9 @@ msgstr ""
msgid "failed to dismiss associated finding(id=%{finding_id}): %{message}"
msgstr ""
+msgid "failed to revert associated finding(id=%{finding_id}) to detected"
+msgstr ""
+
msgid "file"
msgid_plural "files"
msgstr[0] ""
@@ -30033,6 +31005,9 @@ msgstr ""
msgid "must be a root namespace"
msgstr ""
+msgid "must be a valid IPv4 or IPv6 address"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -30069,6 +31044,9 @@ msgstr ""
msgid "no expiration"
msgstr ""
+msgid "no name set"
+msgstr ""
+
msgid "no one can merge"
msgstr ""
@@ -30247,9 +31225,6 @@ msgstr ""
msgid "security Reports|There was an error creating the merge request"
msgstr ""
-msgid "settings saved, but not activated"
-msgstr ""
-
msgid "severity|Critical"
msgstr ""
@@ -30376,9 +31351,6 @@ msgstr ""
msgid "toggle collapse"
msgstr ""
-msgid "toggle dropdown"
-msgstr ""
-
msgid "triggered"
msgstr ""
@@ -30406,6 +31378,9 @@ msgstr ""
msgid "user avatar"
msgstr ""
+msgid "user preferences"
+msgstr ""
+
msgid "username"
msgstr ""
diff --git a/locale/ko/gitlab.po b/locale/ko/gitlab.po
index 76aa839787b..8bc6ac54040 100644
--- a/locale/ko/gitlab.po
+++ b/locale/ko/gitlab.po
@@ -14,7 +14,10 @@ msgstr ""
"X-Crowdin-Language: ko\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 6\n"
-"PO-Revision-Date: 2020-09-04 23:08\n"
+"PO-Revision-Date: 2020-10-02 18:48\n"
+
+msgid " %{project_name}#%{issue_iid} &middot; opened %{issue_created} by %{author}"
+msgstr ""
msgid " %{start} to %{end}"
msgstr " %{start}부터 %{end}까지"
@@ -72,6 +75,14 @@ msgstr "\"%{path}\"는 \"%{ref}\"ì— ì¡´ìž¬í•˜ì§€ 않습니다"
msgid "\"el\" parameter is required for createInstance()"
msgstr ""
+msgid "%d Approval"
+msgid_plural "%d Approvals"
+msgstr[0] ""
+
+msgid "%d Package"
+msgid_plural "%d Packages"
+msgstr[0] ""
+
msgid "%d Scanned URL"
msgid_plural "%d Scanned URLs"
msgstr[0] ""
@@ -123,6 +134,10 @@ msgstr[0] "%dê°œì˜ ì»¤ë°‹,"
msgid "%d commits"
msgstr "%dê°œì˜ ì»¤ë°‹"
+msgid "%d completed issue"
+msgid_plural "%d completed issues"
+msgstr[0] ""
+
msgid "%d contribution"
msgid_plural "%d contributions"
msgstr[0] "%d 기여"
@@ -131,6 +146,10 @@ msgid "%d day"
msgid_plural "%d days"
msgstr[0] "%dì¼"
+msgid "%d day until tags are automatically removed"
+msgid_plural "%d days until tags are automatically removed"
+msgstr[0] ""
+
msgid "%d error"
msgid_plural "%d errors"
msgstr[0] "%dê°œì˜ ì˜¤ë¥˜"
@@ -203,6 +222,14 @@ msgid "%d more comment"
msgid_plural "%d more comments"
msgstr[0] "%d 댓글 ë” ë³´ê¸°"
+msgid "%d open issue"
+msgid_plural "%d open issues"
+msgstr[0] ""
+
+msgid "%d pending comment"
+msgid_plural "%d pending comments"
+msgstr[0] ""
+
msgid "%d personal project will be removed and cannot be restored."
msgid_plural "%d personal projects will be removed and cannot be restored."
msgstr[0] "%dê°œì˜ ê°œì¸ í”„ë¡œì íŠ¸ê°€ 제거ë˜ê³ , ë³µì›í•  수 없게 ë©ë‹ˆë‹¤."
@@ -215,6 +242,10 @@ msgid "%d project"
msgid_plural "%d projects"
msgstr[0] "%d 프로ì íŠ¸"
+msgid "%d project selected"
+msgid_plural "%d projects selected"
+msgstr[0] ""
+
msgid "%d request with warnings"
msgid_plural "%d requests with warnings"
msgstr[0] "%d ê±´ì˜ ê²½ê³ ê°€ 있는 요청"
@@ -231,6 +262,10 @@ msgid "%d tag"
msgid_plural "%d tags"
msgstr[0] "%dê°œì˜ íƒœê·¸"
+msgid "%d tag per image name"
+msgid_plural "%d tags per image name"
+msgstr[0] ""
+
msgid "%d unassigned issue"
msgid_plural "%d unassigned issues"
msgstr[0] ""
@@ -247,6 +282,10 @@ msgid "%d vulnerability dismissed"
msgid_plural "%d vulnerabilities dismissed"
msgstr[0] "%dê°œì˜ ì·¨ì•½ì  ë¬´ì‹œë¨"
+msgid "%d warning found:"
+msgid_plural "%d warnings found:"
+msgstr[0] ""
+
msgid "%s additional commit has been omitted to prevent performance issues."
msgid_plural "%s additional commits have been omitted to prevent performance issues."
msgstr[0] "%s 추가 ì»¤ë°‹ì€ ì„±ëŠ¥ ì´ìŠˆë¥¼ 방지하기 위해 ìƒëžµë˜ì—ˆìŠµë‹ˆë‹¤."
@@ -284,6 +323,9 @@ msgstr ""
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr "%{commit_timeago} ì— %{commit_author_link} ë‹˜ì´ ì»¤ë°‹í•˜ì˜€ìŠµë‹ˆë‹¤."
+msgid "%{completedCount} completed weight"
+msgstr ""
+
msgid "%{completedWeight} of %{totalWeight} weight completed"
msgstr ""
@@ -329,13 +371,12 @@ msgid "%{count} participant"
msgid_plural "%{count} participants"
msgstr[0] "%{count} ëª…ì˜ ì°¸ì—¬ìž"
-msgid "%{count} pending comment"
-msgid_plural "%{count} pending comments"
-msgstr[0] "%{count}ê°œì˜ ëŒ€ê¸°ì¤‘ì¸ ëŒ“ê¸€ "
-
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr "%{count} ê±´ê³¼ ê´€ë ¨ëœ %{pluralized_subject}: %{links}"
+msgid "%{count} total weight"
+msgstr ""
+
msgid "%{dashboard_path} could not be found."
msgstr "%{dashboard_path}(ì„)를 ì°¾ì„ ìˆ˜ 없습니다."
@@ -390,6 +431,9 @@ msgstr ""
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 ê³„ì •ì„ ë§Œë“¤ì–´ì•¼ 합니다."
+msgid "%{group_name}&%{epic_iid} &middot; opened %{epic_created} by %{author}"
+msgstr ""
+
msgid "%{host} sign-in from new location"
msgstr "새로운 위치ì—ì„œ %{host}ì— ë¡œê·¸ì¸ë˜ì—ˆìŠµë‹ˆë‹¤."
@@ -402,7 +446,7 @@ msgstr ""
msgid "%{issuableType} will be removed! Are you sure?"
msgstr "%{issuableType}ì´ ì‚­ì œë©ë‹ˆë‹¤! 확실합니까?"
-msgid "%{issuesSize} issues with a limit of %{maxIssueCount}"
+msgid "%{issuesCount} issues with a limit of %{maxIssueCount}"
msgstr ""
msgid "%{issuesSize} with a limit of %{maxIssueCount}"
@@ -435,7 +479,7 @@ msgstr ""
msgid "%{labelStart}Namespace:%{labelEnd} %{namespace}"
msgstr ""
-msgid "%{labelStart}Report Type:%{labelEnd} %{reportType}"
+msgid "%{labelStart}Scan Type:%{labelEnd} %{reportType}"
msgstr ""
msgid "%{labelStart}Scanner:%{labelEnd} %{scanner}"
@@ -625,9 +669,6 @@ msgid "%{securityScanner} result is not available because a pipeline has not bee
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] ""
-msgid "%{service_title} %{message}."
-msgstr "%{service_title} %{message}."
-
msgid "%{size} GiB"
msgstr "%{size} GiB"
@@ -711,6 +752,12 @@ msgstr "%{text} 사용 가능"
msgid "%{timebox_name} should belong either to a project or a group."
msgstr "%{timebox_name}ì€(는) 프로ì íŠ¸ë‚˜ ê·¸ë£¹ì— ì†í•´ì•¼í•©ë‹ˆë‹¤."
+msgid "%{timebox_type} does not support burnup charts"
+msgstr ""
+
+msgid "%{timebox_type} must have a start and due date"
+msgstr ""
+
msgid "%{title} %{operator} %{threshold}"
msgstr "%{title} %{operator} %{threshold}"
@@ -735,8 +782,8 @@ msgstr ""
msgid "%{total} open issue weight"
msgstr ""
-msgid "%{total} open issues"
-msgstr "%{total}ê°œì˜ ì´ìŠˆ 열림"
+msgid "%{total} warnings found: showing first %{warningsDisplayed}"
+msgstr ""
msgid "%{usage_ping_link_start}Learn more%{usage_ping_link_end} about what information is shared with GitLab Inc."
msgstr "GitLab Inc와 공유ë˜ëŠ” ì •ë³´ì— ëŒ€í•´ %{usage_ping_link_start}ë” ì•Œì•„ë³´ê¸°%{usage_ping_link_end}"
@@ -768,9 +815,6 @@ msgstr ""
msgid "&lt; 1 hour"
msgstr ""
-msgid "&lt;no name set&gt;"
-msgstr ""
-
msgid "&lt;no scopes selected&gt;"
msgstr ""
@@ -801,6 +845,9 @@ msgstr "'%{level}' ìˆ˜ì¤€ì€ ì˜¬ë°”ë¥¸ 공개 ìˆ˜ì¤€ì´ ì•„ë‹™ë‹ˆë‹¤"
msgid "'%{name}' Value Stream created"
msgstr ""
+msgid "'%{name}' Value Stream deleted"
+msgstr ""
+
msgid "'%{name}' stage already exists"
msgstr ""
@@ -859,6 +906,9 @@ msgstr "+ %{moreCount} ë”"
msgid "+ %{numberOfHiddenAssignees} more"
msgstr "+ %{numberOfHiddenAssignees}명 ë” ìžˆìŒ"
+msgid "+ %{numberOfHiddenReviewers} more"
+msgstr ""
+
msgid "+%d more"
msgid_plural "+%d more"
msgstr[0] "+%d개"
@@ -913,6 +963,10 @@ msgid "1 Day"
msgid_plural "%d Days"
msgstr[0] "%dì¼"
+msgid "1 Issue"
+msgid_plural "%d Issues"
+msgstr[0] ""
+
msgid "1 closed issue"
msgid_plural "%{issues} closed issues"
msgstr[0] "%{issues} ê°œì˜ ì´ìŠˆ closed"
@@ -925,6 +979,10 @@ msgid "1 day"
msgid_plural "%d days"
msgstr[0] "%dì¼"
+msgid "1 deploy key"
+msgid_plural "%d deploy keys"
+msgstr[0] ""
+
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] "%d 그룹"
@@ -1018,6 +1076,9 @@ msgstr "8 시간"
msgid ":%{startLine} to %{endLine}"
msgstr ""
+msgid "A %{incident_docs_start}modified issue%{incident_docs_end} to guide the resolution of incidents."
+msgstr ""
+
msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr "'러너(Runner)'는 ìž‘ì—…ì„ ì‹¤í–‰í•˜ëŠ” 프로세스입니다. 필요한 ë§Œí¼ ëŸ¬ë„ˆë¥¼ ì…‹ì—…í•  수 있습니다."
@@ -1030,6 +1091,9 @@ msgstr ""
msgid "A GitBook site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr "ì´ GitBook 사ì´íŠ¸ëŠ” GitLab CI/CD 대신 Netlify를 사용하지만, GitLabì˜ ë‹¤ë¥¸ 멋진 ê¸°ëŠ¥ì„ ê³„ì† ì‚¬ìš©í•  수 있습니다."
+msgid "A Gitpod configured Webapplication in Spring and Java"
+msgstr ""
+
msgid "A Hexo site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr "ì´ Hexo 사ì´íŠ¸ëŠ” GitLab CI/CD 대신 Netlify를 사용하지만, GitLabì˜ ë‹¤ë¥¸ 멋진 ê¸°ëŠ¥ì„ ê³„ì† ì‚¬ìš©í•  수 있습니다."
@@ -1201,9 +1265,15 @@ msgstr "ì ‘ê·¼ì´ ê±°ë¶€ë˜ì—ˆìŠµë‹ˆë‹¤! ì´ ì €ìž¥ì†Œì— ë°°í¬ í‚¤ë¥¼ 추가 í
msgid "Access expiration date"
msgstr "액세스 만료ì¼"
+msgid "Access expires"
+msgstr ""
+
msgid "Access forbidden. Check your access level."
msgstr "액세스 금지. ì ‘ê·¼ ê¶Œí•œì„ í™•ì¸í•˜ì„¸ìš”."
+msgid "Access granted"
+msgstr ""
+
msgid "Access requests"
msgstr ""
@@ -1213,6 +1283,9 @@ msgstr "%{classification_label} ì— ëŒ€í•œ 액세스가 허용ë˜ì§€ 않습니ë‹
msgid "Access to Pages websites are controlled based on the user's membership to a given project. By checking this box, users will be required to be logged in to have access to all Pages websites in your instance."
msgstr ""
+msgid "AccessDropdown|Deploy Keys"
+msgstr ""
+
msgid "AccessDropdown|Groups"
msgstr "그룹"
@@ -1330,12 +1403,6 @@ msgstr "%{type} 활성화 (%{token_length})"
msgid "Active Sessions"
msgstr "í™œì„±í™”ëœ ì„¸ì…˜"
-msgid "Active Users:"
-msgstr "활성 사용ìž:"
-
-msgid "Active users"
-msgstr "활성 사용ìž"
-
msgid "Activity"
msgstr "활ë™"
@@ -1502,9 +1569,6 @@ msgstr ""
msgid "Add label(s)"
msgstr "ë ˆì´ë¸” 추가"
-msgid "Add license"
-msgstr "ë¼ì´ì„ ìŠ¤ 추가"
-
msgid "Add list"
msgstr "ëª©ë¡ ì¶”ê°€"
@@ -1679,21 +1743,51 @@ msgstr "ì°¨ë‹¨ëœ ì‚¬ìš©ìž"
msgid "AdminArea|Bots"
msgstr "ë´‡"
+msgid "AdminArea|Components"
+msgstr ""
+
msgid "AdminArea|Developer"
msgstr ""
+msgid "AdminArea|Features"
+msgstr ""
+
+msgid "AdminArea|Groups: %{number_of_groups}"
+msgstr ""
+
msgid "AdminArea|Guest"
msgstr ""
msgid "AdminArea|Included Free in license"
msgstr ""
+msgid "AdminArea|Latest groups"
+msgstr ""
+
+msgid "AdminArea|Latest projects"
+msgstr ""
+
+msgid "AdminArea|Latest users"
+msgstr ""
+
msgid "AdminArea|Maintainer"
msgstr ""
+msgid "AdminArea|New group"
+msgstr ""
+
+msgid "AdminArea|New project"
+msgstr ""
+
+msgid "AdminArea|New user"
+msgstr ""
+
msgid "AdminArea|Owner"
msgstr ""
+msgid "AdminArea|Projects: %{number_of_projects}"
+msgstr ""
+
msgid "AdminArea|Reporter"
msgstr ""
@@ -1721,6 +1815,9 @@ msgstr ""
msgid "AdminArea|Users without a Group and Project"
msgstr ""
+msgid "AdminArea|Users: %{number_of_users}"
+msgstr ""
+
msgid "AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running."
msgstr "모든 ìž‘ì—…ì„ ì¤‘ì§€í•©ë‹ˆë‹¤. 현재 ì‹¤í–‰ì¤‘ì¸ ëª¨ë“  ìž‘ì—…ì´ ì¤‘ì§€ë©ë‹ˆë‹¤."
@@ -1739,9 +1836,6 @@ msgstr "삭제"
msgid "AdminProjects|Delete Project %{projectName}?"
msgstr "%{projectName} 프로ì íŠ¸ë¥¼ 삭제하시겠습니까?"
-msgid "AdminProjects|Delete project"
-msgstr "프로ì íŠ¸ ì‚­ì œ"
-
msgid "AdminSettings|Apply integration settings to all Projects"
msgstr ""
@@ -1979,21 +2073,30 @@ msgstr ""
msgid "AdminUsers|Without projects"
msgstr "프로ì íŠ¸ ì—†ì´"
-msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 ""
msgid "AdminUsers|You cannot remove your own admin rights."
msgstr ""
+msgid "AdminUsers|You must transfer ownership or delete the groups owned by this user before you can delete their account"
+msgstr ""
+
msgid "Administration"
msgstr ""
msgid "Advanced"
msgstr "고급"
+msgid "Advanced Search"
+msgstr ""
+
+msgid "Advanced Search with Elasticsearch"
+msgstr ""
+
msgid "Advanced Settings"
msgstr "고급 설정"
@@ -2070,6 +2173,9 @@ msgstr ""
msgid "AlertManagement|Edit"
msgstr ""
+msgid "AlertManagement|Environment"
+msgstr ""
+
msgid "AlertManagement|Events"
msgstr ""
@@ -2082,6 +2188,9 @@ msgstr ""
msgid "AlertManagement|Issue"
msgstr ""
+msgid "AlertManagement|Key"
+msgstr ""
+
msgid "AlertManagement|Low"
msgstr ""
@@ -2175,6 +2284,9 @@ msgstr ""
msgid "AlertManagement|Unknown"
msgstr ""
+msgid "AlertManagement|Value"
+msgstr ""
+
msgid "AlertManagement|View alerts in Opsgenie"
msgstr ""
@@ -2334,6 +2446,9 @@ msgstr ""
msgid "All projects"
msgstr "모든 프로ì íŠ¸"
+msgid "All projects selected"
+msgstr ""
+
msgid "All security scans are enabled because %{linkStart}Auto DevOps%{linkEnd} is enabled on this project"
msgstr ""
@@ -2421,6 +2536,9 @@ msgstr "Kubernetes í´ëŸ¬ìŠ¤í„°ë¥¼ 추가하고 관리 í•  수 ​​있습니ë‹
msgid "Almost there"
msgstr "ê±°ì˜ ë‹¤ ë났습니다"
+msgid "Already blocked"
+msgstr ""
+
msgid "Also called \"Issuer\" or \"Relying party trust identifier\""
msgstr "\"issuer\" ë˜ëŠ” \"Relying party trust identifier\" ë¼ê³ ë„ 합니다."
@@ -2475,6 +2593,9 @@ msgstr "비어 있는 GitLab User 필드는 FogBugzì˜ ì‚¬ìš©ìž ì „ì²´ ì´ë¦„ (
msgid "An error has occurred"
msgstr "ì—러가 ë°œìƒí–ˆìŠµë‹ˆë‹¤."
+msgid "An error occured while making the changes: %{error}"
+msgstr ""
+
msgid "An error occurred adding a draft to the thread."
msgstr ""
@@ -2502,12 +2623,6 @@ msgstr "BLOB 미리보기 ì¤‘ì— ì˜¤ë¥˜ê°€ ë°œìƒí–ˆìŠµë‹ˆë‹¤."
msgid "An error occurred when toggling the notification subscription"
msgstr "알림 êµ¬ë… ì—¬ë¶€ 변경 ì¤‘ì— ì˜¤ë¥˜ê°€ ë°œìƒí–ˆìŠµë‹ˆë‹¤."
-msgid "An error occurred when trying to resolve a comment. Please try again."
-msgstr ""
-
-msgid "An error occurred when trying to resolve a discussion. Please try again."
-msgstr ""
-
msgid "An error occurred when updating the issue weight"
msgstr "ì´ìŠˆ ì¤‘ìš”ë„ ì—…ë°ì´íŠ¸ 중 문제가 ë°œìƒí–ˆìŠµë‹ˆë‹¤."
@@ -2523,12 +2638,6 @@ msgstr ""
msgid "An error occurred while checking group path. Please refresh and try again."
msgstr ""
-msgid "An error occurred while committing your changes."
-msgstr "ë‚´ ë³€ê²½ì‚¬í•­ì„ ì»¤ë°‹í•˜ë˜ ë„중 오류가 ë°œìƒí–ˆìŠµë‹ˆë‹¤."
-
-msgid "An error occurred while creating the list. Please try again."
-msgstr ""
-
msgid "An error occurred while decoding the file."
msgstr ""
@@ -2601,26 +2710,20 @@ msgstr ""
msgid "An error occurred while fetching the Service Desk address."
msgstr ""
-msgid "An error occurred while fetching the board issues. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the board lists. Please reload the page."
msgstr ""
msgid "An error occurred while fetching the board lists. Please try again."
msgstr ""
-msgid "An error occurred while fetching the board swimlanes. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the builds."
msgstr ""
msgid "An error occurred while fetching the job log."
msgstr "ìž‘ì—… 로그를 가져 오는 ì¤‘ì— ì˜¤ë¥˜ê°€ ë°œìƒí–ˆìŠµë‹ˆë‹¤."
-msgid "An error occurred while fetching the job trace."
-msgstr "ìž‘ì—… 기ë¡ì„ 가져오는 ë„중 오류가 ë°œìƒí–ˆìŠµë‹ˆë‹¤."
+msgid "An error occurred while fetching the job logs."
+msgstr ""
msgid "An error occurred while fetching the job."
msgstr "ìž‘ì—…ì„ ê°€ì ¸ 오는 ì¤‘ì— ì˜¤ë¥˜ê°€ ë°œìƒí–ˆìŠµë‹ˆë‹¤."
@@ -2766,9 +2869,6 @@ msgstr "LDAP 무시 ìƒíƒœë¥¼ 저장하는 중 오류가 ë°œìƒí–ˆìŠµë‹ˆë‹¤. 다
msgid "An error occurred while saving assignees"
msgstr "담당ìžë¥¼ 저장하는 중 오류가 ë°œìƒí•˜ì˜€ìŠµë‹ˆë‹¤."
-msgid "An error occurred while saving the template. Please check if the template exists."
-msgstr ""
-
msgid "An error occurred while searching for milestones"
msgstr ""
@@ -2787,12 +2887,12 @@ msgstr "알림 구ë…ì„ í•´ì œí•˜ëŠ” 중 오류가 ë°œìƒí–ˆìŠµë‹ˆë‹¤."
msgid "An error occurred while updating approvers"
msgstr "승ì¸ìžë¥¼ ì—…ë°ì´íŠ¸í•˜ëŠ” ë™ì•ˆ 오류가 ë°œìƒí–ˆìŠµë‹ˆë‹¤"
+msgid "An error occurred while updating labels."
+msgstr ""
+
msgid "An error occurred while updating the comment"
msgstr "ëŒ“ê¸€ì„ ì—…ë°ì´íŠ¸í•˜ëŠ” 중 오류가 ë°œìƒí–ˆìŠµë‹ˆë‹¤."
-msgid "An error occurred while updating the list. Please try again."
-msgstr ""
-
msgid "An error occurred while validating group path"
msgstr ""
@@ -2844,6 +2944,9 @@ msgstr "웹 터미ë„ì˜ ìž‘ë™ì„ ë©ˆì¶”ë˜ ë„중 예ìƒì¹˜ ì•Šì€ ì˜¤ë¥˜ê°€ ë
msgid "An unknown error occurred while loading this graph."
msgstr ""
+msgid "An unknown error occurred."
+msgstr ""
+
msgid "Analytics"
msgstr "분ì„"
@@ -2877,10 +2980,10 @@ msgstr "안티 스팸 ê²€ì¦"
msgid "Any"
msgstr "Any"
-msgid "Any Author"
+msgid "Any %{header}"
msgstr ""
-msgid "Any Status"
+msgid "Any Author"
msgstr ""
msgid "Any branch"
@@ -2934,6 +3037,9 @@ msgstr "어플리케ì´ì…˜"
msgid "Application ID"
msgstr "애플리케ì´ì…˜ ID"
+msgid "Application limits saved successfully"
+msgstr ""
+
msgid "Application settings saved successfully"
msgstr "어플리케ì´ì…˜ ì„¤ì •ì´ ì„±ê³µì ìœ¼ë¡œ 저장ë˜ì—ˆìŠµë‹ˆë‹¤."
@@ -3139,6 +3245,9 @@ msgstr ""
msgid "Are you sure you want to close this blocked issue?"
msgstr ""
+msgid "Are you sure you want to delete \"%{name}\" Value Stream?"
+msgstr ""
+
msgid "Are you sure you want to delete %{name}?"
msgstr ""
@@ -3148,6 +3257,9 @@ msgstr ""
msgid "Are you sure you want to delete this %{typeOfComment}?"
msgstr ""
+msgid "Are you sure you want to delete this SSH key?"
+msgstr ""
+
msgid "Are you sure you want to delete this board?"
msgstr ""
@@ -3172,6 +3284,10 @@ msgstr ""
msgid "Are you sure you want to erase this build?"
msgstr "ì •ë§ë¡œ ì´ ë¹Œë“œë¥¼ 지우시겠습니까?"
+msgid "Are you sure you want to import %d repository?"
+msgid_plural "Are you sure you want to import %d repositories?"
+msgstr[0] ""
+
msgid "Are you sure you want to lose unsaved changes?"
msgstr "저장ë˜ì§€ ì•Šì€ ë³€ê²½ì‚¬í•­ì„ ì‚­ì œí•˜ê² ìŠµë‹ˆê¹Œ?"
@@ -3181,15 +3297,15 @@ msgstr "ì •ë§ ì´ìŠˆ 정보를 삭제하길 ì›í•˜ì‹­ë‹ˆê¹Œ?"
msgid "Are you sure you want to merge immediately?"
msgstr ""
-msgid "Are you sure you want to permanently delete this license?"
-msgstr ""
-
msgid "Are you sure you want to re-deploy this environment?"
msgstr ""
msgid "Are you sure you want to regenerate the public key? You will have to update the public key on the remote server before mirroring will work again."
msgstr "공개키를 재ìƒì„±í•˜ì‹œê² ìŠµë‹ˆê¹Œ? 미러ë§ì´ 다시 ë™ìž‘하기 위해서 remote ì„œë²„ì˜ ê³µê°œí‚¤ë¥¼ ì—…ë°ì´íŠ¸í•´ì•¼ í•  것입니다."
+msgid "Are you sure you want to reindex?"
+msgstr ""
+
msgid "Are you sure you want to remove %{group_name}?"
msgstr "ì •ë§ë¡œ %{group_name}(ì„)를 ì‚­ì œ 하시겠습니까?"
@@ -3217,6 +3333,9 @@ msgstr ""
msgid "Are you sure you want to revoke this nickname?"
msgstr ""
+msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
+msgstr ""
+
msgid "Are you sure you want to stop this environment?"
msgstr "ì´ í™˜ê²½ì„ ì¤‘ë‹¨í•˜ê¸¸ ì›í•˜ë‚˜ìš”?"
@@ -3238,6 +3357,9 @@ msgstr ""
msgid "Are you sure? The device will be signed out of GitLab and all remember me tokens revoked."
msgstr ""
+msgid "Are you sure? This will invalidate your registered applications and U2F / WebAuthn devices."
+msgstr ""
+
msgid "Are you sure? This will invalidate your registered applications and U2F devices."
msgstr ""
@@ -3256,9 +3378,6 @@ msgstr ""
msgid "Artifacts"
msgstr "결과물"
-msgid "As U2F devices are only supported by a few browsers, we require that you set up a two-factor authentication app before a U2F device. That way you'll always be able to log in - even when you're using an unsupported browser."
-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 ""
@@ -3450,6 +3569,9 @@ msgstr ""
msgid "AuditLogs|Target"
msgstr ""
+msgid "AuditLogs|This month"
+msgstr ""
+
msgid "AuditLogs|User Events"
msgstr ""
@@ -3489,6 +3611,9 @@ msgstr "ì¸ì¦ ë°©ë²•ì´ ì—…ë°ì´íŠ¸ ë˜ì—ˆìŠµë‹ˆë‹¤."
msgid "Authentication via U2F device failed."
msgstr "U2F 장치를 통한 ì¸ì¦ì´ 실패하였습니다."
+msgid "Authentication via WebAuthn device failed."
+msgstr ""
+
msgid "Author"
msgstr "작성ìž"
@@ -3756,15 +3881,6 @@ msgstr ""
msgid "BambooService|You must set up automatic revision labeling and a repository trigger in Bamboo."
msgstr ""
-msgid "BatchComments|Delete all pending comments"
-msgstr "모든 보류 ì¤‘ì— ìžˆëŠ” 커맨트 ì‚­ì œ"
-
-msgid "BatchComments|Discard review?"
-msgstr "리뷰를 취소 하시겠습니까?"
-
-msgid "BatchComments|You're about to discard your review which will delete all of your pending comments. The deleted comments %{strong_start}cannot%{strong_end} be restored."
-msgstr "리뷰를 취소하시려고 합니다. 리뷰를 취소 하시면 보류 ì¤‘ì— ìžˆëŠ” 모든 ëŒ“ê¸€ì´ ì‚­ì œë©ë‹ˆë‹¤. %{strong_start} 여기부터%{strong_end} ì—¬ê¸°ê¹Œì§€ì˜ ì‚­ì œëœ ëŒ“ê¸€ì€ ë³µì› í•˜ì‹¤ 수 없습니다."
-
msgid "Be careful. Changing the project's namespace can have unintended side effects."
msgstr ""
@@ -3786,6 +3902,9 @@ msgstr "공개 ëœ ëª¨ë“  ê·¸ë£¹ì„ ì•„ëž˜ì—ì„œ ì°¾ì„ ìˆ˜ 있습니다."
msgid "Bi-weekly code coverage"
msgstr ""
+msgid "Billable Users:"
+msgstr ""
+
msgid "Billing"
msgstr "결제"
@@ -3795,8 +3914,8 @@ msgstr "%{group_name}(ì€)는 %{plan_name} í”Œëžœì„ ì‚¬ìš©í•˜ê³  있습니다."
msgid "BillingPlans|@%{user_name} you are currently using the %{plan_name} plan."
msgstr "@%{user_name}ë‹˜ì€ í˜„ìž¬ %{plan_name} í”Œëžœì„ ì‚¬ìš©í•˜ê³  있습니다."
-msgid "BillingPlans|Congratulations, your new trial is activated"
-msgstr "축하합니다, 새 ì²´í—˜íŒì´ 활성화ë˜ì—ˆìŠµë‹ˆë‹¤."
+msgid "BillingPlans|Congratulations, your free trial is activated."
+msgstr ""
msgid "BillingPlans|If you would like to downgrade your plan please contact %{support_link_start}Customer Support%{support_link_end}."
msgstr "요금제를 다운그레ì´ë“œí•˜ë ¤ë©´ %{support_link_start}ê³ ê° ì§€ì›%{support_link_end}ì— ë¬¸ì˜í•´ì£¼ì„¸ìš”."
@@ -3858,6 +3977,9 @@ msgstr "Bitbucketì—ì„œ 가져오기"
msgid "Blame"
msgstr ""
+msgid "Block user"
+msgstr ""
+
msgid "Blocked"
msgstr "차단ë¨"
@@ -3873,31 +3995,37 @@ msgstr ""
msgid "Blog"
msgstr "블로그"
-msgid "Board name"
-msgstr "ë³´ë“œ ì´ë¦„"
-
msgid "Board scope"
msgstr ""
msgid "Board scope affects which issues are displayed for anyone who visits this board"
msgstr ""
-msgid "BoardBlankState|Add default lists"
+msgid "Boards"
+msgstr "보드"
+
+msgid "Boards and Board Lists"
msgstr ""
-msgid "BoardBlankState|Add the following default lists to your Issue Board with one click:"
+msgid "Boards|An error occurred while creating the issue. Please try again."
msgstr ""
-msgid "BoardBlankState|Nevermind, I'll use my own"
+msgid "Boards|An error occurred while creating the list. Please try again."
msgstr ""
-msgid "BoardBlankState|Starting out with the default set of lists will get you right on the way to making the most of your board."
+msgid "Boards|An error occurred while fetching issues. Please reload the page."
msgstr ""
-msgid "Boards"
-msgstr "보드"
+msgid "Boards|An error occurred while fetching the board issues. Please reload the page."
+msgstr ""
-msgid "Boards and Board Lists"
+msgid "Boards|An error occurred while fetching the board swimlanes. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while moving the issue. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while updating the list. Please try again."
msgstr ""
msgid "Boards|Collapse"
@@ -3924,8 +4052,8 @@ msgstr "%{branchName} 브랜치는 ì´ í”„ë¡œì íŠ¸ ì €ìž¥ì†Œì— ì—†ìŠµë‹ˆë‹¤."
msgid "Branch %{branch_name} was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr ""
-msgid "Branch has changed"
-msgstr "브랜치가 변경ë˜ì—ˆìŠµë‹ˆë‹¤."
+msgid "Branch changed"
+msgstr ""
msgid "Branch is already taken"
msgstr "해당 브랜치는 ì´ë¯¸ 사용중입니다"
@@ -4230,6 +4358,9 @@ msgstr ""
msgid "CLOSED (MOVED)"
msgstr ""
+msgid "CODEOWNERS rule violation"
+msgstr ""
+
msgid "CONTRIBUTING"
msgstr "CONTRIBUTING"
@@ -4260,9 +4391,6 @@ msgstr ""
msgid "Can't create snippet: %{err}"
msgstr ""
-msgid "Can't edit as source branch was deleted"
-msgstr ""
-
msgid "Can't fetch content for the blob: %{err}"
msgstr ""
@@ -4275,9 +4403,6 @@ msgstr ""
msgid "Can't load mermaid module: %{err}"
msgstr ""
-msgid "Can't remove group members without group managed account"
-msgstr ""
-
msgid "Can't scan the code?"
msgstr ""
@@ -4320,6 +4445,9 @@ msgstr ""
msgid "Cannot create the abuse report. This user has been blocked."
msgstr ""
+msgid "Cannot enable shared runners because parent group does not allow it"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -4425,6 +4553,15 @@ msgstr "비밀번호 변경"
msgid "Change your password or recover your current one"
msgstr "비밀번호 변경 ë˜ëŠ” 비밀번호 복구"
+msgid "ChangeReviewer|Reviewer changed from %{old} to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Reviewer changed to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Unassigned"
+msgstr ""
+
msgid "ChangeTypeActionLabel|Pick into branch"
msgstr "브랜치ì—ì„œ Pick"
@@ -4464,6 +4601,9 @@ msgstr "ì—…ë°ì´íŠ¸ê°€ 반려ë˜ì—ˆìŠµë‹ˆë‹¤. í´ë¦­í•˜ì—¬ 확ì¸í•©ë‹ˆë‹¤."
msgid "Changes the title to \"%{title_param}\"."
msgstr ""
+msgid "Changes were successfully made."
+msgstr ""
+
msgid "Changes won't take place until the index is %{link_start}recreated%{link_end}."
msgstr ""
@@ -4869,6 +5009,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove variable"
+msgstr ""
+
msgid "CiVariables|Remove variable row"
msgstr "변수 행 제거"
@@ -4947,9 +5090,6 @@ msgstr ""
msgid "Clear due date"
msgstr ""
-msgid "Clear input"
-msgstr "입력 지우기"
-
msgid "Clear recent searches"
msgstr "최근 검색 지우기"
@@ -4998,6 +5138,9 @@ msgstr "í´ë¼ì´ì–¸íŠ¸ ì¸ì¦ 키"
msgid "Client authentication key password"
msgstr "í´ë¼ì´ì–¸íŠ¸ ì¸ì¦ 키 비밀번호"
+msgid "Client request timeout"
+msgstr ""
+
msgid "Clients"
msgstr "í´ë¼ì´ì–¸íŠ¸"
@@ -5082,6 +5225,27 @@ msgstr ""
msgid "Cluster type must be specificed for Stages::ClusterEndpointInserter"
msgstr ""
+msgid "ClusterAgents|Configuration"
+msgstr ""
+
+msgid "ClusterAgents|Connect your cluster with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate Kubernetes with a GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Name"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Agent also requires %{linkStart}enabling the Agent Server%{linkEnd}"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Kubernetes Agent allows an Infrastructure as Code, GitOps approach to integrating Kubernetes clusters with GitLab. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "ClusterAgent|This feature is only available for premium plans"
msgstr ""
@@ -5151,10 +5315,10 @@ msgstr ""
msgid "ClusterIntegration|All installed applications and related resources"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster."
+msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{linkStart}More information%{linkEnd}"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{startLink}More information%{endLink}"
+msgid "ClusterIntegration|Allow GitLab to manage namespaces and service accounts for this cluster."
msgstr ""
msgid "ClusterIntegration|Alternatively, "
@@ -5175,6 +5339,9 @@ msgstr "ClusterIntegration|프로ì íŠ¸ë¥¼ 가져오는 ë„중 오류가 ë°œìƒí
msgid "ClusterIntegration|An error occurred while trying to fetch zone machine types: %{error}"
msgstr ""
+msgid "ClusterIntegration|An unknown error occurred while attempting to connect to Kubernetes."
+msgstr ""
+
msgid "ClusterIntegration|Any project namespaces"
msgstr ""
@@ -5190,6 +5357,9 @@ msgstr ""
msgid "ClusterIntegration|Authenticate with Amazon Web Services"
msgstr ""
+msgid "ClusterIntegration|Authentication Error"
+msgstr ""
+
msgid "ClusterIntegration|Base domain"
msgstr ""
@@ -5208,13 +5378,22 @@ msgstr ""
msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
msgstr "ì¸ì¦ 기관 번들 (PEM í¬ë§·)"
-msgid "ClusterIntegration|Choose the %{startLink}security group %{externalLinkIcon} %{endLink} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
+msgid "ClusterIntegration|Check your CA certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Check your cluster status"
+msgstr ""
+
+msgid "ClusterIntegration|Check your token"
+msgstr ""
+
+msgid "ClusterIntegration|Choose the %{linkStart}security group %{linkEnd} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}subnets %{externalLinkIcon} %{endLink} in your VPC where your worker nodes will run."
+msgid "ClusterIntegration|Choose the %{linkStart}subnets %{linkEnd} in your VPC where your worker nodes will run."
msgstr ""
-msgid "ClusterIntegration|Choose the worker node %{startLink}instance type %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Choose the worker node %{linkStart}instance type%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Choose which applications to install on your Kubernetes cluster."
@@ -5226,10 +5405,7 @@ msgstr "ì´ Kubernetes í´ëŸ¬ìŠ¤í„°ë¥¼ 사용할 프로ì íŠ¸ 환경 ì„ íƒ"
msgid "ClusterIntegration|Clear cluster cache"
msgstr ""
-msgid "ClusterIntegration|Clear the local cache of namespace and service accounts. This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
-msgstr ""
-
-msgid "ClusterIntegration|Cluster being created"
+msgid "ClusterIntegration|Clear the local cache of namespace and service accounts."
msgstr ""
msgid "ClusterIntegration|Cluster management project (alpha)"
@@ -5241,15 +5417,21 @@ msgstr ""
msgid "ClusterIntegration|Cluster_applications artifact too big. Maximum allowable size: %{human_size}"
msgstr ""
-msgid "ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters."
+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|Clusters connected with a certificate"
msgstr ""
-msgid "ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters. %{linkStart}More information%{linkEnd}"
+msgid "ClusterIntegration|Connect cluster with certificate"
msgstr ""
msgid "ClusterIntegration|Connect existing cluster"
msgstr ""
+msgid "ClusterIntegration|Connection Error"
+msgstr ""
+
msgid "ClusterIntegration|Copy API URL"
msgstr "API URL 복사"
@@ -5325,6 +5507,12 @@ msgstr ""
msgid "ClusterIntegration|Deletes all GitLab resources attached to this cluster during removal"
msgstr ""
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared."
+msgstr ""
+
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared. %{linkStart}More information%{linkEnd}"
+msgstr ""
+
msgid "ClusterIntegration|Did you know?"
msgstr "알고 계셨나요?"
@@ -5394,6 +5582,9 @@ msgstr ""
msgid "ClusterIntegration|Fluentd is an open source data collector, which lets you unify the data collection and consumption for a better use and understanding of data. It requires at least one of the following logs to be successfully installed."
msgstr ""
+msgid "ClusterIntegration|GitLab Agent managed clusters"
+msgstr ""
+
msgid "ClusterIntegration|GitLab Container Network Policies"
msgstr ""
@@ -5406,6 +5597,12 @@ msgstr "ClusterIntegration|GitLab Runner"
msgid "ClusterIntegration|GitLab Runner connects to the repository and executes CI/CD jobs, pushing results back and deploying applications to production."
msgstr ""
+msgid "ClusterIntegration|GitLab failed to authenticate."
+msgstr ""
+
+msgid "ClusterIntegration|GitLab failed to connect to the cluster."
+msgstr ""
+
msgid "ClusterIntegration|GitLab-managed cluster"
msgstr ""
@@ -5427,6 +5624,9 @@ msgstr "Google Kubernetes 엔진 프로ì íŠ¸"
msgid "ClusterIntegration|Group cluster"
msgstr "그룹 í´ëŸ¬ìŠ¤í„°"
+msgid "ClusterIntegration|HTTP Error"
+msgstr ""
+
msgid "ClusterIntegration|Helm Tiller"
msgstr "Helm Tiller"
@@ -5460,8 +5660,11 @@ msgstr ""
msgid "ClusterIntegration|Instance type"
msgstr ""
-msgid "ClusterIntegration|Integrate Kubernetes cluster automation"
-msgstr "Kubernetes í´ëŸ¬ìŠ¤í„° ìžë™í™” 통합"
+msgid "ClusterIntegration|Integrate Kubernetes with a cluster certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Integrate with a cluster certificate"
+msgstr ""
msgid "ClusterIntegration|Issuer Email"
msgstr ""
@@ -5496,9 +5699,6 @@ msgstr ""
msgid "ClusterIntegration|Knative extends Kubernetes to provide a set of middleware components that are essential to build modern, source-centric, and container-based applications that can run anywhere: on premises, in the cloud, or even in a third-party data center."
msgstr ""
-msgid "ClusterIntegration|Kubernetes cluster"
-msgstr "Kubernetes í´ëŸ¬ìŠ¤í„°"
-
msgid "ClusterIntegration|Kubernetes cluster is being created..."
msgstr ""
@@ -5511,9 +5711,6 @@ msgstr ""
msgid "ClusterIntegration|Kubernetes clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr "Kubernetes í´ëŸ¬ìŠ¤í„°ë¥¼ 사용하면 리뷰 í”„ë¡œê·¸ëž¨ì„ ì‚¬ìš©í•˜ê³ , ì‘ìš© í”„ë¡œê·¸ëž¨ì„ ë°°í¬í•˜ê³ , 파ì´í”„ ë¼ì¸ì„ 실행하는 ë“±ì˜ ìž‘ì—…ì„ ì†ì‰½ê²Œ 수행 í•  수 있습니다."
-msgid "ClusterIntegration|Kubernetes clusters can be used to deploy applications and to provide Review Apps for this project"
-msgstr "Kubernetes í´ëŸ¬ìŠ¤í„°ëŠ” 어플리케ì´ì…˜ì„ ë°°í¬í•˜ê³  ì´ í”„ë¡œì íŠ¸ì— 대한 리뷰 어플리케ì´ì…˜ì„ 제공하는 ë° ì‚¬ìš©í•  수 있습니다."
-
msgid "ClusterIntegration|Kubernetes version"
msgstr ""
@@ -5526,7 +5723,7 @@ msgstr "%{help_link_start_machine_type}머신 유형%{help_link_end} ë° %{help_
msgid "ClusterIntegration|Learn more about %{help_link_start}zones%{help_link_end}."
msgstr "%{help_link_start}zones%{help_link_end}ì— ëŒ€í•´ ìžì„¸ížˆ 알아보기"
-msgid "ClusterIntegration|Learn more about %{startLink}Regions %{externalLinkIcon}%{endLink}."
+msgid "ClusterIntegration|Learn more about %{linkStart}Regions%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Learn more about Kubernetes"
@@ -5571,12 +5768,18 @@ msgstr ""
msgid "ClusterIntegration|Machine type"
msgstr "머신 타입"
+msgid "ClusterIntegration|Make sure your API endpoint is correct"
+msgstr ""
+
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create Kubernetes clusters"
msgstr "Kubernetes í´ëŸ¬ìŠ¤í„°ë¥¼ 만들려면 %{link_to_requirements} ë§í¬ì—ì„œ ê³„ì •ì˜ í•„ìˆ˜ì‚¬í•­ì„ í™•ì¸í•˜ì„¸ìš”."
msgid "ClusterIntegration|Manage your Kubernetes cluster by visiting %{provider_link}"
msgstr ""
+msgid "ClusterIntegration|Namespace per environment"
+msgstr ""
+
msgid "ClusterIntegration|No IAM Roles found"
msgstr ""
@@ -5622,6 +5825,9 @@ msgstr ""
msgid "ClusterIntegration|No zones matched your search"
msgstr "검색과 ì¼ì¹˜í•˜ëŠ” ì˜ì—­ì´ 없습니다."
+msgid "ClusterIntegration|Node calculations use the Kubernetes Metrics API. Make sure your cluster has metrics installed"
+msgstr ""
+
msgid "ClusterIntegration|Number of nodes"
msgstr "노드 수"
@@ -5664,6 +5870,9 @@ msgstr ""
msgid "ClusterIntegration|RBAC-enabled cluster"
msgstr ""
+msgid "ClusterIntegration|Read our %{linkStart}help page%{linkEnd} on Kubernetes cluster integration."
+msgstr ""
+
msgid "ClusterIntegration|Read our %{link_start}help page%{link_end} on Kubernetes cluster integration."
msgstr ""
@@ -5766,7 +5975,7 @@ msgstr ""
msgid "ClusterIntegration|Select a VPC to choose a subnet"
msgstr ""
-msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{linkStart}Amazon Web Services %{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select a network to choose a subnetwork"
@@ -5799,7 +6008,7 @@ msgstr ""
msgid "ClusterIntegration|Select project to choose zone"
msgstr ""
-msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select zone"
@@ -5889,9 +6098,18 @@ msgstr ""
msgid "ClusterIntegration|There was a problem authenticating with your cluster. Please ensure your CA Certificate and Token are valid."
msgstr ""
+msgid "ClusterIntegration|There was an HTTP error when connecting to your cluster."
+msgstr ""
+
msgid "ClusterIntegration|This account must have permissions to create a Kubernetes cluster in the %{link_to_container_project} specified below"
msgstr "%{link_to_container_project} 프로ì íŠ¸ì— Kubernetes í´ëŸ¬ìŠ¤í„°ë¥¼ 만들기 위해서는 ì´ ê³„ì •ì— ì•„ëž˜ì— ëª…ì‹œëœ ê¶Œí•œì´ í•„ìš”í•©ë‹ˆë‹¤"
+msgid "ClusterIntegration|This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
+msgstr ""
+
+msgid "ClusterIntegration|This is necessary to clear existing environment-namespace associations from clusters previously managed by GitLab."
+msgstr ""
+
msgid "ClusterIntegration|This option will allow you to install applications on RBAC clusters."
msgstr ""
@@ -5916,9 +6134,21 @@ msgstr ""
msgid "ClusterIntegration|To use a new project, first create one on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}."
msgstr ""
+msgid "ClusterIntegration|Troubleshooting tips:"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Authenticate"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Connect"
+msgstr ""
+
msgid "ClusterIntegration|Uninstall %{appTitle}"
msgstr ""
+msgid "ClusterIntegration|Unknown Error"
+msgstr ""
+
msgid "ClusterIntegration|Update %{appTitle}"
msgstr ""
@@ -5979,7 +6209,7 @@ msgstr "ë‹¹ì‹ ì˜ ê³„ì •ì€ %{link_to_kubernetes_engine} ì´ ìžˆì–´ì•¼ 합니다
msgid "ClusterIntegration|Your cluster API is unreachable. Please ensure your API URL is correct."
msgstr ""
-msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Zone"
@@ -6099,6 +6329,9 @@ msgstr ""
msgid "Collapse"
msgstr "ê°ì¶”기"
+msgid "Collapse all threads"
+msgstr ""
+
msgid "Collapse approvers"
msgstr ""
@@ -6247,8 +6480,8 @@ msgstr "커밋한 사용ìž"
msgid "Commit…"
msgstr "커밋..."
-msgid "Company"
-msgstr "회사"
+msgid "Community forum"
+msgstr ""
msgid "Company name"
msgstr ""
@@ -6256,6 +6489,9 @@ msgstr ""
msgid "Compare"
msgstr "비êµ"
+msgid "Compare %{oldCommitId}...%{newCommitId}"
+msgstr ""
+
msgid "Compare Git revisions"
msgstr "Git 리비전 비êµ"
@@ -6271,6 +6507,9 @@ msgstr "마지막 커밋과 ë³€ê²½ì  ë¹„êµ"
msgid "Compare changes with the merge request target branch"
msgstr "머지 리퀘스트(MR) ëŒ€ìƒ ë¸Œëžœì¹˜ì™€ 변경 사항 비êµ"
+msgid "Compare submodule commit revisions"
+msgstr ""
+
msgid "Compare with previous version"
msgstr ""
@@ -6406,6 +6645,9 @@ msgstr "%{link} ì—°ë™ êµ¬ì„±"
msgid "Configure the way a user creates a new account."
msgstr "사용ìžê°€ 새로운 ê³„ì •ì„ ë§Œë“œëŠ” ë°©ë²•ì„ ì„¤ì •í•©ë‹ˆë‹¤."
+msgid "Configure which lists are shown for anyone who visits this board"
+msgstr ""
+
msgid "Confirm"
msgstr "확ì¸"
@@ -6628,6 +6870,9 @@ msgstr[0] ""
msgid "ContainerRegistry|Set cleanup policy"
msgstr ""
+msgid "ContainerRegistry|Some tags were not deleted"
+msgstr ""
+
msgid "ContainerRegistry|Something went wrong while fetching the cleanup policy."
msgstr ""
@@ -6667,6 +6912,9 @@ msgstr ""
msgid "ContainerRegistry|Tags with names matching this regex pattern will %{italicStart}expire:%{italicEnd}"
msgstr ""
+msgid "ContainerRegistry|The cleanup policy timed out before it could delete all tags. An administrator can %{adminLinkStart}manually run cleanup now%{adminLinkEnd} or you can wait for the cleanup policy to automatically run again. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "ContainerRegistry|The last tag related to this image was recently removed. This empty image and any associated data will be automatically removed as part of the regular Garbage Collection process. If you have any questions, contact your administrator."
msgstr ""
@@ -6799,6 +7047,9 @@ msgstr ""
msgid "Contributions per group member"
msgstr "그룹 구성ì›ë³„ 기여"
+msgid "Contributor"
+msgstr ""
+
msgid "Contributors"
msgstr "기여해 주신 분들"
@@ -6928,6 +7179,9 @@ msgstr "채팅 ë‹‰ë„¤ìž„ì„ ì¸ì¦í•˜ì§€ 못했습니다. 다시 ì‹œë„하세요
msgid "Could not change HEAD: branch '%{branch}' does not exist"
msgstr ""
+msgid "Could not commit. An unexpected error occurred."
+msgstr ""
+
msgid "Could not connect to FogBugz, check your URL"
msgstr "FogBugzì— ì—°ê²°í•˜ì§€ 못했습니다. URLì„ í™•ì¸í•´ì£¼ì„¸ìš”."
@@ -6967,6 +7221,9 @@ msgstr ""
msgid "Could not find iteration"
msgstr ""
+msgid "Could not load instance counts. Please refresh the page to try again."
+msgstr ""
+
msgid "Could not remove the trigger."
msgstr ""
@@ -6991,10 +7248,10 @@ msgstr ""
msgid "Could not save prometheus manual configuration"
msgstr ""
-msgid "Could not udpdate wiki page"
+msgid "Could not update the LDAP settings"
msgstr ""
-msgid "Could not update the LDAP settings"
+msgid "Could not update wiki page"
msgstr ""
msgid "Could not upload your designs as one or more files uploaded are not supported."
@@ -7650,6 +7907,9 @@ msgstr ""
msgid "DastProfiles|Are you sure you want to delete this profile?"
msgstr ""
+msgid "DastProfiles|Could not create site validation token. Please refresh the page, or try again later."
+msgstr ""
+
msgid "DastProfiles|Could not create the scanner profile. Please try again."
msgstr ""
@@ -7674,6 +7934,12 @@ msgstr ""
msgid "DastProfiles|Could not fetch site profiles. Please refresh the page, or try again later."
msgstr ""
+msgid "DastProfiles|Could not retrieve site validation status. Please refresh the page, or try again later."
+msgstr ""
+
+msgid "DastProfiles|Could not update the scanner profile. Please try again."
+msgstr ""
+
msgid "DastProfiles|Could not update the site profile. Please try again."
msgstr ""
@@ -7689,7 +7955,7 @@ msgstr ""
msgid "DastProfiles|Download validation text file"
msgstr ""
-msgid "DastProfiles|Edit feature will come soon. Please create a new profile if changes needed"
+msgid "DastProfiles|Edit scanner profile"
msgstr ""
msgid "DastProfiles|Edit site profile"
@@ -7722,6 +7988,9 @@ msgstr ""
msgid "DastProfiles|No profiles created yet"
msgstr ""
+msgid "DastProfiles|Passive"
+msgstr ""
+
msgid "DastProfiles|Please enter a valid URL format, ex: http://www.example.com/home"
msgstr ""
@@ -7737,6 +8006,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan mode"
+msgstr ""
+
msgid "DastProfiles|Scanner Profile"
msgstr ""
@@ -7776,10 +8048,10 @@ msgstr ""
msgid "DastProfiles|Text file validation"
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
+msgid "DastProfiles|The maximum number of minutes allowed for the spider to traverse the site."
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the spider to traverse the site."
+msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
msgstr ""
msgid "DastProfiles|Validate"
@@ -7812,6 +8084,9 @@ msgstr "날짜"
msgid "Date picker"
msgstr "날짜 ì„ íƒ"
+msgid "Date range"
+msgstr ""
+
msgid "Date range cannot exceed %{maxDateRange} days."
msgstr ""
@@ -7836,6 +8111,9 @@ msgstr ""
msgid "Days to merge"
msgstr ""
+msgid "Dear Administrator,"
+msgstr ""
+
msgid "Debug"
msgstr "디버그"
@@ -7947,12 +8225,18 @@ msgstr "지연ë¨"
msgid "Delete"
msgstr "삭제 "
+msgid "Delete %{name}"
+msgstr ""
+
msgid "Delete Comment"
msgstr "댓글 삭제"
msgid "Delete Snippet"
msgstr "스니펫 삭제"
+msgid "Delete Value Stream"
+msgstr ""
+
msgid "Delete account"
msgstr ""
@@ -7974,9 +8258,6 @@ msgstr ""
msgid "Delete label: %{label_name} ?"
msgstr ""
-msgid "Delete license"
-msgstr "ë¼ì´ì„¼ìŠ¤ ì‚­ì œ"
-
msgid "Delete list"
msgstr "ëª©ë¡ ì‚­ì œ"
@@ -8052,15 +8333,6 @@ msgstr ""
msgid "Deleting a project places it into a read-only state until %{date}, at which point the project will be permanently deleted. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "Deleting the license failed."
-msgstr "ë¼ì´ì„¼ìŠ¤ ì‚­ì œì— ì‹¤íŒ¨í–ˆìŠµë‹ˆë‹¤."
-
-msgid "Deleting the license failed. The license was not found."
-msgstr "ë¼ì´ì„¼ìŠ¤ ì‚­ì œì— ì‹¤íŒ¨í–ˆìŠµë‹ˆë‹¤. ë¼ì´ì„¼ìŠ¤ë¥¼ ì°¾ì„ ìˆ˜ 없습니다."
-
-msgid "Deleting the license failed. You are not permitted to perform this action."
-msgstr "ë¼ì´ì„¼ìŠ¤ë¥¼ 삭제하지 못했습니다. ì´ ìž‘ì—…ì„ ìˆ˜í–‰í•  ê¶Œí•œì´ ì—†ìŠµë‹ˆë‹¤."
-
msgid "Deleting the project will delete its repository and all related resources including issues, merge requests etc."
msgstr ""
@@ -8550,7 +8822,10 @@ msgstr ""
msgid "DesignManagement|The maximum number of designs allowed to be uploaded is %{upload_limit}. Please try again."
msgstr ""
-msgid "DesignManagement|To upload designs, you'll need to enable LFS. %{requirements_link_start}More information%{requirements_link_end}"
+msgid "DesignManagement|There was an error moving your designs. Please upload your designs below."
+msgstr ""
+
+msgid "DesignManagement|To upload designs, you'll need to enable LFS and have admin enable hashed storage. %{requirements_link_start}More information%{requirements_link_end}"
msgstr ""
msgid "DesignManagement|Unresolve thread"
@@ -8562,6 +8837,9 @@ msgstr ""
msgid "DesignManagement|Upload skipped."
msgstr ""
+msgid "DesignManagement|Your designs are being copied and are on their way… Please refresh to update."
+msgstr ""
+
msgid "DesignManagement|and %{moreCount} more."
msgstr ""
@@ -8619,6 +8897,9 @@ msgstr ""
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr "Diffs | ë³µìˆ˜ì˜ ì—´ì„ íŒ¨ì¹˜í•˜ëŠ” 중 문제가 ë°œìƒí–ˆìŠµë‹ˆë‹¤."
+msgid "Direct member"
+msgstr ""
+
msgid "Direction"
msgstr "ë°©í–¥"
@@ -8667,9 +8948,6 @@ msgstr "%{path}ì— ëŒ€í•œ 변경 취소?"
msgid "Discard draft"
msgstr "초안 삭제"
-msgid "Discard review"
-msgstr "리뷰 삭제"
-
msgid "DiscordService|Discord Notifications"
msgstr ""
@@ -8737,10 +9015,10 @@ msgstr ""
msgid "Dismiss Merge Request promotion"
msgstr "머지 리퀘스트 프로모션 제거"
-msgid "Dismiss Selected"
+msgid "Dismiss Value Stream Analytics introduction box"
msgstr ""
-msgid "Dismiss Value Stream Analytics introduction box"
+msgid "Dismiss selected"
msgstr ""
msgid "Dismiss trial promotion"
@@ -8791,9 +9069,6 @@ msgstr "ì¸ê¸°ìžˆëŠ” ID 제공 ì—…ì²´ì— ëŒ€í•œ 문서"
msgid "Documents reindexed: %{processed_documents} (%{percentage}%%)"
msgstr ""
-msgid "Doing"
-msgstr ""
-
msgid "Domain"
msgstr "ë„ë©”ì¸"
@@ -8989,9 +9264,6 @@ msgstr "설명 편집"
msgid "Edit environment"
msgstr "환경 편집"
-msgid "Edit file"
-msgstr "íŒŒì¼ ìˆ˜ì •"
-
msgid "Edit files in the editor and commit changes here"
msgstr "ì—디터ì—ì„œ 파ì¼ì„ 편집하고 여기서 ë³€ê²½ì‚¬í•­ì„ ì»¤ë°‹í•˜ì„¸ìš”."
@@ -9004,6 +9276,12 @@ msgstr "그룹 편집: %{group_name}"
msgid "Edit identity for %{user_name}"
msgstr "%{user_name}ì˜ ì‹ ì› íŽ¸ì§‘"
+msgid "Edit in Web IDE"
+msgstr ""
+
+msgid "Edit in single-file editor"
+msgstr ""
+
msgid "Edit issues"
msgstr "ì´ìŠˆ 편집"
@@ -9031,21 +9309,18 @@ msgstr ""
msgid "Editing"
msgstr ""
-msgid "Elasticsearch"
-msgstr "Elasticsearch"
-
msgid "Elasticsearch AWS IAM credentials"
msgstr ""
+msgid "Elasticsearch HTTP client timeout value in seconds."
+msgstr ""
+
msgid "Elasticsearch indexing restrictions"
msgstr ""
msgid "Elasticsearch indexing started"
msgstr "Elasticsearch ì¸ë±ì‹± 시작ë¨"
-msgid "Elasticsearch integration. Elasticsearch AWS IAM."
-msgstr "Elasticsearch ì—°ë™, Elasticsearch AWS IAM"
-
msgid "Elasticsearch reindexing is already in progress"
msgstr ""
@@ -9073,9 +9348,6 @@ msgstr ""
msgid "Email Notification"
msgstr ""
-msgid "Email address"
-msgstr "ì´ë©”ì¼ ì£¼ì†Œ"
-
msgid "Email could not be sent"
msgstr ""
@@ -9139,6 +9411,9 @@ msgstr "ì´ë©”ì¼"
msgid "Emails sent from Service Desk will have this name"
msgstr ""
+msgid "Emails sent to %{email} will still be supported"
+msgstr ""
+
msgid "Emails separated by comma"
msgstr ""
@@ -9172,9 +9447,18 @@ msgstr "빈 파ì¼"
msgid "Enable"
msgstr "사용"
+msgid "Enable %{link_start}Gitpod%{link_end} integration to launch a development environment in your browser directly from GitLab."
+msgstr ""
+
msgid "Enable Auto DevOps"
msgstr "ìžë™ DevOps 활성화"
+msgid "Enable Gitpod"
+msgstr ""
+
+msgid "Enable Gitpod?"
+msgstr ""
+
msgid "Enable HTML emails"
msgstr "HTML ì´ë©”ì¼ í™œì„±í™”"
@@ -9304,9 +9588,6 @@ msgstr ""
msgid "Encountered an error while rendering: %{err}"
msgstr ""
-msgid "End date"
-msgstr ""
-
msgid "Ends at (UTC)"
msgstr "(UTC)ì— ì¢…ë£Œë©ë‹ˆë‹¤"
@@ -9466,7 +9747,7 @@ msgstr ""
msgid "EnvironmentsDashboard|The environments dashboard provides a summary of each project's environments' status, including pipeline and alert statuses."
msgstr ""
-msgid "EnvironmentsDashboard|This dashboard displays a maximum of 7 projects and 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
+msgid "EnvironmentsDashboard|This dashboard displays 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
msgstr ""
msgid "Environments|An error occurred while canceling the auto stop, please try again"
@@ -9787,6 +10068,9 @@ msgstr ""
msgid "Error deleting project. Check logs for error details."
msgstr ""
+msgid "Error fetching burnup chart data"
+msgstr ""
+
msgid "Error fetching diverging counts for branches. Please try again."
msgstr ""
@@ -9865,6 +10149,9 @@ msgstr ""
msgid "Error occurred when saving assignees"
msgstr ""
+msgid "Error occurred when saving reviewers"
+msgstr ""
+
msgid "Error occurred when toggling the notification subscription"
msgstr "êµ¬ë… ì•Œë¦¼ì„ ì „í™˜í•  ë•Œ 오류가 ë°œìƒí•˜ì˜€ìŠµë‹ˆë‹¤."
@@ -10117,12 +10404,15 @@ msgstr "펼치기"
msgid "Expand all"
msgstr "ëª¨ë‘ í™•ìž¥"
-msgid "Expand approvers"
-msgstr "승ì¸ìž 확장"
+msgid "Expand all files"
+msgstr ""
-msgid "Expand dropdown"
+msgid "Expand all threads"
msgstr ""
+msgid "Expand approvers"
+msgstr "승ì¸ìž 확장"
+
msgid "Expand milestones"
msgstr ""
@@ -10291,6 +10581,9 @@ msgstr "관련 브랜치를 확ì¸í•˜ëŠ”ë° ì‹¤íŒ¨í–ˆìŠµë‹ˆë‹¤."
msgid "Failed to create Merge Request. Please try again."
msgstr ""
+msgid "Failed to create To-Do for the design."
+msgstr ""
+
msgid "Failed to create a branch for this issue. Please try again."
msgstr ""
@@ -10330,6 +10623,12 @@ msgstr ""
msgid "Failed to load authors. Please try again."
msgstr ""
+msgid "Failed to load branches. Please try again."
+msgstr ""
+
+msgid "Failed to load deploy keys."
+msgstr ""
+
msgid "Failed to load emoji list."
msgstr "ì´ëª¨ì§€ 목ë¡ì„ 불러올 수 없습니다"
@@ -10345,6 +10644,9 @@ msgstr ""
msgid "Failed to load groups & users."
msgstr ""
+msgid "Failed to load groups, users and deploy keys."
+msgstr ""
+
msgid "Failed to load labels. Please try again."
msgstr ""
@@ -10354,6 +10656,12 @@ msgstr ""
msgid "Failed to load related branches"
msgstr ""
+msgid "Failed to load sidebar confidential toggle"
+msgstr ""
+
+msgid "Failed to load sidebar lock status"
+msgstr ""
+
msgid "Failed to load stacktrace."
msgstr ""
@@ -10381,6 +10689,9 @@ msgstr ""
msgid "Failed to publish issue on status page."
msgstr ""
+msgid "Failed to remove To-Do for the design."
+msgstr ""
+
msgid "Failed to remove a Zoom meeting"
msgstr ""
@@ -10423,6 +10734,9 @@ msgstr ""
msgid "Failed to signing using smartcard authentication"
msgstr ""
+msgid "Failed to toggle To-Do for the design."
+msgstr ""
+
msgid "Failed to update branch!"
msgstr ""
@@ -10535,7 +10849,7 @@ msgstr "Feature 플래그 수정"
msgid "FeatureFlags|Edit User List"
msgstr ""
-msgid "FeatureFlags|Enable features for specific users and specific environments by defining feature flag strategies."
+msgid "FeatureFlags|Enable features for specific users and environments by configuring feature flag strategies."
msgstr ""
msgid "FeatureFlags|Environment Spec"
@@ -10595,7 +10909,7 @@ msgstr ""
msgid "FeatureFlags|Include additional user IDs"
msgstr ""
-msgid "FeatureFlags|Install a %{docs_link_anchored_start}compatible client library%{docs_link_anchored_end} and specify the API URL, application name, and instance ID during the configuration setup. %{docs_link_start}More Information%{docs_link_end}"
+msgid "FeatureFlags|Install a %{docsLinkAnchoredStart}compatible client library%{docsLinkAnchoredEnd} and specify the API URL, application name, and instance ID during the configuration setup. %{docsLinkStart}More Information%{docsLinkEnd}"
msgstr ""
msgid "FeatureFlags|Instance ID"
@@ -10607,6 +10921,9 @@ msgstr ""
msgid "FeatureFlags|Loading feature flags"
msgstr ""
+msgid "FeatureFlags|Loading user lists"
+msgstr ""
+
msgid "FeatureFlags|More information"
msgstr ""
@@ -10625,7 +10942,7 @@ msgstr ""
msgid "FeatureFlags|New feature flag"
msgstr ""
-msgid "FeatureFlags|New list"
+msgid "FeatureFlags|New user list"
msgstr ""
msgid "FeatureFlags|Percent of users"
@@ -10664,6 +10981,9 @@ msgstr ""
msgid "FeatureFlags|There was an error fetching the feature flags."
msgstr ""
+msgid "FeatureFlags|There was an error fetching the user lists."
+msgstr ""
+
msgid "FeatureFlags|There was an error retrieving user lists"
msgstr ""
@@ -10679,6 +10999,9 @@ msgstr ""
msgid "FeatureFlags|User List"
msgstr ""
+msgid "FeatureFlags|User Lists"
+msgstr ""
+
msgid "FeatureFlag|List"
msgstr ""
@@ -10706,15 +11029,6 @@ msgstr "2ì›”"
msgid "Fetching incoming email"
msgstr ""
-msgid "Fetching licenses failed."
-msgstr ""
-
-msgid "Fetching licenses failed. The request endpoint was not found."
-msgstr ""
-
-msgid "Fetching licenses failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "File"
msgstr ""
@@ -10817,12 +11131,21 @@ msgstr ""
msgid "Filter by status"
msgstr ""
+msgid "Filter by test cases that are currently archived."
+msgstr ""
+
+msgid "Filter by test cases that are currently opened."
+msgstr ""
+
msgid "Filter by two-factor authentication"
msgstr ""
msgid "Filter by user"
msgstr ""
+msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
+msgstr ""
+
msgid "Filter pipelines"
msgstr ""
@@ -10838,7 +11161,7 @@ msgstr ""
msgid "Filter results..."
msgstr ""
-msgid "Filter your projects by name"
+msgid "Filter your repositories by name"
msgstr ""
msgid "Filter..."
@@ -10847,7 +11170,7 @@ msgstr "í•„í„°..."
msgid "Find File"
msgstr ""
-msgid "Find bugs in your code with coverage-guided fuzzing"
+msgid "Find bugs in your code with coverage-guided fuzzing."
msgstr ""
msgid "Find by path"
@@ -10874,9 +11197,6 @@ msgstr "지문"
msgid "Finish editing this message first!"
msgstr ""
-msgid "Finish review"
-msgstr "리뷰 완료"
-
msgid "Finish setting up your dedicated account for %{group_name}."
msgstr ""
@@ -10946,6 +11266,9 @@ msgstr "글꼴 색"
msgid "Footer message"
msgstr "바닥글 메시지"
+msgid "For a faster browsing experience, some files are collapsed by default."
+msgstr ""
+
msgid "For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
@@ -10955,6 +11278,9 @@ msgstr ""
msgid "For more info, read the documentation."
msgstr ""
+msgid "For more information on how the number of active users is calculated, see the %{self_managed_subscriptions_doc_link} documentation."
+msgstr ""
+
msgid "For more information, go to the "
msgstr ""
@@ -11093,6 +11419,9 @@ msgstr ""
msgid "Generate new token"
msgstr ""
+msgid "Generic package file size in bytes"
+msgstr ""
+
msgid "Geo"
msgstr "Geo"
@@ -11354,6 +11683,9 @@ msgstr ""
msgid "Geo|Please refer to Geo Troubleshooting."
msgstr ""
+msgid "Geo|Primary node"
+msgstr ""
+
msgid "Geo|Project"
msgstr ""
@@ -11396,6 +11728,9 @@ msgstr ""
msgid "Geo|Review replication status, and resynchronize and reverify items with the primary node."
msgstr ""
+msgid "Geo|Secondary node"
+msgstr ""
+
msgid "Geo|Status"
msgstr "ìƒíƒœ"
@@ -11435,6 +11770,9 @@ msgstr ""
msgid "Geo|URL must be a valid url (ex: https://gitlab.com)"
msgstr ""
+msgid "Geo|Undefined"
+msgstr ""
+
msgid "Geo|Unknown state"
msgstr "ì•Œ 수 없는 ìƒíƒœ"
@@ -11510,10 +11848,16 @@ msgstr ""
msgid "GitHub import"
msgstr "GitHub 가져오기"
+msgid "GitLab"
+msgstr ""
+
msgid "GitLab / Unsubscribe"
msgstr ""
-msgid "GitLab Enterprise Edition %{plan}"
+msgid "GitLab API"
+msgstr ""
+
+msgid "GitLab Billing Team."
msgstr ""
msgid "GitLab Group Runners can execute code for all the projects in this group."
@@ -11525,12 +11869,18 @@ msgstr "GitLab 가져오기"
msgid "GitLab Issue"
msgstr ""
+msgid "GitLab Pages"
+msgstr ""
+
msgid "GitLab Service Desk is a simple way to allow people to create issues in your GitLab instance without needing their own user account. It provides a unique email address for end users to create issues in a project, and replies can be sent either through the GitLab interface or by email. End users will only see the thread through email."
msgstr ""
msgid "GitLab Shared Runners execute code of different projects on the same Runner unless you configure GitLab Runner Autoscale with MaxBuilds 1 (which it is on GitLab.com)."
msgstr ""
+msgid "GitLab Shell"
+msgstr ""
+
msgid "GitLab Support Bot"
msgstr ""
@@ -11540,7 +11890,7 @@ msgstr ""
msgid "GitLab User"
msgstr "GitLab 사용ìž"
-msgid "GitLab allows you to continue using your license even if you exceed the number of seats you purchased. You will be required to pay for these seats when you renew your license."
+msgid "GitLab Workhorse"
msgstr ""
msgid "GitLab commit"
@@ -11708,6 +12058,21 @@ msgstr "Gitea 가져오기"
msgid "Gitlab Pages"
msgstr ""
+msgid "Gitpod"
+msgstr ""
+
+msgid "Gitpod|Add the URL to your Gitpod instance configured to read your GitLab projects."
+msgstr ""
+
+msgid "Gitpod|Enable Gitpod integration"
+msgstr ""
+
+msgid "Gitpod|Gitpod URL"
+msgstr ""
+
+msgid "Gitpod|e.g. https://gitpod.example.com"
+msgstr ""
+
msgid "Given access %{time_ago}"
msgstr "%{time_ago} ì „ 엑세스 권한 부여ë¨"
@@ -12215,9 +12580,6 @@ msgstr ""
msgid "GroupSAML|Valid SAML Response"
msgstr ""
-msgid "GroupSAML|With group managed accounts enabled, all the users without a group managed account will be excluded from the group."
-msgstr ""
-
msgid "GroupSAML|With prohibit outer forks flag enabled group members will be able to fork project only inside your group."
msgstr ""
@@ -12431,10 +12793,10 @@ msgstr ""
msgid "GroupsNew|Create group"
msgstr ""
-msgid "GroupsNew|GitLab group export"
+msgid "GroupsNew|Import"
msgstr ""
-msgid "GroupsNew|Import"
+msgid "GroupsNew|Import a GitLab group export file"
msgstr ""
msgid "GroupsNew|Import group"
@@ -12576,6 +12938,9 @@ msgid "Hide chart"
msgid_plural "Hide charts"
msgstr[0] ""
+msgid "Hide comments on this file"
+msgstr ""
+
msgid "Hide details"
msgstr ""
@@ -12619,6 +12984,15 @@ msgstr ""
msgid "Highest role:"
msgstr ""
+msgid "HighlightBar|Alert events:"
+msgstr ""
+
+msgid "HighlightBar|Alert start time:"
+msgstr ""
+
+msgid "HighlightBar|Original alert:"
+msgstr ""
+
msgid "History"
msgstr "ì´ë ¥"
@@ -12796,6 +13170,9 @@ msgstr ""
msgid "If enabled, access to projects will be validated on an external service using their classification label."
msgstr ""
+msgid "If the number of active users exceeds the user limit, you will be charged for the number of %{users_over_license_link} at your next license reconciliation."
+msgstr ""
+
msgid "If there is no previous license or if the previous license has expired, some GitLab functionality will be blocked until a new, valid license is uploaded."
msgstr ""
@@ -12835,9 +13212,6 @@ msgstr ""
msgid "If your HTTP repository is not publicly accessible, add your credentials."
msgstr ""
-msgid "Iglu registry URL (optional)"
-msgstr ""
-
msgid "Ignore"
msgstr ""
@@ -12874,6 +13248,14 @@ msgstr ""
msgid "Import"
msgstr "가져오기"
+msgid "Import %d compatible repository"
+msgid_plural "Import %d compatible repositories"
+msgstr[0] ""
+
+msgid "Import %d repository"
+msgid_plural "Import %d repositories"
+msgstr[0] ""
+
msgid "Import CSV"
msgstr "CSV 가져오기"
@@ -12883,15 +13265,9 @@ msgstr "Giteaì—ì„œ 프로ì íŠ¸ 가져오기"
msgid "Import all compatible projects"
msgstr "호환ë˜ëŠ” 모든 프로ì íŠ¸ 가져오기"
-msgid "Import all compatible repositories"
-msgstr ""
-
msgid "Import all projects"
msgstr "모든 프로ì íŠ¸ 가져오기"
-msgid "Import all repositories"
-msgstr "모든 저장소 가져오기"
-
msgid "Import an exported GitLab project"
msgstr "내보낸 GitLab 프로ì íŠ¸ 가져오기"
@@ -12979,6 +13355,9 @@ msgstr ""
msgid "ImportProjects|Error importing repository %{project_safe_import_url} into %{project_full_path} - %{message}"
msgstr ""
+msgid "ImportProjects|Import repositories"
+msgstr ""
+
msgid "ImportProjects|Importing the project failed"
msgstr ""
@@ -12991,7 +13370,7 @@ msgstr ""
msgid "ImportProjects|Requesting your %{provider} repositories failed"
msgstr ""
-msgid "ImportProjects|Select the projects you want to import"
+msgid "ImportProjects|Select the repositories you want to import"
msgstr ""
msgid "ImportProjects|The remote data could not be imported."
@@ -13027,9 +13406,6 @@ msgstr ""
msgid "In order to enable Service Desk for your instance, you must first set up incoming email."
msgstr ""
-msgid "In order to gather accurate feature usage data, it can take 1 to 2 weeks to see your index."
-msgstr ""
-
msgid "In order to personalize your experience with GitLab%{br_tag}we would like to know a bit more about you."
msgstr ""
@@ -13060,18 +13436,30 @@ msgstr ""
msgid "IncidentManagement|Create incident"
msgstr ""
+msgid "IncidentManagement|Critical - S1"
+msgstr ""
+
msgid "IncidentManagement|Date created"
msgstr ""
msgid "IncidentManagement|Display your incidents in a dedicated view"
msgstr ""
+msgid "IncidentManagement|High - S2"
+msgstr ""
+
msgid "IncidentManagement|Incident"
msgstr ""
msgid "IncidentManagement|Incidents"
msgstr ""
+msgid "IncidentManagement|Low - S4"
+msgstr ""
+
+msgid "IncidentManagement|Medium - S3"
+msgstr ""
+
msgid "IncidentManagement|No incidents to display."
msgstr ""
@@ -13084,6 +13472,9 @@ msgstr ""
msgid "IncidentManagement|Published to status page"
msgstr ""
+msgid "IncidentManagement|Severity"
+msgstr ""
+
msgid "IncidentManagement|There are no closed incidents"
msgstr ""
@@ -13093,6 +13484,9 @@ msgstr ""
msgid "IncidentManagement|Unassigned"
msgstr ""
+msgid "IncidentManagement|Unknown"
+msgstr ""
+
msgid "IncidentManagement|Unpublished"
msgstr ""
@@ -13114,6 +13508,15 @@ msgstr ""
msgid "Incidents"
msgstr ""
+msgid "Incident|Alert details"
+msgstr ""
+
+msgid "Incident|Summary"
+msgstr ""
+
+msgid "Incident|There was an issue loading alert data. Please try again."
+msgstr ""
+
msgid "Include a Terms of Service agreement and Privacy Policy that all users must accept."
msgstr "모든 사용ìžê°€ 수ë½í•´ì•¼ 하는 서비스 약관 ë° ê°œì¸ ì •ë³´ 보호 ì •ì±…ì„ í¬í•¨í•©ë‹ˆë‹¤."
@@ -13174,6 +13577,9 @@ msgstr ""
msgid "Information about additional Pages templates and how to install them can be found in our %{pages_getting_started_guide}."
msgstr ""
+msgid "Inherited"
+msgstr ""
+
msgid "Inherited:"
msgstr ""
@@ -13253,7 +13659,22 @@ msgstr ""
msgid "Instance administrators group already exists"
msgstr ""
-msgid "Instance license"
+msgid "InstanceStatistics|Groups"
+msgstr ""
+
+msgid "InstanceStatistics|Issues"
+msgstr ""
+
+msgid "InstanceStatistics|Merge Requests"
+msgstr ""
+
+msgid "InstanceStatistics|Pipelines"
+msgstr ""
+
+msgid "InstanceStatistics|Projects"
+msgstr ""
+
+msgid "InstanceStatistics|Users"
msgstr ""
msgid "Integration"
@@ -13265,6 +13686,12 @@ msgstr ""
msgid "Integrations"
msgstr "ì—°ë™"
+msgid "Integrations|%{integration} settings saved and active."
+msgstr ""
+
+msgid "Integrations|%{integration} settings saved, but not active."
+msgstr ""
+
msgid "Integrations|All details"
msgstr ""
@@ -13274,6 +13701,12 @@ msgstr ""
msgid "Integrations|Comment settings:"
msgstr ""
+msgid "Integrations|Connection failed. Please check your settings."
+msgstr ""
+
+msgid "Integrations|Connection successful."
+msgstr ""
+
msgid "Integrations|Default settings are inherited from the group level."
msgstr ""
@@ -13289,6 +13722,15 @@ msgstr ""
msgid "Integrations|Includes commit title and branch"
msgstr ""
+msgid "Integrations|Projects using custom settings will not be impacted unless the project owner chooses to use instance-level defaults."
+msgstr ""
+
+msgid "Integrations|Save settings?"
+msgstr ""
+
+msgid "Integrations|Saving will update the default settings for all projects that are not using custom settings."
+msgstr ""
+
msgid "Integrations|Standard"
msgstr ""
@@ -13421,6 +13863,9 @@ msgstr ""
msgid "Invitation"
msgstr "초대"
+msgid "Invitation declined"
+msgstr ""
+
msgid "Invite"
msgstr "초대"
@@ -13472,6 +13917,42 @@ 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|%{linkStart}Read more%{linkEnd} about role permissions"
+msgstr ""
+
+msgid "InviteMembersModal|Access expiration date (optional)"
+msgstr ""
+
+msgid "InviteMembersModal|Cancel"
+msgstr ""
+
+msgid "InviteMembersModal|Choose a role permission"
+msgstr ""
+
+msgid "InviteMembersModal|GitLab member or Email address"
+msgstr ""
+
+msgid "InviteMembersModal|Invite"
+msgstr ""
+
+msgid "InviteMembersModal|Invite team members"
+msgstr ""
+
+msgid "InviteMembersModal|Search for members to invite"
+msgstr ""
+
+msgid "InviteMembersModal|User not invited. Feature coming soon!"
+msgstr ""
+
+msgid "InviteMembersModal|Users were succesfully added"
+msgstr ""
+
+msgid "InviteMembersModal|You're inviting members to the %{group_name} group"
+msgstr ""
+
+msgid "InviteMembers|Invite team members"
+msgstr ""
+
msgid "Invited"
msgstr ""
@@ -13526,10 +14007,13 @@ msgstr ""
msgid "Issue cannot be found."
msgstr ""
+msgid "Issue created from vulnerability %{vulnerability_link}"
+msgstr ""
+
msgid "Issue events"
msgstr "ì´ìŠˆ ì´ë²¤íŠ¸"
-msgid "Issue first depoloyed to production"
+msgid "Issue first deployed to production"
msgstr ""
msgid "Issue label"
@@ -13607,6 +14091,9 @@ msgstr ""
msgid "IssueTracker|Custom issue tracker"
msgstr ""
+msgid "IssueTracker|EWM work items tracker"
+msgstr ""
+
msgid "IssueTracker|Redmine issue tracker"
msgstr ""
@@ -13673,6 +14160,9 @@ msgstr ""
msgid "It looks like you have some draft commits in this branch."
msgstr ""
+msgid "It may be several days before you see feature usage data."
+msgstr ""
+
msgid "It must have a header row and at least two columns: the first column is the issue title and the second column is the issue description. The separator is automatically detected."
msgstr ""
@@ -13955,15 +14445,15 @@ msgstr ""
msgid "Join Zoom meeting"
msgstr ""
+msgid "Joined %{time_ago}"
+msgstr ""
+
msgid "Jul"
msgstr "7ì›”"
msgid "July"
msgstr "7ì›”"
-msgid "Jump to first unresolved thread"
-msgstr ""
-
msgid "Jump to next unresolved thread"
msgstr ""
@@ -13997,6 +14487,9 @@ msgstr ""
msgid "Keyboard shortcuts"
msgstr ""
+msgid "KeyboardKey|Ctrl+"
+msgstr ""
+
msgid "Keys"
msgstr ""
@@ -14045,6 +14538,9 @@ msgstr ""
msgid "LDAP Synchronization"
msgstr ""
+msgid "LDAP group settings"
+msgstr ""
+
msgid "LDAP settings"
msgstr ""
@@ -14054,6 +14550,9 @@ msgstr ""
msgid "LDAP sync in progress. This could take a few minutes. Refresh the page to see the changes."
msgstr ""
+msgid "LDAP synchronizations"
+msgstr ""
+
msgid "LFS"
msgstr "LFS"
@@ -14133,7 +14632,16 @@ msgid "Last %d day"
msgid_plural "Last %d days"
msgstr[0] "최근 %d ì¼"
-msgid "Last %{days} days"
+msgid "Last 2 weeks"
+msgstr ""
+
+msgid "Last 30 days"
+msgstr ""
+
+msgid "Last 60 days"
+msgstr ""
+
+msgid "Last 90 days"
msgstr ""
msgid "Last Accessed On"
@@ -14211,6 +14719,9 @@ msgstr ""
msgid "Last used on:"
msgstr ""
+msgid "Last week"
+msgstr ""
+
msgid "LastCommit|authored"
msgstr ""
@@ -14226,6 +14737,9 @@ msgstr "최근 변경사항"
msgid "Latest pipeline for the most recent commit on this branch"
msgstr ""
+msgid "Launch a ready-to-code development environment for your project."
+msgstr ""
+
msgid "Lead"
msgstr ""
@@ -14599,6 +15113,9 @@ msgstr "사용 가능한 저장소 목ë¡"
msgid "List of all merge commits"
msgstr ""
+msgid "List options"
+msgstr ""
+
msgid "List settings"
msgstr ""
@@ -14611,9 +15128,6 @@ msgstr "ëª©ë¡ ë³´ê¸°"
msgid "List your Bitbucket Server repositories"
msgstr "Bitbucket Server 저장소 목ë¡"
-msgid "Lists"
-msgstr ""
-
msgid "Live preview"
msgstr "실시간 미리보기"
@@ -14860,6 +15374,12 @@ msgstr ""
msgid "Mark as done"
msgstr ""
+msgid "Mark as draft"
+msgstr ""
+
+msgid "Mark as ready"
+msgstr ""
+
msgid "Mark as resolved"
msgstr ""
@@ -14881,6 +15401,24 @@ msgstr "마í¬ë‹¤ìš´ 활성화ë¨"
msgid "Markdown is supported"
msgstr ""
+msgid "MarkdownEditor|Add a link (%{modifierKey}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add a link (%{modifier_key}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifierKey}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifier_key}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifierKey}I)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifier_key}I)"
+msgstr ""
+
msgid "Marked For Deletion At - %{deletion_time}"
msgstr ""
@@ -14965,7 +15503,25 @@ msgstr ""
msgid "Max access level"
msgstr "최대 액세스 수준"
-msgid "Max seats used"
+msgid "Max role"
+msgstr ""
+
+msgid "Max size 15 MB"
+msgstr ""
+
+msgid "Maximum Conan package file size in bytes"
+msgstr ""
+
+msgid "Maximum Maven package file size in bytes"
+msgstr ""
+
+msgid "Maximum NPM package file size in bytes"
+msgstr ""
+
+msgid "Maximum NuGet package file size in bytes"
+msgstr ""
+
+msgid "Maximum PyPI package file size in bytes"
msgstr ""
msgid "Maximum Users:"
@@ -15097,6 +15653,18 @@ msgstr ""
msgid "Members with access to %{strong_start}%{group_name}%{strong_end}"
msgstr ""
+msgid "Members|%{time} by %{user}"
+msgstr ""
+
+msgid "Members|Expired"
+msgstr ""
+
+msgid "Members|No expiration set"
+msgstr ""
+
+msgid "Members|in %{time}"
+msgstr ""
+
msgid "Memory Usage"
msgstr ""
@@ -15283,9 +15851,6 @@ msgstr ""
msgid "MergeRequests|Thread will be unresolved"
msgstr ""
-msgid "MergeRequests|Toggle comments for this file"
-msgstr "ì´ íŒŒì¼ì— 대한 설명 전환"
-
msgid "MergeRequests|View file @ %{commitId}"
msgstr "íŒŒì¼ ë³´ê¸° @ %{commitId}"
@@ -15346,6 +15911,9 @@ msgstr ""
msgid "Merging immediately isn't recommended as it may negatively impact the existing merge train. Read the %{docsLinkStart}documentation%{docsLinkEnd} for more information."
msgstr ""
+msgid "Message"
+msgstr ""
+
msgid "Messages"
msgstr "메시지"
@@ -15729,18 +16297,12 @@ msgid "Milestone"
msgid_plural "Milestones"
msgstr[0] ""
-msgid "Milestone does not support burnup charts"
-msgstr ""
-
msgid "Milestone lists not available with your current license"
msgstr "현재 ë¼ì´ì„¼ìŠ¤ì—서는 마ì¼ìŠ¤í†¤ 목ë¡ì„ 사용할 수 없습니다."
msgid "Milestone lists show all issues from the selected milestone."
msgstr "마ì¼ìŠ¤í†¤ 목ë¡ì—는 ì„ íƒí•œ 마ì¼ìŠ¤í†¤ì˜ 모든 문제가 표시ë©ë‹ˆë‹¤."
-msgid "Milestone must have a start and due date"
-msgstr ""
-
msgid "MilestoneSidebar|Closed:"
msgstr ""
@@ -16107,6 +16669,9 @@ msgstr "ì´ë¦„:"
msgid "Namespace"
msgstr ""
+msgid "Namespace ID:"
+msgstr ""
+
msgid "Namespace is empty"
msgstr ""
@@ -16191,6 +16756,9 @@ msgstr ""
msgid "NetworkPolicies|Allow all outbound traffic from %{selector} to %{ruleSelector} on %{ports}"
msgstr ""
+msgid "NetworkPolicies|Are you sure you want to delete this policy? This action cannot be undone."
+msgstr ""
+
msgid "NetworkPolicies|Choose whether to enforce this policy."
msgstr ""
@@ -16200,12 +16768,21 @@ msgstr ""
msgid "NetworkPolicies|Define this policy's location, conditions and actions."
msgstr ""
+msgid "NetworkPolicies|Delete policy"
+msgstr ""
+
+msgid "NetworkPolicies|Delete policy: %{policy}"
+msgstr ""
+
msgid "NetworkPolicies|Deny all traffic"
msgstr ""
msgid "NetworkPolicies|Description"
msgstr ""
+msgid "NetworkPolicies|Edit policy"
+msgstr ""
+
msgid "NetworkPolicies|Editor mode"
msgstr ""
@@ -16233,6 +16810,9 @@ msgstr ""
msgid "NetworkPolicies|Name"
msgstr ""
+msgid "NetworkPolicies|Namespace"
+msgstr ""
+
msgid "NetworkPolicies|Network Policy"
msgstr ""
@@ -16284,6 +16864,9 @@ msgstr ""
msgid "NetworkPolicies|Rules"
msgstr ""
+msgid "NetworkPolicies|Save changes"
+msgstr ""
+
msgid "NetworkPolicies|Something went wrong, failed to update policy"
msgstr ""
@@ -16296,6 +16879,9 @@ msgstr ""
msgid "NetworkPolicies|Traffic that does not match any rule will be blocked."
msgstr ""
+msgid "NetworkPolicies|Unable to parse policy"
+msgstr ""
+
msgid "NetworkPolicies|YAML editor"
msgstr ""
@@ -16408,6 +16994,9 @@ msgstr ""
msgid "New Snippet"
msgstr "새 스니펫"
+msgid "New Test Case"
+msgstr ""
+
msgid "New User"
msgstr ""
@@ -16507,6 +17096,9 @@ msgstr "새 서브그룹"
msgid "New tag"
msgstr "새 태그 "
+msgid "New test case"
+msgstr ""
+
msgid "New users set to external"
msgstr ""
@@ -16579,7 +17171,7 @@ msgstr "브랜치가 존재하지 않습니다."
msgid "No changes"
msgstr "변경 사항 ì—†ìŒ"
-msgid "No changes between %{ref_start}%{source_branch}%{ref_end} and %{ref_start}%{target_branch}%{ref_end}"
+msgid "No changes between %{sourceBranch} and %{targetBranch}"
msgstr ""
msgid "No child epics match applied filters"
@@ -16594,6 +17186,9 @@ msgstr "Gitaly Serverì— ì—°ê²°í•  수 없습니다. 로그를 확ì¸í•˜ì‹­ì‹œì˜
msgid "No containers available"
msgstr ""
+msgid "No content to show"
+msgstr ""
+
msgid "No contributions"
msgstr ""
@@ -16669,9 +17264,6 @@ msgstr "그런 ì´ë¦„ ë˜ëŠ” 설명ì´ìžˆëŠ” ë ˆì´ë¸”ì´ ì—†ìŠµë‹ˆë‹¤."
msgid "No license. All rights reserved"
msgstr "ë¼ì´ì„¼ìŠ¤ê°€ 없습니다. All rights reserved"
-msgid "No licenses found."
-msgstr ""
-
msgid "No matches found"
msgstr ""
@@ -16684,6 +17276,9 @@ msgstr "ì¼ì¹˜í•˜ëŠ” 결과가 없습니다."
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No members found"
+msgstr ""
+
msgid "No merge requests found"
msgstr "머지 리퀘스트(MR)를 ì°¾ì„ ìˆ˜ 없습니다."
@@ -16705,6 +17300,9 @@ msgstr ""
msgid "No parent group"
msgstr ""
+msgid "No plan"
+msgstr ""
+
msgid "No pods available"
msgstr ""
@@ -16801,6 +17399,12 @@ msgstr "ì—†ìŒ"
msgid "Not Implemented"
msgstr ""
+msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+msgstr ""
+
+msgid "Not all browsers support WebAuthn. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even from an unsupported browser."
+msgstr ""
+
msgid "Not all data has been processed yet, the accuracy of the chart for the selected timeframe is limited."
msgstr ""
@@ -16897,6 +17501,9 @@ msgstr "알림 설정 - %{notification_title}"
msgid "Notification settings saved"
msgstr ""
+msgid "NotificationEvent|Change reviewer merge request"
+msgstr ""
+
msgid "NotificationEvent|Close issue"
msgstr "ì´ìŠˆ 닫기"
@@ -17059,10 +17666,7 @@ msgstr ""
msgid "On track"
msgstr ""
-msgid "OnDemandScans|Attached branch"
-msgstr ""
-
-msgid "OnDemandScans|Attached branch is where the scan job runs."
+msgid "OnDemandScans|Could not fetch scanner profiles. Please refresh the page, or try again later."
msgstr ""
msgid "OnDemandScans|Could not fetch site profiles. Please refresh the page, or try again later."
@@ -17071,6 +17675,9 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
+msgid "OnDemandScans|Create a new scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Create a new site profile"
msgstr ""
@@ -17083,6 +17690,9 @@ msgstr ""
msgid "OnDemandScans|New on-demand DAST scan"
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 ""
@@ -17092,16 +17702,10 @@ msgstr ""
msgid "OnDemandScans|On-demand scans run outside the DevOps cycle and find vulnerabilities in your projects. %{learnMoreLinkStart}Learn more%{learnMoreLinkEnd}"
msgstr ""
-msgid "OnDemandScans|Only a passive scan can be performed on demand."
-msgstr ""
-
-msgid "OnDemandScans|Passive"
-msgstr ""
-
msgid "OnDemandScans|Run scan"
msgstr ""
-msgid "OnDemandScans|Scan mode"
+msgid "OnDemandScans|Scanner profile"
msgstr ""
msgid "OnDemandScans|Scanner settings"
@@ -17113,9 +17717,15 @@ msgstr ""
msgid "OnDemandScans|Select one of the existing profiles"
msgstr ""
+msgid "OnDemandScans|Site profile"
+msgstr ""
+
msgid "OnDemandScans|Site profiles"
msgstr ""
+msgid "OnDemandScans|Use existing scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Use existing site profile"
msgstr ""
@@ -17213,9 +17823,6 @@ msgstr "열기"
msgid "Open Selection"
msgstr ""
-msgid "Open Web IDE"
-msgstr ""
-
msgid "Open comment type dropdown"
msgstr ""
@@ -17321,6 +17928,9 @@ msgstr ""
msgid "Origin"
msgstr ""
+msgid "Orphaned member"
+msgstr ""
+
msgid "Other Labels"
msgstr "기타 ë¼ë²¨"
@@ -17336,6 +17946,9 @@ msgstr ""
msgid "Other visibility settings have been disabled by the administrator."
msgstr ""
+msgid "Our documentation includes an example DevOps Score report."
+msgstr ""
+
msgid "Out-of-compliance with this project's policies and should be removed"
msgstr ""
@@ -17360,6 +17973,9 @@ msgstr "개요"
msgid "Overwrite diverged branches"
msgstr ""
+msgid "Owned by %{image_tag}"
+msgstr ""
+
msgid "Owned by anyone"
msgstr ""
@@ -17381,6 +17997,9 @@ msgstr ""
msgid "Package deleted successfully"
msgstr ""
+msgid "Package file size limits"
+msgstr ""
+
msgid "Package recipe already exists"
msgstr ""
@@ -17396,9 +18015,6 @@ msgstr ""
msgid "Package type must be PyPi"
msgstr ""
-msgid "Package was removed"
-msgstr "패키지가 제거ë˜ì—ˆìŠµë‹ˆë‹¤."
-
msgid "PackageRegistry|%{name} version %{version} was created %{datetime}"
msgstr ""
@@ -17540,12 +18156,18 @@ msgstr ""
msgid "PackageRegistry|NuGet Command"
msgstr ""
+msgid "PackageRegistry|Package Registry"
+msgstr ""
+
msgid "PackageRegistry|Pip Command"
msgstr ""
msgid "PackageRegistry|Pipeline %{link} triggered %{datetime} by %{author}"
msgstr ""
+msgid "PackageRegistry|Publish and share packages for a variety of common package managers. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "PackageRegistry|Published to the %{project} Package Registry %{datetime}"
msgstr ""
@@ -17645,6 +18267,9 @@ msgstr ""
msgid "Page not found"
msgstr ""
+msgid "Page settings"
+msgstr ""
+
msgid "Page was successfully deleted"
msgstr ""
@@ -17786,7 +18411,7 @@ msgstr ""
msgid "Paste issue link"
msgstr ""
-msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Don't use your private SSH key."
+msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Do not paste your private SSH key, as that can compromise your identity."
msgstr ""
msgid "Patch to apply"
@@ -17813,6 +18438,9 @@ msgstr "ì¼ì‹œì •ì§€ëœ 러너는 새로운 ìž‘ì—…ì„ í—ˆìš©í•˜ì§€ 않습니다.
msgid "Pending"
msgstr "대기중"
+msgid "Pending comments"
+msgstr ""
+
msgid "People without permission will never get a notification and won't be able to comment."
msgstr ""
@@ -18011,6 +18639,9 @@ msgstr ""
msgid "Pipelines|Build with confidence"
msgstr "ìžì‹ ìžˆê²Œ 빌드하세요"
+msgid "Pipelines|By revoking a trigger you will break any processes making use of it. Are you sure?"
+msgstr ""
+
msgid "Pipelines|CI Lint"
msgstr "CI Lint"
@@ -18023,6 +18654,15 @@ msgstr "Runner ìºì‹œ 정리"
msgid "Pipelines|Continuous Integration can help catch bugs by running your tests automatically, while Continuous Deployment can help you deliver code to your product environment."
msgstr ""
+msgid "Pipelines|Copy trigger token"
+msgstr ""
+
+msgid "Pipelines|Description"
+msgstr ""
+
+msgid "Pipelines|Edit"
+msgstr ""
+
msgid "Pipelines|Get started with Pipelines"
msgstr "파ì´í”„ ë¼ì¸ìœ¼ë¡œ 시작하기"
@@ -18038,15 +18678,27 @@ msgstr ""
msgid "Pipelines|It is recommended the code is reviewed thoroughly before running this pipeline with the parent project's CI resource."
msgstr ""
+msgid "Pipelines|Last Used"
+msgstr ""
+
msgid "Pipelines|Loading Pipelines"
msgstr "파ì´í”„ë¼ì¸ 로딩중"
msgid "Pipelines|More Information"
msgstr ""
+msgid "Pipelines|No triggers have been created yet. Add one using the form above."
+msgstr ""
+
+msgid "Pipelines|Owner"
+msgstr ""
+
msgid "Pipelines|Project cache successfully reset."
msgstr "프로ì íŠ¸ ìºì‹œê°€ 성공ì ìœ¼ë¡œ 재설정ë˜ì—ˆìŠµë‹ˆë‹¤."
+msgid "Pipelines|Revoke"
+msgstr ""
+
msgid "Pipelines|Run Pipeline"
msgstr "파ì´í”„ë¼ì¸ 실행"
@@ -18071,6 +18723,15 @@ msgstr ""
msgid "Pipelines|This project is not currently set up to run pipelines."
msgstr "ì´ í”„ë¡œì íŠ¸ëŠ” 현재 파ì´í”„ë¼ì¸ì„ 실행하ë„ë¡ ì„¤ì •ë˜ì§€ 않았습니다."
+msgid "Pipelines|Token"
+msgstr ""
+
+msgid "Pipelines|Trigger user has insufficient permissions to project"
+msgstr ""
+
+msgid "Pipelines|invalid"
+msgstr ""
+
msgid "Pipelines|parent"
msgstr ""
@@ -18329,10 +18990,10 @@ msgstr ""
msgid "Please provide attributes to update"
msgstr ""
-msgid "Please refer to %{docs_url}"
+msgid "Please reach out if you have any questions and we'll be happy to assist."
msgstr ""
-msgid "Please retype the email address."
+msgid "Please refer to %{docs_url}"
msgstr ""
msgid "Please select"
@@ -18362,6 +19023,9 @@ msgstr "결과를 보려면 최소 í•˜ë‚˜ì˜ í•„í„°ë¥¼ ì„ íƒí•˜ì‹­ì‹œì˜¤"
msgid "Please set a new password before proceeding."
msgstr "계ì†í•˜ê¸° ì „ì— ìƒˆ 비밀번호를 설정해주세요."
+msgid "Please share your feedback about %{featureName} %{linkStart}in this issue%{linkEnd} to help us improve the experience."
+msgstr ""
+
msgid "Please solve the reCAPTCHA"
msgstr "ReCAPTCHA를 풀어 주십시오."
@@ -18665,6 +19329,9 @@ msgstr "%{yourAccount}를 ì˜êµ¬ì ìœ¼ë¡œ 삭제하려고 합니다. ì´ìŠˆ, 머
msgid "Profiles| You are going to change the username %{currentUsernameBold} to %{newUsernameBold}. Profile and projects will be redirected to the %{newUsername} namespace but this redirect will expire once the %{currentUsername} namespace is registered by another user or group. Please update your Git repository remotes as soon as possible."
msgstr "ì‚¬ìš©ìž ì´ë¦„ì„ %{currentUsernameBold}ì—ì„œ %{newUsernameBold}으로 변경하려고 합니다. 기존 프로필과 프로ì íŠ¸ë“¤ì€ %{newUsername}으로 리디렉션ë˜ì§€ë§Œ, %{currentUsername}ê°€ 다른 유저나 ê·¸ë£¹ì— ì˜í•´ 등ë¡ë˜ë©´ ë” ì´ìƒ 리디렉션ë˜ì§€ 않습니다. ì‚¬ìš©ìž ì´ë¦„ì„ ë³€ê²½í•œ ë’¤ git ì €ìž¥ì†Œì˜ ë¦¬ëª¨íŠ¸ë¥¼ 변경하세요."
+msgid "Profiles|%{provider} Active"
+msgstr ""
+
msgid "Profiles|@username"
msgstr "@사용ìžì´ë¦„"
@@ -18716,8 +19383,8 @@ msgstr "ì•„ì´ì½˜ì„ í´ë¦­í•˜ì—¬ 아래 서비스를 ì´ìš©í•œ 로그ì¸ì„ 활
msgid "Profiles|Commit email"
msgstr "커밋 ì´ë©”ì¼"
-msgid "Profiles|Connect"
-msgstr "ì—°ê²°"
+msgid "Profiles|Connect %{provider}"
+msgstr ""
msgid "Profiles|Connected Accounts"
msgstr "ì—°ê²°ëœ ê³„ì •"
@@ -18740,6 +19407,9 @@ msgstr "ê³„ì •ì„ ì‚­ì œí•˜ë©´ 다ìŒê³¼ ê°™ì€ ì˜í–¥ì´ 있습니다:"
msgid "Profiles|Disconnect"
msgstr "연결 해제"
+msgid "Profiles|Disconnect %{provider}"
+msgstr ""
+
msgid "Profiles|Do not show on profile"
msgstr "í”„ë¡œí•„ì— í‘œì‹œí•˜ì§€ ì•ŠìŒ"
@@ -18764,7 +19434,7 @@ msgstr "피드 토í°ì´ 성공ì ìœ¼ë¡œ 초기화ë˜ì—ˆìŠµë‹ˆë‹¤."
msgid "Profiles|Full name"
msgstr "ì´ë¦„"
-msgid "Profiles|Give your individual key a title. This will be publically visible."
+msgid "Profiles|Give your individual key a title."
msgstr ""
msgid "Profiles|Include private contributions on my profile"
@@ -18854,8 +19524,8 @@ msgstr ""
msgid "Profiles|The maximum file size allowed is 200KB."
msgstr "최대 허용ë˜ëŠ” 파ì¼ì˜ í¬ê¸°ëŠ” 200KB입니다."
-msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it?"
-msgstr "ì´ê²ƒì€ 공개 SSH 키가 아닌것 같습니다. ì •ë§ë¡œ 추가 하시겠어요?"
+msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it? It will be publicly visible."
+msgstr ""
msgid "Profiles|This email will be displayed on your public profile"
msgstr "ì´ ì´ë©”ì¼ì€ ë‚´ 공개 í”„ë¡œí•„ì— í‘œì‹œë©ë‹ˆë‹¤."
@@ -18929,6 +19599,9 @@ msgstr "ì´ê³³ì— 아바타를 업로드하거나 %{gravatar_link}ì—ì„œ 변경í
msgid "Profiles|You don't have access to delete this user."
msgstr "ì´ ì‚¬ìš©ìžë¥¼ 삭제할 ê¶Œí•œì´ ì—†ìŠµë‹ˆë‹¤."
+msgid "Profiles|You must transfer ownership or delete groups you are an owner of before you can delete your account"
+msgstr ""
+
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr "ë‹¹ì‹ ì˜ ê³„ì •ì„ ì‚­ì œí•˜ê¸° ì „ì— ì´ ê·¸ë£¹ë“¤ì˜ ì†Œìœ ê¶Œì„ ì´ì „하거나 삭제해야합니다."
@@ -19517,6 +20190,9 @@ msgstr ""
msgid "ProjectTemplates|GitLab Cluster Management"
msgstr ""
+msgid "ProjectTemplates|Gitpod/Spring Petclinic"
+msgstr ""
+
msgid "ProjectTemplates|Go Micro"
msgstr ""
@@ -20126,6 +20802,9 @@ msgstr ""
msgid "Publish to status page"
msgstr ""
+msgid "Published"
+msgstr ""
+
msgid "Published on status page"
msgstr ""
@@ -20243,9 +20922,15 @@ msgstr "Quick actionì€ ì´ìŠˆ 설명ì´ë‚˜ 댓글 박스ì—ì„œ 사용 가능합
msgid "Quick range"
msgstr ""
+msgid "Quickly and easily edit multiple files in your project."
+msgstr ""
+
msgid "README"
msgstr "README"
+msgid "Rails"
+msgstr ""
+
msgid "Rake Tasks Help"
msgstr ""
@@ -20364,10 +21049,13 @@ msgstr "ë“±ë¡ / 로그ì¸"
msgid "Register Two-Factor Authenticator"
msgstr ""
-msgid "Register U2F device"
+msgid "Register Universal Two-Factor (U2F) Device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register WebAuthn Device"
+msgstr ""
+
+msgid "Register device"
msgstr ""
msgid "Register for GitLab"
@@ -20379,9 +21067,6 @@ msgstr ""
msgid "Register with two-factor app"
msgstr ""
-msgid "Registration"
-msgstr ""
-
msgid "Registration|Checkout"
msgstr ""
@@ -20497,9 +21182,6 @@ msgstr ""
msgid "Release|Something went wrong while saving the release details"
msgstr ""
-msgid "Remediated: needs review"
-msgstr ""
-
msgid "Remediations"
msgstr ""
@@ -20605,6 +21287,9 @@ msgstr ""
msgid "Remove priority"
msgstr "우선 순위 삭제"
+msgid "Remove report"
+msgstr ""
+
msgid "Remove secondary node"
msgstr ""
@@ -20617,6 +21302,12 @@ msgstr ""
msgid "Remove time estimate"
msgstr ""
+msgid "Remove user & report"
+msgstr ""
+
+msgid "Remove user from group"
+msgstr ""
+
msgid "Removed"
msgstr ""
@@ -20698,9 +21389,6 @@ msgstr ""
msgid "Removes time estimate."
msgstr ""
-msgid "Removing license…"
-msgstr ""
-
msgid "Removing this group also removes all child projects, including archived projects, and their resources."
msgstr ""
@@ -20785,6 +21473,9 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
+msgid "Reported by %{reporter}"
+msgstr ""
+
msgid "Reporting"
msgstr "ë³´ê³ "
@@ -20870,6 +21561,27 @@ msgstr "ë³€ê²½ëœ í…ŒìŠ¤íŠ¸ ê²°ê³¼ ì—†ìŒ"
msgid "Repositories"
msgstr ""
+msgid "Repositories Analytics"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download Historic Test Coverage Data"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download historic test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Historic Test Coverage Data is available in raw format (.csv) for further analysis."
+msgstr ""
+
+msgid "RepositoriesAnalytics|Test Code Coverage"
+msgstr ""
+
+msgid "RepositoriesAnalytics|There was an error fetching the projects."
+msgstr ""
+
msgid "Repository"
msgstr "저장소"
@@ -20948,9 +21660,15 @@ msgstr ""
msgid "Request parameter %{param} is missing."
msgstr ""
+msgid "Request review from"
+msgstr ""
+
msgid "Request to link SAML account must be authorized"
msgstr ""
+msgid "Requested"
+msgstr ""
+
msgid "Requested %{time_ago}"
msgstr ""
@@ -20969,6 +21687,9 @@ msgstr "요청 프로필"
msgid "Requests to these domain(s)/address(es) on the local network will be allowed when local requests from hooks and services are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 or 127.0.0.0/28 are supported. Domain wildcards are not supported currently. Use comma, semicolon, or newline to separate multiple entries. The allowlist can hold a maximum of 1000 entries. Domains should use IDNA encoding. Ex: example.com, 192.168.1.1, 127.0.0.0/28, xn--itlab-j1a.com."
msgstr ""
+msgid "Require admin approval for new sign-ups"
+msgstr ""
+
msgid "Require all users in this group to setup Two-factor authentication"
msgstr ""
@@ -21094,9 +21815,6 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
-msgid "Resolved by %{resolvedByName}"
-msgstr ""
-
msgid "Resolves IP addresses once and uses them to submit requests"
msgstr ""
@@ -21215,6 +21933,13 @@ msgstr ""
msgid "ReviewApp|Enable Review App"
msgstr ""
+msgid "Reviewer"
+msgid_plural "%d Reviewers"
+msgstr[0] ""
+
+msgid "Reviewer(s)"
+msgstr ""
+
msgid "Reviewing"
msgstr "검토중"
@@ -21254,6 +21979,9 @@ msgstr ""
msgid "Rook"
msgstr ""
+msgid "Ruby"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -21332,6 +22060,63 @@ msgstr ""
msgid "Runners page."
msgstr "Runners 페ì´ì§€."
+msgid "Runners|Active"
+msgstr ""
+
+msgid "Runners|Architecture"
+msgstr ""
+
+msgid "Runners|Can run untagged jobs"
+msgstr ""
+
+msgid "Runners|Description"
+msgstr ""
+
+msgid "Runners|Group"
+msgstr ""
+
+msgid "Runners|IP Address"
+msgstr ""
+
+msgid "Runners|Last contact"
+msgstr ""
+
+msgid "Runners|Locked to this project"
+msgstr ""
+
+msgid "Runners|Maximum job timeout"
+msgstr ""
+
+msgid "Runners|Name"
+msgstr ""
+
+msgid "Runners|Platform"
+msgstr ""
+
+msgid "Runners|Property Name"
+msgstr ""
+
+msgid "Runners|Protected"
+msgstr ""
+
+msgid "Runners|Revision"
+msgstr ""
+
+msgid "Runners|Shared"
+msgstr ""
+
+msgid "Runners|Specific"
+msgstr ""
+
+msgid "Runners|Tags"
+msgstr ""
+
+msgid "Runners|Value"
+msgstr ""
+
+msgid "Runners|Version"
+msgstr ""
+
msgid "Runners|You have used %{quotaUsed} out of %{quotaLimit} of your shared Runners pipeline minutes."
msgstr ""
@@ -21344,6 +22129,9 @@ msgstr ""
msgid "Runs a number of housekeeping tasks within the current repository, such as compressing file revisions and removing unreachable objects."
msgstr ""
+msgid "SAML"
+msgstr ""
+
msgid "SAML SSO"
msgstr "SAML SSO"
@@ -21395,6 +22183,9 @@ msgstr "토요ì¼"
msgid "Save"
msgstr "저장"
+msgid "Save %{name} size limits"
+msgstr ""
+
msgid "Save Changes"
msgstr ""
@@ -21425,9 +22216,6 @@ msgstr "파ì´í”„ë¼ì¸ 스케줄 저장"
msgid "Save space and find tags in the Container Registry more easily. Enable the cleanup policy to remove stale tags and keep only the ones you need."
msgstr ""
-msgid "Save template"
-msgstr ""
-
msgid "Save variables"
msgstr "변수 저장"
@@ -21470,9 +22258,6 @@ msgstr "파ì´í”„ë¼ì¸ 스케줄ë§"
msgid "Scope"
msgstr "스코프"
-msgid "Scope not supported with disabled 'users_search' feature!"
-msgstr ""
-
msgid "Scoped issue boards"
msgstr ""
@@ -21599,9 +22384,6 @@ msgstr ""
msgid "Search requirements"
msgstr ""
-msgid "Search results…"
-msgstr ""
-
msgid "Search users"
msgstr "ì‚¬ìš©ìž ê²€ìƒ‰"
@@ -21671,6 +22453,10 @@ msgid "SearchResults|commit"
msgid_plural "SearchResults|commits"
msgstr[0] ""
+msgid "SearchResults|epic"
+msgid_plural "SearchResults|epics"
+msgstr[0] ""
+
msgid "SearchResults|issue"
msgid_plural "SearchResults|issues"
msgstr[0] ""
@@ -21708,10 +22494,10 @@ msgstr ""
msgid "Seat Link is disabled, and cannot be configured through this form."
msgstr ""
-msgid "Seats currently in use"
+msgid "Seats usage data as of %{last_enqueue_time}"
msgstr ""
-msgid "Seats in license"
+msgid "Seats usage data is updated every day at 12:00pm UTC"
msgstr ""
msgid "Secondary"
@@ -21765,6 +22551,9 @@ msgstr ""
msgid "SecurityConfiguration|Available for on-demand DAST"
msgstr ""
+msgid "SecurityConfiguration|By default, all analyzers are applied in order to cover all languages across your project, and only run if the language is detected in the Merge Request."
+msgstr ""
+
msgid "SecurityConfiguration|Configure"
msgstr ""
@@ -21795,16 +22584,19 @@ msgstr ""
msgid "SecurityConfiguration|Manage"
msgstr ""
+msgid "SecurityConfiguration|More information"
+msgstr ""
+
msgid "SecurityConfiguration|Not enabled"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|Security Control"
+msgid "SecurityConfiguration|SAST Configuration"
msgstr ""
-msgid "SecurityConfiguration|See documentation"
+msgid "SecurityConfiguration|Security Control"
msgstr ""
msgid "SecurityConfiguration|Status"
@@ -21816,6 +22608,9 @@ msgstr ""
msgid "SecurityConfiguration|Using custom settings. You won't receive automatic updates on this variable. %{anchorStart}Restore to default%{anchorEnd}"
msgstr ""
+msgid "SecurityConfiguration|View history"
+msgstr ""
+
msgid "SecurityConfiguration|You can quickly enable all security scanning tools by enabling %{linkStart}Auto DevOps%{linkEnd}."
msgstr ""
@@ -21894,9 +22689,6 @@ msgstr ""
msgid "SecurityReports|Learn more about setting up your dashboard"
msgstr ""
-msgid "SecurityReports|Load more vulnerabilities"
-msgstr ""
-
msgid "SecurityReports|Monitor vulnerabilities in your code"
msgstr ""
@@ -22176,7 +22968,7 @@ msgstr ""
msgid "Select status"
msgstr ""
-msgid "Select strategy activation method"
+msgid "Select strategy activation method."
msgstr ""
msgid "Select subscription"
@@ -22191,7 +22983,7 @@ msgstr ""
msgid "Select the custom project template source group."
msgstr ""
-msgid "Select timeframe"
+msgid "Select the environment scope for this feature flag."
msgstr ""
msgid "Select timezone"
@@ -22440,6 +23232,9 @@ msgstr ""
msgid "Set iteration"
msgstr ""
+msgid "Set limit to 0 to allow any file size."
+msgstr ""
+
msgid "Set max session time for web terminal."
msgstr "웹 터미ë„ì˜ ìµœëŒ€ 세션 ì‹œê°„ì„ ì„¤ì •í•©ë‹ˆë‹¤."
@@ -22518,10 +23313,13 @@ msgstr ""
msgid "Set up a %{type} Runner manually"
msgstr ""
+msgid "Set up a hardware device as a second factor to sign in."
+msgstr ""
+
msgid "Set up assertions/attributes/claims (email, first_name, last_name) and NameID according to %{docsLinkStart}the documentation %{icon}%{docsLinkEnd}"
msgstr ""
-msgid "Set up new U2F device"
+msgid "Set up new device"
msgstr ""
msgid "Set up new password"
@@ -22590,6 +23388,9 @@ msgstr ""
msgid "Sets weight to %{weight}."
msgstr ""
+msgid "Setting this to 0 means using the system default timeout value."
+msgstr ""
+
msgid "Settings"
msgstr "설정"
@@ -22605,6 +23406,15 @@ msgstr ""
msgid "Severity"
msgstr ""
+msgid "SeverityWidget|Severity"
+msgstr ""
+
+msgid "SeverityWidget|Severity: %{severity}"
+msgstr ""
+
+msgid "SeverityWidget|There was an error while updating severity."
+msgstr ""
+
msgid "Shards (%{shards})"
msgstr ""
@@ -22650,6 +23460,9 @@ msgstr ""
msgid "Show all requirements."
msgstr ""
+msgid "Show all test cases."
+msgstr ""
+
msgid "Show archived projects"
msgstr ""
@@ -22662,6 +23475,9 @@ msgstr "명령 보기"
msgid "Show comments"
msgstr "댓글 보기"
+msgid "Show comments on this file"
+msgstr ""
+
msgid "Show comments only"
msgstr ""
@@ -22707,6 +23523,12 @@ msgstr "부모 페ì´ì§€ 보기"
msgid "Show parent subgroups"
msgstr "부모 하위 그룹 보기"
+msgid "Show the Closed list"
+msgstr ""
+
+msgid "Show the Open list"
+msgstr ""
+
msgid "Show whitespace changes"
msgstr ""
@@ -22748,9 +23570,6 @@ msgstr "나란히"
msgid "Sidebar|Assign health status"
msgstr ""
-msgid "Sidebar|Change weight"
-msgstr "ì¤‘ìš”ë„ ë³€ê²½"
-
msgid "Sidebar|Health status"
msgstr ""
@@ -22934,6 +23753,9 @@ msgstr ""
msgid "Snippets|Add another file %{num}/%{total}"
msgstr ""
+msgid "Snippets|Authored %{time_ago} by %{author}"
+msgstr ""
+
msgid "Snippets|Delete file"
msgstr ""
@@ -22961,6 +23783,9 @@ msgstr ""
msgid "Solution"
msgstr ""
+msgid "Some changes are not shown"
+msgstr ""
+
msgid "Some child epics may be hidden due to applied filters"
msgstr ""
@@ -23327,6 +24152,12 @@ msgstr "소스"
msgid "Source (branch or tag)"
msgstr "소스 (브랜치 ë˜ëŠ” 태그)"
+msgid "Source Branch"
+msgstr ""
+
+msgid "Source branch: %{source_branch_open}%{source_branch}%{source_branch_close}"
+msgstr ""
+
msgid "Source code"
msgstr "소스 코드"
@@ -23492,9 +24323,6 @@ msgstr ""
msgid "Start and due date"
msgstr "시작ì¼ê³¼ 마ê°ì¼"
-msgid "Start by choosing a group to see how your team is spending time. You can then drill down to the project level."
-msgstr ""
-
msgid "Start by choosing a group to start exploring the merge requests in that group. You can then proceed to filter by projects, labels, milestones and authors."
msgstr ""
@@ -23576,18 +24404,27 @@ msgstr ""
msgid "StaticSiteEditor|3. Assign a person to review and accept the merge request."
msgstr ""
+msgid "StaticSiteEditor|A link to view the merge request will appear once ready."
+msgstr ""
+
msgid "StaticSiteEditor|An error occurred while submitting your changes."
msgstr ""
msgid "StaticSiteEditor|Branch could not be created."
msgstr ""
+msgid "StaticSiteEditor|Copy update"
+msgstr ""
+
msgid "StaticSiteEditor|Could not commit the content changes."
msgstr ""
msgid "StaticSiteEditor|Could not create merge request."
msgstr ""
+msgid "StaticSiteEditor|Creating your merge request"
+msgstr ""
+
msgid "StaticSiteEditor|Incompatible file content"
msgstr ""
@@ -23609,6 +24446,9 @@ msgstr ""
msgid "StaticSiteEditor|View documentation"
msgstr ""
+msgid "StaticSiteEditor|You can set an assignee to get your changes reviewed and deployed once your merge request is created."
+msgstr ""
+
msgid "StaticSiteEditor|Your merge request has been created"
msgstr ""
@@ -23738,15 +24578,15 @@ msgstr ""
msgid "Submit %{humanized_resource_name}"
msgstr ""
-msgid "Submit Changes"
-msgstr ""
-
msgid "Submit a review"
msgstr ""
msgid "Submit as spam"
msgstr "스팸으로 제출"
+msgid "Submit changes"
+msgstr ""
+
msgid "Submit feedback"
msgstr ""
@@ -23900,6 +24740,9 @@ msgstr "비활성화했습니다."
msgid "Successfully deleted U2F device."
msgstr ""
+msgid "Successfully deleted WebAuthn device."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -24218,9 +25061,6 @@ msgstr "템플릿"
msgid "Template to append to all Service Desk issues"
msgstr ""
-msgid "Template was successfully saved."
-msgstr ""
-
msgid "Templates"
msgstr "템플릿"
@@ -24296,10 +25136,28 @@ msgid "Test coverage: %d hit"
msgid_plural "Test coverage: %d hits"
msgstr[0] ""
-msgid "Test failed."
+msgid "Test settings"
+msgstr ""
+
+msgid "TestCases|New Test Case"
+msgstr ""
+
+msgid "TestCases|New test case"
msgstr ""
-msgid "Test settings and save changes"
+msgid "TestCases|Search test cases"
+msgstr ""
+
+msgid "TestCases|Something went wrong while creating a test case."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching count of test cases."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching test cases list."
+msgstr ""
+
+msgid "TestCases|Submit test case"
msgstr ""
msgid "TestHooks|Ensure one of your projects has merge requests."
@@ -24365,6 +25223,9 @@ msgstr ""
msgid "Thank you for signing up for your free trial! You will get additional instructions in your inbox shortly."
msgstr ""
+msgid "Thank you for your business."
+msgstr ""
+
msgid "Thank you for your feedback!"
msgstr ""
@@ -24423,9 +25284,6 @@ msgstr ""
msgid "The URL to use for connecting to Elasticsearch. Use a comma-separated list to support clustering (e.g., \"http://localhost:9200, http://localhost:9201\")."
msgstr ""
-msgid "The Web IDE offers advanced syntax highlighting capabilities and more."
-msgstr ""
-
msgid "The X509 Certificate to use when mutual TLS is required to communicate with the external authorization service. If left blank, the server certificate is still validated when accessing over HTTPS."
msgstr ""
@@ -24535,6 +25393,9 @@ msgstr "í¬í¬ 관계가 제거ë˜ì—ˆìŠµë‹ˆë‹¤."
msgid "The form contains the following error:"
msgstr ""
+msgid "The form contains the following warning:"
+msgstr ""
+
msgid "The global settings require you to enable Two-Factor Authentication for your account."
msgstr ""
@@ -24649,9 +25510,6 @@ msgstr "ê³„íš ë‹¨ê³„ì—서는 ì´ì „ 단계ì—ì„œ 첫 번째 커밋 ì‹œê°„ì´ í
msgid "The private key to use when a client certificate is provided. This value is encrypted at rest."
msgstr ""
-msgid "The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr "프로ë•ì…˜ 단계ì—서는 문제를 만들고 코드를 프로ë•ì…˜ 환경으로 ë°°í¬í•˜ëŠ” ë° ê±¸ë¦¬ëŠ” ì´ ì‹œê°„ì„ ë³´ì—¬ì¤ë‹ˆë‹¤. ìƒì‚°ì£¼ê¸°ì— 대한 완전한 ì•„ì´ë””어를 ì–»ì€ í›„ì—는 ë°ì´í„°ê°€ ìžë™ìœ¼ë¡œ 추가ë©ë‹ˆë‹¤."
-
msgid "The project can be accessed by any logged in user."
msgstr "ì´ í”„ë¡œì íŠ¸ëŠ” ë¡œê·¸ì¸ í•œ 사용ìžê°€ë§Œ 액세스 í•  수 있습니다."
@@ -24688,7 +25546,7 @@ msgstr ""
msgid "The remote repository is being updated..."
msgstr ""
-msgid "The repository can be commited to, and issues, comments and other entities can be created."
+msgid "The repository can be committed to, and issues, comments and other entities can be created."
msgstr ""
msgid "The repository for this project does not exist."
@@ -24742,9 +25600,6 @@ msgstr "테스트 단계ì—서는 GitLab CIê°€ 관련 머지 리퀘스트(MR)ì„
msgid "The time taken by each data entry gathered by that stage."
msgstr "해당 단계ì—ì„œ 수집 í•œ ê° ë°ì´í„° ìž…ë ¥ì— ì†Œìš” ëœ ì‹œê°„"
-msgid "The total stage shows the time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The update action will time out after %{number_of_minutes} minutes. For big repositories, use a clone/push combination."
msgstr ""
@@ -24808,6 +25663,9 @@ msgstr ""
msgid "There are no archived requirements"
msgstr ""
+msgid "There are no archived test cases"
+msgstr ""
+
msgid "There are no changes"
msgstr ""
@@ -24847,6 +25705,9 @@ msgstr ""
msgid "There are no open requirements"
msgstr ""
+msgid "There are no open test cases"
+msgstr ""
+
msgid "There are no packages yet"
msgstr ""
@@ -24859,6 +25720,9 @@ msgstr ""
msgid "There is a limit of %{ci_project_subscriptions_limit} subscriptions from or to a project."
msgstr ""
+msgid "There is already a To-Do for this design."
+msgstr ""
+
msgid "There is already a repository with that name on disk"
msgstr ""
@@ -24877,6 +25741,9 @@ msgstr ""
msgid "There was a problem communicating with your device."
msgstr ""
+msgid "There was a problem fetching branches."
+msgstr ""
+
msgid "There was a problem fetching groups."
msgstr ""
@@ -25105,9 +25972,15 @@ msgstr ""
msgid "This action can lead to data loss. To prevent accidental actions we ask you to confirm your intention."
msgstr ""
+msgid "This action cannot be undone, and will permanently delete the %{key} SSH key"
+msgstr ""
+
msgid "This action cannot be undone. You will lose the project's repository and all content: issues, merge requests, etc."
msgstr ""
+msgid "This action has been performed too many times. Try again later."
+msgstr ""
+
msgid "This action will %{strongOpen}permanently delete%{strongClose} %{codeOpen}%{project}%{codeClose} %{strongOpen}immediately%{strongClose}, including its repositories and all content: issues, merge requests, etc."
msgstr ""
@@ -25135,9 +26008,6 @@ msgstr ""
msgid "This board's scope is reduced"
msgstr "ì´ ë³´ë“œì˜ ë²”ìœ„ê°€ 축소ë˜ì—ˆìŠµë‹ˆë‹¤."
-msgid "This branch has changed since you started editing. Would you like to create a new branch?"
-msgstr ""
-
msgid "This chart could not be displayed"
msgstr ""
@@ -25264,15 +26134,9 @@ msgstr ""
msgid "This is a security log of important events involving your account."
msgstr ""
-msgid "This is the author's first Merge Request to this project."
-msgstr "ì´ ì €ìžì˜ ì´ í”„ë¡œì íŠ¸ì— 대한 첫번째 머지 리퀘스트(MR) 입니다."
-
msgid "This is the highest peak of users on your installation since the license started."
msgstr ""
-msgid "This is the maximum number of users that have existed at the same time since the license started. This is the minimum number of seats you will need to buy when you renew your license."
-msgstr ""
-
msgid "This is the number of currently active users on your installation, and this is the minimum number you need to purchase when you renew your license."
msgstr ""
@@ -25504,6 +26368,15 @@ msgstr ""
msgid "This user has no identities"
msgstr "ì´ ì‚¬ìš©ìžëŠ” ì‹ ì›ì´ 없습니다."
+msgid "This user has previously committed to the %{name} project."
+msgstr ""
+
+msgid "This user has the %{access} role in the %{name} project."
+msgstr ""
+
+msgid "This user is the author of this %{noteable}."
+msgstr ""
+
msgid "This user will be the author of all events in the activity feed that are the result of an update, like new branches being created or new commits being pushed to existing branches."
msgstr ""
@@ -25534,6 +26407,9 @@ msgstr ""
msgid "Threat Monitoring"
msgstr ""
+msgid "ThreatMonitoring|All Environments"
+msgstr ""
+
msgid "ThreatMonitoring|Anomalous Requests"
msgstr ""
@@ -25561,9 +26437,6 @@ msgstr ""
msgid "ThreatMonitoring|Operations Per Second"
msgstr ""
-msgid "ThreatMonitoring|Overview"
-msgstr ""
-
msgid "ThreatMonitoring|Packet Activity"
msgstr ""
@@ -25582,6 +26455,9 @@ msgstr ""
msgid "ThreatMonitoring|Something went wrong, unable to fetch statistics"
msgstr ""
+msgid "ThreatMonitoring|Statistics"
+msgstr ""
+
msgid "ThreatMonitoring|The firewall is not installed or has been disabled. To view this data, ensure the web application firewall is installed and enabled for your cluster."
msgstr ""
@@ -25971,6 +26847,9 @@ msgstr ""
msgid "To update Snippets with multiple files, you must use the `files` parameter"
msgstr ""
+msgid "To use Gitpod you must first enable the feature in the integrations section of your %{user_prefs}."
+msgstr ""
+
msgid "To view all %{scannedResourcesCount} scanned URLs, please download the CSV file"
msgstr ""
@@ -26004,9 +26883,6 @@ msgstr ""
msgid "Toggle Sidebar"
msgstr "사ì´ë“œë°” 전환"
-msgid "Toggle all threads"
-msgstr ""
-
msgid "Toggle backtrace"
msgstr ""
@@ -26031,9 +26907,6 @@ msgstr ""
msgid "Toggle navigation"
msgstr "토글 네비게ì´ì…˜"
-msgid "Toggle project"
-msgstr ""
-
msgid "Toggle sidebar"
msgstr "사ì´ë“œë°” 토글"
@@ -26073,6 +26946,9 @@ msgstr ""
msgid "Too many projects enabled. You will need to manage them via the console or the API."
msgstr ""
+msgid "Too much data"
+msgstr ""
+
msgid "Topics (optional)"
msgstr ""
@@ -26091,6 +26967,9 @@ msgstr ""
msgid "Total cores (CPUs)"
msgstr ""
+msgid "Total days to completion"
+msgstr ""
+
msgid "Total issues"
msgstr ""
@@ -26187,6 +27066,9 @@ msgstr ""
msgid "Trending"
msgstr "ì¸ê¸°"
+msgid "Trials|Create a new group to start your GitLab Gold trial."
+msgstr ""
+
msgid "Trials|Go back to GitLab"
msgstr ""
@@ -26196,6 +27078,15 @@ msgstr ""
msgid "Trials|You can always resume this process by selecting your avatar and choosing 'Start a Gold trial'"
msgstr ""
+msgid "Trials|You can apply your trial to a new group or an existing group."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group or your personal account."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group, an existing group, or your personal account."
+msgstr ""
+
msgid "Trials|You won't get a free trial right now but you can always resume this process by clicking on your avatar and choosing 'Start a free trial'"
msgstr ""
@@ -26265,6 +27156,9 @@ msgstr ""
msgid "Try using a different search term to find the file you are looking for."
msgstr ""
+msgid "Trying to communicate with your device. Plug it in (if needed) and press the button on the device now."
+msgstr ""
+
msgid "Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now."
msgstr ""
@@ -26352,6 +27246,12 @@ msgstr ""
msgid "URL or request ID"
msgstr ""
+msgid "USER %{user} WILL BE REMOVED! Are you sure?"
+msgstr ""
+
+msgid "USER WILL BE BLOCKED! Are you sure?"
+msgstr ""
+
msgid "UTC"
msgstr ""
@@ -26409,9 +27309,6 @@ msgstr "ì°¨ì´ì ì„ ì½ì–´ë“¤ì¼ 수 없습니다. %{button_try_again}"
msgid "Unable to load the merge request widget. Try reloading the page."
msgstr ""
-msgid "Unable to resolve"
-msgstr ""
-
msgid "Unable to save iteration. Please try again"
msgstr ""
@@ -26460,6 +27357,9 @@ msgstr ""
msgid "Undo ignore"
msgstr ""
+msgid "Unexpected error"
+msgstr ""
+
msgid "Unfortunately, your email message to GitLab could not be processed."
msgstr ""
@@ -26493,6 +27393,9 @@ msgstr ""
msgid "Unknown response text"
msgstr ""
+msgid "Unless otherwise agreed to in writing with GitLab, by clicking \"Upload License\" you agree that your use of GitLab Software is subject to the %{eula_link_start}Terms of Service%{eula_link_end}."
+msgstr ""
+
msgid "Unlimited"
msgstr "무제한"
@@ -26859,9 +27762,6 @@ msgstr ""
msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
msgstr ""
-msgid "Use a hardware device to add the second factor of authentication."
-msgstr ""
-
msgid "Use an one time password authenticator on your mobile device or computer to enable two-factor authentication (2FA)."
msgstr "휴대 기기 ë˜ëŠ” 컴퓨터ì—ì„œ ì¼íšŒìš© 비밀번호 ì¸ì¦ê¸°ë¥¼ 사용하여 ì´ì¤‘ ì¸ì¦(2FA)를 활성화하세요."
@@ -27135,13 +28035,13 @@ msgstr ""
msgid "Users"
msgstr "사용ìžë“¤"
-msgid "Users in License:"
+msgid "Users in License"
msgstr ""
-msgid "Users or groups set as approvers in the project's or merge request's settings."
+msgid "Users in License:"
msgstr ""
-msgid "Users outside of license"
+msgid "Users or groups set as approvers in the project's or merge request's settings."
msgstr ""
msgid "Users over License:"
@@ -27159,9 +28059,6 @@ msgstr ""
msgid "Users with a Guest role or those who don't belong to a Project or Group will not use a seat from your license."
msgstr ""
-msgid "Users with a Guest role or those who don't belong to any projects or groups don't count towards seats in use."
-msgstr ""
-
msgid "UsersSelect|%{name} + %{length} more"
msgstr ""
@@ -27201,9 +28098,6 @@ msgstr ""
msgid "Validations failed."
msgstr ""
-msgid "Validity"
-msgstr ""
-
msgid "Value"
msgstr ""
@@ -27222,6 +28116,9 @@ msgstr ""
msgid "Value Stream Name"
msgstr ""
+msgid "ValueStreamAnalyticsStage|We don't have enough data to show this stage."
+msgstr ""
+
msgid "ValueStreamAnalytics|%{days}d"
msgstr ""
@@ -27476,6 +28373,9 @@ msgstr ""
msgid "VisualReviewApp|Steps 1 and 2 (and sometimes 3) are performed once by the developer before requesting feedback. Steps 3 (if necessary), 4 is performed by the reviewer each time they perform a review."
msgstr ""
+msgid "Visualization"
+msgstr ""
+
msgid "Vulnerabilities"
msgstr ""
@@ -27503,34 +28403,31 @@ msgstr ""
msgid "VulnerabilityChart|Severity"
msgstr ""
-msgid "VulnerabilityManagement|A true-positive and will fix"
-msgstr ""
-
-msgid "VulnerabilityManagement|Change status"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Confirm"
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|Confirmed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Detected %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|A true-positive and will fix"
msgstr ""
-msgid "VulnerabilityManagement|Dismiss"
+msgid "VulnerabilityManagement|Change status"
msgstr ""
-msgid "VulnerabilityManagement|Dismissed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
msgstr ""
-msgid "VulnerabilityManagement|Resolved"
+msgid "VulnerabilityManagement|Detected"
msgstr ""
-msgid "VulnerabilityManagement|Resolved %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Needs triage"
msgstr ""
msgid "VulnerabilityManagement|Something went wrong while trying to delete the comment. Please try again later."
@@ -27581,6 +28478,9 @@ msgstr ""
msgid "Vulnerability|%{scannerName} (version %{scannerVersion})"
msgstr ""
+msgid "Vulnerability|Activity"
+msgstr ""
+
msgid "Vulnerability|Class"
msgstr ""
@@ -27593,6 +28493,9 @@ msgstr ""
msgid "Vulnerability|Description"
msgstr "설명"
+msgid "Vulnerability|Detected"
+msgstr ""
+
msgid "Vulnerability|Evidence"
msgstr ""
@@ -27656,6 +28559,9 @@ msgstr ""
msgid "Warning: Displaying this diagram might cause performance issues on this page."
msgstr ""
+msgid "We are currently unable to fetch data for the pipeline header."
+msgstr ""
+
msgid "We are currently unable to fetch data for this graph."
msgstr ""
@@ -27695,6 +28601,12 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr "ì •ë§ ë‹¹ì‹ ì´ ë§žëŠ”ì§€ 확ì¸í•˜ê³  싶습니다, ë‹¹ì‹ ì´ ë¡œë´‡ì´ ì•„ë‹ˆë¼ëŠ” ê²ƒì„ í™•ì¸í•´ì£¼ì‹­ì‹œì˜¤."
+msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
+msgstr ""
+
+msgid "We would like to inform you that your subscription GitLab Enterprise Edition %{plan_name} is nearing its user limit. You have %{active_user_count} active users, which is almost at the user limit of %{maximum_user_count}."
+msgstr ""
+
msgid "We've found no vulnerabilities"
msgstr ""
@@ -27710,6 +28622,12 @@ msgstr "웹 터미ë„"
msgid "Web terminal"
msgstr "웹 터미ë„"
+msgid "WebAuthn Devices (%{length})"
+msgstr ""
+
+msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
+msgstr ""
+
msgid "WebIDE|Merge request"
msgstr ""
@@ -27848,15 +28766,9 @@ msgstr ""
msgid "Welcome to the guided GitLab tour"
msgstr ""
-msgid "Welcome to your Issue Board!"
-msgstr ""
-
msgid "Welcome to your issue board!"
msgstr ""
-msgid "We’ve been making changes to %{featureName} and we’d love your feedback %{linkStart}in this issue%{linkEnd} to help us improve the experience."
-msgstr ""
-
msgid "What are you searching for?"
msgstr ""
@@ -27875,6 +28787,9 @@ msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
msgstr "Runnerê°€ 잠겨 있으면 다른 프로ì íŠ¸ì— 할당 í•  수 없습니다"
+msgid "When enabled, any user visiting %{host} and creating an account will have to be explicitly approved by the admin before they can login. This setting is effective only if sign-ups are enabled."
+msgstr ""
+
msgid "When enabled, any user visiting %{host} will be able to create an account."
msgstr ""
@@ -28098,6 +29013,9 @@ msgstr ""
msgid "With requirements, you can set criteria to check your products against."
msgstr ""
+msgid "With test cases, you can define conditions for your project to meet in determining quality"
+msgstr ""
+
msgid "Withdraw Access Request"
msgstr "액세스 요청 철회"
@@ -28113,6 +29031,9 @@ msgstr ""
msgid "Workflow Help"
msgstr ""
+msgid "Would you like to create a new branch?"
+msgstr ""
+
msgid "Write"
msgstr ""
@@ -28134,6 +29055,9 @@ msgstr ""
msgid "Wrong extern UID provided. Make sure Auth0 is configured correctly."
msgstr ""
+msgid "YYYY-MM-DD"
+msgstr ""
+
msgid "Yes"
msgstr "예"
@@ -28191,8 +29115,8 @@ msgstr ""
msgid "You are going to remove the fork relationship from %{project_full_name}. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "You are going to transfer %{project_full_name} to another owner. Are you ABSOLUTELY sure?"
-msgstr "%{project_full_name} (ì„) 를 다른 소유ìžì—게 ì´ì „하려고합니다. \"ì •ë§ë¡œ\" 확실합니까?"
+msgid "You are going to transfer %{project_full_name} to another namespace. Are you ABSOLUTELY sure?"
+msgstr ""
msgid "You are going to turn off the confidentiality. This means %{strongStart}everyone%{strongEnd} will be able to see and leave a comment on this %{issuableType}."
msgstr ""
@@ -28251,9 +29175,6 @@ msgstr ""
msgid "You can always edit this later"
msgstr ""
-msgid "You can apply your Trial to your Personal account or create a New Group."
-msgstr ""
-
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings"
msgstr ""
@@ -28275,12 +29196,18 @@ msgstr "Kubernetes í´ëŸ¬ìŠ¤í„°ì— Runner를 쉽게 설치할 수 있습니다.
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
+msgid "You can find more information about GitLab subscriptions in %{subscriptions_doc_link}."
+msgstr ""
+
msgid "You can generate an access token scoped to this project for each application to use the GitLab API."
msgstr ""
msgid "You can get started by cloning the repository or start adding files to it with one of the following options."
msgstr ""
+msgid "You can group test cases using labels. To learn about the future direction of this feature, visit %{linkStart}Quality Management direction page%{linkEnd}."
+msgstr ""
+
msgid "You can invite a new member to %{project_name} or invite another group."
msgstr ""
@@ -28296,6 +29223,9 @@ msgstr "화살표 키를 사용하여 그래프를 움ì§ì¼ 수 있습니다."
msgid "You can notify the app / group or a project by sending them an email notification"
msgstr ""
+msgid "You can now close this window."
+msgstr ""
+
msgid "You can now export your security dashboard to a CSV report."
msgstr ""
@@ -28344,9 +29274,6 @@ msgstr ""
msgid "You can test your .gitlab-ci.yml in %{linkStart}CI Lint%{linkEnd}."
msgstr ""
-msgid "You can try again using %{begin_link}basic search%{end_link}"
-msgstr ""
-
msgid "You cannot access the raw file. Please wait a minute."
msgstr ""
@@ -28398,6 +29325,9 @@ msgstr ""
msgid "You don't have any U2F devices registered yet."
msgstr ""
+msgid "You don't have any WebAuthn devices registered yet."
+msgstr ""
+
msgid "You don't have any active chat names."
msgstr ""
@@ -28485,6 +29415,9 @@ msgstr ""
msgid "You must accept our Terms of Service and privacy policy in order to register an account"
msgstr "ê³„ì •ì„ ë“±ë¡í•˜ë ¤ë©´ 서비스 약관 ë° ê°œì¸ ì •ë³´ 취급 ë°©ì¹¨ì— ë™ì˜í•´ì•¼í•©ë‹ˆë‹¤."
+msgid "You must be logged in to search across all of GitLab"
+msgstr ""
+
msgid "You must disassociate %{domain} from all clusters it is attached to before deletion."
msgstr ""
@@ -28524,7 +29457,7 @@ msgstr "ê¶Œí•œì´ í•„ìš”í•©ë‹ˆë‹¤."
msgid "You need to be logged in."
msgstr ""
-msgid "You need to register a two-factor authentication app before you can set up a U2F device."
+msgid "You need to register a two-factor authentication app before you can set up a device."
msgstr ""
msgid "You need to set terms to be enforced"
@@ -28542,6 +29475,9 @@ msgstr ""
msgid "You reached %{usage_in_percent} of %{namespace_name}'s storage capacity (%{used_storage} of %{storage_limit})"
msgstr ""
+msgid "You successfully declined the invitation"
+msgstr ""
+
msgid "You tried to fork %{link_to_the_project} but it failed for the following reason:"
msgstr ""
@@ -28707,10 +29643,13 @@ msgstr ""
msgid "Your U2F device did not send a valid JSON response."
msgstr ""
-msgid "Your U2F device needs to be set up. Plug it in (if not already) and click the button on the left."
+msgid "Your U2F device was registered!"
msgstr ""
-msgid "Your U2F device was registered!"
+msgid "Your WebAuthn device did not send a valid JSON response."
+msgstr ""
+
+msgid "Your WebAuthn device was registered!"
msgstr ""
msgid "Your access request to the %{source_type} has been withdrawn."
@@ -28734,6 +29673,9 @@ msgstr "승ì¸ëœ 애플리케ì´ì…˜"
msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
msgstr ""
+msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
+msgstr ""
+
msgid "Your changes can be committed to %{branch_name} because a merge request is open."
msgstr "머지 리퀘스트(MR)ê°€ 열려있기 ë•Œë¬¸ì— ë³€ê²½ì‚¬í•­ì€ %{branch_name}(으)ë¡œ ì»¤ë°‹ë  ìˆ˜ 있습니다."
@@ -28770,6 +29712,12 @@ msgstr ""
msgid "Your deployment services will be broken, you will need to manually fix the services after renaming."
msgstr ""
+msgid "Your device is not compatible with GitLab. Please try another device"
+msgstr ""
+
+msgid "Your device needs to be set up. Plug it in (if needed) and click the button on the left."
+msgstr ""
+
msgid "Your device was successfully set up! Give it a name and register it with the GitLab server."
msgstr ""
@@ -28882,9 +29830,6 @@ msgstr[0] ""
msgid "access:"
msgstr ""
-msgid "activated"
-msgstr ""
-
msgid "added %{created_at_timeago}"
msgstr ""
@@ -28957,9 +29902,21 @@ msgstr "by"
msgid "by %{user}"
msgstr ""
+msgid "cannot be a date in the past"
+msgstr ""
+
msgid "cannot be changed if a personal project has container registry tags."
msgstr ""
+msgid "cannot be changed if shared runners are enabled"
+msgstr ""
+
+msgid "cannot be enabled because parent group does not allow it"
+msgstr ""
+
+msgid "cannot be enabled because parent group has shared Runners disabled"
+msgstr ""
+
msgid "cannot be enabled unless all domains have TLS certificates"
msgstr ""
@@ -29005,7 +29962,7 @@ msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about SAST %{linkEndTag}"
msgstr ""
-msgid "ciReport|%{linkStartTag}Learn more about Secret Scanning %{linkEndTag}"
+msgid "ciReport|%{linkStartTag}Learn more about Secret Detection %{linkEndTag}"
msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about codequality reports %{linkEndTag}"
@@ -29317,9 +30274,6 @@ msgstr ""
msgid "error"
msgstr ""
-msgid "error code:"
-msgstr ""
-
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr "%{slash_command} ëª…ë ¹ì€ ì˜ˆìƒì‹œê°„ì„ ê°€ìž¥ 마지막 명령으로 ì—…ë°ì´íŠ¸ 합니다."
@@ -29341,6 +30295,9 @@ msgstr ""
msgid "failed to dismiss associated finding(id=%{finding_id}): %{message}"
msgstr ""
+msgid "failed to revert associated finding(id=%{finding_id}) to detected"
+msgstr ""
+
msgid "file"
msgid_plural "files"
msgstr[0] ""
@@ -29879,6 +30836,9 @@ msgstr ""
msgid "must be a root namespace"
msgstr ""
+msgid "must be a valid IPv4 or IPv6 address"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -29915,6 +30875,9 @@ msgstr ""
msgid "no expiration"
msgstr ""
+msgid "no name set"
+msgstr ""
+
msgid "no one can merge"
msgstr ""
@@ -30088,9 +31051,6 @@ msgstr ""
msgid "security Reports|There was an error creating the merge request"
msgstr ""
-msgid "settings saved, but not activated"
-msgstr ""
-
msgid "severity|Critical"
msgstr ""
@@ -30217,9 +31177,6 @@ msgstr "목ë¡ìœ¼ë¡œ ì´ë™"
msgid "toggle collapse"
msgstr ""
-msgid "toggle dropdown"
-msgstr ""
-
msgid "triggered"
msgstr ""
@@ -30247,6 +31204,9 @@ msgstr ""
msgid "user avatar"
msgstr "ì‚¬ìš©ìž ì•„ë°”íƒ€"
+msgid "user preferences"
+msgstr ""
+
msgid "username"
msgstr "사용ìžëª…"
diff --git a/locale/ku_TR/gitlab.po b/locale/ku_TR/gitlab.po
index 94705cdd7d0..068097dc42e 100644
--- a/locale/ku_TR/gitlab.po
+++ b/locale/ku_TR/gitlab.po
@@ -14,7 +14,10 @@ msgstr ""
"X-Crowdin-Language: ku\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 6\n"
-"PO-Revision-Date: 2020-09-04 23:09\n"
+"PO-Revision-Date: 2020-10-02 18:48\n"
+
+msgid " %{project_name}#%{issue_iid} &middot; opened %{issue_created} by %{author}"
+msgstr ""
msgid " %{start} to %{end}"
msgstr ""
@@ -74,6 +77,16 @@ msgstr ""
msgid "\"el\" parameter is required for createInstance()"
msgstr ""
+msgid "%d Approval"
+msgid_plural "%d Approvals"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d Package"
+msgid_plural "%d Packages"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d Scanned URL"
msgid_plural "%d Scanned URLs"
msgstr[0] ""
@@ -137,6 +150,11 @@ msgstr[1] ""
msgid "%d commits"
msgstr ""
+msgid "%d completed issue"
+msgid_plural "%d completed issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d contribution"
msgid_plural "%d contributions"
msgstr[0] ""
@@ -147,6 +165,11 @@ msgid_plural "%d days"
msgstr[0] ""
msgstr[1] ""
+msgid "%d day until tags are automatically removed"
+msgid_plural "%d days until tags are automatically removed"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d error"
msgid_plural "%d errors"
msgstr[0] ""
@@ -237,6 +260,16 @@ msgid_plural "%d more comments"
msgstr[0] ""
msgstr[1] ""
+msgid "%d open issue"
+msgid_plural "%d open issues"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d pending comment"
+msgid_plural "%d pending comments"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d personal project will be removed and cannot be restored."
msgid_plural "%d personal projects will be removed and cannot be restored."
msgstr[0] ""
@@ -252,6 +285,11 @@ msgid_plural "%d projects"
msgstr[0] ""
msgstr[1] ""
+msgid "%d project selected"
+msgid_plural "%d projects selected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d request with warnings"
msgid_plural "%d requests with warnings"
msgstr[0] ""
@@ -272,6 +310,11 @@ msgid_plural "%d tags"
msgstr[0] ""
msgstr[1] ""
+msgid "%d tag per image name"
+msgid_plural "%d tags per image name"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d unassigned issue"
msgid_plural "%d unassigned issues"
msgstr[0] ""
@@ -292,6 +335,11 @@ msgid_plural "%d vulnerabilities dismissed"
msgstr[0] ""
msgstr[1] ""
+msgid "%d warning found:"
+msgid_plural "%d warnings found:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%s additional commit has been omitted to prevent performance issues."
msgid_plural "%s additional commits have been omitted to prevent performance issues."
msgstr[0] ""
@@ -330,6 +378,9 @@ msgstr ""
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr ""
+msgid "%{completedCount} completed weight"
+msgstr ""
+
msgid "%{completedWeight} of %{totalWeight} weight completed"
msgstr ""
@@ -378,14 +429,12 @@ msgid_plural "%{count} participants"
msgstr[0] ""
msgstr[1] ""
-msgid "%{count} pending comment"
-msgid_plural "%{count} pending comments"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
+msgid "%{count} total weight"
+msgstr ""
+
msgid "%{dashboard_path} could not be found."
msgstr ""
@@ -440,6 +489,9 @@ msgstr ""
msgid "%{group_name} uses group managed accounts. You need to create a new GitLab account which will be managed by %{group_name}."
msgstr ""
+msgid "%{group_name}&%{epic_iid} &middot; opened %{epic_created} by %{author}"
+msgstr ""
+
msgid "%{host} sign-in from new location"
msgstr ""
@@ -452,7 +504,7 @@ msgstr ""
msgid "%{issuableType} will be removed! Are you sure?"
msgstr ""
-msgid "%{issuesSize} issues with a limit of %{maxIssueCount}"
+msgid "%{issuesCount} issues with a limit of %{maxIssueCount}"
msgstr ""
msgid "%{issuesSize} with a limit of %{maxIssueCount}"
@@ -485,7 +537,7 @@ msgstr ""
msgid "%{labelStart}Namespace:%{labelEnd} %{namespace}"
msgstr ""
-msgid "%{labelStart}Report Type:%{labelEnd} %{reportType}"
+msgid "%{labelStart}Scan Type:%{labelEnd} %{reportType}"
msgstr ""
msgid "%{labelStart}Scanner:%{labelEnd} %{scanner}"
@@ -682,9 +734,6 @@ msgid_plural "%{securityScanner} results are not available because a pipeline ha
msgstr[0] ""
msgstr[1] ""
-msgid "%{service_title} %{message}."
-msgstr ""
-
msgid "%{size} GiB"
msgstr ""
@@ -773,6 +822,12 @@ msgstr ""
msgid "%{timebox_name} should belong either to a project or a group."
msgstr ""
+msgid "%{timebox_type} does not support burnup charts"
+msgstr ""
+
+msgid "%{timebox_type} must have a start and due date"
+msgstr ""
+
msgid "%{title} %{operator} %{threshold}"
msgstr ""
@@ -797,7 +852,7 @@ msgstr ""
msgid "%{total} open issue weight"
msgstr ""
-msgid "%{total} open issues"
+msgid "%{total} warnings found: showing first %{warningsDisplayed}"
msgstr ""
msgid "%{usage_ping_link_start}Learn more%{usage_ping_link_end} about what information is shared with GitLab Inc."
@@ -830,9 +885,6 @@ msgstr ""
msgid "&lt; 1 hour"
msgstr ""
-msgid "&lt;no name set&gt;"
-msgstr ""
-
msgid "&lt;no scopes selected&gt;"
msgstr ""
@@ -863,6 +915,9 @@ msgstr ""
msgid "'%{name}' Value Stream created"
msgstr ""
+msgid "'%{name}' Value Stream deleted"
+msgstr ""
+
msgid "'%{name}' stage already exists"
msgstr ""
@@ -922,6 +977,9 @@ msgstr ""
msgid "+ %{numberOfHiddenAssignees} more"
msgstr ""
+msgid "+ %{numberOfHiddenReviewers} more"
+msgstr ""
+
msgid "+%d more"
msgid_plural "+%d more"
msgstr[0] ""
@@ -982,6 +1040,11 @@ msgid_plural "%d Days"
msgstr[0] ""
msgstr[1] ""
+msgid "1 Issue"
+msgid_plural "%d Issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "1 closed issue"
msgid_plural "%{issues} closed issues"
msgstr[0] ""
@@ -997,6 +1060,11 @@ msgid_plural "%d days"
msgstr[0] ""
msgstr[1] ""
+msgid "1 deploy key"
+msgid_plural "%d deploy keys"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1099,6 +1167,9 @@ msgstr ""
msgid ":%{startLine} to %{endLine}"
msgstr ""
+msgid "A %{incident_docs_start}modified issue%{incident_docs_end} to guide the resolution of incidents."
+msgstr ""
+
msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr ""
@@ -1111,6 +1182,9 @@ msgstr ""
msgid "A GitBook site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
+msgid "A Gitpod configured Webapplication in Spring and Java"
+msgstr ""
+
msgid "A Hexo site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
@@ -1282,9 +1356,15 @@ msgstr ""
msgid "Access expiration date"
msgstr ""
+msgid "Access expires"
+msgstr ""
+
msgid "Access forbidden. Check your access level."
msgstr ""
+msgid "Access granted"
+msgstr ""
+
msgid "Access requests"
msgstr ""
@@ -1294,6 +1374,9 @@ msgstr ""
msgid "Access to Pages websites are controlled based on the user's membership to a given project. By checking this box, users will be required to be logged in to have access to all Pages websites in your instance."
msgstr ""
+msgid "AccessDropdown|Deploy Keys"
+msgstr ""
+
msgid "AccessDropdown|Groups"
msgstr ""
@@ -1411,12 +1494,6 @@ msgstr ""
msgid "Active Sessions"
msgstr ""
-msgid "Active Users:"
-msgstr ""
-
-msgid "Active users"
-msgstr ""
-
msgid "Activity"
msgstr ""
@@ -1584,9 +1661,6 @@ msgstr ""
msgid "Add label(s)"
msgstr ""
-msgid "Add license"
-msgstr ""
-
msgid "Add list"
msgstr ""
@@ -1761,21 +1835,51 @@ msgstr ""
msgid "AdminArea|Bots"
msgstr ""
+msgid "AdminArea|Components"
+msgstr ""
+
msgid "AdminArea|Developer"
msgstr ""
+msgid "AdminArea|Features"
+msgstr ""
+
+msgid "AdminArea|Groups: %{number_of_groups}"
+msgstr ""
+
msgid "AdminArea|Guest"
msgstr ""
msgid "AdminArea|Included Free in license"
msgstr ""
+msgid "AdminArea|Latest groups"
+msgstr ""
+
+msgid "AdminArea|Latest projects"
+msgstr ""
+
+msgid "AdminArea|Latest users"
+msgstr ""
+
msgid "AdminArea|Maintainer"
msgstr ""
+msgid "AdminArea|New group"
+msgstr ""
+
+msgid "AdminArea|New project"
+msgstr ""
+
+msgid "AdminArea|New user"
+msgstr ""
+
msgid "AdminArea|Owner"
msgstr ""
+msgid "AdminArea|Projects: %{number_of_projects}"
+msgstr ""
+
msgid "AdminArea|Reporter"
msgstr ""
@@ -1803,6 +1907,9 @@ msgstr ""
msgid "AdminArea|Users without a Group and Project"
msgstr ""
+msgid "AdminArea|Users: %{number_of_users}"
+msgstr ""
+
msgid "AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running."
msgstr ""
@@ -1821,9 +1928,6 @@ msgstr ""
msgid "AdminProjects|Delete Project %{projectName}?"
msgstr ""
-msgid "AdminProjects|Delete project"
-msgstr ""
-
msgid "AdminSettings|Apply integration settings to all Projects"
msgstr ""
@@ -2061,21 +2165,30 @@ msgstr ""
msgid "AdminUsers|Without projects"
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 ""
msgid "AdminUsers|You cannot remove your own admin rights."
msgstr ""
+msgid "AdminUsers|You must transfer ownership or delete the groups owned by this user before you can delete their account"
+msgstr ""
+
msgid "Administration"
msgstr ""
msgid "Advanced"
msgstr ""
+msgid "Advanced Search"
+msgstr ""
+
+msgid "Advanced Search with Elasticsearch"
+msgstr ""
+
msgid "Advanced Settings"
msgstr ""
@@ -2153,6 +2266,9 @@ msgstr ""
msgid "AlertManagement|Edit"
msgstr ""
+msgid "AlertManagement|Environment"
+msgstr ""
+
msgid "AlertManagement|Events"
msgstr ""
@@ -2165,6 +2281,9 @@ msgstr ""
msgid "AlertManagement|Issue"
msgstr ""
+msgid "AlertManagement|Key"
+msgstr ""
+
msgid "AlertManagement|Low"
msgstr ""
@@ -2258,6 +2377,9 @@ msgstr ""
msgid "AlertManagement|Unknown"
msgstr ""
+msgid "AlertManagement|Value"
+msgstr ""
+
msgid "AlertManagement|View alerts in Opsgenie"
msgstr ""
@@ -2417,6 +2539,9 @@ msgstr ""
msgid "All projects"
msgstr ""
+msgid "All projects selected"
+msgstr ""
+
msgid "All security scans are enabled because %{linkStart}Auto DevOps%{linkEnd} is enabled on this project"
msgstr ""
@@ -2504,6 +2629,9 @@ msgstr ""
msgid "Almost there"
msgstr ""
+msgid "Already blocked"
+msgstr ""
+
msgid "Also called \"Issuer\" or \"Relying party trust identifier\""
msgstr ""
@@ -2558,6 +2686,9 @@ msgstr ""
msgid "An error has occurred"
msgstr ""
+msgid "An error occured while making the changes: %{error}"
+msgstr ""
+
msgid "An error occurred adding a draft to the thread."
msgstr ""
@@ -2585,12 +2716,6 @@ msgstr ""
msgid "An error occurred when toggling the notification subscription"
msgstr ""
-msgid "An error occurred when trying to resolve a comment. Please try again."
-msgstr ""
-
-msgid "An error occurred when trying to resolve a discussion. Please try again."
-msgstr ""
-
msgid "An error occurred when updating the issue weight"
msgstr ""
@@ -2606,12 +2731,6 @@ msgstr ""
msgid "An error occurred while checking group path. Please refresh and try again."
msgstr ""
-msgid "An error occurred while committing your changes."
-msgstr ""
-
-msgid "An error occurred while creating the list. Please try again."
-msgstr ""
-
msgid "An error occurred while decoding the file."
msgstr ""
@@ -2684,25 +2803,19 @@ msgstr ""
msgid "An error occurred while fetching the Service Desk address."
msgstr ""
-msgid "An error occurred while fetching the board issues. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the board lists. Please reload the page."
msgstr ""
msgid "An error occurred while fetching the board lists. Please try again."
msgstr ""
-msgid "An error occurred while fetching the board swimlanes. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the builds."
msgstr ""
msgid "An error occurred while fetching the job log."
msgstr ""
-msgid "An error occurred while fetching the job trace."
+msgid "An error occurred while fetching the job logs."
msgstr ""
msgid "An error occurred while fetching the job."
@@ -2849,9 +2962,6 @@ msgstr ""
msgid "An error occurred while saving assignees"
msgstr ""
-msgid "An error occurred while saving the template. Please check if the template exists."
-msgstr ""
-
msgid "An error occurred while searching for milestones"
msgstr ""
@@ -2870,10 +2980,10 @@ msgstr ""
msgid "An error occurred while updating approvers"
msgstr ""
-msgid "An error occurred while updating the comment"
+msgid "An error occurred while updating labels."
msgstr ""
-msgid "An error occurred while updating the list. Please try again."
+msgid "An error occurred while updating the comment"
msgstr ""
msgid "An error occurred while validating group path"
@@ -2927,6 +3037,9 @@ msgstr ""
msgid "An unknown error occurred while loading this graph."
msgstr ""
+msgid "An unknown error occurred."
+msgstr ""
+
msgid "Analytics"
msgstr ""
@@ -2960,10 +3073,10 @@ msgstr ""
msgid "Any"
msgstr ""
-msgid "Any Author"
+msgid "Any %{header}"
msgstr ""
-msgid "Any Status"
+msgid "Any Author"
msgstr ""
msgid "Any branch"
@@ -3017,6 +3130,9 @@ msgstr ""
msgid "Application ID"
msgstr ""
+msgid "Application limits saved successfully"
+msgstr ""
+
msgid "Application settings saved successfully"
msgstr ""
@@ -3226,6 +3342,9 @@ msgstr ""
msgid "Are you sure you want to close this blocked issue?"
msgstr ""
+msgid "Are you sure you want to delete \"%{name}\" Value Stream?"
+msgstr ""
+
msgid "Are you sure you want to delete %{name}?"
msgstr ""
@@ -3235,6 +3354,9 @@ msgstr ""
msgid "Are you sure you want to delete this %{typeOfComment}?"
msgstr ""
+msgid "Are you sure you want to delete this SSH key?"
+msgstr ""
+
msgid "Are you sure you want to delete this board?"
msgstr ""
@@ -3259,6 +3381,11 @@ msgstr ""
msgid "Are you sure you want to erase this build?"
msgstr ""
+msgid "Are you sure you want to import %d repository?"
+msgid_plural "Are you sure you want to import %d repositories?"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Are you sure you want to lose unsaved changes?"
msgstr ""
@@ -3268,15 +3395,15 @@ msgstr ""
msgid "Are you sure you want to merge immediately?"
msgstr ""
-msgid "Are you sure you want to permanently delete this license?"
-msgstr ""
-
msgid "Are you sure you want to re-deploy this environment?"
msgstr ""
msgid "Are you sure you want to regenerate the public key? You will have to update the public key on the remote server before mirroring will work again."
msgstr ""
+msgid "Are you sure you want to reindex?"
+msgstr ""
+
msgid "Are you sure you want to remove %{group_name}?"
msgstr ""
@@ -3304,6 +3431,9 @@ msgstr ""
msgid "Are you sure you want to revoke this nickname?"
msgstr ""
+msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
+msgstr ""
+
msgid "Are you sure you want to stop this environment?"
msgstr ""
@@ -3325,6 +3455,9 @@ msgstr ""
msgid "Are you sure? The device will be signed out of GitLab and all remember me tokens revoked."
msgstr ""
+msgid "Are you sure? This will invalidate your registered applications and U2F / WebAuthn devices."
+msgstr ""
+
msgid "Are you sure? This will invalidate your registered applications and U2F devices."
msgstr ""
@@ -3343,9 +3476,6 @@ msgstr ""
msgid "Artifacts"
msgstr ""
-msgid "As U2F devices are only supported by a few browsers, we require that you set up a two-factor authentication app before a U2F device. That way you'll always be able to log in - even when you're using an unsupported browser."
-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 ""
@@ -3539,6 +3669,9 @@ msgstr ""
msgid "AuditLogs|Target"
msgstr ""
+msgid "AuditLogs|This month"
+msgstr ""
+
msgid "AuditLogs|User Events"
msgstr ""
@@ -3578,6 +3711,9 @@ msgstr ""
msgid "Authentication via U2F device failed."
msgstr ""
+msgid "Authentication via WebAuthn device failed."
+msgstr ""
+
msgid "Author"
msgstr ""
@@ -3845,15 +3981,6 @@ msgstr ""
msgid "BambooService|You must set up automatic revision labeling and a repository trigger in Bamboo."
msgstr ""
-msgid "BatchComments|Delete all pending comments"
-msgstr ""
-
-msgid "BatchComments|Discard review?"
-msgstr ""
-
-msgid "BatchComments|You're about to discard your review which will delete all of your pending comments. The deleted comments %{strong_start}cannot%{strong_end} be restored."
-msgstr ""
-
msgid "Be careful. Changing the project's namespace can have unintended side effects."
msgstr ""
@@ -3875,6 +4002,9 @@ msgstr ""
msgid "Bi-weekly code coverage"
msgstr ""
+msgid "Billable Users:"
+msgstr ""
+
msgid "Billing"
msgstr ""
@@ -3884,7 +4014,7 @@ msgstr ""
msgid "BillingPlans|@%{user_name} you are currently using the %{plan_name} plan."
msgstr ""
-msgid "BillingPlans|Congratulations, your new trial is activated"
+msgid "BillingPlans|Congratulations, your free trial is activated."
msgstr ""
msgid "BillingPlans|If you would like to downgrade your plan please contact %{support_link_start}Customer Support%{support_link_end}."
@@ -3947,6 +4077,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Block user"
+msgstr ""
+
msgid "Blocked"
msgstr ""
@@ -3962,31 +4095,37 @@ msgstr ""
msgid "Blog"
msgstr ""
-msgid "Board name"
-msgstr ""
-
msgid "Board scope"
msgstr ""
msgid "Board scope affects which issues are displayed for anyone who visits this board"
msgstr ""
-msgid "BoardBlankState|Add default lists"
+msgid "Boards"
msgstr ""
-msgid "BoardBlankState|Add the following default lists to your Issue Board with one click:"
+msgid "Boards and Board Lists"
msgstr ""
-msgid "BoardBlankState|Nevermind, I'll use my own"
+msgid "Boards|An error occurred while creating the issue. Please try again."
msgstr ""
-msgid "BoardBlankState|Starting out with the default set of lists will get you right on the way to making the most of your board."
+msgid "Boards|An error occurred while creating the list. Please try again."
msgstr ""
-msgid "Boards"
+msgid "Boards|An error occurred while fetching issues. Please reload the page."
msgstr ""
-msgid "Boards and Board Lists"
+msgid "Boards|An error occurred while fetching the board issues. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching the board swimlanes. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while moving the issue. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while updating the list. Please try again."
msgstr ""
msgid "Boards|Collapse"
@@ -4013,7 +4152,7 @@ msgstr ""
msgid "Branch %{branch_name} was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr ""
-msgid "Branch has changed"
+msgid "Branch changed"
msgstr ""
msgid "Branch is already taken"
@@ -4319,6 +4458,9 @@ msgstr ""
msgid "CLOSED (MOVED)"
msgstr ""
+msgid "CODEOWNERS rule violation"
+msgstr ""
+
msgid "CONTRIBUTING"
msgstr ""
@@ -4349,9 +4491,6 @@ msgstr ""
msgid "Can't create snippet: %{err}"
msgstr ""
-msgid "Can't edit as source branch was deleted"
-msgstr ""
-
msgid "Can't fetch content for the blob: %{err}"
msgstr ""
@@ -4364,9 +4503,6 @@ msgstr ""
msgid "Can't load mermaid module: %{err}"
msgstr ""
-msgid "Can't remove group members without group managed account"
-msgstr ""
-
msgid "Can't scan the code?"
msgstr ""
@@ -4409,6 +4545,9 @@ msgstr ""
msgid "Cannot create the abuse report. This user has been blocked."
msgstr ""
+msgid "Cannot enable shared runners because parent group does not allow it"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -4514,6 +4653,15 @@ msgstr ""
msgid "Change your password or recover your current one"
msgstr ""
+msgid "ChangeReviewer|Reviewer changed from %{old} to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Reviewer changed to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Unassigned"
+msgstr ""
+
msgid "ChangeTypeActionLabel|Pick into branch"
msgstr ""
@@ -4553,6 +4701,9 @@ msgstr ""
msgid "Changes the title to \"%{title_param}\"."
msgstr ""
+msgid "Changes were successfully made."
+msgstr ""
+
msgid "Changes won't take place until the index is %{link_start}recreated%{link_end}."
msgstr ""
@@ -4958,6 +5109,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove variable"
+msgstr ""
+
msgid "CiVariables|Remove variable row"
msgstr ""
@@ -5036,9 +5190,6 @@ msgstr ""
msgid "Clear due date"
msgstr ""
-msgid "Clear input"
-msgstr ""
-
msgid "Clear recent searches"
msgstr ""
@@ -5087,6 +5238,9 @@ msgstr ""
msgid "Client authentication key password"
msgstr ""
+msgid "Client request timeout"
+msgstr ""
+
msgid "Clients"
msgstr ""
@@ -5171,6 +5325,27 @@ msgstr ""
msgid "Cluster type must be specificed for Stages::ClusterEndpointInserter"
msgstr ""
+msgid "ClusterAgents|Configuration"
+msgstr ""
+
+msgid "ClusterAgents|Connect your cluster with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate Kubernetes with a GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Name"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Agent also requires %{linkStart}enabling the Agent Server%{linkEnd}"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Kubernetes Agent allows an Infrastructure as Code, GitOps approach to integrating Kubernetes clusters with GitLab. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "ClusterAgent|This feature is only available for premium plans"
msgstr ""
@@ -5240,10 +5415,10 @@ msgstr ""
msgid "ClusterIntegration|All installed applications and related resources"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster."
+msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{linkStart}More information%{linkEnd}"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{startLink}More information%{endLink}"
+msgid "ClusterIntegration|Allow GitLab to manage namespaces and service accounts for this cluster."
msgstr ""
msgid "ClusterIntegration|Alternatively, "
@@ -5264,6 +5439,9 @@ msgstr ""
msgid "ClusterIntegration|An error occurred while trying to fetch zone machine types: %{error}"
msgstr ""
+msgid "ClusterIntegration|An unknown error occurred while attempting to connect to Kubernetes."
+msgstr ""
+
msgid "ClusterIntegration|Any project namespaces"
msgstr ""
@@ -5279,6 +5457,9 @@ msgstr ""
msgid "ClusterIntegration|Authenticate with Amazon Web Services"
msgstr ""
+msgid "ClusterIntegration|Authentication Error"
+msgstr ""
+
msgid "ClusterIntegration|Base domain"
msgstr ""
@@ -5297,13 +5478,22 @@ msgstr ""
msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}security group %{externalLinkIcon} %{endLink} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
+msgid "ClusterIntegration|Check your CA certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Check your cluster status"
+msgstr ""
+
+msgid "ClusterIntegration|Check your token"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}subnets %{externalLinkIcon} %{endLink} in your VPC where your worker nodes will run."
+msgid "ClusterIntegration|Choose the %{linkStart}security group %{linkEnd} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
msgstr ""
-msgid "ClusterIntegration|Choose the worker node %{startLink}instance type %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Choose the %{linkStart}subnets %{linkEnd} in your VPC where your worker nodes will run."
+msgstr ""
+
+msgid "ClusterIntegration|Choose the worker node %{linkStart}instance type%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Choose which applications to install on your Kubernetes cluster."
@@ -5315,10 +5505,7 @@ msgstr ""
msgid "ClusterIntegration|Clear cluster cache"
msgstr ""
-msgid "ClusterIntegration|Clear the local cache of namespace and service accounts. This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
-msgstr ""
-
-msgid "ClusterIntegration|Cluster being created"
+msgid "ClusterIntegration|Clear the local cache of namespace and service accounts."
msgstr ""
msgid "ClusterIntegration|Cluster management project (alpha)"
@@ -5330,15 +5517,21 @@ msgstr ""
msgid "ClusterIntegration|Cluster_applications artifact too big. Maximum allowable size: %{human_size}"
msgstr ""
-msgid "ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters."
+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|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}"
+msgid "ClusterIntegration|Clusters connected with a certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Connect cluster with certificate"
msgstr ""
msgid "ClusterIntegration|Connect existing cluster"
msgstr ""
+msgid "ClusterIntegration|Connection Error"
+msgstr ""
+
msgid "ClusterIntegration|Copy API URL"
msgstr ""
@@ -5414,6 +5607,12 @@ msgstr ""
msgid "ClusterIntegration|Deletes all GitLab resources attached to this cluster during removal"
msgstr ""
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared."
+msgstr ""
+
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared. %{linkStart}More information%{linkEnd}"
+msgstr ""
+
msgid "ClusterIntegration|Did you know?"
msgstr ""
@@ -5483,6 +5682,9 @@ msgstr ""
msgid "ClusterIntegration|Fluentd is an open source data collector, which lets you unify the data collection and consumption for a better use and understanding of data. It requires at least one of the following logs to be successfully installed."
msgstr ""
+msgid "ClusterIntegration|GitLab Agent managed clusters"
+msgstr ""
+
msgid "ClusterIntegration|GitLab Container Network Policies"
msgstr ""
@@ -5495,6 +5697,12 @@ msgstr ""
msgid "ClusterIntegration|GitLab Runner connects to the repository and executes CI/CD jobs, pushing results back and deploying applications to production."
msgstr ""
+msgid "ClusterIntegration|GitLab failed to authenticate."
+msgstr ""
+
+msgid "ClusterIntegration|GitLab failed to connect to the cluster."
+msgstr ""
+
msgid "ClusterIntegration|GitLab-managed cluster"
msgstr ""
@@ -5516,6 +5724,9 @@ msgstr ""
msgid "ClusterIntegration|Group cluster"
msgstr ""
+msgid "ClusterIntegration|HTTP Error"
+msgstr ""
+
msgid "ClusterIntegration|Helm Tiller"
msgstr ""
@@ -5549,7 +5760,10 @@ msgstr ""
msgid "ClusterIntegration|Instance type"
msgstr ""
-msgid "ClusterIntegration|Integrate Kubernetes cluster automation"
+msgid "ClusterIntegration|Integrate Kubernetes with a cluster certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Integrate with a cluster certificate"
msgstr ""
msgid "ClusterIntegration|Issuer Email"
@@ -5585,9 +5799,6 @@ msgstr ""
msgid "ClusterIntegration|Knative extends Kubernetes to provide a set of middleware components that are essential to build modern, source-centric, and container-based applications that can run anywhere: on premises, in the cloud, or even in a third-party data center."
msgstr ""
-msgid "ClusterIntegration|Kubernetes cluster"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes cluster is being created..."
msgstr ""
@@ -5600,9 +5811,6 @@ msgstr ""
msgid "ClusterIntegration|Kubernetes clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr ""
-msgid "ClusterIntegration|Kubernetes clusters can be used to deploy applications and to provide Review Apps for this project"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes version"
msgstr ""
@@ -5615,7 +5823,7 @@ msgstr ""
msgid "ClusterIntegration|Learn more about %{help_link_start}zones%{help_link_end}."
msgstr ""
-msgid "ClusterIntegration|Learn more about %{startLink}Regions %{externalLinkIcon}%{endLink}."
+msgid "ClusterIntegration|Learn more about %{linkStart}Regions%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Learn more about Kubernetes"
@@ -5660,12 +5868,18 @@ msgstr ""
msgid "ClusterIntegration|Machine type"
msgstr ""
+msgid "ClusterIntegration|Make sure your API endpoint is correct"
+msgstr ""
+
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create Kubernetes clusters"
msgstr ""
msgid "ClusterIntegration|Manage your Kubernetes cluster by visiting %{provider_link}"
msgstr ""
+msgid "ClusterIntegration|Namespace per environment"
+msgstr ""
+
msgid "ClusterIntegration|No IAM Roles found"
msgstr ""
@@ -5711,6 +5925,9 @@ msgstr ""
msgid "ClusterIntegration|No zones matched your search"
msgstr ""
+msgid "ClusterIntegration|Node calculations use the Kubernetes Metrics API. Make sure your cluster has metrics installed"
+msgstr ""
+
msgid "ClusterIntegration|Number of nodes"
msgstr ""
@@ -5753,6 +5970,9 @@ msgstr ""
msgid "ClusterIntegration|RBAC-enabled cluster"
msgstr ""
+msgid "ClusterIntegration|Read our %{linkStart}help page%{linkEnd} on Kubernetes cluster integration."
+msgstr ""
+
msgid "ClusterIntegration|Read our %{link_start}help page%{link_end} on Kubernetes cluster integration."
msgstr ""
@@ -5855,7 +6075,7 @@ msgstr ""
msgid "ClusterIntegration|Select a VPC to choose a subnet"
msgstr ""
-msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{linkStart}Amazon Web Services %{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select a network to choose a subnetwork"
@@ -5888,7 +6108,7 @@ msgstr ""
msgid "ClusterIntegration|Select project to choose zone"
msgstr ""
-msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select zone"
@@ -5978,9 +6198,18 @@ msgstr ""
msgid "ClusterIntegration|There was a problem authenticating with your cluster. Please ensure your CA Certificate and Token are valid."
msgstr ""
+msgid "ClusterIntegration|There was an HTTP error when connecting to your cluster."
+msgstr ""
+
msgid "ClusterIntegration|This account must have permissions to create a Kubernetes cluster in the %{link_to_container_project} specified below"
msgstr ""
+msgid "ClusterIntegration|This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
+msgstr ""
+
+msgid "ClusterIntegration|This is necessary to clear existing environment-namespace associations from clusters previously managed by GitLab."
+msgstr ""
+
msgid "ClusterIntegration|This option will allow you to install applications on RBAC clusters."
msgstr ""
@@ -6005,9 +6234,21 @@ msgstr ""
msgid "ClusterIntegration|To use a new project, first create one on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}."
msgstr ""
+msgid "ClusterIntegration|Troubleshooting tips:"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Authenticate"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Connect"
+msgstr ""
+
msgid "ClusterIntegration|Uninstall %{appTitle}"
msgstr ""
+msgid "ClusterIntegration|Unknown Error"
+msgstr ""
+
msgid "ClusterIntegration|Update %{appTitle}"
msgstr ""
@@ -6068,7 +6309,7 @@ msgstr ""
msgid "ClusterIntegration|Your cluster API is unreachable. Please ensure your API URL is correct."
msgstr ""
-msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Zone"
@@ -6188,6 +6429,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse all threads"
+msgstr ""
+
msgid "Collapse approvers"
msgstr ""
@@ -6337,7 +6581,7 @@ msgstr ""
msgid "Commit…"
msgstr ""
-msgid "Company"
+msgid "Community forum"
msgstr ""
msgid "Company name"
@@ -6346,6 +6590,9 @@ msgstr ""
msgid "Compare"
msgstr ""
+msgid "Compare %{oldCommitId}...%{newCommitId}"
+msgstr ""
+
msgid "Compare Git revisions"
msgstr ""
@@ -6361,6 +6608,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare submodule commit revisions"
+msgstr ""
+
msgid "Compare with previous version"
msgstr ""
@@ -6496,6 +6746,9 @@ msgstr ""
msgid "Configure the way a user creates a new account."
msgstr ""
+msgid "Configure which lists are shown for anyone who visits this board"
+msgstr ""
+
msgid "Confirm"
msgstr ""
@@ -6721,6 +6974,9 @@ msgstr[1] ""
msgid "ContainerRegistry|Set cleanup policy"
msgstr ""
+msgid "ContainerRegistry|Some tags were not deleted"
+msgstr ""
+
msgid "ContainerRegistry|Something went wrong while fetching the cleanup policy."
msgstr ""
@@ -6760,6 +7016,9 @@ msgstr ""
msgid "ContainerRegistry|Tags with names matching this regex pattern will %{italicStart}expire:%{italicEnd}"
msgstr ""
+msgid "ContainerRegistry|The cleanup policy timed out before it could delete all tags. An administrator can %{adminLinkStart}manually run cleanup now%{adminLinkEnd} or you can wait for the cleanup policy to automatically run again. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "ContainerRegistry|The last tag related to this image was recently removed. This empty image and any associated data will be automatically removed as part of the regular Garbage Collection process. If you have any questions, contact your administrator."
msgstr ""
@@ -6892,6 +7151,9 @@ msgstr ""
msgid "Contributions per group member"
msgstr ""
+msgid "Contributor"
+msgstr ""
+
msgid "Contributors"
msgstr ""
@@ -7021,6 +7283,9 @@ msgstr ""
msgid "Could not change HEAD: branch '%{branch}' does not exist"
msgstr ""
+msgid "Could not commit. An unexpected error occurred."
+msgstr ""
+
msgid "Could not connect to FogBugz, check your URL"
msgstr ""
@@ -7060,6 +7325,9 @@ msgstr ""
msgid "Could not find iteration"
msgstr ""
+msgid "Could not load instance counts. Please refresh the page to try again."
+msgstr ""
+
msgid "Could not remove the trigger."
msgstr ""
@@ -7084,10 +7352,10 @@ msgstr ""
msgid "Could not save prometheus manual configuration"
msgstr ""
-msgid "Could not udpdate wiki page"
+msgid "Could not update the LDAP settings"
msgstr ""
-msgid "Could not update the LDAP settings"
+msgid "Could not update wiki page"
msgstr ""
msgid "Could not upload your designs as one or more files uploaded are not supported."
@@ -7745,6 +8013,9 @@ msgstr ""
msgid "DastProfiles|Are you sure you want to delete this profile?"
msgstr ""
+msgid "DastProfiles|Could not create site validation token. Please refresh the page, or try again later."
+msgstr ""
+
msgid "DastProfiles|Could not create the scanner profile. Please try again."
msgstr ""
@@ -7769,6 +8040,12 @@ msgstr ""
msgid "DastProfiles|Could not fetch site profiles. Please refresh the page, or try again later."
msgstr ""
+msgid "DastProfiles|Could not retrieve site validation status. Please refresh the page, or try again later."
+msgstr ""
+
+msgid "DastProfiles|Could not update the scanner profile. Please try again."
+msgstr ""
+
msgid "DastProfiles|Could not update the site profile. Please try again."
msgstr ""
@@ -7784,7 +8061,7 @@ msgstr ""
msgid "DastProfiles|Download validation text file"
msgstr ""
-msgid "DastProfiles|Edit feature will come soon. Please create a new profile if changes needed"
+msgid "DastProfiles|Edit scanner profile"
msgstr ""
msgid "DastProfiles|Edit site profile"
@@ -7817,6 +8094,9 @@ msgstr ""
msgid "DastProfiles|No profiles created yet"
msgstr ""
+msgid "DastProfiles|Passive"
+msgstr ""
+
msgid "DastProfiles|Please enter a valid URL format, ex: http://www.example.com/home"
msgstr ""
@@ -7832,6 +8112,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan mode"
+msgstr ""
+
msgid "DastProfiles|Scanner Profile"
msgstr ""
@@ -7871,10 +8154,10 @@ msgstr ""
msgid "DastProfiles|Text file validation"
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
+msgid "DastProfiles|The maximum number of minutes allowed for the spider to traverse the site."
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the spider to traverse the site."
+msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
msgstr ""
msgid "DastProfiles|Validate"
@@ -7907,6 +8190,9 @@ msgstr ""
msgid "Date picker"
msgstr ""
+msgid "Date range"
+msgstr ""
+
msgid "Date range cannot exceed %{maxDateRange} days."
msgstr ""
@@ -7931,6 +8217,9 @@ msgstr ""
msgid "Days to merge"
msgstr ""
+msgid "Dear Administrator,"
+msgstr ""
+
msgid "Debug"
msgstr ""
@@ -8042,12 +8331,18 @@ msgstr ""
msgid "Delete"
msgstr ""
+msgid "Delete %{name}"
+msgstr ""
+
msgid "Delete Comment"
msgstr ""
msgid "Delete Snippet"
msgstr ""
+msgid "Delete Value Stream"
+msgstr ""
+
msgid "Delete account"
msgstr ""
@@ -8069,9 +8364,6 @@ msgstr ""
msgid "Delete label: %{label_name} ?"
msgstr ""
-msgid "Delete license"
-msgstr ""
-
msgid "Delete list"
msgstr ""
@@ -8147,15 +8439,6 @@ msgstr ""
msgid "Deleting a project places it into a read-only state until %{date}, at which point the project will be permanently deleted. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "Deleting the license failed."
-msgstr ""
-
-msgid "Deleting the license failed. The license was not found."
-msgstr ""
-
-msgid "Deleting the license failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "Deleting the project will delete its repository and all related resources including issues, merge requests etc."
msgstr ""
@@ -8651,7 +8934,10 @@ msgstr ""
msgid "DesignManagement|The maximum number of designs allowed to be uploaded is %{upload_limit}. Please try again."
msgstr ""
-msgid "DesignManagement|To upload designs, you'll need to enable LFS. %{requirements_link_start}More information%{requirements_link_end}"
+msgid "DesignManagement|There was an error moving your designs. Please upload your designs below."
+msgstr ""
+
+msgid "DesignManagement|To upload designs, you'll need to enable LFS and have admin enable hashed storage. %{requirements_link_start}More information%{requirements_link_end}"
msgstr ""
msgid "DesignManagement|Unresolve thread"
@@ -8663,6 +8949,9 @@ msgstr ""
msgid "DesignManagement|Upload skipped."
msgstr ""
+msgid "DesignManagement|Your designs are being copied and are on their way… Please refresh to update."
+msgstr ""
+
msgid "DesignManagement|and %{moreCount} more."
msgstr ""
@@ -8720,6 +9009,9 @@ msgstr ""
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
+msgid "Direct member"
+msgstr ""
+
msgid "Direction"
msgstr ""
@@ -8768,9 +9060,6 @@ msgstr ""
msgid "Discard draft"
msgstr ""
-msgid "Discard review"
-msgstr ""
-
msgid "DiscordService|Discord Notifications"
msgstr ""
@@ -8839,10 +9128,10 @@ msgstr ""
msgid "Dismiss Merge Request promotion"
msgstr ""
-msgid "Dismiss Selected"
+msgid "Dismiss Value Stream Analytics introduction box"
msgstr ""
-msgid "Dismiss Value Stream Analytics introduction box"
+msgid "Dismiss selected"
msgstr ""
msgid "Dismiss trial promotion"
@@ -8893,9 +9182,6 @@ msgstr ""
msgid "Documents reindexed: %{processed_documents} (%{percentage}%%)"
msgstr ""
-msgid "Doing"
-msgstr ""
-
msgid "Domain"
msgstr ""
@@ -9091,9 +9377,6 @@ msgstr ""
msgid "Edit environment"
msgstr ""
-msgid "Edit file"
-msgstr ""
-
msgid "Edit files in the editor and commit changes here"
msgstr ""
@@ -9106,6 +9389,12 @@ msgstr ""
msgid "Edit identity for %{user_name}"
msgstr ""
+msgid "Edit in Web IDE"
+msgstr ""
+
+msgid "Edit in single-file editor"
+msgstr ""
+
msgid "Edit issues"
msgstr ""
@@ -9133,10 +9422,10 @@ msgstr ""
msgid "Editing"
msgstr ""
-msgid "Elasticsearch"
+msgid "Elasticsearch AWS IAM credentials"
msgstr ""
-msgid "Elasticsearch AWS IAM credentials"
+msgid "Elasticsearch HTTP client timeout value in seconds."
msgstr ""
msgid "Elasticsearch indexing restrictions"
@@ -9145,9 +9434,6 @@ msgstr ""
msgid "Elasticsearch indexing started"
msgstr ""
-msgid "Elasticsearch integration. Elasticsearch AWS IAM."
-msgstr ""
-
msgid "Elasticsearch reindexing is already in progress"
msgstr ""
@@ -9175,9 +9461,6 @@ msgstr ""
msgid "Email Notification"
msgstr ""
-msgid "Email address"
-msgstr ""
-
msgid "Email could not be sent"
msgstr ""
@@ -9241,6 +9524,9 @@ msgstr ""
msgid "Emails sent from Service Desk will have this name"
msgstr ""
+msgid "Emails sent to %{email} will still be supported"
+msgstr ""
+
msgid "Emails separated by comma"
msgstr ""
@@ -9274,9 +9560,18 @@ msgstr ""
msgid "Enable"
msgstr ""
+msgid "Enable %{link_start}Gitpod%{link_end} integration to launch a development environment in your browser directly from GitLab."
+msgstr ""
+
msgid "Enable Auto DevOps"
msgstr ""
+msgid "Enable Gitpod"
+msgstr ""
+
+msgid "Enable Gitpod?"
+msgstr ""
+
msgid "Enable HTML emails"
msgstr ""
@@ -9406,9 +9701,6 @@ msgstr ""
msgid "Encountered an error while rendering: %{err}"
msgstr ""
-msgid "End date"
-msgstr ""
-
msgid "Ends at (UTC)"
msgstr ""
@@ -9568,7 +9860,7 @@ msgstr ""
msgid "EnvironmentsDashboard|The environments dashboard provides a summary of each project's environments' status, including pipeline and alert statuses."
msgstr ""
-msgid "EnvironmentsDashboard|This dashboard displays a maximum of 7 projects and 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
+msgid "EnvironmentsDashboard|This dashboard displays 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
msgstr ""
msgid "Environments|An error occurred while canceling the auto stop, please try again"
@@ -9889,6 +10181,9 @@ msgstr ""
msgid "Error deleting project. Check logs for error details."
msgstr ""
+msgid "Error fetching burnup chart data"
+msgstr ""
+
msgid "Error fetching diverging counts for branches. Please try again."
msgstr ""
@@ -9967,6 +10262,9 @@ msgstr ""
msgid "Error occurred when saving assignees"
msgstr ""
+msgid "Error occurred when saving reviewers"
+msgstr ""
+
msgid "Error occurred when toggling the notification subscription"
msgstr ""
@@ -10219,10 +10517,13 @@ msgstr ""
msgid "Expand all"
msgstr ""
-msgid "Expand approvers"
+msgid "Expand all files"
msgstr ""
-msgid "Expand dropdown"
+msgid "Expand all threads"
+msgstr ""
+
+msgid "Expand approvers"
msgstr ""
msgid "Expand milestones"
@@ -10393,6 +10694,9 @@ msgstr ""
msgid "Failed to create Merge Request. Please try again."
msgstr ""
+msgid "Failed to create To-Do for the design."
+msgstr ""
+
msgid "Failed to create a branch for this issue. Please try again."
msgstr ""
@@ -10432,6 +10736,12 @@ msgstr ""
msgid "Failed to load authors. Please try again."
msgstr ""
+msgid "Failed to load branches. Please try again."
+msgstr ""
+
+msgid "Failed to load deploy keys."
+msgstr ""
+
msgid "Failed to load emoji list."
msgstr ""
@@ -10447,6 +10757,9 @@ msgstr ""
msgid "Failed to load groups & users."
msgstr ""
+msgid "Failed to load groups, users and deploy keys."
+msgstr ""
+
msgid "Failed to load labels. Please try again."
msgstr ""
@@ -10456,6 +10769,12 @@ msgstr ""
msgid "Failed to load related branches"
msgstr ""
+msgid "Failed to load sidebar confidential toggle"
+msgstr ""
+
+msgid "Failed to load sidebar lock status"
+msgstr ""
+
msgid "Failed to load stacktrace."
msgstr ""
@@ -10483,6 +10802,9 @@ msgstr ""
msgid "Failed to publish issue on status page."
msgstr ""
+msgid "Failed to remove To-Do for the design."
+msgstr ""
+
msgid "Failed to remove a Zoom meeting"
msgstr ""
@@ -10525,6 +10847,9 @@ msgstr ""
msgid "Failed to signing using smartcard authentication"
msgstr ""
+msgid "Failed to toggle To-Do for the design."
+msgstr ""
+
msgid "Failed to update branch!"
msgstr ""
@@ -10638,7 +10963,7 @@ msgstr ""
msgid "FeatureFlags|Edit User List"
msgstr ""
-msgid "FeatureFlags|Enable features for specific users and specific environments by defining feature flag strategies."
+msgid "FeatureFlags|Enable features for specific users and environments by configuring feature flag strategies."
msgstr ""
msgid "FeatureFlags|Environment Spec"
@@ -10698,7 +11023,7 @@ msgstr ""
msgid "FeatureFlags|Include additional user IDs"
msgstr ""
-msgid "FeatureFlags|Install a %{docs_link_anchored_start}compatible client library%{docs_link_anchored_end} and specify the API URL, application name, and instance ID during the configuration setup. %{docs_link_start}More Information%{docs_link_end}"
+msgid "FeatureFlags|Install a %{docsLinkAnchoredStart}compatible client library%{docsLinkAnchoredEnd} and specify the API URL, application name, and instance ID during the configuration setup. %{docsLinkStart}More Information%{docsLinkEnd}"
msgstr ""
msgid "FeatureFlags|Instance ID"
@@ -10710,6 +11035,9 @@ msgstr ""
msgid "FeatureFlags|Loading feature flags"
msgstr ""
+msgid "FeatureFlags|Loading user lists"
+msgstr ""
+
msgid "FeatureFlags|More information"
msgstr ""
@@ -10728,7 +11056,7 @@ msgstr ""
msgid "FeatureFlags|New feature flag"
msgstr ""
-msgid "FeatureFlags|New list"
+msgid "FeatureFlags|New user list"
msgstr ""
msgid "FeatureFlags|Percent of users"
@@ -10767,6 +11095,9 @@ msgstr ""
msgid "FeatureFlags|There was an error fetching the feature flags."
msgstr ""
+msgid "FeatureFlags|There was an error fetching the user lists."
+msgstr ""
+
msgid "FeatureFlags|There was an error retrieving user lists"
msgstr ""
@@ -10782,6 +11113,9 @@ msgstr ""
msgid "FeatureFlags|User List"
msgstr ""
+msgid "FeatureFlags|User Lists"
+msgstr ""
+
msgid "FeatureFlag|List"
msgstr ""
@@ -10809,15 +11143,6 @@ msgstr ""
msgid "Fetching incoming email"
msgstr ""
-msgid "Fetching licenses failed."
-msgstr ""
-
-msgid "Fetching licenses failed. The request endpoint was not found."
-msgstr ""
-
-msgid "Fetching licenses failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "File"
msgstr ""
@@ -10920,12 +11245,21 @@ msgstr ""
msgid "Filter by status"
msgstr ""
+msgid "Filter by test cases that are currently archived."
+msgstr ""
+
+msgid "Filter by test cases that are currently opened."
+msgstr ""
+
msgid "Filter by two-factor authentication"
msgstr ""
msgid "Filter by user"
msgstr ""
+msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
+msgstr ""
+
msgid "Filter pipelines"
msgstr ""
@@ -10941,7 +11275,7 @@ msgstr ""
msgid "Filter results..."
msgstr ""
-msgid "Filter your projects by name"
+msgid "Filter your repositories by name"
msgstr ""
msgid "Filter..."
@@ -10950,7 +11284,7 @@ msgstr ""
msgid "Find File"
msgstr ""
-msgid "Find bugs in your code with coverage-guided fuzzing"
+msgid "Find bugs in your code with coverage-guided fuzzing."
msgstr ""
msgid "Find by path"
@@ -10977,9 +11311,6 @@ msgstr ""
msgid "Finish editing this message first!"
msgstr ""
-msgid "Finish review"
-msgstr ""
-
msgid "Finish setting up your dedicated account for %{group_name}."
msgstr ""
@@ -11049,6 +11380,9 @@ msgstr ""
msgid "Footer message"
msgstr ""
+msgid "For a faster browsing experience, some files are collapsed by default."
+msgstr ""
+
msgid "For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
@@ -11058,6 +11392,9 @@ msgstr ""
msgid "For more info, read the documentation."
msgstr ""
+msgid "For more information on how the number of active users is calculated, see the %{self_managed_subscriptions_doc_link} documentation."
+msgstr ""
+
msgid "For more information, go to the "
msgstr ""
@@ -11196,6 +11533,9 @@ msgstr ""
msgid "Generate new token"
msgstr ""
+msgid "Generic package file size in bytes"
+msgstr ""
+
msgid "Geo"
msgstr ""
@@ -11457,6 +11797,9 @@ msgstr ""
msgid "Geo|Please refer to Geo Troubleshooting."
msgstr ""
+msgid "Geo|Primary node"
+msgstr ""
+
msgid "Geo|Project"
msgstr ""
@@ -11499,6 +11842,9 @@ msgstr ""
msgid "Geo|Review replication status, and resynchronize and reverify items with the primary node."
msgstr ""
+msgid "Geo|Secondary node"
+msgstr ""
+
msgid "Geo|Status"
msgstr ""
@@ -11538,6 +11884,9 @@ msgstr ""
msgid "Geo|URL must be a valid url (ex: https://gitlab.com)"
msgstr ""
+msgid "Geo|Undefined"
+msgstr ""
+
msgid "Geo|Unknown state"
msgstr ""
@@ -11613,10 +11962,16 @@ msgstr ""
msgid "GitHub import"
msgstr ""
+msgid "GitLab"
+msgstr ""
+
msgid "GitLab / Unsubscribe"
msgstr ""
-msgid "GitLab Enterprise Edition %{plan}"
+msgid "GitLab API"
+msgstr ""
+
+msgid "GitLab Billing Team."
msgstr ""
msgid "GitLab Group Runners can execute code for all the projects in this group."
@@ -11628,12 +11983,18 @@ msgstr ""
msgid "GitLab Issue"
msgstr ""
+msgid "GitLab Pages"
+msgstr ""
+
msgid "GitLab Service Desk is a simple way to allow people to create issues in your GitLab instance without needing their own user account. It provides a unique email address for end users to create issues in a project, and replies can be sent either through the GitLab interface or by email. End users will only see the thread through email."
msgstr ""
msgid "GitLab Shared Runners execute code of different projects on the same Runner unless you configure GitLab Runner Autoscale with MaxBuilds 1 (which it is on GitLab.com)."
msgstr ""
+msgid "GitLab Shell"
+msgstr ""
+
msgid "GitLab Support Bot"
msgstr ""
@@ -11643,7 +12004,7 @@ msgstr ""
msgid "GitLab User"
msgstr ""
-msgid "GitLab allows you to continue using your license even if you exceed the number of seats you purchased. You will be required to pay for these seats when you renew your license."
+msgid "GitLab Workhorse"
msgstr ""
msgid "GitLab commit"
@@ -11811,6 +12172,21 @@ msgstr ""
msgid "Gitlab Pages"
msgstr ""
+msgid "Gitpod"
+msgstr ""
+
+msgid "Gitpod|Add the URL to your Gitpod instance configured to read your GitLab projects."
+msgstr ""
+
+msgid "Gitpod|Enable Gitpod integration"
+msgstr ""
+
+msgid "Gitpod|Gitpod URL"
+msgstr ""
+
+msgid "Gitpod|e.g. https://gitpod.example.com"
+msgstr ""
+
msgid "Given access %{time_ago}"
msgstr ""
@@ -12318,9 +12694,6 @@ msgstr ""
msgid "GroupSAML|Valid SAML Response"
msgstr ""
-msgid "GroupSAML|With group managed accounts enabled, all the users without a group managed account will be excluded from the group."
-msgstr ""
-
msgid "GroupSAML|With prohibit outer forks flag enabled group members will be able to fork project only inside your group."
msgstr ""
@@ -12534,10 +12907,10 @@ msgstr ""
msgid "GroupsNew|Create group"
msgstr ""
-msgid "GroupsNew|GitLab group export"
+msgid "GroupsNew|Import"
msgstr ""
-msgid "GroupsNew|Import"
+msgid "GroupsNew|Import a GitLab group export file"
msgstr ""
msgid "GroupsNew|Import group"
@@ -12680,6 +13053,9 @@ msgid_plural "Hide charts"
msgstr[0] ""
msgstr[1] ""
+msgid "Hide comments on this file"
+msgstr ""
+
msgid "Hide details"
msgstr ""
@@ -12724,6 +13100,15 @@ msgstr ""
msgid "Highest role:"
msgstr ""
+msgid "HighlightBar|Alert events:"
+msgstr ""
+
+msgid "HighlightBar|Alert start time:"
+msgstr ""
+
+msgid "HighlightBar|Original alert:"
+msgstr ""
+
msgid "History"
msgstr ""
@@ -12901,6 +13286,9 @@ msgstr ""
msgid "If enabled, access to projects will be validated on an external service using their classification label."
msgstr ""
+msgid "If the number of active users exceeds the user limit, you will be charged for the number of %{users_over_license_link} at your next license reconciliation."
+msgstr ""
+
msgid "If there is no previous license or if the previous license has expired, some GitLab functionality will be blocked until a new, valid license is uploaded."
msgstr ""
@@ -12940,9 +13328,6 @@ msgstr ""
msgid "If your HTTP repository is not publicly accessible, add your credentials."
msgstr ""
-msgid "Iglu registry URL (optional)"
-msgstr ""
-
msgid "Ignore"
msgstr ""
@@ -12979,6 +13364,16 @@ msgstr ""
msgid "Import"
msgstr ""
+msgid "Import %d compatible repository"
+msgid_plural "Import %d compatible repositories"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Import %d repository"
+msgid_plural "Import %d repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Import CSV"
msgstr ""
@@ -12988,15 +13383,9 @@ msgstr ""
msgid "Import all compatible projects"
msgstr ""
-msgid "Import all compatible repositories"
-msgstr ""
-
msgid "Import all projects"
msgstr ""
-msgid "Import all repositories"
-msgstr ""
-
msgid "Import an exported GitLab project"
msgstr ""
@@ -13084,6 +13473,9 @@ msgstr ""
msgid "ImportProjects|Error importing repository %{project_safe_import_url} into %{project_full_path} - %{message}"
msgstr ""
+msgid "ImportProjects|Import repositories"
+msgstr ""
+
msgid "ImportProjects|Importing the project failed"
msgstr ""
@@ -13096,7 +13488,7 @@ msgstr ""
msgid "ImportProjects|Requesting your %{provider} repositories failed"
msgstr ""
-msgid "ImportProjects|Select the projects you want to import"
+msgid "ImportProjects|Select the repositories you want to import"
msgstr ""
msgid "ImportProjects|The remote data could not be imported."
@@ -13132,9 +13524,6 @@ msgstr ""
msgid "In order to enable Service Desk for your instance, you must first set up incoming email."
msgstr ""
-msgid "In order to gather accurate feature usage data, it can take 1 to 2 weeks to see your index."
-msgstr ""
-
msgid "In order to personalize your experience with GitLab%{br_tag}we would like to know a bit more about you."
msgstr ""
@@ -13165,18 +13554,30 @@ msgstr ""
msgid "IncidentManagement|Create incident"
msgstr ""
+msgid "IncidentManagement|Critical - S1"
+msgstr ""
+
msgid "IncidentManagement|Date created"
msgstr ""
msgid "IncidentManagement|Display your incidents in a dedicated view"
msgstr ""
+msgid "IncidentManagement|High - S2"
+msgstr ""
+
msgid "IncidentManagement|Incident"
msgstr ""
msgid "IncidentManagement|Incidents"
msgstr ""
+msgid "IncidentManagement|Low - S4"
+msgstr ""
+
+msgid "IncidentManagement|Medium - S3"
+msgstr ""
+
msgid "IncidentManagement|No incidents to display."
msgstr ""
@@ -13189,6 +13590,9 @@ msgstr ""
msgid "IncidentManagement|Published to status page"
msgstr ""
+msgid "IncidentManagement|Severity"
+msgstr ""
+
msgid "IncidentManagement|There are no closed incidents"
msgstr ""
@@ -13198,6 +13602,9 @@ msgstr ""
msgid "IncidentManagement|Unassigned"
msgstr ""
+msgid "IncidentManagement|Unknown"
+msgstr ""
+
msgid "IncidentManagement|Unpublished"
msgstr ""
@@ -13219,6 +13626,15 @@ msgstr ""
msgid "Incidents"
msgstr ""
+msgid "Incident|Alert details"
+msgstr ""
+
+msgid "Incident|Summary"
+msgstr ""
+
+msgid "Incident|There was an issue loading alert data. Please try again."
+msgstr ""
+
msgid "Include a Terms of Service agreement and Privacy Policy that all users must accept."
msgstr ""
@@ -13279,6 +13695,9 @@ msgstr ""
msgid "Information about additional Pages templates and how to install them can be found in our %{pages_getting_started_guide}."
msgstr ""
+msgid "Inherited"
+msgstr ""
+
msgid "Inherited:"
msgstr ""
@@ -13359,7 +13778,22 @@ msgstr ""
msgid "Instance administrators group already exists"
msgstr ""
-msgid "Instance license"
+msgid "InstanceStatistics|Groups"
+msgstr ""
+
+msgid "InstanceStatistics|Issues"
+msgstr ""
+
+msgid "InstanceStatistics|Merge Requests"
+msgstr ""
+
+msgid "InstanceStatistics|Pipelines"
+msgstr ""
+
+msgid "InstanceStatistics|Projects"
+msgstr ""
+
+msgid "InstanceStatistics|Users"
msgstr ""
msgid "Integration"
@@ -13371,6 +13805,12 @@ msgstr ""
msgid "Integrations"
msgstr ""
+msgid "Integrations|%{integration} settings saved and active."
+msgstr ""
+
+msgid "Integrations|%{integration} settings saved, but not active."
+msgstr ""
+
msgid "Integrations|All details"
msgstr ""
@@ -13380,6 +13820,12 @@ msgstr ""
msgid "Integrations|Comment settings:"
msgstr ""
+msgid "Integrations|Connection failed. Please check your settings."
+msgstr ""
+
+msgid "Integrations|Connection successful."
+msgstr ""
+
msgid "Integrations|Default settings are inherited from the group level."
msgstr ""
@@ -13395,6 +13841,15 @@ msgstr ""
msgid "Integrations|Includes commit title and branch"
msgstr ""
+msgid "Integrations|Projects using custom settings will not be impacted unless the project owner chooses to use instance-level defaults."
+msgstr ""
+
+msgid "Integrations|Save settings?"
+msgstr ""
+
+msgid "Integrations|Saving will update the default settings for all projects that are not using custom settings."
+msgstr ""
+
msgid "Integrations|Standard"
msgstr ""
@@ -13527,6 +13982,9 @@ msgstr ""
msgid "Invitation"
msgstr ""
+msgid "Invitation declined"
+msgstr ""
+
msgid "Invite"
msgstr ""
@@ -13578,6 +14036,42 @@ 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|%{linkStart}Read more%{linkEnd} about role permissions"
+msgstr ""
+
+msgid "InviteMembersModal|Access expiration date (optional)"
+msgstr ""
+
+msgid "InviteMembersModal|Cancel"
+msgstr ""
+
+msgid "InviteMembersModal|Choose a role permission"
+msgstr ""
+
+msgid "InviteMembersModal|GitLab member or Email address"
+msgstr ""
+
+msgid "InviteMembersModal|Invite"
+msgstr ""
+
+msgid "InviteMembersModal|Invite team members"
+msgstr ""
+
+msgid "InviteMembersModal|Search for members to invite"
+msgstr ""
+
+msgid "InviteMembersModal|User not invited. Feature coming soon!"
+msgstr ""
+
+msgid "InviteMembersModal|Users were succesfully added"
+msgstr ""
+
+msgid "InviteMembersModal|You're inviting members to the %{group_name} group"
+msgstr ""
+
+msgid "InviteMembers|Invite team members"
+msgstr ""
+
msgid "Invited"
msgstr ""
@@ -13632,10 +14126,13 @@ msgstr ""
msgid "Issue cannot be found."
msgstr ""
+msgid "Issue created from vulnerability %{vulnerability_link}"
+msgstr ""
+
msgid "Issue events"
msgstr ""
-msgid "Issue first depoloyed to production"
+msgid "Issue first deployed to production"
msgstr ""
msgid "Issue label"
@@ -13713,6 +14210,9 @@ msgstr ""
msgid "IssueTracker|Custom issue tracker"
msgstr ""
+msgid "IssueTracker|EWM work items tracker"
+msgstr ""
+
msgid "IssueTracker|Redmine issue tracker"
msgstr ""
@@ -13779,6 +14279,9 @@ msgstr ""
msgid "It looks like you have some draft commits in this branch."
msgstr ""
+msgid "It may be several days before you see feature usage data."
+msgstr ""
+
msgid "It must have a header row and at least two columns: the first column is the issue title and the second column is the issue description. The separator is automatically detected."
msgstr ""
@@ -14061,13 +14564,13 @@ msgstr ""
msgid "Join Zoom meeting"
msgstr ""
-msgid "Jul"
+msgid "Joined %{time_ago}"
msgstr ""
-msgid "July"
+msgid "Jul"
msgstr ""
-msgid "Jump to first unresolved thread"
+msgid "July"
msgstr ""
msgid "Jump to next unresolved thread"
@@ -14103,6 +14606,9 @@ msgstr ""
msgid "Keyboard shortcuts"
msgstr ""
+msgid "KeyboardKey|Ctrl+"
+msgstr ""
+
msgid "Keys"
msgstr ""
@@ -14151,6 +14657,9 @@ msgstr ""
msgid "LDAP Synchronization"
msgstr ""
+msgid "LDAP group settings"
+msgstr ""
+
msgid "LDAP settings"
msgstr ""
@@ -14160,6 +14669,9 @@ msgstr ""
msgid "LDAP sync in progress. This could take a few minutes. Refresh the page to see the changes."
msgstr ""
+msgid "LDAP synchronizations"
+msgstr ""
+
msgid "LFS"
msgstr ""
@@ -14240,7 +14752,16 @@ msgid_plural "Last %d days"
msgstr[0] ""
msgstr[1] ""
-msgid "Last %{days} days"
+msgid "Last 2 weeks"
+msgstr ""
+
+msgid "Last 30 days"
+msgstr ""
+
+msgid "Last 60 days"
+msgstr ""
+
+msgid "Last 90 days"
msgstr ""
msgid "Last Accessed On"
@@ -14318,6 +14839,9 @@ msgstr ""
msgid "Last used on:"
msgstr ""
+msgid "Last week"
+msgstr ""
+
msgid "LastCommit|authored"
msgstr ""
@@ -14333,6 +14857,9 @@ msgstr ""
msgid "Latest pipeline for the most recent commit on this branch"
msgstr ""
+msgid "Launch a ready-to-code development environment for your project."
+msgstr ""
+
msgid "Lead"
msgstr ""
@@ -14713,6 +15240,9 @@ msgstr ""
msgid "List of all merge commits"
msgstr ""
+msgid "List options"
+msgstr ""
+
msgid "List settings"
msgstr ""
@@ -14725,9 +15255,6 @@ msgstr ""
msgid "List your Bitbucket Server repositories"
msgstr ""
-msgid "Lists"
-msgstr ""
-
msgid "Live preview"
msgstr ""
@@ -14974,6 +15501,12 @@ msgstr ""
msgid "Mark as done"
msgstr ""
+msgid "Mark as draft"
+msgstr ""
+
+msgid "Mark as ready"
+msgstr ""
+
msgid "Mark as resolved"
msgstr ""
@@ -14995,6 +15528,24 @@ msgstr ""
msgid "Markdown is supported"
msgstr ""
+msgid "MarkdownEditor|Add a link (%{modifierKey}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add a link (%{modifier_key}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifierKey}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifier_key}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifierKey}I)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifier_key}I)"
+msgstr ""
+
msgid "Marked For Deletion At - %{deletion_time}"
msgstr ""
@@ -15079,7 +15630,25 @@ msgstr ""
msgid "Max access level"
msgstr ""
-msgid "Max seats used"
+msgid "Max role"
+msgstr ""
+
+msgid "Max size 15 MB"
+msgstr ""
+
+msgid "Maximum Conan package file size in bytes"
+msgstr ""
+
+msgid "Maximum Maven package file size in bytes"
+msgstr ""
+
+msgid "Maximum NPM package file size in bytes"
+msgstr ""
+
+msgid "Maximum NuGet package file size in bytes"
+msgstr ""
+
+msgid "Maximum PyPI package file size in bytes"
msgstr ""
msgid "Maximum Users:"
@@ -15211,6 +15780,18 @@ msgstr ""
msgid "Members with access to %{strong_start}%{group_name}%{strong_end}"
msgstr ""
+msgid "Members|%{time} by %{user}"
+msgstr ""
+
+msgid "Members|Expired"
+msgstr ""
+
+msgid "Members|No expiration set"
+msgstr ""
+
+msgid "Members|in %{time}"
+msgstr ""
+
msgid "Memory Usage"
msgstr ""
@@ -15397,9 +15978,6 @@ msgstr ""
msgid "MergeRequests|Thread will be unresolved"
msgstr ""
-msgid "MergeRequests|Toggle comments for this file"
-msgstr ""
-
msgid "MergeRequests|View file @ %{commitId}"
msgstr ""
@@ -15460,6 +16038,9 @@ msgstr ""
msgid "Merging immediately isn't recommended as it may negatively impact the existing merge train. Read the %{docsLinkStart}documentation%{docsLinkEnd} for more information."
msgstr ""
+msgid "Message"
+msgstr ""
+
msgid "Messages"
msgstr ""
@@ -15845,18 +16426,12 @@ msgid_plural "Milestones"
msgstr[0] ""
msgstr[1] ""
-msgid "Milestone does not support burnup charts"
-msgstr ""
-
msgid "Milestone lists not available with your current license"
msgstr ""
msgid "Milestone lists show all issues from the selected milestone."
msgstr ""
-msgid "Milestone must have a start and due date"
-msgstr ""
-
msgid "MilestoneSidebar|Closed:"
msgstr ""
@@ -16223,6 +16798,9 @@ msgstr ""
msgid "Namespace"
msgstr ""
+msgid "Namespace ID:"
+msgstr ""
+
msgid "Namespace is empty"
msgstr ""
@@ -16307,6 +16885,9 @@ msgstr ""
msgid "NetworkPolicies|Allow all outbound traffic from %{selector} to %{ruleSelector} on %{ports}"
msgstr ""
+msgid "NetworkPolicies|Are you sure you want to delete this policy? This action cannot be undone."
+msgstr ""
+
msgid "NetworkPolicies|Choose whether to enforce this policy."
msgstr ""
@@ -16316,12 +16897,21 @@ msgstr ""
msgid "NetworkPolicies|Define this policy's location, conditions and actions."
msgstr ""
+msgid "NetworkPolicies|Delete policy"
+msgstr ""
+
+msgid "NetworkPolicies|Delete policy: %{policy}"
+msgstr ""
+
msgid "NetworkPolicies|Deny all traffic"
msgstr ""
msgid "NetworkPolicies|Description"
msgstr ""
+msgid "NetworkPolicies|Edit policy"
+msgstr ""
+
msgid "NetworkPolicies|Editor mode"
msgstr ""
@@ -16349,6 +16939,9 @@ msgstr ""
msgid "NetworkPolicies|Name"
msgstr ""
+msgid "NetworkPolicies|Namespace"
+msgstr ""
+
msgid "NetworkPolicies|Network Policy"
msgstr ""
@@ -16400,6 +16993,9 @@ msgstr ""
msgid "NetworkPolicies|Rules"
msgstr ""
+msgid "NetworkPolicies|Save changes"
+msgstr ""
+
msgid "NetworkPolicies|Something went wrong, failed to update policy"
msgstr ""
@@ -16412,6 +17008,9 @@ msgstr ""
msgid "NetworkPolicies|Traffic that does not match any rule will be blocked."
msgstr ""
+msgid "NetworkPolicies|Unable to parse policy"
+msgstr ""
+
msgid "NetworkPolicies|YAML editor"
msgstr ""
@@ -16525,6 +17124,9 @@ msgstr ""
msgid "New Snippet"
msgstr ""
+msgid "New Test Case"
+msgstr ""
+
msgid "New User"
msgstr ""
@@ -16624,6 +17226,9 @@ msgstr ""
msgid "New tag"
msgstr ""
+msgid "New test case"
+msgstr ""
+
msgid "New users set to external"
msgstr ""
@@ -16696,7 +17301,7 @@ msgstr ""
msgid "No changes"
msgstr ""
-msgid "No changes between %{ref_start}%{source_branch}%{ref_end} and %{ref_start}%{target_branch}%{ref_end}"
+msgid "No changes between %{sourceBranch} and %{targetBranch}"
msgstr ""
msgid "No child epics match applied filters"
@@ -16711,6 +17316,9 @@ msgstr ""
msgid "No containers available"
msgstr ""
+msgid "No content to show"
+msgstr ""
+
msgid "No contributions"
msgstr ""
@@ -16786,9 +17394,6 @@ msgstr ""
msgid "No license. All rights reserved"
msgstr ""
-msgid "No licenses found."
-msgstr ""
-
msgid "No matches found"
msgstr ""
@@ -16801,6 +17406,9 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No members found"
+msgstr ""
+
msgid "No merge requests found"
msgstr ""
@@ -16822,6 +17430,9 @@ msgstr ""
msgid "No parent group"
msgstr ""
+msgid "No plan"
+msgstr ""
+
msgid "No pods available"
msgstr ""
@@ -16918,6 +17529,12 @@ msgstr ""
msgid "Not Implemented"
msgstr ""
+msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+msgstr ""
+
+msgid "Not all browsers support WebAuthn. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even from an unsupported browser."
+msgstr ""
+
msgid "Not all data has been processed yet, the accuracy of the chart for the selected timeframe is limited."
msgstr ""
@@ -17014,6 +17631,9 @@ msgstr ""
msgid "Notification settings saved"
msgstr ""
+msgid "NotificationEvent|Change reviewer merge request"
+msgstr ""
+
msgid "NotificationEvent|Close issue"
msgstr ""
@@ -17176,10 +17796,7 @@ msgstr ""
msgid "On track"
msgstr ""
-msgid "OnDemandScans|Attached branch"
-msgstr ""
-
-msgid "OnDemandScans|Attached branch is where the scan job runs."
+msgid "OnDemandScans|Could not fetch scanner profiles. Please refresh the page, or try again later."
msgstr ""
msgid "OnDemandScans|Could not fetch site profiles. Please refresh the page, or try again later."
@@ -17188,6 +17805,9 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
+msgid "OnDemandScans|Create a new scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Create a new site profile"
msgstr ""
@@ -17200,6 +17820,9 @@ msgstr ""
msgid "OnDemandScans|New on-demand DAST scan"
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 ""
@@ -17209,16 +17832,10 @@ msgstr ""
msgid "OnDemandScans|On-demand scans run outside the DevOps cycle and find vulnerabilities in your projects. %{learnMoreLinkStart}Learn more%{learnMoreLinkEnd}"
msgstr ""
-msgid "OnDemandScans|Only a passive scan can be performed on demand."
-msgstr ""
-
-msgid "OnDemandScans|Passive"
-msgstr ""
-
msgid "OnDemandScans|Run scan"
msgstr ""
-msgid "OnDemandScans|Scan mode"
+msgid "OnDemandScans|Scanner profile"
msgstr ""
msgid "OnDemandScans|Scanner settings"
@@ -17230,9 +17847,15 @@ msgstr ""
msgid "OnDemandScans|Select one of the existing profiles"
msgstr ""
+msgid "OnDemandScans|Site profile"
+msgstr ""
+
msgid "OnDemandScans|Site profiles"
msgstr ""
+msgid "OnDemandScans|Use existing scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Use existing site profile"
msgstr ""
@@ -17331,9 +17954,6 @@ msgstr ""
msgid "Open Selection"
msgstr ""
-msgid "Open Web IDE"
-msgstr ""
-
msgid "Open comment type dropdown"
msgstr ""
@@ -17439,6 +18059,9 @@ msgstr ""
msgid "Origin"
msgstr ""
+msgid "Orphaned member"
+msgstr ""
+
msgid "Other Labels"
msgstr ""
@@ -17454,6 +18077,9 @@ msgstr ""
msgid "Other visibility settings have been disabled by the administrator."
msgstr ""
+msgid "Our documentation includes an example DevOps Score report."
+msgstr ""
+
msgid "Out-of-compliance with this project's policies and should be removed"
msgstr ""
@@ -17478,6 +18104,9 @@ msgstr ""
msgid "Overwrite diverged branches"
msgstr ""
+msgid "Owned by %{image_tag}"
+msgstr ""
+
msgid "Owned by anyone"
msgstr ""
@@ -17499,6 +18128,9 @@ msgstr ""
msgid "Package deleted successfully"
msgstr ""
+msgid "Package file size limits"
+msgstr ""
+
msgid "Package recipe already exists"
msgstr ""
@@ -17514,9 +18146,6 @@ msgstr ""
msgid "Package type must be PyPi"
msgstr ""
-msgid "Package was removed"
-msgstr ""
-
msgid "PackageRegistry|%{name} version %{version} was created %{datetime}"
msgstr ""
@@ -17658,12 +18287,18 @@ msgstr ""
msgid "PackageRegistry|NuGet Command"
msgstr ""
+msgid "PackageRegistry|Package Registry"
+msgstr ""
+
msgid "PackageRegistry|Pip Command"
msgstr ""
msgid "PackageRegistry|Pipeline %{link} triggered %{datetime} by %{author}"
msgstr ""
+msgid "PackageRegistry|Publish and share packages for a variety of common package managers. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "PackageRegistry|Published to the %{project} Package Registry %{datetime}"
msgstr ""
@@ -17763,6 +18398,9 @@ msgstr ""
msgid "Page not found"
msgstr ""
+msgid "Page settings"
+msgstr ""
+
msgid "Page was successfully deleted"
msgstr ""
@@ -17904,7 +18542,7 @@ msgstr ""
msgid "Paste issue link"
msgstr ""
-msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Don't use your private SSH key."
+msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Do not paste your private SSH key, as that can compromise your identity."
msgstr ""
msgid "Patch to apply"
@@ -17931,6 +18569,9 @@ msgstr ""
msgid "Pending"
msgstr ""
+msgid "Pending comments"
+msgstr ""
+
msgid "People without permission will never get a notification and won't be able to comment."
msgstr ""
@@ -18129,6 +18770,9 @@ msgstr ""
msgid "Pipelines|Build with confidence"
msgstr ""
+msgid "Pipelines|By revoking a trigger you will break any processes making use of it. Are you sure?"
+msgstr ""
+
msgid "Pipelines|CI Lint"
msgstr ""
@@ -18141,6 +18785,15 @@ msgstr ""
msgid "Pipelines|Continuous Integration can help catch bugs by running your tests automatically, while Continuous Deployment can help you deliver code to your product environment."
msgstr ""
+msgid "Pipelines|Copy trigger token"
+msgstr ""
+
+msgid "Pipelines|Description"
+msgstr ""
+
+msgid "Pipelines|Edit"
+msgstr ""
+
msgid "Pipelines|Get started with Pipelines"
msgstr ""
@@ -18156,15 +18809,27 @@ msgstr ""
msgid "Pipelines|It is recommended the code is reviewed thoroughly before running this pipeline with the parent project's CI resource."
msgstr ""
+msgid "Pipelines|Last Used"
+msgstr ""
+
msgid "Pipelines|Loading Pipelines"
msgstr ""
msgid "Pipelines|More Information"
msgstr ""
+msgid "Pipelines|No triggers have been created yet. Add one using the form above."
+msgstr ""
+
+msgid "Pipelines|Owner"
+msgstr ""
+
msgid "Pipelines|Project cache successfully reset."
msgstr ""
+msgid "Pipelines|Revoke"
+msgstr ""
+
msgid "Pipelines|Run Pipeline"
msgstr ""
@@ -18189,6 +18854,15 @@ msgstr ""
msgid "Pipelines|This project is not currently set up to run pipelines."
msgstr ""
+msgid "Pipelines|Token"
+msgstr ""
+
+msgid "Pipelines|Trigger user has insufficient permissions to project"
+msgstr ""
+
+msgid "Pipelines|invalid"
+msgstr ""
+
msgid "Pipelines|parent"
msgstr ""
@@ -18447,10 +19121,10 @@ msgstr ""
msgid "Please provide attributes to update"
msgstr ""
-msgid "Please refer to %{docs_url}"
+msgid "Please reach out if you have any questions and we'll be happy to assist."
msgstr ""
-msgid "Please retype the email address."
+msgid "Please refer to %{docs_url}"
msgstr ""
msgid "Please select"
@@ -18480,6 +19154,9 @@ msgstr ""
msgid "Please set a new password before proceeding."
msgstr ""
+msgid "Please share your feedback about %{featureName} %{linkStart}in this issue%{linkEnd} to help us improve the experience."
+msgstr ""
+
msgid "Please solve the reCAPTCHA"
msgstr ""
@@ -18783,6 +19460,9 @@ msgstr ""
msgid "Profiles| You are going to change the username %{currentUsernameBold} to %{newUsernameBold}. Profile and projects will be redirected to the %{newUsername} namespace but this redirect will expire once the %{currentUsername} namespace is registered by another user or group. Please update your Git repository remotes as soon as possible."
msgstr ""
+msgid "Profiles|%{provider} Active"
+msgstr ""
+
msgid "Profiles|@username"
msgstr ""
@@ -18834,7 +19514,7 @@ msgstr ""
msgid "Profiles|Commit email"
msgstr ""
-msgid "Profiles|Connect"
+msgid "Profiles|Connect %{provider}"
msgstr ""
msgid "Profiles|Connected Accounts"
@@ -18858,6 +19538,9 @@ msgstr ""
msgid "Profiles|Disconnect"
msgstr ""
+msgid "Profiles|Disconnect %{provider}"
+msgstr ""
+
msgid "Profiles|Do not show on profile"
msgstr ""
@@ -18882,7 +19565,7 @@ msgstr ""
msgid "Profiles|Full name"
msgstr ""
-msgid "Profiles|Give your individual key a title. This will be publically visible."
+msgid "Profiles|Give your individual key a title."
msgstr ""
msgid "Profiles|Include private contributions on my profile"
@@ -18972,7 +19655,7 @@ msgstr ""
msgid "Profiles|The maximum file size allowed is 200KB."
msgstr ""
-msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it?"
+msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it? It will be publicly visible."
msgstr ""
msgid "Profiles|This email will be displayed on your public profile"
@@ -19047,6 +19730,9 @@ msgstr ""
msgid "Profiles|You don't have access to delete this user."
msgstr ""
+msgid "Profiles|You must transfer ownership or delete groups you are an owner of before you can delete your account"
+msgstr ""
+
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
@@ -19635,6 +20321,9 @@ msgstr ""
msgid "ProjectTemplates|GitLab Cluster Management"
msgstr ""
+msgid "ProjectTemplates|Gitpod/Spring Petclinic"
+msgstr ""
+
msgid "ProjectTemplates|Go Micro"
msgstr ""
@@ -20244,6 +20933,9 @@ msgstr ""
msgid "Publish to status page"
msgstr ""
+msgid "Published"
+msgstr ""
+
msgid "Published on status page"
msgstr ""
@@ -20361,9 +21053,15 @@ msgstr ""
msgid "Quick range"
msgstr ""
+msgid "Quickly and easily edit multiple files in your project."
+msgstr ""
+
msgid "README"
msgstr ""
+msgid "Rails"
+msgstr ""
+
msgid "Rake Tasks Help"
msgstr ""
@@ -20483,10 +21181,13 @@ msgstr ""
msgid "Register Two-Factor Authenticator"
msgstr ""
-msgid "Register U2F device"
+msgid "Register Universal Two-Factor (U2F) Device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register WebAuthn Device"
+msgstr ""
+
+msgid "Register device"
msgstr ""
msgid "Register for GitLab"
@@ -20498,9 +21199,6 @@ msgstr ""
msgid "Register with two-factor app"
msgstr ""
-msgid "Registration"
-msgstr ""
-
msgid "Registration|Checkout"
msgstr ""
@@ -20617,9 +21315,6 @@ msgstr ""
msgid "Release|Something went wrong while saving the release details"
msgstr ""
-msgid "Remediated: needs review"
-msgstr ""
-
msgid "Remediations"
msgstr ""
@@ -20725,6 +21420,9 @@ msgstr ""
msgid "Remove priority"
msgstr ""
+msgid "Remove report"
+msgstr ""
+
msgid "Remove secondary node"
msgstr ""
@@ -20737,6 +21435,12 @@ msgstr ""
msgid "Remove time estimate"
msgstr ""
+msgid "Remove user & report"
+msgstr ""
+
+msgid "Remove user from group"
+msgstr ""
+
msgid "Removed"
msgstr ""
@@ -20818,9 +21522,6 @@ msgstr ""
msgid "Removes time estimate."
msgstr ""
-msgid "Removing license…"
-msgstr ""
-
msgid "Removing this group also removes all child projects, including archived projects, and their resources."
msgstr ""
@@ -20905,6 +21606,9 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
+msgid "Reported by %{reporter}"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -20991,6 +21695,27 @@ msgstr ""
msgid "Repositories"
msgstr ""
+msgid "Repositories Analytics"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download Historic Test Coverage Data"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download historic test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Historic Test Coverage Data is available in raw format (.csv) for further analysis."
+msgstr ""
+
+msgid "RepositoriesAnalytics|Test Code Coverage"
+msgstr ""
+
+msgid "RepositoriesAnalytics|There was an error fetching the projects."
+msgstr ""
+
msgid "Repository"
msgstr ""
@@ -21069,9 +21794,15 @@ msgstr ""
msgid "Request parameter %{param} is missing."
msgstr ""
+msgid "Request review from"
+msgstr ""
+
msgid "Request to link SAML account must be authorized"
msgstr ""
+msgid "Requested"
+msgstr ""
+
msgid "Requested %{time_ago}"
msgstr ""
@@ -21090,6 +21821,9 @@ msgstr ""
msgid "Requests to these domain(s)/address(es) on the local network will be allowed when local requests from hooks and services are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 or 127.0.0.0/28 are supported. Domain wildcards are not supported currently. Use comma, semicolon, or newline to separate multiple entries. The allowlist can hold a maximum of 1000 entries. Domains should use IDNA encoding. Ex: example.com, 192.168.1.1, 127.0.0.0/28, xn--itlab-j1a.com."
msgstr ""
+msgid "Require admin approval for new sign-ups"
+msgstr ""
+
msgid "Require all users in this group to setup Two-factor authentication"
msgstr ""
@@ -21217,9 +21951,6 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
-msgid "Resolved by %{resolvedByName}"
-msgstr ""
-
msgid "Resolves IP addresses once and uses them to submit requests"
msgstr ""
@@ -21339,6 +22070,14 @@ msgstr ""
msgid "ReviewApp|Enable Review App"
msgstr ""
+msgid "Reviewer"
+msgid_plural "%d Reviewers"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Reviewer(s)"
+msgstr ""
+
msgid "Reviewing"
msgstr ""
@@ -21378,6 +22117,9 @@ msgstr ""
msgid "Rook"
msgstr ""
+msgid "Ruby"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -21456,6 +22198,63 @@ msgstr ""
msgid "Runners page."
msgstr ""
+msgid "Runners|Active"
+msgstr ""
+
+msgid "Runners|Architecture"
+msgstr ""
+
+msgid "Runners|Can run untagged jobs"
+msgstr ""
+
+msgid "Runners|Description"
+msgstr ""
+
+msgid "Runners|Group"
+msgstr ""
+
+msgid "Runners|IP Address"
+msgstr ""
+
+msgid "Runners|Last contact"
+msgstr ""
+
+msgid "Runners|Locked to this project"
+msgstr ""
+
+msgid "Runners|Maximum job timeout"
+msgstr ""
+
+msgid "Runners|Name"
+msgstr ""
+
+msgid "Runners|Platform"
+msgstr ""
+
+msgid "Runners|Property Name"
+msgstr ""
+
+msgid "Runners|Protected"
+msgstr ""
+
+msgid "Runners|Revision"
+msgstr ""
+
+msgid "Runners|Shared"
+msgstr ""
+
+msgid "Runners|Specific"
+msgstr ""
+
+msgid "Runners|Tags"
+msgstr ""
+
+msgid "Runners|Value"
+msgstr ""
+
+msgid "Runners|Version"
+msgstr ""
+
msgid "Runners|You have used %{quotaUsed} out of %{quotaLimit} of your shared Runners pipeline minutes."
msgstr ""
@@ -21468,6 +22267,9 @@ msgstr ""
msgid "Runs a number of housekeeping tasks within the current repository, such as compressing file revisions and removing unreachable objects."
msgstr ""
+msgid "SAML"
+msgstr ""
+
msgid "SAML SSO"
msgstr ""
@@ -21519,6 +22321,9 @@ msgstr ""
msgid "Save"
msgstr ""
+msgid "Save %{name} size limits"
+msgstr ""
+
msgid "Save Changes"
msgstr ""
@@ -21549,9 +22354,6 @@ msgstr ""
msgid "Save space and find tags in the Container Registry more easily. Enable the cleanup policy to remove stale tags and keep only the ones you need."
msgstr ""
-msgid "Save template"
-msgstr ""
-
msgid "Save variables"
msgstr ""
@@ -21594,9 +22396,6 @@ msgstr ""
msgid "Scope"
msgstr ""
-msgid "Scope not supported with disabled 'users_search' feature!"
-msgstr ""
-
msgid "Scoped issue boards"
msgstr ""
@@ -21723,9 +22522,6 @@ msgstr ""
msgid "Search requirements"
msgstr ""
-msgid "Search results…"
-msgstr ""
-
msgid "Search users"
msgstr ""
@@ -21798,6 +22594,11 @@ msgid_plural "SearchResults|commits"
msgstr[0] ""
msgstr[1] ""
+msgid "SearchResults|epic"
+msgid_plural "SearchResults|epics"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "SearchResults|issue"
msgid_plural "SearchResults|issues"
msgstr[0] ""
@@ -21842,10 +22643,10 @@ msgstr ""
msgid "Seat Link is disabled, and cannot be configured through this form."
msgstr ""
-msgid "Seats currently in use"
+msgid "Seats usage data as of %{last_enqueue_time}"
msgstr ""
-msgid "Seats in license"
+msgid "Seats usage data is updated every day at 12:00pm UTC"
msgstr ""
msgid "Secondary"
@@ -21899,6 +22700,9 @@ msgstr ""
msgid "SecurityConfiguration|Available for on-demand DAST"
msgstr ""
+msgid "SecurityConfiguration|By default, all analyzers are applied in order to cover all languages across your project, and only run if the language is detected in the Merge Request."
+msgstr ""
+
msgid "SecurityConfiguration|Configure"
msgstr ""
@@ -21929,16 +22733,19 @@ msgstr ""
msgid "SecurityConfiguration|Manage"
msgstr ""
+msgid "SecurityConfiguration|More information"
+msgstr ""
+
msgid "SecurityConfiguration|Not enabled"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|Security Control"
+msgid "SecurityConfiguration|SAST Configuration"
msgstr ""
-msgid "SecurityConfiguration|See documentation"
+msgid "SecurityConfiguration|Security Control"
msgstr ""
msgid "SecurityConfiguration|Status"
@@ -21950,6 +22757,9 @@ msgstr ""
msgid "SecurityConfiguration|Using custom settings. You won't receive automatic updates on this variable. %{anchorStart}Restore to default%{anchorEnd}"
msgstr ""
+msgid "SecurityConfiguration|View history"
+msgstr ""
+
msgid "SecurityConfiguration|You can quickly enable all security scanning tools by enabling %{linkStart}Auto DevOps%{linkEnd}."
msgstr ""
@@ -22028,9 +22838,6 @@ msgstr ""
msgid "SecurityReports|Learn more about setting up your dashboard"
msgstr ""
-msgid "SecurityReports|Load more vulnerabilities"
-msgstr ""
-
msgid "SecurityReports|Monitor vulnerabilities in your code"
msgstr ""
@@ -22310,7 +23117,7 @@ msgstr ""
msgid "Select status"
msgstr ""
-msgid "Select strategy activation method"
+msgid "Select strategy activation method."
msgstr ""
msgid "Select subscription"
@@ -22325,7 +23132,7 @@ msgstr ""
msgid "Select the custom project template source group."
msgstr ""
-msgid "Select timeframe"
+msgid "Select the environment scope for this feature flag."
msgstr ""
msgid "Select timezone"
@@ -22574,6 +23381,9 @@ msgstr ""
msgid "Set iteration"
msgstr ""
+msgid "Set limit to 0 to allow any file size."
+msgstr ""
+
msgid "Set max session time for web terminal."
msgstr ""
@@ -22652,10 +23462,13 @@ msgstr ""
msgid "Set up a %{type} Runner manually"
msgstr ""
+msgid "Set up a hardware device as a second factor to sign in."
+msgstr ""
+
msgid "Set up assertions/attributes/claims (email, first_name, last_name) and NameID according to %{docsLinkStart}the documentation %{icon}%{docsLinkEnd}"
msgstr ""
-msgid "Set up new U2F device"
+msgid "Set up new device"
msgstr ""
msgid "Set up new password"
@@ -22724,6 +23537,9 @@ msgstr ""
msgid "Sets weight to %{weight}."
msgstr ""
+msgid "Setting this to 0 means using the system default timeout value."
+msgstr ""
+
msgid "Settings"
msgstr ""
@@ -22739,6 +23555,15 @@ msgstr ""
msgid "Severity"
msgstr ""
+msgid "SeverityWidget|Severity"
+msgstr ""
+
+msgid "SeverityWidget|Severity: %{severity}"
+msgstr ""
+
+msgid "SeverityWidget|There was an error while updating severity."
+msgstr ""
+
msgid "Shards (%{shards})"
msgstr ""
@@ -22784,6 +23609,9 @@ msgstr ""
msgid "Show all requirements."
msgstr ""
+msgid "Show all test cases."
+msgstr ""
+
msgid "Show archived projects"
msgstr ""
@@ -22796,6 +23624,9 @@ msgstr ""
msgid "Show comments"
msgstr ""
+msgid "Show comments on this file"
+msgstr ""
+
msgid "Show comments only"
msgstr ""
@@ -22841,6 +23672,12 @@ msgstr ""
msgid "Show parent subgroups"
msgstr ""
+msgid "Show the Closed list"
+msgstr ""
+
+msgid "Show the Open list"
+msgstr ""
+
msgid "Show whitespace changes"
msgstr ""
@@ -22884,9 +23721,6 @@ msgstr ""
msgid "Sidebar|Assign health status"
msgstr ""
-msgid "Sidebar|Change weight"
-msgstr ""
-
msgid "Sidebar|Health status"
msgstr ""
@@ -23070,6 +23904,9 @@ msgstr ""
msgid "Snippets|Add another file %{num}/%{total}"
msgstr ""
+msgid "Snippets|Authored %{time_ago} by %{author}"
+msgstr ""
+
msgid "Snippets|Delete file"
msgstr ""
@@ -23097,6 +23934,9 @@ msgstr ""
msgid "Solution"
msgstr ""
+msgid "Some changes are not shown"
+msgstr ""
+
msgid "Some child epics may be hidden due to applied filters"
msgstr ""
@@ -23463,6 +24303,12 @@ msgstr ""
msgid "Source (branch or tag)"
msgstr ""
+msgid "Source Branch"
+msgstr ""
+
+msgid "Source branch: %{source_branch_open}%{source_branch}%{source_branch_close}"
+msgstr ""
+
msgid "Source code"
msgstr ""
@@ -23628,9 +24474,6 @@ msgstr ""
msgid "Start and due date"
msgstr ""
-msgid "Start by choosing a group to see how your team is spending time. You can then drill down to the project level."
-msgstr ""
-
msgid "Start by choosing a group to start exploring the merge requests in that group. You can then proceed to filter by projects, labels, milestones and authors."
msgstr ""
@@ -23712,18 +24555,27 @@ msgstr ""
msgid "StaticSiteEditor|3. Assign a person to review and accept the merge request."
msgstr ""
+msgid "StaticSiteEditor|A link to view the merge request will appear once ready."
+msgstr ""
+
msgid "StaticSiteEditor|An error occurred while submitting your changes."
msgstr ""
msgid "StaticSiteEditor|Branch could not be created."
msgstr ""
+msgid "StaticSiteEditor|Copy update"
+msgstr ""
+
msgid "StaticSiteEditor|Could not commit the content changes."
msgstr ""
msgid "StaticSiteEditor|Could not create merge request."
msgstr ""
+msgid "StaticSiteEditor|Creating your merge request"
+msgstr ""
+
msgid "StaticSiteEditor|Incompatible file content"
msgstr ""
@@ -23745,6 +24597,9 @@ msgstr ""
msgid "StaticSiteEditor|View documentation"
msgstr ""
+msgid "StaticSiteEditor|You can set an assignee to get your changes reviewed and deployed once your merge request is created."
+msgstr ""
+
msgid "StaticSiteEditor|Your merge request has been created"
msgstr ""
@@ -23874,15 +24729,15 @@ msgstr ""
msgid "Submit %{humanized_resource_name}"
msgstr ""
-msgid "Submit Changes"
-msgstr ""
-
msgid "Submit a review"
msgstr ""
msgid "Submit as spam"
msgstr ""
+msgid "Submit changes"
+msgstr ""
+
msgid "Submit feedback"
msgstr ""
@@ -24036,6 +24891,9 @@ msgstr ""
msgid "Successfully deleted U2F device."
msgstr ""
+msgid "Successfully deleted WebAuthn device."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -24354,9 +25212,6 @@ msgstr ""
msgid "Template to append to all Service Desk issues"
msgstr ""
-msgid "Template was successfully saved."
-msgstr ""
-
msgid "Templates"
msgstr ""
@@ -24435,10 +25290,28 @@ msgid_plural "Test coverage: %d hits"
msgstr[0] ""
msgstr[1] ""
-msgid "Test failed."
+msgid "Test settings"
msgstr ""
-msgid "Test settings and save changes"
+msgid "TestCases|New Test Case"
+msgstr ""
+
+msgid "TestCases|New test case"
+msgstr ""
+
+msgid "TestCases|Search test cases"
+msgstr ""
+
+msgid "TestCases|Something went wrong while creating a test case."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching count of test cases."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching test cases list."
+msgstr ""
+
+msgid "TestCases|Submit test case"
msgstr ""
msgid "TestHooks|Ensure one of your projects has merge requests."
@@ -24504,6 +25377,9 @@ msgstr ""
msgid "Thank you for signing up for your free trial! You will get additional instructions in your inbox shortly."
msgstr ""
+msgid "Thank you for your business."
+msgstr ""
+
msgid "Thank you for your feedback!"
msgstr ""
@@ -24563,9 +25439,6 @@ msgstr ""
msgid "The URL to use for connecting to Elasticsearch. Use a comma-separated list to support clustering (e.g., \"http://localhost:9200, http://localhost:9201\")."
msgstr ""
-msgid "The Web IDE offers advanced syntax highlighting capabilities and more."
-msgstr ""
-
msgid "The X509 Certificate to use when mutual TLS is required to communicate with the external authorization service. If left blank, the server certificate is still validated when accessing over HTTPS."
msgstr ""
@@ -24676,6 +25549,9 @@ msgstr ""
msgid "The form contains the following error:"
msgstr ""
+msgid "The form contains the following warning:"
+msgstr ""
+
msgid "The global settings require you to enable Two-Factor Authentication for your account."
msgstr ""
@@ -24790,9 +25666,6 @@ msgstr ""
msgid "The private key to use when a client certificate is provided. This value is encrypted at rest."
msgstr ""
-msgid "The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The project can be accessed by any logged in user."
msgstr ""
@@ -24829,7 +25702,7 @@ msgstr ""
msgid "The remote repository is being updated..."
msgstr ""
-msgid "The repository can be commited to, and issues, comments and other entities can be created."
+msgid "The repository can be committed to, and issues, comments and other entities can be created."
msgstr ""
msgid "The repository for this project does not exist."
@@ -24883,9 +25756,6 @@ msgstr ""
msgid "The time taken by each data entry gathered by that stage."
msgstr ""
-msgid "The total stage shows the time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The update action will time out after %{number_of_minutes} minutes. For big repositories, use a clone/push combination."
msgstr ""
@@ -24949,6 +25819,9 @@ msgstr ""
msgid "There are no archived requirements"
msgstr ""
+msgid "There are no archived test cases"
+msgstr ""
+
msgid "There are no changes"
msgstr ""
@@ -24988,6 +25861,9 @@ msgstr ""
msgid "There are no open requirements"
msgstr ""
+msgid "There are no open test cases"
+msgstr ""
+
msgid "There are no packages yet"
msgstr ""
@@ -25000,6 +25876,9 @@ msgstr ""
msgid "There is a limit of %{ci_project_subscriptions_limit} subscriptions from or to a project."
msgstr ""
+msgid "There is already a To-Do for this design."
+msgstr ""
+
msgid "There is already a repository with that name on disk"
msgstr ""
@@ -25018,6 +25897,9 @@ msgstr ""
msgid "There was a problem communicating with your device."
msgstr ""
+msgid "There was a problem fetching branches."
+msgstr ""
+
msgid "There was a problem fetching groups."
msgstr ""
@@ -25246,9 +26128,15 @@ msgstr ""
msgid "This action can lead to data loss. To prevent accidental actions we ask you to confirm your intention."
msgstr ""
+msgid "This action cannot be undone, and will permanently delete the %{key} SSH key"
+msgstr ""
+
msgid "This action cannot be undone. You will lose the project's repository and all content: issues, merge requests, etc."
msgstr ""
+msgid "This action has been performed too many times. Try again later."
+msgstr ""
+
msgid "This action will %{strongOpen}permanently delete%{strongClose} %{codeOpen}%{project}%{codeClose} %{strongOpen}immediately%{strongClose}, including its repositories and all content: issues, merge requests, etc."
msgstr ""
@@ -25276,9 +26164,6 @@ msgstr ""
msgid "This board's scope is reduced"
msgstr ""
-msgid "This branch has changed since you started editing. Would you like to create a new branch?"
-msgstr ""
-
msgid "This chart could not be displayed"
msgstr ""
@@ -25405,15 +26290,9 @@ msgstr ""
msgid "This is a security log of important events involving your account."
msgstr ""
-msgid "This is the author's first Merge Request to this project."
-msgstr ""
-
msgid "This is the highest peak of users on your installation since the license started."
msgstr ""
-msgid "This is the maximum number of users that have existed at the same time since the license started. This is the minimum number of seats you will need to buy when you renew your license."
-msgstr ""
-
msgid "This is the number of currently active users on your installation, and this is the minimum number you need to purchase when you renew your license."
msgstr ""
@@ -25645,6 +26524,15 @@ msgstr ""
msgid "This user has no identities"
msgstr ""
+msgid "This user has previously committed to the %{name} project."
+msgstr ""
+
+msgid "This user has the %{access} role in the %{name} project."
+msgstr ""
+
+msgid "This user is the author of this %{noteable}."
+msgstr ""
+
msgid "This user will be the author of all events in the activity feed that are the result of an update, like new branches being created or new commits being pushed to existing branches."
msgstr ""
@@ -25675,6 +26563,9 @@ msgstr ""
msgid "Threat Monitoring"
msgstr ""
+msgid "ThreatMonitoring|All Environments"
+msgstr ""
+
msgid "ThreatMonitoring|Anomalous Requests"
msgstr ""
@@ -25702,9 +26593,6 @@ msgstr ""
msgid "ThreatMonitoring|Operations Per Second"
msgstr ""
-msgid "ThreatMonitoring|Overview"
-msgstr ""
-
msgid "ThreatMonitoring|Packet Activity"
msgstr ""
@@ -25723,6 +26611,9 @@ msgstr ""
msgid "ThreatMonitoring|Something went wrong, unable to fetch statistics"
msgstr ""
+msgid "ThreatMonitoring|Statistics"
+msgstr ""
+
msgid "ThreatMonitoring|The firewall is not installed or has been disabled. To view this data, ensure the web application firewall is installed and enabled for your cluster."
msgstr ""
@@ -26114,6 +27005,9 @@ msgstr ""
msgid "To update Snippets with multiple files, you must use the `files` parameter"
msgstr ""
+msgid "To use Gitpod you must first enable the feature in the integrations section of your %{user_prefs}."
+msgstr ""
+
msgid "To view all %{scannedResourcesCount} scanned URLs, please download the CSV file"
msgstr ""
@@ -26147,9 +27041,6 @@ msgstr ""
msgid "Toggle Sidebar"
msgstr ""
-msgid "Toggle all threads"
-msgstr ""
-
msgid "Toggle backtrace"
msgstr ""
@@ -26174,9 +27065,6 @@ msgstr ""
msgid "Toggle navigation"
msgstr ""
-msgid "Toggle project"
-msgstr ""
-
msgid "Toggle sidebar"
msgstr ""
@@ -26216,6 +27104,9 @@ msgstr ""
msgid "Too many projects enabled. You will need to manage them via the console or the API."
msgstr ""
+msgid "Too much data"
+msgstr ""
+
msgid "Topics (optional)"
msgstr ""
@@ -26234,6 +27125,9 @@ msgstr ""
msgid "Total cores (CPUs)"
msgstr ""
+msgid "Total days to completion"
+msgstr ""
+
msgid "Total issues"
msgstr ""
@@ -26330,6 +27224,9 @@ msgstr ""
msgid "Trending"
msgstr ""
+msgid "Trials|Create a new group to start your GitLab Gold trial."
+msgstr ""
+
msgid "Trials|Go back to GitLab"
msgstr ""
@@ -26339,6 +27236,15 @@ msgstr ""
msgid "Trials|You can always resume this process by selecting your avatar and choosing 'Start a Gold trial'"
msgstr ""
+msgid "Trials|You can apply your trial to a new group or an existing group."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group or your personal account."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group, an existing group, or your personal account."
+msgstr ""
+
msgid "Trials|You won't get a free trial right now but you can always resume this process by clicking on your avatar and choosing 'Start a free trial'"
msgstr ""
@@ -26408,6 +27314,9 @@ msgstr ""
msgid "Try using a different search term to find the file you are looking for."
msgstr ""
+msgid "Trying to communicate with your device. Plug it in (if needed) and press the button on the device now."
+msgstr ""
+
msgid "Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now."
msgstr ""
@@ -26495,6 +27404,12 @@ msgstr ""
msgid "URL or request ID"
msgstr ""
+msgid "USER %{user} WILL BE REMOVED! Are you sure?"
+msgstr ""
+
+msgid "USER WILL BE BLOCKED! Are you sure?"
+msgstr ""
+
msgid "UTC"
msgstr ""
@@ -26552,9 +27467,6 @@ msgstr ""
msgid "Unable to load the merge request widget. Try reloading the page."
msgstr ""
-msgid "Unable to resolve"
-msgstr ""
-
msgid "Unable to save iteration. Please try again"
msgstr ""
@@ -26603,6 +27515,9 @@ msgstr ""
msgid "Undo ignore"
msgstr ""
+msgid "Unexpected error"
+msgstr ""
+
msgid "Unfortunately, your email message to GitLab could not be processed."
msgstr ""
@@ -26636,6 +27551,9 @@ msgstr ""
msgid "Unknown response text"
msgstr ""
+msgid "Unless otherwise agreed to in writing with GitLab, by clicking \"Upload License\" you agree that your use of GitLab Software is subject to the %{eula_link_start}Terms of Service%{eula_link_end}."
+msgstr ""
+
msgid "Unlimited"
msgstr ""
@@ -27002,9 +27920,6 @@ msgstr ""
msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
msgstr ""
-msgid "Use a hardware device to add the second factor of authentication."
-msgstr ""
-
msgid "Use an one time password authenticator on your mobile device or computer to enable two-factor authentication (2FA)."
msgstr ""
@@ -27278,13 +28193,13 @@ msgstr ""
msgid "Users"
msgstr ""
-msgid "Users in License:"
+msgid "Users in License"
msgstr ""
-msgid "Users or groups set as approvers in the project's or merge request's settings."
+msgid "Users in License:"
msgstr ""
-msgid "Users outside of license"
+msgid "Users or groups set as approvers in the project's or merge request's settings."
msgstr ""
msgid "Users over License:"
@@ -27302,9 +28217,6 @@ msgstr ""
msgid "Users with a Guest role or those who don't belong to a Project or Group will not use a seat from your license."
msgstr ""
-msgid "Users with a Guest role or those who don't belong to any projects or groups don't count towards seats in use."
-msgstr ""
-
msgid "UsersSelect|%{name} + %{length} more"
msgstr ""
@@ -27344,9 +28256,6 @@ msgstr ""
msgid "Validations failed."
msgstr ""
-msgid "Validity"
-msgstr ""
-
msgid "Value"
msgstr ""
@@ -27365,6 +28274,9 @@ msgstr ""
msgid "Value Stream Name"
msgstr ""
+msgid "ValueStreamAnalyticsStage|We don't have enough data to show this stage."
+msgstr ""
+
msgid "ValueStreamAnalytics|%{days}d"
msgstr ""
@@ -27621,6 +28533,9 @@ msgstr ""
msgid "VisualReviewApp|Steps 1 and 2 (and sometimes 3) are performed once by the developer before requesting feedback. Steps 3 (if necessary), 4 is performed by the reviewer each time they perform a review."
msgstr ""
+msgid "Visualization"
+msgstr ""
+
msgid "Vulnerabilities"
msgstr ""
@@ -27648,34 +28563,31 @@ msgstr ""
msgid "VulnerabilityChart|Severity"
msgstr ""
-msgid "VulnerabilityManagement|A true-positive and will fix"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Change status"
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|Confirm"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Confirmed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
-msgstr ""
-
-msgid "VulnerabilityManagement|Detected %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|A true-positive and will fix"
msgstr ""
-msgid "VulnerabilityManagement|Dismiss"
+msgid "VulnerabilityManagement|Change status"
msgstr ""
-msgid "VulnerabilityManagement|Dismissed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
msgstr ""
-msgid "VulnerabilityManagement|Resolved"
+msgid "VulnerabilityManagement|Detected"
msgstr ""
-msgid "VulnerabilityManagement|Resolved %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Needs triage"
msgstr ""
msgid "VulnerabilityManagement|Something went wrong while trying to delete the comment. Please try again later."
@@ -27726,6 +28638,9 @@ msgstr ""
msgid "Vulnerability|%{scannerName} (version %{scannerVersion})"
msgstr ""
+msgid "Vulnerability|Activity"
+msgstr ""
+
msgid "Vulnerability|Class"
msgstr ""
@@ -27738,6 +28653,9 @@ msgstr ""
msgid "Vulnerability|Description"
msgstr ""
+msgid "Vulnerability|Detected"
+msgstr ""
+
msgid "Vulnerability|Evidence"
msgstr ""
@@ -27801,6 +28719,9 @@ msgstr ""
msgid "Warning: Displaying this diagram might cause performance issues on this page."
msgstr ""
+msgid "We are currently unable to fetch data for the pipeline header."
+msgstr ""
+
msgid "We are currently unable to fetch data for this graph."
msgstr ""
@@ -27840,6 +28761,12 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
+msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
+msgstr ""
+
+msgid "We would like to inform you that your subscription GitLab Enterprise Edition %{plan_name} is nearing its user limit. You have %{active_user_count} active users, which is almost at the user limit of %{maximum_user_count}."
+msgstr ""
+
msgid "We've found no vulnerabilities"
msgstr ""
@@ -27855,6 +28782,12 @@ msgstr ""
msgid "Web terminal"
msgstr ""
+msgid "WebAuthn Devices (%{length})"
+msgstr ""
+
+msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
+msgstr ""
+
msgid "WebIDE|Merge request"
msgstr ""
@@ -27993,15 +28926,9 @@ msgstr ""
msgid "Welcome to the guided GitLab tour"
msgstr ""
-msgid "Welcome to your Issue Board!"
-msgstr ""
-
msgid "Welcome to your issue board!"
msgstr ""
-msgid "We’ve been making changes to %{featureName} and we’d love your feedback %{linkStart}in this issue%{linkEnd} to help us improve the experience."
-msgstr ""
-
msgid "What are you searching for?"
msgstr ""
@@ -28020,6 +28947,9 @@ msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
msgstr ""
+msgid "When enabled, any user visiting %{host} and creating an account will have to be explicitly approved by the admin before they can login. This setting is effective only if sign-ups are enabled."
+msgstr ""
+
msgid "When enabled, any user visiting %{host} will be able to create an account."
msgstr ""
@@ -28244,6 +29174,9 @@ msgstr ""
msgid "With requirements, you can set criteria to check your products against."
msgstr ""
+msgid "With test cases, you can define conditions for your project to meet in determining quality"
+msgstr ""
+
msgid "Withdraw Access Request"
msgstr ""
@@ -28259,6 +29192,9 @@ msgstr ""
msgid "Workflow Help"
msgstr ""
+msgid "Would you like to create a new branch?"
+msgstr ""
+
msgid "Write"
msgstr ""
@@ -28280,6 +29216,9 @@ msgstr ""
msgid "Wrong extern UID provided. Make sure Auth0 is configured correctly."
msgstr ""
+msgid "YYYY-MM-DD"
+msgstr ""
+
msgid "Yes"
msgstr ""
@@ -28337,7 +29276,7 @@ msgstr ""
msgid "You are going to remove the fork relationship from %{project_full_name}. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "You are going to transfer %{project_full_name} to another owner. Are you ABSOLUTELY sure?"
+msgid "You are going to transfer %{project_full_name} to another namespace. Are you ABSOLUTELY sure?"
msgstr ""
msgid "You are going to turn off the confidentiality. This means %{strongStart}everyone%{strongEnd} will be able to see and leave a comment on this %{issuableType}."
@@ -28397,9 +29336,6 @@ msgstr ""
msgid "You can always edit this later"
msgstr ""
-msgid "You can apply your Trial to your Personal account or create a New Group."
-msgstr ""
-
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings"
msgstr ""
@@ -28421,12 +29357,18 @@ msgstr ""
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
+msgid "You can find more information about GitLab subscriptions in %{subscriptions_doc_link}."
+msgstr ""
+
msgid "You can generate an access token scoped to this project for each application to use the GitLab API."
msgstr ""
msgid "You can get started by cloning the repository or start adding files to it with one of the following options."
msgstr ""
+msgid "You can group test cases using labels. To learn about the future direction of this feature, visit %{linkStart}Quality Management direction page%{linkEnd}."
+msgstr ""
+
msgid "You can invite a new member to %{project_name} or invite another group."
msgstr ""
@@ -28442,6 +29384,9 @@ msgstr ""
msgid "You can notify the app / group or a project by sending them an email notification"
msgstr ""
+msgid "You can now close this window."
+msgstr ""
+
msgid "You can now export your security dashboard to a CSV report."
msgstr ""
@@ -28490,9 +29435,6 @@ msgstr ""
msgid "You can test your .gitlab-ci.yml in %{linkStart}CI Lint%{linkEnd}."
msgstr ""
-msgid "You can try again using %{begin_link}basic search%{end_link}"
-msgstr ""
-
msgid "You cannot access the raw file. Please wait a minute."
msgstr ""
@@ -28544,6 +29486,9 @@ msgstr ""
msgid "You don't have any U2F devices registered yet."
msgstr ""
+msgid "You don't have any WebAuthn devices registered yet."
+msgstr ""
+
msgid "You don't have any active chat names."
msgstr ""
@@ -28631,6 +29576,9 @@ msgstr ""
msgid "You must accept our Terms of Service and privacy policy in order to register an account"
msgstr ""
+msgid "You must be logged in to search across all of GitLab"
+msgstr ""
+
msgid "You must disassociate %{domain} from all clusters it is attached to before deletion."
msgstr ""
@@ -28670,7 +29618,7 @@ msgstr ""
msgid "You need to be logged in."
msgstr ""
-msgid "You need to register a two-factor authentication app before you can set up a U2F device."
+msgid "You need to register a two-factor authentication app before you can set up a device."
msgstr ""
msgid "You need to set terms to be enforced"
@@ -28688,6 +29636,9 @@ msgstr ""
msgid "You reached %{usage_in_percent} of %{namespace_name}'s storage capacity (%{used_storage} of %{storage_limit})"
msgstr ""
+msgid "You successfully declined the invitation"
+msgstr ""
+
msgid "You tried to fork %{link_to_the_project} but it failed for the following reason:"
msgstr ""
@@ -28853,10 +29804,13 @@ msgstr ""
msgid "Your U2F device did not send a valid JSON response."
msgstr ""
-msgid "Your U2F device needs to be set up. Plug it in (if not already) and click the button on the left."
+msgid "Your U2F device was registered!"
msgstr ""
-msgid "Your U2F device was registered!"
+msgid "Your WebAuthn device did not send a valid JSON response."
+msgstr ""
+
+msgid "Your WebAuthn device was registered!"
msgstr ""
msgid "Your access request to the %{source_type} has been withdrawn."
@@ -28880,6 +29834,9 @@ msgstr ""
msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
msgstr ""
+msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
+msgstr ""
+
msgid "Your changes can be committed to %{branch_name} because a merge request is open."
msgstr ""
@@ -28916,6 +29873,12 @@ msgstr ""
msgid "Your deployment services will be broken, you will need to manually fix the services after renaming."
msgstr ""
+msgid "Your device is not compatible with GitLab. Please try another device"
+msgstr ""
+
+msgid "Your device needs to be set up. Plug it in (if needed) and click the button on the left."
+msgstr ""
+
msgid "Your device was successfully set up! Give it a name and register it with the GitLab server."
msgstr ""
@@ -29029,9 +29992,6 @@ msgstr[1] ""
msgid "access:"
msgstr ""
-msgid "activated"
-msgstr ""
-
msgid "added %{created_at_timeago}"
msgstr ""
@@ -29104,9 +30064,21 @@ msgstr ""
msgid "by %{user}"
msgstr ""
+msgid "cannot be a date in the past"
+msgstr ""
+
msgid "cannot be changed if a personal project has container registry tags."
msgstr ""
+msgid "cannot be changed if shared runners are enabled"
+msgstr ""
+
+msgid "cannot be enabled because parent group does not allow it"
+msgstr ""
+
+msgid "cannot be enabled because parent group has shared Runners disabled"
+msgstr ""
+
msgid "cannot be enabled unless all domains have TLS certificates"
msgstr ""
@@ -29152,7 +30124,7 @@ msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about SAST %{linkEndTag}"
msgstr ""
-msgid "ciReport|%{linkStartTag}Learn more about Secret Scanning %{linkEndTag}"
+msgid "ciReport|%{linkStartTag}Learn more about Secret Detection %{linkEndTag}"
msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about codequality reports %{linkEndTag}"
@@ -29467,9 +30439,6 @@ msgstr ""
msgid "error"
msgstr ""
-msgid "error code:"
-msgstr ""
-
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr ""
@@ -29491,6 +30460,9 @@ msgstr ""
msgid "failed to dismiss associated finding(id=%{finding_id}): %{message}"
msgstr ""
+msgid "failed to revert associated finding(id=%{finding_id}) to detected"
+msgstr ""
+
msgid "file"
msgid_plural "files"
msgstr[0] ""
@@ -30033,6 +31005,9 @@ msgstr ""
msgid "must be a root namespace"
msgstr ""
+msgid "must be a valid IPv4 or IPv6 address"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -30069,6 +31044,9 @@ msgstr ""
msgid "no expiration"
msgstr ""
+msgid "no name set"
+msgstr ""
+
msgid "no one can merge"
msgstr ""
@@ -30247,9 +31225,6 @@ msgstr ""
msgid "security Reports|There was an error creating the merge request"
msgstr ""
-msgid "settings saved, but not activated"
-msgstr ""
-
msgid "severity|Critical"
msgstr ""
@@ -30376,9 +31351,6 @@ msgstr ""
msgid "toggle collapse"
msgstr ""
-msgid "toggle dropdown"
-msgstr ""
-
msgid "triggered"
msgstr ""
@@ -30406,6 +31378,9 @@ msgstr ""
msgid "user avatar"
msgstr ""
+msgid "user preferences"
+msgstr ""
+
msgid "username"
msgstr ""
diff --git a/locale/ky_KG/gitlab.po b/locale/ky_KG/gitlab.po
index b6373278200..0a8af4d8723 100644
--- a/locale/ky_KG/gitlab.po
+++ b/locale/ky_KG/gitlab.po
@@ -14,7 +14,10 @@ msgstr ""
"X-Crowdin-Language: ky\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 6\n"
-"PO-Revision-Date: 2020-09-04 23:03\n"
+"PO-Revision-Date: 2020-10-02 18:43\n"
+
+msgid " %{project_name}#%{issue_iid} &middot; opened %{issue_created} by %{author}"
+msgstr ""
msgid " %{start} to %{end}"
msgstr ""
@@ -74,6 +77,16 @@ msgstr ""
msgid "\"el\" parameter is required for createInstance()"
msgstr ""
+msgid "%d Approval"
+msgid_plural "%d Approvals"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d Package"
+msgid_plural "%d Packages"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d Scanned URL"
msgid_plural "%d Scanned URLs"
msgstr[0] ""
@@ -137,6 +150,11 @@ msgstr[1] ""
msgid "%d commits"
msgstr ""
+msgid "%d completed issue"
+msgid_plural "%d completed issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d contribution"
msgid_plural "%d contributions"
msgstr[0] ""
@@ -147,6 +165,11 @@ msgid_plural "%d days"
msgstr[0] ""
msgstr[1] ""
+msgid "%d day until tags are automatically removed"
+msgid_plural "%d days until tags are automatically removed"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d error"
msgid_plural "%d errors"
msgstr[0] ""
@@ -237,6 +260,16 @@ msgid_plural "%d more comments"
msgstr[0] ""
msgstr[1] ""
+msgid "%d open issue"
+msgid_plural "%d open issues"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d pending comment"
+msgid_plural "%d pending comments"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d personal project will be removed and cannot be restored."
msgid_plural "%d personal projects will be removed and cannot be restored."
msgstr[0] ""
@@ -252,6 +285,11 @@ msgid_plural "%d projects"
msgstr[0] ""
msgstr[1] ""
+msgid "%d project selected"
+msgid_plural "%d projects selected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d request with warnings"
msgid_plural "%d requests with warnings"
msgstr[0] ""
@@ -272,6 +310,11 @@ msgid_plural "%d tags"
msgstr[0] ""
msgstr[1] ""
+msgid "%d tag per image name"
+msgid_plural "%d tags per image name"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d unassigned issue"
msgid_plural "%d unassigned issues"
msgstr[0] ""
@@ -292,6 +335,11 @@ msgid_plural "%d vulnerabilities dismissed"
msgstr[0] ""
msgstr[1] ""
+msgid "%d warning found:"
+msgid_plural "%d warnings found:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%s additional commit has been omitted to prevent performance issues."
msgid_plural "%s additional commits have been omitted to prevent performance issues."
msgstr[0] ""
@@ -330,6 +378,9 @@ msgstr ""
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr ""
+msgid "%{completedCount} completed weight"
+msgstr ""
+
msgid "%{completedWeight} of %{totalWeight} weight completed"
msgstr ""
@@ -378,14 +429,12 @@ msgid_plural "%{count} participants"
msgstr[0] ""
msgstr[1] ""
-msgid "%{count} pending comment"
-msgid_plural "%{count} pending comments"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
+msgid "%{count} total weight"
+msgstr ""
+
msgid "%{dashboard_path} could not be found."
msgstr ""
@@ -440,6 +489,9 @@ msgstr ""
msgid "%{group_name} uses group managed accounts. You need to create a new GitLab account which will be managed by %{group_name}."
msgstr ""
+msgid "%{group_name}&%{epic_iid} &middot; opened %{epic_created} by %{author}"
+msgstr ""
+
msgid "%{host} sign-in from new location"
msgstr ""
@@ -452,7 +504,7 @@ msgstr ""
msgid "%{issuableType} will be removed! Are you sure?"
msgstr ""
-msgid "%{issuesSize} issues with a limit of %{maxIssueCount}"
+msgid "%{issuesCount} issues with a limit of %{maxIssueCount}"
msgstr ""
msgid "%{issuesSize} with a limit of %{maxIssueCount}"
@@ -485,7 +537,7 @@ msgstr ""
msgid "%{labelStart}Namespace:%{labelEnd} %{namespace}"
msgstr ""
-msgid "%{labelStart}Report Type:%{labelEnd} %{reportType}"
+msgid "%{labelStart}Scan Type:%{labelEnd} %{reportType}"
msgstr ""
msgid "%{labelStart}Scanner:%{labelEnd} %{scanner}"
@@ -682,9 +734,6 @@ msgid_plural "%{securityScanner} results are not available because a pipeline ha
msgstr[0] ""
msgstr[1] ""
-msgid "%{service_title} %{message}."
-msgstr ""
-
msgid "%{size} GiB"
msgstr ""
@@ -773,6 +822,12 @@ msgstr ""
msgid "%{timebox_name} should belong either to a project or a group."
msgstr ""
+msgid "%{timebox_type} does not support burnup charts"
+msgstr ""
+
+msgid "%{timebox_type} must have a start and due date"
+msgstr ""
+
msgid "%{title} %{operator} %{threshold}"
msgstr ""
@@ -797,7 +852,7 @@ msgstr ""
msgid "%{total} open issue weight"
msgstr ""
-msgid "%{total} open issues"
+msgid "%{total} warnings found: showing first %{warningsDisplayed}"
msgstr ""
msgid "%{usage_ping_link_start}Learn more%{usage_ping_link_end} about what information is shared with GitLab Inc."
@@ -830,9 +885,6 @@ msgstr ""
msgid "&lt; 1 hour"
msgstr ""
-msgid "&lt;no name set&gt;"
-msgstr ""
-
msgid "&lt;no scopes selected&gt;"
msgstr ""
@@ -863,6 +915,9 @@ msgstr ""
msgid "'%{name}' Value Stream created"
msgstr ""
+msgid "'%{name}' Value Stream deleted"
+msgstr ""
+
msgid "'%{name}' stage already exists"
msgstr ""
@@ -922,6 +977,9 @@ msgstr ""
msgid "+ %{numberOfHiddenAssignees} more"
msgstr ""
+msgid "+ %{numberOfHiddenReviewers} more"
+msgstr ""
+
msgid "+%d more"
msgid_plural "+%d more"
msgstr[0] ""
@@ -982,6 +1040,11 @@ msgid_plural "%d Days"
msgstr[0] ""
msgstr[1] ""
+msgid "1 Issue"
+msgid_plural "%d Issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "1 closed issue"
msgid_plural "%{issues} closed issues"
msgstr[0] ""
@@ -997,6 +1060,11 @@ msgid_plural "%d days"
msgstr[0] ""
msgstr[1] ""
+msgid "1 deploy key"
+msgid_plural "%d deploy keys"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1099,6 +1167,9 @@ msgstr ""
msgid ":%{startLine} to %{endLine}"
msgstr ""
+msgid "A %{incident_docs_start}modified issue%{incident_docs_end} to guide the resolution of incidents."
+msgstr ""
+
msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr ""
@@ -1111,6 +1182,9 @@ msgstr ""
msgid "A GitBook site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
+msgid "A Gitpod configured Webapplication in Spring and Java"
+msgstr ""
+
msgid "A Hexo site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
@@ -1282,9 +1356,15 @@ msgstr ""
msgid "Access expiration date"
msgstr ""
+msgid "Access expires"
+msgstr ""
+
msgid "Access forbidden. Check your access level."
msgstr ""
+msgid "Access granted"
+msgstr ""
+
msgid "Access requests"
msgstr ""
@@ -1294,6 +1374,9 @@ msgstr ""
msgid "Access to Pages websites are controlled based on the user's membership to a given project. By checking this box, users will be required to be logged in to have access to all Pages websites in your instance."
msgstr ""
+msgid "AccessDropdown|Deploy Keys"
+msgstr ""
+
msgid "AccessDropdown|Groups"
msgstr ""
@@ -1411,12 +1494,6 @@ msgstr ""
msgid "Active Sessions"
msgstr ""
-msgid "Active Users:"
-msgstr ""
-
-msgid "Active users"
-msgstr ""
-
msgid "Activity"
msgstr ""
@@ -1584,9 +1661,6 @@ msgstr ""
msgid "Add label(s)"
msgstr ""
-msgid "Add license"
-msgstr ""
-
msgid "Add list"
msgstr ""
@@ -1761,21 +1835,51 @@ msgstr ""
msgid "AdminArea|Bots"
msgstr ""
+msgid "AdminArea|Components"
+msgstr ""
+
msgid "AdminArea|Developer"
msgstr ""
+msgid "AdminArea|Features"
+msgstr ""
+
+msgid "AdminArea|Groups: %{number_of_groups}"
+msgstr ""
+
msgid "AdminArea|Guest"
msgstr ""
msgid "AdminArea|Included Free in license"
msgstr ""
+msgid "AdminArea|Latest groups"
+msgstr ""
+
+msgid "AdminArea|Latest projects"
+msgstr ""
+
+msgid "AdminArea|Latest users"
+msgstr ""
+
msgid "AdminArea|Maintainer"
msgstr ""
+msgid "AdminArea|New group"
+msgstr ""
+
+msgid "AdminArea|New project"
+msgstr ""
+
+msgid "AdminArea|New user"
+msgstr ""
+
msgid "AdminArea|Owner"
msgstr ""
+msgid "AdminArea|Projects: %{number_of_projects}"
+msgstr ""
+
msgid "AdminArea|Reporter"
msgstr ""
@@ -1803,6 +1907,9 @@ msgstr ""
msgid "AdminArea|Users without a Group and Project"
msgstr ""
+msgid "AdminArea|Users: %{number_of_users}"
+msgstr ""
+
msgid "AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running."
msgstr ""
@@ -1821,9 +1928,6 @@ msgstr ""
msgid "AdminProjects|Delete Project %{projectName}?"
msgstr ""
-msgid "AdminProjects|Delete project"
-msgstr ""
-
msgid "AdminSettings|Apply integration settings to all Projects"
msgstr ""
@@ -2061,21 +2165,30 @@ msgstr ""
msgid "AdminUsers|Without projects"
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 ""
msgid "AdminUsers|You cannot remove your own admin rights."
msgstr ""
+msgid "AdminUsers|You must transfer ownership or delete the groups owned by this user before you can delete their account"
+msgstr ""
+
msgid "Administration"
msgstr ""
msgid "Advanced"
msgstr ""
+msgid "Advanced Search"
+msgstr ""
+
+msgid "Advanced Search with Elasticsearch"
+msgstr ""
+
msgid "Advanced Settings"
msgstr ""
@@ -2153,6 +2266,9 @@ msgstr ""
msgid "AlertManagement|Edit"
msgstr ""
+msgid "AlertManagement|Environment"
+msgstr ""
+
msgid "AlertManagement|Events"
msgstr ""
@@ -2165,6 +2281,9 @@ msgstr ""
msgid "AlertManagement|Issue"
msgstr ""
+msgid "AlertManagement|Key"
+msgstr ""
+
msgid "AlertManagement|Low"
msgstr ""
@@ -2258,6 +2377,9 @@ msgstr ""
msgid "AlertManagement|Unknown"
msgstr ""
+msgid "AlertManagement|Value"
+msgstr ""
+
msgid "AlertManagement|View alerts in Opsgenie"
msgstr ""
@@ -2417,6 +2539,9 @@ msgstr ""
msgid "All projects"
msgstr ""
+msgid "All projects selected"
+msgstr ""
+
msgid "All security scans are enabled because %{linkStart}Auto DevOps%{linkEnd} is enabled on this project"
msgstr ""
@@ -2504,6 +2629,9 @@ msgstr ""
msgid "Almost there"
msgstr ""
+msgid "Already blocked"
+msgstr ""
+
msgid "Also called \"Issuer\" or \"Relying party trust identifier\""
msgstr ""
@@ -2558,6 +2686,9 @@ msgstr ""
msgid "An error has occurred"
msgstr ""
+msgid "An error occured while making the changes: %{error}"
+msgstr ""
+
msgid "An error occurred adding a draft to the thread."
msgstr ""
@@ -2585,12 +2716,6 @@ msgstr ""
msgid "An error occurred when toggling the notification subscription"
msgstr ""
-msgid "An error occurred when trying to resolve a comment. Please try again."
-msgstr ""
-
-msgid "An error occurred when trying to resolve a discussion. Please try again."
-msgstr ""
-
msgid "An error occurred when updating the issue weight"
msgstr ""
@@ -2606,12 +2731,6 @@ msgstr ""
msgid "An error occurred while checking group path. Please refresh and try again."
msgstr ""
-msgid "An error occurred while committing your changes."
-msgstr ""
-
-msgid "An error occurred while creating the list. Please try again."
-msgstr ""
-
msgid "An error occurred while decoding the file."
msgstr ""
@@ -2684,25 +2803,19 @@ msgstr ""
msgid "An error occurred while fetching the Service Desk address."
msgstr ""
-msgid "An error occurred while fetching the board issues. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the board lists. Please reload the page."
msgstr ""
msgid "An error occurred while fetching the board lists. Please try again."
msgstr ""
-msgid "An error occurred while fetching the board swimlanes. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the builds."
msgstr ""
msgid "An error occurred while fetching the job log."
msgstr ""
-msgid "An error occurred while fetching the job trace."
+msgid "An error occurred while fetching the job logs."
msgstr ""
msgid "An error occurred while fetching the job."
@@ -2849,9 +2962,6 @@ msgstr ""
msgid "An error occurred while saving assignees"
msgstr ""
-msgid "An error occurred while saving the template. Please check if the template exists."
-msgstr ""
-
msgid "An error occurred while searching for milestones"
msgstr ""
@@ -2870,10 +2980,10 @@ msgstr ""
msgid "An error occurred while updating approvers"
msgstr ""
-msgid "An error occurred while updating the comment"
+msgid "An error occurred while updating labels."
msgstr ""
-msgid "An error occurred while updating the list. Please try again."
+msgid "An error occurred while updating the comment"
msgstr ""
msgid "An error occurred while validating group path"
@@ -2927,6 +3037,9 @@ msgstr ""
msgid "An unknown error occurred while loading this graph."
msgstr ""
+msgid "An unknown error occurred."
+msgstr ""
+
msgid "Analytics"
msgstr ""
@@ -2960,10 +3073,10 @@ msgstr ""
msgid "Any"
msgstr ""
-msgid "Any Author"
+msgid "Any %{header}"
msgstr ""
-msgid "Any Status"
+msgid "Any Author"
msgstr ""
msgid "Any branch"
@@ -3017,6 +3130,9 @@ msgstr ""
msgid "Application ID"
msgstr ""
+msgid "Application limits saved successfully"
+msgstr ""
+
msgid "Application settings saved successfully"
msgstr ""
@@ -3226,6 +3342,9 @@ msgstr ""
msgid "Are you sure you want to close this blocked issue?"
msgstr ""
+msgid "Are you sure you want to delete \"%{name}\" Value Stream?"
+msgstr ""
+
msgid "Are you sure you want to delete %{name}?"
msgstr ""
@@ -3235,6 +3354,9 @@ msgstr ""
msgid "Are you sure you want to delete this %{typeOfComment}?"
msgstr ""
+msgid "Are you sure you want to delete this SSH key?"
+msgstr ""
+
msgid "Are you sure you want to delete this board?"
msgstr ""
@@ -3259,6 +3381,11 @@ msgstr ""
msgid "Are you sure you want to erase this build?"
msgstr ""
+msgid "Are you sure you want to import %d repository?"
+msgid_plural "Are you sure you want to import %d repositories?"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Are you sure you want to lose unsaved changes?"
msgstr ""
@@ -3268,15 +3395,15 @@ msgstr ""
msgid "Are you sure you want to merge immediately?"
msgstr ""
-msgid "Are you sure you want to permanently delete this license?"
-msgstr ""
-
msgid "Are you sure you want to re-deploy this environment?"
msgstr ""
msgid "Are you sure you want to regenerate the public key? You will have to update the public key on the remote server before mirroring will work again."
msgstr ""
+msgid "Are you sure you want to reindex?"
+msgstr ""
+
msgid "Are you sure you want to remove %{group_name}?"
msgstr ""
@@ -3304,6 +3431,9 @@ msgstr ""
msgid "Are you sure you want to revoke this nickname?"
msgstr ""
+msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
+msgstr ""
+
msgid "Are you sure you want to stop this environment?"
msgstr ""
@@ -3325,6 +3455,9 @@ msgstr ""
msgid "Are you sure? The device will be signed out of GitLab and all remember me tokens revoked."
msgstr ""
+msgid "Are you sure? This will invalidate your registered applications and U2F / WebAuthn devices."
+msgstr ""
+
msgid "Are you sure? This will invalidate your registered applications and U2F devices."
msgstr ""
@@ -3343,9 +3476,6 @@ msgstr ""
msgid "Artifacts"
msgstr ""
-msgid "As U2F devices are only supported by a few browsers, we require that you set up a two-factor authentication app before a U2F device. That way you'll always be able to log in - even when you're using an unsupported browser."
-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 ""
@@ -3539,6 +3669,9 @@ msgstr ""
msgid "AuditLogs|Target"
msgstr ""
+msgid "AuditLogs|This month"
+msgstr ""
+
msgid "AuditLogs|User Events"
msgstr ""
@@ -3578,6 +3711,9 @@ msgstr ""
msgid "Authentication via U2F device failed."
msgstr ""
+msgid "Authentication via WebAuthn device failed."
+msgstr ""
+
msgid "Author"
msgstr ""
@@ -3845,15 +3981,6 @@ msgstr ""
msgid "BambooService|You must set up automatic revision labeling and a repository trigger in Bamboo."
msgstr ""
-msgid "BatchComments|Delete all pending comments"
-msgstr ""
-
-msgid "BatchComments|Discard review?"
-msgstr ""
-
-msgid "BatchComments|You're about to discard your review which will delete all of your pending comments. The deleted comments %{strong_start}cannot%{strong_end} be restored."
-msgstr ""
-
msgid "Be careful. Changing the project's namespace can have unintended side effects."
msgstr ""
@@ -3875,6 +4002,9 @@ msgstr ""
msgid "Bi-weekly code coverage"
msgstr ""
+msgid "Billable Users:"
+msgstr ""
+
msgid "Billing"
msgstr ""
@@ -3884,7 +4014,7 @@ msgstr ""
msgid "BillingPlans|@%{user_name} you are currently using the %{plan_name} plan."
msgstr ""
-msgid "BillingPlans|Congratulations, your new trial is activated"
+msgid "BillingPlans|Congratulations, your free trial is activated."
msgstr ""
msgid "BillingPlans|If you would like to downgrade your plan please contact %{support_link_start}Customer Support%{support_link_end}."
@@ -3947,6 +4077,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Block user"
+msgstr ""
+
msgid "Blocked"
msgstr ""
@@ -3962,31 +4095,37 @@ msgstr ""
msgid "Blog"
msgstr ""
-msgid "Board name"
-msgstr ""
-
msgid "Board scope"
msgstr ""
msgid "Board scope affects which issues are displayed for anyone who visits this board"
msgstr ""
-msgid "BoardBlankState|Add default lists"
+msgid "Boards"
msgstr ""
-msgid "BoardBlankState|Add the following default lists to your Issue Board with one click:"
+msgid "Boards and Board Lists"
msgstr ""
-msgid "BoardBlankState|Nevermind, I'll use my own"
+msgid "Boards|An error occurred while creating the issue. Please try again."
msgstr ""
-msgid "BoardBlankState|Starting out with the default set of lists will get you right on the way to making the most of your board."
+msgid "Boards|An error occurred while creating the list. Please try again."
msgstr ""
-msgid "Boards"
+msgid "Boards|An error occurred while fetching issues. Please reload the page."
msgstr ""
-msgid "Boards and Board Lists"
+msgid "Boards|An error occurred while fetching the board issues. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching the board swimlanes. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while moving the issue. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while updating the list. Please try again."
msgstr ""
msgid "Boards|Collapse"
@@ -4013,7 +4152,7 @@ msgstr ""
msgid "Branch %{branch_name} was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr ""
-msgid "Branch has changed"
+msgid "Branch changed"
msgstr ""
msgid "Branch is already taken"
@@ -4319,6 +4458,9 @@ msgstr ""
msgid "CLOSED (MOVED)"
msgstr ""
+msgid "CODEOWNERS rule violation"
+msgstr ""
+
msgid "CONTRIBUTING"
msgstr ""
@@ -4349,9 +4491,6 @@ msgstr ""
msgid "Can't create snippet: %{err}"
msgstr ""
-msgid "Can't edit as source branch was deleted"
-msgstr ""
-
msgid "Can't fetch content for the blob: %{err}"
msgstr ""
@@ -4364,9 +4503,6 @@ msgstr ""
msgid "Can't load mermaid module: %{err}"
msgstr ""
-msgid "Can't remove group members without group managed account"
-msgstr ""
-
msgid "Can't scan the code?"
msgstr ""
@@ -4409,6 +4545,9 @@ msgstr ""
msgid "Cannot create the abuse report. This user has been blocked."
msgstr ""
+msgid "Cannot enable shared runners because parent group does not allow it"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -4514,6 +4653,15 @@ msgstr ""
msgid "Change your password or recover your current one"
msgstr ""
+msgid "ChangeReviewer|Reviewer changed from %{old} to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Reviewer changed to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Unassigned"
+msgstr ""
+
msgid "ChangeTypeActionLabel|Pick into branch"
msgstr ""
@@ -4553,6 +4701,9 @@ msgstr ""
msgid "Changes the title to \"%{title_param}\"."
msgstr ""
+msgid "Changes were successfully made."
+msgstr ""
+
msgid "Changes won't take place until the index is %{link_start}recreated%{link_end}."
msgstr ""
@@ -4958,6 +5109,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove variable"
+msgstr ""
+
msgid "CiVariables|Remove variable row"
msgstr ""
@@ -5036,9 +5190,6 @@ msgstr ""
msgid "Clear due date"
msgstr ""
-msgid "Clear input"
-msgstr ""
-
msgid "Clear recent searches"
msgstr ""
@@ -5087,6 +5238,9 @@ msgstr ""
msgid "Client authentication key password"
msgstr ""
+msgid "Client request timeout"
+msgstr ""
+
msgid "Clients"
msgstr ""
@@ -5171,6 +5325,27 @@ msgstr ""
msgid "Cluster type must be specificed for Stages::ClusterEndpointInserter"
msgstr ""
+msgid "ClusterAgents|Configuration"
+msgstr ""
+
+msgid "ClusterAgents|Connect your cluster with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate Kubernetes with a GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Name"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Agent also requires %{linkStart}enabling the Agent Server%{linkEnd}"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Kubernetes Agent allows an Infrastructure as Code, GitOps approach to integrating Kubernetes clusters with GitLab. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "ClusterAgent|This feature is only available for premium plans"
msgstr ""
@@ -5240,10 +5415,10 @@ msgstr ""
msgid "ClusterIntegration|All installed applications and related resources"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster."
+msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{linkStart}More information%{linkEnd}"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{startLink}More information%{endLink}"
+msgid "ClusterIntegration|Allow GitLab to manage namespaces and service accounts for this cluster."
msgstr ""
msgid "ClusterIntegration|Alternatively, "
@@ -5264,6 +5439,9 @@ msgstr ""
msgid "ClusterIntegration|An error occurred while trying to fetch zone machine types: %{error}"
msgstr ""
+msgid "ClusterIntegration|An unknown error occurred while attempting to connect to Kubernetes."
+msgstr ""
+
msgid "ClusterIntegration|Any project namespaces"
msgstr ""
@@ -5279,6 +5457,9 @@ msgstr ""
msgid "ClusterIntegration|Authenticate with Amazon Web Services"
msgstr ""
+msgid "ClusterIntegration|Authentication Error"
+msgstr ""
+
msgid "ClusterIntegration|Base domain"
msgstr ""
@@ -5297,13 +5478,22 @@ msgstr ""
msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}security group %{externalLinkIcon} %{endLink} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
+msgid "ClusterIntegration|Check your CA certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Check your cluster status"
+msgstr ""
+
+msgid "ClusterIntegration|Check your token"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}subnets %{externalLinkIcon} %{endLink} in your VPC where your worker nodes will run."
+msgid "ClusterIntegration|Choose the %{linkStart}security group %{linkEnd} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
msgstr ""
-msgid "ClusterIntegration|Choose the worker node %{startLink}instance type %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Choose the %{linkStart}subnets %{linkEnd} in your VPC where your worker nodes will run."
+msgstr ""
+
+msgid "ClusterIntegration|Choose the worker node %{linkStart}instance type%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Choose which applications to install on your Kubernetes cluster."
@@ -5315,10 +5505,7 @@ msgstr ""
msgid "ClusterIntegration|Clear cluster cache"
msgstr ""
-msgid "ClusterIntegration|Clear the local cache of namespace and service accounts. This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
-msgstr ""
-
-msgid "ClusterIntegration|Cluster being created"
+msgid "ClusterIntegration|Clear the local cache of namespace and service accounts."
msgstr ""
msgid "ClusterIntegration|Cluster management project (alpha)"
@@ -5330,15 +5517,21 @@ msgstr ""
msgid "ClusterIntegration|Cluster_applications artifact too big. Maximum allowable size: %{human_size}"
msgstr ""
-msgid "ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters."
+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|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}"
+msgid "ClusterIntegration|Clusters connected with a certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Connect cluster with certificate"
msgstr ""
msgid "ClusterIntegration|Connect existing cluster"
msgstr ""
+msgid "ClusterIntegration|Connection Error"
+msgstr ""
+
msgid "ClusterIntegration|Copy API URL"
msgstr ""
@@ -5414,6 +5607,12 @@ msgstr ""
msgid "ClusterIntegration|Deletes all GitLab resources attached to this cluster during removal"
msgstr ""
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared."
+msgstr ""
+
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared. %{linkStart}More information%{linkEnd}"
+msgstr ""
+
msgid "ClusterIntegration|Did you know?"
msgstr ""
@@ -5483,6 +5682,9 @@ msgstr ""
msgid "ClusterIntegration|Fluentd is an open source data collector, which lets you unify the data collection and consumption for a better use and understanding of data. It requires at least one of the following logs to be successfully installed."
msgstr ""
+msgid "ClusterIntegration|GitLab Agent managed clusters"
+msgstr ""
+
msgid "ClusterIntegration|GitLab Container Network Policies"
msgstr ""
@@ -5495,6 +5697,12 @@ msgstr ""
msgid "ClusterIntegration|GitLab Runner connects to the repository and executes CI/CD jobs, pushing results back and deploying applications to production."
msgstr ""
+msgid "ClusterIntegration|GitLab failed to authenticate."
+msgstr ""
+
+msgid "ClusterIntegration|GitLab failed to connect to the cluster."
+msgstr ""
+
msgid "ClusterIntegration|GitLab-managed cluster"
msgstr ""
@@ -5516,6 +5724,9 @@ msgstr ""
msgid "ClusterIntegration|Group cluster"
msgstr ""
+msgid "ClusterIntegration|HTTP Error"
+msgstr ""
+
msgid "ClusterIntegration|Helm Tiller"
msgstr ""
@@ -5549,7 +5760,10 @@ msgstr ""
msgid "ClusterIntegration|Instance type"
msgstr ""
-msgid "ClusterIntegration|Integrate Kubernetes cluster automation"
+msgid "ClusterIntegration|Integrate Kubernetes with a cluster certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Integrate with a cluster certificate"
msgstr ""
msgid "ClusterIntegration|Issuer Email"
@@ -5585,9 +5799,6 @@ msgstr ""
msgid "ClusterIntegration|Knative extends Kubernetes to provide a set of middleware components that are essential to build modern, source-centric, and container-based applications that can run anywhere: on premises, in the cloud, or even in a third-party data center."
msgstr ""
-msgid "ClusterIntegration|Kubernetes cluster"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes cluster is being created..."
msgstr ""
@@ -5600,9 +5811,6 @@ msgstr ""
msgid "ClusterIntegration|Kubernetes clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr ""
-msgid "ClusterIntegration|Kubernetes clusters can be used to deploy applications and to provide Review Apps for this project"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes version"
msgstr ""
@@ -5615,7 +5823,7 @@ msgstr ""
msgid "ClusterIntegration|Learn more about %{help_link_start}zones%{help_link_end}."
msgstr ""
-msgid "ClusterIntegration|Learn more about %{startLink}Regions %{externalLinkIcon}%{endLink}."
+msgid "ClusterIntegration|Learn more about %{linkStart}Regions%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Learn more about Kubernetes"
@@ -5660,12 +5868,18 @@ msgstr ""
msgid "ClusterIntegration|Machine type"
msgstr ""
+msgid "ClusterIntegration|Make sure your API endpoint is correct"
+msgstr ""
+
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create Kubernetes clusters"
msgstr ""
msgid "ClusterIntegration|Manage your Kubernetes cluster by visiting %{provider_link}"
msgstr ""
+msgid "ClusterIntegration|Namespace per environment"
+msgstr ""
+
msgid "ClusterIntegration|No IAM Roles found"
msgstr ""
@@ -5711,6 +5925,9 @@ msgstr ""
msgid "ClusterIntegration|No zones matched your search"
msgstr ""
+msgid "ClusterIntegration|Node calculations use the Kubernetes Metrics API. Make sure your cluster has metrics installed"
+msgstr ""
+
msgid "ClusterIntegration|Number of nodes"
msgstr ""
@@ -5753,6 +5970,9 @@ msgstr ""
msgid "ClusterIntegration|RBAC-enabled cluster"
msgstr ""
+msgid "ClusterIntegration|Read our %{linkStart}help page%{linkEnd} on Kubernetes cluster integration."
+msgstr ""
+
msgid "ClusterIntegration|Read our %{link_start}help page%{link_end} on Kubernetes cluster integration."
msgstr ""
@@ -5855,7 +6075,7 @@ msgstr ""
msgid "ClusterIntegration|Select a VPC to choose a subnet"
msgstr ""
-msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{linkStart}Amazon Web Services %{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select a network to choose a subnetwork"
@@ -5888,7 +6108,7 @@ msgstr ""
msgid "ClusterIntegration|Select project to choose zone"
msgstr ""
-msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select zone"
@@ -5978,9 +6198,18 @@ msgstr ""
msgid "ClusterIntegration|There was a problem authenticating with your cluster. Please ensure your CA Certificate and Token are valid."
msgstr ""
+msgid "ClusterIntegration|There was an HTTP error when connecting to your cluster."
+msgstr ""
+
msgid "ClusterIntegration|This account must have permissions to create a Kubernetes cluster in the %{link_to_container_project} specified below"
msgstr ""
+msgid "ClusterIntegration|This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
+msgstr ""
+
+msgid "ClusterIntegration|This is necessary to clear existing environment-namespace associations from clusters previously managed by GitLab."
+msgstr ""
+
msgid "ClusterIntegration|This option will allow you to install applications on RBAC clusters."
msgstr ""
@@ -6005,9 +6234,21 @@ msgstr ""
msgid "ClusterIntegration|To use a new project, first create one on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}."
msgstr ""
+msgid "ClusterIntegration|Troubleshooting tips:"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Authenticate"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Connect"
+msgstr ""
+
msgid "ClusterIntegration|Uninstall %{appTitle}"
msgstr ""
+msgid "ClusterIntegration|Unknown Error"
+msgstr ""
+
msgid "ClusterIntegration|Update %{appTitle}"
msgstr ""
@@ -6068,7 +6309,7 @@ msgstr ""
msgid "ClusterIntegration|Your cluster API is unreachable. Please ensure your API URL is correct."
msgstr ""
-msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Zone"
@@ -6188,6 +6429,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse all threads"
+msgstr ""
+
msgid "Collapse approvers"
msgstr ""
@@ -6337,7 +6581,7 @@ msgstr ""
msgid "Commit…"
msgstr ""
-msgid "Company"
+msgid "Community forum"
msgstr ""
msgid "Company name"
@@ -6346,6 +6590,9 @@ msgstr ""
msgid "Compare"
msgstr ""
+msgid "Compare %{oldCommitId}...%{newCommitId}"
+msgstr ""
+
msgid "Compare Git revisions"
msgstr ""
@@ -6361,6 +6608,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare submodule commit revisions"
+msgstr ""
+
msgid "Compare with previous version"
msgstr ""
@@ -6496,6 +6746,9 @@ msgstr ""
msgid "Configure the way a user creates a new account."
msgstr ""
+msgid "Configure which lists are shown for anyone who visits this board"
+msgstr ""
+
msgid "Confirm"
msgstr ""
@@ -6721,6 +6974,9 @@ msgstr[1] ""
msgid "ContainerRegistry|Set cleanup policy"
msgstr ""
+msgid "ContainerRegistry|Some tags were not deleted"
+msgstr ""
+
msgid "ContainerRegistry|Something went wrong while fetching the cleanup policy."
msgstr ""
@@ -6760,6 +7016,9 @@ msgstr ""
msgid "ContainerRegistry|Tags with names matching this regex pattern will %{italicStart}expire:%{italicEnd}"
msgstr ""
+msgid "ContainerRegistry|The cleanup policy timed out before it could delete all tags. An administrator can %{adminLinkStart}manually run cleanup now%{adminLinkEnd} or you can wait for the cleanup policy to automatically run again. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "ContainerRegistry|The last tag related to this image was recently removed. This empty image and any associated data will be automatically removed as part of the regular Garbage Collection process. If you have any questions, contact your administrator."
msgstr ""
@@ -6892,6 +7151,9 @@ msgstr ""
msgid "Contributions per group member"
msgstr ""
+msgid "Contributor"
+msgstr ""
+
msgid "Contributors"
msgstr ""
@@ -7021,6 +7283,9 @@ msgstr ""
msgid "Could not change HEAD: branch '%{branch}' does not exist"
msgstr ""
+msgid "Could not commit. An unexpected error occurred."
+msgstr ""
+
msgid "Could not connect to FogBugz, check your URL"
msgstr ""
@@ -7060,6 +7325,9 @@ msgstr ""
msgid "Could not find iteration"
msgstr ""
+msgid "Could not load instance counts. Please refresh the page to try again."
+msgstr ""
+
msgid "Could not remove the trigger."
msgstr ""
@@ -7084,10 +7352,10 @@ msgstr ""
msgid "Could not save prometheus manual configuration"
msgstr ""
-msgid "Could not udpdate wiki page"
+msgid "Could not update the LDAP settings"
msgstr ""
-msgid "Could not update the LDAP settings"
+msgid "Could not update wiki page"
msgstr ""
msgid "Could not upload your designs as one or more files uploaded are not supported."
@@ -7745,6 +8013,9 @@ msgstr ""
msgid "DastProfiles|Are you sure you want to delete this profile?"
msgstr ""
+msgid "DastProfiles|Could not create site validation token. Please refresh the page, or try again later."
+msgstr ""
+
msgid "DastProfiles|Could not create the scanner profile. Please try again."
msgstr ""
@@ -7769,6 +8040,12 @@ msgstr ""
msgid "DastProfiles|Could not fetch site profiles. Please refresh the page, or try again later."
msgstr ""
+msgid "DastProfiles|Could not retrieve site validation status. Please refresh the page, or try again later."
+msgstr ""
+
+msgid "DastProfiles|Could not update the scanner profile. Please try again."
+msgstr ""
+
msgid "DastProfiles|Could not update the site profile. Please try again."
msgstr ""
@@ -7784,7 +8061,7 @@ msgstr ""
msgid "DastProfiles|Download validation text file"
msgstr ""
-msgid "DastProfiles|Edit feature will come soon. Please create a new profile if changes needed"
+msgid "DastProfiles|Edit scanner profile"
msgstr ""
msgid "DastProfiles|Edit site profile"
@@ -7817,6 +8094,9 @@ msgstr ""
msgid "DastProfiles|No profiles created yet"
msgstr ""
+msgid "DastProfiles|Passive"
+msgstr ""
+
msgid "DastProfiles|Please enter a valid URL format, ex: http://www.example.com/home"
msgstr ""
@@ -7832,6 +8112,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan mode"
+msgstr ""
+
msgid "DastProfiles|Scanner Profile"
msgstr ""
@@ -7871,10 +8154,10 @@ msgstr ""
msgid "DastProfiles|Text file validation"
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
+msgid "DastProfiles|The maximum number of minutes allowed for the spider to traverse the site."
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the spider to traverse the site."
+msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
msgstr ""
msgid "DastProfiles|Validate"
@@ -7907,6 +8190,9 @@ msgstr ""
msgid "Date picker"
msgstr ""
+msgid "Date range"
+msgstr ""
+
msgid "Date range cannot exceed %{maxDateRange} days."
msgstr ""
@@ -7931,6 +8217,9 @@ msgstr ""
msgid "Days to merge"
msgstr ""
+msgid "Dear Administrator,"
+msgstr ""
+
msgid "Debug"
msgstr ""
@@ -8042,12 +8331,18 @@ msgstr ""
msgid "Delete"
msgstr ""
+msgid "Delete %{name}"
+msgstr ""
+
msgid "Delete Comment"
msgstr ""
msgid "Delete Snippet"
msgstr ""
+msgid "Delete Value Stream"
+msgstr ""
+
msgid "Delete account"
msgstr ""
@@ -8069,9 +8364,6 @@ msgstr ""
msgid "Delete label: %{label_name} ?"
msgstr ""
-msgid "Delete license"
-msgstr ""
-
msgid "Delete list"
msgstr ""
@@ -8147,15 +8439,6 @@ msgstr ""
msgid "Deleting a project places it into a read-only state until %{date}, at which point the project will be permanently deleted. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "Deleting the license failed."
-msgstr ""
-
-msgid "Deleting the license failed. The license was not found."
-msgstr ""
-
-msgid "Deleting the license failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "Deleting the project will delete its repository and all related resources including issues, merge requests etc."
msgstr ""
@@ -8651,7 +8934,10 @@ msgstr ""
msgid "DesignManagement|The maximum number of designs allowed to be uploaded is %{upload_limit}. Please try again."
msgstr ""
-msgid "DesignManagement|To upload designs, you'll need to enable LFS. %{requirements_link_start}More information%{requirements_link_end}"
+msgid "DesignManagement|There was an error moving your designs. Please upload your designs below."
+msgstr ""
+
+msgid "DesignManagement|To upload designs, you'll need to enable LFS and have admin enable hashed storage. %{requirements_link_start}More information%{requirements_link_end}"
msgstr ""
msgid "DesignManagement|Unresolve thread"
@@ -8663,6 +8949,9 @@ msgstr ""
msgid "DesignManagement|Upload skipped."
msgstr ""
+msgid "DesignManagement|Your designs are being copied and are on their way… Please refresh to update."
+msgstr ""
+
msgid "DesignManagement|and %{moreCount} more."
msgstr ""
@@ -8720,6 +9009,9 @@ msgstr ""
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
+msgid "Direct member"
+msgstr ""
+
msgid "Direction"
msgstr ""
@@ -8768,9 +9060,6 @@ msgstr ""
msgid "Discard draft"
msgstr ""
-msgid "Discard review"
-msgstr ""
-
msgid "DiscordService|Discord Notifications"
msgstr ""
@@ -8839,10 +9128,10 @@ msgstr ""
msgid "Dismiss Merge Request promotion"
msgstr ""
-msgid "Dismiss Selected"
+msgid "Dismiss Value Stream Analytics introduction box"
msgstr ""
-msgid "Dismiss Value Stream Analytics introduction box"
+msgid "Dismiss selected"
msgstr ""
msgid "Dismiss trial promotion"
@@ -8893,9 +9182,6 @@ msgstr ""
msgid "Documents reindexed: %{processed_documents} (%{percentage}%%)"
msgstr ""
-msgid "Doing"
-msgstr ""
-
msgid "Domain"
msgstr ""
@@ -9091,9 +9377,6 @@ msgstr ""
msgid "Edit environment"
msgstr ""
-msgid "Edit file"
-msgstr ""
-
msgid "Edit files in the editor and commit changes here"
msgstr ""
@@ -9106,6 +9389,12 @@ msgstr ""
msgid "Edit identity for %{user_name}"
msgstr ""
+msgid "Edit in Web IDE"
+msgstr ""
+
+msgid "Edit in single-file editor"
+msgstr ""
+
msgid "Edit issues"
msgstr ""
@@ -9133,10 +9422,10 @@ msgstr ""
msgid "Editing"
msgstr ""
-msgid "Elasticsearch"
+msgid "Elasticsearch AWS IAM credentials"
msgstr ""
-msgid "Elasticsearch AWS IAM credentials"
+msgid "Elasticsearch HTTP client timeout value in seconds."
msgstr ""
msgid "Elasticsearch indexing restrictions"
@@ -9145,9 +9434,6 @@ msgstr ""
msgid "Elasticsearch indexing started"
msgstr ""
-msgid "Elasticsearch integration. Elasticsearch AWS IAM."
-msgstr ""
-
msgid "Elasticsearch reindexing is already in progress"
msgstr ""
@@ -9175,9 +9461,6 @@ msgstr ""
msgid "Email Notification"
msgstr ""
-msgid "Email address"
-msgstr ""
-
msgid "Email could not be sent"
msgstr ""
@@ -9241,6 +9524,9 @@ msgstr ""
msgid "Emails sent from Service Desk will have this name"
msgstr ""
+msgid "Emails sent to %{email} will still be supported"
+msgstr ""
+
msgid "Emails separated by comma"
msgstr ""
@@ -9274,9 +9560,18 @@ msgstr ""
msgid "Enable"
msgstr ""
+msgid "Enable %{link_start}Gitpod%{link_end} integration to launch a development environment in your browser directly from GitLab."
+msgstr ""
+
msgid "Enable Auto DevOps"
msgstr ""
+msgid "Enable Gitpod"
+msgstr ""
+
+msgid "Enable Gitpod?"
+msgstr ""
+
msgid "Enable HTML emails"
msgstr ""
@@ -9406,9 +9701,6 @@ msgstr ""
msgid "Encountered an error while rendering: %{err}"
msgstr ""
-msgid "End date"
-msgstr ""
-
msgid "Ends at (UTC)"
msgstr ""
@@ -9568,7 +9860,7 @@ msgstr ""
msgid "EnvironmentsDashboard|The environments dashboard provides a summary of each project's environments' status, including pipeline and alert statuses."
msgstr ""
-msgid "EnvironmentsDashboard|This dashboard displays a maximum of 7 projects and 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
+msgid "EnvironmentsDashboard|This dashboard displays 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
msgstr ""
msgid "Environments|An error occurred while canceling the auto stop, please try again"
@@ -9889,6 +10181,9 @@ msgstr ""
msgid "Error deleting project. Check logs for error details."
msgstr ""
+msgid "Error fetching burnup chart data"
+msgstr ""
+
msgid "Error fetching diverging counts for branches. Please try again."
msgstr ""
@@ -9967,6 +10262,9 @@ msgstr ""
msgid "Error occurred when saving assignees"
msgstr ""
+msgid "Error occurred when saving reviewers"
+msgstr ""
+
msgid "Error occurred when toggling the notification subscription"
msgstr ""
@@ -10219,10 +10517,13 @@ msgstr ""
msgid "Expand all"
msgstr ""
-msgid "Expand approvers"
+msgid "Expand all files"
msgstr ""
-msgid "Expand dropdown"
+msgid "Expand all threads"
+msgstr ""
+
+msgid "Expand approvers"
msgstr ""
msgid "Expand milestones"
@@ -10393,6 +10694,9 @@ msgstr ""
msgid "Failed to create Merge Request. Please try again."
msgstr ""
+msgid "Failed to create To-Do for the design."
+msgstr ""
+
msgid "Failed to create a branch for this issue. Please try again."
msgstr ""
@@ -10432,6 +10736,12 @@ msgstr ""
msgid "Failed to load authors. Please try again."
msgstr ""
+msgid "Failed to load branches. Please try again."
+msgstr ""
+
+msgid "Failed to load deploy keys."
+msgstr ""
+
msgid "Failed to load emoji list."
msgstr ""
@@ -10447,6 +10757,9 @@ msgstr ""
msgid "Failed to load groups & users."
msgstr ""
+msgid "Failed to load groups, users and deploy keys."
+msgstr ""
+
msgid "Failed to load labels. Please try again."
msgstr ""
@@ -10456,6 +10769,12 @@ msgstr ""
msgid "Failed to load related branches"
msgstr ""
+msgid "Failed to load sidebar confidential toggle"
+msgstr ""
+
+msgid "Failed to load sidebar lock status"
+msgstr ""
+
msgid "Failed to load stacktrace."
msgstr ""
@@ -10483,6 +10802,9 @@ msgstr ""
msgid "Failed to publish issue on status page."
msgstr ""
+msgid "Failed to remove To-Do for the design."
+msgstr ""
+
msgid "Failed to remove a Zoom meeting"
msgstr ""
@@ -10525,6 +10847,9 @@ msgstr ""
msgid "Failed to signing using smartcard authentication"
msgstr ""
+msgid "Failed to toggle To-Do for the design."
+msgstr ""
+
msgid "Failed to update branch!"
msgstr ""
@@ -10638,7 +10963,7 @@ msgstr ""
msgid "FeatureFlags|Edit User List"
msgstr ""
-msgid "FeatureFlags|Enable features for specific users and specific environments by defining feature flag strategies."
+msgid "FeatureFlags|Enable features for specific users and environments by configuring feature flag strategies."
msgstr ""
msgid "FeatureFlags|Environment Spec"
@@ -10698,7 +11023,7 @@ msgstr ""
msgid "FeatureFlags|Include additional user IDs"
msgstr ""
-msgid "FeatureFlags|Install a %{docs_link_anchored_start}compatible client library%{docs_link_anchored_end} and specify the API URL, application name, and instance ID during the configuration setup. %{docs_link_start}More Information%{docs_link_end}"
+msgid "FeatureFlags|Install a %{docsLinkAnchoredStart}compatible client library%{docsLinkAnchoredEnd} and specify the API URL, application name, and instance ID during the configuration setup. %{docsLinkStart}More Information%{docsLinkEnd}"
msgstr ""
msgid "FeatureFlags|Instance ID"
@@ -10710,6 +11035,9 @@ msgstr ""
msgid "FeatureFlags|Loading feature flags"
msgstr ""
+msgid "FeatureFlags|Loading user lists"
+msgstr ""
+
msgid "FeatureFlags|More information"
msgstr ""
@@ -10728,7 +11056,7 @@ msgstr ""
msgid "FeatureFlags|New feature flag"
msgstr ""
-msgid "FeatureFlags|New list"
+msgid "FeatureFlags|New user list"
msgstr ""
msgid "FeatureFlags|Percent of users"
@@ -10767,6 +11095,9 @@ msgstr ""
msgid "FeatureFlags|There was an error fetching the feature flags."
msgstr ""
+msgid "FeatureFlags|There was an error fetching the user lists."
+msgstr ""
+
msgid "FeatureFlags|There was an error retrieving user lists"
msgstr ""
@@ -10782,6 +11113,9 @@ msgstr ""
msgid "FeatureFlags|User List"
msgstr ""
+msgid "FeatureFlags|User Lists"
+msgstr ""
+
msgid "FeatureFlag|List"
msgstr ""
@@ -10809,15 +11143,6 @@ msgstr ""
msgid "Fetching incoming email"
msgstr ""
-msgid "Fetching licenses failed."
-msgstr ""
-
-msgid "Fetching licenses failed. The request endpoint was not found."
-msgstr ""
-
-msgid "Fetching licenses failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "File"
msgstr ""
@@ -10920,12 +11245,21 @@ msgstr ""
msgid "Filter by status"
msgstr ""
+msgid "Filter by test cases that are currently archived."
+msgstr ""
+
+msgid "Filter by test cases that are currently opened."
+msgstr ""
+
msgid "Filter by two-factor authentication"
msgstr ""
msgid "Filter by user"
msgstr ""
+msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
+msgstr ""
+
msgid "Filter pipelines"
msgstr ""
@@ -10941,7 +11275,7 @@ msgstr ""
msgid "Filter results..."
msgstr ""
-msgid "Filter your projects by name"
+msgid "Filter your repositories by name"
msgstr ""
msgid "Filter..."
@@ -10950,7 +11284,7 @@ msgstr ""
msgid "Find File"
msgstr ""
-msgid "Find bugs in your code with coverage-guided fuzzing"
+msgid "Find bugs in your code with coverage-guided fuzzing."
msgstr ""
msgid "Find by path"
@@ -10977,9 +11311,6 @@ msgstr ""
msgid "Finish editing this message first!"
msgstr ""
-msgid "Finish review"
-msgstr ""
-
msgid "Finish setting up your dedicated account for %{group_name}."
msgstr ""
@@ -11049,6 +11380,9 @@ msgstr ""
msgid "Footer message"
msgstr ""
+msgid "For a faster browsing experience, some files are collapsed by default."
+msgstr ""
+
msgid "For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
@@ -11058,6 +11392,9 @@ msgstr ""
msgid "For more info, read the documentation."
msgstr ""
+msgid "For more information on how the number of active users is calculated, see the %{self_managed_subscriptions_doc_link} documentation."
+msgstr ""
+
msgid "For more information, go to the "
msgstr ""
@@ -11196,6 +11533,9 @@ msgstr ""
msgid "Generate new token"
msgstr ""
+msgid "Generic package file size in bytes"
+msgstr ""
+
msgid "Geo"
msgstr ""
@@ -11457,6 +11797,9 @@ msgstr ""
msgid "Geo|Please refer to Geo Troubleshooting."
msgstr ""
+msgid "Geo|Primary node"
+msgstr ""
+
msgid "Geo|Project"
msgstr ""
@@ -11499,6 +11842,9 @@ msgstr ""
msgid "Geo|Review replication status, and resynchronize and reverify items with the primary node."
msgstr ""
+msgid "Geo|Secondary node"
+msgstr ""
+
msgid "Geo|Status"
msgstr ""
@@ -11538,6 +11884,9 @@ msgstr ""
msgid "Geo|URL must be a valid url (ex: https://gitlab.com)"
msgstr ""
+msgid "Geo|Undefined"
+msgstr ""
+
msgid "Geo|Unknown state"
msgstr ""
@@ -11613,10 +11962,16 @@ msgstr ""
msgid "GitHub import"
msgstr ""
+msgid "GitLab"
+msgstr ""
+
msgid "GitLab / Unsubscribe"
msgstr ""
-msgid "GitLab Enterprise Edition %{plan}"
+msgid "GitLab API"
+msgstr ""
+
+msgid "GitLab Billing Team."
msgstr ""
msgid "GitLab Group Runners can execute code for all the projects in this group."
@@ -11628,12 +11983,18 @@ msgstr ""
msgid "GitLab Issue"
msgstr ""
+msgid "GitLab Pages"
+msgstr ""
+
msgid "GitLab Service Desk is a simple way to allow people to create issues in your GitLab instance without needing their own user account. It provides a unique email address for end users to create issues in a project, and replies can be sent either through the GitLab interface or by email. End users will only see the thread through email."
msgstr ""
msgid "GitLab Shared Runners execute code of different projects on the same Runner unless you configure GitLab Runner Autoscale with MaxBuilds 1 (which it is on GitLab.com)."
msgstr ""
+msgid "GitLab Shell"
+msgstr ""
+
msgid "GitLab Support Bot"
msgstr ""
@@ -11643,7 +12004,7 @@ msgstr ""
msgid "GitLab User"
msgstr ""
-msgid "GitLab allows you to continue using your license even if you exceed the number of seats you purchased. You will be required to pay for these seats when you renew your license."
+msgid "GitLab Workhorse"
msgstr ""
msgid "GitLab commit"
@@ -11811,6 +12172,21 @@ msgstr ""
msgid "Gitlab Pages"
msgstr ""
+msgid "Gitpod"
+msgstr ""
+
+msgid "Gitpod|Add the URL to your Gitpod instance configured to read your GitLab projects."
+msgstr ""
+
+msgid "Gitpod|Enable Gitpod integration"
+msgstr ""
+
+msgid "Gitpod|Gitpod URL"
+msgstr ""
+
+msgid "Gitpod|e.g. https://gitpod.example.com"
+msgstr ""
+
msgid "Given access %{time_ago}"
msgstr ""
@@ -12318,9 +12694,6 @@ msgstr ""
msgid "GroupSAML|Valid SAML Response"
msgstr ""
-msgid "GroupSAML|With group managed accounts enabled, all the users without a group managed account will be excluded from the group."
-msgstr ""
-
msgid "GroupSAML|With prohibit outer forks flag enabled group members will be able to fork project only inside your group."
msgstr ""
@@ -12534,10 +12907,10 @@ msgstr ""
msgid "GroupsNew|Create group"
msgstr ""
-msgid "GroupsNew|GitLab group export"
+msgid "GroupsNew|Import"
msgstr ""
-msgid "GroupsNew|Import"
+msgid "GroupsNew|Import a GitLab group export file"
msgstr ""
msgid "GroupsNew|Import group"
@@ -12680,6 +13053,9 @@ msgid_plural "Hide charts"
msgstr[0] ""
msgstr[1] ""
+msgid "Hide comments on this file"
+msgstr ""
+
msgid "Hide details"
msgstr ""
@@ -12724,6 +13100,15 @@ msgstr ""
msgid "Highest role:"
msgstr ""
+msgid "HighlightBar|Alert events:"
+msgstr ""
+
+msgid "HighlightBar|Alert start time:"
+msgstr ""
+
+msgid "HighlightBar|Original alert:"
+msgstr ""
+
msgid "History"
msgstr ""
@@ -12901,6 +13286,9 @@ msgstr ""
msgid "If enabled, access to projects will be validated on an external service using their classification label."
msgstr ""
+msgid "If the number of active users exceeds the user limit, you will be charged for the number of %{users_over_license_link} at your next license reconciliation."
+msgstr ""
+
msgid "If there is no previous license or if the previous license has expired, some GitLab functionality will be blocked until a new, valid license is uploaded."
msgstr ""
@@ -12940,9 +13328,6 @@ msgstr ""
msgid "If your HTTP repository is not publicly accessible, add your credentials."
msgstr ""
-msgid "Iglu registry URL (optional)"
-msgstr ""
-
msgid "Ignore"
msgstr ""
@@ -12979,6 +13364,16 @@ msgstr ""
msgid "Import"
msgstr ""
+msgid "Import %d compatible repository"
+msgid_plural "Import %d compatible repositories"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Import %d repository"
+msgid_plural "Import %d repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Import CSV"
msgstr ""
@@ -12988,15 +13383,9 @@ msgstr ""
msgid "Import all compatible projects"
msgstr ""
-msgid "Import all compatible repositories"
-msgstr ""
-
msgid "Import all projects"
msgstr ""
-msgid "Import all repositories"
-msgstr ""
-
msgid "Import an exported GitLab project"
msgstr ""
@@ -13084,6 +13473,9 @@ msgstr ""
msgid "ImportProjects|Error importing repository %{project_safe_import_url} into %{project_full_path} - %{message}"
msgstr ""
+msgid "ImportProjects|Import repositories"
+msgstr ""
+
msgid "ImportProjects|Importing the project failed"
msgstr ""
@@ -13096,7 +13488,7 @@ msgstr ""
msgid "ImportProjects|Requesting your %{provider} repositories failed"
msgstr ""
-msgid "ImportProjects|Select the projects you want to import"
+msgid "ImportProjects|Select the repositories you want to import"
msgstr ""
msgid "ImportProjects|The remote data could not be imported."
@@ -13132,9 +13524,6 @@ msgstr ""
msgid "In order to enable Service Desk for your instance, you must first set up incoming email."
msgstr ""
-msgid "In order to gather accurate feature usage data, it can take 1 to 2 weeks to see your index."
-msgstr ""
-
msgid "In order to personalize your experience with GitLab%{br_tag}we would like to know a bit more about you."
msgstr ""
@@ -13165,18 +13554,30 @@ msgstr ""
msgid "IncidentManagement|Create incident"
msgstr ""
+msgid "IncidentManagement|Critical - S1"
+msgstr ""
+
msgid "IncidentManagement|Date created"
msgstr ""
msgid "IncidentManagement|Display your incidents in a dedicated view"
msgstr ""
+msgid "IncidentManagement|High - S2"
+msgstr ""
+
msgid "IncidentManagement|Incident"
msgstr ""
msgid "IncidentManagement|Incidents"
msgstr ""
+msgid "IncidentManagement|Low - S4"
+msgstr ""
+
+msgid "IncidentManagement|Medium - S3"
+msgstr ""
+
msgid "IncidentManagement|No incidents to display."
msgstr ""
@@ -13189,6 +13590,9 @@ msgstr ""
msgid "IncidentManagement|Published to status page"
msgstr ""
+msgid "IncidentManagement|Severity"
+msgstr ""
+
msgid "IncidentManagement|There are no closed incidents"
msgstr ""
@@ -13198,6 +13602,9 @@ msgstr ""
msgid "IncidentManagement|Unassigned"
msgstr ""
+msgid "IncidentManagement|Unknown"
+msgstr ""
+
msgid "IncidentManagement|Unpublished"
msgstr ""
@@ -13219,6 +13626,15 @@ msgstr ""
msgid "Incidents"
msgstr ""
+msgid "Incident|Alert details"
+msgstr ""
+
+msgid "Incident|Summary"
+msgstr ""
+
+msgid "Incident|There was an issue loading alert data. Please try again."
+msgstr ""
+
msgid "Include a Terms of Service agreement and Privacy Policy that all users must accept."
msgstr ""
@@ -13279,6 +13695,9 @@ msgstr ""
msgid "Information about additional Pages templates and how to install them can be found in our %{pages_getting_started_guide}."
msgstr ""
+msgid "Inherited"
+msgstr ""
+
msgid "Inherited:"
msgstr ""
@@ -13359,7 +13778,22 @@ msgstr ""
msgid "Instance administrators group already exists"
msgstr ""
-msgid "Instance license"
+msgid "InstanceStatistics|Groups"
+msgstr ""
+
+msgid "InstanceStatistics|Issues"
+msgstr ""
+
+msgid "InstanceStatistics|Merge Requests"
+msgstr ""
+
+msgid "InstanceStatistics|Pipelines"
+msgstr ""
+
+msgid "InstanceStatistics|Projects"
+msgstr ""
+
+msgid "InstanceStatistics|Users"
msgstr ""
msgid "Integration"
@@ -13371,6 +13805,12 @@ msgstr ""
msgid "Integrations"
msgstr ""
+msgid "Integrations|%{integration} settings saved and active."
+msgstr ""
+
+msgid "Integrations|%{integration} settings saved, but not active."
+msgstr ""
+
msgid "Integrations|All details"
msgstr ""
@@ -13380,6 +13820,12 @@ msgstr ""
msgid "Integrations|Comment settings:"
msgstr ""
+msgid "Integrations|Connection failed. Please check your settings."
+msgstr ""
+
+msgid "Integrations|Connection successful."
+msgstr ""
+
msgid "Integrations|Default settings are inherited from the group level."
msgstr ""
@@ -13395,6 +13841,15 @@ msgstr ""
msgid "Integrations|Includes commit title and branch"
msgstr ""
+msgid "Integrations|Projects using custom settings will not be impacted unless the project owner chooses to use instance-level defaults."
+msgstr ""
+
+msgid "Integrations|Save settings?"
+msgstr ""
+
+msgid "Integrations|Saving will update the default settings for all projects that are not using custom settings."
+msgstr ""
+
msgid "Integrations|Standard"
msgstr ""
@@ -13527,6 +13982,9 @@ msgstr ""
msgid "Invitation"
msgstr ""
+msgid "Invitation declined"
+msgstr ""
+
msgid "Invite"
msgstr ""
@@ -13578,6 +14036,42 @@ 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|%{linkStart}Read more%{linkEnd} about role permissions"
+msgstr ""
+
+msgid "InviteMembersModal|Access expiration date (optional)"
+msgstr ""
+
+msgid "InviteMembersModal|Cancel"
+msgstr ""
+
+msgid "InviteMembersModal|Choose a role permission"
+msgstr ""
+
+msgid "InviteMembersModal|GitLab member or Email address"
+msgstr ""
+
+msgid "InviteMembersModal|Invite"
+msgstr ""
+
+msgid "InviteMembersModal|Invite team members"
+msgstr ""
+
+msgid "InviteMembersModal|Search for members to invite"
+msgstr ""
+
+msgid "InviteMembersModal|User not invited. Feature coming soon!"
+msgstr ""
+
+msgid "InviteMembersModal|Users were succesfully added"
+msgstr ""
+
+msgid "InviteMembersModal|You're inviting members to the %{group_name} group"
+msgstr ""
+
+msgid "InviteMembers|Invite team members"
+msgstr ""
+
msgid "Invited"
msgstr ""
@@ -13632,10 +14126,13 @@ msgstr ""
msgid "Issue cannot be found."
msgstr ""
+msgid "Issue created from vulnerability %{vulnerability_link}"
+msgstr ""
+
msgid "Issue events"
msgstr ""
-msgid "Issue first depoloyed to production"
+msgid "Issue first deployed to production"
msgstr ""
msgid "Issue label"
@@ -13713,6 +14210,9 @@ msgstr ""
msgid "IssueTracker|Custom issue tracker"
msgstr ""
+msgid "IssueTracker|EWM work items tracker"
+msgstr ""
+
msgid "IssueTracker|Redmine issue tracker"
msgstr ""
@@ -13779,6 +14279,9 @@ msgstr ""
msgid "It looks like you have some draft commits in this branch."
msgstr ""
+msgid "It may be several days before you see feature usage data."
+msgstr ""
+
msgid "It must have a header row and at least two columns: the first column is the issue title and the second column is the issue description. The separator is automatically detected."
msgstr ""
@@ -14061,13 +14564,13 @@ msgstr ""
msgid "Join Zoom meeting"
msgstr ""
-msgid "Jul"
+msgid "Joined %{time_ago}"
msgstr ""
-msgid "July"
+msgid "Jul"
msgstr ""
-msgid "Jump to first unresolved thread"
+msgid "July"
msgstr ""
msgid "Jump to next unresolved thread"
@@ -14103,6 +14606,9 @@ msgstr ""
msgid "Keyboard shortcuts"
msgstr ""
+msgid "KeyboardKey|Ctrl+"
+msgstr ""
+
msgid "Keys"
msgstr ""
@@ -14151,6 +14657,9 @@ msgstr ""
msgid "LDAP Synchronization"
msgstr ""
+msgid "LDAP group settings"
+msgstr ""
+
msgid "LDAP settings"
msgstr ""
@@ -14160,6 +14669,9 @@ msgstr ""
msgid "LDAP sync in progress. This could take a few minutes. Refresh the page to see the changes."
msgstr ""
+msgid "LDAP synchronizations"
+msgstr ""
+
msgid "LFS"
msgstr ""
@@ -14240,7 +14752,16 @@ msgid_plural "Last %d days"
msgstr[0] ""
msgstr[1] ""
-msgid "Last %{days} days"
+msgid "Last 2 weeks"
+msgstr ""
+
+msgid "Last 30 days"
+msgstr ""
+
+msgid "Last 60 days"
+msgstr ""
+
+msgid "Last 90 days"
msgstr ""
msgid "Last Accessed On"
@@ -14318,6 +14839,9 @@ msgstr ""
msgid "Last used on:"
msgstr ""
+msgid "Last week"
+msgstr ""
+
msgid "LastCommit|authored"
msgstr ""
@@ -14333,6 +14857,9 @@ msgstr ""
msgid "Latest pipeline for the most recent commit on this branch"
msgstr ""
+msgid "Launch a ready-to-code development environment for your project."
+msgstr ""
+
msgid "Lead"
msgstr ""
@@ -14713,6 +15240,9 @@ msgstr ""
msgid "List of all merge commits"
msgstr ""
+msgid "List options"
+msgstr ""
+
msgid "List settings"
msgstr ""
@@ -14725,9 +15255,6 @@ msgstr ""
msgid "List your Bitbucket Server repositories"
msgstr ""
-msgid "Lists"
-msgstr ""
-
msgid "Live preview"
msgstr ""
@@ -14974,6 +15501,12 @@ msgstr ""
msgid "Mark as done"
msgstr ""
+msgid "Mark as draft"
+msgstr ""
+
+msgid "Mark as ready"
+msgstr ""
+
msgid "Mark as resolved"
msgstr ""
@@ -14995,6 +15528,24 @@ msgstr ""
msgid "Markdown is supported"
msgstr ""
+msgid "MarkdownEditor|Add a link (%{modifierKey}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add a link (%{modifier_key}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifierKey}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifier_key}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifierKey}I)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifier_key}I)"
+msgstr ""
+
msgid "Marked For Deletion At - %{deletion_time}"
msgstr ""
@@ -15079,7 +15630,25 @@ msgstr ""
msgid "Max access level"
msgstr ""
-msgid "Max seats used"
+msgid "Max role"
+msgstr ""
+
+msgid "Max size 15 MB"
+msgstr ""
+
+msgid "Maximum Conan package file size in bytes"
+msgstr ""
+
+msgid "Maximum Maven package file size in bytes"
+msgstr ""
+
+msgid "Maximum NPM package file size in bytes"
+msgstr ""
+
+msgid "Maximum NuGet package file size in bytes"
+msgstr ""
+
+msgid "Maximum PyPI package file size in bytes"
msgstr ""
msgid "Maximum Users:"
@@ -15211,6 +15780,18 @@ msgstr ""
msgid "Members with access to %{strong_start}%{group_name}%{strong_end}"
msgstr ""
+msgid "Members|%{time} by %{user}"
+msgstr ""
+
+msgid "Members|Expired"
+msgstr ""
+
+msgid "Members|No expiration set"
+msgstr ""
+
+msgid "Members|in %{time}"
+msgstr ""
+
msgid "Memory Usage"
msgstr ""
@@ -15397,9 +15978,6 @@ msgstr ""
msgid "MergeRequests|Thread will be unresolved"
msgstr ""
-msgid "MergeRequests|Toggle comments for this file"
-msgstr ""
-
msgid "MergeRequests|View file @ %{commitId}"
msgstr ""
@@ -15460,6 +16038,9 @@ msgstr ""
msgid "Merging immediately isn't recommended as it may negatively impact the existing merge train. Read the %{docsLinkStart}documentation%{docsLinkEnd} for more information."
msgstr ""
+msgid "Message"
+msgstr ""
+
msgid "Messages"
msgstr ""
@@ -15845,18 +16426,12 @@ msgid_plural "Milestones"
msgstr[0] ""
msgstr[1] ""
-msgid "Milestone does not support burnup charts"
-msgstr ""
-
msgid "Milestone lists not available with your current license"
msgstr ""
msgid "Milestone lists show all issues from the selected milestone."
msgstr ""
-msgid "Milestone must have a start and due date"
-msgstr ""
-
msgid "MilestoneSidebar|Closed:"
msgstr ""
@@ -16223,6 +16798,9 @@ msgstr ""
msgid "Namespace"
msgstr ""
+msgid "Namespace ID:"
+msgstr ""
+
msgid "Namespace is empty"
msgstr ""
@@ -16307,6 +16885,9 @@ msgstr ""
msgid "NetworkPolicies|Allow all outbound traffic from %{selector} to %{ruleSelector} on %{ports}"
msgstr ""
+msgid "NetworkPolicies|Are you sure you want to delete this policy? This action cannot be undone."
+msgstr ""
+
msgid "NetworkPolicies|Choose whether to enforce this policy."
msgstr ""
@@ -16316,12 +16897,21 @@ msgstr ""
msgid "NetworkPolicies|Define this policy's location, conditions and actions."
msgstr ""
+msgid "NetworkPolicies|Delete policy"
+msgstr ""
+
+msgid "NetworkPolicies|Delete policy: %{policy}"
+msgstr ""
+
msgid "NetworkPolicies|Deny all traffic"
msgstr ""
msgid "NetworkPolicies|Description"
msgstr ""
+msgid "NetworkPolicies|Edit policy"
+msgstr ""
+
msgid "NetworkPolicies|Editor mode"
msgstr ""
@@ -16349,6 +16939,9 @@ msgstr ""
msgid "NetworkPolicies|Name"
msgstr ""
+msgid "NetworkPolicies|Namespace"
+msgstr ""
+
msgid "NetworkPolicies|Network Policy"
msgstr ""
@@ -16400,6 +16993,9 @@ msgstr ""
msgid "NetworkPolicies|Rules"
msgstr ""
+msgid "NetworkPolicies|Save changes"
+msgstr ""
+
msgid "NetworkPolicies|Something went wrong, failed to update policy"
msgstr ""
@@ -16412,6 +17008,9 @@ msgstr ""
msgid "NetworkPolicies|Traffic that does not match any rule will be blocked."
msgstr ""
+msgid "NetworkPolicies|Unable to parse policy"
+msgstr ""
+
msgid "NetworkPolicies|YAML editor"
msgstr ""
@@ -16525,6 +17124,9 @@ msgstr ""
msgid "New Snippet"
msgstr ""
+msgid "New Test Case"
+msgstr ""
+
msgid "New User"
msgstr ""
@@ -16624,6 +17226,9 @@ msgstr ""
msgid "New tag"
msgstr ""
+msgid "New test case"
+msgstr ""
+
msgid "New users set to external"
msgstr ""
@@ -16696,7 +17301,7 @@ msgstr ""
msgid "No changes"
msgstr ""
-msgid "No changes between %{ref_start}%{source_branch}%{ref_end} and %{ref_start}%{target_branch}%{ref_end}"
+msgid "No changes between %{sourceBranch} and %{targetBranch}"
msgstr ""
msgid "No child epics match applied filters"
@@ -16711,6 +17316,9 @@ msgstr ""
msgid "No containers available"
msgstr ""
+msgid "No content to show"
+msgstr ""
+
msgid "No contributions"
msgstr ""
@@ -16786,9 +17394,6 @@ msgstr ""
msgid "No license. All rights reserved"
msgstr ""
-msgid "No licenses found."
-msgstr ""
-
msgid "No matches found"
msgstr ""
@@ -16801,6 +17406,9 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No members found"
+msgstr ""
+
msgid "No merge requests found"
msgstr ""
@@ -16822,6 +17430,9 @@ msgstr ""
msgid "No parent group"
msgstr ""
+msgid "No plan"
+msgstr ""
+
msgid "No pods available"
msgstr ""
@@ -16918,6 +17529,12 @@ msgstr ""
msgid "Not Implemented"
msgstr ""
+msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+msgstr ""
+
+msgid "Not all browsers support WebAuthn. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even from an unsupported browser."
+msgstr ""
+
msgid "Not all data has been processed yet, the accuracy of the chart for the selected timeframe is limited."
msgstr ""
@@ -17014,6 +17631,9 @@ msgstr ""
msgid "Notification settings saved"
msgstr ""
+msgid "NotificationEvent|Change reviewer merge request"
+msgstr ""
+
msgid "NotificationEvent|Close issue"
msgstr ""
@@ -17176,10 +17796,7 @@ msgstr ""
msgid "On track"
msgstr ""
-msgid "OnDemandScans|Attached branch"
-msgstr ""
-
-msgid "OnDemandScans|Attached branch is where the scan job runs."
+msgid "OnDemandScans|Could not fetch scanner profiles. Please refresh the page, or try again later."
msgstr ""
msgid "OnDemandScans|Could not fetch site profiles. Please refresh the page, or try again later."
@@ -17188,6 +17805,9 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
+msgid "OnDemandScans|Create a new scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Create a new site profile"
msgstr ""
@@ -17200,6 +17820,9 @@ msgstr ""
msgid "OnDemandScans|New on-demand DAST scan"
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 ""
@@ -17209,16 +17832,10 @@ msgstr ""
msgid "OnDemandScans|On-demand scans run outside the DevOps cycle and find vulnerabilities in your projects. %{learnMoreLinkStart}Learn more%{learnMoreLinkEnd}"
msgstr ""
-msgid "OnDemandScans|Only a passive scan can be performed on demand."
-msgstr ""
-
-msgid "OnDemandScans|Passive"
-msgstr ""
-
msgid "OnDemandScans|Run scan"
msgstr ""
-msgid "OnDemandScans|Scan mode"
+msgid "OnDemandScans|Scanner profile"
msgstr ""
msgid "OnDemandScans|Scanner settings"
@@ -17230,9 +17847,15 @@ msgstr ""
msgid "OnDemandScans|Select one of the existing profiles"
msgstr ""
+msgid "OnDemandScans|Site profile"
+msgstr ""
+
msgid "OnDemandScans|Site profiles"
msgstr ""
+msgid "OnDemandScans|Use existing scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Use existing site profile"
msgstr ""
@@ -17331,9 +17954,6 @@ msgstr ""
msgid "Open Selection"
msgstr ""
-msgid "Open Web IDE"
-msgstr ""
-
msgid "Open comment type dropdown"
msgstr ""
@@ -17439,6 +18059,9 @@ msgstr ""
msgid "Origin"
msgstr ""
+msgid "Orphaned member"
+msgstr ""
+
msgid "Other Labels"
msgstr ""
@@ -17454,6 +18077,9 @@ msgstr ""
msgid "Other visibility settings have been disabled by the administrator."
msgstr ""
+msgid "Our documentation includes an example DevOps Score report."
+msgstr ""
+
msgid "Out-of-compliance with this project's policies and should be removed"
msgstr ""
@@ -17478,6 +18104,9 @@ msgstr ""
msgid "Overwrite diverged branches"
msgstr ""
+msgid "Owned by %{image_tag}"
+msgstr ""
+
msgid "Owned by anyone"
msgstr ""
@@ -17499,6 +18128,9 @@ msgstr ""
msgid "Package deleted successfully"
msgstr ""
+msgid "Package file size limits"
+msgstr ""
+
msgid "Package recipe already exists"
msgstr ""
@@ -17514,9 +18146,6 @@ msgstr ""
msgid "Package type must be PyPi"
msgstr ""
-msgid "Package was removed"
-msgstr ""
-
msgid "PackageRegistry|%{name} version %{version} was created %{datetime}"
msgstr ""
@@ -17658,12 +18287,18 @@ msgstr ""
msgid "PackageRegistry|NuGet Command"
msgstr ""
+msgid "PackageRegistry|Package Registry"
+msgstr ""
+
msgid "PackageRegistry|Pip Command"
msgstr ""
msgid "PackageRegistry|Pipeline %{link} triggered %{datetime} by %{author}"
msgstr ""
+msgid "PackageRegistry|Publish and share packages for a variety of common package managers. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "PackageRegistry|Published to the %{project} Package Registry %{datetime}"
msgstr ""
@@ -17763,6 +18398,9 @@ msgstr ""
msgid "Page not found"
msgstr ""
+msgid "Page settings"
+msgstr ""
+
msgid "Page was successfully deleted"
msgstr ""
@@ -17904,7 +18542,7 @@ msgstr ""
msgid "Paste issue link"
msgstr ""
-msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Don't use your private SSH key."
+msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Do not paste your private SSH key, as that can compromise your identity."
msgstr ""
msgid "Patch to apply"
@@ -17931,6 +18569,9 @@ msgstr ""
msgid "Pending"
msgstr ""
+msgid "Pending comments"
+msgstr ""
+
msgid "People without permission will never get a notification and won't be able to comment."
msgstr ""
@@ -18129,6 +18770,9 @@ msgstr ""
msgid "Pipelines|Build with confidence"
msgstr ""
+msgid "Pipelines|By revoking a trigger you will break any processes making use of it. Are you sure?"
+msgstr ""
+
msgid "Pipelines|CI Lint"
msgstr ""
@@ -18141,6 +18785,15 @@ msgstr ""
msgid "Pipelines|Continuous Integration can help catch bugs by running your tests automatically, while Continuous Deployment can help you deliver code to your product environment."
msgstr ""
+msgid "Pipelines|Copy trigger token"
+msgstr ""
+
+msgid "Pipelines|Description"
+msgstr ""
+
+msgid "Pipelines|Edit"
+msgstr ""
+
msgid "Pipelines|Get started with Pipelines"
msgstr ""
@@ -18156,15 +18809,27 @@ msgstr ""
msgid "Pipelines|It is recommended the code is reviewed thoroughly before running this pipeline with the parent project's CI resource."
msgstr ""
+msgid "Pipelines|Last Used"
+msgstr ""
+
msgid "Pipelines|Loading Pipelines"
msgstr ""
msgid "Pipelines|More Information"
msgstr ""
+msgid "Pipelines|No triggers have been created yet. Add one using the form above."
+msgstr ""
+
+msgid "Pipelines|Owner"
+msgstr ""
+
msgid "Pipelines|Project cache successfully reset."
msgstr ""
+msgid "Pipelines|Revoke"
+msgstr ""
+
msgid "Pipelines|Run Pipeline"
msgstr ""
@@ -18189,6 +18854,15 @@ msgstr ""
msgid "Pipelines|This project is not currently set up to run pipelines."
msgstr ""
+msgid "Pipelines|Token"
+msgstr ""
+
+msgid "Pipelines|Trigger user has insufficient permissions to project"
+msgstr ""
+
+msgid "Pipelines|invalid"
+msgstr ""
+
msgid "Pipelines|parent"
msgstr ""
@@ -18447,10 +19121,10 @@ msgstr ""
msgid "Please provide attributes to update"
msgstr ""
-msgid "Please refer to %{docs_url}"
+msgid "Please reach out if you have any questions and we'll be happy to assist."
msgstr ""
-msgid "Please retype the email address."
+msgid "Please refer to %{docs_url}"
msgstr ""
msgid "Please select"
@@ -18480,6 +19154,9 @@ msgstr ""
msgid "Please set a new password before proceeding."
msgstr ""
+msgid "Please share your feedback about %{featureName} %{linkStart}in this issue%{linkEnd} to help us improve the experience."
+msgstr ""
+
msgid "Please solve the reCAPTCHA"
msgstr ""
@@ -18783,6 +19460,9 @@ msgstr ""
msgid "Profiles| You are going to change the username %{currentUsernameBold} to %{newUsernameBold}. Profile and projects will be redirected to the %{newUsername} namespace but this redirect will expire once the %{currentUsername} namespace is registered by another user or group. Please update your Git repository remotes as soon as possible."
msgstr ""
+msgid "Profiles|%{provider} Active"
+msgstr ""
+
msgid "Profiles|@username"
msgstr ""
@@ -18834,7 +19514,7 @@ msgstr ""
msgid "Profiles|Commit email"
msgstr ""
-msgid "Profiles|Connect"
+msgid "Profiles|Connect %{provider}"
msgstr ""
msgid "Profiles|Connected Accounts"
@@ -18858,6 +19538,9 @@ msgstr ""
msgid "Profiles|Disconnect"
msgstr ""
+msgid "Profiles|Disconnect %{provider}"
+msgstr ""
+
msgid "Profiles|Do not show on profile"
msgstr ""
@@ -18882,7 +19565,7 @@ msgstr ""
msgid "Profiles|Full name"
msgstr ""
-msgid "Profiles|Give your individual key a title. This will be publically visible."
+msgid "Profiles|Give your individual key a title."
msgstr ""
msgid "Profiles|Include private contributions on my profile"
@@ -18972,7 +19655,7 @@ msgstr ""
msgid "Profiles|The maximum file size allowed is 200KB."
msgstr ""
-msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it?"
+msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it? It will be publicly visible."
msgstr ""
msgid "Profiles|This email will be displayed on your public profile"
@@ -19047,6 +19730,9 @@ msgstr ""
msgid "Profiles|You don't have access to delete this user."
msgstr ""
+msgid "Profiles|You must transfer ownership or delete groups you are an owner of before you can delete your account"
+msgstr ""
+
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
@@ -19635,6 +20321,9 @@ msgstr ""
msgid "ProjectTemplates|GitLab Cluster Management"
msgstr ""
+msgid "ProjectTemplates|Gitpod/Spring Petclinic"
+msgstr ""
+
msgid "ProjectTemplates|Go Micro"
msgstr ""
@@ -20244,6 +20933,9 @@ msgstr ""
msgid "Publish to status page"
msgstr ""
+msgid "Published"
+msgstr ""
+
msgid "Published on status page"
msgstr ""
@@ -20361,9 +21053,15 @@ msgstr ""
msgid "Quick range"
msgstr ""
+msgid "Quickly and easily edit multiple files in your project."
+msgstr ""
+
msgid "README"
msgstr ""
+msgid "Rails"
+msgstr ""
+
msgid "Rake Tasks Help"
msgstr ""
@@ -20483,10 +21181,13 @@ msgstr ""
msgid "Register Two-Factor Authenticator"
msgstr ""
-msgid "Register U2F device"
+msgid "Register Universal Two-Factor (U2F) Device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register WebAuthn Device"
+msgstr ""
+
+msgid "Register device"
msgstr ""
msgid "Register for GitLab"
@@ -20498,9 +21199,6 @@ msgstr ""
msgid "Register with two-factor app"
msgstr ""
-msgid "Registration"
-msgstr ""
-
msgid "Registration|Checkout"
msgstr ""
@@ -20617,9 +21315,6 @@ msgstr ""
msgid "Release|Something went wrong while saving the release details"
msgstr ""
-msgid "Remediated: needs review"
-msgstr ""
-
msgid "Remediations"
msgstr ""
@@ -20725,6 +21420,9 @@ msgstr ""
msgid "Remove priority"
msgstr ""
+msgid "Remove report"
+msgstr ""
+
msgid "Remove secondary node"
msgstr ""
@@ -20737,6 +21435,12 @@ msgstr ""
msgid "Remove time estimate"
msgstr ""
+msgid "Remove user & report"
+msgstr ""
+
+msgid "Remove user from group"
+msgstr ""
+
msgid "Removed"
msgstr ""
@@ -20818,9 +21522,6 @@ msgstr ""
msgid "Removes time estimate."
msgstr ""
-msgid "Removing license…"
-msgstr ""
-
msgid "Removing this group also removes all child projects, including archived projects, and their resources."
msgstr ""
@@ -20905,6 +21606,9 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
+msgid "Reported by %{reporter}"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -20991,6 +21695,27 @@ msgstr ""
msgid "Repositories"
msgstr ""
+msgid "Repositories Analytics"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download Historic Test Coverage Data"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download historic test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Historic Test Coverage Data is available in raw format (.csv) for further analysis."
+msgstr ""
+
+msgid "RepositoriesAnalytics|Test Code Coverage"
+msgstr ""
+
+msgid "RepositoriesAnalytics|There was an error fetching the projects."
+msgstr ""
+
msgid "Repository"
msgstr ""
@@ -21069,9 +21794,15 @@ msgstr ""
msgid "Request parameter %{param} is missing."
msgstr ""
+msgid "Request review from"
+msgstr ""
+
msgid "Request to link SAML account must be authorized"
msgstr ""
+msgid "Requested"
+msgstr ""
+
msgid "Requested %{time_ago}"
msgstr ""
@@ -21090,6 +21821,9 @@ msgstr ""
msgid "Requests to these domain(s)/address(es) on the local network will be allowed when local requests from hooks and services are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 or 127.0.0.0/28 are supported. Domain wildcards are not supported currently. Use comma, semicolon, or newline to separate multiple entries. The allowlist can hold a maximum of 1000 entries. Domains should use IDNA encoding. Ex: example.com, 192.168.1.1, 127.0.0.0/28, xn--itlab-j1a.com."
msgstr ""
+msgid "Require admin approval for new sign-ups"
+msgstr ""
+
msgid "Require all users in this group to setup Two-factor authentication"
msgstr ""
@@ -21217,9 +21951,6 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
-msgid "Resolved by %{resolvedByName}"
-msgstr ""
-
msgid "Resolves IP addresses once and uses them to submit requests"
msgstr ""
@@ -21339,6 +22070,14 @@ msgstr ""
msgid "ReviewApp|Enable Review App"
msgstr ""
+msgid "Reviewer"
+msgid_plural "%d Reviewers"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Reviewer(s)"
+msgstr ""
+
msgid "Reviewing"
msgstr ""
@@ -21378,6 +22117,9 @@ msgstr ""
msgid "Rook"
msgstr ""
+msgid "Ruby"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -21456,6 +22198,63 @@ msgstr ""
msgid "Runners page."
msgstr ""
+msgid "Runners|Active"
+msgstr ""
+
+msgid "Runners|Architecture"
+msgstr ""
+
+msgid "Runners|Can run untagged jobs"
+msgstr ""
+
+msgid "Runners|Description"
+msgstr ""
+
+msgid "Runners|Group"
+msgstr ""
+
+msgid "Runners|IP Address"
+msgstr ""
+
+msgid "Runners|Last contact"
+msgstr ""
+
+msgid "Runners|Locked to this project"
+msgstr ""
+
+msgid "Runners|Maximum job timeout"
+msgstr ""
+
+msgid "Runners|Name"
+msgstr ""
+
+msgid "Runners|Platform"
+msgstr ""
+
+msgid "Runners|Property Name"
+msgstr ""
+
+msgid "Runners|Protected"
+msgstr ""
+
+msgid "Runners|Revision"
+msgstr ""
+
+msgid "Runners|Shared"
+msgstr ""
+
+msgid "Runners|Specific"
+msgstr ""
+
+msgid "Runners|Tags"
+msgstr ""
+
+msgid "Runners|Value"
+msgstr ""
+
+msgid "Runners|Version"
+msgstr ""
+
msgid "Runners|You have used %{quotaUsed} out of %{quotaLimit} of your shared Runners pipeline minutes."
msgstr ""
@@ -21468,6 +22267,9 @@ msgstr ""
msgid "Runs a number of housekeeping tasks within the current repository, such as compressing file revisions and removing unreachable objects."
msgstr ""
+msgid "SAML"
+msgstr ""
+
msgid "SAML SSO"
msgstr ""
@@ -21519,6 +22321,9 @@ msgstr ""
msgid "Save"
msgstr ""
+msgid "Save %{name} size limits"
+msgstr ""
+
msgid "Save Changes"
msgstr ""
@@ -21549,9 +22354,6 @@ msgstr ""
msgid "Save space and find tags in the Container Registry more easily. Enable the cleanup policy to remove stale tags and keep only the ones you need."
msgstr ""
-msgid "Save template"
-msgstr ""
-
msgid "Save variables"
msgstr ""
@@ -21594,9 +22396,6 @@ msgstr ""
msgid "Scope"
msgstr ""
-msgid "Scope not supported with disabled 'users_search' feature!"
-msgstr ""
-
msgid "Scoped issue boards"
msgstr ""
@@ -21723,9 +22522,6 @@ msgstr ""
msgid "Search requirements"
msgstr ""
-msgid "Search results…"
-msgstr ""
-
msgid "Search users"
msgstr ""
@@ -21798,6 +22594,11 @@ msgid_plural "SearchResults|commits"
msgstr[0] ""
msgstr[1] ""
+msgid "SearchResults|epic"
+msgid_plural "SearchResults|epics"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "SearchResults|issue"
msgid_plural "SearchResults|issues"
msgstr[0] ""
@@ -21842,10 +22643,10 @@ msgstr ""
msgid "Seat Link is disabled, and cannot be configured through this form."
msgstr ""
-msgid "Seats currently in use"
+msgid "Seats usage data as of %{last_enqueue_time}"
msgstr ""
-msgid "Seats in license"
+msgid "Seats usage data is updated every day at 12:00pm UTC"
msgstr ""
msgid "Secondary"
@@ -21899,6 +22700,9 @@ msgstr ""
msgid "SecurityConfiguration|Available for on-demand DAST"
msgstr ""
+msgid "SecurityConfiguration|By default, all analyzers are applied in order to cover all languages across your project, and only run if the language is detected in the Merge Request."
+msgstr ""
+
msgid "SecurityConfiguration|Configure"
msgstr ""
@@ -21929,16 +22733,19 @@ msgstr ""
msgid "SecurityConfiguration|Manage"
msgstr ""
+msgid "SecurityConfiguration|More information"
+msgstr ""
+
msgid "SecurityConfiguration|Not enabled"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|Security Control"
+msgid "SecurityConfiguration|SAST Configuration"
msgstr ""
-msgid "SecurityConfiguration|See documentation"
+msgid "SecurityConfiguration|Security Control"
msgstr ""
msgid "SecurityConfiguration|Status"
@@ -21950,6 +22757,9 @@ msgstr ""
msgid "SecurityConfiguration|Using custom settings. You won't receive automatic updates on this variable. %{anchorStart}Restore to default%{anchorEnd}"
msgstr ""
+msgid "SecurityConfiguration|View history"
+msgstr ""
+
msgid "SecurityConfiguration|You can quickly enable all security scanning tools by enabling %{linkStart}Auto DevOps%{linkEnd}."
msgstr ""
@@ -22028,9 +22838,6 @@ msgstr ""
msgid "SecurityReports|Learn more about setting up your dashboard"
msgstr ""
-msgid "SecurityReports|Load more vulnerabilities"
-msgstr ""
-
msgid "SecurityReports|Monitor vulnerabilities in your code"
msgstr ""
@@ -22310,7 +23117,7 @@ msgstr ""
msgid "Select status"
msgstr ""
-msgid "Select strategy activation method"
+msgid "Select strategy activation method."
msgstr ""
msgid "Select subscription"
@@ -22325,7 +23132,7 @@ msgstr ""
msgid "Select the custom project template source group."
msgstr ""
-msgid "Select timeframe"
+msgid "Select the environment scope for this feature flag."
msgstr ""
msgid "Select timezone"
@@ -22574,6 +23381,9 @@ msgstr ""
msgid "Set iteration"
msgstr ""
+msgid "Set limit to 0 to allow any file size."
+msgstr ""
+
msgid "Set max session time for web terminal."
msgstr ""
@@ -22652,10 +23462,13 @@ msgstr ""
msgid "Set up a %{type} Runner manually"
msgstr ""
+msgid "Set up a hardware device as a second factor to sign in."
+msgstr ""
+
msgid "Set up assertions/attributes/claims (email, first_name, last_name) and NameID according to %{docsLinkStart}the documentation %{icon}%{docsLinkEnd}"
msgstr ""
-msgid "Set up new U2F device"
+msgid "Set up new device"
msgstr ""
msgid "Set up new password"
@@ -22724,6 +23537,9 @@ msgstr ""
msgid "Sets weight to %{weight}."
msgstr ""
+msgid "Setting this to 0 means using the system default timeout value."
+msgstr ""
+
msgid "Settings"
msgstr ""
@@ -22739,6 +23555,15 @@ msgstr ""
msgid "Severity"
msgstr ""
+msgid "SeverityWidget|Severity"
+msgstr ""
+
+msgid "SeverityWidget|Severity: %{severity}"
+msgstr ""
+
+msgid "SeverityWidget|There was an error while updating severity."
+msgstr ""
+
msgid "Shards (%{shards})"
msgstr ""
@@ -22784,6 +23609,9 @@ msgstr ""
msgid "Show all requirements."
msgstr ""
+msgid "Show all test cases."
+msgstr ""
+
msgid "Show archived projects"
msgstr ""
@@ -22796,6 +23624,9 @@ msgstr ""
msgid "Show comments"
msgstr ""
+msgid "Show comments on this file"
+msgstr ""
+
msgid "Show comments only"
msgstr ""
@@ -22841,6 +23672,12 @@ msgstr ""
msgid "Show parent subgroups"
msgstr ""
+msgid "Show the Closed list"
+msgstr ""
+
+msgid "Show the Open list"
+msgstr ""
+
msgid "Show whitespace changes"
msgstr ""
@@ -22884,9 +23721,6 @@ msgstr ""
msgid "Sidebar|Assign health status"
msgstr ""
-msgid "Sidebar|Change weight"
-msgstr ""
-
msgid "Sidebar|Health status"
msgstr ""
@@ -23070,6 +23904,9 @@ msgstr ""
msgid "Snippets|Add another file %{num}/%{total}"
msgstr ""
+msgid "Snippets|Authored %{time_ago} by %{author}"
+msgstr ""
+
msgid "Snippets|Delete file"
msgstr ""
@@ -23097,6 +23934,9 @@ msgstr ""
msgid "Solution"
msgstr ""
+msgid "Some changes are not shown"
+msgstr ""
+
msgid "Some child epics may be hidden due to applied filters"
msgstr ""
@@ -23463,6 +24303,12 @@ msgstr ""
msgid "Source (branch or tag)"
msgstr ""
+msgid "Source Branch"
+msgstr ""
+
+msgid "Source branch: %{source_branch_open}%{source_branch}%{source_branch_close}"
+msgstr ""
+
msgid "Source code"
msgstr ""
@@ -23628,9 +24474,6 @@ msgstr ""
msgid "Start and due date"
msgstr ""
-msgid "Start by choosing a group to see how your team is spending time. You can then drill down to the project level."
-msgstr ""
-
msgid "Start by choosing a group to start exploring the merge requests in that group. You can then proceed to filter by projects, labels, milestones and authors."
msgstr ""
@@ -23712,18 +24555,27 @@ msgstr ""
msgid "StaticSiteEditor|3. Assign a person to review and accept the merge request."
msgstr ""
+msgid "StaticSiteEditor|A link to view the merge request will appear once ready."
+msgstr ""
+
msgid "StaticSiteEditor|An error occurred while submitting your changes."
msgstr ""
msgid "StaticSiteEditor|Branch could not be created."
msgstr ""
+msgid "StaticSiteEditor|Copy update"
+msgstr ""
+
msgid "StaticSiteEditor|Could not commit the content changes."
msgstr ""
msgid "StaticSiteEditor|Could not create merge request."
msgstr ""
+msgid "StaticSiteEditor|Creating your merge request"
+msgstr ""
+
msgid "StaticSiteEditor|Incompatible file content"
msgstr ""
@@ -23745,6 +24597,9 @@ msgstr ""
msgid "StaticSiteEditor|View documentation"
msgstr ""
+msgid "StaticSiteEditor|You can set an assignee to get your changes reviewed and deployed once your merge request is created."
+msgstr ""
+
msgid "StaticSiteEditor|Your merge request has been created"
msgstr ""
@@ -23874,15 +24729,15 @@ msgstr ""
msgid "Submit %{humanized_resource_name}"
msgstr ""
-msgid "Submit Changes"
-msgstr ""
-
msgid "Submit a review"
msgstr ""
msgid "Submit as spam"
msgstr ""
+msgid "Submit changes"
+msgstr ""
+
msgid "Submit feedback"
msgstr ""
@@ -24036,6 +24891,9 @@ msgstr ""
msgid "Successfully deleted U2F device."
msgstr ""
+msgid "Successfully deleted WebAuthn device."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -24354,9 +25212,6 @@ msgstr ""
msgid "Template to append to all Service Desk issues"
msgstr ""
-msgid "Template was successfully saved."
-msgstr ""
-
msgid "Templates"
msgstr ""
@@ -24435,10 +25290,28 @@ msgid_plural "Test coverage: %d hits"
msgstr[0] ""
msgstr[1] ""
-msgid "Test failed."
+msgid "Test settings"
msgstr ""
-msgid "Test settings and save changes"
+msgid "TestCases|New Test Case"
+msgstr ""
+
+msgid "TestCases|New test case"
+msgstr ""
+
+msgid "TestCases|Search test cases"
+msgstr ""
+
+msgid "TestCases|Something went wrong while creating a test case."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching count of test cases."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching test cases list."
+msgstr ""
+
+msgid "TestCases|Submit test case"
msgstr ""
msgid "TestHooks|Ensure one of your projects has merge requests."
@@ -24504,6 +25377,9 @@ msgstr ""
msgid "Thank you for signing up for your free trial! You will get additional instructions in your inbox shortly."
msgstr ""
+msgid "Thank you for your business."
+msgstr ""
+
msgid "Thank you for your feedback!"
msgstr ""
@@ -24563,9 +25439,6 @@ msgstr ""
msgid "The URL to use for connecting to Elasticsearch. Use a comma-separated list to support clustering (e.g., \"http://localhost:9200, http://localhost:9201\")."
msgstr ""
-msgid "The Web IDE offers advanced syntax highlighting capabilities and more."
-msgstr ""
-
msgid "The X509 Certificate to use when mutual TLS is required to communicate with the external authorization service. If left blank, the server certificate is still validated when accessing over HTTPS."
msgstr ""
@@ -24676,6 +25549,9 @@ msgstr ""
msgid "The form contains the following error:"
msgstr ""
+msgid "The form contains the following warning:"
+msgstr ""
+
msgid "The global settings require you to enable Two-Factor Authentication for your account."
msgstr ""
@@ -24790,9 +25666,6 @@ msgstr ""
msgid "The private key to use when a client certificate is provided. This value is encrypted at rest."
msgstr ""
-msgid "The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The project can be accessed by any logged in user."
msgstr ""
@@ -24829,7 +25702,7 @@ msgstr ""
msgid "The remote repository is being updated..."
msgstr ""
-msgid "The repository can be commited to, and issues, comments and other entities can be created."
+msgid "The repository can be committed to, and issues, comments and other entities can be created."
msgstr ""
msgid "The repository for this project does not exist."
@@ -24883,9 +25756,6 @@ msgstr ""
msgid "The time taken by each data entry gathered by that stage."
msgstr ""
-msgid "The total stage shows the time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The update action will time out after %{number_of_minutes} minutes. For big repositories, use a clone/push combination."
msgstr ""
@@ -24949,6 +25819,9 @@ msgstr ""
msgid "There are no archived requirements"
msgstr ""
+msgid "There are no archived test cases"
+msgstr ""
+
msgid "There are no changes"
msgstr ""
@@ -24988,6 +25861,9 @@ msgstr ""
msgid "There are no open requirements"
msgstr ""
+msgid "There are no open test cases"
+msgstr ""
+
msgid "There are no packages yet"
msgstr ""
@@ -25000,6 +25876,9 @@ msgstr ""
msgid "There is a limit of %{ci_project_subscriptions_limit} subscriptions from or to a project."
msgstr ""
+msgid "There is already a To-Do for this design."
+msgstr ""
+
msgid "There is already a repository with that name on disk"
msgstr ""
@@ -25018,6 +25897,9 @@ msgstr ""
msgid "There was a problem communicating with your device."
msgstr ""
+msgid "There was a problem fetching branches."
+msgstr ""
+
msgid "There was a problem fetching groups."
msgstr ""
@@ -25246,9 +26128,15 @@ msgstr ""
msgid "This action can lead to data loss. To prevent accidental actions we ask you to confirm your intention."
msgstr ""
+msgid "This action cannot be undone, and will permanently delete the %{key} SSH key"
+msgstr ""
+
msgid "This action cannot be undone. You will lose the project's repository and all content: issues, merge requests, etc."
msgstr ""
+msgid "This action has been performed too many times. Try again later."
+msgstr ""
+
msgid "This action will %{strongOpen}permanently delete%{strongClose} %{codeOpen}%{project}%{codeClose} %{strongOpen}immediately%{strongClose}, including its repositories and all content: issues, merge requests, etc."
msgstr ""
@@ -25276,9 +26164,6 @@ msgstr ""
msgid "This board's scope is reduced"
msgstr ""
-msgid "This branch has changed since you started editing. Would you like to create a new branch?"
-msgstr ""
-
msgid "This chart could not be displayed"
msgstr ""
@@ -25405,15 +26290,9 @@ msgstr ""
msgid "This is a security log of important events involving your account."
msgstr ""
-msgid "This is the author's first Merge Request to this project."
-msgstr ""
-
msgid "This is the highest peak of users on your installation since the license started."
msgstr ""
-msgid "This is the maximum number of users that have existed at the same time since the license started. This is the minimum number of seats you will need to buy when you renew your license."
-msgstr ""
-
msgid "This is the number of currently active users on your installation, and this is the minimum number you need to purchase when you renew your license."
msgstr ""
@@ -25645,6 +26524,15 @@ msgstr ""
msgid "This user has no identities"
msgstr ""
+msgid "This user has previously committed to the %{name} project."
+msgstr ""
+
+msgid "This user has the %{access} role in the %{name} project."
+msgstr ""
+
+msgid "This user is the author of this %{noteable}."
+msgstr ""
+
msgid "This user will be the author of all events in the activity feed that are the result of an update, like new branches being created or new commits being pushed to existing branches."
msgstr ""
@@ -25675,6 +26563,9 @@ msgstr ""
msgid "Threat Monitoring"
msgstr ""
+msgid "ThreatMonitoring|All Environments"
+msgstr ""
+
msgid "ThreatMonitoring|Anomalous Requests"
msgstr ""
@@ -25702,9 +26593,6 @@ msgstr ""
msgid "ThreatMonitoring|Operations Per Second"
msgstr ""
-msgid "ThreatMonitoring|Overview"
-msgstr ""
-
msgid "ThreatMonitoring|Packet Activity"
msgstr ""
@@ -25723,6 +26611,9 @@ msgstr ""
msgid "ThreatMonitoring|Something went wrong, unable to fetch statistics"
msgstr ""
+msgid "ThreatMonitoring|Statistics"
+msgstr ""
+
msgid "ThreatMonitoring|The firewall is not installed or has been disabled. To view this data, ensure the web application firewall is installed and enabled for your cluster."
msgstr ""
@@ -26114,6 +27005,9 @@ msgstr ""
msgid "To update Snippets with multiple files, you must use the `files` parameter"
msgstr ""
+msgid "To use Gitpod you must first enable the feature in the integrations section of your %{user_prefs}."
+msgstr ""
+
msgid "To view all %{scannedResourcesCount} scanned URLs, please download the CSV file"
msgstr ""
@@ -26147,9 +27041,6 @@ msgstr ""
msgid "Toggle Sidebar"
msgstr ""
-msgid "Toggle all threads"
-msgstr ""
-
msgid "Toggle backtrace"
msgstr ""
@@ -26174,9 +27065,6 @@ msgstr ""
msgid "Toggle navigation"
msgstr ""
-msgid "Toggle project"
-msgstr ""
-
msgid "Toggle sidebar"
msgstr ""
@@ -26216,6 +27104,9 @@ msgstr ""
msgid "Too many projects enabled. You will need to manage them via the console or the API."
msgstr ""
+msgid "Too much data"
+msgstr ""
+
msgid "Topics (optional)"
msgstr ""
@@ -26234,6 +27125,9 @@ msgstr ""
msgid "Total cores (CPUs)"
msgstr ""
+msgid "Total days to completion"
+msgstr ""
+
msgid "Total issues"
msgstr ""
@@ -26330,6 +27224,9 @@ msgstr ""
msgid "Trending"
msgstr ""
+msgid "Trials|Create a new group to start your GitLab Gold trial."
+msgstr ""
+
msgid "Trials|Go back to GitLab"
msgstr ""
@@ -26339,6 +27236,15 @@ msgstr ""
msgid "Trials|You can always resume this process by selecting your avatar and choosing 'Start a Gold trial'"
msgstr ""
+msgid "Trials|You can apply your trial to a new group or an existing group."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group or your personal account."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group, an existing group, or your personal account."
+msgstr ""
+
msgid "Trials|You won't get a free trial right now but you can always resume this process by clicking on your avatar and choosing 'Start a free trial'"
msgstr ""
@@ -26408,6 +27314,9 @@ msgstr ""
msgid "Try using a different search term to find the file you are looking for."
msgstr ""
+msgid "Trying to communicate with your device. Plug it in (if needed) and press the button on the device now."
+msgstr ""
+
msgid "Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now."
msgstr ""
@@ -26495,6 +27404,12 @@ msgstr ""
msgid "URL or request ID"
msgstr ""
+msgid "USER %{user} WILL BE REMOVED! Are you sure?"
+msgstr ""
+
+msgid "USER WILL BE BLOCKED! Are you sure?"
+msgstr ""
+
msgid "UTC"
msgstr ""
@@ -26552,9 +27467,6 @@ msgstr ""
msgid "Unable to load the merge request widget. Try reloading the page."
msgstr ""
-msgid "Unable to resolve"
-msgstr ""
-
msgid "Unable to save iteration. Please try again"
msgstr ""
@@ -26603,6 +27515,9 @@ msgstr ""
msgid "Undo ignore"
msgstr ""
+msgid "Unexpected error"
+msgstr ""
+
msgid "Unfortunately, your email message to GitLab could not be processed."
msgstr ""
@@ -26636,6 +27551,9 @@ msgstr ""
msgid "Unknown response text"
msgstr ""
+msgid "Unless otherwise agreed to in writing with GitLab, by clicking \"Upload License\" you agree that your use of GitLab Software is subject to the %{eula_link_start}Terms of Service%{eula_link_end}."
+msgstr ""
+
msgid "Unlimited"
msgstr ""
@@ -27002,9 +27920,6 @@ msgstr ""
msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
msgstr ""
-msgid "Use a hardware device to add the second factor of authentication."
-msgstr ""
-
msgid "Use an one time password authenticator on your mobile device or computer to enable two-factor authentication (2FA)."
msgstr ""
@@ -27278,13 +28193,13 @@ msgstr ""
msgid "Users"
msgstr ""
-msgid "Users in License:"
+msgid "Users in License"
msgstr ""
-msgid "Users or groups set as approvers in the project's or merge request's settings."
+msgid "Users in License:"
msgstr ""
-msgid "Users outside of license"
+msgid "Users or groups set as approvers in the project's or merge request's settings."
msgstr ""
msgid "Users over License:"
@@ -27302,9 +28217,6 @@ msgstr ""
msgid "Users with a Guest role or those who don't belong to a Project or Group will not use a seat from your license."
msgstr ""
-msgid "Users with a Guest role or those who don't belong to any projects or groups don't count towards seats in use."
-msgstr ""
-
msgid "UsersSelect|%{name} + %{length} more"
msgstr ""
@@ -27344,9 +28256,6 @@ msgstr ""
msgid "Validations failed."
msgstr ""
-msgid "Validity"
-msgstr ""
-
msgid "Value"
msgstr ""
@@ -27365,6 +28274,9 @@ msgstr ""
msgid "Value Stream Name"
msgstr ""
+msgid "ValueStreamAnalyticsStage|We don't have enough data to show this stage."
+msgstr ""
+
msgid "ValueStreamAnalytics|%{days}d"
msgstr ""
@@ -27621,6 +28533,9 @@ msgstr ""
msgid "VisualReviewApp|Steps 1 and 2 (and sometimes 3) are performed once by the developer before requesting feedback. Steps 3 (if necessary), 4 is performed by the reviewer each time they perform a review."
msgstr ""
+msgid "Visualization"
+msgstr ""
+
msgid "Vulnerabilities"
msgstr ""
@@ -27648,34 +28563,31 @@ msgstr ""
msgid "VulnerabilityChart|Severity"
msgstr ""
-msgid "VulnerabilityManagement|A true-positive and will fix"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Change status"
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|Confirm"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Confirmed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
-msgstr ""
-
-msgid "VulnerabilityManagement|Detected %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|A true-positive and will fix"
msgstr ""
-msgid "VulnerabilityManagement|Dismiss"
+msgid "VulnerabilityManagement|Change status"
msgstr ""
-msgid "VulnerabilityManagement|Dismissed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
msgstr ""
-msgid "VulnerabilityManagement|Resolved"
+msgid "VulnerabilityManagement|Detected"
msgstr ""
-msgid "VulnerabilityManagement|Resolved %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Needs triage"
msgstr ""
msgid "VulnerabilityManagement|Something went wrong while trying to delete the comment. Please try again later."
@@ -27726,6 +28638,9 @@ msgstr ""
msgid "Vulnerability|%{scannerName} (version %{scannerVersion})"
msgstr ""
+msgid "Vulnerability|Activity"
+msgstr ""
+
msgid "Vulnerability|Class"
msgstr ""
@@ -27738,6 +28653,9 @@ msgstr ""
msgid "Vulnerability|Description"
msgstr ""
+msgid "Vulnerability|Detected"
+msgstr ""
+
msgid "Vulnerability|Evidence"
msgstr ""
@@ -27801,6 +28719,9 @@ msgstr ""
msgid "Warning: Displaying this diagram might cause performance issues on this page."
msgstr ""
+msgid "We are currently unable to fetch data for the pipeline header."
+msgstr ""
+
msgid "We are currently unable to fetch data for this graph."
msgstr ""
@@ -27840,6 +28761,12 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
+msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
+msgstr ""
+
+msgid "We would like to inform you that your subscription GitLab Enterprise Edition %{plan_name} is nearing its user limit. You have %{active_user_count} active users, which is almost at the user limit of %{maximum_user_count}."
+msgstr ""
+
msgid "We've found no vulnerabilities"
msgstr ""
@@ -27855,6 +28782,12 @@ msgstr ""
msgid "Web terminal"
msgstr ""
+msgid "WebAuthn Devices (%{length})"
+msgstr ""
+
+msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
+msgstr ""
+
msgid "WebIDE|Merge request"
msgstr ""
@@ -27993,15 +28926,9 @@ msgstr ""
msgid "Welcome to the guided GitLab tour"
msgstr ""
-msgid "Welcome to your Issue Board!"
-msgstr ""
-
msgid "Welcome to your issue board!"
msgstr ""
-msgid "We’ve been making changes to %{featureName} and we’d love your feedback %{linkStart}in this issue%{linkEnd} to help us improve the experience."
-msgstr ""
-
msgid "What are you searching for?"
msgstr ""
@@ -28020,6 +28947,9 @@ msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
msgstr ""
+msgid "When enabled, any user visiting %{host} and creating an account will have to be explicitly approved by the admin before they can login. This setting is effective only if sign-ups are enabled."
+msgstr ""
+
msgid "When enabled, any user visiting %{host} will be able to create an account."
msgstr ""
@@ -28244,6 +29174,9 @@ msgstr ""
msgid "With requirements, you can set criteria to check your products against."
msgstr ""
+msgid "With test cases, you can define conditions for your project to meet in determining quality"
+msgstr ""
+
msgid "Withdraw Access Request"
msgstr ""
@@ -28259,6 +29192,9 @@ msgstr ""
msgid "Workflow Help"
msgstr ""
+msgid "Would you like to create a new branch?"
+msgstr ""
+
msgid "Write"
msgstr ""
@@ -28280,6 +29216,9 @@ msgstr ""
msgid "Wrong extern UID provided. Make sure Auth0 is configured correctly."
msgstr ""
+msgid "YYYY-MM-DD"
+msgstr ""
+
msgid "Yes"
msgstr ""
@@ -28337,7 +29276,7 @@ msgstr ""
msgid "You are going to remove the fork relationship from %{project_full_name}. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "You are going to transfer %{project_full_name} to another owner. Are you ABSOLUTELY sure?"
+msgid "You are going to transfer %{project_full_name} to another namespace. Are you ABSOLUTELY sure?"
msgstr ""
msgid "You are going to turn off the confidentiality. This means %{strongStart}everyone%{strongEnd} will be able to see and leave a comment on this %{issuableType}."
@@ -28397,9 +29336,6 @@ msgstr ""
msgid "You can always edit this later"
msgstr ""
-msgid "You can apply your Trial to your Personal account or create a New Group."
-msgstr ""
-
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings"
msgstr ""
@@ -28421,12 +29357,18 @@ msgstr ""
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
+msgid "You can find more information about GitLab subscriptions in %{subscriptions_doc_link}."
+msgstr ""
+
msgid "You can generate an access token scoped to this project for each application to use the GitLab API."
msgstr ""
msgid "You can get started by cloning the repository or start adding files to it with one of the following options."
msgstr ""
+msgid "You can group test cases using labels. To learn about the future direction of this feature, visit %{linkStart}Quality Management direction page%{linkEnd}."
+msgstr ""
+
msgid "You can invite a new member to %{project_name} or invite another group."
msgstr ""
@@ -28442,6 +29384,9 @@ msgstr ""
msgid "You can notify the app / group or a project by sending them an email notification"
msgstr ""
+msgid "You can now close this window."
+msgstr ""
+
msgid "You can now export your security dashboard to a CSV report."
msgstr ""
@@ -28490,9 +29435,6 @@ msgstr ""
msgid "You can test your .gitlab-ci.yml in %{linkStart}CI Lint%{linkEnd}."
msgstr ""
-msgid "You can try again using %{begin_link}basic search%{end_link}"
-msgstr ""
-
msgid "You cannot access the raw file. Please wait a minute."
msgstr ""
@@ -28544,6 +29486,9 @@ msgstr ""
msgid "You don't have any U2F devices registered yet."
msgstr ""
+msgid "You don't have any WebAuthn devices registered yet."
+msgstr ""
+
msgid "You don't have any active chat names."
msgstr ""
@@ -28631,6 +29576,9 @@ msgstr ""
msgid "You must accept our Terms of Service and privacy policy in order to register an account"
msgstr ""
+msgid "You must be logged in to search across all of GitLab"
+msgstr ""
+
msgid "You must disassociate %{domain} from all clusters it is attached to before deletion."
msgstr ""
@@ -28670,7 +29618,7 @@ msgstr ""
msgid "You need to be logged in."
msgstr ""
-msgid "You need to register a two-factor authentication app before you can set up a U2F device."
+msgid "You need to register a two-factor authentication app before you can set up a device."
msgstr ""
msgid "You need to set terms to be enforced"
@@ -28688,6 +29636,9 @@ msgstr ""
msgid "You reached %{usage_in_percent} of %{namespace_name}'s storage capacity (%{used_storage} of %{storage_limit})"
msgstr ""
+msgid "You successfully declined the invitation"
+msgstr ""
+
msgid "You tried to fork %{link_to_the_project} but it failed for the following reason:"
msgstr ""
@@ -28853,10 +29804,13 @@ msgstr ""
msgid "Your U2F device did not send a valid JSON response."
msgstr ""
-msgid "Your U2F device needs to be set up. Plug it in (if not already) and click the button on the left."
+msgid "Your U2F device was registered!"
msgstr ""
-msgid "Your U2F device was registered!"
+msgid "Your WebAuthn device did not send a valid JSON response."
+msgstr ""
+
+msgid "Your WebAuthn device was registered!"
msgstr ""
msgid "Your access request to the %{source_type} has been withdrawn."
@@ -28880,6 +29834,9 @@ msgstr ""
msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
msgstr ""
+msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
+msgstr ""
+
msgid "Your changes can be committed to %{branch_name} because a merge request is open."
msgstr ""
@@ -28916,6 +29873,12 @@ msgstr ""
msgid "Your deployment services will be broken, you will need to manually fix the services after renaming."
msgstr ""
+msgid "Your device is not compatible with GitLab. Please try another device"
+msgstr ""
+
+msgid "Your device needs to be set up. Plug it in (if needed) and click the button on the left."
+msgstr ""
+
msgid "Your device was successfully set up! Give it a name and register it with the GitLab server."
msgstr ""
@@ -29029,9 +29992,6 @@ msgstr[1] ""
msgid "access:"
msgstr ""
-msgid "activated"
-msgstr ""
-
msgid "added %{created_at_timeago}"
msgstr ""
@@ -29104,9 +30064,21 @@ msgstr ""
msgid "by %{user}"
msgstr ""
+msgid "cannot be a date in the past"
+msgstr ""
+
msgid "cannot be changed if a personal project has container registry tags."
msgstr ""
+msgid "cannot be changed if shared runners are enabled"
+msgstr ""
+
+msgid "cannot be enabled because parent group does not allow it"
+msgstr ""
+
+msgid "cannot be enabled because parent group has shared Runners disabled"
+msgstr ""
+
msgid "cannot be enabled unless all domains have TLS certificates"
msgstr ""
@@ -29152,7 +30124,7 @@ msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about SAST %{linkEndTag}"
msgstr ""
-msgid "ciReport|%{linkStartTag}Learn more about Secret Scanning %{linkEndTag}"
+msgid "ciReport|%{linkStartTag}Learn more about Secret Detection %{linkEndTag}"
msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about codequality reports %{linkEndTag}"
@@ -29467,9 +30439,6 @@ msgstr ""
msgid "error"
msgstr ""
-msgid "error code:"
-msgstr ""
-
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr ""
@@ -29491,6 +30460,9 @@ msgstr ""
msgid "failed to dismiss associated finding(id=%{finding_id}): %{message}"
msgstr ""
+msgid "failed to revert associated finding(id=%{finding_id}) to detected"
+msgstr ""
+
msgid "file"
msgid_plural "files"
msgstr[0] ""
@@ -30033,6 +31005,9 @@ msgstr ""
msgid "must be a root namespace"
msgstr ""
+msgid "must be a valid IPv4 or IPv6 address"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -30069,6 +31044,9 @@ msgstr ""
msgid "no expiration"
msgstr ""
+msgid "no name set"
+msgstr ""
+
msgid "no one can merge"
msgstr ""
@@ -30247,9 +31225,6 @@ msgstr ""
msgid "security Reports|There was an error creating the merge request"
msgstr ""
-msgid "settings saved, but not activated"
-msgstr ""
-
msgid "severity|Critical"
msgstr ""
@@ -30376,9 +31351,6 @@ msgstr ""
msgid "toggle collapse"
msgstr ""
-msgid "toggle dropdown"
-msgstr ""
-
msgid "triggered"
msgstr ""
@@ -30406,6 +31378,9 @@ msgstr ""
msgid "user avatar"
msgstr ""
+msgid "user preferences"
+msgstr ""
+
msgid "username"
msgstr ""
diff --git a/locale/lt_LT/gitlab.po b/locale/lt_LT/gitlab.po
index d825e9c2d24..8f566274a95 100644
--- a/locale/lt_LT/gitlab.po
+++ b/locale/lt_LT/gitlab.po
@@ -14,7 +14,10 @@ msgstr ""
"X-Crowdin-Language: lt\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 6\n"
-"PO-Revision-Date: 2020-09-04 23:09\n"
+"PO-Revision-Date: 2020-10-02 18:48\n"
+
+msgid " %{project_name}#%{issue_iid} &middot; opened %{issue_created} by %{author}"
+msgstr ""
msgid " %{start} to %{end}"
msgstr ""
@@ -78,6 +81,20 @@ msgstr ""
msgid "\"el\" parameter is required for createInstance()"
msgstr ""
+msgid "%d Approval"
+msgid_plural "%d Approvals"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
+msgid "%d Package"
+msgid_plural "%d Packages"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%d Scanned URL"
msgid_plural "%d Scanned URLs"
msgstr[0] ""
@@ -165,6 +182,13 @@ msgstr[3] ""
msgid "%d commits"
msgstr ""
+msgid "%d completed issue"
+msgid_plural "%d completed issues"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%d contribution"
msgid_plural "%d contributions"
msgstr[0] ""
@@ -179,6 +203,13 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "%d day until tags are automatically removed"
+msgid_plural "%d days until tags are automatically removed"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%d error"
msgid_plural "%d errors"
msgstr[0] ""
@@ -305,6 +336,20 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "%d open issue"
+msgid_plural "%d open issues"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
+msgid "%d pending comment"
+msgid_plural "%d pending comments"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%d personal project will be removed and cannot be restored."
msgid_plural "%d personal projects will be removed and cannot be restored."
msgstr[0] ""
@@ -326,6 +371,13 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "%d project selected"
+msgid_plural "%d projects selected"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%d request with warnings"
msgid_plural "%d requests with warnings"
msgstr[0] ""
@@ -354,6 +406,13 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "%d tag per image name"
+msgid_plural "%d tags per image name"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%d unassigned issue"
msgid_plural "%d unassigned issues"
msgstr[0] ""
@@ -382,6 +441,13 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "%d warning found:"
+msgid_plural "%d warnings found:"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%s additional commit has been omitted to prevent performance issues."
msgid_plural "%s additional commits have been omitted to prevent performance issues."
msgstr[0] ""
@@ -422,6 +488,9 @@ msgstr ""
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr ""
+msgid "%{completedCount} completed weight"
+msgstr ""
+
msgid "%{completedWeight} of %{totalWeight} weight completed"
msgstr ""
@@ -476,16 +545,12 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "%{count} pending comment"
-msgid_plural "%{count} pending comments"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
+msgid "%{count} total weight"
+msgstr ""
+
msgid "%{dashboard_path} could not be found."
msgstr ""
@@ -540,6 +605,9 @@ msgstr ""
msgid "%{group_name} uses group managed accounts. You need to create a new GitLab account which will be managed by %{group_name}."
msgstr ""
+msgid "%{group_name}&%{epic_iid} &middot; opened %{epic_created} by %{author}"
+msgstr ""
+
msgid "%{host} sign-in from new location"
msgstr ""
@@ -552,7 +620,7 @@ msgstr ""
msgid "%{issuableType} will be removed! Are you sure?"
msgstr ""
-msgid "%{issuesSize} issues with a limit of %{maxIssueCount}"
+msgid "%{issuesCount} issues with a limit of %{maxIssueCount}"
msgstr ""
msgid "%{issuesSize} with a limit of %{maxIssueCount}"
@@ -585,7 +653,7 @@ msgstr ""
msgid "%{labelStart}Namespace:%{labelEnd} %{namespace}"
msgstr ""
-msgid "%{labelStart}Report Type:%{labelEnd} %{reportType}"
+msgid "%{labelStart}Scan Type:%{labelEnd} %{reportType}"
msgstr ""
msgid "%{labelStart}Scanner:%{labelEnd} %{scanner}"
@@ -796,9 +864,6 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "%{service_title} %{message}."
-msgstr ""
-
msgid "%{size} GiB"
msgstr ""
@@ -897,6 +962,12 @@ msgstr ""
msgid "%{timebox_name} should belong either to a project or a group."
msgstr ""
+msgid "%{timebox_type} does not support burnup charts"
+msgstr ""
+
+msgid "%{timebox_type} must have a start and due date"
+msgstr ""
+
msgid "%{title} %{operator} %{threshold}"
msgstr ""
@@ -921,7 +992,7 @@ msgstr ""
msgid "%{total} open issue weight"
msgstr ""
-msgid "%{total} open issues"
+msgid "%{total} warnings found: showing first %{warningsDisplayed}"
msgstr ""
msgid "%{usage_ping_link_start}Learn more%{usage_ping_link_end} about what information is shared with GitLab Inc."
@@ -954,9 +1025,6 @@ msgstr ""
msgid "&lt; 1 hour"
msgstr ""
-msgid "&lt;no name set&gt;"
-msgstr ""
-
msgid "&lt;no scopes selected&gt;"
msgstr ""
@@ -987,6 +1055,9 @@ msgstr ""
msgid "'%{name}' Value Stream created"
msgstr ""
+msgid "'%{name}' Value Stream deleted"
+msgstr ""
+
msgid "'%{name}' stage already exists"
msgstr ""
@@ -1048,6 +1119,9 @@ msgstr ""
msgid "+ %{numberOfHiddenAssignees} more"
msgstr ""
+msgid "+ %{numberOfHiddenReviewers} more"
+msgstr ""
+
msgid "+%d more"
msgid_plural "+%d more"
msgstr[0] ""
@@ -1120,6 +1194,13 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "1 Issue"
+msgid_plural "%d Issues"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "1 closed issue"
msgid_plural "%{issues} closed issues"
msgstr[0] ""
@@ -1141,6 +1222,13 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "1 deploy key"
+msgid_plural "%d deploy keys"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1261,6 +1349,9 @@ msgstr ""
msgid ":%{startLine} to %{endLine}"
msgstr ""
+msgid "A %{incident_docs_start}modified issue%{incident_docs_end} to guide the resolution of incidents."
+msgstr ""
+
msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr ""
@@ -1273,6 +1364,9 @@ msgstr ""
msgid "A GitBook site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
+msgid "A Gitpod configured Webapplication in Spring and Java"
+msgstr ""
+
msgid "A Hexo site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
@@ -1444,9 +1538,15 @@ msgstr ""
msgid "Access expiration date"
msgstr ""
+msgid "Access expires"
+msgstr ""
+
msgid "Access forbidden. Check your access level."
msgstr ""
+msgid "Access granted"
+msgstr ""
+
msgid "Access requests"
msgstr ""
@@ -1456,6 +1556,9 @@ msgstr ""
msgid "Access to Pages websites are controlled based on the user's membership to a given project. By checking this box, users will be required to be logged in to have access to all Pages websites in your instance."
msgstr ""
+msgid "AccessDropdown|Deploy Keys"
+msgstr ""
+
msgid "AccessDropdown|Groups"
msgstr ""
@@ -1573,12 +1676,6 @@ msgstr ""
msgid "Active Sessions"
msgstr ""
-msgid "Active Users:"
-msgstr ""
-
-msgid "Active users"
-msgstr ""
-
msgid "Activity"
msgstr ""
@@ -1748,9 +1845,6 @@ msgstr ""
msgid "Add label(s)"
msgstr ""
-msgid "Add license"
-msgstr ""
-
msgid "Add list"
msgstr ""
@@ -1925,21 +2019,51 @@ msgstr ""
msgid "AdminArea|Bots"
msgstr ""
+msgid "AdminArea|Components"
+msgstr ""
+
msgid "AdminArea|Developer"
msgstr ""
+msgid "AdminArea|Features"
+msgstr ""
+
+msgid "AdminArea|Groups: %{number_of_groups}"
+msgstr ""
+
msgid "AdminArea|Guest"
msgstr ""
msgid "AdminArea|Included Free in license"
msgstr ""
+msgid "AdminArea|Latest groups"
+msgstr ""
+
+msgid "AdminArea|Latest projects"
+msgstr ""
+
+msgid "AdminArea|Latest users"
+msgstr ""
+
msgid "AdminArea|Maintainer"
msgstr ""
+msgid "AdminArea|New group"
+msgstr ""
+
+msgid "AdminArea|New project"
+msgstr ""
+
+msgid "AdminArea|New user"
+msgstr ""
+
msgid "AdminArea|Owner"
msgstr ""
+msgid "AdminArea|Projects: %{number_of_projects}"
+msgstr ""
+
msgid "AdminArea|Reporter"
msgstr ""
@@ -1967,6 +2091,9 @@ msgstr ""
msgid "AdminArea|Users without a Group and Project"
msgstr ""
+msgid "AdminArea|Users: %{number_of_users}"
+msgstr ""
+
msgid "AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running."
msgstr ""
@@ -1985,9 +2112,6 @@ msgstr ""
msgid "AdminProjects|Delete Project %{projectName}?"
msgstr ""
-msgid "AdminProjects|Delete project"
-msgstr ""
-
msgid "AdminSettings|Apply integration settings to all Projects"
msgstr ""
@@ -2225,21 +2349,30 @@ msgstr ""
msgid "AdminUsers|Without projects"
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 ""
msgid "AdminUsers|You cannot remove your own admin rights."
msgstr ""
+msgid "AdminUsers|You must transfer ownership or delete the groups owned by this user before you can delete their account"
+msgstr ""
+
msgid "Administration"
msgstr ""
msgid "Advanced"
msgstr ""
+msgid "Advanced Search"
+msgstr ""
+
+msgid "Advanced Search with Elasticsearch"
+msgstr ""
+
msgid "Advanced Settings"
msgstr ""
@@ -2319,6 +2452,9 @@ msgstr ""
msgid "AlertManagement|Edit"
msgstr ""
+msgid "AlertManagement|Environment"
+msgstr ""
+
msgid "AlertManagement|Events"
msgstr ""
@@ -2331,6 +2467,9 @@ msgstr ""
msgid "AlertManagement|Issue"
msgstr ""
+msgid "AlertManagement|Key"
+msgstr ""
+
msgid "AlertManagement|Low"
msgstr ""
@@ -2424,6 +2563,9 @@ msgstr ""
msgid "AlertManagement|Unknown"
msgstr ""
+msgid "AlertManagement|Value"
+msgstr ""
+
msgid "AlertManagement|View alerts in Opsgenie"
msgstr ""
@@ -2583,6 +2725,9 @@ msgstr ""
msgid "All projects"
msgstr ""
+msgid "All projects selected"
+msgstr ""
+
msgid "All security scans are enabled because %{linkStart}Auto DevOps%{linkEnd} is enabled on this project"
msgstr ""
@@ -2670,6 +2815,9 @@ msgstr ""
msgid "Almost there"
msgstr ""
+msgid "Already blocked"
+msgstr ""
+
msgid "Also called \"Issuer\" or \"Relying party trust identifier\""
msgstr ""
@@ -2724,6 +2872,9 @@ msgstr ""
msgid "An error has occurred"
msgstr ""
+msgid "An error occured while making the changes: %{error}"
+msgstr ""
+
msgid "An error occurred adding a draft to the thread."
msgstr ""
@@ -2751,12 +2902,6 @@ msgstr ""
msgid "An error occurred when toggling the notification subscription"
msgstr ""
-msgid "An error occurred when trying to resolve a comment. Please try again."
-msgstr ""
-
-msgid "An error occurred when trying to resolve a discussion. Please try again."
-msgstr ""
-
msgid "An error occurred when updating the issue weight"
msgstr ""
@@ -2772,12 +2917,6 @@ msgstr ""
msgid "An error occurred while checking group path. Please refresh and try again."
msgstr ""
-msgid "An error occurred while committing your changes."
-msgstr ""
-
-msgid "An error occurred while creating the list. Please try again."
-msgstr ""
-
msgid "An error occurred while decoding the file."
msgstr ""
@@ -2850,25 +2989,19 @@ msgstr ""
msgid "An error occurred while fetching the Service Desk address."
msgstr ""
-msgid "An error occurred while fetching the board issues. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the board lists. Please reload the page."
msgstr ""
msgid "An error occurred while fetching the board lists. Please try again."
msgstr ""
-msgid "An error occurred while fetching the board swimlanes. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the builds."
msgstr ""
msgid "An error occurred while fetching the job log."
msgstr ""
-msgid "An error occurred while fetching the job trace."
+msgid "An error occurred while fetching the job logs."
msgstr ""
msgid "An error occurred while fetching the job."
@@ -3015,9 +3148,6 @@ msgstr ""
msgid "An error occurred while saving assignees"
msgstr ""
-msgid "An error occurred while saving the template. Please check if the template exists."
-msgstr ""
-
msgid "An error occurred while searching for milestones"
msgstr ""
@@ -3036,10 +3166,10 @@ msgstr ""
msgid "An error occurred while updating approvers"
msgstr ""
-msgid "An error occurred while updating the comment"
+msgid "An error occurred while updating labels."
msgstr ""
-msgid "An error occurred while updating the list. Please try again."
+msgid "An error occurred while updating the comment"
msgstr ""
msgid "An error occurred while validating group path"
@@ -3093,6 +3223,9 @@ msgstr ""
msgid "An unknown error occurred while loading this graph."
msgstr ""
+msgid "An unknown error occurred."
+msgstr ""
+
msgid "Analytics"
msgstr ""
@@ -3126,10 +3259,10 @@ msgstr ""
msgid "Any"
msgstr ""
-msgid "Any Author"
+msgid "Any %{header}"
msgstr ""
-msgid "Any Status"
+msgid "Any Author"
msgstr ""
msgid "Any branch"
@@ -3183,6 +3316,9 @@ msgstr ""
msgid "Application ID"
msgstr ""
+msgid "Application limits saved successfully"
+msgstr ""
+
msgid "Application settings saved successfully"
msgstr ""
@@ -3400,6 +3536,9 @@ msgstr ""
msgid "Are you sure you want to close this blocked issue?"
msgstr ""
+msgid "Are you sure you want to delete \"%{name}\" Value Stream?"
+msgstr ""
+
msgid "Are you sure you want to delete %{name}?"
msgstr ""
@@ -3409,6 +3548,9 @@ msgstr ""
msgid "Are you sure you want to delete this %{typeOfComment}?"
msgstr ""
+msgid "Are you sure you want to delete this SSH key?"
+msgstr ""
+
msgid "Are you sure you want to delete this board?"
msgstr ""
@@ -3433,6 +3575,13 @@ msgstr ""
msgid "Are you sure you want to erase this build?"
msgstr ""
+msgid "Are you sure you want to import %d repository?"
+msgid_plural "Are you sure you want to import %d repositories?"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "Are you sure you want to lose unsaved changes?"
msgstr ""
@@ -3442,15 +3591,15 @@ msgstr ""
msgid "Are you sure you want to merge immediately?"
msgstr ""
-msgid "Are you sure you want to permanently delete this license?"
-msgstr ""
-
msgid "Are you sure you want to re-deploy this environment?"
msgstr ""
msgid "Are you sure you want to regenerate the public key? You will have to update the public key on the remote server before mirroring will work again."
msgstr ""
+msgid "Are you sure you want to reindex?"
+msgstr ""
+
msgid "Are you sure you want to remove %{group_name}?"
msgstr ""
@@ -3478,6 +3627,9 @@ msgstr ""
msgid "Are you sure you want to revoke this nickname?"
msgstr ""
+msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
+msgstr ""
+
msgid "Are you sure you want to stop this environment?"
msgstr ""
@@ -3499,6 +3651,9 @@ msgstr ""
msgid "Are you sure? The device will be signed out of GitLab and all remember me tokens revoked."
msgstr ""
+msgid "Are you sure? This will invalidate your registered applications and U2F / WebAuthn devices."
+msgstr ""
+
msgid "Are you sure? This will invalidate your registered applications and U2F devices."
msgstr ""
@@ -3517,9 +3672,6 @@ msgstr ""
msgid "Artifacts"
msgstr ""
-msgid "As U2F devices are only supported by a few browsers, we require that you set up a two-factor authentication app before a U2F device. That way you'll always be able to log in - even when you're using an unsupported browser."
-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 ""
@@ -3717,6 +3869,9 @@ msgstr ""
msgid "AuditLogs|Target"
msgstr ""
+msgid "AuditLogs|This month"
+msgstr ""
+
msgid "AuditLogs|User Events"
msgstr ""
@@ -3756,6 +3911,9 @@ msgstr ""
msgid "Authentication via U2F device failed."
msgstr ""
+msgid "Authentication via WebAuthn device failed."
+msgstr ""
+
msgid "Author"
msgstr ""
@@ -4023,15 +4181,6 @@ msgstr ""
msgid "BambooService|You must set up automatic revision labeling and a repository trigger in Bamboo."
msgstr ""
-msgid "BatchComments|Delete all pending comments"
-msgstr ""
-
-msgid "BatchComments|Discard review?"
-msgstr ""
-
-msgid "BatchComments|You're about to discard your review which will delete all of your pending comments. The deleted comments %{strong_start}cannot%{strong_end} be restored."
-msgstr ""
-
msgid "Be careful. Changing the project's namespace can have unintended side effects."
msgstr ""
@@ -4053,6 +4202,9 @@ msgstr ""
msgid "Bi-weekly code coverage"
msgstr ""
+msgid "Billable Users:"
+msgstr ""
+
msgid "Billing"
msgstr ""
@@ -4062,7 +4214,7 @@ msgstr ""
msgid "BillingPlans|@%{user_name} you are currently using the %{plan_name} plan."
msgstr ""
-msgid "BillingPlans|Congratulations, your new trial is activated"
+msgid "BillingPlans|Congratulations, your free trial is activated."
msgstr ""
msgid "BillingPlans|If you would like to downgrade your plan please contact %{support_link_start}Customer Support%{support_link_end}."
@@ -4125,6 +4277,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Block user"
+msgstr ""
+
msgid "Blocked"
msgstr ""
@@ -4140,31 +4295,37 @@ msgstr ""
msgid "Blog"
msgstr ""
-msgid "Board name"
-msgstr ""
-
msgid "Board scope"
msgstr ""
msgid "Board scope affects which issues are displayed for anyone who visits this board"
msgstr ""
-msgid "BoardBlankState|Add default lists"
+msgid "Boards"
msgstr ""
-msgid "BoardBlankState|Add the following default lists to your Issue Board with one click:"
+msgid "Boards and Board Lists"
msgstr ""
-msgid "BoardBlankState|Nevermind, I'll use my own"
+msgid "Boards|An error occurred while creating the issue. Please try again."
msgstr ""
-msgid "BoardBlankState|Starting out with the default set of lists will get you right on the way to making the most of your board."
+msgid "Boards|An error occurred while creating the list. Please try again."
msgstr ""
-msgid "Boards"
+msgid "Boards|An error occurred while fetching issues. Please reload the page."
msgstr ""
-msgid "Boards and Board Lists"
+msgid "Boards|An error occurred while fetching the board issues. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching the board swimlanes. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while moving the issue. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while updating the list. Please try again."
msgstr ""
msgid "Boards|Collapse"
@@ -4191,7 +4352,7 @@ msgstr ""
msgid "Branch %{branch_name} was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr ""
-msgid "Branch has changed"
+msgid "Branch changed"
msgstr ""
msgid "Branch is already taken"
@@ -4497,6 +4658,9 @@ msgstr ""
msgid "CLOSED (MOVED)"
msgstr ""
+msgid "CODEOWNERS rule violation"
+msgstr ""
+
msgid "CONTRIBUTING"
msgstr ""
@@ -4527,9 +4691,6 @@ msgstr ""
msgid "Can't create snippet: %{err}"
msgstr ""
-msgid "Can't edit as source branch was deleted"
-msgstr ""
-
msgid "Can't fetch content for the blob: %{err}"
msgstr ""
@@ -4542,9 +4703,6 @@ msgstr ""
msgid "Can't load mermaid module: %{err}"
msgstr ""
-msgid "Can't remove group members without group managed account"
-msgstr ""
-
msgid "Can't scan the code?"
msgstr ""
@@ -4587,6 +4745,9 @@ msgstr ""
msgid "Cannot create the abuse report. This user has been blocked."
msgstr ""
+msgid "Cannot enable shared runners because parent group does not allow it"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -4692,6 +4853,15 @@ msgstr ""
msgid "Change your password or recover your current one"
msgstr ""
+msgid "ChangeReviewer|Reviewer changed from %{old} to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Reviewer changed to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Unassigned"
+msgstr ""
+
msgid "ChangeTypeActionLabel|Pick into branch"
msgstr ""
@@ -4731,6 +4901,9 @@ msgstr ""
msgid "Changes the title to \"%{title_param}\"."
msgstr ""
+msgid "Changes were successfully made."
+msgstr ""
+
msgid "Changes won't take place until the index is %{link_start}recreated%{link_end}."
msgstr ""
@@ -5136,6 +5309,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove variable"
+msgstr ""
+
msgid "CiVariables|Remove variable row"
msgstr ""
@@ -5214,9 +5390,6 @@ msgstr ""
msgid "Clear due date"
msgstr ""
-msgid "Clear input"
-msgstr ""
-
msgid "Clear recent searches"
msgstr ""
@@ -5265,6 +5438,9 @@ msgstr ""
msgid "Client authentication key password"
msgstr ""
+msgid "Client request timeout"
+msgstr ""
+
msgid "Clients"
msgstr ""
@@ -5349,6 +5525,27 @@ msgstr ""
msgid "Cluster type must be specificed for Stages::ClusterEndpointInserter"
msgstr ""
+msgid "ClusterAgents|Configuration"
+msgstr ""
+
+msgid "ClusterAgents|Connect your cluster with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate Kubernetes with a GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Name"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Agent also requires %{linkStart}enabling the Agent Server%{linkEnd}"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Kubernetes Agent allows an Infrastructure as Code, GitOps approach to integrating Kubernetes clusters with GitLab. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "ClusterAgent|This feature is only available for premium plans"
msgstr ""
@@ -5418,10 +5615,10 @@ msgstr ""
msgid "ClusterIntegration|All installed applications and related resources"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster."
+msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{linkStart}More information%{linkEnd}"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{startLink}More information%{endLink}"
+msgid "ClusterIntegration|Allow GitLab to manage namespaces and service accounts for this cluster."
msgstr ""
msgid "ClusterIntegration|Alternatively, "
@@ -5442,6 +5639,9 @@ msgstr ""
msgid "ClusterIntegration|An error occurred while trying to fetch zone machine types: %{error}"
msgstr ""
+msgid "ClusterIntegration|An unknown error occurred while attempting to connect to Kubernetes."
+msgstr ""
+
msgid "ClusterIntegration|Any project namespaces"
msgstr ""
@@ -5457,6 +5657,9 @@ msgstr ""
msgid "ClusterIntegration|Authenticate with Amazon Web Services"
msgstr ""
+msgid "ClusterIntegration|Authentication Error"
+msgstr ""
+
msgid "ClusterIntegration|Base domain"
msgstr ""
@@ -5475,13 +5678,22 @@ msgstr ""
msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}security group %{externalLinkIcon} %{endLink} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
+msgid "ClusterIntegration|Check your CA certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Check your cluster status"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}subnets %{externalLinkIcon} %{endLink} in your VPC where your worker nodes will run."
+msgid "ClusterIntegration|Check your token"
msgstr ""
-msgid "ClusterIntegration|Choose the worker node %{startLink}instance type %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Choose the %{linkStart}security group %{linkEnd} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
+msgstr ""
+
+msgid "ClusterIntegration|Choose the %{linkStart}subnets %{linkEnd} in your VPC where your worker nodes will run."
+msgstr ""
+
+msgid "ClusterIntegration|Choose the worker node %{linkStart}instance type%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Choose which applications to install on your Kubernetes cluster."
@@ -5493,10 +5705,7 @@ msgstr ""
msgid "ClusterIntegration|Clear cluster cache"
msgstr ""
-msgid "ClusterIntegration|Clear the local cache of namespace and service accounts. This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
-msgstr ""
-
-msgid "ClusterIntegration|Cluster being created"
+msgid "ClusterIntegration|Clear the local cache of namespace and service accounts."
msgstr ""
msgid "ClusterIntegration|Cluster management project (alpha)"
@@ -5508,15 +5717,21 @@ msgstr ""
msgid "ClusterIntegration|Cluster_applications artifact too big. Maximum allowable size: %{human_size}"
msgstr ""
-msgid "ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters."
+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|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}"
+msgid "ClusterIntegration|Clusters connected with a certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Connect cluster with certificate"
msgstr ""
msgid "ClusterIntegration|Connect existing cluster"
msgstr ""
+msgid "ClusterIntegration|Connection Error"
+msgstr ""
+
msgid "ClusterIntegration|Copy API URL"
msgstr ""
@@ -5592,6 +5807,12 @@ msgstr ""
msgid "ClusterIntegration|Deletes all GitLab resources attached to this cluster during removal"
msgstr ""
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared."
+msgstr ""
+
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared. %{linkStart}More information%{linkEnd}"
+msgstr ""
+
msgid "ClusterIntegration|Did you know?"
msgstr ""
@@ -5661,6 +5882,9 @@ msgstr ""
msgid "ClusterIntegration|Fluentd is an open source data collector, which lets you unify the data collection and consumption for a better use and understanding of data. It requires at least one of the following logs to be successfully installed."
msgstr ""
+msgid "ClusterIntegration|GitLab Agent managed clusters"
+msgstr ""
+
msgid "ClusterIntegration|GitLab Container Network Policies"
msgstr ""
@@ -5673,6 +5897,12 @@ msgstr ""
msgid "ClusterIntegration|GitLab Runner connects to the repository and executes CI/CD jobs, pushing results back and deploying applications to production."
msgstr ""
+msgid "ClusterIntegration|GitLab failed to authenticate."
+msgstr ""
+
+msgid "ClusterIntegration|GitLab failed to connect to the cluster."
+msgstr ""
+
msgid "ClusterIntegration|GitLab-managed cluster"
msgstr ""
@@ -5694,6 +5924,9 @@ msgstr ""
msgid "ClusterIntegration|Group cluster"
msgstr ""
+msgid "ClusterIntegration|HTTP Error"
+msgstr ""
+
msgid "ClusterIntegration|Helm Tiller"
msgstr ""
@@ -5727,7 +5960,10 @@ msgstr ""
msgid "ClusterIntegration|Instance type"
msgstr ""
-msgid "ClusterIntegration|Integrate Kubernetes cluster automation"
+msgid "ClusterIntegration|Integrate Kubernetes with a cluster certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Integrate with a cluster certificate"
msgstr ""
msgid "ClusterIntegration|Issuer Email"
@@ -5763,9 +5999,6 @@ msgstr ""
msgid "ClusterIntegration|Knative extends Kubernetes to provide a set of middleware components that are essential to build modern, source-centric, and container-based applications that can run anywhere: on premises, in the cloud, or even in a third-party data center."
msgstr ""
-msgid "ClusterIntegration|Kubernetes cluster"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes cluster is being created..."
msgstr ""
@@ -5778,9 +6011,6 @@ msgstr ""
msgid "ClusterIntegration|Kubernetes clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr ""
-msgid "ClusterIntegration|Kubernetes clusters can be used to deploy applications and to provide Review Apps for this project"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes version"
msgstr ""
@@ -5793,7 +6023,7 @@ msgstr ""
msgid "ClusterIntegration|Learn more about %{help_link_start}zones%{help_link_end}."
msgstr ""
-msgid "ClusterIntegration|Learn more about %{startLink}Regions %{externalLinkIcon}%{endLink}."
+msgid "ClusterIntegration|Learn more about %{linkStart}Regions%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Learn more about Kubernetes"
@@ -5838,12 +6068,18 @@ msgstr ""
msgid "ClusterIntegration|Machine type"
msgstr ""
+msgid "ClusterIntegration|Make sure your API endpoint is correct"
+msgstr ""
+
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create Kubernetes clusters"
msgstr ""
msgid "ClusterIntegration|Manage your Kubernetes cluster by visiting %{provider_link}"
msgstr ""
+msgid "ClusterIntegration|Namespace per environment"
+msgstr ""
+
msgid "ClusterIntegration|No IAM Roles found"
msgstr ""
@@ -5889,6 +6125,9 @@ msgstr ""
msgid "ClusterIntegration|No zones matched your search"
msgstr ""
+msgid "ClusterIntegration|Node calculations use the Kubernetes Metrics API. Make sure your cluster has metrics installed"
+msgstr ""
+
msgid "ClusterIntegration|Number of nodes"
msgstr ""
@@ -5931,6 +6170,9 @@ msgstr ""
msgid "ClusterIntegration|RBAC-enabled cluster"
msgstr ""
+msgid "ClusterIntegration|Read our %{linkStart}help page%{linkEnd} on Kubernetes cluster integration."
+msgstr ""
+
msgid "ClusterIntegration|Read our %{link_start}help page%{link_end} on Kubernetes cluster integration."
msgstr ""
@@ -6033,7 +6275,7 @@ msgstr ""
msgid "ClusterIntegration|Select a VPC to choose a subnet"
msgstr ""
-msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{linkStart}Amazon Web Services %{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select a network to choose a subnetwork"
@@ -6066,7 +6308,7 @@ msgstr ""
msgid "ClusterIntegration|Select project to choose zone"
msgstr ""
-msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select zone"
@@ -6156,9 +6398,18 @@ msgstr ""
msgid "ClusterIntegration|There was a problem authenticating with your cluster. Please ensure your CA Certificate and Token are valid."
msgstr ""
+msgid "ClusterIntegration|There was an HTTP error when connecting to your cluster."
+msgstr ""
+
msgid "ClusterIntegration|This account must have permissions to create a Kubernetes cluster in the %{link_to_container_project} specified below"
msgstr ""
+msgid "ClusterIntegration|This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
+msgstr ""
+
+msgid "ClusterIntegration|This is necessary to clear existing environment-namespace associations from clusters previously managed by GitLab."
+msgstr ""
+
msgid "ClusterIntegration|This option will allow you to install applications on RBAC clusters."
msgstr ""
@@ -6183,9 +6434,21 @@ msgstr ""
msgid "ClusterIntegration|To use a new project, first create one on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}."
msgstr ""
+msgid "ClusterIntegration|Troubleshooting tips:"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Authenticate"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Connect"
+msgstr ""
+
msgid "ClusterIntegration|Uninstall %{appTitle}"
msgstr ""
+msgid "ClusterIntegration|Unknown Error"
+msgstr ""
+
msgid "ClusterIntegration|Update %{appTitle}"
msgstr ""
@@ -6246,7 +6509,7 @@ msgstr ""
msgid "ClusterIntegration|Your cluster API is unreachable. Please ensure your API URL is correct."
msgstr ""
-msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Zone"
@@ -6366,6 +6629,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse all threads"
+msgstr ""
+
msgid "Collapse approvers"
msgstr ""
@@ -6517,7 +6783,7 @@ msgstr ""
msgid "Commit…"
msgstr ""
-msgid "Company"
+msgid "Community forum"
msgstr ""
msgid "Company name"
@@ -6526,6 +6792,9 @@ msgstr ""
msgid "Compare"
msgstr ""
+msgid "Compare %{oldCommitId}...%{newCommitId}"
+msgstr ""
+
msgid "Compare Git revisions"
msgstr ""
@@ -6541,6 +6810,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare submodule commit revisions"
+msgstr ""
+
msgid "Compare with previous version"
msgstr ""
@@ -6676,6 +6948,9 @@ msgstr ""
msgid "Configure the way a user creates a new account."
msgstr ""
+msgid "Configure which lists are shown for anyone who visits this board"
+msgstr ""
+
msgid "Confirm"
msgstr ""
@@ -6907,6 +7182,9 @@ msgstr[3] ""
msgid "ContainerRegistry|Set cleanup policy"
msgstr ""
+msgid "ContainerRegistry|Some tags were not deleted"
+msgstr ""
+
msgid "ContainerRegistry|Something went wrong while fetching the cleanup policy."
msgstr ""
@@ -6946,6 +7224,9 @@ msgstr ""
msgid "ContainerRegistry|Tags with names matching this regex pattern will %{italicStart}expire:%{italicEnd}"
msgstr ""
+msgid "ContainerRegistry|The cleanup policy timed out before it could delete all tags. An administrator can %{adminLinkStart}manually run cleanup now%{adminLinkEnd} or you can wait for the cleanup policy to automatically run again. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "ContainerRegistry|The last tag related to this image was recently removed. This empty image and any associated data will be automatically removed as part of the regular Garbage Collection process. If you have any questions, contact your administrator."
msgstr ""
@@ -7078,6 +7359,9 @@ msgstr ""
msgid "Contributions per group member"
msgstr ""
+msgid "Contributor"
+msgstr ""
+
msgid "Contributors"
msgstr ""
@@ -7207,6 +7491,9 @@ msgstr ""
msgid "Could not change HEAD: branch '%{branch}' does not exist"
msgstr ""
+msgid "Could not commit. An unexpected error occurred."
+msgstr ""
+
msgid "Could not connect to FogBugz, check your URL"
msgstr ""
@@ -7246,6 +7533,9 @@ msgstr ""
msgid "Could not find iteration"
msgstr ""
+msgid "Could not load instance counts. Please refresh the page to try again."
+msgstr ""
+
msgid "Could not remove the trigger."
msgstr ""
@@ -7270,10 +7560,10 @@ msgstr ""
msgid "Could not save prometheus manual configuration"
msgstr ""
-msgid "Could not udpdate wiki page"
+msgid "Could not update the LDAP settings"
msgstr ""
-msgid "Could not update the LDAP settings"
+msgid "Could not update wiki page"
msgstr ""
msgid "Could not upload your designs as one or more files uploaded are not supported."
@@ -7935,6 +8225,9 @@ msgstr ""
msgid "DastProfiles|Are you sure you want to delete this profile?"
msgstr ""
+msgid "DastProfiles|Could not create site validation token. Please refresh the page, or try again later."
+msgstr ""
+
msgid "DastProfiles|Could not create the scanner profile. Please try again."
msgstr ""
@@ -7959,6 +8252,12 @@ msgstr ""
msgid "DastProfiles|Could not fetch site profiles. Please refresh the page, or try again later."
msgstr ""
+msgid "DastProfiles|Could not retrieve site validation status. Please refresh the page, or try again later."
+msgstr ""
+
+msgid "DastProfiles|Could not update the scanner profile. Please try again."
+msgstr ""
+
msgid "DastProfiles|Could not update the site profile. Please try again."
msgstr ""
@@ -7974,7 +8273,7 @@ msgstr ""
msgid "DastProfiles|Download validation text file"
msgstr ""
-msgid "DastProfiles|Edit feature will come soon. Please create a new profile if changes needed"
+msgid "DastProfiles|Edit scanner profile"
msgstr ""
msgid "DastProfiles|Edit site profile"
@@ -8007,6 +8306,9 @@ msgstr ""
msgid "DastProfiles|No profiles created yet"
msgstr ""
+msgid "DastProfiles|Passive"
+msgstr ""
+
msgid "DastProfiles|Please enter a valid URL format, ex: http://www.example.com/home"
msgstr ""
@@ -8022,6 +8324,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan mode"
+msgstr ""
+
msgid "DastProfiles|Scanner Profile"
msgstr ""
@@ -8061,10 +8366,10 @@ msgstr ""
msgid "DastProfiles|Text file validation"
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
+msgid "DastProfiles|The maximum number of minutes allowed for the spider to traverse the site."
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the spider to traverse the site."
+msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
msgstr ""
msgid "DastProfiles|Validate"
@@ -8097,6 +8402,9 @@ msgstr ""
msgid "Date picker"
msgstr ""
+msgid "Date range"
+msgstr ""
+
msgid "Date range cannot exceed %{maxDateRange} days."
msgstr ""
@@ -8121,6 +8429,9 @@ msgstr ""
msgid "Days to merge"
msgstr ""
+msgid "Dear Administrator,"
+msgstr ""
+
msgid "Debug"
msgstr ""
@@ -8232,12 +8543,18 @@ msgstr ""
msgid "Delete"
msgstr ""
+msgid "Delete %{name}"
+msgstr ""
+
msgid "Delete Comment"
msgstr ""
msgid "Delete Snippet"
msgstr ""
+msgid "Delete Value Stream"
+msgstr ""
+
msgid "Delete account"
msgstr ""
@@ -8259,9 +8576,6 @@ msgstr ""
msgid "Delete label: %{label_name} ?"
msgstr ""
-msgid "Delete license"
-msgstr ""
-
msgid "Delete list"
msgstr ""
@@ -8337,15 +8651,6 @@ msgstr ""
msgid "Deleting a project places it into a read-only state until %{date}, at which point the project will be permanently deleted. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "Deleting the license failed."
-msgstr ""
-
-msgid "Deleting the license failed. The license was not found."
-msgstr ""
-
-msgid "Deleting the license failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "Deleting the project will delete its repository and all related resources including issues, merge requests etc."
msgstr ""
@@ -8853,7 +9158,10 @@ msgstr ""
msgid "DesignManagement|The maximum number of designs allowed to be uploaded is %{upload_limit}. Please try again."
msgstr ""
-msgid "DesignManagement|To upload designs, you'll need to enable LFS. %{requirements_link_start}More information%{requirements_link_end}"
+msgid "DesignManagement|There was an error moving your designs. Please upload your designs below."
+msgstr ""
+
+msgid "DesignManagement|To upload designs, you'll need to enable LFS and have admin enable hashed storage. %{requirements_link_start}More information%{requirements_link_end}"
msgstr ""
msgid "DesignManagement|Unresolve thread"
@@ -8865,6 +9173,9 @@ msgstr ""
msgid "DesignManagement|Upload skipped."
msgstr ""
+msgid "DesignManagement|Your designs are being copied and are on their way… Please refresh to update."
+msgstr ""
+
msgid "DesignManagement|and %{moreCount} more."
msgstr ""
@@ -8922,6 +9233,9 @@ msgstr ""
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
+msgid "Direct member"
+msgstr ""
+
msgid "Direction"
msgstr ""
@@ -8970,9 +9284,6 @@ msgstr ""
msgid "Discard draft"
msgstr ""
-msgid "Discard review"
-msgstr ""
-
msgid "DiscordService|Discord Notifications"
msgstr ""
@@ -9043,10 +9354,10 @@ msgstr ""
msgid "Dismiss Merge Request promotion"
msgstr ""
-msgid "Dismiss Selected"
+msgid "Dismiss Value Stream Analytics introduction box"
msgstr ""
-msgid "Dismiss Value Stream Analytics introduction box"
+msgid "Dismiss selected"
msgstr ""
msgid "Dismiss trial promotion"
@@ -9097,9 +9408,6 @@ msgstr ""
msgid "Documents reindexed: %{processed_documents} (%{percentage}%%)"
msgstr ""
-msgid "Doing"
-msgstr ""
-
msgid "Domain"
msgstr ""
@@ -9295,9 +9603,6 @@ msgstr ""
msgid "Edit environment"
msgstr ""
-msgid "Edit file"
-msgstr ""
-
msgid "Edit files in the editor and commit changes here"
msgstr ""
@@ -9310,6 +9615,12 @@ msgstr ""
msgid "Edit identity for %{user_name}"
msgstr ""
+msgid "Edit in Web IDE"
+msgstr ""
+
+msgid "Edit in single-file editor"
+msgstr ""
+
msgid "Edit issues"
msgstr ""
@@ -9337,10 +9648,10 @@ msgstr ""
msgid "Editing"
msgstr ""
-msgid "Elasticsearch"
+msgid "Elasticsearch AWS IAM credentials"
msgstr ""
-msgid "Elasticsearch AWS IAM credentials"
+msgid "Elasticsearch HTTP client timeout value in seconds."
msgstr ""
msgid "Elasticsearch indexing restrictions"
@@ -9349,9 +9660,6 @@ msgstr ""
msgid "Elasticsearch indexing started"
msgstr ""
-msgid "Elasticsearch integration. Elasticsearch AWS IAM."
-msgstr ""
-
msgid "Elasticsearch reindexing is already in progress"
msgstr ""
@@ -9379,9 +9687,6 @@ msgstr ""
msgid "Email Notification"
msgstr ""
-msgid "Email address"
-msgstr ""
-
msgid "Email could not be sent"
msgstr ""
@@ -9445,6 +9750,9 @@ msgstr ""
msgid "Emails sent from Service Desk will have this name"
msgstr ""
+msgid "Emails sent to %{email} will still be supported"
+msgstr ""
+
msgid "Emails separated by comma"
msgstr ""
@@ -9478,9 +9786,18 @@ msgstr ""
msgid "Enable"
msgstr ""
+msgid "Enable %{link_start}Gitpod%{link_end} integration to launch a development environment in your browser directly from GitLab."
+msgstr ""
+
msgid "Enable Auto DevOps"
msgstr ""
+msgid "Enable Gitpod"
+msgstr ""
+
+msgid "Enable Gitpod?"
+msgstr ""
+
msgid "Enable HTML emails"
msgstr ""
@@ -9610,9 +9927,6 @@ msgstr ""
msgid "Encountered an error while rendering: %{err}"
msgstr ""
-msgid "End date"
-msgstr ""
-
msgid "Ends at (UTC)"
msgstr ""
@@ -9772,7 +10086,7 @@ msgstr ""
msgid "EnvironmentsDashboard|The environments dashboard provides a summary of each project's environments' status, including pipeline and alert statuses."
msgstr ""
-msgid "EnvironmentsDashboard|This dashboard displays a maximum of 7 projects and 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
+msgid "EnvironmentsDashboard|This dashboard displays 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
msgstr ""
msgid "Environments|An error occurred while canceling the auto stop, please try again"
@@ -10093,6 +10407,9 @@ msgstr ""
msgid "Error deleting project. Check logs for error details."
msgstr ""
+msgid "Error fetching burnup chart data"
+msgstr ""
+
msgid "Error fetching diverging counts for branches. Please try again."
msgstr ""
@@ -10171,6 +10488,9 @@ msgstr ""
msgid "Error occurred when saving assignees"
msgstr ""
+msgid "Error occurred when saving reviewers"
+msgstr ""
+
msgid "Error occurred when toggling the notification subscription"
msgstr ""
@@ -10423,10 +10743,13 @@ msgstr ""
msgid "Expand all"
msgstr ""
-msgid "Expand approvers"
+msgid "Expand all files"
msgstr ""
-msgid "Expand dropdown"
+msgid "Expand all threads"
+msgstr ""
+
+msgid "Expand approvers"
msgstr ""
msgid "Expand milestones"
@@ -10597,6 +10920,9 @@ msgstr ""
msgid "Failed to create Merge Request. Please try again."
msgstr ""
+msgid "Failed to create To-Do for the design."
+msgstr ""
+
msgid "Failed to create a branch for this issue. Please try again."
msgstr ""
@@ -10636,6 +10962,12 @@ msgstr ""
msgid "Failed to load authors. Please try again."
msgstr ""
+msgid "Failed to load branches. Please try again."
+msgstr ""
+
+msgid "Failed to load deploy keys."
+msgstr ""
+
msgid "Failed to load emoji list."
msgstr ""
@@ -10651,6 +10983,9 @@ msgstr ""
msgid "Failed to load groups & users."
msgstr ""
+msgid "Failed to load groups, users and deploy keys."
+msgstr ""
+
msgid "Failed to load labels. Please try again."
msgstr ""
@@ -10660,6 +10995,12 @@ msgstr ""
msgid "Failed to load related branches"
msgstr ""
+msgid "Failed to load sidebar confidential toggle"
+msgstr ""
+
+msgid "Failed to load sidebar lock status"
+msgstr ""
+
msgid "Failed to load stacktrace."
msgstr ""
@@ -10687,6 +11028,9 @@ msgstr ""
msgid "Failed to publish issue on status page."
msgstr ""
+msgid "Failed to remove To-Do for the design."
+msgstr ""
+
msgid "Failed to remove a Zoom meeting"
msgstr ""
@@ -10729,6 +11073,9 @@ msgstr ""
msgid "Failed to signing using smartcard authentication"
msgstr ""
+msgid "Failed to toggle To-Do for the design."
+msgstr ""
+
msgid "Failed to update branch!"
msgstr ""
@@ -10844,7 +11191,7 @@ msgstr ""
msgid "FeatureFlags|Edit User List"
msgstr ""
-msgid "FeatureFlags|Enable features for specific users and specific environments by defining feature flag strategies."
+msgid "FeatureFlags|Enable features for specific users and environments by configuring feature flag strategies."
msgstr ""
msgid "FeatureFlags|Environment Spec"
@@ -10904,7 +11251,7 @@ msgstr ""
msgid "FeatureFlags|Include additional user IDs"
msgstr ""
-msgid "FeatureFlags|Install a %{docs_link_anchored_start}compatible client library%{docs_link_anchored_end} and specify the API URL, application name, and instance ID during the configuration setup. %{docs_link_start}More Information%{docs_link_end}"
+msgid "FeatureFlags|Install a %{docsLinkAnchoredStart}compatible client library%{docsLinkAnchoredEnd} and specify the API URL, application name, and instance ID during the configuration setup. %{docsLinkStart}More Information%{docsLinkEnd}"
msgstr ""
msgid "FeatureFlags|Instance ID"
@@ -10916,6 +11263,9 @@ msgstr ""
msgid "FeatureFlags|Loading feature flags"
msgstr ""
+msgid "FeatureFlags|Loading user lists"
+msgstr ""
+
msgid "FeatureFlags|More information"
msgstr ""
@@ -10934,7 +11284,7 @@ msgstr ""
msgid "FeatureFlags|New feature flag"
msgstr ""
-msgid "FeatureFlags|New list"
+msgid "FeatureFlags|New user list"
msgstr ""
msgid "FeatureFlags|Percent of users"
@@ -10973,6 +11323,9 @@ msgstr ""
msgid "FeatureFlags|There was an error fetching the feature flags."
msgstr ""
+msgid "FeatureFlags|There was an error fetching the user lists."
+msgstr ""
+
msgid "FeatureFlags|There was an error retrieving user lists"
msgstr ""
@@ -10988,6 +11341,9 @@ msgstr ""
msgid "FeatureFlags|User List"
msgstr ""
+msgid "FeatureFlags|User Lists"
+msgstr ""
+
msgid "FeatureFlag|List"
msgstr ""
@@ -11015,15 +11371,6 @@ msgstr ""
msgid "Fetching incoming email"
msgstr ""
-msgid "Fetching licenses failed."
-msgstr ""
-
-msgid "Fetching licenses failed. The request endpoint was not found."
-msgstr ""
-
-msgid "Fetching licenses failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "File"
msgstr ""
@@ -11126,12 +11473,21 @@ msgstr ""
msgid "Filter by status"
msgstr ""
+msgid "Filter by test cases that are currently archived."
+msgstr ""
+
+msgid "Filter by test cases that are currently opened."
+msgstr ""
+
msgid "Filter by two-factor authentication"
msgstr ""
msgid "Filter by user"
msgstr ""
+msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
+msgstr ""
+
msgid "Filter pipelines"
msgstr ""
@@ -11147,7 +11503,7 @@ msgstr ""
msgid "Filter results..."
msgstr ""
-msgid "Filter your projects by name"
+msgid "Filter your repositories by name"
msgstr ""
msgid "Filter..."
@@ -11156,7 +11512,7 @@ msgstr ""
msgid "Find File"
msgstr ""
-msgid "Find bugs in your code with coverage-guided fuzzing"
+msgid "Find bugs in your code with coverage-guided fuzzing."
msgstr ""
msgid "Find by path"
@@ -11183,9 +11539,6 @@ msgstr ""
msgid "Finish editing this message first!"
msgstr ""
-msgid "Finish review"
-msgstr ""
-
msgid "Finish setting up your dedicated account for %{group_name}."
msgstr ""
@@ -11255,6 +11608,9 @@ msgstr ""
msgid "Footer message"
msgstr ""
+msgid "For a faster browsing experience, some files are collapsed by default."
+msgstr ""
+
msgid "For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
@@ -11264,6 +11620,9 @@ msgstr ""
msgid "For more info, read the documentation."
msgstr ""
+msgid "For more information on how the number of active users is calculated, see the %{self_managed_subscriptions_doc_link} documentation."
+msgstr ""
+
msgid "For more information, go to the "
msgstr ""
@@ -11402,6 +11761,9 @@ msgstr ""
msgid "Generate new token"
msgstr ""
+msgid "Generic package file size in bytes"
+msgstr ""
+
msgid "Geo"
msgstr ""
@@ -11663,6 +12025,9 @@ msgstr ""
msgid "Geo|Please refer to Geo Troubleshooting."
msgstr ""
+msgid "Geo|Primary node"
+msgstr ""
+
msgid "Geo|Project"
msgstr ""
@@ -11705,6 +12070,9 @@ msgstr ""
msgid "Geo|Review replication status, and resynchronize and reverify items with the primary node."
msgstr ""
+msgid "Geo|Secondary node"
+msgstr ""
+
msgid "Geo|Status"
msgstr ""
@@ -11744,6 +12112,9 @@ msgstr ""
msgid "Geo|URL must be a valid url (ex: https://gitlab.com)"
msgstr ""
+msgid "Geo|Undefined"
+msgstr ""
+
msgid "Geo|Unknown state"
msgstr ""
@@ -11819,10 +12190,16 @@ msgstr ""
msgid "GitHub import"
msgstr ""
+msgid "GitLab"
+msgstr ""
+
msgid "GitLab / Unsubscribe"
msgstr ""
-msgid "GitLab Enterprise Edition %{plan}"
+msgid "GitLab API"
+msgstr ""
+
+msgid "GitLab Billing Team."
msgstr ""
msgid "GitLab Group Runners can execute code for all the projects in this group."
@@ -11834,12 +12211,18 @@ msgstr ""
msgid "GitLab Issue"
msgstr ""
+msgid "GitLab Pages"
+msgstr ""
+
msgid "GitLab Service Desk is a simple way to allow people to create issues in your GitLab instance without needing their own user account. It provides a unique email address for end users to create issues in a project, and replies can be sent either through the GitLab interface or by email. End users will only see the thread through email."
msgstr ""
msgid "GitLab Shared Runners execute code of different projects on the same Runner unless you configure GitLab Runner Autoscale with MaxBuilds 1 (which it is on GitLab.com)."
msgstr ""
+msgid "GitLab Shell"
+msgstr ""
+
msgid "GitLab Support Bot"
msgstr ""
@@ -11849,7 +12232,7 @@ msgstr ""
msgid "GitLab User"
msgstr ""
-msgid "GitLab allows you to continue using your license even if you exceed the number of seats you purchased. You will be required to pay for these seats when you renew your license."
+msgid "GitLab Workhorse"
msgstr ""
msgid "GitLab commit"
@@ -12017,6 +12400,21 @@ msgstr ""
msgid "Gitlab Pages"
msgstr ""
+msgid "Gitpod"
+msgstr ""
+
+msgid "Gitpod|Add the URL to your Gitpod instance configured to read your GitLab projects."
+msgstr ""
+
+msgid "Gitpod|Enable Gitpod integration"
+msgstr ""
+
+msgid "Gitpod|Gitpod URL"
+msgstr ""
+
+msgid "Gitpod|e.g. https://gitpod.example.com"
+msgstr ""
+
msgid "Given access %{time_ago}"
msgstr ""
@@ -12524,9 +12922,6 @@ msgstr ""
msgid "GroupSAML|Valid SAML Response"
msgstr ""
-msgid "GroupSAML|With group managed accounts enabled, all the users without a group managed account will be excluded from the group."
-msgstr ""
-
msgid "GroupSAML|With prohibit outer forks flag enabled group members will be able to fork project only inside your group."
msgstr ""
@@ -12740,10 +13135,10 @@ msgstr ""
msgid "GroupsNew|Create group"
msgstr ""
-msgid "GroupsNew|GitLab group export"
+msgid "GroupsNew|Import"
msgstr ""
-msgid "GroupsNew|Import"
+msgid "GroupsNew|Import a GitLab group export file"
msgstr ""
msgid "GroupsNew|Import group"
@@ -12888,6 +13283,9 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "Hide comments on this file"
+msgstr ""
+
msgid "Hide details"
msgstr ""
@@ -12934,6 +13332,15 @@ msgstr ""
msgid "Highest role:"
msgstr ""
+msgid "HighlightBar|Alert events:"
+msgstr ""
+
+msgid "HighlightBar|Alert start time:"
+msgstr ""
+
+msgid "HighlightBar|Original alert:"
+msgstr ""
+
msgid "History"
msgstr ""
@@ -13111,6 +13518,9 @@ msgstr ""
msgid "If enabled, access to projects will be validated on an external service using their classification label."
msgstr ""
+msgid "If the number of active users exceeds the user limit, you will be charged for the number of %{users_over_license_link} at your next license reconciliation."
+msgstr ""
+
msgid "If there is no previous license or if the previous license has expired, some GitLab functionality will be blocked until a new, valid license is uploaded."
msgstr ""
@@ -13150,9 +13560,6 @@ msgstr ""
msgid "If your HTTP repository is not publicly accessible, add your credentials."
msgstr ""
-msgid "Iglu registry URL (optional)"
-msgstr ""
-
msgid "Ignore"
msgstr ""
@@ -13189,6 +13596,20 @@ msgstr ""
msgid "Import"
msgstr ""
+msgid "Import %d compatible repository"
+msgid_plural "Import %d compatible repositories"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
+msgid "Import %d repository"
+msgid_plural "Import %d repositories"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "Import CSV"
msgstr ""
@@ -13198,15 +13619,9 @@ msgstr ""
msgid "Import all compatible projects"
msgstr ""
-msgid "Import all compatible repositories"
-msgstr ""
-
msgid "Import all projects"
msgstr ""
-msgid "Import all repositories"
-msgstr ""
-
msgid "Import an exported GitLab project"
msgstr ""
@@ -13294,6 +13709,9 @@ msgstr ""
msgid "ImportProjects|Error importing repository %{project_safe_import_url} into %{project_full_path} - %{message}"
msgstr ""
+msgid "ImportProjects|Import repositories"
+msgstr ""
+
msgid "ImportProjects|Importing the project failed"
msgstr ""
@@ -13306,7 +13724,7 @@ msgstr ""
msgid "ImportProjects|Requesting your %{provider} repositories failed"
msgstr ""
-msgid "ImportProjects|Select the projects you want to import"
+msgid "ImportProjects|Select the repositories you want to import"
msgstr ""
msgid "ImportProjects|The remote data could not be imported."
@@ -13342,9 +13760,6 @@ msgstr ""
msgid "In order to enable Service Desk for your instance, you must first set up incoming email."
msgstr ""
-msgid "In order to gather accurate feature usage data, it can take 1 to 2 weeks to see your index."
-msgstr ""
-
msgid "In order to personalize your experience with GitLab%{br_tag}we would like to know a bit more about you."
msgstr ""
@@ -13375,18 +13790,30 @@ msgstr ""
msgid "IncidentManagement|Create incident"
msgstr ""
+msgid "IncidentManagement|Critical - S1"
+msgstr ""
+
msgid "IncidentManagement|Date created"
msgstr ""
msgid "IncidentManagement|Display your incidents in a dedicated view"
msgstr ""
+msgid "IncidentManagement|High - S2"
+msgstr ""
+
msgid "IncidentManagement|Incident"
msgstr ""
msgid "IncidentManagement|Incidents"
msgstr ""
+msgid "IncidentManagement|Low - S4"
+msgstr ""
+
+msgid "IncidentManagement|Medium - S3"
+msgstr ""
+
msgid "IncidentManagement|No incidents to display."
msgstr ""
@@ -13399,6 +13826,9 @@ msgstr ""
msgid "IncidentManagement|Published to status page"
msgstr ""
+msgid "IncidentManagement|Severity"
+msgstr ""
+
msgid "IncidentManagement|There are no closed incidents"
msgstr ""
@@ -13408,6 +13838,9 @@ msgstr ""
msgid "IncidentManagement|Unassigned"
msgstr ""
+msgid "IncidentManagement|Unknown"
+msgstr ""
+
msgid "IncidentManagement|Unpublished"
msgstr ""
@@ -13429,6 +13862,15 @@ msgstr ""
msgid "Incidents"
msgstr ""
+msgid "Incident|Alert details"
+msgstr ""
+
+msgid "Incident|Summary"
+msgstr ""
+
+msgid "Incident|There was an issue loading alert data. Please try again."
+msgstr ""
+
msgid "Include a Terms of Service agreement and Privacy Policy that all users must accept."
msgstr ""
@@ -13489,6 +13931,9 @@ msgstr ""
msgid "Information about additional Pages templates and how to install them can be found in our %{pages_getting_started_guide}."
msgstr ""
+msgid "Inherited"
+msgstr ""
+
msgid "Inherited:"
msgstr ""
@@ -13571,7 +14016,22 @@ msgstr ""
msgid "Instance administrators group already exists"
msgstr ""
-msgid "Instance license"
+msgid "InstanceStatistics|Groups"
+msgstr ""
+
+msgid "InstanceStatistics|Issues"
+msgstr ""
+
+msgid "InstanceStatistics|Merge Requests"
+msgstr ""
+
+msgid "InstanceStatistics|Pipelines"
+msgstr ""
+
+msgid "InstanceStatistics|Projects"
+msgstr ""
+
+msgid "InstanceStatistics|Users"
msgstr ""
msgid "Integration"
@@ -13583,6 +14043,12 @@ msgstr ""
msgid "Integrations"
msgstr ""
+msgid "Integrations|%{integration} settings saved and active."
+msgstr ""
+
+msgid "Integrations|%{integration} settings saved, but not active."
+msgstr ""
+
msgid "Integrations|All details"
msgstr ""
@@ -13592,6 +14058,12 @@ msgstr ""
msgid "Integrations|Comment settings:"
msgstr ""
+msgid "Integrations|Connection failed. Please check your settings."
+msgstr ""
+
+msgid "Integrations|Connection successful."
+msgstr ""
+
msgid "Integrations|Default settings are inherited from the group level."
msgstr ""
@@ -13607,6 +14079,15 @@ msgstr ""
msgid "Integrations|Includes commit title and branch"
msgstr ""
+msgid "Integrations|Projects using custom settings will not be impacted unless the project owner chooses to use instance-level defaults."
+msgstr ""
+
+msgid "Integrations|Save settings?"
+msgstr ""
+
+msgid "Integrations|Saving will update the default settings for all projects that are not using custom settings."
+msgstr ""
+
msgid "Integrations|Standard"
msgstr ""
@@ -13739,6 +14220,9 @@ msgstr ""
msgid "Invitation"
msgstr ""
+msgid "Invitation declined"
+msgstr ""
+
msgid "Invite"
msgstr ""
@@ -13790,6 +14274,42 @@ 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|%{linkStart}Read more%{linkEnd} about role permissions"
+msgstr ""
+
+msgid "InviteMembersModal|Access expiration date (optional)"
+msgstr ""
+
+msgid "InviteMembersModal|Cancel"
+msgstr ""
+
+msgid "InviteMembersModal|Choose a role permission"
+msgstr ""
+
+msgid "InviteMembersModal|GitLab member or Email address"
+msgstr ""
+
+msgid "InviteMembersModal|Invite"
+msgstr ""
+
+msgid "InviteMembersModal|Invite team members"
+msgstr ""
+
+msgid "InviteMembersModal|Search for members to invite"
+msgstr ""
+
+msgid "InviteMembersModal|User not invited. Feature coming soon!"
+msgstr ""
+
+msgid "InviteMembersModal|Users were succesfully added"
+msgstr ""
+
+msgid "InviteMembersModal|You're inviting members to the %{group_name} group"
+msgstr ""
+
+msgid "InviteMembers|Invite team members"
+msgstr ""
+
msgid "Invited"
msgstr ""
@@ -13844,10 +14364,13 @@ msgstr ""
msgid "Issue cannot be found."
msgstr ""
+msgid "Issue created from vulnerability %{vulnerability_link}"
+msgstr ""
+
msgid "Issue events"
msgstr ""
-msgid "Issue first depoloyed to production"
+msgid "Issue first deployed to production"
msgstr ""
msgid "Issue label"
@@ -13925,6 +14448,9 @@ msgstr ""
msgid "IssueTracker|Custom issue tracker"
msgstr ""
+msgid "IssueTracker|EWM work items tracker"
+msgstr ""
+
msgid "IssueTracker|Redmine issue tracker"
msgstr ""
@@ -13991,6 +14517,9 @@ msgstr ""
msgid "It looks like you have some draft commits in this branch."
msgstr ""
+msgid "It may be several days before you see feature usage data."
+msgstr ""
+
msgid "It must have a header row and at least two columns: the first column is the issue title and the second column is the issue description. The separator is automatically detected."
msgstr ""
@@ -14273,13 +14802,13 @@ msgstr ""
msgid "Join Zoom meeting"
msgstr ""
-msgid "Jul"
+msgid "Joined %{time_ago}"
msgstr ""
-msgid "July"
+msgid "Jul"
msgstr ""
-msgid "Jump to first unresolved thread"
+msgid "July"
msgstr ""
msgid "Jump to next unresolved thread"
@@ -14315,6 +14844,9 @@ msgstr ""
msgid "Keyboard shortcuts"
msgstr ""
+msgid "KeyboardKey|Ctrl+"
+msgstr ""
+
msgid "Keys"
msgstr ""
@@ -14363,6 +14895,9 @@ msgstr ""
msgid "LDAP Synchronization"
msgstr ""
+msgid "LDAP group settings"
+msgstr ""
+
msgid "LDAP settings"
msgstr ""
@@ -14372,6 +14907,9 @@ msgstr ""
msgid "LDAP sync in progress. This could take a few minutes. Refresh the page to see the changes."
msgstr ""
+msgid "LDAP synchronizations"
+msgstr ""
+
msgid "LFS"
msgstr ""
@@ -14454,7 +14992,16 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "Last %{days} days"
+msgid "Last 2 weeks"
+msgstr ""
+
+msgid "Last 30 days"
+msgstr ""
+
+msgid "Last 60 days"
+msgstr ""
+
+msgid "Last 90 days"
msgstr ""
msgid "Last Accessed On"
@@ -14532,6 +15079,9 @@ msgstr ""
msgid "Last used on:"
msgstr ""
+msgid "Last week"
+msgstr ""
+
msgid "LastCommit|authored"
msgstr ""
@@ -14547,6 +15097,9 @@ msgstr ""
msgid "Latest pipeline for the most recent commit on this branch"
msgstr ""
+msgid "Launch a ready-to-code development environment for your project."
+msgstr ""
+
msgid "Lead"
msgstr ""
@@ -14941,6 +15494,9 @@ msgstr ""
msgid "List of all merge commits"
msgstr ""
+msgid "List options"
+msgstr ""
+
msgid "List settings"
msgstr ""
@@ -14953,9 +15509,6 @@ msgstr ""
msgid "List your Bitbucket Server repositories"
msgstr ""
-msgid "Lists"
-msgstr ""
-
msgid "Live preview"
msgstr ""
@@ -15202,6 +15755,12 @@ msgstr ""
msgid "Mark as done"
msgstr ""
+msgid "Mark as draft"
+msgstr ""
+
+msgid "Mark as ready"
+msgstr ""
+
msgid "Mark as resolved"
msgstr ""
@@ -15223,6 +15782,24 @@ msgstr ""
msgid "Markdown is supported"
msgstr ""
+msgid "MarkdownEditor|Add a link (%{modifierKey}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add a link (%{modifier_key}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifierKey}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifier_key}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifierKey}I)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifier_key}I)"
+msgstr ""
+
msgid "Marked For Deletion At - %{deletion_time}"
msgstr ""
@@ -15307,7 +15884,25 @@ msgstr ""
msgid "Max access level"
msgstr ""
-msgid "Max seats used"
+msgid "Max role"
+msgstr ""
+
+msgid "Max size 15 MB"
+msgstr ""
+
+msgid "Maximum Conan package file size in bytes"
+msgstr ""
+
+msgid "Maximum Maven package file size in bytes"
+msgstr ""
+
+msgid "Maximum NPM package file size in bytes"
+msgstr ""
+
+msgid "Maximum NuGet package file size in bytes"
+msgstr ""
+
+msgid "Maximum PyPI package file size in bytes"
msgstr ""
msgid "Maximum Users:"
@@ -15439,6 +16034,18 @@ msgstr ""
msgid "Members with access to %{strong_start}%{group_name}%{strong_end}"
msgstr ""
+msgid "Members|%{time} by %{user}"
+msgstr ""
+
+msgid "Members|Expired"
+msgstr ""
+
+msgid "Members|No expiration set"
+msgstr ""
+
+msgid "Members|in %{time}"
+msgstr ""
+
msgid "Memory Usage"
msgstr ""
@@ -15625,9 +16232,6 @@ msgstr ""
msgid "MergeRequests|Thread will be unresolved"
msgstr ""
-msgid "MergeRequests|Toggle comments for this file"
-msgstr ""
-
msgid "MergeRequests|View file @ %{commitId}"
msgstr ""
@@ -15688,6 +16292,9 @@ msgstr ""
msgid "Merging immediately isn't recommended as it may negatively impact the existing merge train. Read the %{docsLinkStart}documentation%{docsLinkEnd} for more information."
msgstr ""
+msgid "Message"
+msgstr ""
+
msgid "Messages"
msgstr ""
@@ -16077,18 +16684,12 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "Milestone does not support burnup charts"
-msgstr ""
-
msgid "Milestone lists not available with your current license"
msgstr ""
msgid "Milestone lists show all issues from the selected milestone."
msgstr ""
-msgid "Milestone must have a start and due date"
-msgstr ""
-
msgid "MilestoneSidebar|Closed:"
msgstr ""
@@ -16455,6 +17056,9 @@ msgstr ""
msgid "Namespace"
msgstr ""
+msgid "Namespace ID:"
+msgstr ""
+
msgid "Namespace is empty"
msgstr ""
@@ -16539,6 +17143,9 @@ msgstr ""
msgid "NetworkPolicies|Allow all outbound traffic from %{selector} to %{ruleSelector} on %{ports}"
msgstr ""
+msgid "NetworkPolicies|Are you sure you want to delete this policy? This action cannot be undone."
+msgstr ""
+
msgid "NetworkPolicies|Choose whether to enforce this policy."
msgstr ""
@@ -16548,12 +17155,21 @@ msgstr ""
msgid "NetworkPolicies|Define this policy's location, conditions and actions."
msgstr ""
+msgid "NetworkPolicies|Delete policy"
+msgstr ""
+
+msgid "NetworkPolicies|Delete policy: %{policy}"
+msgstr ""
+
msgid "NetworkPolicies|Deny all traffic"
msgstr ""
msgid "NetworkPolicies|Description"
msgstr ""
+msgid "NetworkPolicies|Edit policy"
+msgstr ""
+
msgid "NetworkPolicies|Editor mode"
msgstr ""
@@ -16581,6 +17197,9 @@ msgstr ""
msgid "NetworkPolicies|Name"
msgstr ""
+msgid "NetworkPolicies|Namespace"
+msgstr ""
+
msgid "NetworkPolicies|Network Policy"
msgstr ""
@@ -16632,6 +17251,9 @@ msgstr ""
msgid "NetworkPolicies|Rules"
msgstr ""
+msgid "NetworkPolicies|Save changes"
+msgstr ""
+
msgid "NetworkPolicies|Something went wrong, failed to update policy"
msgstr ""
@@ -16644,6 +17266,9 @@ msgstr ""
msgid "NetworkPolicies|Traffic that does not match any rule will be blocked."
msgstr ""
+msgid "NetworkPolicies|Unable to parse policy"
+msgstr ""
+
msgid "NetworkPolicies|YAML editor"
msgstr ""
@@ -16759,6 +17384,9 @@ msgstr ""
msgid "New Snippet"
msgstr ""
+msgid "New Test Case"
+msgstr ""
+
msgid "New User"
msgstr ""
@@ -16858,6 +17486,9 @@ msgstr ""
msgid "New tag"
msgstr ""
+msgid "New test case"
+msgstr ""
+
msgid "New users set to external"
msgstr ""
@@ -16930,7 +17561,7 @@ msgstr ""
msgid "No changes"
msgstr ""
-msgid "No changes between %{ref_start}%{source_branch}%{ref_end} and %{ref_start}%{target_branch}%{ref_end}"
+msgid "No changes between %{sourceBranch} and %{targetBranch}"
msgstr ""
msgid "No child epics match applied filters"
@@ -16945,6 +17576,9 @@ msgstr ""
msgid "No containers available"
msgstr ""
+msgid "No content to show"
+msgstr ""
+
msgid "No contributions"
msgstr ""
@@ -17020,9 +17654,6 @@ msgstr ""
msgid "No license. All rights reserved"
msgstr ""
-msgid "No licenses found."
-msgstr ""
-
msgid "No matches found"
msgstr ""
@@ -17035,6 +17666,9 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No members found"
+msgstr ""
+
msgid "No merge requests found"
msgstr ""
@@ -17056,6 +17690,9 @@ msgstr ""
msgid "No parent group"
msgstr ""
+msgid "No plan"
+msgstr ""
+
msgid "No pods available"
msgstr ""
@@ -17152,6 +17789,12 @@ msgstr ""
msgid "Not Implemented"
msgstr ""
+msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+msgstr ""
+
+msgid "Not all browsers support WebAuthn. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even from an unsupported browser."
+msgstr ""
+
msgid "Not all data has been processed yet, the accuracy of the chart for the selected timeframe is limited."
msgstr ""
@@ -17248,6 +17891,9 @@ msgstr ""
msgid "Notification settings saved"
msgstr ""
+msgid "NotificationEvent|Change reviewer merge request"
+msgstr ""
+
msgid "NotificationEvent|Close issue"
msgstr ""
@@ -17410,10 +18056,7 @@ msgstr ""
msgid "On track"
msgstr ""
-msgid "OnDemandScans|Attached branch"
-msgstr ""
-
-msgid "OnDemandScans|Attached branch is where the scan job runs."
+msgid "OnDemandScans|Could not fetch scanner profiles. Please refresh the page, or try again later."
msgstr ""
msgid "OnDemandScans|Could not fetch site profiles. Please refresh the page, or try again later."
@@ -17422,6 +18065,9 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
+msgid "OnDemandScans|Create a new scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Create a new site profile"
msgstr ""
@@ -17434,6 +18080,9 @@ msgstr ""
msgid "OnDemandScans|New on-demand DAST scan"
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 ""
@@ -17443,16 +18092,10 @@ msgstr ""
msgid "OnDemandScans|On-demand scans run outside the DevOps cycle and find vulnerabilities in your projects. %{learnMoreLinkStart}Learn more%{learnMoreLinkEnd}"
msgstr ""
-msgid "OnDemandScans|Only a passive scan can be performed on demand."
-msgstr ""
-
-msgid "OnDemandScans|Passive"
-msgstr ""
-
msgid "OnDemandScans|Run scan"
msgstr ""
-msgid "OnDemandScans|Scan mode"
+msgid "OnDemandScans|Scanner profile"
msgstr ""
msgid "OnDemandScans|Scanner settings"
@@ -17464,9 +18107,15 @@ msgstr ""
msgid "OnDemandScans|Select one of the existing profiles"
msgstr ""
+msgid "OnDemandScans|Site profile"
+msgstr ""
+
msgid "OnDemandScans|Site profiles"
msgstr ""
+msgid "OnDemandScans|Use existing scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Use existing site profile"
msgstr ""
@@ -17567,9 +18216,6 @@ msgstr ""
msgid "Open Selection"
msgstr ""
-msgid "Open Web IDE"
-msgstr ""
-
msgid "Open comment type dropdown"
msgstr ""
@@ -17675,6 +18321,9 @@ msgstr ""
msgid "Origin"
msgstr ""
+msgid "Orphaned member"
+msgstr ""
+
msgid "Other Labels"
msgstr ""
@@ -17690,6 +18339,9 @@ msgstr ""
msgid "Other visibility settings have been disabled by the administrator."
msgstr ""
+msgid "Our documentation includes an example DevOps Score report."
+msgstr ""
+
msgid "Out-of-compliance with this project's policies and should be removed"
msgstr ""
@@ -17714,6 +18366,9 @@ msgstr ""
msgid "Overwrite diverged branches"
msgstr ""
+msgid "Owned by %{image_tag}"
+msgstr ""
+
msgid "Owned by anyone"
msgstr ""
@@ -17735,6 +18390,9 @@ msgstr ""
msgid "Package deleted successfully"
msgstr ""
+msgid "Package file size limits"
+msgstr ""
+
msgid "Package recipe already exists"
msgstr ""
@@ -17750,9 +18408,6 @@ msgstr ""
msgid "Package type must be PyPi"
msgstr ""
-msgid "Package was removed"
-msgstr ""
-
msgid "PackageRegistry|%{name} version %{version} was created %{datetime}"
msgstr ""
@@ -17894,12 +18549,18 @@ msgstr ""
msgid "PackageRegistry|NuGet Command"
msgstr ""
+msgid "PackageRegistry|Package Registry"
+msgstr ""
+
msgid "PackageRegistry|Pip Command"
msgstr ""
msgid "PackageRegistry|Pipeline %{link} triggered %{datetime} by %{author}"
msgstr ""
+msgid "PackageRegistry|Publish and share packages for a variety of common package managers. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "PackageRegistry|Published to the %{project} Package Registry %{datetime}"
msgstr ""
@@ -17999,6 +18660,9 @@ msgstr ""
msgid "Page not found"
msgstr ""
+msgid "Page settings"
+msgstr ""
+
msgid "Page was successfully deleted"
msgstr ""
@@ -18140,7 +18804,7 @@ msgstr ""
msgid "Paste issue link"
msgstr ""
-msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Don't use your private SSH key."
+msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Do not paste your private SSH key, as that can compromise your identity."
msgstr ""
msgid "Patch to apply"
@@ -18167,6 +18831,9 @@ msgstr ""
msgid "Pending"
msgstr ""
+msgid "Pending comments"
+msgstr ""
+
msgid "People without permission will never get a notification and won't be able to comment."
msgstr ""
@@ -18365,6 +19032,9 @@ msgstr ""
msgid "Pipelines|Build with confidence"
msgstr ""
+msgid "Pipelines|By revoking a trigger you will break any processes making use of it. Are you sure?"
+msgstr ""
+
msgid "Pipelines|CI Lint"
msgstr ""
@@ -18377,6 +19047,15 @@ msgstr ""
msgid "Pipelines|Continuous Integration can help catch bugs by running your tests automatically, while Continuous Deployment can help you deliver code to your product environment."
msgstr ""
+msgid "Pipelines|Copy trigger token"
+msgstr ""
+
+msgid "Pipelines|Description"
+msgstr ""
+
+msgid "Pipelines|Edit"
+msgstr ""
+
msgid "Pipelines|Get started with Pipelines"
msgstr ""
@@ -18392,15 +19071,27 @@ msgstr ""
msgid "Pipelines|It is recommended the code is reviewed thoroughly before running this pipeline with the parent project's CI resource."
msgstr ""
+msgid "Pipelines|Last Used"
+msgstr ""
+
msgid "Pipelines|Loading Pipelines"
msgstr ""
msgid "Pipelines|More Information"
msgstr ""
+msgid "Pipelines|No triggers have been created yet. Add one using the form above."
+msgstr ""
+
+msgid "Pipelines|Owner"
+msgstr ""
+
msgid "Pipelines|Project cache successfully reset."
msgstr ""
+msgid "Pipelines|Revoke"
+msgstr ""
+
msgid "Pipelines|Run Pipeline"
msgstr ""
@@ -18425,6 +19116,15 @@ msgstr ""
msgid "Pipelines|This project is not currently set up to run pipelines."
msgstr ""
+msgid "Pipelines|Token"
+msgstr ""
+
+msgid "Pipelines|Trigger user has insufficient permissions to project"
+msgstr ""
+
+msgid "Pipelines|invalid"
+msgstr ""
+
msgid "Pipelines|parent"
msgstr ""
@@ -18683,10 +19383,10 @@ msgstr ""
msgid "Please provide attributes to update"
msgstr ""
-msgid "Please refer to %{docs_url}"
+msgid "Please reach out if you have any questions and we'll be happy to assist."
msgstr ""
-msgid "Please retype the email address."
+msgid "Please refer to %{docs_url}"
msgstr ""
msgid "Please select"
@@ -18716,6 +19416,9 @@ msgstr ""
msgid "Please set a new password before proceeding."
msgstr ""
+msgid "Please share your feedback about %{featureName} %{linkStart}in this issue%{linkEnd} to help us improve the experience."
+msgstr ""
+
msgid "Please solve the reCAPTCHA"
msgstr ""
@@ -19019,6 +19722,9 @@ msgstr ""
msgid "Profiles| You are going to change the username %{currentUsernameBold} to %{newUsernameBold}. Profile and projects will be redirected to the %{newUsername} namespace but this redirect will expire once the %{currentUsername} namespace is registered by another user or group. Please update your Git repository remotes as soon as possible."
msgstr ""
+msgid "Profiles|%{provider} Active"
+msgstr ""
+
msgid "Profiles|@username"
msgstr ""
@@ -19070,7 +19776,7 @@ msgstr ""
msgid "Profiles|Commit email"
msgstr ""
-msgid "Profiles|Connect"
+msgid "Profiles|Connect %{provider}"
msgstr ""
msgid "Profiles|Connected Accounts"
@@ -19094,6 +19800,9 @@ msgstr ""
msgid "Profiles|Disconnect"
msgstr ""
+msgid "Profiles|Disconnect %{provider}"
+msgstr ""
+
msgid "Profiles|Do not show on profile"
msgstr ""
@@ -19118,7 +19827,7 @@ msgstr ""
msgid "Profiles|Full name"
msgstr ""
-msgid "Profiles|Give your individual key a title. This will be publically visible."
+msgid "Profiles|Give your individual key a title."
msgstr ""
msgid "Profiles|Include private contributions on my profile"
@@ -19208,7 +19917,7 @@ msgstr ""
msgid "Profiles|The maximum file size allowed is 200KB."
msgstr ""
-msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it?"
+msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it? It will be publicly visible."
msgstr ""
msgid "Profiles|This email will be displayed on your public profile"
@@ -19283,6 +19992,9 @@ msgstr ""
msgid "Profiles|You don't have access to delete this user."
msgstr ""
+msgid "Profiles|You must transfer ownership or delete groups you are an owner of before you can delete your account"
+msgstr ""
+
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
@@ -19871,6 +20583,9 @@ msgstr ""
msgid "ProjectTemplates|GitLab Cluster Management"
msgstr ""
+msgid "ProjectTemplates|Gitpod/Spring Petclinic"
+msgstr ""
+
msgid "ProjectTemplates|Go Micro"
msgstr ""
@@ -20480,6 +21195,9 @@ msgstr ""
msgid "Publish to status page"
msgstr ""
+msgid "Published"
+msgstr ""
+
msgid "Published on status page"
msgstr ""
@@ -20597,9 +21315,15 @@ msgstr ""
msgid "Quick range"
msgstr ""
+msgid "Quickly and easily edit multiple files in your project."
+msgstr ""
+
msgid "README"
msgstr ""
+msgid "Rails"
+msgstr ""
+
msgid "Rake Tasks Help"
msgstr ""
@@ -20721,10 +21445,13 @@ msgstr ""
msgid "Register Two-Factor Authenticator"
msgstr ""
-msgid "Register U2F device"
+msgid "Register Universal Two-Factor (U2F) Device"
+msgstr ""
+
+msgid "Register WebAuthn Device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register device"
msgstr ""
msgid "Register for GitLab"
@@ -20736,9 +21463,6 @@ msgstr ""
msgid "Register with two-factor app"
msgstr ""
-msgid "Registration"
-msgstr ""
-
msgid "Registration|Checkout"
msgstr ""
@@ -20857,9 +21581,6 @@ msgstr ""
msgid "Release|Something went wrong while saving the release details"
msgstr ""
-msgid "Remediated: needs review"
-msgstr ""
-
msgid "Remediations"
msgstr ""
@@ -20965,6 +21686,9 @@ msgstr ""
msgid "Remove priority"
msgstr ""
+msgid "Remove report"
+msgstr ""
+
msgid "Remove secondary node"
msgstr ""
@@ -20977,6 +21701,12 @@ msgstr ""
msgid "Remove time estimate"
msgstr ""
+msgid "Remove user & report"
+msgstr ""
+
+msgid "Remove user from group"
+msgstr ""
+
msgid "Removed"
msgstr ""
@@ -21058,9 +21788,6 @@ msgstr ""
msgid "Removes time estimate."
msgstr ""
-msgid "Removing license…"
-msgstr ""
-
msgid "Removing this group also removes all child projects, including archived projects, and their resources."
msgstr ""
@@ -21145,6 +21872,9 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
+msgid "Reported by %{reporter}"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -21233,6 +21963,27 @@ msgstr ""
msgid "Repositories"
msgstr ""
+msgid "Repositories Analytics"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download Historic Test Coverage Data"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download historic test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Historic Test Coverage Data is available in raw format (.csv) for further analysis."
+msgstr ""
+
+msgid "RepositoriesAnalytics|Test Code Coverage"
+msgstr ""
+
+msgid "RepositoriesAnalytics|There was an error fetching the projects."
+msgstr ""
+
msgid "Repository"
msgstr ""
@@ -21311,9 +22062,15 @@ msgstr ""
msgid "Request parameter %{param} is missing."
msgstr ""
+msgid "Request review from"
+msgstr ""
+
msgid "Request to link SAML account must be authorized"
msgstr ""
+msgid "Requested"
+msgstr ""
+
msgid "Requested %{time_ago}"
msgstr ""
@@ -21332,6 +22089,9 @@ msgstr ""
msgid "Requests to these domain(s)/address(es) on the local network will be allowed when local requests from hooks and services are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 or 127.0.0.0/28 are supported. Domain wildcards are not supported currently. Use comma, semicolon, or newline to separate multiple entries. The allowlist can hold a maximum of 1000 entries. Domains should use IDNA encoding. Ex: example.com, 192.168.1.1, 127.0.0.0/28, xn--itlab-j1a.com."
msgstr ""
+msgid "Require admin approval for new sign-ups"
+msgstr ""
+
msgid "Require all users in this group to setup Two-factor authentication"
msgstr ""
@@ -21463,9 +22223,6 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
-msgid "Resolved by %{resolvedByName}"
-msgstr ""
-
msgid "Resolves IP addresses once and uses them to submit requests"
msgstr ""
@@ -21587,6 +22344,16 @@ msgstr ""
msgid "ReviewApp|Enable Review App"
msgstr ""
+msgid "Reviewer"
+msgid_plural "%d Reviewers"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
+msgid "Reviewer(s)"
+msgstr ""
+
msgid "Reviewing"
msgstr ""
@@ -21626,6 +22393,9 @@ msgstr ""
msgid "Rook"
msgstr ""
+msgid "Ruby"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -21704,6 +22474,63 @@ msgstr ""
msgid "Runners page."
msgstr ""
+msgid "Runners|Active"
+msgstr ""
+
+msgid "Runners|Architecture"
+msgstr ""
+
+msgid "Runners|Can run untagged jobs"
+msgstr ""
+
+msgid "Runners|Description"
+msgstr ""
+
+msgid "Runners|Group"
+msgstr ""
+
+msgid "Runners|IP Address"
+msgstr ""
+
+msgid "Runners|Last contact"
+msgstr ""
+
+msgid "Runners|Locked to this project"
+msgstr ""
+
+msgid "Runners|Maximum job timeout"
+msgstr ""
+
+msgid "Runners|Name"
+msgstr ""
+
+msgid "Runners|Platform"
+msgstr ""
+
+msgid "Runners|Property Name"
+msgstr ""
+
+msgid "Runners|Protected"
+msgstr ""
+
+msgid "Runners|Revision"
+msgstr ""
+
+msgid "Runners|Shared"
+msgstr ""
+
+msgid "Runners|Specific"
+msgstr ""
+
+msgid "Runners|Tags"
+msgstr ""
+
+msgid "Runners|Value"
+msgstr ""
+
+msgid "Runners|Version"
+msgstr ""
+
msgid "Runners|You have used %{quotaUsed} out of %{quotaLimit} of your shared Runners pipeline minutes."
msgstr ""
@@ -21716,6 +22543,9 @@ msgstr ""
msgid "Runs a number of housekeeping tasks within the current repository, such as compressing file revisions and removing unreachable objects."
msgstr ""
+msgid "SAML"
+msgstr ""
+
msgid "SAML SSO"
msgstr ""
@@ -21767,6 +22597,9 @@ msgstr ""
msgid "Save"
msgstr ""
+msgid "Save %{name} size limits"
+msgstr ""
+
msgid "Save Changes"
msgstr ""
@@ -21797,9 +22630,6 @@ msgstr ""
msgid "Save space and find tags in the Container Registry more easily. Enable the cleanup policy to remove stale tags and keep only the ones you need."
msgstr ""
-msgid "Save template"
-msgstr ""
-
msgid "Save variables"
msgstr ""
@@ -21842,9 +22672,6 @@ msgstr ""
msgid "Scope"
msgstr ""
-msgid "Scope not supported with disabled 'users_search' feature!"
-msgstr ""
-
msgid "Scoped issue boards"
msgstr ""
@@ -21971,9 +22798,6 @@ msgstr ""
msgid "Search requirements"
msgstr ""
-msgid "Search results…"
-msgstr ""
-
msgid "Search users"
msgstr ""
@@ -22052,6 +22876,13 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "SearchResults|epic"
+msgid_plural "SearchResults|epics"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "SearchResults|issue"
msgid_plural "SearchResults|issues"
msgstr[0] ""
@@ -22110,10 +22941,10 @@ msgstr ""
msgid "Seat Link is disabled, and cannot be configured through this form."
msgstr ""
-msgid "Seats currently in use"
+msgid "Seats usage data as of %{last_enqueue_time}"
msgstr ""
-msgid "Seats in license"
+msgid "Seats usage data is updated every day at 12:00pm UTC"
msgstr ""
msgid "Secondary"
@@ -22167,6 +22998,9 @@ msgstr ""
msgid "SecurityConfiguration|Available for on-demand DAST"
msgstr ""
+msgid "SecurityConfiguration|By default, all analyzers are applied in order to cover all languages across your project, and only run if the language is detected in the Merge Request."
+msgstr ""
+
msgid "SecurityConfiguration|Configure"
msgstr ""
@@ -22197,16 +23031,19 @@ msgstr ""
msgid "SecurityConfiguration|Manage"
msgstr ""
+msgid "SecurityConfiguration|More information"
+msgstr ""
+
msgid "SecurityConfiguration|Not enabled"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|Security Control"
+msgid "SecurityConfiguration|SAST Configuration"
msgstr ""
-msgid "SecurityConfiguration|See documentation"
+msgid "SecurityConfiguration|Security Control"
msgstr ""
msgid "SecurityConfiguration|Status"
@@ -22218,6 +23055,9 @@ msgstr ""
msgid "SecurityConfiguration|Using custom settings. You won't receive automatic updates on this variable. %{anchorStart}Restore to default%{anchorEnd}"
msgstr ""
+msgid "SecurityConfiguration|View history"
+msgstr ""
+
msgid "SecurityConfiguration|You can quickly enable all security scanning tools by enabling %{linkStart}Auto DevOps%{linkEnd}."
msgstr ""
@@ -22296,9 +23136,6 @@ msgstr ""
msgid "SecurityReports|Learn more about setting up your dashboard"
msgstr ""
-msgid "SecurityReports|Load more vulnerabilities"
-msgstr ""
-
msgid "SecurityReports|Monitor vulnerabilities in your code"
msgstr ""
@@ -22578,7 +23415,7 @@ msgstr ""
msgid "Select status"
msgstr ""
-msgid "Select strategy activation method"
+msgid "Select strategy activation method."
msgstr ""
msgid "Select subscription"
@@ -22593,7 +23430,7 @@ msgstr ""
msgid "Select the custom project template source group."
msgstr ""
-msgid "Select timeframe"
+msgid "Select the environment scope for this feature flag."
msgstr ""
msgid "Select timezone"
@@ -22842,6 +23679,9 @@ msgstr ""
msgid "Set iteration"
msgstr ""
+msgid "Set limit to 0 to allow any file size."
+msgstr ""
+
msgid "Set max session time for web terminal."
msgstr ""
@@ -22920,10 +23760,13 @@ msgstr ""
msgid "Set up a %{type} Runner manually"
msgstr ""
+msgid "Set up a hardware device as a second factor to sign in."
+msgstr ""
+
msgid "Set up assertions/attributes/claims (email, first_name, last_name) and NameID according to %{docsLinkStart}the documentation %{icon}%{docsLinkEnd}"
msgstr ""
-msgid "Set up new U2F device"
+msgid "Set up new device"
msgstr ""
msgid "Set up new password"
@@ -22992,6 +23835,9 @@ msgstr ""
msgid "Sets weight to %{weight}."
msgstr ""
+msgid "Setting this to 0 means using the system default timeout value."
+msgstr ""
+
msgid "Settings"
msgstr ""
@@ -23007,6 +23853,15 @@ msgstr ""
msgid "Severity"
msgstr ""
+msgid "SeverityWidget|Severity"
+msgstr ""
+
+msgid "SeverityWidget|Severity: %{severity}"
+msgstr ""
+
+msgid "SeverityWidget|There was an error while updating severity."
+msgstr ""
+
msgid "Shards (%{shards})"
msgstr ""
@@ -23052,6 +23907,9 @@ msgstr ""
msgid "Show all requirements."
msgstr ""
+msgid "Show all test cases."
+msgstr ""
+
msgid "Show archived projects"
msgstr ""
@@ -23064,6 +23922,9 @@ msgstr ""
msgid "Show comments"
msgstr ""
+msgid "Show comments on this file"
+msgstr ""
+
msgid "Show comments only"
msgstr ""
@@ -23109,6 +23970,12 @@ msgstr ""
msgid "Show parent subgroups"
msgstr ""
+msgid "Show the Closed list"
+msgstr ""
+
+msgid "Show the Open list"
+msgstr ""
+
msgid "Show whitespace changes"
msgstr ""
@@ -23156,9 +24023,6 @@ msgstr ""
msgid "Sidebar|Assign health status"
msgstr ""
-msgid "Sidebar|Change weight"
-msgstr ""
-
msgid "Sidebar|Health status"
msgstr ""
@@ -23342,6 +24206,9 @@ msgstr ""
msgid "Snippets|Add another file %{num}/%{total}"
msgstr ""
+msgid "Snippets|Authored %{time_ago} by %{author}"
+msgstr ""
+
msgid "Snippets|Delete file"
msgstr ""
@@ -23369,6 +24236,9 @@ msgstr ""
msgid "Solution"
msgstr ""
+msgid "Some changes are not shown"
+msgstr ""
+
msgid "Some child epics may be hidden due to applied filters"
msgstr ""
@@ -23735,6 +24605,12 @@ msgstr ""
msgid "Source (branch or tag)"
msgstr ""
+msgid "Source Branch"
+msgstr ""
+
+msgid "Source branch: %{source_branch_open}%{source_branch}%{source_branch_close}"
+msgstr ""
+
msgid "Source code"
msgstr ""
@@ -23900,9 +24776,6 @@ msgstr ""
msgid "Start and due date"
msgstr ""
-msgid "Start by choosing a group to see how your team is spending time. You can then drill down to the project level."
-msgstr ""
-
msgid "Start by choosing a group to start exploring the merge requests in that group. You can then proceed to filter by projects, labels, milestones and authors."
msgstr ""
@@ -23984,18 +24857,27 @@ msgstr ""
msgid "StaticSiteEditor|3. Assign a person to review and accept the merge request."
msgstr ""
+msgid "StaticSiteEditor|A link to view the merge request will appear once ready."
+msgstr ""
+
msgid "StaticSiteEditor|An error occurred while submitting your changes."
msgstr ""
msgid "StaticSiteEditor|Branch could not be created."
msgstr ""
+msgid "StaticSiteEditor|Copy update"
+msgstr ""
+
msgid "StaticSiteEditor|Could not commit the content changes."
msgstr ""
msgid "StaticSiteEditor|Could not create merge request."
msgstr ""
+msgid "StaticSiteEditor|Creating your merge request"
+msgstr ""
+
msgid "StaticSiteEditor|Incompatible file content"
msgstr ""
@@ -24017,6 +24899,9 @@ msgstr ""
msgid "StaticSiteEditor|View documentation"
msgstr ""
+msgid "StaticSiteEditor|You can set an assignee to get your changes reviewed and deployed once your merge request is created."
+msgstr ""
+
msgid "StaticSiteEditor|Your merge request has been created"
msgstr ""
@@ -24146,15 +25031,15 @@ msgstr ""
msgid "Submit %{humanized_resource_name}"
msgstr ""
-msgid "Submit Changes"
-msgstr ""
-
msgid "Submit a review"
msgstr ""
msgid "Submit as spam"
msgstr ""
+msgid "Submit changes"
+msgstr ""
+
msgid "Submit feedback"
msgstr ""
@@ -24308,6 +25193,9 @@ msgstr ""
msgid "Successfully deleted U2F device."
msgstr ""
+msgid "Successfully deleted WebAuthn device."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -24626,9 +25514,6 @@ msgstr ""
msgid "Template to append to all Service Desk issues"
msgstr ""
-msgid "Template was successfully saved."
-msgstr ""
-
msgid "Templates"
msgstr ""
@@ -24713,10 +25598,28 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "Test failed."
+msgid "Test settings"
+msgstr ""
+
+msgid "TestCases|New Test Case"
+msgstr ""
+
+msgid "TestCases|New test case"
+msgstr ""
+
+msgid "TestCases|Search test cases"
+msgstr ""
+
+msgid "TestCases|Something went wrong while creating a test case."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching count of test cases."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching test cases list."
msgstr ""
-msgid "Test settings and save changes"
+msgid "TestCases|Submit test case"
msgstr ""
msgid "TestHooks|Ensure one of your projects has merge requests."
@@ -24782,6 +25685,9 @@ msgstr ""
msgid "Thank you for signing up for your free trial! You will get additional instructions in your inbox shortly."
msgstr ""
+msgid "Thank you for your business."
+msgstr ""
+
msgid "Thank you for your feedback!"
msgstr ""
@@ -24843,9 +25749,6 @@ msgstr ""
msgid "The URL to use for connecting to Elasticsearch. Use a comma-separated list to support clustering (e.g., \"http://localhost:9200, http://localhost:9201\")."
msgstr ""
-msgid "The Web IDE offers advanced syntax highlighting capabilities and more."
-msgstr ""
-
msgid "The X509 Certificate to use when mutual TLS is required to communicate with the external authorization service. If left blank, the server certificate is still validated when accessing over HTTPS."
msgstr ""
@@ -24958,6 +25861,9 @@ msgstr ""
msgid "The form contains the following error:"
msgstr ""
+msgid "The form contains the following warning:"
+msgstr ""
+
msgid "The global settings require you to enable Two-Factor Authentication for your account."
msgstr ""
@@ -25072,9 +25978,6 @@ msgstr ""
msgid "The private key to use when a client certificate is provided. This value is encrypted at rest."
msgstr ""
-msgid "The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The project can be accessed by any logged in user."
msgstr ""
@@ -25111,7 +26014,7 @@ msgstr ""
msgid "The remote repository is being updated..."
msgstr ""
-msgid "The repository can be commited to, and issues, comments and other entities can be created."
+msgid "The repository can be committed to, and issues, comments and other entities can be created."
msgstr ""
msgid "The repository for this project does not exist."
@@ -25165,9 +26068,6 @@ msgstr ""
msgid "The time taken by each data entry gathered by that stage."
msgstr ""
-msgid "The total stage shows the time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The update action will time out after %{number_of_minutes} minutes. For big repositories, use a clone/push combination."
msgstr ""
@@ -25231,6 +26131,9 @@ msgstr ""
msgid "There are no archived requirements"
msgstr ""
+msgid "There are no archived test cases"
+msgstr ""
+
msgid "There are no changes"
msgstr ""
@@ -25270,6 +26173,9 @@ msgstr ""
msgid "There are no open requirements"
msgstr ""
+msgid "There are no open test cases"
+msgstr ""
+
msgid "There are no packages yet"
msgstr ""
@@ -25282,6 +26188,9 @@ msgstr ""
msgid "There is a limit of %{ci_project_subscriptions_limit} subscriptions from or to a project."
msgstr ""
+msgid "There is already a To-Do for this design."
+msgstr ""
+
msgid "There is already a repository with that name on disk"
msgstr ""
@@ -25300,6 +26209,9 @@ msgstr ""
msgid "There was a problem communicating with your device."
msgstr ""
+msgid "There was a problem fetching branches."
+msgstr ""
+
msgid "There was a problem fetching groups."
msgstr ""
@@ -25528,9 +26440,15 @@ msgstr ""
msgid "This action can lead to data loss. To prevent accidental actions we ask you to confirm your intention."
msgstr ""
+msgid "This action cannot be undone, and will permanently delete the %{key} SSH key"
+msgstr ""
+
msgid "This action cannot be undone. You will lose the project's repository and all content: issues, merge requests, etc."
msgstr ""
+msgid "This action has been performed too many times. Try again later."
+msgstr ""
+
msgid "This action will %{strongOpen}permanently delete%{strongClose} %{codeOpen}%{project}%{codeClose} %{strongOpen}immediately%{strongClose}, including its repositories and all content: issues, merge requests, etc."
msgstr ""
@@ -25558,9 +26476,6 @@ msgstr ""
msgid "This board's scope is reduced"
msgstr ""
-msgid "This branch has changed since you started editing. Would you like to create a new branch?"
-msgstr ""
-
msgid "This chart could not be displayed"
msgstr ""
@@ -25687,15 +26602,9 @@ msgstr ""
msgid "This is a security log of important events involving your account."
msgstr ""
-msgid "This is the author's first Merge Request to this project."
-msgstr ""
-
msgid "This is the highest peak of users on your installation since the license started."
msgstr ""
-msgid "This is the maximum number of users that have existed at the same time since the license started. This is the minimum number of seats you will need to buy when you renew your license."
-msgstr ""
-
msgid "This is the number of currently active users on your installation, and this is the minimum number you need to purchase when you renew your license."
msgstr ""
@@ -25927,6 +26836,15 @@ msgstr ""
msgid "This user has no identities"
msgstr ""
+msgid "This user has previously committed to the %{name} project."
+msgstr ""
+
+msgid "This user has the %{access} role in the %{name} project."
+msgstr ""
+
+msgid "This user is the author of this %{noteable}."
+msgstr ""
+
msgid "This user will be the author of all events in the activity feed that are the result of an update, like new branches being created or new commits being pushed to existing branches."
msgstr ""
@@ -25957,6 +26875,9 @@ msgstr ""
msgid "Threat Monitoring"
msgstr ""
+msgid "ThreatMonitoring|All Environments"
+msgstr ""
+
msgid "ThreatMonitoring|Anomalous Requests"
msgstr ""
@@ -25984,9 +26905,6 @@ msgstr ""
msgid "ThreatMonitoring|Operations Per Second"
msgstr ""
-msgid "ThreatMonitoring|Overview"
-msgstr ""
-
msgid "ThreatMonitoring|Packet Activity"
msgstr ""
@@ -26005,6 +26923,9 @@ msgstr ""
msgid "ThreatMonitoring|Something went wrong, unable to fetch statistics"
msgstr ""
+msgid "ThreatMonitoring|Statistics"
+msgstr ""
+
msgid "ThreatMonitoring|The firewall is not installed or has been disabled. To view this data, ensure the web application firewall is installed and enabled for your cluster."
msgstr ""
@@ -26400,6 +27321,9 @@ msgstr ""
msgid "To update Snippets with multiple files, you must use the `files` parameter"
msgstr ""
+msgid "To use Gitpod you must first enable the feature in the integrations section of your %{user_prefs}."
+msgstr ""
+
msgid "To view all %{scannedResourcesCount} scanned URLs, please download the CSV file"
msgstr ""
@@ -26433,9 +27357,6 @@ msgstr ""
msgid "Toggle Sidebar"
msgstr ""
-msgid "Toggle all threads"
-msgstr ""
-
msgid "Toggle backtrace"
msgstr ""
@@ -26460,9 +27381,6 @@ msgstr ""
msgid "Toggle navigation"
msgstr ""
-msgid "Toggle project"
-msgstr ""
-
msgid "Toggle sidebar"
msgstr ""
@@ -26502,6 +27420,9 @@ msgstr ""
msgid "Too many projects enabled. You will need to manage them via the console or the API."
msgstr ""
+msgid "Too much data"
+msgstr ""
+
msgid "Topics (optional)"
msgstr ""
@@ -26520,6 +27441,9 @@ msgstr ""
msgid "Total cores (CPUs)"
msgstr ""
+msgid "Total days to completion"
+msgstr ""
+
msgid "Total issues"
msgstr ""
@@ -26616,6 +27540,9 @@ msgstr ""
msgid "Trending"
msgstr ""
+msgid "Trials|Create a new group to start your GitLab Gold trial."
+msgstr ""
+
msgid "Trials|Go back to GitLab"
msgstr ""
@@ -26625,6 +27552,15 @@ msgstr ""
msgid "Trials|You can always resume this process by selecting your avatar and choosing 'Start a Gold trial'"
msgstr ""
+msgid "Trials|You can apply your trial to a new group or an existing group."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group or your personal account."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group, an existing group, or your personal account."
+msgstr ""
+
msgid "Trials|You won't get a free trial right now but you can always resume this process by clicking on your avatar and choosing 'Start a free trial'"
msgstr ""
@@ -26694,6 +27630,9 @@ msgstr ""
msgid "Try using a different search term to find the file you are looking for."
msgstr ""
+msgid "Trying to communicate with your device. Plug it in (if needed) and press the button on the device now."
+msgstr ""
+
msgid "Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now."
msgstr ""
@@ -26781,6 +27720,12 @@ msgstr ""
msgid "URL or request ID"
msgstr ""
+msgid "USER %{user} WILL BE REMOVED! Are you sure?"
+msgstr ""
+
+msgid "USER WILL BE BLOCKED! Are you sure?"
+msgstr ""
+
msgid "UTC"
msgstr ""
@@ -26838,9 +27783,6 @@ msgstr ""
msgid "Unable to load the merge request widget. Try reloading the page."
msgstr ""
-msgid "Unable to resolve"
-msgstr ""
-
msgid "Unable to save iteration. Please try again"
msgstr ""
@@ -26889,6 +27831,9 @@ msgstr ""
msgid "Undo ignore"
msgstr ""
+msgid "Unexpected error"
+msgstr ""
+
msgid "Unfortunately, your email message to GitLab could not be processed."
msgstr ""
@@ -26922,6 +27867,9 @@ msgstr ""
msgid "Unknown response text"
msgstr ""
+msgid "Unless otherwise agreed to in writing with GitLab, by clicking \"Upload License\" you agree that your use of GitLab Software is subject to the %{eula_link_start}Terms of Service%{eula_link_end}."
+msgstr ""
+
msgid "Unlimited"
msgstr ""
@@ -27288,9 +28236,6 @@ msgstr ""
msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
msgstr ""
-msgid "Use a hardware device to add the second factor of authentication."
-msgstr ""
-
msgid "Use an one time password authenticator on your mobile device or computer to enable two-factor authentication (2FA)."
msgstr ""
@@ -27564,13 +28509,13 @@ msgstr ""
msgid "Users"
msgstr ""
-msgid "Users in License:"
+msgid "Users in License"
msgstr ""
-msgid "Users or groups set as approvers in the project's or merge request's settings."
+msgid "Users in License:"
msgstr ""
-msgid "Users outside of license"
+msgid "Users or groups set as approvers in the project's or merge request's settings."
msgstr ""
msgid "Users over License:"
@@ -27588,9 +28533,6 @@ msgstr ""
msgid "Users with a Guest role or those who don't belong to a Project or Group will not use a seat from your license."
msgstr ""
-msgid "Users with a Guest role or those who don't belong to any projects or groups don't count towards seats in use."
-msgstr ""
-
msgid "UsersSelect|%{name} + %{length} more"
msgstr ""
@@ -27630,9 +28572,6 @@ msgstr ""
msgid "Validations failed."
msgstr ""
-msgid "Validity"
-msgstr ""
-
msgid "Value"
msgstr ""
@@ -27651,6 +28590,9 @@ msgstr ""
msgid "Value Stream Name"
msgstr ""
+msgid "ValueStreamAnalyticsStage|We don't have enough data to show this stage."
+msgstr ""
+
msgid "ValueStreamAnalytics|%{days}d"
msgstr ""
@@ -27911,6 +28853,9 @@ msgstr ""
msgid "VisualReviewApp|Steps 1 and 2 (and sometimes 3) are performed once by the developer before requesting feedback. Steps 3 (if necessary), 4 is performed by the reviewer each time they perform a review."
msgstr ""
+msgid "Visualization"
+msgstr ""
+
msgid "Vulnerabilities"
msgstr ""
@@ -27938,34 +28883,31 @@ msgstr ""
msgid "VulnerabilityChart|Severity"
msgstr ""
-msgid "VulnerabilityManagement|A true-positive and will fix"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Change status"
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|Confirm"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Confirmed %{timeago} by %{user}"
-msgstr ""
-
-msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Detected %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|A true-positive and will fix"
msgstr ""
-msgid "VulnerabilityManagement|Dismiss"
+msgid "VulnerabilityManagement|Change status"
msgstr ""
-msgid "VulnerabilityManagement|Dismissed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
msgstr ""
-msgid "VulnerabilityManagement|Resolved"
+msgid "VulnerabilityManagement|Detected"
msgstr ""
-msgid "VulnerabilityManagement|Resolved %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Needs triage"
msgstr ""
msgid "VulnerabilityManagement|Something went wrong while trying to delete the comment. Please try again later."
@@ -28016,6 +28958,9 @@ msgstr ""
msgid "Vulnerability|%{scannerName} (version %{scannerVersion})"
msgstr ""
+msgid "Vulnerability|Activity"
+msgstr ""
+
msgid "Vulnerability|Class"
msgstr ""
@@ -28028,6 +28973,9 @@ msgstr ""
msgid "Vulnerability|Description"
msgstr ""
+msgid "Vulnerability|Detected"
+msgstr ""
+
msgid "Vulnerability|Evidence"
msgstr ""
@@ -28091,6 +29039,9 @@ msgstr ""
msgid "Warning: Displaying this diagram might cause performance issues on this page."
msgstr ""
+msgid "We are currently unable to fetch data for the pipeline header."
+msgstr ""
+
msgid "We are currently unable to fetch data for this graph."
msgstr ""
@@ -28130,6 +29081,12 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
+msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
+msgstr ""
+
+msgid "We would like to inform you that your subscription GitLab Enterprise Edition %{plan_name} is nearing its user limit. You have %{active_user_count} active users, which is almost at the user limit of %{maximum_user_count}."
+msgstr ""
+
msgid "We've found no vulnerabilities"
msgstr ""
@@ -28145,6 +29102,12 @@ msgstr ""
msgid "Web terminal"
msgstr ""
+msgid "WebAuthn Devices (%{length})"
+msgstr ""
+
+msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
+msgstr ""
+
msgid "WebIDE|Merge request"
msgstr ""
@@ -28283,15 +29246,9 @@ msgstr ""
msgid "Welcome to the guided GitLab tour"
msgstr ""
-msgid "Welcome to your Issue Board!"
-msgstr ""
-
msgid "Welcome to your issue board!"
msgstr ""
-msgid "We’ve been making changes to %{featureName} and we’d love your feedback %{linkStart}in this issue%{linkEnd} to help us improve the experience."
-msgstr ""
-
msgid "What are you searching for?"
msgstr ""
@@ -28310,6 +29267,9 @@ msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
msgstr ""
+msgid "When enabled, any user visiting %{host} and creating an account will have to be explicitly approved by the admin before they can login. This setting is effective only if sign-ups are enabled."
+msgstr ""
+
msgid "When enabled, any user visiting %{host} will be able to create an account."
msgstr ""
@@ -28536,6 +29496,9 @@ msgstr ""
msgid "With requirements, you can set criteria to check your products against."
msgstr ""
+msgid "With test cases, you can define conditions for your project to meet in determining quality"
+msgstr ""
+
msgid "Withdraw Access Request"
msgstr ""
@@ -28551,6 +29514,9 @@ msgstr ""
msgid "Workflow Help"
msgstr ""
+msgid "Would you like to create a new branch?"
+msgstr ""
+
msgid "Write"
msgstr ""
@@ -28572,6 +29538,9 @@ msgstr ""
msgid "Wrong extern UID provided. Make sure Auth0 is configured correctly."
msgstr ""
+msgid "YYYY-MM-DD"
+msgstr ""
+
msgid "Yes"
msgstr ""
@@ -28629,7 +29598,7 @@ msgstr ""
msgid "You are going to remove the fork relationship from %{project_full_name}. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "You are going to transfer %{project_full_name} to another owner. Are you ABSOLUTELY sure?"
+msgid "You are going to transfer %{project_full_name} to another namespace. Are you ABSOLUTELY sure?"
msgstr ""
msgid "You are going to turn off the confidentiality. This means %{strongStart}everyone%{strongEnd} will be able to see and leave a comment on this %{issuableType}."
@@ -28689,9 +29658,6 @@ msgstr ""
msgid "You can always edit this later"
msgstr ""
-msgid "You can apply your Trial to your Personal account or create a New Group."
-msgstr ""
-
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings"
msgstr ""
@@ -28713,12 +29679,18 @@ msgstr ""
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
+msgid "You can find more information about GitLab subscriptions in %{subscriptions_doc_link}."
+msgstr ""
+
msgid "You can generate an access token scoped to this project for each application to use the GitLab API."
msgstr ""
msgid "You can get started by cloning the repository or start adding files to it with one of the following options."
msgstr ""
+msgid "You can group test cases using labels. To learn about the future direction of this feature, visit %{linkStart}Quality Management direction page%{linkEnd}."
+msgstr ""
+
msgid "You can invite a new member to %{project_name} or invite another group."
msgstr ""
@@ -28734,6 +29706,9 @@ msgstr ""
msgid "You can notify the app / group or a project by sending them an email notification"
msgstr ""
+msgid "You can now close this window."
+msgstr ""
+
msgid "You can now export your security dashboard to a CSV report."
msgstr ""
@@ -28782,9 +29757,6 @@ msgstr ""
msgid "You can test your .gitlab-ci.yml in %{linkStart}CI Lint%{linkEnd}."
msgstr ""
-msgid "You can try again using %{begin_link}basic search%{end_link}"
-msgstr ""
-
msgid "You cannot access the raw file. Please wait a minute."
msgstr ""
@@ -28836,6 +29808,9 @@ msgstr ""
msgid "You don't have any U2F devices registered yet."
msgstr ""
+msgid "You don't have any WebAuthn devices registered yet."
+msgstr ""
+
msgid "You don't have any active chat names."
msgstr ""
@@ -28923,6 +29898,9 @@ msgstr ""
msgid "You must accept our Terms of Service and privacy policy in order to register an account"
msgstr ""
+msgid "You must be logged in to search across all of GitLab"
+msgstr ""
+
msgid "You must disassociate %{domain} from all clusters it is attached to before deletion."
msgstr ""
@@ -28962,7 +29940,7 @@ msgstr ""
msgid "You need to be logged in."
msgstr ""
-msgid "You need to register a two-factor authentication app before you can set up a U2F device."
+msgid "You need to register a two-factor authentication app before you can set up a device."
msgstr ""
msgid "You need to set terms to be enforced"
@@ -28980,6 +29958,9 @@ msgstr ""
msgid "You reached %{usage_in_percent} of %{namespace_name}'s storage capacity (%{used_storage} of %{storage_limit})"
msgstr ""
+msgid "You successfully declined the invitation"
+msgstr ""
+
msgid "You tried to fork %{link_to_the_project} but it failed for the following reason:"
msgstr ""
@@ -29145,10 +30126,13 @@ msgstr ""
msgid "Your U2F device did not send a valid JSON response."
msgstr ""
-msgid "Your U2F device needs to be set up. Plug it in (if not already) and click the button on the left."
+msgid "Your U2F device was registered!"
msgstr ""
-msgid "Your U2F device was registered!"
+msgid "Your WebAuthn device did not send a valid JSON response."
+msgstr ""
+
+msgid "Your WebAuthn device was registered!"
msgstr ""
msgid "Your access request to the %{source_type} has been withdrawn."
@@ -29172,6 +30156,9 @@ msgstr ""
msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
msgstr ""
+msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
+msgstr ""
+
msgid "Your changes can be committed to %{branch_name} because a merge request is open."
msgstr ""
@@ -29208,6 +30195,12 @@ msgstr ""
msgid "Your deployment services will be broken, you will need to manually fix the services after renaming."
msgstr ""
+msgid "Your device is not compatible with GitLab. Please try another device"
+msgstr ""
+
+msgid "Your device needs to be set up. Plug it in (if needed) and click the button on the left."
+msgstr ""
+
msgid "Your device was successfully set up! Give it a name and register it with the GitLab server."
msgstr ""
@@ -29323,9 +30316,6 @@ msgstr[3] ""
msgid "access:"
msgstr ""
-msgid "activated"
-msgstr ""
-
msgid "added %{created_at_timeago}"
msgstr ""
@@ -29398,9 +30388,21 @@ msgstr ""
msgid "by %{user}"
msgstr ""
+msgid "cannot be a date in the past"
+msgstr ""
+
msgid "cannot be changed if a personal project has container registry tags."
msgstr ""
+msgid "cannot be changed if shared runners are enabled"
+msgstr ""
+
+msgid "cannot be enabled because parent group does not allow it"
+msgstr ""
+
+msgid "cannot be enabled because parent group has shared Runners disabled"
+msgstr ""
+
msgid "cannot be enabled unless all domains have TLS certificates"
msgstr ""
@@ -29446,7 +30448,7 @@ msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about SAST %{linkEndTag}"
msgstr ""
-msgid "ciReport|%{linkStartTag}Learn more about Secret Scanning %{linkEndTag}"
+msgid "ciReport|%{linkStartTag}Learn more about Secret Detection %{linkEndTag}"
msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about codequality reports %{linkEndTag}"
@@ -29767,9 +30769,6 @@ msgstr ""
msgid "error"
msgstr ""
-msgid "error code:"
-msgstr ""
-
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr ""
@@ -29791,6 +30790,9 @@ msgstr ""
msgid "failed to dismiss associated finding(id=%{finding_id}): %{message}"
msgstr ""
+msgid "failed to revert associated finding(id=%{finding_id}) to detected"
+msgstr ""
+
msgid "file"
msgid_plural "files"
msgstr[0] ""
@@ -30341,6 +31343,9 @@ msgstr ""
msgid "must be a root namespace"
msgstr ""
+msgid "must be a valid IPv4 or IPv6 address"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -30377,6 +31382,9 @@ msgstr ""
msgid "no expiration"
msgstr ""
+msgid "no name set"
+msgstr ""
+
msgid "no one can merge"
msgstr ""
@@ -30565,9 +31573,6 @@ msgstr ""
msgid "security Reports|There was an error creating the merge request"
msgstr ""
-msgid "settings saved, but not activated"
-msgstr ""
-
msgid "severity|Critical"
msgstr ""
@@ -30694,9 +31699,6 @@ msgstr ""
msgid "toggle collapse"
msgstr ""
-msgid "toggle dropdown"
-msgstr ""
-
msgid "triggered"
msgstr ""
@@ -30724,6 +31726,9 @@ msgstr ""
msgid "user avatar"
msgstr ""
+msgid "user preferences"
+msgstr ""
+
msgid "username"
msgstr ""
diff --git a/locale/mn_MN/gitlab.po b/locale/mn_MN/gitlab.po
index f12bae24baf..030ac1308e7 100644
--- a/locale/mn_MN/gitlab.po
+++ b/locale/mn_MN/gitlab.po
@@ -14,7 +14,10 @@ msgstr ""
"X-Crowdin-Language: mn\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 6\n"
-"PO-Revision-Date: 2020-09-04 23:09\n"
+"PO-Revision-Date: 2020-10-02 18:48\n"
+
+msgid " %{project_name}#%{issue_iid} &middot; opened %{issue_created} by %{author}"
+msgstr ""
msgid " %{start} to %{end}"
msgstr ""
@@ -74,6 +77,16 @@ msgstr ""
msgid "\"el\" parameter is required for createInstance()"
msgstr ""
+msgid "%d Approval"
+msgid_plural "%d Approvals"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d Package"
+msgid_plural "%d Packages"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d Scanned URL"
msgid_plural "%d Scanned URLs"
msgstr[0] ""
@@ -137,6 +150,11 @@ msgstr[1] ""
msgid "%d commits"
msgstr ""
+msgid "%d completed issue"
+msgid_plural "%d completed issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d contribution"
msgid_plural "%d contributions"
msgstr[0] ""
@@ -147,6 +165,11 @@ msgid_plural "%d days"
msgstr[0] ""
msgstr[1] ""
+msgid "%d day until tags are automatically removed"
+msgid_plural "%d days until tags are automatically removed"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d error"
msgid_plural "%d errors"
msgstr[0] ""
@@ -237,6 +260,16 @@ msgid_plural "%d more comments"
msgstr[0] ""
msgstr[1] ""
+msgid "%d open issue"
+msgid_plural "%d open issues"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d pending comment"
+msgid_plural "%d pending comments"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d personal project will be removed and cannot be restored."
msgid_plural "%d personal projects will be removed and cannot be restored."
msgstr[0] ""
@@ -252,6 +285,11 @@ msgid_plural "%d projects"
msgstr[0] ""
msgstr[1] ""
+msgid "%d project selected"
+msgid_plural "%d projects selected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d request with warnings"
msgid_plural "%d requests with warnings"
msgstr[0] ""
@@ -272,6 +310,11 @@ msgid_plural "%d tags"
msgstr[0] ""
msgstr[1] ""
+msgid "%d tag per image name"
+msgid_plural "%d tags per image name"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d unassigned issue"
msgid_plural "%d unassigned issues"
msgstr[0] ""
@@ -292,6 +335,11 @@ msgid_plural "%d vulnerabilities dismissed"
msgstr[0] ""
msgstr[1] ""
+msgid "%d warning found:"
+msgid_plural "%d warnings found:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%s additional commit has been omitted to prevent performance issues."
msgid_plural "%s additional commits have been omitted to prevent performance issues."
msgstr[0] ""
@@ -330,6 +378,9 @@ msgstr ""
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr ""
+msgid "%{completedCount} completed weight"
+msgstr ""
+
msgid "%{completedWeight} of %{totalWeight} weight completed"
msgstr ""
@@ -378,14 +429,12 @@ msgid_plural "%{count} participants"
msgstr[0] ""
msgstr[1] ""
-msgid "%{count} pending comment"
-msgid_plural "%{count} pending comments"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
+msgid "%{count} total weight"
+msgstr ""
+
msgid "%{dashboard_path} could not be found."
msgstr ""
@@ -440,6 +489,9 @@ msgstr ""
msgid "%{group_name} uses group managed accounts. You need to create a new GitLab account which will be managed by %{group_name}."
msgstr ""
+msgid "%{group_name}&%{epic_iid} &middot; opened %{epic_created} by %{author}"
+msgstr ""
+
msgid "%{host} sign-in from new location"
msgstr ""
@@ -452,7 +504,7 @@ msgstr ""
msgid "%{issuableType} will be removed! Are you sure?"
msgstr ""
-msgid "%{issuesSize} issues with a limit of %{maxIssueCount}"
+msgid "%{issuesCount} issues with a limit of %{maxIssueCount}"
msgstr ""
msgid "%{issuesSize} with a limit of %{maxIssueCount}"
@@ -485,7 +537,7 @@ msgstr ""
msgid "%{labelStart}Namespace:%{labelEnd} %{namespace}"
msgstr ""
-msgid "%{labelStart}Report Type:%{labelEnd} %{reportType}"
+msgid "%{labelStart}Scan Type:%{labelEnd} %{reportType}"
msgstr ""
msgid "%{labelStart}Scanner:%{labelEnd} %{scanner}"
@@ -682,9 +734,6 @@ msgid_plural "%{securityScanner} results are not available because a pipeline ha
msgstr[0] ""
msgstr[1] ""
-msgid "%{service_title} %{message}."
-msgstr ""
-
msgid "%{size} GiB"
msgstr ""
@@ -773,6 +822,12 @@ msgstr ""
msgid "%{timebox_name} should belong either to a project or a group."
msgstr ""
+msgid "%{timebox_type} does not support burnup charts"
+msgstr ""
+
+msgid "%{timebox_type} must have a start and due date"
+msgstr ""
+
msgid "%{title} %{operator} %{threshold}"
msgstr ""
@@ -797,7 +852,7 @@ msgstr ""
msgid "%{total} open issue weight"
msgstr ""
-msgid "%{total} open issues"
+msgid "%{total} warnings found: showing first %{warningsDisplayed}"
msgstr ""
msgid "%{usage_ping_link_start}Learn more%{usage_ping_link_end} about what information is shared with GitLab Inc."
@@ -830,9 +885,6 @@ msgstr ""
msgid "&lt; 1 hour"
msgstr ""
-msgid "&lt;no name set&gt;"
-msgstr ""
-
msgid "&lt;no scopes selected&gt;"
msgstr ""
@@ -863,6 +915,9 @@ msgstr ""
msgid "'%{name}' Value Stream created"
msgstr ""
+msgid "'%{name}' Value Stream deleted"
+msgstr ""
+
msgid "'%{name}' stage already exists"
msgstr ""
@@ -922,6 +977,9 @@ msgstr ""
msgid "+ %{numberOfHiddenAssignees} more"
msgstr ""
+msgid "+ %{numberOfHiddenReviewers} more"
+msgstr ""
+
msgid "+%d more"
msgid_plural "+%d more"
msgstr[0] ""
@@ -982,6 +1040,11 @@ msgid_plural "%d Days"
msgstr[0] ""
msgstr[1] ""
+msgid "1 Issue"
+msgid_plural "%d Issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "1 closed issue"
msgid_plural "%{issues} closed issues"
msgstr[0] ""
@@ -997,6 +1060,11 @@ msgid_plural "%d days"
msgstr[0] ""
msgstr[1] ""
+msgid "1 deploy key"
+msgid_plural "%d deploy keys"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1099,6 +1167,9 @@ msgstr ""
msgid ":%{startLine} to %{endLine}"
msgstr ""
+msgid "A %{incident_docs_start}modified issue%{incident_docs_end} to guide the resolution of incidents."
+msgstr ""
+
msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr ""
@@ -1111,6 +1182,9 @@ msgstr ""
msgid "A GitBook site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
+msgid "A Gitpod configured Webapplication in Spring and Java"
+msgstr ""
+
msgid "A Hexo site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
@@ -1282,9 +1356,15 @@ msgstr ""
msgid "Access expiration date"
msgstr ""
+msgid "Access expires"
+msgstr ""
+
msgid "Access forbidden. Check your access level."
msgstr ""
+msgid "Access granted"
+msgstr ""
+
msgid "Access requests"
msgstr ""
@@ -1294,6 +1374,9 @@ msgstr ""
msgid "Access to Pages websites are controlled based on the user's membership to a given project. By checking this box, users will be required to be logged in to have access to all Pages websites in your instance."
msgstr ""
+msgid "AccessDropdown|Deploy Keys"
+msgstr ""
+
msgid "AccessDropdown|Groups"
msgstr ""
@@ -1411,12 +1494,6 @@ msgstr ""
msgid "Active Sessions"
msgstr ""
-msgid "Active Users:"
-msgstr ""
-
-msgid "Active users"
-msgstr ""
-
msgid "Activity"
msgstr ""
@@ -1584,9 +1661,6 @@ msgstr ""
msgid "Add label(s)"
msgstr ""
-msgid "Add license"
-msgstr ""
-
msgid "Add list"
msgstr ""
@@ -1761,21 +1835,51 @@ msgstr ""
msgid "AdminArea|Bots"
msgstr ""
+msgid "AdminArea|Components"
+msgstr ""
+
msgid "AdminArea|Developer"
msgstr ""
+msgid "AdminArea|Features"
+msgstr ""
+
+msgid "AdminArea|Groups: %{number_of_groups}"
+msgstr ""
+
msgid "AdminArea|Guest"
msgstr ""
msgid "AdminArea|Included Free in license"
msgstr ""
+msgid "AdminArea|Latest groups"
+msgstr ""
+
+msgid "AdminArea|Latest projects"
+msgstr ""
+
+msgid "AdminArea|Latest users"
+msgstr ""
+
msgid "AdminArea|Maintainer"
msgstr ""
+msgid "AdminArea|New group"
+msgstr ""
+
+msgid "AdminArea|New project"
+msgstr ""
+
+msgid "AdminArea|New user"
+msgstr ""
+
msgid "AdminArea|Owner"
msgstr ""
+msgid "AdminArea|Projects: %{number_of_projects}"
+msgstr ""
+
msgid "AdminArea|Reporter"
msgstr ""
@@ -1803,6 +1907,9 @@ msgstr ""
msgid "AdminArea|Users without a Group and Project"
msgstr ""
+msgid "AdminArea|Users: %{number_of_users}"
+msgstr ""
+
msgid "AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running."
msgstr ""
@@ -1821,9 +1928,6 @@ msgstr ""
msgid "AdminProjects|Delete Project %{projectName}?"
msgstr ""
-msgid "AdminProjects|Delete project"
-msgstr ""
-
msgid "AdminSettings|Apply integration settings to all Projects"
msgstr ""
@@ -2061,21 +2165,30 @@ msgstr ""
msgid "AdminUsers|Without projects"
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 ""
msgid "AdminUsers|You cannot remove your own admin rights."
msgstr ""
+msgid "AdminUsers|You must transfer ownership or delete the groups owned by this user before you can delete their account"
+msgstr ""
+
msgid "Administration"
msgstr ""
msgid "Advanced"
msgstr ""
+msgid "Advanced Search"
+msgstr ""
+
+msgid "Advanced Search with Elasticsearch"
+msgstr ""
+
msgid "Advanced Settings"
msgstr ""
@@ -2153,6 +2266,9 @@ msgstr ""
msgid "AlertManagement|Edit"
msgstr ""
+msgid "AlertManagement|Environment"
+msgstr ""
+
msgid "AlertManagement|Events"
msgstr ""
@@ -2165,6 +2281,9 @@ msgstr ""
msgid "AlertManagement|Issue"
msgstr ""
+msgid "AlertManagement|Key"
+msgstr ""
+
msgid "AlertManagement|Low"
msgstr ""
@@ -2258,6 +2377,9 @@ msgstr ""
msgid "AlertManagement|Unknown"
msgstr ""
+msgid "AlertManagement|Value"
+msgstr ""
+
msgid "AlertManagement|View alerts in Opsgenie"
msgstr ""
@@ -2417,6 +2539,9 @@ msgstr ""
msgid "All projects"
msgstr ""
+msgid "All projects selected"
+msgstr ""
+
msgid "All security scans are enabled because %{linkStart}Auto DevOps%{linkEnd} is enabled on this project"
msgstr ""
@@ -2504,6 +2629,9 @@ msgstr ""
msgid "Almost there"
msgstr ""
+msgid "Already blocked"
+msgstr ""
+
msgid "Also called \"Issuer\" or \"Relying party trust identifier\""
msgstr ""
@@ -2558,6 +2686,9 @@ msgstr ""
msgid "An error has occurred"
msgstr ""
+msgid "An error occured while making the changes: %{error}"
+msgstr ""
+
msgid "An error occurred adding a draft to the thread."
msgstr ""
@@ -2585,12 +2716,6 @@ msgstr ""
msgid "An error occurred when toggling the notification subscription"
msgstr ""
-msgid "An error occurred when trying to resolve a comment. Please try again."
-msgstr ""
-
-msgid "An error occurred when trying to resolve a discussion. Please try again."
-msgstr ""
-
msgid "An error occurred when updating the issue weight"
msgstr ""
@@ -2606,12 +2731,6 @@ msgstr ""
msgid "An error occurred while checking group path. Please refresh and try again."
msgstr ""
-msgid "An error occurred while committing your changes."
-msgstr ""
-
-msgid "An error occurred while creating the list. Please try again."
-msgstr ""
-
msgid "An error occurred while decoding the file."
msgstr ""
@@ -2684,25 +2803,19 @@ msgstr ""
msgid "An error occurred while fetching the Service Desk address."
msgstr ""
-msgid "An error occurred while fetching the board issues. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the board lists. Please reload the page."
msgstr ""
msgid "An error occurred while fetching the board lists. Please try again."
msgstr ""
-msgid "An error occurred while fetching the board swimlanes. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the builds."
msgstr ""
msgid "An error occurred while fetching the job log."
msgstr ""
-msgid "An error occurred while fetching the job trace."
+msgid "An error occurred while fetching the job logs."
msgstr ""
msgid "An error occurred while fetching the job."
@@ -2849,9 +2962,6 @@ msgstr ""
msgid "An error occurred while saving assignees"
msgstr ""
-msgid "An error occurred while saving the template. Please check if the template exists."
-msgstr ""
-
msgid "An error occurred while searching for milestones"
msgstr ""
@@ -2870,10 +2980,10 @@ msgstr ""
msgid "An error occurred while updating approvers"
msgstr ""
-msgid "An error occurred while updating the comment"
+msgid "An error occurred while updating labels."
msgstr ""
-msgid "An error occurred while updating the list. Please try again."
+msgid "An error occurred while updating the comment"
msgstr ""
msgid "An error occurred while validating group path"
@@ -2927,6 +3037,9 @@ msgstr ""
msgid "An unknown error occurred while loading this graph."
msgstr ""
+msgid "An unknown error occurred."
+msgstr ""
+
msgid "Analytics"
msgstr ""
@@ -2960,10 +3073,10 @@ msgstr ""
msgid "Any"
msgstr ""
-msgid "Any Author"
+msgid "Any %{header}"
msgstr ""
-msgid "Any Status"
+msgid "Any Author"
msgstr ""
msgid "Any branch"
@@ -3017,6 +3130,9 @@ msgstr ""
msgid "Application ID"
msgstr ""
+msgid "Application limits saved successfully"
+msgstr ""
+
msgid "Application settings saved successfully"
msgstr ""
@@ -3226,6 +3342,9 @@ msgstr ""
msgid "Are you sure you want to close this blocked issue?"
msgstr ""
+msgid "Are you sure you want to delete \"%{name}\" Value Stream?"
+msgstr ""
+
msgid "Are you sure you want to delete %{name}?"
msgstr ""
@@ -3235,6 +3354,9 @@ msgstr ""
msgid "Are you sure you want to delete this %{typeOfComment}?"
msgstr ""
+msgid "Are you sure you want to delete this SSH key?"
+msgstr ""
+
msgid "Are you sure you want to delete this board?"
msgstr ""
@@ -3259,6 +3381,11 @@ msgstr ""
msgid "Are you sure you want to erase this build?"
msgstr ""
+msgid "Are you sure you want to import %d repository?"
+msgid_plural "Are you sure you want to import %d repositories?"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Are you sure you want to lose unsaved changes?"
msgstr ""
@@ -3268,15 +3395,15 @@ msgstr ""
msgid "Are you sure you want to merge immediately?"
msgstr ""
-msgid "Are you sure you want to permanently delete this license?"
-msgstr ""
-
msgid "Are you sure you want to re-deploy this environment?"
msgstr ""
msgid "Are you sure you want to regenerate the public key? You will have to update the public key on the remote server before mirroring will work again."
msgstr ""
+msgid "Are you sure you want to reindex?"
+msgstr ""
+
msgid "Are you sure you want to remove %{group_name}?"
msgstr ""
@@ -3304,6 +3431,9 @@ msgstr ""
msgid "Are you sure you want to revoke this nickname?"
msgstr ""
+msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
+msgstr ""
+
msgid "Are you sure you want to stop this environment?"
msgstr ""
@@ -3325,6 +3455,9 @@ msgstr ""
msgid "Are you sure? The device will be signed out of GitLab and all remember me tokens revoked."
msgstr ""
+msgid "Are you sure? This will invalidate your registered applications and U2F / WebAuthn devices."
+msgstr ""
+
msgid "Are you sure? This will invalidate your registered applications and U2F devices."
msgstr ""
@@ -3343,9 +3476,6 @@ msgstr ""
msgid "Artifacts"
msgstr ""
-msgid "As U2F devices are only supported by a few browsers, we require that you set up a two-factor authentication app before a U2F device. That way you'll always be able to log in - even when you're using an unsupported browser."
-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 ""
@@ -3539,6 +3669,9 @@ msgstr ""
msgid "AuditLogs|Target"
msgstr ""
+msgid "AuditLogs|This month"
+msgstr ""
+
msgid "AuditLogs|User Events"
msgstr ""
@@ -3578,6 +3711,9 @@ msgstr ""
msgid "Authentication via U2F device failed."
msgstr ""
+msgid "Authentication via WebAuthn device failed."
+msgstr ""
+
msgid "Author"
msgstr ""
@@ -3845,15 +3981,6 @@ msgstr ""
msgid "BambooService|You must set up automatic revision labeling and a repository trigger in Bamboo."
msgstr ""
-msgid "BatchComments|Delete all pending comments"
-msgstr ""
-
-msgid "BatchComments|Discard review?"
-msgstr ""
-
-msgid "BatchComments|You're about to discard your review which will delete all of your pending comments. The deleted comments %{strong_start}cannot%{strong_end} be restored."
-msgstr ""
-
msgid "Be careful. Changing the project's namespace can have unintended side effects."
msgstr ""
@@ -3875,6 +4002,9 @@ msgstr ""
msgid "Bi-weekly code coverage"
msgstr ""
+msgid "Billable Users:"
+msgstr ""
+
msgid "Billing"
msgstr ""
@@ -3884,7 +4014,7 @@ msgstr ""
msgid "BillingPlans|@%{user_name} you are currently using the %{plan_name} plan."
msgstr ""
-msgid "BillingPlans|Congratulations, your new trial is activated"
+msgid "BillingPlans|Congratulations, your free trial is activated."
msgstr ""
msgid "BillingPlans|If you would like to downgrade your plan please contact %{support_link_start}Customer Support%{support_link_end}."
@@ -3947,6 +4077,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Block user"
+msgstr ""
+
msgid "Blocked"
msgstr ""
@@ -3962,31 +4095,37 @@ msgstr ""
msgid "Blog"
msgstr ""
-msgid "Board name"
-msgstr ""
-
msgid "Board scope"
msgstr ""
msgid "Board scope affects which issues are displayed for anyone who visits this board"
msgstr ""
-msgid "BoardBlankState|Add default lists"
+msgid "Boards"
msgstr ""
-msgid "BoardBlankState|Add the following default lists to your Issue Board with one click:"
+msgid "Boards and Board Lists"
msgstr ""
-msgid "BoardBlankState|Nevermind, I'll use my own"
+msgid "Boards|An error occurred while creating the issue. Please try again."
msgstr ""
-msgid "BoardBlankState|Starting out with the default set of lists will get you right on the way to making the most of your board."
+msgid "Boards|An error occurred while creating the list. Please try again."
msgstr ""
-msgid "Boards"
+msgid "Boards|An error occurred while fetching issues. Please reload the page."
msgstr ""
-msgid "Boards and Board Lists"
+msgid "Boards|An error occurred while fetching the board issues. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching the board swimlanes. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while moving the issue. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while updating the list. Please try again."
msgstr ""
msgid "Boards|Collapse"
@@ -4013,7 +4152,7 @@ msgstr ""
msgid "Branch %{branch_name} was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr ""
-msgid "Branch has changed"
+msgid "Branch changed"
msgstr ""
msgid "Branch is already taken"
@@ -4319,6 +4458,9 @@ msgstr ""
msgid "CLOSED (MOVED)"
msgstr ""
+msgid "CODEOWNERS rule violation"
+msgstr ""
+
msgid "CONTRIBUTING"
msgstr ""
@@ -4349,9 +4491,6 @@ msgstr ""
msgid "Can't create snippet: %{err}"
msgstr ""
-msgid "Can't edit as source branch was deleted"
-msgstr ""
-
msgid "Can't fetch content for the blob: %{err}"
msgstr ""
@@ -4364,9 +4503,6 @@ msgstr ""
msgid "Can't load mermaid module: %{err}"
msgstr ""
-msgid "Can't remove group members without group managed account"
-msgstr ""
-
msgid "Can't scan the code?"
msgstr ""
@@ -4409,6 +4545,9 @@ msgstr ""
msgid "Cannot create the abuse report. This user has been blocked."
msgstr ""
+msgid "Cannot enable shared runners because parent group does not allow it"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -4514,6 +4653,15 @@ msgstr ""
msgid "Change your password or recover your current one"
msgstr ""
+msgid "ChangeReviewer|Reviewer changed from %{old} to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Reviewer changed to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Unassigned"
+msgstr ""
+
msgid "ChangeTypeActionLabel|Pick into branch"
msgstr ""
@@ -4553,6 +4701,9 @@ msgstr ""
msgid "Changes the title to \"%{title_param}\"."
msgstr ""
+msgid "Changes were successfully made."
+msgstr ""
+
msgid "Changes won't take place until the index is %{link_start}recreated%{link_end}."
msgstr ""
@@ -4958,6 +5109,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove variable"
+msgstr ""
+
msgid "CiVariables|Remove variable row"
msgstr ""
@@ -5036,9 +5190,6 @@ msgstr ""
msgid "Clear due date"
msgstr ""
-msgid "Clear input"
-msgstr ""
-
msgid "Clear recent searches"
msgstr ""
@@ -5087,6 +5238,9 @@ msgstr ""
msgid "Client authentication key password"
msgstr ""
+msgid "Client request timeout"
+msgstr ""
+
msgid "Clients"
msgstr ""
@@ -5171,6 +5325,27 @@ msgstr ""
msgid "Cluster type must be specificed for Stages::ClusterEndpointInserter"
msgstr ""
+msgid "ClusterAgents|Configuration"
+msgstr ""
+
+msgid "ClusterAgents|Connect your cluster with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate Kubernetes with a GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Name"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Agent also requires %{linkStart}enabling the Agent Server%{linkEnd}"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Kubernetes Agent allows an Infrastructure as Code, GitOps approach to integrating Kubernetes clusters with GitLab. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "ClusterAgent|This feature is only available for premium plans"
msgstr ""
@@ -5240,10 +5415,10 @@ msgstr ""
msgid "ClusterIntegration|All installed applications and related resources"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster."
+msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{linkStart}More information%{linkEnd}"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{startLink}More information%{endLink}"
+msgid "ClusterIntegration|Allow GitLab to manage namespaces and service accounts for this cluster."
msgstr ""
msgid "ClusterIntegration|Alternatively, "
@@ -5264,6 +5439,9 @@ msgstr ""
msgid "ClusterIntegration|An error occurred while trying to fetch zone machine types: %{error}"
msgstr ""
+msgid "ClusterIntegration|An unknown error occurred while attempting to connect to Kubernetes."
+msgstr ""
+
msgid "ClusterIntegration|Any project namespaces"
msgstr ""
@@ -5279,6 +5457,9 @@ msgstr ""
msgid "ClusterIntegration|Authenticate with Amazon Web Services"
msgstr ""
+msgid "ClusterIntegration|Authentication Error"
+msgstr ""
+
msgid "ClusterIntegration|Base domain"
msgstr ""
@@ -5297,13 +5478,22 @@ msgstr ""
msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}security group %{externalLinkIcon} %{endLink} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
+msgid "ClusterIntegration|Check your CA certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Check your cluster status"
+msgstr ""
+
+msgid "ClusterIntegration|Check your token"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}subnets %{externalLinkIcon} %{endLink} in your VPC where your worker nodes will run."
+msgid "ClusterIntegration|Choose the %{linkStart}security group %{linkEnd} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
msgstr ""
-msgid "ClusterIntegration|Choose the worker node %{startLink}instance type %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Choose the %{linkStart}subnets %{linkEnd} in your VPC where your worker nodes will run."
+msgstr ""
+
+msgid "ClusterIntegration|Choose the worker node %{linkStart}instance type%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Choose which applications to install on your Kubernetes cluster."
@@ -5315,10 +5505,7 @@ msgstr ""
msgid "ClusterIntegration|Clear cluster cache"
msgstr ""
-msgid "ClusterIntegration|Clear the local cache of namespace and service accounts. This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
-msgstr ""
-
-msgid "ClusterIntegration|Cluster being created"
+msgid "ClusterIntegration|Clear the local cache of namespace and service accounts."
msgstr ""
msgid "ClusterIntegration|Cluster management project (alpha)"
@@ -5330,15 +5517,21 @@ msgstr ""
msgid "ClusterIntegration|Cluster_applications artifact too big. Maximum allowable size: %{human_size}"
msgstr ""
-msgid "ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters."
+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|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}"
+msgid "ClusterIntegration|Clusters connected with a certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Connect cluster with certificate"
msgstr ""
msgid "ClusterIntegration|Connect existing cluster"
msgstr ""
+msgid "ClusterIntegration|Connection Error"
+msgstr ""
+
msgid "ClusterIntegration|Copy API URL"
msgstr ""
@@ -5414,6 +5607,12 @@ msgstr ""
msgid "ClusterIntegration|Deletes all GitLab resources attached to this cluster during removal"
msgstr ""
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared."
+msgstr ""
+
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared. %{linkStart}More information%{linkEnd}"
+msgstr ""
+
msgid "ClusterIntegration|Did you know?"
msgstr ""
@@ -5483,6 +5682,9 @@ msgstr ""
msgid "ClusterIntegration|Fluentd is an open source data collector, which lets you unify the data collection and consumption for a better use and understanding of data. It requires at least one of the following logs to be successfully installed."
msgstr ""
+msgid "ClusterIntegration|GitLab Agent managed clusters"
+msgstr ""
+
msgid "ClusterIntegration|GitLab Container Network Policies"
msgstr ""
@@ -5495,6 +5697,12 @@ msgstr ""
msgid "ClusterIntegration|GitLab Runner connects to the repository and executes CI/CD jobs, pushing results back and deploying applications to production."
msgstr ""
+msgid "ClusterIntegration|GitLab failed to authenticate."
+msgstr ""
+
+msgid "ClusterIntegration|GitLab failed to connect to the cluster."
+msgstr ""
+
msgid "ClusterIntegration|GitLab-managed cluster"
msgstr ""
@@ -5516,6 +5724,9 @@ msgstr ""
msgid "ClusterIntegration|Group cluster"
msgstr ""
+msgid "ClusterIntegration|HTTP Error"
+msgstr ""
+
msgid "ClusterIntegration|Helm Tiller"
msgstr ""
@@ -5549,7 +5760,10 @@ msgstr ""
msgid "ClusterIntegration|Instance type"
msgstr ""
-msgid "ClusterIntegration|Integrate Kubernetes cluster automation"
+msgid "ClusterIntegration|Integrate Kubernetes with a cluster certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Integrate with a cluster certificate"
msgstr ""
msgid "ClusterIntegration|Issuer Email"
@@ -5585,9 +5799,6 @@ msgstr ""
msgid "ClusterIntegration|Knative extends Kubernetes to provide a set of middleware components that are essential to build modern, source-centric, and container-based applications that can run anywhere: on premises, in the cloud, or even in a third-party data center."
msgstr ""
-msgid "ClusterIntegration|Kubernetes cluster"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes cluster is being created..."
msgstr ""
@@ -5600,9 +5811,6 @@ msgstr ""
msgid "ClusterIntegration|Kubernetes clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr ""
-msgid "ClusterIntegration|Kubernetes clusters can be used to deploy applications and to provide Review Apps for this project"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes version"
msgstr ""
@@ -5615,7 +5823,7 @@ msgstr ""
msgid "ClusterIntegration|Learn more about %{help_link_start}zones%{help_link_end}."
msgstr ""
-msgid "ClusterIntegration|Learn more about %{startLink}Regions %{externalLinkIcon}%{endLink}."
+msgid "ClusterIntegration|Learn more about %{linkStart}Regions%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Learn more about Kubernetes"
@@ -5660,12 +5868,18 @@ msgstr ""
msgid "ClusterIntegration|Machine type"
msgstr ""
+msgid "ClusterIntegration|Make sure your API endpoint is correct"
+msgstr ""
+
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create Kubernetes clusters"
msgstr ""
msgid "ClusterIntegration|Manage your Kubernetes cluster by visiting %{provider_link}"
msgstr ""
+msgid "ClusterIntegration|Namespace per environment"
+msgstr ""
+
msgid "ClusterIntegration|No IAM Roles found"
msgstr ""
@@ -5711,6 +5925,9 @@ msgstr ""
msgid "ClusterIntegration|No zones matched your search"
msgstr ""
+msgid "ClusterIntegration|Node calculations use the Kubernetes Metrics API. Make sure your cluster has metrics installed"
+msgstr ""
+
msgid "ClusterIntegration|Number of nodes"
msgstr ""
@@ -5753,6 +5970,9 @@ msgstr ""
msgid "ClusterIntegration|RBAC-enabled cluster"
msgstr ""
+msgid "ClusterIntegration|Read our %{linkStart}help page%{linkEnd} on Kubernetes cluster integration."
+msgstr ""
+
msgid "ClusterIntegration|Read our %{link_start}help page%{link_end} on Kubernetes cluster integration."
msgstr ""
@@ -5855,7 +6075,7 @@ msgstr ""
msgid "ClusterIntegration|Select a VPC to choose a subnet"
msgstr ""
-msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{linkStart}Amazon Web Services %{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select a network to choose a subnetwork"
@@ -5888,7 +6108,7 @@ msgstr ""
msgid "ClusterIntegration|Select project to choose zone"
msgstr ""
-msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select zone"
@@ -5978,9 +6198,18 @@ msgstr ""
msgid "ClusterIntegration|There was a problem authenticating with your cluster. Please ensure your CA Certificate and Token are valid."
msgstr ""
+msgid "ClusterIntegration|There was an HTTP error when connecting to your cluster."
+msgstr ""
+
msgid "ClusterIntegration|This account must have permissions to create a Kubernetes cluster in the %{link_to_container_project} specified below"
msgstr ""
+msgid "ClusterIntegration|This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
+msgstr ""
+
+msgid "ClusterIntegration|This is necessary to clear existing environment-namespace associations from clusters previously managed by GitLab."
+msgstr ""
+
msgid "ClusterIntegration|This option will allow you to install applications on RBAC clusters."
msgstr ""
@@ -6005,9 +6234,21 @@ msgstr ""
msgid "ClusterIntegration|To use a new project, first create one on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}."
msgstr ""
+msgid "ClusterIntegration|Troubleshooting tips:"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Authenticate"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Connect"
+msgstr ""
+
msgid "ClusterIntegration|Uninstall %{appTitle}"
msgstr ""
+msgid "ClusterIntegration|Unknown Error"
+msgstr ""
+
msgid "ClusterIntegration|Update %{appTitle}"
msgstr ""
@@ -6068,7 +6309,7 @@ msgstr ""
msgid "ClusterIntegration|Your cluster API is unreachable. Please ensure your API URL is correct."
msgstr ""
-msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Zone"
@@ -6188,6 +6429,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse all threads"
+msgstr ""
+
msgid "Collapse approvers"
msgstr ""
@@ -6337,7 +6581,7 @@ msgstr ""
msgid "Commit…"
msgstr ""
-msgid "Company"
+msgid "Community forum"
msgstr ""
msgid "Company name"
@@ -6346,6 +6590,9 @@ msgstr ""
msgid "Compare"
msgstr ""
+msgid "Compare %{oldCommitId}...%{newCommitId}"
+msgstr ""
+
msgid "Compare Git revisions"
msgstr ""
@@ -6361,6 +6608,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare submodule commit revisions"
+msgstr ""
+
msgid "Compare with previous version"
msgstr ""
@@ -6496,6 +6746,9 @@ msgstr ""
msgid "Configure the way a user creates a new account."
msgstr ""
+msgid "Configure which lists are shown for anyone who visits this board"
+msgstr ""
+
msgid "Confirm"
msgstr ""
@@ -6721,6 +6974,9 @@ msgstr[1] ""
msgid "ContainerRegistry|Set cleanup policy"
msgstr ""
+msgid "ContainerRegistry|Some tags were not deleted"
+msgstr ""
+
msgid "ContainerRegistry|Something went wrong while fetching the cleanup policy."
msgstr ""
@@ -6760,6 +7016,9 @@ msgstr ""
msgid "ContainerRegistry|Tags with names matching this regex pattern will %{italicStart}expire:%{italicEnd}"
msgstr ""
+msgid "ContainerRegistry|The cleanup policy timed out before it could delete all tags. An administrator can %{adminLinkStart}manually run cleanup now%{adminLinkEnd} or you can wait for the cleanup policy to automatically run again. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "ContainerRegistry|The last tag related to this image was recently removed. This empty image and any associated data will be automatically removed as part of the regular Garbage Collection process. If you have any questions, contact your administrator."
msgstr ""
@@ -6892,6 +7151,9 @@ msgstr ""
msgid "Contributions per group member"
msgstr ""
+msgid "Contributor"
+msgstr ""
+
msgid "Contributors"
msgstr ""
@@ -7021,6 +7283,9 @@ msgstr ""
msgid "Could not change HEAD: branch '%{branch}' does not exist"
msgstr ""
+msgid "Could not commit. An unexpected error occurred."
+msgstr ""
+
msgid "Could not connect to FogBugz, check your URL"
msgstr ""
@@ -7060,6 +7325,9 @@ msgstr ""
msgid "Could not find iteration"
msgstr ""
+msgid "Could not load instance counts. Please refresh the page to try again."
+msgstr ""
+
msgid "Could not remove the trigger."
msgstr ""
@@ -7084,10 +7352,10 @@ msgstr ""
msgid "Could not save prometheus manual configuration"
msgstr ""
-msgid "Could not udpdate wiki page"
+msgid "Could not update the LDAP settings"
msgstr ""
-msgid "Could not update the LDAP settings"
+msgid "Could not update wiki page"
msgstr ""
msgid "Could not upload your designs as one or more files uploaded are not supported."
@@ -7745,6 +8013,9 @@ msgstr ""
msgid "DastProfiles|Are you sure you want to delete this profile?"
msgstr ""
+msgid "DastProfiles|Could not create site validation token. Please refresh the page, or try again later."
+msgstr ""
+
msgid "DastProfiles|Could not create the scanner profile. Please try again."
msgstr ""
@@ -7769,6 +8040,12 @@ msgstr ""
msgid "DastProfiles|Could not fetch site profiles. Please refresh the page, or try again later."
msgstr ""
+msgid "DastProfiles|Could not retrieve site validation status. Please refresh the page, or try again later."
+msgstr ""
+
+msgid "DastProfiles|Could not update the scanner profile. Please try again."
+msgstr ""
+
msgid "DastProfiles|Could not update the site profile. Please try again."
msgstr ""
@@ -7784,7 +8061,7 @@ msgstr ""
msgid "DastProfiles|Download validation text file"
msgstr ""
-msgid "DastProfiles|Edit feature will come soon. Please create a new profile if changes needed"
+msgid "DastProfiles|Edit scanner profile"
msgstr ""
msgid "DastProfiles|Edit site profile"
@@ -7817,6 +8094,9 @@ msgstr ""
msgid "DastProfiles|No profiles created yet"
msgstr ""
+msgid "DastProfiles|Passive"
+msgstr ""
+
msgid "DastProfiles|Please enter a valid URL format, ex: http://www.example.com/home"
msgstr ""
@@ -7832,6 +8112,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan mode"
+msgstr ""
+
msgid "DastProfiles|Scanner Profile"
msgstr ""
@@ -7871,10 +8154,10 @@ msgstr ""
msgid "DastProfiles|Text file validation"
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
+msgid "DastProfiles|The maximum number of minutes allowed for the spider to traverse the site."
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the spider to traverse the site."
+msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
msgstr ""
msgid "DastProfiles|Validate"
@@ -7907,6 +8190,9 @@ msgstr ""
msgid "Date picker"
msgstr ""
+msgid "Date range"
+msgstr ""
+
msgid "Date range cannot exceed %{maxDateRange} days."
msgstr ""
@@ -7931,6 +8217,9 @@ msgstr ""
msgid "Days to merge"
msgstr ""
+msgid "Dear Administrator,"
+msgstr ""
+
msgid "Debug"
msgstr ""
@@ -8042,12 +8331,18 @@ msgstr ""
msgid "Delete"
msgstr ""
+msgid "Delete %{name}"
+msgstr ""
+
msgid "Delete Comment"
msgstr ""
msgid "Delete Snippet"
msgstr ""
+msgid "Delete Value Stream"
+msgstr ""
+
msgid "Delete account"
msgstr ""
@@ -8069,9 +8364,6 @@ msgstr ""
msgid "Delete label: %{label_name} ?"
msgstr ""
-msgid "Delete license"
-msgstr ""
-
msgid "Delete list"
msgstr ""
@@ -8147,15 +8439,6 @@ msgstr ""
msgid "Deleting a project places it into a read-only state until %{date}, at which point the project will be permanently deleted. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "Deleting the license failed."
-msgstr ""
-
-msgid "Deleting the license failed. The license was not found."
-msgstr ""
-
-msgid "Deleting the license failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "Deleting the project will delete its repository and all related resources including issues, merge requests etc."
msgstr ""
@@ -8651,7 +8934,10 @@ msgstr ""
msgid "DesignManagement|The maximum number of designs allowed to be uploaded is %{upload_limit}. Please try again."
msgstr ""
-msgid "DesignManagement|To upload designs, you'll need to enable LFS. %{requirements_link_start}More information%{requirements_link_end}"
+msgid "DesignManagement|There was an error moving your designs. Please upload your designs below."
+msgstr ""
+
+msgid "DesignManagement|To upload designs, you'll need to enable LFS and have admin enable hashed storage. %{requirements_link_start}More information%{requirements_link_end}"
msgstr ""
msgid "DesignManagement|Unresolve thread"
@@ -8663,6 +8949,9 @@ msgstr ""
msgid "DesignManagement|Upload skipped."
msgstr ""
+msgid "DesignManagement|Your designs are being copied and are on their way… Please refresh to update."
+msgstr ""
+
msgid "DesignManagement|and %{moreCount} more."
msgstr ""
@@ -8720,6 +9009,9 @@ msgstr ""
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
+msgid "Direct member"
+msgstr ""
+
msgid "Direction"
msgstr ""
@@ -8768,9 +9060,6 @@ msgstr ""
msgid "Discard draft"
msgstr ""
-msgid "Discard review"
-msgstr ""
-
msgid "DiscordService|Discord Notifications"
msgstr ""
@@ -8839,10 +9128,10 @@ msgstr ""
msgid "Dismiss Merge Request promotion"
msgstr ""
-msgid "Dismiss Selected"
+msgid "Dismiss Value Stream Analytics introduction box"
msgstr ""
-msgid "Dismiss Value Stream Analytics introduction box"
+msgid "Dismiss selected"
msgstr ""
msgid "Dismiss trial promotion"
@@ -8893,9 +9182,6 @@ msgstr ""
msgid "Documents reindexed: %{processed_documents} (%{percentage}%%)"
msgstr ""
-msgid "Doing"
-msgstr ""
-
msgid "Domain"
msgstr ""
@@ -9091,9 +9377,6 @@ msgstr ""
msgid "Edit environment"
msgstr ""
-msgid "Edit file"
-msgstr ""
-
msgid "Edit files in the editor and commit changes here"
msgstr ""
@@ -9106,6 +9389,12 @@ msgstr ""
msgid "Edit identity for %{user_name}"
msgstr ""
+msgid "Edit in Web IDE"
+msgstr ""
+
+msgid "Edit in single-file editor"
+msgstr ""
+
msgid "Edit issues"
msgstr ""
@@ -9133,10 +9422,10 @@ msgstr ""
msgid "Editing"
msgstr ""
-msgid "Elasticsearch"
+msgid "Elasticsearch AWS IAM credentials"
msgstr ""
-msgid "Elasticsearch AWS IAM credentials"
+msgid "Elasticsearch HTTP client timeout value in seconds."
msgstr ""
msgid "Elasticsearch indexing restrictions"
@@ -9145,9 +9434,6 @@ msgstr ""
msgid "Elasticsearch indexing started"
msgstr ""
-msgid "Elasticsearch integration. Elasticsearch AWS IAM."
-msgstr ""
-
msgid "Elasticsearch reindexing is already in progress"
msgstr ""
@@ -9175,9 +9461,6 @@ msgstr ""
msgid "Email Notification"
msgstr ""
-msgid "Email address"
-msgstr ""
-
msgid "Email could not be sent"
msgstr ""
@@ -9241,6 +9524,9 @@ msgstr ""
msgid "Emails sent from Service Desk will have this name"
msgstr ""
+msgid "Emails sent to %{email} will still be supported"
+msgstr ""
+
msgid "Emails separated by comma"
msgstr ""
@@ -9274,9 +9560,18 @@ msgstr ""
msgid "Enable"
msgstr ""
+msgid "Enable %{link_start}Gitpod%{link_end} integration to launch a development environment in your browser directly from GitLab."
+msgstr ""
+
msgid "Enable Auto DevOps"
msgstr ""
+msgid "Enable Gitpod"
+msgstr ""
+
+msgid "Enable Gitpod?"
+msgstr ""
+
msgid "Enable HTML emails"
msgstr ""
@@ -9406,9 +9701,6 @@ msgstr ""
msgid "Encountered an error while rendering: %{err}"
msgstr ""
-msgid "End date"
-msgstr ""
-
msgid "Ends at (UTC)"
msgstr ""
@@ -9568,7 +9860,7 @@ msgstr ""
msgid "EnvironmentsDashboard|The environments dashboard provides a summary of each project's environments' status, including pipeline and alert statuses."
msgstr ""
-msgid "EnvironmentsDashboard|This dashboard displays a maximum of 7 projects and 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
+msgid "EnvironmentsDashboard|This dashboard displays 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
msgstr ""
msgid "Environments|An error occurred while canceling the auto stop, please try again"
@@ -9889,6 +10181,9 @@ msgstr ""
msgid "Error deleting project. Check logs for error details."
msgstr ""
+msgid "Error fetching burnup chart data"
+msgstr ""
+
msgid "Error fetching diverging counts for branches. Please try again."
msgstr ""
@@ -9967,6 +10262,9 @@ msgstr ""
msgid "Error occurred when saving assignees"
msgstr ""
+msgid "Error occurred when saving reviewers"
+msgstr ""
+
msgid "Error occurred when toggling the notification subscription"
msgstr ""
@@ -10219,10 +10517,13 @@ msgstr ""
msgid "Expand all"
msgstr ""
-msgid "Expand approvers"
+msgid "Expand all files"
msgstr ""
-msgid "Expand dropdown"
+msgid "Expand all threads"
+msgstr ""
+
+msgid "Expand approvers"
msgstr ""
msgid "Expand milestones"
@@ -10393,6 +10694,9 @@ msgstr ""
msgid "Failed to create Merge Request. Please try again."
msgstr ""
+msgid "Failed to create To-Do for the design."
+msgstr ""
+
msgid "Failed to create a branch for this issue. Please try again."
msgstr ""
@@ -10432,6 +10736,12 @@ msgstr ""
msgid "Failed to load authors. Please try again."
msgstr ""
+msgid "Failed to load branches. Please try again."
+msgstr ""
+
+msgid "Failed to load deploy keys."
+msgstr ""
+
msgid "Failed to load emoji list."
msgstr ""
@@ -10447,6 +10757,9 @@ msgstr ""
msgid "Failed to load groups & users."
msgstr ""
+msgid "Failed to load groups, users and deploy keys."
+msgstr ""
+
msgid "Failed to load labels. Please try again."
msgstr ""
@@ -10456,6 +10769,12 @@ msgstr ""
msgid "Failed to load related branches"
msgstr ""
+msgid "Failed to load sidebar confidential toggle"
+msgstr ""
+
+msgid "Failed to load sidebar lock status"
+msgstr ""
+
msgid "Failed to load stacktrace."
msgstr ""
@@ -10483,6 +10802,9 @@ msgstr ""
msgid "Failed to publish issue on status page."
msgstr ""
+msgid "Failed to remove To-Do for the design."
+msgstr ""
+
msgid "Failed to remove a Zoom meeting"
msgstr ""
@@ -10525,6 +10847,9 @@ msgstr ""
msgid "Failed to signing using smartcard authentication"
msgstr ""
+msgid "Failed to toggle To-Do for the design."
+msgstr ""
+
msgid "Failed to update branch!"
msgstr ""
@@ -10638,7 +10963,7 @@ msgstr ""
msgid "FeatureFlags|Edit User List"
msgstr ""
-msgid "FeatureFlags|Enable features for specific users and specific environments by defining feature flag strategies."
+msgid "FeatureFlags|Enable features for specific users and environments by configuring feature flag strategies."
msgstr ""
msgid "FeatureFlags|Environment Spec"
@@ -10698,7 +11023,7 @@ msgstr ""
msgid "FeatureFlags|Include additional user IDs"
msgstr ""
-msgid "FeatureFlags|Install a %{docs_link_anchored_start}compatible client library%{docs_link_anchored_end} and specify the API URL, application name, and instance ID during the configuration setup. %{docs_link_start}More Information%{docs_link_end}"
+msgid "FeatureFlags|Install a %{docsLinkAnchoredStart}compatible client library%{docsLinkAnchoredEnd} and specify the API URL, application name, and instance ID during the configuration setup. %{docsLinkStart}More Information%{docsLinkEnd}"
msgstr ""
msgid "FeatureFlags|Instance ID"
@@ -10710,6 +11035,9 @@ msgstr ""
msgid "FeatureFlags|Loading feature flags"
msgstr ""
+msgid "FeatureFlags|Loading user lists"
+msgstr ""
+
msgid "FeatureFlags|More information"
msgstr ""
@@ -10728,7 +11056,7 @@ msgstr ""
msgid "FeatureFlags|New feature flag"
msgstr ""
-msgid "FeatureFlags|New list"
+msgid "FeatureFlags|New user list"
msgstr ""
msgid "FeatureFlags|Percent of users"
@@ -10767,6 +11095,9 @@ msgstr ""
msgid "FeatureFlags|There was an error fetching the feature flags."
msgstr ""
+msgid "FeatureFlags|There was an error fetching the user lists."
+msgstr ""
+
msgid "FeatureFlags|There was an error retrieving user lists"
msgstr ""
@@ -10782,6 +11113,9 @@ msgstr ""
msgid "FeatureFlags|User List"
msgstr ""
+msgid "FeatureFlags|User Lists"
+msgstr ""
+
msgid "FeatureFlag|List"
msgstr ""
@@ -10809,15 +11143,6 @@ msgstr ""
msgid "Fetching incoming email"
msgstr ""
-msgid "Fetching licenses failed."
-msgstr ""
-
-msgid "Fetching licenses failed. The request endpoint was not found."
-msgstr ""
-
-msgid "Fetching licenses failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "File"
msgstr ""
@@ -10920,12 +11245,21 @@ msgstr ""
msgid "Filter by status"
msgstr ""
+msgid "Filter by test cases that are currently archived."
+msgstr ""
+
+msgid "Filter by test cases that are currently opened."
+msgstr ""
+
msgid "Filter by two-factor authentication"
msgstr ""
msgid "Filter by user"
msgstr ""
+msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
+msgstr ""
+
msgid "Filter pipelines"
msgstr ""
@@ -10941,7 +11275,7 @@ msgstr ""
msgid "Filter results..."
msgstr ""
-msgid "Filter your projects by name"
+msgid "Filter your repositories by name"
msgstr ""
msgid "Filter..."
@@ -10950,7 +11284,7 @@ msgstr ""
msgid "Find File"
msgstr ""
-msgid "Find bugs in your code with coverage-guided fuzzing"
+msgid "Find bugs in your code with coverage-guided fuzzing."
msgstr ""
msgid "Find by path"
@@ -10977,9 +11311,6 @@ msgstr ""
msgid "Finish editing this message first!"
msgstr ""
-msgid "Finish review"
-msgstr ""
-
msgid "Finish setting up your dedicated account for %{group_name}."
msgstr ""
@@ -11049,6 +11380,9 @@ msgstr ""
msgid "Footer message"
msgstr ""
+msgid "For a faster browsing experience, some files are collapsed by default."
+msgstr ""
+
msgid "For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
@@ -11058,6 +11392,9 @@ msgstr ""
msgid "For more info, read the documentation."
msgstr ""
+msgid "For more information on how the number of active users is calculated, see the %{self_managed_subscriptions_doc_link} documentation."
+msgstr ""
+
msgid "For more information, go to the "
msgstr ""
@@ -11196,6 +11533,9 @@ msgstr ""
msgid "Generate new token"
msgstr ""
+msgid "Generic package file size in bytes"
+msgstr ""
+
msgid "Geo"
msgstr ""
@@ -11457,6 +11797,9 @@ msgstr ""
msgid "Geo|Please refer to Geo Troubleshooting."
msgstr ""
+msgid "Geo|Primary node"
+msgstr ""
+
msgid "Geo|Project"
msgstr ""
@@ -11499,6 +11842,9 @@ msgstr ""
msgid "Geo|Review replication status, and resynchronize and reverify items with the primary node."
msgstr ""
+msgid "Geo|Secondary node"
+msgstr ""
+
msgid "Geo|Status"
msgstr ""
@@ -11538,6 +11884,9 @@ msgstr ""
msgid "Geo|URL must be a valid url (ex: https://gitlab.com)"
msgstr ""
+msgid "Geo|Undefined"
+msgstr ""
+
msgid "Geo|Unknown state"
msgstr ""
@@ -11613,10 +11962,16 @@ msgstr ""
msgid "GitHub import"
msgstr ""
+msgid "GitLab"
+msgstr ""
+
msgid "GitLab / Unsubscribe"
msgstr ""
-msgid "GitLab Enterprise Edition %{plan}"
+msgid "GitLab API"
+msgstr ""
+
+msgid "GitLab Billing Team."
msgstr ""
msgid "GitLab Group Runners can execute code for all the projects in this group."
@@ -11628,12 +11983,18 @@ msgstr ""
msgid "GitLab Issue"
msgstr ""
+msgid "GitLab Pages"
+msgstr ""
+
msgid "GitLab Service Desk is a simple way to allow people to create issues in your GitLab instance without needing their own user account. It provides a unique email address for end users to create issues in a project, and replies can be sent either through the GitLab interface or by email. End users will only see the thread through email."
msgstr ""
msgid "GitLab Shared Runners execute code of different projects on the same Runner unless you configure GitLab Runner Autoscale with MaxBuilds 1 (which it is on GitLab.com)."
msgstr ""
+msgid "GitLab Shell"
+msgstr ""
+
msgid "GitLab Support Bot"
msgstr ""
@@ -11643,7 +12004,7 @@ msgstr ""
msgid "GitLab User"
msgstr ""
-msgid "GitLab allows you to continue using your license even if you exceed the number of seats you purchased. You will be required to pay for these seats when you renew your license."
+msgid "GitLab Workhorse"
msgstr ""
msgid "GitLab commit"
@@ -11811,6 +12172,21 @@ msgstr ""
msgid "Gitlab Pages"
msgstr ""
+msgid "Gitpod"
+msgstr ""
+
+msgid "Gitpod|Add the URL to your Gitpod instance configured to read your GitLab projects."
+msgstr ""
+
+msgid "Gitpod|Enable Gitpod integration"
+msgstr ""
+
+msgid "Gitpod|Gitpod URL"
+msgstr ""
+
+msgid "Gitpod|e.g. https://gitpod.example.com"
+msgstr ""
+
msgid "Given access %{time_ago}"
msgstr ""
@@ -12318,9 +12694,6 @@ msgstr ""
msgid "GroupSAML|Valid SAML Response"
msgstr ""
-msgid "GroupSAML|With group managed accounts enabled, all the users without a group managed account will be excluded from the group."
-msgstr ""
-
msgid "GroupSAML|With prohibit outer forks flag enabled group members will be able to fork project only inside your group."
msgstr ""
@@ -12534,10 +12907,10 @@ msgstr ""
msgid "GroupsNew|Create group"
msgstr ""
-msgid "GroupsNew|GitLab group export"
+msgid "GroupsNew|Import"
msgstr ""
-msgid "GroupsNew|Import"
+msgid "GroupsNew|Import a GitLab group export file"
msgstr ""
msgid "GroupsNew|Import group"
@@ -12680,6 +13053,9 @@ msgid_plural "Hide charts"
msgstr[0] ""
msgstr[1] ""
+msgid "Hide comments on this file"
+msgstr ""
+
msgid "Hide details"
msgstr ""
@@ -12724,6 +13100,15 @@ msgstr ""
msgid "Highest role:"
msgstr ""
+msgid "HighlightBar|Alert events:"
+msgstr ""
+
+msgid "HighlightBar|Alert start time:"
+msgstr ""
+
+msgid "HighlightBar|Original alert:"
+msgstr ""
+
msgid "History"
msgstr ""
@@ -12901,6 +13286,9 @@ msgstr ""
msgid "If enabled, access to projects will be validated on an external service using their classification label."
msgstr ""
+msgid "If the number of active users exceeds the user limit, you will be charged for the number of %{users_over_license_link} at your next license reconciliation."
+msgstr ""
+
msgid "If there is no previous license or if the previous license has expired, some GitLab functionality will be blocked until a new, valid license is uploaded."
msgstr ""
@@ -12940,9 +13328,6 @@ msgstr ""
msgid "If your HTTP repository is not publicly accessible, add your credentials."
msgstr ""
-msgid "Iglu registry URL (optional)"
-msgstr ""
-
msgid "Ignore"
msgstr ""
@@ -12979,6 +13364,16 @@ msgstr ""
msgid "Import"
msgstr ""
+msgid "Import %d compatible repository"
+msgid_plural "Import %d compatible repositories"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Import %d repository"
+msgid_plural "Import %d repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Import CSV"
msgstr ""
@@ -12988,15 +13383,9 @@ msgstr ""
msgid "Import all compatible projects"
msgstr ""
-msgid "Import all compatible repositories"
-msgstr ""
-
msgid "Import all projects"
msgstr ""
-msgid "Import all repositories"
-msgstr ""
-
msgid "Import an exported GitLab project"
msgstr ""
@@ -13084,6 +13473,9 @@ msgstr ""
msgid "ImportProjects|Error importing repository %{project_safe_import_url} into %{project_full_path} - %{message}"
msgstr ""
+msgid "ImportProjects|Import repositories"
+msgstr ""
+
msgid "ImportProjects|Importing the project failed"
msgstr ""
@@ -13096,7 +13488,7 @@ msgstr ""
msgid "ImportProjects|Requesting your %{provider} repositories failed"
msgstr ""
-msgid "ImportProjects|Select the projects you want to import"
+msgid "ImportProjects|Select the repositories you want to import"
msgstr ""
msgid "ImportProjects|The remote data could not be imported."
@@ -13132,9 +13524,6 @@ msgstr ""
msgid "In order to enable Service Desk for your instance, you must first set up incoming email."
msgstr ""
-msgid "In order to gather accurate feature usage data, it can take 1 to 2 weeks to see your index."
-msgstr ""
-
msgid "In order to personalize your experience with GitLab%{br_tag}we would like to know a bit more about you."
msgstr ""
@@ -13165,18 +13554,30 @@ msgstr ""
msgid "IncidentManagement|Create incident"
msgstr ""
+msgid "IncidentManagement|Critical - S1"
+msgstr ""
+
msgid "IncidentManagement|Date created"
msgstr ""
msgid "IncidentManagement|Display your incidents in a dedicated view"
msgstr ""
+msgid "IncidentManagement|High - S2"
+msgstr ""
+
msgid "IncidentManagement|Incident"
msgstr ""
msgid "IncidentManagement|Incidents"
msgstr ""
+msgid "IncidentManagement|Low - S4"
+msgstr ""
+
+msgid "IncidentManagement|Medium - S3"
+msgstr ""
+
msgid "IncidentManagement|No incidents to display."
msgstr ""
@@ -13189,6 +13590,9 @@ msgstr ""
msgid "IncidentManagement|Published to status page"
msgstr ""
+msgid "IncidentManagement|Severity"
+msgstr ""
+
msgid "IncidentManagement|There are no closed incidents"
msgstr ""
@@ -13198,6 +13602,9 @@ msgstr ""
msgid "IncidentManagement|Unassigned"
msgstr ""
+msgid "IncidentManagement|Unknown"
+msgstr ""
+
msgid "IncidentManagement|Unpublished"
msgstr ""
@@ -13219,6 +13626,15 @@ msgstr ""
msgid "Incidents"
msgstr ""
+msgid "Incident|Alert details"
+msgstr ""
+
+msgid "Incident|Summary"
+msgstr ""
+
+msgid "Incident|There was an issue loading alert data. Please try again."
+msgstr ""
+
msgid "Include a Terms of Service agreement and Privacy Policy that all users must accept."
msgstr ""
@@ -13279,6 +13695,9 @@ msgstr ""
msgid "Information about additional Pages templates and how to install them can be found in our %{pages_getting_started_guide}."
msgstr ""
+msgid "Inherited"
+msgstr ""
+
msgid "Inherited:"
msgstr ""
@@ -13359,7 +13778,22 @@ msgstr ""
msgid "Instance administrators group already exists"
msgstr ""
-msgid "Instance license"
+msgid "InstanceStatistics|Groups"
+msgstr ""
+
+msgid "InstanceStatistics|Issues"
+msgstr ""
+
+msgid "InstanceStatistics|Merge Requests"
+msgstr ""
+
+msgid "InstanceStatistics|Pipelines"
+msgstr ""
+
+msgid "InstanceStatistics|Projects"
+msgstr ""
+
+msgid "InstanceStatistics|Users"
msgstr ""
msgid "Integration"
@@ -13371,6 +13805,12 @@ msgstr ""
msgid "Integrations"
msgstr ""
+msgid "Integrations|%{integration} settings saved and active."
+msgstr ""
+
+msgid "Integrations|%{integration} settings saved, but not active."
+msgstr ""
+
msgid "Integrations|All details"
msgstr ""
@@ -13380,6 +13820,12 @@ msgstr ""
msgid "Integrations|Comment settings:"
msgstr ""
+msgid "Integrations|Connection failed. Please check your settings."
+msgstr ""
+
+msgid "Integrations|Connection successful."
+msgstr ""
+
msgid "Integrations|Default settings are inherited from the group level."
msgstr ""
@@ -13395,6 +13841,15 @@ msgstr ""
msgid "Integrations|Includes commit title and branch"
msgstr ""
+msgid "Integrations|Projects using custom settings will not be impacted unless the project owner chooses to use instance-level defaults."
+msgstr ""
+
+msgid "Integrations|Save settings?"
+msgstr ""
+
+msgid "Integrations|Saving will update the default settings for all projects that are not using custom settings."
+msgstr ""
+
msgid "Integrations|Standard"
msgstr ""
@@ -13527,6 +13982,9 @@ msgstr ""
msgid "Invitation"
msgstr ""
+msgid "Invitation declined"
+msgstr ""
+
msgid "Invite"
msgstr ""
@@ -13578,6 +14036,42 @@ 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|%{linkStart}Read more%{linkEnd} about role permissions"
+msgstr ""
+
+msgid "InviteMembersModal|Access expiration date (optional)"
+msgstr ""
+
+msgid "InviteMembersModal|Cancel"
+msgstr ""
+
+msgid "InviteMembersModal|Choose a role permission"
+msgstr ""
+
+msgid "InviteMembersModal|GitLab member or Email address"
+msgstr ""
+
+msgid "InviteMembersModal|Invite"
+msgstr ""
+
+msgid "InviteMembersModal|Invite team members"
+msgstr ""
+
+msgid "InviteMembersModal|Search for members to invite"
+msgstr ""
+
+msgid "InviteMembersModal|User not invited. Feature coming soon!"
+msgstr ""
+
+msgid "InviteMembersModal|Users were succesfully added"
+msgstr ""
+
+msgid "InviteMembersModal|You're inviting members to the %{group_name} group"
+msgstr ""
+
+msgid "InviteMembers|Invite team members"
+msgstr ""
+
msgid "Invited"
msgstr ""
@@ -13632,10 +14126,13 @@ msgstr ""
msgid "Issue cannot be found."
msgstr ""
+msgid "Issue created from vulnerability %{vulnerability_link}"
+msgstr ""
+
msgid "Issue events"
msgstr ""
-msgid "Issue first depoloyed to production"
+msgid "Issue first deployed to production"
msgstr ""
msgid "Issue label"
@@ -13713,6 +14210,9 @@ msgstr ""
msgid "IssueTracker|Custom issue tracker"
msgstr ""
+msgid "IssueTracker|EWM work items tracker"
+msgstr ""
+
msgid "IssueTracker|Redmine issue tracker"
msgstr ""
@@ -13779,6 +14279,9 @@ msgstr ""
msgid "It looks like you have some draft commits in this branch."
msgstr ""
+msgid "It may be several days before you see feature usage data."
+msgstr ""
+
msgid "It must have a header row and at least two columns: the first column is the issue title and the second column is the issue description. The separator is automatically detected."
msgstr ""
@@ -14061,13 +14564,13 @@ msgstr ""
msgid "Join Zoom meeting"
msgstr ""
-msgid "Jul"
+msgid "Joined %{time_ago}"
msgstr ""
-msgid "July"
+msgid "Jul"
msgstr ""
-msgid "Jump to first unresolved thread"
+msgid "July"
msgstr ""
msgid "Jump to next unresolved thread"
@@ -14103,6 +14606,9 @@ msgstr ""
msgid "Keyboard shortcuts"
msgstr ""
+msgid "KeyboardKey|Ctrl+"
+msgstr ""
+
msgid "Keys"
msgstr ""
@@ -14151,6 +14657,9 @@ msgstr ""
msgid "LDAP Synchronization"
msgstr ""
+msgid "LDAP group settings"
+msgstr ""
+
msgid "LDAP settings"
msgstr ""
@@ -14160,6 +14669,9 @@ msgstr ""
msgid "LDAP sync in progress. This could take a few minutes. Refresh the page to see the changes."
msgstr ""
+msgid "LDAP synchronizations"
+msgstr ""
+
msgid "LFS"
msgstr ""
@@ -14240,7 +14752,16 @@ msgid_plural "Last %d days"
msgstr[0] ""
msgstr[1] ""
-msgid "Last %{days} days"
+msgid "Last 2 weeks"
+msgstr ""
+
+msgid "Last 30 days"
+msgstr ""
+
+msgid "Last 60 days"
+msgstr ""
+
+msgid "Last 90 days"
msgstr ""
msgid "Last Accessed On"
@@ -14318,6 +14839,9 @@ msgstr ""
msgid "Last used on:"
msgstr ""
+msgid "Last week"
+msgstr ""
+
msgid "LastCommit|authored"
msgstr ""
@@ -14333,6 +14857,9 @@ msgstr ""
msgid "Latest pipeline for the most recent commit on this branch"
msgstr ""
+msgid "Launch a ready-to-code development environment for your project."
+msgstr ""
+
msgid "Lead"
msgstr ""
@@ -14713,6 +15240,9 @@ msgstr ""
msgid "List of all merge commits"
msgstr ""
+msgid "List options"
+msgstr ""
+
msgid "List settings"
msgstr ""
@@ -14725,9 +15255,6 @@ msgstr ""
msgid "List your Bitbucket Server repositories"
msgstr ""
-msgid "Lists"
-msgstr ""
-
msgid "Live preview"
msgstr ""
@@ -14974,6 +15501,12 @@ msgstr ""
msgid "Mark as done"
msgstr ""
+msgid "Mark as draft"
+msgstr ""
+
+msgid "Mark as ready"
+msgstr ""
+
msgid "Mark as resolved"
msgstr ""
@@ -14995,6 +15528,24 @@ msgstr ""
msgid "Markdown is supported"
msgstr ""
+msgid "MarkdownEditor|Add a link (%{modifierKey}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add a link (%{modifier_key}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifierKey}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifier_key}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifierKey}I)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifier_key}I)"
+msgstr ""
+
msgid "Marked For Deletion At - %{deletion_time}"
msgstr ""
@@ -15079,7 +15630,25 @@ msgstr ""
msgid "Max access level"
msgstr ""
-msgid "Max seats used"
+msgid "Max role"
+msgstr ""
+
+msgid "Max size 15 MB"
+msgstr ""
+
+msgid "Maximum Conan package file size in bytes"
+msgstr ""
+
+msgid "Maximum Maven package file size in bytes"
+msgstr ""
+
+msgid "Maximum NPM package file size in bytes"
+msgstr ""
+
+msgid "Maximum NuGet package file size in bytes"
+msgstr ""
+
+msgid "Maximum PyPI package file size in bytes"
msgstr ""
msgid "Maximum Users:"
@@ -15211,6 +15780,18 @@ msgstr ""
msgid "Members with access to %{strong_start}%{group_name}%{strong_end}"
msgstr ""
+msgid "Members|%{time} by %{user}"
+msgstr ""
+
+msgid "Members|Expired"
+msgstr ""
+
+msgid "Members|No expiration set"
+msgstr ""
+
+msgid "Members|in %{time}"
+msgstr ""
+
msgid "Memory Usage"
msgstr ""
@@ -15397,9 +15978,6 @@ msgstr ""
msgid "MergeRequests|Thread will be unresolved"
msgstr ""
-msgid "MergeRequests|Toggle comments for this file"
-msgstr ""
-
msgid "MergeRequests|View file @ %{commitId}"
msgstr ""
@@ -15460,6 +16038,9 @@ msgstr ""
msgid "Merging immediately isn't recommended as it may negatively impact the existing merge train. Read the %{docsLinkStart}documentation%{docsLinkEnd} for more information."
msgstr ""
+msgid "Message"
+msgstr ""
+
msgid "Messages"
msgstr ""
@@ -15845,18 +16426,12 @@ msgid_plural "Milestones"
msgstr[0] ""
msgstr[1] ""
-msgid "Milestone does not support burnup charts"
-msgstr ""
-
msgid "Milestone lists not available with your current license"
msgstr ""
msgid "Milestone lists show all issues from the selected milestone."
msgstr ""
-msgid "Milestone must have a start and due date"
-msgstr ""
-
msgid "MilestoneSidebar|Closed:"
msgstr ""
@@ -16223,6 +16798,9 @@ msgstr ""
msgid "Namespace"
msgstr ""
+msgid "Namespace ID:"
+msgstr ""
+
msgid "Namespace is empty"
msgstr ""
@@ -16307,6 +16885,9 @@ msgstr ""
msgid "NetworkPolicies|Allow all outbound traffic from %{selector} to %{ruleSelector} on %{ports}"
msgstr ""
+msgid "NetworkPolicies|Are you sure you want to delete this policy? This action cannot be undone."
+msgstr ""
+
msgid "NetworkPolicies|Choose whether to enforce this policy."
msgstr ""
@@ -16316,12 +16897,21 @@ msgstr ""
msgid "NetworkPolicies|Define this policy's location, conditions and actions."
msgstr ""
+msgid "NetworkPolicies|Delete policy"
+msgstr ""
+
+msgid "NetworkPolicies|Delete policy: %{policy}"
+msgstr ""
+
msgid "NetworkPolicies|Deny all traffic"
msgstr ""
msgid "NetworkPolicies|Description"
msgstr ""
+msgid "NetworkPolicies|Edit policy"
+msgstr ""
+
msgid "NetworkPolicies|Editor mode"
msgstr ""
@@ -16349,6 +16939,9 @@ msgstr ""
msgid "NetworkPolicies|Name"
msgstr ""
+msgid "NetworkPolicies|Namespace"
+msgstr ""
+
msgid "NetworkPolicies|Network Policy"
msgstr ""
@@ -16400,6 +16993,9 @@ msgstr ""
msgid "NetworkPolicies|Rules"
msgstr ""
+msgid "NetworkPolicies|Save changes"
+msgstr ""
+
msgid "NetworkPolicies|Something went wrong, failed to update policy"
msgstr ""
@@ -16412,6 +17008,9 @@ msgstr ""
msgid "NetworkPolicies|Traffic that does not match any rule will be blocked."
msgstr ""
+msgid "NetworkPolicies|Unable to parse policy"
+msgstr ""
+
msgid "NetworkPolicies|YAML editor"
msgstr ""
@@ -16525,6 +17124,9 @@ msgstr ""
msgid "New Snippet"
msgstr ""
+msgid "New Test Case"
+msgstr ""
+
msgid "New User"
msgstr ""
@@ -16624,6 +17226,9 @@ msgstr ""
msgid "New tag"
msgstr ""
+msgid "New test case"
+msgstr ""
+
msgid "New users set to external"
msgstr ""
@@ -16696,7 +17301,7 @@ msgstr ""
msgid "No changes"
msgstr ""
-msgid "No changes between %{ref_start}%{source_branch}%{ref_end} and %{ref_start}%{target_branch}%{ref_end}"
+msgid "No changes between %{sourceBranch} and %{targetBranch}"
msgstr ""
msgid "No child epics match applied filters"
@@ -16711,6 +17316,9 @@ msgstr ""
msgid "No containers available"
msgstr ""
+msgid "No content to show"
+msgstr ""
+
msgid "No contributions"
msgstr ""
@@ -16786,9 +17394,6 @@ msgstr ""
msgid "No license. All rights reserved"
msgstr ""
-msgid "No licenses found."
-msgstr ""
-
msgid "No matches found"
msgstr ""
@@ -16801,6 +17406,9 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No members found"
+msgstr ""
+
msgid "No merge requests found"
msgstr ""
@@ -16822,6 +17430,9 @@ msgstr ""
msgid "No parent group"
msgstr ""
+msgid "No plan"
+msgstr ""
+
msgid "No pods available"
msgstr ""
@@ -16918,6 +17529,12 @@ msgstr ""
msgid "Not Implemented"
msgstr ""
+msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+msgstr ""
+
+msgid "Not all browsers support WebAuthn. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even from an unsupported browser."
+msgstr ""
+
msgid "Not all data has been processed yet, the accuracy of the chart for the selected timeframe is limited."
msgstr ""
@@ -17014,6 +17631,9 @@ msgstr ""
msgid "Notification settings saved"
msgstr ""
+msgid "NotificationEvent|Change reviewer merge request"
+msgstr ""
+
msgid "NotificationEvent|Close issue"
msgstr ""
@@ -17176,10 +17796,7 @@ msgstr ""
msgid "On track"
msgstr ""
-msgid "OnDemandScans|Attached branch"
-msgstr ""
-
-msgid "OnDemandScans|Attached branch is where the scan job runs."
+msgid "OnDemandScans|Could not fetch scanner profiles. Please refresh the page, or try again later."
msgstr ""
msgid "OnDemandScans|Could not fetch site profiles. Please refresh the page, or try again later."
@@ -17188,6 +17805,9 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
+msgid "OnDemandScans|Create a new scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Create a new site profile"
msgstr ""
@@ -17200,6 +17820,9 @@ msgstr ""
msgid "OnDemandScans|New on-demand DAST scan"
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 ""
@@ -17209,16 +17832,10 @@ msgstr ""
msgid "OnDemandScans|On-demand scans run outside the DevOps cycle and find vulnerabilities in your projects. %{learnMoreLinkStart}Learn more%{learnMoreLinkEnd}"
msgstr ""
-msgid "OnDemandScans|Only a passive scan can be performed on demand."
-msgstr ""
-
-msgid "OnDemandScans|Passive"
-msgstr ""
-
msgid "OnDemandScans|Run scan"
msgstr ""
-msgid "OnDemandScans|Scan mode"
+msgid "OnDemandScans|Scanner profile"
msgstr ""
msgid "OnDemandScans|Scanner settings"
@@ -17230,9 +17847,15 @@ msgstr ""
msgid "OnDemandScans|Select one of the existing profiles"
msgstr ""
+msgid "OnDemandScans|Site profile"
+msgstr ""
+
msgid "OnDemandScans|Site profiles"
msgstr ""
+msgid "OnDemandScans|Use existing scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Use existing site profile"
msgstr ""
@@ -17331,9 +17954,6 @@ msgstr ""
msgid "Open Selection"
msgstr ""
-msgid "Open Web IDE"
-msgstr ""
-
msgid "Open comment type dropdown"
msgstr ""
@@ -17439,6 +18059,9 @@ msgstr ""
msgid "Origin"
msgstr ""
+msgid "Orphaned member"
+msgstr ""
+
msgid "Other Labels"
msgstr ""
@@ -17454,6 +18077,9 @@ msgstr ""
msgid "Other visibility settings have been disabled by the administrator."
msgstr ""
+msgid "Our documentation includes an example DevOps Score report."
+msgstr ""
+
msgid "Out-of-compliance with this project's policies and should be removed"
msgstr ""
@@ -17478,6 +18104,9 @@ msgstr ""
msgid "Overwrite diverged branches"
msgstr ""
+msgid "Owned by %{image_tag}"
+msgstr ""
+
msgid "Owned by anyone"
msgstr ""
@@ -17499,6 +18128,9 @@ msgstr ""
msgid "Package deleted successfully"
msgstr ""
+msgid "Package file size limits"
+msgstr ""
+
msgid "Package recipe already exists"
msgstr ""
@@ -17514,9 +18146,6 @@ msgstr ""
msgid "Package type must be PyPi"
msgstr ""
-msgid "Package was removed"
-msgstr ""
-
msgid "PackageRegistry|%{name} version %{version} was created %{datetime}"
msgstr ""
@@ -17658,12 +18287,18 @@ msgstr ""
msgid "PackageRegistry|NuGet Command"
msgstr ""
+msgid "PackageRegistry|Package Registry"
+msgstr ""
+
msgid "PackageRegistry|Pip Command"
msgstr ""
msgid "PackageRegistry|Pipeline %{link} triggered %{datetime} by %{author}"
msgstr ""
+msgid "PackageRegistry|Publish and share packages for a variety of common package managers. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "PackageRegistry|Published to the %{project} Package Registry %{datetime}"
msgstr ""
@@ -17763,6 +18398,9 @@ msgstr ""
msgid "Page not found"
msgstr ""
+msgid "Page settings"
+msgstr ""
+
msgid "Page was successfully deleted"
msgstr ""
@@ -17904,7 +18542,7 @@ msgstr ""
msgid "Paste issue link"
msgstr ""
-msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Don't use your private SSH key."
+msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Do not paste your private SSH key, as that can compromise your identity."
msgstr ""
msgid "Patch to apply"
@@ -17931,6 +18569,9 @@ msgstr ""
msgid "Pending"
msgstr ""
+msgid "Pending comments"
+msgstr ""
+
msgid "People without permission will never get a notification and won't be able to comment."
msgstr ""
@@ -18129,6 +18770,9 @@ msgstr ""
msgid "Pipelines|Build with confidence"
msgstr ""
+msgid "Pipelines|By revoking a trigger you will break any processes making use of it. Are you sure?"
+msgstr ""
+
msgid "Pipelines|CI Lint"
msgstr ""
@@ -18141,6 +18785,15 @@ msgstr ""
msgid "Pipelines|Continuous Integration can help catch bugs by running your tests automatically, while Continuous Deployment can help you deliver code to your product environment."
msgstr ""
+msgid "Pipelines|Copy trigger token"
+msgstr ""
+
+msgid "Pipelines|Description"
+msgstr ""
+
+msgid "Pipelines|Edit"
+msgstr ""
+
msgid "Pipelines|Get started with Pipelines"
msgstr ""
@@ -18156,15 +18809,27 @@ msgstr ""
msgid "Pipelines|It is recommended the code is reviewed thoroughly before running this pipeline with the parent project's CI resource."
msgstr ""
+msgid "Pipelines|Last Used"
+msgstr ""
+
msgid "Pipelines|Loading Pipelines"
msgstr ""
msgid "Pipelines|More Information"
msgstr ""
+msgid "Pipelines|No triggers have been created yet. Add one using the form above."
+msgstr ""
+
+msgid "Pipelines|Owner"
+msgstr ""
+
msgid "Pipelines|Project cache successfully reset."
msgstr ""
+msgid "Pipelines|Revoke"
+msgstr ""
+
msgid "Pipelines|Run Pipeline"
msgstr ""
@@ -18189,6 +18854,15 @@ msgstr ""
msgid "Pipelines|This project is not currently set up to run pipelines."
msgstr ""
+msgid "Pipelines|Token"
+msgstr ""
+
+msgid "Pipelines|Trigger user has insufficient permissions to project"
+msgstr ""
+
+msgid "Pipelines|invalid"
+msgstr ""
+
msgid "Pipelines|parent"
msgstr ""
@@ -18447,10 +19121,10 @@ msgstr ""
msgid "Please provide attributes to update"
msgstr ""
-msgid "Please refer to %{docs_url}"
+msgid "Please reach out if you have any questions and we'll be happy to assist."
msgstr ""
-msgid "Please retype the email address."
+msgid "Please refer to %{docs_url}"
msgstr ""
msgid "Please select"
@@ -18480,6 +19154,9 @@ msgstr ""
msgid "Please set a new password before proceeding."
msgstr ""
+msgid "Please share your feedback about %{featureName} %{linkStart}in this issue%{linkEnd} to help us improve the experience."
+msgstr ""
+
msgid "Please solve the reCAPTCHA"
msgstr ""
@@ -18783,6 +19460,9 @@ msgstr ""
msgid "Profiles| You are going to change the username %{currentUsernameBold} to %{newUsernameBold}. Profile and projects will be redirected to the %{newUsername} namespace but this redirect will expire once the %{currentUsername} namespace is registered by another user or group. Please update your Git repository remotes as soon as possible."
msgstr ""
+msgid "Profiles|%{provider} Active"
+msgstr ""
+
msgid "Profiles|@username"
msgstr ""
@@ -18834,7 +19514,7 @@ msgstr ""
msgid "Profiles|Commit email"
msgstr ""
-msgid "Profiles|Connect"
+msgid "Profiles|Connect %{provider}"
msgstr ""
msgid "Profiles|Connected Accounts"
@@ -18858,6 +19538,9 @@ msgstr ""
msgid "Profiles|Disconnect"
msgstr ""
+msgid "Profiles|Disconnect %{provider}"
+msgstr ""
+
msgid "Profiles|Do not show on profile"
msgstr ""
@@ -18882,7 +19565,7 @@ msgstr ""
msgid "Profiles|Full name"
msgstr ""
-msgid "Profiles|Give your individual key a title. This will be publically visible."
+msgid "Profiles|Give your individual key a title."
msgstr ""
msgid "Profiles|Include private contributions on my profile"
@@ -18972,7 +19655,7 @@ msgstr ""
msgid "Profiles|The maximum file size allowed is 200KB."
msgstr ""
-msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it?"
+msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it? It will be publicly visible."
msgstr ""
msgid "Profiles|This email will be displayed on your public profile"
@@ -19047,6 +19730,9 @@ msgstr ""
msgid "Profiles|You don't have access to delete this user."
msgstr ""
+msgid "Profiles|You must transfer ownership or delete groups you are an owner of before you can delete your account"
+msgstr ""
+
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
@@ -19635,6 +20321,9 @@ msgstr ""
msgid "ProjectTemplates|GitLab Cluster Management"
msgstr ""
+msgid "ProjectTemplates|Gitpod/Spring Petclinic"
+msgstr ""
+
msgid "ProjectTemplates|Go Micro"
msgstr ""
@@ -20244,6 +20933,9 @@ msgstr ""
msgid "Publish to status page"
msgstr ""
+msgid "Published"
+msgstr ""
+
msgid "Published on status page"
msgstr ""
@@ -20361,9 +21053,15 @@ msgstr ""
msgid "Quick range"
msgstr ""
+msgid "Quickly and easily edit multiple files in your project."
+msgstr ""
+
msgid "README"
msgstr ""
+msgid "Rails"
+msgstr ""
+
msgid "Rake Tasks Help"
msgstr ""
@@ -20483,10 +21181,13 @@ msgstr ""
msgid "Register Two-Factor Authenticator"
msgstr ""
-msgid "Register U2F device"
+msgid "Register Universal Two-Factor (U2F) Device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register WebAuthn Device"
+msgstr ""
+
+msgid "Register device"
msgstr ""
msgid "Register for GitLab"
@@ -20498,9 +21199,6 @@ msgstr ""
msgid "Register with two-factor app"
msgstr ""
-msgid "Registration"
-msgstr ""
-
msgid "Registration|Checkout"
msgstr ""
@@ -20617,9 +21315,6 @@ msgstr ""
msgid "Release|Something went wrong while saving the release details"
msgstr ""
-msgid "Remediated: needs review"
-msgstr ""
-
msgid "Remediations"
msgstr ""
@@ -20725,6 +21420,9 @@ msgstr ""
msgid "Remove priority"
msgstr ""
+msgid "Remove report"
+msgstr ""
+
msgid "Remove secondary node"
msgstr ""
@@ -20737,6 +21435,12 @@ msgstr ""
msgid "Remove time estimate"
msgstr ""
+msgid "Remove user & report"
+msgstr ""
+
+msgid "Remove user from group"
+msgstr ""
+
msgid "Removed"
msgstr ""
@@ -20818,9 +21522,6 @@ msgstr ""
msgid "Removes time estimate."
msgstr ""
-msgid "Removing license…"
-msgstr ""
-
msgid "Removing this group also removes all child projects, including archived projects, and their resources."
msgstr ""
@@ -20905,6 +21606,9 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
+msgid "Reported by %{reporter}"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -20991,6 +21695,27 @@ msgstr ""
msgid "Repositories"
msgstr ""
+msgid "Repositories Analytics"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download Historic Test Coverage Data"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download historic test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Historic Test Coverage Data is available in raw format (.csv) for further analysis."
+msgstr ""
+
+msgid "RepositoriesAnalytics|Test Code Coverage"
+msgstr ""
+
+msgid "RepositoriesAnalytics|There was an error fetching the projects."
+msgstr ""
+
msgid "Repository"
msgstr ""
@@ -21069,9 +21794,15 @@ msgstr ""
msgid "Request parameter %{param} is missing."
msgstr ""
+msgid "Request review from"
+msgstr ""
+
msgid "Request to link SAML account must be authorized"
msgstr ""
+msgid "Requested"
+msgstr ""
+
msgid "Requested %{time_ago}"
msgstr ""
@@ -21090,6 +21821,9 @@ msgstr ""
msgid "Requests to these domain(s)/address(es) on the local network will be allowed when local requests from hooks and services are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 or 127.0.0.0/28 are supported. Domain wildcards are not supported currently. Use comma, semicolon, or newline to separate multiple entries. The allowlist can hold a maximum of 1000 entries. Domains should use IDNA encoding. Ex: example.com, 192.168.1.1, 127.0.0.0/28, xn--itlab-j1a.com."
msgstr ""
+msgid "Require admin approval for new sign-ups"
+msgstr ""
+
msgid "Require all users in this group to setup Two-factor authentication"
msgstr ""
@@ -21217,9 +21951,6 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
-msgid "Resolved by %{resolvedByName}"
-msgstr ""
-
msgid "Resolves IP addresses once and uses them to submit requests"
msgstr ""
@@ -21339,6 +22070,14 @@ msgstr ""
msgid "ReviewApp|Enable Review App"
msgstr ""
+msgid "Reviewer"
+msgid_plural "%d Reviewers"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Reviewer(s)"
+msgstr ""
+
msgid "Reviewing"
msgstr ""
@@ -21378,6 +22117,9 @@ msgstr ""
msgid "Rook"
msgstr ""
+msgid "Ruby"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -21456,6 +22198,63 @@ msgstr ""
msgid "Runners page."
msgstr ""
+msgid "Runners|Active"
+msgstr ""
+
+msgid "Runners|Architecture"
+msgstr ""
+
+msgid "Runners|Can run untagged jobs"
+msgstr ""
+
+msgid "Runners|Description"
+msgstr ""
+
+msgid "Runners|Group"
+msgstr ""
+
+msgid "Runners|IP Address"
+msgstr ""
+
+msgid "Runners|Last contact"
+msgstr ""
+
+msgid "Runners|Locked to this project"
+msgstr ""
+
+msgid "Runners|Maximum job timeout"
+msgstr ""
+
+msgid "Runners|Name"
+msgstr ""
+
+msgid "Runners|Platform"
+msgstr ""
+
+msgid "Runners|Property Name"
+msgstr ""
+
+msgid "Runners|Protected"
+msgstr ""
+
+msgid "Runners|Revision"
+msgstr ""
+
+msgid "Runners|Shared"
+msgstr ""
+
+msgid "Runners|Specific"
+msgstr ""
+
+msgid "Runners|Tags"
+msgstr ""
+
+msgid "Runners|Value"
+msgstr ""
+
+msgid "Runners|Version"
+msgstr ""
+
msgid "Runners|You have used %{quotaUsed} out of %{quotaLimit} of your shared Runners pipeline minutes."
msgstr ""
@@ -21468,6 +22267,9 @@ msgstr ""
msgid "Runs a number of housekeeping tasks within the current repository, such as compressing file revisions and removing unreachable objects."
msgstr ""
+msgid "SAML"
+msgstr ""
+
msgid "SAML SSO"
msgstr ""
@@ -21519,6 +22321,9 @@ msgstr ""
msgid "Save"
msgstr ""
+msgid "Save %{name} size limits"
+msgstr ""
+
msgid "Save Changes"
msgstr ""
@@ -21549,9 +22354,6 @@ msgstr ""
msgid "Save space and find tags in the Container Registry more easily. Enable the cleanup policy to remove stale tags and keep only the ones you need."
msgstr ""
-msgid "Save template"
-msgstr ""
-
msgid "Save variables"
msgstr ""
@@ -21594,9 +22396,6 @@ msgstr ""
msgid "Scope"
msgstr ""
-msgid "Scope not supported with disabled 'users_search' feature!"
-msgstr ""
-
msgid "Scoped issue boards"
msgstr ""
@@ -21723,9 +22522,6 @@ msgstr ""
msgid "Search requirements"
msgstr ""
-msgid "Search results…"
-msgstr ""
-
msgid "Search users"
msgstr ""
@@ -21798,6 +22594,11 @@ msgid_plural "SearchResults|commits"
msgstr[0] ""
msgstr[1] ""
+msgid "SearchResults|epic"
+msgid_plural "SearchResults|epics"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "SearchResults|issue"
msgid_plural "SearchResults|issues"
msgstr[0] ""
@@ -21842,10 +22643,10 @@ msgstr ""
msgid "Seat Link is disabled, and cannot be configured through this form."
msgstr ""
-msgid "Seats currently in use"
+msgid "Seats usage data as of %{last_enqueue_time}"
msgstr ""
-msgid "Seats in license"
+msgid "Seats usage data is updated every day at 12:00pm UTC"
msgstr ""
msgid "Secondary"
@@ -21899,6 +22700,9 @@ msgstr ""
msgid "SecurityConfiguration|Available for on-demand DAST"
msgstr ""
+msgid "SecurityConfiguration|By default, all analyzers are applied in order to cover all languages across your project, and only run if the language is detected in the Merge Request."
+msgstr ""
+
msgid "SecurityConfiguration|Configure"
msgstr ""
@@ -21929,16 +22733,19 @@ msgstr ""
msgid "SecurityConfiguration|Manage"
msgstr ""
+msgid "SecurityConfiguration|More information"
+msgstr ""
+
msgid "SecurityConfiguration|Not enabled"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|Security Control"
+msgid "SecurityConfiguration|SAST Configuration"
msgstr ""
-msgid "SecurityConfiguration|See documentation"
+msgid "SecurityConfiguration|Security Control"
msgstr ""
msgid "SecurityConfiguration|Status"
@@ -21950,6 +22757,9 @@ msgstr ""
msgid "SecurityConfiguration|Using custom settings. You won't receive automatic updates on this variable. %{anchorStart}Restore to default%{anchorEnd}"
msgstr ""
+msgid "SecurityConfiguration|View history"
+msgstr ""
+
msgid "SecurityConfiguration|You can quickly enable all security scanning tools by enabling %{linkStart}Auto DevOps%{linkEnd}."
msgstr ""
@@ -22028,9 +22838,6 @@ msgstr ""
msgid "SecurityReports|Learn more about setting up your dashboard"
msgstr ""
-msgid "SecurityReports|Load more vulnerabilities"
-msgstr ""
-
msgid "SecurityReports|Monitor vulnerabilities in your code"
msgstr ""
@@ -22310,7 +23117,7 @@ msgstr ""
msgid "Select status"
msgstr ""
-msgid "Select strategy activation method"
+msgid "Select strategy activation method."
msgstr ""
msgid "Select subscription"
@@ -22325,7 +23132,7 @@ msgstr ""
msgid "Select the custom project template source group."
msgstr ""
-msgid "Select timeframe"
+msgid "Select the environment scope for this feature flag."
msgstr ""
msgid "Select timezone"
@@ -22574,6 +23381,9 @@ msgstr ""
msgid "Set iteration"
msgstr ""
+msgid "Set limit to 0 to allow any file size."
+msgstr ""
+
msgid "Set max session time for web terminal."
msgstr ""
@@ -22652,10 +23462,13 @@ msgstr ""
msgid "Set up a %{type} Runner manually"
msgstr ""
+msgid "Set up a hardware device as a second factor to sign in."
+msgstr ""
+
msgid "Set up assertions/attributes/claims (email, first_name, last_name) and NameID according to %{docsLinkStart}the documentation %{icon}%{docsLinkEnd}"
msgstr ""
-msgid "Set up new U2F device"
+msgid "Set up new device"
msgstr ""
msgid "Set up new password"
@@ -22724,6 +23537,9 @@ msgstr ""
msgid "Sets weight to %{weight}."
msgstr ""
+msgid "Setting this to 0 means using the system default timeout value."
+msgstr ""
+
msgid "Settings"
msgstr ""
@@ -22739,6 +23555,15 @@ msgstr ""
msgid "Severity"
msgstr ""
+msgid "SeverityWidget|Severity"
+msgstr ""
+
+msgid "SeverityWidget|Severity: %{severity}"
+msgstr ""
+
+msgid "SeverityWidget|There was an error while updating severity."
+msgstr ""
+
msgid "Shards (%{shards})"
msgstr ""
@@ -22784,6 +23609,9 @@ msgstr ""
msgid "Show all requirements."
msgstr ""
+msgid "Show all test cases."
+msgstr ""
+
msgid "Show archived projects"
msgstr ""
@@ -22796,6 +23624,9 @@ msgstr ""
msgid "Show comments"
msgstr ""
+msgid "Show comments on this file"
+msgstr ""
+
msgid "Show comments only"
msgstr ""
@@ -22841,6 +23672,12 @@ msgstr ""
msgid "Show parent subgroups"
msgstr ""
+msgid "Show the Closed list"
+msgstr ""
+
+msgid "Show the Open list"
+msgstr ""
+
msgid "Show whitespace changes"
msgstr ""
@@ -22884,9 +23721,6 @@ msgstr ""
msgid "Sidebar|Assign health status"
msgstr ""
-msgid "Sidebar|Change weight"
-msgstr ""
-
msgid "Sidebar|Health status"
msgstr ""
@@ -23070,6 +23904,9 @@ msgstr ""
msgid "Snippets|Add another file %{num}/%{total}"
msgstr ""
+msgid "Snippets|Authored %{time_ago} by %{author}"
+msgstr ""
+
msgid "Snippets|Delete file"
msgstr ""
@@ -23097,6 +23934,9 @@ msgstr ""
msgid "Solution"
msgstr ""
+msgid "Some changes are not shown"
+msgstr ""
+
msgid "Some child epics may be hidden due to applied filters"
msgstr ""
@@ -23463,6 +24303,12 @@ msgstr ""
msgid "Source (branch or tag)"
msgstr ""
+msgid "Source Branch"
+msgstr ""
+
+msgid "Source branch: %{source_branch_open}%{source_branch}%{source_branch_close}"
+msgstr ""
+
msgid "Source code"
msgstr ""
@@ -23628,9 +24474,6 @@ msgstr ""
msgid "Start and due date"
msgstr ""
-msgid "Start by choosing a group to see how your team is spending time. You can then drill down to the project level."
-msgstr ""
-
msgid "Start by choosing a group to start exploring the merge requests in that group. You can then proceed to filter by projects, labels, milestones and authors."
msgstr ""
@@ -23712,18 +24555,27 @@ msgstr ""
msgid "StaticSiteEditor|3. Assign a person to review and accept the merge request."
msgstr ""
+msgid "StaticSiteEditor|A link to view the merge request will appear once ready."
+msgstr ""
+
msgid "StaticSiteEditor|An error occurred while submitting your changes."
msgstr ""
msgid "StaticSiteEditor|Branch could not be created."
msgstr ""
+msgid "StaticSiteEditor|Copy update"
+msgstr ""
+
msgid "StaticSiteEditor|Could not commit the content changes."
msgstr ""
msgid "StaticSiteEditor|Could not create merge request."
msgstr ""
+msgid "StaticSiteEditor|Creating your merge request"
+msgstr ""
+
msgid "StaticSiteEditor|Incompatible file content"
msgstr ""
@@ -23745,6 +24597,9 @@ msgstr ""
msgid "StaticSiteEditor|View documentation"
msgstr ""
+msgid "StaticSiteEditor|You can set an assignee to get your changes reviewed and deployed once your merge request is created."
+msgstr ""
+
msgid "StaticSiteEditor|Your merge request has been created"
msgstr ""
@@ -23874,15 +24729,15 @@ msgstr ""
msgid "Submit %{humanized_resource_name}"
msgstr ""
-msgid "Submit Changes"
-msgstr ""
-
msgid "Submit a review"
msgstr ""
msgid "Submit as spam"
msgstr ""
+msgid "Submit changes"
+msgstr ""
+
msgid "Submit feedback"
msgstr ""
@@ -24036,6 +24891,9 @@ msgstr ""
msgid "Successfully deleted U2F device."
msgstr ""
+msgid "Successfully deleted WebAuthn device."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -24354,9 +25212,6 @@ msgstr ""
msgid "Template to append to all Service Desk issues"
msgstr ""
-msgid "Template was successfully saved."
-msgstr ""
-
msgid "Templates"
msgstr ""
@@ -24435,10 +25290,28 @@ msgid_plural "Test coverage: %d hits"
msgstr[0] ""
msgstr[1] ""
-msgid "Test failed."
+msgid "Test settings"
msgstr ""
-msgid "Test settings and save changes"
+msgid "TestCases|New Test Case"
+msgstr ""
+
+msgid "TestCases|New test case"
+msgstr ""
+
+msgid "TestCases|Search test cases"
+msgstr ""
+
+msgid "TestCases|Something went wrong while creating a test case."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching count of test cases."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching test cases list."
+msgstr ""
+
+msgid "TestCases|Submit test case"
msgstr ""
msgid "TestHooks|Ensure one of your projects has merge requests."
@@ -24504,6 +25377,9 @@ msgstr ""
msgid "Thank you for signing up for your free trial! You will get additional instructions in your inbox shortly."
msgstr ""
+msgid "Thank you for your business."
+msgstr ""
+
msgid "Thank you for your feedback!"
msgstr ""
@@ -24563,9 +25439,6 @@ msgstr ""
msgid "The URL to use for connecting to Elasticsearch. Use a comma-separated list to support clustering (e.g., \"http://localhost:9200, http://localhost:9201\")."
msgstr ""
-msgid "The Web IDE offers advanced syntax highlighting capabilities and more."
-msgstr ""
-
msgid "The X509 Certificate to use when mutual TLS is required to communicate with the external authorization service. If left blank, the server certificate is still validated when accessing over HTTPS."
msgstr ""
@@ -24676,6 +25549,9 @@ msgstr ""
msgid "The form contains the following error:"
msgstr ""
+msgid "The form contains the following warning:"
+msgstr ""
+
msgid "The global settings require you to enable Two-Factor Authentication for your account."
msgstr ""
@@ -24790,9 +25666,6 @@ msgstr ""
msgid "The private key to use when a client certificate is provided. This value is encrypted at rest."
msgstr ""
-msgid "The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The project can be accessed by any logged in user."
msgstr ""
@@ -24829,7 +25702,7 @@ msgstr ""
msgid "The remote repository is being updated..."
msgstr ""
-msgid "The repository can be commited to, and issues, comments and other entities can be created."
+msgid "The repository can be committed to, and issues, comments and other entities can be created."
msgstr ""
msgid "The repository for this project does not exist."
@@ -24883,9 +25756,6 @@ msgstr ""
msgid "The time taken by each data entry gathered by that stage."
msgstr ""
-msgid "The total stage shows the time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The update action will time out after %{number_of_minutes} minutes. For big repositories, use a clone/push combination."
msgstr ""
@@ -24949,6 +25819,9 @@ msgstr ""
msgid "There are no archived requirements"
msgstr ""
+msgid "There are no archived test cases"
+msgstr ""
+
msgid "There are no changes"
msgstr ""
@@ -24988,6 +25861,9 @@ msgstr ""
msgid "There are no open requirements"
msgstr ""
+msgid "There are no open test cases"
+msgstr ""
+
msgid "There are no packages yet"
msgstr ""
@@ -25000,6 +25876,9 @@ msgstr ""
msgid "There is a limit of %{ci_project_subscriptions_limit} subscriptions from or to a project."
msgstr ""
+msgid "There is already a To-Do for this design."
+msgstr ""
+
msgid "There is already a repository with that name on disk"
msgstr ""
@@ -25018,6 +25897,9 @@ msgstr ""
msgid "There was a problem communicating with your device."
msgstr ""
+msgid "There was a problem fetching branches."
+msgstr ""
+
msgid "There was a problem fetching groups."
msgstr ""
@@ -25246,9 +26128,15 @@ msgstr ""
msgid "This action can lead to data loss. To prevent accidental actions we ask you to confirm your intention."
msgstr ""
+msgid "This action cannot be undone, and will permanently delete the %{key} SSH key"
+msgstr ""
+
msgid "This action cannot be undone. You will lose the project's repository and all content: issues, merge requests, etc."
msgstr ""
+msgid "This action has been performed too many times. Try again later."
+msgstr ""
+
msgid "This action will %{strongOpen}permanently delete%{strongClose} %{codeOpen}%{project}%{codeClose} %{strongOpen}immediately%{strongClose}, including its repositories and all content: issues, merge requests, etc."
msgstr ""
@@ -25276,9 +26164,6 @@ msgstr ""
msgid "This board's scope is reduced"
msgstr ""
-msgid "This branch has changed since you started editing. Would you like to create a new branch?"
-msgstr ""
-
msgid "This chart could not be displayed"
msgstr ""
@@ -25405,15 +26290,9 @@ msgstr ""
msgid "This is a security log of important events involving your account."
msgstr ""
-msgid "This is the author's first Merge Request to this project."
-msgstr ""
-
msgid "This is the highest peak of users on your installation since the license started."
msgstr ""
-msgid "This is the maximum number of users that have existed at the same time since the license started. This is the minimum number of seats you will need to buy when you renew your license."
-msgstr ""
-
msgid "This is the number of currently active users on your installation, and this is the minimum number you need to purchase when you renew your license."
msgstr ""
@@ -25645,6 +26524,15 @@ msgstr ""
msgid "This user has no identities"
msgstr ""
+msgid "This user has previously committed to the %{name} project."
+msgstr ""
+
+msgid "This user has the %{access} role in the %{name} project."
+msgstr ""
+
+msgid "This user is the author of this %{noteable}."
+msgstr ""
+
msgid "This user will be the author of all events in the activity feed that are the result of an update, like new branches being created or new commits being pushed to existing branches."
msgstr ""
@@ -25675,6 +26563,9 @@ msgstr ""
msgid "Threat Monitoring"
msgstr ""
+msgid "ThreatMonitoring|All Environments"
+msgstr ""
+
msgid "ThreatMonitoring|Anomalous Requests"
msgstr ""
@@ -25702,9 +26593,6 @@ msgstr ""
msgid "ThreatMonitoring|Operations Per Second"
msgstr ""
-msgid "ThreatMonitoring|Overview"
-msgstr ""
-
msgid "ThreatMonitoring|Packet Activity"
msgstr ""
@@ -25723,6 +26611,9 @@ msgstr ""
msgid "ThreatMonitoring|Something went wrong, unable to fetch statistics"
msgstr ""
+msgid "ThreatMonitoring|Statistics"
+msgstr ""
+
msgid "ThreatMonitoring|The firewall is not installed or has been disabled. To view this data, ensure the web application firewall is installed and enabled for your cluster."
msgstr ""
@@ -26114,6 +27005,9 @@ msgstr ""
msgid "To update Snippets with multiple files, you must use the `files` parameter"
msgstr ""
+msgid "To use Gitpod you must first enable the feature in the integrations section of your %{user_prefs}."
+msgstr ""
+
msgid "To view all %{scannedResourcesCount} scanned URLs, please download the CSV file"
msgstr ""
@@ -26147,9 +27041,6 @@ msgstr ""
msgid "Toggle Sidebar"
msgstr ""
-msgid "Toggle all threads"
-msgstr ""
-
msgid "Toggle backtrace"
msgstr ""
@@ -26174,9 +27065,6 @@ msgstr ""
msgid "Toggle navigation"
msgstr ""
-msgid "Toggle project"
-msgstr ""
-
msgid "Toggle sidebar"
msgstr ""
@@ -26216,6 +27104,9 @@ msgstr ""
msgid "Too many projects enabled. You will need to manage them via the console or the API."
msgstr ""
+msgid "Too much data"
+msgstr ""
+
msgid "Topics (optional)"
msgstr ""
@@ -26234,6 +27125,9 @@ msgstr ""
msgid "Total cores (CPUs)"
msgstr ""
+msgid "Total days to completion"
+msgstr ""
+
msgid "Total issues"
msgstr ""
@@ -26330,6 +27224,9 @@ msgstr ""
msgid "Trending"
msgstr ""
+msgid "Trials|Create a new group to start your GitLab Gold trial."
+msgstr ""
+
msgid "Trials|Go back to GitLab"
msgstr ""
@@ -26339,6 +27236,15 @@ msgstr ""
msgid "Trials|You can always resume this process by selecting your avatar and choosing 'Start a Gold trial'"
msgstr ""
+msgid "Trials|You can apply your trial to a new group or an existing group."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group or your personal account."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group, an existing group, or your personal account."
+msgstr ""
+
msgid "Trials|You won't get a free trial right now but you can always resume this process by clicking on your avatar and choosing 'Start a free trial'"
msgstr ""
@@ -26408,6 +27314,9 @@ msgstr ""
msgid "Try using a different search term to find the file you are looking for."
msgstr ""
+msgid "Trying to communicate with your device. Plug it in (if needed) and press the button on the device now."
+msgstr ""
+
msgid "Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now."
msgstr ""
@@ -26495,6 +27404,12 @@ msgstr ""
msgid "URL or request ID"
msgstr ""
+msgid "USER %{user} WILL BE REMOVED! Are you sure?"
+msgstr ""
+
+msgid "USER WILL BE BLOCKED! Are you sure?"
+msgstr ""
+
msgid "UTC"
msgstr ""
@@ -26552,9 +27467,6 @@ msgstr ""
msgid "Unable to load the merge request widget. Try reloading the page."
msgstr ""
-msgid "Unable to resolve"
-msgstr ""
-
msgid "Unable to save iteration. Please try again"
msgstr ""
@@ -26603,6 +27515,9 @@ msgstr ""
msgid "Undo ignore"
msgstr ""
+msgid "Unexpected error"
+msgstr ""
+
msgid "Unfortunately, your email message to GitLab could not be processed."
msgstr ""
@@ -26636,6 +27551,9 @@ msgstr ""
msgid "Unknown response text"
msgstr ""
+msgid "Unless otherwise agreed to in writing with GitLab, by clicking \"Upload License\" you agree that your use of GitLab Software is subject to the %{eula_link_start}Terms of Service%{eula_link_end}."
+msgstr ""
+
msgid "Unlimited"
msgstr ""
@@ -27002,9 +27920,6 @@ msgstr ""
msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
msgstr ""
-msgid "Use a hardware device to add the second factor of authentication."
-msgstr ""
-
msgid "Use an one time password authenticator on your mobile device or computer to enable two-factor authentication (2FA)."
msgstr ""
@@ -27278,13 +28193,13 @@ msgstr ""
msgid "Users"
msgstr ""
-msgid "Users in License:"
+msgid "Users in License"
msgstr ""
-msgid "Users or groups set as approvers in the project's or merge request's settings."
+msgid "Users in License:"
msgstr ""
-msgid "Users outside of license"
+msgid "Users or groups set as approvers in the project's or merge request's settings."
msgstr ""
msgid "Users over License:"
@@ -27302,9 +28217,6 @@ msgstr ""
msgid "Users with a Guest role or those who don't belong to a Project or Group will not use a seat from your license."
msgstr ""
-msgid "Users with a Guest role or those who don't belong to any projects or groups don't count towards seats in use."
-msgstr ""
-
msgid "UsersSelect|%{name} + %{length} more"
msgstr ""
@@ -27344,9 +28256,6 @@ msgstr ""
msgid "Validations failed."
msgstr ""
-msgid "Validity"
-msgstr ""
-
msgid "Value"
msgstr ""
@@ -27365,6 +28274,9 @@ msgstr ""
msgid "Value Stream Name"
msgstr ""
+msgid "ValueStreamAnalyticsStage|We don't have enough data to show this stage."
+msgstr ""
+
msgid "ValueStreamAnalytics|%{days}d"
msgstr ""
@@ -27621,6 +28533,9 @@ msgstr ""
msgid "VisualReviewApp|Steps 1 and 2 (and sometimes 3) are performed once by the developer before requesting feedback. Steps 3 (if necessary), 4 is performed by the reviewer each time they perform a review."
msgstr ""
+msgid "Visualization"
+msgstr ""
+
msgid "Vulnerabilities"
msgstr ""
@@ -27648,34 +28563,31 @@ msgstr ""
msgid "VulnerabilityChart|Severity"
msgstr ""
-msgid "VulnerabilityManagement|A true-positive and will fix"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Change status"
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|Confirm"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Confirmed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
-msgstr ""
-
-msgid "VulnerabilityManagement|Detected %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|A true-positive and will fix"
msgstr ""
-msgid "VulnerabilityManagement|Dismiss"
+msgid "VulnerabilityManagement|Change status"
msgstr ""
-msgid "VulnerabilityManagement|Dismissed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
msgstr ""
-msgid "VulnerabilityManagement|Resolved"
+msgid "VulnerabilityManagement|Detected"
msgstr ""
-msgid "VulnerabilityManagement|Resolved %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Needs triage"
msgstr ""
msgid "VulnerabilityManagement|Something went wrong while trying to delete the comment. Please try again later."
@@ -27726,6 +28638,9 @@ msgstr ""
msgid "Vulnerability|%{scannerName} (version %{scannerVersion})"
msgstr ""
+msgid "Vulnerability|Activity"
+msgstr ""
+
msgid "Vulnerability|Class"
msgstr ""
@@ -27738,6 +28653,9 @@ msgstr ""
msgid "Vulnerability|Description"
msgstr ""
+msgid "Vulnerability|Detected"
+msgstr ""
+
msgid "Vulnerability|Evidence"
msgstr ""
@@ -27801,6 +28719,9 @@ msgstr ""
msgid "Warning: Displaying this diagram might cause performance issues on this page."
msgstr ""
+msgid "We are currently unable to fetch data for the pipeline header."
+msgstr ""
+
msgid "We are currently unable to fetch data for this graph."
msgstr ""
@@ -27840,6 +28761,12 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
+msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
+msgstr ""
+
+msgid "We would like to inform you that your subscription GitLab Enterprise Edition %{plan_name} is nearing its user limit. You have %{active_user_count} active users, which is almost at the user limit of %{maximum_user_count}."
+msgstr ""
+
msgid "We've found no vulnerabilities"
msgstr ""
@@ -27855,6 +28782,12 @@ msgstr ""
msgid "Web terminal"
msgstr ""
+msgid "WebAuthn Devices (%{length})"
+msgstr ""
+
+msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
+msgstr ""
+
msgid "WebIDE|Merge request"
msgstr ""
@@ -27993,15 +28926,9 @@ msgstr ""
msgid "Welcome to the guided GitLab tour"
msgstr ""
-msgid "Welcome to your Issue Board!"
-msgstr ""
-
msgid "Welcome to your issue board!"
msgstr ""
-msgid "We’ve been making changes to %{featureName} and we’d love your feedback %{linkStart}in this issue%{linkEnd} to help us improve the experience."
-msgstr ""
-
msgid "What are you searching for?"
msgstr ""
@@ -28020,6 +28947,9 @@ msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
msgstr ""
+msgid "When enabled, any user visiting %{host} and creating an account will have to be explicitly approved by the admin before they can login. This setting is effective only if sign-ups are enabled."
+msgstr ""
+
msgid "When enabled, any user visiting %{host} will be able to create an account."
msgstr ""
@@ -28244,6 +29174,9 @@ msgstr ""
msgid "With requirements, you can set criteria to check your products against."
msgstr ""
+msgid "With test cases, you can define conditions for your project to meet in determining quality"
+msgstr ""
+
msgid "Withdraw Access Request"
msgstr ""
@@ -28259,6 +29192,9 @@ msgstr ""
msgid "Workflow Help"
msgstr ""
+msgid "Would you like to create a new branch?"
+msgstr ""
+
msgid "Write"
msgstr ""
@@ -28280,6 +29216,9 @@ msgstr ""
msgid "Wrong extern UID provided. Make sure Auth0 is configured correctly."
msgstr ""
+msgid "YYYY-MM-DD"
+msgstr ""
+
msgid "Yes"
msgstr ""
@@ -28337,7 +29276,7 @@ msgstr ""
msgid "You are going to remove the fork relationship from %{project_full_name}. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "You are going to transfer %{project_full_name} to another owner. Are you ABSOLUTELY sure?"
+msgid "You are going to transfer %{project_full_name} to another namespace. Are you ABSOLUTELY sure?"
msgstr ""
msgid "You are going to turn off the confidentiality. This means %{strongStart}everyone%{strongEnd} will be able to see and leave a comment on this %{issuableType}."
@@ -28397,9 +29336,6 @@ msgstr ""
msgid "You can always edit this later"
msgstr ""
-msgid "You can apply your Trial to your Personal account or create a New Group."
-msgstr ""
-
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings"
msgstr ""
@@ -28421,12 +29357,18 @@ msgstr ""
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
+msgid "You can find more information about GitLab subscriptions in %{subscriptions_doc_link}."
+msgstr ""
+
msgid "You can generate an access token scoped to this project for each application to use the GitLab API."
msgstr ""
msgid "You can get started by cloning the repository or start adding files to it with one of the following options."
msgstr ""
+msgid "You can group test cases using labels. To learn about the future direction of this feature, visit %{linkStart}Quality Management direction page%{linkEnd}."
+msgstr ""
+
msgid "You can invite a new member to %{project_name} or invite another group."
msgstr ""
@@ -28442,6 +29384,9 @@ msgstr ""
msgid "You can notify the app / group or a project by sending them an email notification"
msgstr ""
+msgid "You can now close this window."
+msgstr ""
+
msgid "You can now export your security dashboard to a CSV report."
msgstr ""
@@ -28490,9 +29435,6 @@ msgstr ""
msgid "You can test your .gitlab-ci.yml in %{linkStart}CI Lint%{linkEnd}."
msgstr ""
-msgid "You can try again using %{begin_link}basic search%{end_link}"
-msgstr ""
-
msgid "You cannot access the raw file. Please wait a minute."
msgstr ""
@@ -28544,6 +29486,9 @@ msgstr ""
msgid "You don't have any U2F devices registered yet."
msgstr ""
+msgid "You don't have any WebAuthn devices registered yet."
+msgstr ""
+
msgid "You don't have any active chat names."
msgstr ""
@@ -28631,6 +29576,9 @@ msgstr ""
msgid "You must accept our Terms of Service and privacy policy in order to register an account"
msgstr ""
+msgid "You must be logged in to search across all of GitLab"
+msgstr ""
+
msgid "You must disassociate %{domain} from all clusters it is attached to before deletion."
msgstr ""
@@ -28670,7 +29618,7 @@ msgstr ""
msgid "You need to be logged in."
msgstr ""
-msgid "You need to register a two-factor authentication app before you can set up a U2F device."
+msgid "You need to register a two-factor authentication app before you can set up a device."
msgstr ""
msgid "You need to set terms to be enforced"
@@ -28688,6 +29636,9 @@ msgstr ""
msgid "You reached %{usage_in_percent} of %{namespace_name}'s storage capacity (%{used_storage} of %{storage_limit})"
msgstr ""
+msgid "You successfully declined the invitation"
+msgstr ""
+
msgid "You tried to fork %{link_to_the_project} but it failed for the following reason:"
msgstr ""
@@ -28853,10 +29804,13 @@ msgstr ""
msgid "Your U2F device did not send a valid JSON response."
msgstr ""
-msgid "Your U2F device needs to be set up. Plug it in (if not already) and click the button on the left."
+msgid "Your U2F device was registered!"
msgstr ""
-msgid "Your U2F device was registered!"
+msgid "Your WebAuthn device did not send a valid JSON response."
+msgstr ""
+
+msgid "Your WebAuthn device was registered!"
msgstr ""
msgid "Your access request to the %{source_type} has been withdrawn."
@@ -28880,6 +29834,9 @@ msgstr ""
msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
msgstr ""
+msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
+msgstr ""
+
msgid "Your changes can be committed to %{branch_name} because a merge request is open."
msgstr ""
@@ -28916,6 +29873,12 @@ msgstr ""
msgid "Your deployment services will be broken, you will need to manually fix the services after renaming."
msgstr ""
+msgid "Your device is not compatible with GitLab. Please try another device"
+msgstr ""
+
+msgid "Your device needs to be set up. Plug it in (if needed) and click the button on the left."
+msgstr ""
+
msgid "Your device was successfully set up! Give it a name and register it with the GitLab server."
msgstr ""
@@ -29029,9 +29992,6 @@ msgstr[1] ""
msgid "access:"
msgstr ""
-msgid "activated"
-msgstr ""
-
msgid "added %{created_at_timeago}"
msgstr ""
@@ -29104,9 +30064,21 @@ msgstr ""
msgid "by %{user}"
msgstr ""
+msgid "cannot be a date in the past"
+msgstr ""
+
msgid "cannot be changed if a personal project has container registry tags."
msgstr ""
+msgid "cannot be changed if shared runners are enabled"
+msgstr ""
+
+msgid "cannot be enabled because parent group does not allow it"
+msgstr ""
+
+msgid "cannot be enabled because parent group has shared Runners disabled"
+msgstr ""
+
msgid "cannot be enabled unless all domains have TLS certificates"
msgstr ""
@@ -29152,7 +30124,7 @@ msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about SAST %{linkEndTag}"
msgstr ""
-msgid "ciReport|%{linkStartTag}Learn more about Secret Scanning %{linkEndTag}"
+msgid "ciReport|%{linkStartTag}Learn more about Secret Detection %{linkEndTag}"
msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about codequality reports %{linkEndTag}"
@@ -29467,9 +30439,6 @@ msgstr ""
msgid "error"
msgstr ""
-msgid "error code:"
-msgstr ""
-
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr ""
@@ -29491,6 +30460,9 @@ msgstr ""
msgid "failed to dismiss associated finding(id=%{finding_id}): %{message}"
msgstr ""
+msgid "failed to revert associated finding(id=%{finding_id}) to detected"
+msgstr ""
+
msgid "file"
msgid_plural "files"
msgstr[0] ""
@@ -30033,6 +31005,9 @@ msgstr ""
msgid "must be a root namespace"
msgstr ""
+msgid "must be a valid IPv4 or IPv6 address"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -30069,6 +31044,9 @@ msgstr ""
msgid "no expiration"
msgstr ""
+msgid "no name set"
+msgstr ""
+
msgid "no one can merge"
msgstr ""
@@ -30247,9 +31225,6 @@ msgstr ""
msgid "security Reports|There was an error creating the merge request"
msgstr ""
-msgid "settings saved, but not activated"
-msgstr ""
-
msgid "severity|Critical"
msgstr ""
@@ -30376,9 +31351,6 @@ msgstr ""
msgid "toggle collapse"
msgstr ""
-msgid "toggle dropdown"
-msgstr ""
-
msgid "triggered"
msgstr ""
@@ -30406,6 +31378,9 @@ msgstr ""
msgid "user avatar"
msgstr ""
+msgid "user preferences"
+msgstr ""
+
msgid "username"
msgstr ""
diff --git a/locale/nb_NO/gitlab.po b/locale/nb_NO/gitlab.po
index 3caafbd384b..fcf4129f398 100644
--- a/locale/nb_NO/gitlab.po
+++ b/locale/nb_NO/gitlab.po
@@ -14,90 +14,103 @@ msgstr ""
"X-Crowdin-Language: nb\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 6\n"
-"PO-Revision-Date: 2020-09-04 23:05\n"
+"PO-Revision-Date: 2020-10-02 18:44\n"
-msgid " %{start} to %{end}"
+msgid " %{project_name}#%{issue_iid} &middot; opened %{issue_created} by %{author}"
msgstr ""
+msgid " %{start} to %{end}"
+msgstr " %{start} til %{end}"
+
msgid " (from %{timeoutSource})"
-msgstr ""
+msgstr " (fra %{timeoutSource})"
msgid " Collected %{time}"
-msgstr ""
+msgstr " Samlet inn %{time}"
msgid " Please sign in."
-msgstr ""
+msgstr " Vennligst logg inn."
msgid " Try to %{action} this file again."
-msgstr ""
+msgstr " Prøv å %{action} denne filen igjen."
msgid " You need to do this before %{grace_period_deadline}."
-msgstr ""
+msgstr " Du er nødt til at gjøre dette, før %{grace_period_deadline}."
msgid " and"
-msgstr ""
+msgstr "og"
msgid " and "
-msgstr ""
+msgstr " og "
msgid " and %{sliced}"
-msgstr ""
+msgstr " og %{sliced}"
msgid " degraded on %d point"
msgid_plural " degraded on %d points"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] " dårligere på %d punkt"
+msgstr[1] " dårligere på %d punkter"
msgid " improved on %d point"
msgid_plural " improved on %d points"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] " forbedret på %d punkt"
+msgstr[1] " forbedret på %d punkter"
msgid " or "
-msgstr ""
+msgstr " eller "
msgid " or %{emphasisStart}!merge request id%{emphasisEnd}"
-msgstr ""
+msgstr " eller %{emphasisStart}!fletteforespørsels-id%{emphasisEnd}"
msgid " or %{emphasisStart}#issue id%{emphasisEnd}"
-msgstr ""
+msgstr " eller %{emphasisStart}#saks-id%{emphasisEnd}"
msgid " or %{emphasisStart}&epic id%{emphasisEnd}"
-msgstr ""
+msgstr " eller %{emphasisStart}#epos-id%{emphasisEnd}"
msgid " or references (e.g. path/to/project!merge_request_id)"
-msgstr ""
+msgstr " eller referanser (f.eks. filbane/til/prosjekt!merge_request_id)"
msgid "\"%{path}\" did not exist on \"%{ref}\""
-msgstr ""
+msgstr "\"%{path}\" finness ikke på \"%{ref}\""
msgid "\"el\" parameter is required for createInstance()"
-msgstr ""
+msgstr "\"el\"-parameteret er påkrevd for createInstance()"
-msgid "%d Scanned URL"
-msgid_plural "%d Scanned URLs"
+msgid "%d Approval"
+msgid_plural "%d Approvals"
msgstr[0] ""
msgstr[1] ""
-msgid "%d URL scanned"
-msgid_plural "%d URLs scanned"
+msgid "%d Package"
+msgid_plural "%d Packages"
msgstr[0] ""
msgstr[1] ""
+msgid "%d Scanned URL"
+msgid_plural "%d Scanned URLs"
+msgstr[0] "%d skannet URL"
+msgstr[1] "%d skannede URL-er"
+
+msgid "%d URL scanned"
+msgid_plural "%d URLs scanned"
+msgstr[0] "%d URL skannet"
+msgstr[1] "%d URLer skannet"
+
msgid "%d approver"
msgid_plural "%d approvers"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%d godkjenner"
+msgstr[1] "%d godkjennere"
msgid "%d approver (you've approved)"
msgid_plural "%d approvers (you've approved)"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%d godkjenner (du har godkjent)"
+msgstr[1] "%d godkjennere (du har godkjent)"
msgid "%d changed file"
msgid_plural "%d changed files"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%d endret fil"
+msgstr[1] "%d endret filer"
msgid "%d child epic"
msgid_plural "%d child epics"
@@ -106,303 +119,339 @@ msgstr[1] ""
msgid "%d code quality issue"
msgid_plural "%d code quality issues"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%d kodekvalitetsproblem"
+msgstr[1] "%d kodekvalitetsproblemer"
msgid "%d comment"
msgid_plural "%d comments"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%d kommentar"
+msgstr[1] "%d kommentarer"
msgid "%d comment on this commit"
msgid_plural "%d comments on this commit"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%d kommentar på denne commiten"
+msgstr[1] "%d kommentarer på denne commiten"
msgid "%d commit"
msgid_plural "%d commits"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%d commit"
+msgstr[1] "%d commits"
msgid "%d commit behind"
msgid_plural "%d commits behind"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%d commit bak"
+msgstr[1] "%d commits bak"
msgid "%d commit,"
msgid_plural "%d commits,"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%d commit,"
+msgstr[1] "%d commits,"
msgid "%d commits"
-msgstr ""
+msgstr "%d commits"
-msgid "%d contribution"
-msgid_plural "%d contributions"
+msgid "%d completed issue"
+msgid_plural "%d completed issues"
msgstr[0] ""
msgstr[1] ""
+msgid "%d contribution"
+msgid_plural "%d contributions"
+msgstr[0] "%d bidrag"
+msgstr[1] "%d bidrag"
+
msgid "%d day"
msgid_plural "%d days"
+msgstr[0] "%d dag"
+msgstr[1] "%d dager"
+
+msgid "%d day until tags are automatically removed"
+msgid_plural "%d days until tags are automatically removed"
msgstr[0] ""
msgstr[1] ""
msgid "%d error"
msgid_plural "%d errors"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%d feil"
+msgstr[1] "%d feil"
msgid "%d exporter"
msgid_plural "%d exporters"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%d exporter"
+msgstr[1] "%d exporters"
msgid "%d failed"
msgid_plural "%d failed"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%d mislyktes"
+msgstr[1] "%d mislyktes"
msgid "%d fixed test result"
msgid_plural "%d fixed test results"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%d fikset testresultat"
+msgstr[1] "%d fiksede testresultater"
msgid "%d group selected"
msgid_plural "%d groups selected"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%d gruppe valgt"
+msgstr[1] "%d grupper valgt"
msgid "%d hour"
msgid_plural "%d hours"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%d time"
+msgstr[1] "%d timer"
msgid "%d inaccessible merge request"
msgid_plural "%d inaccessible merge requests"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%d utilgjengelig fletteforespørsel"
+msgstr[1] "%d utilgjengelige fletteforespørsler"
msgid "%d issue"
msgid_plural "%d issues"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%d problem"
+msgstr[1] "%d problemer"
msgid "%d issue in this group"
msgid_plural "%d issues in this group"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%d sak i denne gruppen"
+msgstr[1] "%d saker i denne gruppen"
msgid "%d issue selected"
msgid_plural "%d issues selected"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%d sak valgt"
+msgstr[1] "%d saker valgt"
msgid "%d issue successfully imported with the label"
msgid_plural "%d issues successfully imported with the label"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%d sak vellykket importert med stemplet"
+msgstr[1] "%d saker vellykket importert med stemplet"
msgid "%d layer"
msgid_plural "%d layers"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%d lag"
+msgstr[1] "%d lag"
msgid "%d merge request"
msgid_plural "%d merge requests"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%d fletteforespørsel"
+msgstr[1] "%d fletteforespørsler"
msgid "%d merge request that you don't have access to."
msgid_plural "%d merge requests that you don't have access to."
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%d fletteforespørsel som du ikke har tilgang til."
+msgstr[1] "%d fletteforespørsler som du ikke har tilgang til."
msgid "%d metric"
msgid_plural "%d metrics"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%d måltall"
+msgstr[1] "%d måltall"
msgid "%d milestone"
msgid_plural "%d milestones"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%d milepæl"
+msgstr[1] "%d milepæler"
msgid "%d minute"
msgid_plural "%d minutes"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%d minutter"
+msgstr[1] "%d minutter"
msgid "%d more comment"
msgid_plural "%d more comments"
+msgstr[0] "%d flere kommentarer"
+msgstr[1] "%d flere kommentarer"
+
+msgid "%d open issue"
+msgid_plural "%d open issues"
msgstr[0] ""
msgstr[1] ""
-msgid "%d personal project will be removed and cannot be restored."
-msgid_plural "%d personal projects will be removed and cannot be restored."
+msgid "%d pending comment"
+msgid_plural "%d pending comments"
msgstr[0] ""
msgstr[1] ""
+msgid "%d personal project will be removed and cannot be restored."
+msgid_plural "%d personal projects will be removed and cannot be restored."
+msgstr[0] "%d personlig prosjekt vil bli fjernet og kan ikke gjenopprettes."
+msgstr[1] "%d personlige prosjekter vil bli fjernet og kan ikke gjenopprettes."
+
msgid "%d previously merged commit"
msgid_plural "%d previously merged commits"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%d tidligere sammenslått commit"
+msgstr[1] "%d tidligere sammenslåtte commiter"
msgid "%d project"
msgid_plural "%d projects"
+msgstr[0] "%d prosjekt"
+msgstr[1] "%d prosjekter"
+
+msgid "%d project selected"
+msgid_plural "%d projects selected"
msgstr[0] ""
msgstr[1] ""
msgid "%d request with warnings"
msgid_plural "%d requests with warnings"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%d forespørsel med advarsler"
+msgstr[1] "%d forespørsler med advarsler"
msgid "%d second"
msgid_plural "%d seconds"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%d sekund"
+msgstr[1] "%d sekunder"
msgid "%d shard selected"
msgid_plural "%d shards selected"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%d skår valgt"
+msgstr[1] "%d skår valgt"
msgid "%d tag"
msgid_plural "%d tags"
+msgstr[0] "%d etikett"
+msgstr[1] "%d etiketter"
+
+msgid "%d tag per image name"
+msgid_plural "%d tags per image name"
msgstr[0] ""
msgstr[1] ""
msgid "%d unassigned issue"
msgid_plural "%d unassigned issues"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%d utildelt sak"
+msgstr[1] "%d utildelte saker"
msgid "%d unresolved thread"
msgid_plural "%d unresolved threads"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%d uoppklart tråd"
+msgstr[1] "%d uoppklarte tråder"
msgid "%d vulnerability"
msgid_plural "%d vulnerabilities"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%d sårbarhet"
+msgstr[1] "%d sårbarheter"
msgid "%d vulnerability dismissed"
msgid_plural "%d vulnerabilities dismissed"
+msgstr[0] "%d sårbarhet avvist"
+msgstr[1] "%d sårbarheter avvist"
+
+msgid "%d warning found:"
+msgid_plural "%d warnings found:"
msgstr[0] ""
msgstr[1] ""
msgid "%s additional commit has been omitted to prevent performance issues."
msgid_plural "%s additional commits have been omitted to prevent performance issues."
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%s ekstra commit er utelatt for å forhindre ytelsesproblemer."
+msgstr[1] "%s ekstra commiter er utelatt for å forhindre ytelsesproblemer."
msgid "%{actionText} & %{openOrClose} %{noteable}"
-msgstr ""
+msgstr "%{actionText} og %{openOrClose} %{noteable}"
msgid "%{address} is an invalid IP address range"
-msgstr ""
+msgstr "%{address} er et ugyldig IP-adresseområde"
msgid "%{author_link} wrote:"
-msgstr ""
+msgstr "%{author_link} skrev:"
msgid "%{authorsName}'s thread"
-msgstr ""
+msgstr "%{authorsName} sin tråd"
msgid "%{code_open}\"johnsmith@example.com\": \"@johnsmith\"%{code_close} will add \"By %{link_open}@johnsmith%{link_close}\" to all issues and comments originally created by johnsmith@example.com, and will set %{link_open}@johnsmith%{link_close} as the assignee on all issues originally assigned to johnsmith@example.com."
-msgstr ""
+msgstr "%{code_open}\"johnsmith@example.com\": \"@johnsmith\"%{code_close} vil legge til \"Av %{link_open}@johnsmith%{link_close}\" til alle saker og kommentarer opprinnelig opprettet av johnsmith@example.com, og vil sette %{link_open}@johnsmith%{link_close} som tildelt for alle saker som opprinnelig ble tildelt til johnsmith@example.com."
msgid "%{code_open}\"johnsmith@example.com\": \"John Smith\"%{code_close} will add \"By John Smith\" to all issues and comments originally created by johnsmith@example.com."
msgstr ""
msgid "%{code_open}\"johnsmith@example.com\": \"johnsm...@example.com\"%{code_close} will add \"By johnsm...@example.com\" to all issues and comments originally created by johnsmith@example.com. The email address or username is masked to ensure the user's privacy."
-msgstr ""
+msgstr "%{code_open}\"johnsmith@example.com\": \"johnsm...@example.com\"%{code_close} vil legge til \"Av @johnsm...@example.com\" til alle saker og kommentarer som opprinnelig ble opprettet av johnsmith@example.com. E-postadressen eller brukernavnet er maskert for å sikre brukerens privatliv."
msgid "%{code_open}\"johnsmith@example.com\": \"johnsmith@example.com\"%{code_close} will add \"By %{link_open}johnsmith@example.com%{link_close}\" to all issues and comments originally created by johnsmith@example.com. By default, the email address or username is masked to ensure the user's privacy. Use this option if you want to show the full email address."
-msgstr ""
+msgstr "%{code_open}\"johnsmith@example.com\": \"johnsmith@example.com\"%{code_close} vil legge til \"Av%{link_open}johnsmith@example.com%{link_close}\" til alle saker og kommentarer som opprinnelig ble opprettet av johnsmith@example.com. Som standard er e-postadressen eller brukernavnet maskert for å sikre brukerens privatliv. Bruk dette alternativet hvis du vil vise hele e-postadressen."
msgid "%{code_open}Masked%{code_close} variables are hidden in job logs (though they must match certain regexp requirements to do so)."
msgstr ""
msgid "%{code_open}Protected%{code_close} variables are only exposed to protected branches or tags."
-msgstr ""
+msgstr "%{code_open}Beskyttede%{code_close} variabler eksponeres bare for beskyttede grener eller etiketter."
msgid "%{commit_author_link} authored %{commit_timeago}"
+msgstr "%{commit_author_link} forfattet %{commit_timeago}"
+
+msgid "%{completedCount} completed weight"
msgstr ""
msgid "%{completedWeight} of %{totalWeight} weight completed"
-msgstr ""
+msgstr "%{completedWeight} av %{totalWeight} vektlegging fullført"
msgid "%{containerScanningLinkStart}Container Scanning%{containerScanningLinkEnd} and/or %{dependencyScanningLinkStart}Dependency Scanning%{dependencyScanningLinkEnd} must be enabled. %{securityBotLinkStart}GitLab-Security-Bot%{securityBotLinkEnd} will be the author of the auto-created merge request. %{moreInfoLinkStart}More information%{moreInfoLinkEnd}."
-msgstr ""
+msgstr "%{containerScanningLinkStart}Containerskanning%{containerScanningLinkEnd} og/eller %{dependencyScanningLinkStart}Avhengighetsskanning%{dependencyScanningLinkEnd} må være aktivert. %{securityBotLinkStart}GitLab-Security-Bot%{securityBotLinkEnd} vil være forfatteren av den automatisk opprettede fletteforespørselen. %{moreInfoLinkStart}Mer informasjon%{moreInfoLinkEnd}."
msgid "%{cores} cores"
-msgstr ""
+msgstr "%{cores} kjerner"
msgid "%{count} %{scope} for term '%{term}'"
-msgstr ""
+msgstr "%{count} %{scope} for begrepet '%{term}'"
msgid "%{count} LOC/commit"
-msgstr ""
+msgstr "%{count} LOC/commit"
msgid "%{count} approval required from %{name}"
msgid_plural "%{count} approvals required from %{name}"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "Det kreves %{count} godkjenning fra %{name}"
+msgstr[1] "Det kreves %{count} godkjenner fra %{name}"
msgid "%{count} approvals from %{name}"
-msgstr ""
+msgstr "%{count} godkjennelser fra %{name}"
msgid "%{count} files touched"
-msgstr ""
+msgstr "%{count} filer berørt"
msgid "%{count} more"
-msgstr ""
+msgstr "%{count} mer"
msgid "%{count} more assignees"
-msgstr ""
+msgstr "%{count} flere tilordnede"
msgid "%{count} more release"
msgid_plural "%{count} more releases"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%{count} utgivelse til"
+msgstr[1] "%{count} utgivelser til"
msgid "%{count} of %{required} approvals from %{name}"
-msgstr ""
+msgstr "%{count} av %{required} godkjenninger fra %{name}"
msgid "%{count} of %{total}"
-msgstr ""
+msgstr "%{count} av %{total}"
msgid "%{count} participant"
msgid_plural "%{count} participants"
-msgstr[0] ""
-msgstr[1] ""
-
-msgid "%{count} pending comment"
-msgid_plural "%{count} pending comments"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%{count} deltaker"
+msgstr[1] "%{count} deltakere"
msgid "%{count} related %{pluralized_subject}: %{links}"
+msgstr "%{count} relatert(e) %{pluralized_subject}: %{links}"
+
+msgid "%{count} total weight"
msgstr ""
msgid "%{dashboard_path} could not be found."
-msgstr ""
+msgstr "%{dashboard_path} kunne ikke bli funnet."
msgid "%{days} days until tags are automatically removed"
-msgstr ""
+msgstr "%{days} dager til etikettene fjernes automatisk"
msgid "%{deployLinkStart}Use a template to deploy to ECS%{deployLinkEnd}, or use a docker image to %{commandsLinkStart}run AWS commands in GitLab CI/CD%{commandsLinkEnd}."
-msgstr ""
+msgstr "%{deployLinkStart}Bruke en mal for å distribuere til ECS%{deployLinkEnd}, eller benytt en dockerbilde til å %{commandsLinkStart}kjøre AWS.kommandoer i GitLab CI/CD%{commandsLinkEnd}."
msgid "%{description}- Sentry event: %{errorUrl}- First seen: %{firstSeen}- Last seen: %{lastSeen} %{countLabel}: %{count}%{userCountLabel}: %{userCount}"
msgstr ""
msgid "%{due_date} (Past due)"
-msgstr ""
+msgstr "%{due_date} (Forbi måldatoen)"
msgid "%{duration}ms"
-msgstr ""
+msgstr "%{duration}ms"
msgid "%{edit_in_new_fork_notice} Try to cherry-pick this commit again."
msgstr ""
@@ -411,154 +460,157 @@ msgid "%{edit_in_new_fork_notice} Try to create a new directory again."
msgstr ""
msgid "%{edit_in_new_fork_notice} Try to revert this commit again."
-msgstr ""
+msgstr "%{edit_in_new_fork_notice} Prøv å tilbakestille denne commiten igjen."
msgid "%{edit_in_new_fork_notice} Try to upload a file again."
-msgstr ""
+msgstr "%{edit_in_new_fork_notice} Prøv å laste opp en fil igjen."
msgid "%{extra} more downstream pipelines"
-msgstr ""
+msgstr "%{extra} flere nedstrømsrørledninger"
msgid "%{filePath} deleted"
-msgstr ""
+msgstr "%{filePath} slettet"
msgid "%{firstLabel} +%{labelCount} more"
-msgstr ""
+msgstr "%{firstLabel} +%{labelCount} til"
msgid "%{firstMilestoneName} + %{numberOfOtherMilestones} more"
-msgstr ""
+msgstr "%{firstMilestoneName} + %{numberOfOtherMilestones} til"
msgid "%{global_id} is not a valid ID for %{expected_type}."
-msgstr ""
+msgstr "%{global_id} er ikke en gyldig ID for %{expected_type}."
msgid "%{group_docs_link_start}Groups%{group_docs_link_end} allow you to manage and collaborate across multiple projects. Members of a group have access to all of its projects."
-msgstr ""
+msgstr "%{group_docs_link_start}Grupper%{group_docs_link_end} lar deg administrere og samarbeide på tvers av flere prosjekter. Medlemmer av en gruppe har tilgang til alle prosjektene."
msgid "%{group_name} group members"
-msgstr ""
+msgstr "%{group_name} gruppemedlemmer"
msgid "%{group_name} uses group managed accounts. You need to create a new GitLab account which will be managed by %{group_name}."
msgstr ""
-msgid "%{host} sign-in from new location"
+msgid "%{group_name}&%{epic_iid} &middot; opened %{epic_created} by %{author}"
msgstr ""
+msgid "%{host} sign-in from new location"
+msgstr "%{host} pålogging fra nytt sted"
+
msgid "%{icon}You are about to add %{usersTag} people to the discussion. They will all receive a notification."
-msgstr ""
+msgstr "%{icon}Du er i ferd med å legge til %{usersTag} personer til diskusjonen. De vil alle motta et varsel."
msgid "%{integrations_link_start}Integrations%{link_end} enable you to make third-party applications part of your GitLab workflow. If the available integrations don't meet your needs, consider using a %{webhooks_link_start}webhook%{link_end}."
-msgstr ""
+msgstr "%{integrations_link_start}Integrasjoner%{link_end} lar deg gjøre tredjepartsapplikasjoner til en del av GitLab-arbeidsflyten. Hvis de tilgjengelige integrasjonene ikke tilfredsstiller dine behov, kan du vurdere å bruke en %{webhooks_link_start}webhook%{link_end}."
msgid "%{issuableType} will be removed! Are you sure?"
-msgstr ""
+msgstr "%{issuableType} vil bli fjernet! Er du sikker?"
-msgid "%{issuesSize} issues with a limit of %{maxIssueCount}"
+msgid "%{issuesCount} issues with a limit of %{maxIssueCount}"
msgstr ""
msgid "%{issuesSize} with a limit of %{maxIssueCount}"
-msgstr ""
+msgstr "%{issuesSize} med en grense på %{maxIssueCount}"
msgid "%{labelStart}Class:%{labelEnd} %{class}"
-msgstr ""
+msgstr "%{labelStart}Klasse:%{labelEnd} %{class}"
msgid "%{labelStart}Crash Address:%{labelEnd} %{crash_address}"
-msgstr ""
+msgstr "%{labelStart}Krasjadresse:%{labelEnd} %{crash_address}"
msgid "%{labelStart}Crash State:%{labelEnd} %{stacktrace_snippet}"
-msgstr ""
+msgstr "%{labelStart}Krasjtilstand:%{labelEnd} %{stacktrace_snippet}"
msgid "%{labelStart}Evidence:%{labelEnd} %{evidence}"
-msgstr ""
+msgstr "%{labelStart}Bevis:%{labelEnd} %{evidence}"
msgid "%{labelStart}File:%{labelEnd} %{file}"
-msgstr ""
+msgstr "%{labelStart}Fil:%{labelEnd} %{file}"
msgid "%{labelStart}Headers:%{labelEnd} %{headers}"
-msgstr ""
+msgstr "%{labelStart}Toppområder:%{labelEnd} %{headers}"
msgid "%{labelStart}Image:%{labelEnd} %{image}"
-msgstr ""
+msgstr "%{labelStart}Bilde:%{labelEnd} %{image}"
msgid "%{labelStart}Method:%{labelEnd} %{method}"
-msgstr ""
+msgstr "%{labelStart}Metode:%{labelEnd} %{method}"
msgid "%{labelStart}Namespace:%{labelEnd} %{namespace}"
-msgstr ""
+msgstr "%{labelStart}Navnefelt:%{labelEnd} %{namespace}"
-msgid "%{labelStart}Report Type:%{labelEnd} %{reportType}"
+msgid "%{labelStart}Scan Type:%{labelEnd} %{reportType}"
msgstr ""
msgid "%{labelStart}Scanner:%{labelEnd} %{scanner}"
-msgstr ""
+msgstr "%{labelStart}Skanner:%{labelEnd} %{scanner}"
msgid "%{labelStart}Severity:%{labelEnd} %{severity}"
-msgstr ""
+msgstr "%{labelStart}Alvorlighet:%{labelEnd} %{severity}"
msgid "%{labelStart}Status:%{labelEnd} %{status}"
-msgstr ""
+msgstr "%{labelStart}Status:%{labelEnd} %{status}"
msgid "%{labelStart}URL:%{labelEnd} %{url}"
-msgstr ""
+msgstr "%{labelStart}URL:%{labelEnd} %{url}"
msgid "%{label_for_message} unavailable"
-msgstr ""
+msgstr "%{label_for_message} utilgjengelig"
msgid "%{label_name} %{span_open}will be permanently deleted from %{subject_name}. This cannot be undone.%{span_close}"
-msgstr ""
+msgstr "%{label_name} %{span_open}blir permanent slettet fra %{subject_name}. Dette kan ikke angres på.%{span_close}"
msgid "%{lets_encrypt_link_start}Let's Encrypt%{lets_encrypt_link_end} is a free, automated, and open certificate authority (CA), that give digital certificates in order to enable HTTPS (SSL/TLS) for websites."
-msgstr ""
+msgstr "%{lets_encrypt_link_start}Let's Encrypt%{lets_encrypt_link_end} er en gratis, automatisert og åpen sertifikatmyndighet (CA), som utsteder digitale sertifikater for å aktivere HTTPS (SSL/TLS) på nettsteder."
msgid "%{level_name} is not allowed in a %{group_level_name} group."
-msgstr ""
+msgstr "%{level_name} er ikke tillatt i en %{group_level_name}-gruppe."
msgid "%{level_name} is not allowed since the fork source project has lower visibility."
-msgstr ""
+msgstr "%{level_name} er ikke tillatt siden utgreiningskildeprosjektet har lavere synlighet."
msgid "%{link_start}Learn more%{link_end} about what information is shared with GitLab Inc."
-msgstr ""
+msgstr "%{link_start}Lær mer%{link_end} om hvilken informasjon som deles med GitLab Inc."
msgid "%{link_start}Read more%{link_end} about role permissions"
-msgstr ""
+msgstr "%{link_start}Les mer%{link_end} om rolletillatelser"
msgid "%{link_start}Remove the %{draft_or_wip_snippet} prefix%{link_end} from the title to allow this merge request to be merged when it's ready."
-msgstr ""
+msgstr "%{link_start}Fjern %{draft_or_wip_snippet} prefiksen%{link_end} fra tittelen for å tillate at denne fletteforespørselen blir innflettet når den er klar."
msgid "%{link_start}Start the title with %{draft_snippet} or %{wip_snippet}%{link_end} to prevent a merge request that is a work in progress from being merged before it's ready."
-msgstr ""
+msgstr "%{link_start}Start tittelen med %{draft_snippet} eller %{wip_snippet}%{link_end} for å forhindre at en fletteforespørsel som er under arbeid blir innflettet før den er klar."
msgid "%{listToShow}, and %{awardsListLength} more."
-msgstr ""
+msgstr "%{listToShow}, og %{awardsListLength} til."
msgid "%{loadingIcon} Started"
-msgstr ""
+msgstr "%{loadingIcon} Startet"
msgid "%{location} is missing required keys: %{keys}"
-msgstr ""
+msgstr "%{location} mangler nødvendige nøkler: %{keys}"
msgid "%{lock_path} is locked by GitLab User %{lock_user_id}"
-msgstr ""
+msgstr "%{lock_path} er låst av GitLab-brukeren %{lock_user_id}"
msgid "%{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd} and %{quickActionsDocsLinkStart}quick actions%{quickActionsDocsLinkEnd} are supported"
-msgstr ""
+msgstr "%{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd} og %{quickActionsDocsLinkStart}hurtighandlinger%{quickActionsDocsLinkEnd} er støttet"
msgid "%{mergeLength}/%{usersLength} can merge"
-msgstr ""
+msgstr "%{mergeLength}/%{usersLength} kan bli flettet"
msgid "%{message} showing first %{warnings_displayed}"
-msgstr ""
+msgstr "%{message} viser de første %{warnings_displayed}"
msgid "%{milestone_name} (Past due)"
-msgstr ""
+msgstr "%{milestone_name} (Forbi måldatoen)"
msgid "%{milestone} (expired)"
-msgstr ""
+msgstr "%{milestone} (utløpt)"
msgid "%{milliseconds}ms"
-msgstr ""
+msgstr "%{milliseconds}ms"
msgid "%{mrText}, this issue will be closed automatically."
-msgstr ""
+msgstr "%{mrText}, denne saken vil bli automatisk lukket."
msgid "%{name_with_link} has %{percent} or less Shared Runner Pipeline minutes remaining. Once it runs out, no new jobs or pipelines in its projects will run."
msgstr ""
@@ -567,22 +619,22 @@ msgid "%{name_with_link} has run out of Shared Runner Pipeline minutes so no new
msgstr ""
msgid "%{namespace_name} is now read-only. You cannot: %{base_message}"
-msgstr ""
+msgstr "%{namespace_name} er nå skrivebeskyttet. Du kan ikke: %{base_message}"
msgid "%{name} contained %{resultsString}"
-msgstr ""
+msgstr "%{name} inneholdt %{resultsString}"
msgid "%{name} found %{resultsString}"
-msgstr ""
+msgstr "%{name} fant %{resultsString}"
msgid "%{name} is already being used for another emoji"
-msgstr ""
+msgstr "%{name} brukes allerede for en annen emoji"
msgid "%{name} is scheduled for %{action}"
-msgstr ""
+msgstr "%{name} er planlagt for %{action}"
msgid "%{name}'s avatar"
-msgstr ""
+msgstr "%{name} sin avatar"
msgid "%{name}(%{url}) has %{percent} or less Shared Runner Pipeline minutes remaining. Once it runs out, no new jobs or pipelines in its projects will run."
msgstr ""
@@ -592,511 +644,530 @@ msgstr ""
msgid "%{no_of_days} day"
msgid_plural "%{no_of_days} days"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%{no_of_days} dag"
+msgstr[1] "%{no_of_days} dager"
msgid "%{number_commits_behind} commits behind %{default_branch}, %{number_commits_ahead} commits ahead"
-msgstr ""
+msgstr "%{number_commits_behind} commiter bak %{default_branch}, %{number_commits_ahead} commiter foran"
msgid "%{openOrClose} %{noteable}"
-msgstr ""
+msgstr "%{openOrClose} %{noteable}"
msgid "%{openedEpics} open, %{closedEpics} closed"
-msgstr ""
+msgstr "%{openedEpics} åpne, %{closedEpics} lukket"
msgid "%{openedIssues} open, %{closedIssues} closed"
-msgstr ""
+msgstr "%{openedIssues} åpne, %{closedIssues} lukket"
msgid "%{percentage}%% weight completed"
msgstr ""
msgid "%{percent}%% complete"
-msgstr ""
+msgstr "%{percent}%% fullført"
msgid "%{percent}%{percentSymbol} complete"
-msgstr ""
+msgstr "%{percent}%{percentSymbol} fullført"
msgid "%{placeholder} is not a valid color scheme"
-msgstr ""
+msgstr "%{placeholder} er ikke en gyldig fargepalett"
msgid "%{placeholder} is not a valid theme"
-msgstr ""
+msgstr "%{placeholder} er ikke et gyldig tema"
msgid "%{primary} (%{secondary})"
-msgstr ""
+msgstr "%{primary} (%{secondary})"
msgid "%{ref} cannot be added: %{error}"
-msgstr ""
+msgstr "%{ref} kan ikke bli lagt til: %{error}"
msgid "%{releases} release"
msgid_plural "%{releases} releases"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%{releases} utgivelse"
+msgstr[1] "%{releases} utgivelser"
msgid "%{remaining_approvals} left"
-msgstr ""
+msgstr "%{remaining_approvals} igjen"
msgid "%{reportType} %{status} detected %{criticalStart}%{critical} critical%{criticalEnd} and %{highStart}%{high} high%{highEnd} severity vulnerabilities out of %{total}."
-msgstr ""
+msgstr "%{reportType} %{status} oppdaget %{criticalStart}%{critical} kritiske%{criticalEnd} og %{highStart}%{high} høygrads%{highEnd} alvorlige sårbarheter ut av %{total}."
msgid "%{reportType} %{status} detected %{criticalStart}%{critical} critical%{criticalEnd} and %{highStart}%{high} high%{highEnd} severity vulnerabilities."
-msgstr ""
+msgstr "%{reportType} %{status} oppdaget %{criticalStart}%{critical} kritiske%{criticalEnd} og %{highStart}%{high} høygrads%{highEnd} alvorlige sårbarheter."
msgid "%{reportType} %{status} detected %{criticalStart}%{critical} critical%{criticalEnd} severity vulnerabilities out of %{total}."
-msgstr ""
+msgstr "%{reportType} %{status} oppdaget %{criticalStart}%{critical} kritisk%{criticalEnd} alvorlige sårbarheter ut av %{total}."
msgid "%{reportType} %{status} detected %{criticalStart}%{critical} critical%{criticalEnd} severity vulnerability."
msgid_plural "%{reportType} %{status} detected %{criticalStart}%{critical} critical%{criticalEnd} severity vulnerabilities."
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%{reportType} %{status} oppdaget %{criticalStart}%{critical} kritisk%{criticalEnd} severity sårbarhet."
+msgstr[1] "%{reportType} %{status} oppdaget %{criticalStart}%{critical} kritisk%{criticalEnd} alvorlige sårbarheter."
msgid "%{reportType} %{status} detected %{highStart}%{high} high%{highEnd} severity vulnerabilities out of %{total}."
-msgstr ""
+msgstr "%{reportType} %{status} oppdaget %{highStart}%{high} høygrads%{highEnd} alvorlige sårbarheter ut av %{total}."
msgid "%{reportType} %{status} detected %{highStart}%{high} high%{highEnd} severity vulnerability."
msgid_plural "%{reportType} %{status} detected %{highStart}%{high} high%{highEnd} severity vulnerabilities."
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%{reportType} %{status} oppdaget %{highStart}%{high} høygrads%{highEnd} alvorlig sårbarhet."
+msgstr[1] "%{reportType} %{status} oppdaget %{highStart}%{high} høygrads%{highEnd} alvorlige sårbarheter."
msgid "%{reportType} %{status} detected %{other} vulnerability."
msgid_plural "%{reportType} %{status} detected %{other} vulnerabilities."
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%{reportType} %{status} oppdaget %{other} sårbarhet."
+msgstr[1] "%{reportType} %{status} oppdaget %{other} sårbarheter."
msgid "%{reportType} %{status} detected no vulnerabilities."
-msgstr ""
+msgstr "%{reportType} %{status} oppdaget ingen sårbarheter."
msgid "%{retryButtonStart}Try again%{retryButtonEnd} or %{newFileButtonStart}attach a new file%{newFileButtonEnd}"
-msgstr ""
+msgstr "%{retryButtonStart}Prøv igjen%{retryButtonEnd} eller %{newFileButtonStart}legg med en ny fil%{newFileButtonEnd}"
msgid "%{seconds}s"
-msgstr ""
+msgstr "%{seconds}s"
msgid "%{securityScanner} is not enabled for this project. %{linkStart}More information%{linkEnd}"
msgid_plural "%{securityScanner} are not enabled for this project. %{linkStart}More information%{linkEnd}"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%{securityScanner} er ikke aktivert for dette prosjektet. %{linkStart}Mer informasjon%{linkEnd}"
+msgstr[1] "%{securityScanner} er ikke aktivert for dette prosjektet. %{linkStart}Mer informasjon%{linkEnd}"
msgid "%{securityScanner} result is not available because a pipeline has not been run since it was enabled. %{linkStart}Run a pipeline%{linkEnd}"
msgid_plural "%{securityScanner} results are not available because a pipeline has not been run since it was enabled. %{linkStart}Run a pipeline%{linkEnd}"
-msgstr[0] ""
-msgstr[1] ""
-
-msgid "%{service_title} %{message}."
-msgstr ""
+msgstr[0] "%{securityScanner}-resultatet er ikke tilgjengelig fordi en rørledning ikke er kjørt siden den ble aktivert. %{linkStart}Kjør en rørledning%{linkEnd}"
+msgstr[1] "%{securityScanner}-resultater er ikke tilgjengelige fordi en rørledning ikke er kjørt siden den ble aktivert. %{linkStart}Kjør en rørledning%{linkEnd}"
msgid "%{size} GiB"
-msgstr ""
+msgstr "%{size} GiB"
msgid "%{size} KiB"
-msgstr ""
+msgstr "%{size} KiB"
msgid "%{size} MiB"
-msgstr ""
+msgstr "%{size} MiB"
msgid "%{size} bytes"
-msgstr ""
+msgstr "%{size} bytes"
msgid "%{sourceBranch} into %{targetBranch}"
-msgstr ""
+msgstr "%{sourceBranch} til %{targetBranch}"
msgid "%{spammable_titlecase} was submitted to Akismet successfully."
-msgstr ""
+msgstr "%{spammable_titlecase} ble vellykket sendt til Akismet."
msgid "%{spanStart}at line%{spanEnd} %{errorLine}%{errorColumn}"
-msgstr ""
+msgstr "%{spanStart}i linje%{spanEnd} %{errorLine}%{errorColumn}"
msgid "%{spanStart}in%{spanEnd} %{errorFn}"
-msgstr ""
+msgstr "%{spanStart}i%{spanEnd} %{errorFn}"
msgid "%{start} to %{end}"
-msgstr ""
+msgstr "%{start} til %{end}"
msgid "%{state} epics"
-msgstr ""
+msgstr "%{state} epics"
msgid "%{strongStart}Deletes%{strongEnd} source branch"
-msgstr ""
+msgstr "%{strongStart}Sletter%{strongEnd} kildegrenen"
msgid "%{strongStart}Note:%{strongEnd} Once a custom stage has been added you can re-order stages by dragging them into the desired position."
msgstr ""
msgid "%{strong_start}%{branch_count}%{strong_end} Branch"
msgid_plural "%{strong_start}%{branch_count}%{strong_end} Branches"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%{strong_start}%{branch_count}%{strong_end} gren"
+msgstr[1] "%{strong_start}%{branch_count}%{strong_end} grener"
msgid "%{strong_start}%{commit_count}%{strong_end} Commit"
msgid_plural "%{strong_start}%{commit_count}%{strong_end} Commits"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%{strong_start}%{commit_count}%{strong_end} commit"
+msgstr[1] "%{strong_start}%{commit_count}%{strong_end} commiter"
msgid "%{strong_start}%{human_size}%{strong_end} Files"
-msgstr ""
+msgstr "%{strong_start}%{human_size}%{strong_end} filer"
msgid "%{strong_start}%{human_size}%{strong_end} Storage"
-msgstr ""
+msgstr "%{strong_start}%{human_size}%{strong_end} Lagring"
msgid "%{strong_start}%{release_count}%{strong_end} Release"
msgid_plural "%{strong_start}%{release_count}%{strong_end} Releases"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%{strong_start}%{release_count}%{strong_end} utgivelse"
+msgstr[1] "%{strong_start}%{release_count}%{strong_end} utgivelser"
msgid "%{strong_start}%{tag_count}%{strong_end} Tag"
msgid_plural "%{strong_start}%{tag_count}%{strong_end} Tags"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%{strong_start}%{tag_count}%{strong_end} etikett"
+msgstr[1] "%{strong_start}%{tag_count}%{strong_end} etiketter"
msgid "%{tabname} changed"
-msgstr ""
+msgstr "%{tabname} endringer"
msgid "%{tags} tag per image name"
-msgstr ""
+msgstr "%{tags} etikett per billednavn"
msgid "%{tags} tags per image name"
-msgstr ""
+msgstr "%{tags} etiketter per billednavn"
msgid "%{tag}-%{evidence}-%{filename}"
-msgstr ""
+msgstr "%{tag}-%{evidence}-%{filename}"
msgid "%{template_project_id} is unknown or invalid"
-msgstr ""
+msgstr "%{template_project_id} er ukjent eller ugyldig"
msgid "%{text} %{files}"
msgid_plural "%{text} %{files} files"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%{text} %{files}"
+msgstr[1] "%{text} %{files} filer"
msgid "%{text} is available"
-msgstr ""
+msgstr "%{text} er tilgjengelig"
msgid "%{timebox_name} should belong either to a project or a group."
+msgstr "%{timebox_name} burde tilhøre enten et prosjekt eller en gruppe."
+
+msgid "%{timebox_type} does not support burnup charts"
msgstr ""
-msgid "%{title} %{operator} %{threshold}"
+msgid "%{timebox_type} must have a start and due date"
msgstr ""
+msgid "%{title} %{operator} %{threshold}"
+msgstr "%{title} %{operator} %{threshold}"
+
msgid "%{title} changes"
-msgstr ""
+msgstr "%{title} endringer"
msgid "%{token}..."
-msgstr ""
+msgstr "%{token} …"
msgid "%{totalCpu} (%{freeSpacePercentage}%{percentSymbol} free)"
-msgstr ""
+msgstr "%{totalCpu} (%{freeSpacePercentage}%{percentSymbol} ledig)"
msgid "%{totalMemory} (%{freeSpacePercentage}%{percentSymbol} free)"
-msgstr ""
+msgstr "%{totalMemory} (%{freeSpacePercentage}%{percentSymbol} ledig)"
msgid "%{totalWeight} total weight"
-msgstr ""
+msgstr "%{totalWeight} totalvekt"
msgid "%{total_warnings} warning(s) found:"
-msgstr ""
+msgstr "%{total_warnings} advarsel(er) funnet:"
msgid "%{total} open issue weight"
msgstr ""
-msgid "%{total} open issues"
+msgid "%{total} warnings found: showing first %{warningsDisplayed}"
msgstr ""
msgid "%{usage_ping_link_start}Learn more%{usage_ping_link_end} about what information is shared with GitLab Inc."
-msgstr ""
+msgstr "%{usage_ping_link_start}Lær mer%{usage_ping_link_end} om hvilken informasjon som deles med GitLab Inc."
msgid "%{userName} (cannot merge)"
-msgstr ""
+msgstr "%{userName} (kan ikke flette)"
msgid "%{userName}'s avatar"
-msgstr ""
+msgstr "%{userName} sin avatar"
msgid "%{user_name} profile page"
-msgstr ""
+msgstr "%{user_name} sin profilside"
msgid "%{username}'s avatar"
-msgstr ""
+msgstr "%{username} sin avatar"
msgid "%{value} s"
-msgstr ""
+msgstr "%{value} sek"
msgid "%{verb} %{time_spent_value} spent time."
-msgstr ""
+msgstr "%{verb} %{time_spent_value} brukt tid."
msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project."
-msgstr ""
+msgstr "%{webhooks_link_start}%{webhook_type}%{link_end} lar deg sende varsler til nettapplikasjoner som svar på hendelser i en gruppe eller et prosjekt."
msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notifications to web applications in response to events in a group or project. We recommend using an %{integrations_link_start}integration%{link_end} in preference to a webhook."
-msgstr ""
+msgstr "%{webhooks_link_start}%{webhook_type}%{link_end} lar deg sende varsler til nettapplikasjoner som svar på hendelser i en gruppe eller et prosjekt. Vi anbefaler at du bruker en %{integrations_link_start}integrasjon%{link_end} som det foretrukne fremfor en webhook."
msgid "&lt; 1 hour"
-msgstr ""
-
-msgid "&lt;no name set&gt;"
-msgstr ""
+msgstr "&lt; 1 time"
msgid "&lt;no scopes selected&gt;"
-msgstr ""
+msgstr "&lt;no scopes selected&gt;"
msgid "&lt;project name&gt;"
-msgstr ""
+msgstr "&lt;project name&gt;"
msgid "'%{data}' at %{location} does not match format: %{format}"
-msgstr ""
+msgstr "'%{data}' ved %{location} samsvarer ikke med formatet: %{format}"
msgid "'%{data}' at %{location} does not match pattern: %{pattern}"
-msgstr ""
+msgstr "'%{data}' ved %{location} samsvarer ikke med mønsteret: %{pattern}"
msgid "'%{data}' at %{location} is invalid: error_type=%{type}"
-msgstr ""
+msgstr "'%{data}' ved %{location} er ugyldig: error_type=%{type}"
msgid "'%{data}' at %{location} is not of type: %{type}"
-msgstr ""
+msgstr "'%{data}' ved %{location} er ikke av typen: %{type}"
msgid "'%{data}' at %{location} is not one of: %{enum}"
-msgstr ""
+msgstr "'%{data}' ved %{location} er ikke en av: %{enum}"
msgid "'%{data}' at %{location} is not: %{const}"
-msgstr ""
+msgstr "'%{data}' ved %{location} er ikke: %{const}"
msgid "'%{level}' is not a valid visibility level"
-msgstr ""
+msgstr "'%{level}' er ikke et gyldig synlighetsnivå"
msgid "'%{name}' Value Stream created"
+msgstr "'%{name}'-verdistrøm opprettet"
+
+msgid "'%{name}' Value Stream deleted"
msgstr ""
msgid "'%{name}' stage already exists"
-msgstr ""
+msgstr "'%{name}'-trinnet finnes allerede"
msgid "'%{source}' is not a import source"
-msgstr ""
+msgstr "'%{source}' er ikke en importkilde"
msgid "'%{template_name}' is unknown or invalid"
-msgstr ""
+msgstr "'%{template_name}' er ukjent eller ugyldig"
msgid "(%d closed)"
msgid_plural "(%d closed)"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "(%d lukket)"
+msgstr[1] "(%d lukket)"
msgid "(%{mrCount} merged)"
-msgstr ""
+msgstr "(%{mrCount} innflettet)"
msgid "(%{value}) has already been taken"
-msgstr ""
+msgstr "(%{value}) har allerede blitt tatt"
msgid "(No changes)"
-msgstr ""
+msgstr "(Ingen endringer)"
msgid "(check progress)"
-msgstr ""
+msgstr "(sjekk fremgang)"
msgid "(deleted)"
-msgstr ""
+msgstr "(slettet)"
msgid "(external source)"
-msgstr ""
+msgstr "(ekstern kilde)"
msgid "(line: %{startLine})"
-msgstr ""
+msgstr "(linje: %{startLine})"
msgid "(max size 15 MB)"
-msgstr ""
+msgstr "(maks størrelse 15 MB)"
msgid "(removed)"
-msgstr ""
+msgstr "(fjernet)"
msgid "(revoked)"
-msgstr ""
+msgstr "(tilbakekalt)"
msgid "* * * * *"
-msgstr ""
+msgstr "* * * * *"
msgid "+ %{amount} more"
-msgstr ""
+msgstr "+ %{amount} til"
msgid "+ %{count} more"
-msgstr ""
+msgstr "+ %{count} til"
msgid "+ %{moreCount} more"
-msgstr ""
+msgstr "+ %{moreCount} til"
msgid "+ %{numberOfHiddenAssignees} more"
+msgstr "+ %{numberOfHiddenAssignees} til"
+
+msgid "+ %{numberOfHiddenReviewers} more"
msgstr ""
msgid "+%d more"
msgid_plural "+%d more"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "+%d til"
+msgstr[1] "+%d til"
msgid "+%{approvers} more approvers"
-msgstr ""
+msgstr "+%{approvers} flere godkjennere"
msgid "+%{tags} more"
-msgstr ""
+msgstr "+%{tags} til"
msgid ", or "
-msgstr ""
+msgstr ", eller "
msgid "- Event"
msgid_plural "- Events"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "- Hendelse"
+msgstr[1] "- Hendelser"
msgid "- Runner is active and can process any new jobs"
msgstr ""
msgid "- Runner is paused and will not receive any new jobs"
-msgstr ""
+msgstr "- Runner er satt på pause og vil ikke motta nye jobber"
msgid "- User"
msgid_plural "- Users"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "- Bruker"
+msgstr[1] "- Brukere"
msgid "- of - weight completed"
-msgstr ""
+msgstr "- av - vektlegging fullført"
msgid "- show less"
-msgstr ""
+msgstr "- Vis mindre"
msgid "0 bytes"
-msgstr ""
+msgstr "0 byte"
msgid "0 for unlimited"
-msgstr ""
+msgstr "0 for ubegrenset"
msgid "0 for unlimited, only effective with remote storage enabled."
msgstr ""
msgid "1 %{type} addition"
msgid_plural "%{count} %{type} additions"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "1 %{type}-tillegging"
+msgstr[1] "%{count} %{type}-tillegginger"
msgid "1 %{type} modification"
msgid_plural "%{count} %{type} modifications"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "1 %{type} modifikasjon"
+msgstr[1] "%{count} %{type} modifikasjoner"
msgid "1 Day"
msgid_plural "%d Days"
+msgstr[0] "1 dag"
+msgstr[1] "%d dager"
+
+msgid "1 Issue"
+msgid_plural "%d Issues"
msgstr[0] ""
msgstr[1] ""
msgid "1 closed issue"
msgid_plural "%{issues} closed issues"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "1 lukket sak"
+msgstr[1] "%{issues} lukkede saker"
msgid "1 closed merge request"
msgid_plural "%{merge_requests} closed merge requests"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "1 lukket fletteforespørsel"
+msgstr[1] "%{merge_requests} lukkede fletteforespørsler"
msgid "1 day"
msgid_plural "%d days"
+msgstr[0] "1 dag"
+msgstr[1] "%d dager"
+
+msgid "1 deploy key"
+msgid_plural "%d deploy keys"
msgstr[0] ""
msgstr[1] ""
msgid "1 group"
msgid_plural "%d groups"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "1 gruppe"
+msgstr[1] "%d grupper"
msgid "1 hour"
msgid_plural "%d hours"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "1 time"
+msgstr[1] "%d timer"
msgid "1 merged merge request"
msgid_plural "%{merge_requests} merged merge requests"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "1 innflettet fletteforespørsel"
+msgstr[1] "%{merge_requests} innflettede fletteforespørsler"
msgid "1 minute"
msgid_plural "%d minutes"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "1 minutt"
+msgstr[1] "%d minutter"
msgid "1 open issue"
msgid_plural "%{issues} open issues"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "1 åpent problem"
+msgstr[1] "%{issues} åpne problemer"
msgid "1 open merge request"
msgid_plural "%{merge_requests} open merge requests"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "1 åpen fletteforespørsel"
+msgstr[1] "%{merge_requests} åpne fletteforespørsler"
msgid "1 pipeline"
msgid_plural "%d pipelines"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "1 rørledning"
+msgstr[1] "%d rørledninger"
msgid "1 role"
msgid_plural "%d roles"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "1 rolle"
+msgstr[1] "%d roller"
msgid "1 user"
msgid_plural "%{num} users"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "1 bruker"
+msgstr[1] "%{num} brukere"
msgid "1-9 contributions"
-msgstr ""
+msgstr "1-9 bidrag"
msgid "10-19 contributions"
-msgstr ""
+msgstr "10-19 bidrag"
msgid "1st contribution!"
-msgstr ""
+msgstr "Første bidrag!"
msgid "20-29 contributions"
-msgstr ""
+msgstr "20-29 bidrag"
msgid "2FA"
-msgstr ""
+msgstr "2FA"
msgid "2FADevice|Registered On"
-msgstr ""
+msgstr "Registrert den"
msgid "3 days"
-msgstr ""
+msgstr "3 dager"
msgid "3 hours"
-msgstr ""
+msgstr "3 timer"
msgid "30 days"
-msgstr ""
+msgstr "30 dager"
msgid "30 minutes"
-msgstr ""
+msgstr "30 minutter"
msgid "30+ contributions"
-msgstr ""
+msgstr "30+ bidrag"
msgid "403|Please contact your GitLab administrator to get permission."
-msgstr ""
+msgstr "Vennligst ta kontakt med din GitLab-administrator for å få tillatelse."
msgid "403|You don't have the permission to access this page."
-msgstr ""
+msgstr "Du har ikke tilgang til å nå denne siden."
msgid "404|Make sure the address is correct and the page hasn't moved."
-msgstr ""
+msgstr "Kontroller at adressen er riktig og at siden ikke er flyttet."
msgid "404|Page Not Found"
-msgstr ""
+msgstr "Siden ble ikke funnet"
msgid "404|Please contact your GitLab administrator if you think this is a mistake."
-msgstr ""
+msgstr "Ta kontakt med din GitLab-administrator hvis du mener dette er en feil."
msgid "7 days"
-msgstr ""
+msgstr "7 dager"
msgid "8 hours"
-msgstr ""
+msgstr "8 timer"
msgid ":%{startLine} to %{endLine}"
+msgstr ":%{startLine} til %{endLine}"
+
+msgid "A %{incident_docs_start}modified issue%{incident_docs_end} to guide the resolution of incidents."
msgstr ""
msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
@@ -1106,58 +1177,61 @@ msgid "A .NET Core console application template, customizable for any .NET Core
msgstr ""
msgid "A CI/CD pipeline must run and be successful before merge."
-msgstr ""
+msgstr "En CI/CD-rørledning må kjøre og være vellykket før sammenslåing."
msgid "A GitBook site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
+msgstr "Et Gitbook-nettsted som bruker Netlify for CI/CD i stedet for GitLab, men som fremdeles has alle de andre gode GitLab-funksjonene."
+
+msgid "A Gitpod configured Webapplication in Spring and Java"
msgstr ""
msgid "A Hexo site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
-msgstr ""
+msgstr "Et Hexo-nettsted som bruker Netlify for CI/CD i stedet for GitLab, men som fremdeles has alle de andre gode GitLab-funksjonene."
msgid "A Hugo site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
-msgstr ""
+msgstr "Et Hugo-nettsted som bruker Netlify for CI/CD i stedet for GitLab, men som fremdeles has alle de andre gode GitLab-funksjonene."
msgid "A Jekyll site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
-msgstr ""
+msgstr "Et Jekyll-nettsted som bruker Netlify for CI/CD i stedet for GitLab, men som fremdeles has alle de andre gode GitLab-funksjonene."
msgid "A Let's Encrypt SSL certificate can not be obtained until your domain is verified."
-msgstr ""
+msgstr "Et 'Let's Encrypt'-SSL-sertifikat kan ikke fås før domenet ditt har blitt bekreftet."
msgid "A Let's Encrypt account will be configured for this GitLab installation using your email address. You will receive emails to warn of expiring certificates."
-msgstr ""
+msgstr "En Let's Encrypt-konto vil bli konfigurert for denne GitLab-installasjonen ved å bruke e-postadressen din. Du vil motta e-postmeldinger for å advare om utløpende sertifikater."
msgid "A basic page and serverless function that uses AWS Lambda, AWS API Gateway, and GitLab Pages"
msgstr ""
msgid "A complete DevOps platform"
-msgstr ""
+msgstr "En komplett DevOps-plattform"
msgid "A default branch cannot be chosen for an empty project."
-msgstr ""
+msgstr "En standardgren kan ikke velges for et tomt prosjekt."
msgid "A deleted user"
-msgstr ""
+msgstr "En slettet bruker"
msgid "A file has been changed."
-msgstr ""
+msgstr "En fil har blitt endret."
msgid "A file was not found."
-msgstr ""
+msgstr "En fil ble ikke funnet."
msgid "A file with '%{file_name}' already exists in %{branch} branch"
-msgstr ""
+msgstr "En fil med '%{file_name}' finnes allerede i %{branch}-grenen"
msgid "A fork is a copy of a project."
-msgstr ""
+msgstr "En utgreining er en kopi av et prosjekt."
msgid "A group is a collection of several projects"
-msgstr ""
+msgstr "En gruppe er en samling av flere prosjekter"
msgid "A group represents your organization in GitLab. Groups allow you to manage users and collaborate across multiple projects."
-msgstr ""
+msgstr "En gruppe representerer organisasjonen din i GitLab. Grupper lar deg administrere brukere og samarbeide på tvers av flere prosjekter."
msgid "A member of the abuse team will review your report as soon as possible."
-msgstr ""
+msgstr "Et medlem av misbruksteamet vil vurdere rapporten din så snart som mulig."
msgid "A merge request approval is required when a security report contains a new vulnerability of high, critical, or unknown severity."
msgstr ""
@@ -1169,13 +1243,13 @@ msgid "A new Auto DevOps pipeline has been created, go to %{pipelines_link_start
msgstr ""
msgid "A new Release %{tag} for %{name} was published. Visit the %{release_link_start}Releases page%{release_link_end} to read more about it."
-msgstr ""
+msgstr "En ny utgivelse %{tag} for %{name} ble publisert. Besøk %{release_link_start}utgivelsessiden%{release_link_end} for å lese mer om den."
msgid "A new Release %{tag} for %{name} was published. Visit the Releases page to read more about it:"
-msgstr ""
+msgstr "En ny utgivelse %{tag} for %{name} ble publisert. Besøk 'Utgivelser'-siden for å lese mer om den:"
msgid "A new branch will be created in your fork and a new merge request will be started."
-msgstr ""
+msgstr "En ny gren vil bli opprettet i din utgreining, og en ny fletteforespørsel vil bli påbegynt."
msgid "A new impersonation token has been created."
msgstr ""
@@ -1184,10 +1258,10 @@ msgid "A non-confidential epic cannot be assigned to a confidential parent epic"
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 ""
+msgstr "Et rent HTML-nettsted som bruker Netlify for CI/CD i stedet for GitLab, men som fremdeles has alle de andre gode GitLab-funksjonene."
msgid "A platform value can be web, mob or app."
-msgstr ""
+msgstr "En plattformverdi kan være web, mob, eller app."
msgid "A project boilerplate for Salesforce App development with Salesforce Developer tools."
msgstr ""
@@ -1199,10 +1273,10 @@ msgid "A project is where you house your files (repository), plan your work (iss
msgstr ""
msgid "A ready-to-go template for use with Android apps."
-msgstr ""
+msgstr "En klar-til-bruk-mal for bruk til Android-apper."
msgid "A ready-to-go template for use with iOS Swift apps."
-msgstr ""
+msgstr "En klar-til-bruk-mal for bruk til iOS Swift-apper."
msgid "A regular expression that will be used to find the test coverage output in the job log. Leave blank to disable"
msgstr ""
@@ -1214,7 +1288,7 @@ msgid "A sign-in to your account has been made from the following IP address: %{
msgstr ""
msgid "A subscription will trigger a new pipeline on the default branch of this project when a pipeline successfully completes for a new tag on the %{default_branch_docs} of the subscribed project."
-msgstr ""
+msgstr "Et abonnement vil trigge en ny rørledning på standardgrenen til dette prosjektet, når en rørledning blir vellykket fullført for en ny etikett på %{default_branch_docs} av det abonnerte prosjektet."
msgid "A user with write access to the source branch selected this option"
msgstr ""
@@ -1223,91 +1297,100 @@ msgid "ACTION REQUIRED: Something went wrong while obtaining the Let's Encrypt c
msgstr ""
msgid "API Help"
-msgstr ""
+msgstr "API-hjelp"
msgid "API Token"
-msgstr ""
+msgstr "API-token"
msgid "AWS Access Key"
-msgstr ""
+msgstr "AWS tilgangsnøkkel"
msgid "AWS Access Key. Only required if not using role instance credentials"
-msgstr ""
+msgstr "AWS-tilgangsnøkkel. Bare påkrevd hvis du ikke bruker rolleinstans-legitimasjoner"
msgid "AWS Secret Access Key"
-msgstr ""
+msgstr "AWS hemmelig tilgangsnøkkel"
msgid "AWS Secret Access Key. Only required if not using role instance credentials"
-msgstr ""
+msgstr "AWS hemmelig tilgangsnøkkel. Bare påkrevd hvis du ikke bruker rolleinstans-legitimasjoner"
msgid "Abort"
-msgstr ""
+msgstr "Avbryt"
msgid "About GitLab"
-msgstr ""
+msgstr "Om GitLab"
msgid "About GitLab CE"
-msgstr ""
+msgstr "Om GitLab CE"
msgid "About auto deploy"
-msgstr ""
+msgstr "Om automatisk distribusjon"
msgid "About this feature"
-msgstr ""
+msgstr "Om denne funksjonen"
msgid "Abuse Reports"
-msgstr ""
+msgstr "Rapporter over misbruk"
msgid "Abuse reports"
-msgstr ""
+msgstr "Rapporter over misbruk"
msgid "Accept invitation"
-msgstr ""
+msgstr "Aksepter invitasjon"
msgid "Accept terms"
-msgstr ""
+msgstr "Godta vilkår"
msgid "Acceptable for use in this project"
-msgstr ""
+msgstr "Akseptabelt for bruk i dette prosjektet"
msgid "Access Tokens"
-msgstr ""
+msgstr "Tilgangskode"
msgid "Access denied for your LDAP account."
-msgstr ""
+msgstr "Tilgang nektet for LDAP-kontoen din."
msgid "Access denied! Please verify you can add deploy keys to this repository."
-msgstr ""
+msgstr "Ingen tilgang! Vennligst verifiser at du kan legge til nøkler i dette kodelageret."
msgid "Access expiration date"
+msgstr "Tilgangsutløpsdato"
+
+msgid "Access expires"
msgstr ""
msgid "Access forbidden. Check your access level."
+msgstr "Tilgang nektet. Sjekk ditt tilgangsnivå."
+
+msgid "Access granted"
msgstr ""
msgid "Access requests"
msgstr ""
msgid "Access to '%{classification_label}' not allowed"
-msgstr ""
+msgstr "Tilgang til '%{classification_label}' er ikke tillatt"
msgid "Access to Pages websites are controlled based on the user's membership to a given project. By checking this box, users will be required to be logged in to have access to all Pages websites in your instance."
msgstr ""
-msgid "AccessDropdown|Groups"
+msgid "AccessDropdown|Deploy Keys"
msgstr ""
+msgid "AccessDropdown|Groups"
+msgstr "Grupper"
+
msgid "AccessDropdown|Roles"
-msgstr ""
+msgstr "Roller"
msgid "AccessDropdown|Users"
-msgstr ""
+msgstr "Brukere"
msgid "AccessTokens|Access Tokens"
-msgstr ""
+msgstr "Tilgangssjetonger"
msgid "AccessTokens|Are you sure?"
-msgstr ""
+msgstr "Er du sikker?"
msgid "AccessTokens|Are you sure? Any RSS or calendar URLs currently in use will stop working."
msgstr ""
@@ -1316,7 +1399,7 @@ msgid "AccessTokens|Are you sure? Any issue email addresses currently in use wil
msgstr ""
msgid "AccessTokens|Created"
-msgstr ""
+msgstr "Opprettet"
msgid "AccessTokens|Feed token"
msgstr ""
@@ -1325,22 +1408,22 @@ msgid "AccessTokens|Incoming email token"
msgstr ""
msgid "AccessTokens|It cannot be used to access any other data."
-msgstr ""
+msgstr "Den kan ikke brukes til å få tilgang til noen andre data."
msgid "AccessTokens|Keep this token secret. Anyone who gets ahold of it can access repository static objects as if they were you. You should %{reset_link_start}reset it%{reset_link_end} if that ever happens."
-msgstr ""
+msgstr "Hold denne sjetongen hemmelig. Alle som får tak i den, kan få tilgang til statiske objekter i kodelageret som om de var deg. Du bør %{reset_link_start}tilbakestille den%{reset_link_end} dersom det noen gang skjer."
msgid "AccessTokens|Keep this token secret. Anyone who gets ahold of it can create issues as if they were you. You should %{link_reset_it} if that ever happens."
-msgstr ""
+msgstr "Hold denne sjetongen hemmelig. Alle som får tak i den, kan opprette saker som om de var deg. Du bør %{link_reset_it} dersom det noen gang skjer."
msgid "AccessTokens|Keep this token secret. Anyone who gets ahold of it can read activity and issue RSS feeds or your calendar feed as if they were you. You should %{link_reset_it} if that ever happens."
-msgstr ""
+msgstr "Hold denne sjetongen hemmelig. Alle som får tak i den, kan lese aktivitets- og saks-RSS-strømmer eller kalenderstrømmen din som om de var deg. Du bør %{link_reset_it} dersom det noen gang skjer."
msgid "AccessTokens|Personal Access Tokens"
-msgstr ""
+msgstr "Sjetonger for personlig tilgang"
msgid "AccessTokens|Static object token"
-msgstr ""
+msgstr "Statisk objektssjetong"
msgid "AccessTokens|They are the only accepted password when you have Two-Factor Authentication (2FA) enabled."
msgstr ""
@@ -1349,10 +1432,10 @@ msgid "AccessTokens|You can also use personal access tokens to authenticate agai
msgstr ""
msgid "AccessTokens|You can generate a personal access token for each application you use that needs access to the GitLab API."
-msgstr ""
+msgstr "Du kan generere en sjetong for personlig tilgang for hvert program du bruker som trenger tilgang til GitLab-API-en."
msgid "AccessTokens|Your feed token is used to authenticate you when your RSS reader loads a personalized RSS feed or when your calendar application loads a personalized calendar, and is included in those feed URLs."
-msgstr ""
+msgstr "Strøm-sjetongen din brukes til å autentisere deg når RSS-leseren din laster inn en personliggjort RSS-strøm eller når kalenderapplikasjonen din laster inn en personlig kalender, og er inkludert i disse strøm-URL-ene."
msgid "AccessTokens|Your incoming email token is used to authenticate you when you create a new issue by email, and is included in your personal project-specific email addresses."
msgstr ""
@@ -1361,270 +1444,261 @@ msgid "AccessTokens|Your static object token is used to authenticate you when re
msgstr ""
msgid "AccessTokens|reset it"
-msgstr ""
+msgstr "tilbakestill den"
msgid "AccessibilityReport|Learn more"
-msgstr ""
+msgstr "Lær mer"
msgid "AccessibilityReport|Message: %{message}"
-msgstr ""
+msgstr "Melding: %{message}"
msgid "AccessibilityReport|New"
-msgstr ""
+msgstr "Ny"
msgid "AccessibilityReport|The accessibility scanning found an error of the following type: %{code}"
msgstr ""
msgid "Account"
-msgstr ""
+msgstr "Konto"
msgid "Account ID"
-msgstr ""
+msgstr "Konto-ID"
msgid "Account and limit"
-msgstr ""
+msgstr "Konto og grenser"
msgid "Account: %{account}"
-msgstr ""
+msgstr "Konto: %{account}"
msgid "Action to take when receiving an alert. %{docsLink}"
msgstr ""
msgid "Actions"
-msgstr ""
+msgstr "Handlinger"
msgid "Activate"
-msgstr ""
+msgstr "Aktiver"
msgid "Activate Service Desk"
-msgstr ""
+msgstr "Skru på tjenestedesken"
msgid "Activate user activity analysis"
-msgstr ""
+msgstr "Skru på brukeraktivitetsanalyse"
msgid "Active"
-msgstr ""
+msgstr "Aktiv"
msgid "Active %{type} (%{token_length})"
-msgstr ""
+msgstr "Aktiv %{type} (%{token_length})"
msgid "Active Sessions"
-msgstr ""
-
-msgid "Active Users:"
-msgstr ""
-
-msgid "Active users"
-msgstr ""
+msgstr "Aktive økter"
msgid "Activity"
-msgstr ""
+msgstr "Aktivitet"
msgid "Add"
-msgstr ""
+msgstr "Legg til"
msgid "Add \"%{value}\""
-msgstr ""
+msgstr "Legg til «%{value}»"
msgid "Add %d issue"
msgid_plural "Add %d issues"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "Legg til %d sak"
+msgstr[1] "Legg til %d saker"
msgid "Add %{linkStart}assets%{linkEnd} to your Release. GitLab automatically includes read-only assets, like source code and release evidence."
-msgstr ""
+msgstr "Legg til %{linkStart}ressurser%{linkEnd} i utgivelsen din. GitLab inkluderer automatisk skrivebeskyttede ressurser, som kildekoden og utgivelsesbevis."
msgid "Add CHANGELOG"
-msgstr ""
+msgstr "Legg til CHANGELOG"
msgid "Add CONTRIBUTING"
-msgstr ""
+msgstr "Legg til CONTRIBUTING"
msgid "Add GitLab to Slack"
-msgstr ""
+msgstr "Legg til GitLab til Slack"
msgid "Add Group Webhooks and GitLab Enterprise Edition."
-msgstr ""
+msgstr "Legg til gruppe-Webhooks og GitLab Enterprise Edition."
msgid "Add Jaeger URL"
-msgstr ""
+msgstr "Legg til Jaeger-URL"
msgid "Add Kubernetes cluster"
-msgstr ""
+msgstr "Legg til Kubernetes-klynge"
msgid "Add LICENSE"
-msgstr ""
+msgstr "Legg til LICENSE"
msgid "Add New Node"
-msgstr ""
+msgstr "Legg til ny node"
msgid "Add README"
-msgstr ""
+msgstr "Legg til README"
msgid "Add Variable"
-msgstr ""
+msgstr "Legg til variabel"
msgid "Add Zoom meeting"
-msgstr ""
+msgstr "Legg til Zoom-møte"
msgid "Add a %{type}"
-msgstr ""
+msgstr "Legg til en %{type}"
msgid "Add a GPG key"
-msgstr ""
+msgstr "Legg til en GPG-nøkkel"
msgid "Add a Grafana button in the admin sidebar, monitoring section, to access a variety of statistics on the health and performance of GitLab."
msgstr ""
msgid "Add a To Do"
-msgstr ""
+msgstr "Legg til et gjøremål"
msgid "Add a To-Do"
-msgstr ""
+msgstr "Legg til et gjøremål"
msgid "Add a bullet list"
-msgstr ""
+msgstr "Legg til en punktliste"
msgid "Add a comment to this line"
-msgstr ""
+msgstr "Legg til en kommentar til denne linjen"
msgid "Add a general comment to this %{noteableDisplayName}."
-msgstr ""
+msgstr "Legg til en generell kommentar til denne %{noteableDisplayName}."
msgid "Add a general comment to this %{noteable_name}."
-msgstr ""
+msgstr "Legg til en generell kommentar til denne %{noteable_name}."
msgid "Add a homepage to your wiki that contains information about your project and GitLab will display it here instead of this message."
-msgstr ""
+msgstr "Legg til en hjemmeside på din wiki som inneholder informasjon om prosjektet ditt og GitLab vil vise det her i stedet for denne meldingen."
msgid "Add a line"
-msgstr ""
+msgstr "Legg til en linje"
msgid "Add a link"
-msgstr ""
+msgstr "Legg til lenke"
msgid "Add a new issue"
-msgstr ""
+msgstr "Legg til en ny sak"
msgid "Add a numbered list"
-msgstr ""
+msgstr "Legg til en nummerert liste"
msgid "Add a related issue"
-msgstr ""
+msgstr "Legg til en related sak"
msgid "Add a table"
-msgstr ""
+msgstr "Legg til ny tabell"
msgid "Add a task list"
-msgstr ""
+msgstr "Legg til en oppgaveliste"
msgid "Add additional text to appear in all email communications. %{character_limit} character limit"
-msgstr ""
+msgstr "Legge til ekstra tekst som skal vises i all e-postkommunikasjon. Begrensningen er på %{character_limit} tegn"
msgid "Add an SSH key"
-msgstr ""
+msgstr "Legg til en SSH-nøkkel"
msgid "Add an existing issue"
-msgstr ""
+msgstr "Legg til en eksisterende sak"
msgid "Add an impersonation token"
msgstr ""
msgid "Add another link"
-msgstr ""
+msgstr "Legg til en annen lenke"
msgid "Add approval rule"
-msgstr ""
+msgstr "Legg til godkjenningsregel"
msgid "Add approvers"
-msgstr ""
+msgstr "Legg til godkjennere"
msgid "Add bold text"
-msgstr ""
+msgstr "Legg til fet tekst"
msgid "Add child epic to an epic"
msgstr ""
msgid "Add comment now"
-msgstr ""
+msgstr "Legg til kommentar nå"
msgid "Add comment to design"
-msgstr ""
+msgstr "Legg til kommentar til design"
msgid "Add deploy freeze"
msgstr ""
msgid "Add domain"
-msgstr ""
+msgstr "Legg til domene"
msgid "Add email address"
-msgstr ""
+msgstr "Legg til E-postadresse"
msgid "Add environment"
-msgstr ""
+msgstr "Legg til miljø"
msgid "Add existing confidential %{issuableType}"
-msgstr ""
+msgstr "Legg til eksisterende konfidensiell %{issuableType}"
msgid "Add header and footer to emails. Please note that color settings will only be applied within the application interface"
msgstr ""
msgid "Add image comment"
-msgstr ""
+msgstr "Legg til bilde kommentar"
msgid "Add issues"
-msgstr ""
+msgstr "Legg til saker"
msgid "Add italic text"
-msgstr ""
+msgstr "Legg til kursiv tekst"
msgid "Add key"
-msgstr ""
+msgstr "Legg til nøkkel"
msgid "Add label(s)"
-msgstr ""
-
-msgid "Add license"
-msgstr ""
+msgstr "Legg til stempel(er)"
msgid "Add list"
-msgstr ""
+msgstr "Legg til liste"
msgid "Add new application"
-msgstr ""
+msgstr "Legg til ny applikasjon"
msgid "Add new directory"
-msgstr ""
+msgstr "Legg til ny katalog"
msgid "Add or remove previously merged commits"
-msgstr ""
+msgstr "Legg til eller fjern tidligere innflettede commits"
msgid "Add or subtract spent time"
-msgstr ""
+msgstr "Legg til eller trekk fra brukt tid"
msgid "Add previously merged commits"
-msgstr ""
+msgstr "Legg til tidligere innflettede commiter"
msgid "Add reaction"
-msgstr ""
+msgstr "Legg til reaksjon"
msgid "Add request manually"
-msgstr ""
+msgstr "Legg til forespørsel manuelt"
msgid "Add strikethrough text"
-msgstr ""
+msgstr "Legg til gjennomstreket tekst"
msgid "Add suggestion to batch"
-msgstr ""
+msgstr "Legg til forslag i bunken"
msgid "Add system hook"
-msgstr ""
+msgstr "Legg til systemkrok"
msgid "Add to Slack"
-msgstr ""
+msgstr "Legg til i Slack"
msgid "Add to epic"
-msgstr ""
+msgstr "Legg til i epos"
msgid "Add to merge train"
msgstr ""
@@ -1633,73 +1707,73 @@ msgid "Add to merge train when pipeline succeeds"
msgstr ""
msgid "Add to review"
-msgstr ""
+msgstr "Legg til vurdering"
msgid "Add to tree"
-msgstr ""
+msgstr "Legg til i treet"
msgid "Add user(s) to the group:"
-msgstr ""
+msgstr "Legg til bruker(e) til gruppen:"
msgid "Add users to group"
-msgstr ""
+msgstr "Legg til brukere i gruppen"
msgid "Add variable"
-msgstr ""
+msgstr "Legg til variabel"
msgid "Add webhook"
-msgstr ""
+msgstr "Legg til Webhook"
msgid "Add/remove"
-msgstr ""
+msgstr "Legg til/Fjern"
msgid "AddContextCommits|Add previously merged commits"
-msgstr ""
+msgstr "Legg til tidligere innflettede commiter"
msgid "AddContextCommits|Add/remove"
-msgstr ""
+msgstr "Legg til/Fjern"
msgid "AddMember|No users specified."
-msgstr ""
+msgstr "Ingen brukere spesifisert."
msgid "AddMember|Too many users specified (limit is %{user_limit})"
msgstr ""
msgid "Added"
-msgstr ""
+msgstr "Lagt til"
msgid "Added %{epic_ref} as a child epic."
msgstr ""
msgid "Added %{label_references} %{label_text}."
-msgstr ""
+msgstr "La til %{label_references} %{label_text}."
msgid "Added a To Do."
-msgstr ""
+msgstr "La til et gjøremål."
msgid "Added an issue to an epic."
-msgstr ""
+msgstr "La til en sak i en epos."
msgid "Added at"
-msgstr ""
+msgstr "Lagt til på"
msgid "Added for this merge request"
-msgstr ""
+msgstr "Lagt til for denne fletteforespørselen"
msgid "Added in this version"
-msgstr ""
+msgstr "Lagt til i denne versjonen"
msgid "Adding new applications is disabled in your GitLab instance. Please contact your GitLab administrator to get the permission"
-msgstr ""
+msgstr "Å legge til nye applikasjoner er deaktivert i GitLab-instansen din. Ta kontakt med GitLab-administratoren din for å få tillatelse til det"
msgid "Additional Metadata"
-msgstr ""
+msgstr "Ekstra metadata"
msgid "Additional minutes"
-msgstr ""
+msgstr "Ytterligere minutter"
msgid "Additional text"
-msgstr ""
+msgstr "Ytterligere tekst"
msgid "Adds"
msgstr ""
@@ -1708,558 +1782,606 @@ msgid "Adds %{epic_ref} as child epic."
msgstr ""
msgid "Adds %{labels} %{label_text}."
-msgstr ""
+msgstr "Legger til %{labels} %{label_text}."
msgid "Adds a To Do."
-msgstr ""
+msgstr "Legger til et gjøremål."
msgid "Adds a Zoom meeting"
-msgstr ""
+msgstr "Legger til et Zoom-møte"
msgid "Adds an issue to an epic."
-msgstr ""
+msgstr "Legger til en sak i en epos."
msgid "Adjust your filters/search criteria above. If you believe this may be an error, please refer to the %{linkStart}Geo Troubleshooting%{linkEnd} documentation for more information."
-msgstr ""
+msgstr "Juster dine filtre/søkekriterier ovenfor. Hvis du mener at dette kan være en feil, kan du se dokumentasjonen for %{linkStart}Geo-feilsøking%{linkEnd} for mer informasjon."
msgid "Admin Area"
-msgstr ""
+msgstr "Admin-område"
msgid "Admin Note"
-msgstr ""
+msgstr "Admin-notis"
msgid "Admin Notifications"
-msgstr ""
+msgstr "Admin-meldinger"
msgid "Admin Overview"
-msgstr ""
+msgstr "Admin-oversikt"
msgid "Admin Section"
-msgstr ""
+msgstr "Adminseksjon"
msgid "Admin mode already enabled"
-msgstr ""
+msgstr "Admin-modus er allerede aktivert"
msgid "Admin mode disabled"
-msgstr ""
+msgstr "Adminmodus skrudd av"
msgid "Admin mode enabled"
-msgstr ""
+msgstr "Adminmodus skrudd på"
msgid "Admin notes"
-msgstr ""
+msgstr "Admin-notater"
msgid "AdminArea|Active users"
-msgstr ""
+msgstr "Aktive brukere"
msgid "AdminArea|Billable users"
-msgstr ""
+msgstr "Fakturerbare brukere"
msgid "AdminArea|Blocked users"
-msgstr ""
+msgstr "Blokkerte brukere"
msgid "AdminArea|Bots"
+msgstr "Botter"
+
+msgid "AdminArea|Components"
msgstr ""
msgid "AdminArea|Developer"
+msgstr "Utvikler"
+
+msgid "AdminArea|Features"
msgstr ""
-msgid "AdminArea|Guest"
+msgid "AdminArea|Groups: %{number_of_groups}"
msgstr ""
+msgid "AdminArea|Guest"
+msgstr "Gjest"
+
msgid "AdminArea|Included Free in license"
+msgstr "Inkludert gratis i lisensen"
+
+msgid "AdminArea|Latest groups"
+msgstr ""
+
+msgid "AdminArea|Latest projects"
+msgstr ""
+
+msgid "AdminArea|Latest users"
msgstr ""
msgid "AdminArea|Maintainer"
+msgstr "Vedlikeholder"
+
+msgid "AdminArea|New group"
+msgstr ""
+
+msgid "AdminArea|New project"
+msgstr ""
+
+msgid "AdminArea|New user"
msgstr ""
msgid "AdminArea|Owner"
+msgstr "Eier"
+
+msgid "AdminArea|Projects: %{number_of_projects}"
msgstr ""
msgid "AdminArea|Reporter"
-msgstr ""
+msgstr "Rapportør"
msgid "AdminArea|Stop all jobs"
-msgstr ""
+msgstr "Stopp alle jobber"
msgid "AdminArea|Stop all jobs?"
-msgstr ""
+msgstr "Stopp alle jobber?"
msgid "AdminArea|Stop jobs"
-msgstr ""
+msgstr "Stopp jobber"
msgid "AdminArea|Stopping jobs failed"
-msgstr ""
+msgstr "Stopp jobber som mislyktes"
msgid "AdminArea|Total users"
-msgstr ""
+msgstr "Totalt antall brukere"
msgid "AdminArea|Users statistics"
-msgstr ""
+msgstr "Statistikk over brukere"
msgid "AdminArea|Users with highest role"
-msgstr ""
+msgstr "Brukere med høyeste rolle"
msgid "AdminArea|Users without a Group and Project"
+msgstr "Brukere uten gruppe og prosjekt"
+
+msgid "AdminArea|Users: %{number_of_users}"
msgstr ""
msgid "AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running."
-msgstr ""
+msgstr "Du er i ferd med å stoppe alle jobber. Dette stopper alle nåværende jobber som kjører."
msgid "AdminDashboard|Error loading the statistics. Please try again"
-msgstr ""
+msgstr "Feil under innlasting av statistikken. Vennligst prøv igjen"
msgid "AdminNote|Note"
-msgstr ""
+msgstr "Notis"
msgid "AdminProjects| You’re about to permanently delete the project %{projectName}, its repository, and all related resources including issues, merge requests, etc.. Once you confirm and press %{strong_start}Delete project%{strong_end}, it cannot be undone or recovered."
-msgstr ""
+msgstr "Du er i ferd med å permanent slette prosjektet %{projectName}, dets kodelager og alle relaterte ressurser, inkludert saker, fletteforespørsler, osv. Når du har bekreftet og trykket på %{strong_start}Slett prosjekt%{strong_end}, kan det ikke angres på eller gjenopprettes."
msgid "AdminProjects|Delete"
-msgstr ""
+msgstr "Slett"
msgid "AdminProjects|Delete Project %{projectName}?"
-msgstr ""
-
-msgid "AdminProjects|Delete project"
-msgstr ""
+msgstr "Vil du slette prosjektet %{projectName}?"
msgid "AdminSettings|Apply integration settings to all Projects"
-msgstr ""
+msgstr "Benytt integreringsinnstillingene på alle prosjekter"
msgid "AdminSettings|Auto DevOps domain"
-msgstr ""
+msgstr "Auto DevOps-domene"
msgid "AdminSettings|Elasticsearch, PlantUML, Slack application, Third party offers, Snowplow, Amazon EKS have moved to Settings &gt; General."
-msgstr ""
+msgstr "Elasticsearch, PlantUML, Slack-applikasjon, Tredjepartstilbud, Snowplow og Amazon EKS har blitt flyttet til Innstillinger &gt; Generelt."
msgid "AdminSettings|Enable shared runners for new projects"
msgstr ""
msgid "AdminSettings|Environment variables are protected by default"
-msgstr ""
+msgstr "Miljøvariabler er beskyttet som standard"
msgid "AdminSettings|Go to General Settings"
-msgstr ""
+msgstr "GÃ¥ til Generelle innstillinger"
msgid "AdminSettings|Integrations configured here will automatically apply to all projects on this instance."
-msgstr ""
+msgstr "Integrasjoner som konfigureres her vil automatisk gjelde for alle prosjekter i denne instansen."
msgid "AdminSettings|Moved to integrations"
-msgstr ""
+msgstr "Flyttet til integrasjoner"
msgid "AdminSettings|No required pipeline"
-msgstr ""
+msgstr "Ingen påkrevd rørledning"
msgid "AdminSettings|Required pipeline configuration"
-msgstr ""
+msgstr "Påkrevd rørledningsoppsett"
msgid "AdminSettings|Select a pipeline configuration file"
-msgstr ""
+msgstr "Velg en rørledningsoppsettsfil"
msgid "AdminSettings|Select a template"
-msgstr ""
+msgstr "Velg en mal"
msgid "AdminSettings|Service Templates will soon be deprecated."
msgstr ""
msgid "AdminSettings|Service template allows you to set default values for integrations"
-msgstr ""
+msgstr "Tjenestemaler lar deg bestemme standardverdier for integrasjoner"
msgid "AdminSettings|Set an instance-wide auto included %{link_start}pipeline configuration%{link_end}. This pipeline configuration will be run after the project's own configuration."
msgstr ""
msgid "AdminSettings|Some settings have moved"
-msgstr ""
+msgstr "Noen innstillinger har blitt flyttet"
msgid "AdminSettings|Specify a domain to use by default for every project's Auto Review Apps and Auto Deploy stages."
-msgstr ""
+msgstr "Spesifiser et domene som skal brukes som standard for hvert enkelt prosjekts autogjennomgangsapper og autodistribusjonstrinn."
msgid "AdminSettings|The required pipeline configuration can be selected from the %{code_start}gitlab-ci%{code_end} directory inside of the configured %{link_start}instance template repository%{link_end} or from GitLab provided configurations."
-msgstr ""
+msgstr "Den nødvendige rørledningskonfigurasjonen kan velges fra %{code_start}gitlab-ci%{code_end}-mappen inni det konfigurerte %{link_start}instansmal-lageret%{link_end} eller fra de GitLab-leverte konfigurasjonene."
msgid "AdminSettings|Try using the latest version of Integrations instead."
-msgstr ""
+msgstr "Prøv å bruke den nyeste versjonen av Integrasjoner i stedet."
msgid "AdminSettings|When creating a new environment variable it will be protected by default."
-msgstr ""
+msgstr "Når du oppretter en ny miljøvariabel, vil den være beskyttet som standard."
msgid "AdminStatistics|Active Users"
-msgstr ""
+msgstr "Aktive brukere"
msgid "AdminStatistics|Forks"
-msgstr ""
+msgstr "Utgreininger"
msgid "AdminStatistics|Issues"
-msgstr ""
+msgstr "Saker"
msgid "AdminStatistics|Merge Requests"
-msgstr ""
+msgstr "Fletteforespørsler"
msgid "AdminStatistics|Milestones"
-msgstr ""
+msgstr "Milepæler"
msgid "AdminStatistics|Notes"
-msgstr ""
+msgstr "Notiser"
msgid "AdminStatistics|SSH Keys"
-msgstr ""
+msgstr "SSH-nøkler"
msgid "AdminStatistics|Snippets"
-msgstr ""
+msgstr "Utdrag"
msgid "AdminUsers|2FA Disabled"
-msgstr ""
+msgstr "2FA er skrudd av"
msgid "AdminUsers|2FA Enabled"
-msgstr ""
+msgstr "2FA er skrudd på"
msgid "AdminUsers|Access"
-msgstr ""
+msgstr "Tilgang"
msgid "AdminUsers|Active"
-msgstr ""
+msgstr "Aktiv"
msgid "AdminUsers|Admin"
-msgstr ""
+msgstr "Admin"
msgid "AdminUsers|Administrators have access to all groups, projects and users and can manage all features in this installation"
-msgstr ""
+msgstr "Administratorer har tilgang til alle grupper, prosjekter og brukere og kan administrere alle funksjonene i denne installasjonen"
msgid "AdminUsers|Admins"
-msgstr ""
+msgstr "Administratorer"
msgid "AdminUsers|Automatically marked as default internal user"
msgstr ""
msgid "AdminUsers|Block"
-msgstr ""
+msgstr "Blokker"
msgid "AdminUsers|Block user"
-msgstr ""
+msgstr "Blokker bruker"
msgid "AdminUsers|Block user %{username}?"
-msgstr ""
+msgstr "Vil du blokkere brukeren %{username}?"
msgid "AdminUsers|Blocked"
-msgstr ""
+msgstr "Blokkert"
msgid "AdminUsers|Blocking user has the following effects:"
-msgstr ""
+msgstr "Å blokkere brukeren har følgende effekter:"
msgid "AdminUsers|Cannot unblock LDAP blocked users"
-msgstr ""
+msgstr "Kan ikke oppheve blokkering av LDAP-blokkerte brukere"
msgid "AdminUsers|Deactivate"
-msgstr ""
+msgstr "Deaktiver"
msgid "AdminUsers|Deactivate User %{username}?"
-msgstr ""
+msgstr "Vil du deaktivere brukeren %{username}?"
msgid "AdminUsers|Deactivate user"
-msgstr ""
+msgstr "Deaktiver bruker"
msgid "AdminUsers|Deactivated"
-msgstr ""
+msgstr "Deaktivert"
msgid "AdminUsers|Deactivating a user has the following effects:"
-msgstr ""
+msgstr "Å deaktivere en bruker har følgende effekter:"
msgid "AdminUsers|Delete User %{username} and contributions?"
-msgstr ""
+msgstr "Slette brukeren %{username} og hans/hennes bidrag?"
msgid "AdminUsers|Delete User %{username}?"
-msgstr ""
+msgstr "Slette brukeren %{username}?"
msgid "AdminUsers|Delete user"
-msgstr ""
+msgstr "Slett brukere"
msgid "AdminUsers|Delete user and contributions"
-msgstr ""
+msgstr "Slette brukeren og bidragene"
msgid "AdminUsers|External"
-msgstr ""
+msgstr "Ekstern"
msgid "AdminUsers|External users cannot see internal or private projects unless access is explicitly granted. Also, external users cannot create projects, groups, or personal snippets."
-msgstr ""
+msgstr "Eksterne brukere kan ikke se interne eller private prosjekter med mindre tilgang er uttrykkelig gitt. Eksterne brukere kan heller ikke opprette prosjekter, grupper, eller personlige utdrag."
msgid "AdminUsers|Is using seat"
-msgstr ""
+msgstr "Benytter setet"
msgid "AdminUsers|It's you!"
-msgstr ""
+msgstr "Det er deg!"
msgid "AdminUsers|New user"
-msgstr ""
+msgstr "Ny bruker"
msgid "AdminUsers|No users found"
-msgstr ""
+msgstr "Ingen brukere ble funnet"
msgid "AdminUsers|Owned groups will be left"
-msgstr ""
+msgstr "Eide grupper vil bli forlatt"
msgid "AdminUsers|Personal projects will be left"
-msgstr ""
+msgstr "Personlige prosjekter vil bli forlatt"
msgid "AdminUsers|Personal projects, group and user history will be left intact"
msgstr ""
msgid "AdminUsers|Reactivating a user will:"
-msgstr ""
+msgstr "Ã… reaktivere en bruker vil:"
msgid "AdminUsers|Regular"
-msgstr ""
+msgstr "Vanlig"
msgid "AdminUsers|Regular users have access to their groups and projects"
-msgstr ""
+msgstr "Vanlige brukere har tilgang til deres grupper og prosjekter"
msgid "AdminUsers|Restore user access to the account, including web, Git and API."
-msgstr ""
+msgstr "Gjenopprett brukertilgang til kontoen, inkludert nett, Git og API."
msgid "AdminUsers|Search by name, email or username"
-msgstr ""
+msgstr "Søk etter navn, e-postadresse eller brukernavn"
msgid "AdminUsers|Search users"
-msgstr ""
+msgstr "Søk etter brukere"
msgid "AdminUsers|Send email to users"
-msgstr ""
+msgstr "Send E-post til brukere"
msgid "AdminUsers|Sort by"
-msgstr ""
+msgstr "Sorter etter"
msgid "AdminUsers|The user will be logged out"
-msgstr ""
+msgstr "Brukeren vil bli logget av"
msgid "AdminUsers|The user will not be able to access git repositories"
-msgstr ""
+msgstr "Brukeren vil ikke kunne gå inn på git-kodelagre"
msgid "AdminUsers|The user will not be able to access the API"
-msgstr ""
+msgstr "Brukeren vil ikke kunne gå inn i API-en"
msgid "AdminUsers|The user will not be able to use slash commands"
-msgstr ""
+msgstr "Brukeren vil ikke kunne bruke skråstrek-kommandoer"
msgid "AdminUsers|The user will not receive any notifications"
-msgstr ""
+msgstr "Brukeren vil ikke motta noen varsler"
msgid "AdminUsers|To confirm, type %{projectName}"
-msgstr ""
+msgstr "For å bekrefte, skriv %{projectName}"
msgid "AdminUsers|To confirm, type %{username}"
-msgstr ""
+msgstr "For å bekrefte, skriv %{username}"
msgid "AdminUsers|User will not be able to access git repositories"
-msgstr ""
+msgstr "Brukeren vil ikke kunne gå inn på git-kodelagre"
msgid "AdminUsers|User will not be able to login"
-msgstr ""
+msgstr "Brukeren vil ikke kunne logge på"
msgid "AdminUsers|When the user logs back in, their account will reactivate as a fully active account"
-msgstr ""
+msgstr "Når brukeren logger på igjen, blir kontoen deres reaktivert som en fullt aktiv konto"
msgid "AdminUsers|Without projects"
-msgstr ""
+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 %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 ""
msgid "AdminUsers|You cannot remove your own admin rights."
+msgstr "Du kan ikke fjerne dine egne adminrettigheter."
+
+msgid "AdminUsers|You must transfer ownership or delete the groups owned by this user before you can delete their account"
msgstr ""
msgid "Administration"
-msgstr ""
+msgstr "Administrasjon"
msgid "Advanced"
+msgstr "Avansert"
+
+msgid "Advanced Search"
msgstr ""
-msgid "Advanced Settings"
+msgid "Advanced Search with Elasticsearch"
msgstr ""
+msgid "Advanced Settings"
+msgstr "Avanserte innstillinger"
+
msgid "Advanced permissions, Large File Storage and Two-Factor authentication settings."
-msgstr ""
+msgstr "Avanserte tillatelser, stor fillagring, og 2-trinnsautentiseringsinnstillinger."
msgid "Advanced search functionality"
-msgstr ""
+msgstr "Avansert søkefunksjonalitet"
msgid "After a successful password update you will be redirected to login screen."
-msgstr ""
+msgstr "Etter en vellykket passordoppdatering vil du bli omdirigert til påloggingsskjermen."
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 "Etter en vellykket passordoppdatering, vil du bli omdirigert til påloggingssiden der du kan logge på med ditt nye passord."
msgid "After that, you will not to be able to use merge approvals or code quality as well as many other features."
-msgstr ""
+msgstr "Etter det, vil du ikke kunne bruke flettegodkjenninger eller kodekvalitet, så vel som mange andre funksjoner."
msgid "After that, you will not to be able to use merge approvals or epics as well as many other features."
-msgstr ""
+msgstr "Etter det vil du ikke kunne bruke flettegodkjenninger eller eposer, så vel som mange andre funksjoner."
msgid "After that, you will not to be able to use merge approvals or epics as well as many security features."
-msgstr ""
+msgstr "Etter det vil du ikke kunne bruke flettegodkjenninger eller eposer, så vel som mange andre sikkerhetsfunksjoner."
msgid "Alert"
msgid_plural "Alerts"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "Varsel"
+msgstr[1] "Varsler"
msgid "AlertManagement|Acknowledged"
-msgstr ""
+msgstr "Anerkjent"
msgid "AlertManagement|Activity feed"
-msgstr ""
+msgstr "Aktivitetsstrøm"
msgid "AlertManagement|Alert"
-msgstr ""
+msgstr "Alarm"
msgid "AlertManagement|Alert assignee(s): %{assignees}"
msgstr ""
msgid "AlertManagement|Alert detail"
-msgstr ""
+msgstr "Alarmdetalj"
msgid "AlertManagement|Alert details"
-msgstr ""
+msgstr "Alarmdetaljer"
msgid "AlertManagement|Alert status: %{status}"
-msgstr ""
+msgstr "Alarmstatus: %{status}"
msgid "AlertManagement|Alerts"
-msgstr ""
+msgstr "Alarmer"
msgid "AlertManagement|All alerts"
-msgstr ""
+msgstr "Alle alarmer"
msgid "AlertManagement|Assign status"
-msgstr ""
+msgstr "Tildel status"
msgid "AlertManagement|Assignees"
-msgstr ""
+msgstr "Tilordnede"
msgid "AlertManagement|Authorize external service"
-msgstr ""
+msgstr "Autoriser ekstern tjeneste"
msgid "AlertManagement|Create incident"
msgstr ""
msgid "AlertManagement|Critical"
-msgstr ""
+msgstr "Kritisk"
msgid "AlertManagement|Display alerts from all your monitoring tools directly within GitLab. Streamline the investigation of your alerts and the escalation of alerts to incidents."
msgstr ""
msgid "AlertManagement|Edit"
+msgstr "Rediger"
+
+msgid "AlertManagement|Environment"
msgstr ""
msgid "AlertManagement|Events"
-msgstr ""
+msgstr "Hendelser"
msgid "AlertManagement|High"
-msgstr ""
+msgstr "Høy"
msgid "AlertManagement|Info"
-msgstr ""
+msgstr "Info"
msgid "AlertManagement|Issue"
+msgstr "Sak"
+
+msgid "AlertManagement|Key"
msgstr ""
msgid "AlertManagement|Low"
-msgstr ""
+msgstr "Lav"
msgid "AlertManagement|Medium"
-msgstr ""
+msgstr "Medium"
msgid "AlertManagement|Metrics"
-msgstr ""
+msgstr "MÃ¥ltall"
msgid "AlertManagement|Metrics weren't available in the alerts payload."
msgstr ""
msgid "AlertManagement|More information"
-msgstr ""
+msgstr "Mer informasjon"
msgid "AlertManagement|No alert data to display."
-msgstr ""
+msgstr "Ingen alarmdata å vise."
msgid "AlertManagement|No alerts available to display. See %{linkStart}enabling alert management%{linkEnd} for more information on adding alerts to the list."
msgstr ""
msgid "AlertManagement|No alerts to display."
-msgstr ""
+msgstr "Ingen varsler å vise."
msgid "AlertManagement|None"
-msgstr ""
+msgstr "Ingen"
msgid "AlertManagement|Open"
msgstr ""
msgid "AlertManagement|Opsgenie is enabled"
-msgstr ""
+msgstr "Opsgenie er aktivert"
msgid "AlertManagement|Please try again."
-msgstr ""
+msgstr "Vennligst prøv igjen."
msgid "AlertManagement|Reported %{when}"
-msgstr ""
+msgstr "Rapportert %{when}"
msgid "AlertManagement|Reported %{when} by %{tool}"
-msgstr ""
+msgstr "Rapportert %{when} av %{tool}"
msgid "AlertManagement|Resolved"
-msgstr ""
+msgstr "Oppklart"
msgid "AlertManagement|Runbook"
msgstr ""
msgid "AlertManagement|Service"
-msgstr ""
+msgstr "Tjeneste"
msgid "AlertManagement|Severity"
-msgstr ""
+msgstr "Alvorlighet"
msgid "AlertManagement|Start time"
-msgstr ""
+msgstr "Starttid"
msgid "AlertManagement|Status"
-msgstr ""
+msgstr "Status"
msgid "AlertManagement|Surface alerts in GitLab"
msgstr ""
msgid "AlertManagement|There was an error displaying the alert. Please refresh the page to try again."
-msgstr ""
+msgstr "En feil oppstod under visning av varselet. Oppdater siden for å prøve igjen."
msgid "AlertManagement|There was an error displaying the alerts. Confirm your endpoint's configuration details to ensure alerts appear."
-msgstr ""
+msgstr "En feil oppstod under visning av alarmene. Bekreft ditt endepunkts konfigurasjonsdetaljer for å sikre at alarmer vises."
msgid "AlertManagement|There was an error while updating the To-Do of the alert."
-msgstr ""
+msgstr "Det oppstod en feil under oppdatering av alarmens gjøremål."
msgid "AlertManagement|There was an error while updating the assignee(s) list. Please try again."
-msgstr ""
+msgstr "En feil oppstod under oppdatering av listen over tilordnede. Vennligst prøv igjen."
msgid "AlertManagement|There was an error while updating the assignee(s) of the alert. Please try again."
msgstr ""
msgid "AlertManagement|There was an error while updating the status of the alert."
-msgstr ""
+msgstr "Det oppstod en feil under oppdatering av alarmens status."
msgid "AlertManagement|This assignee cannot be assigned to this alert."
-msgstr ""
+msgstr "Denne tilordnede kan ikke tilordnes dette varselet."
msgid "AlertManagement|Tool"
-msgstr ""
+msgstr "Verktøy"
msgid "AlertManagement|Triggered"
-msgstr ""
+msgstr "Trigget"
msgid "AlertManagement|Unknown"
+msgstr "Ukjent"
+
+msgid "AlertManagement|Value"
msgstr ""
msgid "AlertManagement|View alerts in Opsgenie"
-msgstr ""
+msgstr "Vis alarmer i Opsgenie"
msgid "AlertManagement|View incident"
msgstr ""
@@ -2268,19 +2390,19 @@ msgid "AlertManagement|You have enabled the Opsgenie integration. Your alerts wi
msgstr ""
msgid "AlertService|Review your external service's documentation to learn where to provide this information to your external service, and the %{linkStart}GitLab documentation%{linkEnd} to learn more about configuring your endpoint."
-msgstr ""
+msgstr "Gå gjennom dokumentasjonen til din eksterne tjeneste for å lære hvor du kan gi denne informasjonen til din eksterne tjeneste, og %{linkStart}GitLab-dokumentasjonen%{linkEnd} for å lære mer om å sette opp ditt endepunkt."
msgid "AlertService|You must provide this URL and authorization key to authorize an external service to send alerts to GitLab. You can provide this URL and key to multiple services. After configuring an external service, alerts from your service will display on the GitLab %{linkStart}Alerts%{linkEnd} page."
-msgstr ""
+msgstr "Du må oppgi denne URL-en og autorisasjonsnøkkelen for å autorisere en ekstern tjeneste til å sende varsler til GitLab. Du kan oppgi denne URL-en og nøkkelen til flere tjenester. Etter at du har konfigurert en ekstern tjeneste, vises varsler fra tjenesten din på GitLab sin %{linkStart}Alarmer%{linkEnd}-side."
msgid "AlertSettings|API URL"
-msgstr ""
+msgstr "API-URL"
msgid "AlertSettings|Active"
-msgstr ""
+msgstr "Aktiv"
msgid "AlertSettings|Add URL and auth key to your Prometheus config file"
-msgstr ""
+msgstr "Legg til URL og autoriseringsnøkkel i din Prometheus-oppsettsfil"
msgid "AlertSettings|Alert test payload"
msgstr ""
@@ -2289,31 +2411,31 @@ msgid "AlertSettings|Alerts endpoint successfully activated."
msgstr ""
msgid "AlertSettings|Authorization key"
-msgstr ""
+msgstr "Autorisasjonsnøkkel"
msgid "AlertSettings|Authorization key has been successfully reset. Please save your changes now."
msgstr ""
msgid "AlertSettings|Copy"
-msgstr ""
+msgstr "Kopier"
msgid "AlertSettings|Enter test alert JSON...."
msgstr ""
msgid "AlertSettings|External Prometheus"
-msgstr ""
+msgstr "Ekstern Prometheus"
msgid "AlertSettings|Generic"
-msgstr ""
+msgstr "Generisk"
msgid "AlertSettings|Integrations"
-msgstr ""
+msgstr "Integreringer"
msgid "AlertSettings|Learn more about our %{linkStart}upcoming integrations%{linkEnd}"
msgstr ""
msgid "AlertSettings|Opsgenie"
-msgstr ""
+msgstr "Opsgenie"
msgid "AlertSettings|Reset key"
msgstr ""
@@ -2322,7 +2444,7 @@ msgid "AlertSettings|Resetting the authorization key for this project will requi
msgstr ""
msgid "AlertSettings|Review your external service's documentation to learn where to provide this information to your external service, and the %{linkStart}GitLab documentation%{linkEnd} to learn more about configuring your endpoint."
-msgstr ""
+msgstr "Gå gjennom dokumentasjonen til din eksterne tjeneste for å lære hvor du kan gi denne informasjonen til din eksterne tjeneste, og %{linkStart}GitLab-dokumentasjonen%{linkEnd} for å lære mer om å sette opp ditt endepunkt."
msgid "AlertSettings|Test alert payload"
msgstr ""
@@ -2334,112 +2456,115 @@ msgid "AlertSettings|Test failed. Do you still want to save your changes anyway?
msgstr ""
msgid "AlertSettings|There was an error updating the alert settings"
-msgstr ""
+msgstr "Det oppstod en feil under oppdatering av alarminnstillingene"
msgid "AlertSettings|There was an error while trying to reset the key. Please refresh the page to try again."
-msgstr ""
+msgstr "Det oppstod en feil under tilbakestilling av nøkkelen. Oppdater siden for å prøve igjen."
msgid "AlertSettings|URL cannot be blank and must start with http or https"
msgstr ""
msgid "AlertSettings|Webhook URL"
-msgstr ""
+msgstr "Webhook-URL"
msgid "AlertSettings|You can now set up alert endpoints for manually configured Prometheus instances in the Alerts section on the Operations settings page. Alert endpoint fields on this page have been deprecated."
-msgstr ""
+msgstr "Du kan nå sette opp varslings-endepunkter for manuelt konfigurerte Prometheus-instans i Varsler-seksjonen på operasjonsinnstillingsside. Feltet for varslings-endepunkter på denne siden har blitt utfaset."
msgid "AlertSettings|You must provide this URL and authorization key to authorize an external service to send alerts to GitLab. You can provide this URL and key to multiple services. After configuring an external service, alerts from your service will display on the GitLab %{linkStart}Alerts%{linkEnd} page."
-msgstr ""
+msgstr "Du må oppgi denne URL-en og autorisasjonsnøkkelen for å autorisere en ekstern tjeneste til å sende varsler til GitLab. Du kan oppgi denne URL-en og nøkkelen til flere tjenester. Etter at du har konfigurert en ekstern tjeneste, vises varsler fra tjenesten din på GitLab sin %{linkStart}Alarmer%{linkEnd}-side."
msgid "AlertSettings|Your changes were successfully updated."
-msgstr ""
+msgstr "Endringene dine ble vellykket oppdatert."
msgid "Alerts"
-msgstr ""
+msgstr "Varsler"
msgid "Alerts endpoint"
-msgstr ""
+msgstr "Alarm-endepunkt"
msgid "Algorithm"
-msgstr ""
+msgstr "Algoritme"
msgid "All"
-msgstr ""
+msgstr "Alle"
msgid "All %{replicableType} are being scheduled for %{action}"
-msgstr ""
+msgstr "Alle %{replicableType} er planlagt for %{action}"
msgid "All (default)"
-msgstr ""
+msgstr "Alle (standard)"
msgid "All Members"
-msgstr ""
+msgstr "Alle medlemmer"
msgid "All branches"
-msgstr ""
+msgstr "Alle grener"
msgid "All changes are committed"
-msgstr ""
+msgstr "Alle endringer er loggført"
msgid "All default stages are currently visible"
-msgstr ""
+msgstr "Alle standardtrinn er synlige for øyeblikket"
msgid "All email addresses will be used to identify your commits."
-msgstr ""
+msgstr "Alle e-postadressene vil bli brukt til å identifisere dine commiter."
msgid "All environments"
-msgstr ""
+msgstr "Alle miljøer"
msgid "All epics"
-msgstr ""
+msgstr "Alle eposer"
msgid "All features are enabled for blank projects, from templates, or when importing, but you can disable them afterward in the project settings."
-msgstr ""
+msgstr "Alle funksjoner er aktivert for blanke prosjekter, fra maler, eller når du importerer, men du kan deaktivere dem etterpå i prosjektinnstillingene."
msgid "All groups and projects"
-msgstr ""
+msgstr "Alle grupper og prosjekter"
msgid "All issues for this milestone are closed."
-msgstr ""
+msgstr "Alle saker for denne milepælen er lukket."
msgid "All issues for this milestone are closed. You may close this milestone now."
-msgstr ""
+msgstr "Alle saker for denne milepælen er lukket. Du kan lukke denne milepælen nå."
msgid "All merge conflicts were resolved. The merge request can now be merged."
-msgstr ""
+msgstr "Alle flettekonflikter ble oppklart. Fletteforespørselen kan nå bli innflettet."
msgid "All merge request dependencies have been merged"
-msgstr ""
+msgstr "Alle fletteforespørselsavhengigheter har blitt innflettet"
msgid "All paths are relative to the GitLab URL. Do not include %{relative_url_link_start}relative URL%{relative_url_link_end}."
msgstr ""
msgid "All projects"
+msgstr "Alle prosjekter"
+
+msgid "All projects selected"
msgstr ""
msgid "All security scans are enabled because %{linkStart}Auto DevOps%{linkEnd} is enabled on this project"
-msgstr ""
+msgstr "Alle sikkerhetsskanninger er aktivert fordi %{linkStart}Auto DevOps%{linkEnd} er aktivert på dette prosjektet"
msgid "All threads resolved"
-msgstr ""
+msgstr "Alle tråder er oppklart"
msgid "All users"
-msgstr ""
+msgstr "Alle brukere"
msgid "All users must have a name."
-msgstr ""
+msgstr "Alle brukere må ha et navn."
msgid "Allow \"%{group_name}\" to sign you in"
-msgstr ""
+msgstr "Tillat \"%{group_name}\" å logge deg på"
msgid "Allow access to the following IP addresses"
-msgstr ""
+msgstr "Gi tilgang til følgende IP-adresser"
msgid "Allow commits from members who can merge to the target branch."
-msgstr ""
+msgstr "Tillat commits fra medlemmer som kan flette inn til målgrenen."
msgid "Allow group owners to manage LDAP-related settings"
-msgstr ""
+msgstr "Tillat gruppeeiere å behandle LDAP-relaterte innstillinger"
msgid "Allow only the selected protocols to be used for Git access."
msgstr ""
@@ -2448,28 +2573,28 @@ msgid "Allow owners to manage default branch protection per group"
msgstr ""
msgid "Allow owners to manually add users outside of LDAP"
-msgstr ""
+msgstr "Tillat eiere å legge til brukere manuelt utenfor LDAP"
msgid "Allow projects within this group to use Git LFS"
-msgstr ""
+msgstr "Tillat prosjekter innenfor denne gruppen å bruke Git LFS"
msgid "Allow public access to pipelines and job details, including output logs and artifacts"
msgstr ""
msgid "Allow rendering of PlantUML diagrams in Asciidoc documents."
-msgstr ""
+msgstr "Tillat visning av PlantUML-diagrammer i Asciidoc-dokumenter."
msgid "Allow repository mirroring to be configured by project maintainers"
-msgstr ""
+msgstr "Tillat at kodelagerspeiling kan bli satt opp av prosjektvedlikeholdere"
msgid "Allow requests to the local network from hooks and services."
-msgstr ""
+msgstr "Tillat forespørsler til det lokale nettverket fra kroker og tjenester."
msgid "Allow requests to the local network from system hooks"
-msgstr ""
+msgstr "Tillat forespørsler til det lokale nettverket fra systemkroker"
msgid "Allow requests to the local network from web hooks and services"
-msgstr ""
+msgstr "Tillat forespørsler til det lokale nettverket fra Webhooks og tjenester"
msgid "Allow this key to push to repository as well? (Default only allows pull access.)"
msgstr ""
@@ -2478,30 +2603,33 @@ msgid "Allow this secondary node to replicate content on Object Storage"
msgstr ""
msgid "Allow users to dismiss the broadcast message"
-msgstr ""
+msgstr "Tillat brukere å avvise utsendingsmeldingen"
msgid "Allow users to register any application to use GitLab as an OAuth provider"
msgstr ""
msgid "Allow users to request access (if visibility is public or internal)"
-msgstr ""
+msgstr "Tillat brukere å be om tilgang (dersom synligheten er offentlig eller intern)"
msgid "Allowed"
-msgstr ""
+msgstr "Tillatt"
msgid "Allowed Geo IP"
-msgstr ""
+msgstr "Tillatt Geo-IP"
msgid "Allowed email domain restriction only permitted for top-level groups"
msgstr ""
msgid "Allowed to fail"
-msgstr ""
+msgstr "Tillatt å mislykkes"
msgid "Allows you to add and manage Kubernetes clusters."
-msgstr ""
+msgstr "Lar deg legge til og behandle Kubernetes-klynger."
msgid "Almost there"
+msgstr "Nesten der"
+
+msgid "Already blocked"
msgstr ""
msgid "Also called \"Issuer\" or \"Relying party trust identifier\""
@@ -2514,178 +2642,166 @@ msgid "Also unassign this user from related issues and merge requests"
msgstr ""
msgid "Alternate support URL for help page and help dropdown"
-msgstr ""
+msgstr "Alternativ støtte-URL for hjelpesiden og nedfallsmenyen for hjelp"
msgid "Alternatively, you can convert your account to a managed account by the %{group_name} group."
-msgstr ""
+msgstr "Alternativt kan du konvertere kontoen din til en administrert konto av %{group_name}-gruppen."
msgid "Amazon EKS"
-msgstr ""
+msgstr "Amazon EKS"
msgid "Amazon EKS integration allows you to provision EKS clusters from GitLab."
-msgstr ""
+msgstr "Amazon EKS-integrasjon lar deg klargjøre EKS-klynger fra GitLab."
msgid "Amazon Web Services"
-msgstr ""
+msgstr "Amazon Web Services"
msgid "Amazon Web Services Logo"
-msgstr ""
+msgstr "Amazon Web Services-logo"
msgid "Amazon authentication is not %{link_start}correctly configured%{link_end}. Ask your GitLab administrator if you want to use this service."
-msgstr ""
+msgstr "Amazon-autentisering er ikke %{link_start}riktig konfigurert%{link_end}. Spør GitLab-administratoren din hvis du vil bruke denne tjenesten."
msgid "Amount of time (in hours) that users are allowed to skip forced configuration of two-factor authentication"
-msgstr ""
+msgstr "Tidsmengden (i timer) hvor brukere har lov til å hoppe over tvungen konfigurasjon av 2-trinnsautentisering"
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 ""
+msgstr "En %{link_start}alarm%{link_end} med samme fingeravtrykk er allerede åpent. Hvis du vil endre statusen til dette varselet, må du oppklare den tilknyttede alarmen."
msgid "An administrator changed the password for your GitLab account on %{link_to}."
-msgstr ""
+msgstr "En administrator endret passordet til GitLab-kontoen din på %{link_to}."
msgid "An alert has been triggered in %{project_path}."
-msgstr ""
+msgstr "En alarm har blitt utløst i %{project_path}."
msgid "An application called %{link_to_client} is requesting access to your GitLab account."
-msgstr ""
+msgstr "En applikasjon kalt %{link_to_client} ber om tilgang til din GitLab-konto."
msgid "An email notification was recently sent from the admin panel. Please wait %{wait_time_in_words} before attempting to send another message."
msgstr ""
msgid "An 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 ""
+msgstr "Et tomt GitLab-brukerfelt vil legge til FogBugz-brukerens fulle navn (f.eks. \"Av John Smith\") i beskrivelsen av alle saker og kommentarer. Det vil også knytte og/eller tildele disse sakene og kommentarene til prosjektskaperen."
msgid "An error has occurred"
+msgstr "En feil har oppstått"
+
+msgid "An error occured while making the changes: %{error}"
msgstr ""
msgid "An error occurred adding a draft to the thread."
-msgstr ""
+msgstr "En feil oppstod under tillegging av et utkast til tråden."
msgid "An error occurred adding a new draft."
-msgstr ""
+msgstr "En feil oppstod under tillegging av et nytt utkast."
msgid "An error occurred creating the new branch."
-msgstr ""
+msgstr "En feil oppstod under opprettelsen av den nye grenen."
msgid "An error occurred fetching the approval rules."
-msgstr ""
+msgstr "Det oppstod en feil ved innhenting av godkjenningsreglene."
msgid "An error occurred fetching the approvers for the new rule."
-msgstr ""
+msgstr "Det oppstod en feil under innhenting av godkjennerne for den nye regelen."
msgid "An error occurred fetching the dropdown data."
-msgstr ""
+msgstr "Det oppstod en feil under henting av nedfallsdataene."
msgid "An error occurred fetching the project authors."
-msgstr ""
+msgstr "Det oppstod en feil under innhenting av prosjektskaperne."
msgid "An error occurred previewing the blob"
-msgstr ""
+msgstr "En feil oppstod under forhåndsvisning av blobben"
msgid "An error occurred when toggling the notification subscription"
-msgstr ""
-
-msgid "An error occurred when trying to resolve a comment. Please try again."
-msgstr ""
-
-msgid "An error occurred when trying to resolve a discussion. Please try again."
-msgstr ""
+msgstr "En feil oppstod under veksling av varslingsabonnement"
msgid "An error occurred when updating the issue weight"
-msgstr ""
+msgstr "En feil oppstod under oppdatering av saksvektleggingen"
msgid "An error occurred while acknowledging the notification. Refresh the page and try again."
-msgstr ""
+msgstr "En feil oppstod under bekreftelse av meldingen. Oppdater siden og prøv igjen."
msgid "An error occurred while adding approvers"
-msgstr ""
+msgstr "En feil oppstod under tillegging av godkjennere"
msgid "An error occurred while adding formatted title for epic"
msgstr ""
msgid "An error occurred while checking group path. Please refresh and try again."
-msgstr ""
-
-msgid "An error occurred while committing your changes."
-msgstr ""
-
-msgid "An error occurred while creating the list. Please try again."
-msgstr ""
+msgstr "En feil oppstod under sjekking av gruppefilbanen. Vennligst oppdater og prøv igjen."
msgid "An error occurred while decoding the file."
-msgstr ""
+msgstr "En feil oppstod under dekoding av filen."
msgid "An error occurred while deleting the approvers group"
-msgstr ""
+msgstr "Det oppsto en feil under sletting av godkjenningsgruppen"
msgid "An error occurred while deleting the comment"
-msgstr ""
+msgstr "En feil oppstod under sletting av kommentaren"
msgid "An error occurred while deleting the pipeline."
-msgstr ""
+msgstr "En feil oppstod under sletting av rørledningen."
msgid "An error occurred while detecting host keys"
-msgstr ""
+msgstr "En feil oppstod under oppdaging av vertsnøkler"
msgid "An error occurred while disabling Service Desk."
-msgstr ""
+msgstr "En feil oppstod under avskruing av Service Desk."
msgid "An error occurred while dismissing the alert. Refresh the page and try again."
-msgstr ""
+msgstr "En feil oppstod under avvisning av meldingen. Oppdater siden og prøv igjen."
msgid "An error occurred while dismissing the feature highlight. Refresh the page and try dismissing again."
msgstr ""
msgid "An error occurred while enabling Service Desk."
-msgstr ""
+msgstr "En feil oppstod under påskruing av tjenestedesken."
msgid "An error occurred while fetching branches. Retry the search."
-msgstr ""
+msgstr "Det oppstod en feil under innhenting av grener. Prøv søket på nytt."
msgid "An error occurred while fetching commits. Retry the search."
-msgstr ""
+msgstr "Det oppstod en feil under innhenting av commiter. Prøv søket på nytt."
msgid "An error occurred while fetching coverage reports."
-msgstr ""
+msgstr "Det oppstod en feil under innhenting av dekningsrapporter."
msgid "An error occurred while fetching environments."
-msgstr ""
+msgstr "En feil oppstod under innhenting av miljøer."
msgid "An error occurred while fetching exposed artifacts."
-msgstr ""
+msgstr "Det oppstod en feil under innhenting av eksponerte artefakter."
msgid "An error occurred while fetching folder content."
-msgstr ""
+msgstr "En feil oppstod under innhenting av mappeinnhold."
msgid "An error occurred while fetching issues."
-msgstr ""
+msgstr "En feil oppstod under innhenting av saker."
msgid "An error occurred while fetching label colors."
-msgstr ""
+msgstr "En feil oppstod under innhenting av stempelfarger."
msgid "An error occurred while fetching markdown preview"
-msgstr ""
+msgstr "En feil oppstod under forhåndsvisning av markdown"
msgid "An error occurred while fetching pending comments"
-msgstr ""
+msgstr "En feil oppstod under innhenting av ventende kommentarer"
msgid "An error occurred while fetching projects autocomplete."
-msgstr ""
+msgstr "En feill oppstod under innhenting av autofullføring av prosjekter."
msgid "An error occurred while fetching sidebar data"
-msgstr ""
+msgstr "En feil oppstod under innhenting av sidelinjedata"
msgid "An error occurred while fetching tags. Retry the search."
-msgstr ""
+msgstr "Det oppstod en feil under innhenting av etiketter. Prøv søket på nytt."
msgid "An error occurred while fetching terraform reports."
-msgstr ""
+msgstr "Det oppstod en feil under innhenting av terraformingsrapporter."
msgid "An error occurred while fetching the Service Desk address."
-msgstr ""
-
-msgid "An error occurred while fetching the board issues. Please reload the page."
-msgstr ""
+msgstr "Det oppstod en feil under innhenting av Service Desk-adressen."
msgid "An error occurred while fetching the board lists. Please reload the page."
msgstr ""
@@ -2693,206 +2809,200 @@ msgstr ""
msgid "An error occurred while fetching the board lists. Please try again."
msgstr ""
-msgid "An error occurred while fetching the board swimlanes. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the builds."
-msgstr ""
+msgstr "En feil oppstod under innhenting av byggversjonene."
msgid "An error occurred while fetching the job log."
-msgstr ""
+msgstr "En feil oppstod under innhenting av jobbloggføringen."
-msgid "An error occurred while fetching the job trace."
+msgid "An error occurred while fetching the job logs."
msgstr ""
msgid "An error occurred while fetching the job."
-msgstr ""
+msgstr "En feil oppstod under innhenting av jobben."
msgid "An error occurred while fetching the jobs."
-msgstr ""
+msgstr "En feil oppstod under innhenting av jobbene."
msgid "An error occurred while fetching the latest pipeline."
-msgstr ""
+msgstr "En feil oppstod under innhenting av den nyeste rørledningen."
msgid "An error occurred while fetching the pipeline."
-msgstr ""
+msgstr "En feil oppstod under innhenting av rørledningen."
msgid "An error occurred while fetching the releases. Please try again."
-msgstr ""
+msgstr "En feil oppstod under innhenting av lanseringene. Vennligst prøv igjen."
msgid "An error occurred while fetching this tab."
-msgstr ""
+msgstr "En feil oppstod under innhenting av denne fanen."
msgid "An error occurred while generating a username. Please try again."
-msgstr ""
+msgstr "En feil oppstod under generering av brukernavn. Vennligst prøv igjen."
msgid "An error occurred while getting files for - %{branchId}"
-msgstr ""
+msgstr "En feil oppstod under henting av filer for - %{branchId}"
msgid "An error occurred while getting projects"
-msgstr ""
+msgstr "Det oppstod en feil under innhenting av prosjekter"
msgid "An error occurred while importing project: %{details}"
-msgstr ""
+msgstr "En feil oppstod under importering av prosjekt: %{details}"
msgid "An error occurred while initializing path locks"
msgstr ""
msgid "An error occurred while loading all the files."
-msgstr ""
+msgstr "En feil oppstod under innlasting av alle filene."
msgid "An error occurred while loading chart data"
-msgstr ""
+msgstr "En feil oppstod under innlasting av diagramdata"
msgid "An error occurred while loading commit signatures"
-msgstr ""
+msgstr "En feil oppstod under innlasting av commitsignaturer"
msgid "An error occurred while loading designs. Please try again."
-msgstr ""
+msgstr "En feil oppstod under innlasting av designene. Vennligst prøv igjen."
msgid "An error occurred while loading diff"
-msgstr ""
+msgstr "En feil oppstod under innlasting av diffen"
msgid "An error occurred while loading filenames"
-msgstr ""
+msgstr "En feil oppstod under innlasting av filnavn"
msgid "An error occurred while loading group members."
-msgstr ""
+msgstr "En feil oppstod under innlasting av gruppemedlemmer."
msgid "An error occurred while loading issues"
-msgstr ""
+msgstr "En feil oppstod under innlasting av saker"
msgid "An error occurred while loading merge requests."
-msgstr ""
+msgstr "Det oppstod en feil under innlasting av fletteforespørsler."
msgid "An error occurred while loading milestones"
-msgstr ""
+msgstr "En feil oppstod under innlasting av milepæler"
msgid "An error occurred while loading project creation UI"
-msgstr ""
+msgstr "En feil oppstod under innlasting av prosjektopprettings-grensesnittet"
msgid "An error occurred while loading the data. Please try again."
-msgstr ""
+msgstr "En feil oppstod under innlasting av dataene. Vennligst prøv igjen."
msgid "An error occurred while loading the file"
-msgstr ""
+msgstr "En feil oppstod under innlasting av filen"
msgid "An error occurred while loading the file content."
-msgstr ""
+msgstr "En feil oppstod under innlasting av filinnholdet."
msgid "An error occurred while loading the file."
-msgstr ""
+msgstr "En feil oppstod under innlasting av filen."
msgid "An error occurred while loading the file. Please try again later."
-msgstr ""
+msgstr "En feil oppstod under innlasting av filen. Vennligst prøv igjen senere."
msgid "An error occurred while loading the merge request changes."
-msgstr ""
+msgstr "Det oppstod en feil under innlasting av fletteforepørsels-endringene."
msgid "An error occurred while loading the merge request version data."
-msgstr ""
+msgstr "En feil oppstod under innlasting av fletteforepørsels-versjonsdataene."
msgid "An error occurred while loading the merge request."
-msgstr ""
+msgstr "En feil oppstod under innlasting av fletteforespørselsen."
msgid "An error occurred while loading the pipelines jobs."
-msgstr ""
+msgstr "En feil oppstod under innhenting av rørledningsjobbene."
msgid "An error occurred while loading the subscription details."
-msgstr ""
+msgstr "Det oppstod en feil under innlasting av abonnementsdetaljene."
msgid "An error occurred while making the request."
-msgstr ""
+msgstr "Det oppsto en feil under forespørselsforsøket."
msgid "An error occurred while moving the issue."
-msgstr ""
+msgstr "En feil oppstod under flytting av saken."
msgid "An error occurred while parsing recent searches"
msgstr ""
msgid "An error occurred while parsing the file."
-msgstr ""
+msgstr "En feil oppstod under behandling av filen."
msgid "An error occurred while removing epics."
-msgstr ""
+msgstr "En feil oppstod under fjerning av eposer."
msgid "An error occurred while removing issues."
-msgstr ""
+msgstr "En feil oppstod under fjerning av saker."
msgid "An error occurred while rendering preview broadcast message"
msgstr ""
msgid "An error occurred while rendering the editor"
-msgstr ""
+msgstr "En feil oppstod under rendring av redigereren"
msgid "An error occurred while reordering issues."
-msgstr ""
+msgstr "En feil oppstod under omsortering av saker."
msgid "An error occurred while requesting data from the Jira service"
-msgstr ""
+msgstr "En feil oppstod under forespørsel om data fra Jira-tjenesten"
msgid "An error occurred while retrieving calendar activity"
-msgstr ""
+msgstr "Det oppstod en feil under innhenting av kalenderaktivitet"
msgid "An error occurred while retrieving diff"
-msgstr ""
+msgstr "Det oppstod en feil under innhenting av diff"
msgid "An error occurred while retrieving diff files"
-msgstr ""
+msgstr "En feil oppstod under innhenting av diff-filer"
msgid "An error occurred while retrieving projects."
-msgstr ""
+msgstr "Det oppstod en feil under innhenting av prosjekter."
msgid "An error occurred while saving LDAP override status. Please try again."
msgstr ""
msgid "An error occurred while saving assignees"
-msgstr ""
-
-msgid "An error occurred while saving the template. Please check if the template exists."
-msgstr ""
+msgstr "En feil oppstod under lagring av tilordnede"
msgid "An error occurred while searching for milestones"
-msgstr ""
+msgstr "En feil oppstod under søking etter milepæler"
msgid "An error occurred while subscribing to notifications."
-msgstr ""
+msgstr "En feil oppstod under abonnering på varsler."
msgid "An error occurred while triggering the job."
-msgstr ""
+msgstr "En feil oppstod under trigging av jobben."
msgid "An error occurred while trying to run a new pipeline for this Merge Request."
msgstr ""
msgid "An error occurred while unsubscribing to notifications."
-msgstr ""
+msgstr "En feil oppstod under avabonnering på varsler."
msgid "An error occurred while updating approvers"
-msgstr ""
+msgstr "En feil oppstod under oppdatering av godkjennere"
-msgid "An error occurred while updating the comment"
+msgid "An error occurred while updating labels."
msgstr ""
-msgid "An error occurred while updating the list. Please try again."
-msgstr ""
+msgid "An error occurred while updating the comment"
+msgstr "En feil oppstod under oppdatering av kommentaren"
msgid "An error occurred while validating group path"
-msgstr ""
+msgstr "En feil oppstod under validering av gruppebanen"
msgid "An error occurred while validating username"
-msgstr ""
+msgstr "Det oppstod en feil under validering av brukernavn"
msgid "An error occurred. Please sign in again."
-msgstr ""
+msgstr "En feil oppstod. Vennligst logg inn på nytt."
msgid "An error occurred. Please try again."
-msgstr ""
+msgstr "En feil oppstod. Vennligst prøv igjen."
msgid "An error ocurred while loading your content. Please try again."
-msgstr ""
+msgstr "En feil oppstod under innlasting av innholdet ditt. Vennligst prøv igjen."
msgid "An example project for managing Kubernetes clusters integrated with GitLab."
-msgstr ""
+msgstr "Et eksempelprosjekt for å administrere Kubernetes-klynger som er integrert med GitLab."
msgid "An example showing how to use Jsonnet with GitLab dynamic child pipelines"
msgstr ""
@@ -2901,240 +3011,246 @@ msgid "An instance-level serverless domain already exists."
msgstr ""
msgid "An issue already exists"
-msgstr ""
+msgstr "En sak finnes allerede"
msgid "An issue can be a bug, a todo or a feature request that needs to be discussed in a project. Besides, issues are searchable and filterable."
-msgstr ""
+msgstr "En sak kan være en feil, et gjøremål, eller en funksjonsforespørsel som behøver å diskuteres i et prosjekt. Dessuten er saker søkbare og filtrerbare."
msgid "An unauthenticated user"
-msgstr ""
+msgstr "En uautentisert bruker"
msgid "An unexpected error occurred while checking the project environment."
-msgstr ""
+msgstr "En uventet feil oppstod under sjekking av prosjektmiljøet."
msgid "An unexpected error occurred while checking the project runners."
msgstr ""
msgid "An unexpected error occurred while communicating with the Web Terminal."
-msgstr ""
+msgstr "En uventet feil oppstod under kommunikasjonen med netterminalen."
msgid "An unexpected error occurred while starting the Web Terminal."
-msgstr ""
+msgstr "En uventet feil oppstod under oppstart av netterminalen."
msgid "An unexpected error occurred while stopping the Web Terminal."
-msgstr ""
+msgstr "En uventet feil oppstod under stopping av netterminalen."
msgid "An unknown error occurred while loading this graph."
+msgstr "En ukjent feil oppstod under innlasting av denne grafen."
+
+msgid "An unknown error occurred."
msgstr ""
msgid "Analytics"
-msgstr ""
+msgstr "Analyser"
msgid "Analyze a review version of your web application."
-msgstr ""
+msgstr "Analyser en gjennomgangsversjon av nettapplikasjonen din."
msgid "Analyze your dependencies for known vulnerabilities."
-msgstr ""
+msgstr "Analyser avhengighetene dine for kjente sårbarheter."
msgid "Analyze your source code and git history for secrets."
-msgstr ""
+msgstr "Analyser kildekoden og git-historikken din for hemmeligheter."
msgid "Analyze your source code for known vulnerabilities."
-msgstr ""
+msgstr "Analyser kildekoden din for kjente sårbarheter."
msgid "Ancestors"
-msgstr ""
+msgstr "Forfedre"
msgid "Anonymous"
-msgstr ""
+msgstr "Anonym"
msgid "Another action is currently in progress"
-msgstr ""
+msgstr "En annen handling pågår for øyeblikket"
msgid "Another issue tracker is already in use. Only one issue tracker service can be active at a time"
-msgstr ""
+msgstr "En annen sakssporer er allerede i bruk. Bare én sakssporingstjeneste kan være aktiv om gangen"
msgid "Anti-spam verification"
-msgstr ""
+msgstr "Anti-spam verifisering"
msgid "Any"
-msgstr ""
+msgstr "Enhver"
-msgid "Any Author"
+msgid "Any %{header}"
msgstr ""
-msgid "Any Status"
-msgstr ""
+msgid "Any Author"
+msgstr "Enhver skaper"
msgid "Any branch"
-msgstr ""
+msgstr "Enhver gren"
msgid "Any eligible user"
-msgstr ""
+msgstr "Enhver kvalifisert bruker"
msgid "Any encrypted tokens"
-msgstr ""
+msgstr "Alle krypterte sjetonger"
msgid "Any files larger than this limit will not be indexed, and thus will not be searchable."
-msgstr ""
+msgstr "Alle filer som er større enn denne grensen, vil ikke bli indeksert, og vil dermed ikke være søkbare."
msgid "Any label"
-msgstr ""
+msgstr "Ethvert stempel"
msgid "Any member with Developer or higher permissions to the project."
msgstr ""
msgid "Any milestone"
-msgstr ""
+msgstr "Enhver milepæl"
msgid "Any namespace"
-msgstr ""
+msgstr "Ethvert navneområde"
msgid "Any user"
-msgstr ""
+msgstr "Alle brukere"
msgid "App ID"
-msgstr ""
+msgstr "App-ID"
msgid "Appearance"
-msgstr ""
+msgstr "Utseende"
msgid "Appearance was successfully created."
-msgstr ""
+msgstr "Utseendet ble vellykket opprettet."
msgid "Appearance was successfully updated."
-msgstr ""
+msgstr "Utseendet ble vellykket oppdatert."
msgid "Append the comment with %{shrug}"
-msgstr ""
+msgstr "Tilføy til kommentaren med %{shrug}"
msgid "Append the comment with %{tableflip}"
-msgstr ""
+msgstr "Tilføy kommentaren med %{tableflip}"
msgid "Application"
-msgstr ""
+msgstr "Program"
msgid "Application ID"
+msgstr "Applikasjon-ID"
+
+msgid "Application limits saved successfully"
msgstr ""
msgid "Application settings saved successfully"
-msgstr ""
+msgstr "Programinnstillingene ble vellykket lagret"
msgid "Application settings update failed"
-msgstr ""
+msgstr "Oppdatering av programinnstillinger mislyktes"
msgid "Application uninstalled but failed to destroy: %{error_message}"
msgstr ""
msgid "Application was successfully destroyed."
-msgstr ""
+msgstr "Appen ble vellykket søndersmadret."
msgid "Application was successfully updated."
-msgstr ""
+msgstr "Prosjektet ble vellykket oppdatert."
msgid "Application: %{name}"
-msgstr ""
+msgstr "Applikasjon: %{name}"
msgid "Applications"
-msgstr ""
+msgstr "Programmer"
msgid "Applied"
-msgstr ""
+msgstr "Benyttet"
msgid "Apply"
-msgstr ""
+msgstr "Bruk"
msgid "Apply a label"
-msgstr ""
+msgstr "Benytt en etikett"
msgid "Apply a template"
-msgstr ""
+msgstr "Benytt en mal"
msgid "Apply changes"
-msgstr ""
+msgstr "Benytt endringer"
msgid "Apply suggestion"
-msgstr ""
+msgstr "Benytt forslag"
msgid "Apply suggestions"
-msgstr ""
+msgstr "Benytt forslag"
msgid "Apply template"
-msgstr ""
+msgstr "Benytt mal"
msgid "Apply this approval rule to any branch or a specific protected branch."
msgstr ""
msgid "Applying"
-msgstr ""
+msgstr "Benytter"
msgid "Applying a template will replace the existing issue description. Any changes you have made will be lost."
-msgstr ""
+msgstr "Å bruke en mal vil erstatte den nåværende saksbeskrivelsen. Eventuelle endringer du har gjort vil gå tapt."
msgid "Applying command"
-msgstr ""
+msgstr "Benytter kommando"
msgid "Applying command to %{commandDescription}"
-msgstr ""
+msgstr "Benytter kommando på %{commandDescription}"
msgid "Applying multiple commands"
-msgstr ""
+msgstr "Benytter flere kommandoer"
msgid "Applying suggestion..."
-msgstr ""
+msgstr "Benytter forslag …"
msgid "Applying suggestions..."
-msgstr ""
+msgstr "Benytter forslag …"
msgid "Approval Status"
-msgstr ""
+msgstr "Godkjenningsstatus"
msgid "Approval rules"
-msgstr ""
+msgstr "Godkjenningsregler"
msgid "Approval rules reset to project defaults"
-msgstr ""
+msgstr "Godkjenningsreglene ble tilbakestilt til prosjektets standardinnstillinger"
msgid "ApprovalRuleRemove|%d member"
msgid_plural "ApprovalRuleRemove|%d members"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%d medlem"
+msgstr[1] "%d medlemmer"
msgid "ApprovalRuleRemove|Approvals from this member are not revoked."
msgid_plural "ApprovalRuleRemove|Approvals from these members are not revoked."
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "Godkjenninger fra dette medlemmet blir ikke tilbakekalt."
+msgstr[1] "Godkjenninger fra disse medlemmene blir ikke tilbakekalt."
msgid "ApprovalRuleRemove|You are about to remove the %{name} approver group which has %{nMembers}."
-msgstr ""
+msgstr "Du er i ferd med å fjerne %{name}-godkjenningsgruppen som har %{nMembers}."
msgid "ApprovalRuleSummary|%d member"
msgid_plural "ApprovalRuleSummary|%d members"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%d medlem"
+msgstr[1] "%d medlemmer"
msgid "ApprovalRuleSummary|%{count} approval required from %{membersCount}"
msgid_plural "ApprovalRuleSummary|%{count} approvals required from %{membersCount}"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%{count} godkjenning kreves fra %{membersCount}"
+msgstr[1] "%{count} godkjenninger kreves fra %{membersCount}"
msgid "ApprovalRule|Approvers"
-msgstr ""
+msgstr "Godkjennere"
msgid "ApprovalRule|Name"
-msgstr ""
+msgstr "Navn"
msgid "ApprovalRule|No. approvals required"
-msgstr ""
+msgstr "Antall påkrevde godkjenninger"
msgid "ApprovalRule|Rule name"
-msgstr ""
+msgstr "Regelnavn"
msgid "ApprovalRule|Target branch"
-msgstr ""
+msgstr "MÃ¥lgren"
msgid "ApprovalRule|e.g. QA, Security, etc."
-msgstr ""
+msgstr "f.eks. produkttesting, sikkerhet, osv."
msgid "ApprovalStatusTooltip|Adheres to separation of duties"
msgstr ""
@@ -3146,214 +3262,228 @@ msgid "ApprovalStatusTooltip|Fails to adhere to separation of duties"
msgstr ""
msgid "Approvals|Section: %section"
-msgstr ""
+msgstr "Seksjon: %seksjon"
msgid "Approve"
-msgstr ""
+msgstr "Godkjenn"
msgid "Approve a merge request"
-msgstr ""
+msgstr "Godkjenn en fletteforespørsel"
msgid "Approve the current merge request."
-msgstr ""
+msgstr "Godkjenn den nåværende fletteforespørselen."
msgid "Approved"
-msgstr ""
+msgstr "Godkjent"
msgid "Approved MRs"
-msgstr ""
+msgstr "Godkjente FF-er"
msgid "Approved the current merge request."
-msgstr ""
+msgstr "Godkjente den nåværende fletteforespørselen."
msgid "Approved-By"
-msgstr ""
+msgstr "Godkjent av"
msgid "Approver"
-msgstr ""
+msgstr "Godkjenner"
msgid "Approvers"
-msgstr ""
+msgstr "Godkjennere"
msgid "Apr"
-msgstr ""
+msgstr "Apr"
msgid "April"
-msgstr ""
+msgstr "April"
msgid "Architecture not found for OS"
-msgstr ""
+msgstr "Arkitekturen ble ikke funnet for OS"
msgid "Archive"
-msgstr ""
+msgstr "Arkiv"
msgid "Archive jobs"
-msgstr ""
+msgstr "Arkiver jobber"
msgid "Archive project"
-msgstr ""
+msgstr "Arkiver prosjekt"
msgid "Archived"
-msgstr ""
+msgstr "Arkivert"
msgid "Archived in this version"
-msgstr ""
+msgstr "Arkivert i denne versjonen"
msgid "Archived project! Repository and other project resources are read only"
-msgstr ""
+msgstr "Arkivert prosjekt! kodelageret og andre prosjektressurser er skrivebeskyttet"
msgid "Archived project! Repository and other project resources are read-only"
-msgstr ""
+msgstr "Arkivert prosjekt! kodelageret og andre prosjektressurser er skrivebeskyttet"
msgid "Archived projects"
-msgstr ""
+msgstr "Arkiverte prosjekter"
msgid "Archiving the project will make it entirely read only. It is hidden from the dashboard and doesn't show up in searches. %{strong_start}The repository cannot be committed to, and no issues, comments, or other entities can be created.%{strong_end}"
-msgstr ""
+msgstr "Arkivering av prosjektet vil gjøre det helt skrivebeskyttet. Den er skjult fra kontrollpanelet og vises ikke i søk. %{strong_start}Datalageret kan ikke motta commiter, og ingen problemer, kommentarer eller andre enheter kan opprettes.%{strong_end}"
msgid "Are you ABSOLUTELY SURE you wish to delete this project?"
-msgstr ""
+msgstr "Er du HELT SIKKER på at du vil slette dette prosjektet?"
msgid "Are you sure that you want to archive this project?"
-msgstr ""
+msgstr "Er du sikker på at du vil arkivere dette prosjektet?"
msgid "Are you sure that you want to unarchive this project?"
-msgstr ""
+msgstr "Er du sikker på at du vil oppheve arkiveringen av dette prosjektet?"
msgid "Are you sure you want to cancel editing this comment?"
-msgstr ""
+msgstr "Er du sikker på at du vil avbryte redigeringen av denne kommentaren?"
msgid "Are you sure you want to close this blocked issue?"
msgstr ""
-msgid "Are you sure you want to delete %{name}?"
+msgid "Are you sure you want to delete \"%{name}\" Value Stream?"
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 ""
+msgstr "Er du sikker på at du vil slette disse artefaktene?"
msgid "Are you sure you want to delete this %{typeOfComment}?"
+msgstr "Er du sikker på at du vil slette denne %{typeOfComment}?"
+
+msgid "Are you sure you want to delete this SSH key?"
msgstr ""
msgid "Are you sure you want to delete this board?"
-msgstr ""
+msgstr "Er du sikker på at du vil slette dette panelet?"
msgid "Are you sure you want to delete this device? This action cannot be undone."
-msgstr ""
+msgstr "Er du sikker på at du vil slette denne enheten? Denne handlingen kan ikke angres på."
msgid "Are you sure you want to delete this list?"
-msgstr ""
+msgstr "Er du sikker på at du vil slette denne listen?"
msgid "Are you sure you want to delete this pipeline schedule?"
-msgstr ""
+msgstr "Er du sikker på at du vil slette denne rørledningsplanleggingen?"
msgid "Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone."
-msgstr ""
+msgstr "Er du sikker på at du vil slette denne rørledningen? Dette vil tidsutløpe alle rørledningsmellombuffere og slette relaterte objekter, slik som byggversjoner, loggføringer, artefakter og triggere. Denne handlingen kan ikke angres på."
msgid "Are you sure you want to deploy this environment?"
-msgstr ""
+msgstr "Er du sikker på at du vil distribuere dette miljøet?"
msgid "Are you sure you want to discard this comment?"
-msgstr ""
+msgstr "Er du sikker på at du vil forkaste denne kommentaren?"
msgid "Are you sure you want to erase this build?"
-msgstr ""
+msgstr "Er du sikker på at du vil slette denne byggversjonen?"
+
+msgid "Are you sure you want to import %d repository?"
+msgid_plural "Are you sure you want to import %d repositories?"
+msgstr[0] ""
+msgstr[1] ""
msgid "Are you sure you want to lose unsaved changes?"
-msgstr ""
+msgstr "Er du sikker på at du vil miste ulagrede endringer?"
msgid "Are you sure you want to lose your issue information?"
-msgstr ""
+msgstr "Er du sikker på at du vil miste saksinformasjonen din?"
msgid "Are you sure you want to merge immediately?"
-msgstr ""
-
-msgid "Are you sure you want to permanently delete this license?"
-msgstr ""
+msgstr "Er du sikker på at du vil innflette umiddelbart?"
msgid "Are you sure you want to re-deploy this environment?"
-msgstr ""
+msgstr "Er du sikker på at du vil distribuere dette miljøet på nytt?"
msgid "Are you sure you want to regenerate the public key? You will have to update the public key on the remote server before mirroring will work again."
+msgstr "Er du sikker på at du vil regenerere den offentlige nøkkelen? Du vil måtte oppdatere den offentlige nøkkelen på fjerntjeneren før speiling vil fungere igjen."
+
+msgid "Are you sure you want to reindex?"
msgstr ""
msgid "Are you sure you want to remove %{group_name}?"
-msgstr ""
+msgstr "Er du sikker på at du vil fjerne %{group_name}?"
msgid "Are you sure you want to remove the attachment?"
-msgstr ""
+msgstr "Er du sikker på at du vil fjerne vedlegget?"
msgid "Are you sure you want to remove the license?"
-msgstr ""
+msgstr "Er du sikker på at du vil fjerne lisensen?"
msgid "Are you sure you want to remove this identity?"
-msgstr ""
+msgstr "Er du sikker på at du vil fjerne denne identiteten?"
msgid "Are you sure you want to reset registration token?"
-msgstr ""
+msgstr "Er du sikker på at du vil nullstille registreringssjetongen?"
msgid "Are you sure you want to reset the SCIM token? SCIM provisioning will stop working until the new token is updated."
msgstr ""
msgid "Are you sure you want to reset the health check token?"
-msgstr ""
+msgstr "Er du sikker du vil tilbakestille helsesjekksjetongen?"
msgid "Are you sure you want to revoke this %{type}? This action cannot be undone."
-msgstr ""
+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 nickname?"
+msgstr "Er du sikker på at du vil trekke tilbake dette kallenavnet?"
+
+msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to stop this environment?"
-msgstr ""
+msgstr "Er du sikker på at du vil stoppe dette miljøet?"
msgid "Are you sure you want to unlock %{path_lock_path}?"
-msgstr ""
+msgstr "Er du sikker på at du vil låse opp %{path_lock_path}?"
msgid "Are you sure you want to unsubscribe from the %{type}: %{link_to_noteable_text}?"
-msgstr ""
+msgstr "Er du sikker på at du vil avslutte abonnementet på %{type}: %{link_to_noteable_text}?"
msgid "Are you sure?"
-msgstr ""
+msgstr "Er du sikker?"
msgid "Are you sure? All commits that were signed with this GPG key will be unverified."
-msgstr ""
+msgstr "Er du sikker? Alle commiter som ble signert med denne GPG-nøkkelen vil få verifiseringene sine opphevet."
msgid "Are you sure? Removing this GPG key does not affect already signed commits."
-msgstr ""
+msgstr "Er du sikker? Å fjerne denne GPG-nøkkelen påvirker ikke commits som allerede har blitt signert."
msgid "Are you sure? The device will be signed out of GitLab and all remember me tokens revoked."
msgstr ""
+msgid "Are you sure? This will invalidate your registered applications and U2F / WebAuthn devices."
+msgstr ""
+
msgid "Are you sure? This will invalidate your registered applications and U2F devices."
msgstr ""
msgid "Arrange charts"
-msgstr ""
+msgstr "Still opp diagrammer"
msgid "Artifact"
-msgstr ""
+msgstr "Artifakt"
msgid "Artifact could not be deleted."
-msgstr ""
+msgstr "Artifakten kunne ikke bli slettet."
msgid "Artifact was successfully deleted."
-msgstr ""
+msgstr "Artifakten ble vellykket slettet."
msgid "Artifacts"
-msgstr ""
-
-msgid "As U2F devices are only supported by a few browsers, we require that you set up a two-factor authentication app before a U2F device. That way you'll always be able to log in - even when you're using an unsupported browser."
-msgstr ""
+msgstr "Artefakter"
msgid "As we continue to build more features for SAST, we'd love your feedback on the SAST configuration feature in %{linkStart}this issue%{linkEnd}."
msgstr ""
msgid "AsanaService|%{user} pushed to branch %{branch} of %{project_name} ( %{commit_url} ):"
-msgstr ""
+msgstr "%{user} pushet til grenen %{branch} av %{project_name} ( %{commit_url} ):"
msgid "AsanaService|Asana - Teamwork without email"
-msgstr ""
+msgstr "Asana - Lagarbeid uten E-post"
msgid "AsanaService|Comma-separated list of branches which will be automatically inspected. Leave blank to include all branches."
msgstr ""
@@ -3362,7 +3492,7 @@ msgid "AsanaService|User Personal Access Token. User must have access to task, a
msgstr ""
msgid "Ascending"
-msgstr ""
+msgstr "Stigende"
msgid "Ask your group maintainer to set up a group Runner."
msgstr ""
@@ -3371,72 +3501,72 @@ msgid "Assertion consumer service URL"
msgstr ""
msgid "Assets"
-msgstr ""
+msgstr "Ressurser"
msgid "Assets:"
-msgstr ""
+msgstr "Eiendeler"
msgid "Assign"
-msgstr ""
+msgstr "Knytt"
msgid "Assign Iteration"
msgstr ""
msgid "Assign To"
-msgstr ""
+msgstr "Tilordne til"
msgid "Assign custom color like #FF0000"
-msgstr ""
+msgstr "Tilordne en tilpasset farge som #FF0000"
msgid "Assign epic"
-msgstr ""
+msgstr "Tilordne epos"
msgid "Assign labels"
-msgstr ""
+msgstr "Tilordne stempler"
msgid "Assign milestone"
-msgstr ""
+msgstr "Tilordne milepæl"
msgid "Assign some issues to this milestone."
-msgstr ""
+msgstr "Tildel noen saker til denne milepælen."
msgid "Assign to"
-msgstr ""
+msgstr "Tilegn til"
msgid "Assign to commenting user"
-msgstr ""
+msgstr "Tilordne til den kommenterende brukeren"
msgid "Assign yourself to these issues"
-msgstr ""
+msgstr "Tildel deg selv til disse sakene"
msgid "Assign yourself to this issue"
-msgstr ""
+msgstr "Tildel deg selv til denne saken"
msgid "Assigned %{assignee_users_sentence}."
msgstr ""
msgid "Assigned Issues"
-msgstr ""
+msgstr "Tilegnede rapporter"
msgid "Assigned Merge Requests"
-msgstr ""
+msgstr "Tilordnede fletteforespørsel"
msgid "Assigned to %{assigneeName}"
-msgstr ""
+msgstr "Tilordnet til %{assigneeName}"
msgid "Assigned to %{assignee_name}"
-msgstr ""
+msgstr "Tilordnet til %{assignee_name}"
msgid "Assigned to me"
-msgstr ""
+msgstr "Tilordnet meg"
msgid "Assignee"
msgid_plural "%d Assignees"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "Tilordnet"
+msgstr[1] "%d tilordnede"
msgid "Assignee has no permissions"
-msgstr ""
+msgstr "Den tilordnede har ingen tillatelser"
msgid "Assignee lists not available with your current license"
msgstr ""
@@ -3445,16 +3575,16 @@ msgid "Assignee lists show all issues assigned to the selected user."
msgstr ""
msgid "Assignee(s)"
-msgstr ""
+msgstr "Tilordnet(e)"
msgid "Assignees"
-msgstr ""
+msgstr "Tilordnede"
msgid "Assigns %{assignee_users_sentence}."
msgstr ""
msgid "At least one approval from a code owner is required to change files matching the respective CODEOWNER rules."
-msgstr ""
+msgstr "Minst én godkjenning fra en kodeeier kreves for å endre filer som samsvarer med de respektive CODEOWNER-reglene."
msgid "At least one logging option is required to be enabled"
msgstr ""
@@ -3469,27 +3599,27 @@ msgid "At least one of your Personal Access Tokens will expire soon, but expirat
msgstr ""
msgid "At risk"
-msgstr ""
+msgstr "I faresonen"
msgid "Attach a file"
-msgstr ""
+msgstr "Legg ved en fil"
msgid "Attach a file by drag &amp; drop or %{upload_link}"
-msgstr ""
+msgstr "Legg til en fil ved å dra-og-slippe eller %{upload_link}"
msgid "Attaching a file"
msgid_plural "Attaching %d files"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "Legger ved en fil"
+msgstr[1] "Legger ved %d filer"
msgid "Attaching the file failed."
-msgstr ""
+msgstr "Vedlegging av filen mislyktes."
msgid "Attachment"
-msgstr ""
+msgstr "Vedlegg"
msgid "Attachments"
-msgstr ""
+msgstr "Vedlegg"
msgid "Audit Events"
msgstr ""
@@ -3498,139 +3628,145 @@ msgid "Audit Events is a way to keep track of important events that happened in
msgstr ""
msgid "Audit Log"
-msgstr ""
+msgstr "Revisjonslogg"
msgid "AuditLogs|(removed)"
-msgstr ""
+msgstr "(fjernet)"
msgid "AuditLogs|Action"
-msgstr ""
+msgstr "Handling"
msgid "AuditLogs|Author"
-msgstr ""
+msgstr "Skaper"
msgid "AuditLogs|Date"
-msgstr ""
+msgstr "Dato"
msgid "AuditLogs|Failed to find %{type}. Please search for another %{type}."
-msgstr ""
+msgstr "Kunne ikke finne %{type}. Vennligst søk etter en annen %{type}."
msgid "AuditLogs|Failed to find %{type}. Please try again."
-msgstr ""
+msgstr "Kunne ikke finne %{type}. Vennligst prøv igjen."
msgid "AuditLogs|Group Events"
-msgstr ""
+msgstr "Gruppehendelser"
msgid "AuditLogs|IP Address"
-msgstr ""
+msgstr "IP-adresse"
msgid "AuditLogs|Member Events"
-msgstr ""
+msgstr "Medlemshendelser"
msgid "AuditLogs|No matching %{type} found."
-msgstr ""
+msgstr "Ingen samsvarende %{type} funnet."
msgid "AuditLogs|Object"
-msgstr ""
+msgstr "Objekt"
msgid "AuditLogs|Project Events"
-msgstr ""
+msgstr "Prosjekthendelser"
msgid "AuditLogs|Target"
msgstr ""
-msgid "AuditLogs|User Events"
+msgid "AuditLogs|This month"
msgstr ""
+msgid "AuditLogs|User Events"
+msgstr "Brukerhendelser"
+
msgid "Aug"
-msgstr ""
+msgstr "Aug"
msgid "August"
-msgstr ""
+msgstr "August"
msgid "Authenticate"
-msgstr ""
+msgstr "Autentisere"
msgid "Authenticate with GitHub"
-msgstr ""
+msgstr "Autentiser med GitHub"
msgid "Authenticating"
-msgstr ""
+msgstr "Autentiserer"
msgid "Authentication Failure"
-msgstr ""
+msgstr "Autentiseringsfeil"
msgid "Authentication Log"
-msgstr ""
+msgstr "Autentiseringslogg"
msgid "Authentication failed: %{error_message}"
-msgstr ""
+msgstr "Autentisering mislyktes: %{error_message}"
msgid "Authentication log"
-msgstr ""
+msgstr "Autentiseringslogg"
msgid "Authentication method"
-msgstr ""
+msgstr "Autentiseringsmetode"
msgid "Authentication method updated"
-msgstr ""
+msgstr "Autentiseringsmetode oppdatert"
msgid "Authentication via U2F device failed."
+msgstr "Autentisering via U2F-enhet mislyktes."
+
+msgid "Authentication via WebAuthn device failed."
msgstr ""
msgid "Author"
-msgstr ""
+msgstr "Forfatter"
msgid "Author: %{author_name}"
-msgstr ""
+msgstr "Skaper: %{author_name}"
msgid "Authored %{timeago}"
-msgstr ""
+msgstr "Skapt %{timeago}"
msgid "Authored %{timeago} by %{author}"
-msgstr ""
+msgstr "Skapt %{timeago} av %{author}"
msgid "Authorization code:"
-msgstr ""
+msgstr "Autorisasjonskode:"
msgid "Authorization key"
-msgstr ""
+msgstr "Autorisasjonsnøkkel"
msgid "Authorization required"
-msgstr ""
+msgstr "Autorisasjon påkrevd"
msgid "Authorization was granted by entering your username and password in the application."
msgstr ""
msgid "Authorize"
-msgstr ""
+msgstr "Autoriser"
msgid "Authorize %{link_to_client} to use your account?"
msgstr ""
msgid "Authorize %{user} to use your account?"
-msgstr ""
+msgstr "Vil du autorisere at %{user} kan bruke kontoen din?"
msgid "Authorize external services to send alerts to GitLab"
-msgstr ""
+msgstr "Autoriser eksterne tjenester til å sende alarmer til GitLab"
msgid "Authorized %{new_chat_name}"
-msgstr ""
+msgstr "Autoriserte %{new_chat_name}"
msgid "Authorized At"
-msgstr ""
+msgstr "Autorisert den"
msgid "Authorized applications (%{size})"
-msgstr ""
+msgstr "Autoriserte applikasjoner (%{size})"
msgid "Authors: %{authors}"
-msgstr ""
+msgstr "Skapere: %{authors}"
msgid "Auto DevOps"
-msgstr ""
+msgstr "Auto DevOps"
msgid "Auto DevOps enabled"
-msgstr ""
+msgstr "Auto DevOps er aktivert"
msgid "Auto DevOps, runners and job artifacts"
msgstr ""
@@ -3645,64 +3781,64 @@ msgid "Auto-close referenced issues on default branch"
msgstr ""
msgid "AutoDevOps|Auto DevOps"
-msgstr ""
+msgstr "Auto DevOps"
msgid "AutoDevOps|Auto DevOps can automatically build, test, and deploy applications based on predefined continuous integration and delivery configuration. %{auto_devops_start}Learn more about Auto DevOps%{auto_devops_end} or use our %{quickstart_start}quick start guide%{quickstart_end} to get started right away."
-msgstr ""
+msgstr "Auto DevOps kan automatisk bygge, teste og distribuere applikasjoner basert på forhåndsdefinert kontinuerlig integrasjon og leveringsoppsett. %{auto_devops_start}Lær mer om Auto DevOps%{auto_devops_end} eller bruk vår %{quickstart_start}hurtigstartguide%{quickstart_end} for å komme i gang umiddelbart."
msgid "AutoDevOps|Auto DevOps documentation"
-msgstr ""
+msgstr "Auto DevOps dokumentasjon"
msgid "AutoDevOps|Dismiss Auto DevOps box"
-msgstr ""
+msgstr "Avvis Auto DevOps-boksen"
msgid "AutoDevOps|Enable in settings"
-msgstr ""
+msgstr "Aktiver i innstillinger"
msgid "AutoDevOps|It will automatically build, test, and deploy your application based on a predefined CI/CD configuration."
-msgstr ""
+msgstr "Den vil automatisk bygge, teste og distribuere applikasjonen din basert på en forhåndsdefinert CI/CD-konfigurasjon."
msgid "AutoDevOps|Learn more in the %{link_to_documentation}"
-msgstr ""
+msgstr "Lær mer i %{link_to_documentation}"
msgid "AutoDevOps|The Auto DevOps pipeline has been enabled and will be used if no alternative CI configuration file is found. %{more_information_link}"
-msgstr ""
+msgstr "Auto DevOps-rørledningen har blitt aktivert og vil bli brukt hvis ingen alternative CI-konfigurasjonsfiler blir funnet. %{more_information_link}"
msgid "Autocomplete"
-msgstr ""
+msgstr "Automatisk fullføring"
msgid "Autocomplete description"
-msgstr ""
+msgstr "Autofullfør beskrivelsen"
msgid "Autocomplete hint"
-msgstr ""
+msgstr "Autofullfør hintet"
msgid "Autocomplete usage hint"
-msgstr ""
+msgstr "Autofullfør brukshintet"
msgid "Automatic certificate management using %{lets_encrypt_link_start}Let's Encrypt%{lets_encrypt_link_end}"
-msgstr ""
+msgstr "Automatisk sertifikatshåndtering med %{lets_encrypt_link_start}Let's Encrypt%{lets_encrypt_link_end}"
msgid "Automatic certificate management using Let's Encrypt"
-msgstr ""
+msgstr "Automatisk sertifikatshåndtering med Let's Encrypt"
msgid "Automatically close incident issues when the associated Prometheus alert resolves."
msgstr ""
msgid "Automatically create merge requests for vulnerabilities that have fixes available."
-msgstr ""
+msgstr "Opprett automatisk fletteforespørsler for sårbarheter som har tilgjengelige fikser."
msgid "Automatically resolved"
-msgstr ""
+msgstr "Automatisk oppklart"
msgid "Automatically update this project's branches and tags from the upstream repository every hour."
-msgstr ""
+msgstr "Oppdater automatisk dette prosjektets grener og etiketter fra oppstrømskodelageret hver time."
msgid "Autosave|Note"
msgstr ""
msgid "Available"
-msgstr ""
+msgstr "Tilgjengelig"
msgid "Available Runners: %{runners}"
msgstr ""
@@ -3720,121 +3856,121 @@ msgid "Available specific runners"
msgstr ""
msgid "Avatar for %{assigneeName}"
-msgstr ""
+msgstr "Avatar for %{assigneeName}"
msgid "Avatar for %{name}"
-msgstr ""
+msgstr "Avatar for %{name}"
msgid "Avatar will be removed. Are you sure?"
-msgstr ""
+msgstr "Avataren vil bli fjernet. Er du sikker?"
msgid "Average per day: %{average}"
-msgstr ""
+msgstr "Gjennomsnitt per dag: %{average}"
msgid "Back to page %{number}"
-msgstr ""
+msgstr "Tilbake til side %{number}"
msgid "Background Color"
-msgstr ""
+msgstr "Bakgrunnsfarge"
msgid "Background Jobs"
-msgstr ""
+msgstr "Bakgrunnsjobber"
msgid "Background color"
-msgstr ""
+msgstr "Bakgrunnsfarge"
msgid "Badges"
-msgstr ""
+msgstr "Merker"
msgid "Badges|A new badge was added."
-msgstr ""
+msgstr "Et nytt merke ble lagt til."
msgid "Badges|Add badge"
-msgstr ""
+msgstr "Legg til merke"
msgid "Badges|Adding the badge failed, please check the entered URLs and try again."
-msgstr ""
+msgstr "Legge til merket mislyktes, sjekk de angitte nettadressene og prøv igjen."
msgid "Badges|Badge image URL"
-msgstr ""
+msgstr "Merkebilde nettadresse"
msgid "Badges|Badge image preview"
-msgstr ""
+msgstr "Forhåndsvisning av merkebilde"
msgid "Badges|Delete badge"
-msgstr ""
+msgstr "Slett merket"
msgid "Badges|Delete badge?"
-msgstr ""
+msgstr "Slette badge?"
msgid "Badges|Deleting the badge failed, please try again."
-msgstr ""
+msgstr "Sletting av merket mislyktes, vennligst prøv igjen."
msgid "Badges|Group Badge"
-msgstr ""
+msgstr "Grupper merker"
msgid "Badges|Link"
-msgstr ""
+msgstr "Lenke"
msgid "Badges|Name"
-msgstr ""
+msgstr "Navn"
msgid "Badges|No badge image"
-msgstr ""
+msgstr "Ingen merkebilde"
msgid "Badges|No image to preview"
-msgstr ""
+msgstr "Ingen bilder å forhåndsvise"
msgid "Badges|Please fill in a valid URL"
-msgstr ""
+msgstr "Vennligst fyll inn en gyldig nettadresse"
msgid "Badges|Project Badge"
-msgstr ""
+msgstr "Prosjektmerke"
msgid "Badges|Reload badge image"
-msgstr ""
+msgstr "Last inn merkebilde"
msgid "Badges|Save changes"
-msgstr ""
+msgstr "Lagre endringer"
msgid "Badges|Saving the badge failed, please check the entered URLs and try again."
-msgstr ""
+msgstr "Lagring av merket mislyktes, sjekk de angitte nettadressene og prøv igjen."
msgid "Badges|The %{docsLinkStart}variables%{docsLinkEnd} GitLab supports: %{placeholders}"
-msgstr ""
+msgstr "%{docsLinkStart}variablene%{docsLinkEnd} GitLab støtter: %{placeholders}"
msgid "Badges|The badge was deleted."
-msgstr ""
+msgstr "Merket ble slettet."
msgid "Badges|The badge was saved."
-msgstr ""
+msgstr "Merket ble lagret."
msgid "Badges|This group has no badges"
-msgstr ""
+msgstr "Denne gruppen har ingen merker"
msgid "Badges|This project has no badges"
-msgstr ""
+msgstr "Dette prosjektet har ingen merker"
msgid "Badges|You are going to delete this badge. Deleted badges %{strongStart}cannot%{strongEnd} be restored."
msgstr ""
msgid "Badges|Your badges"
-msgstr ""
+msgstr "Dine merker"
msgid "Badges|e.g. %{exampleUrl}"
-msgstr ""
+msgstr "f.eks. %{exampleUrl}"
msgid "Balsamiq file could not be loaded."
-msgstr ""
+msgstr "Balsamiq-filen kunne ikke lastes inn."
msgid "BambooService|A continuous integration and build server"
-msgstr ""
+msgstr "En kontinuerlig integrerings- og byggversjonstjener"
msgid "BambooService|A user with API access, if applicable"
-msgstr ""
+msgstr "En bruker med API-tilgang, hvis aktuelt"
msgid "BambooService|Atlassian Bamboo CI"
-msgstr ""
+msgstr "Atlassian Bamboo CI"
msgid "BambooService|Bamboo build plan key like KEY"
msgstr ""
@@ -3845,15 +3981,6 @@ msgstr ""
msgid "BambooService|You must set up automatic revision labeling and a repository trigger in Bamboo."
msgstr ""
-msgid "BatchComments|Delete all pending comments"
-msgstr ""
-
-msgid "BatchComments|Discard review?"
-msgstr ""
-
-msgid "BatchComments|You're about to discard your review which will delete all of your pending comments. The deleted comments %{strong_start}cannot%{strong_end} be restored."
-msgstr ""
-
msgid "Be careful. Changing the project's namespace can have unintended side effects."
msgstr ""
@@ -3861,7 +3988,7 @@ msgid "Be careful. Renaming a project's repository can have unintended side effe
msgstr ""
msgid "Begin with the selected commit"
-msgstr ""
+msgstr "Begynn med den valgte commiten"
msgid "Below are examples of regex for existing tools:"
msgstr ""
@@ -3870,292 +3997,304 @@ msgid "Below are the fingerprints for the current instance SSH host keys."
msgstr ""
msgid "Below you will find all the groups that are public."
-msgstr ""
+msgstr "Nedenfor vil du finne alle de gruppene som er offentlige."
msgid "Bi-weekly code coverage"
msgstr ""
-msgid "Billing"
+msgid "Billable Users:"
msgstr ""
+msgid "Billing"
+msgstr "Fakturering"
+
msgid "BillingPlans|%{group_name} is currently using the %{plan_name} plan."
-msgstr ""
+msgstr "%{group_name} bruker for tiden %{plan_name}-planen."
msgid "BillingPlans|@%{user_name} you are currently using the %{plan_name} plan."
-msgstr ""
+msgstr "%{user_name}, du bruker for tiden %{plan_name}-planen."
-msgid "BillingPlans|Congratulations, your new trial is activated"
+msgid "BillingPlans|Congratulations, your free trial is activated."
msgstr ""
msgid "BillingPlans|If you would like to downgrade your plan please contact %{support_link_start}Customer Support%{support_link_end}."
-msgstr ""
+msgstr "Hvis du ønsker å nedgradere planen din, kan du kontakte %{support_link_start}Kundestøtte%{support_link_end}."
msgid "BillingPlans|Learn more about each plan by reading our %{faq_link}, or start a free 30-day trial of GitLab.com Gold."
-msgstr ""
+msgstr "Lær mer om hver plan ved å lese vår %{faq_link}, eller start en gratis 30-dagers prøveversjon av GitLab.com Gold."
msgid "BillingPlans|Learn more about each plan by visiting our %{pricing_page_link}."
msgstr ""
msgid "BillingPlans|Manage plan"
-msgstr ""
+msgstr "Behandle planen"
msgid "BillingPlans|Pricing page"
-msgstr ""
+msgstr "Pris-side"
msgid "BillingPlans|See all %{plan_name} features"
-msgstr ""
+msgstr "Se alle %{plan_name}-funksjonene"
msgid "BillingPlans|This group uses the plan associated with its parent group."
msgstr ""
msgid "BillingPlans|To manage the plan for this group, visit the billing section of %{parent_billing_page_link}."
-msgstr ""
+msgstr "For å behandle planen til denne gruppen, besøk faktureringsseksjonen til %{parent_billing_page_link}."
msgid "BillingPlans|Your GitLab.com %{plan} trial will %{strong_open}expire after %{expiration_date}%{strong_close}. You can retain access to the %{plan} features by upgrading below."
-msgstr ""
+msgstr "Din GitLab.com-%{plan}prøveperiode vil %{strong_open}utløpe etter %{expiration_date}%{strong_close}. Du kan beholde tilgangen til %{plan}-funksjonene ved å oppgradere nedenfor."
msgid "BillingPlans|Your GitLab.com trial expired on %{expiration_date}. You can restore access to the features at any time by upgrading below."
-msgstr ""
+msgstr "Din GitLab.com-prøveperiode utløp den %{expiration_date}. Du kan når som helst gjenopprette tilgangen til funksjonene ved å oppgradere nedenfor."
msgid "BillingPlans|billed annually at %{price_per_year}"
-msgstr ""
+msgstr "faktureres årlig for %{price_per_year}"
msgid "BillingPlans|frequently asked questions"
-msgstr ""
+msgstr "ofte stilte spørsmål"
msgid "BillingPlans|monthly"
-msgstr ""
+msgstr "månedlig"
msgid "BillingPlans|per user"
-msgstr ""
+msgstr "per bruker"
msgid "BillingPlan|Contact sales"
-msgstr ""
+msgstr "Kontakt salgsavdelingen"
msgid "BillingPlan|Upgrade"
-msgstr ""
+msgstr "Oppgrader"
msgid "Bitbucket Server Import"
-msgstr ""
+msgstr "Bitbucket-tjenerimportering"
msgid "Bitbucket Server import"
-msgstr ""
+msgstr "Bitbucket-tjenerimportering"
msgid "Bitbucket import"
-msgstr ""
+msgstr "Bitbucket-import"
msgid "Blame"
+msgstr "Ã…rsaksliste"
+
+msgid "Block user"
msgstr ""
msgid "Blocked"
-msgstr ""
+msgstr "Blokkert"
msgid "Blocked issue"
-msgstr ""
+msgstr "Blokkert sak"
msgid "Blocking issues"
msgstr ""
msgid "Blocks"
-msgstr ""
+msgstr "Blokk"
msgid "Blog"
+msgstr "Blogg"
+
+msgid "Board scope"
msgstr ""
-msgid "Board name"
+msgid "Board scope affects which issues are displayed for anyone who visits this board"
msgstr ""
-msgid "Board scope"
+msgid "Boards"
+msgstr "Bord"
+
+msgid "Boards and Board Lists"
msgstr ""
-msgid "Board scope affects which issues are displayed for anyone who visits this board"
+msgid "Boards|An error occurred while creating the issue. Please try again."
msgstr ""
-msgid "BoardBlankState|Add default lists"
+msgid "Boards|An error occurred while creating the list. Please try again."
msgstr ""
-msgid "BoardBlankState|Add the following default lists to your Issue Board with one click:"
+msgid "Boards|An error occurred while fetching issues. Please reload the page."
msgstr ""
-msgid "BoardBlankState|Nevermind, I'll use my own"
+msgid "Boards|An error occurred while fetching the board issues. Please reload the page."
msgstr ""
-msgid "BoardBlankState|Starting out with the default set of lists will get you right on the way to making the most of your board."
+msgid "Boards|An error occurred while fetching the board swimlanes. Please reload the page."
msgstr ""
-msgid "Boards"
+msgid "Boards|An error occurred while moving the issue. Please try again."
msgstr ""
-msgid "Boards and Board Lists"
+msgid "Boards|An error occurred while updating the list. Please try again."
msgstr ""
msgid "Boards|Collapse"
-msgstr ""
+msgstr "Klapp sammen"
msgid "Boards|Edit board"
msgstr ""
msgid "Boards|Expand"
-msgstr ""
+msgstr "Utvid"
msgid "Boards|View scope"
-msgstr ""
+msgstr "Vis omfang"
msgid "Both project and dashboard_path are required"
msgstr ""
msgid "Branch"
-msgstr ""
+msgstr "Gren"
msgid "Branch %{branchName} was not found in this project's repository."
-msgstr ""
+msgstr "Grenen %{branchName} ble ikke funnet i dette prosjektet sitt kodelager."
msgid "Branch %{branch_name} was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
-msgstr ""
+msgstr "%{branch_name}-grenen ble opprettet. For å konfigurere automatisk distribusjon, velg en GitLab CI Yaml-mal og foreta endringene dine. %{link_to_autodeploy_doc}"
-msgid "Branch has changed"
+msgid "Branch changed"
msgstr ""
msgid "Branch is already taken"
-msgstr ""
+msgstr "Grenen er allerede i bruk"
msgid "Branch name"
-msgstr ""
+msgstr "Grennavn"
msgid "Branch not loaded - %{branchId}"
-msgstr ""
+msgstr "Grenen ble ikke lastet inn - %{branchId}"
msgid "Branch prefix"
-msgstr ""
+msgstr "Grenprefiks"
msgid "BranchSwitcherPlaceholder|Search branches"
-msgstr ""
+msgstr "Søk i grener"
msgid "BranchSwitcherTitle|Switch branch"
-msgstr ""
+msgstr "Bytt gren"
msgid "Branches"
-msgstr ""
+msgstr "Grener"
msgid "Branches|Active"
-msgstr ""
+msgstr "Aktiv"
msgid "Branches|Active branches"
-msgstr ""
+msgstr "Aktive grener"
msgid "Branches|All"
-msgstr ""
+msgstr "Alle"
msgid "Branches|Cant find HEAD commit for this branch"
-msgstr ""
+msgstr "Kan ikke finne HEAD-commit for denne grenen"
msgid "Branches|Compare"
-msgstr ""
+msgstr "Sammenlign"
msgid "Branches|Delete all branches that are merged into '%{default_branch}'"
-msgstr ""
+msgstr "Slett alle grener som er flettet sammen til '%{default_branch}'"
msgid "Branches|Delete branch"
-msgstr ""
+msgstr "Slett gren"
msgid "Branches|Delete merged branches"
-msgstr ""
+msgstr "Slett grener som er flettet sammen"
msgid "Branches|Delete protected branch"
-msgstr ""
+msgstr "Slett beskyttet gren"
msgid "Branches|Delete protected branch '%{branch_name}'?"
-msgstr ""
+msgstr "Slette den beskyttede grenen '%{branch_name}'?"
msgid "Branches|Deleting the '%{branch_name}' branch cannot be undone. Are you sure?"
-msgstr ""
+msgstr "Å slette \"%{branch_name}\"-grenen kan ikke angres på. Er du sikker?"
msgid "Branches|Deleting the merged branches cannot be undone. Are you sure?"
-msgstr ""
+msgstr "Å slette de flettede grenene kan ikke angres på. Er du sikker?"
msgid "Branches|Filter by branch name"
-msgstr ""
+msgstr "Filtrer etter grennavn"
msgid "Branches|Merged into %{default_branch}"
-msgstr ""
+msgstr "Flettet inn i %{default_branch}"
msgid "Branches|New branch"
-msgstr ""
+msgstr "Ny gren"
msgid "Branches|No branches to show"
-msgstr ""
+msgstr "Ingen grener å vise"
msgid "Branches|Once you confirm and press %{delete_protected_branch}, it cannot be undone or recovered."
-msgstr ""
+msgstr "Ved bekreftelse og inntasting av %{delete_protected_branch}, er det ikke mulig å angre."
msgid "Branches|Only a project maintainer or owner can delete a protected branch"
-msgstr ""
+msgstr "Bare en prosjektmoderator eller eier kan slette en beskyttet gren"
msgid "Branches|Overview"
-msgstr ""
+msgstr "Oversikt"
msgid "Branches|Protected branches can be managed in %{project_settings_link}."
-msgstr ""
+msgstr "Beskyttede grener kan behandles i %{project_settings_link}."
msgid "Branches|Show active branches"
-msgstr ""
+msgstr "Vis aktive grener"
msgid "Branches|Show all branches"
-msgstr ""
+msgstr "Se alle grener"
msgid "Branches|Show more active branches"
-msgstr ""
+msgstr "Se flere aktiver grener"
msgid "Branches|Show more stale branches"
-msgstr ""
+msgstr "Vis flere stillestående grener"
msgid "Branches|Show overview of the branches"
-msgstr ""
+msgstr "Vis oversikt over grenene"
msgid "Branches|Show stale branches"
-msgstr ""
+msgstr "Vis fastgrodde grener"
msgid "Branches|Sort by"
-msgstr ""
+msgstr "Sorter etter"
msgid "Branches|Stale"
-msgstr ""
+msgstr "Stillestående"
msgid "Branches|Stale branches"
-msgstr ""
+msgstr "Fastgrodde grener"
msgid "Branches|The branch could not be updated automatically because it has diverged from its upstream counterpart."
-msgstr ""
+msgstr "Grenen kunne ikke oppdateres automatisk fordi den har avviket fra sin oppstrømsmotpart."
msgid "Branches|The default branch cannot be deleted"
-msgstr ""
+msgstr "Standardgrenen kan ikke slettes"
msgid "Branches|This branch hasn’t been merged into %{default_branch}."
-msgstr ""
+msgstr "Denne grenen har ikke blitt slått sammen til %{default_branch}."
msgid "Branches|To avoid data loss, consider merging this branch before deleting it."
-msgstr ""
+msgstr "Vurder å slå sammen denne grenen for å hindre tap av data."
msgid "Branches|To confirm, type %{branch_name_confirmation}:"
-msgstr ""
+msgstr "For å bekrefte tast inn %{branch_name_confirmation}:"
msgid "Branches|To discard the local changes and overwrite the branch with the upstream version, delete it here and choose 'Update Now' above."
msgstr ""
msgid "Branches|You’re about to permanently delete the protected branch %{branch_name}."
-msgstr ""
+msgstr "Du er i ferd med å permanent slette den beskyttede grenen %{branch_name}."
msgid "Branches|diverged from upstream"
-msgstr ""
+msgstr "avveket fra oppstrøm"
msgid "Branches|merged"
-msgstr ""
+msgstr "flettet"
msgid "Branches|project settings"
-msgstr ""
+msgstr "prosjektinnstillinger"
msgid "Branches|protected"
-msgstr ""
+msgstr "beskyttet"
msgid "Broadcast Message was successfully created."
msgstr ""
@@ -4164,31 +4303,31 @@ msgid "Broadcast Message was successfully updated."
msgstr ""
msgid "Broadcast Messages"
-msgstr ""
+msgstr "Meldinger"
msgid "Browse Directory"
-msgstr ""
+msgstr "Bla gjennom katalog"
msgid "Browse File"
-msgstr ""
+msgstr "Bla gjennom fil"
msgid "Browse Files"
-msgstr ""
+msgstr "Bla gjennom filer"
msgid "Browse artifacts"
-msgstr ""
+msgstr "Bla gjennom artefakter"
msgid "Browse files"
-msgstr ""
+msgstr "Bla gjennom filer"
msgid "BuildArtifacts|An error occurred while fetching the artifacts"
msgstr ""
msgid "BuildArtifacts|Loading artifacts"
-msgstr ""
+msgstr "Laster inn artefakter"
msgid "Built-in"
-msgstr ""
+msgstr "Innebygget"
msgid "Bulk request concurrency"
msgstr ""
@@ -4209,76 +4348,76 @@ msgid "Burnup chart could not be generated due to too many events"
msgstr ""
msgid "Business"
-msgstr ""
+msgstr "Arbeid"
msgid "Business metrics (Custom)"
msgstr ""
msgid "Buy License"
-msgstr ""
+msgstr "Kjøp lisens"
msgid "Buy more Pipeline minutes"
msgstr ""
msgid "By %{user_name}"
-msgstr ""
+msgstr "Av %{user_name}"
msgid "By URL"
-msgstr ""
+msgstr "Etter URL"
msgid "By clicking Register, I agree that I have read and accepted the GitLab %{linkStart}Terms of Use and Privacy Policy%{linkEnd}"
-msgstr ""
+msgstr "Ved å klikke Registrer, godtar jeg at jeg har lest og godtatt GitLab sine %{linkStart}bruksvilkår og personvernregler%{linkEnd}"
msgid "By default GitLab sends emails in HTML and plain text formats so mail clients can choose what format to use. Disable this option if you only want to send emails in plain text format."
-msgstr ""
+msgstr "Som standard sender GitLab e-post i HTML- og rentekst-formater slik at e-postklienter kan velge hvilket format de skal bruke. Deaktiver dette alternativet hvis du bare vil sende e-post i rentekstformat."
msgid "By default, all projects and groups will use the global notifications setting."
msgstr ""
msgid "ByAuthor|by"
-msgstr ""
+msgstr "av"
msgid "CHANGELOG"
-msgstr ""
+msgstr "ENDRINGSLOGG"
msgid "CI / CD"
-msgstr ""
+msgstr "CI/CD"
msgid "CI / CD Analytics"
-msgstr ""
+msgstr "CI/CD-analystikk"
msgid "CI / CD Settings"
-msgstr ""
+msgstr "CI/CD-Innstillinger"
msgid "CI Lint"
-msgstr ""
+msgstr "CI Lint"
msgid "CI settings"
-msgstr ""
+msgstr "CI-innstillinger"
msgid "CI variables"
-msgstr ""
+msgstr "CI-variabler"
msgid "CI will run using the credentials assigned above."
msgstr ""
msgid "CI/CD"
-msgstr ""
+msgstr "CI/CD"
msgid "CI/CD configuration"
-msgstr ""
+msgstr "CI/CD-konfigurasjon"
msgid "CI/CD for external repo"
-msgstr ""
+msgstr "CI/CD for eksternt kodelager"
msgid "CI/CD settings"
-msgstr ""
+msgstr "CI/CD-innstillinger"
msgid "CICD|Add a %{kubernetes_cluster_link_start}Kubernetes cluster integration%{link_end} with a domain or create an AUTO_DEVOPS_PLATFORM_TARGET CI variable."
msgstr ""
msgid "CICD|Auto DevOps"
-msgstr ""
+msgstr "Auto DevOps"
msgid "CICD|Automatic deployment to staging, manual deployment to production"
msgstr ""
@@ -4290,16 +4429,16 @@ msgid "CICD|Continuous deployment to production using timed incremental rollout"
msgstr ""
msgid "CICD|Default to Auto DevOps pipeline"
-msgstr ""
+msgstr "Bruk Auto DevOps-rørledningen som standard"
msgid "CICD|Default to Auto DevOps pipeline for all projects"
msgstr ""
msgid "CICD|Deployment strategy"
-msgstr ""
+msgstr "Distribusjonsstrategi"
msgid "CICD|Jobs"
-msgstr ""
+msgstr "Jobber"
msgid "CICD|The Auto DevOps pipeline will run if no alternative CI configuration file is found."
msgstr ""
@@ -4308,127 +4447,127 @@ msgid "CICD|You must add a %{base_domain_link_start}base domain%{link_end} to yo
msgstr ""
msgid "CICD|group enabled"
-msgstr ""
+msgstr "gruppe aktivert"
msgid "CICD|instance enabled"
-msgstr ""
+msgstr "instans aktivert"
msgid "CLOSED"
-msgstr ""
+msgstr "LUKKET"
msgid "CLOSED (MOVED)"
+msgstr "LUKKET (FLYTTET)"
+
+msgid "CODEOWNERS rule violation"
msgstr ""
msgid "CONTRIBUTING"
-msgstr ""
+msgstr "CONTRIBUTING"
msgid "CPU"
-msgstr ""
+msgstr "CPU"
msgid "Callback URL"
-msgstr ""
+msgstr "URL-adresse for tilbakeringing"
msgid "Can be manually deployed to"
-msgstr ""
+msgstr "Kan distribueres manuelt til"
msgid "Can override approvers and approvals required per merge request"
msgstr ""
msgid "Can't apply as the source branch was deleted."
-msgstr ""
+msgstr "Kan ikke benytte det, siden kildegrenen ble slettet."
msgid "Can't apply as these lines were changed in a more recent version."
-msgstr ""
+msgstr "Kan ikke benytte det, siden disse linjene ble endret i en nyere versjon."
msgid "Can't apply as this line was changed in a more recent version."
-msgstr ""
+msgstr "Kan ikke benytte det, siden denne linjen ble endret i en nyere versjon."
msgid "Can't apply this suggestion."
-msgstr ""
+msgstr "Kan ikke benytte dette forslaget."
msgid "Can't create snippet: %{err}"
-msgstr ""
-
-msgid "Can't edit as source branch was deleted"
-msgstr ""
+msgstr "Kan ikke opprette utdrag: %{err}"
msgid "Can't fetch content for the blob: %{err}"
-msgstr ""
+msgstr "Kan ikke innhente blobbens innhold: %{err}"
msgid "Can't find HEAD commit for this branch"
msgstr ""
msgid "Can't find variable: ZiteReader"
-msgstr ""
+msgstr "Kan ikke finne variabel: ZiteReader"
msgid "Can't load mermaid module: %{err}"
-msgstr ""
-
-msgid "Can't remove group members without group managed account"
-msgstr ""
+msgstr "Kan ikke laste inn \"mermaid\"-modul: %{err}"
msgid "Can't scan the code?"
-msgstr ""
+msgstr "Kan du ikke skanne koden?"
msgid "Can't update snippet: %{err}"
-msgstr ""
+msgstr "Kan ikke oppdatere utdrag: %{err}"
msgid "Canary"
-msgstr ""
+msgstr "Canary"
msgid "Canary Deployments is a popular CI strategy, where a small portion of the fleet is updated to the new version of your application."
msgstr ""
msgid "Cancel"
-msgstr ""
+msgstr "Avbryt"
msgid "Cancel index deletion"
-msgstr ""
+msgstr "Avbryt indekssletting"
msgid "Cancel running"
msgstr ""
msgid "Cancel this job"
-msgstr ""
+msgstr "Avbryt denne jobben"
msgid "Cancel, keep project"
-msgstr ""
+msgstr "Avbryt, behold prosjektet"
msgid "Canceled deployment to"
msgstr ""
msgid "Cancelling Preview"
-msgstr ""
+msgstr "Avbryter forhåndsvisningen"
msgid "Cannot be merged automatically"
-msgstr ""
+msgstr "Kan ikke flettes automatisk"
msgid "Cannot create the abuse report. The user has been deleted."
-msgstr ""
+msgstr "Kan ikke opprette misbruksrapporten. Brukeren har blitt slettet."
msgid "Cannot create the abuse report. This user has been blocked."
+msgstr "Kan ikke opprette misbruksrapporten. Brukeren har blitt blokkert."
+
+msgid "Cannot enable shared runners because parent group does not allow it"
msgstr ""
msgid "Cannot have multiple Jira imports running at the same time"
-msgstr ""
+msgstr "Kan ikke ha flere Jira-importeringer som kjører samtidig"
msgid "Cannot have multiple unresolved alerts"
msgstr ""
msgid "Cannot import because issues are not available in this project."
-msgstr ""
+msgstr "Kan ikke importere fordi saker ikke er tilgjengelige i dette prosjektet."
msgid "Cannot make the epic confidential if it contains non-confidential child epics"
msgstr ""
msgid "Cannot make the epic confidential if it contains non-confidential issues"
-msgstr ""
+msgstr "Kan ikke gjøre eposet konfidensiell hvis den inneholder ikke-konfidensielle saker"
msgid "Cannot merge"
-msgstr ""
+msgstr "Kan ikke flette"
msgid "Cannot modify managed Kubernetes cluster"
-msgstr ""
+msgstr "Kan ikke modifisere den behandlede Kubernetes-klyngen"
msgid "Cannot modify provider during creation"
msgstr ""
@@ -4437,7 +4576,7 @@ msgid "Cannot promote issue because it does not belong to a group."
msgstr ""
msgid "Cannot promote issue due to insufficient permissions."
-msgstr ""
+msgstr "Kan ikke forfremme saken på grunn av manglende tillatelser."
msgid "Cannot refer to a group %{timebox_type} by an internal id!"
msgstr ""
@@ -4452,94 +4591,103 @@ msgid "Cannot skip two factor authentication setup"
msgstr ""
msgid "Capacity threshold"
-msgstr ""
+msgstr "Kapasitetsterskel"
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 "Visse typer brukerinnhold vil bli flyttet til en systemdekkende 'Spøkelsesbruker' for å opprettholde innholdet for ettertiden. For ytterligere informasjon, se dokumentasjonen %{link_start}for sletting av brukerkontoer.%{link_end}"
msgid "Certificate"
-msgstr ""
+msgstr "Sertifikat"
msgid "Certificate (PEM)"
-msgstr ""
+msgstr "Sertifikat (PEM)"
msgid "Certificate Issuer"
-msgstr ""
+msgstr "Sertifikatutsteder"
msgid "Certificate Subject"
-msgstr ""
+msgstr "Sertifikatets emne"
msgid "Change assignee"
-msgstr ""
+msgstr "Endre tilordnet person"
msgid "Change assignee(s)"
-msgstr ""
+msgstr "Endre tilordnet person(er)"
msgid "Change assignee(s)."
-msgstr ""
+msgstr "Endre tilordnet person(er)."
msgid "Change branches"
-msgstr ""
+msgstr "Endre grener"
msgid "Change label"
-msgstr ""
+msgstr "Endre stempel"
msgid "Change milestone"
-msgstr ""
+msgstr "Endre milepæl"
msgid "Change path"
-msgstr ""
+msgstr "Endre bane"
msgid "Change permissions"
-msgstr ""
+msgstr "Endre rettigheter"
msgid "Change status"
-msgstr ""
+msgstr "Endre status"
msgid "Change subscription"
-msgstr ""
+msgstr "Endre abonnement"
msgid "Change template"
-msgstr ""
+msgstr "Endre mal"
msgid "Change this value to influence how frequently the GitLab UI polls for updates."
msgstr ""
msgid "Change title"
-msgstr ""
+msgstr "Endre tittel"
msgid "Change your password"
-msgstr ""
+msgstr "Endre ditt passord"
msgid "Change your password or recover your current one"
+msgstr "Endre passordet ditt eller gjenopprett ditt nåværende"
+
+msgid "ChangeReviewer|Reviewer changed from %{old} to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Reviewer changed to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Unassigned"
msgstr ""
msgid "ChangeTypeActionLabel|Pick into branch"
msgstr ""
msgid "ChangeTypeActionLabel|Revert in branch"
-msgstr ""
+msgstr "Tilbakestill i grenen"
msgid "ChangeTypeAction|Cherry-pick"
msgstr ""
msgid "ChangeTypeAction|Revert"
-msgstr ""
+msgstr "Tilbakestill"
msgid "ChangeTypeAction|This will create a new commit in order to revert the existing changes."
-msgstr ""
+msgstr "Dette vil opprette en ny commit for å kunne tilbakestille de eksisterende endringene."
msgid "Changed assignee(s)."
-msgstr ""
+msgstr "Endret tilordnet person(er)."
msgid "Changed the title to \"%{title_param}\"."
-msgstr ""
+msgstr "Endret tittelen til «%{title_param}»."
msgid "Changes"
-msgstr ""
+msgstr "Endringer"
msgid "Changes affect new repositories only. If not specified, Git's default name %{branch_name_default} will be used."
-msgstr ""
+msgstr "Endringer påvirker bare nye arkiver. Hvis det ikke er spesifisert, vil Gits standardnavn %{branch_name_default} brukes."
msgid "Changes are shown as if the %{b_open}source%{b_close} revision was being merged into the %{b_open}target%{b_close} revision."
msgstr ""
@@ -4548,40 +4696,43 @@ msgid "Changes are still tracked. Useful for cluster/index migrations."
msgstr ""
msgid "Changes suppressed. Click to show."
-msgstr ""
+msgstr "Endringer er klappet sammen. Klikk for å vise."
msgid "Changes the title to \"%{title_param}\"."
+msgstr "Endrer tittelen til \"%{title_param}\"."
+
+msgid "Changes were successfully made."
msgstr ""
msgid "Changes won't take place until the index is %{link_start}recreated%{link_end}."
msgstr ""
msgid "Changing a Release tag is only supported via Releases API. %{linkStart}More information%{linkEnd}"
-msgstr ""
+msgstr "Å endre en utgivelsesetikett støttes kun gjennom 'Utgivelser'-API-en %{linkStart}Mer informasjon%{linkEnd}"
msgid "Changing group URL can have unintended side effects."
-msgstr ""
+msgstr "Endring av gruppe-URL-en kan ha utilsiktede bivirkninger."
msgid "Channel handle (e.g. town-square)"
msgstr ""
msgid "Charts"
-msgstr ""
+msgstr "Diagram"
msgid "Charts can't be displayed as the request for data has timed out. %{documentationLink}"
msgstr ""
msgid "Chat"
-msgstr ""
+msgstr "Chat"
msgid "ChatMessage|%{project_link}: Pipeline %{pipeline_link} of %{ref_type} %{ref_link} by %{user_combined_name} %{humanized_status} in %{duration}"
-msgstr ""
+msgstr "%{project_link}: Rørledning %{pipeline_link} av %{ref_type} %{ref_link} av %{user_combined_name} %{humanized_status} på %{duration}"
msgid "ChatMessage|Branch"
-msgstr ""
+msgstr "Gren"
msgid "ChatMessage|Commit"
-msgstr ""
+msgstr "Commit"
msgid "ChatMessage|Failed job"
msgstr ""
@@ -4590,55 +4741,55 @@ msgid "ChatMessage|Failed stage"
msgstr ""
msgid "ChatMessage|Invalid CI config YAML file"
-msgstr ""
+msgstr "Ugyldig YAML-konfigurasjonsfil for CI"
msgid "ChatMessage|Pipeline #%{pipeline_id} %{humanized_status} in %{duration}"
-msgstr ""
+msgstr "Rørledning #%{pipeline_id} %{humanized_status} på %{duration}"
msgid "ChatMessage|Pipeline %{pipeline_link} of %{ref_type} %{ref_link} by %{user_combined_name} %{humanized_status}"
-msgstr ""
+msgstr "Rørledning %{pipeline_link} av %{ref_type} %{ref_link} av %{user_combined_name} %{humanized_status}"
msgid "ChatMessage|Tag"
-msgstr ""
+msgstr "Etikett"
msgid "ChatMessage|and [%{count} more](%{pipeline_failed_jobs_url})"
-msgstr ""
+msgstr "og [%{count} til](%{pipeline_failed_jobs_url})"
msgid "ChatMessage|has failed"
-msgstr ""
+msgstr "har mislyktes"
msgid "ChatMessage|has passed"
-msgstr ""
+msgstr "har bestått"
msgid "ChatMessage|has passed with warnings"
-msgstr ""
+msgstr "har bestått med advarsler"
msgid "ChatMessage|in %{duration}"
-msgstr ""
+msgstr "i %{duration}"
msgid "ChatMessage|in %{project_link}"
-msgstr ""
+msgstr "i %{project_link}"
msgid "Check again"
-msgstr ""
+msgstr "Sjekk igjen"
msgid "Check feature availability on namespace plan"
msgstr ""
msgid "Check the %{docs_link_start}documentation%{docs_link_end}."
-msgstr ""
+msgstr "Sjekk %{docs_link_start}dokumentasjonen%{docs_link_end}."
msgid "Check your Docker images for known vulnerabilities."
msgstr ""
msgid "Checking %{text} availability…"
-msgstr ""
+msgstr "Kontrollerer %{text} tilgjengelighet …"
msgid "Checking approval status"
-msgstr ""
+msgstr "Sjekker godkjenningsstatusen"
msgid "Checking branch availability..."
-msgstr ""
+msgstr "Kontrollerer grenens tilgjengelighet …"
msgid "Checking group URL availability..."
msgstr ""
@@ -4647,55 +4798,55 @@ msgid "Checking group path availability..."
msgstr ""
msgid "Checking username availability..."
-msgstr ""
+msgstr "Sjekker brukernavnets tilgjengelighet …"
msgid "Checkout"
-msgstr ""
+msgstr "Kasse"
msgid "Checkout|$%{selectedPlanPrice} per user per year"
-msgstr ""
+msgstr "US$%{selectedPlanPrice} per bruker per år"
msgid "Checkout|%{cardType} ending in %{lastFourDigits}"
-msgstr ""
+msgstr "%{cardType} som slutter på %{lastFourDigits}"
msgid "Checkout|%{name}'s GitLab subscription"
-msgstr ""
+msgstr "%{name} sitt GitLab-abonnement"
msgid "Checkout|%{selectedPlanText} plan"
-msgstr ""
+msgstr "%{selectedPlanText}-plan"
msgid "Checkout|%{startDate} - %{endDate}"
-msgstr ""
+msgstr "%{startDate} - %{endDate}"
msgid "Checkout|(x%{numberOfUsers})"
-msgstr ""
+msgstr "(x%{numberOfUsers})"
msgid "Checkout|Billing address"
-msgstr ""
+msgstr "Faktureringsadresse"
msgid "Checkout|Checkout"
msgstr ""
msgid "Checkout|City"
-msgstr ""
+msgstr "By"
msgid "Checkout|Confirm purchase"
-msgstr ""
+msgstr "Bekreft kjøp"
msgid "Checkout|Confirming..."
-msgstr ""
+msgstr "Bekrefter …"
msgid "Checkout|Continue to billing"
-msgstr ""
+msgstr "Fortsett til fakturering"
msgid "Checkout|Continue to payment"
-msgstr ""
+msgstr "Fortsett til betaling"
msgid "Checkout|Country"
-msgstr ""
+msgstr "Land"
msgid "Checkout|Create a new group"
-msgstr ""
+msgstr "Opprett en ny gruppe"
msgid "Checkout|Credit card form failed to load. Please try again."
msgstr ""
@@ -4704,94 +4855,94 @@ msgid "Checkout|Credit card form failed to load: %{message}"
msgstr ""
msgid "Checkout|Edit"
-msgstr ""
+msgstr "Rediger"
msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
msgstr ""
msgid "Checkout|Failed to confirm your order! Please try again."
-msgstr ""
+msgstr "Mislyktes i å bekrefte din ordre! Vennligst prøv igjen."
msgid "Checkout|Failed to confirm your order: %{message}. Please try again."
-msgstr ""
+msgstr "Mislyktes i å bekrefte din ordre: %{message}. Vennligst prøv igjen."
msgid "Checkout|Failed to load countries. Please try again."
-msgstr ""
+msgstr "Mislyktes i å laste inn land. Vennligst prøv igjen."
msgid "Checkout|Failed to load states. Please try again."
-msgstr ""
+msgstr "Mislyktes i å laste inn delstater. Vennligst prøv igjen."
msgid "Checkout|Failed to register credit card. Please try again."
msgstr ""
msgid "Checkout|GitLab group"
-msgstr ""
+msgstr "GitLab-gruppe"
msgid "Checkout|GitLab plan"
-msgstr ""
+msgstr "GitLab-plan"
msgid "Checkout|Group"
-msgstr ""
+msgstr "Gruppe"
msgid "Checkout|Name of company or organization using GitLab"
msgstr ""
msgid "Checkout|Need more users? Purchase GitLab for your %{company}."
-msgstr ""
+msgstr "Trenger du flere brukere? Kjøp GitLab for ditt %{company}."
msgid "Checkout|Number of users"
-msgstr ""
+msgstr "Antall brukere"
msgid "Checkout|Payment method"
-msgstr ""
+msgstr "Betalingsmetode"
msgid "Checkout|Please select a country"
-msgstr ""
+msgstr "Vennligst velg et land"
msgid "Checkout|Please select a state"
-msgstr ""
+msgstr "Vennligst velg en delstat"
msgid "Checkout|Select"
-msgstr ""
+msgstr "Velg"
msgid "Checkout|State"
-msgstr ""
+msgstr "Delstat"
msgid "Checkout|Street address"
-msgstr ""
+msgstr "Gateadresse"
msgid "Checkout|Submitting the credit card form failed with code %{errorCode}: %{errorMessage}"
msgstr ""
msgid "Checkout|Subscription details"
-msgstr ""
+msgstr "Abonnementsdetaljer"
msgid "Checkout|Subtotal"
-msgstr ""
+msgstr "Delsum"
msgid "Checkout|Tax"
-msgstr ""
+msgstr "Avgift"
msgid "Checkout|Total"
-msgstr ""
+msgstr "Totalt"
msgid "Checkout|Users"
-msgstr ""
+msgstr "Brukere"
msgid "Checkout|You'll create your new group after checkout"
msgstr ""
msgid "Checkout|Your organization"
-msgstr ""
+msgstr "Organisasjonen din"
msgid "Checkout|Your subscription will be applied to this group"
msgstr ""
msgid "Checkout|Zip code"
-msgstr ""
+msgstr "Postnummer"
msgid "Checkout|company or team"
-msgstr ""
+msgstr "firma eller team"
msgid "Cherry-pick this commit"
msgstr ""
@@ -4800,7 +4951,7 @@ msgid "Cherry-pick this merge request"
msgstr ""
msgid "Child"
-msgstr ""
+msgstr "Etterkommer"
msgid "Child epic does not exist."
msgstr ""
@@ -4809,139 +4960,139 @@ msgid "Child epic doesn't exist."
msgstr ""
msgid "Choose %{strong_open}Create archive%{strong_close} and wait for archiving to complete."
-msgstr ""
+msgstr "Velg %{strong_open}Opprett arkiv%{strong_close} og vent til arkivering er fullført."
msgid "Choose %{strong_open}Next%{strong_close} at the bottom of the page."
-msgstr ""
+msgstr "Velg %{strong_open}Neste%{strong_close} nederst på siden."
msgid "Choose a branch/tag (e.g. %{master}) or enter a commit (e.g. %{sha}) to see what's changed or to create a merge request."
-msgstr ""
+msgstr "Velg en gren/etikett (f.eks. %{master}) eller skriv inn en commit (f.eks. %{sha}) for å se hva som er endret eller for å opprette en fletteforespørsel."
msgid "Choose a file"
-msgstr ""
+msgstr "Velg en fil"
msgid "Choose a group"
-msgstr ""
+msgstr "Velg en gruppe"
msgid "Choose a role permission"
-msgstr ""
+msgstr "Velg en rolletillatelse"
msgid "Choose a template"
-msgstr ""
+msgstr "Velg en mal"
msgid "Choose a template..."
-msgstr ""
+msgstr "Velg en mal …"
msgid "Choose a type..."
-msgstr ""
+msgstr "Velg en type …"
msgid "Choose any color."
-msgstr ""
+msgstr "Velg hvilken som helst farge."
msgid "Choose between %{code_open}clone%{code_close} or %{code_open}fetch%{code_close} to get the recent application code"
msgstr ""
msgid "Choose file…"
-msgstr ""
+msgstr "Velg fil …"
msgid "Choose labels"
-msgstr ""
+msgstr "Velg stempler"
msgid "Choose the top-level group for your repository imports."
msgstr ""
msgid "Choose visibility level, enable/disable project features (issues, repository, wiki, snippets) and set permissions."
-msgstr ""
+msgstr "Velg synlighetsnivå, (de)aktiver prosjektets funksjoner (saker,kodelager, wiki, snippets) og bestem tillatelser."
msgid "Choose what content you want to see on a group’s overview page."
-msgstr ""
+msgstr "Velg hvilket innhold du vil se på en gruppes oversiktsside."
msgid "Choose which repositories you want to connect and run CI/CD pipelines."
msgstr ""
msgid "Choose your framework"
-msgstr ""
+msgstr "Velg ditt rammeverk"
msgid "CiStatusLabel|canceled"
-msgstr ""
+msgstr "avbrutt"
msgid "CiStatusLabel|created"
-msgstr ""
+msgstr "opprettet"
msgid "CiStatusLabel|delayed"
-msgstr ""
+msgstr "forsinket"
msgid "CiStatusLabel|failed"
-msgstr ""
+msgstr "mislyktes"
msgid "CiStatusLabel|manual action"
-msgstr ""
+msgstr "manuell handling"
msgid "CiStatusLabel|passed"
-msgstr ""
+msgstr "bestått"
msgid "CiStatusLabel|passed with warnings"
-msgstr ""
+msgstr "bestått med advarsler"
msgid "CiStatusLabel|pending"
-msgstr ""
+msgstr "avventende"
msgid "CiStatusLabel|preparing"
-msgstr ""
+msgstr "forbereder"
msgid "CiStatusLabel|skipped"
-msgstr ""
+msgstr "hoppet over"
msgid "CiStatusLabel|waiting for delayed job"
msgstr ""
msgid "CiStatusLabel|waiting for manual action"
-msgstr ""
+msgstr "venter på manuell handling"
msgid "CiStatusLabel|waiting for resource"
-msgstr ""
+msgstr "venter på ressurs"
msgid "CiStatusText|blocked"
-msgstr ""
+msgstr "blokkert"
msgid "CiStatusText|canceled"
-msgstr ""
+msgstr "kansellert"
msgid "CiStatusText|created"
-msgstr ""
+msgstr "opprettet"
msgid "CiStatusText|delayed"
-msgstr ""
+msgstr "forsinket"
msgid "CiStatusText|failed"
-msgstr ""
+msgstr "mislykket"
msgid "CiStatusText|manual"
-msgstr ""
+msgstr "manuell"
msgid "CiStatusText|passed"
-msgstr ""
+msgstr "bestått"
msgid "CiStatusText|pending"
-msgstr ""
+msgstr "ventende"
msgid "CiStatusText|preparing"
-msgstr ""
+msgstr "forbereder"
msgid "CiStatusText|skipped"
-msgstr ""
+msgstr "hoppet over"
msgid "CiStatusText|waiting"
-msgstr ""
+msgstr "venter"
msgid "CiStatus|running"
-msgstr ""
+msgstr "kjørende"
msgid "CiVariables|Cannot use Masked Variable with current value"
msgstr ""
msgid "CiVariables|Environments"
-msgstr ""
+msgstr "Miljøer"
msgid "CiVariables|Input variable key"
msgstr ""
@@ -4950,70 +5101,73 @@ msgid "CiVariables|Input variable value"
msgstr ""
msgid "CiVariables|Key"
-msgstr ""
+msgstr "Nøkkel"
msgid "CiVariables|Masked"
-msgstr ""
+msgstr "Maskert"
msgid "CiVariables|Protected"
+msgstr "Beskyttet"
+
+msgid "CiVariables|Remove variable"
msgstr ""
msgid "CiVariables|Remove variable row"
-msgstr ""
+msgstr "Fjern variabel-rad"
msgid "CiVariables|Scope"
-msgstr ""
+msgstr "Omfang"
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 ""
msgid "CiVariables|State"
-msgstr ""
+msgstr "Tilstand"
msgid "CiVariables|Type"
-msgstr ""
+msgstr "Type"
msgid "CiVariables|Value"
-msgstr ""
+msgstr "Verdi"
msgid "CiVariables|Variables"
-msgstr ""
+msgstr "Variabler"
msgid "CiVariable|* (All environments)"
-msgstr ""
+msgstr "* (Alle miljøer)"
msgid "CiVariable|All environments"
-msgstr ""
+msgstr "Alle miljøer"
msgid "CiVariable|Create wildcard"
-msgstr ""
+msgstr "Opprett jokertegn"
msgid "CiVariable|Error occurred while saving variables"
msgstr ""
msgid "CiVariable|Masked"
-msgstr ""
+msgstr "Maskert"
msgid "CiVariable|New environment"
-msgstr ""
+msgstr "Nytt miljø"
msgid "CiVariable|Protected"
-msgstr ""
+msgstr "Beskyttet"
msgid "CiVariable|Search environments"
-msgstr ""
+msgstr "Søk i miljøene"
msgid "CiVariable|Toggle masked"
msgstr ""
msgid "CiVariable|Toggle protected"
-msgstr ""
+msgstr "Veksle beskyttelsesstatus"
msgid "CiVariable|Validation failed"
-msgstr ""
+msgstr "Validering mislyktes"
msgid "Classification Label (optional)"
-msgstr ""
+msgstr "Klassifiseringsetikett (valgfritt)"
msgid "ClassificationLabelUnavailable|is unavailable: %{reason}"
msgstr ""
@@ -5025,178 +5179,199 @@ msgid "Cleanup policy maximum processing time (seconds)"
msgstr ""
msgid "Clear"
-msgstr ""
+msgstr "Nullstill"
msgid "Clear all repository checks"
-msgstr ""
+msgstr "Fjern alle kodelagersjekkinger"
msgid "Clear chart filters"
msgstr ""
msgid "Clear due date"
-msgstr ""
-
-msgid "Clear input"
-msgstr ""
+msgstr "Tøm måldato"
msgid "Clear recent searches"
-msgstr ""
+msgstr "Tøm nylige søk"
msgid "Clear search"
-msgstr ""
+msgstr "Tøm søket"
msgid "Clear search input"
-msgstr ""
+msgstr "Tøm søkefelt"
msgid "Clear start date"
-msgstr ""
+msgstr "Tøm startdato"
msgid "Clear templates search input"
msgstr ""
msgid "Clear weight"
-msgstr ""
+msgstr "Tøm vekt"
msgid "Cleared weight."
-msgstr ""
+msgstr "Tømte vekt."
msgid "Clears weight."
-msgstr ""
+msgstr "Tømmer vekten."
msgid "Click the %{strong_open}Download%{strong_close} button and wait for downloading to complete."
-msgstr ""
+msgstr "Klikk på %{strong_open}Last ned%{strong_close}-knappen og vent til nedlastingen er fullført."
msgid "Click the %{strong_open}Select none%{strong_close} button on the right, since we only need \"Google Code Project Hosting\"."
-msgstr ""
+msgstr "Klikk på %{strong_open}Velg ingen%{strong_close}-knappen til høyre, siden vi bare trenger \"Google Code Project Hosting\"."
msgid "Click the button below to begin the install process by navigating to the Kubernetes page"
msgstr ""
msgid "Click to expand it."
-msgstr ""
+msgstr "Klikk for å utvide den."
msgid "Click to expand text"
-msgstr ""
+msgstr "Klikk for å utvide tekst"
msgid "Client authentication certificate"
-msgstr ""
+msgstr "Klientautentiseringssertifikat"
msgid "Client authentication key"
-msgstr ""
+msgstr "Klientautentiseringsnøkkel"
msgid "Client authentication key password"
+msgstr "Klientautentiseringsnøkkel-passord"
+
+msgid "Client request timeout"
msgstr ""
msgid "Clients"
-msgstr ""
+msgstr "Klienter"
msgid "Clone"
-msgstr ""
+msgstr "Klone"
msgid "Clone repository"
-msgstr ""
+msgstr "Klon lageret"
msgid "Clone with %{http_label}"
-msgstr ""
+msgstr "Klon med %{http_label}"
msgid "Clone with %{protocol}"
-msgstr ""
+msgstr "Klon med %{protocol}"
msgid "Clone with KRB5"
-msgstr ""
+msgstr "Klon med KRB5"
msgid "Clone with SSH"
-msgstr ""
+msgstr "Klon med SSH"
msgid "Close"
-msgstr ""
+msgstr "Lukk"
msgid "Close %{display_issuable_type}"
-msgstr ""
+msgstr "Lukk %{display_issuable_type}"
msgid "Close %{tabname}"
-msgstr ""
+msgstr "Lukk %{tabname}"
msgid "Close epic"
-msgstr ""
+msgstr "Lukk epos"
msgid "Close milestone"
-msgstr ""
+msgstr "Lukk milepæl"
msgid "Close sidebar"
-msgstr ""
+msgstr "Lukk sidelinje"
msgid "Close this %{quick_action_target}"
-msgstr ""
+msgstr "Lukk denne %{quick_action_target}"
msgid "Closed"
-msgstr ""
+msgstr "Lukket"
msgid "Closed %{epicTimeagoDate}"
-msgstr ""
+msgstr "Lukket %{epicTimeagoDate}"
msgid "Closed epics"
-msgstr ""
+msgstr "Lukkede eposer"
msgid "Closed issues"
-msgstr ""
+msgstr "Lukkede rapporter"
msgid "Closed this %{quick_action_target}."
-msgstr ""
+msgstr "Lukket denne %{quick_action_target}."
msgid "Closed: %{closedIssuesCount}"
-msgstr ""
+msgstr "Lukket: %{closedIssuesCount}"
msgid "Closes this %{quick_action_target}."
-msgstr ""
+msgstr "Lukker denne %{quick_action_target}."
msgid "Cluster"
-msgstr ""
+msgstr "Klynge"
msgid "Cluster Health"
-msgstr ""
+msgstr "Klynge-helse"
msgid "Cluster cache cleared."
msgstr ""
msgid "Cluster does not exist"
-msgstr ""
+msgstr "Klyngen finnes ikke"
msgid "Cluster is required for Stages::ClusterEndpointInserter"
msgstr ""
msgid "Cluster level"
-msgstr ""
+msgstr "Klynge-nivå"
msgid "Cluster type must be specificed for Stages::ClusterEndpointInserter"
msgstr ""
-msgid "ClusterAgent|This feature is only available for premium plans"
+msgid "ClusterAgents|Configuration"
msgstr ""
-msgid "ClusterAgent|User has insufficient permissions to create a token for this project"
+msgid "ClusterAgents|Connect your cluster with the GitLab Agent"
msgstr ""
-msgid "ClusterAgent|You have insufficient permissions to create a cluster agent for this project"
+msgid "ClusterAgents|Integrate Kubernetes with a GitLab Agent"
msgstr ""
-msgid "ClusterAgent|You have insufficient permissions to delete this cluster agent"
+msgid "ClusterAgents|Integrate with the GitLab Agent"
msgstr ""
-msgid "ClusterIntegration|%{appList} was successfully installed on your Kubernetes cluster"
+msgid "ClusterAgents|Name"
msgstr ""
-msgid "ClusterIntegration|%{externalIp}.nip.io"
+msgid "ClusterAgents|The GitLab Agent also requires %{linkStart}enabling the Agent Server%{linkEnd}"
msgstr ""
-msgid "ClusterIntegration|%{linkStart}More information%{linkEnd}"
+msgid "ClusterAgents|The GitLab Kubernetes Agent allows an Infrastructure as Code, GitOps approach to integrating Kubernetes clusters with GitLab. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
+msgid "ClusterAgent|This feature is only available for premium plans"
+msgstr "Denne funksjonen er bare tilgjengelig for Premium-planer"
+
+msgid "ClusterAgent|User has insufficient permissions to create a token for this project"
+msgstr "Brukeren har ikke tilstrekkelige tillatelser til å opprette en sjetong for dette prosjektet"
+
+msgid "ClusterAgent|You have insufficient permissions to create a cluster agent for this project"
+msgstr "Du har ikke tilstrekkelige tillatelser til å opprette en klyngeagent for dette prosjektet"
+
+msgid "ClusterAgent|You have insufficient permissions to delete this cluster agent"
+msgstr "Du har ikke tilstrekkelige tillatelser til å slette denne klyngeagenten"
+
+msgid "ClusterIntegration|%{appList} was successfully installed on your Kubernetes cluster"
+msgstr "%{appList} ble velykket installert på Kubernetes-klyngen din"
+
+msgid "ClusterIntegration|%{externalIp}.nip.io"
+msgstr "%{externalIp}.nip.io"
+
+msgid "ClusterIntegration|%{linkStart}More information%{linkEnd}"
+msgstr "%{linkStart}Mer informasjon%{linkEnd}"
+
msgid "ClusterIntegration|%{title} uninstalled successfully."
-msgstr ""
+msgstr "%{title} ble vellykket avinstallert."
msgid "ClusterIntegration|%{title} updated successfully."
-msgstr ""
+msgstr "%{title} ble vellykket oppdatert."
msgid "ClusterIntegration|A cluster management project can be used to run deployment jobs with Kubernetes %{code_open}cluster-admin%{code_close} privileges."
msgstr ""
@@ -5205,218 +5380,242 @@ msgid "ClusterIntegration|A service token scoped to %{code}kube-system%{end_code
msgstr ""
msgid "ClusterIntegration|API URL"
-msgstr ""
+msgstr "API-URL"
msgid "ClusterIntegration|API URL should be a valid http/https url."
-msgstr ""
+msgstr "API-URL-en burde være en gyldig http/https-URL."
msgid "ClusterIntegration|Add Kubernetes cluster"
-msgstr ""
+msgstr "Legg til Kubernetes-klynge"
msgid "ClusterIntegration|Add a Kubernetes cluster integration"
-msgstr ""
+msgstr "Legg til en Kubernetes-klyngeintegrasjon"
msgid "ClusterIntegration|Adding a Kubernetes cluster to your group will automatically share the cluster across all your projects. Use review apps, deploy your applications, and easily run your pipelines for all projects using the same cluster."
-msgstr ""
+msgstr "Å legge til en Kubernetes-klynge i gruppen din vil automatisk dele klyngen rundt på tvers av alle prosjektene dine. Bruk gjennomgangsapper, distribuer applikasjonene dine, og kjør rørledningene dine med letthet på alle prosjekter som bruker den samme klyngen."
msgid "ClusterIntegration|Adding a Kubernetes cluster will automatically share the cluster across all projects. Use review apps, deploy your applications, and easily run your pipelines for all projects using the same cluster."
-msgstr ""
+msgstr "Å legge til en Kubernetes-klynge vil automatisk dele klyngen rundt på tvers av alle prosjekter. Bruk gjennomgangsapper, distribuer applikasjonene dine, og kjør rørledningene dine med letthet på alle prosjekter som bruker den samme klyngen."
msgid "ClusterIntegration|Adding an integration to your group will share the cluster across all your projects."
-msgstr ""
+msgstr "Å legge til en integrasjon i gruppen din vil dele klyngen rundt på tvers av alle prosjektene dine."
msgid "ClusterIntegration|Adding an integration will share the cluster across all projects."
msgstr ""
msgid "ClusterIntegration|Advanced options on this Kubernetes cluster’s integration"
-msgstr ""
+msgstr "Avanserte alternativer for denne Kubernetes-klyngens integrering"
msgid "ClusterIntegration|All data not committed to GitLab will be deleted and cannot be restored."
-msgstr ""
+msgstr "Alle data som ikke er commitet til GitLab vil bli slettet og kan ikke bli gjenopprettet."
msgid "ClusterIntegration|All data will be deleted and cannot be restored."
-msgstr ""
+msgstr "Alle data blir slettet og kan ikke gjenopprettes."
msgid "ClusterIntegration|All installed applications and related resources"
-msgstr ""
+msgstr "Alle installerte applikasjoner og relaterte ressurser"
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster."
+msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{linkStart}More information%{linkEnd}"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{startLink}More information%{endLink}"
+msgid "ClusterIntegration|Allow GitLab to manage namespaces and service accounts for this cluster."
msgstr ""
msgid "ClusterIntegration|Alternatively, "
-msgstr ""
+msgstr "Alternativt, "
msgid "ClusterIntegration|Amazon EKS"
-msgstr ""
+msgstr "Amazon EKS"
msgid "ClusterIntegration|An error occurred when trying to contact the Google Cloud API. Please try again later."
-msgstr ""
+msgstr "En feil oppstod under forsøk på å kontakte 'Google Cloud'-API-en. Prøv igjen senere."
msgid "ClusterIntegration|An error occurred while trying to fetch project zones: %{error}"
-msgstr ""
+msgstr "Det oppstod en feil under forsøk på å innhente prosjektsoner: %{error}"
msgid "ClusterIntegration|An error occurred while trying to fetch your projects: %{error}"
-msgstr ""
+msgstr "Det oppstod en feil under forsøk på å innhente prosjektene dine: %{error}"
msgid "ClusterIntegration|An error occurred while trying to fetch zone machine types: %{error}"
+msgstr "Det oppstod en feil under forsøk på å innhente sonemaskintyper: %{error}"
+
+msgid "ClusterIntegration|An unknown error occurred while attempting to connect to Kubernetes."
msgstr ""
msgid "ClusterIntegration|Any project namespaces"
msgstr ""
msgid "ClusterIntegration|Any running pipelines will be canceled."
-msgstr ""
+msgstr "Eventuelle kjørende rørledninger vil bli avbrutt."
msgid "ClusterIntegration|Apply for credit"
msgstr ""
msgid "ClusterIntegration|Authenticate with AWS"
-msgstr ""
+msgstr "Autentiser med AWS"
msgid "ClusterIntegration|Authenticate with Amazon Web Services"
+msgstr "Autentiser med Amazon Web Services"
+
+msgid "ClusterIntegration|Authentication Error"
msgstr ""
msgid "ClusterIntegration|Base domain"
-msgstr ""
+msgstr "Grunndomene"
msgid "ClusterIntegration|Blocking mode"
-msgstr ""
+msgstr "Blokkeringsmodus"
msgid "ClusterIntegration|CA Certificate"
-msgstr ""
+msgstr "CA-sertifikat"
msgid "ClusterIntegration|Cert-Manager"
-msgstr ""
+msgstr "Sertifikatbehandler"
msgid "ClusterIntegration|Cert-Manager is a native Kubernetes certificate management controller that helps with issuing certificates. Installing Cert-Manager on your cluster will issue a certificate by %{linkStart}Let's Encrypt%{linkEnd} and ensure that certificates are valid and up-to-date."
-msgstr ""
+msgstr "Cert-Manager er en innebygd Kubernetes-sertifikatadministrator som hjelper med utstedelse av sertifikater. Installering av Cert-Manager i klyngen din utsteder et sertifikat fra %{linkStart}Let's Encrypt%{linkEnd} og sikrer at sertifikatene er gyldige og oppdaterte."
msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}security group %{externalLinkIcon} %{endLink} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
+msgid "ClusterIntegration|Check your CA certificate"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}subnets %{externalLinkIcon} %{endLink} in your VPC where your worker nodes will run."
+msgid "ClusterIntegration|Check your cluster status"
msgstr ""
-msgid "ClusterIntegration|Choose the worker node %{startLink}instance type %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Check your token"
msgstr ""
-msgid "ClusterIntegration|Choose which applications to install on your Kubernetes cluster."
+msgid "ClusterIntegration|Choose the %{linkStart}security group %{linkEnd} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
msgstr ""
-msgid "ClusterIntegration|Choose which of your environments will use this cluster."
+msgid "ClusterIntegration|Choose the %{linkStart}subnets %{linkEnd} in your VPC where your worker nodes will run."
msgstr ""
-msgid "ClusterIntegration|Clear cluster cache"
+msgid "ClusterIntegration|Choose the worker node %{linkStart}instance type%{linkEnd}."
msgstr ""
-msgid "ClusterIntegration|Clear the local cache of namespace and service accounts. This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
+msgid "ClusterIntegration|Choose which applications to install on your Kubernetes cluster."
+msgstr "Velg hvilke applikasjoner som skal installeres på Kubernetes-klyngen din."
+
+msgid "ClusterIntegration|Choose which of your environments will use this cluster."
+msgstr "Velg hvilke av miljøene dine som skal bruke denne klyngen."
+
+msgid "ClusterIntegration|Clear cluster cache"
msgstr ""
-msgid "ClusterIntegration|Cluster being created"
+msgid "ClusterIntegration|Clear the local cache of namespace and service accounts."
msgstr ""
msgid "ClusterIntegration|Cluster management project (alpha)"
msgstr ""
msgid "ClusterIntegration|Cluster name is required."
-msgstr ""
+msgstr "Klyngenavn er påkrevd."
msgid "ClusterIntegration|Cluster_applications artifact too big. Maximum allowable size: %{human_size}"
msgstr ""
-msgid "ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters."
+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 "Klynger brukes ved å velge nærmeste forfader med et samsvarende miljøomfang. For eksempel vil prosjektklynger overstyre gruppeklynger. %{linkStart}Mere informasjon%{linkEnd}"
+
+msgid "ClusterIntegration|Clusters connected with a certificate"
msgstr ""
-msgid "ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters. %{linkStart}More information%{linkEnd}"
+msgid "ClusterIntegration|Connect cluster with certificate"
msgstr ""
msgid "ClusterIntegration|Connect existing cluster"
+msgstr "Koble til eksisterende klynge"
+
+msgid "ClusterIntegration|Connection Error"
msgstr ""
msgid "ClusterIntegration|Copy API URL"
-msgstr ""
+msgstr "Kopier API-URL"
msgid "ClusterIntegration|Copy CA Certificate"
-msgstr ""
+msgstr "Kopier CA-sertifikat"
msgid "ClusterIntegration|Copy Ingress Endpoint"
-msgstr ""
+msgstr "Kopier Ingress-endepunkt"
msgid "ClusterIntegration|Copy Jupyter Hostname"
-msgstr ""
+msgstr "Kopier Jupyter-vertsnavn"
msgid "ClusterIntegration|Copy Knative Endpoint"
-msgstr ""
+msgstr "Kopier Knative-endepunkt"
msgid "ClusterIntegration|Copy Kubernetes cluster name"
-msgstr ""
+msgstr "Kopier Kubernetes-klyngenavn"
msgid "ClusterIntegration|Could not load IAM roles"
-msgstr ""
+msgstr "Klarte ikke å laste inn IAM-roller"
msgid "ClusterIntegration|Could not load Key Pairs"
-msgstr ""
+msgstr "Klarte ikke å laste inn nøkkelpar"
msgid "ClusterIntegration|Could not load VPCs for the selected region"
msgstr ""
msgid "ClusterIntegration|Could not load instance types"
-msgstr ""
+msgstr "Klarte ikke å laste inn instanstyper"
msgid "ClusterIntegration|Could not load networks"
-msgstr ""
+msgstr "Klarte ikke å laste inn nettverk"
msgid "ClusterIntegration|Could not load regions from your AWS account"
-msgstr ""
+msgstr "Kunne ikke laste inn regioner fra AWS-kontoen din"
msgid "ClusterIntegration|Could not load security groups for the selected VPC"
-msgstr ""
+msgstr "Kunne ikke laste inn sikkerhetsgrupper for den valgte VPC-en"
msgid "ClusterIntegration|Could not load subnets for the selected VPC"
msgstr ""
msgid "ClusterIntegration|Could not load subnetworks"
-msgstr ""
+msgstr "Klarte ikke å laste inn undernettverk"
msgid "ClusterIntegration|Create Kubernetes cluster"
-msgstr ""
+msgstr "Opprett Kubernetes-klynge"
msgid "ClusterIntegration|Create a provision role on %{startAwsLink}Amazon Web Services %{externalLinkIcon}%{endLink} using the account and external ID above. %{startMoreInfoLink}More information%{endLink}"
-msgstr ""
+msgstr "Opprett en klargjøringsrolle på %{startAwsLink}Amazon Web Services %{externalLinkIcon}%{endLink} ved hjelp av kontoen og den eksterne ID-en ovenfor. %{startMoreInfoLink}Mer informasjon%{endLink}"
msgid "ClusterIntegration|Create cluster on"
-msgstr ""
+msgstr "Opprett klynge på"
msgid "ClusterIntegration|Create new cluster"
-msgstr ""
+msgstr "Opprett ny klynge"
msgid "ClusterIntegration|Create new cluster on EKS"
-msgstr ""
+msgstr "Opprett ny klynge på EKS"
msgid "ClusterIntegration|Create new cluster on GKE"
-msgstr ""
+msgstr "Opprett ny klynge på GKE"
msgid "ClusterIntegration|Creating Kubernetes cluster"
-msgstr ""
+msgstr "Oppretter Kubernetes-klynge"
msgid "ClusterIntegration|Crossplane"
-msgstr ""
+msgstr "Crossplane"
msgid "ClusterIntegration|Crossplane enables declarative provisioning of managed services from your cloud of choice using %{codeStart}kubectl%{codeEnd} or %{linkStart}GitLab Integration%{linkEnd}. Crossplane runs inside your Kubernetes cluster and supports secure connectivity and secrets management between app containers and the cloud services they depend on."
-msgstr ""
+msgstr "Crossplane gir deklarativ provisjonering av administrerte tjenester fra din nettsky som bruker %{codeStart}kubectl%{codeEnd} eller %{linkStart}GitLab.integrering%{linkEnd}. Crossplane kjører inne i Kubernetes-klyngen din og støtter sikker tilkobling og hemmelighetsstyring mellom app-containere og de skytjenestene de avhenger av."
msgid "ClusterIntegration|Deletes all GitLab resources attached to this cluster during removal"
+msgstr "Sletter alle GitLab-ressurser som er knyttet til denne klyngen under fjerning"
+
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared."
msgstr ""
-msgid "ClusterIntegration|Did you know?"
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared. %{linkStart}More information%{linkEnd}"
msgstr ""
+msgid "ClusterIntegration|Did you know?"
+msgstr "Visste du det?"
+
msgid "ClusterIntegration|Elastic Kubernetes Service"
msgstr ""
@@ -5430,13 +5629,13 @@ msgid "ClusterIntegration|Enable or disable GitLab's connection to your Kubernet
msgstr ""
msgid "ClusterIntegration|Enable this setting if using role-based access control (RBAC)."
-msgstr ""
+msgstr "Aktiver denne innstillingen hvis du bruker rollebasert tilgangskontroll (RBAC)."
msgid "ClusterIntegration|Enabled stack"
msgstr ""
msgid "ClusterIntegration|Enter new Service Token"
-msgstr ""
+msgstr "Skriv inn ny tjenestesjetong"
msgid "ClusterIntegration|Enter the details for your Amazon EKS Kubernetes cluster"
msgstr ""
@@ -5445,13 +5644,13 @@ msgid "ClusterIntegration|Enter the details for your Kubernetes cluster"
msgstr ""
msgid "ClusterIntegration|Environment scope"
-msgstr ""
+msgstr "Miljøomfang"
msgid "ClusterIntegration|Environment scope is required."
-msgstr ""
+msgstr "Miljøomfanget er påkrevd."
msgid "ClusterIntegration|Every new Google Cloud Platform (GCP) account receives $300 in credit upon %{sign_up_link}. In partnership with Google, GitLab is able to offer an additional $200 for both new and existing GCP accounts to get started with GitLab's Google Kubernetes Engine Integration."
-msgstr ""
+msgstr "Hver nye Google Cloud Platform (GCP)-konto mottar US$300 i kreditt ved %{sign_up_link}. I samarbeid med Google, kan GitLab tilby ytterligere US$200 for både nye og eksisterende GCP-kontoer for å komme i gang med GitLab sin Google Kubernetes Engine-integrering."
msgid "ClusterIntegration|Failed to configure EKS provider: %{message}"
msgstr ""
@@ -5469,43 +5668,52 @@ msgid "ClusterIntegration|Failed to run Kubeclient: %{message}"
msgstr ""
msgid "ClusterIntegration|Fetching machine types"
-msgstr ""
+msgstr "Innhenter maskintyper"
msgid "ClusterIntegration|Fetching projects"
-msgstr ""
+msgstr "Innhenter prosjekter"
msgid "ClusterIntegration|Fetching zones"
-msgstr ""
+msgstr "Innhenter soner"
msgid "ClusterIntegration|Fluentd"
-msgstr ""
+msgstr "Fluentd"
msgid "ClusterIntegration|Fluentd is an open source data collector, which lets you unify the data collection and consumption for a better use and understanding of data. It requires at least one of the following logs to be successfully installed."
+msgstr "Fluentd er en åpenkildekodet datasamler, som lar deg forene datainnsamlingen og forbruket for en bedre bruk og forståelse av data. Det krever at minst en av følgende loggføringer har blitt vellykket installert."
+
+msgid "ClusterIntegration|GitLab Agent managed clusters"
msgstr ""
msgid "ClusterIntegration|GitLab Container Network Policies"
msgstr ""
msgid "ClusterIntegration|GitLab Integration"
-msgstr ""
+msgstr "GitLab-integrering"
msgid "ClusterIntegration|GitLab Runner"
msgstr ""
msgid "ClusterIntegration|GitLab Runner connects to the repository and executes CI/CD jobs, pushing results back and deploying applications to production."
+msgstr "GitLab Runner kobler til kodelageret og iverksetter CI/CD-jobber, pusher resultater tilbake, og distribuerer applikasjoner til produksjonen."
+
+msgid "ClusterIntegration|GitLab failed to authenticate."
msgstr ""
-msgid "ClusterIntegration|GitLab-managed cluster"
+msgid "ClusterIntegration|GitLab failed to connect to the cluster."
msgstr ""
+msgid "ClusterIntegration|GitLab-managed cluster"
+msgstr "GitLab-behandlet klynge"
+
msgid "ClusterIntegration|Global default"
-msgstr ""
+msgstr "Universell standard"
msgid "ClusterIntegration|Google Cloud Platform project"
msgstr ""
msgid "ClusterIntegration|Google GKE"
-msgstr ""
+msgstr "Google GKE"
msgid "ClusterIntegration|Google Kubernetes Engine"
msgstr ""
@@ -5514,13 +5722,16 @@ msgid "ClusterIntegration|Google Kubernetes Engine project"
msgstr ""
msgid "ClusterIntegration|Group cluster"
+msgstr "Gruppeklynge"
+
+msgid "ClusterIntegration|HTTP Error"
msgstr ""
msgid "ClusterIntegration|Helm Tiller"
-msgstr ""
+msgstr "Helm Tiller"
msgid "ClusterIntegration|Helm release failed to install"
-msgstr ""
+msgstr "Helm-utgivelsen mislyktes i å bli installert"
msgid "ClusterIntegration|If you are setting up multiple clusters and are using Auto DevOps, %{help_link_start}read this first%{help_link_end}."
msgstr ""
@@ -5532,10 +5743,10 @@ msgid "ClusterIntegration|In order to view the health of your cluster, you must
msgstr ""
msgid "ClusterIntegration|Ingress"
-msgstr ""
+msgstr "Ingress"
msgid "ClusterIntegration|Ingress Endpoint"
-msgstr ""
+msgstr "Ingress-endepunkt"
msgid "ClusterIntegration|Ingress gives you a way to route requests to services based on the request host or path, centralizing a number of services into a single entrypoint."
msgstr ""
@@ -5544,12 +5755,15 @@ msgid "ClusterIntegration|Installing Ingress may incur additional costs. Learn m
msgstr ""
msgid "ClusterIntegration|Instance cluster"
-msgstr ""
+msgstr "Instansklynge"
msgid "ClusterIntegration|Instance type"
+msgstr "Instanstype"
+
+msgid "ClusterIntegration|Integrate Kubernetes with a cluster certificate"
msgstr ""
-msgid "ClusterIntegration|Integrate Kubernetes cluster automation"
+msgid "ClusterIntegration|Integrate with a cluster certificate"
msgstr ""
msgid "ClusterIntegration|Issuer Email"
@@ -5559,121 +5773,121 @@ msgid "ClusterIntegration|Issuers represent a certificate authority. You must pr
msgstr ""
msgid "ClusterIntegration|Jupyter Hostname"
-msgstr ""
+msgstr "Jupyter-vertsnavn"
msgid "ClusterIntegration|JupyterHub"
-msgstr ""
+msgstr "JupyterHub"
msgid "ClusterIntegration|JupyterHub, a multi-user Hub, spawns, manages, and proxies multiple instances of the single-user Jupyter notebook server. JupyterHub can be used to serve notebooks to a class of students, a corporate data science group, or a scientific research group."
-msgstr ""
+msgstr "JupyterHub, en flerbrukersentral, setter opp, administrerer og mellombetjener flere forekomster av Jupyter-notatbokserveren til en enkeltbruker. JupyterHub kan brukes til å dele ut notatbøker til en studentklasse, en datavitenskapelig firmagruppe eller en vitenskapelig forskningsgruppe."
msgid "ClusterIntegration|Key pair name"
-msgstr ""
+msgstr "Navn på nøkkelpar"
msgid "ClusterIntegration|Knative"
-msgstr ""
+msgstr "Knative"
msgid "ClusterIntegration|Knative Domain Name:"
-msgstr ""
+msgstr "Knativ-domenenavn:"
msgid "ClusterIntegration|Knative Endpoint:"
-msgstr ""
+msgstr "Knative-endepunkt:"
msgid "ClusterIntegration|Knative domain name was updated successfully."
-msgstr ""
+msgstr "Knative-domenenavnet ble vellykket oppdatert."
msgid "ClusterIntegration|Knative extends Kubernetes to provide a set of middleware components that are essential to build modern, source-centric, and container-based applications that can run anywhere: on premises, in the cloud, or even in a third-party data center."
-msgstr ""
-
-msgid "ClusterIntegration|Kubernetes cluster"
-msgstr ""
+msgstr "Knative utvider Kubernetes for å tilby et set medt mellomvarekomponenter som er essensielle for å bygge moderne, kildesentriske og containerbaserte applikasjoner som kan kjøre hvor som helst: hos lokaler, i skyen, eller til og med i et tredjeparts datasenter."
msgid "ClusterIntegration|Kubernetes cluster is being created..."
-msgstr ""
+msgstr "Kubernetes-klynge blir for øyeblikket opprettet..."
msgid "ClusterIntegration|Kubernetes cluster name"
-msgstr ""
+msgstr "Kubernetes-klyngenavn"
msgid "ClusterIntegration|Kubernetes cluster was successfully created."
-msgstr ""
+msgstr "Kubernetes-klyngen ble vellykket opprettet."
msgid "ClusterIntegration|Kubernetes clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr ""
-msgid "ClusterIntegration|Kubernetes clusters can be used to deploy applications and to provide Review Apps for this project"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes version"
-msgstr ""
+msgstr "Kubernetes-versjon"
msgid "ClusterIntegration|Kubernetes version not found"
-msgstr ""
+msgstr "Kubernetes-versjon ble ikke funnet"
msgid "ClusterIntegration|Learn more about %{help_link_start_machine_type}machine types%{help_link_end} and %{help_link_start_pricing}pricing%{help_link_end}."
-msgstr ""
+msgstr "Lær mer om %{help_link_start_machine_type}maskintyper%{help_link_end} og %{help_link_start_pricing}prissetting%{help_link_end}."
msgid "ClusterIntegration|Learn more about %{help_link_start}zones%{help_link_end}."
-msgstr ""
+msgstr "Lær mer om %{help_link_start}soner%{help_link_end}."
-msgid "ClusterIntegration|Learn more about %{startLink}Regions %{externalLinkIcon}%{endLink}."
+msgid "ClusterIntegration|Learn more about %{linkStart}Regions%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Learn more about Kubernetes"
-msgstr ""
+msgstr "Lær mer om Kubernetes"
msgid "ClusterIntegration|Learn more about group Kubernetes clusters"
-msgstr ""
+msgstr "Lær mer om gruppe-Kubernetes-klynger"
msgid "ClusterIntegration|Learn more about instance Kubernetes clusters"
-msgstr ""
+msgstr "Lær mer om instans-Kubernetes-klynger"
msgid "ClusterIntegration|Loading IAM Roles"
-msgstr ""
+msgstr "Laster inn IAM-roller"
msgid "ClusterIntegration|Loading Key Pairs"
-msgstr ""
+msgstr "Laster inn nøkkelpar"
msgid "ClusterIntegration|Loading Regions"
-msgstr ""
+msgstr "Laster inn regioner"
msgid "ClusterIntegration|Loading VPCs"
-msgstr ""
+msgstr "Laster inn VPC-er"
msgid "ClusterIntegration|Loading instance types"
-msgstr ""
+msgstr "Laster inn instanstyper"
msgid "ClusterIntegration|Loading networks"
-msgstr ""
+msgstr "Laster inn nettverk"
msgid "ClusterIntegration|Loading security groups"
-msgstr ""
+msgstr "Laster inn sikkerhetsgrupper"
msgid "ClusterIntegration|Loading subnets"
-msgstr ""
+msgstr "Laster inn undernett"
msgid "ClusterIntegration|Loading subnetworks"
-msgstr ""
+msgstr "Laster inn undernettverk"
msgid "ClusterIntegration|Logging mode"
-msgstr ""
+msgstr "Loggføringsmodus"
msgid "ClusterIntegration|Machine type"
+msgstr "Maskintype"
+
+msgid "ClusterIntegration|Make sure your API endpoint is correct"
msgstr ""
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create Kubernetes clusters"
-msgstr ""
+msgstr "Sørg for at kontoen din %{link_to_requirements} for å opprette Kubernetes-klynger"
msgid "ClusterIntegration|Manage your Kubernetes cluster by visiting %{provider_link}"
+msgstr "Behandle Kubernetes-klyngen din ved å gå til %{provider_link}"
+
+msgid "ClusterIntegration|Namespace per environment"
msgstr ""
msgid "ClusterIntegration|No IAM Roles found"
-msgstr ""
+msgstr "Ingen IAM-roller ble funnet"
msgid "ClusterIntegration|No Key Pairs found"
-msgstr ""
+msgstr "Ingen nøkkelpar funnet"
msgid "ClusterIntegration|No VPCs found"
-msgstr ""
+msgstr "Ingen VPC-er funnet"
msgid "ClusterIntegration|No deployment cluster found for this job"
msgstr ""
@@ -5682,40 +5896,43 @@ msgid "ClusterIntegration|No deployment found for this job"
msgstr ""
msgid "ClusterIntegration|No instance type found"
-msgstr ""
+msgstr "Ingen instanstype funnet"
msgid "ClusterIntegration|No machine types matched your search"
-msgstr ""
+msgstr "Ingen maskintyper samsvarte med søket ditt"
msgid "ClusterIntegration|No networks found"
-msgstr ""
+msgstr "Inget nettverk funnet"
msgid "ClusterIntegration|No projects found"
-msgstr ""
+msgstr "Ingen prosjekter funnet"
msgid "ClusterIntegration|No projects matched your search"
-msgstr ""
+msgstr "Ingen prosjekter samsvarte med søket ditt"
msgid "ClusterIntegration|No region found"
-msgstr ""
+msgstr "Ingen region funnet"
msgid "ClusterIntegration|No security group found"
-msgstr ""
+msgstr "Ingen sikkerhetsgruppe funnet"
msgid "ClusterIntegration|No subnet found"
-msgstr ""
+msgstr "Inget undernett funnet"
msgid "ClusterIntegration|No subnetworks found"
-msgstr ""
+msgstr "Inget undernettverk funnet"
msgid "ClusterIntegration|No zones matched your search"
+msgstr "Ingen soner samsvarte med søket ditt"
+
+msgid "ClusterIntegration|Node calculations use the Kubernetes Metrics API. Make sure your cluster has metrics installed"
msgstr ""
msgid "ClusterIntegration|Number of nodes"
-msgstr ""
+msgstr "Antall noder"
msgid "ClusterIntegration|Number of nodes must be a numerical value."
-msgstr ""
+msgstr "Antall noder må være en numerisk verdi."
msgid "ClusterIntegration|Please enter access information for your Kubernetes cluster. If you need help, you can read our %{linkStart}documentation%{linkEnd} on Kubernetes"
msgstr ""
@@ -5727,25 +5944,25 @@ msgid "ClusterIntegration|Point a wildcard DNS to this generated endpoint in ord
msgstr ""
msgid "ClusterIntegration|Project cluster"
-msgstr ""
+msgstr "Prosjektklynge"
msgid "ClusterIntegration|Project namespace (optional, unique)"
-msgstr ""
+msgstr "Prosjektnavnefelt (valgfritt, unik)"
msgid "ClusterIntegration|Project namespace prefix (optional, unique)"
msgstr ""
msgid "ClusterIntegration|Prometheus"
-msgstr ""
+msgstr "Prometheus"
msgid "ClusterIntegration|Prometheus is an open-source monitoring system with %{linkStart}GitLab Integration%{linkEnd} to monitor deployed applications."
msgstr ""
msgid "ClusterIntegration|Protect your clusters with GitLab Container Network Policies by enforcing how pods communicate with each other and other network endpoints. %{linkStart}Learn more about configuring Network Policies here.%{linkEnd}"
-msgstr ""
+msgstr "Beskytt klyngene dine med GitLab sine containernettverksretningslinjer ved å håndheve hvordan pods kommuniserer med hverandre og andre nettverks-endepunkter. %{linkStart}Lær mer om konfigurering av nettverksretningslinjer her.%{linkEnd}"
msgid "ClusterIntegration|Provider details"
-msgstr ""
+msgstr "Leverandørdetaljer"
msgid "ClusterIntegration|Provision Role ARN"
msgstr ""
@@ -5753,29 +5970,32 @@ msgstr ""
msgid "ClusterIntegration|RBAC-enabled cluster"
msgstr ""
-msgid "ClusterIntegration|Read our %{link_start}help page%{link_end} on Kubernetes cluster integration."
+msgid "ClusterIntegration|Read our %{linkStart}help page%{linkEnd} on Kubernetes cluster integration."
msgstr ""
+msgid "ClusterIntegration|Read our %{link_start}help page%{link_end} on Kubernetes cluster integration."
+msgstr "Les vår %{link_start}hjelpeside%{link_end} om Kubernetes-klyngeintegrasjon."
+
msgid "ClusterIntegration|Real-time web application monitoring, logging and access control. %{linkStart}More information%{linkEnd}"
msgstr ""
msgid "ClusterIntegration|Region"
-msgstr ""
+msgstr "Region"
msgid "ClusterIntegration|Remove Kubernetes cluster integration"
-msgstr ""
+msgstr "Fjern Kubernetes-klyngeintegrasjon"
msgid "ClusterIntegration|Remove integration"
-msgstr ""
+msgstr "Fjern integrering"
msgid "ClusterIntegration|Remove integration and resources"
-msgstr ""
+msgstr "Fjern integrering og ressurser"
msgid "ClusterIntegration|Remove integration and resources?"
-msgstr ""
+msgstr "Fjern integrering og ressurser?"
msgid "ClusterIntegration|Remove integration?"
-msgstr ""
+msgstr "Fjern integrering?"
msgid "ClusterIntegration|Remove this Kubernetes cluster's configuration from this project. This will not delete your actual Kubernetes cluster."
msgstr ""
@@ -5793,109 +6013,109 @@ msgid "ClusterIntegration|Request to begin uninstalling failed"
msgstr ""
msgid "ClusterIntegration|SIEM Hostname"
-msgstr ""
+msgstr "SIEM-vertsnavn"
msgid "ClusterIntegration|SIEM Port"
-msgstr ""
+msgstr "SIEM-port"
msgid "ClusterIntegration|SIEM Protocol"
-msgstr ""
+msgstr "SIEM-protokoll"
msgid "ClusterIntegration|Save changes"
-msgstr ""
+msgstr "Lagre endringer"
msgid "ClusterIntegration|Search IAM Roles"
-msgstr ""
+msgstr "Søk blant IAM-roller"
msgid "ClusterIntegration|Search Key Pairs"
-msgstr ""
+msgstr "Søk blant nøkkelpar"
msgid "ClusterIntegration|Search VPCs"
-msgstr ""
+msgstr "Søk blant VPC-er"
msgid "ClusterIntegration|Search domains"
-msgstr ""
+msgstr "Søk blant domener"
msgid "ClusterIntegration|Search instance types"
-msgstr ""
+msgstr "Søk blant instanstyper"
msgid "ClusterIntegration|Search machine types"
-msgstr ""
+msgstr "Søk blant maskintyper"
msgid "ClusterIntegration|Search networks"
-msgstr ""
+msgstr "Søk blant nettverk"
msgid "ClusterIntegration|Search projects"
-msgstr ""
+msgstr "Søk blant prosjekter"
msgid "ClusterIntegration|Search regions"
-msgstr ""
+msgstr "Søk blant regioner"
msgid "ClusterIntegration|Search security groups"
-msgstr ""
+msgstr "Søk blant sikkerhetsgrupper"
msgid "ClusterIntegration|Search subnets"
-msgstr ""
+msgstr "Søk blant undernett"
msgid "ClusterIntegration|Search subnetworks"
-msgstr ""
+msgstr "Søk blant undernettverk"
msgid "ClusterIntegration|Search zones"
-msgstr ""
+msgstr "Søk blant soner"
msgid "ClusterIntegration|Security group"
-msgstr ""
+msgstr "Sikkerhetsgruppe"
msgid "ClusterIntegration|See and edit the details for your Kubernetes cluster"
msgstr ""
msgid "ClusterIntegration|Select a VPC to choose a security group"
-msgstr ""
+msgstr "Velg en VPC for å velge en sikkerhetsgruppe"
msgid "ClusterIntegration|Select a VPC to choose a subnet"
-msgstr ""
+msgstr "Velg en VPC for å velge et undernett"
-msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{linkStart}Amazon Web Services %{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select a network to choose a subnetwork"
-msgstr ""
+msgstr "Velg et nettverk for å velge et undernettverk"
msgid "ClusterIntegration|Select a region to choose a Key Pair"
-msgstr ""
+msgstr "Velg en region for å velge et nøkkelpar"
msgid "ClusterIntegration|Select a region to choose a VPC"
-msgstr ""
+msgstr "Velg en region for å velge et VPC"
msgid "ClusterIntegration|Select a stack to install Crossplane."
msgstr ""
msgid "ClusterIntegration|Select a zone to choose a network"
-msgstr ""
+msgstr "Velg en sone for å velge et nettverk"
msgid "ClusterIntegration|Select existing domain or use new"
-msgstr ""
+msgstr "Velg et eksisterende domene eller bruk et nytt et"
msgid "ClusterIntegration|Select machine type"
-msgstr ""
+msgstr "Velg maskintype"
msgid "ClusterIntegration|Select project"
-msgstr ""
+msgstr "Velg prosjekt"
msgid "ClusterIntegration|Select project and zone to choose machine type"
-msgstr ""
+msgstr "Velg prosjekt og sone for å velge maskintype"
msgid "ClusterIntegration|Select project to choose zone"
-msgstr ""
+msgstr "Velg prosjekt for å velge sone"
-msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select zone"
-msgstr ""
+msgstr "Velg sone"
msgid "ClusterIntegration|Select zone to choose machine type"
-msgstr ""
+msgstr "Velg sone for å velge maskintype"
msgid "ClusterIntegration|Send Container Network Policies Logs"
msgstr ""
@@ -5904,28 +6124,28 @@ msgid "ClusterIntegration|Send Web Application Firewall Logs"
msgstr ""
msgid "ClusterIntegration|Service Token"
-msgstr ""
+msgstr "Tjenestesjetong"
msgid "ClusterIntegration|Service role"
-msgstr ""
+msgstr "Tjenesterolle"
msgid "ClusterIntegration|Service token is required."
-msgstr ""
+msgstr "Tjenestesjetongen er påkrevd."
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 "Velg et prefiks for navneområdene dine. Hvis det ikke er angitt, brukes prosjektbanen din. Hvis det er endret, vil eksisterende miljøer bruke sine gjeldende navneområder frem til hurtigbufferen til klyngen er tømt."
msgid "ClusterIntegration|Set the global mode for the WAF in this cluster. This can be overridden at the environmental level."
msgstr ""
msgid "ClusterIntegration|Something went wrong on our end."
-msgstr ""
+msgstr "Noe gikk galt på vår side av linja."
msgid "ClusterIntegration|Something went wrong while creating your Kubernetes cluster"
-msgstr ""
+msgstr "Noe gikk galt under oppretting av din Kubernetes-klynge"
msgid "ClusterIntegration|Something went wrong while installing %{title}"
-msgstr ""
+msgstr "Noe gikk galt under installering av %{title}"
msgid "ClusterIntegration|Something went wrong while trying to save your settings. Please try again."
msgstr ""
@@ -5937,25 +6157,25 @@ msgid "ClusterIntegration|Something went wrong while updating Knative domain nam
msgstr ""
msgid "ClusterIntegration|Specifying a domain will allow you to use Auto Review Apps and Auto Deploy stages for %{linkStart}Auto DevOps.%{linkEnd} The domain should have a wildcard DNS configured matching the domain. "
-msgstr ""
+msgstr "Å spesifisere et domene vil la deg bruke auto-gjennomgangsapper og auto-distribusjonstrinn for %{linkStart}Auto DevOps.%{linkEnd} Domenet bør ha en jokertegn-DNS konfigurert som samsvarer med domenet. "
msgid "ClusterIntegration|Subnets"
-msgstr ""
+msgstr "Undernett"
msgid "ClusterIntegration|The %{gitlabNamespace} namespace"
-msgstr ""
+msgstr "%{gitlabNamespace}-navnefeltet"
msgid "ClusterIntegration|The Amazon Resource Name (ARN) associated with your role. If you do not have a provision role, first create one on %{startAwsLink}Amazon Web Services %{externalLinkIcon}%{endLink} using the above account and external IDs. %{startMoreInfoLink}More information%{endLink}"
-msgstr ""
+msgstr "Amazon-ressursnavnet (ARN) som er tilknyttet din rolle. Hvis du ikke har en klargjøringsrolle, må du først opprette en på %{startAwsLink}Amazon Web Services %{externalLinkIcon}%{endLink} ved hjelp av ovennevnte konto og eksterne IDer. %{startMoreInfoLink}Mer informasjon%{endLink}"
msgid "ClusterIntegration|The Kubernetes certificate used to authenticate to the cluster."
msgstr ""
msgid "ClusterIntegration|The URL used to access the Kubernetes API."
-msgstr ""
+msgstr "URL-en som brukes til å få tilgang til Kubernetes-API-en."
msgid "ClusterIntegration|The associated IP and all deployed services will be deleted and cannot be restored. Uninstalling Knative will also remove Istio from your cluster. This will not effect any other applications."
-msgstr ""
+msgstr "Den tilknyttede IP-en og alle distribuerte tjenester vil bli slettet og kan ikke bli gjenopprettet. Avinstallering av Knative fjerner også Istio fra klyngen din. Dette vil ikke påvirke andre programmer."
msgid "ClusterIntegration|The associated Tiller pod, the %{gitlabManagedAppsNamespace} namespace, and all of its resources will be deleted and cannot be restored."
msgstr ""
@@ -5978,59 +6198,80 @@ msgstr ""
msgid "ClusterIntegration|There was a problem authenticating with your cluster. Please ensure your CA Certificate and Token are valid."
msgstr ""
+msgid "ClusterIntegration|There was an HTTP error when connecting to your cluster."
+msgstr ""
+
msgid "ClusterIntegration|This account must have permissions to create a Kubernetes cluster in the %{link_to_container_project} specified below"
msgstr ""
-msgid "ClusterIntegration|This option will allow you to install applications on RBAC clusters."
+msgid "ClusterIntegration|This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
msgstr ""
-msgid "ClusterIntegration|This project does not have billing enabled. To create a cluster, %{linkToBillingStart}enable billing%{linkToBillingEnd} and try again."
+msgid "ClusterIntegration|This is necessary to clear existing environment-namespace associations from clusters previously managed by GitLab."
msgstr ""
+msgid "ClusterIntegration|This option will allow you to install applications on RBAC clusters."
+msgstr "Dette alternativet lar deg installere applikasjoner på RBAC-klynger."
+
+msgid "ClusterIntegration|This project does not have billing enabled. To create a cluster, %{linkToBillingStart}enable billing%{linkToBillingEnd} and try again."
+msgstr "Dette prosjektet har ikke fakturering aktivert. For å opprette en klynge, %{linkToBillingStart}skru på fakturering%{linkToBillingEnd} og prøv igjen."
+
msgid "ClusterIntegration|This will permanently delete the following resources:"
-msgstr ""
+msgstr "Dette vil permanent slette de følgende ressursene:"
msgid "ClusterIntegration|To access your application after deployment, point a wildcard DNS to the Knative Endpoint."
-msgstr ""
+msgstr "For å få tilgang til applikasjonen din etter distribusjon, peker du en jokertegn-DNS mot Knative-endepunktet."
msgid "ClusterIntegration|To create a cluster, first create a project on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}."
-msgstr ""
+msgstr "For å opprette en klynge, må du først opprette et prosjekt på %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}."
msgid "ClusterIntegration|To remove your integration and resources, type %{clusterName} to confirm:"
-msgstr ""
+msgstr "For å fjerne integrasjonen og ressursene dine, skriv %{clusterName} å bekrefte:"
msgid "ClusterIntegration|To remove your integration, type %{clusterName} to confirm:"
-msgstr ""
+msgstr "For å fjerne integrasjonen din, skriv %{clusterName} å bekrefte:"
msgid "ClusterIntegration|To use a new project, first create one on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}."
+msgstr "For å bruke et nytt prosjekt, må du først opprette et på %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}."
+
+msgid "ClusterIntegration|Troubleshooting tips:"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Authenticate"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Connect"
msgstr ""
msgid "ClusterIntegration|Uninstall %{appTitle}"
+msgstr "Avinstaller %{appTitle}"
+
+msgid "ClusterIntegration|Unknown Error"
msgstr ""
msgid "ClusterIntegration|Update %{appTitle}"
-msgstr ""
+msgstr "Oppdater %{appTitle}"
msgid "ClusterIntegration|Update failed. Please check the logs and try again."
-msgstr ""
+msgstr "Oppdatering mislyktes. Kontroller loggføringene og prøv på nytt."
msgid "ClusterIntegration|Use %{query}"
-msgstr ""
+msgstr "Bruk %{query}"
msgid "ClusterIntegration|Uses the Cloud Run, Istio, and HTTP Load Balancing addons for this cluster."
msgstr ""
msgid "ClusterIntegration|VPC"
-msgstr ""
+msgstr "VPC"
msgid "ClusterIntegration|Validating project billing status"
msgstr ""
msgid "ClusterIntegration|We could not verify that one of your projects on GCP has billing enabled. Please try again."
-msgstr ""
+msgstr "Vi kunne ikke bekrefte at et av prosjektene dine på GCP har aktivert fakturering. Vennligst prøv igjen."
msgid "ClusterIntegration|We were unable to fetch any projects. Ensure that you have a project on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}."
-msgstr ""
+msgstr "Vi kunne ikke innhente noen prosjekter. Forsikre deg om at du har et prosjekt på %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}."
msgid "ClusterIntegration|With a Kubernetes cluster associated to this project, you can use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr ""
@@ -6039,91 +6280,91 @@ msgid "ClusterIntegration|You are about to remove your cluster integration and a
msgstr ""
msgid "ClusterIntegration|You are about to remove your cluster integration."
-msgstr ""
+msgstr "Du er i ferd med å fjerne klyngeintegrasjonen din."
msgid "ClusterIntegration|You are about to uninstall %{appTitle} from your cluster."
-msgstr ""
+msgstr "Du er i ferd med å avinstallere %{appTitle} fra klyngen din."
msgid "ClusterIntegration|You are about to update %{appTitle} on your cluster."
-msgstr ""
+msgstr "Du er i ferd med å oppdatere %{appTitle} i klyngen din."
msgid "ClusterIntegration|You must grant access to your organization’s AWS resources in order to create a new EKS cluster. To grant access, create a provision role using the account and external ID below and provide us the ARN."
-msgstr ""
+msgstr "Du må gi tilgang til organisasjonens AWS-ressurser for å opprette en ny EKS-klynge. For å gi tilgang, opprett en klargjøringsrolle ved hjelp av kontoen og den ekstern ID-en nedenfor og gi oss ARN-en."
msgid "ClusterIntegration|You must have an RBAC-enabled cluster to install Knative."
msgstr ""
msgid "ClusterIntegration|You must specify a domain before you can install Knative."
-msgstr ""
+msgstr "Du må spesifisere et domene før du kan installere Knative."
msgid "ClusterIntegration|You should select at least two subnets"
-msgstr ""
+msgstr "Du burde velge minst to undernett"
msgid "ClusterIntegration|Your Elasticsearch cluster will be re-created during this upgrade. Your logs will be re-indexed, and you will lose historical logs from hosts terminated in the last 30 days."
msgstr ""
msgid "ClusterIntegration|Your account must have %{link_to_kubernetes_engine}"
-msgstr ""
+msgstr "Kontoen din må ha %{link_to_kubernetes_engine}"
msgid "ClusterIntegration|Your cluster API is unreachable. Please ensure your API URL is correct."
msgstr ""
-msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Zone"
-msgstr ""
+msgstr "Sone"
msgid "ClusterIntegration|access to Google Kubernetes Engine"
msgstr ""
msgid "ClusterIntegration|can be used instead of a custom domain. "
-msgstr ""
+msgstr "kan brukes i stedet for et tilpasset domene. "
msgid "ClusterIntegration|installed via %{linkStart}Cloud Run%{linkEnd}"
-msgstr ""
+msgstr "installert via %{linkStart}Cloud Run%{linkEnd}"
msgid "ClusterIntegration|meets the requirements"
-msgstr ""
+msgstr "oppfyller kravene"
msgid "ClusterIntegration|sign up"
msgstr ""
msgid "ClusterIntergation|Select a VPC"
-msgstr ""
+msgstr "Velg en VPC"
msgid "ClusterIntergation|Select a network"
-msgstr ""
+msgstr "Velg et nettverk"
msgid "ClusterIntergation|Select a region"
-msgstr ""
+msgstr "Velg en region"
msgid "ClusterIntergation|Select a security group"
-msgstr ""
+msgstr "Velg en sikkerhetsgruppe"
msgid "ClusterIntergation|Select a subnet"
-msgstr ""
+msgstr "Velg et undernett"
msgid "ClusterIntergation|Select a subnetwork"
-msgstr ""
+msgstr "Velg et undernettverk"
msgid "ClusterIntergation|Select an instance type"
-msgstr ""
+msgstr "Velg en instanstype"
msgid "ClusterIntergation|Select key pair"
-msgstr ""
+msgstr "Velg nøkkelpar"
msgid "ClusterIntergation|Select service role"
-msgstr ""
+msgstr "Velg tjenesterolle"
msgid "Clusters|An error occurred while loading clusters"
-msgstr ""
+msgstr "En feil oppstod under innlasting av klynger"
msgid "Code"
-msgstr ""
+msgstr "Kode"
msgid "Code Coverage: %{coveragePercentage}%{percentSymbol}"
-msgstr ""
+msgstr "Kodedekning: %{coveragePercentage}%{percentSymbol}"
msgid "Code Coverage| Empty code coverage data"
msgstr ""
@@ -6132,16 +6373,16 @@ msgid "Code Coverage|Couldn't fetch the code coverage data"
msgstr ""
msgid "Code Owners"
-msgstr ""
+msgstr "Kodeeiere"
msgid "Code Owners to the merge request changes."
msgstr ""
msgid "Code Quality"
-msgstr ""
+msgstr "Kodekvalitet"
msgid "Code Review"
-msgstr ""
+msgstr "Kodevurdering"
msgid "Code Review Analytics displays a table of open merge requests considered to be in code review. There are currently no merge requests in review for this project and/or filters."
msgstr ""
@@ -6150,94 +6391,97 @@ msgid "Code coverage statistics for master %{start_date} - %{end_date}"
msgstr ""
msgid "Code owner approval is required"
-msgstr ""
+msgstr "Kodeeiergodkjenning er påkrevd"
msgid "Code owners"
-msgstr ""
+msgstr "Kodeeiere"
msgid "CodeIntelligence|This is the definition"
-msgstr ""
+msgstr "Dette er definisjonen"
msgid "CodeNavigation|No references found"
-msgstr ""
+msgstr "Ingen referanser ble funnet"
msgid "CodeOwner|Pattern"
-msgstr ""
+msgstr "Mønster"
msgid "Cohorts"
-msgstr ""
+msgstr "Kohorter"
msgid "Cohorts|Inactive users"
-msgstr ""
+msgstr "Inaktive brukere"
msgid "Cohorts|Month %{month_index}"
-msgstr ""
+msgstr "MÃ¥ned %{month_index}"
msgid "Cohorts|New users"
-msgstr ""
+msgstr "Nye brukere"
msgid "Cohorts|Registration month"
-msgstr ""
+msgstr "Registreringsmåned"
msgid "Cohorts|Returning users"
-msgstr ""
+msgstr "Returnerende brukere"
msgid "Cohorts|User cohorts are shown for the last %{months_included} months. Only users with activity are counted in the 'New users' column; inactive users are counted separately."
-msgstr ""
+msgstr "Brukerkohorter vises for de siste %{months_included} månedene. Bare brukere med aktivitet telles med i kolonnen «Nye brukere»; inaktive brukere telles separat."
msgid "Collapse"
+msgstr "Folde sammen"
+
+msgid "Collapse all threads"
msgstr ""
msgid "Collapse approvers"
-msgstr ""
+msgstr "Slå sammen godkjennere"
msgid "Collapse milestones"
-msgstr ""
+msgstr "Klapp sammen milepæler"
msgid "Collapse replies"
-msgstr ""
+msgstr "Klapp sammen svar"
msgid "Collapse sidebar"
-msgstr ""
+msgstr "Fold sammen sidepanelet"
msgid "Collector hostname"
msgstr ""
msgid "ComboSearch is not defined"
-msgstr ""
+msgstr "ComboSearch er ikke definert"
msgid "Coming soon"
-msgstr ""
+msgstr "Kommer snart"
msgid "Comma-separated, e.g. '1.1.1.1, 2.2.2.0/24'"
-msgstr ""
+msgstr "Kommaseparert, f.eks. '1.1.1.1, 2.2.2.0/24'"
msgid "Command"
-msgstr ""
+msgstr "Kommando"
msgid "Command line instructions"
-msgstr ""
+msgstr "Ledetekstinstruksjoner"
msgid "Commands applied"
-msgstr ""
+msgstr "Kommandoer benyttet"
msgid "Commands did not apply"
msgstr ""
msgid "Comment"
-msgstr ""
+msgstr "Kommentar"
msgid "Comment & close %{noteable_name}"
-msgstr ""
+msgstr "Kommenter og lukk %{noteable_name}"
msgid "Comment & reopen %{noteable_name}"
msgstr ""
msgid "Comment & resolve thread"
-msgstr ""
+msgstr "Kommenter og oppklar tråden"
msgid "Comment & unresolve thread"
-msgstr ""
+msgstr "Kommenter og uoppklar tråden"
msgid "Comment '%{label}' position"
msgstr ""
@@ -6246,10 +6490,10 @@ msgid "Comment form position"
msgstr ""
msgid "Comment is being updated"
-msgstr ""
+msgstr "Kommentaren blir oppdatert"
msgid "Comment on lines %{startLine} to %{endLine}"
-msgstr ""
+msgstr "Kommenter på linjene fra %{startLine} til %{endLine}"
msgid "Comment/Reply (quoting selected text)"
msgstr ""
@@ -6261,30 +6505,30 @@ msgid "Commenting on symbolic links that replace or are replaced by files is cur
msgstr ""
msgid "Comments"
-msgstr ""
+msgstr "Kommentarer"
msgid "Commit"
msgid_plural "Commits"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "Commit"
+msgstr[1] "Commiter"
msgid "Commit %{commit_id}"
-msgstr ""
+msgstr "Commit %{commit_id}"
msgid "Commit (when editing commit message)"
-msgstr ""
+msgstr "Commit (under redigering av commit-meldingen)"
msgid "Commit Message"
-msgstr ""
+msgstr "Commit-beskjed"
msgid "Commit deleted"
-msgstr ""
+msgstr "Commiten ble slettet"
msgid "Commit message"
-msgstr ""
+msgstr "Commit-beskjed"
msgid "Commit message (optional)"
-msgstr ""
+msgstr "Commit-melding (valgfritt)"
msgid "Commit statistics for %{ref} %{start_time} - %{end_time}"
msgstr ""
@@ -6293,100 +6537,106 @@ msgid "Commit to %{branchName} branch"
msgstr ""
msgid "CommitBoxTitle|Commit"
-msgstr ""
+msgstr "Commit"
msgid "CommitMessage|Add %{file_name}"
-msgstr ""
+msgstr "Legg til %{file_name}"
msgid "CommitWidget|authored"
-msgstr ""
+msgstr "skapt"
msgid "Commits"
-msgstr ""
+msgstr "Commiter"
msgid "Commits feed"
-msgstr ""
+msgstr "Commit-strøm"
msgid "Commits per day hour (UTC)"
-msgstr ""
+msgstr "Commits per dagstime (UTC)"
msgid "Commits per day of month"
-msgstr ""
+msgstr "Commits per månedsdag"
msgid "Commits per weekday"
-msgstr ""
+msgstr "Commits per ukedag"
msgid "Commits to"
-msgstr ""
+msgstr "Commiter til"
msgid "Commits you select appear here. Go to the first tab and select commits to add to this merge request."
-msgstr ""
+msgstr "Commiter som du har valgt vises her. Gå til den første fanen og velg commiter å legge til i denne fletteforespørselen."
msgid "Commits|An error occurred while fetching merge requests data."
-msgstr ""
+msgstr "En feil oppstod under innhenting av fletteforespørselsdata."
msgid "Commits|History"
-msgstr ""
+msgstr "Historikk"
msgid "Commits|No related merge requests found"
-msgstr ""
+msgstr "Ingen relaterte fletteforespørsler ble funnet"
msgid "Committed by"
-msgstr ""
+msgstr "Loggført av"
msgid "Commit…"
-msgstr ""
+msgstr "Loggfør…"
-msgid "Company"
+msgid "Community forum"
msgstr ""
msgid "Company name"
-msgstr ""
+msgstr "Firmanavn"
msgid "Compare"
+msgstr "Sammenlign"
+
+msgid "Compare %{oldCommitId}...%{newCommitId}"
msgstr ""
msgid "Compare Git revisions"
-msgstr ""
+msgstr "Sammenlign Git-revisjoner"
msgid "Compare Revisions"
-msgstr ""
+msgstr "Sammenlign revisjoner"
msgid "Compare changes"
-msgstr ""
+msgstr "Sammenlign endringer"
msgid "Compare changes with the last commit"
-msgstr ""
+msgstr "Sammenlign endringer med den nyeste commiten"
msgid "Compare changes with the merge request target branch"
msgstr ""
-msgid "Compare with previous version"
+msgid "Compare submodule commit revisions"
msgstr ""
+msgid "Compare with previous version"
+msgstr "Sammenlign med forrige versjon"
+
msgid "CompareBranches|%{source_branch} and %{target_branch} are the same."
-msgstr ""
+msgstr "%{source_branch} og %{target_branch} er de samme."
msgid "CompareBranches|Compare"
-msgstr ""
+msgstr "Sammenlign"
msgid "CompareBranches|Source"
-msgstr ""
+msgstr "Kilde"
msgid "CompareBranches|Target"
-msgstr ""
+msgstr "MÃ¥l"
msgid "CompareBranches|There isn't anything to compare."
-msgstr ""
+msgstr "Det er ikke noe å sammenligne."
msgid "Complete"
-msgstr ""
+msgstr "Fullført"
msgid "Completed"
-msgstr ""
+msgstr "Fullført"
msgid "Compliance"
-msgstr ""
+msgstr "Overholdelse"
msgid "Compliance Dashboard"
msgstr ""
@@ -6398,85 +6648,85 @@ msgid "Compliance frameworks"
msgstr ""
msgid "ComplianceDashboard|created by:"
-msgstr ""
+msgstr "opprettet av:"
msgid "ComplianceFramework|GDPR"
-msgstr ""
+msgstr "GDPR"
msgid "ComplianceFramework|GDPR - General Data Protection Regulation"
-msgstr ""
+msgstr "GDPR - Personvernforordningen"
msgid "ComplianceFramework|HIPAA"
-msgstr ""
+msgstr "HIPAA"
msgid "ComplianceFramework|HIPAA - Health Insurance Portability and Accountability Act"
-msgstr ""
+msgstr "HIPAA - Health Insurance Portability and Accountability Act"
msgid "ComplianceFramework|PCI-DSS"
-msgstr ""
+msgstr "PCI-DSS"
msgid "ComplianceFramework|PCI-DSS - Payment Card Industry-Data Security Standard"
-msgstr ""
+msgstr "PCI-DSS - Payment Card Industry-Data Security Standard"
msgid "ComplianceFramework|SOC 2"
-msgstr ""
+msgstr "SOC 2"
msgid "ComplianceFramework|SOC 2 - Service Organization Control 2"
-msgstr ""
+msgstr "SOC 2 - Service Organization Control 2"
msgid "ComplianceFramework|SOX"
-msgstr ""
+msgstr "SOX"
msgid "ComplianceFramework|SOX - Sarbanes-Oxley"
-msgstr ""
+msgstr "SOX - Sarbanes-Oxley"
msgid "ComplianceFramework|This project is regulated by %{framework}."
-msgstr ""
+msgstr "Dette prosjektet er regulert av %{framework}."
msgid "Confidence"
-msgstr ""
+msgstr "Tillit"
msgid "Confidential"
-msgstr ""
+msgstr "Konfidensiell"
msgid "Confidentiality"
-msgstr ""
+msgstr "Konfidensialitet"
msgid "Configuration"
-msgstr ""
+msgstr "Konfigurasjon"
msgid "Configure GitLab runners to start using the Web Terminal. %{helpStart}Learn more.%{helpEnd}"
msgstr ""
msgid "Configure Gitaly timeouts."
-msgstr ""
+msgstr "Konfigurer Gitaly-tidsavbrudd."
msgid "Configure Let's Encrypt"
-msgstr ""
+msgstr "Sett opp Let's Encrypt"
msgid "Configure Prometheus"
-msgstr ""
+msgstr "Sett opp Prometheus"
msgid "Configure Tracing"
-msgstr ""
+msgstr "Konfigurer sporing"
msgid "Configure a %{codeStart}.gitlab-webide.yml%{codeEnd} file in the %{codeStart}.gitlab%{codeEnd} directory to start using the Web Terminal. %{helpStart}Learn more.%{helpEnd}"
-msgstr ""
+msgstr "Konfigurer en %{codeStart}.gitlab-webide.yml%{codeEnd}-fil i %{codeStart}.gitlab%{codeEnd}-mappen for å begynne å bruke netterminalen. %{helpStart}Lær mer.%{helpEnd}"
msgid "Configure automatic git checks and housekeeping on repositories."
msgstr ""
msgid "Configure existing installation"
-msgstr ""
+msgstr "Sett opp eksisterende installasjon"
msgid "Configure limit for issues created per minute by web and API requests."
-msgstr ""
+msgstr "Konfigurer grensen for saker opprettet per minutt av nett- og API-forespørsler."
msgid "Configure limits for Project/Group Import/Export."
msgstr ""
msgid "Configure limits for web and API requests."
-msgstr ""
+msgstr "Konfigurer grenser for nett- og API-forespørsler."
msgid "Configure limits on the number of inbound alerts able to be sent to a project."
msgstr ""
@@ -6485,28 +6735,31 @@ msgid "Configure paths to be protected by Rack Attack."
msgstr ""
msgid "Configure repository mirroring."
-msgstr ""
+msgstr "Sett opp kodelagerspeiling."
msgid "Configure storage path settings."
-msgstr ""
+msgstr "Sett opp lagringsfilbaneinnstillinger."
msgid "Configure the %{link} integration."
-msgstr ""
+msgstr "Konfigurer %{link}-integrasjonen."
msgid "Configure the way a user creates a new account."
msgstr ""
-msgid "Confirm"
+msgid "Configure which lists are shown for anyone who visits this board"
msgstr ""
+msgid "Confirm"
+msgstr "Bekreft"
+
msgid "Confirmation email sent to %{email}"
-msgstr ""
+msgstr "Bekreftelses-e-post ble sendt til %{email}"
msgid "Confirmation required"
-msgstr ""
+msgstr "Bekreftelse påkrevd"
msgid "Confluence"
-msgstr ""
+msgstr "Confluence"
msgid "ConfluenceService|Confluence Workspace"
msgstr ""
@@ -6527,52 +6780,52 @@ msgid "Congratulations! You have enabled Two-factor Authentication!"
msgstr ""
msgid "Connect"
-msgstr ""
+msgstr "Koble til"
msgid "Connect all repositories"
-msgstr ""
+msgstr "Koble til alle kodelagerene"
msgid "Connect repositories from GitHub"
-msgstr ""
+msgstr "Koble til kodelagre fra GitHub"
msgid "Connect your external repositories, and CI/CD pipelines will run for new commits. A GitLab project will be created with only CI/CD features enabled."
-msgstr ""
+msgstr "Koble til dine eksterne kodelagre og CI/CD-rørledninger vil kjøre for nye commiter. Et GitLab-prosjekt vil bli opprettet med kun CI/CD-funksjoner aktivert."
msgid "Connected"
-msgstr ""
+msgstr "Tilkoblet"
msgid "Connecting"
-msgstr ""
+msgstr "Tilkobler"
msgid "Connecting to terminal sync service"
msgstr ""
msgid "Connecting..."
-msgstr ""
+msgstr "Kobler til..."
msgid "Connection failed"
-msgstr ""
+msgstr "Tilkobling mislyktes"
msgid "Connection failure"
-msgstr ""
+msgstr "Feil ved tilkobling"
msgid "Connection timed out"
-msgstr ""
+msgstr "Tilkoblingen ble tidsavbrutt"
msgid "Connection timeout"
-msgstr ""
+msgstr "Tidsavbrudd på tilkobling"
msgid "Contact sales to upgrade"
-msgstr ""
+msgstr "Kontakt salgsavdelingen for å oppgradere"
msgid "Contact support"
-msgstr ""
+msgstr "Kontakt kundestøtte"
msgid "Container Registry"
-msgstr ""
+msgstr "Container-register"
msgid "Container Scanning"
-msgstr ""
+msgstr "Containerskanning"
msgid "Container does not exist"
msgstr ""
@@ -6584,29 +6837,29 @@ msgid "Container registry is not enabled on this GitLab instance. Ask an adminis
msgstr ""
msgid "Container repositories"
-msgstr ""
+msgstr "Container-kodelagre"
msgid "Container repositories sync capacity"
msgstr ""
msgid "Container repository"
-msgstr ""
+msgstr "Container-kodelager"
msgid "ContainerRegistry| Please visit the %{linkStart}administration settings%{linkEnd} to enable this feature."
msgstr ""
msgid "ContainerRegistry|%{count} Image repository"
msgid_plural "ContainerRegistry|%{count} Image repositories"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%{count} Bildekodelager"
+msgstr[1] "%{count} Bildekodelagre"
msgid "ContainerRegistry|%{count} Tag"
msgid_plural "ContainerRegistry|%{count} Tags"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%{count} etikett"
+msgstr[1] "%{count} etiketter"
msgid "ContainerRegistry|%{imageName} tags"
-msgstr ""
+msgstr "%{imageName} etiketter"
msgid "ContainerRegistry|%{title} was successfully scheduled for deletion"
msgstr ""
@@ -6618,7 +6871,7 @@ msgid "ContainerRegistry|Build an image"
msgstr ""
msgid "ContainerRegistry|CLI Commands"
-msgstr ""
+msgstr "CLI-kommandoer"
msgid "ContainerRegistry|Cleanup policy for tags is disabled"
msgstr ""
@@ -6639,19 +6892,19 @@ msgid "ContainerRegistry|Copy build command"
msgstr ""
msgid "ContainerRegistry|Copy login command"
-msgstr ""
+msgstr "Kopier innloggingskommando"
msgid "ContainerRegistry|Copy push command"
-msgstr ""
+msgstr "Kopier pushkommando"
msgid "ContainerRegistry|Delete selected"
-msgstr ""
+msgstr "Slett valgt"
msgid "ContainerRegistry|Deletion disabled due to missing or insufficient permissions."
msgstr ""
msgid "ContainerRegistry|Digest: %{imageId}"
-msgstr ""
+msgstr "Sammendrag: %{imageId}"
msgid "ContainerRegistry|Docker connection error"
msgstr ""
@@ -6660,7 +6913,7 @@ msgid "ContainerRegistry|Expiration interval:"
msgstr ""
msgid "ContainerRegistry|Expiration policies help manage the storage space used by the Container Registry, but the expiration policies for this registry are disabled. Contact your administrator to enable. %{docLinkStart}More information%{docLinkEnd}"
-msgstr ""
+msgstr "Utløpsretningslinjer hjelper deg med å administrere lagringsplassen som brukes av container-registeret, men utløpsretningslinjene for dette registeret er deaktivert. Kontakt administratoren din for å aktivere. %{docLinkStart}Mer informasjon%{docLinkEnd}"
msgid "ContainerRegistry|Expiration policy is disabled"
msgstr ""
@@ -6672,22 +6925,22 @@ msgid "ContainerRegistry|Expiration schedule:"
msgstr ""
msgid "ContainerRegistry|Filter by name"
-msgstr ""
+msgstr "Filtrer etter navn"
msgid "ContainerRegistry|If you are not already logged in, you need to authenticate to the Container Registry by using your GitLab username and password. If you have %{twofaDocLinkStart}Two-Factor Authentication%{twofaDocLinkEnd} enabled, use a %{personalAccessTokensDocLinkStart}Personal Access Token%{personalAccessTokensDocLinkEnd} instead of a password."
-msgstr ""
+msgstr "Hvis du ikke allerede er logget inn, må du autentisere deg til container-registeret ved å bruke ditt GitLab-brukernavn og -passord. Hvis du har %{twofaDocLinkStart}2-trinnsautentisering%{twofaDocLinkEnd} aktivert, kan du bruke en %{personalAccessTokensDocLinkStart}personlig tilgangssjetong%{personalAccessTokensDocLinkEnd} i stedet for et passord."
msgid "ContainerRegistry|Image Repositories"
-msgstr ""
+msgstr "Bildekodelagre"
msgid "ContainerRegistry|Image tags"
-msgstr ""
+msgstr "Bilde-etiketter"
msgid "ContainerRegistry|Invalid tag: missing manifest digest"
msgstr ""
msgid "ContainerRegistry|Login"
-msgstr ""
+msgstr "Innlogging"
msgid "ContainerRegistry|Manifest digest: %{digest}"
msgstr ""
@@ -6696,45 +6949,48 @@ msgid "ContainerRegistry|Missing or insufficient permission, delete button disab
msgstr ""
msgid "ContainerRegistry|Number of tags to retain:"
-msgstr ""
+msgstr "Antall etiketter å beholde:"
msgid "ContainerRegistry|Published %{timeInfo}"
-msgstr ""
+msgstr "Publisert den %{timeInfo}"
msgid "ContainerRegistry|Published to the %{repositoryPath} image repository at %{time} on %{date}"
msgstr ""
msgid "ContainerRegistry|Push an image"
-msgstr ""
+msgstr "Push et bilde"
msgid "ContainerRegistry|Remember to run %{docLinkStart}garbage collection%{docLinkEnd} to remove the stale data from storage."
msgstr ""
msgid "ContainerRegistry|Remove repository"
-msgstr ""
+msgstr "Fjern kodelageret"
msgid "ContainerRegistry|Remove tag"
msgid_plural "ContainerRegistry|Remove tags"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "Fjern etikett"
+msgstr[1] "Fjern etiketter"
msgid "ContainerRegistry|Set cleanup policy"
msgstr ""
-msgid "ContainerRegistry|Something went wrong while fetching the cleanup policy."
+msgid "ContainerRegistry|Some tags were not deleted"
msgstr ""
+msgid "ContainerRegistry|Something went wrong while fetching the cleanup policy."
+msgstr "Noe gikk galt under innhenting av opprydningsretningslinjen."
+
msgid "ContainerRegistry|Something went wrong while fetching the repository list."
-msgstr ""
+msgstr "Noe gikk galt under innhenting av kodelagerlisten."
msgid "ContainerRegistry|Something went wrong while fetching the tags list."
-msgstr ""
+msgstr "Noe gikk galt under innhenting av etikettlisten."
msgid "ContainerRegistry|Something went wrong while marking the tag for deletion."
-msgstr ""
+msgstr "Noe gikk galt under markering av etiketten for sletting."
msgid "ContainerRegistry|Something went wrong while marking the tags for deletion."
-msgstr ""
+msgstr "Noe gikk galt under markering av etikettene for sletting."
msgid "ContainerRegistry|Something went wrong while scheduling %{title} for deletion. Please try again."
msgstr ""
@@ -6743,16 +6999,16 @@ msgid "ContainerRegistry|Something went wrong while updating the cleanup policy.
msgstr ""
msgid "ContainerRegistry|Sorry, your filter produced no results."
-msgstr ""
+msgstr "Beklager, filteret ditt ga ingen resultater."
msgid "ContainerRegistry|Tag expiration policy"
msgstr ""
msgid "ContainerRegistry|Tag successfully marked for deletion."
-msgstr ""
+msgstr "Etiketten ble vellykket merket for sletting."
msgid "ContainerRegistry|Tags successfully marked for deletion."
-msgstr ""
+msgstr "Etikettene ble vellykket merket for sletting."
msgid "ContainerRegistry|Tags with names matching this regex pattern will %{italicStart}be preserved:%{italicEnd}"
msgstr ""
@@ -6760,11 +7016,14 @@ msgstr ""
msgid "ContainerRegistry|Tags with names matching this regex pattern will %{italicStart}expire:%{italicEnd}"
msgstr ""
-msgid "ContainerRegistry|The last tag related to this image was recently removed. This empty image and any associated data will be automatically removed as part of the regular Garbage Collection process. If you have any questions, contact your administrator."
+msgid "ContainerRegistry|The cleanup policy timed out before it could delete all tags. An administrator can %{adminLinkStart}manually run cleanup now%{adminLinkEnd} or you can wait for the cleanup policy to automatically run again. %{docLinkStart}More information%{docLinkEnd}"
msgstr ""
+msgid "ContainerRegistry|The last tag related to this image was recently removed. This empty image and any associated data will be automatically removed as part of the regular Garbage Collection process. If you have any questions, contact your administrator."
+msgstr "Den siste etiketten som var relatert til dette bildet ble nylig fjernet. Dette tomme bildet og eventuelle tilknyttede data blir automatisk fjernet som en del av den vanlige søppeloppsamlingsprosessen. Kontakt administratoren din hvis du har spørsmål."
+
msgid "ContainerRegistry|The value of this input should be less than 256 characters"
-msgstr ""
+msgstr "Verdien til denne inndataen skal være mindre enn 256 tegn"
msgid "ContainerRegistry|There are no container images available in this group"
msgstr ""
@@ -6776,7 +7035,7 @@ msgid "ContainerRegistry|There was an error during the deletion of this image re
msgstr ""
msgid "ContainerRegistry|This image has no active tags"
-msgstr ""
+msgstr "Dette bildet har ingen aktive etiketter"
msgid "ContainerRegistry|This image repository is scheduled for deletion"
msgstr ""
@@ -6785,13 +7044,13 @@ msgid "ContainerRegistry|This project's cleanup policy for tags is not enabled."
msgstr ""
msgid "ContainerRegistry|To widen your search, change or remove the filters above."
-msgstr ""
+msgstr "For å utvide søket, endre eller fjerne filtrene ovenfor."
msgid "ContainerRegistry|We are having trouble connecting to the Registry, which could be due to an issue with your project name or path. %{docLinkStart}More information%{docLinkEnd}"
msgstr ""
msgid "ContainerRegistry|Wildcards such as %{codeStart}.*-master%{codeEnd} or %{codeStart}release-.*%{codeEnd} are supported"
-msgstr ""
+msgstr "Jokertegn som %{codeStart}*-master%{codeEnd} eller %{codeStart}release-.*%{codeEnd} er støttet"
msgid "ContainerRegistry|Wildcards such as %{codeStart}.*-test%{codeEnd} or %{codeStart}dev-.*%{codeEnd} are supported. To select all tags, use %{codeStart}.*%{codeEnd}"
msgstr ""
@@ -6800,16 +7059,16 @@ msgid "ContainerRegistry|With the Container Registry, every project can have its
msgstr ""
msgid "ContainerRegistry|With the Container Registry, every project can have its own space to store its Docker images. Push at least one Docker image in one of this group's projects in order to show up here. %{docLinkStart}More Information%{docLinkEnd}"
-msgstr ""
+msgstr "Med container-registeret kan hvert prosjekt ha sin egen plass til å lagre sine Docker-bilder. Push minst ett Docker-bilde i et av gruppens prosjekter for at den skal dukke opp her. %{docLinkStart}Mer informasjon%{docLinkEnd}"
msgid "ContainerRegistry|With the GitLab Container Registry, every project can have its own space to store images. %{docLinkStart}More information%{docLinkEnd}"
msgstr ""
msgid "ContainerRegistry|You are about to remove %{item} tags. Are you sure?"
-msgstr ""
+msgstr "Du er i ferd med å fjerne %{item} etiketter. Er du sikker?"
msgid "ContainerRegistry|You are about to remove %{item}. Are you sure?"
-msgstr ""
+msgstr "Du er i ferd med å fjerne %{item}. Er du sikker?"
msgid "ContainerRegistry|You are about to remove repository %{title}. Once you confirm, this repository will be permanently deleted."
msgstr ""
@@ -6821,61 +7080,61 @@ msgid "Contains %{count} blobs of images (%{size})"
msgstr ""
msgid "Contents of .gitlab-ci.yml"
-msgstr ""
+msgstr "Innholdet i .gitlab-ci.yml"
msgid "ContextCommits|Failed to create context commits. Please try again."
-msgstr ""
+msgstr "Kunne ikke opprette sammenhengscommiter. Vennligst prøv igjen."
msgid "ContextCommits|Failed to create/remove context commits. Please try again."
-msgstr ""
+msgstr "Mislyktes i å opprette/fjerne sammenhengscommiter. Vennligst prøv igjen."
msgid "ContextCommits|Failed to delete context commits. Please try again."
-msgstr ""
+msgstr "Mislyktes i å slette sammenhengscommiter. Vennligst prøv igjen."
msgid "Continue"
-msgstr ""
+msgstr "Fortsett"
msgid "Continue to the next step"
-msgstr ""
+msgstr "Fortsett til neste trinn"
msgid "Continuous Integration and Deployment"
msgstr ""
msgid "Contribute to GitLab"
-msgstr ""
+msgstr "Bidra til GitLab"
msgid "Contribution"
-msgstr ""
+msgstr "Bidrag"
msgid "Contribution Analytics"
-msgstr ""
+msgstr "Bidragsanalyse"
msgid "ContributionAnalytics|%{created_count} created, %{closed_count} closed."
-msgstr ""
+msgstr "%{created_count} opprettet, %{closed_count} lukket."
msgid "ContributionAnalytics|%{created_count} created, %{merged_count} merged."
-msgstr ""
+msgstr "%{created_count} opprettet, %{merged_count} innflettet."
msgid "ContributionAnalytics|%{pushes} pushes, more than %{commits} commits by %{people} contributors."
-msgstr ""
+msgstr "%{pushes} pushinger, mer enn %{commits} commiter fra %{people} bidragsytere."
msgid "ContributionAnalytics|Contribution analytics for issues, merge requests and push events since %{start_date}"
msgstr ""
msgid "ContributionAnalytics|Issues"
-msgstr ""
+msgstr "Saker"
msgid "ContributionAnalytics|Last 3 months"
-msgstr ""
+msgstr "Seneste 3 måneder"
msgid "ContributionAnalytics|Last month"
-msgstr ""
+msgstr "Forrige måned"
msgid "ContributionAnalytics|Last week"
-msgstr ""
+msgstr "Forrige uke"
msgid "ContributionAnalytics|Merge Requests"
-msgstr ""
+msgstr "Fletteforespørsler"
msgid "ContributionAnalytics|No issues for the selected time period."
msgstr ""
@@ -6887,13 +7146,16 @@ msgid "ContributionAnalytics|No pushes for the selected time period."
msgstr ""
msgid "Contributions for %{calendar_date}"
-msgstr ""
+msgstr "Bidrag på %{calendar_date}"
msgid "Contributions per group member"
+msgstr "Bidrag per gruppemedlem"
+
+msgid "Contributor"
msgstr ""
msgid "Contributors"
-msgstr ""
+msgstr "Bidragsytere"
msgid "Control emails linked to your account"
msgstr ""
@@ -6902,76 +7164,76 @@ msgid "Control the display of third party offers."
msgstr ""
msgid "Cookie domain"
-msgstr ""
+msgstr "Infokapseldomene"
msgid "Copied"
-msgstr ""
+msgstr "Kopiert"
msgid "Copied labels and milestone from %{source_issuable_reference}."
msgstr ""
msgid "Copy"
-msgstr ""
+msgstr "Kopier"
msgid "Copy %{http_label} clone URL"
-msgstr ""
+msgstr "Kopier %{http_label}-klone-URL"
msgid "Copy %{protocol} clone URL"
-msgstr ""
+msgstr "Kopier %{protocol}-klone-URL"
msgid "Copy %{proxy_url}"
-msgstr ""
+msgstr "Kopier %{proxy_url}"
msgid "Copy %{type}"
-msgstr ""
+msgstr "Kopier %{type}"
msgid "Copy Account ID to clipboard"
-msgstr ""
+msgstr "Kopier konto-ID til utklippstavlen"
msgid "Copy External ID to clipboard"
-msgstr ""
+msgstr "Kopier ekstern ID til utklippstavlen"
msgid "Copy ID"
-msgstr ""
+msgstr "Kopier ID"
msgid "Copy KRB5 clone URL"
-msgstr ""
+msgstr "Kopier KRB5-klone-URL"
msgid "Copy SSH clone URL"
-msgstr ""
+msgstr "Kopier SSH-klone-URL"
msgid "Copy SSH public key"
-msgstr ""
+msgstr "Kopier offentlig SSH-nøkkel"
msgid "Copy URL"
-msgstr ""
+msgstr "Kopier nettadresse"
msgid "Copy branch name"
-msgstr ""
+msgstr "Kopier gren-navn"
msgid "Copy command"
-msgstr ""
+msgstr "Kopier kommando"
msgid "Copy commands"
-msgstr ""
+msgstr "Kopier kommandoer"
msgid "Copy commit SHA"
-msgstr ""
+msgstr "Kopier commit-SHA-en"
msgid "Copy environment"
-msgstr ""
+msgstr "Kopier miljø"
msgid "Copy evidence SHA"
-msgstr ""
+msgstr "Kopier bevis-SHA"
msgid "Copy file contents"
-msgstr ""
+msgstr "Kopier filinnhold"
msgid "Copy file path"
-msgstr ""
+msgstr "Kopier filbanen"
msgid "Copy key"
-msgstr ""
+msgstr "Kopier nøkkel"
msgid "Copy labels and milestone from %{source_issuable_reference}."
msgstr ""
@@ -6980,16 +7242,16 @@ msgid "Copy labels and milestone from other issue or merge request in this proje
msgstr ""
msgid "Copy link"
-msgstr ""
+msgstr "Kopier lenke"
msgid "Copy link to chart"
-msgstr ""
+msgstr "Kopier lenke til diagram"
msgid "Copy reference"
-msgstr ""
+msgstr "Kopier referanse"
msgid "Copy secret"
-msgstr ""
+msgstr "Kopier hemmelighet"
msgid "Copy source branch name"
msgstr ""
@@ -6998,29 +7260,32 @@ msgid "Copy the code below to implement tracking in your application:"
msgstr ""
msgid "Copy to clipboard"
-msgstr ""
+msgstr "Kopier til utklippstavle"
msgid "Copy token"
-msgstr ""
+msgstr "Kopier sjetong"
msgid "Copy trigger token"
msgstr ""
msgid "Copy value"
-msgstr ""
+msgstr "Kopier verdi"
msgid "Could not add admins as members"
msgstr ""
msgid "Could not archive %{design}. Please try again."
-msgstr ""
+msgstr "Klarte ikke å arkivere %{design}. Vennligst prøv igjen."
msgid "Could not authorize chat nickname. Try again!"
-msgstr ""
+msgstr "Klarte ikke å autorisere chat-kallenavnet. Prøv igjen!"
msgid "Could not change HEAD: branch '%{branch}' does not exist"
msgstr ""
+msgid "Could not commit. An unexpected error occurred."
+msgstr ""
+
msgid "Could not connect to FogBugz, check your URL"
msgstr ""
@@ -7034,37 +7299,40 @@ msgid "Could not create Wiki Repository at this time. Please try again later."
msgstr ""
msgid "Could not create environment"
-msgstr ""
+msgstr "Kunne ikke opprette miljø"
msgid "Could not create group"
-msgstr ""
+msgstr "Kunne ikke opprette gruppe"
msgid "Could not create issue"
-msgstr ""
+msgstr "Klarte ikke å opprette saker"
msgid "Could not create project"
-msgstr ""
+msgstr "Kunne ikke opprette prosjekt"
msgid "Could not create wiki page"
-msgstr ""
+msgstr "Klarte ikke å opprette wiki-side"
msgid "Could not delete chat nickname %{chat_name}."
-msgstr ""
+msgstr "Klarte ikke å slette chat-kallenavnet %{chat_name}."
msgid "Could not delete wiki page"
-msgstr ""
+msgstr "Klarte ikke å slette wiki-side"
msgid "Could not find design."
-msgstr ""
+msgstr "Klarte ikke å finne designet."
msgid "Could not find iteration"
msgstr ""
-msgid "Could not remove the trigger."
+msgid "Could not load instance counts. Please refresh the page to try again."
msgstr ""
+msgid "Could not remove the trigger."
+msgstr "Klarte ikke å fjerne trigger."
+
msgid "Could not restore the group"
-msgstr ""
+msgstr "Klarte ikke å gjenopprette gruppen"
msgid "Could not revoke impersonation token %{token_name}."
msgstr ""
@@ -7076,28 +7344,28 @@ msgid "Could not revoke project access token %{project_access_token_name}."
msgstr ""
msgid "Could not save group ID"
-msgstr ""
+msgstr "Klarte ikke å lagre gruppe-ID"
msgid "Could not save project ID"
-msgstr ""
+msgstr "Klarte ikke å lagre prosjekt-ID"
msgid "Could not save prometheus manual configuration"
msgstr ""
-msgid "Could not udpdate wiki page"
-msgstr ""
-
msgid "Could not update the LDAP settings"
+msgstr "Klarte ikke å oppdatere LDAP-innstillingene"
+
+msgid "Could not update wiki page"
msgstr ""
msgid "Could not upload your designs as one or more files uploaded are not supported."
msgstr ""
msgid "Country"
-msgstr ""
+msgstr "Land"
msgid "Coverage"
-msgstr ""
+msgstr "Dekning"
msgid "Coverage Fuzzing"
msgstr ""
@@ -7108,52 +7376,52 @@ msgstr[0] ""
msgstr[1] ""
msgid "Create"
-msgstr ""
+msgstr "Opprett"
msgid "Create %{environment}"
-msgstr ""
+msgstr "Opprett %{environment}"
msgid "Create %{type}"
-msgstr ""
+msgstr "Opprett %{type}"
msgid "Create New Directory"
-msgstr ""
+msgstr "Opprett ny katalog"
msgid "Create New Domain"
-msgstr ""
+msgstr "Opprett nytt domene"
msgid "Create Project"
-msgstr ""
+msgstr "Opprett prosjekt"
msgid "Create Value Stream"
-msgstr ""
+msgstr "Opprett verdistørm"
msgid "Create a GitLab account first, and then connect it to your %{label} account."
msgstr ""
msgid "Create a Mattermost team for this group"
-msgstr ""
+msgstr "Opprett et Mattermost-team for denne gruppen"
msgid "Create a local proxy for storing frequently used upstream images. %{link_start}Learn more%{link_end} about dependency proxies."
msgstr ""
msgid "Create a merge request"
-msgstr ""
+msgstr "Opprett en fletteforespørsel"
msgid "Create a new branch"
-msgstr ""
+msgstr "Opprette en ny gren"
msgid "Create a new deploy key for this project"
msgstr ""
msgid "Create a new file as there are no files yet. Afterwards, you'll be able to commit your changes."
-msgstr ""
+msgstr "Opprett en ny fil siden det ikke er noen filer ennå. Etterpå vil du kunne utføre endringene dine."
msgid "Create a new issue"
-msgstr ""
+msgstr "Opprett et nytt problem"
msgid "Create a new repository"
-msgstr ""
+msgstr "Opprett et nytt kodelager"
msgid "Create a personal access token on your account to pull or push via %{protocol}."
msgstr ""
@@ -7162,22 +7430,22 @@ msgid "Create a project pre-populated with the necessary files to get you starte
msgstr ""
msgid "Create an account using:"
-msgstr ""
+msgstr "Lag en konto med:"
msgid "Create an issue. Issues are created for each alert triggered."
msgstr ""
msgid "Create and provide your GitHub %{link_start}Personal Access Token%{link_end}. You will need to select the %{code_open}repo%{code_close} scope, so we can display a list of your public and private repositories which are available to import."
-msgstr ""
+msgstr "Koble til og lever din %{link_start}personlige GitHub-tilgangssjetong%{link_end}. Du vil måtte velge %{code_open}kodelager%{code_close}-omfanget, så vi kan vise en liste over dine offentlige og private kodelagre som er tilgjengelige for å importere."
msgid "Create board"
msgstr ""
msgid "Create branch"
-msgstr ""
+msgstr "Opprett gren"
msgid "Create commit"
-msgstr ""
+msgstr "Opprett en commit"
msgid "Create confidential merge request"
msgstr ""
@@ -7186,28 +7454,28 @@ msgid "Create confidential merge request and branch"
msgstr ""
msgid "Create directory"
-msgstr ""
+msgstr "Lag mappe"
msgid "Create empty repository"
-msgstr ""
+msgstr "Opprett et tomt kodelager"
msgid "Create epic"
-msgstr ""
+msgstr "Opprett epos"
msgid "Create file"
-msgstr ""
+msgstr "Lag en fil"
msgid "Create from"
-msgstr ""
+msgstr "Opprett fra"
msgid "Create group"
-msgstr ""
+msgstr "Opprett gruppe"
msgid "Create group label"
-msgstr ""
+msgstr "Opprett gruppe-stempel"
msgid "Create issue"
-msgstr ""
+msgstr "Lag en rapport"
msgid "Create iteration"
msgstr ""
@@ -7216,97 +7484,97 @@ msgid "Create lists from labels. Issues with that label appear in that list."
msgstr ""
msgid "Create merge request"
-msgstr ""
+msgstr "Lag en fletteforespørsel"
msgid "Create merge request and branch"
-msgstr ""
+msgstr "Opprett fletteforespørsel og gren"
msgid "Create milestone"
-msgstr ""
+msgstr "Opprett milepæl"
msgid "Create new"
-msgstr ""
+msgstr "Opprett ny"
msgid "Create new Value Stream"
msgstr ""
msgid "Create new board"
-msgstr ""
+msgstr "Opprett ny tavle"
msgid "Create new branch"
-msgstr ""
+msgstr "Opprett ny gren"
msgid "Create new confidential %{issuableType}"
msgstr ""
msgid "Create new directory"
-msgstr ""
+msgstr "Lag en ny mappe"
msgid "Create new file"
-msgstr ""
+msgstr "Lag en ny fil"
msgid "Create new file or directory"
-msgstr ""
+msgstr "Opprett ny fil eller katalog"
msgid "Create new issue in Jira"
-msgstr ""
+msgstr "Opprett ny sak i Jira"
msgid "Create new label"
-msgstr ""
+msgstr "Opprett ny stempel"
msgid "Create new..."
-msgstr ""
+msgstr "Opprett ny..."
msgid "Create project"
-msgstr ""
+msgstr "Opprett prosjekt"
msgid "Create project label"
-msgstr ""
+msgstr "Opprett prosjektstempel"
msgid "Create release"
-msgstr ""
+msgstr "Opprett utgivelse"
msgid "Create requirement"
-msgstr ""
+msgstr "Opprett krav"
msgid "Create snippet"
-msgstr ""
+msgstr "Opprett utdrag"
msgid "Create wildcard: %{searchTerm}"
-msgstr ""
+msgstr "Opprett jokertegn: %{searchTerm}"
msgid "Create your first page"
-msgstr ""
+msgstr "Opprett din første side"
msgid "Create your group"
-msgstr ""
+msgstr "Opprett gruppen din"
msgid "Create/import your first project"
-msgstr ""
+msgstr "Opprett/importer ditt første prosjekt"
msgid "CreateGroup|You don’t have permission to create a subgroup in this group."
-msgstr ""
+msgstr "Du har ikke tillatelse til å opprette en undergruppe i denne gruppen."
msgid "CreateGroup|You don’t have permission to create groups."
-msgstr ""
+msgstr "Du har ikke tillatelse til å opprette grupper."
msgid "CreateTag|Tag"
-msgstr ""
+msgstr "Etikett"
msgid "CreateTokenToCloneLink|create a personal access token"
msgstr ""
msgid "Created"
-msgstr ""
+msgstr "Opprettet"
msgid "Created %{timestamp}"
-msgstr ""
+msgstr "Opprettet %{timestamp}"
msgid "Created At"
-msgstr ""
+msgstr "Opprettet den"
msgid "Created On"
-msgstr ""
+msgstr "Opprettet den"
msgid "Created a branch and a merge request to resolve this issue."
msgstr ""
@@ -7315,34 +7583,34 @@ msgid "Created branch '%{branch_name}' and a merge request to resolve this issue
msgstr ""
msgid "Created by %{job}"
-msgstr ""
+msgstr "Laget av %{job}"
msgid "Created by me"
-msgstr ""
+msgstr "Opprettet av meg"
msgid "Created by:"
-msgstr ""
+msgstr "Laget av:"
msgid "Created date"
-msgstr ""
+msgstr "Opprettelsesdato"
msgid "Created issue %{issueLink}"
-msgstr ""
+msgstr "Opprettet saken %{issueLink}"
msgid "Created issue %{issueLink} at %{projectLink}"
-msgstr ""
+msgstr "Opprettet saken %{issueLink} hos %{projectLink}"
msgid "Created merge request %{mergeRequestLink}"
-msgstr ""
+msgstr "Opprettet fletteforespørselen %{mergeRequestLink}"
msgid "Created merge request %{mergeRequestLink} at %{projectLink}"
-msgstr ""
+msgstr "Opprettet fletteforespørselen %{mergeRequestLink} hos %{projectLink}"
msgid "Created on"
-msgstr ""
+msgstr "Opprettet den"
msgid "Created on:"
-msgstr ""
+msgstr "Opprettet den:"
msgid "Creates a branch and a merge request to resolve this issue."
msgstr ""
@@ -7351,19 +7619,19 @@ msgid "Creates branch '%{branch_name}' and a merge request to resolve this issue
msgstr ""
msgid "Creating"
-msgstr ""
+msgstr "Oppretter"
msgid "Creating epic"
-msgstr ""
+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 ""
+msgstr "Opprettelsesdato"
msgid "Credentials"
-msgstr ""
+msgstr "Legitimasjon"
msgid "CredentialsInventory|No credentials found"
msgstr ""
@@ -7372,37 +7640,37 @@ msgid "CredentialsInventory|Personal Access Tokens"
msgstr ""
msgid "CredentialsInventory|SSH Keys"
-msgstr ""
+msgstr "SSH-nøkler"
msgid "Critical vulnerabilities present"
-msgstr ""
+msgstr "Kritiske sårbarheter til stede"
msgid "Cron Timezone"
-msgstr ""
+msgstr "Cron-tidssone"
msgid "Cron time zone"
msgstr ""
msgid "Crossplane"
-msgstr ""
+msgstr "Crossplane"
msgid "Current Branch"
-msgstr ""
+msgstr "Nåværende gren"
msgid "Current Plan"
-msgstr ""
+msgstr "Gjeldende abonnement"
msgid "Current Project"
-msgstr ""
+msgstr "Gjeldende prosjekt"
msgid "Current node"
-msgstr ""
+msgstr "Nåværende node"
msgid "Current node must be the primary node or you will be locking yourself out"
msgstr ""
msgid "Current password"
-msgstr ""
+msgstr "Nåværende passord"
msgid "Current vulnerabilities count"
msgstr ""
@@ -7414,19 +7682,19 @@ msgid "CurrentUser|One of your groups is running out"
msgstr ""
msgid "CurrentUser|Profile"
-msgstr ""
+msgstr "Profil"
msgid "CurrentUser|Settings"
-msgstr ""
+msgstr "Innstillinger"
msgid "CurrentUser|Start a Gold trial"
-msgstr ""
+msgstr "Begynn en Gold-prøveperiode"
msgid "CurrentUser|Upgrade"
-msgstr ""
+msgstr "Oppgrader"
msgid "Custom Attributes"
-msgstr ""
+msgstr "Tilpassede attributter"
msgid "Custom CI configuration path"
msgstr ""
@@ -7435,34 +7703,34 @@ msgid "Custom Git clone URL for HTTP(S)"
msgstr ""
msgid "Custom hostname (for private commit emails)"
-msgstr ""
+msgstr "Tilpasset vertsnavn (for private commit-e-poster)"
msgid "Custom metrics"
-msgstr ""
+msgstr "Tilpassede målinger"
msgid "Custom notification events"
-msgstr ""
+msgstr "Tilpassede varslingshendelser"
msgid "Custom notification levels are the same as participating levels. With custom notification levels you will also receive notifications for select events. To find out more, check out %{notification_link}."
-msgstr ""
+msgstr "Tilpassede varslingsnivåer er de samme som deltakelsesnivåer. Med tilpassede varslingsnivåer vil du også motta varsler om utvalgte hendelser. For å finne ut mer, sjekk ut %{notification_link}."
msgid "Custom project templates"
-msgstr ""
+msgstr "Tilpassede prosjektmaler"
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 "Egendefinerte prosjektmaler har ikke blitt satt opp for grupper som du er medlem av. De aktiveres fra en gruppes innstillingsside. Kontakt gruppens eier eller vedlikeholder for å sette opp egendefinerte prosjektmaler."
msgid "Custom range"
-msgstr ""
+msgstr "Egendefinert tidsrom"
msgid "Custom range (UTC)"
-msgstr ""
+msgstr "Tilpasset område (UTC)"
msgid "CustomCycleAnalytics|Add a stage"
-msgstr ""
+msgstr "Legg til et trinn"
msgid "CustomCycleAnalytics|Add stage"
-msgstr ""
+msgstr "Legg til trinn"
msgid "CustomCycleAnalytics|Editing stage"
msgstr ""
@@ -7471,25 +7739,25 @@ msgid "CustomCycleAnalytics|Enter a name for the stage"
msgstr ""
msgid "CustomCycleAnalytics|Name"
-msgstr ""
+msgstr "Navn"
msgid "CustomCycleAnalytics|New stage"
-msgstr ""
+msgstr "Nytt trinn"
msgid "CustomCycleAnalytics|Please select a start event first"
msgstr ""
msgid "CustomCycleAnalytics|Select start event"
-msgstr ""
+msgstr "Velg starthendelse"
msgid "CustomCycleAnalytics|Select stop event"
-msgstr ""
+msgstr "Velg stopphendelse"
msgid "CustomCycleAnalytics|Stage name already exists"
-msgstr ""
+msgstr "Trinnavnet finnes allerede"
msgid "CustomCycleAnalytics|Start event"
-msgstr ""
+msgstr "Starthendelse"
msgid "CustomCycleAnalytics|Start event changed, please select a valid stop event"
msgstr ""
@@ -7498,22 +7766,22 @@ msgid "CustomCycleAnalytics|Start event label"
msgstr ""
msgid "CustomCycleAnalytics|Stop event"
-msgstr ""
+msgstr "Stopphendelse"
msgid "CustomCycleAnalytics|Stop event label"
msgstr ""
msgid "CustomCycleAnalytics|Update stage"
-msgstr ""
+msgstr "Oppdater trinn"
msgid "Customer Portal"
-msgstr ""
+msgstr "Kundeportal"
msgid "Customizable by an administrator."
-msgstr ""
+msgstr "Justerbar av en administrator"
msgid "Customize colors"
-msgstr ""
+msgstr "Tilpass farger"
msgid "Customize how FogBugz email addresses and usernames are imported into GitLab. In the next step, you'll be able to select the projects you want to import."
msgstr ""
@@ -7522,13 +7790,13 @@ msgid "Customize how Google Code email addresses and usernames are imported into
msgstr ""
msgid "Customize icon"
-msgstr ""
+msgstr "Tilpass ikon"
msgid "Customize language and region related settings."
msgstr ""
msgid "Customize name"
-msgstr ""
+msgstr "Tilpass navn"
msgid "Customize your pipeline configuration, view your pipeline status and coverage report."
msgstr ""
@@ -7537,22 +7805,22 @@ msgid "Customize your pipeline configuration."
msgstr ""
msgid "CustomizeHomepageBanner|Do you want to customize this page?"
-msgstr ""
+msgstr "Vil du tilpasse denne siden?"
msgid "CustomizeHomepageBanner|Go to preferences"
-msgstr ""
+msgstr "GÃ¥ til preferansene"
msgid "CustomizeHomepageBanner|This page shows a list of your projects by default but it can be changed to show projects' activity, groups, your to-do list, assigned issues, assigned merge requests, and more. You can change this under \"Homepage content\" in your preferences"
-msgstr ""
+msgstr "Denne siden viser en liste over prosjektene dine som standard, men den kan endres til å vise prosjektenes aktivitet, grupper, din oppgaveliste, tilordnede saker, tilordnede flettforespørsler og mer. Du kan endre dette under «Hjemmesideinnhold» i dine preferanser"
msgid "Cycle Time"
-msgstr ""
+msgstr "Syklustid"
msgid "CycleAnalyticsEvent|Issue closed"
-msgstr ""
+msgstr "Sak lukket"
msgid "CycleAnalyticsEvent|Issue created"
-msgstr ""
+msgstr "Sak opprettet"
msgid "CycleAnalyticsEvent|Issue first added to a board"
msgstr ""
@@ -7564,7 +7832,7 @@ msgid "CycleAnalyticsEvent|Issue first associated with a milestone or issue firs
msgstr ""
msgid "CycleAnalyticsEvent|Issue first mentioned in a commit"
-msgstr ""
+msgstr "Saken ble først nevnt i en commit"
msgid "CycleAnalyticsEvent|Issue label was added"
msgstr ""
@@ -7573,22 +7841,22 @@ msgid "CycleAnalyticsEvent|Issue label was removed"
msgstr ""
msgid "CycleAnalyticsEvent|Issue last edited"
-msgstr ""
+msgstr "Sak senest redigert"
msgid "CycleAnalyticsEvent|Merge request closed"
-msgstr ""
+msgstr "Fletteforespørsel lukket"
msgid "CycleAnalyticsEvent|Merge request created"
-msgstr ""
+msgstr "Fletteforespørsel opprettet"
msgid "CycleAnalyticsEvent|Merge request first deployed to production"
msgstr ""
msgid "CycleAnalyticsEvent|Merge request label was added"
-msgstr ""
+msgstr "Fletteforespørselsstempel ble lagt til"
msgid "CycleAnalyticsEvent|Merge request label was removed"
-msgstr ""
+msgstr "Fletteforespørselsstempel ble fjernet"
msgid "CycleAnalyticsEvent|Merge request last build finish time"
msgstr ""
@@ -7597,90 +7865,90 @@ msgid "CycleAnalyticsEvent|Merge request last build start time"
msgstr ""
msgid "CycleAnalyticsEvent|Merge request last edited"
-msgstr ""
+msgstr "Fletteforespørsel senest redigert"
msgid "CycleAnalyticsEvent|Merge request merged"
-msgstr ""
+msgstr "Fletteforespørsel innflettet"
msgid "CycleAnalyticsStage|Code"
-msgstr ""
+msgstr "Kode"
msgid "CycleAnalyticsStage|Issue"
-msgstr ""
+msgstr "Sak"
msgid "CycleAnalyticsStage|Plan"
-msgstr ""
+msgstr "Plan"
msgid "CycleAnalyticsStage|Review"
-msgstr ""
+msgstr "Gjennomgang"
msgid "CycleAnalyticsStage|Staging"
msgstr ""
msgid "CycleAnalyticsStage|Test"
-msgstr ""
+msgstr "Test"
msgid "CycleAnalyticsStage|Total"
-msgstr ""
+msgstr "Totalt"
msgid "CycleAnalyticsStage|is not available for the selected group"
-msgstr ""
+msgstr "er ikke tilgjengelig for den valgte gruppen"
msgid "CycleAnalyticsStage|should be under a group"
msgstr ""
msgid "CycleAnalytics|%{selectedLabelsCount} selected (%{maxLabels} max)"
-msgstr ""
+msgstr "%{selectedLabelsCount} valgt (%{maxLabels} max)"
msgid "CycleAnalytics|%{stageCount} stages selected"
-msgstr ""
+msgstr "%{stageCount} trinn valgt"
msgid "CycleAnalytics|All stages"
-msgstr ""
+msgstr "Alle trinn"
msgid "CycleAnalytics|Date"
-msgstr ""
+msgstr "Dato"
msgid "CycleAnalytics|Days to completion"
-msgstr ""
+msgstr "Dager igjen til fullføring"
msgid "CycleAnalytics|Display chart filters"
-msgstr ""
+msgstr "Vis diagramfiltre"
msgid "CycleAnalytics|No stages selected"
-msgstr ""
+msgstr "Ingen trinn er valgt"
msgid "CycleAnalytics|Number of tasks"
-msgstr ""
+msgstr "Antall oppgaver"
msgid "CycleAnalytics|Only %{maxLabels} labels can be selected at this time"
msgstr ""
msgid "CycleAnalytics|Project selected"
msgid_plural "CycleAnalytics|%d projects selected"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "Prosjekt valgt"
+msgstr[1] "%d prosjekter valgt"
msgid "CycleAnalytics|Select labels"
-msgstr ""
+msgstr "Velg stempler"
msgid "CycleAnalytics|Show"
-msgstr ""
+msgstr "Vis"
msgid "CycleAnalytics|Showing %{subjectFilterText} and %{selectedLabelsCount} labels"
-msgstr ""
+msgstr "Viser %{subjectFilterText} og %{selectedLabelsCount} stempler"
msgid "CycleAnalytics|Showing data for group '%{groupName}' and %{selectedProjectCount} projects from %{startDate} to %{endDate}"
-msgstr ""
+msgstr "Viser data for gruppen '%{groupName}' og %{selectedProjectCount} prosjekter fra %{startDate} til %{endDate}"
msgid "CycleAnalytics|Showing data for group '%{groupName}' from %{startDate} to %{endDate}"
-msgstr ""
+msgstr "Viser data for gruppen '%{groupName}' fra %{startDate} til %{endDate}"
msgid "CycleAnalytics|Stages"
-msgstr ""
+msgstr "Trinn"
msgid "CycleAnalytics|Tasks by type"
-msgstr ""
+msgstr "Oppgaver etter type"
msgid "CycleAnalytics|The given date range is larger than 180 days"
msgstr ""
@@ -7704,64 +7972,67 @@ msgid "CycleAnalytics|stage dropdown"
msgstr ""
msgid "DAG"
-msgstr ""
+msgstr "DAG"
msgid "DAG visualization requires at least 3 dependent jobs."
msgstr ""
msgid "DAST Profiles"
-msgstr ""
+msgstr "DAST-profiler"
msgid "DNS"
-msgstr ""
+msgstr "DNS"
msgid "Dashboard"
-msgstr ""
+msgstr "Kontrollpanel"
msgid "Dashboard uid not found"
msgstr ""
msgid "DashboardProjects|All"
-msgstr ""
+msgstr "Alle"
msgid "DashboardProjects|Personal"
-msgstr ""
+msgstr "Personlig"
msgid "DashboardProjects|Trending"
-msgstr ""
+msgstr "Trendende"
msgid "Dashboards"
-msgstr ""
+msgstr "Kontrollpaneler"
msgid "Dashboard|%{firstProject} and %{secondProject}"
-msgstr ""
+msgstr "%{firstProject} og %{secondProject}"
msgid "Dashboard|%{firstProject}, %{rest}, and %{secondProject}"
-msgstr ""
+msgstr "%{firstProject}, %{rest}, og %{secondProject}"
msgid "Dashboard|Unable to add %{invalidProjects}. This dashboard is available for public projects, and private projects in groups with a Silver plan."
msgstr ""
msgid "DastProfiles|Are you sure you want to delete this profile?"
+msgstr "Er du sikker på at du vil slette profilen?"
+
+msgid "DastProfiles|Could not create site validation token. Please refresh the page, or try again later."
msgstr ""
msgid "DastProfiles|Could not create the scanner profile. Please try again."
msgstr ""
msgid "DastProfiles|Could not create the site profile. Please try again."
-msgstr ""
+msgstr "Klarte ikke å opprette nettstedsprofilen. Vennligst prøv igjen."
msgid "DastProfiles|Could not delete scanner profile. Please refresh the page, or try again later."
-msgstr ""
+msgstr "Klarte ikke å slette skannerprofilen. Vennligst oppfrisk siden, eller prøv igjen senere."
msgid "DastProfiles|Could not delete scanner profiles:"
-msgstr ""
+msgstr "Klarte ikke å slette skannerprofiler:"
msgid "DastProfiles|Could not delete site profile. Please refresh the page, or try again later."
-msgstr ""
+msgstr "Klarte ikke å slette nettstedsprofilen. Vennligst oppfrisk siden, eller prøv igjen senere."
msgid "DastProfiles|Could not delete site profiles:"
-msgstr ""
+msgstr "Klarte ikke å slette nettstedsprofiler:"
msgid "DastProfiles|Could not fetch scanner profiles. Please refresh the page, or try again later."
msgstr ""
@@ -7769,52 +8040,61 @@ msgstr ""
msgid "DastProfiles|Could not fetch site profiles. Please refresh the page, or try again later."
msgstr ""
-msgid "DastProfiles|Could not update the site profile. Please try again."
+msgid "DastProfiles|Could not retrieve site validation status. Please refresh the page, or try again later."
msgstr ""
-msgid "DastProfiles|Do you want to discard this scanner profile?"
+msgid "DastProfiles|Could not update the scanner profile. Please try again."
msgstr ""
+msgid "DastProfiles|Could not update the site profile. Please try again."
+msgstr "Klarte ikke å oppdatere nettstedsprofilen. Vennligst prøv igjen."
+
+msgid "DastProfiles|Do you want to discard this scanner profile?"
+msgstr "Vil du forkaste denne skannerprofilen?"
+
msgid "DastProfiles|Do you want to discard this site profile?"
-msgstr ""
+msgstr "Vil du forkaste denne nettstedsprofilen?"
msgid "DastProfiles|Do you want to discard your changes?"
-msgstr ""
+msgstr "Vil du forkaste dine endringer?"
msgid "DastProfiles|Download validation text file"
msgstr ""
-msgid "DastProfiles|Edit feature will come soon. Please create a new profile if changes needed"
+msgid "DastProfiles|Edit scanner profile"
msgstr ""
msgid "DastProfiles|Edit site profile"
-msgstr ""
+msgstr "Rediger nettstedsprofilen"
msgid "DastProfiles|Error Details"
-msgstr ""
+msgstr "Detaljer om feilen"
msgid "DastProfiles|Manage Profiles"
-msgstr ""
+msgstr "Behandle profiler"
msgid "DastProfiles|Manage profiles"
-msgstr ""
+msgstr "Behandle profiler"
msgid "DastProfiles|Minimum = 0 (no timeout enabled), Maximum = 2880 minutes"
msgstr ""
msgid "DastProfiles|Minimum = 1 second, Maximum = 3600 seconds"
-msgstr ""
+msgstr "Minimum = 1 sekund, Maks = 3600 sekunder"
msgid "DastProfiles|New Profile"
-msgstr ""
+msgstr "Ny profil"
msgid "DastProfiles|New scanner profile"
-msgstr ""
+msgstr "Ny skannerprofil"
msgid "DastProfiles|New site profile"
-msgstr ""
+msgstr "Ny nettstedsprofil"
msgid "DastProfiles|No profiles created yet"
+msgstr "Ingen profiler er opprettet enda"
+
+msgid "DastProfiles|Passive"
msgstr ""
msgid "DastProfiles|Please enter a valid URL format, ex: http://www.example.com/home"
@@ -7824,25 +8104,28 @@ msgid "DastProfiles|Please enter a valid timeout value"
msgstr ""
msgid "DastProfiles|Profile name"
-msgstr ""
+msgstr "Profilnavn"
msgid "DastProfiles|Save commonly used configurations for target sites and scan specifications as profiles. Use these with an on-demand scan."
msgstr ""
msgid "DastProfiles|Save profile"
+msgstr "Lagre profil"
+
+msgid "DastProfiles|Scan mode"
msgstr ""
msgid "DastProfiles|Scanner Profile"
-msgstr ""
+msgstr "Skannerprofil"
msgid "DastProfiles|Scanner Profiles"
-msgstr ""
+msgstr "Skanner-profiler"
msgid "DastProfiles|Site Profile"
-msgstr ""
+msgstr "Nettstedsprofil"
msgid "DastProfiles|Site Profiles"
-msgstr ""
+msgstr "Nettstedsprofiler"
msgid "DastProfiles|Site is not validated yet, please follow the steps."
msgstr ""
@@ -7863,28 +8146,28 @@ msgid "DastProfiles|Step 3 - Confirm text file location and validate"
msgstr ""
msgid "DastProfiles|Target URL"
-msgstr ""
+msgstr "MÃ¥l-URL"
msgid "DastProfiles|Target timeout"
msgstr ""
msgid "DastProfiles|Text file validation"
-msgstr ""
+msgstr "Tekstfilvalidering"
-msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
+msgid "DastProfiles|The maximum number of minutes allowed for the spider to traverse the site."
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the spider to traverse the site."
+msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
msgstr ""
msgid "DastProfiles|Validate"
-msgstr ""
+msgstr "Valider"
msgid "DastProfiles|Validate target site"
-msgstr ""
+msgstr "Valider målnettstedet"
msgid "DastProfiles|Validating..."
-msgstr ""
+msgstr "Validerer …"
msgid "DastProfiles|Validation failed, please make sure that you follow the steps above with the choosen method."
msgstr ""
@@ -7902,55 +8185,61 @@ msgid "Datasource name not found"
msgstr ""
msgid "Date"
-msgstr ""
+msgstr "Dato"
msgid "Date picker"
+msgstr "Datovelger"
+
+msgid "Date range"
msgstr ""
msgid "Date range cannot exceed %{maxDateRange} days."
msgstr ""
msgid "Day of month"
-msgstr ""
+msgstr "Dag i måneden"
msgid "DayTitle|F"
-msgstr ""
+msgstr "F"
msgid "DayTitle|M"
-msgstr ""
+msgstr "M"
msgid "DayTitle|S"
-msgstr ""
+msgstr "L/S"
msgid "DayTitle|W"
-msgstr ""
+msgstr "O"
msgid "Days"
-msgstr ""
+msgstr "Dager"
msgid "Days to merge"
msgstr ""
-msgid "Debug"
+msgid "Dear Administrator,"
msgstr ""
+msgid "Debug"
+msgstr "Feilsøk"
+
msgid "Dec"
-msgstr ""
+msgstr "Des"
msgid "December"
-msgstr ""
+msgstr "Desember"
msgid "Decline"
-msgstr ""
+msgstr "Avslå"
msgid "Decline and sign out"
-msgstr ""
+msgstr "Avvis og logg ut"
msgid "Decompressed archive size validation failed."
msgstr ""
msgid "Default Branch"
-msgstr ""
+msgstr "Standardgren"
msgid "Default CI configuration path"
msgstr ""
@@ -7959,7 +8248,7 @@ msgid "Default artifacts expiration"
msgstr ""
msgid "Default branch"
-msgstr ""
+msgstr "Standardgren"
msgid "Default branch and protected branches"
msgstr ""
@@ -7986,7 +8275,7 @@ msgid "Default initial branch name"
msgstr ""
msgid "Default issue template"
-msgstr ""
+msgstr "Standard-sakermal"
msgid "Default project deletion protection"
msgstr ""
@@ -7995,7 +8284,7 @@ msgid "Default projects limit"
msgstr ""
msgid "Default stages"
-msgstr ""
+msgstr "Standardtrinn"
msgid "Default: Directly import the Google Code email address or username"
msgstr ""
@@ -8004,7 +8293,7 @@ msgid "Default: Map a FogBugz account ID to a full name"
msgstr ""
msgid "DefaultBranchLabel|default"
-msgstr ""
+msgstr "standard"
msgid "Define a custom deploy freeze pattern with %{cronSyntaxStart}cron syntax%{cronSyntaxEnd}"
msgstr ""
@@ -8019,7 +8308,7 @@ msgid "Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%
msgstr ""
msgid "Definition"
-msgstr ""
+msgstr "Definisjon"
msgid "Delayed Project Deletion (%{adjourned_deletion})"
msgstr ""
@@ -8031,88 +8320,91 @@ msgid "DelayedJobs|Are you sure you want to run %{job_name} immediately? This jo
msgstr ""
msgid "DelayedJobs|Start now"
-msgstr ""
+msgstr "Start nå"
msgid "DelayedJobs|Unschedule"
msgstr ""
msgid "DelayedJobs|delayed"
-msgstr ""
+msgstr "forsinket"
msgid "Delete"
+msgstr "Slett"
+
+msgid "Delete %{name}"
msgstr ""
msgid "Delete Comment"
-msgstr ""
+msgstr "Slett kommentar"
msgid "Delete Snippet"
+msgstr "Slett utdraget"
+
+msgid "Delete Value Stream"
msgstr ""
msgid "Delete account"
-msgstr ""
+msgstr "Slett konto"
msgid "Delete artifacts"
-msgstr ""
+msgstr "Slett artefakter"
msgid "Delete board"
-msgstr ""
+msgstr "Slett tavle"
msgid "Delete comment"
-msgstr ""
+msgstr "Slett kommentar"
msgid "Delete domain"
-msgstr ""
+msgstr "Slett domene"
msgid "Delete label"
-msgstr ""
+msgstr "Slett stempel"
msgid "Delete label: %{label_name} ?"
msgstr ""
-msgid "Delete license"
-msgstr ""
-
msgid "Delete list"
-msgstr ""
+msgstr "Slett liste"
msgid "Delete pipeline"
msgstr ""
msgid "Delete project"
-msgstr ""
+msgstr "Slett prosjekt"
msgid "Delete project. Are you ABSOLUTELY SURE?"
-msgstr ""
+msgstr "Slett prosjektet. Er du HELT SIKKER?"
msgid "Delete serverless domain?"
msgstr ""
msgid "Delete snippet"
-msgstr ""
+msgstr "Slett utdraget"
msgid "Delete snippet?"
-msgstr ""
+msgstr "Vil du slette utvalget?"
msgid "Delete source branch"
-msgstr ""
+msgstr "Slett kildegrenen"
msgid "Delete this attachment"
-msgstr ""
+msgstr "Slett dette vedlegget"
msgid "Delete user list"
-msgstr ""
+msgstr "Slett brukerliste"
msgid "Delete variable"
-msgstr ""
+msgstr "Slett variabel"
msgid "DeleteProject|Delete %{name}"
-msgstr ""
+msgstr "Slett %{name}"
msgid "DeleteProject|Failed to remove project repository. Please try again or contact administrator."
msgstr ""
msgid "DeleteProject|Failed to remove project snippets. Please try again or contact administrator."
-msgstr ""
+msgstr "Kunne ikke fjerne prosjektutdrag. Prøv på nytt eller kontakt administratoren."
msgid "DeleteProject|Failed to remove some tags in project container registry. Please try again or contact administrator."
msgstr ""
@@ -8127,7 +8419,7 @@ msgid "DeleteProject|Failed to restore wiki repository. Please contact the admin
msgstr ""
msgid "Deleted"
-msgstr ""
+msgstr "Slettet"
msgid "Deleted Projects"
msgstr ""
@@ -8136,26 +8428,17 @@ msgid "Deleted chat nickname: %{chat_name}!"
msgstr ""
msgid "Deleted projects"
-msgstr ""
+msgstr "Slettede prosjekter"
msgid "Deleted projects cannot be restored!"
msgstr ""
msgid "Deleting"
-msgstr ""
+msgstr "Sletter"
msgid "Deleting a project places it into a read-only state until %{date}, at which point the project will be permanently deleted. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "Deleting the license failed."
-msgstr ""
-
-msgid "Deleting the license failed. The license was not found."
-msgstr ""
-
-msgid "Deleting the license failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "Deleting the project will delete its repository and all related resources including issues, merge requests etc."
msgstr ""
@@ -8163,19 +8446,19 @@ msgid "Deletion pending. This project will be removed on %{date}. Repository and
msgstr ""
msgid "Denied"
-msgstr ""
+msgstr "Avslått"
msgid "Denied authorization of chat nickname %{user_name}."
msgstr ""
msgid "Deny"
-msgstr ""
+msgstr "Avvis"
msgid "Deny access request"
msgstr ""
msgid "Dependencies"
-msgstr ""
+msgstr "Avhengigheter"
msgid "Dependencies help page link"
msgstr ""
@@ -8187,49 +8470,49 @@ msgstr[1] ""
msgid "Dependencies|%d more"
msgid_plural "Dependencies|%d more"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%d til"
+msgstr[1] "%d til"
msgid "Dependencies|%d vulnerability detected"
msgid_plural "Dependencies|%d vulnerabilities detected"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%d sårbarhet oppdaget"
+msgstr[1] "%d sårbarheter oppdaget"
msgid "Dependencies|%{remainingLicensesCount} more"
-msgstr ""
+msgstr "%{remainingLicensesCount} til"
msgid "Dependencies|(top level)"
-msgstr ""
+msgstr "(høyeste nivå)"
msgid "Dependencies|All"
-msgstr ""
+msgstr "Alle"
msgid "Dependencies|Based on the %{linkStart}latest successful%{linkEnd} scan"
msgstr ""
msgid "Dependencies|Component"
-msgstr ""
+msgstr "Komponent"
msgid "Dependencies|Component name"
-msgstr ""
+msgstr "Komponentnavn"
msgid "Dependencies|Dependency path"
msgstr ""
msgid "Dependencies|Export as JSON"
-msgstr ""
+msgstr "Eksporter som JSON"
msgid "Dependencies|Job failed to generate the dependency list"
msgstr ""
msgid "Dependencies|License"
-msgstr ""
+msgstr "Lisens"
msgid "Dependencies|Location"
-msgstr ""
+msgstr "Sted"
msgid "Dependencies|Packager"
-msgstr ""
+msgstr "Innpakker"
msgid "Dependencies|The %{codeStartTag}dependency_scanning%{codeEndTag} job has failed and cannot generate the list. Please ensure the job is running properly and run the pipeline again."
msgstr ""
@@ -8247,7 +8530,7 @@ msgid "Dependencies|Vulnerable components"
msgstr ""
msgid "Dependency List"
-msgstr ""
+msgstr "Avhengighetsliste"
msgid "Dependency List has no entries"
msgstr ""
@@ -8256,10 +8539,10 @@ msgid "Dependency Proxy"
msgstr ""
msgid "Dependency Scanning"
-msgstr ""
+msgstr "Avhengighetsskanning"
msgid "Dependency proxy"
-msgstr ""
+msgstr "Avhengighetsmellomtjener"
msgid "Dependency proxy URL"
msgstr ""
@@ -8282,8 +8565,8 @@ msgstr[1] ""
msgid "Deploy"
msgid_plural "Deploys"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "Distribuering"
+msgstr[1] "Distribueringer"
msgid "Deploy Keys"
msgstr ""
@@ -8322,19 +8605,19 @@ msgid "DeployFreeze|No deploy freezes exist for this project. To add one, click
msgstr ""
msgid "DeployFreeze|Specify times when deployments are not allowed for an environment. The %{filename} file must be updated to make deployment jobs aware of the %{freeze_period_link_start}freeze period%{freeze_period_link_end}."
-msgstr ""
+msgstr "Angi tidspunkter når distribusjoner ikke er tillatt for et miljø. %{filename}-filen må oppdateres for å gjøre distribusjonsjobber oppmerksomme på %{freeze_period_link_start}fryseperioden%{freeze_period_link_end}."
msgid "DeployFreeze|Time zone"
-msgstr ""
+msgstr "Tidssone"
msgid "DeployFreeze|You can specify deploy freezes using only %{cron_syntax_link_start}cron syntax%{cron_syntax_link_end}."
msgstr ""
msgid "DeployKeys|+%{count} others"
-msgstr ""
+msgstr "+%{count} andre"
msgid "DeployKeys|Current project"
-msgstr ""
+msgstr "Nåværende prosjekt"
msgid "DeployKeys|Deploy key"
msgstr ""
@@ -8352,7 +8635,7 @@ msgid "DeployKeys|Error removing deploy key"
msgstr ""
msgid "DeployKeys|Expand %{count} other projects"
-msgstr ""
+msgstr "Utvid %{count} andre prosjekter"
msgid "DeployKeys|Loading deploy keys"
msgstr ""
@@ -8364,16 +8647,16 @@ msgid "DeployKeys|Privately accessible deploy keys"
msgstr ""
msgid "DeployKeys|Project usage"
-msgstr ""
+msgstr "Prosjektbruk"
msgid "DeployKeys|Publicly accessible deploy keys"
msgstr ""
msgid "DeployKeys|Read access only"
-msgstr ""
+msgstr "Kun lesetilgang"
msgid "DeployKeys|Write access allowed"
-msgstr ""
+msgstr "Skrivetilgang er tillatt"
msgid "DeployKeys|You are going to remove this deploy key. Are you sure?"
msgstr ""
@@ -8385,7 +8668,7 @@ msgid "DeployTokens|Add a deploy token"
msgstr ""
msgid "DeployTokens|Allows read access to the package registry"
-msgstr ""
+msgstr "Tillater lesetilgang til pakkeregisteret"
msgid "DeployTokens|Allows read-only access to the registry images"
msgstr ""
@@ -8394,22 +8677,22 @@ msgid "DeployTokens|Allows read-only access to the repository"
msgstr ""
msgid "DeployTokens|Allows write access to the package registry"
-msgstr ""
+msgstr "Tillater skrivetilgang til pakkeregisteret"
msgid "DeployTokens|Allows write access to the registry images"
-msgstr ""
+msgstr "Tillater skrivetilgang til registerbildene"
msgid "DeployTokens|Copy deploy token"
msgstr ""
msgid "DeployTokens|Copy username"
-msgstr ""
+msgstr "Kopier brukernavn"
msgid "DeployTokens|Create deploy token"
msgstr ""
msgid "DeployTokens|Created"
-msgstr ""
+msgstr "Opprettet"
msgid "DeployTokens|Default format is \"gitlab+deploy-token-{n}\". Enter custom username if you want to change it."
msgstr ""
@@ -8421,25 +8704,25 @@ msgid "DeployTokens|Deploy tokens allow access to packages, your repository, and
msgstr ""
msgid "DeployTokens|Expires"
-msgstr ""
+msgstr "Utløper"
msgid "DeployTokens|Group deploy tokens allow access to the packages, repositories, and registry images within the group."
msgstr ""
msgid "DeployTokens|Name"
-msgstr ""
+msgstr "Navn"
msgid "DeployTokens|Pick a name for the application, and we'll give you a unique deploy token."
msgstr ""
msgid "DeployTokens|Revoke"
-msgstr ""
+msgstr "Tilbakekall"
msgid "DeployTokens|Revoke %{b_start}%{name}%{b_end}?"
-msgstr ""
+msgstr "Tilbakekall %{b_start}%{name}%{b_end}?"
msgid "DeployTokens|Revoke %{name}"
-msgstr ""
+msgstr "Tilbakekall %{name}"
msgid "DeployTokens|Scopes"
msgstr ""
@@ -8448,16 +8731,16 @@ msgid "DeployTokens|This %{entity_type} has no active Deploy Tokens."
msgstr ""
msgid "DeployTokens|This action cannot be undone."
-msgstr ""
+msgstr "Denne handlingen kan ikke angres på."
msgid "DeployTokens|Use this token as a password. Make sure you save it - you won't be able to access it again."
msgstr ""
msgid "DeployTokens|Use this username as a login."
-msgstr ""
+msgstr "Bruk dette brukernavnet som en innlogging."
msgid "DeployTokens|Username"
-msgstr ""
+msgstr "Brukernavn"
msgid "DeployTokens|You are about to revoke %{b_start}%{name}%{b_end}."
msgstr ""
@@ -8472,10 +8755,10 @@ msgid "DeployTokens|Your new project deploy token has been created."
msgstr ""
msgid "Deployed"
-msgstr ""
+msgstr "Utstasjonert"
msgid "Deployed to"
-msgstr ""
+msgstr "Utstasjonert til"
msgid "Deploying to"
msgstr ""
@@ -8487,40 +8770,40 @@ msgid "Deployment Frequency"
msgstr ""
msgid "Deployment|API"
-msgstr ""
+msgstr "API"
msgid "Deployment|This deployment was created using the API"
msgstr ""
msgid "Deployment|canceled"
-msgstr ""
+msgstr "avbrutt"
msgid "Deployment|created"
-msgstr ""
+msgstr "opprettet"
msgid "Deployment|failed"
-msgstr ""
+msgstr "mislyktes"
msgid "Deployment|running"
-msgstr ""
+msgstr "kjører"
msgid "Deployment|success"
-msgstr ""
+msgstr "suksess"
msgid "Deprioritize label"
msgstr ""
msgid "Descending"
-msgstr ""
+msgstr "Synkende"
msgid "Describe the goal of the changes and what reviewers should be aware of."
msgstr ""
msgid "Describe the requirement here"
-msgstr ""
+msgstr "Beskriv kravet her"
msgid "Description"
-msgstr ""
+msgstr "Beskrivelse"
msgid "Description parsed with %{link_start}GitLab Flavored Markdown%{link_end}"
msgstr ""
@@ -8529,13 +8812,13 @@ msgid "Description templates allow you to define context-specific templates for
msgstr ""
msgid "Description:"
-msgstr ""
+msgstr "Beskrivelse:"
msgid "Descriptive label"
msgstr ""
msgid "Deselect all"
-msgstr ""
+msgstr "Avvelg alle"
msgid "Design Management files and data"
msgstr ""
@@ -8547,10 +8830,10 @@ msgid "Design repository"
msgstr ""
msgid "DesignManagement|%{current_design} of %{designs_count}"
-msgstr ""
+msgstr "%{current_design} av %{designs_count}"
msgid "DesignManagement|%{filename} did not change."
-msgstr ""
+msgstr "%{filename} forble det samme."
msgid "DesignManagement|Adding a design with the same filename replaces the file in a new version."
msgstr ""
@@ -8559,7 +8842,7 @@ msgid "DesignManagement|Archive designs"
msgstr ""
msgid "DesignManagement|Archive selected"
-msgstr ""
+msgstr "Arkiver de valgte"
msgid "DesignManagement|Archived designs will still be available in previous versions of the design collection."
msgstr ""
@@ -8574,10 +8857,10 @@ msgid "DesignManagement|Are you sure you want to cancel creating this comment?"
msgstr ""
msgid "DesignManagement|Cancel changes"
-msgstr ""
+msgstr "Avbryt endringer"
msgid "DesignManagement|Cancel comment confirmation"
-msgstr ""
+msgstr "Avbryt kommentarbekreftelse"
msgid "DesignManagement|Cancel comment update confirmation"
msgstr ""
@@ -8592,109 +8875,115 @@ msgid "DesignManagement|Comments you resolve can be viewed and unresolved by goi
msgstr ""
msgid "DesignManagement|Could not add a new comment. Please try again."
-msgstr ""
+msgstr "Klarte ikke å legge til en ny kommentar. Vennligst prøv igjen."
msgid "DesignManagement|Could not create new discussion. Please try again."
-msgstr ""
+msgstr "Klarte ikke å opprette en ny diskusjon. Vennligst prøv igjen."
msgid "DesignManagement|Could not update discussion. Please try again."
-msgstr ""
+msgstr "Klarte ikke å oppdatere diskusjonen. Vennligst prøv igjen."
msgid "DesignManagement|Could not update note. Please try again."
-msgstr ""
+msgstr "Klarte ikke å oppdatere notisen. Vennligst prøv igjen."
msgid "DesignManagement|Deselect all"
-msgstr ""
+msgstr "Avvelg alle"
msgid "DesignManagement|Designs"
-msgstr ""
+msgstr "Design"
msgid "DesignManagement|Discard comment"
-msgstr ""
+msgstr "Forkast kommentar"
msgid "DesignManagement|Error uploading a new design. Please try again."
-msgstr ""
+msgstr "Feil under opplasting av et nytt design. Vennligst prøv igjen."
msgid "DesignManagement|Go back to designs"
-msgstr ""
+msgstr "GÃ¥ tilbake til designene"
msgid "DesignManagement|Go to next design"
-msgstr ""
+msgstr "GÃ¥ til neste design"
msgid "DesignManagement|Go to previous design"
-msgstr ""
+msgstr "GÃ¥ til forrige design"
msgid "DesignManagement|Keep changes"
-msgstr ""
+msgstr "Behold endringer"
msgid "DesignManagement|Keep comment"
-msgstr ""
+msgstr "Behold kommentaren"
msgid "DesignManagement|Learn more about resolving comments"
-msgstr ""
+msgstr "Lær om å oppklare kommentarer"
msgid "DesignManagement|Requested design version does not exist. Showing latest version instead"
msgstr ""
msgid "DesignManagement|Resolve thread"
-msgstr ""
+msgstr "Oppklar tråd"
msgid "DesignManagement|Resolved Comments"
-msgstr ""
+msgstr "Oppklarte kommentarer"
msgid "DesignManagement|Save comment"
-msgstr ""
+msgstr "Lagre kommentar"
msgid "DesignManagement|Select all"
-msgstr ""
+msgstr "Velg alle"
msgid "DesignManagement|The maximum number of designs allowed to be uploaded is %{upload_limit}. Please try again."
msgstr ""
-msgid "DesignManagement|To upload designs, you'll need to enable LFS. %{requirements_link_start}More information%{requirements_link_end}"
+msgid "DesignManagement|There was an error moving your designs. Please upload your designs below."
msgstr ""
-msgid "DesignManagement|Unresolve thread"
+msgid "DesignManagement|To upload designs, you'll need to enable LFS and have admin enable hashed storage. %{requirements_link_start}More information%{requirements_link_end}"
msgstr ""
+msgid "DesignManagement|Unresolve thread"
+msgstr "Uoppklar tråden"
+
msgid "DesignManagement|Upload designs"
-msgstr ""
+msgstr "Last opp design"
msgid "DesignManagement|Upload skipped."
+msgstr "Opplasting hoppet over."
+
+msgid "DesignManagement|Your designs are being copied and are on their way… Please refresh to update."
msgstr ""
msgid "DesignManagement|and %{moreCount} more."
-msgstr ""
+msgstr "og %{moreCount} til."
msgid "Designs"
-msgstr ""
+msgstr "Design"
msgid "Destroy"
-msgstr ""
+msgstr "Ødelegg"
msgid "Detail"
-msgstr ""
+msgstr "Detaljer"
msgid "Details"
-msgstr ""
+msgstr "Detaljer"
msgid "Details (default)"
-msgstr ""
+msgstr "Detaljer (standard)"
msgid "Detect host keys"
msgstr ""
msgid "DevOps"
-msgstr ""
+msgstr "DevOps"
msgid "DevOps Report"
-msgstr ""
+msgstr "DevOps-rapport"
msgid "Diff content limits"
msgstr ""
msgid "Diff limits"
-msgstr ""
+msgstr "Diff-grenser"
msgid "Diff view settings"
msgstr ""
@@ -8709,10 +8998,10 @@ msgid "DiffsCompareBaseBranch|(base)"
msgstr ""
msgid "Diffs|No file name available"
-msgstr ""
+msgstr "Ingen filnavn tilgjengelig"
msgid "Diffs|Show %{unfoldCount} lines"
-msgstr ""
+msgstr "Vis %{unfoldCount} linjer"
msgid "Diffs|Show all unchanged lines"
msgstr ""
@@ -8720,17 +9009,20 @@ msgstr ""
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
-msgid "Direction"
+msgid "Direct member"
msgstr ""
+msgid "Direction"
+msgstr "Retning"
+
msgid "Directory name"
-msgstr ""
+msgstr "Katalognavn"
msgid "Disable"
-msgstr ""
+msgstr "Skru av"
msgid "Disable for this project"
-msgstr ""
+msgstr "Deaktiver for dette prosjektet"
msgid "Disable group Runners"
msgstr ""
@@ -8742,46 +9034,43 @@ msgid "Disable shared Runners"
msgstr ""
msgid "Disable two-factor authentication"
-msgstr ""
+msgstr "Skru av 2-trinnsautentisering"
msgid "Disabled"
-msgstr ""
+msgstr "Deaktivert"
msgid "Disabled mirrors can only be enabled by instance owners. It is recommended that you delete them."
msgstr ""
msgid "Discard"
-msgstr ""
+msgstr "Forkast"
msgid "Discard all changes"
-msgstr ""
+msgstr "Forkast alle endringer"
msgid "Discard all changes?"
-msgstr ""
+msgstr "Forkast alle endringer?"
msgid "Discard changes"
-msgstr ""
+msgstr "Forkast endringer"
msgid "Discard changes to %{path}?"
-msgstr ""
+msgstr "Forkast endringer for %{path}?"
msgid "Discard draft"
-msgstr ""
-
-msgid "Discard review"
-msgstr ""
+msgstr "Forkast utkast"
msgid "DiscordService|Discord Notifications"
-msgstr ""
+msgstr "Discord-varsler"
msgid "DiscordService|Receive event notifications in Discord"
msgstr ""
msgid "Discover GitLab Geo"
-msgstr ""
+msgstr "Oppdag GitLab Geo"
msgid "Discover projects, groups and snippets. Share your projects with others"
-msgstr ""
+msgstr "Oppdag prosjekter, grupper og utdrag. Del prosjektene dine med andre"
msgid "Discover|Check your application for security vulnerabilities that may lead to unauthorized access, data leaks, and denial of services."
msgstr ""
@@ -8793,7 +9082,7 @@ msgid "Discover|GitLab will perform static and dynamic tests on the code of your
msgstr ""
msgid "Discover|Give feedback for this page"
-msgstr ""
+msgstr "Gi tilbakemelding på denne siden"
msgid "Discover|Security capabilities, integrated into your development lifecycle"
msgstr ""
@@ -8802,13 +9091,13 @@ msgid "Discover|See the other features of the %{linkStart}gold plan%{linkEnd}"
msgstr ""
msgid "Discover|Start a free trial"
-msgstr ""
+msgstr "Begynn en gratis prøveperiode"
msgid "Discover|Upgrade now"
-msgstr ""
+msgstr "Oppgrader nå"
msgid "Discuss a specific suggestion or question"
-msgstr ""
+msgstr "Diskuter et spesifikt forslag eller løsning"
msgid "Discuss a specific suggestion or question that needs to be resolved"
msgstr ""
@@ -8823,15 +9112,15 @@ msgid "Discussion to reply to cannot be found"
msgstr ""
msgid "Disk Usage"
-msgstr ""
+msgstr "Diskforbruk"
msgid "Dismiss"
-msgstr ""
+msgstr "Avslå"
msgid "Dismiss %d selected vulnerability as"
msgid_plural "Dismiss %d selected vulnerabilities as"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "Avfei %d valgt sårbarhet som"
+msgstr[1] "Avfei %d valgt sårbarheter som"
msgid "Dismiss DevOps Report introduction"
msgstr ""
@@ -8839,23 +9128,23 @@ msgstr ""
msgid "Dismiss Merge Request promotion"
msgstr ""
-msgid "Dismiss Selected"
+msgid "Dismiss Value Stream Analytics introduction box"
msgstr ""
-msgid "Dismiss Value Stream Analytics introduction box"
+msgid "Dismiss selected"
msgstr ""
msgid "Dismiss trial promotion"
msgstr ""
msgid "Dismissable"
-msgstr ""
+msgstr "Avfeibar"
msgid "Dismissed"
-msgstr ""
+msgstr "Avfeid"
msgid "Dismissed at %{projectLink}"
-msgstr ""
+msgstr "Avfeid hos %{projectLink}"
msgid "Dismissed on pipeline %{pipelineLink}"
msgstr ""
@@ -8867,13 +9156,13 @@ msgid "Display alerts from all your monitoring tools directly within GitLab."
msgstr ""
msgid "Display name"
-msgstr ""
+msgstr "Visningsnavn"
msgid "Display rendered file"
msgstr ""
msgid "Display source"
-msgstr ""
+msgstr "Vis kilden"
msgid "Do not display offers from third parties within GitLab"
msgstr ""
@@ -8885,7 +9174,7 @@ msgid "Dockerfile"
msgstr ""
msgid "Documentation"
-msgstr ""
+msgstr "Dokumentasjon"
msgid "Documentation for popular identity providers"
msgstr ""
@@ -8893,11 +9182,8 @@ msgstr ""
msgid "Documents reindexed: %{processed_documents} (%{percentage}%%)"
msgstr ""
-msgid "Doing"
-msgstr ""
-
msgid "Domain"
-msgstr ""
+msgstr "Domene"
msgid "Domain cannot be deleted while associated to one or more clusters."
msgstr ""
@@ -8906,76 +9192,76 @@ msgid "Domain verification is an essential security measure for public GitLab si
msgstr ""
msgid "Domain was successfully created."
-msgstr ""
+msgstr "Domenet ble vellykket opprettet."
msgid "Domain was successfully deleted."
-msgstr ""
+msgstr "Domenet ble vellykket slettet."
msgid "Domain was successfully updated."
-msgstr ""
+msgstr "Domenet ble vellykket oppdatert."
msgid "Don't have an account yet?"
msgstr ""
msgid "Don't include description in commit message"
-msgstr ""
+msgstr "Ikke inkluder beskrivelsen i commit-meldingen"
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 "Ikke lim inn den private delen av GPG-nøkkelen. Lim inn den offentlige delen som begynner med ' -----BEGIN PGP PUBLIC KEY BLOCK-----'."
msgid "Don't show again"
-msgstr ""
+msgstr "Ikke vis igjen"
msgid "Done"
-msgstr ""
+msgstr "Fullført"
msgid "Download"
-msgstr ""
+msgstr "Last ned"
msgid "Download %{format}"
-msgstr ""
+msgstr "Last ned %{format}"
msgid "Download %{format}:"
-msgstr ""
+msgstr "Last ned %{format}:"
msgid "Download CSV"
-msgstr ""
+msgstr "Last ned CSV"
msgid "Download artifacts"
-msgstr ""
+msgstr "Last ned artefakter"
msgid "Download as"
-msgstr ""
+msgstr "Last ned som"
msgid "Download as CSV"
-msgstr ""
+msgstr "Last ned som CSV"
msgid "Download asset"
msgstr ""
msgid "Download codes"
-msgstr ""
+msgstr "Last ned koder"
msgid "Download evidence JSON"
-msgstr ""
+msgstr "Last ned bevis-JSON"
msgid "Download export"
-msgstr ""
+msgstr "Last ned eksport"
msgid "Download image"
-msgstr ""
+msgstr "Last ned bilde"
msgid "Download license"
-msgstr ""
+msgstr "Last ned lisens"
msgid "Download raw data (.csv)"
-msgstr ""
+msgstr "Last ned rå data (.csv)"
msgid "Download source code"
-msgstr ""
+msgstr "Last ned kildekoden"
msgid "Download this directory"
-msgstr ""
+msgstr "Last ned denne mappen"
msgid "DownloadCommit|Email Patches"
msgstr ""
@@ -8984,16 +9270,16 @@ msgid "DownloadCommit|Plain Diff"
msgstr ""
msgid "DownloadSource|Download"
-msgstr ""
+msgstr "Last ned"
msgid "Downstream"
-msgstr ""
+msgstr "Nedstrøms"
msgid "Downvotes"
-msgstr ""
+msgstr "Minusstemmer"
msgid "Draft"
-msgstr ""
+msgstr "Utkast"
msgid "Draft merge requests can't be merged."
msgstr ""
@@ -9005,16 +9291,16 @@ msgid "Drop your designs to start your upload."
msgstr ""
msgid "Due Date"
-msgstr ""
+msgstr "MÃ¥ldato"
msgid "Due date"
-msgstr ""
+msgstr "Forfallsdato"
msgid "Duration"
-msgstr ""
+msgstr "Varighet"
msgid "Duration for the last 30 commits"
-msgstr ""
+msgstr "Varigheten til de seneste 30 commitene"
msgid "During this process, you’ll be asked for URLs from GitLab’s side. Use the URLs shown below."
msgstr ""
@@ -9029,16 +9315,16 @@ msgid "Each Runner can be in one of the following states:"
msgstr ""
msgid "Edit"
-msgstr ""
+msgstr "Rediger"
msgid "Edit %{issuable}"
-msgstr ""
+msgstr "Rediger %{issuable}"
msgid "Edit %{name}"
-msgstr ""
+msgstr "Rediger %{name}"
msgid "Edit Comment"
-msgstr ""
+msgstr "Rediger kommentar"
msgid "Edit Deploy Key"
msgstr ""
@@ -9047,68 +9333,71 @@ msgid "Edit Geo Node"
msgstr ""
msgid "Edit Group Hook"
-msgstr ""
+msgstr "Rediger gruppekrok"
msgid "Edit Label"
-msgstr ""
+msgstr "Rediger stempel"
msgid "Edit Milestone"
-msgstr ""
+msgstr "Rediger milepæl"
msgid "Edit Password"
-msgstr ""
+msgstr "Rediger passord"
msgid "Edit Pipeline Schedule %{id}"
msgstr ""
msgid "Edit Release"
-msgstr ""
+msgstr "Rediger utgivelse"
msgid "Edit Requirement"
-msgstr ""
+msgstr "Rediger krav"
msgid "Edit Slack integration"
-msgstr ""
+msgstr "Rediger Slack-intregrasjon"
msgid "Edit Snippet"
-msgstr ""
+msgstr "Rediger utdrag"
msgid "Edit System Hook"
msgstr ""
msgid "Edit application"
-msgstr ""
+msgstr "Rediger applikasjonen"
msgid "Edit board"
-msgstr ""
+msgstr "Rediger tavle"
msgid "Edit comment"
-msgstr ""
+msgstr "Rediger kommentar"
msgid "Edit description"
-msgstr ""
+msgstr "Rediger beskrivelse"
msgid "Edit environment"
-msgstr ""
-
-msgid "Edit file"
-msgstr ""
+msgstr "Rediger miljø"
msgid "Edit files in the editor and commit changes here"
msgstr ""
msgid "Edit fork in Web IDE"
-msgstr ""
+msgstr "Rediger utgreining i nett-IDE"
msgid "Edit group: %{group_name}"
-msgstr ""
+msgstr "Rediger gruppe: %{group_name}"
msgid "Edit identity for %{user_name}"
+msgstr "Rediger identiteten til %{user_name}"
+
+msgid "Edit in Web IDE"
msgstr ""
-msgid "Edit issues"
+msgid "Edit in single-file editor"
msgstr ""
+msgid "Edit issues"
+msgstr "Rediger saker"
+
msgid "Edit iteration"
msgstr ""
@@ -9116,27 +9405,27 @@ msgid "Edit public deploy key"
msgstr ""
msgid "Edit stage"
-msgstr ""
+msgstr "Rediger trinn"
msgid "Edit this release"
-msgstr ""
+msgstr "Rediger denne utgivelsen"
msgid "Edit wiki page"
-msgstr ""
+msgstr "Rediger wiki-side"
msgid "Edit your most recent comment in a thread (from an empty textarea)"
msgstr ""
msgid "Edited %{timeago}"
-msgstr ""
+msgstr "Redigert %{timeago}"
msgid "Editing"
-msgstr ""
+msgstr "Redigerer"
-msgid "Elasticsearch"
+msgid "Elasticsearch AWS IAM credentials"
msgstr ""
-msgid "Elasticsearch AWS IAM credentials"
+msgid "Elasticsearch HTTP client timeout value in seconds."
msgstr ""
msgid "Elasticsearch indexing restrictions"
@@ -9145,9 +9434,6 @@ msgstr ""
msgid "Elasticsearch indexing started"
msgstr ""
-msgid "Elasticsearch integration. Elasticsearch AWS IAM."
-msgstr ""
-
msgid "Elasticsearch reindexing is already in progress"
msgstr ""
@@ -9161,46 +9447,43 @@ msgid "Elasticsearch zero-downtime reindexing"
msgstr ""
msgid "Elastic|None. Select namespaces to index."
-msgstr ""
+msgstr "Ingen. Velg navneområder å indeksere."
msgid "Elastic|None. Select projects to index."
-msgstr ""
+msgstr "Ingen. Velg prosjekter å indeksere."
msgid "Email"
-msgstr ""
+msgstr "E-post"
msgid "Email %{number}"
-msgstr ""
+msgstr "E-post %{number}"
msgid "Email Notification"
-msgstr ""
-
-msgid "Email address"
-msgstr ""
+msgstr "E-postvarsling"
msgid "Email could not be sent"
-msgstr ""
+msgstr "E-post kunne ikke sendes"
msgid "Email display name"
-msgstr ""
+msgstr "E-postvisningsnavn"
msgid "Email not verified. Please verify your email in Salesforce."
-msgstr ""
+msgstr "E-post er ikke bekreftet. Vennligst bekreft din e-post i Salesforce."
msgid "Email notification for unknown sign-ins"
msgstr ""
msgid "Email patch"
-msgstr ""
+msgstr "Send e-post om programrettelse"
msgid "Email restrictions"
-msgstr ""
+msgstr "E-postbegrensninger"
msgid "Email restrictions for sign-ups"
msgstr ""
msgid "Email sent"
-msgstr ""
+msgstr "E-post sendt"
msgid "Email the pipelines status to a list of recipients."
msgstr ""
@@ -9230,20 +9513,23 @@ msgid "EmailError|Your account has been blocked. If you believe this is in error
msgstr ""
msgid "EmailToken|reset it"
-msgstr ""
+msgstr "tilbakestill den"
msgid "EmailToken|resetting..."
-msgstr ""
+msgstr "tilbakestiller …"
msgid "Emails"
-msgstr ""
+msgstr "E-poster"
msgid "Emails sent from Service Desk will have this name"
msgstr ""
-msgid "Emails separated by comma"
+msgid "Emails sent to %{email} will still be supported"
msgstr ""
+msgid "Emails separated by comma"
+msgstr "E-postadresser adskilt med komma"
+
msgid "EmailsOnPushService|Disable code diffs"
msgstr ""
@@ -9266,43 +9552,52 @@ msgid "EmailsOnPushService|Send notifications from the committer's email address
msgstr ""
msgid "Embed"
-msgstr ""
+msgstr "Innbygging"
msgid "Empty file"
-msgstr ""
+msgstr "Tom fil"
msgid "Enable"
+msgstr "Slå på"
+
+msgid "Enable %{link_start}Gitpod%{link_end} integration to launch a development environment in your browser directly from GitLab."
msgstr ""
msgid "Enable Auto DevOps"
+msgstr "Aktiver Auto DevOps"
+
+msgid "Enable Gitpod"
msgstr ""
-msgid "Enable HTML emails"
+msgid "Enable Gitpod?"
msgstr ""
+msgid "Enable HTML emails"
+msgstr "Aktiver HTML e-poster"
+
msgid "Enable Incident Management inbound alert limit"
msgstr ""
msgid "Enable PlantUML"
-msgstr ""
+msgstr "Skru på PlantUML"
msgid "Enable Pseudonymizer data collection"
msgstr ""
msgid "Enable Seat Link"
-msgstr ""
+msgstr "Skru på Seat Link"
msgid "Enable Spam Check via external API endpoint"
msgstr ""
msgid "Enable access to Grafana"
-msgstr ""
+msgstr "Skru på tilgang til Grafana"
msgid "Enable access to the Performance Bar for a given group."
msgstr ""
msgid "Enable and configure Grafana."
-msgstr ""
+msgstr "Skru på og sett opp Grafana."
msgid "Enable and configure Prometheus metrics."
msgstr ""
@@ -9317,13 +9612,13 @@ msgid "Enable email restrictions for sign ups"
msgstr ""
msgid "Enable error tracking"
-msgstr ""
+msgstr "Skru på feilsporing"
msgid "Enable feature to choose access level"
msgstr ""
msgid "Enable for this project"
-msgstr ""
+msgstr "Aktiver for dette prosjektet"
msgid "Enable group Runners"
msgstr ""
@@ -9332,19 +9627,19 @@ msgid "Enable header and footer in emails"
msgstr ""
msgid "Enable integration"
-msgstr ""
+msgstr "Skru på integrering"
msgid "Enable maintenance mode"
-msgstr ""
+msgstr "Skru på vedlikeholdsmodus"
msgid "Enable mirror configuration"
-msgstr ""
+msgstr "Skru på speiloppsett"
msgid "Enable or disable Seat Link."
-msgstr ""
+msgstr "Skru på eller skru av Seat Link."
msgid "Enable or disable keyboard shortcuts"
-msgstr ""
+msgstr "Skru av eller på tastatursnarveier"
msgid "Enable or disable the Pseudonymizer data collection."
msgstr ""
@@ -9356,7 +9651,7 @@ msgid "Enable protected paths rate limit"
msgstr ""
msgid "Enable proxy"
-msgstr ""
+msgstr "Skru på mellomtjener"
msgid "Enable reCAPTCHA or Akismet and set IP limits. For reCAPTCHA, we currently only support %{recaptcha_v2_link_start}v2%{recaptcha_v2_link_end}"
msgstr ""
@@ -9368,7 +9663,7 @@ msgid "Enable snowplow tracking"
msgstr ""
msgid "Enable two-factor authentication"
-msgstr ""
+msgstr "Skru på 2-trinnsautentisering"
msgid "Enable usage ping"
msgstr ""
@@ -9380,19 +9675,19 @@ msgid "EnableReviewApp|%{stepStart}Step 1%{stepEnd}. Ensure you have Kubernetes
msgstr ""
msgid "EnableReviewApp|%{stepStart}Step 2%{stepEnd}. Copy the following snippet:"
-msgstr ""
+msgstr "%{stepStart}Trinn 2%{stepEnd}. Kopier det følgende utdraget:"
msgid "EnableReviewApp|%{stepStart}Step 3%{stepEnd}. Add it to the project %{linkStart}gitlab-ci.yml%{linkEnd} file."
msgstr ""
msgid "EnableReviewApp|Close"
-msgstr ""
+msgstr "Lukk"
msgid "EnableReviewApp|Copy snippet text"
-msgstr ""
+msgstr "Kopier utdragstekst"
msgid "Enabled"
-msgstr ""
+msgstr "Skrudd på"
msgid "Enabled Git access protocols"
msgstr ""
@@ -9406,11 +9701,8 @@ msgstr ""
msgid "Encountered an error while rendering: %{err}"
msgstr ""
-msgid "End date"
-msgstr ""
-
msgid "Ends at (UTC)"
-msgstr ""
+msgstr "Slutter den (UTC)"
msgid "Enforce DNS rebinding attack protection"
msgstr ""
@@ -9425,28 +9717,28 @@ msgid "Ensure your %{linkStart}environment is part of the deploy stage%{linkEnd}
msgstr ""
msgid "Enter 2FA for Admin Mode"
-msgstr ""
+msgstr "Skriv inn 2FA for adminmodus"
msgid "Enter Admin Mode"
-msgstr ""
+msgstr "GÃ¥ inn i adminmodus"
msgid "Enter IP address range"
-msgstr ""
+msgstr "Skriv inn IP-adresseområde"
msgid "Enter a number"
-msgstr ""
+msgstr "Skriv inn et nummer"
msgid "Enter a whole number between 0 and 100"
-msgstr ""
+msgstr "Skriv inn et helt tall mellom 0 og 100"
msgid "Enter at least three characters to search"
-msgstr ""
+msgstr "Skriv inn minst tre tegn for å søke"
msgid "Enter board name"
msgstr ""
msgid "Enter domain"
-msgstr ""
+msgstr "Skriv inn domene"
msgid "Enter in your Bitbucket Server URL and personal access token below"
msgstr ""
@@ -9458,13 +9750,13 @@ msgid "Enter merge request URLs"
msgstr ""
msgid "Enter new %{field_title}"
-msgstr ""
+msgstr "Skriv inn ny %{field_title}"
msgid "Enter new AWS Secret Access Key"
msgstr ""
msgid "Enter number of issues"
-msgstr ""
+msgstr "Skriv inn antall saker"
msgid "Enter one or more user ID separated by commas"
msgstr ""
@@ -9473,16 +9765,16 @@ msgid "Enter the code from the two-factor app on your mobile device. If you've l
msgstr ""
msgid "Enter the issue description"
-msgstr ""
+msgstr "Skriv inn sakens beskrivelse"
msgid "Enter the issue title"
-msgstr ""
+msgstr "Skriv inn problemets tittel"
msgid "Enter the merge request description"
msgstr ""
msgid "Enter the merge request title"
-msgstr ""
+msgstr "Skriv inn fletteforespørselens tittel"
msgid "Enter the name of your application, and we'll return a unique %{type}."
msgstr ""
@@ -9494,7 +9786,7 @@ msgid "Enter your password to approve"
msgstr ""
msgid "Environment"
-msgstr ""
+msgstr "Miljø"
msgid "Environment does not have deployments"
msgstr ""
@@ -9506,10 +9798,10 @@ msgid "Environment is required for Stages::VariableEndpointInserter"
msgstr ""
msgid "Environment scope"
-msgstr ""
+msgstr "Miljøomfang"
msgid "Environment variables are applied to environments via the Runner. You can use environment variables for passwords, secret keys, etc. Make variables available to the running application by prepending the variable key with %{code_open}K8S_SECRET_%{code_close}. You can set variables to be:"
-msgstr ""
+msgstr "Miljøvariabler brukes på miljøer via Runner. Du kan bruke miljøvariabler til passord, hemmelige nøkler, osv. Gjør variabler tilgjengelig for den kjørende applikasjonen ved å forhåndsstille variabelnøkkelen med %{code_open}K8S_SECRET_%{code_close}. Du kan angi at variabler skal være:"
msgid "Environment variables are configured by your administrator to be %{link_start}protected%{link_end} by default"
msgstr ""
@@ -9518,10 +9810,10 @@ msgid "Environment variables on this GitLab instance are configured to be %{link
msgstr ""
msgid "Environment:"
-msgstr ""
+msgstr "Miljø:"
msgid "EnvironmentDashboard|API"
-msgstr ""
+msgstr "API"
msgid "EnvironmentDashboard|Created through the Deployment API"
msgstr ""
@@ -9530,16 +9822,16 @@ msgid "EnvironmentDashboard|You are looking at the last updated environment"
msgstr ""
msgid "Environments"
-msgstr ""
+msgstr "Miljøer"
msgid "Environments Dashboard"
-msgstr ""
+msgstr "Miljøkontrollpanel"
msgid "Environments allow you to track deployments of your application %{link_to_read_more}."
msgstr ""
msgid "Environments in %{name}"
-msgstr ""
+msgstr "Miljøer i %{name}"
msgid "EnvironmentsAlert|%{severity} • %{title} %{text}. %{linkStart}View Details%{linkEnd} · %{startedAt} "
msgstr ""
@@ -9548,27 +9840,27 @@ msgid "EnvironmentsDashboard|Add a project to the dashboard"
msgstr ""
msgid "EnvironmentsDashboard|Add projects"
-msgstr ""
+msgstr "Legg til prosjekter"
msgid "EnvironmentsDashboard|Environments Dashboard"
msgstr ""
msgid "EnvironmentsDashboard|Job: %{job}"
-msgstr ""
+msgstr "Jobb: %{job}"
msgid "EnvironmentsDashboard|More actions"
-msgstr ""
+msgstr "Flere handlinger"
msgid "EnvironmentsDashboard|More information"
-msgstr ""
+msgstr "Mere informasjon"
msgid "EnvironmentsDashboard|Remove"
-msgstr ""
+msgstr "Fjern"
msgid "EnvironmentsDashboard|The environments dashboard provides a summary of each project's environments' status, including pipeline and alert statuses."
msgstr ""
-msgid "EnvironmentsDashboard|This dashboard displays a maximum of 7 projects and 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
+msgid "EnvironmentsDashboard|This dashboard displays 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
msgstr ""
msgid "Environments|An error occurred while canceling the auto stop, please try again"
@@ -9578,10 +9870,10 @@ msgid "Environments|An error occurred while deleting the environment. Check if t
msgstr ""
msgid "Environments|An error occurred while fetching the environments."
-msgstr ""
+msgstr "Det oppstod en feil mens miljøene ble hentet."
msgid "Environments|An error occurred while making the request."
-msgstr ""
+msgstr "Det oppstod en feil under forespørselen."
msgid "Environments|An error occurred while re-deploying the environment, please try again"
msgstr ""
@@ -9590,16 +9882,16 @@ msgid "Environments|An error occurred while rolling back the environment, please
msgstr ""
msgid "Environments|An error occurred while stopping the environment, please try again"
-msgstr ""
+msgstr "Det oppstod en feil ved stopping av miljøet, vennligst prøv igjen"
msgid "Environments|Are you sure you want to stop this environment?"
-msgstr ""
+msgstr "Er du sikker på at du vil stoppe dette miljøet?"
msgid "Environments|Auto stop in"
-msgstr ""
+msgstr "Autostopp om"
msgid "Environments|Auto stops %{auto_stop_time}"
-msgstr ""
+msgstr "Autostopper kl. %{auto_stop_time}"
msgid "Environments|Commit"
msgstr ""
@@ -9608,13 +9900,13 @@ msgid "Environments|Currently showing %{fetched} results."
msgstr ""
msgid "Environments|Currently showing all results."
-msgstr ""
+msgstr "Viser for øyeblikket alle resultater."
msgid "Environments|Delete"
-msgstr ""
+msgstr "Slett"
msgid "Environments|Delete environment"
-msgstr ""
+msgstr "Slett miljø"
msgid "Environments|Deleting the '%{environmentName}' environment cannot be undone. Do you want to delete it anyway?"
msgstr ""
@@ -9629,10 +9921,10 @@ msgid "Environments|Enable review app"
msgstr ""
msgid "Environments|Environment"
-msgstr ""
+msgstr "Miljø"
msgid "Environments|Environments"
-msgstr ""
+msgstr "Miljøer"
msgid "Environments|Environments are places where code gets deployed, such as staging or production."
msgstr ""
@@ -9641,25 +9933,25 @@ msgid "Environments|Install Elastic Stack on your cluster to enable advanced que
msgstr ""
msgid "Environments|Job"
-msgstr ""
+msgstr "Jobb"
msgid "Environments|Learn about environments"
-msgstr ""
+msgstr "Lær om miljøer"
msgid "Environments|Learn more about stopping environments"
-msgstr ""
+msgstr "Lær mer om hvordan stoppe miljøer"
msgid "Environments|Logs from %{start} to %{end}."
msgstr ""
msgid "Environments|Managed apps"
-msgstr ""
+msgstr "Behandlede apper"
msgid "Environments|More information"
-msgstr ""
+msgstr "Mere informasjon"
msgid "Environments|New environment"
-msgstr ""
+msgstr "Nytt miljø"
msgid "Environments|No deployed environments"
msgstr ""
@@ -9668,16 +9960,16 @@ msgid "Environments|No deployments yet"
msgstr ""
msgid "Environments|No pod selected"
-msgstr ""
+msgstr "Ingen pod er valgt"
msgid "Environments|No pods to display"
-msgstr ""
+msgstr "Ingen podder å vise"
msgid "Environments|Note that this action will stop the environment, but it will %{emphasisStart}not%{emphasisEnd} have an effect on any existing deployment due to no “stop environment action†being defined in the %{ciConfigLinkStart}.gitlab-ci.yml%{ciConfigLinkEnd} file."
-msgstr ""
+msgstr "Merk at denne handlingen vil stoppe miljøet, men det vil %{emphasisStart}ikke%{emphasisEnd} ha en effekt på noen eksisterende distribusjoner fordi ingen «Stopp miljøhandling» er definert i %{ciConfigLinkStart}.gitlab-ci.yml%{ciConfigLinkEnd}-filen."
msgid "Environments|Note that this action will stop the environment, but it will %{emphasis_start}not%{emphasis_end} have an effect on any existing deployment due to no “stop environment action†being defined in the %{ci_config_link_start}.gitlab-ci.yml%{ci_config_link_end} file."
-msgstr ""
+msgstr "Merk at denne handlingen vil stoppe miljøet, men det vil %{emphasis_start}ikke%{emphasis_end} ha en effekt på noen eksisterende distribusjoner fordi ingen «Stopp miljøhandling» er definert i %{ci_config_link_start}.gitlab-ci.yml%{ci_config_link_end}-filen."
msgid "Environments|Open live environment"
msgstr ""
@@ -9710,22 +10002,22 @@ msgid "Environments|Rollback environment %{name}?"
msgstr ""
msgid "Environments|Select pod"
-msgstr ""
+msgstr "Velg pod"
msgid "Environments|Show all"
-msgstr ""
+msgstr "Vis alle"
msgid "Environments|Stop"
-msgstr ""
+msgstr "Stopp"
msgid "Environments|Stop environment"
-msgstr ""
+msgstr "Stopp miljø"
msgid "Environments|Stopping"
-msgstr ""
+msgstr "Stopper"
msgid "Environments|There was an error fetching the logs. Please try again."
-msgstr ""
+msgstr "Det oppstod en feil under innhenting av loggfilene. Vennligst prøv igjen."
msgid "Environments|This action will relaunch the job for commit %{commit_id}, putting the environment in a previous version. Are you sure you want to continue?"
msgstr ""
@@ -9734,40 +10026,40 @@ msgid "Environments|This action will relaunch the job for commit %{linkStart}%{c
msgstr ""
msgid "Environments|This action will run the job defined by %{environment_name} for commit %{commit_id}, putting the environment in a previous version. You can revert it by re-deploying the latest version of your application. Are you sure you want to continue?"
-msgstr ""
+msgstr "Denne handlingen vil kjøre jobben som er definert av %{environment_name} for innsmettingen %{commit_id}, som setter miljøet til en tidligere versjon. Du kan tilbakestille det ved å distribuere den nyeste versjonen av applikasjonen på nytt. Er du sikker på at du vil fortsette?"
msgid "Environments|This action will run the job defined by %{name} for commit %{linkStart}%{commitId}%{linkEnd} putting the environment in a previous version. You can revert it by re-deploying the latest version of your application. Are you sure you want to continue?"
-msgstr ""
+msgstr "Denne handlingen vil kjøre jobben som er definert av %{name} for innsmettingen %{linkStart}%{commitId}%{linkEnd}, som setter miljøet til en tidligere versjon. Du kan tilbakestille det ved å distribuere den nyeste versjonen av applikasjonen på nytt. Er du sikker på at du vil fortsette?"
msgid "Environments|Updated"
-msgstr ""
+msgstr "Oppdatert"
msgid "Environments|You don't have any environments right now"
-msgstr ""
+msgstr "Du har ingen miljøer akkurat nå"
msgid "Environments|protected"
-msgstr ""
+msgstr "beskyttet"
msgid "Epic"
-msgstr ""
+msgstr "Epos"
msgid "Epic cannot be found."
-msgstr ""
+msgstr "Eposen ble ikke funnet."
msgid "Epic events"
-msgstr ""
+msgstr "Epos-hendelser"
msgid "Epic not found for given params"
msgstr ""
msgid "Epics"
-msgstr ""
+msgstr "Eposer"
msgid "Epics Roadmap"
-msgstr ""
+msgstr "Epos-veikart"
msgid "Epics and Issues"
-msgstr ""
+msgstr "Eposer og saker"
msgid "Epics let you manage your portfolio of projects more efficiently and with less effort"
msgstr ""
@@ -9776,10 +10068,10 @@ msgid "Epics, Issues, and Merge Requests"
msgstr ""
msgid "Epics|Add a new epic"
-msgstr ""
+msgstr "Legg til et nytt epos"
msgid "Epics|Add an existing epic"
-msgstr ""
+msgstr "Legg til et eksisterende epos"
msgid "Epics|An error occurred while saving the %{epicDateType} date"
msgstr ""
@@ -9791,25 +10083,25 @@ msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd}
msgstr ""
msgid "Epics|Enter a title for your epic"
-msgstr ""
+msgstr "Skriv inn en tittel på eposet ditt"
msgid "Epics|How can I solve this?"
-msgstr ""
+msgstr "Hvordan kan jeg løse dette?"
msgid "Epics|Leave empty to inherit from milestone dates"
msgstr ""
msgid "Epics|More information"
-msgstr ""
+msgstr "Mer informasjon"
msgid "Epics|Remove epic"
-msgstr ""
+msgstr "Fjern epos"
msgid "Epics|Remove issue"
-msgstr ""
+msgstr "Fjern saker"
msgid "Epics|Show more"
-msgstr ""
+msgstr "Vis mer"
msgid "Epics|Something went wrong while assigning issue to epic."
msgstr ""
@@ -9818,7 +10110,7 @@ msgid "Epics|Something went wrong while creating child epics."
msgstr ""
msgid "Epics|Something went wrong while creating issue."
-msgstr ""
+msgstr "Noe gikk galt under opprettelse av en sak."
msgid "Epics|Something went wrong while fetching child epics."
msgstr ""
@@ -9827,16 +10119,16 @@ msgid "Epics|Something went wrong while fetching group epics."
msgstr ""
msgid "Epics|Something went wrong while moving item."
-msgstr ""
+msgstr "Noe gikk galt under flytting av gjenstand."
msgid "Epics|Something went wrong while ordering item."
-msgstr ""
+msgstr "Noe gikk galt under sortering av gjenstand."
msgid "Epics|Something went wrong while removing issue from epic."
msgstr ""
msgid "Epics|These dates affect how your epics appear in the roadmap. Dates from milestones come from the milestones assigned to issues in the epic. You can also set fixed dates or remove them entirely."
-msgstr ""
+msgstr "Disse datoene påvirker hvordan eposer vises i veikartet. Datoer fra milepæler kommer fra milepælene som er tildelt saker i eposet. Du kan også angi fastsatte datoer eller fjerne dem helt."
msgid "Epics|This epic and any containing child epics are confidential and should only be visible to team members with at least Reporter access."
msgstr ""
@@ -9845,34 +10137,34 @@ msgid "Epics|This will also remove any descendents of %{bStart}%{targetEpicTitle
msgstr ""
msgid "Epics|To schedule your epic's %{epicDateType} date based on milestones, assign a milestone with a %{epicDateType} date to any issue in the epic."
-msgstr ""
+msgstr "For å planlegge en epos sin %{epicDateType} dato basert på milepæler, tilordne en milepæl med %{epicDateType}-dato til enhver sak i eposen."
msgid "Epics|Unable to perform this action"
msgstr ""
msgid "Epics|Unable to save epic. Please try again"
-msgstr ""
+msgstr "Klarte ikke å lagre eposet. Vennligst prøv igjen"
msgid "Epics|due"
msgstr ""
msgid "Epics|start"
-msgstr ""
+msgstr "start"
msgid "Error"
-msgstr ""
+msgstr "Feil"
msgid "Error Details"
-msgstr ""
+msgstr "Feildetaljer"
msgid "Error Tracking"
msgstr ""
msgid "Error creating epic"
-msgstr ""
+msgstr "Feil under oppretting av epos"
msgid "Error creating label."
-msgstr ""
+msgstr "Feil ved oppretting av stempel."
msgid "Error creating new iteration"
msgstr ""
@@ -9881,7 +10173,7 @@ msgid "Error creating repository for snippet with id %{snippet_id}"
msgstr ""
msgid "Error creating the snippet"
-msgstr ""
+msgstr "Feil under opprettelse av utdrag"
msgid "Error deleting %{issuableType}"
msgstr ""
@@ -9889,23 +10181,26 @@ msgstr ""
msgid "Error deleting project. Check logs for error details."
msgstr ""
+msgid "Error fetching burnup chart data"
+msgstr ""
+
msgid "Error fetching diverging counts for branches. Please try again."
msgstr ""
msgid "Error fetching forked projects. Please try again."
-msgstr ""
+msgstr "Feil under innhenting av utgreinede prosjektet. Vennligst prøv igjen."
msgid "Error fetching labels."
-msgstr ""
+msgstr "Feil ved henting av etikketter."
msgid "Error fetching network graph."
-msgstr ""
+msgstr "Feil ved henting av nettverksgrafer."
msgid "Error fetching payload data."
msgstr ""
msgid "Error fetching projects"
-msgstr ""
+msgstr "Feil under innhenting av prosjekter"
msgid "Error fetching refs"
msgstr ""
@@ -9914,10 +10209,10 @@ msgid "Error fetching the dependency list. Please check your network connection
msgstr ""
msgid "Error loading branch data. Please try again."
-msgstr ""
+msgstr "Feil under innlasting av gren-data. Vennligst prøv igjen."
msgid "Error loading branches."
-msgstr ""
+msgstr "Feil under innlasting av grener."
msgid "Error loading burndown chart data"
msgstr ""
@@ -9926,40 +10221,40 @@ msgid "Error loading countries data."
msgstr ""
msgid "Error loading file viewer."
-msgstr ""
+msgstr "Feil under innlasting av filfremviser."
msgid "Error loading issues"
-msgstr ""
+msgstr "Feil under innlasting av saker"
msgid "Error loading iterations"
msgstr ""
msgid "Error loading last commit."
-msgstr ""
+msgstr "Feil under innlasting av nyeste commit."
msgid "Error loading markdown preview"
-msgstr ""
+msgstr "Feil under innlasting av Markdown-forhåndsvisning"
msgid "Error loading merge requests."
-msgstr ""
+msgstr "Feil under innlasting av fletteforespørsler."
msgid "Error loading milestone tab"
-msgstr ""
+msgstr "Feil under innlasting av milepælfanen"
msgid "Error loading project data. Please try again."
-msgstr ""
+msgstr "Feil under innlasting av prosjektdata. Vennligst prøv igjen."
msgid "Error loading template types."
-msgstr ""
+msgstr "Feil under innlasting av maltyper."
msgid "Error loading template."
-msgstr ""
+msgstr "Feil ved henting av mal."
msgid "Error loading viewer"
msgstr ""
msgid "Error message:"
-msgstr ""
+msgstr "Feilmelding:"
msgid "Error occurred when fetching sidebar data"
msgstr ""
@@ -9967,14 +10262,17 @@ msgstr ""
msgid "Error occurred when saving assignees"
msgstr ""
+msgid "Error occurred when saving reviewers"
+msgstr ""
+
msgid "Error occurred when toggling the notification subscription"
msgstr ""
msgid "Error occurred while updating the issue status"
-msgstr ""
+msgstr "En feil oppstod under oppdatering av sakens status"
msgid "Error occurred while updating the issue weight"
-msgstr ""
+msgstr "En feil oppstod under oppdatering av sakens vektlegging"
msgid "Error occurred. A blocked user cannot be deactivated"
msgstr ""
@@ -9983,13 +10281,13 @@ msgid "Error occurred. A blocked user must be unblocked to be activated"
msgstr ""
msgid "Error occurred. User was not blocked"
-msgstr ""
+msgstr "En feil oppstod. Brukeren ble ikke blokkert"
msgid "Error occurred. User was not confirmed"
-msgstr ""
+msgstr "En feil oppstod. Brukeren ble ikke bekreftet"
msgid "Error occurred. User was not unblocked"
-msgstr ""
+msgstr "En feil oppstod. Brukeren ble ikke ublokkert"
msgid "Error occurred. User was not unlocked"
msgstr ""
@@ -9998,7 +10296,7 @@ msgid "Error rendering markdown preview"
msgstr ""
msgid "Error saving label update."
-msgstr ""
+msgstr "Feil ved oppdatering av stempel."
msgid "Error setting up editor. Please try again."
msgstr ""
@@ -10007,7 +10305,7 @@ msgid "Error tracking"
msgstr ""
msgid "Error updating %{issuableType}"
-msgstr ""
+msgstr "Feil under oppdatering av %{issuableType}"
msgid "Error updating status for all to-do items."
msgstr ""
@@ -10016,13 +10314,13 @@ msgid "Error updating status of to-do item."
msgstr ""
msgid "Error updating the snippet"
-msgstr ""
+msgstr "Feil under oppdatering av utdrag"
msgid "Error uploading file"
-msgstr ""
+msgstr "Feil ved opplasting av fil"
msgid "Error uploading file: %{stripped}"
-msgstr ""
+msgstr "Feil under opplasting av fil: %{stripped}"
msgid "Error while loading the merge request. Please try again."
msgstr ""
@@ -10037,13 +10335,13 @@ msgid "Error with Akismet. Please check the logs for more info."
msgstr ""
msgid "Error: %{error_message}"
-msgstr ""
+msgstr "Feil: %{error_message}"
msgid "Error: Unable to create deploy freeze"
msgstr ""
msgid "ErrorTracking|Active"
-msgstr ""
+msgstr "Aktiv"
msgid "ErrorTracking|After adding your Auth Token, use the 'Connect' button to load projects"
msgstr ""
@@ -10061,94 +10359,94 @@ msgid "ErrorTracking|If you self-host Sentry, enter the full URL of your Sentry
msgstr ""
msgid "ErrorTracking|No projects available"
-msgstr ""
+msgstr "Ingen prosjekter er tilgjengelige"
msgid "ErrorTracking|Select project"
-msgstr ""
+msgstr "Velg prosjekt"
msgid "ErrorTracking|To enable project selection, enter a valid Auth Token"
msgstr ""
msgid "Errors"
-msgstr ""
+msgstr "Feil"
msgid "Errors:"
-msgstr ""
+msgstr "Feil:"
msgid "Estimate"
-msgstr ""
+msgstr "Estimat"
msgid "Estimated"
-msgstr ""
+msgstr "Anslått"
msgid "EventFilterBy|Filter by all"
msgstr ""
msgid "EventFilterBy|Filter by comments"
-msgstr ""
+msgstr "Filtrer etter kommentarer"
msgid "EventFilterBy|Filter by designs"
-msgstr ""
+msgstr "Filtrer etter design"
msgid "EventFilterBy|Filter by epic events"
msgstr ""
msgid "EventFilterBy|Filter by issue events"
-msgstr ""
+msgstr "Filtrer etter sakshendelser"
msgid "EventFilterBy|Filter by merge events"
-msgstr ""
+msgstr "Filtrer etter flettehendelser"
msgid "EventFilterBy|Filter by push events"
-msgstr ""
+msgstr "Filtrer etter pushhendelser"
msgid "EventFilterBy|Filter by team"
-msgstr ""
+msgstr "Filtrer etter team"
msgid "EventFilterBy|Filter by wiki"
-msgstr ""
+msgstr "Filtrer etter wiki"
msgid "Events"
-msgstr ""
+msgstr "Hendelser"
msgid "Events in %{project_path}"
-msgstr ""
+msgstr "Hendelser i %{project_path}"
msgid "Every %{action} attempt has failed: %{job_error_message}. Please try again."
msgstr ""
msgid "Every day"
-msgstr ""
+msgstr "Hver dag"
msgid "Every day (at %{time})"
-msgstr ""
+msgstr "Hver dag (kl. %{time})"
msgid "Every month"
-msgstr ""
+msgstr "Hver måned"
msgid "Every month (Day %{day} at %{time})"
-msgstr ""
+msgstr "Hver måned (Dag %{day} kl. %{time})"
msgid "Every three months"
-msgstr ""
+msgstr "Hver 3. måned"
msgid "Every two weeks"
-msgstr ""
+msgstr "Annenhver uke"
msgid "Every week"
-msgstr ""
+msgstr "Hver uke"
msgid "Every week (%{weekday} at %{time})"
-msgstr ""
+msgstr "Hver uke (%{weekday} kl. %{time})"
msgid "Everyone"
-msgstr ""
+msgstr "Alle"
msgid "Everyone With Access"
-msgstr ""
+msgstr "Alle med tilgang"
msgid "Everyone can contribute"
-msgstr ""
+msgstr "Alle kan bidra"
msgid "Everything on your to-do list is marked as done."
msgstr ""
@@ -10178,10 +10476,10 @@ msgid "Exactly one of %{attributes} is required"
msgstr ""
msgid "Example: %{ip_address}. %{read_more_link}."
-msgstr ""
+msgstr "Eksempel: %{ip_address}. %{read_more_link}."
msgid "Example: @sub\\.company\\.com$"
-msgstr ""
+msgstr "Eksempel: @sub\\.firma\\.com$"
msgid "Example: My Value Stream"
msgstr ""
@@ -10193,121 +10491,124 @@ msgid "Except policy:"
msgstr ""
msgid "Excluding merge commits. Limited to %{limit} commits."
-msgstr ""
+msgstr "Ekskludert innflettings-commiter. Begrenset til %{limit} commiter."
msgid "Excluding merge commits. Limited to 6,000 commits."
-msgstr ""
+msgstr "Ekskludert innflettings-commiter. Begrenset til 6 000 commiter."
msgid "Existing branch name, tag, or commit SHA"
-msgstr ""
+msgstr "Eksisterende greinnavn, etikett, eller commit-SHA"
msgid "Existing members and groups"
-msgstr ""
+msgstr "Eksisterende medlemmer og grupper"
msgid "Existing projects may be moved into a group"
msgstr ""
msgid "Existing projects will be able to use expiration policies. Avoid enabling this if an external Container Registry is being used, as there is a performance risk if many images exist on one project."
-msgstr ""
+msgstr "Eksisterende prosjekter vil kunne bruke utløpsretningslinjer. Unngå å aktivere dette hvis et eksternt containerregister blir brukt, da det er en ytelsesrisiko hvis det finnes mange bilder i ett prosjekt."
msgid "Existing sign in methods may be removed"
msgstr ""
msgid "Expand"
-msgstr ""
+msgstr "Utvid"
msgid "Expand all"
-msgstr ""
+msgstr "Utvid alle"
-msgid "Expand approvers"
+msgid "Expand all files"
msgstr ""
-msgid "Expand dropdown"
+msgid "Expand all threads"
msgstr ""
+msgid "Expand approvers"
+msgstr "Utvid godkjennere"
+
msgid "Expand milestones"
-msgstr ""
+msgstr "Utvid milepæler"
msgid "Expand sidebar"
-msgstr ""
+msgstr "Utvid sidepanelet"
msgid "Expected documents: %{expected_documents}"
-msgstr ""
+msgstr "Forventede dokumenter: %{expected_documents}"
msgid "Experienced"
-msgstr ""
+msgstr "Erfaren"
msgid "Expiration"
-msgstr ""
+msgstr "Utløp"
msgid "Expiration date"
-msgstr ""
+msgstr "Utløpsdato"
msgid "Expired"
-msgstr ""
+msgstr "Utløpt"
msgid "Expired %{expiredOn}"
-msgstr ""
+msgstr "Utløpt %{expiredOn}"
msgid "Expired:"
-msgstr ""
+msgstr "Utløpt:"
msgid "Expires"
-msgstr ""
+msgstr "Utløper"
msgid "Expires at"
-msgstr ""
+msgstr "Utløper på"
msgid "Expires in %{expires_at}"
-msgstr ""
+msgstr "Utløper om %{expires_at}"
msgid "Expires on"
-msgstr ""
+msgstr "Utløper den"
msgid "Expires:"
-msgstr ""
+msgstr "Utløper:"
msgid "Explain the problem. If appropriate, provide a link to the relevant issue or comment."
msgstr ""
msgid "Explore"
-msgstr ""
+msgstr "Utforsk"
msgid "Explore GitLab"
-msgstr ""
+msgstr "Utforsk GitLab"
msgid "Explore Groups"
-msgstr ""
+msgstr "Utforsk grupper"
msgid "Explore groups"
-msgstr ""
+msgstr "Utforsk grupper"
msgid "Explore projects"
-msgstr ""
+msgstr "Utforsk prosjekter"
msgid "Explore public groups"
-msgstr ""
+msgstr "Utforsk offentlige grupper"
msgid "Export"
-msgstr ""
+msgstr "Eksporter"
msgid "Export as CSV"
-msgstr ""
+msgstr "Eksporter som CSV"
msgid "Export group"
-msgstr ""
+msgstr "Eksporter gruppe"
msgid "Export issues"
-msgstr ""
+msgstr "Eksporter saker"
msgid "Export project"
-msgstr ""
+msgstr "Eksporter prosjekt"
msgid "Export this group with all related data to a new GitLab instance. Once complete, you can import the data file from the \"New Group\" page."
msgstr ""
msgid "Export this project with all its related data in order to move your project to a new GitLab instance. Once the export is finished, you can import the file from the \"New Project\" page."
-msgstr ""
+msgstr "Eksporter dette prosjektet med alle dens relaterte data for å flytte prosjektet til en ny GitLab-instans. Når eksporteringen er fullført, kan du importere filen fra siden «Nytt prosjekt»."
msgid "Export variable to pipelines running on protected branches and tags only."
msgstr ""
@@ -10316,16 +10617,16 @@ msgid "External Classification Policy Authorization"
msgstr ""
msgid "External ID"
-msgstr ""
+msgstr "Ekstern ID"
msgid "External URL"
-msgstr ""
+msgstr "Ekstern URL"
msgid "External Wiki"
-msgstr ""
+msgstr "Ekstern wiki"
msgid "External authentication"
-msgstr ""
+msgstr "Ekstern autentisering"
msgid "External authorization denied access to this project"
msgstr ""
@@ -10346,31 +10647,31 @@ msgid "ExternalAuthorizationService|When no classification label is set the defa
msgstr ""
msgid "ExternalWikiService|External Wiki"
-msgstr ""
+msgstr "Ekstern wiki"
msgid "ExternalWikiService|Replaces the link to the internal wiki with a link to an external wiki."
msgstr ""
msgid "ExternalWikiService|The URL of the external Wiki"
-msgstr ""
+msgstr "Den eksterne wikiens URL"
msgid "Facebook"
-msgstr ""
+msgstr "Facebook"
msgid "Failed"
-msgstr ""
+msgstr "Mislykket"
msgid "Failed Jobs"
-msgstr ""
+msgstr "Mislykkede jobber"
msgid "Failed on"
msgstr ""
msgid "Failed to add a Zoom meeting"
-msgstr ""
+msgstr "Mislyktes i å legge til et Zoom-møte"
msgid "Failed to apply commands."
-msgstr ""
+msgstr "Mislyktes i å benytte kommandoer."
msgid "Failed to assign a user because no user was found."
msgstr ""
@@ -10385,12 +10686,15 @@ msgid "Failed to cancel auto stop because you do not have permission to update t
msgstr ""
msgid "Failed to change the owner"
-msgstr ""
+msgstr "Klarte ikke å endre eieren"
msgid "Failed to check related branches."
msgstr ""
msgid "Failed to create Merge Request. Please try again."
+msgstr "Klarte ikke å opprette fletteforespørsel. Vennligst prøv igjen."
+
+msgid "Failed to create To-Do for the design."
msgstr ""
msgid "Failed to create a branch for this issue. Please try again."
@@ -10400,13 +10704,13 @@ msgid "Failed to create import label for jira import."
msgstr ""
msgid "Failed to create repository"
-msgstr ""
+msgstr "Mislyktes i å opprette kodelager"
msgid "Failed to create resources"
-msgstr ""
+msgstr "Mislyktes i å opprette ressurser"
msgid "Failed to create wiki"
-msgstr ""
+msgstr "Mislyktes i å opprette wiki"
msgid "Failed to delete board. Please try again."
msgstr ""
@@ -10424,17 +10728,23 @@ msgid "Failed to get ref."
msgstr ""
msgid "Failed to install."
-msgstr ""
+msgstr "Mislyktes i å installere."
msgid "Failed to load assignees. Please try again."
-msgstr ""
+msgstr "Klarte ikke å laste inn tilordnede. Vennligst prøv igjen."
msgid "Failed to load authors. Please try again."
msgstr ""
-msgid "Failed to load emoji list."
+msgid "Failed to load branches. Please try again."
msgstr ""
+msgid "Failed to load deploy keys."
+msgstr ""
+
+msgid "Failed to load emoji list."
+msgstr "Klarte ikke å laste inn emojilisten."
+
msgid "Failed to load error details from Sentry."
msgstr ""
@@ -10445,15 +10755,24 @@ msgid "Failed to load group activity metrics. Please try again."
msgstr ""
msgid "Failed to load groups & users."
+msgstr "Mislyktes i å laste inn grupper og brukere."
+
+msgid "Failed to load groups, users and deploy keys."
msgstr ""
msgid "Failed to load labels. Please try again."
-msgstr ""
+msgstr "Mislyktes i å laste inn stempler. Vennligst prøv igjen."
msgid "Failed to load milestones. Please try again."
-msgstr ""
+msgstr "Mislyktes i å laste inn milepæler. Vennligst prøv igjen."
msgid "Failed to load related branches"
+msgstr "Klarte ikke å laste inn relaterte grener"
+
+msgid "Failed to load sidebar confidential toggle"
+msgstr ""
+
+msgid "Failed to load sidebar lock status"
msgstr ""
msgid "Failed to load stacktrace."
@@ -10475,34 +10794,37 @@ msgid "Failed to promote label due to internal error. Please contact administrat
msgstr ""
msgid "Failed to protect the branch"
-msgstr ""
+msgstr "Mislyktes i å beskytte grenen"
msgid "Failed to protect the environment"
-msgstr ""
+msgstr "Mislyktes i å beskytte miljøet"
msgid "Failed to publish issue on status page."
msgstr ""
-msgid "Failed to remove a Zoom meeting"
+msgid "Failed to remove To-Do for the design."
msgstr ""
+msgid "Failed to remove a Zoom meeting"
+msgstr "Mislyktes i å fjerne et Zoom-møte"
+
msgid "Failed to remove issue from board, please try again."
msgstr ""
msgid "Failed to remove mirror."
-msgstr ""
+msgstr "Mislyktes i å fjerne speilvendingen."
msgid "Failed to remove the pipeline schedule"
msgstr ""
msgid "Failed to remove user identity."
-msgstr ""
+msgstr "Mislyktes i å fjerne brukeridentitet."
msgid "Failed to remove user key."
-msgstr ""
+msgstr "Mislyktes i å fjerne brukernøkkel."
msgid "Failed to reset key. Please try again."
-msgstr ""
+msgstr "Mislyktes i å tilbakestille nøkkel. Vennligst prøv igjen."
msgid "Failed to save merge conflicts resolutions. Please try again!"
msgstr ""
@@ -10511,10 +10833,10 @@ msgid "Failed to save new settings"
msgstr ""
msgid "Failed to save preferences (%{error_message})."
-msgstr ""
+msgstr "Mislyktes i å lagre preferanser (%{error_message})."
msgid "Failed to save preferences."
-msgstr ""
+msgstr "Mislyktes i å lagre preferanser."
msgid "Failed to set due date because the date format is invalid."
msgstr ""
@@ -10525,35 +10847,38 @@ msgstr ""
msgid "Failed to signing using smartcard authentication"
msgstr ""
-msgid "Failed to update branch!"
+msgid "Failed to toggle To-Do for the design."
msgstr ""
+msgid "Failed to update branch!"
+msgstr "Mislyktes i å oppdatere gren!"
+
msgid "Failed to update environment!"
-msgstr ""
+msgstr "Mislyktes i å oppdatere miljø!"
msgid "Failed to update issue status"
-msgstr ""
+msgstr "Mislyktes i å oppdatere-sakerstatus"
msgid "Failed to update issues, please try again."
-msgstr ""
+msgstr "Mislyktes i å oppdatere saker, please try igjen."
msgid "Failed to update tag!"
-msgstr ""
+msgstr "Mislyktes i å oppdatere etikett!"
msgid "Failed to update."
-msgstr ""
+msgstr "Mislyktes i å oppdatere."
msgid "Failed to upgrade."
-msgstr ""
+msgstr "Mislyktes i å upgrade."
msgid "Failed to upload object map file"
msgstr ""
msgid "Failed to verify domain ownership"
-msgstr ""
+msgstr "Mislyktes i å verifisere domeneeierskapet"
msgid "Failure"
-msgstr ""
+msgstr "Feil"
msgid "False positive"
msgstr ""
@@ -10571,7 +10896,7 @@ msgid "Faster as it re-uses the project workspace (falling back to clone if it d
msgstr ""
msgid "Faster releases. Better code. Less pain."
-msgstr ""
+msgstr "Raskere utgivelser. Bedre kode. Mindre smerte."
msgid "Favicon was successfully removed."
msgstr ""
@@ -10587,58 +10912,58 @@ msgstr ""
msgid "FeatureFlags|%d user"
msgid_plural "FeatureFlags|%d users"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%d bruker"
+msgstr[1] "%d brukere"
msgid "FeatureFlags|* (All Environments)"
-msgstr ""
+msgstr "* (Alle miljøer)"
msgid "FeatureFlags|* (All environments)"
-msgstr ""
+msgstr "* (Alle miljøer)"
msgid "FeatureFlags|API URL"
-msgstr ""
+msgstr "API-URL"
msgid "FeatureFlags|Active"
-msgstr ""
+msgstr "Aktiv"
msgid "FeatureFlags|Add strategy"
-msgstr ""
+msgstr "Legg til strategi"
msgid "FeatureFlags|All Environments"
-msgstr ""
+msgstr "Alle miljøer"
msgid "FeatureFlags|All Users"
-msgstr ""
+msgstr "Alle brukere"
msgid "FeatureFlags|All users"
-msgstr ""
+msgstr "Alle brukere"
msgid "FeatureFlags|Configure"
-msgstr ""
+msgstr "Sett opp"
msgid "FeatureFlags|Configure feature flags"
-msgstr ""
+msgstr "Sett opp funksjonsflagg"
msgid "FeatureFlags|Create feature flag"
-msgstr ""
+msgstr "Opprett funksjonsflagg"
msgid "FeatureFlags|Delete %{name}?"
-msgstr ""
+msgstr "Slett %{name}?"
msgid "FeatureFlags|Delete feature flag"
-msgstr ""
+msgstr "Slett funksjonsflagg"
msgid "FeatureFlags|Description"
-msgstr ""
+msgstr "Beskrivelse"
msgid "FeatureFlags|Edit Feature Flag"
-msgstr ""
+msgstr "Rediger funksjonsflagg"
msgid "FeatureFlags|Edit User List"
-msgstr ""
+msgstr "Rediger brukerliste"
-msgid "FeatureFlags|Enable features for specific users and specific environments by defining feature flag strategies."
+msgid "FeatureFlags|Enable features for specific users and environments by configuring feature flag strategies."
msgstr ""
msgid "FeatureFlags|Environment Spec"
@@ -10648,19 +10973,19 @@ msgid "FeatureFlags|Environment Specs"
msgstr ""
msgid "FeatureFlags|Feature Flag"
-msgstr ""
+msgstr "Funksjonsflagg"
msgid "FeatureFlags|Feature Flag User List Details"
msgstr ""
msgid "FeatureFlags|Feature Flag behavior is built up by creating a set of rules to define the status of target environments. A default wildcard rule %{codeStart}*%{codeEnd} for %{boldStart}All Environments%{boldEnd} is set, and you are able to add as many rules as you need by choosing environment specs below. You can toggle the behavior for each of your rules to set them %{boldStart}Active%{boldEnd} or %{boldStart}Inactive%{boldEnd}."
-msgstr ""
+msgstr "Funksjonsflagg-oppførsel bygges opp ved å lage et sett med regler for å definere status for målmiljøer. En standard jokertegnregel %{codeStart}*%{codeEnd} for %{boldStart}Alle miljøer%{boldEnd} er angitt, og du kan legge til så mange regler du trenger ved å velge miljøspesifikasjoner nedenfor. Du kan veksle oppførselen for hver av reglene dine for å sette dem til %{boldStart}Aktiv%{boldEnd} eller %{boldStart}Inaktiv%{boldEnd}."
msgid "FeatureFlags|Feature Flag has no strategies"
msgstr ""
msgid "FeatureFlags|Feature Flags"
-msgstr ""
+msgstr "Funksjonsflagg"
msgid "FeatureFlags|Feature Flags will look different in the next milestone. No action is needed, but you may notice the functionality was changed to improve the workflow."
msgstr ""
@@ -10687,10 +11012,10 @@ msgid "FeatureFlags|GitLab is moving to a new way of managing feature flags. Thi
msgstr ""
msgid "FeatureFlags|ID"
-msgstr ""
+msgstr "ID"
msgid "FeatureFlags|Inactive"
-msgstr ""
+msgstr "Inaktiv"
msgid "FeatureFlags|Inactive flag for %{scope}"
msgstr ""
@@ -10698,11 +11023,11 @@ msgstr ""
msgid "FeatureFlags|Include additional user IDs"
msgstr ""
-msgid "FeatureFlags|Install a %{docs_link_anchored_start}compatible client library%{docs_link_anchored_end} and specify the API URL, application name, and instance ID during the configuration setup. %{docs_link_start}More Information%{docs_link_end}"
+msgid "FeatureFlags|Install a %{docsLinkAnchoredStart}compatible client library%{docsLinkAnchoredEnd} and specify the API URL, application name, and instance ID during the configuration setup. %{docsLinkStart}More Information%{docsLinkEnd}"
msgstr ""
msgid "FeatureFlags|Instance ID"
-msgstr ""
+msgstr "Instans-ID"
msgid "FeatureFlags|List details"
msgstr ""
@@ -10710,25 +11035,28 @@ msgstr ""
msgid "FeatureFlags|Loading feature flags"
msgstr ""
-msgid "FeatureFlags|More information"
+msgid "FeatureFlags|Loading user lists"
msgstr ""
+msgid "FeatureFlags|More information"
+msgstr "Mere informasjon"
+
msgid "FeatureFlags|Name"
-msgstr ""
+msgstr "Navn"
msgid "FeatureFlags|New"
-msgstr ""
+msgstr "Ny"
msgid "FeatureFlags|New Feature Flag"
-msgstr ""
+msgstr "Nytt funksjonsflagg"
msgid "FeatureFlags|New User List"
msgstr ""
msgid "FeatureFlags|New feature flag"
-msgstr ""
+msgstr "Nytt funksjonsflagg"
-msgid "FeatureFlags|New list"
+msgid "FeatureFlags|New user list"
msgstr ""
msgid "FeatureFlags|Percent of users"
@@ -10741,10 +11069,10 @@ msgid "FeatureFlags|Percent rollout must be a whole number between 0 and 100"
msgstr ""
msgid "FeatureFlags|Protected"
-msgstr ""
+msgstr "Beskyttet"
msgid "FeatureFlags|Remove"
-msgstr ""
+msgstr "Fjern"
msgid "FeatureFlags|Rollout Percentage"
msgstr ""
@@ -10753,13 +11081,13 @@ msgid "FeatureFlags|Rollout Strategy"
msgstr ""
msgid "FeatureFlags|Set the Unleash client application name to the name of the environment your application runs in. This value is used to match environment scopes. See the %{linkStart}example client configuration%{linkEnd}."
-msgstr ""
+msgstr "Sett Unleash-klientapplikasjonsnavnet til navnet på miljøet som applikasjonen kjører i. Denne verdien brukes til å samsvare med miljøomfang. Se %{linkStart}eksempelklientoppsettet%{linkEnd}."
msgid "FeatureFlags|Status"
-msgstr ""
+msgstr "Status"
msgid "FeatureFlags|Strategies"
-msgstr ""
+msgstr "Strategier"
msgid "FeatureFlags|Target environments"
msgstr ""
@@ -10767,6 +11095,9 @@ msgstr ""
msgid "FeatureFlags|There was an error fetching the feature flags."
msgstr ""
+msgid "FeatureFlags|There was an error fetching the user lists."
+msgstr ""
+
msgid "FeatureFlags|There was an error retrieving user lists"
msgstr ""
@@ -10777,67 +11108,61 @@ msgid "FeatureFlags|Try again in a few moments or contact your support team."
msgstr ""
msgid "FeatureFlags|User IDs"
-msgstr ""
+msgstr "Bruker-ID-er"
msgid "FeatureFlags|User List"
+msgstr "Brukerliste"
+
+msgid "FeatureFlags|User Lists"
msgstr ""
msgid "FeatureFlag|List"
msgstr ""
msgid "FeatureFlag|Percentage"
-msgstr ""
+msgstr "Prosentandel"
msgid "FeatureFlag|Select a user list"
-msgstr ""
+msgstr "Velg en brukerliste"
msgid "FeatureFlag|There are no configured user lists"
-msgstr ""
+msgstr "Det er ingen oppsatte brukerlister"
msgid "FeatureFlag|Type"
-msgstr ""
+msgstr "Type"
msgid "FeatureFlag|User IDs"
-msgstr ""
+msgstr "Bruker-ID-er"
msgid "Feb"
-msgstr ""
+msgstr "Feb"
msgid "February"
-msgstr ""
+msgstr "Februar"
msgid "Fetching incoming email"
msgstr ""
-msgid "Fetching licenses failed."
-msgstr ""
-
-msgid "Fetching licenses failed. The request endpoint was not found."
-msgstr ""
-
-msgid "Fetching licenses failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "File"
-msgstr ""
+msgstr "Fil"
msgid "File %{current} of %{total}"
-msgstr ""
+msgstr "Fil %{current} av %{total}"
msgid "File Hooks"
-msgstr ""
+msgstr "Filkroker"
msgid "File Hooks (%{count})"
msgstr ""
msgid "File added"
-msgstr ""
+msgstr "Lagt til fil"
msgid "File browser"
-msgstr ""
+msgstr "Filutforsker"
msgid "File deleted"
-msgstr ""
+msgstr "Fil slettet"
msgid "File format is no longer supported"
msgstr ""
@@ -10849,10 +11174,10 @@ msgid "File mode changed from %{a_mode} to %{b_mode}"
msgstr ""
msgid "File moved"
-msgstr ""
+msgstr "Fil flyttet"
msgid "File name"
-msgstr ""
+msgstr "Filnavn"
msgid "File renamed with no changes."
msgstr ""
@@ -10861,13 +11186,13 @@ msgid "File sync capacity"
msgstr ""
msgid "File templates"
-msgstr ""
+msgstr "Fil-maler"
msgid "File upload error."
-msgstr ""
+msgstr "Filopplastingsfeil."
msgid "Files"
-msgstr ""
+msgstr "Filer"
msgid "Files breadcrumb"
msgstr ""
@@ -10879,13 +11204,13 @@ msgid "Fill in the fields below, turn on %{strong_open}Enable SAML authenticatio
msgstr ""
msgid "Filter"
-msgstr ""
+msgstr "Filter"
msgid "Filter by %{issuable_type} that are currently closed."
-msgstr ""
+msgstr "Filtrer etter %{issuable_type} som for øyeblikket er stengt."
msgid "Filter by %{issuable_type} that are currently opened."
-msgstr ""
+msgstr "Filtrer etter %{issuable_type} som for øyeblikket er åpne."
msgid "Filter by %{page_context_word} that are currently opened."
msgstr ""
@@ -10897,7 +11222,7 @@ msgid "Filter by issues that are currently closed."
msgstr ""
msgid "Filter by label"
-msgstr ""
+msgstr "Filtrer etter stempel"
msgid "Filter by merge requests that are currently closed and unmerged."
msgstr ""
@@ -10906,10 +11231,10 @@ msgid "Filter by merge requests that are currently merged."
msgstr ""
msgid "Filter by milestone name"
-msgstr ""
+msgstr "Filtrer etter milepælnavn"
msgid "Filter by name"
-msgstr ""
+msgstr "Filtrer etter navn"
msgid "Filter by requirements that are currently archived."
msgstr ""
@@ -10918,49 +11243,58 @@ msgid "Filter by requirements that are currently opened."
msgstr ""
msgid "Filter by status"
+msgstr "Filtrer etter status"
+
+msgid "Filter by test cases that are currently archived."
msgstr ""
-msgid "Filter by two-factor authentication"
+msgid "Filter by test cases that are currently opened."
msgstr ""
+msgid "Filter by two-factor authentication"
+msgstr "Filtrer etter 2-trinnsautentisering"
+
msgid "Filter by user"
+msgstr "Filtrer etter user"
+
+msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
msgstr ""
msgid "Filter pipelines"
-msgstr ""
+msgstr "Filtrer rørledninger"
msgid "Filter results"
-msgstr ""
+msgstr "Filtrerresultater"
msgid "Filter results by group"
-msgstr ""
+msgstr "Filtrer resultater etter gruppe"
msgid "Filter results by project"
-msgstr ""
+msgstr "Filtrer resultater etter prosjekt"
msgid "Filter results..."
-msgstr ""
+msgstr "Filtrer resultater …"
-msgid "Filter your projects by name"
+msgid "Filter your repositories by name"
msgstr ""
msgid "Filter..."
-msgstr ""
+msgstr "Filter..."
msgid "Find File"
-msgstr ""
+msgstr "Finn fil"
-msgid "Find bugs in your code with coverage-guided fuzzing"
+msgid "Find bugs in your code with coverage-guided fuzzing."
msgstr ""
msgid "Find by path"
-msgstr ""
+msgstr "Finn utifra filbane"
msgid "Find existing members by name"
-msgstr ""
+msgstr "Finn eksisterende medlemmer med navn"
msgid "Find file"
-msgstr ""
+msgstr "Finn fil"
msgid "Find the downloaded ZIP file and decompress it."
msgstr ""
@@ -10969,52 +11303,49 @@ msgid "Find the newly extracted %{code_open}Takeout/Google Code Project Hosting/
msgstr ""
msgid "Fingerprint"
-msgstr ""
+msgstr "Fingeravtrykk"
msgid "Fingerprints"
-msgstr ""
+msgstr "Fingeravtrykk"
msgid "Finish editing this message first!"
-msgstr ""
-
-msgid "Finish review"
-msgstr ""
+msgstr "Fullfør redigeringen av denne meldingen først!"
msgid "Finish setting up your dedicated account for %{group_name}."
msgstr ""
msgid "Finished"
-msgstr ""
+msgstr "Fullført"
msgid "First Name is too long (maximum is %{max_length} characters)."
-msgstr ""
+msgstr "Fornavnet er for langt (Maksgrensen er %{max_length} tegn)."
msgid "First Seen"
-msgstr ""
+msgstr "Først sett"
msgid "First day of the week"
-msgstr ""
+msgstr "Første dagen i uken"
msgid "First name"
-msgstr ""
+msgstr "Fornavn"
msgid "First seen"
-msgstr ""
+msgstr "Først sett"
msgid "Fixed date"
-msgstr ""
+msgstr "Fast dato"
msgid "Fixed due date"
-msgstr ""
+msgstr "Fast forfallsdato"
msgid "Fixed start date"
-msgstr ""
+msgstr "Fast startdato"
msgid "Fixed:"
-msgstr ""
+msgstr "Rettet opp i:"
msgid "Flags"
-msgstr ""
+msgstr "Flagg"
msgid "FlowdockService|Flowdock Git source token"
msgstr ""
@@ -11023,30 +11354,33 @@ msgid "FlowdockService|Flowdock is a collaboration web app for technical teams."
msgstr ""
msgid "FogBugz Email"
-msgstr ""
+msgstr "FogBugz E-post"
msgid "FogBugz Import"
-msgstr ""
+msgstr "FogBugz-importering"
msgid "FogBugz Password"
-msgstr ""
+msgstr "FogBugz-passord"
msgid "FogBugz URL"
-msgstr ""
+msgstr "FogBugz-URL"
msgid "FogBugz import"
-msgstr ""
+msgstr "FogBugz-importering"
msgid "Folder/%{name}"
-msgstr ""
+msgstr "Mappe/%{name}"
msgid "Follow the steps below to export your Google Code project data."
msgstr ""
msgid "Font Color"
-msgstr ""
+msgstr "Skriftfarge"
msgid "Footer message"
+msgstr "Bunntekstmelding"
+
+msgid "For a faster browsing experience, some files are collapsed by default."
msgstr ""
msgid "For help setting up the Service Desk for your instance, please contact an administrator."
@@ -11056,13 +11390,16 @@ msgid "For internal projects, any logged in user can view pipelines and access j
msgstr ""
msgid "For more info, read the documentation."
+msgstr "For mere info, les dokumentasjonen."
+
+msgid "For more information on how the number of active users is calculated, see the %{self_managed_subscriptions_doc_link} documentation."
msgstr ""
msgid "For more information, go to the "
-msgstr ""
+msgstr "For mer informasjon, gå til "
msgid "For more information, please review %{link_start_tag}Jaeger's configuration doc%{link_end_tag}"
-msgstr ""
+msgstr "For mer informasjon, gå gjennom %{link_start_tag}Jaeger sitt konfigurasjonsdokument%{link_end_tag}"
msgid "For more information, see the File Hooks documentation."
msgstr ""
@@ -11080,52 +11417,52 @@ msgid "For public projects, anyone can view pipelines and access job details (ou
msgstr ""
msgid "Forgot your password?"
-msgstr ""
+msgstr "Glemt passordet ditt?"
msgid "Fork"
-msgstr ""
+msgstr "Utgreining"
msgid "Fork Error!"
-msgstr ""
+msgstr "Utgreiningsfeil!"
msgid "Fork project"
-msgstr ""
+msgstr "Utgrein prosjektet"
msgid "Fork project?"
-msgstr ""
+msgstr "Vil du utgreine prosjektet?"
msgid "ForkedFromProjectPath|Forked from"
-msgstr ""
+msgstr "Utgreinet fra"
msgid "ForkedFromProjectPath|Forked from an inaccessible project"
-msgstr ""
+msgstr "Utgreinet fra et utilgjengelig prosjekt"
msgid "Forking a repository allows you to make changes without affecting the original project."
-msgstr ""
+msgstr "Å utgreine et kodelager vil la deg utføre endringer uten å påvirke originalprosjektet."
msgid "Forking in progress"
-msgstr ""
+msgstr "Utgreining pågår"
msgid "Forks"
-msgstr ""
+msgstr "Utgreininger"
msgid "Format: %{dateFormat}"
-msgstr ""
+msgstr "Format: %{dateFormat}"
msgid "Forward external support email address to"
msgstr ""
msgid "Found errors in your %{gitlab_ci_yml}:"
-msgstr ""
+msgstr "Fant feil i din %{gitlab_ci_yml}:"
msgid "Found errors in your .gitlab-ci.yml:"
-msgstr ""
+msgstr "Fant feil i din .gitlab-ci.yml:"
msgid "Free Trial"
-msgstr ""
+msgstr "Gratis prøveperiode"
msgid "Free Trial of GitLab.com Gold"
-msgstr ""
+msgstr "Gratis prøveperiode for GitLab.com Gold"
msgid "Freeze end"
msgstr ""
@@ -11134,22 +11471,22 @@ msgid "Freeze start"
msgstr ""
msgid "Frequency"
-msgstr ""
+msgstr "Frekvens"
msgid "Friday"
-msgstr ""
+msgstr "Fredag"
msgid "From"
-msgstr ""
+msgstr "Fra"
msgid "From %{code_open}%{source_title}%{code_close} into"
-msgstr ""
+msgstr "Fra %{code_open}%{source_title}%{code_close} til"
msgid "From %{providerTitle}"
-msgstr ""
+msgstr "Fra %{providerTitle}"
msgid "From Google Code"
-msgstr ""
+msgstr "Fra Google Code"
msgid "From issue creation until deploy to production"
msgstr ""
@@ -11161,46 +11498,49 @@ msgid "From the Kubernetes cluster details view, install Runner from the applica
msgstr ""
msgid "Full name"
-msgstr ""
+msgstr "Fullt navn"
msgid "GPG Key ID:"
-msgstr ""
+msgstr "GPG-nøkkel-ID:"
msgid "GPG Keys"
-msgstr ""
+msgstr "GPG-nøkler"
msgid "GPG keys allow you to verify signed commits."
-msgstr ""
+msgstr "GPG-nøkler lar deg bekrefte signerte commiter."
msgid "GPG signature (loading...)"
-msgstr ""
+msgstr "GPG-signatur (laster inn …)"
msgid "General"
-msgstr ""
+msgstr "Generell"
msgid "General Settings"
-msgstr ""
+msgstr "Generelle innstillinger"
msgid "General pipelines"
-msgstr ""
+msgstr "Generelle rørledninger"
msgid "Generate a default set of labels"
-msgstr ""
+msgstr "Generer et standardsett med stempler"
msgid "Generate key"
-msgstr ""
+msgstr "Generer nøkkel"
msgid "Generate new export"
-msgstr ""
+msgstr "Generer ny eksportering"
msgid "Generate new token"
+msgstr "Generer ny sjetong"
+
+msgid "Generic package file size in bytes"
msgstr ""
msgid "Geo"
-msgstr ""
+msgstr "Geo"
msgid "Geo Nodes"
-msgstr ""
+msgstr "Geo-noder"
msgid "Geo Nodes|Cannot remove a primary node if there is a secondary node"
msgstr ""
@@ -11209,7 +11549,7 @@ msgid "Geo Replication"
msgstr ""
msgid "Geo Settings"
-msgstr ""
+msgstr "Geo-innstillinger"
msgid "Geo nodes are paused using a command run on the node"
msgstr ""
@@ -11218,7 +11558,7 @@ msgid "GeoNodeStatusEvent|%{timeAgoStr} (%{pendingEvents} events)"
msgstr ""
msgid "GeoNodeSyncStatus|Node is failing or broken."
-msgstr ""
+msgstr "Noden mislykkes eller er ødelagt."
msgid "GeoNodeSyncStatus|Node is slow, overloaded, or it just recovered after an outage."
msgstr ""
@@ -11233,19 +11573,19 @@ msgid "GeoNodes|Does not match the primary storage configuration"
msgstr ""
msgid "GeoNodes|Full"
-msgstr ""
+msgstr "Full"
msgid "GeoNodes|GitLab version"
-msgstr ""
+msgstr "GitLab-versjon"
msgid "GeoNodes|GitLab version does not match the primary node version"
-msgstr ""
+msgstr "GitLab-versjonen samsvarer ikke med primærnodeversjonen"
msgid "GeoNodes|Health status"
-msgstr ""
+msgstr "Helsestatus"
msgid "GeoNodes|Internal URL"
-msgstr ""
+msgstr "Intern URL"
msgid "GeoNodes|Last event ID processed by cursor"
msgstr ""
@@ -11257,22 +11597,22 @@ msgid "GeoNodes|Learn more about Geo node statuses"
msgstr ""
msgid "GeoNodes|Loading nodes"
-msgstr ""
+msgstr "Laster inn noder"
msgid "GeoNodes|New node"
-msgstr ""
+msgstr "Ny node"
msgid "GeoNodes|Node Authentication was successfully repaired."
msgstr ""
msgid "GeoNodes|Node URL"
-msgstr ""
+msgstr "Node-URL"
msgid "GeoNodes|Node was successfully removed."
-msgstr ""
+msgstr "Noden ble vellykket fjernet."
msgid "GeoNodes|Node's status was updated %{timeAgo}."
-msgstr ""
+msgstr "Nodens status ble oppdatert %{timeAgo}."
msgid "GeoNodes|Pausing replication stops the sync process. Are you sure?"
msgstr ""
@@ -11296,19 +11636,19 @@ msgid "GeoNodes|Replication status"
msgstr ""
msgid "GeoNodes|Selective (%{syncLabel})"
-msgstr ""
+msgstr "Selektiv (%{syncLabel})"
msgid "GeoNodes|Selective synchronization"
-msgstr ""
+msgstr "Selektiv synkronisering"
msgid "GeoNodes|Something went wrong while changing node status"
msgstr ""
msgid "GeoNodes|Something went wrong while fetching nodes"
-msgstr ""
+msgstr "Noe gikk galt under innhenting av noder"
msgid "GeoNodes|Something went wrong while removing node"
-msgstr ""
+msgstr "Noe gikk galt under fjerning av node"
msgid "GeoNodes|Something went wrong while repairing node"
msgstr ""
@@ -11317,16 +11657,16 @@ msgid "GeoNodes|Storage config"
msgstr ""
msgid "GeoNodes|Sync settings"
-msgstr ""
+msgstr "Synkroniser innstillinger"
msgid "GeoNodes|Unused slots"
-msgstr ""
+msgstr "Ubrukte plasser"
msgid "GeoNodes|Updated %{timeAgo}"
-msgstr ""
+msgstr "Oppdatert %{timeAgo}"
msgid "GeoNodes|Used slots"
-msgstr ""
+msgstr "Brukte plasser"
msgid "GeoNodes|With %{geo} you can install a special read-only and replicated instance anywhere. Before you add nodes, follow the %{instructions} in the exact order they appear."
msgstr ""
@@ -11335,10 +11675,10 @@ msgid "GeoNodes|You have configured Geo nodes using an insecure HTTP connection.
msgstr ""
msgid "GeoNodes|primary node"
-msgstr ""
+msgstr "hovednode"
msgid "GeoNodes|secondary nodes"
-msgstr ""
+msgstr "sekundærnoder"
msgid "Geo|%{itemTitle} checksum progress"
msgstr ""
@@ -11347,10 +11687,10 @@ msgid "Geo|%{itemTitle} verification progress"
msgstr ""
msgid "Geo|%{label} can't be blank"
-msgstr ""
+msgstr "%{label} kan ikke være tom"
msgid "Geo|%{label} should be between 1-999"
-msgstr ""
+msgstr "%{label} burde være mellom 1-999"
msgid "Geo|%{name} is scheduled for forced re-download"
msgstr ""
@@ -11362,13 +11702,13 @@ msgid "Geo|%{name} is scheduled for re-verify"
msgstr ""
msgid "Geo|Adjust your filters/search criteria above. If you believe this may be an error, please refer to the %{linkStart}Geo Troubleshooting%{linkEnd} documentation for more information."
-msgstr ""
+msgstr "Juster dine filtre/søkekriterier ovenfor. Hvis du mener at dette kan være en feil, kan du se dokumentasjonen for %{linkStart}Geo-feilsøking%{linkEnd} for mer informasjon."
msgid "Geo|All %{replicable_name}"
-msgstr ""
+msgstr "Alle %{replicable_name}"
msgid "Geo|All projects"
-msgstr ""
+msgstr "Alle prosjekter"
msgid "Geo|All projects are being scheduled for resync"
msgstr ""
@@ -11401,88 +11741,91 @@ msgid "Geo|Could not remove tracking entry for an existing upload."
msgstr ""
msgid "Geo|Failed"
-msgstr ""
+msgstr "Mislykket"
msgid "Geo|Filter by status"
-msgstr ""
+msgstr "Filtrer etter status"
msgid "Geo|Geo Status"
-msgstr ""
+msgstr "Geo Status"
msgid "Geo|Go to the primary site"
-msgstr ""
+msgstr "GÃ¥ til hovednettstedet"
msgid "Geo|If you want to make changes, you must visit the primary site."
msgstr ""
msgid "Geo|In progress"
-msgstr ""
+msgstr "Pågår"
msgid "Geo|In sync"
-msgstr ""
+msgstr "Synkronisert"
msgid "Geo|Last repository check run"
msgstr ""
msgid "Geo|Last successful sync"
-msgstr ""
+msgstr "Siste vellykket synkronisering"
msgid "Geo|Last sync attempt"
-msgstr ""
+msgstr "Forrige synkroniseringsforsøk"
msgid "Geo|Last time verified"
-msgstr ""
+msgstr "Sist bekreftet"
msgid "Geo|Never"
-msgstr ""
+msgstr "Aldri"
msgid "Geo|Next sync scheduled at"
-msgstr ""
+msgstr "Neste synkronisering er planlagt kl."
msgid "Geo|Node name can't be blank"
-msgstr ""
+msgstr "Nodenavnet kan ikke være tomt"
msgid "Geo|Node name should be between 1 and 255 characters"
msgstr ""
msgid "Geo|Not synced yet"
-msgstr ""
+msgstr "Ikke synkronisert enda"
msgid "Geo|Pending synchronization"
-msgstr ""
+msgstr "Avventer synkronisering"
msgid "Geo|Pending verification"
-msgstr ""
+msgstr "Venter verifikasjon"
msgid "Geo|Please refer to Geo Troubleshooting."
msgstr ""
-msgid "Geo|Project"
+msgid "Geo|Primary node"
msgstr ""
+msgid "Geo|Project"
+msgstr "Prosjekt"
+
msgid "Geo|Project (ID: %{project_id}) no longer exists on the primary. It is safe to remove this entry, as this will not remove any data on disk."
msgstr ""
msgid "Geo|Projects in certain groups"
-msgstr ""
+msgstr "Prosjekter i enkelte grupper"
msgid "Geo|Projects in certain storage shards"
-msgstr ""
+msgstr "Prosjekter i visse lagringsskår"
msgid "Geo|Redownload"
-msgstr ""
+msgstr "Laste ned på nytt"
msgid "Geo|Remove"
-msgstr ""
+msgstr "Fjern"
msgid "Geo|Remove entry"
-msgstr ""
+msgstr "Fjern oppføring"
msgid "Geo|Remove tracking database entry"
msgstr ""
msgid "Geo|Resync"
-msgstr ""
+msgstr "Synkroniser på nytt"
msgid "Geo|Resync all"
msgstr ""
@@ -11491,28 +11834,31 @@ msgid "Geo|Retry count"
msgstr ""
msgid "Geo|Reverify"
-msgstr ""
+msgstr "Re-verifiser"
msgid "Geo|Reverify all"
-msgstr ""
+msgstr "Re-verifiser alle"
msgid "Geo|Review replication status, and resynchronize and reverify items with the primary node."
msgstr ""
-msgid "Geo|Status"
+msgid "Geo|Secondary node"
msgstr ""
+msgid "Geo|Status"
+msgstr "Status"
+
msgid "Geo|Synced"
-msgstr ""
+msgstr "Synkronisert"
msgid "Geo|Synced at"
-msgstr ""
+msgstr "Synkronisert den"
msgid "Geo|Synchronization failed - %{error}"
-msgstr ""
+msgstr "Synkronisering mislyktes - %{error}"
msgid "Geo|Synchronization of %{itemTitle} is disabled."
-msgstr ""
+msgstr "Synkronisering av %{itemTitle} er deaktivert."
msgid "Geo|The database is currently %{db_lag} behind the primary node."
msgstr ""
@@ -11521,7 +11867,7 @@ msgid "Geo|The node is currently %{minutes_behind} behind the primary node."
msgstr ""
msgid "Geo|There are no %{replicable_type} to show"
-msgstr ""
+msgstr "Det er ingen %{replicable_type} å vise"
msgid "Geo|Tracking database entry will be removed. Are you sure?"
msgstr ""
@@ -11533,19 +11879,22 @@ msgid "Geo|Tracking entry for upload (%{type}/%{id}) was successfully removed."
msgstr ""
msgid "Geo|URL can't be blank"
-msgstr ""
+msgstr "URL-en kan ikke være blank"
msgid "Geo|URL must be a valid url (ex: https://gitlab.com)"
+msgstr "URL-en må være en gyldig URL (f.eks. https://gitlab.com)"
+
+msgid "Geo|Undefined"
msgstr ""
msgid "Geo|Unknown state"
-msgstr ""
+msgstr "Ukjent tilstand"
msgid "Geo|Verification failed - %{error}"
-msgstr ""
+msgstr "Verifisering mislyktes - %{error}"
msgid "Geo|Waiting for scheduler"
-msgstr ""
+msgstr "Venter på planlegger"
msgid "Geo|You are on a secondary, %{b_open}read-only%{b_close} Geo node."
msgstr ""
@@ -11554,19 +11903,19 @@ msgid "Geo|You may be able to make a limited amount of changes or perform a limi
msgstr ""
msgid "Geo|misconfigured"
-msgstr ""
+msgstr "feilkonfigurert"
msgid "Geo|primary"
-msgstr ""
+msgstr "primær"
msgid "Geo|secondary"
-msgstr ""
+msgstr "sekundær"
msgid "Get a free instance review"
msgstr ""
msgid "Get started"
-msgstr ""
+msgstr "Kom i gang"
msgid "Get started with error tracking"
msgstr ""
@@ -11575,10 +11924,10 @@ msgid "Get started with performance monitoring"
msgstr ""
msgid "Get started!"
-msgstr ""
+msgstr "Kom i gang!"
msgid "Getting started with releases"
-msgstr ""
+msgstr "Ã… sette i gang med utgivelser"
msgid "Git LFS is not enabled on this GitLab server, contact your admin."
msgstr ""
@@ -11587,16 +11936,16 @@ msgid "Git LFS objects will be synced in pull mirrors if LFS is %{docs_link_star
msgstr ""
msgid "Git LFS status:"
-msgstr ""
+msgstr "Git LFS-status:"
msgid "Git global setup"
msgstr ""
msgid "Git repository URL"
-msgstr ""
+msgstr "Git-kodelager-URL"
msgid "Git revision"
-msgstr ""
+msgstr "Git-revisjon"
msgid "Git shallow clone"
msgstr ""
@@ -11605,55 +11954,67 @@ msgid "Git strategy for pipelines"
msgstr ""
msgid "Git version"
-msgstr ""
+msgstr "Git-versjon"
msgid "GitHub API rate limit exceeded. Try again after %{reset_time}"
msgstr ""
msgid "GitHub import"
+msgstr "GitHub-import"
+
+msgid "GitLab"
msgstr ""
msgid "GitLab / Unsubscribe"
msgstr ""
-msgid "GitLab Enterprise Edition %{plan}"
+msgid "GitLab API"
+msgstr ""
+
+msgid "GitLab Billing Team."
msgstr ""
msgid "GitLab Group Runners can execute code for all the projects in this group."
msgstr ""
msgid "GitLab Import"
-msgstr ""
+msgstr "GitLab-importering"
msgid "GitLab Issue"
+msgstr "Gitlab-sak"
+
+msgid "GitLab Pages"
msgstr ""
msgid "GitLab Service Desk is a simple way to allow people to create issues in your GitLab instance without needing their own user account. It provides a unique email address for end users to create issues in a project, and replies can be sent either through the GitLab interface or by email. End users will only see the thread through email."
-msgstr ""
+msgstr "GitLab-tjenestedesken er en enkel måte å la folk opprette saksrapporter i din GitLab-forekomst uten å behøve sin egen brukerkonto. Det sørger for en unik e-postadresse for sluttbrukere til å opprette saksrapporter i et prosjekt, og svar kan sendes enten via GitLab-grensesnittet eller via e-post. Sluttbrukere vil bare se tråden via e-post."
msgid "GitLab Shared Runners execute code of different projects on the same Runner unless you configure GitLab Runner Autoscale with MaxBuilds 1 (which it is on GitLab.com)."
msgstr ""
+msgid "GitLab Shell"
+msgstr ""
+
msgid "GitLab Support Bot"
msgstr ""
msgid "GitLab Team Member"
-msgstr ""
+msgstr "GitLab-teammedlem"
msgid "GitLab User"
-msgstr ""
+msgstr "GitLab-bruker"
-msgid "GitLab allows you to continue using your license even if you exceed the number of seats you purchased. You will be required to pay for these seats when you renew your license."
+msgid "GitLab Workhorse"
msgstr ""
msgid "GitLab commit"
-msgstr ""
+msgstr "GitLab-commit"
msgid "GitLab export"
-msgstr ""
+msgstr "GitLab-eksport"
msgid "GitLab for Slack"
-msgstr ""
+msgstr "GitLab for Slack"
msgid "GitLab is a single application for the entire software development lifecycle. From project planning and source code management to CI/CD, monitoring, and security."
msgstr ""
@@ -11671,115 +12032,115 @@ msgid "GitLab metadata URL"
msgstr ""
msgid "GitLab project export"
-msgstr ""
+msgstr "GitLab-prosjekteksportering"
msgid "GitLab restart is required to apply changes."
-msgstr ""
+msgstr "GitLab-omstart er nødvendig for å benytte endringene."
msgid "GitLab single sign-on URL"
msgstr ""
msgid "GitLab username"
-msgstr ""
+msgstr "GitLab-brukernavn"
msgid "GitLab uses %{jaeger_link} to monitor distributed systems."
msgstr ""
msgid "GitLab will run a background job that will produce pseudonymized CSVs of the GitLab database that will be uploaded to your configured object storage directory."
-msgstr ""
+msgstr "GitLab vil kjøre en bakgrunnsjobb som vil opprette pseudonymiserte CSV filer av GitLab-databasen. Disse vil bli lastet opp til den konfigurerte objektlagringskatalogen."
msgid "GitLab.com"
-msgstr ""
+msgstr "GitLab.com"
msgid "GitLab.com import"
-msgstr ""
+msgstr "GitLab.com import"
msgid "GitLabPagesDomains|Retry"
-msgstr ""
+msgstr "Prøv igjen"
msgid "GitLabPages|%{domain} is not verified. To learn how to verify ownership, visit your %{link_start}domain details%{link_end}."
-msgstr ""
+msgstr "%{domain} er ikke bekreftet. Hvis du vil lære hvordan man bekrefter eierskap, kan du gå til dine %{link_start}domenedetaljer%{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 "Tilgangskontroll er aktivert for dette Pages-nettstedet; bare autoriserte brukere vil ha tilgang til den. For å gjøre nettstedet ditt offentlig tilgjengelig, naviger til prosjektets %{strong_start}Innstillinger &gt; Generelt &gt; Synlighet%{strong_end} og velg %{strong_start}Alle%{strong_end} i Sider-seksjonen. Les %{link_start}dokumentasjonen%{link_end} for mer informasjon."
msgid "GitLabPages|Access pages"
msgstr ""
msgid "GitLabPages|Are you sure?"
-msgstr ""
+msgstr "Er du sikker?"
msgid "GitLabPages|Certificate: %{subject}"
-msgstr ""
+msgstr "Sertifikat: %{subject}"
msgid "GitLabPages|Configure pages"
-msgstr ""
+msgstr "Sett opp sider"
msgid "GitLabPages|Domains"
-msgstr ""
+msgstr "Domener"
msgid "GitLabPages|Edit"
-msgstr ""
+msgstr "Rediger"
msgid "GitLabPages|Expired"
-msgstr ""
+msgstr "Utløpt"
msgid "GitLabPages|Force HTTPS (requires valid certificates)"
-msgstr ""
+msgstr "Tving HTTPS (krever gyldige sertifikater)"
msgid "GitLabPages|GitLab Pages are disabled for this project. You can enable them on your project's %{strong_start}Settings &gt; General &gt; Visibility%{strong_end} page."
msgstr ""
msgid "GitLabPages|It may take up to 30 minutes before the site is available after the first deployment."
-msgstr ""
+msgstr "Det kan ta opptil 30 minutter før nettstedet er tilgjengelig etter den første distribusjonen."
msgid "GitLabPages|Learn how to upload your static site and have it served by GitLab by following the %{link_start}documentation on GitLab Pages%{link_end}."
msgstr ""
msgid "GitLabPages|Learn more."
-msgstr ""
+msgstr "Lær mer."
msgid "GitLabPages|Maximum size of pages (MB)"
msgstr ""
msgid "GitLabPages|New Domain"
-msgstr ""
+msgstr "Nytt domene"
msgid "GitLabPages|Only project maintainers can remove pages"
msgstr ""
msgid "GitLabPages|Pages"
-msgstr ""
+msgstr "Sider"
msgid "GitLabPages|Remove"
-msgstr ""
+msgstr "Fjern"
msgid "GitLabPages|Remove pages"
-msgstr ""
+msgstr "Fjern sider"
msgid "GitLabPages|Removing pages will prevent them from being exposed to the outside world."
msgstr ""
msgid "GitLabPages|Save"
-msgstr ""
+msgstr "Lagre"
msgid "GitLabPages|Something went wrong while obtaining the Let's Encrypt certificate for %{domain}. To retry visit your %{link_start}domain details%{link_end}."
-msgstr ""
+msgstr "Noe gikk galt under innhenting av Let's Encrypt-sertifikatet for %{domain}. Gå til dine %{link_start}domenedetaljer%{link_end} for å prøve på nytt."
msgid "GitLabPages|Support for domains and certificates is disabled. Ask your system's administrator to enable it."
-msgstr ""
+msgstr "Støtte for domener og sertifikater er deaktivert. Be systemadministratoren din om å aktivere det."
msgid "GitLabPages|The total size of deployed static content will be limited to this size. 0 for unlimited. Leave empty to inherit the global value."
msgstr ""
msgid "GitLabPages|Unverified"
-msgstr ""
+msgstr "Uverifisert"
msgid "GitLabPages|Verified"
-msgstr ""
+msgstr "Verifisert"
msgid "GitLabPages|When using Pages under the general domain of a GitLab instance (%{pages_host}), you cannot use HTTPS with sub-subdomains. This means that if your username/groupname contains a dot it will not work. This is a limitation of the HTTP Over TLS protocol. HTTP pages will continue to work provided you don't redirect HTTP to HTTPS."
-msgstr ""
+msgstr "Når du bruker Sider under det generelle domenet til en GitLab-forekomst (%{pages_host}), kan du ikke bruke HTTPS med under-underdomener. Dette betyr at hvis brukernavnet/gruppenavnet ditt inneholder en prikk, vil det ikke fungere. Dette er en begrensning for «HTTP-over-TLS»-protokollen. HTTP-sider vil fortsette å fungere, forutsatt dersom du ikke omdirigerer HTTP til HTTPS."
msgid "GitLabPages|With GitLab Pages you can host your static websites on GitLab. Combined with the power of GitLab CI and the help of GitLab Runner you can deploy static pages for your individual projects, your user or your group."
msgstr ""
@@ -11788,10 +12149,10 @@ msgid "GitLabPages|Your pages are served under:"
msgstr ""
msgid "Gitaly"
-msgstr ""
+msgstr "Gitaly"
msgid "Gitaly Servers"
-msgstr ""
+msgstr "Gitaly-tjenere"
msgid "Gitaly relative path:"
msgstr ""
@@ -11800,187 +12161,202 @@ msgid "Gitaly storage name:"
msgstr ""
msgid "Gitaly|Address"
-msgstr ""
+msgstr "Adresse"
msgid "Gitea Host URL"
msgstr ""
msgid "Gitea Import"
-msgstr ""
+msgstr "Gitea-importering"
msgid "Gitlab Pages"
+msgstr "Gitlab Pages"
+
+msgid "Gitpod"
msgstr ""
-msgid "Given access %{time_ago}"
+msgid "Gitpod|Add the URL to your Gitpod instance configured to read your GitLab projects."
msgstr ""
+msgid "Gitpod|Enable Gitpod integration"
+msgstr ""
+
+msgid "Gitpod|Gitpod URL"
+msgstr ""
+
+msgid "Gitpod|e.g. https://gitpod.example.com"
+msgstr ""
+
+msgid "Given access %{time_ago}"
+msgstr "Gitt tilgang %{time_ago}"
+
msgid "Given epic is already related to this epic."
msgstr ""
msgid "Global Shortcuts"
-msgstr ""
+msgstr "Globale hurtigtaster"
msgid "Global notification settings"
-msgstr ""
+msgstr "Universelle varslingsinnstillinger"
msgid "Go Back"
-msgstr ""
+msgstr "GÃ¥ tilbake"
msgid "Go Micro is a framework for micro service development."
msgstr ""
msgid "Go back"
-msgstr ""
+msgstr "GÃ¥ tilbake"
msgid "Go back (while searching for files)"
-msgstr ""
+msgstr "Gå tilbake (mens du søker etter filer)"
msgid "Go back to %{startTag}Open issues%{endTag} and select some issues to add to your board."
msgstr ""
msgid "Go full screen"
-msgstr ""
+msgstr "GÃ¥ til fullskjerm"
msgid "Go to %{link_to_google_takeout}."
-msgstr ""
+msgstr "GÃ¥ til %{link_to_google_takeout}."
msgid "Go to %{strongStart}Issues%{strongEnd} &gt; %{strongStart}Boards%{strongEnd} to access your personalized learning issue board."
msgstr ""
msgid "Go to Integrations"
-msgstr ""
+msgstr "GÃ¥ til Integrasjoner"
msgid "Go to Webhooks"
-msgstr ""
+msgstr "GÃ¥ til Webhooks"
msgid "Go to commits"
-msgstr ""
+msgstr "GÃ¥ til commitene"
msgid "Go to definition"
-msgstr ""
+msgstr "GÃ¥ til definisjonen"
msgid "Go to environments"
-msgstr ""
+msgstr "Gå til miljøer"
msgid "Go to epic"
-msgstr ""
+msgstr "GÃ¥ til epos"
msgid "Go to file"
-msgstr ""
+msgstr "GÃ¥ til fil"
msgid "Go to file permalink (while viewing a file)"
-msgstr ""
+msgstr "GÃ¥ til filens permalenke (mens du viser en fil)"
msgid "Go to files"
-msgstr ""
+msgstr "GÃ¥ til filer"
msgid "Go to find file"
msgstr ""
msgid "Go to fork"
-msgstr ""
+msgstr "GÃ¥ til utgreiningen"
msgid "Go to issue boards"
msgstr ""
msgid "Go to issues"
-msgstr ""
+msgstr "GÃ¥ til saker"
msgid "Go to jobs"
-msgstr ""
+msgstr "GÃ¥ til jobber"
msgid "Go to kubernetes"
-msgstr ""
+msgstr "GÃ¥ til kubernetes"
msgid "Go to merge requests"
-msgstr ""
+msgstr "Gå til fletteforespørsler"
msgid "Go to metrics"
-msgstr ""
+msgstr "Gå til målinger"
msgid "Go to parent"
msgstr ""
msgid "Go to project"
-msgstr ""
+msgstr "GÃ¥ til prosjekt"
msgid "Go to releases"
-msgstr ""
+msgstr "GÃ¥ til lanseringer"
msgid "Go to repository charts"
-msgstr ""
+msgstr "GÃ¥ til kodelagerdiagrammer"
msgid "Go to repository graph"
-msgstr ""
+msgstr "GÃ¥ til kodelagerdiagrammet"
msgid "Go to snippets"
-msgstr ""
+msgstr "GÃ¥ til utdrag"
msgid "Go to the activity feed"
-msgstr ""
+msgstr "Gå til aktivitetsstrømmen"
msgid "Go to the milestone list"
-msgstr ""
+msgstr "Gå til milepælliste"
msgid "Go to the project's activity feed"
-msgstr ""
+msgstr "Gå til prosjektets aktivitetsstrøm"
msgid "Go to the project's overview page"
-msgstr ""
+msgstr "GÃ¥ til prosjektets oversiktsside"
msgid "Go to wiki"
-msgstr ""
+msgstr "GÃ¥ til wikien"
msgid "Go to your To-Do list"
-msgstr ""
+msgstr "Gå til gjøremålslisten din"
msgid "Go to your fork"
-msgstr ""
+msgstr "GÃ¥ til utgreiningen din"
msgid "Go to your groups"
-msgstr ""
+msgstr "GÃ¥ til dine grupper"
msgid "Go to your issues"
-msgstr ""
+msgstr "GÃ¥ til dine saker"
msgid "Go to your merge requests"
-msgstr ""
+msgstr "Gå til dine fletteforespørsler"
msgid "Go to your projects"
-msgstr ""
+msgstr "GÃ¥ til dine prosjekter"
msgid "Go to your snippets"
-msgstr ""
+msgstr "GÃ¥ til utdragene dine"
msgid "Google Cloud Platform"
msgstr ""
msgid "Google Code import"
-msgstr ""
+msgstr "Google Code-importering"
msgid "Google Takeout"
-msgstr ""
+msgstr "Google Takeout"
msgid "Google authentication is not %{link_start}properly configured%{link_end}. Ask your GitLab administrator if you want to use this service."
msgstr ""
msgid "Got it"
-msgstr ""
+msgstr "Jeg forstår"
msgid "Got it!"
-msgstr ""
+msgstr "Skjønner!"
msgid "Grafana URL"
-msgstr ""
+msgstr "Grafana-nettadresse"
msgid "Grafana response contains invalid json"
msgstr ""
msgid "GrafanaIntegration|API Token"
-msgstr ""
+msgstr "API-sjetong"
msgid "GrafanaIntegration|Active"
-msgstr ""
+msgstr "Aktiv"
msgid "GrafanaIntegration|Embed Grafana charts in GitLab issues."
msgstr ""
@@ -11992,25 +12368,25 @@ msgid "GrafanaIntegration|Enter the base URL of the Grafana instance."
msgstr ""
msgid "GrafanaIntegration|Grafana URL"
-msgstr ""
+msgstr "Grafana-URL"
msgid "GrafanaIntegration|Grafana authentication"
-msgstr ""
+msgstr "Grafana-autentisering"
msgid "Grant access"
-msgstr ""
+msgstr "Gi tilgang"
msgid "Graph"
-msgstr ""
+msgstr "Diagram"
msgid "Gravatar"
-msgstr ""
+msgstr "Gravatar"
msgid "Gravatar enabled"
-msgstr ""
+msgstr "Gravatar er skrudd på"
msgid "Group"
-msgstr ""
+msgstr "Gruppe"
msgid "Group %{group_name} couldn't be exported."
msgstr ""
@@ -12019,28 +12395,28 @@ msgid "Group %{group_name} was exported successfully."
msgstr ""
msgid "Group %{group_name} was scheduled for deletion."
-msgstr ""
+msgstr "Gruppen %{group_name} ble planlagt for sletting."
msgid "Group %{group_name} was successfully created."
-msgstr ""
+msgstr "Gruppen %{group_name} ble vellykket opprettet."
msgid "Group Audit Events"
msgstr ""
msgid "Group CI/CD settings"
-msgstr ""
+msgstr "Gruppe-CI/CD-innstillinger"
msgid "Group Git LFS status:"
-msgstr ""
+msgstr "Gruppe-Git-LFS-status:"
msgid "Group Hooks"
-msgstr ""
+msgstr "Gruppekroker"
msgid "Group ID"
-msgstr ""
+msgstr "Gruppe-ID"
msgid "Group ID: %{group_id}"
-msgstr ""
+msgstr "Gruppe-ID: %{group_id}"
msgid "Group Owner must have signed in with SAML before enabling Group Managed Accounts"
msgstr ""
@@ -12052,28 +12428,28 @@ msgid "Group SAML must be enabled to test"
msgstr ""
msgid "Group URL"
-msgstr ""
+msgstr "Gruppe-URL"
msgid "Group avatar"
-msgstr ""
+msgstr "Gruppeavatar"
msgid "Group by:"
-msgstr ""
+msgstr "Gruppe av:"
msgid "Group description"
-msgstr ""
+msgstr "Gruppebeskrivelse"
msgid "Group description (optional)"
-msgstr ""
+msgstr "Gruppebeskrivelse (valgfritt)"
msgid "Group details"
-msgstr ""
+msgstr "Gruppedetaljer"
msgid "Group export could not be started."
-msgstr ""
+msgstr "Gruppeeksport kunne ikke bli påbegynt."
msgid "Group export error"
-msgstr ""
+msgstr "Gruppeeksporteringsfeil"
msgid "Group export link has expired. Please generate a new export from your group settings."
msgstr ""
@@ -12088,10 +12464,10 @@ msgid "Group has not been marked for deletion"
msgstr ""
msgid "Group import could not be scheduled"
-msgstr ""
+msgstr "Gruppeimport kunne ikke bli planlagt"
msgid "Group info:"
-msgstr ""
+msgstr "Gruppeinfo:"
msgid "Group is required when cluster_type is :group"
msgstr ""
@@ -12100,19 +12476,19 @@ msgid "Group maintainers can register group runners in the %{link}"
msgstr ""
msgid "Group members"
-msgstr ""
+msgstr "Gruppemedlemmer"
msgid "Group milestone"
-msgstr ""
+msgstr "Gruppemilepæl"
msgid "Group name"
-msgstr ""
+msgstr "Gruppenavn"
msgid "Group name (your organization)"
msgstr ""
msgid "Group overview"
-msgstr ""
+msgstr "Gruppeoversikt"
msgid "Group overview content"
msgstr ""
@@ -12136,70 +12512,70 @@ msgid "Group requires separate account"
msgstr ""
msgid "Group variables (inherited)"
-msgstr ""
+msgstr "Gruppevariabler (arvet)"
msgid "Group was exported"
-msgstr ""
+msgstr "Gruppen ble eksportert"
msgid "Group was successfully updated."
-msgstr ""
+msgstr "Gruppen ble vellykket oppdatert."
msgid "Group-level events in %{group_name} (no project-level events)"
msgstr ""
msgid "Group: %{group_name}"
-msgstr ""
+msgstr "Gruppe: %{group_name}"
msgid "Group: %{name}"
-msgstr ""
+msgstr "Gruppe: %{name}"
msgid "GroupActivityMetrics|Issues opened"
-msgstr ""
+msgstr "Saker åpnet"
msgid "GroupActivityMetrics|Members added"
-msgstr ""
+msgstr "Medlemmer lagt til"
msgid "GroupActivityMetrics|Merge Requests opened"
msgstr ""
msgid "GroupActivityMetrics|Recent activity (last 90 days)"
-msgstr ""
+msgstr "Nylig aktivitet (seneste 90 dager)"
msgid "GroupImport|Failed to import group."
-msgstr ""
+msgstr "Mislyktes i å importere gruppe."
msgid "GroupImport|Group '%{group_name}' is being imported."
-msgstr ""
+msgstr "'%{group_name}'-gruppen blir importert."
msgid "GroupImport|Group could not be imported: %{errors}"
-msgstr ""
+msgstr "Gruppen kunne ikke importeres: %{errors}"
msgid "GroupImport|Please wait while we import the group for you. Refresh at will."
msgstr ""
msgid "GroupImport|The group was successfully imported."
-msgstr ""
+msgstr "Gruppen ble vellykket importert."
msgid "GroupImport|Unable to process group import file"
msgstr ""
msgid "GroupRoadmap|%{dateWord} – No end date"
-msgstr ""
+msgstr "%{dateWord} - Ingen sluttdato"
msgid "GroupRoadmap|%{startDateInWords} – %{endDateInWords}"
-msgstr ""
+msgstr "%{startDateInWords} - %{endDateInWords}"
msgid "GroupRoadmap|No start and end date"
-msgstr ""
+msgstr "Ingen start- eller sluttdato"
msgid "GroupRoadmap|No start date – %{dateWord}"
-msgstr ""
+msgstr "Ingen startdato – %{dateWord}"
msgid "GroupRoadmap|Something went wrong while fetching epics"
msgstr ""
msgid "GroupRoadmap|Something went wrong while fetching milestones"
-msgstr ""
+msgstr "Noe gikk galt under innhenting av milepæler"
msgid "GroupRoadmap|Sorry, no epics matched your search"
msgstr ""
@@ -12217,16 +12593,16 @@ msgid "GroupRoadmap|To widen your search, change or remove filters; from %{start
msgstr ""
msgid "GroupSAML|Certificate fingerprint"
-msgstr ""
+msgstr "Sertifikat-fingeravtrykk"
msgid "GroupSAML|Configuration"
-msgstr ""
+msgstr "Oppsett"
msgid "GroupSAML|Copy SAML Response XML"
msgstr ""
msgid "GroupSAML|Default membership role"
-msgstr ""
+msgstr "Standardrolle for nye brukere"
msgid "GroupSAML|Enable SAML authentication for this group."
msgstr ""
@@ -12238,16 +12614,16 @@ msgid "GroupSAML|Enforce users to have dedicated group managed accounts for this
msgstr ""
msgid "GroupSAML|Enforced SSO"
-msgstr ""
+msgstr "HÃ¥ndhevet SSO"
msgid "GroupSAML|Generate a SCIM token"
-msgstr ""
+msgstr "Generer en SCIM-sjetong"
msgid "GroupSAML|Generate a SCIM token to set up your System for Cross-Domain Identity Management."
msgstr ""
msgid "GroupSAML|Identity"
-msgstr ""
+msgstr "Identitet"
msgid "GroupSAML|Identity provider single sign-on URL"
msgstr ""
@@ -12259,10 +12635,10 @@ msgid "GroupSAML|Manage your group’s membership while adding another level of
msgstr ""
msgid "GroupSAML|Members"
-msgstr ""
+msgstr "Medlemmer"
msgid "GroupSAML|Members will be forwarded here when signing in to your group. Get this from your identity provider, where it can also be called \"SSO Service Location\", \"SAML Token Issuance Endpoint\", or \"SAML 2.0/W-Federation URL\"."
-msgstr ""
+msgstr "Medlemmer vil bli videresendt hit når du logger inn på gruppen. Få dette fra identitetsleverandøren din, hvor det også kan kalles \"SSO Service Location\", \"SAML Token Issuance Endpoint\", eller \"SAML 2.0/W-Federation URL\"."
msgid "GroupSAML|NameID"
msgstr ""
@@ -12271,7 +12647,7 @@ msgid "GroupSAML|NameID Format"
msgstr ""
msgid "GroupSAML|Prohibit outer forks"
-msgstr ""
+msgstr "Forby ytre utgreininger"
msgid "GroupSAML|Prohibit outer forks for this group."
msgstr ""
@@ -12280,7 +12656,7 @@ msgid "GroupSAML|SAML Response Output"
msgstr ""
msgid "GroupSAML|SAML Response XML"
-msgstr ""
+msgstr "SAML-respons-XML"
msgid "GroupSAML|SAML Single Sign On"
msgstr ""
@@ -12292,7 +12668,7 @@ msgid "GroupSAML|SCIM API endpoint URL"
msgstr ""
msgid "GroupSAML|SCIM Token"
-msgstr ""
+msgstr "SCIM-sjetong"
msgid "GroupSAML|SHA1 fingerprint of the SAML token signing certificate. Get this from your identity provider, where it can also be called \"Thumbprint\"."
msgstr ""
@@ -12313,19 +12689,16 @@ msgid "GroupSAML|To be able to prohibit outer forks, you first need to enforce d
msgstr ""
msgid "GroupSAML|Toggle SAML authentication"
-msgstr ""
+msgstr "Veksle SAML-autentisering"
msgid "GroupSAML|Valid SAML Response"
-msgstr ""
-
-msgid "GroupSAML|With group managed accounts enabled, all the users without a group managed account will be excluded from the group."
-msgstr ""
+msgstr "Gyldig SAML-respons"
msgid "GroupSAML|With prohibit outer forks flag enabled group members will be able to fork project only inside your group."
msgstr ""
msgid "GroupSAML|Your SCIM token"
-msgstr ""
+msgstr "Din SCIM-sjetong"
msgid "GroupSAML|must match stored NameID of \"%{extern_uid}\" as we use this to identify users. If the NameID changes users will be unable to sign in."
msgstr ""
@@ -12349,16 +12722,16 @@ msgid "GroupSettings|Be careful. Changing a group's parent can have unintended %
msgstr ""
msgid "GroupSettings|Cannot update the path because there are projects under this group that contain Docker images in their Container Registry. Please remove the images from your projects first and try again."
-msgstr ""
+msgstr "Kan ikke oppdatere filbanen fordi det er prosjekter innenfor denne gruppen som inneholder Docker-bilder i container-registeret. Fjern bildene fra prosjektene dine først, og prøv så på nytt."
msgid "GroupSettings|Change group URL"
-msgstr ""
+msgstr "Endre gruppe-URL"
msgid "GroupSettings|Changing group URL can have unintended side effects."
msgstr ""
msgid "GroupSettings|Custom project templates"
-msgstr ""
+msgstr "Tilpassede prosjektmaler"
msgid "GroupSettings|Customize your group badges."
msgstr ""
@@ -12367,19 +12740,19 @@ msgid "GroupSettings|Default to Auto DevOps pipeline for all projects within thi
msgstr ""
msgid "GroupSettings|Disable email notifications"
-msgstr ""
+msgstr "Skru av e-postvarsler"
msgid "GroupSettings|Disable group mentions"
-msgstr ""
+msgstr "Skru av gruppenevninger"
msgid "GroupSettings|Enable delayed project removal"
msgstr ""
msgid "GroupSettings|Export group"
-msgstr ""
+msgstr "Eksporter gruppe"
msgid "GroupSettings|If the parent group's visibility is lower than the group current visibility, visibility levels for subgroups and projects will be changed to match the new parent group's visibility."
-msgstr ""
+msgstr "Hvis overgruppens synlighet er lavere enn gruppens nåværende synlighet, vil synlighetsnivåer for undergrupper og prosjekter endres til å samsvare med den nye overgruppens synlighet."
msgid "GroupSettings|Integrations configured here will automatically apply to all projects in this group."
msgstr ""
@@ -12400,16 +12773,16 @@ msgid "GroupSettings|Please choose a group URL with no special characters."
msgstr ""
msgid "GroupSettings|Prevent forking outside of the group"
-msgstr ""
+msgstr "Forhindre utgreining utenfor gruppen"
msgid "GroupSettings|Prevent forking setting was not saved"
-msgstr ""
+msgstr "Innstilling for forhindring av utgreining ble ikke lagret"
msgid "GroupSettings|Prevent sharing a project within %{group} with other groups"
-msgstr ""
+msgstr "Forhindre deling av et prosjekt innenfor %{group} med andre grupper"
msgid "GroupSettings|Projects will be permanently deleted after a %{waiting_period}-day delay. This delay can be %{customization_link} in instance settings"
-msgstr ""
+msgstr "Prosjekter vil bli slettet permanent etter en %{waiting_period}-dags forsinkelse. Denne forsinkelsen kan være %{customization_link} i instansinnstillinger"
msgid "GroupSettings|Select a sub-group as the custom project template source for this group."
msgstr ""
@@ -12427,25 +12800,25 @@ msgid "GroupSettings|This setting is applied on %{ancestor_group} and has been o
msgstr ""
msgid "GroupSettings|This setting is applied on %{ancestor_group}. To share projects in this group with another group, ask the owner to override the setting or %{remove_ancestor_share_with_group_lock}."
-msgstr ""
+msgstr "Denne innstillingen brukes på %{ancestor_group}. Hvis du vil dele prosjekter i denne gruppen med en annen gruppe, ber du eieren om å overstyre innstillingen eller %{remove_ancestor_share_with_group_lock}."
msgid "GroupSettings|This setting is applied on %{ancestor_group}. You can override the setting or %{remove_ancestor_share_with_group_lock}."
-msgstr ""
+msgstr "Denne innstillingen brukes på %{ancestor_group}. Du kan overstyre innstillingen eller %{remove_ancestor_share_with_group_lock}."
msgid "GroupSettings|This setting will be applied to all subgroups unless overridden by a group owner. Groups that already have access to the project will continue to have access unless removed manually."
-msgstr ""
+msgstr "Denne innstillingen vil bli brukt på alle undergrupper med mindre den overstyres av en gruppeeier. Grupper som allerede har tilgang til prosjektet, vil fortsette å ha tilgang med mindre de fjernes manuelt."
msgid "GroupSettings|This setting will override user notification preferences for all members of the group, subgroups, and projects."
-msgstr ""
+msgstr "Denne innstillingen overstyrer brukervarslingsinnstillinger for alle medlemmer av gruppen, undergrupper og prosjekter."
msgid "GroupSettings|This setting will prevent group members from being notified if the group is mentioned."
-msgstr ""
+msgstr "Denne innstillingen vil forhindre at gruppemedlemmer blir varslet hvis gruppen blir nevnt."
msgid "GroupSettings|This setting will prevent group members from forking projects outside of the group."
msgstr ""
msgid "GroupSettings|Transfer group"
-msgstr ""
+msgstr "Overfør gruppe"
msgid "GroupSettings|You can only transfer the group to a group you manage."
msgstr ""
@@ -12454,7 +12827,7 @@ msgid "GroupSettings|You will need to update your local repositories to point to
msgstr ""
msgid "GroupSettings|cannot be changed by you"
-msgstr ""
+msgstr "kan ikke endres av deg"
msgid "GroupSettings|cannot be disabled when the parent group \"Share with group lock\" is enabled, except by the owner of the parent group"
msgstr ""
@@ -12466,124 +12839,124 @@ msgid "GroupSettings|remove the share with group lock from %{ancestor_group_name
msgstr ""
msgid "Groups"
-msgstr ""
+msgstr "Grupper"
msgid "Groups (%{count})"
-msgstr ""
+msgstr "Grupper (%{count})"
msgid "Groups (%{groups})"
-msgstr ""
+msgstr "Grupper (%{groups})"
msgid "Groups and projects"
-msgstr ""
+msgstr "Grupper og prosjekter"
msgid "Groups and subgroups"
-msgstr ""
+msgstr "Grupper og undergrupper"
msgid "Groups can also be nested by creating %{subgroup_docs_link_start}subgroups%{subgroup_docs_link_end}."
msgstr ""
msgid "Groups to synchronize"
-msgstr ""
+msgstr "Grupper å synkronise"
msgid "Groups with access to %{strong_open}%{project_name}%{strong_close}"
-msgstr ""
+msgstr "Grupper med tilgang til %{strong_open}%{project_name}%{strong_close}"
msgid "Groups with access to %{strong_start}%{group_name}%{strong_end}"
-msgstr ""
+msgstr "Grupper med tilgang til %{strong_start}%{group_name}%{strong_end}"
msgid "GroupsDropdown|Frequently visited"
-msgstr ""
+msgstr "Ofte besøkt"
msgid "GroupsDropdown|Groups you visit often will appear here"
-msgstr ""
+msgstr "Grupper du besøker ofte vil vises her"
msgid "GroupsDropdown|Loading groups"
-msgstr ""
+msgstr "Laster inn grupper"
msgid "GroupsDropdown|Search your groups"
-msgstr ""
+msgstr "Søk blant gruppene dine"
msgid "GroupsDropdown|Something went wrong on our end."
-msgstr ""
+msgstr "Noe gikk galt på vår side av linja."
msgid "GroupsDropdown|Sorry, no groups matched your search"
-msgstr ""
+msgstr "Beklager, ingen grupper samsvarte med søket ditt"
msgid "GroupsDropdown|This feature requires browser localStorage support"
msgstr ""
msgid "GroupsEmptyState|A group is a collection of several projects."
-msgstr ""
+msgstr "En gruppe er en samling med flere prosjekter."
msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
msgstr ""
msgid "GroupsEmptyState|No groups found"
-msgstr ""
+msgstr "Ingen grupper ble funnet"
msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
msgstr ""
msgid "GroupsNew|Contact an administrator to enable options for importing your group."
-msgstr ""
+msgstr "Kontakt en administrator for å aktivere alternativer for å importere gruppen din."
msgid "GroupsNew|Create"
-msgstr ""
+msgstr "Opprett"
msgid "GroupsNew|Create group"
-msgstr ""
-
-msgid "GroupsNew|GitLab group export"
-msgstr ""
+msgstr "Opprett gruppe"
msgid "GroupsNew|Import"
+msgstr "Importer"
+
+msgid "GroupsNew|Import a GitLab group export file"
msgstr ""
msgid "GroupsNew|Import group"
-msgstr ""
+msgstr "Importer gruppe"
msgid "GroupsNew|My Awesome Group"
-msgstr ""
+msgstr "Min fantastiske gruppe"
msgid "GroupsNew|No import options available"
-msgstr ""
+msgstr "Ingen importalternativer er tilgjengelige"
msgid "GroupsNew|To copy a GitLab group between installations, navigate to the group settings page for the original installation, generate an export file, and upload it here."
msgstr ""
msgid "GroupsTree|Are you sure you want to leave the \"%{fullName}\" group?"
-msgstr ""
+msgstr "Er du sikker på at du vil forlate «%{fullName}»-gruppen?"
msgid "GroupsTree|Create a project in this group."
-msgstr ""
+msgstr "Opprett en prosjekt i denne gruppen."
msgid "GroupsTree|Create a subgroup in this group."
-msgstr ""
+msgstr "Opprett en undergruppe i denne gruppen."
msgid "GroupsTree|Edit group"
-msgstr ""
+msgstr "Rediger gruppe"
msgid "GroupsTree|Failed to leave the group. Please make sure you are not the only owner."
-msgstr ""
+msgstr "Klarte ikke å forlate gruppen. Forsikre deg om at du ikke er den eneste eieren."
msgid "GroupsTree|Leave this group"
-msgstr ""
+msgstr "Forlat denne gruppen"
msgid "GroupsTree|Loading groups"
-msgstr ""
+msgstr "Laster inn grupper"
msgid "GroupsTree|No groups matched your search"
-msgstr ""
+msgstr "Ingen grupper samsvarte med søket ditt"
msgid "GroupsTree|No groups or projects matched your search"
-msgstr ""
+msgstr "Ingen grupper eller prosjekter samsvarte med søket ditt"
msgid "GroupsTree|Search by name"
-msgstr ""
+msgstr "Søk etter navn"
msgid "Guideline"
-msgstr ""
+msgstr "Retningslinje"
msgid "HTTP Basic: Access denied\\nYou must use a personal access token with 'api' scope for Git over HTTP.\\nYou can generate one at %{profile_personal_access_tokens_url}"
msgstr ""
@@ -12607,19 +12980,19 @@ msgid "Header message"
msgstr ""
msgid "Headings"
-msgstr ""
+msgstr "Overskrifter"
msgid "Health"
-msgstr ""
+msgstr "Helse"
msgid "Health Check"
-msgstr ""
+msgstr "Helsesjekk"
msgid "Health information can be retrieved from the following endpoints. More information is available"
msgstr ""
msgid "Health status"
-msgstr ""
+msgstr "Helsestatus"
msgid "Health status cannot be edited because this issue is closed"
msgstr ""
@@ -12628,25 +13001,25 @@ msgid "HealthCheck|Access token is"
msgstr ""
msgid "HealthCheck|Healthy"
-msgstr ""
+msgstr "God helse"
msgid "HealthCheck|No Health Problems Detected"
msgstr ""
msgid "HealthCheck|Unhealthy"
-msgstr ""
+msgstr "DÃ¥rlig helse"
msgid "Hello there"
-msgstr ""
+msgstr "Heisann"
msgid "Hello, %{username}!"
-msgstr ""
+msgstr "Hallo, %{username}!"
msgid "Help"
-msgstr ""
+msgstr "Hjelp"
msgid "Help page"
-msgstr ""
+msgstr "Hjelpeside"
msgid "Help page text and support page url."
msgstr ""
@@ -12664,36 +13037,39 @@ msgid "Helps reduce request volume for protected paths"
msgstr ""
msgid "Here are all your projects in your group, including the one you just created. To start, let’s take a look at your personalized learning project which will help you learn about GitLab at your own pace."
-msgstr ""
+msgstr "Her er alle prosjektene dine i gruppen din, inkludert den du nettopp opprettet. For å begynne, la oss ta en titt på ditt personlige læringsprosjekt som vil hjelpe deg å lære om GitLab i ditt eget tempo."
msgid "Here you will find recent merge request activity"
msgstr ""
msgid "Hi %{username}!"
-msgstr ""
+msgstr "Hei, %{username}!"
msgid "Hide archived projects"
-msgstr ""
+msgstr "Skjul arkiverte prosjekter"
msgid "Hide chart"
msgid_plural "Hide charts"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "Skjul diagram"
+msgstr[1] "Skjul diagrammer"
-msgid "Hide details"
+msgid "Hide comments on this file"
msgstr ""
+msgid "Hide details"
+msgstr "Skjul detaljer"
+
msgid "Hide file browser"
-msgstr ""
+msgstr "Skjul filutforsker"
msgid "Hide group projects"
-msgstr ""
+msgstr "Skjul gruppeprosjekter"
msgid "Hide host keys manual input"
msgstr ""
msgid "Hide list"
-msgstr ""
+msgstr "Skjul liste"
msgid "Hide marketing-related entries from help"
msgstr ""
@@ -12702,18 +13078,18 @@ msgid "Hide payload"
msgstr ""
msgid "Hide shared projects"
-msgstr ""
+msgstr "Skjul delte prosjekter"
msgid "Hide stage"
-msgstr ""
+msgstr "Skjul trinn"
msgid "Hide value"
msgid_plural "Hide values"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "Skjul verdien"
+msgstr[1] "Skjul verdiene"
msgid "Hide values"
-msgstr ""
+msgstr "Skjul verdier"
msgid "High or unknown vulnerabilities present"
msgstr ""
@@ -12722,34 +13098,43 @@ msgid "Highest number of requests per minute for each raw path, default to 300.
msgstr ""
msgid "Highest role:"
+msgstr "Høyeste rolle:"
+
+msgid "HighlightBar|Alert events:"
msgstr ""
-msgid "History"
+msgid "HighlightBar|Alert start time:"
+msgstr ""
+
+msgid "HighlightBar|Original alert:"
msgstr ""
+msgid "History"
+msgstr "Historie"
+
msgid "History of authentications"
msgstr ""
msgid "Homepage"
-msgstr ""
+msgstr "Hjemmeside"
msgid "Hook execution failed. Ensure the group has a project with commits."
msgstr ""
msgid "Hook was successfully created."
-msgstr ""
+msgstr "Kroken ble vellykket opprettet."
msgid "Hook was successfully updated."
-msgstr ""
+msgstr "Kroken ble vellykket oppdatert."
msgid "Hostname"
-msgstr ""
+msgstr "Servernavn"
msgid "Hour (UTC)"
-msgstr ""
+msgstr "Time (UTC)"
msgid "Housekeeping"
-msgstr ""
+msgstr "Renhold"
msgid "Housekeeping successfully started"
msgstr ""
@@ -12758,7 +13143,7 @@ msgid "Housekeeping, export, path, transfer, remove, archive."
msgstr ""
msgid "How it works"
-msgstr ""
+msgstr "Hvordan det virker"
msgid "How many days need to pass between marking entity for deletion and actual removing it."
msgstr ""
@@ -12767,28 +13152,28 @@ msgid "How many replicas each Elasticsearch shard has."
msgstr ""
msgid "How many shards to split the Elasticsearch index over."
-msgstr ""
+msgstr "Hvor mange skår å dele opp Elasticsearch-indeksen i."
msgid "How many users will be evaluating the trial?"
msgstr ""
msgid "How to upgrade"
-msgstr ""
+msgstr "Hvordan oppgraderer man"
msgid "However, you are already a member of this %{member_source}. Sign in using a different account to accept the invitation."
-msgstr ""
+msgstr "Du er imidlertid allerede et medlem av denne %{member_source}. Logg på med en annen konto for å godta invitasjonen."
msgid "I accept the %{terms_link_start}Terms of Service and Privacy Policy%{terms_link_end}"
msgstr ""
msgid "I accept the %{terms_link}"
-msgstr ""
+msgstr "Jeg aksepterer %{terms_link}"
msgid "I accept the|Terms of Service and Privacy Policy"
msgstr ""
msgid "I forgot my password"
-msgstr ""
+msgstr "Jeg glemte passordet mitt"
msgid "I have read and agree to the Let's Encrypt %{link_start}Terms of Service%{link_end} (PDF)"
msgstr ""
@@ -12797,49 +13182,49 @@ msgid "I'd like to receive updates via email about GitLab"
msgstr ""
msgid "ID"
-msgstr ""
+msgstr "ID"
msgid "ID:"
-msgstr ""
+msgstr "ID:"
msgid "IDE"
-msgstr ""
+msgstr "IDE"
msgid "IDE|Allow live previews of JavaScript projects in the Web IDE using CodeSandbox Live Preview."
msgstr ""
msgid "IDE|Back"
-msgstr ""
+msgstr "Tilbake"
msgid "IDE|Commit"
-msgstr ""
+msgstr "Commit"
msgid "IDE|Commit to %{branchName} branch"
msgstr ""
msgid "IDE|Edit"
-msgstr ""
+msgstr "Rediger"
msgid "IDE|Get started with Live Preview"
msgstr ""
msgid "IDE|Go to project"
-msgstr ""
+msgstr "GÃ¥ til prosjekt"
msgid "IDE|Live Preview"
-msgstr ""
+msgstr "Forhåndsvisning"
msgid "IDE|Preview your web application using Web IDE client-side evaluation."
msgstr ""
msgid "IDE|Refresh preview"
-msgstr ""
+msgstr "Oppdater forhåndsvisning"
msgid "IDE|Review"
-msgstr ""
+msgstr "Omtale"
msgid "IDE|Successful commit"
-msgstr ""
+msgstr "Vellykket commit"
msgid "IDE|This option is disabled because you are not allowed to create merge requests in this project."
msgstr ""
@@ -12848,28 +13233,28 @@ msgid "IDE|This option is disabled because you don't have write permissions for
msgstr ""
msgid "INFO: Your SSH key has expired. Please generate a new key."
-msgstr ""
+msgstr "SSH-nøkkelen din har utløpt. Vennligst generer en ny nøkkel."
msgid "INFO: Your SSH key is expiring soon. Please generate a new key."
-msgstr ""
+msgstr "SSH-nøkkelen din utløper snart. Vennligst generer en ny nøkkel."
msgid "IP Address"
-msgstr ""
+msgstr "IP-adresse"
msgid "IP subnet restriction only allowed for top-level groups"
msgstr ""
msgid "Identifier"
-msgstr ""
+msgstr "Identifikator"
msgid "Identifiers"
-msgstr ""
+msgstr "Identifikasjoner"
msgid "Identities"
-msgstr ""
+msgstr "Identiteter"
msgid "If any indexed field exceeds this limit it will be truncated to this number of characters and the rest will not be indexed or searchable. This does not apply to repository and wiki indexing. Setting this to 0 means it is unlimited."
-msgstr ""
+msgstr "Hvis et indeksert felt overskrider denne grensen, blir det avkortet til dette antall tegn, og resten vil ikke bli indeksert eller søkbart. Dette gjelder ikke indeksering av kodelageret og wikien. Hvis du setter dette til 0, betyr det at det er ubegrenset."
msgid "If any job surpasses this timeout threshold, it will be marked as failed. Human readable time input language is accepted like \"1 hour\". Values without specification represent seconds."
msgstr ""
@@ -12884,7 +13269,7 @@ msgid "If checked, new group memberships and permissions can only be added via L
msgstr ""
msgid "If disabled, a diverged local branch will not be automatically updated with commits from its remote counterpart, to prevent local data loss. If the default branch (%{default_branch}) has diverged and cannot be updated, mirroring will fail. Other diverged branches are silently ignored."
-msgstr ""
+msgstr "Hvis det er deaktivert, vil en avvikende lokal gren ikke automatisk bli oppdatert med forpliktelser fra den eksterne motparten, for å forhindre lokalt datatap. Hvis standardgrenen (%{default_branch}) har avveket og ikke kan oppdateres, vil speiling mislykkes. Andre avvikende grener ignoreres lydløst."
msgid "If disabled, only admins will be able to configure repository mirroring."
msgstr ""
@@ -12893,7 +13278,7 @@ msgid "If disabled, the access level will depend on the user's permissions in th
msgstr ""
msgid "If enabled"
-msgstr ""
+msgstr "Hvis aktivert"
msgid "If enabled, GitLab will handle Object Storage replication using Geo. %{linkStart}More information%{linkEnd}"
msgstr ""
@@ -12901,14 +13286,17 @@ msgstr ""
msgid "If enabled, access to projects will be validated on an external service using their classification label."
msgstr ""
-msgid "If there is no previous license or if the previous license has expired, some GitLab functionality will be blocked until a new, valid license is uploaded."
+msgid "If the number of active users exceeds the user limit, you will be charged for the number of %{users_over_license_link} at your next license reconciliation."
msgstr ""
+msgid "If there is no previous license or if the previous license has expired, some GitLab functionality will be blocked until a new, valid license is uploaded."
+msgstr "Hvis det ikke er noen tidligere lisens, eller hvis den forrige lisensen har utløpt, vil noe GitLab-funksjonalitet bli blokkert frem til en ny og gyldig lisens lastes opp."
+
msgid "If this was a mistake you can %{leave_link_start}leave the %{source_type}%{link_end}."
-msgstr ""
+msgstr "Hvis dette var en feil, kan du %{leave_link_start}forlate %{source_type}%{link_end}."
msgid "If this was a mistake you can leave the %{source_type}."
-msgstr ""
+msgstr "Hvis dette var en feil, kan du forlate %{source_type}."
msgid "If using GitHub, you’ll see pipeline statuses on GitHub for your commits and pull requests. %{more_info_link}"
msgstr ""
@@ -12940,20 +13328,17 @@ msgstr ""
msgid "If your HTTP repository is not publicly accessible, add your credentials."
msgstr ""
-msgid "Iglu registry URL (optional)"
-msgstr ""
-
msgid "Ignore"
-msgstr ""
+msgstr "Ignorer"
msgid "Ignored"
-msgstr ""
+msgstr "Ignorert"
msgid "Image Details"
-msgstr ""
+msgstr "Bildedetaljer"
msgid "Image URL"
-msgstr ""
+msgstr "Bilde URL"
msgid "ImageDiffViewer|2-up"
msgstr ""
@@ -12962,13 +13347,13 @@ msgid "ImageDiffViewer|Onion skin"
msgstr ""
msgid "ImageDiffViewer|Swipe"
-msgstr ""
+msgstr "Sveip"
msgid "ImageViewerDimensions|H"
-msgstr ""
+msgstr "H"
msgid "ImageViewerDimensions|W"
-msgstr ""
+msgstr "B"
msgid "Impersonation Tokens"
msgstr ""
@@ -12977,91 +13362,95 @@ msgid "Impersonation has been disabled"
msgstr ""
msgid "Import"
-msgstr ""
+msgstr "Importer"
+
+msgid "Import %d compatible repository"
+msgid_plural "Import %d compatible repositories"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Import %d repository"
+msgid_plural "Import %d repositories"
+msgstr[0] ""
+msgstr[1] ""
msgid "Import CSV"
-msgstr ""
+msgstr "Importer CSV"
msgid "Import Projects from Gitea"
-msgstr ""
+msgstr "Importer prosjekter fra Gitea"
msgid "Import all compatible projects"
-msgstr ""
-
-msgid "Import all compatible repositories"
-msgstr ""
+msgstr "Importer alle kompatible prosjekter"
msgid "Import all projects"
-msgstr ""
-
-msgid "Import all repositories"
-msgstr ""
+msgstr "Importer alle prosjekter"
msgid "Import an exported GitLab project"
-msgstr ""
+msgstr "Importer et eksportert GitLab-prosjekt"
msgid "Import failed due to a GitHub error: %{original}"
-msgstr ""
+msgstr "Importering mislyktes på grunn av en GitHub-feil: %{original}"
msgid "Import from"
-msgstr ""
+msgstr "Importer fra"
msgid "Import from Jira"
-msgstr ""
+msgstr "Importer fra Jira"
msgid "Import in progress"
-msgstr ""
+msgstr "Holder på å importere"
msgid "Import in progress. Refresh page to see newly added issues."
msgstr ""
msgid "Import issues"
-msgstr ""
+msgstr "Importer saker"
msgid "Import members"
-msgstr ""
+msgstr "Importer medlemmer"
msgid "Import members from another project"
-msgstr ""
+msgstr "Importer medlemmer fra et annet prosjekt"
msgid "Import multiple repositories by uploading a manifest file."
msgstr ""
msgid "Import project"
-msgstr ""
+msgstr "Importer prosjekt"
msgid "Import project members"
-msgstr ""
+msgstr "Importer prosjektmedlemmer"
msgid "Import projects from Bitbucket"
-msgstr ""
+msgstr "Importer prosjekter fra Bitbucket"
msgid "Import projects from Bitbucket Server"
-msgstr ""
+msgstr "Importer prosjekter fra Bitbucket Server"
msgid "Import projects from FogBugz"
-msgstr ""
+msgstr "Importer prosjekter fra FogBugz"
msgid "Import projects from GitLab.com"
-msgstr ""
+msgstr "Importer prosjekter fra GitLab.com"
msgid "Import projects from Google Code"
-msgstr ""
+msgstr "Importer prosjekter fra Google Code"
msgid "Import repositories from Bitbucket Server"
-msgstr ""
+msgstr "Importer kodelagre fra Bitbucket Server"
msgid "Import repositories from GitHub"
-msgstr ""
+msgstr "Importer kodelagre fra GitHub"
msgid "Import repository"
-msgstr ""
+msgstr "Importer kodelager"
msgid "Import started by: %{importInitiator}"
-msgstr ""
+msgstr "Importering startet av: %{importInitiator}"
msgid "Import tasks"
-msgstr ""
+msgstr "Importer oppgaver"
msgid "Import tasks from Phabricator into issues"
msgstr ""
@@ -13076,7 +13465,7 @@ msgid "Import/Export illustration"
msgstr ""
msgid "ImportButtons|Connect repositories from"
-msgstr ""
+msgstr "Koble til kodelagre fra"
msgid "ImportProjects|Blocked import URL: %{message}"
msgstr ""
@@ -13084,9 +13473,12 @@ msgstr ""
msgid "ImportProjects|Error importing repository %{project_safe_import_url} into %{project_full_path} - %{message}"
msgstr ""
-msgid "ImportProjects|Importing the project failed"
+msgid "ImportProjects|Import repositories"
msgstr ""
+msgid "ImportProjects|Importing the project failed"
+msgstr "Importering av prosjektet mislyktes"
+
msgid "ImportProjects|Importing the project failed: %{reason}"
msgstr ""
@@ -13096,14 +13488,14 @@ msgstr ""
msgid "ImportProjects|Requesting your %{provider} repositories failed"
msgstr ""
-msgid "ImportProjects|Select the projects you want to import"
+msgid "ImportProjects|Select the repositories you want to import"
msgstr ""
msgid "ImportProjects|The remote data could not be imported."
msgstr ""
msgid "ImportProjects|The repository could not be created."
-msgstr ""
+msgstr "Kodelageret kunne ikke bli opprettet."
msgid "ImportProjects|Update of imported projects with realtime changes failed"
msgstr ""
@@ -13127,19 +13519,16 @@ msgid "Improve search with Advanced Search and GitLab Enterprise Edition."
msgstr ""
msgid "In %{time_to_now}"
-msgstr ""
+msgstr "Om %{time_to_now}"
msgid "In order to enable Service Desk for your instance, you must first set up incoming email."
msgstr ""
-msgid "In order to gather accurate feature usage data, it can take 1 to 2 weeks to see your index."
-msgstr ""
-
msgid "In order to personalize your experience with GitLab%{br_tag}we would like to know a bit more about you."
msgstr ""
msgid "In progress"
-msgstr ""
+msgstr "Under arbeid"
msgid "In the next step, you'll be able to select the projects you want to import."
msgstr ""
@@ -13151,32 +13540,44 @@ msgid "Incident Management Limits"
msgstr ""
msgid "IncidentManagement|All"
-msgstr ""
+msgstr "Alle"
msgid "IncidentManagement|All alerts promoted to incidents will automatically be displayed within the list. You can also create a new incident using the button below."
msgstr ""
msgid "IncidentManagement|Assignees"
-msgstr ""
+msgstr "Tilordnede"
msgid "IncidentManagement|Closed"
-msgstr ""
+msgstr "Lukket"
msgid "IncidentManagement|Create incident"
msgstr ""
-msgid "IncidentManagement|Date created"
+msgid "IncidentManagement|Critical - S1"
msgstr ""
+msgid "IncidentManagement|Date created"
+msgstr "Dato opprettet"
+
msgid "IncidentManagement|Display your incidents in a dedicated view"
msgstr ""
+msgid "IncidentManagement|High - S2"
+msgstr ""
+
msgid "IncidentManagement|Incident"
msgstr ""
msgid "IncidentManagement|Incidents"
msgstr ""
+msgid "IncidentManagement|Low - S4"
+msgstr ""
+
+msgid "IncidentManagement|Medium - S3"
+msgstr ""
+
msgid "IncidentManagement|No incidents to display."
msgstr ""
@@ -13184,11 +13585,14 @@ msgid "IncidentManagement|Open"
msgstr ""
msgid "IncidentManagement|Published"
-msgstr ""
+msgstr "Publisert"
msgid "IncidentManagement|Published to status page"
msgstr ""
+msgid "IncidentManagement|Severity"
+msgstr ""
+
msgid "IncidentManagement|There are no closed incidents"
msgstr ""
@@ -13196,10 +13600,13 @@ msgid "IncidentManagement|There was an error displaying the incidents."
msgstr ""
msgid "IncidentManagement|Unassigned"
+msgstr "Utilordnet"
+
+msgid "IncidentManagement|Unknown"
msgstr ""
msgid "IncidentManagement|Unpublished"
-msgstr ""
+msgstr "Upublisert"
msgid "IncidentSettings|Alert integration"
msgstr ""
@@ -13219,6 +13626,15 @@ msgstr ""
msgid "Incidents"
msgstr ""
+msgid "Incident|Alert details"
+msgstr ""
+
+msgid "Incident|Summary"
+msgstr ""
+
+msgid "Incident|There was an issue loading alert data. Please try again."
+msgstr ""
+
msgid "Include a Terms of Service agreement and Privacy Policy that all users must accept."
msgstr ""
@@ -13226,7 +13642,7 @@ msgid "Include author name in notification email body"
msgstr ""
msgid "Include description in commit message"
-msgstr ""
+msgstr "Inkluder beskrivelsen i commit-meldingen"
msgid "Include merge request description"
msgstr ""
@@ -13247,25 +13663,25 @@ msgid "Includes an MVC structure, mvnw and pom.xml to help you get started."
msgstr ""
msgid "Incoming email"
-msgstr ""
+msgstr "Innkommende e-post"
msgid "Incoming!"
-msgstr ""
+msgstr "Innkommende!"
msgid "Incompatible Project"
-msgstr ""
+msgstr "Inkompatibelt prosjekt"
msgid "Incompatible options set!"
msgstr ""
msgid "Incompatible project"
-msgstr ""
+msgstr "Inkompatibelt prosjekt"
msgid "Indent"
-msgstr ""
+msgstr "Rykk inn"
msgid "Index all projects"
-msgstr ""
+msgstr "Indekser alle prosjekter"
msgid "Index deletion is canceled"
msgstr ""
@@ -13279,41 +13695,44 @@ msgstr ""
msgid "Information about additional Pages templates and how to install them can be found in our %{pages_getting_started_guide}."
msgstr ""
-msgid "Inherited:"
+msgid "Inherited"
msgstr ""
+msgid "Inherited:"
+msgstr "Arvet:"
+
msgid "Inline"
-msgstr ""
+msgstr "Integrert"
msgid "Input host keys manually"
msgstr ""
msgid "Input your repository URL"
-msgstr ""
+msgstr "Skriv inn din kodelager-URL"
msgid "Insert"
-msgstr ""
+msgstr "Sett inn"
msgid "Insert a code block"
-msgstr ""
+msgstr "Sett inn en kodeblokk"
msgid "Insert a quote"
-msgstr ""
+msgstr "Sett inn et sitat"
msgid "Insert an image"
-msgstr ""
+msgstr "Sett inn et bilde"
msgid "Insert code"
-msgstr ""
+msgstr "Sett inn kode"
msgid "Insert inline code"
msgstr ""
msgid "Insert suggestion"
-msgstr ""
+msgstr "Sett inn forslag"
msgid "Insights"
-msgstr ""
+msgstr "Innsikter"
msgid "Insights|Some items are not visible beacuse the project was filtered out in the insights.yml file (see the projects.only config for more information)."
msgstr ""
@@ -13322,7 +13741,7 @@ msgid "Insights|This project is filtered out in the insights.yml file (see the p
msgstr ""
msgid "Install"
-msgstr ""
+msgstr "Installer"
msgid "Install GitLab Runner"
msgstr ""
@@ -13331,53 +13750,80 @@ msgid "Install Runner on Kubernetes"
msgstr ""
msgid "Install a soft token authenticator like %{free_otp_link} or Google Authenticator from your application repository and use that app to scan this QR code. More information is available in the %{help_link_start}documentation%{help_link_end}."
-msgstr ""
+msgstr "Installer en myksjetongautentikator som %{free_otp_link} eller Google Autentisering fra applikasjonskodelageret ditt og bruk den appen til å skanne QR-koden. Mer informasjon er tilgjengelig i dokumentasjonen %{help_link_start}%{help_link_end}."
msgid "Install on clusters"
-msgstr ""
+msgstr "Installer i klynger"
msgid "Installation"
-msgstr ""
+msgstr "Installasjon"
msgid "Installed"
-msgstr ""
+msgstr "Installert"
msgid "Installing"
-msgstr ""
+msgstr "Installerer"
msgid "Instance"
msgid_plural "Instances"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "Instans"
+msgstr[1] "Instanser"
msgid "Instance Configuration"
-msgstr ""
+msgstr "Instans-oppsett"
msgid "Instance Statistics"
-msgstr ""
+msgstr "Instansstatistikker"
msgid "Instance administrators group already exists"
msgstr ""
-msgid "Instance license"
+msgid "InstanceStatistics|Groups"
msgstr ""
-msgid "Integration"
+msgid "InstanceStatistics|Issues"
msgstr ""
-msgid "Integration Settings"
+msgid "InstanceStatistics|Merge Requests"
+msgstr ""
+
+msgid "InstanceStatistics|Pipelines"
+msgstr ""
+
+msgid "InstanceStatistics|Projects"
+msgstr ""
+
+msgid "InstanceStatistics|Users"
msgstr ""
+msgid "Integration"
+msgstr "Integrasjon"
+
+msgid "Integration Settings"
+msgstr "Integrasjonsinnstillinger"
+
msgid "Integrations"
+msgstr "Integrasjoner"
+
+msgid "Integrations|%{integration} settings saved and active."
msgstr ""
-msgid "Integrations|All details"
+msgid "Integrations|%{integration} settings saved, but not active."
msgstr ""
+msgid "Integrations|All details"
+msgstr "Alle detaljer"
+
msgid "Integrations|Comment detail:"
-msgstr ""
+msgstr "Kommentardetalj:"
msgid "Integrations|Comment settings:"
+msgstr "Kommentarinnstillinger"
+
+msgid "Integrations|Connection failed. Please check your settings."
+msgstr ""
+
+msgid "Integrations|Connection successful."
msgstr ""
msgid "Integrations|Default settings are inherited from the group level."
@@ -13387,22 +13833,31 @@ msgid "Integrations|Default settings are inherited from the instance level."
msgstr ""
msgid "Integrations|Enable comments"
-msgstr ""
+msgstr "Skru på kommentarer"
msgid "Integrations|Includes Standard plus entire commit message, commit hash, and issue IDs"
msgstr ""
msgid "Integrations|Includes commit title and branch"
+msgstr "Inkluderer commit-tittelen og grenen"
+
+msgid "Integrations|Projects using custom settings will not be impacted unless the project owner chooses to use instance-level defaults."
msgstr ""
-msgid "Integrations|Standard"
+msgid "Integrations|Save settings?"
msgstr ""
-msgid "Integrations|Use custom settings"
+msgid "Integrations|Saving will update the default settings for all projects that are not using custom settings."
msgstr ""
+msgid "Integrations|Standard"
+msgstr "Standard "
+
+msgid "Integrations|Use custom settings"
+msgstr "Bruk tilpassede innstillinger"
+
msgid "Integrations|Use default settings"
-msgstr ""
+msgstr "Bruk forvalgte innstillinger"
msgid "Integrations|When a Jira issue is mentioned in a commit or merge request a remote link and comment (if enabled) will be created."
msgstr ""
@@ -13411,7 +13866,7 @@ msgid "Interested parties can even contribute by pushing commits if they want to
msgstr ""
msgid "Internal"
-msgstr ""
+msgstr "Intern"
msgid "Internal - The group and any internal projects can be viewed by any logged in user."
msgstr ""
@@ -13420,10 +13875,10 @@ msgid "Internal - The project can be accessed by any logged in user."
msgstr ""
msgid "Internal URL (optional)"
-msgstr ""
+msgstr "Intern URL (valgfritt)"
msgid "Internal users"
-msgstr ""
+msgstr "Interne brukere"
msgid "Interval Pattern"
msgstr ""
@@ -13435,19 +13890,19 @@ msgid "Introducing Your DevOps Report"
msgstr ""
msgid "Invalid Git ref"
-msgstr ""
+msgstr "Ugyldig Git-ref"
msgid "Invalid Insights config file detected"
msgstr ""
msgid "Invalid Login or password"
-msgstr ""
+msgstr "Ugyldig pålogging eller passord"
msgid "Invalid OS"
-msgstr ""
+msgstr "Ugyldig OS"
msgid "Invalid URL"
-msgstr ""
+msgstr "Ugyldig URL"
msgid "Invalid board"
msgstr ""
@@ -13462,49 +13917,49 @@ msgid "Invalid cursor value provided"
msgstr ""
msgid "Invalid date"
-msgstr ""
+msgstr "Ugyldig dato"
msgid "Invalid date format. Please use UTC format as YYYY-MM-DD"
msgstr ""
msgid "Invalid date range"
-msgstr ""
+msgstr "Ugyldig datoperiode"
msgid "Invalid feature"
-msgstr ""
+msgstr "Ugyldig funksjon"
msgid "Invalid field"
-msgstr ""
+msgstr "Ugyldig felt"
msgid "Invalid file format with specified file type"
msgstr ""
msgid "Invalid file."
-msgstr ""
+msgstr "Ugyldig fil."
msgid "Invalid import params"
-msgstr ""
+msgstr "Ugyldige importparametre"
msgid "Invalid input, please avoid emojis"
msgstr ""
msgid "Invalid login or password"
-msgstr ""
+msgstr "Ugyldig brukernavn eller passord"
msgid "Invalid pin code"
-msgstr ""
+msgstr "Ugyldig PIN-kode"
msgid "Invalid pod_name"
msgstr ""
msgid "Invalid query"
-msgstr ""
+msgstr "Ugyldig spørring"
msgid "Invalid repository bundle for snippet with id %{snippet_id}"
msgstr ""
msgid "Invalid repository path"
-msgstr ""
+msgstr "Ugyldig kodelager-filbane"
msgid "Invalid search parameter"
msgstr ""
@@ -13516,61 +13971,64 @@ msgid "Invalid start or end time format"
msgstr ""
msgid "Invalid status"
-msgstr ""
+msgstr "Ugyldig status"
msgid "Invalid two-factor code."
-msgstr ""
+msgstr "Ugyldig 2-trinnskode."
msgid "Invalid yaml"
-msgstr ""
+msgstr "Ugyldig yaml"
msgid "Invitation"
+msgstr "Invitasjon"
+
+msgid "Invitation declined"
msgstr ""
msgid "Invite"
-msgstr ""
+msgstr "Inviter"
msgid "Invite \"%{trimmed}\" by email"
-msgstr ""
+msgstr "Inviter «%{trimmed}» via e-post"
msgid "Invite Members"
-msgstr ""
+msgstr "Inviter medlemmer"
msgid "Invite another teammate"
-msgstr ""
+msgstr "Inviter en annen teamkamerat"
msgid "Invite group"
-msgstr ""
+msgstr "Inviter gruppe"
msgid "Invite member"
-msgstr ""
+msgstr "Inviter medlem"
msgid "Invite teammates (optional)"
msgstr ""
msgid "InviteEmail|%{inviter} invited you"
-msgstr ""
+msgstr "%{inviter} inviterte deg"
msgid "InviteEmail|%{project_or_group} as a %{role}"
-msgstr ""
+msgstr "%{project_or_group} som en %{role}"
msgid "InviteEmail|Join now"
-msgstr ""
+msgstr "Bli med nå"
msgid "InviteEmail|You are invited!"
-msgstr ""
+msgstr "Du har blitt invitert!"
msgid "InviteEmail|You have been invited"
-msgstr ""
+msgstr "Du har blitt invitert"
msgid "InviteEmail|to join the %{project_or_group_name} %{project_or_group} as a %{role}"
-msgstr ""
+msgstr "til å bli med i %{project_or_group_name} %{project_or_group} som en %{role}"
msgid "InviteEmail|to join the %{strong_start}%{project_or_group_name}%{strong_end}"
-msgstr ""
+msgstr "Til å bli med i %{strong_start}%{project_or_group_name}%{strong_end}"
msgid "InviteMembersBanner|Collaborate with your team"
-msgstr ""
+msgstr "Samarbeid med teamet ditt"
msgid "InviteMembersBanner|Invite your colleagues"
msgstr ""
@@ -13578,9 +14036,45 @@ 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 "Invited"
+msgid "InviteMembersModal|%{linkStart}Read more%{linkEnd} about role permissions"
+msgstr ""
+
+msgid "InviteMembersModal|Access expiration date (optional)"
+msgstr ""
+
+msgid "InviteMembersModal|Cancel"
+msgstr ""
+
+msgid "InviteMembersModal|Choose a role permission"
+msgstr ""
+
+msgid "InviteMembersModal|GitLab member or Email address"
+msgstr ""
+
+msgid "InviteMembersModal|Invite"
+msgstr ""
+
+msgid "InviteMembersModal|Invite team members"
+msgstr ""
+
+msgid "InviteMembersModal|Search for members to invite"
+msgstr ""
+
+msgid "InviteMembersModal|User not invited. Feature coming soon!"
msgstr ""
+msgid "InviteMembersModal|Users were succesfully added"
+msgstr ""
+
+msgid "InviteMembersModal|You're inviting members to the %{group_name} group"
+msgstr ""
+
+msgid "InviteMembers|Invite team members"
+msgstr ""
+
+msgid "Invited"
+msgstr "Invitert"
+
msgid "Invited users will be added with developer level permissions. You can always change this later."
msgstr ""
@@ -13588,103 +14082,106 @@ msgid "Invocations"
msgstr ""
msgid "Is blocked by"
-msgstr ""
+msgstr "Er blokkert av"
msgid "Is this GitLab trial for your company?"
msgstr ""
msgid "Is using license seat:"
-msgstr ""
+msgstr "Bruker lisenssetet:"
msgid "Is using seat"
msgstr ""
msgid "IssuableStatus|Closed"
-msgstr ""
+msgstr "Lukket"
msgid "IssuableStatus|Closed (%{link})"
-msgstr ""
+msgstr "Lukket (%{link})"
msgid "IssuableStatus|duplicated"
-msgstr ""
+msgstr "duplisert"
msgid "IssuableStatus|moved"
-msgstr ""
+msgstr "flyttet"
msgid "IssuableStatus|promoted"
-msgstr ""
+msgstr "forfremmet"
msgid "Issue"
-msgstr ""
+msgstr "Sak"
msgid "Issue %{issue_reference} has already been added to epic %{epic_reference}."
msgstr ""
msgid "Issue Analytics"
-msgstr ""
+msgstr "Saksanalyse"
msgid "Issue Boards"
-msgstr ""
+msgstr "Problemvegger"
msgid "Issue already promoted to epic."
msgstr ""
msgid "Issue cannot be found."
+msgstr "Saken kunne ikke bli funnet."
+
+msgid "Issue created from vulnerability %{vulnerability_link}"
msgstr ""
msgid "Issue events"
-msgstr ""
+msgstr "Sakshendelser"
-msgid "Issue first depoloyed to production"
+msgid "Issue first deployed to production"
msgstr ""
msgid "Issue label"
-msgstr ""
+msgstr "Saksstempel"
msgid "Issue or Merge Request ID is required"
msgstr ""
msgid "Issue published on status page."
-msgstr ""
+msgstr "Sak publisert på statussiden."
msgid "Issue template (optional)"
-msgstr ""
+msgstr "Saksrapportmal (valgfritt)"
msgid "Issue update failed"
-msgstr ""
+msgstr "Saksoppdatering mislyktes"
msgid "Issue was closed by %{name} %{reason}"
-msgstr ""
+msgstr "Saken ble lukket av %{name} %{reason}"
msgid "Issue weight"
-msgstr ""
+msgstr "Saksvektlegging"
msgid "IssueAnalytics|Age"
-msgstr ""
+msgstr "Alder"
msgid "IssueAnalytics|Assignees"
-msgstr ""
+msgstr "Tilordnede"
msgid "IssueAnalytics|Due date"
-msgstr ""
+msgstr "MÃ¥ldato"
msgid "IssueAnalytics|Failed to load issues. Please try again."
msgstr ""
msgid "IssueAnalytics|Issue"
-msgstr ""
+msgstr "Sak"
msgid "IssueAnalytics|Milestone"
-msgstr ""
+msgstr "Milepæl"
msgid "IssueAnalytics|Opened by"
-msgstr ""
+msgstr "Ã…pnet av"
msgid "IssueAnalytics|Status"
-msgstr ""
+msgstr "Status"
msgid "IssueAnalytics|Weight"
-msgstr ""
+msgstr "Vektlegging"
msgid "IssueBoards|Board"
msgstr ""
@@ -13708,77 +14205,83 @@ msgid "IssueBoards|Switch board"
msgstr ""
msgid "IssueTracker|Bugzilla issue tracker"
-msgstr ""
+msgstr "Bugzilla-sakssporer"
msgid "IssueTracker|Custom issue tracker"
+msgstr "Tilpasset sakssporer"
+
+msgid "IssueTracker|EWM work items tracker"
msgstr ""
msgid "IssueTracker|Redmine issue tracker"
-msgstr ""
+msgstr "Redmine-sakssporer"
msgid "IssueTracker|YouTrack issue tracker"
-msgstr ""
+msgstr "YouTrack-sakssporer"
msgid "Issues"
-msgstr ""
+msgstr "Saker"
msgid "Issues Rate Limits"
msgstr ""
msgid "Issues and Merge Requests"
-msgstr ""
+msgstr "Saker og fletteforespørsler"
msgid "Issues can be bugs, tasks or ideas to be discussed. Also, issues are searchable and filterable."
msgstr ""
msgid "Issues closed"
-msgstr ""
+msgstr "Saker lukket"
msgid "Issues referenced by merge requests and commits within the default branch will be closed automatically"
msgstr ""
msgid "Issues with comments, merge requests with diffs and comments, labels, milestones, snippets, and other project entities"
-msgstr ""
+msgstr "Saker med kommentarer, fletteforespørsler med differ og kommentarer, stempler, milepæler, utdrag og andre prosjektenheter"
msgid "Issues with no epic assigned"
-msgstr ""
+msgstr "Saker uten noen tilordnede eposer"
msgid "Issues, merge requests, pushes, and comments."
-msgstr ""
+msgstr "Saker, fletteforespørsler, pushinger og kommentarer."
msgid "IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them"
msgstr ""
msgid "IssuesAnalytics|Avg/Month:"
-msgstr ""
+msgstr "Gj.snitt/måned:"
msgid "IssuesAnalytics|Issues opened"
-msgstr ""
+msgstr "Saker åpnet"
msgid "IssuesAnalytics|Issues opened per month"
-msgstr ""
+msgstr "Saker åpnet per måned"
msgid "IssuesAnalytics|Last 12 months"
-msgstr ""
+msgstr "Seneste 12 måneder"
msgid "IssuesAnalytics|Sorry, your filter produced no results"
-msgstr ""
+msgstr "Beklager, filteret ditt ga ingen resultater"
msgid "IssuesAnalytics|There are no issues for the projects in your group"
-msgstr ""
+msgstr "Det er ingen saker for prosjektene i gruppen din"
msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above"
msgstr ""
msgid "IssuesAnalytics|Total:"
-msgstr ""
+msgstr "Totalt:"
msgid "Issue|Title"
-msgstr ""
+msgstr "Tittel"
msgid "It looks like you have some draft commits in this branch."
msgstr ""
+msgid "It may be several days before you see feature usage data."
+msgstr ""
+
msgid "It must have a header row and at least two columns: the first column is the issue title and the second column is the issue description. The separator is automatically detected."
msgstr ""
@@ -13786,10 +14289,10 @@ msgid "It seems like the Dependency Scanning job ran successfully, but no depend
msgstr ""
msgid "It seems that there is currently no available data for code coverage"
-msgstr ""
+msgstr "Det ser ut til at det for øyeblikket ikke er tilgjengelige data for kodedekning"
msgid "It's you"
-msgstr ""
+msgstr "Det er deg"
msgid "Iteration"
msgstr ""
@@ -13804,13 +14307,13 @@ msgid "Iteration updated"
msgstr ""
msgid "Iterations"
-msgstr ""
+msgstr "Ringer"
msgid "Iteration|Dates cannot overlap with other existing Iterations"
msgstr ""
msgid "Iteration|cannot be in the past"
-msgstr ""
+msgstr "kan ikke være i fortiden"
msgid "Iteration|cannot be more than 500 years in the future"
msgstr ""
@@ -13822,22 +14325,22 @@ msgid "I’m not very familiar with the basics of project management and DevOps.
msgstr ""
msgid "Jaeger URL"
-msgstr ""
+msgstr "Jaeger-URL"
msgid "Jaeger tracing"
-msgstr ""
+msgstr "Jaeger-sporing"
msgid "Jan"
-msgstr ""
+msgstr "Jan"
msgid "January"
-msgstr ""
+msgstr "januar"
msgid "Jira Issues"
-msgstr ""
+msgstr "Jira-saker"
msgid "Jira display name"
-msgstr ""
+msgstr "Jira-visningsnavn"
msgid "Jira import is already running."
msgstr ""
@@ -13849,13 +14352,13 @@ msgid "Jira project key is not configured"
msgstr ""
msgid "Jira project: %{importProject}"
-msgstr ""
+msgstr "Jira-prosjekt: %{importProject}"
msgid "Jira service not configured."
msgstr ""
msgid "Jira users have been imported from the configured Jira instance. They can be mapped by selecting a GitLab user from the dropdown in the \"GitLab username\" column. When the form appears, the dropdown defaults to the user conducting the import."
-msgstr ""
+msgstr "Jira-brukere har blitt importert fra den konfigurerte Jira-instansen. De kan kartlegges ved å velge en GitLab-bruker fra nedfallsmenyen i kolonnen «GitLab-brukernavn». Når skjemaet vises, vil nedfallsmenyen som standard vise brukeren som utfører importeringen."
msgid "Jira-GitLab user mapping template"
msgstr ""
@@ -13870,10 +14373,10 @@ msgid "JiraService|%{user_link} mentioned this issue in %{entity_link} of %{proj
msgstr ""
msgid "JiraService|Displaying Jira issues while leaving the GitLab issue functionality enabled might be confusing. Consider %{linkStart}disabling GitLab issues%{linkEnd} if they won’t otherwise be used."
-msgstr ""
+msgstr "Å vise Jira-saker mens GitLab-saksfunksjonaliteten er aktivert, kan være forvirrende. Vurder å %{linkStart}deaktivere GitLab-problemer%{linkEnd} hvis de ikke ellers blir brukt."
msgid "JiraService|Enable Jira issues"
-msgstr ""
+msgstr "Skru på Jira-saker"
msgid "JiraService|Events for %{noteable_model_name} are disabled."
msgstr ""
@@ -13882,13 +14385,13 @@ msgid "JiraService|If different from Web URL"
msgstr ""
msgid "JiraService|Issue List"
-msgstr ""
+msgstr "Saksliste"
msgid "JiraService|Jira API URL"
-msgstr ""
+msgstr "Jira API-URL"
msgid "JiraService|Jira Issues"
-msgstr ""
+msgstr "Jira-saker"
msgid "JiraService|Jira comments will be created when an issue gets referenced in a commit."
msgstr ""
@@ -13897,22 +14400,22 @@ msgid "JiraService|Jira comments will be created when an issue gets referenced i
msgstr ""
msgid "JiraService|Jira issue tracker"
-msgstr ""
+msgstr "Jira-sakssporer"
msgid "JiraService|Jira project key"
-msgstr ""
+msgstr "Jira-prosjektnøkkel"
msgid "JiraService|Open Jira"
-msgstr ""
+msgstr "Ã…pne Jira"
msgid "JiraService|Password or API token"
msgstr ""
msgid "JiraService|This feature requires a Premium plan."
-msgstr ""
+msgstr "Denne funksjonen krever en Premium-plan."
msgid "JiraService|Transition ID(s)"
-msgstr ""
+msgstr "Overgangs-ID(-er)"
msgid "JiraService|Use , or ; to separate multiple transition IDs"
msgstr ""
@@ -13924,49 +14427,49 @@ msgid "JiraService|Use a username for server version and an email for cloud vers
msgstr ""
msgid "JiraService|Username or Email"
-msgstr ""
+msgstr "Brukernavn eller E-post"
msgid "JiraService|Using Jira for issue tracking?"
msgstr ""
msgid "JiraService|View Jira issues in GitLab"
-msgstr ""
+msgstr "Vis Jira-saker i GitLab"
msgid "JiraService|Warning: All GitLab users that have access to this GitLab project will be able to view all issues from the Jira project specified below."
msgstr ""
msgid "JiraService|Web URL"
-msgstr ""
+msgstr "Nett-URL"
msgid "JiraService|Work on Jira issues without leaving GitLab. Adds a Jira menu to access your list of Jira issues and view any issue as read-only."
msgstr ""
msgid "JiraService|e.g. AB"
-msgstr ""
+msgstr "f.eks. AB"
msgid "JiraService|transition ids can have only numbers which can be split with , or ;"
msgstr ""
msgid "Job"
-msgstr ""
+msgstr "Jobb"
msgid "Job Failed #%{build_id}"
-msgstr ""
+msgstr "Jobben mislyktes #%{build_id}"
msgid "Job ID"
-msgstr ""
+msgstr "Jobb-ID"
msgid "Job artifact"
-msgstr ""
+msgstr "Jobb-artifakt"
msgid "Job artifacts"
-msgstr ""
+msgstr "Jobb-artefakter"
msgid "Job has been erased"
-msgstr ""
+msgstr "Jobben har blitt slettet"
msgid "Job has been successfully erased!"
-msgstr ""
+msgstr "Jobben har blitt vellykket slettet!"
msgid "Job has wrong arguments format."
msgstr ""
@@ -13978,7 +14481,7 @@ msgid "Job is stuck. Check runners."
msgstr ""
msgid "Job logs and artifacts"
-msgstr ""
+msgstr "Jobb-loggføringer og -artefakter"
msgid "Job to create self-monitoring project is in progress"
msgstr ""
@@ -13987,58 +14490,58 @@ msgid "Job to delete self-monitoring project is in progress"
msgstr ""
msgid "Job was retried"
-msgstr ""
+msgstr "Jobben ble forsøkt på nytt"
msgid "Jobs"
-msgstr ""
+msgstr "Jobber"
msgid "Job|Browse"
-msgstr ""
+msgstr "Bla"
msgid "Job|Complete Raw"
msgstr ""
msgid "Job|Download"
-msgstr ""
+msgstr "Last ned"
msgid "Job|Erase job log"
-msgstr ""
+msgstr "Slett jobblogg"
msgid "Job|Job artifacts"
-msgstr ""
+msgstr "Jobb-artefakter"
msgid "Job|Job has been erased"
-msgstr ""
+msgstr "Jobben har blitt slettet"
msgid "Job|Job has been erased by"
-msgstr ""
+msgstr "Jobben har blitt slettet av"
msgid "Job|Keep"
-msgstr ""
+msgstr "Behold"
msgid "Job|Pipeline"
-msgstr ""
+msgstr "Rørledning"
msgid "Job|Scroll to bottom"
-msgstr ""
+msgstr "Bla til bunn"
msgid "Job|Scroll to top"
-msgstr ""
+msgstr "Bla til toppen"
msgid "Job|Show complete raw"
msgstr ""
msgid "Job|The artifacts were removed"
-msgstr ""
+msgstr "Artefaktene ble fjernet"
msgid "Job|The artifacts will be removed"
-msgstr ""
+msgstr "Artefaktene vil bli fjernet"
msgid "Job|These artifacts are the latest. They will not be deleted (even if expired) until newer artifacts are available."
msgstr ""
msgid "Job|This job failed because the necessary resources were not successfully created."
-msgstr ""
+msgstr "Denne jobben mislyktes fordi de nødvendige ressursene ikke ble vellykket opprettet."
msgid "Job|This job is stuck because the project doesn't have any runners online assigned to it."
msgstr ""
@@ -14050,37 +14553,37 @@ msgid "Job|This job is stuck because you don't have any active runners that can
msgstr ""
msgid "Job|for"
-msgstr ""
+msgstr "for"
msgid "Job|into"
-msgstr ""
+msgstr "inni"
msgid "Job|with"
-msgstr ""
+msgstr "med"
msgid "Join Zoom meeting"
+msgstr "Bli med på Zoom-møte"
+
+msgid "Joined %{time_ago}"
msgstr ""
msgid "Jul"
-msgstr ""
+msgstr "Jul"
msgid "July"
-msgstr ""
-
-msgid "Jump to first unresolved thread"
-msgstr ""
+msgstr "juli"
msgid "Jump to next unresolved thread"
msgstr ""
msgid "Jun"
-msgstr ""
+msgstr "Jun"
msgid "June"
-msgstr ""
+msgstr "juni"
msgid "Just me"
-msgstr ""
+msgstr "Bare meg selv"
msgid "K8s pod health"
msgstr ""
@@ -14089,40 +14592,43 @@ msgid "Keep divergent refs"
msgstr ""
msgid "Kerberos access denied"
-msgstr ""
+msgstr "Kerberos-tilgang ble nektet"
msgid "Key"
-msgstr ""
+msgstr "Nøkkel"
msgid "Key (PEM)"
-msgstr ""
+msgstr "Nøkkel (PEM)"
msgid "Key: %{key}"
-msgstr ""
+msgstr "Nøkkel: %{key}"
msgid "Keyboard shortcuts"
+msgstr "Tastatursnarveier"
+
+msgid "KeyboardKey|Ctrl+"
msgstr ""
msgid "Keys"
-msgstr ""
+msgstr "Nøkler"
msgid "Ki"
-msgstr ""
+msgstr "Ki"
msgid "Kubernetes"
-msgstr ""
+msgstr "Kubernetes"
msgid "Kubernetes API returned status code: %{error_code}"
msgstr ""
msgid "Kubernetes Cluster"
-msgstr ""
+msgstr "Kubernetes-klynge"
msgid "Kubernetes Clusters"
-msgstr ""
+msgstr "Kubernetes-klynger"
msgid "Kubernetes cluster"
-msgstr ""
+msgstr "Kubernetes-klynge"
msgid "Kubernetes cluster creation time exceeds timeout; %{timeout}"
msgstr ""
@@ -14131,55 +14637,61 @@ msgid "Kubernetes cluster integration and resources are being removed."
msgstr ""
msgid "Kubernetes cluster integration was successfully removed."
-msgstr ""
+msgstr "Kubernetes-klyngeintegrering ble vellykket fjernet."
msgid "Kubernetes cluster was successfully updated."
-msgstr ""
+msgstr "Kubernetes-klynge ble vellykket oppdatert."
msgid "Kubernetes deployment not found"
msgstr ""
msgid "Kubernetes error: %{error_code}"
-msgstr ""
+msgstr "Kubernetes-feil: %{error_code}"
msgid "Kubernetes popover"
msgstr ""
msgid "LDAP"
-msgstr ""
+msgstr "LDAP"
msgid "LDAP Synchronization"
+msgstr "LDAP-synkronisering"
+
+msgid "LDAP group settings"
msgstr ""
msgid "LDAP settings"
-msgstr ""
+msgstr "LDAP-innstillinger"
msgid "LDAP settings updated"
-msgstr ""
+msgstr "LDAP-innstillinger oppdatert"
msgid "LDAP sync in progress. This could take a few minutes. Refresh the page to see the changes."
msgstr ""
-msgid "LFS"
+msgid "LDAP synchronizations"
msgstr ""
+msgid "LFS"
+msgstr "LFS"
+
msgid "LFS object"
-msgstr ""
+msgstr "LFS-objekt"
msgid "LFS objects"
-msgstr ""
+msgstr "LFS-objekter"
msgid "LFSStatus|Disabled"
-msgstr ""
+msgstr "Deaktivert"
msgid "LFSStatus|Enabled"
-msgstr ""
+msgstr "Aktivert"
msgid "LICENSE"
-msgstr ""
+msgstr "LISENS"
msgid "Label"
-msgstr ""
+msgstr "Etikett"
msgid "Label actions dropdown"
msgstr ""
@@ -14188,25 +14700,25 @@ msgid "Label lists show all issues with the selected label."
msgstr ""
msgid "Label was created"
-msgstr ""
+msgstr "Stempel ble opprettet"
msgid "Label was removed"
-msgstr ""
+msgstr "Stempel ble fjernet"
msgid "Label was successfully updated."
-msgstr ""
+msgstr "Stempel ble vellykket oppdatert."
msgid "LabelSelect|%{firstLabelName} +%{remainingLabelCount} more"
-msgstr ""
+msgstr "%{firstLabelName} + %{remainingLabelCount} til"
msgid "LabelSelect|%{labelsString}, and %{remainingLabelCount} more"
-msgstr ""
+msgstr "%{labelsString}, og %{remainingLabelCount} til"
msgid "LabelSelect|Labels"
-msgstr ""
+msgstr "Stempler"
msgid "Labels"
-msgstr ""
+msgstr "Stempler"
msgid "Labels can be applied to %{features}. Group labels are available for any project within the group."
msgstr ""
@@ -14224,23 +14736,32 @@ msgid "Labels|Promote Label"
msgstr ""
msgid "Labels|Promoting %{labelTitle} will make it available for all projects inside %{groupName}. Existing project labels with the same title will be merged. If a group label with the same title exists, it will also be merged. This action cannot be reversed."
-msgstr ""
+msgstr "Å forfremme %{labelTitle} vil gjøre den tilgjengelig for alle prosjekter innenfor %{groupName}. Eksisterende prosjektstempler med samme tittel vil bli slått sammen. Hvis det finnes et gruppestempel med samme tittel, blir den også slått sammen. Denne handlingen kan ikke reverseres."
msgid "Labels|and %{count} more"
-msgstr ""
+msgstr "and %{count} til"
msgid "Language"
-msgstr ""
+msgstr "Språk"
msgid "Large File Storage"
-msgstr ""
+msgstr "Stor fillagring"
msgid "Last %d day"
msgid_plural "Last %d days"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "Siste %d dag"
+msgstr[1] "Siste %d dager"
+
+msgid "Last 2 weeks"
+msgstr ""
+
+msgid "Last 30 days"
+msgstr ""
+
+msgid "Last 60 days"
+msgstr ""
-msgid "Last %{days} days"
+msgid "Last 90 days"
msgstr ""
msgid "Last Accessed On"
@@ -14250,40 +14771,40 @@ msgid "Last Name is too long (maximum is %{max_length} characters)."
msgstr ""
msgid "Last Pipeline"
-msgstr ""
+msgstr "Nyeste rørledning"
msgid "Last Seen"
-msgstr ""
+msgstr "Sist sett"
msgid "Last Used"
-msgstr ""
+msgstr "Sist brukt"
msgid "Last accessed on"
msgstr ""
msgid "Last activity"
-msgstr ""
+msgstr "Nyeste aktivitet"
msgid "Last commit"
-msgstr ""
+msgstr "Seneste commit"
msgid "Last contact"
-msgstr ""
+msgstr "Siste kontakt"
msgid "Last edited %{date}"
-msgstr ""
+msgstr "Sist endret %{date}"
msgid "Last edited by %{name}"
-msgstr ""
+msgstr "Sist endret av %{name}"
msgid "Last item before this page loaded in your browser:"
msgstr ""
msgid "Last name"
-msgstr ""
+msgstr "Etternavn"
msgid "Last reply by"
-msgstr ""
+msgstr "Siste svar fra"
msgid "Last repository check (%{last_check_timestamp}) failed. See the 'repocheck.log' file for error messages."
msgstr ""
@@ -14292,55 +14813,61 @@ msgid "Last repository check run"
msgstr ""
msgid "Last seen"
-msgstr ""
+msgstr "Sist sett"
msgid "Last successful sync"
msgstr ""
msgid "Last successful update"
-msgstr ""
+msgstr "Forrige vellykkede oppdatering"
msgid "Last time verified"
-msgstr ""
+msgstr "Senest verifisert"
msgid "Last update"
-msgstr ""
+msgstr "Sist oppdatering"
msgid "Last update attempt"
-msgstr ""
+msgstr "Forrige oppdateringsforsøk"
msgid "Last updated"
-msgstr ""
+msgstr "Sist oppdatert"
msgid "Last used"
-msgstr ""
+msgstr "Sist brukt"
msgid "Last used on:"
+msgstr "Senest brukt:"
+
+msgid "Last week"
msgstr ""
msgid "LastCommit|authored"
-msgstr ""
+msgstr "forfattet"
msgid "LastPushEvent|You pushed to"
msgstr ""
msgid "LastPushEvent|at"
-msgstr ""
+msgstr "den"
msgid "Latest changes"
-msgstr ""
+msgstr "Siste endringer"
msgid "Latest pipeline for the most recent commit on this branch"
msgstr ""
-msgid "Lead"
+msgid "Launch a ready-to-code development environment for your project."
msgstr ""
+msgid "Lead"
+msgstr "Tips"
+
msgid "Lead Time"
-msgstr ""
+msgstr "Ledetid"
msgid "Learn GitLab"
-msgstr ""
+msgstr "Lær GitLab"
msgid "Learn how to %{link_start}contribute to the built-in templates%{link_end}"
msgstr ""
@@ -14349,16 +14876,16 @@ msgid "Learn how to %{no_packages_link_start}publish and share your packages%{no
msgstr ""
msgid "Learn how to enable synchronization"
-msgstr ""
+msgstr "Lær hvordan man aktiverer synkronisering"
msgid "Learn more"
-msgstr ""
+msgstr "Lær mer"
msgid "Learn more about Auto DevOps"
-msgstr ""
+msgstr "Lær mer om Auto DevOps"
msgid "Learn more about Kubernetes"
-msgstr ""
+msgstr "Lær mer om Kubernetes"
msgid "Learn more about License-Check"
msgstr ""
@@ -14367,25 +14894,25 @@ msgid "Learn more about Vulnerability-Check"
msgstr ""
msgid "Learn more about Web Terminal"
-msgstr ""
+msgstr "Lær mer om Netterminal"
msgid "Learn more about X.509 signed commits"
-msgstr ""
+msgstr "Lær mer om X.509-signerte commiter"
msgid "Learn more about adding certificates to your project by following the %{docs_link_start}documentation on GitLab Pages%{docs_link_end}."
msgstr ""
msgid "Learn more about approvals."
-msgstr ""
+msgstr "Lær mer om godkjenninger."
msgid "Learn more about custom project templates"
msgstr ""
msgid "Learn more about deploying to AWS"
-msgstr ""
+msgstr "Lær mer om utstasjonering til AWS"
msgid "Learn more about deploying to a cluster"
-msgstr ""
+msgstr "Lær mer om utstasjonering til en klynge"
msgid "Learn more about group-level project templates"
msgstr ""
@@ -14394,22 +14921,22 @@ msgid "Learn more about job dependencies"
msgstr ""
msgid "Learn more about signing commits"
-msgstr ""
+msgstr "Lær mer om å signere commiter"
msgid "Learn more about the dependency list"
-msgstr ""
+msgstr "Lær mer om avhengighetslisten"
msgid "Learn more in the"
-msgstr ""
+msgstr "Lær mer i"
msgid "Learn more in the|pipeline schedules documentation"
msgstr ""
msgid "Leave"
-msgstr ""
+msgstr "Forlat"
msgid "Leave Admin Mode"
-msgstr ""
+msgstr "Forlat adminmodus"
msgid "Leave blank for no limit. Once set, existing personal access tokens may be revoked."
msgstr ""
@@ -14418,40 +14945,40 @@ msgid "Leave edit mode? All unsaved changes will be lost."
msgstr ""
msgid "Leave group"
-msgstr ""
+msgstr "Forlat gruppen"
msgid "Leave project"
-msgstr ""
+msgstr "Forlat prosjektet"
msgid "Leave the \"File type\" and \"Delivery method\" options on their default values."
msgstr ""
msgid "Leave zen mode"
-msgstr ""
+msgstr "Forlat zenmodus"
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 er en gratis, automatisert og åpen sertifikatmyndighet (CA) som gir digitale sertifikater for å kunne aktivere HTTPS (SSL/TLS) på nettsteder. Lær mer om Let's Encrypt-oppsett ved å følge %{docs_link_start}dokumentasjonen på GitLab Pages%{docs_link_end}."
msgid "License"
-msgstr ""
+msgstr "Lisens"
msgid "License Compliance"
msgstr ""
msgid "License History"
-msgstr ""
+msgstr "Lisenshistorikk"
msgid "License ID:"
-msgstr ""
+msgstr "Lisens-ID:"
msgid "License overview"
-msgstr ""
+msgstr "Lisensoversikt"
msgid "License-Check"
-msgstr ""
+msgstr "Lisenssjekk"
msgid "LicenseCompliance|%{docLinkStart}License Approvals%{docLinkEnd} are active"
msgstr ""
@@ -14463,22 +14990,22 @@ msgid "LicenseCompliance|Acceptable license to be used in the project"
msgstr ""
msgid "LicenseCompliance|Add a license"
-msgstr ""
+msgstr "Legg til en lisens"
msgid "LicenseCompliance|Add license and related policy"
msgstr ""
msgid "LicenseCompliance|Allow"
-msgstr ""
+msgstr "Tillat"
msgid "LicenseCompliance|Allowed"
-msgstr ""
+msgstr "Tillatt"
msgid "LicenseCompliance|Denied"
-msgstr ""
+msgstr "Avvist"
msgid "LicenseCompliance|Deny"
-msgstr ""
+msgstr "Avvis"
msgid "LicenseCompliance|Disallow merge request if detected and will instruct developer to remove"
msgstr ""
@@ -14487,10 +15014,10 @@ msgid "LicenseCompliance|Learn more about %{linkStart}License Approvals%{linkEnd
msgstr ""
msgid "LicenseCompliance|License"
-msgstr ""
+msgstr "Lisens"
msgid "LicenseCompliance|License Approvals"
-msgstr ""
+msgstr "Lisensgodkjennelser"
msgid "LicenseCompliance|License Compliance detected %d license and policy violation for the source branch only"
msgid_plural "LicenseCompliance|License Compliance detected %d licenses and policy violations for the source branch only"
@@ -14529,73 +15056,73 @@ msgid "LicenseCompliance|License Compliance detected no new licenses"
msgstr ""
msgid "LicenseCompliance|License details"
-msgstr ""
+msgstr "Lisensdetaljer"
msgid "LicenseCompliance|License name"
-msgstr ""
+msgstr "Lisensnavn"
msgid "LicenseCompliance|License review"
-msgstr ""
+msgstr "Lisensgjennomgang"
msgid "LicenseCompliance|Packages"
-msgstr ""
+msgstr "Pakker"
msgid "LicenseCompliance|Remove license"
-msgstr ""
+msgstr "Fjern lisens"
msgid "LicenseCompliance|Remove license?"
-msgstr ""
+msgstr "Fjern lisens?"
msgid "LicenseCompliance|There are currently no policies in this project."
-msgstr ""
+msgstr "Det er for øyeblikket ingen retningslinjer i dette prosjektet."
msgid "LicenseCompliance|There are currently no policies that match in this project."
-msgstr ""
+msgstr "Det er for øyeblikket ingen retningslinjer som samsvarer i dette prosjektet."
msgid "LicenseCompliance|This license already exists in this project."
-msgstr ""
+msgstr "Denne lisensen finnes allerede i dette prosjektet."
msgid "LicenseCompliance|URL"
-msgstr ""
+msgstr "URL"
msgid "LicenseCompliance|You are about to remove the license, %{name}, from this project."
-msgstr ""
+msgstr "Du er i ferd med å fjerne lisensen, %{name}, fra dette prosjektet."
msgid "LicenseManagement|Allowed"
-msgstr ""
+msgstr "Tillatt"
msgid "LicenseManagement|Denied"
-msgstr ""
+msgstr "Avvist"
msgid "LicenseManagement|Uncategorized"
-msgstr ""
+msgstr "Ukategorisert"
msgid "Licensed Features"
-msgstr ""
+msgstr "Lisensierte funksjoner"
msgid "Licensed to"
-msgstr ""
+msgstr "Lisensiert til"
msgid "Licensed to:"
-msgstr ""
+msgstr "Lisensiert til:"
msgid "Licenses"
-msgstr ""
+msgstr "Lisenser"
msgid "Licenses|%{remainingComponentsCount} more"
-msgstr ""
+msgstr "%{remainingComponentsCount} til"
msgid "Licenses|Acceptable license to be used in the project"
msgstr ""
msgid "Licenses|Component"
-msgstr ""
+msgstr "Komponent"
msgid "Licenses|Components"
-msgstr ""
+msgstr "Komponenter"
msgid "Licenses|Detected in Project"
-msgstr ""
+msgstr "Oppdaget i prosjektet"
msgid "Licenses|Detected licenses that are out-of-compliance with the project's assigned policies"
msgstr ""
@@ -14616,13 +15143,13 @@ msgid "Licenses|License Compliance"
msgstr ""
msgid "Licenses|Name"
-msgstr ""
+msgstr "Navn"
msgid "Licenses|Policies"
-msgstr ""
+msgstr "Retningslinjer"
msgid "Licenses|Policy"
-msgstr ""
+msgstr "Retningslinje"
msgid "Licenses|Policy violation: denied"
msgstr ""
@@ -14637,10 +15164,10 @@ msgid "Licenses|View license details for your project"
msgstr ""
msgid "License|Buy license"
-msgstr ""
+msgstr "Kjøp lisens"
msgid "License|License"
-msgstr ""
+msgstr "Lisens"
msgid "License|You can restore access to the Gold features at any time by upgrading."
msgstr ""
@@ -14649,10 +15176,10 @@ msgid "License|You can start a free trial of GitLab Ultimate without any obligat
msgstr ""
msgid "License|You do not have a license."
-msgstr ""
+msgstr "Du har ikke en lisens."
msgid "License|Your License"
-msgstr ""
+msgstr "Din lisens"
msgid "License|Your free trial of GitLab Ultimate expired on %{trial_ends_on}."
msgstr ""
@@ -14669,76 +15196,76 @@ msgstr[0] ""
msgstr[1] ""
msgid "Line changes"
-msgstr ""
+msgstr "Linjeendringer"
msgid "Link Prometheus monitoring to GitLab."
msgstr ""
msgid "Link copied"
-msgstr ""
+msgstr "Lenken er kopiert"
msgid "Link title"
-msgstr ""
+msgstr "Lenketittel"
msgid "Link title is required"
-msgstr ""
+msgstr "Lenketittel er påkrevd"
msgid "Link to go to GitLab pipeline documentation"
msgstr ""
msgid "Linked emails (%{email_count})"
-msgstr ""
+msgstr "Lenkede e-postadresser (%{email_count})"
msgid "Linked issues"
-msgstr ""
+msgstr "Lenkede saker"
msgid "LinkedIn"
-msgstr ""
+msgstr "Linkedin"
msgid "LinkedPipelines|%{counterLabel} more downstream pipelines"
msgstr ""
msgid "Links"
-msgstr ""
+msgstr "Lenker"
msgid "List"
-msgstr ""
+msgstr "Liste"
msgid "List Your Gitea Repositories"
-msgstr ""
+msgstr "List opp dine Gitea-kodelagre"
msgid "List available repositories"
-msgstr ""
+msgstr "List opp tilgjengelige kodelagre"
msgid "List of all merge commits"
+msgstr "Liste over alle innflettings-commits"
+
+msgid "List options"
msgstr ""
msgid "List settings"
-msgstr ""
+msgstr "Liste innstillinger"
msgid "List the merge requests that must be merged before this one."
msgstr ""
msgid "List view"
-msgstr ""
+msgstr "Listevisning"
msgid "List your Bitbucket Server repositories"
msgstr ""
-msgid "Lists"
-msgstr ""
-
msgid "Live preview"
-msgstr ""
+msgstr "Live forhåndsvisning"
msgid "Load more"
-msgstr ""
+msgstr "Last inn flere"
msgid "Load more users"
-msgstr ""
+msgstr "Last inn flere brukere"
msgid "Loading"
-msgstr ""
+msgstr "Laster"
msgid "Loading contribution stats for group members"
msgstr ""
@@ -14750,79 +15277,79 @@ msgid "Loading functions timed out. Please reload the page to try again."
msgstr ""
msgid "Loading issues"
-msgstr ""
+msgstr "Laster inn saker"
msgid "Loading snippet"
-msgstr ""
+msgstr "Laster inn utdrag"
msgid "Loading the GitLab IDE..."
-msgstr ""
+msgstr "Laster inn GitLab IDE …"
msgid "Loading..."
-msgstr ""
+msgstr "Laster..."
msgid "Loading…"
-msgstr ""
+msgstr "Laster …"
msgid "Local IP addresses and domain names that hooks and services may access."
msgstr ""
msgid "Localization"
-msgstr ""
+msgstr "Lokalisering"
msgid "Location"
-msgstr ""
+msgstr "Adresse"
msgid "Lock"
-msgstr ""
+msgstr "LÃ¥s"
msgid "Lock %{issuableDisplayName}"
-msgstr ""
+msgstr "LÃ¥s %{issuableDisplayName}"
msgid "Lock memberships to LDAP synchronization"
msgstr ""
msgid "Lock not found"
-msgstr ""
+msgstr "LÃ¥s ikke funnet"
msgid "Lock the discussion"
-msgstr ""
+msgstr "LÃ¥s diskusjonen"
msgid "Lock this %{issuableDisplayName}? Only %{strongStart}project members%{strongEnd} will be able to comment."
msgstr ""
msgid "Lock to current projects"
-msgstr ""
+msgstr "Lås til nåværende prosjekter"
msgid "Locked"
-msgstr ""
+msgstr "LÃ¥st"
msgid "Locked Files"
-msgstr ""
+msgstr "LÃ¥ste filer"
msgid "Locked by %{fileLockUserName}"
-msgstr ""
+msgstr "LÃ¥st av %{fileLockUserName}"
msgid "Locked the discussion."
-msgstr ""
+msgstr "LÃ¥ste diskusjonen."
msgid "Locked to current projects"
-msgstr ""
+msgstr "Låst til nåværende prosjekter"
msgid "Locks give the ability to lock specific file or folder."
msgstr ""
msgid "Locks the discussion."
-msgstr ""
+msgstr "LÃ¥ser diskusjonen."
msgid "Login with smartcard"
-msgstr ""
+msgstr "Logg på med et smartkort"
msgid "Logo was successfully removed."
-msgstr ""
+msgstr "Logoen ble vellykket fjernet."
msgid "Logs"
-msgstr ""
+msgstr "Logger"
msgid "Logs|To see the logs, deploy your code to an environment."
msgstr ""
@@ -14831,58 +15358,58 @@ msgid "Low vulnerabilities present"
msgstr ""
msgid "MB"
-msgstr ""
+msgstr "MB"
msgid "MD5"
-msgstr ""
+msgstr "MD5"
msgid "MERGED"
-msgstr ""
+msgstr "INNFLETTET"
msgid "MR widget|Back to the Merge request"
msgstr ""
msgid "MR widget|See your pipeline in action"
-msgstr ""
+msgstr "Se rørledningen din i aksjon"
msgid "MR widget|Take a look at our %{beginnerLinkStart}Beginner's Guide to Continuous Integration%{beginnerLinkEnd} and our %{exampleLinkStart}examples of GitLab CI/CD%{exampleLinkEnd} to learn more."
-msgstr ""
+msgstr "Ta en titt på vår %{beginnerLinkStart}begynnerguide til kontinuerlig integrasjon%{beginnerLinkEnd} og våre %{exampleLinkStart}eksempler på GitLab CI/CD%{exampleLinkEnd} for å lære mer."
msgid "MR widget|The pipeline will test your code on every commit. A %{codeQualityLinkStart}code quality report%{codeQualityLinkEnd} will appear in your merge requests to warn you about potential code degradations."
-msgstr ""
+msgstr "Rørledningen vil teste koden din ved hver commit. En %{codeQualityLinkStart}kodekvalitetsrapport%{codeQualityLinkEnd} vil dukke opp i dine fletteforespørsler for å advare deg om mulige kode-degraderinger."
msgid "MRApprovals|Approvals"
-msgstr ""
+msgstr "Godkjennelser"
msgid "MRApprovals|Approved by"
-msgstr ""
+msgstr "Godkjent av"
msgid "MRApprovals|Approvers"
-msgstr ""
+msgstr "Godkjennere"
msgid "MRApprovals|Commented by"
-msgstr ""
+msgstr "Kommentert av"
msgid "MRDiff|Show changes only"
-msgstr ""
+msgstr "Vis kun endringer"
msgid "MRDiff|Show full file"
-msgstr ""
+msgstr "Vis hele filen"
msgid "Made this issue confidential."
-msgstr ""
+msgstr "Gjorde denne saken konfidensiell."
msgid "Maintenance mode"
-msgstr ""
+msgstr "Vedlikeholdsmodus"
msgid "Make and review changes in the browser with the Web IDE"
msgstr ""
msgid "Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
-msgstr ""
+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 ""
+msgstr "Gjør saken konfidensiell"
msgid "Make sure you save it - you won't be able to access it again."
msgstr ""
@@ -14891,61 +15418,61 @@ msgid "Make sure you're logged into the account that owns the projects you'd lik
msgstr ""
msgid "Make this epic confidential"
-msgstr ""
+msgstr "Gjør denne epos konfidensiell"
msgid "Makes this issue confidential."
-msgstr ""
+msgstr "Gjør denne saken konfidensiell."
msgid "Manage"
-msgstr ""
+msgstr "Administrer"
msgid "Manage Web IDE features"
-msgstr ""
+msgstr "Administrere Web IDE-funksjoner"
msgid "Manage access"
-msgstr ""
+msgstr "Administrer tilgang"
msgid "Manage all notifications"
-msgstr ""
+msgstr "Administrer alle varsler"
msgid "Manage applications that can use GitLab as an OAuth provider, and applications that you've authorized to use your account."
-msgstr ""
+msgstr "Administrer programmer som kan bruke GitLab som OAuth-leverandør, og programmer som du har autorisert til å bruke kontoen din."
msgid "Manage applications that you've authorized to use your account."
-msgstr ""
+msgstr "Administrer programmer som du har autorisert til å bruke kontoen din."
msgid "Manage group labels"
-msgstr ""
+msgstr "Administrer gruppe-etiketter"
msgid "Manage labels"
-msgstr ""
+msgstr "Administrer etiketter"
msgid "Manage milestones"
-msgstr ""
+msgstr "Behandle milepæler"
msgid "Manage project labels"
-msgstr ""
+msgstr "Administrer prosjekt-etiketter"
msgid "Manage storage usage"
-msgstr ""
+msgstr "Behandle lagringsbruk"
msgid "Manage two-factor authentication"
-msgstr ""
+msgstr "Behandle 2-trinnsautentisering"
msgid "Manage your license"
-msgstr ""
+msgstr "Behandle lisensen din"
msgid "Managed Account"
msgstr ""
msgid "Manifest"
-msgstr ""
+msgstr "Manifest"
msgid "Manifest file import"
-msgstr ""
+msgstr "Manifest-filimport"
msgid "Manifest import"
-msgstr ""
+msgstr "Manifest-importering"
msgid "ManualOrdering|Couldn't save the order of the issues"
msgstr ""
@@ -14954,45 +15481,69 @@ msgid "Map a FogBugz account ID to a GitLab user"
msgstr ""
msgid "Map a Google Code user to a GitLab user"
-msgstr ""
+msgstr "Kartlegg en Google Code-bruker til en GitLab-bruker"
msgid "Map a Google Code user to a full email address"
-msgstr ""
+msgstr "Kartlegg en Google Code-bruker til en full e-postadresse"
msgid "Map a Google Code user to a full name"
-msgstr ""
+msgstr "Kartlegg en Google Code-bruker til et fullt navn"
msgid "Mar"
-msgstr ""
+msgstr "Mar"
msgid "March"
-msgstr ""
+msgstr "mars"
msgid "Mark To Do as done"
msgstr ""
msgid "Mark as done"
+msgstr "Marker som ferdig"
+
+msgid "Mark as draft"
msgstr ""
-msgid "Mark as resolved"
+msgid "Mark as ready"
msgstr ""
+msgid "Mark as resolved"
+msgstr "Merk som oppklart"
+
msgid "Mark this issue as a duplicate of another issue"
-msgstr ""
+msgstr "Merk denne saken som et duplikat av en annet sak"
msgid "Mark this issue as related to another issue"
-msgstr ""
+msgstr "Merk denne saken som relatert til en annen sak"
msgid "Markdown"
-msgstr ""
+msgstr "Markdown"
msgid "Markdown Help"
-msgstr ""
+msgstr "Markdown-hjelp"
msgid "Markdown enabled"
-msgstr ""
+msgstr "Markdown er skrudd på"
msgid "Markdown is supported"
+msgstr "Markdown er støttet"
+
+msgid "MarkdownEditor|Add a link (%{modifierKey}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add a link (%{modifier_key}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifierKey}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifier_key}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifierKey}I)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifier_key}I)"
msgstr ""
msgid "Marked For Deletion At - %{deletion_time}"
@@ -15053,7 +15604,7 @@ msgid "MattermostService|See list of available commands in Mattermost after sett
msgstr ""
msgid "MattermostService|Suggestions:"
-msgstr ""
+msgstr "Forslag:"
msgid "MattermostService|This service allows users to perform common operations on this project by entering slash commands in Mattermost."
msgstr ""
@@ -15077,19 +15628,37 @@ msgid "Max Project Import requests per minute per user"
msgstr ""
msgid "Max access level"
+msgstr "Maks tilgangsnivå"
+
+msgid "Max role"
msgstr ""
-msgid "Max seats used"
+msgid "Max size 15 MB"
msgstr ""
-msgid "Maximum Users:"
+msgid "Maximum Conan package file size in bytes"
msgstr ""
+msgid "Maximum Maven package file size in bytes"
+msgstr ""
+
+msgid "Maximum NPM package file size in bytes"
+msgstr ""
+
+msgid "Maximum NuGet package file size in bytes"
+msgstr ""
+
+msgid "Maximum PyPI package file size in bytes"
+msgstr ""
+
+msgid "Maximum Users:"
+msgstr "Maks brukere:"
+
msgid "Maximum allowable lifetime for personal access token (days)"
msgstr ""
msgid "Maximum artifacts size (MB)"
-msgstr ""
+msgstr "Maks artefaktstørrelse (MB)"
msgid "Maximum attachment size (MB)"
msgstr ""
@@ -15098,28 +15667,28 @@ msgid "Maximum bulk request size (MiB)"
msgstr ""
msgid "Maximum capacity"
-msgstr ""
+msgstr "Maks kapasitet"
msgid "Maximum concurrency of Elasticsearch bulk requests per indexing operation."
msgstr ""
msgid "Maximum delay (Minutes)"
-msgstr ""
+msgstr "Maksforsinkelse (i minutter)"
msgid "Maximum duration of a session."
-msgstr ""
+msgstr "En økts maksvarighet."
msgid "Maximum field length"
-msgstr ""
+msgstr "Maksimal feltlengde"
msgid "Maximum file size indexed (KiB)"
msgstr ""
msgid "Maximum file size is 2MB. Please select a smaller file."
-msgstr ""
+msgstr "Maks filstørrelse er 2MB. Vennligst velg en mindre fil."
msgid "Maximum import size (MB)"
-msgstr ""
+msgstr "Maks importstørrelse (MB)"
msgid "Maximum job timeout"
msgstr ""
@@ -15128,40 +15697,40 @@ msgid "Maximum job timeout has a value which could not be accepted"
msgstr ""
msgid "Maximum length 100 characters"
-msgstr ""
+msgstr "Makslengde på 100 tegn"
msgid "Maximum lifetime allowable for Personal Access Tokens is active, your expire date must be set before %{maximum_allowable_date}."
msgstr ""
msgid "Maximum number of %{name} (%{count}) exceeded"
-msgstr ""
+msgstr "Maks antall %{name} (%{count}) har blitt overskredet"
msgid "Maximum number of comments exceeded"
-msgstr ""
+msgstr "Maks antall kommentarer har blitt overskredet"
msgid "Maximum number of mirrors that can be synchronizing at the same time."
msgstr ""
msgid "Maximum number of projects."
-msgstr ""
+msgstr "Maks antall prosjekter."
msgid "Maximum page reached"
-msgstr ""
+msgstr "Maks-siden har blitt nådd"
msgid "Maximum push size (MB)"
-msgstr ""
+msgstr "Maksimal pushstørrelse (MB)"
msgid "Maximum size limit for a single commit."
-msgstr ""
+msgstr "Maksstørrelsesgrense for én enkelt commit."
msgid "Maximum size limit for each repository."
-msgstr ""
+msgstr "Maks filstørrelse for hvert kodelager."
msgid "Maximum size of Elasticsearch bulk indexing requests."
msgstr ""
msgid "Maximum size of import files."
-msgstr ""
+msgstr "Maksstørrelse på importfiler."
msgid "Maximum size of individual attachments in comments."
msgstr ""
@@ -15170,25 +15739,25 @@ msgid "Maximum time between updates that a mirror can have when scheduled to syn
msgstr ""
msgid "May"
-msgstr ""
+msgstr "Mai"
msgid "Measured in bytes of code. Excludes generated and vendored code."
msgstr ""
msgid "Median"
-msgstr ""
+msgstr "Median"
msgid "Medium vulnerabilities present"
msgstr ""
msgid "Member lock"
-msgstr ""
+msgstr "Medlemslås"
msgid "Member since %{date}"
-msgstr ""
+msgstr "Medlem siden %{date}"
msgid "Members"
-msgstr ""
+msgstr "Medlemmer"
msgid "Members can be added by project %{i_open}Maintainers%{i_close} or %{i_open}Owners%{i_close}"
msgstr ""
@@ -15211,20 +15780,32 @@ msgstr ""
msgid "Members with access to %{strong_start}%{group_name}%{strong_end}"
msgstr ""
-msgid "Memory Usage"
+msgid "Members|%{time} by %{user}"
msgstr ""
-msgid "Merge"
+msgid "Members|Expired"
+msgstr ""
+
+msgid "Members|No expiration set"
msgstr ""
+msgid "Members|in %{time}"
+msgstr ""
+
+msgid "Memory Usage"
+msgstr "Minneforbruk"
+
+msgid "Merge"
+msgstr "Flett"
+
msgid "Merge (when the pipeline succeeds)"
msgstr ""
msgid "Merge Conflicts"
-msgstr ""
+msgstr "Flettekonflikter"
msgid "Merge Request"
-msgstr ""
+msgstr "Fletteforespørsel"
msgid "Merge Request Analytics"
msgstr ""
@@ -15233,13 +15814,13 @@ msgid "Merge Request Approvals"
msgstr ""
msgid "Merge Request Commits"
-msgstr ""
+msgstr "Fletteforespørsels-commiter"
msgid "Merge Requests"
-msgstr ""
+msgstr "Fletteforespørsel"
msgid "Merge Requests created"
-msgstr ""
+msgstr "Fletteforespørsel opprettet"
msgid "Merge Requests in Review"
msgstr ""
@@ -15251,34 +15832,34 @@ msgid "Merge automatically (%{strategy})"
msgstr ""
msgid "Merge commit message"
-msgstr ""
+msgstr "Innflettingscommit-melding"
msgid "Merge events"
-msgstr ""
+msgstr "Flett hendelser"
msgid "Merge immediately"
-msgstr ""
+msgstr "Flett umiddelbart"
msgid "Merge in progress"
-msgstr ""
+msgstr "Fletting pågår"
msgid "Merge locally"
-msgstr ""
+msgstr "Flett lokalt"
msgid "Merge options"
msgstr ""
msgid "Merge request"
-msgstr ""
+msgstr "Fletteforespørsel"
msgid "Merge request %{iid} authored by %{authorName}"
-msgstr ""
+msgstr "Fletteforespørsel %{iid} skapt av %{authorName}"
msgid "Merge request %{mr_link} was reviewed by %{mr_author}"
-msgstr ""
+msgstr "Fletteforespørselen %{mr_link} ble gjennomgått av %{mr_author}"
msgid "Merge request approvals"
-msgstr ""
+msgstr "Godkjenninger av fletteforespørsel"
msgid "Merge request approvals allow you to set the number of necessary approvals and predefine a list of approvers that will need to approve every merge request in a project."
msgstr ""
@@ -15290,7 +15871,7 @@ msgid "Merge request was scheduled to merge after pipeline succeeds"
msgstr ""
msgid "Merge requests"
-msgstr ""
+msgstr "Fletteforespørsel"
msgid "Merge requests approvals"
msgstr ""
@@ -15320,10 +15901,10 @@ msgid "MergeConflict|Use theirs"
msgstr ""
msgid "MergeConflict|conflict"
-msgstr ""
+msgstr "konflikt"
msgid "MergeConflict|conflicts"
-msgstr ""
+msgstr "konflikter"
msgid "MergeConflict|origin//their changes"
msgstr ""
@@ -15332,19 +15913,19 @@ msgid "MergeRequestAnalytics|Assignees"
msgstr ""
msgid "MergeRequestAnalytics|Date Merged"
-msgstr ""
+msgstr "Innflettingsdato"
msgid "MergeRequestAnalytics|Line changes"
-msgstr ""
+msgstr "Linjeendringer"
msgid "MergeRequestAnalytics|Merge Request"
-msgstr ""
+msgstr "Fletteforespørsel"
msgid "MergeRequestAnalytics|Milestone"
-msgstr ""
+msgstr "Milepæl"
msgid "MergeRequestAnalytics|Pipelines"
-msgstr ""
+msgstr "Rørledninger"
msgid "MergeRequestAnalytics|Time to merge"
msgstr ""
@@ -15356,7 +15937,7 @@ msgid "MergeRequestDiffs|Select comment starting line"
msgstr ""
msgid "MergeRequests|Add a reply"
-msgstr ""
+msgstr "Legg til et svar"
msgid "MergeRequests|An error occurred while checking whether another squash is in progress."
msgstr ""
@@ -15368,16 +15949,16 @@ msgid "MergeRequests|Failed to squash. Should be done manually."
msgstr ""
msgid "MergeRequests|Jump to next unresolved thread"
-msgstr ""
+msgstr "Hopp til neste uoppklarte tråd"
msgid "MergeRequests|Reply..."
-msgstr ""
+msgstr "Svar …"
msgid "MergeRequests|Resolve this thread in a new issue"
-msgstr ""
+msgstr "Oppklar denne tråden i en ny sak"
msgid "MergeRequests|Saving the comment failed"
-msgstr ""
+msgstr "Lagring av kommentaren mislyktes"
msgid "MergeRequests|Squash task canceled: another squash is already in progress."
msgstr ""
@@ -15386,37 +15967,34 @@ msgid "MergeRequests|This project does not allow squashing commits when merge re
msgstr ""
msgid "MergeRequests|Thread stays resolved"
-msgstr ""
+msgstr "Tråden forblir oppklart"
msgid "MergeRequests|Thread stays unresolved"
-msgstr ""
+msgstr "Tråden forblir uoppklart"
msgid "MergeRequests|Thread will be resolved"
-msgstr ""
+msgstr "Tråden vil bli oppklart"
msgid "MergeRequests|Thread will be unresolved"
-msgstr ""
-
-msgid "MergeRequests|Toggle comments for this file"
-msgstr ""
+msgstr "Tråden vil bli uoppklart"
msgid "MergeRequests|View file @ %{commitId}"
-msgstr ""
+msgstr "Vis filen @ %{commitId}"
msgid "MergeRequests|View replaced file @ %{commitId}"
-msgstr ""
+msgstr "Vis den erstattede filen @ %{commitId}"
msgid "MergeRequests|commented on commit %{commitLink}"
-msgstr ""
+msgstr "kommenterte på commiten %{commitLink}"
msgid "MergeRequests|started a thread"
-msgstr ""
+msgstr "startet en tråd"
msgid "MergeRequests|started a thread on %{linkStart}an old version of the diff%{linkEnd}"
-msgstr ""
+msgstr "startet en tråd på %{linkStart}en gammel versjon av diffen%{linkEnd}"
msgid "MergeRequests|started a thread on %{linkStart}the diff%{linkEnd}"
-msgstr ""
+msgstr "startet en tråd på %{linkStart}diffen%{linkEnd}"
msgid "MergeRequests|started a thread on an outdated change in commit %{linkStart}%{commitDisplay}%{linkEnd}"
msgstr ""
@@ -15425,7 +16003,7 @@ msgid "MergeRequests|started a thread on commit %{linkStart}%{commitDisplay}%{li
msgstr ""
msgid "MergeRequest|Compare %{target} and %{source}"
-msgstr ""
+msgstr "Sammenlign %{target} og %{source}"
msgid "MergeRequest|Error dismissing suggestion popover. Please try again."
msgstr ""
@@ -15434,22 +16012,22 @@ msgid "MergeRequest|Error loading full diff. Please try again."
msgstr ""
msgid "MergeRequest|No files found"
-msgstr ""
+msgstr "Ingen filer ble funnet"
msgid "MergeRequest|Search files (%{modifier_key}P)"
-msgstr ""
+msgstr "Søk i filer (%{modifier_key}P)"
msgid "Merged"
-msgstr ""
+msgstr "Flettet"
msgid "Merged MRs"
-msgstr ""
+msgstr "Innflettede FF-er"
msgid "Merged branches are being deleted. This can take some time depending on the number of branches. Please refresh the page to see changes."
msgstr ""
msgid "Merged this merge request."
-msgstr ""
+msgstr "Innflettet denne fletteforespørselen."
msgid "Merges this merge request immediately."
msgstr ""
@@ -15460,11 +16038,14 @@ msgstr ""
msgid "Merging immediately isn't recommended as it may negatively impact the existing merge train. Read the %{docsLinkStart}documentation%{docsLinkEnd} for more information."
msgstr ""
-msgid "Messages"
+msgid "Message"
msgstr ""
+msgid "Messages"
+msgstr "Meldinger"
+
msgid "Method"
-msgstr ""
+msgstr "Metode"
msgid "Metric was successfully added."
msgstr ""
@@ -15473,13 +16054,13 @@ msgid "Metric was successfully updated."
msgstr ""
msgid "Metric:"
-msgstr ""
+msgstr "MÃ¥ltall:"
msgid "MetricChart|Please select a metric"
msgstr ""
msgid "MetricChart|Selected"
-msgstr ""
+msgstr "Valgt"
msgid "MetricChart|There is no data available. Please change your selection."
msgstr ""
@@ -15488,16 +16069,16 @@ msgid "MetricChart|There is too much data to calculate. Please change your selec
msgstr ""
msgid "Metrics"
-msgstr ""
+msgstr "MÃ¥ltall"
msgid "Metrics - Grafana"
msgstr ""
msgid "Metrics - Prometheus"
-msgstr ""
+msgstr "MÃ¥ltall - Prometheus"
msgid "Metrics Dashboard"
-msgstr ""
+msgstr "MÃ¥lingskontrollpanel"
msgid "Metrics Dashboard YAML definition"
msgstr ""
@@ -15548,7 +16129,7 @@ msgid "MetricsSettings|Choose whether to display dashboard metrics in UTC or the
msgstr ""
msgid "MetricsSettings|Dashboard timezone"
-msgstr ""
+msgstr "Kontrollpanel-tidssone"
msgid "MetricsSettings|External dashboard URL"
msgstr ""
@@ -15560,7 +16141,7 @@ msgid "MetricsSettings|Metrics dashboard"
msgstr ""
msgid "MetricsSettings|UTC (Coordinated Universal Time)"
-msgstr ""
+msgstr "UTC (Coordinated Universal Time)"
msgid "MetricsSettings|User's local timezone"
msgstr ""
@@ -15575,28 +16156,28 @@ msgid "Metrics|Add metric"
msgstr ""
msgid "Metrics|Add panel"
-msgstr ""
+msgstr "Legg til panel"
msgid "Metrics|Avg"
-msgstr ""
+msgstr "Gj.snitt"
msgid "Metrics|Back to dashboard"
-msgstr ""
+msgstr "Tilbake til kontrollpanelet"
msgid "Metrics|Cancel"
-msgstr ""
+msgstr "Avbryt"
msgid "Metrics|Check out the CI/CD documentation on deploying to an environment"
msgstr ""
msgid "Metrics|Collapse panel"
-msgstr ""
+msgstr "Klapp sammen panel"
msgid "Metrics|Collapse panel (Esc)"
msgstr ""
msgid "Metrics|Copy YAML"
-msgstr ""
+msgstr "Kopier YAML"
msgid "Metrics|Copy and paste the panel YAML into your dashboard YAML file."
msgstr ""
@@ -15605,16 +16186,16 @@ msgid "Metrics|Create custom dashboard %{fileName}"
msgstr ""
msgid "Metrics|Create metric"
-msgstr ""
+msgstr "Opprett metrikk"
msgid "Metrics|Create new dashboard"
-msgstr ""
+msgstr "Opprett nytt kontrollpanel"
msgid "Metrics|Create your dashboard configuration file"
msgstr ""
msgid "Metrics|Current"
-msgstr ""
+msgstr "Nåværende"
msgid "Metrics|Dashboard files can be found in %{codeStart}.gitlab/dashboards%{codeEnd} at the root of this project."
msgstr ""
@@ -15629,19 +16210,19 @@ msgid "Metrics|Delete metric?"
msgstr ""
msgid "Metrics|Duplicate"
-msgstr ""
+msgstr "Dupliser"
msgid "Metrics|Duplicate current dashboard"
-msgstr ""
+msgstr "Dupliser det nåværende kontrollpanelet"
msgid "Metrics|Duplicate dashboard"
-msgstr ""
+msgstr "Dupliser kontrollpanel"
msgid "Metrics|Duplicate this dashboard to add panel or edit dashboard YAML."
-msgstr ""
+msgstr "Dupliser dette kontrollpanelet for å legge til et panel eller redigere kontrollpanelets YAML."
msgid "Metrics|Duplicating..."
-msgstr ""
+msgstr "Dupliserer …"
msgid "Metrics|Edit dashboard YAML"
msgstr ""
@@ -15652,10 +16233,10 @@ msgstr[0] ""
msgstr[1] ""
msgid "Metrics|Expand panel"
-msgstr ""
+msgstr "Utvid panel"
msgid "Metrics|For grouping similar metrics"
-msgstr ""
+msgstr "For gruppering av lignende metrikker"
msgid "Metrics|Invalid time range, please verify."
msgstr ""
@@ -15676,28 +16257,28 @@ msgid "Metrics|Manage chart links"
msgstr ""
msgid "Metrics|Max"
-msgstr ""
+msgstr "Maks"
msgid "Metrics|Metrics Settings"
msgstr ""
msgid "Metrics|Min"
-msgstr ""
+msgstr "Min."
msgid "Metrics|More actions"
-msgstr ""
+msgstr "Flere handlinger"
msgid "Metrics|Must be a valid PromQL query."
-msgstr ""
+msgstr "Må være en gyldig PromQL-spørring."
msgid "Metrics|New metric"
-msgstr ""
+msgstr "Ny metrikk"
msgid "Metrics|Open repository"
msgstr ""
msgid "Metrics|Panel YAML"
-msgstr ""
+msgstr "Panel-YAML"
msgid "Metrics|Panel YAML copied"
msgstr ""
@@ -15709,16 +16290,16 @@ msgid "Metrics|PromQL query is valid"
msgstr ""
msgid "Metrics|Prometheus Query Documentation"
-msgstr ""
+msgstr "Prometheus spørrings-dokumentasjon"
msgid "Metrics|Refresh Prometheus data"
-msgstr ""
+msgstr "Oppfrisk Prometheus-data"
msgid "Metrics|Refresh dashboard"
msgstr ""
msgid "Metrics|Select a value"
-msgstr ""
+msgstr "Velg en verdi"
msgid "Metrics|Set refresh rate"
msgstr ""
@@ -15730,13 +16311,13 @@ msgid "Metrics|There was an error creating the dashboard."
msgstr ""
msgid "Metrics|There was an error creating the dashboard. %{error}"
-msgstr ""
+msgstr "En feil oppstod under oppretting av kontrollpanelet. %{error}"
msgid "Metrics|There was an error fetching annotations. Please try again."
msgstr ""
msgid "Metrics|There was an error fetching the environments data, please try again"
-msgstr ""
+msgstr "Det oppstod en feil under henting av miljødataene, prøv igjen"
msgid "Metrics|There was an error getting annotations information."
msgstr ""
@@ -15745,19 +16326,19 @@ msgid "Metrics|There was an error getting dashboard validation warnings informat
msgstr ""
msgid "Metrics|There was an error getting deployment information."
-msgstr ""
+msgstr "Det oppsto en feil ved henting av distribusjonsinformasjon."
msgid "Metrics|There was an error getting environments information."
-msgstr ""
+msgstr "Det oppsto en feil ved henting av informasjon om miljøene."
msgid "Metrics|There was an error getting options for variable \"%{name}\"."
-msgstr ""
+msgstr "En feil oppstod under henting av innstillinger for variabelen «%{name}»."
msgid "Metrics|There was an error trying to validate your query"
msgstr ""
msgid "Metrics|There was an error while retrieving metrics"
-msgstr ""
+msgstr "Det oppstod en feil ved henting av metrikker"
msgid "Metrics|There was an error while retrieving metrics. %{message}"
msgstr ""
@@ -15769,28 +16350,28 @@ msgid "Metrics|Unexpected deployment data response from prometheus endpoint"
msgstr ""
msgid "Metrics|Unit label"
-msgstr ""
+msgstr "Enhets-etikett"
msgid "Metrics|Unstar dashboard"
msgstr ""
msgid "Metrics|Used as a title for the chart"
-msgstr ""
+msgstr "Brukes som tittel for diagrammet"
msgid "Metrics|Used if the query returns a single series. If it returns multiple series, their legend labels will be picked up from the response."
-msgstr ""
+msgstr "Brukes hvis spørringen returnerer en enkelt serie. Hvis den returnerer flere serier, blir legendeetikettene hentet fra svaret."
msgid "Metrics|Validating query"
msgstr ""
msgid "Metrics|Values"
-msgstr ""
+msgstr "Verdier"
msgid "Metrics|View documentation"
-msgstr ""
+msgstr "Vis dokumentasjon"
msgid "Metrics|View logs"
-msgstr ""
+msgstr "Vis loggføringer"
msgid "Metrics|View runbook - %{label}"
msgstr ""
@@ -15808,10 +16389,10 @@ msgid "Metrics|Your dashboard schema is invalid. Edit the dashboard to correct t
msgstr ""
msgid "Metrics|e.g. HTTP requests"
-msgstr ""
+msgstr "f.eks. HTTP-forespørsler"
msgid "Metrics|e.g. Requests/second"
-msgstr ""
+msgstr "f.eks. forespørsler per sekund"
msgid "Metrics|e.g. Throughput"
msgstr ""
@@ -15820,13 +16401,13 @@ msgid "Metrics|e.g. rate(http_requests_total[5m])"
msgstr ""
msgid "Metrics|e.g. req/sec"
-msgstr ""
+msgstr "f.eks. foresprl./sek"
msgid "Mi"
-msgstr ""
+msgstr "Mi"
msgid "Microsoft Azure"
-msgstr ""
+msgstr "Microsoft Azure"
msgid "Middleman project with Static Site Editor support"
msgstr ""
@@ -15842,11 +16423,8 @@ msgstr ""
msgid "Milestone"
msgid_plural "Milestones"
-msgstr[0] ""
-msgstr[1] ""
-
-msgid "Milestone does not support burnup charts"
-msgstr ""
+msgstr[0] "Milepæl"
+msgstr[1] "Milepæler"
msgid "Milestone lists not available with your current license"
msgstr ""
@@ -15854,119 +16432,116 @@ msgstr ""
msgid "Milestone lists show all issues from the selected milestone."
msgstr ""
-msgid "Milestone must have a start and due date"
-msgstr ""
-
msgid "MilestoneSidebar|Closed:"
-msgstr ""
+msgstr "Lukket:"
msgid "MilestoneSidebar|Copy reference"
-msgstr ""
+msgstr "Kopier referanse"
msgid "MilestoneSidebar|Due date"
-msgstr ""
+msgstr "MÃ¥ldato"
msgid "MilestoneSidebar|Edit"
-msgstr ""
+msgstr "Rediger"
msgid "MilestoneSidebar|From"
-msgstr ""
+msgstr "Fra"
msgid "MilestoneSidebar|Issues"
-msgstr ""
+msgstr "Saker"
msgid "MilestoneSidebar|Merge requests"
-msgstr ""
+msgstr "Fletteforespørsler"
msgid "MilestoneSidebar|Merged:"
-msgstr ""
+msgstr "Innflettet:"
msgid "MilestoneSidebar|New Issue"
-msgstr ""
+msgstr "Ny sak"
msgid "MilestoneSidebar|New issue"
-msgstr ""
+msgstr "Ny sak"
msgid "MilestoneSidebar|No due date"
-msgstr ""
+msgstr "Ingen måldato"
msgid "MilestoneSidebar|No start date"
-msgstr ""
+msgstr "Ingen startdato"
msgid "MilestoneSidebar|None"
-msgstr ""
+msgstr "Ingen"
msgid "MilestoneSidebar|Open:"
-msgstr ""
+msgstr "Ã…pen:"
msgid "MilestoneSidebar|Reference:"
-msgstr ""
+msgstr "Referanse:"
msgid "MilestoneSidebar|Start date"
-msgstr ""
+msgstr "Startdato"
msgid "MilestoneSidebar|Toggle sidebar"
-msgstr ""
+msgstr "Veksle sidelinje"
msgid "MilestoneSidebar|Until"
-msgstr ""
+msgstr "Frem til"
msgid "MilestoneSidebar|complete"
-msgstr ""
+msgstr "fullført"
msgid "Milestones"
-msgstr ""
+msgstr "Milepæler"
msgid "Milestones| You’re about to permanently delete the milestone %{milestoneTitle} and remove it from %{issuesWithCount} and %{mergeRequestsWithCount}. Once deleted, it cannot be undone or recovered."
-msgstr ""
+msgstr "Du er i ferd med å slette milepælen %{milestoneTitle} permanent og fjerne den fra %{issuesWithCount} og %{mergeRequestsWithCount}. Når den har blitt slettet, kan den ikke angres på eller gjenopprettes."
msgid "Milestones| You’re about to permanently delete the milestone %{milestoneTitle}. This milestone is not currently used in any issues or merge requests."
-msgstr ""
+msgstr "Du er i ferd med å slette milepælen %{milestoneTitle}permanent. Denne milepælen brukes for øyeblikket ikke i noen saker eller fletteforespørsler."
msgid "Milestones|Close Milestone"
-msgstr ""
+msgstr "Lukk milepæl"
msgid "Milestones|Completed Issues (closed)"
-msgstr ""
+msgstr "Fullførte saker (lukket)"
msgid "Milestones|Delete milestone"
-msgstr ""
+msgstr "Slett milepæl"
msgid "Milestones|Delete milestone %{milestoneTitle}?"
-msgstr ""
+msgstr "Slett milepæl %{milestoneTitle}?"
msgid "Milestones|Failed to delete milestone %{milestoneTitle}"
-msgstr ""
+msgstr "Mislyktes i å slette milepælen %{milestoneTitle}"
msgid "Milestones|Group Milestone"
-msgstr ""
+msgstr "Gruppemilepæl"
msgid "Milestones|Milestone %{milestoneTitle} was not found"
-msgstr ""
+msgstr "Milepælen %{milestoneTitle} ble ikke funnet"
msgid "Milestones|Ongoing Issues (open and assigned)"
-msgstr ""
+msgstr "Pågående saker (åpne og tilordnede)"
msgid "Milestones|Project Milestone"
-msgstr ""
+msgstr "Prosjektmilepæl"
msgid "Milestones|Promote %{milestoneTitle} to group milestone?"
msgstr ""
msgid "Milestones|Promote Milestone"
-msgstr ""
+msgstr "Forfrem milepæl"
msgid "Milestones|Promote to Group Milestone"
-msgstr ""
+msgstr "Forfrem til Gruppemilepæl"
msgid "Milestones|Promoting %{milestoneTitle} will make it available for all projects inside %{groupName}. Existing project milestones with the same title will be merged."
msgstr ""
msgid "Milestones|Reopen Milestone"
-msgstr ""
+msgstr "Gjenåpne milepælen"
msgid "Milestones|This action cannot be reversed."
-msgstr ""
+msgstr "Denne handlingen kan ikke reverseres."
msgid "Milestones|Unstarted Issues (open and unassigned)"
msgstr ""
@@ -15975,40 +16550,40 @@ msgid "Minimum capacity to be available before we schedule more mirrors preempti
msgstr ""
msgid "Minimum interval in days"
-msgstr ""
+msgstr "Minimumsintervall i dager"
msgid "Minimum length is %{minimum_password_length} characters"
-msgstr ""
+msgstr "Minimumslengden er på %{minimum_password_length} tegn"
msgid "Minimum length is %{minimum_password_length} characters."
-msgstr ""
+msgstr "Minimumslengden er på %{minimum_password_length} tegn."
msgid "Minimum password length (number of characters)"
-msgstr ""
+msgstr "Minimumspassordlengde (antall tegn)"
msgid "Minutes"
-msgstr ""
+msgstr "Minutter"
msgid "Mirror direction"
-msgstr ""
+msgstr "Speilingsretning"
msgid "Mirror repository"
-msgstr ""
+msgstr "Speil kodelager"
msgid "Mirror settings are only available to GitLab administrators."
-msgstr ""
+msgstr "Speilingsinnstillinger er bare tilgjengelige for GitLab-administratorer."
msgid "Mirror user"
-msgstr ""
+msgstr "Speil bruker"
msgid "Mirrored branches will have this prefix. If you enabled 'Only mirror protected branches' you need to include this prefix on protected branches in this project or nothing will be mirrored."
msgstr ""
msgid "Mirrored repositories"
-msgstr ""
+msgstr "Speilede kodelagre"
msgid "Mirroring repositories"
-msgstr ""
+msgstr "Speiler kodelagre"
msgid "Mirroring settings were successfully updated."
msgstr ""
@@ -16017,16 +16592,16 @@ msgid "Mirroring settings were successfully updated. The project is being update
msgstr ""
msgid "Mirroring was successfully disabled."
-msgstr ""
+msgstr "Speiling ble vellykket skrudd av."
msgid "Mirroring will only be available if the feature is included in the plan of the selected group or user."
msgstr ""
msgid "Missing OAuth configuration for GitHub."
-msgstr ""
+msgstr "Manglende OAuth-konfigurasjon for GitHub."
msgid "Missing OS"
-msgstr ""
+msgstr "Manglende OS"
msgid "Missing arch"
msgstr ""
@@ -16035,109 +16610,109 @@ msgid "Missing commit signatures endpoint!"
msgstr ""
msgid "MissingSSHKeyWarningLink|Add SSH key"
-msgstr ""
+msgstr "Legg til SSH-nøkkel"
msgid "MissingSSHKeyWarningLink|Don't show again"
-msgstr ""
+msgstr "Ikke vis igjen"
msgid "MissingSSHKeyWarningLink|You won't be able to pull or push project code via SSH until you add an SSH key to your profile"
msgstr ""
msgid "ModalButton|Add projects"
-msgstr ""
+msgstr "Legg til prosjekter"
msgid "Modal|Cancel"
-msgstr ""
+msgstr "Avbryt"
msgid "Modal|Close"
-msgstr ""
+msgstr "Lukk"
msgid "Modified"
-msgstr ""
+msgstr "Endret"
msgid "Modified in this version"
-msgstr ""
+msgstr "Modifisert i denne versjonen"
msgid "Modify commit message"
-msgstr ""
+msgstr "Modifiser commit-meldingen"
msgid "Modify commit messages"
-msgstr ""
+msgstr "Modifiser commit-meldinger"
msgid "Modify merge commit"
-msgstr ""
+msgstr "Modifiser innflettings-commiten"
msgid "Monday"
-msgstr ""
+msgstr "Mandag"
msgid "Monitor your errors by integrating with Sentry."
-msgstr ""
+msgstr "Overvåk feilene dine ved å integrere med Sentry."
msgid "Monitoring"
-msgstr ""
+msgstr "Adminovervåking"
msgid "Month"
-msgstr ""
+msgstr "MÃ¥ned"
msgid "Months"
-msgstr ""
+msgstr "MÃ¥neder"
msgid "More"
-msgstr ""
+msgstr "Mer"
msgid "More Information"
-msgstr ""
+msgstr "Mer informasjon"
msgid "More Slack commands"
-msgstr ""
+msgstr "Mere Slack-kommandoer"
msgid "More actions"
-msgstr ""
+msgstr "Flere handlinger"
msgid "More details"
-msgstr ""
+msgstr "Mere detaljer"
msgid "More info"
-msgstr ""
+msgstr "Mer informasjon"
msgid "More information"
-msgstr ""
+msgstr "Mer informasjon"
msgid "More information and share feedback"
msgstr ""
msgid "More information is available|here"
-msgstr ""
+msgstr "her"
msgid "More information."
-msgstr ""
+msgstr "Mere informasjon."
msgid "More than %{number_commits_distance} commits different with %{default_branch}"
-msgstr ""
+msgstr "Mer enn %{number_commits_distance} commiter er annerledes fra %{default_branch}"
msgid "Most stars"
-msgstr ""
+msgstr "Flest stjerner"
msgid "Mount point %{mounted_as} not found in %{model_class}."
msgstr ""
msgid "Move"
-msgstr ""
+msgstr "Flytt"
msgid "Move issue"
-msgstr ""
+msgstr "Flytt problemet"
msgid "Move issue from one column of the board to another"
msgstr ""
msgid "Move selection down"
-msgstr ""
+msgstr "Flytt utvalget ned"
msgid "Move selection up"
-msgstr ""
+msgstr "Flytt utvalget opp"
msgid "Move this issue to another project."
-msgstr ""
+msgstr "Flytt denne saken til et annet prosjekt."
msgid "MoveIssue|Cannot move issue due to insufficient permissions!"
msgstr ""
@@ -16149,13 +16724,13 @@ msgid "Moved issue to %{label} column in the board."
msgstr ""
msgid "Moved this issue to %{path_to_project}."
-msgstr ""
+msgstr "Flyttet denne saken til %{path_to_project}."
msgid "Moves issue to %{label} column in the board."
msgstr ""
msgid "Moves this issue to %{path_to_project}."
-msgstr ""
+msgstr "Flytter denne saken til %{path_to_project}."
msgid "MrDeploymentActions|Deploy"
msgstr ""
@@ -16167,7 +16742,7 @@ msgid "MrDeploymentActions|Stop environment"
msgstr ""
msgid "Multi-project"
-msgstr ""
+msgstr "Multi-prosjekt"
msgid "Multi-project Runners cannot be removed"
msgstr ""
@@ -16197,40 +16772,43 @@ msgid "My Awesome Group"
msgstr ""
msgid "My company or team"
-msgstr ""
+msgstr "Mitt firma eller team"
msgid "My-Reaction"
msgstr ""
msgid "N/A"
-msgstr ""
+msgstr "Ikke aktuelt"
msgid "Name"
-msgstr ""
+msgstr "Navn"
msgid "Name has already been taken"
msgstr ""
msgid "Name is required"
-msgstr ""
+msgstr "Navn er påkrevd"
msgid "Name new label"
-msgstr ""
+msgstr "Navnet på nytt stempel"
msgid "Name:"
-msgstr ""
+msgstr "Navn:"
msgid "Namespace"
+msgstr "Navnefelt"
+
+msgid "Namespace ID:"
msgstr ""
msgid "Namespace is empty"
-msgstr ""
+msgstr "Navnefeltet er tomt"
msgid "Namespace:"
-msgstr ""
+msgstr "Navneområde:"
msgid "Namespaces"
-msgstr ""
+msgstr "Navnerom"
msgid "Namespaces to index"
msgstr ""
@@ -16239,67 +16817,67 @@ msgid "Naming, topics, avatar"
msgstr ""
msgid "Naming, visibility"
-msgstr ""
+msgstr "Navngivning, synlighet"
msgid "Navigate to the project to close the milestone."
msgstr ""
msgid "Nav|Help"
-msgstr ""
+msgstr "Hjelp"
msgid "Nav|Home"
-msgstr ""
+msgstr "Hjem"
msgid "Nav|Sign In / Register"
-msgstr ""
+msgstr "Logg inn / Registrer deg"
msgid "Nav|Sign out and sign in with a different account"
-msgstr ""
+msgstr "Logg ut og logg inn med en annen konto"
msgid "Need help?"
-msgstr ""
+msgstr "Trenger du hjelp?"
msgid "Needs attention"
-msgstr ""
+msgstr "Trenger oppmerksomhet"
msgid "Network"
-msgstr ""
+msgstr "Nettverk"
msgid "Network Policy|New rule"
msgstr ""
msgid "NetworkPolicies|%{ifLabelStart}if%{ifLabelEnd} %{ruleType} %{isLabelStart}is%{isLabelEnd} %{ruleDirection} %{ruleSelector} %{directionLabelStart}and is inbound from a%{directionLabelEnd} %{rule} %{portsLabelStart}on%{portsLabelEnd} %{ports}"
-msgstr ""
+msgstr "%{ifLabelStart}hvis%{ifLabelEnd} %{ruleType} %{isLabelStart}er%{isLabelEnd} %{ruleDirection} %{ruleSelector} %{directionLabelStart}og er innkommende fra en%{directionLabelEnd} %{rule} %{portsLabelStart}på%{portsLabelEnd} %{ports}"
msgid "NetworkPolicies|%{ifLabelStart}if%{ifLabelEnd} %{ruleType} %{isLabelStart}is%{isLabelEnd} %{ruleDirection} %{ruleSelector} %{directionLabelStart}and is outbound to a%{directionLabelEnd} %{rule} %{portsLabelStart}on%{portsLabelEnd} %{ports}"
-msgstr ""
+msgstr "%{ifLabelStart}hvis%{ifLabelEnd} %{ruleType} %{isLabelStart}er%{isLabelEnd} %{ruleDirection} %{ruleSelector} %{directionLabelStart}og er utgående fra en%{directionLabelEnd} %{rule} %{portsLabelStart}på%{portsLabelEnd} %{ports}"
msgid "NetworkPolicies|%{labelStart}Then%{labelEnd} %{action} %{spanStart}the network traffic.%{spanEnd}"
msgstr ""
msgid "NetworkPolicies|%{number} selected"
-msgstr ""
+msgstr "%{number} valgt"
msgid "NetworkPolicies|%{strongOpen}all%{strongClose} pods"
-msgstr ""
+msgstr "%{strongOpen}alle%{strongClose} podder"
msgid "NetworkPolicies|%{strongOpen}any%{strongClose} port"
-msgstr ""
+msgstr "%{strongOpen}enhver%{strongClose} port"
msgid "NetworkPolicies|.yaml"
-msgstr ""
+msgstr ".yaml"
msgid "NetworkPolicies|.yaml mode"
-msgstr ""
+msgstr ".yaml-modus"
msgid "NetworkPolicies|Actions"
-msgstr ""
+msgstr "Handlinger"
msgid "NetworkPolicies|All selected"
-msgstr ""
+msgstr "Alle valgt"
msgid "NetworkPolicies|Allow"
-msgstr ""
+msgstr "Tillat"
msgid "NetworkPolicies|Allow all inbound traffic to %{selector} from %{ruleSelector} on %{ports}"
msgstr ""
@@ -16307,23 +16885,35 @@ msgstr ""
msgid "NetworkPolicies|Allow all outbound traffic from %{selector} to %{ruleSelector} on %{ports}"
msgstr ""
+msgid "NetworkPolicies|Are you sure you want to delete this policy? This action cannot be undone."
+msgstr ""
+
msgid "NetworkPolicies|Choose whether to enforce this policy."
msgstr ""
msgid "NetworkPolicies|Create policy"
-msgstr ""
+msgstr "Opprett retningslinje"
msgid "NetworkPolicies|Define this policy's location, conditions and actions."
msgstr ""
-msgid "NetworkPolicies|Deny all traffic"
+msgid "NetworkPolicies|Delete policy"
+msgstr ""
+
+msgid "NetworkPolicies|Delete policy: %{policy}"
msgstr ""
+msgid "NetworkPolicies|Deny all traffic"
+msgstr "Avvis all trafikk"
+
msgid "NetworkPolicies|Description"
+msgstr "Beskrivelse"
+
+msgid "NetworkPolicies|Edit policy"
msgstr ""
msgid "NetworkPolicies|Editor mode"
-msgstr ""
+msgstr "Redigeringsmodus"
msgid "NetworkPolicies|Enforcement status"
msgstr ""
@@ -16332,72 +16922,78 @@ msgid "NetworkPolicies|Environment does not have deployment platform"
msgstr ""
msgid "NetworkPolicies|IP/subnet"
-msgstr ""
+msgstr "IP/undernett"
msgid "NetworkPolicies|If you are using Auto DevOps, your %{monospacedStart}auto-deploy-values.yaml%{monospacedEnd} file will not be updated if you change a policy in this section. Auto DevOps users should make changes by following the %{linkStart}Container Network Policy documentation%{linkEnd}."
-msgstr ""
+msgstr "Hvis du bruker Auto DevOps, vil ikke din %{monospacedStart}auto-deploy-values.yaml%{monospacedEnd}-filen bli oppdatert hvis du endrer en retningslinje i denne delen. Auto DevOps-brukere bør gjøre endringer ved å følge dokumentasjonen for %{linkStart}Container-nettverksretningslinjer%{linkEnd}."
msgid "NetworkPolicies|Invalid or empty policy"
-msgstr ""
+msgstr "Ugyldig eller tom retningslinje"
msgid "NetworkPolicies|Kubernetes error: %{error}"
-msgstr ""
+msgstr "Kubernetes-feil: %{error}"
msgid "NetworkPolicies|Last modified"
-msgstr ""
+msgstr "Senest endret"
msgid "NetworkPolicies|Name"
+msgstr "Navn"
+
+msgid "NetworkPolicies|Namespace"
msgstr ""
msgid "NetworkPolicies|Network Policy"
-msgstr ""
+msgstr "Nettverksretningslinje"
msgid "NetworkPolicies|Network traffic"
-msgstr ""
+msgstr "Nettverkstrafikk"
msgid "NetworkPolicies|New policy"
-msgstr ""
+msgstr "Ny retningslinje"
msgid "NetworkPolicies|No policies detected"
-msgstr ""
+msgstr "Ingen retningslinjer ble oppdaget"
msgid "NetworkPolicies|None selected"
-msgstr ""
+msgstr "Ingen valgt"
msgid "NetworkPolicies|Policies are a specification of how groups of pods are allowed to communicate with each other's network endpoints."
msgstr ""
msgid "NetworkPolicies|Policy %{policyName} was successfully changed"
-msgstr ""
+msgstr "%{policyName}-retningslinjen ble vellykket endret"
msgid "NetworkPolicies|Policy definition"
-msgstr ""
+msgstr "Retningslinjedefinisjon"
msgid "NetworkPolicies|Policy description"
-msgstr ""
+msgstr "Retningslinjebeskrivelse"
msgid "NetworkPolicies|Policy editor"
-msgstr ""
+msgstr "Retningslinjeredigerer"
msgid "NetworkPolicies|Policy preview"
msgstr ""
msgid "NetworkPolicies|Policy status"
-msgstr ""
+msgstr "Retningslinjestatus"
msgid "NetworkPolicies|Policy type"
-msgstr ""
+msgstr "Retningslinjetype"
msgid "NetworkPolicies|Rule"
-msgstr ""
+msgstr "Regel"
msgid "NetworkPolicies|Rule mode"
-msgstr ""
+msgstr "Regelmodus"
msgid "NetworkPolicies|Rule mode is unavailable for this policy. In some cases, we cannot parse the YAML file back into the rules editor."
msgstr ""
msgid "NetworkPolicies|Rules"
+msgstr "Regler"
+
+msgid "NetworkPolicies|Save changes"
msgstr ""
msgid "NetworkPolicies|Something went wrong, failed to update policy"
@@ -16407,174 +17003,180 @@ msgid "NetworkPolicies|Something went wrong, unable to fetch policies"
msgstr ""
msgid "NetworkPolicies|Status"
-msgstr ""
+msgstr "Status"
msgid "NetworkPolicies|Traffic that does not match any rule will be blocked."
msgstr ""
-msgid "NetworkPolicies|YAML editor"
+msgid "NetworkPolicies|Unable to parse policy"
msgstr ""
+msgid "NetworkPolicies|YAML editor"
+msgstr "YAML-redigerer"
+
msgid "NetworkPolicies|all DNS names"
-msgstr ""
+msgstr "alle DNS-navn"
msgid "NetworkPolicies|all IP addresses"
-msgstr ""
+msgstr "alle IP-adresser"
msgid "NetworkPolicies|any pod"
-msgstr ""
+msgstr "enhver pod"
msgid "NetworkPolicies|any port"
-msgstr ""
+msgstr "enhver port"
msgid "NetworkPolicies|domain name"
-msgstr ""
+msgstr "domenenavn"
msgid "NetworkPolicies|entity"
-msgstr ""
+msgstr "enhet"
msgid "NetworkPolicies|inbound to"
-msgstr ""
+msgstr "innkommende til"
msgid "NetworkPolicies|nowhere"
-msgstr ""
+msgstr "ingensteds"
msgid "NetworkPolicies|outbound from"
-msgstr ""
+msgstr "utgående fra"
msgid "NetworkPolicies|pod with labels"
-msgstr ""
+msgstr "pod med etiketter"
msgid "NetworkPolicies|pods %{pods}"
-msgstr ""
+msgstr "podder %{pods}"
msgid "NetworkPolicies|pods with labels"
-msgstr ""
+msgstr "podder med etiketter"
msgid "NetworkPolicies|ports %{ports}"
-msgstr ""
+msgstr "porter %{ports}"
msgid "NetworkPolicies|ports/protocols"
-msgstr ""
+msgstr "porter/protokoller"
msgid "Never"
-msgstr ""
+msgstr "Aldri"
msgid "New"
-msgstr ""
+msgstr "Ny"
msgid "New Application"
-msgstr ""
+msgstr "Ny applikasjon"
msgid "New Branch"
-msgstr ""
+msgstr "Ny gren"
msgid "New Deploy Key"
msgstr ""
msgid "New Environment"
-msgstr ""
+msgstr "Nytt miljø"
msgid "New Epic"
-msgstr ""
+msgstr "Nytt epos"
msgid "New File"
-msgstr ""
+msgstr "Ny fil"
msgid "New Group"
-msgstr ""
+msgstr "Ny gruppe"
msgid "New Group Name"
-msgstr ""
+msgstr "Nytt gruppenavn"
msgid "New Identity"
-msgstr ""
+msgstr "Ny identitet"
msgid "New Issue"
msgid_plural "New Issues"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "Nytt problem"
+msgstr[1] "Nye problemer"
msgid "New Jira import"
-msgstr ""
+msgstr "Ny Jira-import"
msgid "New Label"
-msgstr ""
+msgstr "Nytt stempel"
msgid "New Merge Request"
-msgstr ""
+msgstr "Ny fletteforespørsel"
msgid "New Milestone"
-msgstr ""
+msgstr "Ny milepæl"
msgid "New Pages Domain"
msgstr ""
msgid "New Password"
-msgstr ""
+msgstr "Nytt passord"
msgid "New Pipeline Schedule"
msgstr ""
msgid "New Project"
-msgstr ""
+msgstr "Nytt prosjekt"
msgid "New Requirement"
-msgstr ""
+msgstr "Nytt krav"
msgid "New Snippet"
+msgstr "Nytt utdrag"
+
+msgid "New Test Case"
msgstr ""
msgid "New User"
-msgstr ""
+msgstr "Ny bruker"
msgid "New branch"
-msgstr ""
+msgstr "Ny gren"
msgid "New branch unavailable"
-msgstr ""
+msgstr "Ny gren utilgjengelig"
msgid "New changes were added. %{linkStart}Reload the page to review them%{linkEnd}"
msgstr ""
msgid "New confidential epic title "
-msgstr ""
+msgstr "Tittel på nytt konfidensielt epos "
msgid "New confidential issue title"
-msgstr ""
+msgstr "Tittel på den nye konfidensielle saken"
msgid "New deploy key"
msgstr ""
msgid "New directory"
-msgstr ""
+msgstr "Ny katalog"
msgid "New environment"
-msgstr ""
+msgstr "Nytt miljø"
msgid "New epic"
-msgstr ""
+msgstr "Nytt epos"
msgid "New epic title"
-msgstr ""
+msgstr "Tittel på ny epos"
msgid "New file"
-msgstr ""
+msgstr "Ny fil"
msgid "New group"
-msgstr ""
+msgstr "Ny gruppe"
msgid "New health check access token has been generated!"
msgstr ""
msgid "New identity"
-msgstr ""
+msgstr "Ny identitet"
msgid "New issue"
-msgstr ""
+msgstr "Nytt problem"
msgid "New issue title"
-msgstr ""
+msgstr "Tittel på den nye saken"
msgid "New iteration"
msgstr ""
@@ -16583,28 +17185,28 @@ msgid "New iteration created"
msgstr ""
msgid "New label"
-msgstr ""
+msgstr "Nytt merke"
msgid "New merge request"
-msgstr ""
+msgstr "Ny fletteforespørsel"
msgid "New milestone"
-msgstr ""
+msgstr "New milestone"
msgid "New password"
-msgstr ""
+msgstr "Nytt passord"
msgid "New pipelines will cancel older, pending pipelines on the same branch"
msgstr ""
msgid "New project"
-msgstr ""
+msgstr "Nytt prosjekt"
msgid "New release"
-msgstr ""
+msgstr "Ny utgivelse"
msgid "New requirement"
-msgstr ""
+msgstr "Nytt krav"
msgid "New response for issue #%{issue_iid}:"
msgstr ""
@@ -16613,15 +17215,18 @@ msgid "New runners registration token has been generated!"
msgstr ""
msgid "New schedule"
-msgstr ""
+msgstr "Ny tidsplan"
msgid "New snippet"
-msgstr ""
+msgstr "Nytt utdrag"
msgid "New subgroup"
-msgstr ""
+msgstr "Ny undergruppe"
msgid "New tag"
+msgstr "Ny etikett"
+
+msgid "New test case"
msgstr ""
msgid "New users set to external"
@@ -16631,55 +17236,55 @@ msgid "New! Suggest changes directly"
msgstr ""
msgid "New..."
-msgstr ""
+msgstr "Ny..."
msgid "Newest first"
-msgstr ""
+msgstr "Nyeste øverst"
msgid "Newly registered users will by default be external"
msgstr ""
msgid "Next"
-msgstr ""
+msgstr "Neste"
msgid "Next commit"
-msgstr ""
+msgstr "Neste commit"
msgid "Next file in diff"
-msgstr ""
+msgstr "Neste fil i diff"
msgid "Next unresolved discussion"
msgstr ""
msgid "Nickname"
-msgstr ""
+msgstr "Kallenavn"
msgid "No"
-msgstr ""
+msgstr "Nei"
msgid "No %{header} for this request."
-msgstr ""
+msgstr "Ingen %{header} for denne forespørselen."
msgid "No %{providerTitle} repositories found"
msgstr ""
msgid "No Epic"
-msgstr ""
+msgstr "Ingen epos"
msgid "No Matching Results"
-msgstr ""
+msgstr "Ingen samsvarende resultater"
msgid "No Scopes"
msgstr ""
msgid "No Tag"
-msgstr ""
+msgstr "Ingen etikett"
msgid "No active admin user found"
msgstr ""
msgid "No activities found"
-msgstr ""
+msgstr "Ingen aktiviteter ble funnet"
msgid "No application_settings found"
msgstr ""
@@ -16691,19 +17296,19 @@ msgid "No available groups to fork the project."
msgstr ""
msgid "No branches found"
-msgstr ""
+msgstr "Ingen grener funnet"
msgid "No changes"
-msgstr ""
+msgstr "Ingen endringer"
-msgid "No changes between %{ref_start}%{source_branch}%{ref_end} and %{ref_start}%{target_branch}%{ref_end}"
+msgid "No changes between %{sourceBranch} and %{targetBranch}"
msgstr ""
msgid "No child epics match applied filters"
msgstr ""
msgid "No commits present here"
-msgstr ""
+msgstr "Ingen commiter er til stede her"
msgid "No connection could be made to a Gitaly Server, please check your logs!"
msgstr ""
@@ -16711,59 +17316,62 @@ msgstr ""
msgid "No containers available"
msgstr ""
-msgid "No contributions"
+msgid "No content to show"
msgstr ""
+msgid "No contributions"
+msgstr "Ingen bidrag"
+
msgid "No contributions were found"
-msgstr ""
+msgstr "Ingen bidrag ble funnet"
msgid "No credit card required."
-msgstr ""
+msgstr "Ingen kredittkort nødvendig."
msgid "No data found"
-msgstr ""
+msgstr "Ingen data funnet"
msgid "No data to display"
-msgstr ""
+msgstr "Ingen data å vise"
msgid "No deployments found"
msgstr ""
msgid "No due date"
-msgstr ""
+msgstr "Ingen forfallsdato"
msgid "No endpoint provided"
-msgstr ""
+msgstr "Ingen endepunkt ble oppgitt"
msgid "No errors to display."
-msgstr ""
+msgstr "Ingen feil å vise."
msgid "No estimate or time spent"
-msgstr ""
+msgstr "Ingen anslag eller tidsbruk"
msgid "No file chosen"
-msgstr ""
+msgstr "Ingen fil er valgt"
msgid "No file hooks found."
-msgstr ""
+msgstr "Ingen filkroker ble funnet."
msgid "No file selected"
-msgstr ""
+msgstr "Ingen fil er valgt"
msgid "No files"
-msgstr ""
+msgstr "Ingen filer"
msgid "No files found."
-msgstr ""
+msgstr "Ingen filer funnet."
msgid "No forks are available to you."
msgstr ""
msgid "No grouping"
-msgstr ""
+msgstr "Ingen gruppering"
msgid "No issues found"
-msgstr ""
+msgstr "Ingen saker funnet"
msgid "No iteration"
msgstr ""
@@ -16772,49 +17380,49 @@ msgid "No iterations to show"
msgstr ""
msgid "No job log"
-msgstr ""
+msgstr "Ingen jobblogg"
msgid "No jobs to show"
-msgstr ""
+msgstr "Ingen jobber å vise"
msgid "No label"
-msgstr ""
+msgstr "Ingen etikett"
msgid "No labels with such name or description"
msgstr ""
msgid "No license. All rights reserved"
-msgstr ""
-
-msgid "No licenses found."
-msgstr ""
+msgstr "Ingen lisens. Alle rettigheter forbeholdt"
msgid "No matches found"
-msgstr ""
+msgstr "Ingen treff"
msgid "No matching labels"
-msgstr ""
+msgstr "Ingen samsvarende stempler"
msgid "No matching results"
-msgstr ""
+msgstr "Ingen samsvarende resultater"
msgid "No matching results for \"%{query}\""
+msgstr "Ingen samsvarende resultater for \"%{query}\""
+
+msgid "No members found"
msgstr ""
msgid "No merge requests found"
-msgstr ""
+msgstr "Ingen fletteforespørsler ble funnet"
msgid "No messages were logged"
-msgstr ""
+msgstr "Ingen meldinger ble loggført"
msgid "No milestone"
-msgstr ""
+msgstr "Ingen milepæl"
msgid "No milestones to show"
-msgstr ""
+msgstr "Ingen milepæler å vise"
msgid "No other labels with such name or description"
-msgstr ""
+msgstr "Ingen andre stempler med sådan navn eller beskrivelse"
msgid "No panels matching properties %{opts}"
msgstr ""
@@ -16822,20 +17430,23 @@ msgstr ""
msgid "No parent group"
msgstr ""
-msgid "No pods available"
+msgid "No plan"
msgstr ""
+msgid "No pods available"
+msgstr "Ingen podder er tilgjengelige"
+
msgid "No policy matches this license"
-msgstr ""
+msgstr "Ingen retningslinje samsvarer med denne lisensen"
msgid "No preview for this file type"
-msgstr ""
+msgstr "Ingen forhåndsvisning for denne filtypen"
msgid "No prioritized labels with such name or description"
msgstr ""
msgid "No public groups"
-msgstr ""
+msgstr "Ingen offentlige grupper"
msgid "No ref selected"
msgstr ""
@@ -16844,10 +17455,10 @@ msgid "No related merge requests found."
msgstr ""
msgid "No repository"
-msgstr ""
+msgstr "Ingen kodelager"
msgid "No required pipeline"
-msgstr ""
+msgstr "Ingen påkrevd rørledning"
msgid "No runner executable"
msgstr ""
@@ -16856,10 +17467,10 @@ msgid "No runners found"
msgstr ""
msgid "No schedules"
-msgstr ""
+msgstr "Ingen tidsplaner"
msgid "No source selected"
-msgstr ""
+msgstr "Ingen kilde er valgt"
msgid "No stack trace for this error"
msgstr ""
@@ -16868,22 +17479,22 @@ msgid "No starrers matched your search"
msgstr ""
msgid "No start date"
-msgstr ""
+msgstr "Ingen startdato"
msgid "No status"
-msgstr ""
+msgstr "Ingen status"
msgid "No template"
-msgstr ""
+msgstr "Ingen mal"
msgid "No template selected"
-msgstr ""
+msgstr "Ingen mal valgt"
msgid "No test coverage"
-msgstr ""
+msgstr "Ingen testdekning"
msgid "No vulnerabilities present"
-msgstr ""
+msgstr "Ingen sårbarheter er til stede"
msgid "No webhooks found, add one in the form above."
msgstr ""
@@ -16895,61 +17506,67 @@ msgid "No, directly import the existing email addresses and usernames."
msgstr ""
msgid "No. of commits"
-msgstr ""
+msgstr "Antall commiter"
msgid "Nobody has starred this repository yet"
-msgstr ""
+msgstr "Ingen har stjernemerket dette kodelageret enda"
msgid "Node was successfully created."
-msgstr ""
+msgstr "Noden ble vellykket opprettet."
msgid "Node was successfully updated."
-msgstr ""
+msgstr "Noden ble vellykket oppdatert."
msgid "Nodes"
-msgstr ""
+msgstr "Noder"
msgid "Non-admin users can sign in with read-only access and make read-only API requests."
msgstr ""
msgid "None"
-msgstr ""
+msgstr "Ingen"
msgid "Not Implemented"
+msgstr "Ikke implementert"
+
+msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+msgstr ""
+
+msgid "Not all browsers support WebAuthn. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even from an unsupported browser."
msgstr ""
msgid "Not all data has been processed yet, the accuracy of the chart for the selected timeframe is limited."
msgstr ""
msgid "Not available"
-msgstr ""
+msgstr "Ikke tilgjengelig"
msgid "Not available for private projects"
-msgstr ""
+msgstr "Ikke tilgjengelig for private prosjekter"
msgid "Not available for protected branches"
-msgstr ""
+msgstr "Ikke tilgjengelig for beskyttede grener"
msgid "Not confidential"
-msgstr ""
+msgstr "Ikke konfidensiell"
msgid "Not enough data"
-msgstr ""
+msgstr "Ikke nok data"
msgid "Not found."
-msgstr ""
+msgstr "Ikke funnet."
msgid "Not now"
-msgstr ""
+msgstr "Ikke nå"
msgid "Not ready yet. Try again later."
-msgstr ""
+msgstr "Ikke klar enda. Prøv igjen senere."
msgid "Not started"
-msgstr ""
+msgstr "Ikke påbegynt"
msgid "Note"
-msgstr ""
+msgstr "Notis"
msgid "Note parameters are invalid: %{errors}"
msgstr ""
@@ -16958,190 +17575,193 @@ msgid "Note that this invitation was sent to %{mail_to_invite_email}, but you ar
msgstr ""
msgid "Note: As an administrator you may like to configure %{github_integration_link}, which will allow login via GitHub and allow connecting repositories without generating a Personal Access Token."
-msgstr ""
+msgstr "Bemerk: Som en GitLab-administrator, kan du ville konfigurere %{github_integration_link}, som vil tillate innlogging via GitHub og tillate å koble til kodelagre uten å generere en personlig tilgangssjetong."
msgid "Note: As an administrator you may like to configure %{github_integration_link}, which will allow login via GitHub and allow importing repositories without generating a Personal Access Token."
-msgstr ""
+msgstr "Bemerk: Som en GitLab-administrator, kan du ville konfigurere %{github_integration_link}, som vil tillate innlogging via GitHub og tillate å importere til kodelagre uten å generere en personlig tilgangssjetong."
msgid "Note: Consider asking your GitLab administrator to configure %{github_integration_link}, which will allow login via GitHub and allow connecting repositories without generating a Personal Access Token."
-msgstr ""
+msgstr "Bemerk: Vurder å spørre din GitLab-administrator om å konfigurere %{github_integration_link}, som vil tillate innlogging via GitHub og tillate å koble til kodelagre uten å generere en personlig tilgangssjetong."
msgid "Note: Consider asking your GitLab administrator to configure %{github_integration_link}, which will allow login via GitHub and allow importing repositories without generating a Personal Access Token."
-msgstr ""
+msgstr "Bemerk: Vurder å spørre din GitLab-administrator om å konfigurere %{github_integration_link}, som vil tillate innlogging via GitHub og tillate å importere til kodelagre uten å generere en personlig tilgangssjetong."
msgid "NoteForm|Note"
-msgstr ""
+msgstr "Notis"
msgid "Notes|Are you sure you want to cancel creating this comment?"
-msgstr ""
+msgstr "Er du sikker på at du vil avbryte opprettelsen av denne kommentaren?"
msgid "Notes|Collapse replies"
-msgstr ""
+msgstr "Klapp sammen svar"
msgid "Notes|Private comments are accessible by internal staff only"
msgstr ""
msgid "Notes|Show all activity"
-msgstr ""
+msgstr "Vis all historikk"
msgid "Notes|Show comments only"
-msgstr ""
+msgstr "Bare vis kommentarer"
msgid "Notes|Show history only"
-msgstr ""
+msgstr "Bare vis historikken"
msgid "Notes|This comment has changed since you started editing, please review the %{open_link}updated comment%{close_link} to ensure information is not lost"
msgstr ""
msgid "Nothing found…"
-msgstr ""
+msgstr "Ingenting ble funnet …"
msgid "Nothing to preview."
-msgstr ""
+msgstr "Ingenting å forhåndsvise."
msgid "Nothing to synchronize"
-msgstr ""
+msgstr "Ingenting å synkronisere"
msgid "Notification events"
-msgstr ""
+msgstr "Varslingshendelser"
msgid "Notification setting"
-msgstr ""
+msgstr "Varslingsinnstilling"
msgid "Notification setting - %{notification_title}"
-msgstr ""
+msgstr "Varslingsinnstilling - %{notification_title}"
msgid "Notification settings saved"
+msgstr "Varslingsinnstillingene ble lagret"
+
+msgid "NotificationEvent|Change reviewer merge request"
msgstr ""
msgid "NotificationEvent|Close issue"
-msgstr ""
+msgstr "Lukk saker"
msgid "NotificationEvent|Close merge request"
-msgstr ""
+msgstr "Lukke fletteforespørselen"
msgid "NotificationEvent|Failed pipeline"
-msgstr ""
+msgstr "Mislykket rørledning"
msgid "NotificationEvent|Fixed pipeline"
-msgstr ""
+msgstr "Fikset rørledning"
msgid "NotificationEvent|Merge merge request"
-msgstr ""
+msgstr "Innflett fletteforespørsel"
msgid "NotificationEvent|New epic"
-msgstr ""
+msgstr "Nytt epos"
msgid "NotificationEvent|New issue"
-msgstr ""
+msgstr "Ny sak"
msgid "NotificationEvent|New merge request"
-msgstr ""
+msgstr "Ny fletteforespørsel"
msgid "NotificationEvent|New note"
-msgstr ""
+msgstr "Ny notis"
msgid "NotificationEvent|New release"
-msgstr ""
+msgstr "Ny utgivelse"
msgid "NotificationEvent|Reassign issue"
-msgstr ""
+msgstr "Tilordne sak på nytt"
msgid "NotificationEvent|Reassign merge request"
-msgstr ""
+msgstr "Tilordne fletteforespørsel på nytt"
msgid "NotificationEvent|Reopen issue"
-msgstr ""
+msgstr "Gjenåpne saken"
msgid "NotificationEvent|Successful pipeline"
-msgstr ""
+msgstr "Vellykket rørledning"
msgid "NotificationLevel|Custom"
-msgstr ""
+msgstr "Egendefinert"
msgid "NotificationLevel|Disabled"
-msgstr ""
+msgstr "Skrudd av"
msgid "NotificationLevel|Global"
-msgstr ""
+msgstr "Universelt"
msgid "NotificationLevel|On mention"
-msgstr ""
+msgstr "Ved nevning"
msgid "NotificationLevel|Participate"
-msgstr ""
+msgstr "Delta"
msgid "NotificationLevel|Watch"
-msgstr ""
+msgstr "Hold øye med"
msgid "NotificationSetting|Custom"
-msgstr ""
+msgstr "Tilpasset"
msgid "Notifications"
-msgstr ""
+msgstr "Varsler"
msgid "Notifications have been disabled by the project or group owner"
msgstr ""
msgid "Notifications off"
-msgstr ""
+msgstr "Varsling av"
msgid "Notifications on"
-msgstr ""
+msgstr "Varsling på"
msgid "Notify users by email when sign-in location is not recognized"
msgstr ""
msgid "Nov"
-msgstr ""
+msgstr "Nov"
msgid "November"
-msgstr ""
+msgstr "November"
msgid "Novice"
-msgstr ""
+msgstr "Begynner"
msgid "Nuget metadatum must have at least license_url, project_url or icon_url set"
msgstr ""
msgid "Number of %{itemTitle}"
-msgstr ""
+msgstr "Antall %{itemTitle}"
msgid "Number of Elasticsearch replicas"
msgstr ""
msgid "Number of Elasticsearch shards"
-msgstr ""
+msgstr "Antall Elasticsearch-skår"
msgid "Number of LOCs per commit"
-msgstr ""
+msgstr "Antall LOC per commit"
msgid "Number of changes (branches or tags) in a single push to determine whether individual push events or bulk push event will be created. Bulk push event will be created if it surpasses that value."
-msgstr ""
+msgstr "Antall endringer (grener eller etiketter) i én enkelt push for å bestemme om individuelle pushhendelser eller bunke-pushhendelser skal opprettes. Bunke-pushhendelser vil bli opprettet hvis den overstiger denne verdien."
msgid "Number of changes (branches or tags) in a single push to determine whether webhooks and services will be fired or not. Webhooks and services won't be submitted if it surpasses that value."
msgstr ""
msgid "Number of commits"
-msgstr ""
+msgstr "Antall commiter"
msgid "Number of commits per MR"
-msgstr ""
+msgstr "Antall commiter per FF"
msgid "Number of employees"
-msgstr ""
+msgstr "Antall ansatte"
msgid "Number of events"
-msgstr ""
+msgstr "Antall hendelser"
msgid "Number of events for this project: %{total_count}."
msgstr ""
msgid "Number of files touched"
-msgstr ""
+msgstr "Antall berørte filer"
msgid "OK"
-msgstr ""
+msgstr "OK"
msgid "Object Storage replication"
msgstr ""
@@ -17150,36 +17770,33 @@ msgid "Object does not exist on the server or you don't have permissions to acce
msgstr ""
msgid "Oct"
-msgstr ""
+msgstr "Okt"
msgid "October"
-msgstr ""
+msgstr "Oktober"
msgid "OfSearchInADropdown|Filter"
msgstr ""
msgid "Off"
-msgstr ""
+msgstr "Av"
msgid "Oh no!"
-msgstr ""
+msgstr "Ã… nei!"
msgid "Oldest first"
-msgstr ""
+msgstr "Eldste øverst"
msgid "OmniAuth"
-msgstr ""
+msgstr "OmniAuth"
msgid "Omnibus Protected Paths throttle is active, and takes priority over these settings. From 12.4, Omnibus throttle is deprecated and will be removed in a future release. Please read the %{relative_url_link_start}Migrating Protected Paths documentation%{relative_url_link_end}."
-msgstr ""
+msgstr "Omnibus Protected Paths-pedalen er aktiv, og prioriterer disse innstillingene. Fra 12.4, avvikles Omnibus-pedalen og vil bli fjernet i en fremtidig utgivelse. Les dokumentasjonen for %{relative_url_link_start}Migrering av beskyttede filbaner%{relative_url_link_end}."
msgid "On track"
msgstr ""
-msgid "OnDemandScans|Attached branch"
-msgstr ""
-
-msgid "OnDemandScans|Attached branch is where the scan job runs."
+msgid "OnDemandScans|Could not fetch scanner profiles. Please refresh the page, or try again later."
msgstr ""
msgid "OnDemandScans|Could not fetch site profiles. Please refresh the page, or try again later."
@@ -17188,18 +17805,24 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
-msgid "OnDemandScans|Create a new site profile"
+msgid "OnDemandScans|Create a new scanner profile"
msgstr ""
+msgid "OnDemandScans|Create a new site profile"
+msgstr "Opprett en ny nettstedsprofil"
+
msgid "OnDemandScans|Create new DAST scan"
-msgstr ""
+msgstr "Opprett ny DAST-skanning"
msgid "OnDemandScans|Manage profiles"
-msgstr ""
+msgstr "Behandle profiler"
msgid "OnDemandScans|New on-demand DAST scan"
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 ""
@@ -17209,38 +17832,38 @@ msgstr ""
msgid "OnDemandScans|On-demand scans run outside the DevOps cycle and find vulnerabilities in your projects. %{learnMoreLinkStart}Learn more%{learnMoreLinkEnd}"
msgstr ""
-msgid "OnDemandScans|Only a passive scan can be performed on demand."
-msgstr ""
-
-msgid "OnDemandScans|Passive"
-msgstr ""
-
msgid "OnDemandScans|Run scan"
-msgstr ""
+msgstr "Kjør skanning"
-msgid "OnDemandScans|Scan mode"
+msgid "OnDemandScans|Scanner profile"
msgstr ""
msgid "OnDemandScans|Scanner settings"
-msgstr ""
+msgstr "Skannerinnstillinger"
msgid "OnDemandScans|Schedule or run scans immediately against target sites. Currently available on-demand scan type: DAST. %{helpLinkStart}More information%{helpLinkEnd}"
msgstr ""
msgid "OnDemandScans|Select one of the existing profiles"
+msgstr "Velg en av de eksisterende profilene"
+
+msgid "OnDemandScans|Site profile"
msgstr ""
msgid "OnDemandScans|Site profiles"
+msgstr "Nettstedsprofiler"
+
+msgid "OnDemandScans|Use existing scanner profile"
msgstr ""
msgid "OnDemandScans|Use existing site profile"
-msgstr ""
+msgstr "Bruk eksisterende sideprofil"
msgid "Once a project is permanently deleted it %{strongStart}cannot be recovered%{strongEnd}. Permanently deleting this project will %{strongStart}immediately delete%{strongEnd} its repositories and %{strongStart}all related resources%{strongEnd} including issues, merge requests etc."
-msgstr ""
+msgstr "Når et prosjekt er permanent slettet, kan det %{strongStart}ikke gjenopprettes%{strongEnd}. Hvis du sletter dette prosjektet permanent, vil %{strongStart}umiddelbart slette%{strongEnd} kodelagrene og %{strongStart}alle relaterte ressurser%{strongEnd}, inkludert saker, fletteforespørsler, osv."
msgid "Once a project is permanently deleted it cannot be recovered. You will lose this project's repository and all content: issues, merge requests etc."
-msgstr ""
+msgstr "Når et prosjekt er slettet permanent, kan det ikke gjenopprettes. Du mister dette prosjektets kodelager og alt innhold: saker, fletteforespørsler, osv."
msgid "Once imported, repositories can be mirrored over SSH. Read more %{link_start}here%{link_end}."
msgstr ""
@@ -17256,14 +17879,14 @@ msgstr ""
msgid "One more item"
msgid_plural "%d more items"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "Én gjenstand til"
+msgstr[1] "%d gjenstander til"
msgid "One or more groups that you don't have access to."
-msgstr ""
+msgstr "En eller flere grupper som du ikke har tilgang til."
msgid "One or more of you personal access tokens were revoked"
-msgstr ""
+msgstr "En eller flere av dine personlige tilgangssjetonger ble trukket tilbake"
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 ""
@@ -17272,7 +17895,7 @@ msgid "One or more of your Google Code projects cannot be imported into GitLab d
msgstr ""
msgid "One or more of your dependency files are not supported, and the dependency list may be incomplete. Below is a list of supported file types."
-msgstr ""
+msgstr "En eller flere av avhengighetsfilene dine er ikke støttet, og avhengighetslisten kan være ufullstendig. Nedenfor er en liste over støttede filtyper."
msgid "One or more of your personal access tokens has expired."
msgstr ""
@@ -17290,13 +17913,13 @@ msgid "Only Issue ID or Merge Request ID is required"
msgstr ""
msgid "Only Project Members"
-msgstr ""
+msgstr "Kun prosjektmedlemmer"
msgid "Only active this projects shows up in the search and on the dashboard."
msgstr ""
msgid "Only admins can delete project"
-msgstr ""
+msgstr "Bare administratorer kan slette prosjektet"
msgid "Only mirror protected branches"
msgstr ""
@@ -17308,7 +17931,7 @@ msgid "Only proceed if you trust %{idp_url} to control your GitLab account sign
msgstr ""
msgid "Only project members can comment."
-msgstr ""
+msgstr "Kun prosjektmedlemmer kan kommentere."
msgid "Only project members will be imported. Group members will be skipped."
msgstr ""
@@ -17317,73 +17940,70 @@ msgid "Only projects created under a Gold license are available in Security Dash
msgstr ""
msgid "Only verified users with an email address in any of these domains can be added to the group."
-msgstr ""
+msgstr "Bare bekreftede brukere med en e-postadresse hos et av disse domenene kan legges til i gruppen."
msgid "Only ‘Reporter’ roles and above on tiers Premium / Silver and above can see Productivity Analytics."
msgstr ""
msgid "Oops, are you sure?"
-msgstr ""
+msgstr "Oi sann, er du sikker?"
msgid "Open"
-msgstr ""
+msgstr "Ã…pne"
msgid "Open Selection"
msgstr ""
-msgid "Open Web IDE"
-msgstr ""
-
msgid "Open comment type dropdown"
msgstr ""
msgid "Open epics"
-msgstr ""
+msgstr "Ã…pne eposer"
msgid "Open errors"
-msgstr ""
+msgstr "Ã…pne feil"
msgid "Open in Xcode"
-msgstr ""
+msgstr "Ã…pne i Xcode"
msgid "Open in file view"
-msgstr ""
+msgstr "Ã…pne i filvisning"
msgid "Open issues"
-msgstr ""
+msgstr "Ã…pne saker"
msgid "Open projects"
-msgstr ""
+msgstr "Ã…pne prosjekter"
msgid "Open raw"
-msgstr ""
+msgstr "Åpne råversjon"
msgid "Open sidebar"
-msgstr ""
+msgstr "Ã…pne sidelinje"
msgid "Open: %{openIssuesCount}"
-msgstr ""
+msgstr "Ã…pen: %{openIssuesCount}"
msgid "Open: %{open} • Closed: %{closed}"
-msgstr ""
+msgstr "Åpen: %{open} • Lukket: %{closed}"
msgid "Opened"
-msgstr ""
+msgstr "Ã…pnet"
msgid "Opened %{epicTimeagoDate}"
-msgstr ""
+msgstr "Ã…pnet %{epicTimeagoDate}"
msgid "Opened MRs"
msgstr ""
msgid "Opened issues"
-msgstr ""
+msgstr "Ã…pnede problemer"
msgid "OpenedNDaysAgo|Opened"
-msgstr ""
+msgstr "Ã…pnet"
msgid "Opens in a new window"
-msgstr ""
+msgstr "Ã…pnes i et nytt vindu"
msgid "Operation failed. Check pod logs for %{pod_name} for more details."
msgstr ""
@@ -17395,7 +18015,7 @@ msgid "Operation timed out. Check pod logs for %{pod_name} for more details."
msgstr ""
msgid "Operations"
-msgstr ""
+msgstr "Handlinger"
msgid "Operations Dashboard"
msgstr ""
@@ -17407,10 +18027,10 @@ msgid "OperationsDashboard|Add a project to the dashboard"
msgstr ""
msgid "OperationsDashboard|Add projects"
-msgstr ""
+msgstr "Legg til prosjekter"
msgid "OperationsDashboard|More information"
-msgstr ""
+msgstr "Mer informasjon"
msgid "OperationsDashboard|Operations Dashboard"
msgstr ""
@@ -17419,46 +18039,52 @@ msgid "OperationsDashboard|The operations dashboard provides a summary of each p
msgstr ""
msgid "Optional"
-msgstr ""
+msgstr "Valgfritt"
msgid "Optional parameter \"variables\" must be a Hash. Ex: variables[key1]=value1"
msgstr ""
msgid "Optionally, you can %{link_to_customize} how FogBugz email addresses and usernames are imported into GitLab."
-msgstr ""
+msgstr "Eventuelt kan du %{link_to_customize} hvordan FogBugz-e-postadresser og brukernavn importeres til GitLab."
msgid "Optionally, you can %{link_to_customize} how Google Code email addresses and usernames are imported into GitLab."
-msgstr ""
+msgstr "Eventuelt kan du %{link_to_customize} hvordan Google Code-e-postadresser og brukernavn importeres til GitLab."
msgid "Options"
-msgstr ""
+msgstr "Innstillinger"
msgid "Or you can choose one of the suggested colors below"
-msgstr ""
+msgstr "Eller så kan du velge en av de foreslåtte fargene nedenfor"
msgid "Origin"
+msgstr "Opphav"
+
+msgid "Orphaned member"
msgstr ""
msgid "Other Labels"
-msgstr ""
+msgstr "Andre stempler"
msgid "Other information"
-msgstr ""
+msgstr "Annen informasjon"
msgid "Other merge requests block this MR"
msgstr ""
msgid "Other versions"
-msgstr ""
+msgstr "Andre versjoner"
msgid "Other visibility settings have been disabled by the administrator."
msgstr ""
+msgid "Our documentation includes an example DevOps Score report."
+msgstr ""
+
msgid "Out-of-compliance with this project's policies and should be removed"
msgstr ""
msgid "Outbound requests"
-msgstr ""
+msgstr "Utgående forespørsler"
msgid "OutdatedBrowser|GitLab may not work properly, because you are using an outdated web browser."
msgstr ""
@@ -17467,73 +18093,76 @@ msgid "OutdatedBrowser|Please install a %{browser_link_start}supported web brows
msgstr ""
msgid "Outdent"
-msgstr ""
+msgstr "Reduser innrykk"
msgid "Overridden"
-msgstr ""
+msgstr "Overstyrt"
msgid "Overview"
-msgstr ""
+msgstr "Oversikt"
msgid "Overwrite diverged branches"
msgstr ""
-msgid "Owned by anyone"
+msgid "Owned by %{image_tag}"
msgstr ""
+msgid "Owned by anyone"
+msgstr "Eid av hvem som helst"
+
msgid "Owned by me"
-msgstr ""
+msgstr "Eid av meg"
msgid "Owned by:"
-msgstr ""
+msgstr "Eid av:"
msgid "Owner"
-msgstr ""
+msgstr "Eier"
msgid "Package Registry"
-msgstr ""
+msgstr "Pakkeregister"
msgid "Package already exists"
-msgstr ""
+msgstr "Pakken finnes allerede"
msgid "Package deleted successfully"
+msgstr "Pakken ble vellykket slettet"
+
+msgid "Package file size limits"
msgstr ""
msgid "Package recipe already exists"
msgstr ""
msgid "Package type must be Conan"
-msgstr ""
+msgstr "Pakketypen må være Conan"
msgid "Package type must be Maven"
-msgstr ""
+msgstr "Pakketypen må være Maven"
msgid "Package type must be NuGet"
-msgstr ""
+msgstr "Pakketypen må være NuGet"
msgid "Package type must be PyPi"
-msgstr ""
-
-msgid "Package was removed"
-msgstr ""
+msgstr "Pakketypen må være PyPi"
msgid "PackageRegistry|%{name} version %{version} was created %{datetime}"
-msgstr ""
+msgstr "%{name} versjon %{version} ble opprettet den %{datetime}"
msgid "PackageRegistry|%{name} version %{version} was updated %{datetime}"
-msgstr ""
+msgstr "%{name} versjon %{version} ble oppdatert den %{datetime}"
msgid "PackageRegistry|Add Conan Remote"
msgstr ""
msgid "PackageRegistry|Add NuGet Source"
-msgstr ""
+msgstr "Legg til NuGet-kilde"
msgid "PackageRegistry|App group: %{group}"
-msgstr ""
+msgstr "Appgruppe: %{group}"
msgid "PackageRegistry|App name: %{name}"
-msgstr ""
+msgstr "Appnavn: %{name}"
msgid "PackageRegistry|Commit %{link} on branch %{branch}"
msgstr ""
@@ -17542,46 +18171,46 @@ msgid "PackageRegistry|Composer"
msgstr ""
msgid "PackageRegistry|Conan"
-msgstr ""
+msgstr "Conan"
msgid "PackageRegistry|Conan Command"
-msgstr ""
+msgstr "Conan-kommando"
msgid "PackageRegistry|Copy .pypirc content"
-msgstr ""
+msgstr "Kopier .pypirc-innhold"
msgid "PackageRegistry|Copy Conan Command"
-msgstr ""
+msgstr "Kopier Conan-kommando"
msgid "PackageRegistry|Copy Conan Setup Command"
msgstr ""
msgid "PackageRegistry|Copy Maven XML"
-msgstr ""
+msgstr "Kopier Maven-XML"
msgid "PackageRegistry|Copy Maven command"
-msgstr ""
+msgstr "Kopier Maven-kommando"
msgid "PackageRegistry|Copy Maven registry XML"
-msgstr ""
+msgstr "Kopier Maven-register-XML"
msgid "PackageRegistry|Copy NuGet Command"
-msgstr ""
+msgstr "Kopier NuGet-kommando"
msgid "PackageRegistry|Copy NuGet Setup Command"
msgstr ""
msgid "PackageRegistry|Copy Pip command"
-msgstr ""
+msgstr "Kopier Pip-kommando"
msgid "PackageRegistry|Copy and paste this inside your %{codeStart}pom.xml%{codeEnd} %{codeStart}dependencies%{codeEnd} block."
msgstr ""
msgid "PackageRegistry|Copy npm command"
-msgstr ""
+msgstr "Kopier npm-kommando"
msgid "PackageRegistry|Copy npm setup command"
-msgstr ""
+msgstr "Kopier npm setup-kommando"
msgid "PackageRegistry|Copy registry include"
msgstr ""
@@ -17590,19 +18219,19 @@ msgid "PackageRegistry|Copy require package include"
msgstr ""
msgid "PackageRegistry|Copy yarn command"
-msgstr ""
+msgstr "Kopier yarn-kommando"
msgid "PackageRegistry|Copy yarn setup command"
msgstr ""
msgid "PackageRegistry|Delete Package Version"
-msgstr ""
+msgstr "Slett pakkeversjonen"
msgid "PackageRegistry|Delete package"
-msgstr ""
+msgstr "Slett pakke"
msgid "PackageRegistry|Filter by name"
-msgstr ""
+msgstr "Filtrer etter navn"
msgid "PackageRegistry|For more information on Composer packages in GitLab, %{linkStart}see the documentation.%{linkEnd}"
msgstr ""
@@ -17626,55 +18255,61 @@ msgid "PackageRegistry|If you haven't already done so, you will need to add the
msgstr ""
msgid "PackageRegistry|Is your favorite package manager missing? We'd love your help in building first-class support for it into GitLab! %{contributionLinkStart}Visit the contribution documentation%{contributionLinkEnd} to learn more about how to build support for new package managers into GitLab. Below is a list of package managers that are on our radar."
-msgstr ""
+msgstr "Mangler din favorittpakkebehandler? Vi vil gjerne hjelpe deg med å bygge førsteklasses støtte til den i GitLab! %{contributionLinkStart}Gå til bidragsdokumentasjonen%{contributionLinkEnd} for å lære mer om hvordan du bygger støtte for nye pakkebehandlere i GitLab. Nedenfor er en liste over pakkebehandlere som er på radaren vår."
msgid "PackageRegistry|Learn how to %{noPackagesLinkStart}publish and share your packages%{noPackagesLinkEnd} with GitLab."
msgstr ""
msgid "PackageRegistry|License information located at %{link}"
-msgstr ""
+msgstr "Lisensinformasjonen er hos %{link}"
msgid "PackageRegistry|Manually Published"
-msgstr ""
+msgstr "Manuelt publisert"
msgid "PackageRegistry|Maven"
-msgstr ""
+msgstr "Maven"
msgid "PackageRegistry|Maven Command"
-msgstr ""
+msgstr "Maven-kommando"
msgid "PackageRegistry|Maven XML"
-msgstr ""
+msgstr "Maven-XML"
msgid "PackageRegistry|NPM"
-msgstr ""
+msgstr "NPM"
msgid "PackageRegistry|No upcoming issues"
-msgstr ""
+msgstr "Ingen kommende saker"
msgid "PackageRegistry|NuGet"
-msgstr ""
+msgstr "NuGet"
msgid "PackageRegistry|NuGet Command"
+msgstr "NuGet-kommando"
+
+msgid "PackageRegistry|Package Registry"
msgstr ""
msgid "PackageRegistry|Pip Command"
-msgstr ""
+msgstr "Pip-kommando"
msgid "PackageRegistry|Pipeline %{link} triggered %{datetime} by %{author}"
+msgstr "Rørledningen %{link} ble trigget %{datetime} av %{author}"
+
+msgid "PackageRegistry|Publish and share packages for a variety of common package managers. %{docLinkStart}More information%{docLinkEnd}"
msgstr ""
msgid "PackageRegistry|Published to the %{project} Package Registry %{datetime}"
msgstr ""
msgid "PackageRegistry|PyPi"
-msgstr ""
+msgstr "PyPi"
msgid "PackageRegistry|Recipe: %{recipe}"
msgstr ""
msgid "PackageRegistry|Remove package"
-msgstr ""
+msgstr "Fjern pakke"
msgid "PackageRegistry|Sorry, your filter produced no results"
msgstr ""
@@ -17683,16 +18318,16 @@ msgid "PackageRegistry|Source project located at %{link}"
msgstr ""
msgid "PackageRegistry|There are no %{packageType} packages yet"
-msgstr ""
+msgstr "Det er ingen %{packageType}-pakker enda"
msgid "PackageRegistry|There are no other versions of this package."
msgstr ""
msgid "PackageRegistry|There are no packages yet"
-msgstr ""
+msgstr "Det er ingen pakker enda"
msgid "PackageRegistry|There are no upcoming issues to display."
-msgstr ""
+msgstr "Det er ingen kommende saker å vise."
msgid "PackageRegistry|There was a problem fetching the details for this package."
msgstr ""
@@ -17707,10 +18342,10 @@ msgid "PackageRegistry|Unable to fetch package version information."
msgstr ""
msgid "PackageRegistry|Unable to load package"
-msgstr ""
+msgstr "Klarte ikke å laste inn pakke"
msgid "PackageRegistry|Upcoming package managers"
-msgstr ""
+msgstr "Kommende pakkebehandlere"
msgid "PackageRegistry|You are about to delete %{name}, this operation is irreversible, are you sure?"
msgstr ""
@@ -17728,55 +18363,58 @@ msgid "PackageRegistry|composer.json require package include"
msgstr ""
msgid "PackageRegistry|npm command"
-msgstr ""
+msgstr "npm-kommando"
msgid "PackageRegistry|published by %{author}"
-msgstr ""
+msgstr "publisert av %{author}"
msgid "PackageRegistry|yarn command"
-msgstr ""
+msgstr "yarn-kommando"
msgid "PackageType|Composer"
-msgstr ""
+msgstr "Composer"
msgid "PackageType|Conan"
-msgstr ""
+msgstr "Conan"
msgid "PackageType|Maven"
-msgstr ""
+msgstr "Maven"
msgid "PackageType|NPM"
-msgstr ""
+msgstr "NPM"
msgid "PackageType|NuGet"
-msgstr ""
+msgstr "NuGet"
msgid "PackageType|PyPi"
-msgstr ""
+msgstr "PyPi"
msgid "Packages"
-msgstr ""
+msgstr "Pakker"
msgid "Packages & Registries"
-msgstr ""
+msgstr "Pakker og registre"
msgid "Page not found"
+msgstr "Siden ble ikke funnet"
+
+msgid "Page settings"
msgstr ""
msgid "Page was successfully deleted"
-msgstr ""
+msgstr "Siden ble vellykket slettet"
msgid "PagerDutySettings|Active"
-msgstr ""
+msgstr "Aktiv"
msgid "PagerDutySettings|Create a GitLab issue for each PagerDuty incident by %{docsLink}"
msgstr ""
msgid "PagerDutySettings|Failed to update Webhook URL"
-msgstr ""
+msgstr "Mislyktes i å oppdatere Webhook-URL-en"
msgid "PagerDutySettings|Reset webhook URL"
-msgstr ""
+msgstr "Tilbakestill Webhook-URL-en"
msgid "PagerDutySettings|Resetting the webhook URL for this project will require updating this integration's settings in PagerDuty."
msgstr ""
@@ -17785,16 +18423,16 @@ msgid "PagerDutySettings|Setting up a webhook with PagerDuty will automatically
msgstr ""
msgid "PagerDutySettings|Webhook URL"
-msgstr ""
+msgstr "Webhook-URL"
msgid "PagerDutySettings|Webhook URL update was successful"
-msgstr ""
+msgstr "Webhook-URL-oppdateringen var vellykket"
msgid "PagerDutySettings|configuring a webhook in PagerDuty"
msgstr ""
msgid "Pages"
-msgstr ""
+msgstr "Sider"
msgid "Pages Domain"
msgstr ""
@@ -17803,37 +18441,37 @@ msgid "Pages getting started guide"
msgstr ""
msgid "Pagination|Go to first page"
-msgstr ""
+msgstr "Gå til første side"
msgid "Pagination|Go to last page"
-msgstr ""
+msgstr "GÃ¥ til siste side"
msgid "Pagination|Go to next page"
-msgstr ""
+msgstr "GÃ¥ til neste side"
msgid "Pagination|Go to previous page"
-msgstr ""
+msgstr "GÃ¥ til forrige side"
msgid "Pagination|Last »"
-msgstr ""
+msgstr "Siste »"
msgid "Pagination|Next"
-msgstr ""
+msgstr "Neste"
msgid "Pagination|Prev"
-msgstr ""
+msgstr "Forrige"
msgid "Pagination|« First"
-msgstr ""
+msgstr "« Første"
msgid "Parameter"
-msgstr ""
+msgstr "Parameter"
msgid "Parameter \"job_id\" cannot exceed length of %{job_id_max_size}"
msgstr ""
msgid "Parent"
-msgstr ""
+msgstr "Parent"
msgid "Parent epic doesn't exist."
msgstr ""
@@ -17851,40 +18489,40 @@ msgid "Partial token for reference only"
msgstr ""
msgid "Participants"
-msgstr ""
+msgstr "Deltakere"
msgid "Passed"
-msgstr ""
+msgstr "Bestått"
msgid "Passed on"
msgstr ""
msgid "Password"
-msgstr ""
+msgstr "Passord"
msgid "Password (optional)"
-msgstr ""
+msgstr "Passord (frivillig)"
msgid "Password Policy Guidelines"
msgstr ""
msgid "Password authentication is unavailable."
-msgstr ""
+msgstr "Passordautentisering er utilgjengelig."
msgid "Password confirmation"
-msgstr ""
+msgstr "Passordbekreftelse"
msgid "Password successfully changed"
-msgstr ""
+msgstr "Passordet ditt ble endret"
msgid "Password was successfully updated. Please sign in again."
-msgstr ""
+msgstr "Passordet ble vellykket oppdatert. Vennligst logg inn på nytt."
msgid "Passwords should be unique and not used for any other sites or services."
msgstr ""
msgid "Past due"
-msgstr ""
+msgstr "Forbi måldatoen"
msgid "Paste a machine public key here. Read more about how to generate it"
msgstr ""
@@ -17893,34 +18531,34 @@ msgid "Paste a machine public key here. Read more about how to generate it %{lin
msgstr ""
msgid "Paste confidential epic link"
-msgstr ""
+msgstr "Lim inn lenke til konfidensiell epos"
msgid "Paste confidential issue link"
msgstr ""
msgid "Paste epic link"
-msgstr ""
+msgstr "Lim inn epos-lenke"
msgid "Paste issue link"
msgstr ""
-msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Don't use your private SSH key."
+msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Do not paste your private SSH key, as that can compromise your identity."
msgstr ""
msgid "Patch to apply"
msgstr ""
msgid "Path"
-msgstr ""
+msgstr "Sti"
msgid "Path:"
-msgstr ""
+msgstr "Filbane:"
msgid "Paths can contain wildcards, like */welcome"
msgstr ""
msgid "Pause"
-msgstr ""
+msgstr "Pause"
msgid "Pause replication"
msgstr ""
@@ -17929,6 +18567,9 @@ msgid "Paused Runners don't accept new jobs"
msgstr ""
msgid "Pending"
+msgstr "I kø"
+
+msgid "Pending comments"
msgstr ""
msgid "People without permission will never get a notification and won't be able to comment."
@@ -17938,10 +18579,10 @@ msgid "People without permission will never get a notification."
msgstr ""
msgid "Percent of users"
-msgstr ""
+msgstr "Prosent av brukere"
msgid "Percentage"
-msgstr ""
+msgstr "Prosent"
msgid "Perform advanced options such as changing path, transferring, exporting, or removing the group."
msgstr ""
@@ -17953,13 +18594,13 @@ msgid "Performance and resource management"
msgstr ""
msgid "Performance optimization"
-msgstr ""
+msgstr "Optimalisering av ytelsen"
msgid "PerformanceBar|Bullet notifications"
msgstr ""
msgid "PerformanceBar|Download"
-msgstr ""
+msgstr "Last ned"
msgid "PerformanceBar|Elasticsearch calls"
msgstr ""
@@ -17977,22 +18618,22 @@ msgid "PerformanceBar|Rugged calls"
msgstr ""
msgid "PerformanceBar|SQL queries"
-msgstr ""
+msgstr "SQL-forespørsler"
msgid "PerformanceBar|trace"
msgstr ""
msgid "Permissions"
-msgstr ""
+msgstr "Tillatelser"
msgid "Permissions Help"
-msgstr ""
+msgstr "Hjelp for tillatelser"
msgid "Permissions, LFS, 2FA"
-msgstr ""
+msgstr "Tillatelser, LFS, 2FA"
msgid "Personal Access Token"
-msgstr ""
+msgstr "Personlige tilgangsnøkkel"
msgid "Personal project creation is not allowed. Please contact your administrator with questions"
msgstr ""
@@ -18007,16 +18648,16 @@ msgid "Phabricator Tasks"
msgstr ""
msgid "Pick a name"
-msgstr ""
+msgstr "Velg et navn"
msgid "Pin code"
-msgstr ""
+msgstr "PIN-kode"
msgid "Pipeline"
-msgstr ""
+msgstr "Rørledning"
msgid "Pipeline %{label}"
-msgstr ""
+msgstr "Rørledning %{label}"
msgid "Pipeline %{label} for \"%{dataTitle}\""
msgstr ""
@@ -18031,52 +18672,52 @@ msgid "Pipeline minutes quota"
msgstr ""
msgid "Pipeline subscriptions"
-msgstr ""
+msgstr "Rørledningsabonnementer"
msgid "Pipeline triggers"
msgstr ""
msgid "Pipeline: %{status}"
-msgstr ""
+msgstr "Rørledning: %{status}"
msgid "PipelineCharts|CI / CD Analytics"
msgstr ""
msgid "PipelineCharts|Failed:"
-msgstr ""
+msgstr "Mislyktes:"
msgid "PipelineCharts|Overall statistics"
msgstr ""
msgid "PipelineCharts|Success ratio:"
-msgstr ""
+msgstr "Suksessfrekvens:"
msgid "PipelineCharts|Successful:"
-msgstr ""
+msgstr "Vellykket:"
msgid "PipelineCharts|Total:"
-msgstr ""
+msgstr "Totalt:"
msgid "PipelineScheduleIntervalPattern|Custom (%{linkStart}Cron syntax%{linkEnd})"
msgstr ""
msgid "PipelineSchedules|Activated"
-msgstr ""
+msgstr "Aktivert"
msgid "PipelineSchedules|Active"
-msgstr ""
+msgstr "Aktiv"
msgid "PipelineSchedules|All"
-msgstr ""
+msgstr "Alle"
msgid "PipelineSchedules|Inactive"
-msgstr ""
+msgstr "Inaktive"
msgid "PipelineSchedules|Next Run"
-msgstr ""
+msgstr "Neste kjøring"
msgid "PipelineSchedules|None"
-msgstr ""
+msgstr "Ingen"
msgid "PipelineSchedules|Provide a short description for this pipeline"
msgstr ""
@@ -18085,43 +18726,43 @@ msgid "PipelineSchedules|Take ownership"
msgstr ""
msgid "PipelineSchedules|Target"
-msgstr ""
+msgstr "MÃ¥l"
msgid "PipelineSchedules|Variables"
-msgstr ""
+msgstr "Variabler"
msgid "PipelineStatusTooltip|Pipeline: %{ciStatus}"
-msgstr ""
+msgstr "Rørledning: %{ciStatus}"
msgid "PipelineStatusTooltip|Pipeline: %{ci_status}"
-msgstr ""
+msgstr "Rørledning: %{ci_status}"
msgid "Pipelines"
-msgstr ""
+msgstr "Rørledninger"
msgid "Pipelines charts"
-msgstr ""
+msgstr "Rørledningsdiagrammer"
msgid "Pipelines emails"
-msgstr ""
+msgstr "Rørlednings-E-poster"
msgid "Pipelines for last month (%{oneMonthAgo} - %{today})"
-msgstr ""
+msgstr "Rørledninger den siste måneden (%{oneMonthAgo} - %{today})"
msgid "Pipelines for last week (%{oneWeekAgo} - %{today})"
-msgstr ""
+msgstr "Rørledninger den siste uken (%{oneWeekAgo} - %{today})"
msgid "Pipelines for last year"
-msgstr ""
+msgstr "Rørledninger det siste året"
msgid "Pipelines for merge requests are configured. A detached pipeline runs in the context of the merge request, and not against the merged result. Learn more in the documentation for Pipelines for Merged Results."
-msgstr ""
+msgstr "Rørledninger for fletteforespørsler er konfigurert. En frakoblet rørledning kjører i sammenheng med fletteforespørselen, og ikke mot det innflettede resultatet. Lær mer i dokumentasjonen for rørledninger for innflettede resultater."
msgid "Pipelines settings for '%{project_name}' were successfully updated."
msgstr ""
msgid "Pipelines|API"
-msgstr ""
+msgstr "API"
msgid "Pipelines|Are you sure you want to run this pipeline?"
msgstr ""
@@ -18129,9 +18770,12 @@ msgstr ""
msgid "Pipelines|Build with confidence"
msgstr ""
-msgid "Pipelines|CI Lint"
+msgid "Pipelines|By revoking a trigger you will break any processes making use of it. Are you sure?"
msgstr ""
+msgid "Pipelines|CI Lint"
+msgstr "CI Lint"
+
msgid "Pipelines|Child pipeline"
msgstr ""
@@ -18141,6 +18785,15 @@ msgstr ""
msgid "Pipelines|Continuous Integration can help catch bugs by running your tests automatically, while Continuous Deployment can help you deliver code to your product environment."
msgstr ""
+msgid "Pipelines|Copy trigger token"
+msgstr ""
+
+msgid "Pipelines|Description"
+msgstr ""
+
+msgid "Pipelines|Edit"
+msgstr ""
+
msgid "Pipelines|Get started with Pipelines"
msgstr ""
@@ -18156,18 +18809,30 @@ msgstr ""
msgid "Pipelines|It is recommended the code is reviewed thoroughly before running this pipeline with the parent project's CI resource."
msgstr ""
+msgid "Pipelines|Last Used"
+msgstr ""
+
msgid "Pipelines|Loading Pipelines"
msgstr ""
msgid "Pipelines|More Information"
+msgstr "Mer informasjon"
+
+msgid "Pipelines|No triggers have been created yet. Add one using the form above."
+msgstr ""
+
+msgid "Pipelines|Owner"
msgstr ""
msgid "Pipelines|Project cache successfully reset."
msgstr ""
-msgid "Pipelines|Run Pipeline"
+msgid "Pipelines|Revoke"
msgstr ""
+msgid "Pipelines|Run Pipeline"
+msgstr "Kjør rørledning"
+
msgid "Pipelines|Something went wrong while cleaning runners cache."
msgstr ""
@@ -18175,7 +18840,7 @@ msgid "Pipelines|There are currently no finished pipelines."
msgstr ""
msgid "Pipelines|There are currently no pipelines."
-msgstr ""
+msgstr "Det er ingen rørledninger for øyeblikket."
msgid "Pipelines|There was an error fetching the pipelines. Try again in a few moments or contact your support team."
msgstr ""
@@ -18189,50 +18854,59 @@ msgstr ""
msgid "Pipelines|This project is not currently set up to run pipelines."
msgstr ""
+msgid "Pipelines|Token"
+msgstr ""
+
+msgid "Pipelines|Trigger user has insufficient permissions to project"
+msgstr ""
+
+msgid "Pipelines|invalid"
+msgstr ""
+
msgid "Pipelines|parent"
msgstr ""
msgid "Pipeline|Branch name"
-msgstr ""
+msgstr "Grennavn"
msgid "Pipeline|Canceled"
-msgstr ""
+msgstr "Avbrutt"
msgid "Pipeline|Checking pipeline status."
-msgstr ""
+msgstr "Sjekker rørledningsstatusen."
msgid "Pipeline|Commit"
-msgstr ""
+msgstr "Commit"
msgid "Pipeline|Could not retrieve the pipeline status. For troubleshooting steps, read the %{linkStart}documentation%{linkEnd}."
msgstr ""
msgid "Pipeline|Coverage"
-msgstr ""
+msgstr "Dekning"
msgid "Pipeline|Created"
-msgstr ""
+msgstr "Opprettet"
msgid "Pipeline|Date"
-msgstr ""
+msgstr "Dato"
msgid "Pipeline|Detached merge request pipeline"
msgstr ""
msgid "Pipeline|Duration"
-msgstr ""
+msgstr "Varighet"
msgid "Pipeline|Existing branch name or tag"
-msgstr ""
+msgstr "Eksisterende grennavn eller etikett"
msgid "Pipeline|Failed"
-msgstr ""
+msgstr "Mislyktes"
msgid "Pipeline|Key"
-msgstr ""
+msgstr "Nøkkel"
msgid "Pipeline|Manual"
-msgstr ""
+msgstr "Manuelt"
msgid "Pipeline|Merge train pipeline"
msgstr ""
@@ -18241,34 +18915,34 @@ msgid "Pipeline|Merged result pipeline"
msgstr ""
msgid "Pipeline|Passed"
-msgstr ""
+msgstr "Bestått"
msgid "Pipeline|Pending"
-msgstr ""
+msgstr "Avventer"
msgid "Pipeline|Pipeline"
-msgstr ""
+msgstr "Rørledning"
msgid "Pipeline|Pipelines"
-msgstr ""
+msgstr "Rørledninger"
msgid "Pipeline|Raw text search is not currently supported. Please use the available search tokens."
msgstr ""
msgid "Pipeline|Run Pipeline"
-msgstr ""
+msgstr "Kjør rørledning"
msgid "Pipeline|Run for"
msgstr ""
msgid "Pipeline|Running"
-msgstr ""
+msgstr "Kjører"
msgid "Pipeline|Search branches"
msgstr ""
msgid "Pipeline|Skipped"
-msgstr ""
+msgstr "Hoppet over"
msgid "Pipeline|Specify variable values to be used in this run. The values specified in %{linkStart}CI/CD settings%{linkEnd} will be used by default."
msgstr ""
@@ -18277,19 +18951,19 @@ msgid "Pipeline|Specify variable values to be used in this run. The values speci
msgstr ""
msgid "Pipeline|Stages"
-msgstr ""
+msgstr "Trinn"
msgid "Pipeline|Status"
-msgstr ""
+msgstr "Status"
msgid "Pipeline|Stop pipeline"
-msgstr ""
+msgstr "Stopp rørledning"
msgid "Pipeline|Stop pipeline #%{pipelineId}?"
msgstr ""
msgid "Pipeline|Tag name"
-msgstr ""
+msgstr "Etikettnavn"
msgid "Pipeline|Trigger author"
msgstr ""
@@ -18298,25 +18972,25 @@ msgid "Pipeline|Triggerer"
msgstr ""
msgid "Pipeline|Value"
-msgstr ""
+msgstr "Verdi"
msgid "Pipeline|Variables"
-msgstr ""
+msgstr "Variabler"
msgid "Pipeline|You’re about to stop pipeline %{pipelineId}."
msgstr ""
msgid "Pipeline|for"
-msgstr ""
+msgstr "for"
msgid "Pipeline|on"
-msgstr ""
+msgstr "den"
msgid "Pipeline|with stage"
-msgstr ""
+msgstr "med trinn"
msgid "Pipeline|with stages"
-msgstr ""
+msgstr "med trinn"
msgid "PivotalTrackerService|Comma-separated list of branches which will be automatically inspected. Leave blank to include all branches."
msgstr ""
@@ -18331,22 +19005,22 @@ msgid "Plain diff"
msgstr ""
msgid "Plan"
-msgstr ""
+msgstr "Plan"
msgid "Plan:"
-msgstr ""
+msgstr "Plan:"
msgid "PlantUML"
-msgstr ""
+msgstr "PlantUML"
msgid "Play"
-msgstr ""
+msgstr "Spill av"
msgid "Play all manual"
msgstr ""
msgid "Please %{link_to_register} or %{link_to_sign_in} to comment"
-msgstr ""
+msgstr "Vennligst %{link_to_register} eller %{link_to_sign_in} for å kommentere"
msgid "Please %{startTagRegister}register%{endRegisterTag} or %{startTagSignIn}sign in%{endSignInTag} to reply"
msgstr ""
@@ -18373,7 +19047,7 @@ msgid "Please check your email (%{email}) to verify that you own this address an
msgstr ""
msgid "Please choose a file"
-msgstr ""
+msgstr "Vennligst velg en fil"
msgid "Please choose a group URL with no special characters."
msgstr ""
@@ -18382,10 +19056,10 @@ msgid "Please complete your profile with email address"
msgstr ""
msgid "Please contact your administrator with any questions."
-msgstr ""
+msgstr "Vennligst kontakt administratoren din med eventuelle spørsmål."
msgid "Please contact your administrator."
-msgstr ""
+msgstr "Ta kontakt med administratoren."
msgid "Please convert %{linkStart}them to Git%{linkEnd}, and go through the %{linkToImportFlow} again."
msgstr ""
@@ -18394,10 +19068,10 @@ msgid "Please convert them to Git on Google Code, and go through the %{link_to_i
msgstr ""
msgid "Please create a password for your new account."
-msgstr ""
+msgstr "Vennligst skriv inn et passord for din nye konto."
msgid "Please create a username with only alphanumeric characters."
-msgstr ""
+msgstr "Vennligst lag et brukernavn med kun alfanumeriske tegn."
msgid "Please create an index before enabling indexing"
msgstr ""
@@ -18409,19 +19083,19 @@ msgid "Please ensure your account's %{account_link_start}recovery settings%{acco
msgstr ""
msgid "Please enter a non-negative number"
-msgstr ""
+msgstr "Vennligst skriv inn et nummer som ikke er negativt"
msgid "Please enter a number greater than %{number} (from the project settings)"
msgstr ""
msgid "Please enter a valid number"
-msgstr ""
+msgstr "Vennligst skriv inn et gyldig nummer"
msgid "Please enter or upload a license."
-msgstr ""
+msgstr "Vennligst skriv inn eller last opp en lisens."
msgid "Please fill in a descriptive name for your group."
-msgstr ""
+msgstr "Vennligst skriv inn et beskrivende navn på gruppen din."
msgid "Please follow the %{link_start}Let's Encrypt troubleshooting instructions%{link_end} to re-obtain your Let's Encrypt certificate."
msgstr ""
@@ -18436,85 +19110,88 @@ msgid "Please note that this application is not provided by GitLab and you shoul
msgstr ""
msgid "Please provide a name"
-msgstr ""
+msgstr "Vennligst angi et navn"
msgid "Please provide a valid URL"
-msgstr ""
+msgstr "Vennligst skriv inn en gyldig URL"
msgid "Please provide a valid email address."
-msgstr ""
+msgstr "Vennligst oppgi en gyldig e-postadresse."
msgid "Please provide attributes to update"
msgstr ""
-msgid "Please refer to %{docs_url}"
+msgid "Please reach out if you have any questions and we'll be happy to assist."
msgstr ""
-msgid "Please retype the email address."
+msgid "Please refer to %{docs_url}"
msgstr ""
msgid "Please select"
-msgstr ""
+msgstr "Vennligst velg"
msgid "Please select a Jira project"
-msgstr ""
+msgstr "Vennligst velg et Jira-prosjekt"
msgid "Please select a country"
-msgstr ""
+msgstr "Vennligst velg et land"
msgid "Please select a file"
-msgstr ""
+msgstr "Vennligst velg en fil"
msgid "Please select a group."
-msgstr ""
+msgstr "Vennligst velg en gruppe."
msgid "Please select a valid target branch"
-msgstr ""
+msgstr "Vennligst velg en gyldig målgren"
msgid "Please select and add a member"
-msgstr ""
+msgstr "Vennligst velg og legg til et medlem"
msgid "Please select at least one filter to see results"
-msgstr ""
+msgstr "Vennligst velg minst ett filter for å se resultatene"
msgid "Please set a new password before proceeding."
+msgstr "Vennligst velg et nytt passord før du fortsetter."
+
+msgid "Please share your feedback about %{featureName} %{linkStart}in this issue%{linkEnd} to help us improve the experience."
msgstr ""
msgid "Please solve the reCAPTCHA"
-msgstr ""
+msgstr "Vennligst løs reCAPTCHA"
msgid "Please try again"
-msgstr ""
+msgstr "Vennligst prøv igjen"
msgid "Please type %{phrase_code} to proceed or close this modal to cancel."
msgstr ""
msgid "Please type the following to confirm:"
-msgstr ""
+msgstr "Vennligst skriv inn det følgende for å bekrefte:"
msgid "Please use this form to report to the admin users who create spam issues, comments or behave inappropriately."
msgstr ""
msgid "Please wait a moment, this page will automatically refresh when ready."
-msgstr ""
+msgstr "Vennligst vent et øyeblikk, denne siden vil automatisk oppfriskes når det er klart."
msgid "Please wait while we connect to your repository. Refresh at will."
-msgstr ""
+msgstr "Vennligst vent mens vi kobler til kodelageret ditt. Oppdater når du vil."
msgid "Please wait while we import the repository for you. Refresh at will."
-msgstr ""
+msgstr "Vennligst vent mens vi importerer kodelageret ditt. Oppdater når du vil."
msgid "Plugins directory is deprecated and will be removed in 14.0. Please move this file into /file_hooks directory."
msgstr ""
msgid "Pod does not exist"
-msgstr ""
+msgstr "Podden finnes ikke"
msgid "Pod not found"
-msgstr ""
+msgstr "Podden ble ikke funnet"
msgid "Pods in use"
-msgstr ""
+msgstr "Podder som brukes"
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. Duplicate URLs are not allowed."
msgstr ""
@@ -18523,55 +19200,55 @@ msgid "Pre-defined push rules."
msgstr ""
msgid "Preferences"
-msgstr ""
+msgstr "Innstillinger"
msgid "Preferences saved."
-msgstr ""
+msgstr "Innstillingene ble lagret."
msgid "Preferences|Behavior"
-msgstr ""
+msgstr "Oppførsel"
msgid "Preferences|Choose between fixed (max. 1280px) and fluid (%{percentage}) application layout."
-msgstr ""
+msgstr "Velg mellom fastsatt (maks 1280px) og flytende (%{percentage}) applikasjonsutseende."
msgid "Preferences|Choose what content you want to see on a project’s overview page."
-msgstr ""
+msgstr "Velg hvilket innhold du vil se på et prosjekts oversiktsside."
msgid "Preferences|Choose what content you want to see on your homepage."
-msgstr ""
+msgstr "Velg hva slags innhold du vil se på hjemmesiden din."
msgid "Preferences|Customize integrations with third party services."
-msgstr ""
+msgstr "Tilpass integreringer med tredjepartstjenester."
msgid "Preferences|Customize the appearance of the application header and navigation sidebar."
-msgstr ""
+msgstr "Tilpass utseende til applikasjons-toppområdet og navigasjonssidelinjen."
msgid "Preferences|Display time in 24-hour format"
-msgstr ""
+msgstr "Vis tid i 24-timersformat"
msgid "Preferences|Enable integrated code intelligence on code views"
msgstr ""
msgid "Preferences|For example: 30 mins ago."
-msgstr ""
+msgstr "For eksempel: 30min siden."
msgid "Preferences|Homepage content"
-msgstr ""
+msgstr "Hjemmesideinnhold"
msgid "Preferences|Instead of all the files changed, show only one file at a time. To switch between files, use the file browser."
msgstr ""
msgid "Preferences|Integrations"
-msgstr ""
+msgstr "Integreringer"
msgid "Preferences|Layout width"
-msgstr ""
+msgstr "Utformingsbredde"
msgid "Preferences|Must be a number between %{min} and %{max}"
-msgstr ""
+msgstr "Må være et nummer mellom %{min} og %{max}"
msgid "Preferences|Navigation theme"
-msgstr ""
+msgstr "Navigasjonstema"
msgid "Preferences|Project overview content"
msgstr ""
@@ -18586,43 +19263,43 @@ msgid "Preferences|Show whitespace changes in diffs"
msgstr ""
msgid "Preferences|Sourcegraph"
-msgstr ""
+msgstr "Sourcegraph"
msgid "Preferences|Syntax highlighting theme"
-msgstr ""
+msgstr "Syntaksfremhevingstema"
msgid "Preferences|Tab width"
-msgstr ""
+msgstr "Fanebredde"
msgid "Preferences|These settings will update how dates and times are displayed for you."
-msgstr ""
+msgstr "Disse innstillingene vil oppdatere hvordan datoer og tidspunkter vises for deg."
msgid "Preferences|This feature is experimental and translations are not complete yet"
-msgstr ""
+msgstr "Denne funksjonen er eksperimentell, og oversettelser er ikke fullførte enda"
msgid "Preferences|This setting allows you to customize the appearance of the syntax."
-msgstr ""
+msgstr "Denne innstillingen lar deg tilpasse utseendet til syntaksen."
msgid "Preferences|This setting allows you to customize the behavior of the system layout and default views."
-msgstr ""
+msgstr "Denne innstillingen lar deg tilpasse oppførselen til systemoppsettet og standardvisningene."
msgid "Preferences|Time display"
-msgstr ""
+msgstr "Tidsvisning"
msgid "Preferences|Time format"
-msgstr ""
+msgstr "Tidsformat"
msgid "Preferences|Time preferences"
-msgstr ""
+msgstr "Tidspreferanser"
msgid "Preferences|Use relative times"
-msgstr ""
+msgstr "Bruk relative tidspunkter"
msgid "Press %{key}-C to copy"
-msgstr ""
+msgstr "Trykk %{key}-C for å kopiere"
msgid "Prev"
-msgstr ""
+msgstr "Forrige"
msgid "Prevent adding new members to project membership within this group"
msgstr ""
@@ -18649,46 +19326,46 @@ msgid "Prevent users from performing write operations on GitLab while performing
msgstr ""
msgid "Preview"
-msgstr ""
+msgstr "Forhåndsvisning"
msgid "Preview Markdown"
-msgstr ""
+msgstr "Forhåndsvis Markdown"
msgid "Preview changes"
-msgstr ""
+msgstr "Forhåndsvis endringer"
msgid "Preview payload"
msgstr ""
msgid "Previous Artifacts"
-msgstr ""
+msgstr "Tidligere artefakter"
msgid "Previous commit"
-msgstr ""
+msgstr "Forrige commit"
msgid "Previous file in diff"
msgstr ""
msgid "Previous unresolved discussion"
-msgstr ""
+msgstr "Forrige uoppklarte diskusjon"
msgid "Primary"
-msgstr ""
+msgstr "Primær"
msgid "Prioritize"
-msgstr ""
+msgstr "Prioriter"
msgid "Prioritize label"
-msgstr ""
+msgstr "Prioriter etikett"
msgid "Prioritized Labels"
-msgstr ""
+msgstr "Prioriterte etiketter"
msgid "Prioritized label"
-msgstr ""
+msgstr "Prioritert etikett"
msgid "Private"
-msgstr ""
+msgstr "Privat"
msgid "Private - Project access must be granted explicitly to each user. If this project is part of a group, access will be granted to members of the group."
msgstr ""
@@ -18697,10 +19374,10 @@ msgid "Private - The group and its projects can only be viewed by members."
msgstr ""
msgid "Private group(s)"
-msgstr ""
+msgstr "Privat(e) gruppe(r)"
msgid "Private profile"
-msgstr ""
+msgstr "Privatprofil"
msgid "Private projects Minutes cost factor"
msgstr ""
@@ -18709,7 +19386,7 @@ msgid "Private projects can be created in your personal namespace with:"
msgstr ""
msgid "Proceed"
-msgstr ""
+msgstr "Fortsett"
msgid "Product Analytics"
msgstr ""
@@ -18718,10 +19395,10 @@ msgid "ProductAnalytics|There is no data for this type of chart currently. Pleas
msgstr ""
msgid "Productivity"
-msgstr ""
+msgstr "Produktivitet"
msgid "Productivity Analytics"
-msgstr ""
+msgstr "Produktivitetsanalyse"
msgid "Productivity analytics can help identify the problems that are delaying your team"
msgstr ""
@@ -18733,31 +19410,31 @@ msgid "ProductivityAanalytics|is earlier than the allowed minimum date"
msgstr ""
msgid "ProductivityAnalytics|Ascending"
-msgstr ""
+msgstr "Stigende"
msgid "ProductivityAnalytics|Days"
-msgstr ""
+msgstr "Dager"
msgid "ProductivityAnalytics|Days to merge"
-msgstr ""
+msgstr "Dager til innfletting"
msgid "ProductivityAnalytics|Descending"
-msgstr ""
+msgstr "Synkende"
msgid "ProductivityAnalytics|Hours"
-msgstr ""
+msgstr "Timer"
msgid "ProductivityAnalytics|List"
msgstr ""
msgid "ProductivityAnalytics|Merge Requests"
-msgstr ""
+msgstr "Fletteforespørsler"
msgid "ProductivityAnalytics|Merge date"
msgstr ""
msgid "ProductivityAnalytics|Merge requests"
-msgstr ""
+msgstr "Fletteforespørsler"
msgid "ProductivityAnalytics|Time to merge"
msgstr ""
@@ -18769,22 +19446,25 @@ msgid "ProductivityAnalytics|is earlier than the given merged at after date"
msgstr ""
msgid "Profile"
-msgstr ""
+msgstr "Profil"
msgid "Profile Settings"
-msgstr ""
+msgstr "Profilinnstillinger"
msgid "ProfileSession|on"
-msgstr ""
+msgstr "den"
msgid "Profiles| You are about to permanently delete %{yourAccount}, and all of the issues, merge requests, and groups linked to your account. Once you confirm %{deleteAccount}, it cannot be undone or recovered."
-msgstr ""
+msgstr "Du er i ferd med å slette %{yourAccount} permanent, og alle sakene, fletteforespørslene og gruppene som er knyttet til kontoen din. Når du har bekreftet %{deleteAccount}, kan den ikke angres på eller gjenopprettes."
msgid "Profiles| You are going to change the username %{currentUsernameBold} to %{newUsernameBold}. Profile and projects will be redirected to the %{newUsername} namespace but this redirect will expire once the %{currentUsername} namespace is registered by another user or group. Please update your Git repository remotes as soon as possible."
+msgstr "Du er i ferd med å endre brukernavnet %{currentUsernameBold} til %{newUsernameBold}. Profilen og prosjektene blir omdirigert til %{newUsername}-navnefeltet, men denne viderekoblingen utløper når %{currentUsername}-navnene har blitt registrert av en annen bruker eller gruppe. Oppdater Git-kodelagerfjernkontrollene dine så snart som mulig."
+
+msgid "Profiles|%{provider} Active"
msgstr ""
msgid "Profiles|@username"
-msgstr ""
+msgstr "@brukernavn"
msgid "Profiles|Account scheduled for removal."
msgstr ""
@@ -18793,96 +19473,99 @@ msgid "Profiles|Activate signin with one of the following services"
msgstr ""
msgid "Profiles|Active"
-msgstr ""
+msgstr "Aktiv"
msgid "Profiles|Add key"
-msgstr ""
+msgstr "Legg til nøkkel"
msgid "Profiles|Add status emoji"
-msgstr ""
+msgstr "Legg til status emoji"
msgid "Profiles|Avatar cropper"
-msgstr ""
+msgstr "Avatarbeskjærer"
msgid "Profiles|Avatar will be removed. Are you sure?"
-msgstr ""
+msgstr "Avataren vil blir fjernet. Er du sikker?"
msgid "Profiles|Bio"
-msgstr ""
+msgstr "Profil"
msgid "Profiles|Change username"
-msgstr ""
+msgstr "Endre brukernavn"
msgid "Profiles|Changing your username can have unintended side effects."
msgstr ""
msgid "Profiles|Choose file..."
-msgstr ""
+msgstr "Velg fil..."
msgid "Profiles|Choose to show contributions of private projects on your public profile without any project, repository or organization information"
msgstr ""
msgid "Profiles|City, country"
-msgstr ""
+msgstr "By, land"
msgid "Profiles|Clear status"
-msgstr ""
+msgstr "Tøm status"
msgid "Profiles|Click on icon to activate signin with one of the following services"
msgstr ""
msgid "Profiles|Commit email"
-msgstr ""
+msgstr "Commit-E-post"
-msgid "Profiles|Connect"
+msgid "Profiles|Connect %{provider}"
msgstr ""
msgid "Profiles|Connected Accounts"
-msgstr ""
+msgstr "Tilkoblede kontoer"
msgid "Profiles|Current path: %{path}"
-msgstr ""
+msgstr "Nåværende bane: %{path}"
msgid "Profiles|Current status"
-msgstr ""
+msgstr "Gjeldende status"
msgid "Profiles|Default notification email"
-msgstr ""
+msgstr "Standard varslings-E-postadresse"
msgid "Profiles|Delete account"
-msgstr ""
+msgstr "Slett konto"
msgid "Profiles|Deleting an account has the following effects:"
-msgstr ""
+msgstr "Sletting av en konto har følgende konsekvenser:"
msgid "Profiles|Disconnect"
+msgstr "Koble fra"
+
+msgid "Profiles|Disconnect %{provider}"
msgstr ""
msgid "Profiles|Do not show on profile"
-msgstr ""
+msgstr "Vis ikke på profilen"
msgid "Profiles|Don't display activity-related personal information on your profiles"
-msgstr ""
+msgstr "Ikke vis aktivitetsrelatert personlig informasjon på dine profiler"
msgid "Profiles|Edit Profile"
-msgstr ""
+msgstr "Rediger profil"
msgid "Profiles|Enter your name, so people you know can recognize you"
msgstr ""
msgid "Profiles|Expires at"
-msgstr ""
+msgstr "Utløper den"
msgid "Profiles|Expires:"
-msgstr ""
+msgstr "Utløper:"
msgid "Profiles|Feed token was successfully reset"
msgstr ""
msgid "Profiles|Full name"
-msgstr ""
+msgstr "Fullt navn"
-msgid "Profiles|Give your individual key a title. This will be publically visible."
+msgid "Profiles|Give your individual key a title."
msgstr ""
msgid "Profiles|Include private contributions on my profile"
@@ -18895,67 +19578,67 @@ msgid "Profiles|Increase your account's security by enabling Two-Factor Authenti
msgstr ""
msgid "Profiles|Invalid password"
-msgstr ""
+msgstr "Ugyldig passord"
msgid "Profiles|Invalid username"
-msgstr ""
+msgstr "Ugyldig brukernavn"
msgid "Profiles|Key"
-msgstr ""
+msgstr "Nøkkel"
msgid "Profiles|Last used:"
-msgstr ""
+msgstr "Senest brukt:"
msgid "Profiles|Learn more"
-msgstr ""
+msgstr "Lær mer"
msgid "Profiles|Location"
-msgstr ""
+msgstr "Sted"
msgid "Profiles|Made a private contribution"
-msgstr ""
+msgstr "Lag et privat bidrag"
msgid "Profiles|Main settings"
-msgstr ""
+msgstr "Hovedinnstillinger"
msgid "Profiles|No file chosen"
-msgstr ""
+msgstr "Ingen fil valgt"
msgid "Profiles|Notification email"
-msgstr ""
+msgstr "Varsels-E-post"
msgid "Profiles|Organization"
-msgstr ""
+msgstr "Organisasjon"
msgid "Profiles|Path"
msgstr ""
msgid "Profiles|Position and size your new avatar"
-msgstr ""
+msgstr "Posisjoner og endre størrelsen på din nye avatar"
msgid "Profiles|Primary email"
-msgstr ""
+msgstr "Hoved-E-postadresse"
msgid "Profiles|Private contributions"
-msgstr ""
+msgstr "Private bidrag"
msgid "Profiles|Profile was successfully updated"
msgstr ""
msgid "Profiles|Public Avatar"
-msgstr ""
+msgstr "Offentlig avatar"
msgid "Profiles|Public email"
-msgstr ""
+msgstr "Offentlig e-post"
msgid "Profiles|Remove avatar"
-msgstr ""
+msgstr "Fjern avatar"
msgid "Profiles|Set new profile picture"
-msgstr ""
+msgstr "Velg nytt profilbilde"
msgid "Profiles|Social sign-in"
-msgstr ""
+msgstr "PÃ¥logging med sosiale medier"
msgid "Profiles|Some options are unavailable for LDAP accounts"
msgstr ""
@@ -18964,19 +19647,19 @@ msgid "Profiles|Static object token was successfully reset"
msgstr ""
msgid "Profiles|Tell us about yourself in fewer than 250 characters"
-msgstr ""
+msgstr "Fortell oss om deg selv med mindre enn 250 tegn"
msgid "Profiles|The ability to update your name has been disabled by your administrator."
-msgstr ""
+msgstr "Muligheten til å oppdatere navnet ditt har blitt skrudd av administratoren din."
msgid "Profiles|The maximum file size allowed is 200KB."
-msgstr ""
+msgstr "Den maks tillatte filstørrelsen er 200KB."
-msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it?"
+msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it? It will be publicly visible."
msgstr ""
msgid "Profiles|This email will be displayed on your public profile"
-msgstr ""
+msgstr "Denne e-postadressen vil bli vist på din offentlige profil"
msgid "Profiles|This email will be used for web based operations, such as edits and merges. %{commit_email_link_start}Learn more%{commit_email_link_end}"
msgstr ""
@@ -18988,31 +19671,31 @@ msgid "Profiles|This information will appear on your profile"
msgstr ""
msgid "Profiles|Time settings"
-msgstr ""
+msgstr "Tidsinnstillinger"
msgid "Profiles|Two-Factor Authentication"
-msgstr ""
+msgstr "2-trinnsautentisering"
msgid "Profiles|Type your %{confirmationValue} to confirm:"
-msgstr ""
+msgstr "Skriv inn din %{confirmationValue} for å bekrefte:"
msgid "Profiles|Typically starts with \"ssh-ed25519 …\" or \"ssh-rsa …\""
msgstr ""
msgid "Profiles|Update profile settings"
-msgstr ""
+msgstr "Oppdater profilinnstillinger"
msgid "Profiles|Update username"
-msgstr ""
+msgstr "Oppdater brukernavn"
msgid "Profiles|Upload new avatar"
-msgstr ""
+msgstr "Last opp ny avatar"
msgid "Profiles|Use a private email - %{email}"
-msgstr ""
+msgstr "Bruk en privat e-post - %{email}"
msgid "Profiles|User ID"
-msgstr ""
+msgstr "Bruker-ID"
msgid "Profiles|Username change failed - %{message}"
msgstr ""
@@ -19024,109 +19707,112 @@ msgid "Profiles|Using emojis in names seems fun, but please try to set a status
msgstr ""
msgid "Profiles|What's your status?"
-msgstr ""
+msgstr "Hva er statusen din?"
msgid "Profiles|Who you represent or work for"
-msgstr ""
+msgstr "Hvem du representerer eller jobber for"
msgid "Profiles|You can change your avatar here"
-msgstr ""
+msgstr "Du kan endre avataren din her"
msgid "Profiles|You can change your avatar here or remove the current avatar to revert to %{gravatar_link}"
-msgstr ""
+msgstr "Du kan endre avataren din her, eller fjerne gjeldende avatar for å gå tilbake til %{gravatar_link}"
msgid "Profiles|You can set your current timezone here"
-msgstr ""
+msgstr "Du kan velge din nåværende tidssone her"
msgid "Profiles|You can upload your avatar here"
-msgstr ""
+msgstr "Du kan laste opp avataren din her"
msgid "Profiles|You can upload your avatar here or change it at %{gravatar_link}"
-msgstr ""
+msgstr "Du kan laste opp avataren din her eller endre den på %{gravatar_link}"
msgid "Profiles|You don't have access to delete this user."
+msgstr "Du har ikke tilgang til å slette denne brukeren."
+
+msgid "Profiles|You must transfer ownership or delete groups you are an owner of before you can delete your account"
msgstr ""
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
-msgstr ""
+msgstr "Du må overføre eierskapet eller slette disse gruppene før du kan slette kontoen din."
msgid "Profiles|Your LinkedIn profile name from linkedin.com/in/profilename"
-msgstr ""
+msgstr "Ditt LinkedIn-profilnavn fra linkedin.com/in/profilename"
msgid "Profiles|Your account is currently an owner in these groups:"
-msgstr ""
+msgstr "Din konto er for øyeblikket eier i disse gruppene:"
msgid "Profiles|Your email address was automatically set based on your %{provider_label} account"
-msgstr ""
+msgstr "E-postadressen din ble automatisk satt, basert på din %{provider_label}-konto"
msgid "Profiles|Your key has expired"
-msgstr ""
+msgstr "Denne nøkkelen har utløpt"
msgid "Profiles|Your location was automatically set based on your %{provider_label} account"
-msgstr ""
+msgstr "Posisjonen din ble automatisk satt, basert på din %{provider_label}-konto"
msgid "Profiles|Your name was automatically set based on your %{provider_label} account, so people you know can recognize you"
-msgstr ""
+msgstr "Navnet ditt ble automatisk satt, basert på din %{provider_label}-konto, sånn at folk du kjenner kan kjenne deg igjen"
msgid "Profiles|Your status"
-msgstr ""
+msgstr "Din status"
msgid "Profiles|e.g. My MacBook key"
-msgstr ""
+msgstr "f.eks. Min MacBook-nøkkel"
msgid "Profiles|username"
-msgstr ""
+msgstr "brukernavn"
msgid "Profiles|website.com"
msgstr ""
msgid "Profiles|your account"
-msgstr ""
+msgstr "din konto"
msgid "Profile|%{job_title} at %{organization}"
-msgstr ""
+msgstr "%{job_title} hos %{organization}"
msgid "Profiling - Performance bar"
-msgstr ""
+msgstr "Profilering - Ytelseslinje"
msgid "Programming languages used in this repository"
-msgstr ""
+msgstr "Programmeringsspråk som brukes i dette kodelageret"
msgid "Progress"
-msgstr ""
+msgstr "Fremdrift"
msgid "Project"
-msgstr ""
+msgstr "Prosjekt"
msgid "Project \"%{name}\" is no longer available. Select another project to continue."
msgstr ""
msgid "Project %{project_repo} could not be found"
-msgstr ""
+msgstr "%{project_repo}-prosjektet ble ikke funnet"
msgid "Project & Group can not be assigned at the same time"
msgstr ""
msgid "Project '%{project_name}' is being imported."
-msgstr ""
+msgstr "'%{project_name}'-prosjektet blir importert."
msgid "Project '%{project_name}' is in the process of being deleted."
-msgstr ""
+msgstr "Prosjektet '%{project_name}' er i ferd med å bli slettet."
msgid "Project '%{project_name}' is restored."
-msgstr ""
+msgstr "'%{project_name}'-prosjektet blir gjenopprettet."
msgid "Project '%{project_name}' queued for deletion."
-msgstr ""
+msgstr "Prosjektet '%{project_name}' er i kø for å bli slettet."
msgid "Project '%{project_name}' was successfully created."
-msgstr ""
+msgstr "Prosjektet '%{project_name}\" ble vellykket opprettet."
msgid "Project '%{project_name}' was successfully updated."
-msgstr ""
+msgstr "Prosjektet '%{project_name}' ble vellykket oppdatert."
msgid "Project '%{project_name}' will be deleted on %{date}"
-msgstr ""
+msgstr "'%{project_name}'-prosjektet vil bli slettet den %{date}"
msgid "Project Access Tokens"
msgstr ""
@@ -19138,25 +19824,25 @@ msgid "Project Badges"
msgstr ""
msgid "Project Files"
-msgstr ""
+msgstr "Prosjektfiler"
msgid "Project ID"
-msgstr ""
+msgstr "Prosjekt-ID"
msgid "Project URL"
-msgstr ""
+msgstr "Prosjekt URL"
msgid "Project access must be granted explicitly to each user. If this project is part of a group, access will be granted to members of the group."
msgstr ""
msgid "Project already deleted"
-msgstr ""
+msgstr "Prosjektet er allerede slettet"
msgid "Project and wiki repositories"
-msgstr ""
+msgstr "Prosjekt- og wikikodelagre"
msgid "Project avatar"
-msgstr ""
+msgstr "Prosjekt avatar"
msgid "Project cannot be shared with the group it is in or one of its ancestors."
msgstr ""
@@ -19168,22 +19854,22 @@ msgid "Project configuration, excluding integrations"
msgstr ""
msgid "Project description (optional)"
-msgstr ""
+msgstr "Prosjektbeskrivelse (valgfritt)"
msgid "Project details"
-msgstr ""
+msgstr "Prosjektdetaljer"
msgid "Project does not exist or you don't have permission to perform this action"
msgstr ""
msgid "Project export could not be deleted."
-msgstr ""
+msgstr "Prosjekteksporteringen kunne ikke slettes."
msgid "Project export enabled"
-msgstr ""
+msgstr "Prosjekteksport skrudd på"
msgid "Project export has been deleted."
-msgstr ""
+msgstr "Prosjekteksport har blitt slettet."
msgid "Project export link has expired. Please generate a new export from your project settings."
msgstr ""
@@ -19192,22 +19878,22 @@ msgid "Project export started. A download link will be sent by email and made av
msgstr ""
msgid "Project has too many %{label_for_message} to search"
-msgstr ""
+msgstr "Prosjektet har for mange %{label_for_message} til å søkes i"
msgid "Project info:"
-msgstr ""
+msgstr "Prosjektinfo:"
msgid "Project is required when cluster_type is :project"
msgstr ""
msgid "Project members"
-msgstr ""
+msgstr "Prosjektmedlemmer"
msgid "Project milestone"
-msgstr ""
+msgstr "Prosjektmilepæl"
msgid "Project name"
-msgstr ""
+msgstr "Prosjektets navn"
msgid "Project name suffix"
msgstr ""
@@ -19219,16 +19905,16 @@ msgid "Project order will not be saved as local storage is not available."
msgstr ""
msgid "Project overview"
-msgstr ""
+msgstr "Prosjektoversikt"
msgid "Project path"
-msgstr ""
+msgstr "Prosjektfilbane"
msgid "Project scanning help page"
msgstr ""
msgid "Project security status"
-msgstr ""
+msgstr "Prosjekt-sikkerhetsstatus"
msgid "Project security status help page"
msgstr ""
@@ -19237,7 +19923,7 @@ msgid "Project slug"
msgstr ""
msgid "Project uploads"
-msgstr ""
+msgstr "Prosjektopplastinger"
msgid "Project visibility level will be changed to match namespace rules when transferring to a group."
msgstr ""
@@ -19246,58 +19932,58 @@ msgid "Project was not found or you do not have permission to add this project t
msgstr ""
msgid "Project: %{name}"
-msgstr ""
+msgstr "Prosjekt: %{name}"
msgid "ProjectActivityRSS|Subscribe"
-msgstr ""
+msgstr "Abonner"
msgid "ProjectCreationLevel|Allowed to create projects"
-msgstr ""
+msgstr "Tillatelse til å opprette prosjekter"
msgid "ProjectCreationLevel|Default project creation protection"
msgstr ""
msgid "ProjectCreationLevel|Developers + Maintainers"
-msgstr ""
+msgstr "Utviklere + Vedlikeholdere"
msgid "ProjectCreationLevel|Maintainers"
-msgstr ""
+msgstr "Vedlikeholdere"
msgid "ProjectCreationLevel|No one"
-msgstr ""
+msgstr "Ingen"
msgid "ProjectFileTree|Name"
-msgstr ""
+msgstr "Navn"
msgid "ProjectFileTree|Show more"
-msgstr ""
+msgstr "Vis mer"
msgid "ProjectLastActivity|Never"
-msgstr ""
+msgstr "Aldri"
msgid "ProjectLifecycle|Stage"
-msgstr ""
+msgstr "Trinn"
msgid "ProjectOverview|Fork"
-msgstr ""
+msgstr "Utgreining"
msgid "ProjectOverview|Forks"
-msgstr ""
+msgstr "Utgreininger"
msgid "ProjectOverview|Go to your fork"
-msgstr ""
+msgstr "GÃ¥ til utgreiningen din"
msgid "ProjectOverview|Star"
-msgstr ""
+msgstr "Stjernemerk"
msgid "ProjectOverview|Starrer"
-msgstr ""
+msgstr "Stjernemerker"
msgid "ProjectOverview|Starrers"
-msgstr ""
+msgstr "Stjernemerkere"
msgid "ProjectOverview|Unstar"
-msgstr ""
+msgstr "Fjern stjernemerke"
msgid "ProjectOverview|You have reached your project limit"
msgstr ""
@@ -19306,25 +19992,25 @@ msgid "ProjectOverview|You must sign in to star a project"
msgstr ""
msgid "ProjectPage|Project ID: %{project_id}"
-msgstr ""
+msgstr "Prosjekt-ID: %{project_id}"
msgid "ProjectSelect| or group"
-msgstr ""
+msgstr "eller gruppe"
msgid "ProjectSelect|Search for project"
-msgstr ""
+msgstr "Søk etter prosjekt"
msgid "ProjectService|%{service_title}: status off"
-msgstr ""
+msgstr "%{service_title}: status av"
msgid "ProjectService|%{service_title}: status on"
-msgstr ""
+msgstr "%{service_title}: status på"
msgid "ProjectService|Event will be triggered by a push to the repository"
msgstr ""
msgid "ProjectService|Event will be triggered when a commit is created/updated"
-msgstr ""
+msgstr "Hendelsen vil bli trigget dersom en commit er opprettet/oppdatert"
msgid "ProjectService|Event will be triggered when a confidential issue is created/updated/closed"
msgstr ""
@@ -19360,28 +20046,28 @@ msgid "ProjectService|Perform common operations on GitLab project: %{project_nam
msgstr ""
msgid "ProjectService|To set up this service:"
-msgstr ""
+msgstr "For å sette opp denne tjenesten:"
msgid "ProjectSettings|Additional merge request capabilities that influence how and when merges will be performed"
msgstr ""
msgid "ProjectSettings|All discussions must be resolved"
-msgstr ""
+msgstr "Alle diskusjoner må bli oppklart"
msgid "ProjectSettings|Allow"
-msgstr ""
+msgstr "Tillat"
msgid "ProjectSettings|Allow users to make copies of your repository to a new project"
msgstr ""
msgid "ProjectSettings|Allow users to request access"
-msgstr ""
+msgstr "Tillat brukere å be om tilgang"
msgid "ProjectSettings|Automatically resolve merge request diff discussions when they become outdated"
msgstr ""
msgid "ProjectSettings|Badges"
-msgstr ""
+msgstr "Merker"
msgid "ProjectSettings|Build, test, and deploy your changes"
msgstr ""
@@ -19399,7 +20085,7 @@ msgid "ProjectSettings|Choose your merge method, merge options, merge checks, me
msgstr ""
msgid "ProjectSettings|Contact an admin to change this setting."
-msgstr ""
+msgstr "Kontakt en administrator for å endre på denne innstillingen."
msgid "ProjectSettings|Container registry"
msgstr ""
@@ -19408,10 +20094,10 @@ msgid "ProjectSettings|Customize your project badges."
msgstr ""
msgid "ProjectSettings|Disable email notifications"
-msgstr ""
+msgstr "Skru av e-postvarsler"
msgid "ProjectSettings|Do not allow"
-msgstr ""
+msgstr "Ikke tillat"
msgid "ProjectSettings|Enable 'Delete source branch' option by default"
msgstr ""
@@ -19420,10 +20106,10 @@ msgid "ProjectSettings|Enable merge trains and pipelines for merged results"
msgstr ""
msgid "ProjectSettings|Encourage"
-msgstr ""
+msgstr "Oppmuntre til"
msgid "ProjectSettings|Every merge creates a merge commit"
-msgstr ""
+msgstr "Alle innflettinger skaper en innflettings-commit"
msgid "ProjectSettings|Every project can have its own space to store its Docker images"
msgstr ""
@@ -19432,16 +20118,16 @@ msgid "ProjectSettings|Every project can have its own space to store its package
msgstr ""
msgid "ProjectSettings|Everyone"
-msgstr ""
+msgstr "Alle"
msgid "ProjectSettings|Existing merge requests and protected branches are not affected"
msgstr ""
msgid "ProjectSettings|Failed to protect the tag"
-msgstr ""
+msgstr "Mislyktes i å beskytte etiketten"
msgid "ProjectSettings|Failed to update tag!"
-msgstr ""
+msgstr "Mislyktes i å oppdatere etiketten!"
msgid "ProjectSettings|Fast-forward merge"
msgstr ""
@@ -19450,22 +20136,22 @@ msgid "ProjectSettings|Fast-forward merges only"
msgstr ""
msgid "ProjectSettings|Forks"
-msgstr ""
+msgstr "Utgreininger"
msgid "ProjectSettings|Git Large File Storage (LFS)"
msgstr ""
msgid "ProjectSettings|Global"
-msgstr ""
+msgstr "Universelt"
msgid "ProjectSettings|Internal"
-msgstr ""
+msgstr "Internt"
msgid "ProjectSettings|Issues"
-msgstr ""
+msgstr "Saker"
msgid "ProjectSettings|LFS objects from this repository are still available to forks. %{linkStart}How do I remove them?%{linkEnd}"
-msgstr ""
+msgstr "LFS-objekter fra dette kodelageret er fortsatt tilgjengelig for utgreininger. %{linkStart}Hvordan fjerner jeg dem?%{linkEnd}"
msgid "ProjectSettings|Learn more about badges."
msgstr ""
@@ -19477,28 +20163,28 @@ msgid "ProjectSettings|Manages large files such as audio, video, and graphics fi
msgstr ""
msgid "ProjectSettings|Merge checks"
-msgstr ""
+msgstr "Flettesjekker"
msgid "ProjectSettings|Merge commit"
-msgstr ""
+msgstr "Innflettings-commit"
msgid "ProjectSettings|Merge commit with semi-linear history"
-msgstr ""
+msgstr "Innflettings-commit med semi-lineær historikk"
msgid "ProjectSettings|Merge method"
-msgstr ""
+msgstr "Flettemetode"
msgid "ProjectSettings|Merge options"
-msgstr ""
+msgstr "Fletteinnstillinger"
msgid "ProjectSettings|Merge requests"
-msgstr ""
+msgstr "Fletteforespørsler"
msgid "ProjectSettings|Merge suggestions"
-msgstr ""
+msgstr "Fletteforslag"
msgid "ProjectSettings|No merge commits are created"
-msgstr ""
+msgstr "Ingen innflettings-commiter har blitt skapt"
msgid "ProjectSettings|Note: the container registry is always visible when a project is public"
msgstr ""
@@ -19507,40 +20193,40 @@ msgid "ProjectSettings|Only signed commits can be pushed to this repository."
msgstr ""
msgid "ProjectSettings|Packages"
-msgstr ""
+msgstr "Pakker"
msgid "ProjectSettings|Pages"
-msgstr ""
+msgstr "Sider"
msgid "ProjectSettings|Pages for project documentation"
msgstr ""
msgid "ProjectSettings|Pipelines"
-msgstr ""
+msgstr "Rørledninger"
msgid "ProjectSettings|Pipelines for merge requests must be enabled in the CI/CD configuration file, or pipelines could be unresolvable or dropped"
msgstr ""
msgid "ProjectSettings|Pipelines must succeed"
-msgstr ""
+msgstr "Rørledningene må lykkes"
msgid "ProjectSettings|Pipelines need to be configured to enable this feature."
msgstr ""
msgid "ProjectSettings|Private"
-msgstr ""
+msgstr "Private"
msgid "ProjectSettings|Project visibility"
-msgstr ""
+msgstr "Prosjektsynlighet"
msgid "ProjectSettings|Public"
-msgstr ""
+msgstr "Offentlig"
msgid "ProjectSettings|Repository"
-msgstr ""
+msgstr "Kodelager"
msgid "ProjectSettings|Require"
-msgstr ""
+msgstr "Krev"
msgid "ProjectSettings|Set the default behavior and availability of this option in merge requests. Changes made are also applied to existing merge requests."
msgstr ""
@@ -19555,10 +20241,10 @@ msgid "ProjectSettings|Show link to create/view merge request when pushing from
msgstr ""
msgid "ProjectSettings|Skipped pipelines are considered successful"
-msgstr ""
+msgstr "Rørledninger som hoppes over blir ansett som vellykkede"
msgid "ProjectSettings|Snippets"
-msgstr ""
+msgstr "Utdrag"
msgid "ProjectSettings|Squash commits when merging"
msgstr ""
@@ -19573,10 +20259,10 @@ msgid "ProjectSettings|Submit changes to be merged upstream"
msgstr ""
msgid "ProjectSettings|The commit message used to apply merge request suggestions"
-msgstr ""
+msgstr "Commit-meldingen som ble brukt til å benytte fletteforespørselsforslagene"
msgid "ProjectSettings|The variables GitLab supports:"
-msgstr ""
+msgstr "Variablene som GitLab støtter:"
msgid "ProjectSettings|These checks must pass before merge requests can be merged"
msgstr ""
@@ -19600,13 +20286,13 @@ msgid "ProjectSettings|This will dictate the commit history when you merge a mer
msgstr ""
msgid "ProjectSettings|Transfer project"
-msgstr ""
+msgstr "Overfør prosjekt"
msgid "ProjectSettings|Users can only push commits to this repository that were committed with one of their own verified emails."
msgstr ""
msgid "ProjectSettings|View and edit files in this project"
-msgstr ""
+msgstr "Vis og rediger filer i dette prosjektet"
msgid "ProjectSettings|View and edit files in this project. Non-project members will only have read access"
msgstr ""
@@ -19615,10 +20301,10 @@ msgid "ProjectSettings|When conflicts arise the user is given the option to reba
msgstr ""
msgid "ProjectSettings|When enabled, issues, merge requests, and snippets will always show thumbs-up and thumbs-down award emoji buttons."
-msgstr ""
+msgstr "Når dette er aktivert, viser saker, fletteforespørsler og utdrag alltid tommel-opp- og tommel-ned-emojiknapper."
msgid "ProjectSettings|Wiki"
-msgstr ""
+msgstr "Wiki"
msgid "ProjectSettings|With GitLab Pages you can host your static websites on GitLab"
msgstr ""
@@ -19627,37 +20313,40 @@ msgid "ProjectSettings|With Metrics Dashboard you can visualize this project per
msgstr ""
msgid "ProjectTemplates|.NET Core"
-msgstr ""
+msgstr ".NET Core"
msgid "ProjectTemplates|Android"
-msgstr ""
+msgstr "Android"
msgid "ProjectTemplates|GitLab Cluster Management"
msgstr ""
-msgid "ProjectTemplates|Go Micro"
+msgid "ProjectTemplates|Gitpod/Spring Petclinic"
msgstr ""
+msgid "ProjectTemplates|Go Micro"
+msgstr "Go Micro"
+
msgid "ProjectTemplates|HIPAA Audit Protocol"
msgstr ""
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 ""
msgid "ProjectTemplates|NodeJS Express"
-msgstr ""
+msgstr "NodeJS Express"
msgid "ProjectTemplates|Pages/Gatsby"
msgstr ""
@@ -19681,7 +20370,7 @@ msgid "ProjectTemplates|Ruby on Rails"
msgstr ""
msgid "ProjectTemplates|SalesforceDX"
-msgstr ""
+msgstr "SalesforceDX"
msgid "ProjectTemplates|Serverless Framework/JS"
msgstr ""
@@ -19693,13 +20382,13 @@ msgid "ProjectTemplates|Static Site Editor/Middleman"
msgstr ""
msgid "ProjectTemplates|iOS (Swift)"
-msgstr ""
+msgstr "iOS (Swift)"
msgid "Projects"
-msgstr ""
+msgstr "Prosjekt"
msgid "Projects (%{count})"
-msgstr ""
+msgstr "Prosjekter (%{count})"
msgid "Projects Successfully Retrieved"
msgstr ""
@@ -19714,16 +20403,16 @@ msgid "Projects that belong to a group are prefixed with the group namespace. Ex
msgstr ""
msgid "Projects to index"
-msgstr ""
+msgstr "Prosjekter å indeksere"
msgid "Projects will be permanently deleted after a 7-day waiting period."
msgstr ""
msgid "Projects will be permanently deleted immediately."
-msgstr ""
+msgstr "Prosjekter vil bli permanent og umiddelbart slettet."
msgid "Projects with critical vulnerabilities"
-msgstr ""
+msgstr "Prosjekter med kritiske sårbarheter"
msgid "Projects with high or unknown vulnerabilities"
msgstr ""
@@ -19738,22 +20427,22 @@ msgid "Projects with no vulnerabilities and security scanning enabled"
msgstr ""
msgid "Projects with write access"
-msgstr ""
+msgstr "Prosjekter med skrivetilgang"
msgid "ProjectsDropdown|Frequently visited"
-msgstr ""
+msgstr "Ofte besøkt"
msgid "ProjectsDropdown|Loading projects"
-msgstr ""
+msgstr "Laster inn prosjekter"
msgid "ProjectsDropdown|Projects you visit often will appear here"
msgstr ""
msgid "ProjectsDropdown|Search your projects"
-msgstr ""
+msgstr "Søk i dine prosjekter"
msgid "ProjectsDropdown|Something went wrong on our end."
-msgstr ""
+msgstr "Noe gikk galt på vår side av linja."
msgid "ProjectsDropdown|Sorry, no projects matched your search"
msgstr ""
@@ -19765,10 +20454,10 @@ msgid "ProjectsNew|Allows you to immediately clone this project’s repository.
msgstr ""
msgid "ProjectsNew|Blank"
-msgstr ""
+msgstr "Blank"
msgid "ProjectsNew|Blank project"
-msgstr ""
+msgstr "Blankt prosjekt"
msgid "ProjectsNew|Connect your external repository to GitLab CI/CD."
msgstr ""
@@ -19777,58 +20466,58 @@ msgid "ProjectsNew|Contact an administrator to enable options for importing your
msgstr ""
msgid "ProjectsNew|Create"
-msgstr ""
+msgstr "Opprett"
msgid "ProjectsNew|Create a blank project to house your files, plan your work, and collaborate on code, among other things."
msgstr ""
msgid "ProjectsNew|Create blank project"
-msgstr ""
+msgstr "Opprett blankt prosjekt"
msgid "ProjectsNew|Create from template"
-msgstr ""
+msgstr "Opprett fra mal"
msgid "ProjectsNew|Create new project"
-msgstr ""
+msgstr "Opprett nytt prosjekt"
msgid "ProjectsNew|Creating project & repository."
-msgstr ""
+msgstr "Oppretter prosjektet og kodelageret."
msgid "ProjectsNew|Description format"
-msgstr ""
+msgstr "Beskrivelsesformat"
msgid "ProjectsNew|Import"
-msgstr ""
+msgstr "Importer"
msgid "ProjectsNew|Import project"
-msgstr ""
+msgstr "Importer prosjekt"
msgid "ProjectsNew|Initialize repository with a README"
-msgstr ""
+msgstr "Start i gang kodelageret med en README"
msgid "ProjectsNew|No import options available"
-msgstr ""
+msgstr "Ingen importalternativer er tilgjengelige"
msgid "ProjectsNew|Please wait a moment, this page will automatically refresh when ready."
-msgstr ""
+msgstr "Vennligst vent et øyeblikk, denne siden vil automatisk oppfriskes når det er klart."
msgid "ProjectsNew|Project description %{tag_start}(optional)%{tag_end}"
-msgstr ""
+msgstr "Prosjektbeskrivelse %{tag_start}(valgfritt)%{tag_end}"
msgid "ProjectsNew|Run CI/CD for external repository"
-msgstr ""
+msgstr "Kjør CI/CD for et eksternt kodelager"
msgid "ProjectsNew|Template"
-msgstr ""
+msgstr "Mal"
msgid "ProjectsNew|Visibility Level"
-msgstr ""
+msgstr "Synlighetsnivå"
msgid "ProjectsNew|Want to house several dependent projects under the same namespace? %{link_start}Create a group.%{link_end}"
-msgstr ""
+msgstr "Vil du huse flere prosjekter som er avhengig av hverandre i det samme navnefeltet? %{link_start}Opprett en gruppe.%{link_end}"
msgid "Prometheus"
-msgstr ""
+msgstr "Prometheus"
msgid "PrometheusAlerts|%{count} alerts applied"
msgstr ""
@@ -19837,22 +20526,22 @@ msgid "PrometheusAlerts|%{firingCount} firing"
msgstr ""
msgid "PrometheusAlerts|Add alert"
-msgstr ""
+msgstr "Legg til alarm"
msgid "PrometheusAlerts|Edit alert"
-msgstr ""
+msgstr "Rediger alarm"
msgid "PrometheusAlerts|Error creating alert"
-msgstr ""
+msgstr "Feil under oppretting av alarm"
msgid "PrometheusAlerts|Error deleting alert"
-msgstr ""
+msgstr "Feil under sletting av alarm"
msgid "PrometheusAlerts|Error fetching alert"
-msgstr ""
+msgstr "Feil under innhenting av alarm"
msgid "PrometheusAlerts|Error saving alert"
-msgstr ""
+msgstr "Feil under lagring av alarm"
msgid "PrometheusAlerts|Firing: %{alerts}"
msgstr ""
@@ -19867,31 +20556,31 @@ msgid "PrometheusAlerts|Runbook URL (optional)"
msgstr ""
msgid "PrometheusAlerts|Select query"
-msgstr ""
+msgstr "Velg forespørsel"
msgid "PrometheusAlerts|Threshold"
-msgstr ""
+msgstr "Terskel"
msgid "PrometheusAlerts|exceeded"
-msgstr ""
+msgstr "overskredet"
msgid "PrometheusAlerts|https://gitlab.com/gitlab-com/runbooks"
-msgstr ""
+msgstr "https://gitlab.com/gitlab-com/runbooks"
msgid "PrometheusAlerts|is equal to"
-msgstr ""
+msgstr "er det samme som"
msgid "PrometheusAlerts|is less than"
-msgstr ""
+msgstr "er mindre enn"
msgid "PrometheusService|%{exporters} with %{metrics} were found"
msgstr ""
msgid "PrometheusService|Active"
-msgstr ""
+msgstr "Aktiv"
msgid "PrometheusService|Auto configuration"
-msgstr ""
+msgstr "Auto-oppsett"
msgid "PrometheusService|Automatically deploy and configure Prometheus on your clusters to monitor your project’s environments"
msgstr ""
@@ -19900,7 +20589,7 @@ msgid "PrometheusService|Client ID of the IAP secured resource (looks like IAP_C
msgstr ""
msgid "PrometheusService|Common metrics"
-msgstr ""
+msgstr "Vanlige måltall"
msgid "PrometheusService|Common metrics are automatically monitored based on a library of metrics from popular exporters."
msgstr ""
@@ -19909,7 +20598,7 @@ msgid "PrometheusService|Contents of the credentials.json file of your service a
msgstr ""
msgid "PrometheusService|Custom metrics"
-msgstr ""
+msgstr "Tilpassede målinger"
msgid "PrometheusService|Custom metrics require Prometheus installed on a cluster with environment scope \"*\" OR a manually configured Prometheus to be available."
msgstr ""
@@ -19927,19 +20616,19 @@ msgid "PrometheusService|Install Prometheus on clusters"
msgstr ""
msgid "PrometheusService|Manage clusters"
-msgstr ""
+msgstr "Behandle klynger"
msgid "PrometheusService|Manual configuration"
-msgstr ""
+msgstr "Manuelt oppsett"
msgid "PrometheusService|Metrics"
-msgstr ""
+msgstr "MÃ¥ltall"
msgid "PrometheusService|Missing environment variable"
msgstr ""
msgid "PrometheusService|More information"
-msgstr ""
+msgstr "Mere informasjon"
msgid "PrometheusService|New metric"
msgstr ""
@@ -19975,16 +20664,16 @@ msgid "PrometheusService|You can now manage your Prometheus settings on the %{op
msgstr ""
msgid "Promote"
-msgstr ""
+msgstr "Forfrem"
msgid "Promote confidential issue to a non-confidential epic"
msgstr ""
msgid "Promote issue to an epic"
-msgstr ""
+msgstr "Forfrem saken til en epos"
msgid "Promote to group label"
-msgstr ""
+msgstr "Forfrem til gruppestempel"
msgid "PromoteMilestone|Only project milestones can be promoted."
msgstr ""
@@ -19996,22 +20685,22 @@ msgid "PromoteMilestone|Promotion failed - %{message}"
msgstr ""
msgid "Promoted confidential issue to a non-confidential epic. Information in this issue is no longer confidential as epics are public to group members."
-msgstr ""
+msgstr "Forfremmet en konfidensiell sak til en ikke-konfidensiell epos. Informasjon i denne saken er ikke lenger konfidensielle, ettersom eposer er offentlige for gruppemedlemmer."
msgid "Promoted issue to an epic."
-msgstr ""
+msgstr "Forfremmet saken til en epos."
msgid "Promotion is not supported."
-msgstr ""
+msgstr "Forfremming er ikke støttet."
msgid "Promotions|Burndown Charts are visual representations of the progress of completing a milestone. At a glance, you see the current state for the completion a given milestone. Without them, you would have to organize the data from the milestone and plot it yourself to have the same sense of progress."
-msgstr ""
+msgstr "Burndown-diagrammer er visuelle fremstillinger av fremgangen med å fullføre en milepæl. Med et øyekast ser du den nåværende tilstanden for fullføring av en gitt milepæl. Uten dem ville du mptte organisere dataene fra milepælen og håndtere det selv for å ha den samme følelsen av fremgang."
msgid "Promotions|Buy EE"
-msgstr ""
+msgstr "Kjøp EE"
msgid "Promotions|Buy GitLab Enterprise Edition"
-msgstr ""
+msgstr "Kjøp GitLab Enterprise Edition"
msgid "Promotions|Contact an owner of group %{namespace_name} to upgrade the plan."
msgstr ""
@@ -20026,10 +20715,10 @@ msgid "Promotions|Dismiss burndown charts promotion"
msgstr ""
msgid "Promotions|Don't show me this again"
-msgstr ""
+msgstr "Ikke vis meg dette igjen"
msgid "Promotions|Epics let you manage your portfolio of projects more efficiently and with less effort by tracking groups of issues that share a theme, across projects and milestones."
-msgstr ""
+msgstr "Eposer lar deg administrere prosjektporteføljen din mer effektivt og med mindre innsats ved å spore grupper av saker som deler et tema, på tvers av prosjekter og milepæler."
msgid "Promotions|Improve issues management with Issue weight and GitLab Enterprise Edition."
msgstr ""
@@ -20038,10 +20727,10 @@ msgid "Promotions|Improve milestones with Burndown Charts."
msgstr ""
msgid "Promotions|Learn more"
-msgstr ""
+msgstr "Lær mer"
msgid "Promotions|Not now, thanks!"
-msgstr ""
+msgstr "Ikke nå, ellers takk!"
msgid "Promotions|See the other features in the %{subscription_link_start}bronze plan%{subscription_link_end}"
msgstr ""
@@ -20050,19 +20739,19 @@ msgid "Promotions|Start GitLab Ultimate trial"
msgstr ""
msgid "Promotions|This feature is locked."
-msgstr ""
+msgstr "Denne funksjonen er låst"
msgid "Promotions|Track activity with Contribution Analytics."
msgstr ""
msgid "Promotions|Try it for free"
-msgstr ""
+msgstr "Prøv det gratis"
msgid "Promotions|Upgrade plan"
-msgstr ""
+msgstr "Oppgrader planen"
msgid "Promotions|Upgrade your plan"
-msgstr ""
+msgstr "Oppgrader planen din"
msgid "Promotions|Upgrade your plan to activate Contribution Analytics."
msgstr ""
@@ -20077,7 +20766,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 "Når du har mange saker, kan det være vanskelig å få oversikt. Ved å vektlegge dine problemstillinger, kan du få en bedre idé om innsatsen, kostnaden, nødvendig tid eller deres verdier, og så å kunne behandle dem bedre."
msgid "Promotions|With Contribution Analytics you can have an overview for the activity of issues, merge requests, and push events of your organization and its members."
msgstr ""
@@ -20086,46 +20775,46 @@ msgid "Prompt users to upload SSH keys"
msgstr ""
msgid "Protect"
-msgstr ""
+msgstr "Beskytt"
msgid "Protect variable"
-msgstr ""
+msgstr "Beskytt variabel"
msgid "Protected"
-msgstr ""
+msgstr "Beskyttet"
msgid "Protected Branch"
-msgstr ""
+msgstr "Beskyttet gren"
msgid "Protected Branches"
-msgstr ""
+msgstr "Beskyttede grener"
msgid "Protected Environment"
-msgstr ""
+msgstr "Beskyttet miljø"
msgid "Protected Environments"
-msgstr ""
+msgstr "Beskyttede miljøer"
msgid "Protected Paths"
-msgstr ""
+msgstr "Beskyttede stier"
msgid "Protected Tag"
-msgstr ""
+msgstr "Beskyttet etikett"
msgid "Protected Tags"
-msgstr ""
+msgstr "Beskyttede etiketter"
msgid "Protected branches"
-msgstr ""
+msgstr "Beskyttede grener"
msgid "ProtectedBranch|%{wildcards_link_start}Wildcards%{wildcards_link_end} such as %{code_tag_start}*-stable%{code_tag_end} or %{code_tag_start}production/*%{code_tag_end} are supported"
-msgstr ""
+msgstr "%{wildcards_link_start}Jokertegn%{wildcards_link_end} slik som %{code_tag_start}*-stable%{code_tag_end} eller %{code_tag_start}production/*%{code_tag_end} er støttet"
msgid "ProtectedBranch|Allowed to merge"
-msgstr ""
+msgstr "Tillatelse til å innflette"
msgid "ProtectedBranch|Allowed to merge:"
-msgstr ""
+msgstr "Tillatelse til å innflette:"
msgid "ProtectedBranch|Allowed to push"
msgstr ""
@@ -20134,16 +20823,16 @@ msgid "ProtectedBranch|Allowed to push:"
msgstr ""
msgid "ProtectedBranch|Branch"
-msgstr ""
+msgstr "Gren"
msgid "ProtectedBranch|Code owner approval"
msgstr ""
msgid "ProtectedBranch|Protect"
-msgstr ""
+msgstr "Beskytt"
msgid "ProtectedBranch|Protect a branch"
-msgstr ""
+msgstr "Beskytt en gren"
msgid "ProtectedBranch|Protected branch (%{protected_branches_count})"
msgstr ""
@@ -20161,58 +20850,58 @@ msgid "ProtectedBranch|Toggle code owner approval"
msgstr ""
msgid "ProtectedEnvironment|%{environment_name} will be writable for developers. Are you sure?"
-msgstr ""
+msgstr "%{environment_name} vil være skrivbar for utviklere. Er du sikker?"
msgid "ProtectedEnvironment|Allowed to deploy"
-msgstr ""
+msgstr "Tillatt å distribuere"
msgid "ProtectedEnvironment|Environment"
-msgstr ""
+msgstr "Miljø"
msgid "ProtectedEnvironment|Protect"
-msgstr ""
+msgstr "Beskytt"
msgid "ProtectedEnvironment|Protect an environment"
-msgstr ""
+msgstr "Beskytt et miljø"
msgid "ProtectedEnvironment|Protected Environment (%{protected_environments_count})"
-msgstr ""
+msgstr "Beskyttet miljø (%{protected_environments_count})"
msgid "ProtectedEnvironment|Protecting an environment restricts the users who can execute deployments."
msgstr ""
msgid "ProtectedEnvironment|Select an environment"
-msgstr ""
+msgstr "Velg et miljø"
msgid "ProtectedEnvironment|Select users"
-msgstr ""
+msgstr "Velg brukere"
msgid "ProtectedEnvironment|Select users to deploy and manage Feature Flag settings"
msgstr ""
msgid "ProtectedEnvironment|There are currently no protected environments, protect an environment with the form above."
-msgstr ""
+msgstr "Det er for tiden ingen beskyttede miljøer, beskytt et miljø med skjemaet ovenfor."
msgid "ProtectedEnvironment|Unprotect"
-msgstr ""
+msgstr "Ubeskyttet"
msgid "ProtectedEnvironment|Your environment can't be unprotected"
-msgstr ""
+msgstr "Ditt miljø kan ikke være ubeskyttet"
msgid "ProtectedEnvironment|Your environment has been protected."
-msgstr ""
+msgstr "Miljøet ditt er beskyttet."
msgid "ProtectedEnvironment|Your environment has been unprotected"
-msgstr ""
+msgstr "Miljøet ditt er blitt ubeskyttet"
msgid "Protip:"
-msgstr ""
+msgstr "Topptips:"
msgid "Protocol"
-msgstr ""
+msgstr "Protokoll"
msgid "Provider"
-msgstr ""
+msgstr "Leverandør"
msgid "Proxy support for this API is not available currently"
msgstr ""
@@ -20221,7 +20910,7 @@ msgid "Pseudonymizer data collection"
msgstr ""
msgid "Public"
-msgstr ""
+msgstr "Offentlig"
msgid "Public - The group and any public projects can be viewed without any authentication."
msgstr ""
@@ -20236,40 +20925,43 @@ msgid "Public deploy keys (%{deploy_keys_count})"
msgstr ""
msgid "Public pipelines"
-msgstr ""
+msgstr "Offentlige rørledninger"
msgid "Public projects Minutes cost factor"
msgstr ""
msgid "Publish to status page"
+msgstr "Publiser på statussiden"
+
+msgid "Published"
msgstr ""
msgid "Published on status page"
-msgstr ""
+msgstr "Publisert på statussiden"
msgid "Publishes this issue to the associated status page."
msgstr ""
msgid "Pull"
-msgstr ""
+msgstr "Pull"
msgid "Pull requests from fork are not supported"
-msgstr ""
+msgstr "Kodeforespørsler fra utgreininger er ikke støttet"
msgid "Puma is running with a thread count above 1 and the Rugged service is enabled. This may decrease performance in some environments. See our %{link_start}documentation%{link_end} for details of this issue."
msgstr ""
msgid "Purchase more minutes"
-msgstr ""
+msgstr "Kjøp flere minutter"
msgid "Push"
-msgstr ""
+msgstr "Push"
msgid "Push Rule updated successfully."
msgstr ""
msgid "Push Rules"
-msgstr ""
+msgstr "Push-regler"
msgid "Push Rules updated successfully."
msgstr ""
@@ -20284,7 +20976,7 @@ msgid "Push commits to the source branch or add previously merged commits to rev
msgstr ""
msgid "Push events"
-msgstr ""
+msgstr "Push-hendelser"
msgid "Push project from command line"
msgstr ""
@@ -20296,13 +20988,13 @@ msgid "PushRule|Committer restriction"
msgstr ""
msgid "Pushed"
-msgstr ""
+msgstr "Pushet"
msgid "Pushes"
-msgstr ""
+msgstr "Pushinger"
msgid "PushoverService|%{user_name} deleted branch \"%{ref}\"."
-msgstr ""
+msgstr "%{user_name} sletter grenen \"%{ref}\"."
msgid "PushoverService|%{user_name} push to branch \"%{ref}\"."
msgstr ""
@@ -20311,49 +21003,49 @@ msgid "PushoverService|%{user_name} pushed new branch \"%{ref}\"."
msgstr ""
msgid "PushoverService|High Priority"
-msgstr ""
+msgstr "Høy prioritet"
msgid "PushoverService|Leave blank for all active devices"
msgstr ""
msgid "PushoverService|Low Priority"
-msgstr ""
+msgstr "Lav prioritet"
msgid "PushoverService|Lowest Priority"
-msgstr ""
+msgstr "Laveste prioritet"
msgid "PushoverService|Normal Priority"
-msgstr ""
+msgstr "Normal prioritet"
msgid "PushoverService|Pushover makes it easy to get real-time notifications on your Android device, iPhone, iPad, and Desktop."
msgstr ""
msgid "PushoverService|See project %{project_full_name}"
-msgstr ""
+msgstr "Se prosjektet %{project_full_name}"
msgid "PushoverService|Total commits count: %{total_commits_count}"
msgstr ""
msgid "PushoverService|Your application key"
-msgstr ""
+msgstr "Din applikasjonsnøkkel"
msgid "PushoverService|Your user key"
-msgstr ""
+msgstr "Din brukernøkkel"
msgid "Quarters"
-msgstr ""
+msgstr "Kvartal"
msgid "Query"
-msgstr ""
+msgstr "Spørring"
msgid "Query cannot be processed"
-msgstr ""
+msgstr "Spørringen kan ikke behandles"
msgid "Query is valid"
-msgstr ""
+msgstr "Spørringen er gyldig"
msgid "Queued"
-msgstr ""
+msgstr "Satt i kø"
msgid "Quick actions can be used in the issues description and comment boxes."
msgstr ""
@@ -20361,7 +21053,13 @@ msgstr ""
msgid "Quick range"
msgstr ""
+msgid "Quickly and easily edit multiple files in your project."
+msgstr ""
+
msgid "README"
+msgstr "README"
+
+msgid "Rails"
msgstr ""
msgid "Rake Tasks Help"
@@ -20380,7 +21078,7 @@ msgid "Re-verification interval"
msgstr ""
msgid "Read more"
-msgstr ""
+msgstr "Les mer"
msgid "Read more about project permissions %{help_link_open}here%{help_link_close}"
msgstr ""
@@ -20389,10 +21087,10 @@ msgid "Read more about related issues"
msgstr ""
msgid "Real-time features"
-msgstr ""
+msgstr "Sanntidsfunksjoner"
msgid "Rebase"
-msgstr ""
+msgstr "Nullstill"
msgid "Rebase in progress"
msgstr ""
@@ -20404,31 +21102,31 @@ msgid "Receive notifications about your own activity"
msgstr ""
msgid "Recent"
-msgstr ""
+msgstr "Nylig"
msgid "Recent Activity"
-msgstr ""
+msgstr "Nylig aktivitet"
msgid "Recent Project Activity"
-msgstr ""
+msgstr "Nylig prosjektaktivitet"
msgid "Recent Searches Service is unavailable"
-msgstr ""
+msgstr "Tjeneste for nylige søk er ikke tilgjengelig"
msgid "Recent searches"
-msgstr ""
+msgstr "Nylige søk"
msgid "Reconfigure"
-msgstr ""
+msgstr "Sett opp på nytt"
msgid "Recover hidden stage"
msgstr ""
msgid "Recovering projects"
-msgstr ""
+msgstr "Gjenoppretter prosjekter"
msgid "Recovery Codes"
-msgstr ""
+msgstr "Gjenopprettingskoder"
msgid "Redirect to SAML provider to test configuration"
msgstr ""
@@ -20440,13 +21138,13 @@ msgid "Reduce this project’s visibility?"
msgstr ""
msgid "Reference:"
-msgstr ""
+msgstr "Referanse:"
msgid "References"
-msgstr ""
+msgstr "Referanser"
msgid "Refresh"
-msgstr ""
+msgstr "Oppdater"
msgid "Refreshing in a second to show the updated status..."
msgid_plural "Refreshing in %d seconds to show the updated status..."
@@ -20469,49 +21167,49 @@ msgid "Regenerating the instance ID can break integration depending on the clien
msgstr ""
msgid "Regex pattern"
-msgstr ""
+msgstr "Regex-mønster"
msgid "Region that Elasticsearch is configured"
msgstr ""
msgid "Register"
-msgstr ""
+msgstr "Register"
msgid "Register / Sign In"
-msgstr ""
+msgstr "Registrer / Logg inn"
msgid "Register Two-Factor Authenticator"
msgstr ""
-msgid "Register U2F device"
+msgid "Register Universal Two-Factor (U2F) Device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register WebAuthn Device"
msgstr ""
-msgid "Register for GitLab"
+msgid "Register device"
msgstr ""
+msgid "Register for GitLab"
+msgstr "Registrer deg på GitLab"
+
msgid "Register now"
-msgstr ""
+msgstr "Registrer deg nå"
msgid "Register with two-factor app"
-msgstr ""
-
-msgid "Registration"
-msgstr ""
+msgstr "Registrer med 2-trinnsapp"
msgid "Registration|Checkout"
msgstr ""
msgid "Registration|Your GitLab group"
-msgstr ""
+msgstr "Din GitLab-gruppe"
msgid "Registration|Your first project"
-msgstr ""
+msgstr "Ditt første prosjekt"
msgid "Registration|Your profile"
-msgstr ""
+msgstr "Profilen din"
msgid "Registry setup"
msgstr ""
@@ -20520,19 +21218,19 @@ msgid "Regulate approvals by authors/committers, based on compliance frameworks.
msgstr ""
msgid "Reindexing status"
-msgstr ""
+msgstr "Reindekserer statusen"
msgid "Rejected (closed)"
-msgstr ""
+msgstr "Avslått (lukket)"
msgid "Related Deployed Jobs"
msgstr ""
msgid "Related Issues"
-msgstr ""
+msgstr "Relaterte saker"
msgid "Related Jobs"
-msgstr ""
+msgstr "Relaterte jobber"
msgid "Related Merge Requests"
msgstr ""
@@ -20541,18 +21239,18 @@ msgid "Related Merged Requests"
msgstr ""
msgid "Related issues"
-msgstr ""
+msgstr "Relaterte saker"
msgid "Related merge requests"
-msgstr ""
+msgstr "Relaterte fletteforespørsler"
msgid "Relates to"
-msgstr ""
+msgstr "Relatert til"
msgid "Release"
msgid_plural "Releases"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "Utgave"
+msgstr[1] "Utgivelser"
msgid "Release assets"
msgstr ""
@@ -20564,28 +21262,28 @@ msgid "Release does not have the same project as the milestone"
msgstr ""
msgid "Release notes"
-msgstr ""
+msgstr "Versjonsnotat"
msgid "Release notes:"
-msgstr ""
+msgstr "Versjonsnotater:"
msgid "Release title"
-msgstr ""
+msgstr "Utgivelsestittel"
msgid "ReleaseAssetLinkType|Image"
-msgstr ""
+msgstr "Bilde"
msgid "ReleaseAssetLinkType|Images"
-msgstr ""
+msgstr "Bilder"
msgid "ReleaseAssetLinkType|Other"
-msgstr ""
+msgstr "Annet"
msgid "ReleaseAssetLinkType|Package"
-msgstr ""
+msgstr "Pakke"
msgid "ReleaseAssetLinkType|Packages"
-msgstr ""
+msgstr "Pakker"
msgid "ReleaseAssetLinkType|Runbook"
msgstr ""
@@ -20594,55 +21292,52 @@ msgid "ReleaseAssetLinkType|Runbooks"
msgstr ""
msgid "Releases"
-msgstr ""
+msgstr "Utgivelser"
msgid "Releases are based on Git tags and mark specific points in a project's development history. They can contain information about the type of changes and can also deliver binaries, like compiled versions of your software."
-msgstr ""
+msgstr "Utgivelser er basert på Git-etiketter og markerer spesifikke punkter i prosjektets utviklingshistorie. De kan inneholde informasjon om endringstypene og kan også levere binærfiler, slik som kompilerte versjoner av programvaren din."
msgid "Releases are based on Git tags. We recommend tags that use semantic versioning, for example %{codeStart}v1.0%{codeEnd}, %{codeStart}v2.0-pre%{codeEnd}."
-msgstr ""
+msgstr "Utgivelser er basert på Git-etiketter. Vi anbefaler koder som bruker semantisk versjonnummering, for eksempel %{codeStart}v1.0%{codeEnd}, %{codeStart}v2.0-pre%{codeEnd}."
msgid "Releases documentation"
-msgstr ""
+msgstr "Dokumentasjon for utgivelser"
msgid "Releases|New Release"
-msgstr ""
+msgstr "Ny utgivelse"
msgid "Release|Something went wrong while creating a new release"
-msgstr ""
+msgstr "Noe gikk galt under opprettelse av en ny utgivelse"
msgid "Release|Something went wrong while getting the release details"
-msgstr ""
+msgstr "Noe gikk galt under innhenting av utgivelsesdetaljene"
msgid "Release|Something went wrong while saving the release details"
-msgstr ""
-
-msgid "Remediated: needs review"
-msgstr ""
+msgstr "Noe gikk galt under lagring av utgivelsesdetaljene"
msgid "Remediations"
msgstr ""
msgid "Remember me"
-msgstr ""
+msgstr "Husk meg"
msgid "Remind later"
-msgstr ""
+msgstr "PÃ¥minn meg senere"
msgid "Remote object has no absolute path."
msgstr ""
msgid "Remove"
-msgstr ""
+msgstr "Fjern"
msgid "Remove %{displayReference}"
-msgstr ""
+msgstr "Fjern %{displayReference}"
msgid "Remove Runner"
msgstr ""
msgid "Remove Zoom meeting"
-msgstr ""
+msgstr "Fjern Zoom-møte"
msgid "Remove all approvals in a merge request when new commits are pushed to its source branch"
msgstr ""
@@ -20654,34 +21349,34 @@ msgid "Remove all or specific label(s)"
msgstr ""
msgid "Remove approver"
-msgstr ""
+msgstr "Fjern godkjenner"
msgid "Remove approvers"
-msgstr ""
+msgstr "Fjern godkjennere"
msgid "Remove approvers?"
-msgstr ""
+msgstr "Fjerne godkjennere?"
msgid "Remove asset link"
msgstr ""
msgid "Remove assignee"
-msgstr ""
+msgstr "Fjern tilordnet"
msgid "Remove avatar"
-msgstr ""
+msgstr "Fjern avatar"
msgid "Remove card"
-msgstr ""
+msgstr "Fjern kort"
msgid "Remove child epic from an epic"
msgstr ""
msgid "Remove description history"
-msgstr ""
+msgstr "Fjern beskrivelseshistorikken"
msgid "Remove due date"
-msgstr ""
+msgstr "Fjern måldato"
msgid "Remove fork relationship"
msgstr ""
@@ -20693,56 +21388,65 @@ msgid "Remove from board"
msgstr ""
msgid "Remove from epic"
-msgstr ""
+msgstr "Fjern fra epos"
msgid "Remove group"
-msgstr ""
+msgstr "Fjern gruppe"
msgid "Remove iteration"
msgstr ""
msgid "Remove license"
-msgstr ""
+msgstr "Fjern lisens"
msgid "Remove limit"
-msgstr ""
+msgstr "Fjern grensen"
msgid "Remove member"
-msgstr ""
+msgstr "Fjern medlem"
msgid "Remove milestone"
-msgstr ""
+msgstr "Fjern milepæl"
msgid "Remove node"
-msgstr ""
+msgstr "Fjern node"
msgid "Remove parent epic from an epic"
msgstr ""
msgid "Remove primary node"
-msgstr ""
+msgstr "Fjern hovednode"
msgid "Remove priority"
+msgstr "Fjern prioritet"
+
+msgid "Remove report"
msgstr ""
msgid "Remove secondary node"
-msgstr ""
+msgstr "Fjern sekundærnode"
msgid "Remove spent time"
-msgstr ""
+msgstr "Fjern brukt tid"
msgid "Remove stage"
-msgstr ""
+msgstr "Fjern trinn"
msgid "Remove time estimate"
msgstr ""
-msgid "Removed"
+msgid "Remove user & report"
msgstr ""
-msgid "Removed %{assignee_text} %{assignee_references}."
+msgid "Remove user from group"
msgstr ""
+msgid "Removed"
+msgstr "Fjernet"
+
+msgid "Removed %{assignee_text} %{assignee_references}."
+msgstr "Fjernet %{assignee_text} %{assignee_references}."
+
msgid "Removed %{epic_ref} from child epics."
msgstr ""
@@ -20750,19 +21454,19 @@ msgid "Removed %{iteration_reference} iteration."
msgstr ""
msgid "Removed %{label_references} %{label_text}."
-msgstr ""
+msgstr "Fjernet %{label_references} %{label_text}."
msgid "Removed %{milestone_reference} milestone."
-msgstr ""
+msgstr "Fjernet %{milestone_reference}-milepæl."
msgid "Removed %{type} with id %{id}"
-msgstr ""
+msgstr "Fjernet %{type} med ID %{id}"
msgid "Removed all labels."
-msgstr ""
+msgstr "Fjernet alle stempler."
msgid "Removed an issue from an epic."
-msgstr ""
+msgstr "Fjernet en sak fra et epos."
msgid "Removed group can not be restored!"
msgstr ""
@@ -20771,22 +21475,22 @@ msgid "Removed parent epic %{epic_ref}."
msgstr ""
msgid "Removed spent time."
-msgstr ""
+msgstr "Fjernet brukt tid."
msgid "Removed the due date."
-msgstr ""
+msgstr "Fjernet måldatoen."
msgid "Removed time estimate."
-msgstr ""
+msgstr "Fjernet tidsestimat."
msgid "RemovedProjects|Projects which are removed and are yet to be permanently removed are visible here."
msgstr ""
msgid "RemovedProjects|You haven’t removed any projects."
-msgstr ""
+msgstr "Du har ikke fjernet noen prosjekter."
msgid "Removes %{assignee_text} %{assignee_references}."
-msgstr ""
+msgstr "Fjerner %{assignee_text} %{assignee_references}."
msgid "Removes %{epic_ref} from child epics."
msgstr ""
@@ -20795,73 +21499,70 @@ msgid "Removes %{iteration_reference} iteration."
msgstr ""
msgid "Removes %{label_references} %{label_text}."
-msgstr ""
+msgstr "Fjerner %{label_references} %{label_text}."
msgid "Removes %{milestone_reference} milestone."
-msgstr ""
+msgstr "Fjerner %{milestone_reference}-milepælen."
msgid "Removes all labels."
-msgstr ""
+msgstr "Fjerner alle stempler."
msgid "Removes an issue from an epic."
-msgstr ""
+msgstr "Fjerner en sak fra et epos."
msgid "Removes parent epic %{epic_ref}."
msgstr ""
msgid "Removes spent time."
-msgstr ""
+msgstr "Fjerner brukt tid."
msgid "Removes the due date."
-msgstr ""
+msgstr "Fjerner måldatoen."
msgid "Removes time estimate."
-msgstr ""
-
-msgid "Removing license…"
-msgstr ""
+msgstr "Fjerner tidsanslag."
msgid "Removing this group also removes all child projects, including archived projects, and their resources."
msgstr ""
msgid "Rename file"
-msgstr ""
+msgstr "Gi filen nytt navn"
msgid "Rename folder"
-msgstr ""
+msgstr "Gi mappen nytt navn"
msgid "Rename/Move"
-msgstr ""
+msgstr "Endre navn/flytt"
msgid "Reopen"
-msgstr ""
+msgstr "Åpne på nytt"
msgid "Reopen %{display_issuable_type}"
-msgstr ""
+msgstr "Gjenåpne %{display_issuable_type}"
msgid "Reopen epic"
-msgstr ""
+msgstr "Gjenåpne epos"
msgid "Reopen milestone"
-msgstr ""
+msgstr "Gjenåpne milepæl"
msgid "Reopen this %{quick_action_target}"
-msgstr ""
+msgstr "Gjenåpne denne %{quick_action_target}"
msgid "Reopened this %{quick_action_target}."
-msgstr ""
+msgstr "Gjenåpnet denne %{quick_action_target}."
msgid "Reopens this %{quick_action_target}."
-msgstr ""
+msgstr "Gjenåpner denne %{quick_action_target}."
msgid "Repair authentication"
msgstr ""
msgid "Replace"
-msgstr ""
+msgstr "Erstatt"
msgid "Replace all label(s)"
-msgstr ""
+msgstr "Erstatt alle stempler"
msgid "Replaced all labels with %{label_references} %{label_text}."
msgstr ""
@@ -20879,37 +21580,40 @@ msgid "Replication paused"
msgstr ""
msgid "Reply by email"
-msgstr ""
+msgstr "Svar via E-post"
msgid "Reply to comment"
-msgstr ""
+msgstr "Svar på kommentar"
msgid "Reply to this email directly or %{view_it_on_gitlab}."
msgstr ""
msgid "Reply..."
-msgstr ""
+msgstr "Svar ..."
msgid "Repo by URL"
-msgstr ""
+msgstr "Kodelager utifra URL"
msgid "Report %{display_issuable_type} that are abusive, inappropriate or spam."
msgstr ""
msgid "Report abuse"
-msgstr ""
+msgstr "Rapporter misbruk"
msgid "Report abuse to admin"
-msgstr ""
+msgstr "Rapporter misbruk til admin"
msgid "Reported %{timeAgo} by %{reportedBy}"
+msgstr "Rapportert %{timeAgo} av %{reportedBy}"
+
+msgid "Reported by %{reporter}"
msgstr ""
msgid "Reporting"
-msgstr ""
+msgstr "Rapportering"
msgid "Reports|%{combinedString} and %{resolvedString}"
-msgstr ""
+msgstr "%{combinedString} og %{resolvedString}"
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"
@@ -20926,7 +21630,7 @@ msgid "Reports|Accessibility scanning results are being parsed"
msgstr ""
msgid "Reports|Actions"
-msgstr ""
+msgstr "Handlinger"
msgid "Reports|An error occured while loading report"
msgstr ""
@@ -20935,19 +21639,19 @@ msgid "Reports|An error occurred while loading %{name} results"
msgstr ""
msgid "Reports|Class"
-msgstr ""
+msgstr "Klasse"
msgid "Reports|Classname"
-msgstr ""
+msgstr "Klassenavn"
msgid "Reports|Execution time"
-msgstr ""
+msgstr "Kjøretid"
msgid "Reports|Failure"
-msgstr ""
+msgstr "Feilede"
msgid "Reports|Identifier"
-msgstr ""
+msgstr "Identifikator"
msgid "Reports|Metrics reports are loading"
msgstr ""
@@ -20962,16 +21666,16 @@ msgid "Reports|Metrics reports failed loading results"
msgstr ""
msgid "Reports|Scanner"
-msgstr ""
+msgstr "Skanner"
msgid "Reports|Severity"
-msgstr ""
+msgstr "Alvorlighetsgrad"
msgid "Reports|System output"
-msgstr ""
+msgstr "Systemutdata"
msgid "Reports|Test summary"
-msgstr ""
+msgstr "Testoversikt"
msgid "Reports|Test summary failed loading results"
msgstr ""
@@ -20980,29 +21684,50 @@ msgid "Reports|Test summary results are being parsed"
msgstr ""
msgid "Reports|Vulnerability"
-msgstr ""
+msgstr "SÃ¥rbarhet"
msgid "Reports|Vulnerability Name"
-msgstr ""
+msgstr "SÃ¥rbarhetsnavn"
msgid "Reports|no changed test results"
-msgstr ""
+msgstr "Ingen endrede testresultater"
msgid "Repositories"
+msgstr "Kodelagre"
+
+msgid "Repositories Analytics"
msgstr ""
-msgid "Repository"
+msgid "RepositoriesAnalytics|Download Historic Test Coverage Data"
msgstr ""
-msgid "Repository Analytics"
+msgid "RepositoriesAnalytics|Download historic test coverage data (.csv)"
msgstr ""
-msgid "Repository Graph"
+msgid "RepositoriesAnalytics|Download test coverage data (.csv)"
msgstr ""
-msgid "Repository Settings"
+msgid "RepositoriesAnalytics|Historic Test Coverage Data is available in raw format (.csv) for further analysis."
+msgstr ""
+
+msgid "RepositoriesAnalytics|Test Code Coverage"
+msgstr ""
+
+msgid "RepositoriesAnalytics|There was an error fetching the projects."
msgstr ""
+msgid "Repository"
+msgstr "Kodelager"
+
+msgid "Repository Analytics"
+msgstr "Kodelageranalyse"
+
+msgid "Repository Graph"
+msgstr "Kodelagerdiagram"
+
+msgid "Repository Settings"
+msgstr "Kodelager-innstillinger"
+
msgid "Repository check"
msgstr ""
@@ -21028,13 +21753,13 @@ msgid "Repository has no locks."
msgstr ""
msgid "Repository has tags."
-msgstr ""
+msgstr "Kodelageret har etiketter."
msgid "Repository maintenance"
msgstr ""
msgid "Repository mirroring"
-msgstr ""
+msgstr "Kodelagerspeiling"
msgid "Repository must contain at least 1 file."
msgstr ""
@@ -21046,19 +21771,19 @@ msgid "Repository static objects"
msgstr ""
msgid "Repository storage"
-msgstr ""
+msgstr "Kodelager-lagring"
msgid "Repository sync capacity"
-msgstr ""
+msgstr "Kodelagersynkroniseringskapasitet"
msgid "Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets}"
-msgstr ""
+msgstr "Kodelager: %{counter_repositories} / Wikier: %{counter_wikis} / Byggeartefakter: %{counter_build_artifacts} / LFS: %{counter_lfs_objects} / Utdrag: %{counter_snippets}"
msgid "RepositorySettingsAccessLevel|Select"
-msgstr ""
+msgstr "Velg"
msgid "Request Access"
-msgstr ""
+msgstr "Be om tilgang"
msgid "Request Headers"
msgstr ""
@@ -21069,25 +21794,34 @@ msgstr ""
msgid "Request parameter %{param} is missing."
msgstr ""
+msgid "Request review from"
+msgstr ""
+
msgid "Request to link SAML account must be authorized"
msgstr ""
-msgid "Requested %{time_ago}"
+msgid "Requested"
msgstr ""
+msgid "Requested %{time_ago}"
+msgstr "Forespurt %{time_ago}"
+
msgid "Requested design version does not exist."
msgstr ""
msgid "Requested states are invalid"
-msgstr ""
+msgstr "De forespurte tilstandene er ugyldige"
msgid "Requests"
-msgstr ""
+msgstr "Forespørsler"
msgid "Requests Profiles"
-msgstr ""
+msgstr "Forespørselsprofiler"
msgid "Requests to these domain(s)/address(es) on the local network will be allowed when local requests from hooks and services are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 or 127.0.0.0/28 are supported. Domain wildcards are not supported currently. Use comma, semicolon, or newline to separate multiple entries. The allowlist can hold a maximum of 1000 entries. Domains should use IDNA encoding. Ex: example.com, 192.168.1.1, 127.0.0.0/28, xn--itlab-j1a.com."
+msgstr "Forespørsler til disse domenene/adressene i det lokale nettverket vil være tillatt når lokale forespørsler fra kroker og tjenester ikke er tillatt. IP-områder som 1:0:0:0:0:0:0:0/124 eller 127.0.0.0/28 støttes. Domene-jokertegn støttes ikke for øyeblikket. Bruk komma, semikolon eller ny linje for å skille flere oppføringer. Tillatelseslisten kan inneholde maksimalt 1000 oppføringer. Domener bør bruke IDNA-koding. F.eks.: example.com, 192.168.1.1, 127.0.0.0/28, xn--itlab-j1a.com."
+
+msgid "Require admin approval for new sign-ups"
msgstr ""
msgid "Require all users in this group to setup Two-factor authentication"
@@ -21097,28 +21831,28 @@ msgid "Require all users to accept Terms of Service and Privacy Policy when they
msgstr ""
msgid "Require user password to approve"
-msgstr ""
+msgstr "Krev brukerpassord for å godkjenne"
msgid "Require users to prove ownership of custom domains"
msgstr ""
msgid "Required approvals (%{approvals_given} given)"
-msgstr ""
+msgstr "Nødvendige godkjenninger (%{approvals_given} er gitt)"
msgid "Required approvals (%{approvals_given} given, you've approved)"
-msgstr ""
+msgstr "Nødvendige godkjenninger (%{approvals_given} gitt, som du har godkjent)"
msgid "Required in this project."
-msgstr ""
+msgstr "PÃ¥krevd i dette prosjektet."
msgid "Requirement %{reference} has been added"
-msgstr ""
+msgstr "Kravet %{reference} er lagt til"
msgid "Requirement %{reference} has been archived"
-msgstr ""
+msgstr "Kravet %{reference} har blitt arkivert"
msgid "Requirement %{reference} has been reopened"
-msgstr ""
+msgstr "Kravet %{reference} har blitt gjenåpnet"
msgid "Requirement %{reference} has been updated"
msgstr ""
@@ -21127,38 +21861,38 @@ msgid "Requirement title cannot have more than %{limit} characters."
msgstr ""
msgid "Requirements"
-msgstr ""
+msgstr "Krav"
msgid "Requirements can be based on users, stakeholders, system, software, or anything else you find important to capture."
msgstr ""
msgid "Requires approval from %{names}."
msgid_plural "Requires %{count} more approvals from %{names}."
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "Krever godkjenning fra %{names}."
+msgstr[1] "Krever %{count} flere godkjenninger fra %{names}."
msgid "Requires approval."
msgid_plural "Requires %d more approvals."
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "Krever godkjennelse."
+msgstr[1] "Krever %d godkjenninger til."
msgid "Requires values to meet regular expression requirements."
msgstr ""
msgid "Resend Request"
-msgstr ""
+msgstr "Send forespørsel på nytt"
msgid "Resend confirmation email"
-msgstr ""
+msgstr "Send e-postbekreftelse på nytt"
msgid "Resend invite"
-msgstr ""
+msgstr "Send invitasjonen på nytt"
msgid "Resend it"
-msgstr ""
+msgstr "Send det på nytt"
msgid "Reset authorization key"
-msgstr ""
+msgstr "Tilbakestill autorisasjonsnøkkel"
msgid "Reset authorization key?"
msgstr ""
@@ -21167,16 +21901,16 @@ msgid "Reset health check access token"
msgstr ""
msgid "Reset key"
-msgstr ""
+msgstr "Tilbakestill nøkkel"
msgid "Reset runners registration token"
msgstr ""
msgid "Reset template"
-msgstr ""
+msgstr "Tilbakestill mal"
msgid "Reset to project defaults"
-msgstr ""
+msgstr "Tilbakestill til prosjektets standarder"
msgid "Resetting the authorization key for this project will require updating the authorization key in every alert source it is enabled in."
msgstr ""
@@ -21185,13 +21919,13 @@ msgid "Resetting the authorization key will invalidate the previous key. Existin
msgstr ""
msgid "Resolve"
-msgstr ""
+msgstr "Løs"
msgid "Resolve all threads in new issue"
-msgstr ""
+msgstr "Oppklar alle tråder i en ny sak"
msgid "Resolve conflicts"
-msgstr ""
+msgstr "Løs konflikter"
msgid "Resolve conflicts on source branch"
msgstr ""
@@ -21200,70 +21934,67 @@ msgid "Resolve these conflicts or ask someone with write access to this reposito
msgstr ""
msgid "Resolve thread"
-msgstr ""
+msgstr "Oppklar tråden"
msgid "Resolved"
-msgstr ""
+msgstr "Løst"
msgid "Resolved 1 discussion."
-msgstr ""
+msgstr "Løste 1 diskusjon."
msgid "Resolved all discussions."
-msgstr ""
+msgstr "Løste alle diskusjoner."
msgid "Resolved by"
-msgstr ""
+msgstr "Løst av"
msgid "Resolved by %{name}"
-msgstr ""
-
-msgid "Resolved by %{resolvedByName}"
-msgstr ""
+msgstr "Løst av %{name}"
msgid "Resolves IP addresses once and uses them to submit requests"
msgstr ""
msgid "Response"
-msgstr ""
+msgstr "Svar"
msgid "Response Headers"
msgstr ""
msgid "Response Status"
-msgstr ""
+msgstr "Responsstatus"
msgid "Response didn't include `service_desk_address`"
msgstr ""
msgid "Response metrics (AWS ELB)"
-msgstr ""
+msgstr "Responsmåltall (AWS ELB)"
msgid "Response metrics (Custom)"
-msgstr ""
+msgstr "Responsmåltall (Tilpasset)"
msgid "Response metrics (HA Proxy)"
-msgstr ""
+msgstr "Responsmåltall (HA Proxy)"
msgid "Response metrics (NGINX Ingress VTS)"
-msgstr ""
+msgstr "Responsmåltall (NGINX Ingress VTS)"
msgid "Response metrics (NGINX Ingress)"
-msgstr ""
+msgstr "Responsmåltall (NGINX Ingress)"
msgid "Response metrics (NGINX)"
-msgstr ""
+msgstr "Responsmåltall (NGINX)"
msgid "Restart Terminal"
-msgstr ""
+msgstr "Start terminalen på nytt"
msgid "Restore"
-msgstr ""
+msgstr "Gjenopprett"
msgid "Restore group"
-msgstr ""
+msgstr "Gjenopprett gruppe"
msgid "Restore project"
-msgstr ""
+msgstr "Gjenopprett prosjekt"
msgid "Restoring the group will prevent the group, its subgroups and projects from being removed on this date."
msgstr ""
@@ -21278,51 +22009,51 @@ msgid "Restricts sign-ups for email addresses that match the given regex. See th
msgstr ""
msgid "Resume"
-msgstr ""
+msgstr "Fortsett"
msgid "Resync"
-msgstr ""
+msgstr "Re-synk"
msgid "Resync all"
-msgstr ""
+msgstr "Re-synk alle"
msgid "Resync all %{replicableType}"
msgstr ""
msgid "Retry"
-msgstr ""
+msgstr "Forsøk igjen"
msgid "Retry this job"
-msgstr ""
+msgstr "Prøv denne jobben på nytt"
msgid "Retry this job in order to create the necessary resources."
msgstr ""
msgid "Retry update"
-msgstr ""
+msgstr "Prøv oppdatering på nytt"
msgid "Retry verification"
-msgstr ""
+msgstr "Prøv verifikasjon på nytt"
msgid "Reveal value"
msgid_plural "Reveal values"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "Avslør verdi"
+msgstr[1] "Avslør verdier"
msgid "Reveal values"
-msgstr ""
+msgstr "Avslør verdier"
msgid "Revert this commit"
-msgstr ""
+msgstr "Tilbakestill denne commiten"
msgid "Revert this merge request"
msgstr ""
msgid "Review"
-msgstr ""
+msgstr "GÃ¥ gjennom"
msgid "Review App|View app"
-msgstr ""
+msgstr "Vis app"
msgid "Review App|View latest app"
msgstr ""
@@ -21331,7 +22062,7 @@ msgid "Review the process for configuring service providers in your identity pro
msgstr ""
msgid "Review time"
-msgstr ""
+msgstr "Gjennomgangstid"
msgid "Review time is defined as the time it takes from first comment until merged."
msgstr ""
@@ -21339,17 +22070,25 @@ msgstr ""
msgid "ReviewApp|Enable Review App"
msgstr ""
-msgid "Reviewing"
+msgid "Reviewer"
+msgid_plural "%d Reviewers"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Reviewer(s)"
msgstr ""
+msgid "Reviewing"
+msgstr "GÃ¥r gjennom"
+
msgid "Reviewing (merge request !%{mergeRequestId})"
msgstr ""
msgid "Revoke"
-msgstr ""
+msgstr "Tilbakekall"
msgid "Revoked"
-msgstr ""
+msgstr "Tilbakekalt"
msgid "Revoked impersonation token %{token_name}!"
msgstr ""
@@ -21361,26 +22100,29 @@ msgid "Revoked project access token %{project_access_token_name}!"
msgstr ""
msgid "RightSidebar|adding a"
-msgstr ""
+msgstr "legge til en"
msgid "RightSidebar|deleting the"
-msgstr ""
+msgstr "sletter"
msgid "Roadmap"
-msgstr ""
+msgstr "Veikart"
msgid "Role"
-msgstr ""
+msgstr "Rolle"
msgid "Rollback"
-msgstr ""
+msgstr "Tilbakeføring"
msgid "Rook"
msgstr ""
-msgid "Rule name is already taken."
+msgid "Ruby"
msgstr ""
+msgid "Rule name is already taken."
+msgstr "Dette regelnavnet er allerede brukt"
+
msgid "Rules that define what git pushes are accepted for a project in this group. All newly created projects in this group will use these settings."
msgstr ""
@@ -21433,7 +22175,7 @@ msgid "Runner will not receive any new jobs"
msgstr ""
msgid "Runners"
-msgstr ""
+msgstr "Løpere"
msgid "Runners API"
msgstr ""
@@ -21456,50 +22198,110 @@ msgstr ""
msgid "Runners page."
msgstr ""
+msgid "Runners|Active"
+msgstr ""
+
+msgid "Runners|Architecture"
+msgstr ""
+
+msgid "Runners|Can run untagged jobs"
+msgstr ""
+
+msgid "Runners|Description"
+msgstr ""
+
+msgid "Runners|Group"
+msgstr ""
+
+msgid "Runners|IP Address"
+msgstr ""
+
+msgid "Runners|Last contact"
+msgstr ""
+
+msgid "Runners|Locked to this project"
+msgstr ""
+
+msgid "Runners|Maximum job timeout"
+msgstr ""
+
+msgid "Runners|Name"
+msgstr ""
+
+msgid "Runners|Platform"
+msgstr ""
+
+msgid "Runners|Property Name"
+msgstr ""
+
+msgid "Runners|Protected"
+msgstr ""
+
+msgid "Runners|Revision"
+msgstr ""
+
+msgid "Runners|Shared"
+msgstr ""
+
+msgid "Runners|Specific"
+msgstr ""
+
+msgid "Runners|Tags"
+msgstr ""
+
+msgid "Runners|Value"
+msgstr ""
+
+msgid "Runners|Version"
+msgstr ""
+
msgid "Runners|You have used %{quotaUsed} out of %{quotaLimit} of your shared Runners pipeline minutes."
msgstr ""
msgid "Running"
-msgstr ""
+msgstr "Kjører"
msgid "Running…"
-msgstr ""
+msgstr "Kjører …"
msgid "Runs a number of housekeeping tasks within the current repository, such as compressing file revisions and removing unreachable objects."
msgstr ""
-msgid "SAML SSO"
+msgid "SAML"
msgstr ""
+msgid "SAML SSO"
+msgstr "SAML SSO"
+
msgid "SAML SSO for %{group_name}"
-msgstr ""
+msgstr "SAML SSO for %{group_name}"
msgid "SAML discovery tokens"
-msgstr ""
+msgstr "SAML-oppdagelsessjetonger"
msgid "SAML for %{group_name}"
-msgstr ""
+msgstr "SAML for %{group_name}"
msgid "SAST Configuration"
-msgstr ""
+msgstr "SAST-oppsett"
msgid "SHA256"
-msgstr ""
+msgstr "SHA256"
msgid "SSH Key"
-msgstr ""
+msgstr "SSH-nøkkel"
msgid "SSH Keys"
-msgstr ""
+msgstr "SSH-nøkler"
msgid "SSH Keys Help"
-msgstr ""
+msgstr "SSH-nøkkelhjelp"
msgid "SSH host key fingerprints"
msgstr ""
msgid "SSH host keys"
-msgstr ""
+msgstr "SSH-vertsnøkler"
msgid "SSH host keys are not available on this system. Please use %{ssh_keyscan} command or contact your GitLab administrator for more information."
msgstr ""
@@ -21508,40 +22310,43 @@ msgid "SSH keys allow you to establish a secure connection between your computer
msgstr ""
msgid "SSH public key"
-msgstr ""
+msgstr "Offentlig SSH-nøkkel"
msgid "SSL Verification:"
-msgstr ""
+msgstr "SSL-verifisering:"
msgid "Saturday"
-msgstr ""
+msgstr "Lørdag"
msgid "Save"
+msgstr "Lagre"
+
+msgid "Save %{name} size limits"
msgstr ""
msgid "Save Changes"
-msgstr ""
+msgstr "Lagre endringene"
msgid "Save Push Rules"
msgstr ""
msgid "Save anyway"
-msgstr ""
+msgstr "Lagre likevel"
msgid "Save application"
-msgstr ""
+msgstr "Lagre applikasjon"
msgid "Save changes"
-msgstr ""
+msgstr "Lagre endringer"
msgid "Save changes before testing"
-msgstr ""
+msgstr "Lagre endringer før testing"
msgid "Save comment"
-msgstr ""
+msgstr "Lagre kommentar"
msgid "Save password"
-msgstr ""
+msgstr "Lagre passord"
msgid "Save pipeline schedule"
msgstr ""
@@ -21549,26 +22354,23 @@ msgstr ""
msgid "Save space and find tags in the Container Registry more easily. Enable the cleanup policy to remove stale tags and keep only the ones you need."
msgstr ""
-msgid "Save template"
-msgstr ""
-
msgid "Save variables"
-msgstr ""
+msgstr "Lagre variabler"
msgid "Saved scan settings and target site settings which are reusable."
msgstr ""
msgid "Saving"
-msgstr ""
+msgstr "Lagrer"
msgid "Saving project."
-msgstr ""
+msgstr "Lagrer prosjekt."
msgid "Schedule a new pipeline"
-msgstr ""
+msgstr "Planlegg en ny rørledning"
msgid "Scheduled"
-msgstr ""
+msgstr "Planlagt"
msgid "Scheduled Deletion At - %{permanent_deletion_time}"
msgstr ""
@@ -21580,166 +22382,160 @@ msgid "Scheduled to merge this merge request when the pipeline succeeds."
msgstr ""
msgid "Schedules"
-msgstr ""
+msgstr "Tidsplaner"
msgid "Schedules to merge this merge request (%{strategy})."
msgstr ""
msgid "Scheduling"
-msgstr ""
+msgstr "Planlegging"
msgid "Scheduling Pipelines"
msgstr ""
msgid "Scope"
-msgstr ""
-
-msgid "Scope not supported with disabled 'users_search' feature!"
-msgstr ""
+msgstr "Omfang"
msgid "Scoped issue boards"
msgstr ""
msgid "Scopes"
-msgstr ""
+msgstr "Omfang"
msgid "Scopes can't be blank"
-msgstr ""
+msgstr "Omfang kan ikke være tomme"
msgid "Score"
-msgstr ""
+msgstr "Score"
msgid "Scroll down"
-msgstr ""
+msgstr "Rull nedover"
msgid "Scroll down to %{strong_open}Google Code Project Hosting%{strong_close} and enable the switch on the right."
msgstr ""
msgid "Scroll left"
-msgstr ""
+msgstr "Rull til venstre"
msgid "Scroll right"
-msgstr ""
+msgstr "Rull til høyre"
msgid "Scroll to bottom"
-msgstr ""
+msgstr "Bla til bunn"
msgid "Scroll to top"
-msgstr ""
+msgstr "Bla til toppen"
msgid "Scroll up"
-msgstr ""
+msgstr "Rull oppover"
msgid "Search"
-msgstr ""
+msgstr "Søk"
msgid "Search Jira issues"
-msgstr ""
+msgstr "Søk blant Jira-saker"
msgid "Search Milestones"
-msgstr ""
+msgstr "Søk blant milepæler"
msgid "Search an environment spec"
msgstr ""
msgid "Search authors"
-msgstr ""
+msgstr "Søk etter skapere"
msgid "Search branches"
-msgstr ""
+msgstr "Søk i grener"
msgid "Search branches and tags"
-msgstr ""
+msgstr "Søk i grener og merker"
msgid "Search branches, tags, and commits"
-msgstr ""
+msgstr "Søk blant grener, etiketter, og commiter"
msgid "Search by Git revision"
msgstr ""
msgid "Search by author"
-msgstr ""
+msgstr "Søk etter forfatter"
msgid "Search by commit title or SHA"
-msgstr ""
+msgstr "Søk etter commit-tittel eller SHA"
msgid "Search by message"
-msgstr ""
+msgstr "Søk etter melding"
msgid "Search by name"
-msgstr ""
+msgstr "Søk etter navn"
msgid "Search files"
-msgstr ""
+msgstr "Søk i filer"
msgid "Search for Namespace"
-msgstr ""
+msgstr "Søk etter navneområde"
msgid "Search for a LDAP group"
-msgstr ""
+msgstr "Søk etter en LDAP-gruppe"
msgid "Search for a group"
-msgstr ""
+msgstr "Søk etter en gruppe"
msgid "Search for a user"
-msgstr ""
+msgstr "Søk etter en bruker"
msgid "Search for projects, issues, etc."
-msgstr ""
+msgstr "Søk etter prosjekter, saker, etc."
msgid "Search for this text"
-msgstr ""
+msgstr "Søk etter denne teksten"
msgid "Search forks"
-msgstr ""
+msgstr "Velg utgreininger"
msgid "Search groups"
-msgstr ""
+msgstr "Søk etter grupper"
msgid "Search merge requests"
-msgstr ""
+msgstr "Søke i flettede forespørsler"
msgid "Search milestones"
-msgstr ""
+msgstr "Søk i milepæler"
msgid "Search or filter results..."
-msgstr ""
+msgstr "Søk eller filtrer resultater …"
msgid "Search or filter results…"
-msgstr ""
+msgstr "Søk blant eller filtrer resultater …"
msgid "Search or jump to…"
-msgstr ""
+msgstr "Søk eller hopp til …"
msgid "Search project"
-msgstr ""
+msgstr "Søk i prosjekt"
msgid "Search projects"
-msgstr ""
+msgstr "Søk i prosjekter"
msgid "Search projects..."
-msgstr ""
+msgstr "Søk blant prosjekter …"
msgid "Search requirements"
msgstr ""
-msgid "Search results…"
-msgstr ""
-
msgid "Search users"
-msgstr ""
+msgstr "Søk etter brukere"
msgid "Search users or groups"
-msgstr ""
+msgstr "Søk blant brukere eller grupper"
msgid "Search your project dependencies for their licenses and apply policies."
msgstr ""
msgid "Search your projects"
-msgstr ""
+msgstr "Søk i dine prosjekter"
msgid "SearchAutocomplete|All GitLab"
-msgstr ""
+msgstr "Hele GitLab"
msgid "SearchAutocomplete|Issues I've created"
msgstr ""
@@ -21754,31 +22550,31 @@ msgid "SearchAutocomplete|Merge requests assigned to me"
msgstr ""
msgid "SearchAutocomplete|in all GitLab"
-msgstr ""
+msgstr "på hele GitLab"
msgid "SearchAutocomplete|in group %{groupName}"
-msgstr ""
+msgstr "i gruppen %{groupName}"
msgid "SearchAutocomplete|in project %{projectName}"
-msgstr ""
+msgstr "i prosjektet %{projectName}"
msgid "SearchCodeResults|in"
-msgstr ""
+msgstr "i"
msgid "SearchCodeResults|of %{link_to_project}"
-msgstr ""
+msgstr "av %{link_to_project}"
msgid "SearchResults|Showing %{count} %{scope} for%{term_element}"
-msgstr ""
+msgstr "Viser %{count} %{scope} for%{term_element}"
msgid "SearchResults|Showing %{count} %{scope} for%{term_element} in your personal and project snippets"
-msgstr ""
+msgstr "Viser %{count} %{scope} for%{term_element} i dine personlige og prosjektmessige utdrag"
msgid "SearchResults|Showing %{from} - %{to} of %{count} %{scope} for%{term_element}"
-msgstr ""
+msgstr "Viser %{from} - %{to} av %{count} %{scope} for%{term_element}"
msgid "SearchResults|Showing %{from} - %{to} of %{count} %{scope} for%{term_element} in your personal and project snippets"
-msgstr ""
+msgstr "Viser %{from} - %{to} av %{count} %{scope} for%{term_element} i dine personlige og prosjektmessige utdrag"
msgid "SearchResults|We couldn't find any %{scope} matching %{term}"
msgstr ""
@@ -21790,18 +22586,23 @@ msgstr[1] ""
msgid "SearchResults|comment"
msgid_plural "SearchResults|comments"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "kommentar"
+msgstr[1] "kommentarer"
msgid "SearchResults|commit"
msgid_plural "SearchResults|commits"
+msgstr[0] "commit"
+msgstr[1] "commiter"
+
+msgid "SearchResults|epic"
+msgid_plural "SearchResults|epics"
msgstr[0] ""
msgstr[1] ""
msgid "SearchResults|issue"
msgid_plural "SearchResults|issues"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "sak"
+msgstr[1] "saker"
msgid "SearchResults|merge request"
msgid_plural "SearchResults|merge requests"
@@ -21810,28 +22611,28 @@ msgstr[1] ""
msgid "SearchResults|milestone"
msgid_plural "SearchResults|milestones"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "milepæl"
+msgstr[1] "milepæler"
msgid "SearchResults|project"
msgid_plural "SearchResults|projects"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "prosjekt"
+msgstr[1] "prosjekter"
msgid "SearchResults|snippet"
msgid_plural "SearchResults|snippets"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "utdrag"
+msgstr[1] "utdrag"
msgid "SearchResults|user"
msgid_plural "SearchResults|users"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "bruker"
+msgstr[1] "brukere"
msgid "SearchResults|wiki result"
msgid_plural "SearchResults|wiki results"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "wiki-resultat"
+msgstr[1] "wiki-resultater"
msgid "Searching by both author and message is currently not supported."
msgstr ""
@@ -21842,38 +22643,38 @@ msgstr ""
msgid "Seat Link is disabled, and cannot be configured through this form."
msgstr ""
-msgid "Seats currently in use"
+msgid "Seats usage data as of %{last_enqueue_time}"
msgstr ""
-msgid "Seats in license"
+msgid "Seats usage data is updated every day at 12:00pm UTC"
msgstr ""
msgid "Secondary"
-msgstr ""
+msgstr "Sekundær"
msgid "Seconds"
-msgstr ""
+msgstr "Sekunder"
msgid "Secret"
-msgstr ""
+msgstr "Hemmelig"
msgid "Secret Detection"
-msgstr ""
+msgstr "Hemmelig oppdagelse"
msgid "Security"
-msgstr ""
+msgstr "Sikkerhet"
msgid "Security & Compliance"
msgstr ""
msgid "Security Configuration"
-msgstr ""
+msgstr "Sikkerhetsoppsett"
msgid "Security Dashboard"
-msgstr ""
+msgstr "Sikkerhetskontrollpanel"
msgid "Security dashboard"
-msgstr ""
+msgstr "Sikkerhetskontrollpanel"
msgid "Security report is out of date. Please update your branch with the latest changes from the target branch (%{targetBranchName})"
msgstr ""
@@ -21899,9 +22700,12 @@ msgstr ""
msgid "SecurityConfiguration|Available for on-demand DAST"
msgstr ""
-msgid "SecurityConfiguration|Configure"
+msgid "SecurityConfiguration|By default, all analyzers are applied in order to cover all languages across your project, and only run if the language is detected in the Merge Request."
msgstr ""
+msgid "SecurityConfiguration|Configure"
+msgstr "Sett opp"
+
msgid "SecurityConfiguration|Could not retrieve configuration data. Please refresh the page, or try again later."
msgstr ""
@@ -21909,40 +22713,43 @@ msgid "SecurityConfiguration|Create Merge Request"
msgstr ""
msgid "SecurityConfiguration|Customize common SAST settings to suit your requirements. Configuration changes made here override those provided by GitLab and are excluded from updates. For details of more advanced configuration options, see the %{linkStart}GitLab SAST documentation%{linkEnd}."
-msgstr ""
+msgstr "Tilpass vanlige SAST-innstillinger etter dine behov. Oppsettsendringer som er gjort her, overstyrer de som er gitt av GitLab og er ekskludert fra oppdateringer. For detaljer om mer avanserte konfigurasjonsalternativer, se %{linkStart}GitLab sin SAST-dokumentasjon%{linkEnd}."
msgid "SecurityConfiguration|Enable"
-msgstr ""
+msgstr "Skru på"
msgid "SecurityConfiguration|Enable via Merge Request"
msgstr ""
msgid "SecurityConfiguration|Enabled"
-msgstr ""
+msgstr "Skrudd på"
msgid "SecurityConfiguration|Enabled with Auto DevOps"
-msgstr ""
+msgstr "Skrudd på gjennom Auto DevOps"
msgid "SecurityConfiguration|Feature documentation for %{featureName}"
msgstr ""
msgid "SecurityConfiguration|Manage"
+msgstr "Behandle"
+
+msgid "SecurityConfiguration|More information"
msgstr ""
msgid "SecurityConfiguration|Not enabled"
+msgstr "Ikke skrudd på"
+
+msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
msgid "SecurityConfiguration|SAST Configuration"
-msgstr ""
+msgstr "SAST-oppsett"
msgid "SecurityConfiguration|Security Control"
-msgstr ""
-
-msgid "SecurityConfiguration|See documentation"
-msgstr ""
+msgstr "Sikkerhetskontroll"
msgid "SecurityConfiguration|Status"
-msgstr ""
+msgstr "Status"
msgid "SecurityConfiguration|Testing & Compliance"
msgstr ""
@@ -21950,26 +22757,29 @@ msgstr ""
msgid "SecurityConfiguration|Using custom settings. You won't receive automatic updates on this variable. %{anchorStart}Restore to default%{anchorEnd}"
msgstr ""
+msgid "SecurityConfiguration|View history"
+msgstr ""
+
msgid "SecurityConfiguration|You can quickly enable all security scanning tools by enabling %{linkStart}Auto DevOps%{linkEnd}."
msgstr ""
msgid "SecurityReports|%{firstProject} and %{secondProject}"
-msgstr ""
+msgstr "%{firstProject} og %{secondProject}"
msgid "SecurityReports|%{firstProject}, %{secondProject}, and %{rest}"
-msgstr ""
+msgstr "%{firstProject}, %{secondProject}, og %{rest}"
msgid "SecurityReports|Add a project to your dashboard"
-msgstr ""
+msgstr "Legg til et prosjekt på kontrollpanelet ditt"
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 ""
+msgstr "Legg til eller fjern prosjekter som skal overvåkes i sikkerhetsområdet. Prosjekter som er inkludert i denne listen vil få sine resultater vist i sikkerhetskontrollpanelet og sårbarhetsrapporten."
msgid "SecurityReports|Add projects"
-msgstr ""
+msgstr "Legg til prosjekter"
msgid "SecurityReports|Add projects to your group"
-msgstr ""
+msgstr "Legg til prosjekter til din gruppe"
msgid "SecurityReports|Comment added to '%{vulnerabilityName}'"
msgstr ""
@@ -21981,28 +22791,28 @@ msgid "SecurityReports|Comment edited on '%{vulnerabilityName}'"
msgstr ""
msgid "SecurityReports|Create issue"
-msgstr ""
+msgstr "Opprett saker"
msgid "SecurityReports|Dismiss Selected"
-msgstr ""
+msgstr "Avvis de valgte"
msgid "SecurityReports|Dismiss vulnerability"
-msgstr ""
+msgstr "Avfei sårbarhet"
msgid "SecurityReports|Dismissed '%{vulnerabilityName}'"
-msgstr ""
+msgstr "Avfeide '%{vulnerabilityName}'"
msgid "SecurityReports|Dismissed '%{vulnerabilityName}'. Turn off the hide dismissed toggle to view."
msgstr ""
msgid "SecurityReports|Download Report"
-msgstr ""
+msgstr "Last ned rapport"
msgid "SecurityReports|Either you don't have permission to view this dashboard or the dashboard has not been setup. Please check your permission settings with your administrator or check your dashboard configurations to proceed."
-msgstr ""
+msgstr "Enten har du ikke tillatelse til å se dette kontrollpanelet, eller så har kontrollpanelet ikke blitt konfigurert. Kontroller tillatelsesinnstillingene dine med administratoren din, eller sjekk kontrollpanelkonfigurasjonene sine for å fortsette."
msgid "SecurityReports|Ensure that %{trackingStart}issue tracking%{trackingEnd} is enabled for this project and you have %{permissionsStart}permission to create new issues%{permissionsEnd}."
-msgstr ""
+msgstr "Forsikre deg om at %{trackingStart}sakssporing%{trackingEnd} er aktivert for dette prosjektet, og at du har %{permissionsStart}tillatelser til å opprette nye saker%{permissionsEnd}."
msgid "SecurityReports|Error fetching the vulnerability counts. Please check your network connection and try again."
msgstr ""
@@ -22020,7 +22830,7 @@ msgid "SecurityReports|Hide dismissed"
msgstr ""
msgid "SecurityReports|Issue Created"
-msgstr ""
+msgstr "Sak opprettet"
msgid "SecurityReports|Issues created from a vulnerability cannot be removed."
msgstr ""
@@ -22028,9 +22838,6 @@ msgstr ""
msgid "SecurityReports|Learn more about setting up your dashboard"
msgstr ""
-msgid "SecurityReports|Load more vulnerabilities"
-msgstr ""
-
msgid "SecurityReports|Monitor vulnerabilities in your code"
msgstr ""
@@ -22038,40 +22845,40 @@ msgid "SecurityReports|Monitored projects"
msgstr ""
msgid "SecurityReports|More info"
-msgstr ""
+msgstr "Mere info"
msgid "SecurityReports|More information"
-msgstr ""
+msgstr "Mere informasjon"
msgid "SecurityReports|No vulnerabilities found"
-msgstr ""
+msgstr "Ingen sårbarheter funnet"
msgid "SecurityReports|No vulnerabilities found for this pipeline"
msgstr ""
msgid "SecurityReports|Oops, something doesn't seem right."
-msgstr ""
+msgstr "Oi sann, noe ser ikke riktig ut."
msgid "SecurityReports|Project"
-msgstr ""
+msgstr "Prosjekt"
msgid "SecurityReports|Project was not found or you do not have permission to add this project to Security Dashboards."
msgstr ""
msgid "SecurityReports|Projects added"
-msgstr ""
+msgstr "Prosjekter lagt til"
msgid "SecurityReports|Remove project from dashboard"
-msgstr ""
+msgstr "Fjern prosjekt fra kontrollpanelet"
msgid "SecurityReports|Scan details"
-msgstr ""
+msgstr "Skanningsdetaljer"
msgid "SecurityReports|Scanner"
-msgstr ""
+msgstr "Skanner"
msgid "SecurityReports|Security Dashboard"
-msgstr ""
+msgstr "Sikkerhetskontrollpanel"
msgid "SecurityReports|Security reports can only be accessed by authorized users."
msgstr ""
@@ -22080,16 +22887,16 @@ msgid "SecurityReports|Select a project to add by using the project search field
msgstr ""
msgid "SecurityReports|Select a reason"
-msgstr ""
+msgstr "Velg en årsak"
msgid "SecurityReports|Severity"
-msgstr ""
+msgstr "Alvorlighet"
msgid "SecurityReports|Sorry, your filter produced no results"
msgstr ""
msgid "SecurityReports|Status"
-msgstr ""
+msgstr "Status"
msgid "SecurityReports|The rating \"unknown\" indicates that the underlying scanner doesn’t contain or provide a severity rating."
msgstr ""
@@ -22104,22 +22911,22 @@ msgid "SecurityReports|The security dashboard displays the latest security repor
msgstr ""
msgid "SecurityReports|There was an error adding the comment."
-msgstr ""
+msgstr "Det oppstod en feil under tillegging av kommentaren."
msgid "SecurityReports|There was an error creating the issue."
-msgstr ""
+msgstr "En feil oppstod under oppretting av saken."
msgid "SecurityReports|There was an error creating the merge request."
-msgstr ""
+msgstr "En feil oppstod under oppretting av fletteforespørselen."
msgid "SecurityReports|There was an error deleting the comment."
-msgstr ""
+msgstr "Det oppstod en feil under sletting av kommentaren."
msgid "SecurityReports|There was an error dismissing the vulnerabilities."
-msgstr ""
+msgstr "Det oppstod en feil under avfeiing av sårbarhetene."
msgid "SecurityReports|There was an error dismissing the vulnerability."
-msgstr ""
+msgstr "Det oppstod en feil under avfeiing av sårbarheten."
msgid "SecurityReports|There was an error reverting the dismissal."
msgstr ""
@@ -22128,7 +22935,7 @@ msgid "SecurityReports|There was an error reverting this dismissal."
msgstr ""
msgid "SecurityReports|There was an error while generating the report."
-msgstr ""
+msgstr "En feil oppstod under generering av rapporten."
msgid "SecurityReports|To widen your search, change or remove filters above"
msgstr ""
@@ -22137,16 +22944,16 @@ msgid "SecurityReports|Unable to add %{invalidProjectsMessage}: %{errorMessage}"
msgstr ""
msgid "SecurityReports|Unable to add %{invalidProjects}"
-msgstr ""
+msgstr "Klarte ikke å legge til %{invalidProjects}"
msgid "SecurityReports|Undo dismiss"
msgstr ""
msgid "SecurityReports|Vulnerability Report"
-msgstr ""
+msgstr "SÃ¥rbarhetsrapport"
msgid "SecurityReports|While it's rare to have no vulnerabilities for your pipeline, it can happen. In any event, we ask that you double check your settings to make sure all security scanning jobs have passed successfully."
-msgstr ""
+msgstr "Selv om det er sjeldent at du ikke har sårbarheter i rørledningen din, kan det skje. I alle fall ber vi deg dobbeltsjekke innstillingene dine for å forsikre om at alle sikkerhetsskanningsjobber har blitt vellykket bestått."
msgid "SecurityReports|While it's rare to have no vulnerabilities, it can happen. In any event, we ask that you double check your settings to make sure you've set up your dashboard correctly."
msgstr ""
@@ -22161,34 +22968,34 @@ msgid "SecurityReports|You must sign in as an authorized user to see this report
msgstr ""
msgid "SecurityReports|[No reason]"
-msgstr ""
+msgstr "[Ingen grunn]"
msgid "See GitLab's %{password_policy_guidelines}"
-msgstr ""
+msgstr "Se GitLab sine %{password_policy_guidelines}"
msgid "See metrics"
-msgstr ""
+msgstr "Se målinger"
msgid "See the affected projects in the GitLab admin panel"
msgstr ""
msgid "See what's new at GitLab"
-msgstr ""
+msgstr "Se hva som er nytt hos GitLab"
msgid "Select"
-msgstr ""
+msgstr "Velg"
msgid "Select Archive Format"
-msgstr ""
+msgstr "Velg arkivformat"
msgid "Select Git revision"
-msgstr ""
+msgstr "Velg Git-revisjon"
msgid "Select GitLab project to link with your Slack team"
msgstr ""
msgid "Select Page"
-msgstr ""
+msgstr "Velg side"
msgid "Select Stack"
msgstr ""
@@ -22197,154 +23004,154 @@ msgid "Select a file from the left sidebar to begin editing. Afterwards, you'll
msgstr ""
msgid "Select a group to invite"
-msgstr ""
+msgstr "Velg en gruppe du ønsker å invitere"
msgid "Select a label"
-msgstr ""
+msgstr "Velg et stempel"
msgid "Select a namespace to fork the project"
-msgstr ""
+msgstr "Velg et navneområde for å utgreine prosjektet"
msgid "Select a new namespace"
-msgstr ""
+msgstr "Velg et nytt navnefelt"
msgid "Select a project"
-msgstr ""
+msgstr "Velg et prosjekt"
msgid "Select a project to read Insights configuration file"
msgstr ""
msgid "Select a reason"
-msgstr ""
+msgstr "Velg en årsak"
msgid "Select a repository"
-msgstr ""
+msgstr "Velg et kodelager"
msgid "Select a template repository"
-msgstr ""
+msgstr "Velg et mal-kodelager"
msgid "Select a template type"
-msgstr ""
+msgstr "Velg en maltype"
msgid "Select a timezone"
-msgstr ""
+msgstr "Velg en tidssone"
msgid "Select all"
-msgstr ""
+msgstr "Velg alt"
msgid "Select an existing Kubernetes cluster or create a new one"
-msgstr ""
+msgstr "Velg en eksisterende Kubernetes-klynge eller opprett en ny"
msgid "Select assignee"
-msgstr ""
+msgstr "Velg tilordnet"
msgid "Select branch"
-msgstr ""
+msgstr "Velg gren"
msgid "Select branch/tag"
-msgstr ""
+msgstr "Velg gren/etikett"
msgid "Select due date"
-msgstr ""
+msgstr "Velg måldato"
msgid "Select epic"
-msgstr ""
+msgstr "Velg epos"
msgid "Select file"
-msgstr ""
+msgstr "Velg fil"
msgid "Select group or project"
-msgstr ""
+msgstr "Velg gruppe eller prosjekt"
msgid "Select groups to replicate"
msgstr ""
msgid "Select health status"
-msgstr ""
+msgstr "Velg helsestatus"
msgid "Select label"
-msgstr ""
+msgstr "Velg stempel"
msgid "Select labels"
-msgstr ""
+msgstr "Velg stempler"
msgid "Select merge moment"
msgstr ""
msgid "Select milestone"
-msgstr ""
+msgstr "Velg milepæl"
msgid "Select private project"
-msgstr ""
+msgstr "Velg privat prosjekt"
msgid "Select project"
-msgstr ""
+msgstr "Velg prosjekt"
msgid "Select project and zone to choose machine type"
-msgstr ""
+msgstr "Velg prosjekt og sone for å velge maskintype"
msgid "Select project to choose zone"
-msgstr ""
+msgstr "Velg prosjekt for å velge sone"
msgid "Select projects"
-msgstr ""
+msgstr "Velg prosjekter"
msgid "Select projects you want to import."
-msgstr ""
+msgstr "Velg prosjekter du ønsker å importere."
msgid "Select required regulatory standard"
msgstr ""
msgid "Select shards to replicate"
-msgstr ""
+msgstr "Velg skår å replikere"
msgid "Select source"
-msgstr ""
+msgstr "Velg kilde"
msgid "Select source branch"
-msgstr ""
+msgstr "Velg kildegren"
msgid "Select start date"
-msgstr ""
+msgstr "Velg startdato"
msgid "Select status"
-msgstr ""
+msgstr "Velg status"
-msgid "Select strategy activation method"
+msgid "Select strategy activation method."
msgstr ""
msgid "Select subscription"
-msgstr ""
+msgstr "Velg abonnement"
msgid "Select target branch"
-msgstr ""
+msgstr "Velg målgren"
msgid "Select the branch you want to set as the default for this project. All merge requests and commits will automatically be made against this branch unless you specify a different one."
-msgstr ""
+msgstr "Velg grenen du vil angi som standarden for dette prosjektet. Alle fletteforespørsler og commiter vil automatisk bli utført mot denne grenen med mindre du spesifiserer en annen en."
msgid "Select the custom project template source group."
msgstr ""
-msgid "Select timeframe"
+msgid "Select the environment scope for this feature flag."
msgstr ""
msgid "Select timezone"
-msgstr ""
+msgstr "Velg tidssone"
msgid "Select type"
-msgstr ""
+msgstr "Velg type"
msgid "Select user"
-msgstr ""
+msgstr "Velg user"
msgid "Selected commits"
-msgstr ""
+msgstr "Valgte commiter"
msgid "Selected levels cannot be used by non-admin users for groups, projects or snippets. If the public level is restricted, user profiles are only visible to logged in users."
-msgstr ""
+msgstr "De valgte nivåene kan ikke brukes av ikke-administratorbrukere for grupper, prosjekter eller utdrag. Hvis det offentlige nivået er begrenset, er brukerprofilene bare synlige for påloggede brukere."
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 ""
+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 "Selective synchronization"
msgstr ""
@@ -22389,19 +23196,19 @@ msgid "Send a separate email notification to Developers."
msgstr ""
msgid "Send confirmation email"
-msgstr ""
+msgstr "Send bekreftelses-E-post"
msgid "Send email"
-msgstr ""
+msgstr "Send en E-post"
msgid "Send email notification"
-msgstr ""
+msgstr "Send E-postvarsel"
msgid "Send message"
-msgstr ""
+msgstr "Send melding"
msgid "Send report"
-msgstr ""
+msgstr "Send inn rapport"
msgid "Send usage data"
msgstr ""
@@ -22413,13 +23220,13 @@ msgid "Sentry event"
msgstr ""
msgid "Sep"
-msgstr ""
+msgstr "Sep"
msgid "Separate topics with commas."
msgstr ""
msgid "September"
-msgstr ""
+msgstr "September"
msgid "SeriesFinalConjunction|and"
msgstr ""
@@ -22431,7 +23238,7 @@ msgid "Server supports batch API only, please update your Git LFS client to vers
msgstr ""
msgid "Server version"
-msgstr ""
+msgstr "Serverversjon"
msgid "Serverless"
msgstr ""
@@ -22443,7 +23250,7 @@ msgid "ServerlessDetails|Function invocation metrics require Prometheus to be in
msgstr ""
msgid "ServerlessDetails|Install Prometheus"
-msgstr ""
+msgstr "Installer Prometheus"
msgid "ServerlessDetails|Invocation metrics loading or not available at this time."
msgstr ""
@@ -22452,10 +23259,10 @@ msgid "ServerlessDetails|Invocations"
msgstr ""
msgid "ServerlessDetails|Kubernetes Pods"
-msgstr ""
+msgstr "Kubernetes-podder"
msgid "ServerlessDetails|More information"
-msgstr ""
+msgstr "Mere informasjon"
msgid "ServerlessDetails|No pods loaded at this time."
msgstr ""
@@ -22464,13 +23271,13 @@ msgid "ServerlessDetails|Number of Kubernetes pods in use over time based on nec
msgstr ""
msgid "ServerlessDetails|pod in use"
-msgstr ""
+msgstr "pod i bruk"
msgid "ServerlessDetails|pods in use"
-msgstr ""
+msgstr "podder i bruk"
msgid "ServerlessURL|Copy URL"
-msgstr ""
+msgstr "Kopier URL"
msgid "Serverless|Getting started with serverless"
msgstr ""
@@ -22485,7 +23292,7 @@ msgid "Serverless|In order to start using functions as a service, you must first
msgstr ""
msgid "Serverless|Install Knative"
-msgstr ""
+msgstr "Installer Knative"
msgid "Serverless|Learn more about Serverless"
msgstr ""
@@ -22515,10 +23322,10 @@ msgid "Serverless|Your repository does not have a corresponding %{startTag}serve
msgstr ""
msgid "Service"
-msgstr ""
+msgstr "Tjeneste"
msgid "Service Desk"
-msgstr ""
+msgstr "Tjenestedesk"
msgid "Service Desk is enabled but not yet active"
msgstr ""
@@ -22533,10 +23340,10 @@ msgid "Service Templates"
msgstr ""
msgid "Service URL"
-msgstr ""
+msgstr "Tjeneste-URL"
msgid "Session duration (minutes)"
-msgstr ""
+msgstr "Øktvarighet (i minutter)"
msgid "Set %{epic_ref} as the parent epic."
msgstr ""
@@ -22545,7 +23352,7 @@ msgid "Set .gitlab-ci.yml to enable or configure SAST"
msgstr ""
msgid "Set .gitlab-ci.yml to enable or configure SAST security scanning using the GitLab managed template. You can [add variable overrides](https://docs.gitlab.com/ee/user/application_security/sast/#customizing-the-sast-settings) to customize SAST settings."
-msgstr ""
+msgstr "Angi .gitlab-ci.yml for å aktivere eller konfigurere SAST.sikkerhetsskanning ved hjelp av den GitLab-håndterte malen. Du kan [legge til variabel-overstyring](https://docs.gitlab.com/ee/user/application_security/sast/#customizing-the-sast-settings) for å tilpasse SAST-innstillinger."
msgid "Set a default template for issue descriptions."
msgstr ""
@@ -22566,7 +23373,7 @@ msgid "Set default and restrict visibility levels. Configure import sources and
msgstr ""
msgid "Set due date"
-msgstr ""
+msgstr "Bestem måldato"
msgid "Set instance-wide template repository"
msgstr ""
@@ -22574,14 +23381,17 @@ msgstr ""
msgid "Set iteration"
msgstr ""
+msgid "Set limit to 0 to allow any file size."
+msgstr ""
+
msgid "Set max session time for web terminal."
msgstr ""
msgid "Set milestone"
-msgstr ""
+msgstr "Bestem milepæl"
msgid "Set new password"
-msgstr ""
+msgstr "Bestem nytt passord"
msgid "Set notification email for abuse reports."
msgstr ""
@@ -22596,22 +23406,22 @@ msgid "Set requirements for a user to sign-in. Enable mandatory two-factor authe
msgstr ""
msgid "Set target branch"
-msgstr ""
+msgstr "Bestem målgren"
msgid "Set target branch to %{branch_name}."
-msgstr ""
+msgstr "Sett målgrenen til %{branch_name}."
msgid "Set the default expiration time for each job's artifacts. 0 for unlimited. The default unit is in seconds, but you can define an alternative. For example: %{code_open}4 mins 2 sec%{code_close}, %{code_open}2h42min%{code_close}."
-msgstr ""
+msgstr "Angi standard utløpstid for hver jobb. 0 for ubegrenset. Standardenheten er i sekunder, men du kan definere et alternativ. For eksempel: %{code_open}4 mins 2 sec%{code_close}, %{code_open}2h42min%{code_close}."
msgid "Set the default name of the initial branch when creating new repositories through the user interface."
msgstr ""
msgid "Set the due date to %{due_date}."
-msgstr ""
+msgstr "Sett måldatoen til %{due_date}."
msgid "Set the duration for which the jobs will be considered as old and expired. Once that time passes, the jobs will be archived and no longer able to be retried. Make it empty to never expire jobs. It has to be no less than 1 day, for example: %{code_open}15 days%{code_close}, %{code_open}1 month%{code_close}, %{code_open}2 years%{code_close}."
-msgstr ""
+msgstr "Angi hvor lenge jobbene skal betraktes som gamle og utløpte. Når den tiden har gått, vil jobbene arkiveres og vil ikke lenger kunne prøves på nytt. Gjør det tomt for at jobber aldri skal utløpe. Det må ikke være mindre enn 1 dag, for eksempel: %{code_open}15 dager%{code_close}, %{code_open}1 måned%{code_close}, %{code_open}2 år%{code_close}."
msgid "Set the iteration to %{iteration_reference}."
msgstr ""
@@ -22623,7 +23433,7 @@ msgid "Set the maximum number of pipeline minutes that a group can use on shared
msgstr ""
msgid "Set the milestone to %{milestone_reference}."
-msgstr ""
+msgstr "Sett milepælen til %{milestone_reference}."
msgid "Set the number of concurrent requests this secondary node will make to the primary node while backfilling."
msgstr ""
@@ -22635,16 +23445,16 @@ msgid "Set the timeout in seconds to send a secondary node status to the primary
msgstr ""
msgid "Set time estimate"
-msgstr ""
+msgstr "Bestem tidsanslag"
msgid "Set time estimate to %{time_estimate}."
msgstr ""
msgid "Set up CI/CD"
-msgstr ""
+msgstr "Sett opp CI/CD"
msgid "Set up Jira Integration"
-msgstr ""
+msgstr "Sett opp Jira-integrering"
msgid "Set up a %{type} Runner automatically"
msgstr ""
@@ -22652,14 +23462,17 @@ msgstr ""
msgid "Set up a %{type} Runner manually"
msgstr ""
+msgid "Set up a hardware device as a second factor to sign in."
+msgstr ""
+
msgid "Set up assertions/attributes/claims (email, first_name, last_name) and NameID according to %{docsLinkStart}the documentation %{icon}%{docsLinkEnd}"
msgstr ""
-msgid "Set up new U2F device"
+msgid "Set up new device"
msgstr ""
msgid "Set up new password"
-msgstr ""
+msgstr "Sett opp nytt passord"
msgid "Set up pipeline subscriptions for this project."
msgstr ""
@@ -22668,40 +23481,40 @@ msgid "Set up your project to automatically push and/or pull changes to/from ano
msgstr ""
msgid "Set weight"
-msgstr ""
+msgstr "Bestem vekt"
msgid "Set weight to %{weight}."
-msgstr ""
+msgstr "Sett vektlegging til %{weight}."
msgid "Set what should be replicated by choosing specific projects or groups by the secondary node."
msgstr ""
msgid "SetPasswordToCloneLink|set a password"
-msgstr ""
+msgstr "bestem et passord"
msgid "SetStatusModal|Add status emoji"
-msgstr ""
+msgstr "Legg til status-emoji"
msgid "SetStatusModal|Clear status"
-msgstr ""
+msgstr "Tøm status"
msgid "SetStatusModal|Edit status"
-msgstr ""
+msgstr "Rediger status"
msgid "SetStatusModal|Remove status"
-msgstr ""
+msgstr "Fjern status"
msgid "SetStatusModal|Set a status"
-msgstr ""
+msgstr "Bestem en status"
msgid "SetStatusModal|Set status"
-msgstr ""
+msgstr "Bestem status"
msgid "SetStatusModal|Sorry, we weren't able to set your status. Please try again later."
msgstr ""
msgid "SetStatusModal|What's your status?"
-msgstr ""
+msgstr "Hva er statusen din?"
msgid "Sets %{epic_ref} as parent epic."
msgstr ""
@@ -22710,22 +23523,25 @@ msgid "Sets target branch to %{branch_name}."
msgstr ""
msgid "Sets the due date to %{due_date}."
-msgstr ""
+msgstr "Setter måldatoen til %{due_date}."
msgid "Sets the iteration to %{iteration_reference}."
msgstr ""
msgid "Sets the milestone to %{milestone_reference}."
-msgstr ""
+msgstr "Setter milepælen til %{milestone_reference}."
msgid "Sets time estimate to %{time_estimate}."
msgstr ""
msgid "Sets weight to %{weight}."
+msgstr "Setter vekten til %{weight}."
+
+msgid "Setting this to 0 means using the system default timeout value."
msgstr ""
msgid "Settings"
-msgstr ""
+msgstr "Alternativer"
msgid "Settings related to the use and experience of using GitLab's Package Registry."
msgstr ""
@@ -22734,19 +23550,28 @@ msgid "Settings to prevent self-approval across all projects in the instance. On
msgstr ""
msgid "Setup"
-msgstr ""
+msgstr "Oppsett"
msgid "Severity"
+msgstr "Alvorlighetsgrad"
+
+msgid "SeverityWidget|Severity"
msgstr ""
-msgid "Shards (%{shards})"
+msgid "SeverityWidget|Severity: %{severity}"
msgstr ""
-msgid "Shards to synchronize"
+msgid "SeverityWidget|There was an error while updating severity."
msgstr ""
+msgid "Shards (%{shards})"
+msgstr "Skår (%{shards})"
+
+msgid "Shards to synchronize"
+msgstr "Skår å synkronise"
+
msgid "Share"
-msgstr ""
+msgstr "Del"
msgid "Share the %{strong_open}GitLab single sign-on URL%{strong_close} with members so they can sign in to your group through your identity provider"
msgstr ""
@@ -22755,13 +23580,13 @@ msgid "Shared Runners"
msgstr ""
msgid "Shared projects"
-msgstr ""
+msgstr "Delte prosjekter"
msgid "Shared runners help link"
msgstr ""
msgid "SharedRunnersMinutesSettings|By resetting the pipeline minutes for this namespace, the currently used minutes will be set to zero."
-msgstr ""
+msgstr "Ved å tilbakestille rørledningsminuttene for dette navneområdet, blir de nåværende brukte minuttene satt til null."
msgid "SharedRunnersMinutesSettings|Reset pipeline minutes"
msgstr ""
@@ -22773,55 +23598,61 @@ msgid "Sherlock Transactions"
msgstr ""
msgid "Should you ever lose your phone or access to your one time password secret, each of these recovery codes can be used one time each to regain access to your account. Please save them in a safe place, or you %{b_start}will%{b_end} lose access to your account."
-msgstr ""
+msgstr "Hvis du noen gang mister telefonen eller tilgang til din éngangs passordhemmelighet, kan hver av disse gjenopprettingskodene brukes én gang hver for å få tilgang til kontoen din igjen. Vennligst lagre dem på et trygt sted, ellers vil du %{b_start}vil%{b_end} miste tilgang til kontoen din."
msgid "Show all activity"
-msgstr ""
+msgstr "Vis all aktivitet"
msgid "Show all members"
-msgstr ""
+msgstr "Vis alle medlemmer"
msgid "Show all requirements."
+msgstr "Vis alle krav."
+
+msgid "Show all test cases."
msgstr ""
msgid "Show archived projects"
-msgstr ""
+msgstr "Vis arkiverte prosjekter"
msgid "Show archived projects only"
-msgstr ""
+msgstr "Vis kun arkiverte prosjekter"
msgid "Show command"
-msgstr ""
+msgstr "Vis kommando"
msgid "Show comments"
+msgstr "Vis kommentarer"
+
+msgid "Show comments on this file"
msgstr ""
msgid "Show comments only"
-msgstr ""
+msgstr "Vis bare kommentarer"
msgid "Show commit description"
-msgstr ""
+msgstr "Vis commit-beskrivelse"
msgid "Show complete raw log"
msgstr ""
msgid "Show details"
-msgstr ""
+msgstr "Vis detaljer"
msgid "Show file browser"
-msgstr ""
+msgstr "Vis filutforsker"
msgid "Show file contents"
-msgstr ""
+msgstr "Vis filens innhold"
msgid "Show latest version"
-msgstr ""
+msgstr "Vis nyeste versjon"
msgid "Show list"
-msgstr ""
+msgstr "Vis liste"
msgid "Show me everything"
-msgstr ""
+msgstr "Vis meg alt"
msgid "Show me how to add a pipeline"
msgstr ""
@@ -22830,15 +23661,21 @@ msgid "Show me more advanced stuff"
msgstr ""
msgid "Show only direct members"
-msgstr ""
+msgstr "Vis bare direkte medlemmer"
msgid "Show only inherited members"
-msgstr ""
+msgstr "Vis bare arvede medlemmer"
msgid "Show parent pages"
-msgstr ""
+msgstr "Vis overordnede sider"
msgid "Show parent subgroups"
+msgstr "Vis overordnede undergrupper"
+
+msgid "Show the Closed list"
+msgstr ""
+
+msgid "Show the Open list"
msgstr ""
msgid "Show whitespace changes"
@@ -22846,31 +23683,31 @@ msgstr ""
msgid "Showing %d event"
msgid_plural "Showing %d events"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "Viser %d hendelse"
+msgstr[1] "Viser %d hendelser"
msgid "Showing %{count} of %{total} projects"
-msgstr ""
+msgstr "Viser %{count} av %{total} prosjekter"
msgid "Showing %{count} project"
msgid_plural "Showing %{count} projects"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "Viser %{count} prosjekt"
+msgstr[1] "Viser %{count} prosjekter"
msgid "Showing %{limit} of %{total_count} issues. "
-msgstr ""
+msgstr "Viser %{limit} av %{total_count} saker. "
msgid "Showing %{pageSize} of %{total} issues"
-msgstr ""
+msgstr "Viser %{pageSize} av %{total} saker"
msgid "Showing all issues"
-msgstr ""
+msgstr "Viser alle saker"
msgid "Showing graphs based on events of the last %{timerange} days."
msgstr ""
msgid "Showing last %{size} of log -"
-msgstr ""
+msgstr "Viser siste %{size} i loggen -"
msgid "Showing latest version"
msgstr ""
@@ -22879,85 +23716,82 @@ msgid "Showing version #%{versionNumber}"
msgstr ""
msgid "Side-by-side"
-msgstr ""
+msgstr "Side-ved-side"
msgid "Sidebar|Assign health status"
-msgstr ""
-
-msgid "Sidebar|Change weight"
-msgstr ""
+msgstr "Tildel helsestatus"
msgid "Sidebar|Health status"
-msgstr ""
+msgstr "Helsestatus"
msgid "Sidebar|No status"
-msgstr ""
+msgstr "Ingen status"
msgid "Sidebar|None"
-msgstr ""
+msgstr "Ingen"
msgid "Sidebar|Only numeral characters allowed"
msgstr ""
msgid "Sidebar|Weight"
-msgstr ""
+msgstr "Vekt"
msgid "Sign in"
-msgstr ""
+msgstr "Logg på"
msgid "Sign in / Register"
-msgstr ""
+msgstr "Logg inn / Registrer"
msgid "Sign in to \"%{group_name}\""
-msgstr ""
+msgstr "Logg inn hos «%{group_name}»"
msgid "Sign in using smart card"
-msgstr ""
+msgstr "Logg på med smartkort"
msgid "Sign in via 2FA code"
-msgstr ""
+msgstr "Logg på med 2FA-kode"
msgid "Sign in with Single Sign-On"
-msgstr ""
+msgstr "Logg på med enkelt pålogging"
msgid "Sign in with smart card"
-msgstr ""
+msgstr "Logg på med smartkort"
msgid "Sign out"
-msgstr ""
+msgstr "Logg av"
msgid "Sign out & Register"
msgstr ""
msgid "Sign up"
-msgstr ""
+msgstr "Registrer deg"
msgid "Sign up was successful! Please confirm your email to sign in."
msgstr ""
msgid "Sign-in restrictions"
-msgstr ""
+msgstr "PÃ¥loggingsbegrensninger"
msgid "Sign-up restrictions"
-msgstr ""
+msgstr "Registreringsbegrensninger"
msgid "SignUp|First Name is too long (maximum is %{max_length} characters)."
-msgstr ""
+msgstr "Fornavnet er for langt (maksimumet er %{max_length} tegn)."
msgid "SignUp|Last Name is too long (maximum is %{max_length} characters)."
-msgstr ""
+msgstr "Etternavnet er for langt (maksimumet er %{max_length} tegn)."
msgid "SignUp|Name is too long (maximum is %{max_length} characters)."
-msgstr ""
+msgstr "Navnet er for langt (maksimumet er %{max_length} tegn)."
msgid "SignUp|Username is too long (maximum is %{max_length} characters)."
-msgstr ""
+msgstr "Brukernavnet er for langt (maksimumet er %{max_length} tegn)."
msgid "SignUp|Username is too short (minimum is %{min_length} characters)."
-msgstr ""
+msgstr "Brukernavnet er for kort (minimumet er %{min_length} tegn)."
msgid "Signed in"
-msgstr ""
+msgstr "PÃ¥logget"
msgid "Signed in with %{authentication} authentication"
msgstr ""
@@ -22969,7 +23803,7 @@ msgid "Signing in using your %{label} account without a pre-existing GitLab acco
msgstr ""
msgid "Similar issues"
-msgstr ""
+msgstr "Lignende saker"
msgid "Simulate a pipeline created for the default branch"
msgstr ""
@@ -22978,13 +23812,13 @@ msgid "Single or combined queries"
msgstr ""
msgid "Size"
-msgstr ""
+msgstr "Størrelse"
msgid "Size and domain settings for static websites"
-msgstr ""
+msgstr "Størrelse og domeneinnstillinger for statiske nettsteder"
msgid "Size limit per repository (MB)"
-msgstr ""
+msgstr "Størrelsesgrense per kodelager (MB)"
msgid "Size settings for static websites"
msgstr ""
@@ -22993,10 +23827,10 @@ msgid "Skip outdated deployment jobs"
msgstr ""
msgid "Skipped"
-msgstr ""
+msgstr "Hoppet over"
msgid "Slack application"
-msgstr ""
+msgstr "Slack-applikasjon"
msgid "Slack channels (e.g. general, development)"
msgstr ""
@@ -23038,28 +23872,28 @@ msgid "Slower but makes sure the project workspace is pristine as it clones the
msgstr ""
msgid "Smartcard"
-msgstr ""
+msgstr "Smartkort"
msgid "Smartcard authentication failed: client certificate header is missing."
msgstr ""
msgid "Snippets"
-msgstr ""
+msgstr "Tekstblokker"
msgid "Snippets with non-text files can only be edited via Git."
msgstr ""
msgid "SnippetsEmptyState|Code snippets"
-msgstr ""
+msgstr "Kodeutdrag"
msgid "SnippetsEmptyState|Documentation"
-msgstr ""
+msgstr "Dokumentasjon"
msgid "SnippetsEmptyState|New snippet"
-msgstr ""
+msgstr "Nytt utdrag"
msgid "SnippetsEmptyState|No snippets found"
-msgstr ""
+msgstr "Ingen utdrag ble funnet"
msgid "SnippetsEmptyState|Store, share, and embed small pieces of code and text."
msgstr ""
@@ -23068,19 +23902,22 @@ msgid "SnippetsEmptyState|There are no snippets to show."
msgstr ""
msgid "Snippets|Add another file %{num}/%{total}"
+msgstr "Snippets|Legg til en annen fil %{num}/%{total}"
+
+msgid "Snippets|Authored %{time_ago} by %{author}"
msgstr ""
msgid "Snippets|Delete file"
-msgstr ""
+msgstr "Slett fil"
msgid "Snippets|Description (optional)"
-msgstr ""
+msgstr "Beskrivelse (valgfritt)"
msgid "Snippets|File"
-msgstr ""
+msgstr "Fil"
msgid "Snippets|Files"
-msgstr ""
+msgstr "Filer"
msgid "Snippets|Give your file a name to add code highlighting, e.g. example.rb for Ruby"
msgstr ""
@@ -23092,9 +23929,12 @@ msgid "Snippets|Optionally add a description about what your snippet does or how
msgstr ""
msgid "Snowplow"
-msgstr ""
+msgstr "Snøplog"
msgid "Solution"
+msgstr "Løsning"
+
+msgid "Some changes are not shown"
msgstr ""
msgid "Some child epics may be hidden due to applied filters"
@@ -23122,28 +23962,28 @@ msgid "Someone edited this merge request at the same time you did. Please refres
msgstr ""
msgid "Something went wrong on our end"
-msgstr ""
+msgstr "Noe gikk galt i vår ende"
msgid "Something went wrong on our end."
-msgstr ""
+msgstr "Noe gikk galt i vår ende."
msgid "Something went wrong on our end. Please try again!"
-msgstr ""
+msgstr "Noe gikk galt i vår ende. Vennligst prøv på nytt!"
msgid "Something went wrong on our end. Please try again."
-msgstr ""
+msgstr "Noe gikk galt i vår ende. Vennligst prøv igjen."
msgid "Something went wrong trying to change the confidentiality of this issue"
-msgstr ""
+msgstr "Noe gikk galt under endring av konfidensialiteten på dette problemet"
msgid "Something went wrong trying to change the locked state of this %{issuableDisplayName}"
-msgstr ""
+msgstr "Noe gikk galt under endring av låsestatus på denne %{issuableDisplayName}"
msgid "Something went wrong when reordering designs. Please try again"
msgstr ""
msgid "Something went wrong when toggling the button"
-msgstr ""
+msgstr "Noe gikk galt under veksling av knappen"
msgid "Something went wrong while adding your award. Please try again."
msgstr ""
@@ -23152,214 +23992,214 @@ 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 "Noe gikk galt under benyttelse av forslaget. Vennligst prøv igjen."
msgid "Something went wrong while archiving a requirement."
-msgstr ""
+msgstr "Noe gikk galt under arkivering av et krav."
msgid "Something went wrong while closing the %{issuable}. Please try again later"
-msgstr ""
+msgstr "Noe gikk galt under lukking av %{issuable}. Vennligst prøv igjen senere"
msgid "Something went wrong while creating a requirement."
-msgstr ""
+msgstr "Noe gikk galt under opprettelse av et krav."
msgid "Something went wrong while deleting description changes. Please try again."
-msgstr ""
+msgstr "Noe gikk galt under sletting av beskrivelsesendringer. Vennligst prøv igjen."
msgid "Something went wrong while deleting the package."
-msgstr ""
+msgstr "Noe gikk galt under sletting av pakken."
msgid "Something went wrong while deleting the source branch. Please try again."
-msgstr ""
+msgstr "Noe gikk galt under sletting av kildegreinen. Vennligst prøv igjen."
msgid "Something went wrong while deleting your note. Please try again."
-msgstr ""
+msgstr "Noe gikk galt under sletting av noden din. Vennligst prøv igjen."
msgid "Something went wrong while deploying this environment. Please try again."
msgstr ""
msgid "Something went wrong while editing your comment. Please try again."
-msgstr ""
+msgstr "Noe gikk galt under redigering av kommentaren din. Prøv igjen senere."
msgid "Something went wrong while fetching %{listType} list"
-msgstr ""
+msgstr "Noe gikk feil under henting av %{listType} listen"
msgid "Something went wrong while fetching comments. Please try again."
-msgstr ""
+msgstr "Noe gikk feil under henting av kommentarer. Vennligst prøv igjen."
msgid "Something went wrong while fetching description changes. Please try again."
-msgstr ""
+msgstr "Noe gikk galt under innhenting av beskrivelsesendringer. Vennligst prøv igjen."
msgid "Something went wrong while fetching group member contributions"
-msgstr ""
+msgstr "Noe gikk feil under henting av gruppemedlemmenes bidrag"
msgid "Something went wrong while fetching latest comments."
-msgstr ""
+msgstr "Noe gikk galt under innhenting av de nyeste commitene."
msgid "Something went wrong while fetching projects"
-msgstr ""
+msgstr "Noe gikk galt under innhenting av prosjekter"
msgid "Something went wrong while fetching projects."
-msgstr ""
+msgstr "Noe gikk galt under innhenting av prosjekter."
msgid "Something went wrong while fetching related merge requests."
msgstr ""
msgid "Something went wrong while fetching requirements count."
-msgstr ""
+msgstr "Noe gikk galt under innhenting av kravtellingen."
msgid "Something went wrong while fetching requirements list."
-msgstr ""
+msgstr "Noe gikk galt under innhenting av kravlisten."
msgid "Something went wrong while fetching the environments for this merge request. Please try again."
-msgstr ""
+msgstr "Noe gikk galt ved henting av miljøer for denne fletteforespørselen. Vennligst prøv igjen."
msgid "Something went wrong while fetching the package."
-msgstr ""
+msgstr "Noe gikk galt under innhenting av pakken."
msgid "Something went wrong while fetching the packages list."
-msgstr ""
+msgstr "Noe gikk galt under innhenting av pakkelisten."
msgid "Something went wrong while initializing the OpenAPI viewer"
-msgstr ""
+msgstr "Noe gikk galt under oppstart av OpenAPI-visningen"
msgid "Something went wrong while inserting your image. Please try again."
-msgstr ""
+msgstr "Noe gikk galt under redigering av innsetting av bildet ditt. Prøv igjen senere."
msgid "Something went wrong while merging this merge request. Please try again."
msgstr ""
msgid "Something went wrong while moving issues."
-msgstr ""
+msgstr "Noe gikk galt under flytting av saker."
msgid "Something went wrong while obtaining the Let's Encrypt certificate."
msgstr ""
msgid "Something went wrong while performing the action."
-msgstr ""
+msgstr "Noe gikk galt under utføring av handlingen."
msgid "Something went wrong while reopening a requirement."
-msgstr ""
+msgstr "Noe gikk galt under gjenåpning av et krav."
msgid "Something went wrong while reopening the %{issuable}. Please try again later"
-msgstr ""
+msgstr "Noe gikk galt ved gjenåpning av %{issuable}. Vennligst prøv igjen senere"
msgid "Something went wrong while resolving this discussion. Please try again."
-msgstr ""
+msgstr "Noe gikk galt ved løsing av denne diskusjonen. Vennligst prøv igjen."
msgid "Something went wrong while stopping this environment. Please try again."
-msgstr ""
+msgstr "Noe gikk galt under stopping av dette miljøet. Vennligst prøv igjen."
msgid "Something went wrong while toggling auto-fix settings, please try again later."
msgstr ""
msgid "Something went wrong while updating a requirement."
-msgstr ""
+msgstr "Noe gikk galt under oppdatering av et krav."
msgid "Something went wrong while updating assignees"
-msgstr ""
+msgstr "Noe gikk galt under oppdatering av tilordnede"
msgid "Something went wrong while updating your list settings"
-msgstr ""
+msgstr "Noe gikk galt under oppdatering av listeinnstillingene dine"
msgid "Something went wrong with your automatic subscription renewal."
msgstr ""
msgid "Something went wrong, unable to add %{project} to dashboard"
-msgstr ""
+msgstr "Noe gikk galt, kan ikke legge til %{project} på dashbordet"
msgid "Something went wrong, unable to add projects to dashboard"
msgstr ""
msgid "Something went wrong, unable to delete project"
-msgstr ""
+msgstr "Noe gikk galt, klarte ikke å slette prosjektet"
msgid "Something went wrong, unable to get projects"
-msgstr ""
+msgstr "Noe gikk galt, kunne ikke innhente prosjekter"
msgid "Something went wrong, unable to search projects"
-msgstr ""
+msgstr "Noe gikk galt, kunne ikke søke i prosjekter"
msgid "Something went wrong."
-msgstr ""
+msgstr "Noe gikk galt."
msgid "Something went wrong. Please try again."
-msgstr ""
+msgstr "Noe gikk galt. Vennligst prøv igjen."
msgid "Something went wrong. Try again later."
-msgstr ""
+msgstr "Noe gikk galt. Prøv igjen senere."
msgid "Sorry, no epics matched your search"
-msgstr ""
+msgstr "Beklager, ingen eposer samsvarer med søket ditt"
msgid "Sorry, no projects matched your search"
-msgstr ""
+msgstr "Beklager, ingen prosjekter samsvarer med søket ditt"
msgid "Sorry, you have exceeded the maximum browsable page number. Please use the API to explore further."
msgstr ""
msgid "Sorry, your filter produced no results"
-msgstr ""
+msgstr "Beklager, filteret ditt ga ingen resultater"
msgid "Sort by"
-msgstr ""
+msgstr "Sorter etter"
msgid "Sort direction"
-msgstr ""
+msgstr "Sorteringsretning"
msgid "Sort direction: Ascending"
-msgstr ""
+msgstr "Sorter retning: stigende"
msgid "Sort direction: Descending"
-msgstr ""
+msgstr "Sorter retning: synkende"
msgid "SortOptions|Access level, ascending"
-msgstr ""
+msgstr "Tilgangsnivå, stigende"
msgid "SortOptions|Access level, descending"
-msgstr ""
+msgstr "Tilgangsnivå, synkende"
msgid "SortOptions|Created date"
-msgstr ""
+msgstr "Opprettelsesdato"
msgid "SortOptions|Due date"
-msgstr ""
+msgstr "Forfallsdato"
msgid "SortOptions|Due later"
-msgstr ""
+msgstr "Forfall senere"
msgid "SortOptions|Due soon"
-msgstr ""
+msgstr "Forfaller snart"
msgid "SortOptions|Expired date"
-msgstr ""
+msgstr "Utløpsdato"
msgid "SortOptions|Label priority"
-msgstr ""
+msgstr "Etikett prioritet"
msgid "SortOptions|Largest group"
-msgstr ""
+msgstr "Største gruppe"
msgid "SortOptions|Largest repository"
-msgstr ""
+msgstr "Største kodelager"
msgid "SortOptions|Last Contact"
-msgstr ""
+msgstr "Siste kontakt"
msgid "SortOptions|Last created"
-msgstr ""
+msgstr "Sist opprettet"
msgid "SortOptions|Last joined"
-msgstr ""
+msgstr "Ble senest med i"
msgid "SortOptions|Last updated"
-msgstr ""
+msgstr "Senest oppdatert"
msgid "SortOptions|Least popular"
-msgstr ""
+msgstr "Minst populær"
msgid "SortOptions|Less weight"
-msgstr ""
+msgstr "Mindre vekt"
msgid "SortOptions|Manual"
msgstr ""
@@ -23374,22 +24214,22 @@ msgid "SortOptions|Milestone due soon"
msgstr ""
msgid "SortOptions|More weight"
-msgstr ""
+msgstr "Mere vekt"
msgid "SortOptions|Most popular"
-msgstr ""
+msgstr "Mest populær"
msgid "SortOptions|Most stars"
-msgstr ""
+msgstr "Flest stjerner"
msgid "SortOptions|Name"
-msgstr ""
+msgstr "Navn"
msgid "SortOptions|Name, ascending"
-msgstr ""
+msgstr "Navn, stigende"
msgid "SortOptions|Name, descending"
-msgstr ""
+msgstr "Navn, synkende"
msgid "SortOptions|Oldest created"
msgstr ""
@@ -23410,73 +24250,79 @@ msgid "SortOptions|Oldest updated"
msgstr ""
msgid "SortOptions|Popularity"
-msgstr ""
+msgstr "Popularitet"
msgid "SortOptions|Priority"
-msgstr ""
+msgstr "Prioritet"
msgid "SortOptions|Project"
-msgstr ""
+msgstr "Prosjekt"
msgid "SortOptions|Recent last activity"
-msgstr ""
+msgstr "Nyligste aktivitet"
msgid "SortOptions|Recent sign in"
-msgstr ""
+msgstr "Nyligst logget inn"
msgid "SortOptions|Recently starred"
msgstr ""
msgid "SortOptions|Size"
-msgstr ""
+msgstr "Størrelse"
msgid "SortOptions|Sort by:"
-msgstr ""
+msgstr "Sorter etter:"
msgid "SortOptions|Sort direction"
-msgstr ""
+msgstr "Sorteringsretning"
msgid "SortOptions|Stars"
msgstr ""
msgid "SortOptions|Start date"
-msgstr ""
+msgstr "Startdato"
msgid "SortOptions|Start later"
-msgstr ""
+msgstr "Start senere"
msgid "SortOptions|Start soon"
-msgstr ""
+msgstr "Starter snart"
msgid "SortOptions|Type"
-msgstr ""
+msgstr "Type"
msgid "SortOptions|Version"
-msgstr ""
+msgstr "Versjon"
msgid "SortOptions|Weight"
-msgstr ""
+msgstr "Vekt"
msgid "Source"
-msgstr ""
+msgstr "Kilde"
msgid "Source (branch or tag)"
+msgstr "Kilde (branch eller tag)"
+
+msgid "Source Branch"
msgstr ""
-msgid "Source code"
+msgid "Source branch: %{source_branch_open}%{source_branch}%{source_branch_close}"
msgstr ""
+msgid "Source code"
+msgstr "Kildekode"
+
msgid "Source code (%{fileExtension})"
msgstr ""
msgid "Source is not available"
-msgstr ""
+msgstr "Kilden er ikke tilgjengelig"
msgid "Source project cannot be found."
msgstr ""
msgid "Sourcegraph"
-msgstr ""
+msgstr "Sourcegraph"
msgid "SourcegraphAdmin|Block on private and internal projects"
msgstr ""
@@ -23485,7 +24331,7 @@ msgid "SourcegraphAdmin|Configure the URL to a Sourcegraph instance which can re
msgstr ""
msgid "SourcegraphAdmin|Enable Sourcegraph"
-msgstr ""
+msgstr "Skru på Sourcegraph"
msgid "SourcegraphAdmin|Enable code intelligence powered by %{link_start}Sourcegraph%{link_end} on your GitLab instance's code views and merge requests."
msgstr ""
@@ -23497,13 +24343,13 @@ msgid "SourcegraphAdmin|More information"
msgstr ""
msgid "SourcegraphAdmin|Save changes"
-msgstr ""
+msgstr "Lagre endringer"
msgid "SourcegraphAdmin|Sourcegraph URL"
-msgstr ""
+msgstr "Sourcegraph-URL"
msgid "SourcegraphAdmin|e.g. https://sourcegraph.example.com"
-msgstr ""
+msgstr "f.eks. https://sourcegraph.example.com"
msgid "SourcegraphPreferences|This feature is experimental and currently limited to certain projects."
msgstr ""
@@ -23521,7 +24367,7 @@ msgid "SourcegraphPreferences|Uses a custom %{link_start}Sourcegraph instance%{l
msgstr ""
msgid "Spam Logs"
-msgstr ""
+msgstr "Spam-loggbøker"
msgid "Spam and Anti-bot Protection"
msgstr ""
@@ -23554,10 +24400,10 @@ msgid "Stack trace"
msgstr ""
msgid "Stacktrace snippet"
-msgstr ""
+msgstr "Stacktrace-utdrag"
msgid "Stage"
-msgstr ""
+msgstr "Trinn"
msgid "Stage & Commit"
msgstr ""
@@ -23566,10 +24412,10 @@ msgid "Stage data updated"
msgstr ""
msgid "Stage removed"
-msgstr ""
+msgstr "Trinn fjernet"
msgid "Standard"
-msgstr ""
+msgstr "Standard"
msgid "Star a label to make it a priority label. Order the prioritized labels to change their relative priority, by dragging."
msgstr ""
@@ -23584,13 +24430,13 @@ msgid "StarProject|Star"
msgstr ""
msgid "Starred Projects"
-msgstr ""
+msgstr "Stjernemerkede prosjekter"
msgid "Starred Projects' Activity"
-msgstr ""
+msgstr "Stjernemerkede prosjektsaktivitet"
msgid "Starred projects"
-msgstr ""
+msgstr "Stjernemerkede prosjekter"
msgid "StarredProjectsEmptyState|Visit a project page and press on a star icon. Then, you can find the project on this page."
msgstr ""
@@ -23599,16 +24445,16 @@ msgid "StarredProjectsEmptyState|You don't have starred projects yet."
msgstr ""
msgid "Starrers"
-msgstr ""
+msgstr "Stjernemerkere"
msgid "Stars"
-msgstr ""
+msgstr "Stjerner"
msgid "Start Date"
-msgstr ""
+msgstr "Startdato"
msgid "Start Web Terminal"
-msgstr ""
+msgstr "Start netterminal"
msgid "Start a %{new_merge_request} with these changes"
msgstr ""
@@ -23617,28 +24463,25 @@ msgid "Start a Free Gold Trial"
msgstr ""
msgid "Start a new discussion..."
-msgstr ""
+msgstr "Start en ny diskusjon …"
msgid "Start a new merge request"
-msgstr ""
+msgstr "Begynn en ny fletteforespørsel"
msgid "Start a review"
-msgstr ""
+msgstr "Start en anmeldelse"
msgid "Start and due date"
-msgstr ""
-
-msgid "Start by choosing a group to see how your team is spending time. You can then drill down to the project level."
-msgstr ""
+msgstr "Start- og forfallsdato"
msgid "Start by choosing a group to start exploring the merge requests in that group. You can then proceed to filter by projects, labels, milestones and authors."
msgstr ""
msgid "Start cleanup"
-msgstr ""
+msgstr "Start opprydding"
msgid "Start date"
-msgstr ""
+msgstr "Startdato"
msgid "Start merge train"
msgstr ""
@@ -23647,16 +24490,16 @@ msgid "Start merge train when pipeline succeeds"
msgstr ""
msgid "Start search"
-msgstr ""
+msgstr "Start søk"
msgid "Start the Runner!"
msgstr ""
msgid "Start thread"
-msgstr ""
+msgstr "Start tråd"
msgid "Start thread & close %{noteable_name}"
-msgstr ""
+msgstr "Start tråd og lukk %{noteable_name}"
msgid "Start thread & reopen %{noteable_name}"
msgstr ""
@@ -23668,31 +24511,31 @@ msgid "Start your Free Gold Trial"
msgstr ""
msgid "Start your free trial"
-msgstr ""
+msgstr "Begynn din gratis prøveperiode"
msgid "Start your trial"
-msgstr ""
+msgstr "Begynn prøveperioden din"
msgid "Started"
-msgstr ""
+msgstr "Startet"
msgid "Started %{startsIn}"
-msgstr ""
+msgstr "Startet %{startsIn}"
msgid "Started asynchronous removal of all repository check states."
msgstr ""
msgid "Started:"
-msgstr ""
+msgstr "Startet:"
msgid "Starting..."
-msgstr ""
+msgstr "Starter …"
msgid "Starts %{startsIn}"
-msgstr ""
+msgstr "Starter %{startsIn}"
msgid "Starts at (UTC)"
-msgstr ""
+msgstr "Starter (UTC)"
msgid "State your message to activate"
msgstr ""
@@ -23712,23 +24555,32 @@ msgstr ""
msgid "StaticSiteEditor|3. Assign a person to review and accept the merge request."
msgstr ""
+msgid "StaticSiteEditor|A link to view the merge request will appear once ready."
+msgstr ""
+
msgid "StaticSiteEditor|An error occurred while submitting your changes."
msgstr ""
msgid "StaticSiteEditor|Branch could not be created."
msgstr ""
+msgid "StaticSiteEditor|Copy update"
+msgstr ""
+
msgid "StaticSiteEditor|Could not commit the content changes."
msgstr ""
msgid "StaticSiteEditor|Could not create merge request."
msgstr ""
+msgid "StaticSiteEditor|Creating your merge request"
+msgstr ""
+
msgid "StaticSiteEditor|Incompatible file content"
msgstr ""
msgid "StaticSiteEditor|Return to site"
-msgstr ""
+msgstr "GÃ¥ tilbake til nettstedet"
msgid "StaticSiteEditor|Static site editor"
msgstr ""
@@ -23743,37 +24595,40 @@ msgid "StaticSiteEditor|Update %{sourcePath} file"
msgstr ""
msgid "StaticSiteEditor|View documentation"
+msgstr "Vis dokumentasjon"
+
+msgid "StaticSiteEditor|You can set an assignee to get your changes reviewed and deployed once your merge request is created."
msgstr ""
msgid "StaticSiteEditor|Your merge request has been created"
msgstr ""
msgid "Statistics"
-msgstr ""
+msgstr "Statistikk"
msgid "Status"
-msgstr ""
+msgstr "Status"
msgid "Status:"
-msgstr ""
+msgstr "Status:"
msgid "Status: %{title}"
-msgstr ""
+msgstr "Status: %{title}"
msgid "StatusPage|AWS Secret access key"
-msgstr ""
+msgstr "AWS hemmelig tilgangsnøkkel"
msgid "StatusPage|AWS access key ID"
-msgstr ""
+msgstr "AWS-tilgangsnøkkel-ID"
msgid "StatusPage|AWS documentation"
-msgstr ""
+msgstr "AWS-dokumentasjon"
msgid "StatusPage|AWS region"
-msgstr ""
+msgstr "AWS-region"
msgid "StatusPage|Active"
-msgstr ""
+msgstr "Aktiv"
msgid "StatusPage|Bucket %{docsLink}"
msgstr ""
@@ -23788,7 +24643,7 @@ msgid "StatusPage|S3 Bucket name"
msgstr ""
msgid "StatusPage|Status page"
-msgstr ""
+msgstr "Statusside"
msgid "StatusPage|Status page URL"
msgstr ""
@@ -23797,7 +24652,7 @@ msgid "StatusPage|Status page frontend documentation"
msgstr ""
msgid "StatusPage|To publish incidents to an external status page, GitLab will store a JSON file in your Amazon S3 account in a location accessible to your external status page service. Make sure to also set up %{docsLink}"
-msgstr ""
+msgstr "For å publisere hendelser til en ekstern statusside, vil GitLab lagre en JSON-fil i Amazon S3-kontoen din på et sted som er tilgjengelig for den eksterne statustjenesten. Sørg for å også sette opp %{docsLink}"
msgid "StatusPage|configuration documentation"
msgstr ""
@@ -23812,31 +24667,31 @@ msgid "Still, we recommend keeping a backup saved somewhere. Otherwise, if you e
msgstr ""
msgid "Stop Terminal"
-msgstr ""
+msgstr "Stopp terminal"
msgid "Stop impersonation"
msgstr ""
msgid "Stop this environment"
-msgstr ""
+msgstr "Stopp dette miljøet"
msgid "Stopped"
-msgstr ""
+msgstr "Stoppet"
msgid "Stopping..."
-msgstr ""
+msgstr "Stopper …"
msgid "Storage"
-msgstr ""
+msgstr "Lagring"
msgid "Storage nodes for new repositories"
msgstr ""
msgid "Storage:"
-msgstr ""
+msgstr "Oppbevaring:"
msgid "StorageSize|Unknown"
-msgstr ""
+msgstr "Ukjent"
msgid "Subgroup milestone"
msgstr ""
@@ -23851,73 +24706,73 @@ msgid "SubgroupCreationlevel|Allowed to create subgroups"
msgstr ""
msgid "SubgroupCreationlevel|Maintainers"
-msgstr ""
+msgstr "Vedlikeholdere"
msgid "SubgroupCreationlevel|Owners"
-msgstr ""
+msgstr "Eiere"
msgid "Subgroups"
-msgstr ""
+msgstr "Undergrupper"
msgid "Subgroups and projects"
-msgstr ""
+msgstr "Undergrupper og prosjekter"
msgid "Subject Key Identifier:"
msgstr ""
msgid "Subkeys"
-msgstr ""
+msgstr "Undernøkler"
msgid "Submit"
-msgstr ""
+msgstr "Send inn"
msgid "Submit %{humanized_resource_name}"
-msgstr ""
-
-msgid "Submit Changes"
-msgstr ""
+msgstr "Send inn %{humanized_resource_name}"
msgid "Submit a review"
-msgstr ""
+msgstr "Send inn en vurdering"
msgid "Submit as spam"
+msgstr "Send inn som spam"
+
+msgid "Submit changes"
msgstr ""
msgid "Submit feedback"
-msgstr ""
+msgstr "Send tilbakemelding"
msgid "Submit issue"
-msgstr ""
+msgstr "Send inn sak"
msgid "Submit review"
-msgstr ""
+msgstr "Send inn gjennomgang"
msgid "Submit search"
-msgstr ""
+msgstr "Send inn søk"
msgid "Submit the current review."
-msgstr ""
+msgstr "Send inn nåværende vurdering."
msgid "Submitted the current review."
-msgstr ""
+msgstr "Sendte inn den nåværende vurderingen."
msgid "Subscribe"
-msgstr ""
+msgstr "Abonnér"
msgid "Subscribe at group level"
-msgstr ""
+msgstr "Abonner på gruppenivå"
msgid "Subscribe at project level"
-msgstr ""
+msgstr "Abonner på prosjektnivå"
msgid "Subscribe to RSS feed"
-msgstr ""
+msgstr "Abonner på RSS-kilden"
msgid "Subscribe to calendar"
-msgstr ""
+msgstr "Abonner på kalender"
msgid "Subscribed"
-msgstr ""
+msgstr "PÃ¥meldt"
msgid "Subscribed to this %{quick_action_target}."
msgstr ""
@@ -23926,43 +24781,43 @@ msgid "Subscribes to this %{quick_action_target}."
msgstr ""
msgid "Subscription"
-msgstr ""
+msgstr "Abonnement"
msgid "Subscription deletion failed."
-msgstr ""
+msgstr "Abonnementsslettingen mislyktes."
msgid "Subscription successfully applied to \"%{group_name}\""
msgstr ""
msgid "Subscription successfully created."
-msgstr ""
+msgstr "Abonnementet ble vellykket opprettet."
msgid "Subscription successfully deleted."
-msgstr ""
+msgstr "Abonnementet ble vellykket slettet."
msgid "SubscriptionTable|Billing"
-msgstr ""
+msgstr "Fakturering"
msgid "SubscriptionTable|Free"
-msgstr ""
+msgstr "Gratis"
msgid "SubscriptionTable|GitLab allows you to continue using your subscription even if you exceed the number of seats you purchased. You will be required to pay for these seats upon renewal."
-msgstr ""
+msgstr "GitLab lar deg fortsette å bruke abonnementet selv om du overskrider antall seter du kjøpte. Du vil måtte betale for disse setene ved fornyelse."
msgid "SubscriptionTable|Last invoice"
-msgstr ""
+msgstr "Forrige fakturering"
msgid "SubscriptionTable|Loading subscriptions"
msgstr ""
msgid "SubscriptionTable|Manage"
-msgstr ""
+msgstr "Behandle"
msgid "SubscriptionTable|Max seats used"
msgstr ""
msgid "SubscriptionTable|Next invoice"
-msgstr ""
+msgstr "Neste fakturering"
msgid "SubscriptionTable|Seats currently in use"
msgstr ""
@@ -23974,10 +24829,10 @@ msgid "SubscriptionTable|Seats owed"
msgstr ""
msgid "SubscriptionTable|Subscription end date"
-msgstr ""
+msgstr "Abonnementets sluttdato"
msgid "SubscriptionTable|Subscription start date"
-msgstr ""
+msgstr "Abonnementets startdato"
msgid "SubscriptionTable|This is the last time the GitLab.com team was in contact with you to settle any outstanding balances."
msgstr ""
@@ -23992,7 +24847,7 @@ msgid "SubscriptionTable|This is the number of seats you will be required to pur
msgstr ""
msgid "SubscriptionTable|Trial"
-msgstr ""
+msgstr "Prøveperiode"
msgid "SubscriptionTable|Trial end date"
msgstr ""
@@ -24001,39 +24856,42 @@ msgid "SubscriptionTable|Trial start date"
msgstr ""
msgid "SubscriptionTable|Upgrade"
-msgstr ""
+msgstr "Oppgrader"
msgid "SubscriptionTable|Usage"
-msgstr ""
+msgstr "Benyttelse"
msgid "SubscriptionTable|Usage count is performed once a day at 12:00 PM."
msgstr ""
msgid "Subscriptions"
-msgstr ""
+msgstr "Abonnementer"
msgid "Subtracted"
-msgstr ""
+msgstr "Trukket fra"
msgid "Subtracts"
-msgstr ""
+msgstr "Trekker fra"
msgid "Succeeded"
-msgstr ""
+msgstr "Lyktes"
msgid "Successfully activated"
-msgstr ""
+msgstr "Aktivering vellykket"
msgid "Successfully blocked"
-msgstr ""
+msgstr "Vellykket blokkert"
msgid "Successfully confirmed"
-msgstr ""
+msgstr "Vellykket bekreftelse"
msgid "Successfully deactivated"
-msgstr ""
+msgstr "Vellykket deaktivering"
msgid "Successfully deleted U2F device."
+msgstr "U2F-enhet ble slettet."
+
+msgid "Successfully deleted WebAuthn device."
msgstr ""
msgid "Successfully removed email."
@@ -24046,7 +24904,7 @@ msgid "Successfully unblocked"
msgstr ""
msgid "Successfully unlocked"
-msgstr ""
+msgstr "Opplåsingen var vellykket"
msgid "Successfully verified domain ownership"
msgstr ""
@@ -24055,10 +24913,10 @@ msgid "Suggest code changes which can be immediately applied in one click. Try i
msgstr ""
msgid "Suggested Solutions"
-msgstr ""
+msgstr "Foreslåtte endringer"
msgid "Suggested change"
-msgstr ""
+msgstr "Foreslått endring"
msgid "Suggested solutions help link"
msgstr ""
@@ -24082,10 +24940,10 @@ msgid "SuggestedColors|Dark moderate violet"
msgstr ""
msgid "SuggestedColors|Feijoa"
-msgstr ""
+msgstr "Feijoa"
msgid "SuggestedColors|Lime green"
-msgstr ""
+msgstr "Limegrønn"
msgid "SuggestedColors|Moderate blue"
msgstr ""
@@ -24100,10 +24958,10 @@ msgid "SuggestedColors|Slightly desaturated green"
msgstr ""
msgid "SuggestedColors|Soft orange"
-msgstr ""
+msgstr "Myk oransje"
msgid "SuggestedColors|Soft red"
-msgstr ""
+msgstr "Myk rød"
msgid "SuggestedColors|Strong pink"
msgstr ""
@@ -24139,28 +24997,28 @@ msgid "Suggestions must all be on the same branch."
msgstr ""
msgid "Suggestions:"
-msgstr ""
+msgstr "Forslag:"
msgid "Suite"
msgstr ""
msgid "Summary"
-msgstr ""
+msgstr "Sammendrag"
msgid "Sunday"
-msgstr ""
+msgstr "Søndag"
msgid "Support"
-msgstr ""
+msgstr "Støtte"
msgid "Support for custom certificates is disabled. Ask your system's administrator to enable it."
msgstr ""
msgid "Support page URL"
-msgstr ""
+msgstr "Støtteside-URL"
msgid "Survey Response"
-msgstr ""
+msgstr "Undersøkelsessvar"
msgid "Switch branch/tag"
msgstr ""
@@ -24172,28 +25030,28 @@ msgid "Switch to the source to copy the file contents"
msgstr ""
msgid "Symbolic link"
-msgstr ""
+msgstr "Symbolsk lenke"
msgid "Sync information"
-msgstr ""
+msgstr "Synkroniseringsinformasjon"
msgid "Synced"
-msgstr ""
+msgstr "Synkronisert"
msgid "Synchronization disabled"
msgstr ""
msgid "System"
-msgstr ""
+msgstr "System"
msgid "System Hooks"
-msgstr ""
+msgstr "Systemkroker"
msgid "System Hooks Help"
msgstr ""
msgid "System Info"
-msgstr ""
+msgstr "Systeminformasjon"
msgid "System default (%{default})"
msgstr ""
@@ -24205,28 +25063,28 @@ msgid "System hook was successfully updated."
msgstr ""
msgid "System metrics (Custom)"
-msgstr ""
+msgstr "Systemmåltall (egendefinert)"
msgid "System metrics (Kubernetes)"
-msgstr ""
+msgstr "Systemmåltall (Kubernetes)"
msgid "Table of Contents"
-msgstr ""
+msgstr "Innholdsfortegnelse"
msgid "Tag"
-msgstr ""
+msgstr "Etikett"
msgid "Tag list:"
-msgstr ""
+msgstr "Etikettliste:"
msgid "Tag name"
-msgstr ""
+msgstr "Navn på tag"
msgid "Tag name is required"
-msgstr ""
+msgstr "Etikettnavn er påkrevd"
msgid "Tag this commit."
-msgstr ""
+msgstr "Gi denne commiten en etikett."
msgid "Tagged this commit to %{tag_name} with \"%{message}\"."
msgstr ""
@@ -24235,13 +25093,13 @@ msgid "Tagged this commit to %{tag_name}."
msgstr ""
msgid "Tags"
-msgstr ""
+msgstr "Etiketter"
msgid "Tags are deleted until the timeout is reached. Any remaining tags are included the next time the policy runs. To remove the time limit, set it to 0."
msgstr ""
msgid "Tags feed"
-msgstr ""
+msgstr "Tag-strøm"
msgid "Tags this commit to %{tag_name} with \"%{message}\"."
msgstr ""
@@ -24250,115 +25108,112 @@ msgid "Tags this commit to %{tag_name}."
msgstr ""
msgid "Tags:"
-msgstr ""
+msgstr "Etiketter:"
msgid "TagsPage|Browse commits"
-msgstr ""
+msgstr "Bla gjennom commiter"
msgid "TagsPage|Browse files"
-msgstr ""
+msgstr "Bla gjennom filer"
msgid "TagsPage|Can't find HEAD commit for this tag"
msgstr ""
msgid "TagsPage|Cancel"
-msgstr ""
+msgstr "Avbryt"
msgid "TagsPage|Create tag"
-msgstr ""
+msgstr "Opprett tag"
msgid "TagsPage|Delete tag"
-msgstr ""
+msgstr "Slett tag"
msgid "TagsPage|Deleting the %{tag_name} tag cannot be undone. Are you sure?"
msgstr ""
msgid "TagsPage|Edit release notes"
-msgstr ""
+msgstr "Rediger utgivelsesbeskrivelser"
msgid "TagsPage|Existing branch name, tag, or commit SHA"
msgstr ""
msgid "TagsPage|Filter by tag name"
-msgstr ""
+msgstr "Filtrer etter etikettnavn"
msgid "TagsPage|New Tag"
-msgstr ""
+msgstr "Ny Tag"
msgid "TagsPage|New tag"
-msgstr ""
+msgstr "Ny Tag"
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 ""
+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|Release notes"
-msgstr ""
+msgstr "Utgivelsesbeskrivelser"
msgid "TagsPage|Repository has no tags yet."
-msgstr ""
+msgstr "Kodelageret har ingen etiketter enda."
msgid "TagsPage|Sort by"
-msgstr ""
+msgstr "Sorter etter"
msgid "TagsPage|Tags"
-msgstr ""
+msgstr "Tagger"
msgid "TagsPage|Tags give the ability to mark specific points in history as being important"
msgstr ""
msgid "TagsPage|This tag has no release notes."
-msgstr ""
+msgstr "Denne etiketten har ingen utgivelsesbeskrivelser."
msgid "TagsPage|Use git tag command to add a new one:"
msgstr ""
msgid "TagsPage|Write your release notes or drag files here…"
-msgstr ""
+msgstr "Skriv inn dine utgivelsesbeskrivelser eller dra filer hit …"
msgid "TagsPage|protected"
-msgstr ""
+msgstr "beskyttet"
msgid "Target Branch"
-msgstr ""
+msgstr "MÃ¥l-branch"
msgid "Target Path"
-msgstr ""
+msgstr "MÃ¥lsti"
msgid "Target branch"
-msgstr ""
+msgstr "MÃ¥l-branch"
msgid "Target-Branch"
-msgstr ""
+msgstr "MÃ¥lgren"
msgid "Task ID: %{elastic_task}"
-msgstr ""
+msgstr "Oppgave-ID: %{elastic_task}"
msgid "Team"
-msgstr ""
+msgstr "Team"
msgid "Team domain"
-msgstr ""
+msgstr "Team-domene"
msgid "Telephone number"
-msgstr ""
+msgstr "Telefonnummer"
msgid "Telephone number (Optional)"
-msgstr ""
+msgstr "Telefonnummer (valgfritt)"
msgid "Template"
-msgstr ""
+msgstr "Mal"
msgid "Template to append to all Service Desk issues"
msgstr ""
-msgid "Template was successfully saved."
-msgstr ""
-
msgid "Templates"
-msgstr ""
+msgstr "Maler"
msgid "TemporaryStorageIncrease|can only be set once"
msgstr ""
@@ -24367,7 +25222,7 @@ msgid "TemporaryStorageIncrease|can only be set with more than %{percentage}%% u
msgstr ""
msgid "TemporaryStorage|GitLab allows you a %{strongStart}free, one-time storage increase%{strongEnd}. For 30 days your storage will be unlimited. This gives you time to reduce your storage usage. After 30 days, your original storage limit of %{limit} applies. If you are at maximum storage capacity, your account will be read-only. To continue using GitLab you'll have to purchase additional storage or decrease storage usage."
-msgstr ""
+msgstr "GitLab tillater deg en %{strongStart}gratis, en-gangs lagringsøkning%{strongEnd}. I 30 dager er lagringen din ubegrenset. Dette gir deg tid til å redusere din bruk av lagringsplass. Etter 30 dager, vil din opprinnelige lagringsgrense på %{limit} gjelde. Hvis du har nådd maksimal lagringskapasitet vil kontoen din bli skrivebeskyttet. For å fortsette å bruke GitLab må du kjøpe ekstra lagringsplass eller redusere forbruket."
msgid "TemporaryStorage|Increase storage temporarily"
msgstr ""
@@ -24376,7 +25231,7 @@ msgid "TemporaryStorage|Temporarily increase storage now?"
msgstr ""
msgid "Terminal"
-msgstr ""
+msgstr "Terminal"
msgid "Terminal for environment"
msgstr ""
@@ -24385,10 +25240,10 @@ msgid "Terminal sync service is running"
msgstr ""
msgid "Terms of Service Agreement and Privacy Policy"
-msgstr ""
+msgstr "Vilkår for serviceavtale og personvernregler"
msgid "Terms of Service and Privacy Policy"
-msgstr ""
+msgstr "Bruksvilkår og personvern"
msgid "Terraform|%{number} Terraform report failed to generate"
msgid_plural "Terraform|%{number} Terraform reports failed to generate"
@@ -24407,7 +25262,7 @@ msgid "Terraform|A Terraform report was generated in your pipelines."
msgstr ""
msgid "Terraform|Generating the report caused an error."
-msgstr ""
+msgstr "Genereringen av prosjektet forårsaket en feil."
msgid "Terraform|Reported Resource Changes: %{addNum} to add, %{changeNum} to change, %{deleteNum} to delete"
msgstr ""
@@ -24419,7 +25274,7 @@ msgid "Terraform|The Terraform report %{name} was generated in your pipelines."
msgstr ""
msgid "Test"
-msgstr ""
+msgstr "Test"
msgid "Test Cases"
msgstr ""
@@ -24432,13 +25287,31 @@ msgstr ""
msgid "Test coverage: %d hit"
msgid_plural "Test coverage: %d hits"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "Testdekning: %d treff"
+msgstr[1] "Testdekning: %d treff"
+
+msgid "Test settings"
+msgstr ""
+
+msgid "TestCases|New Test Case"
+msgstr ""
+
+msgid "TestCases|New test case"
+msgstr ""
-msgid "Test failed."
+msgid "TestCases|Search test cases"
msgstr ""
-msgid "Test settings and save changes"
+msgid "TestCases|Something went wrong while creating a test case."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching count of test cases."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching test cases list."
+msgstr ""
+
+msgid "TestCases|Submit test case"
msgstr ""
msgid "TestHooks|Ensure one of your projects has merge requests."
@@ -24466,22 +25339,22 @@ msgid "TestHooks|Ensure the wiki is enabled and has pages."
msgstr ""
msgid "TestReports|%{count} errors"
-msgstr ""
+msgstr "%{count} feil"
msgid "TestReports|%{count} failures"
msgstr ""
msgid "TestReports|%{count} tests"
-msgstr ""
+msgstr "%{count} tester"
msgid "TestReports|%{rate}%{sign} success rate"
msgstr ""
msgid "TestReports|Jobs"
-msgstr ""
+msgstr "Jobber"
msgid "TestReports|Tests"
-msgstr ""
+msgstr "Tester"
msgid "TestReports|There are no test cases to display."
msgstr ""
@@ -24490,23 +25363,26 @@ msgid "TestReports|There are no test suites to show."
msgstr ""
msgid "TestReports|There are no tests to show."
-msgstr ""
+msgstr "Det er ingen tester å vise."
msgid "TestReports|There was an error fetching the summary."
-msgstr ""
+msgstr "En feil oppstod under innhenting av oppsummeringen."
msgid "TestReports|There was an error fetching the test suite."
msgstr ""
msgid "Tests"
-msgstr ""
+msgstr "Tester"
msgid "Thank you for signing up for your free trial! You will get additional instructions in your inbox shortly."
msgstr ""
-msgid "Thank you for your feedback!"
+msgid "Thank you for your business."
msgstr ""
+msgid "Thank you for your feedback!"
+msgstr "Takk for din tilbakemelding!"
+
msgid "Thank you for your report. A GitLab administrator will look into it shortly."
msgstr ""
@@ -24514,10 +25390,10 @@ msgid "Thank you for your support request! We are tracking your request as ticke
msgstr ""
msgid "Thanks for your purchase!"
-msgstr ""
+msgstr "Takk for handelen!"
msgid "Thanks! Don't show me this again"
-msgstr ""
+msgstr "Takk! Ikke vis meg dette igjen"
msgid "That's it, well done!%{celebrate}"
msgstr ""
@@ -24537,7 +25413,7 @@ msgstr[0] ""
msgstr[1] ""
msgid "The Advanced Search in GitLab is a powerful search service that saves you time. Instead of creating duplicate code and wasting time, you can now search for code within other teams that can help your own project."
-msgstr ""
+msgstr "Det avansert søket i GitLab er en kraftig søketjeneste som sparer deg tid. I stedet for å opprette duplisert kode og kaste bort tid, kan du nå søke etter kode inni andre team som kan hjelpe ditt eget prosjekt."
msgid "The CSV export will be created in the background. Once finished, it will be sent to %{strong_open}%{email}%{strong_close} in an attachment."
msgstr ""
@@ -24563,11 +25439,8 @@ msgstr ""
msgid "The URL to use for connecting to Elasticsearch. Use a comma-separated list to support clustering (e.g., \"http://localhost:9200, http://localhost:9201\")."
msgstr ""
-msgid "The Web IDE offers advanced syntax highlighting capabilities and more."
-msgstr ""
-
msgid "The X509 Certificate to use when mutual TLS is required to communicate with the external authorization service. If left blank, the server certificate is still validated when accessing over HTTPS."
-msgstr ""
+msgstr "X.509-sertifikatet som skal brukes når det kreves gjensidig TLS for å kommunisere med den eksterne autorisasjonstjenesten. Hvis det er tomt, blir tjenersertifikatet fortsatt validert når du besøker den gjennom HTTPS."
msgid "The above settings apply to all projects with the selected compliance framework(s)."
msgstr ""
@@ -24594,7 +25467,7 @@ msgid "The collection of events added to the data gathered for that stage."
msgstr ""
msgid "The commit does not exist"
-msgstr ""
+msgstr "Commiten finnes ikke"
msgid "The comparison view may be inaccurate due to merge conflicts."
msgstr ""
@@ -24606,10 +25479,10 @@ msgid "The content of this page is not encoded in UTF-8. Edits can only be made
msgstr ""
msgid "The contents of this group, its subgroups and projects will be permanently removed after %{deletion_adjourned_period} days on %{date}. After this point, your data cannot be recovered."
-msgstr ""
+msgstr "Innholdet i denne gruppen, dens undergrupper og prosjekter blir fjernet permanent etter %{deletion_adjourned_period} dager den %{date}. Etter det kan ikke dataene dine gjenopprettes."
msgid "The current issue"
-msgstr ""
+msgstr "Den nåværende saken"
msgid "The data source is connected, but there is no data to display. %{documentationLink}"
msgstr ""
@@ -24627,7 +25500,7 @@ msgid "The designs you tried uploading did not change."
msgstr ""
msgid "The directory has been successfully created."
-msgstr ""
+msgstr "Mappen har blitt vellykket opprettet."
msgid "The domain you entered is misformatted."
msgstr ""
@@ -24636,19 +25509,19 @@ msgid "The domain you entered is not allowed."
msgstr ""
msgid "The download link will expire in 24 hours."
-msgstr ""
+msgstr "Nedlastingslenken vil utløpe om 24 timer."
msgid "The entered user map is not a valid JSON user map."
msgstr ""
msgid "The errors we encountered were:"
-msgstr ""
+msgstr "Feilene vi kom over var:"
msgid "The file has been successfully created."
-msgstr ""
+msgstr "Filen har blitt vellykket opprettet."
msgid "The file has been successfully deleted."
-msgstr ""
+msgstr "Filen har blitt vellykket slettet."
msgid "The file name should have a .yml extension"
msgstr ""
@@ -24660,10 +25533,10 @@ msgid "The following %{user} can also push to this branch: %{branch}"
msgstr ""
msgid "The following items will NOT be exported:"
-msgstr ""
+msgstr "De følgende gjenstander vil IKKE bli eksportert:"
msgid "The following items will be exported:"
-msgstr ""
+msgstr "De følgende gjenstander vil bli eksportert:"
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."
@@ -24676,6 +25549,9 @@ msgstr ""
msgid "The form contains the following error:"
msgstr ""
+msgid "The form contains the following warning:"
+msgstr ""
+
msgid "The global settings require you to enable Two-Factor Authentication for your account."
msgstr ""
@@ -24689,7 +25565,7 @@ msgid "The group and its projects can only be viewed by members."
msgstr ""
msgid "The group can be fully restored"
-msgstr ""
+msgstr "Gruppen kan bli fullt gjenopprettet"
msgid "The group export can be downloaded from:"
msgstr ""
@@ -24707,13 +25583,13 @@ msgid "The import will time out after %{timeout}. For repositories that take lon
msgstr ""
msgid "The invitation could not be accepted."
-msgstr ""
+msgstr "Invitasjonen kunne ikke bli akseptert."
msgid "The invitation could not be declined."
-msgstr ""
+msgstr "Invitasjonen kunne ikke bli avslått."
msgid "The invitation has already been accepted."
-msgstr ""
+msgstr "Invitasjonen har allerede blitt akseptert."
msgid "The invitation was successfully resent."
msgstr ""
@@ -24737,10 +25613,10 @@ msgid "The license was successfully uploaded and will be active from %{starts_at
msgstr ""
msgid "The maximum file size allowed is %{size}."
-msgstr ""
+msgstr "Den maks tillatte filstørrelsen er %{size}."
msgid "The maximum file size allowed is 200KB."
-msgstr ""
+msgstr "Den maksimale filstørrelsen som er tillatt er 200KB."
msgid "The merge conflicts for this merge request cannot be resolved through GitLab. Please try to resolve them locally."
msgstr ""
@@ -24758,7 +25634,7 @@ msgid "The name \"%{name}\" is already taken in this directory."
msgstr ""
msgid "The number of changes to be fetched from GitLab when cloning a repository. This can speed up Pipelines execution. Keep empty or set to 0 to disable shallow clone by default and make GitLab CI fetch all branches and tags each time."
-msgstr ""
+msgstr "Antall endringer som skal innhentes fra GitLab når du kloner et kodelager. Dette kan øke hastigheten på utførelsen av rørledninger. Hold det tomt eller sett til 0 for å deaktivere tynn kloning som standard og få GitLab CI til å hente alle grener og etiketter hver gang."
msgid "The number of merge requests merged by month."
msgstr ""
@@ -24790,9 +25666,6 @@ msgstr ""
msgid "The private key to use when a client certificate is provided. This value is encrypted at rest."
msgstr ""
-msgid "The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The project can be accessed by any logged in user."
msgstr ""
@@ -24815,13 +25688,13 @@ msgid "The project is still being deleted. Please try again later."
msgstr ""
msgid "The project was successfully forked."
-msgstr ""
+msgstr "Prosjektet ble vellykket utgreinet."
msgid "The project was successfully imported."
-msgstr ""
+msgstr "Prosjektet ble vellykket importert."
msgid "The pseudonymizer data collection is disabled. When enabled, GitLab will run a background job that will produce pseudonymized CSVs of the GitLab database that will be uploaded to your configured object storage directory."
-msgstr ""
+msgstr "Pseudonymisert datainnsamling er deaktivert. Når den er aktivert, vil GitLab kjøre en bakgrunnsjobb som vil opprette pseudonymiserte CSV-filer av GitLab-databasen. Disse vil bli lastet opp til den konfigurerte objektlagringskatalogen."
msgid "The remote mirror took to long to complete."
msgstr ""
@@ -24829,17 +25702,17 @@ msgstr ""
msgid "The remote repository is being updated..."
msgstr ""
-msgid "The repository can be commited to, and issues, comments and other entities can be created."
+msgid "The repository can be committed to, and issues, comments and other entities can be created."
msgstr ""
msgid "The repository for this project does not exist."
-msgstr ""
+msgstr "Kodelageret til dette prosjektet finnes ikke."
msgid "The repository for this project is empty"
-msgstr ""
+msgstr "Kodelageret for dette prosjektet er tomt"
msgid "The repository is being updated..."
-msgstr ""
+msgstr "Kodelageret blir for øyeblikket oppdatert …"
msgid "The repository must be accessible over %{code_open}http://%{code_close}, %{code_open}https://%{code_close} or %{code_open}git://%{code_close}."
msgstr ""
@@ -24860,13 +25733,13 @@ msgid "The snippet can be accessed without any authentication."
msgstr ""
msgid "The snippet is visible only to me."
-msgstr ""
+msgstr "Utdraget er bare synlig for meg."
msgid "The snippet is visible only to project members."
-msgstr ""
+msgstr "Utdraget er bare synlig for prosjektmedlemmer."
msgid "The snippet is visible to any logged in user."
-msgstr ""
+msgstr "Utdraget er synlig for alle påloggede brukere."
msgid "The specified tab is invalid, please select another"
msgstr ""
@@ -24875,17 +25748,14 @@ msgid "The staging stage shows the time between merging the MR and deploying cod
msgstr ""
msgid "The status of the table below only applies to the default branch and is based on the %{linkStart}latest pipeline%{linkEnd}. Once you've enabled a scan for the default branch, any subsequent feature branch you create will include the scan."
-msgstr ""
+msgstr "Statusen i tabellen nedenfor gjelder bare for standardgrenen og er basert på den %{linkStart}nyeste rørledningen%{linkEnd}. Når du har aktivert en skanning for standardgrenen, vil enhver påfølgende funksjon gren du oppretter inkludere skanningen."
msgid "The testing stage shows the time GitLab CI takes to run every pipeline for the related merge request. The data will automatically be added after your first pipeline finishes running."
-msgstr ""
+msgstr "Testtrinnet viser tiden GitLab CI bruker på å kjøre hver rørledning for den relaterte fletteforespørselen. Dataene vil automatisk bli lagt til etter at den første rørledningen din er ferdig med å kjøre."
msgid "The time taken by each data entry gathered by that stage."
msgstr ""
-msgid "The total stage shows the time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The update action will time out after %{number_of_minutes} minutes. For big repositories, use a clone/push combination."
msgstr ""
@@ -24896,16 +25766,16 @@ msgid "The usage ping is disabled, and cannot be configured through this form."
msgstr ""
msgid "The user is being deleted."
-msgstr ""
+msgstr "Brukeren blir for øyeblikket slettet."
msgid "The user map has been saved. Continue by selecting the projects you want to import."
msgstr ""
msgid "The user map is a JSON document mapping the Google Code users that participated on your projects to the way their email addresses and usernames will be imported into GitLab. You can change this by changing the value on the right hand side of %{code_open}:%{code_close}. Be sure to preserve the surrounding double quotes, other punctuation and the email address or username on the left hand side."
-msgstr ""
+msgstr "Brukerkartet er et JSON-dokument som tilordner Google Code-brukere som deltok på dine prosjekter, til måten deres e-postadresser og brukernavn vil bli importert til GitLab. Du kan endre dette ved å endre verdien på høyre side av %{code_open}:%{code_close}. Pass på å bevare doble anførselstanker, andre punktumtegn, og e-postadressen eller brukernavnet på venstre side."
msgid "The user map is a mapping of the FogBugz users that participated on your projects to the way their email address and usernames will be imported into GitLab. You can change this by populating the table below."
-msgstr ""
+msgstr "Brukerkartet er en kartlegging av FogBugz-brukerne som deltok på prosjektene dine til måten deres e-postadresse og brukernavn blir importert til GitLab. Du kan endre dette ved å fylle ut tabellen nedenfor."
msgid "The user you are trying to deactivate has been active in the past %{minimum_inactive_days} days and cannot be deactivated"
msgstr ""
@@ -24923,7 +25793,7 @@ msgid "The vulnerability is no longer detected. Verify the vulnerability has bee
msgstr ""
msgid "There are currently no events."
-msgstr ""
+msgstr "Det er ingen hendelser for øyeblikket."
msgid "There are merge conflicts"
msgstr ""
@@ -24932,10 +25802,10 @@ msgid "There are no %{replicableTypeName} to show"
msgstr ""
msgid "There are no GPG keys associated with this account."
-msgstr ""
+msgstr "Det er ingen GPG-nøkler tilknyttet denne kontoen."
msgid "There are no GPG keys with access to your account."
-msgstr ""
+msgstr "Det er ingen GPG-nøkler med tilgang til kontoen din."
msgid "There are no SSH keys associated with this account."
msgstr ""
@@ -24944,19 +25814,22 @@ msgid "There are no SSH keys with access to your account."
msgstr ""
msgid "There are no archived projects yet"
-msgstr ""
+msgstr "Det er ingen arkiverte prosjekter ennå"
msgid "There are no archived requirements"
+msgstr "Det er ingen arkiverte krav"
+
+msgid "There are no archived test cases"
msgstr ""
msgid "There are no changes"
-msgstr ""
+msgstr "Det er ingen endringer"
msgid "There are no charts configured for this page"
msgstr ""
msgid "There are no closed issues"
-msgstr ""
+msgstr "Det er ingen lukkede saker"
msgid "There are no closed merge requests"
msgstr ""
@@ -24965,41 +25838,47 @@ msgid "There are no commits yet."
msgstr ""
msgid "There are no custom project templates set up for this GitLab instance. They are enabled from GitLab's Admin Area. Contact your GitLab instance administrator to setup custom project templates."
-msgstr ""
+msgstr "Det er ingen tilpassede prosjektmaler satt opp for denne GitLab-instansen. De er aktivert fra GitLab sitt Admin-område. Kontakt din GitLab-instansadministrator for å sette opp egendefinerte prosjektmaler."
msgid "There are no issues to show"
-msgstr ""
+msgstr "Det er ingen saker å vise"
msgid "There are no issues to show."
-msgstr ""
+msgstr "Det er ingen saker å vise."
msgid "There are no labels yet"
-msgstr ""
+msgstr "Det er ingen stempler ennå"
msgid "There are no matching files"
-msgstr ""
+msgstr "Det er ingen samsvarende filer"
msgid "There are no open issues"
-msgstr ""
+msgstr "Det er ingen åpne saker"
msgid "There are no open merge requests"
msgstr ""
msgid "There are no open requirements"
+msgstr "Det er ingen åpne krav"
+
+msgid "There are no open test cases"
msgstr ""
msgid "There are no packages yet"
-msgstr ""
+msgstr "Det er ingen pakker ennå"
msgid "There are no projects shared with this group yet"
msgstr ""
msgid "There are no variables yet."
-msgstr ""
+msgstr "Det er ingen variabler enda."
msgid "There is a limit of %{ci_project_subscriptions_limit} subscriptions from or to a project."
msgstr ""
+msgid "There is already a To-Do for this design."
+msgstr ""
+
msgid "There is already a repository with that name on disk"
msgstr ""
@@ -25018,26 +25897,29 @@ msgstr ""
msgid "There was a problem communicating with your device."
msgstr ""
-msgid "There was a problem fetching groups."
+msgid "There was a problem fetching branches."
msgstr ""
+msgid "There was a problem fetching groups."
+msgstr "En feil oppstod under innhenting av grupper."
+
msgid "There was a problem fetching labels."
-msgstr ""
+msgstr "En feil oppstod under innhenting av stempler."
msgid "There was a problem fetching milestones."
-msgstr ""
+msgstr "En feil oppstod under innhenting av milepæler."
msgid "There was a problem fetching project branches."
-msgstr ""
+msgstr "En feil oppstod under innhenting av prosjektgreiner."
msgid "There was a problem fetching project tags."
-msgstr ""
+msgstr "En feil oppstod under innhenting av prosjektetiketter."
msgid "There was a problem fetching project users."
-msgstr ""
+msgstr "En feil oppstod under innhenting av prosjektbrukere."
msgid "There was a problem fetching users."
-msgstr ""
+msgstr "En feil oppstod under innhenting av brukere."
msgid "There was a problem refreshing the data, please try again"
msgstr ""
@@ -25061,7 +25943,7 @@ msgid "There was an error creating the dashboard, branch named: %{branch} alread
msgstr ""
msgid "There was an error creating the issue"
-msgstr ""
+msgstr "En feil oppstod under oppretting av saken"
msgid "There was an error deleting the To Do."
msgstr ""
@@ -25082,10 +25964,10 @@ msgid "There was an error fetching median data for stages"
msgstr ""
msgid "There was an error fetching the %{replicableType}"
-msgstr ""
+msgstr "En feil oppstod under innhenting av %{replicableType}"
msgid "There was an error fetching the Geo Settings"
-msgstr ""
+msgstr "Det oppstod en feil under innhenting av Geo-innstillingene"
msgid "There was an error fetching the Node's Groups"
msgstr ""
@@ -25100,7 +25982,7 @@ msgid "There was an error fetching the top labels for the selected group"
msgstr ""
msgid "There was an error fetching the variables."
-msgstr ""
+msgstr "Det oppstod en feil under innhenting av variablene."
msgid "There was an error fetching value stream analytics stages."
msgstr ""
@@ -25112,7 +25994,7 @@ msgid "There was an error getting the epic participants."
msgstr ""
msgid "There was an error importing the Jira project."
-msgstr ""
+msgstr "Det oppstod en feil under importering av Jira-prosjektet."
msgid "There was an error loading users activity calendar."
msgstr ""
@@ -25136,10 +26018,10 @@ msgid "There was an error retrieving the Jira users."
msgstr ""
msgid "There was an error saving this Geo Node."
-msgstr ""
+msgstr "En feil oppstod under lagring av denne geo-noden."
msgid "There was an error saving your changes."
-msgstr ""
+msgstr "En feil oppstod under lagring av endringene dine."
msgid "There was an error saving your notification settings."
msgstr ""
@@ -25157,7 +26039,7 @@ msgid "There was an error trying to validate your query"
msgstr ""
msgid "There was an error updating the Geo Settings"
-msgstr ""
+msgstr "Det oppstod en feil under oppdatering av Geo-innstillingene"
msgid "There was an error updating the dashboard, branch name is invalid."
msgstr ""
@@ -25208,13 +26090,13 @@ msgid "Third Party Advisory Link"
msgstr ""
msgid "Third party offers"
-msgstr ""
+msgstr "Tredjepartstilbud"
msgid "This %{issuableDisplayName} is locked. Only project members can comment."
msgstr ""
msgid "This %{issuableType} is confidential"
-msgstr ""
+msgstr "Denne %{issuableType} er konfidensiell"
msgid "This %{issuable} is locked. Only %{strong_open}project members%{strong_close} can comment."
msgstr ""
@@ -25246,14 +26128,20 @@ msgstr ""
msgid "This action can lead to data loss. To prevent accidental actions we ask you to confirm your intention."
msgstr ""
+msgid "This action cannot be undone, and will permanently delete the %{key} SSH key"
+msgstr ""
+
msgid "This action cannot be undone. You will lose the project's repository and all content: issues, merge requests, etc."
msgstr ""
-msgid "This action will %{strongOpen}permanently delete%{strongClose} %{codeOpen}%{project}%{codeClose} %{strongOpen}immediately%{strongClose}, including its repositories and all content: issues, merge requests, etc."
+msgid "This action has been performed too many times. Try again later."
msgstr ""
+msgid "This action will %{strongOpen}permanently delete%{strongClose} %{codeOpen}%{project}%{codeClose} %{strongOpen}immediately%{strongClose}, including its repositories and all content: issues, merge requests, etc."
+msgstr "Denne handlingen vil %{strongOpen}permanent slette%{strongClose} %{codeOpen}%{project}%{codeClose} %{strongOpen}umiddelbart%{strongClose}, inkludert kodelagrene dens og alt innhold: saker, fletteforespørsler, osv."
+
msgid "This action will %{strongOpen}permanently delete%{strongClose} %{codeOpen}%{project}%{codeClose} %{strongOpen}on %{date}%{strongClose}, including its repositories and all content: issues, merge requests, etc."
-msgstr ""
+msgstr "Denne handlingen vil %{strongOpen}permanent slette%{strongClose} %{codeOpen}%{project}%{codeClose} %{strongOpen}den %{date}%{strongClose}, inkludert kodelagrene dens og alt innhold: saker, fletteforespørsler, osv."
msgid "This also resolves all related threads"
msgstr ""
@@ -25268,7 +26156,7 @@ msgid "This application will be able to:"
msgstr ""
msgid "This attachment has been truncated to avoid exceeding the maximum allowed attachment size of 15MB. %{written_count} of %{issues_count} issues have been included. Consider re-exporting with a narrower selection of issues."
-msgstr ""
+msgstr "Dette vedlegget har blitt avkortet for å unngå å overskride den maksimalt tillatte størrelsen på vedlegg på 15 MB. %{written_count} av %{issues_count} saker har blitt inkludert. Vurder å eksportere på nytt med et smalere valg av saker."
msgid "This block is self-referential"
msgstr ""
@@ -25276,9 +26164,6 @@ msgstr ""
msgid "This board's scope is reduced"
msgstr ""
-msgid "This branch has changed since you started editing. Would you like to create a new branch?"
-msgstr ""
-
msgid "This chart could not be displayed"
msgstr ""
@@ -25325,13 +26210,13 @@ msgid "This device has not been registered with us."
msgstr ""
msgid "This diff is collapsed."
-msgstr ""
+msgstr "Denne diffen er klappet sammen."
msgid "This diff was suppressed by a .gitattributes entry."
msgstr ""
msgid "This directory"
-msgstr ""
+msgstr "Denne mappen"
msgid "This domain is not verified. You will need to verify ownership before access is enabled."
msgstr ""
@@ -25364,10 +26249,10 @@ msgid "This feature should be used with an index that was created after 13.0"
msgstr ""
msgid "This field is required."
-msgstr ""
+msgstr "Dette feltet er påkrevd."
msgid "This group"
-msgstr ""
+msgstr "Denne gruppen"
msgid "This group cannot be invited to a project inside a group with enforced SSO"
msgstr ""
@@ -25391,7 +26276,7 @@ msgid "This is a \"Ghost User\", created to hold all issues authored by users th
msgstr ""
msgid "This is a Premium feature"
-msgstr ""
+msgstr "Dette er en Premium-funksjon"
msgid "This is a confidential %{noteableTypeText}."
msgstr ""
@@ -25405,20 +26290,14 @@ msgstr ""
msgid "This is a security log of important events involving your account."
msgstr ""
-msgid "This is the author's first Merge Request to this project."
-msgstr ""
-
msgid "This is the highest peak of users on your installation since the license started."
msgstr ""
-msgid "This is the maximum number of users that have existed at the same time since the license started. This is the minimum number of seats you will need to buy when you renew your license."
-msgstr ""
-
msgid "This is the number of currently active users on your installation, and this is the minimum number you need to purchase when you renew your license."
msgstr ""
msgid "This is your current session"
-msgstr ""
+msgstr "Dette er din nåværende økt"
msgid "This issue is currently blocked by the following issues: %{issues}."
msgstr ""
@@ -25436,16 +26315,16 @@ msgid "This job does not have a trace."
msgstr ""
msgid "This job has been canceled"
-msgstr ""
+msgstr "Denne jobben er avbrutt"
msgid "This job has been skipped"
-msgstr ""
+msgstr "Denne jobben har blitt hoppet over"
msgid "This job has not been triggered yet"
-msgstr ""
+msgstr "Denne jobben har ikke blitt utløst enda"
msgid "This job has not started yet"
-msgstr ""
+msgstr "Denne jobben har ikke startet enda"
msgid "This job is an out-of-date deployment to %{environmentLink} using cluster %{clusterNameOrLink} and namespace %{kubernetesNamespace}."
msgstr ""
@@ -25493,7 +26372,7 @@ msgid "This job is deployed to %{environmentLink} using cluster %{clusterNameOrL
msgstr ""
msgid "This job is deployed to %{environmentLink}."
-msgstr ""
+msgstr "Denne jobben distribueres til %{environmentLink}."
msgid "This job is in pending state and is waiting to be picked by a runner"
msgstr ""
@@ -25502,7 +26381,7 @@ msgid "This job is performing tasks that must complete before it can start"
msgstr ""
msgid "This job is preparing to start"
-msgstr ""
+msgstr "Jobben venter på å begynne"
msgid "This job is waiting for resource: "
msgstr ""
@@ -25517,13 +26396,13 @@ msgid "This job will automatically run after its timer finishes. Often they are
msgstr ""
msgid "This license has already expired."
-msgstr ""
+msgstr "Denne lisensen har allerede utløpt."
msgid "This link points to external content"
msgstr ""
msgid "This may expose confidential information as the selected fork is in another namespace that can have other members."
-msgstr ""
+msgstr "Dette kan avsløre konfidensiell informasjon, ettersom den valgte utgreiningen er i et annet navneområde som kan ha andre medlemmer."
msgid "This means you can not push code until you create an empty repository or import existing one."
msgstr ""
@@ -25550,7 +26429,7 @@ msgid "This only applies to repository indexing operations."
msgstr ""
msgid "This option is only available on GitLab.com"
-msgstr ""
+msgstr "Denne innstillingen er kun tilgjengelig på GitLab.com"
msgid "This page is unavailable because you are not allowed to read information across multiple projects."
msgstr ""
@@ -25571,13 +26450,13 @@ msgid "This pipeline was triggered by a schedule."
msgstr ""
msgid "This project"
-msgstr ""
+msgstr "Dette prosjektet"
msgid "This project does not belong to a group and can therefore not make use of group Runners."
msgstr ""
msgid "This project does not have %{service_desk_link_start}Service Desk%{service_desk_link_end} enabled, so the user who created the issue will no longer receive email notifications about new activity."
-msgstr ""
+msgstr "Dette prosjektet har ikke %{service_desk_link_start}Tjenestedesken%{service_desk_link_end} aktivert, så brukeren som opprettet problemet vil ikke lenger motta e-postvarsler om ny aktivitet."
msgid "This project does not have a wiki homepage yet"
msgstr ""
@@ -25601,13 +26480,13 @@ msgid "This project will be removed on %{date} since its parent group '%{parent_
msgstr ""
msgid "This project will live in your group %{strong_open}%{namespace}%{strong_close}. A project is where you house your files (repository), plan your work (issues), publish your documentation (wiki), and so much more."
-msgstr ""
+msgstr "Prosjektet vil leve i gruppen din %{strong_open}%{namespace}%{strong_close}. Et prosjekt er der du huser filene dine (kodelager), planlegger arbeidet ditt (problemer), publiserer dokumentasjonen (wiki) og så mye mer."
msgid "This repository"
-msgstr ""
+msgstr "Dette kodelageret"
msgid "This repository has never been checked."
-msgstr ""
+msgstr "Dette kodelageret har aldri blitt sjekket."
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 ""
@@ -25640,14 +26519,23 @@ msgid "This user cannot be unlocked manually from GitLab"
msgstr ""
msgid "This user has no active %{type}."
-msgstr ""
+msgstr "Denne brukeren har ingen aktive %{type}."
msgid "This user has no identities"
+msgstr "Denne brukeren har ingen identiteter"
+
+msgid "This user has previously committed to the %{name} project."
msgstr ""
-msgid "This user will be the author of all events in the activity feed that are the result of an update, like new branches being created or new commits being pushed to existing branches."
+msgid "This user has the %{access} role in the %{name} project."
msgstr ""
+msgid "This user is the author of this %{noteable}."
+msgstr ""
+
+msgid "This user will be the author of all events in the activity feed that are the result of an update, like new branches being created or new commits being pushed to existing branches."
+msgstr "Denne brukeren vil være skaperen for alle hendelser i aktivitetsstrømmen som er resultatet av en oppdatering, for eksempel nye grener som blir opprettet eller nye commits som blir pushet til eksisterende grener."
+
msgid "This variable can not be masked."
msgstr ""
@@ -25673,10 +26561,13 @@ msgid "Thread to reply to cannot be found"
msgstr ""
msgid "Threat Monitoring"
+msgstr "Trusselovervåking"
+
+msgid "ThreatMonitoring|All Environments"
msgstr ""
msgid "ThreatMonitoring|Anomalous Requests"
-msgstr ""
+msgstr "Abnormale forespørsler"
msgid "ThreatMonitoring|Application firewall not detected"
msgstr ""
@@ -25691,10 +26582,10 @@ msgid "ThreatMonitoring|Container NetworkPolicies not detected"
msgstr ""
msgid "ThreatMonitoring|Dropped Packets"
-msgstr ""
+msgstr "Droppede pakker"
msgid "ThreatMonitoring|Environment"
-msgstr ""
+msgstr "Miljø"
msgid "ThreatMonitoring|No environments detected"
msgstr ""
@@ -25702,41 +26593,41 @@ msgstr ""
msgid "ThreatMonitoring|Operations Per Second"
msgstr ""
-msgid "ThreatMonitoring|Overview"
-msgstr ""
-
msgid "ThreatMonitoring|Packet Activity"
-msgstr ""
+msgstr "Pakkeaktivitet"
msgid "ThreatMonitoring|Policies"
-msgstr ""
+msgstr "Retningslinjer"
msgid "ThreatMonitoring|Requests"
-msgstr ""
+msgstr "Forespørsler"
msgid "ThreatMonitoring|Show last"
-msgstr ""
+msgstr "Vis siste"
msgid "ThreatMonitoring|Something went wrong, unable to fetch environments"
-msgstr ""
+msgstr "Noe gikk galt, kunne ikke innhente miljøer"
msgid "ThreatMonitoring|Something went wrong, unable to fetch statistics"
+msgstr "Noe gikk galt, kunne ikke innhente statistikker"
+
+msgid "ThreatMonitoring|Statistics"
msgstr ""
msgid "ThreatMonitoring|The firewall is not installed or has been disabled. To view this data, ensure the web application firewall is installed and enabled for your cluster."
msgstr ""
msgid "ThreatMonitoring|The graph below is an overview of traffic coming to your application as tracked by the Web Application Firewall (WAF). View the docs for instructions on how to access the WAF logs to see what type of malicious traffic is trying to access your app. The docs link is also accessible by clicking the \"?\" icon next to the title below."
-msgstr ""
+msgstr "TGrafen nedenfor er en oversikt over trafikk som kommer inn til applikasjonen din, som sporet av Web Application Firewall (WAF). Se dokumentene for instruksjoner om hvordan du får tilgang til WAF-loggene for å se hvilken type skadelig trafikk som prøver å få tilgang til appen din. Dokumentkoblingen er også tilgjengelig ved å klikke på «?»-ikonet ved siden av tittelen nedenfor."
msgid "ThreatMonitoring|Threat Monitoring"
-msgstr ""
+msgstr "Trusselovervåking"
msgid "ThreatMonitoring|Threat Monitoring help page link"
msgstr ""
msgid "ThreatMonitoring|Time"
-msgstr ""
+msgstr "Tid"
msgid "ThreatMonitoring|To view this data, ensure you have configured an environment for this project and that at least one threat monitoring feature is enabled."
msgstr ""
@@ -25748,22 +26639,22 @@ msgid "ThreatMonitoring|Total Requests"
msgstr ""
msgid "ThreatMonitoring|View documentation"
-msgstr ""
+msgstr "Vis dokumentasjon"
msgid "ThreatMonitoring|Web Application Firewall"
msgstr ""
msgid "ThreatMonitoring|While it's rare to have no traffic coming to your application, it can happen. In any event, we ask that you double check your settings to make sure you've set up the WAF correctly."
-msgstr ""
+msgstr "Selv om det er sjeldent at det ikke kommer trafikk inn til applikasjonen din, kan det skje. I alle fall ber vi deg dobbeltsjekke innstillingene dine for å sikre at du har konfigurert WAF-en riktig."
msgid "Throughput"
msgstr ""
msgid "Thursday"
-msgstr ""
+msgstr "Torsdag"
msgid "Time"
-msgstr ""
+msgstr "Tid"
msgid "Time based: Yes"
msgstr ""
@@ -25781,31 +26672,31 @@ msgid "Time between merge request creation and merge/close"
msgstr ""
msgid "Time estimate"
-msgstr ""
+msgstr "Tidsanslag"
msgid "Time from first comment to last commit"
-msgstr ""
+msgstr "Tid fra første commit til siste commit"
msgid "Time from first commit until first comment"
-msgstr ""
+msgstr "Tid fra første commit til første kommentar"
msgid "Time from last commit to merge"
-msgstr ""
+msgstr "Tid fra siste commit til innfletting"
msgid "Time in seconds"
-msgstr ""
+msgstr "Tid i sekunder"
msgid "Time in seconds GitLab will wait for a response from the external service. When the service does not respond in time, access will be denied."
msgstr ""
msgid "Time of import: %{importTime}"
-msgstr ""
+msgstr "Importeringstid: %{importTime}"
msgid "Time remaining"
-msgstr ""
+msgstr "Gjenstående tid"
msgid "Time spent"
-msgstr ""
+msgstr "Tid brukt"
msgid "Time to merge"
msgstr ""
@@ -25826,7 +26717,7 @@ msgid "TimeTracking|%{startTag}Spent: %{endTag}%{timeSpentHumanReadable}"
msgstr ""
msgid "TimeTracking|Estimated:"
-msgstr ""
+msgstr "Anslått:"
msgid "TimeTracking|Over by %{timeRemainingHumanReadable}"
msgstr ""
@@ -25838,170 +26729,170 @@ msgid "TimeTracking|Time remaining: %{timeRemainingHumanReadable}"
msgstr ""
msgid "Timeago|%s days ago"
-msgstr ""
+msgstr "%s dager siden"
msgid "Timeago|%s days remaining"
-msgstr ""
+msgstr "%s dager gjenstår"
msgid "Timeago|%s hours ago"
-msgstr ""
+msgstr "%s timer siden"
msgid "Timeago|%s hours remaining"
-msgstr ""
+msgstr "%s timer gjenstår"
msgid "Timeago|%s minutes ago"
-msgstr ""
+msgstr "%s minutter siden"
msgid "Timeago|%s minutes remaining"
-msgstr ""
+msgstr "%s minutter gjenstår"
msgid "Timeago|%s months ago"
-msgstr ""
+msgstr "%s måneder siden"
msgid "Timeago|%s months remaining"
-msgstr ""
+msgstr "%s måneder gjenstår"
msgid "Timeago|%s seconds remaining"
-msgstr ""
+msgstr "%s sekunder gjenstår"
msgid "Timeago|%s weeks ago"
-msgstr ""
+msgstr "%s uker siden"
msgid "Timeago|%s weeks remaining"
-msgstr ""
+msgstr "%s uker gjenstår"
msgid "Timeago|%s years ago"
-msgstr ""
+msgstr "%s år siden"
msgid "Timeago|%s years remaining"
-msgstr ""
+msgstr "%s år gjenstår"
msgid "Timeago|1 day ago"
-msgstr ""
+msgstr "1 dag siden"
msgid "Timeago|1 day remaining"
-msgstr ""
+msgstr "1 dag gjenstår"
msgid "Timeago|1 hour ago"
-msgstr ""
+msgstr "1 time siden"
msgid "Timeago|1 hour remaining"
-msgstr ""
+msgstr "1 time gjenstår"
msgid "Timeago|1 minute ago"
-msgstr ""
+msgstr "1 minutt siden"
msgid "Timeago|1 minute remaining"
-msgstr ""
+msgstr "1 minutt gjenstår"
msgid "Timeago|1 month ago"
-msgstr ""
+msgstr "1 måned siden"
msgid "Timeago|1 month remaining"
-msgstr ""
+msgstr "1 måned gjenstår"
msgid "Timeago|1 week ago"
-msgstr ""
+msgstr "1 uke siden"
msgid "Timeago|1 week remaining"
-msgstr ""
+msgstr "1 uke gjenstår"
msgid "Timeago|1 year ago"
-msgstr ""
+msgstr "1 år siden"
msgid "Timeago|1 year remaining"
-msgstr ""
+msgstr "1 år gjenstår"
msgid "Timeago|Past due"
-msgstr ""
+msgstr "Forfalt"
msgid "Timeago|in %s days"
-msgstr ""
+msgstr "om %s dager"
msgid "Timeago|in %s hours"
-msgstr ""
+msgstr "om %s timer"
msgid "Timeago|in %s minutes"
-msgstr ""
+msgstr "om %s minutter"
msgid "Timeago|in %s months"
-msgstr ""
+msgstr "om %s måneder"
msgid "Timeago|in %s seconds"
-msgstr ""
+msgstr "om %s sekunder"
msgid "Timeago|in %s weeks"
-msgstr ""
+msgstr "om %s uker"
msgid "Timeago|in %s years"
-msgstr ""
+msgstr "om %s år"
msgid "Timeago|in 1 day"
-msgstr ""
+msgstr "om 1 dag"
msgid "Timeago|in 1 hour"
-msgstr ""
+msgstr "om 1 time"
msgid "Timeago|in 1 minute"
-msgstr ""
+msgstr "om 1 minutt"
msgid "Timeago|in 1 month"
-msgstr ""
+msgstr "om 1 måned"
msgid "Timeago|in 1 week"
-msgstr ""
+msgstr "om 1 uke"
msgid "Timeago|in 1 year"
-msgstr ""
+msgstr "om 1 år"
msgid "Timeago|just now"
-msgstr ""
+msgstr "nå nettopp"
msgid "Timeago|right now"
-msgstr ""
+msgstr "akkurat nå"
msgid "Timeout"
-msgstr ""
+msgstr "Tidsavbrudd"
msgid "Timeout connecting to the Google API. Please try again."
msgstr ""
msgid "Time|hr"
msgid_plural "Time|hrs"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "t"
+msgstr[1] "t"
msgid "Time|min"
msgid_plural "Time|mins"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "min"
+msgstr[1] "mins"
msgid "Time|s"
-msgstr ""
+msgstr "sek"
msgid "Tip:"
-msgstr ""
+msgstr "Tips:"
msgid "Title"
-msgstr ""
+msgstr "Tittel"
msgid "Title:"
-msgstr ""
+msgstr "Tittel:"
msgid "Titles and Descriptions"
-msgstr ""
+msgstr "Titler og beskrivelser"
msgid "To"
-msgstr ""
+msgstr "Til"
msgid "To %{link_to_help} of your domain, add the above key to a TXT record within to your DNS configuration."
msgstr ""
msgid "To Do"
-msgstr ""
+msgstr "Oppgaver"
msgid "To GitLab"
-msgstr ""
+msgstr "Til GitLab"
msgid "To access this domain create a new DNS record"
msgstr ""
@@ -26013,7 +26904,7 @@ msgid "To add the entry manually, provide the following details to the applicati
msgstr ""
msgid "To connect GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the %{code_open}repo%{code_close} scope, so we can display a list of your public and private repositories which are available to connect."
-msgstr ""
+msgstr "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."
msgid "To connect GitHub repositories, you first need to authorize GitLab to access the list of your GitHub repositories."
msgstr ""
@@ -26022,34 +26913,34 @@ msgid "To connect GitHub repositories, you first need to authorize GitLab to acc
msgstr ""
msgid "To connect an SVN repository, check out %{svn_link}."
-msgstr ""
+msgstr "For å koble til et SVN-kodelager, sjekk ut %{svn_link}."
msgid "To define internal users, first enable new users set to external"
msgstr ""
msgid "To further protect your account, consider configuring a %{mfa_link_start}two-factor authentication%{mfa_link_end} method."
-msgstr ""
+msgstr "For å beskytte kontoen din ytterligere, bør du vurdere å konfigurere en %{mfa_link_start}2-trinnsautentiserings%{mfa_link_end}metode."
msgid "To further protect your account, consider configuring a two-factor authentication method: %{mfa_link}."
-msgstr ""
+msgstr "For å beskytte kontoen din ytterligere, bør du vurdere å konfigurere en 2-trinnsautentiseringsmetode: %{mfa_link}."
msgid "To get started you enter your FogBugz URL and login information below. In the next steps, you'll be able to map users and select the projects you want to import."
-msgstr ""
+msgstr "For å komme i gang, skriv inn din FogBugz-URL og -påloggingsinformasjon nedenfor. I de neste trinnene vil du kunne kartlegge brukere og velge prosjektene du vil importere."
msgid "To get started, link this page to your Jaeger server, or find out how to %{link_start_tag}install Jaeger%{link_end_tag}"
msgstr ""
msgid "To get started, please enter your Gitea Host URL and a %{link_to_personal_token}."
-msgstr ""
+msgstr "For å komme i gang, skriv inn din Gitea-verts-URL og en %{link_to_personal_token}."
msgid "To help improve GitLab and its user experience, GitLab will periodically collect usage information."
-msgstr ""
+msgstr "For å forbedre GitLab og brukeropplevelsen dens, vil GitLab med jevne mellomrom samle inn bruksinformasjon."
msgid "To help improve GitLab, we would like to periodically collect usage information. This can be changed at any time in %{settings_link_start}Settings%{link_end}. %{info_link_start}More Information%{link_end}"
-msgstr ""
+msgstr "For å hjelpe til med å forbedre GitLab, vil vi periodisk samle inn bruksinformasjon. Dette kan endres når som helst i %{settings_link_start}Innstillinger%{link_end}. %{info_link_start}Mer informasjon%{link_end}"
msgid "To import an SVN repository, check out %{svn_link}."
-msgstr ""
+msgstr "For å importere et SVN-kodelager, sjekk ut %{svn_link}."
msgid "To keep this project going, create a new issue"
msgstr ""
@@ -26079,7 +26970,7 @@ msgid "To protect this issue's confidentiality, a private fork of this project w
msgstr ""
msgid "To receive alerts from manually configured Prometheus services, add the following URL and Authorization key to your Prometheus webhook config file. Learn more about %{linkStart}configuring Prometheus%{linkEnd} to send alerts to GitLab."
-msgstr ""
+msgstr "For å motta alarmer fra manuelt konfigurerte Prometheus-tjenester, legg til den følgende URL-en og autorisasjonsnøkkelen til din Prometeus-webhook-oppsettsfil. Lær mer om %{linkStart}å sette opp Prometheus%{linkEnd} til å sende varsler til GitLab."
msgid "To see all the user's personal access tokens you must impersonate them first."
msgstr ""
@@ -26094,7 +26985,7 @@ msgid "To set up SAML authentication for your group through an identity provider
msgstr ""
msgid "To set up this service:"
-msgstr ""
+msgstr "For å sette opp denne tjenesten:"
msgid "To simplify the billing process, GitLab will collect user counts in order to prorate charges for user growth throughout the year using a quarterly reconciliation process."
msgstr ""
@@ -26112,6 +27003,9 @@ msgid "To unsubscribe from this issue, please paste the following link into your
msgstr ""
msgid "To update Snippets with multiple files, you must use the `files` parameter"
+msgstr "For å oppdatere utdrag med flere filer, må du bruke `files`-parameteren"
+
+msgid "To use Gitpod you must first enable the feature in the integrations section of your %{user_prefs}."
msgstr ""
msgid "To view all %{scannedResourcesCount} scanned URLs, please download the CSV file"
@@ -26121,7 +27015,7 @@ msgid "To view instance-level analytics, ask an admin to turn on %{docLinkStart}
msgstr ""
msgid "To view the roadmap, add a start or due date to one of your epics in this group or its subgroups. In the months view, only epics in the past month, current month, and next 5 months are shown."
-msgstr ""
+msgstr "For å vise veikartet, legg til en start- eller forfallsdato til en av dine eposer i denne gruppen eller dens undergrupper. I månedsvisningen vises bare innholdet i den siste måneden, denne måneden og de neste 5 månedene."
msgid "To widen your search, change or remove filters above"
msgstr ""
@@ -26130,25 +27024,22 @@ msgid "To widen your search, change or remove filters."
msgstr ""
msgid "To-Do"
-msgstr ""
+msgstr "Gjøremål"
msgid "To-Do List"
-msgstr ""
+msgstr "Gjøremålsliste"
msgid "To-do item successfully marked as done."
msgstr ""
msgid "Today"
-msgstr ""
+msgstr "I dag"
msgid "Toggle Markdown preview"
-msgstr ""
+msgstr "Veksle Markdown-forhåndsvisning"
msgid "Toggle Sidebar"
-msgstr ""
-
-msgid "Toggle all threads"
-msgstr ""
+msgstr "Veksle sidelinje"
msgid "Toggle backtrace"
msgstr ""
@@ -26160,25 +27051,22 @@ msgid "Toggle comments for this file"
msgstr ""
msgid "Toggle commit description"
-msgstr ""
+msgstr "Veksle commit-beskrivelsen"
msgid "Toggle commit list"
-msgstr ""
+msgstr "Veksle commit-listen"
msgid "Toggle dropdown"
-msgstr ""
+msgstr "Veksle nedfall"
msgid "Toggle emoji award"
msgstr ""
msgid "Toggle navigation"
-msgstr ""
-
-msgid "Toggle project"
-msgstr ""
+msgstr "Veksle navigasjon"
msgid "Toggle sidebar"
-msgstr ""
+msgstr "Veksle sidelinje"
msgid "Toggle the Performance Bar"
msgstr ""
@@ -26187,7 +27075,7 @@ msgid "Toggle this dialog"
msgstr ""
msgid "Toggle thread"
-msgstr ""
+msgstr "Veksle tråd"
msgid "ToggleButton|Toggle Status: OFF"
msgstr ""
@@ -26205,10 +27093,10 @@ msgid "Token valid until revoked"
msgstr ""
msgid "Tomorrow"
-msgstr ""
+msgstr "I morgen"
msgid "Too many changes to show."
-msgstr ""
+msgstr "For mange endringer å vise."
msgid "Too many namespaces enabled. You will need to manage them via the console or the API."
msgstr ""
@@ -26216,47 +27104,53 @@ msgstr ""
msgid "Too many projects enabled. You will need to manage them via the console or the API."
msgstr ""
-msgid "Topics (optional)"
+msgid "Too much data"
msgstr ""
+msgid "Topics (optional)"
+msgstr "Emner (valgfritt)"
+
msgid "Total"
-msgstr ""
+msgstr "Totalt"
msgid "Total Contributions"
-msgstr ""
+msgstr "Totalt antall bidrag"
msgid "Total Score"
-msgstr ""
+msgstr "Totalscore"
msgid "Total artifacts size: %{total_size}"
msgstr ""
msgid "Total cores (CPUs)"
+msgstr "Totalt antall kjerner (CPU-er)"
+
+msgid "Total days to completion"
msgstr ""
msgid "Total issues"
msgstr ""
msgid "Total memory (GB)"
-msgstr ""
+msgstr "Totalt minne (GB)"
msgid "Total test time for all commits/merges"
-msgstr ""
+msgstr "Total testtid for alle commits/innflettinger"
msgid "Total weight"
-msgstr ""
+msgstr "Total vekt"
msgid "Total: %{total}"
-msgstr ""
+msgstr "Totalt: %{total}"
msgid "TotalRefCountIndicator|1000+"
msgstr ""
msgid "Trace"
-msgstr ""
+msgstr "Spore"
msgid "Tracing"
-msgstr ""
+msgstr "Sporing"
msgid "Track groups of issues that share a theme, across projects and milestones"
msgstr ""
@@ -26271,22 +27165,22 @@ msgid "Track your project with Audit Events."
msgstr ""
msgid "Transfer"
-msgstr ""
+msgstr "Overfør"
msgid "Transfer ownership"
-msgstr ""
+msgstr "Overfør eierskap"
msgid "Transfer project"
-msgstr ""
+msgstr "Overfør prosjekt"
msgid "TransferGroup|Cannot transfer group to one of its subgroup."
msgstr ""
msgid "TransferGroup|Cannot update the path because there are projects under this group that contain Docker images in their Container Registry. Please remove the images from your projects first and try again."
-msgstr ""
+msgstr "Kan ikke oppdatere filbanen fordi det er prosjekter innenfor denne gruppen som inneholder Docker-bilder i container-registeret. Fjern bildene fra prosjektene dine først, og prøv så på nytt."
msgid "TransferGroup|Database is not supported."
-msgstr ""
+msgstr "Databasen er ikke støttet."
msgid "TransferGroup|Group contains projects with NPM packages."
msgstr ""
@@ -26304,10 +27198,10 @@ msgid "TransferGroup|Transfer failed: %{error_message}"
msgstr ""
msgid "TransferGroup|You don't have enough permissions."
-msgstr ""
+msgstr "Du har ikke nok tillatelser."
msgid "TransferProject|Cannot move project"
-msgstr ""
+msgstr "Kan ikke flytte prosjektet"
msgid "TransferProject|Please select a new namespace for your project."
msgstr ""
@@ -26325,13 +27219,16 @@ msgid "TransferProject|Transfer failed, please contact an admin."
msgstr ""
msgid "Tree view"
-msgstr ""
+msgstr "Tre-visning"
msgid "Trending"
+msgstr "Populære"
+
+msgid "Trials|Create a new group to start your GitLab Gold trial."
msgstr ""
msgid "Trials|Go back to GitLab"
-msgstr ""
+msgstr "GÃ¥ tilbake til GitLab"
msgid "Trials|Skip Trial (Continue with Free Account)"
msgstr ""
@@ -26339,11 +27236,20 @@ msgstr ""
msgid "Trials|You can always resume this process by selecting your avatar and choosing 'Start a Gold trial'"
msgstr ""
+msgid "Trials|You can apply your trial to a new group or an existing group."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group or your personal account."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group, an existing group, or your personal account."
+msgstr ""
+
msgid "Trials|You won't get a free trial right now but you can always resume this process by clicking on your avatar and choosing 'Start a free trial'"
msgstr ""
msgid "Trigger"
-msgstr ""
+msgstr "Utløser"
msgid "Trigger cluster reindexing"
msgstr ""
@@ -26355,10 +27261,10 @@ msgid "Trigger pipelines for mirror updates"
msgstr ""
msgid "Trigger pipelines when branches or tags are updated from the upstream repository. Depending on the activity of the upstream repository, this may greatly increase the load on your CI runners. Only enable this if you know they can handle the load."
-msgstr ""
+msgstr "Trigg rørledninger når grener eller koder oppdateres fra oppstrømskodelageret. Avhengig av aktiviteten til oppstrømsregisteret, kan dette øke belastningen på CI-kjørerne dine kraftig. Bare aktiver dette hvis du vet at de kan takle belastningen."
msgid "Trigger removed."
-msgstr ""
+msgstr "Trigger fjernet."
msgid "Trigger repository check"
msgstr ""
@@ -26367,7 +27273,7 @@ msgid "Trigger this manual action"
msgstr ""
msgid "Trigger token:"
-msgstr ""
+msgstr "Triggersjetong:"
msgid "Trigger variables:"
msgstr ""
@@ -26376,7 +27282,7 @@ msgid "Trigger was created successfully."
msgstr ""
msgid "Trigger was successfully updated."
-msgstr ""
+msgstr "Triggeren ble vellykket oppdatert."
msgid "Triggerer"
msgstr ""
@@ -26388,19 +27294,19 @@ msgid "Troubleshoot and monitor your application with tracing"
msgstr ""
msgid "Try again"
-msgstr ""
+msgstr "Prøv igjen"
msgid "Try again?"
-msgstr ""
+msgstr "Prøv igjen?"
msgid "Try all GitLab has to offer for 30 days."
-msgstr ""
+msgstr "Prøv ut alt som GitLab har å tilby i 30 dager."
msgid "Try changing or removing filters."
msgstr ""
msgid "Try to fork again"
-msgstr ""
+msgstr "Prøv å utgreine på nytt"
msgid "Try to keep the first line under 52 characters and the others under 72."
msgstr ""
@@ -26408,23 +27314,26 @@ msgstr ""
msgid "Try using a different search term to find the file you are looking for."
msgstr ""
+msgid "Trying to communicate with your device. Plug it in (if needed) and press the button on the device now."
+msgstr ""
+
msgid "Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now."
msgstr ""
msgid "Tuesday"
-msgstr ""
+msgstr "Tirsdag"
msgid "Turn Off"
-msgstr ""
+msgstr "Slå av"
msgid "Turn On"
-msgstr ""
+msgstr "Slå på"
msgid "Turn on %{strongStart}usage ping%{strongEnd} to activate analysis of user activity, known as %{docLinkStart}Cohorts%{docLinkEnd}."
-msgstr ""
+msgstr "Skru på %{strongStart}bruks-ping%{strongEnd} for å aktivere analyse av brukeraktivitet, kjent som %{docLinkStart}Kohorter%{docLinkEnd}."
msgid "Turn on Service Desk"
-msgstr ""
+msgstr "Slå på Tjenestedesk"
msgid "Turn on usage ping"
msgstr ""
@@ -26433,55 +27342,55 @@ msgid "Turn on usage ping to review instance-level analytics."
msgstr ""
msgid "Twitter"
-msgstr ""
+msgstr "Twitter"
msgid "Two-Factor Authentication"
-msgstr ""
+msgstr "2-trinnautentisering"
msgid "Two-Factor Authentication code"
-msgstr ""
+msgstr "2-trinnsautentiseringskode"
msgid "Two-factor Authentication"
-msgstr ""
+msgstr "2-trinnautentisering"
msgid "Two-factor Authentication Recovery codes"
msgstr ""
msgid "Two-factor authentication"
-msgstr ""
+msgstr "2-trinnsautentisering"
msgid "Two-factor authentication disabled"
-msgstr ""
+msgstr "2-trinnautentisering er skrudd av"
msgid "Two-factor authentication has been disabled for this user"
-msgstr ""
+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!"
-msgstr ""
+msgstr "2-trinnautentisering har blitt skrudd av vellykket!"
msgid "Two-factor authentication is not enabled for this user"
-msgstr ""
+msgstr "2-trinnautentisering er ikke skrudd på for denne brukeren"
msgid "Type"
-msgstr ""
+msgstr "Type"
msgid "Type/State"
-msgstr ""
+msgstr "Type/Tilstand"
msgid "U2F Devices (%{length})"
-msgstr ""
+msgstr "U2F-enheter (%{length})"
msgid "U2F only works with HTTPS-enabled websites. Contact your administrator for more details."
msgstr ""
msgid "URL"
-msgstr ""
+msgstr "URL"
msgid "URL is required"
-msgstr ""
+msgstr "Nettadresse er påkrevd"
msgid "URL must start with %{codeStart}http://%{codeEnd}, %{codeStart}https://%{codeEnd}, or %{codeStart}ftp://%{codeEnd}"
msgstr ""
@@ -26493,31 +27402,37 @@ msgid "URL of the external storage that will serve the repository static objects
msgstr ""
msgid "URL or request ID"
+msgstr "URL eller forespørsels-ID"
+
+msgid "USER %{user} WILL BE REMOVED! Are you sure?"
msgstr ""
-msgid "UTC"
+msgid "USER WILL BE BLOCKED! Are you sure?"
msgstr ""
+msgid "UTC"
+msgstr "UTC"
+
msgid "Unable to apply suggestions to a deleted line."
-msgstr ""
+msgstr "Kan ikke benytte forslag på en slettet linje."
msgid "Unable to build Slack link."
msgstr ""
msgid "Unable to collect CPU info"
-msgstr ""
+msgstr "Klarte ikke å samle inn CPU-info"
msgid "Unable to collect memory info"
-msgstr ""
+msgstr "Klarte ikke å samle inn minneinfo"
msgid "Unable to connect to Elasticsearch"
msgstr ""
msgid "Unable to connect to Prometheus server"
-msgstr ""
+msgstr "Klarte ikke å koble til Prometheus-tjeneren"
msgid "Unable to connect to server: %{error}"
-msgstr ""
+msgstr "Klarte ikke å koble til tjeneren: %{error}"
msgid "Unable to connect to the Jira instance. Please check your Jira integration configuration."
msgstr ""
@@ -26526,40 +27441,37 @@ msgid "Unable to convert Kubernetes logs encoding to UTF-8"
msgstr ""
msgid "Unable to fetch unscanned projects"
-msgstr ""
+msgstr "Klarte ikke å innhente uskannede prosjekter"
msgid "Unable to fetch vulnerable projects"
-msgstr ""
+msgstr "Klarte ikke å innhente sårbare prosjekter"
msgid "Unable to find Jira project to import data from."
msgstr ""
msgid "Unable to generate new instance ID"
-msgstr ""
+msgstr "Klarte ikke å generere ny instans-ID"
msgid "Unable to load commits. Try again later."
-msgstr ""
+msgstr "Klarte ikke å laste inn commiter. Prøv igjen senere."
msgid "Unable to load file contents. Try again later."
-msgstr ""
+msgstr "Klarte ikke å laste inn filinnhold. Prøv igjen senere."
msgid "Unable to load the diff"
-msgstr ""
+msgstr "Klarte ikke å laste inn diffen"
msgid "Unable to load the diff. %{button_try_again}"
-msgstr ""
+msgstr "Klarte ikke å laste inn forskjellen. %{button_try_again}"
msgid "Unable to load the merge request widget. Try reloading the page."
msgstr ""
-msgid "Unable to resolve"
-msgstr ""
-
msgid "Unable to save iteration. Please try again"
msgstr ""
msgid "Unable to save your changes. Please try again."
-msgstr ""
+msgstr "Klarte ikke å lagre dine endringer. Vennligst prøv igjen."
msgid "Unable to schedule a pipeline to run immediately"
msgstr ""
@@ -26574,88 +27486,94 @@ msgid "Unable to update label prioritization at this time"
msgstr ""
msgid "Unable to update this epic at this time."
-msgstr ""
+msgstr "Kan ikke oppdatere dette eposet på dette tidspunktet."
msgid "Unable to update this issue at this time."
msgstr ""
msgid "Unarchive project"
-msgstr ""
+msgstr "Opphev arkivering av prosjekt"
msgid "Unarchiving the project will restore people's ability to make changes to it. The repository can be committed to, and issues, comments, and other entities can be created. %{strong_start}Once active, this project shows up in the search and on the dashboard.%{strong_end}"
-msgstr ""
+msgstr "Å fjerne arkivering av prosjektet vil gjenopprette folks evne til å gjøre endringer i det. Datalageret kan bli kodeinnsmettet til, og saker, kommentarer og andre enheter kan opprettes. %{strong_start}Når dette prosjektet er aktivt, vises det i søket og på kontrollpanelet.%{strong_end}"
msgid "Unassign from commenting user"
msgstr ""
msgid "Unassigned"
-msgstr ""
+msgstr "Ikke tildelte"
msgid "Unblock"
-msgstr ""
+msgstr "Fjern blokkering"
msgid "Undo"
-msgstr ""
+msgstr "Angre"
msgid "Undo Ignore"
-msgstr ""
+msgstr "Angre ignorering"
msgid "Undo ignore"
+msgstr "Angre ignorering"
+
+msgid "Unexpected error"
msgstr ""
msgid "Unfortunately, your email message to GitLab could not be processed."
msgstr ""
msgid "Uninstall"
-msgstr ""
+msgstr "Avinstaller"
msgid "Uninstalling"
-msgstr ""
+msgstr "Avinstallerer"
msgid "Units|ms"
-msgstr ""
+msgstr "ms"
msgid "Units|s"
-msgstr ""
+msgstr "sek"
msgid "Unknown"
-msgstr ""
+msgstr "Ukjent"
msgid "Unknown Error"
-msgstr ""
+msgstr "Ukjent feil"
msgid "Unknown cache key"
-msgstr ""
+msgstr "Ukjent hurtigbuffernøkkel"
msgid "Unknown encryption strategy: %{encrypted_strategy}!"
msgstr ""
msgid "Unknown format"
-msgstr ""
+msgstr "Ukjent format"
msgid "Unknown response text"
+msgstr "Ukjent responstekst"
+
+msgid "Unless otherwise agreed to in writing with GitLab, by clicking \"Upload License\" you agree that your use of GitLab Software is subject to the %{eula_link_start}Terms of Service%{eula_link_end}."
msgstr ""
msgid "Unlimited"
-msgstr ""
+msgstr "Ubegrenset"
msgid "Unlock"
-msgstr ""
+msgstr "LÃ¥s opp"
msgid "Unlock the discussion"
-msgstr ""
+msgstr "LÃ¥s opp diskusjonen"
msgid "Unlock this %{issuableDisplayName}? %{strongStart}Everyone%{strongEnd} will be able to comment."
msgstr ""
msgid "Unlocked"
-msgstr ""
+msgstr "LÃ¥st opp"
msgid "Unlocked the discussion."
-msgstr ""
+msgstr "LÃ¥ste opp diskusjonen."
msgid "Unlocks the discussion."
-msgstr ""
+msgstr "LÃ¥ser opp diskusjonen."
msgid "Unmarked this %{noun} as Work In Progress."
msgstr ""
@@ -26667,52 +27585,52 @@ msgid "Unreachable"
msgstr ""
msgid "Unrecognized cluster type"
-msgstr ""
+msgstr "Klyngetypen ble ikke gjenkjent"
msgid "Unresolve"
-msgstr ""
+msgstr "Uoppklar"
msgid "Unresolve thread"
-msgstr ""
+msgstr "Uoppklar tråden"
msgid "Unresolved"
-msgstr ""
+msgstr "Uoppklart"
msgid "UnscannedProjects|15 or more days"
-msgstr ""
+msgstr "15 eller flere dager"
msgid "UnscannedProjects|30 or more days"
-msgstr ""
+msgstr "30 eller flere dager"
msgid "UnscannedProjects|5 or more days"
-msgstr ""
+msgstr "5 eller flere dager"
msgid "UnscannedProjects|60 or more days"
-msgstr ""
+msgstr "60 eller flere dager"
msgid "UnscannedProjects|Default branch scanning by project"
msgstr ""
msgid "UnscannedProjects|Out of date"
-msgstr ""
+msgstr "Utdatert"
msgid "UnscannedProjects|Project scanning"
-msgstr ""
+msgstr "Prosjektskanning"
msgid "UnscannedProjects|Untested"
-msgstr ""
+msgstr "Utestet"
msgid "UnscannedProjects|Your projects are up do date! Nice job!"
-msgstr ""
+msgstr "Prosjektene dine er fullt oppdatert! Strålende jobbet!"
msgid "Unschedule job"
msgstr ""
msgid "Unstar"
-msgstr ""
+msgstr "Fjern stjerne"
msgid "Unsubscribe"
-msgstr ""
+msgstr "Avabonner"
msgid "Unsubscribe at group level"
msgstr ""
@@ -26721,7 +27639,7 @@ msgid "Unsubscribe at project level"
msgstr ""
msgid "Unsubscribe from %{type}"
-msgstr ""
+msgstr "Avslutt abonnent på %{type}"
msgid "Unsubscribed from this %{quick_action_target}."
msgstr ""
@@ -26733,61 +27651,61 @@ msgid "Unsupported todo type passed. Supported todo types are: %{todo_types}"
msgstr ""
msgid "Until"
-msgstr ""
+msgstr "Frem til"
msgid "Unused, previous index '%{index_name}' will be deleted after %{time} automatically."
msgstr ""
msgid "Unverified"
-msgstr ""
+msgstr "Ubekreftet"
msgid "Up to date"
-msgstr ""
+msgstr "Oppdatert"
msgid "Upcoming"
-msgstr ""
+msgstr "Kommende"
msgid "Upcoming Release"
-msgstr ""
+msgstr "Kommende utgivelse"
msgid "Update"
-msgstr ""
+msgstr "Oppdater"
msgid "Update %{sourcePath} file"
-msgstr ""
+msgstr "Oppdater %{sourcePath}-filen"
msgid "Update all"
-msgstr ""
+msgstr "Oppdater alle"
msgid "Update approval rule"
msgstr ""
msgid "Update approvers"
-msgstr ""
+msgstr "Oppdater godkjennere"
msgid "Update failed"
-msgstr ""
+msgstr "Oppdatering mislyktes"
msgid "Update failed. Please try again."
-msgstr ""
+msgstr "Oppdatering mislyktes. Vennligst prøv igjen."
msgid "Update it"
-msgstr ""
+msgstr "Oppdater den"
msgid "Update iteration"
msgstr ""
msgid "Update now"
-msgstr ""
+msgstr "Oppdater nå"
msgid "Update variable"
-msgstr ""
+msgstr "Oppdater variabel"
msgid "Update your bookmarked URLs as filtered/sorted branches URL has been changed."
msgstr ""
msgid "Update your group name, description, avatar, and visibility."
-msgstr ""
+msgstr "Oppdater ditt gruppenavn, beskrivelse, avatar og synlighet."
msgid "Update your project name, topics, description and avatar."
msgstr ""
@@ -26802,7 +27720,7 @@ msgid "UpdateProject|New visibility level not allowed!"
msgstr ""
msgid "UpdateProject|Project could not be updated!"
-msgstr ""
+msgstr "Prosjektet kunne ikke bli oppdatert!"
msgid "UpdateRepositoryStorage|Error moving repository storage for %{project_full_path} - %{message}"
msgstr ""
@@ -26814,28 +27732,28 @@ msgid "UpdateRepositoryStorage|Timeout waiting for %{type} repository pushes"
msgstr ""
msgid "Updated"
-msgstr ""
+msgstr "Oppdatert"
msgid "Updated %{updated_at} by %{updated_by}"
-msgstr ""
+msgstr "Oppdatert %{updated_at} av %{updated_by}"
msgid "Updated to %{linkStart}chart v%{linkEnd}"
msgstr ""
msgid "Updates"
-msgstr ""
+msgstr "Oppdateringer"
msgid "Updating"
-msgstr ""
+msgstr "Oppdaterer"
msgid "Upgrade plan to unlock Canary Deployments feature"
msgstr ""
msgid "Upgrade your plan"
-msgstr ""
+msgstr "Oppgrader planen din"
msgid "Upgrade your plan to activate Advanced Search."
-msgstr ""
+msgstr "Oppgrader planen din for å skru på avansert søking."
msgid "Upgrade your plan to activate Audit Events."
msgstr ""
@@ -26856,118 +27774,118 @@ msgid "Upload %{code_open}GoogleCodeProjectHosting.json%{code_close} here:"
msgstr ""
msgid "Upload CSV file"
-msgstr ""
+msgstr "Last opp CSV-fil"
msgid "Upload License"
-msgstr ""
+msgstr "Last opp lisens"
msgid "Upload New File"
-msgstr ""
+msgstr "Last opp ny fil"
msgid "Upload New License"
-msgstr ""
+msgstr "Last opp ny lisens"
msgid "Upload a certificate for your domain with all intermediates"
msgstr ""
msgid "Upload a private key for your certificate"
-msgstr ""
+msgstr "Last opp en privat nøkkel til sertifikatet ditt"
msgid "Upload file"
-msgstr ""
+msgstr "Last opp fil"
msgid "Upload object map"
-msgstr ""
+msgstr "Last opp objektkart"
msgid "UploadLink|click to upload"
-msgstr ""
+msgstr "klikk for å laste opp"
msgid "Uploaded on"
-msgstr ""
+msgstr "Lastet opp den"
msgid "Uploaded:"
-msgstr ""
+msgstr "Lastet opp:"
msgid "Uploading changes to terminal"
-msgstr ""
+msgstr "Laster opp endringer til terminalen"
msgid "Uploads"
-msgstr ""
+msgstr "Opplastinger"
msgid "Upon performing this action, the contents of this group, its subgroup and projects will be permanently removed after %{deletion_adjourned_period} days on %{date}. Until that time:"
-msgstr ""
+msgstr "Når du utfører denne handlingen, vil innholdet i denne gruppen, undergruppen og prosjektene bli permanent sletter etter %{deletion_adjourned_period} dager på %{date}. Frem til da:"
msgid "Upstream"
-msgstr ""
+msgstr "Oppstrøms"
msgid "Uptime"
-msgstr ""
+msgstr "Oppetid"
msgid "Upvotes"
-msgstr ""
+msgstr "Plusstemmer"
msgid "Usage"
-msgstr ""
+msgstr "Bruk"
msgid "Usage ping is off"
msgstr ""
msgid "Usage statistics"
-msgstr ""
+msgstr "Bruksstatistikk"
msgid "UsageQuota|%{help_link_start}Shared runners%{help_link_end} are disabled, so there are no limits set on pipeline usage"
msgstr ""
msgid "UsageQuota|Artifacts"
-msgstr ""
+msgstr "Artifakter"
msgid "UsageQuota|Build Artifacts"
msgstr ""
msgid "UsageQuota|Buy additional minutes"
-msgstr ""
+msgstr "Kjøp ekstra minutter"
msgid "UsageQuota|Current period usage"
-msgstr ""
+msgstr "Bruk i nåværende periode"
msgid "UsageQuota|Increase storage temporarily"
msgstr ""
msgid "UsageQuota|LFS Objects"
-msgstr ""
+msgstr "LFS-objekter"
msgid "UsageQuota|LFS Storage"
-msgstr ""
+msgstr "LFS-lagring"
msgid "UsageQuota|Packages"
-msgstr ""
+msgstr "Pakker"
msgid "UsageQuota|Pipelines"
-msgstr ""
+msgstr "Rørledninger"
msgid "UsageQuota|Purchase more storage"
-msgstr ""
+msgstr "Kjøp mer lagringsplass"
msgid "UsageQuota|Repositories"
-msgstr ""
+msgstr "Kodelagre"
msgid "UsageQuota|Repository"
-msgstr ""
+msgstr "Kodelager"
msgid "UsageQuota|Snippets"
-msgstr ""
+msgstr "Utdrag"
msgid "UsageQuota|Storage"
-msgstr ""
+msgstr "Lagring"
msgid "UsageQuota|This namespace has no projects which use shared runners"
msgstr ""
msgid "UsageQuota|Unlimited"
-msgstr ""
+msgstr "Ubegrenset"
msgid "UsageQuota|Usage"
-msgstr ""
+msgstr "Benyttelse"
msgid "UsageQuota|Usage Quotas"
msgstr ""
@@ -26982,16 +27900,16 @@ msgid "UsageQuota|Usage quotas help link"
msgstr ""
msgid "UsageQuota|Usage since"
-msgstr ""
+msgstr "Benyttelse siden"
msgid "UsageQuota|Wiki"
-msgstr ""
+msgstr "Wiki"
msgid "UsageQuota|Wikis"
-msgstr ""
+msgstr "Wikier"
msgid "UsageQuota|You used: %{usage} %{limit}"
-msgstr ""
+msgstr "Du har brukt: %{usage} %{limit}"
msgid "UsageQuota|out of %{formattedLimit} of your namespace storage"
msgstr ""
@@ -27002,9 +27920,6 @@ msgstr ""
msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
msgstr ""
-msgid "Use a hardware device to add the second factor of authentication."
-msgstr ""
-
msgid "Use an one time password authenticator on your mobile device or computer to enable two-factor authentication (2FA)."
msgstr ""
@@ -27012,22 +27927,22 @@ msgid "Use custom color #FF0000"
msgstr ""
msgid "Use hashed storage"
-msgstr ""
+msgstr "Bruk saltet lagring"
msgid "Use hashed storage paths for newly created and renamed repositories. 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 Repository URL changes and may improve disk I/O performance. (Always enabled since 13.0)"
-msgstr ""
+msgstr "Bruk saltede lagringsstier for nyopprettede og nynavngivne kodelagre. Aktiver uforanderlige, saltingsbaserte baner og kodelagernavn for å lagre kodelagre på disken. Dette forhindrer at arkiver må flyttes eller omdøpes når URL-adressen til kodelageret endres, og kan forbedre disk-I/O-ytelsen. (Alltid aktivert siden 13.0)"
msgid "Use one line per URI"
-msgstr ""
+msgstr "Bruk en linje per URI"
msgid "Use template"
-msgstr ""
+msgstr "Bruk mal"
msgid "Use the following registration token during setup:"
msgstr ""
msgid "Use your global notification setting"
-msgstr ""
+msgstr "Bruk din universelle varslingsinnstilling"
msgid "Use your smart card to authenticate with the LDAP server."
msgstr ""
@@ -27036,13 +27951,13 @@ msgid "Used by members to sign in to your group in GitLab"
msgstr ""
msgid "Used programming language"
-msgstr ""
+msgstr "Benyttet programmeringsspråk"
msgid "Used to help configure your identity provider"
msgstr ""
msgid "User"
-msgstr ""
+msgstr "Bruker"
msgid "User %{current_user_username} has started impersonating %{username}"
msgstr ""
@@ -27051,85 +27966,85 @@ msgid "User %{username} was successfully removed."
msgstr ""
msgid "User IDs"
-msgstr ""
+msgstr "Bruker-ID-er"
msgid "User List"
-msgstr ""
+msgstr "Brukerliste"
msgid "User OAuth applications"
msgstr ""
msgid "User Settings"
-msgstr ""
+msgstr "Brukerinnstillinger"
msgid "User and IP Rate Limits"
msgstr ""
msgid "User identity was successfully created."
-msgstr ""
+msgstr "Brukeridentiteten ble vellykket opprettet."
msgid "User identity was successfully removed."
-msgstr ""
+msgstr "Brukeridentiteten ble vellykket fjernet."
msgid "User identity was successfully updated."
-msgstr ""
+msgstr "Brukeridentiteten ble vellykket oppdatert."
msgid "User is not allowed to resolve thread"
-msgstr ""
+msgstr "Brukeren har ikke tillatelse til å oppklare tråden"
msgid "User key was successfully removed."
-msgstr ""
+msgstr "Brukernøkkelen ble vellykket fjernet."
msgid "User list %{name} will be removed. Are you sure?"
msgstr ""
msgid "User map"
-msgstr ""
+msgstr "Brukerkart"
msgid "User pipeline minutes were successfully reset."
msgstr ""
msgid "User restrictions"
-msgstr ""
+msgstr "Brukerbegrensninger"
msgid "User settings"
-msgstr ""
+msgstr "Brukerinnstillinger"
msgid "User was successfully created."
-msgstr ""
+msgstr "Brukeren ble vellykket opprettet."
msgid "User was successfully removed from group and any subresources."
-msgstr ""
+msgstr "Brukeren ble vellykket fjernet fra prosjektet og eventuelle underressurser."
msgid "User was successfully removed from project."
-msgstr ""
+msgstr "Brukeren ble vellykket fjernet fra prosjektet."
msgid "User was successfully updated."
-msgstr ""
+msgstr "Brukeren ble vellykket oppdatert."
msgid "UserLists|Add"
-msgstr ""
+msgstr "Legg til"
msgid "UserLists|Add Users"
-msgstr ""
+msgstr "Legg til brukere"
msgid "UserLists|Add users"
-msgstr ""
+msgstr "Legg til brukere"
msgid "UserLists|Cancel"
-msgstr ""
+msgstr "Avbryt"
msgid "UserLists|Create"
-msgstr ""
+msgstr "Opprett"
msgid "UserLists|Define a set of users to be used within feature flag strategies"
msgstr ""
msgid "UserLists|Edit"
-msgstr ""
+msgstr "Rediger"
msgid "UserLists|Edit %{name}"
-msgstr ""
+msgstr "Rediger %{name}"
msgid "UserLists|Enter a comma separated list of user IDs. These IDs should be the users of the system in which the feature flag is set, not GitLab IDs"
msgstr ""
@@ -27141,184 +28056,181 @@ msgid "UserLists|Lists allow you to define a set of users to be used with featur
msgstr ""
msgid "UserLists|Name"
-msgstr ""
+msgstr "Navn"
msgid "UserLists|New list"
-msgstr ""
+msgstr "Ny liste"
msgid "UserLists|Save"
-msgstr ""
+msgstr "Lagre"
msgid "UserLists|There are no users"
-msgstr ""
+msgstr "Det er ingen brukere"
msgid "UserLists|User ID"
-msgstr ""
+msgstr "Bruker-ID"
msgid "UserLists|User IDs"
-msgstr ""
+msgstr "Bruker-ID-er"
msgid "UserList|Delete %{name}?"
-msgstr ""
+msgstr "Vil du slette %{name}?"
msgid "UserList|created %{timeago}"
-msgstr ""
+msgstr "opprettet %{timeago}"
msgid "UserProfile|Activity"
-msgstr ""
+msgstr "Aktivitet"
msgid "UserProfile|Already reported for abuse"
-msgstr ""
+msgstr "Allerede rapportert for misbruk"
msgid "UserProfile|Blocked user"
-msgstr ""
+msgstr "Blokkert user"
msgid "UserProfile|Contributed projects"
-msgstr ""
+msgstr "Bidratte prosjekter"
msgid "UserProfile|Edit profile"
-msgstr ""
+msgstr "Rediger profil"
msgid "UserProfile|Explore public groups to find projects to contribute to."
-msgstr ""
+msgstr "Utforsk offentlige grupper for å finne prosjekter å bidra til."
msgid "UserProfile|Groups"
-msgstr ""
+msgstr "Grupper"
msgid "UserProfile|Groups are the best way to manage projects and members."
-msgstr ""
+msgstr "Grupper er den beste måten å behandle prosjekter og medlemmer på."
msgid "UserProfile|Join or create a group to start contributing by commenting on issues or submitting merge requests!"
-msgstr ""
+msgstr "Bli med eller opprett en gruppe for å begynne å bidra ved å kommentere på saker eller sende inn fletteforespørsler!"
msgid "UserProfile|Most Recent Activity"
-msgstr ""
+msgstr "Siste aktivitet"
msgid "UserProfile|No snippets found."
-msgstr ""
+msgstr "Ingen utdrag ble funnet."
msgid "UserProfile|Overview"
-msgstr ""
+msgstr "Oversikt"
msgid "UserProfile|Personal projects"
-msgstr ""
+msgstr "Personlige prosjekter"
msgid "UserProfile|Report abuse"
-msgstr ""
+msgstr "Rapporter misbruk"
msgid "UserProfile|Snippets"
-msgstr ""
+msgstr "Utdrag"
msgid "UserProfile|Snippets in GitLab can either be private, internal, or public."
-msgstr ""
+msgstr "Utdrag i GitLab kan enten være private, interne eller offentlige."
msgid "UserProfile|Star projects to track their progress and show your appreciation."
-msgstr ""
+msgstr "Stjernemerk prosjekter for å spore fremdriften deres og vise din takknemlighet."
msgid "UserProfile|Starred projects"
-msgstr ""
+msgstr "Stjernemerkede prosjekter"
msgid "UserProfile|Subscribe"
-msgstr ""
+msgstr "Abonner"
msgid "UserProfile|This user doesn't have any personal projects"
-msgstr ""
+msgstr "Denne brukeren har ingen personlige prosjekter"
msgid "UserProfile|This user has a private profile"
-msgstr ""
+msgstr "Denne brukeren har en privat profil"
msgid "UserProfile|This user hasn't contributed to any projects"
-msgstr ""
+msgstr "Denne brukeren har ikke bidratt til noen prosjekter"
msgid "UserProfile|This user hasn't starred any projects"
-msgstr ""
+msgstr "Denne brukeren har ikke stjernemerket noen prosjekter"
msgid "UserProfile|This user is blocked"
-msgstr ""
+msgstr "Denne brukeren er blokkert"
msgid "UserProfile|View all"
-msgstr ""
+msgstr "Vis alle"
msgid "UserProfile|View user in admin area"
-msgstr ""
+msgstr "Vis brukeren i admin-området"
msgid "UserProfile|You can create a group for several dependent projects."
-msgstr ""
+msgstr "Du kan opprette en gruppe for flere avhengige prosjekter."
msgid "UserProfile|You haven't created any personal projects."
-msgstr ""
+msgstr "Du har ikke opprettet noen personlige prosjekter."
msgid "UserProfile|You haven't created any snippets."
-msgstr ""
+msgstr "Du har ikke opprettet noen utdrag."
msgid "UserProfile|Your projects can be available publicly, internally, or privately, at your choice."
-msgstr ""
+msgstr "Dine prosjekter kan være offentlig, internt, eller privat tilgjengelig, som er ditt valg."
msgid "UserProfile|at"
-msgstr ""
+msgstr "hos"
msgid "UserProfile|made a private contribution"
-msgstr ""
+msgstr "gjorde et privat bidrag"
msgid "Username (optional)"
-msgstr ""
+msgstr "Brukernavn (valgfritt)"
msgid "Username is already taken."
-msgstr ""
+msgstr "Brukernavnet er opptatt."
msgid "Username is available."
-msgstr ""
+msgstr "Brukernavnet er tilgjengelig."
msgid "Username is too long (maximum is %{max_length} characters)."
-msgstr ""
+msgstr "Brukernavnet er for langt (maksimum er %{max_length} tegn)."
msgid "Username or email"
-msgstr ""
+msgstr "Brukernavn eller E-postadresse"
msgid "Users"
+msgstr "Brukere"
+
+msgid "Users in License"
msgstr ""
msgid "Users in License:"
-msgstr ""
+msgstr "Brukere i lisensen:"
msgid "Users or groups set as approvers in the project's or merge request's settings."
-msgstr ""
-
-msgid "Users outside of license"
-msgstr ""
+msgstr "Brukere eller grupper som er angitt som godkjennere i innstillingene til prosjektet eller fletteforespørselen."
msgid "Users over License:"
msgstr ""
msgid "Users requesting access to"
-msgstr ""
+msgstr "Brukere som ber om tilgang til"
msgid "Users requesting access to %{strong_start}%{group_name}%{strong_end}"
msgstr ""
msgid "Users were successfully added."
-msgstr ""
+msgstr "Brukerne ble vellykket lagt til."
msgid "Users with a Guest role or those who don't belong to a Project or Group will not use a seat from your license."
msgstr ""
-msgid "Users with a Guest role or those who don't belong to any projects or groups don't count towards seats in use."
-msgstr ""
-
msgid "UsersSelect|%{name} + %{length} more"
-msgstr ""
+msgstr "%{name} + %{length} til"
msgid "UsersSelect|Any User"
-msgstr ""
+msgstr "Enhver bruker"
msgid "UsersSelect|Assignee"
-msgstr ""
+msgstr "Tilordnet"
msgid "UsersSelect|No assignee - %{openingTag} assign yourself %{closingTag}"
msgstr ""
msgid "UsersSelect|Unassigned"
-msgstr ""
+msgstr "Utildelt"
msgid "Using %{codeStart}needs%{codeEnd} allows jobs to run before their stage is reached, as soon as their individual dependencies are met, which speeds up your pipelines."
msgstr ""
@@ -27330,31 +28242,28 @@ msgid "Using required encryption strategy when encrypted field is missing!"
msgstr ""
msgid "Valid from"
-msgstr ""
+msgstr "Gyldig fra"
msgid "Validate"
-msgstr ""
+msgstr "Valider"
msgid "Validate your GitLab CI configuration"
-msgstr ""
+msgstr "Valider GitLab CI-konfigurasjonen din"
msgid "Validate your GitLab CI configuration file"
-msgstr ""
+msgstr "Valider GitLab CI-konfigurasjonensfilen din"
msgid "Validations failed."
-msgstr ""
-
-msgid "Validity"
-msgstr ""
+msgstr "Valideringer mislyktes."
msgid "Value"
-msgstr ""
+msgstr "Verdi"
msgid "Value Stream"
-msgstr ""
+msgstr "Verdistrøm"
msgid "Value Stream Analytics"
-msgstr ""
+msgstr "Verdistrøm-analyse"
msgid "Value Stream Analytics can help you determine your team’s velocity"
msgstr ""
@@ -27363,99 +28272,102 @@ msgid "Value Stream Analytics gives an overview of how much time it takes to go
msgstr ""
msgid "Value Stream Name"
+msgstr "Verdistrømnavn"
+
+msgid "ValueStreamAnalyticsStage|We don't have enough data to show this stage."
msgstr ""
msgid "ValueStreamAnalytics|%{days}d"
-msgstr ""
+msgstr "%{days}d"
msgid "ValueStreamAnalytics|Median time from first commit to issue closed."
-msgstr ""
+msgstr "Mediantid fra første commit til sakene blir lukket."
msgid "ValueStreamAnalytics|Median time from issue created to issue closed."
msgstr ""
msgid "ValueStream|The Default Value Stream cannot be deleted"
-msgstr ""
+msgstr "Standardverdistrømmen kan ikke bli slettet"
msgid "Variable"
-msgstr ""
+msgstr "Variabel"
msgid "Variable will be masked in job logs."
-msgstr ""
+msgstr "Variabelen vil bli maskert i jobbloggføringene."
msgid "Variables"
-msgstr ""
+msgstr "Variabler"
msgid "Various container registry settings."
msgstr ""
msgid "Various email settings."
-msgstr ""
+msgstr "Ulike e-postinnstillinger."
msgid "Various localization settings."
-msgstr ""
+msgstr "Diverse oversettelsesinnstillinger."
msgid "Various settings that affect GitLab performance."
-msgstr ""
+msgstr "Diverse innstillinger som påvirker GitLab-ytelsen."
msgid "Verification capacity"
-msgstr ""
+msgstr "Verifiseringskapasitet"
msgid "Verification information"
-msgstr ""
+msgstr "Verifikasjonsinformasjon"
msgid "Verification status"
-msgstr ""
+msgstr "Verifiseringsstatus"
msgid "Verified"
-msgstr ""
+msgstr "Bekreftet"
msgid "Verify SAML Configuration"
-msgstr ""
+msgstr "Verifiser SAML-oppsettet"
msgid "Verify configuration"
-msgstr ""
+msgstr "Verifiser oppsettet"
msgid "Version"
-msgstr ""
+msgstr "Versjon"
msgid "Version %{versionNumber}"
-msgstr ""
+msgstr "Versjon %{versionNumber}"
msgid "Version %{versionNumber} (latest)"
-msgstr ""
+msgstr "Versjon %{versionNumber} (nyeste)"
msgid "View Documentation"
-msgstr ""
+msgstr "Vis dokumentasjon"
msgid "View all issues"
-msgstr ""
+msgstr "Vis alle saker"
msgid "View blame prior to this change"
msgstr ""
msgid "View chart"
msgid_plural "View charts"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "Vis diagram"
+msgstr[1] "Vis diagrammer"
msgid "View dependency details for your project"
-msgstr ""
+msgstr "Vis avhengighetsdetaljer for prosjektet ditt"
msgid "View deployment"
-msgstr ""
+msgstr "Vis distribusjon"
msgid "View details"
-msgstr ""
+msgstr "Vis detaljer"
msgid "View details: %{details_url}"
msgstr ""
msgid "View documentation"
-msgstr ""
+msgstr "Vis dokumentasjon"
msgid "View eligible approvers"
-msgstr ""
+msgstr "Vis kvalifiserte godkjennere"
msgid "View epics list"
msgstr ""
@@ -27466,73 +28378,73 @@ msgstr[0] ""
msgstr[1] ""
msgid "View file @ "
-msgstr ""
+msgstr "Vis fil @ "
msgid "View file @ %{commitSha}"
-msgstr ""
+msgstr "Vis fil @ %{commitSha}"
msgid "View full dashboard"
-msgstr ""
+msgstr "Vis full kontrollpanel"
msgid "View full log"
-msgstr ""
+msgstr "Vis full logg"
msgid "View group labels"
-msgstr ""
+msgstr "Vis gruppeetiketter"
msgid "View incident issues."
msgstr ""
msgid "View issue"
-msgstr ""
+msgstr "Vis rapport"
msgid "View issues"
-msgstr ""
+msgstr "Vis saker"
msgid "View it on GitLab"
-msgstr ""
+msgstr "Vis den i GitLab"
msgid "View job"
-msgstr ""
+msgstr "Se stilling"
msgid "View job log"
-msgstr ""
+msgstr "Vis jobblogg"
msgid "View jobs"
-msgstr ""
+msgstr "Vis jobber"
msgid "View labels"
-msgstr ""
+msgstr "Vis stempler"
msgid "View log"
-msgstr ""
+msgstr "Vis loggbok"
msgid "View merge request"
-msgstr ""
+msgstr "Vis fletteforespørsel"
msgid "View open merge request"
-msgstr ""
+msgstr "Vis åpne fletteforespørsler"
msgid "View page @ "
-msgstr ""
+msgstr "Vis side @ "
msgid "View performance dashboard."
-msgstr ""
+msgstr "Vis ytelseskontrollpanelet."
msgid "View project"
-msgstr ""
+msgstr "Vis prosjekt"
msgid "View project labels"
-msgstr ""
+msgstr "Vis prosjektstempler"
msgid "View replaced file @ "
-msgstr ""
+msgstr "Vis erstattet fil @ "
msgid "View supported languages and frameworks"
msgstr ""
msgid "View the documentation"
-msgstr ""
+msgstr "Vis dokumentasjonen"
msgid "View the latest successful deployment to this environment"
msgstr ""
@@ -27544,19 +28456,19 @@ msgid "View users statistics"
msgstr ""
msgid "Viewing commit"
-msgstr ""
+msgstr "Viser commit"
msgid "Visibility"
-msgstr ""
+msgstr "Synlighet"
msgid "Visibility and access controls"
msgstr ""
msgid "Visibility level"
-msgstr ""
+msgstr "Synlighetsnivå"
msgid "Visibility level:"
-msgstr ""
+msgstr "Synlighetsnivå:"
msgid "Visibility settings have been disabled by the administrator."
msgstr ""
@@ -27565,22 +28477,22 @@ msgid "Visibility, project features, permissions"
msgstr ""
msgid "Visibility:"
-msgstr ""
+msgstr "Synlighet:"
msgid "VisibilityLevel|Internal"
-msgstr ""
+msgstr "Intern"
msgid "VisibilityLevel|Private"
-msgstr ""
+msgstr "Privat"
msgid "VisibilityLevel|Public"
-msgstr ""
+msgstr "Offentlig"
msgid "VisibilityLevel|Unknown"
-msgstr ""
+msgstr "Ukjent"
msgid "Visit settings page"
-msgstr ""
+msgstr "GÃ¥ til innstillingssiden"
msgid "VisualReviewApp|%{stepStart}Step 1%{stepEnd}. Copy the following script:"
msgstr ""
@@ -27589,19 +28501,19 @@ msgid "VisualReviewApp|%{stepStart}Step 2%{stepEnd}. Add it to the %{headTags} t
msgstr ""
msgid "VisualReviewApp|%{stepStart}Step 3%{stepEnd}. If not previously %{linkStart}configured%{linkEnd} by a developer, enter the merge request ID for the review when prompted. The ID of this merge request is %{stepStart}%{mrId}%{stepStart}."
-msgstr ""
+msgstr "%{stepStart}Trinn 3%{stepEnd}. Hvis det ikke tidligere er %{linkStart}konfigurert%{linkEnd} av en utvikler, skriv inn fletteforespørsels-IDen for gjennomgang når du blir bedt om det. ID-en til fletteforespørselen er %{stepStart}%{mrId}%{stepStart}."
msgid "VisualReviewApp|%{stepStart}Step 4%{stepEnd}. Leave feedback in the Review App."
msgstr ""
msgid "VisualReviewApp|Cancel"
-msgstr ""
+msgstr "Avbryt"
msgid "VisualReviewApp|Copy merge request ID"
msgstr ""
msgid "VisualReviewApp|Copy script"
-msgstr ""
+msgstr "Kopier skript"
msgid "VisualReviewApp|Enable Visual Reviews"
msgstr ""
@@ -27613,31 +28525,34 @@ msgid "VisualReviewApp|No review app found or available."
msgstr ""
msgid "VisualReviewApp|Open review app"
-msgstr ""
+msgstr "Ã…pne gjennomgangsapp"
msgid "VisualReviewApp|Review"
msgstr ""
msgid "VisualReviewApp|Steps 1 and 2 (and sometimes 3) are performed once by the developer before requesting feedback. Steps 3 (if necessary), 4 is performed by the reviewer each time they perform a review."
+msgstr "Trinn 1 og 2 (og noen ganger 3) utføres en gang av utvikleren før det bes om tilbakemelding. Trinn 3 (om nødvendig) og 4 utføres av anmelderen hver gang de utfører en gjennomgang."
+
+msgid "Visualization"
msgstr ""
msgid "Vulnerabilities"
-msgstr ""
+msgstr "SÃ¥rbarheter"
msgid "Vulnerabilities over time"
-msgstr ""
+msgstr "SÃ¥rbarheter over tid"
msgid "Vulnerability Report"
-msgstr ""
+msgstr "SÃ¥rbarhetsrapport"
msgid "Vulnerability remediated. Review before resolving."
-msgstr ""
+msgstr "Sårbarheten ble utbedret. Gå gjennom det før du oppklarer."
msgid "Vulnerability resolved in %{branch}"
-msgstr ""
+msgstr "SÃ¥rbarhet oppklart i %{branch}"
msgid "Vulnerability resolved in the default branch"
-msgstr ""
+msgstr "SÃ¥rbarhet oppklart i standardgrenen"
msgid "Vulnerability-Check"
msgstr ""
@@ -27646,142 +28561,145 @@ msgid "VulnerabilityChart|%{formattedStartDate} to today"
msgstr ""
msgid "VulnerabilityChart|Severity"
-msgstr ""
+msgstr "Alvorlighetsgrad"
-msgid "VulnerabilityManagement|A true-positive and will fix"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Change status"
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|Confirm"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Confirmed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
-msgstr ""
-
-msgid "VulnerabilityManagement|Detected %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|A true-positive and will fix"
msgstr ""
-msgid "VulnerabilityManagement|Dismiss"
-msgstr ""
+msgid "VulnerabilityManagement|Change status"
+msgstr "Endre status"
-msgid "VulnerabilityManagement|Dismissed %{timeago} by %{user}"
-msgstr ""
+msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
+msgstr "Kunne ikke behandle %{issueReference}: %{errorMessage}."
-msgid "VulnerabilityManagement|Resolved"
+msgid "VulnerabilityManagement|Detected"
msgstr ""
-msgid "VulnerabilityManagement|Resolved %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Needs triage"
msgstr ""
msgid "VulnerabilityManagement|Something went wrong while trying to delete the comment. Please try again later."
-msgstr ""
+msgstr "Noe gikk galt under sletting av kommentaren. Prøv igjen senere."
msgid "VulnerabilityManagement|Something went wrong while trying to refresh the vulnerability. Please try again later."
-msgstr ""
+msgstr "Noe gikk galt under oppfrisking av sårbarheten. Prøv igjen senere."
msgid "VulnerabilityManagement|Something went wrong while trying to retrieve the vulnerability history. Please try again later."
-msgstr ""
+msgstr "Noe gikk galt under innhenting av sårbarhetshistorikken. Prøv igjen senere."
msgid "VulnerabilityManagement|Something went wrong while trying to save the comment. Please try again later."
-msgstr ""
+msgstr "Noe gikk galt under lagring av kommentaren. Prøv igjen senere."
msgid "VulnerabilityManagement|Something went wrong while trying to unlink the issue. Please try again later."
-msgstr ""
+msgstr "Noe gikk galt under avlenking av saken. Prøv igjen senere."
msgid "VulnerabilityManagement|Something went wrong, could not get user."
-msgstr ""
+msgstr "Noe gikk galt, kunne ikke hente bruker."
msgid "VulnerabilityManagement|Something went wrong, could not update vulnerability state."
-msgstr ""
+msgstr "Noe gikk galt, kunne ikke oppdatere sårbarhetsstatusen."
msgid "VulnerabilityManagement|Verified as fixed or mitigated"
-msgstr ""
+msgstr "Verifisert som fikset eller holdt i sjakk"
msgid "VulnerabilityManagement|Will not fix or a false-positive"
msgstr ""
msgid "VulnerabilityManagement|invalid issue link or ID"
-msgstr ""
+msgstr "ugyldig sakslenke eller ID"
msgid "VulnerabilityStatusTypes|All"
-msgstr ""
+msgstr "Alle"
msgid "VulnerabilityStatusTypes|Confirmed"
-msgstr ""
+msgstr "Bekreftet"
msgid "VulnerabilityStatusTypes|Detected"
-msgstr ""
+msgstr "Oppdaget"
msgid "VulnerabilityStatusTypes|Dismissed"
-msgstr ""
+msgstr "Avfeid"
msgid "VulnerabilityStatusTypes|Resolved"
-msgstr ""
+msgstr "Oppklart"
msgid "Vulnerability|%{scannerName} (version %{scannerVersion})"
+msgstr "%{scannerName} (versjon %{scannerVersion})"
+
+msgid "Vulnerability|Activity"
msgstr ""
msgid "Vulnerability|Class"
-msgstr ""
+msgstr "Klasse"
msgid "Vulnerability|Comments"
-msgstr ""
+msgstr "Kommentarer"
msgid "Vulnerability|Crash Address"
-msgstr ""
+msgstr "Krasjadresse"
msgid "Vulnerability|Description"
+msgstr "Beskrivelse"
+
+msgid "Vulnerability|Detected"
msgstr ""
msgid "Vulnerability|Evidence"
-msgstr ""
+msgstr "Bevis"
msgid "Vulnerability|File"
-msgstr ""
+msgstr "File"
msgid "Vulnerability|Identifier"
-msgstr ""
+msgstr "Identifikator"
msgid "Vulnerability|Identifiers"
-msgstr ""
+msgstr "identifikatorer"
msgid "Vulnerability|Image"
-msgstr ""
+msgstr "Bilde"
msgid "Vulnerability|Links"
-msgstr ""
+msgstr "Lenker"
msgid "Vulnerability|Method"
-msgstr ""
+msgstr "Metode"
msgid "Vulnerability|Namespace"
-msgstr ""
+msgstr "Navnefelt"
msgid "Vulnerability|Project"
-msgstr ""
+msgstr "Prosjekt"
msgid "Vulnerability|Request"
msgstr ""
msgid "Vulnerability|Response"
-msgstr ""
+msgstr "Respons"
msgid "Vulnerability|Scanner"
-msgstr ""
+msgstr "Skanner"
msgid "Vulnerability|Scanner Provider"
-msgstr ""
+msgstr "Skannerleverandør"
msgid "Vulnerability|Severity"
-msgstr ""
+msgstr "Alvorlighetsgrad"
msgid "Vulnerability|Status"
-msgstr ""
+msgstr "Status"
msgid "Wait for the file to load to copy its contents"
msgstr ""
@@ -27790,17 +28708,20 @@ msgid "Waiting for merge (open and assigned)"
msgstr ""
msgid "Waiting for performance data"
-msgstr ""
+msgstr "Venter på ytelsesdata"
msgid "Want to see the data? Please ask an administrator for access."
-msgstr ""
+msgstr "Ønsker du å se dataene? Vennligst kontakt en administrator for å få tilgang."
msgid "Warning:"
-msgstr ""
+msgstr "Advarsel:"
msgid "Warning: Displaying this diagram might cause performance issues on this page."
msgstr ""
+msgid "We are currently unable to fetch data for the pipeline header."
+msgstr ""
+
msgid "We are currently unable to fetch data for this graph."
msgstr ""
@@ -27835,55 +28756,67 @@ msgid "We sent you an email with reset password instructions"
msgstr ""
msgid "We tried to automatically renew your subscription for %{strong}%{namespace_name}%{strong_close} on %{expires_on} but something went wrong so your subscription was downgraded to the free plan. Don't worry, your data is safe. We suggest you check your payment method and get in touch with our support team (%{support_link}). They'll gladly help with your subscription renewal."
-msgstr ""
+msgstr "Vi prøvde å fornye abonnementet ditt automatisk for %{strong}%{namespace_name}%{strong_close} på %{expires_on}, men noe gikk galt, så abonnementet ble nedgradert til gratisplanen. Ikke bekymre deg, dataene dine er trygge. Vi foreslår at du sjekker betalingsmåten din og tar kontakt med støtteteamet vårt (%{support_link}). De hjelper deg gjerne med abonnementsfornyelsen."
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
-msgid "We've found no vulnerabilities"
+msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
msgstr ""
-msgid "Web Application Firewall"
+msgid "We would like to inform you that your subscription GitLab Enterprise Edition %{plan_name} is nearing its user limit. You have %{active_user_count} active users, which is almost at the user limit of %{maximum_user_count}."
msgstr ""
+msgid "We've found no vulnerabilities"
+msgstr "Vi fant ingen sårbarheter"
+
+msgid "Web Application Firewall"
+msgstr "Brannmur for nettapplikasjon"
+
msgid "Web IDE"
-msgstr ""
+msgstr "Nett-IDE"
msgid "Web Terminal"
-msgstr ""
+msgstr "Netterminal"
msgid "Web terminal"
+msgstr "Netterminal"
+
+msgid "WebAuthn Devices (%{length})"
msgstr ""
-msgid "WebIDE|Merge request"
+msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
msgstr ""
+msgid "WebIDE|Merge request"
+msgstr "Fletteforespørsel"
+
msgid "Webhook"
-msgstr ""
+msgstr "Webhook"
msgid "Webhook Logs"
-msgstr ""
+msgstr "Webhook-loggføringer"
msgid "Webhook Settings"
-msgstr ""
+msgstr "Webhook-innstillinger"
msgid "Webhooks"
-msgstr ""
+msgstr "Webhooks"
msgid "Webhooks Help"
-msgstr ""
+msgstr "Webhook-hjelp"
msgid "Webhooks allow you to trigger a URL if, for example, new code is pushed or a new issue is created. You can configure webhooks to listen for specific events like pushes, issues or merge requests. Group webhooks will apply to all projects in a group, allowing you to standardize webhook functionality across your entire group."
-msgstr ""
+msgstr "Webhooks lar deg trigge en URL hvis for eksempel ny kode blir pushet eller en ny sak opprettes. Du kan konfigurere webhooks til å lytte etter spesifikke hendelser som push, problemer eller fletteforespørsler. Gruppe-webhooker vil gjelde for alle prosjekter i en gruppe, slik at du kan standardisere webhook-funksjonalitet i hele gruppen."
msgid "Webhooks have moved. They can now be found under the Settings menu."
msgstr ""
msgid "Webhooks|Comments"
-msgstr ""
+msgstr "Kommentarer"
msgid "Webhooks|Confidential Comments"
-msgstr ""
+msgstr "Konfidensielle kommentarer"
msgid "Webhooks|Confidential Issues events"
msgstr ""
@@ -27892,13 +28825,13 @@ msgid "Webhooks|Deployment events"
msgstr ""
msgid "Webhooks|Enable SSL verification"
-msgstr ""
+msgstr "Skru på SSL-verifisering"
msgid "Webhooks|Issues events"
msgstr ""
msgid "Webhooks|Job events"
-msgstr ""
+msgstr "Jobb-hendelser"
msgid "Webhooks|Merge request events"
msgstr ""
@@ -27907,13 +28840,13 @@ msgid "Webhooks|Pipeline events"
msgstr ""
msgid "Webhooks|Push events"
-msgstr ""
+msgstr "Pushhendelser"
msgid "Webhooks|SSL verification"
-msgstr ""
+msgstr "SSL-verifisering"
msgid "Webhooks|Secret Token"
-msgstr ""
+msgstr "Hemmelig sjetong"
msgid "Webhooks|Tag push events"
msgstr ""
@@ -27952,10 +28885,10 @@ msgid "Webhooks|This URL will be triggered when the pipeline status changes"
msgstr ""
msgid "Webhooks|Trigger"
-msgstr ""
+msgstr "Trigger"
msgid "Webhooks|URL"
-msgstr ""
+msgstr "URL"
msgid "Webhooks|Use this token to validate received payloads. It will be sent with the request in the X-Gitlab-Token HTTP header."
msgstr ""
@@ -27964,55 +28897,49 @@ msgid "Webhooks|Wiki Page events"
msgstr ""
msgid "Wednesday"
-msgstr ""
+msgstr "Onsdag"
msgid "Weekday"
-msgstr ""
+msgstr "Ukedag"
msgid "Weeks"
-msgstr ""
+msgstr "Uker"
msgid "Weight"
-msgstr ""
+msgstr "Vekt"
msgid "Weight %{weight}"
-msgstr ""
+msgstr "Vekt %{weight}"
msgid "Welcome back! Your account had been deactivated due to inactivity but is now reactivated."
-msgstr ""
+msgstr "Velkommen tilbake! Kontoen din hadde blitt deaktivert på grunn av inaktivitet, men er nå aktivert på nytt."
msgid "Welcome to GitLab"
-msgstr ""
+msgstr "Velkommen til GitLab"
msgid "Welcome to GitLab%{br_tag}%{name}!"
-msgstr ""
+msgstr "Velkommen til GitLab%{br_tag}%{name}!"
msgid "Welcome to GitLab, %{first_name}!"
-msgstr ""
+msgstr "Velkommen til GitLab, %{first_name}!"
msgid "Welcome to the guided GitLab tour"
-msgstr ""
-
-msgid "Welcome to your Issue Board!"
-msgstr ""
+msgstr "Velkommen til den guidede GitLab-turen"
msgid "Welcome to your issue board!"
-msgstr ""
-
-msgid "We’ve been making changes to %{featureName} and we’d love your feedback %{linkStart}in this issue%{linkEnd} to help us improve the experience."
-msgstr ""
+msgstr "Velkommen til sakspanelet ditt!"
msgid "What are you searching for?"
-msgstr ""
+msgstr "Hva leter du etter?"
msgid "What describes you best?"
-msgstr ""
+msgstr "Hva beskriver deg best?"
msgid "What's new at GitLab"
-msgstr ""
+msgstr "Hva er nytt hos GitLab"
msgid "What’s your experience level?"
-msgstr ""
+msgstr "Hva er ditt erfaringsnivå?"
msgid "When a deployment job is successful, skip older deployment jobs that are still pending"
msgstr ""
@@ -28020,6 +28947,9 @@ msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
msgstr ""
+msgid "When enabled, any user visiting %{host} and creating an account will have to be explicitly approved by the admin before they can login. This setting is effective only if sign-ups are enabled."
+msgstr ""
+
msgid "When enabled, any user visiting %{host} will be able to create an account."
msgstr ""
@@ -28027,60 +28957,60 @@ msgid "When enabled, if an NPM package isn't found in the GitLab Registry, we wi
msgstr ""
msgid "When enabled, users cannot use GitLab until the terms have been accepted."
-msgstr ""
+msgstr "Når det er aktivert, så kan brukere ikke bruke GitLab frem til vilkårene er blitt akseptert."
msgid "When leaving the URL blank, classification labels can still be specified without disabling cross project features or performing external authorization checks."
msgstr ""
msgid "When this merge request is accepted"
msgid_plural "When these merge requests are accepted"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "Når denne fletteforespørselen godtas"
+msgstr[1] "Når disse fletteforespørslene godtas"
msgid "When using the %{code_open}http://%{code_close} or %{code_open}https://%{code_close} protocols, please provide the exact URL to the repository. HTTP redirects will not be followed."
-msgstr ""
+msgstr "Når du bruker %{code_open}http: //%{code_close} eller %{code_open}https: //%{code_close} protokollene, vennligst oppgi den nøyaktige URL-en til kodelageret. HTTP-viderekoblinger blir ikke fulgt."
msgid "When:"
-msgstr ""
+msgstr "NÃ¥r:"
msgid "While it's rare to have no vulnerabilities, it can happen. In any event, we ask that you please double check your settings to make sure you've set up your dashboard correctly."
msgstr ""
msgid "Who can be an approver?"
-msgstr ""
+msgstr "Hvem kan bli en godkjenner?"
msgid "Who can see this group?"
-msgstr ""
+msgstr "Hvem kan se denne gruppen?"
msgid "Who will be able to see this group?"
-msgstr ""
+msgstr "Hvem vil kunne se denne gruppen?"
msgid "Who will be using GitLab?"
-msgstr ""
+msgstr "Hvem skal bruke GitLab?"
msgid "Who will be using this GitLab subscription?"
-msgstr ""
+msgstr "Hvem skal bruke dette GitLab-abonnementet?"
msgid "Who will be using this GitLab trial?"
-msgstr ""
+msgstr "Hvem skal bruke denne GitLab-prøveversjonen?"
msgid "Wiki"
-msgstr ""
+msgstr "Wiki"
msgid "Wiki was successfully updated."
-msgstr ""
+msgstr "Wikien ble vellykket oppdatert."
msgid "WikiClone|Clone your wiki"
-msgstr ""
+msgstr "Klon wikien din"
msgid "WikiClone|Git Access"
-msgstr ""
+msgstr "Git-tilgang"
msgid "WikiClone|Install Gollum"
-msgstr ""
+msgstr "Installer Gollum"
msgid "WikiClone|Start Gollum and edit locally"
-msgstr ""
+msgstr "Start Gollum og rediger lokalt"
msgid "WikiEditPageTip|Tip: You can move this page by adding the path to the beginning of the title."
msgstr ""
@@ -28089,16 +29019,16 @@ msgid "WikiEdit|There is already a page with the same title in that path."
msgstr ""
msgid "WikiEmptyIssueMessage|Suggest wiki improvement"
-msgstr ""
+msgstr "Foreslå wiki-forbedring"
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 "Du må være et gruppemedlem for å kunne legge til wiki-sider. Hvis du har forslag til hvordan du kan forbedre wikien til denne gruppen, bør du vurdere å åpne en sak i %{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 ""
+msgstr "Du må være et prosjektmedlem for å kunne legge til wiki-sider. Hvis du har forslag til hvordan du kan forbedre wikien til dette prosjektet, bør du vurdere å åpne en sak i %{issues_link}."
msgid "WikiEmptyIssueMessage|issue tracker"
-msgstr ""
+msgstr "sakssporer"
msgid "WikiEmpty| Have a Confluence wiki already? Use that instead."
msgstr ""
@@ -28110,133 +29040,133 @@ msgid "WikiEmpty|A wiki is where you can store all the details about your projec
msgstr ""
msgid "WikiEmpty|Confluence is enabled"
-msgstr ""
+msgstr "Confluence er skrudd på"
msgid "WikiEmpty|Create your first page"
-msgstr ""
+msgstr "Lag din første side"
msgid "WikiEmpty|Enable the Confluence Wiki integration"
-msgstr ""
+msgstr "Aktiver Confluence Wiki-integrering"
msgid "WikiEmpty|Go to Confluence"
-msgstr ""
+msgstr "GÃ¥ til Confluence"
msgid "WikiEmpty|Suggest wiki improvement"
-msgstr ""
+msgstr "Foreslå wiki-forbedring"
msgid "WikiEmpty|The wiki lets you write documentation for your group"
-msgstr ""
+msgstr "Wikien lar deg skrive dokumentasjon for gruppen din"
msgid "WikiEmpty|The wiki lets you write documentation for your project"
-msgstr ""
+msgstr "Wikien lar deg skrive dokumentasjon for prosjektet ditt"
msgid "WikiEmpty|This group has no wiki pages"
-msgstr ""
+msgstr "Denne gruppen har ingen wiki-sider"
msgid "WikiEmpty|This project has no wiki pages"
-msgstr ""
+msgstr "Dette prosjektet har ingen wiki-sider"
msgid "WikiEmpty|You must be a group member in order to add wiki pages."
-msgstr ""
+msgstr "Du må være et gruppemedlem for å kunne legge til wiki-sider."
msgid "WikiEmpty|You must be a project member in order to add wiki pages."
-msgstr ""
+msgstr "Du må være prosjektmedlem for å kunne legge til wiki-sider."
msgid "WikiEmpty|You've enabled the Confluence Workspace integration. Your wiki will be viewable directly within Confluence. We are hard at work integrating Confluence more seamlessly into GitLab. If you'd like to stay up to date, follow our %{wiki_confluence_epic_link_start}Confluence epic%{wiki_confluence_epic_link_end}."
-msgstr ""
+msgstr "Du har aktivert Confluence Workspace-integrasjonen. Wikien din kan vises direkte i Confluence. Vi jobber hardt med å integrere Confluence mer sømløst i GitLab. Hvis du ønsker å holde deg oppdatert, følg vår %{wiki_confluence_epic_link_start}Confluence-epic%{wiki_confluence_epic_link_end}."
msgid "WikiHistoricalPage|This is an old version of this page."
-msgstr ""
+msgstr "Dette er en gammel versjon av denne siden."
msgid "WikiHistoricalPage|You can view the %{most_recent_link} or browse the %{history_link}."
-msgstr ""
+msgstr "Du kan se %{most_recent_link} eller bla gjennom %{history_link}."
msgid "WikiHistoricalPage|history"
-msgstr ""
+msgstr "historikk"
msgid "WikiHistoricalPage|most recent version"
-msgstr ""
+msgstr "nyligste versjon"
msgid "WikiMarkdownDocs|More examples are in the %{docs_link}"
-msgstr ""
+msgstr "Flere eksempler er i %{docs_link}"
msgid "WikiMarkdownDocs|documentation"
-msgstr ""
+msgstr "dokumentasjon"
msgid "WikiMarkdownTip|To link to a (new) page, simply type %{link_example}"
-msgstr ""
+msgstr "For å lenke til en (ny) side, bare skriv %{link_example}"
msgid "WikiNewPageTip|Tip: You can specify the full path for the new file. We will automatically create any missing directories."
msgstr ""
msgid "WikiPageConfirmDelete|Are you sure you want to delete this page?"
-msgstr ""
+msgstr "Er du sikker på at du vil slette denne siden?"
msgid "WikiPageConfirmDelete|Delete page"
-msgstr ""
+msgstr "Slett side"
msgid "WikiPageConfirmDelete|Delete page %{pageTitle}?"
-msgstr ""
+msgstr "Vil du slette siden %{pageTitle}?"
msgid "WikiPageConflictMessage|Someone edited the page the same time you did. Please check out %{page_link} and make sure your changes will not unintentionally remove theirs."
msgstr ""
msgid "WikiPageConflictMessage|the page"
-msgstr ""
+msgstr "siden"
msgid "WikiPageCreate|Create %{pageTitle}"
-msgstr ""
+msgstr "Opprett %{pageTitle}"
msgid "WikiPageEdit|Update %{pageTitle}"
-msgstr ""
+msgstr "Oppdater %{pageTitle}"
msgid "WikiPage|Write your content or drag files here…"
msgstr ""
msgid "Wikis"
-msgstr ""
+msgstr "Wikier"
msgid "Wiki|Create New Page"
-msgstr ""
+msgstr "Opprett ny side"
msgid "Wiki|Create page"
-msgstr ""
+msgstr "Opprett side"
msgid "Wiki|Created date"
-msgstr ""
+msgstr "Opprettelsesdato"
msgid "Wiki|Edit Page"
-msgstr ""
+msgstr "Rediger side"
msgid "Wiki|New page"
-msgstr ""
+msgstr "Ny side"
msgid "Wiki|Page history"
-msgstr ""
+msgstr "Sidens historikk"
msgid "Wiki|Page title"
-msgstr ""
+msgstr "Sidetittel"
msgid "Wiki|Page version"
-msgstr ""
+msgstr "Sideversjon"
msgid "Wiki|Pages"
-msgstr ""
+msgstr "Sider"
msgid "Wiki|Title"
-msgstr ""
+msgstr "Tittel"
msgid "Wiki|View All Pages"
-msgstr ""
+msgstr "Vis alle sider"
msgid "Wiki|Wiki Pages"
-msgstr ""
+msgstr "Wiki sider"
msgid "Will be created"
-msgstr ""
+msgstr "Vil bli opprettet"
msgid "Will be mapped to"
-msgstr ""
+msgstr "Vil bli kartlagt til"
msgid "Will deploy to"
msgstr ""
@@ -28244,6 +29174,9 @@ msgstr ""
msgid "With requirements, you can set criteria to check your products against."
msgstr ""
+msgid "With test cases, you can define conditions for your project to meet in determining quality"
+msgstr ""
+
msgid "Withdraw Access Request"
msgstr ""
@@ -28259,20 +29192,23 @@ msgstr ""
msgid "Workflow Help"
msgstr ""
-msgid "Write"
+msgid "Would you like to create a new branch?"
msgstr ""
+msgid "Write"
+msgstr "Skriv"
+
msgid "Write a comment or drag your files here…"
-msgstr ""
+msgstr "Skriv en kommentar eller dra filene dine hit …"
msgid "Write a comment…"
-msgstr ""
+msgstr "Skriv en kommentar …"
msgid "Write access allowed"
-msgstr ""
+msgstr "Skrivetilgang er tillatt"
msgid "Write milestone description..."
-msgstr ""
+msgstr "Skriv en milepælbeskrivelse …"
msgid "Write your release notes or drag your files here…"
msgstr ""
@@ -28280,29 +29216,32 @@ msgstr ""
msgid "Wrong extern UID provided. Make sure Auth0 is configured correctly."
msgstr ""
-msgid "Yes"
+msgid "YYYY-MM-DD"
msgstr ""
+msgid "Yes"
+msgstr "Ja"
+
msgid "Yes or No"
-msgstr ""
+msgstr "Ja eller nei"
msgid "Yes, add it"
-msgstr ""
+msgstr "Ja, legg det til"
msgid "Yes, close issue"
-msgstr ""
+msgstr "Ja, lukk saken"
msgid "Yes, delete project"
-msgstr ""
+msgstr "Ja, slett prosjektet"
msgid "Yes, let me map Google Code users to full names or GitLab users."
msgstr ""
msgid "Yesterday"
-msgstr ""
+msgstr "I går"
msgid "You"
-msgstr ""
+msgstr "Du"
msgid "You already have pending todo for this alert"
msgstr ""
@@ -28314,7 +29253,7 @@ msgid "You are about to permanently delete this project"
msgstr ""
msgid "You are about to transfer the control of your account to %{group_name} group. This action is NOT reversible, you won't be able to access any of your groups and projects outside of %{group_name} once this transfer is complete."
-msgstr ""
+msgstr "Du er i ferd med å overføre kontrollen over kontoen din til %{group_name}-gruppen. Denne handlingen er IKKE reversibel. Du vil ikke ha tilgang til noen av gruppene og prosjektene dine utenfor %{group_name} når overføringen er fullført."
msgid "You are an admin, which means granting access to %{client_name} will allow them to interact with GitLab as an admin as well. Proceed with caution."
msgstr ""
@@ -28337,14 +29276,14 @@ msgstr ""
msgid "You are going to remove the fork relationship from %{project_full_name}. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "You are going to transfer %{project_full_name} to another owner. Are you ABSOLUTELY sure?"
+msgid "You are going to transfer %{project_full_name} to another namespace. Are you ABSOLUTELY sure?"
msgstr ""
msgid "You are going to turn off the confidentiality. This means %{strongStart}everyone%{strongEnd} will be able to see and leave a comment on this %{issuableType}."
msgstr ""
msgid "You are going to turn on the confidentiality. This means that only team members with %{strongStart}at least Reporter access%{strongEnd} are able to see and leave comments on the %{issuableType}."
-msgstr ""
+msgstr "Du kommer til å slå på konfidensialitet. Dette betyr at bare gruppemedlemmer med %{strongStart}minst «Rapportør»-tilgang%{strongEnd} kan se og legge ut kommentarer på %{issuableType}."
msgid "You are not allowed to push into this branch. Create another branch or open a merge request."
msgstr ""
@@ -28365,40 +29304,37 @@ msgid "You are on a read-only GitLab instance."
msgstr ""
msgid "You are receiving this message because you are a GitLab administrator for %{url}."
-msgstr ""
+msgstr "Du mottar denne meldingen fordi du er en GitLab-administrator for %{url}."
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 ""
+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 %{linkStart}view the blob%{linkEnd} instead."
msgstr ""
msgid "You can also create a project from the command line."
-msgstr ""
+msgstr "Du kan også opprette et prosjekt fra kommandolinjen."
msgid "You can also press &#8984;-Enter"
-msgstr ""
+msgstr "Du kan også trykke &#8984;-Enter"
msgid "You can also press Ctrl-Enter"
-msgstr ""
+msgstr "Du kan også trykke Ctrl-Enter"
msgid "You can also star a label to make it a priority label."
msgstr ""
msgid "You can also test your %{gitlab_ci_yml} in %{lint_link_start}CI Lint%{lint_link_end}"
-msgstr ""
+msgstr "Du kan også teste din %{gitlab_ci_yml} i %{lint_link_start}CI Lint%{lint_link_end}"
msgid "You can also upload existing files from your computer using the instructions below."
-msgstr ""
+msgstr "Du kan også laste opp eksisterende filer fra datamaskinen din ved å følge instruksjonene nedenfor."
msgid "You can always edit this later"
-msgstr ""
-
-msgid "You can apply your Trial to your Personal account or create a New Group."
-msgstr ""
+msgstr "Du kan alltid redigere dette senere"
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings"
msgstr ""
@@ -28421,27 +29357,36 @@ msgstr ""
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
+msgid "You can find more information about GitLab subscriptions in %{subscriptions_doc_link}."
+msgstr ""
+
msgid "You can generate an access token scoped to this project for each application to use the GitLab API."
msgstr ""
msgid "You can get started by cloning the repository or start adding files to it with one of the following options."
msgstr ""
-msgid "You can invite a new member to %{project_name} or invite another group."
+msgid "You can group test cases using labels. To learn about the future direction of this feature, visit %{linkStart}Quality Management direction page%{linkEnd}."
msgstr ""
+msgid "You can invite a new member to %{project_name} or invite another group."
+msgstr "Du kan invitere et nytt medlem til %{project_name} eller invitere en annen gruppe."
+
msgid "You can invite a new member to %{project_name}."
-msgstr ""
+msgstr "Du kan invitere et nytt medlem til %{project_name}."
msgid "You can invite another group to %{project_name}."
-msgstr ""
+msgstr "Du kan invitere en annen gruppe til %{project_name}."
msgid "You can move around the graph by using the arrow keys."
-msgstr ""
+msgstr "Du kan flytte rundt på grafen ved hjelp av piltastene."
msgid "You can notify the app / group or a project by sending them an email notification"
msgstr ""
+msgid "You can now close this window."
+msgstr ""
+
msgid "You can now export your security dashboard to a CSV report."
msgstr ""
@@ -28455,7 +29400,7 @@ msgid "You can now submit a merge request to get this change into the original p
msgstr ""
msgid "You can only edit files when you are on a branch"
-msgstr ""
+msgstr "Du kan bare redigere filer når du er på en gren"
msgid "You can only merge once the items above are resolved."
msgstr ""
@@ -28470,13 +29415,13 @@ msgid "You can only upload one design when dropping onto an existing design."
msgstr ""
msgid "You can recover this project until %{date}"
-msgstr ""
+msgstr "Du kan gjenopprette dette prosjektet frem til %{date}"
msgid "You can resolve the merge conflict using either the Interactive mode, by choosing %{use_ours} or %{use_theirs} buttons, or by editing the files directly. Commit these changes into %{branch_name}"
msgstr ""
msgid "You can see your chat accounts."
-msgstr ""
+msgstr "Du kan se dine chatkontoer."
msgid "You can set up as many Runners as you need to run your jobs."
msgstr ""
@@ -28490,11 +29435,8 @@ msgstr ""
msgid "You can test your .gitlab-ci.yml in %{linkStart}CI Lint%{linkEnd}."
msgstr ""
-msgid "You can try again using %{begin_link}basic search%{end_link}"
-msgstr ""
-
msgid "You cannot access the raw file. Please wait a minute."
-msgstr ""
+msgstr "Du kan ikke få tilgang til denne råfilen. Vennligst vent et minutt."
msgid "You cannot impersonate a blocked user"
msgstr ""
@@ -28524,13 +29466,13 @@ msgid "You didn't renew your subscription so it was downgraded to the GitLab Cor
msgstr ""
msgid "You do not have an active license"
-msgstr ""
+msgstr "Du har ikke en aktiv lisens"
msgid "You do not have any subscriptions yet"
-msgstr ""
+msgstr "Du har ikke noen abonnementer enda"
msgid "You do not have permission to leave this %{namespaceType}."
-msgstr ""
+msgstr "Du har ikke tillatelse til å forlate denne %{namespaceType}."
msgid "You do not have permission to run the Web Terminal. Please contact a project administrator."
msgstr ""
@@ -28542,31 +29484,34 @@ msgid "You do not have the correct permissions to override the settings from the
msgstr ""
msgid "You don't have any U2F devices registered yet."
+msgstr "Du har ikke registrert noen U2F-enheter enda."
+
+msgid "You don't have any WebAuthn devices registered yet."
msgstr ""
msgid "You don't have any active chat names."
-msgstr ""
+msgstr "Du har ingen aktive chat-navn."
msgid "You don't have any applications"
-msgstr ""
+msgstr "Du har ingen applikasjoner"
msgid "You don't have any authorized applications"
-msgstr ""
+msgstr "Du har ingen autoriserte applikasjoner"
msgid "You don't have any deployments right now."
msgstr ""
msgid "You don't have any open merge requests"
-msgstr ""
+msgstr "Du har ingen åpne fletteforespørsler"
msgid "You don't have any projects available."
-msgstr ""
+msgstr "Du har ikke noen prosjekter tilgjengelig."
msgid "You don't have any recent searches"
-msgstr ""
+msgstr "Du har ingen nylige søk"
msgid "You don't have sufficient permission to perform this action."
-msgstr ""
+msgstr "Du har ikke tilstrekkelig tillatelse til å utføre denne handlingen."
msgid "You don't have write access to the source branch."
msgstr ""
@@ -28581,22 +29526,22 @@ msgid "You have a license that activates at a future date. Please see the Licens
msgstr ""
msgid "You have been granted %{access_level} access to the %{source_link} %{source_type}."
-msgstr ""
+msgstr "Du har blitt tildelt %{access_level}-tilgang til %{source_link} %{source_type}."
msgid "You have been granted %{access_level} access to the %{source_name} %{source_type}."
-msgstr ""
+msgstr "Du har blitt tildelt %{access_level}-tilgang til %{source_name} %{source_type}."
msgid "You have been granted %{member_human_access} access to %{title} %{name}."
-msgstr ""
+msgstr "Du har blitt tildelt %{member_human_access}-tilgang til %{title} %{name}."
msgid "You have been invited"
-msgstr ""
+msgstr "Du har blitt invitert"
msgid "You have been unsubscribed from this thread."
-msgstr ""
+msgstr "Du har blitt avabonnert på denne tråden."
msgid "You have declined the invitation to join %{title} %{name}."
-msgstr ""
+msgstr "Du har avvist invitasjonen om å bli med i %{title} %{name}."
msgid "You have imported from this project %{numberOfPreviousImports} times before. Each new import will create duplicate issues."
msgstr ""
@@ -28605,49 +29550,52 @@ msgid "You have insufficient permissions to create a Todo for this alert"
msgstr ""
msgid "You have no permissions"
-msgstr ""
+msgstr "Du har ingen tillatelser"
msgid "You have not added any approvers. Start by adding users or groups."
-msgstr ""
+msgstr "Du har ikke lagt til noen godkjennere. Begynn med å legge til brukere eller grupper."
msgid "You have reached your project limit"
-msgstr ""
+msgstr "Du har nådd prosjektgrensen"
msgid "You have successfully purchased a %{plan} plan subscription for %{seats}. You’ll receive a receipt via email."
-msgstr ""
+msgstr "Du har vellykket kjøpt et abonnement på %{plan}-plan for %{seats}. Du mottar en kvittering via e-post."
msgid "You haven't added any issues to your project yet"
-msgstr ""
+msgstr "Du har ikke lagt til noen saker i prosjektet ditt ennå"
msgid "You haven't selected any issues yet"
-msgstr ""
+msgstr "You har ikke valgt noen saker enda"
msgid "You left the \"%{membershipable_human_name}\" %{source_type}."
-msgstr ""
+msgstr "Du forlot «%{membershipable_human_name}»-%{source_type}."
msgid "You may close the milestone now."
-msgstr ""
+msgstr "Du kan lukke milepælen nå."
msgid "You must accept our Terms of Service and privacy policy in order to register an account"
+msgstr "Du må godta vilkårene for bruk og personvern for å kunne registrere en konto"
+
+msgid "You must be logged in to search across all of GitLab"
msgstr ""
msgid "You must disassociate %{domain} from all clusters it is attached to before deletion."
msgstr ""
msgid "You must have maintainer access to force delete a lock"
-msgstr ""
+msgstr "Du må ha vedlikeholder-tilgang for å tvangsslette en lås"
msgid "You must have permission to create a project in a group before forking."
-msgstr ""
+msgstr "Du må tillatelse til å opprette et prosjekt i en gruppe før utgreining."
msgid "You must have permission to create a project in a namespace before forking."
-msgstr ""
+msgstr "Du må tillatelse til å opprette et prosjekt i et navneområde før utgreining."
msgid "You must provide a valid current password"
-msgstr ""
+msgstr "Du må oppgi et gjeldende gyldig passord"
msgid "You must provide your current password in order to change it."
-msgstr ""
+msgstr "Du må oppgi ditt nåværende passord for å kunne endre den."
msgid "You must select a stack for configuring your cloud provider. Learn more about"
msgstr ""
@@ -28656,28 +29604,28 @@ msgid "You must set up incoming email before it becomes active."
msgstr ""
msgid "You must upload a file with the same file name when dropping onto an existing design."
-msgstr ""
+msgstr "Du må laste opp en fil med det samme filnavnet når du slipper inn i et eksisterende design."
msgid "You need a different license to enable FileLocks feature"
-msgstr ""
+msgstr "Du trenger en annen lisens for å aktivere FileLocks-funksjonen"
msgid "You need git-lfs version %{min_git_lfs_version} (or greater) to continue. Please visit https://git-lfs.github.com"
msgstr ""
msgid "You need permission."
-msgstr ""
+msgstr "Du trenger tillatelse."
msgid "You need to be logged in."
-msgstr ""
+msgstr "Du må være logget inn."
-msgid "You need to register a two-factor authentication app before you can set up a U2F device."
+msgid "You need to register a two-factor authentication app before you can set up a device."
msgstr ""
msgid "You need to set terms to be enforced"
msgstr ""
msgid "You need to specify both an Access Token and a Host URL."
-msgstr ""
+msgstr "Du må spesifisere både en tilgangssjetong og en verts-URL."
msgid "You need to upload a GitLab project export archive (ending in .gz)."
msgstr ""
@@ -28688,9 +29636,12 @@ msgstr ""
msgid "You reached %{usage_in_percent} of %{namespace_name}'s storage capacity (%{used_storage} of %{storage_limit})"
msgstr ""
-msgid "You tried to fork %{link_to_the_project} but it failed for the following reason:"
+msgid "You successfully declined the invitation"
msgstr ""
+msgid "You tried to fork %{link_to_the_project} but it failed for the following reason:"
+msgstr "Du prøvde å utgreine %{link_to_the_project}, men det mislyktes av følgende grunn:"
+
msgid "You will be removed from existing projects/groups"
msgstr ""
@@ -28698,7 +29649,7 @@ msgid "You will be the author of all events in the activity feed that are the re
msgstr ""
msgid "You will first need to set up Jira Integration to use this feature."
-msgstr ""
+msgstr "Du må først konfigurere Jira-integrasjon for å bruke denne funksjonen."
msgid "You will lose all changes you've made to this file. This action cannot be undone."
msgstr ""
@@ -28707,25 +29658,25 @@ msgid "You will lose all uncommitted changes you've made in this project. This a
msgstr ""
msgid "You will need to update your local repositories to point to the new location."
-msgstr ""
+msgstr "Du vil måtte oppdatere dine lokale arkiver for å peke dem mot den nye plasseringen."
msgid "You will not get any notifications via email"
-msgstr ""
+msgstr "Du vil ikke motta varsler via e-post"
msgid "You will only receive notifications for the events you choose"
msgstr ""
msgid "You will only receive notifications for threads you have participated in"
-msgstr ""
+msgstr "Du vil bare motta varsler for tråder du har deltatt i"
msgid "You will receive notifications for any activity"
-msgstr ""
+msgstr "Du vil motta varsler om enhver aktivitet"
msgid "You will receive notifications only for comments in which you were @mentioned"
-msgstr ""
+msgstr "Du vil kun motta varsler for kommentarer der du ble @nevnt"
msgid "You won't be able to create new projects because you have reached your project limit."
-msgstr ""
+msgstr "Du vil ikke kunne opprette nye prosjekter fordi du har nådd prosjektgrensen din."
msgid "You won't be able to pull or push project code via %{protocol} until you %{set_password_link} on your account"
msgstr ""
@@ -28746,31 +29697,31 @@ msgid "You're about to reduce the visibility of the project %{strong_start}%{pro
msgstr ""
msgid "You're about to reduce the visibility of the project %{strong_start}%{project_name}%{strong_end}."
-msgstr ""
+msgstr "Du er i ferd med å redusere synligheten til prosjektet %{strong_start}%{project_name}%{strong_end}."
msgid "You're at the first commit"
-msgstr ""
+msgstr "Du er ved den første commiten"
msgid "You're at the last commit"
-msgstr ""
+msgstr "Du er ved den siste commiten"
msgid "You're not allowed to %{tag_start}edit%{tag_end} files in this project directly. Please fork this project, make your changes there, and submit a merge request."
msgstr ""
msgid "You're not allowed to make changes to this project directly. A fork of this project has been created that you can make changes in, so you can submit a merge request."
-msgstr ""
+msgstr "Du har ikke tillatelse til å gjøre endringer i dette prosjektet direkte. En utgreining av dette prosjektet har blitt opprettet som du kan gjøre endringer i, slik at du kan sende inn en fletteforespørsel."
msgid "You're not allowed to make changes to this project directly. A fork of this project is being created that you can make changes in, so you can submit a merge request."
-msgstr ""
+msgstr "Du har ikke tillatelse til å gjøre endringer i dette prosjektet direkte. En utgreining av dette prosjektet blir opprettet som du kan gjøre endringer i, slik at du kan sende inn en fletteforespørsel."
msgid "You're only seeing %{startTag}other activity%{endTag} in the feed. To add a comment, switch to one of the following options."
msgstr ""
msgid "You're receiving this email because of your account on %{host}."
-msgstr ""
+msgstr "Du mottar denne e-posten på grunn av kontoen din på %{host}."
msgid "You're receiving this email because of your account on %{host}. %{manage_notifications_link} &middot; %{help_link}"
-msgstr ""
+msgstr "Du mottar denne e-posten på grunn av kontoen din på %{host}. %{manage_notifications_link} &middot; %{help_link}"
msgid "You're receiving this email because of your activity on %{host}."
msgstr ""
@@ -28782,19 +29733,19 @@ msgid "You're receiving this email because you have been mentioned on %{host}."
msgstr ""
msgid "You've already enabled two-factor authentication using one time password authenticators. In order to register a different device, you must first disable two-factor authentication."
-msgstr ""
+msgstr "Du har allerede aktivert 2-trinnsautentisering ved hjelp av éngangspassord-autentikatorer. For å kunne registrere en annen enhet, må du først deaktivere 2-trinnsautentisering."
msgid "YouTube"
-msgstr ""
+msgstr "YouTube"
msgid "Your %{host} account was signed in to from a new location"
msgstr ""
msgid "Your %{strong}%{plan_name}%{strong_close} subscription for %{strong}%{namespace_name}%{strong_close} will expire on %{strong}%{expires_on}%{strong_close}."
-msgstr ""
+msgstr "Ditt %{strong}%{plan_name}%{strong_close} abonnement på %{strong}%{namespace_name}%{strong_close} vil utløpe den %{strong}%{expires_on}%{strong_close}."
msgid "Your %{strong}%{plan_name}%{strong_close} subscription will expire on %{strong}%{expires_on}%{strong_close}. After that, you will not to be able to create issues or merge requests as well as many other features."
-msgstr ""
+msgstr "Ditt %{strong}%{plan_name}%{strong_close}-abonnement utløper den %{strong}%{expires_on}%{strong_close}. Etter det vil du ikke kunne lage saker eller fletteforespørsler, samt mange andre funksjoner."
msgid "Your CSV export has started. It will be emailed to %{email} when complete."
msgstr ""
@@ -28812,22 +29763,22 @@ msgid "Your Default Notification Email will be used for account notifications if
msgstr ""
msgid "Your DevOps Report gives an overview of how you are using GitLab from a feature perspective. View how you compare with other organizations, discover features you are not using, and learn best practices through blog posts and white papers."
-msgstr ""
+msgstr "DevOps-rapporten din gir en oversikt over hvordan du bruker GitLab fra et funksjonsperspektiv. Se hvordan du ligger an sammenlignet med andre organisasjoner, oppdag funksjoner du ikke bruker, og lær beste praksis gjennom blogginnlegg og rapporter."
msgid "Your GPG keys (%{count})"
-msgstr ""
+msgstr "Dine GPG-nøkler (%{count})"
msgid "Your GitLab group"
-msgstr ""
+msgstr "Din GitLab-gruppe"
msgid "Your Gitlab Gold trial will last 30 days after which point you can keep your free Gitlab account forever. We just need some additional information to activate your trial."
msgstr ""
msgid "Your Groups"
-msgstr ""
+msgstr "Dine grupper"
msgid "Your License"
-msgstr ""
+msgstr "Din lisens"
msgid "Your Personal Access Tokens will expire in %{days_to_expire} days or less"
msgstr ""
@@ -28836,7 +29787,7 @@ msgid "Your Primary Email will be used for avatar detection."
msgstr ""
msgid "Your Projects (default)"
-msgstr ""
+msgstr "Dine prosjekter (standard)"
msgid "Your Projects' Activity"
msgstr ""
@@ -28845,41 +29796,47 @@ msgid "Your Public Email will be displayed on your public profile."
msgstr ""
msgid "Your SSH keys (%{count})"
-msgstr ""
+msgstr "SSH-nøklene dine (%{count})"
msgid "Your To-Do List"
-msgstr ""
+msgstr "Din gjøremålsliste"
msgid "Your U2F device did not send a valid JSON response."
-msgstr ""
+msgstr "U2F-enheten din sendte ikke et gyldig JSON-svar."
-msgid "Your U2F device needs to be set up. Plug it in (if not already) and click the button on the left."
+msgid "Your U2F device was registered!"
+msgstr "Din U2F-enhet ble registrert!"
+
+msgid "Your WebAuthn device did not send a valid JSON response."
msgstr ""
-msgid "Your U2F device was registered!"
+msgid "Your WebAuthn device was registered!"
msgstr ""
msgid "Your access request to the %{source_type} has been withdrawn."
-msgstr ""
+msgstr "Din tilgangsforespørsel til %{source_type} har blitt trukket tilbake."
msgid "Your account has been deactivated by your administrator. Please log back in to reactivate your account."
-msgstr ""
+msgstr "Kontoen din har blitt deaktivert av administratoren din. Logg deg på igjen for å aktivere kontoen din på nytt."
msgid "Your account is locked."
-msgstr ""
+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 applications (%{size})"
-msgstr ""
+msgstr "Dine applikasjoner (%{size})"
msgid "Your authorized applications"
-msgstr ""
+msgstr "Dine autoriserte applikasjoner"
msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
msgstr ""
+msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
+msgstr ""
+
msgid "Your changes can be committed to %{branch_name} because a merge request is open."
msgstr ""
@@ -28887,7 +29844,7 @@ msgid "Your changes have been committed. Commit %{commitId} %{commitStats}"
msgstr ""
msgid "Your changes have been saved"
-msgstr ""
+msgstr "Dine endringer har blitt lagret"
msgid "Your changes have been successfully committed."
msgstr ""
@@ -28902,7 +29859,7 @@ msgid "Your comment could not be updated! Please check your network connection a
msgstr ""
msgid "Your comment will be discarded."
-msgstr ""
+msgstr "Din kommentar vil bli forkastet."
msgid "Your custom stage '%{title}' was created"
msgstr ""
@@ -28916,17 +29873,23 @@ msgstr ""
msgid "Your deployment services will be broken, you will need to manually fix the services after renaming."
msgstr ""
+msgid "Your device is not compatible with GitLab. Please try another device"
+msgstr ""
+
+msgid "Your device needs to be set up. Plug it in (if needed) and click the button on the left."
+msgstr ""
+
msgid "Your device was successfully set up! Give it a name and register it with the GitLab server."
msgstr ""
msgid "Your first project"
-msgstr ""
+msgstr "Ditt første prosjekt"
msgid "Your groups"
-msgstr ""
+msgstr "Dine grupper"
msgid "Your instance has %{remaining_user_count} users remaining of the %{total_user_count} included in your subscription. You can add more users than the number included in your license, and we will include the overage in your next bill."
-msgstr ""
+msgstr "Din instans har %{remaining_user_count} brukere av %{total_user_count} som er inkludert i abonnementet ditt. Du kan legge til flere brukere enn det tallet som er inkludert i lisensen din, og vi vil inkludere overstrekkelsen i din neste regning."
msgid "Your instance has exceeded your subscription's licensed user count."
msgstr ""
@@ -28935,28 +29898,28 @@ msgid "Your instance is approaching its licensed user count"
msgstr ""
msgid "Your issues are being imported. Once finished, you'll get a confirmation email."
-msgstr ""
+msgstr "Sakene dine blir importert. Når det er ferdig, vil du få en bekreftelses-e-post."
msgid "Your issues will be imported in the background. Once finished, you'll get a confirmation email."
msgstr ""
msgid "Your license is valid from"
-msgstr ""
+msgstr "Din lisens er gyldig fra"
msgid "Your license will be included in your GitLab backup and will survive upgrades, so in normal usage you should never need to re-upload your %{code_open}.gitlab-license%{code_close} file."
-msgstr ""
+msgstr "Lisensen din vil bli inkludert i GitLab-sikkerhetskopien og vil overleve oppgraderinger, så ved normal bruk trenger du aldri å laste opp %{code_open}.gitlab-lisens%{code_close}-filen din på nytt."
msgid "Your message here"
-msgstr ""
+msgstr "Din melding her"
msgid "Your name"
-msgstr ""
+msgstr "Navnet ditt"
msgid "Your new %{type}"
-msgstr ""
+msgstr "Din nye %{type}"
msgid "Your new SCIM token"
-msgstr ""
+msgstr "Din nye SCIM-sjetong"
msgid "Your new personal access token has been created."
msgstr ""
@@ -28974,16 +29937,16 @@ msgid "Your personal access token has expired"
msgstr ""
msgid "Your profile"
-msgstr ""
+msgstr "Din profil"
msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it"
-msgstr ""
+msgstr "Prosjektgrensen din er %{limit} prosjekter! Kontakt administratoren din for å øke den"
msgid "Your projects"
-msgstr ""
+msgstr "Dine prosjekter"
msgid "Your request for access could not be processed: %{error_meesage}"
-msgstr ""
+msgstr "Din tilgangsforespørsel kunne ikke behandles: %{error_meesage}"
msgid "Your request for access has been queued for review."
msgstr ""
@@ -28992,45 +29955,42 @@ msgid "Your response has been recorded."
msgstr ""
msgid "Your search didn't match any commits."
-msgstr ""
+msgstr "Søket ditt samsvarte ikke med noen commiter."
msgid "Your search didn't match any commits. Try a different query."
-msgstr ""
+msgstr "Søket ditt samsvarte ikke med noen commiter. Prøv et annet søkeuttrykk."
msgid "Your subscription expired!"
-msgstr ""
+msgstr "Abonnementet ditt har utløpt!"
msgid "Your subscription has been downgraded."
-msgstr ""
+msgstr "Abonnementet ditt har blitt nedgradert."
msgid "Your subscription will expire in %{remaining_days}."
msgstr ""
msgid "Zoom meeting added"
-msgstr ""
+msgstr "Zoom-møte lagt til"
msgid "Zoom meeting removed"
-msgstr ""
+msgstr "Zoom-møte fjernet"
msgid "[No reason]"
-msgstr ""
+msgstr "[Ingen grunn]"
msgid "a deleted user"
-msgstr ""
+msgstr "en slettet bruker"
msgid "a design"
-msgstr ""
+msgstr "et design"
msgid "about 1 hour"
msgid_plural "about %d hours"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "omkring 1 time"
+msgstr[1] "omkring %d timer"
msgid "access:"
-msgstr ""
-
-msgid "activated"
-msgstr ""
+msgstr "tilgang:"
msgid "added %{created_at_timeago}"
msgstr ""
@@ -29039,28 +29999,28 @@ msgid "added a Zoom call to this issue"
msgstr ""
msgid "ago"
-msgstr ""
+msgstr "siden"
msgid "alert"
-msgstr ""
+msgstr "alarm"
msgid "allowed to fail"
-msgstr ""
+msgstr "tillatt å mislykkes"
msgid "already being used for another group or project %{timebox_name}."
-msgstr ""
+msgstr "brukes allerede for en annen gruppe eller prosjekt %{timebox_name}."
msgid "already has a \"created\" issue link"
msgstr ""
msgid "already shared with this group"
-msgstr ""
+msgstr "allerede delt med denne gruppen"
msgid "among other things"
-msgstr ""
+msgstr "blant andre ting"
msgid "and"
-msgstr ""
+msgstr "og"
msgid "any-approver for the merge request already exists"
msgstr ""
@@ -29069,44 +30029,56 @@ msgid "any-approver for the project already exists"
msgstr ""
msgid "approved by: "
-msgstr ""
+msgstr "godkjent av: "
msgid "archived"
-msgstr ""
+msgstr "arkivert"
msgid "archived:"
-msgstr ""
+msgstr "arkivert:"
msgid "as %{role}."
-msgstr ""
+msgstr "som %{role}."
msgid "assign yourself"
-msgstr ""
+msgstr "tildel deg selv"
msgid "at risk"
-msgstr ""
+msgstr "i faresonen"
msgid "attach a new file"
-msgstr ""
+msgstr "legg ved en ny fil"
msgid "authored"
-msgstr ""
+msgstr "skapt"
msgid "blocks"
-msgstr ""
+msgstr "blokker"
msgid "branch name"
-msgstr ""
+msgstr "grennavn"
msgid "by"
-msgstr ""
+msgstr "av"
msgid "by %{user}"
+msgstr "av %{user}"
+
+msgid "cannot be a date in the past"
msgstr ""
msgid "cannot be changed if a personal project has container registry tags."
msgstr ""
+msgid "cannot be changed if shared runners are enabled"
+msgstr ""
+
+msgid "cannot be enabled because parent group does not allow it"
+msgstr ""
+
+msgid "cannot be enabled because parent group has shared Runners disabled"
+msgstr ""
+
msgid "cannot be enabled unless all domains have TLS certificates"
msgstr ""
@@ -29123,19 +30095,19 @@ msgid "cannot include leading slash or directory traversal."
msgstr ""
msgid "cannot itself be blocked"
-msgstr ""
+msgstr "kan ikke selv bli blokkert"
msgid "cannot merge"
-msgstr ""
+msgstr "kan ikke flette"
msgid "child-pipeline"
msgstr ""
msgid "ciReport|%{degradedNum} degraded"
-msgstr ""
+msgstr "%{degradedNum} degradert"
msgid "ciReport|%{improvedNum} improved"
-msgstr ""
+msgstr "%{improvedNum} forbedret"
msgid "ciReport|%{linkStartTag}Learn more about Container Scanning %{linkEndTag}"
msgstr ""
@@ -29144,49 +30116,49 @@ msgid "ciReport|%{linkStartTag}Learn more about Coverage Fuzzing %{linkEndTag}"
msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about DAST %{linkEndTag}"
-msgstr ""
+msgstr "%{linkStartTag}Lær mer om DAST %{linkEndTag}"
msgid "ciReport|%{linkStartTag}Learn more about Dependency Scanning %{linkEndTag}"
-msgstr ""
+msgstr "%{linkStartTag}Lær mer om SAST %{linkEndTag}"
msgid "ciReport|%{linkStartTag}Learn more about SAST %{linkEndTag}"
-msgstr ""
+msgstr "%{linkStartTag}Lær mer om SAST %{linkEndTag}"
-msgid "ciReport|%{linkStartTag}Learn more about Secret Scanning %{linkEndTag}"
+msgid "ciReport|%{linkStartTag}Learn more about Secret Detection %{linkEndTag}"
msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about codequality reports %{linkEndTag}"
msgstr ""
msgid "ciReport|%{remainingPackagesCount} more"
-msgstr ""
+msgstr "%{remainingPackagesCount} til"
msgid "ciReport|%{reportType} is loading"
-msgstr ""
+msgstr "%{reportType} lastes inn"
msgid "ciReport|%{reportType}: Loading resulted in an error"
-msgstr ""
+msgstr "%{reportType}: Innlasting førte til en feil"
msgid "ciReport|%{sameNum} same"
-msgstr ""
+msgstr "%{sameNum} samme"
msgid "ciReport|(errors when loading results)"
-msgstr ""
+msgstr "(feil ved lasting av resultater)"
msgid "ciReport|(is loading)"
-msgstr ""
+msgstr "(laster inn)"
msgid "ciReport|(is loading, errors when loading results)"
-msgstr ""
+msgstr "(lastes, feil ved lasting av resultater)"
msgid "ciReport|All projects"
-msgstr ""
+msgstr "Alle prosjekter"
msgid "ciReport|All scanners"
-msgstr ""
+msgstr "Alle skannere"
msgid "ciReport|All severities"
-msgstr ""
+msgstr "Alle alvorlighetsgrader"
msgid "ciReport|Automatically apply the patch in a new branch"
msgstr ""
@@ -29204,13 +30176,13 @@ msgid "ciReport|Checks"
msgstr ""
msgid "ciReport|Code quality"
-msgstr ""
+msgstr "Kodekvalitet"
msgid "ciReport|Container Scanning"
-msgstr ""
+msgstr "Containerskanning"
msgid "ciReport|Container scanning"
-msgstr ""
+msgstr "Containerskanning"
msgid "ciReport|Container scanning detects known vulnerabilities in your docker images."
msgstr ""
@@ -29228,19 +30200,19 @@ msgid "ciReport|Create a merge request to implement this solution, or download a
msgstr ""
msgid "ciReport|Create issue"
-msgstr ""
+msgstr "Opprett sak"
msgid "ciReport|DAST"
-msgstr ""
+msgstr "DAST"
msgid "ciReport|Dependency Scanning"
-msgstr ""
+msgstr "Avhengighetsskanning"
msgid "ciReport|Dependency Scanning detects known vulnerabilities in your source code's dependencies."
msgstr ""
msgid "ciReport|Dependency scanning"
-msgstr ""
+msgstr "Avhengighetsskanning"
msgid "ciReport|Download patch to resolve"
msgstr ""
@@ -29252,22 +30224,22 @@ msgid "ciReport|Dynamic Application Security Testing (DAST) detects known vulner
msgstr ""
msgid "ciReport|Failed to load %{reportName} report"
-msgstr ""
+msgstr "Kunne ikke laste inn %{reportName}-rapporten"
msgid "ciReport|Fixed"
-msgstr ""
+msgstr "Fikset"
msgid "ciReport|Fixed:"
-msgstr ""
+msgstr "Rettet opp i:"
msgid "ciReport|Found %{issuesWithCount}"
-msgstr ""
+msgstr "Fant %{issuesWithCount}"
msgid "ciReport|Investigate this vulnerability by creating an issue"
-msgstr ""
+msgstr "Undersøk dette sikkerhetsproblemet ved å opprette en sak"
msgid "ciReport|Learn more about interacting with security reports"
-msgstr ""
+msgstr "Lær mer om samhandling med sikkerhetsrapporter"
msgid "ciReport|Load performance test metrics: "
msgstr ""
@@ -29276,61 +30248,61 @@ msgid "ciReport|Load performance test metrics: No changes"
msgstr ""
msgid "ciReport|Loading %{reportName} report"
-msgstr ""
+msgstr "Laster inn %{reportName} rapport"
msgid "ciReport|Manage licenses"
-msgstr ""
+msgstr "Administrer lisenser"
msgid "ciReport|New"
-msgstr ""
+msgstr "Ny"
msgid "ciReport|No changes to code quality"
-msgstr ""
+msgstr "Ingen endringer i kodekvalitet"
msgid "ciReport|No code quality issues found"
-msgstr ""
+msgstr "Ingen kodekvalitetsproblemer ble funnet"
msgid "ciReport|RPS"
-msgstr ""
+msgstr "RPS"
msgid "ciReport|Resolve with merge request"
msgstr ""
msgid "ciReport|SAST"
-msgstr ""
+msgstr "SAST"
msgid "ciReport|Secret Detection"
-msgstr ""
+msgstr "Hemmelig oppdaging"
msgid "ciReport|Secret scanning"
-msgstr ""
+msgstr "Hemmelig skanning"
msgid "ciReport|Secret scanning detects secrets and credentials vulnerabilities in your source code."
msgstr ""
msgid "ciReport|Security scanning"
-msgstr ""
+msgstr "Sikkerhetsskanning"
msgid "ciReport|Security scanning failed loading any results"
msgstr ""
msgid "ciReport|Solution"
-msgstr ""
+msgstr "Løsning"
msgid "ciReport|Static Application Security Testing (SAST) detects known vulnerabilities in your source code."
msgstr ""
msgid "ciReport|TTFB P90"
-msgstr ""
+msgstr "TTFB P90"
msgid "ciReport|TTFB P95"
-msgstr ""
+msgstr "TTFB P95"
msgid "ciReport|There was an error creating the issue. Please try again."
msgstr ""
msgid "ciReport|There was an error creating the merge request. Please try again."
-msgstr ""
+msgstr "Det oppstod en feil under oppretting av fletteforespørselen. Vennligst prøv igjen."
msgid "ciReport|There was an error dismissing the vulnerability. Please try again."
msgstr ""
@@ -29343,29 +30315,29 @@ msgstr ""
msgid "ciReport|Used by %{packagesString}"
msgid_plural "ciReport|Used by %{packagesString}, and %{lastPackage}"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "Brukes av %{packagesString}"
+msgstr[1] "Brukes av %{packagesString}, og %{lastPackage}"
msgid "ciReport|View full report"
-msgstr ""
+msgstr "Vis fullstendig rapport"
msgid "closed issue"
-msgstr ""
+msgstr "lukket saksrapport"
msgid "comment"
-msgstr ""
+msgstr "kommentar"
msgid "commented on %{link_to_project}"
msgstr ""
msgid "commit %{commit_id}"
-msgstr ""
+msgstr "commit %{commit_id}"
msgid "committed"
-msgstr ""
+msgstr "forpliktet"
msgid "connecting"
-msgstr ""
+msgstr "kobler til"
msgid "container_name can contain only lowercase letters, digits, '-', and '.' and must start and end with an alphanumeric character"
msgstr ""
@@ -29377,65 +30349,65 @@ msgid "could not read private key, is the passphrase correct?"
msgstr ""
msgid "created"
-msgstr ""
+msgstr "laget"
msgid "created %{timeAgo}"
-msgstr ""
+msgstr "opprettet %{timeAgo}"
msgid "customize"
-msgstr ""
+msgstr "tilpasse"
msgid "data"
-msgstr ""
+msgstr "data"
msgid "date must not be after 9999-12-31"
msgstr ""
msgid "day"
msgid_plural "days"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "dag"
+msgstr[1] "dager"
msgid "default branch"
msgstr ""
msgid "deleted"
-msgstr ""
+msgstr "slettet"
msgid "deploy"
-msgstr ""
+msgstr "distribuering"
msgid "design"
-msgstr ""
+msgstr "design"
msgid "designs"
-msgstr ""
+msgstr "design"
msgid "detached"
-msgstr ""
+msgstr "frakoblet"
msgid "disabled"
-msgstr ""
+msgstr "ikke i bruk"
msgid "does not exist"
-msgstr ""
+msgstr "eksisterer ikke"
msgid "does not have a supported extension. Only %{extension_list} are supported"
msgstr ""
msgid "done"
-msgstr ""
+msgstr "ferdig"
msgid "download it"
-msgstr ""
+msgstr "last den ned"
msgid "draft"
msgid_plural "drafts"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "utkast"
+msgstr[1] "utkast"
msgid "e.g. %{token}"
-msgstr ""
+msgstr "f.eks. %{token}"
msgid "element is not a hierarchy"
msgstr ""
@@ -29447,107 +30419,107 @@ msgid "email '%{email}' is not a verified email."
msgstr ""
msgid "enabled"
-msgstr ""
+msgstr "aktivert"
msgid "encrypted: needs to be a :required, :optional or :migrating!"
msgstr ""
msgid "entries cannot be larger than 255 characters"
-msgstr ""
+msgstr "oppføringer kan ikke være på mer enn 255 tegn"
msgid "entries cannot be nil"
msgstr ""
msgid "entries cannot contain HTML tags"
-msgstr ""
+msgstr "oppføringer kan ikke inneholde HTML-etiketter"
msgid "epic"
-msgstr ""
+msgstr "epos"
msgid "error"
-msgstr ""
-
-msgid "error code:"
-msgstr ""
+msgstr "feil"
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr ""
msgid "exceeds the limit of %{bytes} bytes"
-msgstr ""
+msgstr "overgår grensen på %{bytes} bytes"
msgid "exceeds the limit of %{bytes} bytes for directory name \"%{dirname}\""
msgstr ""
msgid "expired on %{timebox_due_date}"
-msgstr ""
+msgstr "utløp den %{timebox_due_date}"
msgid "expires on %{timebox_due_date}"
-msgstr ""
+msgstr "utløper den %{timebox_due_date}"
msgid "failed"
-msgstr ""
+msgstr "mislyktes"
msgid "failed to dismiss associated finding(id=%{finding_id}): %{message}"
msgstr ""
+msgid "failed to revert associated finding(id=%{finding_id}) to detected"
+msgstr ""
+
msgid "file"
msgid_plural "files"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "fil"
+msgstr[1] "filer"
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
msgid "for %{link_to_merge_request} with %{link_to_merge_request_source_branch}"
-msgstr ""
+msgstr "for %{link_to_merge_request} med %{link_to_merge_request_source_branch}"
msgid "for %{link_to_merge_request} with %{link_to_merge_request_source_branch} into %{link_to_merge_request_target_branch}"
msgstr ""
msgid "for %{link_to_pipeline_ref}"
-msgstr ""
+msgstr "for %{link_to_pipeline_ref}"
msgid "for %{ref}"
-msgstr ""
+msgstr "for %{ref}"
msgid "for this project"
-msgstr ""
+msgstr "for dette prosjektet"
msgid "fork this project"
-msgstr ""
+msgstr "utgrein dette prosjektet"
msgid "from"
-msgstr ""
+msgstr "fra"
msgid "from %d job"
msgid_plural "from %d jobs"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "fra %d jobb"
+msgstr[1] "fra %d jobber"
msgid "group"
-msgstr ""
+msgstr "gruppe"
msgid "group members"
-msgstr ""
+msgstr "gruppemedlemmer"
msgid "groups"
-msgstr ""
+msgstr "grupper"
msgid "has already been linked to another vulnerability"
msgstr ""
msgid "has already been taken"
-msgstr ""
+msgstr "er allerede i bruk"
msgid "help"
-msgstr ""
+msgstr "hjelp"
msgid "http:"
-msgstr ""
+msgstr "http:"
msgid "https://your-bitbucket-server"
-msgstr ""
+msgstr "https://din-bitbucket-tjener"
msgid "image diff"
msgstr ""
@@ -29562,36 +30534,36 @@ msgid "import flow"
msgstr ""
msgid "importing"
-msgstr ""
+msgstr "importerer"
msgid "in group %{link_to_group}"
-msgstr ""
+msgstr "i gruppen %{link_to_group}"
msgid "in project %{link_to_project}"
-msgstr ""
+msgstr "i prosjektet %{link_to_project}"
msgid "instance completed"
msgid_plural "instances completed"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "instans fullført"
+msgstr[1] "instanser fullført"
msgid "invalid milestone state `%{state}`"
-msgstr ""
+msgstr "ugyldig milepælstilstand `%{state}`"
msgid "is"
-msgstr ""
+msgstr "er"
msgid "is already associated to a GitLab Issue. New issue will not be associated."
msgstr ""
msgid "is an invalid IP address range"
-msgstr ""
+msgstr "er et ugyldig IP-adresseområde"
msgid "is blocked by"
-msgstr ""
+msgstr "er blokkert av"
msgid "is enabled."
-msgstr ""
+msgstr "er skrudd på."
msgid "is invalid because there is downstream lock"
msgstr ""
@@ -29600,13 +30572,13 @@ msgid "is invalid because there is upstream lock"
msgstr ""
msgid "is not"
-msgstr ""
+msgstr "er ikke"
msgid "is not a descendant of the Group owning the template"
msgstr ""
msgid "is not a valid X509 certificate."
-msgstr ""
+msgstr "er ikke et gyldig X509-sertifikat."
msgid "is not allowed. Try again with a different email address, or contact your GitLab admin."
msgstr ""
@@ -29621,19 +30593,19 @@ msgid "is not in the group enforcing Group Managed Account"
msgstr ""
msgid "is read only"
-msgstr ""
+msgstr "har kun lesetilgang"
msgid "is too long (%{current_value}). The maximum size is %{max_size}."
msgstr ""
msgid "is too long (maximum is 100 entries)"
-msgstr ""
+msgstr "er for lang (maksimum er 100 oppføringer)"
msgid "is too long (maximum is 1000 entries)"
-msgstr ""
+msgstr "er for lang (maksimum er 1000 oppføringer)"
msgid "issue"
-msgstr ""
+msgstr "saksrapport"
msgid "issues at risk"
msgstr ""
@@ -29645,7 +30617,7 @@ msgid "issues on track"
msgstr ""
msgid "it is larger than %{limit}"
-msgstr ""
+msgstr "den er større enn %{limit}"
msgid "it is stored as a job artifact"
msgstr ""
@@ -29657,84 +30629,84 @@ msgid "it is stored in LFS"
msgstr ""
msgid "it is too large"
-msgstr ""
+msgstr "den er for stor"
msgid "jigsaw is not defined"
msgstr ""
msgid "last commit:"
-msgstr ""
+msgstr "seneste commit:"
msgid "latest"
-msgstr ""
+msgstr "siste"
msgid "latest deployment"
msgstr ""
msgid "latest version"
-msgstr ""
+msgstr "seneste versjon"
msgid "leave %{group_name}"
-msgstr ""
+msgstr "forlat %{group_name}"
msgid "less than a minute"
-msgstr ""
+msgstr "mindre enn ett minutt"
msgid "level: %{level}"
-msgstr ""
+msgstr "nivå: %{level}"
msgid "limit of %{project_limit} reached"
-msgstr ""
+msgstr "grensen på %{project_limit} er nådd"
msgid "load it anyway"
-msgstr ""
+msgstr "last den inn likevel"
msgid "loading"
-msgstr ""
+msgstr "laster"
msgid "locked"
-msgstr ""
+msgstr "låst"
msgid "locked by %{path_lock_user_name} %{created_at}"
-msgstr ""
+msgstr "låst av %{path_lock_user_name} %{created_at}"
msgid "log in"
-msgstr ""
+msgstr "logg inn"
msgid "manual"
-msgstr ""
+msgstr "manual"
msgid "math|The math in this entry is taking too long to render and may not be displayed as expected. For performance reasons, math blocks are also limited to %{maxChars} characters. Consider splitting up large formulae, splitting math blocks among multiple entries, or using an image instead."
-msgstr ""
+msgstr "Matematikken i denne oppføringen tar for lang tid å gjengi og vises kanskje ikke som forventet. Av ytelsesgrunner er matteblokker også begrenset til %{maxChars} tegn. Vurder å dele opp store formler, å dele matteblokker mellom flere oppføringer, eller å bruke et bilde i stedet."
msgid "math|There was an error rendering this math block"
msgstr ""
msgid "merge request"
msgid_plural "merge requests"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "fletteforespørsel"
+msgstr[1] "fletteforespørsler"
msgid "merged %{timeAgo}"
-msgstr ""
+msgstr "flettet %{timeAgo}"
msgid "metric_id must be unique across a project"
msgstr ""
msgid "missing"
-msgstr ""
+msgstr "mangler"
msgid "most recent deployment"
msgstr ""
msgid "mrWidgetCommitsAdded|%{commitCount} and %{mergeCommitCount} will be added to %{targetBranch}."
-msgstr ""
+msgstr "%{commitCount} og %{mergeCommitCount} vil bli lagt til i %{targetBranch}."
msgid "mrWidgetCommitsAdded|%{commitCount} will be added to %{targetBranch}."
-msgstr ""
+msgstr "%{commitCount} vil bli lagt til i %{targetBranch}."
msgid "mrWidgetCommitsAdded|1 merge commit"
-msgstr ""
+msgstr "1 innflettings-commit"
msgid "mrWidgetNothingToMerge|Currently there are no changes in this merge request's source branch. Please push new commits or use a different branch."
msgstr ""
@@ -29746,7 +30718,7 @@ msgid "mrWidgetNothingToMerge|Merge requests are a place to propose changes you
msgstr ""
msgid "mrWidget| Please restore it or use a different %{missingBranchName} branch"
-msgstr ""
+msgstr "Vennligst gjenopprett den eller bruk en annen %{missingBranchName}-fane"
msgid "mrWidget|%{link_start}Learn more about resolving conflicts%{link_end}"
msgstr ""
@@ -29785,19 +30757,19 @@ msgid "mrWidget|An error occurred while submitting your approval."
msgstr ""
msgid "mrWidget|Approval is optional"
-msgstr ""
+msgstr "Godkjennelse er valgfritt"
msgid "mrWidget|Approval password is invalid."
-msgstr ""
+msgstr "Godkjennelsespassordet er ugyldig."
msgid "mrWidget|Approve"
-msgstr ""
+msgstr "Godkjenn"
msgid "mrWidget|Approve additionally"
msgstr ""
msgid "mrWidget|Approved by"
-msgstr ""
+msgstr "Godkjent av"
msgid "mrWidget|Are you adding technical debt or code vulnerabilities?"
msgstr ""
@@ -29806,7 +30778,7 @@ msgid "mrWidget|Before this can be merged, one or more threads must be resolved.
msgstr ""
msgid "mrWidget|Cancel automatic merge"
-msgstr ""
+msgstr "Avbryt automatisk innfletting"
msgid "mrWidget|Check out branch"
msgstr ""
@@ -29821,13 +30793,13 @@ msgid "mrWidget|Cherry-pick this merge request in a new merge request"
msgstr ""
msgid "mrWidget|Closed"
-msgstr ""
+msgstr "Lukket"
msgid "mrWidget|Closed by"
-msgstr ""
+msgstr "Lukket av"
msgid "mrWidget|Closes"
-msgstr ""
+msgstr "Lukker"
msgid "mrWidget|Delete source branch"
msgstr ""
@@ -29836,10 +30808,10 @@ msgid "mrWidget|Deployment statistics are not available currently"
msgstr ""
msgid "mrWidget|Did not close"
-msgstr ""
+msgstr "Lukket ikke"
msgid "mrWidget|Email patches"
-msgstr ""
+msgstr "Send e-post ved programrettelser"
msgid "mrWidget|Failed to load deployment statistics"
msgstr ""
@@ -29869,31 +30841,31 @@ msgid "mrWidget|Mark as ready"
msgstr ""
msgid "mrWidget|Mentions"
-msgstr ""
+msgstr "Nevnelser"
msgid "mrWidget|Merge"
-msgstr ""
+msgstr "Flett"
msgid "mrWidget|Merge failed."
-msgstr ""
+msgstr "Fletting mislyktes."
msgid "mrWidget|Merge failed: %{mergeError}. Please try again."
msgstr ""
msgid "mrWidget|Merge locally"
-msgstr ""
+msgstr "Flett lokalt"
msgid "mrWidget|Merge request approved."
msgstr ""
msgid "mrWidget|Merged by"
-msgstr ""
+msgstr "Flettet av"
msgid "mrWidget|More information"
-msgstr ""
+msgstr "Mer informasjon"
msgid "mrWidget|Open in Web IDE"
-msgstr ""
+msgstr "Ã…pne i nett-IDE"
msgid "mrWidget|Pipeline blocked. The pipeline for this merge request requires a manual action to proceed"
msgstr ""
@@ -29905,49 +30877,49 @@ msgid "mrWidget|Ready to be merged automatically. Ask someone with write access
msgstr ""
msgid "mrWidget|Refresh"
-msgstr ""
+msgstr "Oppdater"
msgid "mrWidget|Refresh now"
-msgstr ""
+msgstr "Oppdater nå"
msgid "mrWidget|Refreshing now"
-msgstr ""
+msgstr "Oppdaterer nå"
msgid "mrWidget|Remove from merge train"
msgstr ""
msgid "mrWidget|Request to merge"
-msgstr ""
+msgstr "Fletteforespørsel"
msgid "mrWidget|Resolve all threads in new issue"
msgstr ""
msgid "mrWidget|Resolve conflicts"
-msgstr ""
+msgstr "Oppklar konflikter"
msgid "mrWidget|Resolve these conflicts or ask someone with write access to this repository to merge it locally"
msgstr ""
msgid "mrWidget|Revert"
-msgstr ""
+msgstr "Tilbakestill"
msgid "mrWidget|Revert this merge request in a new merge request"
msgstr ""
msgid "mrWidget|Revoke approval"
-msgstr ""
+msgstr "Trekk tilbake godkjennelse"
msgid "mrWidget|Set by"
msgstr ""
msgid "mrWidget|The changes were merged into"
-msgstr ""
+msgstr "Endringene ble flettet inn i"
msgid "mrWidget|The changes were not merged into"
-msgstr ""
+msgstr "Endringene ble ikke flettet inn i"
msgid "mrWidget|The changes will be merged into"
-msgstr ""
+msgstr "Endringene vil bli flettet inn i"
msgid "mrWidget|The pipeline for this merge request failed. Please retry the job or push a new commit to fix the failure"
msgstr ""
@@ -29956,22 +30928,22 @@ msgid "mrWidget|The source branch HEAD has recently changed. Please reload the p
msgstr ""
msgid "mrWidget|The source branch has been deleted"
-msgstr ""
+msgstr "Kildegrenen har blitt slettet"
msgid "mrWidget|The source branch is %{commitsBehindLinkStart}%{commitsBehind}%{commitsBehindLinkEnd} the target branch"
msgstr ""
msgid "mrWidget|The source branch is being deleted"
-msgstr ""
+msgstr "Kildegrenen ble slettet"
msgid "mrWidget|The source branch will be deleted"
-msgstr ""
+msgstr "Kildegrenen vil bli slettet"
msgid "mrWidget|The source branch will not be deleted"
-msgstr ""
+msgstr "Kildegrenen vil ikke bli slettet"
msgid "mrWidget|There are merge conflicts"
-msgstr ""
+msgstr "Det er flette konflikter"
msgid "mrWidget|This action will add the merge request to the merge train when pipeline %{pipelineLink} succeeds."
msgstr ""
@@ -29983,7 +30955,7 @@ msgid "mrWidget|This feature merges changes from the target branch to the source
msgstr ""
msgid "mrWidget|This merge request failed to be merged automatically"
-msgstr ""
+msgstr "Denne fletteforespørsel ble ikke flettet automatisk"
msgid "mrWidget|This merge request is in the process of being merged"
msgstr ""
@@ -29995,10 +30967,10 @@ msgid "mrWidget|To approve this merge request, please enter your password. This
msgstr ""
msgid "mrWidget|Use %{linkStart}CI pipelines to test your code%{linkEnd} by simply adding a GitLab CI configuration file to your project. It only takes a minute to make your code more secure and robust."
-msgstr ""
+msgstr "Bruk %{linkStart}CI-rørledninger til å teste koden%{linkEnd} ved å legge til en GitLab CI-konfigurasjonsfil i prosjektet ditt. Det tar bare et minutt å gjøre koden din mer sikker og robust."
msgid "mrWidget|You are not allowed to edit this project directly. Please fork to make changes."
-msgstr ""
+msgstr "Du har ikke tillatelse til å redigere dette prosjektet direkte. Vennligst utgrein for å utføre endringer."
msgid "mrWidget|You can delete the source branch now"
msgstr ""
@@ -30010,16 +30982,16 @@ msgid "mrWidget|You can merge this merge request manually using the"
msgstr ""
msgid "mrWidget|Your password"
-msgstr ""
+msgstr "Passordet ditt"
msgid "mrWidget|branch does not exist."
-msgstr ""
+msgstr "grenen eksisterer ikke."
msgid "mrWidget|command line"
-msgstr ""
+msgstr "kommandolinje"
msgid "mrWidget|into"
-msgstr ""
+msgstr "inni"
msgid "mrWidget|to be added to the merge train when the pipeline succeeds"
msgstr ""
@@ -30033,9 +31005,12 @@ msgstr ""
msgid "must be a root namespace"
msgstr ""
-msgid "must be greater than start date"
+msgid "must be a valid IPv4 or IPv6 address"
msgstr ""
+msgid "must be greater than start date"
+msgstr "må være høyere enn startdatoen"
+
msgid "must contain only valid frameworks"
msgstr ""
@@ -30043,73 +31018,76 @@ msgid "my-awesome-group"
msgstr ""
msgid "n/a"
-msgstr ""
+msgstr "(ingen)"
msgid "need attention"
-msgstr ""
+msgstr "trenger oppmerksomhet"
msgid "needs to be between 10 minutes and 1 month"
-msgstr ""
+msgstr "må være mellom 10 minutter og 1 måned"
msgid "never"
-msgstr ""
+msgstr "aldri"
msgid "never expires"
-msgstr ""
+msgstr "utløper aldri"
msgid "new merge request"
-msgstr ""
+msgstr "ny fletteforespørsel"
msgid "no approvers"
-msgstr ""
+msgstr "ingen godkjennere"
msgid "no contributions"
-msgstr ""
+msgstr "ingen bidrag"
msgid "no expiration"
+msgstr "ingen utløpsdato"
+
+msgid "no name set"
msgstr ""
msgid "no one can merge"
msgstr ""
msgid "none"
-msgstr ""
+msgstr "ingen"
msgid "not found"
-msgstr ""
+msgstr "ikke funnet"
msgid "notification emails"
-msgstr ""
+msgstr "E-postvarslinger"
msgid "nounSeries|%{firstItem} and %{lastItem}"
-msgstr ""
+msgstr "%{firstItem} og %{lastItem}"
msgid "nounSeries|%{item}"
-msgstr ""
+msgstr "%{item}"
msgid "nounSeries|%{item}, %{nextItem}"
-msgstr ""
+msgstr "%{item}, %{nextItem}"
msgid "nounSeries|%{item}, and %{lastItem}"
-msgstr ""
+msgstr "%{item}, og %{lastItem}"
msgid "on track"
-msgstr ""
+msgstr "på sporet"
msgid "open issue"
-msgstr ""
+msgstr "Ã¥pen sak"
msgid "opened %{timeAgoString} by %{user}"
-msgstr ""
+msgstr "Ã¥pnet %{timeAgoString} av %{user}"
msgid "opened %{timeAgoString} by %{user} in Jira"
-msgstr ""
+msgstr "Ã¥pnet %{timeAgoString} av %{user} i Jira"
msgid "opened %{timeAgo}"
-msgstr ""
+msgstr "Ã¥pnet %{timeAgo}"
msgid "or"
-msgstr ""
+msgstr "eller"
msgid "out of %d total test"
msgid_plural "out of %d total tests"
@@ -30118,32 +31096,32 @@ msgstr[1] ""
msgid "parent"
msgid_plural "parents"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "overkategori"
+msgstr[1] "overkategorier"
msgid "password"
-msgstr ""
+msgstr "passord"
msgid "paused"
-msgstr ""
+msgstr "på pause"
msgid "pending comment"
-msgstr ""
+msgstr "avventende kommentar"
msgid "pending removal"
-msgstr ""
+msgstr "avventende fjerning"
msgid "per day"
-msgstr ""
+msgstr "per dag"
msgid "personal access token"
msgstr ""
msgid "personal access tokens"
-msgstr ""
+msgstr "sjetonger for personlig tilgang"
msgid "pipeline"
-msgstr ""
+msgstr "rørledning"
msgid "pod_name can contain only lowercase letters, digits, '-', and '.' and must start and end with an alphanumeric character"
msgstr ""
@@ -30153,22 +31131,22 @@ msgstr ""
msgid "point"
msgid_plural "points"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "punkt"
+msgstr[1] "punkter"
msgid "private"
-msgstr ""
+msgstr "privat"
msgid "private key does not match certificate."
msgstr ""
msgid "processing"
-msgstr ""
+msgstr "Behandler"
msgid "project"
msgid_plural "projects"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "prosjekt"
+msgstr[1] "prosjekter"
msgid "project access token"
msgstr ""
@@ -30177,7 +31155,7 @@ msgid "project access tokens"
msgstr ""
msgid "project avatar"
-msgstr ""
+msgstr "prosjektavatar"
msgid "project bots cannot be added to other groups / projects"
msgstr ""
@@ -30186,40 +31164,40 @@ msgid "project is read-only"
msgstr ""
msgid "project members"
-msgstr ""
+msgstr "prosjektmedlemmer"
msgid "projects"
-msgstr ""
+msgstr "prosjekter"
msgid "push to your repository, create pipelines, create issues or add comments. To reduce storage capacity, delete unused repositories, artifacts, wikis, issues, and pipelines."
msgstr ""
msgid "quick actions"
-msgstr ""
+msgstr "hurtighandlinger"
msgid "recent activity"
-msgstr ""
+msgstr "nylig aktivitet"
msgid "register"
-msgstr ""
+msgstr "registrer"
msgid "relates to"
-msgstr ""
+msgstr "relatert til"
msgid "released %{time}"
-msgstr ""
+msgstr "utgitt %{time}"
msgid "remaining"
-msgstr ""
+msgstr "gjenstår"
msgid "remove"
-msgstr ""
+msgstr "fjern"
msgid "remove due date"
-msgstr ""
+msgstr "fjern forfallsdato"
msgid "remove weight"
-msgstr ""
+msgstr "fjern vekt"
msgid "removed a Zoom call from this issue"
msgstr ""
@@ -30229,47 +31207,44 @@ msgstr ""
msgid "reply"
msgid_plural "replies"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "svar"
+msgstr[1] "svar"
msgid "repository:"
-msgstr ""
+msgstr "kodelager:"
msgid "reset it."
-msgstr ""
+msgstr "tilbakestille den."
msgid "revised"
-msgstr ""
+msgstr "revidert"
msgid "satisfied"
-msgstr ""
+msgstr "tilfredsstilt"
msgid "security Reports|There was an error creating the merge request"
msgstr ""
-msgid "settings saved, but not activated"
-msgstr ""
-
msgid "severity|Critical"
-msgstr ""
+msgstr "Kritisk"
msgid "severity|High"
-msgstr ""
+msgstr "Høy"
msgid "severity|Info"
-msgstr ""
+msgstr "Info"
msgid "severity|Low"
-msgstr ""
+msgstr "Lav"
msgid "severity|Medium"
-msgstr ""
+msgstr "Medium"
msgid "severity|None"
-msgstr ""
+msgstr "Ingen"
msgid "severity|Unknown"
-msgstr ""
+msgstr "Ukjent"
msgid "should be an array of %{object_name} objects"
msgstr ""
@@ -30278,28 +31253,28 @@ msgid "should be greater than or equal to %{access} inherited membership from gr
msgstr ""
msgid "show %{count} more"
-msgstr ""
+msgstr "vis %{count} til"
msgid "show fewer"
-msgstr ""
+msgstr "vis færre"
msgid "show less"
-msgstr ""
+msgstr "vis mindre"
msgid "sign in"
-msgstr ""
+msgstr "logg inn"
msgid "sort:"
-msgstr ""
+msgstr "sorter:"
msgid "source"
-msgstr ""
+msgstr "kilde"
msgid "source diff"
-msgstr ""
+msgstr "kilde-diff"
msgid "specific"
-msgstr ""
+msgstr "spesifikk"
msgid "specified top is not part of the tree"
msgstr ""
@@ -30308,25 +31283,25 @@ msgid "spendCommand|%{slash_command} will update the sum of the time spent."
msgstr ""
msgid "ssh:"
-msgstr ""
+msgstr "ssh:"
msgid "started"
-msgstr ""
+msgstr "startet"
msgid "started a discussion on %{design_link}"
-msgstr ""
+msgstr "startet en diskusjon på %{design_link}"
msgid "started on %{timebox_start_date}"
msgstr ""
msgid "starts on %{timebox_start_date}"
-msgstr ""
+msgstr "starter den %{timebox_start_date}"
msgid "stuck"
-msgstr ""
+msgstr "fastklemt"
msgid "success"
-msgstr ""
+msgstr "vellykket"
msgid "suggestPipeline|1/2: Choose a template"
msgstr ""
@@ -30341,25 +31316,25 @@ msgid "suggestPipeline|The template is ready! You can now commit it to create yo
msgstr ""
msgid "suggestPipeline|We’re adding a GitLab CI configuration file to add a pipeline to the project. You could create it manually, but we recommend that you start with a GitLab template that works out of the box."
-msgstr ""
+msgstr "Vi legger til en GitLab CI-konfigurasjonsfil for å legge til en rørledning i prosjektet. Du kan opprette det manuelt, men vi anbefaler at du starter med en GitLab-mal som fungerer rett ut av boksen."
msgid "syntax is correct"
-msgstr ""
+msgstr "syntaksen er riktig"
msgid "syntax is incorrect"
-msgstr ""
+msgstr "syntaksen er feil"
msgid "tag name"
-msgstr ""
+msgstr "etikettnavn"
msgid "teammate%{number}@company.com"
msgstr ""
msgid "the following issue(s)"
-msgstr ""
+msgstr "de(n) følgende sak(en)"
msgid "this document"
-msgstr ""
+msgstr "dette dokumentet"
msgid "time summary"
msgstr ""
@@ -30371,16 +31346,13 @@ msgid "to join %{source_name}"
msgstr ""
msgid "to list"
-msgstr ""
+msgstr "Ã¥ liste opp"
msgid "toggle collapse"
msgstr ""
-msgid "toggle dropdown"
-msgstr ""
-
msgid "triggered"
-msgstr ""
+msgstr "utløst"
msgid "two-factor authentication settings"
msgstr ""
@@ -30389,61 +31361,64 @@ msgid "unicode domains should use IDNA encoding"
msgstr ""
msgid "updated"
-msgstr ""
+msgstr "oppdatert"
msgid "updated %{timeAgo}"
-msgstr ""
+msgstr "oppdatert %{timeAgo}"
msgid "updated %{time_ago}"
-msgstr ""
+msgstr "oppdatert %{time_ago}"
msgid "uploaded"
msgstr ""
msgid "uploads"
-msgstr ""
+msgstr "opplastinger"
msgid "user avatar"
+msgstr "brukerens profilbilde"
+
+msgid "user preferences"
msgstr ""
msgid "username"
-msgstr ""
+msgstr "brukernavn"
msgid "uses Kubernetes clusters to deploy your code!"
-msgstr ""
+msgstr "bruker Kubernetes-klynger for å distribuere koden din!"
msgid "v%{version} published %{timeAgo}"
-msgstr ""
+msgstr "v%{version} publisert %{timeAgo}"
msgid "verify ownership"
-msgstr ""
+msgstr "verifiser eierskap"
msgid "version %{versionIndex}"
-msgstr ""
+msgstr "versjon %{versionIndex}"
msgid "via %{closed_via}"
-msgstr ""
+msgstr "via %{closed_via}"
msgid "via merge request %{link}"
msgstr ""
msgid "view it on GitLab"
-msgstr ""
+msgstr "vis den på GitLab"
msgid "view the blob"
-msgstr ""
+msgstr "vis blobben"
msgid "view the source"
-msgstr ""
+msgstr "vis kilden"
msgid "vulnerability|Add a comment"
-msgstr ""
+msgstr "Legg til en kommentar"
msgid "vulnerability|Add a comment or reason for dismissal"
msgstr ""
msgid "vulnerability|Add comment"
-msgstr ""
+msgstr "Legg til kommentar"
msgid "vulnerability|Add comment & dismiss"
msgstr ""
@@ -30455,25 +31430,25 @@ msgid "vulnerability|Dismiss vulnerability"
msgstr ""
msgid "vulnerability|Save comment"
-msgstr ""
+msgstr "Lagre kommentar"
msgid "vulnerability|Undo dismiss"
msgstr ""
msgid "vulnerability|dismissed"
-msgstr ""
+msgstr "avfeid"
msgid "was scheduled to merge after pipeline succeeds by"
msgstr ""
msgid "wiki page"
-msgstr ""
+msgstr "wikiside"
msgid "will be released %{time}"
-msgstr ""
+msgstr "vil bli utgitt %{time}"
msgid "with %{additions} additions, %{deletions} deletions."
-msgstr ""
+msgstr "med %{additions} tillegg, %{deletions} slettinger."
msgid "with expiry changing from %{old_expiry} to %{new_expiry}"
msgstr ""
@@ -30482,5 +31457,5 @@ msgid "with expiry remaining unchanged at %{old_expiry}"
msgstr ""
msgid "yaml invalid"
-msgstr ""
+msgstr "yaml er ugyldig"
diff --git a/locale/nl_NL/gitlab.po b/locale/nl_NL/gitlab.po
index ba62f59ad16..838ca2c1c37 100644
--- a/locale/nl_NL/gitlab.po
+++ b/locale/nl_NL/gitlab.po
@@ -14,7 +14,10 @@ msgstr ""
"X-Crowdin-Language: nl\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 6\n"
-"PO-Revision-Date: 2020-09-04 23:09\n"
+"PO-Revision-Date: 2020-10-02 18:48\n"
+
+msgid " %{project_name}#%{issue_iid} &middot; opened %{issue_created} by %{author}"
+msgstr ""
msgid " %{start} to %{end}"
msgstr ""
@@ -74,6 +77,16 @@ msgstr ""
msgid "\"el\" parameter is required for createInstance()"
msgstr ""
+msgid "%d Approval"
+msgid_plural "%d Approvals"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d Package"
+msgid_plural "%d Packages"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d Scanned URL"
msgid_plural "%d Scanned URLs"
msgstr[0] ""
@@ -137,6 +150,11 @@ msgstr[1] ""
msgid "%d commits"
msgstr ""
+msgid "%d completed issue"
+msgid_plural "%d completed issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d contribution"
msgid_plural "%d contributions"
msgstr[0] ""
@@ -147,6 +165,11 @@ msgid_plural "%d days"
msgstr[0] ""
msgstr[1] ""
+msgid "%d day until tags are automatically removed"
+msgid_plural "%d days until tags are automatically removed"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d error"
msgid_plural "%d errors"
msgstr[0] ""
@@ -237,6 +260,16 @@ msgid_plural "%d more comments"
msgstr[0] ""
msgstr[1] ""
+msgid "%d open issue"
+msgid_plural "%d open issues"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d pending comment"
+msgid_plural "%d pending comments"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d personal project will be removed and cannot be restored."
msgid_plural "%d personal projects will be removed and cannot be restored."
msgstr[0] ""
@@ -252,6 +285,11 @@ msgid_plural "%d projects"
msgstr[0] ""
msgstr[1] ""
+msgid "%d project selected"
+msgid_plural "%d projects selected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d request with warnings"
msgid_plural "%d requests with warnings"
msgstr[0] ""
@@ -272,6 +310,11 @@ msgid_plural "%d tags"
msgstr[0] ""
msgstr[1] ""
+msgid "%d tag per image name"
+msgid_plural "%d tags per image name"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d unassigned issue"
msgid_plural "%d unassigned issues"
msgstr[0] ""
@@ -292,6 +335,11 @@ msgid_plural "%d vulnerabilities dismissed"
msgstr[0] ""
msgstr[1] ""
+msgid "%d warning found:"
+msgid_plural "%d warnings found:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%s additional commit has been omitted to prevent performance issues."
msgid_plural "%s additional commits have been omitted to prevent performance issues."
msgstr[0] "%s andere commit is weggelaten om prestatieproblemen te voorkomen."
@@ -330,6 +378,9 @@ msgstr ""
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr "%{commit_author_link} schreef %{commit_timeago}"
+msgid "%{completedCount} completed weight"
+msgstr ""
+
msgid "%{completedWeight} of %{totalWeight} weight completed"
msgstr ""
@@ -378,14 +429,12 @@ msgid_plural "%{count} participants"
msgstr[0] "%{count} deelnemer"
msgstr[1] "%{count} deelnemers"
-msgid "%{count} pending comment"
-msgid_plural "%{count} pending comments"
-msgstr[0] "%{count} openstaande reactie"
-msgstr[1] "%{count} openstaande reacties"
-
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
+msgid "%{count} total weight"
+msgstr ""
+
msgid "%{dashboard_path} could not be found."
msgstr ""
@@ -440,6 +489,9 @@ msgstr ""
msgid "%{group_name} uses group managed accounts. You need to create a new GitLab account which will be managed by %{group_name}."
msgstr ""
+msgid "%{group_name}&%{epic_iid} &middot; opened %{epic_created} by %{author}"
+msgstr ""
+
msgid "%{host} sign-in from new location"
msgstr ""
@@ -452,7 +504,7 @@ msgstr ""
msgid "%{issuableType} will be removed! Are you sure?"
msgstr "%{issuableType} wordt verwijderd! Weet je het zeker?"
-msgid "%{issuesSize} issues with a limit of %{maxIssueCount}"
+msgid "%{issuesCount} issues with a limit of %{maxIssueCount}"
msgstr ""
msgid "%{issuesSize} with a limit of %{maxIssueCount}"
@@ -485,7 +537,7 @@ msgstr ""
msgid "%{labelStart}Namespace:%{labelEnd} %{namespace}"
msgstr ""
-msgid "%{labelStart}Report Type:%{labelEnd} %{reportType}"
+msgid "%{labelStart}Scan Type:%{labelEnd} %{reportType}"
msgstr ""
msgid "%{labelStart}Scanner:%{labelEnd} %{scanner}"
@@ -682,9 +734,6 @@ msgid_plural "%{securityScanner} results are not available because a pipeline ha
msgstr[0] ""
msgstr[1] ""
-msgid "%{service_title} %{message}."
-msgstr ""
-
msgid "%{size} GiB"
msgstr ""
@@ -773,6 +822,12 @@ msgstr "%{text} is beschikbaar"
msgid "%{timebox_name} should belong either to a project or a group."
msgstr ""
+msgid "%{timebox_type} does not support burnup charts"
+msgstr ""
+
+msgid "%{timebox_type} must have a start and due date"
+msgstr ""
+
msgid "%{title} %{operator} %{threshold}"
msgstr ""
@@ -797,7 +852,7 @@ msgstr ""
msgid "%{total} open issue weight"
msgstr ""
-msgid "%{total} open issues"
+msgid "%{total} warnings found: showing first %{warningsDisplayed}"
msgstr ""
msgid "%{usage_ping_link_start}Learn more%{usage_ping_link_end} about what information is shared with GitLab Inc."
@@ -830,9 +885,6 @@ msgstr ""
msgid "&lt; 1 hour"
msgstr ""
-msgid "&lt;no name set&gt;"
-msgstr ""
-
msgid "&lt;no scopes selected&gt;"
msgstr ""
@@ -863,6 +915,9 @@ msgstr ""
msgid "'%{name}' Value Stream created"
msgstr ""
+msgid "'%{name}' Value Stream deleted"
+msgstr ""
+
msgid "'%{name}' stage already exists"
msgstr ""
@@ -922,6 +977,9 @@ msgstr "+ %{moreCount} meer"
msgid "+ %{numberOfHiddenAssignees} more"
msgstr ""
+msgid "+ %{numberOfHiddenReviewers} more"
+msgstr ""
+
msgid "+%d more"
msgid_plural "+%d more"
msgstr[0] ""
@@ -982,6 +1040,11 @@ msgid_plural "%d Days"
msgstr[0] ""
msgstr[1] ""
+msgid "1 Issue"
+msgid_plural "%d Issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "1 closed issue"
msgid_plural "%{issues} closed issues"
msgstr[0] "1 gesloten issue"
@@ -997,6 +1060,11 @@ msgid_plural "%d days"
msgstr[0] ""
msgstr[1] ""
+msgid "1 deploy key"
+msgid_plural "%d deploy keys"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] "1 groep"
@@ -1099,6 +1167,9 @@ msgstr ""
msgid ":%{startLine} to %{endLine}"
msgstr ""
+msgid "A %{incident_docs_start}modified issue%{incident_docs_end} to guide the resolution of incidents."
+msgstr ""
+
msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr ""
@@ -1111,6 +1182,9 @@ msgstr ""
msgid "A GitBook site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
+msgid "A Gitpod configured Webapplication in Spring and Java"
+msgstr ""
+
msgid "A Hexo site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
@@ -1282,9 +1356,15 @@ msgstr ""
msgid "Access expiration date"
msgstr ""
+msgid "Access expires"
+msgstr ""
+
msgid "Access forbidden. Check your access level."
msgstr ""
+msgid "Access granted"
+msgstr ""
+
msgid "Access requests"
msgstr ""
@@ -1294,6 +1374,9 @@ msgstr ""
msgid "Access to Pages websites are controlled based on the user's membership to a given project. By checking this box, users will be required to be logged in to have access to all Pages websites in your instance."
msgstr ""
+msgid "AccessDropdown|Deploy Keys"
+msgstr ""
+
msgid "AccessDropdown|Groups"
msgstr ""
@@ -1411,12 +1494,6 @@ msgstr ""
msgid "Active Sessions"
msgstr ""
-msgid "Active Users:"
-msgstr ""
-
-msgid "Active users"
-msgstr ""
-
msgid "Activity"
msgstr "Activiteit"
@@ -1584,9 +1661,6 @@ msgstr ""
msgid "Add label(s)"
msgstr ""
-msgid "Add license"
-msgstr ""
-
msgid "Add list"
msgstr ""
@@ -1761,21 +1835,51 @@ msgstr ""
msgid "AdminArea|Bots"
msgstr ""
+msgid "AdminArea|Components"
+msgstr ""
+
msgid "AdminArea|Developer"
msgstr ""
+msgid "AdminArea|Features"
+msgstr ""
+
+msgid "AdminArea|Groups: %{number_of_groups}"
+msgstr ""
+
msgid "AdminArea|Guest"
msgstr ""
msgid "AdminArea|Included Free in license"
msgstr ""
+msgid "AdminArea|Latest groups"
+msgstr ""
+
+msgid "AdminArea|Latest projects"
+msgstr ""
+
+msgid "AdminArea|Latest users"
+msgstr ""
+
msgid "AdminArea|Maintainer"
msgstr ""
+msgid "AdminArea|New group"
+msgstr ""
+
+msgid "AdminArea|New project"
+msgstr ""
+
+msgid "AdminArea|New user"
+msgstr ""
+
msgid "AdminArea|Owner"
msgstr ""
+msgid "AdminArea|Projects: %{number_of_projects}"
+msgstr ""
+
msgid "AdminArea|Reporter"
msgstr ""
@@ -1803,6 +1907,9 @@ msgstr ""
msgid "AdminArea|Users without a Group and Project"
msgstr ""
+msgid "AdminArea|Users: %{number_of_users}"
+msgstr ""
+
msgid "AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running."
msgstr ""
@@ -1821,9 +1928,6 @@ msgstr ""
msgid "AdminProjects|Delete Project %{projectName}?"
msgstr ""
-msgid "AdminProjects|Delete project"
-msgstr ""
-
msgid "AdminSettings|Apply integration settings to all Projects"
msgstr ""
@@ -2061,21 +2165,30 @@ msgstr ""
msgid "AdminUsers|Without projects"
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 ""
msgid "AdminUsers|You cannot remove your own admin rights."
msgstr ""
+msgid "AdminUsers|You must transfer ownership or delete the groups owned by this user before you can delete their account"
+msgstr ""
+
msgid "Administration"
msgstr ""
msgid "Advanced"
msgstr ""
+msgid "Advanced Search"
+msgstr ""
+
+msgid "Advanced Search with Elasticsearch"
+msgstr ""
+
msgid "Advanced Settings"
msgstr ""
@@ -2153,6 +2266,9 @@ msgstr ""
msgid "AlertManagement|Edit"
msgstr ""
+msgid "AlertManagement|Environment"
+msgstr ""
+
msgid "AlertManagement|Events"
msgstr ""
@@ -2165,6 +2281,9 @@ msgstr ""
msgid "AlertManagement|Issue"
msgstr ""
+msgid "AlertManagement|Key"
+msgstr ""
+
msgid "AlertManagement|Low"
msgstr ""
@@ -2258,6 +2377,9 @@ msgstr ""
msgid "AlertManagement|Unknown"
msgstr ""
+msgid "AlertManagement|Value"
+msgstr ""
+
msgid "AlertManagement|View alerts in Opsgenie"
msgstr ""
@@ -2417,6 +2539,9 @@ msgstr ""
msgid "All projects"
msgstr ""
+msgid "All projects selected"
+msgstr ""
+
msgid "All security scans are enabled because %{linkStart}Auto DevOps%{linkEnd} is enabled on this project"
msgstr ""
@@ -2504,6 +2629,9 @@ msgstr ""
msgid "Almost there"
msgstr ""
+msgid "Already blocked"
+msgstr ""
+
msgid "Also called \"Issuer\" or \"Relying party trust identifier\""
msgstr ""
@@ -2558,6 +2686,9 @@ msgstr ""
msgid "An error has occurred"
msgstr ""
+msgid "An error occured while making the changes: %{error}"
+msgstr ""
+
msgid "An error occurred adding a draft to the thread."
msgstr ""
@@ -2585,12 +2716,6 @@ msgstr ""
msgid "An error occurred when toggling the notification subscription"
msgstr ""
-msgid "An error occurred when trying to resolve a comment. Please try again."
-msgstr ""
-
-msgid "An error occurred when trying to resolve a discussion. Please try again."
-msgstr ""
-
msgid "An error occurred when updating the issue weight"
msgstr ""
@@ -2606,12 +2731,6 @@ msgstr ""
msgid "An error occurred while checking group path. Please refresh and try again."
msgstr ""
-msgid "An error occurred while committing your changes."
-msgstr ""
-
-msgid "An error occurred while creating the list. Please try again."
-msgstr ""
-
msgid "An error occurred while decoding the file."
msgstr ""
@@ -2684,25 +2803,19 @@ msgstr ""
msgid "An error occurred while fetching the Service Desk address."
msgstr ""
-msgid "An error occurred while fetching the board issues. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the board lists. Please reload the page."
msgstr ""
msgid "An error occurred while fetching the board lists. Please try again."
msgstr ""
-msgid "An error occurred while fetching the board swimlanes. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the builds."
msgstr ""
msgid "An error occurred while fetching the job log."
msgstr ""
-msgid "An error occurred while fetching the job trace."
+msgid "An error occurred while fetching the job logs."
msgstr ""
msgid "An error occurred while fetching the job."
@@ -2849,9 +2962,6 @@ msgstr ""
msgid "An error occurred while saving assignees"
msgstr ""
-msgid "An error occurred while saving the template. Please check if the template exists."
-msgstr ""
-
msgid "An error occurred while searching for milestones"
msgstr ""
@@ -2870,10 +2980,10 @@ msgstr ""
msgid "An error occurred while updating approvers"
msgstr ""
-msgid "An error occurred while updating the comment"
+msgid "An error occurred while updating labels."
msgstr ""
-msgid "An error occurred while updating the list. Please try again."
+msgid "An error occurred while updating the comment"
msgstr ""
msgid "An error occurred while validating group path"
@@ -2927,6 +3037,9 @@ msgstr ""
msgid "An unknown error occurred while loading this graph."
msgstr ""
+msgid "An unknown error occurred."
+msgstr ""
+
msgid "Analytics"
msgstr ""
@@ -2960,10 +3073,10 @@ msgstr ""
msgid "Any"
msgstr ""
-msgid "Any Author"
+msgid "Any %{header}"
msgstr ""
-msgid "Any Status"
+msgid "Any Author"
msgstr ""
msgid "Any branch"
@@ -3017,6 +3130,9 @@ msgstr "Applicatie"
msgid "Application ID"
msgstr ""
+msgid "Application limits saved successfully"
+msgstr ""
+
msgid "Application settings saved successfully"
msgstr ""
@@ -3226,6 +3342,9 @@ msgstr ""
msgid "Are you sure you want to close this blocked issue?"
msgstr ""
+msgid "Are you sure you want to delete \"%{name}\" Value Stream?"
+msgstr ""
+
msgid "Are you sure you want to delete %{name}?"
msgstr ""
@@ -3235,6 +3354,9 @@ msgstr ""
msgid "Are you sure you want to delete this %{typeOfComment}?"
msgstr ""
+msgid "Are you sure you want to delete this SSH key?"
+msgstr ""
+
msgid "Are you sure you want to delete this board?"
msgstr ""
@@ -3259,6 +3381,11 @@ msgstr ""
msgid "Are you sure you want to erase this build?"
msgstr ""
+msgid "Are you sure you want to import %d repository?"
+msgid_plural "Are you sure you want to import %d repositories?"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Are you sure you want to lose unsaved changes?"
msgstr ""
@@ -3268,15 +3395,15 @@ msgstr ""
msgid "Are you sure you want to merge immediately?"
msgstr ""
-msgid "Are you sure you want to permanently delete this license?"
-msgstr ""
-
msgid "Are you sure you want to re-deploy this environment?"
msgstr ""
msgid "Are you sure you want to regenerate the public key? You will have to update the public key on the remote server before mirroring will work again."
msgstr ""
+msgid "Are you sure you want to reindex?"
+msgstr ""
+
msgid "Are you sure you want to remove %{group_name}?"
msgstr ""
@@ -3304,6 +3431,9 @@ msgstr ""
msgid "Are you sure you want to revoke this nickname?"
msgstr ""
+msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
+msgstr ""
+
msgid "Are you sure you want to stop this environment?"
msgstr ""
@@ -3325,6 +3455,9 @@ msgstr ""
msgid "Are you sure? The device will be signed out of GitLab and all remember me tokens revoked."
msgstr ""
+msgid "Are you sure? This will invalidate your registered applications and U2F / WebAuthn devices."
+msgstr ""
+
msgid "Are you sure? This will invalidate your registered applications and U2F devices."
msgstr ""
@@ -3343,9 +3476,6 @@ msgstr ""
msgid "Artifacts"
msgstr ""
-msgid "As U2F devices are only supported by a few browsers, we require that you set up a two-factor authentication app before a U2F device. That way you'll always be able to log in - even when you're using an unsupported browser."
-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 ""
@@ -3539,6 +3669,9 @@ msgstr ""
msgid "AuditLogs|Target"
msgstr ""
+msgid "AuditLogs|This month"
+msgstr ""
+
msgid "AuditLogs|User Events"
msgstr ""
@@ -3578,6 +3711,9 @@ msgstr ""
msgid "Authentication via U2F device failed."
msgstr ""
+msgid "Authentication via WebAuthn device failed."
+msgstr ""
+
msgid "Author"
msgstr "Auteur"
@@ -3845,15 +3981,6 @@ msgstr ""
msgid "BambooService|You must set up automatic revision labeling and a repository trigger in Bamboo."
msgstr ""
-msgid "BatchComments|Delete all pending comments"
-msgstr ""
-
-msgid "BatchComments|Discard review?"
-msgstr ""
-
-msgid "BatchComments|You're about to discard your review which will delete all of your pending comments. The deleted comments %{strong_start}cannot%{strong_end} be restored."
-msgstr ""
-
msgid "Be careful. Changing the project's namespace can have unintended side effects."
msgstr ""
@@ -3875,6 +4002,9 @@ msgstr ""
msgid "Bi-weekly code coverage"
msgstr ""
+msgid "Billable Users:"
+msgstr ""
+
msgid "Billing"
msgstr ""
@@ -3884,7 +4014,7 @@ msgstr ""
msgid "BillingPlans|@%{user_name} you are currently using the %{plan_name} plan."
msgstr ""
-msgid "BillingPlans|Congratulations, your new trial is activated"
+msgid "BillingPlans|Congratulations, your free trial is activated."
msgstr ""
msgid "BillingPlans|If you would like to downgrade your plan please contact %{support_link_start}Customer Support%{support_link_end}."
@@ -3947,6 +4077,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Block user"
+msgstr ""
+
msgid "Blocked"
msgstr ""
@@ -3962,31 +4095,37 @@ msgstr ""
msgid "Blog"
msgstr ""
-msgid "Board name"
-msgstr ""
-
msgid "Board scope"
msgstr ""
msgid "Board scope affects which issues are displayed for anyone who visits this board"
msgstr ""
-msgid "BoardBlankState|Add default lists"
+msgid "Boards"
msgstr ""
-msgid "BoardBlankState|Add the following default lists to your Issue Board with one click:"
+msgid "Boards and Board Lists"
msgstr ""
-msgid "BoardBlankState|Nevermind, I'll use my own"
+msgid "Boards|An error occurred while creating the issue. Please try again."
msgstr ""
-msgid "BoardBlankState|Starting out with the default set of lists will get you right on the way to making the most of your board."
+msgid "Boards|An error occurred while creating the list. Please try again."
msgstr ""
-msgid "Boards"
+msgid "Boards|An error occurred while fetching issues. Please reload the page."
msgstr ""
-msgid "Boards and Board Lists"
+msgid "Boards|An error occurred while fetching the board issues. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching the board swimlanes. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while moving the issue. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while updating the list. Please try again."
msgstr ""
msgid "Boards|Collapse"
@@ -4013,7 +4152,7 @@ msgstr ""
msgid "Branch %{branch_name} was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr ""
-msgid "Branch has changed"
+msgid "Branch changed"
msgstr ""
msgid "Branch is already taken"
@@ -4319,6 +4458,9 @@ msgstr ""
msgid "CLOSED (MOVED)"
msgstr ""
+msgid "CODEOWNERS rule violation"
+msgstr ""
+
msgid "CONTRIBUTING"
msgstr ""
@@ -4349,9 +4491,6 @@ msgstr ""
msgid "Can't create snippet: %{err}"
msgstr ""
-msgid "Can't edit as source branch was deleted"
-msgstr ""
-
msgid "Can't fetch content for the blob: %{err}"
msgstr ""
@@ -4364,9 +4503,6 @@ msgstr ""
msgid "Can't load mermaid module: %{err}"
msgstr ""
-msgid "Can't remove group members without group managed account"
-msgstr ""
-
msgid "Can't scan the code?"
msgstr ""
@@ -4409,6 +4545,9 @@ msgstr ""
msgid "Cannot create the abuse report. This user has been blocked."
msgstr ""
+msgid "Cannot enable shared runners because parent group does not allow it"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -4514,6 +4653,15 @@ msgstr ""
msgid "Change your password or recover your current one"
msgstr ""
+msgid "ChangeReviewer|Reviewer changed from %{old} to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Reviewer changed to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Unassigned"
+msgstr ""
+
msgid "ChangeTypeActionLabel|Pick into branch"
msgstr ""
@@ -4553,6 +4701,9 @@ msgstr ""
msgid "Changes the title to \"%{title_param}\"."
msgstr ""
+msgid "Changes were successfully made."
+msgstr ""
+
msgid "Changes won't take place until the index is %{link_start}recreated%{link_end}."
msgstr ""
@@ -4958,6 +5109,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove variable"
+msgstr ""
+
msgid "CiVariables|Remove variable row"
msgstr ""
@@ -5036,9 +5190,6 @@ msgstr ""
msgid "Clear due date"
msgstr ""
-msgid "Clear input"
-msgstr ""
-
msgid "Clear recent searches"
msgstr ""
@@ -5087,6 +5238,9 @@ msgstr ""
msgid "Client authentication key password"
msgstr ""
+msgid "Client request timeout"
+msgstr ""
+
msgid "Clients"
msgstr ""
@@ -5171,6 +5325,27 @@ msgstr ""
msgid "Cluster type must be specificed for Stages::ClusterEndpointInserter"
msgstr ""
+msgid "ClusterAgents|Configuration"
+msgstr ""
+
+msgid "ClusterAgents|Connect your cluster with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate Kubernetes with a GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Name"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Agent also requires %{linkStart}enabling the Agent Server%{linkEnd}"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Kubernetes Agent allows an Infrastructure as Code, GitOps approach to integrating Kubernetes clusters with GitLab. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "ClusterAgent|This feature is only available for premium plans"
msgstr ""
@@ -5240,10 +5415,10 @@ msgstr ""
msgid "ClusterIntegration|All installed applications and related resources"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster."
+msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{linkStart}More information%{linkEnd}"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{startLink}More information%{endLink}"
+msgid "ClusterIntegration|Allow GitLab to manage namespaces and service accounts for this cluster."
msgstr ""
msgid "ClusterIntegration|Alternatively, "
@@ -5264,6 +5439,9 @@ msgstr ""
msgid "ClusterIntegration|An error occurred while trying to fetch zone machine types: %{error}"
msgstr ""
+msgid "ClusterIntegration|An unknown error occurred while attempting to connect to Kubernetes."
+msgstr ""
+
msgid "ClusterIntegration|Any project namespaces"
msgstr ""
@@ -5279,6 +5457,9 @@ msgstr ""
msgid "ClusterIntegration|Authenticate with Amazon Web Services"
msgstr ""
+msgid "ClusterIntegration|Authentication Error"
+msgstr ""
+
msgid "ClusterIntegration|Base domain"
msgstr ""
@@ -5297,13 +5478,22 @@ msgstr ""
msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}security group %{externalLinkIcon} %{endLink} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
+msgid "ClusterIntegration|Check your CA certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Check your cluster status"
+msgstr ""
+
+msgid "ClusterIntegration|Check your token"
+msgstr ""
+
+msgid "ClusterIntegration|Choose the %{linkStart}security group %{linkEnd} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}subnets %{externalLinkIcon} %{endLink} in your VPC where your worker nodes will run."
+msgid "ClusterIntegration|Choose the %{linkStart}subnets %{linkEnd} in your VPC where your worker nodes will run."
msgstr ""
-msgid "ClusterIntegration|Choose the worker node %{startLink}instance type %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Choose the worker node %{linkStart}instance type%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Choose which applications to install on your Kubernetes cluster."
@@ -5315,10 +5505,7 @@ msgstr ""
msgid "ClusterIntegration|Clear cluster cache"
msgstr ""
-msgid "ClusterIntegration|Clear the local cache of namespace and service accounts. This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
-msgstr ""
-
-msgid "ClusterIntegration|Cluster being created"
+msgid "ClusterIntegration|Clear the local cache of namespace and service accounts."
msgstr ""
msgid "ClusterIntegration|Cluster management project (alpha)"
@@ -5330,15 +5517,21 @@ msgstr ""
msgid "ClusterIntegration|Cluster_applications artifact too big. Maximum allowable size: %{human_size}"
msgstr ""
-msgid "ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters."
+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|Clusters connected with a certificate"
msgstr ""
-msgid "ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters. %{linkStart}More information%{linkEnd}"
+msgid "ClusterIntegration|Connect cluster with certificate"
msgstr ""
msgid "ClusterIntegration|Connect existing cluster"
msgstr ""
+msgid "ClusterIntegration|Connection Error"
+msgstr ""
+
msgid "ClusterIntegration|Copy API URL"
msgstr ""
@@ -5414,6 +5607,12 @@ msgstr ""
msgid "ClusterIntegration|Deletes all GitLab resources attached to this cluster during removal"
msgstr ""
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared."
+msgstr ""
+
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared. %{linkStart}More information%{linkEnd}"
+msgstr ""
+
msgid "ClusterIntegration|Did you know?"
msgstr ""
@@ -5483,6 +5682,9 @@ msgstr ""
msgid "ClusterIntegration|Fluentd is an open source data collector, which lets you unify the data collection and consumption for a better use and understanding of data. It requires at least one of the following logs to be successfully installed."
msgstr ""
+msgid "ClusterIntegration|GitLab Agent managed clusters"
+msgstr ""
+
msgid "ClusterIntegration|GitLab Container Network Policies"
msgstr ""
@@ -5495,6 +5697,12 @@ msgstr ""
msgid "ClusterIntegration|GitLab Runner connects to the repository and executes CI/CD jobs, pushing results back and deploying applications to production."
msgstr ""
+msgid "ClusterIntegration|GitLab failed to authenticate."
+msgstr ""
+
+msgid "ClusterIntegration|GitLab failed to connect to the cluster."
+msgstr ""
+
msgid "ClusterIntegration|GitLab-managed cluster"
msgstr ""
@@ -5516,6 +5724,9 @@ msgstr ""
msgid "ClusterIntegration|Group cluster"
msgstr ""
+msgid "ClusterIntegration|HTTP Error"
+msgstr ""
+
msgid "ClusterIntegration|Helm Tiller"
msgstr ""
@@ -5549,7 +5760,10 @@ msgstr ""
msgid "ClusterIntegration|Instance type"
msgstr ""
-msgid "ClusterIntegration|Integrate Kubernetes cluster automation"
+msgid "ClusterIntegration|Integrate Kubernetes with a cluster certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Integrate with a cluster certificate"
msgstr ""
msgid "ClusterIntegration|Issuer Email"
@@ -5585,9 +5799,6 @@ msgstr ""
msgid "ClusterIntegration|Knative extends Kubernetes to provide a set of middleware components that are essential to build modern, source-centric, and container-based applications that can run anywhere: on premises, in the cloud, or even in a third-party data center."
msgstr ""
-msgid "ClusterIntegration|Kubernetes cluster"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes cluster is being created..."
msgstr ""
@@ -5600,9 +5811,6 @@ msgstr ""
msgid "ClusterIntegration|Kubernetes clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr ""
-msgid "ClusterIntegration|Kubernetes clusters can be used to deploy applications and to provide Review Apps for this project"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes version"
msgstr ""
@@ -5615,7 +5823,7 @@ msgstr ""
msgid "ClusterIntegration|Learn more about %{help_link_start}zones%{help_link_end}."
msgstr ""
-msgid "ClusterIntegration|Learn more about %{startLink}Regions %{externalLinkIcon}%{endLink}."
+msgid "ClusterIntegration|Learn more about %{linkStart}Regions%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Learn more about Kubernetes"
@@ -5660,12 +5868,18 @@ msgstr ""
msgid "ClusterIntegration|Machine type"
msgstr ""
+msgid "ClusterIntegration|Make sure your API endpoint is correct"
+msgstr ""
+
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create Kubernetes clusters"
msgstr ""
msgid "ClusterIntegration|Manage your Kubernetes cluster by visiting %{provider_link}"
msgstr ""
+msgid "ClusterIntegration|Namespace per environment"
+msgstr ""
+
msgid "ClusterIntegration|No IAM Roles found"
msgstr ""
@@ -5711,6 +5925,9 @@ msgstr ""
msgid "ClusterIntegration|No zones matched your search"
msgstr ""
+msgid "ClusterIntegration|Node calculations use the Kubernetes Metrics API. Make sure your cluster has metrics installed"
+msgstr ""
+
msgid "ClusterIntegration|Number of nodes"
msgstr ""
@@ -5753,6 +5970,9 @@ msgstr ""
msgid "ClusterIntegration|RBAC-enabled cluster"
msgstr ""
+msgid "ClusterIntegration|Read our %{linkStart}help page%{linkEnd} on Kubernetes cluster integration."
+msgstr ""
+
msgid "ClusterIntegration|Read our %{link_start}help page%{link_end} on Kubernetes cluster integration."
msgstr ""
@@ -5855,7 +6075,7 @@ msgstr ""
msgid "ClusterIntegration|Select a VPC to choose a subnet"
msgstr ""
-msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{linkStart}Amazon Web Services %{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select a network to choose a subnetwork"
@@ -5888,7 +6108,7 @@ msgstr ""
msgid "ClusterIntegration|Select project to choose zone"
msgstr ""
-msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select zone"
@@ -5978,9 +6198,18 @@ msgstr ""
msgid "ClusterIntegration|There was a problem authenticating with your cluster. Please ensure your CA Certificate and Token are valid."
msgstr ""
+msgid "ClusterIntegration|There was an HTTP error when connecting to your cluster."
+msgstr ""
+
msgid "ClusterIntegration|This account must have permissions to create a Kubernetes cluster in the %{link_to_container_project} specified below"
msgstr ""
+msgid "ClusterIntegration|This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
+msgstr ""
+
+msgid "ClusterIntegration|This is necessary to clear existing environment-namespace associations from clusters previously managed by GitLab."
+msgstr ""
+
msgid "ClusterIntegration|This option will allow you to install applications on RBAC clusters."
msgstr ""
@@ -6005,9 +6234,21 @@ msgstr ""
msgid "ClusterIntegration|To use a new project, first create one on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}."
msgstr ""
+msgid "ClusterIntegration|Troubleshooting tips:"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Authenticate"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Connect"
+msgstr ""
+
msgid "ClusterIntegration|Uninstall %{appTitle}"
msgstr ""
+msgid "ClusterIntegration|Unknown Error"
+msgstr ""
+
msgid "ClusterIntegration|Update %{appTitle}"
msgstr ""
@@ -6068,7 +6309,7 @@ msgstr ""
msgid "ClusterIntegration|Your cluster API is unreachable. Please ensure your API URL is correct."
msgstr ""
-msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Zone"
@@ -6188,6 +6429,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse all threads"
+msgstr ""
+
msgid "Collapse approvers"
msgstr ""
@@ -6337,7 +6581,7 @@ msgstr "Gecommit door"
msgid "Commit…"
msgstr ""
-msgid "Company"
+msgid "Community forum"
msgstr ""
msgid "Company name"
@@ -6346,6 +6590,9 @@ msgstr ""
msgid "Compare"
msgstr "Vergelijk"
+msgid "Compare %{oldCommitId}...%{newCommitId}"
+msgstr ""
+
msgid "Compare Git revisions"
msgstr ""
@@ -6361,6 +6608,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare submodule commit revisions"
+msgstr ""
+
msgid "Compare with previous version"
msgstr ""
@@ -6496,6 +6746,9 @@ msgstr ""
msgid "Configure the way a user creates a new account."
msgstr ""
+msgid "Configure which lists are shown for anyone who visits this board"
+msgstr ""
+
msgid "Confirm"
msgstr ""
@@ -6721,6 +6974,9 @@ msgstr[1] ""
msgid "ContainerRegistry|Set cleanup policy"
msgstr ""
+msgid "ContainerRegistry|Some tags were not deleted"
+msgstr ""
+
msgid "ContainerRegistry|Something went wrong while fetching the cleanup policy."
msgstr ""
@@ -6760,6 +7016,9 @@ msgstr ""
msgid "ContainerRegistry|Tags with names matching this regex pattern will %{italicStart}expire:%{italicEnd}"
msgstr ""
+msgid "ContainerRegistry|The cleanup policy timed out before it could delete all tags. An administrator can %{adminLinkStart}manually run cleanup now%{adminLinkEnd} or you can wait for the cleanup policy to automatically run again. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "ContainerRegistry|The last tag related to this image was recently removed. This empty image and any associated data will be automatically removed as part of the regular Garbage Collection process. If you have any questions, contact your administrator."
msgstr ""
@@ -6892,6 +7151,9 @@ msgstr ""
msgid "Contributions per group member"
msgstr ""
+msgid "Contributor"
+msgstr ""
+
msgid "Contributors"
msgstr ""
@@ -7021,6 +7283,9 @@ msgstr ""
msgid "Could not change HEAD: branch '%{branch}' does not exist"
msgstr ""
+msgid "Could not commit. An unexpected error occurred."
+msgstr ""
+
msgid "Could not connect to FogBugz, check your URL"
msgstr ""
@@ -7060,6 +7325,9 @@ msgstr ""
msgid "Could not find iteration"
msgstr ""
+msgid "Could not load instance counts. Please refresh the page to try again."
+msgstr ""
+
msgid "Could not remove the trigger."
msgstr ""
@@ -7084,10 +7352,10 @@ msgstr ""
msgid "Could not save prometheus manual configuration"
msgstr ""
-msgid "Could not udpdate wiki page"
+msgid "Could not update the LDAP settings"
msgstr ""
-msgid "Could not update the LDAP settings"
+msgid "Could not update wiki page"
msgstr ""
msgid "Could not upload your designs as one or more files uploaded are not supported."
@@ -7745,6 +8013,9 @@ msgstr ""
msgid "DastProfiles|Are you sure you want to delete this profile?"
msgstr ""
+msgid "DastProfiles|Could not create site validation token. Please refresh the page, or try again later."
+msgstr ""
+
msgid "DastProfiles|Could not create the scanner profile. Please try again."
msgstr ""
@@ -7769,6 +8040,12 @@ msgstr ""
msgid "DastProfiles|Could not fetch site profiles. Please refresh the page, or try again later."
msgstr ""
+msgid "DastProfiles|Could not retrieve site validation status. Please refresh the page, or try again later."
+msgstr ""
+
+msgid "DastProfiles|Could not update the scanner profile. Please try again."
+msgstr ""
+
msgid "DastProfiles|Could not update the site profile. Please try again."
msgstr ""
@@ -7784,7 +8061,7 @@ msgstr ""
msgid "DastProfiles|Download validation text file"
msgstr ""
-msgid "DastProfiles|Edit feature will come soon. Please create a new profile if changes needed"
+msgid "DastProfiles|Edit scanner profile"
msgstr ""
msgid "DastProfiles|Edit site profile"
@@ -7817,6 +8094,9 @@ msgstr ""
msgid "DastProfiles|No profiles created yet"
msgstr ""
+msgid "DastProfiles|Passive"
+msgstr ""
+
msgid "DastProfiles|Please enter a valid URL format, ex: http://www.example.com/home"
msgstr ""
@@ -7832,6 +8112,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan mode"
+msgstr ""
+
msgid "DastProfiles|Scanner Profile"
msgstr ""
@@ -7871,10 +8154,10 @@ msgstr ""
msgid "DastProfiles|Text file validation"
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
+msgid "DastProfiles|The maximum number of minutes allowed for the spider to traverse the site."
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the spider to traverse the site."
+msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
msgstr ""
msgid "DastProfiles|Validate"
@@ -7907,6 +8190,9 @@ msgstr ""
msgid "Date picker"
msgstr ""
+msgid "Date range"
+msgstr ""
+
msgid "Date range cannot exceed %{maxDateRange} days."
msgstr ""
@@ -7931,6 +8217,9 @@ msgstr ""
msgid "Days to merge"
msgstr ""
+msgid "Dear Administrator,"
+msgstr ""
+
msgid "Debug"
msgstr ""
@@ -8042,12 +8331,18 @@ msgstr ""
msgid "Delete"
msgstr ""
+msgid "Delete %{name}"
+msgstr ""
+
msgid "Delete Comment"
msgstr ""
msgid "Delete Snippet"
msgstr ""
+msgid "Delete Value Stream"
+msgstr ""
+
msgid "Delete account"
msgstr ""
@@ -8069,9 +8364,6 @@ msgstr ""
msgid "Delete label: %{label_name} ?"
msgstr ""
-msgid "Delete license"
-msgstr ""
-
msgid "Delete list"
msgstr ""
@@ -8147,15 +8439,6 @@ msgstr ""
msgid "Deleting a project places it into a read-only state until %{date}, at which point the project will be permanently deleted. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "Deleting the license failed."
-msgstr ""
-
-msgid "Deleting the license failed. The license was not found."
-msgstr ""
-
-msgid "Deleting the license failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "Deleting the project will delete its repository and all related resources including issues, merge requests etc."
msgstr ""
@@ -8651,7 +8934,10 @@ msgstr ""
msgid "DesignManagement|The maximum number of designs allowed to be uploaded is %{upload_limit}. Please try again."
msgstr ""
-msgid "DesignManagement|To upload designs, you'll need to enable LFS. %{requirements_link_start}More information%{requirements_link_end}"
+msgid "DesignManagement|There was an error moving your designs. Please upload your designs below."
+msgstr ""
+
+msgid "DesignManagement|To upload designs, you'll need to enable LFS and have admin enable hashed storage. %{requirements_link_start}More information%{requirements_link_end}"
msgstr ""
msgid "DesignManagement|Unresolve thread"
@@ -8663,6 +8949,9 @@ msgstr ""
msgid "DesignManagement|Upload skipped."
msgstr ""
+msgid "DesignManagement|Your designs are being copied and are on their way… Please refresh to update."
+msgstr ""
+
msgid "DesignManagement|and %{moreCount} more."
msgstr ""
@@ -8720,6 +9009,9 @@ msgstr ""
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
+msgid "Direct member"
+msgstr ""
+
msgid "Direction"
msgstr ""
@@ -8768,9 +9060,6 @@ msgstr ""
msgid "Discard draft"
msgstr ""
-msgid "Discard review"
-msgstr ""
-
msgid "DiscordService|Discord Notifications"
msgstr ""
@@ -8839,10 +9128,10 @@ msgstr ""
msgid "Dismiss Merge Request promotion"
msgstr ""
-msgid "Dismiss Selected"
+msgid "Dismiss Value Stream Analytics introduction box"
msgstr ""
-msgid "Dismiss Value Stream Analytics introduction box"
+msgid "Dismiss selected"
msgstr ""
msgid "Dismiss trial promotion"
@@ -8893,9 +9182,6 @@ msgstr ""
msgid "Documents reindexed: %{processed_documents} (%{percentage}%%)"
msgstr ""
-msgid "Doing"
-msgstr ""
-
msgid "Domain"
msgstr ""
@@ -9091,9 +9377,6 @@ msgstr ""
msgid "Edit environment"
msgstr ""
-msgid "Edit file"
-msgstr ""
-
msgid "Edit files in the editor and commit changes here"
msgstr ""
@@ -9106,6 +9389,12 @@ msgstr ""
msgid "Edit identity for %{user_name}"
msgstr ""
+msgid "Edit in Web IDE"
+msgstr ""
+
+msgid "Edit in single-file editor"
+msgstr ""
+
msgid "Edit issues"
msgstr ""
@@ -9133,10 +9422,10 @@ msgstr ""
msgid "Editing"
msgstr ""
-msgid "Elasticsearch"
+msgid "Elasticsearch AWS IAM credentials"
msgstr ""
-msgid "Elasticsearch AWS IAM credentials"
+msgid "Elasticsearch HTTP client timeout value in seconds."
msgstr ""
msgid "Elasticsearch indexing restrictions"
@@ -9145,9 +9434,6 @@ msgstr ""
msgid "Elasticsearch indexing started"
msgstr ""
-msgid "Elasticsearch integration. Elasticsearch AWS IAM."
-msgstr ""
-
msgid "Elasticsearch reindexing is already in progress"
msgstr ""
@@ -9175,9 +9461,6 @@ msgstr ""
msgid "Email Notification"
msgstr ""
-msgid "Email address"
-msgstr ""
-
msgid "Email could not be sent"
msgstr ""
@@ -9241,6 +9524,9 @@ msgstr ""
msgid "Emails sent from Service Desk will have this name"
msgstr ""
+msgid "Emails sent to %{email} will still be supported"
+msgstr ""
+
msgid "Emails separated by comma"
msgstr ""
@@ -9274,9 +9560,18 @@ msgstr ""
msgid "Enable"
msgstr ""
+msgid "Enable %{link_start}Gitpod%{link_end} integration to launch a development environment in your browser directly from GitLab."
+msgstr ""
+
msgid "Enable Auto DevOps"
msgstr ""
+msgid "Enable Gitpod"
+msgstr ""
+
+msgid "Enable Gitpod?"
+msgstr ""
+
msgid "Enable HTML emails"
msgstr ""
@@ -9406,9 +9701,6 @@ msgstr ""
msgid "Encountered an error while rendering: %{err}"
msgstr ""
-msgid "End date"
-msgstr ""
-
msgid "Ends at (UTC)"
msgstr ""
@@ -9568,7 +9860,7 @@ msgstr ""
msgid "EnvironmentsDashboard|The environments dashboard provides a summary of each project's environments' status, including pipeline and alert statuses."
msgstr ""
-msgid "EnvironmentsDashboard|This dashboard displays a maximum of 7 projects and 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
+msgid "EnvironmentsDashboard|This dashboard displays 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
msgstr ""
msgid "Environments|An error occurred while canceling the auto stop, please try again"
@@ -9889,6 +10181,9 @@ msgstr ""
msgid "Error deleting project. Check logs for error details."
msgstr ""
+msgid "Error fetching burnup chart data"
+msgstr ""
+
msgid "Error fetching diverging counts for branches. Please try again."
msgstr ""
@@ -9967,6 +10262,9 @@ msgstr ""
msgid "Error occurred when saving assignees"
msgstr ""
+msgid "Error occurred when saving reviewers"
+msgstr ""
+
msgid "Error occurred when toggling the notification subscription"
msgstr ""
@@ -10219,10 +10517,13 @@ msgstr ""
msgid "Expand all"
msgstr ""
-msgid "Expand approvers"
+msgid "Expand all files"
+msgstr ""
+
+msgid "Expand all threads"
msgstr ""
-msgid "Expand dropdown"
+msgid "Expand approvers"
msgstr ""
msgid "Expand milestones"
@@ -10393,6 +10694,9 @@ msgstr ""
msgid "Failed to create Merge Request. Please try again."
msgstr ""
+msgid "Failed to create To-Do for the design."
+msgstr ""
+
msgid "Failed to create a branch for this issue. Please try again."
msgstr ""
@@ -10432,6 +10736,12 @@ msgstr ""
msgid "Failed to load authors. Please try again."
msgstr ""
+msgid "Failed to load branches. Please try again."
+msgstr ""
+
+msgid "Failed to load deploy keys."
+msgstr ""
+
msgid "Failed to load emoji list."
msgstr ""
@@ -10447,6 +10757,9 @@ msgstr ""
msgid "Failed to load groups & users."
msgstr ""
+msgid "Failed to load groups, users and deploy keys."
+msgstr ""
+
msgid "Failed to load labels. Please try again."
msgstr ""
@@ -10456,6 +10769,12 @@ msgstr ""
msgid "Failed to load related branches"
msgstr ""
+msgid "Failed to load sidebar confidential toggle"
+msgstr ""
+
+msgid "Failed to load sidebar lock status"
+msgstr ""
+
msgid "Failed to load stacktrace."
msgstr ""
@@ -10483,6 +10802,9 @@ msgstr ""
msgid "Failed to publish issue on status page."
msgstr ""
+msgid "Failed to remove To-Do for the design."
+msgstr ""
+
msgid "Failed to remove a Zoom meeting"
msgstr ""
@@ -10525,6 +10847,9 @@ msgstr ""
msgid "Failed to signing using smartcard authentication"
msgstr ""
+msgid "Failed to toggle To-Do for the design."
+msgstr ""
+
msgid "Failed to update branch!"
msgstr ""
@@ -10638,7 +10963,7 @@ msgstr ""
msgid "FeatureFlags|Edit User List"
msgstr ""
-msgid "FeatureFlags|Enable features for specific users and specific environments by defining feature flag strategies."
+msgid "FeatureFlags|Enable features for specific users and environments by configuring feature flag strategies."
msgstr ""
msgid "FeatureFlags|Environment Spec"
@@ -10698,7 +11023,7 @@ msgstr ""
msgid "FeatureFlags|Include additional user IDs"
msgstr ""
-msgid "FeatureFlags|Install a %{docs_link_anchored_start}compatible client library%{docs_link_anchored_end} and specify the API URL, application name, and instance ID during the configuration setup. %{docs_link_start}More Information%{docs_link_end}"
+msgid "FeatureFlags|Install a %{docsLinkAnchoredStart}compatible client library%{docsLinkAnchoredEnd} and specify the API URL, application name, and instance ID during the configuration setup. %{docsLinkStart}More Information%{docsLinkEnd}"
msgstr ""
msgid "FeatureFlags|Instance ID"
@@ -10710,6 +11035,9 @@ msgstr ""
msgid "FeatureFlags|Loading feature flags"
msgstr ""
+msgid "FeatureFlags|Loading user lists"
+msgstr ""
+
msgid "FeatureFlags|More information"
msgstr ""
@@ -10728,7 +11056,7 @@ msgstr ""
msgid "FeatureFlags|New feature flag"
msgstr ""
-msgid "FeatureFlags|New list"
+msgid "FeatureFlags|New user list"
msgstr ""
msgid "FeatureFlags|Percent of users"
@@ -10767,6 +11095,9 @@ msgstr ""
msgid "FeatureFlags|There was an error fetching the feature flags."
msgstr ""
+msgid "FeatureFlags|There was an error fetching the user lists."
+msgstr ""
+
msgid "FeatureFlags|There was an error retrieving user lists"
msgstr ""
@@ -10782,6 +11113,9 @@ msgstr ""
msgid "FeatureFlags|User List"
msgstr ""
+msgid "FeatureFlags|User Lists"
+msgstr ""
+
msgid "FeatureFlag|List"
msgstr ""
@@ -10809,15 +11143,6 @@ msgstr ""
msgid "Fetching incoming email"
msgstr ""
-msgid "Fetching licenses failed."
-msgstr ""
-
-msgid "Fetching licenses failed. The request endpoint was not found."
-msgstr ""
-
-msgid "Fetching licenses failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "File"
msgstr ""
@@ -10920,12 +11245,21 @@ msgstr ""
msgid "Filter by status"
msgstr ""
+msgid "Filter by test cases that are currently archived."
+msgstr ""
+
+msgid "Filter by test cases that are currently opened."
+msgstr ""
+
msgid "Filter by two-factor authentication"
msgstr ""
msgid "Filter by user"
msgstr ""
+msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
+msgstr ""
+
msgid "Filter pipelines"
msgstr ""
@@ -10941,7 +11275,7 @@ msgstr ""
msgid "Filter results..."
msgstr ""
-msgid "Filter your projects by name"
+msgid "Filter your repositories by name"
msgstr ""
msgid "Filter..."
@@ -10950,7 +11284,7 @@ msgstr ""
msgid "Find File"
msgstr ""
-msgid "Find bugs in your code with coverage-guided fuzzing"
+msgid "Find bugs in your code with coverage-guided fuzzing."
msgstr ""
msgid "Find by path"
@@ -10977,9 +11311,6 @@ msgstr ""
msgid "Finish editing this message first!"
msgstr ""
-msgid "Finish review"
-msgstr ""
-
msgid "Finish setting up your dedicated account for %{group_name}."
msgstr ""
@@ -11049,6 +11380,9 @@ msgstr ""
msgid "Footer message"
msgstr ""
+msgid "For a faster browsing experience, some files are collapsed by default."
+msgstr ""
+
msgid "For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
@@ -11058,6 +11392,9 @@ msgstr ""
msgid "For more info, read the documentation."
msgstr ""
+msgid "For more information on how the number of active users is calculated, see the %{self_managed_subscriptions_doc_link} documentation."
+msgstr ""
+
msgid "For more information, go to the "
msgstr ""
@@ -11196,6 +11533,9 @@ msgstr ""
msgid "Generate new token"
msgstr ""
+msgid "Generic package file size in bytes"
+msgstr ""
+
msgid "Geo"
msgstr ""
@@ -11457,6 +11797,9 @@ msgstr ""
msgid "Geo|Please refer to Geo Troubleshooting."
msgstr ""
+msgid "Geo|Primary node"
+msgstr ""
+
msgid "Geo|Project"
msgstr ""
@@ -11499,6 +11842,9 @@ msgstr ""
msgid "Geo|Review replication status, and resynchronize and reverify items with the primary node."
msgstr ""
+msgid "Geo|Secondary node"
+msgstr ""
+
msgid "Geo|Status"
msgstr ""
@@ -11538,6 +11884,9 @@ msgstr ""
msgid "Geo|URL must be a valid url (ex: https://gitlab.com)"
msgstr ""
+msgid "Geo|Undefined"
+msgstr ""
+
msgid "Geo|Unknown state"
msgstr ""
@@ -11613,10 +11962,16 @@ msgstr ""
msgid "GitHub import"
msgstr ""
+msgid "GitLab"
+msgstr ""
+
msgid "GitLab / Unsubscribe"
msgstr ""
-msgid "GitLab Enterprise Edition %{plan}"
+msgid "GitLab API"
+msgstr ""
+
+msgid "GitLab Billing Team."
msgstr ""
msgid "GitLab Group Runners can execute code for all the projects in this group."
@@ -11628,12 +11983,18 @@ msgstr ""
msgid "GitLab Issue"
msgstr ""
+msgid "GitLab Pages"
+msgstr ""
+
msgid "GitLab Service Desk is a simple way to allow people to create issues in your GitLab instance without needing their own user account. It provides a unique email address for end users to create issues in a project, and replies can be sent either through the GitLab interface or by email. End users will only see the thread through email."
msgstr ""
msgid "GitLab Shared Runners execute code of different projects on the same Runner unless you configure GitLab Runner Autoscale with MaxBuilds 1 (which it is on GitLab.com)."
msgstr ""
+msgid "GitLab Shell"
+msgstr ""
+
msgid "GitLab Support Bot"
msgstr ""
@@ -11643,7 +12004,7 @@ msgstr ""
msgid "GitLab User"
msgstr ""
-msgid "GitLab allows you to continue using your license even if you exceed the number of seats you purchased. You will be required to pay for these seats when you renew your license."
+msgid "GitLab Workhorse"
msgstr ""
msgid "GitLab commit"
@@ -11811,6 +12172,21 @@ msgstr ""
msgid "Gitlab Pages"
msgstr ""
+msgid "Gitpod"
+msgstr ""
+
+msgid "Gitpod|Add the URL to your Gitpod instance configured to read your GitLab projects."
+msgstr ""
+
+msgid "Gitpod|Enable Gitpod integration"
+msgstr ""
+
+msgid "Gitpod|Gitpod URL"
+msgstr ""
+
+msgid "Gitpod|e.g. https://gitpod.example.com"
+msgstr ""
+
msgid "Given access %{time_ago}"
msgstr ""
@@ -12318,9 +12694,6 @@ msgstr ""
msgid "GroupSAML|Valid SAML Response"
msgstr ""
-msgid "GroupSAML|With group managed accounts enabled, all the users without a group managed account will be excluded from the group."
-msgstr ""
-
msgid "GroupSAML|With prohibit outer forks flag enabled group members will be able to fork project only inside your group."
msgstr ""
@@ -12534,10 +12907,10 @@ msgstr ""
msgid "GroupsNew|Create group"
msgstr ""
-msgid "GroupsNew|GitLab group export"
+msgid "GroupsNew|Import"
msgstr ""
-msgid "GroupsNew|Import"
+msgid "GroupsNew|Import a GitLab group export file"
msgstr ""
msgid "GroupsNew|Import group"
@@ -12680,6 +13053,9 @@ msgid_plural "Hide charts"
msgstr[0] ""
msgstr[1] ""
+msgid "Hide comments on this file"
+msgstr ""
+
msgid "Hide details"
msgstr ""
@@ -12724,6 +13100,15 @@ msgstr ""
msgid "Highest role:"
msgstr ""
+msgid "HighlightBar|Alert events:"
+msgstr ""
+
+msgid "HighlightBar|Alert start time:"
+msgstr ""
+
+msgid "HighlightBar|Original alert:"
+msgstr ""
+
msgid "History"
msgstr ""
@@ -12901,6 +13286,9 @@ msgstr ""
msgid "If enabled, access to projects will be validated on an external service using their classification label."
msgstr ""
+msgid "If the number of active users exceeds the user limit, you will be charged for the number of %{users_over_license_link} at your next license reconciliation."
+msgstr ""
+
msgid "If there is no previous license or if the previous license has expired, some GitLab functionality will be blocked until a new, valid license is uploaded."
msgstr ""
@@ -12940,9 +13328,6 @@ msgstr ""
msgid "If your HTTP repository is not publicly accessible, add your credentials."
msgstr ""
-msgid "Iglu registry URL (optional)"
-msgstr ""
-
msgid "Ignore"
msgstr ""
@@ -12979,6 +13364,16 @@ msgstr ""
msgid "Import"
msgstr ""
+msgid "Import %d compatible repository"
+msgid_plural "Import %d compatible repositories"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Import %d repository"
+msgid_plural "Import %d repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Import CSV"
msgstr ""
@@ -12988,15 +13383,9 @@ msgstr ""
msgid "Import all compatible projects"
msgstr ""
-msgid "Import all compatible repositories"
-msgstr ""
-
msgid "Import all projects"
msgstr ""
-msgid "Import all repositories"
-msgstr ""
-
msgid "Import an exported GitLab project"
msgstr ""
@@ -13084,6 +13473,9 @@ msgstr ""
msgid "ImportProjects|Error importing repository %{project_safe_import_url} into %{project_full_path} - %{message}"
msgstr ""
+msgid "ImportProjects|Import repositories"
+msgstr ""
+
msgid "ImportProjects|Importing the project failed"
msgstr ""
@@ -13096,7 +13488,7 @@ msgstr ""
msgid "ImportProjects|Requesting your %{provider} repositories failed"
msgstr ""
-msgid "ImportProjects|Select the projects you want to import"
+msgid "ImportProjects|Select the repositories you want to import"
msgstr ""
msgid "ImportProjects|The remote data could not be imported."
@@ -13132,9 +13524,6 @@ msgstr ""
msgid "In order to enable Service Desk for your instance, you must first set up incoming email."
msgstr ""
-msgid "In order to gather accurate feature usage data, it can take 1 to 2 weeks to see your index."
-msgstr ""
-
msgid "In order to personalize your experience with GitLab%{br_tag}we would like to know a bit more about you."
msgstr ""
@@ -13165,18 +13554,30 @@ msgstr ""
msgid "IncidentManagement|Create incident"
msgstr ""
+msgid "IncidentManagement|Critical - S1"
+msgstr ""
+
msgid "IncidentManagement|Date created"
msgstr ""
msgid "IncidentManagement|Display your incidents in a dedicated view"
msgstr ""
+msgid "IncidentManagement|High - S2"
+msgstr ""
+
msgid "IncidentManagement|Incident"
msgstr ""
msgid "IncidentManagement|Incidents"
msgstr ""
+msgid "IncidentManagement|Low - S4"
+msgstr ""
+
+msgid "IncidentManagement|Medium - S3"
+msgstr ""
+
msgid "IncidentManagement|No incidents to display."
msgstr ""
@@ -13189,6 +13590,9 @@ msgstr ""
msgid "IncidentManagement|Published to status page"
msgstr ""
+msgid "IncidentManagement|Severity"
+msgstr ""
+
msgid "IncidentManagement|There are no closed incidents"
msgstr ""
@@ -13198,6 +13602,9 @@ msgstr ""
msgid "IncidentManagement|Unassigned"
msgstr ""
+msgid "IncidentManagement|Unknown"
+msgstr ""
+
msgid "IncidentManagement|Unpublished"
msgstr ""
@@ -13219,6 +13626,15 @@ msgstr ""
msgid "Incidents"
msgstr ""
+msgid "Incident|Alert details"
+msgstr ""
+
+msgid "Incident|Summary"
+msgstr ""
+
+msgid "Incident|There was an issue loading alert data. Please try again."
+msgstr ""
+
msgid "Include a Terms of Service agreement and Privacy Policy that all users must accept."
msgstr ""
@@ -13279,6 +13695,9 @@ msgstr ""
msgid "Information about additional Pages templates and how to install them can be found in our %{pages_getting_started_guide}."
msgstr ""
+msgid "Inherited"
+msgstr ""
+
msgid "Inherited:"
msgstr ""
@@ -13359,7 +13778,22 @@ msgstr ""
msgid "Instance administrators group already exists"
msgstr ""
-msgid "Instance license"
+msgid "InstanceStatistics|Groups"
+msgstr ""
+
+msgid "InstanceStatistics|Issues"
+msgstr ""
+
+msgid "InstanceStatistics|Merge Requests"
+msgstr ""
+
+msgid "InstanceStatistics|Pipelines"
+msgstr ""
+
+msgid "InstanceStatistics|Projects"
+msgstr ""
+
+msgid "InstanceStatistics|Users"
msgstr ""
msgid "Integration"
@@ -13371,6 +13805,12 @@ msgstr ""
msgid "Integrations"
msgstr ""
+msgid "Integrations|%{integration} settings saved and active."
+msgstr ""
+
+msgid "Integrations|%{integration} settings saved, but not active."
+msgstr ""
+
msgid "Integrations|All details"
msgstr ""
@@ -13380,6 +13820,12 @@ msgstr ""
msgid "Integrations|Comment settings:"
msgstr ""
+msgid "Integrations|Connection failed. Please check your settings."
+msgstr ""
+
+msgid "Integrations|Connection successful."
+msgstr ""
+
msgid "Integrations|Default settings are inherited from the group level."
msgstr ""
@@ -13395,6 +13841,15 @@ msgstr ""
msgid "Integrations|Includes commit title and branch"
msgstr ""
+msgid "Integrations|Projects using custom settings will not be impacted unless the project owner chooses to use instance-level defaults."
+msgstr ""
+
+msgid "Integrations|Save settings?"
+msgstr ""
+
+msgid "Integrations|Saving will update the default settings for all projects that are not using custom settings."
+msgstr ""
+
msgid "Integrations|Standard"
msgstr ""
@@ -13527,6 +13982,9 @@ msgstr ""
msgid "Invitation"
msgstr ""
+msgid "Invitation declined"
+msgstr ""
+
msgid "Invite"
msgstr ""
@@ -13578,6 +14036,42 @@ 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|%{linkStart}Read more%{linkEnd} about role permissions"
+msgstr ""
+
+msgid "InviteMembersModal|Access expiration date (optional)"
+msgstr ""
+
+msgid "InviteMembersModal|Cancel"
+msgstr ""
+
+msgid "InviteMembersModal|Choose a role permission"
+msgstr ""
+
+msgid "InviteMembersModal|GitLab member or Email address"
+msgstr ""
+
+msgid "InviteMembersModal|Invite"
+msgstr ""
+
+msgid "InviteMembersModal|Invite team members"
+msgstr ""
+
+msgid "InviteMembersModal|Search for members to invite"
+msgstr ""
+
+msgid "InviteMembersModal|User not invited. Feature coming soon!"
+msgstr ""
+
+msgid "InviteMembersModal|Users were succesfully added"
+msgstr ""
+
+msgid "InviteMembersModal|You're inviting members to the %{group_name} group"
+msgstr ""
+
+msgid "InviteMembers|Invite team members"
+msgstr ""
+
msgid "Invited"
msgstr ""
@@ -13632,10 +14126,13 @@ msgstr ""
msgid "Issue cannot be found."
msgstr ""
+msgid "Issue created from vulnerability %{vulnerability_link}"
+msgstr ""
+
msgid "Issue events"
msgstr ""
-msgid "Issue first depoloyed to production"
+msgid "Issue first deployed to production"
msgstr ""
msgid "Issue label"
@@ -13713,6 +14210,9 @@ msgstr ""
msgid "IssueTracker|Custom issue tracker"
msgstr ""
+msgid "IssueTracker|EWM work items tracker"
+msgstr ""
+
msgid "IssueTracker|Redmine issue tracker"
msgstr ""
@@ -13779,6 +14279,9 @@ msgstr ""
msgid "It looks like you have some draft commits in this branch."
msgstr ""
+msgid "It may be several days before you see feature usage data."
+msgstr ""
+
msgid "It must have a header row and at least two columns: the first column is the issue title and the second column is the issue description. The separator is automatically detected."
msgstr ""
@@ -14061,13 +14564,13 @@ msgstr ""
msgid "Join Zoom meeting"
msgstr ""
-msgid "Jul"
+msgid "Joined %{time_ago}"
msgstr ""
-msgid "July"
+msgid "Jul"
msgstr ""
-msgid "Jump to first unresolved thread"
+msgid "July"
msgstr ""
msgid "Jump to next unresolved thread"
@@ -14103,6 +14606,9 @@ msgstr ""
msgid "Keyboard shortcuts"
msgstr ""
+msgid "KeyboardKey|Ctrl+"
+msgstr ""
+
msgid "Keys"
msgstr ""
@@ -14151,6 +14657,9 @@ msgstr ""
msgid "LDAP Synchronization"
msgstr ""
+msgid "LDAP group settings"
+msgstr ""
+
msgid "LDAP settings"
msgstr ""
@@ -14160,6 +14669,9 @@ msgstr ""
msgid "LDAP sync in progress. This could take a few minutes. Refresh the page to see the changes."
msgstr ""
+msgid "LDAP synchronizations"
+msgstr ""
+
msgid "LFS"
msgstr ""
@@ -14240,7 +14752,16 @@ msgid_plural "Last %d days"
msgstr[0] ""
msgstr[1] ""
-msgid "Last %{days} days"
+msgid "Last 2 weeks"
+msgstr ""
+
+msgid "Last 30 days"
+msgstr ""
+
+msgid "Last 60 days"
+msgstr ""
+
+msgid "Last 90 days"
msgstr ""
msgid "Last Accessed On"
@@ -14318,6 +14839,9 @@ msgstr ""
msgid "Last used on:"
msgstr ""
+msgid "Last week"
+msgstr ""
+
msgid "LastCommit|authored"
msgstr ""
@@ -14333,6 +14857,9 @@ msgstr ""
msgid "Latest pipeline for the most recent commit on this branch"
msgstr ""
+msgid "Launch a ready-to-code development environment for your project."
+msgstr ""
+
msgid "Lead"
msgstr ""
@@ -14713,6 +15240,9 @@ msgstr ""
msgid "List of all merge commits"
msgstr ""
+msgid "List options"
+msgstr ""
+
msgid "List settings"
msgstr ""
@@ -14725,9 +15255,6 @@ msgstr ""
msgid "List your Bitbucket Server repositories"
msgstr ""
-msgid "Lists"
-msgstr ""
-
msgid "Live preview"
msgstr ""
@@ -14974,6 +15501,12 @@ msgstr ""
msgid "Mark as done"
msgstr ""
+msgid "Mark as draft"
+msgstr ""
+
+msgid "Mark as ready"
+msgstr ""
+
msgid "Mark as resolved"
msgstr ""
@@ -14995,6 +15528,24 @@ msgstr ""
msgid "Markdown is supported"
msgstr ""
+msgid "MarkdownEditor|Add a link (%{modifierKey}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add a link (%{modifier_key}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifierKey}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifier_key}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifierKey}I)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifier_key}I)"
+msgstr ""
+
msgid "Marked For Deletion At - %{deletion_time}"
msgstr ""
@@ -15079,7 +15630,25 @@ msgstr ""
msgid "Max access level"
msgstr ""
-msgid "Max seats used"
+msgid "Max role"
+msgstr ""
+
+msgid "Max size 15 MB"
+msgstr ""
+
+msgid "Maximum Conan package file size in bytes"
+msgstr ""
+
+msgid "Maximum Maven package file size in bytes"
+msgstr ""
+
+msgid "Maximum NPM package file size in bytes"
+msgstr ""
+
+msgid "Maximum NuGet package file size in bytes"
+msgstr ""
+
+msgid "Maximum PyPI package file size in bytes"
msgstr ""
msgid "Maximum Users:"
@@ -15211,6 +15780,18 @@ msgstr ""
msgid "Members with access to %{strong_start}%{group_name}%{strong_end}"
msgstr ""
+msgid "Members|%{time} by %{user}"
+msgstr ""
+
+msgid "Members|Expired"
+msgstr ""
+
+msgid "Members|No expiration set"
+msgstr ""
+
+msgid "Members|in %{time}"
+msgstr ""
+
msgid "Memory Usage"
msgstr ""
@@ -15397,9 +15978,6 @@ msgstr ""
msgid "MergeRequests|Thread will be unresolved"
msgstr ""
-msgid "MergeRequests|Toggle comments for this file"
-msgstr ""
-
msgid "MergeRequests|View file @ %{commitId}"
msgstr ""
@@ -15460,6 +16038,9 @@ msgstr ""
msgid "Merging immediately isn't recommended as it may negatively impact the existing merge train. Read the %{docsLinkStart}documentation%{docsLinkEnd} for more information."
msgstr ""
+msgid "Message"
+msgstr ""
+
msgid "Messages"
msgstr ""
@@ -15845,18 +16426,12 @@ msgid_plural "Milestones"
msgstr[0] ""
msgstr[1] ""
-msgid "Milestone does not support burnup charts"
-msgstr ""
-
msgid "Milestone lists not available with your current license"
msgstr ""
msgid "Milestone lists show all issues from the selected milestone."
msgstr ""
-msgid "Milestone must have a start and due date"
-msgstr ""
-
msgid "MilestoneSidebar|Closed:"
msgstr ""
@@ -16223,6 +16798,9 @@ msgstr ""
msgid "Namespace"
msgstr ""
+msgid "Namespace ID:"
+msgstr ""
+
msgid "Namespace is empty"
msgstr ""
@@ -16307,6 +16885,9 @@ msgstr ""
msgid "NetworkPolicies|Allow all outbound traffic from %{selector} to %{ruleSelector} on %{ports}"
msgstr ""
+msgid "NetworkPolicies|Are you sure you want to delete this policy? This action cannot be undone."
+msgstr ""
+
msgid "NetworkPolicies|Choose whether to enforce this policy."
msgstr ""
@@ -16316,12 +16897,21 @@ msgstr ""
msgid "NetworkPolicies|Define this policy's location, conditions and actions."
msgstr ""
+msgid "NetworkPolicies|Delete policy"
+msgstr ""
+
+msgid "NetworkPolicies|Delete policy: %{policy}"
+msgstr ""
+
msgid "NetworkPolicies|Deny all traffic"
msgstr ""
msgid "NetworkPolicies|Description"
msgstr ""
+msgid "NetworkPolicies|Edit policy"
+msgstr ""
+
msgid "NetworkPolicies|Editor mode"
msgstr ""
@@ -16349,6 +16939,9 @@ msgstr ""
msgid "NetworkPolicies|Name"
msgstr ""
+msgid "NetworkPolicies|Namespace"
+msgstr ""
+
msgid "NetworkPolicies|Network Policy"
msgstr ""
@@ -16400,6 +16993,9 @@ msgstr ""
msgid "NetworkPolicies|Rules"
msgstr ""
+msgid "NetworkPolicies|Save changes"
+msgstr ""
+
msgid "NetworkPolicies|Something went wrong, failed to update policy"
msgstr ""
@@ -16412,6 +17008,9 @@ msgstr ""
msgid "NetworkPolicies|Traffic that does not match any rule will be blocked."
msgstr ""
+msgid "NetworkPolicies|Unable to parse policy"
+msgstr ""
+
msgid "NetworkPolicies|YAML editor"
msgstr ""
@@ -16525,6 +17124,9 @@ msgstr ""
msgid "New Snippet"
msgstr ""
+msgid "New Test Case"
+msgstr ""
+
msgid "New User"
msgstr ""
@@ -16624,6 +17226,9 @@ msgstr ""
msgid "New tag"
msgstr ""
+msgid "New test case"
+msgstr ""
+
msgid "New users set to external"
msgstr ""
@@ -16696,7 +17301,7 @@ msgstr ""
msgid "No changes"
msgstr ""
-msgid "No changes between %{ref_start}%{source_branch}%{ref_end} and %{ref_start}%{target_branch}%{ref_end}"
+msgid "No changes between %{sourceBranch} and %{targetBranch}"
msgstr ""
msgid "No child epics match applied filters"
@@ -16711,6 +17316,9 @@ msgstr ""
msgid "No containers available"
msgstr ""
+msgid "No content to show"
+msgstr ""
+
msgid "No contributions"
msgstr ""
@@ -16786,9 +17394,6 @@ msgstr ""
msgid "No license. All rights reserved"
msgstr ""
-msgid "No licenses found."
-msgstr ""
-
msgid "No matches found"
msgstr ""
@@ -16801,6 +17406,9 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No members found"
+msgstr ""
+
msgid "No merge requests found"
msgstr ""
@@ -16822,6 +17430,9 @@ msgstr ""
msgid "No parent group"
msgstr ""
+msgid "No plan"
+msgstr ""
+
msgid "No pods available"
msgstr ""
@@ -16918,6 +17529,12 @@ msgstr ""
msgid "Not Implemented"
msgstr ""
+msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+msgstr ""
+
+msgid "Not all browsers support WebAuthn. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even from an unsupported browser."
+msgstr ""
+
msgid "Not all data has been processed yet, the accuracy of the chart for the selected timeframe is limited."
msgstr ""
@@ -17014,6 +17631,9 @@ msgstr ""
msgid "Notification settings saved"
msgstr ""
+msgid "NotificationEvent|Change reviewer merge request"
+msgstr ""
+
msgid "NotificationEvent|Close issue"
msgstr ""
@@ -17176,10 +17796,7 @@ msgstr ""
msgid "On track"
msgstr ""
-msgid "OnDemandScans|Attached branch"
-msgstr ""
-
-msgid "OnDemandScans|Attached branch is where the scan job runs."
+msgid "OnDemandScans|Could not fetch scanner profiles. Please refresh the page, or try again later."
msgstr ""
msgid "OnDemandScans|Could not fetch site profiles. Please refresh the page, or try again later."
@@ -17188,6 +17805,9 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
+msgid "OnDemandScans|Create a new scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Create a new site profile"
msgstr ""
@@ -17200,6 +17820,9 @@ msgstr ""
msgid "OnDemandScans|New on-demand DAST scan"
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 ""
@@ -17209,16 +17832,10 @@ msgstr ""
msgid "OnDemandScans|On-demand scans run outside the DevOps cycle and find vulnerabilities in your projects. %{learnMoreLinkStart}Learn more%{learnMoreLinkEnd}"
msgstr ""
-msgid "OnDemandScans|Only a passive scan can be performed on demand."
-msgstr ""
-
-msgid "OnDemandScans|Passive"
-msgstr ""
-
msgid "OnDemandScans|Run scan"
msgstr ""
-msgid "OnDemandScans|Scan mode"
+msgid "OnDemandScans|Scanner profile"
msgstr ""
msgid "OnDemandScans|Scanner settings"
@@ -17230,9 +17847,15 @@ msgstr ""
msgid "OnDemandScans|Select one of the existing profiles"
msgstr ""
+msgid "OnDemandScans|Site profile"
+msgstr ""
+
msgid "OnDemandScans|Site profiles"
msgstr ""
+msgid "OnDemandScans|Use existing scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Use existing site profile"
msgstr ""
@@ -17331,9 +17954,6 @@ msgstr ""
msgid "Open Selection"
msgstr ""
-msgid "Open Web IDE"
-msgstr ""
-
msgid "Open comment type dropdown"
msgstr ""
@@ -17439,6 +18059,9 @@ msgstr ""
msgid "Origin"
msgstr ""
+msgid "Orphaned member"
+msgstr ""
+
msgid "Other Labels"
msgstr ""
@@ -17454,6 +18077,9 @@ msgstr ""
msgid "Other visibility settings have been disabled by the administrator."
msgstr ""
+msgid "Our documentation includes an example DevOps Score report."
+msgstr ""
+
msgid "Out-of-compliance with this project's policies and should be removed"
msgstr ""
@@ -17478,6 +18104,9 @@ msgstr ""
msgid "Overwrite diverged branches"
msgstr ""
+msgid "Owned by %{image_tag}"
+msgstr ""
+
msgid "Owned by anyone"
msgstr ""
@@ -17499,6 +18128,9 @@ msgstr ""
msgid "Package deleted successfully"
msgstr ""
+msgid "Package file size limits"
+msgstr ""
+
msgid "Package recipe already exists"
msgstr ""
@@ -17514,9 +18146,6 @@ msgstr ""
msgid "Package type must be PyPi"
msgstr ""
-msgid "Package was removed"
-msgstr ""
-
msgid "PackageRegistry|%{name} version %{version} was created %{datetime}"
msgstr ""
@@ -17658,12 +18287,18 @@ msgstr ""
msgid "PackageRegistry|NuGet Command"
msgstr ""
+msgid "PackageRegistry|Package Registry"
+msgstr ""
+
msgid "PackageRegistry|Pip Command"
msgstr ""
msgid "PackageRegistry|Pipeline %{link} triggered %{datetime} by %{author}"
msgstr ""
+msgid "PackageRegistry|Publish and share packages for a variety of common package managers. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "PackageRegistry|Published to the %{project} Package Registry %{datetime}"
msgstr ""
@@ -17763,6 +18398,9 @@ msgstr ""
msgid "Page not found"
msgstr ""
+msgid "Page settings"
+msgstr ""
+
msgid "Page was successfully deleted"
msgstr ""
@@ -17904,7 +18542,7 @@ msgstr ""
msgid "Paste issue link"
msgstr ""
-msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Don't use your private SSH key."
+msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Do not paste your private SSH key, as that can compromise your identity."
msgstr ""
msgid "Patch to apply"
@@ -17931,6 +18569,9 @@ msgstr ""
msgid "Pending"
msgstr ""
+msgid "Pending comments"
+msgstr ""
+
msgid "People without permission will never get a notification and won't be able to comment."
msgstr ""
@@ -18129,6 +18770,9 @@ msgstr ""
msgid "Pipelines|Build with confidence"
msgstr ""
+msgid "Pipelines|By revoking a trigger you will break any processes making use of it. Are you sure?"
+msgstr ""
+
msgid "Pipelines|CI Lint"
msgstr ""
@@ -18141,6 +18785,15 @@ msgstr ""
msgid "Pipelines|Continuous Integration can help catch bugs by running your tests automatically, while Continuous Deployment can help you deliver code to your product environment."
msgstr ""
+msgid "Pipelines|Copy trigger token"
+msgstr ""
+
+msgid "Pipelines|Description"
+msgstr ""
+
+msgid "Pipelines|Edit"
+msgstr ""
+
msgid "Pipelines|Get started with Pipelines"
msgstr ""
@@ -18156,15 +18809,27 @@ msgstr ""
msgid "Pipelines|It is recommended the code is reviewed thoroughly before running this pipeline with the parent project's CI resource."
msgstr ""
+msgid "Pipelines|Last Used"
+msgstr ""
+
msgid "Pipelines|Loading Pipelines"
msgstr ""
msgid "Pipelines|More Information"
msgstr ""
+msgid "Pipelines|No triggers have been created yet. Add one using the form above."
+msgstr ""
+
+msgid "Pipelines|Owner"
+msgstr ""
+
msgid "Pipelines|Project cache successfully reset."
msgstr ""
+msgid "Pipelines|Revoke"
+msgstr ""
+
msgid "Pipelines|Run Pipeline"
msgstr ""
@@ -18189,6 +18854,15 @@ msgstr ""
msgid "Pipelines|This project is not currently set up to run pipelines."
msgstr ""
+msgid "Pipelines|Token"
+msgstr ""
+
+msgid "Pipelines|Trigger user has insufficient permissions to project"
+msgstr ""
+
+msgid "Pipelines|invalid"
+msgstr ""
+
msgid "Pipelines|parent"
msgstr ""
@@ -18447,10 +19121,10 @@ msgstr ""
msgid "Please provide attributes to update"
msgstr ""
-msgid "Please refer to %{docs_url}"
+msgid "Please reach out if you have any questions and we'll be happy to assist."
msgstr ""
-msgid "Please retype the email address."
+msgid "Please refer to %{docs_url}"
msgstr ""
msgid "Please select"
@@ -18480,6 +19154,9 @@ msgstr ""
msgid "Please set a new password before proceeding."
msgstr ""
+msgid "Please share your feedback about %{featureName} %{linkStart}in this issue%{linkEnd} to help us improve the experience."
+msgstr ""
+
msgid "Please solve the reCAPTCHA"
msgstr ""
@@ -18783,6 +19460,9 @@ msgstr ""
msgid "Profiles| You are going to change the username %{currentUsernameBold} to %{newUsernameBold}. Profile and projects will be redirected to the %{newUsername} namespace but this redirect will expire once the %{currentUsername} namespace is registered by another user or group. Please update your Git repository remotes as soon as possible."
msgstr ""
+msgid "Profiles|%{provider} Active"
+msgstr ""
+
msgid "Profiles|@username"
msgstr ""
@@ -18834,7 +19514,7 @@ msgstr ""
msgid "Profiles|Commit email"
msgstr ""
-msgid "Profiles|Connect"
+msgid "Profiles|Connect %{provider}"
msgstr ""
msgid "Profiles|Connected Accounts"
@@ -18858,6 +19538,9 @@ msgstr ""
msgid "Profiles|Disconnect"
msgstr ""
+msgid "Profiles|Disconnect %{provider}"
+msgstr ""
+
msgid "Profiles|Do not show on profile"
msgstr ""
@@ -18882,7 +19565,7 @@ msgstr ""
msgid "Profiles|Full name"
msgstr ""
-msgid "Profiles|Give your individual key a title. This will be publically visible."
+msgid "Profiles|Give your individual key a title."
msgstr ""
msgid "Profiles|Include private contributions on my profile"
@@ -18972,7 +19655,7 @@ msgstr ""
msgid "Profiles|The maximum file size allowed is 200KB."
msgstr ""
-msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it?"
+msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it? It will be publicly visible."
msgstr ""
msgid "Profiles|This email will be displayed on your public profile"
@@ -19047,6 +19730,9 @@ msgstr ""
msgid "Profiles|You don't have access to delete this user."
msgstr ""
+msgid "Profiles|You must transfer ownership or delete groups you are an owner of before you can delete your account"
+msgstr ""
+
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
@@ -19635,6 +20321,9 @@ msgstr ""
msgid "ProjectTemplates|GitLab Cluster Management"
msgstr ""
+msgid "ProjectTemplates|Gitpod/Spring Petclinic"
+msgstr ""
+
msgid "ProjectTemplates|Go Micro"
msgstr ""
@@ -20244,6 +20933,9 @@ msgstr ""
msgid "Publish to status page"
msgstr ""
+msgid "Published"
+msgstr ""
+
msgid "Published on status page"
msgstr ""
@@ -20361,9 +21053,15 @@ msgstr ""
msgid "Quick range"
msgstr ""
+msgid "Quickly and easily edit multiple files in your project."
+msgstr ""
+
msgid "README"
msgstr ""
+msgid "Rails"
+msgstr ""
+
msgid "Rake Tasks Help"
msgstr ""
@@ -20483,10 +21181,13 @@ msgstr ""
msgid "Register Two-Factor Authenticator"
msgstr ""
-msgid "Register U2F device"
+msgid "Register Universal Two-Factor (U2F) Device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register WebAuthn Device"
+msgstr ""
+
+msgid "Register device"
msgstr ""
msgid "Register for GitLab"
@@ -20498,9 +21199,6 @@ msgstr ""
msgid "Register with two-factor app"
msgstr ""
-msgid "Registration"
-msgstr ""
-
msgid "Registration|Checkout"
msgstr ""
@@ -20617,9 +21315,6 @@ msgstr ""
msgid "Release|Something went wrong while saving the release details"
msgstr ""
-msgid "Remediated: needs review"
-msgstr ""
-
msgid "Remediations"
msgstr ""
@@ -20725,6 +21420,9 @@ msgstr ""
msgid "Remove priority"
msgstr ""
+msgid "Remove report"
+msgstr ""
+
msgid "Remove secondary node"
msgstr ""
@@ -20737,6 +21435,12 @@ msgstr ""
msgid "Remove time estimate"
msgstr ""
+msgid "Remove user & report"
+msgstr ""
+
+msgid "Remove user from group"
+msgstr ""
+
msgid "Removed"
msgstr ""
@@ -20818,9 +21522,6 @@ msgstr ""
msgid "Removes time estimate."
msgstr ""
-msgid "Removing license…"
-msgstr ""
-
msgid "Removing this group also removes all child projects, including archived projects, and their resources."
msgstr ""
@@ -20905,6 +21606,9 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
+msgid "Reported by %{reporter}"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -20991,6 +21695,27 @@ msgstr ""
msgid "Repositories"
msgstr ""
+msgid "Repositories Analytics"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download Historic Test Coverage Data"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download historic test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Historic Test Coverage Data is available in raw format (.csv) for further analysis."
+msgstr ""
+
+msgid "RepositoriesAnalytics|Test Code Coverage"
+msgstr ""
+
+msgid "RepositoriesAnalytics|There was an error fetching the projects."
+msgstr ""
+
msgid "Repository"
msgstr ""
@@ -21069,9 +21794,15 @@ msgstr ""
msgid "Request parameter %{param} is missing."
msgstr ""
+msgid "Request review from"
+msgstr ""
+
msgid "Request to link SAML account must be authorized"
msgstr ""
+msgid "Requested"
+msgstr ""
+
msgid "Requested %{time_ago}"
msgstr ""
@@ -21090,6 +21821,9 @@ msgstr ""
msgid "Requests to these domain(s)/address(es) on the local network will be allowed when local requests from hooks and services are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 or 127.0.0.0/28 are supported. Domain wildcards are not supported currently. Use comma, semicolon, or newline to separate multiple entries. The allowlist can hold a maximum of 1000 entries. Domains should use IDNA encoding. Ex: example.com, 192.168.1.1, 127.0.0.0/28, xn--itlab-j1a.com."
msgstr ""
+msgid "Require admin approval for new sign-ups"
+msgstr ""
+
msgid "Require all users in this group to setup Two-factor authentication"
msgstr ""
@@ -21217,9 +21951,6 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
-msgid "Resolved by %{resolvedByName}"
-msgstr ""
-
msgid "Resolves IP addresses once and uses them to submit requests"
msgstr ""
@@ -21339,6 +22070,14 @@ msgstr ""
msgid "ReviewApp|Enable Review App"
msgstr ""
+msgid "Reviewer"
+msgid_plural "%d Reviewers"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Reviewer(s)"
+msgstr ""
+
msgid "Reviewing"
msgstr ""
@@ -21378,6 +22117,9 @@ msgstr ""
msgid "Rook"
msgstr ""
+msgid "Ruby"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -21456,6 +22198,63 @@ msgstr ""
msgid "Runners page."
msgstr ""
+msgid "Runners|Active"
+msgstr ""
+
+msgid "Runners|Architecture"
+msgstr ""
+
+msgid "Runners|Can run untagged jobs"
+msgstr ""
+
+msgid "Runners|Description"
+msgstr ""
+
+msgid "Runners|Group"
+msgstr ""
+
+msgid "Runners|IP Address"
+msgstr ""
+
+msgid "Runners|Last contact"
+msgstr ""
+
+msgid "Runners|Locked to this project"
+msgstr ""
+
+msgid "Runners|Maximum job timeout"
+msgstr ""
+
+msgid "Runners|Name"
+msgstr ""
+
+msgid "Runners|Platform"
+msgstr ""
+
+msgid "Runners|Property Name"
+msgstr ""
+
+msgid "Runners|Protected"
+msgstr ""
+
+msgid "Runners|Revision"
+msgstr ""
+
+msgid "Runners|Shared"
+msgstr ""
+
+msgid "Runners|Specific"
+msgstr ""
+
+msgid "Runners|Tags"
+msgstr ""
+
+msgid "Runners|Value"
+msgstr ""
+
+msgid "Runners|Version"
+msgstr ""
+
msgid "Runners|You have used %{quotaUsed} out of %{quotaLimit} of your shared Runners pipeline minutes."
msgstr ""
@@ -21468,6 +22267,9 @@ msgstr ""
msgid "Runs a number of housekeeping tasks within the current repository, such as compressing file revisions and removing unreachable objects."
msgstr ""
+msgid "SAML"
+msgstr ""
+
msgid "SAML SSO"
msgstr ""
@@ -21519,6 +22321,9 @@ msgstr ""
msgid "Save"
msgstr ""
+msgid "Save %{name} size limits"
+msgstr ""
+
msgid "Save Changes"
msgstr ""
@@ -21549,9 +22354,6 @@ msgstr ""
msgid "Save space and find tags in the Container Registry more easily. Enable the cleanup policy to remove stale tags and keep only the ones you need."
msgstr ""
-msgid "Save template"
-msgstr ""
-
msgid "Save variables"
msgstr ""
@@ -21594,9 +22396,6 @@ msgstr ""
msgid "Scope"
msgstr ""
-msgid "Scope not supported with disabled 'users_search' feature!"
-msgstr ""
-
msgid "Scoped issue boards"
msgstr ""
@@ -21723,9 +22522,6 @@ msgstr ""
msgid "Search requirements"
msgstr ""
-msgid "Search results…"
-msgstr ""
-
msgid "Search users"
msgstr ""
@@ -21798,6 +22594,11 @@ msgid_plural "SearchResults|commits"
msgstr[0] ""
msgstr[1] ""
+msgid "SearchResults|epic"
+msgid_plural "SearchResults|epics"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "SearchResults|issue"
msgid_plural "SearchResults|issues"
msgstr[0] ""
@@ -21842,10 +22643,10 @@ msgstr ""
msgid "Seat Link is disabled, and cannot be configured through this form."
msgstr ""
-msgid "Seats currently in use"
+msgid "Seats usage data as of %{last_enqueue_time}"
msgstr ""
-msgid "Seats in license"
+msgid "Seats usage data is updated every day at 12:00pm UTC"
msgstr ""
msgid "Secondary"
@@ -21899,6 +22700,9 @@ msgstr ""
msgid "SecurityConfiguration|Available for on-demand DAST"
msgstr ""
+msgid "SecurityConfiguration|By default, all analyzers are applied in order to cover all languages across your project, and only run if the language is detected in the Merge Request."
+msgstr ""
+
msgid "SecurityConfiguration|Configure"
msgstr ""
@@ -21929,16 +22733,19 @@ msgstr ""
msgid "SecurityConfiguration|Manage"
msgstr ""
+msgid "SecurityConfiguration|More information"
+msgstr ""
+
msgid "SecurityConfiguration|Not enabled"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|Security Control"
+msgid "SecurityConfiguration|SAST Configuration"
msgstr ""
-msgid "SecurityConfiguration|See documentation"
+msgid "SecurityConfiguration|Security Control"
msgstr ""
msgid "SecurityConfiguration|Status"
@@ -21950,6 +22757,9 @@ msgstr ""
msgid "SecurityConfiguration|Using custom settings. You won't receive automatic updates on this variable. %{anchorStart}Restore to default%{anchorEnd}"
msgstr ""
+msgid "SecurityConfiguration|View history"
+msgstr ""
+
msgid "SecurityConfiguration|You can quickly enable all security scanning tools by enabling %{linkStart}Auto DevOps%{linkEnd}."
msgstr ""
@@ -22028,9 +22838,6 @@ msgstr ""
msgid "SecurityReports|Learn more about setting up your dashboard"
msgstr ""
-msgid "SecurityReports|Load more vulnerabilities"
-msgstr ""
-
msgid "SecurityReports|Monitor vulnerabilities in your code"
msgstr ""
@@ -22310,7 +23117,7 @@ msgstr ""
msgid "Select status"
msgstr ""
-msgid "Select strategy activation method"
+msgid "Select strategy activation method."
msgstr ""
msgid "Select subscription"
@@ -22325,7 +23132,7 @@ msgstr ""
msgid "Select the custom project template source group."
msgstr ""
-msgid "Select timeframe"
+msgid "Select the environment scope for this feature flag."
msgstr ""
msgid "Select timezone"
@@ -22574,6 +23381,9 @@ msgstr ""
msgid "Set iteration"
msgstr ""
+msgid "Set limit to 0 to allow any file size."
+msgstr ""
+
msgid "Set max session time for web terminal."
msgstr ""
@@ -22652,10 +23462,13 @@ msgstr ""
msgid "Set up a %{type} Runner manually"
msgstr ""
+msgid "Set up a hardware device as a second factor to sign in."
+msgstr ""
+
msgid "Set up assertions/attributes/claims (email, first_name, last_name) and NameID according to %{docsLinkStart}the documentation %{icon}%{docsLinkEnd}"
msgstr ""
-msgid "Set up new U2F device"
+msgid "Set up new device"
msgstr ""
msgid "Set up new password"
@@ -22724,6 +23537,9 @@ msgstr ""
msgid "Sets weight to %{weight}."
msgstr ""
+msgid "Setting this to 0 means using the system default timeout value."
+msgstr ""
+
msgid "Settings"
msgstr ""
@@ -22739,6 +23555,15 @@ msgstr ""
msgid "Severity"
msgstr ""
+msgid "SeverityWidget|Severity"
+msgstr ""
+
+msgid "SeverityWidget|Severity: %{severity}"
+msgstr ""
+
+msgid "SeverityWidget|There was an error while updating severity."
+msgstr ""
+
msgid "Shards (%{shards})"
msgstr ""
@@ -22784,6 +23609,9 @@ msgstr ""
msgid "Show all requirements."
msgstr ""
+msgid "Show all test cases."
+msgstr ""
+
msgid "Show archived projects"
msgstr ""
@@ -22796,6 +23624,9 @@ msgstr ""
msgid "Show comments"
msgstr ""
+msgid "Show comments on this file"
+msgstr ""
+
msgid "Show comments only"
msgstr ""
@@ -22841,6 +23672,12 @@ msgstr ""
msgid "Show parent subgroups"
msgstr ""
+msgid "Show the Closed list"
+msgstr ""
+
+msgid "Show the Open list"
+msgstr ""
+
msgid "Show whitespace changes"
msgstr ""
@@ -22884,9 +23721,6 @@ msgstr ""
msgid "Sidebar|Assign health status"
msgstr ""
-msgid "Sidebar|Change weight"
-msgstr ""
-
msgid "Sidebar|Health status"
msgstr ""
@@ -23070,6 +23904,9 @@ msgstr ""
msgid "Snippets|Add another file %{num}/%{total}"
msgstr ""
+msgid "Snippets|Authored %{time_ago} by %{author}"
+msgstr ""
+
msgid "Snippets|Delete file"
msgstr ""
@@ -23097,6 +23934,9 @@ msgstr ""
msgid "Solution"
msgstr ""
+msgid "Some changes are not shown"
+msgstr ""
+
msgid "Some child epics may be hidden due to applied filters"
msgstr ""
@@ -23463,6 +24303,12 @@ msgstr ""
msgid "Source (branch or tag)"
msgstr ""
+msgid "Source Branch"
+msgstr ""
+
+msgid "Source branch: %{source_branch_open}%{source_branch}%{source_branch_close}"
+msgstr ""
+
msgid "Source code"
msgstr ""
@@ -23628,9 +24474,6 @@ msgstr ""
msgid "Start and due date"
msgstr ""
-msgid "Start by choosing a group to see how your team is spending time. You can then drill down to the project level."
-msgstr ""
-
msgid "Start by choosing a group to start exploring the merge requests in that group. You can then proceed to filter by projects, labels, milestones and authors."
msgstr ""
@@ -23712,18 +24555,27 @@ msgstr ""
msgid "StaticSiteEditor|3. Assign a person to review and accept the merge request."
msgstr ""
+msgid "StaticSiteEditor|A link to view the merge request will appear once ready."
+msgstr ""
+
msgid "StaticSiteEditor|An error occurred while submitting your changes."
msgstr ""
msgid "StaticSiteEditor|Branch could not be created."
msgstr ""
+msgid "StaticSiteEditor|Copy update"
+msgstr ""
+
msgid "StaticSiteEditor|Could not commit the content changes."
msgstr ""
msgid "StaticSiteEditor|Could not create merge request."
msgstr ""
+msgid "StaticSiteEditor|Creating your merge request"
+msgstr ""
+
msgid "StaticSiteEditor|Incompatible file content"
msgstr ""
@@ -23745,6 +24597,9 @@ msgstr ""
msgid "StaticSiteEditor|View documentation"
msgstr ""
+msgid "StaticSiteEditor|You can set an assignee to get your changes reviewed and deployed once your merge request is created."
+msgstr ""
+
msgid "StaticSiteEditor|Your merge request has been created"
msgstr ""
@@ -23874,15 +24729,15 @@ msgstr ""
msgid "Submit %{humanized_resource_name}"
msgstr ""
-msgid "Submit Changes"
-msgstr ""
-
msgid "Submit a review"
msgstr ""
msgid "Submit as spam"
msgstr ""
+msgid "Submit changes"
+msgstr ""
+
msgid "Submit feedback"
msgstr ""
@@ -24036,6 +24891,9 @@ msgstr ""
msgid "Successfully deleted U2F device."
msgstr ""
+msgid "Successfully deleted WebAuthn device."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -24354,9 +25212,6 @@ msgstr ""
msgid "Template to append to all Service Desk issues"
msgstr ""
-msgid "Template was successfully saved."
-msgstr ""
-
msgid "Templates"
msgstr ""
@@ -24435,10 +25290,28 @@ msgid_plural "Test coverage: %d hits"
msgstr[0] ""
msgstr[1] ""
-msgid "Test failed."
+msgid "Test settings"
+msgstr ""
+
+msgid "TestCases|New Test Case"
msgstr ""
-msgid "Test settings and save changes"
+msgid "TestCases|New test case"
+msgstr ""
+
+msgid "TestCases|Search test cases"
+msgstr ""
+
+msgid "TestCases|Something went wrong while creating a test case."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching count of test cases."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching test cases list."
+msgstr ""
+
+msgid "TestCases|Submit test case"
msgstr ""
msgid "TestHooks|Ensure one of your projects has merge requests."
@@ -24504,6 +25377,9 @@ msgstr ""
msgid "Thank you for signing up for your free trial! You will get additional instructions in your inbox shortly."
msgstr ""
+msgid "Thank you for your business."
+msgstr ""
+
msgid "Thank you for your feedback!"
msgstr ""
@@ -24563,9 +25439,6 @@ msgstr ""
msgid "The URL to use for connecting to Elasticsearch. Use a comma-separated list to support clustering (e.g., \"http://localhost:9200, http://localhost:9201\")."
msgstr ""
-msgid "The Web IDE offers advanced syntax highlighting capabilities and more."
-msgstr ""
-
msgid "The X509 Certificate to use when mutual TLS is required to communicate with the external authorization service. If left blank, the server certificate is still validated when accessing over HTTPS."
msgstr ""
@@ -24676,6 +25549,9 @@ msgstr ""
msgid "The form contains the following error:"
msgstr ""
+msgid "The form contains the following warning:"
+msgstr ""
+
msgid "The global settings require you to enable Two-Factor Authentication for your account."
msgstr ""
@@ -24790,9 +25666,6 @@ msgstr ""
msgid "The private key to use when a client certificate is provided. This value is encrypted at rest."
msgstr ""
-msgid "The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The project can be accessed by any logged in user."
msgstr ""
@@ -24829,7 +25702,7 @@ msgstr ""
msgid "The remote repository is being updated..."
msgstr ""
-msgid "The repository can be commited to, and issues, comments and other entities can be created."
+msgid "The repository can be committed to, and issues, comments and other entities can be created."
msgstr ""
msgid "The repository for this project does not exist."
@@ -24883,9 +25756,6 @@ msgstr ""
msgid "The time taken by each data entry gathered by that stage."
msgstr ""
-msgid "The total stage shows the time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The update action will time out after %{number_of_minutes} minutes. For big repositories, use a clone/push combination."
msgstr ""
@@ -24949,6 +25819,9 @@ msgstr ""
msgid "There are no archived requirements"
msgstr ""
+msgid "There are no archived test cases"
+msgstr ""
+
msgid "There are no changes"
msgstr ""
@@ -24988,6 +25861,9 @@ msgstr ""
msgid "There are no open requirements"
msgstr ""
+msgid "There are no open test cases"
+msgstr ""
+
msgid "There are no packages yet"
msgstr ""
@@ -25000,6 +25876,9 @@ msgstr ""
msgid "There is a limit of %{ci_project_subscriptions_limit} subscriptions from or to a project."
msgstr ""
+msgid "There is already a To-Do for this design."
+msgstr ""
+
msgid "There is already a repository with that name on disk"
msgstr ""
@@ -25018,6 +25897,9 @@ msgstr ""
msgid "There was a problem communicating with your device."
msgstr ""
+msgid "There was a problem fetching branches."
+msgstr ""
+
msgid "There was a problem fetching groups."
msgstr ""
@@ -25246,9 +26128,15 @@ msgstr ""
msgid "This action can lead to data loss. To prevent accidental actions we ask you to confirm your intention."
msgstr ""
+msgid "This action cannot be undone, and will permanently delete the %{key} SSH key"
+msgstr ""
+
msgid "This action cannot be undone. You will lose the project's repository and all content: issues, merge requests, etc."
msgstr ""
+msgid "This action has been performed too many times. Try again later."
+msgstr ""
+
msgid "This action will %{strongOpen}permanently delete%{strongClose} %{codeOpen}%{project}%{codeClose} %{strongOpen}immediately%{strongClose}, including its repositories and all content: issues, merge requests, etc."
msgstr ""
@@ -25276,9 +26164,6 @@ msgstr ""
msgid "This board's scope is reduced"
msgstr ""
-msgid "This branch has changed since you started editing. Would you like to create a new branch?"
-msgstr ""
-
msgid "This chart could not be displayed"
msgstr ""
@@ -25405,15 +26290,9 @@ msgstr ""
msgid "This is a security log of important events involving your account."
msgstr ""
-msgid "This is the author's first Merge Request to this project."
-msgstr ""
-
msgid "This is the highest peak of users on your installation since the license started."
msgstr ""
-msgid "This is the maximum number of users that have existed at the same time since the license started. This is the minimum number of seats you will need to buy when you renew your license."
-msgstr ""
-
msgid "This is the number of currently active users on your installation, and this is the minimum number you need to purchase when you renew your license."
msgstr ""
@@ -25645,6 +26524,15 @@ msgstr ""
msgid "This user has no identities"
msgstr ""
+msgid "This user has previously committed to the %{name} project."
+msgstr ""
+
+msgid "This user has the %{access} role in the %{name} project."
+msgstr ""
+
+msgid "This user is the author of this %{noteable}."
+msgstr ""
+
msgid "This user will be the author of all events in the activity feed that are the result of an update, like new branches being created or new commits being pushed to existing branches."
msgstr ""
@@ -25675,6 +26563,9 @@ msgstr ""
msgid "Threat Monitoring"
msgstr ""
+msgid "ThreatMonitoring|All Environments"
+msgstr ""
+
msgid "ThreatMonitoring|Anomalous Requests"
msgstr ""
@@ -25702,9 +26593,6 @@ msgstr ""
msgid "ThreatMonitoring|Operations Per Second"
msgstr ""
-msgid "ThreatMonitoring|Overview"
-msgstr ""
-
msgid "ThreatMonitoring|Packet Activity"
msgstr ""
@@ -25723,6 +26611,9 @@ msgstr ""
msgid "ThreatMonitoring|Something went wrong, unable to fetch statistics"
msgstr ""
+msgid "ThreatMonitoring|Statistics"
+msgstr ""
+
msgid "ThreatMonitoring|The firewall is not installed or has been disabled. To view this data, ensure the web application firewall is installed and enabled for your cluster."
msgstr ""
@@ -26114,6 +27005,9 @@ msgstr ""
msgid "To update Snippets with multiple files, you must use the `files` parameter"
msgstr ""
+msgid "To use Gitpod you must first enable the feature in the integrations section of your %{user_prefs}."
+msgstr ""
+
msgid "To view all %{scannedResourcesCount} scanned URLs, please download the CSV file"
msgstr ""
@@ -26147,9 +27041,6 @@ msgstr ""
msgid "Toggle Sidebar"
msgstr ""
-msgid "Toggle all threads"
-msgstr ""
-
msgid "Toggle backtrace"
msgstr ""
@@ -26174,9 +27065,6 @@ msgstr ""
msgid "Toggle navigation"
msgstr ""
-msgid "Toggle project"
-msgstr ""
-
msgid "Toggle sidebar"
msgstr ""
@@ -26216,6 +27104,9 @@ msgstr ""
msgid "Too many projects enabled. You will need to manage them via the console or the API."
msgstr ""
+msgid "Too much data"
+msgstr ""
+
msgid "Topics (optional)"
msgstr ""
@@ -26234,6 +27125,9 @@ msgstr ""
msgid "Total cores (CPUs)"
msgstr ""
+msgid "Total days to completion"
+msgstr ""
+
msgid "Total issues"
msgstr ""
@@ -26330,6 +27224,9 @@ msgstr ""
msgid "Trending"
msgstr ""
+msgid "Trials|Create a new group to start your GitLab Gold trial."
+msgstr ""
+
msgid "Trials|Go back to GitLab"
msgstr ""
@@ -26339,6 +27236,15 @@ msgstr ""
msgid "Trials|You can always resume this process by selecting your avatar and choosing 'Start a Gold trial'"
msgstr ""
+msgid "Trials|You can apply your trial to a new group or an existing group."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group or your personal account."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group, an existing group, or your personal account."
+msgstr ""
+
msgid "Trials|You won't get a free trial right now but you can always resume this process by clicking on your avatar and choosing 'Start a free trial'"
msgstr ""
@@ -26408,6 +27314,9 @@ msgstr ""
msgid "Try using a different search term to find the file you are looking for."
msgstr ""
+msgid "Trying to communicate with your device. Plug it in (if needed) and press the button on the device now."
+msgstr ""
+
msgid "Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now."
msgstr ""
@@ -26495,6 +27404,12 @@ msgstr ""
msgid "URL or request ID"
msgstr ""
+msgid "USER %{user} WILL BE REMOVED! Are you sure?"
+msgstr ""
+
+msgid "USER WILL BE BLOCKED! Are you sure?"
+msgstr ""
+
msgid "UTC"
msgstr ""
@@ -26552,9 +27467,6 @@ msgstr ""
msgid "Unable to load the merge request widget. Try reloading the page."
msgstr ""
-msgid "Unable to resolve"
-msgstr ""
-
msgid "Unable to save iteration. Please try again"
msgstr ""
@@ -26603,6 +27515,9 @@ msgstr ""
msgid "Undo ignore"
msgstr ""
+msgid "Unexpected error"
+msgstr ""
+
msgid "Unfortunately, your email message to GitLab could not be processed."
msgstr ""
@@ -26636,6 +27551,9 @@ msgstr ""
msgid "Unknown response text"
msgstr ""
+msgid "Unless otherwise agreed to in writing with GitLab, by clicking \"Upload License\" you agree that your use of GitLab Software is subject to the %{eula_link_start}Terms of Service%{eula_link_end}."
+msgstr ""
+
msgid "Unlimited"
msgstr ""
@@ -27002,9 +27920,6 @@ msgstr ""
msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
msgstr ""
-msgid "Use a hardware device to add the second factor of authentication."
-msgstr ""
-
msgid "Use an one time password authenticator on your mobile device or computer to enable two-factor authentication (2FA)."
msgstr ""
@@ -27278,13 +28193,13 @@ msgstr ""
msgid "Users"
msgstr ""
-msgid "Users in License:"
+msgid "Users in License"
msgstr ""
-msgid "Users or groups set as approvers in the project's or merge request's settings."
+msgid "Users in License:"
msgstr ""
-msgid "Users outside of license"
+msgid "Users or groups set as approvers in the project's or merge request's settings."
msgstr ""
msgid "Users over License:"
@@ -27302,9 +28217,6 @@ msgstr ""
msgid "Users with a Guest role or those who don't belong to a Project or Group will not use a seat from your license."
msgstr ""
-msgid "Users with a Guest role or those who don't belong to any projects or groups don't count towards seats in use."
-msgstr ""
-
msgid "UsersSelect|%{name} + %{length} more"
msgstr ""
@@ -27344,9 +28256,6 @@ msgstr ""
msgid "Validations failed."
msgstr ""
-msgid "Validity"
-msgstr ""
-
msgid "Value"
msgstr ""
@@ -27365,6 +28274,9 @@ msgstr ""
msgid "Value Stream Name"
msgstr ""
+msgid "ValueStreamAnalyticsStage|We don't have enough data to show this stage."
+msgstr ""
+
msgid "ValueStreamAnalytics|%{days}d"
msgstr ""
@@ -27621,6 +28533,9 @@ msgstr ""
msgid "VisualReviewApp|Steps 1 and 2 (and sometimes 3) are performed once by the developer before requesting feedback. Steps 3 (if necessary), 4 is performed by the reviewer each time they perform a review."
msgstr ""
+msgid "Visualization"
+msgstr ""
+
msgid "Vulnerabilities"
msgstr ""
@@ -27648,34 +28563,31 @@ msgstr ""
msgid "VulnerabilityChart|Severity"
msgstr ""
-msgid "VulnerabilityManagement|A true-positive and will fix"
-msgstr ""
-
-msgid "VulnerabilityManagement|Change status"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Confirm"
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|Confirmed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Detected %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|A true-positive and will fix"
msgstr ""
-msgid "VulnerabilityManagement|Dismiss"
+msgid "VulnerabilityManagement|Change status"
msgstr ""
-msgid "VulnerabilityManagement|Dismissed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
msgstr ""
-msgid "VulnerabilityManagement|Resolved"
+msgid "VulnerabilityManagement|Detected"
msgstr ""
-msgid "VulnerabilityManagement|Resolved %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Needs triage"
msgstr ""
msgid "VulnerabilityManagement|Something went wrong while trying to delete the comment. Please try again later."
@@ -27726,6 +28638,9 @@ msgstr ""
msgid "Vulnerability|%{scannerName} (version %{scannerVersion})"
msgstr ""
+msgid "Vulnerability|Activity"
+msgstr ""
+
msgid "Vulnerability|Class"
msgstr ""
@@ -27738,6 +28653,9 @@ msgstr ""
msgid "Vulnerability|Description"
msgstr ""
+msgid "Vulnerability|Detected"
+msgstr ""
+
msgid "Vulnerability|Evidence"
msgstr ""
@@ -27801,6 +28719,9 @@ msgstr ""
msgid "Warning: Displaying this diagram might cause performance issues on this page."
msgstr ""
+msgid "We are currently unable to fetch data for the pipeline header."
+msgstr ""
+
msgid "We are currently unable to fetch data for this graph."
msgstr ""
@@ -27840,6 +28761,12 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
+msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
+msgstr ""
+
+msgid "We would like to inform you that your subscription GitLab Enterprise Edition %{plan_name} is nearing its user limit. You have %{active_user_count} active users, which is almost at the user limit of %{maximum_user_count}."
+msgstr ""
+
msgid "We've found no vulnerabilities"
msgstr ""
@@ -27855,6 +28782,12 @@ msgstr ""
msgid "Web terminal"
msgstr ""
+msgid "WebAuthn Devices (%{length})"
+msgstr ""
+
+msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
+msgstr ""
+
msgid "WebIDE|Merge request"
msgstr ""
@@ -27993,15 +28926,9 @@ msgstr ""
msgid "Welcome to the guided GitLab tour"
msgstr ""
-msgid "Welcome to your Issue Board!"
-msgstr ""
-
msgid "Welcome to your issue board!"
msgstr ""
-msgid "We’ve been making changes to %{featureName} and we’d love your feedback %{linkStart}in this issue%{linkEnd} to help us improve the experience."
-msgstr ""
-
msgid "What are you searching for?"
msgstr ""
@@ -28020,6 +28947,9 @@ msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
msgstr ""
+msgid "When enabled, any user visiting %{host} and creating an account will have to be explicitly approved by the admin before they can login. This setting is effective only if sign-ups are enabled."
+msgstr ""
+
msgid "When enabled, any user visiting %{host} will be able to create an account."
msgstr ""
@@ -28244,6 +29174,9 @@ msgstr ""
msgid "With requirements, you can set criteria to check your products against."
msgstr ""
+msgid "With test cases, you can define conditions for your project to meet in determining quality"
+msgstr ""
+
msgid "Withdraw Access Request"
msgstr ""
@@ -28259,6 +29192,9 @@ msgstr ""
msgid "Workflow Help"
msgstr ""
+msgid "Would you like to create a new branch?"
+msgstr ""
+
msgid "Write"
msgstr ""
@@ -28280,6 +29216,9 @@ msgstr ""
msgid "Wrong extern UID provided. Make sure Auth0 is configured correctly."
msgstr ""
+msgid "YYYY-MM-DD"
+msgstr ""
+
msgid "Yes"
msgstr ""
@@ -28337,7 +29276,7 @@ msgstr ""
msgid "You are going to remove the fork relationship from %{project_full_name}. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "You are going to transfer %{project_full_name} to another owner. Are you ABSOLUTELY sure?"
+msgid "You are going to transfer %{project_full_name} to another namespace. Are you ABSOLUTELY sure?"
msgstr ""
msgid "You are going to turn off the confidentiality. This means %{strongStart}everyone%{strongEnd} will be able to see and leave a comment on this %{issuableType}."
@@ -28397,9 +29336,6 @@ msgstr ""
msgid "You can always edit this later"
msgstr ""
-msgid "You can apply your Trial to your Personal account or create a New Group."
-msgstr ""
-
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings"
msgstr ""
@@ -28421,12 +29357,18 @@ msgstr ""
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
+msgid "You can find more information about GitLab subscriptions in %{subscriptions_doc_link}."
+msgstr ""
+
msgid "You can generate an access token scoped to this project for each application to use the GitLab API."
msgstr ""
msgid "You can get started by cloning the repository or start adding files to it with one of the following options."
msgstr ""
+msgid "You can group test cases using labels. To learn about the future direction of this feature, visit %{linkStart}Quality Management direction page%{linkEnd}."
+msgstr ""
+
msgid "You can invite a new member to %{project_name} or invite another group."
msgstr ""
@@ -28442,6 +29384,9 @@ msgstr ""
msgid "You can notify the app / group or a project by sending them an email notification"
msgstr ""
+msgid "You can now close this window."
+msgstr ""
+
msgid "You can now export your security dashboard to a CSV report."
msgstr ""
@@ -28490,9 +29435,6 @@ msgstr ""
msgid "You can test your .gitlab-ci.yml in %{linkStart}CI Lint%{linkEnd}."
msgstr ""
-msgid "You can try again using %{begin_link}basic search%{end_link}"
-msgstr ""
-
msgid "You cannot access the raw file. Please wait a minute."
msgstr ""
@@ -28544,6 +29486,9 @@ msgstr ""
msgid "You don't have any U2F devices registered yet."
msgstr ""
+msgid "You don't have any WebAuthn devices registered yet."
+msgstr ""
+
msgid "You don't have any active chat names."
msgstr ""
@@ -28631,6 +29576,9 @@ msgstr ""
msgid "You must accept our Terms of Service and privacy policy in order to register an account"
msgstr ""
+msgid "You must be logged in to search across all of GitLab"
+msgstr ""
+
msgid "You must disassociate %{domain} from all clusters it is attached to before deletion."
msgstr ""
@@ -28670,7 +29618,7 @@ msgstr ""
msgid "You need to be logged in."
msgstr ""
-msgid "You need to register a two-factor authentication app before you can set up a U2F device."
+msgid "You need to register a two-factor authentication app before you can set up a device."
msgstr ""
msgid "You need to set terms to be enforced"
@@ -28688,6 +29636,9 @@ msgstr ""
msgid "You reached %{usage_in_percent} of %{namespace_name}'s storage capacity (%{used_storage} of %{storage_limit})"
msgstr ""
+msgid "You successfully declined the invitation"
+msgstr ""
+
msgid "You tried to fork %{link_to_the_project} but it failed for the following reason:"
msgstr ""
@@ -28853,10 +29804,13 @@ msgstr ""
msgid "Your U2F device did not send a valid JSON response."
msgstr ""
-msgid "Your U2F device needs to be set up. Plug it in (if not already) and click the button on the left."
+msgid "Your U2F device was registered!"
msgstr ""
-msgid "Your U2F device was registered!"
+msgid "Your WebAuthn device did not send a valid JSON response."
+msgstr ""
+
+msgid "Your WebAuthn device was registered!"
msgstr ""
msgid "Your access request to the %{source_type} has been withdrawn."
@@ -28880,6 +29834,9 @@ msgstr ""
msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
msgstr ""
+msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
+msgstr ""
+
msgid "Your changes can be committed to %{branch_name} because a merge request is open."
msgstr ""
@@ -28916,6 +29873,12 @@ msgstr ""
msgid "Your deployment services will be broken, you will need to manually fix the services after renaming."
msgstr ""
+msgid "Your device is not compatible with GitLab. Please try another device"
+msgstr ""
+
+msgid "Your device needs to be set up. Plug it in (if needed) and click the button on the left."
+msgstr ""
+
msgid "Your device was successfully set up! Give it a name and register it with the GitLab server."
msgstr ""
@@ -29029,9 +29992,6 @@ msgstr[1] ""
msgid "access:"
msgstr ""
-msgid "activated"
-msgstr ""
-
msgid "added %{created_at_timeago}"
msgstr ""
@@ -29104,9 +30064,21 @@ msgstr ""
msgid "by %{user}"
msgstr ""
+msgid "cannot be a date in the past"
+msgstr ""
+
msgid "cannot be changed if a personal project has container registry tags."
msgstr ""
+msgid "cannot be changed if shared runners are enabled"
+msgstr ""
+
+msgid "cannot be enabled because parent group does not allow it"
+msgstr ""
+
+msgid "cannot be enabled because parent group has shared Runners disabled"
+msgstr ""
+
msgid "cannot be enabled unless all domains have TLS certificates"
msgstr ""
@@ -29152,7 +30124,7 @@ msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about SAST %{linkEndTag}"
msgstr ""
-msgid "ciReport|%{linkStartTag}Learn more about Secret Scanning %{linkEndTag}"
+msgid "ciReport|%{linkStartTag}Learn more about Secret Detection %{linkEndTag}"
msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about codequality reports %{linkEndTag}"
@@ -29467,9 +30439,6 @@ msgstr ""
msgid "error"
msgstr ""
-msgid "error code:"
-msgstr ""
-
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr ""
@@ -29491,6 +30460,9 @@ msgstr ""
msgid "failed to dismiss associated finding(id=%{finding_id}): %{message}"
msgstr ""
+msgid "failed to revert associated finding(id=%{finding_id}) to detected"
+msgstr ""
+
msgid "file"
msgid_plural "files"
msgstr[0] ""
@@ -30033,6 +31005,9 @@ msgstr ""
msgid "must be a root namespace"
msgstr ""
+msgid "must be a valid IPv4 or IPv6 address"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -30069,6 +31044,9 @@ msgstr ""
msgid "no expiration"
msgstr ""
+msgid "no name set"
+msgstr ""
+
msgid "no one can merge"
msgstr ""
@@ -30247,9 +31225,6 @@ msgstr ""
msgid "security Reports|There was an error creating the merge request"
msgstr ""
-msgid "settings saved, but not activated"
-msgstr ""
-
msgid "severity|Critical"
msgstr ""
@@ -30376,9 +31351,6 @@ msgstr ""
msgid "toggle collapse"
msgstr ""
-msgid "toggle dropdown"
-msgstr ""
-
msgid "triggered"
msgstr ""
@@ -30406,6 +31378,9 @@ msgstr ""
msgid "user avatar"
msgstr ""
+msgid "user preferences"
+msgstr ""
+
msgid "username"
msgstr ""
diff --git a/locale/pa_IN/gitlab.po b/locale/pa_IN/gitlab.po
index 9c84359c181..9e1e60dd256 100644
--- a/locale/pa_IN/gitlab.po
+++ b/locale/pa_IN/gitlab.po
@@ -14,7 +14,10 @@ msgstr ""
"X-Crowdin-Language: pa-IN\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 6\n"
-"PO-Revision-Date: 2020-09-04 23:09\n"
+"PO-Revision-Date: 2020-10-02 18:49\n"
+
+msgid " %{project_name}#%{issue_iid} &middot; opened %{issue_created} by %{author}"
+msgstr ""
msgid " %{start} to %{end}"
msgstr ""
@@ -74,6 +77,16 @@ msgstr ""
msgid "\"el\" parameter is required for createInstance()"
msgstr ""
+msgid "%d Approval"
+msgid_plural "%d Approvals"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d Package"
+msgid_plural "%d Packages"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d Scanned URL"
msgid_plural "%d Scanned URLs"
msgstr[0] ""
@@ -137,6 +150,11 @@ msgstr[1] ""
msgid "%d commits"
msgstr ""
+msgid "%d completed issue"
+msgid_plural "%d completed issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d contribution"
msgid_plural "%d contributions"
msgstr[0] ""
@@ -147,6 +165,11 @@ msgid_plural "%d days"
msgstr[0] ""
msgstr[1] ""
+msgid "%d day until tags are automatically removed"
+msgid_plural "%d days until tags are automatically removed"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d error"
msgid_plural "%d errors"
msgstr[0] ""
@@ -237,6 +260,16 @@ msgid_plural "%d more comments"
msgstr[0] ""
msgstr[1] ""
+msgid "%d open issue"
+msgid_plural "%d open issues"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d pending comment"
+msgid_plural "%d pending comments"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d personal project will be removed and cannot be restored."
msgid_plural "%d personal projects will be removed and cannot be restored."
msgstr[0] ""
@@ -252,6 +285,11 @@ msgid_plural "%d projects"
msgstr[0] ""
msgstr[1] ""
+msgid "%d project selected"
+msgid_plural "%d projects selected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d request with warnings"
msgid_plural "%d requests with warnings"
msgstr[0] ""
@@ -272,6 +310,11 @@ msgid_plural "%d tags"
msgstr[0] ""
msgstr[1] ""
+msgid "%d tag per image name"
+msgid_plural "%d tags per image name"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d unassigned issue"
msgid_plural "%d unassigned issues"
msgstr[0] ""
@@ -292,6 +335,11 @@ msgid_plural "%d vulnerabilities dismissed"
msgstr[0] ""
msgstr[1] ""
+msgid "%d warning found:"
+msgid_plural "%d warnings found:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%s additional commit has been omitted to prevent performance issues."
msgid_plural "%s additional commits have been omitted to prevent performance issues."
msgstr[0] ""
@@ -330,6 +378,9 @@ msgstr ""
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr ""
+msgid "%{completedCount} completed weight"
+msgstr ""
+
msgid "%{completedWeight} of %{totalWeight} weight completed"
msgstr ""
@@ -378,14 +429,12 @@ msgid_plural "%{count} participants"
msgstr[0] ""
msgstr[1] ""
-msgid "%{count} pending comment"
-msgid_plural "%{count} pending comments"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
+msgid "%{count} total weight"
+msgstr ""
+
msgid "%{dashboard_path} could not be found."
msgstr ""
@@ -440,6 +489,9 @@ msgstr ""
msgid "%{group_name} uses group managed accounts. You need to create a new GitLab account which will be managed by %{group_name}."
msgstr ""
+msgid "%{group_name}&%{epic_iid} &middot; opened %{epic_created} by %{author}"
+msgstr ""
+
msgid "%{host} sign-in from new location"
msgstr ""
@@ -452,7 +504,7 @@ msgstr ""
msgid "%{issuableType} will be removed! Are you sure?"
msgstr ""
-msgid "%{issuesSize} issues with a limit of %{maxIssueCount}"
+msgid "%{issuesCount} issues with a limit of %{maxIssueCount}"
msgstr ""
msgid "%{issuesSize} with a limit of %{maxIssueCount}"
@@ -485,7 +537,7 @@ msgstr ""
msgid "%{labelStart}Namespace:%{labelEnd} %{namespace}"
msgstr ""
-msgid "%{labelStart}Report Type:%{labelEnd} %{reportType}"
+msgid "%{labelStart}Scan Type:%{labelEnd} %{reportType}"
msgstr ""
msgid "%{labelStart}Scanner:%{labelEnd} %{scanner}"
@@ -682,9 +734,6 @@ msgid_plural "%{securityScanner} results are not available because a pipeline ha
msgstr[0] ""
msgstr[1] ""
-msgid "%{service_title} %{message}."
-msgstr ""
-
msgid "%{size} GiB"
msgstr ""
@@ -773,6 +822,12 @@ msgstr ""
msgid "%{timebox_name} should belong either to a project or a group."
msgstr ""
+msgid "%{timebox_type} does not support burnup charts"
+msgstr ""
+
+msgid "%{timebox_type} must have a start and due date"
+msgstr ""
+
msgid "%{title} %{operator} %{threshold}"
msgstr ""
@@ -797,7 +852,7 @@ msgstr ""
msgid "%{total} open issue weight"
msgstr ""
-msgid "%{total} open issues"
+msgid "%{total} warnings found: showing first %{warningsDisplayed}"
msgstr ""
msgid "%{usage_ping_link_start}Learn more%{usage_ping_link_end} about what information is shared with GitLab Inc."
@@ -830,9 +885,6 @@ msgstr ""
msgid "&lt; 1 hour"
msgstr ""
-msgid "&lt;no name set&gt;"
-msgstr ""
-
msgid "&lt;no scopes selected&gt;"
msgstr ""
@@ -863,6 +915,9 @@ msgstr ""
msgid "'%{name}' Value Stream created"
msgstr ""
+msgid "'%{name}' Value Stream deleted"
+msgstr ""
+
msgid "'%{name}' stage already exists"
msgstr ""
@@ -922,6 +977,9 @@ msgstr ""
msgid "+ %{numberOfHiddenAssignees} more"
msgstr ""
+msgid "+ %{numberOfHiddenReviewers} more"
+msgstr ""
+
msgid "+%d more"
msgid_plural "+%d more"
msgstr[0] ""
@@ -982,6 +1040,11 @@ msgid_plural "%d Days"
msgstr[0] ""
msgstr[1] ""
+msgid "1 Issue"
+msgid_plural "%d Issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "1 closed issue"
msgid_plural "%{issues} closed issues"
msgstr[0] ""
@@ -997,6 +1060,11 @@ msgid_plural "%d days"
msgstr[0] ""
msgstr[1] ""
+msgid "1 deploy key"
+msgid_plural "%d deploy keys"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1099,6 +1167,9 @@ msgstr ""
msgid ":%{startLine} to %{endLine}"
msgstr ""
+msgid "A %{incident_docs_start}modified issue%{incident_docs_end} to guide the resolution of incidents."
+msgstr ""
+
msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr ""
@@ -1111,6 +1182,9 @@ msgstr ""
msgid "A GitBook site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
+msgid "A Gitpod configured Webapplication in Spring and Java"
+msgstr ""
+
msgid "A Hexo site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
@@ -1282,9 +1356,15 @@ msgstr ""
msgid "Access expiration date"
msgstr ""
+msgid "Access expires"
+msgstr ""
+
msgid "Access forbidden. Check your access level."
msgstr ""
+msgid "Access granted"
+msgstr ""
+
msgid "Access requests"
msgstr ""
@@ -1294,6 +1374,9 @@ msgstr ""
msgid "Access to Pages websites are controlled based on the user's membership to a given project. By checking this box, users will be required to be logged in to have access to all Pages websites in your instance."
msgstr ""
+msgid "AccessDropdown|Deploy Keys"
+msgstr ""
+
msgid "AccessDropdown|Groups"
msgstr ""
@@ -1411,12 +1494,6 @@ msgstr ""
msgid "Active Sessions"
msgstr ""
-msgid "Active Users:"
-msgstr ""
-
-msgid "Active users"
-msgstr ""
-
msgid "Activity"
msgstr ""
@@ -1584,9 +1661,6 @@ msgstr ""
msgid "Add label(s)"
msgstr ""
-msgid "Add license"
-msgstr ""
-
msgid "Add list"
msgstr ""
@@ -1761,21 +1835,51 @@ msgstr ""
msgid "AdminArea|Bots"
msgstr ""
+msgid "AdminArea|Components"
+msgstr ""
+
msgid "AdminArea|Developer"
msgstr ""
+msgid "AdminArea|Features"
+msgstr ""
+
+msgid "AdminArea|Groups: %{number_of_groups}"
+msgstr ""
+
msgid "AdminArea|Guest"
msgstr ""
msgid "AdminArea|Included Free in license"
msgstr ""
+msgid "AdminArea|Latest groups"
+msgstr ""
+
+msgid "AdminArea|Latest projects"
+msgstr ""
+
+msgid "AdminArea|Latest users"
+msgstr ""
+
msgid "AdminArea|Maintainer"
msgstr ""
+msgid "AdminArea|New group"
+msgstr ""
+
+msgid "AdminArea|New project"
+msgstr ""
+
+msgid "AdminArea|New user"
+msgstr ""
+
msgid "AdminArea|Owner"
msgstr ""
+msgid "AdminArea|Projects: %{number_of_projects}"
+msgstr ""
+
msgid "AdminArea|Reporter"
msgstr ""
@@ -1803,6 +1907,9 @@ msgstr ""
msgid "AdminArea|Users without a Group and Project"
msgstr ""
+msgid "AdminArea|Users: %{number_of_users}"
+msgstr ""
+
msgid "AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running."
msgstr ""
@@ -1821,9 +1928,6 @@ msgstr ""
msgid "AdminProjects|Delete Project %{projectName}?"
msgstr ""
-msgid "AdminProjects|Delete project"
-msgstr ""
-
msgid "AdminSettings|Apply integration settings to all Projects"
msgstr ""
@@ -2061,21 +2165,30 @@ msgstr ""
msgid "AdminUsers|Without projects"
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 ""
msgid "AdminUsers|You cannot remove your own admin rights."
msgstr ""
+msgid "AdminUsers|You must transfer ownership or delete the groups owned by this user before you can delete their account"
+msgstr ""
+
msgid "Administration"
msgstr ""
msgid "Advanced"
msgstr ""
+msgid "Advanced Search"
+msgstr ""
+
+msgid "Advanced Search with Elasticsearch"
+msgstr ""
+
msgid "Advanced Settings"
msgstr ""
@@ -2153,6 +2266,9 @@ msgstr ""
msgid "AlertManagement|Edit"
msgstr ""
+msgid "AlertManagement|Environment"
+msgstr ""
+
msgid "AlertManagement|Events"
msgstr ""
@@ -2165,6 +2281,9 @@ msgstr ""
msgid "AlertManagement|Issue"
msgstr ""
+msgid "AlertManagement|Key"
+msgstr ""
+
msgid "AlertManagement|Low"
msgstr ""
@@ -2258,6 +2377,9 @@ msgstr ""
msgid "AlertManagement|Unknown"
msgstr ""
+msgid "AlertManagement|Value"
+msgstr ""
+
msgid "AlertManagement|View alerts in Opsgenie"
msgstr ""
@@ -2417,6 +2539,9 @@ msgstr ""
msgid "All projects"
msgstr ""
+msgid "All projects selected"
+msgstr ""
+
msgid "All security scans are enabled because %{linkStart}Auto DevOps%{linkEnd} is enabled on this project"
msgstr ""
@@ -2504,6 +2629,9 @@ msgstr ""
msgid "Almost there"
msgstr ""
+msgid "Already blocked"
+msgstr ""
+
msgid "Also called \"Issuer\" or \"Relying party trust identifier\""
msgstr ""
@@ -2558,6 +2686,9 @@ msgstr ""
msgid "An error has occurred"
msgstr ""
+msgid "An error occured while making the changes: %{error}"
+msgstr ""
+
msgid "An error occurred adding a draft to the thread."
msgstr ""
@@ -2585,12 +2716,6 @@ msgstr ""
msgid "An error occurred when toggling the notification subscription"
msgstr ""
-msgid "An error occurred when trying to resolve a comment. Please try again."
-msgstr ""
-
-msgid "An error occurred when trying to resolve a discussion. Please try again."
-msgstr ""
-
msgid "An error occurred when updating the issue weight"
msgstr ""
@@ -2606,12 +2731,6 @@ msgstr ""
msgid "An error occurred while checking group path. Please refresh and try again."
msgstr ""
-msgid "An error occurred while committing your changes."
-msgstr ""
-
-msgid "An error occurred while creating the list. Please try again."
-msgstr ""
-
msgid "An error occurred while decoding the file."
msgstr ""
@@ -2684,25 +2803,19 @@ msgstr ""
msgid "An error occurred while fetching the Service Desk address."
msgstr ""
-msgid "An error occurred while fetching the board issues. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the board lists. Please reload the page."
msgstr ""
msgid "An error occurred while fetching the board lists. Please try again."
msgstr ""
-msgid "An error occurred while fetching the board swimlanes. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the builds."
msgstr ""
msgid "An error occurred while fetching the job log."
msgstr ""
-msgid "An error occurred while fetching the job trace."
+msgid "An error occurred while fetching the job logs."
msgstr ""
msgid "An error occurred while fetching the job."
@@ -2849,9 +2962,6 @@ msgstr ""
msgid "An error occurred while saving assignees"
msgstr ""
-msgid "An error occurred while saving the template. Please check if the template exists."
-msgstr ""
-
msgid "An error occurred while searching for milestones"
msgstr ""
@@ -2870,10 +2980,10 @@ msgstr ""
msgid "An error occurred while updating approvers"
msgstr ""
-msgid "An error occurred while updating the comment"
+msgid "An error occurred while updating labels."
msgstr ""
-msgid "An error occurred while updating the list. Please try again."
+msgid "An error occurred while updating the comment"
msgstr ""
msgid "An error occurred while validating group path"
@@ -2927,6 +3037,9 @@ msgstr ""
msgid "An unknown error occurred while loading this graph."
msgstr ""
+msgid "An unknown error occurred."
+msgstr ""
+
msgid "Analytics"
msgstr ""
@@ -2960,10 +3073,10 @@ msgstr ""
msgid "Any"
msgstr ""
-msgid "Any Author"
+msgid "Any %{header}"
msgstr ""
-msgid "Any Status"
+msgid "Any Author"
msgstr ""
msgid "Any branch"
@@ -3017,6 +3130,9 @@ msgstr ""
msgid "Application ID"
msgstr ""
+msgid "Application limits saved successfully"
+msgstr ""
+
msgid "Application settings saved successfully"
msgstr ""
@@ -3226,6 +3342,9 @@ msgstr ""
msgid "Are you sure you want to close this blocked issue?"
msgstr ""
+msgid "Are you sure you want to delete \"%{name}\" Value Stream?"
+msgstr ""
+
msgid "Are you sure you want to delete %{name}?"
msgstr ""
@@ -3235,6 +3354,9 @@ msgstr ""
msgid "Are you sure you want to delete this %{typeOfComment}?"
msgstr ""
+msgid "Are you sure you want to delete this SSH key?"
+msgstr ""
+
msgid "Are you sure you want to delete this board?"
msgstr ""
@@ -3259,6 +3381,11 @@ msgstr ""
msgid "Are you sure you want to erase this build?"
msgstr ""
+msgid "Are you sure you want to import %d repository?"
+msgid_plural "Are you sure you want to import %d repositories?"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Are you sure you want to lose unsaved changes?"
msgstr ""
@@ -3268,15 +3395,15 @@ msgstr ""
msgid "Are you sure you want to merge immediately?"
msgstr ""
-msgid "Are you sure you want to permanently delete this license?"
-msgstr ""
-
msgid "Are you sure you want to re-deploy this environment?"
msgstr ""
msgid "Are you sure you want to regenerate the public key? You will have to update the public key on the remote server before mirroring will work again."
msgstr ""
+msgid "Are you sure you want to reindex?"
+msgstr ""
+
msgid "Are you sure you want to remove %{group_name}?"
msgstr ""
@@ -3304,6 +3431,9 @@ msgstr ""
msgid "Are you sure you want to revoke this nickname?"
msgstr ""
+msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
+msgstr ""
+
msgid "Are you sure you want to stop this environment?"
msgstr ""
@@ -3325,6 +3455,9 @@ msgstr ""
msgid "Are you sure? The device will be signed out of GitLab and all remember me tokens revoked."
msgstr ""
+msgid "Are you sure? This will invalidate your registered applications and U2F / WebAuthn devices."
+msgstr ""
+
msgid "Are you sure? This will invalidate your registered applications and U2F devices."
msgstr ""
@@ -3343,9 +3476,6 @@ msgstr ""
msgid "Artifacts"
msgstr ""
-msgid "As U2F devices are only supported by a few browsers, we require that you set up a two-factor authentication app before a U2F device. That way you'll always be able to log in - even when you're using an unsupported browser."
-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 ""
@@ -3539,6 +3669,9 @@ msgstr ""
msgid "AuditLogs|Target"
msgstr ""
+msgid "AuditLogs|This month"
+msgstr ""
+
msgid "AuditLogs|User Events"
msgstr ""
@@ -3578,6 +3711,9 @@ msgstr ""
msgid "Authentication via U2F device failed."
msgstr ""
+msgid "Authentication via WebAuthn device failed."
+msgstr ""
+
msgid "Author"
msgstr ""
@@ -3845,15 +3981,6 @@ msgstr ""
msgid "BambooService|You must set up automatic revision labeling and a repository trigger in Bamboo."
msgstr ""
-msgid "BatchComments|Delete all pending comments"
-msgstr ""
-
-msgid "BatchComments|Discard review?"
-msgstr ""
-
-msgid "BatchComments|You're about to discard your review which will delete all of your pending comments. The deleted comments %{strong_start}cannot%{strong_end} be restored."
-msgstr ""
-
msgid "Be careful. Changing the project's namespace can have unintended side effects."
msgstr ""
@@ -3875,6 +4002,9 @@ msgstr ""
msgid "Bi-weekly code coverage"
msgstr ""
+msgid "Billable Users:"
+msgstr ""
+
msgid "Billing"
msgstr ""
@@ -3884,7 +4014,7 @@ msgstr ""
msgid "BillingPlans|@%{user_name} you are currently using the %{plan_name} plan."
msgstr ""
-msgid "BillingPlans|Congratulations, your new trial is activated"
+msgid "BillingPlans|Congratulations, your free trial is activated."
msgstr ""
msgid "BillingPlans|If you would like to downgrade your plan please contact %{support_link_start}Customer Support%{support_link_end}."
@@ -3947,6 +4077,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Block user"
+msgstr ""
+
msgid "Blocked"
msgstr ""
@@ -3962,31 +4095,37 @@ msgstr ""
msgid "Blog"
msgstr ""
-msgid "Board name"
-msgstr ""
-
msgid "Board scope"
msgstr ""
msgid "Board scope affects which issues are displayed for anyone who visits this board"
msgstr ""
-msgid "BoardBlankState|Add default lists"
+msgid "Boards"
msgstr ""
-msgid "BoardBlankState|Add the following default lists to your Issue Board with one click:"
+msgid "Boards and Board Lists"
msgstr ""
-msgid "BoardBlankState|Nevermind, I'll use my own"
+msgid "Boards|An error occurred while creating the issue. Please try again."
msgstr ""
-msgid "BoardBlankState|Starting out with the default set of lists will get you right on the way to making the most of your board."
+msgid "Boards|An error occurred while creating the list. Please try again."
msgstr ""
-msgid "Boards"
+msgid "Boards|An error occurred while fetching issues. Please reload the page."
msgstr ""
-msgid "Boards and Board Lists"
+msgid "Boards|An error occurred while fetching the board issues. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching the board swimlanes. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while moving the issue. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while updating the list. Please try again."
msgstr ""
msgid "Boards|Collapse"
@@ -4013,7 +4152,7 @@ msgstr ""
msgid "Branch %{branch_name} was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr ""
-msgid "Branch has changed"
+msgid "Branch changed"
msgstr ""
msgid "Branch is already taken"
@@ -4319,6 +4458,9 @@ msgstr ""
msgid "CLOSED (MOVED)"
msgstr ""
+msgid "CODEOWNERS rule violation"
+msgstr ""
+
msgid "CONTRIBUTING"
msgstr ""
@@ -4349,9 +4491,6 @@ msgstr ""
msgid "Can't create snippet: %{err}"
msgstr ""
-msgid "Can't edit as source branch was deleted"
-msgstr ""
-
msgid "Can't fetch content for the blob: %{err}"
msgstr ""
@@ -4364,9 +4503,6 @@ msgstr ""
msgid "Can't load mermaid module: %{err}"
msgstr ""
-msgid "Can't remove group members without group managed account"
-msgstr ""
-
msgid "Can't scan the code?"
msgstr ""
@@ -4409,6 +4545,9 @@ msgstr ""
msgid "Cannot create the abuse report. This user has been blocked."
msgstr ""
+msgid "Cannot enable shared runners because parent group does not allow it"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -4514,6 +4653,15 @@ msgstr ""
msgid "Change your password or recover your current one"
msgstr ""
+msgid "ChangeReviewer|Reviewer changed from %{old} to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Reviewer changed to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Unassigned"
+msgstr ""
+
msgid "ChangeTypeActionLabel|Pick into branch"
msgstr ""
@@ -4553,6 +4701,9 @@ msgstr ""
msgid "Changes the title to \"%{title_param}\"."
msgstr ""
+msgid "Changes were successfully made."
+msgstr ""
+
msgid "Changes won't take place until the index is %{link_start}recreated%{link_end}."
msgstr ""
@@ -4958,6 +5109,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove variable"
+msgstr ""
+
msgid "CiVariables|Remove variable row"
msgstr ""
@@ -5036,9 +5190,6 @@ msgstr ""
msgid "Clear due date"
msgstr ""
-msgid "Clear input"
-msgstr ""
-
msgid "Clear recent searches"
msgstr ""
@@ -5087,6 +5238,9 @@ msgstr ""
msgid "Client authentication key password"
msgstr ""
+msgid "Client request timeout"
+msgstr ""
+
msgid "Clients"
msgstr ""
@@ -5171,6 +5325,27 @@ msgstr ""
msgid "Cluster type must be specificed for Stages::ClusterEndpointInserter"
msgstr ""
+msgid "ClusterAgents|Configuration"
+msgstr ""
+
+msgid "ClusterAgents|Connect your cluster with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate Kubernetes with a GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Name"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Agent also requires %{linkStart}enabling the Agent Server%{linkEnd}"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Kubernetes Agent allows an Infrastructure as Code, GitOps approach to integrating Kubernetes clusters with GitLab. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "ClusterAgent|This feature is only available for premium plans"
msgstr ""
@@ -5240,10 +5415,10 @@ msgstr ""
msgid "ClusterIntegration|All installed applications and related resources"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster."
+msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{linkStart}More information%{linkEnd}"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{startLink}More information%{endLink}"
+msgid "ClusterIntegration|Allow GitLab to manage namespaces and service accounts for this cluster."
msgstr ""
msgid "ClusterIntegration|Alternatively, "
@@ -5264,6 +5439,9 @@ msgstr ""
msgid "ClusterIntegration|An error occurred while trying to fetch zone machine types: %{error}"
msgstr ""
+msgid "ClusterIntegration|An unknown error occurred while attempting to connect to Kubernetes."
+msgstr ""
+
msgid "ClusterIntegration|Any project namespaces"
msgstr ""
@@ -5279,6 +5457,9 @@ msgstr ""
msgid "ClusterIntegration|Authenticate with Amazon Web Services"
msgstr ""
+msgid "ClusterIntegration|Authentication Error"
+msgstr ""
+
msgid "ClusterIntegration|Base domain"
msgstr ""
@@ -5297,13 +5478,22 @@ msgstr ""
msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}security group %{externalLinkIcon} %{endLink} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
+msgid "ClusterIntegration|Check your CA certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Check your cluster status"
+msgstr ""
+
+msgid "ClusterIntegration|Check your token"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}subnets %{externalLinkIcon} %{endLink} in your VPC where your worker nodes will run."
+msgid "ClusterIntegration|Choose the %{linkStart}security group %{linkEnd} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
msgstr ""
-msgid "ClusterIntegration|Choose the worker node %{startLink}instance type %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Choose the %{linkStart}subnets %{linkEnd} in your VPC where your worker nodes will run."
+msgstr ""
+
+msgid "ClusterIntegration|Choose the worker node %{linkStart}instance type%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Choose which applications to install on your Kubernetes cluster."
@@ -5315,10 +5505,7 @@ msgstr ""
msgid "ClusterIntegration|Clear cluster cache"
msgstr ""
-msgid "ClusterIntegration|Clear the local cache of namespace and service accounts. This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
-msgstr ""
-
-msgid "ClusterIntegration|Cluster being created"
+msgid "ClusterIntegration|Clear the local cache of namespace and service accounts."
msgstr ""
msgid "ClusterIntegration|Cluster management project (alpha)"
@@ -5330,15 +5517,21 @@ msgstr ""
msgid "ClusterIntegration|Cluster_applications artifact too big. Maximum allowable size: %{human_size}"
msgstr ""
-msgid "ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters."
+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|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}"
+msgid "ClusterIntegration|Clusters connected with a certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Connect cluster with certificate"
msgstr ""
msgid "ClusterIntegration|Connect existing cluster"
msgstr ""
+msgid "ClusterIntegration|Connection Error"
+msgstr ""
+
msgid "ClusterIntegration|Copy API URL"
msgstr ""
@@ -5414,6 +5607,12 @@ msgstr ""
msgid "ClusterIntegration|Deletes all GitLab resources attached to this cluster during removal"
msgstr ""
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared."
+msgstr ""
+
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared. %{linkStart}More information%{linkEnd}"
+msgstr ""
+
msgid "ClusterIntegration|Did you know?"
msgstr ""
@@ -5483,6 +5682,9 @@ msgstr ""
msgid "ClusterIntegration|Fluentd is an open source data collector, which lets you unify the data collection and consumption for a better use and understanding of data. It requires at least one of the following logs to be successfully installed."
msgstr ""
+msgid "ClusterIntegration|GitLab Agent managed clusters"
+msgstr ""
+
msgid "ClusterIntegration|GitLab Container Network Policies"
msgstr ""
@@ -5495,6 +5697,12 @@ msgstr ""
msgid "ClusterIntegration|GitLab Runner connects to the repository and executes CI/CD jobs, pushing results back and deploying applications to production."
msgstr ""
+msgid "ClusterIntegration|GitLab failed to authenticate."
+msgstr ""
+
+msgid "ClusterIntegration|GitLab failed to connect to the cluster."
+msgstr ""
+
msgid "ClusterIntegration|GitLab-managed cluster"
msgstr ""
@@ -5516,6 +5724,9 @@ msgstr ""
msgid "ClusterIntegration|Group cluster"
msgstr ""
+msgid "ClusterIntegration|HTTP Error"
+msgstr ""
+
msgid "ClusterIntegration|Helm Tiller"
msgstr ""
@@ -5549,7 +5760,10 @@ msgstr ""
msgid "ClusterIntegration|Instance type"
msgstr ""
-msgid "ClusterIntegration|Integrate Kubernetes cluster automation"
+msgid "ClusterIntegration|Integrate Kubernetes with a cluster certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Integrate with a cluster certificate"
msgstr ""
msgid "ClusterIntegration|Issuer Email"
@@ -5585,9 +5799,6 @@ msgstr ""
msgid "ClusterIntegration|Knative extends Kubernetes to provide a set of middleware components that are essential to build modern, source-centric, and container-based applications that can run anywhere: on premises, in the cloud, or even in a third-party data center."
msgstr ""
-msgid "ClusterIntegration|Kubernetes cluster"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes cluster is being created..."
msgstr ""
@@ -5600,9 +5811,6 @@ msgstr ""
msgid "ClusterIntegration|Kubernetes clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr ""
-msgid "ClusterIntegration|Kubernetes clusters can be used to deploy applications and to provide Review Apps for this project"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes version"
msgstr ""
@@ -5615,7 +5823,7 @@ msgstr ""
msgid "ClusterIntegration|Learn more about %{help_link_start}zones%{help_link_end}."
msgstr ""
-msgid "ClusterIntegration|Learn more about %{startLink}Regions %{externalLinkIcon}%{endLink}."
+msgid "ClusterIntegration|Learn more about %{linkStart}Regions%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Learn more about Kubernetes"
@@ -5660,12 +5868,18 @@ msgstr ""
msgid "ClusterIntegration|Machine type"
msgstr ""
+msgid "ClusterIntegration|Make sure your API endpoint is correct"
+msgstr ""
+
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create Kubernetes clusters"
msgstr ""
msgid "ClusterIntegration|Manage your Kubernetes cluster by visiting %{provider_link}"
msgstr ""
+msgid "ClusterIntegration|Namespace per environment"
+msgstr ""
+
msgid "ClusterIntegration|No IAM Roles found"
msgstr ""
@@ -5711,6 +5925,9 @@ msgstr ""
msgid "ClusterIntegration|No zones matched your search"
msgstr ""
+msgid "ClusterIntegration|Node calculations use the Kubernetes Metrics API. Make sure your cluster has metrics installed"
+msgstr ""
+
msgid "ClusterIntegration|Number of nodes"
msgstr ""
@@ -5753,6 +5970,9 @@ msgstr ""
msgid "ClusterIntegration|RBAC-enabled cluster"
msgstr ""
+msgid "ClusterIntegration|Read our %{linkStart}help page%{linkEnd} on Kubernetes cluster integration."
+msgstr ""
+
msgid "ClusterIntegration|Read our %{link_start}help page%{link_end} on Kubernetes cluster integration."
msgstr ""
@@ -5855,7 +6075,7 @@ msgstr ""
msgid "ClusterIntegration|Select a VPC to choose a subnet"
msgstr ""
-msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{linkStart}Amazon Web Services %{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select a network to choose a subnetwork"
@@ -5888,7 +6108,7 @@ msgstr ""
msgid "ClusterIntegration|Select project to choose zone"
msgstr ""
-msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select zone"
@@ -5978,9 +6198,18 @@ msgstr ""
msgid "ClusterIntegration|There was a problem authenticating with your cluster. Please ensure your CA Certificate and Token are valid."
msgstr ""
+msgid "ClusterIntegration|There was an HTTP error when connecting to your cluster."
+msgstr ""
+
msgid "ClusterIntegration|This account must have permissions to create a Kubernetes cluster in the %{link_to_container_project} specified below"
msgstr ""
+msgid "ClusterIntegration|This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
+msgstr ""
+
+msgid "ClusterIntegration|This is necessary to clear existing environment-namespace associations from clusters previously managed by GitLab."
+msgstr ""
+
msgid "ClusterIntegration|This option will allow you to install applications on RBAC clusters."
msgstr ""
@@ -6005,9 +6234,21 @@ msgstr ""
msgid "ClusterIntegration|To use a new project, first create one on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}."
msgstr ""
+msgid "ClusterIntegration|Troubleshooting tips:"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Authenticate"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Connect"
+msgstr ""
+
msgid "ClusterIntegration|Uninstall %{appTitle}"
msgstr ""
+msgid "ClusterIntegration|Unknown Error"
+msgstr ""
+
msgid "ClusterIntegration|Update %{appTitle}"
msgstr ""
@@ -6068,7 +6309,7 @@ msgstr ""
msgid "ClusterIntegration|Your cluster API is unreachable. Please ensure your API URL is correct."
msgstr ""
-msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Zone"
@@ -6188,6 +6429,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse all threads"
+msgstr ""
+
msgid "Collapse approvers"
msgstr ""
@@ -6337,7 +6581,7 @@ msgstr ""
msgid "Commit…"
msgstr ""
-msgid "Company"
+msgid "Community forum"
msgstr ""
msgid "Company name"
@@ -6346,6 +6590,9 @@ msgstr ""
msgid "Compare"
msgstr ""
+msgid "Compare %{oldCommitId}...%{newCommitId}"
+msgstr ""
+
msgid "Compare Git revisions"
msgstr ""
@@ -6361,6 +6608,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare submodule commit revisions"
+msgstr ""
+
msgid "Compare with previous version"
msgstr ""
@@ -6496,6 +6746,9 @@ msgstr ""
msgid "Configure the way a user creates a new account."
msgstr ""
+msgid "Configure which lists are shown for anyone who visits this board"
+msgstr ""
+
msgid "Confirm"
msgstr ""
@@ -6721,6 +6974,9 @@ msgstr[1] ""
msgid "ContainerRegistry|Set cleanup policy"
msgstr ""
+msgid "ContainerRegistry|Some tags were not deleted"
+msgstr ""
+
msgid "ContainerRegistry|Something went wrong while fetching the cleanup policy."
msgstr ""
@@ -6760,6 +7016,9 @@ msgstr ""
msgid "ContainerRegistry|Tags with names matching this regex pattern will %{italicStart}expire:%{italicEnd}"
msgstr ""
+msgid "ContainerRegistry|The cleanup policy timed out before it could delete all tags. An administrator can %{adminLinkStart}manually run cleanup now%{adminLinkEnd} or you can wait for the cleanup policy to automatically run again. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "ContainerRegistry|The last tag related to this image was recently removed. This empty image and any associated data will be automatically removed as part of the regular Garbage Collection process. If you have any questions, contact your administrator."
msgstr ""
@@ -6892,6 +7151,9 @@ msgstr ""
msgid "Contributions per group member"
msgstr ""
+msgid "Contributor"
+msgstr ""
+
msgid "Contributors"
msgstr ""
@@ -7021,6 +7283,9 @@ msgstr ""
msgid "Could not change HEAD: branch '%{branch}' does not exist"
msgstr ""
+msgid "Could not commit. An unexpected error occurred."
+msgstr ""
+
msgid "Could not connect to FogBugz, check your URL"
msgstr ""
@@ -7060,6 +7325,9 @@ msgstr ""
msgid "Could not find iteration"
msgstr ""
+msgid "Could not load instance counts. Please refresh the page to try again."
+msgstr ""
+
msgid "Could not remove the trigger."
msgstr ""
@@ -7084,10 +7352,10 @@ msgstr ""
msgid "Could not save prometheus manual configuration"
msgstr ""
-msgid "Could not udpdate wiki page"
+msgid "Could not update the LDAP settings"
msgstr ""
-msgid "Could not update the LDAP settings"
+msgid "Could not update wiki page"
msgstr ""
msgid "Could not upload your designs as one or more files uploaded are not supported."
@@ -7745,6 +8013,9 @@ msgstr ""
msgid "DastProfiles|Are you sure you want to delete this profile?"
msgstr ""
+msgid "DastProfiles|Could not create site validation token. Please refresh the page, or try again later."
+msgstr ""
+
msgid "DastProfiles|Could not create the scanner profile. Please try again."
msgstr ""
@@ -7769,6 +8040,12 @@ msgstr ""
msgid "DastProfiles|Could not fetch site profiles. Please refresh the page, or try again later."
msgstr ""
+msgid "DastProfiles|Could not retrieve site validation status. Please refresh the page, or try again later."
+msgstr ""
+
+msgid "DastProfiles|Could not update the scanner profile. Please try again."
+msgstr ""
+
msgid "DastProfiles|Could not update the site profile. Please try again."
msgstr ""
@@ -7784,7 +8061,7 @@ msgstr ""
msgid "DastProfiles|Download validation text file"
msgstr ""
-msgid "DastProfiles|Edit feature will come soon. Please create a new profile if changes needed"
+msgid "DastProfiles|Edit scanner profile"
msgstr ""
msgid "DastProfiles|Edit site profile"
@@ -7817,6 +8094,9 @@ msgstr ""
msgid "DastProfiles|No profiles created yet"
msgstr ""
+msgid "DastProfiles|Passive"
+msgstr ""
+
msgid "DastProfiles|Please enter a valid URL format, ex: http://www.example.com/home"
msgstr ""
@@ -7832,6 +8112,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan mode"
+msgstr ""
+
msgid "DastProfiles|Scanner Profile"
msgstr ""
@@ -7871,10 +8154,10 @@ msgstr ""
msgid "DastProfiles|Text file validation"
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
+msgid "DastProfiles|The maximum number of minutes allowed for the spider to traverse the site."
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the spider to traverse the site."
+msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
msgstr ""
msgid "DastProfiles|Validate"
@@ -7907,6 +8190,9 @@ msgstr ""
msgid "Date picker"
msgstr ""
+msgid "Date range"
+msgstr ""
+
msgid "Date range cannot exceed %{maxDateRange} days."
msgstr ""
@@ -7931,6 +8217,9 @@ msgstr ""
msgid "Days to merge"
msgstr ""
+msgid "Dear Administrator,"
+msgstr ""
+
msgid "Debug"
msgstr ""
@@ -8042,12 +8331,18 @@ msgstr ""
msgid "Delete"
msgstr ""
+msgid "Delete %{name}"
+msgstr ""
+
msgid "Delete Comment"
msgstr ""
msgid "Delete Snippet"
msgstr ""
+msgid "Delete Value Stream"
+msgstr ""
+
msgid "Delete account"
msgstr ""
@@ -8069,9 +8364,6 @@ msgstr ""
msgid "Delete label: %{label_name} ?"
msgstr ""
-msgid "Delete license"
-msgstr ""
-
msgid "Delete list"
msgstr ""
@@ -8147,15 +8439,6 @@ msgstr ""
msgid "Deleting a project places it into a read-only state until %{date}, at which point the project will be permanently deleted. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "Deleting the license failed."
-msgstr ""
-
-msgid "Deleting the license failed. The license was not found."
-msgstr ""
-
-msgid "Deleting the license failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "Deleting the project will delete its repository and all related resources including issues, merge requests etc."
msgstr ""
@@ -8651,7 +8934,10 @@ msgstr ""
msgid "DesignManagement|The maximum number of designs allowed to be uploaded is %{upload_limit}. Please try again."
msgstr ""
-msgid "DesignManagement|To upload designs, you'll need to enable LFS. %{requirements_link_start}More information%{requirements_link_end}"
+msgid "DesignManagement|There was an error moving your designs. Please upload your designs below."
+msgstr ""
+
+msgid "DesignManagement|To upload designs, you'll need to enable LFS and have admin enable hashed storage. %{requirements_link_start}More information%{requirements_link_end}"
msgstr ""
msgid "DesignManagement|Unresolve thread"
@@ -8663,6 +8949,9 @@ msgstr ""
msgid "DesignManagement|Upload skipped."
msgstr ""
+msgid "DesignManagement|Your designs are being copied and are on their way… Please refresh to update."
+msgstr ""
+
msgid "DesignManagement|and %{moreCount} more."
msgstr ""
@@ -8720,6 +9009,9 @@ msgstr ""
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
+msgid "Direct member"
+msgstr ""
+
msgid "Direction"
msgstr ""
@@ -8768,9 +9060,6 @@ msgstr ""
msgid "Discard draft"
msgstr ""
-msgid "Discard review"
-msgstr ""
-
msgid "DiscordService|Discord Notifications"
msgstr ""
@@ -8839,10 +9128,10 @@ msgstr ""
msgid "Dismiss Merge Request promotion"
msgstr ""
-msgid "Dismiss Selected"
+msgid "Dismiss Value Stream Analytics introduction box"
msgstr ""
-msgid "Dismiss Value Stream Analytics introduction box"
+msgid "Dismiss selected"
msgstr ""
msgid "Dismiss trial promotion"
@@ -8893,9 +9182,6 @@ msgstr ""
msgid "Documents reindexed: %{processed_documents} (%{percentage}%%)"
msgstr ""
-msgid "Doing"
-msgstr ""
-
msgid "Domain"
msgstr ""
@@ -9091,9 +9377,6 @@ msgstr ""
msgid "Edit environment"
msgstr ""
-msgid "Edit file"
-msgstr ""
-
msgid "Edit files in the editor and commit changes here"
msgstr ""
@@ -9106,6 +9389,12 @@ msgstr ""
msgid "Edit identity for %{user_name}"
msgstr ""
+msgid "Edit in Web IDE"
+msgstr ""
+
+msgid "Edit in single-file editor"
+msgstr ""
+
msgid "Edit issues"
msgstr ""
@@ -9133,10 +9422,10 @@ msgstr ""
msgid "Editing"
msgstr ""
-msgid "Elasticsearch"
+msgid "Elasticsearch AWS IAM credentials"
msgstr ""
-msgid "Elasticsearch AWS IAM credentials"
+msgid "Elasticsearch HTTP client timeout value in seconds."
msgstr ""
msgid "Elasticsearch indexing restrictions"
@@ -9145,9 +9434,6 @@ msgstr ""
msgid "Elasticsearch indexing started"
msgstr ""
-msgid "Elasticsearch integration. Elasticsearch AWS IAM."
-msgstr ""
-
msgid "Elasticsearch reindexing is already in progress"
msgstr ""
@@ -9175,9 +9461,6 @@ msgstr ""
msgid "Email Notification"
msgstr ""
-msgid "Email address"
-msgstr ""
-
msgid "Email could not be sent"
msgstr ""
@@ -9241,6 +9524,9 @@ msgstr ""
msgid "Emails sent from Service Desk will have this name"
msgstr ""
+msgid "Emails sent to %{email} will still be supported"
+msgstr ""
+
msgid "Emails separated by comma"
msgstr ""
@@ -9274,9 +9560,18 @@ msgstr ""
msgid "Enable"
msgstr ""
+msgid "Enable %{link_start}Gitpod%{link_end} integration to launch a development environment in your browser directly from GitLab."
+msgstr ""
+
msgid "Enable Auto DevOps"
msgstr ""
+msgid "Enable Gitpod"
+msgstr ""
+
+msgid "Enable Gitpod?"
+msgstr ""
+
msgid "Enable HTML emails"
msgstr ""
@@ -9406,9 +9701,6 @@ msgstr ""
msgid "Encountered an error while rendering: %{err}"
msgstr ""
-msgid "End date"
-msgstr ""
-
msgid "Ends at (UTC)"
msgstr ""
@@ -9568,7 +9860,7 @@ msgstr ""
msgid "EnvironmentsDashboard|The environments dashboard provides a summary of each project's environments' status, including pipeline and alert statuses."
msgstr ""
-msgid "EnvironmentsDashboard|This dashboard displays a maximum of 7 projects and 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
+msgid "EnvironmentsDashboard|This dashboard displays 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
msgstr ""
msgid "Environments|An error occurred while canceling the auto stop, please try again"
@@ -9889,6 +10181,9 @@ msgstr ""
msgid "Error deleting project. Check logs for error details."
msgstr ""
+msgid "Error fetching burnup chart data"
+msgstr ""
+
msgid "Error fetching diverging counts for branches. Please try again."
msgstr ""
@@ -9967,6 +10262,9 @@ msgstr ""
msgid "Error occurred when saving assignees"
msgstr ""
+msgid "Error occurred when saving reviewers"
+msgstr ""
+
msgid "Error occurred when toggling the notification subscription"
msgstr ""
@@ -10219,10 +10517,13 @@ msgstr ""
msgid "Expand all"
msgstr ""
-msgid "Expand approvers"
+msgid "Expand all files"
msgstr ""
-msgid "Expand dropdown"
+msgid "Expand all threads"
+msgstr ""
+
+msgid "Expand approvers"
msgstr ""
msgid "Expand milestones"
@@ -10393,6 +10694,9 @@ msgstr ""
msgid "Failed to create Merge Request. Please try again."
msgstr ""
+msgid "Failed to create To-Do for the design."
+msgstr ""
+
msgid "Failed to create a branch for this issue. Please try again."
msgstr ""
@@ -10432,6 +10736,12 @@ msgstr ""
msgid "Failed to load authors. Please try again."
msgstr ""
+msgid "Failed to load branches. Please try again."
+msgstr ""
+
+msgid "Failed to load deploy keys."
+msgstr ""
+
msgid "Failed to load emoji list."
msgstr ""
@@ -10447,6 +10757,9 @@ msgstr ""
msgid "Failed to load groups & users."
msgstr ""
+msgid "Failed to load groups, users and deploy keys."
+msgstr ""
+
msgid "Failed to load labels. Please try again."
msgstr ""
@@ -10456,6 +10769,12 @@ msgstr ""
msgid "Failed to load related branches"
msgstr ""
+msgid "Failed to load sidebar confidential toggle"
+msgstr ""
+
+msgid "Failed to load sidebar lock status"
+msgstr ""
+
msgid "Failed to load stacktrace."
msgstr ""
@@ -10483,6 +10802,9 @@ msgstr ""
msgid "Failed to publish issue on status page."
msgstr ""
+msgid "Failed to remove To-Do for the design."
+msgstr ""
+
msgid "Failed to remove a Zoom meeting"
msgstr ""
@@ -10525,6 +10847,9 @@ msgstr ""
msgid "Failed to signing using smartcard authentication"
msgstr ""
+msgid "Failed to toggle To-Do for the design."
+msgstr ""
+
msgid "Failed to update branch!"
msgstr ""
@@ -10638,7 +10963,7 @@ msgstr ""
msgid "FeatureFlags|Edit User List"
msgstr ""
-msgid "FeatureFlags|Enable features for specific users and specific environments by defining feature flag strategies."
+msgid "FeatureFlags|Enable features for specific users and environments by configuring feature flag strategies."
msgstr ""
msgid "FeatureFlags|Environment Spec"
@@ -10698,7 +11023,7 @@ msgstr ""
msgid "FeatureFlags|Include additional user IDs"
msgstr ""
-msgid "FeatureFlags|Install a %{docs_link_anchored_start}compatible client library%{docs_link_anchored_end} and specify the API URL, application name, and instance ID during the configuration setup. %{docs_link_start}More Information%{docs_link_end}"
+msgid "FeatureFlags|Install a %{docsLinkAnchoredStart}compatible client library%{docsLinkAnchoredEnd} and specify the API URL, application name, and instance ID during the configuration setup. %{docsLinkStart}More Information%{docsLinkEnd}"
msgstr ""
msgid "FeatureFlags|Instance ID"
@@ -10710,6 +11035,9 @@ msgstr ""
msgid "FeatureFlags|Loading feature flags"
msgstr ""
+msgid "FeatureFlags|Loading user lists"
+msgstr ""
+
msgid "FeatureFlags|More information"
msgstr ""
@@ -10728,7 +11056,7 @@ msgstr ""
msgid "FeatureFlags|New feature flag"
msgstr ""
-msgid "FeatureFlags|New list"
+msgid "FeatureFlags|New user list"
msgstr ""
msgid "FeatureFlags|Percent of users"
@@ -10767,6 +11095,9 @@ msgstr ""
msgid "FeatureFlags|There was an error fetching the feature flags."
msgstr ""
+msgid "FeatureFlags|There was an error fetching the user lists."
+msgstr ""
+
msgid "FeatureFlags|There was an error retrieving user lists"
msgstr ""
@@ -10782,6 +11113,9 @@ msgstr ""
msgid "FeatureFlags|User List"
msgstr ""
+msgid "FeatureFlags|User Lists"
+msgstr ""
+
msgid "FeatureFlag|List"
msgstr ""
@@ -10809,15 +11143,6 @@ msgstr ""
msgid "Fetching incoming email"
msgstr ""
-msgid "Fetching licenses failed."
-msgstr ""
-
-msgid "Fetching licenses failed. The request endpoint was not found."
-msgstr ""
-
-msgid "Fetching licenses failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "File"
msgstr ""
@@ -10920,12 +11245,21 @@ msgstr ""
msgid "Filter by status"
msgstr ""
+msgid "Filter by test cases that are currently archived."
+msgstr ""
+
+msgid "Filter by test cases that are currently opened."
+msgstr ""
+
msgid "Filter by two-factor authentication"
msgstr ""
msgid "Filter by user"
msgstr ""
+msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
+msgstr ""
+
msgid "Filter pipelines"
msgstr ""
@@ -10941,7 +11275,7 @@ msgstr ""
msgid "Filter results..."
msgstr ""
-msgid "Filter your projects by name"
+msgid "Filter your repositories by name"
msgstr ""
msgid "Filter..."
@@ -10950,7 +11284,7 @@ msgstr ""
msgid "Find File"
msgstr ""
-msgid "Find bugs in your code with coverage-guided fuzzing"
+msgid "Find bugs in your code with coverage-guided fuzzing."
msgstr ""
msgid "Find by path"
@@ -10977,9 +11311,6 @@ msgstr ""
msgid "Finish editing this message first!"
msgstr ""
-msgid "Finish review"
-msgstr ""
-
msgid "Finish setting up your dedicated account for %{group_name}."
msgstr ""
@@ -11049,6 +11380,9 @@ msgstr ""
msgid "Footer message"
msgstr ""
+msgid "For a faster browsing experience, some files are collapsed by default."
+msgstr ""
+
msgid "For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
@@ -11058,6 +11392,9 @@ msgstr ""
msgid "For more info, read the documentation."
msgstr ""
+msgid "For more information on how the number of active users is calculated, see the %{self_managed_subscriptions_doc_link} documentation."
+msgstr ""
+
msgid "For more information, go to the "
msgstr ""
@@ -11196,6 +11533,9 @@ msgstr ""
msgid "Generate new token"
msgstr ""
+msgid "Generic package file size in bytes"
+msgstr ""
+
msgid "Geo"
msgstr ""
@@ -11457,6 +11797,9 @@ msgstr ""
msgid "Geo|Please refer to Geo Troubleshooting."
msgstr ""
+msgid "Geo|Primary node"
+msgstr ""
+
msgid "Geo|Project"
msgstr ""
@@ -11499,6 +11842,9 @@ msgstr ""
msgid "Geo|Review replication status, and resynchronize and reverify items with the primary node."
msgstr ""
+msgid "Geo|Secondary node"
+msgstr ""
+
msgid "Geo|Status"
msgstr ""
@@ -11538,6 +11884,9 @@ msgstr ""
msgid "Geo|URL must be a valid url (ex: https://gitlab.com)"
msgstr ""
+msgid "Geo|Undefined"
+msgstr ""
+
msgid "Geo|Unknown state"
msgstr ""
@@ -11613,10 +11962,16 @@ msgstr ""
msgid "GitHub import"
msgstr ""
+msgid "GitLab"
+msgstr ""
+
msgid "GitLab / Unsubscribe"
msgstr ""
-msgid "GitLab Enterprise Edition %{plan}"
+msgid "GitLab API"
+msgstr ""
+
+msgid "GitLab Billing Team."
msgstr ""
msgid "GitLab Group Runners can execute code for all the projects in this group."
@@ -11628,12 +11983,18 @@ msgstr ""
msgid "GitLab Issue"
msgstr ""
+msgid "GitLab Pages"
+msgstr ""
+
msgid "GitLab Service Desk is a simple way to allow people to create issues in your GitLab instance without needing their own user account. It provides a unique email address for end users to create issues in a project, and replies can be sent either through the GitLab interface or by email. End users will only see the thread through email."
msgstr ""
msgid "GitLab Shared Runners execute code of different projects on the same Runner unless you configure GitLab Runner Autoscale with MaxBuilds 1 (which it is on GitLab.com)."
msgstr ""
+msgid "GitLab Shell"
+msgstr ""
+
msgid "GitLab Support Bot"
msgstr ""
@@ -11643,7 +12004,7 @@ msgstr ""
msgid "GitLab User"
msgstr ""
-msgid "GitLab allows you to continue using your license even if you exceed the number of seats you purchased. You will be required to pay for these seats when you renew your license."
+msgid "GitLab Workhorse"
msgstr ""
msgid "GitLab commit"
@@ -11811,6 +12172,21 @@ msgstr ""
msgid "Gitlab Pages"
msgstr ""
+msgid "Gitpod"
+msgstr ""
+
+msgid "Gitpod|Add the URL to your Gitpod instance configured to read your GitLab projects."
+msgstr ""
+
+msgid "Gitpod|Enable Gitpod integration"
+msgstr ""
+
+msgid "Gitpod|Gitpod URL"
+msgstr ""
+
+msgid "Gitpod|e.g. https://gitpod.example.com"
+msgstr ""
+
msgid "Given access %{time_ago}"
msgstr ""
@@ -12318,9 +12694,6 @@ msgstr ""
msgid "GroupSAML|Valid SAML Response"
msgstr ""
-msgid "GroupSAML|With group managed accounts enabled, all the users without a group managed account will be excluded from the group."
-msgstr ""
-
msgid "GroupSAML|With prohibit outer forks flag enabled group members will be able to fork project only inside your group."
msgstr ""
@@ -12534,10 +12907,10 @@ msgstr ""
msgid "GroupsNew|Create group"
msgstr ""
-msgid "GroupsNew|GitLab group export"
+msgid "GroupsNew|Import"
msgstr ""
-msgid "GroupsNew|Import"
+msgid "GroupsNew|Import a GitLab group export file"
msgstr ""
msgid "GroupsNew|Import group"
@@ -12680,6 +13053,9 @@ msgid_plural "Hide charts"
msgstr[0] ""
msgstr[1] ""
+msgid "Hide comments on this file"
+msgstr ""
+
msgid "Hide details"
msgstr ""
@@ -12724,6 +13100,15 @@ msgstr ""
msgid "Highest role:"
msgstr ""
+msgid "HighlightBar|Alert events:"
+msgstr ""
+
+msgid "HighlightBar|Alert start time:"
+msgstr ""
+
+msgid "HighlightBar|Original alert:"
+msgstr ""
+
msgid "History"
msgstr ""
@@ -12901,6 +13286,9 @@ msgstr ""
msgid "If enabled, access to projects will be validated on an external service using their classification label."
msgstr ""
+msgid "If the number of active users exceeds the user limit, you will be charged for the number of %{users_over_license_link} at your next license reconciliation."
+msgstr ""
+
msgid "If there is no previous license or if the previous license has expired, some GitLab functionality will be blocked until a new, valid license is uploaded."
msgstr ""
@@ -12940,9 +13328,6 @@ msgstr ""
msgid "If your HTTP repository is not publicly accessible, add your credentials."
msgstr ""
-msgid "Iglu registry URL (optional)"
-msgstr ""
-
msgid "Ignore"
msgstr ""
@@ -12979,6 +13364,16 @@ msgstr ""
msgid "Import"
msgstr ""
+msgid "Import %d compatible repository"
+msgid_plural "Import %d compatible repositories"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Import %d repository"
+msgid_plural "Import %d repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Import CSV"
msgstr ""
@@ -12988,15 +13383,9 @@ msgstr ""
msgid "Import all compatible projects"
msgstr ""
-msgid "Import all compatible repositories"
-msgstr ""
-
msgid "Import all projects"
msgstr ""
-msgid "Import all repositories"
-msgstr ""
-
msgid "Import an exported GitLab project"
msgstr ""
@@ -13084,6 +13473,9 @@ msgstr ""
msgid "ImportProjects|Error importing repository %{project_safe_import_url} into %{project_full_path} - %{message}"
msgstr ""
+msgid "ImportProjects|Import repositories"
+msgstr ""
+
msgid "ImportProjects|Importing the project failed"
msgstr ""
@@ -13096,7 +13488,7 @@ msgstr ""
msgid "ImportProjects|Requesting your %{provider} repositories failed"
msgstr ""
-msgid "ImportProjects|Select the projects you want to import"
+msgid "ImportProjects|Select the repositories you want to import"
msgstr ""
msgid "ImportProjects|The remote data could not be imported."
@@ -13132,9 +13524,6 @@ msgstr ""
msgid "In order to enable Service Desk for your instance, you must first set up incoming email."
msgstr ""
-msgid "In order to gather accurate feature usage data, it can take 1 to 2 weeks to see your index."
-msgstr ""
-
msgid "In order to personalize your experience with GitLab%{br_tag}we would like to know a bit more about you."
msgstr ""
@@ -13165,18 +13554,30 @@ msgstr ""
msgid "IncidentManagement|Create incident"
msgstr ""
+msgid "IncidentManagement|Critical - S1"
+msgstr ""
+
msgid "IncidentManagement|Date created"
msgstr ""
msgid "IncidentManagement|Display your incidents in a dedicated view"
msgstr ""
+msgid "IncidentManagement|High - S2"
+msgstr ""
+
msgid "IncidentManagement|Incident"
msgstr ""
msgid "IncidentManagement|Incidents"
msgstr ""
+msgid "IncidentManagement|Low - S4"
+msgstr ""
+
+msgid "IncidentManagement|Medium - S3"
+msgstr ""
+
msgid "IncidentManagement|No incidents to display."
msgstr ""
@@ -13189,6 +13590,9 @@ msgstr ""
msgid "IncidentManagement|Published to status page"
msgstr ""
+msgid "IncidentManagement|Severity"
+msgstr ""
+
msgid "IncidentManagement|There are no closed incidents"
msgstr ""
@@ -13198,6 +13602,9 @@ msgstr ""
msgid "IncidentManagement|Unassigned"
msgstr ""
+msgid "IncidentManagement|Unknown"
+msgstr ""
+
msgid "IncidentManagement|Unpublished"
msgstr ""
@@ -13219,6 +13626,15 @@ msgstr ""
msgid "Incidents"
msgstr ""
+msgid "Incident|Alert details"
+msgstr ""
+
+msgid "Incident|Summary"
+msgstr ""
+
+msgid "Incident|There was an issue loading alert data. Please try again."
+msgstr ""
+
msgid "Include a Terms of Service agreement and Privacy Policy that all users must accept."
msgstr ""
@@ -13279,6 +13695,9 @@ msgstr ""
msgid "Information about additional Pages templates and how to install them can be found in our %{pages_getting_started_guide}."
msgstr ""
+msgid "Inherited"
+msgstr ""
+
msgid "Inherited:"
msgstr ""
@@ -13359,7 +13778,22 @@ msgstr ""
msgid "Instance administrators group already exists"
msgstr ""
-msgid "Instance license"
+msgid "InstanceStatistics|Groups"
+msgstr ""
+
+msgid "InstanceStatistics|Issues"
+msgstr ""
+
+msgid "InstanceStatistics|Merge Requests"
+msgstr ""
+
+msgid "InstanceStatistics|Pipelines"
+msgstr ""
+
+msgid "InstanceStatistics|Projects"
+msgstr ""
+
+msgid "InstanceStatistics|Users"
msgstr ""
msgid "Integration"
@@ -13371,6 +13805,12 @@ msgstr ""
msgid "Integrations"
msgstr ""
+msgid "Integrations|%{integration} settings saved and active."
+msgstr ""
+
+msgid "Integrations|%{integration} settings saved, but not active."
+msgstr ""
+
msgid "Integrations|All details"
msgstr ""
@@ -13380,6 +13820,12 @@ msgstr ""
msgid "Integrations|Comment settings:"
msgstr ""
+msgid "Integrations|Connection failed. Please check your settings."
+msgstr ""
+
+msgid "Integrations|Connection successful."
+msgstr ""
+
msgid "Integrations|Default settings are inherited from the group level."
msgstr ""
@@ -13395,6 +13841,15 @@ msgstr ""
msgid "Integrations|Includes commit title and branch"
msgstr ""
+msgid "Integrations|Projects using custom settings will not be impacted unless the project owner chooses to use instance-level defaults."
+msgstr ""
+
+msgid "Integrations|Save settings?"
+msgstr ""
+
+msgid "Integrations|Saving will update the default settings for all projects that are not using custom settings."
+msgstr ""
+
msgid "Integrations|Standard"
msgstr ""
@@ -13527,6 +13982,9 @@ msgstr ""
msgid "Invitation"
msgstr ""
+msgid "Invitation declined"
+msgstr ""
+
msgid "Invite"
msgstr ""
@@ -13578,6 +14036,42 @@ 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|%{linkStart}Read more%{linkEnd} about role permissions"
+msgstr ""
+
+msgid "InviteMembersModal|Access expiration date (optional)"
+msgstr ""
+
+msgid "InviteMembersModal|Cancel"
+msgstr ""
+
+msgid "InviteMembersModal|Choose a role permission"
+msgstr ""
+
+msgid "InviteMembersModal|GitLab member or Email address"
+msgstr ""
+
+msgid "InviteMembersModal|Invite"
+msgstr ""
+
+msgid "InviteMembersModal|Invite team members"
+msgstr ""
+
+msgid "InviteMembersModal|Search for members to invite"
+msgstr ""
+
+msgid "InviteMembersModal|User not invited. Feature coming soon!"
+msgstr ""
+
+msgid "InviteMembersModal|Users were succesfully added"
+msgstr ""
+
+msgid "InviteMembersModal|You're inviting members to the %{group_name} group"
+msgstr ""
+
+msgid "InviteMembers|Invite team members"
+msgstr ""
+
msgid "Invited"
msgstr ""
@@ -13632,10 +14126,13 @@ msgstr ""
msgid "Issue cannot be found."
msgstr ""
+msgid "Issue created from vulnerability %{vulnerability_link}"
+msgstr ""
+
msgid "Issue events"
msgstr ""
-msgid "Issue first depoloyed to production"
+msgid "Issue first deployed to production"
msgstr ""
msgid "Issue label"
@@ -13713,6 +14210,9 @@ msgstr ""
msgid "IssueTracker|Custom issue tracker"
msgstr ""
+msgid "IssueTracker|EWM work items tracker"
+msgstr ""
+
msgid "IssueTracker|Redmine issue tracker"
msgstr ""
@@ -13779,6 +14279,9 @@ msgstr ""
msgid "It looks like you have some draft commits in this branch."
msgstr ""
+msgid "It may be several days before you see feature usage data."
+msgstr ""
+
msgid "It must have a header row and at least two columns: the first column is the issue title and the second column is the issue description. The separator is automatically detected."
msgstr ""
@@ -14061,13 +14564,13 @@ msgstr ""
msgid "Join Zoom meeting"
msgstr ""
-msgid "Jul"
+msgid "Joined %{time_ago}"
msgstr ""
-msgid "July"
+msgid "Jul"
msgstr ""
-msgid "Jump to first unresolved thread"
+msgid "July"
msgstr ""
msgid "Jump to next unresolved thread"
@@ -14103,6 +14606,9 @@ msgstr ""
msgid "Keyboard shortcuts"
msgstr ""
+msgid "KeyboardKey|Ctrl+"
+msgstr ""
+
msgid "Keys"
msgstr ""
@@ -14151,6 +14657,9 @@ msgstr ""
msgid "LDAP Synchronization"
msgstr ""
+msgid "LDAP group settings"
+msgstr ""
+
msgid "LDAP settings"
msgstr ""
@@ -14160,6 +14669,9 @@ msgstr ""
msgid "LDAP sync in progress. This could take a few minutes. Refresh the page to see the changes."
msgstr ""
+msgid "LDAP synchronizations"
+msgstr ""
+
msgid "LFS"
msgstr ""
@@ -14240,7 +14752,16 @@ msgid_plural "Last %d days"
msgstr[0] ""
msgstr[1] ""
-msgid "Last %{days} days"
+msgid "Last 2 weeks"
+msgstr ""
+
+msgid "Last 30 days"
+msgstr ""
+
+msgid "Last 60 days"
+msgstr ""
+
+msgid "Last 90 days"
msgstr ""
msgid "Last Accessed On"
@@ -14318,6 +14839,9 @@ msgstr ""
msgid "Last used on:"
msgstr ""
+msgid "Last week"
+msgstr ""
+
msgid "LastCommit|authored"
msgstr ""
@@ -14333,6 +14857,9 @@ msgstr ""
msgid "Latest pipeline for the most recent commit on this branch"
msgstr ""
+msgid "Launch a ready-to-code development environment for your project."
+msgstr ""
+
msgid "Lead"
msgstr ""
@@ -14713,6 +15240,9 @@ msgstr ""
msgid "List of all merge commits"
msgstr ""
+msgid "List options"
+msgstr ""
+
msgid "List settings"
msgstr ""
@@ -14725,9 +15255,6 @@ msgstr ""
msgid "List your Bitbucket Server repositories"
msgstr ""
-msgid "Lists"
-msgstr ""
-
msgid "Live preview"
msgstr ""
@@ -14974,6 +15501,12 @@ msgstr ""
msgid "Mark as done"
msgstr ""
+msgid "Mark as draft"
+msgstr ""
+
+msgid "Mark as ready"
+msgstr ""
+
msgid "Mark as resolved"
msgstr ""
@@ -14995,6 +15528,24 @@ msgstr ""
msgid "Markdown is supported"
msgstr ""
+msgid "MarkdownEditor|Add a link (%{modifierKey}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add a link (%{modifier_key}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifierKey}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifier_key}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifierKey}I)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifier_key}I)"
+msgstr ""
+
msgid "Marked For Deletion At - %{deletion_time}"
msgstr ""
@@ -15079,7 +15630,25 @@ msgstr ""
msgid "Max access level"
msgstr ""
-msgid "Max seats used"
+msgid "Max role"
+msgstr ""
+
+msgid "Max size 15 MB"
+msgstr ""
+
+msgid "Maximum Conan package file size in bytes"
+msgstr ""
+
+msgid "Maximum Maven package file size in bytes"
+msgstr ""
+
+msgid "Maximum NPM package file size in bytes"
+msgstr ""
+
+msgid "Maximum NuGet package file size in bytes"
+msgstr ""
+
+msgid "Maximum PyPI package file size in bytes"
msgstr ""
msgid "Maximum Users:"
@@ -15211,6 +15780,18 @@ msgstr ""
msgid "Members with access to %{strong_start}%{group_name}%{strong_end}"
msgstr ""
+msgid "Members|%{time} by %{user}"
+msgstr ""
+
+msgid "Members|Expired"
+msgstr ""
+
+msgid "Members|No expiration set"
+msgstr ""
+
+msgid "Members|in %{time}"
+msgstr ""
+
msgid "Memory Usage"
msgstr ""
@@ -15397,9 +15978,6 @@ msgstr ""
msgid "MergeRequests|Thread will be unresolved"
msgstr ""
-msgid "MergeRequests|Toggle comments for this file"
-msgstr ""
-
msgid "MergeRequests|View file @ %{commitId}"
msgstr ""
@@ -15460,6 +16038,9 @@ msgstr ""
msgid "Merging immediately isn't recommended as it may negatively impact the existing merge train. Read the %{docsLinkStart}documentation%{docsLinkEnd} for more information."
msgstr ""
+msgid "Message"
+msgstr ""
+
msgid "Messages"
msgstr ""
@@ -15845,18 +16426,12 @@ msgid_plural "Milestones"
msgstr[0] ""
msgstr[1] ""
-msgid "Milestone does not support burnup charts"
-msgstr ""
-
msgid "Milestone lists not available with your current license"
msgstr ""
msgid "Milestone lists show all issues from the selected milestone."
msgstr ""
-msgid "Milestone must have a start and due date"
-msgstr ""
-
msgid "MilestoneSidebar|Closed:"
msgstr ""
@@ -16223,6 +16798,9 @@ msgstr ""
msgid "Namespace"
msgstr ""
+msgid "Namespace ID:"
+msgstr ""
+
msgid "Namespace is empty"
msgstr ""
@@ -16307,6 +16885,9 @@ msgstr ""
msgid "NetworkPolicies|Allow all outbound traffic from %{selector} to %{ruleSelector} on %{ports}"
msgstr ""
+msgid "NetworkPolicies|Are you sure you want to delete this policy? This action cannot be undone."
+msgstr ""
+
msgid "NetworkPolicies|Choose whether to enforce this policy."
msgstr ""
@@ -16316,12 +16897,21 @@ msgstr ""
msgid "NetworkPolicies|Define this policy's location, conditions and actions."
msgstr ""
+msgid "NetworkPolicies|Delete policy"
+msgstr ""
+
+msgid "NetworkPolicies|Delete policy: %{policy}"
+msgstr ""
+
msgid "NetworkPolicies|Deny all traffic"
msgstr ""
msgid "NetworkPolicies|Description"
msgstr ""
+msgid "NetworkPolicies|Edit policy"
+msgstr ""
+
msgid "NetworkPolicies|Editor mode"
msgstr ""
@@ -16349,6 +16939,9 @@ msgstr ""
msgid "NetworkPolicies|Name"
msgstr ""
+msgid "NetworkPolicies|Namespace"
+msgstr ""
+
msgid "NetworkPolicies|Network Policy"
msgstr ""
@@ -16400,6 +16993,9 @@ msgstr ""
msgid "NetworkPolicies|Rules"
msgstr ""
+msgid "NetworkPolicies|Save changes"
+msgstr ""
+
msgid "NetworkPolicies|Something went wrong, failed to update policy"
msgstr ""
@@ -16412,6 +17008,9 @@ msgstr ""
msgid "NetworkPolicies|Traffic that does not match any rule will be blocked."
msgstr ""
+msgid "NetworkPolicies|Unable to parse policy"
+msgstr ""
+
msgid "NetworkPolicies|YAML editor"
msgstr ""
@@ -16525,6 +17124,9 @@ msgstr ""
msgid "New Snippet"
msgstr ""
+msgid "New Test Case"
+msgstr ""
+
msgid "New User"
msgstr ""
@@ -16624,6 +17226,9 @@ msgstr ""
msgid "New tag"
msgstr ""
+msgid "New test case"
+msgstr ""
+
msgid "New users set to external"
msgstr ""
@@ -16696,7 +17301,7 @@ msgstr ""
msgid "No changes"
msgstr ""
-msgid "No changes between %{ref_start}%{source_branch}%{ref_end} and %{ref_start}%{target_branch}%{ref_end}"
+msgid "No changes between %{sourceBranch} and %{targetBranch}"
msgstr ""
msgid "No child epics match applied filters"
@@ -16711,6 +17316,9 @@ msgstr ""
msgid "No containers available"
msgstr ""
+msgid "No content to show"
+msgstr ""
+
msgid "No contributions"
msgstr ""
@@ -16786,9 +17394,6 @@ msgstr ""
msgid "No license. All rights reserved"
msgstr ""
-msgid "No licenses found."
-msgstr ""
-
msgid "No matches found"
msgstr ""
@@ -16801,6 +17406,9 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No members found"
+msgstr ""
+
msgid "No merge requests found"
msgstr ""
@@ -16822,6 +17430,9 @@ msgstr ""
msgid "No parent group"
msgstr ""
+msgid "No plan"
+msgstr ""
+
msgid "No pods available"
msgstr ""
@@ -16918,6 +17529,12 @@ msgstr ""
msgid "Not Implemented"
msgstr ""
+msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+msgstr ""
+
+msgid "Not all browsers support WebAuthn. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even from an unsupported browser."
+msgstr ""
+
msgid "Not all data has been processed yet, the accuracy of the chart for the selected timeframe is limited."
msgstr ""
@@ -17014,6 +17631,9 @@ msgstr ""
msgid "Notification settings saved"
msgstr ""
+msgid "NotificationEvent|Change reviewer merge request"
+msgstr ""
+
msgid "NotificationEvent|Close issue"
msgstr ""
@@ -17176,10 +17796,7 @@ msgstr ""
msgid "On track"
msgstr ""
-msgid "OnDemandScans|Attached branch"
-msgstr ""
-
-msgid "OnDemandScans|Attached branch is where the scan job runs."
+msgid "OnDemandScans|Could not fetch scanner profiles. Please refresh the page, or try again later."
msgstr ""
msgid "OnDemandScans|Could not fetch site profiles. Please refresh the page, or try again later."
@@ -17188,6 +17805,9 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
+msgid "OnDemandScans|Create a new scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Create a new site profile"
msgstr ""
@@ -17200,6 +17820,9 @@ msgstr ""
msgid "OnDemandScans|New on-demand DAST scan"
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 ""
@@ -17209,16 +17832,10 @@ msgstr ""
msgid "OnDemandScans|On-demand scans run outside the DevOps cycle and find vulnerabilities in your projects. %{learnMoreLinkStart}Learn more%{learnMoreLinkEnd}"
msgstr ""
-msgid "OnDemandScans|Only a passive scan can be performed on demand."
-msgstr ""
-
-msgid "OnDemandScans|Passive"
-msgstr ""
-
msgid "OnDemandScans|Run scan"
msgstr ""
-msgid "OnDemandScans|Scan mode"
+msgid "OnDemandScans|Scanner profile"
msgstr ""
msgid "OnDemandScans|Scanner settings"
@@ -17230,9 +17847,15 @@ msgstr ""
msgid "OnDemandScans|Select one of the existing profiles"
msgstr ""
+msgid "OnDemandScans|Site profile"
+msgstr ""
+
msgid "OnDemandScans|Site profiles"
msgstr ""
+msgid "OnDemandScans|Use existing scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Use existing site profile"
msgstr ""
@@ -17331,9 +17954,6 @@ msgstr ""
msgid "Open Selection"
msgstr ""
-msgid "Open Web IDE"
-msgstr ""
-
msgid "Open comment type dropdown"
msgstr ""
@@ -17439,6 +18059,9 @@ msgstr ""
msgid "Origin"
msgstr ""
+msgid "Orphaned member"
+msgstr ""
+
msgid "Other Labels"
msgstr ""
@@ -17454,6 +18077,9 @@ msgstr ""
msgid "Other visibility settings have been disabled by the administrator."
msgstr ""
+msgid "Our documentation includes an example DevOps Score report."
+msgstr ""
+
msgid "Out-of-compliance with this project's policies and should be removed"
msgstr ""
@@ -17478,6 +18104,9 @@ msgstr ""
msgid "Overwrite diverged branches"
msgstr ""
+msgid "Owned by %{image_tag}"
+msgstr ""
+
msgid "Owned by anyone"
msgstr ""
@@ -17499,6 +18128,9 @@ msgstr ""
msgid "Package deleted successfully"
msgstr ""
+msgid "Package file size limits"
+msgstr ""
+
msgid "Package recipe already exists"
msgstr ""
@@ -17514,9 +18146,6 @@ msgstr ""
msgid "Package type must be PyPi"
msgstr ""
-msgid "Package was removed"
-msgstr ""
-
msgid "PackageRegistry|%{name} version %{version} was created %{datetime}"
msgstr ""
@@ -17658,12 +18287,18 @@ msgstr ""
msgid "PackageRegistry|NuGet Command"
msgstr ""
+msgid "PackageRegistry|Package Registry"
+msgstr ""
+
msgid "PackageRegistry|Pip Command"
msgstr ""
msgid "PackageRegistry|Pipeline %{link} triggered %{datetime} by %{author}"
msgstr ""
+msgid "PackageRegistry|Publish and share packages for a variety of common package managers. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "PackageRegistry|Published to the %{project} Package Registry %{datetime}"
msgstr ""
@@ -17763,6 +18398,9 @@ msgstr ""
msgid "Page not found"
msgstr ""
+msgid "Page settings"
+msgstr ""
+
msgid "Page was successfully deleted"
msgstr ""
@@ -17904,7 +18542,7 @@ msgstr ""
msgid "Paste issue link"
msgstr ""
-msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Don't use your private SSH key."
+msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Do not paste your private SSH key, as that can compromise your identity."
msgstr ""
msgid "Patch to apply"
@@ -17931,6 +18569,9 @@ msgstr ""
msgid "Pending"
msgstr ""
+msgid "Pending comments"
+msgstr ""
+
msgid "People without permission will never get a notification and won't be able to comment."
msgstr ""
@@ -18129,6 +18770,9 @@ msgstr ""
msgid "Pipelines|Build with confidence"
msgstr ""
+msgid "Pipelines|By revoking a trigger you will break any processes making use of it. Are you sure?"
+msgstr ""
+
msgid "Pipelines|CI Lint"
msgstr ""
@@ -18141,6 +18785,15 @@ msgstr ""
msgid "Pipelines|Continuous Integration can help catch bugs by running your tests automatically, while Continuous Deployment can help you deliver code to your product environment."
msgstr ""
+msgid "Pipelines|Copy trigger token"
+msgstr ""
+
+msgid "Pipelines|Description"
+msgstr ""
+
+msgid "Pipelines|Edit"
+msgstr ""
+
msgid "Pipelines|Get started with Pipelines"
msgstr ""
@@ -18156,15 +18809,27 @@ msgstr ""
msgid "Pipelines|It is recommended the code is reviewed thoroughly before running this pipeline with the parent project's CI resource."
msgstr ""
+msgid "Pipelines|Last Used"
+msgstr ""
+
msgid "Pipelines|Loading Pipelines"
msgstr ""
msgid "Pipelines|More Information"
msgstr ""
+msgid "Pipelines|No triggers have been created yet. Add one using the form above."
+msgstr ""
+
+msgid "Pipelines|Owner"
+msgstr ""
+
msgid "Pipelines|Project cache successfully reset."
msgstr ""
+msgid "Pipelines|Revoke"
+msgstr ""
+
msgid "Pipelines|Run Pipeline"
msgstr ""
@@ -18189,6 +18854,15 @@ msgstr ""
msgid "Pipelines|This project is not currently set up to run pipelines."
msgstr ""
+msgid "Pipelines|Token"
+msgstr ""
+
+msgid "Pipelines|Trigger user has insufficient permissions to project"
+msgstr ""
+
+msgid "Pipelines|invalid"
+msgstr ""
+
msgid "Pipelines|parent"
msgstr ""
@@ -18447,10 +19121,10 @@ msgstr ""
msgid "Please provide attributes to update"
msgstr ""
-msgid "Please refer to %{docs_url}"
+msgid "Please reach out if you have any questions and we'll be happy to assist."
msgstr ""
-msgid "Please retype the email address."
+msgid "Please refer to %{docs_url}"
msgstr ""
msgid "Please select"
@@ -18480,6 +19154,9 @@ msgstr ""
msgid "Please set a new password before proceeding."
msgstr ""
+msgid "Please share your feedback about %{featureName} %{linkStart}in this issue%{linkEnd} to help us improve the experience."
+msgstr ""
+
msgid "Please solve the reCAPTCHA"
msgstr ""
@@ -18783,6 +19460,9 @@ msgstr ""
msgid "Profiles| You are going to change the username %{currentUsernameBold} to %{newUsernameBold}. Profile and projects will be redirected to the %{newUsername} namespace but this redirect will expire once the %{currentUsername} namespace is registered by another user or group. Please update your Git repository remotes as soon as possible."
msgstr ""
+msgid "Profiles|%{provider} Active"
+msgstr ""
+
msgid "Profiles|@username"
msgstr ""
@@ -18834,7 +19514,7 @@ msgstr ""
msgid "Profiles|Commit email"
msgstr ""
-msgid "Profiles|Connect"
+msgid "Profiles|Connect %{provider}"
msgstr ""
msgid "Profiles|Connected Accounts"
@@ -18858,6 +19538,9 @@ msgstr ""
msgid "Profiles|Disconnect"
msgstr ""
+msgid "Profiles|Disconnect %{provider}"
+msgstr ""
+
msgid "Profiles|Do not show on profile"
msgstr ""
@@ -18882,7 +19565,7 @@ msgstr ""
msgid "Profiles|Full name"
msgstr ""
-msgid "Profiles|Give your individual key a title. This will be publically visible."
+msgid "Profiles|Give your individual key a title."
msgstr ""
msgid "Profiles|Include private contributions on my profile"
@@ -18972,7 +19655,7 @@ msgstr ""
msgid "Profiles|The maximum file size allowed is 200KB."
msgstr ""
-msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it?"
+msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it? It will be publicly visible."
msgstr ""
msgid "Profiles|This email will be displayed on your public profile"
@@ -19047,6 +19730,9 @@ msgstr ""
msgid "Profiles|You don't have access to delete this user."
msgstr ""
+msgid "Profiles|You must transfer ownership or delete groups you are an owner of before you can delete your account"
+msgstr ""
+
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
@@ -19635,6 +20321,9 @@ msgstr ""
msgid "ProjectTemplates|GitLab Cluster Management"
msgstr ""
+msgid "ProjectTemplates|Gitpod/Spring Petclinic"
+msgstr ""
+
msgid "ProjectTemplates|Go Micro"
msgstr ""
@@ -20244,6 +20933,9 @@ msgstr ""
msgid "Publish to status page"
msgstr ""
+msgid "Published"
+msgstr ""
+
msgid "Published on status page"
msgstr ""
@@ -20361,9 +21053,15 @@ msgstr ""
msgid "Quick range"
msgstr ""
+msgid "Quickly and easily edit multiple files in your project."
+msgstr ""
+
msgid "README"
msgstr ""
+msgid "Rails"
+msgstr ""
+
msgid "Rake Tasks Help"
msgstr ""
@@ -20483,10 +21181,13 @@ msgstr ""
msgid "Register Two-Factor Authenticator"
msgstr ""
-msgid "Register U2F device"
+msgid "Register Universal Two-Factor (U2F) Device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register WebAuthn Device"
+msgstr ""
+
+msgid "Register device"
msgstr ""
msgid "Register for GitLab"
@@ -20498,9 +21199,6 @@ msgstr ""
msgid "Register with two-factor app"
msgstr ""
-msgid "Registration"
-msgstr ""
-
msgid "Registration|Checkout"
msgstr ""
@@ -20617,9 +21315,6 @@ msgstr ""
msgid "Release|Something went wrong while saving the release details"
msgstr ""
-msgid "Remediated: needs review"
-msgstr ""
-
msgid "Remediations"
msgstr ""
@@ -20725,6 +21420,9 @@ msgstr ""
msgid "Remove priority"
msgstr ""
+msgid "Remove report"
+msgstr ""
+
msgid "Remove secondary node"
msgstr ""
@@ -20737,6 +21435,12 @@ msgstr ""
msgid "Remove time estimate"
msgstr ""
+msgid "Remove user & report"
+msgstr ""
+
+msgid "Remove user from group"
+msgstr ""
+
msgid "Removed"
msgstr ""
@@ -20818,9 +21522,6 @@ msgstr ""
msgid "Removes time estimate."
msgstr ""
-msgid "Removing license…"
-msgstr ""
-
msgid "Removing this group also removes all child projects, including archived projects, and their resources."
msgstr ""
@@ -20905,6 +21606,9 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
+msgid "Reported by %{reporter}"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -20991,6 +21695,27 @@ msgstr ""
msgid "Repositories"
msgstr ""
+msgid "Repositories Analytics"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download Historic Test Coverage Data"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download historic test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Historic Test Coverage Data is available in raw format (.csv) for further analysis."
+msgstr ""
+
+msgid "RepositoriesAnalytics|Test Code Coverage"
+msgstr ""
+
+msgid "RepositoriesAnalytics|There was an error fetching the projects."
+msgstr ""
+
msgid "Repository"
msgstr ""
@@ -21069,9 +21794,15 @@ msgstr ""
msgid "Request parameter %{param} is missing."
msgstr ""
+msgid "Request review from"
+msgstr ""
+
msgid "Request to link SAML account must be authorized"
msgstr ""
+msgid "Requested"
+msgstr ""
+
msgid "Requested %{time_ago}"
msgstr ""
@@ -21090,6 +21821,9 @@ msgstr ""
msgid "Requests to these domain(s)/address(es) on the local network will be allowed when local requests from hooks and services are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 or 127.0.0.0/28 are supported. Domain wildcards are not supported currently. Use comma, semicolon, or newline to separate multiple entries. The allowlist can hold a maximum of 1000 entries. Domains should use IDNA encoding. Ex: example.com, 192.168.1.1, 127.0.0.0/28, xn--itlab-j1a.com."
msgstr ""
+msgid "Require admin approval for new sign-ups"
+msgstr ""
+
msgid "Require all users in this group to setup Two-factor authentication"
msgstr ""
@@ -21217,9 +21951,6 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
-msgid "Resolved by %{resolvedByName}"
-msgstr ""
-
msgid "Resolves IP addresses once and uses them to submit requests"
msgstr ""
@@ -21339,6 +22070,14 @@ msgstr ""
msgid "ReviewApp|Enable Review App"
msgstr ""
+msgid "Reviewer"
+msgid_plural "%d Reviewers"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Reviewer(s)"
+msgstr ""
+
msgid "Reviewing"
msgstr ""
@@ -21378,6 +22117,9 @@ msgstr ""
msgid "Rook"
msgstr ""
+msgid "Ruby"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -21456,6 +22198,63 @@ msgstr ""
msgid "Runners page."
msgstr ""
+msgid "Runners|Active"
+msgstr ""
+
+msgid "Runners|Architecture"
+msgstr ""
+
+msgid "Runners|Can run untagged jobs"
+msgstr ""
+
+msgid "Runners|Description"
+msgstr ""
+
+msgid "Runners|Group"
+msgstr ""
+
+msgid "Runners|IP Address"
+msgstr ""
+
+msgid "Runners|Last contact"
+msgstr ""
+
+msgid "Runners|Locked to this project"
+msgstr ""
+
+msgid "Runners|Maximum job timeout"
+msgstr ""
+
+msgid "Runners|Name"
+msgstr ""
+
+msgid "Runners|Platform"
+msgstr ""
+
+msgid "Runners|Property Name"
+msgstr ""
+
+msgid "Runners|Protected"
+msgstr ""
+
+msgid "Runners|Revision"
+msgstr ""
+
+msgid "Runners|Shared"
+msgstr ""
+
+msgid "Runners|Specific"
+msgstr ""
+
+msgid "Runners|Tags"
+msgstr ""
+
+msgid "Runners|Value"
+msgstr ""
+
+msgid "Runners|Version"
+msgstr ""
+
msgid "Runners|You have used %{quotaUsed} out of %{quotaLimit} of your shared Runners pipeline minutes."
msgstr ""
@@ -21468,6 +22267,9 @@ msgstr ""
msgid "Runs a number of housekeeping tasks within the current repository, such as compressing file revisions and removing unreachable objects."
msgstr ""
+msgid "SAML"
+msgstr ""
+
msgid "SAML SSO"
msgstr ""
@@ -21519,6 +22321,9 @@ msgstr ""
msgid "Save"
msgstr ""
+msgid "Save %{name} size limits"
+msgstr ""
+
msgid "Save Changes"
msgstr ""
@@ -21549,9 +22354,6 @@ msgstr ""
msgid "Save space and find tags in the Container Registry more easily. Enable the cleanup policy to remove stale tags and keep only the ones you need."
msgstr ""
-msgid "Save template"
-msgstr ""
-
msgid "Save variables"
msgstr ""
@@ -21594,9 +22396,6 @@ msgstr ""
msgid "Scope"
msgstr ""
-msgid "Scope not supported with disabled 'users_search' feature!"
-msgstr ""
-
msgid "Scoped issue boards"
msgstr ""
@@ -21723,9 +22522,6 @@ msgstr ""
msgid "Search requirements"
msgstr ""
-msgid "Search results…"
-msgstr ""
-
msgid "Search users"
msgstr ""
@@ -21798,6 +22594,11 @@ msgid_plural "SearchResults|commits"
msgstr[0] ""
msgstr[1] ""
+msgid "SearchResults|epic"
+msgid_plural "SearchResults|epics"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "SearchResults|issue"
msgid_plural "SearchResults|issues"
msgstr[0] ""
@@ -21842,10 +22643,10 @@ msgstr ""
msgid "Seat Link is disabled, and cannot be configured through this form."
msgstr ""
-msgid "Seats currently in use"
+msgid "Seats usage data as of %{last_enqueue_time}"
msgstr ""
-msgid "Seats in license"
+msgid "Seats usage data is updated every day at 12:00pm UTC"
msgstr ""
msgid "Secondary"
@@ -21899,6 +22700,9 @@ msgstr ""
msgid "SecurityConfiguration|Available for on-demand DAST"
msgstr ""
+msgid "SecurityConfiguration|By default, all analyzers are applied in order to cover all languages across your project, and only run if the language is detected in the Merge Request."
+msgstr ""
+
msgid "SecurityConfiguration|Configure"
msgstr ""
@@ -21929,16 +22733,19 @@ msgstr ""
msgid "SecurityConfiguration|Manage"
msgstr ""
+msgid "SecurityConfiguration|More information"
+msgstr ""
+
msgid "SecurityConfiguration|Not enabled"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|Security Control"
+msgid "SecurityConfiguration|SAST Configuration"
msgstr ""
-msgid "SecurityConfiguration|See documentation"
+msgid "SecurityConfiguration|Security Control"
msgstr ""
msgid "SecurityConfiguration|Status"
@@ -21950,6 +22757,9 @@ msgstr ""
msgid "SecurityConfiguration|Using custom settings. You won't receive automatic updates on this variable. %{anchorStart}Restore to default%{anchorEnd}"
msgstr ""
+msgid "SecurityConfiguration|View history"
+msgstr ""
+
msgid "SecurityConfiguration|You can quickly enable all security scanning tools by enabling %{linkStart}Auto DevOps%{linkEnd}."
msgstr ""
@@ -22028,9 +22838,6 @@ msgstr ""
msgid "SecurityReports|Learn more about setting up your dashboard"
msgstr ""
-msgid "SecurityReports|Load more vulnerabilities"
-msgstr ""
-
msgid "SecurityReports|Monitor vulnerabilities in your code"
msgstr ""
@@ -22310,7 +23117,7 @@ msgstr ""
msgid "Select status"
msgstr ""
-msgid "Select strategy activation method"
+msgid "Select strategy activation method."
msgstr ""
msgid "Select subscription"
@@ -22325,7 +23132,7 @@ msgstr ""
msgid "Select the custom project template source group."
msgstr ""
-msgid "Select timeframe"
+msgid "Select the environment scope for this feature flag."
msgstr ""
msgid "Select timezone"
@@ -22574,6 +23381,9 @@ msgstr ""
msgid "Set iteration"
msgstr ""
+msgid "Set limit to 0 to allow any file size."
+msgstr ""
+
msgid "Set max session time for web terminal."
msgstr ""
@@ -22652,10 +23462,13 @@ msgstr ""
msgid "Set up a %{type} Runner manually"
msgstr ""
+msgid "Set up a hardware device as a second factor to sign in."
+msgstr ""
+
msgid "Set up assertions/attributes/claims (email, first_name, last_name) and NameID according to %{docsLinkStart}the documentation %{icon}%{docsLinkEnd}"
msgstr ""
-msgid "Set up new U2F device"
+msgid "Set up new device"
msgstr ""
msgid "Set up new password"
@@ -22724,6 +23537,9 @@ msgstr ""
msgid "Sets weight to %{weight}."
msgstr ""
+msgid "Setting this to 0 means using the system default timeout value."
+msgstr ""
+
msgid "Settings"
msgstr ""
@@ -22739,6 +23555,15 @@ msgstr ""
msgid "Severity"
msgstr ""
+msgid "SeverityWidget|Severity"
+msgstr ""
+
+msgid "SeverityWidget|Severity: %{severity}"
+msgstr ""
+
+msgid "SeverityWidget|There was an error while updating severity."
+msgstr ""
+
msgid "Shards (%{shards})"
msgstr ""
@@ -22784,6 +23609,9 @@ msgstr ""
msgid "Show all requirements."
msgstr ""
+msgid "Show all test cases."
+msgstr ""
+
msgid "Show archived projects"
msgstr ""
@@ -22796,6 +23624,9 @@ msgstr ""
msgid "Show comments"
msgstr ""
+msgid "Show comments on this file"
+msgstr ""
+
msgid "Show comments only"
msgstr ""
@@ -22841,6 +23672,12 @@ msgstr ""
msgid "Show parent subgroups"
msgstr ""
+msgid "Show the Closed list"
+msgstr ""
+
+msgid "Show the Open list"
+msgstr ""
+
msgid "Show whitespace changes"
msgstr ""
@@ -22884,9 +23721,6 @@ msgstr ""
msgid "Sidebar|Assign health status"
msgstr ""
-msgid "Sidebar|Change weight"
-msgstr ""
-
msgid "Sidebar|Health status"
msgstr ""
@@ -23070,6 +23904,9 @@ msgstr ""
msgid "Snippets|Add another file %{num}/%{total}"
msgstr ""
+msgid "Snippets|Authored %{time_ago} by %{author}"
+msgstr ""
+
msgid "Snippets|Delete file"
msgstr ""
@@ -23097,6 +23934,9 @@ msgstr ""
msgid "Solution"
msgstr ""
+msgid "Some changes are not shown"
+msgstr ""
+
msgid "Some child epics may be hidden due to applied filters"
msgstr ""
@@ -23463,6 +24303,12 @@ msgstr ""
msgid "Source (branch or tag)"
msgstr ""
+msgid "Source Branch"
+msgstr ""
+
+msgid "Source branch: %{source_branch_open}%{source_branch}%{source_branch_close}"
+msgstr ""
+
msgid "Source code"
msgstr ""
@@ -23628,9 +24474,6 @@ msgstr ""
msgid "Start and due date"
msgstr ""
-msgid "Start by choosing a group to see how your team is spending time. You can then drill down to the project level."
-msgstr ""
-
msgid "Start by choosing a group to start exploring the merge requests in that group. You can then proceed to filter by projects, labels, milestones and authors."
msgstr ""
@@ -23712,18 +24555,27 @@ msgstr ""
msgid "StaticSiteEditor|3. Assign a person to review and accept the merge request."
msgstr ""
+msgid "StaticSiteEditor|A link to view the merge request will appear once ready."
+msgstr ""
+
msgid "StaticSiteEditor|An error occurred while submitting your changes."
msgstr ""
msgid "StaticSiteEditor|Branch could not be created."
msgstr ""
+msgid "StaticSiteEditor|Copy update"
+msgstr ""
+
msgid "StaticSiteEditor|Could not commit the content changes."
msgstr ""
msgid "StaticSiteEditor|Could not create merge request."
msgstr ""
+msgid "StaticSiteEditor|Creating your merge request"
+msgstr ""
+
msgid "StaticSiteEditor|Incompatible file content"
msgstr ""
@@ -23745,6 +24597,9 @@ msgstr ""
msgid "StaticSiteEditor|View documentation"
msgstr ""
+msgid "StaticSiteEditor|You can set an assignee to get your changes reviewed and deployed once your merge request is created."
+msgstr ""
+
msgid "StaticSiteEditor|Your merge request has been created"
msgstr ""
@@ -23874,15 +24729,15 @@ msgstr ""
msgid "Submit %{humanized_resource_name}"
msgstr ""
-msgid "Submit Changes"
-msgstr ""
-
msgid "Submit a review"
msgstr ""
msgid "Submit as spam"
msgstr ""
+msgid "Submit changes"
+msgstr ""
+
msgid "Submit feedback"
msgstr ""
@@ -24036,6 +24891,9 @@ msgstr ""
msgid "Successfully deleted U2F device."
msgstr ""
+msgid "Successfully deleted WebAuthn device."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -24354,9 +25212,6 @@ msgstr ""
msgid "Template to append to all Service Desk issues"
msgstr ""
-msgid "Template was successfully saved."
-msgstr ""
-
msgid "Templates"
msgstr ""
@@ -24435,10 +25290,28 @@ msgid_plural "Test coverage: %d hits"
msgstr[0] ""
msgstr[1] ""
-msgid "Test failed."
+msgid "Test settings"
msgstr ""
-msgid "Test settings and save changes"
+msgid "TestCases|New Test Case"
+msgstr ""
+
+msgid "TestCases|New test case"
+msgstr ""
+
+msgid "TestCases|Search test cases"
+msgstr ""
+
+msgid "TestCases|Something went wrong while creating a test case."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching count of test cases."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching test cases list."
+msgstr ""
+
+msgid "TestCases|Submit test case"
msgstr ""
msgid "TestHooks|Ensure one of your projects has merge requests."
@@ -24504,6 +25377,9 @@ msgstr ""
msgid "Thank you for signing up for your free trial! You will get additional instructions in your inbox shortly."
msgstr ""
+msgid "Thank you for your business."
+msgstr ""
+
msgid "Thank you for your feedback!"
msgstr ""
@@ -24563,9 +25439,6 @@ msgstr ""
msgid "The URL to use for connecting to Elasticsearch. Use a comma-separated list to support clustering (e.g., \"http://localhost:9200, http://localhost:9201\")."
msgstr ""
-msgid "The Web IDE offers advanced syntax highlighting capabilities and more."
-msgstr ""
-
msgid "The X509 Certificate to use when mutual TLS is required to communicate with the external authorization service. If left blank, the server certificate is still validated when accessing over HTTPS."
msgstr ""
@@ -24676,6 +25549,9 @@ msgstr ""
msgid "The form contains the following error:"
msgstr ""
+msgid "The form contains the following warning:"
+msgstr ""
+
msgid "The global settings require you to enable Two-Factor Authentication for your account."
msgstr ""
@@ -24790,9 +25666,6 @@ msgstr ""
msgid "The private key to use when a client certificate is provided. This value is encrypted at rest."
msgstr ""
-msgid "The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The project can be accessed by any logged in user."
msgstr ""
@@ -24829,7 +25702,7 @@ msgstr ""
msgid "The remote repository is being updated..."
msgstr ""
-msgid "The repository can be commited to, and issues, comments and other entities can be created."
+msgid "The repository can be committed to, and issues, comments and other entities can be created."
msgstr ""
msgid "The repository for this project does not exist."
@@ -24883,9 +25756,6 @@ msgstr ""
msgid "The time taken by each data entry gathered by that stage."
msgstr ""
-msgid "The total stage shows the time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The update action will time out after %{number_of_minutes} minutes. For big repositories, use a clone/push combination."
msgstr ""
@@ -24949,6 +25819,9 @@ msgstr ""
msgid "There are no archived requirements"
msgstr ""
+msgid "There are no archived test cases"
+msgstr ""
+
msgid "There are no changes"
msgstr ""
@@ -24988,6 +25861,9 @@ msgstr ""
msgid "There are no open requirements"
msgstr ""
+msgid "There are no open test cases"
+msgstr ""
+
msgid "There are no packages yet"
msgstr ""
@@ -25000,6 +25876,9 @@ msgstr ""
msgid "There is a limit of %{ci_project_subscriptions_limit} subscriptions from or to a project."
msgstr ""
+msgid "There is already a To-Do for this design."
+msgstr ""
+
msgid "There is already a repository with that name on disk"
msgstr ""
@@ -25018,6 +25897,9 @@ msgstr ""
msgid "There was a problem communicating with your device."
msgstr ""
+msgid "There was a problem fetching branches."
+msgstr ""
+
msgid "There was a problem fetching groups."
msgstr ""
@@ -25246,9 +26128,15 @@ msgstr ""
msgid "This action can lead to data loss. To prevent accidental actions we ask you to confirm your intention."
msgstr ""
+msgid "This action cannot be undone, and will permanently delete the %{key} SSH key"
+msgstr ""
+
msgid "This action cannot be undone. You will lose the project's repository and all content: issues, merge requests, etc."
msgstr ""
+msgid "This action has been performed too many times. Try again later."
+msgstr ""
+
msgid "This action will %{strongOpen}permanently delete%{strongClose} %{codeOpen}%{project}%{codeClose} %{strongOpen}immediately%{strongClose}, including its repositories and all content: issues, merge requests, etc."
msgstr ""
@@ -25276,9 +26164,6 @@ msgstr ""
msgid "This board's scope is reduced"
msgstr ""
-msgid "This branch has changed since you started editing. Would you like to create a new branch?"
-msgstr ""
-
msgid "This chart could not be displayed"
msgstr ""
@@ -25405,15 +26290,9 @@ msgstr ""
msgid "This is a security log of important events involving your account."
msgstr ""
-msgid "This is the author's first Merge Request to this project."
-msgstr ""
-
msgid "This is the highest peak of users on your installation since the license started."
msgstr ""
-msgid "This is the maximum number of users that have existed at the same time since the license started. This is the minimum number of seats you will need to buy when you renew your license."
-msgstr ""
-
msgid "This is the number of currently active users on your installation, and this is the minimum number you need to purchase when you renew your license."
msgstr ""
@@ -25645,6 +26524,15 @@ msgstr ""
msgid "This user has no identities"
msgstr ""
+msgid "This user has previously committed to the %{name} project."
+msgstr ""
+
+msgid "This user has the %{access} role in the %{name} project."
+msgstr ""
+
+msgid "This user is the author of this %{noteable}."
+msgstr ""
+
msgid "This user will be the author of all events in the activity feed that are the result of an update, like new branches being created or new commits being pushed to existing branches."
msgstr ""
@@ -25675,6 +26563,9 @@ msgstr ""
msgid "Threat Monitoring"
msgstr ""
+msgid "ThreatMonitoring|All Environments"
+msgstr ""
+
msgid "ThreatMonitoring|Anomalous Requests"
msgstr ""
@@ -25702,9 +26593,6 @@ msgstr ""
msgid "ThreatMonitoring|Operations Per Second"
msgstr ""
-msgid "ThreatMonitoring|Overview"
-msgstr ""
-
msgid "ThreatMonitoring|Packet Activity"
msgstr ""
@@ -25723,6 +26611,9 @@ msgstr ""
msgid "ThreatMonitoring|Something went wrong, unable to fetch statistics"
msgstr ""
+msgid "ThreatMonitoring|Statistics"
+msgstr ""
+
msgid "ThreatMonitoring|The firewall is not installed or has been disabled. To view this data, ensure the web application firewall is installed and enabled for your cluster."
msgstr ""
@@ -26114,6 +27005,9 @@ msgstr ""
msgid "To update Snippets with multiple files, you must use the `files` parameter"
msgstr ""
+msgid "To use Gitpod you must first enable the feature in the integrations section of your %{user_prefs}."
+msgstr ""
+
msgid "To view all %{scannedResourcesCount} scanned URLs, please download the CSV file"
msgstr ""
@@ -26147,9 +27041,6 @@ msgstr ""
msgid "Toggle Sidebar"
msgstr ""
-msgid "Toggle all threads"
-msgstr ""
-
msgid "Toggle backtrace"
msgstr ""
@@ -26174,9 +27065,6 @@ msgstr ""
msgid "Toggle navigation"
msgstr ""
-msgid "Toggle project"
-msgstr ""
-
msgid "Toggle sidebar"
msgstr ""
@@ -26216,6 +27104,9 @@ msgstr ""
msgid "Too many projects enabled. You will need to manage them via the console or the API."
msgstr ""
+msgid "Too much data"
+msgstr ""
+
msgid "Topics (optional)"
msgstr ""
@@ -26234,6 +27125,9 @@ msgstr ""
msgid "Total cores (CPUs)"
msgstr ""
+msgid "Total days to completion"
+msgstr ""
+
msgid "Total issues"
msgstr ""
@@ -26330,6 +27224,9 @@ msgstr ""
msgid "Trending"
msgstr ""
+msgid "Trials|Create a new group to start your GitLab Gold trial."
+msgstr ""
+
msgid "Trials|Go back to GitLab"
msgstr ""
@@ -26339,6 +27236,15 @@ msgstr ""
msgid "Trials|You can always resume this process by selecting your avatar and choosing 'Start a Gold trial'"
msgstr ""
+msgid "Trials|You can apply your trial to a new group or an existing group."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group or your personal account."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group, an existing group, or your personal account."
+msgstr ""
+
msgid "Trials|You won't get a free trial right now but you can always resume this process by clicking on your avatar and choosing 'Start a free trial'"
msgstr ""
@@ -26408,6 +27314,9 @@ msgstr ""
msgid "Try using a different search term to find the file you are looking for."
msgstr ""
+msgid "Trying to communicate with your device. Plug it in (if needed) and press the button on the device now."
+msgstr ""
+
msgid "Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now."
msgstr ""
@@ -26495,6 +27404,12 @@ msgstr ""
msgid "URL or request ID"
msgstr ""
+msgid "USER %{user} WILL BE REMOVED! Are you sure?"
+msgstr ""
+
+msgid "USER WILL BE BLOCKED! Are you sure?"
+msgstr ""
+
msgid "UTC"
msgstr ""
@@ -26552,9 +27467,6 @@ msgstr ""
msgid "Unable to load the merge request widget. Try reloading the page."
msgstr ""
-msgid "Unable to resolve"
-msgstr ""
-
msgid "Unable to save iteration. Please try again"
msgstr ""
@@ -26603,6 +27515,9 @@ msgstr ""
msgid "Undo ignore"
msgstr ""
+msgid "Unexpected error"
+msgstr ""
+
msgid "Unfortunately, your email message to GitLab could not be processed."
msgstr ""
@@ -26636,6 +27551,9 @@ msgstr ""
msgid "Unknown response text"
msgstr ""
+msgid "Unless otherwise agreed to in writing with GitLab, by clicking \"Upload License\" you agree that your use of GitLab Software is subject to the %{eula_link_start}Terms of Service%{eula_link_end}."
+msgstr ""
+
msgid "Unlimited"
msgstr ""
@@ -27002,9 +27920,6 @@ msgstr ""
msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
msgstr ""
-msgid "Use a hardware device to add the second factor of authentication."
-msgstr ""
-
msgid "Use an one time password authenticator on your mobile device or computer to enable two-factor authentication (2FA)."
msgstr ""
@@ -27278,13 +28193,13 @@ msgstr ""
msgid "Users"
msgstr ""
-msgid "Users in License:"
+msgid "Users in License"
msgstr ""
-msgid "Users or groups set as approvers in the project's or merge request's settings."
+msgid "Users in License:"
msgstr ""
-msgid "Users outside of license"
+msgid "Users or groups set as approvers in the project's or merge request's settings."
msgstr ""
msgid "Users over License:"
@@ -27302,9 +28217,6 @@ msgstr ""
msgid "Users with a Guest role or those who don't belong to a Project or Group will not use a seat from your license."
msgstr ""
-msgid "Users with a Guest role or those who don't belong to any projects or groups don't count towards seats in use."
-msgstr ""
-
msgid "UsersSelect|%{name} + %{length} more"
msgstr ""
@@ -27344,9 +28256,6 @@ msgstr ""
msgid "Validations failed."
msgstr ""
-msgid "Validity"
-msgstr ""
-
msgid "Value"
msgstr ""
@@ -27365,6 +28274,9 @@ msgstr ""
msgid "Value Stream Name"
msgstr ""
+msgid "ValueStreamAnalyticsStage|We don't have enough data to show this stage."
+msgstr ""
+
msgid "ValueStreamAnalytics|%{days}d"
msgstr ""
@@ -27621,6 +28533,9 @@ msgstr ""
msgid "VisualReviewApp|Steps 1 and 2 (and sometimes 3) are performed once by the developer before requesting feedback. Steps 3 (if necessary), 4 is performed by the reviewer each time they perform a review."
msgstr ""
+msgid "Visualization"
+msgstr ""
+
msgid "Vulnerabilities"
msgstr ""
@@ -27648,34 +28563,31 @@ msgstr ""
msgid "VulnerabilityChart|Severity"
msgstr ""
-msgid "VulnerabilityManagement|A true-positive and will fix"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Change status"
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|Confirm"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Confirmed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
-msgstr ""
-
-msgid "VulnerabilityManagement|Detected %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|A true-positive and will fix"
msgstr ""
-msgid "VulnerabilityManagement|Dismiss"
+msgid "VulnerabilityManagement|Change status"
msgstr ""
-msgid "VulnerabilityManagement|Dismissed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
msgstr ""
-msgid "VulnerabilityManagement|Resolved"
+msgid "VulnerabilityManagement|Detected"
msgstr ""
-msgid "VulnerabilityManagement|Resolved %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Needs triage"
msgstr ""
msgid "VulnerabilityManagement|Something went wrong while trying to delete the comment. Please try again later."
@@ -27726,6 +28638,9 @@ msgstr ""
msgid "Vulnerability|%{scannerName} (version %{scannerVersion})"
msgstr ""
+msgid "Vulnerability|Activity"
+msgstr ""
+
msgid "Vulnerability|Class"
msgstr ""
@@ -27738,6 +28653,9 @@ msgstr ""
msgid "Vulnerability|Description"
msgstr ""
+msgid "Vulnerability|Detected"
+msgstr ""
+
msgid "Vulnerability|Evidence"
msgstr ""
@@ -27801,6 +28719,9 @@ msgstr ""
msgid "Warning: Displaying this diagram might cause performance issues on this page."
msgstr ""
+msgid "We are currently unable to fetch data for the pipeline header."
+msgstr ""
+
msgid "We are currently unable to fetch data for this graph."
msgstr ""
@@ -27840,6 +28761,12 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
+msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
+msgstr ""
+
+msgid "We would like to inform you that your subscription GitLab Enterprise Edition %{plan_name} is nearing its user limit. You have %{active_user_count} active users, which is almost at the user limit of %{maximum_user_count}."
+msgstr ""
+
msgid "We've found no vulnerabilities"
msgstr ""
@@ -27855,6 +28782,12 @@ msgstr ""
msgid "Web terminal"
msgstr ""
+msgid "WebAuthn Devices (%{length})"
+msgstr ""
+
+msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
+msgstr ""
+
msgid "WebIDE|Merge request"
msgstr ""
@@ -27993,15 +28926,9 @@ msgstr ""
msgid "Welcome to the guided GitLab tour"
msgstr ""
-msgid "Welcome to your Issue Board!"
-msgstr ""
-
msgid "Welcome to your issue board!"
msgstr ""
-msgid "We’ve been making changes to %{featureName} and we’d love your feedback %{linkStart}in this issue%{linkEnd} to help us improve the experience."
-msgstr ""
-
msgid "What are you searching for?"
msgstr ""
@@ -28020,6 +28947,9 @@ msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
msgstr ""
+msgid "When enabled, any user visiting %{host} and creating an account will have to be explicitly approved by the admin before they can login. This setting is effective only if sign-ups are enabled."
+msgstr ""
+
msgid "When enabled, any user visiting %{host} will be able to create an account."
msgstr ""
@@ -28244,6 +29174,9 @@ msgstr ""
msgid "With requirements, you can set criteria to check your products against."
msgstr ""
+msgid "With test cases, you can define conditions for your project to meet in determining quality"
+msgstr ""
+
msgid "Withdraw Access Request"
msgstr ""
@@ -28259,6 +29192,9 @@ msgstr ""
msgid "Workflow Help"
msgstr ""
+msgid "Would you like to create a new branch?"
+msgstr ""
+
msgid "Write"
msgstr ""
@@ -28280,6 +29216,9 @@ msgstr ""
msgid "Wrong extern UID provided. Make sure Auth0 is configured correctly."
msgstr ""
+msgid "YYYY-MM-DD"
+msgstr ""
+
msgid "Yes"
msgstr ""
@@ -28337,7 +29276,7 @@ msgstr ""
msgid "You are going to remove the fork relationship from %{project_full_name}. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "You are going to transfer %{project_full_name} to another owner. Are you ABSOLUTELY sure?"
+msgid "You are going to transfer %{project_full_name} to another namespace. Are you ABSOLUTELY sure?"
msgstr ""
msgid "You are going to turn off the confidentiality. This means %{strongStart}everyone%{strongEnd} will be able to see and leave a comment on this %{issuableType}."
@@ -28397,9 +29336,6 @@ msgstr ""
msgid "You can always edit this later"
msgstr ""
-msgid "You can apply your Trial to your Personal account or create a New Group."
-msgstr ""
-
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings"
msgstr ""
@@ -28421,12 +29357,18 @@ msgstr ""
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
+msgid "You can find more information about GitLab subscriptions in %{subscriptions_doc_link}."
+msgstr ""
+
msgid "You can generate an access token scoped to this project for each application to use the GitLab API."
msgstr ""
msgid "You can get started by cloning the repository or start adding files to it with one of the following options."
msgstr ""
+msgid "You can group test cases using labels. To learn about the future direction of this feature, visit %{linkStart}Quality Management direction page%{linkEnd}."
+msgstr ""
+
msgid "You can invite a new member to %{project_name} or invite another group."
msgstr ""
@@ -28442,6 +29384,9 @@ msgstr ""
msgid "You can notify the app / group or a project by sending them an email notification"
msgstr ""
+msgid "You can now close this window."
+msgstr ""
+
msgid "You can now export your security dashboard to a CSV report."
msgstr ""
@@ -28490,9 +29435,6 @@ msgstr ""
msgid "You can test your .gitlab-ci.yml in %{linkStart}CI Lint%{linkEnd}."
msgstr ""
-msgid "You can try again using %{begin_link}basic search%{end_link}"
-msgstr ""
-
msgid "You cannot access the raw file. Please wait a minute."
msgstr ""
@@ -28544,6 +29486,9 @@ msgstr ""
msgid "You don't have any U2F devices registered yet."
msgstr ""
+msgid "You don't have any WebAuthn devices registered yet."
+msgstr ""
+
msgid "You don't have any active chat names."
msgstr ""
@@ -28631,6 +29576,9 @@ msgstr ""
msgid "You must accept our Terms of Service and privacy policy in order to register an account"
msgstr ""
+msgid "You must be logged in to search across all of GitLab"
+msgstr ""
+
msgid "You must disassociate %{domain} from all clusters it is attached to before deletion."
msgstr ""
@@ -28670,7 +29618,7 @@ msgstr ""
msgid "You need to be logged in."
msgstr ""
-msgid "You need to register a two-factor authentication app before you can set up a U2F device."
+msgid "You need to register a two-factor authentication app before you can set up a device."
msgstr ""
msgid "You need to set terms to be enforced"
@@ -28688,6 +29636,9 @@ msgstr ""
msgid "You reached %{usage_in_percent} of %{namespace_name}'s storage capacity (%{used_storage} of %{storage_limit})"
msgstr ""
+msgid "You successfully declined the invitation"
+msgstr ""
+
msgid "You tried to fork %{link_to_the_project} but it failed for the following reason:"
msgstr ""
@@ -28853,10 +29804,13 @@ msgstr ""
msgid "Your U2F device did not send a valid JSON response."
msgstr ""
-msgid "Your U2F device needs to be set up. Plug it in (if not already) and click the button on the left."
+msgid "Your U2F device was registered!"
msgstr ""
-msgid "Your U2F device was registered!"
+msgid "Your WebAuthn device did not send a valid JSON response."
+msgstr ""
+
+msgid "Your WebAuthn device was registered!"
msgstr ""
msgid "Your access request to the %{source_type} has been withdrawn."
@@ -28880,6 +29834,9 @@ msgstr ""
msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
msgstr ""
+msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
+msgstr ""
+
msgid "Your changes can be committed to %{branch_name} because a merge request is open."
msgstr ""
@@ -28916,6 +29873,12 @@ msgstr ""
msgid "Your deployment services will be broken, you will need to manually fix the services after renaming."
msgstr ""
+msgid "Your device is not compatible with GitLab. Please try another device"
+msgstr ""
+
+msgid "Your device needs to be set up. Plug it in (if needed) and click the button on the left."
+msgstr ""
+
msgid "Your device was successfully set up! Give it a name and register it with the GitLab server."
msgstr ""
@@ -29029,9 +29992,6 @@ msgstr[1] ""
msgid "access:"
msgstr ""
-msgid "activated"
-msgstr ""
-
msgid "added %{created_at_timeago}"
msgstr ""
@@ -29104,9 +30064,21 @@ msgstr ""
msgid "by %{user}"
msgstr ""
+msgid "cannot be a date in the past"
+msgstr ""
+
msgid "cannot be changed if a personal project has container registry tags."
msgstr ""
+msgid "cannot be changed if shared runners are enabled"
+msgstr ""
+
+msgid "cannot be enabled because parent group does not allow it"
+msgstr ""
+
+msgid "cannot be enabled because parent group has shared Runners disabled"
+msgstr ""
+
msgid "cannot be enabled unless all domains have TLS certificates"
msgstr ""
@@ -29152,7 +30124,7 @@ msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about SAST %{linkEndTag}"
msgstr ""
-msgid "ciReport|%{linkStartTag}Learn more about Secret Scanning %{linkEndTag}"
+msgid "ciReport|%{linkStartTag}Learn more about Secret Detection %{linkEndTag}"
msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about codequality reports %{linkEndTag}"
@@ -29467,9 +30439,6 @@ msgstr ""
msgid "error"
msgstr ""
-msgid "error code:"
-msgstr ""
-
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr ""
@@ -29491,6 +30460,9 @@ msgstr ""
msgid "failed to dismiss associated finding(id=%{finding_id}): %{message}"
msgstr ""
+msgid "failed to revert associated finding(id=%{finding_id}) to detected"
+msgstr ""
+
msgid "file"
msgid_plural "files"
msgstr[0] ""
@@ -30033,6 +31005,9 @@ msgstr ""
msgid "must be a root namespace"
msgstr ""
+msgid "must be a valid IPv4 or IPv6 address"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -30069,6 +31044,9 @@ msgstr ""
msgid "no expiration"
msgstr ""
+msgid "no name set"
+msgstr ""
+
msgid "no one can merge"
msgstr ""
@@ -30247,9 +31225,6 @@ msgstr ""
msgid "security Reports|There was an error creating the merge request"
msgstr ""
-msgid "settings saved, but not activated"
-msgstr ""
-
msgid "severity|Critical"
msgstr ""
@@ -30376,9 +31351,6 @@ msgstr ""
msgid "toggle collapse"
msgstr ""
-msgid "toggle dropdown"
-msgstr ""
-
msgid "triggered"
msgstr ""
@@ -30406,6 +31378,9 @@ msgstr ""
msgid "user avatar"
msgstr ""
+msgid "user preferences"
+msgstr ""
+
msgid "username"
msgstr ""
diff --git a/locale/pl_PL/gitlab.po b/locale/pl_PL/gitlab.po
index 952e2204bd3..131ba69cb00 100644
--- a/locale/pl_PL/gitlab.po
+++ b/locale/pl_PL/gitlab.po
@@ -14,7 +14,10 @@ msgstr ""
"X-Crowdin-Language: pl\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 6\n"
-"PO-Revision-Date: 2020-09-04 23:09\n"
+"PO-Revision-Date: 2020-10-02 18:49\n"
+
+msgid " %{project_name}#%{issue_iid} &middot; opened %{issue_created} by %{author}"
+msgstr ""
msgid " %{start} to %{end}"
msgstr ""
@@ -78,6 +81,20 @@ msgstr ""
msgid "\"el\" parameter is required for createInstance()"
msgstr ""
+msgid "%d Approval"
+msgid_plural "%d Approvals"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
+msgid "%d Package"
+msgid_plural "%d Packages"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%d Scanned URL"
msgid_plural "%d Scanned URLs"
msgstr[0] ""
@@ -165,6 +182,13 @@ msgstr[3] ""
msgid "%d commits"
msgstr ""
+msgid "%d completed issue"
+msgid_plural "%d completed issues"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%d contribution"
msgid_plural "%d contributions"
msgstr[0] ""
@@ -179,6 +203,13 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "%d day until tags are automatically removed"
+msgid_plural "%d days until tags are automatically removed"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%d error"
msgid_plural "%d errors"
msgstr[0] ""
@@ -305,6 +336,20 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "%d open issue"
+msgid_plural "%d open issues"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
+msgid "%d pending comment"
+msgid_plural "%d pending comments"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%d personal project will be removed and cannot be restored."
msgid_plural "%d personal projects will be removed and cannot be restored."
msgstr[0] ""
@@ -326,6 +371,13 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "%d project selected"
+msgid_plural "%d projects selected"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%d request with warnings"
msgid_plural "%d requests with warnings"
msgstr[0] ""
@@ -354,6 +406,13 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "%d tag per image name"
+msgid_plural "%d tags per image name"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%d unassigned issue"
msgid_plural "%d unassigned issues"
msgstr[0] ""
@@ -382,6 +441,13 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "%d warning found:"
+msgid_plural "%d warnings found:"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%s additional commit has been omitted to prevent performance issues."
msgid_plural "%s additional commits have been omitted to prevent performance issues."
msgstr[0] ""
@@ -422,6 +488,9 @@ msgstr ""
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr ""
+msgid "%{completedCount} completed weight"
+msgstr ""
+
msgid "%{completedWeight} of %{totalWeight} weight completed"
msgstr ""
@@ -476,16 +545,12 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "%{count} pending comment"
-msgid_plural "%{count} pending comments"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
+msgid "%{count} total weight"
+msgstr ""
+
msgid "%{dashboard_path} could not be found."
msgstr ""
@@ -540,6 +605,9 @@ msgstr ""
msgid "%{group_name} uses group managed accounts. You need to create a new GitLab account which will be managed by %{group_name}."
msgstr ""
+msgid "%{group_name}&%{epic_iid} &middot; opened %{epic_created} by %{author}"
+msgstr ""
+
msgid "%{host} sign-in from new location"
msgstr ""
@@ -552,7 +620,7 @@ msgstr ""
msgid "%{issuableType} will be removed! Are you sure?"
msgstr ""
-msgid "%{issuesSize} issues with a limit of %{maxIssueCount}"
+msgid "%{issuesCount} issues with a limit of %{maxIssueCount}"
msgstr ""
msgid "%{issuesSize} with a limit of %{maxIssueCount}"
@@ -585,7 +653,7 @@ msgstr ""
msgid "%{labelStart}Namespace:%{labelEnd} %{namespace}"
msgstr ""
-msgid "%{labelStart}Report Type:%{labelEnd} %{reportType}"
+msgid "%{labelStart}Scan Type:%{labelEnd} %{reportType}"
msgstr ""
msgid "%{labelStart}Scanner:%{labelEnd} %{scanner}"
@@ -796,9 +864,6 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "%{service_title} %{message}."
-msgstr ""
-
msgid "%{size} GiB"
msgstr ""
@@ -897,6 +962,12 @@ msgstr ""
msgid "%{timebox_name} should belong either to a project or a group."
msgstr ""
+msgid "%{timebox_type} does not support burnup charts"
+msgstr ""
+
+msgid "%{timebox_type} must have a start and due date"
+msgstr ""
+
msgid "%{title} %{operator} %{threshold}"
msgstr ""
@@ -921,7 +992,7 @@ msgstr ""
msgid "%{total} open issue weight"
msgstr ""
-msgid "%{total} open issues"
+msgid "%{total} warnings found: showing first %{warningsDisplayed}"
msgstr ""
msgid "%{usage_ping_link_start}Learn more%{usage_ping_link_end} about what information is shared with GitLab Inc."
@@ -954,9 +1025,6 @@ msgstr ""
msgid "&lt; 1 hour"
msgstr ""
-msgid "&lt;no name set&gt;"
-msgstr ""
-
msgid "&lt;no scopes selected&gt;"
msgstr ""
@@ -987,6 +1055,9 @@ msgstr ""
msgid "'%{name}' Value Stream created"
msgstr ""
+msgid "'%{name}' Value Stream deleted"
+msgstr ""
+
msgid "'%{name}' stage already exists"
msgstr ""
@@ -1048,6 +1119,9 @@ msgstr ""
msgid "+ %{numberOfHiddenAssignees} more"
msgstr ""
+msgid "+ %{numberOfHiddenReviewers} more"
+msgstr ""
+
msgid "+%d more"
msgid_plural "+%d more"
msgstr[0] ""
@@ -1120,6 +1194,13 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "1 Issue"
+msgid_plural "%d Issues"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "1 closed issue"
msgid_plural "%{issues} closed issues"
msgstr[0] ""
@@ -1141,6 +1222,13 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "1 deploy key"
+msgid_plural "%d deploy keys"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1261,6 +1349,9 @@ msgstr ""
msgid ":%{startLine} to %{endLine}"
msgstr ""
+msgid "A %{incident_docs_start}modified issue%{incident_docs_end} to guide the resolution of incidents."
+msgstr ""
+
msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr ""
@@ -1273,6 +1364,9 @@ msgstr ""
msgid "A GitBook site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
+msgid "A Gitpod configured Webapplication in Spring and Java"
+msgstr ""
+
msgid "A Hexo site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
@@ -1444,9 +1538,15 @@ msgstr ""
msgid "Access expiration date"
msgstr ""
+msgid "Access expires"
+msgstr ""
+
msgid "Access forbidden. Check your access level."
msgstr ""
+msgid "Access granted"
+msgstr ""
+
msgid "Access requests"
msgstr ""
@@ -1456,6 +1556,9 @@ msgstr ""
msgid "Access to Pages websites are controlled based on the user's membership to a given project. By checking this box, users will be required to be logged in to have access to all Pages websites in your instance."
msgstr ""
+msgid "AccessDropdown|Deploy Keys"
+msgstr ""
+
msgid "AccessDropdown|Groups"
msgstr ""
@@ -1573,12 +1676,6 @@ msgstr ""
msgid "Active Sessions"
msgstr ""
-msgid "Active Users:"
-msgstr ""
-
-msgid "Active users"
-msgstr ""
-
msgid "Activity"
msgstr ""
@@ -1748,9 +1845,6 @@ msgstr ""
msgid "Add label(s)"
msgstr ""
-msgid "Add license"
-msgstr ""
-
msgid "Add list"
msgstr ""
@@ -1925,21 +2019,51 @@ msgstr ""
msgid "AdminArea|Bots"
msgstr ""
+msgid "AdminArea|Components"
+msgstr ""
+
msgid "AdminArea|Developer"
msgstr ""
+msgid "AdminArea|Features"
+msgstr ""
+
+msgid "AdminArea|Groups: %{number_of_groups}"
+msgstr ""
+
msgid "AdminArea|Guest"
msgstr ""
msgid "AdminArea|Included Free in license"
msgstr ""
+msgid "AdminArea|Latest groups"
+msgstr ""
+
+msgid "AdminArea|Latest projects"
+msgstr ""
+
+msgid "AdminArea|Latest users"
+msgstr ""
+
msgid "AdminArea|Maintainer"
msgstr ""
+msgid "AdminArea|New group"
+msgstr ""
+
+msgid "AdminArea|New project"
+msgstr ""
+
+msgid "AdminArea|New user"
+msgstr ""
+
msgid "AdminArea|Owner"
msgstr ""
+msgid "AdminArea|Projects: %{number_of_projects}"
+msgstr ""
+
msgid "AdminArea|Reporter"
msgstr ""
@@ -1967,6 +2091,9 @@ msgstr ""
msgid "AdminArea|Users without a Group and Project"
msgstr ""
+msgid "AdminArea|Users: %{number_of_users}"
+msgstr ""
+
msgid "AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running."
msgstr ""
@@ -1985,9 +2112,6 @@ msgstr ""
msgid "AdminProjects|Delete Project %{projectName}?"
msgstr ""
-msgid "AdminProjects|Delete project"
-msgstr ""
-
msgid "AdminSettings|Apply integration settings to all Projects"
msgstr ""
@@ -2225,21 +2349,30 @@ msgstr ""
msgid "AdminUsers|Without projects"
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 ""
msgid "AdminUsers|You cannot remove your own admin rights."
msgstr ""
+msgid "AdminUsers|You must transfer ownership or delete the groups owned by this user before you can delete their account"
+msgstr ""
+
msgid "Administration"
msgstr ""
msgid "Advanced"
msgstr ""
+msgid "Advanced Search"
+msgstr ""
+
+msgid "Advanced Search with Elasticsearch"
+msgstr ""
+
msgid "Advanced Settings"
msgstr ""
@@ -2319,6 +2452,9 @@ msgstr ""
msgid "AlertManagement|Edit"
msgstr ""
+msgid "AlertManagement|Environment"
+msgstr ""
+
msgid "AlertManagement|Events"
msgstr ""
@@ -2331,6 +2467,9 @@ msgstr ""
msgid "AlertManagement|Issue"
msgstr ""
+msgid "AlertManagement|Key"
+msgstr ""
+
msgid "AlertManagement|Low"
msgstr ""
@@ -2424,6 +2563,9 @@ msgstr ""
msgid "AlertManagement|Unknown"
msgstr ""
+msgid "AlertManagement|Value"
+msgstr ""
+
msgid "AlertManagement|View alerts in Opsgenie"
msgstr ""
@@ -2583,6 +2725,9 @@ msgstr ""
msgid "All projects"
msgstr ""
+msgid "All projects selected"
+msgstr ""
+
msgid "All security scans are enabled because %{linkStart}Auto DevOps%{linkEnd} is enabled on this project"
msgstr ""
@@ -2670,6 +2815,9 @@ msgstr ""
msgid "Almost there"
msgstr ""
+msgid "Already blocked"
+msgstr ""
+
msgid "Also called \"Issuer\" or \"Relying party trust identifier\""
msgstr ""
@@ -2724,6 +2872,9 @@ msgstr ""
msgid "An error has occurred"
msgstr ""
+msgid "An error occured while making the changes: %{error}"
+msgstr ""
+
msgid "An error occurred adding a draft to the thread."
msgstr ""
@@ -2751,12 +2902,6 @@ msgstr ""
msgid "An error occurred when toggling the notification subscription"
msgstr ""
-msgid "An error occurred when trying to resolve a comment. Please try again."
-msgstr ""
-
-msgid "An error occurred when trying to resolve a discussion. Please try again."
-msgstr ""
-
msgid "An error occurred when updating the issue weight"
msgstr ""
@@ -2772,12 +2917,6 @@ msgstr ""
msgid "An error occurred while checking group path. Please refresh and try again."
msgstr ""
-msgid "An error occurred while committing your changes."
-msgstr ""
-
-msgid "An error occurred while creating the list. Please try again."
-msgstr ""
-
msgid "An error occurred while decoding the file."
msgstr ""
@@ -2850,25 +2989,19 @@ msgstr ""
msgid "An error occurred while fetching the Service Desk address."
msgstr ""
-msgid "An error occurred while fetching the board issues. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the board lists. Please reload the page."
msgstr ""
msgid "An error occurred while fetching the board lists. Please try again."
msgstr ""
-msgid "An error occurred while fetching the board swimlanes. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the builds."
msgstr ""
msgid "An error occurred while fetching the job log."
msgstr ""
-msgid "An error occurred while fetching the job trace."
+msgid "An error occurred while fetching the job logs."
msgstr ""
msgid "An error occurred while fetching the job."
@@ -3015,9 +3148,6 @@ msgstr ""
msgid "An error occurred while saving assignees"
msgstr ""
-msgid "An error occurred while saving the template. Please check if the template exists."
-msgstr ""
-
msgid "An error occurred while searching for milestones"
msgstr ""
@@ -3036,12 +3166,12 @@ msgstr ""
msgid "An error occurred while updating approvers"
msgstr ""
+msgid "An error occurred while updating labels."
+msgstr ""
+
msgid "An error occurred while updating the comment"
msgstr "Wystąpił błąd podczas aktualizacji komentarza"
-msgid "An error occurred while updating the list. Please try again."
-msgstr ""
-
msgid "An error occurred while validating group path"
msgstr ""
@@ -3093,6 +3223,9 @@ msgstr ""
msgid "An unknown error occurred while loading this graph."
msgstr ""
+msgid "An unknown error occurred."
+msgstr ""
+
msgid "Analytics"
msgstr ""
@@ -3126,10 +3259,10 @@ msgstr ""
msgid "Any"
msgstr ""
-msgid "Any Author"
+msgid "Any %{header}"
msgstr ""
-msgid "Any Status"
+msgid "Any Author"
msgstr ""
msgid "Any branch"
@@ -3183,6 +3316,9 @@ msgstr ""
msgid "Application ID"
msgstr ""
+msgid "Application limits saved successfully"
+msgstr ""
+
msgid "Application settings saved successfully"
msgstr ""
@@ -3400,6 +3536,9 @@ msgstr ""
msgid "Are you sure you want to close this blocked issue?"
msgstr ""
+msgid "Are you sure you want to delete \"%{name}\" Value Stream?"
+msgstr ""
+
msgid "Are you sure you want to delete %{name}?"
msgstr ""
@@ -3409,6 +3548,9 @@ msgstr ""
msgid "Are you sure you want to delete this %{typeOfComment}?"
msgstr ""
+msgid "Are you sure you want to delete this SSH key?"
+msgstr ""
+
msgid "Are you sure you want to delete this board?"
msgstr ""
@@ -3433,6 +3575,13 @@ msgstr ""
msgid "Are you sure you want to erase this build?"
msgstr "Czy na pewno chcesz usunąć tę kompilację?"
+msgid "Are you sure you want to import %d repository?"
+msgid_plural "Are you sure you want to import %d repositories?"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "Are you sure you want to lose unsaved changes?"
msgstr ""
@@ -3442,15 +3591,15 @@ msgstr ""
msgid "Are you sure you want to merge immediately?"
msgstr ""
-msgid "Are you sure you want to permanently delete this license?"
-msgstr ""
-
msgid "Are you sure you want to re-deploy this environment?"
msgstr ""
msgid "Are you sure you want to regenerate the public key? You will have to update the public key on the remote server before mirroring will work again."
msgstr ""
+msgid "Are you sure you want to reindex?"
+msgstr ""
+
msgid "Are you sure you want to remove %{group_name}?"
msgstr ""
@@ -3478,6 +3627,9 @@ msgstr ""
msgid "Are you sure you want to revoke this nickname?"
msgstr ""
+msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
+msgstr ""
+
msgid "Are you sure you want to stop this environment?"
msgstr "Czy na pewno chcesz zatrzymać to środowisko?"
@@ -3499,6 +3651,9 @@ msgstr ""
msgid "Are you sure? The device will be signed out of GitLab and all remember me tokens revoked."
msgstr ""
+msgid "Are you sure? This will invalidate your registered applications and U2F / WebAuthn devices."
+msgstr ""
+
msgid "Are you sure? This will invalidate your registered applications and U2F devices."
msgstr ""
@@ -3517,9 +3672,6 @@ msgstr ""
msgid "Artifacts"
msgstr ""
-msgid "As U2F devices are only supported by a few browsers, we require that you set up a two-factor authentication app before a U2F device. That way you'll always be able to log in - even when you're using an unsupported browser."
-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 ""
@@ -3717,6 +3869,9 @@ msgstr ""
msgid "AuditLogs|Target"
msgstr ""
+msgid "AuditLogs|This month"
+msgstr ""
+
msgid "AuditLogs|User Events"
msgstr ""
@@ -3756,6 +3911,9 @@ msgstr ""
msgid "Authentication via U2F device failed."
msgstr ""
+msgid "Authentication via WebAuthn device failed."
+msgstr ""
+
msgid "Author"
msgstr ""
@@ -4023,15 +4181,6 @@ msgstr ""
msgid "BambooService|You must set up automatic revision labeling and a repository trigger in Bamboo."
msgstr ""
-msgid "BatchComments|Delete all pending comments"
-msgstr ""
-
-msgid "BatchComments|Discard review?"
-msgstr ""
-
-msgid "BatchComments|You're about to discard your review which will delete all of your pending comments. The deleted comments %{strong_start}cannot%{strong_end} be restored."
-msgstr "Zamierzasz odrzucić swoją recenzję, co usunie wszystkie Twoje oczekujące komentarze. Usunięte komentarze %{strong_start}nie mogą%{strong_end} zostać przywrócone."
-
msgid "Be careful. Changing the project's namespace can have unintended side effects."
msgstr ""
@@ -4053,6 +4202,9 @@ msgstr ""
msgid "Bi-weekly code coverage"
msgstr ""
+msgid "Billable Users:"
+msgstr ""
+
msgid "Billing"
msgstr ""
@@ -4062,7 +4214,7 @@ msgstr ""
msgid "BillingPlans|@%{user_name} you are currently using the %{plan_name} plan."
msgstr ""
-msgid "BillingPlans|Congratulations, your new trial is activated"
+msgid "BillingPlans|Congratulations, your free trial is activated."
msgstr ""
msgid "BillingPlans|If you would like to downgrade your plan please contact %{support_link_start}Customer Support%{support_link_end}."
@@ -4125,6 +4277,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Block user"
+msgstr ""
+
msgid "Blocked"
msgstr ""
@@ -4140,31 +4295,37 @@ msgstr ""
msgid "Blog"
msgstr ""
-msgid "Board name"
-msgstr ""
-
msgid "Board scope"
msgstr ""
msgid "Board scope affects which issues are displayed for anyone who visits this board"
msgstr ""
-msgid "BoardBlankState|Add default lists"
+msgid "Boards"
msgstr ""
-msgid "BoardBlankState|Add the following default lists to your Issue Board with one click:"
+msgid "Boards and Board Lists"
msgstr ""
-msgid "BoardBlankState|Nevermind, I'll use my own"
+msgid "Boards|An error occurred while creating the issue. Please try again."
msgstr ""
-msgid "BoardBlankState|Starting out with the default set of lists will get you right on the way to making the most of your board."
+msgid "Boards|An error occurred while creating the list. Please try again."
msgstr ""
-msgid "Boards"
+msgid "Boards|An error occurred while fetching issues. Please reload the page."
msgstr ""
-msgid "Boards and Board Lists"
+msgid "Boards|An error occurred while fetching the board issues. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching the board swimlanes. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while moving the issue. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while updating the list. Please try again."
msgstr ""
msgid "Boards|Collapse"
@@ -4191,7 +4352,7 @@ msgstr ""
msgid "Branch %{branch_name} was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr ""
-msgid "Branch has changed"
+msgid "Branch changed"
msgstr ""
msgid "Branch is already taken"
@@ -4497,6 +4658,9 @@ msgstr ""
msgid "CLOSED (MOVED)"
msgstr ""
+msgid "CODEOWNERS rule violation"
+msgstr ""
+
msgid "CONTRIBUTING"
msgstr ""
@@ -4527,9 +4691,6 @@ msgstr ""
msgid "Can't create snippet: %{err}"
msgstr ""
-msgid "Can't edit as source branch was deleted"
-msgstr ""
-
msgid "Can't fetch content for the blob: %{err}"
msgstr ""
@@ -4542,9 +4703,6 @@ msgstr ""
msgid "Can't load mermaid module: %{err}"
msgstr ""
-msgid "Can't remove group members without group managed account"
-msgstr ""
-
msgid "Can't scan the code?"
msgstr ""
@@ -4587,6 +4745,9 @@ msgstr ""
msgid "Cannot create the abuse report. This user has been blocked."
msgstr ""
+msgid "Cannot enable shared runners because parent group does not allow it"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -4692,6 +4853,15 @@ msgstr ""
msgid "Change your password or recover your current one"
msgstr ""
+msgid "ChangeReviewer|Reviewer changed from %{old} to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Reviewer changed to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Unassigned"
+msgstr ""
+
msgid "ChangeTypeActionLabel|Pick into branch"
msgstr ""
@@ -4731,6 +4901,9 @@ msgstr ""
msgid "Changes the title to \"%{title_param}\"."
msgstr ""
+msgid "Changes were successfully made."
+msgstr ""
+
msgid "Changes won't take place until the index is %{link_start}recreated%{link_end}."
msgstr ""
@@ -5136,6 +5309,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove variable"
+msgstr ""
+
msgid "CiVariables|Remove variable row"
msgstr ""
@@ -5214,9 +5390,6 @@ msgstr ""
msgid "Clear due date"
msgstr ""
-msgid "Clear input"
-msgstr ""
-
msgid "Clear recent searches"
msgstr ""
@@ -5265,6 +5438,9 @@ msgstr ""
msgid "Client authentication key password"
msgstr ""
+msgid "Client request timeout"
+msgstr ""
+
msgid "Clients"
msgstr ""
@@ -5349,6 +5525,27 @@ msgstr ""
msgid "Cluster type must be specificed for Stages::ClusterEndpointInserter"
msgstr ""
+msgid "ClusterAgents|Configuration"
+msgstr ""
+
+msgid "ClusterAgents|Connect your cluster with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate Kubernetes with a GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Name"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Agent also requires %{linkStart}enabling the Agent Server%{linkEnd}"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Kubernetes Agent allows an Infrastructure as Code, GitOps approach to integrating Kubernetes clusters with GitLab. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "ClusterAgent|This feature is only available for premium plans"
msgstr ""
@@ -5418,10 +5615,10 @@ msgstr ""
msgid "ClusterIntegration|All installed applications and related resources"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster."
+msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{linkStart}More information%{linkEnd}"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{startLink}More information%{endLink}"
+msgid "ClusterIntegration|Allow GitLab to manage namespaces and service accounts for this cluster."
msgstr ""
msgid "ClusterIntegration|Alternatively, "
@@ -5442,6 +5639,9 @@ msgstr ""
msgid "ClusterIntegration|An error occurred while trying to fetch zone machine types: %{error}"
msgstr ""
+msgid "ClusterIntegration|An unknown error occurred while attempting to connect to Kubernetes."
+msgstr ""
+
msgid "ClusterIntegration|Any project namespaces"
msgstr ""
@@ -5457,6 +5657,9 @@ msgstr ""
msgid "ClusterIntegration|Authenticate with Amazon Web Services"
msgstr ""
+msgid "ClusterIntegration|Authentication Error"
+msgstr ""
+
msgid "ClusterIntegration|Base domain"
msgstr ""
@@ -5475,13 +5678,22 @@ msgstr ""
msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}security group %{externalLinkIcon} %{endLink} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
+msgid "ClusterIntegration|Check your CA certificate"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}subnets %{externalLinkIcon} %{endLink} in your VPC where your worker nodes will run."
+msgid "ClusterIntegration|Check your cluster status"
msgstr ""
-msgid "ClusterIntegration|Choose the worker node %{startLink}instance type %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Check your token"
+msgstr ""
+
+msgid "ClusterIntegration|Choose the %{linkStart}security group %{linkEnd} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
+msgstr ""
+
+msgid "ClusterIntegration|Choose the %{linkStart}subnets %{linkEnd} in your VPC where your worker nodes will run."
+msgstr ""
+
+msgid "ClusterIntegration|Choose the worker node %{linkStart}instance type%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Choose which applications to install on your Kubernetes cluster."
@@ -5493,10 +5705,7 @@ msgstr "Wybierz, które z Twoich środowisk będą używać tego klastra."
msgid "ClusterIntegration|Clear cluster cache"
msgstr ""
-msgid "ClusterIntegration|Clear the local cache of namespace and service accounts. This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
-msgstr ""
-
-msgid "ClusterIntegration|Cluster being created"
+msgid "ClusterIntegration|Clear the local cache of namespace and service accounts."
msgstr ""
msgid "ClusterIntegration|Cluster management project (alpha)"
@@ -5508,15 +5717,21 @@ msgstr ""
msgid "ClusterIntegration|Cluster_applications artifact too big. Maximum allowable size: %{human_size}"
msgstr ""
-msgid "ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters."
+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|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}"
+msgid "ClusterIntegration|Clusters connected with a certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Connect cluster with certificate"
msgstr ""
msgid "ClusterIntegration|Connect existing cluster"
msgstr ""
+msgid "ClusterIntegration|Connection Error"
+msgstr ""
+
msgid "ClusterIntegration|Copy API URL"
msgstr ""
@@ -5592,6 +5807,12 @@ msgstr ""
msgid "ClusterIntegration|Deletes all GitLab resources attached to this cluster during removal"
msgstr ""
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared."
+msgstr ""
+
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared. %{linkStart}More information%{linkEnd}"
+msgstr ""
+
msgid "ClusterIntegration|Did you know?"
msgstr ""
@@ -5661,6 +5882,9 @@ msgstr ""
msgid "ClusterIntegration|Fluentd is an open source data collector, which lets you unify the data collection and consumption for a better use and understanding of data. It requires at least one of the following logs to be successfully installed."
msgstr ""
+msgid "ClusterIntegration|GitLab Agent managed clusters"
+msgstr ""
+
msgid "ClusterIntegration|GitLab Container Network Policies"
msgstr ""
@@ -5673,6 +5897,12 @@ msgstr ""
msgid "ClusterIntegration|GitLab Runner connects to the repository and executes CI/CD jobs, pushing results back and deploying applications to production."
msgstr ""
+msgid "ClusterIntegration|GitLab failed to authenticate."
+msgstr ""
+
+msgid "ClusterIntegration|GitLab failed to connect to the cluster."
+msgstr ""
+
msgid "ClusterIntegration|GitLab-managed cluster"
msgstr ""
@@ -5694,6 +5924,9 @@ msgstr ""
msgid "ClusterIntegration|Group cluster"
msgstr "Klaster grupowy"
+msgid "ClusterIntegration|HTTP Error"
+msgstr ""
+
msgid "ClusterIntegration|Helm Tiller"
msgstr ""
@@ -5727,7 +5960,10 @@ msgstr ""
msgid "ClusterIntegration|Instance type"
msgstr ""
-msgid "ClusterIntegration|Integrate Kubernetes cluster automation"
+msgid "ClusterIntegration|Integrate Kubernetes with a cluster certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Integrate with a cluster certificate"
msgstr ""
msgid "ClusterIntegration|Issuer Email"
@@ -5763,9 +5999,6 @@ msgstr ""
msgid "ClusterIntegration|Knative extends Kubernetes to provide a set of middleware components that are essential to build modern, source-centric, and container-based applications that can run anywhere: on premises, in the cloud, or even in a third-party data center."
msgstr ""
-msgid "ClusterIntegration|Kubernetes cluster"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes cluster is being created..."
msgstr ""
@@ -5778,9 +6011,6 @@ msgstr ""
msgid "ClusterIntegration|Kubernetes clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr "Klastry Kubernetes pozwalają Ci w łatwy sposób używać aplikacji oceniających, wdrażać aplikacje, uruchamiać procesy i wiele więcej."
-msgid "ClusterIntegration|Kubernetes clusters can be used to deploy applications and to provide Review Apps for this project"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes version"
msgstr ""
@@ -5793,7 +6023,7 @@ msgstr "Dowiedz się więcej o %{help_link_start_machine_type}rodzajach maszyn%{
msgid "ClusterIntegration|Learn more about %{help_link_start}zones%{help_link_end}."
msgstr ""
-msgid "ClusterIntegration|Learn more about %{startLink}Regions %{externalLinkIcon}%{endLink}."
+msgid "ClusterIntegration|Learn more about %{linkStart}Regions%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Learn more about Kubernetes"
@@ -5838,12 +6068,18 @@ msgstr ""
msgid "ClusterIntegration|Machine type"
msgstr ""
+msgid "ClusterIntegration|Make sure your API endpoint is correct"
+msgstr ""
+
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create Kubernetes clusters"
msgstr ""
msgid "ClusterIntegration|Manage your Kubernetes cluster by visiting %{provider_link}"
msgstr ""
+msgid "ClusterIntegration|Namespace per environment"
+msgstr ""
+
msgid "ClusterIntegration|No IAM Roles found"
msgstr ""
@@ -5889,6 +6125,9 @@ msgstr ""
msgid "ClusterIntegration|No zones matched your search"
msgstr ""
+msgid "ClusterIntegration|Node calculations use the Kubernetes Metrics API. Make sure your cluster has metrics installed"
+msgstr ""
+
msgid "ClusterIntegration|Number of nodes"
msgstr ""
@@ -5931,6 +6170,9 @@ msgstr ""
msgid "ClusterIntegration|RBAC-enabled cluster"
msgstr ""
+msgid "ClusterIntegration|Read our %{linkStart}help page%{linkEnd} on Kubernetes cluster integration."
+msgstr ""
+
msgid "ClusterIntegration|Read our %{link_start}help page%{link_end} on Kubernetes cluster integration."
msgstr ""
@@ -6033,7 +6275,7 @@ msgstr ""
msgid "ClusterIntegration|Select a VPC to choose a subnet"
msgstr ""
-msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{linkStart}Amazon Web Services %{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select a network to choose a subnetwork"
@@ -6066,7 +6308,7 @@ msgstr ""
msgid "ClusterIntegration|Select project to choose zone"
msgstr ""
-msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select zone"
@@ -6156,9 +6398,18 @@ msgstr ""
msgid "ClusterIntegration|There was a problem authenticating with your cluster. Please ensure your CA Certificate and Token are valid."
msgstr ""
+msgid "ClusterIntegration|There was an HTTP error when connecting to your cluster."
+msgstr ""
+
msgid "ClusterIntegration|This account must have permissions to create a Kubernetes cluster in the %{link_to_container_project} specified below"
msgstr ""
+msgid "ClusterIntegration|This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
+msgstr ""
+
+msgid "ClusterIntegration|This is necessary to clear existing environment-namespace associations from clusters previously managed by GitLab."
+msgstr ""
+
msgid "ClusterIntegration|This option will allow you to install applications on RBAC clusters."
msgstr ""
@@ -6183,9 +6434,21 @@ msgstr ""
msgid "ClusterIntegration|To use a new project, first create one on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}."
msgstr ""
+msgid "ClusterIntegration|Troubleshooting tips:"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Authenticate"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Connect"
+msgstr ""
+
msgid "ClusterIntegration|Uninstall %{appTitle}"
msgstr ""
+msgid "ClusterIntegration|Unknown Error"
+msgstr ""
+
msgid "ClusterIntegration|Update %{appTitle}"
msgstr ""
@@ -6246,7 +6509,7 @@ msgstr ""
msgid "ClusterIntegration|Your cluster API is unreachable. Please ensure your API URL is correct."
msgstr ""
-msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Zone"
@@ -6366,6 +6629,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse all threads"
+msgstr ""
+
msgid "Collapse approvers"
msgstr ""
@@ -6517,7 +6783,7 @@ msgstr ""
msgid "Commit…"
msgstr ""
-msgid "Company"
+msgid "Community forum"
msgstr ""
msgid "Company name"
@@ -6526,6 +6792,9 @@ msgstr ""
msgid "Compare"
msgstr ""
+msgid "Compare %{oldCommitId}...%{newCommitId}"
+msgstr ""
+
msgid "Compare Git revisions"
msgstr ""
@@ -6541,6 +6810,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare submodule commit revisions"
+msgstr ""
+
msgid "Compare with previous version"
msgstr ""
@@ -6676,6 +6948,9 @@ msgstr ""
msgid "Configure the way a user creates a new account."
msgstr ""
+msgid "Configure which lists are shown for anyone who visits this board"
+msgstr ""
+
msgid "Confirm"
msgstr ""
@@ -6907,6 +7182,9 @@ msgstr[3] ""
msgid "ContainerRegistry|Set cleanup policy"
msgstr ""
+msgid "ContainerRegistry|Some tags were not deleted"
+msgstr ""
+
msgid "ContainerRegistry|Something went wrong while fetching the cleanup policy."
msgstr ""
@@ -6946,6 +7224,9 @@ msgstr ""
msgid "ContainerRegistry|Tags with names matching this regex pattern will %{italicStart}expire:%{italicEnd}"
msgstr ""
+msgid "ContainerRegistry|The cleanup policy timed out before it could delete all tags. An administrator can %{adminLinkStart}manually run cleanup now%{adminLinkEnd} or you can wait for the cleanup policy to automatically run again. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "ContainerRegistry|The last tag related to this image was recently removed. This empty image and any associated data will be automatically removed as part of the regular Garbage Collection process. If you have any questions, contact your administrator."
msgstr ""
@@ -7078,6 +7359,9 @@ msgstr ""
msgid "Contributions per group member"
msgstr ""
+msgid "Contributor"
+msgstr ""
+
msgid "Contributors"
msgstr ""
@@ -7207,6 +7491,9 @@ msgstr ""
msgid "Could not change HEAD: branch '%{branch}' does not exist"
msgstr ""
+msgid "Could not commit. An unexpected error occurred."
+msgstr ""
+
msgid "Could not connect to FogBugz, check your URL"
msgstr ""
@@ -7246,6 +7533,9 @@ msgstr ""
msgid "Could not find iteration"
msgstr ""
+msgid "Could not load instance counts. Please refresh the page to try again."
+msgstr ""
+
msgid "Could not remove the trigger."
msgstr ""
@@ -7270,10 +7560,10 @@ msgstr ""
msgid "Could not save prometheus manual configuration"
msgstr ""
-msgid "Could not udpdate wiki page"
+msgid "Could not update the LDAP settings"
msgstr ""
-msgid "Could not update the LDAP settings"
+msgid "Could not update wiki page"
msgstr ""
msgid "Could not upload your designs as one or more files uploaded are not supported."
@@ -7935,6 +8225,9 @@ msgstr ""
msgid "DastProfiles|Are you sure you want to delete this profile?"
msgstr ""
+msgid "DastProfiles|Could not create site validation token. Please refresh the page, or try again later."
+msgstr ""
+
msgid "DastProfiles|Could not create the scanner profile. Please try again."
msgstr ""
@@ -7959,6 +8252,12 @@ msgstr ""
msgid "DastProfiles|Could not fetch site profiles. Please refresh the page, or try again later."
msgstr ""
+msgid "DastProfiles|Could not retrieve site validation status. Please refresh the page, or try again later."
+msgstr ""
+
+msgid "DastProfiles|Could not update the scanner profile. Please try again."
+msgstr ""
+
msgid "DastProfiles|Could not update the site profile. Please try again."
msgstr ""
@@ -7974,7 +8273,7 @@ msgstr ""
msgid "DastProfiles|Download validation text file"
msgstr ""
-msgid "DastProfiles|Edit feature will come soon. Please create a new profile if changes needed"
+msgid "DastProfiles|Edit scanner profile"
msgstr ""
msgid "DastProfiles|Edit site profile"
@@ -8007,6 +8306,9 @@ msgstr ""
msgid "DastProfiles|No profiles created yet"
msgstr ""
+msgid "DastProfiles|Passive"
+msgstr ""
+
msgid "DastProfiles|Please enter a valid URL format, ex: http://www.example.com/home"
msgstr ""
@@ -8022,6 +8324,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan mode"
+msgstr ""
+
msgid "DastProfiles|Scanner Profile"
msgstr ""
@@ -8061,10 +8366,10 @@ msgstr ""
msgid "DastProfiles|Text file validation"
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
+msgid "DastProfiles|The maximum number of minutes allowed for the spider to traverse the site."
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the spider to traverse the site."
+msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
msgstr ""
msgid "DastProfiles|Validate"
@@ -8097,6 +8402,9 @@ msgstr ""
msgid "Date picker"
msgstr ""
+msgid "Date range"
+msgstr ""
+
msgid "Date range cannot exceed %{maxDateRange} days."
msgstr ""
@@ -8121,6 +8429,9 @@ msgstr ""
msgid "Days to merge"
msgstr ""
+msgid "Dear Administrator,"
+msgstr ""
+
msgid "Debug"
msgstr ""
@@ -8232,12 +8543,18 @@ msgstr ""
msgid "Delete"
msgstr ""
+msgid "Delete %{name}"
+msgstr ""
+
msgid "Delete Comment"
msgstr ""
msgid "Delete Snippet"
msgstr ""
+msgid "Delete Value Stream"
+msgstr ""
+
msgid "Delete account"
msgstr ""
@@ -8259,9 +8576,6 @@ msgstr ""
msgid "Delete label: %{label_name} ?"
msgstr ""
-msgid "Delete license"
-msgstr ""
-
msgid "Delete list"
msgstr ""
@@ -8337,15 +8651,6 @@ msgstr ""
msgid "Deleting a project places it into a read-only state until %{date}, at which point the project will be permanently deleted. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "Deleting the license failed."
-msgstr ""
-
-msgid "Deleting the license failed. The license was not found."
-msgstr ""
-
-msgid "Deleting the license failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "Deleting the project will delete its repository and all related resources including issues, merge requests etc."
msgstr ""
@@ -8853,7 +9158,10 @@ msgstr ""
msgid "DesignManagement|The maximum number of designs allowed to be uploaded is %{upload_limit}. Please try again."
msgstr ""
-msgid "DesignManagement|To upload designs, you'll need to enable LFS. %{requirements_link_start}More information%{requirements_link_end}"
+msgid "DesignManagement|There was an error moving your designs. Please upload your designs below."
+msgstr ""
+
+msgid "DesignManagement|To upload designs, you'll need to enable LFS and have admin enable hashed storage. %{requirements_link_start}More information%{requirements_link_end}"
msgstr ""
msgid "DesignManagement|Unresolve thread"
@@ -8865,6 +9173,9 @@ msgstr ""
msgid "DesignManagement|Upload skipped."
msgstr ""
+msgid "DesignManagement|Your designs are being copied and are on their way… Please refresh to update."
+msgstr ""
+
msgid "DesignManagement|and %{moreCount} more."
msgstr ""
@@ -8922,6 +9233,9 @@ msgstr ""
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
+msgid "Direct member"
+msgstr ""
+
msgid "Direction"
msgstr ""
@@ -8970,9 +9284,6 @@ msgstr ""
msgid "Discard draft"
msgstr ""
-msgid "Discard review"
-msgstr ""
-
msgid "DiscordService|Discord Notifications"
msgstr ""
@@ -9043,10 +9354,10 @@ msgstr ""
msgid "Dismiss Merge Request promotion"
msgstr ""
-msgid "Dismiss Selected"
+msgid "Dismiss Value Stream Analytics introduction box"
msgstr ""
-msgid "Dismiss Value Stream Analytics introduction box"
+msgid "Dismiss selected"
msgstr ""
msgid "Dismiss trial promotion"
@@ -9097,9 +9408,6 @@ msgstr ""
msgid "Documents reindexed: %{processed_documents} (%{percentage}%%)"
msgstr ""
-msgid "Doing"
-msgstr ""
-
msgid "Domain"
msgstr ""
@@ -9295,9 +9603,6 @@ msgstr ""
msgid "Edit environment"
msgstr ""
-msgid "Edit file"
-msgstr ""
-
msgid "Edit files in the editor and commit changes here"
msgstr ""
@@ -9310,6 +9615,12 @@ msgstr ""
msgid "Edit identity for %{user_name}"
msgstr ""
+msgid "Edit in Web IDE"
+msgstr ""
+
+msgid "Edit in single-file editor"
+msgstr ""
+
msgid "Edit issues"
msgstr ""
@@ -9337,10 +9648,10 @@ msgstr ""
msgid "Editing"
msgstr ""
-msgid "Elasticsearch"
+msgid "Elasticsearch AWS IAM credentials"
msgstr ""
-msgid "Elasticsearch AWS IAM credentials"
+msgid "Elasticsearch HTTP client timeout value in seconds."
msgstr ""
msgid "Elasticsearch indexing restrictions"
@@ -9349,9 +9660,6 @@ msgstr ""
msgid "Elasticsearch indexing started"
msgstr ""
-msgid "Elasticsearch integration. Elasticsearch AWS IAM."
-msgstr ""
-
msgid "Elasticsearch reindexing is already in progress"
msgstr ""
@@ -9379,9 +9687,6 @@ msgstr ""
msgid "Email Notification"
msgstr ""
-msgid "Email address"
-msgstr ""
-
msgid "Email could not be sent"
msgstr ""
@@ -9445,6 +9750,9 @@ msgstr ""
msgid "Emails sent from Service Desk will have this name"
msgstr ""
+msgid "Emails sent to %{email} will still be supported"
+msgstr ""
+
msgid "Emails separated by comma"
msgstr ""
@@ -9478,9 +9786,18 @@ msgstr ""
msgid "Enable"
msgstr ""
+msgid "Enable %{link_start}Gitpod%{link_end} integration to launch a development environment in your browser directly from GitLab."
+msgstr ""
+
msgid "Enable Auto DevOps"
msgstr ""
+msgid "Enable Gitpod"
+msgstr ""
+
+msgid "Enable Gitpod?"
+msgstr ""
+
msgid "Enable HTML emails"
msgstr ""
@@ -9610,9 +9927,6 @@ msgstr ""
msgid "Encountered an error while rendering: %{err}"
msgstr ""
-msgid "End date"
-msgstr ""
-
msgid "Ends at (UTC)"
msgstr ""
@@ -9772,7 +10086,7 @@ msgstr ""
msgid "EnvironmentsDashboard|The environments dashboard provides a summary of each project's environments' status, including pipeline and alert statuses."
msgstr ""
-msgid "EnvironmentsDashboard|This dashboard displays a maximum of 7 projects and 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
+msgid "EnvironmentsDashboard|This dashboard displays 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
msgstr ""
msgid "Environments|An error occurred while canceling the auto stop, please try again"
@@ -10093,6 +10407,9 @@ msgstr ""
msgid "Error deleting project. Check logs for error details."
msgstr ""
+msgid "Error fetching burnup chart data"
+msgstr ""
+
msgid "Error fetching diverging counts for branches. Please try again."
msgstr ""
@@ -10171,6 +10488,9 @@ msgstr ""
msgid "Error occurred when saving assignees"
msgstr ""
+msgid "Error occurred when saving reviewers"
+msgstr ""
+
msgid "Error occurred when toggling the notification subscription"
msgstr ""
@@ -10423,10 +10743,13 @@ msgstr ""
msgid "Expand all"
msgstr ""
-msgid "Expand approvers"
+msgid "Expand all files"
+msgstr ""
+
+msgid "Expand all threads"
msgstr ""
-msgid "Expand dropdown"
+msgid "Expand approvers"
msgstr ""
msgid "Expand milestones"
@@ -10597,6 +10920,9 @@ msgstr ""
msgid "Failed to create Merge Request. Please try again."
msgstr ""
+msgid "Failed to create To-Do for the design."
+msgstr ""
+
msgid "Failed to create a branch for this issue. Please try again."
msgstr ""
@@ -10636,6 +10962,12 @@ msgstr ""
msgid "Failed to load authors. Please try again."
msgstr ""
+msgid "Failed to load branches. Please try again."
+msgstr ""
+
+msgid "Failed to load deploy keys."
+msgstr ""
+
msgid "Failed to load emoji list."
msgstr ""
@@ -10651,6 +10983,9 @@ msgstr ""
msgid "Failed to load groups & users."
msgstr ""
+msgid "Failed to load groups, users and deploy keys."
+msgstr ""
+
msgid "Failed to load labels. Please try again."
msgstr ""
@@ -10660,6 +10995,12 @@ msgstr ""
msgid "Failed to load related branches"
msgstr ""
+msgid "Failed to load sidebar confidential toggle"
+msgstr ""
+
+msgid "Failed to load sidebar lock status"
+msgstr ""
+
msgid "Failed to load stacktrace."
msgstr ""
@@ -10687,6 +11028,9 @@ msgstr ""
msgid "Failed to publish issue on status page."
msgstr ""
+msgid "Failed to remove To-Do for the design."
+msgstr ""
+
msgid "Failed to remove a Zoom meeting"
msgstr ""
@@ -10729,6 +11073,9 @@ msgstr ""
msgid "Failed to signing using smartcard authentication"
msgstr ""
+msgid "Failed to toggle To-Do for the design."
+msgstr ""
+
msgid "Failed to update branch!"
msgstr ""
@@ -10844,7 +11191,7 @@ msgstr ""
msgid "FeatureFlags|Edit User List"
msgstr ""
-msgid "FeatureFlags|Enable features for specific users and specific environments by defining feature flag strategies."
+msgid "FeatureFlags|Enable features for specific users and environments by configuring feature flag strategies."
msgstr ""
msgid "FeatureFlags|Environment Spec"
@@ -10904,7 +11251,7 @@ msgstr ""
msgid "FeatureFlags|Include additional user IDs"
msgstr ""
-msgid "FeatureFlags|Install a %{docs_link_anchored_start}compatible client library%{docs_link_anchored_end} and specify the API URL, application name, and instance ID during the configuration setup. %{docs_link_start}More Information%{docs_link_end}"
+msgid "FeatureFlags|Install a %{docsLinkAnchoredStart}compatible client library%{docsLinkAnchoredEnd} and specify the API URL, application name, and instance ID during the configuration setup. %{docsLinkStart}More Information%{docsLinkEnd}"
msgstr ""
msgid "FeatureFlags|Instance ID"
@@ -10916,6 +11263,9 @@ msgstr ""
msgid "FeatureFlags|Loading feature flags"
msgstr ""
+msgid "FeatureFlags|Loading user lists"
+msgstr ""
+
msgid "FeatureFlags|More information"
msgstr ""
@@ -10934,7 +11284,7 @@ msgstr ""
msgid "FeatureFlags|New feature flag"
msgstr ""
-msgid "FeatureFlags|New list"
+msgid "FeatureFlags|New user list"
msgstr ""
msgid "FeatureFlags|Percent of users"
@@ -10973,6 +11323,9 @@ msgstr ""
msgid "FeatureFlags|There was an error fetching the feature flags."
msgstr ""
+msgid "FeatureFlags|There was an error fetching the user lists."
+msgstr ""
+
msgid "FeatureFlags|There was an error retrieving user lists"
msgstr ""
@@ -10988,6 +11341,9 @@ msgstr ""
msgid "FeatureFlags|User List"
msgstr ""
+msgid "FeatureFlags|User Lists"
+msgstr ""
+
msgid "FeatureFlag|List"
msgstr ""
@@ -11015,15 +11371,6 @@ msgstr ""
msgid "Fetching incoming email"
msgstr ""
-msgid "Fetching licenses failed."
-msgstr ""
-
-msgid "Fetching licenses failed. The request endpoint was not found."
-msgstr ""
-
-msgid "Fetching licenses failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "File"
msgstr ""
@@ -11126,12 +11473,21 @@ msgstr ""
msgid "Filter by status"
msgstr ""
+msgid "Filter by test cases that are currently archived."
+msgstr ""
+
+msgid "Filter by test cases that are currently opened."
+msgstr ""
+
msgid "Filter by two-factor authentication"
msgstr ""
msgid "Filter by user"
msgstr ""
+msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
+msgstr ""
+
msgid "Filter pipelines"
msgstr ""
@@ -11147,7 +11503,7 @@ msgstr ""
msgid "Filter results..."
msgstr ""
-msgid "Filter your projects by name"
+msgid "Filter your repositories by name"
msgstr ""
msgid "Filter..."
@@ -11156,7 +11512,7 @@ msgstr ""
msgid "Find File"
msgstr ""
-msgid "Find bugs in your code with coverage-guided fuzzing"
+msgid "Find bugs in your code with coverage-guided fuzzing."
msgstr ""
msgid "Find by path"
@@ -11183,9 +11539,6 @@ msgstr ""
msgid "Finish editing this message first!"
msgstr ""
-msgid "Finish review"
-msgstr ""
-
msgid "Finish setting up your dedicated account for %{group_name}."
msgstr ""
@@ -11255,6 +11608,9 @@ msgstr ""
msgid "Footer message"
msgstr ""
+msgid "For a faster browsing experience, some files are collapsed by default."
+msgstr ""
+
msgid "For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
@@ -11264,6 +11620,9 @@ msgstr ""
msgid "For more info, read the documentation."
msgstr ""
+msgid "For more information on how the number of active users is calculated, see the %{self_managed_subscriptions_doc_link} documentation."
+msgstr ""
+
msgid "For more information, go to the "
msgstr ""
@@ -11402,6 +11761,9 @@ msgstr ""
msgid "Generate new token"
msgstr ""
+msgid "Generic package file size in bytes"
+msgstr ""
+
msgid "Geo"
msgstr ""
@@ -11663,6 +12025,9 @@ msgstr ""
msgid "Geo|Please refer to Geo Troubleshooting."
msgstr ""
+msgid "Geo|Primary node"
+msgstr ""
+
msgid "Geo|Project"
msgstr ""
@@ -11705,6 +12070,9 @@ msgstr ""
msgid "Geo|Review replication status, and resynchronize and reverify items with the primary node."
msgstr ""
+msgid "Geo|Secondary node"
+msgstr ""
+
msgid "Geo|Status"
msgstr ""
@@ -11744,6 +12112,9 @@ msgstr ""
msgid "Geo|URL must be a valid url (ex: https://gitlab.com)"
msgstr ""
+msgid "Geo|Undefined"
+msgstr ""
+
msgid "Geo|Unknown state"
msgstr ""
@@ -11819,10 +12190,16 @@ msgstr ""
msgid "GitHub import"
msgstr ""
+msgid "GitLab"
+msgstr ""
+
msgid "GitLab / Unsubscribe"
msgstr ""
-msgid "GitLab Enterprise Edition %{plan}"
+msgid "GitLab API"
+msgstr ""
+
+msgid "GitLab Billing Team."
msgstr ""
msgid "GitLab Group Runners can execute code for all the projects in this group."
@@ -11834,12 +12211,18 @@ msgstr ""
msgid "GitLab Issue"
msgstr ""
+msgid "GitLab Pages"
+msgstr ""
+
msgid "GitLab Service Desk is a simple way to allow people to create issues in your GitLab instance without needing their own user account. It provides a unique email address for end users to create issues in a project, and replies can be sent either through the GitLab interface or by email. End users will only see the thread through email."
msgstr ""
msgid "GitLab Shared Runners execute code of different projects on the same Runner unless you configure GitLab Runner Autoscale with MaxBuilds 1 (which it is on GitLab.com)."
msgstr ""
+msgid "GitLab Shell"
+msgstr ""
+
msgid "GitLab Support Bot"
msgstr ""
@@ -11849,7 +12232,7 @@ msgstr ""
msgid "GitLab User"
msgstr ""
-msgid "GitLab allows you to continue using your license even if you exceed the number of seats you purchased. You will be required to pay for these seats when you renew your license."
+msgid "GitLab Workhorse"
msgstr ""
msgid "GitLab commit"
@@ -12017,6 +12400,21 @@ msgstr ""
msgid "Gitlab Pages"
msgstr ""
+msgid "Gitpod"
+msgstr ""
+
+msgid "Gitpod|Add the URL to your Gitpod instance configured to read your GitLab projects."
+msgstr ""
+
+msgid "Gitpod|Enable Gitpod integration"
+msgstr ""
+
+msgid "Gitpod|Gitpod URL"
+msgstr ""
+
+msgid "Gitpod|e.g. https://gitpod.example.com"
+msgstr ""
+
msgid "Given access %{time_ago}"
msgstr ""
@@ -12524,9 +12922,6 @@ msgstr ""
msgid "GroupSAML|Valid SAML Response"
msgstr ""
-msgid "GroupSAML|With group managed accounts enabled, all the users without a group managed account will be excluded from the group."
-msgstr ""
-
msgid "GroupSAML|With prohibit outer forks flag enabled group members will be able to fork project only inside your group."
msgstr ""
@@ -12740,10 +13135,10 @@ msgstr ""
msgid "GroupsNew|Create group"
msgstr ""
-msgid "GroupsNew|GitLab group export"
+msgid "GroupsNew|Import"
msgstr ""
-msgid "GroupsNew|Import"
+msgid "GroupsNew|Import a GitLab group export file"
msgstr ""
msgid "GroupsNew|Import group"
@@ -12888,6 +13283,9 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "Hide comments on this file"
+msgstr ""
+
msgid "Hide details"
msgstr ""
@@ -12934,6 +13332,15 @@ msgstr ""
msgid "Highest role:"
msgstr ""
+msgid "HighlightBar|Alert events:"
+msgstr ""
+
+msgid "HighlightBar|Alert start time:"
+msgstr ""
+
+msgid "HighlightBar|Original alert:"
+msgstr ""
+
msgid "History"
msgstr ""
@@ -13111,6 +13518,9 @@ msgstr ""
msgid "If enabled, access to projects will be validated on an external service using their classification label."
msgstr ""
+msgid "If the number of active users exceeds the user limit, you will be charged for the number of %{users_over_license_link} at your next license reconciliation."
+msgstr ""
+
msgid "If there is no previous license or if the previous license has expired, some GitLab functionality will be blocked until a new, valid license is uploaded."
msgstr ""
@@ -13150,9 +13560,6 @@ msgstr ""
msgid "If your HTTP repository is not publicly accessible, add your credentials."
msgstr ""
-msgid "Iglu registry URL (optional)"
-msgstr ""
-
msgid "Ignore"
msgstr ""
@@ -13189,6 +13596,20 @@ msgstr ""
msgid "Import"
msgstr ""
+msgid "Import %d compatible repository"
+msgid_plural "Import %d compatible repositories"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
+msgid "Import %d repository"
+msgid_plural "Import %d repositories"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "Import CSV"
msgstr ""
@@ -13198,15 +13619,9 @@ msgstr ""
msgid "Import all compatible projects"
msgstr ""
-msgid "Import all compatible repositories"
-msgstr ""
-
msgid "Import all projects"
msgstr ""
-msgid "Import all repositories"
-msgstr ""
-
msgid "Import an exported GitLab project"
msgstr ""
@@ -13294,6 +13709,9 @@ msgstr ""
msgid "ImportProjects|Error importing repository %{project_safe_import_url} into %{project_full_path} - %{message}"
msgstr ""
+msgid "ImportProjects|Import repositories"
+msgstr ""
+
msgid "ImportProjects|Importing the project failed"
msgstr ""
@@ -13306,7 +13724,7 @@ msgstr ""
msgid "ImportProjects|Requesting your %{provider} repositories failed"
msgstr ""
-msgid "ImportProjects|Select the projects you want to import"
+msgid "ImportProjects|Select the repositories you want to import"
msgstr ""
msgid "ImportProjects|The remote data could not be imported."
@@ -13342,9 +13760,6 @@ msgstr ""
msgid "In order to enable Service Desk for your instance, you must first set up incoming email."
msgstr ""
-msgid "In order to gather accurate feature usage data, it can take 1 to 2 weeks to see your index."
-msgstr ""
-
msgid "In order to personalize your experience with GitLab%{br_tag}we would like to know a bit more about you."
msgstr ""
@@ -13375,18 +13790,30 @@ msgstr ""
msgid "IncidentManagement|Create incident"
msgstr ""
+msgid "IncidentManagement|Critical - S1"
+msgstr ""
+
msgid "IncidentManagement|Date created"
msgstr ""
msgid "IncidentManagement|Display your incidents in a dedicated view"
msgstr ""
+msgid "IncidentManagement|High - S2"
+msgstr ""
+
msgid "IncidentManagement|Incident"
msgstr ""
msgid "IncidentManagement|Incidents"
msgstr ""
+msgid "IncidentManagement|Low - S4"
+msgstr ""
+
+msgid "IncidentManagement|Medium - S3"
+msgstr ""
+
msgid "IncidentManagement|No incidents to display."
msgstr ""
@@ -13399,6 +13826,9 @@ msgstr ""
msgid "IncidentManagement|Published to status page"
msgstr ""
+msgid "IncidentManagement|Severity"
+msgstr ""
+
msgid "IncidentManagement|There are no closed incidents"
msgstr ""
@@ -13408,6 +13838,9 @@ msgstr ""
msgid "IncidentManagement|Unassigned"
msgstr ""
+msgid "IncidentManagement|Unknown"
+msgstr ""
+
msgid "IncidentManagement|Unpublished"
msgstr ""
@@ -13429,6 +13862,15 @@ msgstr ""
msgid "Incidents"
msgstr ""
+msgid "Incident|Alert details"
+msgstr ""
+
+msgid "Incident|Summary"
+msgstr ""
+
+msgid "Incident|There was an issue loading alert data. Please try again."
+msgstr ""
+
msgid "Include a Terms of Service agreement and Privacy Policy that all users must accept."
msgstr ""
@@ -13489,6 +13931,9 @@ msgstr ""
msgid "Information about additional Pages templates and how to install them can be found in our %{pages_getting_started_guide}."
msgstr ""
+msgid "Inherited"
+msgstr ""
+
msgid "Inherited:"
msgstr ""
@@ -13571,7 +14016,22 @@ msgstr ""
msgid "Instance administrators group already exists"
msgstr ""
-msgid "Instance license"
+msgid "InstanceStatistics|Groups"
+msgstr ""
+
+msgid "InstanceStatistics|Issues"
+msgstr ""
+
+msgid "InstanceStatistics|Merge Requests"
+msgstr ""
+
+msgid "InstanceStatistics|Pipelines"
+msgstr ""
+
+msgid "InstanceStatistics|Projects"
+msgstr ""
+
+msgid "InstanceStatistics|Users"
msgstr ""
msgid "Integration"
@@ -13583,6 +14043,12 @@ msgstr ""
msgid "Integrations"
msgstr ""
+msgid "Integrations|%{integration} settings saved and active."
+msgstr ""
+
+msgid "Integrations|%{integration} settings saved, but not active."
+msgstr ""
+
msgid "Integrations|All details"
msgstr ""
@@ -13592,6 +14058,12 @@ msgstr ""
msgid "Integrations|Comment settings:"
msgstr ""
+msgid "Integrations|Connection failed. Please check your settings."
+msgstr ""
+
+msgid "Integrations|Connection successful."
+msgstr ""
+
msgid "Integrations|Default settings are inherited from the group level."
msgstr ""
@@ -13607,6 +14079,15 @@ msgstr ""
msgid "Integrations|Includes commit title and branch"
msgstr ""
+msgid "Integrations|Projects using custom settings will not be impacted unless the project owner chooses to use instance-level defaults."
+msgstr ""
+
+msgid "Integrations|Save settings?"
+msgstr ""
+
+msgid "Integrations|Saving will update the default settings for all projects that are not using custom settings."
+msgstr ""
+
msgid "Integrations|Standard"
msgstr ""
@@ -13739,6 +14220,9 @@ msgstr ""
msgid "Invitation"
msgstr ""
+msgid "Invitation declined"
+msgstr ""
+
msgid "Invite"
msgstr ""
@@ -13790,6 +14274,42 @@ 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|%{linkStart}Read more%{linkEnd} about role permissions"
+msgstr ""
+
+msgid "InviteMembersModal|Access expiration date (optional)"
+msgstr ""
+
+msgid "InviteMembersModal|Cancel"
+msgstr ""
+
+msgid "InviteMembersModal|Choose a role permission"
+msgstr ""
+
+msgid "InviteMembersModal|GitLab member or Email address"
+msgstr ""
+
+msgid "InviteMembersModal|Invite"
+msgstr ""
+
+msgid "InviteMembersModal|Invite team members"
+msgstr ""
+
+msgid "InviteMembersModal|Search for members to invite"
+msgstr ""
+
+msgid "InviteMembersModal|User not invited. Feature coming soon!"
+msgstr ""
+
+msgid "InviteMembersModal|Users were succesfully added"
+msgstr ""
+
+msgid "InviteMembersModal|You're inviting members to the %{group_name} group"
+msgstr ""
+
+msgid "InviteMembers|Invite team members"
+msgstr ""
+
msgid "Invited"
msgstr ""
@@ -13844,10 +14364,13 @@ msgstr ""
msgid "Issue cannot be found."
msgstr ""
+msgid "Issue created from vulnerability %{vulnerability_link}"
+msgstr ""
+
msgid "Issue events"
msgstr ""
-msgid "Issue first depoloyed to production"
+msgid "Issue first deployed to production"
msgstr ""
msgid "Issue label"
@@ -13925,6 +14448,9 @@ msgstr ""
msgid "IssueTracker|Custom issue tracker"
msgstr ""
+msgid "IssueTracker|EWM work items tracker"
+msgstr ""
+
msgid "IssueTracker|Redmine issue tracker"
msgstr ""
@@ -13991,6 +14517,9 @@ msgstr ""
msgid "It looks like you have some draft commits in this branch."
msgstr ""
+msgid "It may be several days before you see feature usage data."
+msgstr ""
+
msgid "It must have a header row and at least two columns: the first column is the issue title and the second column is the issue description. The separator is automatically detected."
msgstr ""
@@ -14273,13 +14802,13 @@ msgstr ""
msgid "Join Zoom meeting"
msgstr ""
-msgid "Jul"
+msgid "Joined %{time_ago}"
msgstr ""
-msgid "July"
+msgid "Jul"
msgstr ""
-msgid "Jump to first unresolved thread"
+msgid "July"
msgstr ""
msgid "Jump to next unresolved thread"
@@ -14315,6 +14844,9 @@ msgstr ""
msgid "Keyboard shortcuts"
msgstr ""
+msgid "KeyboardKey|Ctrl+"
+msgstr ""
+
msgid "Keys"
msgstr ""
@@ -14363,6 +14895,9 @@ msgstr ""
msgid "LDAP Synchronization"
msgstr ""
+msgid "LDAP group settings"
+msgstr ""
+
msgid "LDAP settings"
msgstr ""
@@ -14372,6 +14907,9 @@ msgstr ""
msgid "LDAP sync in progress. This could take a few minutes. Refresh the page to see the changes."
msgstr ""
+msgid "LDAP synchronizations"
+msgstr ""
+
msgid "LFS"
msgstr ""
@@ -14454,7 +14992,16 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "Last %{days} days"
+msgid "Last 2 weeks"
+msgstr ""
+
+msgid "Last 30 days"
+msgstr ""
+
+msgid "Last 60 days"
+msgstr ""
+
+msgid "Last 90 days"
msgstr ""
msgid "Last Accessed On"
@@ -14532,6 +15079,9 @@ msgstr ""
msgid "Last used on:"
msgstr ""
+msgid "Last week"
+msgstr ""
+
msgid "LastCommit|authored"
msgstr ""
@@ -14547,6 +15097,9 @@ msgstr ""
msgid "Latest pipeline for the most recent commit on this branch"
msgstr ""
+msgid "Launch a ready-to-code development environment for your project."
+msgstr ""
+
msgid "Lead"
msgstr ""
@@ -14941,6 +15494,9 @@ msgstr ""
msgid "List of all merge commits"
msgstr ""
+msgid "List options"
+msgstr ""
+
msgid "List settings"
msgstr ""
@@ -14953,9 +15509,6 @@ msgstr ""
msgid "List your Bitbucket Server repositories"
msgstr ""
-msgid "Lists"
-msgstr ""
-
msgid "Live preview"
msgstr ""
@@ -15202,6 +15755,12 @@ msgstr ""
msgid "Mark as done"
msgstr ""
+msgid "Mark as draft"
+msgstr ""
+
+msgid "Mark as ready"
+msgstr ""
+
msgid "Mark as resolved"
msgstr ""
@@ -15223,6 +15782,24 @@ msgstr ""
msgid "Markdown is supported"
msgstr ""
+msgid "MarkdownEditor|Add a link (%{modifierKey}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add a link (%{modifier_key}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifierKey}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifier_key}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifierKey}I)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifier_key}I)"
+msgstr ""
+
msgid "Marked For Deletion At - %{deletion_time}"
msgstr ""
@@ -15307,7 +15884,25 @@ msgstr ""
msgid "Max access level"
msgstr ""
-msgid "Max seats used"
+msgid "Max role"
+msgstr ""
+
+msgid "Max size 15 MB"
+msgstr ""
+
+msgid "Maximum Conan package file size in bytes"
+msgstr ""
+
+msgid "Maximum Maven package file size in bytes"
+msgstr ""
+
+msgid "Maximum NPM package file size in bytes"
+msgstr ""
+
+msgid "Maximum NuGet package file size in bytes"
+msgstr ""
+
+msgid "Maximum PyPI package file size in bytes"
msgstr ""
msgid "Maximum Users:"
@@ -15439,6 +16034,18 @@ msgstr ""
msgid "Members with access to %{strong_start}%{group_name}%{strong_end}"
msgstr ""
+msgid "Members|%{time} by %{user}"
+msgstr ""
+
+msgid "Members|Expired"
+msgstr ""
+
+msgid "Members|No expiration set"
+msgstr ""
+
+msgid "Members|in %{time}"
+msgstr ""
+
msgid "Memory Usage"
msgstr ""
@@ -15625,9 +16232,6 @@ msgstr ""
msgid "MergeRequests|Thread will be unresolved"
msgstr ""
-msgid "MergeRequests|Toggle comments for this file"
-msgstr ""
-
msgid "MergeRequests|View file @ %{commitId}"
msgstr ""
@@ -15688,6 +16292,9 @@ msgstr ""
msgid "Merging immediately isn't recommended as it may negatively impact the existing merge train. Read the %{docsLinkStart}documentation%{docsLinkEnd} for more information."
msgstr ""
+msgid "Message"
+msgstr ""
+
msgid "Messages"
msgstr ""
@@ -16077,18 +16684,12 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "Milestone does not support burnup charts"
-msgstr ""
-
msgid "Milestone lists not available with your current license"
msgstr ""
msgid "Milestone lists show all issues from the selected milestone."
msgstr ""
-msgid "Milestone must have a start and due date"
-msgstr ""
-
msgid "MilestoneSidebar|Closed:"
msgstr ""
@@ -16455,6 +17056,9 @@ msgstr ""
msgid "Namespace"
msgstr ""
+msgid "Namespace ID:"
+msgstr ""
+
msgid "Namespace is empty"
msgstr ""
@@ -16539,6 +17143,9 @@ msgstr ""
msgid "NetworkPolicies|Allow all outbound traffic from %{selector} to %{ruleSelector} on %{ports}"
msgstr ""
+msgid "NetworkPolicies|Are you sure you want to delete this policy? This action cannot be undone."
+msgstr ""
+
msgid "NetworkPolicies|Choose whether to enforce this policy."
msgstr ""
@@ -16548,12 +17155,21 @@ msgstr ""
msgid "NetworkPolicies|Define this policy's location, conditions and actions."
msgstr ""
+msgid "NetworkPolicies|Delete policy"
+msgstr ""
+
+msgid "NetworkPolicies|Delete policy: %{policy}"
+msgstr ""
+
msgid "NetworkPolicies|Deny all traffic"
msgstr ""
msgid "NetworkPolicies|Description"
msgstr ""
+msgid "NetworkPolicies|Edit policy"
+msgstr ""
+
msgid "NetworkPolicies|Editor mode"
msgstr ""
@@ -16581,6 +17197,9 @@ msgstr ""
msgid "NetworkPolicies|Name"
msgstr ""
+msgid "NetworkPolicies|Namespace"
+msgstr ""
+
msgid "NetworkPolicies|Network Policy"
msgstr ""
@@ -16632,6 +17251,9 @@ msgstr ""
msgid "NetworkPolicies|Rules"
msgstr ""
+msgid "NetworkPolicies|Save changes"
+msgstr ""
+
msgid "NetworkPolicies|Something went wrong, failed to update policy"
msgstr ""
@@ -16644,6 +17266,9 @@ msgstr ""
msgid "NetworkPolicies|Traffic that does not match any rule will be blocked."
msgstr ""
+msgid "NetworkPolicies|Unable to parse policy"
+msgstr ""
+
msgid "NetworkPolicies|YAML editor"
msgstr ""
@@ -16759,6 +17384,9 @@ msgstr ""
msgid "New Snippet"
msgstr ""
+msgid "New Test Case"
+msgstr ""
+
msgid "New User"
msgstr ""
@@ -16858,6 +17486,9 @@ msgstr ""
msgid "New tag"
msgstr ""
+msgid "New test case"
+msgstr ""
+
msgid "New users set to external"
msgstr ""
@@ -16930,7 +17561,7 @@ msgstr ""
msgid "No changes"
msgstr ""
-msgid "No changes between %{ref_start}%{source_branch}%{ref_end} and %{ref_start}%{target_branch}%{ref_end}"
+msgid "No changes between %{sourceBranch} and %{targetBranch}"
msgstr ""
msgid "No child epics match applied filters"
@@ -16945,6 +17576,9 @@ msgstr ""
msgid "No containers available"
msgstr ""
+msgid "No content to show"
+msgstr ""
+
msgid "No contributions"
msgstr ""
@@ -17020,9 +17654,6 @@ msgstr ""
msgid "No license. All rights reserved"
msgstr ""
-msgid "No licenses found."
-msgstr ""
-
msgid "No matches found"
msgstr ""
@@ -17035,6 +17666,9 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No members found"
+msgstr ""
+
msgid "No merge requests found"
msgstr ""
@@ -17056,6 +17690,9 @@ msgstr ""
msgid "No parent group"
msgstr ""
+msgid "No plan"
+msgstr ""
+
msgid "No pods available"
msgstr ""
@@ -17152,6 +17789,12 @@ msgstr ""
msgid "Not Implemented"
msgstr ""
+msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+msgstr ""
+
+msgid "Not all browsers support WebAuthn. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even from an unsupported browser."
+msgstr ""
+
msgid "Not all data has been processed yet, the accuracy of the chart for the selected timeframe is limited."
msgstr ""
@@ -17248,6 +17891,9 @@ msgstr ""
msgid "Notification settings saved"
msgstr ""
+msgid "NotificationEvent|Change reviewer merge request"
+msgstr ""
+
msgid "NotificationEvent|Close issue"
msgstr ""
@@ -17410,10 +18056,7 @@ msgstr ""
msgid "On track"
msgstr ""
-msgid "OnDemandScans|Attached branch"
-msgstr ""
-
-msgid "OnDemandScans|Attached branch is where the scan job runs."
+msgid "OnDemandScans|Could not fetch scanner profiles. Please refresh the page, or try again later."
msgstr ""
msgid "OnDemandScans|Could not fetch site profiles. Please refresh the page, or try again later."
@@ -17422,6 +18065,9 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
+msgid "OnDemandScans|Create a new scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Create a new site profile"
msgstr ""
@@ -17434,6 +18080,9 @@ msgstr ""
msgid "OnDemandScans|New on-demand DAST scan"
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 ""
@@ -17443,16 +18092,10 @@ msgstr ""
msgid "OnDemandScans|On-demand scans run outside the DevOps cycle and find vulnerabilities in your projects. %{learnMoreLinkStart}Learn more%{learnMoreLinkEnd}"
msgstr ""
-msgid "OnDemandScans|Only a passive scan can be performed on demand."
-msgstr ""
-
-msgid "OnDemandScans|Passive"
-msgstr ""
-
msgid "OnDemandScans|Run scan"
msgstr ""
-msgid "OnDemandScans|Scan mode"
+msgid "OnDemandScans|Scanner profile"
msgstr ""
msgid "OnDemandScans|Scanner settings"
@@ -17464,9 +18107,15 @@ msgstr ""
msgid "OnDemandScans|Select one of the existing profiles"
msgstr ""
+msgid "OnDemandScans|Site profile"
+msgstr ""
+
msgid "OnDemandScans|Site profiles"
msgstr ""
+msgid "OnDemandScans|Use existing scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Use existing site profile"
msgstr ""
@@ -17567,9 +18216,6 @@ msgstr ""
msgid "Open Selection"
msgstr ""
-msgid "Open Web IDE"
-msgstr ""
-
msgid "Open comment type dropdown"
msgstr ""
@@ -17675,6 +18321,9 @@ msgstr ""
msgid "Origin"
msgstr ""
+msgid "Orphaned member"
+msgstr ""
+
msgid "Other Labels"
msgstr ""
@@ -17690,6 +18339,9 @@ msgstr ""
msgid "Other visibility settings have been disabled by the administrator."
msgstr ""
+msgid "Our documentation includes an example DevOps Score report."
+msgstr ""
+
msgid "Out-of-compliance with this project's policies and should be removed"
msgstr ""
@@ -17714,6 +18366,9 @@ msgstr ""
msgid "Overwrite diverged branches"
msgstr ""
+msgid "Owned by %{image_tag}"
+msgstr ""
+
msgid "Owned by anyone"
msgstr ""
@@ -17735,6 +18390,9 @@ msgstr ""
msgid "Package deleted successfully"
msgstr ""
+msgid "Package file size limits"
+msgstr ""
+
msgid "Package recipe already exists"
msgstr ""
@@ -17750,9 +18408,6 @@ msgstr ""
msgid "Package type must be PyPi"
msgstr ""
-msgid "Package was removed"
-msgstr ""
-
msgid "PackageRegistry|%{name} version %{version} was created %{datetime}"
msgstr ""
@@ -17894,12 +18549,18 @@ msgstr ""
msgid "PackageRegistry|NuGet Command"
msgstr ""
+msgid "PackageRegistry|Package Registry"
+msgstr ""
+
msgid "PackageRegistry|Pip Command"
msgstr ""
msgid "PackageRegistry|Pipeline %{link} triggered %{datetime} by %{author}"
msgstr ""
+msgid "PackageRegistry|Publish and share packages for a variety of common package managers. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "PackageRegistry|Published to the %{project} Package Registry %{datetime}"
msgstr ""
@@ -17999,6 +18660,9 @@ msgstr ""
msgid "Page not found"
msgstr ""
+msgid "Page settings"
+msgstr ""
+
msgid "Page was successfully deleted"
msgstr ""
@@ -18140,7 +18804,7 @@ msgstr ""
msgid "Paste issue link"
msgstr ""
-msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Don't use your private SSH key."
+msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Do not paste your private SSH key, as that can compromise your identity."
msgstr ""
msgid "Patch to apply"
@@ -18167,6 +18831,9 @@ msgstr ""
msgid "Pending"
msgstr ""
+msgid "Pending comments"
+msgstr ""
+
msgid "People without permission will never get a notification and won't be able to comment."
msgstr ""
@@ -18365,6 +19032,9 @@ msgstr ""
msgid "Pipelines|Build with confidence"
msgstr ""
+msgid "Pipelines|By revoking a trigger you will break any processes making use of it. Are you sure?"
+msgstr ""
+
msgid "Pipelines|CI Lint"
msgstr ""
@@ -18377,6 +19047,15 @@ msgstr ""
msgid "Pipelines|Continuous Integration can help catch bugs by running your tests automatically, while Continuous Deployment can help you deliver code to your product environment."
msgstr ""
+msgid "Pipelines|Copy trigger token"
+msgstr ""
+
+msgid "Pipelines|Description"
+msgstr ""
+
+msgid "Pipelines|Edit"
+msgstr ""
+
msgid "Pipelines|Get started with Pipelines"
msgstr ""
@@ -18392,15 +19071,27 @@ msgstr ""
msgid "Pipelines|It is recommended the code is reviewed thoroughly before running this pipeline with the parent project's CI resource."
msgstr ""
+msgid "Pipelines|Last Used"
+msgstr ""
+
msgid "Pipelines|Loading Pipelines"
msgstr ""
msgid "Pipelines|More Information"
msgstr ""
+msgid "Pipelines|No triggers have been created yet. Add one using the form above."
+msgstr ""
+
+msgid "Pipelines|Owner"
+msgstr ""
+
msgid "Pipelines|Project cache successfully reset."
msgstr ""
+msgid "Pipelines|Revoke"
+msgstr ""
+
msgid "Pipelines|Run Pipeline"
msgstr ""
@@ -18425,6 +19116,15 @@ msgstr ""
msgid "Pipelines|This project is not currently set up to run pipelines."
msgstr ""
+msgid "Pipelines|Token"
+msgstr ""
+
+msgid "Pipelines|Trigger user has insufficient permissions to project"
+msgstr ""
+
+msgid "Pipelines|invalid"
+msgstr ""
+
msgid "Pipelines|parent"
msgstr ""
@@ -18683,10 +19383,10 @@ msgstr ""
msgid "Please provide attributes to update"
msgstr ""
-msgid "Please refer to %{docs_url}"
+msgid "Please reach out if you have any questions and we'll be happy to assist."
msgstr ""
-msgid "Please retype the email address."
+msgid "Please refer to %{docs_url}"
msgstr ""
msgid "Please select"
@@ -18716,6 +19416,9 @@ msgstr ""
msgid "Please set a new password before proceeding."
msgstr ""
+msgid "Please share your feedback about %{featureName} %{linkStart}in this issue%{linkEnd} to help us improve the experience."
+msgstr ""
+
msgid "Please solve the reCAPTCHA"
msgstr ""
@@ -19019,6 +19722,9 @@ msgstr ""
msgid "Profiles| You are going to change the username %{currentUsernameBold} to %{newUsernameBold}. Profile and projects will be redirected to the %{newUsername} namespace but this redirect will expire once the %{currentUsername} namespace is registered by another user or group. Please update your Git repository remotes as soon as possible."
msgstr ""
+msgid "Profiles|%{provider} Active"
+msgstr ""
+
msgid "Profiles|@username"
msgstr ""
@@ -19070,7 +19776,7 @@ msgstr ""
msgid "Profiles|Commit email"
msgstr ""
-msgid "Profiles|Connect"
+msgid "Profiles|Connect %{provider}"
msgstr ""
msgid "Profiles|Connected Accounts"
@@ -19094,6 +19800,9 @@ msgstr ""
msgid "Profiles|Disconnect"
msgstr ""
+msgid "Profiles|Disconnect %{provider}"
+msgstr ""
+
msgid "Profiles|Do not show on profile"
msgstr ""
@@ -19118,7 +19827,7 @@ msgstr ""
msgid "Profiles|Full name"
msgstr ""
-msgid "Profiles|Give your individual key a title. This will be publically visible."
+msgid "Profiles|Give your individual key a title."
msgstr ""
msgid "Profiles|Include private contributions on my profile"
@@ -19208,7 +19917,7 @@ msgstr ""
msgid "Profiles|The maximum file size allowed is 200KB."
msgstr ""
-msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it?"
+msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it? It will be publicly visible."
msgstr ""
msgid "Profiles|This email will be displayed on your public profile"
@@ -19283,6 +19992,9 @@ msgstr ""
msgid "Profiles|You don't have access to delete this user."
msgstr ""
+msgid "Profiles|You must transfer ownership or delete groups you are an owner of before you can delete your account"
+msgstr ""
+
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
@@ -19871,6 +20583,9 @@ msgstr ""
msgid "ProjectTemplates|GitLab Cluster Management"
msgstr ""
+msgid "ProjectTemplates|Gitpod/Spring Petclinic"
+msgstr ""
+
msgid "ProjectTemplates|Go Micro"
msgstr ""
@@ -20480,6 +21195,9 @@ msgstr ""
msgid "Publish to status page"
msgstr ""
+msgid "Published"
+msgstr ""
+
msgid "Published on status page"
msgstr ""
@@ -20597,9 +21315,15 @@ msgstr ""
msgid "Quick range"
msgstr ""
+msgid "Quickly and easily edit multiple files in your project."
+msgstr ""
+
msgid "README"
msgstr ""
+msgid "Rails"
+msgstr ""
+
msgid "Rake Tasks Help"
msgstr ""
@@ -20721,10 +21445,13 @@ msgstr ""
msgid "Register Two-Factor Authenticator"
msgstr ""
-msgid "Register U2F device"
+msgid "Register Universal Two-Factor (U2F) Device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register WebAuthn Device"
+msgstr ""
+
+msgid "Register device"
msgstr ""
msgid "Register for GitLab"
@@ -20736,9 +21463,6 @@ msgstr ""
msgid "Register with two-factor app"
msgstr ""
-msgid "Registration"
-msgstr ""
-
msgid "Registration|Checkout"
msgstr ""
@@ -20857,9 +21581,6 @@ msgstr ""
msgid "Release|Something went wrong while saving the release details"
msgstr ""
-msgid "Remediated: needs review"
-msgstr ""
-
msgid "Remediations"
msgstr ""
@@ -20965,6 +21686,9 @@ msgstr ""
msgid "Remove priority"
msgstr ""
+msgid "Remove report"
+msgstr ""
+
msgid "Remove secondary node"
msgstr ""
@@ -20977,6 +21701,12 @@ msgstr ""
msgid "Remove time estimate"
msgstr ""
+msgid "Remove user & report"
+msgstr ""
+
+msgid "Remove user from group"
+msgstr ""
+
msgid "Removed"
msgstr ""
@@ -21058,9 +21788,6 @@ msgstr ""
msgid "Removes time estimate."
msgstr ""
-msgid "Removing license…"
-msgstr ""
-
msgid "Removing this group also removes all child projects, including archived projects, and their resources."
msgstr ""
@@ -21145,6 +21872,9 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
+msgid "Reported by %{reporter}"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -21233,6 +21963,27 @@ msgstr "brak zmienionych wyników testów"
msgid "Repositories"
msgstr ""
+msgid "Repositories Analytics"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download Historic Test Coverage Data"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download historic test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Historic Test Coverage Data is available in raw format (.csv) for further analysis."
+msgstr ""
+
+msgid "RepositoriesAnalytics|Test Code Coverage"
+msgstr ""
+
+msgid "RepositoriesAnalytics|There was an error fetching the projects."
+msgstr ""
+
msgid "Repository"
msgstr ""
@@ -21311,9 +22062,15 @@ msgstr ""
msgid "Request parameter %{param} is missing."
msgstr ""
+msgid "Request review from"
+msgstr ""
+
msgid "Request to link SAML account must be authorized"
msgstr ""
+msgid "Requested"
+msgstr ""
+
msgid "Requested %{time_ago}"
msgstr ""
@@ -21332,6 +22089,9 @@ msgstr "Profile Żądań"
msgid "Requests to these domain(s)/address(es) on the local network will be allowed when local requests from hooks and services are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 or 127.0.0.0/28 are supported. Domain wildcards are not supported currently. Use comma, semicolon, or newline to separate multiple entries. The allowlist can hold a maximum of 1000 entries. Domains should use IDNA encoding. Ex: example.com, 192.168.1.1, 127.0.0.0/28, xn--itlab-j1a.com."
msgstr ""
+msgid "Require admin approval for new sign-ups"
+msgstr ""
+
msgid "Require all users in this group to setup Two-factor authentication"
msgstr "Wymagaj od wszystkich użytkowników w tej grupie do ustawienia uwierzytelniania Dwuczynnikowego"
@@ -21463,9 +22223,6 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
-msgid "Resolved by %{resolvedByName}"
-msgstr ""
-
msgid "Resolves IP addresses once and uses them to submit requests"
msgstr ""
@@ -21587,6 +22344,16 @@ msgstr ""
msgid "ReviewApp|Enable Review App"
msgstr ""
+msgid "Reviewer"
+msgid_plural "%d Reviewers"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
+msgid "Reviewer(s)"
+msgstr ""
+
msgid "Reviewing"
msgstr "PrzeglÄ…d"
@@ -21626,6 +22393,9 @@ msgstr ""
msgid "Rook"
msgstr ""
+msgid "Ruby"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -21704,6 +22474,63 @@ msgstr "Liczba Robotników online: %{active_runners_count}"
msgid "Runners page."
msgstr "Strona Robotników."
+msgid "Runners|Active"
+msgstr ""
+
+msgid "Runners|Architecture"
+msgstr ""
+
+msgid "Runners|Can run untagged jobs"
+msgstr ""
+
+msgid "Runners|Description"
+msgstr ""
+
+msgid "Runners|Group"
+msgstr ""
+
+msgid "Runners|IP Address"
+msgstr ""
+
+msgid "Runners|Last contact"
+msgstr ""
+
+msgid "Runners|Locked to this project"
+msgstr ""
+
+msgid "Runners|Maximum job timeout"
+msgstr ""
+
+msgid "Runners|Name"
+msgstr ""
+
+msgid "Runners|Platform"
+msgstr ""
+
+msgid "Runners|Property Name"
+msgstr ""
+
+msgid "Runners|Protected"
+msgstr ""
+
+msgid "Runners|Revision"
+msgstr ""
+
+msgid "Runners|Shared"
+msgstr ""
+
+msgid "Runners|Specific"
+msgstr ""
+
+msgid "Runners|Tags"
+msgstr ""
+
+msgid "Runners|Value"
+msgstr ""
+
+msgid "Runners|Version"
+msgstr ""
+
msgid "Runners|You have used %{quotaUsed} out of %{quotaLimit} of your shared Runners pipeline minutes."
msgstr ""
@@ -21716,6 +22543,9 @@ msgstr ""
msgid "Runs a number of housekeeping tasks within the current repository, such as compressing file revisions and removing unreachable objects."
msgstr ""
+msgid "SAML"
+msgstr ""
+
msgid "SAML SSO"
msgstr ""
@@ -21767,6 +22597,9 @@ msgstr ""
msgid "Save"
msgstr ""
+msgid "Save %{name} size limits"
+msgstr ""
+
msgid "Save Changes"
msgstr ""
@@ -21797,9 +22630,6 @@ msgstr ""
msgid "Save space and find tags in the Container Registry more easily. Enable the cleanup policy to remove stale tags and keep only the ones you need."
msgstr ""
-msgid "Save template"
-msgstr ""
-
msgid "Save variables"
msgstr ""
@@ -21842,9 +22672,6 @@ msgstr ""
msgid "Scope"
msgstr ""
-msgid "Scope not supported with disabled 'users_search' feature!"
-msgstr ""
-
msgid "Scoped issue boards"
msgstr ""
@@ -21971,9 +22798,6 @@ msgstr ""
msgid "Search requirements"
msgstr ""
-msgid "Search results…"
-msgstr ""
-
msgid "Search users"
msgstr ""
@@ -22052,6 +22876,13 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "SearchResults|epic"
+msgid_plural "SearchResults|epics"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "SearchResults|issue"
msgid_plural "SearchResults|issues"
msgstr[0] ""
@@ -22110,10 +22941,10 @@ msgstr ""
msgid "Seat Link is disabled, and cannot be configured through this form."
msgstr ""
-msgid "Seats currently in use"
+msgid "Seats usage data as of %{last_enqueue_time}"
msgstr ""
-msgid "Seats in license"
+msgid "Seats usage data is updated every day at 12:00pm UTC"
msgstr ""
msgid "Secondary"
@@ -22167,6 +22998,9 @@ msgstr ""
msgid "SecurityConfiguration|Available for on-demand DAST"
msgstr ""
+msgid "SecurityConfiguration|By default, all analyzers are applied in order to cover all languages across your project, and only run if the language is detected in the Merge Request."
+msgstr ""
+
msgid "SecurityConfiguration|Configure"
msgstr ""
@@ -22197,16 +23031,19 @@ msgstr ""
msgid "SecurityConfiguration|Manage"
msgstr ""
+msgid "SecurityConfiguration|More information"
+msgstr ""
+
msgid "SecurityConfiguration|Not enabled"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|Security Control"
+msgid "SecurityConfiguration|SAST Configuration"
msgstr ""
-msgid "SecurityConfiguration|See documentation"
+msgid "SecurityConfiguration|Security Control"
msgstr ""
msgid "SecurityConfiguration|Status"
@@ -22218,6 +23055,9 @@ msgstr ""
msgid "SecurityConfiguration|Using custom settings. You won't receive automatic updates on this variable. %{anchorStart}Restore to default%{anchorEnd}"
msgstr ""
+msgid "SecurityConfiguration|View history"
+msgstr ""
+
msgid "SecurityConfiguration|You can quickly enable all security scanning tools by enabling %{linkStart}Auto DevOps%{linkEnd}."
msgstr ""
@@ -22296,9 +23136,6 @@ msgstr ""
msgid "SecurityReports|Learn more about setting up your dashboard"
msgstr ""
-msgid "SecurityReports|Load more vulnerabilities"
-msgstr ""
-
msgid "SecurityReports|Monitor vulnerabilities in your code"
msgstr ""
@@ -22578,7 +23415,7 @@ msgstr ""
msgid "Select status"
msgstr ""
-msgid "Select strategy activation method"
+msgid "Select strategy activation method."
msgstr ""
msgid "Select subscription"
@@ -22593,7 +23430,7 @@ msgstr ""
msgid "Select the custom project template source group."
msgstr ""
-msgid "Select timeframe"
+msgid "Select the environment scope for this feature flag."
msgstr ""
msgid "Select timezone"
@@ -22842,6 +23679,9 @@ msgstr ""
msgid "Set iteration"
msgstr ""
+msgid "Set limit to 0 to allow any file size."
+msgstr ""
+
msgid "Set max session time for web terminal."
msgstr ""
@@ -22920,10 +23760,13 @@ msgstr ""
msgid "Set up a %{type} Runner manually"
msgstr ""
+msgid "Set up a hardware device as a second factor to sign in."
+msgstr ""
+
msgid "Set up assertions/attributes/claims (email, first_name, last_name) and NameID according to %{docsLinkStart}the documentation %{icon}%{docsLinkEnd}"
msgstr ""
-msgid "Set up new U2F device"
+msgid "Set up new device"
msgstr ""
msgid "Set up new password"
@@ -22992,6 +23835,9 @@ msgstr ""
msgid "Sets weight to %{weight}."
msgstr ""
+msgid "Setting this to 0 means using the system default timeout value."
+msgstr ""
+
msgid "Settings"
msgstr ""
@@ -23007,6 +23853,15 @@ msgstr ""
msgid "Severity"
msgstr ""
+msgid "SeverityWidget|Severity"
+msgstr ""
+
+msgid "SeverityWidget|Severity: %{severity}"
+msgstr ""
+
+msgid "SeverityWidget|There was an error while updating severity."
+msgstr ""
+
msgid "Shards (%{shards})"
msgstr ""
@@ -23052,6 +23907,9 @@ msgstr ""
msgid "Show all requirements."
msgstr ""
+msgid "Show all test cases."
+msgstr ""
+
msgid "Show archived projects"
msgstr ""
@@ -23064,6 +23922,9 @@ msgstr ""
msgid "Show comments"
msgstr ""
+msgid "Show comments on this file"
+msgstr ""
+
msgid "Show comments only"
msgstr ""
@@ -23109,6 +23970,12 @@ msgstr ""
msgid "Show parent subgroups"
msgstr ""
+msgid "Show the Closed list"
+msgstr ""
+
+msgid "Show the Open list"
+msgstr ""
+
msgid "Show whitespace changes"
msgstr ""
@@ -23156,9 +24023,6 @@ msgstr ""
msgid "Sidebar|Assign health status"
msgstr ""
-msgid "Sidebar|Change weight"
-msgstr ""
-
msgid "Sidebar|Health status"
msgstr ""
@@ -23342,6 +24206,9 @@ msgstr ""
msgid "Snippets|Add another file %{num}/%{total}"
msgstr ""
+msgid "Snippets|Authored %{time_ago} by %{author}"
+msgstr ""
+
msgid "Snippets|Delete file"
msgstr ""
@@ -23369,6 +24236,9 @@ msgstr ""
msgid "Solution"
msgstr ""
+msgid "Some changes are not shown"
+msgstr ""
+
msgid "Some child epics may be hidden due to applied filters"
msgstr ""
@@ -23735,6 +24605,12 @@ msgstr ""
msgid "Source (branch or tag)"
msgstr ""
+msgid "Source Branch"
+msgstr ""
+
+msgid "Source branch: %{source_branch_open}%{source_branch}%{source_branch_close}"
+msgstr ""
+
msgid "Source code"
msgstr ""
@@ -23900,9 +24776,6 @@ msgstr "Rozpocznij recenzjÄ™"
msgid "Start and due date"
msgstr "Data początkowa i końcowa"
-msgid "Start by choosing a group to see how your team is spending time. You can then drill down to the project level."
-msgstr ""
-
msgid "Start by choosing a group to start exploring the merge requests in that group. You can then proceed to filter by projects, labels, milestones and authors."
msgstr ""
@@ -23984,18 +24857,27 @@ msgstr ""
msgid "StaticSiteEditor|3. Assign a person to review and accept the merge request."
msgstr ""
+msgid "StaticSiteEditor|A link to view the merge request will appear once ready."
+msgstr ""
+
msgid "StaticSiteEditor|An error occurred while submitting your changes."
msgstr ""
msgid "StaticSiteEditor|Branch could not be created."
msgstr ""
+msgid "StaticSiteEditor|Copy update"
+msgstr ""
+
msgid "StaticSiteEditor|Could not commit the content changes."
msgstr ""
msgid "StaticSiteEditor|Could not create merge request."
msgstr ""
+msgid "StaticSiteEditor|Creating your merge request"
+msgstr ""
+
msgid "StaticSiteEditor|Incompatible file content"
msgstr ""
@@ -24017,6 +24899,9 @@ msgstr ""
msgid "StaticSiteEditor|View documentation"
msgstr ""
+msgid "StaticSiteEditor|You can set an assignee to get your changes reviewed and deployed once your merge request is created."
+msgstr ""
+
msgid "StaticSiteEditor|Your merge request has been created"
msgstr ""
@@ -24146,15 +25031,15 @@ msgstr ""
msgid "Submit %{humanized_resource_name}"
msgstr ""
-msgid "Submit Changes"
-msgstr ""
-
msgid "Submit a review"
msgstr ""
msgid "Submit as spam"
msgstr ""
+msgid "Submit changes"
+msgstr ""
+
msgid "Submit feedback"
msgstr ""
@@ -24308,6 +25193,9 @@ msgstr ""
msgid "Successfully deleted U2F device."
msgstr ""
+msgid "Successfully deleted WebAuthn device."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -24626,9 +25514,6 @@ msgstr ""
msgid "Template to append to all Service Desk issues"
msgstr ""
-msgid "Template was successfully saved."
-msgstr ""
-
msgid "Templates"
msgstr ""
@@ -24713,10 +25598,28 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "Test failed."
+msgid "Test settings"
+msgstr ""
+
+msgid "TestCases|New Test Case"
+msgstr ""
+
+msgid "TestCases|New test case"
+msgstr ""
+
+msgid "TestCases|Search test cases"
+msgstr ""
+
+msgid "TestCases|Something went wrong while creating a test case."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching count of test cases."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching test cases list."
msgstr ""
-msgid "Test settings and save changes"
+msgid "TestCases|Submit test case"
msgstr ""
msgid "TestHooks|Ensure one of your projects has merge requests."
@@ -24782,6 +25685,9 @@ msgstr ""
msgid "Thank you for signing up for your free trial! You will get additional instructions in your inbox shortly."
msgstr ""
+msgid "Thank you for your business."
+msgstr ""
+
msgid "Thank you for your feedback!"
msgstr ""
@@ -24843,9 +25749,6 @@ msgstr ""
msgid "The URL to use for connecting to Elasticsearch. Use a comma-separated list to support clustering (e.g., \"http://localhost:9200, http://localhost:9201\")."
msgstr ""
-msgid "The Web IDE offers advanced syntax highlighting capabilities and more."
-msgstr ""
-
msgid "The X509 Certificate to use when mutual TLS is required to communicate with the external authorization service. If left blank, the server certificate is still validated when accessing over HTTPS."
msgstr "Certyfikat X509 służy do użycia w przypadku, gdy do komunikacji z zewnętrzną usługą autoryzacji jest wymagany wspólny TLS. Jeśli pozostanie puste, certyfikat serwera będzie nadal sprawdzany podczas uzyskiwania dostępu za pośrednictwem protokołu HTTPS."
@@ -24958,6 +25861,9 @@ msgstr ""
msgid "The form contains the following error:"
msgstr ""
+msgid "The form contains the following warning:"
+msgstr ""
+
msgid "The global settings require you to enable Two-Factor Authentication for your account."
msgstr ""
@@ -25072,9 +25978,6 @@ msgstr ""
msgid "The private key to use when a client certificate is provided. This value is encrypted at rest."
msgstr "Klucz prywatny służy do użycia w przypadku, gdy dostarczony jest certyfikat klienta. Ta wartość jest zaszyfrowana w trybie spoczynku."
-msgid "The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The project can be accessed by any logged in user."
msgstr ""
@@ -25111,7 +26014,7 @@ msgstr ""
msgid "The remote repository is being updated..."
msgstr ""
-msgid "The repository can be commited to, and issues, comments and other entities can be created."
+msgid "The repository can be committed to, and issues, comments and other entities can be created."
msgstr ""
msgid "The repository for this project does not exist."
@@ -25165,9 +26068,6 @@ msgstr ""
msgid "The time taken by each data entry gathered by that stage."
msgstr ""
-msgid "The total stage shows the time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The update action will time out after %{number_of_minutes} minutes. For big repositories, use a clone/push combination."
msgstr "Akcja aktualizacji zakończy się po upływie %{number_of_minutes} minut. W przypadku dużych repozytoriów użyj kombinacji klonuj/pchnij."
@@ -25231,6 +26131,9 @@ msgstr "Nie ma jeszcze projektów zarchiwizowanych"
msgid "There are no archived requirements"
msgstr ""
+msgid "There are no archived test cases"
+msgstr ""
+
msgid "There are no changes"
msgstr ""
@@ -25270,6 +26173,9 @@ msgstr ""
msgid "There are no open requirements"
msgstr ""
+msgid "There are no open test cases"
+msgstr ""
+
msgid "There are no packages yet"
msgstr ""
@@ -25282,6 +26188,9 @@ msgstr ""
msgid "There is a limit of %{ci_project_subscriptions_limit} subscriptions from or to a project."
msgstr ""
+msgid "There is already a To-Do for this design."
+msgstr ""
+
msgid "There is already a repository with that name on disk"
msgstr ""
@@ -25300,6 +26209,9 @@ msgstr ""
msgid "There was a problem communicating with your device."
msgstr ""
+msgid "There was a problem fetching branches."
+msgstr ""
+
msgid "There was a problem fetching groups."
msgstr ""
@@ -25528,9 +26440,15 @@ msgstr ""
msgid "This action can lead to data loss. To prevent accidental actions we ask you to confirm your intention."
msgstr ""
+msgid "This action cannot be undone, and will permanently delete the %{key} SSH key"
+msgstr ""
+
msgid "This action cannot be undone. You will lose the project's repository and all content: issues, merge requests, etc."
msgstr ""
+msgid "This action has been performed too many times. Try again later."
+msgstr ""
+
msgid "This action will %{strongOpen}permanently delete%{strongClose} %{codeOpen}%{project}%{codeClose} %{strongOpen}immediately%{strongClose}, including its repositories and all content: issues, merge requests, etc."
msgstr ""
@@ -25558,9 +26476,6 @@ msgstr ""
msgid "This board's scope is reduced"
msgstr ""
-msgid "This branch has changed since you started editing. Would you like to create a new branch?"
-msgstr ""
-
msgid "This chart could not be displayed"
msgstr ""
@@ -25687,15 +26602,9 @@ msgstr ""
msgid "This is a security log of important events involving your account."
msgstr ""
-msgid "This is the author's first Merge Request to this project."
-msgstr ""
-
msgid "This is the highest peak of users on your installation since the license started."
msgstr ""
-msgid "This is the maximum number of users that have existed at the same time since the license started. This is the minimum number of seats you will need to buy when you renew your license."
-msgstr ""
-
msgid "This is the number of currently active users on your installation, and this is the minimum number you need to purchase when you renew your license."
msgstr ""
@@ -25927,6 +26836,15 @@ msgstr ""
msgid "This user has no identities"
msgstr ""
+msgid "This user has previously committed to the %{name} project."
+msgstr ""
+
+msgid "This user has the %{access} role in the %{name} project."
+msgstr ""
+
+msgid "This user is the author of this %{noteable}."
+msgstr ""
+
msgid "This user will be the author of all events in the activity feed that are the result of an update, like new branches being created or new commits being pushed to existing branches."
msgstr ""
@@ -25957,6 +26875,9 @@ msgstr ""
msgid "Threat Monitoring"
msgstr ""
+msgid "ThreatMonitoring|All Environments"
+msgstr ""
+
msgid "ThreatMonitoring|Anomalous Requests"
msgstr ""
@@ -25984,9 +26905,6 @@ msgstr ""
msgid "ThreatMonitoring|Operations Per Second"
msgstr ""
-msgid "ThreatMonitoring|Overview"
-msgstr ""
-
msgid "ThreatMonitoring|Packet Activity"
msgstr ""
@@ -26005,6 +26923,9 @@ msgstr ""
msgid "ThreatMonitoring|Something went wrong, unable to fetch statistics"
msgstr ""
+msgid "ThreatMonitoring|Statistics"
+msgstr ""
+
msgid "ThreatMonitoring|The firewall is not installed or has been disabled. To view this data, ensure the web application firewall is installed and enabled for your cluster."
msgstr ""
@@ -26400,6 +27321,9 @@ msgstr ""
msgid "To update Snippets with multiple files, you must use the `files` parameter"
msgstr ""
+msgid "To use Gitpod you must first enable the feature in the integrations section of your %{user_prefs}."
+msgstr ""
+
msgid "To view all %{scannedResourcesCount} scanned URLs, please download the CSV file"
msgstr ""
@@ -26433,9 +27357,6 @@ msgstr ""
msgid "Toggle Sidebar"
msgstr ""
-msgid "Toggle all threads"
-msgstr ""
-
msgid "Toggle backtrace"
msgstr ""
@@ -26460,9 +27381,6 @@ msgstr ""
msgid "Toggle navigation"
msgstr ""
-msgid "Toggle project"
-msgstr ""
-
msgid "Toggle sidebar"
msgstr ""
@@ -26502,6 +27420,9 @@ msgstr ""
msgid "Too many projects enabled. You will need to manage them via the console or the API."
msgstr ""
+msgid "Too much data"
+msgstr ""
+
msgid "Topics (optional)"
msgstr ""
@@ -26520,6 +27441,9 @@ msgstr ""
msgid "Total cores (CPUs)"
msgstr ""
+msgid "Total days to completion"
+msgstr ""
+
msgid "Total issues"
msgstr ""
@@ -26616,6 +27540,9 @@ msgstr ""
msgid "Trending"
msgstr ""
+msgid "Trials|Create a new group to start your GitLab Gold trial."
+msgstr ""
+
msgid "Trials|Go back to GitLab"
msgstr ""
@@ -26625,6 +27552,15 @@ msgstr ""
msgid "Trials|You can always resume this process by selecting your avatar and choosing 'Start a Gold trial'"
msgstr ""
+msgid "Trials|You can apply your trial to a new group or an existing group."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group or your personal account."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group, an existing group, or your personal account."
+msgstr ""
+
msgid "Trials|You won't get a free trial right now but you can always resume this process by clicking on your avatar and choosing 'Start a free trial'"
msgstr ""
@@ -26694,6 +27630,9 @@ msgstr ""
msgid "Try using a different search term to find the file you are looking for."
msgstr ""
+msgid "Trying to communicate with your device. Plug it in (if needed) and press the button on the device now."
+msgstr ""
+
msgid "Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now."
msgstr ""
@@ -26781,6 +27720,12 @@ msgstr ""
msgid "URL or request ID"
msgstr ""
+msgid "USER %{user} WILL BE REMOVED! Are you sure?"
+msgstr ""
+
+msgid "USER WILL BE BLOCKED! Are you sure?"
+msgstr ""
+
msgid "UTC"
msgstr ""
@@ -26838,9 +27783,6 @@ msgstr ""
msgid "Unable to load the merge request widget. Try reloading the page."
msgstr ""
-msgid "Unable to resolve"
-msgstr ""
-
msgid "Unable to save iteration. Please try again"
msgstr ""
@@ -26889,6 +27831,9 @@ msgstr ""
msgid "Undo ignore"
msgstr ""
+msgid "Unexpected error"
+msgstr ""
+
msgid "Unfortunately, your email message to GitLab could not be processed."
msgstr ""
@@ -26922,6 +27867,9 @@ msgstr ""
msgid "Unknown response text"
msgstr ""
+msgid "Unless otherwise agreed to in writing with GitLab, by clicking \"Upload License\" you agree that your use of GitLab Software is subject to the %{eula_link_start}Terms of Service%{eula_link_end}."
+msgstr ""
+
msgid "Unlimited"
msgstr ""
@@ -27288,9 +28236,6 @@ msgstr ""
msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
msgstr ""
-msgid "Use a hardware device to add the second factor of authentication."
-msgstr ""
-
msgid "Use an one time password authenticator on your mobile device or computer to enable two-factor authentication (2FA)."
msgstr ""
@@ -27564,13 +28509,13 @@ msgstr ""
msgid "Users"
msgstr ""
-msgid "Users in License:"
+msgid "Users in License"
msgstr ""
-msgid "Users or groups set as approvers in the project's or merge request's settings."
+msgid "Users in License:"
msgstr ""
-msgid "Users outside of license"
+msgid "Users or groups set as approvers in the project's or merge request's settings."
msgstr ""
msgid "Users over License:"
@@ -27588,9 +28533,6 @@ msgstr ""
msgid "Users with a Guest role or those who don't belong to a Project or Group will not use a seat from your license."
msgstr ""
-msgid "Users with a Guest role or those who don't belong to any projects or groups don't count towards seats in use."
-msgstr ""
-
msgid "UsersSelect|%{name} + %{length} more"
msgstr ""
@@ -27630,9 +28572,6 @@ msgstr ""
msgid "Validations failed."
msgstr ""
-msgid "Validity"
-msgstr ""
-
msgid "Value"
msgstr ""
@@ -27651,6 +28590,9 @@ msgstr ""
msgid "Value Stream Name"
msgstr ""
+msgid "ValueStreamAnalyticsStage|We don't have enough data to show this stage."
+msgstr ""
+
msgid "ValueStreamAnalytics|%{days}d"
msgstr ""
@@ -27911,6 +28853,9 @@ msgstr ""
msgid "VisualReviewApp|Steps 1 and 2 (and sometimes 3) are performed once by the developer before requesting feedback. Steps 3 (if necessary), 4 is performed by the reviewer each time they perform a review."
msgstr ""
+msgid "Visualization"
+msgstr ""
+
msgid "Vulnerabilities"
msgstr ""
@@ -27938,34 +28883,31 @@ msgstr ""
msgid "VulnerabilityChart|Severity"
msgstr ""
-msgid "VulnerabilityManagement|A true-positive and will fix"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Change status"
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|Confirm"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Confirmed %{timeago} by %{user}"
-msgstr ""
-
-msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Detected %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|A true-positive and will fix"
msgstr ""
-msgid "VulnerabilityManagement|Dismiss"
+msgid "VulnerabilityManagement|Change status"
msgstr ""
-msgid "VulnerabilityManagement|Dismissed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
msgstr ""
-msgid "VulnerabilityManagement|Resolved"
+msgid "VulnerabilityManagement|Detected"
msgstr ""
-msgid "VulnerabilityManagement|Resolved %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Needs triage"
msgstr ""
msgid "VulnerabilityManagement|Something went wrong while trying to delete the comment. Please try again later."
@@ -28016,6 +28958,9 @@ msgstr ""
msgid "Vulnerability|%{scannerName} (version %{scannerVersion})"
msgstr ""
+msgid "Vulnerability|Activity"
+msgstr ""
+
msgid "Vulnerability|Class"
msgstr ""
@@ -28028,6 +28973,9 @@ msgstr ""
msgid "Vulnerability|Description"
msgstr ""
+msgid "Vulnerability|Detected"
+msgstr ""
+
msgid "Vulnerability|Evidence"
msgstr ""
@@ -28091,6 +29039,9 @@ msgstr ""
msgid "Warning: Displaying this diagram might cause performance issues on this page."
msgstr ""
+msgid "We are currently unable to fetch data for the pipeline header."
+msgstr ""
+
msgid "We are currently unable to fetch data for this graph."
msgstr ""
@@ -28130,6 +29081,12 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
+msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
+msgstr ""
+
+msgid "We would like to inform you that your subscription GitLab Enterprise Edition %{plan_name} is nearing its user limit. You have %{active_user_count} active users, which is almost at the user limit of %{maximum_user_count}."
+msgstr ""
+
msgid "We've found no vulnerabilities"
msgstr ""
@@ -28145,6 +29102,12 @@ msgstr ""
msgid "Web terminal"
msgstr ""
+msgid "WebAuthn Devices (%{length})"
+msgstr ""
+
+msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
+msgstr ""
+
msgid "WebIDE|Merge request"
msgstr ""
@@ -28283,15 +29246,9 @@ msgstr ""
msgid "Welcome to the guided GitLab tour"
msgstr ""
-msgid "Welcome to your Issue Board!"
-msgstr ""
-
msgid "Welcome to your issue board!"
msgstr ""
-msgid "We’ve been making changes to %{featureName} and we’d love your feedback %{linkStart}in this issue%{linkEnd} to help us improve the experience."
-msgstr ""
-
msgid "What are you searching for?"
msgstr ""
@@ -28310,6 +29267,9 @@ msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
msgstr ""
+msgid "When enabled, any user visiting %{host} and creating an account will have to be explicitly approved by the admin before they can login. This setting is effective only if sign-ups are enabled."
+msgstr ""
+
msgid "When enabled, any user visiting %{host} will be able to create an account."
msgstr ""
@@ -28536,6 +29496,9 @@ msgstr ""
msgid "With requirements, you can set criteria to check your products against."
msgstr ""
+msgid "With test cases, you can define conditions for your project to meet in determining quality"
+msgstr ""
+
msgid "Withdraw Access Request"
msgstr ""
@@ -28551,6 +29514,9 @@ msgstr ""
msgid "Workflow Help"
msgstr ""
+msgid "Would you like to create a new branch?"
+msgstr ""
+
msgid "Write"
msgstr ""
@@ -28572,6 +29538,9 @@ msgstr ""
msgid "Wrong extern UID provided. Make sure Auth0 is configured correctly."
msgstr ""
+msgid "YYYY-MM-DD"
+msgstr ""
+
msgid "Yes"
msgstr ""
@@ -28629,7 +29598,7 @@ msgstr ""
msgid "You are going to remove the fork relationship from %{project_full_name}. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "You are going to transfer %{project_full_name} to another owner. Are you ABSOLUTELY sure?"
+msgid "You are going to transfer %{project_full_name} to another namespace. Are you ABSOLUTELY sure?"
msgstr ""
msgid "You are going to turn off the confidentiality. This means %{strongStart}everyone%{strongEnd} will be able to see and leave a comment on this %{issuableType}."
@@ -28689,9 +29658,6 @@ msgstr ""
msgid "You can always edit this later"
msgstr ""
-msgid "You can apply your Trial to your Personal account or create a New Group."
-msgstr ""
-
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings"
msgstr ""
@@ -28713,12 +29679,18 @@ msgstr ""
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
+msgid "You can find more information about GitLab subscriptions in %{subscriptions_doc_link}."
+msgstr ""
+
msgid "You can generate an access token scoped to this project for each application to use the GitLab API."
msgstr ""
msgid "You can get started by cloning the repository or start adding files to it with one of the following options."
msgstr ""
+msgid "You can group test cases using labels. To learn about the future direction of this feature, visit %{linkStart}Quality Management direction page%{linkEnd}."
+msgstr ""
+
msgid "You can invite a new member to %{project_name} or invite another group."
msgstr ""
@@ -28734,6 +29706,9 @@ msgstr ""
msgid "You can notify the app / group or a project by sending them an email notification"
msgstr ""
+msgid "You can now close this window."
+msgstr ""
+
msgid "You can now export your security dashboard to a CSV report."
msgstr ""
@@ -28782,9 +29757,6 @@ msgstr ""
msgid "You can test your .gitlab-ci.yml in %{linkStart}CI Lint%{linkEnd}."
msgstr ""
-msgid "You can try again using %{begin_link}basic search%{end_link}"
-msgstr ""
-
msgid "You cannot access the raw file. Please wait a minute."
msgstr ""
@@ -28836,6 +29808,9 @@ msgstr ""
msgid "You don't have any U2F devices registered yet."
msgstr ""
+msgid "You don't have any WebAuthn devices registered yet."
+msgstr ""
+
msgid "You don't have any active chat names."
msgstr ""
@@ -28923,6 +29898,9 @@ msgstr ""
msgid "You must accept our Terms of Service and privacy policy in order to register an account"
msgstr ""
+msgid "You must be logged in to search across all of GitLab"
+msgstr ""
+
msgid "You must disassociate %{domain} from all clusters it is attached to before deletion."
msgstr ""
@@ -28962,7 +29940,7 @@ msgstr ""
msgid "You need to be logged in."
msgstr ""
-msgid "You need to register a two-factor authentication app before you can set up a U2F device."
+msgid "You need to register a two-factor authentication app before you can set up a device."
msgstr ""
msgid "You need to set terms to be enforced"
@@ -28980,6 +29958,9 @@ msgstr ""
msgid "You reached %{usage_in_percent} of %{namespace_name}'s storage capacity (%{used_storage} of %{storage_limit})"
msgstr ""
+msgid "You successfully declined the invitation"
+msgstr ""
+
msgid "You tried to fork %{link_to_the_project} but it failed for the following reason:"
msgstr ""
@@ -29145,10 +30126,13 @@ msgstr ""
msgid "Your U2F device did not send a valid JSON response."
msgstr ""
-msgid "Your U2F device needs to be set up. Plug it in (if not already) and click the button on the left."
+msgid "Your U2F device was registered!"
msgstr ""
-msgid "Your U2F device was registered!"
+msgid "Your WebAuthn device did not send a valid JSON response."
+msgstr ""
+
+msgid "Your WebAuthn device was registered!"
msgstr ""
msgid "Your access request to the %{source_type} has been withdrawn."
@@ -29172,6 +30156,9 @@ msgstr ""
msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
msgstr ""
+msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
+msgstr ""
+
msgid "Your changes can be committed to %{branch_name} because a merge request is open."
msgstr ""
@@ -29208,6 +30195,12 @@ msgstr ""
msgid "Your deployment services will be broken, you will need to manually fix the services after renaming."
msgstr ""
+msgid "Your device is not compatible with GitLab. Please try another device"
+msgstr ""
+
+msgid "Your device needs to be set up. Plug it in (if needed) and click the button on the left."
+msgstr ""
+
msgid "Your device was successfully set up! Give it a name and register it with the GitLab server."
msgstr ""
@@ -29323,9 +30316,6 @@ msgstr[3] ""
msgid "access:"
msgstr ""
-msgid "activated"
-msgstr ""
-
msgid "added %{created_at_timeago}"
msgstr ""
@@ -29398,9 +30388,21 @@ msgstr ""
msgid "by %{user}"
msgstr ""
+msgid "cannot be a date in the past"
+msgstr ""
+
msgid "cannot be changed if a personal project has container registry tags."
msgstr ""
+msgid "cannot be changed if shared runners are enabled"
+msgstr ""
+
+msgid "cannot be enabled because parent group does not allow it"
+msgstr ""
+
+msgid "cannot be enabled because parent group has shared Runners disabled"
+msgstr ""
+
msgid "cannot be enabled unless all domains have TLS certificates"
msgstr ""
@@ -29446,7 +30448,7 @@ msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about SAST %{linkEndTag}"
msgstr ""
-msgid "ciReport|%{linkStartTag}Learn more about Secret Scanning %{linkEndTag}"
+msgid "ciReport|%{linkStartTag}Learn more about Secret Detection %{linkEndTag}"
msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about codequality reports %{linkEndTag}"
@@ -29767,9 +30769,6 @@ msgstr ""
msgid "error"
msgstr ""
-msgid "error code:"
-msgstr ""
-
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr ""
@@ -29791,6 +30790,9 @@ msgstr ""
msgid "failed to dismiss associated finding(id=%{finding_id}): %{message}"
msgstr ""
+msgid "failed to revert associated finding(id=%{finding_id}) to detected"
+msgstr ""
+
msgid "file"
msgid_plural "files"
msgstr[0] ""
@@ -30341,6 +31343,9 @@ msgstr ""
msgid "must be a root namespace"
msgstr ""
+msgid "must be a valid IPv4 or IPv6 address"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -30377,6 +31382,9 @@ msgstr ""
msgid "no expiration"
msgstr ""
+msgid "no name set"
+msgstr ""
+
msgid "no one can merge"
msgstr ""
@@ -30565,9 +31573,6 @@ msgstr ""
msgid "security Reports|There was an error creating the merge request"
msgstr ""
-msgid "settings saved, but not activated"
-msgstr ""
-
msgid "severity|Critical"
msgstr ""
@@ -30694,9 +31699,6 @@ msgstr ""
msgid "toggle collapse"
msgstr ""
-msgid "toggle dropdown"
-msgstr ""
-
msgid "triggered"
msgstr ""
@@ -30724,6 +31726,9 @@ msgstr ""
msgid "user avatar"
msgstr ""
+msgid "user preferences"
+msgstr ""
+
msgid "username"
msgstr ""
diff --git a/locale/pt_BR/gitlab.po b/locale/pt_BR/gitlab.po
index fded4daa217..d877f3e8605 100644
--- a/locale/pt_BR/gitlab.po
+++ b/locale/pt_BR/gitlab.po
@@ -14,7 +14,10 @@ msgstr ""
"X-Crowdin-Language: pt-BR\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 6\n"
-"PO-Revision-Date: 2020-09-04 23:02\n"
+"PO-Revision-Date: 2020-10-02 18:41\n"
+
+msgid " %{project_name}#%{issue_iid} &middot; opened %{issue_created} by %{author}"
+msgstr ""
msgid " %{start} to %{end}"
msgstr ""
@@ -74,6 +77,16 @@ msgstr ""
msgid "\"el\" parameter is required for createInstance()"
msgstr ""
+msgid "%d Approval"
+msgid_plural "%d Approvals"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d Package"
+msgid_plural "%d Packages"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d Scanned URL"
msgid_plural "%d Scanned URLs"
msgstr[0] ""
@@ -137,6 +150,11 @@ msgstr[1] "%d commits,"
msgid "%d commits"
msgstr "%d commits"
+msgid "%d completed issue"
+msgid_plural "%d completed issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d contribution"
msgid_plural "%d contributions"
msgstr[0] "%d contribuição"
@@ -147,6 +165,11 @@ msgid_plural "%d days"
msgstr[0] ""
msgstr[1] ""
+msgid "%d day until tags are automatically removed"
+msgid_plural "%d days until tags are automatically removed"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d error"
msgid_plural "%d errors"
msgstr[0] ""
@@ -237,6 +260,16 @@ msgid_plural "%d more comments"
msgstr[0] "mais %d comentário"
msgstr[1] "mais %d comentários"
+msgid "%d open issue"
+msgid_plural "%d open issues"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d pending comment"
+msgid_plural "%d pending comments"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d personal project will be removed and cannot be restored."
msgid_plural "%d personal projects will be removed and cannot be restored."
msgstr[0] ""
@@ -252,6 +285,11 @@ msgid_plural "%d projects"
msgstr[0] ""
msgstr[1] ""
+msgid "%d project selected"
+msgid_plural "%d projects selected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d request with warnings"
msgid_plural "%d requests with warnings"
msgstr[0] "%d requisição com avisos"
@@ -272,6 +310,11 @@ msgid_plural "%d tags"
msgstr[0] ""
msgstr[1] ""
+msgid "%d tag per image name"
+msgid_plural "%d tags per image name"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d unassigned issue"
msgid_plural "%d unassigned issues"
msgstr[0] ""
@@ -292,6 +335,11 @@ msgid_plural "%d vulnerabilities dismissed"
msgstr[0] ""
msgstr[1] ""
+msgid "%d warning found:"
+msgid_plural "%d warnings found:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%s additional commit has been omitted to prevent performance issues."
msgid_plural "%s additional commits have been omitted to prevent performance issues."
msgstr[0] "%s commit adicional foi omitido para prevenir problemas de performance."
@@ -330,6 +378,9 @@ msgstr ""
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr "%{commit_author_link} fez commit %{commit_timeago}"
+msgid "%{completedCount} completed weight"
+msgstr ""
+
msgid "%{completedWeight} of %{totalWeight} weight completed"
msgstr ""
@@ -378,14 +429,12 @@ msgid_plural "%{count} participants"
msgstr[0] "%{count} participante"
msgstr[1] "%{count} participantes"
-msgid "%{count} pending comment"
-msgid_plural "%{count} pending comments"
-msgstr[0] "%{count} comentário pendente"
-msgstr[1] "%{count} comentários pendentes"
-
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
+msgid "%{count} total weight"
+msgstr ""
+
msgid "%{dashboard_path} could not be found."
msgstr ""
@@ -440,6 +489,9 @@ msgstr ""
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} usa contas gerenciadas por grupo. Você precisa criar uma nova conta do GitLab que será gerenciada por %{group_name}."
+msgid "%{group_name}&%{epic_iid} &middot; opened %{epic_created} by %{author}"
+msgstr ""
+
msgid "%{host} sign-in from new location"
msgstr ""
@@ -452,7 +504,7 @@ msgstr ""
msgid "%{issuableType} will be removed! Are you sure?"
msgstr "%{issuableType} será removido! Você tem certeza?"
-msgid "%{issuesSize} issues with a limit of %{maxIssueCount}"
+msgid "%{issuesCount} issues with a limit of %{maxIssueCount}"
msgstr ""
msgid "%{issuesSize} with a limit of %{maxIssueCount}"
@@ -485,7 +537,7 @@ msgstr ""
msgid "%{labelStart}Namespace:%{labelEnd} %{namespace}"
msgstr ""
-msgid "%{labelStart}Report Type:%{labelEnd} %{reportType}"
+msgid "%{labelStart}Scan Type:%{labelEnd} %{reportType}"
msgstr ""
msgid "%{labelStart}Scanner:%{labelEnd} %{scanner}"
@@ -682,9 +734,6 @@ msgid_plural "%{securityScanner} results are not available because a pipeline ha
msgstr[0] ""
msgstr[1] ""
-msgid "%{service_title} %{message}."
-msgstr ""
-
msgid "%{size} GiB"
msgstr "%{size} GiB"
@@ -773,6 +822,12 @@ msgstr "%{text} está disponível"
msgid "%{timebox_name} should belong either to a project or a group."
msgstr ""
+msgid "%{timebox_type} does not support burnup charts"
+msgstr ""
+
+msgid "%{timebox_type} must have a start and due date"
+msgstr ""
+
msgid "%{title} %{operator} %{threshold}"
msgstr "%{title} %{operator} %{threshold}"
@@ -797,8 +852,8 @@ msgstr ""
msgid "%{total} open issue weight"
msgstr ""
-msgid "%{total} open issues"
-msgstr "%{total} issues abertas"
+msgid "%{total} warnings found: showing first %{warningsDisplayed}"
+msgstr ""
msgid "%{usage_ping_link_start}Learn more%{usage_ping_link_end} about what information is shared with GitLab Inc."
msgstr "%{usage_ping_link_start}Saiba mais%{usage_ping_link_end} sobre quais informações são compartilhadas com o GitLab Inc."
@@ -830,9 +885,6 @@ msgstr ""
msgid "&lt; 1 hour"
msgstr ""
-msgid "&lt;no name set&gt;"
-msgstr ""
-
msgid "&lt;no scopes selected&gt;"
msgstr ""
@@ -863,6 +915,9 @@ msgstr "'%{level}' não é um nível de visibilidade válido"
msgid "'%{name}' Value Stream created"
msgstr ""
+msgid "'%{name}' Value Stream deleted"
+msgstr ""
+
msgid "'%{name}' stage already exists"
msgstr ""
@@ -922,6 +977,9 @@ msgstr "%{moreCount} mais"
msgid "+ %{numberOfHiddenAssignees} more"
msgstr ""
+msgid "+ %{numberOfHiddenReviewers} more"
+msgstr ""
+
msgid "+%d more"
msgid_plural "+%d more"
msgstr[0] ""
@@ -982,6 +1040,11 @@ msgid_plural "%d Days"
msgstr[0] "1 dia"
msgstr[1] "%d dias"
+msgid "1 Issue"
+msgid_plural "%d Issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "1 closed issue"
msgid_plural "%{issues} closed issues"
msgstr[0] "1 issue fechada"
@@ -997,6 +1060,11 @@ msgid_plural "%d days"
msgstr[0] ""
msgstr[1] ""
+msgid "1 deploy key"
+msgid_plural "%d deploy keys"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] "1 grupo"
@@ -1099,6 +1167,9 @@ msgstr "8 horas"
msgid ":%{startLine} to %{endLine}"
msgstr ""
+msgid "A %{incident_docs_start}modified issue%{incident_docs_end} to guide the resolution of incidents."
+msgstr ""
+
msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr "'Runner' é um processo que executa uma tarefa. Você pode configurar quantos Runners você precisar."
@@ -1111,6 +1182,9 @@ msgstr ""
msgid "A GitBook site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr "Um site Gitbook que usa Netlify para CI/CD em vez do Gitlab, mas ainda com todas as outras ótimas funcionalidades do Gitlab."
+msgid "A Gitpod configured Webapplication in Spring and Java"
+msgstr ""
+
msgid "A Hexo site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr "Um site Hexo que usa Netlify para CI/CD em vez do Gitlab, mas ainda com todas as outras ótimas funcionalidades do Gitlab."
@@ -1282,9 +1356,15 @@ msgstr "Acesso negado! Por favor, verifique se você pode adicionar chaves de de
msgid "Access expiration date"
msgstr "Data de expiração do acesso"
+msgid "Access expires"
+msgstr ""
+
msgid "Access forbidden. Check your access level."
msgstr "Acesso proibido. Verifique seu nível de acesso."
+msgid "Access granted"
+msgstr ""
+
msgid "Access requests"
msgstr ""
@@ -1294,6 +1374,9 @@ msgstr "Acesso a '%{classification_label}' não permitido"
msgid "Access to Pages websites are controlled based on the user's membership to a given project. By checking this box, users will be required to be logged in to have access to all Pages websites in your instance."
msgstr ""
+msgid "AccessDropdown|Deploy Keys"
+msgstr ""
+
msgid "AccessDropdown|Groups"
msgstr "Grupos"
@@ -1411,12 +1494,6 @@ msgstr ""
msgid "Active Sessions"
msgstr "Sessões ativas"
-msgid "Active Users:"
-msgstr ""
-
-msgid "Active users"
-msgstr ""
-
msgid "Activity"
msgstr "Atividade"
@@ -1584,9 +1661,6 @@ msgstr ""
msgid "Add label(s)"
msgstr "Adicionar etiqueta(s)"
-msgid "Add license"
-msgstr "Adicionar licença"
-
msgid "Add list"
msgstr "Adicionar lista"
@@ -1761,21 +1835,51 @@ msgstr ""
msgid "AdminArea|Bots"
msgstr ""
+msgid "AdminArea|Components"
+msgstr ""
+
msgid "AdminArea|Developer"
msgstr ""
+msgid "AdminArea|Features"
+msgstr ""
+
+msgid "AdminArea|Groups: %{number_of_groups}"
+msgstr ""
+
msgid "AdminArea|Guest"
msgstr ""
msgid "AdminArea|Included Free in license"
msgstr ""
+msgid "AdminArea|Latest groups"
+msgstr ""
+
+msgid "AdminArea|Latest projects"
+msgstr ""
+
+msgid "AdminArea|Latest users"
+msgstr ""
+
msgid "AdminArea|Maintainer"
msgstr ""
+msgid "AdminArea|New group"
+msgstr ""
+
+msgid "AdminArea|New project"
+msgstr ""
+
+msgid "AdminArea|New user"
+msgstr ""
+
msgid "AdminArea|Owner"
msgstr ""
+msgid "AdminArea|Projects: %{number_of_projects}"
+msgstr ""
+
msgid "AdminArea|Reporter"
msgstr ""
@@ -1803,6 +1907,9 @@ msgstr ""
msgid "AdminArea|Users without a Group and Project"
msgstr ""
+msgid "AdminArea|Users: %{number_of_users}"
+msgstr ""
+
msgid "AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running."
msgstr "Você parará todas as tarefas. Os processos em execução serão abruptamente interrompidos."
@@ -1821,9 +1928,6 @@ msgstr "Excluir"
msgid "AdminProjects|Delete Project %{projectName}?"
msgstr "Excluir o projeto %{projectName}?"
-msgid "AdminProjects|Delete project"
-msgstr "Excluir projeto"
-
msgid "AdminSettings|Apply integration settings to all Projects"
msgstr ""
@@ -2061,21 +2165,30 @@ msgstr ""
msgid "AdminUsers|Without projects"
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 %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 ""
msgid "AdminUsers|You cannot remove your own admin rights."
msgstr ""
+msgid "AdminUsers|You must transfer ownership or delete the groups owned by this user before you can delete their account"
+msgstr ""
+
msgid "Administration"
msgstr ""
msgid "Advanced"
msgstr "Avançado"
+msgid "Advanced Search"
+msgstr ""
+
+msgid "Advanced Search with Elasticsearch"
+msgstr ""
+
msgid "Advanced Settings"
msgstr ""
@@ -2153,6 +2266,9 @@ msgstr ""
msgid "AlertManagement|Edit"
msgstr ""
+msgid "AlertManagement|Environment"
+msgstr ""
+
msgid "AlertManagement|Events"
msgstr ""
@@ -2165,6 +2281,9 @@ msgstr ""
msgid "AlertManagement|Issue"
msgstr ""
+msgid "AlertManagement|Key"
+msgstr ""
+
msgid "AlertManagement|Low"
msgstr ""
@@ -2258,6 +2377,9 @@ msgstr ""
msgid "AlertManagement|Unknown"
msgstr ""
+msgid "AlertManagement|Value"
+msgstr ""
+
msgid "AlertManagement|View alerts in Opsgenie"
msgstr ""
@@ -2417,6 +2539,9 @@ msgstr ""
msgid "All projects"
msgstr "Todos os projetos"
+msgid "All projects selected"
+msgstr ""
+
msgid "All security scans are enabled because %{linkStart}Auto DevOps%{linkEnd} is enabled on this project"
msgstr ""
@@ -2504,6 +2629,9 @@ msgstr "Permite adicionar e gerenciar clusters do Kubernetes."
msgid "Almost there"
msgstr ""
+msgid "Already blocked"
+msgstr ""
+
msgid "Also called \"Issuer\" or \"Relying party trust identifier\""
msgstr "Também chamado de \"Emissor\" ou \"Identificador de confiança em terceiros\""
@@ -2558,6 +2686,9 @@ msgstr "Um campo vazio do usuário do GitLab adicionará o nome completo do usuÃ
msgid "An error has occurred"
msgstr "Ocorreu um erro"
+msgid "An error occured while making the changes: %{error}"
+msgstr ""
+
msgid "An error occurred adding a draft to the thread."
msgstr ""
@@ -2585,12 +2716,6 @@ msgstr "Erro ao pré-visualizar o blob"
msgid "An error occurred when toggling the notification subscription"
msgstr "Erro ao modificar notificação de assinatura"
-msgid "An error occurred when trying to resolve a comment. Please try again."
-msgstr "Ocorreu um erro ao tentar resolver um comentário. Por favor, tente novamente."
-
-msgid "An error occurred when trying to resolve a discussion. Please try again."
-msgstr "Ocorreu um erro ao tentar resolver uma discussão. Por favor, tente novamente."
-
msgid "An error occurred when updating the issue weight"
msgstr "Ocorreu um erro ao atualizar o peso do issue"
@@ -2606,12 +2731,6 @@ msgstr ""
msgid "An error occurred while checking group path. Please refresh and try again."
msgstr ""
-msgid "An error occurred while committing your changes."
-msgstr ""
-
-msgid "An error occurred while creating the list. Please try again."
-msgstr ""
-
msgid "An error occurred while decoding the file."
msgstr ""
@@ -2684,25 +2803,19 @@ msgstr ""
msgid "An error occurred while fetching the Service Desk address."
msgstr "Um erro ocorreu ao consultar o endereço da Central de Serviços."
-msgid "An error occurred while fetching the board issues. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the board lists. Please reload the page."
msgstr ""
msgid "An error occurred while fetching the board lists. Please try again."
msgstr "Ocorreu um erro ao buscar lista de painéis. Por favor, tente novamente."
-msgid "An error occurred while fetching the board swimlanes. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the builds."
msgstr ""
msgid "An error occurred while fetching the job log."
msgstr "Ocorreu um erro na recuperação de logs da tarefa."
-msgid "An error occurred while fetching the job trace."
+msgid "An error occurred while fetching the job logs."
msgstr ""
msgid "An error occurred while fetching the job."
@@ -2849,9 +2962,6 @@ msgstr "Ocorreu um erro ao salvar o status de substituição do LDAP. Por favor,
msgid "An error occurred while saving assignees"
msgstr "Erro ao salvar assignees"
-msgid "An error occurred while saving the template. Please check if the template exists."
-msgstr ""
-
msgid "An error occurred while searching for milestones"
msgstr ""
@@ -2870,12 +2980,12 @@ msgstr "Ocorreu um erro ao desinscrever às notificações."
msgid "An error occurred while updating approvers"
msgstr "Ocorreu um erro ao atualizar os aprovadores"
+msgid "An error occurred while updating labels."
+msgstr ""
+
msgid "An error occurred while updating the comment"
msgstr "Ocorreu um erro durante a atualização do comentário"
-msgid "An error occurred while updating the list. Please try again."
-msgstr ""
-
msgid "An error occurred while validating group path"
msgstr ""
@@ -2927,6 +3037,9 @@ msgstr "Ocorreu um erro inesperado ao parar o terminal da web."
msgid "An unknown error occurred while loading this graph."
msgstr ""
+msgid "An unknown error occurred."
+msgstr ""
+
msgid "Analytics"
msgstr "Telemetria"
@@ -2960,10 +3073,10 @@ msgstr "Verificação anti-spam"
msgid "Any"
msgstr "Qualquer um"
-msgid "Any Author"
+msgid "Any %{header}"
msgstr ""
-msgid "Any Status"
+msgid "Any Author"
msgstr ""
msgid "Any branch"
@@ -3017,6 +3130,9 @@ msgstr "Aplicativo"
msgid "Application ID"
msgstr "ID da aplicação"
+msgid "Application limits saved successfully"
+msgstr ""
+
msgid "Application settings saved successfully"
msgstr "As configurações do aplicativo foram salvas com sucesso"
@@ -3226,6 +3342,9 @@ msgstr "Tem certeza de que deseja cancelar a edição deste comentário?"
msgid "Are you sure you want to close this blocked issue?"
msgstr ""
+msgid "Are you sure you want to delete \"%{name}\" Value Stream?"
+msgstr ""
+
msgid "Are you sure you want to delete %{name}?"
msgstr ""
@@ -3235,6 +3354,9 @@ msgstr "Você tem certeza que deseja excluir estes artefatos?"
msgid "Are you sure you want to delete this %{typeOfComment}?"
msgstr "Tem certeza de que deseja excluir este %{typeOfComment}?"
+msgid "Are you sure you want to delete this SSH key?"
+msgstr ""
+
msgid "Are you sure you want to delete this board?"
msgstr "Tem certeza de que deseja excluir este painel?"
@@ -3259,6 +3381,11 @@ msgstr ""
msgid "Are you sure you want to erase this build?"
msgstr "Tem certeza de que deseja limpar este build?"
+msgid "Are you sure you want to import %d repository?"
+msgid_plural "Are you sure you want to import %d repositories?"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Are you sure you want to lose unsaved changes?"
msgstr "Você tem certeza de que quer perder as alterações não salvas?"
@@ -3268,15 +3395,15 @@ msgstr "Você deseja mesmo perder as informações da sua issue?"
msgid "Are you sure you want to merge immediately?"
msgstr ""
-msgid "Are you sure you want to permanently delete this license?"
-msgstr "Tem certeza que deseja excluir permanentemente esta licença?"
-
msgid "Are you sure you want to re-deploy this environment?"
msgstr ""
msgid "Are you sure you want to regenerate the public key? You will have to update the public key on the remote server before mirroring will work again."
msgstr "Tem certeza de que deseja regenerar a chave pública? Você precisará atualizar a chave pública no servidor remote antes que o espelhamento funcione novamente."
+msgid "Are you sure you want to reindex?"
+msgstr ""
+
msgid "Are you sure you want to remove %{group_name}?"
msgstr "Você tem certeza que quer remover %{group_name}?"
@@ -3304,6 +3431,9 @@ msgstr ""
msgid "Are you sure you want to revoke this nickname?"
msgstr ""
+msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
+msgstr ""
+
msgid "Are you sure you want to stop this environment?"
msgstr "Você tem certeza de que deseja parar este ambiente?"
@@ -3325,6 +3455,9 @@ msgstr ""
msgid "Are you sure? The device will be signed out of GitLab and all remember me tokens revoked."
msgstr ""
+msgid "Are you sure? This will invalidate your registered applications and U2F / WebAuthn devices."
+msgstr ""
+
msgid "Are you sure? This will invalidate your registered applications and U2F devices."
msgstr "Você tem certeza? Isso invalidará seus aplicativos registrados e dispositivos U2F."
@@ -3343,9 +3476,6 @@ msgstr "O artefato foi excluído com sucesso."
msgid "Artifacts"
msgstr "Artefatos"
-msgid "As U2F devices are only supported by a few browsers, we require that you set up a two-factor authentication app before a U2F device. That way you'll always be able to log in - even when you're using an unsupported browser."
-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 ""
@@ -3539,6 +3669,9 @@ msgstr ""
msgid "AuditLogs|Target"
msgstr ""
+msgid "AuditLogs|This month"
+msgstr ""
+
msgid "AuditLogs|User Events"
msgstr ""
@@ -3578,6 +3711,9 @@ msgstr "Método de autenticação atualizado"
msgid "Authentication via U2F device failed."
msgstr "Autenticação via dispositivo U2F falhou."
+msgid "Authentication via WebAuthn device failed."
+msgstr ""
+
msgid "Author"
msgstr "Autor"
@@ -3845,15 +3981,6 @@ msgstr "URL raiz de bambu como https://bamboo.exemplo.com"
msgid "BambooService|You must set up automatic revision labeling and a repository trigger in Bamboo."
msgstr "Você precisa configurar etiquetas de revisão automáticas e um gatilho de repositório no Bamboo."
-msgid "BatchComments|Delete all pending comments"
-msgstr "Excluir todos os comentários pendentes"
-
-msgid "BatchComments|Discard review?"
-msgstr "Descartar revisão?"
-
-msgid "BatchComments|You're about to discard your review which will delete all of your pending comments. The deleted comments %{strong_start}cannot%{strong_end} be restored."
-msgstr "Você está prestes a descartar sua revisão, o que excluirá todos os seus comentários pendentes. Os comentários excluídos %{strong_start}não podem%{strong_end} ser restaurados."
-
msgid "Be careful. Changing the project's namespace can have unintended side effects."
msgstr "Cuidado. Alterar o namespace do projeto pode ter efeitos colaterais indesejados."
@@ -3875,6 +4002,9 @@ msgstr "Abaixo você encontrará todos os grupos que são públicos."
msgid "Bi-weekly code coverage"
msgstr ""
+msgid "Billable Users:"
+msgstr ""
+
msgid "Billing"
msgstr "Cobrança"
@@ -3884,7 +4014,7 @@ msgstr ""
msgid "BillingPlans|@%{user_name} you are currently using the %{plan_name} plan."
msgstr ""
-msgid "BillingPlans|Congratulations, your new trial is activated"
+msgid "BillingPlans|Congratulations, your free trial is activated."
msgstr ""
msgid "BillingPlans|If you would like to downgrade your plan please contact %{support_link_start}Customer Support%{support_link_end}."
@@ -3947,6 +4077,9 @@ msgstr "Importar do Bitbucket"
msgid "Blame"
msgstr ""
+msgid "Block user"
+msgstr ""
+
msgid "Blocked"
msgstr "Bloqueado"
@@ -3962,31 +4095,37 @@ msgstr ""
msgid "Blog"
msgstr "Blog"
-msgid "Board name"
-msgstr "Nome do painel"
-
msgid "Board scope"
msgstr "Escopo do painel"
msgid "Board scope affects which issues are displayed for anyone who visits this board"
msgstr "O escopo do painel afeta quais issues são exibidas para qualquer um que visite este painel"
-msgid "BoardBlankState|Add default lists"
-msgstr "Adicionar listas padrão"
+msgid "Boards"
+msgstr "Painéis"
-msgid "BoardBlankState|Add the following default lists to your Issue Board with one click:"
+msgid "Boards and Board Lists"
msgstr ""
-msgid "BoardBlankState|Nevermind, I'll use my own"
-msgstr "Deixa pra lá, eu vou usar o meu próprio"
+msgid "Boards|An error occurred while creating the issue. Please try again."
+msgstr ""
-msgid "BoardBlankState|Starting out with the default set of lists will get you right on the way to making the most of your board."
+msgid "Boards|An error occurred while creating the list. Please try again."
msgstr ""
-msgid "Boards"
-msgstr "Painéis"
+msgid "Boards|An error occurred while fetching issues. Please reload the page."
+msgstr ""
-msgid "Boards and Board Lists"
+msgid "Boards|An error occurred while fetching the board issues. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching the board swimlanes. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while moving the issue. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while updating the list. Please try again."
msgstr ""
msgid "Boards|Collapse"
@@ -4013,8 +4152,8 @@ msgstr "O branch %{branchName} não foi encontrado no repositório deste projeto
msgid "Branch %{branch_name} was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr ""
-msgid "Branch has changed"
-msgstr "Branch foi alterado"
+msgid "Branch changed"
+msgstr ""
msgid "Branch is already taken"
msgstr "Branch já utilizada"
@@ -4319,6 +4458,9 @@ msgstr "FECHADO"
msgid "CLOSED (MOVED)"
msgstr "FECHADO (MOVIDO)"
+msgid "CODEOWNERS rule violation"
+msgstr ""
+
msgid "CONTRIBUTING"
msgstr "CONTRIBUINDO"
@@ -4349,9 +4491,6 @@ msgstr ""
msgid "Can't create snippet: %{err}"
msgstr ""
-msgid "Can't edit as source branch was deleted"
-msgstr ""
-
msgid "Can't fetch content for the blob: %{err}"
msgstr ""
@@ -4364,9 +4503,6 @@ msgstr "Não foi possível encontrar a variável: ZiteReader"
msgid "Can't load mermaid module: %{err}"
msgstr ""
-msgid "Can't remove group members without group managed account"
-msgstr "Não é possível remover membros do grupo sem uma conta gerenciada do grupo"
-
msgid "Can't scan the code?"
msgstr "Não consegue escanear o código?"
@@ -4409,6 +4545,9 @@ msgstr "Não é possível criar o relatório de abuso. O usuário foi excluído.
msgid "Cannot create the abuse report. This user has been blocked."
msgstr "Não é possível criar o relatório de abuso. Este usuário foi bloqueado."
+msgid "Cannot enable shared runners because parent group does not allow it"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -4514,6 +4653,15 @@ msgstr "Altere sua senha"
msgid "Change your password or recover your current one"
msgstr "Altere sua senha ou recupere sua senha atual"
+msgid "ChangeReviewer|Reviewer changed from %{old} to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Reviewer changed to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Unassigned"
+msgstr ""
+
msgid "ChangeTypeActionLabel|Pick into branch"
msgstr "Pick para um branch"
@@ -4553,6 +4701,9 @@ msgstr "Alterações suprimidas. Clique para mostrar."
msgid "Changes the title to \"%{title_param}\"."
msgstr "Altera o título para \"%{title_param}\"."
+msgid "Changes were successfully made."
+msgstr ""
+
msgid "Changes won't take place until the index is %{link_start}recreated%{link_end}."
msgstr "As alterações não ocorrerão até que o índice seja %{link_start}recriado%{link_end}."
@@ -4958,6 +5109,9 @@ msgstr "Mascarada"
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove variable"
+msgstr ""
+
msgid "CiVariables|Remove variable row"
msgstr "Remover a variável"
@@ -5036,9 +5190,6 @@ msgstr ""
msgid "Clear due date"
msgstr ""
-msgid "Clear input"
-msgstr "Limpar entrada"
-
msgid "Clear recent searches"
msgstr ""
@@ -5087,6 +5238,9 @@ msgstr "Chave de autenticação do cliente"
msgid "Client authentication key password"
msgstr "Senha da chave de autenticação do cliente"
+msgid "Client request timeout"
+msgstr ""
+
msgid "Clients"
msgstr "Clientes"
@@ -5171,6 +5325,27 @@ msgstr ""
msgid "Cluster type must be specificed for Stages::ClusterEndpointInserter"
msgstr ""
+msgid "ClusterAgents|Configuration"
+msgstr ""
+
+msgid "ClusterAgents|Connect your cluster with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate Kubernetes with a GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Name"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Agent also requires %{linkStart}enabling the Agent Server%{linkEnd}"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Kubernetes Agent allows an Infrastructure as Code, GitOps approach to integrating Kubernetes clusters with GitLab. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "ClusterAgent|This feature is only available for premium plans"
msgstr ""
@@ -5240,10 +5415,10 @@ msgstr "Todos os dados serão excluídos e não poderão ser restaurados."
msgid "ClusterIntegration|All installed applications and related resources"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster."
-msgstr "Permite que o GitLab gerencie contas serviços e namespaces para esse cluster."
+msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{linkStart}More information%{linkEnd}"
+msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{startLink}More information%{endLink}"
+msgid "ClusterIntegration|Allow GitLab to manage namespaces and service accounts for this cluster."
msgstr ""
msgid "ClusterIntegration|Alternatively, "
@@ -5264,6 +5439,9 @@ msgstr "Ocorreu um erro ao tentar realizar o fetch de seus projetos: %{error}"
msgid "ClusterIntegration|An error occurred while trying to fetch zone machine types: %{error}"
msgstr "Ocorreu um erro ao tentar realizar o fetch dos tipos de máquinas da zona: %{error}"
+msgid "ClusterIntegration|An unknown error occurred while attempting to connect to Kubernetes."
+msgstr ""
+
msgid "ClusterIntegration|Any project namespaces"
msgstr ""
@@ -5279,6 +5457,9 @@ msgstr ""
msgid "ClusterIntegration|Authenticate with Amazon Web Services"
msgstr ""
+msgid "ClusterIntegration|Authentication Error"
+msgstr ""
+
msgid "ClusterIntegration|Base domain"
msgstr "Domínio base"
@@ -5297,13 +5478,22 @@ msgstr ""
msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
msgstr "Pacote de autoridade certificadora (Formato PEM)"
-msgid "ClusterIntegration|Choose the %{startLink}security group %{externalLinkIcon} %{endLink} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
+msgid "ClusterIntegration|Check your CA certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Check your cluster status"
+msgstr ""
+
+msgid "ClusterIntegration|Check your token"
+msgstr ""
+
+msgid "ClusterIntegration|Choose the %{linkStart}security group %{linkEnd} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}subnets %{externalLinkIcon} %{endLink} in your VPC where your worker nodes will run."
+msgid "ClusterIntegration|Choose the %{linkStart}subnets %{linkEnd} in your VPC where your worker nodes will run."
msgstr ""
-msgid "ClusterIntegration|Choose the worker node %{startLink}instance type %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Choose the worker node %{linkStart}instance type%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Choose which applications to install on your Kubernetes cluster."
@@ -5315,10 +5505,7 @@ msgstr "Escolha quais dos seus ambientes usarão esse cluster."
msgid "ClusterIntegration|Clear cluster cache"
msgstr ""
-msgid "ClusterIntegration|Clear the local cache of namespace and service accounts. This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
-msgstr ""
-
-msgid "ClusterIntegration|Cluster being created"
+msgid "ClusterIntegration|Clear the local cache of namespace and service accounts."
msgstr ""
msgid "ClusterIntegration|Cluster management project (alpha)"
@@ -5330,15 +5517,21 @@ msgstr "O nome do cluster é obrigatório."
msgid "ClusterIntegration|Cluster_applications artifact too big. Maximum allowable size: %{human_size}"
msgstr ""
-msgid "ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters."
-msgstr "Clusters são utilizados selecionando o ancestral mais próximo de um ambiente de escopo correspondente. Por exemplo, projeto de clusters vai substituir grupo de clusters."
-
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|Clusters connected with a certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Connect cluster with certificate"
+msgstr ""
+
msgid "ClusterIntegration|Connect existing cluster"
msgstr ""
+msgid "ClusterIntegration|Connection Error"
+msgstr ""
+
msgid "ClusterIntegration|Copy API URL"
msgstr "Copiar URL da API"
@@ -5414,6 +5607,12 @@ msgstr ""
msgid "ClusterIntegration|Deletes all GitLab resources attached to this cluster during removal"
msgstr ""
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared."
+msgstr ""
+
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared. %{linkStart}More information%{linkEnd}"
+msgstr ""
+
msgid "ClusterIntegration|Did you know?"
msgstr "Você sabia?"
@@ -5483,6 +5682,9 @@ msgstr ""
msgid "ClusterIntegration|Fluentd is an open source data collector, which lets you unify the data collection and consumption for a better use and understanding of data. It requires at least one of the following logs to be successfully installed."
msgstr ""
+msgid "ClusterIntegration|GitLab Agent managed clusters"
+msgstr ""
+
msgid "ClusterIntegration|GitLab Container Network Policies"
msgstr ""
@@ -5495,6 +5697,12 @@ msgstr "Gitlab Runner"
msgid "ClusterIntegration|GitLab Runner connects to the repository and executes CI/CD jobs, pushing results back and deploying applications to production."
msgstr ""
+msgid "ClusterIntegration|GitLab failed to authenticate."
+msgstr ""
+
+msgid "ClusterIntegration|GitLab failed to connect to the cluster."
+msgstr ""
+
msgid "ClusterIntegration|GitLab-managed cluster"
msgstr "Cluster gerenciado pelo GitLab"
@@ -5516,6 +5724,9 @@ msgstr "Projeto do Google Kubernetes Engine"
msgid "ClusterIntegration|Group cluster"
msgstr "Cluster de grupo"
+msgid "ClusterIntegration|HTTP Error"
+msgstr ""
+
msgid "ClusterIntegration|Helm Tiller"
msgstr "Helm Tiller"
@@ -5549,8 +5760,11 @@ msgstr "Cluster de instância"
msgid "ClusterIntegration|Instance type"
msgstr ""
-msgid "ClusterIntegration|Integrate Kubernetes cluster automation"
-msgstr "Integrar automação de cluster Kubernetes"
+msgid "ClusterIntegration|Integrate Kubernetes with a cluster certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Integrate with a cluster certificate"
+msgstr ""
msgid "ClusterIntegration|Issuer Email"
msgstr ""
@@ -5585,9 +5799,6 @@ msgstr "Nome de domínio Knative foi atualizado com sucesso."
msgid "ClusterIntegration|Knative extends Kubernetes to provide a set of middleware components that are essential to build modern, source-centric, and container-based applications that can run anywhere: on premises, in the cloud, or even in a third-party data center."
msgstr "Knative estende Kubernetes para fornecer um conjunto de componentes de middleware que são essenciais para construir aplicativos modernos, centrados em fontes e baseados em contêineres que podem ser executados em qualquer lugar: no local, na nuvem ou até mesmo em um datacenter de terceiros."
-msgid "ClusterIntegration|Kubernetes cluster"
-msgstr "Cluter Kubernetes"
-
msgid "ClusterIntegration|Kubernetes cluster is being created..."
msgstr ""
@@ -5600,9 +5811,6 @@ msgstr ""
msgid "ClusterIntegration|Kubernetes clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr "Clusters Kubernetes permitem que você use apps de revisão, faça deploy de suas aplicações, execute suas pipelines e muito mais de um jeito mais simples."
-msgid "ClusterIntegration|Kubernetes clusters can be used to deploy applications and to provide Review Apps for this project"
-msgstr "Cluster Kubernetes podem ser usados para publicar aplicações e permitir app de revisão para esse projeto"
-
msgid "ClusterIntegration|Kubernetes version"
msgstr ""
@@ -5615,7 +5823,7 @@ msgstr "Saiba mais sobre os %{help_link_start_machine_type}tipos de máquinas%{h
msgid "ClusterIntegration|Learn more about %{help_link_start}zones%{help_link_end}."
msgstr "Saiba mais sobre as %{help_link_start}zonas%{help_link_end}."
-msgid "ClusterIntegration|Learn more about %{startLink}Regions %{externalLinkIcon}%{endLink}."
+msgid "ClusterIntegration|Learn more about %{linkStart}Regions%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Learn more about Kubernetes"
@@ -5660,12 +5868,18 @@ msgstr ""
msgid "ClusterIntegration|Machine type"
msgstr "Tipo de máquina"
+msgid "ClusterIntegration|Make sure your API endpoint is correct"
+msgstr ""
+
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create Kubernetes clusters"
msgstr "Tenha certeza de que sua conta %{link_to_requirements} para criar clusters Kubernetes"
msgid "ClusterIntegration|Manage your Kubernetes cluster by visiting %{provider_link}"
msgstr ""
+msgid "ClusterIntegration|Namespace per environment"
+msgstr ""
+
msgid "ClusterIntegration|No IAM Roles found"
msgstr ""
@@ -5711,6 +5925,9 @@ msgstr ""
msgid "ClusterIntegration|No zones matched your search"
msgstr "Nenhuma zona corresponde à sua pesquisa"
+msgid "ClusterIntegration|Node calculations use the Kubernetes Metrics API. Make sure your cluster has metrics installed"
+msgstr ""
+
msgid "ClusterIntegration|Number of nodes"
msgstr "Número de nós"
@@ -5753,6 +5970,9 @@ msgstr ""
msgid "ClusterIntegration|RBAC-enabled cluster"
msgstr "Cluster habilitado para RBAC"
+msgid "ClusterIntegration|Read our %{linkStart}help page%{linkEnd} on Kubernetes cluster integration."
+msgstr ""
+
msgid "ClusterIntegration|Read our %{link_start}help page%{link_end} on Kubernetes cluster integration."
msgstr ""
@@ -5855,7 +6075,7 @@ msgstr ""
msgid "ClusterIntegration|Select a VPC to choose a subnet"
msgstr ""
-msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{linkStart}Amazon Web Services %{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select a network to choose a subnetwork"
@@ -5888,7 +6108,7 @@ msgstr "Selecione projeto e zona para escolher o tipo de máquina"
msgid "ClusterIntegration|Select project to choose zone"
msgstr "Selecione o projeto para escolher a zona"
-msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select zone"
@@ -5978,9 +6198,18 @@ msgstr ""
msgid "ClusterIntegration|There was a problem authenticating with your cluster. Please ensure your CA Certificate and Token are valid."
msgstr ""
+msgid "ClusterIntegration|There was an HTTP error when connecting to your cluster."
+msgstr ""
+
msgid "ClusterIntegration|This account must have permissions to create a Kubernetes cluster in the %{link_to_container_project} specified below"
msgstr "Essa conta precisa de permissões para criar um cluster Kubernetes no %{link_to_container_project} especificado"
+msgid "ClusterIntegration|This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
+msgstr ""
+
+msgid "ClusterIntegration|This is necessary to clear existing environment-namespace associations from clusters previously managed by GitLab."
+msgstr ""
+
msgid "ClusterIntegration|This option will allow you to install applications on RBAC clusters."
msgstr "Esta opção permite-lhe instalar aplicações em clusters RBAC."
@@ -6005,9 +6234,21 @@ msgstr ""
msgid "ClusterIntegration|To use a new project, first create one on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}."
msgstr ""
+msgid "ClusterIntegration|Troubleshooting tips:"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Authenticate"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Connect"
+msgstr ""
+
msgid "ClusterIntegration|Uninstall %{appTitle}"
msgstr "Desinstalar %{appTitle}"
+msgid "ClusterIntegration|Unknown Error"
+msgstr ""
+
msgid "ClusterIntegration|Update %{appTitle}"
msgstr ""
@@ -6068,7 +6309,7 @@ msgstr "Sua conta precisa de %{link_to_kubernetes_engine}"
msgid "ClusterIntegration|Your cluster API is unreachable. Please ensure your API URL is correct."
msgstr ""
-msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Zone"
@@ -6188,6 +6429,9 @@ msgstr ""
msgid "Collapse"
msgstr "Recolher"
+msgid "Collapse all threads"
+msgstr ""
+
msgid "Collapse approvers"
msgstr "Recolher aprovadores"
@@ -6337,8 +6581,8 @@ msgstr "Commit feito por"
msgid "Commit…"
msgstr "Commit…"
-msgid "Company"
-msgstr "Empresa"
+msgid "Community forum"
+msgstr ""
msgid "Company name"
msgstr ""
@@ -6346,6 +6590,9 @@ msgstr ""
msgid "Compare"
msgstr "Comparar"
+msgid "Compare %{oldCommitId}...%{newCommitId}"
+msgstr ""
+
msgid "Compare Git revisions"
msgstr "Parar versões do Git"
@@ -6361,6 +6608,9 @@ msgstr "Compare as mudanças do último commit"
msgid "Compare changes with the merge request target branch"
msgstr "Compare as mudanças do merge request com o branch de destino"
+msgid "Compare submodule commit revisions"
+msgstr ""
+
msgid "Compare with previous version"
msgstr ""
@@ -6496,6 +6746,9 @@ msgstr "Configure a integração de %{link}."
msgid "Configure the way a user creates a new account."
msgstr "Configurar a forma como o usuário cria uma nova conta."
+msgid "Configure which lists are shown for anyone who visits this board"
+msgstr ""
+
msgid "Confirm"
msgstr "Confirmar"
@@ -6721,6 +6974,9 @@ msgstr[1] ""
msgid "ContainerRegistry|Set cleanup policy"
msgstr ""
+msgid "ContainerRegistry|Some tags were not deleted"
+msgstr ""
+
msgid "ContainerRegistry|Something went wrong while fetching the cleanup policy."
msgstr ""
@@ -6760,6 +7016,9 @@ msgstr ""
msgid "ContainerRegistry|Tags with names matching this regex pattern will %{italicStart}expire:%{italicEnd}"
msgstr ""
+msgid "ContainerRegistry|The cleanup policy timed out before it could delete all tags. An administrator can %{adminLinkStart}manually run cleanup now%{adminLinkEnd} or you can wait for the cleanup policy to automatically run again. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "ContainerRegistry|The last tag related to this image was recently removed. This empty image and any associated data will be automatically removed as part of the regular Garbage Collection process. If you have any questions, contact your administrator."
msgstr ""
@@ -6892,6 +7151,9 @@ msgstr ""
msgid "Contributions per group member"
msgstr "Contribuições por membro do grupo"
+msgid "Contributor"
+msgstr ""
+
msgid "Contributors"
msgstr "Contribuidores"
@@ -7021,6 +7283,9 @@ msgstr ""
msgid "Could not change HEAD: branch '%{branch}' does not exist"
msgstr "Não foi possível mudar o HEAD: o branch \"%{branch}\" não existe"
+msgid "Could not commit. An unexpected error occurred."
+msgstr ""
+
msgid "Could not connect to FogBugz, check your URL"
msgstr "Não foi possível se conectar a FogBugz, verifique sua URL"
@@ -7060,6 +7325,9 @@ msgstr ""
msgid "Could not find iteration"
msgstr ""
+msgid "Could not load instance counts. Please refresh the page to try again."
+msgstr ""
+
msgid "Could not remove the trigger."
msgstr "Não foi possível remover o gatilho."
@@ -7084,10 +7352,10 @@ msgstr "Não foi possível salvar o ID do projeto"
msgid "Could not save prometheus manual configuration"
msgstr "Não foi possível salvar a configuração manual do prometheus"
-msgid "Could not udpdate wiki page"
+msgid "Could not update the LDAP settings"
msgstr ""
-msgid "Could not update the LDAP settings"
+msgid "Could not update wiki page"
msgstr ""
msgid "Could not upload your designs as one or more files uploaded are not supported."
@@ -7745,6 +8013,9 @@ msgstr ""
msgid "DastProfiles|Are you sure you want to delete this profile?"
msgstr ""
+msgid "DastProfiles|Could not create site validation token. Please refresh the page, or try again later."
+msgstr ""
+
msgid "DastProfiles|Could not create the scanner profile. Please try again."
msgstr ""
@@ -7769,6 +8040,12 @@ msgstr ""
msgid "DastProfiles|Could not fetch site profiles. Please refresh the page, or try again later."
msgstr ""
+msgid "DastProfiles|Could not retrieve site validation status. Please refresh the page, or try again later."
+msgstr ""
+
+msgid "DastProfiles|Could not update the scanner profile. Please try again."
+msgstr ""
+
msgid "DastProfiles|Could not update the site profile. Please try again."
msgstr ""
@@ -7784,7 +8061,7 @@ msgstr ""
msgid "DastProfiles|Download validation text file"
msgstr ""
-msgid "DastProfiles|Edit feature will come soon. Please create a new profile if changes needed"
+msgid "DastProfiles|Edit scanner profile"
msgstr ""
msgid "DastProfiles|Edit site profile"
@@ -7817,6 +8094,9 @@ msgstr ""
msgid "DastProfiles|No profiles created yet"
msgstr ""
+msgid "DastProfiles|Passive"
+msgstr ""
+
msgid "DastProfiles|Please enter a valid URL format, ex: http://www.example.com/home"
msgstr ""
@@ -7832,6 +8112,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan mode"
+msgstr ""
+
msgid "DastProfiles|Scanner Profile"
msgstr ""
@@ -7871,10 +8154,10 @@ msgstr ""
msgid "DastProfiles|Text file validation"
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
+msgid "DastProfiles|The maximum number of minutes allowed for the spider to traverse the site."
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the spider to traverse the site."
+msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
msgstr ""
msgid "DastProfiles|Validate"
@@ -7907,6 +8190,9 @@ msgstr ""
msgid "Date picker"
msgstr "Seletor de data"
+msgid "Date range"
+msgstr ""
+
msgid "Date range cannot exceed %{maxDateRange} days."
msgstr ""
@@ -7931,6 +8217,9 @@ msgstr "Dias"
msgid "Days to merge"
msgstr ""
+msgid "Dear Administrator,"
+msgstr ""
+
msgid "Debug"
msgstr "Depurar"
@@ -8042,12 +8331,18 @@ msgstr "atrasado"
msgid "Delete"
msgstr "Excluir"
+msgid "Delete %{name}"
+msgstr ""
+
msgid "Delete Comment"
msgstr ""
msgid "Delete Snippet"
msgstr "Excluir Snippet"
+msgid "Delete Value Stream"
+msgstr ""
+
msgid "Delete account"
msgstr ""
@@ -8069,9 +8364,6 @@ msgstr ""
msgid "Delete label: %{label_name} ?"
msgstr ""
-msgid "Delete license"
-msgstr "Excluir licença"
-
msgid "Delete list"
msgstr "Excluir lista"
@@ -8147,15 +8439,6 @@ msgstr ""
msgid "Deleting a project places it into a read-only state until %{date}, at which point the project will be permanently deleted. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "Deleting the license failed."
-msgstr "A exclusão da licença falhou."
-
-msgid "Deleting the license failed. The license was not found."
-msgstr "A exclusão da licença falhou. A licença não foi encontrada."
-
-msgid "Deleting the license failed. You are not permitted to perform this action."
-msgstr "A exclusão de licença falhou. Você não tem permissão para executar essa ação."
-
msgid "Deleting the project will delete its repository and all related resources including issues, merge requests etc."
msgstr ""
@@ -8651,7 +8934,10 @@ msgstr ""
msgid "DesignManagement|The maximum number of designs allowed to be uploaded is %{upload_limit}. Please try again."
msgstr ""
-msgid "DesignManagement|To upload designs, you'll need to enable LFS. %{requirements_link_start}More information%{requirements_link_end}"
+msgid "DesignManagement|There was an error moving your designs. Please upload your designs below."
+msgstr ""
+
+msgid "DesignManagement|To upload designs, you'll need to enable LFS and have admin enable hashed storage. %{requirements_link_start}More information%{requirements_link_end}"
msgstr ""
msgid "DesignManagement|Unresolve thread"
@@ -8663,6 +8949,9 @@ msgstr ""
msgid "DesignManagement|Upload skipped."
msgstr ""
+msgid "DesignManagement|Your designs are being copied and are on their way… Please refresh to update."
+msgstr ""
+
msgid "DesignManagement|and %{moreCount} more."
msgstr ""
@@ -8720,6 +9009,9 @@ msgstr ""
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr "Algo errado aconteceu ao buscar linhas de comparação."
+msgid "Direct member"
+msgstr ""
+
msgid "Direction"
msgstr "Direção"
@@ -8768,9 +9060,6 @@ msgstr "Descartar as alterações para %{path}?"
msgid "Discard draft"
msgstr "Descartar rascunho"
-msgid "Discard review"
-msgstr "Descartar revisão"
-
msgid "DiscordService|Discord Notifications"
msgstr "Notificações do Discord"
@@ -8839,10 +9128,10 @@ msgstr ""
msgid "Dismiss Merge Request promotion"
msgstr "Descartar promoção de Merge Request"
-msgid "Dismiss Selected"
+msgid "Dismiss Value Stream Analytics introduction box"
msgstr ""
-msgid "Dismiss Value Stream Analytics introduction box"
+msgid "Dismiss selected"
msgstr ""
msgid "Dismiss trial promotion"
@@ -8893,9 +9182,6 @@ msgstr "Documentação para provedores de identidade populares"
msgid "Documents reindexed: %{processed_documents} (%{percentage}%%)"
msgstr ""
-msgid "Doing"
-msgstr "Fazendo"
-
msgid "Domain"
msgstr "Domínio"
@@ -9091,9 +9377,6 @@ msgstr ""
msgid "Edit environment"
msgstr "Editar ambiente"
-msgid "Edit file"
-msgstr "Editar arquivo"
-
msgid "Edit files in the editor and commit changes here"
msgstr "Alterar arquivos no editor e fazer commit das alterações aqui"
@@ -9106,6 +9389,12 @@ msgstr "Editar grupo: %{group_name}"
msgid "Edit identity for %{user_name}"
msgstr "Editar identidade para %{user_name}"
+msgid "Edit in Web IDE"
+msgstr ""
+
+msgid "Edit in single-file editor"
+msgstr ""
+
msgid "Edit issues"
msgstr "Editar issues"
@@ -9133,21 +9422,18 @@ msgstr ""
msgid "Editing"
msgstr ""
-msgid "Elasticsearch"
-msgstr "Elasticsearch"
-
msgid "Elasticsearch AWS IAM credentials"
msgstr ""
+msgid "Elasticsearch HTTP client timeout value in seconds."
+msgstr ""
+
msgid "Elasticsearch indexing restrictions"
msgstr ""
msgid "Elasticsearch indexing started"
msgstr ""
-msgid "Elasticsearch integration. Elasticsearch AWS IAM."
-msgstr "Integração com Elasticsearch. Elasticsearch AWS IAM."
-
msgid "Elasticsearch reindexing is already in progress"
msgstr ""
@@ -9175,9 +9461,6 @@ msgstr ""
msgid "Email Notification"
msgstr ""
-msgid "Email address"
-msgstr "Endereço de e-mail"
-
msgid "Email could not be sent"
msgstr ""
@@ -9241,6 +9524,9 @@ msgstr "E-mails"
msgid "Emails sent from Service Desk will have this name"
msgstr ""
+msgid "Emails sent to %{email} will still be supported"
+msgstr ""
+
msgid "Emails separated by comma"
msgstr "E-mails separados por vírgula"
@@ -9274,9 +9560,18 @@ msgstr "Arquivo vazio"
msgid "Enable"
msgstr "Ativar"
+msgid "Enable %{link_start}Gitpod%{link_end} integration to launch a development environment in your browser directly from GitLab."
+msgstr ""
+
msgid "Enable Auto DevOps"
msgstr "Ativar Auto DevOps"
+msgid "Enable Gitpod"
+msgstr ""
+
+msgid "Enable Gitpod?"
+msgstr ""
+
msgid "Enable HTML emails"
msgstr "Habilitar e-mails em HTML"
@@ -9406,9 +9701,6 @@ msgstr "Ativar isto apenas disponibilizará os recursos EE licenciados para proj
msgid "Encountered an error while rendering: %{err}"
msgstr ""
-msgid "End date"
-msgstr ""
-
msgid "Ends at (UTC)"
msgstr "Termina em (UTC)"
@@ -9568,7 +9860,7 @@ msgstr "Remover"
msgid "EnvironmentsDashboard|The environments dashboard provides a summary of each project's environments' status, including pipeline and alert statuses."
msgstr "O dashboard de ambientes fornece um resumo do status dos ambientes de cada projeto, incluindo status de pipelines e alertas."
-msgid "EnvironmentsDashboard|This dashboard displays a maximum of 7 projects and 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
+msgid "EnvironmentsDashboard|This dashboard displays 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
msgstr ""
msgid "Environments|An error occurred while canceling the auto stop, please try again"
@@ -9889,6 +10181,9 @@ msgstr ""
msgid "Error deleting project. Check logs for error details."
msgstr ""
+msgid "Error fetching burnup chart data"
+msgstr ""
+
msgid "Error fetching diverging counts for branches. Please try again."
msgstr ""
@@ -9967,6 +10262,9 @@ msgstr ""
msgid "Error occurred when saving assignees"
msgstr ""
+msgid "Error occurred when saving reviewers"
+msgstr ""
+
msgid "Error occurred when toggling the notification subscription"
msgstr "Erro ao alterar configuração de notificação de assinatura"
@@ -10219,12 +10517,15 @@ msgstr "Expandir"
msgid "Expand all"
msgstr "Expandir tudo"
-msgid "Expand approvers"
-msgstr "Expandir aprovadores"
+msgid "Expand all files"
+msgstr ""
-msgid "Expand dropdown"
+msgid "Expand all threads"
msgstr ""
+msgid "Expand approvers"
+msgstr "Expandir aprovadores"
+
msgid "Expand milestones"
msgstr ""
@@ -10393,6 +10694,9 @@ msgstr "Falha ao procurar por branches relacionadas."
msgid "Failed to create Merge Request. Please try again."
msgstr ""
+msgid "Failed to create To-Do for the design."
+msgstr ""
+
msgid "Failed to create a branch for this issue. Please try again."
msgstr ""
@@ -10432,6 +10736,12 @@ msgstr ""
msgid "Failed to load authors. Please try again."
msgstr ""
+msgid "Failed to load branches. Please try again."
+msgstr ""
+
+msgid "Failed to load deploy keys."
+msgstr ""
+
msgid "Failed to load emoji list."
msgstr "Falha ao carregar a lista de emojis."
@@ -10447,6 +10757,9 @@ msgstr ""
msgid "Failed to load groups & users."
msgstr ""
+msgid "Failed to load groups, users and deploy keys."
+msgstr ""
+
msgid "Failed to load labels. Please try again."
msgstr ""
@@ -10456,6 +10769,12 @@ msgstr ""
msgid "Failed to load related branches"
msgstr "Falha ao carregar branches relacionados"
+msgid "Failed to load sidebar confidential toggle"
+msgstr ""
+
+msgid "Failed to load sidebar lock status"
+msgstr ""
+
msgid "Failed to load stacktrace."
msgstr "Falha ao carregar a stacktrace."
@@ -10483,6 +10802,9 @@ msgstr ""
msgid "Failed to publish issue on status page."
msgstr ""
+msgid "Failed to remove To-Do for the design."
+msgstr ""
+
msgid "Failed to remove a Zoom meeting"
msgstr ""
@@ -10525,6 +10847,9 @@ msgstr ""
msgid "Failed to signing using smartcard authentication"
msgstr "Falha ao entrar usando a autenticação de cartão inteligente"
+msgid "Failed to toggle To-Do for the design."
+msgstr ""
+
msgid "Failed to update branch!"
msgstr "Falha ao atualizar o branch!"
@@ -10638,7 +10963,7 @@ msgstr "Editar feature flag"
msgid "FeatureFlags|Edit User List"
msgstr ""
-msgid "FeatureFlags|Enable features for specific users and specific environments by defining feature flag strategies."
+msgid "FeatureFlags|Enable features for specific users and environments by configuring feature flag strategies."
msgstr ""
msgid "FeatureFlags|Environment Spec"
@@ -10698,8 +11023,8 @@ msgstr "Sinalizador inativo para %{scope}"
msgid "FeatureFlags|Include additional user IDs"
msgstr ""
-msgid "FeatureFlags|Install a %{docs_link_anchored_start}compatible client library%{docs_link_anchored_end} and specify the API URL, application name, and instance ID during the configuration setup. %{docs_link_start}More Information%{docs_link_end}"
-msgstr "Instale uma %{docs_link_anchored_start}biblioteca de cliente compatível%{docs_link_anchored_end} e especifique o URL da API, o nome do aplicativo e o ID da instância durante a configuração. %{docs_link_start}Mais informações%{docs_link_end}"
+msgid "FeatureFlags|Install a %{docsLinkAnchoredStart}compatible client library%{docsLinkAnchoredEnd} and specify the API URL, application name, and instance ID during the configuration setup. %{docsLinkStart}More Information%{docsLinkEnd}"
+msgstr ""
msgid "FeatureFlags|Instance ID"
msgstr "ID da instância"
@@ -10710,6 +11035,9 @@ msgstr ""
msgid "FeatureFlags|Loading feature flags"
msgstr "Carregando feature flags"
+msgid "FeatureFlags|Loading user lists"
+msgstr ""
+
msgid "FeatureFlags|More information"
msgstr "Mais informações"
@@ -10728,7 +11056,7 @@ msgstr ""
msgid "FeatureFlags|New feature flag"
msgstr "Nova feature flag"
-msgid "FeatureFlags|New list"
+msgid "FeatureFlags|New user list"
msgstr ""
msgid "FeatureFlags|Percent of users"
@@ -10767,6 +11095,9 @@ msgstr "Ambientes alvo"
msgid "FeatureFlags|There was an error fetching the feature flags."
msgstr "Ocorreu um erro ao buscar as feature flag."
+msgid "FeatureFlags|There was an error fetching the user lists."
+msgstr ""
+
msgid "FeatureFlags|There was an error retrieving user lists"
msgstr ""
@@ -10782,6 +11113,9 @@ msgstr ""
msgid "FeatureFlags|User List"
msgstr ""
+msgid "FeatureFlags|User Lists"
+msgstr ""
+
msgid "FeatureFlag|List"
msgstr ""
@@ -10809,15 +11143,6 @@ msgstr "Fevereiro"
msgid "Fetching incoming email"
msgstr "Obtendo e-mails recebidos"
-msgid "Fetching licenses failed."
-msgstr "A obtenção das licenças falhou."
-
-msgid "Fetching licenses failed. The request endpoint was not found."
-msgstr "A obtenção de licenças falhou. O endpoint da requisição não foi encontrado."
-
-msgid "Fetching licenses failed. You are not permitted to perform this action."
-msgstr "A obtenção das licenças falhou. Você não tem permissão para executar esta ação."
-
msgid "File"
msgstr ""
@@ -10920,12 +11245,21 @@ msgstr ""
msgid "Filter by status"
msgstr ""
+msgid "Filter by test cases that are currently archived."
+msgstr ""
+
+msgid "Filter by test cases that are currently opened."
+msgstr ""
+
msgid "Filter by two-factor authentication"
msgstr "Filtrar por autenticação de dois fatores"
msgid "Filter by user"
msgstr ""
+msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
+msgstr ""
+
msgid "Filter pipelines"
msgstr ""
@@ -10941,8 +11275,8 @@ msgstr "Filtrar resultados por projeto"
msgid "Filter results..."
msgstr ""
-msgid "Filter your projects by name"
-msgstr "Filtre seus projetos por nome"
+msgid "Filter your repositories by name"
+msgstr ""
msgid "Filter..."
msgstr "Filtro..."
@@ -10950,7 +11284,7 @@ msgstr "Filtro..."
msgid "Find File"
msgstr ""
-msgid "Find bugs in your code with coverage-guided fuzzing"
+msgid "Find bugs in your code with coverage-guided fuzzing."
msgstr ""
msgid "Find by path"
@@ -10977,9 +11311,6 @@ msgstr "Impressões digitais"
msgid "Finish editing this message first!"
msgstr "Conclua a edição desta mensagem primeiro!"
-msgid "Finish review"
-msgstr "Concluir a revisão"
-
msgid "Finish setting up your dedicated account for %{group_name}."
msgstr ""
@@ -11049,6 +11380,9 @@ msgstr "Cor da Fonte"
msgid "Footer message"
msgstr "Mensagem do Rodapé"
+msgid "For a faster browsing experience, some files are collapsed by default."
+msgstr ""
+
msgid "For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
@@ -11058,6 +11392,9 @@ msgstr "Para projetos internos, qualquer usuário conectado pode visualizar pipe
msgid "For more info, read the documentation."
msgstr "Para mais informações, leia a documentação."
+msgid "For more information on how the number of active users is calculated, see the %{self_managed_subscriptions_doc_link} documentation."
+msgstr ""
+
msgid "For more information, go to the "
msgstr "Para mais informações, vá para o "
@@ -11196,6 +11533,9 @@ msgstr ""
msgid "Generate new token"
msgstr ""
+msgid "Generic package file size in bytes"
+msgstr ""
+
msgid "Geo"
msgstr "Geo"
@@ -11457,6 +11797,9 @@ msgstr "Verificação pendente"
msgid "Geo|Please refer to Geo Troubleshooting."
msgstr ""
+msgid "Geo|Primary node"
+msgstr ""
+
msgid "Geo|Project"
msgstr "Projeto"
@@ -11499,6 +11842,9 @@ msgstr ""
msgid "Geo|Review replication status, and resynchronize and reverify items with the primary node."
msgstr ""
+msgid "Geo|Secondary node"
+msgstr ""
+
msgid "Geo|Status"
msgstr "Status"
@@ -11538,6 +11884,9 @@ msgstr ""
msgid "Geo|URL must be a valid url (ex: https://gitlab.com)"
msgstr ""
+msgid "Geo|Undefined"
+msgstr ""
+
msgid "Geo|Unknown state"
msgstr "Estado desconhecido"
@@ -11613,11 +11962,17 @@ msgstr ""
msgid "GitHub import"
msgstr "Importação do GitHub"
+msgid "GitLab"
+msgstr ""
+
msgid "GitLab / Unsubscribe"
msgstr ""
-msgid "GitLab Enterprise Edition %{plan}"
-msgstr "GitLab Enterprise Edition %{plan}"
+msgid "GitLab API"
+msgstr ""
+
+msgid "GitLab Billing Team."
+msgstr ""
msgid "GitLab Group Runners can execute code for all the projects in this group."
msgstr "Os GitLab Group Runners podem executar código para todos os projetos neste grupo."
@@ -11628,12 +11983,18 @@ msgstr "Importação do GitLab"
msgid "GitLab Issue"
msgstr ""
+msgid "GitLab Pages"
+msgstr ""
+
msgid "GitLab Service Desk is a simple way to allow people to create issues in your GitLab instance without needing their own user account. It provides a unique email address for end users to create issues in a project, and replies can be sent either through the GitLab interface or by email. End users will only see the thread through email."
msgstr ""
msgid "GitLab Shared Runners execute code of different projects on the same Runner unless you configure GitLab Runner Autoscale with MaxBuilds 1 (which it is on GitLab.com)."
msgstr "GitLab Shared Runners executam códigos de projetos diferentes no mesmo Runner, a menos que você configure o GitLab Runner Autoscale com o MaxBuilds 1 (que está no GitLab.com)."
+msgid "GitLab Shell"
+msgstr ""
+
msgid "GitLab Support Bot"
msgstr ""
@@ -11643,8 +12004,8 @@ msgstr ""
msgid "GitLab User"
msgstr "Usuário GitLab"
-msgid "GitLab allows you to continue using your license even if you exceed the number of seats you purchased. You will be required to pay for these seats when you renew your license."
-msgstr "GitLab permite que você continue usando a sua licença mesmo se exceder o número de lugares que você comprou. Você será obrigado a pagar por esses lugares no momento da renovação de sua licença."
+msgid "GitLab Workhorse"
+msgstr ""
msgid "GitLab commit"
msgstr ""
@@ -11811,6 +12172,21 @@ msgstr "Importação do Gitea"
msgid "Gitlab Pages"
msgstr "GitLab Pages"
+msgid "Gitpod"
+msgstr ""
+
+msgid "Gitpod|Add the URL to your Gitpod instance configured to read your GitLab projects."
+msgstr ""
+
+msgid "Gitpod|Enable Gitpod integration"
+msgstr ""
+
+msgid "Gitpod|Gitpod URL"
+msgstr ""
+
+msgid "Gitpod|e.g. https://gitpod.example.com"
+msgstr ""
+
msgid "Given access %{time_ago}"
msgstr "Acesso concedido %{time_ago}"
@@ -12318,9 +12694,6 @@ msgstr ""
msgid "GroupSAML|Valid SAML Response"
msgstr ""
-msgid "GroupSAML|With group managed accounts enabled, all the users without a group managed account will be excluded from the group."
-msgstr ""
-
msgid "GroupSAML|With prohibit outer forks flag enabled group members will be able to fork project only inside your group."
msgstr ""
@@ -12534,10 +12907,10 @@ msgstr ""
msgid "GroupsNew|Create group"
msgstr ""
-msgid "GroupsNew|GitLab group export"
+msgid "GroupsNew|Import"
msgstr ""
-msgid "GroupsNew|Import"
+msgid "GroupsNew|Import a GitLab group export file"
msgstr ""
msgid "GroupsNew|Import group"
@@ -12680,6 +13053,9 @@ msgid_plural "Hide charts"
msgstr[0] ""
msgstr[1] ""
+msgid "Hide comments on this file"
+msgstr ""
+
msgid "Hide details"
msgstr ""
@@ -12724,6 +13100,15 @@ msgstr ""
msgid "Highest role:"
msgstr ""
+msgid "HighlightBar|Alert events:"
+msgstr ""
+
+msgid "HighlightBar|Alert start time:"
+msgstr ""
+
+msgid "HighlightBar|Original alert:"
+msgstr ""
+
msgid "History"
msgstr "Histórico"
@@ -12901,6 +13286,9 @@ msgstr ""
msgid "If enabled, access to projects will be validated on an external service using their classification label."
msgstr "Se ativado, o acesso aos projetos será validado em um serviço externo usando sua etiqueta de classificação."
+msgid "If the number of active users exceeds the user limit, you will be charged for the number of %{users_over_license_link} at your next license reconciliation."
+msgstr ""
+
msgid "If there is no previous license or if the previous license has expired, some GitLab functionality will be blocked until a new, valid license is uploaded."
msgstr ""
@@ -12940,9 +13328,6 @@ msgstr ""
msgid "If your HTTP repository is not publicly accessible, add your credentials."
msgstr ""
-msgid "Iglu registry URL (optional)"
-msgstr ""
-
msgid "Ignore"
msgstr ""
@@ -12979,6 +13364,16 @@ msgstr ""
msgid "Import"
msgstr "Importar"
+msgid "Import %d compatible repository"
+msgid_plural "Import %d compatible repositories"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Import %d repository"
+msgid_plural "Import %d repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Import CSV"
msgstr "Importar CSV"
@@ -12988,15 +13383,9 @@ msgstr "Importar projetos do Gitea"
msgid "Import all compatible projects"
msgstr "Importar todos os projetos compatíveis"
-msgid "Import all compatible repositories"
-msgstr ""
-
msgid "Import all projects"
msgstr "Importar todos os projetos"
-msgid "Import all repositories"
-msgstr "Importar todos repositórios"
-
msgid "Import an exported GitLab project"
msgstr "Importar um projeto GitLab exportado"
@@ -13084,6 +13473,9 @@ msgstr ""
msgid "ImportProjects|Error importing repository %{project_safe_import_url} into %{project_full_path} - %{message}"
msgstr ""
+msgid "ImportProjects|Import repositories"
+msgstr ""
+
msgid "ImportProjects|Importing the project failed"
msgstr "Falha ao importar o projeto"
@@ -13096,8 +13488,8 @@ msgstr ""
msgid "ImportProjects|Requesting your %{provider} repositories failed"
msgstr "Falha ao solicitar seus repositórios do %{provider}"
-msgid "ImportProjects|Select the projects you want to import"
-msgstr "Selecione os projetos que você deseja importar"
+msgid "ImportProjects|Select the repositories you want to import"
+msgstr ""
msgid "ImportProjects|The remote data could not be imported."
msgstr ""
@@ -13132,9 +13524,6 @@ msgstr ""
msgid "In order to enable Service Desk for your instance, you must first set up incoming email."
msgstr ""
-msgid "In order to gather accurate feature usage data, it can take 1 to 2 weeks to see your index."
-msgstr ""
-
msgid "In order to personalize your experience with GitLab%{br_tag}we would like to know a bit more about you."
msgstr ""
@@ -13165,18 +13554,30 @@ msgstr ""
msgid "IncidentManagement|Create incident"
msgstr ""
+msgid "IncidentManagement|Critical - S1"
+msgstr ""
+
msgid "IncidentManagement|Date created"
msgstr ""
msgid "IncidentManagement|Display your incidents in a dedicated view"
msgstr ""
+msgid "IncidentManagement|High - S2"
+msgstr ""
+
msgid "IncidentManagement|Incident"
msgstr ""
msgid "IncidentManagement|Incidents"
msgstr ""
+msgid "IncidentManagement|Low - S4"
+msgstr ""
+
+msgid "IncidentManagement|Medium - S3"
+msgstr ""
+
msgid "IncidentManagement|No incidents to display."
msgstr ""
@@ -13189,6 +13590,9 @@ msgstr ""
msgid "IncidentManagement|Published to status page"
msgstr ""
+msgid "IncidentManagement|Severity"
+msgstr ""
+
msgid "IncidentManagement|There are no closed incidents"
msgstr ""
@@ -13198,6 +13602,9 @@ msgstr ""
msgid "IncidentManagement|Unassigned"
msgstr ""
+msgid "IncidentManagement|Unknown"
+msgstr ""
+
msgid "IncidentManagement|Unpublished"
msgstr ""
@@ -13219,6 +13626,15 @@ msgstr ""
msgid "Incidents"
msgstr "Incidentes"
+msgid "Incident|Alert details"
+msgstr ""
+
+msgid "Incident|Summary"
+msgstr ""
+
+msgid "Incident|There was an issue loading alert data. Please try again."
+msgstr ""
+
msgid "Include a Terms of Service agreement and Privacy Policy that all users must accept."
msgstr "Inclua um contrato de Termos de Serviço e uma Política de Privacidade que todos os usuários devem aceitar."
@@ -13279,6 +13695,9 @@ msgstr "Informar aos usuários sem chaves SSH configuradas que eles não podem r
msgid "Information about additional Pages templates and how to install them can be found in our %{pages_getting_started_guide}."
msgstr "Informações sobre modelos adicionais de Páginas e como instalá-los podem ser encontradas em nosso %{pages_getting_started_guide}."
+msgid "Inherited"
+msgstr ""
+
msgid "Inherited:"
msgstr ""
@@ -13359,8 +13778,23 @@ msgstr ""
msgid "Instance administrators group already exists"
msgstr "O grupo de administradores da instância já existe"
-msgid "Instance license"
-msgstr "Licença da instância"
+msgid "InstanceStatistics|Groups"
+msgstr ""
+
+msgid "InstanceStatistics|Issues"
+msgstr ""
+
+msgid "InstanceStatistics|Merge Requests"
+msgstr ""
+
+msgid "InstanceStatistics|Pipelines"
+msgstr ""
+
+msgid "InstanceStatistics|Projects"
+msgstr ""
+
+msgid "InstanceStatistics|Users"
+msgstr ""
msgid "Integration"
msgstr ""
@@ -13371,6 +13805,12 @@ msgstr ""
msgid "Integrations"
msgstr "Integrações"
+msgid "Integrations|%{integration} settings saved and active."
+msgstr ""
+
+msgid "Integrations|%{integration} settings saved, but not active."
+msgstr ""
+
msgid "Integrations|All details"
msgstr ""
@@ -13380,6 +13820,12 @@ msgstr ""
msgid "Integrations|Comment settings:"
msgstr ""
+msgid "Integrations|Connection failed. Please check your settings."
+msgstr ""
+
+msgid "Integrations|Connection successful."
+msgstr ""
+
msgid "Integrations|Default settings are inherited from the group level."
msgstr ""
@@ -13395,6 +13841,15 @@ msgstr ""
msgid "Integrations|Includes commit title and branch"
msgstr ""
+msgid "Integrations|Projects using custom settings will not be impacted unless the project owner chooses to use instance-level defaults."
+msgstr ""
+
+msgid "Integrations|Save settings?"
+msgstr ""
+
+msgid "Integrations|Saving will update the default settings for all projects that are not using custom settings."
+msgstr ""
+
msgid "Integrations|Standard"
msgstr ""
@@ -13527,6 +13982,9 @@ msgstr ""
msgid "Invitation"
msgstr "Convite"
+msgid "Invitation declined"
+msgstr ""
+
msgid "Invite"
msgstr "Convidar"
@@ -13578,6 +14036,42 @@ 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|%{linkStart}Read more%{linkEnd} about role permissions"
+msgstr ""
+
+msgid "InviteMembersModal|Access expiration date (optional)"
+msgstr ""
+
+msgid "InviteMembersModal|Cancel"
+msgstr ""
+
+msgid "InviteMembersModal|Choose a role permission"
+msgstr ""
+
+msgid "InviteMembersModal|GitLab member or Email address"
+msgstr ""
+
+msgid "InviteMembersModal|Invite"
+msgstr ""
+
+msgid "InviteMembersModal|Invite team members"
+msgstr ""
+
+msgid "InviteMembersModal|Search for members to invite"
+msgstr ""
+
+msgid "InviteMembersModal|User not invited. Feature coming soon!"
+msgstr ""
+
+msgid "InviteMembersModal|Users were succesfully added"
+msgstr ""
+
+msgid "InviteMembersModal|You're inviting members to the %{group_name} group"
+msgstr ""
+
+msgid "InviteMembers|Invite team members"
+msgstr ""
+
msgid "Invited"
msgstr ""
@@ -13632,10 +14126,13 @@ msgstr ""
msgid "Issue cannot be found."
msgstr ""
+msgid "Issue created from vulnerability %{vulnerability_link}"
+msgstr ""
+
msgid "Issue events"
msgstr "Eventos de issue"
-msgid "Issue first depoloyed to production"
+msgid "Issue first deployed to production"
msgstr ""
msgid "Issue label"
@@ -13713,6 +14210,9 @@ msgstr ""
msgid "IssueTracker|Custom issue tracker"
msgstr ""
+msgid "IssueTracker|EWM work items tracker"
+msgstr ""
+
msgid "IssueTracker|Redmine issue tracker"
msgstr ""
@@ -13779,6 +14279,9 @@ msgstr ""
msgid "It looks like you have some draft commits in this branch."
msgstr ""
+msgid "It may be several days before you see feature usage data."
+msgstr ""
+
msgid "It must have a header row and at least two columns: the first column is the issue title and the second column is the issue description. The separator is automatically detected."
msgstr "Deve ter uma linha de cabeçalho e pelo menos duas colunas: a primeira coluna é o título da issue e a segunda coluna é a descrição da issue. O separador é detectado automaticamente."
@@ -14061,15 +14564,15 @@ msgstr "com"
msgid "Join Zoom meeting"
msgstr "Participe da reunião com Zoom"
+msgid "Joined %{time_ago}"
+msgstr ""
+
msgid "Jul"
msgstr "Jul"
msgid "July"
msgstr "Julho"
-msgid "Jump to first unresolved thread"
-msgstr ""
-
msgid "Jump to next unresolved thread"
msgstr ""
@@ -14103,6 +14606,9 @@ msgstr "Chave: %{key}"
msgid "Keyboard shortcuts"
msgstr ""
+msgid "KeyboardKey|Ctrl+"
+msgstr ""
+
msgid "Keys"
msgstr ""
@@ -14151,6 +14657,9 @@ msgstr ""
msgid "LDAP Synchronization"
msgstr ""
+msgid "LDAP group settings"
+msgstr ""
+
msgid "LDAP settings"
msgstr "Configurações LDAP"
@@ -14160,6 +14669,9 @@ msgstr ""
msgid "LDAP sync in progress. This could take a few minutes. Refresh the page to see the changes."
msgstr ""
+msgid "LDAP synchronizations"
+msgstr ""
+
msgid "LFS"
msgstr "LFS"
@@ -14240,8 +14752,17 @@ msgid_plural "Last %d days"
msgstr[0] "Último %d dia"
msgstr[1] "Últimos %d dias"
-msgid "Last %{days} days"
-msgstr "Últimos %{days} dias"
+msgid "Last 2 weeks"
+msgstr ""
+
+msgid "Last 30 days"
+msgstr ""
+
+msgid "Last 60 days"
+msgstr ""
+
+msgid "Last 90 days"
+msgstr ""
msgid "Last Accessed On"
msgstr ""
@@ -14318,6 +14839,9 @@ msgstr "Usado pela última vez"
msgid "Last used on:"
msgstr "Última utilização em:"
+msgid "Last week"
+msgstr ""
+
msgid "LastCommit|authored"
msgstr ""
@@ -14333,6 +14857,9 @@ msgstr "Últimas modificações"
msgid "Latest pipeline for the most recent commit on this branch"
msgstr ""
+msgid "Launch a ready-to-code development environment for your project."
+msgstr ""
+
msgid "Lead"
msgstr ""
@@ -14713,6 +15240,9 @@ msgstr "Listar repositórios disponíveis"
msgid "List of all merge commits"
msgstr ""
+msgid "List options"
+msgstr ""
+
msgid "List settings"
msgstr ""
@@ -14725,9 +15255,6 @@ msgstr "Exibir em lista"
msgid "List your Bitbucket Server repositories"
msgstr "Liste seus repositórios do servidor Bitbucket"
-msgid "Lists"
-msgstr ""
-
msgid "Live preview"
msgstr "Pré-visualização ao vivo"
@@ -14974,6 +15501,12 @@ msgstr ""
msgid "Mark as done"
msgstr ""
+msgid "Mark as draft"
+msgstr ""
+
+msgid "Mark as ready"
+msgstr ""
+
msgid "Mark as resolved"
msgstr ""
@@ -14995,6 +15528,24 @@ msgstr "Markdown habilitado"
msgid "Markdown is supported"
msgstr ""
+msgid "MarkdownEditor|Add a link (%{modifierKey}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add a link (%{modifier_key}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifierKey}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifier_key}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifierKey}I)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifier_key}I)"
+msgstr ""
+
msgid "Marked For Deletion At - %{deletion_time}"
msgstr ""
@@ -15079,7 +15630,25 @@ msgstr ""
msgid "Max access level"
msgstr "Nível máximo de acesso"
-msgid "Max seats used"
+msgid "Max role"
+msgstr ""
+
+msgid "Max size 15 MB"
+msgstr ""
+
+msgid "Maximum Conan package file size in bytes"
+msgstr ""
+
+msgid "Maximum Maven package file size in bytes"
+msgstr ""
+
+msgid "Maximum NPM package file size in bytes"
+msgstr ""
+
+msgid "Maximum NuGet package file size in bytes"
+msgstr ""
+
+msgid "Maximum PyPI package file size in bytes"
msgstr ""
msgid "Maximum Users:"
@@ -15211,6 +15780,18 @@ msgstr ""
msgid "Members with access to %{strong_start}%{group_name}%{strong_end}"
msgstr ""
+msgid "Members|%{time} by %{user}"
+msgstr ""
+
+msgid "Members|Expired"
+msgstr ""
+
+msgid "Members|No expiration set"
+msgstr ""
+
+msgid "Members|in %{time}"
+msgstr ""
+
msgid "Memory Usage"
msgstr ""
@@ -15397,9 +15978,6 @@ msgstr ""
msgid "MergeRequests|Thread will be unresolved"
msgstr ""
-msgid "MergeRequests|Toggle comments for this file"
-msgstr "Ativar/desativar comentários para este arquivo"
-
msgid "MergeRequests|View file @ %{commitId}"
msgstr "Visualizar o arquivo @ %{commitId}"
@@ -15460,6 +16038,9 @@ msgstr ""
msgid "Merging immediately isn't recommended as it may negatively impact the existing merge train. Read the %{docsLinkStart}documentation%{docsLinkEnd} for more information."
msgstr ""
+msgid "Message"
+msgstr ""
+
msgid "Messages"
msgstr "Mensagens"
@@ -15845,18 +16426,12 @@ msgid_plural "Milestones"
msgstr[0] ""
msgstr[1] ""
-msgid "Milestone does not support burnup charts"
-msgstr ""
-
msgid "Milestone lists not available with your current license"
msgstr "Listas de marcos não estão disponíveis para a sua licença atual"
msgid "Milestone lists show all issues from the selected milestone."
msgstr "As listas de marcos mostram todas as issues do marco selecionado."
-msgid "Milestone must have a start and due date"
-msgstr ""
-
msgid "MilestoneSidebar|Closed:"
msgstr ""
@@ -16223,6 +16798,9 @@ msgstr "Nome:"
msgid "Namespace"
msgstr ""
+msgid "Namespace ID:"
+msgstr ""
+
msgid "Namespace is empty"
msgstr ""
@@ -16307,6 +16885,9 @@ msgstr ""
msgid "NetworkPolicies|Allow all outbound traffic from %{selector} to %{ruleSelector} on %{ports}"
msgstr ""
+msgid "NetworkPolicies|Are you sure you want to delete this policy? This action cannot be undone."
+msgstr ""
+
msgid "NetworkPolicies|Choose whether to enforce this policy."
msgstr ""
@@ -16316,12 +16897,21 @@ msgstr ""
msgid "NetworkPolicies|Define this policy's location, conditions and actions."
msgstr ""
+msgid "NetworkPolicies|Delete policy"
+msgstr ""
+
+msgid "NetworkPolicies|Delete policy: %{policy}"
+msgstr ""
+
msgid "NetworkPolicies|Deny all traffic"
msgstr ""
msgid "NetworkPolicies|Description"
msgstr ""
+msgid "NetworkPolicies|Edit policy"
+msgstr ""
+
msgid "NetworkPolicies|Editor mode"
msgstr ""
@@ -16349,6 +16939,9 @@ msgstr ""
msgid "NetworkPolicies|Name"
msgstr ""
+msgid "NetworkPolicies|Namespace"
+msgstr ""
+
msgid "NetworkPolicies|Network Policy"
msgstr ""
@@ -16400,6 +16993,9 @@ msgstr ""
msgid "NetworkPolicies|Rules"
msgstr ""
+msgid "NetworkPolicies|Save changes"
+msgstr ""
+
msgid "NetworkPolicies|Something went wrong, failed to update policy"
msgstr ""
@@ -16412,6 +17008,9 @@ msgstr ""
msgid "NetworkPolicies|Traffic that does not match any rule will be blocked."
msgstr ""
+msgid "NetworkPolicies|Unable to parse policy"
+msgstr ""
+
msgid "NetworkPolicies|YAML editor"
msgstr ""
@@ -16525,6 +17124,9 @@ msgstr ""
msgid "New Snippet"
msgstr "Novo Snippet"
+msgid "New Test Case"
+msgstr ""
+
msgid "New User"
msgstr ""
@@ -16624,6 +17226,9 @@ msgstr "Novo subgrupo"
msgid "New tag"
msgstr "Nova tag"
+msgid "New test case"
+msgstr ""
+
msgid "New users set to external"
msgstr ""
@@ -16696,7 +17301,7 @@ msgstr "Nenhuma branch encontrada"
msgid "No changes"
msgstr "Sem alterarções"
-msgid "No changes between %{ref_start}%{source_branch}%{ref_end} and %{ref_start}%{target_branch}%{ref_end}"
+msgid "No changes between %{sourceBranch} and %{targetBranch}"
msgstr ""
msgid "No child epics match applied filters"
@@ -16711,6 +17316,9 @@ msgstr "Nenhuma conexão pode ser feita para um servidor Gitaly, por favor check
msgid "No containers available"
msgstr ""
+msgid "No content to show"
+msgstr ""
+
msgid "No contributions"
msgstr ""
@@ -16786,9 +17394,6 @@ msgstr "Sem etiquetas com esse nome ou descrição"
msgid "No license. All rights reserved"
msgstr "Nenhuma licença. Todos os direitos reservados"
-msgid "No licenses found."
-msgstr ""
-
msgid "No matches found"
msgstr ""
@@ -16801,6 +17406,9 @@ msgstr "Nenhum resultado correspondente"
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No members found"
+msgstr ""
+
msgid "No merge requests found"
msgstr "Nenhum merge requests encontrado"
@@ -16822,6 +17430,9 @@ msgstr ""
msgid "No parent group"
msgstr ""
+msgid "No plan"
+msgstr ""
+
msgid "No pods available"
msgstr ""
@@ -16918,6 +17529,12 @@ msgstr "Nenhum"
msgid "Not Implemented"
msgstr ""
+msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+msgstr ""
+
+msgid "Not all browsers support WebAuthn. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even from an unsupported browser."
+msgstr ""
+
msgid "Not all data has been processed yet, the accuracy of the chart for the selected timeframe is limited."
msgstr ""
@@ -17014,6 +17631,9 @@ msgstr "Configuração de notificação - %{notification_title}"
msgid "Notification settings saved"
msgstr ""
+msgid "NotificationEvent|Change reviewer merge request"
+msgstr ""
+
msgid "NotificationEvent|Close issue"
msgstr "Fechar issue"
@@ -17176,10 +17796,7 @@ msgstr ""
msgid "On track"
msgstr ""
-msgid "OnDemandScans|Attached branch"
-msgstr ""
-
-msgid "OnDemandScans|Attached branch is where the scan job runs."
+msgid "OnDemandScans|Could not fetch scanner profiles. Please refresh the page, or try again later."
msgstr ""
msgid "OnDemandScans|Could not fetch site profiles. Please refresh the page, or try again later."
@@ -17188,6 +17805,9 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
+msgid "OnDemandScans|Create a new scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Create a new site profile"
msgstr ""
@@ -17200,6 +17820,9 @@ msgstr ""
msgid "OnDemandScans|New on-demand DAST scan"
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 ""
@@ -17209,16 +17832,10 @@ msgstr ""
msgid "OnDemandScans|On-demand scans run outside the DevOps cycle and find vulnerabilities in your projects. %{learnMoreLinkStart}Learn more%{learnMoreLinkEnd}"
msgstr ""
-msgid "OnDemandScans|Only a passive scan can be performed on demand."
-msgstr ""
-
-msgid "OnDemandScans|Passive"
-msgstr ""
-
msgid "OnDemandScans|Run scan"
msgstr ""
-msgid "OnDemandScans|Scan mode"
+msgid "OnDemandScans|Scanner profile"
msgstr ""
msgid "OnDemandScans|Scanner settings"
@@ -17230,9 +17847,15 @@ msgstr ""
msgid "OnDemandScans|Select one of the existing profiles"
msgstr ""
+msgid "OnDemandScans|Site profile"
+msgstr ""
+
msgid "OnDemandScans|Site profiles"
msgstr ""
+msgid "OnDemandScans|Use existing scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Use existing site profile"
msgstr ""
@@ -17331,9 +17954,6 @@ msgstr "Abrir"
msgid "Open Selection"
msgstr ""
-msgid "Open Web IDE"
-msgstr ""
-
msgid "Open comment type dropdown"
msgstr ""
@@ -17439,6 +18059,9 @@ msgstr "Ou você pode escolher uma das cores sugeridas abaixo"
msgid "Origin"
msgstr ""
+msgid "Orphaned member"
+msgstr ""
+
msgid "Other Labels"
msgstr "Outras etiquetas"
@@ -17454,6 +18077,9 @@ msgstr ""
msgid "Other visibility settings have been disabled by the administrator."
msgstr ""
+msgid "Our documentation includes an example DevOps Score report."
+msgstr ""
+
msgid "Out-of-compliance with this project's policies and should be removed"
msgstr ""
@@ -17478,6 +18104,9 @@ msgstr "Visão geral"
msgid "Overwrite diverged branches"
msgstr "Substituir branches divergentes"
+msgid "Owned by %{image_tag}"
+msgstr ""
+
msgid "Owned by anyone"
msgstr "Possuído por qualquer pessoa"
@@ -17499,6 +18128,9 @@ msgstr ""
msgid "Package deleted successfully"
msgstr ""
+msgid "Package file size limits"
+msgstr ""
+
msgid "Package recipe already exists"
msgstr ""
@@ -17514,9 +18146,6 @@ msgstr ""
msgid "Package type must be PyPi"
msgstr ""
-msgid "Package was removed"
-msgstr "O pacote foi removido"
-
msgid "PackageRegistry|%{name} version %{version} was created %{datetime}"
msgstr ""
@@ -17658,12 +18287,18 @@ msgstr ""
msgid "PackageRegistry|NuGet Command"
msgstr ""
+msgid "PackageRegistry|Package Registry"
+msgstr ""
+
msgid "PackageRegistry|Pip Command"
msgstr ""
msgid "PackageRegistry|Pipeline %{link} triggered %{datetime} by %{author}"
msgstr ""
+msgid "PackageRegistry|Publish and share packages for a variety of common package managers. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "PackageRegistry|Published to the %{project} Package Registry %{datetime}"
msgstr ""
@@ -17763,6 +18398,9 @@ msgstr ""
msgid "Page not found"
msgstr "Página não encontrada"
+msgid "Page settings"
+msgstr ""
+
msgid "Page was successfully deleted"
msgstr "Página excluída com sucesso"
@@ -17904,7 +18542,7 @@ msgstr "Colar link de épico"
msgid "Paste issue link"
msgstr "Colar link de issue"
-msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Don't use your private SSH key."
+msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Do not paste your private SSH key, as that can compromise your identity."
msgstr ""
msgid "Patch to apply"
@@ -17931,6 +18569,9 @@ msgstr "Runners pausados não aceitam novas tarefas"
msgid "Pending"
msgstr "Pendente"
+msgid "Pending comments"
+msgstr ""
+
msgid "People without permission will never get a notification and won't be able to comment."
msgstr "Pessoas sem permissão nunca receberão uma notificação e não serão capazes de comentar."
@@ -18129,6 +18770,9 @@ msgstr ""
msgid "Pipelines|Build with confidence"
msgstr "Construa com confiança"
+msgid "Pipelines|By revoking a trigger you will break any processes making use of it. Are you sure?"
+msgstr ""
+
msgid "Pipelines|CI Lint"
msgstr "CI Lint"
@@ -18141,6 +18785,15 @@ msgstr "Limpar cache dos Runners"
msgid "Pipelines|Continuous Integration can help catch bugs by running your tests automatically, while Continuous Deployment can help you deliver code to your product environment."
msgstr "A integração contínua pode ajudar a capturar bugs, executando seus testes automaticamente enquanto a entrega contínua pode ajudá-lo a fornecer o código para o seu ambiente de produto."
+msgid "Pipelines|Copy trigger token"
+msgstr ""
+
+msgid "Pipelines|Description"
+msgstr ""
+
+msgid "Pipelines|Edit"
+msgstr ""
+
msgid "Pipelines|Get started with Pipelines"
msgstr "Saiba como funcionam as pipelines"
@@ -18156,15 +18809,27 @@ msgstr ""
msgid "Pipelines|It is recommended the code is reviewed thoroughly before running this pipeline with the parent project's CI resource."
msgstr ""
+msgid "Pipelines|Last Used"
+msgstr ""
+
msgid "Pipelines|Loading Pipelines"
msgstr "Carregando Pipelines"
msgid "Pipelines|More Information"
msgstr ""
+msgid "Pipelines|No triggers have been created yet. Add one using the form above."
+msgstr ""
+
+msgid "Pipelines|Owner"
+msgstr ""
+
msgid "Pipelines|Project cache successfully reset."
msgstr "Cache do projeto redefinido com sucesso."
+msgid "Pipelines|Revoke"
+msgstr ""
+
msgid "Pipelines|Run Pipeline"
msgstr "Executar Pipeline"
@@ -18189,6 +18854,15 @@ msgstr ""
msgid "Pipelines|This project is not currently set up to run pipelines."
msgstr "Este projeto não está atualmente configurado para executar pipelines."
+msgid "Pipelines|Token"
+msgstr ""
+
+msgid "Pipelines|Trigger user has insufficient permissions to project"
+msgstr ""
+
+msgid "Pipelines|invalid"
+msgstr ""
+
msgid "Pipelines|parent"
msgstr ""
@@ -18447,10 +19121,10 @@ msgstr ""
msgid "Please provide attributes to update"
msgstr ""
-msgid "Please refer to %{docs_url}"
+msgid "Please reach out if you have any questions and we'll be happy to assist."
msgstr ""
-msgid "Please retype the email address."
+msgid "Please refer to %{docs_url}"
msgstr ""
msgid "Please select"
@@ -18480,6 +19154,9 @@ msgstr "Por favor selecione pelo menos um filtro para ver os resultados"
msgid "Please set a new password before proceeding."
msgstr "Defina uma nova senha antes de continuar."
+msgid "Please share your feedback about %{featureName} %{linkStart}in this issue%{linkEnd} to help us improve the experience."
+msgstr ""
+
msgid "Please solve the reCAPTCHA"
msgstr "Por favor, resolva o reCAPTCHA"
@@ -18783,6 +19460,9 @@ msgstr "Você está prestes a excluir permanentemente a %{yourAccount}, e todas
msgid "Profiles| You are going to change the username %{currentUsernameBold} to %{newUsernameBold}. Profile and projects will be redirected to the %{newUsername} namespace but this redirect will expire once the %{currentUsername} namespace is registered by another user or group. Please update your Git repository remotes as soon as possible."
msgstr "Você vai alterar o nome de usuário %{currentUsernameBold} para %{newUsernameBold}. O perfil e os projetos serão redirecionados para %{newUsername} mas esse redirecionamento expirará quando %{currentUsername} for registrado por outro usuário ou grupo. Por favor, atualize seus repositórios remotos Git o mais rápido possível."
+msgid "Profiles|%{provider} Active"
+msgstr ""
+
msgid "Profiles|@username"
msgstr "@nomedeusuário"
@@ -18834,8 +19514,8 @@ msgstr "Clique no ícone para ativar o login com um dos seguintes serviços"
msgid "Profiles|Commit email"
msgstr ""
-msgid "Profiles|Connect"
-msgstr "Conectar"
+msgid "Profiles|Connect %{provider}"
+msgstr ""
msgid "Profiles|Connected Accounts"
msgstr "Contas conectadas"
@@ -18858,6 +19538,9 @@ msgstr "A exclusão de uma conta tem os seguintes efeitos:"
msgid "Profiles|Disconnect"
msgstr "Desconectar"
+msgid "Profiles|Disconnect %{provider}"
+msgstr ""
+
msgid "Profiles|Do not show on profile"
msgstr "Não mostrar no perfil"
@@ -18882,7 +19565,7 @@ msgstr "O token de feed foi redefinido com sucesso"
msgid "Profiles|Full name"
msgstr "Nome completo"
-msgid "Profiles|Give your individual key a title. This will be publically visible."
+msgid "Profiles|Give your individual key a title."
msgstr ""
msgid "Profiles|Include private contributions on my profile"
@@ -18972,8 +19655,8 @@ msgstr ""
msgid "Profiles|The maximum file size allowed is 200KB."
msgstr "O tamanho máximo de arquivo permitido é de 200KB."
-msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it?"
-msgstr "Isso não se parece com uma chave pública SSH, você tem certeza que gostaria de adicioná-la?"
+msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it? It will be publicly visible."
+msgstr ""
msgid "Profiles|This email will be displayed on your public profile"
msgstr "Este e-mail será exibido no seu perfil público"
@@ -19047,6 +19730,9 @@ msgstr "Você pode enviar o seu avatar aqui ou alterá-lo em %{gravatar_link}"
msgid "Profiles|You don't have access to delete this user."
msgstr "Você não tem permissão para apagar esse usuário."
+msgid "Profiles|You must transfer ownership or delete groups you are an owner of before you can delete your account"
+msgstr ""
+
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr "Você precisa delegar outro usuário para ser dono ou apagar esses grupos antes de excluir sua conta."
@@ -19635,6 +20321,9 @@ msgstr "Android"
msgid "ProjectTemplates|GitLab Cluster Management"
msgstr ""
+msgid "ProjectTemplates|Gitpod/Spring Petclinic"
+msgstr ""
+
msgid "ProjectTemplates|Go Micro"
msgstr "Go Micro"
@@ -20244,6 +20933,9 @@ msgstr ""
msgid "Publish to status page"
msgstr ""
+msgid "Published"
+msgstr ""
+
msgid "Published on status page"
msgstr ""
@@ -20361,9 +21053,15 @@ msgstr "Ações rápidas podem ser usadas nas descrições das issues e nas caix
msgid "Quick range"
msgstr ""
+msgid "Quickly and easily edit multiple files in your project."
+msgstr ""
+
msgid "README"
msgstr "README"
+msgid "Rails"
+msgstr ""
+
msgid "Rake Tasks Help"
msgstr ""
@@ -20483,12 +21181,15 @@ msgstr "Registrar/Login"
msgid "Register Two-Factor Authenticator"
msgstr "Registrar autenticador de dois fatores"
-msgid "Register U2F device"
-msgstr "Registrar dispositivo U2F"
-
msgid "Register Universal Two-Factor (U2F) Device"
msgstr "Registrar dispositivo de Dois Fatores Universal (U2F)"
+msgid "Register WebAuthn Device"
+msgstr ""
+
+msgid "Register device"
+msgstr ""
+
msgid "Register for GitLab"
msgstr ""
@@ -20498,9 +21199,6 @@ msgstr ""
msgid "Register with two-factor app"
msgstr "Registre-se com aplicativo de dois fatores"
-msgid "Registration"
-msgstr ""
-
msgid "Registration|Checkout"
msgstr ""
@@ -20617,9 +21315,6 @@ msgstr ""
msgid "Release|Something went wrong while saving the release details"
msgstr ""
-msgid "Remediated: needs review"
-msgstr ""
-
msgid "Remediations"
msgstr ""
@@ -20725,6 +21420,9 @@ msgstr ""
msgid "Remove priority"
msgstr "Remover prioridade"
+msgid "Remove report"
+msgstr ""
+
msgid "Remove secondary node"
msgstr ""
@@ -20737,6 +21435,12 @@ msgstr ""
msgid "Remove time estimate"
msgstr ""
+msgid "Remove user & report"
+msgstr ""
+
+msgid "Remove user from group"
+msgstr ""
+
msgid "Removed"
msgstr "Removido"
@@ -20818,9 +21522,6 @@ msgstr ""
msgid "Removes time estimate."
msgstr ""
-msgid "Removing license…"
-msgstr "Removendo a licença…"
-
msgid "Removing this group also removes all child projects, including archived projects, and their resources."
msgstr ""
@@ -20905,6 +21606,9 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
+msgid "Reported by %{reporter}"
+msgstr ""
+
msgid "Reporting"
msgstr "Reportando"
@@ -20991,6 +21695,27 @@ msgstr "sem resultados de teste alterados"
msgid "Repositories"
msgstr ""
+msgid "Repositories Analytics"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download Historic Test Coverage Data"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download historic test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Historic Test Coverage Data is available in raw format (.csv) for further analysis."
+msgstr ""
+
+msgid "RepositoriesAnalytics|Test Code Coverage"
+msgstr ""
+
+msgid "RepositoriesAnalytics|There was an error fetching the projects."
+msgstr ""
+
msgid "Repository"
msgstr "Repositório"
@@ -21069,9 +21794,15 @@ msgstr ""
msgid "Request parameter %{param} is missing."
msgstr ""
+msgid "Request review from"
+msgstr ""
+
msgid "Request to link SAML account must be authorized"
msgstr ""
+msgid "Requested"
+msgstr ""
+
msgid "Requested %{time_ago}"
msgstr "Solicitado %{time_ago}"
@@ -21090,6 +21821,9 @@ msgstr "Solicita Perfis"
msgid "Requests to these domain(s)/address(es) on the local network will be allowed when local requests from hooks and services are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 or 127.0.0.0/28 are supported. Domain wildcards are not supported currently. Use comma, semicolon, or newline to separate multiple entries. The allowlist can hold a maximum of 1000 entries. Domains should use IDNA encoding. Ex: example.com, 192.168.1.1, 127.0.0.0/28, xn--itlab-j1a.com."
msgstr ""
+msgid "Require admin approval for new sign-ups"
+msgstr ""
+
msgid "Require all users in this group to setup Two-factor authentication"
msgstr "Exigir que todos os usuários deste grupo configurem a autenticação de dois fatores"
@@ -21217,9 +21951,6 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr "Resolvido por %{name}"
-msgid "Resolved by %{resolvedByName}"
-msgstr "Resolvido por %{resolvedByName}"
-
msgid "Resolves IP addresses once and uses them to submit requests"
msgstr ""
@@ -21339,6 +22070,14 @@ msgstr ""
msgid "ReviewApp|Enable Review App"
msgstr ""
+msgid "Reviewer"
+msgid_plural "%d Reviewers"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Reviewer(s)"
+msgstr ""
+
msgid "Reviewing"
msgstr "Revisão"
@@ -21378,6 +22117,9 @@ msgstr ""
msgid "Rook"
msgstr ""
+msgid "Ruby"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -21456,6 +22198,63 @@ msgstr "Executores online no momento: %{active_runners_count}"
msgid "Runners page."
msgstr "Página de runners."
+msgid "Runners|Active"
+msgstr ""
+
+msgid "Runners|Architecture"
+msgstr ""
+
+msgid "Runners|Can run untagged jobs"
+msgstr ""
+
+msgid "Runners|Description"
+msgstr ""
+
+msgid "Runners|Group"
+msgstr ""
+
+msgid "Runners|IP Address"
+msgstr ""
+
+msgid "Runners|Last contact"
+msgstr ""
+
+msgid "Runners|Locked to this project"
+msgstr ""
+
+msgid "Runners|Maximum job timeout"
+msgstr ""
+
+msgid "Runners|Name"
+msgstr ""
+
+msgid "Runners|Platform"
+msgstr ""
+
+msgid "Runners|Property Name"
+msgstr ""
+
+msgid "Runners|Protected"
+msgstr ""
+
+msgid "Runners|Revision"
+msgstr ""
+
+msgid "Runners|Shared"
+msgstr ""
+
+msgid "Runners|Specific"
+msgstr ""
+
+msgid "Runners|Tags"
+msgstr ""
+
+msgid "Runners|Value"
+msgstr ""
+
+msgid "Runners|Version"
+msgstr ""
+
msgid "Runners|You have used %{quotaUsed} out of %{quotaLimit} of your shared Runners pipeline minutes."
msgstr ""
@@ -21468,6 +22267,9 @@ msgstr "Executando…"
msgid "Runs a number of housekeeping tasks within the current repository, such as compressing file revisions and removing unreachable objects."
msgstr ""
+msgid "SAML"
+msgstr ""
+
msgid "SAML SSO"
msgstr "SAML SSO"
@@ -21519,6 +22321,9 @@ msgstr "Sábado"
msgid "Save"
msgstr "Salvar"
+msgid "Save %{name} size limits"
+msgstr ""
+
msgid "Save Changes"
msgstr "Salvar alterações"
@@ -21549,9 +22354,6 @@ msgstr "Salvar agendamento da pipeline"
msgid "Save space and find tags in the Container Registry more easily. Enable the cleanup policy to remove stale tags and keep only the ones you need."
msgstr ""
-msgid "Save template"
-msgstr ""
-
msgid "Save variables"
msgstr "Salvar variáveis"
@@ -21594,9 +22396,6 @@ msgstr "Agendando pipelines"
msgid "Scope"
msgstr "Escopo"
-msgid "Scope not supported with disabled 'users_search' feature!"
-msgstr ""
-
msgid "Scoped issue boards"
msgstr "Painéis de escopo"
@@ -21723,9 +22522,6 @@ msgstr "Pesquisar projetos..."
msgid "Search requirements"
msgstr ""
-msgid "Search results…"
-msgstr ""
-
msgid "Search users"
msgstr "Procurar usuários"
@@ -21798,6 +22594,11 @@ msgid_plural "SearchResults|commits"
msgstr[0] ""
msgstr[1] ""
+msgid "SearchResults|epic"
+msgid_plural "SearchResults|epics"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "SearchResults|issue"
msgid_plural "SearchResults|issues"
msgstr[0] ""
@@ -21842,10 +22643,10 @@ msgstr ""
msgid "Seat Link is disabled, and cannot be configured through this form."
msgstr ""
-msgid "Seats currently in use"
+msgid "Seats usage data as of %{last_enqueue_time}"
msgstr ""
-msgid "Seats in license"
+msgid "Seats usage data is updated every day at 12:00pm UTC"
msgstr ""
msgid "Secondary"
@@ -21899,6 +22700,9 @@ msgstr ""
msgid "SecurityConfiguration|Available for on-demand DAST"
msgstr ""
+msgid "SecurityConfiguration|By default, all analyzers are applied in order to cover all languages across your project, and only run if the language is detected in the Merge Request."
+msgstr ""
+
msgid "SecurityConfiguration|Configure"
msgstr ""
@@ -21929,16 +22733,19 @@ msgstr ""
msgid "SecurityConfiguration|Manage"
msgstr ""
+msgid "SecurityConfiguration|More information"
+msgstr ""
+
msgid "SecurityConfiguration|Not enabled"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|Security Control"
+msgid "SecurityConfiguration|SAST Configuration"
msgstr ""
-msgid "SecurityConfiguration|See documentation"
+msgid "SecurityConfiguration|Security Control"
msgstr ""
msgid "SecurityConfiguration|Status"
@@ -21950,6 +22757,9 @@ msgstr ""
msgid "SecurityConfiguration|Using custom settings. You won't receive automatic updates on this variable. %{anchorStart}Restore to default%{anchorEnd}"
msgstr ""
+msgid "SecurityConfiguration|View history"
+msgstr ""
+
msgid "SecurityConfiguration|You can quickly enable all security scanning tools by enabling %{linkStart}Auto DevOps%{linkEnd}."
msgstr ""
@@ -22028,9 +22838,6 @@ msgstr ""
msgid "SecurityReports|Learn more about setting up your dashboard"
msgstr ""
-msgid "SecurityReports|Load more vulnerabilities"
-msgstr ""
-
msgid "SecurityReports|Monitor vulnerabilities in your code"
msgstr ""
@@ -22310,7 +23117,7 @@ msgstr ""
msgid "Select status"
msgstr ""
-msgid "Select strategy activation method"
+msgid "Select strategy activation method."
msgstr ""
msgid "Select subscription"
@@ -22325,8 +23132,8 @@ msgstr "Selecione o branch que você deseja definir como o padrão para este pro
msgid "Select the custom project template source group."
msgstr "Selecione o grupo de origem dos modelos customizados de projeto."
-msgid "Select timeframe"
-msgstr "Selecionar período"
+msgid "Select the environment scope for this feature flag."
+msgstr ""
msgid "Select timezone"
msgstr ""
@@ -22574,6 +23381,9 @@ msgstr "Definir repositório de modelos para toda a instância"
msgid "Set iteration"
msgstr ""
+msgid "Set limit to 0 to allow any file size."
+msgstr ""
+
msgid "Set max session time for web terminal."
msgstr "Defina o tempo máximo da sessão para o terminal da web."
@@ -22652,10 +23462,13 @@ msgstr ""
msgid "Set up a %{type} Runner manually"
msgstr "Configure o Runner %{type} manualmente"
+msgid "Set up a hardware device as a second factor to sign in."
+msgstr ""
+
msgid "Set up assertions/attributes/claims (email, first_name, last_name) and NameID according to %{docsLinkStart}the documentation %{icon}%{docsLinkEnd}"
msgstr "Configurar asserções/atributos/alegações (email, first_name, last_name) e NameID de acordo com %{docsLinkStart}a documentação %{icon}%{docsLinkEnd}"
-msgid "Set up new U2F device"
+msgid "Set up new device"
msgstr ""
msgid "Set up new password"
@@ -22724,6 +23537,9 @@ msgstr ""
msgid "Sets weight to %{weight}."
msgstr ""
+msgid "Setting this to 0 means using the system default timeout value."
+msgstr ""
+
msgid "Settings"
msgstr "Configurações"
@@ -22739,6 +23555,15 @@ msgstr ""
msgid "Severity"
msgstr ""
+msgid "SeverityWidget|Severity"
+msgstr ""
+
+msgid "SeverityWidget|Severity: %{severity}"
+msgstr ""
+
+msgid "SeverityWidget|There was an error while updating severity."
+msgstr ""
+
msgid "Shards (%{shards})"
msgstr ""
@@ -22784,6 +23609,9 @@ msgstr ""
msgid "Show all requirements."
msgstr ""
+msgid "Show all test cases."
+msgstr ""
+
msgid "Show archived projects"
msgstr "Mostrar projetos arquivados"
@@ -22796,6 +23624,9 @@ msgstr "Exibir comando"
msgid "Show comments"
msgstr "Mostrar comentários"
+msgid "Show comments on this file"
+msgstr ""
+
msgid "Show comments only"
msgstr "Mostrar apenas comentários"
@@ -22841,6 +23672,12 @@ msgstr "Mostrar páginas acima"
msgid "Show parent subgroups"
msgstr "Mostrar subgrupos acima"
+msgid "Show the Closed list"
+msgstr ""
+
+msgid "Show the Open list"
+msgstr ""
+
msgid "Show whitespace changes"
msgstr "Mostrar as alterações de espaço em branco"
@@ -22884,9 +23721,6 @@ msgstr "Lado a lado"
msgid "Sidebar|Assign health status"
msgstr ""
-msgid "Sidebar|Change weight"
-msgstr "Alterar peso"
-
msgid "Sidebar|Health status"
msgstr ""
@@ -23070,6 +23904,9 @@ msgstr ""
msgid "Snippets|Add another file %{num}/%{total}"
msgstr ""
+msgid "Snippets|Authored %{time_ago} by %{author}"
+msgstr ""
+
msgid "Snippets|Delete file"
msgstr ""
@@ -23097,6 +23934,9 @@ msgstr ""
msgid "Solution"
msgstr ""
+msgid "Some changes are not shown"
+msgstr ""
+
msgid "Some child epics may be hidden due to applied filters"
msgstr ""
@@ -23463,6 +24303,12 @@ msgstr "Origem"
msgid "Source (branch or tag)"
msgstr "Fonte (branch or tag)"
+msgid "Source Branch"
+msgstr ""
+
+msgid "Source branch: %{source_branch_open}%{source_branch}%{source_branch_close}"
+msgstr ""
+
msgid "Source code"
msgstr "Código-fonte"
@@ -23628,9 +24474,6 @@ msgstr "Iniciar uma revisão"
msgid "Start and due date"
msgstr "Data de início e término"
-msgid "Start by choosing a group to see how your team is spending time. You can then drill down to the project level."
-msgstr "Comece escolhendo um grupo para ver como seu time esta gastando o tempo. Você pode então detalhar até o nível do projeto."
-
msgid "Start by choosing a group to start exploring the merge requests in that group. You can then proceed to filter by projects, labels, milestones and authors."
msgstr ""
@@ -23712,18 +24555,27 @@ msgstr ""
msgid "StaticSiteEditor|3. Assign a person to review and accept the merge request."
msgstr ""
+msgid "StaticSiteEditor|A link to view the merge request will appear once ready."
+msgstr ""
+
msgid "StaticSiteEditor|An error occurred while submitting your changes."
msgstr ""
msgid "StaticSiteEditor|Branch could not be created."
msgstr ""
+msgid "StaticSiteEditor|Copy update"
+msgstr ""
+
msgid "StaticSiteEditor|Could not commit the content changes."
msgstr ""
msgid "StaticSiteEditor|Could not create merge request."
msgstr ""
+msgid "StaticSiteEditor|Creating your merge request"
+msgstr ""
+
msgid "StaticSiteEditor|Incompatible file content"
msgstr ""
@@ -23745,6 +24597,9 @@ msgstr ""
msgid "StaticSiteEditor|View documentation"
msgstr ""
+msgid "StaticSiteEditor|You can set an assignee to get your changes reviewed and deployed once your merge request is created."
+msgstr ""
+
msgid "StaticSiteEditor|Your merge request has been created"
msgstr ""
@@ -23874,15 +24729,15 @@ msgstr ""
msgid "Submit %{humanized_resource_name}"
msgstr ""
-msgid "Submit Changes"
-msgstr ""
-
msgid "Submit a review"
msgstr ""
msgid "Submit as spam"
msgstr "Enviar como spam"
+msgid "Submit changes"
+msgstr ""
+
msgid "Submit feedback"
msgstr "Enviar feedback"
@@ -24036,6 +24891,9 @@ msgstr ""
msgid "Successfully deleted U2F device."
msgstr ""
+msgid "Successfully deleted WebAuthn device."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -24354,9 +25212,6 @@ msgstr "Modelo"
msgid "Template to append to all Service Desk issues"
msgstr ""
-msgid "Template was successfully saved."
-msgstr ""
-
msgid "Templates"
msgstr "Modelos"
@@ -24435,10 +25290,28 @@ msgid_plural "Test coverage: %d hits"
msgstr[0] ""
msgstr[1] ""
-msgid "Test failed."
+msgid "Test settings"
msgstr ""
-msgid "Test settings and save changes"
+msgid "TestCases|New Test Case"
+msgstr ""
+
+msgid "TestCases|New test case"
+msgstr ""
+
+msgid "TestCases|Search test cases"
+msgstr ""
+
+msgid "TestCases|Something went wrong while creating a test case."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching count of test cases."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching test cases list."
+msgstr ""
+
+msgid "TestCases|Submit test case"
msgstr ""
msgid "TestHooks|Ensure one of your projects has merge requests."
@@ -24504,6 +25377,9 @@ msgstr ""
msgid "Thank you for signing up for your free trial! You will get additional instructions in your inbox shortly."
msgstr ""
+msgid "Thank you for your business."
+msgstr ""
+
msgid "Thank you for your feedback!"
msgstr ""
@@ -24563,9 +25439,6 @@ msgstr ""
msgid "The URL to use for connecting to Elasticsearch. Use a comma-separated list to support clustering (e.g., \"http://localhost:9200, http://localhost:9201\")."
msgstr ""
-msgid "The Web IDE offers advanced syntax highlighting capabilities and more."
-msgstr ""
-
msgid "The X509 Certificate to use when mutual TLS is required to communicate with the external authorization service. If left blank, the server certificate is still validated when accessing over HTTPS."
msgstr "O Certificado X509 a ser usado quando o TLS mútuo é necessário para se comunicar com o serviço de autorização externa. Se deixado em branco, o certificado do servidor ainda será validado ao acessar por HTTPS."
@@ -24676,6 +25549,9 @@ msgstr "O relacionamento como fork foi removido."
msgid "The form contains the following error:"
msgstr ""
+msgid "The form contains the following warning:"
+msgstr ""
+
msgid "The global settings require you to enable Two-Factor Authentication for your account."
msgstr ""
@@ -24790,9 +25666,6 @@ msgstr "A etapa de planejamento mostra o tempo do passo anterior até a publicaÃ
msgid "The private key to use when a client certificate is provided. This value is encrypted at rest."
msgstr "A chave privada a ser usada quando um certificado de cliente é fornecido. Este valor é criptografado."
-msgid "The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr "A etapa de produção mostra o tempo total que leva entre criar uma issue e implantar o código em produção. Os dados serão adicionados automaticamente assim que você completar todo o ciclo de produção."
-
msgid "The project can be accessed by any logged in user."
msgstr "O projeto pode ser acessado por qualquer usuário autenticado."
@@ -24829,7 +25702,7 @@ msgstr ""
msgid "The remote repository is being updated..."
msgstr ""
-msgid "The repository can be commited to, and issues, comments and other entities can be created."
+msgid "The repository can be committed to, and issues, comments and other entities can be created."
msgstr ""
msgid "The repository for this project does not exist."
@@ -24883,9 +25756,6 @@ msgstr "A etapa de testes mostra o tempo que o GitLab CI leva para executar cada
msgid "The time taken by each data entry gathered by that stage."
msgstr "O tempo necessário por cada entrada de dados reunida por essa etapa."
-msgid "The total stage shows the time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The update action will time out after %{number_of_minutes} minutes. For big repositories, use a clone/push combination."
msgstr "A ação de atualização irá expirar depois de %{number_of_minutes} minutos. Para grandes repositórios, use uma combinação de clone/push."
@@ -24949,6 +25819,9 @@ msgstr "Ainda não há projetos arquivados"
msgid "There are no archived requirements"
msgstr ""
+msgid "There are no archived test cases"
+msgstr ""
+
msgid "There are no changes"
msgstr ""
@@ -24988,6 +25861,9 @@ msgstr ""
msgid "There are no open requirements"
msgstr ""
+msgid "There are no open test cases"
+msgstr ""
+
msgid "There are no packages yet"
msgstr ""
@@ -25000,6 +25876,9 @@ msgstr ""
msgid "There is a limit of %{ci_project_subscriptions_limit} subscriptions from or to a project."
msgstr ""
+msgid "There is already a To-Do for this design."
+msgstr ""
+
msgid "There is already a repository with that name on disk"
msgstr "Já existe um repositório com esse nome no disco"
@@ -25018,6 +25897,9 @@ msgstr ""
msgid "There was a problem communicating with your device."
msgstr "Houve um problema de comunicação com o seu dispositivo."
+msgid "There was a problem fetching branches."
+msgstr ""
+
msgid "There was a problem fetching groups."
msgstr ""
@@ -25246,9 +26128,15 @@ msgstr ""
msgid "This action can lead to data loss. To prevent accidental actions we ask you to confirm your intention."
msgstr ""
+msgid "This action cannot be undone, and will permanently delete the %{key} SSH key"
+msgstr ""
+
msgid "This action cannot be undone. You will lose the project's repository and all content: issues, merge requests, etc."
msgstr ""
+msgid "This action has been performed too many times. Try again later."
+msgstr ""
+
msgid "This action will %{strongOpen}permanently delete%{strongClose} %{codeOpen}%{project}%{codeClose} %{strongOpen}immediately%{strongClose}, including its repositories and all content: issues, merge requests, etc."
msgstr ""
@@ -25276,9 +26164,6 @@ msgstr ""
msgid "This board's scope is reduced"
msgstr "O escopo deste painel está reduzido"
-msgid "This branch has changed since you started editing. Would you like to create a new branch?"
-msgstr "Esse branch mudou desde quando você começou sua edição. Você quer criar um novo branch?"
-
msgid "This chart could not be displayed"
msgstr ""
@@ -25405,15 +26290,9 @@ msgstr "Esta é uma lista de dispositivos com os quais você logou em sua conta.
msgid "This is a security log of important events involving your account."
msgstr "Este é um registro de segurança de eventos importantes envolvendo a sua conta."
-msgid "This is the author's first Merge Request to this project."
-msgstr "Esse é o autor do primeiro merge request desse projeto."
-
msgid "This is the highest peak of users on your installation since the license started."
msgstr ""
-msgid "This is the maximum number of users that have existed at the same time since the license started. This is the minimum number of seats you will need to buy when you renew your license."
-msgstr ""
-
msgid "This is the number of currently active users on your installation, and this is the minimum number you need to purchase when you renew your license."
msgstr ""
@@ -25645,6 +26524,15 @@ msgstr ""
msgid "This user has no identities"
msgstr "Esse usuário não tem identidades"
+msgid "This user has previously committed to the %{name} project."
+msgstr ""
+
+msgid "This user has the %{access} role in the %{name} project."
+msgstr ""
+
+msgid "This user is the author of this %{noteable}."
+msgstr ""
+
msgid "This user will be the author of all events in the activity feed that are the result of an update, like new branches being created or new commits being pushed to existing branches."
msgstr "Esse usuário será o autor de todos os eventos no feed de atividades que são o resultado de uma atualização, como novos branches sendo criados ou novos commits sendo enviados para os branches existentes."
@@ -25675,6 +26563,9 @@ msgstr ""
msgid "Threat Monitoring"
msgstr ""
+msgid "ThreatMonitoring|All Environments"
+msgstr ""
+
msgid "ThreatMonitoring|Anomalous Requests"
msgstr ""
@@ -25702,9 +26593,6 @@ msgstr ""
msgid "ThreatMonitoring|Operations Per Second"
msgstr ""
-msgid "ThreatMonitoring|Overview"
-msgstr ""
-
msgid "ThreatMonitoring|Packet Activity"
msgstr ""
@@ -25723,6 +26611,9 @@ msgstr ""
msgid "ThreatMonitoring|Something went wrong, unable to fetch statistics"
msgstr ""
+msgid "ThreatMonitoring|Statistics"
+msgstr ""
+
msgid "ThreatMonitoring|The firewall is not installed or has been disabled. To view this data, ensure the web application firewall is installed and enabled for your cluster."
msgstr ""
@@ -26114,6 +27005,9 @@ msgstr ""
msgid "To update Snippets with multiple files, you must use the `files` parameter"
msgstr ""
+msgid "To use Gitpod you must first enable the feature in the integrations section of your %{user_prefs}."
+msgstr ""
+
msgid "To view all %{scannedResourcesCount} scanned URLs, please download the CSV file"
msgstr ""
@@ -26147,9 +27041,6 @@ msgstr ""
msgid "Toggle Sidebar"
msgstr "Alternar barra lateral"
-msgid "Toggle all threads"
-msgstr ""
-
msgid "Toggle backtrace"
msgstr "Alternar backtrace"
@@ -26174,9 +27065,6 @@ msgstr "Alternar prêmio de emoji"
msgid "Toggle navigation"
msgstr "Alternar navegação"
-msgid "Toggle project"
-msgstr ""
-
msgid "Toggle sidebar"
msgstr "Ativar/Desativar barra lateral"
@@ -26216,6 +27104,9 @@ msgstr ""
msgid "Too many projects enabled. You will need to manage them via the console or the API."
msgstr ""
+msgid "Too much data"
+msgstr ""
+
msgid "Topics (optional)"
msgstr ""
@@ -26234,6 +27125,9 @@ msgstr ""
msgid "Total cores (CPUs)"
msgstr ""
+msgid "Total days to completion"
+msgstr ""
+
msgid "Total issues"
msgstr ""
@@ -26330,6 +27224,9 @@ msgstr "Visão em árvore"
msgid "Trending"
msgstr "Mais populares"
+msgid "Trials|Create a new group to start your GitLab Gold trial."
+msgstr ""
+
msgid "Trials|Go back to GitLab"
msgstr ""
@@ -26339,6 +27236,15 @@ msgstr ""
msgid "Trials|You can always resume this process by selecting your avatar and choosing 'Start a Gold trial'"
msgstr ""
+msgid "Trials|You can apply your trial to a new group or an existing group."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group or your personal account."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group, an existing group, or your personal account."
+msgstr ""
+
msgid "Trials|You won't get a free trial right now but you can always resume this process by clicking on your avatar and choosing 'Start a free trial'"
msgstr ""
@@ -26408,6 +27314,9 @@ msgstr ""
msgid "Try using a different search term to find the file you are looking for."
msgstr ""
+msgid "Trying to communicate with your device. Plug it in (if needed) and press the button on the device now."
+msgstr ""
+
msgid "Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now."
msgstr ""
@@ -26495,6 +27404,12 @@ msgstr ""
msgid "URL or request ID"
msgstr ""
+msgid "USER %{user} WILL BE REMOVED! Are you sure?"
+msgstr ""
+
+msgid "USER WILL BE BLOCKED! Are you sure?"
+msgstr ""
+
msgid "UTC"
msgstr ""
@@ -26552,9 +27467,6 @@ msgstr "Não é possível carregar o diff. %{button_try_again}"
msgid "Unable to load the merge request widget. Try reloading the page."
msgstr ""
-msgid "Unable to resolve"
-msgstr ""
-
msgid "Unable to save iteration. Please try again"
msgstr ""
@@ -26603,6 +27515,9 @@ msgstr ""
msgid "Undo ignore"
msgstr ""
+msgid "Unexpected error"
+msgstr ""
+
msgid "Unfortunately, your email message to GitLab could not be processed."
msgstr ""
@@ -26636,6 +27551,9 @@ msgstr "Formato desconhecido"
msgid "Unknown response text"
msgstr ""
+msgid "Unless otherwise agreed to in writing with GitLab, by clicking \"Upload License\" you agree that your use of GitLab Software is subject to the %{eula_link_start}Terms of Service%{eula_link_end}."
+msgstr ""
+
msgid "Unlimited"
msgstr "Ilimitado"
@@ -27002,9 +27920,6 @@ msgstr ""
msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
msgstr "Use o Balcão de Atendimento para se conectar com seus usuários (por exemplo, para oferecer suporte ao cliente) por email dentro do GitLab"
-msgid "Use a hardware device to add the second factor of authentication."
-msgstr ""
-
msgid "Use an one time password authenticator on your mobile device or computer to enable two-factor authentication (2FA)."
msgstr ""
@@ -27278,13 +28193,13 @@ msgstr ""
msgid "Users"
msgstr "Usuários"
-msgid "Users in License:"
+msgid "Users in License"
msgstr ""
-msgid "Users or groups set as approvers in the project's or merge request's settings."
+msgid "Users in License:"
msgstr ""
-msgid "Users outside of license"
+msgid "Users or groups set as approvers in the project's or merge request's settings."
msgstr ""
msgid "Users over License:"
@@ -27302,9 +28217,6 @@ msgstr ""
msgid "Users with a Guest role or those who don't belong to a Project or Group will not use a seat from your license."
msgstr ""
-msgid "Users with a Guest role or those who don't belong to any projects or groups don't count towards seats in use."
-msgstr ""
-
msgid "UsersSelect|%{name} + %{length} more"
msgstr "%{name} + %{length} mais"
@@ -27344,9 +28256,6 @@ msgstr ""
msgid "Validations failed."
msgstr ""
-msgid "Validity"
-msgstr "Validade"
-
msgid "Value"
msgstr "Valor"
@@ -27365,6 +28274,9 @@ msgstr ""
msgid "Value Stream Name"
msgstr ""
+msgid "ValueStreamAnalyticsStage|We don't have enough data to show this stage."
+msgstr ""
+
msgid "ValueStreamAnalytics|%{days}d"
msgstr ""
@@ -27621,6 +28533,9 @@ msgstr "Revisar"
msgid "VisualReviewApp|Steps 1 and 2 (and sometimes 3) are performed once by the developer before requesting feedback. Steps 3 (if necessary), 4 is performed by the reviewer each time they perform a review."
msgstr ""
+msgid "Visualization"
+msgstr ""
+
msgid "Vulnerabilities"
msgstr "Vulnerabilidades"
@@ -27648,34 +28563,31 @@ msgstr ""
msgid "VulnerabilityChart|Severity"
msgstr ""
-msgid "VulnerabilityManagement|A true-positive and will fix"
-msgstr ""
-
-msgid "VulnerabilityManagement|Change status"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Confirm"
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|Confirmed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Detected %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|A true-positive and will fix"
msgstr ""
-msgid "VulnerabilityManagement|Dismiss"
+msgid "VulnerabilityManagement|Change status"
msgstr ""
-msgid "VulnerabilityManagement|Dismissed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
msgstr ""
-msgid "VulnerabilityManagement|Resolved"
+msgid "VulnerabilityManagement|Detected"
msgstr ""
-msgid "VulnerabilityManagement|Resolved %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Needs triage"
msgstr ""
msgid "VulnerabilityManagement|Something went wrong while trying to delete the comment. Please try again later."
@@ -27726,6 +28638,9 @@ msgstr ""
msgid "Vulnerability|%{scannerName} (version %{scannerVersion})"
msgstr ""
+msgid "Vulnerability|Activity"
+msgstr ""
+
msgid "Vulnerability|Class"
msgstr "Classe"
@@ -27738,6 +28653,9 @@ msgstr ""
msgid "Vulnerability|Description"
msgstr "Descrição"
+msgid "Vulnerability|Detected"
+msgstr ""
+
msgid "Vulnerability|Evidence"
msgstr ""
@@ -27801,6 +28719,9 @@ msgstr ""
msgid "Warning: Displaying this diagram might cause performance issues on this page."
msgstr ""
+msgid "We are currently unable to fetch data for the pipeline header."
+msgstr ""
+
msgid "We are currently unable to fetch data for this graph."
msgstr ""
@@ -27840,6 +28761,12 @@ 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 will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
+msgstr ""
+
+msgid "We would like to inform you that your subscription GitLab Enterprise Edition %{plan_name} is nearing its user limit. You have %{active_user_count} active users, which is almost at the user limit of %{maximum_user_count}."
+msgstr ""
+
msgid "We've found no vulnerabilities"
msgstr ""
@@ -27855,6 +28782,12 @@ msgstr "Terminal Web"
msgid "Web terminal"
msgstr "Terminal Web"
+msgid "WebAuthn Devices (%{length})"
+msgstr ""
+
+msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
+msgstr ""
+
msgid "WebIDE|Merge request"
msgstr ""
@@ -27993,15 +28926,9 @@ msgstr ""
msgid "Welcome to the guided GitLab tour"
msgstr ""
-msgid "Welcome to your Issue Board!"
-msgstr ""
-
msgid "Welcome to your issue board!"
msgstr ""
-msgid "We’ve been making changes to %{featureName} and we’d love your feedback %{linkStart}in this issue%{linkEnd} to help us improve the experience."
-msgstr ""
-
msgid "What are you searching for?"
msgstr ""
@@ -28020,6 +28947,9 @@ msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
msgstr "Quando um runner está bloqueado, não pode ser atribuído a outros projetos"
+msgid "When enabled, any user visiting %{host} and creating an account will have to be explicitly approved by the admin before they can login. This setting is effective only if sign-ups are enabled."
+msgstr ""
+
msgid "When enabled, any user visiting %{host} will be able to create an account."
msgstr ""
@@ -28244,6 +29174,9 @@ msgstr ""
msgid "With requirements, you can set criteria to check your products against."
msgstr ""
+msgid "With test cases, you can define conditions for your project to meet in determining quality"
+msgstr ""
+
msgid "Withdraw Access Request"
msgstr "Remover Requisição de Acesso"
@@ -28259,6 +29192,9 @@ msgstr ""
msgid "Workflow Help"
msgstr ""
+msgid "Would you like to create a new branch?"
+msgstr ""
+
msgid "Write"
msgstr ""
@@ -28280,6 +29216,9 @@ msgstr ""
msgid "Wrong extern UID provided. Make sure Auth0 is configured correctly."
msgstr ""
+msgid "YYYY-MM-DD"
+msgstr ""
+
msgid "Yes"
msgstr "Sim"
@@ -28337,8 +29276,8 @@ msgstr ""
msgid "You are going to remove the fork relationship from %{project_full_name}. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "You are going to transfer %{project_full_name} to another owner. Are you ABSOLUTELY sure?"
-msgstr "Você irá transferir %{project_full_name} para outro proprietário. Tem certeza ABSOLUTA?"
+msgid "You are going to transfer %{project_full_name} to another namespace. Are you ABSOLUTELY sure?"
+msgstr ""
msgid "You are going to turn off the confidentiality. This means %{strongStart}everyone%{strongEnd} will be able to see and leave a comment on this %{issuableType}."
msgstr ""
@@ -28397,9 +29336,6 @@ msgstr ""
msgid "You can always edit this later"
msgstr ""
-msgid "You can apply your Trial to your Personal account or create a New Group."
-msgstr ""
-
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings"
msgstr ""
@@ -28421,12 +29357,18 @@ msgstr "Você pode instalar facilmente um Runner em um cluster Kubernetes. %{lin
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
+msgid "You can find more information about GitLab subscriptions in %{subscriptions_doc_link}."
+msgstr ""
+
msgid "You can generate an access token scoped to this project for each application to use the GitLab API."
msgstr ""
msgid "You can get started by cloning the repository or start adding files to it with one of the following options."
msgstr ""
+msgid "You can group test cases using labels. To learn about the future direction of this feature, visit %{linkStart}Quality Management direction page%{linkEnd}."
+msgstr ""
+
msgid "You can invite a new member to %{project_name} or invite another group."
msgstr ""
@@ -28442,6 +29384,9 @@ msgstr "Você pode mover o gráfico usando as setas do teclado."
msgid "You can notify the app / group or a project by sending them an email notification"
msgstr ""
+msgid "You can now close this window."
+msgstr ""
+
msgid "You can now export your security dashboard to a CSV report."
msgstr ""
@@ -28490,9 +29435,6 @@ msgstr ""
msgid "You can test your .gitlab-ci.yml in %{linkStart}CI Lint%{linkEnd}."
msgstr "Você pode testar o seu .gitlab-ci.yml no %{linkStart}CI Lint%{linkEnd}."
-msgid "You can try again using %{begin_link}basic search%{end_link}"
-msgstr ""
-
msgid "You cannot access the raw file. Please wait a minute."
msgstr ""
@@ -28544,6 +29486,9 @@ msgstr "Você não tem as permissões corretas para substituir as configuraçõe
msgid "You don't have any U2F devices registered yet."
msgstr ""
+msgid "You don't have any WebAuthn devices registered yet."
+msgstr ""
+
msgid "You don't have any active chat names."
msgstr "Você não tem nenhum nome de bate-papo ativo."
@@ -28631,6 +29576,9 @@ msgstr ""
msgid "You must accept our Terms of Service and privacy policy in order to register an account"
msgstr "Você deve aceitar nossos Termos de Serviço e política de privacidade para registrar uma conta"
+msgid "You must be logged in to search across all of GitLab"
+msgstr ""
+
msgid "You must disassociate %{domain} from all clusters it is attached to before deletion."
msgstr ""
@@ -28670,7 +29618,7 @@ msgstr "Você precisa de permissão."
msgid "You need to be logged in."
msgstr "Você precisa estar conectado."
-msgid "You need to register a two-factor authentication app before you can set up a U2F device."
+msgid "You need to register a two-factor authentication app before you can set up a device."
msgstr ""
msgid "You need to set terms to be enforced"
@@ -28688,6 +29636,9 @@ msgstr ""
msgid "You reached %{usage_in_percent} of %{namespace_name}'s storage capacity (%{used_storage} of %{storage_limit})"
msgstr ""
+msgid "You successfully declined the invitation"
+msgstr ""
+
msgid "You tried to fork %{link_to_the_project} but it failed for the following reason:"
msgstr "Você tentou criar o fork %{link_to_the_project}, mas ocorreu uma falha pelo seguinte motivo:"
@@ -28853,10 +29804,13 @@ msgstr ""
msgid "Your U2F device did not send a valid JSON response."
msgstr ""
-msgid "Your U2F device needs to be set up. Plug it in (if not already) and click the button on the left."
+msgid "Your U2F device was registered!"
+msgstr ""
+
+msgid "Your WebAuthn device did not send a valid JSON response."
msgstr ""
-msgid "Your U2F device was registered!"
+msgid "Your WebAuthn device was registered!"
msgstr ""
msgid "Your access request to the %{source_type} has been withdrawn."
@@ -28880,6 +29834,9 @@ msgstr "Seus aplicativos autorizados"
msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
msgstr ""
+msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
+msgstr ""
+
msgid "Your changes can be committed to %{branch_name} because a merge request is open."
msgstr "Você pode fazer commit de suas alterações para %{branch_name} porque um merge request está aberto."
@@ -28916,6 +29873,12 @@ msgstr ""
msgid "Your deployment services will be broken, you will need to manually fix the services after renaming."
msgstr ""
+msgid "Your device is not compatible with GitLab. Please try another device"
+msgstr ""
+
+msgid "Your device needs to be set up. Plug it in (if needed) and click the button on the left."
+msgstr ""
+
msgid "Your device was successfully set up! Give it a name and register it with the GitLab server."
msgstr ""
@@ -29029,9 +29992,6 @@ msgstr[1] ""
msgid "access:"
msgstr ""
-msgid "activated"
-msgstr ""
-
msgid "added %{created_at_timeago}"
msgstr "adicionado %{created_at_timeago}"
@@ -29104,9 +30064,21 @@ msgstr "por"
msgid "by %{user}"
msgstr ""
+msgid "cannot be a date in the past"
+msgstr ""
+
msgid "cannot be changed if a personal project has container registry tags."
msgstr ""
+msgid "cannot be changed if shared runners are enabled"
+msgstr ""
+
+msgid "cannot be enabled because parent group does not allow it"
+msgstr ""
+
+msgid "cannot be enabled because parent group has shared Runners disabled"
+msgstr ""
+
msgid "cannot be enabled unless all domains have TLS certificates"
msgstr ""
@@ -29152,7 +30124,7 @@ msgstr "%{linkStartTag}Saiba mais sobre a Verificação de Dependência %{linkEn
msgid "ciReport|%{linkStartTag}Learn more about SAST %{linkEndTag}"
msgstr "%{linkStartTag}Saiba mais sobre o SAST %{linkEndTag}"
-msgid "ciReport|%{linkStartTag}Learn more about Secret Scanning %{linkEndTag}"
+msgid "ciReport|%{linkStartTag}Learn more about Secret Detection %{linkEndTag}"
msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about codequality reports %{linkEndTag}"
@@ -29467,9 +30439,6 @@ msgstr ""
msgid "error"
msgstr ""
-msgid "error code:"
-msgstr "código de erro:"
-
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr "%{slash_command} irá atualizar o tempo estimado com o último comando."
@@ -29491,6 +30460,9 @@ msgstr ""
msgid "failed to dismiss associated finding(id=%{finding_id}): %{message}"
msgstr ""
+msgid "failed to revert associated finding(id=%{finding_id}) to detected"
+msgstr ""
+
msgid "file"
msgid_plural "files"
msgstr[0] ""
@@ -30033,6 +31005,9 @@ msgstr ""
msgid "must be a root namespace"
msgstr ""
+msgid "must be a valid IPv4 or IPv6 address"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -30069,6 +31044,9 @@ msgstr "nenhuma contribuição"
msgid "no expiration"
msgstr ""
+msgid "no name set"
+msgstr ""
+
msgid "no one can merge"
msgstr ""
@@ -30247,9 +31225,6 @@ msgstr ""
msgid "security Reports|There was an error creating the merge request"
msgstr ""
-msgid "settings saved, but not activated"
-msgstr ""
-
msgid "severity|Critical"
msgstr ""
@@ -30376,9 +31351,6 @@ msgstr ""
msgid "toggle collapse"
msgstr ""
-msgid "toggle dropdown"
-msgstr ""
-
msgid "triggered"
msgstr ""
@@ -30406,6 +31378,9 @@ msgstr ""
msgid "user avatar"
msgstr ""
+msgid "user preferences"
+msgstr ""
+
msgid "username"
msgstr "nome do usuário"
diff --git a/locale/pt_PT/gitlab.po b/locale/pt_PT/gitlab.po
index 6b0b2792c8c..8884f6ffb93 100644
--- a/locale/pt_PT/gitlab.po
+++ b/locale/pt_PT/gitlab.po
@@ -14,7 +14,10 @@ msgstr ""
"X-Crowdin-Language: pt-PT\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 6\n"
-"PO-Revision-Date: 2020-09-04 23:10\n"
+"PO-Revision-Date: 2020-10-02 18:49\n"
+
+msgid " %{project_name}#%{issue_iid} &middot; opened %{issue_created} by %{author}"
+msgstr ""
msgid " %{start} to %{end}"
msgstr ""
@@ -74,6 +77,16 @@ msgstr ""
msgid "\"el\" parameter is required for createInstance()"
msgstr ""
+msgid "%d Approval"
+msgid_plural "%d Approvals"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d Package"
+msgid_plural "%d Packages"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d Scanned URL"
msgid_plural "%d Scanned URLs"
msgstr[0] ""
@@ -137,6 +150,11 @@ msgstr[1] "%d envios"
msgid "%d commits"
msgstr "%d envios"
+msgid "%d completed issue"
+msgid_plural "%d completed issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d contribution"
msgid_plural "%d contributions"
msgstr[0] "%d contribuição"
@@ -147,6 +165,11 @@ msgid_plural "%d days"
msgstr[0] ""
msgstr[1] ""
+msgid "%d day until tags are automatically removed"
+msgid_plural "%d days until tags are automatically removed"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d error"
msgid_plural "%d errors"
msgstr[0] ""
@@ -237,6 +260,16 @@ msgid_plural "%d more comments"
msgstr[0] "mais %d comentário"
msgstr[1] "mais %d comentários"
+msgid "%d open issue"
+msgid_plural "%d open issues"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d pending comment"
+msgid_plural "%d pending comments"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d personal project will be removed and cannot be restored."
msgid_plural "%d personal projects will be removed and cannot be restored."
msgstr[0] ""
@@ -252,6 +285,11 @@ msgid_plural "%d projects"
msgstr[0] ""
msgstr[1] ""
+msgid "%d project selected"
+msgid_plural "%d projects selected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d request with warnings"
msgid_plural "%d requests with warnings"
msgstr[0] ""
@@ -272,6 +310,11 @@ msgid_plural "%d tags"
msgstr[0] ""
msgstr[1] ""
+msgid "%d tag per image name"
+msgid_plural "%d tags per image name"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d unassigned issue"
msgid_plural "%d unassigned issues"
msgstr[0] ""
@@ -292,6 +335,11 @@ msgid_plural "%d vulnerabilities dismissed"
msgstr[0] ""
msgstr[1] ""
+msgid "%d warning found:"
+msgid_plural "%d warnings found:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%s additional commit has been omitted to prevent performance issues."
msgid_plural "%s additional commits have been omitted to prevent performance issues."
msgstr[0] "%s envio adicional foi omitido para prevenir problemas de desempenho."
@@ -330,6 +378,9 @@ msgstr ""
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr "%{commit_author_link} autorizou %{commit_timeago}"
+msgid "%{completedCount} completed weight"
+msgstr ""
+
msgid "%{completedWeight} of %{totalWeight} weight completed"
msgstr ""
@@ -378,14 +429,12 @@ msgid_plural "%{count} participants"
msgstr[0] "%{count} participante"
msgstr[1] "%{count} participantes"
-msgid "%{count} pending comment"
-msgid_plural "%{count} pending comments"
-msgstr[0] "%{count} comentário pendente"
-msgstr[1] "%{count} comentários pendentes"
-
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
+msgid "%{count} total weight"
+msgstr ""
+
msgid "%{dashboard_path} could not be found."
msgstr ""
@@ -440,6 +489,9 @@ msgstr ""
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} usa contas de gestão de grupo. Precisas de criar uma nova conta no GitLab que será gerida por %{group_name}."
+msgid "%{group_name}&%{epic_iid} &middot; opened %{epic_created} by %{author}"
+msgstr ""
+
msgid "%{host} sign-in from new location"
msgstr ""
@@ -452,7 +504,7 @@ msgstr ""
msgid "%{issuableType} will be removed! Are you sure?"
msgstr "%{issuableType} será removido! Tens a certeza?"
-msgid "%{issuesSize} issues with a limit of %{maxIssueCount}"
+msgid "%{issuesCount} issues with a limit of %{maxIssueCount}"
msgstr ""
msgid "%{issuesSize} with a limit of %{maxIssueCount}"
@@ -485,7 +537,7 @@ msgstr ""
msgid "%{labelStart}Namespace:%{labelEnd} %{namespace}"
msgstr ""
-msgid "%{labelStart}Report Type:%{labelEnd} %{reportType}"
+msgid "%{labelStart}Scan Type:%{labelEnd} %{reportType}"
msgstr ""
msgid "%{labelStart}Scanner:%{labelEnd} %{scanner}"
@@ -682,9 +734,6 @@ msgid_plural "%{securityScanner} results are not available because a pipeline ha
msgstr[0] ""
msgstr[1] ""
-msgid "%{service_title} %{message}."
-msgstr ""
-
msgid "%{size} GiB"
msgstr "%{size} GiB"
@@ -773,6 +822,12 @@ msgstr "%{text} está disponível"
msgid "%{timebox_name} should belong either to a project or a group."
msgstr ""
+msgid "%{timebox_type} does not support burnup charts"
+msgstr ""
+
+msgid "%{timebox_type} must have a start and due date"
+msgstr ""
+
msgid "%{title} %{operator} %{threshold}"
msgstr "%{title} %{operator} %{threshold}"
@@ -797,7 +852,7 @@ msgstr ""
msgid "%{total} open issue weight"
msgstr ""
-msgid "%{total} open issues"
+msgid "%{total} warnings found: showing first %{warningsDisplayed}"
msgstr ""
msgid "%{usage_ping_link_start}Learn more%{usage_ping_link_end} about what information is shared with GitLab Inc."
@@ -830,9 +885,6 @@ msgstr ""
msgid "&lt; 1 hour"
msgstr ""
-msgid "&lt;no name set&gt;"
-msgstr ""
-
msgid "&lt;no scopes selected&gt;"
msgstr ""
@@ -863,6 +915,9 @@ msgstr "'%{level}' não é um nível de visibilidade válido"
msgid "'%{name}' Value Stream created"
msgstr ""
+msgid "'%{name}' Value Stream deleted"
+msgstr ""
+
msgid "'%{name}' stage already exists"
msgstr ""
@@ -922,6 +977,9 @@ msgstr "+ mais %{moreCount}"
msgid "+ %{numberOfHiddenAssignees} more"
msgstr ""
+msgid "+ %{numberOfHiddenReviewers} more"
+msgstr ""
+
msgid "+%d more"
msgid_plural "+%d more"
msgstr[0] ""
@@ -982,6 +1040,11 @@ msgid_plural "%d Days"
msgstr[0] "1 Dia"
msgstr[1] "%d Dias"
+msgid "1 Issue"
+msgid_plural "%d Issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "1 closed issue"
msgid_plural "%{issues} closed issues"
msgstr[0] "1 problema encerrado"
@@ -997,6 +1060,11 @@ msgid_plural "%d days"
msgstr[0] ""
msgstr[1] ""
+msgid "1 deploy key"
+msgid_plural "%d deploy keys"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] "1 grupo"
@@ -1099,6 +1167,9 @@ msgstr "8 horas"
msgid ":%{startLine} to %{endLine}"
msgstr ""
+msgid "A %{incident_docs_start}modified issue%{incident_docs_end} to guide the resolution of incidents."
+msgstr ""
+
msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr "Um 'Executador' é um processo que executa um trabalho. Podes configurar tantos 'Executadores' quantos precisares."
@@ -1111,6 +1182,9 @@ msgstr ""
msgid "A GitBook site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr "Um site GitBook que usa o Netlify para CI/CD, em vez do GitLab, mas ainda com todos os outros ótimos recursos do GitLab."
+msgid "A Gitpod configured Webapplication in Spring and Java"
+msgstr ""
+
msgid "A Hexo site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr "Um site Hexo que usa o Netlify para CI/CD, em vez do GitLab, mas ainda com todos os outros ótimos recursos do GitLab."
@@ -1282,9 +1356,15 @@ msgstr "Acesso negado! Por favor, verifica se podes adicionar chaves de implanta
msgid "Access expiration date"
msgstr "Data de expiração do acesso"
+msgid "Access expires"
+msgstr ""
+
msgid "Access forbidden. Check your access level."
msgstr "Acesso proibido. Verifica o teu nível de acesso."
+msgid "Access granted"
+msgstr ""
+
msgid "Access requests"
msgstr ""
@@ -1294,6 +1374,9 @@ msgstr "Acesso a(ao) '%{classification_label}' não permitido"
msgid "Access to Pages websites are controlled based on the user's membership to a given project. By checking this box, users will be required to be logged in to have access to all Pages websites in your instance."
msgstr ""
+msgid "AccessDropdown|Deploy Keys"
+msgstr ""
+
msgid "AccessDropdown|Groups"
msgstr "Grupos"
@@ -1411,12 +1494,6 @@ msgstr ""
msgid "Active Sessions"
msgstr "Sessões Ativas"
-msgid "Active Users:"
-msgstr ""
-
-msgid "Active users"
-msgstr ""
-
msgid "Activity"
msgstr "Atividade"
@@ -1584,9 +1661,6 @@ msgstr ""
msgid "Add label(s)"
msgstr "Adicionar etiqueta(s)"
-msgid "Add license"
-msgstr "Adicionar licença"
-
msgid "Add list"
msgstr "Adicionar lista"
@@ -1761,21 +1835,51 @@ msgstr ""
msgid "AdminArea|Bots"
msgstr ""
+msgid "AdminArea|Components"
+msgstr ""
+
msgid "AdminArea|Developer"
msgstr ""
+msgid "AdminArea|Features"
+msgstr ""
+
+msgid "AdminArea|Groups: %{number_of_groups}"
+msgstr ""
+
msgid "AdminArea|Guest"
msgstr ""
msgid "AdminArea|Included Free in license"
msgstr ""
+msgid "AdminArea|Latest groups"
+msgstr ""
+
+msgid "AdminArea|Latest projects"
+msgstr ""
+
+msgid "AdminArea|Latest users"
+msgstr ""
+
msgid "AdminArea|Maintainer"
msgstr ""
+msgid "AdminArea|New group"
+msgstr ""
+
+msgid "AdminArea|New project"
+msgstr ""
+
+msgid "AdminArea|New user"
+msgstr ""
+
msgid "AdminArea|Owner"
msgstr ""
+msgid "AdminArea|Projects: %{number_of_projects}"
+msgstr ""
+
msgid "AdminArea|Reporter"
msgstr ""
@@ -1803,6 +1907,9 @@ msgstr ""
msgid "AdminArea|Users without a Group and Project"
msgstr ""
+msgid "AdminArea|Users: %{number_of_users}"
+msgstr ""
+
msgid "AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running."
msgstr "Estás prestes a parar todos os trabalhos. Isto irá interromper todos os trabalhos em execução."
@@ -1821,9 +1928,6 @@ msgstr "Apagar"
msgid "AdminProjects|Delete Project %{projectName}?"
msgstr "Apagar o Projeto %{projectName}?"
-msgid "AdminProjects|Delete project"
-msgstr "Apagar projeto"
-
msgid "AdminSettings|Apply integration settings to all Projects"
msgstr ""
@@ -2061,21 +2165,30 @@ msgstr ""
msgid "AdminUsers|Without projects"
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 %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 ""
msgid "AdminUsers|You cannot remove your own admin rights."
msgstr ""
+msgid "AdminUsers|You must transfer ownership or delete the groups owned by this user before you can delete their account"
+msgstr ""
+
msgid "Administration"
msgstr ""
msgid "Advanced"
msgstr "Avançado"
+msgid "Advanced Search"
+msgstr ""
+
+msgid "Advanced Search with Elasticsearch"
+msgstr ""
+
msgid "Advanced Settings"
msgstr ""
@@ -2153,6 +2266,9 @@ msgstr ""
msgid "AlertManagement|Edit"
msgstr ""
+msgid "AlertManagement|Environment"
+msgstr ""
+
msgid "AlertManagement|Events"
msgstr ""
@@ -2165,6 +2281,9 @@ msgstr ""
msgid "AlertManagement|Issue"
msgstr ""
+msgid "AlertManagement|Key"
+msgstr ""
+
msgid "AlertManagement|Low"
msgstr ""
@@ -2258,6 +2377,9 @@ msgstr ""
msgid "AlertManagement|Unknown"
msgstr ""
+msgid "AlertManagement|Value"
+msgstr ""
+
msgid "AlertManagement|View alerts in Opsgenie"
msgstr ""
@@ -2417,6 +2539,9 @@ msgstr ""
msgid "All projects"
msgstr "Todos os projetos"
+msgid "All projects selected"
+msgstr ""
+
msgid "All security scans are enabled because %{linkStart}Auto DevOps%{linkEnd} is enabled on this project"
msgstr ""
@@ -2504,6 +2629,9 @@ msgstr "Permite -te adicionar e gerir clusters do Kubernetes."
msgid "Almost there"
msgstr ""
+msgid "Already blocked"
+msgstr ""
+
msgid "Also called \"Issuer\" or \"Relying party trust identifier\""
msgstr "Também chamado de \"Emissor\" ou \"Identificador de confiança de terceiros\""
@@ -2558,6 +2686,9 @@ msgstr "Um campo vazio do Utilizador do GitLab adicionará o nome completo do ut
msgid "An error has occurred"
msgstr "Ocorreu um erro"
+msgid "An error occured while making the changes: %{error}"
+msgstr ""
+
msgid "An error occurred adding a draft to the thread."
msgstr ""
@@ -2585,12 +2716,6 @@ msgstr "Ocorreu um erro ao pré-visualizar o blob"
msgid "An error occurred when toggling the notification subscription"
msgstr "Ocorreu um erro ao alternar a notificação de assinatura"
-msgid "An error occurred when trying to resolve a comment. Please try again."
-msgstr "Ocorreu um erro ao tentar resolver um comentário. Por favor, tenta novamente."
-
-msgid "An error occurred when trying to resolve a discussion. Please try again."
-msgstr "Ocorreu um erro ao tentar resolver uma discussão. Por favor, tenta novamente."
-
msgid "An error occurred when updating the issue weight"
msgstr "Ocorreu um erro ao atualizar o peso do problema"
@@ -2606,12 +2731,6 @@ msgstr ""
msgid "An error occurred while checking group path. Please refresh and try again."
msgstr ""
-msgid "An error occurred while committing your changes."
-msgstr ""
-
-msgid "An error occurred while creating the list. Please try again."
-msgstr ""
-
msgid "An error occurred while decoding the file."
msgstr ""
@@ -2684,25 +2803,19 @@ msgstr ""
msgid "An error occurred while fetching the Service Desk address."
msgstr "Ocorreu um erro ao buscar o endereço da Central de Serviços."
-msgid "An error occurred while fetching the board issues. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the board lists. Please reload the page."
msgstr ""
msgid "An error occurred while fetching the board lists. Please try again."
msgstr "Ocorreu um erro ao buscar as listas do painel. Por favor, tenta novamente."
-msgid "An error occurred while fetching the board swimlanes. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the builds."
msgstr "Ocorreu um erro ao buscar as compilações."
msgid "An error occurred while fetching the job log."
msgstr "Ocorreu um erro ao buscar o registo do trabalho."
-msgid "An error occurred while fetching the job trace."
+msgid "An error occurred while fetching the job logs."
msgstr ""
msgid "An error occurred while fetching the job."
@@ -2849,9 +2962,6 @@ msgstr "Ocorreu um erro ao guardar o estado de sobreposição do LDAP. Por favor
msgid "An error occurred while saving assignees"
msgstr "Ocorreu um erro ao guardar destinatários"
-msgid "An error occurred while saving the template. Please check if the template exists."
-msgstr ""
-
msgid "An error occurred while searching for milestones"
msgstr ""
@@ -2870,12 +2980,12 @@ msgstr "Ocorreu um erro ao cancelar a assinatura das notificações."
msgid "An error occurred while updating approvers"
msgstr "Ocorreu um erro ao atualizar aprovadores"
+msgid "An error occurred while updating labels."
+msgstr ""
+
msgid "An error occurred while updating the comment"
msgstr "Ocorreu um erro ao atualizar o comentário"
-msgid "An error occurred while updating the list. Please try again."
-msgstr ""
-
msgid "An error occurred while validating group path"
msgstr ""
@@ -2927,6 +3037,9 @@ msgstr "Ocorreu um erro inesperado ao parar o Terminal Web."
msgid "An unknown error occurred while loading this graph."
msgstr ""
+msgid "An unknown error occurred."
+msgstr ""
+
msgid "Analytics"
msgstr "Estatísticas"
@@ -2960,10 +3073,10 @@ msgstr "Verificação de anti-spam"
msgid "Any"
msgstr "Qualquer"
-msgid "Any Author"
+msgid "Any %{header}"
msgstr ""
-msgid "Any Status"
+msgid "Any Author"
msgstr ""
msgid "Any branch"
@@ -3017,6 +3130,9 @@ msgstr "Aplicação"
msgid "Application ID"
msgstr "ID da Aplicação"
+msgid "Application limits saved successfully"
+msgstr ""
+
msgid "Application settings saved successfully"
msgstr "Definições da aplicação salvas com sucesso"
@@ -3226,6 +3342,9 @@ msgstr "Tens a certeza de que desejas cancelar a edição deste comentário?"
msgid "Are you sure you want to close this blocked issue?"
msgstr ""
+msgid "Are you sure you want to delete \"%{name}\" Value Stream?"
+msgstr ""
+
msgid "Are you sure you want to delete %{name}?"
msgstr ""
@@ -3235,6 +3354,9 @@ msgstr ""
msgid "Are you sure you want to delete this %{typeOfComment}?"
msgstr ""
+msgid "Are you sure you want to delete this SSH key?"
+msgstr ""
+
msgid "Are you sure you want to delete this board?"
msgstr ""
@@ -3259,6 +3381,11 @@ msgstr ""
msgid "Are you sure you want to erase this build?"
msgstr "Tens a certeza de que desejas apagar esta compilação?"
+msgid "Are you sure you want to import %d repository?"
+msgid_plural "Are you sure you want to import %d repositories?"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Are you sure you want to lose unsaved changes?"
msgstr "Tens a certeza de que queres perder as alterações não guardadas?"
@@ -3268,15 +3395,15 @@ msgstr "Tens a certeza de que desejas alterar as informações do teu perfil?"
msgid "Are you sure you want to merge immediately?"
msgstr ""
-msgid "Are you sure you want to permanently delete this license?"
-msgstr "Tens a certeza de que desejas apagar permanentemente esta licença?"
-
msgid "Are you sure you want to re-deploy this environment?"
msgstr ""
msgid "Are you sure you want to regenerate the public key? You will have to update the public key on the remote server before mirroring will work again."
msgstr "Tens a certeza de que pretendes gerar novamente a chave pública? Terás que atualizar a chave pública no servidor remoto para que a sincronização fique novamente a funcionar."
+msgid "Are you sure you want to reindex?"
+msgstr ""
+
msgid "Are you sure you want to remove %{group_name}?"
msgstr "Tens a certeza de que queres remover %{group_name}?"
@@ -3304,6 +3431,9 @@ msgstr ""
msgid "Are you sure you want to revoke this nickname?"
msgstr "Tens a certeza de que desejas revogar este apelido?"
+msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
+msgstr ""
+
msgid "Are you sure you want to stop this environment?"
msgstr "Tens a certeza de que desejas parar este ambiente?"
@@ -3325,6 +3455,9 @@ msgstr "Tens a certeza? Remover esta chave GPG não afeta as confirmações já
msgid "Are you sure? The device will be signed out of GitLab and all remember me tokens revoked."
msgstr ""
+msgid "Are you sure? This will invalidate your registered applications and U2F / WebAuthn devices."
+msgstr ""
+
msgid "Are you sure? This will invalidate your registered applications and U2F devices."
msgstr "Tens a certeza? Isto invalidará as tuas aplicações registadas e dispositivos U2F."
@@ -3343,9 +3476,6 @@ msgstr ""
msgid "Artifacts"
msgstr "Artefactos"
-msgid "As U2F devices are only supported by a few browsers, we require that you set up a two-factor authentication app before a U2F device. That way you'll always be able to log in - even when you're using an unsupported browser."
-msgstr "Como os dispositivos U2F são somente suportados por alguns navegadores, exigimos que configures uma aplicação de autenticação de dois fatores antes de um dispositivo U2F. Dessa forma, poderás sempre iniciar sessão, mesmo quando estiveres a usar um navegador não suportado."
-
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 ""
@@ -3539,6 +3669,9 @@ msgstr ""
msgid "AuditLogs|Target"
msgstr ""
+msgid "AuditLogs|This month"
+msgstr ""
+
msgid "AuditLogs|User Events"
msgstr ""
@@ -3578,6 +3711,9 @@ msgstr "Método de autenticação atualizado"
msgid "Authentication via U2F device failed."
msgstr "Falha na autenticação via dispositivo U2F."
+msgid "Authentication via WebAuthn device failed."
+msgstr ""
+
msgid "Author"
msgstr "Autor"
@@ -3845,15 +3981,6 @@ msgstr "URL raiz do Bamboo como https://bamboo.example.com"
msgid "BambooService|You must set up automatic revision labeling and a repository trigger in Bamboo."
msgstr "Deves configurar uma etiqueta de revisão automático e um disparador de repositório no Bamboo."
-msgid "BatchComments|Delete all pending comments"
-msgstr "Apagar todos os comentários pendentes"
-
-msgid "BatchComments|Discard review?"
-msgstr "Rejeitar revisão?"
-
-msgid "BatchComments|You're about to discard your review which will delete all of your pending comments. The deleted comments %{strong_start}cannot%{strong_end} be restored."
-msgstr "Estás prestes a rejeitar a tua revisão, o que apagará todos os teus comentários pendentes. Os comentários apagados %{strong_start}não podem%{strong_end} ser restaurados."
-
msgid "Be careful. Changing the project's namespace can have unintended side effects."
msgstr "Tem cuidado. Alterar o espaço de nomes do projeto pode ter efeitos secundários não intencionais."
@@ -3875,6 +4002,9 @@ msgstr "Abaixo vais encontrar todos os grupos que são públicos."
msgid "Bi-weekly code coverage"
msgstr ""
+msgid "Billable Users:"
+msgstr ""
+
msgid "Billing"
msgstr "Faturação"
@@ -3884,7 +4014,7 @@ msgstr ""
msgid "BillingPlans|@%{user_name} you are currently using the %{plan_name} plan."
msgstr ""
-msgid "BillingPlans|Congratulations, your new trial is activated"
+msgid "BillingPlans|Congratulations, your free trial is activated."
msgstr ""
msgid "BillingPlans|If you would like to downgrade your plan please contact %{support_link_start}Customer Support%{support_link_end}."
@@ -3947,6 +4077,9 @@ msgstr "Importar do Bitbucket"
msgid "Blame"
msgstr ""
+msgid "Block user"
+msgstr ""
+
msgid "Blocked"
msgstr "Bloqueado"
@@ -3962,31 +4095,37 @@ msgstr ""
msgid "Blog"
msgstr "Blogue"
-msgid "Board name"
-msgstr ""
-
msgid "Board scope"
msgstr ""
msgid "Board scope affects which issues are displayed for anyone who visits this board"
msgstr ""
-msgid "BoardBlankState|Add default lists"
-msgstr "Adicionar listas padrão"
+msgid "Boards"
+msgstr "Painéis"
-msgid "BoardBlankState|Add the following default lists to your Issue Board with one click:"
-msgstr "Adicionar as seguintes listas padrão para o teu Painel de Problema com um clique:"
+msgid "Boards and Board Lists"
+msgstr ""
-msgid "BoardBlankState|Nevermind, I'll use my own"
-msgstr "Deixa para lá, usarei por mim mesmo"
+msgid "Boards|An error occurred while creating the issue. Please try again."
+msgstr ""
-msgid "BoardBlankState|Starting out with the default set of lists will get you right on the way to making the most of your board."
-msgstr "Ao começar com o conjunto de listas padrão, estarás no caminho certo para aproveitar ao máximo o teu painel."
+msgid "Boards|An error occurred while creating the list. Please try again."
+msgstr ""
-msgid "Boards"
-msgstr "Painéis"
+msgid "Boards|An error occurred while fetching issues. Please reload the page."
+msgstr ""
-msgid "Boards and Board Lists"
+msgid "Boards|An error occurred while fetching the board issues. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching the board swimlanes. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while moving the issue. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while updating the list. Please try again."
msgstr ""
msgid "Boards|Collapse"
@@ -4013,8 +4152,8 @@ msgstr "O ramo %{branchName} não foi encontrado no repositório deste projeto."
msgid "Branch %{branch_name} was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr ""
-msgid "Branch has changed"
-msgstr "Ramo foi alterado"
+msgid "Branch changed"
+msgstr ""
msgid "Branch is already taken"
msgstr "Ramo já está a ser usado"
@@ -4319,6 +4458,9 @@ msgstr ""
msgid "CLOSED (MOVED)"
msgstr ""
+msgid "CODEOWNERS rule violation"
+msgstr ""
+
msgid "CONTRIBUTING"
msgstr "CONTRIBUTING"
@@ -4349,9 +4491,6 @@ msgstr ""
msgid "Can't create snippet: %{err}"
msgstr ""
-msgid "Can't edit as source branch was deleted"
-msgstr ""
-
msgid "Can't fetch content for the blob: %{err}"
msgstr ""
@@ -4364,9 +4503,6 @@ msgstr "Não foi possível encontrar a variável: ZiteReader"
msgid "Can't load mermaid module: %{err}"
msgstr ""
-msgid "Can't remove group members without group managed account"
-msgstr "Não é possível remover membros do grupo sem conta gerenciada do grupo"
-
msgid "Can't scan the code?"
msgstr "Não consegues digitalizar o código?"
@@ -4409,6 +4545,9 @@ msgstr "Não foi possível criar o relatório de abuso. O utilizador foi apagado
msgid "Cannot create the abuse report. This user has been blocked."
msgstr "Não foi possível criar o relatório de abuso. Este utilizador foi bloqueado."
+msgid "Cannot enable shared runners because parent group does not allow it"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -4514,6 +4653,15 @@ msgstr "Alterar a tua palavra-passe"
msgid "Change your password or recover your current one"
msgstr "Altera a tua palavra-passe ou recupera a tua atual"
+msgid "ChangeReviewer|Reviewer changed from %{old} to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Reviewer changed to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Unassigned"
+msgstr ""
+
msgid "ChangeTypeActionLabel|Pick into branch"
msgstr "Escolher no ramo"
@@ -4553,6 +4701,9 @@ msgstr "Alterações suprimidas Clica para mostrar."
msgid "Changes the title to \"%{title_param}\"."
msgstr "Altera o título para \"%{title_param}\"."
+msgid "Changes were successfully made."
+msgstr ""
+
msgid "Changes won't take place until the index is %{link_start}recreated%{link_end}."
msgstr "As alterações não terão lugar até que o índice seja %{link_start}recriado%{link_end}."
@@ -4958,6 +5109,9 @@ msgstr "Mascarado"
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove variable"
+msgstr ""
+
msgid "CiVariables|Remove variable row"
msgstr "Remover linha da variável"
@@ -5036,9 +5190,6 @@ msgstr ""
msgid "Clear due date"
msgstr ""
-msgid "Clear input"
-msgstr "Limpar entrada"
-
msgid "Clear recent searches"
msgstr ""
@@ -5087,6 +5238,9 @@ msgstr "Chave de autenticação do cliente"
msgid "Client authentication key password"
msgstr "Palavra-chave de autenticação do cliente"
+msgid "Client request timeout"
+msgstr ""
+
msgid "Clients"
msgstr "Clientes"
@@ -5171,6 +5325,27 @@ msgstr ""
msgid "Cluster type must be specificed for Stages::ClusterEndpointInserter"
msgstr ""
+msgid "ClusterAgents|Configuration"
+msgstr ""
+
+msgid "ClusterAgents|Connect your cluster with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate Kubernetes with a GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Name"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Agent also requires %{linkStart}enabling the Agent Server%{linkEnd}"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Kubernetes Agent allows an Infrastructure as Code, GitOps approach to integrating Kubernetes clusters with GitLab. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "ClusterAgent|This feature is only available for premium plans"
msgstr ""
@@ -5240,10 +5415,10 @@ msgstr "Todos os dados serão apagados e não podem ser restaurados."
msgid "ClusterIntegration|All installed applications and related resources"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster."
-msgstr "Permitir que o GitLab gerêncie contas de espaço de nome e de serviço para este cluster."
+msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{linkStart}More information%{linkEnd}"
+msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{startLink}More information%{endLink}"
+msgid "ClusterIntegration|Allow GitLab to manage namespaces and service accounts for this cluster."
msgstr ""
msgid "ClusterIntegration|Alternatively, "
@@ -5264,6 +5439,9 @@ msgstr "Ocorreu um erro ao tentar buscar os teus projetos: %{error}"
msgid "ClusterIntegration|An error occurred while trying to fetch zone machine types: %{error}"
msgstr "Ocorreu um erro ao tentar buscar as máquinas da zona: %{error}"
+msgid "ClusterIntegration|An unknown error occurred while attempting to connect to Kubernetes."
+msgstr ""
+
msgid "ClusterIntegration|Any project namespaces"
msgstr ""
@@ -5279,6 +5457,9 @@ msgstr ""
msgid "ClusterIntegration|Authenticate with Amazon Web Services"
msgstr ""
+msgid "ClusterIntegration|Authentication Error"
+msgstr ""
+
msgid "ClusterIntegration|Base domain"
msgstr "Domínio base"
@@ -5297,13 +5478,22 @@ msgstr ""
msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
msgstr "Pacote de Autoridade de Certificados (formato PEM)"
-msgid "ClusterIntegration|Choose the %{startLink}security group %{externalLinkIcon} %{endLink} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
+msgid "ClusterIntegration|Check your CA certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Check your cluster status"
+msgstr ""
+
+msgid "ClusterIntegration|Check your token"
+msgstr ""
+
+msgid "ClusterIntegration|Choose the %{linkStart}security group %{linkEnd} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}subnets %{externalLinkIcon} %{endLink} in your VPC where your worker nodes will run."
+msgid "ClusterIntegration|Choose the %{linkStart}subnets %{linkEnd} in your VPC where your worker nodes will run."
msgstr ""
-msgid "ClusterIntegration|Choose the worker node %{startLink}instance type %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Choose the worker node %{linkStart}instance type%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Choose which applications to install on your Kubernetes cluster."
@@ -5315,10 +5505,7 @@ msgstr "Escolhe qual dos teus ambientes usarás este cluster."
msgid "ClusterIntegration|Clear cluster cache"
msgstr ""
-msgid "ClusterIntegration|Clear the local cache of namespace and service accounts. This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
-msgstr ""
-
-msgid "ClusterIntegration|Cluster being created"
+msgid "ClusterIntegration|Clear the local cache of namespace and service accounts."
msgstr ""
msgid "ClusterIntegration|Cluster management project (alpha)"
@@ -5330,15 +5517,21 @@ msgstr "O nome do cluster é obrigatório."
msgid "ClusterIntegration|Cluster_applications artifact too big. Maximum allowable size: %{human_size}"
msgstr ""
-msgid "ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters."
-msgstr "Os clusters são utilizados ao selecionar o antepassado mais próximo com um contexto de ambiente correspondente. Por exemplo, os clusters de projeto substituirão os clusters de grupo."
-
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|Clusters connected with a certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Connect cluster with certificate"
+msgstr ""
+
msgid "ClusterIntegration|Connect existing cluster"
msgstr ""
+msgid "ClusterIntegration|Connection Error"
+msgstr ""
+
msgid "ClusterIntegration|Copy API URL"
msgstr " Copiar URL da API"
@@ -5414,6 +5607,12 @@ msgstr ""
msgid "ClusterIntegration|Deletes all GitLab resources attached to this cluster during removal"
msgstr ""
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared."
+msgstr ""
+
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared. %{linkStart}More information%{linkEnd}"
+msgstr ""
+
msgid "ClusterIntegration|Did you know?"
msgstr "Sabias que?"
@@ -5483,6 +5682,9 @@ msgstr ""
msgid "ClusterIntegration|Fluentd is an open source data collector, which lets you unify the data collection and consumption for a better use and understanding of data. It requires at least one of the following logs to be successfully installed."
msgstr ""
+msgid "ClusterIntegration|GitLab Agent managed clusters"
+msgstr ""
+
msgid "ClusterIntegration|GitLab Container Network Policies"
msgstr ""
@@ -5495,6 +5697,12 @@ msgstr "Executador do GitLab"
msgid "ClusterIntegration|GitLab Runner connects to the repository and executes CI/CD jobs, pushing results back and deploying applications to production."
msgstr "O Executador do GitLab conecta-se ao repositório e executa os trabalhos CI/CD, ao empurrar os resultados para trás e implementar aplicações para produção."
+msgid "ClusterIntegration|GitLab failed to authenticate."
+msgstr ""
+
+msgid "ClusterIntegration|GitLab failed to connect to the cluster."
+msgstr ""
+
msgid "ClusterIntegration|GitLab-managed cluster"
msgstr "Cluster gerido por GitLab"
@@ -5516,6 +5724,9 @@ msgstr " Projeto do Google Kubernetes Engine"
msgid "ClusterIntegration|Group cluster"
msgstr "Cluster de grupo"
+msgid "ClusterIntegration|HTTP Error"
+msgstr ""
+
msgid "ClusterIntegration|Helm Tiller"
msgstr "Helm Tiller"
@@ -5549,8 +5760,11 @@ msgstr "Cluster de instância"
msgid "ClusterIntegration|Instance type"
msgstr ""
-msgid "ClusterIntegration|Integrate Kubernetes cluster automation"
-msgstr "Integrar automação de cluster Kubernetes"
+msgid "ClusterIntegration|Integrate Kubernetes with a cluster certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Integrate with a cluster certificate"
+msgstr ""
msgid "ClusterIntegration|Issuer Email"
msgstr "Email do emissor"
@@ -5585,9 +5799,6 @@ msgstr "O nome de domínio do Knative foi atualizado com sucesso."
msgid "ClusterIntegration|Knative extends Kubernetes to provide a set of middleware components that are essential to build modern, source-centric, and container-based applications that can run anywhere: on premises, in the cloud, or even in a third-party data center."
msgstr "Knative estende o Kubernetes para fornecer um conjunto de componentes de middleware que são essenciais para construir modernas, centrado na origem, aplicações baseadas em contentor que podem ser executados em qualquer lugar: no local, na nuvem, ou até mesmo num terceiro centro de dados."
-msgid "ClusterIntegration|Kubernetes cluster"
-msgstr "Cluster do Kubernetes"
-
msgid "ClusterIntegration|Kubernetes cluster is being created..."
msgstr ""
@@ -5600,9 +5811,6 @@ msgstr ""
msgid "ClusterIntegration|Kubernetes clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr "Com um cluster Kubernetes associado a este projeto, podes utilizar apps de revisão, publicar as tuas aplicações, executar as tuas pipelines e muito mais de uma maneira simples."
-msgid "ClusterIntegration|Kubernetes clusters can be used to deploy applications and to provide Review Apps for this project"
-msgstr "Os clusters Kubernetes podem ser usados para implementar aplicações e fornecer Revisão de Aplicações para este projeto"
-
msgid "ClusterIntegration|Kubernetes version"
msgstr ""
@@ -5615,7 +5823,7 @@ msgstr "Aprende mais sobre %{help_link_start_machine_type}tipos de máquina%{hel
msgid "ClusterIntegration|Learn more about %{help_link_start}zones%{help_link_end}."
msgstr "Aprende mais sobre %{help_link_start}zonas%{help_link_end}."
-msgid "ClusterIntegration|Learn more about %{startLink}Regions %{externalLinkIcon}%{endLink}."
+msgid "ClusterIntegration|Learn more about %{linkStart}Regions%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Learn more about Kubernetes"
@@ -5660,12 +5868,18 @@ msgstr ""
msgid "ClusterIntegration|Machine type"
msgstr "Tipo de máquina"
+msgid "ClusterIntegration|Make sure your API endpoint is correct"
+msgstr ""
+
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create Kubernetes clusters"
msgstr "Certifica-te de que tua conta %{link_to_requirements} para criar clusters Kubernetes"
msgid "ClusterIntegration|Manage your Kubernetes cluster by visiting %{provider_link}"
msgstr ""
+msgid "ClusterIntegration|Namespace per environment"
+msgstr ""
+
msgid "ClusterIntegration|No IAM Roles found"
msgstr ""
@@ -5711,6 +5925,9 @@ msgstr ""
msgid "ClusterIntegration|No zones matched your search"
msgstr "Nenhuma zona correspondeu à tua pesquisa"
+msgid "ClusterIntegration|Node calculations use the Kubernetes Metrics API. Make sure your cluster has metrics installed"
+msgstr ""
+
msgid "ClusterIntegration|Number of nodes"
msgstr "Número de nós"
@@ -5753,6 +5970,9 @@ msgstr ""
msgid "ClusterIntegration|RBAC-enabled cluster"
msgstr "Cluster ativado pelo RBAC"
+msgid "ClusterIntegration|Read our %{linkStart}help page%{linkEnd} on Kubernetes cluster integration."
+msgstr ""
+
msgid "ClusterIntegration|Read our %{link_start}help page%{link_end} on Kubernetes cluster integration."
msgstr ""
@@ -5855,7 +6075,7 @@ msgstr ""
msgid "ClusterIntegration|Select a VPC to choose a subnet"
msgstr ""
-msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{linkStart}Amazon Web Services %{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select a network to choose a subnetwork"
@@ -5888,7 +6108,7 @@ msgstr "Selecionar projeto e zona para escolher o tipo de máquina"
msgid "ClusterIntegration|Select project to choose zone"
msgstr "Selecionar projeto para escolher a zona"
-msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select zone"
@@ -5978,9 +6198,18 @@ msgstr ""
msgid "ClusterIntegration|There was a problem authenticating with your cluster. Please ensure your CA Certificate and Token are valid."
msgstr "Houve um problema ao autenticar com o teu cluster. Por favor, certifica-te de que o teu Certificado e Token da CA são válidos."
+msgid "ClusterIntegration|There was an HTTP error when connecting to your cluster."
+msgstr ""
+
msgid "ClusterIntegration|This account must have permissions to create a Kubernetes cluster in the %{link_to_container_project} specified below"
msgstr "Esta conta precisa de permissões para criar um cluster Kubernetes no %{link_to_container_project} especificado"
+msgid "ClusterIntegration|This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
+msgstr ""
+
+msgid "ClusterIntegration|This is necessary to clear existing environment-namespace associations from clusters previously managed by GitLab."
+msgstr ""
+
msgid "ClusterIntegration|This option will allow you to install applications on RBAC clusters."
msgstr "Esta opção permite-te instalar aplicações no RBAC clusters."
@@ -6005,9 +6234,21 @@ msgstr ""
msgid "ClusterIntegration|To use a new project, first create one on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}."
msgstr ""
+msgid "ClusterIntegration|Troubleshooting tips:"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Authenticate"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Connect"
+msgstr ""
+
msgid "ClusterIntegration|Uninstall %{appTitle}"
msgstr "Desinstalar %{appTitle}"
+msgid "ClusterIntegration|Unknown Error"
+msgstr ""
+
msgid "ClusterIntegration|Update %{appTitle}"
msgstr ""
@@ -6068,7 +6309,7 @@ msgstr ""
msgid "ClusterIntegration|Your cluster API is unreachable. Please ensure your API URL is correct."
msgstr ""
-msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Zone"
@@ -6188,6 +6429,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse all threads"
+msgstr ""
+
msgid "Collapse approvers"
msgstr ""
@@ -6337,7 +6581,7 @@ msgstr ""
msgid "Commit…"
msgstr ""
-msgid "Company"
+msgid "Community forum"
msgstr ""
msgid "Company name"
@@ -6346,6 +6590,9 @@ msgstr ""
msgid "Compare"
msgstr ""
+msgid "Compare %{oldCommitId}...%{newCommitId}"
+msgstr ""
+
msgid "Compare Git revisions"
msgstr ""
@@ -6361,6 +6608,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare submodule commit revisions"
+msgstr ""
+
msgid "Compare with previous version"
msgstr ""
@@ -6496,6 +6746,9 @@ msgstr ""
msgid "Configure the way a user creates a new account."
msgstr ""
+msgid "Configure which lists are shown for anyone who visits this board"
+msgstr ""
+
msgid "Confirm"
msgstr ""
@@ -6721,6 +6974,9 @@ msgstr[1] ""
msgid "ContainerRegistry|Set cleanup policy"
msgstr ""
+msgid "ContainerRegistry|Some tags were not deleted"
+msgstr ""
+
msgid "ContainerRegistry|Something went wrong while fetching the cleanup policy."
msgstr ""
@@ -6760,6 +7016,9 @@ msgstr ""
msgid "ContainerRegistry|Tags with names matching this regex pattern will %{italicStart}expire:%{italicEnd}"
msgstr ""
+msgid "ContainerRegistry|The cleanup policy timed out before it could delete all tags. An administrator can %{adminLinkStart}manually run cleanup now%{adminLinkEnd} or you can wait for the cleanup policy to automatically run again. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "ContainerRegistry|The last tag related to this image was recently removed. This empty image and any associated data will be automatically removed as part of the regular Garbage Collection process. If you have any questions, contact your administrator."
msgstr ""
@@ -6892,6 +7151,9 @@ msgstr ""
msgid "Contributions per group member"
msgstr ""
+msgid "Contributor"
+msgstr ""
+
msgid "Contributors"
msgstr ""
@@ -7021,6 +7283,9 @@ msgstr ""
msgid "Could not change HEAD: branch '%{branch}' does not exist"
msgstr ""
+msgid "Could not commit. An unexpected error occurred."
+msgstr ""
+
msgid "Could not connect to FogBugz, check your URL"
msgstr ""
@@ -7060,6 +7325,9 @@ msgstr ""
msgid "Could not find iteration"
msgstr ""
+msgid "Could not load instance counts. Please refresh the page to try again."
+msgstr ""
+
msgid "Could not remove the trigger."
msgstr ""
@@ -7084,10 +7352,10 @@ msgstr ""
msgid "Could not save prometheus manual configuration"
msgstr ""
-msgid "Could not udpdate wiki page"
+msgid "Could not update the LDAP settings"
msgstr ""
-msgid "Could not update the LDAP settings"
+msgid "Could not update wiki page"
msgstr ""
msgid "Could not upload your designs as one or more files uploaded are not supported."
@@ -7745,6 +8013,9 @@ msgstr ""
msgid "DastProfiles|Are you sure you want to delete this profile?"
msgstr ""
+msgid "DastProfiles|Could not create site validation token. Please refresh the page, or try again later."
+msgstr ""
+
msgid "DastProfiles|Could not create the scanner profile. Please try again."
msgstr ""
@@ -7769,6 +8040,12 @@ msgstr ""
msgid "DastProfiles|Could not fetch site profiles. Please refresh the page, or try again later."
msgstr ""
+msgid "DastProfiles|Could not retrieve site validation status. Please refresh the page, or try again later."
+msgstr ""
+
+msgid "DastProfiles|Could not update the scanner profile. Please try again."
+msgstr ""
+
msgid "DastProfiles|Could not update the site profile. Please try again."
msgstr ""
@@ -7784,7 +8061,7 @@ msgstr ""
msgid "DastProfiles|Download validation text file"
msgstr ""
-msgid "DastProfiles|Edit feature will come soon. Please create a new profile if changes needed"
+msgid "DastProfiles|Edit scanner profile"
msgstr ""
msgid "DastProfiles|Edit site profile"
@@ -7817,6 +8094,9 @@ msgstr ""
msgid "DastProfiles|No profiles created yet"
msgstr ""
+msgid "DastProfiles|Passive"
+msgstr ""
+
msgid "DastProfiles|Please enter a valid URL format, ex: http://www.example.com/home"
msgstr ""
@@ -7832,6 +8112,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan mode"
+msgstr ""
+
msgid "DastProfiles|Scanner Profile"
msgstr ""
@@ -7871,10 +8154,10 @@ msgstr ""
msgid "DastProfiles|Text file validation"
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
+msgid "DastProfiles|The maximum number of minutes allowed for the spider to traverse the site."
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the spider to traverse the site."
+msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
msgstr ""
msgid "DastProfiles|Validate"
@@ -7907,6 +8190,9 @@ msgstr ""
msgid "Date picker"
msgstr ""
+msgid "Date range"
+msgstr ""
+
msgid "Date range cannot exceed %{maxDateRange} days."
msgstr ""
@@ -7931,6 +8217,9 @@ msgstr ""
msgid "Days to merge"
msgstr ""
+msgid "Dear Administrator,"
+msgstr ""
+
msgid "Debug"
msgstr ""
@@ -8042,12 +8331,18 @@ msgstr ""
msgid "Delete"
msgstr ""
+msgid "Delete %{name}"
+msgstr ""
+
msgid "Delete Comment"
msgstr ""
msgid "Delete Snippet"
msgstr ""
+msgid "Delete Value Stream"
+msgstr ""
+
msgid "Delete account"
msgstr ""
@@ -8069,9 +8364,6 @@ msgstr ""
msgid "Delete label: %{label_name} ?"
msgstr ""
-msgid "Delete license"
-msgstr ""
-
msgid "Delete list"
msgstr ""
@@ -8147,15 +8439,6 @@ msgstr ""
msgid "Deleting a project places it into a read-only state until %{date}, at which point the project will be permanently deleted. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "Deleting the license failed."
-msgstr "Ocorreu um erro ao apagar a licença."
-
-msgid "Deleting the license failed. The license was not found."
-msgstr ""
-
-msgid "Deleting the license failed. You are not permitted to perform this action."
-msgstr "Ocorreu um erro ao apagar a licença. Não tens permissões para realizar esta operação."
-
msgid "Deleting the project will delete its repository and all related resources including issues, merge requests etc."
msgstr ""
@@ -8651,7 +8934,10 @@ msgstr ""
msgid "DesignManagement|The maximum number of designs allowed to be uploaded is %{upload_limit}. Please try again."
msgstr ""
-msgid "DesignManagement|To upload designs, you'll need to enable LFS. %{requirements_link_start}More information%{requirements_link_end}"
+msgid "DesignManagement|There was an error moving your designs. Please upload your designs below."
+msgstr ""
+
+msgid "DesignManagement|To upload designs, you'll need to enable LFS and have admin enable hashed storage. %{requirements_link_start}More information%{requirements_link_end}"
msgstr ""
msgid "DesignManagement|Unresolve thread"
@@ -8663,6 +8949,9 @@ msgstr ""
msgid "DesignManagement|Upload skipped."
msgstr ""
+msgid "DesignManagement|Your designs are being copied and are on their way… Please refresh to update."
+msgstr ""
+
msgid "DesignManagement|and %{moreCount} more."
msgstr ""
@@ -8720,6 +9009,9 @@ msgstr ""
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
+msgid "Direct member"
+msgstr ""
+
msgid "Direction"
msgstr ""
@@ -8768,9 +9060,6 @@ msgstr ""
msgid "Discard draft"
msgstr ""
-msgid "Discard review"
-msgstr ""
-
msgid "DiscordService|Discord Notifications"
msgstr ""
@@ -8839,10 +9128,10 @@ msgstr ""
msgid "Dismiss Merge Request promotion"
msgstr ""
-msgid "Dismiss Selected"
+msgid "Dismiss Value Stream Analytics introduction box"
msgstr ""
-msgid "Dismiss Value Stream Analytics introduction box"
+msgid "Dismiss selected"
msgstr ""
msgid "Dismiss trial promotion"
@@ -8893,9 +9182,6 @@ msgstr ""
msgid "Documents reindexed: %{processed_documents} (%{percentage}%%)"
msgstr ""
-msgid "Doing"
-msgstr ""
-
msgid "Domain"
msgstr ""
@@ -9091,9 +9377,6 @@ msgstr ""
msgid "Edit environment"
msgstr ""
-msgid "Edit file"
-msgstr ""
-
msgid "Edit files in the editor and commit changes here"
msgstr ""
@@ -9106,6 +9389,12 @@ msgstr ""
msgid "Edit identity for %{user_name}"
msgstr ""
+msgid "Edit in Web IDE"
+msgstr ""
+
+msgid "Edit in single-file editor"
+msgstr ""
+
msgid "Edit issues"
msgstr ""
@@ -9133,10 +9422,10 @@ msgstr ""
msgid "Editing"
msgstr ""
-msgid "Elasticsearch"
+msgid "Elasticsearch AWS IAM credentials"
msgstr ""
-msgid "Elasticsearch AWS IAM credentials"
+msgid "Elasticsearch HTTP client timeout value in seconds."
msgstr ""
msgid "Elasticsearch indexing restrictions"
@@ -9145,9 +9434,6 @@ msgstr ""
msgid "Elasticsearch indexing started"
msgstr ""
-msgid "Elasticsearch integration. Elasticsearch AWS IAM."
-msgstr ""
-
msgid "Elasticsearch reindexing is already in progress"
msgstr ""
@@ -9175,9 +9461,6 @@ msgstr ""
msgid "Email Notification"
msgstr ""
-msgid "Email address"
-msgstr "Endereço de email"
-
msgid "Email could not be sent"
msgstr ""
@@ -9241,6 +9524,9 @@ msgstr ""
msgid "Emails sent from Service Desk will have this name"
msgstr ""
+msgid "Emails sent to %{email} will still be supported"
+msgstr ""
+
msgid "Emails separated by comma"
msgstr ""
@@ -9274,9 +9560,18 @@ msgstr ""
msgid "Enable"
msgstr ""
+msgid "Enable %{link_start}Gitpod%{link_end} integration to launch a development environment in your browser directly from GitLab."
+msgstr ""
+
msgid "Enable Auto DevOps"
msgstr ""
+msgid "Enable Gitpod"
+msgstr ""
+
+msgid "Enable Gitpod?"
+msgstr ""
+
msgid "Enable HTML emails"
msgstr ""
@@ -9406,9 +9701,6 @@ msgstr ""
msgid "Encountered an error while rendering: %{err}"
msgstr ""
-msgid "End date"
-msgstr ""
-
msgid "Ends at (UTC)"
msgstr ""
@@ -9568,7 +9860,7 @@ msgstr ""
msgid "EnvironmentsDashboard|The environments dashboard provides a summary of each project's environments' status, including pipeline and alert statuses."
msgstr ""
-msgid "EnvironmentsDashboard|This dashboard displays a maximum of 7 projects and 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
+msgid "EnvironmentsDashboard|This dashboard displays 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
msgstr ""
msgid "Environments|An error occurred while canceling the auto stop, please try again"
@@ -9889,6 +10181,9 @@ msgstr ""
msgid "Error deleting project. Check logs for error details."
msgstr ""
+msgid "Error fetching burnup chart data"
+msgstr ""
+
msgid "Error fetching diverging counts for branches. Please try again."
msgstr ""
@@ -9967,6 +10262,9 @@ msgstr ""
msgid "Error occurred when saving assignees"
msgstr ""
+msgid "Error occurred when saving reviewers"
+msgstr ""
+
msgid "Error occurred when toggling the notification subscription"
msgstr ""
@@ -10219,10 +10517,13 @@ msgstr ""
msgid "Expand all"
msgstr ""
-msgid "Expand approvers"
+msgid "Expand all files"
+msgstr ""
+
+msgid "Expand all threads"
msgstr ""
-msgid "Expand dropdown"
+msgid "Expand approvers"
msgstr ""
msgid "Expand milestones"
@@ -10393,6 +10694,9 @@ msgstr ""
msgid "Failed to create Merge Request. Please try again."
msgstr ""
+msgid "Failed to create To-Do for the design."
+msgstr ""
+
msgid "Failed to create a branch for this issue. Please try again."
msgstr ""
@@ -10432,6 +10736,12 @@ msgstr ""
msgid "Failed to load authors. Please try again."
msgstr ""
+msgid "Failed to load branches. Please try again."
+msgstr ""
+
+msgid "Failed to load deploy keys."
+msgstr ""
+
msgid "Failed to load emoji list."
msgstr ""
@@ -10447,6 +10757,9 @@ msgstr ""
msgid "Failed to load groups & users."
msgstr ""
+msgid "Failed to load groups, users and deploy keys."
+msgstr ""
+
msgid "Failed to load labels. Please try again."
msgstr ""
@@ -10456,6 +10769,12 @@ msgstr ""
msgid "Failed to load related branches"
msgstr ""
+msgid "Failed to load sidebar confidential toggle"
+msgstr ""
+
+msgid "Failed to load sidebar lock status"
+msgstr ""
+
msgid "Failed to load stacktrace."
msgstr ""
@@ -10483,6 +10802,9 @@ msgstr ""
msgid "Failed to publish issue on status page."
msgstr ""
+msgid "Failed to remove To-Do for the design."
+msgstr ""
+
msgid "Failed to remove a Zoom meeting"
msgstr ""
@@ -10525,6 +10847,9 @@ msgstr ""
msgid "Failed to signing using smartcard authentication"
msgstr ""
+msgid "Failed to toggle To-Do for the design."
+msgstr ""
+
msgid "Failed to update branch!"
msgstr ""
@@ -10638,7 +10963,7 @@ msgstr ""
msgid "FeatureFlags|Edit User List"
msgstr ""
-msgid "FeatureFlags|Enable features for specific users and specific environments by defining feature flag strategies."
+msgid "FeatureFlags|Enable features for specific users and environments by configuring feature flag strategies."
msgstr ""
msgid "FeatureFlags|Environment Spec"
@@ -10698,7 +11023,7 @@ msgstr ""
msgid "FeatureFlags|Include additional user IDs"
msgstr ""
-msgid "FeatureFlags|Install a %{docs_link_anchored_start}compatible client library%{docs_link_anchored_end} and specify the API URL, application name, and instance ID during the configuration setup. %{docs_link_start}More Information%{docs_link_end}"
+msgid "FeatureFlags|Install a %{docsLinkAnchoredStart}compatible client library%{docsLinkAnchoredEnd} and specify the API URL, application name, and instance ID during the configuration setup. %{docsLinkStart}More Information%{docsLinkEnd}"
msgstr ""
msgid "FeatureFlags|Instance ID"
@@ -10710,6 +11035,9 @@ msgstr ""
msgid "FeatureFlags|Loading feature flags"
msgstr ""
+msgid "FeatureFlags|Loading user lists"
+msgstr ""
+
msgid "FeatureFlags|More information"
msgstr ""
@@ -10728,7 +11056,7 @@ msgstr ""
msgid "FeatureFlags|New feature flag"
msgstr ""
-msgid "FeatureFlags|New list"
+msgid "FeatureFlags|New user list"
msgstr ""
msgid "FeatureFlags|Percent of users"
@@ -10767,6 +11095,9 @@ msgstr ""
msgid "FeatureFlags|There was an error fetching the feature flags."
msgstr ""
+msgid "FeatureFlags|There was an error fetching the user lists."
+msgstr ""
+
msgid "FeatureFlags|There was an error retrieving user lists"
msgstr ""
@@ -10782,6 +11113,9 @@ msgstr ""
msgid "FeatureFlags|User List"
msgstr ""
+msgid "FeatureFlags|User Lists"
+msgstr ""
+
msgid "FeatureFlag|List"
msgstr ""
@@ -10809,15 +11143,6 @@ msgstr ""
msgid "Fetching incoming email"
msgstr ""
-msgid "Fetching licenses failed."
-msgstr ""
-
-msgid "Fetching licenses failed. The request endpoint was not found."
-msgstr ""
-
-msgid "Fetching licenses failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "File"
msgstr ""
@@ -10920,12 +11245,21 @@ msgstr ""
msgid "Filter by status"
msgstr ""
+msgid "Filter by test cases that are currently archived."
+msgstr ""
+
+msgid "Filter by test cases that are currently opened."
+msgstr ""
+
msgid "Filter by two-factor authentication"
msgstr ""
msgid "Filter by user"
msgstr ""
+msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
+msgstr ""
+
msgid "Filter pipelines"
msgstr ""
@@ -10941,7 +11275,7 @@ msgstr ""
msgid "Filter results..."
msgstr ""
-msgid "Filter your projects by name"
+msgid "Filter your repositories by name"
msgstr ""
msgid "Filter..."
@@ -10950,7 +11284,7 @@ msgstr ""
msgid "Find File"
msgstr ""
-msgid "Find bugs in your code with coverage-guided fuzzing"
+msgid "Find bugs in your code with coverage-guided fuzzing."
msgstr ""
msgid "Find by path"
@@ -10977,9 +11311,6 @@ msgstr ""
msgid "Finish editing this message first!"
msgstr ""
-msgid "Finish review"
-msgstr ""
-
msgid "Finish setting up your dedicated account for %{group_name}."
msgstr ""
@@ -11049,6 +11380,9 @@ msgstr ""
msgid "Footer message"
msgstr ""
+msgid "For a faster browsing experience, some files are collapsed by default."
+msgstr ""
+
msgid "For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
@@ -11058,6 +11392,9 @@ msgstr ""
msgid "For more info, read the documentation."
msgstr ""
+msgid "For more information on how the number of active users is calculated, see the %{self_managed_subscriptions_doc_link} documentation."
+msgstr ""
+
msgid "For more information, go to the "
msgstr ""
@@ -11196,6 +11533,9 @@ msgstr ""
msgid "Generate new token"
msgstr ""
+msgid "Generic package file size in bytes"
+msgstr ""
+
msgid "Geo"
msgstr ""
@@ -11457,6 +11797,9 @@ msgstr ""
msgid "Geo|Please refer to Geo Troubleshooting."
msgstr ""
+msgid "Geo|Primary node"
+msgstr ""
+
msgid "Geo|Project"
msgstr ""
@@ -11499,6 +11842,9 @@ msgstr ""
msgid "Geo|Review replication status, and resynchronize and reverify items with the primary node."
msgstr ""
+msgid "Geo|Secondary node"
+msgstr ""
+
msgid "Geo|Status"
msgstr ""
@@ -11538,6 +11884,9 @@ msgstr ""
msgid "Geo|URL must be a valid url (ex: https://gitlab.com)"
msgstr ""
+msgid "Geo|Undefined"
+msgstr ""
+
msgid "Geo|Unknown state"
msgstr ""
@@ -11613,10 +11962,16 @@ msgstr ""
msgid "GitHub import"
msgstr ""
+msgid "GitLab"
+msgstr ""
+
msgid "GitLab / Unsubscribe"
msgstr ""
-msgid "GitLab Enterprise Edition %{plan}"
+msgid "GitLab API"
+msgstr ""
+
+msgid "GitLab Billing Team."
msgstr ""
msgid "GitLab Group Runners can execute code for all the projects in this group."
@@ -11628,12 +11983,18 @@ msgstr ""
msgid "GitLab Issue"
msgstr ""
+msgid "GitLab Pages"
+msgstr ""
+
msgid "GitLab Service Desk is a simple way to allow people to create issues in your GitLab instance without needing their own user account. It provides a unique email address for end users to create issues in a project, and replies can be sent either through the GitLab interface or by email. End users will only see the thread through email."
msgstr ""
msgid "GitLab Shared Runners execute code of different projects on the same Runner unless you configure GitLab Runner Autoscale with MaxBuilds 1 (which it is on GitLab.com)."
msgstr ""
+msgid "GitLab Shell"
+msgstr ""
+
msgid "GitLab Support Bot"
msgstr ""
@@ -11643,7 +12004,7 @@ msgstr ""
msgid "GitLab User"
msgstr ""
-msgid "GitLab allows you to continue using your license even if you exceed the number of seats you purchased. You will be required to pay for these seats when you renew your license."
+msgid "GitLab Workhorse"
msgstr ""
msgid "GitLab commit"
@@ -11811,6 +12172,21 @@ msgstr ""
msgid "Gitlab Pages"
msgstr ""
+msgid "Gitpod"
+msgstr ""
+
+msgid "Gitpod|Add the URL to your Gitpod instance configured to read your GitLab projects."
+msgstr ""
+
+msgid "Gitpod|Enable Gitpod integration"
+msgstr ""
+
+msgid "Gitpod|Gitpod URL"
+msgstr ""
+
+msgid "Gitpod|e.g. https://gitpod.example.com"
+msgstr ""
+
msgid "Given access %{time_ago}"
msgstr ""
@@ -12318,9 +12694,6 @@ msgstr ""
msgid "GroupSAML|Valid SAML Response"
msgstr ""
-msgid "GroupSAML|With group managed accounts enabled, all the users without a group managed account will be excluded from the group."
-msgstr ""
-
msgid "GroupSAML|With prohibit outer forks flag enabled group members will be able to fork project only inside your group."
msgstr ""
@@ -12534,10 +12907,10 @@ msgstr ""
msgid "GroupsNew|Create group"
msgstr ""
-msgid "GroupsNew|GitLab group export"
+msgid "GroupsNew|Import"
msgstr ""
-msgid "GroupsNew|Import"
+msgid "GroupsNew|Import a GitLab group export file"
msgstr ""
msgid "GroupsNew|Import group"
@@ -12680,6 +13053,9 @@ msgid_plural "Hide charts"
msgstr[0] ""
msgstr[1] ""
+msgid "Hide comments on this file"
+msgstr ""
+
msgid "Hide details"
msgstr ""
@@ -12724,6 +13100,15 @@ msgstr ""
msgid "Highest role:"
msgstr ""
+msgid "HighlightBar|Alert events:"
+msgstr ""
+
+msgid "HighlightBar|Alert start time:"
+msgstr ""
+
+msgid "HighlightBar|Original alert:"
+msgstr ""
+
msgid "History"
msgstr ""
@@ -12901,6 +13286,9 @@ msgstr ""
msgid "If enabled, access to projects will be validated on an external service using their classification label."
msgstr ""
+msgid "If the number of active users exceeds the user limit, you will be charged for the number of %{users_over_license_link} at your next license reconciliation."
+msgstr ""
+
msgid "If there is no previous license or if the previous license has expired, some GitLab functionality will be blocked until a new, valid license is uploaded."
msgstr ""
@@ -12940,9 +13328,6 @@ msgstr ""
msgid "If your HTTP repository is not publicly accessible, add your credentials."
msgstr ""
-msgid "Iglu registry URL (optional)"
-msgstr ""
-
msgid "Ignore"
msgstr ""
@@ -12979,6 +13364,16 @@ msgstr ""
msgid "Import"
msgstr ""
+msgid "Import %d compatible repository"
+msgid_plural "Import %d compatible repositories"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Import %d repository"
+msgid_plural "Import %d repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Import CSV"
msgstr ""
@@ -12988,15 +13383,9 @@ msgstr ""
msgid "Import all compatible projects"
msgstr ""
-msgid "Import all compatible repositories"
-msgstr ""
-
msgid "Import all projects"
msgstr ""
-msgid "Import all repositories"
-msgstr ""
-
msgid "Import an exported GitLab project"
msgstr ""
@@ -13084,6 +13473,9 @@ msgstr ""
msgid "ImportProjects|Error importing repository %{project_safe_import_url} into %{project_full_path} - %{message}"
msgstr ""
+msgid "ImportProjects|Import repositories"
+msgstr ""
+
msgid "ImportProjects|Importing the project failed"
msgstr ""
@@ -13096,7 +13488,7 @@ msgstr ""
msgid "ImportProjects|Requesting your %{provider} repositories failed"
msgstr ""
-msgid "ImportProjects|Select the projects you want to import"
+msgid "ImportProjects|Select the repositories you want to import"
msgstr ""
msgid "ImportProjects|The remote data could not be imported."
@@ -13132,9 +13524,6 @@ msgstr ""
msgid "In order to enable Service Desk for your instance, you must first set up incoming email."
msgstr ""
-msgid "In order to gather accurate feature usage data, it can take 1 to 2 weeks to see your index."
-msgstr ""
-
msgid "In order to personalize your experience with GitLab%{br_tag}we would like to know a bit more about you."
msgstr ""
@@ -13165,18 +13554,30 @@ msgstr ""
msgid "IncidentManagement|Create incident"
msgstr ""
+msgid "IncidentManagement|Critical - S1"
+msgstr ""
+
msgid "IncidentManagement|Date created"
msgstr ""
msgid "IncidentManagement|Display your incidents in a dedicated view"
msgstr ""
+msgid "IncidentManagement|High - S2"
+msgstr ""
+
msgid "IncidentManagement|Incident"
msgstr ""
msgid "IncidentManagement|Incidents"
msgstr ""
+msgid "IncidentManagement|Low - S4"
+msgstr ""
+
+msgid "IncidentManagement|Medium - S3"
+msgstr ""
+
msgid "IncidentManagement|No incidents to display."
msgstr ""
@@ -13189,6 +13590,9 @@ msgstr ""
msgid "IncidentManagement|Published to status page"
msgstr ""
+msgid "IncidentManagement|Severity"
+msgstr ""
+
msgid "IncidentManagement|There are no closed incidents"
msgstr ""
@@ -13198,6 +13602,9 @@ msgstr ""
msgid "IncidentManagement|Unassigned"
msgstr ""
+msgid "IncidentManagement|Unknown"
+msgstr ""
+
msgid "IncidentManagement|Unpublished"
msgstr ""
@@ -13219,6 +13626,15 @@ msgstr ""
msgid "Incidents"
msgstr ""
+msgid "Incident|Alert details"
+msgstr ""
+
+msgid "Incident|Summary"
+msgstr ""
+
+msgid "Incident|There was an issue loading alert data. Please try again."
+msgstr ""
+
msgid "Include a Terms of Service agreement and Privacy Policy that all users must accept."
msgstr ""
@@ -13279,6 +13695,9 @@ msgstr "Informar os utilizadores sem enviar as chaves SSH que não podem empurra
msgid "Information about additional Pages templates and how to install them can be found in our %{pages_getting_started_guide}."
msgstr ""
+msgid "Inherited"
+msgstr ""
+
msgid "Inherited:"
msgstr ""
@@ -13359,7 +13778,22 @@ msgstr ""
msgid "Instance administrators group already exists"
msgstr ""
-msgid "Instance license"
+msgid "InstanceStatistics|Groups"
+msgstr ""
+
+msgid "InstanceStatistics|Issues"
+msgstr ""
+
+msgid "InstanceStatistics|Merge Requests"
+msgstr ""
+
+msgid "InstanceStatistics|Pipelines"
+msgstr ""
+
+msgid "InstanceStatistics|Projects"
+msgstr ""
+
+msgid "InstanceStatistics|Users"
msgstr ""
msgid "Integration"
@@ -13371,6 +13805,12 @@ msgstr ""
msgid "Integrations"
msgstr ""
+msgid "Integrations|%{integration} settings saved and active."
+msgstr ""
+
+msgid "Integrations|%{integration} settings saved, but not active."
+msgstr ""
+
msgid "Integrations|All details"
msgstr ""
@@ -13380,6 +13820,12 @@ msgstr ""
msgid "Integrations|Comment settings:"
msgstr ""
+msgid "Integrations|Connection failed. Please check your settings."
+msgstr ""
+
+msgid "Integrations|Connection successful."
+msgstr ""
+
msgid "Integrations|Default settings are inherited from the group level."
msgstr ""
@@ -13395,6 +13841,15 @@ msgstr ""
msgid "Integrations|Includes commit title and branch"
msgstr ""
+msgid "Integrations|Projects using custom settings will not be impacted unless the project owner chooses to use instance-level defaults."
+msgstr ""
+
+msgid "Integrations|Save settings?"
+msgstr ""
+
+msgid "Integrations|Saving will update the default settings for all projects that are not using custom settings."
+msgstr ""
+
msgid "Integrations|Standard"
msgstr ""
@@ -13527,6 +13982,9 @@ msgstr ""
msgid "Invitation"
msgstr ""
+msgid "Invitation declined"
+msgstr ""
+
msgid "Invite"
msgstr ""
@@ -13578,6 +14036,42 @@ 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|%{linkStart}Read more%{linkEnd} about role permissions"
+msgstr ""
+
+msgid "InviteMembersModal|Access expiration date (optional)"
+msgstr ""
+
+msgid "InviteMembersModal|Cancel"
+msgstr ""
+
+msgid "InviteMembersModal|Choose a role permission"
+msgstr ""
+
+msgid "InviteMembersModal|GitLab member or Email address"
+msgstr ""
+
+msgid "InviteMembersModal|Invite"
+msgstr ""
+
+msgid "InviteMembersModal|Invite team members"
+msgstr ""
+
+msgid "InviteMembersModal|Search for members to invite"
+msgstr ""
+
+msgid "InviteMembersModal|User not invited. Feature coming soon!"
+msgstr ""
+
+msgid "InviteMembersModal|Users were succesfully added"
+msgstr ""
+
+msgid "InviteMembersModal|You're inviting members to the %{group_name} group"
+msgstr ""
+
+msgid "InviteMembers|Invite team members"
+msgstr ""
+
msgid "Invited"
msgstr ""
@@ -13632,10 +14126,13 @@ msgstr ""
msgid "Issue cannot be found."
msgstr ""
+msgid "Issue created from vulnerability %{vulnerability_link}"
+msgstr ""
+
msgid "Issue events"
msgstr ""
-msgid "Issue first depoloyed to production"
+msgid "Issue first deployed to production"
msgstr ""
msgid "Issue label"
@@ -13713,6 +14210,9 @@ msgstr ""
msgid "IssueTracker|Custom issue tracker"
msgstr ""
+msgid "IssueTracker|EWM work items tracker"
+msgstr ""
+
msgid "IssueTracker|Redmine issue tracker"
msgstr ""
@@ -13779,6 +14279,9 @@ msgstr ""
msgid "It looks like you have some draft commits in this branch."
msgstr ""
+msgid "It may be several days before you see feature usage data."
+msgstr ""
+
msgid "It must have a header row and at least two columns: the first column is the issue title and the second column is the issue description. The separator is automatically detected."
msgstr ""
@@ -14061,13 +14564,13 @@ msgstr ""
msgid "Join Zoom meeting"
msgstr ""
-msgid "Jul"
+msgid "Joined %{time_ago}"
msgstr ""
-msgid "July"
+msgid "Jul"
msgstr ""
-msgid "Jump to first unresolved thread"
+msgid "July"
msgstr ""
msgid "Jump to next unresolved thread"
@@ -14103,6 +14606,9 @@ msgstr ""
msgid "Keyboard shortcuts"
msgstr ""
+msgid "KeyboardKey|Ctrl+"
+msgstr ""
+
msgid "Keys"
msgstr ""
@@ -14151,6 +14657,9 @@ msgstr ""
msgid "LDAP Synchronization"
msgstr ""
+msgid "LDAP group settings"
+msgstr ""
+
msgid "LDAP settings"
msgstr ""
@@ -14160,6 +14669,9 @@ msgstr ""
msgid "LDAP sync in progress. This could take a few minutes. Refresh the page to see the changes."
msgstr ""
+msgid "LDAP synchronizations"
+msgstr ""
+
msgid "LFS"
msgstr ""
@@ -14240,7 +14752,16 @@ msgid_plural "Last %d days"
msgstr[0] ""
msgstr[1] ""
-msgid "Last %{days} days"
+msgid "Last 2 weeks"
+msgstr ""
+
+msgid "Last 30 days"
+msgstr ""
+
+msgid "Last 60 days"
+msgstr ""
+
+msgid "Last 90 days"
msgstr ""
msgid "Last Accessed On"
@@ -14318,6 +14839,9 @@ msgstr ""
msgid "Last used on:"
msgstr ""
+msgid "Last week"
+msgstr ""
+
msgid "LastCommit|authored"
msgstr ""
@@ -14333,6 +14857,9 @@ msgstr ""
msgid "Latest pipeline for the most recent commit on this branch"
msgstr ""
+msgid "Launch a ready-to-code development environment for your project."
+msgstr ""
+
msgid "Lead"
msgstr ""
@@ -14713,6 +15240,9 @@ msgstr ""
msgid "List of all merge commits"
msgstr ""
+msgid "List options"
+msgstr ""
+
msgid "List settings"
msgstr ""
@@ -14725,9 +15255,6 @@ msgstr ""
msgid "List your Bitbucket Server repositories"
msgstr ""
-msgid "Lists"
-msgstr ""
-
msgid "Live preview"
msgstr ""
@@ -14974,6 +15501,12 @@ msgstr ""
msgid "Mark as done"
msgstr ""
+msgid "Mark as draft"
+msgstr ""
+
+msgid "Mark as ready"
+msgstr ""
+
msgid "Mark as resolved"
msgstr ""
@@ -14995,6 +15528,24 @@ msgstr ""
msgid "Markdown is supported"
msgstr ""
+msgid "MarkdownEditor|Add a link (%{modifierKey}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add a link (%{modifier_key}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifierKey}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifier_key}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifierKey}I)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifier_key}I)"
+msgstr ""
+
msgid "Marked For Deletion At - %{deletion_time}"
msgstr ""
@@ -15079,7 +15630,25 @@ msgstr ""
msgid "Max access level"
msgstr ""
-msgid "Max seats used"
+msgid "Max role"
+msgstr ""
+
+msgid "Max size 15 MB"
+msgstr ""
+
+msgid "Maximum Conan package file size in bytes"
+msgstr ""
+
+msgid "Maximum Maven package file size in bytes"
+msgstr ""
+
+msgid "Maximum NPM package file size in bytes"
+msgstr ""
+
+msgid "Maximum NuGet package file size in bytes"
+msgstr ""
+
+msgid "Maximum PyPI package file size in bytes"
msgstr ""
msgid "Maximum Users:"
@@ -15211,6 +15780,18 @@ msgstr ""
msgid "Members with access to %{strong_start}%{group_name}%{strong_end}"
msgstr ""
+msgid "Members|%{time} by %{user}"
+msgstr ""
+
+msgid "Members|Expired"
+msgstr ""
+
+msgid "Members|No expiration set"
+msgstr ""
+
+msgid "Members|in %{time}"
+msgstr ""
+
msgid "Memory Usage"
msgstr ""
@@ -15397,9 +15978,6 @@ msgstr ""
msgid "MergeRequests|Thread will be unresolved"
msgstr ""
-msgid "MergeRequests|Toggle comments for this file"
-msgstr ""
-
msgid "MergeRequests|View file @ %{commitId}"
msgstr ""
@@ -15460,6 +16038,9 @@ msgstr ""
msgid "Merging immediately isn't recommended as it may negatively impact the existing merge train. Read the %{docsLinkStart}documentation%{docsLinkEnd} for more information."
msgstr ""
+msgid "Message"
+msgstr ""
+
msgid "Messages"
msgstr ""
@@ -15845,18 +16426,12 @@ msgid_plural "Milestones"
msgstr[0] ""
msgstr[1] ""
-msgid "Milestone does not support burnup charts"
-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 lists show all issues from the selected milestone."
msgstr "As listas de objetivos mostram todos os problemas do objetivo selecionado."
-msgid "Milestone must have a start and due date"
-msgstr ""
-
msgid "MilestoneSidebar|Closed:"
msgstr ""
@@ -16223,6 +16798,9 @@ msgstr ""
msgid "Namespace"
msgstr ""
+msgid "Namespace ID:"
+msgstr ""
+
msgid "Namespace is empty"
msgstr ""
@@ -16307,6 +16885,9 @@ msgstr ""
msgid "NetworkPolicies|Allow all outbound traffic from %{selector} to %{ruleSelector} on %{ports}"
msgstr ""
+msgid "NetworkPolicies|Are you sure you want to delete this policy? This action cannot be undone."
+msgstr ""
+
msgid "NetworkPolicies|Choose whether to enforce this policy."
msgstr ""
@@ -16316,12 +16897,21 @@ msgstr ""
msgid "NetworkPolicies|Define this policy's location, conditions and actions."
msgstr ""
+msgid "NetworkPolicies|Delete policy"
+msgstr ""
+
+msgid "NetworkPolicies|Delete policy: %{policy}"
+msgstr ""
+
msgid "NetworkPolicies|Deny all traffic"
msgstr ""
msgid "NetworkPolicies|Description"
msgstr ""
+msgid "NetworkPolicies|Edit policy"
+msgstr ""
+
msgid "NetworkPolicies|Editor mode"
msgstr ""
@@ -16349,6 +16939,9 @@ msgstr ""
msgid "NetworkPolicies|Name"
msgstr ""
+msgid "NetworkPolicies|Namespace"
+msgstr ""
+
msgid "NetworkPolicies|Network Policy"
msgstr ""
@@ -16400,6 +16993,9 @@ msgstr ""
msgid "NetworkPolicies|Rules"
msgstr ""
+msgid "NetworkPolicies|Save changes"
+msgstr ""
+
msgid "NetworkPolicies|Something went wrong, failed to update policy"
msgstr ""
@@ -16412,6 +17008,9 @@ msgstr ""
msgid "NetworkPolicies|Traffic that does not match any rule will be blocked."
msgstr ""
+msgid "NetworkPolicies|Unable to parse policy"
+msgstr ""
+
msgid "NetworkPolicies|YAML editor"
msgstr ""
@@ -16525,6 +17124,9 @@ msgstr ""
msgid "New Snippet"
msgstr ""
+msgid "New Test Case"
+msgstr ""
+
msgid "New User"
msgstr ""
@@ -16624,6 +17226,9 @@ msgstr ""
msgid "New tag"
msgstr ""
+msgid "New test case"
+msgstr ""
+
msgid "New users set to external"
msgstr ""
@@ -16696,7 +17301,7 @@ msgstr ""
msgid "No changes"
msgstr ""
-msgid "No changes between %{ref_start}%{source_branch}%{ref_end} and %{ref_start}%{target_branch}%{ref_end}"
+msgid "No changes between %{sourceBranch} and %{targetBranch}"
msgstr ""
msgid "No child epics match applied filters"
@@ -16711,6 +17316,9 @@ msgstr ""
msgid "No containers available"
msgstr ""
+msgid "No content to show"
+msgstr ""
+
msgid "No contributions"
msgstr ""
@@ -16786,9 +17394,6 @@ msgstr ""
msgid "No license. All rights reserved"
msgstr ""
-msgid "No licenses found."
-msgstr ""
-
msgid "No matches found"
msgstr ""
@@ -16801,6 +17406,9 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No members found"
+msgstr ""
+
msgid "No merge requests found"
msgstr ""
@@ -16822,6 +17430,9 @@ msgstr ""
msgid "No parent group"
msgstr ""
+msgid "No plan"
+msgstr ""
+
msgid "No pods available"
msgstr ""
@@ -16918,6 +17529,12 @@ msgstr ""
msgid "Not Implemented"
msgstr ""
+msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+msgstr ""
+
+msgid "Not all browsers support WebAuthn. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even from an unsupported browser."
+msgstr ""
+
msgid "Not all data has been processed yet, the accuracy of the chart for the selected timeframe is limited."
msgstr ""
@@ -17014,6 +17631,9 @@ msgstr ""
msgid "Notification settings saved"
msgstr "Definições de notificação salvas"
+msgid "NotificationEvent|Change reviewer merge request"
+msgstr ""
+
msgid "NotificationEvent|Close issue"
msgstr ""
@@ -17176,10 +17796,7 @@ msgstr ""
msgid "On track"
msgstr ""
-msgid "OnDemandScans|Attached branch"
-msgstr ""
-
-msgid "OnDemandScans|Attached branch is where the scan job runs."
+msgid "OnDemandScans|Could not fetch scanner profiles. Please refresh the page, or try again later."
msgstr ""
msgid "OnDemandScans|Could not fetch site profiles. Please refresh the page, or try again later."
@@ -17188,6 +17805,9 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
+msgid "OnDemandScans|Create a new scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Create a new site profile"
msgstr ""
@@ -17200,6 +17820,9 @@ msgstr ""
msgid "OnDemandScans|New on-demand DAST scan"
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 ""
@@ -17209,16 +17832,10 @@ msgstr ""
msgid "OnDemandScans|On-demand scans run outside the DevOps cycle and find vulnerabilities in your projects. %{learnMoreLinkStart}Learn more%{learnMoreLinkEnd}"
msgstr ""
-msgid "OnDemandScans|Only a passive scan can be performed on demand."
-msgstr ""
-
-msgid "OnDemandScans|Passive"
-msgstr ""
-
msgid "OnDemandScans|Run scan"
msgstr ""
-msgid "OnDemandScans|Scan mode"
+msgid "OnDemandScans|Scanner profile"
msgstr ""
msgid "OnDemandScans|Scanner settings"
@@ -17230,9 +17847,15 @@ msgstr ""
msgid "OnDemandScans|Select one of the existing profiles"
msgstr ""
+msgid "OnDemandScans|Site profile"
+msgstr ""
+
msgid "OnDemandScans|Site profiles"
msgstr ""
+msgid "OnDemandScans|Use existing scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Use existing site profile"
msgstr ""
@@ -17331,9 +17954,6 @@ msgstr ""
msgid "Open Selection"
msgstr ""
-msgid "Open Web IDE"
-msgstr ""
-
msgid "Open comment type dropdown"
msgstr ""
@@ -17439,6 +18059,9 @@ msgstr ""
msgid "Origin"
msgstr ""
+msgid "Orphaned member"
+msgstr ""
+
msgid "Other Labels"
msgstr "Outros Rótulos"
@@ -17454,6 +18077,9 @@ msgstr ""
msgid "Other visibility settings have been disabled by the administrator."
msgstr ""
+msgid "Our documentation includes an example DevOps Score report."
+msgstr ""
+
msgid "Out-of-compliance with this project's policies and should be removed"
msgstr ""
@@ -17478,6 +18104,9 @@ msgstr ""
msgid "Overwrite diverged branches"
msgstr ""
+msgid "Owned by %{image_tag}"
+msgstr ""
+
msgid "Owned by anyone"
msgstr ""
@@ -17499,6 +18128,9 @@ msgstr ""
msgid "Package deleted successfully"
msgstr ""
+msgid "Package file size limits"
+msgstr ""
+
msgid "Package recipe already exists"
msgstr ""
@@ -17514,9 +18146,6 @@ msgstr ""
msgid "Package type must be PyPi"
msgstr ""
-msgid "Package was removed"
-msgstr ""
-
msgid "PackageRegistry|%{name} version %{version} was created %{datetime}"
msgstr ""
@@ -17658,12 +18287,18 @@ msgstr ""
msgid "PackageRegistry|NuGet Command"
msgstr ""
+msgid "PackageRegistry|Package Registry"
+msgstr ""
+
msgid "PackageRegistry|Pip Command"
msgstr ""
msgid "PackageRegistry|Pipeline %{link} triggered %{datetime} by %{author}"
msgstr ""
+msgid "PackageRegistry|Publish and share packages for a variety of common package managers. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "PackageRegistry|Published to the %{project} Package Registry %{datetime}"
msgstr ""
@@ -17763,6 +18398,9 @@ msgstr ""
msgid "Page not found"
msgstr ""
+msgid "Page settings"
+msgstr ""
+
msgid "Page was successfully deleted"
msgstr ""
@@ -17904,7 +18542,7 @@ msgstr ""
msgid "Paste issue link"
msgstr ""
-msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Don't use your private SSH key."
+msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Do not paste your private SSH key, as that can compromise your identity."
msgstr ""
msgid "Patch to apply"
@@ -17931,6 +18569,9 @@ msgstr ""
msgid "Pending"
msgstr ""
+msgid "Pending comments"
+msgstr ""
+
msgid "People without permission will never get a notification and won't be able to comment."
msgstr ""
@@ -18129,6 +18770,9 @@ msgstr ""
msgid "Pipelines|Build with confidence"
msgstr ""
+msgid "Pipelines|By revoking a trigger you will break any processes making use of it. Are you sure?"
+msgstr ""
+
msgid "Pipelines|CI Lint"
msgstr ""
@@ -18141,6 +18785,15 @@ msgstr ""
msgid "Pipelines|Continuous Integration can help catch bugs by running your tests automatically, while Continuous Deployment can help you deliver code to your product environment."
msgstr ""
+msgid "Pipelines|Copy trigger token"
+msgstr ""
+
+msgid "Pipelines|Description"
+msgstr ""
+
+msgid "Pipelines|Edit"
+msgstr ""
+
msgid "Pipelines|Get started with Pipelines"
msgstr ""
@@ -18156,15 +18809,27 @@ msgstr ""
msgid "Pipelines|It is recommended the code is reviewed thoroughly before running this pipeline with the parent project's CI resource."
msgstr ""
+msgid "Pipelines|Last Used"
+msgstr ""
+
msgid "Pipelines|Loading Pipelines"
msgstr ""
msgid "Pipelines|More Information"
msgstr ""
+msgid "Pipelines|No triggers have been created yet. Add one using the form above."
+msgstr ""
+
+msgid "Pipelines|Owner"
+msgstr ""
+
msgid "Pipelines|Project cache successfully reset."
msgstr ""
+msgid "Pipelines|Revoke"
+msgstr ""
+
msgid "Pipelines|Run Pipeline"
msgstr ""
@@ -18189,6 +18854,15 @@ msgstr ""
msgid "Pipelines|This project is not currently set up to run pipelines."
msgstr ""
+msgid "Pipelines|Token"
+msgstr ""
+
+msgid "Pipelines|Trigger user has insufficient permissions to project"
+msgstr ""
+
+msgid "Pipelines|invalid"
+msgstr ""
+
msgid "Pipelines|parent"
msgstr ""
@@ -18447,10 +19121,10 @@ msgstr ""
msgid "Please provide attributes to update"
msgstr ""
-msgid "Please refer to %{docs_url}"
+msgid "Please reach out if you have any questions and we'll be happy to assist."
msgstr ""
-msgid "Please retype the email address."
+msgid "Please refer to %{docs_url}"
msgstr ""
msgid "Please select"
@@ -18480,6 +19154,9 @@ msgstr ""
msgid "Please set a new password before proceeding."
msgstr ""
+msgid "Please share your feedback about %{featureName} %{linkStart}in this issue%{linkEnd} to help us improve the experience."
+msgstr ""
+
msgid "Please solve the reCAPTCHA"
msgstr ""
@@ -18783,6 +19460,9 @@ msgstr ""
msgid "Profiles| You are going to change the username %{currentUsernameBold} to %{newUsernameBold}. Profile and projects will be redirected to the %{newUsername} namespace but this redirect will expire once the %{currentUsername} namespace is registered by another user or group. Please update your Git repository remotes as soon as possible."
msgstr ""
+msgid "Profiles|%{provider} Active"
+msgstr ""
+
msgid "Profiles|@username"
msgstr ""
@@ -18834,8 +19514,8 @@ msgstr ""
msgid "Profiles|Commit email"
msgstr ""
-msgid "Profiles|Connect"
-msgstr "Conectar"
+msgid "Profiles|Connect %{provider}"
+msgstr ""
msgid "Profiles|Connected Accounts"
msgstr ""
@@ -18858,6 +19538,9 @@ msgstr ""
msgid "Profiles|Disconnect"
msgstr "Desconectar"
+msgid "Profiles|Disconnect %{provider}"
+msgstr ""
+
msgid "Profiles|Do not show on profile"
msgstr ""
@@ -18882,7 +19565,7 @@ msgstr ""
msgid "Profiles|Full name"
msgstr ""
-msgid "Profiles|Give your individual key a title. This will be publically visible."
+msgid "Profiles|Give your individual key a title."
msgstr ""
msgid "Profiles|Include private contributions on my profile"
@@ -18972,7 +19655,7 @@ msgstr ""
msgid "Profiles|The maximum file size allowed is 200KB."
msgstr ""
-msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it?"
+msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it? It will be publicly visible."
msgstr ""
msgid "Profiles|This email will be displayed on your public profile"
@@ -19047,6 +19730,9 @@ msgstr "Podes enviar o teu avatar aqui ou alterá-lo em %{gravatar_link}"
msgid "Profiles|You don't have access to delete this user."
msgstr ""
+msgid "Profiles|You must transfer ownership or delete groups you are an owner of before you can delete your account"
+msgstr ""
+
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
@@ -19635,6 +20321,9 @@ msgstr ""
msgid "ProjectTemplates|GitLab Cluster Management"
msgstr ""
+msgid "ProjectTemplates|Gitpod/Spring Petclinic"
+msgstr ""
+
msgid "ProjectTemplates|Go Micro"
msgstr ""
@@ -20244,6 +20933,9 @@ msgstr ""
msgid "Publish to status page"
msgstr ""
+msgid "Published"
+msgstr ""
+
msgid "Published on status page"
msgstr ""
@@ -20361,9 +21053,15 @@ msgstr ""
msgid "Quick range"
msgstr ""
+msgid "Quickly and easily edit multiple files in your project."
+msgstr ""
+
msgid "README"
msgstr ""
+msgid "Rails"
+msgstr ""
+
msgid "Rake Tasks Help"
msgstr ""
@@ -20483,10 +21181,13 @@ msgstr ""
msgid "Register Two-Factor Authenticator"
msgstr ""
-msgid "Register U2F device"
+msgid "Register Universal Two-Factor (U2F) Device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register WebAuthn Device"
+msgstr ""
+
+msgid "Register device"
msgstr ""
msgid "Register for GitLab"
@@ -20498,9 +21199,6 @@ msgstr ""
msgid "Register with two-factor app"
msgstr ""
-msgid "Registration"
-msgstr ""
-
msgid "Registration|Checkout"
msgstr ""
@@ -20617,9 +21315,6 @@ msgstr ""
msgid "Release|Something went wrong while saving the release details"
msgstr ""
-msgid "Remediated: needs review"
-msgstr ""
-
msgid "Remediations"
msgstr ""
@@ -20725,6 +21420,9 @@ msgstr ""
msgid "Remove priority"
msgstr ""
+msgid "Remove report"
+msgstr ""
+
msgid "Remove secondary node"
msgstr ""
@@ -20737,6 +21435,12 @@ msgstr ""
msgid "Remove time estimate"
msgstr ""
+msgid "Remove user & report"
+msgstr ""
+
+msgid "Remove user from group"
+msgstr ""
+
msgid "Removed"
msgstr ""
@@ -20818,9 +21522,6 @@ msgstr ""
msgid "Removes time estimate."
msgstr ""
-msgid "Removing license…"
-msgstr ""
-
msgid "Removing this group also removes all child projects, including archived projects, and their resources."
msgstr ""
@@ -20905,6 +21606,9 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
+msgid "Reported by %{reporter}"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -20991,6 +21695,27 @@ msgstr ""
msgid "Repositories"
msgstr ""
+msgid "Repositories Analytics"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download Historic Test Coverage Data"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download historic test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Historic Test Coverage Data is available in raw format (.csv) for further analysis."
+msgstr ""
+
+msgid "RepositoriesAnalytics|Test Code Coverage"
+msgstr ""
+
+msgid "RepositoriesAnalytics|There was an error fetching the projects."
+msgstr ""
+
msgid "Repository"
msgstr ""
@@ -21069,9 +21794,15 @@ msgstr ""
msgid "Request parameter %{param} is missing."
msgstr ""
+msgid "Request review from"
+msgstr ""
+
msgid "Request to link SAML account must be authorized"
msgstr ""
+msgid "Requested"
+msgstr ""
+
msgid "Requested %{time_ago}"
msgstr ""
@@ -21090,6 +21821,9 @@ msgstr ""
msgid "Requests to these domain(s)/address(es) on the local network will be allowed when local requests from hooks and services are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 or 127.0.0.0/28 are supported. Domain wildcards are not supported currently. Use comma, semicolon, or newline to separate multiple entries. The allowlist can hold a maximum of 1000 entries. Domains should use IDNA encoding. Ex: example.com, 192.168.1.1, 127.0.0.0/28, xn--itlab-j1a.com."
msgstr ""
+msgid "Require admin approval for new sign-ups"
+msgstr ""
+
msgid "Require all users in this group to setup Two-factor authentication"
msgstr ""
@@ -21217,9 +21951,6 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
-msgid "Resolved by %{resolvedByName}"
-msgstr ""
-
msgid "Resolves IP addresses once and uses them to submit requests"
msgstr ""
@@ -21339,6 +22070,14 @@ msgstr ""
msgid "ReviewApp|Enable Review App"
msgstr ""
+msgid "Reviewer"
+msgid_plural "%d Reviewers"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Reviewer(s)"
+msgstr ""
+
msgid "Reviewing"
msgstr ""
@@ -21378,6 +22117,9 @@ msgstr ""
msgid "Rook"
msgstr ""
+msgid "Ruby"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -21456,6 +22198,63 @@ msgstr ""
msgid "Runners page."
msgstr ""
+msgid "Runners|Active"
+msgstr ""
+
+msgid "Runners|Architecture"
+msgstr ""
+
+msgid "Runners|Can run untagged jobs"
+msgstr ""
+
+msgid "Runners|Description"
+msgstr ""
+
+msgid "Runners|Group"
+msgstr ""
+
+msgid "Runners|IP Address"
+msgstr ""
+
+msgid "Runners|Last contact"
+msgstr ""
+
+msgid "Runners|Locked to this project"
+msgstr ""
+
+msgid "Runners|Maximum job timeout"
+msgstr ""
+
+msgid "Runners|Name"
+msgstr ""
+
+msgid "Runners|Platform"
+msgstr ""
+
+msgid "Runners|Property Name"
+msgstr ""
+
+msgid "Runners|Protected"
+msgstr ""
+
+msgid "Runners|Revision"
+msgstr ""
+
+msgid "Runners|Shared"
+msgstr ""
+
+msgid "Runners|Specific"
+msgstr ""
+
+msgid "Runners|Tags"
+msgstr ""
+
+msgid "Runners|Value"
+msgstr ""
+
+msgid "Runners|Version"
+msgstr ""
+
msgid "Runners|You have used %{quotaUsed} out of %{quotaLimit} of your shared Runners pipeline minutes."
msgstr ""
@@ -21468,6 +22267,9 @@ msgstr ""
msgid "Runs a number of housekeeping tasks within the current repository, such as compressing file revisions and removing unreachable objects."
msgstr ""
+msgid "SAML"
+msgstr ""
+
msgid "SAML SSO"
msgstr ""
@@ -21519,6 +22321,9 @@ msgstr ""
msgid "Save"
msgstr ""
+msgid "Save %{name} size limits"
+msgstr ""
+
msgid "Save Changes"
msgstr ""
@@ -21549,9 +22354,6 @@ msgstr ""
msgid "Save space and find tags in the Container Registry more easily. Enable the cleanup policy to remove stale tags and keep only the ones you need."
msgstr ""
-msgid "Save template"
-msgstr ""
-
msgid "Save variables"
msgstr ""
@@ -21594,9 +22396,6 @@ msgstr ""
msgid "Scope"
msgstr ""
-msgid "Scope not supported with disabled 'users_search' feature!"
-msgstr "Escopo não compatível com o recurso desabilitado 'users_search'!"
-
msgid "Scoped issue boards"
msgstr ""
@@ -21723,9 +22522,6 @@ msgstr ""
msgid "Search requirements"
msgstr ""
-msgid "Search results…"
-msgstr ""
-
msgid "Search users"
msgstr ""
@@ -21798,6 +22594,11 @@ msgid_plural "SearchResults|commits"
msgstr[0] ""
msgstr[1] ""
+msgid "SearchResults|epic"
+msgid_plural "SearchResults|epics"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "SearchResults|issue"
msgid_plural "SearchResults|issues"
msgstr[0] ""
@@ -21842,10 +22643,10 @@ msgstr ""
msgid "Seat Link is disabled, and cannot be configured through this form."
msgstr ""
-msgid "Seats currently in use"
+msgid "Seats usage data as of %{last_enqueue_time}"
msgstr ""
-msgid "Seats in license"
+msgid "Seats usage data is updated every day at 12:00pm UTC"
msgstr ""
msgid "Secondary"
@@ -21899,6 +22700,9 @@ msgstr ""
msgid "SecurityConfiguration|Available for on-demand DAST"
msgstr ""
+msgid "SecurityConfiguration|By default, all analyzers are applied in order to cover all languages across your project, and only run if the language is detected in the Merge Request."
+msgstr ""
+
msgid "SecurityConfiguration|Configure"
msgstr ""
@@ -21929,16 +22733,19 @@ msgstr ""
msgid "SecurityConfiguration|Manage"
msgstr ""
+msgid "SecurityConfiguration|More information"
+msgstr ""
+
msgid "SecurityConfiguration|Not enabled"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|Security Control"
+msgid "SecurityConfiguration|SAST Configuration"
msgstr ""
-msgid "SecurityConfiguration|See documentation"
+msgid "SecurityConfiguration|Security Control"
msgstr ""
msgid "SecurityConfiguration|Status"
@@ -21950,6 +22757,9 @@ msgstr ""
msgid "SecurityConfiguration|Using custom settings. You won't receive automatic updates on this variable. %{anchorStart}Restore to default%{anchorEnd}"
msgstr ""
+msgid "SecurityConfiguration|View history"
+msgstr ""
+
msgid "SecurityConfiguration|You can quickly enable all security scanning tools by enabling %{linkStart}Auto DevOps%{linkEnd}."
msgstr ""
@@ -22028,9 +22838,6 @@ msgstr ""
msgid "SecurityReports|Learn more about setting up your dashboard"
msgstr ""
-msgid "SecurityReports|Load more vulnerabilities"
-msgstr ""
-
msgid "SecurityReports|Monitor vulnerabilities in your code"
msgstr ""
@@ -22310,7 +23117,7 @@ msgstr ""
msgid "Select status"
msgstr ""
-msgid "Select strategy activation method"
+msgid "Select strategy activation method."
msgstr ""
msgid "Select subscription"
@@ -22325,7 +23132,7 @@ msgstr ""
msgid "Select the custom project template source group."
msgstr ""
-msgid "Select timeframe"
+msgid "Select the environment scope for this feature flag."
msgstr ""
msgid "Select timezone"
@@ -22574,6 +23381,9 @@ msgstr ""
msgid "Set iteration"
msgstr ""
+msgid "Set limit to 0 to allow any file size."
+msgstr ""
+
msgid "Set max session time for web terminal."
msgstr ""
@@ -22652,10 +23462,13 @@ msgstr ""
msgid "Set up a %{type} Runner manually"
msgstr ""
+msgid "Set up a hardware device as a second factor to sign in."
+msgstr ""
+
msgid "Set up assertions/attributes/claims (email, first_name, last_name) and NameID according to %{docsLinkStart}the documentation %{icon}%{docsLinkEnd}"
msgstr ""
-msgid "Set up new U2F device"
+msgid "Set up new device"
msgstr ""
msgid "Set up new password"
@@ -22724,6 +23537,9 @@ msgstr ""
msgid "Sets weight to %{weight}."
msgstr ""
+msgid "Setting this to 0 means using the system default timeout value."
+msgstr ""
+
msgid "Settings"
msgstr ""
@@ -22739,6 +23555,15 @@ msgstr ""
msgid "Severity"
msgstr ""
+msgid "SeverityWidget|Severity"
+msgstr ""
+
+msgid "SeverityWidget|Severity: %{severity}"
+msgstr ""
+
+msgid "SeverityWidget|There was an error while updating severity."
+msgstr ""
+
msgid "Shards (%{shards})"
msgstr ""
@@ -22784,6 +23609,9 @@ msgstr ""
msgid "Show all requirements."
msgstr ""
+msgid "Show all test cases."
+msgstr ""
+
msgid "Show archived projects"
msgstr ""
@@ -22796,6 +23624,9 @@ msgstr ""
msgid "Show comments"
msgstr "Mostrar comentários"
+msgid "Show comments on this file"
+msgstr ""
+
msgid "Show comments only"
msgstr ""
@@ -22841,6 +23672,12 @@ msgstr ""
msgid "Show parent subgroups"
msgstr ""
+msgid "Show the Closed list"
+msgstr ""
+
+msgid "Show the Open list"
+msgstr ""
+
msgid "Show whitespace changes"
msgstr ""
@@ -22884,9 +23721,6 @@ msgstr ""
msgid "Sidebar|Assign health status"
msgstr ""
-msgid "Sidebar|Change weight"
-msgstr ""
-
msgid "Sidebar|Health status"
msgstr ""
@@ -23070,6 +23904,9 @@ msgstr ""
msgid "Snippets|Add another file %{num}/%{total}"
msgstr ""
+msgid "Snippets|Authored %{time_ago} by %{author}"
+msgstr ""
+
msgid "Snippets|Delete file"
msgstr ""
@@ -23097,6 +23934,9 @@ msgstr ""
msgid "Solution"
msgstr ""
+msgid "Some changes are not shown"
+msgstr ""
+
msgid "Some child epics may be hidden due to applied filters"
msgstr ""
@@ -23463,6 +24303,12 @@ msgstr ""
msgid "Source (branch or tag)"
msgstr ""
+msgid "Source Branch"
+msgstr ""
+
+msgid "Source branch: %{source_branch_open}%{source_branch}%{source_branch_close}"
+msgstr ""
+
msgid "Source code"
msgstr ""
@@ -23628,9 +24474,6 @@ msgstr ""
msgid "Start and due date"
msgstr ""
-msgid "Start by choosing a group to see how your team is spending time. You can then drill down to the project level."
-msgstr ""
-
msgid "Start by choosing a group to start exploring the merge requests in that group. You can then proceed to filter by projects, labels, milestones and authors."
msgstr ""
@@ -23712,18 +24555,27 @@ msgstr ""
msgid "StaticSiteEditor|3. Assign a person to review and accept the merge request."
msgstr ""
+msgid "StaticSiteEditor|A link to view the merge request will appear once ready."
+msgstr ""
+
msgid "StaticSiteEditor|An error occurred while submitting your changes."
msgstr ""
msgid "StaticSiteEditor|Branch could not be created."
msgstr ""
+msgid "StaticSiteEditor|Copy update"
+msgstr ""
+
msgid "StaticSiteEditor|Could not commit the content changes."
msgstr ""
msgid "StaticSiteEditor|Could not create merge request."
msgstr ""
+msgid "StaticSiteEditor|Creating your merge request"
+msgstr ""
+
msgid "StaticSiteEditor|Incompatible file content"
msgstr ""
@@ -23745,6 +24597,9 @@ msgstr ""
msgid "StaticSiteEditor|View documentation"
msgstr ""
+msgid "StaticSiteEditor|You can set an assignee to get your changes reviewed and deployed once your merge request is created."
+msgstr ""
+
msgid "StaticSiteEditor|Your merge request has been created"
msgstr ""
@@ -23874,15 +24729,15 @@ msgstr ""
msgid "Submit %{humanized_resource_name}"
msgstr ""
-msgid "Submit Changes"
-msgstr ""
-
msgid "Submit a review"
msgstr ""
msgid "Submit as spam"
msgstr ""
+msgid "Submit changes"
+msgstr ""
+
msgid "Submit feedback"
msgstr ""
@@ -24036,6 +24891,9 @@ msgstr ""
msgid "Successfully deleted U2F device."
msgstr ""
+msgid "Successfully deleted WebAuthn device."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -24354,9 +25212,6 @@ msgstr ""
msgid "Template to append to all Service Desk issues"
msgstr ""
-msgid "Template was successfully saved."
-msgstr ""
-
msgid "Templates"
msgstr ""
@@ -24435,10 +25290,28 @@ msgid_plural "Test coverage: %d hits"
msgstr[0] ""
msgstr[1] ""
-msgid "Test failed."
+msgid "Test settings"
+msgstr ""
+
+msgid "TestCases|New Test Case"
msgstr ""
-msgid "Test settings and save changes"
+msgid "TestCases|New test case"
+msgstr ""
+
+msgid "TestCases|Search test cases"
+msgstr ""
+
+msgid "TestCases|Something went wrong while creating a test case."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching count of test cases."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching test cases list."
+msgstr ""
+
+msgid "TestCases|Submit test case"
msgstr ""
msgid "TestHooks|Ensure one of your projects has merge requests."
@@ -24504,6 +25377,9 @@ msgstr ""
msgid "Thank you for signing up for your free trial! You will get additional instructions in your inbox shortly."
msgstr ""
+msgid "Thank you for your business."
+msgstr ""
+
msgid "Thank you for your feedback!"
msgstr ""
@@ -24563,9 +25439,6 @@ msgstr ""
msgid "The URL to use for connecting to Elasticsearch. Use a comma-separated list to support clustering (e.g., \"http://localhost:9200, http://localhost:9201\")."
msgstr ""
-msgid "The Web IDE offers advanced syntax highlighting capabilities and more."
-msgstr ""
-
msgid "The X509 Certificate to use when mutual TLS is required to communicate with the external authorization service. If left blank, the server certificate is still validated when accessing over HTTPS."
msgstr ""
@@ -24676,6 +25549,9 @@ msgstr ""
msgid "The form contains the following error:"
msgstr ""
+msgid "The form contains the following warning:"
+msgstr ""
+
msgid "The global settings require you to enable Two-Factor Authentication for your account."
msgstr ""
@@ -24790,9 +25666,6 @@ msgstr ""
msgid "The private key to use when a client certificate is provided. This value is encrypted at rest."
msgstr ""
-msgid "The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The project can be accessed by any logged in user."
msgstr ""
@@ -24829,7 +25702,7 @@ msgstr ""
msgid "The remote repository is being updated..."
msgstr ""
-msgid "The repository can be commited to, and issues, comments and other entities can be created."
+msgid "The repository can be committed to, and issues, comments and other entities can be created."
msgstr ""
msgid "The repository for this project does not exist."
@@ -24883,9 +25756,6 @@ msgstr ""
msgid "The time taken by each data entry gathered by that stage."
msgstr ""
-msgid "The total stage shows the time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The update action will time out after %{number_of_minutes} minutes. For big repositories, use a clone/push combination."
msgstr ""
@@ -24949,6 +25819,9 @@ msgstr ""
msgid "There are no archived requirements"
msgstr ""
+msgid "There are no archived test cases"
+msgstr ""
+
msgid "There are no changes"
msgstr ""
@@ -24988,6 +25861,9 @@ msgstr "Não há pedidos de mesclagem abertos"
msgid "There are no open requirements"
msgstr ""
+msgid "There are no open test cases"
+msgstr ""
+
msgid "There are no packages yet"
msgstr ""
@@ -25000,6 +25876,9 @@ msgstr ""
msgid "There is a limit of %{ci_project_subscriptions_limit} subscriptions from or to a project."
msgstr ""
+msgid "There is already a To-Do for this design."
+msgstr ""
+
msgid "There is already a repository with that name on disk"
msgstr ""
@@ -25018,6 +25897,9 @@ msgstr ""
msgid "There was a problem communicating with your device."
msgstr ""
+msgid "There was a problem fetching branches."
+msgstr ""
+
msgid "There was a problem fetching groups."
msgstr ""
@@ -25246,9 +26128,15 @@ msgstr ""
msgid "This action can lead to data loss. To prevent accidental actions we ask you to confirm your intention."
msgstr ""
+msgid "This action cannot be undone, and will permanently delete the %{key} SSH key"
+msgstr ""
+
msgid "This action cannot be undone. You will lose the project's repository and all content: issues, merge requests, etc."
msgstr ""
+msgid "This action has been performed too many times. Try again later."
+msgstr ""
+
msgid "This action will %{strongOpen}permanently delete%{strongClose} %{codeOpen}%{project}%{codeClose} %{strongOpen}immediately%{strongClose}, including its repositories and all content: issues, merge requests, etc."
msgstr ""
@@ -25276,9 +26164,6 @@ msgstr ""
msgid "This board's scope is reduced"
msgstr ""
-msgid "This branch has changed since you started editing. Would you like to create a new branch?"
-msgstr ""
-
msgid "This chart could not be displayed"
msgstr ""
@@ -25405,15 +26290,9 @@ msgstr ""
msgid "This is a security log of important events involving your account."
msgstr "Este é um registo de segurança de eventos importantes que envolvem a tua conta."
-msgid "This is the author's first Merge Request to this project."
-msgstr ""
-
msgid "This is the highest peak of users on your installation since the license started."
msgstr ""
-msgid "This is the maximum number of users that have existed at the same time since the license started. This is the minimum number of seats you will need to buy when you renew your license."
-msgstr ""
-
msgid "This is the number of currently active users on your installation, and this is the minimum number you need to purchase when you renew your license."
msgstr ""
@@ -25645,6 +26524,15 @@ msgstr ""
msgid "This user has no identities"
msgstr ""
+msgid "This user has previously committed to the %{name} project."
+msgstr ""
+
+msgid "This user has the %{access} role in the %{name} project."
+msgstr ""
+
+msgid "This user is the author of this %{noteable}."
+msgstr ""
+
msgid "This user will be the author of all events in the activity feed that are the result of an update, like new branches being created or new commits being pushed to existing branches."
msgstr ""
@@ -25675,6 +26563,9 @@ msgstr ""
msgid "Threat Monitoring"
msgstr ""
+msgid "ThreatMonitoring|All Environments"
+msgstr ""
+
msgid "ThreatMonitoring|Anomalous Requests"
msgstr ""
@@ -25702,9 +26593,6 @@ msgstr ""
msgid "ThreatMonitoring|Operations Per Second"
msgstr ""
-msgid "ThreatMonitoring|Overview"
-msgstr ""
-
msgid "ThreatMonitoring|Packet Activity"
msgstr ""
@@ -25723,6 +26611,9 @@ msgstr ""
msgid "ThreatMonitoring|Something went wrong, unable to fetch statistics"
msgstr ""
+msgid "ThreatMonitoring|Statistics"
+msgstr ""
+
msgid "ThreatMonitoring|The firewall is not installed or has been disabled. To view this data, ensure the web application firewall is installed and enabled for your cluster."
msgstr ""
@@ -26114,6 +27005,9 @@ msgstr ""
msgid "To update Snippets with multiple files, you must use the `files` parameter"
msgstr ""
+msgid "To use Gitpod you must first enable the feature in the integrations section of your %{user_prefs}."
+msgstr ""
+
msgid "To view all %{scannedResourcesCount} scanned URLs, please download the CSV file"
msgstr ""
@@ -26147,9 +27041,6 @@ msgstr ""
msgid "Toggle Sidebar"
msgstr ""
-msgid "Toggle all threads"
-msgstr ""
-
msgid "Toggle backtrace"
msgstr ""
@@ -26174,9 +27065,6 @@ msgstr ""
msgid "Toggle navigation"
msgstr ""
-msgid "Toggle project"
-msgstr ""
-
msgid "Toggle sidebar"
msgstr ""
@@ -26216,6 +27104,9 @@ msgstr ""
msgid "Too many projects enabled. You will need to manage them via the console or the API."
msgstr ""
+msgid "Too much data"
+msgstr ""
+
msgid "Topics (optional)"
msgstr ""
@@ -26234,6 +27125,9 @@ msgstr ""
msgid "Total cores (CPUs)"
msgstr ""
+msgid "Total days to completion"
+msgstr ""
+
msgid "Total issues"
msgstr ""
@@ -26330,6 +27224,9 @@ msgstr ""
msgid "Trending"
msgstr ""
+msgid "Trials|Create a new group to start your GitLab Gold trial."
+msgstr ""
+
msgid "Trials|Go back to GitLab"
msgstr ""
@@ -26339,6 +27236,15 @@ msgstr ""
msgid "Trials|You can always resume this process by selecting your avatar and choosing 'Start a Gold trial'"
msgstr ""
+msgid "Trials|You can apply your trial to a new group or an existing group."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group or your personal account."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group, an existing group, or your personal account."
+msgstr ""
+
msgid "Trials|You won't get a free trial right now but you can always resume this process by clicking on your avatar and choosing 'Start a free trial'"
msgstr ""
@@ -26408,6 +27314,9 @@ msgstr ""
msgid "Try using a different search term to find the file you are looking for."
msgstr ""
+msgid "Trying to communicate with your device. Plug it in (if needed) and press the button on the device now."
+msgstr ""
+
msgid "Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now."
msgstr ""
@@ -26495,6 +27404,12 @@ msgstr ""
msgid "URL or request ID"
msgstr ""
+msgid "USER %{user} WILL BE REMOVED! Are you sure?"
+msgstr ""
+
+msgid "USER WILL BE BLOCKED! Are you sure?"
+msgstr ""
+
msgid "UTC"
msgstr ""
@@ -26552,9 +27467,6 @@ msgstr ""
msgid "Unable to load the merge request widget. Try reloading the page."
msgstr ""
-msgid "Unable to resolve"
-msgstr ""
-
msgid "Unable to save iteration. Please try again"
msgstr ""
@@ -26603,6 +27515,9 @@ msgstr ""
msgid "Undo ignore"
msgstr ""
+msgid "Unexpected error"
+msgstr ""
+
msgid "Unfortunately, your email message to GitLab could not be processed."
msgstr ""
@@ -26636,6 +27551,9 @@ msgstr ""
msgid "Unknown response text"
msgstr ""
+msgid "Unless otherwise agreed to in writing with GitLab, by clicking \"Upload License\" you agree that your use of GitLab Software is subject to the %{eula_link_start}Terms of Service%{eula_link_end}."
+msgstr ""
+
msgid "Unlimited"
msgstr ""
@@ -27002,9 +27920,6 @@ msgstr ""
msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
msgstr ""
-msgid "Use a hardware device to add the second factor of authentication."
-msgstr ""
-
msgid "Use an one time password authenticator on your mobile device or computer to enable two-factor authentication (2FA)."
msgstr ""
@@ -27278,13 +28193,13 @@ msgstr ""
msgid "Users"
msgstr ""
-msgid "Users in License:"
+msgid "Users in License"
msgstr ""
-msgid "Users or groups set as approvers in the project's or merge request's settings."
+msgid "Users in License:"
msgstr ""
-msgid "Users outside of license"
+msgid "Users or groups set as approvers in the project's or merge request's settings."
msgstr ""
msgid "Users over License:"
@@ -27302,9 +28217,6 @@ msgstr ""
msgid "Users with a Guest role or those who don't belong to a Project or Group will not use a seat from your license."
msgstr ""
-msgid "Users with a Guest role or those who don't belong to any projects or groups don't count towards seats in use."
-msgstr ""
-
msgid "UsersSelect|%{name} + %{length} more"
msgstr ""
@@ -27344,9 +28256,6 @@ msgstr ""
msgid "Validations failed."
msgstr ""
-msgid "Validity"
-msgstr ""
-
msgid "Value"
msgstr ""
@@ -27365,6 +28274,9 @@ msgstr ""
msgid "Value Stream Name"
msgstr ""
+msgid "ValueStreamAnalyticsStage|We don't have enough data to show this stage."
+msgstr ""
+
msgid "ValueStreamAnalytics|%{days}d"
msgstr ""
@@ -27621,6 +28533,9 @@ msgstr ""
msgid "VisualReviewApp|Steps 1 and 2 (and sometimes 3) are performed once by the developer before requesting feedback. Steps 3 (if necessary), 4 is performed by the reviewer each time they perform a review."
msgstr ""
+msgid "Visualization"
+msgstr ""
+
msgid "Vulnerabilities"
msgstr ""
@@ -27648,34 +28563,31 @@ msgstr ""
msgid "VulnerabilityChart|Severity"
msgstr ""
-msgid "VulnerabilityManagement|A true-positive and will fix"
-msgstr ""
-
-msgid "VulnerabilityManagement|Change status"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Confirm"
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|Confirmed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Detected %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|A true-positive and will fix"
msgstr ""
-msgid "VulnerabilityManagement|Dismiss"
+msgid "VulnerabilityManagement|Change status"
msgstr ""
-msgid "VulnerabilityManagement|Dismissed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
msgstr ""
-msgid "VulnerabilityManagement|Resolved"
+msgid "VulnerabilityManagement|Detected"
msgstr ""
-msgid "VulnerabilityManagement|Resolved %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Needs triage"
msgstr ""
msgid "VulnerabilityManagement|Something went wrong while trying to delete the comment. Please try again later."
@@ -27726,6 +28638,9 @@ msgstr ""
msgid "Vulnerability|%{scannerName} (version %{scannerVersion})"
msgstr ""
+msgid "Vulnerability|Activity"
+msgstr ""
+
msgid "Vulnerability|Class"
msgstr ""
@@ -27738,6 +28653,9 @@ msgstr ""
msgid "Vulnerability|Description"
msgstr ""
+msgid "Vulnerability|Detected"
+msgstr ""
+
msgid "Vulnerability|Evidence"
msgstr ""
@@ -27801,6 +28719,9 @@ msgstr ""
msgid "Warning: Displaying this diagram might cause performance issues on this page."
msgstr ""
+msgid "We are currently unable to fetch data for the pipeline header."
+msgstr ""
+
msgid "We are currently unable to fetch data for this graph."
msgstr ""
@@ -27840,6 +28761,12 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
+msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
+msgstr ""
+
+msgid "We would like to inform you that your subscription GitLab Enterprise Edition %{plan_name} is nearing its user limit. You have %{active_user_count} active users, which is almost at the user limit of %{maximum_user_count}."
+msgstr ""
+
msgid "We've found no vulnerabilities"
msgstr ""
@@ -27855,6 +28782,12 @@ msgstr ""
msgid "Web terminal"
msgstr ""
+msgid "WebAuthn Devices (%{length})"
+msgstr ""
+
+msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
+msgstr ""
+
msgid "WebIDE|Merge request"
msgstr ""
@@ -27993,15 +28926,9 @@ msgstr ""
msgid "Welcome to the guided GitLab tour"
msgstr ""
-msgid "Welcome to your Issue Board!"
-msgstr ""
-
msgid "Welcome to your issue board!"
msgstr ""
-msgid "We’ve been making changes to %{featureName} and we’d love your feedback %{linkStart}in this issue%{linkEnd} to help us improve the experience."
-msgstr ""
-
msgid "What are you searching for?"
msgstr ""
@@ -28020,6 +28947,9 @@ msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
msgstr ""
+msgid "When enabled, any user visiting %{host} and creating an account will have to be explicitly approved by the admin before they can login. This setting is effective only if sign-ups are enabled."
+msgstr ""
+
msgid "When enabled, any user visiting %{host} will be able to create an account."
msgstr ""
@@ -28244,6 +29174,9 @@ msgstr ""
msgid "With requirements, you can set criteria to check your products against."
msgstr ""
+msgid "With test cases, you can define conditions for your project to meet in determining quality"
+msgstr ""
+
msgid "Withdraw Access Request"
msgstr ""
@@ -28259,6 +29192,9 @@ msgstr ""
msgid "Workflow Help"
msgstr ""
+msgid "Would you like to create a new branch?"
+msgstr ""
+
msgid "Write"
msgstr ""
@@ -28280,6 +29216,9 @@ msgstr ""
msgid "Wrong extern UID provided. Make sure Auth0 is configured correctly."
msgstr ""
+msgid "YYYY-MM-DD"
+msgstr ""
+
msgid "Yes"
msgstr ""
@@ -28337,7 +29276,7 @@ msgstr ""
msgid "You are going to remove the fork relationship from %{project_full_name}. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "You are going to transfer %{project_full_name} to another owner. Are you ABSOLUTELY sure?"
+msgid "You are going to transfer %{project_full_name} to another namespace. Are you ABSOLUTELY sure?"
msgstr ""
msgid "You are going to turn off the confidentiality. This means %{strongStart}everyone%{strongEnd} will be able to see and leave a comment on this %{issuableType}."
@@ -28397,9 +29336,6 @@ msgstr "Também podes enviar ficheiros existentes do teu computador ao usar as i
msgid "You can always edit this later"
msgstr ""
-msgid "You can apply your Trial to your Personal account or create a New Group."
-msgstr ""
-
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings"
msgstr ""
@@ -28421,12 +29357,18 @@ msgstr ""
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
+msgid "You can find more information about GitLab subscriptions in %{subscriptions_doc_link}."
+msgstr ""
+
msgid "You can generate an access token scoped to this project for each application to use the GitLab API."
msgstr ""
msgid "You can get started by cloning the repository or start adding files to it with one of the following options."
msgstr ""
+msgid "You can group test cases using labels. To learn about the future direction of this feature, visit %{linkStart}Quality Management direction page%{linkEnd}."
+msgstr ""
+
msgid "You can invite a new member to %{project_name} or invite another group."
msgstr ""
@@ -28442,6 +29384,9 @@ msgstr ""
msgid "You can notify the app / group or a project by sending them an email notification"
msgstr ""
+msgid "You can now close this window."
+msgstr ""
+
msgid "You can now export your security dashboard to a CSV report."
msgstr ""
@@ -28490,9 +29435,6 @@ msgstr ""
msgid "You can test your .gitlab-ci.yml in %{linkStart}CI Lint%{linkEnd}."
msgstr ""
-msgid "You can try again using %{begin_link}basic search%{end_link}"
-msgstr ""
-
msgid "You cannot access the raw file. Please wait a minute."
msgstr ""
@@ -28544,6 +29486,9 @@ msgstr ""
msgid "You don't have any U2F devices registered yet."
msgstr ""
+msgid "You don't have any WebAuthn devices registered yet."
+msgstr ""
+
msgid "You don't have any active chat names."
msgstr ""
@@ -28631,6 +29576,9 @@ msgstr ""
msgid "You must accept our Terms of Service and privacy policy in order to register an account"
msgstr ""
+msgid "You must be logged in to search across all of GitLab"
+msgstr ""
+
msgid "You must disassociate %{domain} from all clusters it is attached to before deletion."
msgstr ""
@@ -28670,7 +29618,7 @@ msgstr ""
msgid "You need to be logged in."
msgstr ""
-msgid "You need to register a two-factor authentication app before you can set up a U2F device."
+msgid "You need to register a two-factor authentication app before you can set up a device."
msgstr ""
msgid "You need to set terms to be enforced"
@@ -28688,6 +29636,9 @@ msgstr ""
msgid "You reached %{usage_in_percent} of %{namespace_name}'s storage capacity (%{used_storage} of %{storage_limit})"
msgstr ""
+msgid "You successfully declined the invitation"
+msgstr ""
+
msgid "You tried to fork %{link_to_the_project} but it failed for the following reason:"
msgstr ""
@@ -28853,10 +29804,13 @@ msgstr ""
msgid "Your U2F device did not send a valid JSON response."
msgstr ""
-msgid "Your U2F device needs to be set up. Plug it in (if not already) and click the button on the left."
+msgid "Your U2F device was registered!"
msgstr ""
-msgid "Your U2F device was registered!"
+msgid "Your WebAuthn device did not send a valid JSON response."
+msgstr ""
+
+msgid "Your WebAuthn device was registered!"
msgstr ""
msgid "Your access request to the %{source_type} has been withdrawn."
@@ -28880,6 +29834,9 @@ msgstr ""
msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
msgstr ""
+msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
+msgstr ""
+
msgid "Your changes can be committed to %{branch_name} because a merge request is open."
msgstr ""
@@ -28916,6 +29873,12 @@ msgstr ""
msgid "Your deployment services will be broken, you will need to manually fix the services after renaming."
msgstr ""
+msgid "Your device is not compatible with GitLab. Please try another device"
+msgstr ""
+
+msgid "Your device needs to be set up. Plug it in (if needed) and click the button on the left."
+msgstr ""
+
msgid "Your device was successfully set up! Give it a name and register it with the GitLab server."
msgstr ""
@@ -29029,9 +29992,6 @@ msgstr[1] ""
msgid "access:"
msgstr ""
-msgid "activated"
-msgstr ""
-
msgid "added %{created_at_timeago}"
msgstr "adicionado %{created_at_timeago}"
@@ -29104,9 +30064,21 @@ msgstr ""
msgid "by %{user}"
msgstr ""
+msgid "cannot be a date in the past"
+msgstr ""
+
msgid "cannot be changed if a personal project has container registry tags."
msgstr ""
+msgid "cannot be changed if shared runners are enabled"
+msgstr ""
+
+msgid "cannot be enabled because parent group does not allow it"
+msgstr ""
+
+msgid "cannot be enabled because parent group has shared Runners disabled"
+msgstr ""
+
msgid "cannot be enabled unless all domains have TLS certificates"
msgstr ""
@@ -29152,7 +30124,7 @@ msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about SAST %{linkEndTag}"
msgstr ""
-msgid "ciReport|%{linkStartTag}Learn more about Secret Scanning %{linkEndTag}"
+msgid "ciReport|%{linkStartTag}Learn more about Secret Detection %{linkEndTag}"
msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about codequality reports %{linkEndTag}"
@@ -29467,9 +30439,6 @@ msgstr ""
msgid "error"
msgstr ""
-msgid "error code:"
-msgstr ""
-
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr ""
@@ -29491,6 +30460,9 @@ msgstr ""
msgid "failed to dismiss associated finding(id=%{finding_id}): %{message}"
msgstr ""
+msgid "failed to revert associated finding(id=%{finding_id}) to detected"
+msgstr ""
+
msgid "file"
msgid_plural "files"
msgstr[0] ""
@@ -30033,6 +31005,9 @@ msgstr ""
msgid "must be a root namespace"
msgstr ""
+msgid "must be a valid IPv4 or IPv6 address"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -30069,6 +31044,9 @@ msgstr ""
msgid "no expiration"
msgstr ""
+msgid "no name set"
+msgstr ""
+
msgid "no one can merge"
msgstr ""
@@ -30247,9 +31225,6 @@ msgstr ""
msgid "security Reports|There was an error creating the merge request"
msgstr ""
-msgid "settings saved, but not activated"
-msgstr ""
-
msgid "severity|Critical"
msgstr ""
@@ -30376,9 +31351,6 @@ msgstr ""
msgid "toggle collapse"
msgstr ""
-msgid "toggle dropdown"
-msgstr ""
-
msgid "triggered"
msgstr ""
@@ -30406,6 +31378,9 @@ msgstr ""
msgid "user avatar"
msgstr ""
+msgid "user preferences"
+msgstr ""
+
msgid "username"
msgstr ""
diff --git a/locale/ro_RO/gitlab.po b/locale/ro_RO/gitlab.po
index 85654a79425..136ddb9ae67 100644
--- a/locale/ro_RO/gitlab.po
+++ b/locale/ro_RO/gitlab.po
@@ -14,7 +14,10 @@ msgstr ""
"X-Crowdin-Language: ro\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 6\n"
-"PO-Revision-Date: 2020-09-04 23:01\n"
+"PO-Revision-Date: 2020-10-02 18:40\n"
+
+msgid " %{project_name}#%{issue_iid} &middot; opened %{issue_created} by %{author}"
+msgstr ""
msgid " %{start} to %{end}"
msgstr ""
@@ -76,6 +79,18 @@ msgstr ""
msgid "\"el\" parameter is required for createInstance()"
msgstr ""
+msgid "%d Approval"
+msgid_plural "%d Approvals"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
+msgid "%d Package"
+msgid_plural "%d Packages"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "%d Scanned URL"
msgid_plural "%d Scanned URLs"
msgstr[0] ""
@@ -151,6 +166,12 @@ msgstr[2] ""
msgid "%d commits"
msgstr ""
+msgid "%d completed issue"
+msgid_plural "%d completed issues"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "%d contribution"
msgid_plural "%d contributions"
msgstr[0] ""
@@ -163,6 +184,12 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgid "%d day until tags are automatically removed"
+msgid_plural "%d days until tags are automatically removed"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "%d error"
msgid_plural "%d errors"
msgstr[0] ""
@@ -271,6 +298,18 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgid "%d open issue"
+msgid_plural "%d open issues"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
+msgid "%d pending comment"
+msgid_plural "%d pending comments"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "%d personal project will be removed and cannot be restored."
msgid_plural "%d personal projects will be removed and cannot be restored."
msgstr[0] ""
@@ -289,6 +328,12 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgid "%d project selected"
+msgid_plural "%d projects selected"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "%d request with warnings"
msgid_plural "%d requests with warnings"
msgstr[0] ""
@@ -313,6 +358,12 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgid "%d tag per image name"
+msgid_plural "%d tags per image name"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "%d unassigned issue"
msgid_plural "%d unassigned issues"
msgstr[0] ""
@@ -337,6 +388,12 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgid "%d warning found:"
+msgid_plural "%d warnings found:"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "%s additional commit has been omitted to prevent performance issues."
msgid_plural "%s additional commits have been omitted to prevent performance issues."
msgstr[0] ""
@@ -376,6 +433,9 @@ msgstr ""
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr ""
+msgid "%{completedCount} completed weight"
+msgstr ""
+
msgid "%{completedWeight} of %{totalWeight} weight completed"
msgstr ""
@@ -427,15 +487,12 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
-msgid "%{count} pending comment"
-msgid_plural "%{count} pending comments"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
+msgid "%{count} total weight"
+msgstr ""
+
msgid "%{dashboard_path} could not be found."
msgstr ""
@@ -490,6 +547,9 @@ msgstr ""
msgid "%{group_name} uses group managed accounts. You need to create a new GitLab account which will be managed by %{group_name}."
msgstr ""
+msgid "%{group_name}&%{epic_iid} &middot; opened %{epic_created} by %{author}"
+msgstr ""
+
msgid "%{host} sign-in from new location"
msgstr ""
@@ -502,7 +562,7 @@ msgstr ""
msgid "%{issuableType} will be removed! Are you sure?"
msgstr "%{issuableType} va fi eliminat! Esti sigur?"
-msgid "%{issuesSize} issues with a limit of %{maxIssueCount}"
+msgid "%{issuesCount} issues with a limit of %{maxIssueCount}"
msgstr ""
msgid "%{issuesSize} with a limit of %{maxIssueCount}"
@@ -535,7 +595,7 @@ msgstr ""
msgid "%{labelStart}Namespace:%{labelEnd} %{namespace}"
msgstr ""
-msgid "%{labelStart}Report Type:%{labelEnd} %{reportType}"
+msgid "%{labelStart}Scan Type:%{labelEnd} %{reportType}"
msgstr ""
msgid "%{labelStart}Scanner:%{labelEnd} %{scanner}"
@@ -739,9 +799,6 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
-msgid "%{service_title} %{message}."
-msgstr ""
-
msgid "%{size} GiB"
msgstr ""
@@ -835,6 +892,12 @@ msgstr "%{text} este disponibil"
msgid "%{timebox_name} should belong either to a project or a group."
msgstr ""
+msgid "%{timebox_type} does not support burnup charts"
+msgstr ""
+
+msgid "%{timebox_type} must have a start and due date"
+msgstr ""
+
msgid "%{title} %{operator} %{threshold}"
msgstr ""
@@ -859,7 +922,7 @@ msgstr ""
msgid "%{total} open issue weight"
msgstr ""
-msgid "%{total} open issues"
+msgid "%{total} warnings found: showing first %{warningsDisplayed}"
msgstr ""
msgid "%{usage_ping_link_start}Learn more%{usage_ping_link_end} about what information is shared with GitLab Inc."
@@ -892,9 +955,6 @@ msgstr ""
msgid "&lt; 1 hour"
msgstr ""
-msgid "&lt;no name set&gt;"
-msgstr ""
-
msgid "&lt;no scopes selected&gt;"
msgstr ""
@@ -925,6 +985,9 @@ msgstr ""
msgid "'%{name}' Value Stream created"
msgstr ""
+msgid "'%{name}' Value Stream deleted"
+msgstr ""
+
msgid "'%{name}' stage already exists"
msgstr ""
@@ -985,6 +1048,9 @@ msgstr ""
msgid "+ %{numberOfHiddenAssignees} more"
msgstr ""
+msgid "+ %{numberOfHiddenReviewers} more"
+msgstr ""
+
msgid "+%d more"
msgid_plural "+%d more"
msgstr[0] ""
@@ -1051,6 +1117,12 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgid "1 Issue"
+msgid_plural "%d Issues"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "1 closed issue"
msgid_plural "%{issues} closed issues"
msgstr[0] ""
@@ -1069,6 +1141,12 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgid "1 deploy key"
+msgid_plural "%d deploy keys"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1180,6 +1258,9 @@ msgstr ""
msgid ":%{startLine} to %{endLine}"
msgstr ""
+msgid "A %{incident_docs_start}modified issue%{incident_docs_end} to guide the resolution of incidents."
+msgstr ""
+
msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr ""
@@ -1192,6 +1273,9 @@ msgstr ""
msgid "A GitBook site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
+msgid "A Gitpod configured Webapplication in Spring and Java"
+msgstr ""
+
msgid "A Hexo site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
@@ -1363,9 +1447,15 @@ msgstr ""
msgid "Access expiration date"
msgstr ""
+msgid "Access expires"
+msgstr ""
+
msgid "Access forbidden. Check your access level."
msgstr ""
+msgid "Access granted"
+msgstr ""
+
msgid "Access requests"
msgstr ""
@@ -1375,6 +1465,9 @@ msgstr ""
msgid "Access to Pages websites are controlled based on the user's membership to a given project. By checking this box, users will be required to be logged in to have access to all Pages websites in your instance."
msgstr ""
+msgid "AccessDropdown|Deploy Keys"
+msgstr ""
+
msgid "AccessDropdown|Groups"
msgstr ""
@@ -1492,12 +1585,6 @@ msgstr ""
msgid "Active Sessions"
msgstr ""
-msgid "Active Users:"
-msgstr ""
-
-msgid "Active users"
-msgstr ""
-
msgid "Activity"
msgstr ""
@@ -1666,9 +1753,6 @@ msgstr ""
msgid "Add label(s)"
msgstr ""
-msgid "Add license"
-msgstr ""
-
msgid "Add list"
msgstr ""
@@ -1843,21 +1927,51 @@ msgstr ""
msgid "AdminArea|Bots"
msgstr ""
+msgid "AdminArea|Components"
+msgstr ""
+
msgid "AdminArea|Developer"
msgstr ""
+msgid "AdminArea|Features"
+msgstr ""
+
+msgid "AdminArea|Groups: %{number_of_groups}"
+msgstr ""
+
msgid "AdminArea|Guest"
msgstr ""
msgid "AdminArea|Included Free in license"
msgstr ""
+msgid "AdminArea|Latest groups"
+msgstr ""
+
+msgid "AdminArea|Latest projects"
+msgstr ""
+
+msgid "AdminArea|Latest users"
+msgstr ""
+
msgid "AdminArea|Maintainer"
msgstr ""
+msgid "AdminArea|New group"
+msgstr ""
+
+msgid "AdminArea|New project"
+msgstr ""
+
+msgid "AdminArea|New user"
+msgstr ""
+
msgid "AdminArea|Owner"
msgstr ""
+msgid "AdminArea|Projects: %{number_of_projects}"
+msgstr ""
+
msgid "AdminArea|Reporter"
msgstr ""
@@ -1885,6 +1999,9 @@ msgstr ""
msgid "AdminArea|Users without a Group and Project"
msgstr ""
+msgid "AdminArea|Users: %{number_of_users}"
+msgstr ""
+
msgid "AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running."
msgstr ""
@@ -1903,9 +2020,6 @@ msgstr ""
msgid "AdminProjects|Delete Project %{projectName}?"
msgstr ""
-msgid "AdminProjects|Delete project"
-msgstr ""
-
msgid "AdminSettings|Apply integration settings to all Projects"
msgstr ""
@@ -2143,21 +2257,30 @@ msgstr ""
msgid "AdminUsers|Without projects"
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 ""
msgid "AdminUsers|You cannot remove your own admin rights."
msgstr ""
+msgid "AdminUsers|You must transfer ownership or delete the groups owned by this user before you can delete their account"
+msgstr ""
+
msgid "Administration"
msgstr ""
msgid "Advanced"
msgstr ""
+msgid "Advanced Search"
+msgstr ""
+
+msgid "Advanced Search with Elasticsearch"
+msgstr ""
+
msgid "Advanced Settings"
msgstr ""
@@ -2236,6 +2359,9 @@ msgstr ""
msgid "AlertManagement|Edit"
msgstr ""
+msgid "AlertManagement|Environment"
+msgstr ""
+
msgid "AlertManagement|Events"
msgstr ""
@@ -2248,6 +2374,9 @@ msgstr ""
msgid "AlertManagement|Issue"
msgstr ""
+msgid "AlertManagement|Key"
+msgstr ""
+
msgid "AlertManagement|Low"
msgstr ""
@@ -2341,6 +2470,9 @@ msgstr ""
msgid "AlertManagement|Unknown"
msgstr ""
+msgid "AlertManagement|Value"
+msgstr ""
+
msgid "AlertManagement|View alerts in Opsgenie"
msgstr ""
@@ -2500,6 +2632,9 @@ msgstr ""
msgid "All projects"
msgstr ""
+msgid "All projects selected"
+msgstr ""
+
msgid "All security scans are enabled because %{linkStart}Auto DevOps%{linkEnd} is enabled on this project"
msgstr ""
@@ -2587,6 +2722,9 @@ msgstr ""
msgid "Almost there"
msgstr ""
+msgid "Already blocked"
+msgstr ""
+
msgid "Also called \"Issuer\" or \"Relying party trust identifier\""
msgstr ""
@@ -2641,6 +2779,9 @@ msgstr ""
msgid "An error has occurred"
msgstr ""
+msgid "An error occured while making the changes: %{error}"
+msgstr ""
+
msgid "An error occurred adding a draft to the thread."
msgstr ""
@@ -2668,12 +2809,6 @@ msgstr ""
msgid "An error occurred when toggling the notification subscription"
msgstr ""
-msgid "An error occurred when trying to resolve a comment. Please try again."
-msgstr ""
-
-msgid "An error occurred when trying to resolve a discussion. Please try again."
-msgstr ""
-
msgid "An error occurred when updating the issue weight"
msgstr ""
@@ -2689,12 +2824,6 @@ msgstr ""
msgid "An error occurred while checking group path. Please refresh and try again."
msgstr ""
-msgid "An error occurred while committing your changes."
-msgstr ""
-
-msgid "An error occurred while creating the list. Please try again."
-msgstr ""
-
msgid "An error occurred while decoding the file."
msgstr ""
@@ -2767,25 +2896,19 @@ msgstr ""
msgid "An error occurred while fetching the Service Desk address."
msgstr ""
-msgid "An error occurred while fetching the board issues. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the board lists. Please reload the page."
msgstr ""
msgid "An error occurred while fetching the board lists. Please try again."
msgstr ""
-msgid "An error occurred while fetching the board swimlanes. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the builds."
msgstr ""
msgid "An error occurred while fetching the job log."
msgstr ""
-msgid "An error occurred while fetching the job trace."
+msgid "An error occurred while fetching the job logs."
msgstr ""
msgid "An error occurred while fetching the job."
@@ -2932,9 +3055,6 @@ msgstr ""
msgid "An error occurred while saving assignees"
msgstr ""
-msgid "An error occurred while saving the template. Please check if the template exists."
-msgstr ""
-
msgid "An error occurred while searching for milestones"
msgstr ""
@@ -2953,10 +3073,10 @@ msgstr ""
msgid "An error occurred while updating approvers"
msgstr ""
-msgid "An error occurred while updating the comment"
+msgid "An error occurred while updating labels."
msgstr ""
-msgid "An error occurred while updating the list. Please try again."
+msgid "An error occurred while updating the comment"
msgstr ""
msgid "An error occurred while validating group path"
@@ -3010,6 +3130,9 @@ msgstr ""
msgid "An unknown error occurred while loading this graph."
msgstr ""
+msgid "An unknown error occurred."
+msgstr ""
+
msgid "Analytics"
msgstr ""
@@ -3043,10 +3166,10 @@ msgstr ""
msgid "Any"
msgstr ""
-msgid "Any Author"
+msgid "Any %{header}"
msgstr ""
-msgid "Any Status"
+msgid "Any Author"
msgstr ""
msgid "Any branch"
@@ -3100,6 +3223,9 @@ msgstr ""
msgid "Application ID"
msgstr ""
+msgid "Application limits saved successfully"
+msgstr ""
+
msgid "Application settings saved successfully"
msgstr ""
@@ -3313,6 +3439,9 @@ msgstr ""
msgid "Are you sure you want to close this blocked issue?"
msgstr ""
+msgid "Are you sure you want to delete \"%{name}\" Value Stream?"
+msgstr ""
+
msgid "Are you sure you want to delete %{name}?"
msgstr ""
@@ -3322,6 +3451,9 @@ msgstr ""
msgid "Are you sure you want to delete this %{typeOfComment}?"
msgstr ""
+msgid "Are you sure you want to delete this SSH key?"
+msgstr ""
+
msgid "Are you sure you want to delete this board?"
msgstr ""
@@ -3346,6 +3478,12 @@ msgstr ""
msgid "Are you sure you want to erase this build?"
msgstr ""
+msgid "Are you sure you want to import %d repository?"
+msgid_plural "Are you sure you want to import %d repositories?"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "Are you sure you want to lose unsaved changes?"
msgstr ""
@@ -3355,15 +3493,15 @@ msgstr ""
msgid "Are you sure you want to merge immediately?"
msgstr ""
-msgid "Are you sure you want to permanently delete this license?"
-msgstr ""
-
msgid "Are you sure you want to re-deploy this environment?"
msgstr ""
msgid "Are you sure you want to regenerate the public key? You will have to update the public key on the remote server before mirroring will work again."
msgstr ""
+msgid "Are you sure you want to reindex?"
+msgstr ""
+
msgid "Are you sure you want to remove %{group_name}?"
msgstr ""
@@ -3391,6 +3529,9 @@ msgstr ""
msgid "Are you sure you want to revoke this nickname?"
msgstr ""
+msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
+msgstr ""
+
msgid "Are you sure you want to stop this environment?"
msgstr ""
@@ -3412,6 +3553,9 @@ msgstr ""
msgid "Are you sure? The device will be signed out of GitLab and all remember me tokens revoked."
msgstr ""
+msgid "Are you sure? This will invalidate your registered applications and U2F / WebAuthn devices."
+msgstr ""
+
msgid "Are you sure? This will invalidate your registered applications and U2F devices."
msgstr ""
@@ -3430,9 +3574,6 @@ msgstr ""
msgid "Artifacts"
msgstr ""
-msgid "As U2F devices are only supported by a few browsers, we require that you set up a two-factor authentication app before a U2F device. That way you'll always be able to log in - even when you're using an unsupported browser."
-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 ""
@@ -3628,6 +3769,9 @@ msgstr ""
msgid "AuditLogs|Target"
msgstr ""
+msgid "AuditLogs|This month"
+msgstr ""
+
msgid "AuditLogs|User Events"
msgstr ""
@@ -3667,6 +3811,9 @@ msgstr ""
msgid "Authentication via U2F device failed."
msgstr ""
+msgid "Authentication via WebAuthn device failed."
+msgstr ""
+
msgid "Author"
msgstr ""
@@ -3934,15 +4081,6 @@ msgstr ""
msgid "BambooService|You must set up automatic revision labeling and a repository trigger in Bamboo."
msgstr ""
-msgid "BatchComments|Delete all pending comments"
-msgstr ""
-
-msgid "BatchComments|Discard review?"
-msgstr ""
-
-msgid "BatchComments|You're about to discard your review which will delete all of your pending comments. The deleted comments %{strong_start}cannot%{strong_end} be restored."
-msgstr ""
-
msgid "Be careful. Changing the project's namespace can have unintended side effects."
msgstr ""
@@ -3964,6 +4102,9 @@ msgstr ""
msgid "Bi-weekly code coverage"
msgstr ""
+msgid "Billable Users:"
+msgstr ""
+
msgid "Billing"
msgstr ""
@@ -3973,7 +4114,7 @@ msgstr ""
msgid "BillingPlans|@%{user_name} you are currently using the %{plan_name} plan."
msgstr ""
-msgid "BillingPlans|Congratulations, your new trial is activated"
+msgid "BillingPlans|Congratulations, your free trial is activated."
msgstr ""
msgid "BillingPlans|If you would like to downgrade your plan please contact %{support_link_start}Customer Support%{support_link_end}."
@@ -4036,6 +4177,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Block user"
+msgstr ""
+
msgid "Blocked"
msgstr ""
@@ -4051,31 +4195,37 @@ msgstr ""
msgid "Blog"
msgstr ""
-msgid "Board name"
-msgstr ""
-
msgid "Board scope"
msgstr ""
msgid "Board scope affects which issues are displayed for anyone who visits this board"
msgstr ""
-msgid "BoardBlankState|Add default lists"
+msgid "Boards"
msgstr ""
-msgid "BoardBlankState|Add the following default lists to your Issue Board with one click:"
+msgid "Boards and Board Lists"
msgstr ""
-msgid "BoardBlankState|Nevermind, I'll use my own"
+msgid "Boards|An error occurred while creating the issue. Please try again."
msgstr ""
-msgid "BoardBlankState|Starting out with the default set of lists will get you right on the way to making the most of your board."
+msgid "Boards|An error occurred while creating the list. Please try again."
msgstr ""
-msgid "Boards"
+msgid "Boards|An error occurred while fetching issues. Please reload the page."
msgstr ""
-msgid "Boards and Board Lists"
+msgid "Boards|An error occurred while fetching the board issues. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching the board swimlanes. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while moving the issue. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while updating the list. Please try again."
msgstr ""
msgid "Boards|Collapse"
@@ -4102,7 +4252,7 @@ msgstr ""
msgid "Branch %{branch_name} was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr ""
-msgid "Branch has changed"
+msgid "Branch changed"
msgstr ""
msgid "Branch is already taken"
@@ -4408,6 +4558,9 @@ msgstr ""
msgid "CLOSED (MOVED)"
msgstr ""
+msgid "CODEOWNERS rule violation"
+msgstr ""
+
msgid "CONTRIBUTING"
msgstr ""
@@ -4438,9 +4591,6 @@ msgstr ""
msgid "Can't create snippet: %{err}"
msgstr ""
-msgid "Can't edit as source branch was deleted"
-msgstr ""
-
msgid "Can't fetch content for the blob: %{err}"
msgstr ""
@@ -4453,9 +4603,6 @@ msgstr ""
msgid "Can't load mermaid module: %{err}"
msgstr ""
-msgid "Can't remove group members without group managed account"
-msgstr ""
-
msgid "Can't scan the code?"
msgstr ""
@@ -4498,6 +4645,9 @@ msgstr ""
msgid "Cannot create the abuse report. This user has been blocked."
msgstr ""
+msgid "Cannot enable shared runners because parent group does not allow it"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -4603,6 +4753,15 @@ msgstr ""
msgid "Change your password or recover your current one"
msgstr ""
+msgid "ChangeReviewer|Reviewer changed from %{old} to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Reviewer changed to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Unassigned"
+msgstr ""
+
msgid "ChangeTypeActionLabel|Pick into branch"
msgstr ""
@@ -4642,6 +4801,9 @@ msgstr ""
msgid "Changes the title to \"%{title_param}\"."
msgstr ""
+msgid "Changes were successfully made."
+msgstr ""
+
msgid "Changes won't take place until the index is %{link_start}recreated%{link_end}."
msgstr ""
@@ -5047,6 +5209,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove variable"
+msgstr ""
+
msgid "CiVariables|Remove variable row"
msgstr ""
@@ -5125,9 +5290,6 @@ msgstr ""
msgid "Clear due date"
msgstr ""
-msgid "Clear input"
-msgstr ""
-
msgid "Clear recent searches"
msgstr ""
@@ -5176,6 +5338,9 @@ msgstr ""
msgid "Client authentication key password"
msgstr ""
+msgid "Client request timeout"
+msgstr ""
+
msgid "Clients"
msgstr ""
@@ -5260,6 +5425,27 @@ msgstr ""
msgid "Cluster type must be specificed for Stages::ClusterEndpointInserter"
msgstr ""
+msgid "ClusterAgents|Configuration"
+msgstr ""
+
+msgid "ClusterAgents|Connect your cluster with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate Kubernetes with a GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Name"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Agent also requires %{linkStart}enabling the Agent Server%{linkEnd}"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Kubernetes Agent allows an Infrastructure as Code, GitOps approach to integrating Kubernetes clusters with GitLab. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "ClusterAgent|This feature is only available for premium plans"
msgstr ""
@@ -5329,10 +5515,10 @@ msgstr ""
msgid "ClusterIntegration|All installed applications and related resources"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster."
+msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{linkStart}More information%{linkEnd}"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{startLink}More information%{endLink}"
+msgid "ClusterIntegration|Allow GitLab to manage namespaces and service accounts for this cluster."
msgstr ""
msgid "ClusterIntegration|Alternatively, "
@@ -5353,6 +5539,9 @@ msgstr ""
msgid "ClusterIntegration|An error occurred while trying to fetch zone machine types: %{error}"
msgstr ""
+msgid "ClusterIntegration|An unknown error occurred while attempting to connect to Kubernetes."
+msgstr ""
+
msgid "ClusterIntegration|Any project namespaces"
msgstr ""
@@ -5368,6 +5557,9 @@ msgstr ""
msgid "ClusterIntegration|Authenticate with Amazon Web Services"
msgstr ""
+msgid "ClusterIntegration|Authentication Error"
+msgstr ""
+
msgid "ClusterIntegration|Base domain"
msgstr ""
@@ -5386,13 +5578,22 @@ msgstr ""
msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}security group %{externalLinkIcon} %{endLink} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
+msgid "ClusterIntegration|Check your CA certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Check your cluster status"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}subnets %{externalLinkIcon} %{endLink} in your VPC where your worker nodes will run."
+msgid "ClusterIntegration|Check your token"
msgstr ""
-msgid "ClusterIntegration|Choose the worker node %{startLink}instance type %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Choose the %{linkStart}security group %{linkEnd} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
+msgstr ""
+
+msgid "ClusterIntegration|Choose the %{linkStart}subnets %{linkEnd} in your VPC where your worker nodes will run."
+msgstr ""
+
+msgid "ClusterIntegration|Choose the worker node %{linkStart}instance type%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Choose which applications to install on your Kubernetes cluster."
@@ -5404,10 +5605,7 @@ msgstr ""
msgid "ClusterIntegration|Clear cluster cache"
msgstr ""
-msgid "ClusterIntegration|Clear the local cache of namespace and service accounts. This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
-msgstr ""
-
-msgid "ClusterIntegration|Cluster being created"
+msgid "ClusterIntegration|Clear the local cache of namespace and service accounts."
msgstr ""
msgid "ClusterIntegration|Cluster management project (alpha)"
@@ -5419,15 +5617,21 @@ msgstr ""
msgid "ClusterIntegration|Cluster_applications artifact too big. Maximum allowable size: %{human_size}"
msgstr ""
-msgid "ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters."
+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|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}"
+msgid "ClusterIntegration|Clusters connected with a certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Connect cluster with certificate"
msgstr ""
msgid "ClusterIntegration|Connect existing cluster"
msgstr ""
+msgid "ClusterIntegration|Connection Error"
+msgstr ""
+
msgid "ClusterIntegration|Copy API URL"
msgstr ""
@@ -5503,6 +5707,12 @@ msgstr ""
msgid "ClusterIntegration|Deletes all GitLab resources attached to this cluster during removal"
msgstr ""
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared."
+msgstr ""
+
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared. %{linkStart}More information%{linkEnd}"
+msgstr ""
+
msgid "ClusterIntegration|Did you know?"
msgstr ""
@@ -5572,6 +5782,9 @@ msgstr ""
msgid "ClusterIntegration|Fluentd is an open source data collector, which lets you unify the data collection and consumption for a better use and understanding of data. It requires at least one of the following logs to be successfully installed."
msgstr ""
+msgid "ClusterIntegration|GitLab Agent managed clusters"
+msgstr ""
+
msgid "ClusterIntegration|GitLab Container Network Policies"
msgstr ""
@@ -5584,6 +5797,12 @@ msgstr ""
msgid "ClusterIntegration|GitLab Runner connects to the repository and executes CI/CD jobs, pushing results back and deploying applications to production."
msgstr ""
+msgid "ClusterIntegration|GitLab failed to authenticate."
+msgstr ""
+
+msgid "ClusterIntegration|GitLab failed to connect to the cluster."
+msgstr ""
+
msgid "ClusterIntegration|GitLab-managed cluster"
msgstr ""
@@ -5605,6 +5824,9 @@ msgstr ""
msgid "ClusterIntegration|Group cluster"
msgstr ""
+msgid "ClusterIntegration|HTTP Error"
+msgstr ""
+
msgid "ClusterIntegration|Helm Tiller"
msgstr ""
@@ -5638,7 +5860,10 @@ msgstr ""
msgid "ClusterIntegration|Instance type"
msgstr ""
-msgid "ClusterIntegration|Integrate Kubernetes cluster automation"
+msgid "ClusterIntegration|Integrate Kubernetes with a cluster certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Integrate with a cluster certificate"
msgstr ""
msgid "ClusterIntegration|Issuer Email"
@@ -5674,9 +5899,6 @@ msgstr ""
msgid "ClusterIntegration|Knative extends Kubernetes to provide a set of middleware components that are essential to build modern, source-centric, and container-based applications that can run anywhere: on premises, in the cloud, or even in a third-party data center."
msgstr ""
-msgid "ClusterIntegration|Kubernetes cluster"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes cluster is being created..."
msgstr ""
@@ -5689,9 +5911,6 @@ msgstr ""
msgid "ClusterIntegration|Kubernetes clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr ""
-msgid "ClusterIntegration|Kubernetes clusters can be used to deploy applications and to provide Review Apps for this project"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes version"
msgstr ""
@@ -5704,7 +5923,7 @@ msgstr ""
msgid "ClusterIntegration|Learn more about %{help_link_start}zones%{help_link_end}."
msgstr ""
-msgid "ClusterIntegration|Learn more about %{startLink}Regions %{externalLinkIcon}%{endLink}."
+msgid "ClusterIntegration|Learn more about %{linkStart}Regions%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Learn more about Kubernetes"
@@ -5749,12 +5968,18 @@ msgstr ""
msgid "ClusterIntegration|Machine type"
msgstr ""
+msgid "ClusterIntegration|Make sure your API endpoint is correct"
+msgstr ""
+
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create Kubernetes clusters"
msgstr ""
msgid "ClusterIntegration|Manage your Kubernetes cluster by visiting %{provider_link}"
msgstr ""
+msgid "ClusterIntegration|Namespace per environment"
+msgstr ""
+
msgid "ClusterIntegration|No IAM Roles found"
msgstr ""
@@ -5800,6 +6025,9 @@ msgstr ""
msgid "ClusterIntegration|No zones matched your search"
msgstr ""
+msgid "ClusterIntegration|Node calculations use the Kubernetes Metrics API. Make sure your cluster has metrics installed"
+msgstr ""
+
msgid "ClusterIntegration|Number of nodes"
msgstr ""
@@ -5842,6 +6070,9 @@ msgstr ""
msgid "ClusterIntegration|RBAC-enabled cluster"
msgstr ""
+msgid "ClusterIntegration|Read our %{linkStart}help page%{linkEnd} on Kubernetes cluster integration."
+msgstr ""
+
msgid "ClusterIntegration|Read our %{link_start}help page%{link_end} on Kubernetes cluster integration."
msgstr ""
@@ -5944,7 +6175,7 @@ msgstr ""
msgid "ClusterIntegration|Select a VPC to choose a subnet"
msgstr ""
-msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{linkStart}Amazon Web Services %{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select a network to choose a subnetwork"
@@ -5977,7 +6208,7 @@ msgstr ""
msgid "ClusterIntegration|Select project to choose zone"
msgstr ""
-msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select zone"
@@ -6067,9 +6298,18 @@ msgstr ""
msgid "ClusterIntegration|There was a problem authenticating with your cluster. Please ensure your CA Certificate and Token are valid."
msgstr ""
+msgid "ClusterIntegration|There was an HTTP error when connecting to your cluster."
+msgstr ""
+
msgid "ClusterIntegration|This account must have permissions to create a Kubernetes cluster in the %{link_to_container_project} specified below"
msgstr ""
+msgid "ClusterIntegration|This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
+msgstr ""
+
+msgid "ClusterIntegration|This is necessary to clear existing environment-namespace associations from clusters previously managed by GitLab."
+msgstr ""
+
msgid "ClusterIntegration|This option will allow you to install applications on RBAC clusters."
msgstr ""
@@ -6094,9 +6334,21 @@ msgstr ""
msgid "ClusterIntegration|To use a new project, first create one on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}."
msgstr ""
+msgid "ClusterIntegration|Troubleshooting tips:"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Authenticate"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Connect"
+msgstr ""
+
msgid "ClusterIntegration|Uninstall %{appTitle}"
msgstr ""
+msgid "ClusterIntegration|Unknown Error"
+msgstr ""
+
msgid "ClusterIntegration|Update %{appTitle}"
msgstr ""
@@ -6157,7 +6409,7 @@ msgstr ""
msgid "ClusterIntegration|Your cluster API is unreachable. Please ensure your API URL is correct."
msgstr ""
-msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Zone"
@@ -6277,6 +6529,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse all threads"
+msgstr ""
+
msgid "Collapse approvers"
msgstr ""
@@ -6427,7 +6682,7 @@ msgstr ""
msgid "Commit…"
msgstr ""
-msgid "Company"
+msgid "Community forum"
msgstr ""
msgid "Company name"
@@ -6436,6 +6691,9 @@ msgstr ""
msgid "Compare"
msgstr ""
+msgid "Compare %{oldCommitId}...%{newCommitId}"
+msgstr ""
+
msgid "Compare Git revisions"
msgstr ""
@@ -6451,6 +6709,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare submodule commit revisions"
+msgstr ""
+
msgid "Compare with previous version"
msgstr ""
@@ -6586,6 +6847,9 @@ msgstr ""
msgid "Configure the way a user creates a new account."
msgstr ""
+msgid "Configure which lists are shown for anyone who visits this board"
+msgstr ""
+
msgid "Confirm"
msgstr ""
@@ -6814,6 +7078,9 @@ msgstr[2] ""
msgid "ContainerRegistry|Set cleanup policy"
msgstr ""
+msgid "ContainerRegistry|Some tags were not deleted"
+msgstr ""
+
msgid "ContainerRegistry|Something went wrong while fetching the cleanup policy."
msgstr ""
@@ -6853,6 +7120,9 @@ msgstr ""
msgid "ContainerRegistry|Tags with names matching this regex pattern will %{italicStart}expire:%{italicEnd}"
msgstr ""
+msgid "ContainerRegistry|The cleanup policy timed out before it could delete all tags. An administrator can %{adminLinkStart}manually run cleanup now%{adminLinkEnd} or you can wait for the cleanup policy to automatically run again. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "ContainerRegistry|The last tag related to this image was recently removed. This empty image and any associated data will be automatically removed as part of the regular Garbage Collection process. If you have any questions, contact your administrator."
msgstr ""
@@ -6985,6 +7255,9 @@ msgstr ""
msgid "Contributions per group member"
msgstr ""
+msgid "Contributor"
+msgstr ""
+
msgid "Contributors"
msgstr ""
@@ -7114,6 +7387,9 @@ msgstr ""
msgid "Could not change HEAD: branch '%{branch}' does not exist"
msgstr ""
+msgid "Could not commit. An unexpected error occurred."
+msgstr ""
+
msgid "Could not connect to FogBugz, check your URL"
msgstr ""
@@ -7153,6 +7429,9 @@ msgstr ""
msgid "Could not find iteration"
msgstr ""
+msgid "Could not load instance counts. Please refresh the page to try again."
+msgstr ""
+
msgid "Could not remove the trigger."
msgstr ""
@@ -7177,10 +7456,10 @@ msgstr ""
msgid "Could not save prometheus manual configuration"
msgstr ""
-msgid "Could not udpdate wiki page"
+msgid "Could not update the LDAP settings"
msgstr ""
-msgid "Could not update the LDAP settings"
+msgid "Could not update wiki page"
msgstr ""
msgid "Could not upload your designs as one or more files uploaded are not supported."
@@ -7840,6 +8119,9 @@ msgstr ""
msgid "DastProfiles|Are you sure you want to delete this profile?"
msgstr ""
+msgid "DastProfiles|Could not create site validation token. Please refresh the page, or try again later."
+msgstr ""
+
msgid "DastProfiles|Could not create the scanner profile. Please try again."
msgstr ""
@@ -7864,6 +8146,12 @@ msgstr ""
msgid "DastProfiles|Could not fetch site profiles. Please refresh the page, or try again later."
msgstr ""
+msgid "DastProfiles|Could not retrieve site validation status. Please refresh the page, or try again later."
+msgstr ""
+
+msgid "DastProfiles|Could not update the scanner profile. Please try again."
+msgstr ""
+
msgid "DastProfiles|Could not update the site profile. Please try again."
msgstr ""
@@ -7879,7 +8167,7 @@ msgstr ""
msgid "DastProfiles|Download validation text file"
msgstr ""
-msgid "DastProfiles|Edit feature will come soon. Please create a new profile if changes needed"
+msgid "DastProfiles|Edit scanner profile"
msgstr ""
msgid "DastProfiles|Edit site profile"
@@ -7912,6 +8200,9 @@ msgstr ""
msgid "DastProfiles|No profiles created yet"
msgstr ""
+msgid "DastProfiles|Passive"
+msgstr ""
+
msgid "DastProfiles|Please enter a valid URL format, ex: http://www.example.com/home"
msgstr ""
@@ -7927,6 +8218,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan mode"
+msgstr ""
+
msgid "DastProfiles|Scanner Profile"
msgstr ""
@@ -7966,10 +8260,10 @@ msgstr ""
msgid "DastProfiles|Text file validation"
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
+msgid "DastProfiles|The maximum number of minutes allowed for the spider to traverse the site."
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the spider to traverse the site."
+msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
msgstr ""
msgid "DastProfiles|Validate"
@@ -8002,6 +8296,9 @@ msgstr ""
msgid "Date picker"
msgstr ""
+msgid "Date range"
+msgstr ""
+
msgid "Date range cannot exceed %{maxDateRange} days."
msgstr ""
@@ -8026,6 +8323,9 @@ msgstr ""
msgid "Days to merge"
msgstr ""
+msgid "Dear Administrator,"
+msgstr ""
+
msgid "Debug"
msgstr ""
@@ -8137,12 +8437,18 @@ msgstr ""
msgid "Delete"
msgstr ""
+msgid "Delete %{name}"
+msgstr ""
+
msgid "Delete Comment"
msgstr ""
msgid "Delete Snippet"
msgstr ""
+msgid "Delete Value Stream"
+msgstr ""
+
msgid "Delete account"
msgstr ""
@@ -8164,9 +8470,6 @@ msgstr ""
msgid "Delete label: %{label_name} ?"
msgstr ""
-msgid "Delete license"
-msgstr ""
-
msgid "Delete list"
msgstr ""
@@ -8242,15 +8545,6 @@ msgstr ""
msgid "Deleting a project places it into a read-only state until %{date}, at which point the project will be permanently deleted. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "Deleting the license failed."
-msgstr ""
-
-msgid "Deleting the license failed. The license was not found."
-msgstr ""
-
-msgid "Deleting the license failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "Deleting the project will delete its repository and all related resources including issues, merge requests etc."
msgstr ""
@@ -8752,7 +9046,10 @@ msgstr ""
msgid "DesignManagement|The maximum number of designs allowed to be uploaded is %{upload_limit}. Please try again."
msgstr ""
-msgid "DesignManagement|To upload designs, you'll need to enable LFS. %{requirements_link_start}More information%{requirements_link_end}"
+msgid "DesignManagement|There was an error moving your designs. Please upload your designs below."
+msgstr ""
+
+msgid "DesignManagement|To upload designs, you'll need to enable LFS and have admin enable hashed storage. %{requirements_link_start}More information%{requirements_link_end}"
msgstr ""
msgid "DesignManagement|Unresolve thread"
@@ -8764,6 +9061,9 @@ msgstr ""
msgid "DesignManagement|Upload skipped."
msgstr ""
+msgid "DesignManagement|Your designs are being copied and are on their way… Please refresh to update."
+msgstr ""
+
msgid "DesignManagement|and %{moreCount} more."
msgstr ""
@@ -8821,6 +9121,9 @@ msgstr ""
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
+msgid "Direct member"
+msgstr ""
+
msgid "Direction"
msgstr ""
@@ -8869,9 +9172,6 @@ msgstr ""
msgid "Discard draft"
msgstr ""
-msgid "Discard review"
-msgstr ""
-
msgid "DiscordService|Discord Notifications"
msgstr ""
@@ -8941,10 +9241,10 @@ msgstr ""
msgid "Dismiss Merge Request promotion"
msgstr ""
-msgid "Dismiss Selected"
+msgid "Dismiss Value Stream Analytics introduction box"
msgstr ""
-msgid "Dismiss Value Stream Analytics introduction box"
+msgid "Dismiss selected"
msgstr ""
msgid "Dismiss trial promotion"
@@ -8995,9 +9295,6 @@ msgstr ""
msgid "Documents reindexed: %{processed_documents} (%{percentage}%%)"
msgstr ""
-msgid "Doing"
-msgstr ""
-
msgid "Domain"
msgstr ""
@@ -9193,9 +9490,6 @@ msgstr ""
msgid "Edit environment"
msgstr ""
-msgid "Edit file"
-msgstr ""
-
msgid "Edit files in the editor and commit changes here"
msgstr ""
@@ -9208,6 +9502,12 @@ msgstr ""
msgid "Edit identity for %{user_name}"
msgstr ""
+msgid "Edit in Web IDE"
+msgstr ""
+
+msgid "Edit in single-file editor"
+msgstr ""
+
msgid "Edit issues"
msgstr ""
@@ -9235,10 +9535,10 @@ msgstr ""
msgid "Editing"
msgstr ""
-msgid "Elasticsearch"
+msgid "Elasticsearch AWS IAM credentials"
msgstr ""
-msgid "Elasticsearch AWS IAM credentials"
+msgid "Elasticsearch HTTP client timeout value in seconds."
msgstr ""
msgid "Elasticsearch indexing restrictions"
@@ -9247,9 +9547,6 @@ msgstr ""
msgid "Elasticsearch indexing started"
msgstr ""
-msgid "Elasticsearch integration. Elasticsearch AWS IAM."
-msgstr ""
-
msgid "Elasticsearch reindexing is already in progress"
msgstr ""
@@ -9277,9 +9574,6 @@ msgstr ""
msgid "Email Notification"
msgstr ""
-msgid "Email address"
-msgstr ""
-
msgid "Email could not be sent"
msgstr ""
@@ -9343,6 +9637,9 @@ msgstr ""
msgid "Emails sent from Service Desk will have this name"
msgstr ""
+msgid "Emails sent to %{email} will still be supported"
+msgstr ""
+
msgid "Emails separated by comma"
msgstr ""
@@ -9376,9 +9673,18 @@ msgstr ""
msgid "Enable"
msgstr ""
+msgid "Enable %{link_start}Gitpod%{link_end} integration to launch a development environment in your browser directly from GitLab."
+msgstr ""
+
msgid "Enable Auto DevOps"
msgstr ""
+msgid "Enable Gitpod"
+msgstr ""
+
+msgid "Enable Gitpod?"
+msgstr ""
+
msgid "Enable HTML emails"
msgstr ""
@@ -9508,9 +9814,6 @@ msgstr ""
msgid "Encountered an error while rendering: %{err}"
msgstr ""
-msgid "End date"
-msgstr ""
-
msgid "Ends at (UTC)"
msgstr ""
@@ -9670,7 +9973,7 @@ msgstr ""
msgid "EnvironmentsDashboard|The environments dashboard provides a summary of each project's environments' status, including pipeline and alert statuses."
msgstr ""
-msgid "EnvironmentsDashboard|This dashboard displays a maximum of 7 projects and 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
+msgid "EnvironmentsDashboard|This dashboard displays 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
msgstr ""
msgid "Environments|An error occurred while canceling the auto stop, please try again"
@@ -9991,6 +10294,9 @@ msgstr ""
msgid "Error deleting project. Check logs for error details."
msgstr ""
+msgid "Error fetching burnup chart data"
+msgstr ""
+
msgid "Error fetching diverging counts for branches. Please try again."
msgstr ""
@@ -10069,6 +10375,9 @@ msgstr ""
msgid "Error occurred when saving assignees"
msgstr ""
+msgid "Error occurred when saving reviewers"
+msgstr ""
+
msgid "Error occurred when toggling the notification subscription"
msgstr ""
@@ -10321,10 +10630,13 @@ msgstr ""
msgid "Expand all"
msgstr ""
-msgid "Expand approvers"
+msgid "Expand all files"
+msgstr ""
+
+msgid "Expand all threads"
msgstr ""
-msgid "Expand dropdown"
+msgid "Expand approvers"
msgstr ""
msgid "Expand milestones"
@@ -10495,6 +10807,9 @@ msgstr ""
msgid "Failed to create Merge Request. Please try again."
msgstr ""
+msgid "Failed to create To-Do for the design."
+msgstr ""
+
msgid "Failed to create a branch for this issue. Please try again."
msgstr ""
@@ -10534,6 +10849,12 @@ msgstr ""
msgid "Failed to load authors. Please try again."
msgstr ""
+msgid "Failed to load branches. Please try again."
+msgstr ""
+
+msgid "Failed to load deploy keys."
+msgstr ""
+
msgid "Failed to load emoji list."
msgstr ""
@@ -10549,6 +10870,9 @@ msgstr ""
msgid "Failed to load groups & users."
msgstr ""
+msgid "Failed to load groups, users and deploy keys."
+msgstr ""
+
msgid "Failed to load labels. Please try again."
msgstr ""
@@ -10558,6 +10882,12 @@ msgstr ""
msgid "Failed to load related branches"
msgstr ""
+msgid "Failed to load sidebar confidential toggle"
+msgstr ""
+
+msgid "Failed to load sidebar lock status"
+msgstr ""
+
msgid "Failed to load stacktrace."
msgstr ""
@@ -10585,6 +10915,9 @@ msgstr ""
msgid "Failed to publish issue on status page."
msgstr ""
+msgid "Failed to remove To-Do for the design."
+msgstr ""
+
msgid "Failed to remove a Zoom meeting"
msgstr ""
@@ -10627,6 +10960,9 @@ msgstr ""
msgid "Failed to signing using smartcard authentication"
msgstr ""
+msgid "Failed to toggle To-Do for the design."
+msgstr ""
+
msgid "Failed to update branch!"
msgstr ""
@@ -10741,7 +11077,7 @@ msgstr ""
msgid "FeatureFlags|Edit User List"
msgstr ""
-msgid "FeatureFlags|Enable features for specific users and specific environments by defining feature flag strategies."
+msgid "FeatureFlags|Enable features for specific users and environments by configuring feature flag strategies."
msgstr ""
msgid "FeatureFlags|Environment Spec"
@@ -10801,7 +11137,7 @@ msgstr ""
msgid "FeatureFlags|Include additional user IDs"
msgstr ""
-msgid "FeatureFlags|Install a %{docs_link_anchored_start}compatible client library%{docs_link_anchored_end} and specify the API URL, application name, and instance ID during the configuration setup. %{docs_link_start}More Information%{docs_link_end}"
+msgid "FeatureFlags|Install a %{docsLinkAnchoredStart}compatible client library%{docsLinkAnchoredEnd} and specify the API URL, application name, and instance ID during the configuration setup. %{docsLinkStart}More Information%{docsLinkEnd}"
msgstr ""
msgid "FeatureFlags|Instance ID"
@@ -10813,6 +11149,9 @@ msgstr ""
msgid "FeatureFlags|Loading feature flags"
msgstr ""
+msgid "FeatureFlags|Loading user lists"
+msgstr ""
+
msgid "FeatureFlags|More information"
msgstr ""
@@ -10831,7 +11170,7 @@ msgstr ""
msgid "FeatureFlags|New feature flag"
msgstr ""
-msgid "FeatureFlags|New list"
+msgid "FeatureFlags|New user list"
msgstr ""
msgid "FeatureFlags|Percent of users"
@@ -10870,6 +11209,9 @@ msgstr ""
msgid "FeatureFlags|There was an error fetching the feature flags."
msgstr ""
+msgid "FeatureFlags|There was an error fetching the user lists."
+msgstr ""
+
msgid "FeatureFlags|There was an error retrieving user lists"
msgstr ""
@@ -10885,6 +11227,9 @@ msgstr ""
msgid "FeatureFlags|User List"
msgstr ""
+msgid "FeatureFlags|User Lists"
+msgstr ""
+
msgid "FeatureFlag|List"
msgstr ""
@@ -10912,15 +11257,6 @@ msgstr ""
msgid "Fetching incoming email"
msgstr ""
-msgid "Fetching licenses failed."
-msgstr ""
-
-msgid "Fetching licenses failed. The request endpoint was not found."
-msgstr ""
-
-msgid "Fetching licenses failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "File"
msgstr ""
@@ -11023,12 +11359,21 @@ msgstr ""
msgid "Filter by status"
msgstr ""
+msgid "Filter by test cases that are currently archived."
+msgstr ""
+
+msgid "Filter by test cases that are currently opened."
+msgstr ""
+
msgid "Filter by two-factor authentication"
msgstr ""
msgid "Filter by user"
msgstr ""
+msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
+msgstr ""
+
msgid "Filter pipelines"
msgstr ""
@@ -11044,7 +11389,7 @@ msgstr ""
msgid "Filter results..."
msgstr ""
-msgid "Filter your projects by name"
+msgid "Filter your repositories by name"
msgstr ""
msgid "Filter..."
@@ -11053,7 +11398,7 @@ msgstr ""
msgid "Find File"
msgstr ""
-msgid "Find bugs in your code with coverage-guided fuzzing"
+msgid "Find bugs in your code with coverage-guided fuzzing."
msgstr ""
msgid "Find by path"
@@ -11080,9 +11425,6 @@ msgstr ""
msgid "Finish editing this message first!"
msgstr ""
-msgid "Finish review"
-msgstr ""
-
msgid "Finish setting up your dedicated account for %{group_name}."
msgstr ""
@@ -11152,6 +11494,9 @@ msgstr ""
msgid "Footer message"
msgstr ""
+msgid "For a faster browsing experience, some files are collapsed by default."
+msgstr ""
+
msgid "For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
@@ -11161,6 +11506,9 @@ msgstr ""
msgid "For more info, read the documentation."
msgstr ""
+msgid "For more information on how the number of active users is calculated, see the %{self_managed_subscriptions_doc_link} documentation."
+msgstr ""
+
msgid "For more information, go to the "
msgstr ""
@@ -11299,6 +11647,9 @@ msgstr ""
msgid "Generate new token"
msgstr ""
+msgid "Generic package file size in bytes"
+msgstr ""
+
msgid "Geo"
msgstr ""
@@ -11560,6 +11911,9 @@ msgstr ""
msgid "Geo|Please refer to Geo Troubleshooting."
msgstr ""
+msgid "Geo|Primary node"
+msgstr ""
+
msgid "Geo|Project"
msgstr ""
@@ -11602,6 +11956,9 @@ msgstr ""
msgid "Geo|Review replication status, and resynchronize and reverify items with the primary node."
msgstr ""
+msgid "Geo|Secondary node"
+msgstr ""
+
msgid "Geo|Status"
msgstr ""
@@ -11641,6 +11998,9 @@ msgstr ""
msgid "Geo|URL must be a valid url (ex: https://gitlab.com)"
msgstr ""
+msgid "Geo|Undefined"
+msgstr ""
+
msgid "Geo|Unknown state"
msgstr ""
@@ -11716,10 +12076,16 @@ msgstr ""
msgid "GitHub import"
msgstr ""
+msgid "GitLab"
+msgstr ""
+
msgid "GitLab / Unsubscribe"
msgstr ""
-msgid "GitLab Enterprise Edition %{plan}"
+msgid "GitLab API"
+msgstr ""
+
+msgid "GitLab Billing Team."
msgstr ""
msgid "GitLab Group Runners can execute code for all the projects in this group."
@@ -11731,12 +12097,18 @@ msgstr ""
msgid "GitLab Issue"
msgstr ""
+msgid "GitLab Pages"
+msgstr ""
+
msgid "GitLab Service Desk is a simple way to allow people to create issues in your GitLab instance without needing their own user account. It provides a unique email address for end users to create issues in a project, and replies can be sent either through the GitLab interface or by email. End users will only see the thread through email."
msgstr ""
msgid "GitLab Shared Runners execute code of different projects on the same Runner unless you configure GitLab Runner Autoscale with MaxBuilds 1 (which it is on GitLab.com)."
msgstr ""
+msgid "GitLab Shell"
+msgstr ""
+
msgid "GitLab Support Bot"
msgstr ""
@@ -11746,7 +12118,7 @@ msgstr ""
msgid "GitLab User"
msgstr ""
-msgid "GitLab allows you to continue using your license even if you exceed the number of seats you purchased. You will be required to pay for these seats when you renew your license."
+msgid "GitLab Workhorse"
msgstr ""
msgid "GitLab commit"
@@ -11914,6 +12286,21 @@ msgstr ""
msgid "Gitlab Pages"
msgstr ""
+msgid "Gitpod"
+msgstr ""
+
+msgid "Gitpod|Add the URL to your Gitpod instance configured to read your GitLab projects."
+msgstr ""
+
+msgid "Gitpod|Enable Gitpod integration"
+msgstr ""
+
+msgid "Gitpod|Gitpod URL"
+msgstr ""
+
+msgid "Gitpod|e.g. https://gitpod.example.com"
+msgstr ""
+
msgid "Given access %{time_ago}"
msgstr ""
@@ -12421,9 +12808,6 @@ msgstr ""
msgid "GroupSAML|Valid SAML Response"
msgstr ""
-msgid "GroupSAML|With group managed accounts enabled, all the users without a group managed account will be excluded from the group."
-msgstr ""
-
msgid "GroupSAML|With prohibit outer forks flag enabled group members will be able to fork project only inside your group."
msgstr ""
@@ -12637,10 +13021,10 @@ msgstr ""
msgid "GroupsNew|Create group"
msgstr ""
-msgid "GroupsNew|GitLab group export"
+msgid "GroupsNew|Import"
msgstr ""
-msgid "GroupsNew|Import"
+msgid "GroupsNew|Import a GitLab group export file"
msgstr ""
msgid "GroupsNew|Import group"
@@ -12784,6 +13168,9 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgid "Hide comments on this file"
+msgstr ""
+
msgid "Hide details"
msgstr ""
@@ -12829,6 +13216,15 @@ msgstr ""
msgid "Highest role:"
msgstr ""
+msgid "HighlightBar|Alert events:"
+msgstr ""
+
+msgid "HighlightBar|Alert start time:"
+msgstr ""
+
+msgid "HighlightBar|Original alert:"
+msgstr ""
+
msgid "History"
msgstr ""
@@ -13006,6 +13402,9 @@ msgstr ""
msgid "If enabled, access to projects will be validated on an external service using their classification label."
msgstr ""
+msgid "If the number of active users exceeds the user limit, you will be charged for the number of %{users_over_license_link} at your next license reconciliation."
+msgstr ""
+
msgid "If there is no previous license or if the previous license has expired, some GitLab functionality will be blocked until a new, valid license is uploaded."
msgstr ""
@@ -13045,9 +13444,6 @@ msgstr ""
msgid "If your HTTP repository is not publicly accessible, add your credentials."
msgstr ""
-msgid "Iglu registry URL (optional)"
-msgstr ""
-
msgid "Ignore"
msgstr ""
@@ -13084,6 +13480,18 @@ msgstr ""
msgid "Import"
msgstr ""
+msgid "Import %d compatible repository"
+msgid_plural "Import %d compatible repositories"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
+msgid "Import %d repository"
+msgid_plural "Import %d repositories"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "Import CSV"
msgstr ""
@@ -13093,15 +13501,9 @@ msgstr ""
msgid "Import all compatible projects"
msgstr ""
-msgid "Import all compatible repositories"
-msgstr ""
-
msgid "Import all projects"
msgstr ""
-msgid "Import all repositories"
-msgstr ""
-
msgid "Import an exported GitLab project"
msgstr ""
@@ -13189,6 +13591,9 @@ msgstr ""
msgid "ImportProjects|Error importing repository %{project_safe_import_url} into %{project_full_path} - %{message}"
msgstr ""
+msgid "ImportProjects|Import repositories"
+msgstr ""
+
msgid "ImportProjects|Importing the project failed"
msgstr ""
@@ -13201,7 +13606,7 @@ msgstr ""
msgid "ImportProjects|Requesting your %{provider} repositories failed"
msgstr ""
-msgid "ImportProjects|Select the projects you want to import"
+msgid "ImportProjects|Select the repositories you want to import"
msgstr ""
msgid "ImportProjects|The remote data could not be imported."
@@ -13237,9 +13642,6 @@ msgstr ""
msgid "In order to enable Service Desk for your instance, you must first set up incoming email."
msgstr ""
-msgid "In order to gather accurate feature usage data, it can take 1 to 2 weeks to see your index."
-msgstr ""
-
msgid "In order to personalize your experience with GitLab%{br_tag}we would like to know a bit more about you."
msgstr ""
@@ -13270,18 +13672,30 @@ msgstr ""
msgid "IncidentManagement|Create incident"
msgstr ""
+msgid "IncidentManagement|Critical - S1"
+msgstr ""
+
msgid "IncidentManagement|Date created"
msgstr ""
msgid "IncidentManagement|Display your incidents in a dedicated view"
msgstr ""
+msgid "IncidentManagement|High - S2"
+msgstr ""
+
msgid "IncidentManagement|Incident"
msgstr ""
msgid "IncidentManagement|Incidents"
msgstr ""
+msgid "IncidentManagement|Low - S4"
+msgstr ""
+
+msgid "IncidentManagement|Medium - S3"
+msgstr ""
+
msgid "IncidentManagement|No incidents to display."
msgstr ""
@@ -13294,6 +13708,9 @@ msgstr ""
msgid "IncidentManagement|Published to status page"
msgstr ""
+msgid "IncidentManagement|Severity"
+msgstr ""
+
msgid "IncidentManagement|There are no closed incidents"
msgstr ""
@@ -13303,6 +13720,9 @@ msgstr ""
msgid "IncidentManagement|Unassigned"
msgstr ""
+msgid "IncidentManagement|Unknown"
+msgstr ""
+
msgid "IncidentManagement|Unpublished"
msgstr ""
@@ -13324,6 +13744,15 @@ msgstr ""
msgid "Incidents"
msgstr ""
+msgid "Incident|Alert details"
+msgstr ""
+
+msgid "Incident|Summary"
+msgstr ""
+
+msgid "Incident|There was an issue loading alert data. Please try again."
+msgstr ""
+
msgid "Include a Terms of Service agreement and Privacy Policy that all users must accept."
msgstr ""
@@ -13384,6 +13813,9 @@ msgstr ""
msgid "Information about additional Pages templates and how to install them can be found in our %{pages_getting_started_guide}."
msgstr ""
+msgid "Inherited"
+msgstr ""
+
msgid "Inherited:"
msgstr ""
@@ -13465,7 +13897,22 @@ msgstr ""
msgid "Instance administrators group already exists"
msgstr ""
-msgid "Instance license"
+msgid "InstanceStatistics|Groups"
+msgstr ""
+
+msgid "InstanceStatistics|Issues"
+msgstr ""
+
+msgid "InstanceStatistics|Merge Requests"
+msgstr ""
+
+msgid "InstanceStatistics|Pipelines"
+msgstr ""
+
+msgid "InstanceStatistics|Projects"
+msgstr ""
+
+msgid "InstanceStatistics|Users"
msgstr ""
msgid "Integration"
@@ -13477,6 +13924,12 @@ msgstr ""
msgid "Integrations"
msgstr ""
+msgid "Integrations|%{integration} settings saved and active."
+msgstr ""
+
+msgid "Integrations|%{integration} settings saved, but not active."
+msgstr ""
+
msgid "Integrations|All details"
msgstr ""
@@ -13486,6 +13939,12 @@ msgstr ""
msgid "Integrations|Comment settings:"
msgstr ""
+msgid "Integrations|Connection failed. Please check your settings."
+msgstr ""
+
+msgid "Integrations|Connection successful."
+msgstr ""
+
msgid "Integrations|Default settings are inherited from the group level."
msgstr ""
@@ -13501,6 +13960,15 @@ msgstr ""
msgid "Integrations|Includes commit title and branch"
msgstr ""
+msgid "Integrations|Projects using custom settings will not be impacted unless the project owner chooses to use instance-level defaults."
+msgstr ""
+
+msgid "Integrations|Save settings?"
+msgstr ""
+
+msgid "Integrations|Saving will update the default settings for all projects that are not using custom settings."
+msgstr ""
+
msgid "Integrations|Standard"
msgstr ""
@@ -13633,6 +14101,9 @@ msgstr ""
msgid "Invitation"
msgstr ""
+msgid "Invitation declined"
+msgstr ""
+
msgid "Invite"
msgstr ""
@@ -13684,6 +14155,42 @@ 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|%{linkStart}Read more%{linkEnd} about role permissions"
+msgstr ""
+
+msgid "InviteMembersModal|Access expiration date (optional)"
+msgstr ""
+
+msgid "InviteMembersModal|Cancel"
+msgstr ""
+
+msgid "InviteMembersModal|Choose a role permission"
+msgstr ""
+
+msgid "InviteMembersModal|GitLab member or Email address"
+msgstr ""
+
+msgid "InviteMembersModal|Invite"
+msgstr ""
+
+msgid "InviteMembersModal|Invite team members"
+msgstr ""
+
+msgid "InviteMembersModal|Search for members to invite"
+msgstr ""
+
+msgid "InviteMembersModal|User not invited. Feature coming soon!"
+msgstr ""
+
+msgid "InviteMembersModal|Users were succesfully added"
+msgstr ""
+
+msgid "InviteMembersModal|You're inviting members to the %{group_name} group"
+msgstr ""
+
+msgid "InviteMembers|Invite team members"
+msgstr ""
+
msgid "Invited"
msgstr ""
@@ -13738,10 +14245,13 @@ msgstr ""
msgid "Issue cannot be found."
msgstr ""
+msgid "Issue created from vulnerability %{vulnerability_link}"
+msgstr ""
+
msgid "Issue events"
msgstr ""
-msgid "Issue first depoloyed to production"
+msgid "Issue first deployed to production"
msgstr ""
msgid "Issue label"
@@ -13819,6 +14329,9 @@ msgstr ""
msgid "IssueTracker|Custom issue tracker"
msgstr ""
+msgid "IssueTracker|EWM work items tracker"
+msgstr ""
+
msgid "IssueTracker|Redmine issue tracker"
msgstr ""
@@ -13885,6 +14398,9 @@ msgstr ""
msgid "It looks like you have some draft commits in this branch."
msgstr ""
+msgid "It may be several days before you see feature usage data."
+msgstr ""
+
msgid "It must have a header row and at least two columns: the first column is the issue title and the second column is the issue description. The separator is automatically detected."
msgstr ""
@@ -14167,13 +14683,13 @@ msgstr ""
msgid "Join Zoom meeting"
msgstr ""
-msgid "Jul"
+msgid "Joined %{time_ago}"
msgstr ""
-msgid "July"
+msgid "Jul"
msgstr ""
-msgid "Jump to first unresolved thread"
+msgid "July"
msgstr ""
msgid "Jump to next unresolved thread"
@@ -14209,6 +14725,9 @@ msgstr ""
msgid "Keyboard shortcuts"
msgstr ""
+msgid "KeyboardKey|Ctrl+"
+msgstr ""
+
msgid "Keys"
msgstr ""
@@ -14257,6 +14776,9 @@ msgstr ""
msgid "LDAP Synchronization"
msgstr ""
+msgid "LDAP group settings"
+msgstr ""
+
msgid "LDAP settings"
msgstr ""
@@ -14266,6 +14788,9 @@ msgstr ""
msgid "LDAP sync in progress. This could take a few minutes. Refresh the page to see the changes."
msgstr ""
+msgid "LDAP synchronizations"
+msgstr ""
+
msgid "LFS"
msgstr ""
@@ -14347,7 +14872,16 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
-msgid "Last %{days} days"
+msgid "Last 2 weeks"
+msgstr ""
+
+msgid "Last 30 days"
+msgstr ""
+
+msgid "Last 60 days"
+msgstr ""
+
+msgid "Last 90 days"
msgstr ""
msgid "Last Accessed On"
@@ -14425,6 +14959,9 @@ msgstr ""
msgid "Last used on:"
msgstr ""
+msgid "Last week"
+msgstr ""
+
msgid "LastCommit|authored"
msgstr ""
@@ -14440,6 +14977,9 @@ msgstr ""
msgid "Latest pipeline for the most recent commit on this branch"
msgstr ""
+msgid "Launch a ready-to-code development environment for your project."
+msgstr ""
+
msgid "Lead"
msgstr ""
@@ -14827,6 +15367,9 @@ msgstr ""
msgid "List of all merge commits"
msgstr ""
+msgid "List options"
+msgstr ""
+
msgid "List settings"
msgstr ""
@@ -14839,9 +15382,6 @@ msgstr ""
msgid "List your Bitbucket Server repositories"
msgstr ""
-msgid "Lists"
-msgstr ""
-
msgid "Live preview"
msgstr ""
@@ -15088,6 +15628,12 @@ msgstr ""
msgid "Mark as done"
msgstr ""
+msgid "Mark as draft"
+msgstr ""
+
+msgid "Mark as ready"
+msgstr ""
+
msgid "Mark as resolved"
msgstr ""
@@ -15109,6 +15655,24 @@ msgstr ""
msgid "Markdown is supported"
msgstr ""
+msgid "MarkdownEditor|Add a link (%{modifierKey}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add a link (%{modifier_key}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifierKey}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifier_key}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifierKey}I)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifier_key}I)"
+msgstr ""
+
msgid "Marked For Deletion At - %{deletion_time}"
msgstr ""
@@ -15193,7 +15757,25 @@ msgstr ""
msgid "Max access level"
msgstr ""
-msgid "Max seats used"
+msgid "Max role"
+msgstr ""
+
+msgid "Max size 15 MB"
+msgstr ""
+
+msgid "Maximum Conan package file size in bytes"
+msgstr ""
+
+msgid "Maximum Maven package file size in bytes"
+msgstr ""
+
+msgid "Maximum NPM package file size in bytes"
+msgstr ""
+
+msgid "Maximum NuGet package file size in bytes"
+msgstr ""
+
+msgid "Maximum PyPI package file size in bytes"
msgstr ""
msgid "Maximum Users:"
@@ -15325,6 +15907,18 @@ msgstr ""
msgid "Members with access to %{strong_start}%{group_name}%{strong_end}"
msgstr ""
+msgid "Members|%{time} by %{user}"
+msgstr ""
+
+msgid "Members|Expired"
+msgstr ""
+
+msgid "Members|No expiration set"
+msgstr ""
+
+msgid "Members|in %{time}"
+msgstr ""
+
msgid "Memory Usage"
msgstr ""
@@ -15511,9 +16105,6 @@ msgstr ""
msgid "MergeRequests|Thread will be unresolved"
msgstr ""
-msgid "MergeRequests|Toggle comments for this file"
-msgstr ""
-
msgid "MergeRequests|View file @ %{commitId}"
msgstr ""
@@ -15574,6 +16165,9 @@ msgstr ""
msgid "Merging immediately isn't recommended as it may negatively impact the existing merge train. Read the %{docsLinkStart}documentation%{docsLinkEnd} for more information."
msgstr ""
+msgid "Message"
+msgstr ""
+
msgid "Messages"
msgstr ""
@@ -15961,18 +16555,12 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
-msgid "Milestone does not support burnup charts"
-msgstr ""
-
msgid "Milestone lists not available with your current license"
msgstr ""
msgid "Milestone lists show all issues from the selected milestone."
msgstr ""
-msgid "Milestone must have a start and due date"
-msgstr ""
-
msgid "MilestoneSidebar|Closed:"
msgstr ""
@@ -16339,6 +16927,9 @@ msgstr ""
msgid "Namespace"
msgstr ""
+msgid "Namespace ID:"
+msgstr ""
+
msgid "Namespace is empty"
msgstr ""
@@ -16423,6 +17014,9 @@ msgstr ""
msgid "NetworkPolicies|Allow all outbound traffic from %{selector} to %{ruleSelector} on %{ports}"
msgstr ""
+msgid "NetworkPolicies|Are you sure you want to delete this policy? This action cannot be undone."
+msgstr ""
+
msgid "NetworkPolicies|Choose whether to enforce this policy."
msgstr ""
@@ -16432,12 +17026,21 @@ msgstr ""
msgid "NetworkPolicies|Define this policy's location, conditions and actions."
msgstr ""
+msgid "NetworkPolicies|Delete policy"
+msgstr ""
+
+msgid "NetworkPolicies|Delete policy: %{policy}"
+msgstr ""
+
msgid "NetworkPolicies|Deny all traffic"
msgstr ""
msgid "NetworkPolicies|Description"
msgstr ""
+msgid "NetworkPolicies|Edit policy"
+msgstr ""
+
msgid "NetworkPolicies|Editor mode"
msgstr ""
@@ -16465,6 +17068,9 @@ msgstr ""
msgid "NetworkPolicies|Name"
msgstr ""
+msgid "NetworkPolicies|Namespace"
+msgstr ""
+
msgid "NetworkPolicies|Network Policy"
msgstr ""
@@ -16516,6 +17122,9 @@ msgstr ""
msgid "NetworkPolicies|Rules"
msgstr ""
+msgid "NetworkPolicies|Save changes"
+msgstr ""
+
msgid "NetworkPolicies|Something went wrong, failed to update policy"
msgstr ""
@@ -16528,6 +17137,9 @@ msgstr ""
msgid "NetworkPolicies|Traffic that does not match any rule will be blocked."
msgstr ""
+msgid "NetworkPolicies|Unable to parse policy"
+msgstr ""
+
msgid "NetworkPolicies|YAML editor"
msgstr ""
@@ -16642,6 +17254,9 @@ msgstr ""
msgid "New Snippet"
msgstr ""
+msgid "New Test Case"
+msgstr ""
+
msgid "New User"
msgstr ""
@@ -16741,6 +17356,9 @@ msgstr ""
msgid "New tag"
msgstr ""
+msgid "New test case"
+msgstr ""
+
msgid "New users set to external"
msgstr ""
@@ -16813,7 +17431,7 @@ msgstr ""
msgid "No changes"
msgstr ""
-msgid "No changes between %{ref_start}%{source_branch}%{ref_end} and %{ref_start}%{target_branch}%{ref_end}"
+msgid "No changes between %{sourceBranch} and %{targetBranch}"
msgstr ""
msgid "No child epics match applied filters"
@@ -16828,6 +17446,9 @@ msgstr ""
msgid "No containers available"
msgstr ""
+msgid "No content to show"
+msgstr ""
+
msgid "No contributions"
msgstr ""
@@ -16903,9 +17524,6 @@ msgstr ""
msgid "No license. All rights reserved"
msgstr ""
-msgid "No licenses found."
-msgstr ""
-
msgid "No matches found"
msgstr ""
@@ -16918,6 +17536,9 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No members found"
+msgstr ""
+
msgid "No merge requests found"
msgstr ""
@@ -16939,6 +17560,9 @@ msgstr ""
msgid "No parent group"
msgstr ""
+msgid "No plan"
+msgstr ""
+
msgid "No pods available"
msgstr ""
@@ -17035,6 +17659,12 @@ msgstr ""
msgid "Not Implemented"
msgstr ""
+msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+msgstr ""
+
+msgid "Not all browsers support WebAuthn. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even from an unsupported browser."
+msgstr ""
+
msgid "Not all data has been processed yet, the accuracy of the chart for the selected timeframe is limited."
msgstr ""
@@ -17131,6 +17761,9 @@ msgstr ""
msgid "Notification settings saved"
msgstr ""
+msgid "NotificationEvent|Change reviewer merge request"
+msgstr ""
+
msgid "NotificationEvent|Close issue"
msgstr ""
@@ -17293,10 +17926,7 @@ msgstr ""
msgid "On track"
msgstr ""
-msgid "OnDemandScans|Attached branch"
-msgstr ""
-
-msgid "OnDemandScans|Attached branch is where the scan job runs."
+msgid "OnDemandScans|Could not fetch scanner profiles. Please refresh the page, or try again later."
msgstr ""
msgid "OnDemandScans|Could not fetch site profiles. Please refresh the page, or try again later."
@@ -17305,6 +17935,9 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
+msgid "OnDemandScans|Create a new scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Create a new site profile"
msgstr ""
@@ -17317,6 +17950,9 @@ msgstr ""
msgid "OnDemandScans|New on-demand DAST scan"
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 ""
@@ -17326,16 +17962,10 @@ msgstr ""
msgid "OnDemandScans|On-demand scans run outside the DevOps cycle and find vulnerabilities in your projects. %{learnMoreLinkStart}Learn more%{learnMoreLinkEnd}"
msgstr ""
-msgid "OnDemandScans|Only a passive scan can be performed on demand."
-msgstr ""
-
-msgid "OnDemandScans|Passive"
-msgstr ""
-
msgid "OnDemandScans|Run scan"
msgstr ""
-msgid "OnDemandScans|Scan mode"
+msgid "OnDemandScans|Scanner profile"
msgstr ""
msgid "OnDemandScans|Scanner settings"
@@ -17347,9 +17977,15 @@ msgstr ""
msgid "OnDemandScans|Select one of the existing profiles"
msgstr ""
+msgid "OnDemandScans|Site profile"
+msgstr ""
+
msgid "OnDemandScans|Site profiles"
msgstr ""
+msgid "OnDemandScans|Use existing scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Use existing site profile"
msgstr ""
@@ -17449,9 +18085,6 @@ msgstr ""
msgid "Open Selection"
msgstr ""
-msgid "Open Web IDE"
-msgstr ""
-
msgid "Open comment type dropdown"
msgstr ""
@@ -17557,6 +18190,9 @@ msgstr ""
msgid "Origin"
msgstr ""
+msgid "Orphaned member"
+msgstr ""
+
msgid "Other Labels"
msgstr ""
@@ -17572,6 +18208,9 @@ msgstr ""
msgid "Other visibility settings have been disabled by the administrator."
msgstr ""
+msgid "Our documentation includes an example DevOps Score report."
+msgstr ""
+
msgid "Out-of-compliance with this project's policies and should be removed"
msgstr ""
@@ -17596,6 +18235,9 @@ msgstr ""
msgid "Overwrite diverged branches"
msgstr ""
+msgid "Owned by %{image_tag}"
+msgstr ""
+
msgid "Owned by anyone"
msgstr ""
@@ -17617,6 +18259,9 @@ msgstr ""
msgid "Package deleted successfully"
msgstr ""
+msgid "Package file size limits"
+msgstr ""
+
msgid "Package recipe already exists"
msgstr ""
@@ -17632,9 +18277,6 @@ msgstr ""
msgid "Package type must be PyPi"
msgstr ""
-msgid "Package was removed"
-msgstr ""
-
msgid "PackageRegistry|%{name} version %{version} was created %{datetime}"
msgstr ""
@@ -17776,12 +18418,18 @@ msgstr ""
msgid "PackageRegistry|NuGet Command"
msgstr ""
+msgid "PackageRegistry|Package Registry"
+msgstr ""
+
msgid "PackageRegistry|Pip Command"
msgstr ""
msgid "PackageRegistry|Pipeline %{link} triggered %{datetime} by %{author}"
msgstr ""
+msgid "PackageRegistry|Publish and share packages for a variety of common package managers. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "PackageRegistry|Published to the %{project} Package Registry %{datetime}"
msgstr ""
@@ -17881,6 +18529,9 @@ msgstr ""
msgid "Page not found"
msgstr ""
+msgid "Page settings"
+msgstr ""
+
msgid "Page was successfully deleted"
msgstr ""
@@ -18022,7 +18673,7 @@ msgstr ""
msgid "Paste issue link"
msgstr ""
-msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Don't use your private SSH key."
+msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Do not paste your private SSH key, as that can compromise your identity."
msgstr ""
msgid "Patch to apply"
@@ -18049,6 +18700,9 @@ msgstr ""
msgid "Pending"
msgstr ""
+msgid "Pending comments"
+msgstr ""
+
msgid "People without permission will never get a notification and won't be able to comment."
msgstr ""
@@ -18247,6 +18901,9 @@ msgstr ""
msgid "Pipelines|Build with confidence"
msgstr ""
+msgid "Pipelines|By revoking a trigger you will break any processes making use of it. Are you sure?"
+msgstr ""
+
msgid "Pipelines|CI Lint"
msgstr ""
@@ -18259,6 +18916,15 @@ msgstr ""
msgid "Pipelines|Continuous Integration can help catch bugs by running your tests automatically, while Continuous Deployment can help you deliver code to your product environment."
msgstr ""
+msgid "Pipelines|Copy trigger token"
+msgstr ""
+
+msgid "Pipelines|Description"
+msgstr ""
+
+msgid "Pipelines|Edit"
+msgstr ""
+
msgid "Pipelines|Get started with Pipelines"
msgstr ""
@@ -18274,15 +18940,27 @@ msgstr ""
msgid "Pipelines|It is recommended the code is reviewed thoroughly before running this pipeline with the parent project's CI resource."
msgstr ""
+msgid "Pipelines|Last Used"
+msgstr ""
+
msgid "Pipelines|Loading Pipelines"
msgstr ""
msgid "Pipelines|More Information"
msgstr ""
+msgid "Pipelines|No triggers have been created yet. Add one using the form above."
+msgstr ""
+
+msgid "Pipelines|Owner"
+msgstr ""
+
msgid "Pipelines|Project cache successfully reset."
msgstr ""
+msgid "Pipelines|Revoke"
+msgstr ""
+
msgid "Pipelines|Run Pipeline"
msgstr ""
@@ -18307,6 +18985,15 @@ msgstr ""
msgid "Pipelines|This project is not currently set up to run pipelines."
msgstr ""
+msgid "Pipelines|Token"
+msgstr ""
+
+msgid "Pipelines|Trigger user has insufficient permissions to project"
+msgstr ""
+
+msgid "Pipelines|invalid"
+msgstr ""
+
msgid "Pipelines|parent"
msgstr ""
@@ -18565,10 +19252,10 @@ msgstr ""
msgid "Please provide attributes to update"
msgstr ""
-msgid "Please refer to %{docs_url}"
+msgid "Please reach out if you have any questions and we'll be happy to assist."
msgstr ""
-msgid "Please retype the email address."
+msgid "Please refer to %{docs_url}"
msgstr ""
msgid "Please select"
@@ -18598,6 +19285,9 @@ msgstr ""
msgid "Please set a new password before proceeding."
msgstr ""
+msgid "Please share your feedback about %{featureName} %{linkStart}in this issue%{linkEnd} to help us improve the experience."
+msgstr ""
+
msgid "Please solve the reCAPTCHA"
msgstr ""
@@ -18901,6 +19591,9 @@ msgstr ""
msgid "Profiles| You are going to change the username %{currentUsernameBold} to %{newUsernameBold}. Profile and projects will be redirected to the %{newUsername} namespace but this redirect will expire once the %{currentUsername} namespace is registered by another user or group. Please update your Git repository remotes as soon as possible."
msgstr ""
+msgid "Profiles|%{provider} Active"
+msgstr ""
+
msgid "Profiles|@username"
msgstr ""
@@ -18952,7 +19645,7 @@ msgstr ""
msgid "Profiles|Commit email"
msgstr ""
-msgid "Profiles|Connect"
+msgid "Profiles|Connect %{provider}"
msgstr ""
msgid "Profiles|Connected Accounts"
@@ -18976,6 +19669,9 @@ msgstr ""
msgid "Profiles|Disconnect"
msgstr ""
+msgid "Profiles|Disconnect %{provider}"
+msgstr ""
+
msgid "Profiles|Do not show on profile"
msgstr ""
@@ -19000,7 +19696,7 @@ msgstr ""
msgid "Profiles|Full name"
msgstr ""
-msgid "Profiles|Give your individual key a title. This will be publically visible."
+msgid "Profiles|Give your individual key a title."
msgstr ""
msgid "Profiles|Include private contributions on my profile"
@@ -19090,7 +19786,7 @@ msgstr ""
msgid "Profiles|The maximum file size allowed is 200KB."
msgstr ""
-msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it?"
+msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it? It will be publicly visible."
msgstr ""
msgid "Profiles|This email will be displayed on your public profile"
@@ -19165,6 +19861,9 @@ msgstr ""
msgid "Profiles|You don't have access to delete this user."
msgstr ""
+msgid "Profiles|You must transfer ownership or delete groups you are an owner of before you can delete your account"
+msgstr ""
+
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
@@ -19753,6 +20452,9 @@ msgstr ""
msgid "ProjectTemplates|GitLab Cluster Management"
msgstr ""
+msgid "ProjectTemplates|Gitpod/Spring Petclinic"
+msgstr ""
+
msgid "ProjectTemplates|Go Micro"
msgstr ""
@@ -20362,6 +21064,9 @@ msgstr ""
msgid "Publish to status page"
msgstr ""
+msgid "Published"
+msgstr ""
+
msgid "Published on status page"
msgstr ""
@@ -20479,9 +21184,15 @@ msgstr ""
msgid "Quick range"
msgstr ""
+msgid "Quickly and easily edit multiple files in your project."
+msgstr ""
+
msgid "README"
msgstr ""
+msgid "Rails"
+msgstr ""
+
msgid "Rake Tasks Help"
msgstr ""
@@ -20602,10 +21313,13 @@ msgstr ""
msgid "Register Two-Factor Authenticator"
msgstr ""
-msgid "Register U2F device"
+msgid "Register Universal Two-Factor (U2F) Device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register WebAuthn Device"
+msgstr ""
+
+msgid "Register device"
msgstr ""
msgid "Register for GitLab"
@@ -20617,9 +21331,6 @@ msgstr ""
msgid "Register with two-factor app"
msgstr ""
-msgid "Registration"
-msgstr ""
-
msgid "Registration|Checkout"
msgstr ""
@@ -20737,9 +21448,6 @@ msgstr ""
msgid "Release|Something went wrong while saving the release details"
msgstr ""
-msgid "Remediated: needs review"
-msgstr ""
-
msgid "Remediations"
msgstr ""
@@ -20845,6 +21553,9 @@ msgstr ""
msgid "Remove priority"
msgstr ""
+msgid "Remove report"
+msgstr ""
+
msgid "Remove secondary node"
msgstr ""
@@ -20857,6 +21568,12 @@ msgstr ""
msgid "Remove time estimate"
msgstr ""
+msgid "Remove user & report"
+msgstr ""
+
+msgid "Remove user from group"
+msgstr ""
+
msgid "Removed"
msgstr ""
@@ -20938,9 +21655,6 @@ msgstr ""
msgid "Removes time estimate."
msgstr ""
-msgid "Removing license…"
-msgstr ""
-
msgid "Removing this group also removes all child projects, including archived projects, and their resources."
msgstr ""
@@ -21025,6 +21739,9 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
+msgid "Reported by %{reporter}"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -21112,6 +21829,27 @@ msgstr ""
msgid "Repositories"
msgstr ""
+msgid "Repositories Analytics"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download Historic Test Coverage Data"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download historic test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Historic Test Coverage Data is available in raw format (.csv) for further analysis."
+msgstr ""
+
+msgid "RepositoriesAnalytics|Test Code Coverage"
+msgstr ""
+
+msgid "RepositoriesAnalytics|There was an error fetching the projects."
+msgstr ""
+
msgid "Repository"
msgstr ""
@@ -21190,9 +21928,15 @@ msgstr ""
msgid "Request parameter %{param} is missing."
msgstr ""
+msgid "Request review from"
+msgstr ""
+
msgid "Request to link SAML account must be authorized"
msgstr ""
+msgid "Requested"
+msgstr ""
+
msgid "Requested %{time_ago}"
msgstr ""
@@ -21211,6 +21955,9 @@ msgstr ""
msgid "Requests to these domain(s)/address(es) on the local network will be allowed when local requests from hooks and services are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 or 127.0.0.0/28 are supported. Domain wildcards are not supported currently. Use comma, semicolon, or newline to separate multiple entries. The allowlist can hold a maximum of 1000 entries. Domains should use IDNA encoding. Ex: example.com, 192.168.1.1, 127.0.0.0/28, xn--itlab-j1a.com."
msgstr ""
+msgid "Require admin approval for new sign-ups"
+msgstr ""
+
msgid "Require all users in this group to setup Two-factor authentication"
msgstr ""
@@ -21340,9 +22087,6 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
-msgid "Resolved by %{resolvedByName}"
-msgstr ""
-
msgid "Resolves IP addresses once and uses them to submit requests"
msgstr ""
@@ -21463,6 +22207,15 @@ msgstr ""
msgid "ReviewApp|Enable Review App"
msgstr ""
+msgid "Reviewer"
+msgid_plural "%d Reviewers"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
+msgid "Reviewer(s)"
+msgstr ""
+
msgid "Reviewing"
msgstr ""
@@ -21502,6 +22255,9 @@ msgstr ""
msgid "Rook"
msgstr ""
+msgid "Ruby"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -21580,6 +22336,63 @@ msgstr ""
msgid "Runners page."
msgstr ""
+msgid "Runners|Active"
+msgstr ""
+
+msgid "Runners|Architecture"
+msgstr ""
+
+msgid "Runners|Can run untagged jobs"
+msgstr ""
+
+msgid "Runners|Description"
+msgstr ""
+
+msgid "Runners|Group"
+msgstr ""
+
+msgid "Runners|IP Address"
+msgstr ""
+
+msgid "Runners|Last contact"
+msgstr ""
+
+msgid "Runners|Locked to this project"
+msgstr ""
+
+msgid "Runners|Maximum job timeout"
+msgstr ""
+
+msgid "Runners|Name"
+msgstr ""
+
+msgid "Runners|Platform"
+msgstr ""
+
+msgid "Runners|Property Name"
+msgstr ""
+
+msgid "Runners|Protected"
+msgstr ""
+
+msgid "Runners|Revision"
+msgstr ""
+
+msgid "Runners|Shared"
+msgstr ""
+
+msgid "Runners|Specific"
+msgstr ""
+
+msgid "Runners|Tags"
+msgstr ""
+
+msgid "Runners|Value"
+msgstr ""
+
+msgid "Runners|Version"
+msgstr ""
+
msgid "Runners|You have used %{quotaUsed} out of %{quotaLimit} of your shared Runners pipeline minutes."
msgstr ""
@@ -21592,6 +22405,9 @@ msgstr ""
msgid "Runs a number of housekeeping tasks within the current repository, such as compressing file revisions and removing unreachable objects."
msgstr ""
+msgid "SAML"
+msgstr ""
+
msgid "SAML SSO"
msgstr ""
@@ -21643,6 +22459,9 @@ msgstr ""
msgid "Save"
msgstr ""
+msgid "Save %{name} size limits"
+msgstr ""
+
msgid "Save Changes"
msgstr ""
@@ -21673,9 +22492,6 @@ msgstr ""
msgid "Save space and find tags in the Container Registry more easily. Enable the cleanup policy to remove stale tags and keep only the ones you need."
msgstr ""
-msgid "Save template"
-msgstr ""
-
msgid "Save variables"
msgstr ""
@@ -21718,9 +22534,6 @@ msgstr ""
msgid "Scope"
msgstr ""
-msgid "Scope not supported with disabled 'users_search' feature!"
-msgstr ""
-
msgid "Scoped issue boards"
msgstr ""
@@ -21847,9 +22660,6 @@ msgstr ""
msgid "Search requirements"
msgstr ""
-msgid "Search results…"
-msgstr ""
-
msgid "Search users"
msgstr ""
@@ -21925,6 +22735,12 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgid "SearchResults|epic"
+msgid_plural "SearchResults|epics"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "SearchResults|issue"
msgid_plural "SearchResults|issues"
msgstr[0] ""
@@ -21976,10 +22792,10 @@ msgstr ""
msgid "Seat Link is disabled, and cannot be configured through this form."
msgstr ""
-msgid "Seats currently in use"
+msgid "Seats usage data as of %{last_enqueue_time}"
msgstr ""
-msgid "Seats in license"
+msgid "Seats usage data is updated every day at 12:00pm UTC"
msgstr ""
msgid "Secondary"
@@ -22033,6 +22849,9 @@ msgstr ""
msgid "SecurityConfiguration|Available for on-demand DAST"
msgstr ""
+msgid "SecurityConfiguration|By default, all analyzers are applied in order to cover all languages across your project, and only run if the language is detected in the Merge Request."
+msgstr ""
+
msgid "SecurityConfiguration|Configure"
msgstr ""
@@ -22063,16 +22882,19 @@ msgstr ""
msgid "SecurityConfiguration|Manage"
msgstr ""
+msgid "SecurityConfiguration|More information"
+msgstr ""
+
msgid "SecurityConfiguration|Not enabled"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|Security Control"
+msgid "SecurityConfiguration|SAST Configuration"
msgstr ""
-msgid "SecurityConfiguration|See documentation"
+msgid "SecurityConfiguration|Security Control"
msgstr ""
msgid "SecurityConfiguration|Status"
@@ -22084,6 +22906,9 @@ msgstr ""
msgid "SecurityConfiguration|Using custom settings. You won't receive automatic updates on this variable. %{anchorStart}Restore to default%{anchorEnd}"
msgstr ""
+msgid "SecurityConfiguration|View history"
+msgstr ""
+
msgid "SecurityConfiguration|You can quickly enable all security scanning tools by enabling %{linkStart}Auto DevOps%{linkEnd}."
msgstr ""
@@ -22162,9 +22987,6 @@ msgstr ""
msgid "SecurityReports|Learn more about setting up your dashboard"
msgstr ""
-msgid "SecurityReports|Load more vulnerabilities"
-msgstr ""
-
msgid "SecurityReports|Monitor vulnerabilities in your code"
msgstr ""
@@ -22444,7 +23266,7 @@ msgstr ""
msgid "Select status"
msgstr ""
-msgid "Select strategy activation method"
+msgid "Select strategy activation method."
msgstr ""
msgid "Select subscription"
@@ -22459,7 +23281,7 @@ msgstr ""
msgid "Select the custom project template source group."
msgstr ""
-msgid "Select timeframe"
+msgid "Select the environment scope for this feature flag."
msgstr ""
msgid "Select timezone"
@@ -22708,6 +23530,9 @@ msgstr ""
msgid "Set iteration"
msgstr ""
+msgid "Set limit to 0 to allow any file size."
+msgstr ""
+
msgid "Set max session time for web terminal."
msgstr ""
@@ -22786,10 +23611,13 @@ msgstr ""
msgid "Set up a %{type} Runner manually"
msgstr ""
+msgid "Set up a hardware device as a second factor to sign in."
+msgstr ""
+
msgid "Set up assertions/attributes/claims (email, first_name, last_name) and NameID according to %{docsLinkStart}the documentation %{icon}%{docsLinkEnd}"
msgstr ""
-msgid "Set up new U2F device"
+msgid "Set up new device"
msgstr ""
msgid "Set up new password"
@@ -22858,6 +23686,9 @@ msgstr ""
msgid "Sets weight to %{weight}."
msgstr ""
+msgid "Setting this to 0 means using the system default timeout value."
+msgstr ""
+
msgid "Settings"
msgstr ""
@@ -22873,6 +23704,15 @@ msgstr ""
msgid "Severity"
msgstr ""
+msgid "SeverityWidget|Severity"
+msgstr ""
+
+msgid "SeverityWidget|Severity: %{severity}"
+msgstr ""
+
+msgid "SeverityWidget|There was an error while updating severity."
+msgstr ""
+
msgid "Shards (%{shards})"
msgstr ""
@@ -22918,6 +23758,9 @@ msgstr ""
msgid "Show all requirements."
msgstr ""
+msgid "Show all test cases."
+msgstr ""
+
msgid "Show archived projects"
msgstr ""
@@ -22930,6 +23773,9 @@ msgstr ""
msgid "Show comments"
msgstr ""
+msgid "Show comments on this file"
+msgstr ""
+
msgid "Show comments only"
msgstr ""
@@ -22975,6 +23821,12 @@ msgstr ""
msgid "Show parent subgroups"
msgstr ""
+msgid "Show the Closed list"
+msgstr ""
+
+msgid "Show the Open list"
+msgstr ""
+
msgid "Show whitespace changes"
msgstr ""
@@ -23020,9 +23872,6 @@ msgstr ""
msgid "Sidebar|Assign health status"
msgstr ""
-msgid "Sidebar|Change weight"
-msgstr ""
-
msgid "Sidebar|Health status"
msgstr ""
@@ -23206,6 +24055,9 @@ msgstr ""
msgid "Snippets|Add another file %{num}/%{total}"
msgstr ""
+msgid "Snippets|Authored %{time_ago} by %{author}"
+msgstr ""
+
msgid "Snippets|Delete file"
msgstr ""
@@ -23233,6 +24085,9 @@ msgstr ""
msgid "Solution"
msgstr ""
+msgid "Some changes are not shown"
+msgstr ""
+
msgid "Some child epics may be hidden due to applied filters"
msgstr ""
@@ -23599,6 +24454,12 @@ msgstr ""
msgid "Source (branch or tag)"
msgstr ""
+msgid "Source Branch"
+msgstr ""
+
+msgid "Source branch: %{source_branch_open}%{source_branch}%{source_branch_close}"
+msgstr ""
+
msgid "Source code"
msgstr ""
@@ -23764,9 +24625,6 @@ msgstr ""
msgid "Start and due date"
msgstr ""
-msgid "Start by choosing a group to see how your team is spending time. You can then drill down to the project level."
-msgstr ""
-
msgid "Start by choosing a group to start exploring the merge requests in that group. You can then proceed to filter by projects, labels, milestones and authors."
msgstr ""
@@ -23848,18 +24706,27 @@ msgstr ""
msgid "StaticSiteEditor|3. Assign a person to review and accept the merge request."
msgstr ""
+msgid "StaticSiteEditor|A link to view the merge request will appear once ready."
+msgstr ""
+
msgid "StaticSiteEditor|An error occurred while submitting your changes."
msgstr ""
msgid "StaticSiteEditor|Branch could not be created."
msgstr ""
+msgid "StaticSiteEditor|Copy update"
+msgstr ""
+
msgid "StaticSiteEditor|Could not commit the content changes."
msgstr ""
msgid "StaticSiteEditor|Could not create merge request."
msgstr ""
+msgid "StaticSiteEditor|Creating your merge request"
+msgstr ""
+
msgid "StaticSiteEditor|Incompatible file content"
msgstr ""
@@ -23881,6 +24748,9 @@ msgstr ""
msgid "StaticSiteEditor|View documentation"
msgstr ""
+msgid "StaticSiteEditor|You can set an assignee to get your changes reviewed and deployed once your merge request is created."
+msgstr ""
+
msgid "StaticSiteEditor|Your merge request has been created"
msgstr ""
@@ -24010,15 +24880,15 @@ msgstr ""
msgid "Submit %{humanized_resource_name}"
msgstr ""
-msgid "Submit Changes"
-msgstr ""
-
msgid "Submit a review"
msgstr ""
msgid "Submit as spam"
msgstr ""
+msgid "Submit changes"
+msgstr ""
+
msgid "Submit feedback"
msgstr ""
@@ -24172,6 +25042,9 @@ msgstr ""
msgid "Successfully deleted U2F device."
msgstr ""
+msgid "Successfully deleted WebAuthn device."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -24490,9 +25363,6 @@ msgstr ""
msgid "Template to append to all Service Desk issues"
msgstr ""
-msgid "Template was successfully saved."
-msgstr ""
-
msgid "Templates"
msgstr ""
@@ -24574,10 +25444,28 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
-msgid "Test failed."
+msgid "Test settings"
+msgstr ""
+
+msgid "TestCases|New Test Case"
+msgstr ""
+
+msgid "TestCases|New test case"
+msgstr ""
+
+msgid "TestCases|Search test cases"
msgstr ""
-msgid "Test settings and save changes"
+msgid "TestCases|Something went wrong while creating a test case."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching count of test cases."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching test cases list."
+msgstr ""
+
+msgid "TestCases|Submit test case"
msgstr ""
msgid "TestHooks|Ensure one of your projects has merge requests."
@@ -24643,6 +25531,9 @@ msgstr ""
msgid "Thank you for signing up for your free trial! You will get additional instructions in your inbox shortly."
msgstr ""
+msgid "Thank you for your business."
+msgstr ""
+
msgid "Thank you for your feedback!"
msgstr ""
@@ -24703,9 +25594,6 @@ msgstr ""
msgid "The URL to use for connecting to Elasticsearch. Use a comma-separated list to support clustering (e.g., \"http://localhost:9200, http://localhost:9201\")."
msgstr ""
-msgid "The Web IDE offers advanced syntax highlighting capabilities and more."
-msgstr ""
-
msgid "The X509 Certificate to use when mutual TLS is required to communicate with the external authorization service. If left blank, the server certificate is still validated when accessing over HTTPS."
msgstr ""
@@ -24817,6 +25705,9 @@ msgstr ""
msgid "The form contains the following error:"
msgstr ""
+msgid "The form contains the following warning:"
+msgstr ""
+
msgid "The global settings require you to enable Two-Factor Authentication for your account."
msgstr ""
@@ -24931,9 +25822,6 @@ msgstr ""
msgid "The private key to use when a client certificate is provided. This value is encrypted at rest."
msgstr ""
-msgid "The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The project can be accessed by any logged in user."
msgstr ""
@@ -24970,7 +25858,7 @@ msgstr ""
msgid "The remote repository is being updated..."
msgstr ""
-msgid "The repository can be commited to, and issues, comments and other entities can be created."
+msgid "The repository can be committed to, and issues, comments and other entities can be created."
msgstr ""
msgid "The repository for this project does not exist."
@@ -25024,9 +25912,6 @@ msgstr ""
msgid "The time taken by each data entry gathered by that stage."
msgstr ""
-msgid "The total stage shows the time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The update action will time out after %{number_of_minutes} minutes. For big repositories, use a clone/push combination."
msgstr ""
@@ -25090,6 +25975,9 @@ msgstr ""
msgid "There are no archived requirements"
msgstr ""
+msgid "There are no archived test cases"
+msgstr ""
+
msgid "There are no changes"
msgstr ""
@@ -25129,6 +26017,9 @@ msgstr ""
msgid "There are no open requirements"
msgstr ""
+msgid "There are no open test cases"
+msgstr ""
+
msgid "There are no packages yet"
msgstr ""
@@ -25141,6 +26032,9 @@ msgstr ""
msgid "There is a limit of %{ci_project_subscriptions_limit} subscriptions from or to a project."
msgstr ""
+msgid "There is already a To-Do for this design."
+msgstr ""
+
msgid "There is already a repository with that name on disk"
msgstr ""
@@ -25159,6 +26053,9 @@ msgstr ""
msgid "There was a problem communicating with your device."
msgstr ""
+msgid "There was a problem fetching branches."
+msgstr ""
+
msgid "There was a problem fetching groups."
msgstr ""
@@ -25387,9 +26284,15 @@ msgstr ""
msgid "This action can lead to data loss. To prevent accidental actions we ask you to confirm your intention."
msgstr ""
+msgid "This action cannot be undone, and will permanently delete the %{key} SSH key"
+msgstr ""
+
msgid "This action cannot be undone. You will lose the project's repository and all content: issues, merge requests, etc."
msgstr ""
+msgid "This action has been performed too many times. Try again later."
+msgstr ""
+
msgid "This action will %{strongOpen}permanently delete%{strongClose} %{codeOpen}%{project}%{codeClose} %{strongOpen}immediately%{strongClose}, including its repositories and all content: issues, merge requests, etc."
msgstr ""
@@ -25417,9 +26320,6 @@ msgstr ""
msgid "This board's scope is reduced"
msgstr ""
-msgid "This branch has changed since you started editing. Would you like to create a new branch?"
-msgstr ""
-
msgid "This chart could not be displayed"
msgstr ""
@@ -25546,15 +26446,9 @@ msgstr ""
msgid "This is a security log of important events involving your account."
msgstr ""
-msgid "This is the author's first Merge Request to this project."
-msgstr ""
-
msgid "This is the highest peak of users on your installation since the license started."
msgstr ""
-msgid "This is the maximum number of users that have existed at the same time since the license started. This is the minimum number of seats you will need to buy when you renew your license."
-msgstr ""
-
msgid "This is the number of currently active users on your installation, and this is the minimum number you need to purchase when you renew your license."
msgstr ""
@@ -25786,6 +26680,15 @@ msgstr ""
msgid "This user has no identities"
msgstr ""
+msgid "This user has previously committed to the %{name} project."
+msgstr ""
+
+msgid "This user has the %{access} role in the %{name} project."
+msgstr ""
+
+msgid "This user is the author of this %{noteable}."
+msgstr ""
+
msgid "This user will be the author of all events in the activity feed that are the result of an update, like new branches being created or new commits being pushed to existing branches."
msgstr ""
@@ -25816,6 +26719,9 @@ msgstr ""
msgid "Threat Monitoring"
msgstr ""
+msgid "ThreatMonitoring|All Environments"
+msgstr ""
+
msgid "ThreatMonitoring|Anomalous Requests"
msgstr ""
@@ -25843,9 +26749,6 @@ msgstr ""
msgid "ThreatMonitoring|Operations Per Second"
msgstr ""
-msgid "ThreatMonitoring|Overview"
-msgstr ""
-
msgid "ThreatMonitoring|Packet Activity"
msgstr ""
@@ -25864,6 +26767,9 @@ msgstr ""
msgid "ThreatMonitoring|Something went wrong, unable to fetch statistics"
msgstr ""
+msgid "ThreatMonitoring|Statistics"
+msgstr ""
+
msgid "ThreatMonitoring|The firewall is not installed or has been disabled. To view this data, ensure the web application firewall is installed and enabled for your cluster."
msgstr ""
@@ -26257,6 +27163,9 @@ msgstr ""
msgid "To update Snippets with multiple files, you must use the `files` parameter"
msgstr ""
+msgid "To use Gitpod you must first enable the feature in the integrations section of your %{user_prefs}."
+msgstr ""
+
msgid "To view all %{scannedResourcesCount} scanned URLs, please download the CSV file"
msgstr ""
@@ -26290,9 +27199,6 @@ msgstr ""
msgid "Toggle Sidebar"
msgstr ""
-msgid "Toggle all threads"
-msgstr ""
-
msgid "Toggle backtrace"
msgstr ""
@@ -26317,9 +27223,6 @@ msgstr ""
msgid "Toggle navigation"
msgstr ""
-msgid "Toggle project"
-msgstr ""
-
msgid "Toggle sidebar"
msgstr ""
@@ -26359,6 +27262,9 @@ msgstr ""
msgid "Too many projects enabled. You will need to manage them via the console or the API."
msgstr ""
+msgid "Too much data"
+msgstr ""
+
msgid "Topics (optional)"
msgstr ""
@@ -26377,6 +27283,9 @@ msgstr ""
msgid "Total cores (CPUs)"
msgstr ""
+msgid "Total days to completion"
+msgstr ""
+
msgid "Total issues"
msgstr ""
@@ -26473,6 +27382,9 @@ msgstr ""
msgid "Trending"
msgstr ""
+msgid "Trials|Create a new group to start your GitLab Gold trial."
+msgstr ""
+
msgid "Trials|Go back to GitLab"
msgstr ""
@@ -26482,6 +27394,15 @@ msgstr ""
msgid "Trials|You can always resume this process by selecting your avatar and choosing 'Start a Gold trial'"
msgstr ""
+msgid "Trials|You can apply your trial to a new group or an existing group."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group or your personal account."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group, an existing group, or your personal account."
+msgstr ""
+
msgid "Trials|You won't get a free trial right now but you can always resume this process by clicking on your avatar and choosing 'Start a free trial'"
msgstr ""
@@ -26551,6 +27472,9 @@ msgstr ""
msgid "Try using a different search term to find the file you are looking for."
msgstr ""
+msgid "Trying to communicate with your device. Plug it in (if needed) and press the button on the device now."
+msgstr ""
+
msgid "Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now."
msgstr ""
@@ -26638,6 +27562,12 @@ msgstr ""
msgid "URL or request ID"
msgstr ""
+msgid "USER %{user} WILL BE REMOVED! Are you sure?"
+msgstr ""
+
+msgid "USER WILL BE BLOCKED! Are you sure?"
+msgstr ""
+
msgid "UTC"
msgstr ""
@@ -26695,9 +27625,6 @@ msgstr ""
msgid "Unable to load the merge request widget. Try reloading the page."
msgstr ""
-msgid "Unable to resolve"
-msgstr ""
-
msgid "Unable to save iteration. Please try again"
msgstr ""
@@ -26746,6 +27673,9 @@ msgstr ""
msgid "Undo ignore"
msgstr ""
+msgid "Unexpected error"
+msgstr ""
+
msgid "Unfortunately, your email message to GitLab could not be processed."
msgstr ""
@@ -26779,6 +27709,9 @@ msgstr ""
msgid "Unknown response text"
msgstr ""
+msgid "Unless otherwise agreed to in writing with GitLab, by clicking \"Upload License\" you agree that your use of GitLab Software is subject to the %{eula_link_start}Terms of Service%{eula_link_end}."
+msgstr ""
+
msgid "Unlimited"
msgstr ""
@@ -27145,9 +28078,6 @@ msgstr ""
msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
msgstr ""
-msgid "Use a hardware device to add the second factor of authentication."
-msgstr ""
-
msgid "Use an one time password authenticator on your mobile device or computer to enable two-factor authentication (2FA)."
msgstr ""
@@ -27421,13 +28351,13 @@ msgstr ""
msgid "Users"
msgstr ""
-msgid "Users in License:"
+msgid "Users in License"
msgstr ""
-msgid "Users or groups set as approvers in the project's or merge request's settings."
+msgid "Users in License:"
msgstr ""
-msgid "Users outside of license"
+msgid "Users or groups set as approvers in the project's or merge request's settings."
msgstr ""
msgid "Users over License:"
@@ -27445,9 +28375,6 @@ msgstr ""
msgid "Users with a Guest role or those who don't belong to a Project or Group will not use a seat from your license."
msgstr ""
-msgid "Users with a Guest role or those who don't belong to any projects or groups don't count towards seats in use."
-msgstr ""
-
msgid "UsersSelect|%{name} + %{length} more"
msgstr ""
@@ -27487,9 +28414,6 @@ msgstr ""
msgid "Validations failed."
msgstr ""
-msgid "Validity"
-msgstr ""
-
msgid "Value"
msgstr ""
@@ -27508,6 +28432,9 @@ msgstr ""
msgid "Value Stream Name"
msgstr ""
+msgid "ValueStreamAnalyticsStage|We don't have enough data to show this stage."
+msgstr ""
+
msgid "ValueStreamAnalytics|%{days}d"
msgstr ""
@@ -27766,6 +28693,9 @@ msgstr ""
msgid "VisualReviewApp|Steps 1 and 2 (and sometimes 3) are performed once by the developer before requesting feedback. Steps 3 (if necessary), 4 is performed by the reviewer each time they perform a review."
msgstr ""
+msgid "Visualization"
+msgstr ""
+
msgid "Vulnerabilities"
msgstr ""
@@ -27793,34 +28723,31 @@ msgstr ""
msgid "VulnerabilityChart|Severity"
msgstr ""
-msgid "VulnerabilityManagement|A true-positive and will fix"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Change status"
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|Confirm"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Confirmed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
-msgstr ""
-
-msgid "VulnerabilityManagement|Detected %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|A true-positive and will fix"
msgstr ""
-msgid "VulnerabilityManagement|Dismiss"
+msgid "VulnerabilityManagement|Change status"
msgstr ""
-msgid "VulnerabilityManagement|Dismissed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
msgstr ""
-msgid "VulnerabilityManagement|Resolved"
+msgid "VulnerabilityManagement|Detected"
msgstr ""
-msgid "VulnerabilityManagement|Resolved %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Needs triage"
msgstr ""
msgid "VulnerabilityManagement|Something went wrong while trying to delete the comment. Please try again later."
@@ -27871,6 +28798,9 @@ msgstr ""
msgid "Vulnerability|%{scannerName} (version %{scannerVersion})"
msgstr ""
+msgid "Vulnerability|Activity"
+msgstr ""
+
msgid "Vulnerability|Class"
msgstr ""
@@ -27883,6 +28813,9 @@ msgstr ""
msgid "Vulnerability|Description"
msgstr ""
+msgid "Vulnerability|Detected"
+msgstr ""
+
msgid "Vulnerability|Evidence"
msgstr ""
@@ -27946,6 +28879,9 @@ msgstr ""
msgid "Warning: Displaying this diagram might cause performance issues on this page."
msgstr ""
+msgid "We are currently unable to fetch data for the pipeline header."
+msgstr ""
+
msgid "We are currently unable to fetch data for this graph."
msgstr ""
@@ -27985,6 +28921,12 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
+msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
+msgstr ""
+
+msgid "We would like to inform you that your subscription GitLab Enterprise Edition %{plan_name} is nearing its user limit. You have %{active_user_count} active users, which is almost at the user limit of %{maximum_user_count}."
+msgstr ""
+
msgid "We've found no vulnerabilities"
msgstr ""
@@ -28000,6 +28942,12 @@ msgstr ""
msgid "Web terminal"
msgstr ""
+msgid "WebAuthn Devices (%{length})"
+msgstr ""
+
+msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
+msgstr ""
+
msgid "WebIDE|Merge request"
msgstr ""
@@ -28138,15 +29086,9 @@ msgstr ""
msgid "Welcome to the guided GitLab tour"
msgstr ""
-msgid "Welcome to your Issue Board!"
-msgstr ""
-
msgid "Welcome to your issue board!"
msgstr ""
-msgid "We’ve been making changes to %{featureName} and we’d love your feedback %{linkStart}in this issue%{linkEnd} to help us improve the experience."
-msgstr ""
-
msgid "What are you searching for?"
msgstr ""
@@ -28165,6 +29107,9 @@ msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
msgstr ""
+msgid "When enabled, any user visiting %{host} and creating an account will have to be explicitly approved by the admin before they can login. This setting is effective only if sign-ups are enabled."
+msgstr ""
+
msgid "When enabled, any user visiting %{host} will be able to create an account."
msgstr ""
@@ -28390,6 +29335,9 @@ msgstr ""
msgid "With requirements, you can set criteria to check your products against."
msgstr ""
+msgid "With test cases, you can define conditions for your project to meet in determining quality"
+msgstr ""
+
msgid "Withdraw Access Request"
msgstr ""
@@ -28405,6 +29353,9 @@ msgstr ""
msgid "Workflow Help"
msgstr ""
+msgid "Would you like to create a new branch?"
+msgstr ""
+
msgid "Write"
msgstr ""
@@ -28426,6 +29377,9 @@ msgstr ""
msgid "Wrong extern UID provided. Make sure Auth0 is configured correctly."
msgstr ""
+msgid "YYYY-MM-DD"
+msgstr ""
+
msgid "Yes"
msgstr ""
@@ -28483,7 +29437,7 @@ msgstr ""
msgid "You are going to remove the fork relationship from %{project_full_name}. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "You are going to transfer %{project_full_name} to another owner. Are you ABSOLUTELY sure?"
+msgid "You are going to transfer %{project_full_name} to another namespace. Are you ABSOLUTELY sure?"
msgstr ""
msgid "You are going to turn off the confidentiality. This means %{strongStart}everyone%{strongEnd} will be able to see and leave a comment on this %{issuableType}."
@@ -28543,9 +29497,6 @@ msgstr ""
msgid "You can always edit this later"
msgstr ""
-msgid "You can apply your Trial to your Personal account or create a New Group."
-msgstr ""
-
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings"
msgstr ""
@@ -28567,12 +29518,18 @@ msgstr ""
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
+msgid "You can find more information about GitLab subscriptions in %{subscriptions_doc_link}."
+msgstr ""
+
msgid "You can generate an access token scoped to this project for each application to use the GitLab API."
msgstr ""
msgid "You can get started by cloning the repository or start adding files to it with one of the following options."
msgstr ""
+msgid "You can group test cases using labels. To learn about the future direction of this feature, visit %{linkStart}Quality Management direction page%{linkEnd}."
+msgstr ""
+
msgid "You can invite a new member to %{project_name} or invite another group."
msgstr ""
@@ -28588,6 +29545,9 @@ msgstr ""
msgid "You can notify the app / group or a project by sending them an email notification"
msgstr ""
+msgid "You can now close this window."
+msgstr ""
+
msgid "You can now export your security dashboard to a CSV report."
msgstr ""
@@ -28636,9 +29596,6 @@ msgstr ""
msgid "You can test your .gitlab-ci.yml in %{linkStart}CI Lint%{linkEnd}."
msgstr ""
-msgid "You can try again using %{begin_link}basic search%{end_link}"
-msgstr ""
-
msgid "You cannot access the raw file. Please wait a minute."
msgstr ""
@@ -28690,6 +29647,9 @@ msgstr ""
msgid "You don't have any U2F devices registered yet."
msgstr ""
+msgid "You don't have any WebAuthn devices registered yet."
+msgstr ""
+
msgid "You don't have any active chat names."
msgstr ""
@@ -28777,6 +29737,9 @@ msgstr ""
msgid "You must accept our Terms of Service and privacy policy in order to register an account"
msgstr ""
+msgid "You must be logged in to search across all of GitLab"
+msgstr ""
+
msgid "You must disassociate %{domain} from all clusters it is attached to before deletion."
msgstr ""
@@ -28816,7 +29779,7 @@ msgstr ""
msgid "You need to be logged in."
msgstr ""
-msgid "You need to register a two-factor authentication app before you can set up a U2F device."
+msgid "You need to register a two-factor authentication app before you can set up a device."
msgstr ""
msgid "You need to set terms to be enforced"
@@ -28834,6 +29797,9 @@ msgstr ""
msgid "You reached %{usage_in_percent} of %{namespace_name}'s storage capacity (%{used_storage} of %{storage_limit})"
msgstr ""
+msgid "You successfully declined the invitation"
+msgstr ""
+
msgid "You tried to fork %{link_to_the_project} but it failed for the following reason:"
msgstr ""
@@ -28999,10 +29965,13 @@ msgstr ""
msgid "Your U2F device did not send a valid JSON response."
msgstr ""
-msgid "Your U2F device needs to be set up. Plug it in (if not already) and click the button on the left."
+msgid "Your U2F device was registered!"
+msgstr ""
+
+msgid "Your WebAuthn device did not send a valid JSON response."
msgstr ""
-msgid "Your U2F device was registered!"
+msgid "Your WebAuthn device was registered!"
msgstr ""
msgid "Your access request to the %{source_type} has been withdrawn."
@@ -29026,6 +29995,9 @@ msgstr ""
msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
msgstr ""
+msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
+msgstr ""
+
msgid "Your changes can be committed to %{branch_name} because a merge request is open."
msgstr ""
@@ -29062,6 +30034,12 @@ msgstr ""
msgid "Your deployment services will be broken, you will need to manually fix the services after renaming."
msgstr ""
+msgid "Your device is not compatible with GitLab. Please try another device"
+msgstr ""
+
+msgid "Your device needs to be set up. Plug it in (if needed) and click the button on the left."
+msgstr ""
+
msgid "Your device was successfully set up! Give it a name and register it with the GitLab server."
msgstr ""
@@ -29176,9 +30154,6 @@ msgstr[2] ""
msgid "access:"
msgstr ""
-msgid "activated"
-msgstr ""
-
msgid "added %{created_at_timeago}"
msgstr ""
@@ -29251,9 +30226,21 @@ msgstr ""
msgid "by %{user}"
msgstr ""
+msgid "cannot be a date in the past"
+msgstr ""
+
msgid "cannot be changed if a personal project has container registry tags."
msgstr ""
+msgid "cannot be changed if shared runners are enabled"
+msgstr ""
+
+msgid "cannot be enabled because parent group does not allow it"
+msgstr ""
+
+msgid "cannot be enabled because parent group has shared Runners disabled"
+msgstr ""
+
msgid "cannot be enabled unless all domains have TLS certificates"
msgstr ""
@@ -29299,7 +30286,7 @@ msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about SAST %{linkEndTag}"
msgstr ""
-msgid "ciReport|%{linkStartTag}Learn more about Secret Scanning %{linkEndTag}"
+msgid "ciReport|%{linkStartTag}Learn more about Secret Detection %{linkEndTag}"
msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about codequality reports %{linkEndTag}"
@@ -29617,9 +30604,6 @@ msgstr ""
msgid "error"
msgstr ""
-msgid "error code:"
-msgstr ""
-
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr ""
@@ -29641,6 +30625,9 @@ msgstr ""
msgid "failed to dismiss associated finding(id=%{finding_id}): %{message}"
msgstr ""
+msgid "failed to revert associated finding(id=%{finding_id}) to detected"
+msgstr ""
+
msgid "file"
msgid_plural "files"
msgstr[0] ""
@@ -30187,6 +31174,9 @@ msgstr ""
msgid "must be a root namespace"
msgstr ""
+msgid "must be a valid IPv4 or IPv6 address"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -30223,6 +31213,9 @@ msgstr ""
msgid "no expiration"
msgstr ""
+msgid "no name set"
+msgstr ""
+
msgid "no one can merge"
msgstr ""
@@ -30406,9 +31399,6 @@ msgstr ""
msgid "security Reports|There was an error creating the merge request"
msgstr ""
-msgid "settings saved, but not activated"
-msgstr ""
-
msgid "severity|Critical"
msgstr ""
@@ -30535,9 +31525,6 @@ msgstr ""
msgid "toggle collapse"
msgstr ""
-msgid "toggle dropdown"
-msgstr ""
-
msgid "triggered"
msgstr ""
@@ -30565,6 +31552,9 @@ msgstr ""
msgid "user avatar"
msgstr ""
+msgid "user preferences"
+msgstr ""
+
msgid "username"
msgstr ""
diff --git a/locale/ru/gitlab.po b/locale/ru/gitlab.po
index aa6349ac3b9..3b4f55c5faa 100644
--- a/locale/ru/gitlab.po
+++ b/locale/ru/gitlab.po
@@ -14,7 +14,10 @@ msgstr ""
"X-Crowdin-Language: ru\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 6\n"
-"PO-Revision-Date: 2020-09-04 23:10\n"
+"PO-Revision-Date: 2020-10-02 18:49\n"
+
+msgid " %{project_name}#%{issue_iid} &middot; opened %{issue_created} by %{author}"
+msgstr ""
msgid " %{start} to %{end}"
msgstr " %{start} по %{end}"
@@ -78,6 +81,20 @@ msgstr "\"%{path}\" не ÑущеÑтвует на \"%{ref}\""
msgid "\"el\" parameter is required for createInstance()"
msgstr ""
+msgid "%d Approval"
+msgid_plural "%d Approvals"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
+msgid "%d Package"
+msgid_plural "%d Packages"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%d Scanned URL"
msgid_plural "%d Scanned URLs"
msgstr[0] ""
@@ -165,6 +182,13 @@ msgstr[3] "%d коммитов,"
msgid "%d commits"
msgstr "%d коммитов"
+msgid "%d completed issue"
+msgid_plural "%d completed issues"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%d contribution"
msgid_plural "%d contributions"
msgstr[0] "%d вклад"
@@ -174,6 +198,13 @@ msgstr[3] "%d вкладов"
msgid "%d day"
msgid_plural "%d days"
+msgstr[0] "%d день"
+msgstr[1] "%d днÑ"
+msgstr[2] "%d дней"
+msgstr[3] "%d дней"
+
+msgid "%d day until tags are automatically removed"
+msgid_plural "%d days until tags are automatically removed"
msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
@@ -216,10 +247,10 @@ msgstr[3] "%d групп выбрано"
msgid "%d hour"
msgid_plural "%d hours"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
+msgstr[0] "%d чаÑ"
+msgstr[1] "%d чаÑа"
+msgstr[2] "%d чаÑов"
+msgstr[3] "%d чаÑов"
msgid "%d inaccessible merge request"
msgid_plural "%d inaccessible merge requests"
@@ -305,6 +336,20 @@ msgstr[1] "еще %d комментариÑ"
msgstr[2] "еще %d комментариев"
msgstr[3] "еще %d комментариев"
+msgid "%d open issue"
+msgid_plural "%d open issues"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
+msgid "%d pending comment"
+msgid_plural "%d pending comments"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%d personal project will be removed and cannot be restored."
msgid_plural "%d personal projects will be removed and cannot be restored."
msgstr[0] ""
@@ -326,6 +371,13 @@ msgstr[1] "%d проекта"
msgstr[2] "%d проектов"
msgstr[3] "%d проектов"
+msgid "%d project selected"
+msgid_plural "%d projects selected"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%d request with warnings"
msgid_plural "%d requests with warnings"
msgstr[0] "%d Ð·Ð°Ð¿Ñ€Ð¾Ñ Ñ Ð¿Ñ€ÐµÐ´ÑƒÐ¿Ñ€ÐµÐ¶Ð´ÐµÐ½Ð¸Ñми"
@@ -354,6 +406,13 @@ msgstr[1] "%d тега"
msgstr[2] "%d тегов"
msgstr[3] "%d тегов"
+msgid "%d tag per image name"
+msgid_plural "%d tags per image name"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%d unassigned issue"
msgid_plural "%d unassigned issues"
msgstr[0] ""
@@ -382,6 +441,13 @@ msgstr[1] "%d уÑзвимоÑти отклонено"
msgstr[2] "%d уÑзвимоÑтей отклонено"
msgstr[3] "%d уÑзвимоÑтей отклонено"
+msgid "%d warning found:"
+msgid_plural "%d warnings found:"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%s additional commit has been omitted to prevent performance issues."
msgid_plural "%s additional commits have been omitted to prevent performance issues."
msgstr[0] "%s дополнительный коммит был пропущен Ð´Ð»Ñ Ð¿Ñ€ÐµÐ´Ð¾Ñ‚Ð²Ñ€Ð°Ñ‰ÐµÐ½Ð¸Ñ Ð¿Ñ€Ð¾Ð±Ð»ÐµÐ¼ Ñ Ð¿Ñ€Ð¾Ð¸Ð·Ð²Ð¾Ð´Ð¸Ñ‚ÐµÐ»ÑŒÐ½Ð¾Ñтью."
@@ -396,7 +462,7 @@ msgid "%{address} is an invalid IP address range"
msgstr ""
msgid "%{author_link} wrote:"
-msgstr ""
+msgstr "%{author_link} напиÑал:"
msgid "%{authorsName}'s thread"
msgstr "тема %{authorsName}"
@@ -422,6 +488,9 @@ msgstr ""
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr "%{commit_author_link} Ñоздал %{commit_timeago}"
+msgid "%{completedCount} completed weight"
+msgstr ""
+
msgid "%{completedWeight} of %{totalWeight} weight completed"
msgstr "Завершено %{completedWeight} из %{totalWeight} приоритета"
@@ -476,19 +545,15 @@ msgstr[1] "%{count} учаÑтника"
msgstr[2] "%{count} учаÑтников"
msgstr[3] "%{count} учаÑтников"
-msgid "%{count} pending comment"
-msgid_plural "%{count} pending comments"
-msgstr[0] "%{count} ожидающий комментарий"
-msgstr[1] "%{count} ожидающих комментариÑ"
-msgstr[2] "%{count} ожидающих комментариев"
-msgstr[3] "%{count} ожидающих комментариев"
-
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr "%{count} ÑвÑзанный %{pluralized_subject}: %{links}"
-msgid "%{dashboard_path} could not be found."
+msgid "%{count} total weight"
msgstr ""
+msgid "%{dashboard_path} could not be found."
+msgstr "%{dashboard_path} не может быть найден."
+
msgid "%{days} days until tags are automatically removed"
msgstr "%{days} дней до автоматичеÑкого ÑƒÐ´Ð°Ð»ÐµÐ½Ð¸Ñ Ñ‚ÐµÐ³Ð¾Ð²"
@@ -540,6 +605,9 @@ msgstr ""
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} иÑпользует управлÑемые групповые аккаунты. Вам нужно Ñоздать новый аккаунт GitLab, который будет управлÑÑ‚ÑŒÑÑ %{group_name}."
+msgid "%{group_name}&%{epic_iid} &middot; opened %{epic_created} by %{author}"
+msgstr ""
+
msgid "%{host} sign-in from new location"
msgstr ""
@@ -552,14 +620,14 @@ msgstr ""
msgid "%{issuableType} will be removed! Are you sure?"
msgstr "%{issuableType} будет удален! Вы уверены?"
-msgid "%{issuesSize} issues with a limit of %{maxIssueCount}"
-msgstr "%{issuesSize} обÑуждение Ñ Ð»Ð¸Ð¼Ð¸Ñ‚Ð¾Ð¼ в %{maxIssueCount}"
+msgid "%{issuesCount} issues with a limit of %{maxIssueCount}"
+msgstr ""
msgid "%{issuesSize} with a limit of %{maxIssueCount}"
msgstr ""
msgid "%{labelStart}Class:%{labelEnd} %{class}"
-msgstr ""
+msgstr "%{labelStart}КлаÑÑ:%{labelEnd} %{class}"
msgid "%{labelStart}Crash Address:%{labelEnd} %{crash_address}"
msgstr ""
@@ -568,28 +636,28 @@ msgid "%{labelStart}Crash State:%{labelEnd} %{stacktrace_snippet}"
msgstr ""
msgid "%{labelStart}Evidence:%{labelEnd} %{evidence}"
-msgstr ""
+msgstr "%{labelStart}ДоказательÑтва:%{labelEnd} %{evidence}"
msgid "%{labelStart}File:%{labelEnd} %{file}"
-msgstr ""
+msgstr "%{labelStart}Файл:%{labelEnd} %{file}"
msgid "%{labelStart}Headers:%{labelEnd} %{headers}"
msgstr ""
msgid "%{labelStart}Image:%{labelEnd} %{image}"
-msgstr ""
+msgstr "%{labelStart}Изображение:%{labelEnd} %{image}"
msgid "%{labelStart}Method:%{labelEnd} %{method}"
-msgstr ""
+msgstr "%{labelStart}Метод:%{labelEnd} %{method}"
msgid "%{labelStart}Namespace:%{labelEnd} %{namespace}"
msgstr ""
-msgid "%{labelStart}Report Type:%{labelEnd} %{reportType}"
+msgid "%{labelStart}Scan Type:%{labelEnd} %{reportType}"
msgstr ""
msgid "%{labelStart}Scanner:%{labelEnd} %{scanner}"
-msgstr ""
+msgstr "%{labelStart}Сканер:%{labelEnd} %{scanner}"
msgid "%{labelStart}Severity:%{labelEnd} %{severity}"
msgstr ""
@@ -655,7 +723,7 @@ msgid "%{milestone} (expired)"
msgstr ""
msgid "%{milliseconds}ms"
-msgstr ""
+msgstr "%{milliseconds}мÑ"
msgid "%{mrText}, this issue will be closed automatically."
msgstr "%{mrText}, Ñто обÑуждение будет закрыто автоматичеÑки."
@@ -738,7 +806,7 @@ msgstr[2] "%{releases} релизов"
msgstr[3] "%{releases} релизов"
msgid "%{remaining_approvals} left"
-msgstr ""
+msgstr "%{remaining_approvals} оÑталоÑÑŒ"
msgid "%{reportType} %{status} detected %{criticalStart}%{critical} critical%{criticalEnd} and %{highStart}%{high} high%{highEnd} severity vulnerabilities out of %{total}."
msgstr ""
@@ -768,10 +836,10 @@ msgstr[3] ""
msgid "%{reportType} %{status} detected %{other} vulnerability."
msgid_plural "%{reportType} %{status} detected %{other} vulnerabilities."
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
+msgstr[0] "%{reportType} %{status} обнаружено %{other} уÑзвимоÑÑ‚ÑŒ."
+msgstr[1] "%{reportType} %{status} обнаружено %{other} уÑзвимоÑти."
+msgstr[2] "%{reportType} %{status} обнаружено %{other} уÑзвимоÑтей."
+msgstr[3] "%{reportType} %{status} обнаружено %{other} уÑзвимоÑтей."
msgid "%{reportType} %{status} detected no vulnerabilities."
msgstr ""
@@ -780,7 +848,7 @@ msgid "%{retryButtonStart}Try again%{retryButtonEnd} or %{newFileButtonStart}att
msgstr ""
msgid "%{seconds}s"
-msgstr ""
+msgstr "%{seconds}Ñ"
msgid "%{securityScanner} is not enabled for this project. %{linkStart}More information%{linkEnd}"
msgid_plural "%{securityScanner} are not enabled for this project. %{linkStart}More information%{linkEnd}"
@@ -796,9 +864,6 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "%{service_title} %{message}."
-msgstr "%{service_title} %{message}."
-
msgid "%{size} GiB"
msgstr "%{size} ГиБ"
@@ -897,6 +962,12 @@ msgstr "%{text} доÑтупен"
msgid "%{timebox_name} should belong either to a project or a group."
msgstr "%{timebox_name} должен принадлежать проекту или группе"
+msgid "%{timebox_type} does not support burnup charts"
+msgstr ""
+
+msgid "%{timebox_type} must have a start and due date"
+msgstr ""
+
msgid "%{title} %{operator} %{threshold}"
msgstr "%{title} %{operator} %{threshold}"
@@ -921,8 +992,8 @@ msgstr ""
msgid "%{total} open issue weight"
msgstr "приоритет открытого обÑÑƒÐ¶Ð´ÐµÐ½Ð¸Ñ %{total}"
-msgid "%{total} open issues"
-msgstr "%{total} открытых задач"
+msgid "%{total} warnings found: showing first %{warningsDisplayed}"
+msgstr ""
msgid "%{usage_ping_link_start}Learn more%{usage_ping_link_end} about what information is shared with GitLab Inc."
msgstr "%{usage_ping_link_start}Узнайте больше%{usage_ping_link_end} о том, ÐºÐ°ÐºÐ°Ñ Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¿ÐµÑ€ÐµÐ´Ð°ÐµÑ‚ÑÑ GitLab Inc."
@@ -952,10 +1023,7 @@ msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notif
msgstr ""
msgid "&lt; 1 hour"
-msgstr ""
-
-msgid "&lt;no name set&gt;"
-msgstr ""
+msgstr "&lt; 1 чаÑ"
msgid "&lt;no scopes selected&gt;"
msgstr ""
@@ -987,6 +1055,9 @@ msgstr ""
msgid "'%{name}' Value Stream created"
msgstr ""
+msgid "'%{name}' Value Stream deleted"
+msgstr ""
+
msgid "'%{name}' stage already exists"
msgstr "Этап '%{name}' уже ÑущеÑтвует"
@@ -1016,7 +1087,7 @@ msgid "(check progress)"
msgstr "(прогреÑÑ Ð¿Ñ€Ð¾Ð²ÐµÑ€ÐºÐ¸)"
msgid "(deleted)"
-msgstr ""
+msgstr "(удалено)"
msgid "(external source)"
msgstr "(внешний иÑточник)"
@@ -1034,7 +1105,7 @@ msgid "(revoked)"
msgstr "(отозван)"
msgid "* * * * *"
-msgstr ""
+msgstr "* * * * *"
msgid "+ %{amount} more"
msgstr "+%{amount} ещё"
@@ -1048,6 +1119,9 @@ msgstr "+ ещё %{moreCount}"
msgid "+ %{numberOfHiddenAssignees} more"
msgstr "+ещё %{numberOfHiddenAssignees}"
+msgid "+ %{numberOfHiddenReviewers} more"
+msgstr ""
+
msgid "+%d more"
msgid_plural "+%d more"
msgstr[0] "+ещё %d"
@@ -1091,7 +1165,7 @@ msgid "- show less"
msgstr "- Ñвернуть"
msgid "0 bytes"
-msgstr ""
+msgstr "0 байт"
msgid "0 for unlimited"
msgstr "0 — без ограничений"
@@ -1120,6 +1194,13 @@ msgstr[1] "%d днÑ"
msgstr[2] "%d дней"
msgstr[3] "%d дней"
+msgid "1 Issue"
+msgid_plural "%d Issues"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "1 closed issue"
msgid_plural "%{issues} closed issues"
msgstr[0] "1 Ð·Ð°ÐºÑ€Ñ‹Ñ‚Ð°Ñ Ð·Ð°Ð´Ð°Ñ‡Ð°"
@@ -1141,6 +1222,13 @@ msgstr[1] "%d днÑ"
msgstr[2] "%d дней"
msgstr[3] "%d дней"
+msgid "1 deploy key"
+msgid_plural "%d deploy keys"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] "1 группа"
@@ -1229,7 +1317,7 @@ msgid "3 hours"
msgstr "3 чаÑа"
msgid "30 days"
-msgstr ""
+msgstr "30 дней"
msgid "30 minutes"
msgstr "30 минут"
@@ -1253,7 +1341,7 @@ msgid "404|Please contact your GitLab administrator if you think this is a mista
msgstr "ПожалуйÑта ÑвÑжитеÑÑŒ Ñ Ð²Ð°ÑˆÐ¸Ð¼ админиÑтратором GitLab Ñервера, еÑли вы Ñчитаете данное поведение ошибкой."
msgid "7 days"
-msgstr ""
+msgstr "7 дней"
msgid "8 hours"
msgstr "8 чаÑов"
@@ -1261,6 +1349,9 @@ msgstr "8 чаÑов"
msgid ":%{startLine} to %{endLine}"
msgstr ""
+msgid "A %{incident_docs_start}modified issue%{incident_docs_end} to guide the resolution of incidents."
+msgstr ""
+
msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr "«Runner» - Ñто процеÑÑ, который выполнÑет Ñозданное вами задание. Ð’Ñ‹ можете наÑтроить Ñтолько таких процеÑÑов, Ñколько вам нужно."
@@ -1273,6 +1364,9 @@ msgstr ""
msgid "A GitBook site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr "Сайт GitBook, который иÑпользует Netlify Ð´Ð»Ñ CI/CD вмеÑто GitLab, но вÑÑ‘ ещё Ñ Ð´Ñ€ÑƒÐ³Ð¸Ð¼Ð¸ замечательными возможноÑÑ‚Ñми GitLab."
+msgid "A Gitpod configured Webapplication in Spring and Java"
+msgstr ""
+
msgid "A Hexo site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr "Сайт Hexo, который иÑпользует Netlify Ð´Ð»Ñ CI/CD вмеÑто GitLab, но вÑÑ‘ ещё Ñ Ð´Ñ€ÑƒÐ³Ð¸Ð¼Ð¸ замечательными возможноÑÑ‚Ñми GitLab."
@@ -1301,10 +1395,10 @@ msgid "A deleted user"
msgstr "Удаленный пользователь"
msgid "A file has been changed."
-msgstr ""
+msgstr "Файл был изменён."
msgid "A file was not found."
-msgstr ""
+msgstr "Файл не найден!"
msgid "A file with '%{file_name}' already exists in %{branch} branch"
msgstr "Файл '%{file_name}' уже ÑущеÑтвует в ветке %{branch}"
@@ -1385,7 +1479,7 @@ msgid "ACTION REQUIRED: Something went wrong while obtaining the Let's Encrypt c
msgstr "ТРЕБУЕТСЯ ДЕЙСТВИЕ: Что-то пошло не так при получении Ñертификата Let's Encrypt Ð´Ð»Ñ Ð´Ð¾Ð¼ÐµÐ½Ð° GitLab Pages '%{domain}'"
msgid "API Help"
-msgstr ""
+msgstr "Справка по API"
msgid "API Token"
msgstr "API токен"
@@ -1444,9 +1538,15 @@ msgstr "ДоÑтуп запрещен! ПожалуйÑта, убедитеÑÑŒ,
msgid "Access expiration date"
msgstr "Дата Ð¿Ñ€ÐµÐºÑ€Ð°Ñ‰ÐµÐ½Ð¸Ñ Ð´Ð¾Ñтупа"
+msgid "Access expires"
+msgstr ""
+
msgid "Access forbidden. Check your access level."
msgstr "ДоÑтуп запрещен. Проверьте Ñвой уровень доÑтупа."
+msgid "Access granted"
+msgstr ""
+
msgid "Access requests"
msgstr ""
@@ -1456,6 +1556,9 @@ msgstr "ДоÑтуп к '%{classification_label}' не разрешён"
msgid "Access to Pages websites are controlled based on the user's membership to a given project. By checking this box, users will be required to be logged in to have access to all Pages websites in your instance."
msgstr ""
+msgid "AccessDropdown|Deploy Keys"
+msgstr ""
+
msgid "AccessDropdown|Groups"
msgstr "Группы"
@@ -1553,7 +1656,7 @@ msgid "Action to take when receiving an alert. %{docsLink}"
msgstr ""
msgid "Actions"
-msgstr ""
+msgstr "ДейÑтвиÑ"
msgid "Activate"
msgstr "Ðктивировать"
@@ -1573,12 +1676,6 @@ msgstr ""
msgid "Active Sessions"
msgstr "Ðктивные ÑеÑÑии"
-msgid "Active Users:"
-msgstr "Ðктивные пользователи:"
-
-msgid "Active users"
-msgstr ""
-
msgid "Activity"
msgstr "ÐктивноÑÑ‚ÑŒ"
@@ -1620,7 +1717,7 @@ msgid "Add LICENSE"
msgstr "Добавить LICENSE"
msgid "Add New Node"
-msgstr ""
+msgstr "Добавить новый узел"
msgid "Add README"
msgstr "Добавить README"
@@ -1632,7 +1729,7 @@ msgid "Add Zoom meeting"
msgstr "ПриÑоединитьÑÑ Ðº вÑтрече в Zoom"
msgid "Add a %{type}"
-msgstr ""
+msgstr "Добавить %{type}"
msgid "Add a GPG key"
msgstr "Добавить ключ GPG"
@@ -1743,14 +1840,11 @@ msgid "Add italic text"
msgstr "Добавить курÑив"
msgid "Add key"
-msgstr ""
+msgstr "Добавить ключ"
msgid "Add label(s)"
msgstr "Добавить метку(и)"
-msgid "Add license"
-msgstr "Добавить лицензию"
-
msgid "Add list"
msgstr "Добавить ÑпиÑок"
@@ -1776,7 +1870,7 @@ msgid "Add request manually"
msgstr "Добавить Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð²Ñ€ÑƒÑ‡Ð½ÑƒÑŽ"
msgid "Add strikethrough text"
-msgstr ""
+msgstr "Добавить зачеркнутый текÑÑ‚"
msgid "Add suggestion to batch"
msgstr ""
@@ -1815,7 +1909,7 @@ msgid "Add webhook"
msgstr "Добавить веб-обработчик"
msgid "Add/remove"
-msgstr ""
+msgstr "Добавить/удалить"
msgid "AddContextCommits|Add previously merged commits"
msgstr ""
@@ -1925,19 +2019,49 @@ msgstr "Заблокированные пользователи"
msgid "AdminArea|Bots"
msgstr "Боты"
+msgid "AdminArea|Components"
+msgstr ""
+
msgid "AdminArea|Developer"
msgstr "Developer"
-msgid "AdminArea|Guest"
+msgid "AdminArea|Features"
msgstr ""
+msgid "AdminArea|Groups: %{number_of_groups}"
+msgstr ""
+
+msgid "AdminArea|Guest"
+msgstr "Guest"
+
msgid "AdminArea|Included Free in license"
msgstr "Включены в лицензию беÑплатно"
+msgid "AdminArea|Latest groups"
+msgstr ""
+
+msgid "AdminArea|Latest projects"
+msgstr ""
+
+msgid "AdminArea|Latest users"
+msgstr ""
+
msgid "AdminArea|Maintainer"
+msgstr "Maintainer"
+
+msgid "AdminArea|New group"
+msgstr ""
+
+msgid "AdminArea|New project"
+msgstr ""
+
+msgid "AdminArea|New user"
msgstr ""
msgid "AdminArea|Owner"
+msgstr "Owner"
+
+msgid "AdminArea|Projects: %{number_of_projects}"
msgstr ""
msgid "AdminArea|Reporter"
@@ -1967,6 +2091,9 @@ msgstr "Пользователи Ñ Ð½Ð°Ð¸Ð²Ñ‹Ñшей ролью"
msgid "AdminArea|Users without a Group and Project"
msgstr "Пользователи без группы и проекта"
+msgid "AdminArea|Users: %{number_of_users}"
+msgstr ""
+
msgid "AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running."
msgstr "Ð’Ñ‹ ÑобираетеÑÑŒ оÑтановить вÑе заданиÑ. Это дейÑтвие оÑтановит вÑе текущие заданиÑ, находÑщиеÑÑ Ð² процеÑÑе выполнениÑ."
@@ -1985,9 +2112,6 @@ msgstr "Удалить"
msgid "AdminProjects|Delete Project %{projectName}?"
msgstr "Удалить Проект %{projectName}?"
-msgid "AdminProjects|Delete project"
-msgstr "Удалить проект"
-
msgid "AdminSettings|Apply integration settings to all Projects"
msgstr "Применить наÑтройки интеграции ко вÑем проектам"
@@ -2225,21 +2349,30 @@ msgstr "Когда пользователь в Ñледующий раз войÐ
msgid "AdminUsers|Without projects"
msgstr "Без проектов"
-msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
-msgstr "Ð’Ñ‹ ÑобираетеÑÑŒ окончательно удалить Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ %{username}. ОбÑуждениÑ, запроÑÑ‹ ÑлиÑÐ½Ð¸Ñ Ð¸ ÑвÑзанные Ñ Ð½Ð¸Ð¼Ð¸ группы будут переданы глобальному \"пользователю-призраку\". Чтобы избежать потери данных, раÑÑмотрите возможноÑÑ‚ÑŒ иÑÐ¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ñ„ÑƒÐ½ÐºÑ†Ð¸Ð¸ %{strong_start}блокировки пользователÑ%{strong_end}. ПоÑле %{strong_start}ÑƒÐ´Ð°Ð»ÐµÐ½Ð¸Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ%{strong_end}, Ð½ÐµÐ»ÑŒÐ·Ñ Ð±ÑƒÐ´ÐµÑ‚ его воÑÑтановить или отменить удаление."
+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 %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
-msgstr "Ð’Ñ‹ ÑобираетеÑÑŒ окончательно удалить Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ %{username}. Это удалит вÑе его обÑуждениÑ, запроÑÑ‹ ÑлиÑÐ½Ð¸Ñ Ð¸ ÑвÑзанные Ñ Ð½Ð¸Ð¼Ð¸ группы. Чтобы избежать потери данных, раÑÑмотрите возможноÑÑ‚ÑŒ иÑÐ¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ñ„ÑƒÐ½ÐºÑ†Ð¸Ð¸ %{strong_start}блокировки пользователÑ%{strong_end}. ПоÑле %{strong_start}ÑƒÐ´Ð°Ð»ÐµÐ½Ð¸Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ%{strong_end}, Ð½ÐµÐ»ÑŒÐ·Ñ Ð±ÑƒÐ´ÐµÑ‚ его воÑÑтановить или отменить удаление."
+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 ""
msgid "AdminUsers|You cannot remove your own admin rights."
msgstr ""
+msgid "AdminUsers|You must transfer ownership or delete the groups owned by this user before you can delete their account"
+msgstr ""
+
msgid "Administration"
msgstr "ÐдминиÑтрирование"
msgid "Advanced"
msgstr "РаÑширенные"
+msgid "Advanced Search"
+msgstr ""
+
+msgid "Advanced Search with Elasticsearch"
+msgstr ""
+
msgid "Advanced Settings"
msgstr "Дополнительные наÑтройки"
@@ -2319,6 +2452,9 @@ msgstr "Выводите ÑƒÐ²ÐµÐ´Ð¾Ð¼Ð»ÐµÐ½Ð¸Ñ Ð¾Ñ‚ вÑех Ñвоих инÑÑ
msgid "AlertManagement|Edit"
msgstr ""
+msgid "AlertManagement|Environment"
+msgstr ""
+
msgid "AlertManagement|Events"
msgstr "СобытиÑ"
@@ -2331,6 +2467,9 @@ msgstr ""
msgid "AlertManagement|Issue"
msgstr ""
+msgid "AlertManagement|Key"
+msgstr ""
+
msgid "AlertManagement|Low"
msgstr ""
@@ -2424,6 +2563,9 @@ msgstr "Получено"
msgid "AlertManagement|Unknown"
msgstr ""
+msgid "AlertManagement|Value"
+msgstr ""
+
msgid "AlertManagement|View alerts in Opsgenie"
msgstr ""
@@ -2583,6 +2725,9 @@ msgstr "Ð’Ñе пути должны быть указаны отноÑителÑ
msgid "All projects"
msgstr "Ð’Ñе проекты"
+msgid "All projects selected"
+msgstr ""
+
msgid "All security scans are enabled because %{linkStart}Auto DevOps%{linkEnd} is enabled on this project"
msgstr ""
@@ -2653,7 +2798,7 @@ msgid "Allow users to request access (if visibility is public or internal)"
msgstr "Разрешить пользователÑм запрашивать доÑтуп (еÑли видимоÑÑ‚ÑŒ ÑвлÑетÑÑ Ð¾Ð±Ñ‰ÐµÐ´Ð¾Ñтупной или внутренней)"
msgid "Allowed"
-msgstr ""
+msgstr "Разрешено"
msgid "Allowed Geo IP"
msgstr ""
@@ -2670,6 +2815,9 @@ msgstr "ПозволÑет добавлÑÑ‚ÑŒ и управлÑÑ‚ÑŒ клаÑте
msgid "Almost there"
msgstr "Почти готово"
+msgid "Already blocked"
+msgstr ""
+
msgid "Also called \"Issuer\" or \"Relying party trust identifier\""
msgstr "Также называетÑÑ \"Ñмитент\" или \"идентификатор Ð´Ð¾Ð²ÐµÑ€Ð¸Ñ Ñтороны\""
@@ -2724,6 +2872,9 @@ msgstr "ПуÑтое значение в поле Пользователь Gitla
msgid "An error has occurred"
msgstr "Произошла ошибка"
+msgid "An error occured while making the changes: %{error}"
+msgstr ""
+
msgid "An error occurred adding a draft to the thread."
msgstr "Произошла ошибка при добавлении черновика в тему."
@@ -2751,12 +2902,6 @@ msgstr "Произошла ошибка при предварительном п
msgid "An error occurred when toggling the notification subscription"
msgstr "Произошла ошибка при переключении подпиÑки на оповещениÑ"
-msgid "An error occurred when trying to resolve a comment. Please try again."
-msgstr "Произошла ошибка при попытке разрешить комментарий. ПожалуйÑта, попробуйте ещё раз."
-
-msgid "An error occurred when trying to resolve a discussion. Please try again."
-msgstr "Произошла ошибка при попытке разрешить диÑкуÑÑию. ПожалуйÑта, попробуйте ещё раз."
-
msgid "An error occurred when updating the issue weight"
msgstr "Произошла ошибка при обновлении приоритета обÑуждениÑ"
@@ -2772,12 +2917,6 @@ msgstr "Произошла ошибка при Ñоздании форматир
msgid "An error occurred while checking group path. Please refresh and try again."
msgstr ""
-msgid "An error occurred while committing your changes."
-msgstr "Произошла ошибка во Ð²Ñ€ÐµÐ¼Ñ Ñ„Ð¸ÐºÑации изменений."
-
-msgid "An error occurred while creating the list. Please try again."
-msgstr ""
-
msgid "An error occurred while decoding the file."
msgstr "Произошла ошибка при декодировании файла."
@@ -2850,26 +2989,20 @@ msgstr "Произошла ошибка при получении отчётов
msgid "An error occurred while fetching the Service Desk address."
msgstr "Произошла ошибка при получении адреÑа Службы поддержки."
-msgid "An error occurred while fetching the board issues. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the board lists. Please reload the page."
msgstr ""
msgid "An error occurred while fetching the board lists. Please try again."
msgstr "Произошла ошибка при получении ÑпиÑка панелей управлениÑ. ПожалуйÑта, попробуйте ещё раз."
-msgid "An error occurred while fetching the board swimlanes. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the builds."
msgstr "Произошла ошибка при получении Ñборок."
msgid "An error occurred while fetching the job log."
msgstr "Произошла ошибка при получении журнала заданий."
-msgid "An error occurred while fetching the job trace."
-msgstr "Произошла ошибка при извлечении траÑÑировки заданиÑ."
+msgid "An error occurred while fetching the job logs."
+msgstr ""
msgid "An error occurred while fetching the job."
msgstr "Произошла ошибка при извлечении заданиÑ."
@@ -3015,9 +3148,6 @@ msgstr "Произошла ошибка при Ñохранении ÑтатуÑ
msgid "An error occurred while saving assignees"
msgstr "Произошла ошибка при Ñохранении ответÑтвенных"
-msgid "An error occurred while saving the template. Please check if the template exists."
-msgstr "Произошла ошибка во Ð²Ñ€ÐµÐ¼Ñ ÑÐ¾Ñ…Ñ€Ð°Ð½ÐµÐ½Ð¸Ñ ÑˆÐ°Ð±Ð»Ð¾Ð½Ð°. ПожалуйÑта, проверьте, ÑущеÑтвует ли шаблон."
-
msgid "An error occurred while searching for milestones"
msgstr ""
@@ -3036,12 +3166,12 @@ msgstr "При отпиÑке от уведомлений произошла оÑ
msgid "An error occurred while updating approvers"
msgstr "Произошла ошибка при обновлении утверждающих"
+msgid "An error occurred while updating labels."
+msgstr ""
+
msgid "An error occurred while updating the comment"
msgstr "Произошла ошибка при обновлении комментариÑ"
-msgid "An error occurred while updating the list. Please try again."
-msgstr ""
-
msgid "An error occurred while validating group path"
msgstr "Произошла ошибка при валидации пути группы"
@@ -3093,6 +3223,9 @@ msgstr "Произошла Ð½ÐµÐ¿Ñ€ÐµÐ´Ð²Ð¸Ð´ÐµÐ½Ð½Ð°Ñ Ð¾ÑˆÐ¸Ð±ÐºÐ° при оÑ
msgid "An unknown error occurred while loading this graph."
msgstr ""
+msgid "An unknown error occurred."
+msgstr ""
+
msgid "Analytics"
msgstr "Ðналитика"
@@ -3126,11 +3259,11 @@ msgstr "Ðнти-Ñпам проверка"
msgid "Any"
msgstr "Любой"
-msgid "Any Author"
+msgid "Any %{header}"
msgstr ""
-msgid "Any Status"
-msgstr ""
+msgid "Any Author"
+msgstr "Любой автор"
msgid "Any branch"
msgstr "Ð›ÑŽÐ±Ð°Ñ Ð²ÐµÑ‚ÐºÐ°"
@@ -3145,7 +3278,7 @@ msgid "Any files larger than this limit will not be indexed, and thus will not b
msgstr ""
msgid "Any label"
-msgstr ""
+msgstr "Ð›ÑŽÐ±Ð°Ñ Ð¼ÐµÑ‚ÐºÐ°"
msgid "Any member with Developer or higher permissions to the project."
msgstr "Любой учаÑтник проекта Ñ Ð¿Ñ€Ð°Ð²Ð°Ð¼Ð¸ Developer или выше."
@@ -3183,6 +3316,9 @@ msgstr "Приложение"
msgid "Application ID"
msgstr "Идентификатор приложениÑ"
+msgid "Application limits saved successfully"
+msgstr ""
+
msgid "Application settings saved successfully"
msgstr "ÐаÑтройки Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ ÑƒÑпешно Ñохранены"
@@ -3341,7 +3477,7 @@ msgid "Approved the current merge request."
msgstr ""
msgid "Approved-By"
-msgstr ""
+msgstr "Утверждено"
msgid "Approver"
msgstr "Утверждающий"
@@ -3400,6 +3536,9 @@ msgstr "Вы уверены, что хотите отменить редакти
msgid "Are you sure you want to close this blocked issue?"
msgstr ""
+msgid "Are you sure you want to delete \"%{name}\" Value Stream?"
+msgstr ""
+
msgid "Are you sure you want to delete %{name}?"
msgstr "Вы точно хотите удалить %{name}?"
@@ -3409,6 +3548,9 @@ msgstr "Ð’Ñ‹ уверены, что хотите удалить Ñти артеÑ
msgid "Are you sure you want to delete this %{typeOfComment}?"
msgstr "Ð’Ñ‹ уверены что дейÑтвительно хотите удалить Ñто %{typeOfComment}?"
+msgid "Are you sure you want to delete this SSH key?"
+msgstr ""
+
msgid "Are you sure you want to delete this board?"
msgstr "Ð’Ñ‹ уверены, что дейÑтвительно хотите удалить Ñту доÑку?"
@@ -3433,6 +3575,13 @@ msgstr ""
msgid "Are you sure you want to erase this build?"
msgstr "Ð’Ñ‹ уверены, что вы хотите удалить Ñту Ñборку?"
+msgid "Are you sure you want to import %d repository?"
+msgid_plural "Are you sure you want to import %d repositories?"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "Are you sure you want to lose unsaved changes?"
msgstr "Ð’Ñ‹ уверены, что вы хотите потерÑÑ‚ÑŒ не Ñохранённые изменениÑ?"
@@ -3442,15 +3591,15 @@ msgstr "Ð’Ñ‹ уверены, что хотите потерÑÑ‚ÑŒ информа
msgid "Are you sure you want to merge immediately?"
msgstr ""
-msgid "Are you sure you want to permanently delete this license?"
-msgstr "Ð’Ñ‹ дейÑтвительно хотите безвозвратно удалить Ñту лицензию?"
-
msgid "Are you sure you want to re-deploy this environment?"
msgstr ""
msgid "Are you sure you want to regenerate the public key? You will have to update the public key on the remote server before mirroring will work again."
msgstr "Ð’Ñ‹ уверены, что вы хотите заново Ñгенерировать публичный ключ? Вам нужно будет обновить публичный ключ на удаленном Ñервере, прежде чем зеркалирование Ñнова будет работать."
+msgid "Are you sure you want to reindex?"
+msgstr ""
+
msgid "Are you sure you want to remove %{group_name}?"
msgstr "Вы уверены, что вы хотите удалить %{group_name}?"
@@ -3478,6 +3627,9 @@ msgstr ""
msgid "Are you sure you want to revoke this nickname?"
msgstr "Ð’Ñ‹ уверены, что хотите отменить Ñтот ник?"
+msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
+msgstr ""
+
msgid "Are you sure you want to stop this environment?"
msgstr "Ð’Ñ‹ уверены, что вы хотите оÑтановить Ñто окружение?"
@@ -3499,6 +3651,9 @@ msgstr "Ð’Ñ‹ уверены? Удаление Ñтого ключа GPG не пÐ
msgid "Are you sure? The device will be signed out of GitLab and all remember me tokens revoked."
msgstr ""
+msgid "Are you sure? This will invalidate your registered applications and U2F / WebAuthn devices."
+msgstr ""
+
msgid "Are you sure? This will invalidate your registered applications and U2F devices."
msgstr "Ð’Ñ‹ уверены? Это аннулирует ваши зарегиÑтрированные Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¸ U2F уÑтройÑтва."
@@ -3517,9 +3672,6 @@ msgstr "Ðртефакт был уÑпешно удален."
msgid "Artifacts"
msgstr "Ðртефакты"
-msgid "As U2F devices are only supported by a few browsers, we require that you set up a two-factor authentication app before a U2F device. That way you'll always be able to log in - even when you're using an unsupported browser."
-msgstr "ПоÑкольку уÑтройÑтва U2F поддерживаютÑÑ Ñ‚Ð¾Ð»ÑŒÐºÐ¾ неÑколькими браузерами, мы требуем, чтобы вы наÑтроили двухфакторную аутентификацию перед U2F уÑтройÑтвом. Таким образом, вы вÑегда Ñможете войти в ÑиÑтему, даже еÑли вы иÑпользуете неподдерживаемый браузер."
-
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 ""
@@ -3612,7 +3764,7 @@ msgstr[2] "%d ответÑтвенных"
msgstr[3] "%d ответÑтвенных"
msgid "Assignee has no permissions"
-msgstr ""
+msgstr "ОтветÑтвенный не имеет доÑтупа"
msgid "Assignee lists not available with your current license"
msgstr "СпиÑки ответÑтвенных не доÑтупны Ñ Ð²Ð°ÑˆÐµÐ¹ текущей лицензией"
@@ -3624,7 +3776,7 @@ msgid "Assignee(s)"
msgstr "ОтветÑтвенный(ые)"
msgid "Assignees"
-msgstr ""
+msgstr "ОтветÑтвенные"
msgid "Assigns %{assignee_users_sentence}."
msgstr "Ðазначение %{assignee_users_sentence}."
@@ -3676,7 +3828,7 @@ msgid "Audit Events is a way to keep track of important events that happened in
msgstr ""
msgid "Audit Log"
-msgstr ""
+msgstr "Журнал аудита"
msgid "AuditLogs|(removed)"
msgstr ""
@@ -3717,6 +3869,9 @@ msgstr ""
msgid "AuditLogs|Target"
msgstr ""
+msgid "AuditLogs|This month"
+msgstr ""
+
msgid "AuditLogs|User Events"
msgstr ""
@@ -3756,6 +3911,9 @@ msgstr ""
msgid "Authentication via U2F device failed."
msgstr "Проверка подлинноÑти через U2F уÑтройÑтва не удалоÑÑŒ."
+msgid "Authentication via WebAuthn device failed."
+msgstr ""
+
msgid "Author"
msgstr "Ðвтор"
@@ -3871,7 +4029,7 @@ msgid "Automatically create merge requests for vulnerabilities that have fixes a
msgstr ""
msgid "Automatically resolved"
-msgstr ""
+msgstr "Разрешено автоматичеÑки"
msgid "Automatically update this project's branches and tags from the upstream repository every hour."
msgstr "ÐвтоматичеÑки обновлÑÑ‚ÑŒ ветки и теги Ñтого проекта из иÑходного Ñ€ÐµÐ¿Ð¾Ð·Ð¸Ñ‚Ð¾Ñ€Ð¸Ñ ÐºÐ°Ð¶Ð´Ñ‹Ð¹ чаÑ."
@@ -3910,7 +4068,7 @@ msgid "Average per day: %{average}"
msgstr "Ð’ Ñреднем за день: %{average}"
msgid "Back to page %{number}"
-msgstr ""
+msgstr "Ðазад к Ñтранице %{number}"
msgid "Background Color"
msgstr "Цвет Фона"
@@ -4023,15 +4181,6 @@ msgstr "Корневой URL-Ð°Ð´Ñ€ÐµÑ Bamboo, подобный https://bamboo.
msgid "BambooService|You must set up automatic revision labeling and a repository trigger in Bamboo."
msgstr "Ð’Ñ‹ должны наÑтроить автоматичеÑкое приÑвоение меток ревизиÑм и триггер Ñ€ÐµÐ¿Ð¾Ð·Ð¸Ñ‚Ð¾Ñ€Ð¸Ñ Ð² ÑервиÑе Bamboo."
-msgid "BatchComments|Delete all pending comments"
-msgstr "Удалить вÑе ожидающие комментарии"
-
-msgid "BatchComments|Discard review?"
-msgstr "Закрыть отзыв без ÑохранениÑ?"
-
-msgid "BatchComments|You're about to discard your review which will delete all of your pending comments. The deleted comments %{strong_start}cannot%{strong_end} be restored."
-msgstr "Ð’Ñ‹ ÑобираетеÑÑŒ отменить рецензию, что приведет к удалению вÑех ожидающих комментариев. Удалённые комментарии %{strong_start}невозможно%{strong_end} воÑÑтановить."
-
msgid "Be careful. Changing the project's namespace can have unintended side effects."
msgstr "Будьте оÑторожны. Изменение пути проекта может вызвать нежелательные побочные Ñффекты."
@@ -4053,6 +4202,9 @@ msgstr "Ðиже показаны вÑе открытые группы."
msgid "Bi-weekly code coverage"
msgstr ""
+msgid "Billable Users:"
+msgstr ""
+
msgid "Billing"
msgstr "Тарифы"
@@ -4062,7 +4214,7 @@ msgstr "%{group_name} ÑÐµÐ¹Ñ‡Ð°Ñ Ð¸Ñпользует тарифный плаÐ
msgid "BillingPlans|@%{user_name} you are currently using the %{plan_name} plan."
msgstr "@%{user_name}, ÑÐµÐ¹Ñ‡Ð°Ñ Ð²Ñ‹ иÑпользуете тарифный план %{plan_name}."
-msgid "BillingPlans|Congratulations, your new trial is activated"
+msgid "BillingPlans|Congratulations, your free trial is activated."
msgstr ""
msgid "BillingPlans|If you would like to downgrade your plan please contact %{support_link_start}Customer Support%{support_link_end}."
@@ -4125,6 +4277,9 @@ msgstr "Импорт из BitBucket"
msgid "Blame"
msgstr ""
+msgid "Block user"
+msgstr ""
+
msgid "Blocked"
msgstr ""
@@ -4140,31 +4295,37 @@ msgstr "Блокирует"
msgid "Blog"
msgstr "Блог"
-msgid "Board name"
-msgstr "Ðазвание доÑки"
-
msgid "Board scope"
msgstr "ОблаÑÑ‚ÑŒ дейÑÑ‚Ð²Ð¸Ñ Ð´Ð¾Ñки"
msgid "Board scope affects which issues are displayed for anyone who visits this board"
msgstr "ОблаÑÑ‚ÑŒ дейÑÑ‚Ð²Ð¸Ñ Ð´Ð¾Ñки влиÑет на то, какие задачи отображаютÑÑ Ð´Ð»Ñ Ð²Ñех, кто поÑещает Ñту доÑку"
-msgid "BoardBlankState|Add default lists"
-msgstr "Добавить ÑпиÑки по умолчанию"
+msgid "Boards"
+msgstr "ДоÑки"
-msgid "BoardBlankState|Add the following default lists to your Issue Board with one click:"
-msgstr "Добавьте Ñледующие ÑпиÑки по умолчанию в доÑку обÑуждений одним нажатием:"
+msgid "Boards and Board Lists"
+msgstr ""
-msgid "BoardBlankState|Nevermind, I'll use my own"
-msgstr "Ðеважно, Ñ Ð±ÑƒÐ´Ñƒ иÑпользовать Ñвой ÑобÑтвенный"
+msgid "Boards|An error occurred while creating the issue. Please try again."
+msgstr ""
-msgid "BoardBlankState|Starting out with the default set of lists will get you right on the way to making the most of your board."
-msgstr "ЗапуÑк Ñ Ð½Ð°Ð±Ð¾Ñ€Ð¾Ð¼ ÑпиÑков по умолчанию позволит вам Ñделать большую чаÑÑ‚ÑŒ вашей доÑки."
+msgid "Boards|An error occurred while creating the list. Please try again."
+msgstr ""
-msgid "Boards"
-msgstr "ДоÑки"
+msgid "Boards|An error occurred while fetching issues. Please reload the page."
+msgstr ""
-msgid "Boards and Board Lists"
+msgid "Boards|An error occurred while fetching the board issues. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching the board swimlanes. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while moving the issue. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while updating the list. Please try again."
msgstr ""
msgid "Boards|Collapse"
@@ -4191,8 +4352,8 @@ msgstr "Ветка %{branchName} не найдена в репозитории Ð
msgid "Branch %{branch_name} was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr ""
-msgid "Branch has changed"
-msgstr "Ветка была изменена"
+msgid "Branch changed"
+msgstr ""
msgid "Branch is already taken"
msgstr "Ветвь уже ÑущеÑтвует"
@@ -4393,7 +4554,7 @@ msgid "Business metrics (Custom)"
msgstr "БизнеÑ-метрики (наÑтраиваемые)"
msgid "Buy License"
-msgstr ""
+msgstr "Купить лицензию"
msgid "Buy more Pipeline minutes"
msgstr "Купить минут Ð´Ð»Ñ CI"
@@ -4402,7 +4563,7 @@ msgid "By %{user_name}"
msgstr "От %{user_name}"
msgid "By URL"
-msgstr ""
+msgstr "По URL"
msgid "By clicking Register, I agree that I have read and accepted the GitLab %{linkStart}Terms of Use and Privacy Policy%{linkEnd}"
msgstr ""
@@ -4423,7 +4584,7 @@ msgid "CI / CD"
msgstr "CI / CD"
msgid "CI / CD Analytics"
-msgstr ""
+msgstr "Ðналитика CI / CD"
msgid "CI / CD Settings"
msgstr "ÐаÑтройки CI / CD"
@@ -4432,7 +4593,7 @@ msgid "CI Lint"
msgstr "CI Lint"
msgid "CI settings"
-msgstr ""
+msgstr "ÐаÑтройки CI"
msgid "CI variables"
msgstr "Переменные CI"
@@ -4497,6 +4658,9 @@ msgstr "ЗÐКРЫТО"
msgid "CLOSED (MOVED)"
msgstr "ЗÐКРЫТО (ПЕРЕМЕЩЕÐО)"
+msgid "CODEOWNERS rule violation"
+msgstr ""
+
msgid "CONTRIBUTING"
msgstr "CONTRIBUTING"
@@ -4527,9 +4691,6 @@ msgstr ""
msgid "Can't create snippet: %{err}"
msgstr ""
-msgid "Can't edit as source branch was deleted"
-msgstr ""
-
msgid "Can't fetch content for the blob: %{err}"
msgstr ""
@@ -4542,9 +4703,6 @@ msgstr "Ðе удаётÑÑ Ð½Ð°Ð¹Ñ‚Ð¸ переменную: ZiteReader"
msgid "Can't load mermaid module: %{err}"
msgstr "Ðе удалоÑÑŒ загрузить Mermaid-модуль: %{err}"
-msgid "Can't remove group members without group managed account"
-msgstr ""
-
msgid "Can't scan the code?"
msgstr "Ðе удаетÑÑ Ð¾Ñ‚Ñканировать QR-код?"
@@ -4587,6 +4745,9 @@ msgstr ""
msgid "Cannot create the abuse report. This user has been blocked."
msgstr ""
+msgid "Cannot enable shared runners because parent group does not allow it"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr "Ðевозможно проводить одновременно неÑколько импортов из Jira"
@@ -4672,10 +4833,10 @@ msgid "Change permissions"
msgstr "Изменить разрешениÑ"
msgid "Change status"
-msgstr ""
+msgstr "Изменить ÑтатуÑ"
msgid "Change subscription"
-msgstr ""
+msgstr "Изменить подпиÑку"
msgid "Change template"
msgstr "Изменить шаблон"
@@ -4692,6 +4853,15 @@ msgstr "Изменить пароль"
msgid "Change your password or recover your current one"
msgstr "Измените пароль или воÑÑтановите текущий"
+msgid "ChangeReviewer|Reviewer changed from %{old} to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Reviewer changed to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Unassigned"
+msgstr ""
+
msgid "ChangeTypeActionLabel|Pick into branch"
msgstr "Выбрать в ветке"
@@ -4731,6 +4901,9 @@ msgstr "Ð˜Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ñкрыты. Ðажмите, чтобы показа
msgid "Changes the title to \"%{title_param}\"."
msgstr "ИзменÑет название на \"%{title_param}\"."
+msgid "Changes were successfully made."
+msgstr ""
+
msgid "Changes won't take place until the index is %{link_start}recreated%{link_end}."
msgstr ""
@@ -4855,7 +5028,7 @@ msgid "Checkout|Checkout"
msgstr ""
msgid "Checkout|City"
-msgstr ""
+msgstr "Город"
msgid "Checkout|Confirm purchase"
msgstr ""
@@ -4870,7 +5043,7 @@ msgid "Checkout|Continue to payment"
msgstr ""
msgid "Checkout|Country"
-msgstr ""
+msgstr "Страна"
msgid "Checkout|Create a new group"
msgstr ""
@@ -5136,6 +5309,9 @@ msgstr "МаÑкируемаÑ"
msgid "CiVariables|Protected"
msgstr "ЗащищеннаÑ"
+msgid "CiVariables|Remove variable"
+msgstr ""
+
msgid "CiVariables|Remove variable row"
msgstr "Удалить Ñтроку переменных"
@@ -5203,7 +5379,7 @@ msgid "Cleanup policy maximum processing time (seconds)"
msgstr ""
msgid "Clear"
-msgstr ""
+msgstr "ОчиÑтить"
msgid "Clear all repository checks"
msgstr ""
@@ -5214,9 +5390,6 @@ msgstr ""
msgid "Clear due date"
msgstr ""
-msgid "Clear input"
-msgstr "ОчиÑтить ввод"
-
msgid "Clear recent searches"
msgstr "ОчиÑтить поÑледние запроÑÑ‹"
@@ -5265,6 +5438,9 @@ msgstr "Ключ аутентификации клиента"
msgid "Client authentication key password"
msgstr ""
+msgid "Client request timeout"
+msgstr ""
+
msgid "Clients"
msgstr "Клиенты"
@@ -5349,6 +5525,27 @@ msgstr ""
msgid "Cluster type must be specificed for Stages::ClusterEndpointInserter"
msgstr ""
+msgid "ClusterAgents|Configuration"
+msgstr ""
+
+msgid "ClusterAgents|Connect your cluster with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate Kubernetes with a GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Name"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Agent also requires %{linkStart}enabling the Agent Server%{linkEnd}"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Kubernetes Agent allows an Infrastructure as Code, GitOps approach to integrating Kubernetes clusters with GitLab. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "ClusterAgent|This feature is only available for premium plans"
msgstr ""
@@ -5418,11 +5615,11 @@ msgstr "Ð’Ñе данные будут удалены без возможноÑÑ
msgid "ClusterIntegration|All installed applications and related resources"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster."
-msgstr "Разрешить GitLab управлÑÑ‚ÑŒ проÑтранÑтвами имен и Ñлужебными аккаунтами Ñтого клаÑтера."
+msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{linkStart}More information%{linkEnd}"
+msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{startLink}More information%{endLink}"
-msgstr "Разрешить GitLab управлÑÑ‚ÑŒ проÑтранÑтвом имен и учетными запиÑÑми Ñлужб Ð´Ð»Ñ Ñтого клаÑтера. %{startLink}Ð”Ð¾Ð¿Ð¾Ð»Ð½Ð¸Ñ‚ÐµÐ»ÑŒÐ½Ð°Ñ Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ%{endLink}"
+msgid "ClusterIntegration|Allow GitLab to manage namespaces and service accounts for this cluster."
+msgstr ""
msgid "ClusterIntegration|Alternatively, "
msgstr ""
@@ -5442,6 +5639,9 @@ msgstr "Произошла ошибка при попытке получениÑ
msgid "ClusterIntegration|An error occurred while trying to fetch zone machine types: %{error}"
msgstr "Произошла ошибка при попытке извлечь типы машин облаÑти: %{error}"
+msgid "ClusterIntegration|An unknown error occurred while attempting to connect to Kubernetes."
+msgstr ""
+
msgid "ClusterIntegration|Any project namespaces"
msgstr ""
@@ -5457,6 +5657,9 @@ msgstr "ÐÑƒÑ‚ÐµÐ½Ñ‚Ð¸Ñ„Ð¸ÐºÐ°Ñ†Ð¸Ñ Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ AWS"
msgid "ClusterIntegration|Authenticate with Amazon Web Services"
msgstr "ÐÑƒÑ‚ÐµÐ½Ñ‚Ð¸Ñ„Ð¸ÐºÐ°Ñ†Ð¸Ñ Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ Amazon Web Services"
+msgid "ClusterIntegration|Authentication Error"
+msgstr ""
+
msgid "ClusterIntegration|Base domain"
msgstr "Базовое доменное имÑ"
@@ -5475,13 +5678,22 @@ msgstr ""
msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
msgstr "Комплект Ñертификатов удоÑтоверÑющего центра (формат PEM)"
-msgid "ClusterIntegration|Choose the %{startLink}security group %{externalLinkIcon} %{endLink} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
+msgid "ClusterIntegration|Check your CA certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Check your cluster status"
+msgstr ""
+
+msgid "ClusterIntegration|Check your token"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}subnets %{externalLinkIcon} %{endLink} in your VPC where your worker nodes will run."
+msgid "ClusterIntegration|Choose the %{linkStart}security group %{linkEnd} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
msgstr ""
-msgid "ClusterIntegration|Choose the worker node %{startLink}instance type %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Choose the %{linkStart}subnets %{linkEnd} in your VPC where your worker nodes will run."
+msgstr ""
+
+msgid "ClusterIntegration|Choose the worker node %{linkStart}instance type%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Choose which applications to install on your Kubernetes cluster."
@@ -5493,12 +5705,9 @@ msgstr "Выберите, какие из ваших окружений буду
msgid "ClusterIntegration|Clear cluster cache"
msgstr "ОчиÑтить кÑш клаÑтера"
-msgid "ClusterIntegration|Clear the local cache of namespace and service accounts. This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
+msgid "ClusterIntegration|Clear the local cache of namespace and service accounts."
msgstr ""
-msgid "ClusterIntegration|Cluster being created"
-msgstr "КлаÑтер ÑоздаетÑÑ"
-
msgid "ClusterIntegration|Cluster management project (alpha)"
msgstr "Проект ÑƒÐ¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ ÐºÐ»Ð°Ñтером (alpha)"
@@ -5508,15 +5717,21 @@ msgstr "ТребуетÑÑ Ð½Ð°Ð·Ð²Ð°Ð½Ð¸Ðµ клаÑтера."
msgid "ClusterIntegration|Cluster_applications artifact too big. Maximum allowable size: %{human_size}"
msgstr ""
-msgid "ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters."
-msgstr "КлаÑтеры иÑпользуютÑÑ Ð¿ÑƒÑ‚Ñ‘Ð¼ выбора ближайшего предка Ñ Ð¿Ð¾Ð´Ñ…Ð¾Ð´Ñщей облаÑтью видимоÑти Ñреды. Ðапример, клаÑтеры проектов будут переопределÑÑ‚ÑŒ клаÑтеры групп."
-
msgid "ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters. %{linkStart}More information%{linkEnd}"
msgstr ""
+msgid "ClusterIntegration|Clusters connected with a certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Connect cluster with certificate"
+msgstr ""
+
msgid "ClusterIntegration|Connect existing cluster"
msgstr ""
+msgid "ClusterIntegration|Connection Error"
+msgstr ""
+
msgid "ClusterIntegration|Copy API URL"
msgstr "Скопировать Ð°Ð´Ñ€ÐµÑ API"
@@ -5592,6 +5807,12 @@ msgstr ""
msgid "ClusterIntegration|Deletes all GitLab resources attached to this cluster during removal"
msgstr ""
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared."
+msgstr ""
+
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared. %{linkStart}More information%{linkEnd}"
+msgstr ""
+
msgid "ClusterIntegration|Did you know?"
msgstr "Знаете ли вы?"
@@ -5661,6 +5882,9 @@ msgstr ""
msgid "ClusterIntegration|Fluentd is an open source data collector, which lets you unify the data collection and consumption for a better use and understanding of data. It requires at least one of the following logs to be successfully installed."
msgstr ""
+msgid "ClusterIntegration|GitLab Agent managed clusters"
+msgstr ""
+
msgid "ClusterIntegration|GitLab Container Network Policies"
msgstr ""
@@ -5673,6 +5897,12 @@ msgstr "GitLab Runner"
msgid "ClusterIntegration|GitLab Runner connects to the repository and executes CI/CD jobs, pushing results back and deploying applications to production."
msgstr "GitLab Runner подключаетÑÑ Ðº репозиторию и выполнÑет Ð·Ð°Ð´Ð°Ð½Ð¸Ñ CI/CD, отправлÑÑ Ñ€ÐµÐ·ÑƒÐ»ÑŒÑ‚Ð°Ñ‚Ñ‹ назад и Ñ€Ð°Ð·Ð²Ð¾Ñ€Ð°Ñ‡Ð¸Ð²Ð°Ñ Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð² продакшн."
+msgid "ClusterIntegration|GitLab failed to authenticate."
+msgstr ""
+
+msgid "ClusterIntegration|GitLab failed to connect to the cluster."
+msgstr ""
+
msgid "ClusterIntegration|GitLab-managed cluster"
msgstr "КлаÑтер управлÑемый GitLab"
@@ -5694,6 +5924,9 @@ msgstr "Проект Google Kubernetes Engine"
msgid "ClusterIntegration|Group cluster"
msgstr "КлаÑтер группы"
+msgid "ClusterIntegration|HTTP Error"
+msgstr ""
+
msgid "ClusterIntegration|Helm Tiller"
msgstr "Helm Tiller"
@@ -5727,8 +5960,11 @@ msgstr "ЭкземплÑÑ€ клаÑтера"
msgid "ClusterIntegration|Instance type"
msgstr "Тип ÑкземплÑра"
-msgid "ClusterIntegration|Integrate Kubernetes cluster automation"
-msgstr "Ð˜Ð½Ñ‚ÐµÐ³Ñ€Ð°Ñ†Ð¸Ñ Ð°Ð²Ñ‚Ð¾Ð¼Ð°Ñ‚Ð¸Ð·Ð°Ñ†Ð¸Ð¸ клаÑтеров Kubernetes"
+msgid "ClusterIntegration|Integrate Kubernetes with a cluster certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Integrate with a cluster certificate"
+msgstr ""
msgid "ClusterIntegration|Issuer Email"
msgstr "Ð­Ð»ÐµÐºÑ‚Ñ€Ð¾Ð½Ð½Ð°Ñ Ð¿Ð¾Ñ‡Ñ‚Ð° Ñмитента"
@@ -5763,9 +5999,6 @@ msgstr "Доменное Ð¸Ð¼Ñ Knative уÑпешно обновлено."
msgid "ClusterIntegration|Knative extends Kubernetes to provide a set of middleware components that are essential to build modern, source-centric, and container-based applications that can run anywhere: on premises, in the cloud, or even in a third-party data center."
msgstr "Knative раÑширÑет возможноÑти Kubernetes в чаÑти обеÑÐ¿ÐµÑ‡ÐµÐ½Ð¸Ñ Ð½Ð°Ð±Ð¾Ñ€Ð¾Ð¼ промежуточных компонентов, которые необходимы Ð´Ð»Ñ Ñ€Ð°Ð·Ñ€Ð°Ð±Ð¾Ñ‚ÐºÐ¸ Ñовременных, оÑнованных на иÑходных данных и контейнерах, приложений, которые могут выполнÑÑ‚ÑŒÑÑ Ð³Ð´Ðµ угодно: локально, в облаках и даже в Ñторонних дата-центрах."
-msgid "ClusterIntegration|Kubernetes cluster"
-msgstr "КлаÑтер Kubernetes"
-
msgid "ClusterIntegration|Kubernetes cluster is being created..."
msgstr ""
@@ -5778,9 +6011,6 @@ msgstr ""
msgid "ClusterIntegration|Kubernetes clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr ""
-msgid "ClusterIntegration|Kubernetes clusters can be used to deploy applications and to provide Review Apps for this project"
-msgstr "КлаÑтеры Kubernetes могут иÑпользоватьÑÑ Ð´Ð»Ñ Ñ€Ð°Ð·Ð²ÐµÑ€Ñ‚Ñ‹Ð²Ð°Ð½Ð¸Ñ Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ð¹ и предоÑÑ‚Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ð¹ Review Ð´Ð»Ñ Ñтого проекта"
-
msgid "ClusterIntegration|Kubernetes version"
msgstr "ВерÑÐ¸Ñ Kubernetes"
@@ -5793,7 +6023,7 @@ msgstr ""
msgid "ClusterIntegration|Learn more about %{help_link_start}zones%{help_link_end}."
msgstr ""
-msgid "ClusterIntegration|Learn more about %{startLink}Regions %{externalLinkIcon}%{endLink}."
+msgid "ClusterIntegration|Learn more about %{linkStart}Regions%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Learn more about Kubernetes"
@@ -5838,12 +6068,18 @@ msgstr ""
msgid "ClusterIntegration|Machine type"
msgstr "Тип машины"
+msgid "ClusterIntegration|Make sure your API endpoint is correct"
+msgstr ""
+
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create Kubernetes clusters"
msgstr "УбедитеÑÑŒ, что ваша ÑƒÑ‡Ñ‘Ñ‚Ð½Ð°Ñ Ð·Ð°Ð¿Ð¸ÑÑŒ %{link_to_requirements} Ð´Ð»Ñ ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ ÐºÐ»Ð°Ñтеров"
msgid "ClusterIntegration|Manage your Kubernetes cluster by visiting %{provider_link}"
msgstr ""
+msgid "ClusterIntegration|Namespace per environment"
+msgstr ""
+
msgid "ClusterIntegration|No IAM Roles found"
msgstr "Роли IAM не найдены"
@@ -5889,6 +6125,9 @@ msgstr "ПодÑети не найдены"
msgid "ClusterIntegration|No zones matched your search"
msgstr "Ðет зон, ÑоответÑтвующих вашему поиÑковому запроÑу"
+msgid "ClusterIntegration|Node calculations use the Kubernetes Metrics API. Make sure your cluster has metrics installed"
+msgstr ""
+
msgid "ClusterIntegration|Number of nodes"
msgstr "КоличеÑтво узлов"
@@ -5931,6 +6170,9 @@ msgstr ""
msgid "ClusterIntegration|RBAC-enabled cluster"
msgstr "КлаÑтер Ñ Ð¿Ð¾Ð´Ð´ÐµÑ€Ð¶ÐºÐ¾Ð¹ RBAC"
+msgid "ClusterIntegration|Read our %{linkStart}help page%{linkEnd} on Kubernetes cluster integration."
+msgstr ""
+
msgid "ClusterIntegration|Read our %{link_start}help page%{link_end} on Kubernetes cluster integration."
msgstr ""
@@ -6033,7 +6275,7 @@ msgstr "Ð”Ð»Ñ Ð²Ñ‹Ð±Ð¾Ñ€Ð° группы безопаÑноÑти необход
msgid "ClusterIntegration|Select a VPC to choose a subnet"
msgstr "Ð”Ð»Ñ Ð²Ñ‹Ð±Ð¾Ñ€Ð° подÑети необходимо выбрать VPC"
-msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{linkStart}Amazon Web Services %{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select a network to choose a subnetwork"
@@ -6066,7 +6308,7 @@ msgstr "Выберите проект и зону, чтобы выбрать Ñ‚Ð
msgid "ClusterIntegration|Select project to choose zone"
msgstr "Выберите проект, чтобы выбрать зону"
-msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select zone"
@@ -6156,9 +6398,18 @@ msgstr ""
msgid "ClusterIntegration|There was a problem authenticating with your cluster. Please ensure your CA Certificate and Token are valid."
msgstr "Произошла ошибка при аутентификации Ñ Ð²Ð°ÑˆÐ¸Ð¼ клаÑтером. УбедитеÑÑŒ, что Ñертификат CA и токен дейÑтвительны."
+msgid "ClusterIntegration|There was an HTTP error when connecting to your cluster."
+msgstr ""
+
msgid "ClusterIntegration|This account must have permissions to create a Kubernetes cluster in the %{link_to_container_project} specified below"
msgstr " У Ñтой учетной запиÑи должны быть Ñ€Ð°Ð·Ñ€ÐµÑˆÐµÐ½Ð¸Ñ Ð½Ð° Ñоздание клаÑтера Kubernetes в %{link_to_container_project} указанных ниже"
+msgid "ClusterIntegration|This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
+msgstr ""
+
+msgid "ClusterIntegration|This is necessary to clear existing environment-namespace associations from clusters previously managed by GitLab."
+msgstr ""
+
msgid "ClusterIntegration|This option will allow you to install applications on RBAC clusters."
msgstr "Эта Ð¾Ð¿Ñ†Ð¸Ñ Ð¿Ð¾Ð·Ð²Ð¾Ð»Ð¸Ñ‚ вам уÑтанавливать Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð½Ð° клаÑтеры RBAC."
@@ -6183,9 +6434,21 @@ msgstr ""
msgid "ClusterIntegration|To use a new project, first create one on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}."
msgstr ""
+msgid "ClusterIntegration|Troubleshooting tips:"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Authenticate"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Connect"
+msgstr ""
+
msgid "ClusterIntegration|Uninstall %{appTitle}"
msgstr "Удалить %{appTitle}"
+msgid "ClusterIntegration|Unknown Error"
+msgstr ""
+
msgid "ClusterIntegration|Update %{appTitle}"
msgstr ""
@@ -6246,7 +6509,7 @@ msgstr "Ваша ÑƒÑ‡Ñ‘Ñ‚Ð½Ð°Ñ Ð·Ð°Ð¿Ð¸ÑÑŒ должна иметь %{link_to_k
msgid "ClusterIntegration|Your cluster API is unreachable. Please ensure your API URL is correct."
msgstr "API клаÑтера недоÑтупно. ПожалуйÑта, убедитеÑÑŒ, что ваш API URL правильный."
-msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Zone"
@@ -6316,7 +6579,7 @@ msgid "Code Owners to the merge request changes."
msgstr ""
msgid "Code Quality"
-msgstr ""
+msgstr "КачеÑтво кода"
msgid "Code Review"
msgstr ""
@@ -6366,6 +6629,9 @@ msgstr ""
msgid "Collapse"
msgstr "Свернуть"
+msgid "Collapse all threads"
+msgstr ""
+
msgid "Collapse approvers"
msgstr "Свернуть утверждающих"
@@ -6391,7 +6657,7 @@ msgid "Comma-separated, e.g. '1.1.1.1, 2.2.2.0/24'"
msgstr ""
msgid "Command"
-msgstr ""
+msgstr "Команда"
msgid "Command line instructions"
msgstr "ИнÑтрукции командной Ñтроки"
@@ -6517,7 +6783,7 @@ msgstr "ЗафикÑировано автором"
msgid "Commit…"
msgstr "Коммит…"
-msgid "Company"
+msgid "Community forum"
msgstr ""
msgid "Company name"
@@ -6526,6 +6792,9 @@ msgstr ""
msgid "Compare"
msgstr "Сравнить"
+msgid "Compare %{oldCommitId}...%{newCommitId}"
+msgstr ""
+
msgid "Compare Git revisions"
msgstr "Сравнение верÑий Git"
@@ -6541,6 +6810,9 @@ msgstr "Сравнить Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ñ Ð¿Ð¾Ñледним коммито
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare submodule commit revisions"
+msgstr ""
+
msgid "Compare with previous version"
msgstr ""
@@ -6676,6 +6948,9 @@ msgstr ""
msgid "Configure the way a user creates a new account."
msgstr ""
+msgid "Configure which lists are shown for anyone who visits this board"
+msgstr ""
+
msgid "Confirm"
msgstr "Подтвердить"
@@ -6749,7 +7024,7 @@ msgid "Contact support"
msgstr ""
msgid "Container Registry"
-msgstr "РееÑÑ‚Ñ€ Контейнеров"
+msgstr "РееÑÑ‚Ñ€ контейнеров"
msgid "Container Scanning"
msgstr "Сканирование контейнеров"
@@ -6802,7 +7077,7 @@ msgid "ContainerRegistry|Build an image"
msgstr "Собрать образ"
msgid "ContainerRegistry|CLI Commands"
-msgstr ""
+msgstr "Команды CLI"
msgid "ContainerRegistry|Cleanup policy for tags is disabled"
msgstr ""
@@ -6847,7 +7122,7 @@ msgid "ContainerRegistry|Expiration policies help manage the storage space used
msgstr ""
msgid "ContainerRegistry|Expiration policy is disabled"
-msgstr ""
+msgstr "Правила иÑÑ‚ÐµÑ‡ÐµÐ½Ð¸Ñ Ð¾Ñ‚ÐºÐ»ÑŽÑ‡ÐµÐ½Ñ‹"
msgid "ContainerRegistry|Expiration policy will run in %{time}"
msgstr ""
@@ -6907,6 +7182,9 @@ msgstr[3] "Удалить тегов"
msgid "ContainerRegistry|Set cleanup policy"
msgstr ""
+msgid "ContainerRegistry|Some tags were not deleted"
+msgstr ""
+
msgid "ContainerRegistry|Something went wrong while fetching the cleanup policy."
msgstr ""
@@ -6946,6 +7224,9 @@ msgstr ""
msgid "ContainerRegistry|Tags with names matching this regex pattern will %{italicStart}expire:%{italicEnd}"
msgstr "Теги Ñ Ð¸Ð¼ÐµÐ½Ð°Ð¼Ð¸, ÑоответÑтвующими Ñтому регулÑрному выражению, будут %{italicStart}проÑрочены:%{italicEnd}"
+msgid "ContainerRegistry|The cleanup policy timed out before it could delete all tags. An administrator can %{adminLinkStart}manually run cleanup now%{adminLinkEnd} or you can wait for the cleanup policy to automatically run again. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "ContainerRegistry|The last tag related to this image was recently removed. This empty image and any associated data will be automatically removed as part of the regular Garbage Collection process. If you have any questions, contact your administrator."
msgstr "ПоÑледний тег, ÑвÑзанный Ñ Ñтим образом недавно был удалён. Этот пуÑтой образ и любые ÑвÑзанные Ñ Ð½Ð¸Ð¼ данные будут автоматичеÑки удалены в ходе регулÑрной Ñборки муÑора. ЕÑли у Ð²Ð°Ñ ÐµÑÑ‚ÑŒ вопроÑÑ‹, ÑвÑжитеÑÑŒ Ñо Ñвоим админиÑтратором."
@@ -6986,10 +7267,10 @@ msgid "ContainerRegistry|With the Container Registry, every project can have its
msgstr "С рееÑтром контейнеров каждый проект может иметь Ñвое меÑто Ð´Ð»Ñ Ñ…Ñ€Ð°Ð½ÐµÐ½Ð¸Ñ Ñвоих Docker образов. %{docLinkStart}ÐŸÐ¾Ð´Ñ€Ð¾Ð±Ð½Ð°Ñ Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ%{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 ""
+msgstr "С рееÑтром контейнеров каждый проект имеет меÑто Ð´Ð»Ñ Ñ…Ñ€Ð°Ð½ÐµÐ½Ð¸Ñ Ñвоих образов Docker. Добавьте Ñ…Ð¾Ñ‚Ñ Ð±Ñ‹ один образ в один из проектов Ñтой группы, чтобы увидеть его здеÑÑŒ.%{docLinkStart}Узнать подробнее%{docLinkEnd}"
msgid "ContainerRegistry|With the GitLab Container Registry, every project can have its own space to store images. %{docLinkStart}More information%{docLinkEnd}"
-msgstr ""
+msgstr "С рееÑтром контейнеров GitLab, у каждого проекта еÑÑ‚ÑŒ Ñвоё меÑто Ð´Ð»Ñ Ñ…Ñ€Ð°Ð½ÐµÐ½Ð¸Ñ Ð¾Ð±Ñ€Ð°Ð·Ð¾Ð² Docker. %{docLinkStart}ÐŸÐ¾Ð´Ñ€Ð¾Ð±Ð½Ð°Ñ Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ%{docLinkEnd}"
msgid "ContainerRegistry|You are about to remove %{item} tags. Are you sure?"
msgstr "Ð’Ñ‹ ÑобираетеÑÑŒ удалить %{item} тегов. Ð’Ñ‹ уверены?"
@@ -7078,6 +7359,9 @@ msgstr ""
msgid "Contributions per group member"
msgstr ""
+msgid "Contributor"
+msgstr ""
+
msgid "Contributors"
msgstr "УчаÑтники"
@@ -7118,7 +7402,7 @@ msgid "Copy External ID to clipboard"
msgstr ""
msgid "Copy ID"
-msgstr ""
+msgstr "Копировать ID"
msgid "Copy KRB5 clone URL"
msgstr "Скопировать URL Ð´Ð»Ñ ÐºÐ»Ð¾Ð½Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ñ‡ÐµÑ€ÐµÐ· KRB5"
@@ -7130,7 +7414,7 @@ msgid "Copy SSH public key"
msgstr "Копировать открытый ключ SSH"
msgid "Copy URL"
-msgstr ""
+msgstr "Копировать URL"
msgid "Copy branch name"
msgstr "Копировать Ð¸Ð¼Ñ Ð²ÐµÑ‚ÐºÐ¸"
@@ -7145,7 +7429,7 @@ msgid "Copy commit SHA"
msgstr "Копировать SHA-Ñумму коммита"
msgid "Copy environment"
-msgstr ""
+msgstr "Скопировать окружение"
msgid "Copy evidence SHA"
msgstr ""
@@ -7207,6 +7491,9 @@ msgstr "Ðе удалоÑÑŒ авторизовать никнейм чата. П
msgid "Could not change HEAD: branch '%{branch}' does not exist"
msgstr ""
+msgid "Could not commit. An unexpected error occurred."
+msgstr ""
+
msgid "Could not connect to FogBugz, check your URL"
msgstr ""
@@ -7232,13 +7519,13 @@ msgid "Could not create project"
msgstr "Ðе удалоÑÑŒ Ñоздать репозиторий"
msgid "Could not create wiki page"
-msgstr ""
+msgstr "Ðе удалоÑÑŒ Ñоздать вики-Ñтраницу"
msgid "Could not delete chat nickname %{chat_name}."
msgstr "Ðе удалоÑÑŒ удалить никнейм чата %{chat_name}."
msgid "Could not delete wiki page"
-msgstr ""
+msgstr "Ðе удалоÑÑŒ удалить вики-Ñтраницу"
msgid "Could not find design."
msgstr ""
@@ -7246,6 +7533,9 @@ msgstr ""
msgid "Could not find iteration"
msgstr ""
+msgid "Could not load instance counts. Please refresh the page to try again."
+msgstr ""
+
msgid "Could not remove the trigger."
msgstr ""
@@ -7270,17 +7560,17 @@ msgstr ""
msgid "Could not save prometheus manual configuration"
msgstr "Ðе удалоÑÑŒ Ñохранить ручную конфигурацию prometheus"
-msgid "Could not udpdate wiki page"
-msgstr ""
-
msgid "Could not update the LDAP settings"
msgstr "Ðе удалоÑÑŒ обновить наÑтройки LDAP"
+msgid "Could not update wiki page"
+msgstr ""
+
msgid "Could not upload your designs as one or more files uploaded are not supported."
msgstr ""
msgid "Country"
-msgstr ""
+msgstr "Страна"
msgid "Coverage"
msgstr "Покрытие"
@@ -7311,7 +7601,7 @@ msgid "Create New Domain"
msgstr "Создать новый домен"
msgid "Create Project"
-msgstr ""
+msgstr "Создать проект"
msgid "Create Value Stream"
msgstr ""
@@ -7894,7 +8184,7 @@ msgid "CycleAnalytics|stage dropdown"
msgstr "Выпадающий ÑпиÑок Ñтапов"
msgid "DAG"
-msgstr ""
+msgstr "DAG"
msgid "DAG visualization requires at least 3 dependent jobs."
msgstr ""
@@ -7935,6 +8225,9 @@ msgstr ""
msgid "DastProfiles|Are you sure you want to delete this profile?"
msgstr ""
+msgid "DastProfiles|Could not create site validation token. Please refresh the page, or try again later."
+msgstr ""
+
msgid "DastProfiles|Could not create the scanner profile. Please try again."
msgstr ""
@@ -7959,6 +8252,12 @@ msgstr ""
msgid "DastProfiles|Could not fetch site profiles. Please refresh the page, or try again later."
msgstr ""
+msgid "DastProfiles|Could not retrieve site validation status. Please refresh the page, or try again later."
+msgstr ""
+
+msgid "DastProfiles|Could not update the scanner profile. Please try again."
+msgstr ""
+
msgid "DastProfiles|Could not update the site profile. Please try again."
msgstr ""
@@ -7974,7 +8273,7 @@ msgstr ""
msgid "DastProfiles|Download validation text file"
msgstr ""
-msgid "DastProfiles|Edit feature will come soon. Please create a new profile if changes needed"
+msgid "DastProfiles|Edit scanner profile"
msgstr ""
msgid "DastProfiles|Edit site profile"
@@ -8007,6 +8306,9 @@ msgstr ""
msgid "DastProfiles|No profiles created yet"
msgstr ""
+msgid "DastProfiles|Passive"
+msgstr ""
+
msgid "DastProfiles|Please enter a valid URL format, ex: http://www.example.com/home"
msgstr ""
@@ -8022,6 +8324,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan mode"
+msgstr ""
+
msgid "DastProfiles|Scanner Profile"
msgstr ""
@@ -8061,10 +8366,10 @@ msgstr ""
msgid "DastProfiles|Text file validation"
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
+msgid "DastProfiles|The maximum number of minutes allowed for the spider to traverse the site."
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the spider to traverse the site."
+msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
msgstr ""
msgid "DastProfiles|Validate"
@@ -8097,6 +8402,9 @@ msgstr "Дата"
msgid "Date picker"
msgstr ""
+msgid "Date range"
+msgstr ""
+
msgid "Date range cannot exceed %{maxDateRange} days."
msgstr ""
@@ -8121,6 +8429,9 @@ msgstr "Дней"
msgid "Days to merge"
msgstr ""
+msgid "Dear Administrator,"
+msgstr ""
+
msgid "Debug"
msgstr "Отладка"
@@ -8131,7 +8442,7 @@ msgid "December"
msgstr "Декабрь"
msgid "Decline"
-msgstr ""
+msgstr "Отклонить"
msgid "Decline and sign out"
msgstr "Отклонить и выйти"
@@ -8232,12 +8543,18 @@ msgstr ""
msgid "Delete"
msgstr "Удалить"
+msgid "Delete %{name}"
+msgstr ""
+
msgid "Delete Comment"
msgstr "Удалить комментарий"
msgid "Delete Snippet"
msgstr "Удалить Ñниппет"
+msgid "Delete Value Stream"
+msgstr ""
+
msgid "Delete account"
msgstr ""
@@ -8259,17 +8576,14 @@ msgstr ""
msgid "Delete label: %{label_name} ?"
msgstr ""
-msgid "Delete license"
-msgstr "Удалить лицензию"
-
msgid "Delete list"
msgstr "Удалить ÑпиÑок"
msgid "Delete pipeline"
-msgstr ""
+msgstr "Удалить Ñборочную линию"
msgid "Delete project"
-msgstr ""
+msgstr "Удалить проект"
msgid "Delete project. Are you ABSOLUTELY SURE?"
msgstr ""
@@ -8278,7 +8592,7 @@ msgid "Delete serverless domain?"
msgstr ""
msgid "Delete snippet"
-msgstr ""
+msgstr "Удалить Ñниппет"
msgid "Delete snippet?"
msgstr ""
@@ -8329,7 +8643,7 @@ msgid "Deleted projects"
msgstr ""
msgid "Deleted projects cannot be restored!"
-msgstr ""
+msgstr "Удаленные проекты не могут воÑÑтановлены!"
msgid "Deleting"
msgstr "Идет удаление"
@@ -8337,15 +8651,6 @@ msgstr "Идет удаление"
msgid "Deleting a project places it into a read-only state until %{date}, at which point the project will be permanently deleted. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "Deleting the license failed."
-msgstr ""
-
-msgid "Deleting the license failed. The license was not found."
-msgstr ""
-
-msgid "Deleting the license failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "Deleting the project will delete its repository and all related resources including issues, merge requests etc."
msgstr ""
@@ -8853,7 +9158,10 @@ msgstr ""
msgid "DesignManagement|The maximum number of designs allowed to be uploaded is %{upload_limit}. Please try again."
msgstr ""
-msgid "DesignManagement|To upload designs, you'll need to enable LFS. %{requirements_link_start}More information%{requirements_link_end}"
+msgid "DesignManagement|There was an error moving your designs. Please upload your designs below."
+msgstr ""
+
+msgid "DesignManagement|To upload designs, you'll need to enable LFS and have admin enable hashed storage. %{requirements_link_start}More information%{requirements_link_end}"
msgstr ""
msgid "DesignManagement|Unresolve thread"
@@ -8865,6 +9173,9 @@ msgstr ""
msgid "DesignManagement|Upload skipped."
msgstr ""
+msgid "DesignManagement|Your designs are being copied and are on their way… Please refresh to update."
+msgstr ""
+
msgid "DesignManagement|and %{moreCount} more."
msgstr "и ещё %{moreCount}."
@@ -8922,6 +9233,9 @@ msgstr ""
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr "Что-то пошло не так при извлечении отличий."
+msgid "Direct member"
+msgstr ""
+
msgid "Direction"
msgstr ""
@@ -8970,9 +9284,6 @@ msgstr "Отменить Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð² %{path}?"
msgid "Discard draft"
msgstr "Удалить черновик"
-msgid "Discard review"
-msgstr ""
-
msgid "DiscordService|Discord Notifications"
msgstr "Discord УведомлениÑ"
@@ -9043,10 +9354,10 @@ msgstr ""
msgid "Dismiss Merge Request promotion"
msgstr ""
-msgid "Dismiss Selected"
+msgid "Dismiss Value Stream Analytics introduction box"
msgstr ""
-msgid "Dismiss Value Stream Analytics introduction box"
+msgid "Dismiss selected"
msgstr ""
msgid "Dismiss trial promotion"
@@ -9089,7 +9400,7 @@ msgid "Dockerfile"
msgstr "Dockerfile"
msgid "Documentation"
-msgstr ""
+msgstr "ДокументациÑ"
msgid "Documentation for popular identity providers"
msgstr ""
@@ -9097,9 +9408,6 @@ msgstr ""
msgid "Documents reindexed: %{processed_documents} (%{percentage}%%)"
msgstr ""
-msgid "Doing"
-msgstr ""
-
msgid "Domain"
msgstr "Домен"
@@ -9155,7 +9463,7 @@ msgid "Download as CSV"
msgstr ""
msgid "Download asset"
-msgstr ""
+msgstr "Скачать реÑурÑ"
msgid "Download codes"
msgstr "Скачать коды"
@@ -9215,7 +9523,7 @@ msgid "Due date"
msgstr "Дата завершениÑ"
msgid "Duration"
-msgstr ""
+msgstr "ДлительноÑÑ‚ÑŒ"
msgid "Duration for the last 30 commits"
msgstr "ДлительноÑÑ‚ÑŒ за поÑледние 30 коммитов"
@@ -9295,9 +9603,6 @@ msgstr "Изменить опиÑание"
msgid "Edit environment"
msgstr ""
-msgid "Edit file"
-msgstr "Изменить файл"
-
msgid "Edit files in the editor and commit changes here"
msgstr "Редактируйте файлы в редакторе и зафикÑируйте Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð·Ð´ÐµÑÑŒ"
@@ -9310,6 +9615,12 @@ msgstr ""
msgid "Edit identity for %{user_name}"
msgstr "Изменить идентификацию Ð´Ð»Ñ %{user_name}"
+msgid "Edit in Web IDE"
+msgstr ""
+
+msgid "Edit in single-file editor"
+msgstr ""
+
msgid "Edit issues"
msgstr ""
@@ -9337,21 +9648,18 @@ msgstr ""
msgid "Editing"
msgstr "Редактирование"
-msgid "Elasticsearch"
-msgstr "Elasticsearch"
-
msgid "Elasticsearch AWS IAM credentials"
msgstr ""
+msgid "Elasticsearch HTTP client timeout value in seconds."
+msgstr ""
+
msgid "Elasticsearch indexing restrictions"
msgstr ""
msgid "Elasticsearch indexing started"
msgstr "ИндекÑÐ°Ñ†Ð¸Ñ Elasticsearch начата"
-msgid "Elasticsearch integration. Elasticsearch AWS IAM."
-msgstr "Ð˜Ð½Ñ‚ÐµÐ³Ñ€Ð°Ñ†Ð¸Ñ Elasticsearch. Elasticsearch AWS IAM."
-
msgid "Elasticsearch reindexing is already in progress"
msgstr ""
@@ -9379,9 +9687,6 @@ msgstr ""
msgid "Email Notification"
msgstr ""
-msgid "Email address"
-msgstr ""
-
msgid "Email could not be sent"
msgstr ""
@@ -9445,6 +9750,9 @@ msgstr "ÐдреÑа Ñл. почты"
msgid "Emails sent from Service Desk will have this name"
msgstr "ПиÑьма, отправленные Ñлужбой поддержки будут иметь Ñто имÑ"
+msgid "Emails sent to %{email} will still be supported"
+msgstr ""
+
msgid "Emails separated by comma"
msgstr "Электронные адреÑа разделенные запÑтой"
@@ -9478,9 +9786,18 @@ msgstr "ПуÑтой файл"
msgid "Enable"
msgstr "Включить"
+msgid "Enable %{link_start}Gitpod%{link_end} integration to launch a development environment in your browser directly from GitLab."
+msgstr ""
+
msgid "Enable Auto DevOps"
msgstr "Включить Auto DevOps"
+msgid "Enable Gitpod"
+msgstr ""
+
+msgid "Enable Gitpod?"
+msgstr ""
+
msgid "Enable HTML emails"
msgstr ""
@@ -9610,9 +9927,6 @@ msgstr ""
msgid "Encountered an error while rendering: %{err}"
msgstr "Произошла ошибка во Ð²Ñ€ÐµÐ¼Ñ Ñ€ÐµÐ½Ð´ÐµÑ€Ð¸Ð½Ð³Ð°: %{err}"
-msgid "End date"
-msgstr ""
-
msgid "Ends at (UTC)"
msgstr "ЗаканчиваетÑÑ Ð² (UTC)"
@@ -9772,7 +10086,7 @@ msgstr "Удалить"
msgid "EnvironmentsDashboard|The environments dashboard provides a summary of each project's environments' status, including pipeline and alert statuses."
msgstr "Панель ÑƒÐ¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ñредами предоÑтавлÑет Ñводку ÑоÑтоÑÐ½Ð¸Ñ Ð¾ÐºÑ€ÑƒÐ¶ÐµÐ½Ð¸Ð¹ каждого проекта, Ð²ÐºÐ»ÑŽÑ‡Ð°Ñ ÑтатуÑÑ‹ Ñборочной линии и оповещений."
-msgid "EnvironmentsDashboard|This dashboard displays a maximum of 7 projects and 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
+msgid "EnvironmentsDashboard|This dashboard displays 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
msgstr ""
msgid "Environments|An error occurred while canceling the auto stop, please try again"
@@ -10093,6 +10407,9 @@ msgstr ""
msgid "Error deleting project. Check logs for error details."
msgstr "Ошибка при удалении проекта. Проверьте журналы Ð´Ð»Ñ Ð¿Ð¾Ð´Ñ€Ð¾Ð±Ð½Ð¾Ñтей об ошибке."
+msgid "Error fetching burnup chart data"
+msgstr ""
+
msgid "Error fetching diverging counts for branches. Please try again."
msgstr ""
@@ -10171,6 +10488,9 @@ msgstr "Произошла ошибка при получении данных Ð
msgid "Error occurred when saving assignees"
msgstr "Произошла ошибка при Ñохранении ответÑтвенных"
+msgid "Error occurred when saving reviewers"
+msgstr ""
+
msgid "Error occurred when toggling the notification subscription"
msgstr "Произошла ошибка при переключении подпиÑки на оповещение"
@@ -10277,7 +10597,7 @@ msgid "Errors"
msgstr "Ошибки"
msgid "Errors:"
-msgstr ""
+msgstr "Ошибки:"
msgid "Estimate"
msgstr ""
@@ -10349,10 +10669,10 @@ msgid "Everyone"
msgstr "Ð’Ñе"
msgid "Everyone With Access"
-msgstr ""
+msgstr "Ð’Ñе, имеющие доÑтуп"
msgid "Everyone can contribute"
-msgstr ""
+msgstr "Каждый может внеÑти Ñвой вклад"
msgid "Everything on your to-do list is marked as done."
msgstr ""
@@ -10423,12 +10743,15 @@ msgstr "Развернуть"
msgid "Expand all"
msgstr "Развернуть вÑе"
+msgid "Expand all files"
+msgstr ""
+
+msgid "Expand all threads"
+msgstr ""
+
msgid "Expand approvers"
msgstr "Развернуть утверждающих"
-msgid "Expand dropdown"
-msgstr "Развернуть раÑкрывающийÑÑ ÑпиÑок"
-
msgid "Expand milestones"
msgstr ""
@@ -10469,7 +10792,7 @@ msgid "Expires on"
msgstr ""
msgid "Expires:"
-msgstr ""
+msgstr "ИÑтекает:"
msgid "Explain the problem. If appropriate, provide a link to the relevant issue or comment."
msgstr "ОбъÑÑните проблему. ЕÑли необходимо, укажите ÑÑылку на ÑоответÑтвующее обÑуждение или комментарий."
@@ -10597,6 +10920,9 @@ msgstr "Ðе удалоÑÑŒ проверить ÑвÑзанные ветки."
msgid "Failed to create Merge Request. Please try again."
msgstr ""
+msgid "Failed to create To-Do for the design."
+msgstr ""
+
msgid "Failed to create a branch for this issue. Please try again."
msgstr ""
@@ -10636,6 +10962,12 @@ msgstr ""
msgid "Failed to load authors. Please try again."
msgstr ""
+msgid "Failed to load branches. Please try again."
+msgstr ""
+
+msgid "Failed to load deploy keys."
+msgstr ""
+
msgid "Failed to load emoji list."
msgstr ""
@@ -10651,6 +10983,9 @@ msgstr "Ðе удалоÑÑŒ загрузить метрики активноÑÑ‚
msgid "Failed to load groups & users."
msgstr "Ðе удалоÑÑŒ загрузить группы и пользователей."
+msgid "Failed to load groups, users and deploy keys."
+msgstr ""
+
msgid "Failed to load labels. Please try again."
msgstr ""
@@ -10660,6 +10995,12 @@ msgstr "Ðе удалоÑÑŒ загрузить Ñтапы. ПожалуйÑта,
msgid "Failed to load related branches"
msgstr ""
+msgid "Failed to load sidebar confidential toggle"
+msgstr ""
+
+msgid "Failed to load sidebar lock status"
+msgstr ""
+
msgid "Failed to load stacktrace."
msgstr ""
@@ -10687,6 +11028,9 @@ msgstr "Ðе удалоÑÑŒ защитить окружение"
msgid "Failed to publish issue on status page."
msgstr ""
+msgid "Failed to remove To-Do for the design."
+msgstr ""
+
msgid "Failed to remove a Zoom meeting"
msgstr ""
@@ -10729,6 +11073,9 @@ msgstr ""
msgid "Failed to signing using smartcard authentication"
msgstr ""
+msgid "Failed to toggle To-Do for the design."
+msgstr ""
+
msgid "Failed to update branch!"
msgstr ""
@@ -10844,7 +11191,7 @@ msgstr ""
msgid "FeatureFlags|Edit User List"
msgstr ""
-msgid "FeatureFlags|Enable features for specific users and specific environments by defining feature flag strategies."
+msgid "FeatureFlags|Enable features for specific users and environments by configuring feature flag strategies."
msgstr ""
msgid "FeatureFlags|Environment Spec"
@@ -10893,7 +11240,7 @@ msgid "FeatureFlags|GitLab is moving to a new way of managing feature flags. Thi
msgstr ""
msgid "FeatureFlags|ID"
-msgstr ""
+msgstr "ID"
msgid "FeatureFlags|Inactive"
msgstr "Ðеактивен"
@@ -10904,8 +11251,8 @@ msgstr "Ðеактивных флаг Ð´Ð»Ñ %{scope}"
msgid "FeatureFlags|Include additional user IDs"
msgstr ""
-msgid "FeatureFlags|Install a %{docs_link_anchored_start}compatible client library%{docs_link_anchored_end} and specify the API URL, application name, and instance ID during the configuration setup. %{docs_link_start}More Information%{docs_link_end}"
-msgstr "УÑтановите %{docs_link_anchored_start}ÑовмеÑтимую клиентÑкую библиотеку%{docs_link_anchored_end} и укажите URL Ð°Ð´Ñ€ÐµÑ API, наименование Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¸ идентификатор ÑкземплÑра Ð¾ÐºÑ€ÑƒÐ¶ÐµÐ½Ð¸Ñ Ð² процеÑÑе наÑтройки конфигурации. %{docs_link_start} Ð”Ð»Ñ Ð±Ð¾Ð»ÑŒÑˆÐµÐ¹ информации%{docs_link_end}"
+msgid "FeatureFlags|Install a %{docsLinkAnchoredStart}compatible client library%{docsLinkAnchoredEnd} and specify the API URL, application name, and instance ID during the configuration setup. %{docsLinkStart}More Information%{docsLinkEnd}"
+msgstr ""
msgid "FeatureFlags|Instance ID"
msgstr "ID ÑкземплÑра"
@@ -10916,6 +11263,9 @@ msgstr ""
msgid "FeatureFlags|Loading feature flags"
msgstr "Загрузка Функциональных опций"
+msgid "FeatureFlags|Loading user lists"
+msgstr ""
+
msgid "FeatureFlags|More information"
msgstr "Подробнее"
@@ -10934,7 +11284,7 @@ msgstr ""
msgid "FeatureFlags|New feature flag"
msgstr "Ðовый переключатель функциональной опции"
-msgid "FeatureFlags|New list"
+msgid "FeatureFlags|New user list"
msgstr ""
msgid "FeatureFlags|Percent of users"
@@ -10973,6 +11323,9 @@ msgstr "Целевые окружениÑ"
msgid "FeatureFlags|There was an error fetching the feature flags."
msgstr ""
+msgid "FeatureFlags|There was an error fetching the user lists."
+msgstr ""
+
msgid "FeatureFlags|There was an error retrieving user lists"
msgstr ""
@@ -10988,6 +11341,9 @@ msgstr "Идентификаторы пользователÑ"
msgid "FeatureFlags|User List"
msgstr ""
+msgid "FeatureFlags|User Lists"
+msgstr ""
+
msgid "FeatureFlag|List"
msgstr ""
@@ -11001,7 +11357,7 @@ msgid "FeatureFlag|There are no configured user lists"
msgstr ""
msgid "FeatureFlag|Type"
-msgstr ""
+msgstr "Тип"
msgid "FeatureFlag|User IDs"
msgstr ""
@@ -11015,15 +11371,6 @@ msgstr "Февраль"
msgid "Fetching incoming email"
msgstr ""
-msgid "Fetching licenses failed."
-msgstr ""
-
-msgid "Fetching licenses failed. The request endpoint was not found."
-msgstr "Ðе удалоÑÑŒ открыть лицензию. ÐšÐ¾Ð½ÐµÑ‡Ð½Ð°Ñ Ñ‚Ð¾Ñ‡ÐºÐ° запроÑа не найдена."
-
-msgid "Fetching licenses failed. You are not permitted to perform this action."
-msgstr "Ðе удалоÑÑŒ открыть лицензию. У Ð²Ð°Ñ Ð½ÐµÑ‚ прав на выполнение Ñтого дейÑтвиÑ."
-
msgid "File"
msgstr "Файл"
@@ -11115,7 +11462,7 @@ msgid "Filter by milestone name"
msgstr "Фильтр по названию Ñтапа"
msgid "Filter by name"
-msgstr ""
+msgstr "Фильтровать по имени"
msgid "Filter by requirements that are currently archived."
msgstr ""
@@ -11126,12 +11473,21 @@ msgstr ""
msgid "Filter by status"
msgstr ""
+msgid "Filter by test cases that are currently archived."
+msgstr ""
+
+msgid "Filter by test cases that are currently opened."
+msgstr ""
+
msgid "Filter by two-factor authentication"
msgstr "Фильтр по двухфакторной аутентификации"
msgid "Filter by user"
msgstr "Фильтр по пользователю"
+msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
+msgstr ""
+
msgid "Filter pipelines"
msgstr ""
@@ -11147,8 +11503,8 @@ msgstr "Фильтровать результаты по проекту"
msgid "Filter results..."
msgstr ""
-msgid "Filter your projects by name"
-msgstr "Отфильтровать проекты по названию"
+msgid "Filter your repositories by name"
+msgstr ""
msgid "Filter..."
msgstr "Фильтр..."
@@ -11156,7 +11512,7 @@ msgstr "Фильтр..."
msgid "Find File"
msgstr ""
-msgid "Find bugs in your code with coverage-guided fuzzing"
+msgid "Find bugs in your code with coverage-guided fuzzing."
msgstr ""
msgid "Find by path"
@@ -11183,9 +11539,6 @@ msgstr ""
msgid "Finish editing this message first!"
msgstr "Сначала завершите редактирование Ñтого ÑообщениÑ!"
-msgid "Finish review"
-msgstr ""
-
msgid "Finish setting up your dedicated account for %{group_name}."
msgstr ""
@@ -11255,6 +11608,9 @@ msgstr "Цвет Шрифта"
msgid "Footer message"
msgstr ""
+msgid "For a faster browsing experience, some files are collapsed by default."
+msgstr ""
+
msgid "For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
@@ -11264,6 +11620,9 @@ msgstr "Во внутренних проектах: любой зарегиÑÑ‚Ñ
msgid "For more info, read the documentation."
msgstr "Ð”Ð»Ñ Ð¿Ð¾Ð»ÑƒÑ‡ÐµÐ½Ð¸Ñ Ð´Ð¾Ð¿Ð¾Ð»Ð½Ð¸Ñ‚ÐµÐ»ÑŒÐ½Ð¾Ð¹ информации читайте документацию."
+msgid "For more information on how the number of active users is calculated, see the %{self_managed_subscriptions_doc_link} documentation."
+msgstr ""
+
msgid "For more information, go to the "
msgstr ""
@@ -11340,7 +11699,7 @@ msgid "Freeze start"
msgstr ""
msgid "Frequency"
-msgstr ""
+msgstr "ЧаÑтота"
msgid "Friday"
msgstr "ПÑтница"
@@ -11402,6 +11761,9 @@ msgstr "Создать новый ÑкÑпорт"
msgid "Generate new token"
msgstr ""
+msgid "Generic package file size in bytes"
+msgstr ""
+
msgid "Geo"
msgstr "Geo"
@@ -11663,6 +12025,9 @@ msgstr ""
msgid "Geo|Please refer to Geo Troubleshooting."
msgstr "ПожалуйÑта обратитеÑÑŒ к решению проблем Geo."
+msgid "Geo|Primary node"
+msgstr ""
+
msgid "Geo|Project"
msgstr "Проект"
@@ -11705,6 +12070,9 @@ msgstr "Cверить вÑе"
msgid "Geo|Review replication status, and resynchronize and reverify items with the primary node."
msgstr ""
+msgid "Geo|Secondary node"
+msgstr ""
+
msgid "Geo|Status"
msgstr "СтатуÑ"
@@ -11744,6 +12112,9 @@ msgstr ""
msgid "Geo|URL must be a valid url (ex: https://gitlab.com)"
msgstr ""
+msgid "Geo|Undefined"
+msgstr ""
+
msgid "Geo|Unknown state"
msgstr "ÐеизвеÑтное ÑоÑтоÑние"
@@ -11819,10 +12190,16 @@ msgstr ""
msgid "GitHub import"
msgstr "Импорт из GitHub"
+msgid "GitLab"
+msgstr ""
+
msgid "GitLab / Unsubscribe"
msgstr "GitLab / ОтпиÑатьÑÑ"
-msgid "GitLab Enterprise Edition %{plan}"
+msgid "GitLab API"
+msgstr ""
+
+msgid "GitLab Billing Team."
msgstr ""
msgid "GitLab Group Runners can execute code for all the projects in this group."
@@ -11834,12 +12211,18 @@ msgstr ""
msgid "GitLab Issue"
msgstr ""
+msgid "GitLab Pages"
+msgstr ""
+
msgid "GitLab Service Desk is a simple way to allow people to create issues in your GitLab instance without needing their own user account. It provides a unique email address for end users to create issues in a project, and replies can be sent either through the GitLab interface or by email. End users will only see the thread through email."
msgstr ""
msgid "GitLab Shared Runners execute code of different projects on the same Runner unless you configure GitLab Runner Autoscale with MaxBuilds 1 (which it is on GitLab.com)."
msgstr ""
+msgid "GitLab Shell"
+msgstr ""
+
msgid "GitLab Support Bot"
msgstr ""
@@ -11849,8 +12232,8 @@ msgstr "Член команды GitLab"
msgid "GitLab User"
msgstr "Пользователь GitLab"
-msgid "GitLab allows you to continue using your license even if you exceed the number of seats you purchased. You will be required to pay for these seats when you renew your license."
-msgstr "GitLab позволÑет продолжить иÑпользование лицензии, даже еÑли вы превыÑили количеÑтво меÑÑ‚, которые вы приобрели. Ð’Ñ‹ должны будете оплатить Ñти меÑта при продлении лицензии."
+msgid "GitLab Workhorse"
+msgstr ""
msgid "GitLab commit"
msgstr "Коммит GitLab"
@@ -12017,6 +12400,21 @@ msgstr ""
msgid "Gitlab Pages"
msgstr "Gitlab Pages"
+msgid "Gitpod"
+msgstr ""
+
+msgid "Gitpod|Add the URL to your Gitpod instance configured to read your GitLab projects."
+msgstr ""
+
+msgid "Gitpod|Enable Gitpod integration"
+msgstr ""
+
+msgid "Gitpod|Gitpod URL"
+msgstr ""
+
+msgid "Gitpod|e.g. https://gitpod.example.com"
+msgstr ""
+
msgid "Given access %{time_ago}"
msgstr "ДоÑтуп предоÑтавлен %{time_ago}"
@@ -12135,7 +12533,7 @@ msgid "Go to the project's overview page"
msgstr "Перейти на Ñтраницу обзора проекта"
msgid "Go to wiki"
-msgstr "Перейти к Wiki"
+msgstr "Перейти к вики"
msgid "Go to your To-Do list"
msgstr ""
@@ -12171,7 +12569,7 @@ msgid "Google authentication is not %{link_start}properly configured%{link_end}.
msgstr ""
msgid "Got it"
-msgstr ""
+msgstr "Готово"
msgid "Got it!"
msgstr "ПонÑтно!"
@@ -12524,9 +12922,6 @@ msgstr ""
msgid "GroupSAML|Valid SAML Response"
msgstr ""
-msgid "GroupSAML|With group managed accounts enabled, all the users without a group managed account will be excluded from the group."
-msgstr ""
-
msgid "GroupSAML|With prohibit outer forks flag enabled group members will be able to fork project only inside your group."
msgstr ""
@@ -12740,10 +13135,10 @@ msgstr ""
msgid "GroupsNew|Create group"
msgstr "Создать группу"
-msgid "GroupsNew|GitLab group export"
+msgid "GroupsNew|Import"
msgstr ""
-msgid "GroupsNew|Import"
+msgid "GroupsNew|Import a GitLab group export file"
msgstr ""
msgid "GroupsNew|Import group"
@@ -12883,10 +13278,13 @@ msgstr "Скрывать архивные проекты"
msgid "Hide chart"
msgid_plural "Hide charts"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
+msgstr[0] "Скрыть график"
+msgstr[1] "Скрыть графики"
+msgstr[2] "Скрыть графики"
+msgstr[3] "Скрыть графики"
+
+msgid "Hide comments on this file"
+msgstr ""
msgid "Hide details"
msgstr ""
@@ -12934,6 +13332,15 @@ msgstr ""
msgid "Highest role:"
msgstr "ÐÐ°Ð¸Ð±Ð¾Ð»ÑŒÑˆÐ°Ñ Ñ€Ð¾Ð»ÑŒ:"
+msgid "HighlightBar|Alert events:"
+msgstr ""
+
+msgid "HighlightBar|Alert start time:"
+msgstr ""
+
+msgid "HighlightBar|Original alert:"
+msgstr ""
+
msgid "History"
msgstr "ИÑториÑ"
@@ -12956,7 +13363,7 @@ msgid "Hostname"
msgstr ""
msgid "Hour (UTC)"
-msgstr ""
+msgstr "Ð§Ð°Ñ (UTC)"
msgid "Housekeeping"
msgstr "ОчиÑтка"
@@ -13013,7 +13420,7 @@ msgid "ID:"
msgstr "ID:"
msgid "IDE"
-msgstr ""
+msgstr "IDE"
msgid "IDE|Allow live previews of JavaScript projects in the Web IDE using CodeSandbox Live Preview."
msgstr ""
@@ -13111,6 +13518,9 @@ msgstr ""
msgid "If enabled, access to projects will be validated on an external service using their classification label."
msgstr ""
+msgid "If the number of active users exceeds the user limit, you will be charged for the number of %{users_over_license_link} at your next license reconciliation."
+msgstr ""
+
msgid "If there is no previous license or if the previous license has expired, some GitLab functionality will be blocked until a new, valid license is uploaded."
msgstr ""
@@ -13150,9 +13560,6 @@ msgstr ""
msgid "If your HTTP repository is not publicly accessible, add your credentials."
msgstr ""
-msgid "Iglu registry URL (optional)"
-msgstr ""
-
msgid "Ignore"
msgstr ""
@@ -13189,6 +13596,20 @@ msgstr "ПерÑÐ¾Ð½Ð°Ð»Ð¸Ð·Ð°Ñ†Ð¸Ñ Ð¾Ñ‚ÐºÐ»ÑŽÑ‡ÐµÐ½Ð°"
msgid "Import"
msgstr "Импортировать"
+msgid "Import %d compatible repository"
+msgid_plural "Import %d compatible repositories"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
+msgid "Import %d repository"
+msgid_plural "Import %d repositories"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "Import CSV"
msgstr ""
@@ -13198,15 +13619,9 @@ msgstr "Импорт проектов из Gitea"
msgid "Import all compatible projects"
msgstr ""
-msgid "Import all compatible repositories"
-msgstr ""
-
msgid "Import all projects"
msgstr ""
-msgid "Import all repositories"
-msgstr "Импортировать вÑе репозитории"
-
msgid "Import an exported GitLab project"
msgstr "Импортировать ÑкÑпортированный проект GitLab"
@@ -13294,6 +13709,9 @@ msgstr "Заблокирован URL импорта: %{message}"
msgid "ImportProjects|Error importing repository %{project_safe_import_url} into %{project_full_path} - %{message}"
msgstr "Ошибка импорта Ñ€ÐµÐ¿Ð¾Ð·Ð¸Ñ‚Ð¾Ñ€Ð¸Ñ %{project_safe_import_url} в %{project_full_path} - %{message}"
+msgid "ImportProjects|Import repositories"
+msgstr ""
+
msgid "ImportProjects|Importing the project failed"
msgstr "Ðе удалоÑÑŒ импортировать проект"
@@ -13306,8 +13724,8 @@ msgstr ""
msgid "ImportProjects|Requesting your %{provider} repositories failed"
msgstr "Ðе удалоÑÑŒ запроÑить %{provider} репозиториев"
-msgid "ImportProjects|Select the projects you want to import"
-msgstr "Выберите проекты, которые вы хотите импортировать"
+msgid "ImportProjects|Select the repositories you want to import"
+msgstr ""
msgid "ImportProjects|The remote data could not be imported."
msgstr "Удаленные данные не могут быть импортированы."
@@ -13342,14 +13760,11 @@ msgstr ""
msgid "In order to enable Service Desk for your instance, you must first set up incoming email."
msgstr ""
-msgid "In order to gather accurate feature usage data, it can take 1 to 2 weeks to see your index."
-msgstr ""
-
msgid "In order to personalize your experience with GitLab%{br_tag}we would like to know a bit more about you."
msgstr ""
msgid "In progress"
-msgstr ""
+msgstr "Ð’ процеÑÑе"
msgid "In the next step, you'll be able to select the projects you want to import."
msgstr ""
@@ -13375,18 +13790,30 @@ msgstr ""
msgid "IncidentManagement|Create incident"
msgstr ""
+msgid "IncidentManagement|Critical - S1"
+msgstr ""
+
msgid "IncidentManagement|Date created"
msgstr ""
msgid "IncidentManagement|Display your incidents in a dedicated view"
msgstr ""
+msgid "IncidentManagement|High - S2"
+msgstr ""
+
msgid "IncidentManagement|Incident"
msgstr ""
msgid "IncidentManagement|Incidents"
msgstr ""
+msgid "IncidentManagement|Low - S4"
+msgstr ""
+
+msgid "IncidentManagement|Medium - S3"
+msgstr ""
+
msgid "IncidentManagement|No incidents to display."
msgstr ""
@@ -13399,6 +13826,9 @@ msgstr ""
msgid "IncidentManagement|Published to status page"
msgstr ""
+msgid "IncidentManagement|Severity"
+msgstr ""
+
msgid "IncidentManagement|There are no closed incidents"
msgstr ""
@@ -13408,6 +13838,9 @@ msgstr ""
msgid "IncidentManagement|Unassigned"
msgstr ""
+msgid "IncidentManagement|Unknown"
+msgstr ""
+
msgid "IncidentManagement|Unpublished"
msgstr ""
@@ -13429,6 +13862,15 @@ msgstr ""
msgid "Incidents"
msgstr "Инциденты"
+msgid "Incident|Alert details"
+msgstr ""
+
+msgid "Incident|Summary"
+msgstr ""
+
+msgid "Incident|There was an issue loading alert data. Please try again."
+msgstr ""
+
msgid "Include a Terms of Service agreement and Privacy Policy that all users must accept."
msgstr ""
@@ -13489,6 +13931,9 @@ msgstr "Сообщать пользователÑм без загруженныÑ
msgid "Information about additional Pages templates and how to install them can be found in our %{pages_getting_started_guide}."
msgstr "Информацию о дополнительных шаблонах Ñтраниц и о том, как их уÑтановить, можно найти в нашем %{pages_getting_started_guide}."
+msgid "Inherited"
+msgstr ""
+
msgid "Inherited:"
msgstr ""
@@ -13571,8 +14016,23 @@ msgstr ""
msgid "Instance administrators group already exists"
msgstr ""
-msgid "Instance license"
-msgstr "Ð›Ð¸Ñ†ÐµÐ½Ð·Ð¸Ñ ÑкземплÑра"
+msgid "InstanceStatistics|Groups"
+msgstr ""
+
+msgid "InstanceStatistics|Issues"
+msgstr ""
+
+msgid "InstanceStatistics|Merge Requests"
+msgstr ""
+
+msgid "InstanceStatistics|Pipelines"
+msgstr ""
+
+msgid "InstanceStatistics|Projects"
+msgstr ""
+
+msgid "InstanceStatistics|Users"
+msgstr ""
msgid "Integration"
msgstr "ИнтеграциÑ"
@@ -13583,6 +14043,12 @@ msgstr ""
msgid "Integrations"
msgstr "Интеграции"
+msgid "Integrations|%{integration} settings saved and active."
+msgstr ""
+
+msgid "Integrations|%{integration} settings saved, but not active."
+msgstr ""
+
msgid "Integrations|All details"
msgstr ""
@@ -13592,6 +14058,12 @@ msgstr ""
msgid "Integrations|Comment settings:"
msgstr ""
+msgid "Integrations|Connection failed. Please check your settings."
+msgstr ""
+
+msgid "Integrations|Connection successful."
+msgstr ""
+
msgid "Integrations|Default settings are inherited from the group level."
msgstr ""
@@ -13607,6 +14079,15 @@ msgstr ""
msgid "Integrations|Includes commit title and branch"
msgstr ""
+msgid "Integrations|Projects using custom settings will not be impacted unless the project owner chooses to use instance-level defaults."
+msgstr ""
+
+msgid "Integrations|Save settings?"
+msgstr ""
+
+msgid "Integrations|Saving will update the default settings for all projects that are not using custom settings."
+msgstr ""
+
msgid "Integrations|Standard"
msgstr ""
@@ -13739,6 +14220,9 @@ msgstr ""
msgid "Invitation"
msgstr ""
+msgid "Invitation declined"
+msgstr ""
+
msgid "Invite"
msgstr "Приглашение"
@@ -13790,6 +14274,42 @@ 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|%{linkStart}Read more%{linkEnd} about role permissions"
+msgstr ""
+
+msgid "InviteMembersModal|Access expiration date (optional)"
+msgstr ""
+
+msgid "InviteMembersModal|Cancel"
+msgstr ""
+
+msgid "InviteMembersModal|Choose a role permission"
+msgstr ""
+
+msgid "InviteMembersModal|GitLab member or Email address"
+msgstr ""
+
+msgid "InviteMembersModal|Invite"
+msgstr ""
+
+msgid "InviteMembersModal|Invite team members"
+msgstr ""
+
+msgid "InviteMembersModal|Search for members to invite"
+msgstr ""
+
+msgid "InviteMembersModal|User not invited. Feature coming soon!"
+msgstr ""
+
+msgid "InviteMembersModal|Users were succesfully added"
+msgstr ""
+
+msgid "InviteMembersModal|You're inviting members to the %{group_name} group"
+msgstr ""
+
+msgid "InviteMembers|Invite team members"
+msgstr ""
+
msgid "Invited"
msgstr ""
@@ -13844,10 +14364,13 @@ msgstr "ОбÑуждение уже было продвинуто до цели.
msgid "Issue cannot be found."
msgstr ""
+msgid "Issue created from vulnerability %{vulnerability_link}"
+msgstr ""
+
msgid "Issue events"
msgstr "Ð¡Ð¾Ð±Ñ‹Ñ‚Ð¸Ñ Ð¾Ð±Ñуждений"
-msgid "Issue first depoloyed to production"
+msgid "Issue first deployed to production"
msgstr ""
msgid "Issue label"
@@ -13925,6 +14448,9 @@ msgstr "СиÑтема ÐºÐ¾Ð½Ñ‚Ñ€Ð¾Ð»Ñ Ð¾Ð±Ñуждений Bugzilla"
msgid "IssueTracker|Custom issue tracker"
msgstr "ПользовательÑÐºÐ°Ñ ÑиÑтема ÐºÐ¾Ð½Ñ‚Ñ€Ð¾Ð»Ñ Ð¾Ð±Ñуждений"
+msgid "IssueTracker|EWM work items tracker"
+msgstr ""
+
msgid "IssueTracker|Redmine issue tracker"
msgstr "СиÑтема ÐºÐ¾Ð½Ñ‚Ñ€Ð¾Ð»Ñ Ð¾Ð±Ñуждений Redmine"
@@ -13991,6 +14517,9 @@ msgstr ""
msgid "It looks like you have some draft commits in this branch."
msgstr ""
+msgid "It may be several days before you see feature usage data."
+msgstr ""
+
msgid "It must have a header row and at least two columns: the first column is the issue title and the second column is the issue description. The separator is automatically detected."
msgstr "Он должен иметь Ñтроку заголовка и по крайней мере две колонки: первый Ñтолбец ÑвлÑетÑÑ Ð·Ð°Ð³Ð¾Ð»Ð¾Ð²ÐºÐ¾Ð¼ обÑуждениÑ, а второй Ñтолбец - опиÑание обÑуждениÑ. Разделитель автоматичеÑки обнаружен."
@@ -14265,23 +14794,23 @@ msgid "Job|for"
msgstr ""
msgid "Job|into"
-msgstr ""
+msgstr "в"
msgid "Job|with"
-msgstr ""
+msgstr "Ñ"
msgid "Join Zoom meeting"
msgstr ""
+msgid "Joined %{time_ago}"
+msgstr ""
+
msgid "Jul"
msgstr "Июл."
msgid "July"
msgstr "Июль"
-msgid "Jump to first unresolved thread"
-msgstr ""
-
msgid "Jump to next unresolved thread"
msgstr ""
@@ -14307,7 +14836,7 @@ msgid "Key"
msgstr "Ключ"
msgid "Key (PEM)"
-msgstr ""
+msgstr "Ключ (PEM)"
msgid "Key: %{key}"
msgstr "Ключ: %{key}"
@@ -14315,11 +14844,14 @@ msgstr "Ключ: %{key}"
msgid "Keyboard shortcuts"
msgstr ""
-msgid "Keys"
+msgid "KeyboardKey|Ctrl+"
msgstr ""
+msgid "Keys"
+msgstr "Ключи"
+
msgid "Ki"
-msgstr ""
+msgstr "Ки"
msgid "Kubernetes"
msgstr "Kubernetes"
@@ -14363,6 +14895,9 @@ msgstr "LDAP"
msgid "LDAP Synchronization"
msgstr ""
+msgid "LDAP group settings"
+msgstr ""
+
msgid "LDAP settings"
msgstr "ÐаÑтройки LDAP"
@@ -14372,6 +14907,9 @@ msgstr "ÐаÑтройки LDAP обновлены"
msgid "LDAP sync in progress. This could take a few minutes. Refresh the page to see the changes."
msgstr "Идет ÑÐ¸Ð½Ñ…Ñ€Ð¾Ð½Ð¸Ð·Ð°Ñ†Ð¸Ñ LDAP. Это может занÑÑ‚ÑŒ неÑколько минут. Обновите Ñтраницу, чтобы увидеть изменениÑ."
+msgid "LDAP synchronizations"
+msgstr ""
+
msgid "LFS"
msgstr "LFS"
@@ -14454,8 +14992,17 @@ msgstr[1] "ПоÑледние %d днÑ"
msgstr[2] "ПоÑледние %d дней"
msgstr[3] "ПоÑледние %d дни"
-msgid "Last %{days} days"
-msgstr "ПоÑледние %{days} днÑ(ей)"
+msgid "Last 2 weeks"
+msgstr ""
+
+msgid "Last 30 days"
+msgstr ""
+
+msgid "Last 60 days"
+msgstr ""
+
+msgid "Last 90 days"
+msgstr ""
msgid "Last Accessed On"
msgstr "ПоÑледнее обращение"
@@ -14532,6 +15079,9 @@ msgstr ""
msgid "Last used on:"
msgstr "ПоÑледнее иÑпользование:"
+msgid "Last week"
+msgstr ""
+
msgid "LastCommit|authored"
msgstr "Ñоздал"
@@ -14547,6 +15097,9 @@ msgstr "ПоÑледние изменениÑ"
msgid "Latest pipeline for the most recent commit on this branch"
msgstr "ПоÑледнÑÑ ÑÐ±Ð¾Ñ€Ð¾Ñ‡Ð½Ð°Ñ Ð»Ð¸Ð½Ð¸Ñ Ð´Ð»Ñ Ñамого Ñвежего коммита в Ñтой ветке"
+msgid "Launch a ready-to-code development environment for your project."
+msgstr ""
+
msgid "Lead"
msgstr ""
@@ -14941,6 +15494,9 @@ msgstr ""
msgid "List of all merge commits"
msgstr ""
+msgid "List options"
+msgstr ""
+
msgid "List settings"
msgstr "ПеречиÑлить наÑтройки"
@@ -14953,9 +15509,6 @@ msgstr ""
msgid "List your Bitbucket Server repositories"
msgstr "СпиÑок репозиториев из Bitbucket Server"
-msgid "Lists"
-msgstr ""
-
msgid "Live preview"
msgstr "Предварительный проÑмотр в реальном времени"
@@ -15202,6 +15755,12 @@ msgstr "Отметить как выполненное"
msgid "Mark as done"
msgstr "Отметить как выполнено"
+msgid "Mark as draft"
+msgstr ""
+
+msgid "Mark as ready"
+msgstr ""
+
msgid "Mark as resolved"
msgstr "Отметить как решенное"
@@ -15223,6 +15782,24 @@ msgstr "Включен режим Markdown"
msgid "Markdown is supported"
msgstr "Markdown поддерживаетÑÑ"
+msgid "MarkdownEditor|Add a link (%{modifierKey}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add a link (%{modifier_key}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifierKey}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifier_key}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifierKey}I)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifier_key}I)"
+msgstr ""
+
msgid "Marked For Deletion At - %{deletion_time}"
msgstr ""
@@ -15307,8 +15884,26 @@ msgstr ""
msgid "Max access level"
msgstr "МакÑимальный уровень доÑтупа"
-msgid "Max seats used"
-msgstr "МакÑимальное количеÑтво иÑпользуемых меÑÑ‚"
+msgid "Max role"
+msgstr ""
+
+msgid "Max size 15 MB"
+msgstr ""
+
+msgid "Maximum Conan package file size in bytes"
+msgstr ""
+
+msgid "Maximum Maven package file size in bytes"
+msgstr ""
+
+msgid "Maximum NPM package file size in bytes"
+msgstr ""
+
+msgid "Maximum NuGet package file size in bytes"
+msgstr ""
+
+msgid "Maximum PyPI package file size in bytes"
+msgstr ""
msgid "Maximum Users:"
msgstr ""
@@ -15419,7 +16014,7 @@ msgid "Members"
msgstr "УчаÑтники"
msgid "Members can be added by project %{i_open}Maintainers%{i_close} or %{i_open}Owners%{i_close}"
-msgstr ""
+msgstr "%{i_open}Maintainer'Ñ‹%{i_close} и %{i_open}Owner'Ñ‹%{i_close} могут добавлÑÑ‚ÑŒ новых учаÑтников"
msgid "Members invited to %{strong_start}%{group_name}%{strong_end}"
msgstr ""
@@ -15439,11 +16034,23 @@ msgstr ""
msgid "Members with access to %{strong_start}%{group_name}%{strong_end}"
msgstr ""
+msgid "Members|%{time} by %{user}"
+msgstr ""
+
+msgid "Members|Expired"
+msgstr ""
+
+msgid "Members|No expiration set"
+msgstr ""
+
+msgid "Members|in %{time}"
+msgstr ""
+
msgid "Memory Usage"
msgstr ""
msgid "Merge"
-msgstr ""
+msgstr "СлиÑние"
msgid "Merge (when the pipeline succeeds)"
msgstr ""
@@ -15625,9 +16232,6 @@ msgstr ""
msgid "MergeRequests|Thread will be unresolved"
msgstr ""
-msgid "MergeRequests|Toggle comments for this file"
-msgstr ""
-
msgid "MergeRequests|View file @ %{commitId}"
msgstr "ПроÑмотр файла @ %{commitId}"
@@ -15688,6 +16292,9 @@ msgstr ""
msgid "Merging immediately isn't recommended as it may negatively impact the existing merge train. Read the %{docsLinkStart}documentation%{docsLinkEnd} for more information."
msgstr ""
+msgid "Message"
+msgstr ""
+
msgid "Messages"
msgstr "СообщениÑ"
@@ -16053,7 +16660,7 @@ msgid "Metrics|e.g. req/sec"
msgstr "например, запроÑов в Ñекунду"
msgid "Mi"
-msgstr ""
+msgstr "Ми"
msgid "Microsoft Azure"
msgstr ""
@@ -16077,18 +16684,12 @@ msgstr[1] "Этапы"
msgstr[2] "Этапы"
msgstr[3] "Этапы"
-msgid "Milestone does not support burnup charts"
-msgstr ""
-
msgid "Milestone lists not available with your current license"
msgstr ""
msgid "Milestone lists show all issues from the selected milestone."
msgstr ""
-msgid "Milestone must have a start and due date"
-msgstr ""
-
msgid "MilestoneSidebar|Closed:"
msgstr ""
@@ -16309,7 +16910,7 @@ msgid "Monitoring"
msgstr "Мониторинг"
msgid "Month"
-msgstr ""
+msgstr "МеÑÑц"
msgid "Months"
msgstr "МеÑÑцы"
@@ -16435,7 +17036,7 @@ msgid "My-Reaction"
msgstr "ÐœÐ¾Ñ Ñ€ÐµÐ°ÐºÑ†Ð¸Ñ"
msgid "N/A"
-msgstr ""
+msgstr "Ðе применимо"
msgid "Name"
msgstr "ИмÑ"
@@ -16455,6 +17056,9 @@ msgstr "Ðаименование:"
msgid "Namespace"
msgstr ""
+msgid "Namespace ID:"
+msgstr ""
+
msgid "Namespace is empty"
msgstr "ПроÑтранÑтво имён пуÑто"
@@ -16495,7 +17099,7 @@ msgid "Needs attention"
msgstr ""
msgid "Network"
-msgstr ""
+msgstr "Сеть"
msgid "Network Policy|New rule"
msgstr ""
@@ -16539,6 +17143,9 @@ msgstr ""
msgid "NetworkPolicies|Allow all outbound traffic from %{selector} to %{ruleSelector} on %{ports}"
msgstr ""
+msgid "NetworkPolicies|Are you sure you want to delete this policy? This action cannot be undone."
+msgstr ""
+
msgid "NetworkPolicies|Choose whether to enforce this policy."
msgstr ""
@@ -16548,12 +17155,21 @@ msgstr ""
msgid "NetworkPolicies|Define this policy's location, conditions and actions."
msgstr ""
+msgid "NetworkPolicies|Delete policy"
+msgstr ""
+
+msgid "NetworkPolicies|Delete policy: %{policy}"
+msgstr ""
+
msgid "NetworkPolicies|Deny all traffic"
msgstr ""
msgid "NetworkPolicies|Description"
msgstr ""
+msgid "NetworkPolicies|Edit policy"
+msgstr ""
+
msgid "NetworkPolicies|Editor mode"
msgstr ""
@@ -16581,6 +17197,9 @@ msgstr ""
msgid "NetworkPolicies|Name"
msgstr ""
+msgid "NetworkPolicies|Namespace"
+msgstr ""
+
msgid "NetworkPolicies|Network Policy"
msgstr ""
@@ -16632,6 +17251,9 @@ msgstr ""
msgid "NetworkPolicies|Rules"
msgstr ""
+msgid "NetworkPolicies|Save changes"
+msgstr ""
+
msgid "NetworkPolicies|Something went wrong, failed to update policy"
msgstr ""
@@ -16644,6 +17266,9 @@ msgstr ""
msgid "NetworkPolicies|Traffic that does not match any rule will be blocked."
msgstr ""
+msgid "NetworkPolicies|Unable to parse policy"
+msgstr ""
+
msgid "NetworkPolicies|YAML editor"
msgstr ""
@@ -16745,7 +17370,7 @@ msgid "New Pages Domain"
msgstr "Ðовый домен Ð´Ð»Ñ Gitlab Pages"
msgid "New Password"
-msgstr ""
+msgstr "Ðовый пароль"
msgid "New Pipeline Schedule"
msgstr "Ðовое РаÑпиÑание Сборочной Линии"
@@ -16759,6 +17384,9 @@ msgstr ""
msgid "New Snippet"
msgstr "Ðовый Ñниппет"
+msgid "New Test Case"
+msgstr ""
+
msgid "New User"
msgstr ""
@@ -16835,7 +17463,7 @@ msgid "New project"
msgstr "Ðовый проект"
msgid "New release"
-msgstr ""
+msgstr "Ðовый релиз"
msgid "New requirement"
msgstr "Ðовое требование"
@@ -16858,6 +17486,9 @@ msgstr "ÐÐ¾Ð²Ð°Ñ Ð¿Ð¾Ð´Ð³Ñ€ÑƒÐ¿Ð¿Ð°"
msgid "New tag"
msgstr "Ðовый тег"
+msgid "New test case"
+msgstr ""
+
msgid "New users set to external"
msgstr ""
@@ -16868,7 +17499,7 @@ msgid "New..."
msgstr "Ðовый..."
msgid "Newest first"
-msgstr ""
+msgstr "Сначала новые"
msgid "Newly registered users will by default be external"
msgstr ""
@@ -16930,7 +17561,7 @@ msgstr ""
msgid "No changes"
msgstr "Ðет изменений"
-msgid "No changes between %{ref_start}%{source_branch}%{ref_end} and %{ref_start}%{target_branch}%{ref_end}"
+msgid "No changes between %{sourceBranch} and %{targetBranch}"
msgstr ""
msgid "No child epics match applied filters"
@@ -16945,6 +17576,9 @@ msgstr ""
msgid "No containers available"
msgstr ""
+msgid "No content to show"
+msgstr ""
+
msgid "No contributions"
msgstr ""
@@ -17020,9 +17654,6 @@ msgstr "Ðет меток Ñ Ñ‚Ð°ÐºÐ¸Ð¼ наименованием или опи
msgid "No license. All rights reserved"
msgstr ""
-msgid "No licenses found."
-msgstr ""
-
msgid "No matches found"
msgstr ""
@@ -17035,6 +17666,9 @@ msgstr "Ðет результатов"
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No members found"
+msgstr ""
+
msgid "No merge requests found"
msgstr ""
@@ -17056,6 +17690,9 @@ msgstr ""
msgid "No parent group"
msgstr ""
+msgid "No plan"
+msgstr ""
+
msgid "No pods available"
msgstr "Ðет доÑтупных подов"
@@ -17141,7 +17778,7 @@ msgid "Node was successfully updated."
msgstr ""
msgid "Nodes"
-msgstr ""
+msgstr "Узлы"
msgid "Non-admin users can sign in with read-only access and make read-only API requests."
msgstr ""
@@ -17152,6 +17789,12 @@ msgstr "ПуÑто"
msgid "Not Implemented"
msgstr ""
+msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+msgstr ""
+
+msgid "Not all browsers support WebAuthn. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even from an unsupported browser."
+msgstr ""
+
msgid "Not all data has been processed yet, the accuracy of the chart for the selected timeframe is limited."
msgstr "Были обработаны не вÑе данные, точноÑÑ‚ÑŒ графика Ð´Ð»Ñ Ð²Ñ‹Ð±Ñ€Ð°Ð½Ð½Ð¾Ð³Ð¾ периода времени ограничена."
@@ -17174,7 +17817,7 @@ msgid "Not found."
msgstr ""
msgid "Not now"
-msgstr ""
+msgstr "Ðе ÑейчаÑ"
msgid "Not ready yet. Try again later."
msgstr ""
@@ -17248,6 +17891,9 @@ msgstr ""
msgid "Notification settings saved"
msgstr "ÐаÑтройки уведомлений Ñохранены"
+msgid "NotificationEvent|Change reviewer merge request"
+msgstr ""
+
msgid "NotificationEvent|Close issue"
msgstr "ОбÑуждение закрыто"
@@ -17399,7 +18045,7 @@ msgid "Oh no!"
msgstr "О, нет!"
msgid "Oldest first"
-msgstr ""
+msgstr "Сначала Ñтарые"
msgid "OmniAuth"
msgstr "OmniAuth"
@@ -17410,10 +18056,7 @@ msgstr ""
msgid "On track"
msgstr "По плану"
-msgid "OnDemandScans|Attached branch"
-msgstr ""
-
-msgid "OnDemandScans|Attached branch is where the scan job runs."
+msgid "OnDemandScans|Could not fetch scanner profiles. Please refresh the page, or try again later."
msgstr ""
msgid "OnDemandScans|Could not fetch site profiles. Please refresh the page, or try again later."
@@ -17422,6 +18065,9 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
+msgid "OnDemandScans|Create a new scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Create a new site profile"
msgstr ""
@@ -17434,6 +18080,9 @@ msgstr ""
msgid "OnDemandScans|New on-demand DAST scan"
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 ""
@@ -17443,16 +18092,10 @@ msgstr ""
msgid "OnDemandScans|On-demand scans run outside the DevOps cycle and find vulnerabilities in your projects. %{learnMoreLinkStart}Learn more%{learnMoreLinkEnd}"
msgstr ""
-msgid "OnDemandScans|Only a passive scan can be performed on demand."
-msgstr ""
-
-msgid "OnDemandScans|Passive"
-msgstr ""
-
msgid "OnDemandScans|Run scan"
msgstr ""
-msgid "OnDemandScans|Scan mode"
+msgid "OnDemandScans|Scanner profile"
msgstr ""
msgid "OnDemandScans|Scanner settings"
@@ -17464,9 +18107,15 @@ msgstr ""
msgid "OnDemandScans|Select one of the existing profiles"
msgstr ""
+msgid "OnDemandScans|Site profile"
+msgstr ""
+
msgid "OnDemandScans|Site profiles"
msgstr ""
+msgid "OnDemandScans|Use existing scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Use existing site profile"
msgstr ""
@@ -17567,9 +18216,6 @@ msgstr "Открыть"
msgid "Open Selection"
msgstr ""
-msgid "Open Web IDE"
-msgstr ""
-
msgid "Open comment type dropdown"
msgstr ""
@@ -17604,7 +18250,7 @@ msgid "Open: %{open} • Closed: %{closed}"
msgstr ""
msgid "Opened"
-msgstr ""
+msgstr "Открыто"
msgid "Opened %{epicTimeagoDate}"
msgstr ""
@@ -17675,6 +18321,9 @@ msgstr ""
msgid "Origin"
msgstr ""
+msgid "Orphaned member"
+msgstr ""
+
msgid "Other Labels"
msgstr "Другие Метки"
@@ -17690,6 +18339,9 @@ msgstr ""
msgid "Other visibility settings have been disabled by the administrator."
msgstr ""
+msgid "Our documentation includes an example DevOps Score report."
+msgstr ""
+
msgid "Out-of-compliance with this project's policies and should be removed"
msgstr "Ðе определена политиками проекта и должна быть удалена"
@@ -17714,8 +18366,11 @@ msgstr "Обзор"
msgid "Overwrite diverged branches"
msgstr ""
+msgid "Owned by %{image_tag}"
+msgstr ""
+
msgid "Owned by anyone"
-msgstr "Принадлежащие кому-либо"
+msgstr "Принадлежащие кому угодно"
msgid "Owned by me"
msgstr "Принадлежащие мне"
@@ -17735,6 +18390,9 @@ msgstr ""
msgid "Package deleted successfully"
msgstr ""
+msgid "Package file size limits"
+msgstr ""
+
msgid "Package recipe already exists"
msgstr ""
@@ -17750,9 +18408,6 @@ msgstr ""
msgid "Package type must be PyPi"
msgstr ""
-msgid "Package was removed"
-msgstr "Пакет был удален"
-
msgid "PackageRegistry|%{name} version %{version} was created %{datetime}"
msgstr ""
@@ -17894,12 +18549,18 @@ msgstr "NuGet"
msgid "PackageRegistry|NuGet Command"
msgstr "Команда NuGet"
+msgid "PackageRegistry|Package Registry"
+msgstr ""
+
msgid "PackageRegistry|Pip Command"
msgstr "Команда pip"
msgid "PackageRegistry|Pipeline %{link} triggered %{datetime} by %{author}"
msgstr ""
+msgid "PackageRegistry|Publish and share packages for a variety of common package managers. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "PackageRegistry|Published to the %{project} Package Registry %{datetime}"
msgstr ""
@@ -17982,7 +18643,7 @@ msgid "PackageType|Maven"
msgstr ""
msgid "PackageType|NPM"
-msgstr ""
+msgstr "NPM"
msgid "PackageType|NuGet"
msgstr ""
@@ -17994,11 +18655,14 @@ msgid "Packages"
msgstr "Пакеты"
msgid "Packages & Registries"
-msgstr ""
+msgstr "Пакеты и рееÑтры"
msgid "Page not found"
msgstr ""
+msgid "Page settings"
+msgstr ""
+
msgid "Page was successfully deleted"
msgstr "Страница была уÑпешно удалена"
@@ -18087,7 +18751,7 @@ msgid "Partial token for reference only"
msgstr ""
msgid "Participants"
-msgstr ""
+msgstr "УчаÑтники"
msgid "Passed"
msgstr ""
@@ -18140,8 +18804,8 @@ msgstr "Ð’Ñтавить ÑÑылку на цель"
msgid "Paste issue link"
msgstr ""
-msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Don't use your private SSH key."
-msgstr "Ð’Ñтавьте ваш открытый ключ SSH, который обычно ÑодержитÑÑ Ð² файле '~/.ssh/id_ed25519.pub' или '~/.ssh/id_rsa.pub' и начинаетÑÑ Ñ 'ssh-ed25519' или 'ssh-rsa'. Ðе иÑпользуйте ваш закрытый ключ SSH."
+msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Do not paste your private SSH key, as that can compromise your identity."
+msgstr ""
msgid "Patch to apply"
msgstr ""
@@ -18167,6 +18831,9 @@ msgstr ""
msgid "Pending"
msgstr "В ожидании"
+msgid "Pending comments"
+msgstr ""
+
msgid "People without permission will never get a notification and won't be able to comment."
msgstr ""
@@ -18177,7 +18844,7 @@ msgid "Percent of users"
msgstr ""
msgid "Percentage"
-msgstr ""
+msgstr "Процент"
msgid "Perform advanced options such as changing path, transferring, exporting, or removing the group."
msgstr ""
@@ -18365,6 +19032,9 @@ msgstr ""
msgid "Pipelines|Build with confidence"
msgstr "ВыполнÑйте Ñборки Ñ ÑƒÐ²ÐµÑ€ÐµÐ½Ð½Ð¾Ñтью"
+msgid "Pipelines|By revoking a trigger you will break any processes making use of it. Are you sure?"
+msgstr ""
+
msgid "Pipelines|CI Lint"
msgstr "CI Lint"
@@ -18377,6 +19047,15 @@ msgstr "ОчиÑтить Runner кÑши "
msgid "Pipelines|Continuous Integration can help catch bugs by running your tests automatically, while Continuous Deployment can help you deliver code to your product environment."
msgstr "ÐÐµÐ¿Ñ€ÐµÑ€Ñ‹Ð²Ð½Ð°Ñ Ð¸Ð½Ñ‚ÐµÐ³Ñ€Ð°Ñ†Ð¸Ñ Ð¼Ð¾Ð¶ÐµÑ‚ помочь выÑвить ошибки, автоматичеÑки выполнÑÑ Ñ‚ÐµÑÑ‚Ñ‹, а непрерывное развёртывание может помочь доÑтавить код в окружение вашего продукта."
+msgid "Pipelines|Copy trigger token"
+msgstr ""
+
+msgid "Pipelines|Description"
+msgstr ""
+
+msgid "Pipelines|Edit"
+msgstr ""
+
msgid "Pipelines|Get started with Pipelines"
msgstr "Ðачало работы Ñо Ñборочными линиÑми"
@@ -18392,15 +19071,27 @@ msgstr ""
msgid "Pipelines|It is recommended the code is reviewed thoroughly before running this pipeline with the parent project's CI resource."
msgstr ""
+msgid "Pipelines|Last Used"
+msgstr ""
+
msgid "Pipelines|Loading Pipelines"
msgstr "ЗагружаютÑÑ Ñборочные линии"
msgid "Pipelines|More Information"
msgstr ""
+msgid "Pipelines|No triggers have been created yet. Add one using the form above."
+msgstr ""
+
+msgid "Pipelines|Owner"
+msgstr ""
+
msgid "Pipelines|Project cache successfully reset."
msgstr "КÑш проекта уÑпешно очищен."
+msgid "Pipelines|Revoke"
+msgstr ""
+
msgid "Pipelines|Run Pipeline"
msgstr "ЗапуÑтить Ñборочную линию"
@@ -18425,6 +19116,15 @@ msgstr ""
msgid "Pipelines|This project is not currently set up to run pipelines."
msgstr "Этот проект в наÑтоÑщее Ð²Ñ€ÐµÐ¼Ñ Ð½Ðµ наÑтроен Ð´Ð»Ñ Ð·Ð°Ð¿ÑƒÑка Ñборочных линий."
+msgid "Pipelines|Token"
+msgstr ""
+
+msgid "Pipelines|Trigger user has insufficient permissions to project"
+msgstr ""
+
+msgid "Pipelines|invalid"
+msgstr ""
+
msgid "Pipelines|parent"
msgstr ""
@@ -18534,7 +19234,7 @@ msgid "Pipeline|Triggerer"
msgstr ""
msgid "Pipeline|Value"
-msgstr ""
+msgstr "Значение"
msgid "Pipeline|Variables"
msgstr "Переменные"
@@ -18567,10 +19267,10 @@ msgid "Plain diff"
msgstr "ПроÑтое отличие"
msgid "Plan"
-msgstr ""
+msgstr "План"
msgid "Plan:"
-msgstr ""
+msgstr "План:"
msgid "PlantUML"
msgstr "PlantUML"
@@ -18683,10 +19383,10 @@ msgstr ""
msgid "Please provide attributes to update"
msgstr ""
-msgid "Please refer to %{docs_url}"
+msgid "Please reach out if you have any questions and we'll be happy to assist."
msgstr ""
-msgid "Please retype the email address."
+msgid "Please refer to %{docs_url}"
msgstr ""
msgid "Please select"
@@ -18716,6 +19416,9 @@ msgstr "ПожалуйÑта, выберите по крайней мере од
msgid "Please set a new password before proceeding."
msgstr ""
+msgid "Please share your feedback about %{featureName} %{linkStart}in this issue%{linkEnd} to help us improve the experience."
+msgstr ""
+
msgid "Please solve the reCAPTCHA"
msgstr "ПожалуйÑта, решите reCAPTCHA"
@@ -18822,7 +19525,7 @@ msgid "Preferences|Show whitespace changes in diffs"
msgstr "Показывать Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð¿Ñ€Ð¾Ð±ÐµÐ»Ð¾Ð² в отличиÑÑ…"
msgid "Preferences|Sourcegraph"
-msgstr ""
+msgstr "Sourcegraph"
msgid "Preferences|Syntax highlighting theme"
msgstr "Тема подÑветки ÑинтакÑиÑа"
@@ -18858,7 +19561,7 @@ msgid "Press %{key}-C to copy"
msgstr ""
msgid "Prev"
-msgstr ""
+msgstr "Пред."
msgid "Prevent adding new members to project membership within this group"
msgstr "Запретить добавление новых учаÑтников в проектах Ñтой группы"
@@ -18954,7 +19657,7 @@ msgid "ProductAnalytics|There is no data for this type of chart currently. Pleas
msgstr ""
msgid "Productivity"
-msgstr ""
+msgstr "ПродуктивноÑÑ‚ÑŒ"
msgid "Productivity Analytics"
msgstr ""
@@ -19019,6 +19722,9 @@ msgstr "Ð’Ñ‹ ÑобираетеÑÑŒ навÑегда удалить %{yourAccoun
msgid "Profiles| You are going to change the username %{currentUsernameBold} to %{newUsernameBold}. Profile and projects will be redirected to the %{newUsername} namespace but this redirect will expire once the %{currentUsername} namespace is registered by another user or group. Please update your Git repository remotes as soon as possible."
msgstr "Ð’Ñ‹ ÑобираетеÑÑŒ изменить Ð¸Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ %{currentUsernameBold} на %{newUsernameBold}. Профиль и проекты будут перенаправлены в проÑтранÑтво имен %{newUsername}, но Ñто перенаправление переÑтанет дейÑтвовать, как только проÑтранÑтво имён %{currentUsername} будет зарегиÑтрировано другим пользователем или группой. ПожалуйÑта, как можно Ñкорее, обновите указатели на Ñвои удаленные репозитории Git."
+msgid "Profiles|%{provider} Active"
+msgstr ""
+
msgid "Profiles|@username"
msgstr "@username"
@@ -19070,8 +19776,8 @@ msgstr "Ðажмите на значок, чтобы активировать в
msgid "Profiles|Commit email"
msgstr "Email коммита"
-msgid "Profiles|Connect"
-msgstr "Подключить"
+msgid "Profiles|Connect %{provider}"
+msgstr ""
msgid "Profiles|Connected Accounts"
msgstr "Подключенные аккаунты"
@@ -19094,6 +19800,9 @@ msgstr "Удаление учетной запиÑи приведет к ÑлеÐ
msgid "Profiles|Disconnect"
msgstr "Отключить"
+msgid "Profiles|Disconnect %{provider}"
+msgstr ""
+
msgid "Profiles|Do not show on profile"
msgstr "Ðе показывать в профиле"
@@ -19118,7 +19827,7 @@ msgstr "Токен новоÑтной ленты уÑпешно Ñброшен"
msgid "Profiles|Full name"
msgstr "Полное имÑ"
-msgid "Profiles|Give your individual key a title. This will be publically visible."
+msgid "Profiles|Give your individual key a title."
msgstr ""
msgid "Profiles|Include private contributions on my profile"
@@ -19208,8 +19917,8 @@ msgstr ""
msgid "Profiles|The maximum file size allowed is 200KB."
msgstr "МакÑимально допуÑтимый размер файла ÑоÑтавлÑет 200 Кбайт."
-msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it?"
-msgstr "Это не выглÑдит как публичный SSH-ключ, вы уверены, что вы хотите добавить его?"
+msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it? It will be publicly visible."
+msgstr ""
msgid "Profiles|This email will be displayed on your public profile"
msgstr "Этот email будет отображатьÑÑ Ð² вашем профиле"
@@ -19283,6 +19992,9 @@ msgstr "Ð’Ñ‹ можете загрузить Ñвой аватар здеÑÑŒ и
msgid "Profiles|You don't have access to delete this user."
msgstr "У Ð²Ð°Ñ Ð½ÐµÑ‚ прав на удаление Ñтого пользователÑ."
+msgid "Profiles|You must transfer ownership or delete groups you are an owner of before you can delete your account"
+msgstr ""
+
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr "Перед удалением учётной запиÑи, вам необходимо передать право Ð²Ð»Ð°Ð´ÐµÐ½Ð¸Ñ Ð¸Ð»Ð¸ удалить Ñти группы."
@@ -19329,7 +20041,7 @@ msgid "Programming languages used in this repository"
msgstr "Языки программированиÑ, иÑпользуемые в Ñтом репозитории"
msgid "Progress"
-msgstr ""
+msgstr "ПрогреÑÑ"
msgid "Project"
msgstr "Проект"
@@ -19389,7 +20101,7 @@ msgid "Project already deleted"
msgstr ""
msgid "Project and wiki repositories"
-msgstr "Репозитории проекта и Wiki"
+msgstr "Репозитории проекта и вики"
msgid "Project avatar"
msgstr "Ðватар проекта"
@@ -19431,7 +20143,7 @@ msgid "Project has too many %{label_for_message} to search"
msgstr "Проект имеет Ñлишком много %{label_for_message} Ð´Ð»Ñ Ð¿Ð¾Ð¸Ñка"
msgid "Project info:"
-msgstr ""
+msgstr "Ð˜Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¾ проекте:"
msgid "Project is required when cluster_type is :project"
msgstr ""
@@ -19647,10 +20359,10 @@ msgid "ProjectSettings|Disable email notifications"
msgstr "Отключить ÑƒÐ²ÐµÐ´Ð¾Ð¼Ð»ÐµÐ½Ð¸Ñ Ð¿Ð¾ Ñлектронной почте"
msgid "ProjectSettings|Do not allow"
-msgstr ""
+msgstr "Ðе разрешать"
msgid "ProjectSettings|Enable 'Delete source branch' option by default"
-msgstr ""
+msgstr "Включить опцию 'Удалить иÑходную ветку' по-умолчанию"
msgid "ProjectSettings|Enable merge trains and pipelines for merged results"
msgstr ""
@@ -19871,6 +20583,9 @@ msgstr "Android"
msgid "ProjectTemplates|GitLab Cluster Management"
msgstr ""
+msgid "ProjectTemplates|Gitpod/Spring Petclinic"
+msgstr ""
+
msgid "ProjectTemplates|Go Micro"
msgstr "Go Micro"
@@ -20325,10 +21040,10 @@ msgid "Protect"
msgstr ""
msgid "Protect variable"
-msgstr ""
+msgstr "Защитить переменную"
msgid "Protected"
-msgstr ""
+msgstr "Защищённый"
msgid "Protected Branch"
msgstr ""
@@ -20480,6 +21195,9 @@ msgstr ""
msgid "Publish to status page"
msgstr ""
+msgid "Published"
+msgstr ""
+
msgid "Published on status page"
msgstr ""
@@ -20586,7 +21304,7 @@ msgid "Query cannot be processed"
msgstr ""
msgid "Query is valid"
-msgstr ""
+msgstr "Ð—Ð°Ð¿Ñ€Ð¾Ñ Ð²ÐµÑ€ÐµÐ½"
msgid "Queued"
msgstr ""
@@ -20597,9 +21315,15 @@ msgstr "БыÑтрые дейÑÑ‚Ð²Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ иÑпользоватьÑÑ
msgid "Quick range"
msgstr ""
+msgid "Quickly and easily edit multiple files in your project."
+msgstr ""
+
msgid "README"
msgstr ""
+msgid "Rails"
+msgstr ""
+
msgid "Rake Tasks Help"
msgstr ""
@@ -20721,12 +21445,15 @@ msgstr "РегиÑÑ‚Ñ€Ð°Ñ†Ð¸Ñ / Вход"
msgid "Register Two-Factor Authenticator"
msgstr "РегиÑÑ‚Ñ€Ð°Ñ†Ð¸Ñ Ð´Ð²ÑƒÑ…Ñ„Ð°ÐºÑ‚Ð¾Ñ€Ð½Ð¾Ð¹ аутентификации"
-msgid "Register U2F device"
-msgstr "ЗарегиÑтрировать уÑтройÑтво U2F"
-
msgid "Register Universal Two-Factor (U2F) Device"
msgstr "ЗарегиÑтрируйте универÑальное двухфакторное (U2F) уÑтройÑтво"
+msgid "Register WebAuthn Device"
+msgstr ""
+
+msgid "Register device"
+msgstr ""
+
msgid "Register for GitLab"
msgstr ""
@@ -20736,9 +21463,6 @@ msgstr ""
msgid "Register with two-factor app"
msgstr "РегиÑÑ‚Ñ€Ð°Ñ†Ð¸Ñ Ð¿Ñ€Ð¸ помощи приложениÑ"
-msgid "Registration"
-msgstr ""
-
msgid "Registration|Checkout"
msgstr ""
@@ -20789,10 +21513,10 @@ msgstr ""
msgid "Release"
msgid_plural "Releases"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
+msgstr[0] "Релиз"
+msgstr[1] "Релиза"
+msgstr[2] "Релизов"
+msgstr[3] "Релизов"
msgid "Release assets"
msgstr ""
@@ -20857,9 +21581,6 @@ msgstr ""
msgid "Release|Something went wrong while saving the release details"
msgstr ""
-msgid "Remediated: needs review"
-msgstr ""
-
msgid "Remediations"
msgstr ""
@@ -20945,7 +21666,7 @@ msgid "Remove license"
msgstr ""
msgid "Remove limit"
-msgstr ""
+msgstr "Убрать лимит"
msgid "Remove member"
msgstr ""
@@ -20965,6 +21686,9 @@ msgstr ""
msgid "Remove priority"
msgstr ""
+msgid "Remove report"
+msgstr ""
+
msgid "Remove secondary node"
msgstr ""
@@ -20977,6 +21701,12 @@ msgstr "Удалить Ñтап"
msgid "Remove time estimate"
msgstr ""
+msgid "Remove user & report"
+msgstr ""
+
+msgid "Remove user from group"
+msgstr ""
+
msgid "Removed"
msgstr ""
@@ -21058,9 +21788,6 @@ msgstr "УдалÑет дату завершениÑ."
msgid "Removes time estimate."
msgstr ""
-msgid "Removing license…"
-msgstr "Удаление лицензии…"
-
msgid "Removing this group also removes all child projects, including archived projects, and their resources."
msgstr "Удаление Ñтой группы также приведет к удалению вÑех дочерних проектов, Ð²ÐºÐ»ÑŽÑ‡Ð°Ñ Ð°Ñ€Ñ…Ð¸Ð²Ð½Ñ‹Ðµ, а также их реÑурÑов."
@@ -21071,7 +21798,7 @@ msgid "Rename folder"
msgstr ""
msgid "Rename/Move"
-msgstr ""
+msgstr "Переименовать/перемеÑтить"
msgid "Reopen"
msgstr "Открыть заново"
@@ -21145,6 +21872,9 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr "Сообщил %{reportedBy} %{timeAgo}"
+msgid "Reported by %{reporter}"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -21177,7 +21907,7 @@ msgid "Reports|An error occurred while loading %{name} results"
msgstr ""
msgid "Reports|Class"
-msgstr ""
+msgstr "КлаÑÑ"
msgid "Reports|Classname"
msgstr ""
@@ -21233,6 +21963,27 @@ msgstr ""
msgid "Repositories"
msgstr ""
+msgid "Repositories Analytics"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download Historic Test Coverage Data"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download historic test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Historic Test Coverage Data is available in raw format (.csv) for further analysis."
+msgstr ""
+
+msgid "RepositoriesAnalytics|Test Code Coverage"
+msgstr ""
+
+msgid "RepositoriesAnalytics|There was an error fetching the projects."
+msgstr ""
+
msgid "Repository"
msgstr "Репозиторий"
@@ -21311,9 +22062,15 @@ msgstr ""
msgid "Request parameter %{param} is missing."
msgstr ""
+msgid "Request review from"
+msgstr ""
+
msgid "Request to link SAML account must be authorized"
msgstr ""
+msgid "Requested"
+msgstr ""
+
msgid "Requested %{time_ago}"
msgstr "Запрошено %{time_ago}"
@@ -21332,6 +22089,9 @@ msgstr ""
msgid "Requests to these domain(s)/address(es) on the local network will be allowed when local requests from hooks and services are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 or 127.0.0.0/28 are supported. Domain wildcards are not supported currently. Use comma, semicolon, or newline to separate multiple entries. The allowlist can hold a maximum of 1000 entries. Domains should use IDNA encoding. Ex: example.com, 192.168.1.1, 127.0.0.0/28, xn--itlab-j1a.com."
msgstr ""
+msgid "Require admin approval for new sign-ups"
+msgstr ""
+
msgid "Require all users in this group to setup Two-factor authentication"
msgstr "Требовать от вÑех пользователей в группе наÑтроить двух-факторную аутентификацию"
@@ -21463,9 +22223,6 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
-msgid "Resolved by %{resolvedByName}"
-msgstr "Решено %{resolvedByName}"
-
msgid "Resolves IP addresses once and uses them to submit requests"
msgstr ""
@@ -21587,6 +22344,16 @@ msgstr ""
msgid "ReviewApp|Enable Review App"
msgstr ""
+msgid "Reviewer"
+msgid_plural "%d Reviewers"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
+msgid "Reviewer(s)"
+msgstr ""
+
msgid "Reviewing"
msgstr "Рецензировать"
@@ -21626,6 +22393,9 @@ msgstr ""
msgid "Rook"
msgstr ""
+msgid "Ruby"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -21704,6 +22474,63 @@ msgstr ""
msgid "Runners page."
msgstr ""
+msgid "Runners|Active"
+msgstr ""
+
+msgid "Runners|Architecture"
+msgstr ""
+
+msgid "Runners|Can run untagged jobs"
+msgstr ""
+
+msgid "Runners|Description"
+msgstr ""
+
+msgid "Runners|Group"
+msgstr ""
+
+msgid "Runners|IP Address"
+msgstr ""
+
+msgid "Runners|Last contact"
+msgstr ""
+
+msgid "Runners|Locked to this project"
+msgstr ""
+
+msgid "Runners|Maximum job timeout"
+msgstr ""
+
+msgid "Runners|Name"
+msgstr ""
+
+msgid "Runners|Platform"
+msgstr ""
+
+msgid "Runners|Property Name"
+msgstr ""
+
+msgid "Runners|Protected"
+msgstr ""
+
+msgid "Runners|Revision"
+msgstr ""
+
+msgid "Runners|Shared"
+msgstr ""
+
+msgid "Runners|Specific"
+msgstr ""
+
+msgid "Runners|Tags"
+msgstr ""
+
+msgid "Runners|Value"
+msgstr ""
+
+msgid "Runners|Version"
+msgstr ""
+
msgid "Runners|You have used %{quotaUsed} out of %{quotaLimit} of your shared Runners pipeline minutes."
msgstr "Ð’Ñ‹ иÑпользовали %{quotaUsed} из %{quotaLimit} ваших минут Ñборки на общих Runner'ах."
@@ -21716,6 +22543,9 @@ msgstr "ВыполнÑетÑÑ…"
msgid "Runs a number of housekeeping tasks within the current repository, such as compressing file revisions and removing unreachable objects."
msgstr "ЗапуÑкает Ñ€Ñд Ñлужебных задач в текущем репозитории, таких как Ñжатие верÑий файлов и удаление недоÑтупных объектов."
+msgid "SAML"
+msgstr ""
+
msgid "SAML SSO"
msgstr ""
@@ -21732,7 +22562,7 @@ msgid "SAST Configuration"
msgstr ""
msgid "SHA256"
-msgstr ""
+msgstr "SHA256"
msgid "SSH Key"
msgstr "Ключ SSH"
@@ -21767,6 +22597,9 @@ msgstr "Суббота"
msgid "Save"
msgstr "Сохранить"
+msgid "Save %{name} size limits"
+msgstr ""
+
msgid "Save Changes"
msgstr ""
@@ -21797,9 +22630,6 @@ msgstr "Сохранить раÑпиÑание Ñборочной лини"
msgid "Save space and find tags in the Container Registry more easily. Enable the cleanup policy to remove stale tags and keep only the ones you need."
msgstr ""
-msgid "Save template"
-msgstr ""
-
msgid "Save variables"
msgstr "Сохранить переменные"
@@ -21842,9 +22672,6 @@ msgstr "Планирование Сборочных Линий"
msgid "Scope"
msgstr "ОблаÑÑ‚ÑŒ"
-msgid "Scope not supported with disabled 'users_search' feature!"
-msgstr ""
-
msgid "Scoped issue boards"
msgstr ""
@@ -21971,9 +22798,6 @@ msgstr ""
msgid "Search requirements"
msgstr ""
-msgid "Search results…"
-msgstr ""
-
msgid "Search users"
msgstr "ПоиÑк пользователей"
@@ -22052,6 +22876,13 @@ msgstr[1] "коммита"
msgstr[2] "коммитов"
msgstr[3] "коммитов"
+msgid "SearchResults|epic"
+msgid_plural "SearchResults|epics"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "SearchResults|issue"
msgid_plural "SearchResults|issues"
msgstr[0] ""
@@ -22089,10 +22920,10 @@ msgstr[3] ""
msgid "SearchResults|user"
msgid_plural "SearchResults|users"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
+msgstr[0] "пользователь"
+msgstr[1] "пользователÑ"
+msgstr[2] "пользователей"
+msgstr[3] "пользователей"
msgid "SearchResults|wiki result"
msgid_plural "SearchResults|wiki results"
@@ -22110,11 +22941,11 @@ msgstr ""
msgid "Seat Link is disabled, and cannot be configured through this form."
msgstr ""
-msgid "Seats currently in use"
-msgstr "МеÑта в наÑтоÑщее Ð²Ñ€ÐµÐ¼Ñ Ð¸ÑпользуютÑÑ"
+msgid "Seats usage data as of %{last_enqueue_time}"
+msgstr ""
-msgid "Seats in license"
-msgstr "МеÑÑ‚ в лицензии"
+msgid "Seats usage data is updated every day at 12:00pm UTC"
+msgstr ""
msgid "Secondary"
msgstr ""
@@ -22167,6 +22998,9 @@ msgstr ""
msgid "SecurityConfiguration|Available for on-demand DAST"
msgstr ""
+msgid "SecurityConfiguration|By default, all analyzers are applied in order to cover all languages across your project, and only run if the language is detected in the Merge Request."
+msgstr ""
+
msgid "SecurityConfiguration|Configure"
msgstr ""
@@ -22197,16 +23031,19 @@ msgstr ""
msgid "SecurityConfiguration|Manage"
msgstr ""
+msgid "SecurityConfiguration|More information"
+msgstr ""
+
msgid "SecurityConfiguration|Not enabled"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|Security Control"
+msgid "SecurityConfiguration|SAST Configuration"
msgstr ""
-msgid "SecurityConfiguration|See documentation"
+msgid "SecurityConfiguration|Security Control"
msgstr ""
msgid "SecurityConfiguration|Status"
@@ -22218,6 +23055,9 @@ msgstr ""
msgid "SecurityConfiguration|Using custom settings. You won't receive automatic updates on this variable. %{anchorStart}Restore to default%{anchorEnd}"
msgstr ""
+msgid "SecurityConfiguration|View history"
+msgstr ""
+
msgid "SecurityConfiguration|You can quickly enable all security scanning tools by enabling %{linkStart}Auto DevOps%{linkEnd}."
msgstr ""
@@ -22296,9 +23136,6 @@ msgstr ""
msgid "SecurityReports|Learn more about setting up your dashboard"
msgstr ""
-msgid "SecurityReports|Load more vulnerabilities"
-msgstr ""
-
msgid "SecurityReports|Monitor vulnerabilities in your code"
msgstr ""
@@ -22483,7 +23320,7 @@ msgid "Select a project to read Insights configuration file"
msgstr "Выберите проект Ð´Ð»Ñ Ñ‡Ñ‚ÐµÐ½Ð¸Ñ Ñ„Ð°Ð¹Ð»Ð° конфигурации Insights"
msgid "Select a reason"
-msgstr ""
+msgstr "Выберите причину"
msgid "Select a repository"
msgstr ""
@@ -22578,7 +23415,7 @@ msgstr ""
msgid "Select status"
msgstr ""
-msgid "Select strategy activation method"
+msgid "Select strategy activation method."
msgstr ""
msgid "Select subscription"
@@ -22593,7 +23430,7 @@ msgstr "Выберите ветвь, которую вы хотите уÑтан
msgid "Select the custom project template source group."
msgstr ""
-msgid "Select timeframe"
+msgid "Select the environment scope for this feature flag."
msgstr ""
msgid "Select timezone"
@@ -22842,6 +23679,9 @@ msgstr ""
msgid "Set iteration"
msgstr ""
+msgid "Set limit to 0 to allow any file size."
+msgstr ""
+
msgid "Set max session time for web terminal."
msgstr "УÑтановить макÑимальное Ð²Ñ€ÐµÐ¼Ñ ÑеанÑа Ð´Ð»Ñ Ð²ÐµÐ±-терминала."
@@ -22920,11 +23760,14 @@ msgstr ""
msgid "Set up a %{type} Runner manually"
msgstr ""
+msgid "Set up a hardware device as a second factor to sign in."
+msgstr ""
+
msgid "Set up assertions/attributes/claims (email, first_name, last_name) and NameID according to %{docsLinkStart}the documentation %{icon}%{docsLinkEnd}"
msgstr ""
-msgid "Set up new U2F device"
-msgstr "ÐаÑтроить новое уÑтройÑтво U2F"
+msgid "Set up new device"
+msgstr ""
msgid "Set up new password"
msgstr ""
@@ -22992,6 +23835,9 @@ msgstr ""
msgid "Sets weight to %{weight}."
msgstr "УÑтанавливает приоритет на %{weight}."
+msgid "Setting this to 0 means using the system default timeout value."
+msgstr ""
+
msgid "Settings"
msgstr "ÐаÑтройки"
@@ -23007,6 +23853,15 @@ msgstr ""
msgid "Severity"
msgstr ""
+msgid "SeverityWidget|Severity"
+msgstr ""
+
+msgid "SeverityWidget|Severity: %{severity}"
+msgstr ""
+
+msgid "SeverityWidget|There was an error while updating severity."
+msgstr ""
+
msgid "Shards (%{shards})"
msgstr ""
@@ -23052,6 +23907,9 @@ msgstr "Показывать вÑех учаÑтников"
msgid "Show all requirements."
msgstr ""
+msgid "Show all test cases."
+msgstr ""
+
msgid "Show archived projects"
msgstr "Показывать архивные проекты"
@@ -23064,6 +23922,9 @@ msgstr "Показать команду"
msgid "Show comments"
msgstr ""
+msgid "Show comments on this file"
+msgstr ""
+
msgid "Show comments only"
msgstr "Показать только комментарии"
@@ -23109,6 +23970,12 @@ msgstr "Показать родительÑкие Ñтраницы"
msgid "Show parent subgroups"
msgstr "Показать родительÑкие подгруппы"
+msgid "Show the Closed list"
+msgstr ""
+
+msgid "Show the Open list"
+msgstr ""
+
msgid "Show whitespace changes"
msgstr "Показать Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð¿Ñ€Ð¾Ð±ÐµÐ»Ð¾Ð²"
@@ -23156,9 +24023,6 @@ msgstr ""
msgid "Sidebar|Assign health status"
msgstr ""
-msgid "Sidebar|Change weight"
-msgstr "Изменить приоритет"
-
msgid "Sidebar|Health status"
msgstr ""
@@ -23322,7 +24186,7 @@ msgid "Snippets with non-text files can only be edited via Git."
msgstr ""
msgid "SnippetsEmptyState|Code snippets"
-msgstr ""
+msgstr "Сниппеты"
msgid "SnippetsEmptyState|Documentation"
msgstr ""
@@ -23334,7 +24198,7 @@ msgid "SnippetsEmptyState|No snippets found"
msgstr "Сниппеты не найдены"
msgid "SnippetsEmptyState|Store, share, and embed small pieces of code and text."
-msgstr ""
+msgstr "СохранÑйте, раÑпроÑтранÑйте и вÑтраиваете небольшие фрагменты кода и текÑта."
msgid "SnippetsEmptyState|There are no snippets to show."
msgstr "Ðет Ñниппетов Ð´Ð»Ñ Ð¾Ñ‚Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ."
@@ -23342,6 +24206,9 @@ msgstr "Ðет Ñниппетов Ð´Ð»Ñ Ð¾Ñ‚Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ."
msgid "Snippets|Add another file %{num}/%{total}"
msgstr ""
+msgid "Snippets|Authored %{time_ago} by %{author}"
+msgstr ""
+
msgid "Snippets|Delete file"
msgstr ""
@@ -23369,6 +24236,9 @@ msgstr ""
msgid "Solution"
msgstr ""
+msgid "Some changes are not shown"
+msgstr ""
+
msgid "Some child epics may be hidden due to applied filters"
msgstr ""
@@ -23735,6 +24605,12 @@ msgstr "ИÑточник"
msgid "Source (branch or tag)"
msgstr "ИÑточник (ветка или тег)"
+msgid "Source Branch"
+msgstr ""
+
+msgid "Source branch: %{source_branch_open}%{source_branch}%{source_branch_close}"
+msgstr ""
+
msgid "Source code"
msgstr "ИÑходный код"
@@ -23748,7 +24624,7 @@ msgid "Source project cannot be found."
msgstr ""
msgid "Sourcegraph"
-msgstr ""
+msgstr "Sourcegraph"
msgid "SourcegraphAdmin|Block on private and internal projects"
msgstr ""
@@ -23757,7 +24633,7 @@ msgid "SourcegraphAdmin|Configure the URL to a Sourcegraph instance which can re
msgstr ""
msgid "SourcegraphAdmin|Enable Sourcegraph"
-msgstr ""
+msgstr "Включить Sourcegraph"
msgid "SourcegraphAdmin|Enable code intelligence powered by %{link_start}Sourcegraph%{link_end} on your GitLab instance's code views and merge requests."
msgstr ""
@@ -23766,10 +24642,10 @@ msgid "SourcegraphAdmin|If checked, only public projects will have code intellig
msgstr ""
msgid "SourcegraphAdmin|More information"
-msgstr ""
+msgstr "Больше данных"
msgid "SourcegraphAdmin|Save changes"
-msgstr ""
+msgstr "Сохранить изменениÑ"
msgid "SourcegraphAdmin|Sourcegraph URL"
msgstr ""
@@ -23900,9 +24776,6 @@ msgstr "Ðачать рецензию"
msgid "Start and due date"
msgstr "Дата начала и завершениÑ"
-msgid "Start by choosing a group to see how your team is spending time. You can then drill down to the project level."
-msgstr ""
-
msgid "Start by choosing a group to start exploring the merge requests in that group. You can then proceed to filter by projects, labels, milestones and authors."
msgstr "Ðачните Ñ Ð²Ñ‹Ð±Ð¾Ñ€Ð° группы, чтобы проÑмотреть ÑпиÑок отноÑÑщихÑÑ Ðº ней запроÑов на ÑлиÑние, который вы затем Ñможете отфильтровать по проектам, меткам, Ñтапам и авторам."
@@ -23984,18 +24857,27 @@ msgstr ""
msgid "StaticSiteEditor|3. Assign a person to review and accept the merge request."
msgstr ""
+msgid "StaticSiteEditor|A link to view the merge request will appear once ready."
+msgstr ""
+
msgid "StaticSiteEditor|An error occurred while submitting your changes."
msgstr ""
msgid "StaticSiteEditor|Branch could not be created."
msgstr ""
+msgid "StaticSiteEditor|Copy update"
+msgstr ""
+
msgid "StaticSiteEditor|Could not commit the content changes."
msgstr "Ðевозможно зафикÑировать Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ ÐºÐ¾Ð½Ñ‚ÐµÐ½Ñ‚Ð°."
msgid "StaticSiteEditor|Could not create merge request."
msgstr ""
+msgid "StaticSiteEditor|Creating your merge request"
+msgstr ""
+
msgid "StaticSiteEditor|Incompatible file content"
msgstr ""
@@ -24017,6 +24899,9 @@ msgstr ""
msgid "StaticSiteEditor|View documentation"
msgstr ""
+msgid "StaticSiteEditor|You can set an assignee to get your changes reviewed and deployed once your merge request is created."
+msgstr ""
+
msgid "StaticSiteEditor|Your merge request has been created"
msgstr ""
@@ -24027,7 +24912,7 @@ msgid "Status"
msgstr "СтатуÑ"
msgid "Status:"
-msgstr ""
+msgstr "СтатуÑ:"
msgid "Status: %{title}"
msgstr ""
@@ -24146,15 +25031,15 @@ msgstr ""
msgid "Submit %{humanized_resource_name}"
msgstr ""
-msgid "Submit Changes"
-msgstr ""
-
msgid "Submit a review"
msgstr ""
msgid "Submit as spam"
msgstr ""
+msgid "Submit changes"
+msgstr ""
+
msgid "Submit feedback"
msgstr ""
@@ -24308,6 +25193,9 @@ msgstr ""
msgid "Successfully deleted U2F device."
msgstr "УÑтройÑтво U2F уÑпешно удалено."
+msgid "Successfully deleted WebAuthn device."
+msgstr ""
+
msgid "Successfully removed email."
msgstr "ÐÐ´Ñ€ÐµÑ Ñлектронной почты уÑпешно удален."
@@ -24417,7 +25305,7 @@ msgid "Suite"
msgstr ""
msgid "Summary"
-msgstr ""
+msgstr "Сводка"
msgid "Sunday"
msgstr "ВоÑкреÑенье"
@@ -24626,9 +25514,6 @@ msgstr "Шаблон"
msgid "Template to append to all Service Desk issues"
msgstr "Шаблон Ð´Ð»Ñ Ð´Ð¾Ð±Ð°Ð²Ð»ÐµÐ½Ð¸Ñ ÐºÐ¾ вÑем обÑуждениÑм Ñлужбы поддержки"
-msgid "Template was successfully saved."
-msgstr "Шаблон был уÑпешно Ñохранен."
-
msgid "Templates"
msgstr "Шаблоны"
@@ -24648,7 +25533,7 @@ msgid "TemporaryStorage|Temporarily increase storage now?"
msgstr ""
msgid "Terminal"
-msgstr ""
+msgstr "Терминал"
msgid "Terminal for environment"
msgstr "Терминал Ð´Ð»Ñ Ð¾ÐºÑ€ÑƒÐ¶ÐµÐ½Ð¸Ñ"
@@ -24713,11 +25598,29 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "Test failed."
-msgstr "ТеÑÑ‚ не пройден."
+msgid "Test settings"
+msgstr ""
+
+msgid "TestCases|New Test Case"
+msgstr ""
+
+msgid "TestCases|New test case"
+msgstr ""
+
+msgid "TestCases|Search test cases"
+msgstr ""
+
+msgid "TestCases|Something went wrong while creating a test case."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching count of test cases."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching test cases list."
+msgstr ""
-msgid "Test settings and save changes"
-msgstr "Проверьте наÑтройки и Ñохраните изменениÑ"
+msgid "TestCases|Submit test case"
+msgstr ""
msgid "TestHooks|Ensure one of your projects has merge requests."
msgstr "УбедитеÑÑŒ, что один из ваших проектов имеет запроÑÑ‹ на ÑлиÑние."
@@ -24782,6 +25685,9 @@ msgstr "ТеÑÑ‚Ñ‹"
msgid "Thank you for signing up for your free trial! You will get additional instructions in your inbox shortly."
msgstr "СпаÑибо, что подпиÑалиÑÑŒ на беÑплатный пробный период. Ð’Ñкоре мы отправим дополнительные инÑтрукции на ваш почтовый Ñщик."
+msgid "Thank you for your business."
+msgstr ""
+
msgid "Thank you for your feedback!"
msgstr ""
@@ -24843,9 +25749,6 @@ msgstr ""
msgid "The URL to use for connecting to Elasticsearch. Use a comma-separated list to support clustering (e.g., \"http://localhost:9200, http://localhost:9201\")."
msgstr "URL, иÑпользуемый Ð´Ð»Ñ Ð¿Ð¾Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ Ðº Elasticsearch. ИÑпользуйте ÑпиÑок разделÑемых запÑтыми адреÑов Ð´Ð»Ñ Ð¿Ð¾Ð´Ð´ÐµÑ€Ð¶ÐºÐ¸ клаÑтеризации (напр., \"http://localhost:9200, http://localhost:9201\")."
-msgid "The Web IDE offers advanced syntax highlighting capabilities and more."
-msgstr ""
-
msgid "The X509 Certificate to use when mutual TLS is required to communicate with the external authorization service. If left blank, the server certificate is still validated when accessing over HTTPS."
msgstr "Сертификат X509, иÑпользуемый в том Ñлучае, когда Ð´Ð»Ñ ÑвÑзи Ñ Ð²Ð½ÐµÑˆÐ½ÐµÐ¹ Ñлужбой авторизации требуетÑÑ Ð²Ð·Ð°Ð¸Ð¼Ð½Ð°Ñ Ð¿Ñ€Ð¾Ð²ÐµÑ€ÐºÐ° подлинноÑти TLS. ЕÑли оÑтавить пуÑтым, Ñертификат Ñервера вÑе еще будет проверÑÑ‚ÑŒÑÑ Ð¿Ñ€Ð¸ доÑтупе через HTTPS."
@@ -24958,6 +25861,9 @@ msgstr "СвÑзь Ñ Ð¾Ñ‚Ð²ÐµÑ‚Ð²Ð»ÐµÐ½Ð¸ÐµÐ¼ удалена."
msgid "The form contains the following error:"
msgstr ""
+msgid "The form contains the following warning:"
+msgstr ""
+
msgid "The global settings require you to enable Two-Factor Authentication for your account."
msgstr "Глобальные наÑтройки требуют, чтобы вы включили двухфакторную аутентификацию Ð´Ð»Ñ Ð²Ð°ÑˆÐµÐ¹ учетной запиÑи."
@@ -25072,9 +25978,6 @@ msgstr "Этап Ð¿Ð»Ð°Ð½Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¿Ð¾ÐºÐ°Ð·Ñ‹Ð²Ð°ÐµÑ‚ Ð²Ñ€ÐµÐ¼Ñ Ð¾Ñ‚ Ð
msgid "The private key to use when a client certificate is provided. This value is encrypted at rest."
msgstr "Закрытый ключ, иÑпользуемый при предоÑтавлении клиентÑкого Ñертификата. Он будет зашифрован в ÑоÑтоÑнии покоÑ."
-msgid "The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr "ПроизводÑтвенный Ñтап показывает общее Ð²Ñ€ÐµÐ¼Ñ Ð¼ÐµÐ¶Ð´Ñƒ Ñозданием обÑÑƒÐ¶Ð´ÐµÐ½Ð¸Ñ Ð¸ развертыванием кода в продуктивной Ñреде. Данные будут автоматичеÑки добавлены поÑле полного Ð·Ð°Ð²ÐµÑ€ÑˆÐµÐ½Ð¸Ñ Ð¸Ð´ÐµÐ¸."
-
msgid "The project can be accessed by any logged in user."
msgstr "ДоÑтуп к проекту возможен любым зарегиÑтрированным пользователем."
@@ -25111,8 +26014,8 @@ msgstr "Удаленное зеркалирование занÑло ÑлишкÐ
msgid "The remote repository is being updated..."
msgstr "Удаленный репозиторий обновлÑетÑÑ..."
-msgid "The repository can be commited to, and issues, comments and other entities can be created."
-msgstr "Ð’ репозиторий можно вноÑить коммиты, а также Ñоздавать в нём обÑуждениÑ, комментарии и прочие ÑущноÑти."
+msgid "The repository can be committed to, and issues, comments and other entities can be created."
+msgstr ""
msgid "The repository for this project does not exist."
msgstr "Репозиторий Ð´Ð»Ñ Ñтого проекта не ÑущеÑтвует."
@@ -25165,9 +26068,6 @@ msgstr "Этап теÑÑ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¿Ð¾ÐºÐ°Ð·Ñ‹Ð²Ð°ÐµÑ‚ времÑ, коÑ
msgid "The time taken by each data entry gathered by that stage."
msgstr "ВремÑ, затраченное каждым Ñлементом, Ñобранным на Ñтом Ñтапе."
-msgid "The total stage shows the time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The update action will time out after %{number_of_minutes} minutes. For big repositories, use a clone/push combination."
msgstr "Ð’Ñ€ÐµÐ¼Ñ Ð´ÐµÐ¹ÑÑ‚Ð²Ð¸Ñ Ð¾Ð±Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ Ð¸Ñтечет через %{number_of_minutes} минут. Ð”Ð»Ñ Ð±Ð¾Ð»ÑŒÑˆÐ¸Ñ… репозиториев иÑпользуйте комбинацию clone/push."
@@ -25231,6 +26131,9 @@ msgstr "Ðрхивных проектов пока нет"
msgid "There are no archived requirements"
msgstr "Ðет архивных требований"
+msgid "There are no archived test cases"
+msgstr ""
+
msgid "There are no changes"
msgstr ""
@@ -25270,6 +26173,9 @@ msgstr ""
msgid "There are no open requirements"
msgstr "Открытых требований нет"
+msgid "There are no open test cases"
+msgstr ""
+
msgid "There are no packages yet"
msgstr "Пакетов пока нет"
@@ -25282,6 +26188,9 @@ msgstr ""
msgid "There is a limit of %{ci_project_subscriptions_limit} subscriptions from or to a project."
msgstr ""
+msgid "There is already a To-Do for this design."
+msgstr ""
+
msgid "There is already a repository with that name on disk"
msgstr "Ðа диÑке уже еÑÑ‚ÑŒ репозиторий Ñ Ñ‚Ð°ÐºÐ¸Ð¼ именем"
@@ -25300,6 +26209,9 @@ msgstr ""
msgid "There was a problem communicating with your device."
msgstr "Произошла ошибка ÑÐ¾ÐµÐ´Ð¸Ð½ÐµÐ½Ð¸Ñ Ñ Ð²Ð°ÑˆÐ¸Ð¼ уÑтройÑтвом."
+msgid "There was a problem fetching branches."
+msgstr ""
+
msgid "There was a problem fetching groups."
msgstr ""
@@ -25528,9 +26440,15 @@ msgstr ""
msgid "This action can lead to data loss. To prevent accidental actions we ask you to confirm your intention."
msgstr "Это дейÑтвие может привеÑти к потере данных. Чтобы предотвратить Ñлучайные дейÑтвиÑ, мы проÑим Ð’Ð°Ñ Ð¿Ð¾Ð´Ñ‚Ð²ÐµÑ€Ð´Ð¸Ñ‚ÑŒ Ваше намерение."
+msgid "This action cannot be undone, and will permanently delete the %{key} SSH key"
+msgstr ""
+
msgid "This action cannot be undone. You will lose the project's repository and all content: issues, merge requests, etc."
msgstr ""
+msgid "This action has been performed too many times. Try again later."
+msgstr ""
+
msgid "This action will %{strongOpen}permanently delete%{strongClose} %{codeOpen}%{project}%{codeClose} %{strongOpen}immediately%{strongClose}, including its repositories and all content: issues, merge requests, etc."
msgstr ""
@@ -25558,9 +26476,6 @@ msgstr ""
msgid "This board's scope is reduced"
msgstr ""
-msgid "This branch has changed since you started editing. Would you like to create a new branch?"
-msgstr ""
-
msgid "This chart could not be displayed"
msgstr "Эта диаграмма не может быть отображена"
@@ -25687,15 +26602,9 @@ msgstr "Это ÑпиÑок уÑтройÑтв, c которых вошли в Ð
msgid "This is a security log of important events involving your account."
msgstr "Это журнал безопаÑноÑти важных Ñобытий, ÑвÑзанных Ñ Ð²Ð°ÑˆÐµÐ¹ учетной запиÑью."
-msgid "This is the author's first Merge Request to this project."
-msgstr "Это первый Ð—Ð°Ð¿Ñ€Ð¾Ñ Ð½Ð° ÑлиÑние от автора в Ñтот проект."
-
msgid "This is the highest peak of users on your installation since the license started."
msgstr ""
-msgid "This is the maximum number of users that have existed at the same time since the license started. This is the minimum number of seats you will need to buy when you renew your license."
-msgstr ""
-
msgid "This is the number of currently active users on your installation, and this is the minimum number you need to purchase when you renew your license."
msgstr ""
@@ -25865,7 +26774,7 @@ msgid "This project does not have a wiki homepage yet"
msgstr ""
msgid "This project has no active access tokens."
-msgstr ""
+msgstr "Ð’ Ñтом проекте нет активных токенов доÑтупа."
msgid "This project is archived and cannot be commented on."
msgstr ""
@@ -25927,6 +26836,15 @@ msgstr ""
msgid "This user has no identities"
msgstr ""
+msgid "This user has previously committed to the %{name} project."
+msgstr ""
+
+msgid "This user has the %{access} role in the %{name} project."
+msgstr ""
+
+msgid "This user is the author of this %{noteable}."
+msgstr ""
+
msgid "This user will be the author of all events in the activity feed that are the result of an update, like new branches being created or new commits being pushed to existing branches."
msgstr "Этот пользователь будет автором вÑех Ñобытий в ленте активноÑти, которые ÑвлÑÑŽÑ‚ÑÑ Ñ€ÐµÐ·ÑƒÐ»ÑŒÑ‚Ð°Ñ‚Ð¾Ð¼ обновлениÑ, например, Ñоздание новых веток или новые коммиты, отправлÑемые в ÑущеÑтвующие ветки."
@@ -25957,6 +26875,9 @@ msgstr ""
msgid "Threat Monitoring"
msgstr ""
+msgid "ThreatMonitoring|All Environments"
+msgstr ""
+
msgid "ThreatMonitoring|Anomalous Requests"
msgstr ""
@@ -25984,9 +26905,6 @@ msgstr ""
msgid "ThreatMonitoring|Operations Per Second"
msgstr ""
-msgid "ThreatMonitoring|Overview"
-msgstr ""
-
msgid "ThreatMonitoring|Packet Activity"
msgstr ""
@@ -26005,6 +26923,9 @@ msgstr ""
msgid "ThreatMonitoring|Something went wrong, unable to fetch statistics"
msgstr ""
+msgid "ThreatMonitoring|Statistics"
+msgstr ""
+
msgid "ThreatMonitoring|The firewall is not installed or has been disabled. To view this data, ensure the web application firewall is installed and enabled for your cluster."
msgstr ""
@@ -26045,7 +26966,7 @@ msgid "Thursday"
msgstr "Четверг"
msgid "Time"
-msgstr ""
+msgstr "ВремÑ"
msgid "Time based: Yes"
msgstr "Time based: Да"
@@ -26278,7 +27199,7 @@ msgid "Titles and Descriptions"
msgstr ""
msgid "To"
-msgstr ""
+msgstr "Ð’"
msgid "To %{link_to_help} of your domain, add the above key to a TXT record within to your DNS configuration."
msgstr ""
@@ -26400,6 +27321,9 @@ msgstr ""
msgid "To update Snippets with multiple files, you must use the `files` parameter"
msgstr ""
+msgid "To use Gitpod you must first enable the feature in the integrations section of your %{user_prefs}."
+msgstr ""
+
msgid "To view all %{scannedResourcesCount} scanned URLs, please download the CSV file"
msgstr ""
@@ -26433,9 +27357,6 @@ msgstr "Переключить предварительный проÑмотр M
msgid "Toggle Sidebar"
msgstr ""
-msgid "Toggle all threads"
-msgstr ""
-
msgid "Toggle backtrace"
msgstr ""
@@ -26460,9 +27381,6 @@ msgstr ""
msgid "Toggle navigation"
msgstr ""
-msgid "Toggle project"
-msgstr ""
-
msgid "Toggle sidebar"
msgstr "Переключить боковую панель"
@@ -26502,11 +27420,14 @@ msgstr "Слишком много проÑтранÑтв имен включен
msgid "Too many projects enabled. You will need to manage them via the console or the API."
msgstr "Слишком много проектов включено. Ð”Ð»Ñ ÑƒÐ¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ð¸Ð¼Ð¸ вам потребуетÑÑ ÐºÐ¾Ð½Ñоль или API."
+msgid "Too much data"
+msgstr ""
+
msgid "Topics (optional)"
msgstr "Темы (необÑзательно)"
msgid "Total"
-msgstr ""
+msgstr "Ð’Ñего"
msgid "Total Contributions"
msgstr "Общий вклад"
@@ -26520,6 +27441,9 @@ msgstr "Общий размер артефактов: %{total_size}"
msgid "Total cores (CPUs)"
msgstr ""
+msgid "Total days to completion"
+msgstr ""
+
msgid "Total issues"
msgstr ""
@@ -26616,6 +27540,9 @@ msgstr ""
msgid "Trending"
msgstr "ПопулÑрные"
+msgid "Trials|Create a new group to start your GitLab Gold trial."
+msgstr ""
+
msgid "Trials|Go back to GitLab"
msgstr ""
@@ -26625,6 +27552,15 @@ msgstr ""
msgid "Trials|You can always resume this process by selecting your avatar and choosing 'Start a Gold trial'"
msgstr "Ð’Ñ‹ вÑегда можете продолжить Ñтот процеÑÑ, нажав на Ñвой аватар и выбрав \"Ðачать пробный период Gold\""
+msgid "Trials|You can apply your trial to a new group or an existing group."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group or your personal account."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group, an existing group, or your personal account."
+msgstr ""
+
msgid "Trials|You won't get a free trial right now but you can always resume this process by clicking on your avatar and choosing 'Start a free trial'"
msgstr "Ð’Ñ‹ не получите беÑплатный пробный период прÑмо ÑейчаÑ, но вы вÑегда можете продолжить Ñтот процеÑÑ, нажав на Ñвой аватар и выбрав \"Ðачать беÑплатный пробный период\""
@@ -26694,6 +27630,9 @@ msgstr ""
msgid "Try using a different search term to find the file you are looking for."
msgstr "Попробуйте изменить поиÑковый запроÑ, чтобы найти нужный файл."
+msgid "Trying to communicate with your device. Plug it in (if needed) and press the button on the device now."
+msgstr ""
+
msgid "Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now."
msgstr ""
@@ -26719,7 +27658,7 @@ msgid "Turn on usage ping to review instance-level analytics."
msgstr ""
msgid "Twitter"
-msgstr ""
+msgstr "Twitter"
msgid "Two-Factor Authentication"
msgstr "Ð”Ð²ÑƒÑ…Ñ„Ð°ÐºÑ‚Ð¾Ñ€Ð½Ð°Ñ Ð°ÑƒÑ‚ÐµÐ½Ñ‚Ð¸Ñ„Ð¸ÐºÐ°Ñ†Ð¸Ñ"
@@ -26752,7 +27691,7 @@ msgid "Two-factor authentication is not enabled for this user"
msgstr ""
msgid "Type"
-msgstr ""
+msgstr "Тип"
msgid "Type/State"
msgstr ""
@@ -26781,9 +27720,15 @@ msgstr "URL внешнего хранилища, которое будет обÑ
msgid "URL or request ID"
msgstr ""
-msgid "UTC"
+msgid "USER %{user} WILL BE REMOVED! Are you sure?"
msgstr ""
+msgid "USER WILL BE BLOCKED! Are you sure?"
+msgstr ""
+
+msgid "UTC"
+msgstr "UTC"
+
msgid "Unable to apply suggestions to a deleted line."
msgstr ""
@@ -26838,9 +27783,6 @@ msgstr "Ðе удаетÑÑ Ð·Ð°Ð³Ñ€ÑƒÐ·Ð¸Ñ‚ÑŒ отличиÑ. %{button_try_agai
msgid "Unable to load the merge request widget. Try reloading the page."
msgstr ""
-msgid "Unable to resolve"
-msgstr "Ðевозможно решить"
-
msgid "Unable to save iteration. Please try again"
msgstr ""
@@ -26881,7 +27823,7 @@ msgid "Unblock"
msgstr ""
msgid "Undo"
-msgstr ""
+msgstr "Отменить"
msgid "Undo Ignore"
msgstr ""
@@ -26889,6 +27831,9 @@ msgstr ""
msgid "Undo ignore"
msgstr ""
+msgid "Unexpected error"
+msgstr ""
+
msgid "Unfortunately, your email message to GitLab could not be processed."
msgstr "К Ñожалению, ваше пиÑьмо в GitLab не может быть обработано."
@@ -26922,6 +27867,9 @@ msgstr ""
msgid "Unknown response text"
msgstr "ÐеизвеÑтный текÑÑ‚ ответа"
+msgid "Unless otherwise agreed to in writing with GitLab, by clicking \"Upload License\" you agree that your use of GitLab Software is subject to the %{eula_link_start}Terms of Service%{eula_link_end}."
+msgstr ""
+
msgid "Unlimited"
msgstr ""
@@ -27019,7 +27967,7 @@ msgid "Unsupported todo type passed. Supported todo types are: %{todo_types}"
msgstr ""
msgid "Until"
-msgstr ""
+msgstr "До"
msgid "Unused, previous index '%{index_name}' will be deleted after %{time} automatically."
msgstr ""
@@ -27058,7 +28006,7 @@ msgid "Update failed. Please try again."
msgstr "Обновление не удалоÑÑŒ. Попробуйте ещё раз."
msgid "Update it"
-msgstr ""
+msgstr "Обновить Ñто"
msgid "Update iteration"
msgstr ""
@@ -27274,7 +28222,7 @@ msgid "UsageQuota|Wiki"
msgstr "Wiki"
msgid "UsageQuota|Wikis"
-msgstr ""
+msgstr "Вики"
msgid "UsageQuota|You used: %{usage} %{limit}"
msgstr ""
@@ -27288,9 +28236,6 @@ msgstr "ИÑпользуйте %{code_start}::%{code_end}, чтобы Ñозда
msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
msgstr ""
-msgid "Use a hardware device to add the second factor of authentication."
-msgstr "ИÑпользуйте аппаратное уÑтройÑтво, чтобы добавить второй фактор аутентификации."
-
msgid "Use an one time password authenticator on your mobile device or computer to enable two-factor authentication (2FA)."
msgstr "ИÑпользуйте одноразовый аутентификатор Ð¿Ð°Ñ€Ð¾Ð»Ñ Ð½Ð° вашем мобильном уÑтройÑтве или компьютере, чтобы включить двухфакторную аутентификацию (2FA)."
@@ -27564,15 +28509,15 @@ msgstr "Ð˜Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Ð¸Ð»Ð¸ email"
msgid "Users"
msgstr "Пользователи"
+msgid "Users in License"
+msgstr ""
+
msgid "Users in License:"
msgstr ""
msgid "Users or groups set as approvers in the project's or merge request's settings."
msgstr "Пользователи или группы, назначенные утверждающими в наÑтройках проекта или запроÑа на ÑлиÑние."
-msgid "Users outside of license"
-msgstr ""
-
msgid "Users over License:"
msgstr ""
@@ -27588,9 +28533,6 @@ msgstr "Пользователи были уÑпешно добавлены."
msgid "Users with a Guest role or those who don't belong to a Project or Group will not use a seat from your license."
msgstr ""
-msgid "Users with a Guest role or those who don't belong to any projects or groups don't count towards seats in use."
-msgstr ""
-
msgid "UsersSelect|%{name} + %{length} more"
msgstr "еще %{name} + %{length}"
@@ -27630,9 +28572,6 @@ msgstr ""
msgid "Validations failed."
msgstr ""
-msgid "Validity"
-msgstr ""
-
msgid "Value"
msgstr ""
@@ -27651,6 +28590,9 @@ msgstr ""
msgid "Value Stream Name"
msgstr ""
+msgid "ValueStreamAnalyticsStage|We don't have enough data to show this stage."
+msgstr ""
+
msgid "ValueStreamAnalytics|%{days}d"
msgstr ""
@@ -27722,10 +28664,10 @@ msgstr ""
msgid "View chart"
msgid_plural "View charts"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
+msgstr[0] "Показать график"
+msgstr[1] "Показать графики"
+msgstr[2] "Показать графики"
+msgstr[3] "Показать графики"
msgid "View dependency details for your project"
msgstr ""
@@ -27911,6 +28853,9 @@ msgstr ""
msgid "VisualReviewApp|Steps 1 and 2 (and sometimes 3) are performed once by the developer before requesting feedback. Steps 3 (if necessary), 4 is performed by the reviewer each time they perform a review."
msgstr ""
+msgid "Visualization"
+msgstr ""
+
msgid "Vulnerabilities"
msgstr ""
@@ -27938,34 +28883,31 @@ msgstr ""
msgid "VulnerabilityChart|Severity"
msgstr "СерьёзноÑÑ‚ÑŒ"
-msgid "VulnerabilityManagement|A true-positive and will fix"
-msgstr ""
-
-msgid "VulnerabilityManagement|Change status"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Confirm"
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|Confirmed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Detected %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|A true-positive and will fix"
msgstr ""
-msgid "VulnerabilityManagement|Dismiss"
+msgid "VulnerabilityManagement|Change status"
msgstr ""
-msgid "VulnerabilityManagement|Dismissed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
msgstr ""
-msgid "VulnerabilityManagement|Resolved"
+msgid "VulnerabilityManagement|Detected"
msgstr ""
-msgid "VulnerabilityManagement|Resolved %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Needs triage"
msgstr ""
msgid "VulnerabilityManagement|Something went wrong while trying to delete the comment. Please try again later."
@@ -28016,6 +28958,9 @@ msgstr ""
msgid "Vulnerability|%{scannerName} (version %{scannerVersion})"
msgstr ""
+msgid "Vulnerability|Activity"
+msgstr ""
+
msgid "Vulnerability|Class"
msgstr ""
@@ -28028,6 +28973,9 @@ msgstr ""
msgid "Vulnerability|Description"
msgstr "ОпиÑание"
+msgid "Vulnerability|Detected"
+msgstr ""
+
msgid "Vulnerability|Evidence"
msgstr ""
@@ -28091,6 +29039,9 @@ msgstr "Предупреждение:"
msgid "Warning: Displaying this diagram might cause performance issues on this page."
msgstr ""
+msgid "We are currently unable to fetch data for the pipeline header."
+msgstr ""
+
msgid "We are currently unable to fetch data for this graph."
msgstr ""
@@ -28130,6 +29081,12 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr "Мы хотим быть уверены, что Ñто вы, пожалуйÑта, подтвердите, что вы не робот."
+msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
+msgstr ""
+
+msgid "We would like to inform you that your subscription GitLab Enterprise Edition %{plan_name} is nearing its user limit. You have %{active_user_count} active users, which is almost at the user limit of %{maximum_user_count}."
+msgstr ""
+
msgid "We've found no vulnerabilities"
msgstr ""
@@ -28145,6 +29102,12 @@ msgstr ""
msgid "Web terminal"
msgstr "Web терминал"
+msgid "WebAuthn Devices (%{length})"
+msgstr ""
+
+msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
+msgstr ""
+
msgid "WebIDE|Merge request"
msgstr "Ð—Ð°Ð¿Ñ€Ð¾Ñ Ð½Ð° ÑлиÑние"
@@ -28283,15 +29246,9 @@ msgstr ""
msgid "Welcome to the guided GitLab tour"
msgstr ""
-msgid "Welcome to your Issue Board!"
-msgstr ""
-
msgid "Welcome to your issue board!"
msgstr ""
-msgid "We’ve been making changes to %{featureName} and we’d love your feedback %{linkStart}in this issue%{linkEnd} to help us improve the experience."
-msgstr ""
-
msgid "What are you searching for?"
msgstr ""
@@ -28310,6 +29267,9 @@ msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
msgstr "Когда процеÑÑ Runner заблокирован, он не может быть назначен другим проектам"
+msgid "When enabled, any user visiting %{host} and creating an account will have to be explicitly approved by the admin before they can login. This setting is effective only if sign-ups are enabled."
+msgstr ""
+
msgid "When enabled, any user visiting %{host} will be able to create an account."
msgstr ""
@@ -28426,7 +29386,7 @@ msgid "WikiEmpty|This group has no wiki pages"
msgstr ""
msgid "WikiEmpty|This project has no wiki pages"
-msgstr ""
+msgstr "Ð’ Ñтом проекте нет вики-Ñтраниц"
msgid "WikiEmpty|You must be a group member in order to add wiki pages."
msgstr ""
@@ -28522,7 +29482,7 @@ msgid "Wiki|View All Pages"
msgstr ""
msgid "Wiki|Wiki Pages"
-msgstr "Страницы Wiki"
+msgstr "Вики-Ñтраницы"
msgid "Will be created"
msgstr ""
@@ -28536,6 +29496,9 @@ msgstr ""
msgid "With requirements, you can set criteria to check your products against."
msgstr ""
+msgid "With test cases, you can define conditions for your project to meet in determining quality"
+msgstr ""
+
msgid "Withdraw Access Request"
msgstr "Отменить Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð´Ð¾Ñтупа"
@@ -28551,6 +29514,9 @@ msgstr ""
msgid "Workflow Help"
msgstr ""
+msgid "Would you like to create a new branch?"
+msgstr ""
+
msgid "Write"
msgstr "Правка"
@@ -28572,11 +29538,14 @@ msgstr "Ðапишите Ñвои заметки к релизу или пере
msgid "Wrong extern UID provided. Make sure Auth0 is configured correctly."
msgstr ""
+msgid "YYYY-MM-DD"
+msgstr ""
+
msgid "Yes"
msgstr "Да"
msgid "Yes or No"
-msgstr ""
+msgstr "Да или нет"
msgid "Yes, add it"
msgstr "Да, добавить"
@@ -28624,13 +29593,13 @@ msgid "You are going to delete %{project_full_name}. Deleted projects CANNOT be
msgstr ""
msgid "You are going to remove %{group_name}, this will also delete all of its subgroups and projects. Removed groups CANNOT be restored! Are you ABSOLUTELY sure?"
-msgstr ""
+msgstr "Ð’Ñ‹ ÑобираетеÑÑŒ удалить %{group_name}, Ñто приведет к удалению вÑех подгруппи проектов. Удаленные группы ÐЕ МОГУТ быть воÑÑтановлены! Ð’Ñ‹ ТОЧÐО уверены?"
msgid "You are going to remove the fork relationship from %{project_full_name}. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "You are going to transfer %{project_full_name} to another owner. Are you ABSOLUTELY sure?"
-msgstr "Ð’Ñ‹ ÑобираетеÑÑŒ передать проект %{project_full_name} другому владельцу. Ð’Ñ‹ ÐБСОЛЮТÐО уверены?"
+msgid "You are going to transfer %{project_full_name} to another namespace. Are you ABSOLUTELY sure?"
+msgstr ""
msgid "You are going to turn off the confidentiality. This means %{strongStart}everyone%{strongEnd} will be able to see and leave a comment on this %{issuableType}."
msgstr ""
@@ -28689,9 +29658,6 @@ msgstr "Ð’Ñ‹ также можете загрузить ÑущеÑтвующие
msgid "You can always edit this later"
msgstr ""
-msgid "You can apply your Trial to your Personal account or create a New Group."
-msgstr ""
-
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings"
msgstr ""
@@ -28713,12 +29679,18 @@ msgstr "Ð’Ñ‹ можете легко уÑтановить Runner в клаÑте
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
+msgid "You can find more information about GitLab subscriptions in %{subscriptions_doc_link}."
+msgstr ""
+
msgid "You can generate an access token scoped to this project for each application to use the GitLab API."
msgstr ""
msgid "You can get started by cloning the repository or start adding files to it with one of the following options."
msgstr "Ð’Ñ‹ можете начать Ñ ÐºÐ»Ð¾Ð½Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ñ€ÐµÐ¿Ð¾Ð·Ð¸Ñ‚Ð¾Ñ€Ð¸Ñ Ð¸Ð»Ð¸ Ð´Ð¾Ð±Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ñ„Ð°Ð¹Ð»Ð¾Ð² в него одним из Ñледующих ÑпоÑобов."
+msgid "You can group test cases using labels. To learn about the future direction of this feature, visit %{linkStart}Quality Management direction page%{linkEnd}."
+msgstr ""
+
msgid "You can invite a new member to %{project_name} or invite another group."
msgstr ""
@@ -28734,6 +29706,9 @@ msgstr "Ð’Ñ‹ можете перемещатьÑÑ Ð¿Ð¾ диаграмме Ñ Ð¿
msgid "You can notify the app / group or a project by sending them an email notification"
msgstr ""
+msgid "You can now close this window."
+msgstr ""
+
msgid "You can now export your security dashboard to a CSV report."
msgstr ""
@@ -28782,9 +29757,6 @@ msgstr "Ð’Ñ‹ можете указать уровень уведомлений Ð
msgid "You can test your .gitlab-ci.yml in %{linkStart}CI Lint%{linkEnd}."
msgstr "Ð’Ñ‹ можете протеÑтировать Ñвой файл .gitlab-ci.yml Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ %{linkStart}CI Lint%{linkEnd}."
-msgid "You can try again using %{begin_link}basic search%{end_link}"
-msgstr ""
-
msgid "You cannot access the raw file. Please wait a minute."
msgstr ""
@@ -28836,6 +29808,9 @@ msgstr "У Ð²Ð°Ñ Ð½ÐµÑ‚ необходимых прав Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÐ¾Ð¿Ñ€Ðµ
msgid "You don't have any U2F devices registered yet."
msgstr "У Ð²Ð°Ñ ÐµÑ‰Ñ‘ нет зарегиÑтрированных уÑтройÑтв U2F."
+msgid "You don't have any WebAuthn devices registered yet."
+msgstr ""
+
msgid "You don't have any active chat names."
msgstr "У Ð²Ð°Ñ Ð½ÐµÑ‚ активных имен в чатах."
@@ -28923,6 +29898,9 @@ msgstr "Теперь вы можете закрыть Ñтап."
msgid "You must accept our Terms of Service and privacy policy in order to register an account"
msgstr ""
+msgid "You must be logged in to search across all of GitLab"
+msgstr ""
+
msgid "You must disassociate %{domain} from all clusters it is attached to before deletion."
msgstr ""
@@ -28962,8 +29940,8 @@ msgstr "Вам нужно разрешение."
msgid "You need to be logged in."
msgstr "Вы должны быть авторизованы."
-msgid "You need to register a two-factor authentication app before you can set up a U2F device."
-msgstr "Вам необходимо зарегиÑтрировать приложение Ð´Ð»Ñ Ð´Ð²ÑƒÑ…Ñ„Ð°ÐºÑ‚Ð¾Ñ€Ð½Ð¾Ð¹ аутентификации, прежде чем вы Ñможете наÑтроить уÑтройÑтво U2F."
+msgid "You need to register a two-factor authentication app before you can set up a device."
+msgstr ""
msgid "You need to set terms to be enforced"
msgstr ""
@@ -28980,6 +29958,9 @@ msgstr ""
msgid "You reached %{usage_in_percent} of %{namespace_name}'s storage capacity (%{used_storage} of %{storage_limit})"
msgstr ""
+msgid "You successfully declined the invitation"
+msgstr ""
+
msgid "You tried to fork %{link_to_the_project} but it failed for the following reason:"
msgstr ""
@@ -29145,12 +30126,15 @@ msgstr ""
msgid "Your U2F device did not send a valid JSON response."
msgstr ""
-msgid "Your U2F device needs to be set up. Plug it in (if not already) and click the button on the left."
-msgstr ""
-
msgid "Your U2F device was registered!"
msgstr "Ваше уÑтройÑтво U2F зарегиÑтрировано!"
+msgid "Your WebAuthn device did not send a valid JSON response."
+msgstr ""
+
+msgid "Your WebAuthn device was registered!"
+msgstr ""
+
msgid "Your access request to the %{source_type} has been withdrawn."
msgstr "Ваш Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð´Ð¾Ñтупа к %{source_type} был отозван."
@@ -29172,6 +30156,9 @@ msgstr ""
msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
msgstr "Ваш браузер не поддерживает U2F. ПожалуйÑта, иÑпользуйте Google Chrome Desktop (верÑÐ¸Ñ 41 или новее)."
+msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
+msgstr ""
+
msgid "Your changes can be committed to %{branch_name} because a merge request is open."
msgstr "Ваши Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð³ÑƒÑ‚ быть зафикÑированы в ветке %{branch_name}, так как открыт Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð½Ð° ÑлиÑние."
@@ -29208,6 +30195,12 @@ msgstr "Ваша панель ÑƒÐ¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ð±Ñ‹Ð»Ð° обновлена.
msgid "Your deployment services will be broken, you will need to manually fix the services after renaming."
msgstr "Ваши Ñлужбы Ñ€Ð°Ð·Ð²Ñ‘Ñ€Ñ‚Ñ‹Ð²Ð°Ð½Ð¸Ñ ÑломаютÑÑ, и вам нужно будет вручную иÑправить Ñлужбы поÑле переименованиÑ."
+msgid "Your device is not compatible with GitLab. Please try another device"
+msgstr ""
+
+msgid "Your device needs to be set up. Plug it in (if needed) and click the button on the left."
+msgstr ""
+
msgid "Your device was successfully set up! Give it a name and register it with the GitLab server."
msgstr "Ваше уÑтройÑтво было уÑпешно наÑтроено! Дайте ему Ð¸Ð¼Ñ Ð¸ зарегиÑтрируйте его на Ñервере GitLab."
@@ -29315,17 +30308,14 @@ msgstr ""
msgid "about 1 hour"
msgid_plural "about %d hours"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
+msgstr[0] "примерно чаÑ"
+msgstr[1] "примерно %d чаÑа"
+msgstr[2] "примерно %d чаÑов"
+msgstr[3] "примерно %d чаÑов"
msgid "access:"
msgstr ""
-msgid "activated"
-msgstr ""
-
msgid "added %{created_at_timeago}"
msgstr "добавлено %{created_at_timeago}"
@@ -29354,7 +30344,7 @@ msgid "among other things"
msgstr "читать документацию"
msgid "and"
-msgstr ""
+msgstr "и"
msgid "any-approver for the merge request already exists"
msgstr "утверждающий Ð´Ð»Ñ Ñтого запроÑа на ÑлиÑние уже ÑущеÑтвует"
@@ -29393,14 +30383,26 @@ msgid "branch name"
msgstr "Ð¸Ð¼Ñ Ð²ÐµÑ‚Ð²Ð¸"
msgid "by"
-msgstr ""
+msgstr "по"
msgid "by %{user}"
+msgstr "от %{user}"
+
+msgid "cannot be a date in the past"
msgstr ""
msgid "cannot be changed if a personal project has container registry tags."
msgstr "невозможно изменить, еÑли в личном проекте еÑÑ‚ÑŒ метки рееÑтра контейнеров."
+msgid "cannot be changed if shared runners are enabled"
+msgstr ""
+
+msgid "cannot be enabled because parent group does not allow it"
+msgstr ""
+
+msgid "cannot be enabled because parent group has shared Runners disabled"
+msgstr ""
+
msgid "cannot be enabled unless all domains have TLS certificates"
msgstr "невозможно включить, еÑли вÑе домены не имеют Ñертификата TLS"
@@ -29446,7 +30448,7 @@ msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about SAST %{linkEndTag}"
msgstr ""
-msgid "ciReport|%{linkStartTag}Learn more about Secret Scanning %{linkEndTag}"
+msgid "ciReport|%{linkStartTag}Learn more about Secret Detection %{linkEndTag}"
msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about codequality reports %{linkEndTag}"
@@ -29682,7 +30684,7 @@ msgid "customize"
msgstr ""
msgid "data"
-msgstr ""
+msgstr "данные"
msgid "date must not be after 9999-12-31"
msgstr ""
@@ -29698,7 +30700,7 @@ msgid "default branch"
msgstr ""
msgid "deleted"
-msgstr ""
+msgstr "удалено"
msgid "deploy"
msgstr "развернуть"
@@ -29722,7 +30724,7 @@ msgid "does not have a supported extension. Only %{extension_list} are supported
msgstr ""
msgid "done"
-msgstr ""
+msgstr "готово"
msgid "download it"
msgstr ""
@@ -29762,13 +30764,10 @@ msgid "entries cannot contain HTML tags"
msgstr ""
msgid "epic"
-msgstr ""
+msgstr "цель"
msgid "error"
-msgstr ""
-
-msgid "error code:"
-msgstr ""
+msgstr "ошибка"
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr "%{slash_command} обновит раÑчетное Ð²Ñ€ÐµÐ¼Ñ Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ поÑледней команды."
@@ -29791,6 +30790,9 @@ msgstr "не удалоÑÑŒ"
msgid "failed to dismiss associated finding(id=%{finding_id}): %{message}"
msgstr ""
+msgid "failed to revert associated finding(id=%{finding_id}) to detected"
+msgstr ""
+
msgid "file"
msgid_plural "files"
msgstr[0] "файл"
@@ -29820,7 +30822,7 @@ msgid "fork this project"
msgstr ""
msgid "from"
-msgstr ""
+msgstr "от"
msgid "from %d job"
msgid_plural "from %d jobs"
@@ -29830,7 +30832,7 @@ msgstr[2] ""
msgstr[3] ""
msgid "group"
-msgstr ""
+msgstr "группа"
msgid "group members"
msgstr ""
@@ -29848,7 +30850,7 @@ msgid "help"
msgstr "помощь"
msgid "http:"
-msgstr ""
+msgstr "http:"
msgid "https://your-bitbucket-server"
msgstr "https://ваш-bitbucket-server"
@@ -29885,7 +30887,7 @@ msgid "invalid milestone state `%{state}`"
msgstr "неверное ÑоÑтоÑние Ñтапа `%{state}`"
msgid "is"
-msgstr ""
+msgstr "ÑвлÑетÑÑ"
msgid "is already associated to a GitLab Issue. New issue will not be associated."
msgstr ""
@@ -30341,6 +31343,9 @@ msgstr ""
msgid "must be a root namespace"
msgstr ""
+msgid "must be a valid IPv4 or IPv6 address"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -30377,6 +31382,9 @@ msgstr "не учаÑтвовали"
msgid "no expiration"
msgstr ""
+msgid "no name set"
+msgstr ""
+
msgid "no one can merge"
msgstr ""
@@ -30446,7 +31454,7 @@ msgid "pending removal"
msgstr ""
msgid "per day"
-msgstr ""
+msgstr "в день"
msgid "personal access token"
msgstr ""
@@ -30455,7 +31463,7 @@ msgid "personal access tokens"
msgstr ""
msgid "pipeline"
-msgstr ""
+msgstr "ÑÐ±Ð¾Ñ€Ð¾Ñ‡Ð½Ð°Ñ Ð»Ð¸Ð½Ð¸Ñ"
msgid "pod_name can contain only lowercase letters, digits, '-', and '.' and must start and end with an alphanumeric character"
msgstr ""
@@ -30529,7 +31537,7 @@ msgid "remaining"
msgstr "оÑталоÑÑŒ"
msgid "remove"
-msgstr ""
+msgstr "удалить"
msgid "remove due date"
msgstr "удалить дату завершениÑ"
@@ -30551,7 +31559,7 @@ msgstr[2] "ответов"
msgstr[3] "ответов"
msgid "repository:"
-msgstr ""
+msgstr "репозиторий:"
msgid "reset it."
msgstr "ÑброÑить."
@@ -30565,9 +31573,6 @@ msgstr ""
msgid "security Reports|There was an error creating the merge request"
msgstr ""
-msgid "settings saved, but not activated"
-msgstr "наÑтройки Ñохранены, но не применены"
-
msgid "severity|Critical"
msgstr "КритичеÑкий"
@@ -30626,7 +31631,7 @@ msgid "spendCommand|%{slash_command} will update the sum of the time spent."
msgstr "%{slash_command} обновит Ñумму потраченного времени."
msgid "ssh:"
-msgstr ""
+msgstr "ssh:"
msgid "started"
msgstr "запущено"
@@ -30694,9 +31699,6 @@ msgstr "к ÑпиÑку"
msgid "toggle collapse"
msgstr "Ñвернуть/развернуть"
-msgid "toggle dropdown"
-msgstr ""
-
msgid "triggered"
msgstr "запущено"
@@ -30724,6 +31726,9 @@ msgstr ""
msgid "user avatar"
msgstr "аватар пользователÑ"
+msgid "user preferences"
+msgstr ""
+
msgid "username"
msgstr "Ð¸Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ"
diff --git a/locale/si_LK/gitlab.po b/locale/si_LK/gitlab.po
index 19b82c10987..46cded55d06 100644
--- a/locale/si_LK/gitlab.po
+++ b/locale/si_LK/gitlab.po
@@ -14,7 +14,10 @@ msgstr ""
"X-Crowdin-Language: si-LK\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 6\n"
-"PO-Revision-Date: 2020-09-04 23:04\n"
+"PO-Revision-Date: 2020-10-02 18:43\n"
+
+msgid " %{project_name}#%{issue_iid} &middot; opened %{issue_created} by %{author}"
+msgstr ""
msgid " %{start} to %{end}"
msgstr ""
@@ -74,6 +77,16 @@ msgstr ""
msgid "\"el\" parameter is required for createInstance()"
msgstr ""
+msgid "%d Approval"
+msgid_plural "%d Approvals"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d Package"
+msgid_plural "%d Packages"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d Scanned URL"
msgid_plural "%d Scanned URLs"
msgstr[0] ""
@@ -137,6 +150,11 @@ msgstr[1] ""
msgid "%d commits"
msgstr ""
+msgid "%d completed issue"
+msgid_plural "%d completed issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d contribution"
msgid_plural "%d contributions"
msgstr[0] ""
@@ -147,6 +165,11 @@ msgid_plural "%d days"
msgstr[0] ""
msgstr[1] ""
+msgid "%d day until tags are automatically removed"
+msgid_plural "%d days until tags are automatically removed"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d error"
msgid_plural "%d errors"
msgstr[0] ""
@@ -237,6 +260,16 @@ msgid_plural "%d more comments"
msgstr[0] ""
msgstr[1] ""
+msgid "%d open issue"
+msgid_plural "%d open issues"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d pending comment"
+msgid_plural "%d pending comments"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d personal project will be removed and cannot be restored."
msgid_plural "%d personal projects will be removed and cannot be restored."
msgstr[0] ""
@@ -252,6 +285,11 @@ msgid_plural "%d projects"
msgstr[0] ""
msgstr[1] ""
+msgid "%d project selected"
+msgid_plural "%d projects selected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d request with warnings"
msgid_plural "%d requests with warnings"
msgstr[0] ""
@@ -272,6 +310,11 @@ msgid_plural "%d tags"
msgstr[0] ""
msgstr[1] ""
+msgid "%d tag per image name"
+msgid_plural "%d tags per image name"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d unassigned issue"
msgid_plural "%d unassigned issues"
msgstr[0] ""
@@ -292,6 +335,11 @@ msgid_plural "%d vulnerabilities dismissed"
msgstr[0] ""
msgstr[1] ""
+msgid "%d warning found:"
+msgid_plural "%d warnings found:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%s additional commit has been omitted to prevent performance issues."
msgid_plural "%s additional commits have been omitted to prevent performance issues."
msgstr[0] ""
@@ -330,6 +378,9 @@ msgstr ""
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr ""
+msgid "%{completedCount} completed weight"
+msgstr ""
+
msgid "%{completedWeight} of %{totalWeight} weight completed"
msgstr ""
@@ -378,14 +429,12 @@ msgid_plural "%{count} participants"
msgstr[0] ""
msgstr[1] ""
-msgid "%{count} pending comment"
-msgid_plural "%{count} pending comments"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
+msgid "%{count} total weight"
+msgstr ""
+
msgid "%{dashboard_path} could not be found."
msgstr ""
@@ -440,6 +489,9 @@ msgstr ""
msgid "%{group_name} uses group managed accounts. You need to create a new GitLab account which will be managed by %{group_name}."
msgstr ""
+msgid "%{group_name}&%{epic_iid} &middot; opened %{epic_created} by %{author}"
+msgstr ""
+
msgid "%{host} sign-in from new location"
msgstr ""
@@ -452,7 +504,7 @@ msgstr ""
msgid "%{issuableType} will be removed! Are you sure?"
msgstr ""
-msgid "%{issuesSize} issues with a limit of %{maxIssueCount}"
+msgid "%{issuesCount} issues with a limit of %{maxIssueCount}"
msgstr ""
msgid "%{issuesSize} with a limit of %{maxIssueCount}"
@@ -485,7 +537,7 @@ msgstr ""
msgid "%{labelStart}Namespace:%{labelEnd} %{namespace}"
msgstr ""
-msgid "%{labelStart}Report Type:%{labelEnd} %{reportType}"
+msgid "%{labelStart}Scan Type:%{labelEnd} %{reportType}"
msgstr ""
msgid "%{labelStart}Scanner:%{labelEnd} %{scanner}"
@@ -682,9 +734,6 @@ msgid_plural "%{securityScanner} results are not available because a pipeline ha
msgstr[0] ""
msgstr[1] ""
-msgid "%{service_title} %{message}."
-msgstr ""
-
msgid "%{size} GiB"
msgstr ""
@@ -773,6 +822,12 @@ msgstr ""
msgid "%{timebox_name} should belong either to a project or a group."
msgstr ""
+msgid "%{timebox_type} does not support burnup charts"
+msgstr ""
+
+msgid "%{timebox_type} must have a start and due date"
+msgstr ""
+
msgid "%{title} %{operator} %{threshold}"
msgstr ""
@@ -797,7 +852,7 @@ msgstr ""
msgid "%{total} open issue weight"
msgstr ""
-msgid "%{total} open issues"
+msgid "%{total} warnings found: showing first %{warningsDisplayed}"
msgstr ""
msgid "%{usage_ping_link_start}Learn more%{usage_ping_link_end} about what information is shared with GitLab Inc."
@@ -830,9 +885,6 @@ msgstr ""
msgid "&lt; 1 hour"
msgstr ""
-msgid "&lt;no name set&gt;"
-msgstr ""
-
msgid "&lt;no scopes selected&gt;"
msgstr ""
@@ -863,6 +915,9 @@ msgstr ""
msgid "'%{name}' Value Stream created"
msgstr ""
+msgid "'%{name}' Value Stream deleted"
+msgstr ""
+
msgid "'%{name}' stage already exists"
msgstr ""
@@ -922,6 +977,9 @@ msgstr ""
msgid "+ %{numberOfHiddenAssignees} more"
msgstr ""
+msgid "+ %{numberOfHiddenReviewers} more"
+msgstr ""
+
msgid "+%d more"
msgid_plural "+%d more"
msgstr[0] ""
@@ -982,6 +1040,11 @@ msgid_plural "%d Days"
msgstr[0] ""
msgstr[1] ""
+msgid "1 Issue"
+msgid_plural "%d Issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "1 closed issue"
msgid_plural "%{issues} closed issues"
msgstr[0] ""
@@ -997,6 +1060,11 @@ msgid_plural "%d days"
msgstr[0] ""
msgstr[1] ""
+msgid "1 deploy key"
+msgid_plural "%d deploy keys"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1099,6 +1167,9 @@ msgstr ""
msgid ":%{startLine} to %{endLine}"
msgstr ""
+msgid "A %{incident_docs_start}modified issue%{incident_docs_end} to guide the resolution of incidents."
+msgstr ""
+
msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr ""
@@ -1111,6 +1182,9 @@ msgstr ""
msgid "A GitBook site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
+msgid "A Gitpod configured Webapplication in Spring and Java"
+msgstr ""
+
msgid "A Hexo site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
@@ -1282,9 +1356,15 @@ msgstr ""
msgid "Access expiration date"
msgstr ""
+msgid "Access expires"
+msgstr ""
+
msgid "Access forbidden. Check your access level."
msgstr ""
+msgid "Access granted"
+msgstr ""
+
msgid "Access requests"
msgstr ""
@@ -1294,6 +1374,9 @@ msgstr ""
msgid "Access to Pages websites are controlled based on the user's membership to a given project. By checking this box, users will be required to be logged in to have access to all Pages websites in your instance."
msgstr ""
+msgid "AccessDropdown|Deploy Keys"
+msgstr ""
+
msgid "AccessDropdown|Groups"
msgstr ""
@@ -1411,12 +1494,6 @@ msgstr ""
msgid "Active Sessions"
msgstr ""
-msgid "Active Users:"
-msgstr ""
-
-msgid "Active users"
-msgstr ""
-
msgid "Activity"
msgstr ""
@@ -1584,9 +1661,6 @@ msgstr ""
msgid "Add label(s)"
msgstr ""
-msgid "Add license"
-msgstr ""
-
msgid "Add list"
msgstr ""
@@ -1761,21 +1835,51 @@ msgstr ""
msgid "AdminArea|Bots"
msgstr ""
+msgid "AdminArea|Components"
+msgstr ""
+
msgid "AdminArea|Developer"
msgstr ""
+msgid "AdminArea|Features"
+msgstr ""
+
+msgid "AdminArea|Groups: %{number_of_groups}"
+msgstr ""
+
msgid "AdminArea|Guest"
msgstr ""
msgid "AdminArea|Included Free in license"
msgstr ""
+msgid "AdminArea|Latest groups"
+msgstr ""
+
+msgid "AdminArea|Latest projects"
+msgstr ""
+
+msgid "AdminArea|Latest users"
+msgstr ""
+
msgid "AdminArea|Maintainer"
msgstr ""
+msgid "AdminArea|New group"
+msgstr ""
+
+msgid "AdminArea|New project"
+msgstr ""
+
+msgid "AdminArea|New user"
+msgstr ""
+
msgid "AdminArea|Owner"
msgstr ""
+msgid "AdminArea|Projects: %{number_of_projects}"
+msgstr ""
+
msgid "AdminArea|Reporter"
msgstr ""
@@ -1803,6 +1907,9 @@ msgstr ""
msgid "AdminArea|Users without a Group and Project"
msgstr ""
+msgid "AdminArea|Users: %{number_of_users}"
+msgstr ""
+
msgid "AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running."
msgstr ""
@@ -1821,9 +1928,6 @@ msgstr ""
msgid "AdminProjects|Delete Project %{projectName}?"
msgstr ""
-msgid "AdminProjects|Delete project"
-msgstr ""
-
msgid "AdminSettings|Apply integration settings to all Projects"
msgstr ""
@@ -2061,21 +2165,30 @@ msgstr ""
msgid "AdminUsers|Without projects"
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 ""
msgid "AdminUsers|You cannot remove your own admin rights."
msgstr ""
+msgid "AdminUsers|You must transfer ownership or delete the groups owned by this user before you can delete their account"
+msgstr ""
+
msgid "Administration"
msgstr ""
msgid "Advanced"
msgstr ""
+msgid "Advanced Search"
+msgstr ""
+
+msgid "Advanced Search with Elasticsearch"
+msgstr ""
+
msgid "Advanced Settings"
msgstr ""
@@ -2153,6 +2266,9 @@ msgstr ""
msgid "AlertManagement|Edit"
msgstr ""
+msgid "AlertManagement|Environment"
+msgstr ""
+
msgid "AlertManagement|Events"
msgstr ""
@@ -2165,6 +2281,9 @@ msgstr ""
msgid "AlertManagement|Issue"
msgstr ""
+msgid "AlertManagement|Key"
+msgstr ""
+
msgid "AlertManagement|Low"
msgstr ""
@@ -2258,6 +2377,9 @@ msgstr ""
msgid "AlertManagement|Unknown"
msgstr ""
+msgid "AlertManagement|Value"
+msgstr ""
+
msgid "AlertManagement|View alerts in Opsgenie"
msgstr ""
@@ -2417,6 +2539,9 @@ msgstr ""
msgid "All projects"
msgstr ""
+msgid "All projects selected"
+msgstr ""
+
msgid "All security scans are enabled because %{linkStart}Auto DevOps%{linkEnd} is enabled on this project"
msgstr ""
@@ -2504,6 +2629,9 @@ msgstr ""
msgid "Almost there"
msgstr ""
+msgid "Already blocked"
+msgstr ""
+
msgid "Also called \"Issuer\" or \"Relying party trust identifier\""
msgstr ""
@@ -2558,6 +2686,9 @@ msgstr ""
msgid "An error has occurred"
msgstr ""
+msgid "An error occured while making the changes: %{error}"
+msgstr ""
+
msgid "An error occurred adding a draft to the thread."
msgstr ""
@@ -2585,12 +2716,6 @@ msgstr ""
msgid "An error occurred when toggling the notification subscription"
msgstr ""
-msgid "An error occurred when trying to resolve a comment. Please try again."
-msgstr ""
-
-msgid "An error occurred when trying to resolve a discussion. Please try again."
-msgstr ""
-
msgid "An error occurred when updating the issue weight"
msgstr ""
@@ -2606,12 +2731,6 @@ msgstr ""
msgid "An error occurred while checking group path. Please refresh and try again."
msgstr ""
-msgid "An error occurred while committing your changes."
-msgstr ""
-
-msgid "An error occurred while creating the list. Please try again."
-msgstr ""
-
msgid "An error occurred while decoding the file."
msgstr ""
@@ -2684,25 +2803,19 @@ msgstr ""
msgid "An error occurred while fetching the Service Desk address."
msgstr ""
-msgid "An error occurred while fetching the board issues. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the board lists. Please reload the page."
msgstr ""
msgid "An error occurred while fetching the board lists. Please try again."
msgstr ""
-msgid "An error occurred while fetching the board swimlanes. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the builds."
msgstr ""
msgid "An error occurred while fetching the job log."
msgstr ""
-msgid "An error occurred while fetching the job trace."
+msgid "An error occurred while fetching the job logs."
msgstr ""
msgid "An error occurred while fetching the job."
@@ -2849,9 +2962,6 @@ msgstr ""
msgid "An error occurred while saving assignees"
msgstr ""
-msgid "An error occurred while saving the template. Please check if the template exists."
-msgstr ""
-
msgid "An error occurred while searching for milestones"
msgstr ""
@@ -2870,10 +2980,10 @@ msgstr ""
msgid "An error occurred while updating approvers"
msgstr ""
-msgid "An error occurred while updating the comment"
+msgid "An error occurred while updating labels."
msgstr ""
-msgid "An error occurred while updating the list. Please try again."
+msgid "An error occurred while updating the comment"
msgstr ""
msgid "An error occurred while validating group path"
@@ -2927,6 +3037,9 @@ msgstr ""
msgid "An unknown error occurred while loading this graph."
msgstr ""
+msgid "An unknown error occurred."
+msgstr ""
+
msgid "Analytics"
msgstr ""
@@ -2960,10 +3073,10 @@ msgstr ""
msgid "Any"
msgstr ""
-msgid "Any Author"
+msgid "Any %{header}"
msgstr ""
-msgid "Any Status"
+msgid "Any Author"
msgstr ""
msgid "Any branch"
@@ -3017,6 +3130,9 @@ msgstr ""
msgid "Application ID"
msgstr ""
+msgid "Application limits saved successfully"
+msgstr ""
+
msgid "Application settings saved successfully"
msgstr ""
@@ -3226,6 +3342,9 @@ msgstr ""
msgid "Are you sure you want to close this blocked issue?"
msgstr ""
+msgid "Are you sure you want to delete \"%{name}\" Value Stream?"
+msgstr ""
+
msgid "Are you sure you want to delete %{name}?"
msgstr ""
@@ -3235,6 +3354,9 @@ msgstr ""
msgid "Are you sure you want to delete this %{typeOfComment}?"
msgstr ""
+msgid "Are you sure you want to delete this SSH key?"
+msgstr ""
+
msgid "Are you sure you want to delete this board?"
msgstr ""
@@ -3259,6 +3381,11 @@ msgstr ""
msgid "Are you sure you want to erase this build?"
msgstr ""
+msgid "Are you sure you want to import %d repository?"
+msgid_plural "Are you sure you want to import %d repositories?"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Are you sure you want to lose unsaved changes?"
msgstr ""
@@ -3268,15 +3395,15 @@ msgstr ""
msgid "Are you sure you want to merge immediately?"
msgstr ""
-msgid "Are you sure you want to permanently delete this license?"
-msgstr ""
-
msgid "Are you sure you want to re-deploy this environment?"
msgstr ""
msgid "Are you sure you want to regenerate the public key? You will have to update the public key on the remote server before mirroring will work again."
msgstr ""
+msgid "Are you sure you want to reindex?"
+msgstr ""
+
msgid "Are you sure you want to remove %{group_name}?"
msgstr ""
@@ -3304,6 +3431,9 @@ msgstr ""
msgid "Are you sure you want to revoke this nickname?"
msgstr ""
+msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
+msgstr ""
+
msgid "Are you sure you want to stop this environment?"
msgstr ""
@@ -3325,6 +3455,9 @@ msgstr ""
msgid "Are you sure? The device will be signed out of GitLab and all remember me tokens revoked."
msgstr ""
+msgid "Are you sure? This will invalidate your registered applications and U2F / WebAuthn devices."
+msgstr ""
+
msgid "Are you sure? This will invalidate your registered applications and U2F devices."
msgstr ""
@@ -3343,9 +3476,6 @@ msgstr ""
msgid "Artifacts"
msgstr ""
-msgid "As U2F devices are only supported by a few browsers, we require that you set up a two-factor authentication app before a U2F device. That way you'll always be able to log in - even when you're using an unsupported browser."
-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 ""
@@ -3539,6 +3669,9 @@ msgstr ""
msgid "AuditLogs|Target"
msgstr ""
+msgid "AuditLogs|This month"
+msgstr ""
+
msgid "AuditLogs|User Events"
msgstr ""
@@ -3578,6 +3711,9 @@ msgstr ""
msgid "Authentication via U2F device failed."
msgstr ""
+msgid "Authentication via WebAuthn device failed."
+msgstr ""
+
msgid "Author"
msgstr ""
@@ -3845,15 +3981,6 @@ msgstr ""
msgid "BambooService|You must set up automatic revision labeling and a repository trigger in Bamboo."
msgstr ""
-msgid "BatchComments|Delete all pending comments"
-msgstr ""
-
-msgid "BatchComments|Discard review?"
-msgstr ""
-
-msgid "BatchComments|You're about to discard your review which will delete all of your pending comments. The deleted comments %{strong_start}cannot%{strong_end} be restored."
-msgstr ""
-
msgid "Be careful. Changing the project's namespace can have unintended side effects."
msgstr ""
@@ -3875,6 +4002,9 @@ msgstr ""
msgid "Bi-weekly code coverage"
msgstr ""
+msgid "Billable Users:"
+msgstr ""
+
msgid "Billing"
msgstr ""
@@ -3884,7 +4014,7 @@ msgstr ""
msgid "BillingPlans|@%{user_name} you are currently using the %{plan_name} plan."
msgstr ""
-msgid "BillingPlans|Congratulations, your new trial is activated"
+msgid "BillingPlans|Congratulations, your free trial is activated."
msgstr ""
msgid "BillingPlans|If you would like to downgrade your plan please contact %{support_link_start}Customer Support%{support_link_end}."
@@ -3947,6 +4077,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Block user"
+msgstr ""
+
msgid "Blocked"
msgstr ""
@@ -3962,31 +4095,37 @@ msgstr ""
msgid "Blog"
msgstr ""
-msgid "Board name"
-msgstr ""
-
msgid "Board scope"
msgstr ""
msgid "Board scope affects which issues are displayed for anyone who visits this board"
msgstr ""
-msgid "BoardBlankState|Add default lists"
+msgid "Boards"
msgstr ""
-msgid "BoardBlankState|Add the following default lists to your Issue Board with one click:"
+msgid "Boards and Board Lists"
msgstr ""
-msgid "BoardBlankState|Nevermind, I'll use my own"
+msgid "Boards|An error occurred while creating the issue. Please try again."
msgstr ""
-msgid "BoardBlankState|Starting out with the default set of lists will get you right on the way to making the most of your board."
+msgid "Boards|An error occurred while creating the list. Please try again."
msgstr ""
-msgid "Boards"
+msgid "Boards|An error occurred while fetching issues. Please reload the page."
msgstr ""
-msgid "Boards and Board Lists"
+msgid "Boards|An error occurred while fetching the board issues. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching the board swimlanes. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while moving the issue. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while updating the list. Please try again."
msgstr ""
msgid "Boards|Collapse"
@@ -4013,7 +4152,7 @@ msgstr ""
msgid "Branch %{branch_name} was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr ""
-msgid "Branch has changed"
+msgid "Branch changed"
msgstr ""
msgid "Branch is already taken"
@@ -4319,6 +4458,9 @@ msgstr ""
msgid "CLOSED (MOVED)"
msgstr ""
+msgid "CODEOWNERS rule violation"
+msgstr ""
+
msgid "CONTRIBUTING"
msgstr ""
@@ -4349,9 +4491,6 @@ msgstr ""
msgid "Can't create snippet: %{err}"
msgstr ""
-msgid "Can't edit as source branch was deleted"
-msgstr ""
-
msgid "Can't fetch content for the blob: %{err}"
msgstr ""
@@ -4364,9 +4503,6 @@ msgstr ""
msgid "Can't load mermaid module: %{err}"
msgstr ""
-msgid "Can't remove group members without group managed account"
-msgstr ""
-
msgid "Can't scan the code?"
msgstr ""
@@ -4409,6 +4545,9 @@ msgstr ""
msgid "Cannot create the abuse report. This user has been blocked."
msgstr ""
+msgid "Cannot enable shared runners because parent group does not allow it"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -4514,6 +4653,15 @@ msgstr ""
msgid "Change your password or recover your current one"
msgstr ""
+msgid "ChangeReviewer|Reviewer changed from %{old} to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Reviewer changed to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Unassigned"
+msgstr ""
+
msgid "ChangeTypeActionLabel|Pick into branch"
msgstr ""
@@ -4553,6 +4701,9 @@ msgstr ""
msgid "Changes the title to \"%{title_param}\"."
msgstr ""
+msgid "Changes were successfully made."
+msgstr ""
+
msgid "Changes won't take place until the index is %{link_start}recreated%{link_end}."
msgstr ""
@@ -4958,6 +5109,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove variable"
+msgstr ""
+
msgid "CiVariables|Remove variable row"
msgstr ""
@@ -5036,9 +5190,6 @@ msgstr ""
msgid "Clear due date"
msgstr ""
-msgid "Clear input"
-msgstr ""
-
msgid "Clear recent searches"
msgstr ""
@@ -5087,6 +5238,9 @@ msgstr ""
msgid "Client authentication key password"
msgstr ""
+msgid "Client request timeout"
+msgstr ""
+
msgid "Clients"
msgstr ""
@@ -5171,6 +5325,27 @@ msgstr ""
msgid "Cluster type must be specificed for Stages::ClusterEndpointInserter"
msgstr ""
+msgid "ClusterAgents|Configuration"
+msgstr ""
+
+msgid "ClusterAgents|Connect your cluster with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate Kubernetes with a GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Name"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Agent also requires %{linkStart}enabling the Agent Server%{linkEnd}"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Kubernetes Agent allows an Infrastructure as Code, GitOps approach to integrating Kubernetes clusters with GitLab. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "ClusterAgent|This feature is only available for premium plans"
msgstr ""
@@ -5240,10 +5415,10 @@ msgstr ""
msgid "ClusterIntegration|All installed applications and related resources"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster."
+msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{linkStart}More information%{linkEnd}"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{startLink}More information%{endLink}"
+msgid "ClusterIntegration|Allow GitLab to manage namespaces and service accounts for this cluster."
msgstr ""
msgid "ClusterIntegration|Alternatively, "
@@ -5264,6 +5439,9 @@ msgstr ""
msgid "ClusterIntegration|An error occurred while trying to fetch zone machine types: %{error}"
msgstr ""
+msgid "ClusterIntegration|An unknown error occurred while attempting to connect to Kubernetes."
+msgstr ""
+
msgid "ClusterIntegration|Any project namespaces"
msgstr ""
@@ -5279,6 +5457,9 @@ msgstr ""
msgid "ClusterIntegration|Authenticate with Amazon Web Services"
msgstr ""
+msgid "ClusterIntegration|Authentication Error"
+msgstr ""
+
msgid "ClusterIntegration|Base domain"
msgstr ""
@@ -5297,13 +5478,22 @@ msgstr ""
msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}security group %{externalLinkIcon} %{endLink} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
+msgid "ClusterIntegration|Check your CA certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Check your cluster status"
+msgstr ""
+
+msgid "ClusterIntegration|Check your token"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}subnets %{externalLinkIcon} %{endLink} in your VPC where your worker nodes will run."
+msgid "ClusterIntegration|Choose the %{linkStart}security group %{linkEnd} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
msgstr ""
-msgid "ClusterIntegration|Choose the worker node %{startLink}instance type %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Choose the %{linkStart}subnets %{linkEnd} in your VPC where your worker nodes will run."
+msgstr ""
+
+msgid "ClusterIntegration|Choose the worker node %{linkStart}instance type%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Choose which applications to install on your Kubernetes cluster."
@@ -5315,10 +5505,7 @@ msgstr ""
msgid "ClusterIntegration|Clear cluster cache"
msgstr ""
-msgid "ClusterIntegration|Clear the local cache of namespace and service accounts. This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
-msgstr ""
-
-msgid "ClusterIntegration|Cluster being created"
+msgid "ClusterIntegration|Clear the local cache of namespace and service accounts."
msgstr ""
msgid "ClusterIntegration|Cluster management project (alpha)"
@@ -5330,15 +5517,21 @@ msgstr ""
msgid "ClusterIntegration|Cluster_applications artifact too big. Maximum allowable size: %{human_size}"
msgstr ""
-msgid "ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters."
+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|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}"
+msgid "ClusterIntegration|Clusters connected with a certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Connect cluster with certificate"
msgstr ""
msgid "ClusterIntegration|Connect existing cluster"
msgstr ""
+msgid "ClusterIntegration|Connection Error"
+msgstr ""
+
msgid "ClusterIntegration|Copy API URL"
msgstr ""
@@ -5414,6 +5607,12 @@ msgstr ""
msgid "ClusterIntegration|Deletes all GitLab resources attached to this cluster during removal"
msgstr ""
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared."
+msgstr ""
+
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared. %{linkStart}More information%{linkEnd}"
+msgstr ""
+
msgid "ClusterIntegration|Did you know?"
msgstr ""
@@ -5483,6 +5682,9 @@ msgstr ""
msgid "ClusterIntegration|Fluentd is an open source data collector, which lets you unify the data collection and consumption for a better use and understanding of data. It requires at least one of the following logs to be successfully installed."
msgstr ""
+msgid "ClusterIntegration|GitLab Agent managed clusters"
+msgstr ""
+
msgid "ClusterIntegration|GitLab Container Network Policies"
msgstr ""
@@ -5495,6 +5697,12 @@ msgstr ""
msgid "ClusterIntegration|GitLab Runner connects to the repository and executes CI/CD jobs, pushing results back and deploying applications to production."
msgstr ""
+msgid "ClusterIntegration|GitLab failed to authenticate."
+msgstr ""
+
+msgid "ClusterIntegration|GitLab failed to connect to the cluster."
+msgstr ""
+
msgid "ClusterIntegration|GitLab-managed cluster"
msgstr ""
@@ -5516,6 +5724,9 @@ msgstr ""
msgid "ClusterIntegration|Group cluster"
msgstr ""
+msgid "ClusterIntegration|HTTP Error"
+msgstr ""
+
msgid "ClusterIntegration|Helm Tiller"
msgstr ""
@@ -5549,7 +5760,10 @@ msgstr ""
msgid "ClusterIntegration|Instance type"
msgstr ""
-msgid "ClusterIntegration|Integrate Kubernetes cluster automation"
+msgid "ClusterIntegration|Integrate Kubernetes with a cluster certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Integrate with a cluster certificate"
msgstr ""
msgid "ClusterIntegration|Issuer Email"
@@ -5585,9 +5799,6 @@ msgstr ""
msgid "ClusterIntegration|Knative extends Kubernetes to provide a set of middleware components that are essential to build modern, source-centric, and container-based applications that can run anywhere: on premises, in the cloud, or even in a third-party data center."
msgstr ""
-msgid "ClusterIntegration|Kubernetes cluster"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes cluster is being created..."
msgstr ""
@@ -5600,9 +5811,6 @@ msgstr ""
msgid "ClusterIntegration|Kubernetes clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr ""
-msgid "ClusterIntegration|Kubernetes clusters can be used to deploy applications and to provide Review Apps for this project"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes version"
msgstr ""
@@ -5615,7 +5823,7 @@ msgstr ""
msgid "ClusterIntegration|Learn more about %{help_link_start}zones%{help_link_end}."
msgstr ""
-msgid "ClusterIntegration|Learn more about %{startLink}Regions %{externalLinkIcon}%{endLink}."
+msgid "ClusterIntegration|Learn more about %{linkStart}Regions%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Learn more about Kubernetes"
@@ -5660,12 +5868,18 @@ msgstr ""
msgid "ClusterIntegration|Machine type"
msgstr ""
+msgid "ClusterIntegration|Make sure your API endpoint is correct"
+msgstr ""
+
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create Kubernetes clusters"
msgstr ""
msgid "ClusterIntegration|Manage your Kubernetes cluster by visiting %{provider_link}"
msgstr ""
+msgid "ClusterIntegration|Namespace per environment"
+msgstr ""
+
msgid "ClusterIntegration|No IAM Roles found"
msgstr ""
@@ -5711,6 +5925,9 @@ msgstr ""
msgid "ClusterIntegration|No zones matched your search"
msgstr ""
+msgid "ClusterIntegration|Node calculations use the Kubernetes Metrics API. Make sure your cluster has metrics installed"
+msgstr ""
+
msgid "ClusterIntegration|Number of nodes"
msgstr ""
@@ -5753,6 +5970,9 @@ msgstr ""
msgid "ClusterIntegration|RBAC-enabled cluster"
msgstr ""
+msgid "ClusterIntegration|Read our %{linkStart}help page%{linkEnd} on Kubernetes cluster integration."
+msgstr ""
+
msgid "ClusterIntegration|Read our %{link_start}help page%{link_end} on Kubernetes cluster integration."
msgstr ""
@@ -5855,7 +6075,7 @@ msgstr ""
msgid "ClusterIntegration|Select a VPC to choose a subnet"
msgstr ""
-msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{linkStart}Amazon Web Services %{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select a network to choose a subnetwork"
@@ -5888,7 +6108,7 @@ msgstr ""
msgid "ClusterIntegration|Select project to choose zone"
msgstr ""
-msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select zone"
@@ -5978,9 +6198,18 @@ msgstr ""
msgid "ClusterIntegration|There was a problem authenticating with your cluster. Please ensure your CA Certificate and Token are valid."
msgstr ""
+msgid "ClusterIntegration|There was an HTTP error when connecting to your cluster."
+msgstr ""
+
msgid "ClusterIntegration|This account must have permissions to create a Kubernetes cluster in the %{link_to_container_project} specified below"
msgstr ""
+msgid "ClusterIntegration|This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
+msgstr ""
+
+msgid "ClusterIntegration|This is necessary to clear existing environment-namespace associations from clusters previously managed by GitLab."
+msgstr ""
+
msgid "ClusterIntegration|This option will allow you to install applications on RBAC clusters."
msgstr ""
@@ -6005,9 +6234,21 @@ msgstr ""
msgid "ClusterIntegration|To use a new project, first create one on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}."
msgstr ""
+msgid "ClusterIntegration|Troubleshooting tips:"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Authenticate"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Connect"
+msgstr ""
+
msgid "ClusterIntegration|Uninstall %{appTitle}"
msgstr ""
+msgid "ClusterIntegration|Unknown Error"
+msgstr ""
+
msgid "ClusterIntegration|Update %{appTitle}"
msgstr ""
@@ -6068,7 +6309,7 @@ msgstr ""
msgid "ClusterIntegration|Your cluster API is unreachable. Please ensure your API URL is correct."
msgstr ""
-msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Zone"
@@ -6188,6 +6429,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse all threads"
+msgstr ""
+
msgid "Collapse approvers"
msgstr ""
@@ -6337,7 +6581,7 @@ msgstr ""
msgid "Commit…"
msgstr ""
-msgid "Company"
+msgid "Community forum"
msgstr ""
msgid "Company name"
@@ -6346,6 +6590,9 @@ msgstr ""
msgid "Compare"
msgstr ""
+msgid "Compare %{oldCommitId}...%{newCommitId}"
+msgstr ""
+
msgid "Compare Git revisions"
msgstr ""
@@ -6361,6 +6608,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare submodule commit revisions"
+msgstr ""
+
msgid "Compare with previous version"
msgstr ""
@@ -6496,6 +6746,9 @@ msgstr ""
msgid "Configure the way a user creates a new account."
msgstr ""
+msgid "Configure which lists are shown for anyone who visits this board"
+msgstr ""
+
msgid "Confirm"
msgstr ""
@@ -6721,6 +6974,9 @@ msgstr[1] ""
msgid "ContainerRegistry|Set cleanup policy"
msgstr ""
+msgid "ContainerRegistry|Some tags were not deleted"
+msgstr ""
+
msgid "ContainerRegistry|Something went wrong while fetching the cleanup policy."
msgstr ""
@@ -6760,6 +7016,9 @@ msgstr ""
msgid "ContainerRegistry|Tags with names matching this regex pattern will %{italicStart}expire:%{italicEnd}"
msgstr ""
+msgid "ContainerRegistry|The cleanup policy timed out before it could delete all tags. An administrator can %{adminLinkStart}manually run cleanup now%{adminLinkEnd} or you can wait for the cleanup policy to automatically run again. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "ContainerRegistry|The last tag related to this image was recently removed. This empty image and any associated data will be automatically removed as part of the regular Garbage Collection process. If you have any questions, contact your administrator."
msgstr ""
@@ -6892,6 +7151,9 @@ msgstr ""
msgid "Contributions per group member"
msgstr ""
+msgid "Contributor"
+msgstr ""
+
msgid "Contributors"
msgstr ""
@@ -7021,6 +7283,9 @@ msgstr ""
msgid "Could not change HEAD: branch '%{branch}' does not exist"
msgstr ""
+msgid "Could not commit. An unexpected error occurred."
+msgstr ""
+
msgid "Could not connect to FogBugz, check your URL"
msgstr ""
@@ -7060,6 +7325,9 @@ msgstr ""
msgid "Could not find iteration"
msgstr ""
+msgid "Could not load instance counts. Please refresh the page to try again."
+msgstr ""
+
msgid "Could not remove the trigger."
msgstr ""
@@ -7084,10 +7352,10 @@ msgstr ""
msgid "Could not save prometheus manual configuration"
msgstr ""
-msgid "Could not udpdate wiki page"
+msgid "Could not update the LDAP settings"
msgstr ""
-msgid "Could not update the LDAP settings"
+msgid "Could not update wiki page"
msgstr ""
msgid "Could not upload your designs as one or more files uploaded are not supported."
@@ -7745,6 +8013,9 @@ msgstr ""
msgid "DastProfiles|Are you sure you want to delete this profile?"
msgstr ""
+msgid "DastProfiles|Could not create site validation token. Please refresh the page, or try again later."
+msgstr ""
+
msgid "DastProfiles|Could not create the scanner profile. Please try again."
msgstr ""
@@ -7769,6 +8040,12 @@ msgstr ""
msgid "DastProfiles|Could not fetch site profiles. Please refresh the page, or try again later."
msgstr ""
+msgid "DastProfiles|Could not retrieve site validation status. Please refresh the page, or try again later."
+msgstr ""
+
+msgid "DastProfiles|Could not update the scanner profile. Please try again."
+msgstr ""
+
msgid "DastProfiles|Could not update the site profile. Please try again."
msgstr ""
@@ -7784,7 +8061,7 @@ msgstr ""
msgid "DastProfiles|Download validation text file"
msgstr ""
-msgid "DastProfiles|Edit feature will come soon. Please create a new profile if changes needed"
+msgid "DastProfiles|Edit scanner profile"
msgstr ""
msgid "DastProfiles|Edit site profile"
@@ -7817,6 +8094,9 @@ msgstr ""
msgid "DastProfiles|No profiles created yet"
msgstr ""
+msgid "DastProfiles|Passive"
+msgstr ""
+
msgid "DastProfiles|Please enter a valid URL format, ex: http://www.example.com/home"
msgstr ""
@@ -7832,6 +8112,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan mode"
+msgstr ""
+
msgid "DastProfiles|Scanner Profile"
msgstr ""
@@ -7871,10 +8154,10 @@ msgstr ""
msgid "DastProfiles|Text file validation"
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
+msgid "DastProfiles|The maximum number of minutes allowed for the spider to traverse the site."
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the spider to traverse the site."
+msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
msgstr ""
msgid "DastProfiles|Validate"
@@ -7907,6 +8190,9 @@ msgstr ""
msgid "Date picker"
msgstr ""
+msgid "Date range"
+msgstr ""
+
msgid "Date range cannot exceed %{maxDateRange} days."
msgstr ""
@@ -7931,6 +8217,9 @@ msgstr ""
msgid "Days to merge"
msgstr ""
+msgid "Dear Administrator,"
+msgstr ""
+
msgid "Debug"
msgstr ""
@@ -8042,12 +8331,18 @@ msgstr ""
msgid "Delete"
msgstr ""
+msgid "Delete %{name}"
+msgstr ""
+
msgid "Delete Comment"
msgstr ""
msgid "Delete Snippet"
msgstr ""
+msgid "Delete Value Stream"
+msgstr ""
+
msgid "Delete account"
msgstr ""
@@ -8069,9 +8364,6 @@ msgstr ""
msgid "Delete label: %{label_name} ?"
msgstr ""
-msgid "Delete license"
-msgstr ""
-
msgid "Delete list"
msgstr ""
@@ -8147,15 +8439,6 @@ msgstr ""
msgid "Deleting a project places it into a read-only state until %{date}, at which point the project will be permanently deleted. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "Deleting the license failed."
-msgstr ""
-
-msgid "Deleting the license failed. The license was not found."
-msgstr ""
-
-msgid "Deleting the license failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "Deleting the project will delete its repository and all related resources including issues, merge requests etc."
msgstr ""
@@ -8651,7 +8934,10 @@ msgstr ""
msgid "DesignManagement|The maximum number of designs allowed to be uploaded is %{upload_limit}. Please try again."
msgstr ""
-msgid "DesignManagement|To upload designs, you'll need to enable LFS. %{requirements_link_start}More information%{requirements_link_end}"
+msgid "DesignManagement|There was an error moving your designs. Please upload your designs below."
+msgstr ""
+
+msgid "DesignManagement|To upload designs, you'll need to enable LFS and have admin enable hashed storage. %{requirements_link_start}More information%{requirements_link_end}"
msgstr ""
msgid "DesignManagement|Unresolve thread"
@@ -8663,6 +8949,9 @@ msgstr ""
msgid "DesignManagement|Upload skipped."
msgstr ""
+msgid "DesignManagement|Your designs are being copied and are on their way… Please refresh to update."
+msgstr ""
+
msgid "DesignManagement|and %{moreCount} more."
msgstr ""
@@ -8720,6 +9009,9 @@ msgstr ""
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
+msgid "Direct member"
+msgstr ""
+
msgid "Direction"
msgstr ""
@@ -8768,9 +9060,6 @@ msgstr ""
msgid "Discard draft"
msgstr ""
-msgid "Discard review"
-msgstr ""
-
msgid "DiscordService|Discord Notifications"
msgstr ""
@@ -8839,10 +9128,10 @@ msgstr ""
msgid "Dismiss Merge Request promotion"
msgstr ""
-msgid "Dismiss Selected"
+msgid "Dismiss Value Stream Analytics introduction box"
msgstr ""
-msgid "Dismiss Value Stream Analytics introduction box"
+msgid "Dismiss selected"
msgstr ""
msgid "Dismiss trial promotion"
@@ -8893,9 +9182,6 @@ msgstr ""
msgid "Documents reindexed: %{processed_documents} (%{percentage}%%)"
msgstr ""
-msgid "Doing"
-msgstr ""
-
msgid "Domain"
msgstr ""
@@ -9091,9 +9377,6 @@ msgstr ""
msgid "Edit environment"
msgstr ""
-msgid "Edit file"
-msgstr ""
-
msgid "Edit files in the editor and commit changes here"
msgstr ""
@@ -9106,6 +9389,12 @@ msgstr ""
msgid "Edit identity for %{user_name}"
msgstr ""
+msgid "Edit in Web IDE"
+msgstr ""
+
+msgid "Edit in single-file editor"
+msgstr ""
+
msgid "Edit issues"
msgstr ""
@@ -9133,10 +9422,10 @@ msgstr ""
msgid "Editing"
msgstr ""
-msgid "Elasticsearch"
+msgid "Elasticsearch AWS IAM credentials"
msgstr ""
-msgid "Elasticsearch AWS IAM credentials"
+msgid "Elasticsearch HTTP client timeout value in seconds."
msgstr ""
msgid "Elasticsearch indexing restrictions"
@@ -9145,9 +9434,6 @@ msgstr ""
msgid "Elasticsearch indexing started"
msgstr ""
-msgid "Elasticsearch integration. Elasticsearch AWS IAM."
-msgstr ""
-
msgid "Elasticsearch reindexing is already in progress"
msgstr ""
@@ -9175,9 +9461,6 @@ msgstr ""
msgid "Email Notification"
msgstr ""
-msgid "Email address"
-msgstr ""
-
msgid "Email could not be sent"
msgstr ""
@@ -9241,6 +9524,9 @@ msgstr ""
msgid "Emails sent from Service Desk will have this name"
msgstr ""
+msgid "Emails sent to %{email} will still be supported"
+msgstr ""
+
msgid "Emails separated by comma"
msgstr ""
@@ -9274,9 +9560,18 @@ msgstr ""
msgid "Enable"
msgstr ""
+msgid "Enable %{link_start}Gitpod%{link_end} integration to launch a development environment in your browser directly from GitLab."
+msgstr ""
+
msgid "Enable Auto DevOps"
msgstr ""
+msgid "Enable Gitpod"
+msgstr ""
+
+msgid "Enable Gitpod?"
+msgstr ""
+
msgid "Enable HTML emails"
msgstr ""
@@ -9406,9 +9701,6 @@ msgstr ""
msgid "Encountered an error while rendering: %{err}"
msgstr ""
-msgid "End date"
-msgstr ""
-
msgid "Ends at (UTC)"
msgstr ""
@@ -9568,7 +9860,7 @@ msgstr ""
msgid "EnvironmentsDashboard|The environments dashboard provides a summary of each project's environments' status, including pipeline and alert statuses."
msgstr ""
-msgid "EnvironmentsDashboard|This dashboard displays a maximum of 7 projects and 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
+msgid "EnvironmentsDashboard|This dashboard displays 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
msgstr ""
msgid "Environments|An error occurred while canceling the auto stop, please try again"
@@ -9889,6 +10181,9 @@ msgstr ""
msgid "Error deleting project. Check logs for error details."
msgstr ""
+msgid "Error fetching burnup chart data"
+msgstr ""
+
msgid "Error fetching diverging counts for branches. Please try again."
msgstr ""
@@ -9967,6 +10262,9 @@ msgstr ""
msgid "Error occurred when saving assignees"
msgstr ""
+msgid "Error occurred when saving reviewers"
+msgstr ""
+
msgid "Error occurred when toggling the notification subscription"
msgstr ""
@@ -10219,10 +10517,13 @@ msgstr ""
msgid "Expand all"
msgstr ""
-msgid "Expand approvers"
+msgid "Expand all files"
msgstr ""
-msgid "Expand dropdown"
+msgid "Expand all threads"
+msgstr ""
+
+msgid "Expand approvers"
msgstr ""
msgid "Expand milestones"
@@ -10393,6 +10694,9 @@ msgstr ""
msgid "Failed to create Merge Request. Please try again."
msgstr ""
+msgid "Failed to create To-Do for the design."
+msgstr ""
+
msgid "Failed to create a branch for this issue. Please try again."
msgstr ""
@@ -10432,6 +10736,12 @@ msgstr ""
msgid "Failed to load authors. Please try again."
msgstr ""
+msgid "Failed to load branches. Please try again."
+msgstr ""
+
+msgid "Failed to load deploy keys."
+msgstr ""
+
msgid "Failed to load emoji list."
msgstr ""
@@ -10447,6 +10757,9 @@ msgstr ""
msgid "Failed to load groups & users."
msgstr ""
+msgid "Failed to load groups, users and deploy keys."
+msgstr ""
+
msgid "Failed to load labels. Please try again."
msgstr ""
@@ -10456,6 +10769,12 @@ msgstr ""
msgid "Failed to load related branches"
msgstr ""
+msgid "Failed to load sidebar confidential toggle"
+msgstr ""
+
+msgid "Failed to load sidebar lock status"
+msgstr ""
+
msgid "Failed to load stacktrace."
msgstr ""
@@ -10483,6 +10802,9 @@ msgstr ""
msgid "Failed to publish issue on status page."
msgstr ""
+msgid "Failed to remove To-Do for the design."
+msgstr ""
+
msgid "Failed to remove a Zoom meeting"
msgstr ""
@@ -10525,6 +10847,9 @@ msgstr ""
msgid "Failed to signing using smartcard authentication"
msgstr ""
+msgid "Failed to toggle To-Do for the design."
+msgstr ""
+
msgid "Failed to update branch!"
msgstr ""
@@ -10638,7 +10963,7 @@ msgstr ""
msgid "FeatureFlags|Edit User List"
msgstr ""
-msgid "FeatureFlags|Enable features for specific users and specific environments by defining feature flag strategies."
+msgid "FeatureFlags|Enable features for specific users and environments by configuring feature flag strategies."
msgstr ""
msgid "FeatureFlags|Environment Spec"
@@ -10698,7 +11023,7 @@ msgstr ""
msgid "FeatureFlags|Include additional user IDs"
msgstr ""
-msgid "FeatureFlags|Install a %{docs_link_anchored_start}compatible client library%{docs_link_anchored_end} and specify the API URL, application name, and instance ID during the configuration setup. %{docs_link_start}More Information%{docs_link_end}"
+msgid "FeatureFlags|Install a %{docsLinkAnchoredStart}compatible client library%{docsLinkAnchoredEnd} and specify the API URL, application name, and instance ID during the configuration setup. %{docsLinkStart}More Information%{docsLinkEnd}"
msgstr ""
msgid "FeatureFlags|Instance ID"
@@ -10710,6 +11035,9 @@ msgstr ""
msgid "FeatureFlags|Loading feature flags"
msgstr ""
+msgid "FeatureFlags|Loading user lists"
+msgstr ""
+
msgid "FeatureFlags|More information"
msgstr ""
@@ -10728,7 +11056,7 @@ msgstr ""
msgid "FeatureFlags|New feature flag"
msgstr ""
-msgid "FeatureFlags|New list"
+msgid "FeatureFlags|New user list"
msgstr ""
msgid "FeatureFlags|Percent of users"
@@ -10767,6 +11095,9 @@ msgstr ""
msgid "FeatureFlags|There was an error fetching the feature flags."
msgstr ""
+msgid "FeatureFlags|There was an error fetching the user lists."
+msgstr ""
+
msgid "FeatureFlags|There was an error retrieving user lists"
msgstr ""
@@ -10782,6 +11113,9 @@ msgstr ""
msgid "FeatureFlags|User List"
msgstr ""
+msgid "FeatureFlags|User Lists"
+msgstr ""
+
msgid "FeatureFlag|List"
msgstr ""
@@ -10809,15 +11143,6 @@ msgstr ""
msgid "Fetching incoming email"
msgstr ""
-msgid "Fetching licenses failed."
-msgstr ""
-
-msgid "Fetching licenses failed. The request endpoint was not found."
-msgstr ""
-
-msgid "Fetching licenses failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "File"
msgstr ""
@@ -10920,12 +11245,21 @@ msgstr ""
msgid "Filter by status"
msgstr ""
+msgid "Filter by test cases that are currently archived."
+msgstr ""
+
+msgid "Filter by test cases that are currently opened."
+msgstr ""
+
msgid "Filter by two-factor authentication"
msgstr ""
msgid "Filter by user"
msgstr ""
+msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
+msgstr ""
+
msgid "Filter pipelines"
msgstr ""
@@ -10941,7 +11275,7 @@ msgstr ""
msgid "Filter results..."
msgstr ""
-msgid "Filter your projects by name"
+msgid "Filter your repositories by name"
msgstr ""
msgid "Filter..."
@@ -10950,7 +11284,7 @@ msgstr ""
msgid "Find File"
msgstr ""
-msgid "Find bugs in your code with coverage-guided fuzzing"
+msgid "Find bugs in your code with coverage-guided fuzzing."
msgstr ""
msgid "Find by path"
@@ -10977,9 +11311,6 @@ msgstr ""
msgid "Finish editing this message first!"
msgstr ""
-msgid "Finish review"
-msgstr ""
-
msgid "Finish setting up your dedicated account for %{group_name}."
msgstr ""
@@ -11049,6 +11380,9 @@ msgstr ""
msgid "Footer message"
msgstr ""
+msgid "For a faster browsing experience, some files are collapsed by default."
+msgstr ""
+
msgid "For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
@@ -11058,6 +11392,9 @@ msgstr ""
msgid "For more info, read the documentation."
msgstr ""
+msgid "For more information on how the number of active users is calculated, see the %{self_managed_subscriptions_doc_link} documentation."
+msgstr ""
+
msgid "For more information, go to the "
msgstr ""
@@ -11196,6 +11533,9 @@ msgstr ""
msgid "Generate new token"
msgstr ""
+msgid "Generic package file size in bytes"
+msgstr ""
+
msgid "Geo"
msgstr ""
@@ -11457,6 +11797,9 @@ msgstr ""
msgid "Geo|Please refer to Geo Troubleshooting."
msgstr ""
+msgid "Geo|Primary node"
+msgstr ""
+
msgid "Geo|Project"
msgstr ""
@@ -11499,6 +11842,9 @@ msgstr ""
msgid "Geo|Review replication status, and resynchronize and reverify items with the primary node."
msgstr ""
+msgid "Geo|Secondary node"
+msgstr ""
+
msgid "Geo|Status"
msgstr ""
@@ -11538,6 +11884,9 @@ msgstr ""
msgid "Geo|URL must be a valid url (ex: https://gitlab.com)"
msgstr ""
+msgid "Geo|Undefined"
+msgstr ""
+
msgid "Geo|Unknown state"
msgstr ""
@@ -11613,10 +11962,16 @@ msgstr ""
msgid "GitHub import"
msgstr ""
+msgid "GitLab"
+msgstr ""
+
msgid "GitLab / Unsubscribe"
msgstr ""
-msgid "GitLab Enterprise Edition %{plan}"
+msgid "GitLab API"
+msgstr ""
+
+msgid "GitLab Billing Team."
msgstr ""
msgid "GitLab Group Runners can execute code for all the projects in this group."
@@ -11628,12 +11983,18 @@ msgstr ""
msgid "GitLab Issue"
msgstr ""
+msgid "GitLab Pages"
+msgstr ""
+
msgid "GitLab Service Desk is a simple way to allow people to create issues in your GitLab instance without needing their own user account. It provides a unique email address for end users to create issues in a project, and replies can be sent either through the GitLab interface or by email. End users will only see the thread through email."
msgstr ""
msgid "GitLab Shared Runners execute code of different projects on the same Runner unless you configure GitLab Runner Autoscale with MaxBuilds 1 (which it is on GitLab.com)."
msgstr ""
+msgid "GitLab Shell"
+msgstr ""
+
msgid "GitLab Support Bot"
msgstr ""
@@ -11643,7 +12004,7 @@ msgstr ""
msgid "GitLab User"
msgstr ""
-msgid "GitLab allows you to continue using your license even if you exceed the number of seats you purchased. You will be required to pay for these seats when you renew your license."
+msgid "GitLab Workhorse"
msgstr ""
msgid "GitLab commit"
@@ -11811,6 +12172,21 @@ msgstr ""
msgid "Gitlab Pages"
msgstr ""
+msgid "Gitpod"
+msgstr ""
+
+msgid "Gitpod|Add the URL to your Gitpod instance configured to read your GitLab projects."
+msgstr ""
+
+msgid "Gitpod|Enable Gitpod integration"
+msgstr ""
+
+msgid "Gitpod|Gitpod URL"
+msgstr ""
+
+msgid "Gitpod|e.g. https://gitpod.example.com"
+msgstr ""
+
msgid "Given access %{time_ago}"
msgstr ""
@@ -12318,9 +12694,6 @@ msgstr ""
msgid "GroupSAML|Valid SAML Response"
msgstr ""
-msgid "GroupSAML|With group managed accounts enabled, all the users without a group managed account will be excluded from the group."
-msgstr ""
-
msgid "GroupSAML|With prohibit outer forks flag enabled group members will be able to fork project only inside your group."
msgstr ""
@@ -12534,10 +12907,10 @@ msgstr ""
msgid "GroupsNew|Create group"
msgstr ""
-msgid "GroupsNew|GitLab group export"
+msgid "GroupsNew|Import"
msgstr ""
-msgid "GroupsNew|Import"
+msgid "GroupsNew|Import a GitLab group export file"
msgstr ""
msgid "GroupsNew|Import group"
@@ -12680,6 +13053,9 @@ msgid_plural "Hide charts"
msgstr[0] ""
msgstr[1] ""
+msgid "Hide comments on this file"
+msgstr ""
+
msgid "Hide details"
msgstr ""
@@ -12724,6 +13100,15 @@ msgstr ""
msgid "Highest role:"
msgstr ""
+msgid "HighlightBar|Alert events:"
+msgstr ""
+
+msgid "HighlightBar|Alert start time:"
+msgstr ""
+
+msgid "HighlightBar|Original alert:"
+msgstr ""
+
msgid "History"
msgstr ""
@@ -12901,6 +13286,9 @@ msgstr ""
msgid "If enabled, access to projects will be validated on an external service using their classification label."
msgstr ""
+msgid "If the number of active users exceeds the user limit, you will be charged for the number of %{users_over_license_link} at your next license reconciliation."
+msgstr ""
+
msgid "If there is no previous license or if the previous license has expired, some GitLab functionality will be blocked until a new, valid license is uploaded."
msgstr ""
@@ -12940,9 +13328,6 @@ msgstr ""
msgid "If your HTTP repository is not publicly accessible, add your credentials."
msgstr ""
-msgid "Iglu registry URL (optional)"
-msgstr ""
-
msgid "Ignore"
msgstr ""
@@ -12979,6 +13364,16 @@ msgstr ""
msgid "Import"
msgstr ""
+msgid "Import %d compatible repository"
+msgid_plural "Import %d compatible repositories"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Import %d repository"
+msgid_plural "Import %d repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Import CSV"
msgstr ""
@@ -12988,15 +13383,9 @@ msgstr ""
msgid "Import all compatible projects"
msgstr ""
-msgid "Import all compatible repositories"
-msgstr ""
-
msgid "Import all projects"
msgstr ""
-msgid "Import all repositories"
-msgstr ""
-
msgid "Import an exported GitLab project"
msgstr ""
@@ -13084,6 +13473,9 @@ msgstr ""
msgid "ImportProjects|Error importing repository %{project_safe_import_url} into %{project_full_path} - %{message}"
msgstr ""
+msgid "ImportProjects|Import repositories"
+msgstr ""
+
msgid "ImportProjects|Importing the project failed"
msgstr ""
@@ -13096,7 +13488,7 @@ msgstr ""
msgid "ImportProjects|Requesting your %{provider} repositories failed"
msgstr ""
-msgid "ImportProjects|Select the projects you want to import"
+msgid "ImportProjects|Select the repositories you want to import"
msgstr ""
msgid "ImportProjects|The remote data could not be imported."
@@ -13132,9 +13524,6 @@ msgstr ""
msgid "In order to enable Service Desk for your instance, you must first set up incoming email."
msgstr ""
-msgid "In order to gather accurate feature usage data, it can take 1 to 2 weeks to see your index."
-msgstr ""
-
msgid "In order to personalize your experience with GitLab%{br_tag}we would like to know a bit more about you."
msgstr ""
@@ -13165,18 +13554,30 @@ msgstr ""
msgid "IncidentManagement|Create incident"
msgstr ""
+msgid "IncidentManagement|Critical - S1"
+msgstr ""
+
msgid "IncidentManagement|Date created"
msgstr ""
msgid "IncidentManagement|Display your incidents in a dedicated view"
msgstr ""
+msgid "IncidentManagement|High - S2"
+msgstr ""
+
msgid "IncidentManagement|Incident"
msgstr ""
msgid "IncidentManagement|Incidents"
msgstr ""
+msgid "IncidentManagement|Low - S4"
+msgstr ""
+
+msgid "IncidentManagement|Medium - S3"
+msgstr ""
+
msgid "IncidentManagement|No incidents to display."
msgstr ""
@@ -13189,6 +13590,9 @@ msgstr ""
msgid "IncidentManagement|Published to status page"
msgstr ""
+msgid "IncidentManagement|Severity"
+msgstr ""
+
msgid "IncidentManagement|There are no closed incidents"
msgstr ""
@@ -13198,6 +13602,9 @@ msgstr ""
msgid "IncidentManagement|Unassigned"
msgstr ""
+msgid "IncidentManagement|Unknown"
+msgstr ""
+
msgid "IncidentManagement|Unpublished"
msgstr ""
@@ -13219,6 +13626,15 @@ msgstr ""
msgid "Incidents"
msgstr ""
+msgid "Incident|Alert details"
+msgstr ""
+
+msgid "Incident|Summary"
+msgstr ""
+
+msgid "Incident|There was an issue loading alert data. Please try again."
+msgstr ""
+
msgid "Include a Terms of Service agreement and Privacy Policy that all users must accept."
msgstr ""
@@ -13279,6 +13695,9 @@ msgstr ""
msgid "Information about additional Pages templates and how to install them can be found in our %{pages_getting_started_guide}."
msgstr ""
+msgid "Inherited"
+msgstr ""
+
msgid "Inherited:"
msgstr ""
@@ -13359,7 +13778,22 @@ msgstr ""
msgid "Instance administrators group already exists"
msgstr ""
-msgid "Instance license"
+msgid "InstanceStatistics|Groups"
+msgstr ""
+
+msgid "InstanceStatistics|Issues"
+msgstr ""
+
+msgid "InstanceStatistics|Merge Requests"
+msgstr ""
+
+msgid "InstanceStatistics|Pipelines"
+msgstr ""
+
+msgid "InstanceStatistics|Projects"
+msgstr ""
+
+msgid "InstanceStatistics|Users"
msgstr ""
msgid "Integration"
@@ -13371,6 +13805,12 @@ msgstr ""
msgid "Integrations"
msgstr ""
+msgid "Integrations|%{integration} settings saved and active."
+msgstr ""
+
+msgid "Integrations|%{integration} settings saved, but not active."
+msgstr ""
+
msgid "Integrations|All details"
msgstr ""
@@ -13380,6 +13820,12 @@ msgstr ""
msgid "Integrations|Comment settings:"
msgstr ""
+msgid "Integrations|Connection failed. Please check your settings."
+msgstr ""
+
+msgid "Integrations|Connection successful."
+msgstr ""
+
msgid "Integrations|Default settings are inherited from the group level."
msgstr ""
@@ -13395,6 +13841,15 @@ msgstr ""
msgid "Integrations|Includes commit title and branch"
msgstr ""
+msgid "Integrations|Projects using custom settings will not be impacted unless the project owner chooses to use instance-level defaults."
+msgstr ""
+
+msgid "Integrations|Save settings?"
+msgstr ""
+
+msgid "Integrations|Saving will update the default settings for all projects that are not using custom settings."
+msgstr ""
+
msgid "Integrations|Standard"
msgstr ""
@@ -13527,6 +13982,9 @@ msgstr ""
msgid "Invitation"
msgstr ""
+msgid "Invitation declined"
+msgstr ""
+
msgid "Invite"
msgstr ""
@@ -13578,6 +14036,42 @@ 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|%{linkStart}Read more%{linkEnd} about role permissions"
+msgstr ""
+
+msgid "InviteMembersModal|Access expiration date (optional)"
+msgstr ""
+
+msgid "InviteMembersModal|Cancel"
+msgstr ""
+
+msgid "InviteMembersModal|Choose a role permission"
+msgstr ""
+
+msgid "InviteMembersModal|GitLab member or Email address"
+msgstr ""
+
+msgid "InviteMembersModal|Invite"
+msgstr ""
+
+msgid "InviteMembersModal|Invite team members"
+msgstr ""
+
+msgid "InviteMembersModal|Search for members to invite"
+msgstr ""
+
+msgid "InviteMembersModal|User not invited. Feature coming soon!"
+msgstr ""
+
+msgid "InviteMembersModal|Users were succesfully added"
+msgstr ""
+
+msgid "InviteMembersModal|You're inviting members to the %{group_name} group"
+msgstr ""
+
+msgid "InviteMembers|Invite team members"
+msgstr ""
+
msgid "Invited"
msgstr ""
@@ -13632,10 +14126,13 @@ msgstr ""
msgid "Issue cannot be found."
msgstr ""
+msgid "Issue created from vulnerability %{vulnerability_link}"
+msgstr ""
+
msgid "Issue events"
msgstr ""
-msgid "Issue first depoloyed to production"
+msgid "Issue first deployed to production"
msgstr ""
msgid "Issue label"
@@ -13713,6 +14210,9 @@ msgstr ""
msgid "IssueTracker|Custom issue tracker"
msgstr ""
+msgid "IssueTracker|EWM work items tracker"
+msgstr ""
+
msgid "IssueTracker|Redmine issue tracker"
msgstr ""
@@ -13779,6 +14279,9 @@ msgstr ""
msgid "It looks like you have some draft commits in this branch."
msgstr ""
+msgid "It may be several days before you see feature usage data."
+msgstr ""
+
msgid "It must have a header row and at least two columns: the first column is the issue title and the second column is the issue description. The separator is automatically detected."
msgstr ""
@@ -14061,13 +14564,13 @@ msgstr ""
msgid "Join Zoom meeting"
msgstr ""
-msgid "Jul"
+msgid "Joined %{time_ago}"
msgstr ""
-msgid "July"
+msgid "Jul"
msgstr ""
-msgid "Jump to first unresolved thread"
+msgid "July"
msgstr ""
msgid "Jump to next unresolved thread"
@@ -14103,6 +14606,9 @@ msgstr ""
msgid "Keyboard shortcuts"
msgstr ""
+msgid "KeyboardKey|Ctrl+"
+msgstr ""
+
msgid "Keys"
msgstr ""
@@ -14151,6 +14657,9 @@ msgstr ""
msgid "LDAP Synchronization"
msgstr ""
+msgid "LDAP group settings"
+msgstr ""
+
msgid "LDAP settings"
msgstr ""
@@ -14160,6 +14669,9 @@ msgstr ""
msgid "LDAP sync in progress. This could take a few minutes. Refresh the page to see the changes."
msgstr ""
+msgid "LDAP synchronizations"
+msgstr ""
+
msgid "LFS"
msgstr ""
@@ -14240,7 +14752,16 @@ msgid_plural "Last %d days"
msgstr[0] ""
msgstr[1] ""
-msgid "Last %{days} days"
+msgid "Last 2 weeks"
+msgstr ""
+
+msgid "Last 30 days"
+msgstr ""
+
+msgid "Last 60 days"
+msgstr ""
+
+msgid "Last 90 days"
msgstr ""
msgid "Last Accessed On"
@@ -14318,6 +14839,9 @@ msgstr ""
msgid "Last used on:"
msgstr ""
+msgid "Last week"
+msgstr ""
+
msgid "LastCommit|authored"
msgstr ""
@@ -14333,6 +14857,9 @@ msgstr ""
msgid "Latest pipeline for the most recent commit on this branch"
msgstr ""
+msgid "Launch a ready-to-code development environment for your project."
+msgstr ""
+
msgid "Lead"
msgstr ""
@@ -14713,6 +15240,9 @@ msgstr ""
msgid "List of all merge commits"
msgstr ""
+msgid "List options"
+msgstr ""
+
msgid "List settings"
msgstr ""
@@ -14725,9 +15255,6 @@ msgstr ""
msgid "List your Bitbucket Server repositories"
msgstr ""
-msgid "Lists"
-msgstr ""
-
msgid "Live preview"
msgstr ""
@@ -14974,6 +15501,12 @@ msgstr ""
msgid "Mark as done"
msgstr ""
+msgid "Mark as draft"
+msgstr ""
+
+msgid "Mark as ready"
+msgstr ""
+
msgid "Mark as resolved"
msgstr ""
@@ -14995,6 +15528,24 @@ msgstr ""
msgid "Markdown is supported"
msgstr ""
+msgid "MarkdownEditor|Add a link (%{modifierKey}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add a link (%{modifier_key}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifierKey}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifier_key}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifierKey}I)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifier_key}I)"
+msgstr ""
+
msgid "Marked For Deletion At - %{deletion_time}"
msgstr ""
@@ -15079,7 +15630,25 @@ msgstr ""
msgid "Max access level"
msgstr ""
-msgid "Max seats used"
+msgid "Max role"
+msgstr ""
+
+msgid "Max size 15 MB"
+msgstr ""
+
+msgid "Maximum Conan package file size in bytes"
+msgstr ""
+
+msgid "Maximum Maven package file size in bytes"
+msgstr ""
+
+msgid "Maximum NPM package file size in bytes"
+msgstr ""
+
+msgid "Maximum NuGet package file size in bytes"
+msgstr ""
+
+msgid "Maximum PyPI package file size in bytes"
msgstr ""
msgid "Maximum Users:"
@@ -15211,6 +15780,18 @@ msgstr ""
msgid "Members with access to %{strong_start}%{group_name}%{strong_end}"
msgstr ""
+msgid "Members|%{time} by %{user}"
+msgstr ""
+
+msgid "Members|Expired"
+msgstr ""
+
+msgid "Members|No expiration set"
+msgstr ""
+
+msgid "Members|in %{time}"
+msgstr ""
+
msgid "Memory Usage"
msgstr ""
@@ -15397,9 +15978,6 @@ msgstr ""
msgid "MergeRequests|Thread will be unresolved"
msgstr ""
-msgid "MergeRequests|Toggle comments for this file"
-msgstr ""
-
msgid "MergeRequests|View file @ %{commitId}"
msgstr ""
@@ -15460,6 +16038,9 @@ msgstr ""
msgid "Merging immediately isn't recommended as it may negatively impact the existing merge train. Read the %{docsLinkStart}documentation%{docsLinkEnd} for more information."
msgstr ""
+msgid "Message"
+msgstr ""
+
msgid "Messages"
msgstr ""
@@ -15845,18 +16426,12 @@ msgid_plural "Milestones"
msgstr[0] ""
msgstr[1] ""
-msgid "Milestone does not support burnup charts"
-msgstr ""
-
msgid "Milestone lists not available with your current license"
msgstr ""
msgid "Milestone lists show all issues from the selected milestone."
msgstr ""
-msgid "Milestone must have a start and due date"
-msgstr ""
-
msgid "MilestoneSidebar|Closed:"
msgstr ""
@@ -16223,6 +16798,9 @@ msgstr ""
msgid "Namespace"
msgstr ""
+msgid "Namespace ID:"
+msgstr ""
+
msgid "Namespace is empty"
msgstr ""
@@ -16307,6 +16885,9 @@ msgstr ""
msgid "NetworkPolicies|Allow all outbound traffic from %{selector} to %{ruleSelector} on %{ports}"
msgstr ""
+msgid "NetworkPolicies|Are you sure you want to delete this policy? This action cannot be undone."
+msgstr ""
+
msgid "NetworkPolicies|Choose whether to enforce this policy."
msgstr ""
@@ -16316,12 +16897,21 @@ msgstr ""
msgid "NetworkPolicies|Define this policy's location, conditions and actions."
msgstr ""
+msgid "NetworkPolicies|Delete policy"
+msgstr ""
+
+msgid "NetworkPolicies|Delete policy: %{policy}"
+msgstr ""
+
msgid "NetworkPolicies|Deny all traffic"
msgstr ""
msgid "NetworkPolicies|Description"
msgstr ""
+msgid "NetworkPolicies|Edit policy"
+msgstr ""
+
msgid "NetworkPolicies|Editor mode"
msgstr ""
@@ -16349,6 +16939,9 @@ msgstr ""
msgid "NetworkPolicies|Name"
msgstr ""
+msgid "NetworkPolicies|Namespace"
+msgstr ""
+
msgid "NetworkPolicies|Network Policy"
msgstr ""
@@ -16400,6 +16993,9 @@ msgstr ""
msgid "NetworkPolicies|Rules"
msgstr ""
+msgid "NetworkPolicies|Save changes"
+msgstr ""
+
msgid "NetworkPolicies|Something went wrong, failed to update policy"
msgstr ""
@@ -16412,6 +17008,9 @@ msgstr ""
msgid "NetworkPolicies|Traffic that does not match any rule will be blocked."
msgstr ""
+msgid "NetworkPolicies|Unable to parse policy"
+msgstr ""
+
msgid "NetworkPolicies|YAML editor"
msgstr ""
@@ -16525,6 +17124,9 @@ msgstr ""
msgid "New Snippet"
msgstr ""
+msgid "New Test Case"
+msgstr ""
+
msgid "New User"
msgstr ""
@@ -16624,6 +17226,9 @@ msgstr ""
msgid "New tag"
msgstr ""
+msgid "New test case"
+msgstr ""
+
msgid "New users set to external"
msgstr ""
@@ -16696,7 +17301,7 @@ msgstr ""
msgid "No changes"
msgstr ""
-msgid "No changes between %{ref_start}%{source_branch}%{ref_end} and %{ref_start}%{target_branch}%{ref_end}"
+msgid "No changes between %{sourceBranch} and %{targetBranch}"
msgstr ""
msgid "No child epics match applied filters"
@@ -16711,6 +17316,9 @@ msgstr ""
msgid "No containers available"
msgstr ""
+msgid "No content to show"
+msgstr ""
+
msgid "No contributions"
msgstr ""
@@ -16786,9 +17394,6 @@ msgstr ""
msgid "No license. All rights reserved"
msgstr ""
-msgid "No licenses found."
-msgstr ""
-
msgid "No matches found"
msgstr ""
@@ -16801,6 +17406,9 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No members found"
+msgstr ""
+
msgid "No merge requests found"
msgstr ""
@@ -16822,6 +17430,9 @@ msgstr ""
msgid "No parent group"
msgstr ""
+msgid "No plan"
+msgstr ""
+
msgid "No pods available"
msgstr ""
@@ -16918,6 +17529,12 @@ msgstr ""
msgid "Not Implemented"
msgstr ""
+msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+msgstr ""
+
+msgid "Not all browsers support WebAuthn. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even from an unsupported browser."
+msgstr ""
+
msgid "Not all data has been processed yet, the accuracy of the chart for the selected timeframe is limited."
msgstr ""
@@ -17014,6 +17631,9 @@ msgstr ""
msgid "Notification settings saved"
msgstr ""
+msgid "NotificationEvent|Change reviewer merge request"
+msgstr ""
+
msgid "NotificationEvent|Close issue"
msgstr ""
@@ -17176,10 +17796,7 @@ msgstr ""
msgid "On track"
msgstr ""
-msgid "OnDemandScans|Attached branch"
-msgstr ""
-
-msgid "OnDemandScans|Attached branch is where the scan job runs."
+msgid "OnDemandScans|Could not fetch scanner profiles. Please refresh the page, or try again later."
msgstr ""
msgid "OnDemandScans|Could not fetch site profiles. Please refresh the page, or try again later."
@@ -17188,6 +17805,9 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
+msgid "OnDemandScans|Create a new scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Create a new site profile"
msgstr ""
@@ -17200,6 +17820,9 @@ msgstr ""
msgid "OnDemandScans|New on-demand DAST scan"
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 ""
@@ -17209,16 +17832,10 @@ msgstr ""
msgid "OnDemandScans|On-demand scans run outside the DevOps cycle and find vulnerabilities in your projects. %{learnMoreLinkStart}Learn more%{learnMoreLinkEnd}"
msgstr ""
-msgid "OnDemandScans|Only a passive scan can be performed on demand."
-msgstr ""
-
-msgid "OnDemandScans|Passive"
-msgstr ""
-
msgid "OnDemandScans|Run scan"
msgstr ""
-msgid "OnDemandScans|Scan mode"
+msgid "OnDemandScans|Scanner profile"
msgstr ""
msgid "OnDemandScans|Scanner settings"
@@ -17230,9 +17847,15 @@ msgstr ""
msgid "OnDemandScans|Select one of the existing profiles"
msgstr ""
+msgid "OnDemandScans|Site profile"
+msgstr ""
+
msgid "OnDemandScans|Site profiles"
msgstr ""
+msgid "OnDemandScans|Use existing scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Use existing site profile"
msgstr ""
@@ -17331,9 +17954,6 @@ msgstr ""
msgid "Open Selection"
msgstr ""
-msgid "Open Web IDE"
-msgstr ""
-
msgid "Open comment type dropdown"
msgstr ""
@@ -17439,6 +18059,9 @@ msgstr ""
msgid "Origin"
msgstr ""
+msgid "Orphaned member"
+msgstr ""
+
msgid "Other Labels"
msgstr ""
@@ -17454,6 +18077,9 @@ msgstr ""
msgid "Other visibility settings have been disabled by the administrator."
msgstr ""
+msgid "Our documentation includes an example DevOps Score report."
+msgstr ""
+
msgid "Out-of-compliance with this project's policies and should be removed"
msgstr ""
@@ -17478,6 +18104,9 @@ msgstr ""
msgid "Overwrite diverged branches"
msgstr ""
+msgid "Owned by %{image_tag}"
+msgstr ""
+
msgid "Owned by anyone"
msgstr ""
@@ -17499,6 +18128,9 @@ msgstr ""
msgid "Package deleted successfully"
msgstr ""
+msgid "Package file size limits"
+msgstr ""
+
msgid "Package recipe already exists"
msgstr ""
@@ -17514,9 +18146,6 @@ msgstr ""
msgid "Package type must be PyPi"
msgstr ""
-msgid "Package was removed"
-msgstr ""
-
msgid "PackageRegistry|%{name} version %{version} was created %{datetime}"
msgstr ""
@@ -17658,12 +18287,18 @@ msgstr ""
msgid "PackageRegistry|NuGet Command"
msgstr ""
+msgid "PackageRegistry|Package Registry"
+msgstr ""
+
msgid "PackageRegistry|Pip Command"
msgstr ""
msgid "PackageRegistry|Pipeline %{link} triggered %{datetime} by %{author}"
msgstr ""
+msgid "PackageRegistry|Publish and share packages for a variety of common package managers. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "PackageRegistry|Published to the %{project} Package Registry %{datetime}"
msgstr ""
@@ -17763,6 +18398,9 @@ msgstr ""
msgid "Page not found"
msgstr ""
+msgid "Page settings"
+msgstr ""
+
msgid "Page was successfully deleted"
msgstr ""
@@ -17904,7 +18542,7 @@ msgstr ""
msgid "Paste issue link"
msgstr ""
-msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Don't use your private SSH key."
+msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Do not paste your private SSH key, as that can compromise your identity."
msgstr ""
msgid "Patch to apply"
@@ -17931,6 +18569,9 @@ msgstr ""
msgid "Pending"
msgstr ""
+msgid "Pending comments"
+msgstr ""
+
msgid "People without permission will never get a notification and won't be able to comment."
msgstr ""
@@ -18129,6 +18770,9 @@ msgstr ""
msgid "Pipelines|Build with confidence"
msgstr ""
+msgid "Pipelines|By revoking a trigger you will break any processes making use of it. Are you sure?"
+msgstr ""
+
msgid "Pipelines|CI Lint"
msgstr ""
@@ -18141,6 +18785,15 @@ msgstr ""
msgid "Pipelines|Continuous Integration can help catch bugs by running your tests automatically, while Continuous Deployment can help you deliver code to your product environment."
msgstr ""
+msgid "Pipelines|Copy trigger token"
+msgstr ""
+
+msgid "Pipelines|Description"
+msgstr ""
+
+msgid "Pipelines|Edit"
+msgstr ""
+
msgid "Pipelines|Get started with Pipelines"
msgstr ""
@@ -18156,15 +18809,27 @@ msgstr ""
msgid "Pipelines|It is recommended the code is reviewed thoroughly before running this pipeline with the parent project's CI resource."
msgstr ""
+msgid "Pipelines|Last Used"
+msgstr ""
+
msgid "Pipelines|Loading Pipelines"
msgstr ""
msgid "Pipelines|More Information"
msgstr ""
+msgid "Pipelines|No triggers have been created yet. Add one using the form above."
+msgstr ""
+
+msgid "Pipelines|Owner"
+msgstr ""
+
msgid "Pipelines|Project cache successfully reset."
msgstr ""
+msgid "Pipelines|Revoke"
+msgstr ""
+
msgid "Pipelines|Run Pipeline"
msgstr ""
@@ -18189,6 +18854,15 @@ msgstr ""
msgid "Pipelines|This project is not currently set up to run pipelines."
msgstr ""
+msgid "Pipelines|Token"
+msgstr ""
+
+msgid "Pipelines|Trigger user has insufficient permissions to project"
+msgstr ""
+
+msgid "Pipelines|invalid"
+msgstr ""
+
msgid "Pipelines|parent"
msgstr ""
@@ -18447,10 +19121,10 @@ msgstr ""
msgid "Please provide attributes to update"
msgstr ""
-msgid "Please refer to %{docs_url}"
+msgid "Please reach out if you have any questions and we'll be happy to assist."
msgstr ""
-msgid "Please retype the email address."
+msgid "Please refer to %{docs_url}"
msgstr ""
msgid "Please select"
@@ -18480,6 +19154,9 @@ msgstr ""
msgid "Please set a new password before proceeding."
msgstr ""
+msgid "Please share your feedback about %{featureName} %{linkStart}in this issue%{linkEnd} to help us improve the experience."
+msgstr ""
+
msgid "Please solve the reCAPTCHA"
msgstr ""
@@ -18783,6 +19460,9 @@ msgstr ""
msgid "Profiles| You are going to change the username %{currentUsernameBold} to %{newUsernameBold}. Profile and projects will be redirected to the %{newUsername} namespace but this redirect will expire once the %{currentUsername} namespace is registered by another user or group. Please update your Git repository remotes as soon as possible."
msgstr ""
+msgid "Profiles|%{provider} Active"
+msgstr ""
+
msgid "Profiles|@username"
msgstr ""
@@ -18834,7 +19514,7 @@ msgstr ""
msgid "Profiles|Commit email"
msgstr ""
-msgid "Profiles|Connect"
+msgid "Profiles|Connect %{provider}"
msgstr ""
msgid "Profiles|Connected Accounts"
@@ -18858,6 +19538,9 @@ msgstr ""
msgid "Profiles|Disconnect"
msgstr ""
+msgid "Profiles|Disconnect %{provider}"
+msgstr ""
+
msgid "Profiles|Do not show on profile"
msgstr ""
@@ -18882,7 +19565,7 @@ msgstr ""
msgid "Profiles|Full name"
msgstr ""
-msgid "Profiles|Give your individual key a title. This will be publically visible."
+msgid "Profiles|Give your individual key a title."
msgstr ""
msgid "Profiles|Include private contributions on my profile"
@@ -18972,7 +19655,7 @@ msgstr ""
msgid "Profiles|The maximum file size allowed is 200KB."
msgstr ""
-msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it?"
+msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it? It will be publicly visible."
msgstr ""
msgid "Profiles|This email will be displayed on your public profile"
@@ -19047,6 +19730,9 @@ msgstr ""
msgid "Profiles|You don't have access to delete this user."
msgstr ""
+msgid "Profiles|You must transfer ownership or delete groups you are an owner of before you can delete your account"
+msgstr ""
+
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
@@ -19635,6 +20321,9 @@ msgstr ""
msgid "ProjectTemplates|GitLab Cluster Management"
msgstr ""
+msgid "ProjectTemplates|Gitpod/Spring Petclinic"
+msgstr ""
+
msgid "ProjectTemplates|Go Micro"
msgstr ""
@@ -20244,6 +20933,9 @@ msgstr ""
msgid "Publish to status page"
msgstr ""
+msgid "Published"
+msgstr ""
+
msgid "Published on status page"
msgstr ""
@@ -20361,9 +21053,15 @@ msgstr ""
msgid "Quick range"
msgstr ""
+msgid "Quickly and easily edit multiple files in your project."
+msgstr ""
+
msgid "README"
msgstr ""
+msgid "Rails"
+msgstr ""
+
msgid "Rake Tasks Help"
msgstr ""
@@ -20483,10 +21181,13 @@ msgstr ""
msgid "Register Two-Factor Authenticator"
msgstr ""
-msgid "Register U2F device"
+msgid "Register Universal Two-Factor (U2F) Device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register WebAuthn Device"
+msgstr ""
+
+msgid "Register device"
msgstr ""
msgid "Register for GitLab"
@@ -20498,9 +21199,6 @@ msgstr ""
msgid "Register with two-factor app"
msgstr ""
-msgid "Registration"
-msgstr ""
-
msgid "Registration|Checkout"
msgstr ""
@@ -20617,9 +21315,6 @@ msgstr ""
msgid "Release|Something went wrong while saving the release details"
msgstr ""
-msgid "Remediated: needs review"
-msgstr ""
-
msgid "Remediations"
msgstr ""
@@ -20725,6 +21420,9 @@ msgstr ""
msgid "Remove priority"
msgstr ""
+msgid "Remove report"
+msgstr ""
+
msgid "Remove secondary node"
msgstr ""
@@ -20737,6 +21435,12 @@ msgstr ""
msgid "Remove time estimate"
msgstr ""
+msgid "Remove user & report"
+msgstr ""
+
+msgid "Remove user from group"
+msgstr ""
+
msgid "Removed"
msgstr ""
@@ -20818,9 +21522,6 @@ msgstr ""
msgid "Removes time estimate."
msgstr ""
-msgid "Removing license…"
-msgstr ""
-
msgid "Removing this group also removes all child projects, including archived projects, and their resources."
msgstr ""
@@ -20905,6 +21606,9 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
+msgid "Reported by %{reporter}"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -20991,6 +21695,27 @@ msgstr ""
msgid "Repositories"
msgstr ""
+msgid "Repositories Analytics"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download Historic Test Coverage Data"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download historic test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Historic Test Coverage Data is available in raw format (.csv) for further analysis."
+msgstr ""
+
+msgid "RepositoriesAnalytics|Test Code Coverage"
+msgstr ""
+
+msgid "RepositoriesAnalytics|There was an error fetching the projects."
+msgstr ""
+
msgid "Repository"
msgstr ""
@@ -21069,9 +21794,15 @@ msgstr ""
msgid "Request parameter %{param} is missing."
msgstr ""
+msgid "Request review from"
+msgstr ""
+
msgid "Request to link SAML account must be authorized"
msgstr ""
+msgid "Requested"
+msgstr ""
+
msgid "Requested %{time_ago}"
msgstr ""
@@ -21090,6 +21821,9 @@ msgstr ""
msgid "Requests to these domain(s)/address(es) on the local network will be allowed when local requests from hooks and services are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 or 127.0.0.0/28 are supported. Domain wildcards are not supported currently. Use comma, semicolon, or newline to separate multiple entries. The allowlist can hold a maximum of 1000 entries. Domains should use IDNA encoding. Ex: example.com, 192.168.1.1, 127.0.0.0/28, xn--itlab-j1a.com."
msgstr ""
+msgid "Require admin approval for new sign-ups"
+msgstr ""
+
msgid "Require all users in this group to setup Two-factor authentication"
msgstr ""
@@ -21217,9 +21951,6 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
-msgid "Resolved by %{resolvedByName}"
-msgstr ""
-
msgid "Resolves IP addresses once and uses them to submit requests"
msgstr ""
@@ -21339,6 +22070,14 @@ msgstr ""
msgid "ReviewApp|Enable Review App"
msgstr ""
+msgid "Reviewer"
+msgid_plural "%d Reviewers"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Reviewer(s)"
+msgstr ""
+
msgid "Reviewing"
msgstr ""
@@ -21378,6 +22117,9 @@ msgstr ""
msgid "Rook"
msgstr ""
+msgid "Ruby"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -21456,6 +22198,63 @@ msgstr ""
msgid "Runners page."
msgstr ""
+msgid "Runners|Active"
+msgstr ""
+
+msgid "Runners|Architecture"
+msgstr ""
+
+msgid "Runners|Can run untagged jobs"
+msgstr ""
+
+msgid "Runners|Description"
+msgstr ""
+
+msgid "Runners|Group"
+msgstr ""
+
+msgid "Runners|IP Address"
+msgstr ""
+
+msgid "Runners|Last contact"
+msgstr ""
+
+msgid "Runners|Locked to this project"
+msgstr ""
+
+msgid "Runners|Maximum job timeout"
+msgstr ""
+
+msgid "Runners|Name"
+msgstr ""
+
+msgid "Runners|Platform"
+msgstr ""
+
+msgid "Runners|Property Name"
+msgstr ""
+
+msgid "Runners|Protected"
+msgstr ""
+
+msgid "Runners|Revision"
+msgstr ""
+
+msgid "Runners|Shared"
+msgstr ""
+
+msgid "Runners|Specific"
+msgstr ""
+
+msgid "Runners|Tags"
+msgstr ""
+
+msgid "Runners|Value"
+msgstr ""
+
+msgid "Runners|Version"
+msgstr ""
+
msgid "Runners|You have used %{quotaUsed} out of %{quotaLimit} of your shared Runners pipeline minutes."
msgstr ""
@@ -21468,6 +22267,9 @@ msgstr ""
msgid "Runs a number of housekeeping tasks within the current repository, such as compressing file revisions and removing unreachable objects."
msgstr ""
+msgid "SAML"
+msgstr ""
+
msgid "SAML SSO"
msgstr ""
@@ -21519,6 +22321,9 @@ msgstr ""
msgid "Save"
msgstr ""
+msgid "Save %{name} size limits"
+msgstr ""
+
msgid "Save Changes"
msgstr ""
@@ -21549,9 +22354,6 @@ msgstr ""
msgid "Save space and find tags in the Container Registry more easily. Enable the cleanup policy to remove stale tags and keep only the ones you need."
msgstr ""
-msgid "Save template"
-msgstr ""
-
msgid "Save variables"
msgstr ""
@@ -21594,9 +22396,6 @@ msgstr ""
msgid "Scope"
msgstr ""
-msgid "Scope not supported with disabled 'users_search' feature!"
-msgstr ""
-
msgid "Scoped issue boards"
msgstr ""
@@ -21723,9 +22522,6 @@ msgstr ""
msgid "Search requirements"
msgstr ""
-msgid "Search results…"
-msgstr ""
-
msgid "Search users"
msgstr ""
@@ -21798,6 +22594,11 @@ msgid_plural "SearchResults|commits"
msgstr[0] ""
msgstr[1] ""
+msgid "SearchResults|epic"
+msgid_plural "SearchResults|epics"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "SearchResults|issue"
msgid_plural "SearchResults|issues"
msgstr[0] ""
@@ -21842,10 +22643,10 @@ msgstr ""
msgid "Seat Link is disabled, and cannot be configured through this form."
msgstr ""
-msgid "Seats currently in use"
+msgid "Seats usage data as of %{last_enqueue_time}"
msgstr ""
-msgid "Seats in license"
+msgid "Seats usage data is updated every day at 12:00pm UTC"
msgstr ""
msgid "Secondary"
@@ -21899,6 +22700,9 @@ msgstr ""
msgid "SecurityConfiguration|Available for on-demand DAST"
msgstr ""
+msgid "SecurityConfiguration|By default, all analyzers are applied in order to cover all languages across your project, and only run if the language is detected in the Merge Request."
+msgstr ""
+
msgid "SecurityConfiguration|Configure"
msgstr ""
@@ -21929,16 +22733,19 @@ msgstr ""
msgid "SecurityConfiguration|Manage"
msgstr ""
+msgid "SecurityConfiguration|More information"
+msgstr ""
+
msgid "SecurityConfiguration|Not enabled"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|Security Control"
+msgid "SecurityConfiguration|SAST Configuration"
msgstr ""
-msgid "SecurityConfiguration|See documentation"
+msgid "SecurityConfiguration|Security Control"
msgstr ""
msgid "SecurityConfiguration|Status"
@@ -21950,6 +22757,9 @@ msgstr ""
msgid "SecurityConfiguration|Using custom settings. You won't receive automatic updates on this variable. %{anchorStart}Restore to default%{anchorEnd}"
msgstr ""
+msgid "SecurityConfiguration|View history"
+msgstr ""
+
msgid "SecurityConfiguration|You can quickly enable all security scanning tools by enabling %{linkStart}Auto DevOps%{linkEnd}."
msgstr ""
@@ -22028,9 +22838,6 @@ msgstr ""
msgid "SecurityReports|Learn more about setting up your dashboard"
msgstr ""
-msgid "SecurityReports|Load more vulnerabilities"
-msgstr ""
-
msgid "SecurityReports|Monitor vulnerabilities in your code"
msgstr ""
@@ -22310,7 +23117,7 @@ msgstr ""
msgid "Select status"
msgstr ""
-msgid "Select strategy activation method"
+msgid "Select strategy activation method."
msgstr ""
msgid "Select subscription"
@@ -22325,7 +23132,7 @@ msgstr ""
msgid "Select the custom project template source group."
msgstr ""
-msgid "Select timeframe"
+msgid "Select the environment scope for this feature flag."
msgstr ""
msgid "Select timezone"
@@ -22574,6 +23381,9 @@ msgstr ""
msgid "Set iteration"
msgstr ""
+msgid "Set limit to 0 to allow any file size."
+msgstr ""
+
msgid "Set max session time for web terminal."
msgstr ""
@@ -22652,10 +23462,13 @@ msgstr ""
msgid "Set up a %{type} Runner manually"
msgstr ""
+msgid "Set up a hardware device as a second factor to sign in."
+msgstr ""
+
msgid "Set up assertions/attributes/claims (email, first_name, last_name) and NameID according to %{docsLinkStart}the documentation %{icon}%{docsLinkEnd}"
msgstr ""
-msgid "Set up new U2F device"
+msgid "Set up new device"
msgstr ""
msgid "Set up new password"
@@ -22724,6 +23537,9 @@ msgstr ""
msgid "Sets weight to %{weight}."
msgstr ""
+msgid "Setting this to 0 means using the system default timeout value."
+msgstr ""
+
msgid "Settings"
msgstr ""
@@ -22739,6 +23555,15 @@ msgstr ""
msgid "Severity"
msgstr ""
+msgid "SeverityWidget|Severity"
+msgstr ""
+
+msgid "SeverityWidget|Severity: %{severity}"
+msgstr ""
+
+msgid "SeverityWidget|There was an error while updating severity."
+msgstr ""
+
msgid "Shards (%{shards})"
msgstr ""
@@ -22784,6 +23609,9 @@ msgstr ""
msgid "Show all requirements."
msgstr ""
+msgid "Show all test cases."
+msgstr ""
+
msgid "Show archived projects"
msgstr ""
@@ -22796,6 +23624,9 @@ msgstr ""
msgid "Show comments"
msgstr ""
+msgid "Show comments on this file"
+msgstr ""
+
msgid "Show comments only"
msgstr ""
@@ -22841,6 +23672,12 @@ msgstr ""
msgid "Show parent subgroups"
msgstr ""
+msgid "Show the Closed list"
+msgstr ""
+
+msgid "Show the Open list"
+msgstr ""
+
msgid "Show whitespace changes"
msgstr ""
@@ -22884,9 +23721,6 @@ msgstr ""
msgid "Sidebar|Assign health status"
msgstr ""
-msgid "Sidebar|Change weight"
-msgstr ""
-
msgid "Sidebar|Health status"
msgstr ""
@@ -23070,6 +23904,9 @@ msgstr ""
msgid "Snippets|Add another file %{num}/%{total}"
msgstr ""
+msgid "Snippets|Authored %{time_ago} by %{author}"
+msgstr ""
+
msgid "Snippets|Delete file"
msgstr ""
@@ -23097,6 +23934,9 @@ msgstr ""
msgid "Solution"
msgstr ""
+msgid "Some changes are not shown"
+msgstr ""
+
msgid "Some child epics may be hidden due to applied filters"
msgstr ""
@@ -23463,6 +24303,12 @@ msgstr ""
msgid "Source (branch or tag)"
msgstr ""
+msgid "Source Branch"
+msgstr ""
+
+msgid "Source branch: %{source_branch_open}%{source_branch}%{source_branch_close}"
+msgstr ""
+
msgid "Source code"
msgstr ""
@@ -23628,9 +24474,6 @@ msgstr ""
msgid "Start and due date"
msgstr ""
-msgid "Start by choosing a group to see how your team is spending time. You can then drill down to the project level."
-msgstr ""
-
msgid "Start by choosing a group to start exploring the merge requests in that group. You can then proceed to filter by projects, labels, milestones and authors."
msgstr ""
@@ -23712,18 +24555,27 @@ msgstr ""
msgid "StaticSiteEditor|3. Assign a person to review and accept the merge request."
msgstr ""
+msgid "StaticSiteEditor|A link to view the merge request will appear once ready."
+msgstr ""
+
msgid "StaticSiteEditor|An error occurred while submitting your changes."
msgstr ""
msgid "StaticSiteEditor|Branch could not be created."
msgstr ""
+msgid "StaticSiteEditor|Copy update"
+msgstr ""
+
msgid "StaticSiteEditor|Could not commit the content changes."
msgstr ""
msgid "StaticSiteEditor|Could not create merge request."
msgstr ""
+msgid "StaticSiteEditor|Creating your merge request"
+msgstr ""
+
msgid "StaticSiteEditor|Incompatible file content"
msgstr ""
@@ -23745,6 +24597,9 @@ msgstr ""
msgid "StaticSiteEditor|View documentation"
msgstr ""
+msgid "StaticSiteEditor|You can set an assignee to get your changes reviewed and deployed once your merge request is created."
+msgstr ""
+
msgid "StaticSiteEditor|Your merge request has been created"
msgstr ""
@@ -23874,15 +24729,15 @@ msgstr ""
msgid "Submit %{humanized_resource_name}"
msgstr ""
-msgid "Submit Changes"
-msgstr ""
-
msgid "Submit a review"
msgstr ""
msgid "Submit as spam"
msgstr ""
+msgid "Submit changes"
+msgstr ""
+
msgid "Submit feedback"
msgstr ""
@@ -24036,6 +24891,9 @@ msgstr ""
msgid "Successfully deleted U2F device."
msgstr ""
+msgid "Successfully deleted WebAuthn device."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -24354,9 +25212,6 @@ msgstr ""
msgid "Template to append to all Service Desk issues"
msgstr ""
-msgid "Template was successfully saved."
-msgstr ""
-
msgid "Templates"
msgstr ""
@@ -24435,10 +25290,28 @@ msgid_plural "Test coverage: %d hits"
msgstr[0] ""
msgstr[1] ""
-msgid "Test failed."
+msgid "Test settings"
msgstr ""
-msgid "Test settings and save changes"
+msgid "TestCases|New Test Case"
+msgstr ""
+
+msgid "TestCases|New test case"
+msgstr ""
+
+msgid "TestCases|Search test cases"
+msgstr ""
+
+msgid "TestCases|Something went wrong while creating a test case."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching count of test cases."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching test cases list."
+msgstr ""
+
+msgid "TestCases|Submit test case"
msgstr ""
msgid "TestHooks|Ensure one of your projects has merge requests."
@@ -24504,6 +25377,9 @@ msgstr ""
msgid "Thank you for signing up for your free trial! You will get additional instructions in your inbox shortly."
msgstr ""
+msgid "Thank you for your business."
+msgstr ""
+
msgid "Thank you for your feedback!"
msgstr ""
@@ -24563,9 +25439,6 @@ msgstr ""
msgid "The URL to use for connecting to Elasticsearch. Use a comma-separated list to support clustering (e.g., \"http://localhost:9200, http://localhost:9201\")."
msgstr ""
-msgid "The Web IDE offers advanced syntax highlighting capabilities and more."
-msgstr ""
-
msgid "The X509 Certificate to use when mutual TLS is required to communicate with the external authorization service. If left blank, the server certificate is still validated when accessing over HTTPS."
msgstr ""
@@ -24676,6 +25549,9 @@ msgstr ""
msgid "The form contains the following error:"
msgstr ""
+msgid "The form contains the following warning:"
+msgstr ""
+
msgid "The global settings require you to enable Two-Factor Authentication for your account."
msgstr ""
@@ -24790,9 +25666,6 @@ msgstr ""
msgid "The private key to use when a client certificate is provided. This value is encrypted at rest."
msgstr ""
-msgid "The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The project can be accessed by any logged in user."
msgstr ""
@@ -24829,7 +25702,7 @@ msgstr ""
msgid "The remote repository is being updated..."
msgstr ""
-msgid "The repository can be commited to, and issues, comments and other entities can be created."
+msgid "The repository can be committed to, and issues, comments and other entities can be created."
msgstr ""
msgid "The repository for this project does not exist."
@@ -24883,9 +25756,6 @@ msgstr ""
msgid "The time taken by each data entry gathered by that stage."
msgstr ""
-msgid "The total stage shows the time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The update action will time out after %{number_of_minutes} minutes. For big repositories, use a clone/push combination."
msgstr ""
@@ -24949,6 +25819,9 @@ msgstr ""
msgid "There are no archived requirements"
msgstr ""
+msgid "There are no archived test cases"
+msgstr ""
+
msgid "There are no changes"
msgstr ""
@@ -24988,6 +25861,9 @@ msgstr ""
msgid "There are no open requirements"
msgstr ""
+msgid "There are no open test cases"
+msgstr ""
+
msgid "There are no packages yet"
msgstr ""
@@ -25000,6 +25876,9 @@ msgstr ""
msgid "There is a limit of %{ci_project_subscriptions_limit} subscriptions from or to a project."
msgstr ""
+msgid "There is already a To-Do for this design."
+msgstr ""
+
msgid "There is already a repository with that name on disk"
msgstr ""
@@ -25018,6 +25897,9 @@ msgstr ""
msgid "There was a problem communicating with your device."
msgstr ""
+msgid "There was a problem fetching branches."
+msgstr ""
+
msgid "There was a problem fetching groups."
msgstr ""
@@ -25246,9 +26128,15 @@ msgstr ""
msgid "This action can lead to data loss. To prevent accidental actions we ask you to confirm your intention."
msgstr ""
+msgid "This action cannot be undone, and will permanently delete the %{key} SSH key"
+msgstr ""
+
msgid "This action cannot be undone. You will lose the project's repository and all content: issues, merge requests, etc."
msgstr ""
+msgid "This action has been performed too many times. Try again later."
+msgstr ""
+
msgid "This action will %{strongOpen}permanently delete%{strongClose} %{codeOpen}%{project}%{codeClose} %{strongOpen}immediately%{strongClose}, including its repositories and all content: issues, merge requests, etc."
msgstr ""
@@ -25276,9 +26164,6 @@ msgstr ""
msgid "This board's scope is reduced"
msgstr ""
-msgid "This branch has changed since you started editing. Would you like to create a new branch?"
-msgstr ""
-
msgid "This chart could not be displayed"
msgstr ""
@@ -25405,15 +26290,9 @@ msgstr ""
msgid "This is a security log of important events involving your account."
msgstr ""
-msgid "This is the author's first Merge Request to this project."
-msgstr ""
-
msgid "This is the highest peak of users on your installation since the license started."
msgstr ""
-msgid "This is the maximum number of users that have existed at the same time since the license started. This is the minimum number of seats you will need to buy when you renew your license."
-msgstr ""
-
msgid "This is the number of currently active users on your installation, and this is the minimum number you need to purchase when you renew your license."
msgstr ""
@@ -25645,6 +26524,15 @@ msgstr ""
msgid "This user has no identities"
msgstr ""
+msgid "This user has previously committed to the %{name} project."
+msgstr ""
+
+msgid "This user has the %{access} role in the %{name} project."
+msgstr ""
+
+msgid "This user is the author of this %{noteable}."
+msgstr ""
+
msgid "This user will be the author of all events in the activity feed that are the result of an update, like new branches being created or new commits being pushed to existing branches."
msgstr ""
@@ -25675,6 +26563,9 @@ msgstr ""
msgid "Threat Monitoring"
msgstr ""
+msgid "ThreatMonitoring|All Environments"
+msgstr ""
+
msgid "ThreatMonitoring|Anomalous Requests"
msgstr ""
@@ -25702,9 +26593,6 @@ msgstr ""
msgid "ThreatMonitoring|Operations Per Second"
msgstr ""
-msgid "ThreatMonitoring|Overview"
-msgstr ""
-
msgid "ThreatMonitoring|Packet Activity"
msgstr ""
@@ -25723,6 +26611,9 @@ msgstr ""
msgid "ThreatMonitoring|Something went wrong, unable to fetch statistics"
msgstr ""
+msgid "ThreatMonitoring|Statistics"
+msgstr ""
+
msgid "ThreatMonitoring|The firewall is not installed or has been disabled. To view this data, ensure the web application firewall is installed and enabled for your cluster."
msgstr ""
@@ -26114,6 +27005,9 @@ msgstr ""
msgid "To update Snippets with multiple files, you must use the `files` parameter"
msgstr ""
+msgid "To use Gitpod you must first enable the feature in the integrations section of your %{user_prefs}."
+msgstr ""
+
msgid "To view all %{scannedResourcesCount} scanned URLs, please download the CSV file"
msgstr ""
@@ -26147,9 +27041,6 @@ msgstr ""
msgid "Toggle Sidebar"
msgstr ""
-msgid "Toggle all threads"
-msgstr ""
-
msgid "Toggle backtrace"
msgstr ""
@@ -26174,9 +27065,6 @@ msgstr ""
msgid "Toggle navigation"
msgstr ""
-msgid "Toggle project"
-msgstr ""
-
msgid "Toggle sidebar"
msgstr ""
@@ -26216,6 +27104,9 @@ msgstr ""
msgid "Too many projects enabled. You will need to manage them via the console or the API."
msgstr ""
+msgid "Too much data"
+msgstr ""
+
msgid "Topics (optional)"
msgstr ""
@@ -26234,6 +27125,9 @@ msgstr ""
msgid "Total cores (CPUs)"
msgstr ""
+msgid "Total days to completion"
+msgstr ""
+
msgid "Total issues"
msgstr ""
@@ -26330,6 +27224,9 @@ msgstr ""
msgid "Trending"
msgstr ""
+msgid "Trials|Create a new group to start your GitLab Gold trial."
+msgstr ""
+
msgid "Trials|Go back to GitLab"
msgstr ""
@@ -26339,6 +27236,15 @@ msgstr ""
msgid "Trials|You can always resume this process by selecting your avatar and choosing 'Start a Gold trial'"
msgstr ""
+msgid "Trials|You can apply your trial to a new group or an existing group."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group or your personal account."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group, an existing group, or your personal account."
+msgstr ""
+
msgid "Trials|You won't get a free trial right now but you can always resume this process by clicking on your avatar and choosing 'Start a free trial'"
msgstr ""
@@ -26408,6 +27314,9 @@ msgstr ""
msgid "Try using a different search term to find the file you are looking for."
msgstr ""
+msgid "Trying to communicate with your device. Plug it in (if needed) and press the button on the device now."
+msgstr ""
+
msgid "Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now."
msgstr ""
@@ -26495,6 +27404,12 @@ msgstr ""
msgid "URL or request ID"
msgstr ""
+msgid "USER %{user} WILL BE REMOVED! Are you sure?"
+msgstr ""
+
+msgid "USER WILL BE BLOCKED! Are you sure?"
+msgstr ""
+
msgid "UTC"
msgstr ""
@@ -26552,9 +27467,6 @@ msgstr ""
msgid "Unable to load the merge request widget. Try reloading the page."
msgstr ""
-msgid "Unable to resolve"
-msgstr ""
-
msgid "Unable to save iteration. Please try again"
msgstr ""
@@ -26603,6 +27515,9 @@ msgstr ""
msgid "Undo ignore"
msgstr ""
+msgid "Unexpected error"
+msgstr ""
+
msgid "Unfortunately, your email message to GitLab could not be processed."
msgstr ""
@@ -26636,6 +27551,9 @@ msgstr ""
msgid "Unknown response text"
msgstr ""
+msgid "Unless otherwise agreed to in writing with GitLab, by clicking \"Upload License\" you agree that your use of GitLab Software is subject to the %{eula_link_start}Terms of Service%{eula_link_end}."
+msgstr ""
+
msgid "Unlimited"
msgstr ""
@@ -27002,9 +27920,6 @@ msgstr ""
msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
msgstr ""
-msgid "Use a hardware device to add the second factor of authentication."
-msgstr ""
-
msgid "Use an one time password authenticator on your mobile device or computer to enable two-factor authentication (2FA)."
msgstr ""
@@ -27278,13 +28193,13 @@ msgstr ""
msgid "Users"
msgstr ""
-msgid "Users in License:"
+msgid "Users in License"
msgstr ""
-msgid "Users or groups set as approvers in the project's or merge request's settings."
+msgid "Users in License:"
msgstr ""
-msgid "Users outside of license"
+msgid "Users or groups set as approvers in the project's or merge request's settings."
msgstr ""
msgid "Users over License:"
@@ -27302,9 +28217,6 @@ msgstr ""
msgid "Users with a Guest role or those who don't belong to a Project or Group will not use a seat from your license."
msgstr ""
-msgid "Users with a Guest role or those who don't belong to any projects or groups don't count towards seats in use."
-msgstr ""
-
msgid "UsersSelect|%{name} + %{length} more"
msgstr ""
@@ -27344,9 +28256,6 @@ msgstr ""
msgid "Validations failed."
msgstr ""
-msgid "Validity"
-msgstr ""
-
msgid "Value"
msgstr ""
@@ -27365,6 +28274,9 @@ msgstr ""
msgid "Value Stream Name"
msgstr ""
+msgid "ValueStreamAnalyticsStage|We don't have enough data to show this stage."
+msgstr ""
+
msgid "ValueStreamAnalytics|%{days}d"
msgstr ""
@@ -27621,6 +28533,9 @@ msgstr ""
msgid "VisualReviewApp|Steps 1 and 2 (and sometimes 3) are performed once by the developer before requesting feedback. Steps 3 (if necessary), 4 is performed by the reviewer each time they perform a review."
msgstr ""
+msgid "Visualization"
+msgstr ""
+
msgid "Vulnerabilities"
msgstr ""
@@ -27648,34 +28563,31 @@ msgstr ""
msgid "VulnerabilityChart|Severity"
msgstr ""
-msgid "VulnerabilityManagement|A true-positive and will fix"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Change status"
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|Confirm"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Confirmed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
-msgstr ""
-
-msgid "VulnerabilityManagement|Detected %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|A true-positive and will fix"
msgstr ""
-msgid "VulnerabilityManagement|Dismiss"
+msgid "VulnerabilityManagement|Change status"
msgstr ""
-msgid "VulnerabilityManagement|Dismissed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
msgstr ""
-msgid "VulnerabilityManagement|Resolved"
+msgid "VulnerabilityManagement|Detected"
msgstr ""
-msgid "VulnerabilityManagement|Resolved %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Needs triage"
msgstr ""
msgid "VulnerabilityManagement|Something went wrong while trying to delete the comment. Please try again later."
@@ -27726,6 +28638,9 @@ msgstr ""
msgid "Vulnerability|%{scannerName} (version %{scannerVersion})"
msgstr ""
+msgid "Vulnerability|Activity"
+msgstr ""
+
msgid "Vulnerability|Class"
msgstr ""
@@ -27738,6 +28653,9 @@ msgstr ""
msgid "Vulnerability|Description"
msgstr ""
+msgid "Vulnerability|Detected"
+msgstr ""
+
msgid "Vulnerability|Evidence"
msgstr ""
@@ -27801,6 +28719,9 @@ msgstr ""
msgid "Warning: Displaying this diagram might cause performance issues on this page."
msgstr ""
+msgid "We are currently unable to fetch data for the pipeline header."
+msgstr ""
+
msgid "We are currently unable to fetch data for this graph."
msgstr ""
@@ -27840,6 +28761,12 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
+msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
+msgstr ""
+
+msgid "We would like to inform you that your subscription GitLab Enterprise Edition %{plan_name} is nearing its user limit. You have %{active_user_count} active users, which is almost at the user limit of %{maximum_user_count}."
+msgstr ""
+
msgid "We've found no vulnerabilities"
msgstr ""
@@ -27855,6 +28782,12 @@ msgstr ""
msgid "Web terminal"
msgstr ""
+msgid "WebAuthn Devices (%{length})"
+msgstr ""
+
+msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
+msgstr ""
+
msgid "WebIDE|Merge request"
msgstr ""
@@ -27993,15 +28926,9 @@ msgstr ""
msgid "Welcome to the guided GitLab tour"
msgstr ""
-msgid "Welcome to your Issue Board!"
-msgstr ""
-
msgid "Welcome to your issue board!"
msgstr ""
-msgid "We’ve been making changes to %{featureName} and we’d love your feedback %{linkStart}in this issue%{linkEnd} to help us improve the experience."
-msgstr ""
-
msgid "What are you searching for?"
msgstr ""
@@ -28020,6 +28947,9 @@ msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
msgstr ""
+msgid "When enabled, any user visiting %{host} and creating an account will have to be explicitly approved by the admin before they can login. This setting is effective only if sign-ups are enabled."
+msgstr ""
+
msgid "When enabled, any user visiting %{host} will be able to create an account."
msgstr ""
@@ -28244,6 +29174,9 @@ msgstr ""
msgid "With requirements, you can set criteria to check your products against."
msgstr ""
+msgid "With test cases, you can define conditions for your project to meet in determining quality"
+msgstr ""
+
msgid "Withdraw Access Request"
msgstr ""
@@ -28259,6 +29192,9 @@ msgstr ""
msgid "Workflow Help"
msgstr ""
+msgid "Would you like to create a new branch?"
+msgstr ""
+
msgid "Write"
msgstr ""
@@ -28280,6 +29216,9 @@ msgstr ""
msgid "Wrong extern UID provided. Make sure Auth0 is configured correctly."
msgstr ""
+msgid "YYYY-MM-DD"
+msgstr ""
+
msgid "Yes"
msgstr ""
@@ -28337,7 +29276,7 @@ msgstr ""
msgid "You are going to remove the fork relationship from %{project_full_name}. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "You are going to transfer %{project_full_name} to another owner. Are you ABSOLUTELY sure?"
+msgid "You are going to transfer %{project_full_name} to another namespace. Are you ABSOLUTELY sure?"
msgstr ""
msgid "You are going to turn off the confidentiality. This means %{strongStart}everyone%{strongEnd} will be able to see and leave a comment on this %{issuableType}."
@@ -28397,9 +29336,6 @@ msgstr ""
msgid "You can always edit this later"
msgstr ""
-msgid "You can apply your Trial to your Personal account or create a New Group."
-msgstr ""
-
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings"
msgstr ""
@@ -28421,12 +29357,18 @@ msgstr ""
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
+msgid "You can find more information about GitLab subscriptions in %{subscriptions_doc_link}."
+msgstr ""
+
msgid "You can generate an access token scoped to this project for each application to use the GitLab API."
msgstr ""
msgid "You can get started by cloning the repository or start adding files to it with one of the following options."
msgstr ""
+msgid "You can group test cases using labels. To learn about the future direction of this feature, visit %{linkStart}Quality Management direction page%{linkEnd}."
+msgstr ""
+
msgid "You can invite a new member to %{project_name} or invite another group."
msgstr ""
@@ -28442,6 +29384,9 @@ msgstr ""
msgid "You can notify the app / group or a project by sending them an email notification"
msgstr ""
+msgid "You can now close this window."
+msgstr ""
+
msgid "You can now export your security dashboard to a CSV report."
msgstr ""
@@ -28490,9 +29435,6 @@ msgstr ""
msgid "You can test your .gitlab-ci.yml in %{linkStart}CI Lint%{linkEnd}."
msgstr ""
-msgid "You can try again using %{begin_link}basic search%{end_link}"
-msgstr ""
-
msgid "You cannot access the raw file. Please wait a minute."
msgstr ""
@@ -28544,6 +29486,9 @@ msgstr ""
msgid "You don't have any U2F devices registered yet."
msgstr ""
+msgid "You don't have any WebAuthn devices registered yet."
+msgstr ""
+
msgid "You don't have any active chat names."
msgstr ""
@@ -28631,6 +29576,9 @@ msgstr ""
msgid "You must accept our Terms of Service and privacy policy in order to register an account"
msgstr ""
+msgid "You must be logged in to search across all of GitLab"
+msgstr ""
+
msgid "You must disassociate %{domain} from all clusters it is attached to before deletion."
msgstr ""
@@ -28670,7 +29618,7 @@ msgstr ""
msgid "You need to be logged in."
msgstr ""
-msgid "You need to register a two-factor authentication app before you can set up a U2F device."
+msgid "You need to register a two-factor authentication app before you can set up a device."
msgstr ""
msgid "You need to set terms to be enforced"
@@ -28688,6 +29636,9 @@ msgstr ""
msgid "You reached %{usage_in_percent} of %{namespace_name}'s storage capacity (%{used_storage} of %{storage_limit})"
msgstr ""
+msgid "You successfully declined the invitation"
+msgstr ""
+
msgid "You tried to fork %{link_to_the_project} but it failed for the following reason:"
msgstr ""
@@ -28853,10 +29804,13 @@ msgstr ""
msgid "Your U2F device did not send a valid JSON response."
msgstr ""
-msgid "Your U2F device needs to be set up. Plug it in (if not already) and click the button on the left."
+msgid "Your U2F device was registered!"
msgstr ""
-msgid "Your U2F device was registered!"
+msgid "Your WebAuthn device did not send a valid JSON response."
+msgstr ""
+
+msgid "Your WebAuthn device was registered!"
msgstr ""
msgid "Your access request to the %{source_type} has been withdrawn."
@@ -28880,6 +29834,9 @@ msgstr ""
msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
msgstr ""
+msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
+msgstr ""
+
msgid "Your changes can be committed to %{branch_name} because a merge request is open."
msgstr ""
@@ -28916,6 +29873,12 @@ msgstr ""
msgid "Your deployment services will be broken, you will need to manually fix the services after renaming."
msgstr ""
+msgid "Your device is not compatible with GitLab. Please try another device"
+msgstr ""
+
+msgid "Your device needs to be set up. Plug it in (if needed) and click the button on the left."
+msgstr ""
+
msgid "Your device was successfully set up! Give it a name and register it with the GitLab server."
msgstr ""
@@ -29029,9 +29992,6 @@ msgstr[1] ""
msgid "access:"
msgstr ""
-msgid "activated"
-msgstr ""
-
msgid "added %{created_at_timeago}"
msgstr ""
@@ -29104,9 +30064,21 @@ msgstr ""
msgid "by %{user}"
msgstr ""
+msgid "cannot be a date in the past"
+msgstr ""
+
msgid "cannot be changed if a personal project has container registry tags."
msgstr ""
+msgid "cannot be changed if shared runners are enabled"
+msgstr ""
+
+msgid "cannot be enabled because parent group does not allow it"
+msgstr ""
+
+msgid "cannot be enabled because parent group has shared Runners disabled"
+msgstr ""
+
msgid "cannot be enabled unless all domains have TLS certificates"
msgstr ""
@@ -29152,7 +30124,7 @@ msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about SAST %{linkEndTag}"
msgstr ""
-msgid "ciReport|%{linkStartTag}Learn more about Secret Scanning %{linkEndTag}"
+msgid "ciReport|%{linkStartTag}Learn more about Secret Detection %{linkEndTag}"
msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about codequality reports %{linkEndTag}"
@@ -29467,9 +30439,6 @@ msgstr ""
msgid "error"
msgstr ""
-msgid "error code:"
-msgstr ""
-
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr ""
@@ -29491,6 +30460,9 @@ msgstr ""
msgid "failed to dismiss associated finding(id=%{finding_id}): %{message}"
msgstr ""
+msgid "failed to revert associated finding(id=%{finding_id}) to detected"
+msgstr ""
+
msgid "file"
msgid_plural "files"
msgstr[0] ""
@@ -30033,6 +31005,9 @@ msgstr ""
msgid "must be a root namespace"
msgstr ""
+msgid "must be a valid IPv4 or IPv6 address"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -30069,6 +31044,9 @@ msgstr ""
msgid "no expiration"
msgstr ""
+msgid "no name set"
+msgstr ""
+
msgid "no one can merge"
msgstr ""
@@ -30247,9 +31225,6 @@ msgstr ""
msgid "security Reports|There was an error creating the merge request"
msgstr ""
-msgid "settings saved, but not activated"
-msgstr ""
-
msgid "severity|Critical"
msgstr ""
@@ -30376,9 +31351,6 @@ msgstr ""
msgid "toggle collapse"
msgstr ""
-msgid "toggle dropdown"
-msgstr ""
-
msgid "triggered"
msgstr ""
@@ -30406,6 +31378,9 @@ msgstr ""
msgid "user avatar"
msgstr ""
+msgid "user preferences"
+msgstr ""
+
msgid "username"
msgstr ""
diff --git a/locale/sk_SK/gitlab.po b/locale/sk_SK/gitlab.po
index 5a8b2438718..331c8a5f3b6 100644
--- a/locale/sk_SK/gitlab.po
+++ b/locale/sk_SK/gitlab.po
@@ -14,7 +14,10 @@ msgstr ""
"X-Crowdin-Language: sk\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 6\n"
-"PO-Revision-Date: 2020-09-04 23:10\n"
+"PO-Revision-Date: 2020-10-02 18:50\n"
+
+msgid " %{project_name}#%{issue_iid} &middot; opened %{issue_created} by %{author}"
+msgstr ""
msgid " %{start} to %{end}"
msgstr ""
@@ -78,6 +81,20 @@ msgstr ""
msgid "\"el\" parameter is required for createInstance()"
msgstr ""
+msgid "%d Approval"
+msgid_plural "%d Approvals"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
+msgid "%d Package"
+msgid_plural "%d Packages"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%d Scanned URL"
msgid_plural "%d Scanned URLs"
msgstr[0] ""
@@ -165,6 +182,13 @@ msgstr[3] ""
msgid "%d commits"
msgstr ""
+msgid "%d completed issue"
+msgid_plural "%d completed issues"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%d contribution"
msgid_plural "%d contributions"
msgstr[0] ""
@@ -179,6 +203,13 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "%d day until tags are automatically removed"
+msgid_plural "%d days until tags are automatically removed"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%d error"
msgid_plural "%d errors"
msgstr[0] ""
@@ -305,6 +336,20 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "%d open issue"
+msgid_plural "%d open issues"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
+msgid "%d pending comment"
+msgid_plural "%d pending comments"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%d personal project will be removed and cannot be restored."
msgid_plural "%d personal projects will be removed and cannot be restored."
msgstr[0] ""
@@ -326,6 +371,13 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "%d project selected"
+msgid_plural "%d projects selected"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%d request with warnings"
msgid_plural "%d requests with warnings"
msgstr[0] ""
@@ -354,6 +406,13 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "%d tag per image name"
+msgid_plural "%d tags per image name"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%d unassigned issue"
msgid_plural "%d unassigned issues"
msgstr[0] ""
@@ -382,6 +441,13 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "%d warning found:"
+msgid_plural "%d warnings found:"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%s additional commit has been omitted to prevent performance issues."
msgid_plural "%s additional commits have been omitted to prevent performance issues."
msgstr[0] ""
@@ -422,6 +488,9 @@ msgstr ""
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr ""
+msgid "%{completedCount} completed weight"
+msgstr ""
+
msgid "%{completedWeight} of %{totalWeight} weight completed"
msgstr ""
@@ -476,16 +545,12 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "%{count} pending comment"
-msgid_plural "%{count} pending comments"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
+msgid "%{count} total weight"
+msgstr ""
+
msgid "%{dashboard_path} could not be found."
msgstr ""
@@ -540,6 +605,9 @@ msgstr ""
msgid "%{group_name} uses group managed accounts. You need to create a new GitLab account which will be managed by %{group_name}."
msgstr ""
+msgid "%{group_name}&%{epic_iid} &middot; opened %{epic_created} by %{author}"
+msgstr ""
+
msgid "%{host} sign-in from new location"
msgstr ""
@@ -552,7 +620,7 @@ msgstr ""
msgid "%{issuableType} will be removed! Are you sure?"
msgstr ""
-msgid "%{issuesSize} issues with a limit of %{maxIssueCount}"
+msgid "%{issuesCount} issues with a limit of %{maxIssueCount}"
msgstr ""
msgid "%{issuesSize} with a limit of %{maxIssueCount}"
@@ -585,7 +653,7 @@ msgstr ""
msgid "%{labelStart}Namespace:%{labelEnd} %{namespace}"
msgstr ""
-msgid "%{labelStart}Report Type:%{labelEnd} %{reportType}"
+msgid "%{labelStart}Scan Type:%{labelEnd} %{reportType}"
msgstr ""
msgid "%{labelStart}Scanner:%{labelEnd} %{scanner}"
@@ -796,9 +864,6 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "%{service_title} %{message}."
-msgstr ""
-
msgid "%{size} GiB"
msgstr ""
@@ -897,6 +962,12 @@ msgstr ""
msgid "%{timebox_name} should belong either to a project or a group."
msgstr ""
+msgid "%{timebox_type} does not support burnup charts"
+msgstr ""
+
+msgid "%{timebox_type} must have a start and due date"
+msgstr ""
+
msgid "%{title} %{operator} %{threshold}"
msgstr ""
@@ -921,7 +992,7 @@ msgstr ""
msgid "%{total} open issue weight"
msgstr ""
-msgid "%{total} open issues"
+msgid "%{total} warnings found: showing first %{warningsDisplayed}"
msgstr ""
msgid "%{usage_ping_link_start}Learn more%{usage_ping_link_end} about what information is shared with GitLab Inc."
@@ -954,9 +1025,6 @@ msgstr ""
msgid "&lt; 1 hour"
msgstr ""
-msgid "&lt;no name set&gt;"
-msgstr ""
-
msgid "&lt;no scopes selected&gt;"
msgstr ""
@@ -987,6 +1055,9 @@ msgstr ""
msgid "'%{name}' Value Stream created"
msgstr ""
+msgid "'%{name}' Value Stream deleted"
+msgstr ""
+
msgid "'%{name}' stage already exists"
msgstr ""
@@ -1048,6 +1119,9 @@ msgstr ""
msgid "+ %{numberOfHiddenAssignees} more"
msgstr ""
+msgid "+ %{numberOfHiddenReviewers} more"
+msgstr ""
+
msgid "+%d more"
msgid_plural "+%d more"
msgstr[0] ""
@@ -1120,6 +1194,13 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "1 Issue"
+msgid_plural "%d Issues"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "1 closed issue"
msgid_plural "%{issues} closed issues"
msgstr[0] ""
@@ -1141,6 +1222,13 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "1 deploy key"
+msgid_plural "%d deploy keys"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1261,6 +1349,9 @@ msgstr ""
msgid ":%{startLine} to %{endLine}"
msgstr ""
+msgid "A %{incident_docs_start}modified issue%{incident_docs_end} to guide the resolution of incidents."
+msgstr ""
+
msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr ""
@@ -1273,6 +1364,9 @@ msgstr ""
msgid "A GitBook site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
+msgid "A Gitpod configured Webapplication in Spring and Java"
+msgstr ""
+
msgid "A Hexo site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
@@ -1444,9 +1538,15 @@ msgstr ""
msgid "Access expiration date"
msgstr ""
+msgid "Access expires"
+msgstr ""
+
msgid "Access forbidden. Check your access level."
msgstr ""
+msgid "Access granted"
+msgstr ""
+
msgid "Access requests"
msgstr ""
@@ -1456,6 +1556,9 @@ msgstr ""
msgid "Access to Pages websites are controlled based on the user's membership to a given project. By checking this box, users will be required to be logged in to have access to all Pages websites in your instance."
msgstr ""
+msgid "AccessDropdown|Deploy Keys"
+msgstr ""
+
msgid "AccessDropdown|Groups"
msgstr ""
@@ -1573,12 +1676,6 @@ msgstr ""
msgid "Active Sessions"
msgstr ""
-msgid "Active Users:"
-msgstr ""
-
-msgid "Active users"
-msgstr ""
-
msgid "Activity"
msgstr ""
@@ -1748,9 +1845,6 @@ msgstr ""
msgid "Add label(s)"
msgstr ""
-msgid "Add license"
-msgstr ""
-
msgid "Add list"
msgstr ""
@@ -1925,21 +2019,51 @@ msgstr ""
msgid "AdminArea|Bots"
msgstr ""
+msgid "AdminArea|Components"
+msgstr ""
+
msgid "AdminArea|Developer"
msgstr ""
+msgid "AdminArea|Features"
+msgstr ""
+
+msgid "AdminArea|Groups: %{number_of_groups}"
+msgstr ""
+
msgid "AdminArea|Guest"
msgstr ""
msgid "AdminArea|Included Free in license"
msgstr ""
+msgid "AdminArea|Latest groups"
+msgstr ""
+
+msgid "AdminArea|Latest projects"
+msgstr ""
+
+msgid "AdminArea|Latest users"
+msgstr ""
+
msgid "AdminArea|Maintainer"
msgstr ""
+msgid "AdminArea|New group"
+msgstr ""
+
+msgid "AdminArea|New project"
+msgstr ""
+
+msgid "AdminArea|New user"
+msgstr ""
+
msgid "AdminArea|Owner"
msgstr ""
+msgid "AdminArea|Projects: %{number_of_projects}"
+msgstr ""
+
msgid "AdminArea|Reporter"
msgstr ""
@@ -1967,6 +2091,9 @@ msgstr ""
msgid "AdminArea|Users without a Group and Project"
msgstr ""
+msgid "AdminArea|Users: %{number_of_users}"
+msgstr ""
+
msgid "AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running."
msgstr ""
@@ -1985,9 +2112,6 @@ msgstr ""
msgid "AdminProjects|Delete Project %{projectName}?"
msgstr ""
-msgid "AdminProjects|Delete project"
-msgstr ""
-
msgid "AdminSettings|Apply integration settings to all Projects"
msgstr ""
@@ -2225,21 +2349,30 @@ msgstr ""
msgid "AdminUsers|Without projects"
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 ""
msgid "AdminUsers|You cannot remove your own admin rights."
msgstr ""
+msgid "AdminUsers|You must transfer ownership or delete the groups owned by this user before you can delete their account"
+msgstr ""
+
msgid "Administration"
msgstr ""
msgid "Advanced"
msgstr ""
+msgid "Advanced Search"
+msgstr ""
+
+msgid "Advanced Search with Elasticsearch"
+msgstr ""
+
msgid "Advanced Settings"
msgstr ""
@@ -2319,6 +2452,9 @@ msgstr ""
msgid "AlertManagement|Edit"
msgstr ""
+msgid "AlertManagement|Environment"
+msgstr ""
+
msgid "AlertManagement|Events"
msgstr ""
@@ -2331,6 +2467,9 @@ msgstr ""
msgid "AlertManagement|Issue"
msgstr ""
+msgid "AlertManagement|Key"
+msgstr ""
+
msgid "AlertManagement|Low"
msgstr ""
@@ -2424,6 +2563,9 @@ msgstr ""
msgid "AlertManagement|Unknown"
msgstr ""
+msgid "AlertManagement|Value"
+msgstr ""
+
msgid "AlertManagement|View alerts in Opsgenie"
msgstr ""
@@ -2583,6 +2725,9 @@ msgstr ""
msgid "All projects"
msgstr ""
+msgid "All projects selected"
+msgstr ""
+
msgid "All security scans are enabled because %{linkStart}Auto DevOps%{linkEnd} is enabled on this project"
msgstr ""
@@ -2670,6 +2815,9 @@ msgstr ""
msgid "Almost there"
msgstr ""
+msgid "Already blocked"
+msgstr ""
+
msgid "Also called \"Issuer\" or \"Relying party trust identifier\""
msgstr ""
@@ -2724,6 +2872,9 @@ msgstr ""
msgid "An error has occurred"
msgstr ""
+msgid "An error occured while making the changes: %{error}"
+msgstr ""
+
msgid "An error occurred adding a draft to the thread."
msgstr ""
@@ -2751,12 +2902,6 @@ msgstr ""
msgid "An error occurred when toggling the notification subscription"
msgstr ""
-msgid "An error occurred when trying to resolve a comment. Please try again."
-msgstr ""
-
-msgid "An error occurred when trying to resolve a discussion. Please try again."
-msgstr ""
-
msgid "An error occurred when updating the issue weight"
msgstr ""
@@ -2772,12 +2917,6 @@ msgstr ""
msgid "An error occurred while checking group path. Please refresh and try again."
msgstr ""
-msgid "An error occurred while committing your changes."
-msgstr ""
-
-msgid "An error occurred while creating the list. Please try again."
-msgstr ""
-
msgid "An error occurred while decoding the file."
msgstr ""
@@ -2850,25 +2989,19 @@ msgstr ""
msgid "An error occurred while fetching the Service Desk address."
msgstr ""
-msgid "An error occurred while fetching the board issues. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the board lists. Please reload the page."
msgstr ""
msgid "An error occurred while fetching the board lists. Please try again."
msgstr ""
-msgid "An error occurred while fetching the board swimlanes. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the builds."
msgstr ""
msgid "An error occurred while fetching the job log."
msgstr ""
-msgid "An error occurred while fetching the job trace."
+msgid "An error occurred while fetching the job logs."
msgstr ""
msgid "An error occurred while fetching the job."
@@ -3015,9 +3148,6 @@ msgstr ""
msgid "An error occurred while saving assignees"
msgstr ""
-msgid "An error occurred while saving the template. Please check if the template exists."
-msgstr ""
-
msgid "An error occurred while searching for milestones"
msgstr ""
@@ -3036,10 +3166,10 @@ msgstr ""
msgid "An error occurred while updating approvers"
msgstr ""
-msgid "An error occurred while updating the comment"
+msgid "An error occurred while updating labels."
msgstr ""
-msgid "An error occurred while updating the list. Please try again."
+msgid "An error occurred while updating the comment"
msgstr ""
msgid "An error occurred while validating group path"
@@ -3093,6 +3223,9 @@ msgstr ""
msgid "An unknown error occurred while loading this graph."
msgstr ""
+msgid "An unknown error occurred."
+msgstr ""
+
msgid "Analytics"
msgstr ""
@@ -3126,10 +3259,10 @@ msgstr ""
msgid "Any"
msgstr ""
-msgid "Any Author"
+msgid "Any %{header}"
msgstr ""
-msgid "Any Status"
+msgid "Any Author"
msgstr ""
msgid "Any branch"
@@ -3183,6 +3316,9 @@ msgstr ""
msgid "Application ID"
msgstr ""
+msgid "Application limits saved successfully"
+msgstr ""
+
msgid "Application settings saved successfully"
msgstr ""
@@ -3400,6 +3536,9 @@ msgstr ""
msgid "Are you sure you want to close this blocked issue?"
msgstr ""
+msgid "Are you sure you want to delete \"%{name}\" Value Stream?"
+msgstr ""
+
msgid "Are you sure you want to delete %{name}?"
msgstr ""
@@ -3409,6 +3548,9 @@ msgstr ""
msgid "Are you sure you want to delete this %{typeOfComment}?"
msgstr ""
+msgid "Are you sure you want to delete this SSH key?"
+msgstr ""
+
msgid "Are you sure you want to delete this board?"
msgstr ""
@@ -3433,6 +3575,13 @@ msgstr ""
msgid "Are you sure you want to erase this build?"
msgstr ""
+msgid "Are you sure you want to import %d repository?"
+msgid_plural "Are you sure you want to import %d repositories?"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "Are you sure you want to lose unsaved changes?"
msgstr ""
@@ -3442,15 +3591,15 @@ msgstr ""
msgid "Are you sure you want to merge immediately?"
msgstr ""
-msgid "Are you sure you want to permanently delete this license?"
-msgstr ""
-
msgid "Are you sure you want to re-deploy this environment?"
msgstr ""
msgid "Are you sure you want to regenerate the public key? You will have to update the public key on the remote server before mirroring will work again."
msgstr ""
+msgid "Are you sure you want to reindex?"
+msgstr ""
+
msgid "Are you sure you want to remove %{group_name}?"
msgstr ""
@@ -3478,6 +3627,9 @@ msgstr ""
msgid "Are you sure you want to revoke this nickname?"
msgstr ""
+msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
+msgstr ""
+
msgid "Are you sure you want to stop this environment?"
msgstr ""
@@ -3499,6 +3651,9 @@ msgstr ""
msgid "Are you sure? The device will be signed out of GitLab and all remember me tokens revoked."
msgstr ""
+msgid "Are you sure? This will invalidate your registered applications and U2F / WebAuthn devices."
+msgstr ""
+
msgid "Are you sure? This will invalidate your registered applications and U2F devices."
msgstr ""
@@ -3517,9 +3672,6 @@ msgstr ""
msgid "Artifacts"
msgstr ""
-msgid "As U2F devices are only supported by a few browsers, we require that you set up a two-factor authentication app before a U2F device. That way you'll always be able to log in - even when you're using an unsupported browser."
-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 ""
@@ -3717,6 +3869,9 @@ msgstr ""
msgid "AuditLogs|Target"
msgstr ""
+msgid "AuditLogs|This month"
+msgstr ""
+
msgid "AuditLogs|User Events"
msgstr ""
@@ -3756,6 +3911,9 @@ msgstr ""
msgid "Authentication via U2F device failed."
msgstr ""
+msgid "Authentication via WebAuthn device failed."
+msgstr ""
+
msgid "Author"
msgstr ""
@@ -4023,15 +4181,6 @@ msgstr ""
msgid "BambooService|You must set up automatic revision labeling and a repository trigger in Bamboo."
msgstr ""
-msgid "BatchComments|Delete all pending comments"
-msgstr ""
-
-msgid "BatchComments|Discard review?"
-msgstr ""
-
-msgid "BatchComments|You're about to discard your review which will delete all of your pending comments. The deleted comments %{strong_start}cannot%{strong_end} be restored."
-msgstr ""
-
msgid "Be careful. Changing the project's namespace can have unintended side effects."
msgstr ""
@@ -4053,6 +4202,9 @@ msgstr ""
msgid "Bi-weekly code coverage"
msgstr ""
+msgid "Billable Users:"
+msgstr ""
+
msgid "Billing"
msgstr ""
@@ -4062,7 +4214,7 @@ msgstr ""
msgid "BillingPlans|@%{user_name} you are currently using the %{plan_name} plan."
msgstr ""
-msgid "BillingPlans|Congratulations, your new trial is activated"
+msgid "BillingPlans|Congratulations, your free trial is activated."
msgstr ""
msgid "BillingPlans|If you would like to downgrade your plan please contact %{support_link_start}Customer Support%{support_link_end}."
@@ -4125,6 +4277,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Block user"
+msgstr ""
+
msgid "Blocked"
msgstr ""
@@ -4140,31 +4295,37 @@ msgstr ""
msgid "Blog"
msgstr ""
-msgid "Board name"
-msgstr ""
-
msgid "Board scope"
msgstr ""
msgid "Board scope affects which issues are displayed for anyone who visits this board"
msgstr ""
-msgid "BoardBlankState|Add default lists"
+msgid "Boards"
msgstr ""
-msgid "BoardBlankState|Add the following default lists to your Issue Board with one click:"
+msgid "Boards and Board Lists"
msgstr ""
-msgid "BoardBlankState|Nevermind, I'll use my own"
+msgid "Boards|An error occurred while creating the issue. Please try again."
msgstr ""
-msgid "BoardBlankState|Starting out with the default set of lists will get you right on the way to making the most of your board."
+msgid "Boards|An error occurred while creating the list. Please try again."
msgstr ""
-msgid "Boards"
+msgid "Boards|An error occurred while fetching issues. Please reload the page."
msgstr ""
-msgid "Boards and Board Lists"
+msgid "Boards|An error occurred while fetching the board issues. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching the board swimlanes. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while moving the issue. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while updating the list. Please try again."
msgstr ""
msgid "Boards|Collapse"
@@ -4191,7 +4352,7 @@ msgstr ""
msgid "Branch %{branch_name} was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr ""
-msgid "Branch has changed"
+msgid "Branch changed"
msgstr ""
msgid "Branch is already taken"
@@ -4497,6 +4658,9 @@ msgstr ""
msgid "CLOSED (MOVED)"
msgstr ""
+msgid "CODEOWNERS rule violation"
+msgstr ""
+
msgid "CONTRIBUTING"
msgstr ""
@@ -4527,9 +4691,6 @@ msgstr ""
msgid "Can't create snippet: %{err}"
msgstr ""
-msgid "Can't edit as source branch was deleted"
-msgstr ""
-
msgid "Can't fetch content for the blob: %{err}"
msgstr ""
@@ -4542,9 +4703,6 @@ msgstr ""
msgid "Can't load mermaid module: %{err}"
msgstr ""
-msgid "Can't remove group members without group managed account"
-msgstr ""
-
msgid "Can't scan the code?"
msgstr ""
@@ -4587,6 +4745,9 @@ msgstr ""
msgid "Cannot create the abuse report. This user has been blocked."
msgstr ""
+msgid "Cannot enable shared runners because parent group does not allow it"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -4692,6 +4853,15 @@ msgstr ""
msgid "Change your password or recover your current one"
msgstr ""
+msgid "ChangeReviewer|Reviewer changed from %{old} to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Reviewer changed to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Unassigned"
+msgstr ""
+
msgid "ChangeTypeActionLabel|Pick into branch"
msgstr ""
@@ -4731,6 +4901,9 @@ msgstr ""
msgid "Changes the title to \"%{title_param}\"."
msgstr ""
+msgid "Changes were successfully made."
+msgstr ""
+
msgid "Changes won't take place until the index is %{link_start}recreated%{link_end}."
msgstr ""
@@ -5136,6 +5309,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove variable"
+msgstr ""
+
msgid "CiVariables|Remove variable row"
msgstr ""
@@ -5214,9 +5390,6 @@ msgstr ""
msgid "Clear due date"
msgstr ""
-msgid "Clear input"
-msgstr ""
-
msgid "Clear recent searches"
msgstr ""
@@ -5265,6 +5438,9 @@ msgstr ""
msgid "Client authentication key password"
msgstr ""
+msgid "Client request timeout"
+msgstr ""
+
msgid "Clients"
msgstr ""
@@ -5349,6 +5525,27 @@ msgstr ""
msgid "Cluster type must be specificed for Stages::ClusterEndpointInserter"
msgstr ""
+msgid "ClusterAgents|Configuration"
+msgstr ""
+
+msgid "ClusterAgents|Connect your cluster with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate Kubernetes with a GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Name"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Agent also requires %{linkStart}enabling the Agent Server%{linkEnd}"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Kubernetes Agent allows an Infrastructure as Code, GitOps approach to integrating Kubernetes clusters with GitLab. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "ClusterAgent|This feature is only available for premium plans"
msgstr ""
@@ -5418,10 +5615,10 @@ msgstr ""
msgid "ClusterIntegration|All installed applications and related resources"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster."
+msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{linkStart}More information%{linkEnd}"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{startLink}More information%{endLink}"
+msgid "ClusterIntegration|Allow GitLab to manage namespaces and service accounts for this cluster."
msgstr ""
msgid "ClusterIntegration|Alternatively, "
@@ -5442,6 +5639,9 @@ msgstr ""
msgid "ClusterIntegration|An error occurred while trying to fetch zone machine types: %{error}"
msgstr ""
+msgid "ClusterIntegration|An unknown error occurred while attempting to connect to Kubernetes."
+msgstr ""
+
msgid "ClusterIntegration|Any project namespaces"
msgstr ""
@@ -5457,6 +5657,9 @@ msgstr ""
msgid "ClusterIntegration|Authenticate with Amazon Web Services"
msgstr ""
+msgid "ClusterIntegration|Authentication Error"
+msgstr ""
+
msgid "ClusterIntegration|Base domain"
msgstr ""
@@ -5475,13 +5678,22 @@ msgstr ""
msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}security group %{externalLinkIcon} %{endLink} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
+msgid "ClusterIntegration|Check your CA certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Check your cluster status"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}subnets %{externalLinkIcon} %{endLink} in your VPC where your worker nodes will run."
+msgid "ClusterIntegration|Check your token"
msgstr ""
-msgid "ClusterIntegration|Choose the worker node %{startLink}instance type %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Choose the %{linkStart}security group %{linkEnd} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
+msgstr ""
+
+msgid "ClusterIntegration|Choose the %{linkStart}subnets %{linkEnd} in your VPC where your worker nodes will run."
+msgstr ""
+
+msgid "ClusterIntegration|Choose the worker node %{linkStart}instance type%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Choose which applications to install on your Kubernetes cluster."
@@ -5493,10 +5705,7 @@ msgstr ""
msgid "ClusterIntegration|Clear cluster cache"
msgstr ""
-msgid "ClusterIntegration|Clear the local cache of namespace and service accounts. This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
-msgstr ""
-
-msgid "ClusterIntegration|Cluster being created"
+msgid "ClusterIntegration|Clear the local cache of namespace and service accounts."
msgstr ""
msgid "ClusterIntegration|Cluster management project (alpha)"
@@ -5508,15 +5717,21 @@ msgstr ""
msgid "ClusterIntegration|Cluster_applications artifact too big. Maximum allowable size: %{human_size}"
msgstr ""
-msgid "ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters."
+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|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}"
+msgid "ClusterIntegration|Clusters connected with a certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Connect cluster with certificate"
msgstr ""
msgid "ClusterIntegration|Connect existing cluster"
msgstr ""
+msgid "ClusterIntegration|Connection Error"
+msgstr ""
+
msgid "ClusterIntegration|Copy API URL"
msgstr ""
@@ -5592,6 +5807,12 @@ msgstr ""
msgid "ClusterIntegration|Deletes all GitLab resources attached to this cluster during removal"
msgstr ""
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared."
+msgstr ""
+
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared. %{linkStart}More information%{linkEnd}"
+msgstr ""
+
msgid "ClusterIntegration|Did you know?"
msgstr ""
@@ -5661,6 +5882,9 @@ msgstr ""
msgid "ClusterIntegration|Fluentd is an open source data collector, which lets you unify the data collection and consumption for a better use and understanding of data. It requires at least one of the following logs to be successfully installed."
msgstr ""
+msgid "ClusterIntegration|GitLab Agent managed clusters"
+msgstr ""
+
msgid "ClusterIntegration|GitLab Container Network Policies"
msgstr ""
@@ -5673,6 +5897,12 @@ msgstr ""
msgid "ClusterIntegration|GitLab Runner connects to the repository and executes CI/CD jobs, pushing results back and deploying applications to production."
msgstr ""
+msgid "ClusterIntegration|GitLab failed to authenticate."
+msgstr ""
+
+msgid "ClusterIntegration|GitLab failed to connect to the cluster."
+msgstr ""
+
msgid "ClusterIntegration|GitLab-managed cluster"
msgstr ""
@@ -5694,6 +5924,9 @@ msgstr ""
msgid "ClusterIntegration|Group cluster"
msgstr ""
+msgid "ClusterIntegration|HTTP Error"
+msgstr ""
+
msgid "ClusterIntegration|Helm Tiller"
msgstr ""
@@ -5727,7 +5960,10 @@ msgstr ""
msgid "ClusterIntegration|Instance type"
msgstr ""
-msgid "ClusterIntegration|Integrate Kubernetes cluster automation"
+msgid "ClusterIntegration|Integrate Kubernetes with a cluster certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Integrate with a cluster certificate"
msgstr ""
msgid "ClusterIntegration|Issuer Email"
@@ -5763,9 +5999,6 @@ msgstr ""
msgid "ClusterIntegration|Knative extends Kubernetes to provide a set of middleware components that are essential to build modern, source-centric, and container-based applications that can run anywhere: on premises, in the cloud, or even in a third-party data center."
msgstr ""
-msgid "ClusterIntegration|Kubernetes cluster"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes cluster is being created..."
msgstr ""
@@ -5778,9 +6011,6 @@ msgstr ""
msgid "ClusterIntegration|Kubernetes clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr ""
-msgid "ClusterIntegration|Kubernetes clusters can be used to deploy applications and to provide Review Apps for this project"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes version"
msgstr ""
@@ -5793,7 +6023,7 @@ msgstr ""
msgid "ClusterIntegration|Learn more about %{help_link_start}zones%{help_link_end}."
msgstr ""
-msgid "ClusterIntegration|Learn more about %{startLink}Regions %{externalLinkIcon}%{endLink}."
+msgid "ClusterIntegration|Learn more about %{linkStart}Regions%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Learn more about Kubernetes"
@@ -5838,12 +6068,18 @@ msgstr ""
msgid "ClusterIntegration|Machine type"
msgstr ""
+msgid "ClusterIntegration|Make sure your API endpoint is correct"
+msgstr ""
+
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create Kubernetes clusters"
msgstr ""
msgid "ClusterIntegration|Manage your Kubernetes cluster by visiting %{provider_link}"
msgstr ""
+msgid "ClusterIntegration|Namespace per environment"
+msgstr ""
+
msgid "ClusterIntegration|No IAM Roles found"
msgstr ""
@@ -5889,6 +6125,9 @@ msgstr ""
msgid "ClusterIntegration|No zones matched your search"
msgstr ""
+msgid "ClusterIntegration|Node calculations use the Kubernetes Metrics API. Make sure your cluster has metrics installed"
+msgstr ""
+
msgid "ClusterIntegration|Number of nodes"
msgstr ""
@@ -5931,6 +6170,9 @@ msgstr ""
msgid "ClusterIntegration|RBAC-enabled cluster"
msgstr ""
+msgid "ClusterIntegration|Read our %{linkStart}help page%{linkEnd} on Kubernetes cluster integration."
+msgstr ""
+
msgid "ClusterIntegration|Read our %{link_start}help page%{link_end} on Kubernetes cluster integration."
msgstr ""
@@ -6033,7 +6275,7 @@ msgstr ""
msgid "ClusterIntegration|Select a VPC to choose a subnet"
msgstr ""
-msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{linkStart}Amazon Web Services %{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select a network to choose a subnetwork"
@@ -6066,7 +6308,7 @@ msgstr ""
msgid "ClusterIntegration|Select project to choose zone"
msgstr ""
-msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select zone"
@@ -6156,9 +6398,18 @@ msgstr ""
msgid "ClusterIntegration|There was a problem authenticating with your cluster. Please ensure your CA Certificate and Token are valid."
msgstr ""
+msgid "ClusterIntegration|There was an HTTP error when connecting to your cluster."
+msgstr ""
+
msgid "ClusterIntegration|This account must have permissions to create a Kubernetes cluster in the %{link_to_container_project} specified below"
msgstr ""
+msgid "ClusterIntegration|This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
+msgstr ""
+
+msgid "ClusterIntegration|This is necessary to clear existing environment-namespace associations from clusters previously managed by GitLab."
+msgstr ""
+
msgid "ClusterIntegration|This option will allow you to install applications on RBAC clusters."
msgstr ""
@@ -6183,9 +6434,21 @@ msgstr ""
msgid "ClusterIntegration|To use a new project, first create one on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}."
msgstr ""
+msgid "ClusterIntegration|Troubleshooting tips:"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Authenticate"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Connect"
+msgstr ""
+
msgid "ClusterIntegration|Uninstall %{appTitle}"
msgstr ""
+msgid "ClusterIntegration|Unknown Error"
+msgstr ""
+
msgid "ClusterIntegration|Update %{appTitle}"
msgstr ""
@@ -6246,7 +6509,7 @@ msgstr ""
msgid "ClusterIntegration|Your cluster API is unreachable. Please ensure your API URL is correct."
msgstr ""
-msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Zone"
@@ -6366,6 +6629,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse all threads"
+msgstr ""
+
msgid "Collapse approvers"
msgstr ""
@@ -6517,7 +6783,7 @@ msgstr ""
msgid "Commit…"
msgstr ""
-msgid "Company"
+msgid "Community forum"
msgstr ""
msgid "Company name"
@@ -6526,6 +6792,9 @@ msgstr ""
msgid "Compare"
msgstr ""
+msgid "Compare %{oldCommitId}...%{newCommitId}"
+msgstr ""
+
msgid "Compare Git revisions"
msgstr ""
@@ -6541,6 +6810,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare submodule commit revisions"
+msgstr ""
+
msgid "Compare with previous version"
msgstr ""
@@ -6676,6 +6948,9 @@ msgstr ""
msgid "Configure the way a user creates a new account."
msgstr ""
+msgid "Configure which lists are shown for anyone who visits this board"
+msgstr ""
+
msgid "Confirm"
msgstr ""
@@ -6907,6 +7182,9 @@ msgstr[3] ""
msgid "ContainerRegistry|Set cleanup policy"
msgstr ""
+msgid "ContainerRegistry|Some tags were not deleted"
+msgstr ""
+
msgid "ContainerRegistry|Something went wrong while fetching the cleanup policy."
msgstr ""
@@ -6946,6 +7224,9 @@ msgstr ""
msgid "ContainerRegistry|Tags with names matching this regex pattern will %{italicStart}expire:%{italicEnd}"
msgstr ""
+msgid "ContainerRegistry|The cleanup policy timed out before it could delete all tags. An administrator can %{adminLinkStart}manually run cleanup now%{adminLinkEnd} or you can wait for the cleanup policy to automatically run again. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "ContainerRegistry|The last tag related to this image was recently removed. This empty image and any associated data will be automatically removed as part of the regular Garbage Collection process. If you have any questions, contact your administrator."
msgstr ""
@@ -7078,6 +7359,9 @@ msgstr ""
msgid "Contributions per group member"
msgstr ""
+msgid "Contributor"
+msgstr ""
+
msgid "Contributors"
msgstr ""
@@ -7207,6 +7491,9 @@ msgstr ""
msgid "Could not change HEAD: branch '%{branch}' does not exist"
msgstr ""
+msgid "Could not commit. An unexpected error occurred."
+msgstr ""
+
msgid "Could not connect to FogBugz, check your URL"
msgstr ""
@@ -7246,6 +7533,9 @@ msgstr ""
msgid "Could not find iteration"
msgstr ""
+msgid "Could not load instance counts. Please refresh the page to try again."
+msgstr ""
+
msgid "Could not remove the trigger."
msgstr ""
@@ -7270,10 +7560,10 @@ msgstr ""
msgid "Could not save prometheus manual configuration"
msgstr ""
-msgid "Could not udpdate wiki page"
+msgid "Could not update the LDAP settings"
msgstr ""
-msgid "Could not update the LDAP settings"
+msgid "Could not update wiki page"
msgstr ""
msgid "Could not upload your designs as one or more files uploaded are not supported."
@@ -7935,6 +8225,9 @@ msgstr ""
msgid "DastProfiles|Are you sure you want to delete this profile?"
msgstr ""
+msgid "DastProfiles|Could not create site validation token. Please refresh the page, or try again later."
+msgstr ""
+
msgid "DastProfiles|Could not create the scanner profile. Please try again."
msgstr ""
@@ -7959,6 +8252,12 @@ msgstr ""
msgid "DastProfiles|Could not fetch site profiles. Please refresh the page, or try again later."
msgstr ""
+msgid "DastProfiles|Could not retrieve site validation status. Please refresh the page, or try again later."
+msgstr ""
+
+msgid "DastProfiles|Could not update the scanner profile. Please try again."
+msgstr ""
+
msgid "DastProfiles|Could not update the site profile. Please try again."
msgstr ""
@@ -7974,7 +8273,7 @@ msgstr ""
msgid "DastProfiles|Download validation text file"
msgstr ""
-msgid "DastProfiles|Edit feature will come soon. Please create a new profile if changes needed"
+msgid "DastProfiles|Edit scanner profile"
msgstr ""
msgid "DastProfiles|Edit site profile"
@@ -8007,6 +8306,9 @@ msgstr ""
msgid "DastProfiles|No profiles created yet"
msgstr ""
+msgid "DastProfiles|Passive"
+msgstr ""
+
msgid "DastProfiles|Please enter a valid URL format, ex: http://www.example.com/home"
msgstr ""
@@ -8022,6 +8324,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan mode"
+msgstr ""
+
msgid "DastProfiles|Scanner Profile"
msgstr ""
@@ -8061,10 +8366,10 @@ msgstr ""
msgid "DastProfiles|Text file validation"
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
+msgid "DastProfiles|The maximum number of minutes allowed for the spider to traverse the site."
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the spider to traverse the site."
+msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
msgstr ""
msgid "DastProfiles|Validate"
@@ -8097,6 +8402,9 @@ msgstr ""
msgid "Date picker"
msgstr ""
+msgid "Date range"
+msgstr ""
+
msgid "Date range cannot exceed %{maxDateRange} days."
msgstr ""
@@ -8121,6 +8429,9 @@ msgstr ""
msgid "Days to merge"
msgstr ""
+msgid "Dear Administrator,"
+msgstr ""
+
msgid "Debug"
msgstr ""
@@ -8232,12 +8543,18 @@ msgstr ""
msgid "Delete"
msgstr ""
+msgid "Delete %{name}"
+msgstr ""
+
msgid "Delete Comment"
msgstr ""
msgid "Delete Snippet"
msgstr ""
+msgid "Delete Value Stream"
+msgstr ""
+
msgid "Delete account"
msgstr ""
@@ -8259,9 +8576,6 @@ msgstr ""
msgid "Delete label: %{label_name} ?"
msgstr ""
-msgid "Delete license"
-msgstr ""
-
msgid "Delete list"
msgstr ""
@@ -8337,15 +8651,6 @@ msgstr ""
msgid "Deleting a project places it into a read-only state until %{date}, at which point the project will be permanently deleted. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "Deleting the license failed."
-msgstr ""
-
-msgid "Deleting the license failed. The license was not found."
-msgstr ""
-
-msgid "Deleting the license failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "Deleting the project will delete its repository and all related resources including issues, merge requests etc."
msgstr ""
@@ -8853,7 +9158,10 @@ msgstr ""
msgid "DesignManagement|The maximum number of designs allowed to be uploaded is %{upload_limit}. Please try again."
msgstr ""
-msgid "DesignManagement|To upload designs, you'll need to enable LFS. %{requirements_link_start}More information%{requirements_link_end}"
+msgid "DesignManagement|There was an error moving your designs. Please upload your designs below."
+msgstr ""
+
+msgid "DesignManagement|To upload designs, you'll need to enable LFS and have admin enable hashed storage. %{requirements_link_start}More information%{requirements_link_end}"
msgstr ""
msgid "DesignManagement|Unresolve thread"
@@ -8865,6 +9173,9 @@ msgstr ""
msgid "DesignManagement|Upload skipped."
msgstr ""
+msgid "DesignManagement|Your designs are being copied and are on their way… Please refresh to update."
+msgstr ""
+
msgid "DesignManagement|and %{moreCount} more."
msgstr ""
@@ -8922,6 +9233,9 @@ msgstr ""
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
+msgid "Direct member"
+msgstr ""
+
msgid "Direction"
msgstr ""
@@ -8970,9 +9284,6 @@ msgstr ""
msgid "Discard draft"
msgstr ""
-msgid "Discard review"
-msgstr ""
-
msgid "DiscordService|Discord Notifications"
msgstr ""
@@ -9043,10 +9354,10 @@ msgstr ""
msgid "Dismiss Merge Request promotion"
msgstr ""
-msgid "Dismiss Selected"
+msgid "Dismiss Value Stream Analytics introduction box"
msgstr ""
-msgid "Dismiss Value Stream Analytics introduction box"
+msgid "Dismiss selected"
msgstr ""
msgid "Dismiss trial promotion"
@@ -9097,9 +9408,6 @@ msgstr ""
msgid "Documents reindexed: %{processed_documents} (%{percentage}%%)"
msgstr ""
-msgid "Doing"
-msgstr ""
-
msgid "Domain"
msgstr ""
@@ -9295,9 +9603,6 @@ msgstr ""
msgid "Edit environment"
msgstr ""
-msgid "Edit file"
-msgstr ""
-
msgid "Edit files in the editor and commit changes here"
msgstr ""
@@ -9310,6 +9615,12 @@ msgstr ""
msgid "Edit identity for %{user_name}"
msgstr ""
+msgid "Edit in Web IDE"
+msgstr ""
+
+msgid "Edit in single-file editor"
+msgstr ""
+
msgid "Edit issues"
msgstr ""
@@ -9337,10 +9648,10 @@ msgstr ""
msgid "Editing"
msgstr ""
-msgid "Elasticsearch"
+msgid "Elasticsearch AWS IAM credentials"
msgstr ""
-msgid "Elasticsearch AWS IAM credentials"
+msgid "Elasticsearch HTTP client timeout value in seconds."
msgstr ""
msgid "Elasticsearch indexing restrictions"
@@ -9349,9 +9660,6 @@ msgstr ""
msgid "Elasticsearch indexing started"
msgstr ""
-msgid "Elasticsearch integration. Elasticsearch AWS IAM."
-msgstr ""
-
msgid "Elasticsearch reindexing is already in progress"
msgstr ""
@@ -9379,9 +9687,6 @@ msgstr ""
msgid "Email Notification"
msgstr ""
-msgid "Email address"
-msgstr ""
-
msgid "Email could not be sent"
msgstr ""
@@ -9445,6 +9750,9 @@ msgstr ""
msgid "Emails sent from Service Desk will have this name"
msgstr ""
+msgid "Emails sent to %{email} will still be supported"
+msgstr ""
+
msgid "Emails separated by comma"
msgstr ""
@@ -9478,9 +9786,18 @@ msgstr ""
msgid "Enable"
msgstr ""
+msgid "Enable %{link_start}Gitpod%{link_end} integration to launch a development environment in your browser directly from GitLab."
+msgstr ""
+
msgid "Enable Auto DevOps"
msgstr ""
+msgid "Enable Gitpod"
+msgstr ""
+
+msgid "Enable Gitpod?"
+msgstr ""
+
msgid "Enable HTML emails"
msgstr ""
@@ -9610,9 +9927,6 @@ msgstr ""
msgid "Encountered an error while rendering: %{err}"
msgstr ""
-msgid "End date"
-msgstr ""
-
msgid "Ends at (UTC)"
msgstr ""
@@ -9772,7 +10086,7 @@ msgstr ""
msgid "EnvironmentsDashboard|The environments dashboard provides a summary of each project's environments' status, including pipeline and alert statuses."
msgstr ""
-msgid "EnvironmentsDashboard|This dashboard displays a maximum of 7 projects and 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
+msgid "EnvironmentsDashboard|This dashboard displays 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
msgstr ""
msgid "Environments|An error occurred while canceling the auto stop, please try again"
@@ -10093,6 +10407,9 @@ msgstr ""
msgid "Error deleting project. Check logs for error details."
msgstr ""
+msgid "Error fetching burnup chart data"
+msgstr ""
+
msgid "Error fetching diverging counts for branches. Please try again."
msgstr ""
@@ -10171,6 +10488,9 @@ msgstr ""
msgid "Error occurred when saving assignees"
msgstr ""
+msgid "Error occurred when saving reviewers"
+msgstr ""
+
msgid "Error occurred when toggling the notification subscription"
msgstr ""
@@ -10423,10 +10743,13 @@ msgstr ""
msgid "Expand all"
msgstr ""
-msgid "Expand approvers"
+msgid "Expand all files"
msgstr ""
-msgid "Expand dropdown"
+msgid "Expand all threads"
+msgstr ""
+
+msgid "Expand approvers"
msgstr ""
msgid "Expand milestones"
@@ -10597,6 +10920,9 @@ msgstr ""
msgid "Failed to create Merge Request. Please try again."
msgstr ""
+msgid "Failed to create To-Do for the design."
+msgstr ""
+
msgid "Failed to create a branch for this issue. Please try again."
msgstr ""
@@ -10636,6 +10962,12 @@ msgstr ""
msgid "Failed to load authors. Please try again."
msgstr ""
+msgid "Failed to load branches. Please try again."
+msgstr ""
+
+msgid "Failed to load deploy keys."
+msgstr ""
+
msgid "Failed to load emoji list."
msgstr ""
@@ -10651,6 +10983,9 @@ msgstr ""
msgid "Failed to load groups & users."
msgstr ""
+msgid "Failed to load groups, users and deploy keys."
+msgstr ""
+
msgid "Failed to load labels. Please try again."
msgstr ""
@@ -10660,6 +10995,12 @@ msgstr ""
msgid "Failed to load related branches"
msgstr ""
+msgid "Failed to load sidebar confidential toggle"
+msgstr ""
+
+msgid "Failed to load sidebar lock status"
+msgstr ""
+
msgid "Failed to load stacktrace."
msgstr ""
@@ -10687,6 +11028,9 @@ msgstr ""
msgid "Failed to publish issue on status page."
msgstr ""
+msgid "Failed to remove To-Do for the design."
+msgstr ""
+
msgid "Failed to remove a Zoom meeting"
msgstr ""
@@ -10729,6 +11073,9 @@ msgstr ""
msgid "Failed to signing using smartcard authentication"
msgstr ""
+msgid "Failed to toggle To-Do for the design."
+msgstr ""
+
msgid "Failed to update branch!"
msgstr ""
@@ -10844,7 +11191,7 @@ msgstr ""
msgid "FeatureFlags|Edit User List"
msgstr ""
-msgid "FeatureFlags|Enable features for specific users and specific environments by defining feature flag strategies."
+msgid "FeatureFlags|Enable features for specific users and environments by configuring feature flag strategies."
msgstr ""
msgid "FeatureFlags|Environment Spec"
@@ -10904,7 +11251,7 @@ msgstr ""
msgid "FeatureFlags|Include additional user IDs"
msgstr ""
-msgid "FeatureFlags|Install a %{docs_link_anchored_start}compatible client library%{docs_link_anchored_end} and specify the API URL, application name, and instance ID during the configuration setup. %{docs_link_start}More Information%{docs_link_end}"
+msgid "FeatureFlags|Install a %{docsLinkAnchoredStart}compatible client library%{docsLinkAnchoredEnd} and specify the API URL, application name, and instance ID during the configuration setup. %{docsLinkStart}More Information%{docsLinkEnd}"
msgstr ""
msgid "FeatureFlags|Instance ID"
@@ -10916,6 +11263,9 @@ msgstr ""
msgid "FeatureFlags|Loading feature flags"
msgstr ""
+msgid "FeatureFlags|Loading user lists"
+msgstr ""
+
msgid "FeatureFlags|More information"
msgstr ""
@@ -10934,7 +11284,7 @@ msgstr ""
msgid "FeatureFlags|New feature flag"
msgstr ""
-msgid "FeatureFlags|New list"
+msgid "FeatureFlags|New user list"
msgstr ""
msgid "FeatureFlags|Percent of users"
@@ -10973,6 +11323,9 @@ msgstr ""
msgid "FeatureFlags|There was an error fetching the feature flags."
msgstr ""
+msgid "FeatureFlags|There was an error fetching the user lists."
+msgstr ""
+
msgid "FeatureFlags|There was an error retrieving user lists"
msgstr ""
@@ -10988,6 +11341,9 @@ msgstr ""
msgid "FeatureFlags|User List"
msgstr ""
+msgid "FeatureFlags|User Lists"
+msgstr ""
+
msgid "FeatureFlag|List"
msgstr ""
@@ -11015,15 +11371,6 @@ msgstr ""
msgid "Fetching incoming email"
msgstr ""
-msgid "Fetching licenses failed."
-msgstr ""
-
-msgid "Fetching licenses failed. The request endpoint was not found."
-msgstr ""
-
-msgid "Fetching licenses failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "File"
msgstr ""
@@ -11126,12 +11473,21 @@ msgstr ""
msgid "Filter by status"
msgstr ""
+msgid "Filter by test cases that are currently archived."
+msgstr ""
+
+msgid "Filter by test cases that are currently opened."
+msgstr ""
+
msgid "Filter by two-factor authentication"
msgstr ""
msgid "Filter by user"
msgstr ""
+msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
+msgstr ""
+
msgid "Filter pipelines"
msgstr ""
@@ -11147,7 +11503,7 @@ msgstr ""
msgid "Filter results..."
msgstr ""
-msgid "Filter your projects by name"
+msgid "Filter your repositories by name"
msgstr ""
msgid "Filter..."
@@ -11156,7 +11512,7 @@ msgstr ""
msgid "Find File"
msgstr ""
-msgid "Find bugs in your code with coverage-guided fuzzing"
+msgid "Find bugs in your code with coverage-guided fuzzing."
msgstr ""
msgid "Find by path"
@@ -11183,9 +11539,6 @@ msgstr ""
msgid "Finish editing this message first!"
msgstr ""
-msgid "Finish review"
-msgstr ""
-
msgid "Finish setting up your dedicated account for %{group_name}."
msgstr ""
@@ -11255,6 +11608,9 @@ msgstr ""
msgid "Footer message"
msgstr ""
+msgid "For a faster browsing experience, some files are collapsed by default."
+msgstr ""
+
msgid "For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
@@ -11264,6 +11620,9 @@ msgstr ""
msgid "For more info, read the documentation."
msgstr ""
+msgid "For more information on how the number of active users is calculated, see the %{self_managed_subscriptions_doc_link} documentation."
+msgstr ""
+
msgid "For more information, go to the "
msgstr ""
@@ -11402,6 +11761,9 @@ msgstr ""
msgid "Generate new token"
msgstr ""
+msgid "Generic package file size in bytes"
+msgstr ""
+
msgid "Geo"
msgstr ""
@@ -11663,6 +12025,9 @@ msgstr ""
msgid "Geo|Please refer to Geo Troubleshooting."
msgstr ""
+msgid "Geo|Primary node"
+msgstr ""
+
msgid "Geo|Project"
msgstr ""
@@ -11705,6 +12070,9 @@ msgstr ""
msgid "Geo|Review replication status, and resynchronize and reverify items with the primary node."
msgstr ""
+msgid "Geo|Secondary node"
+msgstr ""
+
msgid "Geo|Status"
msgstr ""
@@ -11744,6 +12112,9 @@ msgstr ""
msgid "Geo|URL must be a valid url (ex: https://gitlab.com)"
msgstr ""
+msgid "Geo|Undefined"
+msgstr ""
+
msgid "Geo|Unknown state"
msgstr ""
@@ -11819,10 +12190,16 @@ msgstr ""
msgid "GitHub import"
msgstr ""
+msgid "GitLab"
+msgstr ""
+
msgid "GitLab / Unsubscribe"
msgstr ""
-msgid "GitLab Enterprise Edition %{plan}"
+msgid "GitLab API"
+msgstr ""
+
+msgid "GitLab Billing Team."
msgstr ""
msgid "GitLab Group Runners can execute code for all the projects in this group."
@@ -11834,12 +12211,18 @@ msgstr ""
msgid "GitLab Issue"
msgstr ""
+msgid "GitLab Pages"
+msgstr ""
+
msgid "GitLab Service Desk is a simple way to allow people to create issues in your GitLab instance without needing their own user account. It provides a unique email address for end users to create issues in a project, and replies can be sent either through the GitLab interface or by email. End users will only see the thread through email."
msgstr ""
msgid "GitLab Shared Runners execute code of different projects on the same Runner unless you configure GitLab Runner Autoscale with MaxBuilds 1 (which it is on GitLab.com)."
msgstr ""
+msgid "GitLab Shell"
+msgstr ""
+
msgid "GitLab Support Bot"
msgstr ""
@@ -11849,7 +12232,7 @@ msgstr ""
msgid "GitLab User"
msgstr ""
-msgid "GitLab allows you to continue using your license even if you exceed the number of seats you purchased. You will be required to pay for these seats when you renew your license."
+msgid "GitLab Workhorse"
msgstr ""
msgid "GitLab commit"
@@ -12017,6 +12400,21 @@ msgstr ""
msgid "Gitlab Pages"
msgstr ""
+msgid "Gitpod"
+msgstr ""
+
+msgid "Gitpod|Add the URL to your Gitpod instance configured to read your GitLab projects."
+msgstr ""
+
+msgid "Gitpod|Enable Gitpod integration"
+msgstr ""
+
+msgid "Gitpod|Gitpod URL"
+msgstr ""
+
+msgid "Gitpod|e.g. https://gitpod.example.com"
+msgstr ""
+
msgid "Given access %{time_ago}"
msgstr ""
@@ -12524,9 +12922,6 @@ msgstr ""
msgid "GroupSAML|Valid SAML Response"
msgstr ""
-msgid "GroupSAML|With group managed accounts enabled, all the users without a group managed account will be excluded from the group."
-msgstr ""
-
msgid "GroupSAML|With prohibit outer forks flag enabled group members will be able to fork project only inside your group."
msgstr ""
@@ -12740,10 +13135,10 @@ msgstr ""
msgid "GroupsNew|Create group"
msgstr ""
-msgid "GroupsNew|GitLab group export"
+msgid "GroupsNew|Import"
msgstr ""
-msgid "GroupsNew|Import"
+msgid "GroupsNew|Import a GitLab group export file"
msgstr ""
msgid "GroupsNew|Import group"
@@ -12888,6 +13283,9 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "Hide comments on this file"
+msgstr ""
+
msgid "Hide details"
msgstr ""
@@ -12934,6 +13332,15 @@ msgstr ""
msgid "Highest role:"
msgstr ""
+msgid "HighlightBar|Alert events:"
+msgstr ""
+
+msgid "HighlightBar|Alert start time:"
+msgstr ""
+
+msgid "HighlightBar|Original alert:"
+msgstr ""
+
msgid "History"
msgstr ""
@@ -13111,6 +13518,9 @@ msgstr ""
msgid "If enabled, access to projects will be validated on an external service using their classification label."
msgstr ""
+msgid "If the number of active users exceeds the user limit, you will be charged for the number of %{users_over_license_link} at your next license reconciliation."
+msgstr ""
+
msgid "If there is no previous license or if the previous license has expired, some GitLab functionality will be blocked until a new, valid license is uploaded."
msgstr ""
@@ -13150,9 +13560,6 @@ msgstr ""
msgid "If your HTTP repository is not publicly accessible, add your credentials."
msgstr ""
-msgid "Iglu registry URL (optional)"
-msgstr ""
-
msgid "Ignore"
msgstr ""
@@ -13189,6 +13596,20 @@ msgstr ""
msgid "Import"
msgstr ""
+msgid "Import %d compatible repository"
+msgid_plural "Import %d compatible repositories"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
+msgid "Import %d repository"
+msgid_plural "Import %d repositories"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "Import CSV"
msgstr ""
@@ -13198,15 +13619,9 @@ msgstr ""
msgid "Import all compatible projects"
msgstr ""
-msgid "Import all compatible repositories"
-msgstr ""
-
msgid "Import all projects"
msgstr ""
-msgid "Import all repositories"
-msgstr ""
-
msgid "Import an exported GitLab project"
msgstr ""
@@ -13294,6 +13709,9 @@ msgstr ""
msgid "ImportProjects|Error importing repository %{project_safe_import_url} into %{project_full_path} - %{message}"
msgstr ""
+msgid "ImportProjects|Import repositories"
+msgstr ""
+
msgid "ImportProjects|Importing the project failed"
msgstr ""
@@ -13306,7 +13724,7 @@ msgstr ""
msgid "ImportProjects|Requesting your %{provider} repositories failed"
msgstr ""
-msgid "ImportProjects|Select the projects you want to import"
+msgid "ImportProjects|Select the repositories you want to import"
msgstr ""
msgid "ImportProjects|The remote data could not be imported."
@@ -13342,9 +13760,6 @@ msgstr ""
msgid "In order to enable Service Desk for your instance, you must first set up incoming email."
msgstr ""
-msgid "In order to gather accurate feature usage data, it can take 1 to 2 weeks to see your index."
-msgstr ""
-
msgid "In order to personalize your experience with GitLab%{br_tag}we would like to know a bit more about you."
msgstr ""
@@ -13375,18 +13790,30 @@ msgstr ""
msgid "IncidentManagement|Create incident"
msgstr ""
+msgid "IncidentManagement|Critical - S1"
+msgstr ""
+
msgid "IncidentManagement|Date created"
msgstr ""
msgid "IncidentManagement|Display your incidents in a dedicated view"
msgstr ""
+msgid "IncidentManagement|High - S2"
+msgstr ""
+
msgid "IncidentManagement|Incident"
msgstr ""
msgid "IncidentManagement|Incidents"
msgstr ""
+msgid "IncidentManagement|Low - S4"
+msgstr ""
+
+msgid "IncidentManagement|Medium - S3"
+msgstr ""
+
msgid "IncidentManagement|No incidents to display."
msgstr ""
@@ -13399,6 +13826,9 @@ msgstr ""
msgid "IncidentManagement|Published to status page"
msgstr ""
+msgid "IncidentManagement|Severity"
+msgstr ""
+
msgid "IncidentManagement|There are no closed incidents"
msgstr ""
@@ -13408,6 +13838,9 @@ msgstr ""
msgid "IncidentManagement|Unassigned"
msgstr ""
+msgid "IncidentManagement|Unknown"
+msgstr ""
+
msgid "IncidentManagement|Unpublished"
msgstr ""
@@ -13429,6 +13862,15 @@ msgstr ""
msgid "Incidents"
msgstr ""
+msgid "Incident|Alert details"
+msgstr ""
+
+msgid "Incident|Summary"
+msgstr ""
+
+msgid "Incident|There was an issue loading alert data. Please try again."
+msgstr ""
+
msgid "Include a Terms of Service agreement and Privacy Policy that all users must accept."
msgstr ""
@@ -13489,6 +13931,9 @@ msgstr ""
msgid "Information about additional Pages templates and how to install them can be found in our %{pages_getting_started_guide}."
msgstr ""
+msgid "Inherited"
+msgstr ""
+
msgid "Inherited:"
msgstr ""
@@ -13571,7 +14016,22 @@ msgstr ""
msgid "Instance administrators group already exists"
msgstr ""
-msgid "Instance license"
+msgid "InstanceStatistics|Groups"
+msgstr ""
+
+msgid "InstanceStatistics|Issues"
+msgstr ""
+
+msgid "InstanceStatistics|Merge Requests"
+msgstr ""
+
+msgid "InstanceStatistics|Pipelines"
+msgstr ""
+
+msgid "InstanceStatistics|Projects"
+msgstr ""
+
+msgid "InstanceStatistics|Users"
msgstr ""
msgid "Integration"
@@ -13583,6 +14043,12 @@ msgstr ""
msgid "Integrations"
msgstr ""
+msgid "Integrations|%{integration} settings saved and active."
+msgstr ""
+
+msgid "Integrations|%{integration} settings saved, but not active."
+msgstr ""
+
msgid "Integrations|All details"
msgstr ""
@@ -13592,6 +14058,12 @@ msgstr ""
msgid "Integrations|Comment settings:"
msgstr ""
+msgid "Integrations|Connection failed. Please check your settings."
+msgstr ""
+
+msgid "Integrations|Connection successful."
+msgstr ""
+
msgid "Integrations|Default settings are inherited from the group level."
msgstr ""
@@ -13607,6 +14079,15 @@ msgstr ""
msgid "Integrations|Includes commit title and branch"
msgstr ""
+msgid "Integrations|Projects using custom settings will not be impacted unless the project owner chooses to use instance-level defaults."
+msgstr ""
+
+msgid "Integrations|Save settings?"
+msgstr ""
+
+msgid "Integrations|Saving will update the default settings for all projects that are not using custom settings."
+msgstr ""
+
msgid "Integrations|Standard"
msgstr ""
@@ -13739,6 +14220,9 @@ msgstr ""
msgid "Invitation"
msgstr ""
+msgid "Invitation declined"
+msgstr ""
+
msgid "Invite"
msgstr ""
@@ -13790,6 +14274,42 @@ 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|%{linkStart}Read more%{linkEnd} about role permissions"
+msgstr ""
+
+msgid "InviteMembersModal|Access expiration date (optional)"
+msgstr ""
+
+msgid "InviteMembersModal|Cancel"
+msgstr ""
+
+msgid "InviteMembersModal|Choose a role permission"
+msgstr ""
+
+msgid "InviteMembersModal|GitLab member or Email address"
+msgstr ""
+
+msgid "InviteMembersModal|Invite"
+msgstr ""
+
+msgid "InviteMembersModal|Invite team members"
+msgstr ""
+
+msgid "InviteMembersModal|Search for members to invite"
+msgstr ""
+
+msgid "InviteMembersModal|User not invited. Feature coming soon!"
+msgstr ""
+
+msgid "InviteMembersModal|Users were succesfully added"
+msgstr ""
+
+msgid "InviteMembersModal|You're inviting members to the %{group_name} group"
+msgstr ""
+
+msgid "InviteMembers|Invite team members"
+msgstr ""
+
msgid "Invited"
msgstr ""
@@ -13844,10 +14364,13 @@ msgstr ""
msgid "Issue cannot be found."
msgstr ""
+msgid "Issue created from vulnerability %{vulnerability_link}"
+msgstr ""
+
msgid "Issue events"
msgstr ""
-msgid "Issue first depoloyed to production"
+msgid "Issue first deployed to production"
msgstr ""
msgid "Issue label"
@@ -13925,6 +14448,9 @@ msgstr ""
msgid "IssueTracker|Custom issue tracker"
msgstr ""
+msgid "IssueTracker|EWM work items tracker"
+msgstr ""
+
msgid "IssueTracker|Redmine issue tracker"
msgstr ""
@@ -13991,6 +14517,9 @@ msgstr ""
msgid "It looks like you have some draft commits in this branch."
msgstr ""
+msgid "It may be several days before you see feature usage data."
+msgstr ""
+
msgid "It must have a header row and at least two columns: the first column is the issue title and the second column is the issue description. The separator is automatically detected."
msgstr ""
@@ -14273,13 +14802,13 @@ msgstr ""
msgid "Join Zoom meeting"
msgstr ""
-msgid "Jul"
+msgid "Joined %{time_ago}"
msgstr ""
-msgid "July"
+msgid "Jul"
msgstr ""
-msgid "Jump to first unresolved thread"
+msgid "July"
msgstr ""
msgid "Jump to next unresolved thread"
@@ -14315,6 +14844,9 @@ msgstr ""
msgid "Keyboard shortcuts"
msgstr ""
+msgid "KeyboardKey|Ctrl+"
+msgstr ""
+
msgid "Keys"
msgstr ""
@@ -14363,6 +14895,9 @@ msgstr ""
msgid "LDAP Synchronization"
msgstr ""
+msgid "LDAP group settings"
+msgstr ""
+
msgid "LDAP settings"
msgstr ""
@@ -14372,6 +14907,9 @@ msgstr ""
msgid "LDAP sync in progress. This could take a few minutes. Refresh the page to see the changes."
msgstr ""
+msgid "LDAP synchronizations"
+msgstr ""
+
msgid "LFS"
msgstr ""
@@ -14454,7 +14992,16 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "Last %{days} days"
+msgid "Last 2 weeks"
+msgstr ""
+
+msgid "Last 30 days"
+msgstr ""
+
+msgid "Last 60 days"
+msgstr ""
+
+msgid "Last 90 days"
msgstr ""
msgid "Last Accessed On"
@@ -14532,6 +15079,9 @@ msgstr ""
msgid "Last used on:"
msgstr ""
+msgid "Last week"
+msgstr ""
+
msgid "LastCommit|authored"
msgstr ""
@@ -14547,6 +15097,9 @@ msgstr ""
msgid "Latest pipeline for the most recent commit on this branch"
msgstr ""
+msgid "Launch a ready-to-code development environment for your project."
+msgstr ""
+
msgid "Lead"
msgstr ""
@@ -14941,6 +15494,9 @@ msgstr ""
msgid "List of all merge commits"
msgstr ""
+msgid "List options"
+msgstr ""
+
msgid "List settings"
msgstr ""
@@ -14953,9 +15509,6 @@ msgstr ""
msgid "List your Bitbucket Server repositories"
msgstr ""
-msgid "Lists"
-msgstr ""
-
msgid "Live preview"
msgstr ""
@@ -15202,6 +15755,12 @@ msgstr ""
msgid "Mark as done"
msgstr ""
+msgid "Mark as draft"
+msgstr ""
+
+msgid "Mark as ready"
+msgstr ""
+
msgid "Mark as resolved"
msgstr ""
@@ -15223,6 +15782,24 @@ msgstr ""
msgid "Markdown is supported"
msgstr ""
+msgid "MarkdownEditor|Add a link (%{modifierKey}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add a link (%{modifier_key}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifierKey}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifier_key}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifierKey}I)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifier_key}I)"
+msgstr ""
+
msgid "Marked For Deletion At - %{deletion_time}"
msgstr ""
@@ -15307,7 +15884,25 @@ msgstr ""
msgid "Max access level"
msgstr ""
-msgid "Max seats used"
+msgid "Max role"
+msgstr ""
+
+msgid "Max size 15 MB"
+msgstr ""
+
+msgid "Maximum Conan package file size in bytes"
+msgstr ""
+
+msgid "Maximum Maven package file size in bytes"
+msgstr ""
+
+msgid "Maximum NPM package file size in bytes"
+msgstr ""
+
+msgid "Maximum NuGet package file size in bytes"
+msgstr ""
+
+msgid "Maximum PyPI package file size in bytes"
msgstr ""
msgid "Maximum Users:"
@@ -15439,6 +16034,18 @@ msgstr ""
msgid "Members with access to %{strong_start}%{group_name}%{strong_end}"
msgstr ""
+msgid "Members|%{time} by %{user}"
+msgstr ""
+
+msgid "Members|Expired"
+msgstr ""
+
+msgid "Members|No expiration set"
+msgstr ""
+
+msgid "Members|in %{time}"
+msgstr ""
+
msgid "Memory Usage"
msgstr ""
@@ -15625,9 +16232,6 @@ msgstr ""
msgid "MergeRequests|Thread will be unresolved"
msgstr ""
-msgid "MergeRequests|Toggle comments for this file"
-msgstr ""
-
msgid "MergeRequests|View file @ %{commitId}"
msgstr ""
@@ -15688,6 +16292,9 @@ msgstr ""
msgid "Merging immediately isn't recommended as it may negatively impact the existing merge train. Read the %{docsLinkStart}documentation%{docsLinkEnd} for more information."
msgstr ""
+msgid "Message"
+msgstr ""
+
msgid "Messages"
msgstr ""
@@ -16077,18 +16684,12 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "Milestone does not support burnup charts"
-msgstr ""
-
msgid "Milestone lists not available with your current license"
msgstr ""
msgid "Milestone lists show all issues from the selected milestone."
msgstr ""
-msgid "Milestone must have a start and due date"
-msgstr ""
-
msgid "MilestoneSidebar|Closed:"
msgstr ""
@@ -16455,6 +17056,9 @@ msgstr ""
msgid "Namespace"
msgstr ""
+msgid "Namespace ID:"
+msgstr ""
+
msgid "Namespace is empty"
msgstr ""
@@ -16539,6 +17143,9 @@ msgstr ""
msgid "NetworkPolicies|Allow all outbound traffic from %{selector} to %{ruleSelector} on %{ports}"
msgstr ""
+msgid "NetworkPolicies|Are you sure you want to delete this policy? This action cannot be undone."
+msgstr ""
+
msgid "NetworkPolicies|Choose whether to enforce this policy."
msgstr ""
@@ -16548,12 +17155,21 @@ msgstr ""
msgid "NetworkPolicies|Define this policy's location, conditions and actions."
msgstr ""
+msgid "NetworkPolicies|Delete policy"
+msgstr ""
+
+msgid "NetworkPolicies|Delete policy: %{policy}"
+msgstr ""
+
msgid "NetworkPolicies|Deny all traffic"
msgstr ""
msgid "NetworkPolicies|Description"
msgstr ""
+msgid "NetworkPolicies|Edit policy"
+msgstr ""
+
msgid "NetworkPolicies|Editor mode"
msgstr ""
@@ -16581,6 +17197,9 @@ msgstr ""
msgid "NetworkPolicies|Name"
msgstr ""
+msgid "NetworkPolicies|Namespace"
+msgstr ""
+
msgid "NetworkPolicies|Network Policy"
msgstr ""
@@ -16632,6 +17251,9 @@ msgstr ""
msgid "NetworkPolicies|Rules"
msgstr ""
+msgid "NetworkPolicies|Save changes"
+msgstr ""
+
msgid "NetworkPolicies|Something went wrong, failed to update policy"
msgstr ""
@@ -16644,6 +17266,9 @@ msgstr ""
msgid "NetworkPolicies|Traffic that does not match any rule will be blocked."
msgstr ""
+msgid "NetworkPolicies|Unable to parse policy"
+msgstr ""
+
msgid "NetworkPolicies|YAML editor"
msgstr ""
@@ -16759,6 +17384,9 @@ msgstr ""
msgid "New Snippet"
msgstr ""
+msgid "New Test Case"
+msgstr ""
+
msgid "New User"
msgstr ""
@@ -16858,6 +17486,9 @@ msgstr ""
msgid "New tag"
msgstr ""
+msgid "New test case"
+msgstr ""
+
msgid "New users set to external"
msgstr ""
@@ -16930,7 +17561,7 @@ msgstr ""
msgid "No changes"
msgstr ""
-msgid "No changes between %{ref_start}%{source_branch}%{ref_end} and %{ref_start}%{target_branch}%{ref_end}"
+msgid "No changes between %{sourceBranch} and %{targetBranch}"
msgstr ""
msgid "No child epics match applied filters"
@@ -16945,6 +17576,9 @@ msgstr ""
msgid "No containers available"
msgstr ""
+msgid "No content to show"
+msgstr ""
+
msgid "No contributions"
msgstr ""
@@ -17020,9 +17654,6 @@ msgstr ""
msgid "No license. All rights reserved"
msgstr ""
-msgid "No licenses found."
-msgstr ""
-
msgid "No matches found"
msgstr ""
@@ -17035,6 +17666,9 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No members found"
+msgstr ""
+
msgid "No merge requests found"
msgstr ""
@@ -17056,6 +17690,9 @@ msgstr ""
msgid "No parent group"
msgstr ""
+msgid "No plan"
+msgstr ""
+
msgid "No pods available"
msgstr ""
@@ -17152,6 +17789,12 @@ msgstr ""
msgid "Not Implemented"
msgstr ""
+msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+msgstr ""
+
+msgid "Not all browsers support WebAuthn. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even from an unsupported browser."
+msgstr ""
+
msgid "Not all data has been processed yet, the accuracy of the chart for the selected timeframe is limited."
msgstr ""
@@ -17248,6 +17891,9 @@ msgstr ""
msgid "Notification settings saved"
msgstr ""
+msgid "NotificationEvent|Change reviewer merge request"
+msgstr ""
+
msgid "NotificationEvent|Close issue"
msgstr ""
@@ -17410,10 +18056,7 @@ msgstr ""
msgid "On track"
msgstr ""
-msgid "OnDemandScans|Attached branch"
-msgstr ""
-
-msgid "OnDemandScans|Attached branch is where the scan job runs."
+msgid "OnDemandScans|Could not fetch scanner profiles. Please refresh the page, or try again later."
msgstr ""
msgid "OnDemandScans|Could not fetch site profiles. Please refresh the page, or try again later."
@@ -17422,6 +18065,9 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
+msgid "OnDemandScans|Create a new scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Create a new site profile"
msgstr ""
@@ -17434,6 +18080,9 @@ msgstr ""
msgid "OnDemandScans|New on-demand DAST scan"
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 ""
@@ -17443,16 +18092,10 @@ msgstr ""
msgid "OnDemandScans|On-demand scans run outside the DevOps cycle and find vulnerabilities in your projects. %{learnMoreLinkStart}Learn more%{learnMoreLinkEnd}"
msgstr ""
-msgid "OnDemandScans|Only a passive scan can be performed on demand."
-msgstr ""
-
-msgid "OnDemandScans|Passive"
-msgstr ""
-
msgid "OnDemandScans|Run scan"
msgstr ""
-msgid "OnDemandScans|Scan mode"
+msgid "OnDemandScans|Scanner profile"
msgstr ""
msgid "OnDemandScans|Scanner settings"
@@ -17464,9 +18107,15 @@ msgstr ""
msgid "OnDemandScans|Select one of the existing profiles"
msgstr ""
+msgid "OnDemandScans|Site profile"
+msgstr ""
+
msgid "OnDemandScans|Site profiles"
msgstr ""
+msgid "OnDemandScans|Use existing scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Use existing site profile"
msgstr ""
@@ -17567,9 +18216,6 @@ msgstr ""
msgid "Open Selection"
msgstr ""
-msgid "Open Web IDE"
-msgstr ""
-
msgid "Open comment type dropdown"
msgstr ""
@@ -17675,6 +18321,9 @@ msgstr ""
msgid "Origin"
msgstr ""
+msgid "Orphaned member"
+msgstr ""
+
msgid "Other Labels"
msgstr ""
@@ -17690,6 +18339,9 @@ msgstr ""
msgid "Other visibility settings have been disabled by the administrator."
msgstr ""
+msgid "Our documentation includes an example DevOps Score report."
+msgstr ""
+
msgid "Out-of-compliance with this project's policies and should be removed"
msgstr ""
@@ -17714,6 +18366,9 @@ msgstr ""
msgid "Overwrite diverged branches"
msgstr ""
+msgid "Owned by %{image_tag}"
+msgstr ""
+
msgid "Owned by anyone"
msgstr ""
@@ -17735,6 +18390,9 @@ msgstr ""
msgid "Package deleted successfully"
msgstr ""
+msgid "Package file size limits"
+msgstr ""
+
msgid "Package recipe already exists"
msgstr ""
@@ -17750,9 +18408,6 @@ msgstr ""
msgid "Package type must be PyPi"
msgstr ""
-msgid "Package was removed"
-msgstr ""
-
msgid "PackageRegistry|%{name} version %{version} was created %{datetime}"
msgstr ""
@@ -17894,12 +18549,18 @@ msgstr ""
msgid "PackageRegistry|NuGet Command"
msgstr ""
+msgid "PackageRegistry|Package Registry"
+msgstr ""
+
msgid "PackageRegistry|Pip Command"
msgstr ""
msgid "PackageRegistry|Pipeline %{link} triggered %{datetime} by %{author}"
msgstr ""
+msgid "PackageRegistry|Publish and share packages for a variety of common package managers. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "PackageRegistry|Published to the %{project} Package Registry %{datetime}"
msgstr ""
@@ -17999,6 +18660,9 @@ msgstr ""
msgid "Page not found"
msgstr ""
+msgid "Page settings"
+msgstr ""
+
msgid "Page was successfully deleted"
msgstr ""
@@ -18140,7 +18804,7 @@ msgstr ""
msgid "Paste issue link"
msgstr ""
-msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Don't use your private SSH key."
+msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Do not paste your private SSH key, as that can compromise your identity."
msgstr ""
msgid "Patch to apply"
@@ -18167,6 +18831,9 @@ msgstr ""
msgid "Pending"
msgstr ""
+msgid "Pending comments"
+msgstr ""
+
msgid "People without permission will never get a notification and won't be able to comment."
msgstr ""
@@ -18365,6 +19032,9 @@ msgstr ""
msgid "Pipelines|Build with confidence"
msgstr ""
+msgid "Pipelines|By revoking a trigger you will break any processes making use of it. Are you sure?"
+msgstr ""
+
msgid "Pipelines|CI Lint"
msgstr ""
@@ -18377,6 +19047,15 @@ msgstr ""
msgid "Pipelines|Continuous Integration can help catch bugs by running your tests automatically, while Continuous Deployment can help you deliver code to your product environment."
msgstr ""
+msgid "Pipelines|Copy trigger token"
+msgstr ""
+
+msgid "Pipelines|Description"
+msgstr ""
+
+msgid "Pipelines|Edit"
+msgstr ""
+
msgid "Pipelines|Get started with Pipelines"
msgstr ""
@@ -18392,15 +19071,27 @@ msgstr ""
msgid "Pipelines|It is recommended the code is reviewed thoroughly before running this pipeline with the parent project's CI resource."
msgstr ""
+msgid "Pipelines|Last Used"
+msgstr ""
+
msgid "Pipelines|Loading Pipelines"
msgstr ""
msgid "Pipelines|More Information"
msgstr ""
+msgid "Pipelines|No triggers have been created yet. Add one using the form above."
+msgstr ""
+
+msgid "Pipelines|Owner"
+msgstr ""
+
msgid "Pipelines|Project cache successfully reset."
msgstr ""
+msgid "Pipelines|Revoke"
+msgstr ""
+
msgid "Pipelines|Run Pipeline"
msgstr ""
@@ -18425,6 +19116,15 @@ msgstr ""
msgid "Pipelines|This project is not currently set up to run pipelines."
msgstr ""
+msgid "Pipelines|Token"
+msgstr ""
+
+msgid "Pipelines|Trigger user has insufficient permissions to project"
+msgstr ""
+
+msgid "Pipelines|invalid"
+msgstr ""
+
msgid "Pipelines|parent"
msgstr ""
@@ -18683,10 +19383,10 @@ msgstr ""
msgid "Please provide attributes to update"
msgstr ""
-msgid "Please refer to %{docs_url}"
+msgid "Please reach out if you have any questions and we'll be happy to assist."
msgstr ""
-msgid "Please retype the email address."
+msgid "Please refer to %{docs_url}"
msgstr ""
msgid "Please select"
@@ -18716,6 +19416,9 @@ msgstr ""
msgid "Please set a new password before proceeding."
msgstr ""
+msgid "Please share your feedback about %{featureName} %{linkStart}in this issue%{linkEnd} to help us improve the experience."
+msgstr ""
+
msgid "Please solve the reCAPTCHA"
msgstr ""
@@ -19019,6 +19722,9 @@ msgstr ""
msgid "Profiles| You are going to change the username %{currentUsernameBold} to %{newUsernameBold}. Profile and projects will be redirected to the %{newUsername} namespace but this redirect will expire once the %{currentUsername} namespace is registered by another user or group. Please update your Git repository remotes as soon as possible."
msgstr ""
+msgid "Profiles|%{provider} Active"
+msgstr ""
+
msgid "Profiles|@username"
msgstr ""
@@ -19070,7 +19776,7 @@ msgstr ""
msgid "Profiles|Commit email"
msgstr ""
-msgid "Profiles|Connect"
+msgid "Profiles|Connect %{provider}"
msgstr ""
msgid "Profiles|Connected Accounts"
@@ -19094,6 +19800,9 @@ msgstr ""
msgid "Profiles|Disconnect"
msgstr ""
+msgid "Profiles|Disconnect %{provider}"
+msgstr ""
+
msgid "Profiles|Do not show on profile"
msgstr ""
@@ -19118,7 +19827,7 @@ msgstr ""
msgid "Profiles|Full name"
msgstr ""
-msgid "Profiles|Give your individual key a title. This will be publically visible."
+msgid "Profiles|Give your individual key a title."
msgstr ""
msgid "Profiles|Include private contributions on my profile"
@@ -19208,7 +19917,7 @@ msgstr ""
msgid "Profiles|The maximum file size allowed is 200KB."
msgstr ""
-msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it?"
+msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it? It will be publicly visible."
msgstr ""
msgid "Profiles|This email will be displayed on your public profile"
@@ -19283,6 +19992,9 @@ msgstr ""
msgid "Profiles|You don't have access to delete this user."
msgstr ""
+msgid "Profiles|You must transfer ownership or delete groups you are an owner of before you can delete your account"
+msgstr ""
+
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
@@ -19871,6 +20583,9 @@ msgstr ""
msgid "ProjectTemplates|GitLab Cluster Management"
msgstr ""
+msgid "ProjectTemplates|Gitpod/Spring Petclinic"
+msgstr ""
+
msgid "ProjectTemplates|Go Micro"
msgstr ""
@@ -20480,6 +21195,9 @@ msgstr ""
msgid "Publish to status page"
msgstr ""
+msgid "Published"
+msgstr ""
+
msgid "Published on status page"
msgstr ""
@@ -20597,9 +21315,15 @@ msgstr ""
msgid "Quick range"
msgstr ""
+msgid "Quickly and easily edit multiple files in your project."
+msgstr ""
+
msgid "README"
msgstr ""
+msgid "Rails"
+msgstr ""
+
msgid "Rake Tasks Help"
msgstr ""
@@ -20721,10 +21445,13 @@ msgstr ""
msgid "Register Two-Factor Authenticator"
msgstr ""
-msgid "Register U2F device"
+msgid "Register Universal Two-Factor (U2F) Device"
+msgstr ""
+
+msgid "Register WebAuthn Device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register device"
msgstr ""
msgid "Register for GitLab"
@@ -20736,9 +21463,6 @@ msgstr ""
msgid "Register with two-factor app"
msgstr ""
-msgid "Registration"
-msgstr ""
-
msgid "Registration|Checkout"
msgstr ""
@@ -20857,9 +21581,6 @@ msgstr ""
msgid "Release|Something went wrong while saving the release details"
msgstr ""
-msgid "Remediated: needs review"
-msgstr ""
-
msgid "Remediations"
msgstr ""
@@ -20965,6 +21686,9 @@ msgstr ""
msgid "Remove priority"
msgstr ""
+msgid "Remove report"
+msgstr ""
+
msgid "Remove secondary node"
msgstr ""
@@ -20977,6 +21701,12 @@ msgstr ""
msgid "Remove time estimate"
msgstr ""
+msgid "Remove user & report"
+msgstr ""
+
+msgid "Remove user from group"
+msgstr ""
+
msgid "Removed"
msgstr ""
@@ -21058,9 +21788,6 @@ msgstr ""
msgid "Removes time estimate."
msgstr ""
-msgid "Removing license…"
-msgstr ""
-
msgid "Removing this group also removes all child projects, including archived projects, and their resources."
msgstr ""
@@ -21145,6 +21872,9 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
+msgid "Reported by %{reporter}"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -21233,6 +21963,27 @@ msgstr ""
msgid "Repositories"
msgstr ""
+msgid "Repositories Analytics"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download Historic Test Coverage Data"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download historic test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Historic Test Coverage Data is available in raw format (.csv) for further analysis."
+msgstr ""
+
+msgid "RepositoriesAnalytics|Test Code Coverage"
+msgstr ""
+
+msgid "RepositoriesAnalytics|There was an error fetching the projects."
+msgstr ""
+
msgid "Repository"
msgstr ""
@@ -21311,9 +22062,15 @@ msgstr ""
msgid "Request parameter %{param} is missing."
msgstr ""
+msgid "Request review from"
+msgstr ""
+
msgid "Request to link SAML account must be authorized"
msgstr ""
+msgid "Requested"
+msgstr ""
+
msgid "Requested %{time_ago}"
msgstr ""
@@ -21332,6 +22089,9 @@ msgstr ""
msgid "Requests to these domain(s)/address(es) on the local network will be allowed when local requests from hooks and services are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 or 127.0.0.0/28 are supported. Domain wildcards are not supported currently. Use comma, semicolon, or newline to separate multiple entries. The allowlist can hold a maximum of 1000 entries. Domains should use IDNA encoding. Ex: example.com, 192.168.1.1, 127.0.0.0/28, xn--itlab-j1a.com."
msgstr ""
+msgid "Require admin approval for new sign-ups"
+msgstr ""
+
msgid "Require all users in this group to setup Two-factor authentication"
msgstr ""
@@ -21463,9 +22223,6 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
-msgid "Resolved by %{resolvedByName}"
-msgstr ""
-
msgid "Resolves IP addresses once and uses them to submit requests"
msgstr ""
@@ -21587,6 +22344,16 @@ msgstr ""
msgid "ReviewApp|Enable Review App"
msgstr ""
+msgid "Reviewer"
+msgid_plural "%d Reviewers"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
+msgid "Reviewer(s)"
+msgstr ""
+
msgid "Reviewing"
msgstr ""
@@ -21626,6 +22393,9 @@ msgstr ""
msgid "Rook"
msgstr ""
+msgid "Ruby"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -21704,6 +22474,63 @@ msgstr ""
msgid "Runners page."
msgstr ""
+msgid "Runners|Active"
+msgstr ""
+
+msgid "Runners|Architecture"
+msgstr ""
+
+msgid "Runners|Can run untagged jobs"
+msgstr ""
+
+msgid "Runners|Description"
+msgstr ""
+
+msgid "Runners|Group"
+msgstr ""
+
+msgid "Runners|IP Address"
+msgstr ""
+
+msgid "Runners|Last contact"
+msgstr ""
+
+msgid "Runners|Locked to this project"
+msgstr ""
+
+msgid "Runners|Maximum job timeout"
+msgstr ""
+
+msgid "Runners|Name"
+msgstr ""
+
+msgid "Runners|Platform"
+msgstr ""
+
+msgid "Runners|Property Name"
+msgstr ""
+
+msgid "Runners|Protected"
+msgstr ""
+
+msgid "Runners|Revision"
+msgstr ""
+
+msgid "Runners|Shared"
+msgstr ""
+
+msgid "Runners|Specific"
+msgstr ""
+
+msgid "Runners|Tags"
+msgstr ""
+
+msgid "Runners|Value"
+msgstr ""
+
+msgid "Runners|Version"
+msgstr ""
+
msgid "Runners|You have used %{quotaUsed} out of %{quotaLimit} of your shared Runners pipeline minutes."
msgstr ""
@@ -21716,6 +22543,9 @@ msgstr ""
msgid "Runs a number of housekeeping tasks within the current repository, such as compressing file revisions and removing unreachable objects."
msgstr ""
+msgid "SAML"
+msgstr ""
+
msgid "SAML SSO"
msgstr ""
@@ -21767,6 +22597,9 @@ msgstr ""
msgid "Save"
msgstr ""
+msgid "Save %{name} size limits"
+msgstr ""
+
msgid "Save Changes"
msgstr ""
@@ -21797,9 +22630,6 @@ msgstr ""
msgid "Save space and find tags in the Container Registry more easily. Enable the cleanup policy to remove stale tags and keep only the ones you need."
msgstr ""
-msgid "Save template"
-msgstr ""
-
msgid "Save variables"
msgstr ""
@@ -21842,9 +22672,6 @@ msgstr ""
msgid "Scope"
msgstr ""
-msgid "Scope not supported with disabled 'users_search' feature!"
-msgstr ""
-
msgid "Scoped issue boards"
msgstr ""
@@ -21971,9 +22798,6 @@ msgstr ""
msgid "Search requirements"
msgstr ""
-msgid "Search results…"
-msgstr ""
-
msgid "Search users"
msgstr ""
@@ -22052,6 +22876,13 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "SearchResults|epic"
+msgid_plural "SearchResults|epics"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "SearchResults|issue"
msgid_plural "SearchResults|issues"
msgstr[0] ""
@@ -22110,10 +22941,10 @@ msgstr ""
msgid "Seat Link is disabled, and cannot be configured through this form."
msgstr ""
-msgid "Seats currently in use"
+msgid "Seats usage data as of %{last_enqueue_time}"
msgstr ""
-msgid "Seats in license"
+msgid "Seats usage data is updated every day at 12:00pm UTC"
msgstr ""
msgid "Secondary"
@@ -22167,6 +22998,9 @@ msgstr ""
msgid "SecurityConfiguration|Available for on-demand DAST"
msgstr ""
+msgid "SecurityConfiguration|By default, all analyzers are applied in order to cover all languages across your project, and only run if the language is detected in the Merge Request."
+msgstr ""
+
msgid "SecurityConfiguration|Configure"
msgstr ""
@@ -22197,16 +23031,19 @@ msgstr ""
msgid "SecurityConfiguration|Manage"
msgstr ""
+msgid "SecurityConfiguration|More information"
+msgstr ""
+
msgid "SecurityConfiguration|Not enabled"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|Security Control"
+msgid "SecurityConfiguration|SAST Configuration"
msgstr ""
-msgid "SecurityConfiguration|See documentation"
+msgid "SecurityConfiguration|Security Control"
msgstr ""
msgid "SecurityConfiguration|Status"
@@ -22218,6 +23055,9 @@ msgstr ""
msgid "SecurityConfiguration|Using custom settings. You won't receive automatic updates on this variable. %{anchorStart}Restore to default%{anchorEnd}"
msgstr ""
+msgid "SecurityConfiguration|View history"
+msgstr ""
+
msgid "SecurityConfiguration|You can quickly enable all security scanning tools by enabling %{linkStart}Auto DevOps%{linkEnd}."
msgstr ""
@@ -22296,9 +23136,6 @@ msgstr ""
msgid "SecurityReports|Learn more about setting up your dashboard"
msgstr ""
-msgid "SecurityReports|Load more vulnerabilities"
-msgstr ""
-
msgid "SecurityReports|Monitor vulnerabilities in your code"
msgstr ""
@@ -22578,7 +23415,7 @@ msgstr ""
msgid "Select status"
msgstr ""
-msgid "Select strategy activation method"
+msgid "Select strategy activation method."
msgstr ""
msgid "Select subscription"
@@ -22593,7 +23430,7 @@ msgstr ""
msgid "Select the custom project template source group."
msgstr ""
-msgid "Select timeframe"
+msgid "Select the environment scope for this feature flag."
msgstr ""
msgid "Select timezone"
@@ -22842,6 +23679,9 @@ msgstr ""
msgid "Set iteration"
msgstr ""
+msgid "Set limit to 0 to allow any file size."
+msgstr ""
+
msgid "Set max session time for web terminal."
msgstr ""
@@ -22920,10 +23760,13 @@ msgstr ""
msgid "Set up a %{type} Runner manually"
msgstr ""
+msgid "Set up a hardware device as a second factor to sign in."
+msgstr ""
+
msgid "Set up assertions/attributes/claims (email, first_name, last_name) and NameID according to %{docsLinkStart}the documentation %{icon}%{docsLinkEnd}"
msgstr ""
-msgid "Set up new U2F device"
+msgid "Set up new device"
msgstr ""
msgid "Set up new password"
@@ -22992,6 +23835,9 @@ msgstr ""
msgid "Sets weight to %{weight}."
msgstr ""
+msgid "Setting this to 0 means using the system default timeout value."
+msgstr ""
+
msgid "Settings"
msgstr ""
@@ -23007,6 +23853,15 @@ msgstr ""
msgid "Severity"
msgstr ""
+msgid "SeverityWidget|Severity"
+msgstr ""
+
+msgid "SeverityWidget|Severity: %{severity}"
+msgstr ""
+
+msgid "SeverityWidget|There was an error while updating severity."
+msgstr ""
+
msgid "Shards (%{shards})"
msgstr ""
@@ -23052,6 +23907,9 @@ msgstr ""
msgid "Show all requirements."
msgstr ""
+msgid "Show all test cases."
+msgstr ""
+
msgid "Show archived projects"
msgstr ""
@@ -23064,6 +23922,9 @@ msgstr ""
msgid "Show comments"
msgstr ""
+msgid "Show comments on this file"
+msgstr ""
+
msgid "Show comments only"
msgstr ""
@@ -23109,6 +23970,12 @@ msgstr ""
msgid "Show parent subgroups"
msgstr ""
+msgid "Show the Closed list"
+msgstr ""
+
+msgid "Show the Open list"
+msgstr ""
+
msgid "Show whitespace changes"
msgstr ""
@@ -23156,9 +24023,6 @@ msgstr ""
msgid "Sidebar|Assign health status"
msgstr ""
-msgid "Sidebar|Change weight"
-msgstr ""
-
msgid "Sidebar|Health status"
msgstr ""
@@ -23342,6 +24206,9 @@ msgstr ""
msgid "Snippets|Add another file %{num}/%{total}"
msgstr ""
+msgid "Snippets|Authored %{time_ago} by %{author}"
+msgstr ""
+
msgid "Snippets|Delete file"
msgstr ""
@@ -23369,6 +24236,9 @@ msgstr ""
msgid "Solution"
msgstr ""
+msgid "Some changes are not shown"
+msgstr ""
+
msgid "Some child epics may be hidden due to applied filters"
msgstr ""
@@ -23735,6 +24605,12 @@ msgstr ""
msgid "Source (branch or tag)"
msgstr ""
+msgid "Source Branch"
+msgstr ""
+
+msgid "Source branch: %{source_branch_open}%{source_branch}%{source_branch_close}"
+msgstr ""
+
msgid "Source code"
msgstr ""
@@ -23900,9 +24776,6 @@ msgstr ""
msgid "Start and due date"
msgstr ""
-msgid "Start by choosing a group to see how your team is spending time. You can then drill down to the project level."
-msgstr ""
-
msgid "Start by choosing a group to start exploring the merge requests in that group. You can then proceed to filter by projects, labels, milestones and authors."
msgstr ""
@@ -23984,18 +24857,27 @@ msgstr ""
msgid "StaticSiteEditor|3. Assign a person to review and accept the merge request."
msgstr ""
+msgid "StaticSiteEditor|A link to view the merge request will appear once ready."
+msgstr ""
+
msgid "StaticSiteEditor|An error occurred while submitting your changes."
msgstr ""
msgid "StaticSiteEditor|Branch could not be created."
msgstr ""
+msgid "StaticSiteEditor|Copy update"
+msgstr ""
+
msgid "StaticSiteEditor|Could not commit the content changes."
msgstr ""
msgid "StaticSiteEditor|Could not create merge request."
msgstr ""
+msgid "StaticSiteEditor|Creating your merge request"
+msgstr ""
+
msgid "StaticSiteEditor|Incompatible file content"
msgstr ""
@@ -24017,6 +24899,9 @@ msgstr ""
msgid "StaticSiteEditor|View documentation"
msgstr ""
+msgid "StaticSiteEditor|You can set an assignee to get your changes reviewed and deployed once your merge request is created."
+msgstr ""
+
msgid "StaticSiteEditor|Your merge request has been created"
msgstr ""
@@ -24146,15 +25031,15 @@ msgstr ""
msgid "Submit %{humanized_resource_name}"
msgstr ""
-msgid "Submit Changes"
-msgstr ""
-
msgid "Submit a review"
msgstr ""
msgid "Submit as spam"
msgstr ""
+msgid "Submit changes"
+msgstr ""
+
msgid "Submit feedback"
msgstr ""
@@ -24308,6 +25193,9 @@ msgstr ""
msgid "Successfully deleted U2F device."
msgstr ""
+msgid "Successfully deleted WebAuthn device."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -24626,9 +25514,6 @@ msgstr ""
msgid "Template to append to all Service Desk issues"
msgstr ""
-msgid "Template was successfully saved."
-msgstr ""
-
msgid "Templates"
msgstr ""
@@ -24713,10 +25598,28 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "Test failed."
+msgid "Test settings"
+msgstr ""
+
+msgid "TestCases|New Test Case"
+msgstr ""
+
+msgid "TestCases|New test case"
+msgstr ""
+
+msgid "TestCases|Search test cases"
+msgstr ""
+
+msgid "TestCases|Something went wrong while creating a test case."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching count of test cases."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching test cases list."
msgstr ""
-msgid "Test settings and save changes"
+msgid "TestCases|Submit test case"
msgstr ""
msgid "TestHooks|Ensure one of your projects has merge requests."
@@ -24782,6 +25685,9 @@ msgstr ""
msgid "Thank you for signing up for your free trial! You will get additional instructions in your inbox shortly."
msgstr ""
+msgid "Thank you for your business."
+msgstr ""
+
msgid "Thank you for your feedback!"
msgstr ""
@@ -24843,9 +25749,6 @@ msgstr ""
msgid "The URL to use for connecting to Elasticsearch. Use a comma-separated list to support clustering (e.g., \"http://localhost:9200, http://localhost:9201\")."
msgstr ""
-msgid "The Web IDE offers advanced syntax highlighting capabilities and more."
-msgstr ""
-
msgid "The X509 Certificate to use when mutual TLS is required to communicate with the external authorization service. If left blank, the server certificate is still validated when accessing over HTTPS."
msgstr ""
@@ -24958,6 +25861,9 @@ msgstr ""
msgid "The form contains the following error:"
msgstr ""
+msgid "The form contains the following warning:"
+msgstr ""
+
msgid "The global settings require you to enable Two-Factor Authentication for your account."
msgstr ""
@@ -25072,9 +25978,6 @@ msgstr ""
msgid "The private key to use when a client certificate is provided. This value is encrypted at rest."
msgstr ""
-msgid "The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The project can be accessed by any logged in user."
msgstr ""
@@ -25111,7 +26014,7 @@ msgstr ""
msgid "The remote repository is being updated..."
msgstr ""
-msgid "The repository can be commited to, and issues, comments and other entities can be created."
+msgid "The repository can be committed to, and issues, comments and other entities can be created."
msgstr ""
msgid "The repository for this project does not exist."
@@ -25165,9 +26068,6 @@ msgstr ""
msgid "The time taken by each data entry gathered by that stage."
msgstr ""
-msgid "The total stage shows the time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The update action will time out after %{number_of_minutes} minutes. For big repositories, use a clone/push combination."
msgstr ""
@@ -25231,6 +26131,9 @@ msgstr ""
msgid "There are no archived requirements"
msgstr ""
+msgid "There are no archived test cases"
+msgstr ""
+
msgid "There are no changes"
msgstr ""
@@ -25270,6 +26173,9 @@ msgstr ""
msgid "There are no open requirements"
msgstr ""
+msgid "There are no open test cases"
+msgstr ""
+
msgid "There are no packages yet"
msgstr ""
@@ -25282,6 +26188,9 @@ msgstr ""
msgid "There is a limit of %{ci_project_subscriptions_limit} subscriptions from or to a project."
msgstr ""
+msgid "There is already a To-Do for this design."
+msgstr ""
+
msgid "There is already a repository with that name on disk"
msgstr ""
@@ -25300,6 +26209,9 @@ msgstr ""
msgid "There was a problem communicating with your device."
msgstr ""
+msgid "There was a problem fetching branches."
+msgstr ""
+
msgid "There was a problem fetching groups."
msgstr ""
@@ -25528,9 +26440,15 @@ msgstr ""
msgid "This action can lead to data loss. To prevent accidental actions we ask you to confirm your intention."
msgstr ""
+msgid "This action cannot be undone, and will permanently delete the %{key} SSH key"
+msgstr ""
+
msgid "This action cannot be undone. You will lose the project's repository and all content: issues, merge requests, etc."
msgstr ""
+msgid "This action has been performed too many times. Try again later."
+msgstr ""
+
msgid "This action will %{strongOpen}permanently delete%{strongClose} %{codeOpen}%{project}%{codeClose} %{strongOpen}immediately%{strongClose}, including its repositories and all content: issues, merge requests, etc."
msgstr ""
@@ -25558,9 +26476,6 @@ msgstr ""
msgid "This board's scope is reduced"
msgstr ""
-msgid "This branch has changed since you started editing. Would you like to create a new branch?"
-msgstr ""
-
msgid "This chart could not be displayed"
msgstr ""
@@ -25687,15 +26602,9 @@ msgstr ""
msgid "This is a security log of important events involving your account."
msgstr ""
-msgid "This is the author's first Merge Request to this project."
-msgstr ""
-
msgid "This is the highest peak of users on your installation since the license started."
msgstr ""
-msgid "This is the maximum number of users that have existed at the same time since the license started. This is the minimum number of seats you will need to buy when you renew your license."
-msgstr ""
-
msgid "This is the number of currently active users on your installation, and this is the minimum number you need to purchase when you renew your license."
msgstr ""
@@ -25927,6 +26836,15 @@ msgstr ""
msgid "This user has no identities"
msgstr ""
+msgid "This user has previously committed to the %{name} project."
+msgstr ""
+
+msgid "This user has the %{access} role in the %{name} project."
+msgstr ""
+
+msgid "This user is the author of this %{noteable}."
+msgstr ""
+
msgid "This user will be the author of all events in the activity feed that are the result of an update, like new branches being created or new commits being pushed to existing branches."
msgstr ""
@@ -25957,6 +26875,9 @@ msgstr ""
msgid "Threat Monitoring"
msgstr ""
+msgid "ThreatMonitoring|All Environments"
+msgstr ""
+
msgid "ThreatMonitoring|Anomalous Requests"
msgstr ""
@@ -25984,9 +26905,6 @@ msgstr ""
msgid "ThreatMonitoring|Operations Per Second"
msgstr ""
-msgid "ThreatMonitoring|Overview"
-msgstr ""
-
msgid "ThreatMonitoring|Packet Activity"
msgstr ""
@@ -26005,6 +26923,9 @@ msgstr ""
msgid "ThreatMonitoring|Something went wrong, unable to fetch statistics"
msgstr ""
+msgid "ThreatMonitoring|Statistics"
+msgstr ""
+
msgid "ThreatMonitoring|The firewall is not installed or has been disabled. To view this data, ensure the web application firewall is installed and enabled for your cluster."
msgstr ""
@@ -26400,6 +27321,9 @@ msgstr ""
msgid "To update Snippets with multiple files, you must use the `files` parameter"
msgstr ""
+msgid "To use Gitpod you must first enable the feature in the integrations section of your %{user_prefs}."
+msgstr ""
+
msgid "To view all %{scannedResourcesCount} scanned URLs, please download the CSV file"
msgstr ""
@@ -26433,9 +27357,6 @@ msgstr ""
msgid "Toggle Sidebar"
msgstr ""
-msgid "Toggle all threads"
-msgstr ""
-
msgid "Toggle backtrace"
msgstr ""
@@ -26460,9 +27381,6 @@ msgstr ""
msgid "Toggle navigation"
msgstr ""
-msgid "Toggle project"
-msgstr ""
-
msgid "Toggle sidebar"
msgstr ""
@@ -26502,6 +27420,9 @@ msgstr ""
msgid "Too many projects enabled. You will need to manage them via the console or the API."
msgstr ""
+msgid "Too much data"
+msgstr ""
+
msgid "Topics (optional)"
msgstr ""
@@ -26520,6 +27441,9 @@ msgstr ""
msgid "Total cores (CPUs)"
msgstr ""
+msgid "Total days to completion"
+msgstr ""
+
msgid "Total issues"
msgstr ""
@@ -26616,6 +27540,9 @@ msgstr ""
msgid "Trending"
msgstr ""
+msgid "Trials|Create a new group to start your GitLab Gold trial."
+msgstr ""
+
msgid "Trials|Go back to GitLab"
msgstr ""
@@ -26625,6 +27552,15 @@ msgstr ""
msgid "Trials|You can always resume this process by selecting your avatar and choosing 'Start a Gold trial'"
msgstr ""
+msgid "Trials|You can apply your trial to a new group or an existing group."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group or your personal account."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group, an existing group, or your personal account."
+msgstr ""
+
msgid "Trials|You won't get a free trial right now but you can always resume this process by clicking on your avatar and choosing 'Start a free trial'"
msgstr ""
@@ -26694,6 +27630,9 @@ msgstr ""
msgid "Try using a different search term to find the file you are looking for."
msgstr ""
+msgid "Trying to communicate with your device. Plug it in (if needed) and press the button on the device now."
+msgstr ""
+
msgid "Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now."
msgstr ""
@@ -26781,6 +27720,12 @@ msgstr ""
msgid "URL or request ID"
msgstr ""
+msgid "USER %{user} WILL BE REMOVED! Are you sure?"
+msgstr ""
+
+msgid "USER WILL BE BLOCKED! Are you sure?"
+msgstr ""
+
msgid "UTC"
msgstr ""
@@ -26838,9 +27783,6 @@ msgstr ""
msgid "Unable to load the merge request widget. Try reloading the page."
msgstr ""
-msgid "Unable to resolve"
-msgstr ""
-
msgid "Unable to save iteration. Please try again"
msgstr ""
@@ -26889,6 +27831,9 @@ msgstr ""
msgid "Undo ignore"
msgstr ""
+msgid "Unexpected error"
+msgstr ""
+
msgid "Unfortunately, your email message to GitLab could not be processed."
msgstr ""
@@ -26922,6 +27867,9 @@ msgstr ""
msgid "Unknown response text"
msgstr ""
+msgid "Unless otherwise agreed to in writing with GitLab, by clicking \"Upload License\" you agree that your use of GitLab Software is subject to the %{eula_link_start}Terms of Service%{eula_link_end}."
+msgstr ""
+
msgid "Unlimited"
msgstr ""
@@ -27288,9 +28236,6 @@ msgstr ""
msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
msgstr ""
-msgid "Use a hardware device to add the second factor of authentication."
-msgstr ""
-
msgid "Use an one time password authenticator on your mobile device or computer to enable two-factor authentication (2FA)."
msgstr ""
@@ -27564,13 +28509,13 @@ msgstr ""
msgid "Users"
msgstr ""
-msgid "Users in License:"
+msgid "Users in License"
msgstr ""
-msgid "Users or groups set as approvers in the project's or merge request's settings."
+msgid "Users in License:"
msgstr ""
-msgid "Users outside of license"
+msgid "Users or groups set as approvers in the project's or merge request's settings."
msgstr ""
msgid "Users over License:"
@@ -27588,9 +28533,6 @@ msgstr ""
msgid "Users with a Guest role or those who don't belong to a Project or Group will not use a seat from your license."
msgstr ""
-msgid "Users with a Guest role or those who don't belong to any projects or groups don't count towards seats in use."
-msgstr ""
-
msgid "UsersSelect|%{name} + %{length} more"
msgstr ""
@@ -27630,9 +28572,6 @@ msgstr ""
msgid "Validations failed."
msgstr ""
-msgid "Validity"
-msgstr ""
-
msgid "Value"
msgstr ""
@@ -27651,6 +28590,9 @@ msgstr ""
msgid "Value Stream Name"
msgstr ""
+msgid "ValueStreamAnalyticsStage|We don't have enough data to show this stage."
+msgstr ""
+
msgid "ValueStreamAnalytics|%{days}d"
msgstr ""
@@ -27911,6 +28853,9 @@ msgstr ""
msgid "VisualReviewApp|Steps 1 and 2 (and sometimes 3) are performed once by the developer before requesting feedback. Steps 3 (if necessary), 4 is performed by the reviewer each time they perform a review."
msgstr ""
+msgid "Visualization"
+msgstr ""
+
msgid "Vulnerabilities"
msgstr ""
@@ -27938,34 +28883,31 @@ msgstr ""
msgid "VulnerabilityChart|Severity"
msgstr ""
-msgid "VulnerabilityManagement|A true-positive and will fix"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Change status"
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|Confirm"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Confirmed %{timeago} by %{user}"
-msgstr ""
-
-msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Detected %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|A true-positive and will fix"
msgstr ""
-msgid "VulnerabilityManagement|Dismiss"
+msgid "VulnerabilityManagement|Change status"
msgstr ""
-msgid "VulnerabilityManagement|Dismissed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
msgstr ""
-msgid "VulnerabilityManagement|Resolved"
+msgid "VulnerabilityManagement|Detected"
msgstr ""
-msgid "VulnerabilityManagement|Resolved %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Needs triage"
msgstr ""
msgid "VulnerabilityManagement|Something went wrong while trying to delete the comment. Please try again later."
@@ -28016,6 +28958,9 @@ msgstr ""
msgid "Vulnerability|%{scannerName} (version %{scannerVersion})"
msgstr ""
+msgid "Vulnerability|Activity"
+msgstr ""
+
msgid "Vulnerability|Class"
msgstr ""
@@ -28028,6 +28973,9 @@ msgstr ""
msgid "Vulnerability|Description"
msgstr ""
+msgid "Vulnerability|Detected"
+msgstr ""
+
msgid "Vulnerability|Evidence"
msgstr ""
@@ -28091,6 +29039,9 @@ msgstr ""
msgid "Warning: Displaying this diagram might cause performance issues on this page."
msgstr ""
+msgid "We are currently unable to fetch data for the pipeline header."
+msgstr ""
+
msgid "We are currently unable to fetch data for this graph."
msgstr ""
@@ -28130,6 +29081,12 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
+msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
+msgstr ""
+
+msgid "We would like to inform you that your subscription GitLab Enterprise Edition %{plan_name} is nearing its user limit. You have %{active_user_count} active users, which is almost at the user limit of %{maximum_user_count}."
+msgstr ""
+
msgid "We've found no vulnerabilities"
msgstr ""
@@ -28145,6 +29102,12 @@ msgstr ""
msgid "Web terminal"
msgstr ""
+msgid "WebAuthn Devices (%{length})"
+msgstr ""
+
+msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
+msgstr ""
+
msgid "WebIDE|Merge request"
msgstr ""
@@ -28283,15 +29246,9 @@ msgstr ""
msgid "Welcome to the guided GitLab tour"
msgstr ""
-msgid "Welcome to your Issue Board!"
-msgstr ""
-
msgid "Welcome to your issue board!"
msgstr ""
-msgid "We’ve been making changes to %{featureName} and we’d love your feedback %{linkStart}in this issue%{linkEnd} to help us improve the experience."
-msgstr ""
-
msgid "What are you searching for?"
msgstr ""
@@ -28310,6 +29267,9 @@ msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
msgstr ""
+msgid "When enabled, any user visiting %{host} and creating an account will have to be explicitly approved by the admin before they can login. This setting is effective only if sign-ups are enabled."
+msgstr ""
+
msgid "When enabled, any user visiting %{host} will be able to create an account."
msgstr ""
@@ -28536,6 +29496,9 @@ msgstr ""
msgid "With requirements, you can set criteria to check your products against."
msgstr ""
+msgid "With test cases, you can define conditions for your project to meet in determining quality"
+msgstr ""
+
msgid "Withdraw Access Request"
msgstr ""
@@ -28551,6 +29514,9 @@ msgstr ""
msgid "Workflow Help"
msgstr ""
+msgid "Would you like to create a new branch?"
+msgstr ""
+
msgid "Write"
msgstr ""
@@ -28572,6 +29538,9 @@ msgstr ""
msgid "Wrong extern UID provided. Make sure Auth0 is configured correctly."
msgstr ""
+msgid "YYYY-MM-DD"
+msgstr ""
+
msgid "Yes"
msgstr ""
@@ -28629,7 +29598,7 @@ msgstr ""
msgid "You are going to remove the fork relationship from %{project_full_name}. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "You are going to transfer %{project_full_name} to another owner. Are you ABSOLUTELY sure?"
+msgid "You are going to transfer %{project_full_name} to another namespace. Are you ABSOLUTELY sure?"
msgstr ""
msgid "You are going to turn off the confidentiality. This means %{strongStart}everyone%{strongEnd} will be able to see and leave a comment on this %{issuableType}."
@@ -28689,9 +29658,6 @@ msgstr ""
msgid "You can always edit this later"
msgstr ""
-msgid "You can apply your Trial to your Personal account or create a New Group."
-msgstr ""
-
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings"
msgstr ""
@@ -28713,12 +29679,18 @@ msgstr ""
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
+msgid "You can find more information about GitLab subscriptions in %{subscriptions_doc_link}."
+msgstr ""
+
msgid "You can generate an access token scoped to this project for each application to use the GitLab API."
msgstr ""
msgid "You can get started by cloning the repository or start adding files to it with one of the following options."
msgstr ""
+msgid "You can group test cases using labels. To learn about the future direction of this feature, visit %{linkStart}Quality Management direction page%{linkEnd}."
+msgstr ""
+
msgid "You can invite a new member to %{project_name} or invite another group."
msgstr ""
@@ -28734,6 +29706,9 @@ msgstr ""
msgid "You can notify the app / group or a project by sending them an email notification"
msgstr ""
+msgid "You can now close this window."
+msgstr ""
+
msgid "You can now export your security dashboard to a CSV report."
msgstr ""
@@ -28782,9 +29757,6 @@ msgstr ""
msgid "You can test your .gitlab-ci.yml in %{linkStart}CI Lint%{linkEnd}."
msgstr ""
-msgid "You can try again using %{begin_link}basic search%{end_link}"
-msgstr ""
-
msgid "You cannot access the raw file. Please wait a minute."
msgstr ""
@@ -28836,6 +29808,9 @@ msgstr ""
msgid "You don't have any U2F devices registered yet."
msgstr ""
+msgid "You don't have any WebAuthn devices registered yet."
+msgstr ""
+
msgid "You don't have any active chat names."
msgstr ""
@@ -28923,6 +29898,9 @@ msgstr ""
msgid "You must accept our Terms of Service and privacy policy in order to register an account"
msgstr ""
+msgid "You must be logged in to search across all of GitLab"
+msgstr ""
+
msgid "You must disassociate %{domain} from all clusters it is attached to before deletion."
msgstr ""
@@ -28962,7 +29940,7 @@ msgstr ""
msgid "You need to be logged in."
msgstr ""
-msgid "You need to register a two-factor authentication app before you can set up a U2F device."
+msgid "You need to register a two-factor authentication app before you can set up a device."
msgstr ""
msgid "You need to set terms to be enforced"
@@ -28980,6 +29958,9 @@ msgstr ""
msgid "You reached %{usage_in_percent} of %{namespace_name}'s storage capacity (%{used_storage} of %{storage_limit})"
msgstr ""
+msgid "You successfully declined the invitation"
+msgstr ""
+
msgid "You tried to fork %{link_to_the_project} but it failed for the following reason:"
msgstr ""
@@ -29145,10 +30126,13 @@ msgstr ""
msgid "Your U2F device did not send a valid JSON response."
msgstr ""
-msgid "Your U2F device needs to be set up. Plug it in (if not already) and click the button on the left."
+msgid "Your U2F device was registered!"
msgstr ""
-msgid "Your U2F device was registered!"
+msgid "Your WebAuthn device did not send a valid JSON response."
+msgstr ""
+
+msgid "Your WebAuthn device was registered!"
msgstr ""
msgid "Your access request to the %{source_type} has been withdrawn."
@@ -29172,6 +30156,9 @@ msgstr ""
msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
msgstr ""
+msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
+msgstr ""
+
msgid "Your changes can be committed to %{branch_name} because a merge request is open."
msgstr ""
@@ -29208,6 +30195,12 @@ msgstr ""
msgid "Your deployment services will be broken, you will need to manually fix the services after renaming."
msgstr ""
+msgid "Your device is not compatible with GitLab. Please try another device"
+msgstr ""
+
+msgid "Your device needs to be set up. Plug it in (if needed) and click the button on the left."
+msgstr ""
+
msgid "Your device was successfully set up! Give it a name and register it with the GitLab server."
msgstr ""
@@ -29323,9 +30316,6 @@ msgstr[3] ""
msgid "access:"
msgstr ""
-msgid "activated"
-msgstr ""
-
msgid "added %{created_at_timeago}"
msgstr ""
@@ -29398,9 +30388,21 @@ msgstr ""
msgid "by %{user}"
msgstr ""
+msgid "cannot be a date in the past"
+msgstr ""
+
msgid "cannot be changed if a personal project has container registry tags."
msgstr ""
+msgid "cannot be changed if shared runners are enabled"
+msgstr ""
+
+msgid "cannot be enabled because parent group does not allow it"
+msgstr ""
+
+msgid "cannot be enabled because parent group has shared Runners disabled"
+msgstr ""
+
msgid "cannot be enabled unless all domains have TLS certificates"
msgstr ""
@@ -29446,7 +30448,7 @@ msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about SAST %{linkEndTag}"
msgstr ""
-msgid "ciReport|%{linkStartTag}Learn more about Secret Scanning %{linkEndTag}"
+msgid "ciReport|%{linkStartTag}Learn more about Secret Detection %{linkEndTag}"
msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about codequality reports %{linkEndTag}"
@@ -29767,9 +30769,6 @@ msgstr ""
msgid "error"
msgstr ""
-msgid "error code:"
-msgstr ""
-
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr ""
@@ -29791,6 +30790,9 @@ msgstr ""
msgid "failed to dismiss associated finding(id=%{finding_id}): %{message}"
msgstr ""
+msgid "failed to revert associated finding(id=%{finding_id}) to detected"
+msgstr ""
+
msgid "file"
msgid_plural "files"
msgstr[0] ""
@@ -30341,6 +31343,9 @@ msgstr ""
msgid "must be a root namespace"
msgstr ""
+msgid "must be a valid IPv4 or IPv6 address"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -30377,6 +31382,9 @@ msgstr ""
msgid "no expiration"
msgstr ""
+msgid "no name set"
+msgstr ""
+
msgid "no one can merge"
msgstr ""
@@ -30565,9 +31573,6 @@ msgstr ""
msgid "security Reports|There was an error creating the merge request"
msgstr ""
-msgid "settings saved, but not activated"
-msgstr ""
-
msgid "severity|Critical"
msgstr ""
@@ -30694,9 +31699,6 @@ msgstr ""
msgid "toggle collapse"
msgstr ""
-msgid "toggle dropdown"
-msgstr ""
-
msgid "triggered"
msgstr ""
@@ -30724,6 +31726,9 @@ msgstr ""
msgid "user avatar"
msgstr ""
+msgid "user preferences"
+msgstr ""
+
msgid "username"
msgstr ""
diff --git a/locale/sl_SI/gitlab.po b/locale/sl_SI/gitlab.po
index 513148503b9..769f12b690b 100644
--- a/locale/sl_SI/gitlab.po
+++ b/locale/sl_SI/gitlab.po
@@ -14,7 +14,10 @@ msgstr ""
"X-Crowdin-Language: sl\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 6\n"
-"PO-Revision-Date: 2020-09-04 23:10\n"
+"PO-Revision-Date: 2020-10-02 18:50\n"
+
+msgid " %{project_name}#%{issue_iid} &middot; opened %{issue_created} by %{author}"
+msgstr ""
msgid " %{start} to %{end}"
msgstr ""
@@ -78,6 +81,20 @@ msgstr ""
msgid "\"el\" parameter is required for createInstance()"
msgstr ""
+msgid "%d Approval"
+msgid_plural "%d Approvals"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
+msgid "%d Package"
+msgid_plural "%d Packages"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%d Scanned URL"
msgid_plural "%d Scanned URLs"
msgstr[0] ""
@@ -165,6 +182,13 @@ msgstr[3] ""
msgid "%d commits"
msgstr ""
+msgid "%d completed issue"
+msgid_plural "%d completed issues"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%d contribution"
msgid_plural "%d contributions"
msgstr[0] ""
@@ -179,6 +203,13 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "%d day until tags are automatically removed"
+msgid_plural "%d days until tags are automatically removed"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%d error"
msgid_plural "%d errors"
msgstr[0] ""
@@ -305,6 +336,20 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "%d open issue"
+msgid_plural "%d open issues"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
+msgid "%d pending comment"
+msgid_plural "%d pending comments"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%d personal project will be removed and cannot be restored."
msgid_plural "%d personal projects will be removed and cannot be restored."
msgstr[0] ""
@@ -326,6 +371,13 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "%d project selected"
+msgid_plural "%d projects selected"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%d request with warnings"
msgid_plural "%d requests with warnings"
msgstr[0] ""
@@ -354,6 +406,13 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "%d tag per image name"
+msgid_plural "%d tags per image name"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%d unassigned issue"
msgid_plural "%d unassigned issues"
msgstr[0] ""
@@ -382,6 +441,13 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "%d warning found:"
+msgid_plural "%d warnings found:"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%s additional commit has been omitted to prevent performance issues."
msgid_plural "%s additional commits have been omitted to prevent performance issues."
msgstr[0] ""
@@ -422,6 +488,9 @@ msgstr ""
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr ""
+msgid "%{completedCount} completed weight"
+msgstr ""
+
msgid "%{completedWeight} of %{totalWeight} weight completed"
msgstr ""
@@ -476,16 +545,12 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "%{count} pending comment"
-msgid_plural "%{count} pending comments"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
+msgid "%{count} total weight"
+msgstr ""
+
msgid "%{dashboard_path} could not be found."
msgstr ""
@@ -540,6 +605,9 @@ msgstr ""
msgid "%{group_name} uses group managed accounts. You need to create a new GitLab account which will be managed by %{group_name}."
msgstr ""
+msgid "%{group_name}&%{epic_iid} &middot; opened %{epic_created} by %{author}"
+msgstr ""
+
msgid "%{host} sign-in from new location"
msgstr ""
@@ -552,7 +620,7 @@ msgstr ""
msgid "%{issuableType} will be removed! Are you sure?"
msgstr ""
-msgid "%{issuesSize} issues with a limit of %{maxIssueCount}"
+msgid "%{issuesCount} issues with a limit of %{maxIssueCount}"
msgstr ""
msgid "%{issuesSize} with a limit of %{maxIssueCount}"
@@ -585,7 +653,7 @@ msgstr ""
msgid "%{labelStart}Namespace:%{labelEnd} %{namespace}"
msgstr ""
-msgid "%{labelStart}Report Type:%{labelEnd} %{reportType}"
+msgid "%{labelStart}Scan Type:%{labelEnd} %{reportType}"
msgstr ""
msgid "%{labelStart}Scanner:%{labelEnd} %{scanner}"
@@ -796,9 +864,6 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "%{service_title} %{message}."
-msgstr ""
-
msgid "%{size} GiB"
msgstr ""
@@ -897,6 +962,12 @@ msgstr ""
msgid "%{timebox_name} should belong either to a project or a group."
msgstr ""
+msgid "%{timebox_type} does not support burnup charts"
+msgstr ""
+
+msgid "%{timebox_type} must have a start and due date"
+msgstr ""
+
msgid "%{title} %{operator} %{threshold}"
msgstr ""
@@ -921,7 +992,7 @@ msgstr ""
msgid "%{total} open issue weight"
msgstr ""
-msgid "%{total} open issues"
+msgid "%{total} warnings found: showing first %{warningsDisplayed}"
msgstr ""
msgid "%{usage_ping_link_start}Learn more%{usage_ping_link_end} about what information is shared with GitLab Inc."
@@ -954,9 +1025,6 @@ msgstr ""
msgid "&lt; 1 hour"
msgstr ""
-msgid "&lt;no name set&gt;"
-msgstr ""
-
msgid "&lt;no scopes selected&gt;"
msgstr ""
@@ -987,6 +1055,9 @@ msgstr ""
msgid "'%{name}' Value Stream created"
msgstr ""
+msgid "'%{name}' Value Stream deleted"
+msgstr ""
+
msgid "'%{name}' stage already exists"
msgstr ""
@@ -1048,6 +1119,9 @@ msgstr ""
msgid "+ %{numberOfHiddenAssignees} more"
msgstr ""
+msgid "+ %{numberOfHiddenReviewers} more"
+msgstr ""
+
msgid "+%d more"
msgid_plural "+%d more"
msgstr[0] ""
@@ -1120,6 +1194,13 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "1 Issue"
+msgid_plural "%d Issues"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "1 closed issue"
msgid_plural "%{issues} closed issues"
msgstr[0] ""
@@ -1141,6 +1222,13 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "1 deploy key"
+msgid_plural "%d deploy keys"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1261,6 +1349,9 @@ msgstr ""
msgid ":%{startLine} to %{endLine}"
msgstr ""
+msgid "A %{incident_docs_start}modified issue%{incident_docs_end} to guide the resolution of incidents."
+msgstr ""
+
msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr ""
@@ -1273,6 +1364,9 @@ msgstr ""
msgid "A GitBook site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
+msgid "A Gitpod configured Webapplication in Spring and Java"
+msgstr ""
+
msgid "A Hexo site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
@@ -1444,9 +1538,15 @@ msgstr ""
msgid "Access expiration date"
msgstr ""
+msgid "Access expires"
+msgstr ""
+
msgid "Access forbidden. Check your access level."
msgstr ""
+msgid "Access granted"
+msgstr ""
+
msgid "Access requests"
msgstr ""
@@ -1456,6 +1556,9 @@ msgstr ""
msgid "Access to Pages websites are controlled based on the user's membership to a given project. By checking this box, users will be required to be logged in to have access to all Pages websites in your instance."
msgstr ""
+msgid "AccessDropdown|Deploy Keys"
+msgstr ""
+
msgid "AccessDropdown|Groups"
msgstr ""
@@ -1573,12 +1676,6 @@ msgstr ""
msgid "Active Sessions"
msgstr ""
-msgid "Active Users:"
-msgstr ""
-
-msgid "Active users"
-msgstr ""
-
msgid "Activity"
msgstr ""
@@ -1748,9 +1845,6 @@ msgstr ""
msgid "Add label(s)"
msgstr ""
-msgid "Add license"
-msgstr ""
-
msgid "Add list"
msgstr ""
@@ -1925,21 +2019,51 @@ msgstr ""
msgid "AdminArea|Bots"
msgstr ""
+msgid "AdminArea|Components"
+msgstr ""
+
msgid "AdminArea|Developer"
msgstr ""
+msgid "AdminArea|Features"
+msgstr ""
+
+msgid "AdminArea|Groups: %{number_of_groups}"
+msgstr ""
+
msgid "AdminArea|Guest"
msgstr ""
msgid "AdminArea|Included Free in license"
msgstr ""
+msgid "AdminArea|Latest groups"
+msgstr ""
+
+msgid "AdminArea|Latest projects"
+msgstr ""
+
+msgid "AdminArea|Latest users"
+msgstr ""
+
msgid "AdminArea|Maintainer"
msgstr ""
+msgid "AdminArea|New group"
+msgstr ""
+
+msgid "AdminArea|New project"
+msgstr ""
+
+msgid "AdminArea|New user"
+msgstr ""
+
msgid "AdminArea|Owner"
msgstr ""
+msgid "AdminArea|Projects: %{number_of_projects}"
+msgstr ""
+
msgid "AdminArea|Reporter"
msgstr ""
@@ -1967,6 +2091,9 @@ msgstr ""
msgid "AdminArea|Users without a Group and Project"
msgstr ""
+msgid "AdminArea|Users: %{number_of_users}"
+msgstr ""
+
msgid "AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running."
msgstr ""
@@ -1985,9 +2112,6 @@ msgstr ""
msgid "AdminProjects|Delete Project %{projectName}?"
msgstr ""
-msgid "AdminProjects|Delete project"
-msgstr ""
-
msgid "AdminSettings|Apply integration settings to all Projects"
msgstr ""
@@ -2225,21 +2349,30 @@ msgstr ""
msgid "AdminUsers|Without projects"
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 ""
msgid "AdminUsers|You cannot remove your own admin rights."
msgstr ""
+msgid "AdminUsers|You must transfer ownership or delete the groups owned by this user before you can delete their account"
+msgstr ""
+
msgid "Administration"
msgstr ""
msgid "Advanced"
msgstr ""
+msgid "Advanced Search"
+msgstr ""
+
+msgid "Advanced Search with Elasticsearch"
+msgstr ""
+
msgid "Advanced Settings"
msgstr ""
@@ -2319,6 +2452,9 @@ msgstr ""
msgid "AlertManagement|Edit"
msgstr ""
+msgid "AlertManagement|Environment"
+msgstr ""
+
msgid "AlertManagement|Events"
msgstr ""
@@ -2331,6 +2467,9 @@ msgstr ""
msgid "AlertManagement|Issue"
msgstr ""
+msgid "AlertManagement|Key"
+msgstr ""
+
msgid "AlertManagement|Low"
msgstr ""
@@ -2424,6 +2563,9 @@ msgstr ""
msgid "AlertManagement|Unknown"
msgstr ""
+msgid "AlertManagement|Value"
+msgstr ""
+
msgid "AlertManagement|View alerts in Opsgenie"
msgstr ""
@@ -2583,6 +2725,9 @@ msgstr ""
msgid "All projects"
msgstr ""
+msgid "All projects selected"
+msgstr ""
+
msgid "All security scans are enabled because %{linkStart}Auto DevOps%{linkEnd} is enabled on this project"
msgstr ""
@@ -2670,6 +2815,9 @@ msgstr ""
msgid "Almost there"
msgstr ""
+msgid "Already blocked"
+msgstr ""
+
msgid "Also called \"Issuer\" or \"Relying party trust identifier\""
msgstr ""
@@ -2724,6 +2872,9 @@ msgstr ""
msgid "An error has occurred"
msgstr ""
+msgid "An error occured while making the changes: %{error}"
+msgstr ""
+
msgid "An error occurred adding a draft to the thread."
msgstr ""
@@ -2751,12 +2902,6 @@ msgstr ""
msgid "An error occurred when toggling the notification subscription"
msgstr ""
-msgid "An error occurred when trying to resolve a comment. Please try again."
-msgstr ""
-
-msgid "An error occurred when trying to resolve a discussion. Please try again."
-msgstr ""
-
msgid "An error occurred when updating the issue weight"
msgstr ""
@@ -2772,12 +2917,6 @@ msgstr ""
msgid "An error occurred while checking group path. Please refresh and try again."
msgstr ""
-msgid "An error occurred while committing your changes."
-msgstr ""
-
-msgid "An error occurred while creating the list. Please try again."
-msgstr ""
-
msgid "An error occurred while decoding the file."
msgstr ""
@@ -2850,25 +2989,19 @@ msgstr ""
msgid "An error occurred while fetching the Service Desk address."
msgstr ""
-msgid "An error occurred while fetching the board issues. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the board lists. Please reload the page."
msgstr ""
msgid "An error occurred while fetching the board lists. Please try again."
msgstr ""
-msgid "An error occurred while fetching the board swimlanes. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the builds."
msgstr ""
msgid "An error occurred while fetching the job log."
msgstr ""
-msgid "An error occurred while fetching the job trace."
+msgid "An error occurred while fetching the job logs."
msgstr ""
msgid "An error occurred while fetching the job."
@@ -3015,9 +3148,6 @@ msgstr ""
msgid "An error occurred while saving assignees"
msgstr ""
-msgid "An error occurred while saving the template. Please check if the template exists."
-msgstr ""
-
msgid "An error occurred while searching for milestones"
msgstr ""
@@ -3036,10 +3166,10 @@ msgstr ""
msgid "An error occurred while updating approvers"
msgstr ""
-msgid "An error occurred while updating the comment"
+msgid "An error occurred while updating labels."
msgstr ""
-msgid "An error occurred while updating the list. Please try again."
+msgid "An error occurred while updating the comment"
msgstr ""
msgid "An error occurred while validating group path"
@@ -3093,6 +3223,9 @@ msgstr ""
msgid "An unknown error occurred while loading this graph."
msgstr ""
+msgid "An unknown error occurred."
+msgstr ""
+
msgid "Analytics"
msgstr ""
@@ -3126,10 +3259,10 @@ msgstr ""
msgid "Any"
msgstr ""
-msgid "Any Author"
+msgid "Any %{header}"
msgstr ""
-msgid "Any Status"
+msgid "Any Author"
msgstr ""
msgid "Any branch"
@@ -3183,6 +3316,9 @@ msgstr ""
msgid "Application ID"
msgstr ""
+msgid "Application limits saved successfully"
+msgstr ""
+
msgid "Application settings saved successfully"
msgstr ""
@@ -3400,6 +3536,9 @@ msgstr ""
msgid "Are you sure you want to close this blocked issue?"
msgstr ""
+msgid "Are you sure you want to delete \"%{name}\" Value Stream?"
+msgstr ""
+
msgid "Are you sure you want to delete %{name}?"
msgstr ""
@@ -3409,6 +3548,9 @@ msgstr ""
msgid "Are you sure you want to delete this %{typeOfComment}?"
msgstr ""
+msgid "Are you sure you want to delete this SSH key?"
+msgstr ""
+
msgid "Are you sure you want to delete this board?"
msgstr ""
@@ -3433,6 +3575,13 @@ msgstr ""
msgid "Are you sure you want to erase this build?"
msgstr ""
+msgid "Are you sure you want to import %d repository?"
+msgid_plural "Are you sure you want to import %d repositories?"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "Are you sure you want to lose unsaved changes?"
msgstr ""
@@ -3442,15 +3591,15 @@ msgstr ""
msgid "Are you sure you want to merge immediately?"
msgstr ""
-msgid "Are you sure you want to permanently delete this license?"
-msgstr ""
-
msgid "Are you sure you want to re-deploy this environment?"
msgstr ""
msgid "Are you sure you want to regenerate the public key? You will have to update the public key on the remote server before mirroring will work again."
msgstr ""
+msgid "Are you sure you want to reindex?"
+msgstr ""
+
msgid "Are you sure you want to remove %{group_name}?"
msgstr ""
@@ -3478,6 +3627,9 @@ msgstr ""
msgid "Are you sure you want to revoke this nickname?"
msgstr ""
+msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
+msgstr ""
+
msgid "Are you sure you want to stop this environment?"
msgstr ""
@@ -3499,6 +3651,9 @@ msgstr ""
msgid "Are you sure? The device will be signed out of GitLab and all remember me tokens revoked."
msgstr ""
+msgid "Are you sure? This will invalidate your registered applications and U2F / WebAuthn devices."
+msgstr ""
+
msgid "Are you sure? This will invalidate your registered applications and U2F devices."
msgstr ""
@@ -3517,9 +3672,6 @@ msgstr ""
msgid "Artifacts"
msgstr ""
-msgid "As U2F devices are only supported by a few browsers, we require that you set up a two-factor authentication app before a U2F device. That way you'll always be able to log in - even when you're using an unsupported browser."
-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 ""
@@ -3717,6 +3869,9 @@ msgstr ""
msgid "AuditLogs|Target"
msgstr ""
+msgid "AuditLogs|This month"
+msgstr ""
+
msgid "AuditLogs|User Events"
msgstr ""
@@ -3756,6 +3911,9 @@ msgstr ""
msgid "Authentication via U2F device failed."
msgstr ""
+msgid "Authentication via WebAuthn device failed."
+msgstr ""
+
msgid "Author"
msgstr ""
@@ -4023,15 +4181,6 @@ msgstr ""
msgid "BambooService|You must set up automatic revision labeling and a repository trigger in Bamboo."
msgstr ""
-msgid "BatchComments|Delete all pending comments"
-msgstr ""
-
-msgid "BatchComments|Discard review?"
-msgstr ""
-
-msgid "BatchComments|You're about to discard your review which will delete all of your pending comments. The deleted comments %{strong_start}cannot%{strong_end} be restored."
-msgstr ""
-
msgid "Be careful. Changing the project's namespace can have unintended side effects."
msgstr ""
@@ -4053,6 +4202,9 @@ msgstr ""
msgid "Bi-weekly code coverage"
msgstr ""
+msgid "Billable Users:"
+msgstr ""
+
msgid "Billing"
msgstr ""
@@ -4062,7 +4214,7 @@ msgstr ""
msgid "BillingPlans|@%{user_name} you are currently using the %{plan_name} plan."
msgstr ""
-msgid "BillingPlans|Congratulations, your new trial is activated"
+msgid "BillingPlans|Congratulations, your free trial is activated."
msgstr ""
msgid "BillingPlans|If you would like to downgrade your plan please contact %{support_link_start}Customer Support%{support_link_end}."
@@ -4125,6 +4277,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Block user"
+msgstr ""
+
msgid "Blocked"
msgstr ""
@@ -4140,31 +4295,37 @@ msgstr ""
msgid "Blog"
msgstr ""
-msgid "Board name"
-msgstr ""
-
msgid "Board scope"
msgstr ""
msgid "Board scope affects which issues are displayed for anyone who visits this board"
msgstr ""
-msgid "BoardBlankState|Add default lists"
+msgid "Boards"
msgstr ""
-msgid "BoardBlankState|Add the following default lists to your Issue Board with one click:"
+msgid "Boards and Board Lists"
msgstr ""
-msgid "BoardBlankState|Nevermind, I'll use my own"
+msgid "Boards|An error occurred while creating the issue. Please try again."
msgstr ""
-msgid "BoardBlankState|Starting out with the default set of lists will get you right on the way to making the most of your board."
+msgid "Boards|An error occurred while creating the list. Please try again."
msgstr ""
-msgid "Boards"
+msgid "Boards|An error occurred while fetching issues. Please reload the page."
msgstr ""
-msgid "Boards and Board Lists"
+msgid "Boards|An error occurred while fetching the board issues. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching the board swimlanes. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while moving the issue. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while updating the list. Please try again."
msgstr ""
msgid "Boards|Collapse"
@@ -4191,7 +4352,7 @@ msgstr ""
msgid "Branch %{branch_name} was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr ""
-msgid "Branch has changed"
+msgid "Branch changed"
msgstr ""
msgid "Branch is already taken"
@@ -4497,6 +4658,9 @@ msgstr ""
msgid "CLOSED (MOVED)"
msgstr ""
+msgid "CODEOWNERS rule violation"
+msgstr ""
+
msgid "CONTRIBUTING"
msgstr ""
@@ -4527,9 +4691,6 @@ msgstr ""
msgid "Can't create snippet: %{err}"
msgstr ""
-msgid "Can't edit as source branch was deleted"
-msgstr ""
-
msgid "Can't fetch content for the blob: %{err}"
msgstr ""
@@ -4542,9 +4703,6 @@ msgstr ""
msgid "Can't load mermaid module: %{err}"
msgstr ""
-msgid "Can't remove group members without group managed account"
-msgstr ""
-
msgid "Can't scan the code?"
msgstr ""
@@ -4587,6 +4745,9 @@ msgstr ""
msgid "Cannot create the abuse report. This user has been blocked."
msgstr ""
+msgid "Cannot enable shared runners because parent group does not allow it"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -4692,6 +4853,15 @@ msgstr ""
msgid "Change your password or recover your current one"
msgstr ""
+msgid "ChangeReviewer|Reviewer changed from %{old} to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Reviewer changed to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Unassigned"
+msgstr ""
+
msgid "ChangeTypeActionLabel|Pick into branch"
msgstr ""
@@ -4731,6 +4901,9 @@ msgstr ""
msgid "Changes the title to \"%{title_param}\"."
msgstr ""
+msgid "Changes were successfully made."
+msgstr ""
+
msgid "Changes won't take place until the index is %{link_start}recreated%{link_end}."
msgstr ""
@@ -5136,6 +5309,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove variable"
+msgstr ""
+
msgid "CiVariables|Remove variable row"
msgstr ""
@@ -5214,9 +5390,6 @@ msgstr ""
msgid "Clear due date"
msgstr ""
-msgid "Clear input"
-msgstr ""
-
msgid "Clear recent searches"
msgstr ""
@@ -5265,6 +5438,9 @@ msgstr ""
msgid "Client authentication key password"
msgstr ""
+msgid "Client request timeout"
+msgstr ""
+
msgid "Clients"
msgstr ""
@@ -5349,6 +5525,27 @@ msgstr ""
msgid "Cluster type must be specificed for Stages::ClusterEndpointInserter"
msgstr ""
+msgid "ClusterAgents|Configuration"
+msgstr ""
+
+msgid "ClusterAgents|Connect your cluster with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate Kubernetes with a GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Name"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Agent also requires %{linkStart}enabling the Agent Server%{linkEnd}"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Kubernetes Agent allows an Infrastructure as Code, GitOps approach to integrating Kubernetes clusters with GitLab. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "ClusterAgent|This feature is only available for premium plans"
msgstr ""
@@ -5418,10 +5615,10 @@ msgstr ""
msgid "ClusterIntegration|All installed applications and related resources"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster."
+msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{linkStart}More information%{linkEnd}"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{startLink}More information%{endLink}"
+msgid "ClusterIntegration|Allow GitLab to manage namespaces and service accounts for this cluster."
msgstr ""
msgid "ClusterIntegration|Alternatively, "
@@ -5442,6 +5639,9 @@ msgstr ""
msgid "ClusterIntegration|An error occurred while trying to fetch zone machine types: %{error}"
msgstr ""
+msgid "ClusterIntegration|An unknown error occurred while attempting to connect to Kubernetes."
+msgstr ""
+
msgid "ClusterIntegration|Any project namespaces"
msgstr ""
@@ -5457,6 +5657,9 @@ msgstr ""
msgid "ClusterIntegration|Authenticate with Amazon Web Services"
msgstr ""
+msgid "ClusterIntegration|Authentication Error"
+msgstr ""
+
msgid "ClusterIntegration|Base domain"
msgstr ""
@@ -5475,13 +5678,22 @@ msgstr ""
msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}security group %{externalLinkIcon} %{endLink} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
+msgid "ClusterIntegration|Check your CA certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Check your cluster status"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}subnets %{externalLinkIcon} %{endLink} in your VPC where your worker nodes will run."
+msgid "ClusterIntegration|Check your token"
msgstr ""
-msgid "ClusterIntegration|Choose the worker node %{startLink}instance type %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Choose the %{linkStart}security group %{linkEnd} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
+msgstr ""
+
+msgid "ClusterIntegration|Choose the %{linkStart}subnets %{linkEnd} in your VPC where your worker nodes will run."
+msgstr ""
+
+msgid "ClusterIntegration|Choose the worker node %{linkStart}instance type%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Choose which applications to install on your Kubernetes cluster."
@@ -5493,10 +5705,7 @@ msgstr ""
msgid "ClusterIntegration|Clear cluster cache"
msgstr ""
-msgid "ClusterIntegration|Clear the local cache of namespace and service accounts. This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
-msgstr ""
-
-msgid "ClusterIntegration|Cluster being created"
+msgid "ClusterIntegration|Clear the local cache of namespace and service accounts."
msgstr ""
msgid "ClusterIntegration|Cluster management project (alpha)"
@@ -5508,15 +5717,21 @@ msgstr ""
msgid "ClusterIntegration|Cluster_applications artifact too big. Maximum allowable size: %{human_size}"
msgstr ""
-msgid "ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters."
+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|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}"
+msgid "ClusterIntegration|Clusters connected with a certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Connect cluster with certificate"
msgstr ""
msgid "ClusterIntegration|Connect existing cluster"
msgstr ""
+msgid "ClusterIntegration|Connection Error"
+msgstr ""
+
msgid "ClusterIntegration|Copy API URL"
msgstr ""
@@ -5592,6 +5807,12 @@ msgstr ""
msgid "ClusterIntegration|Deletes all GitLab resources attached to this cluster during removal"
msgstr ""
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared."
+msgstr ""
+
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared. %{linkStart}More information%{linkEnd}"
+msgstr ""
+
msgid "ClusterIntegration|Did you know?"
msgstr ""
@@ -5661,6 +5882,9 @@ msgstr ""
msgid "ClusterIntegration|Fluentd is an open source data collector, which lets you unify the data collection and consumption for a better use and understanding of data. It requires at least one of the following logs to be successfully installed."
msgstr ""
+msgid "ClusterIntegration|GitLab Agent managed clusters"
+msgstr ""
+
msgid "ClusterIntegration|GitLab Container Network Policies"
msgstr ""
@@ -5673,6 +5897,12 @@ msgstr ""
msgid "ClusterIntegration|GitLab Runner connects to the repository and executes CI/CD jobs, pushing results back and deploying applications to production."
msgstr ""
+msgid "ClusterIntegration|GitLab failed to authenticate."
+msgstr ""
+
+msgid "ClusterIntegration|GitLab failed to connect to the cluster."
+msgstr ""
+
msgid "ClusterIntegration|GitLab-managed cluster"
msgstr ""
@@ -5694,6 +5924,9 @@ msgstr ""
msgid "ClusterIntegration|Group cluster"
msgstr ""
+msgid "ClusterIntegration|HTTP Error"
+msgstr ""
+
msgid "ClusterIntegration|Helm Tiller"
msgstr ""
@@ -5727,7 +5960,10 @@ msgstr ""
msgid "ClusterIntegration|Instance type"
msgstr ""
-msgid "ClusterIntegration|Integrate Kubernetes cluster automation"
+msgid "ClusterIntegration|Integrate Kubernetes with a cluster certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Integrate with a cluster certificate"
msgstr ""
msgid "ClusterIntegration|Issuer Email"
@@ -5763,9 +5999,6 @@ msgstr ""
msgid "ClusterIntegration|Knative extends Kubernetes to provide a set of middleware components that are essential to build modern, source-centric, and container-based applications that can run anywhere: on premises, in the cloud, or even in a third-party data center."
msgstr ""
-msgid "ClusterIntegration|Kubernetes cluster"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes cluster is being created..."
msgstr ""
@@ -5778,9 +6011,6 @@ msgstr ""
msgid "ClusterIntegration|Kubernetes clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr ""
-msgid "ClusterIntegration|Kubernetes clusters can be used to deploy applications and to provide Review Apps for this project"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes version"
msgstr ""
@@ -5793,7 +6023,7 @@ msgstr ""
msgid "ClusterIntegration|Learn more about %{help_link_start}zones%{help_link_end}."
msgstr ""
-msgid "ClusterIntegration|Learn more about %{startLink}Regions %{externalLinkIcon}%{endLink}."
+msgid "ClusterIntegration|Learn more about %{linkStart}Regions%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Learn more about Kubernetes"
@@ -5838,12 +6068,18 @@ msgstr ""
msgid "ClusterIntegration|Machine type"
msgstr ""
+msgid "ClusterIntegration|Make sure your API endpoint is correct"
+msgstr ""
+
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create Kubernetes clusters"
msgstr ""
msgid "ClusterIntegration|Manage your Kubernetes cluster by visiting %{provider_link}"
msgstr ""
+msgid "ClusterIntegration|Namespace per environment"
+msgstr ""
+
msgid "ClusterIntegration|No IAM Roles found"
msgstr ""
@@ -5889,6 +6125,9 @@ msgstr ""
msgid "ClusterIntegration|No zones matched your search"
msgstr ""
+msgid "ClusterIntegration|Node calculations use the Kubernetes Metrics API. Make sure your cluster has metrics installed"
+msgstr ""
+
msgid "ClusterIntegration|Number of nodes"
msgstr ""
@@ -5931,6 +6170,9 @@ msgstr ""
msgid "ClusterIntegration|RBAC-enabled cluster"
msgstr ""
+msgid "ClusterIntegration|Read our %{linkStart}help page%{linkEnd} on Kubernetes cluster integration."
+msgstr ""
+
msgid "ClusterIntegration|Read our %{link_start}help page%{link_end} on Kubernetes cluster integration."
msgstr ""
@@ -6033,7 +6275,7 @@ msgstr ""
msgid "ClusterIntegration|Select a VPC to choose a subnet"
msgstr ""
-msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{linkStart}Amazon Web Services %{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select a network to choose a subnetwork"
@@ -6066,7 +6308,7 @@ msgstr ""
msgid "ClusterIntegration|Select project to choose zone"
msgstr ""
-msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select zone"
@@ -6156,9 +6398,18 @@ msgstr ""
msgid "ClusterIntegration|There was a problem authenticating with your cluster. Please ensure your CA Certificate and Token are valid."
msgstr ""
+msgid "ClusterIntegration|There was an HTTP error when connecting to your cluster."
+msgstr ""
+
msgid "ClusterIntegration|This account must have permissions to create a Kubernetes cluster in the %{link_to_container_project} specified below"
msgstr ""
+msgid "ClusterIntegration|This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
+msgstr ""
+
+msgid "ClusterIntegration|This is necessary to clear existing environment-namespace associations from clusters previously managed by GitLab."
+msgstr ""
+
msgid "ClusterIntegration|This option will allow you to install applications on RBAC clusters."
msgstr ""
@@ -6183,9 +6434,21 @@ msgstr ""
msgid "ClusterIntegration|To use a new project, first create one on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}."
msgstr ""
+msgid "ClusterIntegration|Troubleshooting tips:"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Authenticate"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Connect"
+msgstr ""
+
msgid "ClusterIntegration|Uninstall %{appTitle}"
msgstr ""
+msgid "ClusterIntegration|Unknown Error"
+msgstr ""
+
msgid "ClusterIntegration|Update %{appTitle}"
msgstr ""
@@ -6246,7 +6509,7 @@ msgstr ""
msgid "ClusterIntegration|Your cluster API is unreachable. Please ensure your API URL is correct."
msgstr ""
-msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Zone"
@@ -6366,6 +6629,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse all threads"
+msgstr ""
+
msgid "Collapse approvers"
msgstr ""
@@ -6517,7 +6783,7 @@ msgstr ""
msgid "Commit…"
msgstr ""
-msgid "Company"
+msgid "Community forum"
msgstr ""
msgid "Company name"
@@ -6526,6 +6792,9 @@ msgstr ""
msgid "Compare"
msgstr ""
+msgid "Compare %{oldCommitId}...%{newCommitId}"
+msgstr ""
+
msgid "Compare Git revisions"
msgstr ""
@@ -6541,6 +6810,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare submodule commit revisions"
+msgstr ""
+
msgid "Compare with previous version"
msgstr ""
@@ -6676,6 +6948,9 @@ msgstr ""
msgid "Configure the way a user creates a new account."
msgstr ""
+msgid "Configure which lists are shown for anyone who visits this board"
+msgstr ""
+
msgid "Confirm"
msgstr ""
@@ -6907,6 +7182,9 @@ msgstr[3] ""
msgid "ContainerRegistry|Set cleanup policy"
msgstr ""
+msgid "ContainerRegistry|Some tags were not deleted"
+msgstr ""
+
msgid "ContainerRegistry|Something went wrong while fetching the cleanup policy."
msgstr ""
@@ -6946,6 +7224,9 @@ msgstr ""
msgid "ContainerRegistry|Tags with names matching this regex pattern will %{italicStart}expire:%{italicEnd}"
msgstr ""
+msgid "ContainerRegistry|The cleanup policy timed out before it could delete all tags. An administrator can %{adminLinkStart}manually run cleanup now%{adminLinkEnd} or you can wait for the cleanup policy to automatically run again. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "ContainerRegistry|The last tag related to this image was recently removed. This empty image and any associated data will be automatically removed as part of the regular Garbage Collection process. If you have any questions, contact your administrator."
msgstr ""
@@ -7078,6 +7359,9 @@ msgstr ""
msgid "Contributions per group member"
msgstr ""
+msgid "Contributor"
+msgstr ""
+
msgid "Contributors"
msgstr ""
@@ -7207,6 +7491,9 @@ msgstr ""
msgid "Could not change HEAD: branch '%{branch}' does not exist"
msgstr ""
+msgid "Could not commit. An unexpected error occurred."
+msgstr ""
+
msgid "Could not connect to FogBugz, check your URL"
msgstr ""
@@ -7246,6 +7533,9 @@ msgstr ""
msgid "Could not find iteration"
msgstr ""
+msgid "Could not load instance counts. Please refresh the page to try again."
+msgstr ""
+
msgid "Could not remove the trigger."
msgstr ""
@@ -7270,10 +7560,10 @@ msgstr ""
msgid "Could not save prometheus manual configuration"
msgstr ""
-msgid "Could not udpdate wiki page"
+msgid "Could not update the LDAP settings"
msgstr ""
-msgid "Could not update the LDAP settings"
+msgid "Could not update wiki page"
msgstr ""
msgid "Could not upload your designs as one or more files uploaded are not supported."
@@ -7935,6 +8225,9 @@ msgstr ""
msgid "DastProfiles|Are you sure you want to delete this profile?"
msgstr ""
+msgid "DastProfiles|Could not create site validation token. Please refresh the page, or try again later."
+msgstr ""
+
msgid "DastProfiles|Could not create the scanner profile. Please try again."
msgstr ""
@@ -7959,6 +8252,12 @@ msgstr ""
msgid "DastProfiles|Could not fetch site profiles. Please refresh the page, or try again later."
msgstr ""
+msgid "DastProfiles|Could not retrieve site validation status. Please refresh the page, or try again later."
+msgstr ""
+
+msgid "DastProfiles|Could not update the scanner profile. Please try again."
+msgstr ""
+
msgid "DastProfiles|Could not update the site profile. Please try again."
msgstr ""
@@ -7974,7 +8273,7 @@ msgstr ""
msgid "DastProfiles|Download validation text file"
msgstr ""
-msgid "DastProfiles|Edit feature will come soon. Please create a new profile if changes needed"
+msgid "DastProfiles|Edit scanner profile"
msgstr ""
msgid "DastProfiles|Edit site profile"
@@ -8007,6 +8306,9 @@ msgstr ""
msgid "DastProfiles|No profiles created yet"
msgstr ""
+msgid "DastProfiles|Passive"
+msgstr ""
+
msgid "DastProfiles|Please enter a valid URL format, ex: http://www.example.com/home"
msgstr ""
@@ -8022,6 +8324,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan mode"
+msgstr ""
+
msgid "DastProfiles|Scanner Profile"
msgstr ""
@@ -8061,10 +8366,10 @@ msgstr ""
msgid "DastProfiles|Text file validation"
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
+msgid "DastProfiles|The maximum number of minutes allowed for the spider to traverse the site."
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the spider to traverse the site."
+msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
msgstr ""
msgid "DastProfiles|Validate"
@@ -8097,6 +8402,9 @@ msgstr ""
msgid "Date picker"
msgstr ""
+msgid "Date range"
+msgstr ""
+
msgid "Date range cannot exceed %{maxDateRange} days."
msgstr ""
@@ -8121,6 +8429,9 @@ msgstr ""
msgid "Days to merge"
msgstr ""
+msgid "Dear Administrator,"
+msgstr ""
+
msgid "Debug"
msgstr ""
@@ -8232,12 +8543,18 @@ msgstr ""
msgid "Delete"
msgstr ""
+msgid "Delete %{name}"
+msgstr ""
+
msgid "Delete Comment"
msgstr ""
msgid "Delete Snippet"
msgstr ""
+msgid "Delete Value Stream"
+msgstr ""
+
msgid "Delete account"
msgstr ""
@@ -8259,9 +8576,6 @@ msgstr ""
msgid "Delete label: %{label_name} ?"
msgstr ""
-msgid "Delete license"
-msgstr ""
-
msgid "Delete list"
msgstr ""
@@ -8337,15 +8651,6 @@ msgstr ""
msgid "Deleting a project places it into a read-only state until %{date}, at which point the project will be permanently deleted. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "Deleting the license failed."
-msgstr ""
-
-msgid "Deleting the license failed. The license was not found."
-msgstr ""
-
-msgid "Deleting the license failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "Deleting the project will delete its repository and all related resources including issues, merge requests etc."
msgstr ""
@@ -8853,7 +9158,10 @@ msgstr ""
msgid "DesignManagement|The maximum number of designs allowed to be uploaded is %{upload_limit}. Please try again."
msgstr ""
-msgid "DesignManagement|To upload designs, you'll need to enable LFS. %{requirements_link_start}More information%{requirements_link_end}"
+msgid "DesignManagement|There was an error moving your designs. Please upload your designs below."
+msgstr ""
+
+msgid "DesignManagement|To upload designs, you'll need to enable LFS and have admin enable hashed storage. %{requirements_link_start}More information%{requirements_link_end}"
msgstr ""
msgid "DesignManagement|Unresolve thread"
@@ -8865,6 +9173,9 @@ msgstr ""
msgid "DesignManagement|Upload skipped."
msgstr ""
+msgid "DesignManagement|Your designs are being copied and are on their way… Please refresh to update."
+msgstr ""
+
msgid "DesignManagement|and %{moreCount} more."
msgstr ""
@@ -8922,6 +9233,9 @@ msgstr ""
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
+msgid "Direct member"
+msgstr ""
+
msgid "Direction"
msgstr ""
@@ -8970,9 +9284,6 @@ msgstr ""
msgid "Discard draft"
msgstr ""
-msgid "Discard review"
-msgstr ""
-
msgid "DiscordService|Discord Notifications"
msgstr ""
@@ -9043,10 +9354,10 @@ msgstr ""
msgid "Dismiss Merge Request promotion"
msgstr ""
-msgid "Dismiss Selected"
+msgid "Dismiss Value Stream Analytics introduction box"
msgstr ""
-msgid "Dismiss Value Stream Analytics introduction box"
+msgid "Dismiss selected"
msgstr ""
msgid "Dismiss trial promotion"
@@ -9097,9 +9408,6 @@ msgstr ""
msgid "Documents reindexed: %{processed_documents} (%{percentage}%%)"
msgstr ""
-msgid "Doing"
-msgstr ""
-
msgid "Domain"
msgstr ""
@@ -9295,9 +9603,6 @@ msgstr ""
msgid "Edit environment"
msgstr ""
-msgid "Edit file"
-msgstr ""
-
msgid "Edit files in the editor and commit changes here"
msgstr ""
@@ -9310,6 +9615,12 @@ msgstr ""
msgid "Edit identity for %{user_name}"
msgstr ""
+msgid "Edit in Web IDE"
+msgstr ""
+
+msgid "Edit in single-file editor"
+msgstr ""
+
msgid "Edit issues"
msgstr ""
@@ -9337,10 +9648,10 @@ msgstr ""
msgid "Editing"
msgstr ""
-msgid "Elasticsearch"
+msgid "Elasticsearch AWS IAM credentials"
msgstr ""
-msgid "Elasticsearch AWS IAM credentials"
+msgid "Elasticsearch HTTP client timeout value in seconds."
msgstr ""
msgid "Elasticsearch indexing restrictions"
@@ -9349,9 +9660,6 @@ msgstr ""
msgid "Elasticsearch indexing started"
msgstr ""
-msgid "Elasticsearch integration. Elasticsearch AWS IAM."
-msgstr ""
-
msgid "Elasticsearch reindexing is already in progress"
msgstr ""
@@ -9379,9 +9687,6 @@ msgstr ""
msgid "Email Notification"
msgstr ""
-msgid "Email address"
-msgstr ""
-
msgid "Email could not be sent"
msgstr ""
@@ -9445,6 +9750,9 @@ msgstr ""
msgid "Emails sent from Service Desk will have this name"
msgstr ""
+msgid "Emails sent to %{email} will still be supported"
+msgstr ""
+
msgid "Emails separated by comma"
msgstr ""
@@ -9478,9 +9786,18 @@ msgstr ""
msgid "Enable"
msgstr ""
+msgid "Enable %{link_start}Gitpod%{link_end} integration to launch a development environment in your browser directly from GitLab."
+msgstr ""
+
msgid "Enable Auto DevOps"
msgstr ""
+msgid "Enable Gitpod"
+msgstr ""
+
+msgid "Enable Gitpod?"
+msgstr ""
+
msgid "Enable HTML emails"
msgstr ""
@@ -9610,9 +9927,6 @@ msgstr ""
msgid "Encountered an error while rendering: %{err}"
msgstr ""
-msgid "End date"
-msgstr ""
-
msgid "Ends at (UTC)"
msgstr ""
@@ -9772,7 +10086,7 @@ msgstr ""
msgid "EnvironmentsDashboard|The environments dashboard provides a summary of each project's environments' status, including pipeline and alert statuses."
msgstr ""
-msgid "EnvironmentsDashboard|This dashboard displays a maximum of 7 projects and 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
+msgid "EnvironmentsDashboard|This dashboard displays 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
msgstr ""
msgid "Environments|An error occurred while canceling the auto stop, please try again"
@@ -10093,6 +10407,9 @@ msgstr ""
msgid "Error deleting project. Check logs for error details."
msgstr ""
+msgid "Error fetching burnup chart data"
+msgstr ""
+
msgid "Error fetching diverging counts for branches. Please try again."
msgstr ""
@@ -10171,6 +10488,9 @@ msgstr ""
msgid "Error occurred when saving assignees"
msgstr ""
+msgid "Error occurred when saving reviewers"
+msgstr ""
+
msgid "Error occurred when toggling the notification subscription"
msgstr ""
@@ -10423,10 +10743,13 @@ msgstr ""
msgid "Expand all"
msgstr ""
-msgid "Expand approvers"
+msgid "Expand all files"
msgstr ""
-msgid "Expand dropdown"
+msgid "Expand all threads"
+msgstr ""
+
+msgid "Expand approvers"
msgstr ""
msgid "Expand milestones"
@@ -10597,6 +10920,9 @@ msgstr ""
msgid "Failed to create Merge Request. Please try again."
msgstr ""
+msgid "Failed to create To-Do for the design."
+msgstr ""
+
msgid "Failed to create a branch for this issue. Please try again."
msgstr ""
@@ -10636,6 +10962,12 @@ msgstr ""
msgid "Failed to load authors. Please try again."
msgstr ""
+msgid "Failed to load branches. Please try again."
+msgstr ""
+
+msgid "Failed to load deploy keys."
+msgstr ""
+
msgid "Failed to load emoji list."
msgstr ""
@@ -10651,6 +10983,9 @@ msgstr ""
msgid "Failed to load groups & users."
msgstr ""
+msgid "Failed to load groups, users and deploy keys."
+msgstr ""
+
msgid "Failed to load labels. Please try again."
msgstr ""
@@ -10660,6 +10995,12 @@ msgstr ""
msgid "Failed to load related branches"
msgstr ""
+msgid "Failed to load sidebar confidential toggle"
+msgstr ""
+
+msgid "Failed to load sidebar lock status"
+msgstr ""
+
msgid "Failed to load stacktrace."
msgstr ""
@@ -10687,6 +11028,9 @@ msgstr ""
msgid "Failed to publish issue on status page."
msgstr ""
+msgid "Failed to remove To-Do for the design."
+msgstr ""
+
msgid "Failed to remove a Zoom meeting"
msgstr ""
@@ -10729,6 +11073,9 @@ msgstr ""
msgid "Failed to signing using smartcard authentication"
msgstr ""
+msgid "Failed to toggle To-Do for the design."
+msgstr ""
+
msgid "Failed to update branch!"
msgstr ""
@@ -10844,7 +11191,7 @@ msgstr ""
msgid "FeatureFlags|Edit User List"
msgstr ""
-msgid "FeatureFlags|Enable features for specific users and specific environments by defining feature flag strategies."
+msgid "FeatureFlags|Enable features for specific users and environments by configuring feature flag strategies."
msgstr ""
msgid "FeatureFlags|Environment Spec"
@@ -10904,7 +11251,7 @@ msgstr ""
msgid "FeatureFlags|Include additional user IDs"
msgstr ""
-msgid "FeatureFlags|Install a %{docs_link_anchored_start}compatible client library%{docs_link_anchored_end} and specify the API URL, application name, and instance ID during the configuration setup. %{docs_link_start}More Information%{docs_link_end}"
+msgid "FeatureFlags|Install a %{docsLinkAnchoredStart}compatible client library%{docsLinkAnchoredEnd} and specify the API URL, application name, and instance ID during the configuration setup. %{docsLinkStart}More Information%{docsLinkEnd}"
msgstr ""
msgid "FeatureFlags|Instance ID"
@@ -10916,6 +11263,9 @@ msgstr ""
msgid "FeatureFlags|Loading feature flags"
msgstr ""
+msgid "FeatureFlags|Loading user lists"
+msgstr ""
+
msgid "FeatureFlags|More information"
msgstr ""
@@ -10934,7 +11284,7 @@ msgstr ""
msgid "FeatureFlags|New feature flag"
msgstr ""
-msgid "FeatureFlags|New list"
+msgid "FeatureFlags|New user list"
msgstr ""
msgid "FeatureFlags|Percent of users"
@@ -10973,6 +11323,9 @@ msgstr ""
msgid "FeatureFlags|There was an error fetching the feature flags."
msgstr ""
+msgid "FeatureFlags|There was an error fetching the user lists."
+msgstr ""
+
msgid "FeatureFlags|There was an error retrieving user lists"
msgstr ""
@@ -10988,6 +11341,9 @@ msgstr ""
msgid "FeatureFlags|User List"
msgstr ""
+msgid "FeatureFlags|User Lists"
+msgstr ""
+
msgid "FeatureFlag|List"
msgstr ""
@@ -11015,15 +11371,6 @@ msgstr ""
msgid "Fetching incoming email"
msgstr ""
-msgid "Fetching licenses failed."
-msgstr ""
-
-msgid "Fetching licenses failed. The request endpoint was not found."
-msgstr ""
-
-msgid "Fetching licenses failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "File"
msgstr ""
@@ -11126,12 +11473,21 @@ msgstr ""
msgid "Filter by status"
msgstr ""
+msgid "Filter by test cases that are currently archived."
+msgstr ""
+
+msgid "Filter by test cases that are currently opened."
+msgstr ""
+
msgid "Filter by two-factor authentication"
msgstr ""
msgid "Filter by user"
msgstr ""
+msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
+msgstr ""
+
msgid "Filter pipelines"
msgstr ""
@@ -11147,7 +11503,7 @@ msgstr ""
msgid "Filter results..."
msgstr ""
-msgid "Filter your projects by name"
+msgid "Filter your repositories by name"
msgstr ""
msgid "Filter..."
@@ -11156,7 +11512,7 @@ msgstr ""
msgid "Find File"
msgstr ""
-msgid "Find bugs in your code with coverage-guided fuzzing"
+msgid "Find bugs in your code with coverage-guided fuzzing."
msgstr ""
msgid "Find by path"
@@ -11183,9 +11539,6 @@ msgstr ""
msgid "Finish editing this message first!"
msgstr ""
-msgid "Finish review"
-msgstr ""
-
msgid "Finish setting up your dedicated account for %{group_name}."
msgstr ""
@@ -11255,6 +11608,9 @@ msgstr ""
msgid "Footer message"
msgstr ""
+msgid "For a faster browsing experience, some files are collapsed by default."
+msgstr ""
+
msgid "For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
@@ -11264,6 +11620,9 @@ msgstr ""
msgid "For more info, read the documentation."
msgstr ""
+msgid "For more information on how the number of active users is calculated, see the %{self_managed_subscriptions_doc_link} documentation."
+msgstr ""
+
msgid "For more information, go to the "
msgstr ""
@@ -11402,6 +11761,9 @@ msgstr ""
msgid "Generate new token"
msgstr ""
+msgid "Generic package file size in bytes"
+msgstr ""
+
msgid "Geo"
msgstr ""
@@ -11663,6 +12025,9 @@ msgstr ""
msgid "Geo|Please refer to Geo Troubleshooting."
msgstr ""
+msgid "Geo|Primary node"
+msgstr ""
+
msgid "Geo|Project"
msgstr ""
@@ -11705,6 +12070,9 @@ msgstr ""
msgid "Geo|Review replication status, and resynchronize and reverify items with the primary node."
msgstr ""
+msgid "Geo|Secondary node"
+msgstr ""
+
msgid "Geo|Status"
msgstr ""
@@ -11744,6 +12112,9 @@ msgstr ""
msgid "Geo|URL must be a valid url (ex: https://gitlab.com)"
msgstr ""
+msgid "Geo|Undefined"
+msgstr ""
+
msgid "Geo|Unknown state"
msgstr ""
@@ -11819,10 +12190,16 @@ msgstr ""
msgid "GitHub import"
msgstr ""
+msgid "GitLab"
+msgstr ""
+
msgid "GitLab / Unsubscribe"
msgstr ""
-msgid "GitLab Enterprise Edition %{plan}"
+msgid "GitLab API"
+msgstr ""
+
+msgid "GitLab Billing Team."
msgstr ""
msgid "GitLab Group Runners can execute code for all the projects in this group."
@@ -11834,12 +12211,18 @@ msgstr ""
msgid "GitLab Issue"
msgstr ""
+msgid "GitLab Pages"
+msgstr ""
+
msgid "GitLab Service Desk is a simple way to allow people to create issues in your GitLab instance without needing their own user account. It provides a unique email address for end users to create issues in a project, and replies can be sent either through the GitLab interface or by email. End users will only see the thread through email."
msgstr ""
msgid "GitLab Shared Runners execute code of different projects on the same Runner unless you configure GitLab Runner Autoscale with MaxBuilds 1 (which it is on GitLab.com)."
msgstr ""
+msgid "GitLab Shell"
+msgstr ""
+
msgid "GitLab Support Bot"
msgstr ""
@@ -11849,7 +12232,7 @@ msgstr ""
msgid "GitLab User"
msgstr ""
-msgid "GitLab allows you to continue using your license even if you exceed the number of seats you purchased. You will be required to pay for these seats when you renew your license."
+msgid "GitLab Workhorse"
msgstr ""
msgid "GitLab commit"
@@ -12017,6 +12400,21 @@ msgstr ""
msgid "Gitlab Pages"
msgstr ""
+msgid "Gitpod"
+msgstr ""
+
+msgid "Gitpod|Add the URL to your Gitpod instance configured to read your GitLab projects."
+msgstr ""
+
+msgid "Gitpod|Enable Gitpod integration"
+msgstr ""
+
+msgid "Gitpod|Gitpod URL"
+msgstr ""
+
+msgid "Gitpod|e.g. https://gitpod.example.com"
+msgstr ""
+
msgid "Given access %{time_ago}"
msgstr ""
@@ -12524,9 +12922,6 @@ msgstr ""
msgid "GroupSAML|Valid SAML Response"
msgstr ""
-msgid "GroupSAML|With group managed accounts enabled, all the users without a group managed account will be excluded from the group."
-msgstr ""
-
msgid "GroupSAML|With prohibit outer forks flag enabled group members will be able to fork project only inside your group."
msgstr ""
@@ -12740,10 +13135,10 @@ msgstr ""
msgid "GroupsNew|Create group"
msgstr ""
-msgid "GroupsNew|GitLab group export"
+msgid "GroupsNew|Import"
msgstr ""
-msgid "GroupsNew|Import"
+msgid "GroupsNew|Import a GitLab group export file"
msgstr ""
msgid "GroupsNew|Import group"
@@ -12888,6 +13283,9 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "Hide comments on this file"
+msgstr ""
+
msgid "Hide details"
msgstr ""
@@ -12934,6 +13332,15 @@ msgstr ""
msgid "Highest role:"
msgstr ""
+msgid "HighlightBar|Alert events:"
+msgstr ""
+
+msgid "HighlightBar|Alert start time:"
+msgstr ""
+
+msgid "HighlightBar|Original alert:"
+msgstr ""
+
msgid "History"
msgstr ""
@@ -13111,6 +13518,9 @@ msgstr ""
msgid "If enabled, access to projects will be validated on an external service using their classification label."
msgstr ""
+msgid "If the number of active users exceeds the user limit, you will be charged for the number of %{users_over_license_link} at your next license reconciliation."
+msgstr ""
+
msgid "If there is no previous license or if the previous license has expired, some GitLab functionality will be blocked until a new, valid license is uploaded."
msgstr ""
@@ -13150,9 +13560,6 @@ msgstr ""
msgid "If your HTTP repository is not publicly accessible, add your credentials."
msgstr ""
-msgid "Iglu registry URL (optional)"
-msgstr ""
-
msgid "Ignore"
msgstr ""
@@ -13189,6 +13596,20 @@ msgstr ""
msgid "Import"
msgstr ""
+msgid "Import %d compatible repository"
+msgid_plural "Import %d compatible repositories"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
+msgid "Import %d repository"
+msgid_plural "Import %d repositories"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "Import CSV"
msgstr ""
@@ -13198,15 +13619,9 @@ msgstr ""
msgid "Import all compatible projects"
msgstr ""
-msgid "Import all compatible repositories"
-msgstr ""
-
msgid "Import all projects"
msgstr ""
-msgid "Import all repositories"
-msgstr ""
-
msgid "Import an exported GitLab project"
msgstr ""
@@ -13294,6 +13709,9 @@ msgstr ""
msgid "ImportProjects|Error importing repository %{project_safe_import_url} into %{project_full_path} - %{message}"
msgstr ""
+msgid "ImportProjects|Import repositories"
+msgstr ""
+
msgid "ImportProjects|Importing the project failed"
msgstr ""
@@ -13306,7 +13724,7 @@ msgstr ""
msgid "ImportProjects|Requesting your %{provider} repositories failed"
msgstr ""
-msgid "ImportProjects|Select the projects you want to import"
+msgid "ImportProjects|Select the repositories you want to import"
msgstr ""
msgid "ImportProjects|The remote data could not be imported."
@@ -13342,9 +13760,6 @@ msgstr ""
msgid "In order to enable Service Desk for your instance, you must first set up incoming email."
msgstr ""
-msgid "In order to gather accurate feature usage data, it can take 1 to 2 weeks to see your index."
-msgstr ""
-
msgid "In order to personalize your experience with GitLab%{br_tag}we would like to know a bit more about you."
msgstr ""
@@ -13375,18 +13790,30 @@ msgstr ""
msgid "IncidentManagement|Create incident"
msgstr ""
+msgid "IncidentManagement|Critical - S1"
+msgstr ""
+
msgid "IncidentManagement|Date created"
msgstr ""
msgid "IncidentManagement|Display your incidents in a dedicated view"
msgstr ""
+msgid "IncidentManagement|High - S2"
+msgstr ""
+
msgid "IncidentManagement|Incident"
msgstr ""
msgid "IncidentManagement|Incidents"
msgstr ""
+msgid "IncidentManagement|Low - S4"
+msgstr ""
+
+msgid "IncidentManagement|Medium - S3"
+msgstr ""
+
msgid "IncidentManagement|No incidents to display."
msgstr ""
@@ -13399,6 +13826,9 @@ msgstr ""
msgid "IncidentManagement|Published to status page"
msgstr ""
+msgid "IncidentManagement|Severity"
+msgstr ""
+
msgid "IncidentManagement|There are no closed incidents"
msgstr ""
@@ -13408,6 +13838,9 @@ msgstr ""
msgid "IncidentManagement|Unassigned"
msgstr ""
+msgid "IncidentManagement|Unknown"
+msgstr ""
+
msgid "IncidentManagement|Unpublished"
msgstr ""
@@ -13429,6 +13862,15 @@ msgstr ""
msgid "Incidents"
msgstr ""
+msgid "Incident|Alert details"
+msgstr ""
+
+msgid "Incident|Summary"
+msgstr ""
+
+msgid "Incident|There was an issue loading alert data. Please try again."
+msgstr ""
+
msgid "Include a Terms of Service agreement and Privacy Policy that all users must accept."
msgstr ""
@@ -13489,6 +13931,9 @@ msgstr ""
msgid "Information about additional Pages templates and how to install them can be found in our %{pages_getting_started_guide}."
msgstr ""
+msgid "Inherited"
+msgstr ""
+
msgid "Inherited:"
msgstr ""
@@ -13571,7 +14016,22 @@ msgstr ""
msgid "Instance administrators group already exists"
msgstr ""
-msgid "Instance license"
+msgid "InstanceStatistics|Groups"
+msgstr ""
+
+msgid "InstanceStatistics|Issues"
+msgstr ""
+
+msgid "InstanceStatistics|Merge Requests"
+msgstr ""
+
+msgid "InstanceStatistics|Pipelines"
+msgstr ""
+
+msgid "InstanceStatistics|Projects"
+msgstr ""
+
+msgid "InstanceStatistics|Users"
msgstr ""
msgid "Integration"
@@ -13583,6 +14043,12 @@ msgstr ""
msgid "Integrations"
msgstr ""
+msgid "Integrations|%{integration} settings saved and active."
+msgstr ""
+
+msgid "Integrations|%{integration} settings saved, but not active."
+msgstr ""
+
msgid "Integrations|All details"
msgstr ""
@@ -13592,6 +14058,12 @@ msgstr ""
msgid "Integrations|Comment settings:"
msgstr ""
+msgid "Integrations|Connection failed. Please check your settings."
+msgstr ""
+
+msgid "Integrations|Connection successful."
+msgstr ""
+
msgid "Integrations|Default settings are inherited from the group level."
msgstr ""
@@ -13607,6 +14079,15 @@ msgstr ""
msgid "Integrations|Includes commit title and branch"
msgstr ""
+msgid "Integrations|Projects using custom settings will not be impacted unless the project owner chooses to use instance-level defaults."
+msgstr ""
+
+msgid "Integrations|Save settings?"
+msgstr ""
+
+msgid "Integrations|Saving will update the default settings for all projects that are not using custom settings."
+msgstr ""
+
msgid "Integrations|Standard"
msgstr ""
@@ -13739,6 +14220,9 @@ msgstr ""
msgid "Invitation"
msgstr ""
+msgid "Invitation declined"
+msgstr ""
+
msgid "Invite"
msgstr ""
@@ -13790,6 +14274,42 @@ 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|%{linkStart}Read more%{linkEnd} about role permissions"
+msgstr ""
+
+msgid "InviteMembersModal|Access expiration date (optional)"
+msgstr ""
+
+msgid "InviteMembersModal|Cancel"
+msgstr ""
+
+msgid "InviteMembersModal|Choose a role permission"
+msgstr ""
+
+msgid "InviteMembersModal|GitLab member or Email address"
+msgstr ""
+
+msgid "InviteMembersModal|Invite"
+msgstr ""
+
+msgid "InviteMembersModal|Invite team members"
+msgstr ""
+
+msgid "InviteMembersModal|Search for members to invite"
+msgstr ""
+
+msgid "InviteMembersModal|User not invited. Feature coming soon!"
+msgstr ""
+
+msgid "InviteMembersModal|Users were succesfully added"
+msgstr ""
+
+msgid "InviteMembersModal|You're inviting members to the %{group_name} group"
+msgstr ""
+
+msgid "InviteMembers|Invite team members"
+msgstr ""
+
msgid "Invited"
msgstr ""
@@ -13844,10 +14364,13 @@ msgstr ""
msgid "Issue cannot be found."
msgstr ""
+msgid "Issue created from vulnerability %{vulnerability_link}"
+msgstr ""
+
msgid "Issue events"
msgstr ""
-msgid "Issue first depoloyed to production"
+msgid "Issue first deployed to production"
msgstr ""
msgid "Issue label"
@@ -13925,6 +14448,9 @@ msgstr ""
msgid "IssueTracker|Custom issue tracker"
msgstr ""
+msgid "IssueTracker|EWM work items tracker"
+msgstr ""
+
msgid "IssueTracker|Redmine issue tracker"
msgstr ""
@@ -13991,6 +14517,9 @@ msgstr ""
msgid "It looks like you have some draft commits in this branch."
msgstr ""
+msgid "It may be several days before you see feature usage data."
+msgstr ""
+
msgid "It must have a header row and at least two columns: the first column is the issue title and the second column is the issue description. The separator is automatically detected."
msgstr ""
@@ -14273,13 +14802,13 @@ msgstr ""
msgid "Join Zoom meeting"
msgstr ""
-msgid "Jul"
+msgid "Joined %{time_ago}"
msgstr ""
-msgid "July"
+msgid "Jul"
msgstr ""
-msgid "Jump to first unresolved thread"
+msgid "July"
msgstr ""
msgid "Jump to next unresolved thread"
@@ -14315,6 +14844,9 @@ msgstr ""
msgid "Keyboard shortcuts"
msgstr ""
+msgid "KeyboardKey|Ctrl+"
+msgstr ""
+
msgid "Keys"
msgstr ""
@@ -14363,6 +14895,9 @@ msgstr ""
msgid "LDAP Synchronization"
msgstr ""
+msgid "LDAP group settings"
+msgstr ""
+
msgid "LDAP settings"
msgstr ""
@@ -14372,6 +14907,9 @@ msgstr ""
msgid "LDAP sync in progress. This could take a few minutes. Refresh the page to see the changes."
msgstr ""
+msgid "LDAP synchronizations"
+msgstr ""
+
msgid "LFS"
msgstr ""
@@ -14454,7 +14992,16 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "Last %{days} days"
+msgid "Last 2 weeks"
+msgstr ""
+
+msgid "Last 30 days"
+msgstr ""
+
+msgid "Last 60 days"
+msgstr ""
+
+msgid "Last 90 days"
msgstr ""
msgid "Last Accessed On"
@@ -14532,6 +15079,9 @@ msgstr ""
msgid "Last used on:"
msgstr ""
+msgid "Last week"
+msgstr ""
+
msgid "LastCommit|authored"
msgstr ""
@@ -14547,6 +15097,9 @@ msgstr ""
msgid "Latest pipeline for the most recent commit on this branch"
msgstr ""
+msgid "Launch a ready-to-code development environment for your project."
+msgstr ""
+
msgid "Lead"
msgstr ""
@@ -14941,6 +15494,9 @@ msgstr ""
msgid "List of all merge commits"
msgstr ""
+msgid "List options"
+msgstr ""
+
msgid "List settings"
msgstr ""
@@ -14953,9 +15509,6 @@ msgstr ""
msgid "List your Bitbucket Server repositories"
msgstr ""
-msgid "Lists"
-msgstr ""
-
msgid "Live preview"
msgstr ""
@@ -15202,6 +15755,12 @@ msgstr ""
msgid "Mark as done"
msgstr ""
+msgid "Mark as draft"
+msgstr ""
+
+msgid "Mark as ready"
+msgstr ""
+
msgid "Mark as resolved"
msgstr ""
@@ -15223,6 +15782,24 @@ msgstr ""
msgid "Markdown is supported"
msgstr ""
+msgid "MarkdownEditor|Add a link (%{modifierKey}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add a link (%{modifier_key}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifierKey}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifier_key}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifierKey}I)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifier_key}I)"
+msgstr ""
+
msgid "Marked For Deletion At - %{deletion_time}"
msgstr ""
@@ -15307,7 +15884,25 @@ msgstr ""
msgid "Max access level"
msgstr ""
-msgid "Max seats used"
+msgid "Max role"
+msgstr ""
+
+msgid "Max size 15 MB"
+msgstr ""
+
+msgid "Maximum Conan package file size in bytes"
+msgstr ""
+
+msgid "Maximum Maven package file size in bytes"
+msgstr ""
+
+msgid "Maximum NPM package file size in bytes"
+msgstr ""
+
+msgid "Maximum NuGet package file size in bytes"
+msgstr ""
+
+msgid "Maximum PyPI package file size in bytes"
msgstr ""
msgid "Maximum Users:"
@@ -15439,6 +16034,18 @@ msgstr ""
msgid "Members with access to %{strong_start}%{group_name}%{strong_end}"
msgstr ""
+msgid "Members|%{time} by %{user}"
+msgstr ""
+
+msgid "Members|Expired"
+msgstr ""
+
+msgid "Members|No expiration set"
+msgstr ""
+
+msgid "Members|in %{time}"
+msgstr ""
+
msgid "Memory Usage"
msgstr ""
@@ -15625,9 +16232,6 @@ msgstr ""
msgid "MergeRequests|Thread will be unresolved"
msgstr ""
-msgid "MergeRequests|Toggle comments for this file"
-msgstr ""
-
msgid "MergeRequests|View file @ %{commitId}"
msgstr ""
@@ -15688,6 +16292,9 @@ msgstr ""
msgid "Merging immediately isn't recommended as it may negatively impact the existing merge train. Read the %{docsLinkStart}documentation%{docsLinkEnd} for more information."
msgstr ""
+msgid "Message"
+msgstr ""
+
msgid "Messages"
msgstr ""
@@ -16077,18 +16684,12 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "Milestone does not support burnup charts"
-msgstr ""
-
msgid "Milestone lists not available with your current license"
msgstr ""
msgid "Milestone lists show all issues from the selected milestone."
msgstr ""
-msgid "Milestone must have a start and due date"
-msgstr ""
-
msgid "MilestoneSidebar|Closed:"
msgstr ""
@@ -16455,6 +17056,9 @@ msgstr ""
msgid "Namespace"
msgstr ""
+msgid "Namespace ID:"
+msgstr ""
+
msgid "Namespace is empty"
msgstr ""
@@ -16539,6 +17143,9 @@ msgstr ""
msgid "NetworkPolicies|Allow all outbound traffic from %{selector} to %{ruleSelector} on %{ports}"
msgstr ""
+msgid "NetworkPolicies|Are you sure you want to delete this policy? This action cannot be undone."
+msgstr ""
+
msgid "NetworkPolicies|Choose whether to enforce this policy."
msgstr ""
@@ -16548,12 +17155,21 @@ msgstr ""
msgid "NetworkPolicies|Define this policy's location, conditions and actions."
msgstr ""
+msgid "NetworkPolicies|Delete policy"
+msgstr ""
+
+msgid "NetworkPolicies|Delete policy: %{policy}"
+msgstr ""
+
msgid "NetworkPolicies|Deny all traffic"
msgstr ""
msgid "NetworkPolicies|Description"
msgstr ""
+msgid "NetworkPolicies|Edit policy"
+msgstr ""
+
msgid "NetworkPolicies|Editor mode"
msgstr ""
@@ -16581,6 +17197,9 @@ msgstr ""
msgid "NetworkPolicies|Name"
msgstr ""
+msgid "NetworkPolicies|Namespace"
+msgstr ""
+
msgid "NetworkPolicies|Network Policy"
msgstr ""
@@ -16632,6 +17251,9 @@ msgstr ""
msgid "NetworkPolicies|Rules"
msgstr ""
+msgid "NetworkPolicies|Save changes"
+msgstr ""
+
msgid "NetworkPolicies|Something went wrong, failed to update policy"
msgstr ""
@@ -16644,6 +17266,9 @@ msgstr ""
msgid "NetworkPolicies|Traffic that does not match any rule will be blocked."
msgstr ""
+msgid "NetworkPolicies|Unable to parse policy"
+msgstr ""
+
msgid "NetworkPolicies|YAML editor"
msgstr ""
@@ -16759,6 +17384,9 @@ msgstr ""
msgid "New Snippet"
msgstr ""
+msgid "New Test Case"
+msgstr ""
+
msgid "New User"
msgstr ""
@@ -16858,6 +17486,9 @@ msgstr ""
msgid "New tag"
msgstr ""
+msgid "New test case"
+msgstr ""
+
msgid "New users set to external"
msgstr ""
@@ -16930,7 +17561,7 @@ msgstr ""
msgid "No changes"
msgstr ""
-msgid "No changes between %{ref_start}%{source_branch}%{ref_end} and %{ref_start}%{target_branch}%{ref_end}"
+msgid "No changes between %{sourceBranch} and %{targetBranch}"
msgstr ""
msgid "No child epics match applied filters"
@@ -16945,6 +17576,9 @@ msgstr ""
msgid "No containers available"
msgstr ""
+msgid "No content to show"
+msgstr ""
+
msgid "No contributions"
msgstr ""
@@ -17020,9 +17654,6 @@ msgstr ""
msgid "No license. All rights reserved"
msgstr ""
-msgid "No licenses found."
-msgstr ""
-
msgid "No matches found"
msgstr ""
@@ -17035,6 +17666,9 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No members found"
+msgstr ""
+
msgid "No merge requests found"
msgstr ""
@@ -17056,6 +17690,9 @@ msgstr ""
msgid "No parent group"
msgstr ""
+msgid "No plan"
+msgstr ""
+
msgid "No pods available"
msgstr ""
@@ -17152,6 +17789,12 @@ msgstr ""
msgid "Not Implemented"
msgstr ""
+msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+msgstr ""
+
+msgid "Not all browsers support WebAuthn. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even from an unsupported browser."
+msgstr ""
+
msgid "Not all data has been processed yet, the accuracy of the chart for the selected timeframe is limited."
msgstr ""
@@ -17248,6 +17891,9 @@ msgstr ""
msgid "Notification settings saved"
msgstr ""
+msgid "NotificationEvent|Change reviewer merge request"
+msgstr ""
+
msgid "NotificationEvent|Close issue"
msgstr ""
@@ -17410,10 +18056,7 @@ msgstr ""
msgid "On track"
msgstr ""
-msgid "OnDemandScans|Attached branch"
-msgstr ""
-
-msgid "OnDemandScans|Attached branch is where the scan job runs."
+msgid "OnDemandScans|Could not fetch scanner profiles. Please refresh the page, or try again later."
msgstr ""
msgid "OnDemandScans|Could not fetch site profiles. Please refresh the page, or try again later."
@@ -17422,6 +18065,9 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
+msgid "OnDemandScans|Create a new scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Create a new site profile"
msgstr ""
@@ -17434,6 +18080,9 @@ msgstr ""
msgid "OnDemandScans|New on-demand DAST scan"
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 ""
@@ -17443,16 +18092,10 @@ msgstr ""
msgid "OnDemandScans|On-demand scans run outside the DevOps cycle and find vulnerabilities in your projects. %{learnMoreLinkStart}Learn more%{learnMoreLinkEnd}"
msgstr ""
-msgid "OnDemandScans|Only a passive scan can be performed on demand."
-msgstr ""
-
-msgid "OnDemandScans|Passive"
-msgstr ""
-
msgid "OnDemandScans|Run scan"
msgstr ""
-msgid "OnDemandScans|Scan mode"
+msgid "OnDemandScans|Scanner profile"
msgstr ""
msgid "OnDemandScans|Scanner settings"
@@ -17464,9 +18107,15 @@ msgstr ""
msgid "OnDemandScans|Select one of the existing profiles"
msgstr ""
+msgid "OnDemandScans|Site profile"
+msgstr ""
+
msgid "OnDemandScans|Site profiles"
msgstr ""
+msgid "OnDemandScans|Use existing scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Use existing site profile"
msgstr ""
@@ -17567,9 +18216,6 @@ msgstr ""
msgid "Open Selection"
msgstr ""
-msgid "Open Web IDE"
-msgstr ""
-
msgid "Open comment type dropdown"
msgstr ""
@@ -17675,6 +18321,9 @@ msgstr ""
msgid "Origin"
msgstr ""
+msgid "Orphaned member"
+msgstr ""
+
msgid "Other Labels"
msgstr ""
@@ -17690,6 +18339,9 @@ msgstr ""
msgid "Other visibility settings have been disabled by the administrator."
msgstr ""
+msgid "Our documentation includes an example DevOps Score report."
+msgstr ""
+
msgid "Out-of-compliance with this project's policies and should be removed"
msgstr ""
@@ -17714,6 +18366,9 @@ msgstr ""
msgid "Overwrite diverged branches"
msgstr ""
+msgid "Owned by %{image_tag}"
+msgstr ""
+
msgid "Owned by anyone"
msgstr ""
@@ -17735,6 +18390,9 @@ msgstr ""
msgid "Package deleted successfully"
msgstr ""
+msgid "Package file size limits"
+msgstr ""
+
msgid "Package recipe already exists"
msgstr ""
@@ -17750,9 +18408,6 @@ msgstr ""
msgid "Package type must be PyPi"
msgstr ""
-msgid "Package was removed"
-msgstr ""
-
msgid "PackageRegistry|%{name} version %{version} was created %{datetime}"
msgstr ""
@@ -17894,12 +18549,18 @@ msgstr ""
msgid "PackageRegistry|NuGet Command"
msgstr ""
+msgid "PackageRegistry|Package Registry"
+msgstr ""
+
msgid "PackageRegistry|Pip Command"
msgstr ""
msgid "PackageRegistry|Pipeline %{link} triggered %{datetime} by %{author}"
msgstr ""
+msgid "PackageRegistry|Publish and share packages for a variety of common package managers. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "PackageRegistry|Published to the %{project} Package Registry %{datetime}"
msgstr ""
@@ -17999,6 +18660,9 @@ msgstr ""
msgid "Page not found"
msgstr ""
+msgid "Page settings"
+msgstr ""
+
msgid "Page was successfully deleted"
msgstr ""
@@ -18140,7 +18804,7 @@ msgstr ""
msgid "Paste issue link"
msgstr ""
-msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Don't use your private SSH key."
+msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Do not paste your private SSH key, as that can compromise your identity."
msgstr ""
msgid "Patch to apply"
@@ -18167,6 +18831,9 @@ msgstr ""
msgid "Pending"
msgstr ""
+msgid "Pending comments"
+msgstr ""
+
msgid "People without permission will never get a notification and won't be able to comment."
msgstr ""
@@ -18365,6 +19032,9 @@ msgstr ""
msgid "Pipelines|Build with confidence"
msgstr ""
+msgid "Pipelines|By revoking a trigger you will break any processes making use of it. Are you sure?"
+msgstr ""
+
msgid "Pipelines|CI Lint"
msgstr ""
@@ -18377,6 +19047,15 @@ msgstr ""
msgid "Pipelines|Continuous Integration can help catch bugs by running your tests automatically, while Continuous Deployment can help you deliver code to your product environment."
msgstr ""
+msgid "Pipelines|Copy trigger token"
+msgstr ""
+
+msgid "Pipelines|Description"
+msgstr ""
+
+msgid "Pipelines|Edit"
+msgstr ""
+
msgid "Pipelines|Get started with Pipelines"
msgstr ""
@@ -18392,15 +19071,27 @@ msgstr ""
msgid "Pipelines|It is recommended the code is reviewed thoroughly before running this pipeline with the parent project's CI resource."
msgstr ""
+msgid "Pipelines|Last Used"
+msgstr ""
+
msgid "Pipelines|Loading Pipelines"
msgstr ""
msgid "Pipelines|More Information"
msgstr ""
+msgid "Pipelines|No triggers have been created yet. Add one using the form above."
+msgstr ""
+
+msgid "Pipelines|Owner"
+msgstr ""
+
msgid "Pipelines|Project cache successfully reset."
msgstr ""
+msgid "Pipelines|Revoke"
+msgstr ""
+
msgid "Pipelines|Run Pipeline"
msgstr ""
@@ -18425,6 +19116,15 @@ msgstr ""
msgid "Pipelines|This project is not currently set up to run pipelines."
msgstr ""
+msgid "Pipelines|Token"
+msgstr ""
+
+msgid "Pipelines|Trigger user has insufficient permissions to project"
+msgstr ""
+
+msgid "Pipelines|invalid"
+msgstr ""
+
msgid "Pipelines|parent"
msgstr ""
@@ -18683,10 +19383,10 @@ msgstr ""
msgid "Please provide attributes to update"
msgstr ""
-msgid "Please refer to %{docs_url}"
+msgid "Please reach out if you have any questions and we'll be happy to assist."
msgstr ""
-msgid "Please retype the email address."
+msgid "Please refer to %{docs_url}"
msgstr ""
msgid "Please select"
@@ -18716,6 +19416,9 @@ msgstr ""
msgid "Please set a new password before proceeding."
msgstr ""
+msgid "Please share your feedback about %{featureName} %{linkStart}in this issue%{linkEnd} to help us improve the experience."
+msgstr ""
+
msgid "Please solve the reCAPTCHA"
msgstr ""
@@ -19019,6 +19722,9 @@ msgstr ""
msgid "Profiles| You are going to change the username %{currentUsernameBold} to %{newUsernameBold}. Profile and projects will be redirected to the %{newUsername} namespace but this redirect will expire once the %{currentUsername} namespace is registered by another user or group. Please update your Git repository remotes as soon as possible."
msgstr ""
+msgid "Profiles|%{provider} Active"
+msgstr ""
+
msgid "Profiles|@username"
msgstr ""
@@ -19070,7 +19776,7 @@ msgstr ""
msgid "Profiles|Commit email"
msgstr ""
-msgid "Profiles|Connect"
+msgid "Profiles|Connect %{provider}"
msgstr ""
msgid "Profiles|Connected Accounts"
@@ -19094,6 +19800,9 @@ msgstr ""
msgid "Profiles|Disconnect"
msgstr ""
+msgid "Profiles|Disconnect %{provider}"
+msgstr ""
+
msgid "Profiles|Do not show on profile"
msgstr ""
@@ -19118,7 +19827,7 @@ msgstr ""
msgid "Profiles|Full name"
msgstr ""
-msgid "Profiles|Give your individual key a title. This will be publically visible."
+msgid "Profiles|Give your individual key a title."
msgstr ""
msgid "Profiles|Include private contributions on my profile"
@@ -19208,7 +19917,7 @@ msgstr ""
msgid "Profiles|The maximum file size allowed is 200KB."
msgstr ""
-msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it?"
+msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it? It will be publicly visible."
msgstr ""
msgid "Profiles|This email will be displayed on your public profile"
@@ -19283,6 +19992,9 @@ msgstr ""
msgid "Profiles|You don't have access to delete this user."
msgstr ""
+msgid "Profiles|You must transfer ownership or delete groups you are an owner of before you can delete your account"
+msgstr ""
+
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
@@ -19871,6 +20583,9 @@ msgstr ""
msgid "ProjectTemplates|GitLab Cluster Management"
msgstr ""
+msgid "ProjectTemplates|Gitpod/Spring Petclinic"
+msgstr ""
+
msgid "ProjectTemplates|Go Micro"
msgstr ""
@@ -20480,6 +21195,9 @@ msgstr ""
msgid "Publish to status page"
msgstr ""
+msgid "Published"
+msgstr ""
+
msgid "Published on status page"
msgstr ""
@@ -20597,9 +21315,15 @@ msgstr ""
msgid "Quick range"
msgstr ""
+msgid "Quickly and easily edit multiple files in your project."
+msgstr ""
+
msgid "README"
msgstr ""
+msgid "Rails"
+msgstr ""
+
msgid "Rake Tasks Help"
msgstr ""
@@ -20721,10 +21445,13 @@ msgstr ""
msgid "Register Two-Factor Authenticator"
msgstr ""
-msgid "Register U2F device"
+msgid "Register Universal Two-Factor (U2F) Device"
+msgstr ""
+
+msgid "Register WebAuthn Device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register device"
msgstr ""
msgid "Register for GitLab"
@@ -20736,9 +21463,6 @@ msgstr ""
msgid "Register with two-factor app"
msgstr ""
-msgid "Registration"
-msgstr ""
-
msgid "Registration|Checkout"
msgstr ""
@@ -20857,9 +21581,6 @@ msgstr ""
msgid "Release|Something went wrong while saving the release details"
msgstr ""
-msgid "Remediated: needs review"
-msgstr ""
-
msgid "Remediations"
msgstr ""
@@ -20965,6 +21686,9 @@ msgstr ""
msgid "Remove priority"
msgstr ""
+msgid "Remove report"
+msgstr ""
+
msgid "Remove secondary node"
msgstr ""
@@ -20977,6 +21701,12 @@ msgstr ""
msgid "Remove time estimate"
msgstr ""
+msgid "Remove user & report"
+msgstr ""
+
+msgid "Remove user from group"
+msgstr ""
+
msgid "Removed"
msgstr ""
@@ -21058,9 +21788,6 @@ msgstr ""
msgid "Removes time estimate."
msgstr ""
-msgid "Removing license…"
-msgstr ""
-
msgid "Removing this group also removes all child projects, including archived projects, and their resources."
msgstr ""
@@ -21145,6 +21872,9 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
+msgid "Reported by %{reporter}"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -21233,6 +21963,27 @@ msgstr ""
msgid "Repositories"
msgstr ""
+msgid "Repositories Analytics"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download Historic Test Coverage Data"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download historic test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Historic Test Coverage Data is available in raw format (.csv) for further analysis."
+msgstr ""
+
+msgid "RepositoriesAnalytics|Test Code Coverage"
+msgstr ""
+
+msgid "RepositoriesAnalytics|There was an error fetching the projects."
+msgstr ""
+
msgid "Repository"
msgstr ""
@@ -21311,9 +22062,15 @@ msgstr ""
msgid "Request parameter %{param} is missing."
msgstr ""
+msgid "Request review from"
+msgstr ""
+
msgid "Request to link SAML account must be authorized"
msgstr ""
+msgid "Requested"
+msgstr ""
+
msgid "Requested %{time_ago}"
msgstr ""
@@ -21332,6 +22089,9 @@ msgstr ""
msgid "Requests to these domain(s)/address(es) on the local network will be allowed when local requests from hooks and services are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 or 127.0.0.0/28 are supported. Domain wildcards are not supported currently. Use comma, semicolon, or newline to separate multiple entries. The allowlist can hold a maximum of 1000 entries. Domains should use IDNA encoding. Ex: example.com, 192.168.1.1, 127.0.0.0/28, xn--itlab-j1a.com."
msgstr ""
+msgid "Require admin approval for new sign-ups"
+msgstr ""
+
msgid "Require all users in this group to setup Two-factor authentication"
msgstr ""
@@ -21463,9 +22223,6 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
-msgid "Resolved by %{resolvedByName}"
-msgstr ""
-
msgid "Resolves IP addresses once and uses them to submit requests"
msgstr ""
@@ -21587,6 +22344,16 @@ msgstr ""
msgid "ReviewApp|Enable Review App"
msgstr ""
+msgid "Reviewer"
+msgid_plural "%d Reviewers"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
+msgid "Reviewer(s)"
+msgstr ""
+
msgid "Reviewing"
msgstr ""
@@ -21626,6 +22393,9 @@ msgstr ""
msgid "Rook"
msgstr ""
+msgid "Ruby"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -21704,6 +22474,63 @@ msgstr ""
msgid "Runners page."
msgstr ""
+msgid "Runners|Active"
+msgstr ""
+
+msgid "Runners|Architecture"
+msgstr ""
+
+msgid "Runners|Can run untagged jobs"
+msgstr ""
+
+msgid "Runners|Description"
+msgstr ""
+
+msgid "Runners|Group"
+msgstr ""
+
+msgid "Runners|IP Address"
+msgstr ""
+
+msgid "Runners|Last contact"
+msgstr ""
+
+msgid "Runners|Locked to this project"
+msgstr ""
+
+msgid "Runners|Maximum job timeout"
+msgstr ""
+
+msgid "Runners|Name"
+msgstr ""
+
+msgid "Runners|Platform"
+msgstr ""
+
+msgid "Runners|Property Name"
+msgstr ""
+
+msgid "Runners|Protected"
+msgstr ""
+
+msgid "Runners|Revision"
+msgstr ""
+
+msgid "Runners|Shared"
+msgstr ""
+
+msgid "Runners|Specific"
+msgstr ""
+
+msgid "Runners|Tags"
+msgstr ""
+
+msgid "Runners|Value"
+msgstr ""
+
+msgid "Runners|Version"
+msgstr ""
+
msgid "Runners|You have used %{quotaUsed} out of %{quotaLimit} of your shared Runners pipeline minutes."
msgstr ""
@@ -21716,6 +22543,9 @@ msgstr ""
msgid "Runs a number of housekeeping tasks within the current repository, such as compressing file revisions and removing unreachable objects."
msgstr ""
+msgid "SAML"
+msgstr ""
+
msgid "SAML SSO"
msgstr ""
@@ -21767,6 +22597,9 @@ msgstr ""
msgid "Save"
msgstr ""
+msgid "Save %{name} size limits"
+msgstr ""
+
msgid "Save Changes"
msgstr ""
@@ -21797,9 +22630,6 @@ msgstr ""
msgid "Save space and find tags in the Container Registry more easily. Enable the cleanup policy to remove stale tags and keep only the ones you need."
msgstr ""
-msgid "Save template"
-msgstr ""
-
msgid "Save variables"
msgstr ""
@@ -21842,9 +22672,6 @@ msgstr ""
msgid "Scope"
msgstr ""
-msgid "Scope not supported with disabled 'users_search' feature!"
-msgstr ""
-
msgid "Scoped issue boards"
msgstr ""
@@ -21971,9 +22798,6 @@ msgstr ""
msgid "Search requirements"
msgstr ""
-msgid "Search results…"
-msgstr ""
-
msgid "Search users"
msgstr ""
@@ -22052,6 +22876,13 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "SearchResults|epic"
+msgid_plural "SearchResults|epics"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "SearchResults|issue"
msgid_plural "SearchResults|issues"
msgstr[0] ""
@@ -22110,10 +22941,10 @@ msgstr ""
msgid "Seat Link is disabled, and cannot be configured through this form."
msgstr ""
-msgid "Seats currently in use"
+msgid "Seats usage data as of %{last_enqueue_time}"
msgstr ""
-msgid "Seats in license"
+msgid "Seats usage data is updated every day at 12:00pm UTC"
msgstr ""
msgid "Secondary"
@@ -22167,6 +22998,9 @@ msgstr ""
msgid "SecurityConfiguration|Available for on-demand DAST"
msgstr ""
+msgid "SecurityConfiguration|By default, all analyzers are applied in order to cover all languages across your project, and only run if the language is detected in the Merge Request."
+msgstr ""
+
msgid "SecurityConfiguration|Configure"
msgstr ""
@@ -22197,16 +23031,19 @@ msgstr ""
msgid "SecurityConfiguration|Manage"
msgstr ""
+msgid "SecurityConfiguration|More information"
+msgstr ""
+
msgid "SecurityConfiguration|Not enabled"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|Security Control"
+msgid "SecurityConfiguration|SAST Configuration"
msgstr ""
-msgid "SecurityConfiguration|See documentation"
+msgid "SecurityConfiguration|Security Control"
msgstr ""
msgid "SecurityConfiguration|Status"
@@ -22218,6 +23055,9 @@ msgstr ""
msgid "SecurityConfiguration|Using custom settings. You won't receive automatic updates on this variable. %{anchorStart}Restore to default%{anchorEnd}"
msgstr ""
+msgid "SecurityConfiguration|View history"
+msgstr ""
+
msgid "SecurityConfiguration|You can quickly enable all security scanning tools by enabling %{linkStart}Auto DevOps%{linkEnd}."
msgstr ""
@@ -22296,9 +23136,6 @@ msgstr ""
msgid "SecurityReports|Learn more about setting up your dashboard"
msgstr ""
-msgid "SecurityReports|Load more vulnerabilities"
-msgstr ""
-
msgid "SecurityReports|Monitor vulnerabilities in your code"
msgstr ""
@@ -22578,7 +23415,7 @@ msgstr ""
msgid "Select status"
msgstr ""
-msgid "Select strategy activation method"
+msgid "Select strategy activation method."
msgstr ""
msgid "Select subscription"
@@ -22593,7 +23430,7 @@ msgstr ""
msgid "Select the custom project template source group."
msgstr ""
-msgid "Select timeframe"
+msgid "Select the environment scope for this feature flag."
msgstr ""
msgid "Select timezone"
@@ -22842,6 +23679,9 @@ msgstr ""
msgid "Set iteration"
msgstr ""
+msgid "Set limit to 0 to allow any file size."
+msgstr ""
+
msgid "Set max session time for web terminal."
msgstr ""
@@ -22920,10 +23760,13 @@ msgstr ""
msgid "Set up a %{type} Runner manually"
msgstr ""
+msgid "Set up a hardware device as a second factor to sign in."
+msgstr ""
+
msgid "Set up assertions/attributes/claims (email, first_name, last_name) and NameID according to %{docsLinkStart}the documentation %{icon}%{docsLinkEnd}"
msgstr ""
-msgid "Set up new U2F device"
+msgid "Set up new device"
msgstr ""
msgid "Set up new password"
@@ -22992,6 +23835,9 @@ msgstr ""
msgid "Sets weight to %{weight}."
msgstr ""
+msgid "Setting this to 0 means using the system default timeout value."
+msgstr ""
+
msgid "Settings"
msgstr ""
@@ -23007,6 +23853,15 @@ msgstr ""
msgid "Severity"
msgstr ""
+msgid "SeverityWidget|Severity"
+msgstr ""
+
+msgid "SeverityWidget|Severity: %{severity}"
+msgstr ""
+
+msgid "SeverityWidget|There was an error while updating severity."
+msgstr ""
+
msgid "Shards (%{shards})"
msgstr ""
@@ -23052,6 +23907,9 @@ msgstr ""
msgid "Show all requirements."
msgstr ""
+msgid "Show all test cases."
+msgstr ""
+
msgid "Show archived projects"
msgstr ""
@@ -23064,6 +23922,9 @@ msgstr ""
msgid "Show comments"
msgstr ""
+msgid "Show comments on this file"
+msgstr ""
+
msgid "Show comments only"
msgstr ""
@@ -23109,6 +23970,12 @@ msgstr ""
msgid "Show parent subgroups"
msgstr ""
+msgid "Show the Closed list"
+msgstr ""
+
+msgid "Show the Open list"
+msgstr ""
+
msgid "Show whitespace changes"
msgstr ""
@@ -23156,9 +24023,6 @@ msgstr ""
msgid "Sidebar|Assign health status"
msgstr ""
-msgid "Sidebar|Change weight"
-msgstr ""
-
msgid "Sidebar|Health status"
msgstr ""
@@ -23342,6 +24206,9 @@ msgstr ""
msgid "Snippets|Add another file %{num}/%{total}"
msgstr ""
+msgid "Snippets|Authored %{time_ago} by %{author}"
+msgstr ""
+
msgid "Snippets|Delete file"
msgstr ""
@@ -23369,6 +24236,9 @@ msgstr ""
msgid "Solution"
msgstr ""
+msgid "Some changes are not shown"
+msgstr ""
+
msgid "Some child epics may be hidden due to applied filters"
msgstr ""
@@ -23735,6 +24605,12 @@ msgstr ""
msgid "Source (branch or tag)"
msgstr ""
+msgid "Source Branch"
+msgstr ""
+
+msgid "Source branch: %{source_branch_open}%{source_branch}%{source_branch_close}"
+msgstr ""
+
msgid "Source code"
msgstr ""
@@ -23900,9 +24776,6 @@ msgstr ""
msgid "Start and due date"
msgstr ""
-msgid "Start by choosing a group to see how your team is spending time. You can then drill down to the project level."
-msgstr ""
-
msgid "Start by choosing a group to start exploring the merge requests in that group. You can then proceed to filter by projects, labels, milestones and authors."
msgstr ""
@@ -23984,18 +24857,27 @@ msgstr ""
msgid "StaticSiteEditor|3. Assign a person to review and accept the merge request."
msgstr ""
+msgid "StaticSiteEditor|A link to view the merge request will appear once ready."
+msgstr ""
+
msgid "StaticSiteEditor|An error occurred while submitting your changes."
msgstr ""
msgid "StaticSiteEditor|Branch could not be created."
msgstr ""
+msgid "StaticSiteEditor|Copy update"
+msgstr ""
+
msgid "StaticSiteEditor|Could not commit the content changes."
msgstr ""
msgid "StaticSiteEditor|Could not create merge request."
msgstr ""
+msgid "StaticSiteEditor|Creating your merge request"
+msgstr ""
+
msgid "StaticSiteEditor|Incompatible file content"
msgstr ""
@@ -24017,6 +24899,9 @@ msgstr ""
msgid "StaticSiteEditor|View documentation"
msgstr ""
+msgid "StaticSiteEditor|You can set an assignee to get your changes reviewed and deployed once your merge request is created."
+msgstr ""
+
msgid "StaticSiteEditor|Your merge request has been created"
msgstr ""
@@ -24146,15 +25031,15 @@ msgstr ""
msgid "Submit %{humanized_resource_name}"
msgstr ""
-msgid "Submit Changes"
-msgstr ""
-
msgid "Submit a review"
msgstr ""
msgid "Submit as spam"
msgstr ""
+msgid "Submit changes"
+msgstr ""
+
msgid "Submit feedback"
msgstr ""
@@ -24308,6 +25193,9 @@ msgstr ""
msgid "Successfully deleted U2F device."
msgstr ""
+msgid "Successfully deleted WebAuthn device."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -24626,9 +25514,6 @@ msgstr ""
msgid "Template to append to all Service Desk issues"
msgstr ""
-msgid "Template was successfully saved."
-msgstr ""
-
msgid "Templates"
msgstr ""
@@ -24713,10 +25598,28 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "Test failed."
+msgid "Test settings"
+msgstr ""
+
+msgid "TestCases|New Test Case"
+msgstr ""
+
+msgid "TestCases|New test case"
+msgstr ""
+
+msgid "TestCases|Search test cases"
+msgstr ""
+
+msgid "TestCases|Something went wrong while creating a test case."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching count of test cases."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching test cases list."
msgstr ""
-msgid "Test settings and save changes"
+msgid "TestCases|Submit test case"
msgstr ""
msgid "TestHooks|Ensure one of your projects has merge requests."
@@ -24782,6 +25685,9 @@ msgstr ""
msgid "Thank you for signing up for your free trial! You will get additional instructions in your inbox shortly."
msgstr ""
+msgid "Thank you for your business."
+msgstr ""
+
msgid "Thank you for your feedback!"
msgstr ""
@@ -24843,9 +25749,6 @@ msgstr ""
msgid "The URL to use for connecting to Elasticsearch. Use a comma-separated list to support clustering (e.g., \"http://localhost:9200, http://localhost:9201\")."
msgstr ""
-msgid "The Web IDE offers advanced syntax highlighting capabilities and more."
-msgstr ""
-
msgid "The X509 Certificate to use when mutual TLS is required to communicate with the external authorization service. If left blank, the server certificate is still validated when accessing over HTTPS."
msgstr ""
@@ -24958,6 +25861,9 @@ msgstr ""
msgid "The form contains the following error:"
msgstr ""
+msgid "The form contains the following warning:"
+msgstr ""
+
msgid "The global settings require you to enable Two-Factor Authentication for your account."
msgstr ""
@@ -25072,9 +25978,6 @@ msgstr ""
msgid "The private key to use when a client certificate is provided. This value is encrypted at rest."
msgstr ""
-msgid "The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The project can be accessed by any logged in user."
msgstr ""
@@ -25111,7 +26014,7 @@ msgstr ""
msgid "The remote repository is being updated..."
msgstr ""
-msgid "The repository can be commited to, and issues, comments and other entities can be created."
+msgid "The repository can be committed to, and issues, comments and other entities can be created."
msgstr ""
msgid "The repository for this project does not exist."
@@ -25165,9 +26068,6 @@ msgstr ""
msgid "The time taken by each data entry gathered by that stage."
msgstr ""
-msgid "The total stage shows the time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The update action will time out after %{number_of_minutes} minutes. For big repositories, use a clone/push combination."
msgstr ""
@@ -25231,6 +26131,9 @@ msgstr ""
msgid "There are no archived requirements"
msgstr ""
+msgid "There are no archived test cases"
+msgstr ""
+
msgid "There are no changes"
msgstr ""
@@ -25270,6 +26173,9 @@ msgstr ""
msgid "There are no open requirements"
msgstr ""
+msgid "There are no open test cases"
+msgstr ""
+
msgid "There are no packages yet"
msgstr ""
@@ -25282,6 +26188,9 @@ msgstr ""
msgid "There is a limit of %{ci_project_subscriptions_limit} subscriptions from or to a project."
msgstr ""
+msgid "There is already a To-Do for this design."
+msgstr ""
+
msgid "There is already a repository with that name on disk"
msgstr ""
@@ -25300,6 +26209,9 @@ msgstr ""
msgid "There was a problem communicating with your device."
msgstr ""
+msgid "There was a problem fetching branches."
+msgstr ""
+
msgid "There was a problem fetching groups."
msgstr ""
@@ -25528,9 +26440,15 @@ msgstr ""
msgid "This action can lead to data loss. To prevent accidental actions we ask you to confirm your intention."
msgstr ""
+msgid "This action cannot be undone, and will permanently delete the %{key} SSH key"
+msgstr ""
+
msgid "This action cannot be undone. You will lose the project's repository and all content: issues, merge requests, etc."
msgstr ""
+msgid "This action has been performed too many times. Try again later."
+msgstr ""
+
msgid "This action will %{strongOpen}permanently delete%{strongClose} %{codeOpen}%{project}%{codeClose} %{strongOpen}immediately%{strongClose}, including its repositories and all content: issues, merge requests, etc."
msgstr ""
@@ -25558,9 +26476,6 @@ msgstr ""
msgid "This board's scope is reduced"
msgstr ""
-msgid "This branch has changed since you started editing. Would you like to create a new branch?"
-msgstr ""
-
msgid "This chart could not be displayed"
msgstr ""
@@ -25687,15 +26602,9 @@ msgstr ""
msgid "This is a security log of important events involving your account."
msgstr ""
-msgid "This is the author's first Merge Request to this project."
-msgstr ""
-
msgid "This is the highest peak of users on your installation since the license started."
msgstr ""
-msgid "This is the maximum number of users that have existed at the same time since the license started. This is the minimum number of seats you will need to buy when you renew your license."
-msgstr ""
-
msgid "This is the number of currently active users on your installation, and this is the minimum number you need to purchase when you renew your license."
msgstr ""
@@ -25927,6 +26836,15 @@ msgstr ""
msgid "This user has no identities"
msgstr ""
+msgid "This user has previously committed to the %{name} project."
+msgstr ""
+
+msgid "This user has the %{access} role in the %{name} project."
+msgstr ""
+
+msgid "This user is the author of this %{noteable}."
+msgstr ""
+
msgid "This user will be the author of all events in the activity feed that are the result of an update, like new branches being created or new commits being pushed to existing branches."
msgstr ""
@@ -25957,6 +26875,9 @@ msgstr ""
msgid "Threat Monitoring"
msgstr ""
+msgid "ThreatMonitoring|All Environments"
+msgstr ""
+
msgid "ThreatMonitoring|Anomalous Requests"
msgstr ""
@@ -25984,9 +26905,6 @@ msgstr ""
msgid "ThreatMonitoring|Operations Per Second"
msgstr ""
-msgid "ThreatMonitoring|Overview"
-msgstr ""
-
msgid "ThreatMonitoring|Packet Activity"
msgstr ""
@@ -26005,6 +26923,9 @@ msgstr ""
msgid "ThreatMonitoring|Something went wrong, unable to fetch statistics"
msgstr ""
+msgid "ThreatMonitoring|Statistics"
+msgstr ""
+
msgid "ThreatMonitoring|The firewall is not installed or has been disabled. To view this data, ensure the web application firewall is installed and enabled for your cluster."
msgstr ""
@@ -26400,6 +27321,9 @@ msgstr ""
msgid "To update Snippets with multiple files, you must use the `files` parameter"
msgstr ""
+msgid "To use Gitpod you must first enable the feature in the integrations section of your %{user_prefs}."
+msgstr ""
+
msgid "To view all %{scannedResourcesCount} scanned URLs, please download the CSV file"
msgstr ""
@@ -26433,9 +27357,6 @@ msgstr ""
msgid "Toggle Sidebar"
msgstr ""
-msgid "Toggle all threads"
-msgstr ""
-
msgid "Toggle backtrace"
msgstr ""
@@ -26460,9 +27381,6 @@ msgstr ""
msgid "Toggle navigation"
msgstr ""
-msgid "Toggle project"
-msgstr ""
-
msgid "Toggle sidebar"
msgstr ""
@@ -26502,6 +27420,9 @@ msgstr ""
msgid "Too many projects enabled. You will need to manage them via the console or the API."
msgstr ""
+msgid "Too much data"
+msgstr ""
+
msgid "Topics (optional)"
msgstr ""
@@ -26520,6 +27441,9 @@ msgstr ""
msgid "Total cores (CPUs)"
msgstr ""
+msgid "Total days to completion"
+msgstr ""
+
msgid "Total issues"
msgstr ""
@@ -26616,6 +27540,9 @@ msgstr ""
msgid "Trending"
msgstr ""
+msgid "Trials|Create a new group to start your GitLab Gold trial."
+msgstr ""
+
msgid "Trials|Go back to GitLab"
msgstr ""
@@ -26625,6 +27552,15 @@ msgstr ""
msgid "Trials|You can always resume this process by selecting your avatar and choosing 'Start a Gold trial'"
msgstr ""
+msgid "Trials|You can apply your trial to a new group or an existing group."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group or your personal account."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group, an existing group, or your personal account."
+msgstr ""
+
msgid "Trials|You won't get a free trial right now but you can always resume this process by clicking on your avatar and choosing 'Start a free trial'"
msgstr ""
@@ -26694,6 +27630,9 @@ msgstr ""
msgid "Try using a different search term to find the file you are looking for."
msgstr ""
+msgid "Trying to communicate with your device. Plug it in (if needed) and press the button on the device now."
+msgstr ""
+
msgid "Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now."
msgstr ""
@@ -26781,6 +27720,12 @@ msgstr ""
msgid "URL or request ID"
msgstr ""
+msgid "USER %{user} WILL BE REMOVED! Are you sure?"
+msgstr ""
+
+msgid "USER WILL BE BLOCKED! Are you sure?"
+msgstr ""
+
msgid "UTC"
msgstr ""
@@ -26838,9 +27783,6 @@ msgstr ""
msgid "Unable to load the merge request widget. Try reloading the page."
msgstr ""
-msgid "Unable to resolve"
-msgstr ""
-
msgid "Unable to save iteration. Please try again"
msgstr ""
@@ -26889,6 +27831,9 @@ msgstr ""
msgid "Undo ignore"
msgstr ""
+msgid "Unexpected error"
+msgstr ""
+
msgid "Unfortunately, your email message to GitLab could not be processed."
msgstr ""
@@ -26922,6 +27867,9 @@ msgstr ""
msgid "Unknown response text"
msgstr ""
+msgid "Unless otherwise agreed to in writing with GitLab, by clicking \"Upload License\" you agree that your use of GitLab Software is subject to the %{eula_link_start}Terms of Service%{eula_link_end}."
+msgstr ""
+
msgid "Unlimited"
msgstr ""
@@ -27288,9 +28236,6 @@ msgstr ""
msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
msgstr ""
-msgid "Use a hardware device to add the second factor of authentication."
-msgstr ""
-
msgid "Use an one time password authenticator on your mobile device or computer to enable two-factor authentication (2FA)."
msgstr ""
@@ -27564,13 +28509,13 @@ msgstr ""
msgid "Users"
msgstr ""
-msgid "Users in License:"
+msgid "Users in License"
msgstr ""
-msgid "Users or groups set as approvers in the project's or merge request's settings."
+msgid "Users in License:"
msgstr ""
-msgid "Users outside of license"
+msgid "Users or groups set as approvers in the project's or merge request's settings."
msgstr ""
msgid "Users over License:"
@@ -27588,9 +28533,6 @@ msgstr ""
msgid "Users with a Guest role or those who don't belong to a Project or Group will not use a seat from your license."
msgstr ""
-msgid "Users with a Guest role or those who don't belong to any projects or groups don't count towards seats in use."
-msgstr ""
-
msgid "UsersSelect|%{name} + %{length} more"
msgstr ""
@@ -27630,9 +28572,6 @@ msgstr ""
msgid "Validations failed."
msgstr ""
-msgid "Validity"
-msgstr ""
-
msgid "Value"
msgstr ""
@@ -27651,6 +28590,9 @@ msgstr ""
msgid "Value Stream Name"
msgstr ""
+msgid "ValueStreamAnalyticsStage|We don't have enough data to show this stage."
+msgstr ""
+
msgid "ValueStreamAnalytics|%{days}d"
msgstr ""
@@ -27911,6 +28853,9 @@ msgstr ""
msgid "VisualReviewApp|Steps 1 and 2 (and sometimes 3) are performed once by the developer before requesting feedback. Steps 3 (if necessary), 4 is performed by the reviewer each time they perform a review."
msgstr ""
+msgid "Visualization"
+msgstr ""
+
msgid "Vulnerabilities"
msgstr ""
@@ -27938,34 +28883,31 @@ msgstr ""
msgid "VulnerabilityChart|Severity"
msgstr ""
-msgid "VulnerabilityManagement|A true-positive and will fix"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Change status"
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|Confirm"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Confirmed %{timeago} by %{user}"
-msgstr ""
-
-msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Detected %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|A true-positive and will fix"
msgstr ""
-msgid "VulnerabilityManagement|Dismiss"
+msgid "VulnerabilityManagement|Change status"
msgstr ""
-msgid "VulnerabilityManagement|Dismissed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
msgstr ""
-msgid "VulnerabilityManagement|Resolved"
+msgid "VulnerabilityManagement|Detected"
msgstr ""
-msgid "VulnerabilityManagement|Resolved %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Needs triage"
msgstr ""
msgid "VulnerabilityManagement|Something went wrong while trying to delete the comment. Please try again later."
@@ -28016,6 +28958,9 @@ msgstr ""
msgid "Vulnerability|%{scannerName} (version %{scannerVersion})"
msgstr ""
+msgid "Vulnerability|Activity"
+msgstr ""
+
msgid "Vulnerability|Class"
msgstr ""
@@ -28028,6 +28973,9 @@ msgstr ""
msgid "Vulnerability|Description"
msgstr ""
+msgid "Vulnerability|Detected"
+msgstr ""
+
msgid "Vulnerability|Evidence"
msgstr ""
@@ -28091,6 +29039,9 @@ msgstr ""
msgid "Warning: Displaying this diagram might cause performance issues on this page."
msgstr ""
+msgid "We are currently unable to fetch data for the pipeline header."
+msgstr ""
+
msgid "We are currently unable to fetch data for this graph."
msgstr ""
@@ -28130,6 +29081,12 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
+msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
+msgstr ""
+
+msgid "We would like to inform you that your subscription GitLab Enterprise Edition %{plan_name} is nearing its user limit. You have %{active_user_count} active users, which is almost at the user limit of %{maximum_user_count}."
+msgstr ""
+
msgid "We've found no vulnerabilities"
msgstr ""
@@ -28145,6 +29102,12 @@ msgstr ""
msgid "Web terminal"
msgstr ""
+msgid "WebAuthn Devices (%{length})"
+msgstr ""
+
+msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
+msgstr ""
+
msgid "WebIDE|Merge request"
msgstr ""
@@ -28283,15 +29246,9 @@ msgstr ""
msgid "Welcome to the guided GitLab tour"
msgstr ""
-msgid "Welcome to your Issue Board!"
-msgstr ""
-
msgid "Welcome to your issue board!"
msgstr ""
-msgid "We’ve been making changes to %{featureName} and we’d love your feedback %{linkStart}in this issue%{linkEnd} to help us improve the experience."
-msgstr ""
-
msgid "What are you searching for?"
msgstr ""
@@ -28310,6 +29267,9 @@ msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
msgstr ""
+msgid "When enabled, any user visiting %{host} and creating an account will have to be explicitly approved by the admin before they can login. This setting is effective only if sign-ups are enabled."
+msgstr ""
+
msgid "When enabled, any user visiting %{host} will be able to create an account."
msgstr ""
@@ -28536,6 +29496,9 @@ msgstr ""
msgid "With requirements, you can set criteria to check your products against."
msgstr ""
+msgid "With test cases, you can define conditions for your project to meet in determining quality"
+msgstr ""
+
msgid "Withdraw Access Request"
msgstr ""
@@ -28551,6 +29514,9 @@ msgstr ""
msgid "Workflow Help"
msgstr ""
+msgid "Would you like to create a new branch?"
+msgstr ""
+
msgid "Write"
msgstr ""
@@ -28572,6 +29538,9 @@ msgstr ""
msgid "Wrong extern UID provided. Make sure Auth0 is configured correctly."
msgstr ""
+msgid "YYYY-MM-DD"
+msgstr ""
+
msgid "Yes"
msgstr ""
@@ -28629,7 +29598,7 @@ msgstr ""
msgid "You are going to remove the fork relationship from %{project_full_name}. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "You are going to transfer %{project_full_name} to another owner. Are you ABSOLUTELY sure?"
+msgid "You are going to transfer %{project_full_name} to another namespace. Are you ABSOLUTELY sure?"
msgstr ""
msgid "You are going to turn off the confidentiality. This means %{strongStart}everyone%{strongEnd} will be able to see and leave a comment on this %{issuableType}."
@@ -28689,9 +29658,6 @@ msgstr ""
msgid "You can always edit this later"
msgstr ""
-msgid "You can apply your Trial to your Personal account or create a New Group."
-msgstr ""
-
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings"
msgstr ""
@@ -28713,12 +29679,18 @@ msgstr ""
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
+msgid "You can find more information about GitLab subscriptions in %{subscriptions_doc_link}."
+msgstr ""
+
msgid "You can generate an access token scoped to this project for each application to use the GitLab API."
msgstr ""
msgid "You can get started by cloning the repository or start adding files to it with one of the following options."
msgstr ""
+msgid "You can group test cases using labels. To learn about the future direction of this feature, visit %{linkStart}Quality Management direction page%{linkEnd}."
+msgstr ""
+
msgid "You can invite a new member to %{project_name} or invite another group."
msgstr ""
@@ -28734,6 +29706,9 @@ msgstr ""
msgid "You can notify the app / group or a project by sending them an email notification"
msgstr ""
+msgid "You can now close this window."
+msgstr ""
+
msgid "You can now export your security dashboard to a CSV report."
msgstr ""
@@ -28782,9 +29757,6 @@ msgstr ""
msgid "You can test your .gitlab-ci.yml in %{linkStart}CI Lint%{linkEnd}."
msgstr ""
-msgid "You can try again using %{begin_link}basic search%{end_link}"
-msgstr ""
-
msgid "You cannot access the raw file. Please wait a minute."
msgstr ""
@@ -28836,6 +29808,9 @@ msgstr ""
msgid "You don't have any U2F devices registered yet."
msgstr ""
+msgid "You don't have any WebAuthn devices registered yet."
+msgstr ""
+
msgid "You don't have any active chat names."
msgstr ""
@@ -28923,6 +29898,9 @@ msgstr ""
msgid "You must accept our Terms of Service and privacy policy in order to register an account"
msgstr ""
+msgid "You must be logged in to search across all of GitLab"
+msgstr ""
+
msgid "You must disassociate %{domain} from all clusters it is attached to before deletion."
msgstr ""
@@ -28962,7 +29940,7 @@ msgstr ""
msgid "You need to be logged in."
msgstr ""
-msgid "You need to register a two-factor authentication app before you can set up a U2F device."
+msgid "You need to register a two-factor authentication app before you can set up a device."
msgstr ""
msgid "You need to set terms to be enforced"
@@ -28980,6 +29958,9 @@ msgstr ""
msgid "You reached %{usage_in_percent} of %{namespace_name}'s storage capacity (%{used_storage} of %{storage_limit})"
msgstr ""
+msgid "You successfully declined the invitation"
+msgstr ""
+
msgid "You tried to fork %{link_to_the_project} but it failed for the following reason:"
msgstr ""
@@ -29145,10 +30126,13 @@ msgstr ""
msgid "Your U2F device did not send a valid JSON response."
msgstr ""
-msgid "Your U2F device needs to be set up. Plug it in (if not already) and click the button on the left."
+msgid "Your U2F device was registered!"
msgstr ""
-msgid "Your U2F device was registered!"
+msgid "Your WebAuthn device did not send a valid JSON response."
+msgstr ""
+
+msgid "Your WebAuthn device was registered!"
msgstr ""
msgid "Your access request to the %{source_type} has been withdrawn."
@@ -29172,6 +30156,9 @@ msgstr ""
msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
msgstr ""
+msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
+msgstr ""
+
msgid "Your changes can be committed to %{branch_name} because a merge request is open."
msgstr ""
@@ -29208,6 +30195,12 @@ msgstr ""
msgid "Your deployment services will be broken, you will need to manually fix the services after renaming."
msgstr ""
+msgid "Your device is not compatible with GitLab. Please try another device"
+msgstr ""
+
+msgid "Your device needs to be set up. Plug it in (if needed) and click the button on the left."
+msgstr ""
+
msgid "Your device was successfully set up! Give it a name and register it with the GitLab server."
msgstr ""
@@ -29323,9 +30316,6 @@ msgstr[3] ""
msgid "access:"
msgstr ""
-msgid "activated"
-msgstr ""
-
msgid "added %{created_at_timeago}"
msgstr ""
@@ -29398,9 +30388,21 @@ msgstr ""
msgid "by %{user}"
msgstr ""
+msgid "cannot be a date in the past"
+msgstr ""
+
msgid "cannot be changed if a personal project has container registry tags."
msgstr ""
+msgid "cannot be changed if shared runners are enabled"
+msgstr ""
+
+msgid "cannot be enabled because parent group does not allow it"
+msgstr ""
+
+msgid "cannot be enabled because parent group has shared Runners disabled"
+msgstr ""
+
msgid "cannot be enabled unless all domains have TLS certificates"
msgstr ""
@@ -29446,7 +30448,7 @@ msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about SAST %{linkEndTag}"
msgstr ""
-msgid "ciReport|%{linkStartTag}Learn more about Secret Scanning %{linkEndTag}"
+msgid "ciReport|%{linkStartTag}Learn more about Secret Detection %{linkEndTag}"
msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about codequality reports %{linkEndTag}"
@@ -29767,9 +30769,6 @@ msgstr ""
msgid "error"
msgstr ""
-msgid "error code:"
-msgstr ""
-
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr ""
@@ -29791,6 +30790,9 @@ msgstr ""
msgid "failed to dismiss associated finding(id=%{finding_id}): %{message}"
msgstr ""
+msgid "failed to revert associated finding(id=%{finding_id}) to detected"
+msgstr ""
+
msgid "file"
msgid_plural "files"
msgstr[0] ""
@@ -30341,6 +31343,9 @@ msgstr ""
msgid "must be a root namespace"
msgstr ""
+msgid "must be a valid IPv4 or IPv6 address"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -30377,6 +31382,9 @@ msgstr ""
msgid "no expiration"
msgstr ""
+msgid "no name set"
+msgstr ""
+
msgid "no one can merge"
msgstr ""
@@ -30565,9 +31573,6 @@ msgstr ""
msgid "security Reports|There was an error creating the merge request"
msgstr ""
-msgid "settings saved, but not activated"
-msgstr ""
-
msgid "severity|Critical"
msgstr ""
@@ -30694,9 +31699,6 @@ msgstr ""
msgid "toggle collapse"
msgstr ""
-msgid "toggle dropdown"
-msgstr ""
-
msgid "triggered"
msgstr ""
@@ -30724,6 +31726,9 @@ msgstr ""
msgid "user avatar"
msgstr ""
+msgid "user preferences"
+msgstr ""
+
msgid "username"
msgstr ""
diff --git a/locale/sq_AL/gitlab.po b/locale/sq_AL/gitlab.po
index 446c8057633..b1b63eb174d 100644
--- a/locale/sq_AL/gitlab.po
+++ b/locale/sq_AL/gitlab.po
@@ -14,7 +14,10 @@ msgstr ""
"X-Crowdin-Language: sq\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 6\n"
-"PO-Revision-Date: 2020-09-04 23:10\n"
+"PO-Revision-Date: 2020-10-02 18:50\n"
+
+msgid " %{project_name}#%{issue_iid} &middot; opened %{issue_created} by %{author}"
+msgstr ""
msgid " %{start} to %{end}"
msgstr ""
@@ -74,6 +77,16 @@ msgstr ""
msgid "\"el\" parameter is required for createInstance()"
msgstr ""
+msgid "%d Approval"
+msgid_plural "%d Approvals"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d Package"
+msgid_plural "%d Packages"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d Scanned URL"
msgid_plural "%d Scanned URLs"
msgstr[0] ""
@@ -137,6 +150,11 @@ msgstr[1] ""
msgid "%d commits"
msgstr ""
+msgid "%d completed issue"
+msgid_plural "%d completed issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d contribution"
msgid_plural "%d contributions"
msgstr[0] ""
@@ -147,6 +165,11 @@ msgid_plural "%d days"
msgstr[0] ""
msgstr[1] ""
+msgid "%d day until tags are automatically removed"
+msgid_plural "%d days until tags are automatically removed"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d error"
msgid_plural "%d errors"
msgstr[0] ""
@@ -237,6 +260,16 @@ msgid_plural "%d more comments"
msgstr[0] ""
msgstr[1] ""
+msgid "%d open issue"
+msgid_plural "%d open issues"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d pending comment"
+msgid_plural "%d pending comments"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d personal project will be removed and cannot be restored."
msgid_plural "%d personal projects will be removed and cannot be restored."
msgstr[0] ""
@@ -252,6 +285,11 @@ msgid_plural "%d projects"
msgstr[0] ""
msgstr[1] ""
+msgid "%d project selected"
+msgid_plural "%d projects selected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d request with warnings"
msgid_plural "%d requests with warnings"
msgstr[0] ""
@@ -272,6 +310,11 @@ msgid_plural "%d tags"
msgstr[0] ""
msgstr[1] ""
+msgid "%d tag per image name"
+msgid_plural "%d tags per image name"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d unassigned issue"
msgid_plural "%d unassigned issues"
msgstr[0] ""
@@ -292,6 +335,11 @@ msgid_plural "%d vulnerabilities dismissed"
msgstr[0] ""
msgstr[1] ""
+msgid "%d warning found:"
+msgid_plural "%d warnings found:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%s additional commit has been omitted to prevent performance issues."
msgid_plural "%s additional commits have been omitted to prevent performance issues."
msgstr[0] ""
@@ -330,6 +378,9 @@ msgstr ""
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr ""
+msgid "%{completedCount} completed weight"
+msgstr ""
+
msgid "%{completedWeight} of %{totalWeight} weight completed"
msgstr ""
@@ -378,14 +429,12 @@ msgid_plural "%{count} participants"
msgstr[0] ""
msgstr[1] ""
-msgid "%{count} pending comment"
-msgid_plural "%{count} pending comments"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
+msgid "%{count} total weight"
+msgstr ""
+
msgid "%{dashboard_path} could not be found."
msgstr ""
@@ -440,6 +489,9 @@ msgstr ""
msgid "%{group_name} uses group managed accounts. You need to create a new GitLab account which will be managed by %{group_name}."
msgstr ""
+msgid "%{group_name}&%{epic_iid} &middot; opened %{epic_created} by %{author}"
+msgstr ""
+
msgid "%{host} sign-in from new location"
msgstr ""
@@ -452,7 +504,7 @@ msgstr ""
msgid "%{issuableType} will be removed! Are you sure?"
msgstr ""
-msgid "%{issuesSize} issues with a limit of %{maxIssueCount}"
+msgid "%{issuesCount} issues with a limit of %{maxIssueCount}"
msgstr ""
msgid "%{issuesSize} with a limit of %{maxIssueCount}"
@@ -485,7 +537,7 @@ msgstr ""
msgid "%{labelStart}Namespace:%{labelEnd} %{namespace}"
msgstr ""
-msgid "%{labelStart}Report Type:%{labelEnd} %{reportType}"
+msgid "%{labelStart}Scan Type:%{labelEnd} %{reportType}"
msgstr ""
msgid "%{labelStart}Scanner:%{labelEnd} %{scanner}"
@@ -682,9 +734,6 @@ msgid_plural "%{securityScanner} results are not available because a pipeline ha
msgstr[0] ""
msgstr[1] ""
-msgid "%{service_title} %{message}."
-msgstr ""
-
msgid "%{size} GiB"
msgstr ""
@@ -773,6 +822,12 @@ msgstr ""
msgid "%{timebox_name} should belong either to a project or a group."
msgstr ""
+msgid "%{timebox_type} does not support burnup charts"
+msgstr ""
+
+msgid "%{timebox_type} must have a start and due date"
+msgstr ""
+
msgid "%{title} %{operator} %{threshold}"
msgstr ""
@@ -797,7 +852,7 @@ msgstr ""
msgid "%{total} open issue weight"
msgstr ""
-msgid "%{total} open issues"
+msgid "%{total} warnings found: showing first %{warningsDisplayed}"
msgstr ""
msgid "%{usage_ping_link_start}Learn more%{usage_ping_link_end} about what information is shared with GitLab Inc."
@@ -830,9 +885,6 @@ msgstr ""
msgid "&lt; 1 hour"
msgstr ""
-msgid "&lt;no name set&gt;"
-msgstr ""
-
msgid "&lt;no scopes selected&gt;"
msgstr ""
@@ -863,6 +915,9 @@ msgstr ""
msgid "'%{name}' Value Stream created"
msgstr ""
+msgid "'%{name}' Value Stream deleted"
+msgstr ""
+
msgid "'%{name}' stage already exists"
msgstr ""
@@ -922,6 +977,9 @@ msgstr ""
msgid "+ %{numberOfHiddenAssignees} more"
msgstr ""
+msgid "+ %{numberOfHiddenReviewers} more"
+msgstr ""
+
msgid "+%d more"
msgid_plural "+%d more"
msgstr[0] ""
@@ -982,6 +1040,11 @@ msgid_plural "%d Days"
msgstr[0] ""
msgstr[1] ""
+msgid "1 Issue"
+msgid_plural "%d Issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "1 closed issue"
msgid_plural "%{issues} closed issues"
msgstr[0] ""
@@ -997,6 +1060,11 @@ msgid_plural "%d days"
msgstr[0] ""
msgstr[1] ""
+msgid "1 deploy key"
+msgid_plural "%d deploy keys"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1099,6 +1167,9 @@ msgstr ""
msgid ":%{startLine} to %{endLine}"
msgstr ""
+msgid "A %{incident_docs_start}modified issue%{incident_docs_end} to guide the resolution of incidents."
+msgstr ""
+
msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr ""
@@ -1111,6 +1182,9 @@ msgstr ""
msgid "A GitBook site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
+msgid "A Gitpod configured Webapplication in Spring and Java"
+msgstr ""
+
msgid "A Hexo site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
@@ -1282,9 +1356,15 @@ msgstr ""
msgid "Access expiration date"
msgstr ""
+msgid "Access expires"
+msgstr ""
+
msgid "Access forbidden. Check your access level."
msgstr ""
+msgid "Access granted"
+msgstr ""
+
msgid "Access requests"
msgstr ""
@@ -1294,6 +1374,9 @@ msgstr ""
msgid "Access to Pages websites are controlled based on the user's membership to a given project. By checking this box, users will be required to be logged in to have access to all Pages websites in your instance."
msgstr ""
+msgid "AccessDropdown|Deploy Keys"
+msgstr ""
+
msgid "AccessDropdown|Groups"
msgstr ""
@@ -1411,12 +1494,6 @@ msgstr ""
msgid "Active Sessions"
msgstr ""
-msgid "Active Users:"
-msgstr ""
-
-msgid "Active users"
-msgstr ""
-
msgid "Activity"
msgstr ""
@@ -1584,9 +1661,6 @@ msgstr ""
msgid "Add label(s)"
msgstr ""
-msgid "Add license"
-msgstr ""
-
msgid "Add list"
msgstr ""
@@ -1761,21 +1835,51 @@ msgstr ""
msgid "AdminArea|Bots"
msgstr ""
+msgid "AdminArea|Components"
+msgstr ""
+
msgid "AdminArea|Developer"
msgstr ""
+msgid "AdminArea|Features"
+msgstr ""
+
+msgid "AdminArea|Groups: %{number_of_groups}"
+msgstr ""
+
msgid "AdminArea|Guest"
msgstr ""
msgid "AdminArea|Included Free in license"
msgstr ""
+msgid "AdminArea|Latest groups"
+msgstr ""
+
+msgid "AdminArea|Latest projects"
+msgstr ""
+
+msgid "AdminArea|Latest users"
+msgstr ""
+
msgid "AdminArea|Maintainer"
msgstr ""
+msgid "AdminArea|New group"
+msgstr ""
+
+msgid "AdminArea|New project"
+msgstr ""
+
+msgid "AdminArea|New user"
+msgstr ""
+
msgid "AdminArea|Owner"
msgstr ""
+msgid "AdminArea|Projects: %{number_of_projects}"
+msgstr ""
+
msgid "AdminArea|Reporter"
msgstr ""
@@ -1803,6 +1907,9 @@ msgstr ""
msgid "AdminArea|Users without a Group and Project"
msgstr ""
+msgid "AdminArea|Users: %{number_of_users}"
+msgstr ""
+
msgid "AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running."
msgstr ""
@@ -1821,9 +1928,6 @@ msgstr ""
msgid "AdminProjects|Delete Project %{projectName}?"
msgstr ""
-msgid "AdminProjects|Delete project"
-msgstr ""
-
msgid "AdminSettings|Apply integration settings to all Projects"
msgstr ""
@@ -2061,21 +2165,30 @@ msgstr ""
msgid "AdminUsers|Without projects"
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 ""
msgid "AdminUsers|You cannot remove your own admin rights."
msgstr ""
+msgid "AdminUsers|You must transfer ownership or delete the groups owned by this user before you can delete their account"
+msgstr ""
+
msgid "Administration"
msgstr ""
msgid "Advanced"
msgstr ""
+msgid "Advanced Search"
+msgstr ""
+
+msgid "Advanced Search with Elasticsearch"
+msgstr ""
+
msgid "Advanced Settings"
msgstr ""
@@ -2153,6 +2266,9 @@ msgstr ""
msgid "AlertManagement|Edit"
msgstr ""
+msgid "AlertManagement|Environment"
+msgstr ""
+
msgid "AlertManagement|Events"
msgstr ""
@@ -2165,6 +2281,9 @@ msgstr ""
msgid "AlertManagement|Issue"
msgstr ""
+msgid "AlertManagement|Key"
+msgstr ""
+
msgid "AlertManagement|Low"
msgstr ""
@@ -2258,6 +2377,9 @@ msgstr ""
msgid "AlertManagement|Unknown"
msgstr ""
+msgid "AlertManagement|Value"
+msgstr ""
+
msgid "AlertManagement|View alerts in Opsgenie"
msgstr ""
@@ -2417,6 +2539,9 @@ msgstr ""
msgid "All projects"
msgstr ""
+msgid "All projects selected"
+msgstr ""
+
msgid "All security scans are enabled because %{linkStart}Auto DevOps%{linkEnd} is enabled on this project"
msgstr ""
@@ -2504,6 +2629,9 @@ msgstr ""
msgid "Almost there"
msgstr ""
+msgid "Already blocked"
+msgstr ""
+
msgid "Also called \"Issuer\" or \"Relying party trust identifier\""
msgstr ""
@@ -2558,6 +2686,9 @@ msgstr ""
msgid "An error has occurred"
msgstr ""
+msgid "An error occured while making the changes: %{error}"
+msgstr ""
+
msgid "An error occurred adding a draft to the thread."
msgstr ""
@@ -2585,12 +2716,6 @@ msgstr ""
msgid "An error occurred when toggling the notification subscription"
msgstr ""
-msgid "An error occurred when trying to resolve a comment. Please try again."
-msgstr ""
-
-msgid "An error occurred when trying to resolve a discussion. Please try again."
-msgstr ""
-
msgid "An error occurred when updating the issue weight"
msgstr ""
@@ -2606,12 +2731,6 @@ msgstr ""
msgid "An error occurred while checking group path. Please refresh and try again."
msgstr ""
-msgid "An error occurred while committing your changes."
-msgstr ""
-
-msgid "An error occurred while creating the list. Please try again."
-msgstr ""
-
msgid "An error occurred while decoding the file."
msgstr ""
@@ -2684,25 +2803,19 @@ msgstr ""
msgid "An error occurred while fetching the Service Desk address."
msgstr ""
-msgid "An error occurred while fetching the board issues. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the board lists. Please reload the page."
msgstr ""
msgid "An error occurred while fetching the board lists. Please try again."
msgstr ""
-msgid "An error occurred while fetching the board swimlanes. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the builds."
msgstr ""
msgid "An error occurred while fetching the job log."
msgstr ""
-msgid "An error occurred while fetching the job trace."
+msgid "An error occurred while fetching the job logs."
msgstr ""
msgid "An error occurred while fetching the job."
@@ -2849,9 +2962,6 @@ msgstr ""
msgid "An error occurred while saving assignees"
msgstr ""
-msgid "An error occurred while saving the template. Please check if the template exists."
-msgstr ""
-
msgid "An error occurred while searching for milestones"
msgstr ""
@@ -2870,10 +2980,10 @@ msgstr ""
msgid "An error occurred while updating approvers"
msgstr ""
-msgid "An error occurred while updating the comment"
+msgid "An error occurred while updating labels."
msgstr ""
-msgid "An error occurred while updating the list. Please try again."
+msgid "An error occurred while updating the comment"
msgstr ""
msgid "An error occurred while validating group path"
@@ -2927,6 +3037,9 @@ msgstr ""
msgid "An unknown error occurred while loading this graph."
msgstr ""
+msgid "An unknown error occurred."
+msgstr ""
+
msgid "Analytics"
msgstr ""
@@ -2960,10 +3073,10 @@ msgstr ""
msgid "Any"
msgstr ""
-msgid "Any Author"
+msgid "Any %{header}"
msgstr ""
-msgid "Any Status"
+msgid "Any Author"
msgstr ""
msgid "Any branch"
@@ -3017,6 +3130,9 @@ msgstr ""
msgid "Application ID"
msgstr ""
+msgid "Application limits saved successfully"
+msgstr ""
+
msgid "Application settings saved successfully"
msgstr ""
@@ -3226,6 +3342,9 @@ msgstr ""
msgid "Are you sure you want to close this blocked issue?"
msgstr ""
+msgid "Are you sure you want to delete \"%{name}\" Value Stream?"
+msgstr ""
+
msgid "Are you sure you want to delete %{name}?"
msgstr ""
@@ -3235,6 +3354,9 @@ msgstr ""
msgid "Are you sure you want to delete this %{typeOfComment}?"
msgstr ""
+msgid "Are you sure you want to delete this SSH key?"
+msgstr ""
+
msgid "Are you sure you want to delete this board?"
msgstr ""
@@ -3259,6 +3381,11 @@ msgstr ""
msgid "Are you sure you want to erase this build?"
msgstr ""
+msgid "Are you sure you want to import %d repository?"
+msgid_plural "Are you sure you want to import %d repositories?"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Are you sure you want to lose unsaved changes?"
msgstr ""
@@ -3268,15 +3395,15 @@ msgstr ""
msgid "Are you sure you want to merge immediately?"
msgstr ""
-msgid "Are you sure you want to permanently delete this license?"
-msgstr ""
-
msgid "Are you sure you want to re-deploy this environment?"
msgstr ""
msgid "Are you sure you want to regenerate the public key? You will have to update the public key on the remote server before mirroring will work again."
msgstr ""
+msgid "Are you sure you want to reindex?"
+msgstr ""
+
msgid "Are you sure you want to remove %{group_name}?"
msgstr ""
@@ -3304,6 +3431,9 @@ msgstr ""
msgid "Are you sure you want to revoke this nickname?"
msgstr ""
+msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
+msgstr ""
+
msgid "Are you sure you want to stop this environment?"
msgstr ""
@@ -3325,6 +3455,9 @@ msgstr ""
msgid "Are you sure? The device will be signed out of GitLab and all remember me tokens revoked."
msgstr ""
+msgid "Are you sure? This will invalidate your registered applications and U2F / WebAuthn devices."
+msgstr ""
+
msgid "Are you sure? This will invalidate your registered applications and U2F devices."
msgstr ""
@@ -3343,9 +3476,6 @@ msgstr ""
msgid "Artifacts"
msgstr ""
-msgid "As U2F devices are only supported by a few browsers, we require that you set up a two-factor authentication app before a U2F device. That way you'll always be able to log in - even when you're using an unsupported browser."
-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 ""
@@ -3539,6 +3669,9 @@ msgstr ""
msgid "AuditLogs|Target"
msgstr ""
+msgid "AuditLogs|This month"
+msgstr ""
+
msgid "AuditLogs|User Events"
msgstr ""
@@ -3578,6 +3711,9 @@ msgstr ""
msgid "Authentication via U2F device failed."
msgstr ""
+msgid "Authentication via WebAuthn device failed."
+msgstr ""
+
msgid "Author"
msgstr ""
@@ -3845,15 +3981,6 @@ msgstr ""
msgid "BambooService|You must set up automatic revision labeling and a repository trigger in Bamboo."
msgstr ""
-msgid "BatchComments|Delete all pending comments"
-msgstr ""
-
-msgid "BatchComments|Discard review?"
-msgstr ""
-
-msgid "BatchComments|You're about to discard your review which will delete all of your pending comments. The deleted comments %{strong_start}cannot%{strong_end} be restored."
-msgstr ""
-
msgid "Be careful. Changing the project's namespace can have unintended side effects."
msgstr ""
@@ -3875,6 +4002,9 @@ msgstr ""
msgid "Bi-weekly code coverage"
msgstr ""
+msgid "Billable Users:"
+msgstr ""
+
msgid "Billing"
msgstr ""
@@ -3884,7 +4014,7 @@ msgstr ""
msgid "BillingPlans|@%{user_name} you are currently using the %{plan_name} plan."
msgstr ""
-msgid "BillingPlans|Congratulations, your new trial is activated"
+msgid "BillingPlans|Congratulations, your free trial is activated."
msgstr ""
msgid "BillingPlans|If you would like to downgrade your plan please contact %{support_link_start}Customer Support%{support_link_end}."
@@ -3947,6 +4077,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Block user"
+msgstr ""
+
msgid "Blocked"
msgstr ""
@@ -3962,31 +4095,37 @@ msgstr ""
msgid "Blog"
msgstr ""
-msgid "Board name"
-msgstr ""
-
msgid "Board scope"
msgstr ""
msgid "Board scope affects which issues are displayed for anyone who visits this board"
msgstr ""
-msgid "BoardBlankState|Add default lists"
+msgid "Boards"
msgstr ""
-msgid "BoardBlankState|Add the following default lists to your Issue Board with one click:"
+msgid "Boards and Board Lists"
msgstr ""
-msgid "BoardBlankState|Nevermind, I'll use my own"
+msgid "Boards|An error occurred while creating the issue. Please try again."
msgstr ""
-msgid "BoardBlankState|Starting out with the default set of lists will get you right on the way to making the most of your board."
+msgid "Boards|An error occurred while creating the list. Please try again."
msgstr ""
-msgid "Boards"
+msgid "Boards|An error occurred while fetching issues. Please reload the page."
msgstr ""
-msgid "Boards and Board Lists"
+msgid "Boards|An error occurred while fetching the board issues. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching the board swimlanes. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while moving the issue. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while updating the list. Please try again."
msgstr ""
msgid "Boards|Collapse"
@@ -4013,7 +4152,7 @@ msgstr ""
msgid "Branch %{branch_name} was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr ""
-msgid "Branch has changed"
+msgid "Branch changed"
msgstr ""
msgid "Branch is already taken"
@@ -4319,6 +4458,9 @@ msgstr ""
msgid "CLOSED (MOVED)"
msgstr ""
+msgid "CODEOWNERS rule violation"
+msgstr ""
+
msgid "CONTRIBUTING"
msgstr ""
@@ -4349,9 +4491,6 @@ msgstr ""
msgid "Can't create snippet: %{err}"
msgstr ""
-msgid "Can't edit as source branch was deleted"
-msgstr ""
-
msgid "Can't fetch content for the blob: %{err}"
msgstr ""
@@ -4364,9 +4503,6 @@ msgstr ""
msgid "Can't load mermaid module: %{err}"
msgstr ""
-msgid "Can't remove group members without group managed account"
-msgstr ""
-
msgid "Can't scan the code?"
msgstr ""
@@ -4409,6 +4545,9 @@ msgstr ""
msgid "Cannot create the abuse report. This user has been blocked."
msgstr ""
+msgid "Cannot enable shared runners because parent group does not allow it"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -4514,6 +4653,15 @@ msgstr ""
msgid "Change your password or recover your current one"
msgstr ""
+msgid "ChangeReviewer|Reviewer changed from %{old} to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Reviewer changed to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Unassigned"
+msgstr ""
+
msgid "ChangeTypeActionLabel|Pick into branch"
msgstr ""
@@ -4553,6 +4701,9 @@ msgstr ""
msgid "Changes the title to \"%{title_param}\"."
msgstr ""
+msgid "Changes were successfully made."
+msgstr ""
+
msgid "Changes won't take place until the index is %{link_start}recreated%{link_end}."
msgstr ""
@@ -4958,6 +5109,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove variable"
+msgstr ""
+
msgid "CiVariables|Remove variable row"
msgstr ""
@@ -5036,9 +5190,6 @@ msgstr ""
msgid "Clear due date"
msgstr ""
-msgid "Clear input"
-msgstr ""
-
msgid "Clear recent searches"
msgstr ""
@@ -5087,6 +5238,9 @@ msgstr ""
msgid "Client authentication key password"
msgstr ""
+msgid "Client request timeout"
+msgstr ""
+
msgid "Clients"
msgstr ""
@@ -5171,6 +5325,27 @@ msgstr ""
msgid "Cluster type must be specificed for Stages::ClusterEndpointInserter"
msgstr ""
+msgid "ClusterAgents|Configuration"
+msgstr ""
+
+msgid "ClusterAgents|Connect your cluster with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate Kubernetes with a GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Name"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Agent also requires %{linkStart}enabling the Agent Server%{linkEnd}"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Kubernetes Agent allows an Infrastructure as Code, GitOps approach to integrating Kubernetes clusters with GitLab. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "ClusterAgent|This feature is only available for premium plans"
msgstr ""
@@ -5240,10 +5415,10 @@ msgstr ""
msgid "ClusterIntegration|All installed applications and related resources"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster."
+msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{linkStart}More information%{linkEnd}"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{startLink}More information%{endLink}"
+msgid "ClusterIntegration|Allow GitLab to manage namespaces and service accounts for this cluster."
msgstr ""
msgid "ClusterIntegration|Alternatively, "
@@ -5264,6 +5439,9 @@ msgstr ""
msgid "ClusterIntegration|An error occurred while trying to fetch zone machine types: %{error}"
msgstr ""
+msgid "ClusterIntegration|An unknown error occurred while attempting to connect to Kubernetes."
+msgstr ""
+
msgid "ClusterIntegration|Any project namespaces"
msgstr ""
@@ -5279,6 +5457,9 @@ msgstr ""
msgid "ClusterIntegration|Authenticate with Amazon Web Services"
msgstr ""
+msgid "ClusterIntegration|Authentication Error"
+msgstr ""
+
msgid "ClusterIntegration|Base domain"
msgstr ""
@@ -5297,13 +5478,22 @@ msgstr ""
msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}security group %{externalLinkIcon} %{endLink} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
+msgid "ClusterIntegration|Check your CA certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Check your cluster status"
+msgstr ""
+
+msgid "ClusterIntegration|Check your token"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}subnets %{externalLinkIcon} %{endLink} in your VPC where your worker nodes will run."
+msgid "ClusterIntegration|Choose the %{linkStart}security group %{linkEnd} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
msgstr ""
-msgid "ClusterIntegration|Choose the worker node %{startLink}instance type %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Choose the %{linkStart}subnets %{linkEnd} in your VPC where your worker nodes will run."
+msgstr ""
+
+msgid "ClusterIntegration|Choose the worker node %{linkStart}instance type%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Choose which applications to install on your Kubernetes cluster."
@@ -5315,10 +5505,7 @@ msgstr ""
msgid "ClusterIntegration|Clear cluster cache"
msgstr ""
-msgid "ClusterIntegration|Clear the local cache of namespace and service accounts. This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
-msgstr ""
-
-msgid "ClusterIntegration|Cluster being created"
+msgid "ClusterIntegration|Clear the local cache of namespace and service accounts."
msgstr ""
msgid "ClusterIntegration|Cluster management project (alpha)"
@@ -5330,15 +5517,21 @@ msgstr ""
msgid "ClusterIntegration|Cluster_applications artifact too big. Maximum allowable size: %{human_size}"
msgstr ""
-msgid "ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters."
+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|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}"
+msgid "ClusterIntegration|Clusters connected with a certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Connect cluster with certificate"
msgstr ""
msgid "ClusterIntegration|Connect existing cluster"
msgstr ""
+msgid "ClusterIntegration|Connection Error"
+msgstr ""
+
msgid "ClusterIntegration|Copy API URL"
msgstr ""
@@ -5414,6 +5607,12 @@ msgstr ""
msgid "ClusterIntegration|Deletes all GitLab resources attached to this cluster during removal"
msgstr ""
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared."
+msgstr ""
+
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared. %{linkStart}More information%{linkEnd}"
+msgstr ""
+
msgid "ClusterIntegration|Did you know?"
msgstr ""
@@ -5483,6 +5682,9 @@ msgstr ""
msgid "ClusterIntegration|Fluentd is an open source data collector, which lets you unify the data collection and consumption for a better use and understanding of data. It requires at least one of the following logs to be successfully installed."
msgstr ""
+msgid "ClusterIntegration|GitLab Agent managed clusters"
+msgstr ""
+
msgid "ClusterIntegration|GitLab Container Network Policies"
msgstr ""
@@ -5495,6 +5697,12 @@ msgstr ""
msgid "ClusterIntegration|GitLab Runner connects to the repository and executes CI/CD jobs, pushing results back and deploying applications to production."
msgstr ""
+msgid "ClusterIntegration|GitLab failed to authenticate."
+msgstr ""
+
+msgid "ClusterIntegration|GitLab failed to connect to the cluster."
+msgstr ""
+
msgid "ClusterIntegration|GitLab-managed cluster"
msgstr ""
@@ -5516,6 +5724,9 @@ msgstr ""
msgid "ClusterIntegration|Group cluster"
msgstr ""
+msgid "ClusterIntegration|HTTP Error"
+msgstr ""
+
msgid "ClusterIntegration|Helm Tiller"
msgstr ""
@@ -5549,7 +5760,10 @@ msgstr ""
msgid "ClusterIntegration|Instance type"
msgstr ""
-msgid "ClusterIntegration|Integrate Kubernetes cluster automation"
+msgid "ClusterIntegration|Integrate Kubernetes with a cluster certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Integrate with a cluster certificate"
msgstr ""
msgid "ClusterIntegration|Issuer Email"
@@ -5585,9 +5799,6 @@ msgstr ""
msgid "ClusterIntegration|Knative extends Kubernetes to provide a set of middleware components that are essential to build modern, source-centric, and container-based applications that can run anywhere: on premises, in the cloud, or even in a third-party data center."
msgstr ""
-msgid "ClusterIntegration|Kubernetes cluster"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes cluster is being created..."
msgstr ""
@@ -5600,9 +5811,6 @@ msgstr ""
msgid "ClusterIntegration|Kubernetes clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr ""
-msgid "ClusterIntegration|Kubernetes clusters can be used to deploy applications and to provide Review Apps for this project"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes version"
msgstr ""
@@ -5615,7 +5823,7 @@ msgstr ""
msgid "ClusterIntegration|Learn more about %{help_link_start}zones%{help_link_end}."
msgstr ""
-msgid "ClusterIntegration|Learn more about %{startLink}Regions %{externalLinkIcon}%{endLink}."
+msgid "ClusterIntegration|Learn more about %{linkStart}Regions%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Learn more about Kubernetes"
@@ -5660,12 +5868,18 @@ msgstr ""
msgid "ClusterIntegration|Machine type"
msgstr ""
+msgid "ClusterIntegration|Make sure your API endpoint is correct"
+msgstr ""
+
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create Kubernetes clusters"
msgstr ""
msgid "ClusterIntegration|Manage your Kubernetes cluster by visiting %{provider_link}"
msgstr ""
+msgid "ClusterIntegration|Namespace per environment"
+msgstr ""
+
msgid "ClusterIntegration|No IAM Roles found"
msgstr ""
@@ -5711,6 +5925,9 @@ msgstr ""
msgid "ClusterIntegration|No zones matched your search"
msgstr ""
+msgid "ClusterIntegration|Node calculations use the Kubernetes Metrics API. Make sure your cluster has metrics installed"
+msgstr ""
+
msgid "ClusterIntegration|Number of nodes"
msgstr ""
@@ -5753,6 +5970,9 @@ msgstr ""
msgid "ClusterIntegration|RBAC-enabled cluster"
msgstr ""
+msgid "ClusterIntegration|Read our %{linkStart}help page%{linkEnd} on Kubernetes cluster integration."
+msgstr ""
+
msgid "ClusterIntegration|Read our %{link_start}help page%{link_end} on Kubernetes cluster integration."
msgstr ""
@@ -5855,7 +6075,7 @@ msgstr ""
msgid "ClusterIntegration|Select a VPC to choose a subnet"
msgstr ""
-msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{linkStart}Amazon Web Services %{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select a network to choose a subnetwork"
@@ -5888,7 +6108,7 @@ msgstr ""
msgid "ClusterIntegration|Select project to choose zone"
msgstr ""
-msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select zone"
@@ -5978,9 +6198,18 @@ msgstr ""
msgid "ClusterIntegration|There was a problem authenticating with your cluster. Please ensure your CA Certificate and Token are valid."
msgstr ""
+msgid "ClusterIntegration|There was an HTTP error when connecting to your cluster."
+msgstr ""
+
msgid "ClusterIntegration|This account must have permissions to create a Kubernetes cluster in the %{link_to_container_project} specified below"
msgstr ""
+msgid "ClusterIntegration|This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
+msgstr ""
+
+msgid "ClusterIntegration|This is necessary to clear existing environment-namespace associations from clusters previously managed by GitLab."
+msgstr ""
+
msgid "ClusterIntegration|This option will allow you to install applications on RBAC clusters."
msgstr ""
@@ -6005,9 +6234,21 @@ msgstr ""
msgid "ClusterIntegration|To use a new project, first create one on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}."
msgstr ""
+msgid "ClusterIntegration|Troubleshooting tips:"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Authenticate"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Connect"
+msgstr ""
+
msgid "ClusterIntegration|Uninstall %{appTitle}"
msgstr ""
+msgid "ClusterIntegration|Unknown Error"
+msgstr ""
+
msgid "ClusterIntegration|Update %{appTitle}"
msgstr ""
@@ -6068,7 +6309,7 @@ msgstr ""
msgid "ClusterIntegration|Your cluster API is unreachable. Please ensure your API URL is correct."
msgstr ""
-msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Zone"
@@ -6188,6 +6429,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse all threads"
+msgstr ""
+
msgid "Collapse approvers"
msgstr ""
@@ -6337,7 +6581,7 @@ msgstr ""
msgid "Commit…"
msgstr ""
-msgid "Company"
+msgid "Community forum"
msgstr ""
msgid "Company name"
@@ -6346,6 +6590,9 @@ msgstr ""
msgid "Compare"
msgstr ""
+msgid "Compare %{oldCommitId}...%{newCommitId}"
+msgstr ""
+
msgid "Compare Git revisions"
msgstr ""
@@ -6361,6 +6608,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare submodule commit revisions"
+msgstr ""
+
msgid "Compare with previous version"
msgstr ""
@@ -6496,6 +6746,9 @@ msgstr ""
msgid "Configure the way a user creates a new account."
msgstr ""
+msgid "Configure which lists are shown for anyone who visits this board"
+msgstr ""
+
msgid "Confirm"
msgstr ""
@@ -6721,6 +6974,9 @@ msgstr[1] ""
msgid "ContainerRegistry|Set cleanup policy"
msgstr ""
+msgid "ContainerRegistry|Some tags were not deleted"
+msgstr ""
+
msgid "ContainerRegistry|Something went wrong while fetching the cleanup policy."
msgstr ""
@@ -6760,6 +7016,9 @@ msgstr ""
msgid "ContainerRegistry|Tags with names matching this regex pattern will %{italicStart}expire:%{italicEnd}"
msgstr ""
+msgid "ContainerRegistry|The cleanup policy timed out before it could delete all tags. An administrator can %{adminLinkStart}manually run cleanup now%{adminLinkEnd} or you can wait for the cleanup policy to automatically run again. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "ContainerRegistry|The last tag related to this image was recently removed. This empty image and any associated data will be automatically removed as part of the regular Garbage Collection process. If you have any questions, contact your administrator."
msgstr ""
@@ -6892,6 +7151,9 @@ msgstr ""
msgid "Contributions per group member"
msgstr ""
+msgid "Contributor"
+msgstr ""
+
msgid "Contributors"
msgstr ""
@@ -7021,6 +7283,9 @@ msgstr ""
msgid "Could not change HEAD: branch '%{branch}' does not exist"
msgstr ""
+msgid "Could not commit. An unexpected error occurred."
+msgstr ""
+
msgid "Could not connect to FogBugz, check your URL"
msgstr ""
@@ -7060,6 +7325,9 @@ msgstr ""
msgid "Could not find iteration"
msgstr ""
+msgid "Could not load instance counts. Please refresh the page to try again."
+msgstr ""
+
msgid "Could not remove the trigger."
msgstr ""
@@ -7084,10 +7352,10 @@ msgstr ""
msgid "Could not save prometheus manual configuration"
msgstr ""
-msgid "Could not udpdate wiki page"
+msgid "Could not update the LDAP settings"
msgstr ""
-msgid "Could not update the LDAP settings"
+msgid "Could not update wiki page"
msgstr ""
msgid "Could not upload your designs as one or more files uploaded are not supported."
@@ -7745,6 +8013,9 @@ msgstr ""
msgid "DastProfiles|Are you sure you want to delete this profile?"
msgstr ""
+msgid "DastProfiles|Could not create site validation token. Please refresh the page, or try again later."
+msgstr ""
+
msgid "DastProfiles|Could not create the scanner profile. Please try again."
msgstr ""
@@ -7769,6 +8040,12 @@ msgstr ""
msgid "DastProfiles|Could not fetch site profiles. Please refresh the page, or try again later."
msgstr ""
+msgid "DastProfiles|Could not retrieve site validation status. Please refresh the page, or try again later."
+msgstr ""
+
+msgid "DastProfiles|Could not update the scanner profile. Please try again."
+msgstr ""
+
msgid "DastProfiles|Could not update the site profile. Please try again."
msgstr ""
@@ -7784,7 +8061,7 @@ msgstr ""
msgid "DastProfiles|Download validation text file"
msgstr ""
-msgid "DastProfiles|Edit feature will come soon. Please create a new profile if changes needed"
+msgid "DastProfiles|Edit scanner profile"
msgstr ""
msgid "DastProfiles|Edit site profile"
@@ -7817,6 +8094,9 @@ msgstr ""
msgid "DastProfiles|No profiles created yet"
msgstr ""
+msgid "DastProfiles|Passive"
+msgstr ""
+
msgid "DastProfiles|Please enter a valid URL format, ex: http://www.example.com/home"
msgstr ""
@@ -7832,6 +8112,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan mode"
+msgstr ""
+
msgid "DastProfiles|Scanner Profile"
msgstr ""
@@ -7871,10 +8154,10 @@ msgstr ""
msgid "DastProfiles|Text file validation"
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
+msgid "DastProfiles|The maximum number of minutes allowed for the spider to traverse the site."
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the spider to traverse the site."
+msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
msgstr ""
msgid "DastProfiles|Validate"
@@ -7907,6 +8190,9 @@ msgstr ""
msgid "Date picker"
msgstr ""
+msgid "Date range"
+msgstr ""
+
msgid "Date range cannot exceed %{maxDateRange} days."
msgstr ""
@@ -7931,6 +8217,9 @@ msgstr ""
msgid "Days to merge"
msgstr ""
+msgid "Dear Administrator,"
+msgstr ""
+
msgid "Debug"
msgstr ""
@@ -8042,12 +8331,18 @@ msgstr ""
msgid "Delete"
msgstr ""
+msgid "Delete %{name}"
+msgstr ""
+
msgid "Delete Comment"
msgstr ""
msgid "Delete Snippet"
msgstr ""
+msgid "Delete Value Stream"
+msgstr ""
+
msgid "Delete account"
msgstr ""
@@ -8069,9 +8364,6 @@ msgstr ""
msgid "Delete label: %{label_name} ?"
msgstr ""
-msgid "Delete license"
-msgstr ""
-
msgid "Delete list"
msgstr ""
@@ -8147,15 +8439,6 @@ msgstr ""
msgid "Deleting a project places it into a read-only state until %{date}, at which point the project will be permanently deleted. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "Deleting the license failed."
-msgstr ""
-
-msgid "Deleting the license failed. The license was not found."
-msgstr ""
-
-msgid "Deleting the license failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "Deleting the project will delete its repository and all related resources including issues, merge requests etc."
msgstr ""
@@ -8651,7 +8934,10 @@ msgstr ""
msgid "DesignManagement|The maximum number of designs allowed to be uploaded is %{upload_limit}. Please try again."
msgstr ""
-msgid "DesignManagement|To upload designs, you'll need to enable LFS. %{requirements_link_start}More information%{requirements_link_end}"
+msgid "DesignManagement|There was an error moving your designs. Please upload your designs below."
+msgstr ""
+
+msgid "DesignManagement|To upload designs, you'll need to enable LFS and have admin enable hashed storage. %{requirements_link_start}More information%{requirements_link_end}"
msgstr ""
msgid "DesignManagement|Unresolve thread"
@@ -8663,6 +8949,9 @@ msgstr ""
msgid "DesignManagement|Upload skipped."
msgstr ""
+msgid "DesignManagement|Your designs are being copied and are on their way… Please refresh to update."
+msgstr ""
+
msgid "DesignManagement|and %{moreCount} more."
msgstr ""
@@ -8720,6 +9009,9 @@ msgstr ""
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
+msgid "Direct member"
+msgstr ""
+
msgid "Direction"
msgstr ""
@@ -8768,9 +9060,6 @@ msgstr ""
msgid "Discard draft"
msgstr ""
-msgid "Discard review"
-msgstr ""
-
msgid "DiscordService|Discord Notifications"
msgstr ""
@@ -8839,10 +9128,10 @@ msgstr ""
msgid "Dismiss Merge Request promotion"
msgstr ""
-msgid "Dismiss Selected"
+msgid "Dismiss Value Stream Analytics introduction box"
msgstr ""
-msgid "Dismiss Value Stream Analytics introduction box"
+msgid "Dismiss selected"
msgstr ""
msgid "Dismiss trial promotion"
@@ -8893,9 +9182,6 @@ msgstr ""
msgid "Documents reindexed: %{processed_documents} (%{percentage}%%)"
msgstr ""
-msgid "Doing"
-msgstr ""
-
msgid "Domain"
msgstr ""
@@ -9091,9 +9377,6 @@ msgstr ""
msgid "Edit environment"
msgstr ""
-msgid "Edit file"
-msgstr ""
-
msgid "Edit files in the editor and commit changes here"
msgstr ""
@@ -9106,6 +9389,12 @@ msgstr ""
msgid "Edit identity for %{user_name}"
msgstr ""
+msgid "Edit in Web IDE"
+msgstr ""
+
+msgid "Edit in single-file editor"
+msgstr ""
+
msgid "Edit issues"
msgstr ""
@@ -9133,10 +9422,10 @@ msgstr ""
msgid "Editing"
msgstr ""
-msgid "Elasticsearch"
+msgid "Elasticsearch AWS IAM credentials"
msgstr ""
-msgid "Elasticsearch AWS IAM credentials"
+msgid "Elasticsearch HTTP client timeout value in seconds."
msgstr ""
msgid "Elasticsearch indexing restrictions"
@@ -9145,9 +9434,6 @@ msgstr ""
msgid "Elasticsearch indexing started"
msgstr ""
-msgid "Elasticsearch integration. Elasticsearch AWS IAM."
-msgstr ""
-
msgid "Elasticsearch reindexing is already in progress"
msgstr ""
@@ -9175,9 +9461,6 @@ msgstr ""
msgid "Email Notification"
msgstr ""
-msgid "Email address"
-msgstr ""
-
msgid "Email could not be sent"
msgstr ""
@@ -9241,6 +9524,9 @@ msgstr ""
msgid "Emails sent from Service Desk will have this name"
msgstr ""
+msgid "Emails sent to %{email} will still be supported"
+msgstr ""
+
msgid "Emails separated by comma"
msgstr ""
@@ -9274,9 +9560,18 @@ msgstr ""
msgid "Enable"
msgstr ""
+msgid "Enable %{link_start}Gitpod%{link_end} integration to launch a development environment in your browser directly from GitLab."
+msgstr ""
+
msgid "Enable Auto DevOps"
msgstr ""
+msgid "Enable Gitpod"
+msgstr ""
+
+msgid "Enable Gitpod?"
+msgstr ""
+
msgid "Enable HTML emails"
msgstr ""
@@ -9406,9 +9701,6 @@ msgstr ""
msgid "Encountered an error while rendering: %{err}"
msgstr ""
-msgid "End date"
-msgstr ""
-
msgid "Ends at (UTC)"
msgstr ""
@@ -9568,7 +9860,7 @@ msgstr ""
msgid "EnvironmentsDashboard|The environments dashboard provides a summary of each project's environments' status, including pipeline and alert statuses."
msgstr ""
-msgid "EnvironmentsDashboard|This dashboard displays a maximum of 7 projects and 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
+msgid "EnvironmentsDashboard|This dashboard displays 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
msgstr ""
msgid "Environments|An error occurred while canceling the auto stop, please try again"
@@ -9889,6 +10181,9 @@ msgstr ""
msgid "Error deleting project. Check logs for error details."
msgstr ""
+msgid "Error fetching burnup chart data"
+msgstr ""
+
msgid "Error fetching diverging counts for branches. Please try again."
msgstr ""
@@ -9967,6 +10262,9 @@ msgstr ""
msgid "Error occurred when saving assignees"
msgstr ""
+msgid "Error occurred when saving reviewers"
+msgstr ""
+
msgid "Error occurred when toggling the notification subscription"
msgstr ""
@@ -10219,10 +10517,13 @@ msgstr ""
msgid "Expand all"
msgstr ""
-msgid "Expand approvers"
+msgid "Expand all files"
msgstr ""
-msgid "Expand dropdown"
+msgid "Expand all threads"
+msgstr ""
+
+msgid "Expand approvers"
msgstr ""
msgid "Expand milestones"
@@ -10393,6 +10694,9 @@ msgstr ""
msgid "Failed to create Merge Request. Please try again."
msgstr ""
+msgid "Failed to create To-Do for the design."
+msgstr ""
+
msgid "Failed to create a branch for this issue. Please try again."
msgstr ""
@@ -10432,6 +10736,12 @@ msgstr ""
msgid "Failed to load authors. Please try again."
msgstr ""
+msgid "Failed to load branches. Please try again."
+msgstr ""
+
+msgid "Failed to load deploy keys."
+msgstr ""
+
msgid "Failed to load emoji list."
msgstr ""
@@ -10447,6 +10757,9 @@ msgstr ""
msgid "Failed to load groups & users."
msgstr ""
+msgid "Failed to load groups, users and deploy keys."
+msgstr ""
+
msgid "Failed to load labels. Please try again."
msgstr ""
@@ -10456,6 +10769,12 @@ msgstr ""
msgid "Failed to load related branches"
msgstr ""
+msgid "Failed to load sidebar confidential toggle"
+msgstr ""
+
+msgid "Failed to load sidebar lock status"
+msgstr ""
+
msgid "Failed to load stacktrace."
msgstr ""
@@ -10483,6 +10802,9 @@ msgstr ""
msgid "Failed to publish issue on status page."
msgstr ""
+msgid "Failed to remove To-Do for the design."
+msgstr ""
+
msgid "Failed to remove a Zoom meeting"
msgstr ""
@@ -10525,6 +10847,9 @@ msgstr ""
msgid "Failed to signing using smartcard authentication"
msgstr ""
+msgid "Failed to toggle To-Do for the design."
+msgstr ""
+
msgid "Failed to update branch!"
msgstr ""
@@ -10638,7 +10963,7 @@ msgstr ""
msgid "FeatureFlags|Edit User List"
msgstr ""
-msgid "FeatureFlags|Enable features for specific users and specific environments by defining feature flag strategies."
+msgid "FeatureFlags|Enable features for specific users and environments by configuring feature flag strategies."
msgstr ""
msgid "FeatureFlags|Environment Spec"
@@ -10698,7 +11023,7 @@ msgstr ""
msgid "FeatureFlags|Include additional user IDs"
msgstr ""
-msgid "FeatureFlags|Install a %{docs_link_anchored_start}compatible client library%{docs_link_anchored_end} and specify the API URL, application name, and instance ID during the configuration setup. %{docs_link_start}More Information%{docs_link_end}"
+msgid "FeatureFlags|Install a %{docsLinkAnchoredStart}compatible client library%{docsLinkAnchoredEnd} and specify the API URL, application name, and instance ID during the configuration setup. %{docsLinkStart}More Information%{docsLinkEnd}"
msgstr ""
msgid "FeatureFlags|Instance ID"
@@ -10710,6 +11035,9 @@ msgstr ""
msgid "FeatureFlags|Loading feature flags"
msgstr ""
+msgid "FeatureFlags|Loading user lists"
+msgstr ""
+
msgid "FeatureFlags|More information"
msgstr ""
@@ -10728,7 +11056,7 @@ msgstr ""
msgid "FeatureFlags|New feature flag"
msgstr ""
-msgid "FeatureFlags|New list"
+msgid "FeatureFlags|New user list"
msgstr ""
msgid "FeatureFlags|Percent of users"
@@ -10767,6 +11095,9 @@ msgstr ""
msgid "FeatureFlags|There was an error fetching the feature flags."
msgstr ""
+msgid "FeatureFlags|There was an error fetching the user lists."
+msgstr ""
+
msgid "FeatureFlags|There was an error retrieving user lists"
msgstr ""
@@ -10782,6 +11113,9 @@ msgstr ""
msgid "FeatureFlags|User List"
msgstr ""
+msgid "FeatureFlags|User Lists"
+msgstr ""
+
msgid "FeatureFlag|List"
msgstr ""
@@ -10809,15 +11143,6 @@ msgstr ""
msgid "Fetching incoming email"
msgstr ""
-msgid "Fetching licenses failed."
-msgstr ""
-
-msgid "Fetching licenses failed. The request endpoint was not found."
-msgstr ""
-
-msgid "Fetching licenses failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "File"
msgstr ""
@@ -10920,12 +11245,21 @@ msgstr ""
msgid "Filter by status"
msgstr ""
+msgid "Filter by test cases that are currently archived."
+msgstr ""
+
+msgid "Filter by test cases that are currently opened."
+msgstr ""
+
msgid "Filter by two-factor authentication"
msgstr ""
msgid "Filter by user"
msgstr ""
+msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
+msgstr ""
+
msgid "Filter pipelines"
msgstr ""
@@ -10941,7 +11275,7 @@ msgstr ""
msgid "Filter results..."
msgstr ""
-msgid "Filter your projects by name"
+msgid "Filter your repositories by name"
msgstr ""
msgid "Filter..."
@@ -10950,7 +11284,7 @@ msgstr ""
msgid "Find File"
msgstr ""
-msgid "Find bugs in your code with coverage-guided fuzzing"
+msgid "Find bugs in your code with coverage-guided fuzzing."
msgstr ""
msgid "Find by path"
@@ -10977,9 +11311,6 @@ msgstr ""
msgid "Finish editing this message first!"
msgstr ""
-msgid "Finish review"
-msgstr ""
-
msgid "Finish setting up your dedicated account for %{group_name}."
msgstr ""
@@ -11049,6 +11380,9 @@ msgstr ""
msgid "Footer message"
msgstr ""
+msgid "For a faster browsing experience, some files are collapsed by default."
+msgstr ""
+
msgid "For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
@@ -11058,6 +11392,9 @@ msgstr ""
msgid "For more info, read the documentation."
msgstr ""
+msgid "For more information on how the number of active users is calculated, see the %{self_managed_subscriptions_doc_link} documentation."
+msgstr ""
+
msgid "For more information, go to the "
msgstr ""
@@ -11196,6 +11533,9 @@ msgstr ""
msgid "Generate new token"
msgstr ""
+msgid "Generic package file size in bytes"
+msgstr ""
+
msgid "Geo"
msgstr ""
@@ -11457,6 +11797,9 @@ msgstr ""
msgid "Geo|Please refer to Geo Troubleshooting."
msgstr ""
+msgid "Geo|Primary node"
+msgstr ""
+
msgid "Geo|Project"
msgstr ""
@@ -11499,6 +11842,9 @@ msgstr ""
msgid "Geo|Review replication status, and resynchronize and reverify items with the primary node."
msgstr ""
+msgid "Geo|Secondary node"
+msgstr ""
+
msgid "Geo|Status"
msgstr ""
@@ -11538,6 +11884,9 @@ msgstr ""
msgid "Geo|URL must be a valid url (ex: https://gitlab.com)"
msgstr ""
+msgid "Geo|Undefined"
+msgstr ""
+
msgid "Geo|Unknown state"
msgstr ""
@@ -11613,10 +11962,16 @@ msgstr ""
msgid "GitHub import"
msgstr ""
+msgid "GitLab"
+msgstr ""
+
msgid "GitLab / Unsubscribe"
msgstr ""
-msgid "GitLab Enterprise Edition %{plan}"
+msgid "GitLab API"
+msgstr ""
+
+msgid "GitLab Billing Team."
msgstr ""
msgid "GitLab Group Runners can execute code for all the projects in this group."
@@ -11628,12 +11983,18 @@ msgstr ""
msgid "GitLab Issue"
msgstr ""
+msgid "GitLab Pages"
+msgstr ""
+
msgid "GitLab Service Desk is a simple way to allow people to create issues in your GitLab instance without needing their own user account. It provides a unique email address for end users to create issues in a project, and replies can be sent either through the GitLab interface or by email. End users will only see the thread through email."
msgstr ""
msgid "GitLab Shared Runners execute code of different projects on the same Runner unless you configure GitLab Runner Autoscale with MaxBuilds 1 (which it is on GitLab.com)."
msgstr ""
+msgid "GitLab Shell"
+msgstr ""
+
msgid "GitLab Support Bot"
msgstr ""
@@ -11643,7 +12004,7 @@ msgstr ""
msgid "GitLab User"
msgstr ""
-msgid "GitLab allows you to continue using your license even if you exceed the number of seats you purchased. You will be required to pay for these seats when you renew your license."
+msgid "GitLab Workhorse"
msgstr ""
msgid "GitLab commit"
@@ -11811,6 +12172,21 @@ msgstr ""
msgid "Gitlab Pages"
msgstr ""
+msgid "Gitpod"
+msgstr ""
+
+msgid "Gitpod|Add the URL to your Gitpod instance configured to read your GitLab projects."
+msgstr ""
+
+msgid "Gitpod|Enable Gitpod integration"
+msgstr ""
+
+msgid "Gitpod|Gitpod URL"
+msgstr ""
+
+msgid "Gitpod|e.g. https://gitpod.example.com"
+msgstr ""
+
msgid "Given access %{time_ago}"
msgstr ""
@@ -12318,9 +12694,6 @@ msgstr ""
msgid "GroupSAML|Valid SAML Response"
msgstr ""
-msgid "GroupSAML|With group managed accounts enabled, all the users without a group managed account will be excluded from the group."
-msgstr ""
-
msgid "GroupSAML|With prohibit outer forks flag enabled group members will be able to fork project only inside your group."
msgstr ""
@@ -12534,10 +12907,10 @@ msgstr ""
msgid "GroupsNew|Create group"
msgstr ""
-msgid "GroupsNew|GitLab group export"
+msgid "GroupsNew|Import"
msgstr ""
-msgid "GroupsNew|Import"
+msgid "GroupsNew|Import a GitLab group export file"
msgstr ""
msgid "GroupsNew|Import group"
@@ -12680,6 +13053,9 @@ msgid_plural "Hide charts"
msgstr[0] ""
msgstr[1] ""
+msgid "Hide comments on this file"
+msgstr ""
+
msgid "Hide details"
msgstr ""
@@ -12724,6 +13100,15 @@ msgstr ""
msgid "Highest role:"
msgstr ""
+msgid "HighlightBar|Alert events:"
+msgstr ""
+
+msgid "HighlightBar|Alert start time:"
+msgstr ""
+
+msgid "HighlightBar|Original alert:"
+msgstr ""
+
msgid "History"
msgstr ""
@@ -12901,6 +13286,9 @@ msgstr ""
msgid "If enabled, access to projects will be validated on an external service using their classification label."
msgstr ""
+msgid "If the number of active users exceeds the user limit, you will be charged for the number of %{users_over_license_link} at your next license reconciliation."
+msgstr ""
+
msgid "If there is no previous license or if the previous license has expired, some GitLab functionality will be blocked until a new, valid license is uploaded."
msgstr ""
@@ -12940,9 +13328,6 @@ msgstr ""
msgid "If your HTTP repository is not publicly accessible, add your credentials."
msgstr ""
-msgid "Iglu registry URL (optional)"
-msgstr ""
-
msgid "Ignore"
msgstr ""
@@ -12979,6 +13364,16 @@ msgstr ""
msgid "Import"
msgstr ""
+msgid "Import %d compatible repository"
+msgid_plural "Import %d compatible repositories"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Import %d repository"
+msgid_plural "Import %d repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Import CSV"
msgstr ""
@@ -12988,15 +13383,9 @@ msgstr ""
msgid "Import all compatible projects"
msgstr ""
-msgid "Import all compatible repositories"
-msgstr ""
-
msgid "Import all projects"
msgstr ""
-msgid "Import all repositories"
-msgstr ""
-
msgid "Import an exported GitLab project"
msgstr ""
@@ -13084,6 +13473,9 @@ msgstr ""
msgid "ImportProjects|Error importing repository %{project_safe_import_url} into %{project_full_path} - %{message}"
msgstr ""
+msgid "ImportProjects|Import repositories"
+msgstr ""
+
msgid "ImportProjects|Importing the project failed"
msgstr ""
@@ -13096,7 +13488,7 @@ msgstr ""
msgid "ImportProjects|Requesting your %{provider} repositories failed"
msgstr ""
-msgid "ImportProjects|Select the projects you want to import"
+msgid "ImportProjects|Select the repositories you want to import"
msgstr ""
msgid "ImportProjects|The remote data could not be imported."
@@ -13132,9 +13524,6 @@ msgstr ""
msgid "In order to enable Service Desk for your instance, you must first set up incoming email."
msgstr ""
-msgid "In order to gather accurate feature usage data, it can take 1 to 2 weeks to see your index."
-msgstr ""
-
msgid "In order to personalize your experience with GitLab%{br_tag}we would like to know a bit more about you."
msgstr ""
@@ -13165,18 +13554,30 @@ msgstr ""
msgid "IncidentManagement|Create incident"
msgstr ""
+msgid "IncidentManagement|Critical - S1"
+msgstr ""
+
msgid "IncidentManagement|Date created"
msgstr ""
msgid "IncidentManagement|Display your incidents in a dedicated view"
msgstr ""
+msgid "IncidentManagement|High - S2"
+msgstr ""
+
msgid "IncidentManagement|Incident"
msgstr ""
msgid "IncidentManagement|Incidents"
msgstr ""
+msgid "IncidentManagement|Low - S4"
+msgstr ""
+
+msgid "IncidentManagement|Medium - S3"
+msgstr ""
+
msgid "IncidentManagement|No incidents to display."
msgstr ""
@@ -13189,6 +13590,9 @@ msgstr ""
msgid "IncidentManagement|Published to status page"
msgstr ""
+msgid "IncidentManagement|Severity"
+msgstr ""
+
msgid "IncidentManagement|There are no closed incidents"
msgstr ""
@@ -13198,6 +13602,9 @@ msgstr ""
msgid "IncidentManagement|Unassigned"
msgstr ""
+msgid "IncidentManagement|Unknown"
+msgstr ""
+
msgid "IncidentManagement|Unpublished"
msgstr ""
@@ -13219,6 +13626,15 @@ msgstr ""
msgid "Incidents"
msgstr ""
+msgid "Incident|Alert details"
+msgstr ""
+
+msgid "Incident|Summary"
+msgstr ""
+
+msgid "Incident|There was an issue loading alert data. Please try again."
+msgstr ""
+
msgid "Include a Terms of Service agreement and Privacy Policy that all users must accept."
msgstr ""
@@ -13279,6 +13695,9 @@ msgstr ""
msgid "Information about additional Pages templates and how to install them can be found in our %{pages_getting_started_guide}."
msgstr ""
+msgid "Inherited"
+msgstr ""
+
msgid "Inherited:"
msgstr ""
@@ -13359,7 +13778,22 @@ msgstr ""
msgid "Instance administrators group already exists"
msgstr ""
-msgid "Instance license"
+msgid "InstanceStatistics|Groups"
+msgstr ""
+
+msgid "InstanceStatistics|Issues"
+msgstr ""
+
+msgid "InstanceStatistics|Merge Requests"
+msgstr ""
+
+msgid "InstanceStatistics|Pipelines"
+msgstr ""
+
+msgid "InstanceStatistics|Projects"
+msgstr ""
+
+msgid "InstanceStatistics|Users"
msgstr ""
msgid "Integration"
@@ -13371,6 +13805,12 @@ msgstr ""
msgid "Integrations"
msgstr ""
+msgid "Integrations|%{integration} settings saved and active."
+msgstr ""
+
+msgid "Integrations|%{integration} settings saved, but not active."
+msgstr ""
+
msgid "Integrations|All details"
msgstr ""
@@ -13380,6 +13820,12 @@ msgstr ""
msgid "Integrations|Comment settings:"
msgstr ""
+msgid "Integrations|Connection failed. Please check your settings."
+msgstr ""
+
+msgid "Integrations|Connection successful."
+msgstr ""
+
msgid "Integrations|Default settings are inherited from the group level."
msgstr ""
@@ -13395,6 +13841,15 @@ msgstr ""
msgid "Integrations|Includes commit title and branch"
msgstr ""
+msgid "Integrations|Projects using custom settings will not be impacted unless the project owner chooses to use instance-level defaults."
+msgstr ""
+
+msgid "Integrations|Save settings?"
+msgstr ""
+
+msgid "Integrations|Saving will update the default settings for all projects that are not using custom settings."
+msgstr ""
+
msgid "Integrations|Standard"
msgstr ""
@@ -13527,6 +13982,9 @@ msgstr ""
msgid "Invitation"
msgstr ""
+msgid "Invitation declined"
+msgstr ""
+
msgid "Invite"
msgstr ""
@@ -13578,6 +14036,42 @@ 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|%{linkStart}Read more%{linkEnd} about role permissions"
+msgstr ""
+
+msgid "InviteMembersModal|Access expiration date (optional)"
+msgstr ""
+
+msgid "InviteMembersModal|Cancel"
+msgstr ""
+
+msgid "InviteMembersModal|Choose a role permission"
+msgstr ""
+
+msgid "InviteMembersModal|GitLab member or Email address"
+msgstr ""
+
+msgid "InviteMembersModal|Invite"
+msgstr ""
+
+msgid "InviteMembersModal|Invite team members"
+msgstr ""
+
+msgid "InviteMembersModal|Search for members to invite"
+msgstr ""
+
+msgid "InviteMembersModal|User not invited. Feature coming soon!"
+msgstr ""
+
+msgid "InviteMembersModal|Users were succesfully added"
+msgstr ""
+
+msgid "InviteMembersModal|You're inviting members to the %{group_name} group"
+msgstr ""
+
+msgid "InviteMembers|Invite team members"
+msgstr ""
+
msgid "Invited"
msgstr ""
@@ -13632,10 +14126,13 @@ msgstr ""
msgid "Issue cannot be found."
msgstr ""
+msgid "Issue created from vulnerability %{vulnerability_link}"
+msgstr ""
+
msgid "Issue events"
msgstr ""
-msgid "Issue first depoloyed to production"
+msgid "Issue first deployed to production"
msgstr ""
msgid "Issue label"
@@ -13713,6 +14210,9 @@ msgstr ""
msgid "IssueTracker|Custom issue tracker"
msgstr ""
+msgid "IssueTracker|EWM work items tracker"
+msgstr ""
+
msgid "IssueTracker|Redmine issue tracker"
msgstr ""
@@ -13779,6 +14279,9 @@ msgstr ""
msgid "It looks like you have some draft commits in this branch."
msgstr ""
+msgid "It may be several days before you see feature usage data."
+msgstr ""
+
msgid "It must have a header row and at least two columns: the first column is the issue title and the second column is the issue description. The separator is automatically detected."
msgstr ""
@@ -14061,13 +14564,13 @@ msgstr ""
msgid "Join Zoom meeting"
msgstr ""
-msgid "Jul"
+msgid "Joined %{time_ago}"
msgstr ""
-msgid "July"
+msgid "Jul"
msgstr ""
-msgid "Jump to first unresolved thread"
+msgid "July"
msgstr ""
msgid "Jump to next unresolved thread"
@@ -14103,6 +14606,9 @@ msgstr ""
msgid "Keyboard shortcuts"
msgstr ""
+msgid "KeyboardKey|Ctrl+"
+msgstr ""
+
msgid "Keys"
msgstr ""
@@ -14151,6 +14657,9 @@ msgstr ""
msgid "LDAP Synchronization"
msgstr ""
+msgid "LDAP group settings"
+msgstr ""
+
msgid "LDAP settings"
msgstr ""
@@ -14160,6 +14669,9 @@ msgstr ""
msgid "LDAP sync in progress. This could take a few minutes. Refresh the page to see the changes."
msgstr ""
+msgid "LDAP synchronizations"
+msgstr ""
+
msgid "LFS"
msgstr ""
@@ -14240,7 +14752,16 @@ msgid_plural "Last %d days"
msgstr[0] ""
msgstr[1] ""
-msgid "Last %{days} days"
+msgid "Last 2 weeks"
+msgstr ""
+
+msgid "Last 30 days"
+msgstr ""
+
+msgid "Last 60 days"
+msgstr ""
+
+msgid "Last 90 days"
msgstr ""
msgid "Last Accessed On"
@@ -14318,6 +14839,9 @@ msgstr ""
msgid "Last used on:"
msgstr ""
+msgid "Last week"
+msgstr ""
+
msgid "LastCommit|authored"
msgstr ""
@@ -14333,6 +14857,9 @@ msgstr ""
msgid "Latest pipeline for the most recent commit on this branch"
msgstr ""
+msgid "Launch a ready-to-code development environment for your project."
+msgstr ""
+
msgid "Lead"
msgstr ""
@@ -14713,6 +15240,9 @@ msgstr ""
msgid "List of all merge commits"
msgstr ""
+msgid "List options"
+msgstr ""
+
msgid "List settings"
msgstr ""
@@ -14725,9 +15255,6 @@ msgstr ""
msgid "List your Bitbucket Server repositories"
msgstr ""
-msgid "Lists"
-msgstr ""
-
msgid "Live preview"
msgstr ""
@@ -14974,6 +15501,12 @@ msgstr ""
msgid "Mark as done"
msgstr ""
+msgid "Mark as draft"
+msgstr ""
+
+msgid "Mark as ready"
+msgstr ""
+
msgid "Mark as resolved"
msgstr ""
@@ -14995,6 +15528,24 @@ msgstr ""
msgid "Markdown is supported"
msgstr ""
+msgid "MarkdownEditor|Add a link (%{modifierKey}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add a link (%{modifier_key}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifierKey}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifier_key}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifierKey}I)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifier_key}I)"
+msgstr ""
+
msgid "Marked For Deletion At - %{deletion_time}"
msgstr ""
@@ -15079,7 +15630,25 @@ msgstr ""
msgid "Max access level"
msgstr ""
-msgid "Max seats used"
+msgid "Max role"
+msgstr ""
+
+msgid "Max size 15 MB"
+msgstr ""
+
+msgid "Maximum Conan package file size in bytes"
+msgstr ""
+
+msgid "Maximum Maven package file size in bytes"
+msgstr ""
+
+msgid "Maximum NPM package file size in bytes"
+msgstr ""
+
+msgid "Maximum NuGet package file size in bytes"
+msgstr ""
+
+msgid "Maximum PyPI package file size in bytes"
msgstr ""
msgid "Maximum Users:"
@@ -15211,6 +15780,18 @@ msgstr ""
msgid "Members with access to %{strong_start}%{group_name}%{strong_end}"
msgstr ""
+msgid "Members|%{time} by %{user}"
+msgstr ""
+
+msgid "Members|Expired"
+msgstr ""
+
+msgid "Members|No expiration set"
+msgstr ""
+
+msgid "Members|in %{time}"
+msgstr ""
+
msgid "Memory Usage"
msgstr ""
@@ -15397,9 +15978,6 @@ msgstr ""
msgid "MergeRequests|Thread will be unresolved"
msgstr ""
-msgid "MergeRequests|Toggle comments for this file"
-msgstr ""
-
msgid "MergeRequests|View file @ %{commitId}"
msgstr ""
@@ -15460,6 +16038,9 @@ msgstr ""
msgid "Merging immediately isn't recommended as it may negatively impact the existing merge train. Read the %{docsLinkStart}documentation%{docsLinkEnd} for more information."
msgstr ""
+msgid "Message"
+msgstr ""
+
msgid "Messages"
msgstr ""
@@ -15845,18 +16426,12 @@ msgid_plural "Milestones"
msgstr[0] ""
msgstr[1] ""
-msgid "Milestone does not support burnup charts"
-msgstr ""
-
msgid "Milestone lists not available with your current license"
msgstr ""
msgid "Milestone lists show all issues from the selected milestone."
msgstr ""
-msgid "Milestone must have a start and due date"
-msgstr ""
-
msgid "MilestoneSidebar|Closed:"
msgstr ""
@@ -16223,6 +16798,9 @@ msgstr ""
msgid "Namespace"
msgstr ""
+msgid "Namespace ID:"
+msgstr ""
+
msgid "Namespace is empty"
msgstr ""
@@ -16307,6 +16885,9 @@ msgstr ""
msgid "NetworkPolicies|Allow all outbound traffic from %{selector} to %{ruleSelector} on %{ports}"
msgstr ""
+msgid "NetworkPolicies|Are you sure you want to delete this policy? This action cannot be undone."
+msgstr ""
+
msgid "NetworkPolicies|Choose whether to enforce this policy."
msgstr ""
@@ -16316,12 +16897,21 @@ msgstr ""
msgid "NetworkPolicies|Define this policy's location, conditions and actions."
msgstr ""
+msgid "NetworkPolicies|Delete policy"
+msgstr ""
+
+msgid "NetworkPolicies|Delete policy: %{policy}"
+msgstr ""
+
msgid "NetworkPolicies|Deny all traffic"
msgstr ""
msgid "NetworkPolicies|Description"
msgstr ""
+msgid "NetworkPolicies|Edit policy"
+msgstr ""
+
msgid "NetworkPolicies|Editor mode"
msgstr ""
@@ -16349,6 +16939,9 @@ msgstr ""
msgid "NetworkPolicies|Name"
msgstr ""
+msgid "NetworkPolicies|Namespace"
+msgstr ""
+
msgid "NetworkPolicies|Network Policy"
msgstr ""
@@ -16400,6 +16993,9 @@ msgstr ""
msgid "NetworkPolicies|Rules"
msgstr ""
+msgid "NetworkPolicies|Save changes"
+msgstr ""
+
msgid "NetworkPolicies|Something went wrong, failed to update policy"
msgstr ""
@@ -16412,6 +17008,9 @@ msgstr ""
msgid "NetworkPolicies|Traffic that does not match any rule will be blocked."
msgstr ""
+msgid "NetworkPolicies|Unable to parse policy"
+msgstr ""
+
msgid "NetworkPolicies|YAML editor"
msgstr ""
@@ -16525,6 +17124,9 @@ msgstr ""
msgid "New Snippet"
msgstr ""
+msgid "New Test Case"
+msgstr ""
+
msgid "New User"
msgstr ""
@@ -16624,6 +17226,9 @@ msgstr ""
msgid "New tag"
msgstr ""
+msgid "New test case"
+msgstr ""
+
msgid "New users set to external"
msgstr ""
@@ -16696,7 +17301,7 @@ msgstr ""
msgid "No changes"
msgstr ""
-msgid "No changes between %{ref_start}%{source_branch}%{ref_end} and %{ref_start}%{target_branch}%{ref_end}"
+msgid "No changes between %{sourceBranch} and %{targetBranch}"
msgstr ""
msgid "No child epics match applied filters"
@@ -16711,6 +17316,9 @@ msgstr ""
msgid "No containers available"
msgstr ""
+msgid "No content to show"
+msgstr ""
+
msgid "No contributions"
msgstr ""
@@ -16786,9 +17394,6 @@ msgstr ""
msgid "No license. All rights reserved"
msgstr ""
-msgid "No licenses found."
-msgstr ""
-
msgid "No matches found"
msgstr ""
@@ -16801,6 +17406,9 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No members found"
+msgstr ""
+
msgid "No merge requests found"
msgstr ""
@@ -16822,6 +17430,9 @@ msgstr ""
msgid "No parent group"
msgstr ""
+msgid "No plan"
+msgstr ""
+
msgid "No pods available"
msgstr ""
@@ -16918,6 +17529,12 @@ msgstr ""
msgid "Not Implemented"
msgstr ""
+msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+msgstr ""
+
+msgid "Not all browsers support WebAuthn. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even from an unsupported browser."
+msgstr ""
+
msgid "Not all data has been processed yet, the accuracy of the chart for the selected timeframe is limited."
msgstr ""
@@ -17014,6 +17631,9 @@ msgstr ""
msgid "Notification settings saved"
msgstr ""
+msgid "NotificationEvent|Change reviewer merge request"
+msgstr ""
+
msgid "NotificationEvent|Close issue"
msgstr ""
@@ -17176,10 +17796,7 @@ msgstr ""
msgid "On track"
msgstr ""
-msgid "OnDemandScans|Attached branch"
-msgstr ""
-
-msgid "OnDemandScans|Attached branch is where the scan job runs."
+msgid "OnDemandScans|Could not fetch scanner profiles. Please refresh the page, or try again later."
msgstr ""
msgid "OnDemandScans|Could not fetch site profiles. Please refresh the page, or try again later."
@@ -17188,6 +17805,9 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
+msgid "OnDemandScans|Create a new scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Create a new site profile"
msgstr ""
@@ -17200,6 +17820,9 @@ msgstr ""
msgid "OnDemandScans|New on-demand DAST scan"
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 ""
@@ -17209,16 +17832,10 @@ msgstr ""
msgid "OnDemandScans|On-demand scans run outside the DevOps cycle and find vulnerabilities in your projects. %{learnMoreLinkStart}Learn more%{learnMoreLinkEnd}"
msgstr ""
-msgid "OnDemandScans|Only a passive scan can be performed on demand."
-msgstr ""
-
-msgid "OnDemandScans|Passive"
-msgstr ""
-
msgid "OnDemandScans|Run scan"
msgstr ""
-msgid "OnDemandScans|Scan mode"
+msgid "OnDemandScans|Scanner profile"
msgstr ""
msgid "OnDemandScans|Scanner settings"
@@ -17230,9 +17847,15 @@ msgstr ""
msgid "OnDemandScans|Select one of the existing profiles"
msgstr ""
+msgid "OnDemandScans|Site profile"
+msgstr ""
+
msgid "OnDemandScans|Site profiles"
msgstr ""
+msgid "OnDemandScans|Use existing scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Use existing site profile"
msgstr ""
@@ -17331,9 +17954,6 @@ msgstr ""
msgid "Open Selection"
msgstr ""
-msgid "Open Web IDE"
-msgstr ""
-
msgid "Open comment type dropdown"
msgstr ""
@@ -17439,6 +18059,9 @@ msgstr ""
msgid "Origin"
msgstr ""
+msgid "Orphaned member"
+msgstr ""
+
msgid "Other Labels"
msgstr ""
@@ -17454,6 +18077,9 @@ msgstr ""
msgid "Other visibility settings have been disabled by the administrator."
msgstr ""
+msgid "Our documentation includes an example DevOps Score report."
+msgstr ""
+
msgid "Out-of-compliance with this project's policies and should be removed"
msgstr ""
@@ -17478,6 +18104,9 @@ msgstr ""
msgid "Overwrite diverged branches"
msgstr ""
+msgid "Owned by %{image_tag}"
+msgstr ""
+
msgid "Owned by anyone"
msgstr ""
@@ -17499,6 +18128,9 @@ msgstr ""
msgid "Package deleted successfully"
msgstr ""
+msgid "Package file size limits"
+msgstr ""
+
msgid "Package recipe already exists"
msgstr ""
@@ -17514,9 +18146,6 @@ msgstr ""
msgid "Package type must be PyPi"
msgstr ""
-msgid "Package was removed"
-msgstr ""
-
msgid "PackageRegistry|%{name} version %{version} was created %{datetime}"
msgstr ""
@@ -17658,12 +18287,18 @@ msgstr ""
msgid "PackageRegistry|NuGet Command"
msgstr ""
+msgid "PackageRegistry|Package Registry"
+msgstr ""
+
msgid "PackageRegistry|Pip Command"
msgstr ""
msgid "PackageRegistry|Pipeline %{link} triggered %{datetime} by %{author}"
msgstr ""
+msgid "PackageRegistry|Publish and share packages for a variety of common package managers. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "PackageRegistry|Published to the %{project} Package Registry %{datetime}"
msgstr ""
@@ -17763,6 +18398,9 @@ msgstr ""
msgid "Page not found"
msgstr ""
+msgid "Page settings"
+msgstr ""
+
msgid "Page was successfully deleted"
msgstr ""
@@ -17904,7 +18542,7 @@ msgstr ""
msgid "Paste issue link"
msgstr ""
-msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Don't use your private SSH key."
+msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Do not paste your private SSH key, as that can compromise your identity."
msgstr ""
msgid "Patch to apply"
@@ -17931,6 +18569,9 @@ msgstr ""
msgid "Pending"
msgstr ""
+msgid "Pending comments"
+msgstr ""
+
msgid "People without permission will never get a notification and won't be able to comment."
msgstr ""
@@ -18129,6 +18770,9 @@ msgstr ""
msgid "Pipelines|Build with confidence"
msgstr ""
+msgid "Pipelines|By revoking a trigger you will break any processes making use of it. Are you sure?"
+msgstr ""
+
msgid "Pipelines|CI Lint"
msgstr ""
@@ -18141,6 +18785,15 @@ msgstr ""
msgid "Pipelines|Continuous Integration can help catch bugs by running your tests automatically, while Continuous Deployment can help you deliver code to your product environment."
msgstr ""
+msgid "Pipelines|Copy trigger token"
+msgstr ""
+
+msgid "Pipelines|Description"
+msgstr ""
+
+msgid "Pipelines|Edit"
+msgstr ""
+
msgid "Pipelines|Get started with Pipelines"
msgstr ""
@@ -18156,15 +18809,27 @@ msgstr ""
msgid "Pipelines|It is recommended the code is reviewed thoroughly before running this pipeline with the parent project's CI resource."
msgstr ""
+msgid "Pipelines|Last Used"
+msgstr ""
+
msgid "Pipelines|Loading Pipelines"
msgstr ""
msgid "Pipelines|More Information"
msgstr ""
+msgid "Pipelines|No triggers have been created yet. Add one using the form above."
+msgstr ""
+
+msgid "Pipelines|Owner"
+msgstr ""
+
msgid "Pipelines|Project cache successfully reset."
msgstr ""
+msgid "Pipelines|Revoke"
+msgstr ""
+
msgid "Pipelines|Run Pipeline"
msgstr ""
@@ -18189,6 +18854,15 @@ msgstr ""
msgid "Pipelines|This project is not currently set up to run pipelines."
msgstr ""
+msgid "Pipelines|Token"
+msgstr ""
+
+msgid "Pipelines|Trigger user has insufficient permissions to project"
+msgstr ""
+
+msgid "Pipelines|invalid"
+msgstr ""
+
msgid "Pipelines|parent"
msgstr ""
@@ -18447,10 +19121,10 @@ msgstr ""
msgid "Please provide attributes to update"
msgstr ""
-msgid "Please refer to %{docs_url}"
+msgid "Please reach out if you have any questions and we'll be happy to assist."
msgstr ""
-msgid "Please retype the email address."
+msgid "Please refer to %{docs_url}"
msgstr ""
msgid "Please select"
@@ -18480,6 +19154,9 @@ msgstr ""
msgid "Please set a new password before proceeding."
msgstr ""
+msgid "Please share your feedback about %{featureName} %{linkStart}in this issue%{linkEnd} to help us improve the experience."
+msgstr ""
+
msgid "Please solve the reCAPTCHA"
msgstr ""
@@ -18783,6 +19460,9 @@ msgstr ""
msgid "Profiles| You are going to change the username %{currentUsernameBold} to %{newUsernameBold}. Profile and projects will be redirected to the %{newUsername} namespace but this redirect will expire once the %{currentUsername} namespace is registered by another user or group. Please update your Git repository remotes as soon as possible."
msgstr ""
+msgid "Profiles|%{provider} Active"
+msgstr ""
+
msgid "Profiles|@username"
msgstr ""
@@ -18834,7 +19514,7 @@ msgstr ""
msgid "Profiles|Commit email"
msgstr ""
-msgid "Profiles|Connect"
+msgid "Profiles|Connect %{provider}"
msgstr ""
msgid "Profiles|Connected Accounts"
@@ -18858,6 +19538,9 @@ msgstr ""
msgid "Profiles|Disconnect"
msgstr ""
+msgid "Profiles|Disconnect %{provider}"
+msgstr ""
+
msgid "Profiles|Do not show on profile"
msgstr ""
@@ -18882,7 +19565,7 @@ msgstr ""
msgid "Profiles|Full name"
msgstr ""
-msgid "Profiles|Give your individual key a title. This will be publically visible."
+msgid "Profiles|Give your individual key a title."
msgstr ""
msgid "Profiles|Include private contributions on my profile"
@@ -18972,7 +19655,7 @@ msgstr ""
msgid "Profiles|The maximum file size allowed is 200KB."
msgstr ""
-msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it?"
+msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it? It will be publicly visible."
msgstr ""
msgid "Profiles|This email will be displayed on your public profile"
@@ -19047,6 +19730,9 @@ msgstr ""
msgid "Profiles|You don't have access to delete this user."
msgstr ""
+msgid "Profiles|You must transfer ownership or delete groups you are an owner of before you can delete your account"
+msgstr ""
+
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
@@ -19635,6 +20321,9 @@ msgstr ""
msgid "ProjectTemplates|GitLab Cluster Management"
msgstr ""
+msgid "ProjectTemplates|Gitpod/Spring Petclinic"
+msgstr ""
+
msgid "ProjectTemplates|Go Micro"
msgstr ""
@@ -20244,6 +20933,9 @@ msgstr ""
msgid "Publish to status page"
msgstr ""
+msgid "Published"
+msgstr ""
+
msgid "Published on status page"
msgstr ""
@@ -20361,9 +21053,15 @@ msgstr ""
msgid "Quick range"
msgstr ""
+msgid "Quickly and easily edit multiple files in your project."
+msgstr ""
+
msgid "README"
msgstr ""
+msgid "Rails"
+msgstr ""
+
msgid "Rake Tasks Help"
msgstr ""
@@ -20483,10 +21181,13 @@ msgstr ""
msgid "Register Two-Factor Authenticator"
msgstr ""
-msgid "Register U2F device"
+msgid "Register Universal Two-Factor (U2F) Device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register WebAuthn Device"
+msgstr ""
+
+msgid "Register device"
msgstr ""
msgid "Register for GitLab"
@@ -20498,9 +21199,6 @@ msgstr ""
msgid "Register with two-factor app"
msgstr ""
-msgid "Registration"
-msgstr ""
-
msgid "Registration|Checkout"
msgstr ""
@@ -20617,9 +21315,6 @@ msgstr ""
msgid "Release|Something went wrong while saving the release details"
msgstr ""
-msgid "Remediated: needs review"
-msgstr ""
-
msgid "Remediations"
msgstr ""
@@ -20725,6 +21420,9 @@ msgstr ""
msgid "Remove priority"
msgstr ""
+msgid "Remove report"
+msgstr ""
+
msgid "Remove secondary node"
msgstr ""
@@ -20737,6 +21435,12 @@ msgstr ""
msgid "Remove time estimate"
msgstr ""
+msgid "Remove user & report"
+msgstr ""
+
+msgid "Remove user from group"
+msgstr ""
+
msgid "Removed"
msgstr ""
@@ -20818,9 +21522,6 @@ msgstr ""
msgid "Removes time estimate."
msgstr ""
-msgid "Removing license…"
-msgstr ""
-
msgid "Removing this group also removes all child projects, including archived projects, and their resources."
msgstr ""
@@ -20905,6 +21606,9 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
+msgid "Reported by %{reporter}"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -20991,6 +21695,27 @@ msgstr ""
msgid "Repositories"
msgstr ""
+msgid "Repositories Analytics"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download Historic Test Coverage Data"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download historic test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Historic Test Coverage Data is available in raw format (.csv) for further analysis."
+msgstr ""
+
+msgid "RepositoriesAnalytics|Test Code Coverage"
+msgstr ""
+
+msgid "RepositoriesAnalytics|There was an error fetching the projects."
+msgstr ""
+
msgid "Repository"
msgstr ""
@@ -21069,9 +21794,15 @@ msgstr ""
msgid "Request parameter %{param} is missing."
msgstr ""
+msgid "Request review from"
+msgstr ""
+
msgid "Request to link SAML account must be authorized"
msgstr ""
+msgid "Requested"
+msgstr ""
+
msgid "Requested %{time_ago}"
msgstr ""
@@ -21090,6 +21821,9 @@ msgstr ""
msgid "Requests to these domain(s)/address(es) on the local network will be allowed when local requests from hooks and services are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 or 127.0.0.0/28 are supported. Domain wildcards are not supported currently. Use comma, semicolon, or newline to separate multiple entries. The allowlist can hold a maximum of 1000 entries. Domains should use IDNA encoding. Ex: example.com, 192.168.1.1, 127.0.0.0/28, xn--itlab-j1a.com."
msgstr ""
+msgid "Require admin approval for new sign-ups"
+msgstr ""
+
msgid "Require all users in this group to setup Two-factor authentication"
msgstr ""
@@ -21217,9 +21951,6 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
-msgid "Resolved by %{resolvedByName}"
-msgstr ""
-
msgid "Resolves IP addresses once and uses them to submit requests"
msgstr ""
@@ -21339,6 +22070,14 @@ msgstr ""
msgid "ReviewApp|Enable Review App"
msgstr ""
+msgid "Reviewer"
+msgid_plural "%d Reviewers"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Reviewer(s)"
+msgstr ""
+
msgid "Reviewing"
msgstr ""
@@ -21378,6 +22117,9 @@ msgstr ""
msgid "Rook"
msgstr ""
+msgid "Ruby"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -21456,6 +22198,63 @@ msgstr ""
msgid "Runners page."
msgstr ""
+msgid "Runners|Active"
+msgstr ""
+
+msgid "Runners|Architecture"
+msgstr ""
+
+msgid "Runners|Can run untagged jobs"
+msgstr ""
+
+msgid "Runners|Description"
+msgstr ""
+
+msgid "Runners|Group"
+msgstr ""
+
+msgid "Runners|IP Address"
+msgstr ""
+
+msgid "Runners|Last contact"
+msgstr ""
+
+msgid "Runners|Locked to this project"
+msgstr ""
+
+msgid "Runners|Maximum job timeout"
+msgstr ""
+
+msgid "Runners|Name"
+msgstr ""
+
+msgid "Runners|Platform"
+msgstr ""
+
+msgid "Runners|Property Name"
+msgstr ""
+
+msgid "Runners|Protected"
+msgstr ""
+
+msgid "Runners|Revision"
+msgstr ""
+
+msgid "Runners|Shared"
+msgstr ""
+
+msgid "Runners|Specific"
+msgstr ""
+
+msgid "Runners|Tags"
+msgstr ""
+
+msgid "Runners|Value"
+msgstr ""
+
+msgid "Runners|Version"
+msgstr ""
+
msgid "Runners|You have used %{quotaUsed} out of %{quotaLimit} of your shared Runners pipeline minutes."
msgstr ""
@@ -21468,6 +22267,9 @@ msgstr ""
msgid "Runs a number of housekeeping tasks within the current repository, such as compressing file revisions and removing unreachable objects."
msgstr ""
+msgid "SAML"
+msgstr ""
+
msgid "SAML SSO"
msgstr ""
@@ -21519,6 +22321,9 @@ msgstr ""
msgid "Save"
msgstr ""
+msgid "Save %{name} size limits"
+msgstr ""
+
msgid "Save Changes"
msgstr ""
@@ -21549,9 +22354,6 @@ msgstr ""
msgid "Save space and find tags in the Container Registry more easily. Enable the cleanup policy to remove stale tags and keep only the ones you need."
msgstr ""
-msgid "Save template"
-msgstr ""
-
msgid "Save variables"
msgstr ""
@@ -21594,9 +22396,6 @@ msgstr ""
msgid "Scope"
msgstr ""
-msgid "Scope not supported with disabled 'users_search' feature!"
-msgstr ""
-
msgid "Scoped issue boards"
msgstr ""
@@ -21723,9 +22522,6 @@ msgstr ""
msgid "Search requirements"
msgstr ""
-msgid "Search results…"
-msgstr ""
-
msgid "Search users"
msgstr ""
@@ -21798,6 +22594,11 @@ msgid_plural "SearchResults|commits"
msgstr[0] ""
msgstr[1] ""
+msgid "SearchResults|epic"
+msgid_plural "SearchResults|epics"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "SearchResults|issue"
msgid_plural "SearchResults|issues"
msgstr[0] ""
@@ -21842,10 +22643,10 @@ msgstr ""
msgid "Seat Link is disabled, and cannot be configured through this form."
msgstr ""
-msgid "Seats currently in use"
+msgid "Seats usage data as of %{last_enqueue_time}"
msgstr ""
-msgid "Seats in license"
+msgid "Seats usage data is updated every day at 12:00pm UTC"
msgstr ""
msgid "Secondary"
@@ -21899,6 +22700,9 @@ msgstr ""
msgid "SecurityConfiguration|Available for on-demand DAST"
msgstr ""
+msgid "SecurityConfiguration|By default, all analyzers are applied in order to cover all languages across your project, and only run if the language is detected in the Merge Request."
+msgstr ""
+
msgid "SecurityConfiguration|Configure"
msgstr ""
@@ -21929,16 +22733,19 @@ msgstr ""
msgid "SecurityConfiguration|Manage"
msgstr ""
+msgid "SecurityConfiguration|More information"
+msgstr ""
+
msgid "SecurityConfiguration|Not enabled"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|Security Control"
+msgid "SecurityConfiguration|SAST Configuration"
msgstr ""
-msgid "SecurityConfiguration|See documentation"
+msgid "SecurityConfiguration|Security Control"
msgstr ""
msgid "SecurityConfiguration|Status"
@@ -21950,6 +22757,9 @@ msgstr ""
msgid "SecurityConfiguration|Using custom settings. You won't receive automatic updates on this variable. %{anchorStart}Restore to default%{anchorEnd}"
msgstr ""
+msgid "SecurityConfiguration|View history"
+msgstr ""
+
msgid "SecurityConfiguration|You can quickly enable all security scanning tools by enabling %{linkStart}Auto DevOps%{linkEnd}."
msgstr ""
@@ -22028,9 +22838,6 @@ msgstr ""
msgid "SecurityReports|Learn more about setting up your dashboard"
msgstr ""
-msgid "SecurityReports|Load more vulnerabilities"
-msgstr ""
-
msgid "SecurityReports|Monitor vulnerabilities in your code"
msgstr ""
@@ -22310,7 +23117,7 @@ msgstr ""
msgid "Select status"
msgstr ""
-msgid "Select strategy activation method"
+msgid "Select strategy activation method."
msgstr ""
msgid "Select subscription"
@@ -22325,7 +23132,7 @@ msgstr ""
msgid "Select the custom project template source group."
msgstr ""
-msgid "Select timeframe"
+msgid "Select the environment scope for this feature flag."
msgstr ""
msgid "Select timezone"
@@ -22574,6 +23381,9 @@ msgstr ""
msgid "Set iteration"
msgstr ""
+msgid "Set limit to 0 to allow any file size."
+msgstr ""
+
msgid "Set max session time for web terminal."
msgstr ""
@@ -22652,10 +23462,13 @@ msgstr ""
msgid "Set up a %{type} Runner manually"
msgstr ""
+msgid "Set up a hardware device as a second factor to sign in."
+msgstr ""
+
msgid "Set up assertions/attributes/claims (email, first_name, last_name) and NameID according to %{docsLinkStart}the documentation %{icon}%{docsLinkEnd}"
msgstr ""
-msgid "Set up new U2F device"
+msgid "Set up new device"
msgstr ""
msgid "Set up new password"
@@ -22724,6 +23537,9 @@ msgstr ""
msgid "Sets weight to %{weight}."
msgstr ""
+msgid "Setting this to 0 means using the system default timeout value."
+msgstr ""
+
msgid "Settings"
msgstr ""
@@ -22739,6 +23555,15 @@ msgstr ""
msgid "Severity"
msgstr ""
+msgid "SeverityWidget|Severity"
+msgstr ""
+
+msgid "SeverityWidget|Severity: %{severity}"
+msgstr ""
+
+msgid "SeverityWidget|There was an error while updating severity."
+msgstr ""
+
msgid "Shards (%{shards})"
msgstr ""
@@ -22784,6 +23609,9 @@ msgstr ""
msgid "Show all requirements."
msgstr ""
+msgid "Show all test cases."
+msgstr ""
+
msgid "Show archived projects"
msgstr ""
@@ -22796,6 +23624,9 @@ msgstr ""
msgid "Show comments"
msgstr ""
+msgid "Show comments on this file"
+msgstr ""
+
msgid "Show comments only"
msgstr ""
@@ -22841,6 +23672,12 @@ msgstr ""
msgid "Show parent subgroups"
msgstr ""
+msgid "Show the Closed list"
+msgstr ""
+
+msgid "Show the Open list"
+msgstr ""
+
msgid "Show whitespace changes"
msgstr ""
@@ -22884,9 +23721,6 @@ msgstr ""
msgid "Sidebar|Assign health status"
msgstr ""
-msgid "Sidebar|Change weight"
-msgstr ""
-
msgid "Sidebar|Health status"
msgstr ""
@@ -23070,6 +23904,9 @@ msgstr ""
msgid "Snippets|Add another file %{num}/%{total}"
msgstr ""
+msgid "Snippets|Authored %{time_ago} by %{author}"
+msgstr ""
+
msgid "Snippets|Delete file"
msgstr ""
@@ -23097,6 +23934,9 @@ msgstr ""
msgid "Solution"
msgstr ""
+msgid "Some changes are not shown"
+msgstr ""
+
msgid "Some child epics may be hidden due to applied filters"
msgstr ""
@@ -23463,6 +24303,12 @@ msgstr ""
msgid "Source (branch or tag)"
msgstr ""
+msgid "Source Branch"
+msgstr ""
+
+msgid "Source branch: %{source_branch_open}%{source_branch}%{source_branch_close}"
+msgstr ""
+
msgid "Source code"
msgstr ""
@@ -23628,9 +24474,6 @@ msgstr ""
msgid "Start and due date"
msgstr ""
-msgid "Start by choosing a group to see how your team is spending time. You can then drill down to the project level."
-msgstr ""
-
msgid "Start by choosing a group to start exploring the merge requests in that group. You can then proceed to filter by projects, labels, milestones and authors."
msgstr ""
@@ -23712,18 +24555,27 @@ msgstr ""
msgid "StaticSiteEditor|3. Assign a person to review and accept the merge request."
msgstr ""
+msgid "StaticSiteEditor|A link to view the merge request will appear once ready."
+msgstr ""
+
msgid "StaticSiteEditor|An error occurred while submitting your changes."
msgstr ""
msgid "StaticSiteEditor|Branch could not be created."
msgstr ""
+msgid "StaticSiteEditor|Copy update"
+msgstr ""
+
msgid "StaticSiteEditor|Could not commit the content changes."
msgstr ""
msgid "StaticSiteEditor|Could not create merge request."
msgstr ""
+msgid "StaticSiteEditor|Creating your merge request"
+msgstr ""
+
msgid "StaticSiteEditor|Incompatible file content"
msgstr ""
@@ -23745,6 +24597,9 @@ msgstr ""
msgid "StaticSiteEditor|View documentation"
msgstr ""
+msgid "StaticSiteEditor|You can set an assignee to get your changes reviewed and deployed once your merge request is created."
+msgstr ""
+
msgid "StaticSiteEditor|Your merge request has been created"
msgstr ""
@@ -23874,15 +24729,15 @@ msgstr ""
msgid "Submit %{humanized_resource_name}"
msgstr ""
-msgid "Submit Changes"
-msgstr ""
-
msgid "Submit a review"
msgstr ""
msgid "Submit as spam"
msgstr ""
+msgid "Submit changes"
+msgstr ""
+
msgid "Submit feedback"
msgstr ""
@@ -24036,6 +24891,9 @@ msgstr ""
msgid "Successfully deleted U2F device."
msgstr ""
+msgid "Successfully deleted WebAuthn device."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -24354,9 +25212,6 @@ msgstr ""
msgid "Template to append to all Service Desk issues"
msgstr ""
-msgid "Template was successfully saved."
-msgstr ""
-
msgid "Templates"
msgstr ""
@@ -24435,10 +25290,28 @@ msgid_plural "Test coverage: %d hits"
msgstr[0] ""
msgstr[1] ""
-msgid "Test failed."
+msgid "Test settings"
msgstr ""
-msgid "Test settings and save changes"
+msgid "TestCases|New Test Case"
+msgstr ""
+
+msgid "TestCases|New test case"
+msgstr ""
+
+msgid "TestCases|Search test cases"
+msgstr ""
+
+msgid "TestCases|Something went wrong while creating a test case."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching count of test cases."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching test cases list."
+msgstr ""
+
+msgid "TestCases|Submit test case"
msgstr ""
msgid "TestHooks|Ensure one of your projects has merge requests."
@@ -24504,6 +25377,9 @@ msgstr ""
msgid "Thank you for signing up for your free trial! You will get additional instructions in your inbox shortly."
msgstr ""
+msgid "Thank you for your business."
+msgstr ""
+
msgid "Thank you for your feedback!"
msgstr ""
@@ -24563,9 +25439,6 @@ msgstr ""
msgid "The URL to use for connecting to Elasticsearch. Use a comma-separated list to support clustering (e.g., \"http://localhost:9200, http://localhost:9201\")."
msgstr ""
-msgid "The Web IDE offers advanced syntax highlighting capabilities and more."
-msgstr ""
-
msgid "The X509 Certificate to use when mutual TLS is required to communicate with the external authorization service. If left blank, the server certificate is still validated when accessing over HTTPS."
msgstr ""
@@ -24676,6 +25549,9 @@ msgstr ""
msgid "The form contains the following error:"
msgstr ""
+msgid "The form contains the following warning:"
+msgstr ""
+
msgid "The global settings require you to enable Two-Factor Authentication for your account."
msgstr ""
@@ -24790,9 +25666,6 @@ msgstr ""
msgid "The private key to use when a client certificate is provided. This value is encrypted at rest."
msgstr ""
-msgid "The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The project can be accessed by any logged in user."
msgstr ""
@@ -24829,7 +25702,7 @@ msgstr ""
msgid "The remote repository is being updated..."
msgstr ""
-msgid "The repository can be commited to, and issues, comments and other entities can be created."
+msgid "The repository can be committed to, and issues, comments and other entities can be created."
msgstr ""
msgid "The repository for this project does not exist."
@@ -24883,9 +25756,6 @@ msgstr ""
msgid "The time taken by each data entry gathered by that stage."
msgstr ""
-msgid "The total stage shows the time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The update action will time out after %{number_of_minutes} minutes. For big repositories, use a clone/push combination."
msgstr ""
@@ -24949,6 +25819,9 @@ msgstr ""
msgid "There are no archived requirements"
msgstr ""
+msgid "There are no archived test cases"
+msgstr ""
+
msgid "There are no changes"
msgstr ""
@@ -24988,6 +25861,9 @@ msgstr ""
msgid "There are no open requirements"
msgstr ""
+msgid "There are no open test cases"
+msgstr ""
+
msgid "There are no packages yet"
msgstr ""
@@ -25000,6 +25876,9 @@ msgstr ""
msgid "There is a limit of %{ci_project_subscriptions_limit} subscriptions from or to a project."
msgstr ""
+msgid "There is already a To-Do for this design."
+msgstr ""
+
msgid "There is already a repository with that name on disk"
msgstr ""
@@ -25018,6 +25897,9 @@ msgstr ""
msgid "There was a problem communicating with your device."
msgstr ""
+msgid "There was a problem fetching branches."
+msgstr ""
+
msgid "There was a problem fetching groups."
msgstr ""
@@ -25246,9 +26128,15 @@ msgstr ""
msgid "This action can lead to data loss. To prevent accidental actions we ask you to confirm your intention."
msgstr ""
+msgid "This action cannot be undone, and will permanently delete the %{key} SSH key"
+msgstr ""
+
msgid "This action cannot be undone. You will lose the project's repository and all content: issues, merge requests, etc."
msgstr ""
+msgid "This action has been performed too many times. Try again later."
+msgstr ""
+
msgid "This action will %{strongOpen}permanently delete%{strongClose} %{codeOpen}%{project}%{codeClose} %{strongOpen}immediately%{strongClose}, including its repositories and all content: issues, merge requests, etc."
msgstr ""
@@ -25276,9 +26164,6 @@ msgstr ""
msgid "This board's scope is reduced"
msgstr ""
-msgid "This branch has changed since you started editing. Would you like to create a new branch?"
-msgstr ""
-
msgid "This chart could not be displayed"
msgstr ""
@@ -25405,15 +26290,9 @@ msgstr ""
msgid "This is a security log of important events involving your account."
msgstr ""
-msgid "This is the author's first Merge Request to this project."
-msgstr ""
-
msgid "This is the highest peak of users on your installation since the license started."
msgstr ""
-msgid "This is the maximum number of users that have existed at the same time since the license started. This is the minimum number of seats you will need to buy when you renew your license."
-msgstr ""
-
msgid "This is the number of currently active users on your installation, and this is the minimum number you need to purchase when you renew your license."
msgstr ""
@@ -25645,6 +26524,15 @@ msgstr ""
msgid "This user has no identities"
msgstr ""
+msgid "This user has previously committed to the %{name} project."
+msgstr ""
+
+msgid "This user has the %{access} role in the %{name} project."
+msgstr ""
+
+msgid "This user is the author of this %{noteable}."
+msgstr ""
+
msgid "This user will be the author of all events in the activity feed that are the result of an update, like new branches being created or new commits being pushed to existing branches."
msgstr ""
@@ -25675,6 +26563,9 @@ msgstr ""
msgid "Threat Monitoring"
msgstr ""
+msgid "ThreatMonitoring|All Environments"
+msgstr ""
+
msgid "ThreatMonitoring|Anomalous Requests"
msgstr ""
@@ -25702,9 +26593,6 @@ msgstr ""
msgid "ThreatMonitoring|Operations Per Second"
msgstr ""
-msgid "ThreatMonitoring|Overview"
-msgstr ""
-
msgid "ThreatMonitoring|Packet Activity"
msgstr ""
@@ -25723,6 +26611,9 @@ msgstr ""
msgid "ThreatMonitoring|Something went wrong, unable to fetch statistics"
msgstr ""
+msgid "ThreatMonitoring|Statistics"
+msgstr ""
+
msgid "ThreatMonitoring|The firewall is not installed or has been disabled. To view this data, ensure the web application firewall is installed and enabled for your cluster."
msgstr ""
@@ -26114,6 +27005,9 @@ msgstr ""
msgid "To update Snippets with multiple files, you must use the `files` parameter"
msgstr ""
+msgid "To use Gitpod you must first enable the feature in the integrations section of your %{user_prefs}."
+msgstr ""
+
msgid "To view all %{scannedResourcesCount} scanned URLs, please download the CSV file"
msgstr ""
@@ -26147,9 +27041,6 @@ msgstr ""
msgid "Toggle Sidebar"
msgstr ""
-msgid "Toggle all threads"
-msgstr ""
-
msgid "Toggle backtrace"
msgstr ""
@@ -26174,9 +27065,6 @@ msgstr ""
msgid "Toggle navigation"
msgstr ""
-msgid "Toggle project"
-msgstr ""
-
msgid "Toggle sidebar"
msgstr ""
@@ -26216,6 +27104,9 @@ msgstr ""
msgid "Too many projects enabled. You will need to manage them via the console or the API."
msgstr ""
+msgid "Too much data"
+msgstr ""
+
msgid "Topics (optional)"
msgstr ""
@@ -26234,6 +27125,9 @@ msgstr ""
msgid "Total cores (CPUs)"
msgstr ""
+msgid "Total days to completion"
+msgstr ""
+
msgid "Total issues"
msgstr ""
@@ -26330,6 +27224,9 @@ msgstr ""
msgid "Trending"
msgstr ""
+msgid "Trials|Create a new group to start your GitLab Gold trial."
+msgstr ""
+
msgid "Trials|Go back to GitLab"
msgstr ""
@@ -26339,6 +27236,15 @@ msgstr ""
msgid "Trials|You can always resume this process by selecting your avatar and choosing 'Start a Gold trial'"
msgstr ""
+msgid "Trials|You can apply your trial to a new group or an existing group."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group or your personal account."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group, an existing group, or your personal account."
+msgstr ""
+
msgid "Trials|You won't get a free trial right now but you can always resume this process by clicking on your avatar and choosing 'Start a free trial'"
msgstr ""
@@ -26408,6 +27314,9 @@ msgstr ""
msgid "Try using a different search term to find the file you are looking for."
msgstr ""
+msgid "Trying to communicate with your device. Plug it in (if needed) and press the button on the device now."
+msgstr ""
+
msgid "Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now."
msgstr ""
@@ -26495,6 +27404,12 @@ msgstr ""
msgid "URL or request ID"
msgstr ""
+msgid "USER %{user} WILL BE REMOVED! Are you sure?"
+msgstr ""
+
+msgid "USER WILL BE BLOCKED! Are you sure?"
+msgstr ""
+
msgid "UTC"
msgstr ""
@@ -26552,9 +27467,6 @@ msgstr ""
msgid "Unable to load the merge request widget. Try reloading the page."
msgstr ""
-msgid "Unable to resolve"
-msgstr ""
-
msgid "Unable to save iteration. Please try again"
msgstr ""
@@ -26603,6 +27515,9 @@ msgstr ""
msgid "Undo ignore"
msgstr ""
+msgid "Unexpected error"
+msgstr ""
+
msgid "Unfortunately, your email message to GitLab could not be processed."
msgstr ""
@@ -26636,6 +27551,9 @@ msgstr ""
msgid "Unknown response text"
msgstr ""
+msgid "Unless otherwise agreed to in writing with GitLab, by clicking \"Upload License\" you agree that your use of GitLab Software is subject to the %{eula_link_start}Terms of Service%{eula_link_end}."
+msgstr ""
+
msgid "Unlimited"
msgstr ""
@@ -27002,9 +27920,6 @@ msgstr ""
msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
msgstr ""
-msgid "Use a hardware device to add the second factor of authentication."
-msgstr ""
-
msgid "Use an one time password authenticator on your mobile device or computer to enable two-factor authentication (2FA)."
msgstr ""
@@ -27278,13 +28193,13 @@ msgstr ""
msgid "Users"
msgstr ""
-msgid "Users in License:"
+msgid "Users in License"
msgstr ""
-msgid "Users or groups set as approvers in the project's or merge request's settings."
+msgid "Users in License:"
msgstr ""
-msgid "Users outside of license"
+msgid "Users or groups set as approvers in the project's or merge request's settings."
msgstr ""
msgid "Users over License:"
@@ -27302,9 +28217,6 @@ msgstr ""
msgid "Users with a Guest role or those who don't belong to a Project or Group will not use a seat from your license."
msgstr ""
-msgid "Users with a Guest role or those who don't belong to any projects or groups don't count towards seats in use."
-msgstr ""
-
msgid "UsersSelect|%{name} + %{length} more"
msgstr ""
@@ -27344,9 +28256,6 @@ msgstr ""
msgid "Validations failed."
msgstr ""
-msgid "Validity"
-msgstr ""
-
msgid "Value"
msgstr ""
@@ -27365,6 +28274,9 @@ msgstr ""
msgid "Value Stream Name"
msgstr ""
+msgid "ValueStreamAnalyticsStage|We don't have enough data to show this stage."
+msgstr ""
+
msgid "ValueStreamAnalytics|%{days}d"
msgstr ""
@@ -27621,6 +28533,9 @@ msgstr ""
msgid "VisualReviewApp|Steps 1 and 2 (and sometimes 3) are performed once by the developer before requesting feedback. Steps 3 (if necessary), 4 is performed by the reviewer each time they perform a review."
msgstr ""
+msgid "Visualization"
+msgstr ""
+
msgid "Vulnerabilities"
msgstr ""
@@ -27648,34 +28563,31 @@ msgstr ""
msgid "VulnerabilityChart|Severity"
msgstr ""
-msgid "VulnerabilityManagement|A true-positive and will fix"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Change status"
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|Confirm"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Confirmed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
-msgstr ""
-
-msgid "VulnerabilityManagement|Detected %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|A true-positive and will fix"
msgstr ""
-msgid "VulnerabilityManagement|Dismiss"
+msgid "VulnerabilityManagement|Change status"
msgstr ""
-msgid "VulnerabilityManagement|Dismissed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
msgstr ""
-msgid "VulnerabilityManagement|Resolved"
+msgid "VulnerabilityManagement|Detected"
msgstr ""
-msgid "VulnerabilityManagement|Resolved %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Needs triage"
msgstr ""
msgid "VulnerabilityManagement|Something went wrong while trying to delete the comment. Please try again later."
@@ -27726,6 +28638,9 @@ msgstr ""
msgid "Vulnerability|%{scannerName} (version %{scannerVersion})"
msgstr ""
+msgid "Vulnerability|Activity"
+msgstr ""
+
msgid "Vulnerability|Class"
msgstr ""
@@ -27738,6 +28653,9 @@ msgstr ""
msgid "Vulnerability|Description"
msgstr ""
+msgid "Vulnerability|Detected"
+msgstr ""
+
msgid "Vulnerability|Evidence"
msgstr ""
@@ -27801,6 +28719,9 @@ msgstr ""
msgid "Warning: Displaying this diagram might cause performance issues on this page."
msgstr ""
+msgid "We are currently unable to fetch data for the pipeline header."
+msgstr ""
+
msgid "We are currently unable to fetch data for this graph."
msgstr ""
@@ -27840,6 +28761,12 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
+msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
+msgstr ""
+
+msgid "We would like to inform you that your subscription GitLab Enterprise Edition %{plan_name} is nearing its user limit. You have %{active_user_count} active users, which is almost at the user limit of %{maximum_user_count}."
+msgstr ""
+
msgid "We've found no vulnerabilities"
msgstr ""
@@ -27855,6 +28782,12 @@ msgstr ""
msgid "Web terminal"
msgstr ""
+msgid "WebAuthn Devices (%{length})"
+msgstr ""
+
+msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
+msgstr ""
+
msgid "WebIDE|Merge request"
msgstr ""
@@ -27993,15 +28926,9 @@ msgstr ""
msgid "Welcome to the guided GitLab tour"
msgstr ""
-msgid "Welcome to your Issue Board!"
-msgstr ""
-
msgid "Welcome to your issue board!"
msgstr ""
-msgid "We’ve been making changes to %{featureName} and we’d love your feedback %{linkStart}in this issue%{linkEnd} to help us improve the experience."
-msgstr ""
-
msgid "What are you searching for?"
msgstr ""
@@ -28020,6 +28947,9 @@ msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
msgstr ""
+msgid "When enabled, any user visiting %{host} and creating an account will have to be explicitly approved by the admin before they can login. This setting is effective only if sign-ups are enabled."
+msgstr ""
+
msgid "When enabled, any user visiting %{host} will be able to create an account."
msgstr ""
@@ -28244,6 +29174,9 @@ msgstr ""
msgid "With requirements, you can set criteria to check your products against."
msgstr ""
+msgid "With test cases, you can define conditions for your project to meet in determining quality"
+msgstr ""
+
msgid "Withdraw Access Request"
msgstr ""
@@ -28259,6 +29192,9 @@ msgstr ""
msgid "Workflow Help"
msgstr ""
+msgid "Would you like to create a new branch?"
+msgstr ""
+
msgid "Write"
msgstr ""
@@ -28280,6 +29216,9 @@ msgstr ""
msgid "Wrong extern UID provided. Make sure Auth0 is configured correctly."
msgstr ""
+msgid "YYYY-MM-DD"
+msgstr ""
+
msgid "Yes"
msgstr ""
@@ -28337,7 +29276,7 @@ msgstr ""
msgid "You are going to remove the fork relationship from %{project_full_name}. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "You are going to transfer %{project_full_name} to another owner. Are you ABSOLUTELY sure?"
+msgid "You are going to transfer %{project_full_name} to another namespace. Are you ABSOLUTELY sure?"
msgstr ""
msgid "You are going to turn off the confidentiality. This means %{strongStart}everyone%{strongEnd} will be able to see and leave a comment on this %{issuableType}."
@@ -28397,9 +29336,6 @@ msgstr ""
msgid "You can always edit this later"
msgstr ""
-msgid "You can apply your Trial to your Personal account or create a New Group."
-msgstr ""
-
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings"
msgstr ""
@@ -28421,12 +29357,18 @@ msgstr ""
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
+msgid "You can find more information about GitLab subscriptions in %{subscriptions_doc_link}."
+msgstr ""
+
msgid "You can generate an access token scoped to this project for each application to use the GitLab API."
msgstr ""
msgid "You can get started by cloning the repository or start adding files to it with one of the following options."
msgstr ""
+msgid "You can group test cases using labels. To learn about the future direction of this feature, visit %{linkStart}Quality Management direction page%{linkEnd}."
+msgstr ""
+
msgid "You can invite a new member to %{project_name} or invite another group."
msgstr ""
@@ -28442,6 +29384,9 @@ msgstr ""
msgid "You can notify the app / group or a project by sending them an email notification"
msgstr ""
+msgid "You can now close this window."
+msgstr ""
+
msgid "You can now export your security dashboard to a CSV report."
msgstr ""
@@ -28490,9 +29435,6 @@ msgstr ""
msgid "You can test your .gitlab-ci.yml in %{linkStart}CI Lint%{linkEnd}."
msgstr ""
-msgid "You can try again using %{begin_link}basic search%{end_link}"
-msgstr ""
-
msgid "You cannot access the raw file. Please wait a minute."
msgstr ""
@@ -28544,6 +29486,9 @@ msgstr ""
msgid "You don't have any U2F devices registered yet."
msgstr ""
+msgid "You don't have any WebAuthn devices registered yet."
+msgstr ""
+
msgid "You don't have any active chat names."
msgstr ""
@@ -28631,6 +29576,9 @@ msgstr ""
msgid "You must accept our Terms of Service and privacy policy in order to register an account"
msgstr ""
+msgid "You must be logged in to search across all of GitLab"
+msgstr ""
+
msgid "You must disassociate %{domain} from all clusters it is attached to before deletion."
msgstr ""
@@ -28670,7 +29618,7 @@ msgstr ""
msgid "You need to be logged in."
msgstr ""
-msgid "You need to register a two-factor authentication app before you can set up a U2F device."
+msgid "You need to register a two-factor authentication app before you can set up a device."
msgstr ""
msgid "You need to set terms to be enforced"
@@ -28688,6 +29636,9 @@ msgstr ""
msgid "You reached %{usage_in_percent} of %{namespace_name}'s storage capacity (%{used_storage} of %{storage_limit})"
msgstr ""
+msgid "You successfully declined the invitation"
+msgstr ""
+
msgid "You tried to fork %{link_to_the_project} but it failed for the following reason:"
msgstr ""
@@ -28853,10 +29804,13 @@ msgstr ""
msgid "Your U2F device did not send a valid JSON response."
msgstr ""
-msgid "Your U2F device needs to be set up. Plug it in (if not already) and click the button on the left."
+msgid "Your U2F device was registered!"
msgstr ""
-msgid "Your U2F device was registered!"
+msgid "Your WebAuthn device did not send a valid JSON response."
+msgstr ""
+
+msgid "Your WebAuthn device was registered!"
msgstr ""
msgid "Your access request to the %{source_type} has been withdrawn."
@@ -28880,6 +29834,9 @@ msgstr ""
msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
msgstr ""
+msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
+msgstr ""
+
msgid "Your changes can be committed to %{branch_name} because a merge request is open."
msgstr ""
@@ -28916,6 +29873,12 @@ msgstr ""
msgid "Your deployment services will be broken, you will need to manually fix the services after renaming."
msgstr ""
+msgid "Your device is not compatible with GitLab. Please try another device"
+msgstr ""
+
+msgid "Your device needs to be set up. Plug it in (if needed) and click the button on the left."
+msgstr ""
+
msgid "Your device was successfully set up! Give it a name and register it with the GitLab server."
msgstr ""
@@ -29029,9 +29992,6 @@ msgstr[1] ""
msgid "access:"
msgstr ""
-msgid "activated"
-msgstr ""
-
msgid "added %{created_at_timeago}"
msgstr ""
@@ -29104,9 +30064,21 @@ msgstr ""
msgid "by %{user}"
msgstr ""
+msgid "cannot be a date in the past"
+msgstr ""
+
msgid "cannot be changed if a personal project has container registry tags."
msgstr ""
+msgid "cannot be changed if shared runners are enabled"
+msgstr ""
+
+msgid "cannot be enabled because parent group does not allow it"
+msgstr ""
+
+msgid "cannot be enabled because parent group has shared Runners disabled"
+msgstr ""
+
msgid "cannot be enabled unless all domains have TLS certificates"
msgstr ""
@@ -29152,7 +30124,7 @@ msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about SAST %{linkEndTag}"
msgstr ""
-msgid "ciReport|%{linkStartTag}Learn more about Secret Scanning %{linkEndTag}"
+msgid "ciReport|%{linkStartTag}Learn more about Secret Detection %{linkEndTag}"
msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about codequality reports %{linkEndTag}"
@@ -29467,9 +30439,6 @@ msgstr ""
msgid "error"
msgstr ""
-msgid "error code:"
-msgstr ""
-
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr ""
@@ -29491,6 +30460,9 @@ msgstr ""
msgid "failed to dismiss associated finding(id=%{finding_id}): %{message}"
msgstr ""
+msgid "failed to revert associated finding(id=%{finding_id}) to detected"
+msgstr ""
+
msgid "file"
msgid_plural "files"
msgstr[0] ""
@@ -30033,6 +31005,9 @@ msgstr ""
msgid "must be a root namespace"
msgstr ""
+msgid "must be a valid IPv4 or IPv6 address"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -30069,6 +31044,9 @@ msgstr ""
msgid "no expiration"
msgstr ""
+msgid "no name set"
+msgstr ""
+
msgid "no one can merge"
msgstr ""
@@ -30247,9 +31225,6 @@ msgstr ""
msgid "security Reports|There was an error creating the merge request"
msgstr ""
-msgid "settings saved, but not activated"
-msgstr ""
-
msgid "severity|Critical"
msgstr ""
@@ -30376,9 +31351,6 @@ msgstr ""
msgid "toggle collapse"
msgstr ""
-msgid "toggle dropdown"
-msgstr ""
-
msgid "triggered"
msgstr ""
@@ -30406,6 +31378,9 @@ msgstr ""
msgid "user avatar"
msgstr ""
+msgid "user preferences"
+msgstr ""
+
msgid "username"
msgstr ""
diff --git a/locale/sr_CS/gitlab.po b/locale/sr_CS/gitlab.po
index f630cca8ec0..a6daa719153 100644
--- a/locale/sr_CS/gitlab.po
+++ b/locale/sr_CS/gitlab.po
@@ -14,7 +14,10 @@ msgstr ""
"X-Crowdin-Language: sr-CS\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 6\n"
-"PO-Revision-Date: 2020-09-04 23:05\n"
+"PO-Revision-Date: 2020-10-02 18:44\n"
+
+msgid " %{project_name}#%{issue_iid} &middot; opened %{issue_created} by %{author}"
+msgstr ""
msgid " %{start} to %{end}"
msgstr ""
@@ -76,6 +79,18 @@ msgstr ""
msgid "\"el\" parameter is required for createInstance()"
msgstr ""
+msgid "%d Approval"
+msgid_plural "%d Approvals"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
+msgid "%d Package"
+msgid_plural "%d Packages"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "%d Scanned URL"
msgid_plural "%d Scanned URLs"
msgstr[0] ""
@@ -151,6 +166,12 @@ msgstr[2] ""
msgid "%d commits"
msgstr ""
+msgid "%d completed issue"
+msgid_plural "%d completed issues"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "%d contribution"
msgid_plural "%d contributions"
msgstr[0] ""
@@ -163,6 +184,12 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgid "%d day until tags are automatically removed"
+msgid_plural "%d days until tags are automatically removed"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "%d error"
msgid_plural "%d errors"
msgstr[0] "%d greška"
@@ -271,6 +298,18 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgid "%d open issue"
+msgid_plural "%d open issues"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
+msgid "%d pending comment"
+msgid_plural "%d pending comments"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "%d personal project will be removed and cannot be restored."
msgid_plural "%d personal projects will be removed and cannot be restored."
msgstr[0] ""
@@ -289,6 +328,12 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgid "%d project selected"
+msgid_plural "%d projects selected"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "%d request with warnings"
msgid_plural "%d requests with warnings"
msgstr[0] ""
@@ -313,6 +358,12 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgid "%d tag per image name"
+msgid_plural "%d tags per image name"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "%d unassigned issue"
msgid_plural "%d unassigned issues"
msgstr[0] ""
@@ -337,6 +388,12 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgid "%d warning found:"
+msgid_plural "%d warnings found:"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "%s additional commit has been omitted to prevent performance issues."
msgid_plural "%s additional commits have been omitted to prevent performance issues."
msgstr[0] ""
@@ -376,6 +433,9 @@ msgstr ""
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr ""
+msgid "%{completedCount} completed weight"
+msgstr ""
+
msgid "%{completedWeight} of %{totalWeight} weight completed"
msgstr ""
@@ -427,15 +487,12 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
-msgid "%{count} pending comment"
-msgid_plural "%{count} pending comments"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
+msgid "%{count} total weight"
+msgstr ""
+
msgid "%{dashboard_path} could not be found."
msgstr ""
@@ -490,6 +547,9 @@ msgstr ""
msgid "%{group_name} uses group managed accounts. You need to create a new GitLab account which will be managed by %{group_name}."
msgstr ""
+msgid "%{group_name}&%{epic_iid} &middot; opened %{epic_created} by %{author}"
+msgstr ""
+
msgid "%{host} sign-in from new location"
msgstr ""
@@ -502,7 +562,7 @@ msgstr ""
msgid "%{issuableType} will be removed! Are you sure?"
msgstr ""
-msgid "%{issuesSize} issues with a limit of %{maxIssueCount}"
+msgid "%{issuesCount} issues with a limit of %{maxIssueCount}"
msgstr ""
msgid "%{issuesSize} with a limit of %{maxIssueCount}"
@@ -535,7 +595,7 @@ msgstr ""
msgid "%{labelStart}Namespace:%{labelEnd} %{namespace}"
msgstr ""
-msgid "%{labelStart}Report Type:%{labelEnd} %{reportType}"
+msgid "%{labelStart}Scan Type:%{labelEnd} %{reportType}"
msgstr ""
msgid "%{labelStart}Scanner:%{labelEnd} %{scanner}"
@@ -739,9 +799,6 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
-msgid "%{service_title} %{message}."
-msgstr ""
-
msgid "%{size} GiB"
msgstr ""
@@ -835,6 +892,12 @@ msgstr ""
msgid "%{timebox_name} should belong either to a project or a group."
msgstr ""
+msgid "%{timebox_type} does not support burnup charts"
+msgstr ""
+
+msgid "%{timebox_type} must have a start and due date"
+msgstr ""
+
msgid "%{title} %{operator} %{threshold}"
msgstr ""
@@ -859,7 +922,7 @@ msgstr ""
msgid "%{total} open issue weight"
msgstr ""
-msgid "%{total} open issues"
+msgid "%{total} warnings found: showing first %{warningsDisplayed}"
msgstr ""
msgid "%{usage_ping_link_start}Learn more%{usage_ping_link_end} about what information is shared with GitLab Inc."
@@ -892,9 +955,6 @@ msgstr ""
msgid "&lt; 1 hour"
msgstr ""
-msgid "&lt;no name set&gt;"
-msgstr ""
-
msgid "&lt;no scopes selected&gt;"
msgstr ""
@@ -925,6 +985,9 @@ msgstr ""
msgid "'%{name}' Value Stream created"
msgstr ""
+msgid "'%{name}' Value Stream deleted"
+msgstr ""
+
msgid "'%{name}' stage already exists"
msgstr ""
@@ -985,6 +1048,9 @@ msgstr ""
msgid "+ %{numberOfHiddenAssignees} more"
msgstr ""
+msgid "+ %{numberOfHiddenReviewers} more"
+msgstr ""
+
msgid "+%d more"
msgid_plural "+%d more"
msgstr[0] ""
@@ -1051,6 +1117,12 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgid "1 Issue"
+msgid_plural "%d Issues"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "1 closed issue"
msgid_plural "%{issues} closed issues"
msgstr[0] ""
@@ -1069,6 +1141,12 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgid "1 deploy key"
+msgid_plural "%d deploy keys"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1180,6 +1258,9 @@ msgstr ""
msgid ":%{startLine} to %{endLine}"
msgstr ""
+msgid "A %{incident_docs_start}modified issue%{incident_docs_end} to guide the resolution of incidents."
+msgstr ""
+
msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr ""
@@ -1192,6 +1273,9 @@ msgstr ""
msgid "A GitBook site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
+msgid "A Gitpod configured Webapplication in Spring and Java"
+msgstr ""
+
msgid "A Hexo site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
@@ -1363,9 +1447,15 @@ msgstr ""
msgid "Access expiration date"
msgstr ""
+msgid "Access expires"
+msgstr ""
+
msgid "Access forbidden. Check your access level."
msgstr ""
+msgid "Access granted"
+msgstr ""
+
msgid "Access requests"
msgstr ""
@@ -1375,6 +1465,9 @@ msgstr ""
msgid "Access to Pages websites are controlled based on the user's membership to a given project. By checking this box, users will be required to be logged in to have access to all Pages websites in your instance."
msgstr ""
+msgid "AccessDropdown|Deploy Keys"
+msgstr ""
+
msgid "AccessDropdown|Groups"
msgstr ""
@@ -1492,12 +1585,6 @@ msgstr ""
msgid "Active Sessions"
msgstr ""
-msgid "Active Users:"
-msgstr ""
-
-msgid "Active users"
-msgstr ""
-
msgid "Activity"
msgstr ""
@@ -1666,9 +1753,6 @@ msgstr ""
msgid "Add label(s)"
msgstr ""
-msgid "Add license"
-msgstr ""
-
msgid "Add list"
msgstr ""
@@ -1843,21 +1927,51 @@ msgstr ""
msgid "AdminArea|Bots"
msgstr ""
+msgid "AdminArea|Components"
+msgstr ""
+
msgid "AdminArea|Developer"
msgstr ""
+msgid "AdminArea|Features"
+msgstr ""
+
+msgid "AdminArea|Groups: %{number_of_groups}"
+msgstr ""
+
msgid "AdminArea|Guest"
msgstr ""
msgid "AdminArea|Included Free in license"
msgstr ""
+msgid "AdminArea|Latest groups"
+msgstr ""
+
+msgid "AdminArea|Latest projects"
+msgstr ""
+
+msgid "AdminArea|Latest users"
+msgstr ""
+
msgid "AdminArea|Maintainer"
msgstr ""
+msgid "AdminArea|New group"
+msgstr ""
+
+msgid "AdminArea|New project"
+msgstr ""
+
+msgid "AdminArea|New user"
+msgstr ""
+
msgid "AdminArea|Owner"
msgstr ""
+msgid "AdminArea|Projects: %{number_of_projects}"
+msgstr ""
+
msgid "AdminArea|Reporter"
msgstr ""
@@ -1885,6 +1999,9 @@ msgstr ""
msgid "AdminArea|Users without a Group and Project"
msgstr ""
+msgid "AdminArea|Users: %{number_of_users}"
+msgstr ""
+
msgid "AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running."
msgstr ""
@@ -1903,9 +2020,6 @@ msgstr ""
msgid "AdminProjects|Delete Project %{projectName}?"
msgstr ""
-msgid "AdminProjects|Delete project"
-msgstr ""
-
msgid "AdminSettings|Apply integration settings to all Projects"
msgstr ""
@@ -2143,21 +2257,30 @@ msgstr ""
msgid "AdminUsers|Without projects"
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 ""
msgid "AdminUsers|You cannot remove your own admin rights."
msgstr ""
+msgid "AdminUsers|You must transfer ownership or delete the groups owned by this user before you can delete their account"
+msgstr ""
+
msgid "Administration"
msgstr ""
msgid "Advanced"
msgstr ""
+msgid "Advanced Search"
+msgstr ""
+
+msgid "Advanced Search with Elasticsearch"
+msgstr ""
+
msgid "Advanced Settings"
msgstr ""
@@ -2236,6 +2359,9 @@ msgstr ""
msgid "AlertManagement|Edit"
msgstr ""
+msgid "AlertManagement|Environment"
+msgstr ""
+
msgid "AlertManagement|Events"
msgstr ""
@@ -2248,6 +2374,9 @@ msgstr ""
msgid "AlertManagement|Issue"
msgstr ""
+msgid "AlertManagement|Key"
+msgstr ""
+
msgid "AlertManagement|Low"
msgstr ""
@@ -2341,6 +2470,9 @@ msgstr ""
msgid "AlertManagement|Unknown"
msgstr ""
+msgid "AlertManagement|Value"
+msgstr ""
+
msgid "AlertManagement|View alerts in Opsgenie"
msgstr ""
@@ -2500,6 +2632,9 @@ msgstr ""
msgid "All projects"
msgstr ""
+msgid "All projects selected"
+msgstr ""
+
msgid "All security scans are enabled because %{linkStart}Auto DevOps%{linkEnd} is enabled on this project"
msgstr ""
@@ -2587,6 +2722,9 @@ msgstr ""
msgid "Almost there"
msgstr ""
+msgid "Already blocked"
+msgstr ""
+
msgid "Also called \"Issuer\" or \"Relying party trust identifier\""
msgstr ""
@@ -2641,6 +2779,9 @@ msgstr ""
msgid "An error has occurred"
msgstr ""
+msgid "An error occured while making the changes: %{error}"
+msgstr ""
+
msgid "An error occurred adding a draft to the thread."
msgstr ""
@@ -2668,12 +2809,6 @@ msgstr ""
msgid "An error occurred when toggling the notification subscription"
msgstr ""
-msgid "An error occurred when trying to resolve a comment. Please try again."
-msgstr ""
-
-msgid "An error occurred when trying to resolve a discussion. Please try again."
-msgstr ""
-
msgid "An error occurred when updating the issue weight"
msgstr ""
@@ -2689,12 +2824,6 @@ msgstr ""
msgid "An error occurred while checking group path. Please refresh and try again."
msgstr ""
-msgid "An error occurred while committing your changes."
-msgstr ""
-
-msgid "An error occurred while creating the list. Please try again."
-msgstr ""
-
msgid "An error occurred while decoding the file."
msgstr ""
@@ -2767,25 +2896,19 @@ msgstr ""
msgid "An error occurred while fetching the Service Desk address."
msgstr ""
-msgid "An error occurred while fetching the board issues. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the board lists. Please reload the page."
msgstr ""
msgid "An error occurred while fetching the board lists. Please try again."
msgstr ""
-msgid "An error occurred while fetching the board swimlanes. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the builds."
msgstr ""
msgid "An error occurred while fetching the job log."
msgstr ""
-msgid "An error occurred while fetching the job trace."
+msgid "An error occurred while fetching the job logs."
msgstr ""
msgid "An error occurred while fetching the job."
@@ -2932,9 +3055,6 @@ msgstr ""
msgid "An error occurred while saving assignees"
msgstr ""
-msgid "An error occurred while saving the template. Please check if the template exists."
-msgstr ""
-
msgid "An error occurred while searching for milestones"
msgstr ""
@@ -2953,10 +3073,10 @@ msgstr ""
msgid "An error occurred while updating approvers"
msgstr ""
-msgid "An error occurred while updating the comment"
+msgid "An error occurred while updating labels."
msgstr ""
-msgid "An error occurred while updating the list. Please try again."
+msgid "An error occurred while updating the comment"
msgstr ""
msgid "An error occurred while validating group path"
@@ -3010,6 +3130,9 @@ msgstr ""
msgid "An unknown error occurred while loading this graph."
msgstr ""
+msgid "An unknown error occurred."
+msgstr ""
+
msgid "Analytics"
msgstr ""
@@ -3043,10 +3166,10 @@ msgstr ""
msgid "Any"
msgstr ""
-msgid "Any Author"
+msgid "Any %{header}"
msgstr ""
-msgid "Any Status"
+msgid "Any Author"
msgstr ""
msgid "Any branch"
@@ -3100,6 +3223,9 @@ msgstr ""
msgid "Application ID"
msgstr ""
+msgid "Application limits saved successfully"
+msgstr ""
+
msgid "Application settings saved successfully"
msgstr ""
@@ -3313,6 +3439,9 @@ msgstr ""
msgid "Are you sure you want to close this blocked issue?"
msgstr ""
+msgid "Are you sure you want to delete \"%{name}\" Value Stream?"
+msgstr ""
+
msgid "Are you sure you want to delete %{name}?"
msgstr ""
@@ -3322,6 +3451,9 @@ msgstr ""
msgid "Are you sure you want to delete this %{typeOfComment}?"
msgstr ""
+msgid "Are you sure you want to delete this SSH key?"
+msgstr ""
+
msgid "Are you sure you want to delete this board?"
msgstr ""
@@ -3346,6 +3478,12 @@ msgstr ""
msgid "Are you sure you want to erase this build?"
msgstr ""
+msgid "Are you sure you want to import %d repository?"
+msgid_plural "Are you sure you want to import %d repositories?"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "Are you sure you want to lose unsaved changes?"
msgstr ""
@@ -3355,15 +3493,15 @@ msgstr ""
msgid "Are you sure you want to merge immediately?"
msgstr ""
-msgid "Are you sure you want to permanently delete this license?"
-msgstr ""
-
msgid "Are you sure you want to re-deploy this environment?"
msgstr ""
msgid "Are you sure you want to regenerate the public key? You will have to update the public key on the remote server before mirroring will work again."
msgstr ""
+msgid "Are you sure you want to reindex?"
+msgstr ""
+
msgid "Are you sure you want to remove %{group_name}?"
msgstr ""
@@ -3391,6 +3529,9 @@ msgstr ""
msgid "Are you sure you want to revoke this nickname?"
msgstr ""
+msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
+msgstr ""
+
msgid "Are you sure you want to stop this environment?"
msgstr ""
@@ -3412,6 +3553,9 @@ msgstr ""
msgid "Are you sure? The device will be signed out of GitLab and all remember me tokens revoked."
msgstr ""
+msgid "Are you sure? This will invalidate your registered applications and U2F / WebAuthn devices."
+msgstr ""
+
msgid "Are you sure? This will invalidate your registered applications and U2F devices."
msgstr ""
@@ -3430,9 +3574,6 @@ msgstr ""
msgid "Artifacts"
msgstr ""
-msgid "As U2F devices are only supported by a few browsers, we require that you set up a two-factor authentication app before a U2F device. That way you'll always be able to log in - even when you're using an unsupported browser."
-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 ""
@@ -3628,6 +3769,9 @@ msgstr ""
msgid "AuditLogs|Target"
msgstr ""
+msgid "AuditLogs|This month"
+msgstr ""
+
msgid "AuditLogs|User Events"
msgstr ""
@@ -3667,6 +3811,9 @@ msgstr ""
msgid "Authentication via U2F device failed."
msgstr ""
+msgid "Authentication via WebAuthn device failed."
+msgstr ""
+
msgid "Author"
msgstr ""
@@ -3934,15 +4081,6 @@ msgstr ""
msgid "BambooService|You must set up automatic revision labeling and a repository trigger in Bamboo."
msgstr ""
-msgid "BatchComments|Delete all pending comments"
-msgstr ""
-
-msgid "BatchComments|Discard review?"
-msgstr ""
-
-msgid "BatchComments|You're about to discard your review which will delete all of your pending comments. The deleted comments %{strong_start}cannot%{strong_end} be restored."
-msgstr ""
-
msgid "Be careful. Changing the project's namespace can have unintended side effects."
msgstr ""
@@ -3964,6 +4102,9 @@ msgstr ""
msgid "Bi-weekly code coverage"
msgstr ""
+msgid "Billable Users:"
+msgstr ""
+
msgid "Billing"
msgstr ""
@@ -3973,7 +4114,7 @@ msgstr ""
msgid "BillingPlans|@%{user_name} you are currently using the %{plan_name} plan."
msgstr ""
-msgid "BillingPlans|Congratulations, your new trial is activated"
+msgid "BillingPlans|Congratulations, your free trial is activated."
msgstr ""
msgid "BillingPlans|If you would like to downgrade your plan please contact %{support_link_start}Customer Support%{support_link_end}."
@@ -4036,6 +4177,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Block user"
+msgstr ""
+
msgid "Blocked"
msgstr ""
@@ -4051,31 +4195,37 @@ msgstr ""
msgid "Blog"
msgstr ""
-msgid "Board name"
-msgstr ""
-
msgid "Board scope"
msgstr ""
msgid "Board scope affects which issues are displayed for anyone who visits this board"
msgstr ""
-msgid "BoardBlankState|Add default lists"
+msgid "Boards"
msgstr ""
-msgid "BoardBlankState|Add the following default lists to your Issue Board with one click:"
+msgid "Boards and Board Lists"
msgstr ""
-msgid "BoardBlankState|Nevermind, I'll use my own"
+msgid "Boards|An error occurred while creating the issue. Please try again."
msgstr ""
-msgid "BoardBlankState|Starting out with the default set of lists will get you right on the way to making the most of your board."
+msgid "Boards|An error occurred while creating the list. Please try again."
msgstr ""
-msgid "Boards"
+msgid "Boards|An error occurred while fetching issues. Please reload the page."
msgstr ""
-msgid "Boards and Board Lists"
+msgid "Boards|An error occurred while fetching the board issues. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching the board swimlanes. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while moving the issue. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while updating the list. Please try again."
msgstr ""
msgid "Boards|Collapse"
@@ -4102,7 +4252,7 @@ msgstr ""
msgid "Branch %{branch_name} was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr ""
-msgid "Branch has changed"
+msgid "Branch changed"
msgstr ""
msgid "Branch is already taken"
@@ -4408,6 +4558,9 @@ msgstr ""
msgid "CLOSED (MOVED)"
msgstr ""
+msgid "CODEOWNERS rule violation"
+msgstr ""
+
msgid "CONTRIBUTING"
msgstr ""
@@ -4438,9 +4591,6 @@ msgstr ""
msgid "Can't create snippet: %{err}"
msgstr ""
-msgid "Can't edit as source branch was deleted"
-msgstr ""
-
msgid "Can't fetch content for the blob: %{err}"
msgstr ""
@@ -4453,9 +4603,6 @@ msgstr ""
msgid "Can't load mermaid module: %{err}"
msgstr ""
-msgid "Can't remove group members without group managed account"
-msgstr ""
-
msgid "Can't scan the code?"
msgstr ""
@@ -4498,6 +4645,9 @@ msgstr ""
msgid "Cannot create the abuse report. This user has been blocked."
msgstr ""
+msgid "Cannot enable shared runners because parent group does not allow it"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -4603,6 +4753,15 @@ msgstr ""
msgid "Change your password or recover your current one"
msgstr ""
+msgid "ChangeReviewer|Reviewer changed from %{old} to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Reviewer changed to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Unassigned"
+msgstr ""
+
msgid "ChangeTypeActionLabel|Pick into branch"
msgstr ""
@@ -4642,6 +4801,9 @@ msgstr ""
msgid "Changes the title to \"%{title_param}\"."
msgstr ""
+msgid "Changes were successfully made."
+msgstr ""
+
msgid "Changes won't take place until the index is %{link_start}recreated%{link_end}."
msgstr ""
@@ -5047,6 +5209,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove variable"
+msgstr ""
+
msgid "CiVariables|Remove variable row"
msgstr ""
@@ -5125,9 +5290,6 @@ msgstr ""
msgid "Clear due date"
msgstr ""
-msgid "Clear input"
-msgstr ""
-
msgid "Clear recent searches"
msgstr ""
@@ -5176,6 +5338,9 @@ msgstr ""
msgid "Client authentication key password"
msgstr ""
+msgid "Client request timeout"
+msgstr ""
+
msgid "Clients"
msgstr ""
@@ -5260,6 +5425,27 @@ msgstr ""
msgid "Cluster type must be specificed for Stages::ClusterEndpointInserter"
msgstr ""
+msgid "ClusterAgents|Configuration"
+msgstr ""
+
+msgid "ClusterAgents|Connect your cluster with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate Kubernetes with a GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Name"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Agent also requires %{linkStart}enabling the Agent Server%{linkEnd}"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Kubernetes Agent allows an Infrastructure as Code, GitOps approach to integrating Kubernetes clusters with GitLab. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "ClusterAgent|This feature is only available for premium plans"
msgstr ""
@@ -5329,10 +5515,10 @@ msgstr ""
msgid "ClusterIntegration|All installed applications and related resources"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster."
+msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{linkStart}More information%{linkEnd}"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{startLink}More information%{endLink}"
+msgid "ClusterIntegration|Allow GitLab to manage namespaces and service accounts for this cluster."
msgstr ""
msgid "ClusterIntegration|Alternatively, "
@@ -5353,6 +5539,9 @@ msgstr ""
msgid "ClusterIntegration|An error occurred while trying to fetch zone machine types: %{error}"
msgstr ""
+msgid "ClusterIntegration|An unknown error occurred while attempting to connect to Kubernetes."
+msgstr ""
+
msgid "ClusterIntegration|Any project namespaces"
msgstr ""
@@ -5368,6 +5557,9 @@ msgstr ""
msgid "ClusterIntegration|Authenticate with Amazon Web Services"
msgstr ""
+msgid "ClusterIntegration|Authentication Error"
+msgstr ""
+
msgid "ClusterIntegration|Base domain"
msgstr ""
@@ -5386,13 +5578,22 @@ msgstr ""
msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}security group %{externalLinkIcon} %{endLink} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
+msgid "ClusterIntegration|Check your CA certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Check your cluster status"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}subnets %{externalLinkIcon} %{endLink} in your VPC where your worker nodes will run."
+msgid "ClusterIntegration|Check your token"
msgstr ""
-msgid "ClusterIntegration|Choose the worker node %{startLink}instance type %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Choose the %{linkStart}security group %{linkEnd} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
+msgstr ""
+
+msgid "ClusterIntegration|Choose the %{linkStart}subnets %{linkEnd} in your VPC where your worker nodes will run."
+msgstr ""
+
+msgid "ClusterIntegration|Choose the worker node %{linkStart}instance type%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Choose which applications to install on your Kubernetes cluster."
@@ -5404,10 +5605,7 @@ msgstr ""
msgid "ClusterIntegration|Clear cluster cache"
msgstr ""
-msgid "ClusterIntegration|Clear the local cache of namespace and service accounts. This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
-msgstr ""
-
-msgid "ClusterIntegration|Cluster being created"
+msgid "ClusterIntegration|Clear the local cache of namespace and service accounts."
msgstr ""
msgid "ClusterIntegration|Cluster management project (alpha)"
@@ -5419,15 +5617,21 @@ msgstr ""
msgid "ClusterIntegration|Cluster_applications artifact too big. Maximum allowable size: %{human_size}"
msgstr ""
-msgid "ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters."
+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|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}"
+msgid "ClusterIntegration|Clusters connected with a certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Connect cluster with certificate"
msgstr ""
msgid "ClusterIntegration|Connect existing cluster"
msgstr ""
+msgid "ClusterIntegration|Connection Error"
+msgstr ""
+
msgid "ClusterIntegration|Copy API URL"
msgstr ""
@@ -5503,6 +5707,12 @@ msgstr ""
msgid "ClusterIntegration|Deletes all GitLab resources attached to this cluster during removal"
msgstr ""
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared."
+msgstr ""
+
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared. %{linkStart}More information%{linkEnd}"
+msgstr ""
+
msgid "ClusterIntegration|Did you know?"
msgstr ""
@@ -5572,6 +5782,9 @@ msgstr ""
msgid "ClusterIntegration|Fluentd is an open source data collector, which lets you unify the data collection and consumption for a better use and understanding of data. It requires at least one of the following logs to be successfully installed."
msgstr ""
+msgid "ClusterIntegration|GitLab Agent managed clusters"
+msgstr ""
+
msgid "ClusterIntegration|GitLab Container Network Policies"
msgstr ""
@@ -5584,6 +5797,12 @@ msgstr ""
msgid "ClusterIntegration|GitLab Runner connects to the repository and executes CI/CD jobs, pushing results back and deploying applications to production."
msgstr ""
+msgid "ClusterIntegration|GitLab failed to authenticate."
+msgstr ""
+
+msgid "ClusterIntegration|GitLab failed to connect to the cluster."
+msgstr ""
+
msgid "ClusterIntegration|GitLab-managed cluster"
msgstr ""
@@ -5605,6 +5824,9 @@ msgstr ""
msgid "ClusterIntegration|Group cluster"
msgstr ""
+msgid "ClusterIntegration|HTTP Error"
+msgstr ""
+
msgid "ClusterIntegration|Helm Tiller"
msgstr ""
@@ -5638,7 +5860,10 @@ msgstr ""
msgid "ClusterIntegration|Instance type"
msgstr ""
-msgid "ClusterIntegration|Integrate Kubernetes cluster automation"
+msgid "ClusterIntegration|Integrate Kubernetes with a cluster certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Integrate with a cluster certificate"
msgstr ""
msgid "ClusterIntegration|Issuer Email"
@@ -5674,9 +5899,6 @@ msgstr ""
msgid "ClusterIntegration|Knative extends Kubernetes to provide a set of middleware components that are essential to build modern, source-centric, and container-based applications that can run anywhere: on premises, in the cloud, or even in a third-party data center."
msgstr ""
-msgid "ClusterIntegration|Kubernetes cluster"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes cluster is being created..."
msgstr ""
@@ -5689,9 +5911,6 @@ msgstr ""
msgid "ClusterIntegration|Kubernetes clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr ""
-msgid "ClusterIntegration|Kubernetes clusters can be used to deploy applications and to provide Review Apps for this project"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes version"
msgstr ""
@@ -5704,7 +5923,7 @@ msgstr ""
msgid "ClusterIntegration|Learn more about %{help_link_start}zones%{help_link_end}."
msgstr ""
-msgid "ClusterIntegration|Learn more about %{startLink}Regions %{externalLinkIcon}%{endLink}."
+msgid "ClusterIntegration|Learn more about %{linkStart}Regions%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Learn more about Kubernetes"
@@ -5749,12 +5968,18 @@ msgstr ""
msgid "ClusterIntegration|Machine type"
msgstr ""
+msgid "ClusterIntegration|Make sure your API endpoint is correct"
+msgstr ""
+
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create Kubernetes clusters"
msgstr ""
msgid "ClusterIntegration|Manage your Kubernetes cluster by visiting %{provider_link}"
msgstr ""
+msgid "ClusterIntegration|Namespace per environment"
+msgstr ""
+
msgid "ClusterIntegration|No IAM Roles found"
msgstr ""
@@ -5800,6 +6025,9 @@ msgstr ""
msgid "ClusterIntegration|No zones matched your search"
msgstr ""
+msgid "ClusterIntegration|Node calculations use the Kubernetes Metrics API. Make sure your cluster has metrics installed"
+msgstr ""
+
msgid "ClusterIntegration|Number of nodes"
msgstr ""
@@ -5842,6 +6070,9 @@ msgstr ""
msgid "ClusterIntegration|RBAC-enabled cluster"
msgstr ""
+msgid "ClusterIntegration|Read our %{linkStart}help page%{linkEnd} on Kubernetes cluster integration."
+msgstr ""
+
msgid "ClusterIntegration|Read our %{link_start}help page%{link_end} on Kubernetes cluster integration."
msgstr ""
@@ -5944,7 +6175,7 @@ msgstr ""
msgid "ClusterIntegration|Select a VPC to choose a subnet"
msgstr ""
-msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{linkStart}Amazon Web Services %{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select a network to choose a subnetwork"
@@ -5977,7 +6208,7 @@ msgstr ""
msgid "ClusterIntegration|Select project to choose zone"
msgstr ""
-msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select zone"
@@ -6067,9 +6298,18 @@ msgstr ""
msgid "ClusterIntegration|There was a problem authenticating with your cluster. Please ensure your CA Certificate and Token are valid."
msgstr ""
+msgid "ClusterIntegration|There was an HTTP error when connecting to your cluster."
+msgstr ""
+
msgid "ClusterIntegration|This account must have permissions to create a Kubernetes cluster in the %{link_to_container_project} specified below"
msgstr ""
+msgid "ClusterIntegration|This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
+msgstr ""
+
+msgid "ClusterIntegration|This is necessary to clear existing environment-namespace associations from clusters previously managed by GitLab."
+msgstr ""
+
msgid "ClusterIntegration|This option will allow you to install applications on RBAC clusters."
msgstr ""
@@ -6094,9 +6334,21 @@ msgstr ""
msgid "ClusterIntegration|To use a new project, first create one on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}."
msgstr ""
+msgid "ClusterIntegration|Troubleshooting tips:"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Authenticate"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Connect"
+msgstr ""
+
msgid "ClusterIntegration|Uninstall %{appTitle}"
msgstr ""
+msgid "ClusterIntegration|Unknown Error"
+msgstr ""
+
msgid "ClusterIntegration|Update %{appTitle}"
msgstr ""
@@ -6157,7 +6409,7 @@ msgstr ""
msgid "ClusterIntegration|Your cluster API is unreachable. Please ensure your API URL is correct."
msgstr ""
-msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Zone"
@@ -6277,6 +6529,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse all threads"
+msgstr ""
+
msgid "Collapse approvers"
msgstr ""
@@ -6427,7 +6682,7 @@ msgstr ""
msgid "Commit…"
msgstr ""
-msgid "Company"
+msgid "Community forum"
msgstr ""
msgid "Company name"
@@ -6436,6 +6691,9 @@ msgstr ""
msgid "Compare"
msgstr ""
+msgid "Compare %{oldCommitId}...%{newCommitId}"
+msgstr ""
+
msgid "Compare Git revisions"
msgstr ""
@@ -6451,6 +6709,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare submodule commit revisions"
+msgstr ""
+
msgid "Compare with previous version"
msgstr ""
@@ -6586,6 +6847,9 @@ msgstr ""
msgid "Configure the way a user creates a new account."
msgstr ""
+msgid "Configure which lists are shown for anyone who visits this board"
+msgstr ""
+
msgid "Confirm"
msgstr ""
@@ -6814,6 +7078,9 @@ msgstr[2] ""
msgid "ContainerRegistry|Set cleanup policy"
msgstr ""
+msgid "ContainerRegistry|Some tags were not deleted"
+msgstr ""
+
msgid "ContainerRegistry|Something went wrong while fetching the cleanup policy."
msgstr ""
@@ -6853,6 +7120,9 @@ msgstr ""
msgid "ContainerRegistry|Tags with names matching this regex pattern will %{italicStart}expire:%{italicEnd}"
msgstr ""
+msgid "ContainerRegistry|The cleanup policy timed out before it could delete all tags. An administrator can %{adminLinkStart}manually run cleanup now%{adminLinkEnd} or you can wait for the cleanup policy to automatically run again. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "ContainerRegistry|The last tag related to this image was recently removed. This empty image and any associated data will be automatically removed as part of the regular Garbage Collection process. If you have any questions, contact your administrator."
msgstr ""
@@ -6985,6 +7255,9 @@ msgstr ""
msgid "Contributions per group member"
msgstr ""
+msgid "Contributor"
+msgstr ""
+
msgid "Contributors"
msgstr ""
@@ -7114,6 +7387,9 @@ msgstr ""
msgid "Could not change HEAD: branch '%{branch}' does not exist"
msgstr ""
+msgid "Could not commit. An unexpected error occurred."
+msgstr ""
+
msgid "Could not connect to FogBugz, check your URL"
msgstr ""
@@ -7153,6 +7429,9 @@ msgstr ""
msgid "Could not find iteration"
msgstr ""
+msgid "Could not load instance counts. Please refresh the page to try again."
+msgstr ""
+
msgid "Could not remove the trigger."
msgstr ""
@@ -7177,10 +7456,10 @@ msgstr ""
msgid "Could not save prometheus manual configuration"
msgstr ""
-msgid "Could not udpdate wiki page"
+msgid "Could not update the LDAP settings"
msgstr ""
-msgid "Could not update the LDAP settings"
+msgid "Could not update wiki page"
msgstr ""
msgid "Could not upload your designs as one or more files uploaded are not supported."
@@ -7840,6 +8119,9 @@ msgstr ""
msgid "DastProfiles|Are you sure you want to delete this profile?"
msgstr ""
+msgid "DastProfiles|Could not create site validation token. Please refresh the page, or try again later."
+msgstr ""
+
msgid "DastProfiles|Could not create the scanner profile. Please try again."
msgstr ""
@@ -7864,6 +8146,12 @@ msgstr ""
msgid "DastProfiles|Could not fetch site profiles. Please refresh the page, or try again later."
msgstr ""
+msgid "DastProfiles|Could not retrieve site validation status. Please refresh the page, or try again later."
+msgstr ""
+
+msgid "DastProfiles|Could not update the scanner profile. Please try again."
+msgstr ""
+
msgid "DastProfiles|Could not update the site profile. Please try again."
msgstr ""
@@ -7879,7 +8167,7 @@ msgstr ""
msgid "DastProfiles|Download validation text file"
msgstr ""
-msgid "DastProfiles|Edit feature will come soon. Please create a new profile if changes needed"
+msgid "DastProfiles|Edit scanner profile"
msgstr ""
msgid "DastProfiles|Edit site profile"
@@ -7912,6 +8200,9 @@ msgstr ""
msgid "DastProfiles|No profiles created yet"
msgstr ""
+msgid "DastProfiles|Passive"
+msgstr ""
+
msgid "DastProfiles|Please enter a valid URL format, ex: http://www.example.com/home"
msgstr ""
@@ -7927,6 +8218,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan mode"
+msgstr ""
+
msgid "DastProfiles|Scanner Profile"
msgstr ""
@@ -7966,10 +8260,10 @@ msgstr ""
msgid "DastProfiles|Text file validation"
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
+msgid "DastProfiles|The maximum number of minutes allowed for the spider to traverse the site."
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the spider to traverse the site."
+msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
msgstr ""
msgid "DastProfiles|Validate"
@@ -8002,6 +8296,9 @@ msgstr ""
msgid "Date picker"
msgstr ""
+msgid "Date range"
+msgstr ""
+
msgid "Date range cannot exceed %{maxDateRange} days."
msgstr ""
@@ -8026,6 +8323,9 @@ msgstr ""
msgid "Days to merge"
msgstr ""
+msgid "Dear Administrator,"
+msgstr ""
+
msgid "Debug"
msgstr ""
@@ -8137,12 +8437,18 @@ msgstr ""
msgid "Delete"
msgstr ""
+msgid "Delete %{name}"
+msgstr ""
+
msgid "Delete Comment"
msgstr ""
msgid "Delete Snippet"
msgstr ""
+msgid "Delete Value Stream"
+msgstr ""
+
msgid "Delete account"
msgstr ""
@@ -8164,9 +8470,6 @@ msgstr ""
msgid "Delete label: %{label_name} ?"
msgstr ""
-msgid "Delete license"
-msgstr ""
-
msgid "Delete list"
msgstr ""
@@ -8242,15 +8545,6 @@ msgstr ""
msgid "Deleting a project places it into a read-only state until %{date}, at which point the project will be permanently deleted. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "Deleting the license failed."
-msgstr ""
-
-msgid "Deleting the license failed. The license was not found."
-msgstr ""
-
-msgid "Deleting the license failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "Deleting the project will delete its repository and all related resources including issues, merge requests etc."
msgstr ""
@@ -8752,7 +9046,10 @@ msgstr ""
msgid "DesignManagement|The maximum number of designs allowed to be uploaded is %{upload_limit}. Please try again."
msgstr ""
-msgid "DesignManagement|To upload designs, you'll need to enable LFS. %{requirements_link_start}More information%{requirements_link_end}"
+msgid "DesignManagement|There was an error moving your designs. Please upload your designs below."
+msgstr ""
+
+msgid "DesignManagement|To upload designs, you'll need to enable LFS and have admin enable hashed storage. %{requirements_link_start}More information%{requirements_link_end}"
msgstr ""
msgid "DesignManagement|Unresolve thread"
@@ -8764,6 +9061,9 @@ msgstr ""
msgid "DesignManagement|Upload skipped."
msgstr ""
+msgid "DesignManagement|Your designs are being copied and are on their way… Please refresh to update."
+msgstr ""
+
msgid "DesignManagement|and %{moreCount} more."
msgstr ""
@@ -8821,6 +9121,9 @@ msgstr ""
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
+msgid "Direct member"
+msgstr ""
+
msgid "Direction"
msgstr ""
@@ -8869,9 +9172,6 @@ msgstr ""
msgid "Discard draft"
msgstr ""
-msgid "Discard review"
-msgstr ""
-
msgid "DiscordService|Discord Notifications"
msgstr ""
@@ -8941,10 +9241,10 @@ msgstr ""
msgid "Dismiss Merge Request promotion"
msgstr ""
-msgid "Dismiss Selected"
+msgid "Dismiss Value Stream Analytics introduction box"
msgstr ""
-msgid "Dismiss Value Stream Analytics introduction box"
+msgid "Dismiss selected"
msgstr ""
msgid "Dismiss trial promotion"
@@ -8995,9 +9295,6 @@ msgstr ""
msgid "Documents reindexed: %{processed_documents} (%{percentage}%%)"
msgstr ""
-msgid "Doing"
-msgstr ""
-
msgid "Domain"
msgstr ""
@@ -9193,9 +9490,6 @@ msgstr ""
msgid "Edit environment"
msgstr ""
-msgid "Edit file"
-msgstr ""
-
msgid "Edit files in the editor and commit changes here"
msgstr ""
@@ -9208,6 +9502,12 @@ msgstr ""
msgid "Edit identity for %{user_name}"
msgstr ""
+msgid "Edit in Web IDE"
+msgstr ""
+
+msgid "Edit in single-file editor"
+msgstr ""
+
msgid "Edit issues"
msgstr ""
@@ -9235,10 +9535,10 @@ msgstr ""
msgid "Editing"
msgstr ""
-msgid "Elasticsearch"
+msgid "Elasticsearch AWS IAM credentials"
msgstr ""
-msgid "Elasticsearch AWS IAM credentials"
+msgid "Elasticsearch HTTP client timeout value in seconds."
msgstr ""
msgid "Elasticsearch indexing restrictions"
@@ -9247,9 +9547,6 @@ msgstr ""
msgid "Elasticsearch indexing started"
msgstr ""
-msgid "Elasticsearch integration. Elasticsearch AWS IAM."
-msgstr ""
-
msgid "Elasticsearch reindexing is already in progress"
msgstr ""
@@ -9277,9 +9574,6 @@ msgstr ""
msgid "Email Notification"
msgstr ""
-msgid "Email address"
-msgstr ""
-
msgid "Email could not be sent"
msgstr ""
@@ -9343,6 +9637,9 @@ msgstr ""
msgid "Emails sent from Service Desk will have this name"
msgstr ""
+msgid "Emails sent to %{email} will still be supported"
+msgstr ""
+
msgid "Emails separated by comma"
msgstr ""
@@ -9376,9 +9673,18 @@ msgstr ""
msgid "Enable"
msgstr ""
+msgid "Enable %{link_start}Gitpod%{link_end} integration to launch a development environment in your browser directly from GitLab."
+msgstr ""
+
msgid "Enable Auto DevOps"
msgstr ""
+msgid "Enable Gitpod"
+msgstr ""
+
+msgid "Enable Gitpod?"
+msgstr ""
+
msgid "Enable HTML emails"
msgstr ""
@@ -9508,9 +9814,6 @@ msgstr ""
msgid "Encountered an error while rendering: %{err}"
msgstr ""
-msgid "End date"
-msgstr ""
-
msgid "Ends at (UTC)"
msgstr ""
@@ -9670,7 +9973,7 @@ msgstr ""
msgid "EnvironmentsDashboard|The environments dashboard provides a summary of each project's environments' status, including pipeline and alert statuses."
msgstr ""
-msgid "EnvironmentsDashboard|This dashboard displays a maximum of 7 projects and 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
+msgid "EnvironmentsDashboard|This dashboard displays 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
msgstr ""
msgid "Environments|An error occurred while canceling the auto stop, please try again"
@@ -9991,6 +10294,9 @@ msgstr ""
msgid "Error deleting project. Check logs for error details."
msgstr ""
+msgid "Error fetching burnup chart data"
+msgstr ""
+
msgid "Error fetching diverging counts for branches. Please try again."
msgstr ""
@@ -10069,6 +10375,9 @@ msgstr ""
msgid "Error occurred when saving assignees"
msgstr ""
+msgid "Error occurred when saving reviewers"
+msgstr ""
+
msgid "Error occurred when toggling the notification subscription"
msgstr ""
@@ -10321,10 +10630,13 @@ msgstr ""
msgid "Expand all"
msgstr ""
-msgid "Expand approvers"
+msgid "Expand all files"
+msgstr ""
+
+msgid "Expand all threads"
msgstr ""
-msgid "Expand dropdown"
+msgid "Expand approvers"
msgstr ""
msgid "Expand milestones"
@@ -10495,6 +10807,9 @@ msgstr ""
msgid "Failed to create Merge Request. Please try again."
msgstr ""
+msgid "Failed to create To-Do for the design."
+msgstr ""
+
msgid "Failed to create a branch for this issue. Please try again."
msgstr ""
@@ -10534,6 +10849,12 @@ msgstr ""
msgid "Failed to load authors. Please try again."
msgstr ""
+msgid "Failed to load branches. Please try again."
+msgstr ""
+
+msgid "Failed to load deploy keys."
+msgstr ""
+
msgid "Failed to load emoji list."
msgstr ""
@@ -10549,6 +10870,9 @@ msgstr ""
msgid "Failed to load groups & users."
msgstr ""
+msgid "Failed to load groups, users and deploy keys."
+msgstr ""
+
msgid "Failed to load labels. Please try again."
msgstr ""
@@ -10558,6 +10882,12 @@ msgstr ""
msgid "Failed to load related branches"
msgstr ""
+msgid "Failed to load sidebar confidential toggle"
+msgstr ""
+
+msgid "Failed to load sidebar lock status"
+msgstr ""
+
msgid "Failed to load stacktrace."
msgstr ""
@@ -10585,6 +10915,9 @@ msgstr ""
msgid "Failed to publish issue on status page."
msgstr ""
+msgid "Failed to remove To-Do for the design."
+msgstr ""
+
msgid "Failed to remove a Zoom meeting"
msgstr ""
@@ -10627,6 +10960,9 @@ msgstr ""
msgid "Failed to signing using smartcard authentication"
msgstr ""
+msgid "Failed to toggle To-Do for the design."
+msgstr ""
+
msgid "Failed to update branch!"
msgstr ""
@@ -10741,7 +11077,7 @@ msgstr ""
msgid "FeatureFlags|Edit User List"
msgstr ""
-msgid "FeatureFlags|Enable features for specific users and specific environments by defining feature flag strategies."
+msgid "FeatureFlags|Enable features for specific users and environments by configuring feature flag strategies."
msgstr ""
msgid "FeatureFlags|Environment Spec"
@@ -10801,7 +11137,7 @@ msgstr ""
msgid "FeatureFlags|Include additional user IDs"
msgstr ""
-msgid "FeatureFlags|Install a %{docs_link_anchored_start}compatible client library%{docs_link_anchored_end} and specify the API URL, application name, and instance ID during the configuration setup. %{docs_link_start}More Information%{docs_link_end}"
+msgid "FeatureFlags|Install a %{docsLinkAnchoredStart}compatible client library%{docsLinkAnchoredEnd} and specify the API URL, application name, and instance ID during the configuration setup. %{docsLinkStart}More Information%{docsLinkEnd}"
msgstr ""
msgid "FeatureFlags|Instance ID"
@@ -10813,6 +11149,9 @@ msgstr ""
msgid "FeatureFlags|Loading feature flags"
msgstr ""
+msgid "FeatureFlags|Loading user lists"
+msgstr ""
+
msgid "FeatureFlags|More information"
msgstr ""
@@ -10831,7 +11170,7 @@ msgstr ""
msgid "FeatureFlags|New feature flag"
msgstr ""
-msgid "FeatureFlags|New list"
+msgid "FeatureFlags|New user list"
msgstr ""
msgid "FeatureFlags|Percent of users"
@@ -10870,6 +11209,9 @@ msgstr ""
msgid "FeatureFlags|There was an error fetching the feature flags."
msgstr ""
+msgid "FeatureFlags|There was an error fetching the user lists."
+msgstr ""
+
msgid "FeatureFlags|There was an error retrieving user lists"
msgstr ""
@@ -10885,6 +11227,9 @@ msgstr ""
msgid "FeatureFlags|User List"
msgstr ""
+msgid "FeatureFlags|User Lists"
+msgstr ""
+
msgid "FeatureFlag|List"
msgstr ""
@@ -10912,15 +11257,6 @@ msgstr ""
msgid "Fetching incoming email"
msgstr ""
-msgid "Fetching licenses failed."
-msgstr ""
-
-msgid "Fetching licenses failed. The request endpoint was not found."
-msgstr ""
-
-msgid "Fetching licenses failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "File"
msgstr ""
@@ -11023,12 +11359,21 @@ msgstr ""
msgid "Filter by status"
msgstr ""
+msgid "Filter by test cases that are currently archived."
+msgstr ""
+
+msgid "Filter by test cases that are currently opened."
+msgstr ""
+
msgid "Filter by two-factor authentication"
msgstr ""
msgid "Filter by user"
msgstr ""
+msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
+msgstr ""
+
msgid "Filter pipelines"
msgstr ""
@@ -11044,7 +11389,7 @@ msgstr ""
msgid "Filter results..."
msgstr ""
-msgid "Filter your projects by name"
+msgid "Filter your repositories by name"
msgstr ""
msgid "Filter..."
@@ -11053,7 +11398,7 @@ msgstr ""
msgid "Find File"
msgstr ""
-msgid "Find bugs in your code with coverage-guided fuzzing"
+msgid "Find bugs in your code with coverage-guided fuzzing."
msgstr ""
msgid "Find by path"
@@ -11080,9 +11425,6 @@ msgstr ""
msgid "Finish editing this message first!"
msgstr ""
-msgid "Finish review"
-msgstr ""
-
msgid "Finish setting up your dedicated account for %{group_name}."
msgstr ""
@@ -11152,6 +11494,9 @@ msgstr ""
msgid "Footer message"
msgstr ""
+msgid "For a faster browsing experience, some files are collapsed by default."
+msgstr ""
+
msgid "For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
@@ -11161,6 +11506,9 @@ msgstr ""
msgid "For more info, read the documentation."
msgstr ""
+msgid "For more information on how the number of active users is calculated, see the %{self_managed_subscriptions_doc_link} documentation."
+msgstr ""
+
msgid "For more information, go to the "
msgstr ""
@@ -11299,6 +11647,9 @@ msgstr ""
msgid "Generate new token"
msgstr ""
+msgid "Generic package file size in bytes"
+msgstr ""
+
msgid "Geo"
msgstr ""
@@ -11560,6 +11911,9 @@ msgstr ""
msgid "Geo|Please refer to Geo Troubleshooting."
msgstr ""
+msgid "Geo|Primary node"
+msgstr ""
+
msgid "Geo|Project"
msgstr ""
@@ -11602,6 +11956,9 @@ msgstr ""
msgid "Geo|Review replication status, and resynchronize and reverify items with the primary node."
msgstr ""
+msgid "Geo|Secondary node"
+msgstr ""
+
msgid "Geo|Status"
msgstr ""
@@ -11641,6 +11998,9 @@ msgstr ""
msgid "Geo|URL must be a valid url (ex: https://gitlab.com)"
msgstr ""
+msgid "Geo|Undefined"
+msgstr ""
+
msgid "Geo|Unknown state"
msgstr ""
@@ -11716,10 +12076,16 @@ msgstr ""
msgid "GitHub import"
msgstr ""
+msgid "GitLab"
+msgstr ""
+
msgid "GitLab / Unsubscribe"
msgstr ""
-msgid "GitLab Enterprise Edition %{plan}"
+msgid "GitLab API"
+msgstr ""
+
+msgid "GitLab Billing Team."
msgstr ""
msgid "GitLab Group Runners can execute code for all the projects in this group."
@@ -11731,12 +12097,18 @@ msgstr ""
msgid "GitLab Issue"
msgstr ""
+msgid "GitLab Pages"
+msgstr ""
+
msgid "GitLab Service Desk is a simple way to allow people to create issues in your GitLab instance without needing their own user account. It provides a unique email address for end users to create issues in a project, and replies can be sent either through the GitLab interface or by email. End users will only see the thread through email."
msgstr ""
msgid "GitLab Shared Runners execute code of different projects on the same Runner unless you configure GitLab Runner Autoscale with MaxBuilds 1 (which it is on GitLab.com)."
msgstr ""
+msgid "GitLab Shell"
+msgstr ""
+
msgid "GitLab Support Bot"
msgstr ""
@@ -11746,7 +12118,7 @@ msgstr ""
msgid "GitLab User"
msgstr ""
-msgid "GitLab allows you to continue using your license even if you exceed the number of seats you purchased. You will be required to pay for these seats when you renew your license."
+msgid "GitLab Workhorse"
msgstr ""
msgid "GitLab commit"
@@ -11914,6 +12286,21 @@ msgstr ""
msgid "Gitlab Pages"
msgstr ""
+msgid "Gitpod"
+msgstr ""
+
+msgid "Gitpod|Add the URL to your Gitpod instance configured to read your GitLab projects."
+msgstr ""
+
+msgid "Gitpod|Enable Gitpod integration"
+msgstr ""
+
+msgid "Gitpod|Gitpod URL"
+msgstr ""
+
+msgid "Gitpod|e.g. https://gitpod.example.com"
+msgstr ""
+
msgid "Given access %{time_ago}"
msgstr ""
@@ -12421,9 +12808,6 @@ msgstr ""
msgid "GroupSAML|Valid SAML Response"
msgstr ""
-msgid "GroupSAML|With group managed accounts enabled, all the users without a group managed account will be excluded from the group."
-msgstr ""
-
msgid "GroupSAML|With prohibit outer forks flag enabled group members will be able to fork project only inside your group."
msgstr ""
@@ -12637,10 +13021,10 @@ msgstr ""
msgid "GroupsNew|Create group"
msgstr ""
-msgid "GroupsNew|GitLab group export"
+msgid "GroupsNew|Import"
msgstr ""
-msgid "GroupsNew|Import"
+msgid "GroupsNew|Import a GitLab group export file"
msgstr ""
msgid "GroupsNew|Import group"
@@ -12784,6 +13168,9 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgid "Hide comments on this file"
+msgstr ""
+
msgid "Hide details"
msgstr ""
@@ -12829,6 +13216,15 @@ msgstr ""
msgid "Highest role:"
msgstr ""
+msgid "HighlightBar|Alert events:"
+msgstr ""
+
+msgid "HighlightBar|Alert start time:"
+msgstr ""
+
+msgid "HighlightBar|Original alert:"
+msgstr ""
+
msgid "History"
msgstr ""
@@ -13006,6 +13402,9 @@ msgstr ""
msgid "If enabled, access to projects will be validated on an external service using their classification label."
msgstr ""
+msgid "If the number of active users exceeds the user limit, you will be charged for the number of %{users_over_license_link} at your next license reconciliation."
+msgstr ""
+
msgid "If there is no previous license or if the previous license has expired, some GitLab functionality will be blocked until a new, valid license is uploaded."
msgstr ""
@@ -13045,9 +13444,6 @@ msgstr ""
msgid "If your HTTP repository is not publicly accessible, add your credentials."
msgstr ""
-msgid "Iglu registry URL (optional)"
-msgstr ""
-
msgid "Ignore"
msgstr ""
@@ -13084,6 +13480,18 @@ msgstr ""
msgid "Import"
msgstr ""
+msgid "Import %d compatible repository"
+msgid_plural "Import %d compatible repositories"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
+msgid "Import %d repository"
+msgid_plural "Import %d repositories"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "Import CSV"
msgstr ""
@@ -13093,15 +13501,9 @@ msgstr ""
msgid "Import all compatible projects"
msgstr ""
-msgid "Import all compatible repositories"
-msgstr ""
-
msgid "Import all projects"
msgstr ""
-msgid "Import all repositories"
-msgstr ""
-
msgid "Import an exported GitLab project"
msgstr ""
@@ -13189,6 +13591,9 @@ msgstr ""
msgid "ImportProjects|Error importing repository %{project_safe_import_url} into %{project_full_path} - %{message}"
msgstr ""
+msgid "ImportProjects|Import repositories"
+msgstr ""
+
msgid "ImportProjects|Importing the project failed"
msgstr ""
@@ -13201,7 +13606,7 @@ msgstr ""
msgid "ImportProjects|Requesting your %{provider} repositories failed"
msgstr ""
-msgid "ImportProjects|Select the projects you want to import"
+msgid "ImportProjects|Select the repositories you want to import"
msgstr ""
msgid "ImportProjects|The remote data could not be imported."
@@ -13237,9 +13642,6 @@ msgstr ""
msgid "In order to enable Service Desk for your instance, you must first set up incoming email."
msgstr ""
-msgid "In order to gather accurate feature usage data, it can take 1 to 2 weeks to see your index."
-msgstr ""
-
msgid "In order to personalize your experience with GitLab%{br_tag}we would like to know a bit more about you."
msgstr ""
@@ -13270,18 +13672,30 @@ msgstr ""
msgid "IncidentManagement|Create incident"
msgstr ""
+msgid "IncidentManagement|Critical - S1"
+msgstr ""
+
msgid "IncidentManagement|Date created"
msgstr ""
msgid "IncidentManagement|Display your incidents in a dedicated view"
msgstr ""
+msgid "IncidentManagement|High - S2"
+msgstr ""
+
msgid "IncidentManagement|Incident"
msgstr ""
msgid "IncidentManagement|Incidents"
msgstr ""
+msgid "IncidentManagement|Low - S4"
+msgstr ""
+
+msgid "IncidentManagement|Medium - S3"
+msgstr ""
+
msgid "IncidentManagement|No incidents to display."
msgstr ""
@@ -13294,6 +13708,9 @@ msgstr ""
msgid "IncidentManagement|Published to status page"
msgstr ""
+msgid "IncidentManagement|Severity"
+msgstr ""
+
msgid "IncidentManagement|There are no closed incidents"
msgstr ""
@@ -13303,6 +13720,9 @@ msgstr ""
msgid "IncidentManagement|Unassigned"
msgstr ""
+msgid "IncidentManagement|Unknown"
+msgstr ""
+
msgid "IncidentManagement|Unpublished"
msgstr ""
@@ -13324,6 +13744,15 @@ msgstr ""
msgid "Incidents"
msgstr ""
+msgid "Incident|Alert details"
+msgstr ""
+
+msgid "Incident|Summary"
+msgstr ""
+
+msgid "Incident|There was an issue loading alert data. Please try again."
+msgstr ""
+
msgid "Include a Terms of Service agreement and Privacy Policy that all users must accept."
msgstr ""
@@ -13384,6 +13813,9 @@ msgstr ""
msgid "Information about additional Pages templates and how to install them can be found in our %{pages_getting_started_guide}."
msgstr ""
+msgid "Inherited"
+msgstr ""
+
msgid "Inherited:"
msgstr ""
@@ -13465,7 +13897,22 @@ msgstr ""
msgid "Instance administrators group already exists"
msgstr ""
-msgid "Instance license"
+msgid "InstanceStatistics|Groups"
+msgstr ""
+
+msgid "InstanceStatistics|Issues"
+msgstr ""
+
+msgid "InstanceStatistics|Merge Requests"
+msgstr ""
+
+msgid "InstanceStatistics|Pipelines"
+msgstr ""
+
+msgid "InstanceStatistics|Projects"
+msgstr ""
+
+msgid "InstanceStatistics|Users"
msgstr ""
msgid "Integration"
@@ -13477,6 +13924,12 @@ msgstr ""
msgid "Integrations"
msgstr ""
+msgid "Integrations|%{integration} settings saved and active."
+msgstr ""
+
+msgid "Integrations|%{integration} settings saved, but not active."
+msgstr ""
+
msgid "Integrations|All details"
msgstr ""
@@ -13486,6 +13939,12 @@ msgstr ""
msgid "Integrations|Comment settings:"
msgstr ""
+msgid "Integrations|Connection failed. Please check your settings."
+msgstr ""
+
+msgid "Integrations|Connection successful."
+msgstr ""
+
msgid "Integrations|Default settings are inherited from the group level."
msgstr ""
@@ -13501,6 +13960,15 @@ msgstr ""
msgid "Integrations|Includes commit title and branch"
msgstr ""
+msgid "Integrations|Projects using custom settings will not be impacted unless the project owner chooses to use instance-level defaults."
+msgstr ""
+
+msgid "Integrations|Save settings?"
+msgstr ""
+
+msgid "Integrations|Saving will update the default settings for all projects that are not using custom settings."
+msgstr ""
+
msgid "Integrations|Standard"
msgstr ""
@@ -13633,6 +14101,9 @@ msgstr ""
msgid "Invitation"
msgstr ""
+msgid "Invitation declined"
+msgstr ""
+
msgid "Invite"
msgstr ""
@@ -13684,6 +14155,42 @@ 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|%{linkStart}Read more%{linkEnd} about role permissions"
+msgstr ""
+
+msgid "InviteMembersModal|Access expiration date (optional)"
+msgstr ""
+
+msgid "InviteMembersModal|Cancel"
+msgstr ""
+
+msgid "InviteMembersModal|Choose a role permission"
+msgstr ""
+
+msgid "InviteMembersModal|GitLab member or Email address"
+msgstr ""
+
+msgid "InviteMembersModal|Invite"
+msgstr ""
+
+msgid "InviteMembersModal|Invite team members"
+msgstr ""
+
+msgid "InviteMembersModal|Search for members to invite"
+msgstr ""
+
+msgid "InviteMembersModal|User not invited. Feature coming soon!"
+msgstr ""
+
+msgid "InviteMembersModal|Users were succesfully added"
+msgstr ""
+
+msgid "InviteMembersModal|You're inviting members to the %{group_name} group"
+msgstr ""
+
+msgid "InviteMembers|Invite team members"
+msgstr ""
+
msgid "Invited"
msgstr ""
@@ -13738,10 +14245,13 @@ msgstr ""
msgid "Issue cannot be found."
msgstr ""
+msgid "Issue created from vulnerability %{vulnerability_link}"
+msgstr ""
+
msgid "Issue events"
msgstr ""
-msgid "Issue first depoloyed to production"
+msgid "Issue first deployed to production"
msgstr ""
msgid "Issue label"
@@ -13819,6 +14329,9 @@ msgstr ""
msgid "IssueTracker|Custom issue tracker"
msgstr ""
+msgid "IssueTracker|EWM work items tracker"
+msgstr ""
+
msgid "IssueTracker|Redmine issue tracker"
msgstr ""
@@ -13885,6 +14398,9 @@ msgstr ""
msgid "It looks like you have some draft commits in this branch."
msgstr ""
+msgid "It may be several days before you see feature usage data."
+msgstr ""
+
msgid "It must have a header row and at least two columns: the first column is the issue title and the second column is the issue description. The separator is automatically detected."
msgstr ""
@@ -14167,13 +14683,13 @@ msgstr ""
msgid "Join Zoom meeting"
msgstr ""
-msgid "Jul"
+msgid "Joined %{time_ago}"
msgstr ""
-msgid "July"
+msgid "Jul"
msgstr ""
-msgid "Jump to first unresolved thread"
+msgid "July"
msgstr ""
msgid "Jump to next unresolved thread"
@@ -14209,6 +14725,9 @@ msgstr ""
msgid "Keyboard shortcuts"
msgstr ""
+msgid "KeyboardKey|Ctrl+"
+msgstr ""
+
msgid "Keys"
msgstr ""
@@ -14257,6 +14776,9 @@ msgstr ""
msgid "LDAP Synchronization"
msgstr ""
+msgid "LDAP group settings"
+msgstr ""
+
msgid "LDAP settings"
msgstr ""
@@ -14266,6 +14788,9 @@ msgstr ""
msgid "LDAP sync in progress. This could take a few minutes. Refresh the page to see the changes."
msgstr ""
+msgid "LDAP synchronizations"
+msgstr ""
+
msgid "LFS"
msgstr ""
@@ -14347,7 +14872,16 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
-msgid "Last %{days} days"
+msgid "Last 2 weeks"
+msgstr ""
+
+msgid "Last 30 days"
+msgstr ""
+
+msgid "Last 60 days"
+msgstr ""
+
+msgid "Last 90 days"
msgstr ""
msgid "Last Accessed On"
@@ -14425,6 +14959,9 @@ msgstr ""
msgid "Last used on:"
msgstr ""
+msgid "Last week"
+msgstr ""
+
msgid "LastCommit|authored"
msgstr ""
@@ -14440,6 +14977,9 @@ msgstr ""
msgid "Latest pipeline for the most recent commit on this branch"
msgstr ""
+msgid "Launch a ready-to-code development environment for your project."
+msgstr ""
+
msgid "Lead"
msgstr ""
@@ -14827,6 +15367,9 @@ msgstr ""
msgid "List of all merge commits"
msgstr ""
+msgid "List options"
+msgstr ""
+
msgid "List settings"
msgstr ""
@@ -14839,9 +15382,6 @@ msgstr ""
msgid "List your Bitbucket Server repositories"
msgstr ""
-msgid "Lists"
-msgstr ""
-
msgid "Live preview"
msgstr ""
@@ -15088,6 +15628,12 @@ msgstr ""
msgid "Mark as done"
msgstr ""
+msgid "Mark as draft"
+msgstr ""
+
+msgid "Mark as ready"
+msgstr ""
+
msgid "Mark as resolved"
msgstr ""
@@ -15109,6 +15655,24 @@ msgstr ""
msgid "Markdown is supported"
msgstr ""
+msgid "MarkdownEditor|Add a link (%{modifierKey}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add a link (%{modifier_key}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifierKey}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifier_key}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifierKey}I)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifier_key}I)"
+msgstr ""
+
msgid "Marked For Deletion At - %{deletion_time}"
msgstr ""
@@ -15193,7 +15757,25 @@ msgstr ""
msgid "Max access level"
msgstr ""
-msgid "Max seats used"
+msgid "Max role"
+msgstr ""
+
+msgid "Max size 15 MB"
+msgstr ""
+
+msgid "Maximum Conan package file size in bytes"
+msgstr ""
+
+msgid "Maximum Maven package file size in bytes"
+msgstr ""
+
+msgid "Maximum NPM package file size in bytes"
+msgstr ""
+
+msgid "Maximum NuGet package file size in bytes"
+msgstr ""
+
+msgid "Maximum PyPI package file size in bytes"
msgstr ""
msgid "Maximum Users:"
@@ -15325,6 +15907,18 @@ msgstr ""
msgid "Members with access to %{strong_start}%{group_name}%{strong_end}"
msgstr ""
+msgid "Members|%{time} by %{user}"
+msgstr ""
+
+msgid "Members|Expired"
+msgstr ""
+
+msgid "Members|No expiration set"
+msgstr ""
+
+msgid "Members|in %{time}"
+msgstr ""
+
msgid "Memory Usage"
msgstr ""
@@ -15511,9 +16105,6 @@ msgstr ""
msgid "MergeRequests|Thread will be unresolved"
msgstr ""
-msgid "MergeRequests|Toggle comments for this file"
-msgstr ""
-
msgid "MergeRequests|View file @ %{commitId}"
msgstr ""
@@ -15574,6 +16165,9 @@ msgstr ""
msgid "Merging immediately isn't recommended as it may negatively impact the existing merge train. Read the %{docsLinkStart}documentation%{docsLinkEnd} for more information."
msgstr ""
+msgid "Message"
+msgstr ""
+
msgid "Messages"
msgstr ""
@@ -15961,18 +16555,12 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
-msgid "Milestone does not support burnup charts"
-msgstr ""
-
msgid "Milestone lists not available with your current license"
msgstr ""
msgid "Milestone lists show all issues from the selected milestone."
msgstr ""
-msgid "Milestone must have a start and due date"
-msgstr ""
-
msgid "MilestoneSidebar|Closed:"
msgstr ""
@@ -16339,6 +16927,9 @@ msgstr ""
msgid "Namespace"
msgstr ""
+msgid "Namespace ID:"
+msgstr ""
+
msgid "Namespace is empty"
msgstr ""
@@ -16423,6 +17014,9 @@ msgstr ""
msgid "NetworkPolicies|Allow all outbound traffic from %{selector} to %{ruleSelector} on %{ports}"
msgstr ""
+msgid "NetworkPolicies|Are you sure you want to delete this policy? This action cannot be undone."
+msgstr ""
+
msgid "NetworkPolicies|Choose whether to enforce this policy."
msgstr ""
@@ -16432,12 +17026,21 @@ msgstr ""
msgid "NetworkPolicies|Define this policy's location, conditions and actions."
msgstr ""
+msgid "NetworkPolicies|Delete policy"
+msgstr ""
+
+msgid "NetworkPolicies|Delete policy: %{policy}"
+msgstr ""
+
msgid "NetworkPolicies|Deny all traffic"
msgstr ""
msgid "NetworkPolicies|Description"
msgstr ""
+msgid "NetworkPolicies|Edit policy"
+msgstr ""
+
msgid "NetworkPolicies|Editor mode"
msgstr ""
@@ -16465,6 +17068,9 @@ msgstr ""
msgid "NetworkPolicies|Name"
msgstr ""
+msgid "NetworkPolicies|Namespace"
+msgstr ""
+
msgid "NetworkPolicies|Network Policy"
msgstr ""
@@ -16516,6 +17122,9 @@ msgstr ""
msgid "NetworkPolicies|Rules"
msgstr ""
+msgid "NetworkPolicies|Save changes"
+msgstr ""
+
msgid "NetworkPolicies|Something went wrong, failed to update policy"
msgstr ""
@@ -16528,6 +17137,9 @@ msgstr ""
msgid "NetworkPolicies|Traffic that does not match any rule will be blocked."
msgstr ""
+msgid "NetworkPolicies|Unable to parse policy"
+msgstr ""
+
msgid "NetworkPolicies|YAML editor"
msgstr ""
@@ -16642,6 +17254,9 @@ msgstr ""
msgid "New Snippet"
msgstr ""
+msgid "New Test Case"
+msgstr ""
+
msgid "New User"
msgstr ""
@@ -16741,6 +17356,9 @@ msgstr ""
msgid "New tag"
msgstr ""
+msgid "New test case"
+msgstr ""
+
msgid "New users set to external"
msgstr ""
@@ -16813,7 +17431,7 @@ msgstr ""
msgid "No changes"
msgstr ""
-msgid "No changes between %{ref_start}%{source_branch}%{ref_end} and %{ref_start}%{target_branch}%{ref_end}"
+msgid "No changes between %{sourceBranch} and %{targetBranch}"
msgstr ""
msgid "No child epics match applied filters"
@@ -16828,6 +17446,9 @@ msgstr ""
msgid "No containers available"
msgstr ""
+msgid "No content to show"
+msgstr ""
+
msgid "No contributions"
msgstr ""
@@ -16903,9 +17524,6 @@ msgstr ""
msgid "No license. All rights reserved"
msgstr ""
-msgid "No licenses found."
-msgstr ""
-
msgid "No matches found"
msgstr ""
@@ -16918,6 +17536,9 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No members found"
+msgstr ""
+
msgid "No merge requests found"
msgstr ""
@@ -16939,6 +17560,9 @@ msgstr ""
msgid "No parent group"
msgstr ""
+msgid "No plan"
+msgstr ""
+
msgid "No pods available"
msgstr ""
@@ -17035,6 +17659,12 @@ msgstr ""
msgid "Not Implemented"
msgstr ""
+msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+msgstr ""
+
+msgid "Not all browsers support WebAuthn. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even from an unsupported browser."
+msgstr ""
+
msgid "Not all data has been processed yet, the accuracy of the chart for the selected timeframe is limited."
msgstr ""
@@ -17131,6 +17761,9 @@ msgstr ""
msgid "Notification settings saved"
msgstr ""
+msgid "NotificationEvent|Change reviewer merge request"
+msgstr ""
+
msgid "NotificationEvent|Close issue"
msgstr ""
@@ -17293,10 +17926,7 @@ msgstr ""
msgid "On track"
msgstr ""
-msgid "OnDemandScans|Attached branch"
-msgstr ""
-
-msgid "OnDemandScans|Attached branch is where the scan job runs."
+msgid "OnDemandScans|Could not fetch scanner profiles. Please refresh the page, or try again later."
msgstr ""
msgid "OnDemandScans|Could not fetch site profiles. Please refresh the page, or try again later."
@@ -17305,6 +17935,9 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
+msgid "OnDemandScans|Create a new scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Create a new site profile"
msgstr ""
@@ -17317,6 +17950,9 @@ msgstr ""
msgid "OnDemandScans|New on-demand DAST scan"
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 ""
@@ -17326,16 +17962,10 @@ msgstr ""
msgid "OnDemandScans|On-demand scans run outside the DevOps cycle and find vulnerabilities in your projects. %{learnMoreLinkStart}Learn more%{learnMoreLinkEnd}"
msgstr ""
-msgid "OnDemandScans|Only a passive scan can be performed on demand."
-msgstr ""
-
-msgid "OnDemandScans|Passive"
-msgstr ""
-
msgid "OnDemandScans|Run scan"
msgstr ""
-msgid "OnDemandScans|Scan mode"
+msgid "OnDemandScans|Scanner profile"
msgstr ""
msgid "OnDemandScans|Scanner settings"
@@ -17347,9 +17977,15 @@ msgstr ""
msgid "OnDemandScans|Select one of the existing profiles"
msgstr ""
+msgid "OnDemandScans|Site profile"
+msgstr ""
+
msgid "OnDemandScans|Site profiles"
msgstr ""
+msgid "OnDemandScans|Use existing scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Use existing site profile"
msgstr ""
@@ -17449,9 +18085,6 @@ msgstr ""
msgid "Open Selection"
msgstr ""
-msgid "Open Web IDE"
-msgstr ""
-
msgid "Open comment type dropdown"
msgstr ""
@@ -17557,6 +18190,9 @@ msgstr ""
msgid "Origin"
msgstr ""
+msgid "Orphaned member"
+msgstr ""
+
msgid "Other Labels"
msgstr ""
@@ -17572,6 +18208,9 @@ msgstr ""
msgid "Other visibility settings have been disabled by the administrator."
msgstr ""
+msgid "Our documentation includes an example DevOps Score report."
+msgstr ""
+
msgid "Out-of-compliance with this project's policies and should be removed"
msgstr ""
@@ -17596,6 +18235,9 @@ msgstr ""
msgid "Overwrite diverged branches"
msgstr ""
+msgid "Owned by %{image_tag}"
+msgstr ""
+
msgid "Owned by anyone"
msgstr ""
@@ -17617,6 +18259,9 @@ msgstr ""
msgid "Package deleted successfully"
msgstr ""
+msgid "Package file size limits"
+msgstr ""
+
msgid "Package recipe already exists"
msgstr ""
@@ -17632,9 +18277,6 @@ msgstr ""
msgid "Package type must be PyPi"
msgstr ""
-msgid "Package was removed"
-msgstr ""
-
msgid "PackageRegistry|%{name} version %{version} was created %{datetime}"
msgstr ""
@@ -17776,12 +18418,18 @@ msgstr ""
msgid "PackageRegistry|NuGet Command"
msgstr ""
+msgid "PackageRegistry|Package Registry"
+msgstr ""
+
msgid "PackageRegistry|Pip Command"
msgstr ""
msgid "PackageRegistry|Pipeline %{link} triggered %{datetime} by %{author}"
msgstr ""
+msgid "PackageRegistry|Publish and share packages for a variety of common package managers. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "PackageRegistry|Published to the %{project} Package Registry %{datetime}"
msgstr ""
@@ -17881,6 +18529,9 @@ msgstr ""
msgid "Page not found"
msgstr ""
+msgid "Page settings"
+msgstr ""
+
msgid "Page was successfully deleted"
msgstr ""
@@ -18022,7 +18673,7 @@ msgstr ""
msgid "Paste issue link"
msgstr ""
-msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Don't use your private SSH key."
+msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Do not paste your private SSH key, as that can compromise your identity."
msgstr ""
msgid "Patch to apply"
@@ -18049,6 +18700,9 @@ msgstr ""
msgid "Pending"
msgstr ""
+msgid "Pending comments"
+msgstr ""
+
msgid "People without permission will never get a notification and won't be able to comment."
msgstr ""
@@ -18247,6 +18901,9 @@ msgstr ""
msgid "Pipelines|Build with confidence"
msgstr ""
+msgid "Pipelines|By revoking a trigger you will break any processes making use of it. Are you sure?"
+msgstr ""
+
msgid "Pipelines|CI Lint"
msgstr ""
@@ -18259,6 +18916,15 @@ msgstr ""
msgid "Pipelines|Continuous Integration can help catch bugs by running your tests automatically, while Continuous Deployment can help you deliver code to your product environment."
msgstr ""
+msgid "Pipelines|Copy trigger token"
+msgstr ""
+
+msgid "Pipelines|Description"
+msgstr ""
+
+msgid "Pipelines|Edit"
+msgstr ""
+
msgid "Pipelines|Get started with Pipelines"
msgstr ""
@@ -18274,15 +18940,27 @@ msgstr ""
msgid "Pipelines|It is recommended the code is reviewed thoroughly before running this pipeline with the parent project's CI resource."
msgstr ""
+msgid "Pipelines|Last Used"
+msgstr ""
+
msgid "Pipelines|Loading Pipelines"
msgstr ""
msgid "Pipelines|More Information"
msgstr ""
+msgid "Pipelines|No triggers have been created yet. Add one using the form above."
+msgstr ""
+
+msgid "Pipelines|Owner"
+msgstr ""
+
msgid "Pipelines|Project cache successfully reset."
msgstr ""
+msgid "Pipelines|Revoke"
+msgstr ""
+
msgid "Pipelines|Run Pipeline"
msgstr ""
@@ -18307,6 +18985,15 @@ msgstr ""
msgid "Pipelines|This project is not currently set up to run pipelines."
msgstr ""
+msgid "Pipelines|Token"
+msgstr ""
+
+msgid "Pipelines|Trigger user has insufficient permissions to project"
+msgstr ""
+
+msgid "Pipelines|invalid"
+msgstr ""
+
msgid "Pipelines|parent"
msgstr ""
@@ -18565,10 +19252,10 @@ msgstr ""
msgid "Please provide attributes to update"
msgstr ""
-msgid "Please refer to %{docs_url}"
+msgid "Please reach out if you have any questions and we'll be happy to assist."
msgstr ""
-msgid "Please retype the email address."
+msgid "Please refer to %{docs_url}"
msgstr ""
msgid "Please select"
@@ -18598,6 +19285,9 @@ msgstr ""
msgid "Please set a new password before proceeding."
msgstr ""
+msgid "Please share your feedback about %{featureName} %{linkStart}in this issue%{linkEnd} to help us improve the experience."
+msgstr ""
+
msgid "Please solve the reCAPTCHA"
msgstr ""
@@ -18901,6 +19591,9 @@ msgstr ""
msgid "Profiles| You are going to change the username %{currentUsernameBold} to %{newUsernameBold}. Profile and projects will be redirected to the %{newUsername} namespace but this redirect will expire once the %{currentUsername} namespace is registered by another user or group. Please update your Git repository remotes as soon as possible."
msgstr ""
+msgid "Profiles|%{provider} Active"
+msgstr ""
+
msgid "Profiles|@username"
msgstr ""
@@ -18952,7 +19645,7 @@ msgstr ""
msgid "Profiles|Commit email"
msgstr ""
-msgid "Profiles|Connect"
+msgid "Profiles|Connect %{provider}"
msgstr ""
msgid "Profiles|Connected Accounts"
@@ -18976,6 +19669,9 @@ msgstr ""
msgid "Profiles|Disconnect"
msgstr ""
+msgid "Profiles|Disconnect %{provider}"
+msgstr ""
+
msgid "Profiles|Do not show on profile"
msgstr ""
@@ -19000,7 +19696,7 @@ msgstr ""
msgid "Profiles|Full name"
msgstr ""
-msgid "Profiles|Give your individual key a title. This will be publically visible."
+msgid "Profiles|Give your individual key a title."
msgstr ""
msgid "Profiles|Include private contributions on my profile"
@@ -19090,7 +19786,7 @@ msgstr ""
msgid "Profiles|The maximum file size allowed is 200KB."
msgstr ""
-msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it?"
+msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it? It will be publicly visible."
msgstr ""
msgid "Profiles|This email will be displayed on your public profile"
@@ -19165,6 +19861,9 @@ msgstr ""
msgid "Profiles|You don't have access to delete this user."
msgstr ""
+msgid "Profiles|You must transfer ownership or delete groups you are an owner of before you can delete your account"
+msgstr ""
+
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
@@ -19753,6 +20452,9 @@ msgstr ""
msgid "ProjectTemplates|GitLab Cluster Management"
msgstr ""
+msgid "ProjectTemplates|Gitpod/Spring Petclinic"
+msgstr ""
+
msgid "ProjectTemplates|Go Micro"
msgstr ""
@@ -20362,6 +21064,9 @@ msgstr ""
msgid "Publish to status page"
msgstr ""
+msgid "Published"
+msgstr ""
+
msgid "Published on status page"
msgstr ""
@@ -20479,9 +21184,15 @@ msgstr ""
msgid "Quick range"
msgstr ""
+msgid "Quickly and easily edit multiple files in your project."
+msgstr ""
+
msgid "README"
msgstr ""
+msgid "Rails"
+msgstr ""
+
msgid "Rake Tasks Help"
msgstr ""
@@ -20602,10 +21313,13 @@ msgstr ""
msgid "Register Two-Factor Authenticator"
msgstr ""
-msgid "Register U2F device"
+msgid "Register Universal Two-Factor (U2F) Device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register WebAuthn Device"
+msgstr ""
+
+msgid "Register device"
msgstr ""
msgid "Register for GitLab"
@@ -20617,9 +21331,6 @@ msgstr ""
msgid "Register with two-factor app"
msgstr ""
-msgid "Registration"
-msgstr ""
-
msgid "Registration|Checkout"
msgstr ""
@@ -20737,9 +21448,6 @@ msgstr ""
msgid "Release|Something went wrong while saving the release details"
msgstr ""
-msgid "Remediated: needs review"
-msgstr ""
-
msgid "Remediations"
msgstr ""
@@ -20845,6 +21553,9 @@ msgstr ""
msgid "Remove priority"
msgstr ""
+msgid "Remove report"
+msgstr ""
+
msgid "Remove secondary node"
msgstr ""
@@ -20857,6 +21568,12 @@ msgstr ""
msgid "Remove time estimate"
msgstr ""
+msgid "Remove user & report"
+msgstr ""
+
+msgid "Remove user from group"
+msgstr ""
+
msgid "Removed"
msgstr ""
@@ -20938,9 +21655,6 @@ msgstr ""
msgid "Removes time estimate."
msgstr ""
-msgid "Removing license…"
-msgstr ""
-
msgid "Removing this group also removes all child projects, including archived projects, and their resources."
msgstr ""
@@ -21025,6 +21739,9 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
+msgid "Reported by %{reporter}"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -21112,6 +21829,27 @@ msgstr ""
msgid "Repositories"
msgstr ""
+msgid "Repositories Analytics"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download Historic Test Coverage Data"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download historic test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Historic Test Coverage Data is available in raw format (.csv) for further analysis."
+msgstr ""
+
+msgid "RepositoriesAnalytics|Test Code Coverage"
+msgstr ""
+
+msgid "RepositoriesAnalytics|There was an error fetching the projects."
+msgstr ""
+
msgid "Repository"
msgstr ""
@@ -21190,9 +21928,15 @@ msgstr ""
msgid "Request parameter %{param} is missing."
msgstr ""
+msgid "Request review from"
+msgstr ""
+
msgid "Request to link SAML account must be authorized"
msgstr ""
+msgid "Requested"
+msgstr ""
+
msgid "Requested %{time_ago}"
msgstr ""
@@ -21211,6 +21955,9 @@ msgstr ""
msgid "Requests to these domain(s)/address(es) on the local network will be allowed when local requests from hooks and services are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 or 127.0.0.0/28 are supported. Domain wildcards are not supported currently. Use comma, semicolon, or newline to separate multiple entries. The allowlist can hold a maximum of 1000 entries. Domains should use IDNA encoding. Ex: example.com, 192.168.1.1, 127.0.0.0/28, xn--itlab-j1a.com."
msgstr ""
+msgid "Require admin approval for new sign-ups"
+msgstr ""
+
msgid "Require all users in this group to setup Two-factor authentication"
msgstr ""
@@ -21340,9 +22087,6 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
-msgid "Resolved by %{resolvedByName}"
-msgstr ""
-
msgid "Resolves IP addresses once and uses them to submit requests"
msgstr ""
@@ -21463,6 +22207,15 @@ msgstr ""
msgid "ReviewApp|Enable Review App"
msgstr ""
+msgid "Reviewer"
+msgid_plural "%d Reviewers"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
+msgid "Reviewer(s)"
+msgstr ""
+
msgid "Reviewing"
msgstr ""
@@ -21502,6 +22255,9 @@ msgstr ""
msgid "Rook"
msgstr ""
+msgid "Ruby"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -21580,6 +22336,63 @@ msgstr ""
msgid "Runners page."
msgstr ""
+msgid "Runners|Active"
+msgstr ""
+
+msgid "Runners|Architecture"
+msgstr ""
+
+msgid "Runners|Can run untagged jobs"
+msgstr ""
+
+msgid "Runners|Description"
+msgstr ""
+
+msgid "Runners|Group"
+msgstr ""
+
+msgid "Runners|IP Address"
+msgstr ""
+
+msgid "Runners|Last contact"
+msgstr ""
+
+msgid "Runners|Locked to this project"
+msgstr ""
+
+msgid "Runners|Maximum job timeout"
+msgstr ""
+
+msgid "Runners|Name"
+msgstr ""
+
+msgid "Runners|Platform"
+msgstr ""
+
+msgid "Runners|Property Name"
+msgstr ""
+
+msgid "Runners|Protected"
+msgstr ""
+
+msgid "Runners|Revision"
+msgstr ""
+
+msgid "Runners|Shared"
+msgstr ""
+
+msgid "Runners|Specific"
+msgstr ""
+
+msgid "Runners|Tags"
+msgstr ""
+
+msgid "Runners|Value"
+msgstr ""
+
+msgid "Runners|Version"
+msgstr ""
+
msgid "Runners|You have used %{quotaUsed} out of %{quotaLimit} of your shared Runners pipeline minutes."
msgstr ""
@@ -21592,6 +22405,9 @@ msgstr ""
msgid "Runs a number of housekeeping tasks within the current repository, such as compressing file revisions and removing unreachable objects."
msgstr ""
+msgid "SAML"
+msgstr ""
+
msgid "SAML SSO"
msgstr ""
@@ -21643,6 +22459,9 @@ msgstr ""
msgid "Save"
msgstr ""
+msgid "Save %{name} size limits"
+msgstr ""
+
msgid "Save Changes"
msgstr ""
@@ -21673,9 +22492,6 @@ msgstr ""
msgid "Save space and find tags in the Container Registry more easily. Enable the cleanup policy to remove stale tags and keep only the ones you need."
msgstr ""
-msgid "Save template"
-msgstr ""
-
msgid "Save variables"
msgstr ""
@@ -21718,9 +22534,6 @@ msgstr ""
msgid "Scope"
msgstr ""
-msgid "Scope not supported with disabled 'users_search' feature!"
-msgstr ""
-
msgid "Scoped issue boards"
msgstr ""
@@ -21847,9 +22660,6 @@ msgstr ""
msgid "Search requirements"
msgstr ""
-msgid "Search results…"
-msgstr ""
-
msgid "Search users"
msgstr ""
@@ -21925,6 +22735,12 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgid "SearchResults|epic"
+msgid_plural "SearchResults|epics"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "SearchResults|issue"
msgid_plural "SearchResults|issues"
msgstr[0] ""
@@ -21976,10 +22792,10 @@ msgstr ""
msgid "Seat Link is disabled, and cannot be configured through this form."
msgstr ""
-msgid "Seats currently in use"
+msgid "Seats usage data as of %{last_enqueue_time}"
msgstr ""
-msgid "Seats in license"
+msgid "Seats usage data is updated every day at 12:00pm UTC"
msgstr ""
msgid "Secondary"
@@ -22033,6 +22849,9 @@ msgstr ""
msgid "SecurityConfiguration|Available for on-demand DAST"
msgstr ""
+msgid "SecurityConfiguration|By default, all analyzers are applied in order to cover all languages across your project, and only run if the language is detected in the Merge Request."
+msgstr ""
+
msgid "SecurityConfiguration|Configure"
msgstr ""
@@ -22063,16 +22882,19 @@ msgstr ""
msgid "SecurityConfiguration|Manage"
msgstr ""
+msgid "SecurityConfiguration|More information"
+msgstr ""
+
msgid "SecurityConfiguration|Not enabled"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|Security Control"
+msgid "SecurityConfiguration|SAST Configuration"
msgstr ""
-msgid "SecurityConfiguration|See documentation"
+msgid "SecurityConfiguration|Security Control"
msgstr ""
msgid "SecurityConfiguration|Status"
@@ -22084,6 +22906,9 @@ msgstr ""
msgid "SecurityConfiguration|Using custom settings. You won't receive automatic updates on this variable. %{anchorStart}Restore to default%{anchorEnd}"
msgstr ""
+msgid "SecurityConfiguration|View history"
+msgstr ""
+
msgid "SecurityConfiguration|You can quickly enable all security scanning tools by enabling %{linkStart}Auto DevOps%{linkEnd}."
msgstr ""
@@ -22162,9 +22987,6 @@ msgstr ""
msgid "SecurityReports|Learn more about setting up your dashboard"
msgstr ""
-msgid "SecurityReports|Load more vulnerabilities"
-msgstr ""
-
msgid "SecurityReports|Monitor vulnerabilities in your code"
msgstr ""
@@ -22444,7 +23266,7 @@ msgstr ""
msgid "Select status"
msgstr ""
-msgid "Select strategy activation method"
+msgid "Select strategy activation method."
msgstr ""
msgid "Select subscription"
@@ -22459,7 +23281,7 @@ msgstr ""
msgid "Select the custom project template source group."
msgstr ""
-msgid "Select timeframe"
+msgid "Select the environment scope for this feature flag."
msgstr ""
msgid "Select timezone"
@@ -22708,6 +23530,9 @@ msgstr ""
msgid "Set iteration"
msgstr ""
+msgid "Set limit to 0 to allow any file size."
+msgstr ""
+
msgid "Set max session time for web terminal."
msgstr ""
@@ -22786,10 +23611,13 @@ msgstr ""
msgid "Set up a %{type} Runner manually"
msgstr ""
+msgid "Set up a hardware device as a second factor to sign in."
+msgstr ""
+
msgid "Set up assertions/attributes/claims (email, first_name, last_name) and NameID according to %{docsLinkStart}the documentation %{icon}%{docsLinkEnd}"
msgstr ""
-msgid "Set up new U2F device"
+msgid "Set up new device"
msgstr ""
msgid "Set up new password"
@@ -22858,6 +23686,9 @@ msgstr ""
msgid "Sets weight to %{weight}."
msgstr ""
+msgid "Setting this to 0 means using the system default timeout value."
+msgstr ""
+
msgid "Settings"
msgstr ""
@@ -22873,6 +23704,15 @@ msgstr ""
msgid "Severity"
msgstr ""
+msgid "SeverityWidget|Severity"
+msgstr ""
+
+msgid "SeverityWidget|Severity: %{severity}"
+msgstr ""
+
+msgid "SeverityWidget|There was an error while updating severity."
+msgstr ""
+
msgid "Shards (%{shards})"
msgstr ""
@@ -22918,6 +23758,9 @@ msgstr ""
msgid "Show all requirements."
msgstr ""
+msgid "Show all test cases."
+msgstr ""
+
msgid "Show archived projects"
msgstr ""
@@ -22930,6 +23773,9 @@ msgstr ""
msgid "Show comments"
msgstr ""
+msgid "Show comments on this file"
+msgstr ""
+
msgid "Show comments only"
msgstr ""
@@ -22975,6 +23821,12 @@ msgstr ""
msgid "Show parent subgroups"
msgstr ""
+msgid "Show the Closed list"
+msgstr ""
+
+msgid "Show the Open list"
+msgstr ""
+
msgid "Show whitespace changes"
msgstr ""
@@ -23020,9 +23872,6 @@ msgstr ""
msgid "Sidebar|Assign health status"
msgstr ""
-msgid "Sidebar|Change weight"
-msgstr ""
-
msgid "Sidebar|Health status"
msgstr ""
@@ -23206,6 +24055,9 @@ msgstr ""
msgid "Snippets|Add another file %{num}/%{total}"
msgstr ""
+msgid "Snippets|Authored %{time_ago} by %{author}"
+msgstr ""
+
msgid "Snippets|Delete file"
msgstr ""
@@ -23233,6 +24085,9 @@ msgstr ""
msgid "Solution"
msgstr ""
+msgid "Some changes are not shown"
+msgstr ""
+
msgid "Some child epics may be hidden due to applied filters"
msgstr ""
@@ -23599,6 +24454,12 @@ msgstr ""
msgid "Source (branch or tag)"
msgstr ""
+msgid "Source Branch"
+msgstr ""
+
+msgid "Source branch: %{source_branch_open}%{source_branch}%{source_branch_close}"
+msgstr ""
+
msgid "Source code"
msgstr ""
@@ -23764,9 +24625,6 @@ msgstr ""
msgid "Start and due date"
msgstr ""
-msgid "Start by choosing a group to see how your team is spending time. You can then drill down to the project level."
-msgstr ""
-
msgid "Start by choosing a group to start exploring the merge requests in that group. You can then proceed to filter by projects, labels, milestones and authors."
msgstr ""
@@ -23848,18 +24706,27 @@ msgstr ""
msgid "StaticSiteEditor|3. Assign a person to review and accept the merge request."
msgstr ""
+msgid "StaticSiteEditor|A link to view the merge request will appear once ready."
+msgstr ""
+
msgid "StaticSiteEditor|An error occurred while submitting your changes."
msgstr ""
msgid "StaticSiteEditor|Branch could not be created."
msgstr ""
+msgid "StaticSiteEditor|Copy update"
+msgstr ""
+
msgid "StaticSiteEditor|Could not commit the content changes."
msgstr ""
msgid "StaticSiteEditor|Could not create merge request."
msgstr ""
+msgid "StaticSiteEditor|Creating your merge request"
+msgstr ""
+
msgid "StaticSiteEditor|Incompatible file content"
msgstr ""
@@ -23881,6 +24748,9 @@ msgstr ""
msgid "StaticSiteEditor|View documentation"
msgstr ""
+msgid "StaticSiteEditor|You can set an assignee to get your changes reviewed and deployed once your merge request is created."
+msgstr ""
+
msgid "StaticSiteEditor|Your merge request has been created"
msgstr ""
@@ -24010,15 +24880,15 @@ msgstr ""
msgid "Submit %{humanized_resource_name}"
msgstr ""
-msgid "Submit Changes"
-msgstr ""
-
msgid "Submit a review"
msgstr ""
msgid "Submit as spam"
msgstr ""
+msgid "Submit changes"
+msgstr ""
+
msgid "Submit feedback"
msgstr ""
@@ -24172,6 +25042,9 @@ msgstr ""
msgid "Successfully deleted U2F device."
msgstr ""
+msgid "Successfully deleted WebAuthn device."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -24490,9 +25363,6 @@ msgstr ""
msgid "Template to append to all Service Desk issues"
msgstr ""
-msgid "Template was successfully saved."
-msgstr ""
-
msgid "Templates"
msgstr ""
@@ -24574,10 +25444,28 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
-msgid "Test failed."
+msgid "Test settings"
+msgstr ""
+
+msgid "TestCases|New Test Case"
+msgstr ""
+
+msgid "TestCases|New test case"
+msgstr ""
+
+msgid "TestCases|Search test cases"
msgstr ""
-msgid "Test settings and save changes"
+msgid "TestCases|Something went wrong while creating a test case."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching count of test cases."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching test cases list."
+msgstr ""
+
+msgid "TestCases|Submit test case"
msgstr ""
msgid "TestHooks|Ensure one of your projects has merge requests."
@@ -24643,6 +25531,9 @@ msgstr ""
msgid "Thank you for signing up for your free trial! You will get additional instructions in your inbox shortly."
msgstr ""
+msgid "Thank you for your business."
+msgstr ""
+
msgid "Thank you for your feedback!"
msgstr ""
@@ -24703,9 +25594,6 @@ msgstr ""
msgid "The URL to use for connecting to Elasticsearch. Use a comma-separated list to support clustering (e.g., \"http://localhost:9200, http://localhost:9201\")."
msgstr ""
-msgid "The Web IDE offers advanced syntax highlighting capabilities and more."
-msgstr ""
-
msgid "The X509 Certificate to use when mutual TLS is required to communicate with the external authorization service. If left blank, the server certificate is still validated when accessing over HTTPS."
msgstr ""
@@ -24817,6 +25705,9 @@ msgstr ""
msgid "The form contains the following error:"
msgstr ""
+msgid "The form contains the following warning:"
+msgstr ""
+
msgid "The global settings require you to enable Two-Factor Authentication for your account."
msgstr ""
@@ -24931,9 +25822,6 @@ msgstr ""
msgid "The private key to use when a client certificate is provided. This value is encrypted at rest."
msgstr ""
-msgid "The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The project can be accessed by any logged in user."
msgstr ""
@@ -24970,7 +25858,7 @@ msgstr ""
msgid "The remote repository is being updated..."
msgstr ""
-msgid "The repository can be commited to, and issues, comments and other entities can be created."
+msgid "The repository can be committed to, and issues, comments and other entities can be created."
msgstr ""
msgid "The repository for this project does not exist."
@@ -25024,9 +25912,6 @@ msgstr ""
msgid "The time taken by each data entry gathered by that stage."
msgstr ""
-msgid "The total stage shows the time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The update action will time out after %{number_of_minutes} minutes. For big repositories, use a clone/push combination."
msgstr ""
@@ -25090,6 +25975,9 @@ msgstr ""
msgid "There are no archived requirements"
msgstr ""
+msgid "There are no archived test cases"
+msgstr ""
+
msgid "There are no changes"
msgstr ""
@@ -25129,6 +26017,9 @@ msgstr ""
msgid "There are no open requirements"
msgstr ""
+msgid "There are no open test cases"
+msgstr ""
+
msgid "There are no packages yet"
msgstr ""
@@ -25141,6 +26032,9 @@ msgstr ""
msgid "There is a limit of %{ci_project_subscriptions_limit} subscriptions from or to a project."
msgstr ""
+msgid "There is already a To-Do for this design."
+msgstr ""
+
msgid "There is already a repository with that name on disk"
msgstr ""
@@ -25159,6 +26053,9 @@ msgstr ""
msgid "There was a problem communicating with your device."
msgstr ""
+msgid "There was a problem fetching branches."
+msgstr ""
+
msgid "There was a problem fetching groups."
msgstr ""
@@ -25387,9 +26284,15 @@ msgstr ""
msgid "This action can lead to data loss. To prevent accidental actions we ask you to confirm your intention."
msgstr ""
+msgid "This action cannot be undone, and will permanently delete the %{key} SSH key"
+msgstr ""
+
msgid "This action cannot be undone. You will lose the project's repository and all content: issues, merge requests, etc."
msgstr ""
+msgid "This action has been performed too many times. Try again later."
+msgstr ""
+
msgid "This action will %{strongOpen}permanently delete%{strongClose} %{codeOpen}%{project}%{codeClose} %{strongOpen}immediately%{strongClose}, including its repositories and all content: issues, merge requests, etc."
msgstr ""
@@ -25417,9 +26320,6 @@ msgstr ""
msgid "This board's scope is reduced"
msgstr ""
-msgid "This branch has changed since you started editing. Would you like to create a new branch?"
-msgstr ""
-
msgid "This chart could not be displayed"
msgstr ""
@@ -25546,15 +26446,9 @@ msgstr ""
msgid "This is a security log of important events involving your account."
msgstr ""
-msgid "This is the author's first Merge Request to this project."
-msgstr ""
-
msgid "This is the highest peak of users on your installation since the license started."
msgstr ""
-msgid "This is the maximum number of users that have existed at the same time since the license started. This is the minimum number of seats you will need to buy when you renew your license."
-msgstr ""
-
msgid "This is the number of currently active users on your installation, and this is the minimum number you need to purchase when you renew your license."
msgstr ""
@@ -25786,6 +26680,15 @@ msgstr ""
msgid "This user has no identities"
msgstr ""
+msgid "This user has previously committed to the %{name} project."
+msgstr ""
+
+msgid "This user has the %{access} role in the %{name} project."
+msgstr ""
+
+msgid "This user is the author of this %{noteable}."
+msgstr ""
+
msgid "This user will be the author of all events in the activity feed that are the result of an update, like new branches being created or new commits being pushed to existing branches."
msgstr ""
@@ -25816,6 +26719,9 @@ msgstr ""
msgid "Threat Monitoring"
msgstr ""
+msgid "ThreatMonitoring|All Environments"
+msgstr ""
+
msgid "ThreatMonitoring|Anomalous Requests"
msgstr ""
@@ -25843,9 +26749,6 @@ msgstr ""
msgid "ThreatMonitoring|Operations Per Second"
msgstr ""
-msgid "ThreatMonitoring|Overview"
-msgstr ""
-
msgid "ThreatMonitoring|Packet Activity"
msgstr ""
@@ -25864,6 +26767,9 @@ msgstr ""
msgid "ThreatMonitoring|Something went wrong, unable to fetch statistics"
msgstr ""
+msgid "ThreatMonitoring|Statistics"
+msgstr ""
+
msgid "ThreatMonitoring|The firewall is not installed or has been disabled. To view this data, ensure the web application firewall is installed and enabled for your cluster."
msgstr ""
@@ -26257,6 +27163,9 @@ msgstr ""
msgid "To update Snippets with multiple files, you must use the `files` parameter"
msgstr ""
+msgid "To use Gitpod you must first enable the feature in the integrations section of your %{user_prefs}."
+msgstr ""
+
msgid "To view all %{scannedResourcesCount} scanned URLs, please download the CSV file"
msgstr ""
@@ -26290,9 +27199,6 @@ msgstr ""
msgid "Toggle Sidebar"
msgstr ""
-msgid "Toggle all threads"
-msgstr ""
-
msgid "Toggle backtrace"
msgstr ""
@@ -26317,9 +27223,6 @@ msgstr ""
msgid "Toggle navigation"
msgstr ""
-msgid "Toggle project"
-msgstr ""
-
msgid "Toggle sidebar"
msgstr ""
@@ -26359,6 +27262,9 @@ msgstr ""
msgid "Too many projects enabled. You will need to manage them via the console or the API."
msgstr ""
+msgid "Too much data"
+msgstr ""
+
msgid "Topics (optional)"
msgstr ""
@@ -26377,6 +27283,9 @@ msgstr ""
msgid "Total cores (CPUs)"
msgstr ""
+msgid "Total days to completion"
+msgstr ""
+
msgid "Total issues"
msgstr ""
@@ -26473,6 +27382,9 @@ msgstr ""
msgid "Trending"
msgstr ""
+msgid "Trials|Create a new group to start your GitLab Gold trial."
+msgstr ""
+
msgid "Trials|Go back to GitLab"
msgstr ""
@@ -26482,6 +27394,15 @@ msgstr ""
msgid "Trials|You can always resume this process by selecting your avatar and choosing 'Start a Gold trial'"
msgstr ""
+msgid "Trials|You can apply your trial to a new group or an existing group."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group or your personal account."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group, an existing group, or your personal account."
+msgstr ""
+
msgid "Trials|You won't get a free trial right now but you can always resume this process by clicking on your avatar and choosing 'Start a free trial'"
msgstr ""
@@ -26551,6 +27472,9 @@ msgstr ""
msgid "Try using a different search term to find the file you are looking for."
msgstr ""
+msgid "Trying to communicate with your device. Plug it in (if needed) and press the button on the device now."
+msgstr ""
+
msgid "Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now."
msgstr ""
@@ -26638,6 +27562,12 @@ msgstr ""
msgid "URL or request ID"
msgstr ""
+msgid "USER %{user} WILL BE REMOVED! Are you sure?"
+msgstr ""
+
+msgid "USER WILL BE BLOCKED! Are you sure?"
+msgstr ""
+
msgid "UTC"
msgstr ""
@@ -26695,9 +27625,6 @@ msgstr ""
msgid "Unable to load the merge request widget. Try reloading the page."
msgstr ""
-msgid "Unable to resolve"
-msgstr ""
-
msgid "Unable to save iteration. Please try again"
msgstr ""
@@ -26746,6 +27673,9 @@ msgstr ""
msgid "Undo ignore"
msgstr ""
+msgid "Unexpected error"
+msgstr ""
+
msgid "Unfortunately, your email message to GitLab could not be processed."
msgstr ""
@@ -26779,6 +27709,9 @@ msgstr ""
msgid "Unknown response text"
msgstr ""
+msgid "Unless otherwise agreed to in writing with GitLab, by clicking \"Upload License\" you agree that your use of GitLab Software is subject to the %{eula_link_start}Terms of Service%{eula_link_end}."
+msgstr ""
+
msgid "Unlimited"
msgstr ""
@@ -27145,9 +28078,6 @@ msgstr ""
msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
msgstr ""
-msgid "Use a hardware device to add the second factor of authentication."
-msgstr ""
-
msgid "Use an one time password authenticator on your mobile device or computer to enable two-factor authentication (2FA)."
msgstr ""
@@ -27421,13 +28351,13 @@ msgstr ""
msgid "Users"
msgstr ""
-msgid "Users in License:"
+msgid "Users in License"
msgstr ""
-msgid "Users or groups set as approvers in the project's or merge request's settings."
+msgid "Users in License:"
msgstr ""
-msgid "Users outside of license"
+msgid "Users or groups set as approvers in the project's or merge request's settings."
msgstr ""
msgid "Users over License:"
@@ -27445,9 +28375,6 @@ msgstr ""
msgid "Users with a Guest role or those who don't belong to a Project or Group will not use a seat from your license."
msgstr ""
-msgid "Users with a Guest role or those who don't belong to any projects or groups don't count towards seats in use."
-msgstr ""
-
msgid "UsersSelect|%{name} + %{length} more"
msgstr ""
@@ -27487,9 +28414,6 @@ msgstr ""
msgid "Validations failed."
msgstr ""
-msgid "Validity"
-msgstr ""
-
msgid "Value"
msgstr ""
@@ -27508,6 +28432,9 @@ msgstr ""
msgid "Value Stream Name"
msgstr ""
+msgid "ValueStreamAnalyticsStage|We don't have enough data to show this stage."
+msgstr ""
+
msgid "ValueStreamAnalytics|%{days}d"
msgstr ""
@@ -27766,6 +28693,9 @@ msgstr ""
msgid "VisualReviewApp|Steps 1 and 2 (and sometimes 3) are performed once by the developer before requesting feedback. Steps 3 (if necessary), 4 is performed by the reviewer each time they perform a review."
msgstr ""
+msgid "Visualization"
+msgstr ""
+
msgid "Vulnerabilities"
msgstr ""
@@ -27793,34 +28723,31 @@ msgstr ""
msgid "VulnerabilityChart|Severity"
msgstr ""
-msgid "VulnerabilityManagement|A true-positive and will fix"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Change status"
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|Confirm"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Confirmed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
-msgstr ""
-
-msgid "VulnerabilityManagement|Detected %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|A true-positive and will fix"
msgstr ""
-msgid "VulnerabilityManagement|Dismiss"
+msgid "VulnerabilityManagement|Change status"
msgstr ""
-msgid "VulnerabilityManagement|Dismissed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
msgstr ""
-msgid "VulnerabilityManagement|Resolved"
+msgid "VulnerabilityManagement|Detected"
msgstr ""
-msgid "VulnerabilityManagement|Resolved %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Needs triage"
msgstr ""
msgid "VulnerabilityManagement|Something went wrong while trying to delete the comment. Please try again later."
@@ -27871,6 +28798,9 @@ msgstr ""
msgid "Vulnerability|%{scannerName} (version %{scannerVersion})"
msgstr ""
+msgid "Vulnerability|Activity"
+msgstr ""
+
msgid "Vulnerability|Class"
msgstr ""
@@ -27883,6 +28813,9 @@ msgstr ""
msgid "Vulnerability|Description"
msgstr ""
+msgid "Vulnerability|Detected"
+msgstr ""
+
msgid "Vulnerability|Evidence"
msgstr ""
@@ -27946,6 +28879,9 @@ msgstr ""
msgid "Warning: Displaying this diagram might cause performance issues on this page."
msgstr ""
+msgid "We are currently unable to fetch data for the pipeline header."
+msgstr ""
+
msgid "We are currently unable to fetch data for this graph."
msgstr ""
@@ -27985,6 +28921,12 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
+msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
+msgstr ""
+
+msgid "We would like to inform you that your subscription GitLab Enterprise Edition %{plan_name} is nearing its user limit. You have %{active_user_count} active users, which is almost at the user limit of %{maximum_user_count}."
+msgstr ""
+
msgid "We've found no vulnerabilities"
msgstr ""
@@ -28000,6 +28942,12 @@ msgstr ""
msgid "Web terminal"
msgstr ""
+msgid "WebAuthn Devices (%{length})"
+msgstr ""
+
+msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
+msgstr ""
+
msgid "WebIDE|Merge request"
msgstr ""
@@ -28138,15 +29086,9 @@ msgstr ""
msgid "Welcome to the guided GitLab tour"
msgstr ""
-msgid "Welcome to your Issue Board!"
-msgstr ""
-
msgid "Welcome to your issue board!"
msgstr ""
-msgid "We’ve been making changes to %{featureName} and we’d love your feedback %{linkStart}in this issue%{linkEnd} to help us improve the experience."
-msgstr ""
-
msgid "What are you searching for?"
msgstr ""
@@ -28165,6 +29107,9 @@ msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
msgstr ""
+msgid "When enabled, any user visiting %{host} and creating an account will have to be explicitly approved by the admin before they can login. This setting is effective only if sign-ups are enabled."
+msgstr ""
+
msgid "When enabled, any user visiting %{host} will be able to create an account."
msgstr ""
@@ -28390,6 +29335,9 @@ msgstr ""
msgid "With requirements, you can set criteria to check your products against."
msgstr ""
+msgid "With test cases, you can define conditions for your project to meet in determining quality"
+msgstr ""
+
msgid "Withdraw Access Request"
msgstr ""
@@ -28405,6 +29353,9 @@ msgstr ""
msgid "Workflow Help"
msgstr ""
+msgid "Would you like to create a new branch?"
+msgstr ""
+
msgid "Write"
msgstr ""
@@ -28426,6 +29377,9 @@ msgstr ""
msgid "Wrong extern UID provided. Make sure Auth0 is configured correctly."
msgstr ""
+msgid "YYYY-MM-DD"
+msgstr ""
+
msgid "Yes"
msgstr ""
@@ -28483,7 +29437,7 @@ msgstr ""
msgid "You are going to remove the fork relationship from %{project_full_name}. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "You are going to transfer %{project_full_name} to another owner. Are you ABSOLUTELY sure?"
+msgid "You are going to transfer %{project_full_name} to another namespace. Are you ABSOLUTELY sure?"
msgstr ""
msgid "You are going to turn off the confidentiality. This means %{strongStart}everyone%{strongEnd} will be able to see and leave a comment on this %{issuableType}."
@@ -28543,9 +29497,6 @@ msgstr ""
msgid "You can always edit this later"
msgstr ""
-msgid "You can apply your Trial to your Personal account or create a New Group."
-msgstr ""
-
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings"
msgstr ""
@@ -28567,12 +29518,18 @@ msgstr ""
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
+msgid "You can find more information about GitLab subscriptions in %{subscriptions_doc_link}."
+msgstr ""
+
msgid "You can generate an access token scoped to this project for each application to use the GitLab API."
msgstr ""
msgid "You can get started by cloning the repository or start adding files to it with one of the following options."
msgstr ""
+msgid "You can group test cases using labels. To learn about the future direction of this feature, visit %{linkStart}Quality Management direction page%{linkEnd}."
+msgstr ""
+
msgid "You can invite a new member to %{project_name} or invite another group."
msgstr ""
@@ -28588,6 +29545,9 @@ msgstr ""
msgid "You can notify the app / group or a project by sending them an email notification"
msgstr ""
+msgid "You can now close this window."
+msgstr ""
+
msgid "You can now export your security dashboard to a CSV report."
msgstr ""
@@ -28636,9 +29596,6 @@ msgstr ""
msgid "You can test your .gitlab-ci.yml in %{linkStart}CI Lint%{linkEnd}."
msgstr ""
-msgid "You can try again using %{begin_link}basic search%{end_link}"
-msgstr ""
-
msgid "You cannot access the raw file. Please wait a minute."
msgstr ""
@@ -28690,6 +29647,9 @@ msgstr ""
msgid "You don't have any U2F devices registered yet."
msgstr ""
+msgid "You don't have any WebAuthn devices registered yet."
+msgstr ""
+
msgid "You don't have any active chat names."
msgstr ""
@@ -28777,6 +29737,9 @@ msgstr ""
msgid "You must accept our Terms of Service and privacy policy in order to register an account"
msgstr ""
+msgid "You must be logged in to search across all of GitLab"
+msgstr ""
+
msgid "You must disassociate %{domain} from all clusters it is attached to before deletion."
msgstr ""
@@ -28816,7 +29779,7 @@ msgstr ""
msgid "You need to be logged in."
msgstr ""
-msgid "You need to register a two-factor authentication app before you can set up a U2F device."
+msgid "You need to register a two-factor authentication app before you can set up a device."
msgstr ""
msgid "You need to set terms to be enforced"
@@ -28834,6 +29797,9 @@ msgstr ""
msgid "You reached %{usage_in_percent} of %{namespace_name}'s storage capacity (%{used_storage} of %{storage_limit})"
msgstr ""
+msgid "You successfully declined the invitation"
+msgstr ""
+
msgid "You tried to fork %{link_to_the_project} but it failed for the following reason:"
msgstr ""
@@ -28999,10 +29965,13 @@ msgstr ""
msgid "Your U2F device did not send a valid JSON response."
msgstr ""
-msgid "Your U2F device needs to be set up. Plug it in (if not already) and click the button on the left."
+msgid "Your U2F device was registered!"
+msgstr ""
+
+msgid "Your WebAuthn device did not send a valid JSON response."
msgstr ""
-msgid "Your U2F device was registered!"
+msgid "Your WebAuthn device was registered!"
msgstr ""
msgid "Your access request to the %{source_type} has been withdrawn."
@@ -29026,6 +29995,9 @@ msgstr ""
msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
msgstr ""
+msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
+msgstr ""
+
msgid "Your changes can be committed to %{branch_name} because a merge request is open."
msgstr ""
@@ -29062,6 +30034,12 @@ msgstr ""
msgid "Your deployment services will be broken, you will need to manually fix the services after renaming."
msgstr ""
+msgid "Your device is not compatible with GitLab. Please try another device"
+msgstr ""
+
+msgid "Your device needs to be set up. Plug it in (if needed) and click the button on the left."
+msgstr ""
+
msgid "Your device was successfully set up! Give it a name and register it with the GitLab server."
msgstr ""
@@ -29176,9 +30154,6 @@ msgstr[2] ""
msgid "access:"
msgstr ""
-msgid "activated"
-msgstr ""
-
msgid "added %{created_at_timeago}"
msgstr ""
@@ -29251,9 +30226,21 @@ msgstr ""
msgid "by %{user}"
msgstr ""
+msgid "cannot be a date in the past"
+msgstr ""
+
msgid "cannot be changed if a personal project has container registry tags."
msgstr ""
+msgid "cannot be changed if shared runners are enabled"
+msgstr ""
+
+msgid "cannot be enabled because parent group does not allow it"
+msgstr ""
+
+msgid "cannot be enabled because parent group has shared Runners disabled"
+msgstr ""
+
msgid "cannot be enabled unless all domains have TLS certificates"
msgstr ""
@@ -29299,7 +30286,7 @@ msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about SAST %{linkEndTag}"
msgstr ""
-msgid "ciReport|%{linkStartTag}Learn more about Secret Scanning %{linkEndTag}"
+msgid "ciReport|%{linkStartTag}Learn more about Secret Detection %{linkEndTag}"
msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about codequality reports %{linkEndTag}"
@@ -29617,9 +30604,6 @@ msgstr ""
msgid "error"
msgstr ""
-msgid "error code:"
-msgstr ""
-
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr ""
@@ -29641,6 +30625,9 @@ msgstr ""
msgid "failed to dismiss associated finding(id=%{finding_id}): %{message}"
msgstr ""
+msgid "failed to revert associated finding(id=%{finding_id}) to detected"
+msgstr ""
+
msgid "file"
msgid_plural "files"
msgstr[0] ""
@@ -30187,6 +31174,9 @@ msgstr ""
msgid "must be a root namespace"
msgstr ""
+msgid "must be a valid IPv4 or IPv6 address"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -30223,6 +31213,9 @@ msgstr ""
msgid "no expiration"
msgstr ""
+msgid "no name set"
+msgstr ""
+
msgid "no one can merge"
msgstr ""
@@ -30406,9 +31399,6 @@ msgstr ""
msgid "security Reports|There was an error creating the merge request"
msgstr ""
-msgid "settings saved, but not activated"
-msgstr ""
-
msgid "severity|Critical"
msgstr ""
@@ -30535,9 +31525,6 @@ msgstr ""
msgid "toggle collapse"
msgstr ""
-msgid "toggle dropdown"
-msgstr ""
-
msgid "triggered"
msgstr ""
@@ -30565,6 +31552,9 @@ msgstr ""
msgid "user avatar"
msgstr ""
+msgid "user preferences"
+msgstr ""
+
msgid "username"
msgstr ""
diff --git a/locale/sr_SP/gitlab.po b/locale/sr_SP/gitlab.po
index 0bd37acc6bf..5a1ed95156c 100644
--- a/locale/sr_SP/gitlab.po
+++ b/locale/sr_SP/gitlab.po
@@ -14,7 +14,10 @@ msgstr ""
"X-Crowdin-Language: sr\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 6\n"
-"PO-Revision-Date: 2020-09-04 23:10\n"
+"PO-Revision-Date: 2020-10-02 18:50\n"
+
+msgid " %{project_name}#%{issue_iid} &middot; opened %{issue_created} by %{author}"
+msgstr ""
msgid " %{start} to %{end}"
msgstr ""
@@ -76,6 +79,18 @@ msgstr ""
msgid "\"el\" parameter is required for createInstance()"
msgstr ""
+msgid "%d Approval"
+msgid_plural "%d Approvals"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
+msgid "%d Package"
+msgid_plural "%d Packages"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "%d Scanned URL"
msgid_plural "%d Scanned URLs"
msgstr[0] ""
@@ -151,6 +166,12 @@ msgstr[2] ""
msgid "%d commits"
msgstr ""
+msgid "%d completed issue"
+msgid_plural "%d completed issues"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "%d contribution"
msgid_plural "%d contributions"
msgstr[0] ""
@@ -163,6 +184,12 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgid "%d day until tags are automatically removed"
+msgid_plural "%d days until tags are automatically removed"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "%d error"
msgid_plural "%d errors"
msgstr[0] ""
@@ -271,6 +298,18 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgid "%d open issue"
+msgid_plural "%d open issues"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
+msgid "%d pending comment"
+msgid_plural "%d pending comments"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "%d personal project will be removed and cannot be restored."
msgid_plural "%d personal projects will be removed and cannot be restored."
msgstr[0] ""
@@ -289,6 +328,12 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgid "%d project selected"
+msgid_plural "%d projects selected"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "%d request with warnings"
msgid_plural "%d requests with warnings"
msgstr[0] ""
@@ -313,6 +358,12 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgid "%d tag per image name"
+msgid_plural "%d tags per image name"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "%d unassigned issue"
msgid_plural "%d unassigned issues"
msgstr[0] ""
@@ -337,6 +388,12 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgid "%d warning found:"
+msgid_plural "%d warnings found:"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "%s additional commit has been omitted to prevent performance issues."
msgid_plural "%s additional commits have been omitted to prevent performance issues."
msgstr[0] ""
@@ -376,6 +433,9 @@ msgstr ""
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr ""
+msgid "%{completedCount} completed weight"
+msgstr ""
+
msgid "%{completedWeight} of %{totalWeight} weight completed"
msgstr ""
@@ -427,15 +487,12 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
-msgid "%{count} pending comment"
-msgid_plural "%{count} pending comments"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
+msgid "%{count} total weight"
+msgstr ""
+
msgid "%{dashboard_path} could not be found."
msgstr ""
@@ -490,6 +547,9 @@ msgstr ""
msgid "%{group_name} uses group managed accounts. You need to create a new GitLab account which will be managed by %{group_name}."
msgstr ""
+msgid "%{group_name}&%{epic_iid} &middot; opened %{epic_created} by %{author}"
+msgstr ""
+
msgid "%{host} sign-in from new location"
msgstr ""
@@ -502,7 +562,7 @@ msgstr ""
msgid "%{issuableType} will be removed! Are you sure?"
msgstr ""
-msgid "%{issuesSize} issues with a limit of %{maxIssueCount}"
+msgid "%{issuesCount} issues with a limit of %{maxIssueCount}"
msgstr ""
msgid "%{issuesSize} with a limit of %{maxIssueCount}"
@@ -535,7 +595,7 @@ msgstr ""
msgid "%{labelStart}Namespace:%{labelEnd} %{namespace}"
msgstr ""
-msgid "%{labelStart}Report Type:%{labelEnd} %{reportType}"
+msgid "%{labelStart}Scan Type:%{labelEnd} %{reportType}"
msgstr ""
msgid "%{labelStart}Scanner:%{labelEnd} %{scanner}"
@@ -739,9 +799,6 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
-msgid "%{service_title} %{message}."
-msgstr ""
-
msgid "%{size} GiB"
msgstr ""
@@ -835,6 +892,12 @@ msgstr ""
msgid "%{timebox_name} should belong either to a project or a group."
msgstr ""
+msgid "%{timebox_type} does not support burnup charts"
+msgstr ""
+
+msgid "%{timebox_type} must have a start and due date"
+msgstr ""
+
msgid "%{title} %{operator} %{threshold}"
msgstr ""
@@ -859,7 +922,7 @@ msgstr ""
msgid "%{total} open issue weight"
msgstr ""
-msgid "%{total} open issues"
+msgid "%{total} warnings found: showing first %{warningsDisplayed}"
msgstr ""
msgid "%{usage_ping_link_start}Learn more%{usage_ping_link_end} about what information is shared with GitLab Inc."
@@ -892,9 +955,6 @@ msgstr ""
msgid "&lt; 1 hour"
msgstr ""
-msgid "&lt;no name set&gt;"
-msgstr ""
-
msgid "&lt;no scopes selected&gt;"
msgstr ""
@@ -925,6 +985,9 @@ msgstr ""
msgid "'%{name}' Value Stream created"
msgstr ""
+msgid "'%{name}' Value Stream deleted"
+msgstr ""
+
msgid "'%{name}' stage already exists"
msgstr ""
@@ -985,6 +1048,9 @@ msgstr ""
msgid "+ %{numberOfHiddenAssignees} more"
msgstr ""
+msgid "+ %{numberOfHiddenReviewers} more"
+msgstr ""
+
msgid "+%d more"
msgid_plural "+%d more"
msgstr[0] ""
@@ -1051,6 +1117,12 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgid "1 Issue"
+msgid_plural "%d Issues"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "1 closed issue"
msgid_plural "%{issues} closed issues"
msgstr[0] ""
@@ -1069,6 +1141,12 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgid "1 deploy key"
+msgid_plural "%d deploy keys"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1180,6 +1258,9 @@ msgstr ""
msgid ":%{startLine} to %{endLine}"
msgstr ""
+msgid "A %{incident_docs_start}modified issue%{incident_docs_end} to guide the resolution of incidents."
+msgstr ""
+
msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr ""
@@ -1192,6 +1273,9 @@ msgstr ""
msgid "A GitBook site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
+msgid "A Gitpod configured Webapplication in Spring and Java"
+msgstr ""
+
msgid "A Hexo site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
@@ -1363,9 +1447,15 @@ msgstr ""
msgid "Access expiration date"
msgstr ""
+msgid "Access expires"
+msgstr ""
+
msgid "Access forbidden. Check your access level."
msgstr ""
+msgid "Access granted"
+msgstr ""
+
msgid "Access requests"
msgstr ""
@@ -1375,6 +1465,9 @@ msgstr ""
msgid "Access to Pages websites are controlled based on the user's membership to a given project. By checking this box, users will be required to be logged in to have access to all Pages websites in your instance."
msgstr ""
+msgid "AccessDropdown|Deploy Keys"
+msgstr ""
+
msgid "AccessDropdown|Groups"
msgstr ""
@@ -1492,12 +1585,6 @@ msgstr ""
msgid "Active Sessions"
msgstr ""
-msgid "Active Users:"
-msgstr ""
-
-msgid "Active users"
-msgstr ""
-
msgid "Activity"
msgstr ""
@@ -1666,9 +1753,6 @@ msgstr ""
msgid "Add label(s)"
msgstr ""
-msgid "Add license"
-msgstr ""
-
msgid "Add list"
msgstr ""
@@ -1843,21 +1927,51 @@ msgstr ""
msgid "AdminArea|Bots"
msgstr ""
+msgid "AdminArea|Components"
+msgstr ""
+
msgid "AdminArea|Developer"
msgstr ""
+msgid "AdminArea|Features"
+msgstr ""
+
+msgid "AdminArea|Groups: %{number_of_groups}"
+msgstr ""
+
msgid "AdminArea|Guest"
msgstr ""
msgid "AdminArea|Included Free in license"
msgstr ""
+msgid "AdminArea|Latest groups"
+msgstr ""
+
+msgid "AdminArea|Latest projects"
+msgstr ""
+
+msgid "AdminArea|Latest users"
+msgstr ""
+
msgid "AdminArea|Maintainer"
msgstr ""
+msgid "AdminArea|New group"
+msgstr ""
+
+msgid "AdminArea|New project"
+msgstr ""
+
+msgid "AdminArea|New user"
+msgstr ""
+
msgid "AdminArea|Owner"
msgstr ""
+msgid "AdminArea|Projects: %{number_of_projects}"
+msgstr ""
+
msgid "AdminArea|Reporter"
msgstr ""
@@ -1885,6 +1999,9 @@ msgstr ""
msgid "AdminArea|Users without a Group and Project"
msgstr ""
+msgid "AdminArea|Users: %{number_of_users}"
+msgstr ""
+
msgid "AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running."
msgstr ""
@@ -1903,9 +2020,6 @@ msgstr ""
msgid "AdminProjects|Delete Project %{projectName}?"
msgstr ""
-msgid "AdminProjects|Delete project"
-msgstr ""
-
msgid "AdminSettings|Apply integration settings to all Projects"
msgstr ""
@@ -2143,21 +2257,30 @@ msgstr ""
msgid "AdminUsers|Without projects"
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 ""
msgid "AdminUsers|You cannot remove your own admin rights."
msgstr ""
+msgid "AdminUsers|You must transfer ownership or delete the groups owned by this user before you can delete their account"
+msgstr ""
+
msgid "Administration"
msgstr ""
msgid "Advanced"
msgstr ""
+msgid "Advanced Search"
+msgstr ""
+
+msgid "Advanced Search with Elasticsearch"
+msgstr ""
+
msgid "Advanced Settings"
msgstr ""
@@ -2236,6 +2359,9 @@ msgstr ""
msgid "AlertManagement|Edit"
msgstr ""
+msgid "AlertManagement|Environment"
+msgstr ""
+
msgid "AlertManagement|Events"
msgstr ""
@@ -2248,6 +2374,9 @@ msgstr ""
msgid "AlertManagement|Issue"
msgstr ""
+msgid "AlertManagement|Key"
+msgstr ""
+
msgid "AlertManagement|Low"
msgstr ""
@@ -2341,6 +2470,9 @@ msgstr ""
msgid "AlertManagement|Unknown"
msgstr ""
+msgid "AlertManagement|Value"
+msgstr ""
+
msgid "AlertManagement|View alerts in Opsgenie"
msgstr ""
@@ -2500,6 +2632,9 @@ msgstr ""
msgid "All projects"
msgstr ""
+msgid "All projects selected"
+msgstr ""
+
msgid "All security scans are enabled because %{linkStart}Auto DevOps%{linkEnd} is enabled on this project"
msgstr ""
@@ -2587,6 +2722,9 @@ msgstr ""
msgid "Almost there"
msgstr ""
+msgid "Already blocked"
+msgstr ""
+
msgid "Also called \"Issuer\" or \"Relying party trust identifier\""
msgstr ""
@@ -2641,6 +2779,9 @@ msgstr ""
msgid "An error has occurred"
msgstr ""
+msgid "An error occured while making the changes: %{error}"
+msgstr ""
+
msgid "An error occurred adding a draft to the thread."
msgstr ""
@@ -2668,12 +2809,6 @@ msgstr ""
msgid "An error occurred when toggling the notification subscription"
msgstr ""
-msgid "An error occurred when trying to resolve a comment. Please try again."
-msgstr ""
-
-msgid "An error occurred when trying to resolve a discussion. Please try again."
-msgstr ""
-
msgid "An error occurred when updating the issue weight"
msgstr ""
@@ -2689,12 +2824,6 @@ msgstr ""
msgid "An error occurred while checking group path. Please refresh and try again."
msgstr ""
-msgid "An error occurred while committing your changes."
-msgstr ""
-
-msgid "An error occurred while creating the list. Please try again."
-msgstr ""
-
msgid "An error occurred while decoding the file."
msgstr ""
@@ -2767,25 +2896,19 @@ msgstr ""
msgid "An error occurred while fetching the Service Desk address."
msgstr ""
-msgid "An error occurred while fetching the board issues. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the board lists. Please reload the page."
msgstr ""
msgid "An error occurred while fetching the board lists. Please try again."
msgstr ""
-msgid "An error occurred while fetching the board swimlanes. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the builds."
msgstr ""
msgid "An error occurred while fetching the job log."
msgstr ""
-msgid "An error occurred while fetching the job trace."
+msgid "An error occurred while fetching the job logs."
msgstr ""
msgid "An error occurred while fetching the job."
@@ -2932,9 +3055,6 @@ msgstr ""
msgid "An error occurred while saving assignees"
msgstr ""
-msgid "An error occurred while saving the template. Please check if the template exists."
-msgstr ""
-
msgid "An error occurred while searching for milestones"
msgstr ""
@@ -2953,10 +3073,10 @@ msgstr ""
msgid "An error occurred while updating approvers"
msgstr ""
-msgid "An error occurred while updating the comment"
+msgid "An error occurred while updating labels."
msgstr ""
-msgid "An error occurred while updating the list. Please try again."
+msgid "An error occurred while updating the comment"
msgstr ""
msgid "An error occurred while validating group path"
@@ -3010,6 +3130,9 @@ msgstr ""
msgid "An unknown error occurred while loading this graph."
msgstr ""
+msgid "An unknown error occurred."
+msgstr ""
+
msgid "Analytics"
msgstr ""
@@ -3043,10 +3166,10 @@ msgstr ""
msgid "Any"
msgstr ""
-msgid "Any Author"
+msgid "Any %{header}"
msgstr ""
-msgid "Any Status"
+msgid "Any Author"
msgstr ""
msgid "Any branch"
@@ -3100,6 +3223,9 @@ msgstr ""
msgid "Application ID"
msgstr ""
+msgid "Application limits saved successfully"
+msgstr ""
+
msgid "Application settings saved successfully"
msgstr ""
@@ -3313,6 +3439,9 @@ msgstr ""
msgid "Are you sure you want to close this blocked issue?"
msgstr ""
+msgid "Are you sure you want to delete \"%{name}\" Value Stream?"
+msgstr ""
+
msgid "Are you sure you want to delete %{name}?"
msgstr ""
@@ -3322,6 +3451,9 @@ msgstr ""
msgid "Are you sure you want to delete this %{typeOfComment}?"
msgstr ""
+msgid "Are you sure you want to delete this SSH key?"
+msgstr ""
+
msgid "Are you sure you want to delete this board?"
msgstr ""
@@ -3346,6 +3478,12 @@ msgstr ""
msgid "Are you sure you want to erase this build?"
msgstr ""
+msgid "Are you sure you want to import %d repository?"
+msgid_plural "Are you sure you want to import %d repositories?"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "Are you sure you want to lose unsaved changes?"
msgstr ""
@@ -3355,15 +3493,15 @@ msgstr ""
msgid "Are you sure you want to merge immediately?"
msgstr ""
-msgid "Are you sure you want to permanently delete this license?"
-msgstr ""
-
msgid "Are you sure you want to re-deploy this environment?"
msgstr ""
msgid "Are you sure you want to regenerate the public key? You will have to update the public key on the remote server before mirroring will work again."
msgstr ""
+msgid "Are you sure you want to reindex?"
+msgstr ""
+
msgid "Are you sure you want to remove %{group_name}?"
msgstr ""
@@ -3391,6 +3529,9 @@ msgstr ""
msgid "Are you sure you want to revoke this nickname?"
msgstr ""
+msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
+msgstr ""
+
msgid "Are you sure you want to stop this environment?"
msgstr ""
@@ -3412,6 +3553,9 @@ msgstr ""
msgid "Are you sure? The device will be signed out of GitLab and all remember me tokens revoked."
msgstr ""
+msgid "Are you sure? This will invalidate your registered applications and U2F / WebAuthn devices."
+msgstr ""
+
msgid "Are you sure? This will invalidate your registered applications and U2F devices."
msgstr ""
@@ -3430,9 +3574,6 @@ msgstr ""
msgid "Artifacts"
msgstr ""
-msgid "As U2F devices are only supported by a few browsers, we require that you set up a two-factor authentication app before a U2F device. That way you'll always be able to log in - even when you're using an unsupported browser."
-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 ""
@@ -3628,6 +3769,9 @@ msgstr ""
msgid "AuditLogs|Target"
msgstr ""
+msgid "AuditLogs|This month"
+msgstr ""
+
msgid "AuditLogs|User Events"
msgstr ""
@@ -3667,6 +3811,9 @@ msgstr ""
msgid "Authentication via U2F device failed."
msgstr ""
+msgid "Authentication via WebAuthn device failed."
+msgstr ""
+
msgid "Author"
msgstr ""
@@ -3934,15 +4081,6 @@ msgstr ""
msgid "BambooService|You must set up automatic revision labeling and a repository trigger in Bamboo."
msgstr ""
-msgid "BatchComments|Delete all pending comments"
-msgstr ""
-
-msgid "BatchComments|Discard review?"
-msgstr ""
-
-msgid "BatchComments|You're about to discard your review which will delete all of your pending comments. The deleted comments %{strong_start}cannot%{strong_end} be restored."
-msgstr ""
-
msgid "Be careful. Changing the project's namespace can have unintended side effects."
msgstr ""
@@ -3964,6 +4102,9 @@ msgstr ""
msgid "Bi-weekly code coverage"
msgstr ""
+msgid "Billable Users:"
+msgstr ""
+
msgid "Billing"
msgstr ""
@@ -3973,7 +4114,7 @@ msgstr ""
msgid "BillingPlans|@%{user_name} you are currently using the %{plan_name} plan."
msgstr ""
-msgid "BillingPlans|Congratulations, your new trial is activated"
+msgid "BillingPlans|Congratulations, your free trial is activated."
msgstr ""
msgid "BillingPlans|If you would like to downgrade your plan please contact %{support_link_start}Customer Support%{support_link_end}."
@@ -4036,6 +4177,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Block user"
+msgstr ""
+
msgid "Blocked"
msgstr ""
@@ -4051,31 +4195,37 @@ msgstr ""
msgid "Blog"
msgstr ""
-msgid "Board name"
-msgstr ""
-
msgid "Board scope"
msgstr ""
msgid "Board scope affects which issues are displayed for anyone who visits this board"
msgstr ""
-msgid "BoardBlankState|Add default lists"
+msgid "Boards"
msgstr ""
-msgid "BoardBlankState|Add the following default lists to your Issue Board with one click:"
+msgid "Boards and Board Lists"
msgstr ""
-msgid "BoardBlankState|Nevermind, I'll use my own"
+msgid "Boards|An error occurred while creating the issue. Please try again."
msgstr ""
-msgid "BoardBlankState|Starting out with the default set of lists will get you right on the way to making the most of your board."
+msgid "Boards|An error occurred while creating the list. Please try again."
msgstr ""
-msgid "Boards"
+msgid "Boards|An error occurred while fetching issues. Please reload the page."
msgstr ""
-msgid "Boards and Board Lists"
+msgid "Boards|An error occurred while fetching the board issues. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching the board swimlanes. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while moving the issue. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while updating the list. Please try again."
msgstr ""
msgid "Boards|Collapse"
@@ -4102,7 +4252,7 @@ msgstr ""
msgid "Branch %{branch_name} was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr ""
-msgid "Branch has changed"
+msgid "Branch changed"
msgstr ""
msgid "Branch is already taken"
@@ -4408,6 +4558,9 @@ msgstr ""
msgid "CLOSED (MOVED)"
msgstr ""
+msgid "CODEOWNERS rule violation"
+msgstr ""
+
msgid "CONTRIBUTING"
msgstr ""
@@ -4438,9 +4591,6 @@ msgstr ""
msgid "Can't create snippet: %{err}"
msgstr ""
-msgid "Can't edit as source branch was deleted"
-msgstr ""
-
msgid "Can't fetch content for the blob: %{err}"
msgstr ""
@@ -4453,9 +4603,6 @@ msgstr ""
msgid "Can't load mermaid module: %{err}"
msgstr ""
-msgid "Can't remove group members without group managed account"
-msgstr ""
-
msgid "Can't scan the code?"
msgstr ""
@@ -4498,6 +4645,9 @@ msgstr ""
msgid "Cannot create the abuse report. This user has been blocked."
msgstr ""
+msgid "Cannot enable shared runners because parent group does not allow it"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -4603,6 +4753,15 @@ msgstr ""
msgid "Change your password or recover your current one"
msgstr ""
+msgid "ChangeReviewer|Reviewer changed from %{old} to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Reviewer changed to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Unassigned"
+msgstr ""
+
msgid "ChangeTypeActionLabel|Pick into branch"
msgstr ""
@@ -4642,6 +4801,9 @@ msgstr ""
msgid "Changes the title to \"%{title_param}\"."
msgstr ""
+msgid "Changes were successfully made."
+msgstr ""
+
msgid "Changes won't take place until the index is %{link_start}recreated%{link_end}."
msgstr ""
@@ -5047,6 +5209,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove variable"
+msgstr ""
+
msgid "CiVariables|Remove variable row"
msgstr ""
@@ -5125,9 +5290,6 @@ msgstr ""
msgid "Clear due date"
msgstr ""
-msgid "Clear input"
-msgstr ""
-
msgid "Clear recent searches"
msgstr ""
@@ -5176,6 +5338,9 @@ msgstr ""
msgid "Client authentication key password"
msgstr ""
+msgid "Client request timeout"
+msgstr ""
+
msgid "Clients"
msgstr ""
@@ -5260,6 +5425,27 @@ msgstr ""
msgid "Cluster type must be specificed for Stages::ClusterEndpointInserter"
msgstr ""
+msgid "ClusterAgents|Configuration"
+msgstr ""
+
+msgid "ClusterAgents|Connect your cluster with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate Kubernetes with a GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Name"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Agent also requires %{linkStart}enabling the Agent Server%{linkEnd}"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Kubernetes Agent allows an Infrastructure as Code, GitOps approach to integrating Kubernetes clusters with GitLab. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "ClusterAgent|This feature is only available for premium plans"
msgstr ""
@@ -5329,10 +5515,10 @@ msgstr ""
msgid "ClusterIntegration|All installed applications and related resources"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster."
+msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{linkStart}More information%{linkEnd}"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{startLink}More information%{endLink}"
+msgid "ClusterIntegration|Allow GitLab to manage namespaces and service accounts for this cluster."
msgstr ""
msgid "ClusterIntegration|Alternatively, "
@@ -5353,6 +5539,9 @@ msgstr ""
msgid "ClusterIntegration|An error occurred while trying to fetch zone machine types: %{error}"
msgstr ""
+msgid "ClusterIntegration|An unknown error occurred while attempting to connect to Kubernetes."
+msgstr ""
+
msgid "ClusterIntegration|Any project namespaces"
msgstr ""
@@ -5368,6 +5557,9 @@ msgstr ""
msgid "ClusterIntegration|Authenticate with Amazon Web Services"
msgstr ""
+msgid "ClusterIntegration|Authentication Error"
+msgstr ""
+
msgid "ClusterIntegration|Base domain"
msgstr ""
@@ -5386,13 +5578,22 @@ msgstr ""
msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}security group %{externalLinkIcon} %{endLink} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
+msgid "ClusterIntegration|Check your CA certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Check your cluster status"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}subnets %{externalLinkIcon} %{endLink} in your VPC where your worker nodes will run."
+msgid "ClusterIntegration|Check your token"
msgstr ""
-msgid "ClusterIntegration|Choose the worker node %{startLink}instance type %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Choose the %{linkStart}security group %{linkEnd} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
+msgstr ""
+
+msgid "ClusterIntegration|Choose the %{linkStart}subnets %{linkEnd} in your VPC where your worker nodes will run."
+msgstr ""
+
+msgid "ClusterIntegration|Choose the worker node %{linkStart}instance type%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Choose which applications to install on your Kubernetes cluster."
@@ -5404,10 +5605,7 @@ msgstr ""
msgid "ClusterIntegration|Clear cluster cache"
msgstr ""
-msgid "ClusterIntegration|Clear the local cache of namespace and service accounts. This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
-msgstr ""
-
-msgid "ClusterIntegration|Cluster being created"
+msgid "ClusterIntegration|Clear the local cache of namespace and service accounts."
msgstr ""
msgid "ClusterIntegration|Cluster management project (alpha)"
@@ -5419,15 +5617,21 @@ msgstr ""
msgid "ClusterIntegration|Cluster_applications artifact too big. Maximum allowable size: %{human_size}"
msgstr ""
-msgid "ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters."
+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|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}"
+msgid "ClusterIntegration|Clusters connected with a certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Connect cluster with certificate"
msgstr ""
msgid "ClusterIntegration|Connect existing cluster"
msgstr ""
+msgid "ClusterIntegration|Connection Error"
+msgstr ""
+
msgid "ClusterIntegration|Copy API URL"
msgstr ""
@@ -5503,6 +5707,12 @@ msgstr ""
msgid "ClusterIntegration|Deletes all GitLab resources attached to this cluster during removal"
msgstr ""
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared."
+msgstr ""
+
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared. %{linkStart}More information%{linkEnd}"
+msgstr ""
+
msgid "ClusterIntegration|Did you know?"
msgstr ""
@@ -5572,6 +5782,9 @@ msgstr ""
msgid "ClusterIntegration|Fluentd is an open source data collector, which lets you unify the data collection and consumption for a better use and understanding of data. It requires at least one of the following logs to be successfully installed."
msgstr ""
+msgid "ClusterIntegration|GitLab Agent managed clusters"
+msgstr ""
+
msgid "ClusterIntegration|GitLab Container Network Policies"
msgstr ""
@@ -5584,6 +5797,12 @@ msgstr ""
msgid "ClusterIntegration|GitLab Runner connects to the repository and executes CI/CD jobs, pushing results back and deploying applications to production."
msgstr ""
+msgid "ClusterIntegration|GitLab failed to authenticate."
+msgstr ""
+
+msgid "ClusterIntegration|GitLab failed to connect to the cluster."
+msgstr ""
+
msgid "ClusterIntegration|GitLab-managed cluster"
msgstr ""
@@ -5605,6 +5824,9 @@ msgstr ""
msgid "ClusterIntegration|Group cluster"
msgstr ""
+msgid "ClusterIntegration|HTTP Error"
+msgstr ""
+
msgid "ClusterIntegration|Helm Tiller"
msgstr ""
@@ -5638,7 +5860,10 @@ msgstr ""
msgid "ClusterIntegration|Instance type"
msgstr ""
-msgid "ClusterIntegration|Integrate Kubernetes cluster automation"
+msgid "ClusterIntegration|Integrate Kubernetes with a cluster certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Integrate with a cluster certificate"
msgstr ""
msgid "ClusterIntegration|Issuer Email"
@@ -5674,9 +5899,6 @@ msgstr ""
msgid "ClusterIntegration|Knative extends Kubernetes to provide a set of middleware components that are essential to build modern, source-centric, and container-based applications that can run anywhere: on premises, in the cloud, or even in a third-party data center."
msgstr ""
-msgid "ClusterIntegration|Kubernetes cluster"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes cluster is being created..."
msgstr ""
@@ -5689,9 +5911,6 @@ msgstr ""
msgid "ClusterIntegration|Kubernetes clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr ""
-msgid "ClusterIntegration|Kubernetes clusters can be used to deploy applications and to provide Review Apps for this project"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes version"
msgstr ""
@@ -5704,7 +5923,7 @@ msgstr ""
msgid "ClusterIntegration|Learn more about %{help_link_start}zones%{help_link_end}."
msgstr ""
-msgid "ClusterIntegration|Learn more about %{startLink}Regions %{externalLinkIcon}%{endLink}."
+msgid "ClusterIntegration|Learn more about %{linkStart}Regions%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Learn more about Kubernetes"
@@ -5749,12 +5968,18 @@ msgstr ""
msgid "ClusterIntegration|Machine type"
msgstr ""
+msgid "ClusterIntegration|Make sure your API endpoint is correct"
+msgstr ""
+
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create Kubernetes clusters"
msgstr ""
msgid "ClusterIntegration|Manage your Kubernetes cluster by visiting %{provider_link}"
msgstr ""
+msgid "ClusterIntegration|Namespace per environment"
+msgstr ""
+
msgid "ClusterIntegration|No IAM Roles found"
msgstr ""
@@ -5800,6 +6025,9 @@ msgstr ""
msgid "ClusterIntegration|No zones matched your search"
msgstr ""
+msgid "ClusterIntegration|Node calculations use the Kubernetes Metrics API. Make sure your cluster has metrics installed"
+msgstr ""
+
msgid "ClusterIntegration|Number of nodes"
msgstr ""
@@ -5842,6 +6070,9 @@ msgstr ""
msgid "ClusterIntegration|RBAC-enabled cluster"
msgstr ""
+msgid "ClusterIntegration|Read our %{linkStart}help page%{linkEnd} on Kubernetes cluster integration."
+msgstr ""
+
msgid "ClusterIntegration|Read our %{link_start}help page%{link_end} on Kubernetes cluster integration."
msgstr ""
@@ -5944,7 +6175,7 @@ msgstr ""
msgid "ClusterIntegration|Select a VPC to choose a subnet"
msgstr ""
-msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{linkStart}Amazon Web Services %{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select a network to choose a subnetwork"
@@ -5977,7 +6208,7 @@ msgstr ""
msgid "ClusterIntegration|Select project to choose zone"
msgstr ""
-msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select zone"
@@ -6067,9 +6298,18 @@ msgstr ""
msgid "ClusterIntegration|There was a problem authenticating with your cluster. Please ensure your CA Certificate and Token are valid."
msgstr ""
+msgid "ClusterIntegration|There was an HTTP error when connecting to your cluster."
+msgstr ""
+
msgid "ClusterIntegration|This account must have permissions to create a Kubernetes cluster in the %{link_to_container_project} specified below"
msgstr ""
+msgid "ClusterIntegration|This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
+msgstr ""
+
+msgid "ClusterIntegration|This is necessary to clear existing environment-namespace associations from clusters previously managed by GitLab."
+msgstr ""
+
msgid "ClusterIntegration|This option will allow you to install applications on RBAC clusters."
msgstr ""
@@ -6094,9 +6334,21 @@ msgstr ""
msgid "ClusterIntegration|To use a new project, first create one on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}."
msgstr ""
+msgid "ClusterIntegration|Troubleshooting tips:"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Authenticate"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Connect"
+msgstr ""
+
msgid "ClusterIntegration|Uninstall %{appTitle}"
msgstr ""
+msgid "ClusterIntegration|Unknown Error"
+msgstr ""
+
msgid "ClusterIntegration|Update %{appTitle}"
msgstr ""
@@ -6157,7 +6409,7 @@ msgstr ""
msgid "ClusterIntegration|Your cluster API is unreachable. Please ensure your API URL is correct."
msgstr ""
-msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Zone"
@@ -6277,6 +6529,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse all threads"
+msgstr ""
+
msgid "Collapse approvers"
msgstr ""
@@ -6427,7 +6682,7 @@ msgstr ""
msgid "Commit…"
msgstr ""
-msgid "Company"
+msgid "Community forum"
msgstr ""
msgid "Company name"
@@ -6436,6 +6691,9 @@ msgstr ""
msgid "Compare"
msgstr ""
+msgid "Compare %{oldCommitId}...%{newCommitId}"
+msgstr ""
+
msgid "Compare Git revisions"
msgstr ""
@@ -6451,6 +6709,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare submodule commit revisions"
+msgstr ""
+
msgid "Compare with previous version"
msgstr ""
@@ -6586,6 +6847,9 @@ msgstr ""
msgid "Configure the way a user creates a new account."
msgstr ""
+msgid "Configure which lists are shown for anyone who visits this board"
+msgstr ""
+
msgid "Confirm"
msgstr ""
@@ -6814,6 +7078,9 @@ msgstr[2] ""
msgid "ContainerRegistry|Set cleanup policy"
msgstr ""
+msgid "ContainerRegistry|Some tags were not deleted"
+msgstr ""
+
msgid "ContainerRegistry|Something went wrong while fetching the cleanup policy."
msgstr ""
@@ -6853,6 +7120,9 @@ msgstr ""
msgid "ContainerRegistry|Tags with names matching this regex pattern will %{italicStart}expire:%{italicEnd}"
msgstr ""
+msgid "ContainerRegistry|The cleanup policy timed out before it could delete all tags. An administrator can %{adminLinkStart}manually run cleanup now%{adminLinkEnd} or you can wait for the cleanup policy to automatically run again. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "ContainerRegistry|The last tag related to this image was recently removed. This empty image and any associated data will be automatically removed as part of the regular Garbage Collection process. If you have any questions, contact your administrator."
msgstr ""
@@ -6985,6 +7255,9 @@ msgstr ""
msgid "Contributions per group member"
msgstr ""
+msgid "Contributor"
+msgstr ""
+
msgid "Contributors"
msgstr ""
@@ -7114,6 +7387,9 @@ msgstr ""
msgid "Could not change HEAD: branch '%{branch}' does not exist"
msgstr ""
+msgid "Could not commit. An unexpected error occurred."
+msgstr ""
+
msgid "Could not connect to FogBugz, check your URL"
msgstr ""
@@ -7153,6 +7429,9 @@ msgstr ""
msgid "Could not find iteration"
msgstr ""
+msgid "Could not load instance counts. Please refresh the page to try again."
+msgstr ""
+
msgid "Could not remove the trigger."
msgstr ""
@@ -7177,10 +7456,10 @@ msgstr ""
msgid "Could not save prometheus manual configuration"
msgstr ""
-msgid "Could not udpdate wiki page"
+msgid "Could not update the LDAP settings"
msgstr ""
-msgid "Could not update the LDAP settings"
+msgid "Could not update wiki page"
msgstr ""
msgid "Could not upload your designs as one or more files uploaded are not supported."
@@ -7840,6 +8119,9 @@ msgstr ""
msgid "DastProfiles|Are you sure you want to delete this profile?"
msgstr ""
+msgid "DastProfiles|Could not create site validation token. Please refresh the page, or try again later."
+msgstr ""
+
msgid "DastProfiles|Could not create the scanner profile. Please try again."
msgstr ""
@@ -7864,6 +8146,12 @@ msgstr ""
msgid "DastProfiles|Could not fetch site profiles. Please refresh the page, or try again later."
msgstr ""
+msgid "DastProfiles|Could not retrieve site validation status. Please refresh the page, or try again later."
+msgstr ""
+
+msgid "DastProfiles|Could not update the scanner profile. Please try again."
+msgstr ""
+
msgid "DastProfiles|Could not update the site profile. Please try again."
msgstr ""
@@ -7879,7 +8167,7 @@ msgstr ""
msgid "DastProfiles|Download validation text file"
msgstr ""
-msgid "DastProfiles|Edit feature will come soon. Please create a new profile if changes needed"
+msgid "DastProfiles|Edit scanner profile"
msgstr ""
msgid "DastProfiles|Edit site profile"
@@ -7912,6 +8200,9 @@ msgstr ""
msgid "DastProfiles|No profiles created yet"
msgstr ""
+msgid "DastProfiles|Passive"
+msgstr ""
+
msgid "DastProfiles|Please enter a valid URL format, ex: http://www.example.com/home"
msgstr ""
@@ -7927,6 +8218,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan mode"
+msgstr ""
+
msgid "DastProfiles|Scanner Profile"
msgstr ""
@@ -7966,10 +8260,10 @@ msgstr ""
msgid "DastProfiles|Text file validation"
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
+msgid "DastProfiles|The maximum number of minutes allowed for the spider to traverse the site."
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the spider to traverse the site."
+msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
msgstr ""
msgid "DastProfiles|Validate"
@@ -8002,6 +8296,9 @@ msgstr ""
msgid "Date picker"
msgstr ""
+msgid "Date range"
+msgstr ""
+
msgid "Date range cannot exceed %{maxDateRange} days."
msgstr ""
@@ -8026,6 +8323,9 @@ msgstr ""
msgid "Days to merge"
msgstr ""
+msgid "Dear Administrator,"
+msgstr ""
+
msgid "Debug"
msgstr ""
@@ -8137,12 +8437,18 @@ msgstr ""
msgid "Delete"
msgstr ""
+msgid "Delete %{name}"
+msgstr ""
+
msgid "Delete Comment"
msgstr ""
msgid "Delete Snippet"
msgstr ""
+msgid "Delete Value Stream"
+msgstr ""
+
msgid "Delete account"
msgstr ""
@@ -8164,9 +8470,6 @@ msgstr ""
msgid "Delete label: %{label_name} ?"
msgstr ""
-msgid "Delete license"
-msgstr ""
-
msgid "Delete list"
msgstr ""
@@ -8242,15 +8545,6 @@ msgstr ""
msgid "Deleting a project places it into a read-only state until %{date}, at which point the project will be permanently deleted. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "Deleting the license failed."
-msgstr ""
-
-msgid "Deleting the license failed. The license was not found."
-msgstr ""
-
-msgid "Deleting the license failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "Deleting the project will delete its repository and all related resources including issues, merge requests etc."
msgstr ""
@@ -8752,7 +9046,10 @@ msgstr ""
msgid "DesignManagement|The maximum number of designs allowed to be uploaded is %{upload_limit}. Please try again."
msgstr ""
-msgid "DesignManagement|To upload designs, you'll need to enable LFS. %{requirements_link_start}More information%{requirements_link_end}"
+msgid "DesignManagement|There was an error moving your designs. Please upload your designs below."
+msgstr ""
+
+msgid "DesignManagement|To upload designs, you'll need to enable LFS and have admin enable hashed storage. %{requirements_link_start}More information%{requirements_link_end}"
msgstr ""
msgid "DesignManagement|Unresolve thread"
@@ -8764,6 +9061,9 @@ msgstr ""
msgid "DesignManagement|Upload skipped."
msgstr ""
+msgid "DesignManagement|Your designs are being copied and are on their way… Please refresh to update."
+msgstr ""
+
msgid "DesignManagement|and %{moreCount} more."
msgstr ""
@@ -8821,6 +9121,9 @@ msgstr ""
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
+msgid "Direct member"
+msgstr ""
+
msgid "Direction"
msgstr ""
@@ -8869,9 +9172,6 @@ msgstr ""
msgid "Discard draft"
msgstr ""
-msgid "Discard review"
-msgstr ""
-
msgid "DiscordService|Discord Notifications"
msgstr ""
@@ -8941,10 +9241,10 @@ msgstr ""
msgid "Dismiss Merge Request promotion"
msgstr ""
-msgid "Dismiss Selected"
+msgid "Dismiss Value Stream Analytics introduction box"
msgstr ""
-msgid "Dismiss Value Stream Analytics introduction box"
+msgid "Dismiss selected"
msgstr ""
msgid "Dismiss trial promotion"
@@ -8995,9 +9295,6 @@ msgstr ""
msgid "Documents reindexed: %{processed_documents} (%{percentage}%%)"
msgstr ""
-msgid "Doing"
-msgstr ""
-
msgid "Domain"
msgstr ""
@@ -9193,9 +9490,6 @@ msgstr ""
msgid "Edit environment"
msgstr ""
-msgid "Edit file"
-msgstr ""
-
msgid "Edit files in the editor and commit changes here"
msgstr ""
@@ -9208,6 +9502,12 @@ msgstr ""
msgid "Edit identity for %{user_name}"
msgstr ""
+msgid "Edit in Web IDE"
+msgstr ""
+
+msgid "Edit in single-file editor"
+msgstr ""
+
msgid "Edit issues"
msgstr ""
@@ -9235,10 +9535,10 @@ msgstr ""
msgid "Editing"
msgstr ""
-msgid "Elasticsearch"
+msgid "Elasticsearch AWS IAM credentials"
msgstr ""
-msgid "Elasticsearch AWS IAM credentials"
+msgid "Elasticsearch HTTP client timeout value in seconds."
msgstr ""
msgid "Elasticsearch indexing restrictions"
@@ -9247,9 +9547,6 @@ msgstr ""
msgid "Elasticsearch indexing started"
msgstr ""
-msgid "Elasticsearch integration. Elasticsearch AWS IAM."
-msgstr ""
-
msgid "Elasticsearch reindexing is already in progress"
msgstr ""
@@ -9277,9 +9574,6 @@ msgstr ""
msgid "Email Notification"
msgstr ""
-msgid "Email address"
-msgstr ""
-
msgid "Email could not be sent"
msgstr ""
@@ -9343,6 +9637,9 @@ msgstr ""
msgid "Emails sent from Service Desk will have this name"
msgstr ""
+msgid "Emails sent to %{email} will still be supported"
+msgstr ""
+
msgid "Emails separated by comma"
msgstr ""
@@ -9376,9 +9673,18 @@ msgstr ""
msgid "Enable"
msgstr ""
+msgid "Enable %{link_start}Gitpod%{link_end} integration to launch a development environment in your browser directly from GitLab."
+msgstr ""
+
msgid "Enable Auto DevOps"
msgstr ""
+msgid "Enable Gitpod"
+msgstr ""
+
+msgid "Enable Gitpod?"
+msgstr ""
+
msgid "Enable HTML emails"
msgstr ""
@@ -9508,9 +9814,6 @@ msgstr ""
msgid "Encountered an error while rendering: %{err}"
msgstr ""
-msgid "End date"
-msgstr ""
-
msgid "Ends at (UTC)"
msgstr ""
@@ -9670,7 +9973,7 @@ msgstr ""
msgid "EnvironmentsDashboard|The environments dashboard provides a summary of each project's environments' status, including pipeline and alert statuses."
msgstr ""
-msgid "EnvironmentsDashboard|This dashboard displays a maximum of 7 projects and 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
+msgid "EnvironmentsDashboard|This dashboard displays 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
msgstr ""
msgid "Environments|An error occurred while canceling the auto stop, please try again"
@@ -9991,6 +10294,9 @@ msgstr ""
msgid "Error deleting project. Check logs for error details."
msgstr ""
+msgid "Error fetching burnup chart data"
+msgstr ""
+
msgid "Error fetching diverging counts for branches. Please try again."
msgstr ""
@@ -10069,6 +10375,9 @@ msgstr ""
msgid "Error occurred when saving assignees"
msgstr ""
+msgid "Error occurred when saving reviewers"
+msgstr ""
+
msgid "Error occurred when toggling the notification subscription"
msgstr ""
@@ -10321,10 +10630,13 @@ msgstr ""
msgid "Expand all"
msgstr ""
-msgid "Expand approvers"
+msgid "Expand all files"
+msgstr ""
+
+msgid "Expand all threads"
msgstr ""
-msgid "Expand dropdown"
+msgid "Expand approvers"
msgstr ""
msgid "Expand milestones"
@@ -10495,6 +10807,9 @@ msgstr ""
msgid "Failed to create Merge Request. Please try again."
msgstr ""
+msgid "Failed to create To-Do for the design."
+msgstr ""
+
msgid "Failed to create a branch for this issue. Please try again."
msgstr ""
@@ -10534,6 +10849,12 @@ msgstr ""
msgid "Failed to load authors. Please try again."
msgstr ""
+msgid "Failed to load branches. Please try again."
+msgstr ""
+
+msgid "Failed to load deploy keys."
+msgstr ""
+
msgid "Failed to load emoji list."
msgstr ""
@@ -10549,6 +10870,9 @@ msgstr ""
msgid "Failed to load groups & users."
msgstr ""
+msgid "Failed to load groups, users and deploy keys."
+msgstr ""
+
msgid "Failed to load labels. Please try again."
msgstr ""
@@ -10558,6 +10882,12 @@ msgstr ""
msgid "Failed to load related branches"
msgstr ""
+msgid "Failed to load sidebar confidential toggle"
+msgstr ""
+
+msgid "Failed to load sidebar lock status"
+msgstr ""
+
msgid "Failed to load stacktrace."
msgstr ""
@@ -10585,6 +10915,9 @@ msgstr ""
msgid "Failed to publish issue on status page."
msgstr ""
+msgid "Failed to remove To-Do for the design."
+msgstr ""
+
msgid "Failed to remove a Zoom meeting"
msgstr ""
@@ -10627,6 +10960,9 @@ msgstr ""
msgid "Failed to signing using smartcard authentication"
msgstr ""
+msgid "Failed to toggle To-Do for the design."
+msgstr ""
+
msgid "Failed to update branch!"
msgstr ""
@@ -10741,7 +11077,7 @@ msgstr ""
msgid "FeatureFlags|Edit User List"
msgstr ""
-msgid "FeatureFlags|Enable features for specific users and specific environments by defining feature flag strategies."
+msgid "FeatureFlags|Enable features for specific users and environments by configuring feature flag strategies."
msgstr ""
msgid "FeatureFlags|Environment Spec"
@@ -10801,7 +11137,7 @@ msgstr ""
msgid "FeatureFlags|Include additional user IDs"
msgstr ""
-msgid "FeatureFlags|Install a %{docs_link_anchored_start}compatible client library%{docs_link_anchored_end} and specify the API URL, application name, and instance ID during the configuration setup. %{docs_link_start}More Information%{docs_link_end}"
+msgid "FeatureFlags|Install a %{docsLinkAnchoredStart}compatible client library%{docsLinkAnchoredEnd} and specify the API URL, application name, and instance ID during the configuration setup. %{docsLinkStart}More Information%{docsLinkEnd}"
msgstr ""
msgid "FeatureFlags|Instance ID"
@@ -10813,6 +11149,9 @@ msgstr ""
msgid "FeatureFlags|Loading feature flags"
msgstr ""
+msgid "FeatureFlags|Loading user lists"
+msgstr ""
+
msgid "FeatureFlags|More information"
msgstr ""
@@ -10831,7 +11170,7 @@ msgstr ""
msgid "FeatureFlags|New feature flag"
msgstr ""
-msgid "FeatureFlags|New list"
+msgid "FeatureFlags|New user list"
msgstr ""
msgid "FeatureFlags|Percent of users"
@@ -10870,6 +11209,9 @@ msgstr ""
msgid "FeatureFlags|There was an error fetching the feature flags."
msgstr ""
+msgid "FeatureFlags|There was an error fetching the user lists."
+msgstr ""
+
msgid "FeatureFlags|There was an error retrieving user lists"
msgstr ""
@@ -10885,6 +11227,9 @@ msgstr ""
msgid "FeatureFlags|User List"
msgstr ""
+msgid "FeatureFlags|User Lists"
+msgstr ""
+
msgid "FeatureFlag|List"
msgstr ""
@@ -10912,15 +11257,6 @@ msgstr ""
msgid "Fetching incoming email"
msgstr ""
-msgid "Fetching licenses failed."
-msgstr ""
-
-msgid "Fetching licenses failed. The request endpoint was not found."
-msgstr ""
-
-msgid "Fetching licenses failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "File"
msgstr ""
@@ -11023,12 +11359,21 @@ msgstr ""
msgid "Filter by status"
msgstr ""
+msgid "Filter by test cases that are currently archived."
+msgstr ""
+
+msgid "Filter by test cases that are currently opened."
+msgstr ""
+
msgid "Filter by two-factor authentication"
msgstr ""
msgid "Filter by user"
msgstr ""
+msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
+msgstr ""
+
msgid "Filter pipelines"
msgstr ""
@@ -11044,7 +11389,7 @@ msgstr ""
msgid "Filter results..."
msgstr ""
-msgid "Filter your projects by name"
+msgid "Filter your repositories by name"
msgstr ""
msgid "Filter..."
@@ -11053,7 +11398,7 @@ msgstr ""
msgid "Find File"
msgstr ""
-msgid "Find bugs in your code with coverage-guided fuzzing"
+msgid "Find bugs in your code with coverage-guided fuzzing."
msgstr ""
msgid "Find by path"
@@ -11080,9 +11425,6 @@ msgstr ""
msgid "Finish editing this message first!"
msgstr ""
-msgid "Finish review"
-msgstr ""
-
msgid "Finish setting up your dedicated account for %{group_name}."
msgstr ""
@@ -11152,6 +11494,9 @@ msgstr ""
msgid "Footer message"
msgstr ""
+msgid "For a faster browsing experience, some files are collapsed by default."
+msgstr ""
+
msgid "For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
@@ -11161,6 +11506,9 @@ msgstr ""
msgid "For more info, read the documentation."
msgstr ""
+msgid "For more information on how the number of active users is calculated, see the %{self_managed_subscriptions_doc_link} documentation."
+msgstr ""
+
msgid "For more information, go to the "
msgstr ""
@@ -11299,6 +11647,9 @@ msgstr ""
msgid "Generate new token"
msgstr ""
+msgid "Generic package file size in bytes"
+msgstr ""
+
msgid "Geo"
msgstr ""
@@ -11560,6 +11911,9 @@ msgstr ""
msgid "Geo|Please refer to Geo Troubleshooting."
msgstr ""
+msgid "Geo|Primary node"
+msgstr ""
+
msgid "Geo|Project"
msgstr ""
@@ -11602,6 +11956,9 @@ msgstr ""
msgid "Geo|Review replication status, and resynchronize and reverify items with the primary node."
msgstr ""
+msgid "Geo|Secondary node"
+msgstr ""
+
msgid "Geo|Status"
msgstr ""
@@ -11641,6 +11998,9 @@ msgstr ""
msgid "Geo|URL must be a valid url (ex: https://gitlab.com)"
msgstr ""
+msgid "Geo|Undefined"
+msgstr ""
+
msgid "Geo|Unknown state"
msgstr ""
@@ -11716,10 +12076,16 @@ msgstr ""
msgid "GitHub import"
msgstr ""
+msgid "GitLab"
+msgstr ""
+
msgid "GitLab / Unsubscribe"
msgstr ""
-msgid "GitLab Enterprise Edition %{plan}"
+msgid "GitLab API"
+msgstr ""
+
+msgid "GitLab Billing Team."
msgstr ""
msgid "GitLab Group Runners can execute code for all the projects in this group."
@@ -11731,12 +12097,18 @@ msgstr ""
msgid "GitLab Issue"
msgstr ""
+msgid "GitLab Pages"
+msgstr ""
+
msgid "GitLab Service Desk is a simple way to allow people to create issues in your GitLab instance without needing their own user account. It provides a unique email address for end users to create issues in a project, and replies can be sent either through the GitLab interface or by email. End users will only see the thread through email."
msgstr ""
msgid "GitLab Shared Runners execute code of different projects on the same Runner unless you configure GitLab Runner Autoscale with MaxBuilds 1 (which it is on GitLab.com)."
msgstr ""
+msgid "GitLab Shell"
+msgstr ""
+
msgid "GitLab Support Bot"
msgstr ""
@@ -11746,7 +12118,7 @@ msgstr ""
msgid "GitLab User"
msgstr ""
-msgid "GitLab allows you to continue using your license even if you exceed the number of seats you purchased. You will be required to pay for these seats when you renew your license."
+msgid "GitLab Workhorse"
msgstr ""
msgid "GitLab commit"
@@ -11914,6 +12286,21 @@ msgstr ""
msgid "Gitlab Pages"
msgstr ""
+msgid "Gitpod"
+msgstr ""
+
+msgid "Gitpod|Add the URL to your Gitpod instance configured to read your GitLab projects."
+msgstr ""
+
+msgid "Gitpod|Enable Gitpod integration"
+msgstr ""
+
+msgid "Gitpod|Gitpod URL"
+msgstr ""
+
+msgid "Gitpod|e.g. https://gitpod.example.com"
+msgstr ""
+
msgid "Given access %{time_ago}"
msgstr ""
@@ -12421,9 +12808,6 @@ msgstr ""
msgid "GroupSAML|Valid SAML Response"
msgstr ""
-msgid "GroupSAML|With group managed accounts enabled, all the users without a group managed account will be excluded from the group."
-msgstr ""
-
msgid "GroupSAML|With prohibit outer forks flag enabled group members will be able to fork project only inside your group."
msgstr ""
@@ -12637,10 +13021,10 @@ msgstr ""
msgid "GroupsNew|Create group"
msgstr ""
-msgid "GroupsNew|GitLab group export"
+msgid "GroupsNew|Import"
msgstr ""
-msgid "GroupsNew|Import"
+msgid "GroupsNew|Import a GitLab group export file"
msgstr ""
msgid "GroupsNew|Import group"
@@ -12784,6 +13168,9 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgid "Hide comments on this file"
+msgstr ""
+
msgid "Hide details"
msgstr ""
@@ -12829,6 +13216,15 @@ msgstr ""
msgid "Highest role:"
msgstr ""
+msgid "HighlightBar|Alert events:"
+msgstr ""
+
+msgid "HighlightBar|Alert start time:"
+msgstr ""
+
+msgid "HighlightBar|Original alert:"
+msgstr ""
+
msgid "History"
msgstr ""
@@ -13006,6 +13402,9 @@ msgstr ""
msgid "If enabled, access to projects will be validated on an external service using their classification label."
msgstr ""
+msgid "If the number of active users exceeds the user limit, you will be charged for the number of %{users_over_license_link} at your next license reconciliation."
+msgstr ""
+
msgid "If there is no previous license or if the previous license has expired, some GitLab functionality will be blocked until a new, valid license is uploaded."
msgstr ""
@@ -13045,9 +13444,6 @@ msgstr ""
msgid "If your HTTP repository is not publicly accessible, add your credentials."
msgstr ""
-msgid "Iglu registry URL (optional)"
-msgstr ""
-
msgid "Ignore"
msgstr ""
@@ -13084,6 +13480,18 @@ msgstr ""
msgid "Import"
msgstr ""
+msgid "Import %d compatible repository"
+msgid_plural "Import %d compatible repositories"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
+msgid "Import %d repository"
+msgid_plural "Import %d repositories"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "Import CSV"
msgstr ""
@@ -13093,15 +13501,9 @@ msgstr ""
msgid "Import all compatible projects"
msgstr ""
-msgid "Import all compatible repositories"
-msgstr ""
-
msgid "Import all projects"
msgstr ""
-msgid "Import all repositories"
-msgstr ""
-
msgid "Import an exported GitLab project"
msgstr ""
@@ -13189,6 +13591,9 @@ msgstr ""
msgid "ImportProjects|Error importing repository %{project_safe_import_url} into %{project_full_path} - %{message}"
msgstr ""
+msgid "ImportProjects|Import repositories"
+msgstr ""
+
msgid "ImportProjects|Importing the project failed"
msgstr ""
@@ -13201,7 +13606,7 @@ msgstr ""
msgid "ImportProjects|Requesting your %{provider} repositories failed"
msgstr ""
-msgid "ImportProjects|Select the projects you want to import"
+msgid "ImportProjects|Select the repositories you want to import"
msgstr ""
msgid "ImportProjects|The remote data could not be imported."
@@ -13237,9 +13642,6 @@ msgstr ""
msgid "In order to enable Service Desk for your instance, you must first set up incoming email."
msgstr ""
-msgid "In order to gather accurate feature usage data, it can take 1 to 2 weeks to see your index."
-msgstr ""
-
msgid "In order to personalize your experience with GitLab%{br_tag}we would like to know a bit more about you."
msgstr ""
@@ -13270,18 +13672,30 @@ msgstr ""
msgid "IncidentManagement|Create incident"
msgstr ""
+msgid "IncidentManagement|Critical - S1"
+msgstr ""
+
msgid "IncidentManagement|Date created"
msgstr ""
msgid "IncidentManagement|Display your incidents in a dedicated view"
msgstr ""
+msgid "IncidentManagement|High - S2"
+msgstr ""
+
msgid "IncidentManagement|Incident"
msgstr ""
msgid "IncidentManagement|Incidents"
msgstr ""
+msgid "IncidentManagement|Low - S4"
+msgstr ""
+
+msgid "IncidentManagement|Medium - S3"
+msgstr ""
+
msgid "IncidentManagement|No incidents to display."
msgstr ""
@@ -13294,6 +13708,9 @@ msgstr ""
msgid "IncidentManagement|Published to status page"
msgstr ""
+msgid "IncidentManagement|Severity"
+msgstr ""
+
msgid "IncidentManagement|There are no closed incidents"
msgstr ""
@@ -13303,6 +13720,9 @@ msgstr ""
msgid "IncidentManagement|Unassigned"
msgstr ""
+msgid "IncidentManagement|Unknown"
+msgstr ""
+
msgid "IncidentManagement|Unpublished"
msgstr ""
@@ -13324,6 +13744,15 @@ msgstr ""
msgid "Incidents"
msgstr ""
+msgid "Incident|Alert details"
+msgstr ""
+
+msgid "Incident|Summary"
+msgstr ""
+
+msgid "Incident|There was an issue loading alert data. Please try again."
+msgstr ""
+
msgid "Include a Terms of Service agreement and Privacy Policy that all users must accept."
msgstr ""
@@ -13384,6 +13813,9 @@ msgstr ""
msgid "Information about additional Pages templates and how to install them can be found in our %{pages_getting_started_guide}."
msgstr ""
+msgid "Inherited"
+msgstr ""
+
msgid "Inherited:"
msgstr ""
@@ -13465,7 +13897,22 @@ msgstr ""
msgid "Instance administrators group already exists"
msgstr ""
-msgid "Instance license"
+msgid "InstanceStatistics|Groups"
+msgstr ""
+
+msgid "InstanceStatistics|Issues"
+msgstr ""
+
+msgid "InstanceStatistics|Merge Requests"
+msgstr ""
+
+msgid "InstanceStatistics|Pipelines"
+msgstr ""
+
+msgid "InstanceStatistics|Projects"
+msgstr ""
+
+msgid "InstanceStatistics|Users"
msgstr ""
msgid "Integration"
@@ -13477,6 +13924,12 @@ msgstr ""
msgid "Integrations"
msgstr ""
+msgid "Integrations|%{integration} settings saved and active."
+msgstr ""
+
+msgid "Integrations|%{integration} settings saved, but not active."
+msgstr ""
+
msgid "Integrations|All details"
msgstr ""
@@ -13486,6 +13939,12 @@ msgstr ""
msgid "Integrations|Comment settings:"
msgstr ""
+msgid "Integrations|Connection failed. Please check your settings."
+msgstr ""
+
+msgid "Integrations|Connection successful."
+msgstr ""
+
msgid "Integrations|Default settings are inherited from the group level."
msgstr ""
@@ -13501,6 +13960,15 @@ msgstr ""
msgid "Integrations|Includes commit title and branch"
msgstr ""
+msgid "Integrations|Projects using custom settings will not be impacted unless the project owner chooses to use instance-level defaults."
+msgstr ""
+
+msgid "Integrations|Save settings?"
+msgstr ""
+
+msgid "Integrations|Saving will update the default settings for all projects that are not using custom settings."
+msgstr ""
+
msgid "Integrations|Standard"
msgstr ""
@@ -13633,6 +14101,9 @@ msgstr ""
msgid "Invitation"
msgstr ""
+msgid "Invitation declined"
+msgstr ""
+
msgid "Invite"
msgstr ""
@@ -13684,6 +14155,42 @@ 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|%{linkStart}Read more%{linkEnd} about role permissions"
+msgstr ""
+
+msgid "InviteMembersModal|Access expiration date (optional)"
+msgstr ""
+
+msgid "InviteMembersModal|Cancel"
+msgstr ""
+
+msgid "InviteMembersModal|Choose a role permission"
+msgstr ""
+
+msgid "InviteMembersModal|GitLab member or Email address"
+msgstr ""
+
+msgid "InviteMembersModal|Invite"
+msgstr ""
+
+msgid "InviteMembersModal|Invite team members"
+msgstr ""
+
+msgid "InviteMembersModal|Search for members to invite"
+msgstr ""
+
+msgid "InviteMembersModal|User not invited. Feature coming soon!"
+msgstr ""
+
+msgid "InviteMembersModal|Users were succesfully added"
+msgstr ""
+
+msgid "InviteMembersModal|You're inviting members to the %{group_name} group"
+msgstr ""
+
+msgid "InviteMembers|Invite team members"
+msgstr ""
+
msgid "Invited"
msgstr ""
@@ -13738,10 +14245,13 @@ msgstr ""
msgid "Issue cannot be found."
msgstr ""
+msgid "Issue created from vulnerability %{vulnerability_link}"
+msgstr ""
+
msgid "Issue events"
msgstr ""
-msgid "Issue first depoloyed to production"
+msgid "Issue first deployed to production"
msgstr ""
msgid "Issue label"
@@ -13819,6 +14329,9 @@ msgstr ""
msgid "IssueTracker|Custom issue tracker"
msgstr ""
+msgid "IssueTracker|EWM work items tracker"
+msgstr ""
+
msgid "IssueTracker|Redmine issue tracker"
msgstr ""
@@ -13885,6 +14398,9 @@ msgstr ""
msgid "It looks like you have some draft commits in this branch."
msgstr ""
+msgid "It may be several days before you see feature usage data."
+msgstr ""
+
msgid "It must have a header row and at least two columns: the first column is the issue title and the second column is the issue description. The separator is automatically detected."
msgstr ""
@@ -14167,13 +14683,13 @@ msgstr ""
msgid "Join Zoom meeting"
msgstr ""
-msgid "Jul"
+msgid "Joined %{time_ago}"
msgstr ""
-msgid "July"
+msgid "Jul"
msgstr ""
-msgid "Jump to first unresolved thread"
+msgid "July"
msgstr ""
msgid "Jump to next unresolved thread"
@@ -14209,6 +14725,9 @@ msgstr ""
msgid "Keyboard shortcuts"
msgstr ""
+msgid "KeyboardKey|Ctrl+"
+msgstr ""
+
msgid "Keys"
msgstr ""
@@ -14257,6 +14776,9 @@ msgstr ""
msgid "LDAP Synchronization"
msgstr ""
+msgid "LDAP group settings"
+msgstr ""
+
msgid "LDAP settings"
msgstr ""
@@ -14266,6 +14788,9 @@ msgstr ""
msgid "LDAP sync in progress. This could take a few minutes. Refresh the page to see the changes."
msgstr ""
+msgid "LDAP synchronizations"
+msgstr ""
+
msgid "LFS"
msgstr ""
@@ -14347,7 +14872,16 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
-msgid "Last %{days} days"
+msgid "Last 2 weeks"
+msgstr ""
+
+msgid "Last 30 days"
+msgstr ""
+
+msgid "Last 60 days"
+msgstr ""
+
+msgid "Last 90 days"
msgstr ""
msgid "Last Accessed On"
@@ -14425,6 +14959,9 @@ msgstr ""
msgid "Last used on:"
msgstr ""
+msgid "Last week"
+msgstr ""
+
msgid "LastCommit|authored"
msgstr ""
@@ -14440,6 +14977,9 @@ msgstr ""
msgid "Latest pipeline for the most recent commit on this branch"
msgstr ""
+msgid "Launch a ready-to-code development environment for your project."
+msgstr ""
+
msgid "Lead"
msgstr ""
@@ -14827,6 +15367,9 @@ msgstr ""
msgid "List of all merge commits"
msgstr ""
+msgid "List options"
+msgstr ""
+
msgid "List settings"
msgstr ""
@@ -14839,9 +15382,6 @@ msgstr ""
msgid "List your Bitbucket Server repositories"
msgstr ""
-msgid "Lists"
-msgstr ""
-
msgid "Live preview"
msgstr ""
@@ -15088,6 +15628,12 @@ msgstr ""
msgid "Mark as done"
msgstr ""
+msgid "Mark as draft"
+msgstr ""
+
+msgid "Mark as ready"
+msgstr ""
+
msgid "Mark as resolved"
msgstr ""
@@ -15109,6 +15655,24 @@ msgstr ""
msgid "Markdown is supported"
msgstr ""
+msgid "MarkdownEditor|Add a link (%{modifierKey}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add a link (%{modifier_key}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifierKey}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifier_key}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifierKey}I)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifier_key}I)"
+msgstr ""
+
msgid "Marked For Deletion At - %{deletion_time}"
msgstr ""
@@ -15193,7 +15757,25 @@ msgstr ""
msgid "Max access level"
msgstr ""
-msgid "Max seats used"
+msgid "Max role"
+msgstr ""
+
+msgid "Max size 15 MB"
+msgstr ""
+
+msgid "Maximum Conan package file size in bytes"
+msgstr ""
+
+msgid "Maximum Maven package file size in bytes"
+msgstr ""
+
+msgid "Maximum NPM package file size in bytes"
+msgstr ""
+
+msgid "Maximum NuGet package file size in bytes"
+msgstr ""
+
+msgid "Maximum PyPI package file size in bytes"
msgstr ""
msgid "Maximum Users:"
@@ -15325,6 +15907,18 @@ msgstr ""
msgid "Members with access to %{strong_start}%{group_name}%{strong_end}"
msgstr ""
+msgid "Members|%{time} by %{user}"
+msgstr ""
+
+msgid "Members|Expired"
+msgstr ""
+
+msgid "Members|No expiration set"
+msgstr ""
+
+msgid "Members|in %{time}"
+msgstr ""
+
msgid "Memory Usage"
msgstr ""
@@ -15511,9 +16105,6 @@ msgstr ""
msgid "MergeRequests|Thread will be unresolved"
msgstr ""
-msgid "MergeRequests|Toggle comments for this file"
-msgstr ""
-
msgid "MergeRequests|View file @ %{commitId}"
msgstr ""
@@ -15574,6 +16165,9 @@ msgstr ""
msgid "Merging immediately isn't recommended as it may negatively impact the existing merge train. Read the %{docsLinkStart}documentation%{docsLinkEnd} for more information."
msgstr ""
+msgid "Message"
+msgstr ""
+
msgid "Messages"
msgstr ""
@@ -15961,18 +16555,12 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
-msgid "Milestone does not support burnup charts"
-msgstr ""
-
msgid "Milestone lists not available with your current license"
msgstr ""
msgid "Milestone lists show all issues from the selected milestone."
msgstr ""
-msgid "Milestone must have a start and due date"
-msgstr ""
-
msgid "MilestoneSidebar|Closed:"
msgstr ""
@@ -16339,6 +16927,9 @@ msgstr ""
msgid "Namespace"
msgstr ""
+msgid "Namespace ID:"
+msgstr ""
+
msgid "Namespace is empty"
msgstr ""
@@ -16423,6 +17014,9 @@ msgstr ""
msgid "NetworkPolicies|Allow all outbound traffic from %{selector} to %{ruleSelector} on %{ports}"
msgstr ""
+msgid "NetworkPolicies|Are you sure you want to delete this policy? This action cannot be undone."
+msgstr ""
+
msgid "NetworkPolicies|Choose whether to enforce this policy."
msgstr ""
@@ -16432,12 +17026,21 @@ msgstr ""
msgid "NetworkPolicies|Define this policy's location, conditions and actions."
msgstr ""
+msgid "NetworkPolicies|Delete policy"
+msgstr ""
+
+msgid "NetworkPolicies|Delete policy: %{policy}"
+msgstr ""
+
msgid "NetworkPolicies|Deny all traffic"
msgstr ""
msgid "NetworkPolicies|Description"
msgstr ""
+msgid "NetworkPolicies|Edit policy"
+msgstr ""
+
msgid "NetworkPolicies|Editor mode"
msgstr ""
@@ -16465,6 +17068,9 @@ msgstr ""
msgid "NetworkPolicies|Name"
msgstr ""
+msgid "NetworkPolicies|Namespace"
+msgstr ""
+
msgid "NetworkPolicies|Network Policy"
msgstr ""
@@ -16516,6 +17122,9 @@ msgstr ""
msgid "NetworkPolicies|Rules"
msgstr ""
+msgid "NetworkPolicies|Save changes"
+msgstr ""
+
msgid "NetworkPolicies|Something went wrong, failed to update policy"
msgstr ""
@@ -16528,6 +17137,9 @@ msgstr ""
msgid "NetworkPolicies|Traffic that does not match any rule will be blocked."
msgstr ""
+msgid "NetworkPolicies|Unable to parse policy"
+msgstr ""
+
msgid "NetworkPolicies|YAML editor"
msgstr ""
@@ -16642,6 +17254,9 @@ msgstr ""
msgid "New Snippet"
msgstr ""
+msgid "New Test Case"
+msgstr ""
+
msgid "New User"
msgstr ""
@@ -16741,6 +17356,9 @@ msgstr ""
msgid "New tag"
msgstr ""
+msgid "New test case"
+msgstr ""
+
msgid "New users set to external"
msgstr ""
@@ -16813,7 +17431,7 @@ msgstr ""
msgid "No changes"
msgstr ""
-msgid "No changes between %{ref_start}%{source_branch}%{ref_end} and %{ref_start}%{target_branch}%{ref_end}"
+msgid "No changes between %{sourceBranch} and %{targetBranch}"
msgstr ""
msgid "No child epics match applied filters"
@@ -16828,6 +17446,9 @@ msgstr ""
msgid "No containers available"
msgstr ""
+msgid "No content to show"
+msgstr ""
+
msgid "No contributions"
msgstr ""
@@ -16903,9 +17524,6 @@ msgstr ""
msgid "No license. All rights reserved"
msgstr ""
-msgid "No licenses found."
-msgstr ""
-
msgid "No matches found"
msgstr ""
@@ -16918,6 +17536,9 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No members found"
+msgstr ""
+
msgid "No merge requests found"
msgstr ""
@@ -16939,6 +17560,9 @@ msgstr ""
msgid "No parent group"
msgstr ""
+msgid "No plan"
+msgstr ""
+
msgid "No pods available"
msgstr ""
@@ -17035,6 +17659,12 @@ msgstr ""
msgid "Not Implemented"
msgstr ""
+msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+msgstr ""
+
+msgid "Not all browsers support WebAuthn. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even from an unsupported browser."
+msgstr ""
+
msgid "Not all data has been processed yet, the accuracy of the chart for the selected timeframe is limited."
msgstr ""
@@ -17131,6 +17761,9 @@ msgstr ""
msgid "Notification settings saved"
msgstr ""
+msgid "NotificationEvent|Change reviewer merge request"
+msgstr ""
+
msgid "NotificationEvent|Close issue"
msgstr ""
@@ -17293,10 +17926,7 @@ msgstr ""
msgid "On track"
msgstr ""
-msgid "OnDemandScans|Attached branch"
-msgstr ""
-
-msgid "OnDemandScans|Attached branch is where the scan job runs."
+msgid "OnDemandScans|Could not fetch scanner profiles. Please refresh the page, or try again later."
msgstr ""
msgid "OnDemandScans|Could not fetch site profiles. Please refresh the page, or try again later."
@@ -17305,6 +17935,9 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
+msgid "OnDemandScans|Create a new scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Create a new site profile"
msgstr ""
@@ -17317,6 +17950,9 @@ msgstr ""
msgid "OnDemandScans|New on-demand DAST scan"
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 ""
@@ -17326,16 +17962,10 @@ msgstr ""
msgid "OnDemandScans|On-demand scans run outside the DevOps cycle and find vulnerabilities in your projects. %{learnMoreLinkStart}Learn more%{learnMoreLinkEnd}"
msgstr ""
-msgid "OnDemandScans|Only a passive scan can be performed on demand."
-msgstr ""
-
-msgid "OnDemandScans|Passive"
-msgstr ""
-
msgid "OnDemandScans|Run scan"
msgstr ""
-msgid "OnDemandScans|Scan mode"
+msgid "OnDemandScans|Scanner profile"
msgstr ""
msgid "OnDemandScans|Scanner settings"
@@ -17347,9 +17977,15 @@ msgstr ""
msgid "OnDemandScans|Select one of the existing profiles"
msgstr ""
+msgid "OnDemandScans|Site profile"
+msgstr ""
+
msgid "OnDemandScans|Site profiles"
msgstr ""
+msgid "OnDemandScans|Use existing scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Use existing site profile"
msgstr ""
@@ -17449,9 +18085,6 @@ msgstr ""
msgid "Open Selection"
msgstr ""
-msgid "Open Web IDE"
-msgstr ""
-
msgid "Open comment type dropdown"
msgstr ""
@@ -17557,6 +18190,9 @@ msgstr ""
msgid "Origin"
msgstr ""
+msgid "Orphaned member"
+msgstr ""
+
msgid "Other Labels"
msgstr ""
@@ -17572,6 +18208,9 @@ msgstr ""
msgid "Other visibility settings have been disabled by the administrator."
msgstr ""
+msgid "Our documentation includes an example DevOps Score report."
+msgstr ""
+
msgid "Out-of-compliance with this project's policies and should be removed"
msgstr ""
@@ -17596,6 +18235,9 @@ msgstr ""
msgid "Overwrite diverged branches"
msgstr ""
+msgid "Owned by %{image_tag}"
+msgstr ""
+
msgid "Owned by anyone"
msgstr ""
@@ -17617,6 +18259,9 @@ msgstr ""
msgid "Package deleted successfully"
msgstr ""
+msgid "Package file size limits"
+msgstr ""
+
msgid "Package recipe already exists"
msgstr ""
@@ -17632,9 +18277,6 @@ msgstr ""
msgid "Package type must be PyPi"
msgstr ""
-msgid "Package was removed"
-msgstr ""
-
msgid "PackageRegistry|%{name} version %{version} was created %{datetime}"
msgstr ""
@@ -17776,12 +18418,18 @@ msgstr ""
msgid "PackageRegistry|NuGet Command"
msgstr ""
+msgid "PackageRegistry|Package Registry"
+msgstr ""
+
msgid "PackageRegistry|Pip Command"
msgstr ""
msgid "PackageRegistry|Pipeline %{link} triggered %{datetime} by %{author}"
msgstr ""
+msgid "PackageRegistry|Publish and share packages for a variety of common package managers. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "PackageRegistry|Published to the %{project} Package Registry %{datetime}"
msgstr ""
@@ -17881,6 +18529,9 @@ msgstr ""
msgid "Page not found"
msgstr ""
+msgid "Page settings"
+msgstr ""
+
msgid "Page was successfully deleted"
msgstr ""
@@ -18022,7 +18673,7 @@ msgstr ""
msgid "Paste issue link"
msgstr ""
-msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Don't use your private SSH key."
+msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Do not paste your private SSH key, as that can compromise your identity."
msgstr ""
msgid "Patch to apply"
@@ -18049,6 +18700,9 @@ msgstr ""
msgid "Pending"
msgstr ""
+msgid "Pending comments"
+msgstr ""
+
msgid "People without permission will never get a notification and won't be able to comment."
msgstr ""
@@ -18247,6 +18901,9 @@ msgstr ""
msgid "Pipelines|Build with confidence"
msgstr ""
+msgid "Pipelines|By revoking a trigger you will break any processes making use of it. Are you sure?"
+msgstr ""
+
msgid "Pipelines|CI Lint"
msgstr ""
@@ -18259,6 +18916,15 @@ msgstr ""
msgid "Pipelines|Continuous Integration can help catch bugs by running your tests automatically, while Continuous Deployment can help you deliver code to your product environment."
msgstr ""
+msgid "Pipelines|Copy trigger token"
+msgstr ""
+
+msgid "Pipelines|Description"
+msgstr ""
+
+msgid "Pipelines|Edit"
+msgstr ""
+
msgid "Pipelines|Get started with Pipelines"
msgstr ""
@@ -18274,15 +18940,27 @@ msgstr ""
msgid "Pipelines|It is recommended the code is reviewed thoroughly before running this pipeline with the parent project's CI resource."
msgstr ""
+msgid "Pipelines|Last Used"
+msgstr ""
+
msgid "Pipelines|Loading Pipelines"
msgstr ""
msgid "Pipelines|More Information"
msgstr ""
+msgid "Pipelines|No triggers have been created yet. Add one using the form above."
+msgstr ""
+
+msgid "Pipelines|Owner"
+msgstr ""
+
msgid "Pipelines|Project cache successfully reset."
msgstr ""
+msgid "Pipelines|Revoke"
+msgstr ""
+
msgid "Pipelines|Run Pipeline"
msgstr ""
@@ -18307,6 +18985,15 @@ msgstr ""
msgid "Pipelines|This project is not currently set up to run pipelines."
msgstr ""
+msgid "Pipelines|Token"
+msgstr ""
+
+msgid "Pipelines|Trigger user has insufficient permissions to project"
+msgstr ""
+
+msgid "Pipelines|invalid"
+msgstr ""
+
msgid "Pipelines|parent"
msgstr ""
@@ -18565,10 +19252,10 @@ msgstr ""
msgid "Please provide attributes to update"
msgstr ""
-msgid "Please refer to %{docs_url}"
+msgid "Please reach out if you have any questions and we'll be happy to assist."
msgstr ""
-msgid "Please retype the email address."
+msgid "Please refer to %{docs_url}"
msgstr ""
msgid "Please select"
@@ -18598,6 +19285,9 @@ msgstr ""
msgid "Please set a new password before proceeding."
msgstr ""
+msgid "Please share your feedback about %{featureName} %{linkStart}in this issue%{linkEnd} to help us improve the experience."
+msgstr ""
+
msgid "Please solve the reCAPTCHA"
msgstr ""
@@ -18901,6 +19591,9 @@ msgstr ""
msgid "Profiles| You are going to change the username %{currentUsernameBold} to %{newUsernameBold}. Profile and projects will be redirected to the %{newUsername} namespace but this redirect will expire once the %{currentUsername} namespace is registered by another user or group. Please update your Git repository remotes as soon as possible."
msgstr ""
+msgid "Profiles|%{provider} Active"
+msgstr ""
+
msgid "Profiles|@username"
msgstr ""
@@ -18952,7 +19645,7 @@ msgstr ""
msgid "Profiles|Commit email"
msgstr ""
-msgid "Profiles|Connect"
+msgid "Profiles|Connect %{provider}"
msgstr ""
msgid "Profiles|Connected Accounts"
@@ -18976,6 +19669,9 @@ msgstr ""
msgid "Profiles|Disconnect"
msgstr ""
+msgid "Profiles|Disconnect %{provider}"
+msgstr ""
+
msgid "Profiles|Do not show on profile"
msgstr ""
@@ -19000,7 +19696,7 @@ msgstr ""
msgid "Profiles|Full name"
msgstr ""
-msgid "Profiles|Give your individual key a title. This will be publically visible."
+msgid "Profiles|Give your individual key a title."
msgstr ""
msgid "Profiles|Include private contributions on my profile"
@@ -19090,7 +19786,7 @@ msgstr ""
msgid "Profiles|The maximum file size allowed is 200KB."
msgstr ""
-msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it?"
+msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it? It will be publicly visible."
msgstr ""
msgid "Profiles|This email will be displayed on your public profile"
@@ -19165,6 +19861,9 @@ msgstr ""
msgid "Profiles|You don't have access to delete this user."
msgstr ""
+msgid "Profiles|You must transfer ownership or delete groups you are an owner of before you can delete your account"
+msgstr ""
+
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
@@ -19753,6 +20452,9 @@ msgstr ""
msgid "ProjectTemplates|GitLab Cluster Management"
msgstr ""
+msgid "ProjectTemplates|Gitpod/Spring Petclinic"
+msgstr ""
+
msgid "ProjectTemplates|Go Micro"
msgstr ""
@@ -20362,6 +21064,9 @@ msgstr ""
msgid "Publish to status page"
msgstr ""
+msgid "Published"
+msgstr ""
+
msgid "Published on status page"
msgstr ""
@@ -20479,9 +21184,15 @@ msgstr ""
msgid "Quick range"
msgstr ""
+msgid "Quickly and easily edit multiple files in your project."
+msgstr ""
+
msgid "README"
msgstr ""
+msgid "Rails"
+msgstr ""
+
msgid "Rake Tasks Help"
msgstr ""
@@ -20602,10 +21313,13 @@ msgstr ""
msgid "Register Two-Factor Authenticator"
msgstr ""
-msgid "Register U2F device"
+msgid "Register Universal Two-Factor (U2F) Device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register WebAuthn Device"
+msgstr ""
+
+msgid "Register device"
msgstr ""
msgid "Register for GitLab"
@@ -20617,9 +21331,6 @@ msgstr ""
msgid "Register with two-factor app"
msgstr ""
-msgid "Registration"
-msgstr ""
-
msgid "Registration|Checkout"
msgstr ""
@@ -20737,9 +21448,6 @@ msgstr ""
msgid "Release|Something went wrong while saving the release details"
msgstr ""
-msgid "Remediated: needs review"
-msgstr ""
-
msgid "Remediations"
msgstr ""
@@ -20845,6 +21553,9 @@ msgstr ""
msgid "Remove priority"
msgstr ""
+msgid "Remove report"
+msgstr ""
+
msgid "Remove secondary node"
msgstr ""
@@ -20857,6 +21568,12 @@ msgstr ""
msgid "Remove time estimate"
msgstr ""
+msgid "Remove user & report"
+msgstr ""
+
+msgid "Remove user from group"
+msgstr ""
+
msgid "Removed"
msgstr ""
@@ -20938,9 +21655,6 @@ msgstr ""
msgid "Removes time estimate."
msgstr ""
-msgid "Removing license…"
-msgstr ""
-
msgid "Removing this group also removes all child projects, including archived projects, and their resources."
msgstr ""
@@ -21025,6 +21739,9 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
+msgid "Reported by %{reporter}"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -21112,6 +21829,27 @@ msgstr ""
msgid "Repositories"
msgstr ""
+msgid "Repositories Analytics"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download Historic Test Coverage Data"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download historic test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Historic Test Coverage Data is available in raw format (.csv) for further analysis."
+msgstr ""
+
+msgid "RepositoriesAnalytics|Test Code Coverage"
+msgstr ""
+
+msgid "RepositoriesAnalytics|There was an error fetching the projects."
+msgstr ""
+
msgid "Repository"
msgstr ""
@@ -21190,9 +21928,15 @@ msgstr ""
msgid "Request parameter %{param} is missing."
msgstr ""
+msgid "Request review from"
+msgstr ""
+
msgid "Request to link SAML account must be authorized"
msgstr ""
+msgid "Requested"
+msgstr ""
+
msgid "Requested %{time_ago}"
msgstr ""
@@ -21211,6 +21955,9 @@ msgstr ""
msgid "Requests to these domain(s)/address(es) on the local network will be allowed when local requests from hooks and services are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 or 127.0.0.0/28 are supported. Domain wildcards are not supported currently. Use comma, semicolon, or newline to separate multiple entries. The allowlist can hold a maximum of 1000 entries. Domains should use IDNA encoding. Ex: example.com, 192.168.1.1, 127.0.0.0/28, xn--itlab-j1a.com."
msgstr ""
+msgid "Require admin approval for new sign-ups"
+msgstr ""
+
msgid "Require all users in this group to setup Two-factor authentication"
msgstr ""
@@ -21340,9 +22087,6 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
-msgid "Resolved by %{resolvedByName}"
-msgstr ""
-
msgid "Resolves IP addresses once and uses them to submit requests"
msgstr ""
@@ -21463,6 +22207,15 @@ msgstr ""
msgid "ReviewApp|Enable Review App"
msgstr ""
+msgid "Reviewer"
+msgid_plural "%d Reviewers"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
+msgid "Reviewer(s)"
+msgstr ""
+
msgid "Reviewing"
msgstr ""
@@ -21502,6 +22255,9 @@ msgstr ""
msgid "Rook"
msgstr ""
+msgid "Ruby"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -21580,6 +22336,63 @@ msgstr ""
msgid "Runners page."
msgstr ""
+msgid "Runners|Active"
+msgstr ""
+
+msgid "Runners|Architecture"
+msgstr ""
+
+msgid "Runners|Can run untagged jobs"
+msgstr ""
+
+msgid "Runners|Description"
+msgstr ""
+
+msgid "Runners|Group"
+msgstr ""
+
+msgid "Runners|IP Address"
+msgstr ""
+
+msgid "Runners|Last contact"
+msgstr ""
+
+msgid "Runners|Locked to this project"
+msgstr ""
+
+msgid "Runners|Maximum job timeout"
+msgstr ""
+
+msgid "Runners|Name"
+msgstr ""
+
+msgid "Runners|Platform"
+msgstr ""
+
+msgid "Runners|Property Name"
+msgstr ""
+
+msgid "Runners|Protected"
+msgstr ""
+
+msgid "Runners|Revision"
+msgstr ""
+
+msgid "Runners|Shared"
+msgstr ""
+
+msgid "Runners|Specific"
+msgstr ""
+
+msgid "Runners|Tags"
+msgstr ""
+
+msgid "Runners|Value"
+msgstr ""
+
+msgid "Runners|Version"
+msgstr ""
+
msgid "Runners|You have used %{quotaUsed} out of %{quotaLimit} of your shared Runners pipeline minutes."
msgstr ""
@@ -21592,6 +22405,9 @@ msgstr ""
msgid "Runs a number of housekeeping tasks within the current repository, such as compressing file revisions and removing unreachable objects."
msgstr ""
+msgid "SAML"
+msgstr ""
+
msgid "SAML SSO"
msgstr ""
@@ -21643,6 +22459,9 @@ msgstr ""
msgid "Save"
msgstr ""
+msgid "Save %{name} size limits"
+msgstr ""
+
msgid "Save Changes"
msgstr ""
@@ -21673,9 +22492,6 @@ msgstr ""
msgid "Save space and find tags in the Container Registry more easily. Enable the cleanup policy to remove stale tags and keep only the ones you need."
msgstr ""
-msgid "Save template"
-msgstr ""
-
msgid "Save variables"
msgstr ""
@@ -21718,9 +22534,6 @@ msgstr ""
msgid "Scope"
msgstr ""
-msgid "Scope not supported with disabled 'users_search' feature!"
-msgstr ""
-
msgid "Scoped issue boards"
msgstr ""
@@ -21847,9 +22660,6 @@ msgstr ""
msgid "Search requirements"
msgstr ""
-msgid "Search results…"
-msgstr ""
-
msgid "Search users"
msgstr ""
@@ -21925,6 +22735,12 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgid "SearchResults|epic"
+msgid_plural "SearchResults|epics"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "SearchResults|issue"
msgid_plural "SearchResults|issues"
msgstr[0] ""
@@ -21976,10 +22792,10 @@ msgstr ""
msgid "Seat Link is disabled, and cannot be configured through this form."
msgstr ""
-msgid "Seats currently in use"
+msgid "Seats usage data as of %{last_enqueue_time}"
msgstr ""
-msgid "Seats in license"
+msgid "Seats usage data is updated every day at 12:00pm UTC"
msgstr ""
msgid "Secondary"
@@ -22033,6 +22849,9 @@ msgstr ""
msgid "SecurityConfiguration|Available for on-demand DAST"
msgstr ""
+msgid "SecurityConfiguration|By default, all analyzers are applied in order to cover all languages across your project, and only run if the language is detected in the Merge Request."
+msgstr ""
+
msgid "SecurityConfiguration|Configure"
msgstr ""
@@ -22063,16 +22882,19 @@ msgstr ""
msgid "SecurityConfiguration|Manage"
msgstr ""
+msgid "SecurityConfiguration|More information"
+msgstr ""
+
msgid "SecurityConfiguration|Not enabled"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|Security Control"
+msgid "SecurityConfiguration|SAST Configuration"
msgstr ""
-msgid "SecurityConfiguration|See documentation"
+msgid "SecurityConfiguration|Security Control"
msgstr ""
msgid "SecurityConfiguration|Status"
@@ -22084,6 +22906,9 @@ msgstr ""
msgid "SecurityConfiguration|Using custom settings. You won't receive automatic updates on this variable. %{anchorStart}Restore to default%{anchorEnd}"
msgstr ""
+msgid "SecurityConfiguration|View history"
+msgstr ""
+
msgid "SecurityConfiguration|You can quickly enable all security scanning tools by enabling %{linkStart}Auto DevOps%{linkEnd}."
msgstr ""
@@ -22162,9 +22987,6 @@ msgstr ""
msgid "SecurityReports|Learn more about setting up your dashboard"
msgstr ""
-msgid "SecurityReports|Load more vulnerabilities"
-msgstr ""
-
msgid "SecurityReports|Monitor vulnerabilities in your code"
msgstr ""
@@ -22444,7 +23266,7 @@ msgstr ""
msgid "Select status"
msgstr ""
-msgid "Select strategy activation method"
+msgid "Select strategy activation method."
msgstr ""
msgid "Select subscription"
@@ -22459,7 +23281,7 @@ msgstr ""
msgid "Select the custom project template source group."
msgstr ""
-msgid "Select timeframe"
+msgid "Select the environment scope for this feature flag."
msgstr ""
msgid "Select timezone"
@@ -22708,6 +23530,9 @@ msgstr ""
msgid "Set iteration"
msgstr ""
+msgid "Set limit to 0 to allow any file size."
+msgstr ""
+
msgid "Set max session time for web terminal."
msgstr ""
@@ -22786,10 +23611,13 @@ msgstr ""
msgid "Set up a %{type} Runner manually"
msgstr ""
+msgid "Set up a hardware device as a second factor to sign in."
+msgstr ""
+
msgid "Set up assertions/attributes/claims (email, first_name, last_name) and NameID according to %{docsLinkStart}the documentation %{icon}%{docsLinkEnd}"
msgstr ""
-msgid "Set up new U2F device"
+msgid "Set up new device"
msgstr ""
msgid "Set up new password"
@@ -22858,6 +23686,9 @@ msgstr ""
msgid "Sets weight to %{weight}."
msgstr ""
+msgid "Setting this to 0 means using the system default timeout value."
+msgstr ""
+
msgid "Settings"
msgstr ""
@@ -22873,6 +23704,15 @@ msgstr ""
msgid "Severity"
msgstr ""
+msgid "SeverityWidget|Severity"
+msgstr ""
+
+msgid "SeverityWidget|Severity: %{severity}"
+msgstr ""
+
+msgid "SeverityWidget|There was an error while updating severity."
+msgstr ""
+
msgid "Shards (%{shards})"
msgstr ""
@@ -22918,6 +23758,9 @@ msgstr ""
msgid "Show all requirements."
msgstr ""
+msgid "Show all test cases."
+msgstr ""
+
msgid "Show archived projects"
msgstr ""
@@ -22930,6 +23773,9 @@ msgstr ""
msgid "Show comments"
msgstr ""
+msgid "Show comments on this file"
+msgstr ""
+
msgid "Show comments only"
msgstr ""
@@ -22975,6 +23821,12 @@ msgstr ""
msgid "Show parent subgroups"
msgstr ""
+msgid "Show the Closed list"
+msgstr ""
+
+msgid "Show the Open list"
+msgstr ""
+
msgid "Show whitespace changes"
msgstr ""
@@ -23020,9 +23872,6 @@ msgstr ""
msgid "Sidebar|Assign health status"
msgstr ""
-msgid "Sidebar|Change weight"
-msgstr ""
-
msgid "Sidebar|Health status"
msgstr ""
@@ -23206,6 +24055,9 @@ msgstr ""
msgid "Snippets|Add another file %{num}/%{total}"
msgstr ""
+msgid "Snippets|Authored %{time_ago} by %{author}"
+msgstr ""
+
msgid "Snippets|Delete file"
msgstr ""
@@ -23233,6 +24085,9 @@ msgstr ""
msgid "Solution"
msgstr ""
+msgid "Some changes are not shown"
+msgstr ""
+
msgid "Some child epics may be hidden due to applied filters"
msgstr ""
@@ -23599,6 +24454,12 @@ msgstr ""
msgid "Source (branch or tag)"
msgstr ""
+msgid "Source Branch"
+msgstr ""
+
+msgid "Source branch: %{source_branch_open}%{source_branch}%{source_branch_close}"
+msgstr ""
+
msgid "Source code"
msgstr ""
@@ -23764,9 +24625,6 @@ msgstr ""
msgid "Start and due date"
msgstr ""
-msgid "Start by choosing a group to see how your team is spending time. You can then drill down to the project level."
-msgstr ""
-
msgid "Start by choosing a group to start exploring the merge requests in that group. You can then proceed to filter by projects, labels, milestones and authors."
msgstr ""
@@ -23848,18 +24706,27 @@ msgstr ""
msgid "StaticSiteEditor|3. Assign a person to review and accept the merge request."
msgstr ""
+msgid "StaticSiteEditor|A link to view the merge request will appear once ready."
+msgstr ""
+
msgid "StaticSiteEditor|An error occurred while submitting your changes."
msgstr ""
msgid "StaticSiteEditor|Branch could not be created."
msgstr ""
+msgid "StaticSiteEditor|Copy update"
+msgstr ""
+
msgid "StaticSiteEditor|Could not commit the content changes."
msgstr ""
msgid "StaticSiteEditor|Could not create merge request."
msgstr ""
+msgid "StaticSiteEditor|Creating your merge request"
+msgstr ""
+
msgid "StaticSiteEditor|Incompatible file content"
msgstr ""
@@ -23881,6 +24748,9 @@ msgstr ""
msgid "StaticSiteEditor|View documentation"
msgstr ""
+msgid "StaticSiteEditor|You can set an assignee to get your changes reviewed and deployed once your merge request is created."
+msgstr ""
+
msgid "StaticSiteEditor|Your merge request has been created"
msgstr ""
@@ -24010,15 +24880,15 @@ msgstr ""
msgid "Submit %{humanized_resource_name}"
msgstr ""
-msgid "Submit Changes"
-msgstr ""
-
msgid "Submit a review"
msgstr ""
msgid "Submit as spam"
msgstr ""
+msgid "Submit changes"
+msgstr ""
+
msgid "Submit feedback"
msgstr ""
@@ -24172,6 +25042,9 @@ msgstr ""
msgid "Successfully deleted U2F device."
msgstr ""
+msgid "Successfully deleted WebAuthn device."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -24490,9 +25363,6 @@ msgstr ""
msgid "Template to append to all Service Desk issues"
msgstr ""
-msgid "Template was successfully saved."
-msgstr ""
-
msgid "Templates"
msgstr ""
@@ -24574,10 +25444,28 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
-msgid "Test failed."
+msgid "Test settings"
+msgstr ""
+
+msgid "TestCases|New Test Case"
+msgstr ""
+
+msgid "TestCases|New test case"
+msgstr ""
+
+msgid "TestCases|Search test cases"
msgstr ""
-msgid "Test settings and save changes"
+msgid "TestCases|Something went wrong while creating a test case."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching count of test cases."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching test cases list."
+msgstr ""
+
+msgid "TestCases|Submit test case"
msgstr ""
msgid "TestHooks|Ensure one of your projects has merge requests."
@@ -24643,6 +25531,9 @@ msgstr ""
msgid "Thank you for signing up for your free trial! You will get additional instructions in your inbox shortly."
msgstr ""
+msgid "Thank you for your business."
+msgstr ""
+
msgid "Thank you for your feedback!"
msgstr ""
@@ -24703,9 +25594,6 @@ msgstr ""
msgid "The URL to use for connecting to Elasticsearch. Use a comma-separated list to support clustering (e.g., \"http://localhost:9200, http://localhost:9201\")."
msgstr ""
-msgid "The Web IDE offers advanced syntax highlighting capabilities and more."
-msgstr ""
-
msgid "The X509 Certificate to use when mutual TLS is required to communicate with the external authorization service. If left blank, the server certificate is still validated when accessing over HTTPS."
msgstr ""
@@ -24817,6 +25705,9 @@ msgstr ""
msgid "The form contains the following error:"
msgstr ""
+msgid "The form contains the following warning:"
+msgstr ""
+
msgid "The global settings require you to enable Two-Factor Authentication for your account."
msgstr ""
@@ -24931,9 +25822,6 @@ msgstr ""
msgid "The private key to use when a client certificate is provided. This value is encrypted at rest."
msgstr ""
-msgid "The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The project can be accessed by any logged in user."
msgstr ""
@@ -24970,7 +25858,7 @@ msgstr ""
msgid "The remote repository is being updated..."
msgstr ""
-msgid "The repository can be commited to, and issues, comments and other entities can be created."
+msgid "The repository can be committed to, and issues, comments and other entities can be created."
msgstr ""
msgid "The repository for this project does not exist."
@@ -25024,9 +25912,6 @@ msgstr ""
msgid "The time taken by each data entry gathered by that stage."
msgstr ""
-msgid "The total stage shows the time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The update action will time out after %{number_of_minutes} minutes. For big repositories, use a clone/push combination."
msgstr ""
@@ -25090,6 +25975,9 @@ msgstr ""
msgid "There are no archived requirements"
msgstr ""
+msgid "There are no archived test cases"
+msgstr ""
+
msgid "There are no changes"
msgstr ""
@@ -25129,6 +26017,9 @@ msgstr ""
msgid "There are no open requirements"
msgstr ""
+msgid "There are no open test cases"
+msgstr ""
+
msgid "There are no packages yet"
msgstr ""
@@ -25141,6 +26032,9 @@ msgstr ""
msgid "There is a limit of %{ci_project_subscriptions_limit} subscriptions from or to a project."
msgstr ""
+msgid "There is already a To-Do for this design."
+msgstr ""
+
msgid "There is already a repository with that name on disk"
msgstr ""
@@ -25159,6 +26053,9 @@ msgstr ""
msgid "There was a problem communicating with your device."
msgstr ""
+msgid "There was a problem fetching branches."
+msgstr ""
+
msgid "There was a problem fetching groups."
msgstr ""
@@ -25387,9 +26284,15 @@ msgstr ""
msgid "This action can lead to data loss. To prevent accidental actions we ask you to confirm your intention."
msgstr ""
+msgid "This action cannot be undone, and will permanently delete the %{key} SSH key"
+msgstr ""
+
msgid "This action cannot be undone. You will lose the project's repository and all content: issues, merge requests, etc."
msgstr ""
+msgid "This action has been performed too many times. Try again later."
+msgstr ""
+
msgid "This action will %{strongOpen}permanently delete%{strongClose} %{codeOpen}%{project}%{codeClose} %{strongOpen}immediately%{strongClose}, including its repositories and all content: issues, merge requests, etc."
msgstr ""
@@ -25417,9 +26320,6 @@ msgstr ""
msgid "This board's scope is reduced"
msgstr ""
-msgid "This branch has changed since you started editing. Would you like to create a new branch?"
-msgstr ""
-
msgid "This chart could not be displayed"
msgstr ""
@@ -25546,15 +26446,9 @@ msgstr ""
msgid "This is a security log of important events involving your account."
msgstr ""
-msgid "This is the author's first Merge Request to this project."
-msgstr ""
-
msgid "This is the highest peak of users on your installation since the license started."
msgstr ""
-msgid "This is the maximum number of users that have existed at the same time since the license started. This is the minimum number of seats you will need to buy when you renew your license."
-msgstr ""
-
msgid "This is the number of currently active users on your installation, and this is the minimum number you need to purchase when you renew your license."
msgstr ""
@@ -25786,6 +26680,15 @@ msgstr ""
msgid "This user has no identities"
msgstr ""
+msgid "This user has previously committed to the %{name} project."
+msgstr ""
+
+msgid "This user has the %{access} role in the %{name} project."
+msgstr ""
+
+msgid "This user is the author of this %{noteable}."
+msgstr ""
+
msgid "This user will be the author of all events in the activity feed that are the result of an update, like new branches being created or new commits being pushed to existing branches."
msgstr ""
@@ -25816,6 +26719,9 @@ msgstr ""
msgid "Threat Monitoring"
msgstr ""
+msgid "ThreatMonitoring|All Environments"
+msgstr ""
+
msgid "ThreatMonitoring|Anomalous Requests"
msgstr ""
@@ -25843,9 +26749,6 @@ msgstr ""
msgid "ThreatMonitoring|Operations Per Second"
msgstr ""
-msgid "ThreatMonitoring|Overview"
-msgstr ""
-
msgid "ThreatMonitoring|Packet Activity"
msgstr ""
@@ -25864,6 +26767,9 @@ msgstr ""
msgid "ThreatMonitoring|Something went wrong, unable to fetch statistics"
msgstr ""
+msgid "ThreatMonitoring|Statistics"
+msgstr ""
+
msgid "ThreatMonitoring|The firewall is not installed or has been disabled. To view this data, ensure the web application firewall is installed and enabled for your cluster."
msgstr ""
@@ -26257,6 +27163,9 @@ msgstr ""
msgid "To update Snippets with multiple files, you must use the `files` parameter"
msgstr ""
+msgid "To use Gitpod you must first enable the feature in the integrations section of your %{user_prefs}."
+msgstr ""
+
msgid "To view all %{scannedResourcesCount} scanned URLs, please download the CSV file"
msgstr ""
@@ -26290,9 +27199,6 @@ msgstr ""
msgid "Toggle Sidebar"
msgstr ""
-msgid "Toggle all threads"
-msgstr ""
-
msgid "Toggle backtrace"
msgstr ""
@@ -26317,9 +27223,6 @@ msgstr ""
msgid "Toggle navigation"
msgstr ""
-msgid "Toggle project"
-msgstr ""
-
msgid "Toggle sidebar"
msgstr ""
@@ -26359,6 +27262,9 @@ msgstr ""
msgid "Too many projects enabled. You will need to manage them via the console or the API."
msgstr ""
+msgid "Too much data"
+msgstr ""
+
msgid "Topics (optional)"
msgstr ""
@@ -26377,6 +27283,9 @@ msgstr ""
msgid "Total cores (CPUs)"
msgstr ""
+msgid "Total days to completion"
+msgstr ""
+
msgid "Total issues"
msgstr ""
@@ -26473,6 +27382,9 @@ msgstr ""
msgid "Trending"
msgstr ""
+msgid "Trials|Create a new group to start your GitLab Gold trial."
+msgstr ""
+
msgid "Trials|Go back to GitLab"
msgstr ""
@@ -26482,6 +27394,15 @@ msgstr ""
msgid "Trials|You can always resume this process by selecting your avatar and choosing 'Start a Gold trial'"
msgstr ""
+msgid "Trials|You can apply your trial to a new group or an existing group."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group or your personal account."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group, an existing group, or your personal account."
+msgstr ""
+
msgid "Trials|You won't get a free trial right now but you can always resume this process by clicking on your avatar and choosing 'Start a free trial'"
msgstr ""
@@ -26551,6 +27472,9 @@ msgstr ""
msgid "Try using a different search term to find the file you are looking for."
msgstr ""
+msgid "Trying to communicate with your device. Plug it in (if needed) and press the button on the device now."
+msgstr ""
+
msgid "Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now."
msgstr ""
@@ -26638,6 +27562,12 @@ msgstr ""
msgid "URL or request ID"
msgstr ""
+msgid "USER %{user} WILL BE REMOVED! Are you sure?"
+msgstr ""
+
+msgid "USER WILL BE BLOCKED! Are you sure?"
+msgstr ""
+
msgid "UTC"
msgstr ""
@@ -26695,9 +27625,6 @@ msgstr ""
msgid "Unable to load the merge request widget. Try reloading the page."
msgstr ""
-msgid "Unable to resolve"
-msgstr ""
-
msgid "Unable to save iteration. Please try again"
msgstr ""
@@ -26746,6 +27673,9 @@ msgstr ""
msgid "Undo ignore"
msgstr ""
+msgid "Unexpected error"
+msgstr ""
+
msgid "Unfortunately, your email message to GitLab could not be processed."
msgstr ""
@@ -26779,6 +27709,9 @@ msgstr ""
msgid "Unknown response text"
msgstr ""
+msgid "Unless otherwise agreed to in writing with GitLab, by clicking \"Upload License\" you agree that your use of GitLab Software is subject to the %{eula_link_start}Terms of Service%{eula_link_end}."
+msgstr ""
+
msgid "Unlimited"
msgstr ""
@@ -27145,9 +28078,6 @@ msgstr ""
msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
msgstr ""
-msgid "Use a hardware device to add the second factor of authentication."
-msgstr ""
-
msgid "Use an one time password authenticator on your mobile device or computer to enable two-factor authentication (2FA)."
msgstr ""
@@ -27421,13 +28351,13 @@ msgstr ""
msgid "Users"
msgstr ""
-msgid "Users in License:"
+msgid "Users in License"
msgstr ""
-msgid "Users or groups set as approvers in the project's or merge request's settings."
+msgid "Users in License:"
msgstr ""
-msgid "Users outside of license"
+msgid "Users or groups set as approvers in the project's or merge request's settings."
msgstr ""
msgid "Users over License:"
@@ -27445,9 +28375,6 @@ msgstr ""
msgid "Users with a Guest role or those who don't belong to a Project or Group will not use a seat from your license."
msgstr ""
-msgid "Users with a Guest role or those who don't belong to any projects or groups don't count towards seats in use."
-msgstr ""
-
msgid "UsersSelect|%{name} + %{length} more"
msgstr ""
@@ -27487,9 +28414,6 @@ msgstr ""
msgid "Validations failed."
msgstr ""
-msgid "Validity"
-msgstr ""
-
msgid "Value"
msgstr ""
@@ -27508,6 +28432,9 @@ msgstr ""
msgid "Value Stream Name"
msgstr ""
+msgid "ValueStreamAnalyticsStage|We don't have enough data to show this stage."
+msgstr ""
+
msgid "ValueStreamAnalytics|%{days}d"
msgstr ""
@@ -27766,6 +28693,9 @@ msgstr ""
msgid "VisualReviewApp|Steps 1 and 2 (and sometimes 3) are performed once by the developer before requesting feedback. Steps 3 (if necessary), 4 is performed by the reviewer each time they perform a review."
msgstr ""
+msgid "Visualization"
+msgstr ""
+
msgid "Vulnerabilities"
msgstr ""
@@ -27793,34 +28723,31 @@ msgstr ""
msgid "VulnerabilityChart|Severity"
msgstr ""
-msgid "VulnerabilityManagement|A true-positive and will fix"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Change status"
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|Confirm"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Confirmed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
-msgstr ""
-
-msgid "VulnerabilityManagement|Detected %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|A true-positive and will fix"
msgstr ""
-msgid "VulnerabilityManagement|Dismiss"
+msgid "VulnerabilityManagement|Change status"
msgstr ""
-msgid "VulnerabilityManagement|Dismissed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
msgstr ""
-msgid "VulnerabilityManagement|Resolved"
+msgid "VulnerabilityManagement|Detected"
msgstr ""
-msgid "VulnerabilityManagement|Resolved %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Needs triage"
msgstr ""
msgid "VulnerabilityManagement|Something went wrong while trying to delete the comment. Please try again later."
@@ -27871,6 +28798,9 @@ msgstr ""
msgid "Vulnerability|%{scannerName} (version %{scannerVersion})"
msgstr ""
+msgid "Vulnerability|Activity"
+msgstr ""
+
msgid "Vulnerability|Class"
msgstr ""
@@ -27883,6 +28813,9 @@ msgstr ""
msgid "Vulnerability|Description"
msgstr ""
+msgid "Vulnerability|Detected"
+msgstr ""
+
msgid "Vulnerability|Evidence"
msgstr ""
@@ -27946,6 +28879,9 @@ msgstr ""
msgid "Warning: Displaying this diagram might cause performance issues on this page."
msgstr ""
+msgid "We are currently unable to fetch data for the pipeline header."
+msgstr ""
+
msgid "We are currently unable to fetch data for this graph."
msgstr ""
@@ -27985,6 +28921,12 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
+msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
+msgstr ""
+
+msgid "We would like to inform you that your subscription GitLab Enterprise Edition %{plan_name} is nearing its user limit. You have %{active_user_count} active users, which is almost at the user limit of %{maximum_user_count}."
+msgstr ""
+
msgid "We've found no vulnerabilities"
msgstr ""
@@ -28000,6 +28942,12 @@ msgstr ""
msgid "Web terminal"
msgstr ""
+msgid "WebAuthn Devices (%{length})"
+msgstr ""
+
+msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
+msgstr ""
+
msgid "WebIDE|Merge request"
msgstr ""
@@ -28138,15 +29086,9 @@ msgstr ""
msgid "Welcome to the guided GitLab tour"
msgstr ""
-msgid "Welcome to your Issue Board!"
-msgstr ""
-
msgid "Welcome to your issue board!"
msgstr ""
-msgid "We’ve been making changes to %{featureName} and we’d love your feedback %{linkStart}in this issue%{linkEnd} to help us improve the experience."
-msgstr ""
-
msgid "What are you searching for?"
msgstr ""
@@ -28165,6 +29107,9 @@ msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
msgstr ""
+msgid "When enabled, any user visiting %{host} and creating an account will have to be explicitly approved by the admin before they can login. This setting is effective only if sign-ups are enabled."
+msgstr ""
+
msgid "When enabled, any user visiting %{host} will be able to create an account."
msgstr ""
@@ -28390,6 +29335,9 @@ msgstr ""
msgid "With requirements, you can set criteria to check your products against."
msgstr ""
+msgid "With test cases, you can define conditions for your project to meet in determining quality"
+msgstr ""
+
msgid "Withdraw Access Request"
msgstr ""
@@ -28405,6 +29353,9 @@ msgstr ""
msgid "Workflow Help"
msgstr ""
+msgid "Would you like to create a new branch?"
+msgstr ""
+
msgid "Write"
msgstr ""
@@ -28426,6 +29377,9 @@ msgstr ""
msgid "Wrong extern UID provided. Make sure Auth0 is configured correctly."
msgstr ""
+msgid "YYYY-MM-DD"
+msgstr ""
+
msgid "Yes"
msgstr ""
@@ -28483,7 +29437,7 @@ msgstr ""
msgid "You are going to remove the fork relationship from %{project_full_name}. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "You are going to transfer %{project_full_name} to another owner. Are you ABSOLUTELY sure?"
+msgid "You are going to transfer %{project_full_name} to another namespace. Are you ABSOLUTELY sure?"
msgstr ""
msgid "You are going to turn off the confidentiality. This means %{strongStart}everyone%{strongEnd} will be able to see and leave a comment on this %{issuableType}."
@@ -28543,9 +29497,6 @@ msgstr ""
msgid "You can always edit this later"
msgstr ""
-msgid "You can apply your Trial to your Personal account or create a New Group."
-msgstr ""
-
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings"
msgstr ""
@@ -28567,12 +29518,18 @@ msgstr ""
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
+msgid "You can find more information about GitLab subscriptions in %{subscriptions_doc_link}."
+msgstr ""
+
msgid "You can generate an access token scoped to this project for each application to use the GitLab API."
msgstr ""
msgid "You can get started by cloning the repository or start adding files to it with one of the following options."
msgstr ""
+msgid "You can group test cases using labels. To learn about the future direction of this feature, visit %{linkStart}Quality Management direction page%{linkEnd}."
+msgstr ""
+
msgid "You can invite a new member to %{project_name} or invite another group."
msgstr ""
@@ -28588,6 +29545,9 @@ msgstr ""
msgid "You can notify the app / group or a project by sending them an email notification"
msgstr ""
+msgid "You can now close this window."
+msgstr ""
+
msgid "You can now export your security dashboard to a CSV report."
msgstr ""
@@ -28636,9 +29596,6 @@ msgstr ""
msgid "You can test your .gitlab-ci.yml in %{linkStart}CI Lint%{linkEnd}."
msgstr ""
-msgid "You can try again using %{begin_link}basic search%{end_link}"
-msgstr ""
-
msgid "You cannot access the raw file. Please wait a minute."
msgstr ""
@@ -28690,6 +29647,9 @@ msgstr ""
msgid "You don't have any U2F devices registered yet."
msgstr ""
+msgid "You don't have any WebAuthn devices registered yet."
+msgstr ""
+
msgid "You don't have any active chat names."
msgstr ""
@@ -28777,6 +29737,9 @@ msgstr ""
msgid "You must accept our Terms of Service and privacy policy in order to register an account"
msgstr ""
+msgid "You must be logged in to search across all of GitLab"
+msgstr ""
+
msgid "You must disassociate %{domain} from all clusters it is attached to before deletion."
msgstr ""
@@ -28816,7 +29779,7 @@ msgstr ""
msgid "You need to be logged in."
msgstr ""
-msgid "You need to register a two-factor authentication app before you can set up a U2F device."
+msgid "You need to register a two-factor authentication app before you can set up a device."
msgstr ""
msgid "You need to set terms to be enforced"
@@ -28834,6 +29797,9 @@ msgstr ""
msgid "You reached %{usage_in_percent} of %{namespace_name}'s storage capacity (%{used_storage} of %{storage_limit})"
msgstr ""
+msgid "You successfully declined the invitation"
+msgstr ""
+
msgid "You tried to fork %{link_to_the_project} but it failed for the following reason:"
msgstr ""
@@ -28999,10 +29965,13 @@ msgstr ""
msgid "Your U2F device did not send a valid JSON response."
msgstr ""
-msgid "Your U2F device needs to be set up. Plug it in (if not already) and click the button on the left."
+msgid "Your U2F device was registered!"
+msgstr ""
+
+msgid "Your WebAuthn device did not send a valid JSON response."
msgstr ""
-msgid "Your U2F device was registered!"
+msgid "Your WebAuthn device was registered!"
msgstr ""
msgid "Your access request to the %{source_type} has been withdrawn."
@@ -29026,6 +29995,9 @@ msgstr ""
msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
msgstr ""
+msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
+msgstr ""
+
msgid "Your changes can be committed to %{branch_name} because a merge request is open."
msgstr ""
@@ -29062,6 +30034,12 @@ msgstr ""
msgid "Your deployment services will be broken, you will need to manually fix the services after renaming."
msgstr ""
+msgid "Your device is not compatible with GitLab. Please try another device"
+msgstr ""
+
+msgid "Your device needs to be set up. Plug it in (if needed) and click the button on the left."
+msgstr ""
+
msgid "Your device was successfully set up! Give it a name and register it with the GitLab server."
msgstr ""
@@ -29176,9 +30154,6 @@ msgstr[2] ""
msgid "access:"
msgstr ""
-msgid "activated"
-msgstr ""
-
msgid "added %{created_at_timeago}"
msgstr ""
@@ -29251,9 +30226,21 @@ msgstr ""
msgid "by %{user}"
msgstr ""
+msgid "cannot be a date in the past"
+msgstr ""
+
msgid "cannot be changed if a personal project has container registry tags."
msgstr ""
+msgid "cannot be changed if shared runners are enabled"
+msgstr ""
+
+msgid "cannot be enabled because parent group does not allow it"
+msgstr ""
+
+msgid "cannot be enabled because parent group has shared Runners disabled"
+msgstr ""
+
msgid "cannot be enabled unless all domains have TLS certificates"
msgstr ""
@@ -29299,7 +30286,7 @@ msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about SAST %{linkEndTag}"
msgstr ""
-msgid "ciReport|%{linkStartTag}Learn more about Secret Scanning %{linkEndTag}"
+msgid "ciReport|%{linkStartTag}Learn more about Secret Detection %{linkEndTag}"
msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about codequality reports %{linkEndTag}"
@@ -29617,9 +30604,6 @@ msgstr ""
msgid "error"
msgstr ""
-msgid "error code:"
-msgstr ""
-
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr ""
@@ -29641,6 +30625,9 @@ msgstr ""
msgid "failed to dismiss associated finding(id=%{finding_id}): %{message}"
msgstr ""
+msgid "failed to revert associated finding(id=%{finding_id}) to detected"
+msgstr ""
+
msgid "file"
msgid_plural "files"
msgstr[0] ""
@@ -30187,6 +31174,9 @@ msgstr ""
msgid "must be a root namespace"
msgstr ""
+msgid "must be a valid IPv4 or IPv6 address"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -30223,6 +31213,9 @@ msgstr ""
msgid "no expiration"
msgstr ""
+msgid "no name set"
+msgstr ""
+
msgid "no one can merge"
msgstr ""
@@ -30406,9 +31399,6 @@ msgstr ""
msgid "security Reports|There was an error creating the merge request"
msgstr ""
-msgid "settings saved, but not activated"
-msgstr ""
-
msgid "severity|Critical"
msgstr ""
@@ -30535,9 +31525,6 @@ msgstr ""
msgid "toggle collapse"
msgstr ""
-msgid "toggle dropdown"
-msgstr ""
-
msgid "triggered"
msgstr ""
@@ -30565,6 +31552,9 @@ msgstr ""
msgid "user avatar"
msgstr ""
+msgid "user preferences"
+msgstr ""
+
msgid "username"
msgstr ""
diff --git a/locale/sv_SE/gitlab.po b/locale/sv_SE/gitlab.po
index 2e0e28ee022..93e28b8a8d9 100644
--- a/locale/sv_SE/gitlab.po
+++ b/locale/sv_SE/gitlab.po
@@ -14,7 +14,10 @@ msgstr ""
"X-Crowdin-Language: sv-SE\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 6\n"
-"PO-Revision-Date: 2020-09-04 23:11\n"
+"PO-Revision-Date: 2020-10-02 18:51\n"
+
+msgid " %{project_name}#%{issue_iid} &middot; opened %{issue_created} by %{author}"
+msgstr ""
msgid " %{start} to %{end}"
msgstr ""
@@ -74,6 +77,16 @@ msgstr ""
msgid "\"el\" parameter is required for createInstance()"
msgstr ""
+msgid "%d Approval"
+msgid_plural "%d Approvals"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d Package"
+msgid_plural "%d Packages"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d Scanned URL"
msgid_plural "%d Scanned URLs"
msgstr[0] ""
@@ -137,6 +150,11 @@ msgstr[1] ""
msgid "%d commits"
msgstr ""
+msgid "%d completed issue"
+msgid_plural "%d completed issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d contribution"
msgid_plural "%d contributions"
msgstr[0] ""
@@ -147,6 +165,11 @@ msgid_plural "%d days"
msgstr[0] ""
msgstr[1] ""
+msgid "%d day until tags are automatically removed"
+msgid_plural "%d days until tags are automatically removed"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d error"
msgid_plural "%d errors"
msgstr[0] ""
@@ -237,6 +260,16 @@ msgid_plural "%d more comments"
msgstr[0] ""
msgstr[1] ""
+msgid "%d open issue"
+msgid_plural "%d open issues"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d pending comment"
+msgid_plural "%d pending comments"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d personal project will be removed and cannot be restored."
msgid_plural "%d personal projects will be removed and cannot be restored."
msgstr[0] ""
@@ -252,6 +285,11 @@ msgid_plural "%d projects"
msgstr[0] ""
msgstr[1] ""
+msgid "%d project selected"
+msgid_plural "%d projects selected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d request with warnings"
msgid_plural "%d requests with warnings"
msgstr[0] ""
@@ -272,6 +310,11 @@ msgid_plural "%d tags"
msgstr[0] ""
msgstr[1] ""
+msgid "%d tag per image name"
+msgid_plural "%d tags per image name"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d unassigned issue"
msgid_plural "%d unassigned issues"
msgstr[0] ""
@@ -292,6 +335,11 @@ msgid_plural "%d vulnerabilities dismissed"
msgstr[0] ""
msgstr[1] ""
+msgid "%d warning found:"
+msgid_plural "%d warnings found:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%s additional commit has been omitted to prevent performance issues."
msgid_plural "%s additional commits have been omitted to prevent performance issues."
msgstr[0] ""
@@ -330,6 +378,9 @@ msgstr ""
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr ""
+msgid "%{completedCount} completed weight"
+msgstr ""
+
msgid "%{completedWeight} of %{totalWeight} weight completed"
msgstr ""
@@ -378,14 +429,12 @@ msgid_plural "%{count} participants"
msgstr[0] ""
msgstr[1] ""
-msgid "%{count} pending comment"
-msgid_plural "%{count} pending comments"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
+msgid "%{count} total weight"
+msgstr ""
+
msgid "%{dashboard_path} could not be found."
msgstr ""
@@ -440,6 +489,9 @@ msgstr ""
msgid "%{group_name} uses group managed accounts. You need to create a new GitLab account which will be managed by %{group_name}."
msgstr ""
+msgid "%{group_name}&%{epic_iid} &middot; opened %{epic_created} by %{author}"
+msgstr ""
+
msgid "%{host} sign-in from new location"
msgstr ""
@@ -452,7 +504,7 @@ msgstr ""
msgid "%{issuableType} will be removed! Are you sure?"
msgstr ""
-msgid "%{issuesSize} issues with a limit of %{maxIssueCount}"
+msgid "%{issuesCount} issues with a limit of %{maxIssueCount}"
msgstr ""
msgid "%{issuesSize} with a limit of %{maxIssueCount}"
@@ -485,7 +537,7 @@ msgstr ""
msgid "%{labelStart}Namespace:%{labelEnd} %{namespace}"
msgstr ""
-msgid "%{labelStart}Report Type:%{labelEnd} %{reportType}"
+msgid "%{labelStart}Scan Type:%{labelEnd} %{reportType}"
msgstr ""
msgid "%{labelStart}Scanner:%{labelEnd} %{scanner}"
@@ -682,9 +734,6 @@ msgid_plural "%{securityScanner} results are not available because a pipeline ha
msgstr[0] ""
msgstr[1] ""
-msgid "%{service_title} %{message}."
-msgstr ""
-
msgid "%{size} GiB"
msgstr ""
@@ -773,6 +822,12 @@ msgstr ""
msgid "%{timebox_name} should belong either to a project or a group."
msgstr ""
+msgid "%{timebox_type} does not support burnup charts"
+msgstr ""
+
+msgid "%{timebox_type} must have a start and due date"
+msgstr ""
+
msgid "%{title} %{operator} %{threshold}"
msgstr ""
@@ -797,7 +852,7 @@ msgstr ""
msgid "%{total} open issue weight"
msgstr ""
-msgid "%{total} open issues"
+msgid "%{total} warnings found: showing first %{warningsDisplayed}"
msgstr ""
msgid "%{usage_ping_link_start}Learn more%{usage_ping_link_end} about what information is shared with GitLab Inc."
@@ -830,9 +885,6 @@ msgstr ""
msgid "&lt; 1 hour"
msgstr ""
-msgid "&lt;no name set&gt;"
-msgstr ""
-
msgid "&lt;no scopes selected&gt;"
msgstr ""
@@ -863,6 +915,9 @@ msgstr ""
msgid "'%{name}' Value Stream created"
msgstr ""
+msgid "'%{name}' Value Stream deleted"
+msgstr ""
+
msgid "'%{name}' stage already exists"
msgstr ""
@@ -922,6 +977,9 @@ msgstr ""
msgid "+ %{numberOfHiddenAssignees} more"
msgstr ""
+msgid "+ %{numberOfHiddenReviewers} more"
+msgstr ""
+
msgid "+%d more"
msgid_plural "+%d more"
msgstr[0] ""
@@ -982,6 +1040,11 @@ msgid_plural "%d Days"
msgstr[0] ""
msgstr[1] ""
+msgid "1 Issue"
+msgid_plural "%d Issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "1 closed issue"
msgid_plural "%{issues} closed issues"
msgstr[0] ""
@@ -997,6 +1060,11 @@ msgid_plural "%d days"
msgstr[0] ""
msgstr[1] ""
+msgid "1 deploy key"
+msgid_plural "%d deploy keys"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1099,6 +1167,9 @@ msgstr ""
msgid ":%{startLine} to %{endLine}"
msgstr ""
+msgid "A %{incident_docs_start}modified issue%{incident_docs_end} to guide the resolution of incidents."
+msgstr ""
+
msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr ""
@@ -1111,6 +1182,9 @@ msgstr ""
msgid "A GitBook site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
+msgid "A Gitpod configured Webapplication in Spring and Java"
+msgstr ""
+
msgid "A Hexo site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
@@ -1282,9 +1356,15 @@ msgstr ""
msgid "Access expiration date"
msgstr ""
+msgid "Access expires"
+msgstr ""
+
msgid "Access forbidden. Check your access level."
msgstr ""
+msgid "Access granted"
+msgstr ""
+
msgid "Access requests"
msgstr ""
@@ -1294,6 +1374,9 @@ msgstr ""
msgid "Access to Pages websites are controlled based on the user's membership to a given project. By checking this box, users will be required to be logged in to have access to all Pages websites in your instance."
msgstr ""
+msgid "AccessDropdown|Deploy Keys"
+msgstr ""
+
msgid "AccessDropdown|Groups"
msgstr ""
@@ -1411,12 +1494,6 @@ msgstr ""
msgid "Active Sessions"
msgstr ""
-msgid "Active Users:"
-msgstr ""
-
-msgid "Active users"
-msgstr ""
-
msgid "Activity"
msgstr ""
@@ -1584,9 +1661,6 @@ msgstr ""
msgid "Add label(s)"
msgstr ""
-msgid "Add license"
-msgstr ""
-
msgid "Add list"
msgstr ""
@@ -1761,21 +1835,51 @@ msgstr ""
msgid "AdminArea|Bots"
msgstr ""
+msgid "AdminArea|Components"
+msgstr ""
+
msgid "AdminArea|Developer"
msgstr ""
+msgid "AdminArea|Features"
+msgstr ""
+
+msgid "AdminArea|Groups: %{number_of_groups}"
+msgstr ""
+
msgid "AdminArea|Guest"
msgstr ""
msgid "AdminArea|Included Free in license"
msgstr ""
+msgid "AdminArea|Latest groups"
+msgstr ""
+
+msgid "AdminArea|Latest projects"
+msgstr ""
+
+msgid "AdminArea|Latest users"
+msgstr ""
+
msgid "AdminArea|Maintainer"
msgstr ""
+msgid "AdminArea|New group"
+msgstr ""
+
+msgid "AdminArea|New project"
+msgstr ""
+
+msgid "AdminArea|New user"
+msgstr ""
+
msgid "AdminArea|Owner"
msgstr ""
+msgid "AdminArea|Projects: %{number_of_projects}"
+msgstr ""
+
msgid "AdminArea|Reporter"
msgstr ""
@@ -1803,6 +1907,9 @@ msgstr ""
msgid "AdminArea|Users without a Group and Project"
msgstr ""
+msgid "AdminArea|Users: %{number_of_users}"
+msgstr ""
+
msgid "AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running."
msgstr ""
@@ -1821,9 +1928,6 @@ msgstr ""
msgid "AdminProjects|Delete Project %{projectName}?"
msgstr ""
-msgid "AdminProjects|Delete project"
-msgstr ""
-
msgid "AdminSettings|Apply integration settings to all Projects"
msgstr ""
@@ -2061,21 +2165,30 @@ msgstr ""
msgid "AdminUsers|Without projects"
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 ""
msgid "AdminUsers|You cannot remove your own admin rights."
msgstr ""
+msgid "AdminUsers|You must transfer ownership or delete the groups owned by this user before you can delete their account"
+msgstr ""
+
msgid "Administration"
msgstr ""
msgid "Advanced"
msgstr ""
+msgid "Advanced Search"
+msgstr ""
+
+msgid "Advanced Search with Elasticsearch"
+msgstr ""
+
msgid "Advanced Settings"
msgstr ""
@@ -2153,6 +2266,9 @@ msgstr ""
msgid "AlertManagement|Edit"
msgstr ""
+msgid "AlertManagement|Environment"
+msgstr ""
+
msgid "AlertManagement|Events"
msgstr ""
@@ -2165,6 +2281,9 @@ msgstr ""
msgid "AlertManagement|Issue"
msgstr ""
+msgid "AlertManagement|Key"
+msgstr ""
+
msgid "AlertManagement|Low"
msgstr ""
@@ -2258,6 +2377,9 @@ msgstr ""
msgid "AlertManagement|Unknown"
msgstr ""
+msgid "AlertManagement|Value"
+msgstr ""
+
msgid "AlertManagement|View alerts in Opsgenie"
msgstr ""
@@ -2417,6 +2539,9 @@ msgstr ""
msgid "All projects"
msgstr ""
+msgid "All projects selected"
+msgstr ""
+
msgid "All security scans are enabled because %{linkStart}Auto DevOps%{linkEnd} is enabled on this project"
msgstr ""
@@ -2504,6 +2629,9 @@ msgstr ""
msgid "Almost there"
msgstr ""
+msgid "Already blocked"
+msgstr ""
+
msgid "Also called \"Issuer\" or \"Relying party trust identifier\""
msgstr ""
@@ -2558,6 +2686,9 @@ msgstr ""
msgid "An error has occurred"
msgstr ""
+msgid "An error occured while making the changes: %{error}"
+msgstr ""
+
msgid "An error occurred adding a draft to the thread."
msgstr ""
@@ -2585,12 +2716,6 @@ msgstr ""
msgid "An error occurred when toggling the notification subscription"
msgstr ""
-msgid "An error occurred when trying to resolve a comment. Please try again."
-msgstr ""
-
-msgid "An error occurred when trying to resolve a discussion. Please try again."
-msgstr ""
-
msgid "An error occurred when updating the issue weight"
msgstr ""
@@ -2606,12 +2731,6 @@ msgstr ""
msgid "An error occurred while checking group path. Please refresh and try again."
msgstr ""
-msgid "An error occurred while committing your changes."
-msgstr ""
-
-msgid "An error occurred while creating the list. Please try again."
-msgstr ""
-
msgid "An error occurred while decoding the file."
msgstr ""
@@ -2684,25 +2803,19 @@ msgstr ""
msgid "An error occurred while fetching the Service Desk address."
msgstr ""
-msgid "An error occurred while fetching the board issues. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the board lists. Please reload the page."
msgstr ""
msgid "An error occurred while fetching the board lists. Please try again."
msgstr ""
-msgid "An error occurred while fetching the board swimlanes. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the builds."
msgstr ""
msgid "An error occurred while fetching the job log."
msgstr ""
-msgid "An error occurred while fetching the job trace."
+msgid "An error occurred while fetching the job logs."
msgstr ""
msgid "An error occurred while fetching the job."
@@ -2849,9 +2962,6 @@ msgstr ""
msgid "An error occurred while saving assignees"
msgstr ""
-msgid "An error occurred while saving the template. Please check if the template exists."
-msgstr ""
-
msgid "An error occurred while searching for milestones"
msgstr ""
@@ -2870,10 +2980,10 @@ msgstr ""
msgid "An error occurred while updating approvers"
msgstr ""
-msgid "An error occurred while updating the comment"
+msgid "An error occurred while updating labels."
msgstr ""
-msgid "An error occurred while updating the list. Please try again."
+msgid "An error occurred while updating the comment"
msgstr ""
msgid "An error occurred while validating group path"
@@ -2927,6 +3037,9 @@ msgstr ""
msgid "An unknown error occurred while loading this graph."
msgstr ""
+msgid "An unknown error occurred."
+msgstr ""
+
msgid "Analytics"
msgstr ""
@@ -2960,10 +3073,10 @@ msgstr ""
msgid "Any"
msgstr ""
-msgid "Any Author"
+msgid "Any %{header}"
msgstr ""
-msgid "Any Status"
+msgid "Any Author"
msgstr ""
msgid "Any branch"
@@ -3017,6 +3130,9 @@ msgstr ""
msgid "Application ID"
msgstr ""
+msgid "Application limits saved successfully"
+msgstr ""
+
msgid "Application settings saved successfully"
msgstr ""
@@ -3226,6 +3342,9 @@ msgstr ""
msgid "Are you sure you want to close this blocked issue?"
msgstr ""
+msgid "Are you sure you want to delete \"%{name}\" Value Stream?"
+msgstr ""
+
msgid "Are you sure you want to delete %{name}?"
msgstr ""
@@ -3235,6 +3354,9 @@ msgstr ""
msgid "Are you sure you want to delete this %{typeOfComment}?"
msgstr ""
+msgid "Are you sure you want to delete this SSH key?"
+msgstr ""
+
msgid "Are you sure you want to delete this board?"
msgstr ""
@@ -3259,6 +3381,11 @@ msgstr ""
msgid "Are you sure you want to erase this build?"
msgstr ""
+msgid "Are you sure you want to import %d repository?"
+msgid_plural "Are you sure you want to import %d repositories?"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Are you sure you want to lose unsaved changes?"
msgstr ""
@@ -3268,15 +3395,15 @@ msgstr ""
msgid "Are you sure you want to merge immediately?"
msgstr ""
-msgid "Are you sure you want to permanently delete this license?"
-msgstr ""
-
msgid "Are you sure you want to re-deploy this environment?"
msgstr ""
msgid "Are you sure you want to regenerate the public key? You will have to update the public key on the remote server before mirroring will work again."
msgstr ""
+msgid "Are you sure you want to reindex?"
+msgstr ""
+
msgid "Are you sure you want to remove %{group_name}?"
msgstr ""
@@ -3304,6 +3431,9 @@ msgstr ""
msgid "Are you sure you want to revoke this nickname?"
msgstr ""
+msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
+msgstr ""
+
msgid "Are you sure you want to stop this environment?"
msgstr ""
@@ -3325,6 +3455,9 @@ msgstr ""
msgid "Are you sure? The device will be signed out of GitLab and all remember me tokens revoked."
msgstr ""
+msgid "Are you sure? This will invalidate your registered applications and U2F / WebAuthn devices."
+msgstr ""
+
msgid "Are you sure? This will invalidate your registered applications and U2F devices."
msgstr ""
@@ -3343,9 +3476,6 @@ msgstr ""
msgid "Artifacts"
msgstr ""
-msgid "As U2F devices are only supported by a few browsers, we require that you set up a two-factor authentication app before a U2F device. That way you'll always be able to log in - even when you're using an unsupported browser."
-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 ""
@@ -3539,6 +3669,9 @@ msgstr ""
msgid "AuditLogs|Target"
msgstr ""
+msgid "AuditLogs|This month"
+msgstr ""
+
msgid "AuditLogs|User Events"
msgstr ""
@@ -3578,6 +3711,9 @@ msgstr ""
msgid "Authentication via U2F device failed."
msgstr ""
+msgid "Authentication via WebAuthn device failed."
+msgstr ""
+
msgid "Author"
msgstr ""
@@ -3845,15 +3981,6 @@ msgstr ""
msgid "BambooService|You must set up automatic revision labeling and a repository trigger in Bamboo."
msgstr ""
-msgid "BatchComments|Delete all pending comments"
-msgstr ""
-
-msgid "BatchComments|Discard review?"
-msgstr ""
-
-msgid "BatchComments|You're about to discard your review which will delete all of your pending comments. The deleted comments %{strong_start}cannot%{strong_end} be restored."
-msgstr ""
-
msgid "Be careful. Changing the project's namespace can have unintended side effects."
msgstr ""
@@ -3875,6 +4002,9 @@ msgstr ""
msgid "Bi-weekly code coverage"
msgstr ""
+msgid "Billable Users:"
+msgstr ""
+
msgid "Billing"
msgstr ""
@@ -3884,7 +4014,7 @@ msgstr ""
msgid "BillingPlans|@%{user_name} you are currently using the %{plan_name} plan."
msgstr ""
-msgid "BillingPlans|Congratulations, your new trial is activated"
+msgid "BillingPlans|Congratulations, your free trial is activated."
msgstr ""
msgid "BillingPlans|If you would like to downgrade your plan please contact %{support_link_start}Customer Support%{support_link_end}."
@@ -3947,6 +4077,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Block user"
+msgstr ""
+
msgid "Blocked"
msgstr ""
@@ -3962,31 +4095,37 @@ msgstr ""
msgid "Blog"
msgstr ""
-msgid "Board name"
-msgstr ""
-
msgid "Board scope"
msgstr ""
msgid "Board scope affects which issues are displayed for anyone who visits this board"
msgstr ""
-msgid "BoardBlankState|Add default lists"
+msgid "Boards"
msgstr ""
-msgid "BoardBlankState|Add the following default lists to your Issue Board with one click:"
+msgid "Boards and Board Lists"
msgstr ""
-msgid "BoardBlankState|Nevermind, I'll use my own"
+msgid "Boards|An error occurred while creating the issue. Please try again."
msgstr ""
-msgid "BoardBlankState|Starting out with the default set of lists will get you right on the way to making the most of your board."
+msgid "Boards|An error occurred while creating the list. Please try again."
msgstr ""
-msgid "Boards"
+msgid "Boards|An error occurred while fetching issues. Please reload the page."
msgstr ""
-msgid "Boards and Board Lists"
+msgid "Boards|An error occurred while fetching the board issues. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching the board swimlanes. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while moving the issue. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while updating the list. Please try again."
msgstr ""
msgid "Boards|Collapse"
@@ -4013,7 +4152,7 @@ msgstr ""
msgid "Branch %{branch_name} was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr ""
-msgid "Branch has changed"
+msgid "Branch changed"
msgstr ""
msgid "Branch is already taken"
@@ -4319,6 +4458,9 @@ msgstr ""
msgid "CLOSED (MOVED)"
msgstr ""
+msgid "CODEOWNERS rule violation"
+msgstr ""
+
msgid "CONTRIBUTING"
msgstr ""
@@ -4349,9 +4491,6 @@ msgstr ""
msgid "Can't create snippet: %{err}"
msgstr ""
-msgid "Can't edit as source branch was deleted"
-msgstr ""
-
msgid "Can't fetch content for the blob: %{err}"
msgstr ""
@@ -4364,9 +4503,6 @@ msgstr ""
msgid "Can't load mermaid module: %{err}"
msgstr ""
-msgid "Can't remove group members without group managed account"
-msgstr ""
-
msgid "Can't scan the code?"
msgstr ""
@@ -4409,6 +4545,9 @@ msgstr ""
msgid "Cannot create the abuse report. This user has been blocked."
msgstr ""
+msgid "Cannot enable shared runners because parent group does not allow it"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -4514,6 +4653,15 @@ msgstr ""
msgid "Change your password or recover your current one"
msgstr ""
+msgid "ChangeReviewer|Reviewer changed from %{old} to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Reviewer changed to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Unassigned"
+msgstr ""
+
msgid "ChangeTypeActionLabel|Pick into branch"
msgstr ""
@@ -4553,6 +4701,9 @@ msgstr ""
msgid "Changes the title to \"%{title_param}\"."
msgstr ""
+msgid "Changes were successfully made."
+msgstr ""
+
msgid "Changes won't take place until the index is %{link_start}recreated%{link_end}."
msgstr ""
@@ -4958,6 +5109,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove variable"
+msgstr ""
+
msgid "CiVariables|Remove variable row"
msgstr ""
@@ -5036,9 +5190,6 @@ msgstr ""
msgid "Clear due date"
msgstr ""
-msgid "Clear input"
-msgstr ""
-
msgid "Clear recent searches"
msgstr ""
@@ -5087,6 +5238,9 @@ msgstr ""
msgid "Client authentication key password"
msgstr ""
+msgid "Client request timeout"
+msgstr ""
+
msgid "Clients"
msgstr ""
@@ -5171,6 +5325,27 @@ msgstr ""
msgid "Cluster type must be specificed for Stages::ClusterEndpointInserter"
msgstr ""
+msgid "ClusterAgents|Configuration"
+msgstr ""
+
+msgid "ClusterAgents|Connect your cluster with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate Kubernetes with a GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Name"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Agent also requires %{linkStart}enabling the Agent Server%{linkEnd}"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Kubernetes Agent allows an Infrastructure as Code, GitOps approach to integrating Kubernetes clusters with GitLab. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "ClusterAgent|This feature is only available for premium plans"
msgstr ""
@@ -5240,10 +5415,10 @@ msgstr ""
msgid "ClusterIntegration|All installed applications and related resources"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster."
+msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{linkStart}More information%{linkEnd}"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{startLink}More information%{endLink}"
+msgid "ClusterIntegration|Allow GitLab to manage namespaces and service accounts for this cluster."
msgstr ""
msgid "ClusterIntegration|Alternatively, "
@@ -5264,6 +5439,9 @@ msgstr ""
msgid "ClusterIntegration|An error occurred while trying to fetch zone machine types: %{error}"
msgstr ""
+msgid "ClusterIntegration|An unknown error occurred while attempting to connect to Kubernetes."
+msgstr ""
+
msgid "ClusterIntegration|Any project namespaces"
msgstr ""
@@ -5279,6 +5457,9 @@ msgstr ""
msgid "ClusterIntegration|Authenticate with Amazon Web Services"
msgstr ""
+msgid "ClusterIntegration|Authentication Error"
+msgstr ""
+
msgid "ClusterIntegration|Base domain"
msgstr ""
@@ -5297,13 +5478,22 @@ msgstr ""
msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}security group %{externalLinkIcon} %{endLink} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
+msgid "ClusterIntegration|Check your CA certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Check your cluster status"
+msgstr ""
+
+msgid "ClusterIntegration|Check your token"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}subnets %{externalLinkIcon} %{endLink} in your VPC where your worker nodes will run."
+msgid "ClusterIntegration|Choose the %{linkStart}security group %{linkEnd} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
msgstr ""
-msgid "ClusterIntegration|Choose the worker node %{startLink}instance type %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Choose the %{linkStart}subnets %{linkEnd} in your VPC where your worker nodes will run."
+msgstr ""
+
+msgid "ClusterIntegration|Choose the worker node %{linkStart}instance type%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Choose which applications to install on your Kubernetes cluster."
@@ -5315,10 +5505,7 @@ msgstr ""
msgid "ClusterIntegration|Clear cluster cache"
msgstr ""
-msgid "ClusterIntegration|Clear the local cache of namespace and service accounts. This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
-msgstr ""
-
-msgid "ClusterIntegration|Cluster being created"
+msgid "ClusterIntegration|Clear the local cache of namespace and service accounts."
msgstr ""
msgid "ClusterIntegration|Cluster management project (alpha)"
@@ -5330,15 +5517,21 @@ msgstr ""
msgid "ClusterIntegration|Cluster_applications artifact too big. Maximum allowable size: %{human_size}"
msgstr ""
-msgid "ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters."
+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|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}"
+msgid "ClusterIntegration|Clusters connected with a certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Connect cluster with certificate"
msgstr ""
msgid "ClusterIntegration|Connect existing cluster"
msgstr ""
+msgid "ClusterIntegration|Connection Error"
+msgstr ""
+
msgid "ClusterIntegration|Copy API URL"
msgstr ""
@@ -5414,6 +5607,12 @@ msgstr ""
msgid "ClusterIntegration|Deletes all GitLab resources attached to this cluster during removal"
msgstr ""
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared."
+msgstr ""
+
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared. %{linkStart}More information%{linkEnd}"
+msgstr ""
+
msgid "ClusterIntegration|Did you know?"
msgstr ""
@@ -5483,6 +5682,9 @@ msgstr ""
msgid "ClusterIntegration|Fluentd is an open source data collector, which lets you unify the data collection and consumption for a better use and understanding of data. It requires at least one of the following logs to be successfully installed."
msgstr ""
+msgid "ClusterIntegration|GitLab Agent managed clusters"
+msgstr ""
+
msgid "ClusterIntegration|GitLab Container Network Policies"
msgstr ""
@@ -5495,6 +5697,12 @@ msgstr ""
msgid "ClusterIntegration|GitLab Runner connects to the repository and executes CI/CD jobs, pushing results back and deploying applications to production."
msgstr ""
+msgid "ClusterIntegration|GitLab failed to authenticate."
+msgstr ""
+
+msgid "ClusterIntegration|GitLab failed to connect to the cluster."
+msgstr ""
+
msgid "ClusterIntegration|GitLab-managed cluster"
msgstr ""
@@ -5516,6 +5724,9 @@ msgstr ""
msgid "ClusterIntegration|Group cluster"
msgstr ""
+msgid "ClusterIntegration|HTTP Error"
+msgstr ""
+
msgid "ClusterIntegration|Helm Tiller"
msgstr ""
@@ -5549,7 +5760,10 @@ msgstr ""
msgid "ClusterIntegration|Instance type"
msgstr ""
-msgid "ClusterIntegration|Integrate Kubernetes cluster automation"
+msgid "ClusterIntegration|Integrate Kubernetes with a cluster certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Integrate with a cluster certificate"
msgstr ""
msgid "ClusterIntegration|Issuer Email"
@@ -5585,9 +5799,6 @@ msgstr ""
msgid "ClusterIntegration|Knative extends Kubernetes to provide a set of middleware components that are essential to build modern, source-centric, and container-based applications that can run anywhere: on premises, in the cloud, or even in a third-party data center."
msgstr ""
-msgid "ClusterIntegration|Kubernetes cluster"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes cluster is being created..."
msgstr ""
@@ -5600,9 +5811,6 @@ msgstr ""
msgid "ClusterIntegration|Kubernetes clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr ""
-msgid "ClusterIntegration|Kubernetes clusters can be used to deploy applications and to provide Review Apps for this project"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes version"
msgstr ""
@@ -5615,7 +5823,7 @@ msgstr ""
msgid "ClusterIntegration|Learn more about %{help_link_start}zones%{help_link_end}."
msgstr ""
-msgid "ClusterIntegration|Learn more about %{startLink}Regions %{externalLinkIcon}%{endLink}."
+msgid "ClusterIntegration|Learn more about %{linkStart}Regions%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Learn more about Kubernetes"
@@ -5660,12 +5868,18 @@ msgstr ""
msgid "ClusterIntegration|Machine type"
msgstr ""
+msgid "ClusterIntegration|Make sure your API endpoint is correct"
+msgstr ""
+
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create Kubernetes clusters"
msgstr ""
msgid "ClusterIntegration|Manage your Kubernetes cluster by visiting %{provider_link}"
msgstr ""
+msgid "ClusterIntegration|Namespace per environment"
+msgstr ""
+
msgid "ClusterIntegration|No IAM Roles found"
msgstr ""
@@ -5711,6 +5925,9 @@ msgstr ""
msgid "ClusterIntegration|No zones matched your search"
msgstr ""
+msgid "ClusterIntegration|Node calculations use the Kubernetes Metrics API. Make sure your cluster has metrics installed"
+msgstr ""
+
msgid "ClusterIntegration|Number of nodes"
msgstr ""
@@ -5753,6 +5970,9 @@ msgstr ""
msgid "ClusterIntegration|RBAC-enabled cluster"
msgstr ""
+msgid "ClusterIntegration|Read our %{linkStart}help page%{linkEnd} on Kubernetes cluster integration."
+msgstr ""
+
msgid "ClusterIntegration|Read our %{link_start}help page%{link_end} on Kubernetes cluster integration."
msgstr ""
@@ -5855,7 +6075,7 @@ msgstr ""
msgid "ClusterIntegration|Select a VPC to choose a subnet"
msgstr ""
-msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{linkStart}Amazon Web Services %{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select a network to choose a subnetwork"
@@ -5888,7 +6108,7 @@ msgstr ""
msgid "ClusterIntegration|Select project to choose zone"
msgstr ""
-msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select zone"
@@ -5978,9 +6198,18 @@ msgstr ""
msgid "ClusterIntegration|There was a problem authenticating with your cluster. Please ensure your CA Certificate and Token are valid."
msgstr ""
+msgid "ClusterIntegration|There was an HTTP error when connecting to your cluster."
+msgstr ""
+
msgid "ClusterIntegration|This account must have permissions to create a Kubernetes cluster in the %{link_to_container_project} specified below"
msgstr ""
+msgid "ClusterIntegration|This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
+msgstr ""
+
+msgid "ClusterIntegration|This is necessary to clear existing environment-namespace associations from clusters previously managed by GitLab."
+msgstr ""
+
msgid "ClusterIntegration|This option will allow you to install applications on RBAC clusters."
msgstr ""
@@ -6005,9 +6234,21 @@ msgstr ""
msgid "ClusterIntegration|To use a new project, first create one on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}."
msgstr ""
+msgid "ClusterIntegration|Troubleshooting tips:"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Authenticate"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Connect"
+msgstr ""
+
msgid "ClusterIntegration|Uninstall %{appTitle}"
msgstr ""
+msgid "ClusterIntegration|Unknown Error"
+msgstr ""
+
msgid "ClusterIntegration|Update %{appTitle}"
msgstr ""
@@ -6068,7 +6309,7 @@ msgstr ""
msgid "ClusterIntegration|Your cluster API is unreachable. Please ensure your API URL is correct."
msgstr ""
-msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Zone"
@@ -6188,6 +6429,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse all threads"
+msgstr ""
+
msgid "Collapse approvers"
msgstr ""
@@ -6337,7 +6581,7 @@ msgstr ""
msgid "Commit…"
msgstr ""
-msgid "Company"
+msgid "Community forum"
msgstr ""
msgid "Company name"
@@ -6346,6 +6590,9 @@ msgstr ""
msgid "Compare"
msgstr ""
+msgid "Compare %{oldCommitId}...%{newCommitId}"
+msgstr ""
+
msgid "Compare Git revisions"
msgstr ""
@@ -6361,6 +6608,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare submodule commit revisions"
+msgstr ""
+
msgid "Compare with previous version"
msgstr ""
@@ -6496,6 +6746,9 @@ msgstr ""
msgid "Configure the way a user creates a new account."
msgstr ""
+msgid "Configure which lists are shown for anyone who visits this board"
+msgstr ""
+
msgid "Confirm"
msgstr ""
@@ -6721,6 +6974,9 @@ msgstr[1] ""
msgid "ContainerRegistry|Set cleanup policy"
msgstr ""
+msgid "ContainerRegistry|Some tags were not deleted"
+msgstr ""
+
msgid "ContainerRegistry|Something went wrong while fetching the cleanup policy."
msgstr ""
@@ -6760,6 +7016,9 @@ msgstr ""
msgid "ContainerRegistry|Tags with names matching this regex pattern will %{italicStart}expire:%{italicEnd}"
msgstr ""
+msgid "ContainerRegistry|The cleanup policy timed out before it could delete all tags. An administrator can %{adminLinkStart}manually run cleanup now%{adminLinkEnd} or you can wait for the cleanup policy to automatically run again. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "ContainerRegistry|The last tag related to this image was recently removed. This empty image and any associated data will be automatically removed as part of the regular Garbage Collection process. If you have any questions, contact your administrator."
msgstr ""
@@ -6892,6 +7151,9 @@ msgstr ""
msgid "Contributions per group member"
msgstr ""
+msgid "Contributor"
+msgstr ""
+
msgid "Contributors"
msgstr ""
@@ -7021,6 +7283,9 @@ msgstr ""
msgid "Could not change HEAD: branch '%{branch}' does not exist"
msgstr ""
+msgid "Could not commit. An unexpected error occurred."
+msgstr ""
+
msgid "Could not connect to FogBugz, check your URL"
msgstr ""
@@ -7060,6 +7325,9 @@ msgstr ""
msgid "Could not find iteration"
msgstr ""
+msgid "Could not load instance counts. Please refresh the page to try again."
+msgstr ""
+
msgid "Could not remove the trigger."
msgstr ""
@@ -7084,10 +7352,10 @@ msgstr ""
msgid "Could not save prometheus manual configuration"
msgstr ""
-msgid "Could not udpdate wiki page"
+msgid "Could not update the LDAP settings"
msgstr ""
-msgid "Could not update the LDAP settings"
+msgid "Could not update wiki page"
msgstr ""
msgid "Could not upload your designs as one or more files uploaded are not supported."
@@ -7745,6 +8013,9 @@ msgstr ""
msgid "DastProfiles|Are you sure you want to delete this profile?"
msgstr ""
+msgid "DastProfiles|Could not create site validation token. Please refresh the page, or try again later."
+msgstr ""
+
msgid "DastProfiles|Could not create the scanner profile. Please try again."
msgstr ""
@@ -7769,6 +8040,12 @@ msgstr ""
msgid "DastProfiles|Could not fetch site profiles. Please refresh the page, or try again later."
msgstr ""
+msgid "DastProfiles|Could not retrieve site validation status. Please refresh the page, or try again later."
+msgstr ""
+
+msgid "DastProfiles|Could not update the scanner profile. Please try again."
+msgstr ""
+
msgid "DastProfiles|Could not update the site profile. Please try again."
msgstr ""
@@ -7784,7 +8061,7 @@ msgstr ""
msgid "DastProfiles|Download validation text file"
msgstr ""
-msgid "DastProfiles|Edit feature will come soon. Please create a new profile if changes needed"
+msgid "DastProfiles|Edit scanner profile"
msgstr ""
msgid "DastProfiles|Edit site profile"
@@ -7817,6 +8094,9 @@ msgstr ""
msgid "DastProfiles|No profiles created yet"
msgstr ""
+msgid "DastProfiles|Passive"
+msgstr ""
+
msgid "DastProfiles|Please enter a valid URL format, ex: http://www.example.com/home"
msgstr ""
@@ -7832,6 +8112,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan mode"
+msgstr ""
+
msgid "DastProfiles|Scanner Profile"
msgstr ""
@@ -7871,10 +8154,10 @@ msgstr ""
msgid "DastProfiles|Text file validation"
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
+msgid "DastProfiles|The maximum number of minutes allowed for the spider to traverse the site."
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the spider to traverse the site."
+msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
msgstr ""
msgid "DastProfiles|Validate"
@@ -7907,6 +8190,9 @@ msgstr ""
msgid "Date picker"
msgstr ""
+msgid "Date range"
+msgstr ""
+
msgid "Date range cannot exceed %{maxDateRange} days."
msgstr ""
@@ -7931,6 +8217,9 @@ msgstr ""
msgid "Days to merge"
msgstr ""
+msgid "Dear Administrator,"
+msgstr ""
+
msgid "Debug"
msgstr ""
@@ -8042,12 +8331,18 @@ msgstr ""
msgid "Delete"
msgstr ""
+msgid "Delete %{name}"
+msgstr ""
+
msgid "Delete Comment"
msgstr ""
msgid "Delete Snippet"
msgstr ""
+msgid "Delete Value Stream"
+msgstr ""
+
msgid "Delete account"
msgstr ""
@@ -8069,9 +8364,6 @@ msgstr ""
msgid "Delete label: %{label_name} ?"
msgstr ""
-msgid "Delete license"
-msgstr ""
-
msgid "Delete list"
msgstr ""
@@ -8147,15 +8439,6 @@ msgstr ""
msgid "Deleting a project places it into a read-only state until %{date}, at which point the project will be permanently deleted. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "Deleting the license failed."
-msgstr ""
-
-msgid "Deleting the license failed. The license was not found."
-msgstr ""
-
-msgid "Deleting the license failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "Deleting the project will delete its repository and all related resources including issues, merge requests etc."
msgstr ""
@@ -8651,7 +8934,10 @@ msgstr ""
msgid "DesignManagement|The maximum number of designs allowed to be uploaded is %{upload_limit}. Please try again."
msgstr ""
-msgid "DesignManagement|To upload designs, you'll need to enable LFS. %{requirements_link_start}More information%{requirements_link_end}"
+msgid "DesignManagement|There was an error moving your designs. Please upload your designs below."
+msgstr ""
+
+msgid "DesignManagement|To upload designs, you'll need to enable LFS and have admin enable hashed storage. %{requirements_link_start}More information%{requirements_link_end}"
msgstr ""
msgid "DesignManagement|Unresolve thread"
@@ -8663,6 +8949,9 @@ msgstr ""
msgid "DesignManagement|Upload skipped."
msgstr ""
+msgid "DesignManagement|Your designs are being copied and are on their way… Please refresh to update."
+msgstr ""
+
msgid "DesignManagement|and %{moreCount} more."
msgstr ""
@@ -8720,6 +9009,9 @@ msgstr ""
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
+msgid "Direct member"
+msgstr ""
+
msgid "Direction"
msgstr ""
@@ -8768,9 +9060,6 @@ msgstr ""
msgid "Discard draft"
msgstr ""
-msgid "Discard review"
-msgstr ""
-
msgid "DiscordService|Discord Notifications"
msgstr ""
@@ -8839,10 +9128,10 @@ msgstr ""
msgid "Dismiss Merge Request promotion"
msgstr ""
-msgid "Dismiss Selected"
+msgid "Dismiss Value Stream Analytics introduction box"
msgstr ""
-msgid "Dismiss Value Stream Analytics introduction box"
+msgid "Dismiss selected"
msgstr ""
msgid "Dismiss trial promotion"
@@ -8893,9 +9182,6 @@ msgstr ""
msgid "Documents reindexed: %{processed_documents} (%{percentage}%%)"
msgstr ""
-msgid "Doing"
-msgstr ""
-
msgid "Domain"
msgstr ""
@@ -9091,9 +9377,6 @@ msgstr ""
msgid "Edit environment"
msgstr ""
-msgid "Edit file"
-msgstr ""
-
msgid "Edit files in the editor and commit changes here"
msgstr ""
@@ -9106,6 +9389,12 @@ msgstr ""
msgid "Edit identity for %{user_name}"
msgstr ""
+msgid "Edit in Web IDE"
+msgstr ""
+
+msgid "Edit in single-file editor"
+msgstr ""
+
msgid "Edit issues"
msgstr ""
@@ -9133,10 +9422,10 @@ msgstr ""
msgid "Editing"
msgstr ""
-msgid "Elasticsearch"
+msgid "Elasticsearch AWS IAM credentials"
msgstr ""
-msgid "Elasticsearch AWS IAM credentials"
+msgid "Elasticsearch HTTP client timeout value in seconds."
msgstr ""
msgid "Elasticsearch indexing restrictions"
@@ -9145,9 +9434,6 @@ msgstr ""
msgid "Elasticsearch indexing started"
msgstr ""
-msgid "Elasticsearch integration. Elasticsearch AWS IAM."
-msgstr ""
-
msgid "Elasticsearch reindexing is already in progress"
msgstr ""
@@ -9175,9 +9461,6 @@ msgstr ""
msgid "Email Notification"
msgstr ""
-msgid "Email address"
-msgstr ""
-
msgid "Email could not be sent"
msgstr ""
@@ -9241,6 +9524,9 @@ msgstr ""
msgid "Emails sent from Service Desk will have this name"
msgstr ""
+msgid "Emails sent to %{email} will still be supported"
+msgstr ""
+
msgid "Emails separated by comma"
msgstr ""
@@ -9274,9 +9560,18 @@ msgstr ""
msgid "Enable"
msgstr ""
+msgid "Enable %{link_start}Gitpod%{link_end} integration to launch a development environment in your browser directly from GitLab."
+msgstr ""
+
msgid "Enable Auto DevOps"
msgstr ""
+msgid "Enable Gitpod"
+msgstr ""
+
+msgid "Enable Gitpod?"
+msgstr ""
+
msgid "Enable HTML emails"
msgstr ""
@@ -9406,9 +9701,6 @@ msgstr ""
msgid "Encountered an error while rendering: %{err}"
msgstr ""
-msgid "End date"
-msgstr ""
-
msgid "Ends at (UTC)"
msgstr ""
@@ -9568,7 +9860,7 @@ msgstr ""
msgid "EnvironmentsDashboard|The environments dashboard provides a summary of each project's environments' status, including pipeline and alert statuses."
msgstr ""
-msgid "EnvironmentsDashboard|This dashboard displays a maximum of 7 projects and 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
+msgid "EnvironmentsDashboard|This dashboard displays 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
msgstr ""
msgid "Environments|An error occurred while canceling the auto stop, please try again"
@@ -9889,6 +10181,9 @@ msgstr ""
msgid "Error deleting project. Check logs for error details."
msgstr ""
+msgid "Error fetching burnup chart data"
+msgstr ""
+
msgid "Error fetching diverging counts for branches. Please try again."
msgstr ""
@@ -9967,6 +10262,9 @@ msgstr ""
msgid "Error occurred when saving assignees"
msgstr ""
+msgid "Error occurred when saving reviewers"
+msgstr ""
+
msgid "Error occurred when toggling the notification subscription"
msgstr ""
@@ -10219,10 +10517,13 @@ msgstr ""
msgid "Expand all"
msgstr ""
-msgid "Expand approvers"
+msgid "Expand all files"
msgstr ""
-msgid "Expand dropdown"
+msgid "Expand all threads"
+msgstr ""
+
+msgid "Expand approvers"
msgstr ""
msgid "Expand milestones"
@@ -10393,6 +10694,9 @@ msgstr ""
msgid "Failed to create Merge Request. Please try again."
msgstr ""
+msgid "Failed to create To-Do for the design."
+msgstr ""
+
msgid "Failed to create a branch for this issue. Please try again."
msgstr ""
@@ -10432,6 +10736,12 @@ msgstr ""
msgid "Failed to load authors. Please try again."
msgstr ""
+msgid "Failed to load branches. Please try again."
+msgstr ""
+
+msgid "Failed to load deploy keys."
+msgstr ""
+
msgid "Failed to load emoji list."
msgstr ""
@@ -10447,6 +10757,9 @@ msgstr ""
msgid "Failed to load groups & users."
msgstr ""
+msgid "Failed to load groups, users and deploy keys."
+msgstr ""
+
msgid "Failed to load labels. Please try again."
msgstr ""
@@ -10456,6 +10769,12 @@ msgstr ""
msgid "Failed to load related branches"
msgstr ""
+msgid "Failed to load sidebar confidential toggle"
+msgstr ""
+
+msgid "Failed to load sidebar lock status"
+msgstr ""
+
msgid "Failed to load stacktrace."
msgstr ""
@@ -10483,6 +10802,9 @@ msgstr ""
msgid "Failed to publish issue on status page."
msgstr ""
+msgid "Failed to remove To-Do for the design."
+msgstr ""
+
msgid "Failed to remove a Zoom meeting"
msgstr ""
@@ -10525,6 +10847,9 @@ msgstr ""
msgid "Failed to signing using smartcard authentication"
msgstr ""
+msgid "Failed to toggle To-Do for the design."
+msgstr ""
+
msgid "Failed to update branch!"
msgstr ""
@@ -10638,7 +10963,7 @@ msgstr ""
msgid "FeatureFlags|Edit User List"
msgstr ""
-msgid "FeatureFlags|Enable features for specific users and specific environments by defining feature flag strategies."
+msgid "FeatureFlags|Enable features for specific users and environments by configuring feature flag strategies."
msgstr ""
msgid "FeatureFlags|Environment Spec"
@@ -10698,7 +11023,7 @@ msgstr ""
msgid "FeatureFlags|Include additional user IDs"
msgstr ""
-msgid "FeatureFlags|Install a %{docs_link_anchored_start}compatible client library%{docs_link_anchored_end} and specify the API URL, application name, and instance ID during the configuration setup. %{docs_link_start}More Information%{docs_link_end}"
+msgid "FeatureFlags|Install a %{docsLinkAnchoredStart}compatible client library%{docsLinkAnchoredEnd} and specify the API URL, application name, and instance ID during the configuration setup. %{docsLinkStart}More Information%{docsLinkEnd}"
msgstr ""
msgid "FeatureFlags|Instance ID"
@@ -10710,6 +11035,9 @@ msgstr ""
msgid "FeatureFlags|Loading feature flags"
msgstr ""
+msgid "FeatureFlags|Loading user lists"
+msgstr ""
+
msgid "FeatureFlags|More information"
msgstr ""
@@ -10728,7 +11056,7 @@ msgstr ""
msgid "FeatureFlags|New feature flag"
msgstr ""
-msgid "FeatureFlags|New list"
+msgid "FeatureFlags|New user list"
msgstr ""
msgid "FeatureFlags|Percent of users"
@@ -10767,6 +11095,9 @@ msgstr ""
msgid "FeatureFlags|There was an error fetching the feature flags."
msgstr ""
+msgid "FeatureFlags|There was an error fetching the user lists."
+msgstr ""
+
msgid "FeatureFlags|There was an error retrieving user lists"
msgstr ""
@@ -10782,6 +11113,9 @@ msgstr ""
msgid "FeatureFlags|User List"
msgstr ""
+msgid "FeatureFlags|User Lists"
+msgstr ""
+
msgid "FeatureFlag|List"
msgstr ""
@@ -10809,15 +11143,6 @@ msgstr ""
msgid "Fetching incoming email"
msgstr ""
-msgid "Fetching licenses failed."
-msgstr ""
-
-msgid "Fetching licenses failed. The request endpoint was not found."
-msgstr ""
-
-msgid "Fetching licenses failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "File"
msgstr ""
@@ -10920,12 +11245,21 @@ msgstr ""
msgid "Filter by status"
msgstr ""
+msgid "Filter by test cases that are currently archived."
+msgstr ""
+
+msgid "Filter by test cases that are currently opened."
+msgstr ""
+
msgid "Filter by two-factor authentication"
msgstr ""
msgid "Filter by user"
msgstr ""
+msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
+msgstr ""
+
msgid "Filter pipelines"
msgstr ""
@@ -10941,7 +11275,7 @@ msgstr ""
msgid "Filter results..."
msgstr ""
-msgid "Filter your projects by name"
+msgid "Filter your repositories by name"
msgstr ""
msgid "Filter..."
@@ -10950,7 +11284,7 @@ msgstr ""
msgid "Find File"
msgstr ""
-msgid "Find bugs in your code with coverage-guided fuzzing"
+msgid "Find bugs in your code with coverage-guided fuzzing."
msgstr ""
msgid "Find by path"
@@ -10977,9 +11311,6 @@ msgstr ""
msgid "Finish editing this message first!"
msgstr ""
-msgid "Finish review"
-msgstr ""
-
msgid "Finish setting up your dedicated account for %{group_name}."
msgstr ""
@@ -11049,6 +11380,9 @@ msgstr ""
msgid "Footer message"
msgstr ""
+msgid "For a faster browsing experience, some files are collapsed by default."
+msgstr ""
+
msgid "For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
@@ -11058,6 +11392,9 @@ msgstr ""
msgid "For more info, read the documentation."
msgstr ""
+msgid "For more information on how the number of active users is calculated, see the %{self_managed_subscriptions_doc_link} documentation."
+msgstr ""
+
msgid "For more information, go to the "
msgstr ""
@@ -11196,6 +11533,9 @@ msgstr ""
msgid "Generate new token"
msgstr ""
+msgid "Generic package file size in bytes"
+msgstr ""
+
msgid "Geo"
msgstr ""
@@ -11457,6 +11797,9 @@ msgstr ""
msgid "Geo|Please refer to Geo Troubleshooting."
msgstr ""
+msgid "Geo|Primary node"
+msgstr ""
+
msgid "Geo|Project"
msgstr ""
@@ -11499,6 +11842,9 @@ msgstr ""
msgid "Geo|Review replication status, and resynchronize and reverify items with the primary node."
msgstr ""
+msgid "Geo|Secondary node"
+msgstr ""
+
msgid "Geo|Status"
msgstr ""
@@ -11538,6 +11884,9 @@ msgstr ""
msgid "Geo|URL must be a valid url (ex: https://gitlab.com)"
msgstr ""
+msgid "Geo|Undefined"
+msgstr ""
+
msgid "Geo|Unknown state"
msgstr ""
@@ -11613,10 +11962,16 @@ msgstr ""
msgid "GitHub import"
msgstr ""
+msgid "GitLab"
+msgstr ""
+
msgid "GitLab / Unsubscribe"
msgstr ""
-msgid "GitLab Enterprise Edition %{plan}"
+msgid "GitLab API"
+msgstr ""
+
+msgid "GitLab Billing Team."
msgstr ""
msgid "GitLab Group Runners can execute code for all the projects in this group."
@@ -11628,12 +11983,18 @@ msgstr ""
msgid "GitLab Issue"
msgstr ""
+msgid "GitLab Pages"
+msgstr ""
+
msgid "GitLab Service Desk is a simple way to allow people to create issues in your GitLab instance without needing their own user account. It provides a unique email address for end users to create issues in a project, and replies can be sent either through the GitLab interface or by email. End users will only see the thread through email."
msgstr ""
msgid "GitLab Shared Runners execute code of different projects on the same Runner unless you configure GitLab Runner Autoscale with MaxBuilds 1 (which it is on GitLab.com)."
msgstr ""
+msgid "GitLab Shell"
+msgstr ""
+
msgid "GitLab Support Bot"
msgstr ""
@@ -11643,7 +12004,7 @@ msgstr ""
msgid "GitLab User"
msgstr ""
-msgid "GitLab allows you to continue using your license even if you exceed the number of seats you purchased. You will be required to pay for these seats when you renew your license."
+msgid "GitLab Workhorse"
msgstr ""
msgid "GitLab commit"
@@ -11811,6 +12172,21 @@ msgstr ""
msgid "Gitlab Pages"
msgstr ""
+msgid "Gitpod"
+msgstr ""
+
+msgid "Gitpod|Add the URL to your Gitpod instance configured to read your GitLab projects."
+msgstr ""
+
+msgid "Gitpod|Enable Gitpod integration"
+msgstr ""
+
+msgid "Gitpod|Gitpod URL"
+msgstr ""
+
+msgid "Gitpod|e.g. https://gitpod.example.com"
+msgstr ""
+
msgid "Given access %{time_ago}"
msgstr ""
@@ -12318,9 +12694,6 @@ msgstr ""
msgid "GroupSAML|Valid SAML Response"
msgstr ""
-msgid "GroupSAML|With group managed accounts enabled, all the users without a group managed account will be excluded from the group."
-msgstr ""
-
msgid "GroupSAML|With prohibit outer forks flag enabled group members will be able to fork project only inside your group."
msgstr ""
@@ -12534,10 +12907,10 @@ msgstr ""
msgid "GroupsNew|Create group"
msgstr ""
-msgid "GroupsNew|GitLab group export"
+msgid "GroupsNew|Import"
msgstr ""
-msgid "GroupsNew|Import"
+msgid "GroupsNew|Import a GitLab group export file"
msgstr ""
msgid "GroupsNew|Import group"
@@ -12680,6 +13053,9 @@ msgid_plural "Hide charts"
msgstr[0] ""
msgstr[1] ""
+msgid "Hide comments on this file"
+msgstr ""
+
msgid "Hide details"
msgstr ""
@@ -12724,6 +13100,15 @@ msgstr ""
msgid "Highest role:"
msgstr ""
+msgid "HighlightBar|Alert events:"
+msgstr ""
+
+msgid "HighlightBar|Alert start time:"
+msgstr ""
+
+msgid "HighlightBar|Original alert:"
+msgstr ""
+
msgid "History"
msgstr ""
@@ -12901,6 +13286,9 @@ msgstr ""
msgid "If enabled, access to projects will be validated on an external service using their classification label."
msgstr ""
+msgid "If the number of active users exceeds the user limit, you will be charged for the number of %{users_over_license_link} at your next license reconciliation."
+msgstr ""
+
msgid "If there is no previous license or if the previous license has expired, some GitLab functionality will be blocked until a new, valid license is uploaded."
msgstr ""
@@ -12940,9 +13328,6 @@ msgstr ""
msgid "If your HTTP repository is not publicly accessible, add your credentials."
msgstr ""
-msgid "Iglu registry URL (optional)"
-msgstr ""
-
msgid "Ignore"
msgstr ""
@@ -12979,6 +13364,16 @@ msgstr ""
msgid "Import"
msgstr ""
+msgid "Import %d compatible repository"
+msgid_plural "Import %d compatible repositories"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Import %d repository"
+msgid_plural "Import %d repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Import CSV"
msgstr ""
@@ -12988,15 +13383,9 @@ msgstr ""
msgid "Import all compatible projects"
msgstr ""
-msgid "Import all compatible repositories"
-msgstr ""
-
msgid "Import all projects"
msgstr ""
-msgid "Import all repositories"
-msgstr ""
-
msgid "Import an exported GitLab project"
msgstr ""
@@ -13084,6 +13473,9 @@ msgstr ""
msgid "ImportProjects|Error importing repository %{project_safe_import_url} into %{project_full_path} - %{message}"
msgstr ""
+msgid "ImportProjects|Import repositories"
+msgstr ""
+
msgid "ImportProjects|Importing the project failed"
msgstr ""
@@ -13096,7 +13488,7 @@ msgstr ""
msgid "ImportProjects|Requesting your %{provider} repositories failed"
msgstr ""
-msgid "ImportProjects|Select the projects you want to import"
+msgid "ImportProjects|Select the repositories you want to import"
msgstr ""
msgid "ImportProjects|The remote data could not be imported."
@@ -13132,9 +13524,6 @@ msgstr ""
msgid "In order to enable Service Desk for your instance, you must first set up incoming email."
msgstr ""
-msgid "In order to gather accurate feature usage data, it can take 1 to 2 weeks to see your index."
-msgstr ""
-
msgid "In order to personalize your experience with GitLab%{br_tag}we would like to know a bit more about you."
msgstr ""
@@ -13165,18 +13554,30 @@ msgstr ""
msgid "IncidentManagement|Create incident"
msgstr ""
+msgid "IncidentManagement|Critical - S1"
+msgstr ""
+
msgid "IncidentManagement|Date created"
msgstr ""
msgid "IncidentManagement|Display your incidents in a dedicated view"
msgstr ""
+msgid "IncidentManagement|High - S2"
+msgstr ""
+
msgid "IncidentManagement|Incident"
msgstr ""
msgid "IncidentManagement|Incidents"
msgstr ""
+msgid "IncidentManagement|Low - S4"
+msgstr ""
+
+msgid "IncidentManagement|Medium - S3"
+msgstr ""
+
msgid "IncidentManagement|No incidents to display."
msgstr ""
@@ -13189,6 +13590,9 @@ msgstr ""
msgid "IncidentManagement|Published to status page"
msgstr ""
+msgid "IncidentManagement|Severity"
+msgstr ""
+
msgid "IncidentManagement|There are no closed incidents"
msgstr ""
@@ -13198,6 +13602,9 @@ msgstr ""
msgid "IncidentManagement|Unassigned"
msgstr ""
+msgid "IncidentManagement|Unknown"
+msgstr ""
+
msgid "IncidentManagement|Unpublished"
msgstr ""
@@ -13219,6 +13626,15 @@ msgstr ""
msgid "Incidents"
msgstr ""
+msgid "Incident|Alert details"
+msgstr ""
+
+msgid "Incident|Summary"
+msgstr ""
+
+msgid "Incident|There was an issue loading alert data. Please try again."
+msgstr ""
+
msgid "Include a Terms of Service agreement and Privacy Policy that all users must accept."
msgstr ""
@@ -13279,6 +13695,9 @@ msgstr ""
msgid "Information about additional Pages templates and how to install them can be found in our %{pages_getting_started_guide}."
msgstr ""
+msgid "Inherited"
+msgstr ""
+
msgid "Inherited:"
msgstr ""
@@ -13359,7 +13778,22 @@ msgstr ""
msgid "Instance administrators group already exists"
msgstr ""
-msgid "Instance license"
+msgid "InstanceStatistics|Groups"
+msgstr ""
+
+msgid "InstanceStatistics|Issues"
+msgstr ""
+
+msgid "InstanceStatistics|Merge Requests"
+msgstr ""
+
+msgid "InstanceStatistics|Pipelines"
+msgstr ""
+
+msgid "InstanceStatistics|Projects"
+msgstr ""
+
+msgid "InstanceStatistics|Users"
msgstr ""
msgid "Integration"
@@ -13371,6 +13805,12 @@ msgstr ""
msgid "Integrations"
msgstr ""
+msgid "Integrations|%{integration} settings saved and active."
+msgstr ""
+
+msgid "Integrations|%{integration} settings saved, but not active."
+msgstr ""
+
msgid "Integrations|All details"
msgstr ""
@@ -13380,6 +13820,12 @@ msgstr ""
msgid "Integrations|Comment settings:"
msgstr ""
+msgid "Integrations|Connection failed. Please check your settings."
+msgstr ""
+
+msgid "Integrations|Connection successful."
+msgstr ""
+
msgid "Integrations|Default settings are inherited from the group level."
msgstr ""
@@ -13395,6 +13841,15 @@ msgstr ""
msgid "Integrations|Includes commit title and branch"
msgstr ""
+msgid "Integrations|Projects using custom settings will not be impacted unless the project owner chooses to use instance-level defaults."
+msgstr ""
+
+msgid "Integrations|Save settings?"
+msgstr ""
+
+msgid "Integrations|Saving will update the default settings for all projects that are not using custom settings."
+msgstr ""
+
msgid "Integrations|Standard"
msgstr ""
@@ -13527,6 +13982,9 @@ msgstr ""
msgid "Invitation"
msgstr ""
+msgid "Invitation declined"
+msgstr ""
+
msgid "Invite"
msgstr ""
@@ -13578,6 +14036,42 @@ 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|%{linkStart}Read more%{linkEnd} about role permissions"
+msgstr ""
+
+msgid "InviteMembersModal|Access expiration date (optional)"
+msgstr ""
+
+msgid "InviteMembersModal|Cancel"
+msgstr ""
+
+msgid "InviteMembersModal|Choose a role permission"
+msgstr ""
+
+msgid "InviteMembersModal|GitLab member or Email address"
+msgstr ""
+
+msgid "InviteMembersModal|Invite"
+msgstr ""
+
+msgid "InviteMembersModal|Invite team members"
+msgstr ""
+
+msgid "InviteMembersModal|Search for members to invite"
+msgstr ""
+
+msgid "InviteMembersModal|User not invited. Feature coming soon!"
+msgstr ""
+
+msgid "InviteMembersModal|Users were succesfully added"
+msgstr ""
+
+msgid "InviteMembersModal|You're inviting members to the %{group_name} group"
+msgstr ""
+
+msgid "InviteMembers|Invite team members"
+msgstr ""
+
msgid "Invited"
msgstr ""
@@ -13632,10 +14126,13 @@ msgstr ""
msgid "Issue cannot be found."
msgstr ""
+msgid "Issue created from vulnerability %{vulnerability_link}"
+msgstr ""
+
msgid "Issue events"
msgstr ""
-msgid "Issue first depoloyed to production"
+msgid "Issue first deployed to production"
msgstr ""
msgid "Issue label"
@@ -13713,6 +14210,9 @@ msgstr ""
msgid "IssueTracker|Custom issue tracker"
msgstr ""
+msgid "IssueTracker|EWM work items tracker"
+msgstr ""
+
msgid "IssueTracker|Redmine issue tracker"
msgstr ""
@@ -13779,6 +14279,9 @@ msgstr ""
msgid "It looks like you have some draft commits in this branch."
msgstr ""
+msgid "It may be several days before you see feature usage data."
+msgstr ""
+
msgid "It must have a header row and at least two columns: the first column is the issue title and the second column is the issue description. The separator is automatically detected."
msgstr ""
@@ -14061,13 +14564,13 @@ msgstr ""
msgid "Join Zoom meeting"
msgstr ""
-msgid "Jul"
+msgid "Joined %{time_ago}"
msgstr ""
-msgid "July"
+msgid "Jul"
msgstr ""
-msgid "Jump to first unresolved thread"
+msgid "July"
msgstr ""
msgid "Jump to next unresolved thread"
@@ -14103,6 +14606,9 @@ msgstr ""
msgid "Keyboard shortcuts"
msgstr ""
+msgid "KeyboardKey|Ctrl+"
+msgstr ""
+
msgid "Keys"
msgstr ""
@@ -14151,6 +14657,9 @@ msgstr ""
msgid "LDAP Synchronization"
msgstr ""
+msgid "LDAP group settings"
+msgstr ""
+
msgid "LDAP settings"
msgstr ""
@@ -14160,6 +14669,9 @@ msgstr ""
msgid "LDAP sync in progress. This could take a few minutes. Refresh the page to see the changes."
msgstr ""
+msgid "LDAP synchronizations"
+msgstr ""
+
msgid "LFS"
msgstr ""
@@ -14240,7 +14752,16 @@ msgid_plural "Last %d days"
msgstr[0] ""
msgstr[1] ""
-msgid "Last %{days} days"
+msgid "Last 2 weeks"
+msgstr ""
+
+msgid "Last 30 days"
+msgstr ""
+
+msgid "Last 60 days"
+msgstr ""
+
+msgid "Last 90 days"
msgstr ""
msgid "Last Accessed On"
@@ -14318,6 +14839,9 @@ msgstr ""
msgid "Last used on:"
msgstr ""
+msgid "Last week"
+msgstr ""
+
msgid "LastCommit|authored"
msgstr ""
@@ -14333,6 +14857,9 @@ msgstr ""
msgid "Latest pipeline for the most recent commit on this branch"
msgstr ""
+msgid "Launch a ready-to-code development environment for your project."
+msgstr ""
+
msgid "Lead"
msgstr ""
@@ -14713,6 +15240,9 @@ msgstr ""
msgid "List of all merge commits"
msgstr ""
+msgid "List options"
+msgstr ""
+
msgid "List settings"
msgstr ""
@@ -14725,9 +15255,6 @@ msgstr ""
msgid "List your Bitbucket Server repositories"
msgstr ""
-msgid "Lists"
-msgstr ""
-
msgid "Live preview"
msgstr ""
@@ -14974,6 +15501,12 @@ msgstr ""
msgid "Mark as done"
msgstr ""
+msgid "Mark as draft"
+msgstr ""
+
+msgid "Mark as ready"
+msgstr ""
+
msgid "Mark as resolved"
msgstr ""
@@ -14995,6 +15528,24 @@ msgstr ""
msgid "Markdown is supported"
msgstr ""
+msgid "MarkdownEditor|Add a link (%{modifierKey}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add a link (%{modifier_key}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifierKey}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifier_key}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifierKey}I)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifier_key}I)"
+msgstr ""
+
msgid "Marked For Deletion At - %{deletion_time}"
msgstr ""
@@ -15079,7 +15630,25 @@ msgstr ""
msgid "Max access level"
msgstr ""
-msgid "Max seats used"
+msgid "Max role"
+msgstr ""
+
+msgid "Max size 15 MB"
+msgstr ""
+
+msgid "Maximum Conan package file size in bytes"
+msgstr ""
+
+msgid "Maximum Maven package file size in bytes"
+msgstr ""
+
+msgid "Maximum NPM package file size in bytes"
+msgstr ""
+
+msgid "Maximum NuGet package file size in bytes"
+msgstr ""
+
+msgid "Maximum PyPI package file size in bytes"
msgstr ""
msgid "Maximum Users:"
@@ -15211,6 +15780,18 @@ msgstr ""
msgid "Members with access to %{strong_start}%{group_name}%{strong_end}"
msgstr ""
+msgid "Members|%{time} by %{user}"
+msgstr ""
+
+msgid "Members|Expired"
+msgstr ""
+
+msgid "Members|No expiration set"
+msgstr ""
+
+msgid "Members|in %{time}"
+msgstr ""
+
msgid "Memory Usage"
msgstr ""
@@ -15397,9 +15978,6 @@ msgstr ""
msgid "MergeRequests|Thread will be unresolved"
msgstr ""
-msgid "MergeRequests|Toggle comments for this file"
-msgstr ""
-
msgid "MergeRequests|View file @ %{commitId}"
msgstr ""
@@ -15460,6 +16038,9 @@ msgstr ""
msgid "Merging immediately isn't recommended as it may negatively impact the existing merge train. Read the %{docsLinkStart}documentation%{docsLinkEnd} for more information."
msgstr ""
+msgid "Message"
+msgstr ""
+
msgid "Messages"
msgstr ""
@@ -15845,18 +16426,12 @@ msgid_plural "Milestones"
msgstr[0] ""
msgstr[1] ""
-msgid "Milestone does not support burnup charts"
-msgstr ""
-
msgid "Milestone lists not available with your current license"
msgstr ""
msgid "Milestone lists show all issues from the selected milestone."
msgstr ""
-msgid "Milestone must have a start and due date"
-msgstr ""
-
msgid "MilestoneSidebar|Closed:"
msgstr ""
@@ -16223,6 +16798,9 @@ msgstr ""
msgid "Namespace"
msgstr ""
+msgid "Namespace ID:"
+msgstr ""
+
msgid "Namespace is empty"
msgstr ""
@@ -16307,6 +16885,9 @@ msgstr ""
msgid "NetworkPolicies|Allow all outbound traffic from %{selector} to %{ruleSelector} on %{ports}"
msgstr ""
+msgid "NetworkPolicies|Are you sure you want to delete this policy? This action cannot be undone."
+msgstr ""
+
msgid "NetworkPolicies|Choose whether to enforce this policy."
msgstr ""
@@ -16316,12 +16897,21 @@ msgstr ""
msgid "NetworkPolicies|Define this policy's location, conditions and actions."
msgstr ""
+msgid "NetworkPolicies|Delete policy"
+msgstr ""
+
+msgid "NetworkPolicies|Delete policy: %{policy}"
+msgstr ""
+
msgid "NetworkPolicies|Deny all traffic"
msgstr ""
msgid "NetworkPolicies|Description"
msgstr ""
+msgid "NetworkPolicies|Edit policy"
+msgstr ""
+
msgid "NetworkPolicies|Editor mode"
msgstr ""
@@ -16349,6 +16939,9 @@ msgstr ""
msgid "NetworkPolicies|Name"
msgstr ""
+msgid "NetworkPolicies|Namespace"
+msgstr ""
+
msgid "NetworkPolicies|Network Policy"
msgstr ""
@@ -16400,6 +16993,9 @@ msgstr ""
msgid "NetworkPolicies|Rules"
msgstr ""
+msgid "NetworkPolicies|Save changes"
+msgstr ""
+
msgid "NetworkPolicies|Something went wrong, failed to update policy"
msgstr ""
@@ -16412,6 +17008,9 @@ msgstr ""
msgid "NetworkPolicies|Traffic that does not match any rule will be blocked."
msgstr ""
+msgid "NetworkPolicies|Unable to parse policy"
+msgstr ""
+
msgid "NetworkPolicies|YAML editor"
msgstr ""
@@ -16525,6 +17124,9 @@ msgstr ""
msgid "New Snippet"
msgstr ""
+msgid "New Test Case"
+msgstr ""
+
msgid "New User"
msgstr ""
@@ -16624,6 +17226,9 @@ msgstr ""
msgid "New tag"
msgstr ""
+msgid "New test case"
+msgstr ""
+
msgid "New users set to external"
msgstr ""
@@ -16696,7 +17301,7 @@ msgstr ""
msgid "No changes"
msgstr ""
-msgid "No changes between %{ref_start}%{source_branch}%{ref_end} and %{ref_start}%{target_branch}%{ref_end}"
+msgid "No changes between %{sourceBranch} and %{targetBranch}"
msgstr ""
msgid "No child epics match applied filters"
@@ -16711,6 +17316,9 @@ msgstr ""
msgid "No containers available"
msgstr ""
+msgid "No content to show"
+msgstr ""
+
msgid "No contributions"
msgstr ""
@@ -16786,9 +17394,6 @@ msgstr ""
msgid "No license. All rights reserved"
msgstr ""
-msgid "No licenses found."
-msgstr ""
-
msgid "No matches found"
msgstr ""
@@ -16801,6 +17406,9 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No members found"
+msgstr ""
+
msgid "No merge requests found"
msgstr ""
@@ -16822,6 +17430,9 @@ msgstr ""
msgid "No parent group"
msgstr ""
+msgid "No plan"
+msgstr ""
+
msgid "No pods available"
msgstr ""
@@ -16918,6 +17529,12 @@ msgstr ""
msgid "Not Implemented"
msgstr ""
+msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+msgstr ""
+
+msgid "Not all browsers support WebAuthn. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even from an unsupported browser."
+msgstr ""
+
msgid "Not all data has been processed yet, the accuracy of the chart for the selected timeframe is limited."
msgstr ""
@@ -17014,6 +17631,9 @@ msgstr ""
msgid "Notification settings saved"
msgstr ""
+msgid "NotificationEvent|Change reviewer merge request"
+msgstr ""
+
msgid "NotificationEvent|Close issue"
msgstr ""
@@ -17176,10 +17796,7 @@ msgstr ""
msgid "On track"
msgstr ""
-msgid "OnDemandScans|Attached branch"
-msgstr ""
-
-msgid "OnDemandScans|Attached branch is where the scan job runs."
+msgid "OnDemandScans|Could not fetch scanner profiles. Please refresh the page, or try again later."
msgstr ""
msgid "OnDemandScans|Could not fetch site profiles. Please refresh the page, or try again later."
@@ -17188,6 +17805,9 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
+msgid "OnDemandScans|Create a new scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Create a new site profile"
msgstr ""
@@ -17200,6 +17820,9 @@ msgstr ""
msgid "OnDemandScans|New on-demand DAST scan"
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 ""
@@ -17209,16 +17832,10 @@ msgstr ""
msgid "OnDemandScans|On-demand scans run outside the DevOps cycle and find vulnerabilities in your projects. %{learnMoreLinkStart}Learn more%{learnMoreLinkEnd}"
msgstr ""
-msgid "OnDemandScans|Only a passive scan can be performed on demand."
-msgstr ""
-
-msgid "OnDemandScans|Passive"
-msgstr ""
-
msgid "OnDemandScans|Run scan"
msgstr ""
-msgid "OnDemandScans|Scan mode"
+msgid "OnDemandScans|Scanner profile"
msgstr ""
msgid "OnDemandScans|Scanner settings"
@@ -17230,9 +17847,15 @@ msgstr ""
msgid "OnDemandScans|Select one of the existing profiles"
msgstr ""
+msgid "OnDemandScans|Site profile"
+msgstr ""
+
msgid "OnDemandScans|Site profiles"
msgstr ""
+msgid "OnDemandScans|Use existing scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Use existing site profile"
msgstr ""
@@ -17331,9 +17954,6 @@ msgstr ""
msgid "Open Selection"
msgstr ""
-msgid "Open Web IDE"
-msgstr ""
-
msgid "Open comment type dropdown"
msgstr ""
@@ -17439,6 +18059,9 @@ msgstr ""
msgid "Origin"
msgstr ""
+msgid "Orphaned member"
+msgstr ""
+
msgid "Other Labels"
msgstr ""
@@ -17454,6 +18077,9 @@ msgstr ""
msgid "Other visibility settings have been disabled by the administrator."
msgstr ""
+msgid "Our documentation includes an example DevOps Score report."
+msgstr ""
+
msgid "Out-of-compliance with this project's policies and should be removed"
msgstr ""
@@ -17478,6 +18104,9 @@ msgstr ""
msgid "Overwrite diverged branches"
msgstr ""
+msgid "Owned by %{image_tag}"
+msgstr ""
+
msgid "Owned by anyone"
msgstr ""
@@ -17499,6 +18128,9 @@ msgstr ""
msgid "Package deleted successfully"
msgstr ""
+msgid "Package file size limits"
+msgstr ""
+
msgid "Package recipe already exists"
msgstr ""
@@ -17514,9 +18146,6 @@ msgstr ""
msgid "Package type must be PyPi"
msgstr ""
-msgid "Package was removed"
-msgstr ""
-
msgid "PackageRegistry|%{name} version %{version} was created %{datetime}"
msgstr ""
@@ -17658,12 +18287,18 @@ msgstr ""
msgid "PackageRegistry|NuGet Command"
msgstr ""
+msgid "PackageRegistry|Package Registry"
+msgstr ""
+
msgid "PackageRegistry|Pip Command"
msgstr ""
msgid "PackageRegistry|Pipeline %{link} triggered %{datetime} by %{author}"
msgstr ""
+msgid "PackageRegistry|Publish and share packages for a variety of common package managers. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "PackageRegistry|Published to the %{project} Package Registry %{datetime}"
msgstr ""
@@ -17763,6 +18398,9 @@ msgstr ""
msgid "Page not found"
msgstr ""
+msgid "Page settings"
+msgstr ""
+
msgid "Page was successfully deleted"
msgstr ""
@@ -17904,7 +18542,7 @@ msgstr ""
msgid "Paste issue link"
msgstr ""
-msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Don't use your private SSH key."
+msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Do not paste your private SSH key, as that can compromise your identity."
msgstr ""
msgid "Patch to apply"
@@ -17931,6 +18569,9 @@ msgstr ""
msgid "Pending"
msgstr ""
+msgid "Pending comments"
+msgstr ""
+
msgid "People without permission will never get a notification and won't be able to comment."
msgstr ""
@@ -18129,6 +18770,9 @@ msgstr ""
msgid "Pipelines|Build with confidence"
msgstr ""
+msgid "Pipelines|By revoking a trigger you will break any processes making use of it. Are you sure?"
+msgstr ""
+
msgid "Pipelines|CI Lint"
msgstr ""
@@ -18141,6 +18785,15 @@ msgstr ""
msgid "Pipelines|Continuous Integration can help catch bugs by running your tests automatically, while Continuous Deployment can help you deliver code to your product environment."
msgstr ""
+msgid "Pipelines|Copy trigger token"
+msgstr ""
+
+msgid "Pipelines|Description"
+msgstr ""
+
+msgid "Pipelines|Edit"
+msgstr ""
+
msgid "Pipelines|Get started with Pipelines"
msgstr ""
@@ -18156,15 +18809,27 @@ msgstr ""
msgid "Pipelines|It is recommended the code is reviewed thoroughly before running this pipeline with the parent project's CI resource."
msgstr ""
+msgid "Pipelines|Last Used"
+msgstr ""
+
msgid "Pipelines|Loading Pipelines"
msgstr ""
msgid "Pipelines|More Information"
msgstr ""
+msgid "Pipelines|No triggers have been created yet. Add one using the form above."
+msgstr ""
+
+msgid "Pipelines|Owner"
+msgstr ""
+
msgid "Pipelines|Project cache successfully reset."
msgstr ""
+msgid "Pipelines|Revoke"
+msgstr ""
+
msgid "Pipelines|Run Pipeline"
msgstr ""
@@ -18189,6 +18854,15 @@ msgstr ""
msgid "Pipelines|This project is not currently set up to run pipelines."
msgstr ""
+msgid "Pipelines|Token"
+msgstr ""
+
+msgid "Pipelines|Trigger user has insufficient permissions to project"
+msgstr ""
+
+msgid "Pipelines|invalid"
+msgstr ""
+
msgid "Pipelines|parent"
msgstr ""
@@ -18447,10 +19121,10 @@ msgstr ""
msgid "Please provide attributes to update"
msgstr ""
-msgid "Please refer to %{docs_url}"
+msgid "Please reach out if you have any questions and we'll be happy to assist."
msgstr ""
-msgid "Please retype the email address."
+msgid "Please refer to %{docs_url}"
msgstr ""
msgid "Please select"
@@ -18480,6 +19154,9 @@ msgstr ""
msgid "Please set a new password before proceeding."
msgstr ""
+msgid "Please share your feedback about %{featureName} %{linkStart}in this issue%{linkEnd} to help us improve the experience."
+msgstr ""
+
msgid "Please solve the reCAPTCHA"
msgstr ""
@@ -18783,6 +19460,9 @@ msgstr ""
msgid "Profiles| You are going to change the username %{currentUsernameBold} to %{newUsernameBold}. Profile and projects will be redirected to the %{newUsername} namespace but this redirect will expire once the %{currentUsername} namespace is registered by another user or group. Please update your Git repository remotes as soon as possible."
msgstr ""
+msgid "Profiles|%{provider} Active"
+msgstr ""
+
msgid "Profiles|@username"
msgstr ""
@@ -18834,7 +19514,7 @@ msgstr ""
msgid "Profiles|Commit email"
msgstr ""
-msgid "Profiles|Connect"
+msgid "Profiles|Connect %{provider}"
msgstr ""
msgid "Profiles|Connected Accounts"
@@ -18858,6 +19538,9 @@ msgstr ""
msgid "Profiles|Disconnect"
msgstr ""
+msgid "Profiles|Disconnect %{provider}"
+msgstr ""
+
msgid "Profiles|Do not show on profile"
msgstr ""
@@ -18882,7 +19565,7 @@ msgstr ""
msgid "Profiles|Full name"
msgstr ""
-msgid "Profiles|Give your individual key a title. This will be publically visible."
+msgid "Profiles|Give your individual key a title."
msgstr ""
msgid "Profiles|Include private contributions on my profile"
@@ -18972,7 +19655,7 @@ msgstr ""
msgid "Profiles|The maximum file size allowed is 200KB."
msgstr ""
-msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it?"
+msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it? It will be publicly visible."
msgstr ""
msgid "Profiles|This email will be displayed on your public profile"
@@ -19047,6 +19730,9 @@ msgstr ""
msgid "Profiles|You don't have access to delete this user."
msgstr ""
+msgid "Profiles|You must transfer ownership or delete groups you are an owner of before you can delete your account"
+msgstr ""
+
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
@@ -19635,6 +20321,9 @@ msgstr ""
msgid "ProjectTemplates|GitLab Cluster Management"
msgstr ""
+msgid "ProjectTemplates|Gitpod/Spring Petclinic"
+msgstr ""
+
msgid "ProjectTemplates|Go Micro"
msgstr ""
@@ -20244,6 +20933,9 @@ msgstr ""
msgid "Publish to status page"
msgstr ""
+msgid "Published"
+msgstr ""
+
msgid "Published on status page"
msgstr ""
@@ -20361,9 +21053,15 @@ msgstr ""
msgid "Quick range"
msgstr ""
+msgid "Quickly and easily edit multiple files in your project."
+msgstr ""
+
msgid "README"
msgstr ""
+msgid "Rails"
+msgstr ""
+
msgid "Rake Tasks Help"
msgstr ""
@@ -20483,10 +21181,13 @@ msgstr ""
msgid "Register Two-Factor Authenticator"
msgstr ""
-msgid "Register U2F device"
+msgid "Register Universal Two-Factor (U2F) Device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register WebAuthn Device"
+msgstr ""
+
+msgid "Register device"
msgstr ""
msgid "Register for GitLab"
@@ -20498,9 +21199,6 @@ msgstr ""
msgid "Register with two-factor app"
msgstr ""
-msgid "Registration"
-msgstr ""
-
msgid "Registration|Checkout"
msgstr ""
@@ -20617,9 +21315,6 @@ msgstr ""
msgid "Release|Something went wrong while saving the release details"
msgstr ""
-msgid "Remediated: needs review"
-msgstr ""
-
msgid "Remediations"
msgstr ""
@@ -20725,6 +21420,9 @@ msgstr ""
msgid "Remove priority"
msgstr ""
+msgid "Remove report"
+msgstr ""
+
msgid "Remove secondary node"
msgstr ""
@@ -20737,6 +21435,12 @@ msgstr ""
msgid "Remove time estimate"
msgstr ""
+msgid "Remove user & report"
+msgstr ""
+
+msgid "Remove user from group"
+msgstr ""
+
msgid "Removed"
msgstr ""
@@ -20818,9 +21522,6 @@ msgstr ""
msgid "Removes time estimate."
msgstr ""
-msgid "Removing license…"
-msgstr ""
-
msgid "Removing this group also removes all child projects, including archived projects, and their resources."
msgstr ""
@@ -20905,6 +21606,9 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
+msgid "Reported by %{reporter}"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -20991,6 +21695,27 @@ msgstr ""
msgid "Repositories"
msgstr ""
+msgid "Repositories Analytics"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download Historic Test Coverage Data"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download historic test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Historic Test Coverage Data is available in raw format (.csv) for further analysis."
+msgstr ""
+
+msgid "RepositoriesAnalytics|Test Code Coverage"
+msgstr ""
+
+msgid "RepositoriesAnalytics|There was an error fetching the projects."
+msgstr ""
+
msgid "Repository"
msgstr ""
@@ -21069,9 +21794,15 @@ msgstr ""
msgid "Request parameter %{param} is missing."
msgstr ""
+msgid "Request review from"
+msgstr ""
+
msgid "Request to link SAML account must be authorized"
msgstr ""
+msgid "Requested"
+msgstr ""
+
msgid "Requested %{time_ago}"
msgstr ""
@@ -21090,6 +21821,9 @@ msgstr ""
msgid "Requests to these domain(s)/address(es) on the local network will be allowed when local requests from hooks and services are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 or 127.0.0.0/28 are supported. Domain wildcards are not supported currently. Use comma, semicolon, or newline to separate multiple entries. The allowlist can hold a maximum of 1000 entries. Domains should use IDNA encoding. Ex: example.com, 192.168.1.1, 127.0.0.0/28, xn--itlab-j1a.com."
msgstr ""
+msgid "Require admin approval for new sign-ups"
+msgstr ""
+
msgid "Require all users in this group to setup Two-factor authentication"
msgstr ""
@@ -21217,9 +21951,6 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
-msgid "Resolved by %{resolvedByName}"
-msgstr ""
-
msgid "Resolves IP addresses once and uses them to submit requests"
msgstr ""
@@ -21339,6 +22070,14 @@ msgstr ""
msgid "ReviewApp|Enable Review App"
msgstr ""
+msgid "Reviewer"
+msgid_plural "%d Reviewers"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Reviewer(s)"
+msgstr ""
+
msgid "Reviewing"
msgstr ""
@@ -21378,6 +22117,9 @@ msgstr ""
msgid "Rook"
msgstr ""
+msgid "Ruby"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -21456,6 +22198,63 @@ msgstr ""
msgid "Runners page."
msgstr ""
+msgid "Runners|Active"
+msgstr ""
+
+msgid "Runners|Architecture"
+msgstr ""
+
+msgid "Runners|Can run untagged jobs"
+msgstr ""
+
+msgid "Runners|Description"
+msgstr ""
+
+msgid "Runners|Group"
+msgstr ""
+
+msgid "Runners|IP Address"
+msgstr ""
+
+msgid "Runners|Last contact"
+msgstr ""
+
+msgid "Runners|Locked to this project"
+msgstr ""
+
+msgid "Runners|Maximum job timeout"
+msgstr ""
+
+msgid "Runners|Name"
+msgstr ""
+
+msgid "Runners|Platform"
+msgstr ""
+
+msgid "Runners|Property Name"
+msgstr ""
+
+msgid "Runners|Protected"
+msgstr ""
+
+msgid "Runners|Revision"
+msgstr ""
+
+msgid "Runners|Shared"
+msgstr ""
+
+msgid "Runners|Specific"
+msgstr ""
+
+msgid "Runners|Tags"
+msgstr ""
+
+msgid "Runners|Value"
+msgstr ""
+
+msgid "Runners|Version"
+msgstr ""
+
msgid "Runners|You have used %{quotaUsed} out of %{quotaLimit} of your shared Runners pipeline minutes."
msgstr ""
@@ -21468,6 +22267,9 @@ msgstr ""
msgid "Runs a number of housekeeping tasks within the current repository, such as compressing file revisions and removing unreachable objects."
msgstr ""
+msgid "SAML"
+msgstr ""
+
msgid "SAML SSO"
msgstr ""
@@ -21519,6 +22321,9 @@ msgstr ""
msgid "Save"
msgstr ""
+msgid "Save %{name} size limits"
+msgstr ""
+
msgid "Save Changes"
msgstr ""
@@ -21549,9 +22354,6 @@ msgstr ""
msgid "Save space and find tags in the Container Registry more easily. Enable the cleanup policy to remove stale tags and keep only the ones you need."
msgstr ""
-msgid "Save template"
-msgstr ""
-
msgid "Save variables"
msgstr ""
@@ -21594,9 +22396,6 @@ msgstr ""
msgid "Scope"
msgstr ""
-msgid "Scope not supported with disabled 'users_search' feature!"
-msgstr ""
-
msgid "Scoped issue boards"
msgstr ""
@@ -21723,9 +22522,6 @@ msgstr ""
msgid "Search requirements"
msgstr ""
-msgid "Search results…"
-msgstr ""
-
msgid "Search users"
msgstr ""
@@ -21798,6 +22594,11 @@ msgid_plural "SearchResults|commits"
msgstr[0] ""
msgstr[1] ""
+msgid "SearchResults|epic"
+msgid_plural "SearchResults|epics"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "SearchResults|issue"
msgid_plural "SearchResults|issues"
msgstr[0] ""
@@ -21842,10 +22643,10 @@ msgstr ""
msgid "Seat Link is disabled, and cannot be configured through this form."
msgstr ""
-msgid "Seats currently in use"
+msgid "Seats usage data as of %{last_enqueue_time}"
msgstr ""
-msgid "Seats in license"
+msgid "Seats usage data is updated every day at 12:00pm UTC"
msgstr ""
msgid "Secondary"
@@ -21899,6 +22700,9 @@ msgstr ""
msgid "SecurityConfiguration|Available for on-demand DAST"
msgstr ""
+msgid "SecurityConfiguration|By default, all analyzers are applied in order to cover all languages across your project, and only run if the language is detected in the Merge Request."
+msgstr ""
+
msgid "SecurityConfiguration|Configure"
msgstr ""
@@ -21929,16 +22733,19 @@ msgstr ""
msgid "SecurityConfiguration|Manage"
msgstr ""
+msgid "SecurityConfiguration|More information"
+msgstr ""
+
msgid "SecurityConfiguration|Not enabled"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|Security Control"
+msgid "SecurityConfiguration|SAST Configuration"
msgstr ""
-msgid "SecurityConfiguration|See documentation"
+msgid "SecurityConfiguration|Security Control"
msgstr ""
msgid "SecurityConfiguration|Status"
@@ -21950,6 +22757,9 @@ msgstr ""
msgid "SecurityConfiguration|Using custom settings. You won't receive automatic updates on this variable. %{anchorStart}Restore to default%{anchorEnd}"
msgstr ""
+msgid "SecurityConfiguration|View history"
+msgstr ""
+
msgid "SecurityConfiguration|You can quickly enable all security scanning tools by enabling %{linkStart}Auto DevOps%{linkEnd}."
msgstr ""
@@ -22028,9 +22838,6 @@ msgstr ""
msgid "SecurityReports|Learn more about setting up your dashboard"
msgstr ""
-msgid "SecurityReports|Load more vulnerabilities"
-msgstr ""
-
msgid "SecurityReports|Monitor vulnerabilities in your code"
msgstr ""
@@ -22310,7 +23117,7 @@ msgstr ""
msgid "Select status"
msgstr ""
-msgid "Select strategy activation method"
+msgid "Select strategy activation method."
msgstr ""
msgid "Select subscription"
@@ -22325,7 +23132,7 @@ msgstr ""
msgid "Select the custom project template source group."
msgstr ""
-msgid "Select timeframe"
+msgid "Select the environment scope for this feature flag."
msgstr ""
msgid "Select timezone"
@@ -22574,6 +23381,9 @@ msgstr ""
msgid "Set iteration"
msgstr ""
+msgid "Set limit to 0 to allow any file size."
+msgstr ""
+
msgid "Set max session time for web terminal."
msgstr ""
@@ -22652,10 +23462,13 @@ msgstr ""
msgid "Set up a %{type} Runner manually"
msgstr ""
+msgid "Set up a hardware device as a second factor to sign in."
+msgstr ""
+
msgid "Set up assertions/attributes/claims (email, first_name, last_name) and NameID according to %{docsLinkStart}the documentation %{icon}%{docsLinkEnd}"
msgstr ""
-msgid "Set up new U2F device"
+msgid "Set up new device"
msgstr ""
msgid "Set up new password"
@@ -22724,6 +23537,9 @@ msgstr ""
msgid "Sets weight to %{weight}."
msgstr ""
+msgid "Setting this to 0 means using the system default timeout value."
+msgstr ""
+
msgid "Settings"
msgstr ""
@@ -22739,6 +23555,15 @@ msgstr ""
msgid "Severity"
msgstr ""
+msgid "SeverityWidget|Severity"
+msgstr ""
+
+msgid "SeverityWidget|Severity: %{severity}"
+msgstr ""
+
+msgid "SeverityWidget|There was an error while updating severity."
+msgstr ""
+
msgid "Shards (%{shards})"
msgstr ""
@@ -22784,6 +23609,9 @@ msgstr ""
msgid "Show all requirements."
msgstr ""
+msgid "Show all test cases."
+msgstr ""
+
msgid "Show archived projects"
msgstr ""
@@ -22796,6 +23624,9 @@ msgstr ""
msgid "Show comments"
msgstr ""
+msgid "Show comments on this file"
+msgstr ""
+
msgid "Show comments only"
msgstr ""
@@ -22841,6 +23672,12 @@ msgstr ""
msgid "Show parent subgroups"
msgstr ""
+msgid "Show the Closed list"
+msgstr ""
+
+msgid "Show the Open list"
+msgstr ""
+
msgid "Show whitespace changes"
msgstr ""
@@ -22884,9 +23721,6 @@ msgstr ""
msgid "Sidebar|Assign health status"
msgstr ""
-msgid "Sidebar|Change weight"
-msgstr ""
-
msgid "Sidebar|Health status"
msgstr ""
@@ -23070,6 +23904,9 @@ msgstr ""
msgid "Snippets|Add another file %{num}/%{total}"
msgstr ""
+msgid "Snippets|Authored %{time_ago} by %{author}"
+msgstr ""
+
msgid "Snippets|Delete file"
msgstr ""
@@ -23097,6 +23934,9 @@ msgstr ""
msgid "Solution"
msgstr ""
+msgid "Some changes are not shown"
+msgstr ""
+
msgid "Some child epics may be hidden due to applied filters"
msgstr ""
@@ -23463,6 +24303,12 @@ msgstr ""
msgid "Source (branch or tag)"
msgstr ""
+msgid "Source Branch"
+msgstr ""
+
+msgid "Source branch: %{source_branch_open}%{source_branch}%{source_branch_close}"
+msgstr ""
+
msgid "Source code"
msgstr ""
@@ -23628,9 +24474,6 @@ msgstr ""
msgid "Start and due date"
msgstr ""
-msgid "Start by choosing a group to see how your team is spending time. You can then drill down to the project level."
-msgstr ""
-
msgid "Start by choosing a group to start exploring the merge requests in that group. You can then proceed to filter by projects, labels, milestones and authors."
msgstr ""
@@ -23712,18 +24555,27 @@ msgstr ""
msgid "StaticSiteEditor|3. Assign a person to review and accept the merge request."
msgstr ""
+msgid "StaticSiteEditor|A link to view the merge request will appear once ready."
+msgstr ""
+
msgid "StaticSiteEditor|An error occurred while submitting your changes."
msgstr ""
msgid "StaticSiteEditor|Branch could not be created."
msgstr ""
+msgid "StaticSiteEditor|Copy update"
+msgstr ""
+
msgid "StaticSiteEditor|Could not commit the content changes."
msgstr ""
msgid "StaticSiteEditor|Could not create merge request."
msgstr ""
+msgid "StaticSiteEditor|Creating your merge request"
+msgstr ""
+
msgid "StaticSiteEditor|Incompatible file content"
msgstr ""
@@ -23745,6 +24597,9 @@ msgstr ""
msgid "StaticSiteEditor|View documentation"
msgstr ""
+msgid "StaticSiteEditor|You can set an assignee to get your changes reviewed and deployed once your merge request is created."
+msgstr ""
+
msgid "StaticSiteEditor|Your merge request has been created"
msgstr ""
@@ -23874,15 +24729,15 @@ msgstr ""
msgid "Submit %{humanized_resource_name}"
msgstr ""
-msgid "Submit Changes"
-msgstr ""
-
msgid "Submit a review"
msgstr ""
msgid "Submit as spam"
msgstr ""
+msgid "Submit changes"
+msgstr ""
+
msgid "Submit feedback"
msgstr ""
@@ -24036,6 +24891,9 @@ msgstr ""
msgid "Successfully deleted U2F device."
msgstr ""
+msgid "Successfully deleted WebAuthn device."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -24354,9 +25212,6 @@ msgstr ""
msgid "Template to append to all Service Desk issues"
msgstr ""
-msgid "Template was successfully saved."
-msgstr ""
-
msgid "Templates"
msgstr ""
@@ -24435,10 +25290,28 @@ msgid_plural "Test coverage: %d hits"
msgstr[0] ""
msgstr[1] ""
-msgid "Test failed."
+msgid "Test settings"
msgstr ""
-msgid "Test settings and save changes"
+msgid "TestCases|New Test Case"
+msgstr ""
+
+msgid "TestCases|New test case"
+msgstr ""
+
+msgid "TestCases|Search test cases"
+msgstr ""
+
+msgid "TestCases|Something went wrong while creating a test case."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching count of test cases."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching test cases list."
+msgstr ""
+
+msgid "TestCases|Submit test case"
msgstr ""
msgid "TestHooks|Ensure one of your projects has merge requests."
@@ -24504,6 +25377,9 @@ msgstr ""
msgid "Thank you for signing up for your free trial! You will get additional instructions in your inbox shortly."
msgstr ""
+msgid "Thank you for your business."
+msgstr ""
+
msgid "Thank you for your feedback!"
msgstr ""
@@ -24563,9 +25439,6 @@ msgstr ""
msgid "The URL to use for connecting to Elasticsearch. Use a comma-separated list to support clustering (e.g., \"http://localhost:9200, http://localhost:9201\")."
msgstr ""
-msgid "The Web IDE offers advanced syntax highlighting capabilities and more."
-msgstr ""
-
msgid "The X509 Certificate to use when mutual TLS is required to communicate with the external authorization service. If left blank, the server certificate is still validated when accessing over HTTPS."
msgstr ""
@@ -24676,6 +25549,9 @@ msgstr ""
msgid "The form contains the following error:"
msgstr ""
+msgid "The form contains the following warning:"
+msgstr ""
+
msgid "The global settings require you to enable Two-Factor Authentication for your account."
msgstr ""
@@ -24790,9 +25666,6 @@ msgstr ""
msgid "The private key to use when a client certificate is provided. This value is encrypted at rest."
msgstr ""
-msgid "The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The project can be accessed by any logged in user."
msgstr ""
@@ -24829,7 +25702,7 @@ msgstr ""
msgid "The remote repository is being updated..."
msgstr ""
-msgid "The repository can be commited to, and issues, comments and other entities can be created."
+msgid "The repository can be committed to, and issues, comments and other entities can be created."
msgstr ""
msgid "The repository for this project does not exist."
@@ -24883,9 +25756,6 @@ msgstr ""
msgid "The time taken by each data entry gathered by that stage."
msgstr ""
-msgid "The total stage shows the time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The update action will time out after %{number_of_minutes} minutes. For big repositories, use a clone/push combination."
msgstr ""
@@ -24949,6 +25819,9 @@ msgstr ""
msgid "There are no archived requirements"
msgstr ""
+msgid "There are no archived test cases"
+msgstr ""
+
msgid "There are no changes"
msgstr ""
@@ -24988,6 +25861,9 @@ msgstr ""
msgid "There are no open requirements"
msgstr ""
+msgid "There are no open test cases"
+msgstr ""
+
msgid "There are no packages yet"
msgstr ""
@@ -25000,6 +25876,9 @@ msgstr ""
msgid "There is a limit of %{ci_project_subscriptions_limit} subscriptions from or to a project."
msgstr ""
+msgid "There is already a To-Do for this design."
+msgstr ""
+
msgid "There is already a repository with that name on disk"
msgstr ""
@@ -25018,6 +25897,9 @@ msgstr ""
msgid "There was a problem communicating with your device."
msgstr ""
+msgid "There was a problem fetching branches."
+msgstr ""
+
msgid "There was a problem fetching groups."
msgstr ""
@@ -25246,9 +26128,15 @@ msgstr ""
msgid "This action can lead to data loss. To prevent accidental actions we ask you to confirm your intention."
msgstr ""
+msgid "This action cannot be undone, and will permanently delete the %{key} SSH key"
+msgstr ""
+
msgid "This action cannot be undone. You will lose the project's repository and all content: issues, merge requests, etc."
msgstr ""
+msgid "This action has been performed too many times. Try again later."
+msgstr ""
+
msgid "This action will %{strongOpen}permanently delete%{strongClose} %{codeOpen}%{project}%{codeClose} %{strongOpen}immediately%{strongClose}, including its repositories and all content: issues, merge requests, etc."
msgstr ""
@@ -25276,9 +26164,6 @@ msgstr ""
msgid "This board's scope is reduced"
msgstr ""
-msgid "This branch has changed since you started editing. Would you like to create a new branch?"
-msgstr ""
-
msgid "This chart could not be displayed"
msgstr ""
@@ -25405,15 +26290,9 @@ msgstr ""
msgid "This is a security log of important events involving your account."
msgstr ""
-msgid "This is the author's first Merge Request to this project."
-msgstr ""
-
msgid "This is the highest peak of users on your installation since the license started."
msgstr ""
-msgid "This is the maximum number of users that have existed at the same time since the license started. This is the minimum number of seats you will need to buy when you renew your license."
-msgstr ""
-
msgid "This is the number of currently active users on your installation, and this is the minimum number you need to purchase when you renew your license."
msgstr ""
@@ -25645,6 +26524,15 @@ msgstr ""
msgid "This user has no identities"
msgstr ""
+msgid "This user has previously committed to the %{name} project."
+msgstr ""
+
+msgid "This user has the %{access} role in the %{name} project."
+msgstr ""
+
+msgid "This user is the author of this %{noteable}."
+msgstr ""
+
msgid "This user will be the author of all events in the activity feed that are the result of an update, like new branches being created or new commits being pushed to existing branches."
msgstr ""
@@ -25675,6 +26563,9 @@ msgstr ""
msgid "Threat Monitoring"
msgstr ""
+msgid "ThreatMonitoring|All Environments"
+msgstr ""
+
msgid "ThreatMonitoring|Anomalous Requests"
msgstr ""
@@ -25702,9 +26593,6 @@ msgstr ""
msgid "ThreatMonitoring|Operations Per Second"
msgstr ""
-msgid "ThreatMonitoring|Overview"
-msgstr ""
-
msgid "ThreatMonitoring|Packet Activity"
msgstr ""
@@ -25723,6 +26611,9 @@ msgstr ""
msgid "ThreatMonitoring|Something went wrong, unable to fetch statistics"
msgstr ""
+msgid "ThreatMonitoring|Statistics"
+msgstr ""
+
msgid "ThreatMonitoring|The firewall is not installed or has been disabled. To view this data, ensure the web application firewall is installed and enabled for your cluster."
msgstr ""
@@ -26114,6 +27005,9 @@ msgstr ""
msgid "To update Snippets with multiple files, you must use the `files` parameter"
msgstr ""
+msgid "To use Gitpod you must first enable the feature in the integrations section of your %{user_prefs}."
+msgstr ""
+
msgid "To view all %{scannedResourcesCount} scanned URLs, please download the CSV file"
msgstr ""
@@ -26147,9 +27041,6 @@ msgstr ""
msgid "Toggle Sidebar"
msgstr ""
-msgid "Toggle all threads"
-msgstr ""
-
msgid "Toggle backtrace"
msgstr ""
@@ -26174,9 +27065,6 @@ msgstr ""
msgid "Toggle navigation"
msgstr ""
-msgid "Toggle project"
-msgstr ""
-
msgid "Toggle sidebar"
msgstr ""
@@ -26216,6 +27104,9 @@ msgstr ""
msgid "Too many projects enabled. You will need to manage them via the console or the API."
msgstr ""
+msgid "Too much data"
+msgstr ""
+
msgid "Topics (optional)"
msgstr ""
@@ -26234,6 +27125,9 @@ msgstr ""
msgid "Total cores (CPUs)"
msgstr ""
+msgid "Total days to completion"
+msgstr ""
+
msgid "Total issues"
msgstr ""
@@ -26330,6 +27224,9 @@ msgstr ""
msgid "Trending"
msgstr ""
+msgid "Trials|Create a new group to start your GitLab Gold trial."
+msgstr ""
+
msgid "Trials|Go back to GitLab"
msgstr ""
@@ -26339,6 +27236,15 @@ msgstr ""
msgid "Trials|You can always resume this process by selecting your avatar and choosing 'Start a Gold trial'"
msgstr ""
+msgid "Trials|You can apply your trial to a new group or an existing group."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group or your personal account."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group, an existing group, or your personal account."
+msgstr ""
+
msgid "Trials|You won't get a free trial right now but you can always resume this process by clicking on your avatar and choosing 'Start a free trial'"
msgstr ""
@@ -26408,6 +27314,9 @@ msgstr ""
msgid "Try using a different search term to find the file you are looking for."
msgstr ""
+msgid "Trying to communicate with your device. Plug it in (if needed) and press the button on the device now."
+msgstr ""
+
msgid "Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now."
msgstr ""
@@ -26495,6 +27404,12 @@ msgstr ""
msgid "URL or request ID"
msgstr ""
+msgid "USER %{user} WILL BE REMOVED! Are you sure?"
+msgstr ""
+
+msgid "USER WILL BE BLOCKED! Are you sure?"
+msgstr ""
+
msgid "UTC"
msgstr ""
@@ -26552,9 +27467,6 @@ msgstr ""
msgid "Unable to load the merge request widget. Try reloading the page."
msgstr ""
-msgid "Unable to resolve"
-msgstr ""
-
msgid "Unable to save iteration. Please try again"
msgstr ""
@@ -26603,6 +27515,9 @@ msgstr ""
msgid "Undo ignore"
msgstr ""
+msgid "Unexpected error"
+msgstr ""
+
msgid "Unfortunately, your email message to GitLab could not be processed."
msgstr ""
@@ -26636,6 +27551,9 @@ msgstr ""
msgid "Unknown response text"
msgstr ""
+msgid "Unless otherwise agreed to in writing with GitLab, by clicking \"Upload License\" you agree that your use of GitLab Software is subject to the %{eula_link_start}Terms of Service%{eula_link_end}."
+msgstr ""
+
msgid "Unlimited"
msgstr ""
@@ -27002,9 +27920,6 @@ msgstr ""
msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
msgstr ""
-msgid "Use a hardware device to add the second factor of authentication."
-msgstr ""
-
msgid "Use an one time password authenticator on your mobile device or computer to enable two-factor authentication (2FA)."
msgstr ""
@@ -27278,13 +28193,13 @@ msgstr ""
msgid "Users"
msgstr ""
-msgid "Users in License:"
+msgid "Users in License"
msgstr ""
-msgid "Users or groups set as approvers in the project's or merge request's settings."
+msgid "Users in License:"
msgstr ""
-msgid "Users outside of license"
+msgid "Users or groups set as approvers in the project's or merge request's settings."
msgstr ""
msgid "Users over License:"
@@ -27302,9 +28217,6 @@ msgstr ""
msgid "Users with a Guest role or those who don't belong to a Project or Group will not use a seat from your license."
msgstr ""
-msgid "Users with a Guest role or those who don't belong to any projects or groups don't count towards seats in use."
-msgstr ""
-
msgid "UsersSelect|%{name} + %{length} more"
msgstr ""
@@ -27344,9 +28256,6 @@ msgstr ""
msgid "Validations failed."
msgstr ""
-msgid "Validity"
-msgstr ""
-
msgid "Value"
msgstr ""
@@ -27365,6 +28274,9 @@ msgstr ""
msgid "Value Stream Name"
msgstr ""
+msgid "ValueStreamAnalyticsStage|We don't have enough data to show this stage."
+msgstr ""
+
msgid "ValueStreamAnalytics|%{days}d"
msgstr ""
@@ -27621,6 +28533,9 @@ msgstr ""
msgid "VisualReviewApp|Steps 1 and 2 (and sometimes 3) are performed once by the developer before requesting feedback. Steps 3 (if necessary), 4 is performed by the reviewer each time they perform a review."
msgstr ""
+msgid "Visualization"
+msgstr ""
+
msgid "Vulnerabilities"
msgstr ""
@@ -27648,34 +28563,31 @@ msgstr ""
msgid "VulnerabilityChart|Severity"
msgstr ""
-msgid "VulnerabilityManagement|A true-positive and will fix"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Change status"
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|Confirm"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Confirmed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
-msgstr ""
-
-msgid "VulnerabilityManagement|Detected %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|A true-positive and will fix"
msgstr ""
-msgid "VulnerabilityManagement|Dismiss"
+msgid "VulnerabilityManagement|Change status"
msgstr ""
-msgid "VulnerabilityManagement|Dismissed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
msgstr ""
-msgid "VulnerabilityManagement|Resolved"
+msgid "VulnerabilityManagement|Detected"
msgstr ""
-msgid "VulnerabilityManagement|Resolved %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Needs triage"
msgstr ""
msgid "VulnerabilityManagement|Something went wrong while trying to delete the comment. Please try again later."
@@ -27726,6 +28638,9 @@ msgstr ""
msgid "Vulnerability|%{scannerName} (version %{scannerVersion})"
msgstr ""
+msgid "Vulnerability|Activity"
+msgstr ""
+
msgid "Vulnerability|Class"
msgstr ""
@@ -27738,6 +28653,9 @@ msgstr ""
msgid "Vulnerability|Description"
msgstr ""
+msgid "Vulnerability|Detected"
+msgstr ""
+
msgid "Vulnerability|Evidence"
msgstr ""
@@ -27801,6 +28719,9 @@ msgstr ""
msgid "Warning: Displaying this diagram might cause performance issues on this page."
msgstr ""
+msgid "We are currently unable to fetch data for the pipeline header."
+msgstr ""
+
msgid "We are currently unable to fetch data for this graph."
msgstr ""
@@ -27840,6 +28761,12 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
+msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
+msgstr ""
+
+msgid "We would like to inform you that your subscription GitLab Enterprise Edition %{plan_name} is nearing its user limit. You have %{active_user_count} active users, which is almost at the user limit of %{maximum_user_count}."
+msgstr ""
+
msgid "We've found no vulnerabilities"
msgstr ""
@@ -27855,6 +28782,12 @@ msgstr ""
msgid "Web terminal"
msgstr ""
+msgid "WebAuthn Devices (%{length})"
+msgstr ""
+
+msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
+msgstr ""
+
msgid "WebIDE|Merge request"
msgstr ""
@@ -27993,15 +28926,9 @@ msgstr ""
msgid "Welcome to the guided GitLab tour"
msgstr ""
-msgid "Welcome to your Issue Board!"
-msgstr ""
-
msgid "Welcome to your issue board!"
msgstr ""
-msgid "We’ve been making changes to %{featureName} and we’d love your feedback %{linkStart}in this issue%{linkEnd} to help us improve the experience."
-msgstr ""
-
msgid "What are you searching for?"
msgstr ""
@@ -28020,6 +28947,9 @@ msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
msgstr ""
+msgid "When enabled, any user visiting %{host} and creating an account will have to be explicitly approved by the admin before they can login. This setting is effective only if sign-ups are enabled."
+msgstr ""
+
msgid "When enabled, any user visiting %{host} will be able to create an account."
msgstr ""
@@ -28244,6 +29174,9 @@ msgstr ""
msgid "With requirements, you can set criteria to check your products against."
msgstr ""
+msgid "With test cases, you can define conditions for your project to meet in determining quality"
+msgstr ""
+
msgid "Withdraw Access Request"
msgstr ""
@@ -28259,6 +29192,9 @@ msgstr ""
msgid "Workflow Help"
msgstr ""
+msgid "Would you like to create a new branch?"
+msgstr ""
+
msgid "Write"
msgstr ""
@@ -28280,6 +29216,9 @@ msgstr ""
msgid "Wrong extern UID provided. Make sure Auth0 is configured correctly."
msgstr ""
+msgid "YYYY-MM-DD"
+msgstr ""
+
msgid "Yes"
msgstr ""
@@ -28337,7 +29276,7 @@ msgstr ""
msgid "You are going to remove the fork relationship from %{project_full_name}. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "You are going to transfer %{project_full_name} to another owner. Are you ABSOLUTELY sure?"
+msgid "You are going to transfer %{project_full_name} to another namespace. Are you ABSOLUTELY sure?"
msgstr ""
msgid "You are going to turn off the confidentiality. This means %{strongStart}everyone%{strongEnd} will be able to see and leave a comment on this %{issuableType}."
@@ -28397,9 +29336,6 @@ msgstr ""
msgid "You can always edit this later"
msgstr ""
-msgid "You can apply your Trial to your Personal account or create a New Group."
-msgstr ""
-
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings"
msgstr ""
@@ -28421,12 +29357,18 @@ msgstr ""
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
+msgid "You can find more information about GitLab subscriptions in %{subscriptions_doc_link}."
+msgstr ""
+
msgid "You can generate an access token scoped to this project for each application to use the GitLab API."
msgstr ""
msgid "You can get started by cloning the repository or start adding files to it with one of the following options."
msgstr ""
+msgid "You can group test cases using labels. To learn about the future direction of this feature, visit %{linkStart}Quality Management direction page%{linkEnd}."
+msgstr ""
+
msgid "You can invite a new member to %{project_name} or invite another group."
msgstr ""
@@ -28442,6 +29384,9 @@ msgstr ""
msgid "You can notify the app / group or a project by sending them an email notification"
msgstr ""
+msgid "You can now close this window."
+msgstr ""
+
msgid "You can now export your security dashboard to a CSV report."
msgstr ""
@@ -28490,9 +29435,6 @@ msgstr ""
msgid "You can test your .gitlab-ci.yml in %{linkStart}CI Lint%{linkEnd}."
msgstr ""
-msgid "You can try again using %{begin_link}basic search%{end_link}"
-msgstr ""
-
msgid "You cannot access the raw file. Please wait a minute."
msgstr ""
@@ -28544,6 +29486,9 @@ msgstr ""
msgid "You don't have any U2F devices registered yet."
msgstr ""
+msgid "You don't have any WebAuthn devices registered yet."
+msgstr ""
+
msgid "You don't have any active chat names."
msgstr ""
@@ -28631,6 +29576,9 @@ msgstr ""
msgid "You must accept our Terms of Service and privacy policy in order to register an account"
msgstr ""
+msgid "You must be logged in to search across all of GitLab"
+msgstr ""
+
msgid "You must disassociate %{domain} from all clusters it is attached to before deletion."
msgstr ""
@@ -28670,7 +29618,7 @@ msgstr ""
msgid "You need to be logged in."
msgstr ""
-msgid "You need to register a two-factor authentication app before you can set up a U2F device."
+msgid "You need to register a two-factor authentication app before you can set up a device."
msgstr ""
msgid "You need to set terms to be enforced"
@@ -28688,6 +29636,9 @@ msgstr ""
msgid "You reached %{usage_in_percent} of %{namespace_name}'s storage capacity (%{used_storage} of %{storage_limit})"
msgstr ""
+msgid "You successfully declined the invitation"
+msgstr ""
+
msgid "You tried to fork %{link_to_the_project} but it failed for the following reason:"
msgstr ""
@@ -28853,10 +29804,13 @@ msgstr ""
msgid "Your U2F device did not send a valid JSON response."
msgstr ""
-msgid "Your U2F device needs to be set up. Plug it in (if not already) and click the button on the left."
+msgid "Your U2F device was registered!"
msgstr ""
-msgid "Your U2F device was registered!"
+msgid "Your WebAuthn device did not send a valid JSON response."
+msgstr ""
+
+msgid "Your WebAuthn device was registered!"
msgstr ""
msgid "Your access request to the %{source_type} has been withdrawn."
@@ -28880,6 +29834,9 @@ msgstr ""
msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
msgstr ""
+msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
+msgstr ""
+
msgid "Your changes can be committed to %{branch_name} because a merge request is open."
msgstr ""
@@ -28916,6 +29873,12 @@ msgstr ""
msgid "Your deployment services will be broken, you will need to manually fix the services after renaming."
msgstr ""
+msgid "Your device is not compatible with GitLab. Please try another device"
+msgstr ""
+
+msgid "Your device needs to be set up. Plug it in (if needed) and click the button on the left."
+msgstr ""
+
msgid "Your device was successfully set up! Give it a name and register it with the GitLab server."
msgstr ""
@@ -29029,9 +29992,6 @@ msgstr[1] ""
msgid "access:"
msgstr ""
-msgid "activated"
-msgstr ""
-
msgid "added %{created_at_timeago}"
msgstr ""
@@ -29104,9 +30064,21 @@ msgstr ""
msgid "by %{user}"
msgstr ""
+msgid "cannot be a date in the past"
+msgstr ""
+
msgid "cannot be changed if a personal project has container registry tags."
msgstr ""
+msgid "cannot be changed if shared runners are enabled"
+msgstr ""
+
+msgid "cannot be enabled because parent group does not allow it"
+msgstr ""
+
+msgid "cannot be enabled because parent group has shared Runners disabled"
+msgstr ""
+
msgid "cannot be enabled unless all domains have TLS certificates"
msgstr ""
@@ -29152,7 +30124,7 @@ msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about SAST %{linkEndTag}"
msgstr ""
-msgid "ciReport|%{linkStartTag}Learn more about Secret Scanning %{linkEndTag}"
+msgid "ciReport|%{linkStartTag}Learn more about Secret Detection %{linkEndTag}"
msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about codequality reports %{linkEndTag}"
@@ -29467,9 +30439,6 @@ msgstr ""
msgid "error"
msgstr ""
-msgid "error code:"
-msgstr ""
-
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr ""
@@ -29491,6 +30460,9 @@ msgstr ""
msgid "failed to dismiss associated finding(id=%{finding_id}): %{message}"
msgstr ""
+msgid "failed to revert associated finding(id=%{finding_id}) to detected"
+msgstr ""
+
msgid "file"
msgid_plural "files"
msgstr[0] ""
@@ -30033,6 +31005,9 @@ msgstr ""
msgid "must be a root namespace"
msgstr ""
+msgid "must be a valid IPv4 or IPv6 address"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -30069,6 +31044,9 @@ msgstr ""
msgid "no expiration"
msgstr ""
+msgid "no name set"
+msgstr ""
+
msgid "no one can merge"
msgstr ""
@@ -30247,9 +31225,6 @@ msgstr ""
msgid "security Reports|There was an error creating the merge request"
msgstr ""
-msgid "settings saved, but not activated"
-msgstr ""
-
msgid "severity|Critical"
msgstr ""
@@ -30376,9 +31351,6 @@ msgstr ""
msgid "toggle collapse"
msgstr ""
-msgid "toggle dropdown"
-msgstr ""
-
msgid "triggered"
msgstr ""
@@ -30406,6 +31378,9 @@ msgstr ""
msgid "user avatar"
msgstr ""
+msgid "user preferences"
+msgstr ""
+
msgid "username"
msgstr ""
diff --git a/locale/sw_KE/gitlab.po b/locale/sw_KE/gitlab.po
index 4132468d6f6..82de5bbebf3 100644
--- a/locale/sw_KE/gitlab.po
+++ b/locale/sw_KE/gitlab.po
@@ -14,7 +14,10 @@ msgstr ""
"X-Crowdin-Language: sw\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 6\n"
-"PO-Revision-Date: 2020-09-04 23:05\n"
+"PO-Revision-Date: 2020-10-02 18:44\n"
+
+msgid " %{project_name}#%{issue_iid} &middot; opened %{issue_created} by %{author}"
+msgstr ""
msgid " %{start} to %{end}"
msgstr ""
@@ -74,6 +77,16 @@ msgstr ""
msgid "\"el\" parameter is required for createInstance()"
msgstr ""
+msgid "%d Approval"
+msgid_plural "%d Approvals"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d Package"
+msgid_plural "%d Packages"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d Scanned URL"
msgid_plural "%d Scanned URLs"
msgstr[0] ""
@@ -137,6 +150,11 @@ msgstr[1] ""
msgid "%d commits"
msgstr ""
+msgid "%d completed issue"
+msgid_plural "%d completed issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d contribution"
msgid_plural "%d contributions"
msgstr[0] ""
@@ -147,6 +165,11 @@ msgid_plural "%d days"
msgstr[0] ""
msgstr[1] ""
+msgid "%d day until tags are automatically removed"
+msgid_plural "%d days until tags are automatically removed"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d error"
msgid_plural "%d errors"
msgstr[0] ""
@@ -237,6 +260,16 @@ msgid_plural "%d more comments"
msgstr[0] ""
msgstr[1] ""
+msgid "%d open issue"
+msgid_plural "%d open issues"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d pending comment"
+msgid_plural "%d pending comments"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d personal project will be removed and cannot be restored."
msgid_plural "%d personal projects will be removed and cannot be restored."
msgstr[0] ""
@@ -252,6 +285,11 @@ msgid_plural "%d projects"
msgstr[0] ""
msgstr[1] ""
+msgid "%d project selected"
+msgid_plural "%d projects selected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d request with warnings"
msgid_plural "%d requests with warnings"
msgstr[0] ""
@@ -272,6 +310,11 @@ msgid_plural "%d tags"
msgstr[0] ""
msgstr[1] ""
+msgid "%d tag per image name"
+msgid_plural "%d tags per image name"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d unassigned issue"
msgid_plural "%d unassigned issues"
msgstr[0] ""
@@ -292,6 +335,11 @@ msgid_plural "%d vulnerabilities dismissed"
msgstr[0] ""
msgstr[1] ""
+msgid "%d warning found:"
+msgid_plural "%d warnings found:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%s additional commit has been omitted to prevent performance issues."
msgid_plural "%s additional commits have been omitted to prevent performance issues."
msgstr[0] ""
@@ -330,6 +378,9 @@ msgstr ""
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr ""
+msgid "%{completedCount} completed weight"
+msgstr ""
+
msgid "%{completedWeight} of %{totalWeight} weight completed"
msgstr ""
@@ -378,14 +429,12 @@ msgid_plural "%{count} participants"
msgstr[0] ""
msgstr[1] ""
-msgid "%{count} pending comment"
-msgid_plural "%{count} pending comments"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
+msgid "%{count} total weight"
+msgstr ""
+
msgid "%{dashboard_path} could not be found."
msgstr ""
@@ -440,6 +489,9 @@ msgstr ""
msgid "%{group_name} uses group managed accounts. You need to create a new GitLab account which will be managed by %{group_name}."
msgstr ""
+msgid "%{group_name}&%{epic_iid} &middot; opened %{epic_created} by %{author}"
+msgstr ""
+
msgid "%{host} sign-in from new location"
msgstr ""
@@ -452,7 +504,7 @@ msgstr ""
msgid "%{issuableType} will be removed! Are you sure?"
msgstr ""
-msgid "%{issuesSize} issues with a limit of %{maxIssueCount}"
+msgid "%{issuesCount} issues with a limit of %{maxIssueCount}"
msgstr ""
msgid "%{issuesSize} with a limit of %{maxIssueCount}"
@@ -485,7 +537,7 @@ msgstr ""
msgid "%{labelStart}Namespace:%{labelEnd} %{namespace}"
msgstr ""
-msgid "%{labelStart}Report Type:%{labelEnd} %{reportType}"
+msgid "%{labelStart}Scan Type:%{labelEnd} %{reportType}"
msgstr ""
msgid "%{labelStart}Scanner:%{labelEnd} %{scanner}"
@@ -682,9 +734,6 @@ msgid_plural "%{securityScanner} results are not available because a pipeline ha
msgstr[0] ""
msgstr[1] ""
-msgid "%{service_title} %{message}."
-msgstr ""
-
msgid "%{size} GiB"
msgstr ""
@@ -773,6 +822,12 @@ msgstr ""
msgid "%{timebox_name} should belong either to a project or a group."
msgstr ""
+msgid "%{timebox_type} does not support burnup charts"
+msgstr ""
+
+msgid "%{timebox_type} must have a start and due date"
+msgstr ""
+
msgid "%{title} %{operator} %{threshold}"
msgstr ""
@@ -797,7 +852,7 @@ msgstr ""
msgid "%{total} open issue weight"
msgstr ""
-msgid "%{total} open issues"
+msgid "%{total} warnings found: showing first %{warningsDisplayed}"
msgstr ""
msgid "%{usage_ping_link_start}Learn more%{usage_ping_link_end} about what information is shared with GitLab Inc."
@@ -830,9 +885,6 @@ msgstr ""
msgid "&lt; 1 hour"
msgstr ""
-msgid "&lt;no name set&gt;"
-msgstr ""
-
msgid "&lt;no scopes selected&gt;"
msgstr ""
@@ -863,6 +915,9 @@ msgstr ""
msgid "'%{name}' Value Stream created"
msgstr ""
+msgid "'%{name}' Value Stream deleted"
+msgstr ""
+
msgid "'%{name}' stage already exists"
msgstr ""
@@ -922,6 +977,9 @@ msgstr ""
msgid "+ %{numberOfHiddenAssignees} more"
msgstr ""
+msgid "+ %{numberOfHiddenReviewers} more"
+msgstr ""
+
msgid "+%d more"
msgid_plural "+%d more"
msgstr[0] ""
@@ -982,6 +1040,11 @@ msgid_plural "%d Days"
msgstr[0] ""
msgstr[1] ""
+msgid "1 Issue"
+msgid_plural "%d Issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "1 closed issue"
msgid_plural "%{issues} closed issues"
msgstr[0] ""
@@ -997,6 +1060,11 @@ msgid_plural "%d days"
msgstr[0] ""
msgstr[1] ""
+msgid "1 deploy key"
+msgid_plural "%d deploy keys"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1099,6 +1167,9 @@ msgstr ""
msgid ":%{startLine} to %{endLine}"
msgstr ""
+msgid "A %{incident_docs_start}modified issue%{incident_docs_end} to guide the resolution of incidents."
+msgstr ""
+
msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr ""
@@ -1111,6 +1182,9 @@ msgstr ""
msgid "A GitBook site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
+msgid "A Gitpod configured Webapplication in Spring and Java"
+msgstr ""
+
msgid "A Hexo site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
@@ -1282,9 +1356,15 @@ msgstr ""
msgid "Access expiration date"
msgstr ""
+msgid "Access expires"
+msgstr ""
+
msgid "Access forbidden. Check your access level."
msgstr ""
+msgid "Access granted"
+msgstr ""
+
msgid "Access requests"
msgstr ""
@@ -1294,6 +1374,9 @@ msgstr ""
msgid "Access to Pages websites are controlled based on the user's membership to a given project. By checking this box, users will be required to be logged in to have access to all Pages websites in your instance."
msgstr ""
+msgid "AccessDropdown|Deploy Keys"
+msgstr ""
+
msgid "AccessDropdown|Groups"
msgstr ""
@@ -1411,12 +1494,6 @@ msgstr ""
msgid "Active Sessions"
msgstr ""
-msgid "Active Users:"
-msgstr ""
-
-msgid "Active users"
-msgstr ""
-
msgid "Activity"
msgstr ""
@@ -1584,9 +1661,6 @@ msgstr ""
msgid "Add label(s)"
msgstr ""
-msgid "Add license"
-msgstr ""
-
msgid "Add list"
msgstr ""
@@ -1761,21 +1835,51 @@ msgstr ""
msgid "AdminArea|Bots"
msgstr ""
+msgid "AdminArea|Components"
+msgstr ""
+
msgid "AdminArea|Developer"
msgstr ""
+msgid "AdminArea|Features"
+msgstr ""
+
+msgid "AdminArea|Groups: %{number_of_groups}"
+msgstr ""
+
msgid "AdminArea|Guest"
msgstr ""
msgid "AdminArea|Included Free in license"
msgstr ""
+msgid "AdminArea|Latest groups"
+msgstr ""
+
+msgid "AdminArea|Latest projects"
+msgstr ""
+
+msgid "AdminArea|Latest users"
+msgstr ""
+
msgid "AdminArea|Maintainer"
msgstr ""
+msgid "AdminArea|New group"
+msgstr ""
+
+msgid "AdminArea|New project"
+msgstr ""
+
+msgid "AdminArea|New user"
+msgstr ""
+
msgid "AdminArea|Owner"
msgstr ""
+msgid "AdminArea|Projects: %{number_of_projects}"
+msgstr ""
+
msgid "AdminArea|Reporter"
msgstr ""
@@ -1803,6 +1907,9 @@ msgstr ""
msgid "AdminArea|Users without a Group and Project"
msgstr ""
+msgid "AdminArea|Users: %{number_of_users}"
+msgstr ""
+
msgid "AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running."
msgstr ""
@@ -1821,9 +1928,6 @@ msgstr ""
msgid "AdminProjects|Delete Project %{projectName}?"
msgstr ""
-msgid "AdminProjects|Delete project"
-msgstr ""
-
msgid "AdminSettings|Apply integration settings to all Projects"
msgstr ""
@@ -2061,21 +2165,30 @@ msgstr ""
msgid "AdminUsers|Without projects"
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 ""
msgid "AdminUsers|You cannot remove your own admin rights."
msgstr ""
+msgid "AdminUsers|You must transfer ownership or delete the groups owned by this user before you can delete their account"
+msgstr ""
+
msgid "Administration"
msgstr ""
msgid "Advanced"
msgstr ""
+msgid "Advanced Search"
+msgstr ""
+
+msgid "Advanced Search with Elasticsearch"
+msgstr ""
+
msgid "Advanced Settings"
msgstr ""
@@ -2153,6 +2266,9 @@ msgstr ""
msgid "AlertManagement|Edit"
msgstr ""
+msgid "AlertManagement|Environment"
+msgstr ""
+
msgid "AlertManagement|Events"
msgstr ""
@@ -2165,6 +2281,9 @@ msgstr ""
msgid "AlertManagement|Issue"
msgstr ""
+msgid "AlertManagement|Key"
+msgstr ""
+
msgid "AlertManagement|Low"
msgstr ""
@@ -2258,6 +2377,9 @@ msgstr ""
msgid "AlertManagement|Unknown"
msgstr ""
+msgid "AlertManagement|Value"
+msgstr ""
+
msgid "AlertManagement|View alerts in Opsgenie"
msgstr ""
@@ -2417,6 +2539,9 @@ msgstr ""
msgid "All projects"
msgstr ""
+msgid "All projects selected"
+msgstr ""
+
msgid "All security scans are enabled because %{linkStart}Auto DevOps%{linkEnd} is enabled on this project"
msgstr ""
@@ -2504,6 +2629,9 @@ msgstr ""
msgid "Almost there"
msgstr ""
+msgid "Already blocked"
+msgstr ""
+
msgid "Also called \"Issuer\" or \"Relying party trust identifier\""
msgstr ""
@@ -2558,6 +2686,9 @@ msgstr ""
msgid "An error has occurred"
msgstr ""
+msgid "An error occured while making the changes: %{error}"
+msgstr ""
+
msgid "An error occurred adding a draft to the thread."
msgstr ""
@@ -2585,12 +2716,6 @@ msgstr ""
msgid "An error occurred when toggling the notification subscription"
msgstr ""
-msgid "An error occurred when trying to resolve a comment. Please try again."
-msgstr ""
-
-msgid "An error occurred when trying to resolve a discussion. Please try again."
-msgstr ""
-
msgid "An error occurred when updating the issue weight"
msgstr ""
@@ -2606,12 +2731,6 @@ msgstr ""
msgid "An error occurred while checking group path. Please refresh and try again."
msgstr ""
-msgid "An error occurred while committing your changes."
-msgstr ""
-
-msgid "An error occurred while creating the list. Please try again."
-msgstr ""
-
msgid "An error occurred while decoding the file."
msgstr ""
@@ -2684,25 +2803,19 @@ msgstr ""
msgid "An error occurred while fetching the Service Desk address."
msgstr ""
-msgid "An error occurred while fetching the board issues. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the board lists. Please reload the page."
msgstr ""
msgid "An error occurred while fetching the board lists. Please try again."
msgstr ""
-msgid "An error occurred while fetching the board swimlanes. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the builds."
msgstr ""
msgid "An error occurred while fetching the job log."
msgstr ""
-msgid "An error occurred while fetching the job trace."
+msgid "An error occurred while fetching the job logs."
msgstr ""
msgid "An error occurred while fetching the job."
@@ -2849,9 +2962,6 @@ msgstr ""
msgid "An error occurred while saving assignees"
msgstr ""
-msgid "An error occurred while saving the template. Please check if the template exists."
-msgstr ""
-
msgid "An error occurred while searching for milestones"
msgstr ""
@@ -2870,10 +2980,10 @@ msgstr ""
msgid "An error occurred while updating approvers"
msgstr ""
-msgid "An error occurred while updating the comment"
+msgid "An error occurred while updating labels."
msgstr ""
-msgid "An error occurred while updating the list. Please try again."
+msgid "An error occurred while updating the comment"
msgstr ""
msgid "An error occurred while validating group path"
@@ -2927,6 +3037,9 @@ msgstr ""
msgid "An unknown error occurred while loading this graph."
msgstr ""
+msgid "An unknown error occurred."
+msgstr ""
+
msgid "Analytics"
msgstr ""
@@ -2960,10 +3073,10 @@ msgstr ""
msgid "Any"
msgstr ""
-msgid "Any Author"
+msgid "Any %{header}"
msgstr ""
-msgid "Any Status"
+msgid "Any Author"
msgstr ""
msgid "Any branch"
@@ -3017,6 +3130,9 @@ msgstr ""
msgid "Application ID"
msgstr ""
+msgid "Application limits saved successfully"
+msgstr ""
+
msgid "Application settings saved successfully"
msgstr ""
@@ -3226,6 +3342,9 @@ msgstr ""
msgid "Are you sure you want to close this blocked issue?"
msgstr ""
+msgid "Are you sure you want to delete \"%{name}\" Value Stream?"
+msgstr ""
+
msgid "Are you sure you want to delete %{name}?"
msgstr ""
@@ -3235,6 +3354,9 @@ msgstr ""
msgid "Are you sure you want to delete this %{typeOfComment}?"
msgstr ""
+msgid "Are you sure you want to delete this SSH key?"
+msgstr ""
+
msgid "Are you sure you want to delete this board?"
msgstr ""
@@ -3259,6 +3381,11 @@ msgstr ""
msgid "Are you sure you want to erase this build?"
msgstr ""
+msgid "Are you sure you want to import %d repository?"
+msgid_plural "Are you sure you want to import %d repositories?"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Are you sure you want to lose unsaved changes?"
msgstr ""
@@ -3268,15 +3395,15 @@ msgstr ""
msgid "Are you sure you want to merge immediately?"
msgstr ""
-msgid "Are you sure you want to permanently delete this license?"
-msgstr ""
-
msgid "Are you sure you want to re-deploy this environment?"
msgstr ""
msgid "Are you sure you want to regenerate the public key? You will have to update the public key on the remote server before mirroring will work again."
msgstr ""
+msgid "Are you sure you want to reindex?"
+msgstr ""
+
msgid "Are you sure you want to remove %{group_name}?"
msgstr ""
@@ -3304,6 +3431,9 @@ msgstr ""
msgid "Are you sure you want to revoke this nickname?"
msgstr ""
+msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
+msgstr ""
+
msgid "Are you sure you want to stop this environment?"
msgstr ""
@@ -3325,6 +3455,9 @@ msgstr ""
msgid "Are you sure? The device will be signed out of GitLab and all remember me tokens revoked."
msgstr ""
+msgid "Are you sure? This will invalidate your registered applications and U2F / WebAuthn devices."
+msgstr ""
+
msgid "Are you sure? This will invalidate your registered applications and U2F devices."
msgstr ""
@@ -3343,9 +3476,6 @@ msgstr ""
msgid "Artifacts"
msgstr ""
-msgid "As U2F devices are only supported by a few browsers, we require that you set up a two-factor authentication app before a U2F device. That way you'll always be able to log in - even when you're using an unsupported browser."
-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 ""
@@ -3539,6 +3669,9 @@ msgstr ""
msgid "AuditLogs|Target"
msgstr ""
+msgid "AuditLogs|This month"
+msgstr ""
+
msgid "AuditLogs|User Events"
msgstr ""
@@ -3578,6 +3711,9 @@ msgstr ""
msgid "Authentication via U2F device failed."
msgstr ""
+msgid "Authentication via WebAuthn device failed."
+msgstr ""
+
msgid "Author"
msgstr ""
@@ -3845,15 +3981,6 @@ msgstr ""
msgid "BambooService|You must set up automatic revision labeling and a repository trigger in Bamboo."
msgstr ""
-msgid "BatchComments|Delete all pending comments"
-msgstr ""
-
-msgid "BatchComments|Discard review?"
-msgstr ""
-
-msgid "BatchComments|You're about to discard your review which will delete all of your pending comments. The deleted comments %{strong_start}cannot%{strong_end} be restored."
-msgstr ""
-
msgid "Be careful. Changing the project's namespace can have unintended side effects."
msgstr ""
@@ -3875,6 +4002,9 @@ msgstr ""
msgid "Bi-weekly code coverage"
msgstr ""
+msgid "Billable Users:"
+msgstr ""
+
msgid "Billing"
msgstr ""
@@ -3884,7 +4014,7 @@ msgstr ""
msgid "BillingPlans|@%{user_name} you are currently using the %{plan_name} plan."
msgstr ""
-msgid "BillingPlans|Congratulations, your new trial is activated"
+msgid "BillingPlans|Congratulations, your free trial is activated."
msgstr ""
msgid "BillingPlans|If you would like to downgrade your plan please contact %{support_link_start}Customer Support%{support_link_end}."
@@ -3947,6 +4077,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Block user"
+msgstr ""
+
msgid "Blocked"
msgstr ""
@@ -3962,31 +4095,37 @@ msgstr ""
msgid "Blog"
msgstr ""
-msgid "Board name"
-msgstr ""
-
msgid "Board scope"
msgstr ""
msgid "Board scope affects which issues are displayed for anyone who visits this board"
msgstr ""
-msgid "BoardBlankState|Add default lists"
+msgid "Boards"
msgstr ""
-msgid "BoardBlankState|Add the following default lists to your Issue Board with one click:"
+msgid "Boards and Board Lists"
msgstr ""
-msgid "BoardBlankState|Nevermind, I'll use my own"
+msgid "Boards|An error occurred while creating the issue. Please try again."
msgstr ""
-msgid "BoardBlankState|Starting out with the default set of lists will get you right on the way to making the most of your board."
+msgid "Boards|An error occurred while creating the list. Please try again."
msgstr ""
-msgid "Boards"
+msgid "Boards|An error occurred while fetching issues. Please reload the page."
msgstr ""
-msgid "Boards and Board Lists"
+msgid "Boards|An error occurred while fetching the board issues. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching the board swimlanes. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while moving the issue. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while updating the list. Please try again."
msgstr ""
msgid "Boards|Collapse"
@@ -4013,7 +4152,7 @@ msgstr ""
msgid "Branch %{branch_name} was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr ""
-msgid "Branch has changed"
+msgid "Branch changed"
msgstr ""
msgid "Branch is already taken"
@@ -4319,6 +4458,9 @@ msgstr ""
msgid "CLOSED (MOVED)"
msgstr ""
+msgid "CODEOWNERS rule violation"
+msgstr ""
+
msgid "CONTRIBUTING"
msgstr ""
@@ -4349,9 +4491,6 @@ msgstr ""
msgid "Can't create snippet: %{err}"
msgstr ""
-msgid "Can't edit as source branch was deleted"
-msgstr ""
-
msgid "Can't fetch content for the blob: %{err}"
msgstr ""
@@ -4364,9 +4503,6 @@ msgstr ""
msgid "Can't load mermaid module: %{err}"
msgstr ""
-msgid "Can't remove group members without group managed account"
-msgstr ""
-
msgid "Can't scan the code?"
msgstr ""
@@ -4409,6 +4545,9 @@ msgstr ""
msgid "Cannot create the abuse report. This user has been blocked."
msgstr ""
+msgid "Cannot enable shared runners because parent group does not allow it"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -4514,6 +4653,15 @@ msgstr ""
msgid "Change your password or recover your current one"
msgstr ""
+msgid "ChangeReviewer|Reviewer changed from %{old} to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Reviewer changed to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Unassigned"
+msgstr ""
+
msgid "ChangeTypeActionLabel|Pick into branch"
msgstr ""
@@ -4553,6 +4701,9 @@ msgstr ""
msgid "Changes the title to \"%{title_param}\"."
msgstr ""
+msgid "Changes were successfully made."
+msgstr ""
+
msgid "Changes won't take place until the index is %{link_start}recreated%{link_end}."
msgstr ""
@@ -4958,6 +5109,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove variable"
+msgstr ""
+
msgid "CiVariables|Remove variable row"
msgstr ""
@@ -5036,9 +5190,6 @@ msgstr ""
msgid "Clear due date"
msgstr ""
-msgid "Clear input"
-msgstr ""
-
msgid "Clear recent searches"
msgstr ""
@@ -5087,6 +5238,9 @@ msgstr ""
msgid "Client authentication key password"
msgstr ""
+msgid "Client request timeout"
+msgstr ""
+
msgid "Clients"
msgstr ""
@@ -5171,6 +5325,27 @@ msgstr ""
msgid "Cluster type must be specificed for Stages::ClusterEndpointInserter"
msgstr ""
+msgid "ClusterAgents|Configuration"
+msgstr ""
+
+msgid "ClusterAgents|Connect your cluster with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate Kubernetes with a GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Name"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Agent also requires %{linkStart}enabling the Agent Server%{linkEnd}"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Kubernetes Agent allows an Infrastructure as Code, GitOps approach to integrating Kubernetes clusters with GitLab. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "ClusterAgent|This feature is only available for premium plans"
msgstr ""
@@ -5240,10 +5415,10 @@ msgstr ""
msgid "ClusterIntegration|All installed applications and related resources"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster."
+msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{linkStart}More information%{linkEnd}"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{startLink}More information%{endLink}"
+msgid "ClusterIntegration|Allow GitLab to manage namespaces and service accounts for this cluster."
msgstr ""
msgid "ClusterIntegration|Alternatively, "
@@ -5264,6 +5439,9 @@ msgstr ""
msgid "ClusterIntegration|An error occurred while trying to fetch zone machine types: %{error}"
msgstr ""
+msgid "ClusterIntegration|An unknown error occurred while attempting to connect to Kubernetes."
+msgstr ""
+
msgid "ClusterIntegration|Any project namespaces"
msgstr ""
@@ -5279,6 +5457,9 @@ msgstr ""
msgid "ClusterIntegration|Authenticate with Amazon Web Services"
msgstr ""
+msgid "ClusterIntegration|Authentication Error"
+msgstr ""
+
msgid "ClusterIntegration|Base domain"
msgstr ""
@@ -5297,13 +5478,22 @@ msgstr ""
msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}security group %{externalLinkIcon} %{endLink} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
+msgid "ClusterIntegration|Check your CA certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Check your cluster status"
+msgstr ""
+
+msgid "ClusterIntegration|Check your token"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}subnets %{externalLinkIcon} %{endLink} in your VPC where your worker nodes will run."
+msgid "ClusterIntegration|Choose the %{linkStart}security group %{linkEnd} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
msgstr ""
-msgid "ClusterIntegration|Choose the worker node %{startLink}instance type %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Choose the %{linkStart}subnets %{linkEnd} in your VPC where your worker nodes will run."
+msgstr ""
+
+msgid "ClusterIntegration|Choose the worker node %{linkStart}instance type%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Choose which applications to install on your Kubernetes cluster."
@@ -5315,10 +5505,7 @@ msgstr ""
msgid "ClusterIntegration|Clear cluster cache"
msgstr ""
-msgid "ClusterIntegration|Clear the local cache of namespace and service accounts. This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
-msgstr ""
-
-msgid "ClusterIntegration|Cluster being created"
+msgid "ClusterIntegration|Clear the local cache of namespace and service accounts."
msgstr ""
msgid "ClusterIntegration|Cluster management project (alpha)"
@@ -5330,15 +5517,21 @@ msgstr ""
msgid "ClusterIntegration|Cluster_applications artifact too big. Maximum allowable size: %{human_size}"
msgstr ""
-msgid "ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters."
+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|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}"
+msgid "ClusterIntegration|Clusters connected with a certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Connect cluster with certificate"
msgstr ""
msgid "ClusterIntegration|Connect existing cluster"
msgstr ""
+msgid "ClusterIntegration|Connection Error"
+msgstr ""
+
msgid "ClusterIntegration|Copy API URL"
msgstr ""
@@ -5414,6 +5607,12 @@ msgstr ""
msgid "ClusterIntegration|Deletes all GitLab resources attached to this cluster during removal"
msgstr ""
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared."
+msgstr ""
+
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared. %{linkStart}More information%{linkEnd}"
+msgstr ""
+
msgid "ClusterIntegration|Did you know?"
msgstr ""
@@ -5483,6 +5682,9 @@ msgstr ""
msgid "ClusterIntegration|Fluentd is an open source data collector, which lets you unify the data collection and consumption for a better use and understanding of data. It requires at least one of the following logs to be successfully installed."
msgstr ""
+msgid "ClusterIntegration|GitLab Agent managed clusters"
+msgstr ""
+
msgid "ClusterIntegration|GitLab Container Network Policies"
msgstr ""
@@ -5495,6 +5697,12 @@ msgstr ""
msgid "ClusterIntegration|GitLab Runner connects to the repository and executes CI/CD jobs, pushing results back and deploying applications to production."
msgstr ""
+msgid "ClusterIntegration|GitLab failed to authenticate."
+msgstr ""
+
+msgid "ClusterIntegration|GitLab failed to connect to the cluster."
+msgstr ""
+
msgid "ClusterIntegration|GitLab-managed cluster"
msgstr ""
@@ -5516,6 +5724,9 @@ msgstr ""
msgid "ClusterIntegration|Group cluster"
msgstr ""
+msgid "ClusterIntegration|HTTP Error"
+msgstr ""
+
msgid "ClusterIntegration|Helm Tiller"
msgstr ""
@@ -5549,7 +5760,10 @@ msgstr ""
msgid "ClusterIntegration|Instance type"
msgstr ""
-msgid "ClusterIntegration|Integrate Kubernetes cluster automation"
+msgid "ClusterIntegration|Integrate Kubernetes with a cluster certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Integrate with a cluster certificate"
msgstr ""
msgid "ClusterIntegration|Issuer Email"
@@ -5585,9 +5799,6 @@ msgstr ""
msgid "ClusterIntegration|Knative extends Kubernetes to provide a set of middleware components that are essential to build modern, source-centric, and container-based applications that can run anywhere: on premises, in the cloud, or even in a third-party data center."
msgstr ""
-msgid "ClusterIntegration|Kubernetes cluster"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes cluster is being created..."
msgstr ""
@@ -5600,9 +5811,6 @@ msgstr ""
msgid "ClusterIntegration|Kubernetes clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr ""
-msgid "ClusterIntegration|Kubernetes clusters can be used to deploy applications and to provide Review Apps for this project"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes version"
msgstr ""
@@ -5615,7 +5823,7 @@ msgstr ""
msgid "ClusterIntegration|Learn more about %{help_link_start}zones%{help_link_end}."
msgstr ""
-msgid "ClusterIntegration|Learn more about %{startLink}Regions %{externalLinkIcon}%{endLink}."
+msgid "ClusterIntegration|Learn more about %{linkStart}Regions%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Learn more about Kubernetes"
@@ -5660,12 +5868,18 @@ msgstr ""
msgid "ClusterIntegration|Machine type"
msgstr ""
+msgid "ClusterIntegration|Make sure your API endpoint is correct"
+msgstr ""
+
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create Kubernetes clusters"
msgstr ""
msgid "ClusterIntegration|Manage your Kubernetes cluster by visiting %{provider_link}"
msgstr ""
+msgid "ClusterIntegration|Namespace per environment"
+msgstr ""
+
msgid "ClusterIntegration|No IAM Roles found"
msgstr ""
@@ -5711,6 +5925,9 @@ msgstr ""
msgid "ClusterIntegration|No zones matched your search"
msgstr ""
+msgid "ClusterIntegration|Node calculations use the Kubernetes Metrics API. Make sure your cluster has metrics installed"
+msgstr ""
+
msgid "ClusterIntegration|Number of nodes"
msgstr ""
@@ -5753,6 +5970,9 @@ msgstr ""
msgid "ClusterIntegration|RBAC-enabled cluster"
msgstr ""
+msgid "ClusterIntegration|Read our %{linkStart}help page%{linkEnd} on Kubernetes cluster integration."
+msgstr ""
+
msgid "ClusterIntegration|Read our %{link_start}help page%{link_end} on Kubernetes cluster integration."
msgstr ""
@@ -5855,7 +6075,7 @@ msgstr ""
msgid "ClusterIntegration|Select a VPC to choose a subnet"
msgstr ""
-msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{linkStart}Amazon Web Services %{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select a network to choose a subnetwork"
@@ -5888,7 +6108,7 @@ msgstr ""
msgid "ClusterIntegration|Select project to choose zone"
msgstr ""
-msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select zone"
@@ -5978,9 +6198,18 @@ msgstr ""
msgid "ClusterIntegration|There was a problem authenticating with your cluster. Please ensure your CA Certificate and Token are valid."
msgstr ""
+msgid "ClusterIntegration|There was an HTTP error when connecting to your cluster."
+msgstr ""
+
msgid "ClusterIntegration|This account must have permissions to create a Kubernetes cluster in the %{link_to_container_project} specified below"
msgstr ""
+msgid "ClusterIntegration|This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
+msgstr ""
+
+msgid "ClusterIntegration|This is necessary to clear existing environment-namespace associations from clusters previously managed by GitLab."
+msgstr ""
+
msgid "ClusterIntegration|This option will allow you to install applications on RBAC clusters."
msgstr ""
@@ -6005,9 +6234,21 @@ msgstr ""
msgid "ClusterIntegration|To use a new project, first create one on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}."
msgstr ""
+msgid "ClusterIntegration|Troubleshooting tips:"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Authenticate"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Connect"
+msgstr ""
+
msgid "ClusterIntegration|Uninstall %{appTitle}"
msgstr ""
+msgid "ClusterIntegration|Unknown Error"
+msgstr ""
+
msgid "ClusterIntegration|Update %{appTitle}"
msgstr ""
@@ -6068,7 +6309,7 @@ msgstr ""
msgid "ClusterIntegration|Your cluster API is unreachable. Please ensure your API URL is correct."
msgstr ""
-msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Zone"
@@ -6188,6 +6429,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse all threads"
+msgstr ""
+
msgid "Collapse approvers"
msgstr ""
@@ -6337,7 +6581,7 @@ msgstr ""
msgid "Commit…"
msgstr ""
-msgid "Company"
+msgid "Community forum"
msgstr ""
msgid "Company name"
@@ -6346,6 +6590,9 @@ msgstr ""
msgid "Compare"
msgstr ""
+msgid "Compare %{oldCommitId}...%{newCommitId}"
+msgstr ""
+
msgid "Compare Git revisions"
msgstr ""
@@ -6361,6 +6608,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare submodule commit revisions"
+msgstr ""
+
msgid "Compare with previous version"
msgstr ""
@@ -6496,6 +6746,9 @@ msgstr ""
msgid "Configure the way a user creates a new account."
msgstr ""
+msgid "Configure which lists are shown for anyone who visits this board"
+msgstr ""
+
msgid "Confirm"
msgstr ""
@@ -6721,6 +6974,9 @@ msgstr[1] ""
msgid "ContainerRegistry|Set cleanup policy"
msgstr ""
+msgid "ContainerRegistry|Some tags were not deleted"
+msgstr ""
+
msgid "ContainerRegistry|Something went wrong while fetching the cleanup policy."
msgstr ""
@@ -6760,6 +7016,9 @@ msgstr ""
msgid "ContainerRegistry|Tags with names matching this regex pattern will %{italicStart}expire:%{italicEnd}"
msgstr ""
+msgid "ContainerRegistry|The cleanup policy timed out before it could delete all tags. An administrator can %{adminLinkStart}manually run cleanup now%{adminLinkEnd} or you can wait for the cleanup policy to automatically run again. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "ContainerRegistry|The last tag related to this image was recently removed. This empty image and any associated data will be automatically removed as part of the regular Garbage Collection process. If you have any questions, contact your administrator."
msgstr ""
@@ -6892,6 +7151,9 @@ msgstr ""
msgid "Contributions per group member"
msgstr ""
+msgid "Contributor"
+msgstr ""
+
msgid "Contributors"
msgstr ""
@@ -7021,6 +7283,9 @@ msgstr ""
msgid "Could not change HEAD: branch '%{branch}' does not exist"
msgstr ""
+msgid "Could not commit. An unexpected error occurred."
+msgstr ""
+
msgid "Could not connect to FogBugz, check your URL"
msgstr ""
@@ -7060,6 +7325,9 @@ msgstr ""
msgid "Could not find iteration"
msgstr ""
+msgid "Could not load instance counts. Please refresh the page to try again."
+msgstr ""
+
msgid "Could not remove the trigger."
msgstr ""
@@ -7084,10 +7352,10 @@ msgstr ""
msgid "Could not save prometheus manual configuration"
msgstr ""
-msgid "Could not udpdate wiki page"
+msgid "Could not update the LDAP settings"
msgstr ""
-msgid "Could not update the LDAP settings"
+msgid "Could not update wiki page"
msgstr ""
msgid "Could not upload your designs as one or more files uploaded are not supported."
@@ -7745,6 +8013,9 @@ msgstr ""
msgid "DastProfiles|Are you sure you want to delete this profile?"
msgstr ""
+msgid "DastProfiles|Could not create site validation token. Please refresh the page, or try again later."
+msgstr ""
+
msgid "DastProfiles|Could not create the scanner profile. Please try again."
msgstr ""
@@ -7769,6 +8040,12 @@ msgstr ""
msgid "DastProfiles|Could not fetch site profiles. Please refresh the page, or try again later."
msgstr ""
+msgid "DastProfiles|Could not retrieve site validation status. Please refresh the page, or try again later."
+msgstr ""
+
+msgid "DastProfiles|Could not update the scanner profile. Please try again."
+msgstr ""
+
msgid "DastProfiles|Could not update the site profile. Please try again."
msgstr ""
@@ -7784,7 +8061,7 @@ msgstr ""
msgid "DastProfiles|Download validation text file"
msgstr ""
-msgid "DastProfiles|Edit feature will come soon. Please create a new profile if changes needed"
+msgid "DastProfiles|Edit scanner profile"
msgstr ""
msgid "DastProfiles|Edit site profile"
@@ -7817,6 +8094,9 @@ msgstr ""
msgid "DastProfiles|No profiles created yet"
msgstr ""
+msgid "DastProfiles|Passive"
+msgstr ""
+
msgid "DastProfiles|Please enter a valid URL format, ex: http://www.example.com/home"
msgstr ""
@@ -7832,6 +8112,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan mode"
+msgstr ""
+
msgid "DastProfiles|Scanner Profile"
msgstr ""
@@ -7871,10 +8154,10 @@ msgstr ""
msgid "DastProfiles|Text file validation"
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
+msgid "DastProfiles|The maximum number of minutes allowed for the spider to traverse the site."
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the spider to traverse the site."
+msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
msgstr ""
msgid "DastProfiles|Validate"
@@ -7907,6 +8190,9 @@ msgstr ""
msgid "Date picker"
msgstr ""
+msgid "Date range"
+msgstr ""
+
msgid "Date range cannot exceed %{maxDateRange} days."
msgstr ""
@@ -7931,6 +8217,9 @@ msgstr ""
msgid "Days to merge"
msgstr ""
+msgid "Dear Administrator,"
+msgstr ""
+
msgid "Debug"
msgstr ""
@@ -8042,12 +8331,18 @@ msgstr ""
msgid "Delete"
msgstr ""
+msgid "Delete %{name}"
+msgstr ""
+
msgid "Delete Comment"
msgstr ""
msgid "Delete Snippet"
msgstr ""
+msgid "Delete Value Stream"
+msgstr ""
+
msgid "Delete account"
msgstr ""
@@ -8069,9 +8364,6 @@ msgstr ""
msgid "Delete label: %{label_name} ?"
msgstr ""
-msgid "Delete license"
-msgstr ""
-
msgid "Delete list"
msgstr ""
@@ -8147,15 +8439,6 @@ msgstr ""
msgid "Deleting a project places it into a read-only state until %{date}, at which point the project will be permanently deleted. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "Deleting the license failed."
-msgstr ""
-
-msgid "Deleting the license failed. The license was not found."
-msgstr ""
-
-msgid "Deleting the license failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "Deleting the project will delete its repository and all related resources including issues, merge requests etc."
msgstr ""
@@ -8651,7 +8934,10 @@ msgstr ""
msgid "DesignManagement|The maximum number of designs allowed to be uploaded is %{upload_limit}. Please try again."
msgstr ""
-msgid "DesignManagement|To upload designs, you'll need to enable LFS. %{requirements_link_start}More information%{requirements_link_end}"
+msgid "DesignManagement|There was an error moving your designs. Please upload your designs below."
+msgstr ""
+
+msgid "DesignManagement|To upload designs, you'll need to enable LFS and have admin enable hashed storage. %{requirements_link_start}More information%{requirements_link_end}"
msgstr ""
msgid "DesignManagement|Unresolve thread"
@@ -8663,6 +8949,9 @@ msgstr ""
msgid "DesignManagement|Upload skipped."
msgstr ""
+msgid "DesignManagement|Your designs are being copied and are on their way… Please refresh to update."
+msgstr ""
+
msgid "DesignManagement|and %{moreCount} more."
msgstr ""
@@ -8720,6 +9009,9 @@ msgstr ""
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
+msgid "Direct member"
+msgstr ""
+
msgid "Direction"
msgstr ""
@@ -8768,9 +9060,6 @@ msgstr ""
msgid "Discard draft"
msgstr ""
-msgid "Discard review"
-msgstr ""
-
msgid "DiscordService|Discord Notifications"
msgstr ""
@@ -8839,10 +9128,10 @@ msgstr ""
msgid "Dismiss Merge Request promotion"
msgstr ""
-msgid "Dismiss Selected"
+msgid "Dismiss Value Stream Analytics introduction box"
msgstr ""
-msgid "Dismiss Value Stream Analytics introduction box"
+msgid "Dismiss selected"
msgstr ""
msgid "Dismiss trial promotion"
@@ -8893,9 +9182,6 @@ msgstr ""
msgid "Documents reindexed: %{processed_documents} (%{percentage}%%)"
msgstr ""
-msgid "Doing"
-msgstr ""
-
msgid "Domain"
msgstr ""
@@ -9091,9 +9377,6 @@ msgstr ""
msgid "Edit environment"
msgstr ""
-msgid "Edit file"
-msgstr ""
-
msgid "Edit files in the editor and commit changes here"
msgstr ""
@@ -9106,6 +9389,12 @@ msgstr ""
msgid "Edit identity for %{user_name}"
msgstr ""
+msgid "Edit in Web IDE"
+msgstr ""
+
+msgid "Edit in single-file editor"
+msgstr ""
+
msgid "Edit issues"
msgstr ""
@@ -9133,10 +9422,10 @@ msgstr ""
msgid "Editing"
msgstr ""
-msgid "Elasticsearch"
+msgid "Elasticsearch AWS IAM credentials"
msgstr ""
-msgid "Elasticsearch AWS IAM credentials"
+msgid "Elasticsearch HTTP client timeout value in seconds."
msgstr ""
msgid "Elasticsearch indexing restrictions"
@@ -9145,9 +9434,6 @@ msgstr ""
msgid "Elasticsearch indexing started"
msgstr ""
-msgid "Elasticsearch integration. Elasticsearch AWS IAM."
-msgstr ""
-
msgid "Elasticsearch reindexing is already in progress"
msgstr ""
@@ -9175,9 +9461,6 @@ msgstr ""
msgid "Email Notification"
msgstr ""
-msgid "Email address"
-msgstr ""
-
msgid "Email could not be sent"
msgstr ""
@@ -9241,6 +9524,9 @@ msgstr ""
msgid "Emails sent from Service Desk will have this name"
msgstr ""
+msgid "Emails sent to %{email} will still be supported"
+msgstr ""
+
msgid "Emails separated by comma"
msgstr ""
@@ -9274,9 +9560,18 @@ msgstr ""
msgid "Enable"
msgstr ""
+msgid "Enable %{link_start}Gitpod%{link_end} integration to launch a development environment in your browser directly from GitLab."
+msgstr ""
+
msgid "Enable Auto DevOps"
msgstr ""
+msgid "Enable Gitpod"
+msgstr ""
+
+msgid "Enable Gitpod?"
+msgstr ""
+
msgid "Enable HTML emails"
msgstr ""
@@ -9406,9 +9701,6 @@ msgstr ""
msgid "Encountered an error while rendering: %{err}"
msgstr ""
-msgid "End date"
-msgstr ""
-
msgid "Ends at (UTC)"
msgstr ""
@@ -9568,7 +9860,7 @@ msgstr ""
msgid "EnvironmentsDashboard|The environments dashboard provides a summary of each project's environments' status, including pipeline and alert statuses."
msgstr ""
-msgid "EnvironmentsDashboard|This dashboard displays a maximum of 7 projects and 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
+msgid "EnvironmentsDashboard|This dashboard displays 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
msgstr ""
msgid "Environments|An error occurred while canceling the auto stop, please try again"
@@ -9889,6 +10181,9 @@ msgstr ""
msgid "Error deleting project. Check logs for error details."
msgstr ""
+msgid "Error fetching burnup chart data"
+msgstr ""
+
msgid "Error fetching diverging counts for branches. Please try again."
msgstr ""
@@ -9967,6 +10262,9 @@ msgstr ""
msgid "Error occurred when saving assignees"
msgstr ""
+msgid "Error occurred when saving reviewers"
+msgstr ""
+
msgid "Error occurred when toggling the notification subscription"
msgstr ""
@@ -10219,10 +10517,13 @@ msgstr ""
msgid "Expand all"
msgstr ""
-msgid "Expand approvers"
+msgid "Expand all files"
msgstr ""
-msgid "Expand dropdown"
+msgid "Expand all threads"
+msgstr ""
+
+msgid "Expand approvers"
msgstr ""
msgid "Expand milestones"
@@ -10393,6 +10694,9 @@ msgstr ""
msgid "Failed to create Merge Request. Please try again."
msgstr ""
+msgid "Failed to create To-Do for the design."
+msgstr ""
+
msgid "Failed to create a branch for this issue. Please try again."
msgstr ""
@@ -10432,6 +10736,12 @@ msgstr ""
msgid "Failed to load authors. Please try again."
msgstr ""
+msgid "Failed to load branches. Please try again."
+msgstr ""
+
+msgid "Failed to load deploy keys."
+msgstr ""
+
msgid "Failed to load emoji list."
msgstr ""
@@ -10447,6 +10757,9 @@ msgstr ""
msgid "Failed to load groups & users."
msgstr ""
+msgid "Failed to load groups, users and deploy keys."
+msgstr ""
+
msgid "Failed to load labels. Please try again."
msgstr ""
@@ -10456,6 +10769,12 @@ msgstr ""
msgid "Failed to load related branches"
msgstr ""
+msgid "Failed to load sidebar confidential toggle"
+msgstr ""
+
+msgid "Failed to load sidebar lock status"
+msgstr ""
+
msgid "Failed to load stacktrace."
msgstr ""
@@ -10483,6 +10802,9 @@ msgstr ""
msgid "Failed to publish issue on status page."
msgstr ""
+msgid "Failed to remove To-Do for the design."
+msgstr ""
+
msgid "Failed to remove a Zoom meeting"
msgstr ""
@@ -10525,6 +10847,9 @@ msgstr ""
msgid "Failed to signing using smartcard authentication"
msgstr ""
+msgid "Failed to toggle To-Do for the design."
+msgstr ""
+
msgid "Failed to update branch!"
msgstr ""
@@ -10638,7 +10963,7 @@ msgstr ""
msgid "FeatureFlags|Edit User List"
msgstr ""
-msgid "FeatureFlags|Enable features for specific users and specific environments by defining feature flag strategies."
+msgid "FeatureFlags|Enable features for specific users and environments by configuring feature flag strategies."
msgstr ""
msgid "FeatureFlags|Environment Spec"
@@ -10698,7 +11023,7 @@ msgstr ""
msgid "FeatureFlags|Include additional user IDs"
msgstr ""
-msgid "FeatureFlags|Install a %{docs_link_anchored_start}compatible client library%{docs_link_anchored_end} and specify the API URL, application name, and instance ID during the configuration setup. %{docs_link_start}More Information%{docs_link_end}"
+msgid "FeatureFlags|Install a %{docsLinkAnchoredStart}compatible client library%{docsLinkAnchoredEnd} and specify the API URL, application name, and instance ID during the configuration setup. %{docsLinkStart}More Information%{docsLinkEnd}"
msgstr ""
msgid "FeatureFlags|Instance ID"
@@ -10710,6 +11035,9 @@ msgstr ""
msgid "FeatureFlags|Loading feature flags"
msgstr ""
+msgid "FeatureFlags|Loading user lists"
+msgstr ""
+
msgid "FeatureFlags|More information"
msgstr ""
@@ -10728,7 +11056,7 @@ msgstr ""
msgid "FeatureFlags|New feature flag"
msgstr ""
-msgid "FeatureFlags|New list"
+msgid "FeatureFlags|New user list"
msgstr ""
msgid "FeatureFlags|Percent of users"
@@ -10767,6 +11095,9 @@ msgstr ""
msgid "FeatureFlags|There was an error fetching the feature flags."
msgstr ""
+msgid "FeatureFlags|There was an error fetching the user lists."
+msgstr ""
+
msgid "FeatureFlags|There was an error retrieving user lists"
msgstr ""
@@ -10782,6 +11113,9 @@ msgstr ""
msgid "FeatureFlags|User List"
msgstr ""
+msgid "FeatureFlags|User Lists"
+msgstr ""
+
msgid "FeatureFlag|List"
msgstr ""
@@ -10809,15 +11143,6 @@ msgstr ""
msgid "Fetching incoming email"
msgstr ""
-msgid "Fetching licenses failed."
-msgstr ""
-
-msgid "Fetching licenses failed. The request endpoint was not found."
-msgstr ""
-
-msgid "Fetching licenses failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "File"
msgstr ""
@@ -10920,12 +11245,21 @@ msgstr ""
msgid "Filter by status"
msgstr ""
+msgid "Filter by test cases that are currently archived."
+msgstr ""
+
+msgid "Filter by test cases that are currently opened."
+msgstr ""
+
msgid "Filter by two-factor authentication"
msgstr ""
msgid "Filter by user"
msgstr ""
+msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
+msgstr ""
+
msgid "Filter pipelines"
msgstr ""
@@ -10941,7 +11275,7 @@ msgstr ""
msgid "Filter results..."
msgstr ""
-msgid "Filter your projects by name"
+msgid "Filter your repositories by name"
msgstr ""
msgid "Filter..."
@@ -10950,7 +11284,7 @@ msgstr ""
msgid "Find File"
msgstr ""
-msgid "Find bugs in your code with coverage-guided fuzzing"
+msgid "Find bugs in your code with coverage-guided fuzzing."
msgstr ""
msgid "Find by path"
@@ -10977,9 +11311,6 @@ msgstr ""
msgid "Finish editing this message first!"
msgstr ""
-msgid "Finish review"
-msgstr ""
-
msgid "Finish setting up your dedicated account for %{group_name}."
msgstr ""
@@ -11049,6 +11380,9 @@ msgstr ""
msgid "Footer message"
msgstr ""
+msgid "For a faster browsing experience, some files are collapsed by default."
+msgstr ""
+
msgid "For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
@@ -11058,6 +11392,9 @@ msgstr ""
msgid "For more info, read the documentation."
msgstr ""
+msgid "For more information on how the number of active users is calculated, see the %{self_managed_subscriptions_doc_link} documentation."
+msgstr ""
+
msgid "For more information, go to the "
msgstr ""
@@ -11196,6 +11533,9 @@ msgstr ""
msgid "Generate new token"
msgstr ""
+msgid "Generic package file size in bytes"
+msgstr ""
+
msgid "Geo"
msgstr ""
@@ -11457,6 +11797,9 @@ msgstr ""
msgid "Geo|Please refer to Geo Troubleshooting."
msgstr ""
+msgid "Geo|Primary node"
+msgstr ""
+
msgid "Geo|Project"
msgstr ""
@@ -11499,6 +11842,9 @@ msgstr ""
msgid "Geo|Review replication status, and resynchronize and reverify items with the primary node."
msgstr ""
+msgid "Geo|Secondary node"
+msgstr ""
+
msgid "Geo|Status"
msgstr ""
@@ -11538,6 +11884,9 @@ msgstr ""
msgid "Geo|URL must be a valid url (ex: https://gitlab.com)"
msgstr ""
+msgid "Geo|Undefined"
+msgstr ""
+
msgid "Geo|Unknown state"
msgstr ""
@@ -11613,10 +11962,16 @@ msgstr ""
msgid "GitHub import"
msgstr ""
+msgid "GitLab"
+msgstr ""
+
msgid "GitLab / Unsubscribe"
msgstr ""
-msgid "GitLab Enterprise Edition %{plan}"
+msgid "GitLab API"
+msgstr ""
+
+msgid "GitLab Billing Team."
msgstr ""
msgid "GitLab Group Runners can execute code for all the projects in this group."
@@ -11628,12 +11983,18 @@ msgstr ""
msgid "GitLab Issue"
msgstr ""
+msgid "GitLab Pages"
+msgstr ""
+
msgid "GitLab Service Desk is a simple way to allow people to create issues in your GitLab instance without needing their own user account. It provides a unique email address for end users to create issues in a project, and replies can be sent either through the GitLab interface or by email. End users will only see the thread through email."
msgstr ""
msgid "GitLab Shared Runners execute code of different projects on the same Runner unless you configure GitLab Runner Autoscale with MaxBuilds 1 (which it is on GitLab.com)."
msgstr ""
+msgid "GitLab Shell"
+msgstr ""
+
msgid "GitLab Support Bot"
msgstr ""
@@ -11643,7 +12004,7 @@ msgstr ""
msgid "GitLab User"
msgstr ""
-msgid "GitLab allows you to continue using your license even if you exceed the number of seats you purchased. You will be required to pay for these seats when you renew your license."
+msgid "GitLab Workhorse"
msgstr ""
msgid "GitLab commit"
@@ -11811,6 +12172,21 @@ msgstr ""
msgid "Gitlab Pages"
msgstr ""
+msgid "Gitpod"
+msgstr ""
+
+msgid "Gitpod|Add the URL to your Gitpod instance configured to read your GitLab projects."
+msgstr ""
+
+msgid "Gitpod|Enable Gitpod integration"
+msgstr ""
+
+msgid "Gitpod|Gitpod URL"
+msgstr ""
+
+msgid "Gitpod|e.g. https://gitpod.example.com"
+msgstr ""
+
msgid "Given access %{time_ago}"
msgstr ""
@@ -12318,9 +12694,6 @@ msgstr ""
msgid "GroupSAML|Valid SAML Response"
msgstr ""
-msgid "GroupSAML|With group managed accounts enabled, all the users without a group managed account will be excluded from the group."
-msgstr ""
-
msgid "GroupSAML|With prohibit outer forks flag enabled group members will be able to fork project only inside your group."
msgstr ""
@@ -12534,10 +12907,10 @@ msgstr ""
msgid "GroupsNew|Create group"
msgstr ""
-msgid "GroupsNew|GitLab group export"
+msgid "GroupsNew|Import"
msgstr ""
-msgid "GroupsNew|Import"
+msgid "GroupsNew|Import a GitLab group export file"
msgstr ""
msgid "GroupsNew|Import group"
@@ -12680,6 +13053,9 @@ msgid_plural "Hide charts"
msgstr[0] ""
msgstr[1] ""
+msgid "Hide comments on this file"
+msgstr ""
+
msgid "Hide details"
msgstr ""
@@ -12724,6 +13100,15 @@ msgstr ""
msgid "Highest role:"
msgstr ""
+msgid "HighlightBar|Alert events:"
+msgstr ""
+
+msgid "HighlightBar|Alert start time:"
+msgstr ""
+
+msgid "HighlightBar|Original alert:"
+msgstr ""
+
msgid "History"
msgstr ""
@@ -12901,6 +13286,9 @@ msgstr ""
msgid "If enabled, access to projects will be validated on an external service using their classification label."
msgstr ""
+msgid "If the number of active users exceeds the user limit, you will be charged for the number of %{users_over_license_link} at your next license reconciliation."
+msgstr ""
+
msgid "If there is no previous license or if the previous license has expired, some GitLab functionality will be blocked until a new, valid license is uploaded."
msgstr ""
@@ -12940,9 +13328,6 @@ msgstr ""
msgid "If your HTTP repository is not publicly accessible, add your credentials."
msgstr ""
-msgid "Iglu registry URL (optional)"
-msgstr ""
-
msgid "Ignore"
msgstr ""
@@ -12979,6 +13364,16 @@ msgstr ""
msgid "Import"
msgstr ""
+msgid "Import %d compatible repository"
+msgid_plural "Import %d compatible repositories"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Import %d repository"
+msgid_plural "Import %d repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Import CSV"
msgstr ""
@@ -12988,15 +13383,9 @@ msgstr ""
msgid "Import all compatible projects"
msgstr ""
-msgid "Import all compatible repositories"
-msgstr ""
-
msgid "Import all projects"
msgstr ""
-msgid "Import all repositories"
-msgstr ""
-
msgid "Import an exported GitLab project"
msgstr ""
@@ -13084,6 +13473,9 @@ msgstr ""
msgid "ImportProjects|Error importing repository %{project_safe_import_url} into %{project_full_path} - %{message}"
msgstr ""
+msgid "ImportProjects|Import repositories"
+msgstr ""
+
msgid "ImportProjects|Importing the project failed"
msgstr ""
@@ -13096,7 +13488,7 @@ msgstr ""
msgid "ImportProjects|Requesting your %{provider} repositories failed"
msgstr ""
-msgid "ImportProjects|Select the projects you want to import"
+msgid "ImportProjects|Select the repositories you want to import"
msgstr ""
msgid "ImportProjects|The remote data could not be imported."
@@ -13132,9 +13524,6 @@ msgstr ""
msgid "In order to enable Service Desk for your instance, you must first set up incoming email."
msgstr ""
-msgid "In order to gather accurate feature usage data, it can take 1 to 2 weeks to see your index."
-msgstr ""
-
msgid "In order to personalize your experience with GitLab%{br_tag}we would like to know a bit more about you."
msgstr ""
@@ -13165,18 +13554,30 @@ msgstr ""
msgid "IncidentManagement|Create incident"
msgstr ""
+msgid "IncidentManagement|Critical - S1"
+msgstr ""
+
msgid "IncidentManagement|Date created"
msgstr ""
msgid "IncidentManagement|Display your incidents in a dedicated view"
msgstr ""
+msgid "IncidentManagement|High - S2"
+msgstr ""
+
msgid "IncidentManagement|Incident"
msgstr ""
msgid "IncidentManagement|Incidents"
msgstr ""
+msgid "IncidentManagement|Low - S4"
+msgstr ""
+
+msgid "IncidentManagement|Medium - S3"
+msgstr ""
+
msgid "IncidentManagement|No incidents to display."
msgstr ""
@@ -13189,6 +13590,9 @@ msgstr ""
msgid "IncidentManagement|Published to status page"
msgstr ""
+msgid "IncidentManagement|Severity"
+msgstr ""
+
msgid "IncidentManagement|There are no closed incidents"
msgstr ""
@@ -13198,6 +13602,9 @@ msgstr ""
msgid "IncidentManagement|Unassigned"
msgstr ""
+msgid "IncidentManagement|Unknown"
+msgstr ""
+
msgid "IncidentManagement|Unpublished"
msgstr ""
@@ -13219,6 +13626,15 @@ msgstr ""
msgid "Incidents"
msgstr ""
+msgid "Incident|Alert details"
+msgstr ""
+
+msgid "Incident|Summary"
+msgstr ""
+
+msgid "Incident|There was an issue loading alert data. Please try again."
+msgstr ""
+
msgid "Include a Terms of Service agreement and Privacy Policy that all users must accept."
msgstr ""
@@ -13279,6 +13695,9 @@ msgstr ""
msgid "Information about additional Pages templates and how to install them can be found in our %{pages_getting_started_guide}."
msgstr ""
+msgid "Inherited"
+msgstr ""
+
msgid "Inherited:"
msgstr ""
@@ -13359,7 +13778,22 @@ msgstr ""
msgid "Instance administrators group already exists"
msgstr ""
-msgid "Instance license"
+msgid "InstanceStatistics|Groups"
+msgstr ""
+
+msgid "InstanceStatistics|Issues"
+msgstr ""
+
+msgid "InstanceStatistics|Merge Requests"
+msgstr ""
+
+msgid "InstanceStatistics|Pipelines"
+msgstr ""
+
+msgid "InstanceStatistics|Projects"
+msgstr ""
+
+msgid "InstanceStatistics|Users"
msgstr ""
msgid "Integration"
@@ -13371,6 +13805,12 @@ msgstr ""
msgid "Integrations"
msgstr ""
+msgid "Integrations|%{integration} settings saved and active."
+msgstr ""
+
+msgid "Integrations|%{integration} settings saved, but not active."
+msgstr ""
+
msgid "Integrations|All details"
msgstr ""
@@ -13380,6 +13820,12 @@ msgstr ""
msgid "Integrations|Comment settings:"
msgstr ""
+msgid "Integrations|Connection failed. Please check your settings."
+msgstr ""
+
+msgid "Integrations|Connection successful."
+msgstr ""
+
msgid "Integrations|Default settings are inherited from the group level."
msgstr ""
@@ -13395,6 +13841,15 @@ msgstr ""
msgid "Integrations|Includes commit title and branch"
msgstr ""
+msgid "Integrations|Projects using custom settings will not be impacted unless the project owner chooses to use instance-level defaults."
+msgstr ""
+
+msgid "Integrations|Save settings?"
+msgstr ""
+
+msgid "Integrations|Saving will update the default settings for all projects that are not using custom settings."
+msgstr ""
+
msgid "Integrations|Standard"
msgstr ""
@@ -13527,6 +13982,9 @@ msgstr ""
msgid "Invitation"
msgstr ""
+msgid "Invitation declined"
+msgstr ""
+
msgid "Invite"
msgstr ""
@@ -13578,6 +14036,42 @@ 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|%{linkStart}Read more%{linkEnd} about role permissions"
+msgstr ""
+
+msgid "InviteMembersModal|Access expiration date (optional)"
+msgstr ""
+
+msgid "InviteMembersModal|Cancel"
+msgstr ""
+
+msgid "InviteMembersModal|Choose a role permission"
+msgstr ""
+
+msgid "InviteMembersModal|GitLab member or Email address"
+msgstr ""
+
+msgid "InviteMembersModal|Invite"
+msgstr ""
+
+msgid "InviteMembersModal|Invite team members"
+msgstr ""
+
+msgid "InviteMembersModal|Search for members to invite"
+msgstr ""
+
+msgid "InviteMembersModal|User not invited. Feature coming soon!"
+msgstr ""
+
+msgid "InviteMembersModal|Users were succesfully added"
+msgstr ""
+
+msgid "InviteMembersModal|You're inviting members to the %{group_name} group"
+msgstr ""
+
+msgid "InviteMembers|Invite team members"
+msgstr ""
+
msgid "Invited"
msgstr ""
@@ -13632,10 +14126,13 @@ msgstr ""
msgid "Issue cannot be found."
msgstr ""
+msgid "Issue created from vulnerability %{vulnerability_link}"
+msgstr ""
+
msgid "Issue events"
msgstr ""
-msgid "Issue first depoloyed to production"
+msgid "Issue first deployed to production"
msgstr ""
msgid "Issue label"
@@ -13713,6 +14210,9 @@ msgstr ""
msgid "IssueTracker|Custom issue tracker"
msgstr ""
+msgid "IssueTracker|EWM work items tracker"
+msgstr ""
+
msgid "IssueTracker|Redmine issue tracker"
msgstr ""
@@ -13779,6 +14279,9 @@ msgstr ""
msgid "It looks like you have some draft commits in this branch."
msgstr ""
+msgid "It may be several days before you see feature usage data."
+msgstr ""
+
msgid "It must have a header row and at least two columns: the first column is the issue title and the second column is the issue description. The separator is automatically detected."
msgstr ""
@@ -14061,13 +14564,13 @@ msgstr ""
msgid "Join Zoom meeting"
msgstr ""
-msgid "Jul"
+msgid "Joined %{time_ago}"
msgstr ""
-msgid "July"
+msgid "Jul"
msgstr ""
-msgid "Jump to first unresolved thread"
+msgid "July"
msgstr ""
msgid "Jump to next unresolved thread"
@@ -14103,6 +14606,9 @@ msgstr ""
msgid "Keyboard shortcuts"
msgstr ""
+msgid "KeyboardKey|Ctrl+"
+msgstr ""
+
msgid "Keys"
msgstr ""
@@ -14151,6 +14657,9 @@ msgstr ""
msgid "LDAP Synchronization"
msgstr ""
+msgid "LDAP group settings"
+msgstr ""
+
msgid "LDAP settings"
msgstr ""
@@ -14160,6 +14669,9 @@ msgstr ""
msgid "LDAP sync in progress. This could take a few minutes. Refresh the page to see the changes."
msgstr ""
+msgid "LDAP synchronizations"
+msgstr ""
+
msgid "LFS"
msgstr ""
@@ -14240,7 +14752,16 @@ msgid_plural "Last %d days"
msgstr[0] ""
msgstr[1] ""
-msgid "Last %{days} days"
+msgid "Last 2 weeks"
+msgstr ""
+
+msgid "Last 30 days"
+msgstr ""
+
+msgid "Last 60 days"
+msgstr ""
+
+msgid "Last 90 days"
msgstr ""
msgid "Last Accessed On"
@@ -14318,6 +14839,9 @@ msgstr ""
msgid "Last used on:"
msgstr ""
+msgid "Last week"
+msgstr ""
+
msgid "LastCommit|authored"
msgstr ""
@@ -14333,6 +14857,9 @@ msgstr ""
msgid "Latest pipeline for the most recent commit on this branch"
msgstr ""
+msgid "Launch a ready-to-code development environment for your project."
+msgstr ""
+
msgid "Lead"
msgstr ""
@@ -14713,6 +15240,9 @@ msgstr ""
msgid "List of all merge commits"
msgstr ""
+msgid "List options"
+msgstr ""
+
msgid "List settings"
msgstr ""
@@ -14725,9 +15255,6 @@ msgstr ""
msgid "List your Bitbucket Server repositories"
msgstr ""
-msgid "Lists"
-msgstr ""
-
msgid "Live preview"
msgstr ""
@@ -14974,6 +15501,12 @@ msgstr ""
msgid "Mark as done"
msgstr ""
+msgid "Mark as draft"
+msgstr ""
+
+msgid "Mark as ready"
+msgstr ""
+
msgid "Mark as resolved"
msgstr ""
@@ -14995,6 +15528,24 @@ msgstr ""
msgid "Markdown is supported"
msgstr ""
+msgid "MarkdownEditor|Add a link (%{modifierKey}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add a link (%{modifier_key}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifierKey}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifier_key}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifierKey}I)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifier_key}I)"
+msgstr ""
+
msgid "Marked For Deletion At - %{deletion_time}"
msgstr ""
@@ -15079,7 +15630,25 @@ msgstr ""
msgid "Max access level"
msgstr ""
-msgid "Max seats used"
+msgid "Max role"
+msgstr ""
+
+msgid "Max size 15 MB"
+msgstr ""
+
+msgid "Maximum Conan package file size in bytes"
+msgstr ""
+
+msgid "Maximum Maven package file size in bytes"
+msgstr ""
+
+msgid "Maximum NPM package file size in bytes"
+msgstr ""
+
+msgid "Maximum NuGet package file size in bytes"
+msgstr ""
+
+msgid "Maximum PyPI package file size in bytes"
msgstr ""
msgid "Maximum Users:"
@@ -15211,6 +15780,18 @@ msgstr ""
msgid "Members with access to %{strong_start}%{group_name}%{strong_end}"
msgstr ""
+msgid "Members|%{time} by %{user}"
+msgstr ""
+
+msgid "Members|Expired"
+msgstr ""
+
+msgid "Members|No expiration set"
+msgstr ""
+
+msgid "Members|in %{time}"
+msgstr ""
+
msgid "Memory Usage"
msgstr ""
@@ -15397,9 +15978,6 @@ msgstr ""
msgid "MergeRequests|Thread will be unresolved"
msgstr ""
-msgid "MergeRequests|Toggle comments for this file"
-msgstr ""
-
msgid "MergeRequests|View file @ %{commitId}"
msgstr ""
@@ -15460,6 +16038,9 @@ msgstr ""
msgid "Merging immediately isn't recommended as it may negatively impact the existing merge train. Read the %{docsLinkStart}documentation%{docsLinkEnd} for more information."
msgstr ""
+msgid "Message"
+msgstr ""
+
msgid "Messages"
msgstr ""
@@ -15845,18 +16426,12 @@ msgid_plural "Milestones"
msgstr[0] ""
msgstr[1] ""
-msgid "Milestone does not support burnup charts"
-msgstr ""
-
msgid "Milestone lists not available with your current license"
msgstr ""
msgid "Milestone lists show all issues from the selected milestone."
msgstr ""
-msgid "Milestone must have a start and due date"
-msgstr ""
-
msgid "MilestoneSidebar|Closed:"
msgstr ""
@@ -16223,6 +16798,9 @@ msgstr ""
msgid "Namespace"
msgstr ""
+msgid "Namespace ID:"
+msgstr ""
+
msgid "Namespace is empty"
msgstr ""
@@ -16307,6 +16885,9 @@ msgstr ""
msgid "NetworkPolicies|Allow all outbound traffic from %{selector} to %{ruleSelector} on %{ports}"
msgstr ""
+msgid "NetworkPolicies|Are you sure you want to delete this policy? This action cannot be undone."
+msgstr ""
+
msgid "NetworkPolicies|Choose whether to enforce this policy."
msgstr ""
@@ -16316,12 +16897,21 @@ msgstr ""
msgid "NetworkPolicies|Define this policy's location, conditions and actions."
msgstr ""
+msgid "NetworkPolicies|Delete policy"
+msgstr ""
+
+msgid "NetworkPolicies|Delete policy: %{policy}"
+msgstr ""
+
msgid "NetworkPolicies|Deny all traffic"
msgstr ""
msgid "NetworkPolicies|Description"
msgstr ""
+msgid "NetworkPolicies|Edit policy"
+msgstr ""
+
msgid "NetworkPolicies|Editor mode"
msgstr ""
@@ -16349,6 +16939,9 @@ msgstr ""
msgid "NetworkPolicies|Name"
msgstr ""
+msgid "NetworkPolicies|Namespace"
+msgstr ""
+
msgid "NetworkPolicies|Network Policy"
msgstr ""
@@ -16400,6 +16993,9 @@ msgstr ""
msgid "NetworkPolicies|Rules"
msgstr ""
+msgid "NetworkPolicies|Save changes"
+msgstr ""
+
msgid "NetworkPolicies|Something went wrong, failed to update policy"
msgstr ""
@@ -16412,6 +17008,9 @@ msgstr ""
msgid "NetworkPolicies|Traffic that does not match any rule will be blocked."
msgstr ""
+msgid "NetworkPolicies|Unable to parse policy"
+msgstr ""
+
msgid "NetworkPolicies|YAML editor"
msgstr ""
@@ -16525,6 +17124,9 @@ msgstr ""
msgid "New Snippet"
msgstr ""
+msgid "New Test Case"
+msgstr ""
+
msgid "New User"
msgstr ""
@@ -16624,6 +17226,9 @@ msgstr ""
msgid "New tag"
msgstr ""
+msgid "New test case"
+msgstr ""
+
msgid "New users set to external"
msgstr ""
@@ -16696,7 +17301,7 @@ msgstr ""
msgid "No changes"
msgstr ""
-msgid "No changes between %{ref_start}%{source_branch}%{ref_end} and %{ref_start}%{target_branch}%{ref_end}"
+msgid "No changes between %{sourceBranch} and %{targetBranch}"
msgstr ""
msgid "No child epics match applied filters"
@@ -16711,6 +17316,9 @@ msgstr ""
msgid "No containers available"
msgstr ""
+msgid "No content to show"
+msgstr ""
+
msgid "No contributions"
msgstr ""
@@ -16786,9 +17394,6 @@ msgstr ""
msgid "No license. All rights reserved"
msgstr ""
-msgid "No licenses found."
-msgstr ""
-
msgid "No matches found"
msgstr ""
@@ -16801,6 +17406,9 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No members found"
+msgstr ""
+
msgid "No merge requests found"
msgstr ""
@@ -16822,6 +17430,9 @@ msgstr ""
msgid "No parent group"
msgstr ""
+msgid "No plan"
+msgstr ""
+
msgid "No pods available"
msgstr ""
@@ -16918,6 +17529,12 @@ msgstr ""
msgid "Not Implemented"
msgstr ""
+msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+msgstr ""
+
+msgid "Not all browsers support WebAuthn. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even from an unsupported browser."
+msgstr ""
+
msgid "Not all data has been processed yet, the accuracy of the chart for the selected timeframe is limited."
msgstr ""
@@ -17014,6 +17631,9 @@ msgstr ""
msgid "Notification settings saved"
msgstr ""
+msgid "NotificationEvent|Change reviewer merge request"
+msgstr ""
+
msgid "NotificationEvent|Close issue"
msgstr ""
@@ -17176,10 +17796,7 @@ msgstr ""
msgid "On track"
msgstr ""
-msgid "OnDemandScans|Attached branch"
-msgstr ""
-
-msgid "OnDemandScans|Attached branch is where the scan job runs."
+msgid "OnDemandScans|Could not fetch scanner profiles. Please refresh the page, or try again later."
msgstr ""
msgid "OnDemandScans|Could not fetch site profiles. Please refresh the page, or try again later."
@@ -17188,6 +17805,9 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
+msgid "OnDemandScans|Create a new scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Create a new site profile"
msgstr ""
@@ -17200,6 +17820,9 @@ msgstr ""
msgid "OnDemandScans|New on-demand DAST scan"
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 ""
@@ -17209,16 +17832,10 @@ msgstr ""
msgid "OnDemandScans|On-demand scans run outside the DevOps cycle and find vulnerabilities in your projects. %{learnMoreLinkStart}Learn more%{learnMoreLinkEnd}"
msgstr ""
-msgid "OnDemandScans|Only a passive scan can be performed on demand."
-msgstr ""
-
-msgid "OnDemandScans|Passive"
-msgstr ""
-
msgid "OnDemandScans|Run scan"
msgstr ""
-msgid "OnDemandScans|Scan mode"
+msgid "OnDemandScans|Scanner profile"
msgstr ""
msgid "OnDemandScans|Scanner settings"
@@ -17230,9 +17847,15 @@ msgstr ""
msgid "OnDemandScans|Select one of the existing profiles"
msgstr ""
+msgid "OnDemandScans|Site profile"
+msgstr ""
+
msgid "OnDemandScans|Site profiles"
msgstr ""
+msgid "OnDemandScans|Use existing scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Use existing site profile"
msgstr ""
@@ -17331,9 +17954,6 @@ msgstr ""
msgid "Open Selection"
msgstr ""
-msgid "Open Web IDE"
-msgstr ""
-
msgid "Open comment type dropdown"
msgstr ""
@@ -17439,6 +18059,9 @@ msgstr ""
msgid "Origin"
msgstr ""
+msgid "Orphaned member"
+msgstr ""
+
msgid "Other Labels"
msgstr ""
@@ -17454,6 +18077,9 @@ msgstr ""
msgid "Other visibility settings have been disabled by the administrator."
msgstr ""
+msgid "Our documentation includes an example DevOps Score report."
+msgstr ""
+
msgid "Out-of-compliance with this project's policies and should be removed"
msgstr ""
@@ -17478,6 +18104,9 @@ msgstr ""
msgid "Overwrite diverged branches"
msgstr ""
+msgid "Owned by %{image_tag}"
+msgstr ""
+
msgid "Owned by anyone"
msgstr ""
@@ -17499,6 +18128,9 @@ msgstr ""
msgid "Package deleted successfully"
msgstr ""
+msgid "Package file size limits"
+msgstr ""
+
msgid "Package recipe already exists"
msgstr ""
@@ -17514,9 +18146,6 @@ msgstr ""
msgid "Package type must be PyPi"
msgstr ""
-msgid "Package was removed"
-msgstr ""
-
msgid "PackageRegistry|%{name} version %{version} was created %{datetime}"
msgstr ""
@@ -17658,12 +18287,18 @@ msgstr ""
msgid "PackageRegistry|NuGet Command"
msgstr ""
+msgid "PackageRegistry|Package Registry"
+msgstr ""
+
msgid "PackageRegistry|Pip Command"
msgstr ""
msgid "PackageRegistry|Pipeline %{link} triggered %{datetime} by %{author}"
msgstr ""
+msgid "PackageRegistry|Publish and share packages for a variety of common package managers. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "PackageRegistry|Published to the %{project} Package Registry %{datetime}"
msgstr ""
@@ -17763,6 +18398,9 @@ msgstr ""
msgid "Page not found"
msgstr ""
+msgid "Page settings"
+msgstr ""
+
msgid "Page was successfully deleted"
msgstr ""
@@ -17904,7 +18542,7 @@ msgstr ""
msgid "Paste issue link"
msgstr ""
-msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Don't use your private SSH key."
+msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Do not paste your private SSH key, as that can compromise your identity."
msgstr ""
msgid "Patch to apply"
@@ -17931,6 +18569,9 @@ msgstr ""
msgid "Pending"
msgstr ""
+msgid "Pending comments"
+msgstr ""
+
msgid "People without permission will never get a notification and won't be able to comment."
msgstr ""
@@ -18129,6 +18770,9 @@ msgstr ""
msgid "Pipelines|Build with confidence"
msgstr ""
+msgid "Pipelines|By revoking a trigger you will break any processes making use of it. Are you sure?"
+msgstr ""
+
msgid "Pipelines|CI Lint"
msgstr ""
@@ -18141,6 +18785,15 @@ msgstr ""
msgid "Pipelines|Continuous Integration can help catch bugs by running your tests automatically, while Continuous Deployment can help you deliver code to your product environment."
msgstr ""
+msgid "Pipelines|Copy trigger token"
+msgstr ""
+
+msgid "Pipelines|Description"
+msgstr ""
+
+msgid "Pipelines|Edit"
+msgstr ""
+
msgid "Pipelines|Get started with Pipelines"
msgstr ""
@@ -18156,15 +18809,27 @@ msgstr ""
msgid "Pipelines|It is recommended the code is reviewed thoroughly before running this pipeline with the parent project's CI resource."
msgstr ""
+msgid "Pipelines|Last Used"
+msgstr ""
+
msgid "Pipelines|Loading Pipelines"
msgstr ""
msgid "Pipelines|More Information"
msgstr ""
+msgid "Pipelines|No triggers have been created yet. Add one using the form above."
+msgstr ""
+
+msgid "Pipelines|Owner"
+msgstr ""
+
msgid "Pipelines|Project cache successfully reset."
msgstr ""
+msgid "Pipelines|Revoke"
+msgstr ""
+
msgid "Pipelines|Run Pipeline"
msgstr ""
@@ -18189,6 +18854,15 @@ msgstr ""
msgid "Pipelines|This project is not currently set up to run pipelines."
msgstr ""
+msgid "Pipelines|Token"
+msgstr ""
+
+msgid "Pipelines|Trigger user has insufficient permissions to project"
+msgstr ""
+
+msgid "Pipelines|invalid"
+msgstr ""
+
msgid "Pipelines|parent"
msgstr ""
@@ -18447,10 +19121,10 @@ msgstr ""
msgid "Please provide attributes to update"
msgstr ""
-msgid "Please refer to %{docs_url}"
+msgid "Please reach out if you have any questions and we'll be happy to assist."
msgstr ""
-msgid "Please retype the email address."
+msgid "Please refer to %{docs_url}"
msgstr ""
msgid "Please select"
@@ -18480,6 +19154,9 @@ msgstr ""
msgid "Please set a new password before proceeding."
msgstr ""
+msgid "Please share your feedback about %{featureName} %{linkStart}in this issue%{linkEnd} to help us improve the experience."
+msgstr ""
+
msgid "Please solve the reCAPTCHA"
msgstr ""
@@ -18783,6 +19460,9 @@ msgstr ""
msgid "Profiles| You are going to change the username %{currentUsernameBold} to %{newUsernameBold}. Profile and projects will be redirected to the %{newUsername} namespace but this redirect will expire once the %{currentUsername} namespace is registered by another user or group. Please update your Git repository remotes as soon as possible."
msgstr ""
+msgid "Profiles|%{provider} Active"
+msgstr ""
+
msgid "Profiles|@username"
msgstr ""
@@ -18834,7 +19514,7 @@ msgstr ""
msgid "Profiles|Commit email"
msgstr ""
-msgid "Profiles|Connect"
+msgid "Profiles|Connect %{provider}"
msgstr ""
msgid "Profiles|Connected Accounts"
@@ -18858,6 +19538,9 @@ msgstr ""
msgid "Profiles|Disconnect"
msgstr ""
+msgid "Profiles|Disconnect %{provider}"
+msgstr ""
+
msgid "Profiles|Do not show on profile"
msgstr ""
@@ -18882,7 +19565,7 @@ msgstr ""
msgid "Profiles|Full name"
msgstr ""
-msgid "Profiles|Give your individual key a title. This will be publically visible."
+msgid "Profiles|Give your individual key a title."
msgstr ""
msgid "Profiles|Include private contributions on my profile"
@@ -18972,7 +19655,7 @@ msgstr ""
msgid "Profiles|The maximum file size allowed is 200KB."
msgstr ""
-msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it?"
+msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it? It will be publicly visible."
msgstr ""
msgid "Profiles|This email will be displayed on your public profile"
@@ -19047,6 +19730,9 @@ msgstr ""
msgid "Profiles|You don't have access to delete this user."
msgstr ""
+msgid "Profiles|You must transfer ownership or delete groups you are an owner of before you can delete your account"
+msgstr ""
+
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
@@ -19635,6 +20321,9 @@ msgstr ""
msgid "ProjectTemplates|GitLab Cluster Management"
msgstr ""
+msgid "ProjectTemplates|Gitpod/Spring Petclinic"
+msgstr ""
+
msgid "ProjectTemplates|Go Micro"
msgstr ""
@@ -20244,6 +20933,9 @@ msgstr ""
msgid "Publish to status page"
msgstr ""
+msgid "Published"
+msgstr ""
+
msgid "Published on status page"
msgstr ""
@@ -20361,9 +21053,15 @@ msgstr ""
msgid "Quick range"
msgstr ""
+msgid "Quickly and easily edit multiple files in your project."
+msgstr ""
+
msgid "README"
msgstr ""
+msgid "Rails"
+msgstr ""
+
msgid "Rake Tasks Help"
msgstr ""
@@ -20483,10 +21181,13 @@ msgstr ""
msgid "Register Two-Factor Authenticator"
msgstr ""
-msgid "Register U2F device"
+msgid "Register Universal Two-Factor (U2F) Device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register WebAuthn Device"
+msgstr ""
+
+msgid "Register device"
msgstr ""
msgid "Register for GitLab"
@@ -20498,9 +21199,6 @@ msgstr ""
msgid "Register with two-factor app"
msgstr ""
-msgid "Registration"
-msgstr ""
-
msgid "Registration|Checkout"
msgstr ""
@@ -20617,9 +21315,6 @@ msgstr ""
msgid "Release|Something went wrong while saving the release details"
msgstr ""
-msgid "Remediated: needs review"
-msgstr ""
-
msgid "Remediations"
msgstr ""
@@ -20725,6 +21420,9 @@ msgstr ""
msgid "Remove priority"
msgstr ""
+msgid "Remove report"
+msgstr ""
+
msgid "Remove secondary node"
msgstr ""
@@ -20737,6 +21435,12 @@ msgstr ""
msgid "Remove time estimate"
msgstr ""
+msgid "Remove user & report"
+msgstr ""
+
+msgid "Remove user from group"
+msgstr ""
+
msgid "Removed"
msgstr ""
@@ -20818,9 +21522,6 @@ msgstr ""
msgid "Removes time estimate."
msgstr ""
-msgid "Removing license…"
-msgstr ""
-
msgid "Removing this group also removes all child projects, including archived projects, and their resources."
msgstr ""
@@ -20905,6 +21606,9 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
+msgid "Reported by %{reporter}"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -20991,6 +21695,27 @@ msgstr ""
msgid "Repositories"
msgstr ""
+msgid "Repositories Analytics"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download Historic Test Coverage Data"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download historic test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Historic Test Coverage Data is available in raw format (.csv) for further analysis."
+msgstr ""
+
+msgid "RepositoriesAnalytics|Test Code Coverage"
+msgstr ""
+
+msgid "RepositoriesAnalytics|There was an error fetching the projects."
+msgstr ""
+
msgid "Repository"
msgstr ""
@@ -21069,9 +21794,15 @@ msgstr ""
msgid "Request parameter %{param} is missing."
msgstr ""
+msgid "Request review from"
+msgstr ""
+
msgid "Request to link SAML account must be authorized"
msgstr ""
+msgid "Requested"
+msgstr ""
+
msgid "Requested %{time_ago}"
msgstr ""
@@ -21090,6 +21821,9 @@ msgstr ""
msgid "Requests to these domain(s)/address(es) on the local network will be allowed when local requests from hooks and services are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 or 127.0.0.0/28 are supported. Domain wildcards are not supported currently. Use comma, semicolon, or newline to separate multiple entries. The allowlist can hold a maximum of 1000 entries. Domains should use IDNA encoding. Ex: example.com, 192.168.1.1, 127.0.0.0/28, xn--itlab-j1a.com."
msgstr ""
+msgid "Require admin approval for new sign-ups"
+msgstr ""
+
msgid "Require all users in this group to setup Two-factor authentication"
msgstr ""
@@ -21217,9 +21951,6 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
-msgid "Resolved by %{resolvedByName}"
-msgstr ""
-
msgid "Resolves IP addresses once and uses them to submit requests"
msgstr ""
@@ -21339,6 +22070,14 @@ msgstr ""
msgid "ReviewApp|Enable Review App"
msgstr ""
+msgid "Reviewer"
+msgid_plural "%d Reviewers"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Reviewer(s)"
+msgstr ""
+
msgid "Reviewing"
msgstr ""
@@ -21378,6 +22117,9 @@ msgstr ""
msgid "Rook"
msgstr ""
+msgid "Ruby"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -21456,6 +22198,63 @@ msgstr ""
msgid "Runners page."
msgstr ""
+msgid "Runners|Active"
+msgstr ""
+
+msgid "Runners|Architecture"
+msgstr ""
+
+msgid "Runners|Can run untagged jobs"
+msgstr ""
+
+msgid "Runners|Description"
+msgstr ""
+
+msgid "Runners|Group"
+msgstr ""
+
+msgid "Runners|IP Address"
+msgstr ""
+
+msgid "Runners|Last contact"
+msgstr ""
+
+msgid "Runners|Locked to this project"
+msgstr ""
+
+msgid "Runners|Maximum job timeout"
+msgstr ""
+
+msgid "Runners|Name"
+msgstr ""
+
+msgid "Runners|Platform"
+msgstr ""
+
+msgid "Runners|Property Name"
+msgstr ""
+
+msgid "Runners|Protected"
+msgstr ""
+
+msgid "Runners|Revision"
+msgstr ""
+
+msgid "Runners|Shared"
+msgstr ""
+
+msgid "Runners|Specific"
+msgstr ""
+
+msgid "Runners|Tags"
+msgstr ""
+
+msgid "Runners|Value"
+msgstr ""
+
+msgid "Runners|Version"
+msgstr ""
+
msgid "Runners|You have used %{quotaUsed} out of %{quotaLimit} of your shared Runners pipeline minutes."
msgstr ""
@@ -21468,6 +22267,9 @@ msgstr ""
msgid "Runs a number of housekeeping tasks within the current repository, such as compressing file revisions and removing unreachable objects."
msgstr ""
+msgid "SAML"
+msgstr ""
+
msgid "SAML SSO"
msgstr ""
@@ -21519,6 +22321,9 @@ msgstr ""
msgid "Save"
msgstr ""
+msgid "Save %{name} size limits"
+msgstr ""
+
msgid "Save Changes"
msgstr ""
@@ -21549,9 +22354,6 @@ msgstr ""
msgid "Save space and find tags in the Container Registry more easily. Enable the cleanup policy to remove stale tags and keep only the ones you need."
msgstr ""
-msgid "Save template"
-msgstr ""
-
msgid "Save variables"
msgstr ""
@@ -21594,9 +22396,6 @@ msgstr ""
msgid "Scope"
msgstr ""
-msgid "Scope not supported with disabled 'users_search' feature!"
-msgstr ""
-
msgid "Scoped issue boards"
msgstr ""
@@ -21723,9 +22522,6 @@ msgstr ""
msgid "Search requirements"
msgstr ""
-msgid "Search results…"
-msgstr ""
-
msgid "Search users"
msgstr ""
@@ -21798,6 +22594,11 @@ msgid_plural "SearchResults|commits"
msgstr[0] ""
msgstr[1] ""
+msgid "SearchResults|epic"
+msgid_plural "SearchResults|epics"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "SearchResults|issue"
msgid_plural "SearchResults|issues"
msgstr[0] ""
@@ -21842,10 +22643,10 @@ msgstr ""
msgid "Seat Link is disabled, and cannot be configured through this form."
msgstr ""
-msgid "Seats currently in use"
+msgid "Seats usage data as of %{last_enqueue_time}"
msgstr ""
-msgid "Seats in license"
+msgid "Seats usage data is updated every day at 12:00pm UTC"
msgstr ""
msgid "Secondary"
@@ -21899,6 +22700,9 @@ msgstr ""
msgid "SecurityConfiguration|Available for on-demand DAST"
msgstr ""
+msgid "SecurityConfiguration|By default, all analyzers are applied in order to cover all languages across your project, and only run if the language is detected in the Merge Request."
+msgstr ""
+
msgid "SecurityConfiguration|Configure"
msgstr ""
@@ -21929,16 +22733,19 @@ msgstr ""
msgid "SecurityConfiguration|Manage"
msgstr ""
+msgid "SecurityConfiguration|More information"
+msgstr ""
+
msgid "SecurityConfiguration|Not enabled"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|Security Control"
+msgid "SecurityConfiguration|SAST Configuration"
msgstr ""
-msgid "SecurityConfiguration|See documentation"
+msgid "SecurityConfiguration|Security Control"
msgstr ""
msgid "SecurityConfiguration|Status"
@@ -21950,6 +22757,9 @@ msgstr ""
msgid "SecurityConfiguration|Using custom settings. You won't receive automatic updates on this variable. %{anchorStart}Restore to default%{anchorEnd}"
msgstr ""
+msgid "SecurityConfiguration|View history"
+msgstr ""
+
msgid "SecurityConfiguration|You can quickly enable all security scanning tools by enabling %{linkStart}Auto DevOps%{linkEnd}."
msgstr ""
@@ -22028,9 +22838,6 @@ msgstr ""
msgid "SecurityReports|Learn more about setting up your dashboard"
msgstr ""
-msgid "SecurityReports|Load more vulnerabilities"
-msgstr ""
-
msgid "SecurityReports|Monitor vulnerabilities in your code"
msgstr ""
@@ -22310,7 +23117,7 @@ msgstr ""
msgid "Select status"
msgstr ""
-msgid "Select strategy activation method"
+msgid "Select strategy activation method."
msgstr ""
msgid "Select subscription"
@@ -22325,7 +23132,7 @@ msgstr ""
msgid "Select the custom project template source group."
msgstr ""
-msgid "Select timeframe"
+msgid "Select the environment scope for this feature flag."
msgstr ""
msgid "Select timezone"
@@ -22574,6 +23381,9 @@ msgstr ""
msgid "Set iteration"
msgstr ""
+msgid "Set limit to 0 to allow any file size."
+msgstr ""
+
msgid "Set max session time for web terminal."
msgstr ""
@@ -22652,10 +23462,13 @@ msgstr ""
msgid "Set up a %{type} Runner manually"
msgstr ""
+msgid "Set up a hardware device as a second factor to sign in."
+msgstr ""
+
msgid "Set up assertions/attributes/claims (email, first_name, last_name) and NameID according to %{docsLinkStart}the documentation %{icon}%{docsLinkEnd}"
msgstr ""
-msgid "Set up new U2F device"
+msgid "Set up new device"
msgstr ""
msgid "Set up new password"
@@ -22724,6 +23537,9 @@ msgstr ""
msgid "Sets weight to %{weight}."
msgstr ""
+msgid "Setting this to 0 means using the system default timeout value."
+msgstr ""
+
msgid "Settings"
msgstr ""
@@ -22739,6 +23555,15 @@ msgstr ""
msgid "Severity"
msgstr ""
+msgid "SeverityWidget|Severity"
+msgstr ""
+
+msgid "SeverityWidget|Severity: %{severity}"
+msgstr ""
+
+msgid "SeverityWidget|There was an error while updating severity."
+msgstr ""
+
msgid "Shards (%{shards})"
msgstr ""
@@ -22784,6 +23609,9 @@ msgstr ""
msgid "Show all requirements."
msgstr ""
+msgid "Show all test cases."
+msgstr ""
+
msgid "Show archived projects"
msgstr ""
@@ -22796,6 +23624,9 @@ msgstr ""
msgid "Show comments"
msgstr ""
+msgid "Show comments on this file"
+msgstr ""
+
msgid "Show comments only"
msgstr ""
@@ -22841,6 +23672,12 @@ msgstr ""
msgid "Show parent subgroups"
msgstr ""
+msgid "Show the Closed list"
+msgstr ""
+
+msgid "Show the Open list"
+msgstr ""
+
msgid "Show whitespace changes"
msgstr ""
@@ -22884,9 +23721,6 @@ msgstr ""
msgid "Sidebar|Assign health status"
msgstr ""
-msgid "Sidebar|Change weight"
-msgstr ""
-
msgid "Sidebar|Health status"
msgstr ""
@@ -23070,6 +23904,9 @@ msgstr ""
msgid "Snippets|Add another file %{num}/%{total}"
msgstr ""
+msgid "Snippets|Authored %{time_ago} by %{author}"
+msgstr ""
+
msgid "Snippets|Delete file"
msgstr ""
@@ -23097,6 +23934,9 @@ msgstr ""
msgid "Solution"
msgstr ""
+msgid "Some changes are not shown"
+msgstr ""
+
msgid "Some child epics may be hidden due to applied filters"
msgstr ""
@@ -23463,6 +24303,12 @@ msgstr ""
msgid "Source (branch or tag)"
msgstr ""
+msgid "Source Branch"
+msgstr ""
+
+msgid "Source branch: %{source_branch_open}%{source_branch}%{source_branch_close}"
+msgstr ""
+
msgid "Source code"
msgstr ""
@@ -23628,9 +24474,6 @@ msgstr ""
msgid "Start and due date"
msgstr ""
-msgid "Start by choosing a group to see how your team is spending time. You can then drill down to the project level."
-msgstr ""
-
msgid "Start by choosing a group to start exploring the merge requests in that group. You can then proceed to filter by projects, labels, milestones and authors."
msgstr ""
@@ -23712,18 +24555,27 @@ msgstr ""
msgid "StaticSiteEditor|3. Assign a person to review and accept the merge request."
msgstr ""
+msgid "StaticSiteEditor|A link to view the merge request will appear once ready."
+msgstr ""
+
msgid "StaticSiteEditor|An error occurred while submitting your changes."
msgstr ""
msgid "StaticSiteEditor|Branch could not be created."
msgstr ""
+msgid "StaticSiteEditor|Copy update"
+msgstr ""
+
msgid "StaticSiteEditor|Could not commit the content changes."
msgstr ""
msgid "StaticSiteEditor|Could not create merge request."
msgstr ""
+msgid "StaticSiteEditor|Creating your merge request"
+msgstr ""
+
msgid "StaticSiteEditor|Incompatible file content"
msgstr ""
@@ -23745,6 +24597,9 @@ msgstr ""
msgid "StaticSiteEditor|View documentation"
msgstr ""
+msgid "StaticSiteEditor|You can set an assignee to get your changes reviewed and deployed once your merge request is created."
+msgstr ""
+
msgid "StaticSiteEditor|Your merge request has been created"
msgstr ""
@@ -23874,15 +24729,15 @@ msgstr ""
msgid "Submit %{humanized_resource_name}"
msgstr ""
-msgid "Submit Changes"
-msgstr ""
-
msgid "Submit a review"
msgstr ""
msgid "Submit as spam"
msgstr ""
+msgid "Submit changes"
+msgstr ""
+
msgid "Submit feedback"
msgstr ""
@@ -24036,6 +24891,9 @@ msgstr ""
msgid "Successfully deleted U2F device."
msgstr ""
+msgid "Successfully deleted WebAuthn device."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -24354,9 +25212,6 @@ msgstr ""
msgid "Template to append to all Service Desk issues"
msgstr ""
-msgid "Template was successfully saved."
-msgstr ""
-
msgid "Templates"
msgstr ""
@@ -24435,10 +25290,28 @@ msgid_plural "Test coverage: %d hits"
msgstr[0] ""
msgstr[1] ""
-msgid "Test failed."
+msgid "Test settings"
msgstr ""
-msgid "Test settings and save changes"
+msgid "TestCases|New Test Case"
+msgstr ""
+
+msgid "TestCases|New test case"
+msgstr ""
+
+msgid "TestCases|Search test cases"
+msgstr ""
+
+msgid "TestCases|Something went wrong while creating a test case."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching count of test cases."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching test cases list."
+msgstr ""
+
+msgid "TestCases|Submit test case"
msgstr ""
msgid "TestHooks|Ensure one of your projects has merge requests."
@@ -24504,6 +25377,9 @@ msgstr ""
msgid "Thank you for signing up for your free trial! You will get additional instructions in your inbox shortly."
msgstr ""
+msgid "Thank you for your business."
+msgstr ""
+
msgid "Thank you for your feedback!"
msgstr ""
@@ -24563,9 +25439,6 @@ msgstr ""
msgid "The URL to use for connecting to Elasticsearch. Use a comma-separated list to support clustering (e.g., \"http://localhost:9200, http://localhost:9201\")."
msgstr ""
-msgid "The Web IDE offers advanced syntax highlighting capabilities and more."
-msgstr ""
-
msgid "The X509 Certificate to use when mutual TLS is required to communicate with the external authorization service. If left blank, the server certificate is still validated when accessing over HTTPS."
msgstr ""
@@ -24676,6 +25549,9 @@ msgstr ""
msgid "The form contains the following error:"
msgstr ""
+msgid "The form contains the following warning:"
+msgstr ""
+
msgid "The global settings require you to enable Two-Factor Authentication for your account."
msgstr ""
@@ -24790,9 +25666,6 @@ msgstr ""
msgid "The private key to use when a client certificate is provided. This value is encrypted at rest."
msgstr ""
-msgid "The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The project can be accessed by any logged in user."
msgstr ""
@@ -24829,7 +25702,7 @@ msgstr ""
msgid "The remote repository is being updated..."
msgstr ""
-msgid "The repository can be commited to, and issues, comments and other entities can be created."
+msgid "The repository can be committed to, and issues, comments and other entities can be created."
msgstr ""
msgid "The repository for this project does not exist."
@@ -24883,9 +25756,6 @@ msgstr ""
msgid "The time taken by each data entry gathered by that stage."
msgstr ""
-msgid "The total stage shows the time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The update action will time out after %{number_of_minutes} minutes. For big repositories, use a clone/push combination."
msgstr ""
@@ -24949,6 +25819,9 @@ msgstr ""
msgid "There are no archived requirements"
msgstr ""
+msgid "There are no archived test cases"
+msgstr ""
+
msgid "There are no changes"
msgstr ""
@@ -24988,6 +25861,9 @@ msgstr ""
msgid "There are no open requirements"
msgstr ""
+msgid "There are no open test cases"
+msgstr ""
+
msgid "There are no packages yet"
msgstr ""
@@ -25000,6 +25876,9 @@ msgstr ""
msgid "There is a limit of %{ci_project_subscriptions_limit} subscriptions from or to a project."
msgstr ""
+msgid "There is already a To-Do for this design."
+msgstr ""
+
msgid "There is already a repository with that name on disk"
msgstr ""
@@ -25018,6 +25897,9 @@ msgstr ""
msgid "There was a problem communicating with your device."
msgstr ""
+msgid "There was a problem fetching branches."
+msgstr ""
+
msgid "There was a problem fetching groups."
msgstr ""
@@ -25246,9 +26128,15 @@ msgstr ""
msgid "This action can lead to data loss. To prevent accidental actions we ask you to confirm your intention."
msgstr ""
+msgid "This action cannot be undone, and will permanently delete the %{key} SSH key"
+msgstr ""
+
msgid "This action cannot be undone. You will lose the project's repository and all content: issues, merge requests, etc."
msgstr ""
+msgid "This action has been performed too many times. Try again later."
+msgstr ""
+
msgid "This action will %{strongOpen}permanently delete%{strongClose} %{codeOpen}%{project}%{codeClose} %{strongOpen}immediately%{strongClose}, including its repositories and all content: issues, merge requests, etc."
msgstr ""
@@ -25276,9 +26164,6 @@ msgstr ""
msgid "This board's scope is reduced"
msgstr ""
-msgid "This branch has changed since you started editing. Would you like to create a new branch?"
-msgstr ""
-
msgid "This chart could not be displayed"
msgstr ""
@@ -25405,15 +26290,9 @@ msgstr ""
msgid "This is a security log of important events involving your account."
msgstr ""
-msgid "This is the author's first Merge Request to this project."
-msgstr ""
-
msgid "This is the highest peak of users on your installation since the license started."
msgstr ""
-msgid "This is the maximum number of users that have existed at the same time since the license started. This is the minimum number of seats you will need to buy when you renew your license."
-msgstr ""
-
msgid "This is the number of currently active users on your installation, and this is the minimum number you need to purchase when you renew your license."
msgstr ""
@@ -25645,6 +26524,15 @@ msgstr ""
msgid "This user has no identities"
msgstr ""
+msgid "This user has previously committed to the %{name} project."
+msgstr ""
+
+msgid "This user has the %{access} role in the %{name} project."
+msgstr ""
+
+msgid "This user is the author of this %{noteable}."
+msgstr ""
+
msgid "This user will be the author of all events in the activity feed that are the result of an update, like new branches being created or new commits being pushed to existing branches."
msgstr ""
@@ -25675,6 +26563,9 @@ msgstr ""
msgid "Threat Monitoring"
msgstr ""
+msgid "ThreatMonitoring|All Environments"
+msgstr ""
+
msgid "ThreatMonitoring|Anomalous Requests"
msgstr ""
@@ -25702,9 +26593,6 @@ msgstr ""
msgid "ThreatMonitoring|Operations Per Second"
msgstr ""
-msgid "ThreatMonitoring|Overview"
-msgstr ""
-
msgid "ThreatMonitoring|Packet Activity"
msgstr ""
@@ -25723,6 +26611,9 @@ msgstr ""
msgid "ThreatMonitoring|Something went wrong, unable to fetch statistics"
msgstr ""
+msgid "ThreatMonitoring|Statistics"
+msgstr ""
+
msgid "ThreatMonitoring|The firewall is not installed or has been disabled. To view this data, ensure the web application firewall is installed and enabled for your cluster."
msgstr ""
@@ -26114,6 +27005,9 @@ msgstr ""
msgid "To update Snippets with multiple files, you must use the `files` parameter"
msgstr ""
+msgid "To use Gitpod you must first enable the feature in the integrations section of your %{user_prefs}."
+msgstr ""
+
msgid "To view all %{scannedResourcesCount} scanned URLs, please download the CSV file"
msgstr ""
@@ -26147,9 +27041,6 @@ msgstr ""
msgid "Toggle Sidebar"
msgstr ""
-msgid "Toggle all threads"
-msgstr ""
-
msgid "Toggle backtrace"
msgstr ""
@@ -26174,9 +27065,6 @@ msgstr ""
msgid "Toggle navigation"
msgstr ""
-msgid "Toggle project"
-msgstr ""
-
msgid "Toggle sidebar"
msgstr ""
@@ -26216,6 +27104,9 @@ msgstr ""
msgid "Too many projects enabled. You will need to manage them via the console or the API."
msgstr ""
+msgid "Too much data"
+msgstr ""
+
msgid "Topics (optional)"
msgstr ""
@@ -26234,6 +27125,9 @@ msgstr ""
msgid "Total cores (CPUs)"
msgstr ""
+msgid "Total days to completion"
+msgstr ""
+
msgid "Total issues"
msgstr ""
@@ -26330,6 +27224,9 @@ msgstr ""
msgid "Trending"
msgstr ""
+msgid "Trials|Create a new group to start your GitLab Gold trial."
+msgstr ""
+
msgid "Trials|Go back to GitLab"
msgstr ""
@@ -26339,6 +27236,15 @@ msgstr ""
msgid "Trials|You can always resume this process by selecting your avatar and choosing 'Start a Gold trial'"
msgstr ""
+msgid "Trials|You can apply your trial to a new group or an existing group."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group or your personal account."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group, an existing group, or your personal account."
+msgstr ""
+
msgid "Trials|You won't get a free trial right now but you can always resume this process by clicking on your avatar and choosing 'Start a free trial'"
msgstr ""
@@ -26408,6 +27314,9 @@ msgstr ""
msgid "Try using a different search term to find the file you are looking for."
msgstr ""
+msgid "Trying to communicate with your device. Plug it in (if needed) and press the button on the device now."
+msgstr ""
+
msgid "Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now."
msgstr ""
@@ -26495,6 +27404,12 @@ msgstr ""
msgid "URL or request ID"
msgstr ""
+msgid "USER %{user} WILL BE REMOVED! Are you sure?"
+msgstr ""
+
+msgid "USER WILL BE BLOCKED! Are you sure?"
+msgstr ""
+
msgid "UTC"
msgstr ""
@@ -26552,9 +27467,6 @@ msgstr ""
msgid "Unable to load the merge request widget. Try reloading the page."
msgstr ""
-msgid "Unable to resolve"
-msgstr ""
-
msgid "Unable to save iteration. Please try again"
msgstr ""
@@ -26603,6 +27515,9 @@ msgstr ""
msgid "Undo ignore"
msgstr ""
+msgid "Unexpected error"
+msgstr ""
+
msgid "Unfortunately, your email message to GitLab could not be processed."
msgstr ""
@@ -26636,6 +27551,9 @@ msgstr ""
msgid "Unknown response text"
msgstr ""
+msgid "Unless otherwise agreed to in writing with GitLab, by clicking \"Upload License\" you agree that your use of GitLab Software is subject to the %{eula_link_start}Terms of Service%{eula_link_end}."
+msgstr ""
+
msgid "Unlimited"
msgstr ""
@@ -27002,9 +27920,6 @@ msgstr ""
msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
msgstr ""
-msgid "Use a hardware device to add the second factor of authentication."
-msgstr ""
-
msgid "Use an one time password authenticator on your mobile device or computer to enable two-factor authentication (2FA)."
msgstr ""
@@ -27278,13 +28193,13 @@ msgstr ""
msgid "Users"
msgstr ""
-msgid "Users in License:"
+msgid "Users in License"
msgstr ""
-msgid "Users or groups set as approvers in the project's or merge request's settings."
+msgid "Users in License:"
msgstr ""
-msgid "Users outside of license"
+msgid "Users or groups set as approvers in the project's or merge request's settings."
msgstr ""
msgid "Users over License:"
@@ -27302,9 +28217,6 @@ msgstr ""
msgid "Users with a Guest role or those who don't belong to a Project or Group will not use a seat from your license."
msgstr ""
-msgid "Users with a Guest role or those who don't belong to any projects or groups don't count towards seats in use."
-msgstr ""
-
msgid "UsersSelect|%{name} + %{length} more"
msgstr ""
@@ -27344,9 +28256,6 @@ msgstr ""
msgid "Validations failed."
msgstr ""
-msgid "Validity"
-msgstr ""
-
msgid "Value"
msgstr ""
@@ -27365,6 +28274,9 @@ msgstr ""
msgid "Value Stream Name"
msgstr ""
+msgid "ValueStreamAnalyticsStage|We don't have enough data to show this stage."
+msgstr ""
+
msgid "ValueStreamAnalytics|%{days}d"
msgstr ""
@@ -27621,6 +28533,9 @@ msgstr ""
msgid "VisualReviewApp|Steps 1 and 2 (and sometimes 3) are performed once by the developer before requesting feedback. Steps 3 (if necessary), 4 is performed by the reviewer each time they perform a review."
msgstr ""
+msgid "Visualization"
+msgstr ""
+
msgid "Vulnerabilities"
msgstr ""
@@ -27648,34 +28563,31 @@ msgstr ""
msgid "VulnerabilityChart|Severity"
msgstr ""
-msgid "VulnerabilityManagement|A true-positive and will fix"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Change status"
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|Confirm"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Confirmed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
-msgstr ""
-
-msgid "VulnerabilityManagement|Detected %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|A true-positive and will fix"
msgstr ""
-msgid "VulnerabilityManagement|Dismiss"
+msgid "VulnerabilityManagement|Change status"
msgstr ""
-msgid "VulnerabilityManagement|Dismissed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
msgstr ""
-msgid "VulnerabilityManagement|Resolved"
+msgid "VulnerabilityManagement|Detected"
msgstr ""
-msgid "VulnerabilityManagement|Resolved %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Needs triage"
msgstr ""
msgid "VulnerabilityManagement|Something went wrong while trying to delete the comment. Please try again later."
@@ -27726,6 +28638,9 @@ msgstr ""
msgid "Vulnerability|%{scannerName} (version %{scannerVersion})"
msgstr ""
+msgid "Vulnerability|Activity"
+msgstr ""
+
msgid "Vulnerability|Class"
msgstr ""
@@ -27738,6 +28653,9 @@ msgstr ""
msgid "Vulnerability|Description"
msgstr ""
+msgid "Vulnerability|Detected"
+msgstr ""
+
msgid "Vulnerability|Evidence"
msgstr ""
@@ -27801,6 +28719,9 @@ msgstr ""
msgid "Warning: Displaying this diagram might cause performance issues on this page."
msgstr ""
+msgid "We are currently unable to fetch data for the pipeline header."
+msgstr ""
+
msgid "We are currently unable to fetch data for this graph."
msgstr ""
@@ -27840,6 +28761,12 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
+msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
+msgstr ""
+
+msgid "We would like to inform you that your subscription GitLab Enterprise Edition %{plan_name} is nearing its user limit. You have %{active_user_count} active users, which is almost at the user limit of %{maximum_user_count}."
+msgstr ""
+
msgid "We've found no vulnerabilities"
msgstr ""
@@ -27855,6 +28782,12 @@ msgstr ""
msgid "Web terminal"
msgstr ""
+msgid "WebAuthn Devices (%{length})"
+msgstr ""
+
+msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
+msgstr ""
+
msgid "WebIDE|Merge request"
msgstr ""
@@ -27993,15 +28926,9 @@ msgstr ""
msgid "Welcome to the guided GitLab tour"
msgstr ""
-msgid "Welcome to your Issue Board!"
-msgstr ""
-
msgid "Welcome to your issue board!"
msgstr ""
-msgid "We’ve been making changes to %{featureName} and we’d love your feedback %{linkStart}in this issue%{linkEnd} to help us improve the experience."
-msgstr ""
-
msgid "What are you searching for?"
msgstr ""
@@ -28020,6 +28947,9 @@ msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
msgstr ""
+msgid "When enabled, any user visiting %{host} and creating an account will have to be explicitly approved by the admin before they can login. This setting is effective only if sign-ups are enabled."
+msgstr ""
+
msgid "When enabled, any user visiting %{host} will be able to create an account."
msgstr ""
@@ -28244,6 +29174,9 @@ msgstr ""
msgid "With requirements, you can set criteria to check your products against."
msgstr ""
+msgid "With test cases, you can define conditions for your project to meet in determining quality"
+msgstr ""
+
msgid "Withdraw Access Request"
msgstr ""
@@ -28259,6 +29192,9 @@ msgstr ""
msgid "Workflow Help"
msgstr ""
+msgid "Would you like to create a new branch?"
+msgstr ""
+
msgid "Write"
msgstr ""
@@ -28280,6 +29216,9 @@ msgstr ""
msgid "Wrong extern UID provided. Make sure Auth0 is configured correctly."
msgstr ""
+msgid "YYYY-MM-DD"
+msgstr ""
+
msgid "Yes"
msgstr ""
@@ -28337,7 +29276,7 @@ msgstr ""
msgid "You are going to remove the fork relationship from %{project_full_name}. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "You are going to transfer %{project_full_name} to another owner. Are you ABSOLUTELY sure?"
+msgid "You are going to transfer %{project_full_name} to another namespace. Are you ABSOLUTELY sure?"
msgstr ""
msgid "You are going to turn off the confidentiality. This means %{strongStart}everyone%{strongEnd} will be able to see and leave a comment on this %{issuableType}."
@@ -28397,9 +29336,6 @@ msgstr ""
msgid "You can always edit this later"
msgstr ""
-msgid "You can apply your Trial to your Personal account or create a New Group."
-msgstr ""
-
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings"
msgstr ""
@@ -28421,12 +29357,18 @@ msgstr ""
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
+msgid "You can find more information about GitLab subscriptions in %{subscriptions_doc_link}."
+msgstr ""
+
msgid "You can generate an access token scoped to this project for each application to use the GitLab API."
msgstr ""
msgid "You can get started by cloning the repository or start adding files to it with one of the following options."
msgstr ""
+msgid "You can group test cases using labels. To learn about the future direction of this feature, visit %{linkStart}Quality Management direction page%{linkEnd}."
+msgstr ""
+
msgid "You can invite a new member to %{project_name} or invite another group."
msgstr ""
@@ -28442,6 +29384,9 @@ msgstr ""
msgid "You can notify the app / group or a project by sending them an email notification"
msgstr ""
+msgid "You can now close this window."
+msgstr ""
+
msgid "You can now export your security dashboard to a CSV report."
msgstr ""
@@ -28490,9 +29435,6 @@ msgstr ""
msgid "You can test your .gitlab-ci.yml in %{linkStart}CI Lint%{linkEnd}."
msgstr ""
-msgid "You can try again using %{begin_link}basic search%{end_link}"
-msgstr ""
-
msgid "You cannot access the raw file. Please wait a minute."
msgstr ""
@@ -28544,6 +29486,9 @@ msgstr ""
msgid "You don't have any U2F devices registered yet."
msgstr ""
+msgid "You don't have any WebAuthn devices registered yet."
+msgstr ""
+
msgid "You don't have any active chat names."
msgstr ""
@@ -28631,6 +29576,9 @@ msgstr ""
msgid "You must accept our Terms of Service and privacy policy in order to register an account"
msgstr ""
+msgid "You must be logged in to search across all of GitLab"
+msgstr ""
+
msgid "You must disassociate %{domain} from all clusters it is attached to before deletion."
msgstr ""
@@ -28670,7 +29618,7 @@ msgstr ""
msgid "You need to be logged in."
msgstr ""
-msgid "You need to register a two-factor authentication app before you can set up a U2F device."
+msgid "You need to register a two-factor authentication app before you can set up a device."
msgstr ""
msgid "You need to set terms to be enforced"
@@ -28688,6 +29636,9 @@ msgstr ""
msgid "You reached %{usage_in_percent} of %{namespace_name}'s storage capacity (%{used_storage} of %{storage_limit})"
msgstr ""
+msgid "You successfully declined the invitation"
+msgstr ""
+
msgid "You tried to fork %{link_to_the_project} but it failed for the following reason:"
msgstr ""
@@ -28853,10 +29804,13 @@ msgstr ""
msgid "Your U2F device did not send a valid JSON response."
msgstr ""
-msgid "Your U2F device needs to be set up. Plug it in (if not already) and click the button on the left."
+msgid "Your U2F device was registered!"
msgstr ""
-msgid "Your U2F device was registered!"
+msgid "Your WebAuthn device did not send a valid JSON response."
+msgstr ""
+
+msgid "Your WebAuthn device was registered!"
msgstr ""
msgid "Your access request to the %{source_type} has been withdrawn."
@@ -28880,6 +29834,9 @@ msgstr ""
msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
msgstr ""
+msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
+msgstr ""
+
msgid "Your changes can be committed to %{branch_name} because a merge request is open."
msgstr ""
@@ -28916,6 +29873,12 @@ msgstr ""
msgid "Your deployment services will be broken, you will need to manually fix the services after renaming."
msgstr ""
+msgid "Your device is not compatible with GitLab. Please try another device"
+msgstr ""
+
+msgid "Your device needs to be set up. Plug it in (if needed) and click the button on the left."
+msgstr ""
+
msgid "Your device was successfully set up! Give it a name and register it with the GitLab server."
msgstr ""
@@ -29029,9 +29992,6 @@ msgstr[1] ""
msgid "access:"
msgstr ""
-msgid "activated"
-msgstr ""
-
msgid "added %{created_at_timeago}"
msgstr ""
@@ -29104,9 +30064,21 @@ msgstr ""
msgid "by %{user}"
msgstr ""
+msgid "cannot be a date in the past"
+msgstr ""
+
msgid "cannot be changed if a personal project has container registry tags."
msgstr ""
+msgid "cannot be changed if shared runners are enabled"
+msgstr ""
+
+msgid "cannot be enabled because parent group does not allow it"
+msgstr ""
+
+msgid "cannot be enabled because parent group has shared Runners disabled"
+msgstr ""
+
msgid "cannot be enabled unless all domains have TLS certificates"
msgstr ""
@@ -29152,7 +30124,7 @@ msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about SAST %{linkEndTag}"
msgstr ""
-msgid "ciReport|%{linkStartTag}Learn more about Secret Scanning %{linkEndTag}"
+msgid "ciReport|%{linkStartTag}Learn more about Secret Detection %{linkEndTag}"
msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about codequality reports %{linkEndTag}"
@@ -29467,9 +30439,6 @@ msgstr ""
msgid "error"
msgstr ""
-msgid "error code:"
-msgstr ""
-
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr ""
@@ -29491,6 +30460,9 @@ msgstr ""
msgid "failed to dismiss associated finding(id=%{finding_id}): %{message}"
msgstr ""
+msgid "failed to revert associated finding(id=%{finding_id}) to detected"
+msgstr ""
+
msgid "file"
msgid_plural "files"
msgstr[0] ""
@@ -30033,6 +31005,9 @@ msgstr ""
msgid "must be a root namespace"
msgstr ""
+msgid "must be a valid IPv4 or IPv6 address"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -30069,6 +31044,9 @@ msgstr ""
msgid "no expiration"
msgstr ""
+msgid "no name set"
+msgstr ""
+
msgid "no one can merge"
msgstr ""
@@ -30247,9 +31225,6 @@ msgstr ""
msgid "security Reports|There was an error creating the merge request"
msgstr ""
-msgid "settings saved, but not activated"
-msgstr ""
-
msgid "severity|Critical"
msgstr ""
@@ -30376,9 +31351,6 @@ msgstr ""
msgid "toggle collapse"
msgstr ""
-msgid "toggle dropdown"
-msgstr ""
-
msgid "triggered"
msgstr ""
@@ -30406,6 +31378,9 @@ msgstr ""
msgid "user avatar"
msgstr ""
+msgid "user preferences"
+msgstr ""
+
msgid "username"
msgstr ""
diff --git a/locale/tr_TR/gitlab.po b/locale/tr_TR/gitlab.po
index 07e6b569ad6..1e89acbf717 100644
--- a/locale/tr_TR/gitlab.po
+++ b/locale/tr_TR/gitlab.po
@@ -14,7 +14,10 @@ msgstr ""
"X-Crowdin-Language: tr\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 6\n"
-"PO-Revision-Date: 2020-09-04 23:08\n"
+"PO-Revision-Date: 2020-10-02 18:48\n"
+
+msgid " %{project_name}#%{issue_iid} &middot; opened %{issue_created} by %{author}"
+msgstr ""
msgid " %{start} to %{end}"
msgstr ""
@@ -63,10 +66,10 @@ msgid " or %{emphasisStart}#issue id%{emphasisEnd}"
msgstr ""
msgid " or %{emphasisStart}&epic id%{emphasisEnd}"
-msgstr ""
+msgstr " ya da %{emphasisStart}&epic id%{emphasisEnd}"
msgid " or references (e.g. path/to/project!merge_request_id)"
-msgstr ""
+msgstr " ya da referanslar (ör. path/to/project!merge_request_id)"
msgid "\"%{path}\" did not exist on \"%{ref}\""
msgstr ""
@@ -74,11 +77,21 @@ msgstr ""
msgid "\"el\" parameter is required for createInstance()"
msgstr ""
-msgid "%d Scanned URL"
-msgid_plural "%d Scanned URLs"
+msgid "%d Approval"
+msgid_plural "%d Approvals"
msgstr[0] ""
msgstr[1] ""
+msgid "%d Package"
+msgid_plural "%d Packages"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d Scanned URL"
+msgid_plural "%d Scanned URLs"
+msgstr[0] "%d Taranan URL"
+msgstr[1] "%d Taranan URL"
+
msgid "%d URL scanned"
msgid_plural "%d URLs scanned"
msgstr[0] "%d URL tarandı"
@@ -86,13 +99,13 @@ msgstr[1] "%d URL tarandı"
msgid "%d approver"
msgid_plural "%d approvers"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%d onaylayan"
+msgstr[1] "%d onaylayan"
msgid "%d approver (you've approved)"
msgid_plural "%d approvers (you've approved)"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%d onaylayan (onayladınız)"
+msgstr[1] "%d onaylayan (onayladınız)"
msgid "%d changed file"
msgid_plural "%d changed files"
@@ -137,6 +150,11 @@ msgstr[1] "%d iÅŸlem"
msgid "%d commits"
msgstr "%d iÅŸlem"
+msgid "%d completed issue"
+msgid_plural "%d completed issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d contribution"
msgid_plural "%d contributions"
msgstr[0] "%d katkı"
@@ -147,6 +165,11 @@ msgid_plural "%d days"
msgstr[0] "%d gün"
msgstr[1] "%d gün"
+msgid "%d day until tags are automatically removed"
+msgid_plural "%d days until tags are automatically removed"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d error"
msgid_plural "%d errors"
msgstr[0] "%d hata"
@@ -174,8 +197,8 @@ msgstr[1] "%d grup seçildi"
msgid "%d hour"
msgid_plural "%d hours"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%d saat"
+msgstr[1] "%d saat"
msgid "%d inaccessible merge request"
msgid_plural "%d inaccessible merge requests"
@@ -189,8 +212,8 @@ msgstr[1] "%d soru"
msgid "%d issue in this group"
msgid_plural "%d issues in this group"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "Bu grupta %d sorun"
+msgstr[1] "Bu grupta %d sorun"
msgid "%d issue selected"
msgid_plural "%d issues selected"
@@ -199,8 +222,8 @@ msgstr[1] "%d sorun seçili"
msgid "%d issue successfully imported with the label"
msgid_plural "%d issues successfully imported with the label"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%d sorun etiketle başarıyla içe aktarıldı"
+msgstr[1] "%d sorun etiketle başarıyla içe aktarıldı"
msgid "%d layer"
msgid_plural "%d layers"
@@ -224,8 +247,8 @@ msgstr[1] "%d metrik"
msgid "%d milestone"
msgid_plural "%d milestones"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%d dönüm noktası"
+msgstr[1] "%d dönüm noktası"
msgid "%d minute"
msgid_plural "%d minutes"
@@ -237,6 +260,16 @@ msgid_plural "%d more comments"
msgstr[0] "%d yorum daha"
msgstr[1] "%d yorum daha"
+msgid "%d open issue"
+msgid_plural "%d open issues"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d pending comment"
+msgid_plural "%d pending comments"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d personal project will be removed and cannot be restored."
msgid_plural "%d personal projects will be removed and cannot be restored."
msgstr[0] "%d kişisel proje kaldırılır ve geri yüklenemez."
@@ -244,14 +277,19 @@ msgstr[1] "%d kişisel proje kaldırılır ve geri yüklenemez."
msgid "%d previously merged commit"
msgid_plural "%d previously merged commits"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "Önceden birleştirilmiş %d işlem"
+msgstr[1] "Önceden birleştirilmiş %d işlem"
msgid "%d project"
msgid_plural "%d projects"
msgstr[0] "%d proje"
msgstr[1] "%d proje"
+msgid "%d project selected"
+msgid_plural "%d projects selected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d request with warnings"
msgid_plural "%d requests with warnings"
msgstr[0] "Uyarı içeren %d istek"
@@ -264,14 +302,19 @@ msgstr[1] "%d saniye"
msgid "%d shard selected"
msgid_plural "%d shards selected"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%d parça seçildi"
+msgstr[1] "%d parça seçildi"
msgid "%d tag"
msgid_plural "%d tags"
msgstr[0] "%d etiket"
msgstr[1] "%d etiket"
+msgid "%d tag per image name"
+msgid_plural "%d tags per image name"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d unassigned issue"
msgid_plural "%d unassigned issues"
msgstr[0] ""
@@ -292,6 +335,11 @@ msgid_plural "%d vulnerabilities dismissed"
msgstr[0] ""
msgstr[1] ""
+msgid "%d warning found:"
+msgid_plural "%d warnings found:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%s additional commit has been omitted to prevent performance issues."
msgid_plural "%s additional commits have been omitted to prevent performance issues."
msgstr[0] "%s performans sorunlarını önlemek için ek işlem konulmuştur."
@@ -301,13 +349,13 @@ msgid "%{actionText} & %{openOrClose} %{noteable}"
msgstr "%{actionText} ve %{openOrClose} %{noteable}"
msgid "%{address} is an invalid IP address range"
-msgstr ""
+msgstr "%{address} geçersiz bir IP adresi aralığıdır"
msgid "%{author_link} wrote:"
msgstr "%{author_link} yazdı:"
msgid "%{authorsName}'s thread"
-msgstr ""
+msgstr "%{authorsName} kiÅŸisinin konusu"
msgid "%{code_open}\"johnsmith@example.com\": \"@johnsmith\"%{code_close} will add \"By %{link_open}@johnsmith%{link_close}\" to all issues and comments originally created by johnsmith@example.com, and will set %{link_open}@johnsmith%{link_close} as the assignee on all issues originally assigned to johnsmith@example.com."
msgstr ""
@@ -330,6 +378,9 @@ msgstr ""
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr "%{commit_author_link} %{commit_timeago} oluÅŸturdu"
+msgid "%{completedCount} completed weight"
+msgstr ""
+
msgid "%{completedWeight} of %{totalWeight} weight completed"
msgstr ""
@@ -378,14 +429,12 @@ msgid_plural "%{count} participants"
msgstr[0] "%{count} katılımcı"
msgstr[1] "%{count} katılımcı"
-msgid "%{count} pending comment"
-msgid_plural "%{count} pending comments"
-msgstr[0] "%{count} bekleyen yorum"
-msgstr[1] "%{count} bekleyen yorum"
-
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
+msgid "%{count} total weight"
+msgstr ""
+
msgid "%{dashboard_path} could not be found."
msgstr "%{dashboard_path} bulunamadı."
@@ -440,6 +489,9 @@ msgstr "%{group_name} grubunun üyeleri"
msgid "%{group_name} uses group managed accounts. You need to create a new GitLab account which will be managed by %{group_name}."
msgstr ""
+msgid "%{group_name}&%{epic_iid} &middot; opened %{epic_created} by %{author}"
+msgstr ""
+
msgid "%{host} sign-in from new location"
msgstr "%{host} yeni konumdan oturum açma"
@@ -452,8 +504,8 @@ msgstr ""
msgid "%{issuableType} will be removed! Are you sure?"
msgstr "%{issuableType} kaldırılacak! Emin misiniz?"
-msgid "%{issuesSize} issues with a limit of %{maxIssueCount}"
-msgstr "%{maxIssueCount} sınırı olan %{issuesSize} sorun"
+msgid "%{issuesCount} issues with a limit of %{maxIssueCount}"
+msgstr ""
msgid "%{issuesSize} with a limit of %{maxIssueCount}"
msgstr ""
@@ -485,8 +537,8 @@ msgstr "%{labelStart}Yöntem:%{labelEnd} %{method}"
msgid "%{labelStart}Namespace:%{labelEnd} %{namespace}"
msgstr "%{labelStart}İsim alanları:%{labelEnd} %{namespace}"
-msgid "%{labelStart}Report Type:%{labelEnd} %{reportType}"
-msgstr "%{labelStart}Rapor Türü:%{labelEnd} %{reportType}"
+msgid "%{labelStart}Scan Type:%{labelEnd} %{reportType}"
+msgstr ""
msgid "%{labelStart}Scanner:%{labelEnd} %{scanner}"
msgstr "%{labelStart}Tarayıcı:%{labelEnd}%{scanner}"
@@ -552,10 +604,10 @@ msgid "%{milestone_name} (Past due)"
msgstr ""
msgid "%{milestone} (expired)"
-msgstr ""
+msgstr "%{milestone} (süresi doldu)"
msgid "%{milliseconds}ms"
-msgstr ""
+msgstr "%{milliseconds}ms"
msgid "%{mrText}, this issue will be closed automatically."
msgstr "%{mrText}, bu sorun otomatik olarak kapatılacaktır."
@@ -576,7 +628,7 @@ msgid "%{name} found %{resultsString}"
msgstr "%{name} bulundu %{resultsString}"
msgid "%{name} is already being used for another emoji"
-msgstr ""
+msgstr "%{name} zaten başka bir ifade için kullanılıyor"
msgid "%{name} is scheduled for %{action}"
msgstr "%{name}, %{action} için zamanlandı"
@@ -626,7 +678,7 @@ msgid "%{primary} (%{secondary})"
msgstr "%{primary} (%{secondary})"
msgid "%{ref} cannot be added: %{error}"
-msgstr ""
+msgstr "%{ref} eklenemiyor: %{error}"
msgid "%{releases} release"
msgid_plural "%{releases} releases"
@@ -670,7 +722,7 @@ msgid "%{retryButtonStart}Try again%{retryButtonEnd} or %{newFileButtonStart}att
msgstr ""
msgid "%{seconds}s"
-msgstr ""
+msgstr "%{seconds}sn"
msgid "%{securityScanner} is not enabled for this project. %{linkStart}More information%{linkEnd}"
msgid_plural "%{securityScanner} are not enabled for this project. %{linkStart}More information%{linkEnd}"
@@ -682,9 +734,6 @@ msgid_plural "%{securityScanner} results are not available because a pipeline ha
msgstr[0] ""
msgstr[1] ""
-msgid "%{service_title} %{message}."
-msgstr "%{service_title} %{message}."
-
msgid "%{size} GiB"
msgstr "%{size} GiB"
@@ -773,6 +822,12 @@ msgstr "%{text} kullanılabilir"
msgid "%{timebox_name} should belong either to a project or a group."
msgstr "%{timebox_name} bir projeye ya da bir gruba ait olmalıdır."
+msgid "%{timebox_type} does not support burnup charts"
+msgstr ""
+
+msgid "%{timebox_type} must have a start and due date"
+msgstr ""
+
msgid "%{title} %{operator} %{threshold}"
msgstr "%{title} %{operator} %{threshold}"
@@ -792,13 +847,13 @@ msgid "%{totalWeight} total weight"
msgstr "%{totalWeight} toplam ağırlık"
msgid "%{total_warnings} warning(s) found:"
-msgstr ""
+msgstr "%{total_warnings} uyarı bulundu:"
msgid "%{total} open issue weight"
msgstr "%{total} açık sorun ağırlığı"
-msgid "%{total} open issues"
-msgstr "%{total} açık sorun"
+msgid "%{total} warnings found: showing first %{warningsDisplayed}"
+msgstr ""
msgid "%{usage_ping_link_start}Learn more%{usage_ping_link_end} about what information is shared with GitLab Inc."
msgstr "Hangi bilgilerin GitLab Inc. ile paylaşıldığı hakkında %{usage_ping_link_start}daha fazla bilgi edinin%{usage_ping_link_end}."
@@ -828,16 +883,13 @@ msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notif
msgstr ""
msgid "&lt; 1 hour"
-msgstr ""
-
-msgid "&lt;no name set&gt;"
-msgstr ""
+msgstr "&lt; 1 saat"
msgid "&lt;no scopes selected&gt;"
-msgstr ""
+msgstr "&lt;no scopes selected&gt;"
msgid "&lt;project name&gt;"
-msgstr ""
+msgstr "&lt;project name&gt;"
msgid "'%{data}' at %{location} does not match format: %{format}"
msgstr ""
@@ -863,6 +915,9 @@ msgstr "'%{level}' geçerli bir görünürlük seviyesi değil"
msgid "'%{name}' Value Stream created"
msgstr ""
+msgid "'%{name}' Value Stream deleted"
+msgstr ""
+
msgid "'%{name}' stage already exists"
msgstr "'%{name}' aşaması zaten var"
@@ -881,7 +936,7 @@ msgid "(%{mrCount} merged)"
msgstr "(%{mrCount} birleÅŸtirildi)"
msgid "(%{value}) has already been taken"
-msgstr ""
+msgstr "(%{value}) zaten alınmış"
msgid "(No changes)"
msgstr "(DeÄŸiÅŸiklik yok)"
@@ -896,10 +951,10 @@ msgid "(external source)"
msgstr "(dış kaynak)"
msgid "(line: %{startLine})"
-msgstr ""
+msgstr "(satır: %{startLine})"
msgid "(max size 15 MB)"
-msgstr ""
+msgstr "(en yüksek boyut 15 MB)"
msgid "(removed)"
msgstr "(silindi)"
@@ -908,7 +963,7 @@ msgid "(revoked)"
msgstr "(iptal edildi)"
msgid "* * * * *"
-msgstr ""
+msgstr "* * * * *"
msgid "+ %{amount} more"
msgstr "%{amount} tane daha"
@@ -922,6 +977,9 @@ msgstr "+ %{moreCount} daha fazla"
msgid "+ %{numberOfHiddenAssignees} more"
msgstr "+ %{numberOfHiddenAssignees} daha"
+msgid "+ %{numberOfHiddenReviewers} more"
+msgstr ""
+
msgid "+%d more"
msgid_plural "+%d more"
msgstr[0] ""
@@ -982,6 +1040,11 @@ msgid_plural "%d Days"
msgstr[0] "1 gün"
msgstr[1] "%d gün"
+msgid "1 Issue"
+msgid_plural "%d Issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "1 closed issue"
msgid_plural "%{issues} closed issues"
msgstr[0] "1 kapatılmış sorun"
@@ -997,6 +1060,11 @@ msgid_plural "%d days"
msgstr[0] "1 gün"
msgstr[1] "%d gün"
+msgid "1 deploy key"
+msgid_plural "%d deploy keys"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] "1 grup"
@@ -1099,6 +1167,9 @@ msgstr "8 saat"
msgid ":%{startLine} to %{endLine}"
msgstr ":%{startLine} satırından %{endLine} satırına"
+msgid "A %{incident_docs_start}modified issue%{incident_docs_end} to guide the resolution of incidents."
+msgstr ""
+
msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr ""
@@ -1111,6 +1182,9 @@ msgstr ""
msgid "A GitBook site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
+msgid "A Gitpod configured Webapplication in Spring and Java"
+msgstr ""
+
msgid "A Hexo site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr "GitLab yerine CI/CD için Netlify kullanan, ancak diğer tüm GitLab özelliklerine sahip bir Hexo sitesi."
@@ -1148,10 +1222,10 @@ msgid "A file with '%{file_name}' already exists in %{branch} branch"
msgstr ""
msgid "A fork is a copy of a project."
-msgstr ""
+msgstr "Çatal, projenin bir kopyasıdır."
msgid "A group is a collection of several projects"
-msgstr ""
+msgstr "Bir grup birkaç proje topluluğudur"
msgid "A group represents your organization in GitLab. Groups allow you to manage users and collaborate across multiple projects."
msgstr ""
@@ -1187,7 +1261,7 @@ msgid "A plain HTML site that uses Netlify for CI/CD instead of GitLab, but stil
msgstr "GitLab yerine CI/CD için Netlify kullanan, ancak diğer tüm GitLab özelliklerine sahip bir düz bir HTML sitesi."
msgid "A platform value can be web, mob or app."
-msgstr ""
+msgstr "Bir platform deÄŸeri web, mobil veya uygulama olabilir."
msgid "A project boilerplate for Salesforce App development with Salesforce Developer tools."
msgstr ""
@@ -1211,7 +1285,7 @@ msgid "A secure token that identifies an external storage request."
msgstr "Harici depolama isteğini tanımlayan güvenli bir erişim anahtarı."
msgid "A sign-in to your account has been made from the following IP address: %{ip}"
-msgstr ""
+msgstr "%{ip} IP adresinden hesabınızda oturum açıldı."
msgid "A subscription will trigger a new pipeline on the default branch of this project when a pipeline successfully completes for a new tag on the %{default_branch_docs} of the subscribed project."
msgstr ""
@@ -1223,7 +1297,7 @@ msgid "ACTION REQUIRED: Something went wrong while obtaining the Let's Encrypt c
msgstr ""
msgid "API Help"
-msgstr ""
+msgstr "API Yardımı"
msgid "API Token"
msgstr "API Erişim Anahtarı"
@@ -1282,18 +1356,27 @@ msgstr "Erişim reddedildi! Lütfen bu depoya dağıtım anahtarlarını ekleyeb
msgid "Access expiration date"
msgstr "EriÅŸim bitiÅŸ tarihi"
+msgid "Access expires"
+msgstr ""
+
msgid "Access forbidden. Check your access level."
msgstr "Erişim yasaklandı. Erişim seviyenizi kontrol edin."
-msgid "Access requests"
+msgid "Access granted"
msgstr ""
+msgid "Access requests"
+msgstr "EriÅŸim istekleri"
+
msgid "Access to '%{classification_label}' not allowed"
msgstr "'%{classification_label}' eriÅŸimine izin verilmedi"
msgid "Access to Pages websites are controlled based on the user's membership to a given project. By checking this box, users will be required to be logged in to have access to all Pages websites in your instance."
msgstr ""
+msgid "AccessDropdown|Deploy Keys"
+msgstr ""
+
msgid "AccessDropdown|Groups"
msgstr "Gruplar"
@@ -1343,7 +1426,7 @@ msgid "AccessTokens|Static object token"
msgstr "Statik nesne erişim anahtarı"
msgid "AccessTokens|They are the only accepted password when you have Two-Factor Authentication (2FA) enabled."
-msgstr ""
+msgstr "Bunlar yalnızca İki Adımlı Kimlik Doğrulama (2FA) özelliğini etkinleştirdiğinizde, kabul edilen şifredir."
msgid "AccessTokens|You can also use personal access tokens to authenticate against Git over HTTP."
msgstr "Git üzerinden HTTP üzerinden kimlik doğrulaması yapmak için kişisel erişim anahtarlarını da kullanabilirsiniz."
@@ -1364,7 +1447,7 @@ msgid "AccessTokens|reset it"
msgstr "sıfırla"
msgid "AccessibilityReport|Learn more"
-msgstr ""
+msgstr "Daha fazlasını öğren"
msgid "AccessibilityReport|Message: %{message}"
msgstr "Mesaj: %{message}"
@@ -1411,12 +1494,6 @@ msgstr ""
msgid "Active Sessions"
msgstr "Etkin Oturumlar"
-msgid "Active Users:"
-msgstr "Etkin Kullanıcılar:"
-
-msgid "Active users"
-msgstr "Aktif kullanıcılar"
-
msgid "Activity"
msgstr "Etkinlik"
@@ -1424,7 +1501,7 @@ msgid "Add"
msgstr "Ekle"
msgid "Add \"%{value}\""
-msgstr ""
+msgstr "\"%{value}\" ekle"
msgid "Add %d issue"
msgid_plural "Add %d issues"
@@ -1480,7 +1557,7 @@ msgid "Add a To Do"
msgstr "Yapılacaklar listesi ekle"
msgid "Add a To-Do"
-msgstr ""
+msgstr "Yapılacak ekle"
msgid "Add a bullet list"
msgstr "Madde iÅŸareti listesi ekle"
@@ -1510,7 +1587,7 @@ msgid "Add a numbered list"
msgstr "Numaralı liste ekle"
msgid "Add a related issue"
-msgstr ""
+msgstr "Ä°lgili sorun ekle"
msgid "Add a table"
msgstr "Tablo ekle"
@@ -1549,10 +1626,10 @@ msgid "Add comment now"
msgstr "Åžimdi yorum ekle"
msgid "Add comment to design"
-msgstr ""
+msgstr "Tasarıma yorum ekle"
msgid "Add deploy freeze"
-msgstr ""
+msgstr "Dağıtım durdurma ekle"
msgid "Add domain"
msgstr "Etki alanı ekle"
@@ -1579,14 +1656,11 @@ msgid "Add italic text"
msgstr "EÄŸik metin ekle"
msgid "Add key"
-msgstr ""
+msgstr "Anahtar ekle"
msgid "Add label(s)"
msgstr "Etiket(ler) ekleyin"
-msgid "Add license"
-msgstr "Lisans ekle"
-
msgid "Add list"
msgstr "Liste ekle"
@@ -1657,7 +1731,7 @@ msgid "AddContextCommits|Add previously merged commits"
msgstr ""
msgid "AddContextCommits|Add/remove"
-msgstr ""
+msgstr "Ekle/kaldır"
msgid "AddMember|No users specified."
msgstr "Kullanıcı belirtilmedi."
@@ -1761,21 +1835,51 @@ msgstr "Engellenen kullanıcılar"
msgid "AdminArea|Bots"
msgstr "Botlar"
+msgid "AdminArea|Components"
+msgstr ""
+
msgid "AdminArea|Developer"
msgstr "GeliÅŸtirici"
+msgid "AdminArea|Features"
+msgstr ""
+
+msgid "AdminArea|Groups: %{number_of_groups}"
+msgstr ""
+
msgid "AdminArea|Guest"
msgstr "Misafir"
msgid "AdminArea|Included Free in license"
msgstr "Lisansa ücretsiz dahildir"
+msgid "AdminArea|Latest groups"
+msgstr ""
+
+msgid "AdminArea|Latest projects"
+msgstr ""
+
+msgid "AdminArea|Latest users"
+msgstr ""
+
msgid "AdminArea|Maintainer"
msgstr "Sorumlu"
+msgid "AdminArea|New group"
+msgstr ""
+
+msgid "AdminArea|New project"
+msgstr ""
+
+msgid "AdminArea|New user"
+msgstr ""
+
msgid "AdminArea|Owner"
msgstr "Sahibi"
+msgid "AdminArea|Projects: %{number_of_projects}"
+msgstr ""
+
msgid "AdminArea|Reporter"
msgstr "Raporlayıcı"
@@ -1803,6 +1907,9 @@ msgstr "En yüksek role sahip kullanıcılar"
msgid "AdminArea|Users without a Group and Project"
msgstr "Grubu ve projesi olmayan kullanıcılar"
+msgid "AdminArea|Users: %{number_of_users}"
+msgstr ""
+
msgid "AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running."
msgstr "Bütün işleri durdurmak üzeresiniz. Bu işlem, çalışan tüm mevcut işleri durduracaktır."
@@ -1821,9 +1928,6 @@ msgstr "Sil"
msgid "AdminProjects|Delete Project %{projectName}?"
msgstr "%{projectName} projesi silinsin mi?"
-msgid "AdminProjects|Delete project"
-msgstr "Projeyi sil"
-
msgid "AdminSettings|Apply integration settings to all Projects"
msgstr "Tüm projelere entegrasyon ayarlarını uygula"
@@ -1915,7 +2019,7 @@ msgid "AdminUsers|2FA Enabled"
msgstr "2FA Etkin"
msgid "AdminUsers|Access"
-msgstr ""
+msgstr "EriÅŸim"
msgid "AdminUsers|Active"
msgstr "Etkin"
@@ -2061,21 +2165,30 @@ msgstr ""
msgid "AdminUsers|Without projects"
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 %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 ""
msgid "AdminUsers|You cannot remove your own admin rights."
msgstr ""
+msgid "AdminUsers|You must transfer ownership or delete the groups owned by this user before you can delete their account"
+msgstr ""
+
msgid "Administration"
msgstr "Yönetim"
msgid "Advanced"
msgstr "GeliÅŸmiÅŸ"
+msgid "Advanced Search"
+msgstr ""
+
+msgid "Advanced Search with Elasticsearch"
+msgstr ""
+
msgid "Advanced Settings"
msgstr "GeliÅŸmiÅŸ Ayarlar"
@@ -2095,10 +2208,10 @@ msgid "After that, you will not to be able to use merge approvals or code qualit
msgstr ""
msgid "After that, you will not to be able to use merge approvals or epics as well as many other features."
-msgstr ""
+msgstr "Bundan sonra, birleştirme onaylarını veya epikleri ve diğer birçok özelliği kullanamazsınız."
msgid "After that, you will not to be able to use merge approvals or epics as well as many security features."
-msgstr ""
+msgstr "Bundan sonra, birleştirme onaylarını veya epikleri ve birçok güvenlik özelliğini kullanamazsınız."
msgid "Alert"
msgid_plural "Alerts"
@@ -2153,6 +2266,9 @@ msgstr ""
msgid "AlertManagement|Edit"
msgstr "Düzenle"
+msgid "AlertManagement|Environment"
+msgstr ""
+
msgid "AlertManagement|Events"
msgstr "Olaylar"
@@ -2163,6 +2279,9 @@ msgid "AlertManagement|Info"
msgstr "Bilgi"
msgid "AlertManagement|Issue"
+msgstr "Sorun"
+
+msgid "AlertManagement|Key"
msgstr ""
msgid "AlertManagement|Low"
@@ -2187,7 +2306,7 @@ msgid "AlertManagement|No alerts available to display. See %{linkStart}enabling
msgstr ""
msgid "AlertManagement|No alerts to display."
-msgstr ""
+msgstr "Görüntülenecek uyarı yok."
msgid "AlertManagement|None"
msgstr "Yok"
@@ -2226,7 +2345,7 @@ msgid "AlertManagement|Status"
msgstr "Durum"
msgid "AlertManagement|Surface alerts in GitLab"
-msgstr ""
+msgstr "GitLab'da yüzey uyarıları"
msgid "AlertManagement|There was an error displaying the alert. Please refresh the page to try again."
msgstr "Uyarı görüntülenirken bir hata oluştu. Lütfen tekrar denemek için sayfayı yenileyin."
@@ -2258,6 +2377,9 @@ msgstr "Tetiklenenler"
msgid "AlertManagement|Unknown"
msgstr "Bilinmeyen"
+msgid "AlertManagement|Value"
+msgstr ""
+
msgid "AlertManagement|View alerts in Opsgenie"
msgstr ""
@@ -2274,10 +2396,10 @@ msgid "AlertService|You must provide this URL and authorization key to authorize
msgstr ""
msgid "AlertSettings|API URL"
-msgstr ""
+msgstr "API URL"
msgid "AlertSettings|Active"
-msgstr ""
+msgstr "Etkin"
msgid "AlertSettings|Add URL and auth key to your Prometheus config file"
msgstr ""
@@ -2289,13 +2411,13 @@ msgid "AlertSettings|Alerts endpoint successfully activated."
msgstr ""
msgid "AlertSettings|Authorization key"
-msgstr ""
+msgstr "Yetkilendirme anahtarı"
msgid "AlertSettings|Authorization key has been successfully reset. Please save your changes now."
msgstr ""
msgid "AlertSettings|Copy"
-msgstr ""
+msgstr "Kopyala"
msgid "AlertSettings|Enter test alert JSON...."
msgstr ""
@@ -2304,7 +2426,7 @@ msgid "AlertSettings|External Prometheus"
msgstr ""
msgid "AlertSettings|Generic"
-msgstr ""
+msgstr "Genel"
msgid "AlertSettings|Integrations"
msgstr ""
@@ -2316,7 +2438,7 @@ msgid "AlertSettings|Opsgenie"
msgstr ""
msgid "AlertSettings|Reset key"
-msgstr ""
+msgstr "Sıfırlama anahtarı"
msgid "AlertSettings|Resetting the authorization key for this project will require updating the authorization key in every alert source it is enabled in."
msgstr ""
@@ -2391,7 +2513,7 @@ msgid "All environments"
msgstr "Tüm ortamlar"
msgid "All epics"
-msgstr ""
+msgstr "Tüm epikler"
msgid "All features are enabled for blank projects, from templates, or when importing, but you can disable them afterward in the project settings."
msgstr "Tüm özellikler şablonlardan veya içe aktarırken boş projeler için etkindir, ancak daha sonra proje ayarlarında bunları devre dışı bırakabilirsiniz."
@@ -2417,6 +2539,9 @@ msgstr ""
msgid "All projects"
msgstr "Tüm projeler"
+msgid "All projects selected"
+msgstr ""
+
msgid "All security scans are enabled because %{linkStart}Auto DevOps%{linkEnd} is enabled on this project"
msgstr ""
@@ -2504,6 +2629,9 @@ msgstr "Kubernetes kümelerini eklemeye ve yönetmenize olanak tanır."
msgid "Almost there"
msgstr "Neredeyse tamamlandı"
+msgid "Already blocked"
+msgstr ""
+
msgid "Also called \"Issuer\" or \"Relying party trust identifier\""
msgstr ""
@@ -2558,6 +2686,9 @@ msgstr ""
msgid "An error has occurred"
msgstr "Bir hata oluÅŸtu"
+msgid "An error occured while making the changes: %{error}"
+msgstr ""
+
msgid "An error occurred adding a draft to the thread."
msgstr "Konuya taslak eklenirken bir hata oluÅŸtu."
@@ -2574,7 +2705,7 @@ msgid "An error occurred fetching the approvers for the new rule."
msgstr "Yeni kuralın onaylayanları alınırken bir hata oluştu."
msgid "An error occurred fetching the dropdown data."
-msgstr ""
+msgstr "Açılır liste verileri alınırken bir hata oluştu."
msgid "An error occurred fetching the project authors."
msgstr "Proje yazarları alınırken bir hata oluştu."
@@ -2585,12 +2716,6 @@ msgstr "Blob datanın öngösteriminde, bir hata meydana geldi"
msgid "An error occurred when toggling the notification subscription"
msgstr "Bildirim aboneliÄŸini deÄŸiÅŸtirirken bir sorun meydana geldi"
-msgid "An error occurred when trying to resolve a comment. Please try again."
-msgstr ""
-
-msgid "An error occurred when trying to resolve a discussion. Please try again."
-msgstr ""
-
msgid "An error occurred when updating the issue weight"
msgstr "Sorun ağırlığı güncellenirken bir hata oluştu"
@@ -2601,17 +2726,11 @@ msgid "An error occurred while adding approvers"
msgstr ""
msgid "An error occurred while adding formatted title for epic"
-msgstr ""
+msgstr "Epik için biçimlendirilmiş başlık eklenirken bir hata oluştu"
msgid "An error occurred while checking group path. Please refresh and try again."
msgstr ""
-msgid "An error occurred while committing your changes."
-msgstr "DeÄŸiÅŸiklikleriniz iÅŸlenirken bir hata oluÅŸtu."
-
-msgid "An error occurred while creating the list. Please try again."
-msgstr ""
-
msgid "An error occurred while decoding the file."
msgstr ""
@@ -2622,13 +2741,13 @@ msgid "An error occurred while deleting the comment"
msgstr "Yorum silinirken bir hata oluÅŸtu"
msgid "An error occurred while deleting the pipeline."
-msgstr ""
+msgstr "İş hattı silinirken bir hata oluştu."
msgid "An error occurred while detecting host keys"
msgstr "Ana bilgisayar anahtarları algılanırken bir hata oluştu"
msgid "An error occurred while disabling Service Desk."
-msgstr ""
+msgstr "Servis Masası devre dışı bırakılırken bir hata oluştu."
msgid "An error occurred while dismissing the alert. Refresh the page and try again."
msgstr "Uyarıyı kaldırırken bir sorun oluştu. Sayfayı yenileyin ve yeniden deneyin."
@@ -2637,7 +2756,7 @@ msgid "An error occurred while dismissing the feature highlight. Refresh the pag
msgstr "Özellik vurgusunu gönderirken bir hata oluştu. Sayfayı yenileyin ve tekrar gönderin."
msgid "An error occurred while enabling Service Desk."
-msgstr ""
+msgstr "Servis Masası etkinleştirilirken bir hata oluştu."
msgid "An error occurred while fetching branches. Retry the search."
msgstr ""
@@ -2646,10 +2765,10 @@ msgid "An error occurred while fetching commits. Retry the search."
msgstr ""
msgid "An error occurred while fetching coverage reports."
-msgstr ""
+msgstr "Kapsam raporu alınırken bir hata oluştu."
msgid "An error occurred while fetching environments."
-msgstr ""
+msgstr "Ortamlar alınırken bir hata oluştu."
msgid "An error occurred while fetching exposed artifacts."
msgstr ""
@@ -2684,26 +2803,20 @@ msgstr "Terraform raporu alınırken bir hata oluştu."
msgid "An error occurred while fetching the Service Desk address."
msgstr ""
-msgid "An error occurred while fetching the board issues. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the board lists. Please reload the page."
msgstr ""
msgid "An error occurred while fetching the board lists. Please try again."
msgstr "Pano listeleri alınırken bir hata oluştu. Lütfen tekrar deneyin."
-msgid "An error occurred while fetching the board swimlanes. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the builds."
-msgstr ""
+msgstr "Yapılar alınırken bir hata oluştu."
msgid "An error occurred while fetching the job log."
msgstr "İş kayıtları alınırken bir hata oluştu."
-msgid "An error occurred while fetching the job trace."
-msgstr "Ä°ÅŸ izi getirilirken bir hata oluÅŸtu."
+msgid "An error occurred while fetching the job logs."
+msgstr ""
msgid "An error occurred while fetching the job."
msgstr "İş alınırken bir hata oluştu."
@@ -2849,9 +2962,6 @@ msgstr ""
msgid "An error occurred while saving assignees"
msgstr "Vekiller kaydedilirken bir hata oluÅŸtu"
-msgid "An error occurred while saving the template. Please check if the template exists."
-msgstr ""
-
msgid "An error occurred while searching for milestones"
msgstr "Dönüm noktaları aranırken bir hata oluştu"
@@ -2859,7 +2969,7 @@ msgid "An error occurred while subscribing to notifications."
msgstr "Bildirimlere abone olunurken bir hata oluÅŸtu."
msgid "An error occurred while triggering the job."
-msgstr ""
+msgstr "Ä°ÅŸ tetiklenirken bir hata oluÅŸtu."
msgid "An error occurred while trying to run a new pipeline for this Merge Request."
msgstr ""
@@ -2870,12 +2980,12 @@ msgstr "Bildirim aboneliÄŸi iptal edilirken bir hata oluÅŸtu."
msgid "An error occurred while updating approvers"
msgstr "Onaylama sırasında güncelleme yapılırken bir hata oluştu"
+msgid "An error occurred while updating labels."
+msgstr ""
+
msgid "An error occurred while updating the comment"
msgstr "Yorum güncellenirken bir hata oluştu"
-msgid "An error occurred while updating the list. Please try again."
-msgstr ""
-
msgid "An error occurred while validating group path"
msgstr "Grup yolu doğrulanırken bir hata oluştu"
@@ -2927,6 +3037,9 @@ msgstr "Web Terminali durdurulurken beklenmeyen bir hata oluÅŸtu."
msgid "An unknown error occurred while loading this graph."
msgstr "Bu grafik yüklenirken bilinmeyen bir hata oluştu."
+msgid "An unknown error occurred."
+msgstr ""
+
msgid "Analytics"
msgstr "Analizler"
@@ -2943,7 +3056,7 @@ msgid "Analyze your source code for known vulnerabilities."
msgstr ""
msgid "Ancestors"
-msgstr ""
+msgstr "Atalar"
msgid "Anonymous"
msgstr "Anonim"
@@ -2960,12 +3073,12 @@ msgstr "Anti-spam doÄŸrulama"
msgid "Any"
msgstr "Herhangi"
+msgid "Any %{header}"
+msgstr ""
+
msgid "Any Author"
msgstr "Herhangi yazar"
-msgid "Any Status"
-msgstr ""
-
msgid "Any branch"
msgstr "Herhangi dal"
@@ -3006,7 +3119,7 @@ msgid "Appearance was successfully updated."
msgstr "Görünüm başarıyla güncellendi."
msgid "Append the comment with %{shrug}"
-msgstr ""
+msgstr "Yorumu %{shrug} ile ekle"
msgid "Append the comment with %{tableflip}"
msgstr "Yorumu %{tableflip} ile ekle"
@@ -3017,6 +3130,9 @@ msgstr "Uygulama"
msgid "Application ID"
msgstr "Uygulama KimliÄŸi"
+msgid "Application limits saved successfully"
+msgstr ""
+
msgid "Application settings saved successfully"
msgstr "Uygulama ayarları başarıyla kaydedildi"
@@ -3197,7 +3313,7 @@ msgid "Archived"
msgstr "ArÅŸivlenmiÅŸ"
msgid "Archived in this version"
-msgstr ""
+msgstr "Bu sürümde arşivlendi"
msgid "Archived project! Repository and other project resources are read only"
msgstr "Arşivlenmiş proje! Depo ve diğer proje kaynakları sadece okunabilir özelliğe sahiptir"
@@ -3226,6 +3342,9 @@ msgstr "Bu yorumu oluşturmayı iptal etmek istediğinizden emin misiniz?"
msgid "Are you sure you want to close this blocked issue?"
msgstr ""
+msgid "Are you sure you want to delete \"%{name}\" Value Stream?"
+msgstr ""
+
msgid "Are you sure you want to delete %{name}?"
msgstr "%{name} ismini silmek istediÄŸinizden emin misiniz?"
@@ -3235,6 +3354,9 @@ msgstr "Bu artifact'ları silmek istediğinize emin misiniz?"
msgid "Are you sure you want to delete this %{typeOfComment}?"
msgstr "Bu %{typeOfComment} silmek istediÄŸinizden emin misiniz?"
+msgid "Are you sure you want to delete this SSH key?"
+msgstr ""
+
msgid "Are you sure you want to delete this board?"
msgstr "Bu panoyu silmek istediÄŸinizden emin misiniz?"
@@ -3259,6 +3381,11 @@ msgstr "Bu yorumu silmek istediÄŸinizden emin misiniz?"
msgid "Are you sure you want to erase this build?"
msgstr "Bu yapıyı silmek istediğinizden emin misiniz?"
+msgid "Are you sure you want to import %d repository?"
+msgid_plural "Are you sure you want to import %d repositories?"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Are you sure you want to lose unsaved changes?"
msgstr "KaydedilmemiÅŸ deÄŸiÅŸiklikleri kaybetmek istediÄŸinizden emin misiniz?"
@@ -3268,15 +3395,15 @@ msgstr "Sorun bilgilerinizi kaybetmek istediÄŸinizden emin misiniz?"
msgid "Are you sure you want to merge immediately?"
msgstr ""
-msgid "Are you sure you want to permanently delete this license?"
-msgstr ""
-
msgid "Are you sure you want to re-deploy this environment?"
msgstr ""
msgid "Are you sure you want to regenerate the public key? You will have to update the public key on the remote server before mirroring will work again."
msgstr "Genel anahtarı yeniden oluşturmak istediğinizden emin misiniz? Yansıtma işleminin tekrar çalışması için önce uzak sunucudaki ortak anahtarı güncellemeniz gerekecektir."
+msgid "Are you sure you want to reindex?"
+msgstr ""
+
msgid "Are you sure you want to remove %{group_name}?"
msgstr "%{group_name} grubunu silmek istediÄŸinizden emin misiniz?"
@@ -3304,6 +3431,9 @@ msgstr ""
msgid "Are you sure you want to revoke this nickname?"
msgstr ""
+msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
+msgstr ""
+
msgid "Are you sure you want to stop this environment?"
msgstr ""
@@ -3317,7 +3447,7 @@ msgid "Are you sure?"
msgstr "Emin misiniz?"
msgid "Are you sure? All commits that were signed with this GPG key will be unverified."
-msgstr ""
+msgstr "Emin misiniz? Bu GPG anahtarı ile imzalanan tüm işlemler doğrulanmamış olacaktır."
msgid "Are you sure? Removing this GPG key does not affect already signed commits."
msgstr ""
@@ -3325,6 +3455,9 @@ msgstr ""
msgid "Are you sure? The device will be signed out of GitLab and all remember me tokens revoked."
msgstr ""
+msgid "Are you sure? This will invalidate your registered applications and U2F / WebAuthn devices."
+msgstr ""
+
msgid "Are you sure? This will invalidate your registered applications and U2F devices."
msgstr "Emin misiniz? Bu, kayıtlı uygulamalarınızı ve U2F cihazlarınızı geçersiz kılar."
@@ -3343,9 +3476,6 @@ msgstr "Artifact başarıyla silindi."
msgid "Artifacts"
msgstr "Yapılar"
-msgid "As U2F devices are only supported by a few browsers, we require that you set up a two-factor authentication app before a U2F device. That way you'll always be able to log in - even when you're using an unsupported browser."
-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 ""
@@ -3486,10 +3616,10 @@ msgid "Attaching the file failed."
msgstr "Dosya ekleme başarısız oldu."
msgid "Attachment"
-msgstr ""
+msgstr "Ek"
msgid "Attachments"
-msgstr ""
+msgstr "Ekler"
msgid "Audit Events"
msgstr "Denetim Etkinlikleri"
@@ -3539,6 +3669,9 @@ msgstr "Proje Etkinlikleri"
msgid "AuditLogs|Target"
msgstr "Hedef"
+msgid "AuditLogs|This month"
+msgstr ""
+
msgid "AuditLogs|User Events"
msgstr "Kullanıcı Etkinlikleri"
@@ -3578,6 +3711,9 @@ msgstr "Kimlik doğrulama yöntemi güncellendi"
msgid "Authentication via U2F device failed."
msgstr ""
+msgid "Authentication via WebAuthn device failed."
+msgstr ""
+
msgid "Author"
msgstr "Yazar"
@@ -3585,7 +3721,7 @@ msgid "Author: %{author_name}"
msgstr ""
msgid "Authored %{timeago}"
-msgstr ""
+msgstr "%{timeago} yazıldı"
msgid "Authored %{timeago} by %{author}"
msgstr "%{author} tarafından %{timeago} oluşturuldu"
@@ -3597,7 +3733,7 @@ msgid "Authorization key"
msgstr "Yetkilendirme anahtarı"
msgid "Authorization required"
-msgstr ""
+msgstr "Yetkilendirme gerekli"
msgid "Authorization was granted by entering your username and password in the application."
msgstr "Uygulamaya kullanıcı adınız ve şifreniz girilererek yetki verildi."
@@ -3845,15 +3981,6 @@ msgstr ""
msgid "BambooService|You must set up automatic revision labeling and a repository trigger in Bamboo."
msgstr ""
-msgid "BatchComments|Delete all pending comments"
-msgstr "Bekleyen tüm yorumları sil"
-
-msgid "BatchComments|Discard review?"
-msgstr "İnceleme atılsın mı?"
-
-msgid "BatchComments|You're about to discard your review which will delete all of your pending comments. The deleted comments %{strong_start}cannot%{strong_end} be restored."
-msgstr "Bekleyen tüm yorumlarınızı silecek olan incelemenizi silmek üzeresiniz. Silinen yorumlar %{strong_start}geri%{strong_end} yüklenemez."
-
msgid "Be careful. Changing the project's namespace can have unintended side effects."
msgstr "Dikkatli olun. Projenin isim alanını değiştirmek, istenmeyen yan etkilere neden olabilir."
@@ -3875,6 +4002,9 @@ msgstr ""
msgid "Bi-weekly code coverage"
msgstr ""
+msgid "Billable Users:"
+msgstr ""
+
msgid "Billing"
msgstr "Fatura"
@@ -3884,8 +4014,8 @@ msgstr "%{group_name} şu anda %{plan_name} planı kullanıyor."
msgid "BillingPlans|@%{user_name} you are currently using the %{plan_name} plan."
msgstr "@%{user_name} olarak şu anda %{plan_name} planı kullanıyorsunuz."
-msgid "BillingPlans|Congratulations, your new trial is activated"
-msgstr "Tebrikler, yeni denemeniz etkinleÅŸtirildi"
+msgid "BillingPlans|Congratulations, your free trial is activated."
+msgstr ""
msgid "BillingPlans|If you would like to downgrade your plan please contact %{support_link_start}Customer Support%{support_link_end}."
msgstr ""
@@ -3947,6 +4077,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Block user"
+msgstr ""
+
msgid "Blocked"
msgstr "EngellenmiÅŸ"
@@ -3962,31 +4095,37 @@ msgstr ""
msgid "Blog"
msgstr "Blog"
-msgid "Board name"
-msgstr "Pano adı"
-
msgid "Board scope"
msgstr "Pano kapsamı"
msgid "Board scope affects which issues are displayed for anyone who visits this board"
msgstr "Pano kapsamı, bu panoyu ziyaret eden kişilere hangi sorunların gösterileceğini belirler"
-msgid "BoardBlankState|Add default lists"
-msgstr "Varsayılan listesine ekle"
+msgid "Boards"
+msgstr "Panolar"
-msgid "BoardBlankState|Add the following default lists to your Issue Board with one click:"
+msgid "Boards and Board Lists"
msgstr ""
-msgid "BoardBlankState|Nevermind, I'll use my own"
+msgid "Boards|An error occurred while creating the issue. Please try again."
msgstr ""
-msgid "BoardBlankState|Starting out with the default set of lists will get you right on the way to making the most of your board."
+msgid "Boards|An error occurred while creating the list. Please try again."
msgstr ""
-msgid "Boards"
-msgstr "Panolar"
+msgid "Boards|An error occurred while fetching issues. Please reload the page."
+msgstr ""
-msgid "Boards and Board Lists"
+msgid "Boards|An error occurred while fetching the board issues. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching the board swimlanes. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while moving the issue. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while updating the list. Please try again."
msgstr ""
msgid "Boards|Collapse"
@@ -4013,8 +4152,8 @@ msgstr "Bu projenin deposunda %{branchName} dalı bulunamadı."
msgid "Branch %{branch_name} was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr ""
-msgid "Branch has changed"
-msgstr "Dal deÄŸiÅŸti"
+msgid "Branch changed"
+msgstr ""
msgid "Branch is already taken"
msgstr "Dal zaten alınmış"
@@ -4023,10 +4162,10 @@ msgid "Branch name"
msgstr "Dal adı"
msgid "Branch not loaded - %{branchId}"
-msgstr ""
+msgstr "Dal yüklü değil - %{branchId}"
msgid "Branch prefix"
-msgstr ""
+msgstr "Dal öneki"
msgid "BranchSwitcherPlaceholder|Search branches"
msgstr "Dallarda ara"
@@ -4317,10 +4456,13 @@ msgid "CLOSED"
msgstr "KAPATILDI"
msgid "CLOSED (MOVED)"
+msgstr "KAPANDI (TAÅžINDI)"
+
+msgid "CODEOWNERS rule violation"
msgstr ""
msgid "CONTRIBUTING"
-msgstr ""
+msgstr "KATKI"
msgid "CPU"
msgstr "CPU"
@@ -4349,9 +4491,6 @@ msgstr ""
msgid "Can't create snippet: %{err}"
msgstr "Parçacık üretemiyor: %{err}"
-msgid "Can't edit as source branch was deleted"
-msgstr ""
-
msgid "Can't fetch content for the blob: %{err}"
msgstr ""
@@ -4359,19 +4498,16 @@ msgid "Can't find HEAD commit for this branch"
msgstr "Bu dal için HEAD işlemi bulunamadı"
msgid "Can't find variable: ZiteReader"
-msgstr ""
+msgstr "Değişken bulunamıyor: ZiteReader"
msgid "Can't load mermaid module: %{err}"
msgstr ""
-msgid "Can't remove group members without group managed account"
-msgstr ""
-
msgid "Can't scan the code?"
msgstr "Kodu tarayamıyor musun?"
msgid "Can't update snippet: %{err}"
-msgstr ""
+msgstr "Parçacık güncellenemiyor: %{err}"
msgid "Canary"
msgstr ""
@@ -4409,6 +4545,9 @@ msgstr ""
msgid "Cannot create the abuse report. This user has been blocked."
msgstr ""
+msgid "Cannot enable shared runners because parent group does not allow it"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -4419,10 +4558,10 @@ msgid "Cannot import because issues are not available in this project."
msgstr "Bu projede sorunlar bulunmadığı için içe aktarılamıyor."
msgid "Cannot make the epic confidential if it contains non-confidential child epics"
-msgstr ""
+msgstr "Gizli olmayan alt epikler içeriyorsa epik gizli hale getirilemez"
msgid "Cannot make the epic confidential if it contains non-confidential issues"
-msgstr ""
+msgstr "Gizli olmayan sorunlar içeriyorsa epik gizli hale getirilemez"
msgid "Cannot merge"
msgstr "BirleÅŸtirilemez"
@@ -4443,7 +4582,7 @@ msgid "Cannot refer to a group %{timebox_type} by an internal id!"
msgstr ""
msgid "Cannot set confidential epic for a non-confidential issue"
-msgstr ""
+msgstr "Gizli olmayan bir sorun için gizli epik ayarlanamaz"
msgid "Cannot show preview. For previews on sketch files, they must have the file format introduced by Sketch version 43 and above."
msgstr ""
@@ -4514,6 +4653,15 @@ msgstr "Åžifrenizi deÄŸiÅŸtirin"
msgid "Change your password or recover your current one"
msgstr "Şifrenizi değiştirin veya mevcut şifrenizi kurtarın"
+msgid "ChangeReviewer|Reviewer changed from %{old} to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Reviewer changed to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Unassigned"
+msgstr ""
+
msgid "ChangeTypeActionLabel|Pick into branch"
msgstr "Dalı seç"
@@ -4553,6 +4701,9 @@ msgstr "Değişiklikler bastırıldı. Göstermek için tıkla."
msgid "Changes the title to \"%{title_param}\"."
msgstr ""
+msgid "Changes were successfully made."
+msgstr ""
+
msgid "Changes won't take place until the index is %{link_start}recreated%{link_end}."
msgstr ""
@@ -4566,7 +4717,7 @@ msgid "Channel handle (e.g. town-square)"
msgstr "Kanal yönetimi (ör. Şehir Meydanı)"
msgid "Charts"
-msgstr ""
+msgstr "Grafikler"
msgid "Charts can't be displayed as the request for data has timed out. %{documentationLink}"
msgstr ""
@@ -4665,7 +4816,7 @@ msgid "Checkout|%{selectedPlanText} plan"
msgstr "%{selectedPlanText} planı"
msgid "Checkout|%{startDate} - %{endDate}"
-msgstr ""
+msgstr "%{startDate} - %{endDate}"
msgid "Checkout|(x%{numberOfUsers})"
msgstr ""
@@ -4677,25 +4828,25 @@ msgid "Checkout|Checkout"
msgstr "Ödeme"
msgid "Checkout|City"
-msgstr ""
+msgstr "Åžehir"
msgid "Checkout|Confirm purchase"
-msgstr ""
+msgstr "Satın almayı onayla"
msgid "Checkout|Confirming..."
-msgstr ""
+msgstr "Onaylanıyor..."
msgid "Checkout|Continue to billing"
-msgstr ""
+msgstr "Faturalandırmaya devam et"
msgid "Checkout|Continue to payment"
-msgstr ""
+msgstr "Ödemeye devam et"
msgid "Checkout|Country"
-msgstr ""
+msgstr "Ãœlke"
msgid "Checkout|Create a new group"
-msgstr ""
+msgstr "Yeni grup oluÅŸtur"
msgid "Checkout|Credit card form failed to load. Please try again."
msgstr ""
@@ -4707,25 +4858,25 @@ msgid "Checkout|Edit"
msgstr "Düzenle"
msgid "Checkout|Exp %{expirationMonth}/%{expirationYear}"
-msgstr ""
+msgstr "Son Erme %{expirationMonth}/%{expirationYear}"
msgid "Checkout|Failed to confirm your order! Please try again."
-msgstr ""
+msgstr "Siparişiniz onaylanamadı! Lütfen tekrar deneyin."
msgid "Checkout|Failed to confirm your order: %{message}. Please try again."
-msgstr ""
+msgstr "Siparişiniz onaylanamadı: %{message}. Lütfen tekrar deneyin."
msgid "Checkout|Failed to load countries. Please try again."
-msgstr ""
+msgstr "Ülkeler yüklenemedi. Lütfen tekrar deneyin."
msgid "Checkout|Failed to load states. Please try again."
-msgstr ""
+msgstr "İller yüklenemedi. Lütfen tekrar deneyin."
msgid "Checkout|Failed to register credit card. Please try again."
-msgstr ""
+msgstr "Kredi kartı kaydedilemedi. Lütfen tekrar deneyin."
msgid "Checkout|GitLab group"
-msgstr ""
+msgstr "GitLab grubu"
msgid "Checkout|GitLab plan"
msgstr "GitLab planı"
@@ -4734,22 +4885,22 @@ msgid "Checkout|Group"
msgstr "Grup"
msgid "Checkout|Name of company or organization using GitLab"
-msgstr ""
+msgstr "GitLab kullanan şirketin veya kuruluşun adı"
msgid "Checkout|Need more users? Purchase GitLab for your %{company}."
msgstr ""
msgid "Checkout|Number of users"
-msgstr ""
+msgstr "Kullanıcı sayısı"
msgid "Checkout|Payment method"
-msgstr ""
+msgstr "Ödeme yöntemi"
msgid "Checkout|Please select a country"
-msgstr ""
+msgstr "Lütfen bir ülke seçin"
msgid "Checkout|Please select a state"
-msgstr ""
+msgstr "Lütfen bir il seçin"
msgid "Checkout|Select"
msgstr ""
@@ -4803,10 +4954,10 @@ msgid "Child"
msgstr ""
msgid "Child epic does not exist."
-msgstr ""
+msgstr "Alt epik mevcut deÄŸil."
msgid "Child epic doesn't exist."
-msgstr ""
+msgstr "Alt epik mevcut deÄŸil."
msgid "Choose %{strong_open}Create archive%{strong_close} and wait for archiving to complete."
msgstr ""
@@ -4958,6 +5109,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove variable"
+msgstr ""
+
msgid "CiVariables|Remove variable row"
msgstr "Değişken satırı kaldırın"
@@ -5036,9 +5190,6 @@ msgstr ""
msgid "Clear due date"
msgstr "BitiÅŸ tarihini temizle"
-msgid "Clear input"
-msgstr "GiriÅŸi temizle"
-
msgid "Clear recent searches"
msgstr "Son aramaları temizle"
@@ -5087,6 +5238,9 @@ msgstr "İstemci kimlik doğrulama anahtarı"
msgid "Client authentication key password"
msgstr "İstemci kimlik doğrulama anahtar parolası"
+msgid "Client request timeout"
+msgstr ""
+
msgid "Clients"
msgstr "Ä°stemciler"
@@ -5133,10 +5287,10 @@ msgid "Closed"
msgstr "Kapalı"
msgid "Closed %{epicTimeagoDate}"
-msgstr ""
+msgstr "%{epicTimeagoDate} kapatıldı"
msgid "Closed epics"
-msgstr ""
+msgstr "Epikler kapatıldı"
msgid "Closed issues"
msgstr "Kapalı sorunlar"
@@ -5171,6 +5325,27 @@ msgstr ""
msgid "Cluster type must be specificed for Stages::ClusterEndpointInserter"
msgstr ""
+msgid "ClusterAgents|Configuration"
+msgstr ""
+
+msgid "ClusterAgents|Connect your cluster with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate Kubernetes with a GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Name"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Agent also requires %{linkStart}enabling the Agent Server%{linkEnd}"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Kubernetes Agent allows an Infrastructure as Code, GitOps approach to integrating Kubernetes clusters with GitLab. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "ClusterAgent|This feature is only available for premium plans"
msgstr ""
@@ -5240,10 +5415,10 @@ msgstr ""
msgid "ClusterIntegration|All installed applications and related resources"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster."
+msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{linkStart}More information%{linkEnd}"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{startLink}More information%{endLink}"
+msgid "ClusterIntegration|Allow GitLab to manage namespaces and service accounts for this cluster."
msgstr ""
msgid "ClusterIntegration|Alternatively, "
@@ -5264,6 +5439,9 @@ msgstr "Projelerinizi almaya çalışırken bir hata oluştu: %{error}"
msgid "ClusterIntegration|An error occurred while trying to fetch zone machine types: %{error}"
msgstr "Bölge makine türlerini getirmeye çalışırken bir hata oluştu: %{error}"
+msgid "ClusterIntegration|An unknown error occurred while attempting to connect to Kubernetes."
+msgstr ""
+
msgid "ClusterIntegration|Any project namespaces"
msgstr ""
@@ -5279,6 +5457,9 @@ msgstr "AWS ile kimlik doğrulaması"
msgid "ClusterIntegration|Authenticate with Amazon Web Services"
msgstr "Amazon Web Servisleri ile kimlik doğrulaması"
+msgid "ClusterIntegration|Authentication Error"
+msgstr ""
+
msgid "ClusterIntegration|Base domain"
msgstr "Temel etki alanı"
@@ -5297,13 +5478,22 @@ msgstr ""
msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
msgstr "Sertifika Yetkilisi paketi (PEM biçiminde)"
-msgid "ClusterIntegration|Choose the %{startLink}security group %{externalLinkIcon} %{endLink} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
+msgid "ClusterIntegration|Check your CA certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Check your cluster status"
+msgstr ""
+
+msgid "ClusterIntegration|Check your token"
+msgstr ""
+
+msgid "ClusterIntegration|Choose the %{linkStart}security group %{linkEnd} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}subnets %{externalLinkIcon} %{endLink} in your VPC where your worker nodes will run."
+msgid "ClusterIntegration|Choose the %{linkStart}subnets %{linkEnd} in your VPC where your worker nodes will run."
msgstr ""
-msgid "ClusterIntegration|Choose the worker node %{startLink}instance type %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Choose the worker node %{linkStart}instance type%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Choose which applications to install on your Kubernetes cluster."
@@ -5315,10 +5505,7 @@ msgstr "Ortamlarınızdan hangisinin bu kümeyi kullanacağını seçin."
msgid "ClusterIntegration|Clear cluster cache"
msgstr ""
-msgid "ClusterIntegration|Clear the local cache of namespace and service accounts. This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
-msgstr ""
-
-msgid "ClusterIntegration|Cluster being created"
+msgid "ClusterIntegration|Clear the local cache of namespace and service accounts."
msgstr ""
msgid "ClusterIntegration|Cluster management project (alpha)"
@@ -5330,15 +5517,21 @@ msgstr "Küme ismi gerekli."
msgid "ClusterIntegration|Cluster_applications artifact too big. Maximum allowable size: %{human_size}"
msgstr ""
-msgid "ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters."
+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|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}"
+msgid "ClusterIntegration|Clusters connected with a certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Connect cluster with certificate"
msgstr ""
msgid "ClusterIntegration|Connect existing cluster"
msgstr ""
+msgid "ClusterIntegration|Connection Error"
+msgstr ""
+
msgid "ClusterIntegration|Copy API URL"
msgstr "API URL'sini Kopyala"
@@ -5394,7 +5587,7 @@ msgid "ClusterIntegration|Create cluster on"
msgstr ""
msgid "ClusterIntegration|Create new cluster"
-msgstr ""
+msgstr "Yeni küme oluştur"
msgid "ClusterIntegration|Create new cluster on EKS"
msgstr ""
@@ -5403,10 +5596,10 @@ msgid "ClusterIntegration|Create new cluster on GKE"
msgstr ""
msgid "ClusterIntegration|Creating Kubernetes cluster"
-msgstr ""
+msgstr "Kubernetes kümesi oluşturuluyor"
msgid "ClusterIntegration|Crossplane"
-msgstr ""
+msgstr "Crossplane"
msgid "ClusterIntegration|Crossplane enables declarative provisioning of managed services from your cloud of choice using %{codeStart}kubectl%{codeEnd} or %{linkStart}GitLab Integration%{linkEnd}. Crossplane runs inside your Kubernetes cluster and supports secure connectivity and secrets management between app containers and the cloud services they depend on."
msgstr ""
@@ -5414,6 +5607,12 @@ msgstr ""
msgid "ClusterIntegration|Deletes all GitLab resources attached to this cluster during removal"
msgstr ""
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared."
+msgstr ""
+
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared. %{linkStart}More information%{linkEnd}"
+msgstr ""
+
msgid "ClusterIntegration|Did you know?"
msgstr "Biliyor muydunuz?"
@@ -5478,11 +5677,14 @@ msgid "ClusterIntegration|Fetching zones"
msgstr "Alanlar getiriliyor"
msgid "ClusterIntegration|Fluentd"
-msgstr ""
+msgstr "Fluentd"
msgid "ClusterIntegration|Fluentd is an open source data collector, which lets you unify the data collection and consumption for a better use and understanding of data. It requires at least one of the following logs to be successfully installed."
msgstr ""
+msgid "ClusterIntegration|GitLab Agent managed clusters"
+msgstr ""
+
msgid "ClusterIntegration|GitLab Container Network Policies"
msgstr ""
@@ -5495,6 +5697,12 @@ msgstr "GitLab Çalıştırıcı"
msgid "ClusterIntegration|GitLab Runner connects to the repository and executes CI/CD jobs, pushing results back and deploying applications to production."
msgstr "GitLab Çalıştırıcı; depoya bağlanır ve CI/CD işlerini yürütür, sonuçları geri iter ve uygulamaları üretime dağıtır."
+msgid "ClusterIntegration|GitLab failed to authenticate."
+msgstr ""
+
+msgid "ClusterIntegration|GitLab failed to connect to the cluster."
+msgstr ""
+
msgid "ClusterIntegration|GitLab-managed cluster"
msgstr ""
@@ -5505,7 +5713,7 @@ msgid "ClusterIntegration|Google Cloud Platform project"
msgstr "Google Cloud Platform projesi"
msgid "ClusterIntegration|Google GKE"
-msgstr ""
+msgstr "Google GKE"
msgid "ClusterIntegration|Google Kubernetes Engine"
msgstr "Google Kubernetes Motoru"
@@ -5516,6 +5724,9 @@ msgstr "Google Kubernetes Motoru projesi"
msgid "ClusterIntegration|Group cluster"
msgstr "Grup kümesi"
+msgid "ClusterIntegration|HTTP Error"
+msgstr ""
+
msgid "ClusterIntegration|Helm Tiller"
msgstr "Helm Tiller"
@@ -5544,13 +5755,16 @@ msgid "ClusterIntegration|Installing Ingress may incur additional costs. Learn m
msgstr ""
msgid "ClusterIntegration|Instance cluster"
-msgstr ""
+msgstr "Örnek küme"
msgid "ClusterIntegration|Instance type"
+msgstr "Örnek türü"
+
+msgid "ClusterIntegration|Integrate Kubernetes with a cluster certificate"
msgstr ""
-msgid "ClusterIntegration|Integrate Kubernetes cluster automation"
-msgstr "Kubernetes küme otomasyonunu bütünleştir"
+msgid "ClusterIntegration|Integrate with a cluster certificate"
+msgstr ""
msgid "ClusterIntegration|Issuer Email"
msgstr "Yayınlayıcı e-postası"
@@ -5585,29 +5799,23 @@ msgstr ""
msgid "ClusterIntegration|Knative extends Kubernetes to provide a set of middleware components that are essential to build modern, source-centric, and container-based applications that can run anywhere: on premises, in the cloud, or even in a third-party data center."
msgstr ""
-msgid "ClusterIntegration|Kubernetes cluster"
-msgstr "Kubernetes kümesi"
-
msgid "ClusterIntegration|Kubernetes cluster is being created..."
-msgstr ""
+msgstr "Kubernetes kümesi oluşturuluyor..."
msgid "ClusterIntegration|Kubernetes cluster name"
msgstr "Kubernetes kümesi adı"
msgid "ClusterIntegration|Kubernetes cluster was successfully created."
-msgstr ""
+msgstr "Kubernetes kümesi başarıyla oluşturuldu."
msgid "ClusterIntegration|Kubernetes clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr "Kubernetes kümeleri; uygulamaları gözden geçirme özelliğini kullanmanıza, uygulamalarınızı yayınlamanıza, iş hattınızı çalıştırmanıza ve çok daha fazlasına kolay bir şekilde izin verir."
-msgid "ClusterIntegration|Kubernetes clusters can be used to deploy applications and to provide Review Apps for this project"
-msgstr "Kubernet kümeleri, uygulamaları dağıtmak ve bu proje için Gözden Geçirme Uygulamaları sağlamak için kullanılabilir"
-
msgid "ClusterIntegration|Kubernetes version"
-msgstr ""
+msgstr "Kubernetes sürümü"
msgid "ClusterIntegration|Kubernetes version not found"
-msgstr ""
+msgstr "Kubernetes sürümü bulunamadı"
msgid "ClusterIntegration|Learn more about %{help_link_start_machine_type}machine types%{help_link_end} and %{help_link_start_pricing}pricing%{help_link_end}."
msgstr ""
@@ -5615,7 +5823,7 @@ msgstr ""
msgid "ClusterIntegration|Learn more about %{help_link_start}zones%{help_link_end}."
msgstr ""
-msgid "ClusterIntegration|Learn more about %{startLink}Regions %{externalLinkIcon}%{endLink}."
+msgid "ClusterIntegration|Learn more about %{linkStart}Regions%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Learn more about Kubernetes"
@@ -5643,7 +5851,7 @@ msgid "ClusterIntegration|Loading instance types"
msgstr "Örnek türleri yükleniyor"
msgid "ClusterIntegration|Loading networks"
-msgstr ""
+msgstr "Ağlar yükleniyor"
msgid "ClusterIntegration|Loading security groups"
msgstr "Güvenlik grupları yükleniyor"
@@ -5660,12 +5868,18 @@ msgstr ""
msgid "ClusterIntegration|Machine type"
msgstr "Makine türü"
+msgid "ClusterIntegration|Make sure your API endpoint is correct"
+msgstr ""
+
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create Kubernetes clusters"
msgstr ""
msgid "ClusterIntegration|Manage your Kubernetes cluster by visiting %{provider_link}"
msgstr ""
+msgid "ClusterIntegration|Namespace per environment"
+msgstr ""
+
msgid "ClusterIntegration|No IAM Roles found"
msgstr ""
@@ -5697,7 +5911,7 @@ msgid "ClusterIntegration|No projects matched your search"
msgstr "Aramanız ile eşleşen bir proje yok"
msgid "ClusterIntegration|No region found"
-msgstr ""
+msgstr "Bölge bulunamadı"
msgid "ClusterIntegration|No security group found"
msgstr ""
@@ -5711,6 +5925,9 @@ msgstr ""
msgid "ClusterIntegration|No zones matched your search"
msgstr "Aramanızla hiçbir alan eşleşmedi"
+msgid "ClusterIntegration|Node calculations use the Kubernetes Metrics API. Make sure your cluster has metrics installed"
+msgstr ""
+
msgid "ClusterIntegration|Number of nodes"
msgstr ""
@@ -5727,7 +5944,7 @@ msgid "ClusterIntegration|Point a wildcard DNS to this generated endpoint in ord
msgstr ""
msgid "ClusterIntegration|Project cluster"
-msgstr ""
+msgstr "Proje kümesi"
msgid "ClusterIntegration|Project namespace (optional, unique)"
msgstr ""
@@ -5753,6 +5970,9 @@ msgstr ""
msgid "ClusterIntegration|RBAC-enabled cluster"
msgstr ""
+msgid "ClusterIntegration|Read our %{linkStart}help page%{linkEnd} on Kubernetes cluster integration."
+msgstr ""
+
msgid "ClusterIntegration|Read our %{link_start}help page%{link_end} on Kubernetes cluster integration."
msgstr ""
@@ -5829,7 +6049,7 @@ msgid "ClusterIntegration|Search projects"
msgstr "Projeleri ara"
msgid "ClusterIntegration|Search regions"
-msgstr ""
+msgstr "Bölgeleri ara"
msgid "ClusterIntegration|Search security groups"
msgstr "Güvenlik gruplarını ara"
@@ -5855,7 +6075,7 @@ msgstr ""
msgid "ClusterIntegration|Select a VPC to choose a subnet"
msgstr ""
-msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{linkStart}Amazon Web Services %{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select a network to choose a subnetwork"
@@ -5888,7 +6108,7 @@ msgstr "Makine türü seçimine göre alan ve proje seç"
msgid "ClusterIntegration|Select project to choose zone"
msgstr "Seçili alan için proje seç"
-msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select zone"
@@ -5978,9 +6198,18 @@ msgstr ""
msgid "ClusterIntegration|There was a problem authenticating with your cluster. Please ensure your CA Certificate and Token are valid."
msgstr ""
+msgid "ClusterIntegration|There was an HTTP error when connecting to your cluster."
+msgstr ""
+
msgid "ClusterIntegration|This account must have permissions to create a Kubernetes cluster in the %{link_to_container_project} specified below"
msgstr ""
+msgid "ClusterIntegration|This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
+msgstr ""
+
+msgid "ClusterIntegration|This is necessary to clear existing environment-namespace associations from clusters previously managed by GitLab."
+msgstr ""
+
msgid "ClusterIntegration|This option will allow you to install applications on RBAC clusters."
msgstr ""
@@ -6005,7 +6234,19 @@ msgstr ""
msgid "ClusterIntegration|To use a new project, first create one on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}."
msgstr ""
+msgid "ClusterIntegration|Troubleshooting tips:"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Authenticate"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Connect"
+msgstr ""
+
msgid "ClusterIntegration|Uninstall %{appTitle}"
+msgstr "%{appTitle} uygulamasını kaldır"
+
+msgid "ClusterIntegration|Unknown Error"
msgstr ""
msgid "ClusterIntegration|Update %{appTitle}"
@@ -6015,7 +6256,7 @@ msgid "ClusterIntegration|Update failed. Please check the logs and try again."
msgstr ""
msgid "ClusterIntegration|Use %{query}"
-msgstr ""
+msgstr "%{query} sorgusunu kullan"
msgid "ClusterIntegration|Uses the Cloud Run, Istio, and HTTP Load Balancing addons for this cluster."
msgstr ""
@@ -6068,7 +6309,7 @@ msgstr ""
msgid "ClusterIntegration|Your cluster API is unreachable. Please ensure your API URL is correct."
msgstr ""
-msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Zone"
@@ -6096,31 +6337,31 @@ msgid "ClusterIntergation|Select a network"
msgstr ""
msgid "ClusterIntergation|Select a region"
-msgstr ""
+msgstr "Bir bölge seçin"
msgid "ClusterIntergation|Select a security group"
-msgstr ""
+msgstr "Bir güvenlik grubu seçin"
msgid "ClusterIntergation|Select a subnet"
-msgstr ""
+msgstr "Bir alt ağ seçin"
msgid "ClusterIntergation|Select a subnetwork"
msgstr ""
msgid "ClusterIntergation|Select an instance type"
-msgstr ""
+msgstr "Bir örnek türü seçin"
msgid "ClusterIntergation|Select key pair"
-msgstr ""
+msgstr "Anahtar çifti seçin"
msgid "ClusterIntergation|Select service role"
-msgstr ""
+msgstr "Bir hizmet rolü seçin"
msgid "Clusters|An error occurred while loading clusters"
msgstr ""
msgid "Code"
-msgstr ""
+msgstr "Kod"
msgid "Code Coverage: %{coveragePercentage}%{percentSymbol}"
msgstr ""
@@ -6138,7 +6379,7 @@ msgid "Code Owners to the merge request changes."
msgstr ""
msgid "Code Quality"
-msgstr ""
+msgstr "Kod Kalitesi"
msgid "Code Review"
msgstr "Kod Ä°ncelemesi"
@@ -6153,7 +6394,7 @@ msgid "Code owner approval is required"
msgstr "Kod sahibi onayı gerekiyor"
msgid "Code owners"
-msgstr ""
+msgstr "Kod sahipleri"
msgid "CodeIntelligence|This is the definition"
msgstr ""
@@ -6162,7 +6403,7 @@ msgid "CodeNavigation|No references found"
msgstr ""
msgid "CodeOwner|Pattern"
-msgstr ""
+msgstr "Desen"
msgid "Cohorts"
msgstr ""
@@ -6174,13 +6415,13 @@ msgid "Cohorts|Month %{month_index}"
msgstr ""
msgid "Cohorts|New users"
-msgstr ""
+msgstr "Yeni kullanıcılar"
msgid "Cohorts|Registration month"
-msgstr ""
+msgstr "Kayıt ayı"
msgid "Cohorts|Returning users"
-msgstr ""
+msgstr "Geri dönen kullanıcılar"
msgid "Cohorts|User cohorts are shown for the last %{months_included} months. Only users with activity are counted in the 'New users' column; inactive users are counted separately."
msgstr ""
@@ -6188,6 +6429,9 @@ msgstr ""
msgid "Collapse"
msgstr "Daralt"
+msgid "Collapse all threads"
+msgstr ""
+
msgid "Collapse approvers"
msgstr "Onaylananları daralt"
@@ -6213,16 +6457,16 @@ msgid "Comma-separated, e.g. '1.1.1.1, 2.2.2.0/24'"
msgstr "Virgülle ayrılmış, örneğin '1.1.1.1, 2.2.2.0/24'"
msgid "Command"
-msgstr ""
+msgstr "Komut"
msgid "Command line instructions"
msgstr "Komut satırı talimatları"
msgid "Commands applied"
-msgstr ""
+msgstr "Komutlar uygulandı"
msgid "Commands did not apply"
-msgstr ""
+msgstr "Komutlar uygulanmadı"
msgid "Comment"
msgstr "Yorum"
@@ -6337,8 +6581,8 @@ msgstr "Ä°ÅŸleyen:"
msgid "Commit…"
msgstr ""
-msgid "Company"
-msgstr "Åžirket"
+msgid "Community forum"
+msgstr ""
msgid "Company name"
msgstr "Åžirket ismi"
@@ -6346,6 +6590,9 @@ msgstr "Åžirket ismi"
msgid "Compare"
msgstr "Karşılaştır"
+msgid "Compare %{oldCommitId}...%{newCommitId}"
+msgstr ""
+
msgid "Compare Git revisions"
msgstr "Git düzeltmelerini karşılaştır"
@@ -6361,6 +6608,9 @@ msgstr "Son işlem ile değişiklikleri karşılaştır"
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare submodule commit revisions"
+msgstr ""
+
msgid "Compare with previous version"
msgstr ""
@@ -6496,6 +6746,9 @@ msgstr ""
msgid "Configure the way a user creates a new account."
msgstr ""
+msgid "Configure which lists are shown for anyone who visits this board"
+msgstr ""
+
msgid "Confirm"
msgstr "Onayla"
@@ -6539,10 +6792,10 @@ msgid "Connect your external repositories, and CI/CD pipelines will run for new
msgstr ""
msgid "Connected"
-msgstr ""
+msgstr "Bağlandı"
msgid "Connecting"
-msgstr ""
+msgstr "Bağlanılıyor"
msgid "Connecting to terminal sync service"
msgstr ""
@@ -6554,7 +6807,7 @@ msgid "Connection failed"
msgstr "Bağlantı başarısız oldu"
msgid "Connection failure"
-msgstr ""
+msgstr "Bağlantı başarısız"
msgid "Connection timed out"
msgstr "Bağlantı zaman aşımına uğradı"
@@ -6715,12 +6968,15 @@ msgstr "Depoyu kaldır"
msgid "ContainerRegistry|Remove tag"
msgid_plural "ContainerRegistry|Remove tags"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "Etiketi kaldır"
+msgstr[1] "Etiketleri kaldır"
msgid "ContainerRegistry|Set cleanup policy"
msgstr ""
+msgid "ContainerRegistry|Some tags were not deleted"
+msgstr ""
+
msgid "ContainerRegistry|Something went wrong while fetching the cleanup policy."
msgstr ""
@@ -6760,6 +7016,9 @@ msgstr ""
msgid "ContainerRegistry|Tags with names matching this regex pattern will %{italicStart}expire:%{italicEnd}"
msgstr ""
+msgid "ContainerRegistry|The cleanup policy timed out before it could delete all tags. An administrator can %{adminLinkStart}manually run cleanup now%{adminLinkEnd} or you can wait for the cleanup policy to automatically run again. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "ContainerRegistry|The last tag related to this image was recently removed. This empty image and any associated data will be automatically removed as part of the regular Garbage Collection process. If you have any questions, contact your administrator."
msgstr ""
@@ -6875,7 +7134,7 @@ msgid "ContributionAnalytics|Last week"
msgstr "Geçen hafta"
msgid "ContributionAnalytics|Merge Requests"
-msgstr ""
+msgstr "BirleÅŸtirme Talepleri"
msgid "ContributionAnalytics|No issues for the selected time period."
msgstr ""
@@ -6892,6 +7151,9 @@ msgstr ""
msgid "Contributions per group member"
msgstr "Grup üyesi başına katkılar"
+msgid "Contributor"
+msgstr ""
+
msgid "Contributors"
msgstr "Katkıda Bulunanlar"
@@ -6902,7 +7164,7 @@ msgid "Control the display of third party offers."
msgstr ""
msgid "Cookie domain"
-msgstr ""
+msgstr "Çerez etki alanı"
msgid "Copied"
msgstr "Kopyalandı"
@@ -6926,10 +7188,10 @@ msgid "Copy %{type}"
msgstr ""
msgid "Copy Account ID to clipboard"
-msgstr ""
+msgstr "Hesap kimliÄŸini panoya kopyala"
msgid "Copy External ID to clipboard"
-msgstr ""
+msgstr "Harici kimliÄŸi panoya kopyala"
msgid "Copy ID"
msgstr "KimliÄŸi kopyala"
@@ -6986,7 +7248,7 @@ msgid "Copy link to chart"
msgstr "Bağlantıyı grafiğe kopyala"
msgid "Copy reference"
-msgstr ""
+msgstr "Referansı kopyala"
msgid "Copy secret"
msgstr ""
@@ -7021,6 +7283,9 @@ msgstr "Bu sohbet takma adı yetkilendirilemedi. Tekrar deneyin!"
msgid "Could not change HEAD: branch '%{branch}' does not exist"
msgstr ""
+msgid "Could not commit. An unexpected error occurred."
+msgstr ""
+
msgid "Could not connect to FogBugz, check your URL"
msgstr ""
@@ -7037,7 +7302,7 @@ msgid "Could not create environment"
msgstr "Ortam oluşturulamadı"
msgid "Could not create group"
-msgstr ""
+msgstr "Grup oluşturulamadı"
msgid "Could not create issue"
msgstr ""
@@ -7060,11 +7325,14 @@ msgstr ""
msgid "Could not find iteration"
msgstr ""
+msgid "Could not load instance counts. Please refresh the page to try again."
+msgstr ""
+
msgid "Could not remove the trigger."
msgstr ""
msgid "Could not restore the group"
-msgstr ""
+msgstr "Grup geri yüklenemedi"
msgid "Could not revoke impersonation token %{token_name}."
msgstr ""
@@ -7084,10 +7352,10 @@ msgstr ""
msgid "Could not save prometheus manual configuration"
msgstr ""
-msgid "Could not udpdate wiki page"
+msgid "Could not update the LDAP settings"
msgstr ""
-msgid "Could not update the LDAP settings"
+msgid "Could not update wiki page"
msgstr ""
msgid "Could not upload your designs as one or more files uploaded are not supported."
@@ -7120,7 +7388,7 @@ msgid "Create New Directory"
msgstr "Yeni Dizin OluÅŸtur"
msgid "Create New Domain"
-msgstr ""
+msgstr "Yeni Etki Alanı Oluştur"
msgid "Create Project"
msgstr "Proje OluÅŸtur"
@@ -7138,7 +7406,7 @@ msgid "Create a local proxy for storing frequently used upstream images. %{link_
msgstr ""
msgid "Create a merge request"
-msgstr ""
+msgstr "BirleÅŸtirme isteÄŸi oluÅŸtur"
msgid "Create a new branch"
msgstr "Yeni bir dal oluÅŸtur"
@@ -7354,7 +7622,7 @@ msgid "Creating"
msgstr "OluÅŸturuluyor"
msgid "Creating epic"
-msgstr ""
+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 ""
@@ -7453,28 +7721,28 @@ msgid "Custom project templates have not been set up for groups that you are a m
msgstr ""
msgid "Custom range"
-msgstr ""
+msgstr "Özel aralık"
msgid "Custom range (UTC)"
msgstr ""
msgid "CustomCycleAnalytics|Add a stage"
-msgstr ""
+msgstr "AÅŸama ekle"
msgid "CustomCycleAnalytics|Add stage"
-msgstr ""
+msgstr "AÅŸama ekle"
msgid "CustomCycleAnalytics|Editing stage"
-msgstr ""
+msgstr "Düzenleme aşaması"
msgid "CustomCycleAnalytics|Enter a name for the stage"
-msgstr ""
+msgstr "Aşama için bir isim girin"
msgid "CustomCycleAnalytics|Name"
-msgstr ""
+msgstr "Ä°sim"
msgid "CustomCycleAnalytics|New stage"
-msgstr ""
+msgstr "Yeni aÅŸama"
msgid "CustomCycleAnalytics|Please select a start event first"
msgstr ""
@@ -7552,7 +7820,7 @@ msgid "CycleAnalyticsEvent|Issue closed"
msgstr "Sorun kapatıldı"
msgid "CycleAnalyticsEvent|Issue created"
-msgstr ""
+msgstr "Sorun oluÅŸturuldu"
msgid "CycleAnalyticsEvent|Issue first added to a board"
msgstr ""
@@ -7745,6 +8013,9 @@ msgstr ""
msgid "DastProfiles|Are you sure you want to delete this profile?"
msgstr ""
+msgid "DastProfiles|Could not create site validation token. Please refresh the page, or try again later."
+msgstr ""
+
msgid "DastProfiles|Could not create the scanner profile. Please try again."
msgstr ""
@@ -7769,6 +8040,12 @@ msgstr ""
msgid "DastProfiles|Could not fetch site profiles. Please refresh the page, or try again later."
msgstr ""
+msgid "DastProfiles|Could not retrieve site validation status. Please refresh the page, or try again later."
+msgstr ""
+
+msgid "DastProfiles|Could not update the scanner profile. Please try again."
+msgstr ""
+
msgid "DastProfiles|Could not update the site profile. Please try again."
msgstr ""
@@ -7784,7 +8061,7 @@ msgstr ""
msgid "DastProfiles|Download validation text file"
msgstr ""
-msgid "DastProfiles|Edit feature will come soon. Please create a new profile if changes needed"
+msgid "DastProfiles|Edit scanner profile"
msgstr ""
msgid "DastProfiles|Edit site profile"
@@ -7817,6 +8094,9 @@ msgstr ""
msgid "DastProfiles|No profiles created yet"
msgstr ""
+msgid "DastProfiles|Passive"
+msgstr ""
+
msgid "DastProfiles|Please enter a valid URL format, ex: http://www.example.com/home"
msgstr ""
@@ -7832,6 +8112,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan mode"
+msgstr ""
+
msgid "DastProfiles|Scanner Profile"
msgstr ""
@@ -7871,10 +8154,10 @@ msgstr ""
msgid "DastProfiles|Text file validation"
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
+msgid "DastProfiles|The maximum number of minutes allowed for the spider to traverse the site."
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the spider to traverse the site."
+msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
msgstr ""
msgid "DastProfiles|Validate"
@@ -7907,6 +8190,9 @@ msgstr ""
msgid "Date picker"
msgstr "Tarih seçici"
+msgid "Date range"
+msgstr ""
+
msgid "Date range cannot exceed %{maxDateRange} days."
msgstr "Tarih aralığı %{maxDateRange} günü aşamaz."
@@ -7931,6 +8217,9 @@ msgstr ""
msgid "Days to merge"
msgstr ""
+msgid "Dear Administrator,"
+msgstr ""
+
msgid "Debug"
msgstr ""
@@ -8042,12 +8331,18 @@ msgstr ""
msgid "Delete"
msgstr "Sil"
+msgid "Delete %{name}"
+msgstr ""
+
msgid "Delete Comment"
msgstr "Yorumu sil"
msgid "Delete Snippet"
msgstr "Parçacığı Sil"
+msgid "Delete Value Stream"
+msgstr ""
+
msgid "Delete account"
msgstr ""
@@ -8069,9 +8364,6 @@ msgstr "Etiketi sil"
msgid "Delete label: %{label_name} ?"
msgstr "%{label_name} etiketi silinsin mi?"
-msgid "Delete license"
-msgstr "Lisansı sil"
-
msgid "Delete list"
msgstr "Listeyi sil"
@@ -8147,15 +8439,6 @@ msgstr "Siliniyor"
msgid "Deleting a project places it into a read-only state until %{date}, at which point the project will be permanently deleted. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "Deleting the license failed."
-msgstr ""
-
-msgid "Deleting the license failed. The license was not found."
-msgstr ""
-
-msgid "Deleting the license failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "Deleting the project will delete its repository and all related resources including issues, merge requests etc."
msgstr ""
@@ -8349,7 +8632,7 @@ msgid "DeployKeys|Error getting deploy keys"
msgstr ""
msgid "DeployKeys|Error removing deploy key"
-msgstr ""
+msgstr "Dağıtım anahtarı kaldırılırken hata oluştu"
msgid "DeployKeys|Expand %{count} other projects"
msgstr ""
@@ -8651,7 +8934,10 @@ msgstr "Tümünü seç"
msgid "DesignManagement|The maximum number of designs allowed to be uploaded is %{upload_limit}. Please try again."
msgstr ""
-msgid "DesignManagement|To upload designs, you'll need to enable LFS. %{requirements_link_start}More information%{requirements_link_end}"
+msgid "DesignManagement|There was an error moving your designs. Please upload your designs below."
+msgstr ""
+
+msgid "DesignManagement|To upload designs, you'll need to enable LFS and have admin enable hashed storage. %{requirements_link_start}More information%{requirements_link_end}"
msgstr ""
msgid "DesignManagement|Unresolve thread"
@@ -8663,6 +8949,9 @@ msgstr ""
msgid "DesignManagement|Upload skipped."
msgstr ""
+msgid "DesignManagement|Your designs are being copied and are on their way… Please refresh to update."
+msgstr ""
+
msgid "DesignManagement|and %{moreCount} more."
msgstr ""
@@ -8720,6 +9009,9 @@ msgstr ""
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr "Değişiklik çizgileri alırken bir şeyler ters gitti."
+msgid "Direct member"
+msgstr ""
+
msgid "Direction"
msgstr ""
@@ -8768,9 +9060,6 @@ msgstr "%{path} yolundaki değişiklikler yok sayılsın mı?"
msgid "Discard draft"
msgstr ""
-msgid "Discard review"
-msgstr ""
-
msgid "DiscordService|Discord Notifications"
msgstr "Discord Bildirimleri"
@@ -8839,10 +9128,10 @@ msgstr ""
msgid "Dismiss Merge Request promotion"
msgstr ""
-msgid "Dismiss Selected"
+msgid "Dismiss Value Stream Analytics introduction box"
msgstr ""
-msgid "Dismiss Value Stream Analytics introduction box"
+msgid "Dismiss selected"
msgstr ""
msgid "Dismiss trial promotion"
@@ -8893,9 +9182,6 @@ msgstr ""
msgid "Documents reindexed: %{processed_documents} (%{percentage}%%)"
msgstr ""
-msgid "Doing"
-msgstr ""
-
msgid "Domain"
msgstr ""
@@ -9091,9 +9377,6 @@ msgstr "Açıklamayı düzenle"
msgid "Edit environment"
msgstr "Ortamı düzenle"
-msgid "Edit file"
-msgstr "Dosyayı düzenle"
-
msgid "Edit files in the editor and commit changes here"
msgstr ""
@@ -9106,6 +9389,12 @@ msgstr "Grubu düzenle: %{group_name}"
msgid "Edit identity for %{user_name}"
msgstr ""
+msgid "Edit in Web IDE"
+msgstr ""
+
+msgid "Edit in single-file editor"
+msgstr ""
+
msgid "Edit issues"
msgstr "Sorunları düzenle"
@@ -9133,21 +9422,18 @@ msgstr "%{timeago} düzenlendi"
msgid "Editing"
msgstr "Düzenleme"
-msgid "Elasticsearch"
-msgstr "Esnek arama"
-
msgid "Elasticsearch AWS IAM credentials"
msgstr ""
+msgid "Elasticsearch HTTP client timeout value in seconds."
+msgstr ""
+
msgid "Elasticsearch indexing restrictions"
msgstr ""
msgid "Elasticsearch indexing started"
msgstr ""
-msgid "Elasticsearch integration. Elasticsearch AWS IAM."
-msgstr "Esnek arama bütünleşmesi. Esnek arama AWS IAM."
-
msgid "Elasticsearch reindexing is already in progress"
msgstr ""
@@ -9175,9 +9461,6 @@ msgstr ""
msgid "Email Notification"
msgstr ""
-msgid "Email address"
-msgstr "E-posta adresi"
-
msgid "Email could not be sent"
msgstr ""
@@ -9241,6 +9524,9 @@ msgstr "E-postalar"
msgid "Emails sent from Service Desk will have this name"
msgstr ""
+msgid "Emails sent to %{email} will still be supported"
+msgstr ""
+
msgid "Emails separated by comma"
msgstr ""
@@ -9274,9 +9560,18 @@ msgstr "BoÅŸ dosya"
msgid "Enable"
msgstr "EtkinleÅŸtir"
+msgid "Enable %{link_start}Gitpod%{link_end} integration to launch a development environment in your browser directly from GitLab."
+msgstr ""
+
msgid "Enable Auto DevOps"
msgstr ""
+msgid "Enable Gitpod"
+msgstr ""
+
+msgid "Enable Gitpod?"
+msgstr ""
+
msgid "Enable HTML emails"
msgstr "HTML e-postalarını etkinleştir"
@@ -9406,9 +9701,6 @@ msgstr ""
msgid "Encountered an error while rendering: %{err}"
msgstr ""
-msgid "End date"
-msgstr ""
-
msgid "Ends at (UTC)"
msgstr ""
@@ -9568,7 +9860,7 @@ msgstr "Kaldır"
msgid "EnvironmentsDashboard|The environments dashboard provides a summary of each project's environments' status, including pipeline and alert statuses."
msgstr ""
-msgid "EnvironmentsDashboard|This dashboard displays a maximum of 7 projects and 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
+msgid "EnvironmentsDashboard|This dashboard displays 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
msgstr ""
msgid "Environments|An error occurred while canceling the auto stop, please try again"
@@ -9749,40 +10041,40 @@ msgid "Environments|protected"
msgstr ""
msgid "Epic"
-msgstr ""
+msgstr "Epik"
msgid "Epic cannot be found."
-msgstr ""
+msgstr "Epik bulunamıyor."
msgid "Epic events"
-msgstr ""
+msgstr "Epik olayları"
msgid "Epic not found for given params"
-msgstr ""
+msgstr "Verilen parametrelerle epik bulunamadı"
msgid "Epics"
-msgstr ""
+msgstr "Epikler"
msgid "Epics Roadmap"
-msgstr ""
+msgstr "Epiklerin Yol Haritası"
msgid "Epics and Issues"
-msgstr ""
+msgstr "Epikler ve Sorunlar"
msgid "Epics let you manage your portfolio of projects more efficiently and with less effort"
-msgstr ""
+msgstr "Epikler, proje portföyünüzü daha verimli ve daha az çaba ile yönetmenizi sağlar"
msgid "Epics, Issues, and Merge Requests"
msgstr "Epikler, Sorunlar ve BirleÅŸtirme Ä°stekleri"
msgid "Epics|Add a new epic"
-msgstr ""
+msgstr "Yeni epik ekle"
msgid "Epics|Add an existing epic"
-msgstr ""
+msgstr "Mevcut bir epiÄŸi ekle"
msgid "Epics|An error occurred while saving the %{epicDateType} date"
-msgstr ""
+msgstr "%{epicDateType} tarihini kaydederken bir hata oluÅŸtu"
msgid "Epics|An error occurred while updating labels."
msgstr ""
@@ -9794,7 +10086,7 @@ msgid "Epics|Enter a title for your epic"
msgstr ""
msgid "Epics|How can I solve this?"
-msgstr ""
+msgstr "Bunu nasıl çözebilirim?"
msgid "Epics|Leave empty to inherit from milestone dates"
msgstr ""
@@ -9803,37 +10095,37 @@ msgid "Epics|More information"
msgstr "Daha fazla bilgi"
msgid "Epics|Remove epic"
-msgstr ""
+msgstr "EpiÄŸi sil"
msgid "Epics|Remove issue"
-msgstr ""
+msgstr "Sorunu sil"
msgid "Epics|Show more"
msgstr "Daha fazlasını göster"
msgid "Epics|Something went wrong while assigning issue to epic."
-msgstr ""
+msgstr "Epiğe sorun atama sırasında bir şeyler ters gitti."
msgid "Epics|Something went wrong while creating child epics."
-msgstr ""
+msgstr "Alt epikler oluÅŸturulurken bir ÅŸeyler ters gitti."
msgid "Epics|Something went wrong while creating issue."
-msgstr ""
+msgstr "Sorun oluştururken birşeyler yanlış gitti."
msgid "Epics|Something went wrong while fetching child epics."
-msgstr ""
+msgstr "Alt epikler alınırken bir şeyler ters gitti."
msgid "Epics|Something went wrong while fetching group epics."
-msgstr ""
+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 ""
+msgstr "Öge sıralanırken bir şeyler ters gitti."
msgid "Epics|Something went wrong while removing issue from epic."
-msgstr ""
+msgstr "Epikten sorun kaldırılırken bir şeyler ters gitti."
msgid "Epics|These dates affect how your epics appear in the roadmap. Dates from milestones come from the milestones assigned to issues in the epic. You can also set fixed dates or remove them entirely."
msgstr ""
@@ -9842,7 +10134,7 @@ msgid "Epics|This epic and any containing child epics are confidential and shoul
msgstr ""
msgid "Epics|This will also remove any descendents of %{bStart}%{targetEpicTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}. Are you sure?"
-msgstr ""
+msgstr "Bu aynı zamanda %{bStart}%{targetEpicTitle}%{bEnd} epiğinin alt öğelerini %{bStart}%{parentEpicTitle}%{bEnd} epiğinden kaldırır. Emin misiniz?"
msgid "Epics|To schedule your epic's %{epicDateType} date based on milestones, assign a milestone with a %{epicDateType} date to any issue in the epic."
msgstr ""
@@ -9854,7 +10146,7 @@ msgid "Epics|Unable to save epic. Please try again"
msgstr ""
msgid "Epics|due"
-msgstr ""
+msgstr "süresi dolmuş"
msgid "Epics|start"
msgstr ""
@@ -9869,7 +10161,7 @@ msgid "Error Tracking"
msgstr ""
msgid "Error creating epic"
-msgstr ""
+msgstr "Epik oluÅŸtururken hata oluÅŸtu"
msgid "Error creating label."
msgstr "Etiket ayarlanırken hata oluştu"
@@ -9889,6 +10181,9 @@ msgstr ""
msgid "Error deleting project. Check logs for error details."
msgstr ""
+msgid "Error fetching burnup chart data"
+msgstr ""
+
msgid "Error fetching diverging counts for branches. Please try again."
msgstr ""
@@ -9967,6 +10262,9 @@ msgstr "Kenar çubuğu verileri alınırken hata oluştu"
msgid "Error occurred when saving assignees"
msgstr "Vekiller kaydedilirken bir hata oluÅŸtu"
+msgid "Error occurred when saving reviewers"
+msgstr ""
+
msgid "Error occurred when toggling the notification subscription"
msgstr "Bildirim aboneliÄŸini deÄŸiÅŸtirirken bir sorun meydana geldi"
@@ -10219,12 +10517,15 @@ msgstr "GeniÅŸlet"
msgid "Expand all"
msgstr "Tümünü genişlet"
+msgid "Expand all files"
+msgstr ""
+
+msgid "Expand all threads"
+msgstr ""
+
msgid "Expand approvers"
msgstr "Onaylayanları genişlet"
-msgid "Expand dropdown"
-msgstr "Açılır listeyi genişlet"
-
msgid "Expand milestones"
msgstr ""
@@ -10393,6 +10694,9 @@ msgstr ""
msgid "Failed to create Merge Request. Please try again."
msgstr ""
+msgid "Failed to create To-Do for the design."
+msgstr ""
+
msgid "Failed to create a branch for this issue. Please try again."
msgstr ""
@@ -10432,6 +10736,12 @@ msgstr ""
msgid "Failed to load authors. Please try again."
msgstr ""
+msgid "Failed to load branches. Please try again."
+msgstr ""
+
+msgid "Failed to load deploy keys."
+msgstr ""
+
msgid "Failed to load emoji list."
msgstr ""
@@ -10447,6 +10757,9 @@ msgstr ""
msgid "Failed to load groups & users."
msgstr ""
+msgid "Failed to load groups, users and deploy keys."
+msgstr ""
+
msgid "Failed to load labels. Please try again."
msgstr ""
@@ -10456,6 +10769,12 @@ msgstr ""
msgid "Failed to load related branches"
msgstr "İlgili dalların yüklenmesi başarısız oldu"
+msgid "Failed to load sidebar confidential toggle"
+msgstr ""
+
+msgid "Failed to load sidebar lock status"
+msgstr ""
+
msgid "Failed to load stacktrace."
msgstr ""
@@ -10483,6 +10802,9 @@ msgstr ""
msgid "Failed to publish issue on status page."
msgstr ""
+msgid "Failed to remove To-Do for the design."
+msgstr ""
+
msgid "Failed to remove a Zoom meeting"
msgstr ""
@@ -10525,6 +10847,9 @@ msgstr ""
msgid "Failed to signing using smartcard authentication"
msgstr ""
+msgid "Failed to toggle To-Do for the design."
+msgstr ""
+
msgid "Failed to update branch!"
msgstr ""
@@ -10638,7 +10963,7 @@ msgstr ""
msgid "FeatureFlags|Edit User List"
msgstr ""
-msgid "FeatureFlags|Enable features for specific users and specific environments by defining feature flag strategies."
+msgid "FeatureFlags|Enable features for specific users and environments by configuring feature flag strategies."
msgstr ""
msgid "FeatureFlags|Environment Spec"
@@ -10698,7 +11023,7 @@ msgstr ""
msgid "FeatureFlags|Include additional user IDs"
msgstr ""
-msgid "FeatureFlags|Install a %{docs_link_anchored_start}compatible client library%{docs_link_anchored_end} and specify the API URL, application name, and instance ID during the configuration setup. %{docs_link_start}More Information%{docs_link_end}"
+msgid "FeatureFlags|Install a %{docsLinkAnchoredStart}compatible client library%{docsLinkAnchoredEnd} and specify the API URL, application name, and instance ID during the configuration setup. %{docsLinkStart}More Information%{docsLinkEnd}"
msgstr ""
msgid "FeatureFlags|Instance ID"
@@ -10710,6 +11035,9 @@ msgstr ""
msgid "FeatureFlags|Loading feature flags"
msgstr ""
+msgid "FeatureFlags|Loading user lists"
+msgstr ""
+
msgid "FeatureFlags|More information"
msgstr "Daha fazla bilgi"
@@ -10728,8 +11056,8 @@ msgstr ""
msgid "FeatureFlags|New feature flag"
msgstr "Yeni özellik bayrağı"
-msgid "FeatureFlags|New list"
-msgstr "Yeni liste"
+msgid "FeatureFlags|New user list"
+msgstr ""
msgid "FeatureFlags|Percent of users"
msgstr ""
@@ -10767,6 +11095,9 @@ msgstr "Hedef ortamlar"
msgid "FeatureFlags|There was an error fetching the feature flags."
msgstr ""
+msgid "FeatureFlags|There was an error fetching the user lists."
+msgstr ""
+
msgid "FeatureFlags|There was an error retrieving user lists"
msgstr "Kullanıcı listeleri geri alınırken bir hata oluştu"
@@ -10782,6 +11113,9 @@ msgstr "Kullanıcı Kimlikleri"
msgid "FeatureFlags|User List"
msgstr ""
+msgid "FeatureFlags|User Lists"
+msgstr ""
+
msgid "FeatureFlag|List"
msgstr "Liste"
@@ -10809,15 +11143,6 @@ msgstr "Åžubat"
msgid "Fetching incoming email"
msgstr ""
-msgid "Fetching licenses failed."
-msgstr ""
-
-msgid "Fetching licenses failed. The request endpoint was not found."
-msgstr ""
-
-msgid "Fetching licenses failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "File"
msgstr "Dosya"
@@ -10920,12 +11245,21 @@ msgstr ""
msgid "Filter by status"
msgstr "Duruma göre filtrele"
+msgid "Filter by test cases that are currently archived."
+msgstr ""
+
+msgid "Filter by test cases that are currently opened."
+msgstr ""
+
msgid "Filter by two-factor authentication"
msgstr "İki adımlı kimlik doğrulamasına göre süz"
msgid "Filter by user"
msgstr "Kullanıcıya göre filtrele"
+msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
+msgstr ""
+
msgid "Filter pipelines"
msgstr ""
@@ -10941,8 +11275,8 @@ msgstr "Projeye göre sonuçları süz"
msgid "Filter results..."
msgstr "Sonuçları filtrele..."
-msgid "Filter your projects by name"
-msgstr "Projelerinizi isme göre filtreleyin"
+msgid "Filter your repositories by name"
+msgstr ""
msgid "Filter..."
msgstr "Süzgeç..."
@@ -10950,7 +11284,7 @@ msgstr "Süzgeç..."
msgid "Find File"
msgstr ""
-msgid "Find bugs in your code with coverage-guided fuzzing"
+msgid "Find bugs in your code with coverage-guided fuzzing."
msgstr ""
msgid "Find by path"
@@ -10977,9 +11311,6 @@ msgstr ""
msgid "Finish editing this message first!"
msgstr ""
-msgid "Finish review"
-msgstr ""
-
msgid "Finish setting up your dedicated account for %{group_name}."
msgstr ""
@@ -11049,6 +11380,9 @@ msgstr "Yazı Tipi Rengi"
msgid "Footer message"
msgstr "Altbilgi mesajı"
+msgid "For a faster browsing experience, some files are collapsed by default."
+msgstr ""
+
msgid "For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
@@ -11058,6 +11392,9 @@ msgstr ""
msgid "For more info, read the documentation."
msgstr "Daha fazla bilgi için belgeyi okuyun."
+msgid "For more information on how the number of active users is calculated, see the %{self_managed_subscriptions_doc_link} documentation."
+msgstr ""
+
msgid "For more information, go to the "
msgstr "Daha fazla bilgi için şu adrese gidin: "
@@ -11196,6 +11533,9 @@ msgstr ""
msgid "Generate new token"
msgstr ""
+msgid "Generic package file size in bytes"
+msgstr ""
+
msgid "Geo"
msgstr "CoÄŸrafi"
@@ -11272,7 +11612,7 @@ msgid "GeoNodes|Node was successfully removed."
msgstr ""
msgid "GeoNodes|Node's status was updated %{timeAgo}."
-msgstr ""
+msgstr "%{timeAgo} düğümün durumu güncellendi."
msgid "GeoNodes|Pausing replication stops the sync process. Are you sure?"
msgstr ""
@@ -11457,6 +11797,9 @@ msgstr "DoÄŸrulama bekliyor"
msgid "Geo|Please refer to Geo Troubleshooting."
msgstr ""
+msgid "Geo|Primary node"
+msgstr ""
+
msgid "Geo|Project"
msgstr "Proje"
@@ -11499,6 +11842,9 @@ msgstr ""
msgid "Geo|Review replication status, and resynchronize and reverify items with the primary node."
msgstr ""
+msgid "Geo|Secondary node"
+msgstr ""
+
msgid "Geo|Status"
msgstr "Durum"
@@ -11538,6 +11884,9 @@ msgstr ""
msgid "Geo|URL must be a valid url (ex: https://gitlab.com)"
msgstr ""
+msgid "Geo|Undefined"
+msgstr ""
+
msgid "Geo|Unknown state"
msgstr "Bilinmeyen konum"
@@ -11613,10 +11962,16 @@ msgstr ""
msgid "GitHub import"
msgstr "GitHub içe aktarma"
+msgid "GitLab"
+msgstr ""
+
msgid "GitLab / Unsubscribe"
msgstr ""
-msgid "GitLab Enterprise Edition %{plan}"
+msgid "GitLab API"
+msgstr ""
+
+msgid "GitLab Billing Team."
msgstr ""
msgid "GitLab Group Runners can execute code for all the projects in this group."
@@ -11628,12 +11983,18 @@ msgstr "GitLab içe aktarma"
msgid "GitLab Issue"
msgstr "GitLab Sorunu"
+msgid "GitLab Pages"
+msgstr ""
+
msgid "GitLab Service Desk is a simple way to allow people to create issues in your GitLab instance without needing their own user account. It provides a unique email address for end users to create issues in a project, and replies can be sent either through the GitLab interface or by email. End users will only see the thread through email."
msgstr ""
msgid "GitLab Shared Runners execute code of different projects on the same Runner unless you configure GitLab Runner Autoscale with MaxBuilds 1 (which it is on GitLab.com)."
msgstr ""
+msgid "GitLab Shell"
+msgstr ""
+
msgid "GitLab Support Bot"
msgstr ""
@@ -11643,7 +12004,7 @@ msgstr ""
msgid "GitLab User"
msgstr ""
-msgid "GitLab allows you to continue using your license even if you exceed the number of seats you purchased. You will be required to pay for these seats when you renew your license."
+msgid "GitLab Workhorse"
msgstr ""
msgid "GitLab commit"
@@ -11811,6 +12172,21 @@ msgstr "Gitea içe aktarma"
msgid "Gitlab Pages"
msgstr "GitLab Sayfaları"
+msgid "Gitpod"
+msgstr ""
+
+msgid "Gitpod|Add the URL to your Gitpod instance configured to read your GitLab projects."
+msgstr ""
+
+msgid "Gitpod|Enable Gitpod integration"
+msgstr ""
+
+msgid "Gitpod|Gitpod URL"
+msgstr ""
+
+msgid "Gitpod|e.g. https://gitpod.example.com"
+msgstr ""
+
msgid "Given access %{time_ago}"
msgstr "%{time_ago} eriÅŸim verildi"
@@ -12196,7 +12572,7 @@ msgid "GroupRoadmap|No start date – %{dateWord}"
msgstr ""
msgid "GroupRoadmap|Something went wrong while fetching epics"
-msgstr ""
+msgstr "Epikler alınırken bir şeyler ters gitti"
msgid "GroupRoadmap|Something went wrong while fetching milestones"
msgstr ""
@@ -12205,7 +12581,7 @@ msgid "GroupRoadmap|Sorry, no epics matched your search"
msgstr "Üzgünüz, aramanızla eşleşen bir epik yok"
msgid "GroupRoadmap|The roadmap shows the progress of your epics along a timeline"
-msgstr ""
+msgstr "Yol haritası, epiklerinizin bir zaman çizelgesi boyunca ilerlemesini gösterir"
msgid "GroupRoadmap|To view the roadmap, add a start or due date to one of the %{linkStart}child epics%{linkEnd}."
msgstr ""
@@ -12318,9 +12694,6 @@ msgstr "SAML kimlik doğrulamasını aç/kapat"
msgid "GroupSAML|Valid SAML Response"
msgstr ""
-msgid "GroupSAML|With group managed accounts enabled, all the users without a group managed account will be excluded from the group."
-msgstr ""
-
msgid "GroupSAML|With prohibit outer forks flag enabled group members will be able to fork project only inside your group."
msgstr ""
@@ -12534,12 +12907,12 @@ msgstr "OluÅŸtur"
msgid "GroupsNew|Create group"
msgstr "Grup oluÅŸtur"
-msgid "GroupsNew|GitLab group export"
-msgstr "GitLab grubunu dışa aktar"
-
msgid "GroupsNew|Import"
msgstr "İçe aktar"
+msgid "GroupsNew|Import a GitLab group export file"
+msgstr ""
+
msgid "GroupsNew|Import group"
msgstr "Grubu içe aktar"
@@ -12680,6 +13053,9 @@ msgid_plural "Hide charts"
msgstr[0] ""
msgstr[1] ""
+msgid "Hide comments on this file"
+msgstr ""
+
msgid "Hide details"
msgstr ""
@@ -12724,6 +13100,15 @@ msgstr ""
msgid "Highest role:"
msgstr "En yüksek rol:"
+msgid "HighlightBar|Alert events:"
+msgstr ""
+
+msgid "HighlightBar|Alert start time:"
+msgstr ""
+
+msgid "HighlightBar|Original alert:"
+msgstr ""
+
msgid "History"
msgstr "Geçmiş"
@@ -12901,6 +13286,9 @@ msgstr ""
msgid "If enabled, access to projects will be validated on an external service using their classification label."
msgstr ""
+msgid "If the number of active users exceeds the user limit, you will be charged for the number of %{users_over_license_link} at your next license reconciliation."
+msgstr ""
+
msgid "If there is no previous license or if the previous license has expired, some GitLab functionality will be blocked until a new, valid license is uploaded."
msgstr ""
@@ -12940,9 +13328,6 @@ msgstr ""
msgid "If your HTTP repository is not publicly accessible, add your credentials."
msgstr ""
-msgid "Iglu registry URL (optional)"
-msgstr ""
-
msgid "Ignore"
msgstr ""
@@ -12979,6 +13364,16 @@ msgstr ""
msgid "Import"
msgstr "İçe Aktar"
+msgid "Import %d compatible repository"
+msgid_plural "Import %d compatible repositories"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Import %d repository"
+msgid_plural "Import %d repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Import CSV"
msgstr "CSV'yi içe aktar"
@@ -12988,15 +13383,9 @@ msgstr "Gitea'dan projeleri içe aktar"
msgid "Import all compatible projects"
msgstr ""
-msgid "Import all compatible repositories"
-msgstr ""
-
msgid "Import all projects"
msgstr "Tüm projeleri içe aktar"
-msgid "Import all repositories"
-msgstr ""
-
msgid "Import an exported GitLab project"
msgstr ""
@@ -13084,6 +13473,9 @@ msgstr ""
msgid "ImportProjects|Error importing repository %{project_safe_import_url} into %{project_full_path} - %{message}"
msgstr ""
+msgid "ImportProjects|Import repositories"
+msgstr ""
+
msgid "ImportProjects|Importing the project failed"
msgstr ""
@@ -13096,8 +13488,8 @@ msgstr ""
msgid "ImportProjects|Requesting your %{provider} repositories failed"
msgstr ""
-msgid "ImportProjects|Select the projects you want to import"
-msgstr "Almak istediğiniz projeleri seçin"
+msgid "ImportProjects|Select the repositories you want to import"
+msgstr ""
msgid "ImportProjects|The remote data could not be imported."
msgstr ""
@@ -13132,9 +13524,6 @@ msgstr ""
msgid "In order to enable Service Desk for your instance, you must first set up incoming email."
msgstr ""
-msgid "In order to gather accurate feature usage data, it can take 1 to 2 weeks to see your index."
-msgstr ""
-
msgid "In order to personalize your experience with GitLab%{br_tag}we would like to know a bit more about you."
msgstr ""
@@ -13165,18 +13554,30 @@ msgstr ""
msgid "IncidentManagement|Create incident"
msgstr ""
+msgid "IncidentManagement|Critical - S1"
+msgstr ""
+
msgid "IncidentManagement|Date created"
msgstr ""
msgid "IncidentManagement|Display your incidents in a dedicated view"
msgstr ""
+msgid "IncidentManagement|High - S2"
+msgstr ""
+
msgid "IncidentManagement|Incident"
msgstr ""
msgid "IncidentManagement|Incidents"
msgstr ""
+msgid "IncidentManagement|Low - S4"
+msgstr ""
+
+msgid "IncidentManagement|Medium - S3"
+msgstr ""
+
msgid "IncidentManagement|No incidents to display."
msgstr ""
@@ -13189,6 +13590,9 @@ msgstr ""
msgid "IncidentManagement|Published to status page"
msgstr ""
+msgid "IncidentManagement|Severity"
+msgstr ""
+
msgid "IncidentManagement|There are no closed incidents"
msgstr ""
@@ -13198,6 +13602,9 @@ msgstr ""
msgid "IncidentManagement|Unassigned"
msgstr ""
+msgid "IncidentManagement|Unknown"
+msgstr ""
+
msgid "IncidentManagement|Unpublished"
msgstr ""
@@ -13219,6 +13626,15 @@ msgstr ""
msgid "Incidents"
msgstr ""
+msgid "Incident|Alert details"
+msgstr ""
+
+msgid "Incident|Summary"
+msgstr ""
+
+msgid "Incident|There was an issue loading alert data. Please try again."
+msgstr ""
+
msgid "Include a Terms of Service agreement and Privacy Policy that all users must accept."
msgstr ""
@@ -13279,6 +13695,9 @@ msgstr ""
msgid "Information about additional Pages templates and how to install them can be found in our %{pages_getting_started_guide}."
msgstr ""
+msgid "Inherited"
+msgstr ""
+
msgid "Inherited:"
msgstr ""
@@ -13359,7 +13778,22 @@ msgstr ""
msgid "Instance administrators group already exists"
msgstr ""
-msgid "Instance license"
+msgid "InstanceStatistics|Groups"
+msgstr ""
+
+msgid "InstanceStatistics|Issues"
+msgstr ""
+
+msgid "InstanceStatistics|Merge Requests"
+msgstr ""
+
+msgid "InstanceStatistics|Pipelines"
+msgstr ""
+
+msgid "InstanceStatistics|Projects"
+msgstr ""
+
+msgid "InstanceStatistics|Users"
msgstr ""
msgid "Integration"
@@ -13371,6 +13805,12 @@ msgstr ""
msgid "Integrations"
msgstr "Entegrasyonlar"
+msgid "Integrations|%{integration} settings saved and active."
+msgstr ""
+
+msgid "Integrations|%{integration} settings saved, but not active."
+msgstr ""
+
msgid "Integrations|All details"
msgstr "Tüm ayrıntılar"
@@ -13380,6 +13820,12 @@ msgstr "Yorum ayrıntıları:"
msgid "Integrations|Comment settings:"
msgstr "Yorum ayarları:"
+msgid "Integrations|Connection failed. Please check your settings."
+msgstr ""
+
+msgid "Integrations|Connection successful."
+msgstr ""
+
msgid "Integrations|Default settings are inherited from the group level."
msgstr ""
@@ -13395,6 +13841,15 @@ msgstr ""
msgid "Integrations|Includes commit title and branch"
msgstr ""
+msgid "Integrations|Projects using custom settings will not be impacted unless the project owner chooses to use instance-level defaults."
+msgstr ""
+
+msgid "Integrations|Save settings?"
+msgstr ""
+
+msgid "Integrations|Saving will update the default settings for all projects that are not using custom settings."
+msgstr ""
+
msgid "Integrations|Standard"
msgstr "Standart"
@@ -13527,6 +13982,9 @@ msgstr ""
msgid "Invitation"
msgstr ""
+msgid "Invitation declined"
+msgstr ""
+
msgid "Invite"
msgstr "Davet et"
@@ -13578,6 +14036,42 @@ 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|%{linkStart}Read more%{linkEnd} about role permissions"
+msgstr ""
+
+msgid "InviteMembersModal|Access expiration date (optional)"
+msgstr ""
+
+msgid "InviteMembersModal|Cancel"
+msgstr ""
+
+msgid "InviteMembersModal|Choose a role permission"
+msgstr ""
+
+msgid "InviteMembersModal|GitLab member or Email address"
+msgstr ""
+
+msgid "InviteMembersModal|Invite"
+msgstr ""
+
+msgid "InviteMembersModal|Invite team members"
+msgstr ""
+
+msgid "InviteMembersModal|Search for members to invite"
+msgstr ""
+
+msgid "InviteMembersModal|User not invited. Feature coming soon!"
+msgstr ""
+
+msgid "InviteMembersModal|Users were succesfully added"
+msgstr ""
+
+msgid "InviteMembersModal|You're inviting members to the %{group_name} group"
+msgstr ""
+
+msgid "InviteMembers|Invite team members"
+msgstr ""
+
msgid "Invited"
msgstr ""
@@ -13615,7 +14109,7 @@ msgid "IssuableStatus|promoted"
msgstr ""
msgid "Issue"
-msgstr ""
+msgstr "Konu"
msgid "Issue %{issue_reference} has already been added to epic %{epic_reference}."
msgstr ""
@@ -13632,10 +14126,13 @@ msgstr ""
msgid "Issue cannot be found."
msgstr ""
+msgid "Issue created from vulnerability %{vulnerability_link}"
+msgstr ""
+
msgid "Issue events"
msgstr "Sorun etkinlikleri"
-msgid "Issue first depoloyed to production"
+msgid "Issue first deployed to production"
msgstr ""
msgid "Issue label"
@@ -13713,6 +14210,9 @@ msgstr ""
msgid "IssueTracker|Custom issue tracker"
msgstr ""
+msgid "IssueTracker|EWM work items tracker"
+msgstr ""
+
msgid "IssueTracker|Redmine issue tracker"
msgstr ""
@@ -13779,6 +14279,9 @@ msgstr "Başlık"
msgid "It looks like you have some draft commits in this branch."
msgstr ""
+msgid "It may be several days before you see feature usage data."
+msgstr ""
+
msgid "It must have a header row and at least two columns: the first column is the issue title and the second column is the issue description. The separator is automatically detected."
msgstr ""
@@ -14061,15 +14564,15 @@ msgstr ""
msgid "Join Zoom meeting"
msgstr ""
+msgid "Joined %{time_ago}"
+msgstr ""
+
msgid "Jul"
msgstr "Tem"
msgid "July"
msgstr "Temmuz"
-msgid "Jump to first unresolved thread"
-msgstr ""
-
msgid "Jump to next unresolved thread"
msgstr ""
@@ -14103,6 +14606,9 @@ msgstr ""
msgid "Keyboard shortcuts"
msgstr "Klavye kısayolları"
+msgid "KeyboardKey|Ctrl+"
+msgstr ""
+
msgid "Keys"
msgstr ""
@@ -14151,6 +14657,9 @@ msgstr ""
msgid "LDAP Synchronization"
msgstr ""
+msgid "LDAP group settings"
+msgstr ""
+
msgid "LDAP settings"
msgstr "LDAP ayarları"
@@ -14160,6 +14669,9 @@ msgstr ""
msgid "LDAP sync in progress. This could take a few minutes. Refresh the page to see the changes."
msgstr "LDAP eşitlemesi devam ediyor. Bu birkaç dakika sürebilir. Değişiklikleri görmek için sayfayı yenileyin."
+msgid "LDAP synchronizations"
+msgstr ""
+
msgid "LFS"
msgstr ""
@@ -14240,7 +14752,16 @@ msgid_plural "Last %d days"
msgstr[0] "Son %d gün"
msgstr[1] "Son %d gün"
-msgid "Last %{days} days"
+msgid "Last 2 weeks"
+msgstr ""
+
+msgid "Last 30 days"
+msgstr ""
+
+msgid "Last 60 days"
+msgstr ""
+
+msgid "Last 90 days"
msgstr ""
msgid "Last Accessed On"
@@ -14318,6 +14839,9 @@ msgstr "Son kullanılan"
msgid "Last used on:"
msgstr "Son kullanım:"
+msgid "Last week"
+msgstr ""
+
msgid "LastCommit|authored"
msgstr "oluÅŸturdu:"
@@ -14333,6 +14857,9 @@ msgstr ""
msgid "Latest pipeline for the most recent commit on this branch"
msgstr ""
+msgid "Launch a ready-to-code development environment for your project."
+msgstr ""
+
msgid "Lead"
msgstr ""
@@ -14713,6 +15240,9 @@ msgstr ""
msgid "List of all merge commits"
msgstr ""
+msgid "List options"
+msgstr ""
+
msgid "List settings"
msgstr ""
@@ -14725,9 +15255,6 @@ msgstr ""
msgid "List your Bitbucket Server repositories"
msgstr ""
-msgid "Lists"
-msgstr ""
-
msgid "Live preview"
msgstr "Canlı önizleme"
@@ -14974,6 +15501,12 @@ msgstr "Yapılacakları yapıldı olarak işaretle"
msgid "Mark as done"
msgstr "Bitti olarak iÅŸaretle"
+msgid "Mark as draft"
+msgstr ""
+
+msgid "Mark as ready"
+msgstr ""
+
msgid "Mark as resolved"
msgstr ""
@@ -14995,6 +15528,24 @@ msgstr "Biçimlendirme etkin"
msgid "Markdown is supported"
msgstr "Biçimlendirme desteklenmektedir"
+msgid "MarkdownEditor|Add a link (%{modifierKey}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add a link (%{modifier_key}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifierKey}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifier_key}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifierKey}I)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifier_key}I)"
+msgstr ""
+
msgid "Marked For Deletion At - %{deletion_time}"
msgstr ""
@@ -15079,7 +15630,25 @@ msgstr ""
msgid "Max access level"
msgstr ""
-msgid "Max seats used"
+msgid "Max role"
+msgstr ""
+
+msgid "Max size 15 MB"
+msgstr ""
+
+msgid "Maximum Conan package file size in bytes"
+msgstr ""
+
+msgid "Maximum Maven package file size in bytes"
+msgstr ""
+
+msgid "Maximum NPM package file size in bytes"
+msgstr ""
+
+msgid "Maximum NuGet package file size in bytes"
+msgstr ""
+
+msgid "Maximum PyPI package file size in bytes"
msgstr ""
msgid "Maximum Users:"
@@ -15211,6 +15780,18 @@ msgstr ""
msgid "Members with access to %{strong_start}%{group_name}%{strong_end}"
msgstr ""
+msgid "Members|%{time} by %{user}"
+msgstr ""
+
+msgid "Members|Expired"
+msgstr ""
+
+msgid "Members|No expiration set"
+msgstr ""
+
+msgid "Members|in %{time}"
+msgstr ""
+
msgid "Memory Usage"
msgstr ""
@@ -15397,9 +15978,6 @@ msgstr ""
msgid "MergeRequests|Thread will be unresolved"
msgstr ""
-msgid "MergeRequests|Toggle comments for this file"
-msgstr "Bu dosya için yorumları aç/kapat"
-
msgid "MergeRequests|View file @ %{commitId}"
msgstr "Dosyayı göster @ %{commitId}"
@@ -15460,6 +16038,9 @@ msgstr ""
msgid "Merging immediately isn't recommended as it may negatively impact the existing merge train. Read the %{docsLinkStart}documentation%{docsLinkEnd} for more information."
msgstr ""
+msgid "Message"
+msgstr ""
+
msgid "Messages"
msgstr "Mesajlar"
@@ -15845,18 +16426,12 @@ msgid_plural "Milestones"
msgstr[0] ""
msgstr[1] ""
-msgid "Milestone does not support burnup charts"
-msgstr ""
-
msgid "Milestone lists not available with your current license"
msgstr ""
msgid "Milestone lists show all issues from the selected milestone."
msgstr ""
-msgid "Milestone must have a start and due date"
-msgstr ""
-
msgid "MilestoneSidebar|Closed:"
msgstr ""
@@ -16223,6 +16798,9 @@ msgstr "Ä°sim:"
msgid "Namespace"
msgstr ""
+msgid "Namespace ID:"
+msgstr ""
+
msgid "Namespace is empty"
msgstr ""
@@ -16307,6 +16885,9 @@ msgstr ""
msgid "NetworkPolicies|Allow all outbound traffic from %{selector} to %{ruleSelector} on %{ports}"
msgstr ""
+msgid "NetworkPolicies|Are you sure you want to delete this policy? This action cannot be undone."
+msgstr ""
+
msgid "NetworkPolicies|Choose whether to enforce this policy."
msgstr ""
@@ -16316,12 +16897,21 @@ msgstr ""
msgid "NetworkPolicies|Define this policy's location, conditions and actions."
msgstr ""
+msgid "NetworkPolicies|Delete policy"
+msgstr ""
+
+msgid "NetworkPolicies|Delete policy: %{policy}"
+msgstr ""
+
msgid "NetworkPolicies|Deny all traffic"
msgstr ""
msgid "NetworkPolicies|Description"
msgstr ""
+msgid "NetworkPolicies|Edit policy"
+msgstr ""
+
msgid "NetworkPolicies|Editor mode"
msgstr ""
@@ -16349,6 +16939,9 @@ msgstr ""
msgid "NetworkPolicies|Name"
msgstr ""
+msgid "NetworkPolicies|Namespace"
+msgstr ""
+
msgid "NetworkPolicies|Network Policy"
msgstr ""
@@ -16400,6 +16993,9 @@ msgstr ""
msgid "NetworkPolicies|Rules"
msgstr ""
+msgid "NetworkPolicies|Save changes"
+msgstr ""
+
msgid "NetworkPolicies|Something went wrong, failed to update policy"
msgstr ""
@@ -16412,6 +17008,9 @@ msgstr "Durum"
msgid "NetworkPolicies|Traffic that does not match any rule will be blocked."
msgstr ""
+msgid "NetworkPolicies|Unable to parse policy"
+msgstr ""
+
msgid "NetworkPolicies|YAML editor"
msgstr ""
@@ -16476,7 +17075,7 @@ msgid "New Environment"
msgstr "Yeni Ortam"
msgid "New Epic"
-msgstr ""
+msgstr "Yeni Epik"
msgid "New File"
msgstr ""
@@ -16525,6 +17124,9 @@ msgstr ""
msgid "New Snippet"
msgstr "Yeni Parçacık"
+msgid "New Test Case"
+msgstr ""
+
msgid "New User"
msgstr ""
@@ -16556,7 +17158,7 @@ msgid "New epic"
msgstr "Yeni epik"
msgid "New epic title"
-msgstr ""
+msgstr "Yeni epik başlığı"
msgid "New file"
msgstr "Yeni dosya"
@@ -16624,6 +17226,9 @@ msgstr "Yeni alt grup"
msgid "New tag"
msgstr "Yeni etiket"
+msgid "New test case"
+msgstr ""
+
msgid "New users set to external"
msgstr "Yeni kullanıcılar harici olarak ayarlandı"
@@ -16664,7 +17269,7 @@ msgid "No %{providerTitle} repositories found"
msgstr ""
msgid "No Epic"
-msgstr ""
+msgstr "Epik Yok"
msgid "No Matching Results"
msgstr ""
@@ -16696,7 +17301,7 @@ msgstr "Dal bulunamadı"
msgid "No changes"
msgstr "DeÄŸiÅŸiklik yok"
-msgid "No changes between %{ref_start}%{source_branch}%{ref_end} and %{ref_start}%{target_branch}%{ref_end}"
+msgid "No changes between %{sourceBranch} and %{targetBranch}"
msgstr ""
msgid "No child epics match applied filters"
@@ -16711,6 +17316,9 @@ msgstr ""
msgid "No containers available"
msgstr ""
+msgid "No content to show"
+msgstr ""
+
msgid "No contributions"
msgstr ""
@@ -16786,9 +17394,6 @@ msgstr ""
msgid "No license. All rights reserved"
msgstr ""
-msgid "No licenses found."
-msgstr ""
-
msgid "No matches found"
msgstr ""
@@ -16801,6 +17406,9 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No members found"
+msgstr ""
+
msgid "No merge requests found"
msgstr "Birleştirme isteği bulunamadı"
@@ -16822,6 +17430,9 @@ msgstr ""
msgid "No parent group"
msgstr ""
+msgid "No plan"
+msgstr ""
+
msgid "No pods available"
msgstr ""
@@ -16918,6 +17529,12 @@ msgstr "Yok"
msgid "Not Implemented"
msgstr ""
+msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+msgstr ""
+
+msgid "Not all browsers support WebAuthn. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even from an unsupported browser."
+msgstr ""
+
msgid "Not all data has been processed yet, the accuracy of the chart for the selected timeframe is limited."
msgstr ""
@@ -17014,6 +17631,9 @@ msgstr "Bildirim ayarı - %{notification_title}"
msgid "Notification settings saved"
msgstr "Bildirim ayarları kaydedildi"
+msgid "NotificationEvent|Change reviewer merge request"
+msgstr ""
+
msgid "NotificationEvent|Close issue"
msgstr "Sorunu kapat"
@@ -17176,10 +17796,7 @@ msgstr ""
msgid "On track"
msgstr ""
-msgid "OnDemandScans|Attached branch"
-msgstr ""
-
-msgid "OnDemandScans|Attached branch is where the scan job runs."
+msgid "OnDemandScans|Could not fetch scanner profiles. Please refresh the page, or try again later."
msgstr ""
msgid "OnDemandScans|Could not fetch site profiles. Please refresh the page, or try again later."
@@ -17188,6 +17805,9 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
+msgid "OnDemandScans|Create a new scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Create a new site profile"
msgstr ""
@@ -17200,6 +17820,9 @@ msgstr ""
msgid "OnDemandScans|New on-demand DAST scan"
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 ""
@@ -17209,16 +17832,10 @@ msgstr ""
msgid "OnDemandScans|On-demand scans run outside the DevOps cycle and find vulnerabilities in your projects. %{learnMoreLinkStart}Learn more%{learnMoreLinkEnd}"
msgstr ""
-msgid "OnDemandScans|Only a passive scan can be performed on demand."
-msgstr ""
-
-msgid "OnDemandScans|Passive"
-msgstr ""
-
msgid "OnDemandScans|Run scan"
msgstr ""
-msgid "OnDemandScans|Scan mode"
+msgid "OnDemandScans|Scanner profile"
msgstr ""
msgid "OnDemandScans|Scanner settings"
@@ -17230,9 +17847,15 @@ msgstr ""
msgid "OnDemandScans|Select one of the existing profiles"
msgstr ""
+msgid "OnDemandScans|Site profile"
+msgstr ""
+
msgid "OnDemandScans|Site profiles"
msgstr ""
+msgid "OnDemandScans|Use existing scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Use existing site profile"
msgstr ""
@@ -17331,9 +17954,6 @@ msgstr "Açık"
msgid "Open Selection"
msgstr "Seçimi Aç"
-msgid "Open Web IDE"
-msgstr ""
-
msgid "Open comment type dropdown"
msgstr "Yorum türü açılır penceresini aç"
@@ -17371,7 +17991,7 @@ msgid "Opened"
msgstr "Açıldı"
msgid "Opened %{epicTimeagoDate}"
-msgstr ""
+msgstr "%{epicTimeagoDate} açıldı"
msgid "Opened MRs"
msgstr ""
@@ -17439,6 +18059,9 @@ msgstr ""
msgid "Origin"
msgstr ""
+msgid "Orphaned member"
+msgstr ""
+
msgid "Other Labels"
msgstr "DiÄŸer Etiketler"
@@ -17454,6 +18077,9 @@ msgstr ""
msgid "Other visibility settings have been disabled by the administrator."
msgstr "Diğer görünürlük ayarları yönetici tarafından devre dışı bırakıldı."
+msgid "Our documentation includes an example DevOps Score report."
+msgstr ""
+
msgid "Out-of-compliance with this project's policies and should be removed"
msgstr ""
@@ -17478,6 +18104,9 @@ msgstr "Genel bakış"
msgid "Overwrite diverged branches"
msgstr ""
+msgid "Owned by %{image_tag}"
+msgstr ""
+
msgid "Owned by anyone"
msgstr ""
@@ -17499,6 +18128,9 @@ msgstr ""
msgid "Package deleted successfully"
msgstr ""
+msgid "Package file size limits"
+msgstr ""
+
msgid "Package recipe already exists"
msgstr ""
@@ -17514,9 +18146,6 @@ msgstr ""
msgid "Package type must be PyPi"
msgstr ""
-msgid "Package was removed"
-msgstr ""
-
msgid "PackageRegistry|%{name} version %{version} was created %{datetime}"
msgstr ""
@@ -17658,12 +18287,18 @@ msgstr ""
msgid "PackageRegistry|NuGet Command"
msgstr ""
+msgid "PackageRegistry|Package Registry"
+msgstr ""
+
msgid "PackageRegistry|Pip Command"
msgstr ""
msgid "PackageRegistry|Pipeline %{link} triggered %{datetime} by %{author}"
msgstr ""
+msgid "PackageRegistry|Publish and share packages for a variety of common package managers. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "PackageRegistry|Published to the %{project} Package Registry %{datetime}"
msgstr ""
@@ -17763,6 +18398,9 @@ msgstr ""
msgid "Page not found"
msgstr ""
+msgid "Page settings"
+msgstr ""
+
msgid "Page was successfully deleted"
msgstr ""
@@ -17836,10 +18474,10 @@ msgid "Parent"
msgstr ""
msgid "Parent epic doesn't exist."
-msgstr ""
+msgstr "Ãœst epik yok."
msgid "Parent epic is not present."
-msgstr ""
+msgstr "Ãœst epik mevcut deÄŸil."
msgid "Parsing error for param :embed_json. %{message}"
msgstr ""
@@ -17899,12 +18537,12 @@ msgid "Paste confidential issue link"
msgstr ""
msgid "Paste epic link"
-msgstr ""
+msgstr "Epik bağlantısını yapıştır"
msgid "Paste issue link"
msgstr ""
-msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Don't use your private SSH key."
+msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Do not paste your private SSH key, as that can compromise your identity."
msgstr ""
msgid "Patch to apply"
@@ -17931,6 +18569,9 @@ msgstr ""
msgid "Pending"
msgstr ""
+msgid "Pending comments"
+msgstr ""
+
msgid "People without permission will never get a notification and won't be able to comment."
msgstr ""
@@ -18129,6 +18770,9 @@ msgstr ""
msgid "Pipelines|Build with confidence"
msgstr ""
+msgid "Pipelines|By revoking a trigger you will break any processes making use of it. Are you sure?"
+msgstr ""
+
msgid "Pipelines|CI Lint"
msgstr ""
@@ -18141,6 +18785,15 @@ msgstr ""
msgid "Pipelines|Continuous Integration can help catch bugs by running your tests automatically, while Continuous Deployment can help you deliver code to your product environment."
msgstr ""
+msgid "Pipelines|Copy trigger token"
+msgstr ""
+
+msgid "Pipelines|Description"
+msgstr ""
+
+msgid "Pipelines|Edit"
+msgstr ""
+
msgid "Pipelines|Get started with Pipelines"
msgstr ""
@@ -18156,15 +18809,27 @@ msgstr ""
msgid "Pipelines|It is recommended the code is reviewed thoroughly before running this pipeline with the parent project's CI resource."
msgstr ""
+msgid "Pipelines|Last Used"
+msgstr ""
+
msgid "Pipelines|Loading Pipelines"
msgstr "İş Hatları Yükleniyor"
msgid "Pipelines|More Information"
msgstr ""
+msgid "Pipelines|No triggers have been created yet. Add one using the form above."
+msgstr ""
+
+msgid "Pipelines|Owner"
+msgstr ""
+
msgid "Pipelines|Project cache successfully reset."
msgstr ""
+msgid "Pipelines|Revoke"
+msgstr ""
+
msgid "Pipelines|Run Pipeline"
msgstr ""
@@ -18189,6 +18854,15 @@ msgstr ""
msgid "Pipelines|This project is not currently set up to run pipelines."
msgstr ""
+msgid "Pipelines|Token"
+msgstr ""
+
+msgid "Pipelines|Trigger user has insufficient permissions to project"
+msgstr ""
+
+msgid "Pipelines|invalid"
+msgstr ""
+
msgid "Pipelines|parent"
msgstr ""
@@ -18447,10 +19121,10 @@ msgstr ""
msgid "Please provide attributes to update"
msgstr ""
-msgid "Please refer to %{docs_url}"
+msgid "Please reach out if you have any questions and we'll be happy to assist."
msgstr ""
-msgid "Please retype the email address."
+msgid "Please refer to %{docs_url}"
msgstr ""
msgid "Please select"
@@ -18480,6 +19154,9 @@ msgstr ""
msgid "Please set a new password before proceeding."
msgstr "Lütfen devam etmeden önce yeni bir şifre belirleyin."
+msgid "Please share your feedback about %{featureName} %{linkStart}in this issue%{linkEnd} to help us improve the experience."
+msgstr ""
+
msgid "Please solve the reCAPTCHA"
msgstr "Lütfen reCAPTCHA'yı çözün"
@@ -18783,6 +19460,9 @@ msgstr ""
msgid "Profiles| You are going to change the username %{currentUsernameBold} to %{newUsernameBold}. Profile and projects will be redirected to the %{newUsername} namespace but this redirect will expire once the %{currentUsername} namespace is registered by another user or group. Please update your Git repository remotes as soon as possible."
msgstr ""
+msgid "Profiles|%{provider} Active"
+msgstr ""
+
msgid "Profiles|@username"
msgstr "@kullanıcıadı"
@@ -18834,8 +19514,8 @@ msgstr "Aşağıdaki hizmetlerden biriyle giriş yapmak için simgeye tıklayın
msgid "Profiles|Commit email"
msgstr "İşlem e-postası"
-msgid "Profiles|Connect"
-msgstr "BaÄŸlan"
+msgid "Profiles|Connect %{provider}"
+msgstr ""
msgid "Profiles|Connected Accounts"
msgstr "Bağlı Hesaplar"
@@ -18858,6 +19538,9 @@ msgstr "Bir hesabı silmek aşağıdaki etkilere sahiptir:"
msgid "Profiles|Disconnect"
msgstr "Bağlantıyı kes"
+msgid "Profiles|Disconnect %{provider}"
+msgstr ""
+
msgid "Profiles|Do not show on profile"
msgstr "Profilde gösterme"
@@ -18882,7 +19565,7 @@ msgstr "Besleme erişim anahtarı başarıyla sıfırlandı"
msgid "Profiles|Full name"
msgstr "Tam isim"
-msgid "Profiles|Give your individual key a title. This will be publically visible."
+msgid "Profiles|Give your individual key a title."
msgstr ""
msgid "Profiles|Include private contributions on my profile"
@@ -18972,8 +19655,8 @@ msgstr ""
msgid "Profiles|The maximum file size allowed is 200KB."
msgstr "İzin verilen en yüksek dosya boyutu 200KB'dır."
-msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it?"
-msgstr "Bu, genel bir SSH anahtarına benzemiyor. Eklemek istediğinizden emin misiniz?"
+msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it? It will be publicly visible."
+msgstr ""
msgid "Profiles|This email will be displayed on your public profile"
msgstr "Bu e-posta, herkese açık profilinizde gösterilecek"
@@ -19047,6 +19730,9 @@ msgstr "Profil resminizi buraya yükleyebilir veya %{gravatar_link} adresinden d
msgid "Profiles|You don't have access to delete this user."
msgstr "Bu kullanıcıyı silme yetkiniz yok."
+msgid "Profiles|You must transfer ownership or delete groups you are an owner of before you can delete your account"
+msgstr ""
+
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr "Hesabınızı silmeden önce sahipliği devretmeniz veya bu grupları silmeniz gerekir."
@@ -19635,6 +20321,9 @@ msgstr "Android"
msgid "ProjectTemplates|GitLab Cluster Management"
msgstr ""
+msgid "ProjectTemplates|Gitpod/Spring Petclinic"
+msgstr ""
+
msgid "ProjectTemplates|Go Micro"
msgstr ""
@@ -19981,7 +20670,7 @@ msgid "Promote confidential issue to a non-confidential epic"
msgstr ""
msgid "Promote issue to an epic"
-msgstr ""
+msgstr "Sorunu bir epiğe yükselt"
msgid "Promote to group label"
msgstr "Grup etiketini tanıtın"
@@ -19999,7 +20688,7 @@ msgid "Promoted confidential issue to a non-confidential epic. Information in th
msgstr ""
msgid "Promoted issue to an epic."
-msgstr ""
+msgstr "Sorun bir epiğe yükseltildi."
msgid "Promotion is not supported."
msgstr ""
@@ -20244,6 +20933,9 @@ msgstr ""
msgid "Publish to status page"
msgstr ""
+msgid "Published"
+msgstr ""
+
msgid "Published on status page"
msgstr ""
@@ -20361,9 +21053,15 @@ msgstr ""
msgid "Quick range"
msgstr ""
+msgid "Quickly and easily edit multiple files in your project."
+msgstr ""
+
msgid "README"
msgstr "BENÄ°OKU"
+msgid "Rails"
+msgstr ""
+
msgid "Rake Tasks Help"
msgstr ""
@@ -20483,10 +21181,13 @@ msgstr "Kaydol / Oturum Aç"
msgid "Register Two-Factor Authenticator"
msgstr ""
-msgid "Register U2F device"
+msgid "Register Universal Two-Factor (U2F) Device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register WebAuthn Device"
+msgstr ""
+
+msgid "Register device"
msgstr ""
msgid "Register for GitLab"
@@ -20498,9 +21199,6 @@ msgstr ""
msgid "Register with two-factor app"
msgstr ""
-msgid "Registration"
-msgstr ""
-
msgid "Registration|Checkout"
msgstr ""
@@ -20617,9 +21315,6 @@ msgstr ""
msgid "Release|Something went wrong while saving the release details"
msgstr ""
-msgid "Remediated: needs review"
-msgstr ""
-
msgid "Remediations"
msgstr ""
@@ -20693,7 +21388,7 @@ msgid "Remove from board"
msgstr ""
msgid "Remove from epic"
-msgstr ""
+msgstr "Epikten kaldır"
msgid "Remove group"
msgstr ""
@@ -20717,7 +21412,7 @@ msgid "Remove node"
msgstr ""
msgid "Remove parent epic from an epic"
-msgstr ""
+msgstr "Bir epikten üst epiği kaldır"
msgid "Remove primary node"
msgstr ""
@@ -20725,6 +21420,9 @@ msgstr ""
msgid "Remove priority"
msgstr ""
+msgid "Remove report"
+msgstr ""
+
msgid "Remove secondary node"
msgstr ""
@@ -20737,6 +21435,12 @@ msgstr ""
msgid "Remove time estimate"
msgstr ""
+msgid "Remove user & report"
+msgstr ""
+
+msgid "Remove user from group"
+msgstr ""
+
msgid "Removed"
msgstr ""
@@ -20744,7 +21448,7 @@ msgid "Removed %{assignee_text} %{assignee_references}."
msgstr ""
msgid "Removed %{epic_ref} from child epics."
-msgstr ""
+msgstr "Alt epiklerden %{epic_ref} kaldırıldı."
msgid "Removed %{iteration_reference} iteration."
msgstr ""
@@ -20762,13 +21466,13 @@ msgid "Removed all labels."
msgstr ""
msgid "Removed an issue from an epic."
-msgstr ""
+msgstr "Epikten bir sorun kaldırıldı."
msgid "Removed group can not be restored!"
msgstr ""
msgid "Removed parent epic %{epic_ref}."
-msgstr ""
+msgstr "Üst epik %{epic_ref} kaldırıldı."
msgid "Removed spent time."
msgstr ""
@@ -20789,7 +21493,7 @@ msgid "Removes %{assignee_text} %{assignee_references}."
msgstr ""
msgid "Removes %{epic_ref} from child epics."
-msgstr ""
+msgstr "Alt epiklerden %{epic_ref} kaldırır."
msgid "Removes %{iteration_reference} iteration."
msgstr ""
@@ -20804,10 +21508,10 @@ msgid "Removes all labels."
msgstr ""
msgid "Removes an issue from an epic."
-msgstr ""
+msgstr "Epikten bir sorunu kaldırır."
msgid "Removes parent epic %{epic_ref}."
-msgstr ""
+msgstr "Üst epik %{epic_ref} kaldırır."
msgid "Removes spent time."
msgstr ""
@@ -20818,9 +21522,6 @@ msgstr "Bitiş tarihini kaldırır."
msgid "Removes time estimate."
msgstr ""
-msgid "Removing license…"
-msgstr ""
-
msgid "Removing this group also removes all child projects, including archived projects, and their resources."
msgstr ""
@@ -20840,7 +21541,7 @@ msgid "Reopen %{display_issuable_type}"
msgstr ""
msgid "Reopen epic"
-msgstr ""
+msgstr "Epiği yeniden aç"
msgid "Reopen milestone"
msgstr ""
@@ -20905,6 +21606,9 @@ msgstr "Kötüye kullanımı yöneticiye bildir"
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr "%{reportedBy} tarafından %{timeAgo} bildirildi"
+msgid "Reported by %{reporter}"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -20991,6 +21695,27 @@ msgstr "deÄŸiÅŸtirilmiÅŸ test sonucu yok"
msgid "Repositories"
msgstr ""
+msgid "Repositories Analytics"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download Historic Test Coverage Data"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download historic test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Historic Test Coverage Data is available in raw format (.csv) for further analysis."
+msgstr ""
+
+msgid "RepositoriesAnalytics|Test Code Coverage"
+msgstr ""
+
+msgid "RepositoriesAnalytics|There was an error fetching the projects."
+msgstr ""
+
msgid "Repository"
msgstr "Depo"
@@ -21069,9 +21794,15 @@ msgstr ""
msgid "Request parameter %{param} is missing."
msgstr ""
+msgid "Request review from"
+msgstr ""
+
msgid "Request to link SAML account must be authorized"
msgstr ""
+msgid "Requested"
+msgstr ""
+
msgid "Requested %{time_ago}"
msgstr "%{time_ago} istendi"
@@ -21090,6 +21821,9 @@ msgstr "Profil Ä°stekleri"
msgid "Requests to these domain(s)/address(es) on the local network will be allowed when local requests from hooks and services are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 or 127.0.0.0/28 are supported. Domain wildcards are not supported currently. Use comma, semicolon, or newline to separate multiple entries. The allowlist can hold a maximum of 1000 entries. Domains should use IDNA encoding. Ex: example.com, 192.168.1.1, 127.0.0.0/28, xn--itlab-j1a.com."
msgstr ""
+msgid "Require admin approval for new sign-ups"
+msgstr ""
+
msgid "Require all users in this group to setup Two-factor authentication"
msgstr ""
@@ -21217,9 +21951,6 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr "%{name} tarafından çözüldü"
-msgid "Resolved by %{resolvedByName}"
-msgstr "%{resolvedByName} tarafından çözüldü"
-
msgid "Resolves IP addresses once and uses them to submit requests"
msgstr ""
@@ -21339,6 +22070,14 @@ msgstr "İnceleme süresi, ilk yorumdan birleştirilene kadar geçen süre olara
msgid "ReviewApp|Enable Review App"
msgstr ""
+msgid "Reviewer"
+msgid_plural "%d Reviewers"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Reviewer(s)"
+msgstr ""
+
msgid "Reviewing"
msgstr ""
@@ -21378,6 +22117,9 @@ msgstr ""
msgid "Rook"
msgstr ""
+msgid "Ruby"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -21456,6 +22198,63 @@ msgstr ""
msgid "Runners page."
msgstr ""
+msgid "Runners|Active"
+msgstr ""
+
+msgid "Runners|Architecture"
+msgstr ""
+
+msgid "Runners|Can run untagged jobs"
+msgstr ""
+
+msgid "Runners|Description"
+msgstr ""
+
+msgid "Runners|Group"
+msgstr ""
+
+msgid "Runners|IP Address"
+msgstr ""
+
+msgid "Runners|Last contact"
+msgstr ""
+
+msgid "Runners|Locked to this project"
+msgstr ""
+
+msgid "Runners|Maximum job timeout"
+msgstr ""
+
+msgid "Runners|Name"
+msgstr ""
+
+msgid "Runners|Platform"
+msgstr ""
+
+msgid "Runners|Property Name"
+msgstr ""
+
+msgid "Runners|Protected"
+msgstr ""
+
+msgid "Runners|Revision"
+msgstr ""
+
+msgid "Runners|Shared"
+msgstr ""
+
+msgid "Runners|Specific"
+msgstr ""
+
+msgid "Runners|Tags"
+msgstr ""
+
+msgid "Runners|Value"
+msgstr ""
+
+msgid "Runners|Version"
+msgstr ""
+
msgid "Runners|You have used %{quotaUsed} out of %{quotaLimit} of your shared Runners pipeline minutes."
msgstr ""
@@ -21468,6 +22267,9 @@ msgstr "Çalışıyor…"
msgid "Runs a number of housekeeping tasks within the current repository, such as compressing file revisions and removing unreachable objects."
msgstr "Geçerli depoda, dosya düzeltmelerini sıkıştırma ve erişilemeyen nesneleri kaldırma gibi bir dizi temizlik görevi yürütür."
+msgid "SAML"
+msgstr ""
+
msgid "SAML SSO"
msgstr ""
@@ -21519,6 +22321,9 @@ msgstr "Cumartesi"
msgid "Save"
msgstr ""
+msgid "Save %{name} size limits"
+msgstr ""
+
msgid "Save Changes"
msgstr "DeÄŸiÅŸiklikleri Kaydet"
@@ -21549,9 +22354,6 @@ msgstr "İş hattı takvimini kaydet"
msgid "Save space and find tags in the Container Registry more easily. Enable the cleanup policy to remove stale tags and keep only the ones you need."
msgstr ""
-msgid "Save template"
-msgstr "Åžablonu kaydet"
-
msgid "Save variables"
msgstr "DeÄŸiÅŸkenleri kaydet"
@@ -21594,9 +22396,6 @@ msgstr "İş Hatları Zamanlanıyor"
msgid "Scope"
msgstr ""
-msgid "Scope not supported with disabled 'users_search' feature!"
-msgstr "Kapsam, devre dışı 'users_search' özelliği ile desteklenmiyor!"
-
msgid "Scoped issue boards"
msgstr "Kapsamlı sorun panoları"
@@ -21723,9 +22522,6 @@ msgstr "Projeleri ara..."
msgid "Search requirements"
msgstr "Gereksinimleri ara"
-msgid "Search results…"
-msgstr ""
-
msgid "Search users"
msgstr "Kullanıcıları ara"
@@ -21798,6 +22594,11 @@ msgid_plural "SearchResults|commits"
msgstr[0] ""
msgstr[1] ""
+msgid "SearchResults|epic"
+msgid_plural "SearchResults|epics"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "SearchResults|issue"
msgid_plural "SearchResults|issues"
msgstr[0] ""
@@ -21842,10 +22643,10 @@ msgstr ""
msgid "Seat Link is disabled, and cannot be configured through this form."
msgstr ""
-msgid "Seats currently in use"
+msgid "Seats usage data as of %{last_enqueue_time}"
msgstr ""
-msgid "Seats in license"
+msgid "Seats usage data is updated every day at 12:00pm UTC"
msgstr ""
msgid "Secondary"
@@ -21899,6 +22700,9 @@ msgstr ""
msgid "SecurityConfiguration|Available for on-demand DAST"
msgstr ""
+msgid "SecurityConfiguration|By default, all analyzers are applied in order to cover all languages across your project, and only run if the language is detected in the Merge Request."
+msgstr ""
+
msgid "SecurityConfiguration|Configure"
msgstr ""
@@ -21929,16 +22733,19 @@ msgstr ""
msgid "SecurityConfiguration|Manage"
msgstr ""
+msgid "SecurityConfiguration|More information"
+msgstr ""
+
msgid "SecurityConfiguration|Not enabled"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|Security Control"
+msgid "SecurityConfiguration|SAST Configuration"
msgstr ""
-msgid "SecurityConfiguration|See documentation"
+msgid "SecurityConfiguration|Security Control"
msgstr ""
msgid "SecurityConfiguration|Status"
@@ -21950,6 +22757,9 @@ msgstr ""
msgid "SecurityConfiguration|Using custom settings. You won't receive automatic updates on this variable. %{anchorStart}Restore to default%{anchorEnd}"
msgstr ""
+msgid "SecurityConfiguration|View history"
+msgstr ""
+
msgid "SecurityConfiguration|You can quickly enable all security scanning tools by enabling %{linkStart}Auto DevOps%{linkEnd}."
msgstr ""
@@ -22028,9 +22838,6 @@ msgstr ""
msgid "SecurityReports|Learn more about setting up your dashboard"
msgstr ""
-msgid "SecurityReports|Load more vulnerabilities"
-msgstr ""
-
msgid "SecurityReports|Monitor vulnerabilities in your code"
msgstr ""
@@ -22310,7 +23117,7 @@ msgstr ""
msgid "Select status"
msgstr ""
-msgid "Select strategy activation method"
+msgid "Select strategy activation method."
msgstr ""
msgid "Select subscription"
@@ -22325,7 +23132,7 @@ msgstr ""
msgid "Select the custom project template source group."
msgstr "Özel proje şablonu kaynak grubunu seçin."
-msgid "Select timeframe"
+msgid "Select the environment scope for this feature flag."
msgstr ""
msgid "Select timezone"
@@ -22574,6 +23381,9 @@ msgstr ""
msgid "Set iteration"
msgstr ""
+msgid "Set limit to 0 to allow any file size."
+msgstr ""
+
msgid "Set max session time for web terminal."
msgstr "Web terminali için en yüksek oturum süresini ayarlayın."
@@ -22587,7 +23397,7 @@ msgid "Set notification email for abuse reports."
msgstr "Kötüye kullanım raporları için bildirim e-postası ayarlayın."
msgid "Set parent epic to an epic"
-msgstr ""
+msgstr "Bir epiğe üst epik ayarla"
msgid "Set projects and maximum size limits, session duration, user options, and check feature availability for namespace plan."
msgstr ""
@@ -22652,10 +23462,13 @@ msgstr ""
msgid "Set up a %{type} Runner manually"
msgstr ""
+msgid "Set up a hardware device as a second factor to sign in."
+msgstr ""
+
msgid "Set up assertions/attributes/claims (email, first_name, last_name) and NameID according to %{docsLinkStart}the documentation %{icon}%{docsLinkEnd}"
msgstr ""
-msgid "Set up new U2F device"
+msgid "Set up new device"
msgstr ""
msgid "Set up new password"
@@ -22704,7 +23517,7 @@ msgid "SetStatusModal|What's your status?"
msgstr "Durumunuz nedir?"
msgid "Sets %{epic_ref} as parent epic."
-msgstr ""
+msgstr "%{epic_ref} epiğini üst epik olarak ayarlar."
msgid "Sets target branch to %{branch_name}."
msgstr ""
@@ -22724,6 +23537,9 @@ msgstr ""
msgid "Sets weight to %{weight}."
msgstr ""
+msgid "Setting this to 0 means using the system default timeout value."
+msgstr ""
+
msgid "Settings"
msgstr "Ayarlar"
@@ -22739,6 +23555,15 @@ msgstr ""
msgid "Severity"
msgstr ""
+msgid "SeverityWidget|Severity"
+msgstr ""
+
+msgid "SeverityWidget|Severity: %{severity}"
+msgstr ""
+
+msgid "SeverityWidget|There was an error while updating severity."
+msgstr ""
+
msgid "Shards (%{shards})"
msgstr ""
@@ -22784,6 +23609,9 @@ msgstr "Tüm üyeleri göster"
msgid "Show all requirements."
msgstr "Tüm gereksinimleri göster."
+msgid "Show all test cases."
+msgstr ""
+
msgid "Show archived projects"
msgstr "Arşivlenmiş projeleri göster"
@@ -22796,6 +23624,9 @@ msgstr "Komutu göster"
msgid "Show comments"
msgstr ""
+msgid "Show comments on this file"
+msgstr ""
+
msgid "Show comments only"
msgstr ""
@@ -22841,6 +23672,12 @@ msgstr "Üst sayfaları göster"
msgid "Show parent subgroups"
msgstr "Üst alt grupları göster"
+msgid "Show the Closed list"
+msgstr ""
+
+msgid "Show the Open list"
+msgstr ""
+
msgid "Show whitespace changes"
msgstr "Boşluk değişikliklerini göster"
@@ -22884,9 +23721,6 @@ msgstr ""
msgid "Sidebar|Assign health status"
msgstr "Sağlık durumu ata"
-msgid "Sidebar|Change weight"
-msgstr "Ağırlığı değiştir"
-
msgid "Sidebar|Health status"
msgstr "Sağlık durumu"
@@ -23070,6 +23904,9 @@ msgstr "Gösterilecek parçacık yok."
msgid "Snippets|Add another file %{num}/%{total}"
msgstr ""
+msgid "Snippets|Authored %{time_ago} by %{author}"
+msgstr ""
+
msgid "Snippets|Delete file"
msgstr ""
@@ -23097,6 +23934,9 @@ msgstr ""
msgid "Solution"
msgstr ""
+msgid "Some changes are not shown"
+msgstr ""
+
msgid "Some child epics may be hidden due to applied filters"
msgstr ""
@@ -23463,6 +24303,12 @@ msgstr "Kaynak"
msgid "Source (branch or tag)"
msgstr "Kaynak (dal veya etiket)"
+msgid "Source Branch"
+msgstr ""
+
+msgid "Source branch: %{source_branch_open}%{source_branch}%{source_branch_close}"
+msgstr ""
+
msgid "Source code"
msgstr "Kaynak kodu"
@@ -23628,9 +24474,6 @@ msgstr "Ä°nceleme baÅŸlat"
msgid "Start and due date"
msgstr "Başlangıç ve bitiş tarihi"
-msgid "Start by choosing a group to see how your team is spending time. You can then drill down to the project level."
-msgstr ""
-
msgid "Start by choosing a group to start exploring the merge requests in that group. You can then proceed to filter by projects, labels, milestones and authors."
msgstr ""
@@ -23712,18 +24555,27 @@ msgstr ""
msgid "StaticSiteEditor|3. Assign a person to review and accept the merge request."
msgstr ""
+msgid "StaticSiteEditor|A link to view the merge request will appear once ready."
+msgstr ""
+
msgid "StaticSiteEditor|An error occurred while submitting your changes."
msgstr ""
msgid "StaticSiteEditor|Branch could not be created."
msgstr ""
+msgid "StaticSiteEditor|Copy update"
+msgstr ""
+
msgid "StaticSiteEditor|Could not commit the content changes."
msgstr ""
msgid "StaticSiteEditor|Could not create merge request."
msgstr ""
+msgid "StaticSiteEditor|Creating your merge request"
+msgstr ""
+
msgid "StaticSiteEditor|Incompatible file content"
msgstr ""
@@ -23745,6 +24597,9 @@ msgstr ""
msgid "StaticSiteEditor|View documentation"
msgstr ""
+msgid "StaticSiteEditor|You can set an assignee to get your changes reviewed and deployed once your merge request is created."
+msgstr ""
+
msgid "StaticSiteEditor|Your merge request has been created"
msgstr ""
@@ -23874,15 +24729,15 @@ msgstr ""
msgid "Submit %{humanized_resource_name}"
msgstr ""
-msgid "Submit Changes"
-msgstr ""
-
msgid "Submit a review"
msgstr ""
msgid "Submit as spam"
msgstr "Spam olarak gönder"
+msgid "Submit changes"
+msgstr ""
+
msgid "Submit feedback"
msgstr "Geri bildirim gönder"
@@ -24036,6 +24891,9 @@ msgstr ""
msgid "Successfully deleted U2F device."
msgstr ""
+msgid "Successfully deleted WebAuthn device."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -24354,9 +25212,6 @@ msgstr "Åžablon"
msgid "Template to append to all Service Desk issues"
msgstr ""
-msgid "Template was successfully saved."
-msgstr ""
-
msgid "Templates"
msgstr "Åžablonlar"
@@ -24435,11 +25290,29 @@ msgid_plural "Test coverage: %d hits"
msgstr[0] ""
msgstr[1] ""
-msgid "Test failed."
+msgid "Test settings"
+msgstr ""
+
+msgid "TestCases|New Test Case"
+msgstr ""
+
+msgid "TestCases|New test case"
msgstr ""
-msgid "Test settings and save changes"
-msgstr "Ayarları test et ve değişiklikleri kaydet"
+msgid "TestCases|Search test cases"
+msgstr ""
+
+msgid "TestCases|Something went wrong while creating a test case."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching count of test cases."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching test cases list."
+msgstr ""
+
+msgid "TestCases|Submit test case"
+msgstr ""
msgid "TestHooks|Ensure one of your projects has merge requests."
msgstr ""
@@ -24504,6 +25377,9 @@ msgstr ""
msgid "Thank you for signing up for your free trial! You will get additional instructions in your inbox shortly."
msgstr ""
+msgid "Thank you for your business."
+msgstr ""
+
msgid "Thank you for your feedback!"
msgstr ""
@@ -24563,9 +25439,6 @@ msgstr ""
msgid "The URL to use for connecting to Elasticsearch. Use a comma-separated list to support clustering (e.g., \"http://localhost:9200, http://localhost:9201\")."
msgstr ""
-msgid "The Web IDE offers advanced syntax highlighting capabilities and more."
-msgstr ""
-
msgid "The X509 Certificate to use when mutual TLS is required to communicate with the external authorization service. If left blank, the server certificate is still validated when accessing over HTTPS."
msgstr ""
@@ -24676,6 +25549,9 @@ msgstr "Çatal ilişkisi kaldırıldı."
msgid "The form contains the following error:"
msgstr ""
+msgid "The form contains the following warning:"
+msgstr ""
+
msgid "The global settings require you to enable Two-Factor Authentication for your account."
msgstr ""
@@ -24790,9 +25666,6 @@ msgstr ""
msgid "The private key to use when a client certificate is provided. This value is encrypted at rest."
msgstr ""
-msgid "The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The project can be accessed by any logged in user."
msgstr ""
@@ -24829,7 +25702,7 @@ msgstr ""
msgid "The remote repository is being updated..."
msgstr "Uzak depo güncelleniyor..."
-msgid "The repository can be commited to, and issues, comments and other entities can be created."
+msgid "The repository can be committed to, and issues, comments and other entities can be created."
msgstr ""
msgid "The repository for this project does not exist."
@@ -24851,7 +25724,7 @@ msgid "The review stage shows the time from creating the merge request to mergin
msgstr ""
msgid "The roadmap shows the progress of your epics along a timeline"
-msgstr ""
+msgstr "Yol haritası, epiklerinizin bir zaman çizelgesi boyunca ilerlemesini gösterir"
msgid "The schedule time must be in the future!"
msgstr ""
@@ -24883,9 +25756,6 @@ msgstr ""
msgid "The time taken by each data entry gathered by that stage."
msgstr "Her veri girişinde harcanan zaman bu aşamada toplanır."
-msgid "The total stage shows the time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The update action will time out after %{number_of_minutes} minutes. For big repositories, use a clone/push combination."
msgstr ""
@@ -24949,6 +25819,9 @@ msgstr "Henüz arşivlenmiş proje yok"
msgid "There are no archived requirements"
msgstr ""
+msgid "There are no archived test cases"
+msgstr ""
+
msgid "There are no changes"
msgstr ""
@@ -24988,6 +25861,9 @@ msgstr "Açık birleştirme isteği yok"
msgid "There are no open requirements"
msgstr ""
+msgid "There are no open test cases"
+msgstr ""
+
msgid "There are no packages yet"
msgstr ""
@@ -25000,6 +25876,9 @@ msgstr ""
msgid "There is a limit of %{ci_project_subscriptions_limit} subscriptions from or to a project."
msgstr ""
+msgid "There is already a To-Do for this design."
+msgstr ""
+
msgid "There is already a repository with that name on disk"
msgstr ""
@@ -25018,6 +25897,9 @@ msgstr ""
msgid "There was a problem communicating with your device."
msgstr ""
+msgid "There was a problem fetching branches."
+msgstr ""
+
msgid "There was a problem fetching groups."
msgstr ""
@@ -25246,9 +26128,15 @@ msgstr ""
msgid "This action can lead to data loss. To prevent accidental actions we ask you to confirm your intention."
msgstr "Bu işlem veri kaybına yol açabilir. Yanlışlıkla yapılacak işlemleri önlemek için niyetinizi onaylamanızı istiyoruz."
+msgid "This action cannot be undone, and will permanently delete the %{key} SSH key"
+msgstr ""
+
msgid "This action cannot be undone. You will lose the project's repository and all content: issues, merge requests, etc."
msgstr ""
+msgid "This action has been performed too many times. Try again later."
+msgstr ""
+
msgid "This action will %{strongOpen}permanently delete%{strongClose} %{codeOpen}%{project}%{codeClose} %{strongOpen}immediately%{strongClose}, including its repositories and all content: issues, merge requests, etc."
msgstr ""
@@ -25276,9 +26164,6 @@ msgstr ""
msgid "This board's scope is reduced"
msgstr ""
-msgid "This branch has changed since you started editing. Would you like to create a new branch?"
-msgstr "Düzenlemeye başladığınızdan bu yana dal değişti. Yeni bir dal oluşturmak ister misiniz?"
-
msgid "This chart could not be displayed"
msgstr ""
@@ -25313,10 +26198,10 @@ msgid "This credential has expired"
msgstr ""
msgid "This date is after the due date, so this epic won't appear in the roadmap."
-msgstr ""
+msgstr "Bu tarih, sona erme tarihinden sonra olduğundan dolayı bu epik yol haritasında görünmez."
msgid "This date is before the start date, so this epic won't appear in the roadmap."
-msgstr ""
+msgstr "Bu tarih, başlangıç tarihinden önce olduğundan dolayı bu epik yol haritasında görünmez."
msgid "This device has already been registered with us."
msgstr ""
@@ -25405,15 +26290,9 @@ msgstr "Bu, hesabınıza giriÅŸ yaptığınız cihazların listesidir. TanımadÄ
msgid "This is a security log of important events involving your account."
msgstr "Bu, hesabınızla ilgili önemli olayların bir güvenlik günlüğüdür."
-msgid "This is the author's first Merge Request to this project."
-msgstr ""
-
msgid "This is the highest peak of users on your installation since the license started."
msgstr ""
-msgid "This is the maximum number of users that have existed at the same time since the license started. This is the minimum number of seats you will need to buy when you renew your license."
-msgstr ""
-
msgid "This is the number of currently active users on your installation, and this is the minimum number you need to purchase when you renew your license."
msgstr ""
@@ -25645,6 +26524,15 @@ msgstr ""
msgid "This user has no identities"
msgstr "Bu kullanıcının kimliği yok"
+msgid "This user has previously committed to the %{name} project."
+msgstr ""
+
+msgid "This user has the %{access} role in the %{name} project."
+msgstr ""
+
+msgid "This user is the author of this %{noteable}."
+msgstr ""
+
msgid "This user will be the author of all events in the activity feed that are the result of an update, like new branches being created or new commits being pushed to existing branches."
msgstr ""
@@ -25675,6 +26563,9 @@ msgstr ""
msgid "Threat Monitoring"
msgstr ""
+msgid "ThreatMonitoring|All Environments"
+msgstr ""
+
msgid "ThreatMonitoring|Anomalous Requests"
msgstr ""
@@ -25702,9 +26593,6 @@ msgstr ""
msgid "ThreatMonitoring|Operations Per Second"
msgstr ""
-msgid "ThreatMonitoring|Overview"
-msgstr ""
-
msgid "ThreatMonitoring|Packet Activity"
msgstr ""
@@ -25723,6 +26611,9 @@ msgstr ""
msgid "ThreatMonitoring|Something went wrong, unable to fetch statistics"
msgstr ""
+msgid "ThreatMonitoring|Statistics"
+msgstr ""
+
msgid "ThreatMonitoring|The firewall is not installed or has been disabled. To view this data, ensure the web application firewall is installed and enabled for your cluster."
msgstr ""
@@ -26114,6 +27005,9 @@ msgstr ""
msgid "To update Snippets with multiple files, you must use the `files` parameter"
msgstr ""
+msgid "To use Gitpod you must first enable the feature in the integrations section of your %{user_prefs}."
+msgstr ""
+
msgid "To view all %{scannedResourcesCount} scanned URLs, please download the CSV file"
msgstr ""
@@ -26147,9 +27041,6 @@ msgstr "Biçimlendirme önizlemesini aç/kapat"
msgid "Toggle Sidebar"
msgstr "Kenar çubuğunu aç/kapat"
-msgid "Toggle all threads"
-msgstr "Tüm konuları aç/kapat"
-
msgid "Toggle backtrace"
msgstr "Geri izlemeyi aç/kapat"
@@ -26174,9 +27065,6 @@ msgstr "İfade ödülünü aç/kapat"
msgid "Toggle navigation"
msgstr "Gezinmeyi aç/kapat"
-msgid "Toggle project"
-msgstr "Projeyi aç/kapat"
-
msgid "Toggle sidebar"
msgstr "Kenar çubuğunu aç/kapat"
@@ -26216,6 +27104,9 @@ msgstr ""
msgid "Too many projects enabled. You will need to manage them via the console or the API."
msgstr ""
+msgid "Too much data"
+msgstr ""
+
msgid "Topics (optional)"
msgstr ""
@@ -26234,6 +27125,9 @@ msgstr ""
msgid "Total cores (CPUs)"
msgstr ""
+msgid "Total days to completion"
+msgstr ""
+
msgid "Total issues"
msgstr ""
@@ -26330,6 +27224,9 @@ msgstr ""
msgid "Trending"
msgstr "Öne Çıkanlar"
+msgid "Trials|Create a new group to start your GitLab Gold trial."
+msgstr ""
+
msgid "Trials|Go back to GitLab"
msgstr ""
@@ -26339,6 +27236,15 @@ msgstr ""
msgid "Trials|You can always resume this process by selecting your avatar and choosing 'Start a Gold trial'"
msgstr ""
+msgid "Trials|You can apply your trial to a new group or an existing group."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group or your personal account."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group, an existing group, or your personal account."
+msgstr ""
+
msgid "Trials|You won't get a free trial right now but you can always resume this process by clicking on your avatar and choosing 'Start a free trial'"
msgstr ""
@@ -26408,6 +27314,9 @@ msgstr ""
msgid "Try using a different search term to find the file you are looking for."
msgstr ""
+msgid "Trying to communicate with your device. Plug it in (if needed) and press the button on the device now."
+msgstr ""
+
msgid "Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now."
msgstr ""
@@ -26495,6 +27404,12 @@ msgstr ""
msgid "URL or request ID"
msgstr ""
+msgid "USER %{user} WILL BE REMOVED! Are you sure?"
+msgstr ""
+
+msgid "USER WILL BE BLOCKED! Are you sure?"
+msgstr ""
+
msgid "UTC"
msgstr ""
@@ -26552,9 +27467,6 @@ msgstr ""
msgid "Unable to load the merge request widget. Try reloading the page."
msgstr ""
-msgid "Unable to resolve"
-msgstr ""
-
msgid "Unable to save iteration. Please try again"
msgstr ""
@@ -26574,7 +27486,7 @@ msgid "Unable to update label prioritization at this time"
msgstr ""
msgid "Unable to update this epic at this time."
-msgstr ""
+msgstr "Bu epik şu anda güncellenemiyor."
msgid "Unable to update this issue at this time."
msgstr ""
@@ -26603,6 +27515,9 @@ msgstr ""
msgid "Undo ignore"
msgstr ""
+msgid "Unexpected error"
+msgstr ""
+
msgid "Unfortunately, your email message to GitLab could not be processed."
msgstr ""
@@ -26636,6 +27551,9 @@ msgstr "Bilinmeyen biçim"
msgid "Unknown response text"
msgstr "Bilinmeyen yanıt metni"
+msgid "Unless otherwise agreed to in writing with GitLab, by clicking \"Upload License\" you agree that your use of GitLab Software is subject to the %{eula_link_start}Terms of Service%{eula_link_end}."
+msgstr ""
+
msgid "Unlimited"
msgstr "Sınırsız"
@@ -27002,9 +27920,6 @@ msgstr ""
msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
msgstr ""
-msgid "Use a hardware device to add the second factor of authentication."
-msgstr ""
-
msgid "Use an one time password authenticator on your mobile device or computer to enable two-factor authentication (2FA)."
msgstr ""
@@ -27162,7 +28077,7 @@ msgid "UserList|Delete %{name}?"
msgstr ""
msgid "UserList|created %{timeago}"
-msgstr ""
+msgstr "%{timeago} oluÅŸturuldu"
msgid "UserProfile|Activity"
msgstr "Etkinlik"
@@ -27278,15 +28193,15 @@ msgstr "Kullanıcı adı ya da e-posta"
msgid "Users"
msgstr "Kullanıcılar"
+msgid "Users in License"
+msgstr ""
+
msgid "Users in License:"
msgstr "Lisanslı kullanıcılar:"
msgid "Users or groups set as approvers in the project's or merge request's settings."
msgstr ""
-msgid "Users outside of license"
-msgstr ""
-
msgid "Users over License:"
msgstr "Lisansı bitmiş kullanıcılar:"
@@ -27302,9 +28217,6 @@ msgstr ""
msgid "Users with a Guest role or those who don't belong to a Project or Group will not use a seat from your license."
msgstr ""
-msgid "Users with a Guest role or those who don't belong to any projects or groups don't count towards seats in use."
-msgstr ""
-
msgid "UsersSelect|%{name} + %{length} more"
msgstr ""
@@ -27344,9 +28256,6 @@ msgstr ""
msgid "Validations failed."
msgstr ""
-msgid "Validity"
-msgstr ""
-
msgid "Value"
msgstr "DeÄŸer"
@@ -27365,6 +28274,9 @@ msgstr ""
msgid "Value Stream Name"
msgstr ""
+msgid "ValueStreamAnalyticsStage|We don't have enough data to show this stage."
+msgstr ""
+
msgid "ValueStreamAnalytics|%{days}d"
msgstr ""
@@ -27458,7 +28370,7 @@ msgid "View eligible approvers"
msgstr ""
msgid "View epics list"
-msgstr ""
+msgstr "Epik listesini görüntüle"
msgid "View exposed artifact"
msgid_plural "View %d exposed artifacts"
@@ -27621,6 +28533,9 @@ msgstr ""
msgid "VisualReviewApp|Steps 1 and 2 (and sometimes 3) are performed once by the developer before requesting feedback. Steps 3 (if necessary), 4 is performed by the reviewer each time they perform a review."
msgstr ""
+msgid "Visualization"
+msgstr ""
+
msgid "Vulnerabilities"
msgstr ""
@@ -27648,35 +28563,32 @@ msgstr ""
msgid "VulnerabilityChart|Severity"
msgstr ""
-msgid "VulnerabilityManagement|A true-positive and will fix"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Change status"
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|Confirm"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Confirmed %{timeago} by %{user}"
-msgstr "%{user} tarafından %{timeago} onaylandı"
-
-msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Detected %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|A true-positive and will fix"
msgstr ""
-msgid "VulnerabilityManagement|Dismiss"
+msgid "VulnerabilityManagement|Change status"
msgstr ""
-msgid "VulnerabilityManagement|Dismissed %{timeago} by %{user}"
-msgstr "%{user} tarafından %{timeago} reddedildi"
+msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
+msgstr ""
-msgid "VulnerabilityManagement|Resolved"
+msgid "VulnerabilityManagement|Detected"
msgstr ""
-msgid "VulnerabilityManagement|Resolved %{timeago} by %{user}"
-msgstr "%{user} tarafından %{timeago} çözüldü"
+msgid "VulnerabilityManagement|Needs triage"
+msgstr ""
msgid "VulnerabilityManagement|Something went wrong while trying to delete the comment. Please try again later."
msgstr ""
@@ -27726,6 +28638,9 @@ msgstr ""
msgid "Vulnerability|%{scannerName} (version %{scannerVersion})"
msgstr ""
+msgid "Vulnerability|Activity"
+msgstr ""
+
msgid "Vulnerability|Class"
msgstr ""
@@ -27738,6 +28653,9 @@ msgstr ""
msgid "Vulnerability|Description"
msgstr "Açıklama"
+msgid "Vulnerability|Detected"
+msgstr ""
+
msgid "Vulnerability|Evidence"
msgstr ""
@@ -27801,11 +28719,14 @@ msgstr ""
msgid "Warning: Displaying this diagram might cause performance issues on this page."
msgstr ""
+msgid "We are currently unable to fetch data for the pipeline header."
+msgstr ""
+
msgid "We are currently unable to fetch data for this graph."
msgstr ""
msgid "We could not determine the path to remove the epic"
-msgstr ""
+msgstr "Epik kaldırma yolunu belirleyemedik"
msgid "We could not determine the path to remove the issue"
msgstr ""
@@ -27840,6 +28761,12 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
+msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
+msgstr ""
+
+msgid "We would like to inform you that your subscription GitLab Enterprise Edition %{plan_name} is nearing its user limit. You have %{active_user_count} active users, which is almost at the user limit of %{maximum_user_count}."
+msgstr ""
+
msgid "We've found no vulnerabilities"
msgstr ""
@@ -27855,6 +28782,12 @@ msgstr ""
msgid "Web terminal"
msgstr "Web terminali"
+msgid "WebAuthn Devices (%{length})"
+msgstr ""
+
+msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
+msgstr ""
+
msgid "WebIDE|Merge request"
msgstr ""
@@ -27993,15 +28926,9 @@ msgstr ""
msgid "Welcome to the guided GitLab tour"
msgstr ""
-msgid "Welcome to your Issue Board!"
-msgstr ""
-
msgid "Welcome to your issue board!"
msgstr ""
-msgid "We’ve been making changes to %{featureName} and we’d love your feedback %{linkStart}in this issue%{linkEnd} to help us improve the experience."
-msgstr ""
-
msgid "What are you searching for?"
msgstr ""
@@ -28020,6 +28947,9 @@ msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
msgstr ""
+msgid "When enabled, any user visiting %{host} and creating an account will have to be explicitly approved by the admin before they can login. This setting is effective only if sign-ups are enabled."
+msgstr ""
+
msgid "When enabled, any user visiting %{host} will be able to create an account."
msgstr ""
@@ -28244,6 +29174,9 @@ msgstr ""
msgid "With requirements, you can set criteria to check your products against."
msgstr ""
+msgid "With test cases, you can define conditions for your project to meet in determining quality"
+msgstr ""
+
msgid "Withdraw Access Request"
msgstr "Erişim İsteğini Geri Çek"
@@ -28259,6 +29192,9 @@ msgstr ""
msgid "Workflow Help"
msgstr ""
+msgid "Would you like to create a new branch?"
+msgstr ""
+
msgid "Write"
msgstr "Yaz"
@@ -28280,6 +29216,9 @@ msgstr ""
msgid "Wrong extern UID provided. Make sure Auth0 is configured correctly."
msgstr ""
+msgid "YYYY-MM-DD"
+msgstr ""
+
msgid "Yes"
msgstr "Evet"
@@ -28337,7 +29276,7 @@ msgstr ""
msgid "You are going to remove the fork relationship from %{project_full_name}. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "You are going to transfer %{project_full_name} to another owner. Are you ABSOLUTELY sure?"
+msgid "You are going to transfer %{project_full_name} to another namespace. Are you ABSOLUTELY sure?"
msgstr ""
msgid "You are going to turn off the confidentiality. This means %{strongStart}everyone%{strongEnd} will be able to see and leave a comment on this %{issuableType}."
@@ -28397,9 +29336,6 @@ msgstr ""
msgid "You can always edit this later"
msgstr ""
-msgid "You can apply your Trial to your Personal account or create a New Group."
-msgstr ""
-
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings"
msgstr ""
@@ -28421,12 +29357,18 @@ msgstr ""
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
+msgid "You can find more information about GitLab subscriptions in %{subscriptions_doc_link}."
+msgstr ""
+
msgid "You can generate an access token scoped to this project for each application to use the GitLab API."
msgstr ""
msgid "You can get started by cloning the repository or start adding files to it with one of the following options."
msgstr ""
+msgid "You can group test cases using labels. To learn about the future direction of this feature, visit %{linkStart}Quality Management direction page%{linkEnd}."
+msgstr ""
+
msgid "You can invite a new member to %{project_name} or invite another group."
msgstr ""
@@ -28442,6 +29384,9 @@ msgstr ""
msgid "You can notify the app / group or a project by sending them an email notification"
msgstr ""
+msgid "You can now close this window."
+msgstr ""
+
msgid "You can now export your security dashboard to a CSV report."
msgstr ""
@@ -28490,9 +29435,6 @@ msgstr "Grup başına veya proje başına bildirim düzeyi belirleyebilirsiniz."
msgid "You can test your .gitlab-ci.yml in %{linkStart}CI Lint%{linkEnd}."
msgstr ""
-msgid "You can try again using %{begin_link}basic search%{end_link}"
-msgstr ""
-
msgid "You cannot access the raw file. Please wait a minute."
msgstr ""
@@ -28544,6 +29486,9 @@ msgstr ""
msgid "You don't have any U2F devices registered yet."
msgstr ""
+msgid "You don't have any WebAuthn devices registered yet."
+msgstr ""
+
msgid "You don't have any active chat names."
msgstr "Etkin sohbet adınız yok."
@@ -28631,6 +29576,9 @@ msgstr ""
msgid "You must accept our Terms of Service and privacy policy in order to register an account"
msgstr ""
+msgid "You must be logged in to search across all of GitLab"
+msgstr ""
+
msgid "You must disassociate %{domain} from all clusters it is attached to before deletion."
msgstr ""
@@ -28670,7 +29618,7 @@ msgstr "İzin almanız gerekli."
msgid "You need to be logged in."
msgstr ""
-msgid "You need to register a two-factor authentication app before you can set up a U2F device."
+msgid "You need to register a two-factor authentication app before you can set up a device."
msgstr ""
msgid "You need to set terms to be enforced"
@@ -28688,6 +29636,9 @@ msgstr ""
msgid "You reached %{usage_in_percent} of %{namespace_name}'s storage capacity (%{used_storage} of %{storage_limit})"
msgstr ""
+msgid "You successfully declined the invitation"
+msgstr ""
+
msgid "You tried to fork %{link_to_the_project} but it failed for the following reason:"
msgstr ""
@@ -28853,10 +29804,13 @@ msgstr "Yapılacaklar Listeniz"
msgid "Your U2F device did not send a valid JSON response."
msgstr ""
-msgid "Your U2F device needs to be set up. Plug it in (if not already) and click the button on the left."
+msgid "Your U2F device was registered!"
msgstr ""
-msgid "Your U2F device was registered!"
+msgid "Your WebAuthn device did not send a valid JSON response."
+msgstr ""
+
+msgid "Your WebAuthn device was registered!"
msgstr ""
msgid "Your access request to the %{source_type} has been withdrawn."
@@ -28880,6 +29834,9 @@ msgstr "Yetkili uygulamalarınız"
msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
msgstr ""
+msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
+msgstr ""
+
msgid "Your changes can be committed to %{branch_name} because a merge request is open."
msgstr ""
@@ -28916,6 +29873,12 @@ msgstr ""
msgid "Your deployment services will be broken, you will need to manually fix the services after renaming."
msgstr ""
+msgid "Your device is not compatible with GitLab. Please try another device"
+msgstr ""
+
+msgid "Your device needs to be set up. Plug it in (if needed) and click the button on the left."
+msgstr ""
+
msgid "Your device was successfully set up! Give it a name and register it with the GitLab server."
msgstr ""
@@ -29029,9 +29992,6 @@ msgstr[1] ""
msgid "access:"
msgstr ""
-msgid "activated"
-msgstr "etkinleÅŸtirildi"
-
msgid "added %{created_at_timeago}"
msgstr "%{created_at_timeago} eklendi"
@@ -29104,9 +30064,21 @@ msgstr "tarafından"
msgid "by %{user}"
msgstr "%{user} tarafından"
+msgid "cannot be a date in the past"
+msgstr ""
+
msgid "cannot be changed if a personal project has container registry tags."
msgstr ""
+msgid "cannot be changed if shared runners are enabled"
+msgstr ""
+
+msgid "cannot be enabled because parent group does not allow it"
+msgstr ""
+
+msgid "cannot be enabled because parent group has shared Runners disabled"
+msgstr ""
+
msgid "cannot be enabled unless all domains have TLS certificates"
msgstr ""
@@ -29152,7 +30124,7 @@ msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about SAST %{linkEndTag}"
msgstr ""
-msgid "ciReport|%{linkStartTag}Learn more about Secret Scanning %{linkEndTag}"
+msgid "ciReport|%{linkStartTag}Learn more about Secret Detection %{linkEndTag}"
msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about codequality reports %{linkEndTag}"
@@ -29467,9 +30439,6 @@ msgstr ""
msgid "error"
msgstr "hata"
-msgid "error code:"
-msgstr "hata kodu:"
-
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr ""
@@ -29491,6 +30460,9 @@ msgstr "başarısız"
msgid "failed to dismiss associated finding(id=%{finding_id}): %{message}"
msgstr ""
+msgid "failed to revert associated finding(id=%{finding_id}) to detected"
+msgstr ""
+
msgid "file"
msgid_plural "files"
msgstr[0] "dosya"
@@ -30033,6 +31005,9 @@ msgstr ""
msgid "must be a root namespace"
msgstr ""
+msgid "must be a valid IPv4 or IPv6 address"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -30069,6 +31044,9 @@ msgstr "hiç katkı yok"
msgid "no expiration"
msgstr ""
+msgid "no name set"
+msgstr ""
+
msgid "no one can merge"
msgstr ""
@@ -30247,9 +31225,6 @@ msgstr ""
msgid "security Reports|There was an error creating the merge request"
msgstr ""
-msgid "settings saved, but not activated"
-msgstr ""
-
msgid "severity|Critical"
msgstr "Kritik"
@@ -30376,9 +31351,6 @@ msgstr ""
msgid "toggle collapse"
msgstr "daraltmayı aç/kapat"
-msgid "toggle dropdown"
-msgstr "açılır listeyi aç/kapat"
-
msgid "triggered"
msgstr "tetiklendi"
@@ -30406,6 +31378,9 @@ msgstr ""
msgid "user avatar"
msgstr "kullanıcının profil resmi"
+msgid "user preferences"
+msgstr ""
+
msgid "username"
msgstr "kullanıcı adı"
@@ -30413,7 +31388,7 @@ msgid "uses Kubernetes clusters to deploy your code!"
msgstr ""
msgid "v%{version} published %{timeAgo}"
-msgstr ""
+msgstr "v%{version} sürümü %{timeAgo} yayınlandı"
msgid "verify ownership"
msgstr "sahipliÄŸi doÄŸrula"
diff --git a/locale/uk/gitlab.po b/locale/uk/gitlab.po
index b640ab44b93..1d5c6c6b36e 100644
--- a/locale/uk/gitlab.po
+++ b/locale/uk/gitlab.po
@@ -14,10 +14,13 @@ msgstr ""
"X-Crowdin-Language: uk\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 6\n"
-"PO-Revision-Date: 2020-09-04 23:06\n"
+"PO-Revision-Date: 2020-10-02 18:45\n"
+
+msgid " %{project_name}#%{issue_iid} &middot; opened %{issue_created} by %{author}"
+msgstr ""
msgid " %{start} to %{end}"
-msgstr "%{start} до %{end}"
+msgstr " %{start} до %{end}"
msgid " (from %{timeoutSource})"
msgstr " (з %{timeoutSource})"
@@ -78,6 +81,20 @@ msgstr "\"%{path}\" не Ñ–Ñнував у \"%{ref}\""
msgid "\"el\" parameter is required for createInstance()"
msgstr ""
+msgid "%d Approval"
+msgid_plural "%d Approvals"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
+msgid "%d Package"
+msgid_plural "%d Packages"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%d Scanned URL"
msgid_plural "%d Scanned URLs"
msgstr[0] ""
@@ -165,6 +182,13 @@ msgstr[3] "%d комітів,"
msgid "%d commits"
msgstr "%d комітів"
+msgid "%d completed issue"
+msgid_plural "%d completed issues"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%d contribution"
msgid_plural "%d contributions"
msgstr[0] "%d внеÑок"
@@ -179,6 +203,13 @@ msgstr[1] "%d дні"
msgstr[2] "%d днів"
msgstr[3] "%d днів"
+msgid "%d day until tags are automatically removed"
+msgid_plural "%d days until tags are automatically removed"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%d error"
msgid_plural "%d errors"
msgstr[0] "%d помилка"
@@ -305,6 +336,20 @@ msgstr[1] "ще %d коментарі"
msgstr[2] "ще %d коментарів"
msgstr[3] "ще %d коментарів"
+msgid "%d open issue"
+msgid_plural "%d open issues"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
+msgid "%d pending comment"
+msgid_plural "%d pending comments"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%d personal project will be removed and cannot be restored."
msgid_plural "%d personal projects will be removed and cannot be restored."
msgstr[0] ""
@@ -326,6 +371,13 @@ msgstr[1] "%d проєкти"
msgstr[2] "%d проєктів"
msgstr[3] "%d проєктів"
+msgid "%d project selected"
+msgid_plural "%d projects selected"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%d request with warnings"
msgid_plural "%d requests with warnings"
msgstr[0] "%d запит із зауваженнÑми"
@@ -354,6 +406,13 @@ msgstr[1] "%d теги"
msgstr[2] "%d тегів"
msgstr[3] "%d тегів"
+msgid "%d tag per image name"
+msgid_plural "%d tags per image name"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%d unassigned issue"
msgid_plural "%d unassigned issues"
msgstr[0] ""
@@ -382,6 +441,13 @@ msgstr[1] "%d вразливоÑÑ‚Ñ– відхилено"
msgstr[2] "%d вразливоÑтей відхилено"
msgstr[3] "%d вразливоÑтей відхилено"
+msgid "%d warning found:"
+msgid_plural "%d warnings found:"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%s additional commit has been omitted to prevent performance issues."
msgid_plural "%s additional commits have been omitted to prevent performance issues."
msgstr[0] "%s доданий коміт був виключений Ð´Ð»Ñ Ð·Ð°Ð¿Ð¾Ð±Ñ–Ð³Ð°Ð½Ð½Ñ Ð¿Ñ€Ð¾Ð±Ð»ÐµÐ¼ із продуктивніÑÑ‚ÑŽ."
@@ -393,10 +459,10 @@ msgid "%{actionText} & %{openOrClose} %{noteable}"
msgstr "%{actionText} Ñ– %{openOrClose} %{noteable}"
msgid "%{address} is an invalid IP address range"
-msgstr ""
+msgstr "%{address} - недійÑний діапазон IP-адреÑ"
msgid "%{author_link} wrote:"
-msgstr ""
+msgstr "%{author_link} напиÑав:"
msgid "%{authorsName}'s thread"
msgstr "Ð¾Ð±Ð³Ð¾Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ %{authorsName}"
@@ -422,6 +488,9 @@ msgstr ""
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr "%{commit_author_link} закомітив %{commit_timeago}"
+msgid "%{completedCount} completed weight"
+msgstr ""
+
msgid "%{completedWeight} of %{totalWeight} weight completed"
msgstr ""
@@ -476,16 +545,12 @@ msgstr[1] "%{count} учаÑтника"
msgstr[2] "%{count} учаÑтників"
msgstr[3] "%{count} учаÑтників"
-msgid "%{count} pending comment"
-msgid_plural "%{count} pending comments"
-msgstr[0] "%{count} коментар в очікуванні"
-msgstr[1] "%{count} коментарі в очікуванні"
-msgstr[2] "%{count} коментарів в очікуванні"
-msgstr[3] "%{count} коментарів в очікуванні"
-
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr "%{count} пов’Ñзаних %{pluralized_subject}: %{links}"
+msgid "%{count} total weight"
+msgstr ""
+
msgid "%{dashboard_path} could not be found."
msgstr ""
@@ -540,6 +605,9 @@ 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} викориÑтовує облікові запиÑи керовані групою. Вам необхідно Ñтворити новий обліковий Ð·Ð°Ð¿Ð¸Ñ GitLab, Ñкий буде керуватиÑÑ %{group_name}."
+msgid "%{group_name}&%{epic_iid} &middot; opened %{epic_created} by %{author}"
+msgstr ""
+
msgid "%{host} sign-in from new location"
msgstr "вхід на %{host} з нового розташуваннÑ"
@@ -552,8 +620,8 @@ msgstr ""
msgid "%{issuableType} will be removed! Are you sure?"
msgstr "%{issuableType} буде видалено! Ви впевнені?"
-msgid "%{issuesSize} issues with a limit of %{maxIssueCount}"
-msgstr "%{issuesSize} задач з обмеженнÑм %{maxIssueCount}"
+msgid "%{issuesCount} issues with a limit of %{maxIssueCount}"
+msgstr ""
msgid "%{issuesSize} with a limit of %{maxIssueCount}"
msgstr "%{issuesSize} з обмеженнÑм %{maxIssueCount}"
@@ -585,8 +653,8 @@ msgstr "%{labelStart}Метод:%{labelEnd} %{method}"
msgid "%{labelStart}Namespace:%{labelEnd} %{namespace}"
msgstr "%{labelStart}проÑÑ‚Ñ–Ñ€ імен:%{labelEnd} %{namespace}"
-msgid "%{labelStart}Report Type:%{labelEnd} %{reportType}"
-msgstr "%{labelStart}Тип звіту:%{labelEnd} %{reportType}"
+msgid "%{labelStart}Scan Type:%{labelEnd} %{reportType}"
+msgstr ""
msgid "%{labelStart}Scanner:%{labelEnd} %{scanner}"
msgstr "%{labelStart}Сканер:%{labelEnd} %{scanner}"
@@ -652,10 +720,10 @@ msgid "%{milestone_name} (Past due)"
msgstr ""
msgid "%{milestone} (expired)"
-msgstr ""
+msgstr "%{milestone} (термін дії минув)"
msgid "%{milliseconds}ms"
-msgstr ""
+msgstr "%{milliseconds}мÑ"
msgid "%{mrText}, this issue will be closed automatically."
msgstr "%{mrText}, Ñ†Ñ Ð·Ð°Ð´Ð°Ñ‡Ð° буде закрита автоматично."
@@ -728,7 +796,7 @@ msgid "%{primary} (%{secondary})"
msgstr "%{primary} (%{secondary})"
msgid "%{ref} cannot be added: %{error}"
-msgstr ""
+msgstr "%{ref} неможливо додати: %{error}"
msgid "%{releases} release"
msgid_plural "%{releases} releases"
@@ -780,7 +848,7 @@ msgid "%{retryButtonStart}Try again%{retryButtonEnd} or %{newFileButtonStart}att
msgstr ""
msgid "%{seconds}s"
-msgstr ""
+msgstr "%{seconds}Ñ"
msgid "%{securityScanner} is not enabled for this project. %{linkStart}More information%{linkEnd}"
msgid_plural "%{securityScanner} are not enabled for this project. %{linkStart}More information%{linkEnd}"
@@ -796,9 +864,6 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "%{service_title} %{message}."
-msgstr "%{service_title} %{message}."
-
msgid "%{size} GiB"
msgstr "%{size} GiB"
@@ -897,6 +962,12 @@ msgstr "%{text} доÑтупний"
msgid "%{timebox_name} should belong either to a project or a group."
msgstr "%{timebox_name} повинен належати до проєкту або до групи."
+msgid "%{timebox_type} does not support burnup charts"
+msgstr ""
+
+msgid "%{timebox_type} must have a start and due date"
+msgstr ""
+
msgid "%{title} %{operator} %{threshold}"
msgstr "%{title} %{operator} %{threshold}"
@@ -921,8 +992,8 @@ msgstr ""
msgid "%{total} open issue weight"
msgstr "%{total} загальна вага відкритих задач"
-msgid "%{total} open issues"
-msgstr "%{total} відкритих задач"
+msgid "%{total} warnings found: showing first %{warningsDisplayed}"
+msgstr ""
msgid "%{usage_ping_link_start}Learn more%{usage_ping_link_end} about what information is shared with GitLab Inc."
msgstr "%{usage_ping_link_start}ДовідатиÑÑŒ більше%{usage_ping_link_end} про те, Ñкою інформацією Ви ділитеÑÑŒ із GitLab Inc."
@@ -952,10 +1023,7 @@ msgid "%{webhooks_link_start}%{webhook_type}%{link_end} enable you to send notif
msgstr ""
msgid "&lt; 1 hour"
-msgstr ""
-
-msgid "&lt;no name set&gt;"
-msgstr ""
+msgstr "&lt; 1 година"
msgid "&lt;no scopes selected&gt;"
msgstr ""
@@ -987,6 +1055,9 @@ msgstr "\"%{level}\" не Ñ” допуÑтимим рівнем видимоÑÑ‚Ñ
msgid "'%{name}' Value Stream created"
msgstr ""
+msgid "'%{name}' Value Stream deleted"
+msgstr ""
+
msgid "'%{name}' stage already exists"
msgstr "'%{name}' ÑÑ‚Ð°Ð´Ñ–Ñ Ð²Ð¶Ðµ Ñ–Ñнує"
@@ -1007,7 +1078,7 @@ msgid "(%{mrCount} merged)"
msgstr "(%{mrCount} злито)"
msgid "(%{value}) has already been taken"
-msgstr ""
+msgstr "(%{value}) вже зайнÑто"
msgid "(No changes)"
msgstr "(Ðемає змін)"
@@ -1022,10 +1093,10 @@ msgid "(external source)"
msgstr "(зовнішнє джерело)"
msgid "(line: %{startLine})"
-msgstr ""
+msgstr "(Ñ€Ñдок: %{startLine})"
msgid "(max size 15 MB)"
-msgstr ""
+msgstr "(макÑимальний розмір 15 Мб)"
msgid "(removed)"
msgstr "(видалено)"
@@ -1048,6 +1119,9 @@ msgstr "+ ще %{moreCount}"
msgid "+ %{numberOfHiddenAssignees} more"
msgstr "+ %{numberOfHiddenAssignees} більше"
+msgid "+ %{numberOfHiddenReviewers} more"
+msgstr ""
+
msgid "+%d more"
msgid_plural "+%d more"
msgstr[0] ""
@@ -1120,6 +1194,13 @@ msgstr[1] "%d дні"
msgstr[2] "%d днів"
msgstr[3] "%d днів"
+msgid "1 Issue"
+msgid_plural "%d Issues"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "1 closed issue"
msgid_plural "%{issues} closed issues"
msgstr[0] "1 закрита задача"
@@ -1141,6 +1222,13 @@ msgstr[1] "%d дні"
msgstr[2] "%d днів"
msgstr[3] "%d днів"
+msgid "1 deploy key"
+msgid_plural "%d deploy keys"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] "1 група"
@@ -1261,6 +1349,9 @@ msgstr "8 годин"
msgid ":%{startLine} to %{endLine}"
msgstr ":%{startLine} до %{endLine}"
+msgid "A %{incident_docs_start}modified issue%{incident_docs_end} to guide the resolution of incidents."
+msgstr ""
+
msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr "'Runner' — це процеÑ, Ñкий виконує завданнÑ. Ви можете Ñтворити потрібну кількіÑÑ‚ÑŒ Runner'ів."
@@ -1273,6 +1364,9 @@ msgstr ""
msgid "A GitBook site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr "Сайт GitBook, Ñкий викориÑтовує Netlify Ð´Ð»Ñ CI/CD заміÑÑ‚ÑŒ GitLab, але вÑе ще з уÑіма іншими чудовими функціÑми GitLab."
+msgid "A Gitpod configured Webapplication in Spring and Java"
+msgstr ""
+
msgid "A Hexo site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr "Сайт Hexo, Ñкий викориÑтовує Netlify Ð´Ð»Ñ CI/CD заміÑÑ‚ÑŒ GitLab, але вÑе ще з уÑіма іншими чудовими функціÑми GitLab."
@@ -1301,7 +1395,7 @@ msgid "A deleted user"
msgstr "Видалений кориÑтувач"
msgid "A file has been changed."
-msgstr ""
+msgstr "Файл змінено."
msgid "A file was not found."
msgstr "Файл не знайдено."
@@ -1385,7 +1479,7 @@ msgid "ACTION REQUIRED: Something went wrong while obtaining the Let's Encrypt c
msgstr "ÐЕОБХІДÐРДІЯ: ЩоÑÑŒ пішло не так при отриманні Ñертифікату Let's Encrypt Ð´Ð»Ñ Ð´Ð¾Ð¼ÐµÐ½Ñƒ GitLab Pages '%{domain}'"
msgid "API Help"
-msgstr ""
+msgstr "Довідка API"
msgid "API Token"
msgstr "API-токен"
@@ -1444,18 +1538,27 @@ msgstr "ДоÑтуп заборонено! Будь-лаÑка, перевірт
msgid "Access expiration date"
msgstr "Дата Ð¿Ñ€Ð¸Ð¿Ð¸Ð½ÐµÐ½Ð½Ñ Ð´Ð¾Ñтупу"
+msgid "Access expires"
+msgstr ""
+
msgid "Access forbidden. Check your access level."
msgstr "ДоÑтуп заборонено. Перевірте рівень доÑтупу."
-msgid "Access requests"
+msgid "Access granted"
msgstr ""
+msgid "Access requests"
+msgstr "Запити на доÑтуп"
+
msgid "Access to '%{classification_label}' not allowed"
msgstr "ДоÑтуп до \"%{classification_label}\" заборонено"
msgid "Access to Pages websites are controlled based on the user's membership to a given project. By checking this box, users will be required to be logged in to have access to all Pages websites in your instance."
msgstr "ДоÑтуп до Ñайтів Pages контролюєтьÑÑ Ð½Ð° оÑнові належноÑÑ‚Ñ– кориÑтувача до певного проєкту. Якщо вÑтановити цей прапорець, кориÑтувачі повинні будуть увійти в ÑиÑтему, щоб мати доÑтуп до вÑÑ–Ñ… Ñайтів Pages у вашому інÑтанÑÑ–."
+msgid "AccessDropdown|Deploy Keys"
+msgstr ""
+
msgid "AccessDropdown|Groups"
msgstr "Групи"
@@ -1573,12 +1676,6 @@ msgstr "Ðктивні %{type} (%{token_length})"
msgid "Active Sessions"
msgstr "Ðктивні ÑеÑÑ–Ñ—"
-msgid "Active Users:"
-msgstr "Ðктивні кориÑтувачі:"
-
-msgid "Active users"
-msgstr "Ðктивні кориÑтувачі"
-
msgid "Activity"
msgstr "ÐктивніÑÑ‚ÑŒ"
@@ -1644,7 +1741,7 @@ msgid "Add a To Do"
msgstr "Додати нагадуваннÑ"
msgid "Add a To-Do"
-msgstr ""
+msgstr "Додати нагадуваннÑ"
msgid "Add a bullet list"
msgstr "Додати ненумерований ÑпиÑок"
@@ -1674,7 +1771,7 @@ msgid "Add a numbered list"
msgstr "Додати нумерований ÑпиÑок"
msgid "Add a related issue"
-msgstr ""
+msgstr "Додати пов'Ñзану задачу"
msgid "Add a table"
msgstr "Додати таблицю"
@@ -1689,7 +1786,7 @@ msgid "Add an SSH key"
msgstr "Додати SSH ключ"
msgid "Add an existing issue"
-msgstr ""
+msgstr "Додати Ñ–Ñнуючу задачу"
msgid "Add an impersonation token"
msgstr ""
@@ -1743,14 +1840,11 @@ msgid "Add italic text"
msgstr "Додати курÑивний текÑÑ‚"
msgid "Add key"
-msgstr ""
+msgstr "Додати ключ"
msgid "Add label(s)"
msgstr "Додати мітку(-ки)"
-msgid "Add license"
-msgstr "Додати ліцензію"
-
msgid "Add list"
msgstr "Додати ÑпиÑок"
@@ -1899,7 +1993,7 @@ msgid "Admin Overview"
msgstr "ОглÑд адмініÑтратора"
msgid "Admin Section"
-msgstr ""
+msgstr "Розділ ÐдмініÑтруваннÑ"
msgid "Admin mode already enabled"
msgstr "Режим адмініÑтратора вже ввімкнено"
@@ -1925,21 +2019,51 @@ msgstr "Заблоковані кориÑтувачі"
msgid "AdminArea|Bots"
msgstr "Боти"
+msgid "AdminArea|Components"
+msgstr ""
+
msgid "AdminArea|Developer"
msgstr "Розробник"
+msgid "AdminArea|Features"
+msgstr ""
+
+msgid "AdminArea|Groups: %{number_of_groups}"
+msgstr ""
+
msgid "AdminArea|Guest"
msgstr "ГіÑÑ‚ÑŒ"
msgid "AdminArea|Included Free in license"
msgstr "Безкоштовно включені в ліцензію"
+msgid "AdminArea|Latest groups"
+msgstr ""
+
+msgid "AdminArea|Latest projects"
+msgstr ""
+
+msgid "AdminArea|Latest users"
+msgstr ""
+
msgid "AdminArea|Maintainer"
msgstr "Керівник"
+msgid "AdminArea|New group"
+msgstr ""
+
+msgid "AdminArea|New project"
+msgstr ""
+
+msgid "AdminArea|New user"
+msgstr ""
+
msgid "AdminArea|Owner"
msgstr "ВлаÑник"
+msgid "AdminArea|Projects: %{number_of_projects}"
+msgstr ""
+
msgid "AdminArea|Reporter"
msgstr "Репортер"
@@ -1967,6 +2091,9 @@ msgstr "КориÑтувачі з найвищою роллю"
msgid "AdminArea|Users without a Group and Project"
msgstr "КориÑтувачі без групи та проєкту"
+msgid "AdminArea|Users: %{number_of_users}"
+msgstr ""
+
msgid "AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running."
msgstr "Зараз ви зупинете вÑÑ– завданнÑ. Це обірве уÑÑ– запущені завданнÑ."
@@ -1985,9 +2112,6 @@ msgstr "Видалити"
msgid "AdminProjects|Delete Project %{projectName}?"
msgstr "Видалити проєкт %{projectName}?"
-msgid "AdminProjects|Delete project"
-msgstr "Видалити проєкт"
-
msgid "AdminSettings|Apply integration settings to all Projects"
msgstr "ЗаÑтоÑувати Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ñ–Ð½Ñ‚ÐµÐ³Ñ€Ð°Ñ†Ñ–Ñ— до вÑÑ–Ñ… проєктів"
@@ -2225,21 +2349,30 @@ msgstr "Коли кориÑтувач повторно увійде у ÑиÑÑ‚Ð
msgid "AdminUsers|Without projects"
msgstr "Без проєктів"
-msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
-msgstr "Ви збираєтеÑÑ Ð¾Ñтаточно видалити кориÑтувача %{username}. Пов'Ñзані з ним задачі, запити на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ñ– групи будуть передані загальноÑиÑтемному кориÑтувачеві \"Ghost User\". Щоб уникнути втрати даних, розглÑньте можливіÑÑ‚ÑŒ %{strong_start}Ð±Ð»Ð¾ÐºÑƒÐ²Ð°Ð½Ð½Ñ ÐºÐ¾Ñ€Ð¸Ñтувача%{strong_end} заміÑÑ‚ÑŒ видаленнÑ. ПіÑÐ»Ñ %{strong_start}Ð²Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ ÐºÐ¾Ñ€Ð¸Ñтувача%{strong_end}, його неможливо буде відновити."
+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 %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
-msgstr "Ви збираєтеÑÑ Ð¾Ñтаточно видалити кориÑтувача %{username}. Ð’ÑÑ– пов'Ñзані з ним задачі, запити на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ñ– групи будуть видалені. Щоб уникнути втрати даних, розглÑньте можливіÑÑ‚ÑŒ %{strong_start}Ð±Ð»Ð¾ÐºÑƒÐ²Ð°Ð½Ð½Ñ ÐºÐ¾Ñ€Ð¸Ñтувача%{strong_end} заміÑÑ‚ÑŒ видаленнÑ. ПіÑÐ»Ñ %{strong_start}Ð²Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ ÐºÐ¾Ñ€Ð¸Ñтувача%{strong_end}, його неможливо буде відновити."
+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 ""
msgid "AdminUsers|You cannot remove your own admin rights."
msgstr ""
+msgid "AdminUsers|You must transfer ownership or delete the groups owned by this user before you can delete their account"
+msgstr ""
+
msgid "Administration"
msgstr "ÐдмініÑтруваннÑ"
msgid "Advanced"
msgstr "Розширений"
+msgid "Advanced Search"
+msgstr ""
+
+msgid "Advanced Search with Elasticsearch"
+msgstr ""
+
msgid "Advanced Settings"
msgstr "Додаткові налаштуваннÑ"
@@ -2319,6 +2452,9 @@ msgstr ""
msgid "AlertManagement|Edit"
msgstr "Редагувати"
+msgid "AlertManagement|Environment"
+msgstr ""
+
msgid "AlertManagement|Events"
msgstr "Події"
@@ -2331,6 +2467,9 @@ msgstr "Інформаційне"
msgid "AlertManagement|Issue"
msgstr ""
+msgid "AlertManagement|Key"
+msgstr ""
+
msgid "AlertManagement|Low"
msgstr "Ðизьке"
@@ -2424,6 +2563,9 @@ msgstr ""
msgid "AlertManagement|Unknown"
msgstr "Ðевідоме"
+msgid "AlertManagement|Value"
+msgstr ""
+
msgid "AlertManagement|View alerts in Opsgenie"
msgstr ""
@@ -2557,7 +2699,7 @@ msgid "All environments"
msgstr "Ð’ÑÑ– Ñередовища"
msgid "All epics"
-msgstr ""
+msgstr "Ð’ÑÑ– епіки"
msgid "All features are enabled for blank projects, from templates, or when importing, but you can disable them afterward in the project settings."
msgstr "Ð’ÑÑ– функції Ð´Ð»Ñ Ð½Ð¾Ð²Ð¸Ñ… проєктів берутьÑÑ Ñ–Ð· шаблонів або під Ñ‡Ð°Ñ Ñ–Ð¼Ð¿Ð¾Ñ€Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ, але ви можете вимикати Ñ—Ñ… пізніше в налаштуваннÑÑ… проєкту."
@@ -2583,6 +2725,9 @@ msgstr "Ð’ÑÑ– шлÑхи Ñ” відноÑними до URL-адреÑи GitLab.
msgid "All projects"
msgstr "Ð’ÑÑ– проєкти"
+msgid "All projects selected"
+msgstr ""
+
msgid "All security scans are enabled because %{linkStart}Auto DevOps%{linkEnd} is enabled on this project"
msgstr "Ð’ÑÑ– ÑÐºÐ°Ð½ÑƒÐ²Ð°Ð½Ð½Ñ Ð±ÐµÐ·Ð¿ÐµÐºÐ¸ увімкнені, тому що %{linkStart}Auto DevOps%{linkEnd} увімкнено в цьому проєкті"
@@ -2670,6 +2815,9 @@ msgstr "ДозволÑÑ” додавати та керувати клаÑтера
msgid "Almost there"
msgstr "Майже готово"
+msgid "Already blocked"
+msgstr ""
+
msgid "Also called \"Issuer\" or \"Relying party trust identifier\""
msgstr "Також відомий Ñк «Емітент» або «Ідентифікатор довіри перевірÑючої Ñторони»"
@@ -2724,6 +2872,9 @@ msgstr "Порожнє поле Gitlab-кориÑтувача буде запоÐ
msgid "An error has occurred"
msgstr "ТрапилаÑÑ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ°"
+msgid "An error occured while making the changes: %{error}"
+msgstr ""
+
msgid "An error occurred adding a draft to the thread."
msgstr "Помилка при додаванні чернетки до обговореннÑ."
@@ -2751,12 +2902,6 @@ msgstr "СталаÑÑ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ° під Ñ‡Ð°Ñ Ð¿Ð¾Ð¿ÐµÑ€ÐµÐ´Ð½ÑŒÐ¾Ð³Ð¾ пÐ
msgid "An error occurred when toggling the notification subscription"
msgstr "Виникла помилка під Ñ‡Ð°Ñ Ð·Ð¼Ñ–Ð½Ð¸ підпиÑки на ÑповіщеннÑ"
-msgid "An error occurred when trying to resolve a comment. Please try again."
-msgstr "Помилка при вирішенні коментарÑ. Будь лаÑка, Ñпробуйте знову."
-
-msgid "An error occurred when trying to resolve a discussion. Please try again."
-msgstr "Помилка при вирішенні обговореннÑ. Будь лаÑка, Ñпробуйте знову."
-
msgid "An error occurred when updating the issue weight"
msgstr "Збій під Ñ‡Ð°Ñ Ð¾Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ð²Ð°Ð³Ð¸ задачі"
@@ -2772,12 +2917,6 @@ msgstr "Помилка під Ñ‡Ð°Ñ Ð´Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ð²Ñ–Ð´Ñ„Ð¾Ñ€Ð¼Ð°Ñ‚Ð¾Ð²Ð°
msgid "An error occurred while checking group path. Please refresh and try again."
msgstr ""
-msgid "An error occurred while committing your changes."
-msgstr "Помилка при коміті ваших змін."
-
-msgid "An error occurred while creating the list. Please try again."
-msgstr ""
-
msgid "An error occurred while decoding the file."
msgstr "СталаÑÑ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ° під Ñ‡Ð°Ñ Ð´ÐµÐºÐ¾Ð´ÑƒÐ²Ð°Ð½Ð½Ñ Ñ„Ð°Ð¹Ð»Ñƒ."
@@ -2850,26 +2989,20 @@ msgstr ""
msgid "An error occurred while fetching the Service Desk address."
msgstr "СталаÑÑ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ° під Ñ‡Ð°Ñ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ Ð°Ð´Ñ€ÐµÑи Служби підтримки."
-msgid "An error occurred while fetching the board issues. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the board lists. Please reload the page."
msgstr ""
msgid "An error occurred while fetching the board lists. Please try again."
msgstr "Помилка при отриманні ÑпиÑків дошки. Будь лаÑка, Ñпробуйте знову."
-msgid "An error occurred while fetching the board swimlanes. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the builds."
msgstr "Помилка при отриманні збірок."
msgid "An error occurred while fetching the job log."
msgstr "Помилка при отриманні логів завданнÑ."
-msgid "An error occurred while fetching the job trace."
-msgstr "Помилка при отриманні логу завданнÑ."
+msgid "An error occurred while fetching the job logs."
+msgstr ""
msgid "An error occurred while fetching the job."
msgstr "Помилка при отриманні завданнÑ."
@@ -3015,9 +3148,6 @@ msgstr "Помилка при збереженні ÑтатуÑу перевиз
msgid "An error occurred while saving assignees"
msgstr "Помилка при збереженні виконавців"
-msgid "An error occurred while saving the template. Please check if the template exists."
-msgstr "Під Ñ‡Ð°Ñ Ð·Ð±ÐµÑ€ÐµÐ¶ÐµÐ½Ð½Ñ ÑˆÐ°Ð±Ð»Ð¾Ð½Ñƒ ÑталаÑÑ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ°. Будь лаÑка, перевірте, чи такий шаблон Ñ–Ñнує."
-
msgid "An error occurred while searching for milestones"
msgstr ""
@@ -3036,12 +3166,12 @@ msgstr "Помилка при відпиÑці від Ñповіщень."
msgid "An error occurred while updating approvers"
msgstr "Помилка при оновленні затверджуючих оÑіб"
+msgid "An error occurred while updating labels."
+msgstr ""
+
msgid "An error occurred while updating the comment"
msgstr "Під Ñ‡Ð°Ñ Ð¾Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ ÐºÐ¾Ð¼ÐµÐ½Ñ‚Ð°Ñ€Ñ ÑталаÑÑ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ°"
-msgid "An error occurred while updating the list. Please try again."
-msgstr ""
-
msgid "An error occurred while validating group path"
msgstr "Помилка при перевірці шлÑху групи"
@@ -3093,6 +3223,9 @@ msgstr "Ðеочікувана помилка при зупинці Веб-теÑ
msgid "An unknown error occurred while loading this graph."
msgstr ""
+msgid "An unknown error occurred."
+msgstr ""
+
msgid "Analytics"
msgstr "Ðналітика"
@@ -3126,12 +3259,12 @@ msgstr "Перевірка проти Ñпаму"
msgid "Any"
msgstr "Будь-Ñкий"
+msgid "Any %{header}"
+msgstr ""
+
msgid "Any Author"
msgstr "Будь-Ñкий автор"
-msgid "Any Status"
-msgstr ""
-
msgid "Any branch"
msgstr "Будь-Ñка гілка"
@@ -3183,6 +3316,9 @@ msgstr "Додаток"
msgid "Application ID"
msgstr "Ідентифікатор заÑтоÑунку"
+msgid "Application limits saved successfully"
+msgstr ""
+
msgid "Application settings saved successfully"
msgstr "ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð·Ð°ÑтоÑунку уÑпішно збережено"
@@ -3253,7 +3389,7 @@ msgid "Applying suggestions..."
msgstr ""
msgid "Approval Status"
-msgstr ""
+msgstr "Ð¡Ñ‚Ð°Ñ‚ÑƒÑ Ð·Ð°Ñ‚Ð²ÐµÑ€Ð´Ð¶ÐµÐ½Ð½Ñ"
msgid "Approval rules"
msgstr "Правила затвердженнÑ"
@@ -3400,6 +3536,9 @@ msgstr "Ви впевнені, що хочете ÑкаÑувати редагу
msgid "Are you sure you want to close this blocked issue?"
msgstr "Ви впевнені, що хочете закрити цю заблоковану задачу?"
+msgid "Are you sure you want to delete \"%{name}\" Value Stream?"
+msgstr ""
+
msgid "Are you sure you want to delete %{name}?"
msgstr "Ви впевнені, що хочете видалити %{name}?"
@@ -3409,6 +3548,9 @@ msgstr "Ви впевнені, що бажаєте видалити ці артÐ
msgid "Are you sure you want to delete this %{typeOfComment}?"
msgstr "Ви впевнені що хочете видалити цей %{typeOfComment}?"
+msgid "Are you sure you want to delete this SSH key?"
+msgstr ""
+
msgid "Are you sure you want to delete this board?"
msgstr "Ви дійÑно бажаєте видалити цю дошку?"
@@ -3433,6 +3575,13 @@ msgstr "Ви впевнені, що хочете видалити цей комÐ
msgid "Are you sure you want to erase this build?"
msgstr "Ви впевнені, що хочете видалити цей білд?"
+msgid "Are you sure you want to import %d repository?"
+msgid_plural "Are you sure you want to import %d repositories?"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "Are you sure you want to lose unsaved changes?"
msgstr "Ви впевнені, що бажаєте втратити незбережені зміни?"
@@ -3442,15 +3591,15 @@ msgstr "Ви впевнені, що хочете втратити інформа
msgid "Are you sure you want to merge immediately?"
msgstr "Ви впевнені, що хочете об'єднати негайно?"
-msgid "Are you sure you want to permanently delete this license?"
-msgstr "Ви дійÑно бажаєте оÑтаточно видалити цю ліцензію?"
-
msgid "Are you sure you want to re-deploy this environment?"
msgstr ""
msgid "Are you sure you want to regenerate the public key? You will have to update the public key on the remote server before mirroring will work again."
msgstr "Ви впевнені, що хочете повторно згенерувати відкритий ключ? Вам доведетьÑÑ Ð¾Ð½Ð¾Ð²Ð¸Ñ‚Ð¸ відкритий ключ на віддаленому Ñервері, перш ніж Ð´Ð·ÐµÑ€ÐºÐ°Ð»ÑŽÐ²Ð°Ð½Ð½Ñ Ð·Ð°Ð¿Ñ€Ð°Ñ†ÑŽÑ” знову."
+msgid "Are you sure you want to reindex?"
+msgstr ""
+
msgid "Are you sure you want to remove %{group_name}?"
msgstr "Ви впевнені, що хочете видалити %{group_name}?"
@@ -3478,6 +3627,9 @@ msgstr ""
msgid "Are you sure you want to revoke this nickname?"
msgstr "Ви впевнені, що хочете ÑкаÑувати цей пÑевдонім?"
+msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
+msgstr ""
+
msgid "Are you sure you want to stop this environment?"
msgstr "Ви впевнені що хочете зупинити це Ñередовище?"
@@ -3499,6 +3651,9 @@ msgstr "Ви впевнені? Ð’Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ Ñ†ÑŒÐ¾Ð³Ð¾ GPG ключа не
msgid "Are you sure? The device will be signed out of GitLab and all remember me tokens revoked."
msgstr ""
+msgid "Are you sure? This will invalidate your registered applications and U2F / WebAuthn devices."
+msgstr ""
+
msgid "Are you sure? This will invalidate your registered applications and U2F devices."
msgstr "Ви впевнені? Це призведе до Ð°Ð½ÑƒÐ»ÑŽÐ²Ð°Ð½Ð½Ñ Ð·Ð°Ñ€ÐµÑ”Ñтрованих заÑтоÑунків та U2F приÑтроїв."
@@ -3517,9 +3672,6 @@ msgstr "Ðртефакт було уÑпішно видалено."
msgid "Artifacts"
msgstr "Ðртефакти"
-msgid "As U2F devices are only supported by a few browsers, we require that you set up a two-factor authentication app before a U2F device. That way you'll always be able to log in - even when you're using an unsupported browser."
-msgstr "ОÑкільки приÑтрої U2F підтримуютьÑÑ Ð»Ð¸ÑˆÐµ кількома браузерами, ми вимагаємо, щоб ви налаштували заÑтоÑунок Ð´Ð»Ñ Ð´Ð²Ð¾Ñ„Ð°ÐºÑ‚Ð¾Ñ€Ð½Ð¾Ñ— автентифікації перед приÑтроєм U2F. Таким чином ви завжди зможете увійти, навіть при викориÑтанні непідтримуваного браузера."
-
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 ""
@@ -3554,7 +3706,7 @@ msgid "Assign"
msgstr "Призначити"
msgid "Assign Iteration"
-msgstr ""
+msgstr "Призначити ітерацію"
msgid "Assign To"
msgstr ""
@@ -3667,7 +3819,7 @@ msgid "Attachment"
msgstr "ВкладеннÑ"
msgid "Attachments"
-msgstr ""
+msgstr "ВкладеннÑ"
msgid "Audit Events"
msgstr "Події аудиту"
@@ -3717,6 +3869,9 @@ msgstr "Події проєкту"
msgid "AuditLogs|Target"
msgstr "Ціль"
+msgid "AuditLogs|This month"
+msgstr ""
+
msgid "AuditLogs|User Events"
msgstr "Події кориÑтувача"
@@ -3756,11 +3911,14 @@ msgstr "Метод автентифікації оновлено"
msgid "Authentication via U2F device failed."
msgstr "Ðе вдалоÑÑ Ð²Ð¸ÐºÐ¾Ð½Ð°Ñ‚Ð¸ автентифікацію через U2F приÑтрій."
+msgid "Authentication via WebAuthn device failed."
+msgstr ""
+
msgid "Author"
msgstr "Ðвтор"
msgid "Author: %{author_name}"
-msgstr ""
+msgstr "Ðвтор: %{author_name}"
msgid "Authored %{timeago}"
msgstr ""
@@ -3775,7 +3933,7 @@ msgid "Authorization key"
msgstr "Ключ авторизації"
msgid "Authorization required"
-msgstr ""
+msgstr "Потрібна авторизаціÑ"
msgid "Authorization was granted by entering your username and password in the application."
msgstr "ÐÐ²Ñ‚Ð¾Ñ€Ð¸Ð·Ð°Ñ†Ñ–Ñ Ð²Ñ–Ð´Ð±ÑƒÐ»Ð°ÑÑ Ð¿Ñ–ÑÐ»Ñ Ð²Ð²Ð¾Ð´Ñƒ вашого імені та паролю у заÑтоÑунку."
@@ -4023,15 +4181,6 @@ msgstr "Коренева URL-адреÑа Bamboo, наприклад https://bam
msgid "BambooService|You must set up automatic revision labeling and a repository trigger in Bamboo."
msgstr "Ви повинні налаштувати автоматичне вÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ð¼Ñ–Ñ‚Ð¾Ðº на ревізії, а також тригер репозиторію в Bamboo."
-msgid "BatchComments|Delete all pending comments"
-msgstr "Видалити вÑÑ– коментарі в очікуванні"
-
-msgid "BatchComments|Discard review?"
-msgstr "Відхилити відгук?"
-
-msgid "BatchComments|You're about to discard your review which will delete all of your pending comments. The deleted comments %{strong_start}cannot%{strong_end} be restored."
-msgstr "Ви збираєтеÑÑ Ð²Ñ–Ð´Ñ…Ð¸Ð»Ð¸Ñ‚Ð¸ ваш відгук, що призведе до Ð²Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ Ð²ÑÑ–Ñ… ваших коментарів в очікуванні. Видалені коментарі %{strong_start}не можливо%{strong_end} буде відновити."
-
msgid "Be careful. Changing the project's namespace can have unintended side effects."
msgstr "Будьте обережні. Зміна проÑтору імен проєкту може мати небажані побічні ефекти."
@@ -4053,6 +4202,9 @@ msgstr "Ðижче ви знайдете вÑÑ– загальнодоÑтупні
msgid "Bi-weekly code coverage"
msgstr ""
+msgid "Billable Users:"
+msgstr ""
+
msgid "Billing"
msgstr "Білінг"
@@ -4062,8 +4214,8 @@ msgstr "%{group_name} наразі викориÑтовує план %{plan_name
msgid "BillingPlans|@%{user_name} you are currently using the %{plan_name} plan."
msgstr "@%{user_name} наразі ви викориÑтовуєте план %{plan_name}."
-msgid "BillingPlans|Congratulations, your new trial is activated"
-msgstr "Вітаємо, ваша нова пробна верÑÑ–Ñ Ð°ÐºÑ‚Ð¸Ð²Ð¾Ð²Ð°Ð½Ð°"
+msgid "BillingPlans|Congratulations, your free trial is activated."
+msgstr ""
msgid "BillingPlans|If you would like to downgrade your plan please contact %{support_link_start}Customer Support%{support_link_end}."
msgstr "Якщо ви хочете перейти на нижчий план, будь лаÑка, зв'ÑжітьÑÑ Ð· %{support_link_start}Службою підтримки%{support_link_end}."
@@ -4117,7 +4269,7 @@ msgid "Bitbucket Server Import"
msgstr "Імпорт з Bitbucket Server"
msgid "Bitbucket Server import"
-msgstr ""
+msgstr "Імпорт з Bitbucket Server"
msgid "Bitbucket import"
msgstr "Імпорт з Bitbucket"
@@ -4125,6 +4277,9 @@ msgstr "Імпорт з Bitbucket"
msgid "Blame"
msgstr ""
+msgid "Block user"
+msgstr ""
+
msgid "Blocked"
msgstr "Заблокований"
@@ -4135,36 +4290,42 @@ msgid "Blocking issues"
msgstr ""
msgid "Blocks"
-msgstr ""
+msgstr "Блокує"
msgid "Blog"
msgstr "Блог"
-msgid "Board name"
-msgstr "Ðазва дошки"
-
msgid "Board scope"
msgstr "ОблаÑÑ‚ÑŒ видимоÑÑ‚Ñ– дошки"
msgid "Board scope affects which issues are displayed for anyone who visits this board"
msgstr "ОблаÑÑ‚ÑŒ видимоÑÑ‚Ñ– дошки впливає на те, Ñкі задачі відображаютьÑÑ Ð´Ð»Ñ Ñ‚Ð¸Ñ…, хто Ñ—Ñ— переглÑдає"
-msgid "BoardBlankState|Add default lists"
-msgstr "Додати Ñтандартні ÑпиÑки"
+msgid "Boards"
+msgstr "Дошки"
+
+msgid "Boards and Board Lists"
+msgstr ""
+
+msgid "Boards|An error occurred while creating the issue. Please try again."
+msgstr ""
-msgid "BoardBlankState|Add the following default lists to your Issue Board with one click:"
-msgstr "Додати наÑтупні Ñтандартні ÑпиÑки до вашої дошки задач за допомогою одного кліка:"
+msgid "Boards|An error occurred while creating the list. Please try again."
+msgstr ""
-msgid "BoardBlankState|Nevermind, I'll use my own"
-msgstr "Забудьте, Ñ Ð±ÑƒÐ´Ñƒ викориÑтовувати влаÑні"
+msgid "Boards|An error occurred while fetching issues. Please reload the page."
+msgstr ""
-msgid "BoardBlankState|Starting out with the default set of lists will get you right on the way to making the most of your board."
-msgstr "Початок роботи з типовим набором ÑпиÑків допоможе вам отримати макÑимальну кориÑÑ‚ÑŒ від вашої дошки."
+msgid "Boards|An error occurred while fetching the board issues. Please reload the page."
+msgstr ""
-msgid "Boards"
-msgstr "Дошки"
+msgid "Boards|An error occurred while fetching the board swimlanes. Please reload the page."
+msgstr ""
-msgid "Boards and Board Lists"
+msgid "Boards|An error occurred while moving the issue. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while updating the list. Please try again."
msgstr ""
msgid "Boards|Collapse"
@@ -4191,8 +4352,8 @@ msgstr "Гілка %{branchName} відÑÑƒÑ‚Ð½Ñ Ð² репозиторії ць
msgid "Branch %{branch_name} was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr ""
-msgid "Branch has changed"
-msgstr "Гілка змінилаÑÑŒ"
+msgid "Branch changed"
+msgstr ""
msgid "Branch is already taken"
msgstr "Гілка вже Ñ–Ñнує"
@@ -4393,7 +4554,7 @@ msgid "Business metrics (Custom)"
msgstr "Ð‘Ñ–Ð·Ð½ÐµÑ Ð¼ÐµÑ‚Ñ€Ð¸ÐºÐ¸ (ВлаÑні)"
msgid "Buy License"
-msgstr ""
+msgstr "Придбати ліцензію"
msgid "Buy more Pipeline minutes"
msgstr ""
@@ -4402,7 +4563,7 @@ msgid "By %{user_name}"
msgstr "Від %{user_name}"
msgid "By URL"
-msgstr ""
+msgstr "За URL-адреÑою"
msgid "By clicking Register, I agree that I have read and accepted the GitLab %{linkStart}Terms of Use and Privacy Policy%{linkEnd}"
msgstr ""
@@ -4471,7 +4632,7 @@ msgid "CICD|Default to Auto DevOps pipeline"
msgstr "За замовчуваннÑм Ð´Ð»Ñ ÐºÐ¾Ð½Ð²ÐµÑ”Ñ€Ð° Auto DevOps"
msgid "CICD|Default to Auto DevOps pipeline for all projects"
-msgstr "ВикориÑтовувати Auto DevOps конвеєр за замовчуваннÑм Ð´Ð»Ñ ÑƒÑÑ–Ñ… проектів"
+msgstr "ВикориÑтовувати Auto DevOps конвеєр за замовчуваннÑм Ð´Ð»Ñ ÑƒÑÑ–Ñ… проєктів"
msgid "CICD|Deployment strategy"
msgstr "Ð¡Ñ‚Ñ€Ð°Ñ‚ÐµÐ³Ñ–Ñ Ñ€Ð¾Ð·Ð³Ð¾Ñ€Ñ‚Ð°Ð½Ð½Ñ"
@@ -4497,6 +4658,9 @@ msgstr "ЗÐКРИТО"
msgid "CLOSED (MOVED)"
msgstr "ЗÐКРИТО (ПЕРЕМІЩЕÐО)"
+msgid "CODEOWNERS rule violation"
+msgstr ""
+
msgid "CONTRIBUTING"
msgstr "CONTRIBUTING"
@@ -4527,9 +4691,6 @@ msgstr ""
msgid "Can't create snippet: %{err}"
msgstr ""
-msgid "Can't edit as source branch was deleted"
-msgstr ""
-
msgid "Can't fetch content for the blob: %{err}"
msgstr ""
@@ -4542,9 +4703,6 @@ msgstr "Ðеможливо знайти змінну: ZiteReader"
msgid "Can't load mermaid module: %{err}"
msgstr ""
-msgid "Can't remove group members without group managed account"
-msgstr "Ðеможливо видалити учаÑників групи без облікових запиÑів, що керуютьÑÑ Ð³Ñ€ÑƒÐ¿Ð¾ÑŽ"
-
msgid "Can't scan the code?"
msgstr "Ðеможливо Ñканувати код?"
@@ -4570,7 +4728,7 @@ msgid "Cancel this job"
msgstr "СкаÑувати це завданнÑ"
msgid "Cancel, keep project"
-msgstr ""
+msgstr "СкаÑувати, зберегти проєкт"
msgid "Canceled deployment to"
msgstr "СкаÑовано Ñ€Ð¾Ð·Ð³Ð¾Ñ€Ñ‚Ð°Ð½Ð½Ñ Ð½Ð°"
@@ -4587,6 +4745,9 @@ msgstr "Ðеможливо Ñтворити звіт про зловживанн
msgid "Cannot create the abuse report. This user has been blocked."
msgstr "Ðеможливо Ñтворити звіт про зловживаннÑ. КориÑтувача було заблоковано."
+msgid "Cannot enable shared runners because parent group does not allow it"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -4675,7 +4836,7 @@ msgid "Change status"
msgstr "Змінити ÑтатуÑ"
msgid "Change subscription"
-msgstr ""
+msgstr "Змінити підпиÑку"
msgid "Change template"
msgstr "Змінити шаблон"
@@ -4692,6 +4853,15 @@ msgstr "Змінити пароль"
msgid "Change your password or recover your current one"
msgstr "Змініть пароль або відновіть поточний"
+msgid "ChangeReviewer|Reviewer changed from %{old} to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Reviewer changed to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Unassigned"
+msgstr ""
+
msgid "ChangeTypeActionLabel|Pick into branch"
msgstr "Вибрати в гілці"
@@ -4731,6 +4901,9 @@ msgstr "Зміни приховано. ÐатиÑніть щоб показатÐ
msgid "Changes the title to \"%{title_param}\"."
msgstr "Змінює заголовок на \"%{title_param}\"."
+msgid "Changes were successfully made."
+msgstr ""
+
msgid "Changes won't take place until the index is %{link_start}recreated%{link_end}."
msgstr "Зміни не будуть заÑтоÑовані, поки Ñ–Ð½Ð´ÐµÐºÑ Ð½Ðµ буде %{link_start}перегенерований%{link_end}."
@@ -5023,13 +5196,13 @@ msgid "Choose file…"
msgstr "Виберіть файл…"
msgid "Choose labels"
-msgstr ""
+msgstr "Оберіть мітки"
msgid "Choose the top-level group for your repository imports."
msgstr "Оберіть групу найвищого Ñ€Ñ–Ð²Ð½Ñ Ð´Ð»Ñ Ñ–Ð¼Ð¿Ð¾Ñ€Ñ‚Ñƒ репозиторіїв."
msgid "Choose visibility level, enable/disable project features (issues, repository, wiki, snippets) and set permissions."
-msgstr "Виберіть рівень видимоÑÑ‚Ñ–, увімкніть/вимкніть функції Ð´Ð»Ñ Ð¿Ñ€Ð¾ÐµÐºÑ‚Ñƒ (задачі, репозиторій, вікі, Ñніпети) та вÑтановіть дозволи."
+msgstr "Виберіть рівень видимоÑÑ‚Ñ–, увімкніть/вимкніть функції Ð´Ð»Ñ Ð¿Ñ€Ð¾Ñ”ÐºÑ‚Ñƒ (задачі, репозиторій, вікі, Ñніпети) та вÑтановіть дозволи."
msgid "Choose what content you want to see on a group’s overview page."
msgstr ""
@@ -5136,6 +5309,9 @@ msgstr "Приховано"
msgid "CiVariables|Protected"
msgstr "Захищений"
+msgid "CiVariables|Remove variable"
+msgstr ""
+
msgid "CiVariables|Remove variable row"
msgstr "Видалити Ñ€Ñдок змінних"
@@ -5214,9 +5390,6 @@ msgstr "ОчиÑтити фільтри графіків"
msgid "Clear due date"
msgstr "ОчиÑтити дату завершеннÑ"
-msgid "Clear input"
-msgstr "ОчиÑтити ввід"
-
msgid "Clear recent searches"
msgstr "ОчиÑтити недавні пошуки"
@@ -5265,6 +5438,9 @@ msgstr "Ключ автентифікації клієнта"
msgid "Client authentication key password"
msgstr "Пароль ключа автентифікації клієнта"
+msgid "Client request timeout"
+msgstr ""
+
msgid "Clients"
msgstr "Клієнти"
@@ -5349,6 +5525,27 @@ msgstr "Рівень клаÑтера"
msgid "Cluster type must be specificed for Stages::ClusterEndpointInserter"
msgstr ""
+msgid "ClusterAgents|Configuration"
+msgstr ""
+
+msgid "ClusterAgents|Connect your cluster with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate Kubernetes with a GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Name"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Agent also requires %{linkStart}enabling the Agent Server%{linkEnd}"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Kubernetes Agent allows an Infrastructure as Code, GitOps approach to integrating Kubernetes clusters with GitLab. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "ClusterAgent|This feature is only available for premium plans"
msgstr ""
@@ -5395,16 +5592,16 @@ msgid "ClusterIntegration|Add a Kubernetes cluster integration"
msgstr "Додати інтеграцію із клаÑтером Kubernetes"
msgid "ClusterIntegration|Adding a Kubernetes cluster to your group will automatically share the cluster across all your projects. Use review apps, deploy your applications, and easily run your pipelines for all projects using the same cluster."
-msgstr "Ð”Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ ÐºÐ»Ð°Ñтера Kubernetes до вашої групи автоматично зробить його доÑтупним у вÑÑ–Ñ… ваших проектах. ВикориÑтовуйте Review Apps, розгортайте заÑтоÑунки Ñ– легко запуÑкайте Ñвої конвеєри Ð´Ð»Ñ Ð²ÑÑ–Ñ… проектів з викориÑтаннÑм цього клаÑтера."
+msgstr "Ð”Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ ÐºÐ»Ð°Ñтера Kubernetes до вашої групи автоматично зробить його доÑтупним у вÑÑ–Ñ… ваших проєктах. ВикориÑтовуйте Review Apps, розгортайте заÑтоÑунки Ñ– легко запуÑкайте Ñвої конвеєри Ð´Ð»Ñ Ð²ÑÑ–Ñ… проєктів з викориÑтаннÑм цього клаÑтера."
msgid "ClusterIntegration|Adding a Kubernetes cluster will automatically share the cluster across all projects. Use review apps, deploy your applications, and easily run your pipelines for all projects using the same cluster."
-msgstr "Ð”Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ ÐºÐ»Ð°Ñтера Kubernetes автоматично зробить його доÑтупним у вÑÑ–Ñ… ваших проектах. ВикориÑтовуйте Review Apps, розгортайте заÑтоÑунки Ñ– легко запуÑкайте Ñвої конвеєри Ð´Ð»Ñ Ð²ÑÑ–Ñ… проектів з викориÑтаннÑм цього клаÑтера."
+msgstr "Ð”Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ ÐºÐ»Ð°Ñтера Kubernetes автоматично зробить його доÑтупним у вÑÑ–Ñ… ваших проєктах. ВикориÑтовуйте Review Apps, розгортайте заÑтоÑунки Ñ– легко запуÑкайте Ñвої конвеєри Ð´Ð»Ñ Ð²ÑÑ–Ñ… проєктів з викориÑтаннÑм цього клаÑтера."
msgid "ClusterIntegration|Adding an integration to your group will share the cluster across all your projects."
-msgstr "Ð”Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ñ–Ð½Ñ‚ÐµÐ³Ñ€Ð°Ñ†Ñ–Ñ— до вашої групи надаÑÑ‚ÑŒ доÑтуп до клаÑтера у вÑÑ–Ñ… ваших проектах."
+msgstr "Ð”Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ñ–Ð½Ñ‚ÐµÐ³Ñ€Ð°Ñ†Ñ–Ñ— до вашої групи надаÑÑ‚ÑŒ доÑтуп до клаÑтера у вÑÑ–Ñ… ваших проєктах."
msgid "ClusterIntegration|Adding an integration will share the cluster across all projects."
-msgstr "Ð”Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ñ–Ð½Ñ‚ÐµÐ³Ñ€Ð°Ñ†Ñ–Ñ— надаÑÑ‚ÑŒ доÑтуп до клаÑтера у вÑÑ–Ñ… ваших проектах."
+msgstr "Ð”Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ñ–Ð½Ñ‚ÐµÐ³Ñ€Ð°Ñ†Ñ–Ñ— надаÑÑ‚ÑŒ доÑтуп до клаÑтера у вÑÑ–Ñ… ваших проєктах."
msgid "ClusterIntegration|Advanced options on this Kubernetes cluster’s integration"
msgstr ""
@@ -5418,11 +5615,11 @@ msgstr "Ð’ÑÑ– дані буде видалено Ñ– вони не зможутÑ
msgid "ClusterIntegration|All installed applications and related resources"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster."
-msgstr "Дозволити GitLab керувати проÑторами імен (namespace) та Ñлужбовими обліковими запиÑами (service account) в цьому клаÑтері."
+msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{linkStart}More information%{linkEnd}"
+msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{startLink}More information%{endLink}"
-msgstr "Дозволити GitLab керувати проÑторами імен (namespace) та Ñлужбовими обліковими запиÑами (service account) в цьому клаÑтері. %{startLink}ДізнатиÑÑ Ð±Ñ–Ð»ÑŒÑˆÐµ%{endLink}"
+msgid "ClusterIntegration|Allow GitLab to manage namespaces and service accounts for this cluster."
+msgstr ""
msgid "ClusterIntegration|Alternatively, "
msgstr ""
@@ -5434,14 +5631,17 @@ msgid "ClusterIntegration|An error occurred when trying to contact the Google Cl
msgstr "Помилка під Ñ‡Ð°Ñ Ð·'Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ð· Google Cloud API. Будь лаÑка, Ñпробуйте знову пізніше."
msgid "ClusterIntegration|An error occurred while trying to fetch project zones: %{error}"
-msgstr "Помилка при отриманні зон проекту: %{error}"
+msgstr "Помилка при отриманні зон проєкту: %{error}"
msgid "ClusterIntegration|An error occurred while trying to fetch your projects: %{error}"
-msgstr "Помилка при отриманні ваших проектів: %{error}"
+msgstr "Помилка при отриманні ваших проєктів: %{error}"
msgid "ClusterIntegration|An error occurred while trying to fetch zone machine types: %{error}"
msgstr "Помилка при отриманні типів машин зони: %{error}"
+msgid "ClusterIntegration|An unknown error occurred while attempting to connect to Kubernetes."
+msgstr ""
+
msgid "ClusterIntegration|Any project namespaces"
msgstr ""
@@ -5457,6 +5657,9 @@ msgstr "ÐÐ²Ñ‚ÐµÐ½Ñ‚Ð¸Ñ„Ñ–ÐºÐ°Ñ†Ñ–Ñ Ñ‡ÐµÑ€ÐµÐ· AWS"
msgid "ClusterIntegration|Authenticate with Amazon Web Services"
msgstr "ÐÐ²Ñ‚ÐµÐ½Ñ‚Ð¸Ñ„Ñ–ÐºÐ°Ñ†Ñ–Ñ Ñ‡ÐµÑ€ÐµÐ· Amazon Web Services"
+msgid "ClusterIntegration|Authentication Error"
+msgstr ""
+
msgid "ClusterIntegration|Base domain"
msgstr "ОÑновний домен"
@@ -5475,14 +5678,23 @@ msgstr ""
msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
msgstr "Ðабір Ñертифікатів (формат PEM)"
-msgid "ClusterIntegration|Choose the %{startLink}security group %{externalLinkIcon} %{endLink} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
-msgstr "Вибрати %{startLink}групу безпеки%{externalLinkIcon} %{endLink} Ð´Ð»Ñ Ð·Ð°ÑтоÑÑƒÐ²Ð°Ð½Ð½Ñ Ð´Ð¾ Elastic Network Interfaces, керованих EKS, Ñ– Ñтворених в підмережах ваших робочих вузлів."
+msgid "ClusterIntegration|Check your CA certificate"
+msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}subnets %{externalLinkIcon} %{endLink} in your VPC where your worker nodes will run."
-msgstr "Виберіть %{startLink}підмережі%{externalLinkIcon} %{endLink} вашої VPC де будуть запуÑкатиÑÑ Ð²Ð°ÑˆÑ– робочі вузли."
+msgid "ClusterIntegration|Check your cluster status"
+msgstr ""
-msgid "ClusterIntegration|Choose the worker node %{startLink}instance type %{externalLinkIcon} %{endLink}."
-msgstr "Вибрати %{startLink}тип інÑтанÑу %{externalLinkIcon}%{endLink} робочого вузла."
+msgid "ClusterIntegration|Check your token"
+msgstr ""
+
+msgid "ClusterIntegration|Choose the %{linkStart}security group %{linkEnd} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
+msgstr ""
+
+msgid "ClusterIntegration|Choose the %{linkStart}subnets %{linkEnd} in your VPC where your worker nodes will run."
+msgstr ""
+
+msgid "ClusterIntegration|Choose the worker node %{linkStart}instance type%{linkEnd}."
+msgstr ""
msgid "ClusterIntegration|Choose which applications to install on your Kubernetes cluster."
msgstr ""
@@ -5493,10 +5705,7 @@ msgstr "Виберіть, Ñке із ваших Ñередовищ буде вÐ
msgid "ClusterIntegration|Clear cluster cache"
msgstr "ОчиÑтити кеш клаÑтера"
-msgid "ClusterIntegration|Clear the local cache of namespace and service accounts. This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
-msgstr ""
-
-msgid "ClusterIntegration|Cluster being created"
+msgid "ClusterIntegration|Clear the local cache of namespace and service accounts."
msgstr ""
msgid "ClusterIntegration|Cluster management project (alpha)"
@@ -5508,15 +5717,21 @@ msgstr "Ім'Ñ ÐºÐ»Ð°Ñтера Ñ” обов'Ñзковим."
msgid "ClusterIntegration|Cluster_applications artifact too big. Maximum allowable size: %{human_size}"
msgstr ""
-msgid "ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters."
-msgstr "КлаÑтери викориÑтовуютьÑÑ ÑˆÐ»Ñхом вибору найближчого предка з підходÑщою доÑтупніÑÑ‚ÑŽ Ð´Ð»Ñ Ñередовищ. Ðаприклад проєктні клаÑтери перекривають групові клаÑтери."
-
msgid "ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters. %{linkStart}More information%{linkEnd}"
msgstr ""
+msgid "ClusterIntegration|Clusters connected with a certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Connect cluster with certificate"
+msgstr ""
+
msgid "ClusterIntegration|Connect existing cluster"
msgstr ""
+msgid "ClusterIntegration|Connection Error"
+msgstr ""
+
msgid "ClusterIntegration|Copy API URL"
msgstr "Скопіювати API URL"
@@ -5592,6 +5807,12 @@ msgstr ""
msgid "ClusterIntegration|Deletes all GitLab resources attached to this cluster during removal"
msgstr ""
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared."
+msgstr ""
+
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared. %{linkStart}More information%{linkEnd}"
+msgstr ""
+
msgid "ClusterIntegration|Did you know?"
msgstr "Чи знаєте ви?"
@@ -5661,6 +5882,9 @@ msgstr "Fluentd"
msgid "ClusterIntegration|Fluentd is an open source data collector, which lets you unify the data collection and consumption for a better use and understanding of data. It requires at least one of the following logs to be successfully installed."
msgstr ""
+msgid "ClusterIntegration|GitLab Agent managed clusters"
+msgstr ""
+
msgid "ClusterIntegration|GitLab Container Network Policies"
msgstr ""
@@ -5673,6 +5897,12 @@ msgstr "GitLab Runner"
msgid "ClusterIntegration|GitLab Runner connects to the repository and executes CI/CD jobs, pushing results back and deploying applications to production."
msgstr "Runner Gitlab з’єднуєтьÑÑ Ñ–Ð· репозиторієм та запуÑкає Ð·Ð°Ð²Ð´Ð°Ð½Ð½Ñ CI/CD, повертаючи результати та розгортаючи заÑтоÑунки в production."
+msgid "ClusterIntegration|GitLab failed to authenticate."
+msgstr ""
+
+msgid "ClusterIntegration|GitLab failed to connect to the cluster."
+msgstr ""
+
msgid "ClusterIntegration|GitLab-managed cluster"
msgstr "КлаÑтер, що керуєтьÑÑ GitLab"
@@ -5694,6 +5924,9 @@ msgstr "проєкті Google Kubernetes Engine"
msgid "ClusterIntegration|Group cluster"
msgstr "КлаÑтер групи"
+msgid "ClusterIntegration|HTTP Error"
+msgstr ""
+
msgid "ClusterIntegration|Helm Tiller"
msgstr "Helm Tiller"
@@ -5727,8 +5960,11 @@ msgstr "КлаÑтер інÑтанÑу"
msgid "ClusterIntegration|Instance type"
msgstr "Тип інÑтанÑу"
-msgid "ClusterIntegration|Integrate Kubernetes cluster automation"
-msgstr "Ð†Ð½Ñ‚ÐµÐ³Ñ€Ð°Ñ†Ñ–Ñ ÐºÐ»Ð°Ñтерної автоматизації Kubernetes"
+msgid "ClusterIntegration|Integrate Kubernetes with a cluster certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Integrate with a cluster certificate"
+msgstr ""
msgid "ClusterIntegration|Issuer Email"
msgstr "Електронна пошта емітента"
@@ -5763,9 +5999,6 @@ msgstr "Доменне Ñ–Ð¼â€™Ñ Knative уÑпішно оновлено."
msgid "ClusterIntegration|Knative extends Kubernetes to provide a set of middleware components that are essential to build modern, source-centric, and container-based applications that can run anywhere: on premises, in the cloud, or even in a third-party data center."
msgstr "Knative розширює Kubernetes, щоб забезпечити набір middleware-компонентів, необхідних Ð´Ð»Ñ ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ ÑучаÑних, source-centric заÑтоÑунків на оÑнові контейнерів, Ñкі можна запуÑкати в будь-Ñкому міÑці: локально, у хмарі, Ñ– навіть в Ñторонніх дата-центрах."
-msgid "ClusterIntegration|Kubernetes cluster"
-msgstr "Kubernetes-клаÑтер"
-
msgid "ClusterIntegration|Kubernetes cluster is being created..."
msgstr "СтворюєтьÑÑ ÐºÐ»Ð°Ñтер Kubernetes..."
@@ -5778,9 +6011,6 @@ msgstr "КлаÑтер Kubernetes було уÑпішно Ñтворено."
msgid "ClusterIntegration|Kubernetes clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr "Kubernetes-клаÑтери дозволÑÑŽÑ‚ÑŒ вам викориÑтовувати Review Apps, розгортати ваші заÑтоÑунки, запуÑкати конвеєри Ñ– багато іншого проÑтим ÑпоÑобом."
-msgid "ClusterIntegration|Kubernetes clusters can be used to deploy applications and to provide Review Apps for this project"
-msgstr "Kubernetes-клаÑтери можуть бути викориÑтані Ð´Ð»Ñ Ñ€Ð¾Ð·Ð³Ð¾Ñ€Ñ‚Ð°Ð½Ð½Ñ Ð·Ð°ÑтоÑунків Ñ– викориÑÑ‚Ð°Ð½Ð½Ñ Review Apps Ð´Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ проекту"
-
msgid "ClusterIntegration|Kubernetes version"
msgstr "ВерÑÑ–Ñ Kubernetes"
@@ -5793,8 +6023,8 @@ msgstr "ДізнайтеÑÑ Ð±Ñ–Ð»ÑŒÑˆÐµ про %{help_link_start_machine_type}
msgid "ClusterIntegration|Learn more about %{help_link_start}zones%{help_link_end}."
msgstr "ДізнайтеÑÑ Ð±Ñ–Ð»ÑŒÑˆÐµ про %{help_link_start}зони%{help_link_end}."
-msgid "ClusterIntegration|Learn more about %{startLink}Regions %{externalLinkIcon}%{endLink}."
-msgstr "ДізнатиÑÑ Ð±Ñ–Ð»ÑŒÑˆÐµ про %{startLink}Регіони %{externalLinkIcon}%{endLink}."
+msgid "ClusterIntegration|Learn more about %{linkStart}Regions%{linkEnd}."
+msgstr ""
msgid "ClusterIntegration|Learn more about Kubernetes"
msgstr "ДізнайтеÑÑ Ð±Ñ–Ð»ÑŒÑˆÐµ про Kubernetes"
@@ -5838,12 +6068,18 @@ msgstr ""
msgid "ClusterIntegration|Machine type"
msgstr "Тип машини"
+msgid "ClusterIntegration|Make sure your API endpoint is correct"
+msgstr ""
+
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create Kubernetes clusters"
msgstr "ВпевнітьÑÑ, що ваш обліковий Ð·Ð°Ð¿Ð¸Ñ %{link_to_requirements} Ð´Ð»Ñ ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Kubernetes-клаÑтерів"
msgid "ClusterIntegration|Manage your Kubernetes cluster by visiting %{provider_link}"
msgstr ""
+msgid "ClusterIntegration|Namespace per environment"
+msgstr ""
+
msgid "ClusterIntegration|No IAM Roles found"
msgstr "Ролі IAM не найдені"
@@ -5872,7 +6108,7 @@ msgid "ClusterIntegration|No projects found"
msgstr "Проектів не знайдено"
msgid "ClusterIntegration|No projects matched your search"
-msgstr "Жоден проект не відповідає вашому пошуку"
+msgstr "Жоден проєкт не відповідає вашому пошуку"
msgid "ClusterIntegration|No region found"
msgstr "Регіони не знайдено"
@@ -5889,6 +6125,9 @@ msgstr ""
msgid "ClusterIntegration|No zones matched your search"
msgstr "Жодна зона не відповідає вашому пошуку"
+msgid "ClusterIntegration|Node calculations use the Kubernetes Metrics API. Make sure your cluster has metrics installed"
+msgstr ""
+
msgid "ClusterIntegration|Number of nodes"
msgstr "КількіÑÑ‚ÑŒ вузлів"
@@ -5905,13 +6144,13 @@ msgid "ClusterIntegration|Point a wildcard DNS to this generated endpoint in ord
msgstr "Ðаправте ваш DNS на цю згенеровану кінцеву точку, щоб отримати доÑтуп до вашого заÑтоÑунку, піÑÐ»Ñ Ð¹Ð¾Ð³Ð¾ розгортаннÑ."
msgid "ClusterIntegration|Project cluster"
-msgstr "КлаÑтер проекту"
+msgstr "КлаÑтер проєкту"
msgid "ClusterIntegration|Project namespace (optional, unique)"
-msgstr "ПроÑÑ‚Ñ–Ñ€ імен проекту (не обов’Ñзковий, унікальний)"
+msgstr "ПроÑÑ‚Ñ–Ñ€ імен проєкту (не обов’Ñзковий, унікальний)"
msgid "ClusterIntegration|Project namespace prefix (optional, unique)"
-msgstr "ÐŸÑ€ÐµÑ„Ñ–ÐºÑ Ð¿Ñ€Ð¾Ñтору імен проекту (не обов’Ñзковий, унікальний)"
+msgstr "ÐŸÑ€ÐµÑ„Ñ–ÐºÑ Ð¿Ñ€Ð¾Ñтору імен проєкту (не обов’Ñзковий, унікальний)"
msgid "ClusterIntegration|Prometheus"
msgstr "Prometheus"
@@ -5931,6 +6170,9 @@ msgstr "ARN ролі Ð´Ð»Ñ Ð¿Ñ€Ð¾Ð²Ñ–Ð·Ñ–ÑŽÐ²Ð°Ð½Ð½Ñ"
msgid "ClusterIntegration|RBAC-enabled cluster"
msgstr "КлаÑтер з підтримкою RBAC"
+msgid "ClusterIntegration|Read our %{linkStart}help page%{linkEnd} on Kubernetes cluster integration."
+msgstr ""
+
msgid "ClusterIntegration|Read our %{link_start}help page%{link_end} on Kubernetes cluster integration."
msgstr "ПереглÑньте %{link_start}Ñторінку довідки%{link_end} по інтеграції з Kubernetes клаÑтером."
@@ -5956,7 +6198,7 @@ msgid "ClusterIntegration|Remove integration?"
msgstr "Видалити інтеграцію?"
msgid "ClusterIntegration|Remove this Kubernetes cluster's configuration from this project. This will not delete your actual Kubernetes cluster."
-msgstr "Видалити конфігурацію Kubernetes-клаÑтера Ð´Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ проекту. Це не призведе до Ð²Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ Ñамого клаÑтера."
+msgstr "Видалити конфігурацію Kubernetes-клаÑтера Ð´Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ проєкту. Це не призведе до Ð²Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ Ñамого клаÑтера."
msgid "ClusterIntegration|Removes cluster from project but keeps associated resources"
msgstr "ВидалÑÑ” клаÑтер із проєкту, але зберігає пов'Ñзані реÑурÑи"
@@ -6004,7 +6246,7 @@ msgid "ClusterIntegration|Search networks"
msgstr "Пошук мереж"
msgid "ClusterIntegration|Search projects"
-msgstr "Пошук проектів"
+msgstr "Пошук проєктів"
msgid "ClusterIntegration|Search regions"
msgstr "Пошук регіонів"
@@ -6033,8 +6275,8 @@ msgstr "Виберіть VPC Ð´Ð»Ñ Ð²Ð¸Ð±Ð¾Ñ€Ñƒ групи безпеки"
msgid "ClusterIntegration|Select a VPC to choose a subnet"
msgstr "Виберіть VPC Ð´Ð»Ñ Ð²Ð¸Ð±Ð¾Ñ€Ñƒ підмережі"
-msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
-msgstr "Виберіть VPC Ð´Ð»Ñ Ð²Ð¸ÐºÐ¾Ñ€Ð¸ÑÑ‚Ð°Ð½Ð½Ñ Ð´Ð»Ñ Ð²Ð°ÑˆÐ¸Ñ… реÑурÑів EKS клаÑтеру. Ð”Ð»Ñ Ð²Ð¸ÐºÐ¾Ñ€Ð¸ÑÑ‚Ð°Ð½Ð½Ñ Ð½Ð¾Ð²Ð¾Ñ— VPC, Ñпочатку Ñтворіть Ñ—Ñ— в %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{linkStart}Amazon Web Services %{linkEnd}."
+msgstr ""
msgid "ClusterIntegration|Select a network to choose a subnetwork"
msgstr "Виберіть мережу Ð´Ð»Ñ Ð²Ð¸Ð±Ð¾Ñ€Ñƒ підмережі"
@@ -6058,16 +6300,16 @@ msgid "ClusterIntegration|Select machine type"
msgstr "Вибрати тип машин"
msgid "ClusterIntegration|Select project"
-msgstr "Вибрати проект"
+msgstr "Вибрати проєкт"
msgid "ClusterIntegration|Select project and zone to choose machine type"
-msgstr "Виберіть проект та зону Ð´Ð»Ñ Ñ‚Ð¾Ð³Ð¾, що вибрати тип машини"
+msgstr "Виберіть проєкт та зону Ð´Ð»Ñ Ñ‚Ð¾Ð³Ð¾, що вибрати тип машини"
msgid "ClusterIntegration|Select project to choose zone"
-msgstr "Виберіть проект, щоб вибрати зону"
+msgstr "Виберіть проєкт, щоб вибрати зону"
-msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
-msgstr "Виберіть назву пари ключів, Ñка буде викориÑтовуватиÑÑ Ð´Ð»Ñ ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð²ÑƒÐ·Ð»Ñ–Ð² EC2. Ð”Ð»Ñ Ð²Ð¸ÐºÐ¾Ñ€Ð¸ÑÑ‚Ð°Ð½Ð½Ñ Ð½Ð¾Ð²Ð¾Ð³Ð¾ імені пари ключів, Ñпочатку Ñтворіть його у %{startLink}Amazon Web Services %{externalLinkIcon}%{endLink}."
+msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
+msgstr ""
msgid "ClusterIntegration|Select zone"
msgstr "Вибрати зону"
@@ -6156,9 +6398,18 @@ msgstr ""
msgid "ClusterIntegration|There was a problem authenticating with your cluster. Please ensure your CA Certificate and Token are valid."
msgstr "Проблема автентифікації у вашому клаÑтері. Будь лаÑка, переконайтеÑÑ, що Ñертифікат CA та токен Ñ” правильними."
+msgid "ClusterIntegration|There was an HTTP error when connecting to your cluster."
+msgstr ""
+
msgid "ClusterIntegration|This account must have permissions to create a Kubernetes cluster in the %{link_to_container_project} specified below"
msgstr "Цей обліковий Ð·Ð°Ð¿Ð¸Ñ Ð¿Ð¾Ð²Ð¸Ð½ÐµÐ½ мати наÑтупні права Ð´Ð»Ñ ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Kubernetes-клаÑтера в %{link_to_container_project}"
+msgid "ClusterIntegration|This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
+msgstr ""
+
+msgid "ClusterIntegration|This is necessary to clear existing environment-namespace associations from clusters previously managed by GitLab."
+msgstr ""
+
msgid "ClusterIntegration|This option will allow you to install applications on RBAC clusters."
msgstr "Цей параметр дозволить вам вÑтановлювати заÑтоÑунки на клаÑтери RBAC."
@@ -6183,9 +6434,21 @@ msgstr "Щоб видалити Ñвою інтеграцію, введіть %{
msgid "ClusterIntegration|To use a new project, first create one on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}."
msgstr ""
+msgid "ClusterIntegration|Troubleshooting tips:"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Authenticate"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Connect"
+msgstr ""
+
msgid "ClusterIntegration|Uninstall %{appTitle}"
msgstr "Видалити %{appTitle}"
+msgid "ClusterIntegration|Unknown Error"
+msgstr ""
+
msgid "ClusterIntegration|Update %{appTitle}"
msgstr ""
@@ -6202,16 +6465,16 @@ msgid "ClusterIntegration|VPC"
msgstr "VPC"
msgid "ClusterIntegration|Validating project billing status"
-msgstr "Перевірка Ñтану білінгу проекта"
+msgstr "Перевірка Ñтану білінгу проєкта"
msgid "ClusterIntegration|We could not verify that one of your projects on GCP has billing enabled. Please try again."
-msgstr "Ми не змогли перевірити, що один із ваших проектів в GCP має ввімкнений білінг. Будь лаÑка, Ñпробуйте ще раз."
+msgstr "Ми не змогли перевірити, що один із ваших проєктів в GCP має ввімкнений білінг. Будь лаÑка, Ñпробуйте ще раз."
msgid "ClusterIntegration|We were unable to fetch any projects. Ensure that you have a project on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}."
msgstr ""
msgid "ClusterIntegration|With a Kubernetes cluster associated to this project, you can use review apps, deploy your applications, run your pipelines, and much more in an easy way."
-msgstr "За допомогою підключеного до цього проєкту Kubernetes-клаÑтера, ви можете викориÑтовувати Review Apps, розгортати ваші проекти, запуÑкати конвеєри збірки тощо."
+msgstr "За допомогою підключеного до цього проєкту Kubernetes-клаÑтера, ви можете викориÑтовувати Review Apps, розгортати ваші проєкти, запуÑкати конвеєри збірки тощо."
msgid "ClusterIntegration|You are about to remove your cluster integration and all GitLab-created resources associated with this cluster."
msgstr "Ви збираєтеÑÑ Ð²Ð¸Ð´Ð°Ð»Ð¸Ñ‚Ð¸ інтеграцію вашого клаÑтера та вÑÑ– реÑурÑи пов'Ñзані з цим клаÑтером, Ñкі були Ñтворені GitLab."
@@ -6246,8 +6509,8 @@ msgstr "Ваш обліковий Ð·Ð°Ð¿Ð¸Ñ Ð¿Ð¾Ð²Ð¸Ð½ÐµÐ½ мати %{link_to_k
msgid "ClusterIntegration|Your cluster API is unreachable. Please ensure your API URL is correct."
msgstr "API вашого клаÑтера недоÑтупний. ПереконайтеÑÑ, що ваш API URL правильний."
-msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
-msgstr "Ваша Ñлужбова роль відмінна від ролі Ð´Ð»Ñ Ð¿Ñ€Ð¾Ð²Ñ–Ð·Ñ–ÑŽÐ²Ð°Ð½Ð½Ñ, Ñка викориÑтовувалаÑÑ Ð¿Ñ€Ð¸ автентифікації. Це дозволить Amazon EKS та панелі ÑƒÐ¿Ñ€Ð°Ð²Ð»Ñ–Ð½Ð½Ñ Kubernetes керувати реÑурÑами AWS від вашого імені. Ð”Ð»Ñ Ð²Ð¸ÐºÐ¾Ñ€Ð¸ÑÑ‚Ð°Ð½Ð½Ñ Ð½Ð¾Ð²Ð¾Ð³Ð¾ імені ролі, Ñпочатку Ñтворіть Ñ—Ñ— в %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
+msgstr ""
msgid "ClusterIntegration|Zone"
msgstr "Зона"
@@ -6366,6 +6629,9 @@ msgstr "Когорти кориÑтувачів показано за оÑтан
msgid "Collapse"
msgstr "Згорнути"
+msgid "Collapse all threads"
+msgstr ""
+
msgid "Collapse approvers"
msgstr "Згорнути ÑпиÑок затверджуючих оÑіб"
@@ -6517,8 +6783,8 @@ msgstr "Коміт від"
msgid "Commit…"
msgstr "Коміт…"
-msgid "Company"
-msgstr "КомпаніÑ"
+msgid "Community forum"
+msgstr ""
msgid "Company name"
msgstr "Ðазва компанії"
@@ -6526,6 +6792,9 @@ msgstr "Ðазва компанії"
msgid "Compare"
msgstr "ПорівнÑти"
+msgid "Compare %{oldCommitId}...%{newCommitId}"
+msgstr ""
+
msgid "Compare Git revisions"
msgstr "ПорівнÑти Git-редакції"
@@ -6541,6 +6810,9 @@ msgstr "ПорівнÑти зміни з оÑтаннім комітом"
msgid "Compare changes with the merge request target branch"
msgstr "ПорівнÑти зміни із ціловою гілкою запиту на злиттÑ"
+msgid "Compare submodule commit revisions"
+msgstr ""
+
msgid "Compare with previous version"
msgstr "ПорівнÑти із попередньою верÑією"
@@ -6563,10 +6835,10 @@ msgid "Complete"
msgstr "Завершено"
msgid "Completed"
-msgstr ""
+msgstr "Завершено"
msgid "Compliance"
-msgstr ""
+msgstr "ВідповідніÑÑ‚ÑŒ"
msgid "Compliance Dashboard"
msgstr ""
@@ -6614,7 +6886,7 @@ msgid "ComplianceFramework|This project is regulated by %{framework}."
msgstr ""
msgid "Confidence"
-msgstr ""
+msgstr "ВпевненіÑÑ‚ÑŒ"
msgid "Confidential"
msgstr "Конфіденційний"
@@ -6659,7 +6931,7 @@ msgid "Configure limits for web and API requests."
msgstr "Ðалаштуйте Ð¾Ð±Ð¼ÐµÐ¶ÐµÐ½Ð½Ñ Ð´Ð»Ñ Ð²ÐµÐ± та API запитів."
msgid "Configure limits on the number of inbound alerts able to be sent to a project."
-msgstr "Ðалаштувати Ð¾Ð±Ð¼ÐµÐ¶ÐµÐ½Ð½Ñ ÐºÑ–Ð»ÑŒÐºÐ¾ÑÑ‚Ñ– вхідних попереджень, Ñкі можна надіÑлати у проект."
+msgstr "Ðалаштувати Ð¾Ð±Ð¼ÐµÐ¶ÐµÐ½Ð½Ñ ÐºÑ–Ð»ÑŒÐºÐ¾ÑÑ‚Ñ– вхідних попереджень, Ñкі можна надіÑлати у проєкт."
msgid "Configure paths to be protected by Rack Attack."
msgstr "Ðалаштуйте шлÑхи Ð´Ð»Ñ Ð·Ð°Ñ…Ð¸Ñту від атак Rack Attack."
@@ -6676,6 +6948,9 @@ msgstr "ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ñ–Ð½Ñ‚ÐµÐ³Ñ€Ð°Ñ†Ñ–Ñ— з %{link}."
msgid "Configure the way a user creates a new account."
msgstr "Ðалаштувати ÑпоÑіб ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ ÐºÐ¾Ñ€Ð¸Ñтувачем нового облікового запиÑу."
+msgid "Configure which lists are shown for anyone who visits this board"
+msgstr ""
+
msgid "Confirm"
msgstr "Підтвердити"
@@ -6716,7 +6991,7 @@ msgid "Connect repositories from GitHub"
msgstr "Підключити репозиторії з GitHub"
msgid "Connect your external repositories, and CI/CD pipelines will run for new commits. A GitLab project will be created with only CI/CD features enabled."
-msgstr "Підключіть ваші зовнішні репозиторії, Ñ– CI/CD конвеєри будуть запуÑкатиÑÑ Ð´Ð»Ñ Ð½Ð¾Ð²Ð¸Ñ… комітів. Створений GitLab-проект буде мати лише CI/CD фунції."
+msgstr "Підключіть ваші зовнішні репозиторії, Ñ– CI/CD конвеєри будуть запуÑкатиÑÑ Ð´Ð»Ñ Ð½Ð¾Ð²Ð¸Ñ… комітів. Створений GitLab-проєкт буде мати лише CI/CD фунції."
msgid "Connected"
msgstr "Підключено"
@@ -6746,7 +7021,7 @@ msgid "Contact sales to upgrade"
msgstr "ЗвернітьÑÑ Ð´Ð¾ відділу продажів Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÑ…Ð¾Ð´Ñƒ на вищий тарифний план"
msgid "Contact support"
-msgstr ""
+msgstr "ЗвернутиÑÑ Ð´Ð¾ Ñлужби підтримки"
msgid "Container Registry"
msgstr "РеєÑÑ‚Ñ€ Контейнерів"
@@ -6764,7 +7039,7 @@ msgid "Container registry is not enabled on this GitLab instance. Ask an adminis
msgstr "РеєÑÑ‚Ñ€ контейнерів не включений у даний інÑÑ‚Ð°Ð½Ñ GitLab. ПопроÑÑ–Ñ‚ÑŒ адмініÑтратора включити його Ð´Ð»Ñ Ñ‚Ð¾Ð³Ð¾, щоб Auto DevOps працював."
msgid "Container repositories"
-msgstr ""
+msgstr "Репозиторії контейнерів"
msgid "Container repositories sync capacity"
msgstr ""
@@ -6907,6 +7182,9 @@ msgstr[3] "Видалити тегів"
msgid "ContainerRegistry|Set cleanup policy"
msgstr ""
+msgid "ContainerRegistry|Some tags were not deleted"
+msgstr ""
+
msgid "ContainerRegistry|Something went wrong while fetching the cleanup policy."
msgstr ""
@@ -6946,6 +7224,9 @@ msgstr ""
msgid "ContainerRegistry|Tags with names matching this regex pattern will %{italicStart}expire:%{italicEnd}"
msgstr ""
+msgid "ContainerRegistry|The cleanup policy timed out before it could delete all tags. An administrator can %{adminLinkStart}manually run cleanup now%{adminLinkEnd} or you can wait for the cleanup policy to automatically run again. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "ContainerRegistry|The last tag related to this image was recently removed. This empty image and any associated data will be automatically removed as part of the regular Garbage Collection process. If you have any questions, contact your administrator."
msgstr "ОÑтанній тег Ñкий відноÑивÑÑ Ð´Ð¾ цього образу нещодавно було видалено. Цей порожній образ та вÑÑ– пов’Ñзані дані будуть автоматично видалені під Ñ‡Ð°Ñ Ñ€ÐµÐ³ÑƒÐ»Ñрного \"збору ÑміттÑ\". Якщо у Ð²Ð°Ñ Ñ” питаннÑ, звернітьÑÑ Ð´Ð¾ Ñвого адмініÑтратора."
@@ -6956,7 +7237,7 @@ msgid "ContainerRegistry|There are no container images available in this group"
msgstr "В цій групі немає образів контейнерів"
msgid "ContainerRegistry|There are no container images stored for this project"
-msgstr "Ð”Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ проекту не збережено жодного образу контейнерів"
+msgstr "Ð”Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ проєкту не збережено жодного образу контейнерів"
msgid "ContainerRegistry|There was an error during the deletion of this image repository, please try again."
msgstr ""
@@ -6983,10 +7264,10 @@ msgid "ContainerRegistry|Wildcards such as %{codeStart}.*-test%{codeEnd} or %{co
msgstr ""
msgid "ContainerRegistry|With the Container Registry, every project can have its own space to store its Docker images. %{docLinkStart}More Information%{docLinkEnd}"
-msgstr "За допомогою РеєÑтру контейнерів, кожен проект може мати влаÑний проÑÑ‚Ñ–Ñ€ Ð´Ð»Ñ Ñ€Ð¾Ð·Ð¼Ñ–Ñ‰ÐµÐ½Ð½Ñ Ð¾Ð±Ñ€Ð°Ð·Ñ–Ð² Docker. %{docLinkStart}ДізнатиÑÑ Ð±Ñ–Ð»ÑŒÑˆÐµ%{docLinkEnd}"
+msgstr "За допомогою РеєÑтру контейнерів, кожен проєкт може мати влаÑний проÑÑ‚Ñ–Ñ€ Ð´Ð»Ñ Ñ€Ð¾Ð·Ð¼Ñ–Ñ‰ÐµÐ½Ð½Ñ Ð¾Ð±Ñ€Ð°Ð·Ñ–Ð² Docker. %{docLinkStart}ДізнатиÑÑ Ð±Ñ–Ð»ÑŒÑˆÐµ%{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 "За допомогою РеєÑтру Контейнерів кожен проект може мати влаÑний проÑÑ‚Ñ–Ñ€ Ð´Ð»Ñ Ð·Ð±ÐµÑ€Ñ–Ð³Ð°Ð½Ð½Ñ Docker-образів. РозміÑÑ‚Ñ–Ñ‚ÑŒ хоча б один Docker-образ у ÑкомуÑÑŒ із проектів групи щоб його тут побачити. %{docLinkStart}Детальніше%{docLinkEnd}"
+msgstr "За допомогою РеєÑтру Контейнерів кожен проєкт може мати влаÑний проÑÑ‚Ñ–Ñ€ Ð´Ð»Ñ Ð·Ð±ÐµÑ€Ñ–Ð³Ð°Ð½Ð½Ñ Docker-образів. РозміÑÑ‚Ñ–Ñ‚ÑŒ хоча б один Docker-образ у ÑкомуÑÑŒ із проєктів групи щоб його тут побачити. %{docLinkStart}Детальніше%{docLinkEnd}"
msgid "ContainerRegistry|With the GitLab Container Registry, every project can have its own space to store images. %{docLinkStart}More information%{docLinkEnd}"
msgstr ""
@@ -7078,6 +7359,9 @@ msgstr ""
msgid "Contributions per group member"
msgstr "КількіÑÑ‚ÑŒ внеÑків на кожного учаÑника групи"
+msgid "Contributor"
+msgstr ""
+
msgid "Contributors"
msgstr "УчаÑники"
@@ -7163,7 +7447,7 @@ msgid "Copy labels and milestone from %{source_issuable_reference}."
msgstr "Скопіювати мітки та етап із %{source_issuable_reference}."
msgid "Copy labels and milestone from other issue or merge request in this project"
-msgstr "Скопіювати мітки та етап з іншої задачі чи запиту на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð² цьому проекті"
+msgstr "Скопіювати мітки та етап з іншої задачі чи запиту на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð² цьому проєкті"
msgid "Copy link"
msgstr "Скопіювати поÑиланнÑ"
@@ -7184,7 +7468,7 @@ msgid "Copy the code below to implement tracking in your application:"
msgstr ""
msgid "Copy to clipboard"
-msgstr ""
+msgstr "Копіювати в буфер обміну"
msgid "Copy token"
msgstr "Скопіювати токен"
@@ -7207,6 +7491,9 @@ msgstr "Ðе вдалоÑÑ Ð°Ð²Ñ‚Ð¾Ñ€Ð¸Ð·ÑƒÐ²Ð°Ñ‚Ð¸ пÑевдонім Ð´Ð»Ñ Ñ
msgid "Could not change HEAD: branch '%{branch}' does not exist"
msgstr "Ðе можливо змінити HEAD: гілка \"%{branch}\" не Ñ–Ñнує"
+msgid "Could not commit. An unexpected error occurred."
+msgstr ""
+
msgid "Could not connect to FogBugz, check your URL"
msgstr "Ðе можливо зв’ÑзатиÑÑ Ñ–Ð· FogBugz, перевірте URL-адреÑу"
@@ -7229,7 +7516,7 @@ msgid "Could not create issue"
msgstr ""
msgid "Could not create project"
-msgstr "Ðе вдалоÑÑ Ñтворити проект"
+msgstr "Ðе вдалоÑÑ Ñтворити проєкт"
msgid "Could not create wiki page"
msgstr ""
@@ -7244,6 +7531,9 @@ msgid "Could not find design."
msgstr "Ðе вдалоÑÑ Ð·Ð½Ð°Ð¹Ñ‚Ð¸ дизайн."
msgid "Could not find iteration"
+msgstr "Ðе вдалоÑÑ Ð·Ð½Ð°Ð¹Ñ‚Ð¸ ітерацію"
+
+msgid "Could not load instance counts. Please refresh the page to try again."
msgstr ""
msgid "Could not remove the trigger."
@@ -7265,17 +7555,17 @@ msgid "Could not save group ID"
msgstr "Ðе вдалоÑÑ Ð·Ð±ÐµÑ€ÐµÐ³Ñ‚Ð¸ ID групи."
msgid "Could not save project ID"
-msgstr "Ðе вдалоÑÑ Ð·Ð±ÐµÑ€ÐµÐ³Ñ‚Ð¸ ідентифікатор проекту"
+msgstr "Ðе вдалоÑÑ Ð·Ð±ÐµÑ€ÐµÐ³Ñ‚Ð¸ ідентифікатор проєкту"
msgid "Could not save prometheus manual configuration"
msgstr "Ðе вдалоÑÑ Ð·Ð±ÐµÑ€ÐµÐ³Ñ‚Ð¸ ручні Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Prometheus"
-msgid "Could not udpdate wiki page"
-msgstr ""
-
msgid "Could not update the LDAP settings"
msgstr "Ðе вдалоÑÑ Ð¾Ð½Ð¾Ð²Ð¸Ñ‚Ð¸ Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ LDAP."
+msgid "Could not update wiki page"
+msgstr ""
+
msgid "Could not upload your designs as one or more files uploaded are not supported."
msgstr "Ðе вдалоÑÑ Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶Ð¸Ñ‚Ð¸ ваші дизайни, оÑкільки один або кілька файлів, що завантажуютьÑÑ, не підтримуютьÑÑ."
@@ -7398,7 +7688,7 @@ msgid "Create issue"
msgstr "Створити задачу"
msgid "Create iteration"
-msgstr ""
+msgstr "Створити ітерацію"
msgid "Create lists from labels. Issues with that label appear in that list."
msgstr "Створити ÑпиÑок на оÑнові міток. Ð’ ньому будуть задачі з такими мітками."
@@ -7446,10 +7736,10 @@ msgid "Create new..."
msgstr "Створити..."
msgid "Create project"
-msgstr "Створити проект"
+msgstr "Створити проєкт"
msgid "Create project label"
-msgstr "Створити мітку проекту"
+msgstr "Створити мітку проєкту"
msgid "Create release"
msgstr ""
@@ -7509,10 +7799,10 @@ msgid "Created by me"
msgstr "Створено мною"
msgid "Created by:"
-msgstr ""
+msgstr "Ðвтор:"
msgid "Created date"
-msgstr ""
+msgstr "Дата ÑтвореннÑ"
msgid "Created issue %{issueLink}"
msgstr "Створено задачу %{issueLink}"
@@ -7539,7 +7829,7 @@ msgid "Creates branch '%{branch_name}' and a merge request to resolve this issue
msgstr "Створює гілку \"%{branch_name}\" та запит на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð´Ð»Ñ Ð²Ð¸Ñ€Ñ–ÑˆÐµÐ½Ð½Ñ Ñ†Ñ–Ñ”Ñ— проблеми."
msgid "Creating"
-msgstr ""
+msgstr "СтвореннÑ"
msgid "Creating epic"
msgstr "Ð¡Ñ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ ÐµÐ¿Ñ–ÐºÑƒ"
@@ -7569,7 +7859,7 @@ msgid "Cron Timezone"
msgstr "ЧаÑовий поÑÑ Cron"
msgid "Cron time zone"
-msgstr ""
+msgstr "ЧаÑовий поÑÑ Cron"
msgid "Crossplane"
msgstr "Crossplane"
@@ -7581,13 +7871,13 @@ msgid "Current Plan"
msgstr "Поточний План"
msgid "Current Project"
-msgstr "Поточний проект"
+msgstr "Поточний проєкт"
msgid "Current node"
msgstr "Поточний вузол"
msgid "Current node must be the primary node or you will be locking yourself out"
-msgstr "Поточний вузол повинен бути оÑновним, інакше ви будете заблоковані."
+msgstr "Поточний вузол повинен бути оÑновним, інакше ви будете заблоковані"
msgid "Current password"
msgstr "Поточний пароль"
@@ -7635,10 +7925,10 @@ msgid "Custom notification levels are the same as participating levels. With cus
msgstr "Спеціальні рівні Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ñпівпадають з рівнем учаÑÑ‚Ñ–. За допомогою Ñпеціальних рівнів Ñповіщень ви також отримуватимете ÑÐ¿Ð¾Ð²Ñ–Ñ‰ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾ вибрані події. Щоб дізнатиÑÑŒ більше, переглÑньте %{notification_link}."
msgid "Custom project templates"
-msgstr "ВлаÑні шаблони проектів"
+msgstr "ВлаÑні шаблони проєктів"
msgid "Custom project templates have not been set up for groups that you are a member of. They are enabled from a group’s settings page. Contact your group’s Owner or Maintainer to setup custom project templates."
-msgstr "ВлаÑні шаблони проектів не налаштовані Ð´Ð»Ñ Ð³Ñ€ÑƒÐ¿, до Ñких ви входите. Вони активуютьÑÑ Ð½Ð° Ñторінці налаштувань групи. ЗвернітьÑÑ Ð´Ð¾ влаÑника або керівника вашої групи Ð´Ð»Ñ Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð²Ð»Ð°Ñних шаблонів проектів."
+msgstr "ВлаÑні шаблони проєктів не налаштовані Ð´Ð»Ñ Ð³Ñ€ÑƒÐ¿, до Ñких ви входите. Вони активуютьÑÑ Ð½Ð° Ñторінці налаштувань групи. ЗвернітьÑÑ Ð´Ð¾ влаÑника або керівника вашої групи Ð´Ð»Ñ Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð²Ð»Ð°Ñних шаблонів проєктів."
msgid "Custom range"
msgstr "КориÑтувацький діапазон"
@@ -7695,7 +7985,7 @@ msgid "CustomCycleAnalytics|Update stage"
msgstr "Оновити Ñтадію"
msgid "Customer Portal"
-msgstr ""
+msgstr "Портал клієнтів"
msgid "Customizable by an administrator."
msgstr ""
@@ -7704,10 +7994,10 @@ msgid "Customize colors"
msgstr "ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ ÐºÐ¾Ð»ÑŒÐ¾Ñ€Ñ–Ð²"
msgid "Customize how FogBugz email addresses and usernames are imported into GitLab. In the next step, you'll be able to select the projects you want to import."
-msgstr "Ðалаштуйте, Ñк адреÑи електронної пошти та імена кориÑтувачів FogBugz імпортуютьÑÑ Ð² GitLab. Ðа наÑтупному кроці ви зможете вибрати проекти, Ñкі потрібно імпортувати."
+msgstr "Ðалаштуйте, Ñк адреÑи електронної пошти та імена кориÑтувачів FogBugz імпортуютьÑÑ Ð² GitLab. Ðа наÑтупному кроці ви зможете вибрати проєкти, Ñкі потрібно імпортувати."
msgid "Customize how Google Code email addresses and usernames are imported into GitLab. In the next step, you'll be able to select the projects you want to import."
-msgstr "Ðалаштуйте, Ñк адреÑи електронної пошти та імена кориÑтувачів Google Code імпортуютьÑÑ Ð² GitLab. Ðа наÑтупному кроці ви зможете вибрати проекти, Ñкі потрібно імпортувати."
+msgstr "Ðалаштуйте, Ñк адреÑи електронної пошти та імена кориÑтувачів Google Code імпортуютьÑÑ Ð² GitLab. Ðа наÑтупному кроці ви зможете вибрати проєкти, Ñкі потрібно імпортувати."
msgid "Customize icon"
msgstr "Ðалаштувати значок"
@@ -7930,11 +8220,14 @@ msgid "Dashboard|%{firstProject}, %{rest}, and %{secondProject}"
msgstr "%{firstProject}, %{rest}, Ñ– %{secondProject}"
msgid "Dashboard|Unable to add %{invalidProjects}. This dashboard is available for public projects, and private projects in groups with a Silver plan."
-msgstr "Ðе вдалоÑÑ Ð´Ð¾Ð´Ð°Ñ‚Ð¸ %{invalidProjects}. Ð¦Ñ Ð¿Ð°Ð½ÐµÐ»ÑŒ ÐºÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð´Ð¾Ñтупна Ð´Ð»Ñ Ð¿ÑƒÐ±Ð»Ñ–Ñ‡Ð½Ð¸Ñ… проектів та приватних проектів в групах із планом Silver."
+msgstr "Ðе вдалоÑÑ Ð´Ð¾Ð´Ð°Ñ‚Ð¸ %{invalidProjects}. Ð¦Ñ Ð¿Ð°Ð½ÐµÐ»ÑŒ ÐºÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð´Ð¾Ñтупна Ð´Ð»Ñ Ð¿ÑƒÐ±Ð»Ñ–Ñ‡Ð½Ð¸Ñ… проєктів та приватних проєктів в групах із планом Silver."
msgid "DastProfiles|Are you sure you want to delete this profile?"
msgstr ""
+msgid "DastProfiles|Could not create site validation token. Please refresh the page, or try again later."
+msgstr ""
+
msgid "DastProfiles|Could not create the scanner profile. Please try again."
msgstr ""
@@ -7959,6 +8252,12 @@ msgstr ""
msgid "DastProfiles|Could not fetch site profiles. Please refresh the page, or try again later."
msgstr ""
+msgid "DastProfiles|Could not retrieve site validation status. Please refresh the page, or try again later."
+msgstr ""
+
+msgid "DastProfiles|Could not update the scanner profile. Please try again."
+msgstr ""
+
msgid "DastProfiles|Could not update the site profile. Please try again."
msgstr ""
@@ -7974,7 +8273,7 @@ msgstr ""
msgid "DastProfiles|Download validation text file"
msgstr ""
-msgid "DastProfiles|Edit feature will come soon. Please create a new profile if changes needed"
+msgid "DastProfiles|Edit scanner profile"
msgstr ""
msgid "DastProfiles|Edit site profile"
@@ -8007,6 +8306,9 @@ msgstr ""
msgid "DastProfiles|No profiles created yet"
msgstr ""
+msgid "DastProfiles|Passive"
+msgstr ""
+
msgid "DastProfiles|Please enter a valid URL format, ex: http://www.example.com/home"
msgstr ""
@@ -8022,6 +8324,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan mode"
+msgstr ""
+
msgid "DastProfiles|Scanner Profile"
msgstr ""
@@ -8061,10 +8366,10 @@ msgstr ""
msgid "DastProfiles|Text file validation"
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
+msgid "DastProfiles|The maximum number of minutes allowed for the spider to traverse the site."
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the spider to traverse the site."
+msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
msgstr ""
msgid "DastProfiles|Validate"
@@ -8097,8 +8402,11 @@ msgstr "Дата"
msgid "Date picker"
msgstr "Вибір дати"
+msgid "Date range"
+msgstr ""
+
msgid "Date range cannot exceed %{maxDateRange} days."
-msgstr "Діапазон дат не може перевищувати %{maxDateRange} днів.\n"
+msgstr "Діапазон дат не може перевищувати %{maxDateRange} днів."
msgid "Day of month"
msgstr "День міÑÑцÑ"
@@ -8121,6 +8429,9 @@ msgstr "Днів"
msgid "Days to merge"
msgstr "Днів до злиттÑ"
+msgid "Dear Administrator,"
+msgstr ""
+
msgid "Debug"
msgstr "Відладка"
@@ -8158,7 +8469,7 @@ msgid "Default classification label"
msgstr "Мітка клаÑифікації за замовчуваннÑм"
msgid "Default deletion delay"
-msgstr ""
+msgstr "Стандартна затримка видаленнÑ"
msgid "Default description template for issues"
msgstr "Шаблон опиÑу задач за замовчуваннÑм"
@@ -8179,7 +8490,7 @@ msgid "Default issue template"
msgstr "Шаблон задач за замовчуваннÑм"
msgid "Default project deletion protection"
-msgstr "ЗахиÑÑ‚ від Ð²Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾ÐµÐºÑ‚Ñƒ за замовчуваннÑм"
+msgstr "ЗахиÑÑ‚ від Ð²Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾Ñ”ÐºÑ‚Ñƒ за замовчуваннÑм"
msgid "Default projects limit"
msgstr "Ліміт проєктів за замовчуваннÑм"
@@ -8209,7 +8520,7 @@ msgid "Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%
msgstr ""
msgid "Definition"
-msgstr ""
+msgstr "ВизначеннÑ"
msgid "Delayed Project Deletion (%{adjourned_deletion})"
msgstr ""
@@ -8232,15 +8543,21 @@ msgstr "відкладено"
msgid "Delete"
msgstr "Видалити"
+msgid "Delete %{name}"
+msgstr ""
+
msgid "Delete Comment"
msgstr "Видалити коментар"
msgid "Delete Snippet"
msgstr "Видалити Ñніпет"
-msgid "Delete account"
+msgid "Delete Value Stream"
msgstr ""
+msgid "Delete account"
+msgstr "Видалити обліковий запиÑ"
+
msgid "Delete artifacts"
msgstr "Видалити артефакти"
@@ -8259,9 +8576,6 @@ msgstr "Видалити мітку"
msgid "Delete label: %{label_name} ?"
msgstr "Видалити мітку: %{label_name}?"
-msgid "Delete license"
-msgstr "Видалити ліцензію"
-
msgid "Delete list"
msgstr "Видалити ÑпиÑок"
@@ -8299,19 +8613,19 @@ msgid "DeleteProject|Delete %{name}"
msgstr ""
msgid "DeleteProject|Failed to remove project repository. Please try again or contact administrator."
-msgstr "Помилка при видаленні репозиторію проекту. Будь лаÑка, Ñпробуйте знову, або зв'ÑжітьÑÑ Ñ–Ð· адмініÑтратором."
+msgstr "Помилка при видаленні репозиторію проєкту. Будь лаÑка, Ñпробуйте знову, або зв'ÑжітьÑÑ Ñ–Ð· адмініÑтратором."
msgid "DeleteProject|Failed to remove project snippets. Please try again or contact administrator."
msgstr "Ðе вдалоÑÑ Ð²Ð¸Ð´Ð°Ð»Ð¸Ñ‚Ð¸ Ñніпети проєкту. Будь лаÑка, Ñпробуйте ще раз або зв'ÑжітьÑÑ Ð· адмініÑтратором."
msgid "DeleteProject|Failed to remove some tags in project container registry. Please try again or contact administrator."
-msgstr "Помилка при видаленні деÑких тегів в реєÑтрі контейнерів проекту. Будь лаÑка, Ñпробуйте знову, або зв'ÑжітьÑÑ Ñ–Ð· адмініÑтратором."
+msgstr "Помилка при видаленні деÑких тегів в реєÑтрі контейнерів проєкту. Будь лаÑка, Ñпробуйте знову, або зв'ÑжітьÑÑ Ñ–Ð· адмініÑтратором."
msgid "DeleteProject|Failed to remove wiki repository. Please try again or contact administrator."
-msgstr "Помилка при видаленні вікі проекту. Будь лаÑка, Ñпробуйте знову, або зв'ÑжітьÑÑ Ñ–Ð· адмініÑтратором."
+msgstr "Помилка при видаленні вікі проєкту. Будь лаÑка, Ñпробуйте знову, або зв'ÑжітьÑÑ Ñ–Ð· адмініÑтратором."
msgid "DeleteProject|Failed to restore project repository. Please contact the administrator."
-msgstr "Помилка при відновленні репозиторію проекту. Будь лаÑка, Ñпробуйте знову, або зв'ÑжітьÑÑ Ñ–Ð· адмініÑтратором."
+msgstr "Помилка при відновленні репозиторію проєкту. Будь лаÑка, Ñпробуйте знову, або зв'ÑжітьÑÑ Ñ–Ð· адмініÑтратором."
msgid "DeleteProject|Failed to restore wiki repository. Please contact the administrator."
msgstr "Помилка при відновленні вікі репозиторію. Будь лаÑка, Ñпробуйте знову, або зв'ÑжітьÑÑ Ñ–Ð· адмініÑтратором."
@@ -8320,13 +8634,13 @@ msgid "Deleted"
msgstr "Видалено"
msgid "Deleted Projects"
-msgstr ""
+msgstr "Видалені проєкти"
msgid "Deleted chat nickname: %{chat_name}!"
msgstr "Видалено пÑевдонім Ð´Ð»Ñ Ñ‡Ð°Ñ‚Ñƒ: %{chat_name}!"
msgid "Deleted projects"
-msgstr ""
+msgstr "Видалені проєкти"
msgid "Deleted projects cannot be restored!"
msgstr ""
@@ -8337,15 +8651,6 @@ msgstr "ВидаленнÑ"
msgid "Deleting a project places it into a read-only state until %{date}, at which point the project will be permanently deleted. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "Deleting the license failed."
-msgstr "Ðе вдалоÑÑ Ð²Ð¸Ð´Ð°Ð»Ð¸Ñ‚Ð¸ ліцензію."
-
-msgid "Deleting the license failed. The license was not found."
-msgstr "Ðе вдалоÑÑ Ð²Ð¸Ð´Ð°Ð»Ð¸Ñ‚Ð¸ ліцензію. Ліцензію не знайдено."
-
-msgid "Deleting the license failed. You are not permitted to perform this action."
-msgstr "Ðе вдалоÑÑ Ð²Ð¸Ð´Ð°Ð»Ð¸Ñ‚Ð¸ ліцензію. У Ð²Ð°Ñ Ð½ÐµÐ¼Ð°Ñ” дозволів виконувати цю дію."
-
msgid "Deleting the project will delete its repository and all related resources including issues, merge requests etc."
msgstr ""
@@ -8353,7 +8658,7 @@ msgid "Deletion pending. This project will be removed on %{date}. Repository and
msgstr "ÐžÑ‡Ñ–ÐºÑƒÐ²Ð°Ð½Ð½Ñ Ð²Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ. Цей проєкт буде видалено %{date}. Репозиторій та інші реÑурÑи проєкту доÑтупні лише Ð´Ð»Ñ Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ."
msgid "Denied"
-msgstr ""
+msgstr "Відмовлено"
msgid "Denied authorization of chat nickname %{user_name}."
msgstr "Відмовлено в авторизації пÑевдоніму Ð´Ð»Ñ Ñ‡Ð°Ñ‚Ñƒ %{user_name}."
@@ -8362,7 +8667,7 @@ msgid "Deny"
msgstr "Заборонити"
msgid "Deny access request"
-msgstr ""
+msgstr "Відхилити запит доÑтупу"
msgid "Dependencies"
msgstr "ЗалежноÑÑ‚Ñ–"
@@ -8536,7 +8841,7 @@ msgid "DeployKeys|+%{count} others"
msgstr "+%{count} інших"
msgid "DeployKeys|Current project"
-msgstr "Поточний проект"
+msgstr "Поточний проєкт"
msgid "DeployKeys|Deploy key"
msgstr "Ключ Ð´Ð»Ñ Ñ€Ð¾Ð·Ð³Ð¾Ñ€Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ"
@@ -8554,7 +8859,7 @@ msgid "DeployKeys|Error removing deploy key"
msgstr "Помилка при видаленні ключа розгортаннÑ"
msgid "DeployKeys|Expand %{count} other projects"
-msgstr "Розгорнути %{count} інших проектів"
+msgstr "Розгорнути %{count} інших проєктів"
msgid "DeployKeys|Loading deploy keys"
msgstr "Ð—Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ ÐºÐ¾Ð»ÑŽÑ‡Ñ–Ð² розгортаннÑ"
@@ -8566,7 +8871,7 @@ msgid "DeployKeys|Privately accessible deploy keys"
msgstr "Приватні ключі розгортаннÑ"
msgid "DeployKeys|Project usage"
-msgstr "ВикориÑтовуєтьÑÑ Ñƒ проектах"
+msgstr "ВикориÑтовуєтьÑÑ Ñƒ проєктах"
msgid "DeployKeys|Publicly accessible deploy keys"
msgstr "Публічні ключі розгортаннÑ"
@@ -8671,7 +8976,7 @@ msgid "DeployTokens|Your new group deploy token has been created."
msgstr ""
msgid "DeployTokens|Your new project deploy token has been created."
-msgstr "Створено ваш новий токен Ñ€Ð¾Ð·Ð³Ð¾Ñ€Ñ‚Ð°Ð½Ð½Ñ Ð´Ð»Ñ Ð¿Ñ€Ð¾ÐµÐºÑ‚Ñƒ."
+msgstr "Створено ваш новий токен Ñ€Ð¾Ð·Ð³Ð¾Ñ€Ñ‚Ð°Ð½Ð½Ñ Ð´Ð»Ñ Ð¿Ñ€Ð¾Ñ”ÐºÑ‚Ñƒ."
msgid "Deployed"
msgstr "Розгорнуто"
@@ -8728,7 +9033,7 @@ msgid "Description parsed with %{link_start}GitLab Flavored Markdown%{link_end}"
msgstr "ÐžÐ¿Ð¸Ñ Ð¾Ð±Ñ€Ð¾Ð±Ð»ÐµÐ½Ð¾ за допомогою %{link_start}GitLab Flavored Markdown%{link_end}"
msgid "Description templates allow you to define context-specific templates for issue and merge request description fields for your project."
-msgstr "Шаблони опиÑу дозволÑÑŽÑ‚ÑŒ визначити конкретні шаблони задач та запитів на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð´Ð»Ñ Ð²Ð°ÑˆÐ¾Ð³Ð¾ проекту."
+msgstr "Шаблони опиÑу дозволÑÑŽÑ‚ÑŒ визначити конкретні шаблони задач та запитів на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð´Ð»Ñ Ð²Ð°ÑˆÐ¾Ð³Ð¾ проєкту."
msgid "Description:"
msgstr "ОпиÑ:"
@@ -8853,7 +9158,10 @@ msgstr "Виділити уÑÑ–"
msgid "DesignManagement|The maximum number of designs allowed to be uploaded is %{upload_limit}. Please try again."
msgstr "МакÑимальна кількіÑÑ‚ÑŒ дизайнів, Ñкі можна завантажити — %{upload_limit}. Будь лаÑка, Ñпробуйте знову."
-msgid "DesignManagement|To upload designs, you'll need to enable LFS. %{requirements_link_start}More information%{requirements_link_end}"
+msgid "DesignManagement|There was an error moving your designs. Please upload your designs below."
+msgstr ""
+
+msgid "DesignManagement|To upload designs, you'll need to enable LFS and have admin enable hashed storage. %{requirements_link_start}More information%{requirements_link_end}"
msgstr ""
msgid "DesignManagement|Unresolve thread"
@@ -8865,6 +9173,9 @@ msgstr ""
msgid "DesignManagement|Upload skipped."
msgstr ""
+msgid "DesignManagement|Your designs are being copied and are on their way… Please refresh to update."
+msgstr ""
+
msgid "DesignManagement|and %{moreCount} more."
msgstr ""
@@ -8887,10 +9198,10 @@ msgid "Detect host keys"
msgstr "ВиÑÐ²Ð»ÐµÐ½Ð½Ñ ÐºÐ»ÑŽÑ‡Ñ–Ð² хоÑта"
msgid "DevOps"
-msgstr ""
+msgstr "DevOps"
msgid "DevOps Report"
-msgstr ""
+msgstr "Звіт DevOps"
msgid "Diff content limits"
msgstr "ÐžÐ±Ð¼ÐµÐ¶ÐµÐ½Ð½Ñ Ð¿Ð¾Ñ€Ñ–Ð²Ð½ÑÐ½Ð½Ñ Ð·Ð¼Ñ–Ñту"
@@ -8922,6 +9233,9 @@ msgstr ""
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr "Проблема при отриманні Ñ€Ñдків відмінноÑтей."
+msgid "Direct member"
+msgstr ""
+
msgid "Direction"
msgstr "ÐапрÑмок"
@@ -8932,7 +9246,7 @@ msgid "Disable"
msgstr "Вимкнути"
msgid "Disable for this project"
-msgstr "Вимкнути Ð´Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ проекту"
+msgstr "Вимкнути Ð´Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ проєкту"
msgid "Disable group Runners"
msgstr "Вимкнути групові Runner'и"
@@ -8953,7 +9267,7 @@ msgid "Disabled mirrors can only be enabled by instance owners. It is recommende
msgstr "Вимкнені дзеркала можуть бути увімкнені тільки влаÑниками інÑтанÑу. Рекомендовано Ñ—Ñ… видалити."
msgid "Discard"
-msgstr ""
+msgstr "Відкинути"
msgid "Discard all changes"
msgstr "Відхилити вÑÑ– зміни"
@@ -8970,9 +9284,6 @@ msgstr "Відхилити зміни до %{path}?"
msgid "Discard draft"
msgstr "Видалити чернетку"
-msgid "Discard review"
-msgstr "Відхилити перевірку"
-
msgid "DiscordService|Discord Notifications"
msgstr "Discord СповіщеннÑ"
@@ -8983,7 +9294,7 @@ msgid "Discover GitLab Geo"
msgstr "Відкрийте GitLab Geo"
msgid "Discover projects, groups and snippets. Share your projects with others"
-msgstr "Відкрийте Ð´Ð»Ñ Ñебе групи, проекти та фрагменти коду. ПоділітьÑÑ Ñвоїми проектами з іншими"
+msgstr "Відкрийте Ð´Ð»Ñ Ñебе групи, проєкти та фрагменти коду. ПоділітьÑÑ Ñвоїми проєктами з іншими"
msgid "Discover|Check your application for security vulnerabilities that may lead to unauthorized access, data leaks, and denial of services."
msgstr "Перевірте Ñвій заÑтоÑунок на наÑвніÑÑ‚ÑŒ вразливоÑтей безпеки, що можуть привеÑти до неавторизованого доÑтупу, витоку даних, або відмови ÑевіÑів."
@@ -9043,12 +9354,12 @@ msgstr ""
msgid "Dismiss Merge Request promotion"
msgstr "Видалити Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾ запит на злиттÑ"
-msgid "Dismiss Selected"
-msgstr "Відхилити вибране"
-
msgid "Dismiss Value Stream Analytics introduction box"
msgstr ""
+msgid "Dismiss selected"
+msgstr ""
+
msgid "Dismiss trial promotion"
msgstr "Відхилити пробну верÑÑ–ÑŽ"
@@ -9077,7 +9388,7 @@ msgid "Display rendered file"
msgstr ""
msgid "Display source"
-msgstr ""
+msgstr "Показати джерело"
msgid "Do not display offers from third parties within GitLab"
msgstr "Ðе відображати пропозиції від третіх Ñторін у GitLab"
@@ -9097,9 +9408,6 @@ msgstr "Ð”Ð¾ÐºÑƒÐ¼ÐµÐ½Ñ‚Ð°Ñ†Ñ–Ñ Ð´Ð»Ñ Ð¿Ð¾ÑˆÐ¸Ñ€ÐµÐ½Ð¸Ñ… провайдеріÐ
msgid "Documents reindexed: %{processed_documents} (%{percentage}%%)"
msgstr ""
-msgid "Doing"
-msgstr "В роботі"
-
msgid "Domain"
msgstr "Домен"
@@ -9173,7 +9481,7 @@ msgid "Download license"
msgstr "Завантажити ліцензію"
msgid "Download raw data (.csv)"
-msgstr ""
+msgstr "Завантажити необроблені дані (.csv)"
msgid "Download source code"
msgstr "Завантажити вихідний код"
@@ -9197,7 +9505,7 @@ msgid "Downvotes"
msgstr "Дизлайки"
msgid "Draft"
-msgstr ""
+msgstr "Чернетка"
msgid "Draft merge requests can't be merged."
msgstr ""
@@ -9269,10 +9577,10 @@ msgid "Edit Release"
msgstr "Редагувати Реліз"
msgid "Edit Requirement"
-msgstr ""
+msgstr "Редагувати вимоги"
msgid "Edit Slack integration"
-msgstr ""
+msgstr "Редагувати інтеграцію Slack"
msgid "Edit Snippet"
msgstr "Редагувати Ñніпет"
@@ -9295,14 +9603,11 @@ msgstr "Редагувати опиÑ"
msgid "Edit environment"
msgstr "Редагувати Ñередовище"
-msgid "Edit file"
-msgstr "Редагувати файл"
-
msgid "Edit files in the editor and commit changes here"
msgstr "Редагуйте файли в редакторі і закомітьте зміни тут"
msgid "Edit fork in Web IDE"
-msgstr ""
+msgstr "Редагувати форк в Web IDE"
msgid "Edit group: %{group_name}"
msgstr "Редагувати групу: %{group_name}"
@@ -9310,11 +9615,17 @@ msgstr "Редагувати групу: %{group_name}"
msgid "Edit identity for %{user_name}"
msgstr "Редагувати ідентифікацію Ð´Ð»Ñ %{user_name}"
+msgid "Edit in Web IDE"
+msgstr ""
+
+msgid "Edit in single-file editor"
+msgstr ""
+
msgid "Edit issues"
msgstr "Редагувати задачі"
msgid "Edit iteration"
-msgstr ""
+msgstr "Редагувати ітерацію"
msgid "Edit public deploy key"
msgstr "Редагувати публічний ключ Ð´Ð»Ñ Ñ€Ð¾Ð·Ð³Ð¾Ñ€Ñ‚Ð°Ð½Ð½Ñ"
@@ -9337,21 +9648,18 @@ msgstr "Відредаговано %{timeago}"
msgid "Editing"
msgstr "РедагуваннÑ"
-msgid "Elasticsearch"
-msgstr "Elasticsearch"
-
msgid "Elasticsearch AWS IAM credentials"
msgstr "Параметри доÑтупу IAM Ð´Ð»Ñ Elasticsearch AWS"
+msgid "Elasticsearch HTTP client timeout value in seconds."
+msgstr ""
+
msgid "Elasticsearch indexing restrictions"
msgstr "ÐžÐ±Ð¼ÐµÐ¶ÐµÐ½Ð½Ñ Ñ–Ð½Ð´ÐµÐºÑÑƒÐ²Ð°Ð½Ð½Ñ Elasticsearch"
msgid "Elasticsearch indexing started"
msgstr "Розпочато індекÑацію Elasticsearch"
-msgid "Elasticsearch integration. Elasticsearch AWS IAM."
-msgstr "Ð†Ð½Ñ‚ÐµÐ³Ñ€Ð°Ñ†Ñ–Ñ Ð· Elasticsearch. Elasticsearch AWS IAM."
-
msgid "Elasticsearch reindexing is already in progress"
msgstr ""
@@ -9368,7 +9676,7 @@ msgid "Elastic|None. Select namespaces to index."
msgstr "Ðемає. Виберіть проÑтори імен Ð´Ð»Ñ Ñ–Ð½Ð´ÐµÐºÑуваннÑ."
msgid "Elastic|None. Select projects to index."
-msgstr "Ðемає. Виберіть проекти Ð´Ð»Ñ Ñ–Ð½Ð´ÐµÐºÑуваннÑ."
+msgstr "Ðемає. Виберіть проєкти Ð´Ð»Ñ Ñ–Ð½Ð´ÐµÐºÑуваннÑ."
msgid "Email"
msgstr "Електронна пошта"
@@ -9377,10 +9685,7 @@ msgid "Email %{number}"
msgstr ""
msgid "Email Notification"
-msgstr ""
-
-msgid "Email address"
-msgstr "ÐдреÑа електронної пошти"
+msgstr "Ð¡Ð¿Ð¾Ð²Ñ–Ñ‰ÐµÐ½Ð½Ñ ÐµÐ»ÐµÐºÑ‚Ñ€Ð¾Ð½Ð½Ð¾ÑŽ поштою"
msgid "Email could not be sent"
msgstr ""
@@ -9404,7 +9709,7 @@ msgid "Email restrictions for sign-ups"
msgstr ""
msgid "Email sent"
-msgstr ""
+msgstr "ЛиÑта відправлено"
msgid "Email the pipelines status to a list of recipients."
msgstr "ÐадіÑлати ÑÑ‚Ð°Ñ‚ÑƒÑ ÐºÐ¾Ð½Ð²ÐµÑ”Ñ€Ð° по електронній пошті ÑпиÑку отримувачів."
@@ -9425,7 +9730,7 @@ msgid "EmailError|We couldn't figure out what user corresponds to the email. Ple
msgstr "Ми не змогли визначити від імені Ñкого кориÑтувача надіÑлано це повідомленнÑ. Будь лаÑка, Ñтворіть ваш коментар через веб-інтерфейÑ."
msgid "EmailError|We couldn't find the project. Please check if there's any typo."
-msgstr "Ми не змогли знайти проект. Будь лаÑка, перевірте, чи немає помилок."
+msgstr "Ми не змогли знайти проєкт. Будь лаÑка, перевірте, чи немає помилок."
msgid "EmailError|You are not allowed to perform this action. If you believe this is in error, contact a staff member."
msgstr "Вам не дозволено виконувати цю дію. Якщо ви вважаєте, що це неправильно, звернітьÑÑ Ð´Ð¾ Ñпівробітника."
@@ -9445,6 +9750,9 @@ msgstr "ÐдреÑи електронної пошти"
msgid "Emails sent from Service Desk will have this name"
msgstr ""
+msgid "Emails sent to %{email} will still be supported"
+msgstr ""
+
msgid "Emails separated by comma"
msgstr "ÐдреÑи електронної пошти, розділені комами"
@@ -9478,9 +9786,18 @@ msgstr "Порожній файл"
msgid "Enable"
msgstr "Увімкнути"
+msgid "Enable %{link_start}Gitpod%{link_end} integration to launch a development environment in your browser directly from GitLab."
+msgstr ""
+
msgid "Enable Auto DevOps"
msgstr "Увімкнути Auto DevOps"
+msgid "Enable Gitpod"
+msgstr ""
+
+msgid "Enable Gitpod?"
+msgstr ""
+
msgid "Enable HTML emails"
msgstr "Увімкнути HTML лиÑти"
@@ -9527,7 +9844,7 @@ msgid "Enable feature to choose access level"
msgstr "Увімкнути функцію Ð´Ð»Ñ Ð²Ð¸Ð±Ð¾Ñ€Ñƒ Ñ€Ñ–Ð²Ð½Ñ Ð´Ð¾Ñтупу"
msgid "Enable for this project"
-msgstr "Увімкнути Ð´Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ проекту"
+msgstr "Увімкнути Ð´Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ проєкту"
msgid "Enable group Runners"
msgstr "Увімкнути групові Runner'и"
@@ -9536,7 +9853,7 @@ msgid "Enable header and footer in emails"
msgstr "Увімкнути заголовок та футер в електронних лиÑтах"
msgid "Enable integration"
-msgstr ""
+msgstr "Увімкнути інтеграцію"
msgid "Enable maintenance mode"
msgstr "Увімкнути режим обÑлуговуваннÑ"
@@ -9602,17 +9919,14 @@ msgid "Enabled Git access protocols"
msgstr "Увімкнути протоколи доÑтупу до Git"
msgid "Enabled sources for code import during project creation. OmniAuth must be configured for GitHub"
-msgstr "Ðктивовані джерела Ð´Ð»Ñ Ñ–Ð¼Ð¿Ð¾Ñ€Ñ‚Ñƒ коду під Ñ‡Ð°Ñ ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾ÐµÐºÑ‚Ñƒ. OmniAuth має бути Ñконфігурована Ð´Ð»Ñ GitHub"
+msgstr "Ðктивовані джерела Ð´Ð»Ñ Ñ–Ð¼Ð¿Ð¾Ñ€Ñ‚Ñƒ коду під Ñ‡Ð°Ñ ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾Ñ”ÐºÑ‚Ñƒ. OmniAuth має бути Ñконфігурована Ð´Ð»Ñ GitHub"
msgid "Enabling this will only make licensed EE features available to projects if the project namespace's plan includes the feature or if the project is public."
-msgstr "Ð£Ð²Ñ–Ð¼ÐºÐ½ÐµÐ½Ð½Ñ Ñ†ÑŒÐ¾Ð³Ð¾ зробить ліцензовану функціональніÑÑ‚ÑŒ EE доÑтупною тільки Ð´Ð»Ñ Ð¿Ñ€Ð¾ÐµÐºÑ‚Ñ–Ð², план проÑтору імен Ñких включає цю функціональніÑÑ‚ÑŒ або Ñкщо проект Ñ” публічним."
+msgstr "Ð£Ð²Ñ–Ð¼ÐºÐ½ÐµÐ½Ð½Ñ Ñ†ÑŒÐ¾Ð³Ð¾ зробить ліцензовану функціональніÑÑ‚ÑŒ EE доÑтупною тільки Ð´Ð»Ñ Ð¿Ñ€Ð¾Ñ”ÐºÑ‚Ñ–Ð², план проÑтору імен Ñких включає цю функціональніÑÑ‚ÑŒ або Ñкщо проєкт Ñ” публічним."
msgid "Encountered an error while rendering: %{err}"
msgstr ""
-msgid "End date"
-msgstr "Дата завершеннÑ"
-
msgid "Ends at (UTC)"
msgstr "ЗавершуєтьÑÑ Ð¾ (за Грінвічем)"
@@ -9749,10 +10063,10 @@ msgid "EnvironmentsAlert|%{severity} • %{title} %{text}. %{linkStart}View Deta
msgstr ""
msgid "EnvironmentsDashboard|Add a project to the dashboard"
-msgstr "Додати проект до панелі керуваннÑ"
+msgstr "Додати проєкт до панелі керуваннÑ"
msgid "EnvironmentsDashboard|Add projects"
-msgstr "Додати проекти"
+msgstr "Додати проєкти"
msgid "EnvironmentsDashboard|Environments Dashboard"
msgstr "Панель ÐºÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Ñередовищами"
@@ -9770,9 +10084,9 @@ msgid "EnvironmentsDashboard|Remove"
msgstr "Видалити"
msgid "EnvironmentsDashboard|The environments dashboard provides a summary of each project's environments' status, including pipeline and alert statuses."
-msgstr "Панель ÐºÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Ñередовищами міÑтить інформацію про Ñтан кожного із проектних Ñередовищ включно зі Ñтаном конвеєрів та попереджень."
+msgstr "Панель ÐºÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Ñередовищами міÑтить інформацію про Ñтан кожного із проєктних Ñередовищ включно зі Ñтаном конвеєрів та попереджень."
-msgid "EnvironmentsDashboard|This dashboard displays a maximum of 7 projects and 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
+msgid "EnvironmentsDashboard|This dashboard displays 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
msgstr ""
msgid "Environments|An error occurred while canceling the auto stop, please try again"
@@ -9974,7 +10288,7 @@ msgid "Epics and Issues"
msgstr "Епіки та задачі"
msgid "Epics let you manage your portfolio of projects more efficiently and with less effort"
-msgstr "Епіки дозволÑÑŽÑ‚ÑŒ керувати вашим портфелем проектів ефективніше та з меншими зуÑиллÑми"
+msgstr "Епіки дозволÑÑŽÑ‚ÑŒ керувати вашим портфелем проєктів ефективніше та з меншими зуÑиллÑми"
msgid "Epics, Issues, and Merge Requests"
msgstr "Епіки, Задачі та Запити на злиттÑ"
@@ -10079,7 +10393,7 @@ msgid "Error creating label."
msgstr "Помилка при Ñтворенні мітки."
msgid "Error creating new iteration"
-msgstr ""
+msgstr "Помилка при Ñтворенні нової ітерації"
msgid "Error creating repository for snippet with id %{snippet_id}"
msgstr ""
@@ -10093,6 +10407,9 @@ msgstr ""
msgid "Error deleting project. Check logs for error details."
msgstr "Помилка при видаленні проєкту. Перевірте журнали Ð´Ð»Ñ Ð¿Ð¾Ð´Ñ€Ð¾Ð±Ð¸Ñ†ÑŒ про помилку."
+msgid "Error fetching burnup chart data"
+msgstr ""
+
msgid "Error fetching diverging counts for branches. Please try again."
msgstr "Помилка при отриманні кількоÑÑ‚Ñ– розбіжноÑтей Ð´Ð»Ñ Ð³Ñ–Ð»Ð¾Ðº. Будь лаÑка, Ñпробуйте знову."
@@ -10109,7 +10426,7 @@ msgid "Error fetching payload data."
msgstr "СталаÑÑ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ° при отриманні даних."
msgid "Error fetching projects"
-msgstr "Помилка Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ Ð¿Ñ€Ð¾ÐµÐºÑ‚Ñ–Ð²"
+msgstr "Помилка Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ Ð¿Ñ€Ð¾Ñ”ÐºÑ‚Ñ–Ð²"
msgid "Error fetching refs"
msgstr "Помилка Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ refs"
@@ -10133,10 +10450,10 @@ msgid "Error loading file viewer."
msgstr "Помилка при Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ Ð¿ÐµÑ€ÐµÐ³Ð»Ñдача файлів."
msgid "Error loading issues"
-msgstr ""
+msgstr "Помилка при завантаженні проблем"
msgid "Error loading iterations"
-msgstr ""
+msgstr "Помилка при завантаженні ітерацій"
msgid "Error loading last commit."
msgstr "Помилка при завантаженні оÑтаннього коміту."
@@ -10151,7 +10468,7 @@ msgid "Error loading milestone tab"
msgstr "Помилка при завантаженні вкладки етапів"
msgid "Error loading project data. Please try again."
-msgstr "Помилка при завантаженні даних проекту. Будь лаÑка, Ñпробуйте знову."
+msgstr "Помилка при завантаженні даних проєкту. Будь лаÑка, Ñпробуйте знову."
msgid "Error loading template types."
msgstr "Помилка при завантаженні типів шаблонів."
@@ -10163,7 +10480,7 @@ msgid "Error loading viewer"
msgstr "Помилка при завантаженні переглÑдача"
msgid "Error message:"
-msgstr ""
+msgstr "ÐŸÐ¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾ помилку:"
msgid "Error occurred when fetching sidebar data"
msgstr "Помилка при отриманні даних Ð´Ð»Ñ Ð±Ñ–Ñ‡Ð½Ð¾Ñ— панелі"
@@ -10171,6 +10488,9 @@ msgstr "Помилка при отриманні даних Ð´Ð»Ñ Ð±Ñ–Ñ‡Ð½Ð¾Ñ—
msgid "Error occurred when saving assignees"
msgstr "Помилка при збереженні виконавців"
+msgid "Error occurred when saving reviewers"
+msgstr ""
+
msgid "Error occurred when toggling the notification subscription"
msgstr "СталаÑÑ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ° під Ñ‡Ð°Ñ Ð¿Ñ–Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð½Ñ Ð¿Ñ–Ð´Ð¿Ð¸Ñки на ÑповіщеннÑ"
@@ -10208,7 +10528,7 @@ msgid "Error setting up editor. Please try again."
msgstr "Проблема при налаштуванні редактора. Будь лаÑка, Ñпробуйте знову."
msgid "Error tracking"
-msgstr ""
+msgstr "ВідÑÑ‚ÐµÐ¶ÐµÐ½Ð½Ñ Ð¿Ð¾Ð¼Ð¸Ð»Ð¾Ðº"
msgid "Error updating %{issuableType}"
msgstr "Помилка при оновленні %{issuableType}"
@@ -10232,7 +10552,7 @@ msgid "Error while loading the merge request. Please try again."
msgstr "Помилка при завантаженні запита на злиттÑ. Будь лаÑка, Ñпробуйте знову."
msgid "Error while loading the project data. Please try again."
-msgstr "Помилка при завантаженні даних проекту. Будь лаÑка, Ñпробуйте знову."
+msgstr "Помилка при завантаженні даних проєкту. Будь лаÑка, Ñпробуйте знову."
msgid "Error while migrating %{upload_id}: %{error_message}"
msgstr "Помилка при міграції %{upload_id}: %{error_message}"
@@ -10250,7 +10570,7 @@ msgid "ErrorTracking|Active"
msgstr "Ðктивовано"
msgid "ErrorTracking|After adding your Auth Token, use the 'Connect' button to load projects"
-msgstr "ПіÑÐ»Ñ Ð´Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ð²Ð°ÑˆÐ¾Ð³Ð¾ токена автентифікації викориÑтовуйте кнопку \"З’єднаннÑ\" Ð´Ð»Ñ Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾ÐµÐºÑ‚Ñ–Ð²"
+msgstr "ПіÑÐ»Ñ Ð´Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ð²Ð°ÑˆÐ¾Ð³Ð¾ токена автентифікації викориÑтовуйте кнопку \"З’єднаннÑ\" Ð´Ð»Ñ Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾Ñ”ÐºÑ‚Ñ–Ð²"
msgid "ErrorTracking|Auth Token"
msgstr "Токен автентифікації"
@@ -10265,13 +10585,13 @@ msgid "ErrorTracking|If you self-host Sentry, enter the full URL of your Sentry
msgstr "Якщо ви розміщуєте Sentry ÑамоÑтійно, введіть повну URL-адреÑу вашого інÑтанÑу Sentry. Якщо ви викориÑтовуєте Ñ€Ñ–ÑˆÐµÐ½Ð½Ñ Ð½Ð° інфраÑтруктурі Sentry, введіть https://sentry.io"
msgid "ErrorTracking|No projects available"
-msgstr "Ðемає доÑтупних проектів"
+msgstr "Ðемає доÑтупних проєктів"
msgid "ErrorTracking|Select project"
-msgstr "Виберіть проект"
+msgstr "Виберіть проєкт"
msgid "ErrorTracking|To enable project selection, enter a valid Auth Token"
-msgstr "Ð”Ð»Ñ Ð¼Ð¾Ð¶Ð»Ð¸Ð²Ð¾ÑÑ‚Ñ– вибору проектів введіть дійÑний токен автентифікації"
+msgstr "Ð”Ð»Ñ Ð¼Ð¾Ð¶Ð»Ð¸Ð²Ð¾ÑÑ‚Ñ– вибору проєктів введіть дійÑний токен автентифікації"
msgid "Errors"
msgstr "Помилки"
@@ -10423,12 +10743,15 @@ msgstr "Розгорнути"
msgid "Expand all"
msgstr "Розгорнути вÑе"
+msgid "Expand all files"
+msgstr ""
+
+msgid "Expand all threads"
+msgstr ""
+
msgid "Expand approvers"
msgstr "Розгорнути ÑпиÑок затверджуючих оÑіб"
-msgid "Expand dropdown"
-msgstr "Розгорнути випадаючий ÑпиÑок"
-
msgid "Expand milestones"
msgstr ""
@@ -10454,7 +10777,7 @@ msgid "Expired %{expiredOn}"
msgstr "Минув(-ло) %{expiredOn}"
msgid "Expired:"
-msgstr ""
+msgstr "Термін дії закінчивÑÑ:"
msgid "Expires"
msgstr "ЗакінчуєтьÑÑ"
@@ -10466,7 +10789,7 @@ msgid "Expires in %{expires_at}"
msgstr "ЗакінчуєтьÑÑ %{expires_at}"
msgid "Expires on"
-msgstr ""
+msgstr "Діє до"
msgid "Expires:"
msgstr "ЗакінчуєтьÑÑ:"
@@ -10487,7 +10810,7 @@ msgid "Explore groups"
msgstr "ОглÑд груп"
msgid "Explore projects"
-msgstr "ОглÑд проектів"
+msgstr "ОглÑд проєктів"
msgid "Explore public groups"
msgstr "ПереглÑнути публічні групи"
@@ -10505,13 +10828,13 @@ msgid "Export issues"
msgstr "ЕкÑпортувати задачі"
msgid "Export project"
-msgstr "ЕкÑпорт проекту"
+msgstr "ЕкÑпорт проєкту"
msgid "Export this group with all related data to a new GitLab instance. Once complete, you can import the data file from the \"New Group\" page."
msgstr "ЕкÑпортуйте цю групу з уÑіма відповідними даними в новий екземплÑÑ€ GitLab. ПіÑÐ»Ñ Ð·Ð°Ð²ÐµÑ€ÑˆÐµÐ½Ð½Ñ Ð²Ð¸ зможете імпортувати файл даних зі Ñторінки \"Ðова Група\"."
msgid "Export this project with all its related data in order to move your project to a new GitLab instance. Once the export is finished, you can import the file from the \"New Project\" page."
-msgstr "ЕкÑпортувати цей проект з уÑіма пов'Ñзаними даними Ð´Ð»Ñ Ñ‚Ð¾Ð³Ð¾, щоб переміÑтити його на новий інÑÑ‚Ð°Ð½Ñ GitLab. ПіÑÐ»Ñ Ð·Ð°Ð²ÐµÑ€ÑˆÐµÐ½Ð½Ñ ÐµÐºÑпорту ви зможете імпортувати файл на Ñторінці \"Ðовий проект\"."
+msgstr "ЕкÑпортувати цей проєкт з уÑіма пов'Ñзаними даними Ð´Ð»Ñ Ñ‚Ð¾Ð³Ð¾, щоб переміÑтити його на новий інÑÑ‚Ð°Ð½Ñ GitLab. ПіÑÐ»Ñ Ð·Ð°Ð²ÐµÑ€ÑˆÐµÐ½Ð½Ñ ÐµÐºÑпорту ви зможете імпортувати файл на Ñторінці \"Ðовий проєкт\"."
msgid "Export variable to pipelines running on protected branches and tags only."
msgstr ""
@@ -10532,7 +10855,7 @@ msgid "External authentication"
msgstr "Ð—Ð¾Ð²Ð½Ñ–ÑˆÐ½Ñ Ð°Ð²Ñ‚ÐµÐ½Ñ‚Ð¸Ñ„Ñ–ÐºÐ°Ñ†Ñ–Ñ"
msgid "External authorization denied access to this project"
-msgstr "Ð—Ð¾Ð²Ð½Ñ–ÑˆÐ½Ñ Ð°Ð²Ñ‚Ð¾Ñ€Ð¸Ð·Ð°Ñ†Ñ–Ñ Ð·Ð°Ð±Ð¾Ñ€Ð¾Ð½Ð¸Ð»Ð° доÑтуп до цього проекту"
+msgstr "Ð—Ð¾Ð²Ð½Ñ–ÑˆÐ½Ñ Ð°Ð²Ñ‚Ð¾Ñ€Ð¸Ð·Ð°Ñ†Ñ–Ñ Ð·Ð°Ð±Ð¾Ñ€Ð¾Ð½Ð¸Ð»Ð° доÑтуп до цього проєкту"
msgid "External authorization request timeout"
msgstr "Ð§Ð°Ñ Ð¾Ñ‡Ñ–ÐºÑƒÐ²Ð°Ð½Ð½Ñ Ð·Ð°Ð¿Ð¸Ñ‚Ñƒ на зовнішню авторизацію"
@@ -10597,6 +10920,9 @@ msgstr "Ðе вдалоÑÑ Ð¿ÐµÑ€ÐµÐ²Ñ–Ñ€Ð¸Ñ‚Ð¸ пов’Ñзані гілки.
msgid "Failed to create Merge Request. Please try again."
msgstr "Ðе вдалоÑÑ Ñтворити запит на злиттÑ. Будь лаÑка, Ñпробуйте знову."
+msgid "Failed to create To-Do for the design."
+msgstr ""
+
msgid "Failed to create a branch for this issue. Please try again."
msgstr "Ðе вдалоÑÑ Ñтворити гілку Ð´Ð»Ñ Ñ†Ñ–Ñ”Ñ— задачі. Будь лаÑка, Ñпробуйте знову."
@@ -10636,6 +10962,12 @@ msgstr ""
msgid "Failed to load authors. Please try again."
msgstr ""
+msgid "Failed to load branches. Please try again."
+msgstr ""
+
+msgid "Failed to load deploy keys."
+msgstr ""
+
msgid "Failed to load emoji list."
msgstr "Ðе вдалоÑÑ Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶Ð¸Ñ‚Ð¸ ÑпиÑок Ñмайликів."
@@ -10651,6 +10983,9 @@ msgstr ""
msgid "Failed to load groups & users."
msgstr "Ðе вдалоÑÑ Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶Ð¸Ñ‚Ð¸ групи та кориÑтувачів."
+msgid "Failed to load groups, users and deploy keys."
+msgstr ""
+
msgid "Failed to load labels. Please try again."
msgstr "Ðе вдалоÑÑ Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶Ð¸Ñ‚Ð¸ мітки. Будь лаÑка, Ñпробуйте ще раз."
@@ -10660,6 +10995,12 @@ msgstr ""
msgid "Failed to load related branches"
msgstr "Ðе вдалоÑÑ Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶Ð¸Ñ‚Ð¸ пов’Ñзані гілки"
+msgid "Failed to load sidebar confidential toggle"
+msgstr ""
+
+msgid "Failed to load sidebar lock status"
+msgstr ""
+
msgid "Failed to load stacktrace."
msgstr "Ðе вдалоÑÑ Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶Ð¸Ñ‚Ð¸ траÑÑƒÐ²Ð°Ð½Ð½Ñ Ñтеку."
@@ -10673,7 +11014,7 @@ msgid "Failed to move this issue because only a single label can be provided."
msgstr "Ðе вдалоÑÑ Ð¿ÐµÑ€ÐµÐ¼Ñ–Ñтити цю задачу, тому що можна вказувати тільки одну мітку."
msgid "Failed to move this issue because target project doesn't exist."
-msgstr "Ðе вдалоÑÑ Ð¿ÐµÑ€ÐµÐ¼Ñ–Ñтити цю задачу, тому що цільовий проект не Ñ–Ñнує."
+msgstr "Ðе вдалоÑÑ Ð¿ÐµÑ€ÐµÐ¼Ñ–Ñтити цю задачу, тому що цільовий проєкт не Ñ–Ñнує."
msgid "Failed to promote label due to internal error. Please contact administrators."
msgstr "Ðе вдалоÑÑ Ð¿ÐµÑ€ÐµÐ½ÐµÑти мітку через внутрішню проблему. Будь лаÑка, звернітьÑÑ Ð´Ð¾ адмініÑтраторів."
@@ -10687,6 +11028,9 @@ msgstr "Ðе вдалоÑÑ Ð·Ñ€Ð¾Ð±Ð¸Ñ‚Ð¸ Ñередовище захищени
msgid "Failed to publish issue on status page."
msgstr ""
+msgid "Failed to remove To-Do for the design."
+msgstr ""
+
msgid "Failed to remove a Zoom meeting"
msgstr "Ðе вдалоÑÑ Ð²Ð¸Ð´Ð°Ð»Ð¸Ñ‚Ð¸ Zoom-зуÑтріч"
@@ -10729,6 +11073,9 @@ msgstr ""
msgid "Failed to signing using smartcard authentication"
msgstr "Ðе вдалоÑÑ Ð¿Ñ–Ð´Ð¿Ð¸Ñати з викориÑтаннÑм перевірки автентичноÑÑ‚Ñ– Ñмарт-карти"
+msgid "Failed to toggle To-Do for the design."
+msgstr ""
+
msgid "Failed to update branch!"
msgstr "Ðе вдалоÑÑ Ð¾Ð½Ð¾Ð²Ð¸Ñ‚Ð¸ гілку!"
@@ -10772,7 +11119,7 @@ msgid "Fast-forward merge without a merge commit"
msgstr "Fast-forward Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð±ÐµÐ· окремого коміту злиттÑ"
msgid "Faster as it re-uses the project workspace (falling back to clone if it doesn't exist)"
-msgstr "Швидше, бо повтоно викориÑтовує робочу облаÑÑ‚ÑŒ проекту (викориÑтовуючи clone, Ñкщо та відÑутнÑ)"
+msgstr "Швидше, бо повтоно викориÑтовує робочу облаÑÑ‚ÑŒ проєкту (викориÑтовуючи clone, Ñкщо та відÑутнÑ)"
msgid "Faster releases. Better code. Less pain."
msgstr "Швидші релізи. Кращий код. Менше болю."
@@ -10844,7 +11191,7 @@ msgstr "Редагувати перемикач функції"
msgid "FeatureFlags|Edit User List"
msgstr ""
-msgid "FeatureFlags|Enable features for specific users and specific environments by defining feature flag strategies."
+msgid "FeatureFlags|Enable features for specific users and environments by configuring feature flag strategies."
msgstr ""
msgid "FeatureFlags|Environment Spec"
@@ -10904,8 +11251,8 @@ msgstr "Ðеактивний перемикач функції Ð´Ð»Ñ %{scope}"
msgid "FeatureFlags|Include additional user IDs"
msgstr ""
-msgid "FeatureFlags|Install a %{docs_link_anchored_start}compatible client library%{docs_link_anchored_end} and specify the API URL, application name, and instance ID during the configuration setup. %{docs_link_start}More Information%{docs_link_end}"
-msgstr "Ð’Ñтановіть %{docs_link_anchored_start}ÑуміÑну клієнтÑьку бібліотеку%{docs_link_anchored_end} Ñ– вкажіть URL адреÑу API, назву заÑтоÑунку та ідентифікатор інÑтанÑа під Ñ‡Ð°Ñ Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ. %{docs_link_start}Більше інформації%{docs_link_end}"
+msgid "FeatureFlags|Install a %{docsLinkAnchoredStart}compatible client library%{docsLinkAnchoredEnd} and specify the API URL, application name, and instance ID during the configuration setup. %{docsLinkStart}More Information%{docsLinkEnd}"
+msgstr ""
msgid "FeatureFlags|Instance ID"
msgstr "Ідентифікатор ІнÑтанÑу"
@@ -10916,6 +11263,9 @@ msgstr ""
msgid "FeatureFlags|Loading feature flags"
msgstr "Ð—Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ Ð¿ÐµÑ€ÐµÐ¼Ð¸ÐºÐ°Ñ‡Ñ–Ð² функцій"
+msgid "FeatureFlags|Loading user lists"
+msgstr ""
+
msgid "FeatureFlags|More information"
msgstr "Більше інформації"
@@ -10934,8 +11284,8 @@ msgstr ""
msgid "FeatureFlags|New feature flag"
msgstr "Ðовий перемикач функції"
-msgid "FeatureFlags|New list"
-msgstr "Ðовий ÑпиÑок"
+msgid "FeatureFlags|New user list"
+msgstr ""
msgid "FeatureFlags|Percent of users"
msgstr ""
@@ -10973,6 +11323,9 @@ msgstr "Цільові Ñередовища"
msgid "FeatureFlags|There was an error fetching the feature flags."
msgstr "Помилка при отриманні перемикачів функцій."
+msgid "FeatureFlags|There was an error fetching the user lists."
+msgstr ""
+
msgid "FeatureFlags|There was an error retrieving user lists"
msgstr ""
@@ -10988,6 +11341,9 @@ msgstr "Ідентифікатори кориÑтувачів"
msgid "FeatureFlags|User List"
msgstr ""
+msgid "FeatureFlags|User Lists"
+msgstr ""
+
msgid "FeatureFlag|List"
msgstr "СпиÑок"
@@ -11015,15 +11371,6 @@ msgstr "лютий"
msgid "Fetching incoming email"
msgstr "ÐžÑ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ Ð²Ñ…Ñ–Ð´Ð½Ð¸Ñ… повідомлень електронної пошти"
-msgid "Fetching licenses failed."
-msgstr "Ðе вдалоÑÑ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ñ‚Ð¸ ліцензії."
-
-msgid "Fetching licenses failed. The request endpoint was not found."
-msgstr "Ðе вдалоÑÑ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ñ‚Ð¸ ліцензії. Кінцева точка Ð´Ð»Ñ Ð·Ð°Ð¿Ð¸Ñ‚Ñƒ не знайдена."
-
-msgid "Fetching licenses failed. You are not permitted to perform this action."
-msgstr "Ðе вдалоÑÑ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ñ‚Ð¸ ліцензії. У Ð²Ð°Ñ Ð½ÐµÐ¼Ð°Ñ” дозовлів виконувати цю дію."
-
msgid "File"
msgstr "Файл"
@@ -11126,12 +11473,21 @@ msgstr ""
msgid "Filter by status"
msgstr "Фільтрувати за ÑтатуÑом"
+msgid "Filter by test cases that are currently archived."
+msgstr ""
+
+msgid "Filter by test cases that are currently opened."
+msgstr ""
+
msgid "Filter by two-factor authentication"
msgstr "Фільтрувати за двофакторною автентифікацією"
msgid "Filter by user"
msgstr "Сортувати по кориÑтувачах"
+msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
+msgstr ""
+
msgid "Filter pipelines"
msgstr "Фільтр конвеєрів"
@@ -11142,13 +11498,13 @@ msgid "Filter results by group"
msgstr "Фільтрувати результати за групою"
msgid "Filter results by project"
-msgstr "Фільтрувати результати за проектом"
+msgstr "Фільтрувати результати за проєктом"
msgid "Filter results..."
msgstr "Фільтрувати результати..."
-msgid "Filter your projects by name"
-msgstr "Відфільтрувати ваші проекти за іменами"
+msgid "Filter your repositories by name"
+msgstr ""
msgid "Filter..."
msgstr "Фільтр..."
@@ -11156,7 +11512,7 @@ msgstr "Фільтр..."
msgid "Find File"
msgstr "Знайти файл"
-msgid "Find bugs in your code with coverage-guided fuzzing"
+msgid "Find bugs in your code with coverage-guided fuzzing."
msgstr ""
msgid "Find by path"
@@ -11183,9 +11539,6 @@ msgstr "Відбитки пальців"
msgid "Finish editing this message first!"
msgstr "Спочатку завершіть Ñ€ÐµÐ´Ð°Ð³ÑƒÐ²Ð°Ð½Ð½Ñ Ñ†ÑŒÐ¾Ð³Ð¾ повідомленнÑ!"
-msgid "Finish review"
-msgstr "Завершити перевірку"
-
msgid "Finish setting up your dedicated account for %{group_name}."
msgstr ""
@@ -11247,7 +11600,7 @@ msgid "Folder/%{name}"
msgstr "Папка/%{name}"
msgid "Follow the steps below to export your Google Code project data."
-msgstr "Виконайте наведені нижче кроки, щоб екÑпортувати дані проекту з Google Code."
+msgstr "Виконайте наведені нижче кроки, щоб екÑпортувати дані проєкту з Google Code."
msgid "Font Color"
msgstr "Колір шрифту"
@@ -11255,15 +11608,21 @@ msgstr "Колір шрифту"
msgid "Footer message"
msgstr "ÐŸÐ¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð² футері"
+msgid "For a faster browsing experience, some files are collapsed by default."
+msgstr ""
+
msgid "For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
msgid "For internal projects, any logged in user can view pipelines and access job details (output logs and artifacts)"
-msgstr "Ð”Ð»Ñ Ð²Ð½ÑƒÑ‚Ñ€Ñ–ÑˆÐ½Ñ–Ñ… проектів будь-Ñкий зареєÑтрований кориÑтувач може переглÑдати конвеєри та отримати доÑтуп до інформації про роботу (логи та артефакти)"
+msgstr "Ð”Ð»Ñ Ð²Ð½ÑƒÑ‚Ñ€Ñ–ÑˆÐ½Ñ–Ñ… проєктів будь-Ñкий зареєÑтрований кориÑтувач може переглÑдати конвеєри та отримати доÑтуп до інформації про роботу (логи та артефакти)"
msgid "For more info, read the documentation."
msgstr "Ð”Ð»Ñ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ Ð´Ð¾Ð´Ð°Ñ‚ÐºÐ¾Ð²Ð¾Ñ— інформації читайте документацію."
+msgid "For more information on how the number of active users is calculated, see the %{self_managed_subscriptions_doc_link} documentation."
+msgstr ""
+
msgid "For more information, go to the "
msgstr "Ð”Ð»Ñ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ Ð´Ð¾Ð´Ð°Ñ‚ÐºÐ¾Ð²Ð¾Ñ— інформації, відвідайте "
@@ -11280,10 +11639,10 @@ msgid "For more information, see the documentation on %{link_start}disabling Sea
msgstr ""
msgid "For private projects, any member (guest or higher) can view pipelines and access job details (output logs and artifacts)"
-msgstr "Ð”Ð»Ñ Ð¿Ñ€Ð¸Ð²Ð°Ñ‚Ð½Ð¸Ñ… проектів будь-Ñкий кориÑтувач (гіÑÑ‚ÑŒ або вище) може переглÑдати конвеєри та отримати доÑтуп до інформації про роботу (логи та артефакти)"
+msgstr "Ð”Ð»Ñ Ð¿Ñ€Ð¸Ð²Ð°Ñ‚Ð½Ð¸Ñ… проєктів будь-Ñкий кориÑтувач (гіÑÑ‚ÑŒ або вище) може переглÑдати конвеєри та отримати доÑтуп до інформації про роботу (логи та артефакти)"
msgid "For public projects, anyone can view pipelines and access job details (output logs and artifacts)"
-msgstr "Ð”Ð»Ñ Ð¿ÑƒÐ±Ð»Ñ–Ñ‡Ð½Ð¸Ñ… проектів будь-Ñкий зареєÑтрований кориÑтувач може переглÑдати конвеєри та отримати доÑтуп до інформації про роботу (логи та артефакти)"
+msgstr "Ð”Ð»Ñ Ð¿ÑƒÐ±Ð»Ñ–Ñ‡Ð½Ð¸Ñ… проєктів будь-Ñкий зареєÑтрований кориÑтувач може переглÑдати конвеєри та отримати доÑтуп до інформації про роботу (логи та артефакти)"
msgid "Forgot your password?"
msgstr "Забули ваш пароль?"
@@ -11295,10 +11654,10 @@ msgid "Fork Error!"
msgstr "Помилка форку!"
msgid "Fork project"
-msgstr "Форк проекту"
+msgstr "Форк проєкту"
msgid "Fork project?"
-msgstr "Створити форк проекту?"
+msgstr "Створити форк проєкту?"
msgid "ForkedFromProjectPath|Forked from"
msgstr "Форк від"
@@ -11400,6 +11759,9 @@ msgid "Generate new export"
msgstr "Створити новий екÑпорт"
msgid "Generate new token"
+msgstr "Згенерувати новий токен"
+
+msgid "Generic package file size in bytes"
msgstr ""
msgid "Geo"
@@ -11601,7 +11963,7 @@ msgid "Geo|Connection timeout should be between 1-120"
msgstr ""
msgid "Geo|Could not remove tracking entry for an existing project."
-msgstr "Ðе вдалоÑÑ Ð²Ð¸Ð´Ð°Ð»Ð¸Ñ‚Ð¸ Ð·Ð°Ð¿Ð¸Ñ Ð²Ñ–Ð´ÑÑ‚ÐµÐ¶ÐµÐ½Ð½Ñ Ð´Ð»Ñ Ñ–Ñнуючого проекту."
+msgstr "Ðе вдалоÑÑ Ð²Ð¸Ð´Ð°Ð»Ð¸Ñ‚Ð¸ Ð·Ð°Ð¿Ð¸Ñ Ð²Ñ–Ð´ÑÑ‚ÐµÐ¶ÐµÐ½Ð½Ñ Ð´Ð»Ñ Ñ–Ñнуючого проєкту."
msgid "Geo|Could not remove tracking entry for an existing upload."
msgstr "Ðе вдалоÑÑ Ð²Ð¸Ð´Ð°Ð»Ð¸Ñ‚Ð¸ Ð·Ð°Ð¿Ð¸Ñ Ð²Ñ–Ð´ÑÑ‚ÐµÐ¶ÐµÐ½Ð½Ñ Ð´Ð»Ñ Ñ–Ñнуючого завантаженнÑ."
@@ -11663,6 +12025,9 @@ msgstr "ÐžÑ‡Ñ–ÐºÑƒÐ²Ð°Ð½Ð½Ñ Ð¿ÐµÑ€ÐµÐ²Ñ–Ñ€ÐºÐ¸"
msgid "Geo|Please refer to Geo Troubleshooting."
msgstr "Будь лаÑка, переглÑньте документацію з уÑÑƒÐ½ÐµÐ½Ð½Ñ Ð½ÐµÐ¿Ð¾Ð»Ð°Ð´Ð¾Ðº Geo."
+msgid "Geo|Primary node"
+msgstr ""
+
msgid "Geo|Project"
msgstr "Проект"
@@ -11705,6 +12070,9 @@ msgstr "Повторно перевірити вÑе"
msgid "Geo|Review replication status, and resynchronize and reverify items with the primary node."
msgstr ""
+msgid "Geo|Secondary node"
+msgstr ""
+
msgid "Geo|Status"
msgstr "СтатуÑ"
@@ -11733,7 +12101,7 @@ msgid "Geo|Tracking database entry will be removed. Are you sure?"
msgstr ""
msgid "Geo|Tracking entry for project (%{project_id}) was successfully removed."
-msgstr "Ð—Ð°Ð¿Ð¸Ñ Ð²Ñ–Ð´ÑÑ‚ÐµÐ¶ÐµÐ½Ð½Ñ Ð´Ð»Ñ Ð¿Ñ€Ð¾ÐµÐºÑ‚Ñƒ (%{project_id}) уÑпішно видалено."
+msgstr "Ð—Ð°Ð¿Ð¸Ñ Ð²Ñ–Ð´ÑÑ‚ÐµÐ¶ÐµÐ½Ð½Ñ Ð´Ð»Ñ Ð¿Ñ€Ð¾Ñ”ÐºÑ‚Ñƒ (%{project_id}) уÑпішно видалено."
msgid "Geo|Tracking entry for upload (%{type}/%{id}) was successfully removed."
msgstr "Ð—Ð°Ð¿Ð¸Ñ Ð²Ñ–Ð´ÑÑ‚ÐµÐ¶ÐµÐ½Ð½Ñ Ð´Ð»Ñ Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ (%{type}/%{id}) було уÑпішно видалено."
@@ -11744,6 +12112,9 @@ msgstr ""
msgid "Geo|URL must be a valid url (ex: https://gitlab.com)"
msgstr ""
+msgid "Geo|Undefined"
+msgstr ""
+
msgid "Geo|Unknown state"
msgstr "Ðевідомий Ñтан"
@@ -11819,14 +12190,20 @@ msgstr ""
msgid "GitHub import"
msgstr "GitHub-імпорт"
+msgid "GitLab"
+msgstr ""
+
msgid "GitLab / Unsubscribe"
msgstr "GitLab / СкаÑувати підпиÑку"
-msgid "GitLab Enterprise Edition %{plan}"
-msgstr "GitLab Enterprise Edition %{plan}"
+msgid "GitLab API"
+msgstr ""
+
+msgid "GitLab Billing Team."
+msgstr ""
msgid "GitLab Group Runners can execute code for all the projects in this group."
-msgstr "Групові Runner'и Gitlab можуть виконувати код Ð´Ð»Ñ ÑƒÑÑ–Ñ… проектів у цій групі."
+msgstr "Групові Runner'и Gitlab можуть виконувати код Ð´Ð»Ñ ÑƒÑÑ–Ñ… проєктів у цій групі."
msgid "GitLab Import"
msgstr "Імпорт з GitLab"
@@ -11834,11 +12211,17 @@ msgstr "Імпорт з GitLab"
msgid "GitLab Issue"
msgstr ""
+msgid "GitLab Pages"
+msgstr ""
+
msgid "GitLab Service Desk is a simple way to allow people to create issues in your GitLab instance without needing their own user account. It provides a unique email address for end users to create issues in a project, and replies can be sent either through the GitLab interface or by email. End users will only see the thread through email."
msgstr ""
msgid "GitLab Shared Runners execute code of different projects on the same Runner unless you configure GitLab Runner Autoscale with MaxBuilds 1 (which it is on GitLab.com)."
-msgstr "Загальні Runner'и GitLab виконують код Ð´Ð»Ñ Ñ€Ñ–Ð·Ð½Ð¸Ñ… проектів на одному Ñ– тому ж Runner, Ñкщо ви не налаштуєте автоматичне маÑÑˆÑ‚Ð°Ð±ÑƒÐ²Ð°Ð½Ð½Ñ GitLab Runner’ів за допомогою MaxBuilds 1 (Ñк зроблено на GitLab.com)."
+msgstr "Загальні Runner'и GitLab виконують код Ð´Ð»Ñ Ñ€Ñ–Ð·Ð½Ð¸Ñ… проєктів на одному Ñ– тому ж Runner, Ñкщо ви не налаштуєте автоматичне маÑÑˆÑ‚Ð°Ð±ÑƒÐ²Ð°Ð½Ð½Ñ GitLab Runner’ів за допомогою MaxBuilds 1 (Ñк зроблено на GitLab.com)."
+
+msgid "GitLab Shell"
+msgstr ""
msgid "GitLab Support Bot"
msgstr "Бот Підтримки GitLab"
@@ -11849,14 +12232,14 @@ msgstr "УчаÑник команди GitLab"
msgid "GitLab User"
msgstr "GitLab КориÑтувач"
-msgid "GitLab allows you to continue using your license even if you exceed the number of seats you purchased. You will be required to pay for these seats when you renew your license."
-msgstr "GitLab дозволÑÑ” вам викориÑтовувати вашу підпиÑку, навіть Ñкщо ви перевищили кількіÑÑ‚ÑŒ придбаних міÑць. Вам треба буде заплатити за ці міÑÑ†Ñ Ð¿Ñ€Ð¸ Ñ—Ñ— поновленні."
+msgid "GitLab Workhorse"
+msgstr ""
msgid "GitLab commit"
msgstr "GitLab коміт"
msgid "GitLab export"
-msgstr ""
+msgstr "ЕкÑпорт GitLab"
msgid "GitLab for Slack"
msgstr "GitLab Ð´Ð»Ñ Slack"
@@ -11877,7 +12260,7 @@ msgid "GitLab metadata URL"
msgstr "URL-адреÑа метаданних GitLab"
msgid "GitLab project export"
-msgstr "ЕкÑпорт проекту GitLab"
+msgstr "ЕкÑпорт проєкту GitLab"
msgid "GitLab restart is required to apply changes."
msgstr "Ðеобхідно перезавантажити GitLab Ð´Ð»Ñ Ð·Ð°ÑтоÑÑƒÐ²Ð°Ð½Ð½Ñ Ð·Ð¼Ñ–Ð½."
@@ -11886,7 +12269,7 @@ msgid "GitLab single sign-on URL"
msgstr ""
msgid "GitLab username"
-msgstr ""
+msgstr "Ім'Ñ ÐºÐ¾Ñ€Ð¸Ñтувача GitLab"
msgid "GitLab uses %{jaeger_link} to monitor distributed systems."
msgstr "GitLab викориÑтовує %{jaeger_link} Ð´Ð»Ñ Ð¼Ð¾Ð½Ñ–Ñ‚Ð¾Ñ€Ð¸Ð½Ð³Ñƒ розподілених ÑиÑтем."
@@ -11952,7 +12335,7 @@ msgid "GitLabPages|New Domain"
msgstr "Ðовий домен"
msgid "GitLabPages|Only project maintainers can remove pages"
-msgstr "Лише керівники проектів можуть видалÑти Ñторінки"
+msgstr "Лише керівники проєктів можуть видалÑти Ñторінки"
msgid "GitLabPages|Pages"
msgstr "Pages"
@@ -11988,7 +12371,7 @@ msgid "GitLabPages|When using Pages under the general domain of a GitLab instanc
msgstr "ВикориÑтовуючи Pages під загальним доменом інÑтанÑу GitLab (%{pages_host}), ви не можете викориÑтовувати HTTPS через піддомени. Це означає, що Ñкщо ваше ім'Ñ ÐºÐ¾Ñ€Ð¸Ñтувача/групи міÑтить крапку, воно не Ñпрацює. Це Ð¾Ð±Ð¼ÐµÐ¶ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾Ñ‚Ð¾ÐºÐ¾Ð»Ñƒ HTTP Over TLS. HTTP-Ñторінки продовжать працювати, Ñкщо ви не перенаправлÑєте HTTP на HTTPS."
msgid "GitLabPages|With GitLab Pages you can host your static websites on GitLab. Combined with the power of GitLab CI and the help of GitLab Runner you can deploy static pages for your individual projects, your user or your group."
-msgstr "За допомогою GitLab Pages ви можете розміщувати Ñвої Ñтатичні Ñайти на GitLab. Разом із можливоÑÑ‚Ñми GitLab CI та за допомогою Gitlab Runner'ів ми можете розгортати Ñтатичні Ñторінки Ð´Ð»Ñ Ð²Ð°ÑˆÐ¸Ñ… окремих проектів, кориÑтувача чи групи."
+msgstr "За допомогою GitLab Pages ви можете розміщувати Ñвої Ñтатичні Ñайти на GitLab. Разом із можливоÑÑ‚Ñми GitLab CI та за допомогою Gitlab Runner'ів ми можете розгортати Ñтатичні Ñторінки Ð´Ð»Ñ Ð²Ð°ÑˆÐ¸Ñ… окремих проєктів, кориÑтувача чи групи."
msgid "GitLabPages|Your pages are served under:"
msgstr "Ваші Ñторінки показуютьÑÑ Ð½Ð°:"
@@ -12017,6 +12400,21 @@ msgstr "Імпорт з Gitea"
msgid "Gitlab Pages"
msgstr "Gitlab Pages"
+msgid "Gitpod"
+msgstr ""
+
+msgid "Gitpod|Add the URL to your Gitpod instance configured to read your GitLab projects."
+msgstr ""
+
+msgid "Gitpod|Enable Gitpod integration"
+msgstr ""
+
+msgid "Gitpod|Gitpod URL"
+msgstr ""
+
+msgid "Gitpod|e.g. https://gitpod.example.com"
+msgstr ""
+
msgid "Given access %{time_ago}"
msgstr "Ðадано доÑтуп %{time_ago}"
@@ -12108,7 +12506,7 @@ msgid "Go to parent"
msgstr "Перейти на рівень вище"
msgid "Go to project"
-msgstr "Перейти до проекту"
+msgstr "Перейти до проєкту"
msgid "Go to releases"
msgstr "Перейти до релізів"
@@ -12129,10 +12527,10 @@ msgid "Go to the milestone list"
msgstr "Перейти до ÑпиÑку етапів"
msgid "Go to the project's activity feed"
-msgstr "Перейти до каналу активноÑÑ‚Ñ– проекту"
+msgstr "Перейти до каналу активноÑÑ‚Ñ– проєкту"
msgid "Go to the project's overview page"
-msgstr "Перейти до Ñторінки оглÑду проекту"
+msgstr "Перейти до Ñторінки оглÑду проєкту"
msgid "Go to wiki"
msgstr "Перейти до wiki"
@@ -12153,7 +12551,7 @@ msgid "Go to your merge requests"
msgstr "Перейти до ваших запитів на злиттÑ"
msgid "Go to your projects"
-msgstr "Перейти до ваших проектів"
+msgstr "Перейти до ваших проєктів"
msgid "Go to your snippets"
msgstr "Перейти до ваших Ñніпетів"
@@ -12524,9 +12922,6 @@ msgstr "Увімкнути/вимкнути автентифікацію SAML"
msgid "GroupSAML|Valid SAML Response"
msgstr ""
-msgid "GroupSAML|With group managed accounts enabled, all the users without a group managed account will be excluded from the group."
-msgstr "При активаціх облікових запиÑів керованих групою, вÑÑ– кориÑтувачі, що не мають облікового запиÑу керованого групою, будуть виключеню з неї."
-
msgid "GroupSAML|With prohibit outer forks flag enabled group members will be able to fork project only inside your group."
msgstr ""
@@ -12555,7 +12950,7 @@ msgid "GroupSettings|Be careful. Changing a group's parent can have unintended %
msgstr "Будьте обережні. Зміна батьківÑької групи може мати %{side_effects_link_start}небажані наÑлідки%{side_effects_link_end}."
msgid "GroupSettings|Cannot update the path because there are projects under this group that contain Docker images in their Container Registry. Please remove the images from your projects first and try again."
-msgstr "Ðе вдалоÑÑ Ð·Ð¼Ñ–Ð½Ð¸Ñ‚Ð¸ шлÑÑ… тому що в цій групі Ñ” проекти із образами Docker у Ñвоїх РеєÑтрах контейнерів. Будь лаÑка, Ñпочатку видаліть ці образи з ваших проектів Ñ– Ñпробуйте знову."
+msgstr "Ðе вдалоÑÑ Ð·Ð¼Ñ–Ð½Ð¸Ñ‚Ð¸ шлÑÑ… тому що в цій групі Ñ” проєкти із образами Docker у Ñвоїх РеєÑтрах контейнерів. Будь лаÑка, Ñпочатку видаліть ці образи з ваших проєктів Ñ– Ñпробуйте знову."
msgid "GroupSettings|Change group URL"
msgstr ""
@@ -12564,13 +12959,13 @@ msgid "GroupSettings|Changing group URL can have unintended side effects."
msgstr ""
msgid "GroupSettings|Custom project templates"
-msgstr "ВлаÑні шаблони проектів"
+msgstr "ВлаÑні шаблони проєктів"
msgid "GroupSettings|Customize your group badges."
msgstr "Ðалаштувати значки групи."
msgid "GroupSettings|Default to Auto DevOps pipeline for all projects within this group"
-msgstr "ВикориÑтовувати за замовчуваннÑм конвеєри Auto DevOps Ð´Ð»Ñ ÑƒÑÑ–Ñ… проектів цієї групи"
+msgstr "ВикориÑтовувати за замовчуваннÑм конвеєри Auto DevOps Ð´Ð»Ñ ÑƒÑÑ–Ñ… проєктів цієї групи"
msgid "GroupSettings|Disable email notifications"
msgstr "Вимкнути ÑÐ¿Ð¾Ð²Ñ–Ñ‰ÐµÐ½Ð½Ñ ÐµÐ»ÐµÐºÑ‚Ñ€Ð¾Ð½Ð½Ð¾ÑŽ поштою"
@@ -12585,7 +12980,7 @@ msgid "GroupSettings|Export group"
msgstr ""
msgid "GroupSettings|If the parent group's visibility is lower than the group current visibility, visibility levels for subgroups and projects will be changed to match the new parent group's visibility."
-msgstr "Якщо видиміÑÑ‚ÑŒ батьківÑької групи нижча, за поточну видиміÑÑ‚ÑŒ групи, тоді рівні видимоÑÑ‚Ñ– Ð´Ð»Ñ Ð¿Ñ–Ð´Ð³Ñ€ÑƒÐ¿ та проектів будуть змінені, щоб відповідати новій видимоÑÑ‚Ñ– батьківÑької групи."
+msgstr "Якщо видиміÑÑ‚ÑŒ батьківÑької групи нижча, за поточну видиміÑÑ‚ÑŒ групи, тоді рівні видимоÑÑ‚Ñ– Ð´Ð»Ñ Ð¿Ñ–Ð´Ð³Ñ€ÑƒÐ¿ та проєктів будуть змінені, щоб відповідати новій видимоÑÑ‚Ñ– батьківÑької групи."
msgid "GroupSettings|Integrations configured here will automatically apply to all projects in this group."
msgstr ""
@@ -12594,7 +12989,7 @@ msgid "GroupSettings|Learn more about badges."
msgstr "ДізнайтеÑÑ Ð±Ñ–Ð»ÑŒÑˆÐµ про значки."
msgid "GroupSettings|Learn more about group-level project templates."
-msgstr "Докладніше про шаблони проектів на рівні групи."
+msgstr "Докладніше про шаблони проєктів на рівні групи."
msgid "GroupSettings|New runners registration token has been generated!"
msgstr "Згенеровано новий токен Ð´Ð»Ñ Ñ€ÐµÑ”Ñтрації runner'ів!"
@@ -12612,13 +13007,13 @@ msgid "GroupSettings|Prevent forking setting was not saved"
msgstr ""
msgid "GroupSettings|Prevent sharing a project within %{group} with other groups"
-msgstr "Заборонити Ñпільний доÑтуп до проекту в рамках %{group} з іншими групами"
+msgstr "Заборонити Ñпільний доÑтуп до проєкту в рамках %{group} з іншими групами"
msgid "GroupSettings|Projects will be permanently deleted after a %{waiting_period}-day delay. This delay can be %{customization_link} in instance settings"
msgstr ""
msgid "GroupSettings|Select a sub-group as the custom project template source for this group."
-msgstr "Виберіть підгрупу Ñк джерело влаÑних шаблонів проектів Ð´Ð»Ñ Ñ†Ñ–Ñ”Ñ— групи."
+msgstr "Виберіть підгрупу Ñк джерело влаÑних шаблонів проєктів Ð´Ð»Ñ Ñ†Ñ–Ñ”Ñ— групи."
msgid "GroupSettings|The Auto DevOps pipeline will run if no alternative CI configuration file is found."
msgstr "Конвеєр Auto DevOps буде запущено, Ñкщо не буде знайдено альтернативного файлу конфігуріції CI."
@@ -12633,16 +13028,16 @@ msgid "GroupSettings|This setting is applied on %{ancestor_group} and has been o
msgstr "Цей параметр заÑтоÑовано до %{ancestor_group} Ñ– його було перевизначено в цій підгрупі."
msgid "GroupSettings|This setting is applied on %{ancestor_group}. To share projects in this group with another group, ask the owner to override the setting or %{remove_ancestor_share_with_group_lock}."
-msgstr "Цей параметр заÑтоÑовано до %{ancestor_group}. Щоб поділитиÑÑ Ð¿Ñ€Ð¾ÐµÐºÑ‚Ð°Ð¼Ð¸ з цієї групи з іншою групою, попроÑÑ–Ñ‚ÑŒ влаÑника перевизначити параметр або %{remove_ancestor_share_with_group_lock}."
+msgstr "Цей параметр заÑтоÑовано до %{ancestor_group}. Щоб поділитиÑÑ Ð¿Ñ€Ð¾Ñ”ÐºÑ‚Ð°Ð¼Ð¸ з цієї групи з іншою групою, попроÑÑ–Ñ‚ÑŒ влаÑника перевизначити параметр або %{remove_ancestor_share_with_group_lock}."
msgid "GroupSettings|This setting is applied on %{ancestor_group}. You can override the setting or %{remove_ancestor_share_with_group_lock}."
msgstr "Цей параметр заÑтоÑовано до %{ancestor_group}. Ви можете перевизначити Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð°Ð±Ð¾ %{remove_ancestor_share_with_group_lock}."
msgid "GroupSettings|This setting will be applied to all subgroups unless overridden by a group owner. Groups that already have access to the project will continue to have access unless removed manually."
-msgstr "Цей параметр буде заÑтоÑовано до вÑÑ–Ñ… підгруп, Ñкщо тільки не буде перевизначено влаÑником групи. Групи, Ñкі вже мають доÑтуп до проекту, будуть мати доÑтуп, Ñкщо вони не будуть вилучені вручну."
+msgstr "Цей параметр буде заÑтоÑовано до вÑÑ–Ñ… підгруп, Ñкщо тільки не буде перевизначено влаÑником групи. Групи, Ñкі вже мають доÑтуп до проєкту, будуть мати доÑтуп, Ñкщо вони не будуть вилучені вручну."
msgid "GroupSettings|This setting will override user notification preferences for all members of the group, subgroups, and projects."
-msgstr "Це Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð¿ÐµÑ€ÐµÐ²Ð¸Ð·Ð½Ð°Ñ‡Ð¸Ñ‚ÑŒ Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ñповіщень Ð´Ð»Ñ Ð²ÑÑ–Ñ… учаÑників групи, підгруп та проектів."
+msgstr "Це Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð¿ÐµÑ€ÐµÐ²Ð¸Ð·Ð½Ð°Ñ‡Ð¸Ñ‚ÑŒ Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ñповіщень Ð´Ð»Ñ Ð²ÑÑ–Ñ… учаÑників групи, підгруп та проєктів."
msgid "GroupSettings|This setting will prevent group members from being notified if the group is mentioned."
msgstr "Цей параметр запобігає оповіщенню учаÑників групи в разі Ñ—Ñ— згадки."
@@ -12720,16 +13115,16 @@ msgid "GroupsDropdown|This feature requires browser localStorage support"
msgstr "Ð¦Ñ Ñ„ÑƒÐ½ÐºÑ†Ñ–Ñ Ð¿Ð¾Ñ‚Ñ€ÐµÐ±ÑƒÑ” підтримки localStorage вашим браузером"
msgid "GroupsEmptyState|A group is a collection of several projects."
-msgstr "Група — набір із декількох проектів."
+msgstr "Група — набір із декількох проєктів."
msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
-msgstr "Ð Ð¾Ð·Ð¼Ñ–Ñ‰ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾ÐµÐºÑ‚Ñ–Ð² у групі Ñхоже на Ñ€Ð¾Ð·Ð¼Ñ–Ñ‰ÐµÐ½Ð½Ñ Ð² папці."
+msgstr "Ð Ð¾Ð·Ð¼Ñ–Ñ‰ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾Ñ”ÐºÑ‚Ñ–Ð² у групі Ñхоже на Ñ€Ð¾Ð·Ð¼Ñ–Ñ‰ÐµÐ½Ð½Ñ Ð² папці."
msgid "GroupsEmptyState|No groups found"
msgstr "Групи не знайдені"
msgid "GroupsEmptyState|You can manage your group member’s permissions and access to each project in the group."
-msgstr "Ви можете керувати правами доÑтупу членів групи мати доÑтуп до кожного проекту в ній."
+msgstr "Ви можете керувати правами доÑтупу членів групи мати доÑтуп до кожного проєкту в ній."
msgid "GroupsNew|Contact an administrator to enable options for importing your group."
msgstr ""
@@ -12740,12 +13135,12 @@ msgstr "Створити"
msgid "GroupsNew|Create group"
msgstr "Створити групу"
-msgid "GroupsNew|GitLab group export"
-msgstr ""
-
msgid "GroupsNew|Import"
msgstr "Імпорт"
+msgid "GroupsNew|Import a GitLab group export file"
+msgstr ""
+
msgid "GroupsNew|Import group"
msgstr "Імпортувати групу"
@@ -12762,7 +13157,7 @@ msgid "GroupsTree|Are you sure you want to leave the \"%{fullName}\" group?"
msgstr "Ви впевнені, що хочете залишити групу \"%{fullName}\"?"
msgid "GroupsTree|Create a project in this group."
-msgstr "Створити проект у групі."
+msgstr "Створити проєкт у групі."
msgid "GroupsTree|Create a subgroup in this group."
msgstr "Створити підгрупи у цій групі."
@@ -12813,7 +13208,7 @@ msgid "Header message"
msgstr "ÐŸÐ¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð·Ð°Ð³Ð¾Ð»Ð¾Ð²ÐºÐ°"
msgid "Headings"
-msgstr ""
+msgstr "Заголовки"
msgid "Health"
msgstr "Здоров'Ñ"
@@ -12825,7 +13220,7 @@ msgid "Health information can be retrieved from the following endpoints. More in
msgstr "Інформацію про працездатніÑÑ‚ÑŒ можна отримати з наÑтупних кінцевих точок. Більше інформації доÑтупно"
msgid "Health status"
-msgstr ""
+msgstr "Стан здоров’Ñ"
msgid "Health status cannot be edited because this issue is closed"
msgstr ""
@@ -12846,7 +13241,7 @@ msgid "Hello there"
msgstr "Привіт"
msgid "Hello, %{username}!"
-msgstr ""
+msgstr "Привіт, %{username}!"
msgid "Help"
msgstr "Допомога"
@@ -12879,7 +13274,7 @@ msgid "Hi %{username}!"
msgstr "Привіт %{username}!"
msgid "Hide archived projects"
-msgstr "Сховати архівовані проекти"
+msgstr "Сховати архівовані проєкти"
msgid "Hide chart"
msgid_plural "Hide charts"
@@ -12888,6 +13283,9 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "Hide comments on this file"
+msgstr ""
+
msgid "Hide details"
msgstr ""
@@ -12895,7 +13293,7 @@ msgid "Hide file browser"
msgstr "Сховати файловий менеджер"
msgid "Hide group projects"
-msgstr "Приховати проекти групи"
+msgstr "Приховати проєкти групи"
msgid "Hide host keys manual input"
msgstr "Сховати ввід ключів хоÑта"
@@ -12910,7 +13308,7 @@ msgid "Hide payload"
msgstr "Приховати кориÑне навантаженнÑ"
msgid "Hide shared projects"
-msgstr "Сховати Ñпільні проекти"
+msgstr "Сховати Ñпільні проєкти"
msgid "Hide stage"
msgstr "Сховати етап"
@@ -12934,6 +13332,15 @@ msgstr "Ðайвища кількіÑÑ‚ÑŒ запитів за хвилину дÐ
msgid "Highest role:"
msgstr "Ðайвища роль:"
+msgid "HighlightBar|Alert events:"
+msgstr ""
+
+msgid "HighlightBar|Alert start time:"
+msgstr ""
+
+msgid "HighlightBar|Original alert:"
+msgstr ""
+
msgid "History"
msgstr "ІÑторіÑ"
@@ -12944,7 +13351,7 @@ msgid "Homepage"
msgstr "Ð”Ð¾Ð¼Ð°ÑˆÐ½Ñ Ñторінка"
msgid "Hook execution failed. Ensure the group has a project with commits."
-msgstr "Ðевдале Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ Ñ…ÑƒÐºÐ°. ПереконайтеÑÑ, що Ñ†Ñ Ð³Ñ€ÑƒÐ¿Ð° має проект із комітами."
+msgstr "Ðевдале Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ Ñ…ÑƒÐºÐ°. ПереконайтеÑÑ, що Ñ†Ñ Ð³Ñ€ÑƒÐ¿Ð° має проєкт із комітами."
msgid "Hook was successfully created."
msgstr "Хук уÑпішно Ñтворено."
@@ -13034,7 +13441,7 @@ msgid "IDE|Get started with Live Preview"
msgstr "Розпочати роботу із попереднім переглÑдом"
msgid "IDE|Go to project"
-msgstr "Перейти до проекту"
+msgstr "Перейти до проєкту"
msgid "IDE|Live Preview"
msgstr "Попередній переглÑд"
@@ -13100,7 +13507,7 @@ msgid "If disabled, only admins will be able to configure repository mirroring."
msgstr "Якщо вимкнено, лише адмініÑтратори зможуть налаштовувати Ð²Ñ–Ð´Ð´Ð·ÐµÑ€ÐºÐ°Ð»ÐµÐ½Ñ Ñ€ÐµÐ¿Ð¾Ð·Ð¸Ñ‚Ð¾Ñ€Ñ–Ñ—Ð²."
msgid "If disabled, the access level will depend on the user's permissions in the project."
-msgstr "Якщо це відключено, то рівень доÑтупу буде залежати від дозволів кориÑтувача в проекті."
+msgstr "Якщо це відключено, то рівень доÑтупу буде залежати від дозволів кориÑтувача в проєкті."
msgid "If enabled"
msgstr "Якщо увімкнено"
@@ -13109,7 +13516,10 @@ msgid "If enabled, GitLab will handle Object Storage replication using Geo. %{li
msgstr ""
msgid "If enabled, access to projects will be validated on an external service using their classification label."
-msgstr "Якщо це дозволено, доÑтуп до проектів буде перевірÑтиÑÑ Ð·Ð¾Ð²Ð½Ñ–ÑˆÐ½ÑŒÐ¾ÑŽ Ñлужбою з викориÑтаннÑм Ñ—Ñ… мітки клаÑифікації."
+msgstr "Якщо це дозволено, доÑтуп до проєктів буде перевірÑтиÑÑ Ð·Ð¾Ð²Ð½Ñ–ÑˆÐ½ÑŒÐ¾ÑŽ Ñлужбою з викориÑтаннÑм Ñ—Ñ… мітки клаÑифікації."
+
+msgid "If the number of active users exceeds the user limit, you will be charged for the number of %{users_over_license_link} at your next license reconciliation."
+msgstr ""
msgid "If there is no previous license or if the previous license has expired, some GitLab functionality will be blocked until a new, valid license is uploaded."
msgstr ""
@@ -13150,9 +13560,6 @@ msgstr ""
msgid "If your HTTP repository is not publicly accessible, add your credentials."
msgstr "Якщо ваш HTTP-репозиторій не Ñ” загальнодоÑтупним, додайте Ñвої облікові дані."
-msgid "Iglu registry URL (optional)"
-msgstr "URL-адреÑа реєÑтру Iglu (необов'Ñзково)"
-
msgid "Ignore"
msgstr "Iгнорувати"
@@ -13163,7 +13570,7 @@ msgid "Image Details"
msgstr "Деталі образу"
msgid "Image URL"
-msgstr ""
+msgstr "URL-адреÑа зображеннÑ"
msgid "ImageDiffViewer|2-up"
msgstr "2 поруч"
@@ -13189,26 +13596,34 @@ msgstr "Ð†Ð¼Ñ–Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð±ÑƒÐ»Ð¾ вимкнено"
msgid "Import"
msgstr "Імпорт"
+msgid "Import %d compatible repository"
+msgid_plural "Import %d compatible repositories"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
+msgid "Import %d repository"
+msgid_plural "Import %d repositories"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "Import CSV"
msgstr "Імпортувати CSV"
msgid "Import Projects from Gitea"
-msgstr "Імпортувати проекти з Gitea"
+msgstr "Імпортувати проєкти з Gitea"
msgid "Import all compatible projects"
-msgstr "Імпорт вÑÑ–Ñ… ÑуміÑних проектів"
-
-msgid "Import all compatible repositories"
-msgstr ""
+msgstr "Імпорт вÑÑ–Ñ… ÑуміÑних проєктів"
msgid "Import all projects"
-msgstr "Імпортувати вÑÑ– проекти"
-
-msgid "Import all repositories"
-msgstr "Імпорт вÑÑ–Ñ… репозиторіїв"
+msgstr "Імпортувати вÑÑ– проєкти"
msgid "Import an exported GitLab project"
-msgstr "Імпортувати екÑпортований проект GitLab"
+msgstr "Імпортувати екÑпортований проєкт GitLab"
msgid "Import failed due to a GitHub error: %{original}"
msgstr ""
@@ -13232,31 +13647,31 @@ msgid "Import members"
msgstr "Імпортувати учаÑників"
msgid "Import members from another project"
-msgstr "Імпортувати учаÑників з іншого проекту"
+msgstr "Імпортувати учаÑників з іншого проєкту"
msgid "Import multiple repositories by uploading a manifest file."
msgstr "Імпортувати кілька репозиторіїв, надіÑлавши файл маніфеÑту."
msgid "Import project"
-msgstr "Імпорт проекту"
+msgstr "Імпорт проєкту"
msgid "Import project members"
-msgstr "Імпортувати учаÑників проекту"
+msgstr "Імпортувати учаÑників проєкту"
msgid "Import projects from Bitbucket"
-msgstr "Імпортувати проекти з Bitbucket"
+msgstr "Імпортувати проєкти з Bitbucket"
msgid "Import projects from Bitbucket Server"
-msgstr "Імпортувати проекти з Bitbucket Server"
+msgstr "Імпортувати проєкти з Bitbucket Server"
msgid "Import projects from FogBugz"
-msgstr "Імпортувати проекти з FogBugz"
+msgstr "Імпортувати проєкти з FogBugz"
msgid "Import projects from GitLab.com"
-msgstr "Імпортувати проекти з GitLab.com"
+msgstr "Імпортувати проєкти з GitLab.com"
msgid "Import projects from Google Code"
-msgstr "Імпортувати проекти з Google Code"
+msgstr "Імпортувати проєкти з Google Code"
msgid "Import repositories from Bitbucket Server"
msgstr "Імпортувати репозиторії з Bitbucket Server"
@@ -13294,8 +13709,11 @@ msgstr "Заблокований URL Ð´Ð»Ñ Ñ–Ð¼Ð¿Ð¾Ñ€Ñ‚Ñƒ: %{message}"
msgid "ImportProjects|Error importing repository %{project_safe_import_url} into %{project_full_path} - %{message}"
msgstr "Помилка при імпортуванні репозиторію %{project_safe_import_url} в %{project_full_path} - %{message}"
+msgid "ImportProjects|Import repositories"
+msgstr ""
+
msgid "ImportProjects|Importing the project failed"
-msgstr "Ð†Ð¼Ð¿Ð¾Ñ€Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð¿Ñ€Ð¾ÐµÐºÑ‚Ñƒ невдале"
+msgstr "Ð†Ð¼Ð¿Ð¾Ñ€Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð¿Ñ€Ð¾Ñ”ÐºÑ‚Ñƒ невдале"
msgid "ImportProjects|Importing the project failed: %{reason}"
msgstr ""
@@ -13306,8 +13724,8 @@ msgstr ""
msgid "ImportProjects|Requesting your %{provider} repositories failed"
msgstr "Запит ваших %{provider} репозиторіїв пройшов невдало"
-msgid "ImportProjects|Select the projects you want to import"
-msgstr "Виберіть проекти Ð´Ð»Ñ Ñ–Ð¼Ð¿Ð¾Ñ€Ñ‚Ñƒ"
+msgid "ImportProjects|Select the repositories you want to import"
+msgstr ""
msgid "ImportProjects|The remote data could not be imported."
msgstr "Віддалені дані не можуть бути імпортовані."
@@ -13342,9 +13760,6 @@ msgstr ""
msgid "In order to enable Service Desk for your instance, you must first set up incoming email."
msgstr ""
-msgid "In order to gather accurate feature usage data, it can take 1 to 2 weeks to see your index."
-msgstr "Збір точних даних про викориÑÑ‚Ð°Ð½Ð½Ñ Ð´Ð»Ñ Ð²Ñ–Ð´Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ Ð²Ð°ÑˆÐ¾Ð³Ð¾ індекÑу може зайнÑти від 1 до 2 тижнів."
-
msgid "In order to personalize your experience with GitLab%{br_tag}we would like to know a bit more about you."
msgstr ""
@@ -13352,10 +13767,10 @@ msgid "In progress"
msgstr "Ð’ процеÑÑ–"
msgid "In the next step, you'll be able to select the projects you want to import."
-msgstr "Ðа наÑтупному кроці ви зможете вибрати проекти, Ñкі хочете імпортувати."
+msgstr "Ðа наÑтупному кроці ви зможете вибрати проєкти, Ñкі хочете імпортувати."
msgid "Incident"
-msgstr ""
+msgstr "Інцидент"
msgid "Incident Management Limits"
msgstr "Ліміти, пов’Ñзані із УправліннÑм Інцидентами"
@@ -13375,18 +13790,30 @@ msgstr ""
msgid "IncidentManagement|Create incident"
msgstr ""
+msgid "IncidentManagement|Critical - S1"
+msgstr ""
+
msgid "IncidentManagement|Date created"
msgstr ""
msgid "IncidentManagement|Display your incidents in a dedicated view"
msgstr ""
+msgid "IncidentManagement|High - S2"
+msgstr ""
+
msgid "IncidentManagement|Incident"
msgstr ""
msgid "IncidentManagement|Incidents"
msgstr ""
+msgid "IncidentManagement|Low - S4"
+msgstr ""
+
+msgid "IncidentManagement|Medium - S3"
+msgstr ""
+
msgid "IncidentManagement|No incidents to display."
msgstr ""
@@ -13399,6 +13826,9 @@ msgstr ""
msgid "IncidentManagement|Published to status page"
msgstr ""
+msgid "IncidentManagement|Severity"
+msgstr ""
+
msgid "IncidentManagement|There are no closed incidents"
msgstr ""
@@ -13408,6 +13838,9 @@ msgstr ""
msgid "IncidentManagement|Unassigned"
msgstr ""
+msgid "IncidentManagement|Unknown"
+msgstr ""
+
msgid "IncidentManagement|Unpublished"
msgstr ""
@@ -13429,6 +13862,15 @@ msgstr ""
msgid "Incidents"
msgstr "Інциденти"
+msgid "Incident|Alert details"
+msgstr ""
+
+msgid "Incident|Summary"
+msgstr ""
+
+msgid "Incident|There was an issue loading alert data. Please try again."
+msgstr ""
+
msgid "Include a Terms of Service agreement and Privacy Policy that all users must accept."
msgstr "Включити угоду про Ð½Ð°Ð´Ð°Ð½Ð½Ñ Ð¿Ð¾Ñлуг та правила конфіденційноÑÑ‚Ñ–, Ñкі повинні прийнÑти вÑÑ– кориÑтувачі."
@@ -13445,7 +13887,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. 0 for unlimited."
-msgstr "Включає об'єкти LFS. Може бути перевизначено в групі або проекті. 0 — необмежено."
+msgstr "Включає об'єкти LFS. Може бути перевизначено в групі або проєкті. 0 — необмежено."
msgid "Includes an MVC structure to help you get started."
msgstr "Включає Ñтруктуру MVC, щоб допомогти вам розпочати роботу."
@@ -13460,10 +13902,10 @@ msgid "Incoming email"
msgstr "Вхідна пошта"
msgid "Incoming!"
-msgstr ""
+msgstr "Вхідні!"
msgid "Incompatible Project"
-msgstr "ÐеÑуміÑний проект"
+msgstr "ÐеÑуміÑний проєкт"
msgid "Incompatible options set!"
msgstr "Ð’Ñтановлено неÑуміÑні параметри!"
@@ -13472,10 +13914,10 @@ msgid "Incompatible project"
msgstr ""
msgid "Indent"
-msgstr ""
+msgstr "ВідÑтуп"
msgid "Index all projects"
-msgstr "ІндекÑувати вÑÑ– проекти"
+msgstr "ІндекÑувати вÑÑ– проєкти"
msgid "Index deletion is canceled"
msgstr ""
@@ -13489,6 +13931,9 @@ msgstr "ПовідомлÑти кориÑтувачам без клічів SSH,
msgid "Information about additional Pages templates and how to install them can be found in our %{pages_getting_started_guide}."
msgstr "Ви можете знайти інформацію про додаткові шаблони Pages та те, Ñк Ñ—Ñ… вÑтановити в нашій %{pages_getting_started_guide}."
+msgid "Inherited"
+msgstr ""
+
msgid "Inherited:"
msgstr "УÑпадковано:"
@@ -13502,16 +13947,16 @@ msgid "Input your repository URL"
msgstr "Введіть ваш URL репозиторію"
msgid "Insert"
-msgstr ""
+msgstr "Ð’Ñтавити"
msgid "Insert a code block"
-msgstr ""
+msgstr "Ð’Ñтавити блок коду"
msgid "Insert a quote"
msgstr "Ð’Ñтавити цитату"
msgid "Insert an image"
-msgstr ""
+msgstr "Ð’Ñтавити малюнок"
msgid "Insert code"
msgstr "Ð’Ñтавити код"
@@ -13571,8 +14016,23 @@ msgstr ""
msgid "Instance administrators group already exists"
msgstr "Група Ð´Ð»Ñ Ð°Ð´Ð¼Ñ–Ð½Ñ–Ñтраторів інÑтанÑу вже Ñ–Ñнує"
-msgid "Instance license"
-msgstr "Ð›Ñ–Ñ†ÐµÐ½Ð·Ñ–Ñ Ñ–Ð½ÑтанÑу"
+msgid "InstanceStatistics|Groups"
+msgstr ""
+
+msgid "InstanceStatistics|Issues"
+msgstr ""
+
+msgid "InstanceStatistics|Merge Requests"
+msgstr ""
+
+msgid "InstanceStatistics|Pipelines"
+msgstr ""
+
+msgid "InstanceStatistics|Projects"
+msgstr ""
+
+msgid "InstanceStatistics|Users"
+msgstr ""
msgid "Integration"
msgstr "ІнтеграціÑ"
@@ -13583,6 +14043,12 @@ msgstr "ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð†Ð½Ñ‚ÐµÐ³Ñ€Ð°Ñ†Ñ–Ñ—"
msgid "Integrations"
msgstr "Інтеграції"
+msgid "Integrations|%{integration} settings saved and active."
+msgstr ""
+
+msgid "Integrations|%{integration} settings saved, but not active."
+msgstr ""
+
msgid "Integrations|All details"
msgstr "Ð’ÑÑ– деталі"
@@ -13592,6 +14058,12 @@ msgstr ""
msgid "Integrations|Comment settings:"
msgstr ""
+msgid "Integrations|Connection failed. Please check your settings."
+msgstr ""
+
+msgid "Integrations|Connection successful."
+msgstr ""
+
msgid "Integrations|Default settings are inherited from the group level."
msgstr ""
@@ -13607,6 +14079,15 @@ msgstr ""
msgid "Integrations|Includes commit title and branch"
msgstr ""
+msgid "Integrations|Projects using custom settings will not be impacted unless the project owner chooses to use instance-level defaults."
+msgstr ""
+
+msgid "Integrations|Save settings?"
+msgstr ""
+
+msgid "Integrations|Saving will update the default settings for all projects that are not using custom settings."
+msgstr ""
+
msgid "Integrations|Standard"
msgstr ""
@@ -13626,10 +14107,10 @@ msgid "Internal"
msgstr "Внутрішній"
msgid "Internal - The group and any internal projects can be viewed by any logged in user."
-msgstr "Ð’Ð½ÑƒÑ‚Ñ€Ñ–ÑˆÐ½Ñ â€” будь-Ñкий автентифікований кориÑтувач має доÑтуп до цієї групи та уÑÑ–Ñ… Ñ—Ñ— внутрішніх проектів."
+msgstr "Ð’Ð½ÑƒÑ‚Ñ€Ñ–ÑˆÐ½Ñ â€” будь-Ñкий автентифікований кориÑтувач має доÑтуп до цієї групи та уÑÑ–Ñ… Ñ—Ñ— внутрішніх проєктів."
msgid "Internal - The project can be accessed by any logged in user."
-msgstr "Внутрішній — будь-Ñкий автентифікований кориÑтувач має доÑтуп до цього проекту."
+msgstr "Внутрішній — будь-Ñкий автентифікований кориÑтувач має доÑтуп до цього проєкту."
msgid "Internal URL (optional)"
msgstr ""
@@ -13728,7 +14209,7 @@ msgid "Invalid start or end time format"
msgstr ""
msgid "Invalid status"
-msgstr ""
+msgstr "ÐеприпуÑтимий ÑтатуÑ"
msgid "Invalid two-factor code."
msgstr "ÐедійÑний двофакторний код підтвердженнÑ."
@@ -13739,6 +14220,9 @@ msgstr ""
msgid "Invitation"
msgstr "ЗапрошеннÑ"
+msgid "Invitation declined"
+msgstr ""
+
msgid "Invite"
msgstr "ЗапрошеннÑ"
@@ -13746,7 +14230,7 @@ msgid "Invite \"%{trimmed}\" by email"
msgstr "ЗапроÑити \"%{trimmed}\" за електронною поштою"
msgid "Invite Members"
-msgstr ""
+msgstr "ЗапроÑити учаÑників"
msgid "Invite another teammate"
msgstr ""
@@ -13790,6 +14274,42 @@ 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|%{linkStart}Read more%{linkEnd} about role permissions"
+msgstr ""
+
+msgid "InviteMembersModal|Access expiration date (optional)"
+msgstr ""
+
+msgid "InviteMembersModal|Cancel"
+msgstr ""
+
+msgid "InviteMembersModal|Choose a role permission"
+msgstr ""
+
+msgid "InviteMembersModal|GitLab member or Email address"
+msgstr ""
+
+msgid "InviteMembersModal|Invite"
+msgstr ""
+
+msgid "InviteMembersModal|Invite team members"
+msgstr ""
+
+msgid "InviteMembersModal|Search for members to invite"
+msgstr ""
+
+msgid "InviteMembersModal|User not invited. Feature coming soon!"
+msgstr ""
+
+msgid "InviteMembersModal|Users were succesfully added"
+msgstr ""
+
+msgid "InviteMembersModal|You're inviting members to the %{group_name} group"
+msgstr ""
+
+msgid "InviteMembers|Invite team members"
+msgstr ""
+
msgid "Invited"
msgstr ""
@@ -13844,10 +14364,13 @@ msgstr "Задачу вже переведено до епіку."
msgid "Issue cannot be found."
msgstr "Ðеможливо знайти задачу."
+msgid "Issue created from vulnerability %{vulnerability_link}"
+msgstr ""
+
msgid "Issue events"
msgstr "Задачі"
-msgid "Issue first depoloyed to production"
+msgid "Issue first deployed to production"
msgstr ""
msgid "Issue label"
@@ -13925,6 +14448,9 @@ msgstr "РеєÑÑ‚Ñ€ задач Bugzilla"
msgid "IssueTracker|Custom issue tracker"
msgstr "ВлаÑний реєÑÑ‚Ñ€ задач"
+msgid "IssueTracker|EWM work items tracker"
+msgstr ""
+
msgid "IssueTracker|Redmine issue tracker"
msgstr "РеєÑÑ‚Ñ€ задач Redmine"
@@ -13950,7 +14476,7 @@ msgid "Issues referenced by merge requests and commits within the default branch
msgstr ""
msgid "Issues with comments, merge requests with diffs and comments, labels, milestones, snippets, and other project entities"
-msgstr "Задачі з коментарÑми, запити на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð· порівнÑннÑми (diff) та коментарÑми, мітки, етапи, Ñніпети та інші об'єкти в проекті"
+msgstr "Задачі з коментарÑми, запити на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð· порівнÑннÑми (diff) та коментарÑми, мітки, етапи, Ñніпети та інші об'єкти в проєкті"
msgid "Issues with no epic assigned"
msgstr ""
@@ -13959,7 +14485,7 @@ msgid "Issues, merge requests, pushes, and comments."
msgstr "Задачі, запити на злиттÑ, Ð²Ñ–Ð´Ð¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð½Ñ ÐºÐ¾Ð´Ñƒ Ñ– коментарі."
msgid "IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them"
-msgstr "ПіÑÐ»Ñ ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð·Ð°Ð´Ð°Ñ‡ Ð´Ð»Ñ Ð²Ð°ÑˆÐ¸Ñ… проектів, ми зможемо почати відÑтежувати Ñ– відображати метрики Ð´Ð»Ñ Ð½Ð¸Ñ…"
+msgstr "ПіÑÐ»Ñ ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð·Ð°Ð´Ð°Ñ‡ Ð´Ð»Ñ Ð²Ð°ÑˆÐ¸Ñ… проєктів, ми зможемо почати відÑтежувати Ñ– відображати метрики Ð´Ð»Ñ Ð½Ð¸Ñ…"
msgid "IssuesAnalytics|Avg/Month:"
msgstr "Ð’ Ñередньому за міÑÑць:"
@@ -13977,7 +14503,7 @@ msgid "IssuesAnalytics|Sorry, your filter produced no results"
msgstr "Ðа жаль, немає результатів, Ñкі відповідають фільтру"
msgid "IssuesAnalytics|There are no issues for the projects in your group"
-msgstr "Ðемає задач Ð´Ð»Ñ Ð²ÑÑ–Ñ… проектів у групі"
+msgstr "Ðемає задач Ð´Ð»Ñ Ð²ÑÑ–Ñ… проєктів у групі"
msgid "IssuesAnalytics|To widen your search, change or remove filters in the filter bar above"
msgstr "Щоб розширити пошук, будь лаÑка, змініть або видаліть фільтр вище"
@@ -13991,6 +14517,9 @@ msgstr "Ðазва"
msgid "It looks like you have some draft commits in this branch."
msgstr ""
+msgid "It may be several days before you see feature usage data."
+msgstr ""
+
msgid "It must have a header row and at least two columns: the first column is the issue title and the second column is the issue description. The separator is automatically detected."
msgstr "Має ÑкладатиÑÑ Ñ–Ð· Ñ€Ñдка заголовка Ñ– мінімум двох колонок: перша — заголовок задачі, а друга — Ñ—Ñ— опиÑ. Розділювач визначаєтьÑÑ Ð°Ð²Ñ‚Ð¾Ð¼Ð°Ñ‚Ð¸Ñ‡Ð½Ð¾."
@@ -14004,19 +14533,19 @@ msgid "It's you"
msgstr "Це ви"
msgid "Iteration"
-msgstr ""
+msgstr "ІтераціÑ"
msgid "Iteration changed to"
-msgstr ""
+msgstr "Ітерацію змінено на"
msgid "Iteration removed"
-msgstr ""
+msgstr "Ітерацію видалено"
msgid "Iteration updated"
-msgstr ""
+msgstr "Ітерацію оновлено"
msgid "Iterations"
-msgstr ""
+msgstr "Ітерації"
msgid "Iteration|Dates cannot overlap with other existing Iterations"
msgstr ""
@@ -14253,7 +14782,7 @@ msgid "Job|This job failed because the necessary resources were not successfully
msgstr "Ð—Ð°Ð²Ð´Ð°Ð½Ð½Ñ Ð·Ð°Ð²ÐµÑ€ÑˆÐ¸Ð»Ð¾ÑÑ Ð½ÐµÐ²Ð´Ð°Ð»Ð¾ тому що необхідні реÑурÑи не було уÑпішно Ñтворені."
msgid "Job|This job is stuck because the project doesn't have any runners online assigned to it."
-msgstr "Це Ð·Ð°Ð²Ð´Ð°Ð½Ð½Ñ Ð·Ð°Ð±Ð»Ð¾ÐºÐ¾Ð²Ð°Ð½Ðµ, тому що цей проект не має жодних runner'ів призначених Ð´Ð»Ñ Ð½ÑŒÐ¾Ð³Ð¾."
+msgstr "Це Ð·Ð°Ð²Ð´Ð°Ð½Ð½Ñ Ð·Ð°Ð±Ð»Ð¾ÐºÐ¾Ð²Ð°Ð½Ðµ, тому що цей проєкт не має жодних runner'ів призначених Ð´Ð»Ñ Ð½ÑŒÐ¾Ð³Ð¾."
msgid "Job|This job is stuck because you don't have any active runners online or available with any of these tags assigned to them:"
msgstr ""
@@ -14273,15 +14802,15 @@ msgstr "з"
msgid "Join Zoom meeting"
msgstr "ПриєднатиÑÑ Ð´Ð¾ зуÑтрічі в Zoom"
+msgid "Joined %{time_ago}"
+msgstr ""
+
msgid "Jul"
msgstr "лип."
msgid "July"
msgstr "липень"
-msgid "Jump to first unresolved thread"
-msgstr ""
-
msgid "Jump to next unresolved thread"
msgstr ""
@@ -14315,6 +14844,9 @@ msgstr "Ключ: %{key}"
msgid "Keyboard shortcuts"
msgstr "Комбінації клавіш"
+msgid "KeyboardKey|Ctrl+"
+msgstr ""
+
msgid "Keys"
msgstr "Ключі"
@@ -14363,15 +14895,21 @@ msgstr "LDAP"
msgid "LDAP Synchronization"
msgstr "Ð¡Ð¸Ð½Ñ…Ñ€Ð¾Ð½Ñ–Ð·Ð°Ñ†Ñ–Ñ LDAP"
+msgid "LDAP group settings"
+msgstr ""
+
msgid "LDAP settings"
msgstr "ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ LDAP"
msgid "LDAP settings updated"
-msgstr ""
+msgstr "Параметри LDAP оновлено"
msgid "LDAP sync in progress. This could take a few minutes. Refresh the page to see the changes."
msgstr "ВідбуваєтьÑÑ ÑÐ¸Ð½Ñ…Ñ€Ð¾Ð½Ñ–Ð·Ð°Ñ†Ñ–Ñ LDAP. Вона може зайнÑти кілька хвилин. Оновлюйте Ñторінку, щоб бачити зміни."
+msgid "LDAP synchronizations"
+msgstr ""
+
msgid "LFS"
msgstr "LFS"
@@ -14421,7 +14959,7 @@ msgid "Labels"
msgstr "Мітки"
msgid "Labels can be applied to %{features}. Group labels are available for any project within the group."
-msgstr "Мітки можуть бути заÑтоÑовані до %{features}. Групові мітки доÑтупні Ð´Ð»Ñ Ð±ÑƒÐ´ÑŒ-Ñкого проекту в межах групи."
+msgstr "Мітки можуть бути заÑтоÑовані до %{features}. Групові мітки доÑтупні Ð´Ð»Ñ Ð±ÑƒÐ´ÑŒ-Ñкого проєкту в межах групи."
msgid "Labels can be applied to issues and merge requests to categorize them."
msgstr "Мітки можуть бути заÑтоÑовані до задач та запитів на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð´Ð»Ñ Ñ—Ñ… категоризації."
@@ -14454,8 +14992,17 @@ msgstr[1] "ОÑтанніх %d дні"
msgstr[2] "ОÑтанніх %d днів"
msgstr[3] "ОÑтанніх %d днів"
-msgid "Last %{days} days"
-msgstr "ОÑтанніх %{days} днів"
+msgid "Last 2 weeks"
+msgstr ""
+
+msgid "Last 30 days"
+msgstr ""
+
+msgid "Last 60 days"
+msgstr ""
+
+msgid "Last 90 days"
+msgstr ""
msgid "Last Accessed On"
msgstr ""
@@ -14532,6 +15079,9 @@ msgstr "ВоÑтаннє викориÑтано"
msgid "Last used on:"
msgstr "ОÑтаннє викориÑтаннÑ:"
+msgid "Last week"
+msgstr ""
+
msgid "LastCommit|authored"
msgstr "автор"
@@ -14547,6 +15097,9 @@ msgstr "ОÑтанні зміни"
msgid "Latest pipeline for the most recent commit on this branch"
msgstr "ОÑтанній конвеєр Ð´Ð»Ñ Ð¾Ñтаннього коміту в цій гілці"
+msgid "Launch a ready-to-code development environment for your project."
+msgstr ""
+
msgid "Lead"
msgstr "Керувати"
@@ -14587,13 +15140,13 @@ 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 "ДізнатиÑÑ Ð±Ñ–Ð»ÑŒÑˆÐµ про Ð´Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ñертифікатів до проекту перейшовши до %{docs_link_start}документації по GitLab Pages%{docs_link_end}."
+msgstr "ДізнатиÑÑ Ð±Ñ–Ð»ÑŒÑˆÐµ про Ð´Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ñертифікатів до проєкту перейшовши до %{docs_link_start}документації по GitLab Pages%{docs_link_end}."
msgid "Learn more about approvals."
msgstr "ДізнайтеÑÑ Ð±Ñ–Ð»ÑŒÑˆÐµ про затвердженнÑ."
msgid "Learn more about custom project templates"
-msgstr "Докладніше про влаÑні шаблони проектів"
+msgstr "Докладніше про влаÑні шаблони проєктів"
msgid "Learn more about deploying to AWS"
msgstr ""
@@ -14602,7 +15155,7 @@ msgid "Learn more about deploying to a cluster"
msgstr "ДізнайтеÑÑ Ð±Ñ–Ð»ÑŒÑˆÐµ про Ñ€Ð¾Ð·Ð³Ð¾Ñ€Ñ‚Ð°Ð½Ð½Ñ Ð² клаÑтер"
msgid "Learn more about group-level project templates"
-msgstr "Докладніше про шаблони проектів на рівні групи"
+msgstr "Докладніше про шаблони проєктів на рівні групи"
msgid "Learn more about job dependencies"
msgstr ""
@@ -14635,7 +15188,7 @@ msgid "Leave group"
msgstr "Залишити групу"
msgid "Leave project"
-msgstr "Залишити проект"
+msgstr "Залишити проєкт"
msgid "Leave the \"File type\" and \"Delivery method\" options on their default values."
msgstr "Залиште параметри \"Тип файлу\" та \"Метод доÑтавки\" із значеннÑми по замовчуванню."
@@ -14656,7 +15209,7 @@ msgid "License Compliance"
msgstr "ВідповідніÑÑ‚ÑŒ ліцензіÑм"
msgid "License History"
-msgstr ""
+msgstr "ІÑÑ‚Ð¾Ñ€Ñ–Ñ Ð»Ñ–Ñ†ÐµÐ½Ð·Ñ–Ð¹"
msgid "License ID:"
msgstr "ID ліцензії:"
@@ -14779,13 +15332,13 @@ msgid "LicenseCompliance|There are currently no policies that match in this proj
msgstr ""
msgid "LicenseCompliance|This license already exists in this project."
-msgstr "Така Ð»Ñ–Ñ†ÐµÐ½Ð·Ñ–Ñ Ð²Ð¶Ðµ Ñ–Ñнує в цьому проекті."
+msgstr "Така Ð»Ñ–Ñ†ÐµÐ½Ð·Ñ–Ñ Ð²Ð¶Ðµ Ñ–Ñнує в цьому проєкті."
msgid "LicenseCompliance|URL"
msgstr "URL-адреÑа"
msgid "LicenseCompliance|You are about to remove the license, %{name}, from this project."
-msgstr "Ви збираєтеÑÑ Ð²Ð¸Ð´Ð°Ð»Ð¸Ñ‚Ð¸ ліцензію %{name} із цього проекту."
+msgstr "Ви збираєтеÑÑ Ð²Ð¸Ð´Ð°Ð»Ð¸Ñ‚Ð¸ ліцензію %{name} із цього проєкту."
msgid "LicenseManagement|Allowed"
msgstr "Дозволено"
@@ -14887,7 +15440,7 @@ msgid "Limit display of time tracking units to hours."
msgstr "Обмежити Ð²Ñ–Ð´Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ Ð¾Ð´Ð¸Ð½Ð¸Ñ†ÑŒ відÑÑ‚ÐµÐ¶ÐµÐ½Ð½Ñ Ñ‡Ð°Ñу до годин."
msgid "Limit namespaces and projects that can be indexed"
-msgstr "Обмежити проÑтори імен та проекти Ñкі можуть бути проіндекÑовані"
+msgstr "Обмежити проÑтори імен та проєкти Ñкі можуть бути проіндекÑовані"
msgid "Limited to showing %d event at most"
msgid_plural "Limited to showing %d events at most"
@@ -14941,6 +15494,9 @@ msgstr "СпиÑок доÑтупних репозиторіїв"
msgid "List of all merge commits"
msgstr ""
+msgid "List options"
+msgstr ""
+
msgid "List settings"
msgstr "СпиÑок налаштувань"
@@ -14953,14 +15509,11 @@ msgstr "Режим ÑпиÑку"
msgid "List your Bitbucket Server repositories"
msgstr "СпиÑко репозиторіїв вашого Bitbucket Server"
-msgid "Lists"
-msgstr "СпиÑки"
-
msgid "Live preview"
msgstr "Попередній переглÑд"
msgid "Load more"
-msgstr ""
+msgstr "Завантажити ще"
msgid "Load more users"
msgstr ""
@@ -15020,7 +15573,7 @@ msgid "Lock this %{issuableDisplayName}? Only %{strongStart}project members%{str
msgstr ""
msgid "Lock to current projects"
-msgstr "Закріпити за поточними проектами"
+msgstr "Закріпити за поточними проєктами"
msgid "Locked"
msgstr "Заблоковано"
@@ -15035,7 +15588,7 @@ msgid "Locked the discussion."
msgstr "ДиÑкуÑÑ–ÑŽ закрито."
msgid "Locked to current projects"
-msgstr "Закріплено за поточними проектами"
+msgstr "Закріплено за поточними проєктами"
msgid "Locks give the ability to lock specific file or folder."
msgstr "Ð‘Ð»Ð¾ÐºÑƒÐ²Ð°Ð½Ð½Ñ Ð¼Ð¾Ð¶Ðµ бути заÑтоÑоване до конкретного файлу або директорії."
@@ -15116,7 +15669,7 @@ msgid "Make sure you save it - you won't be able to access it again."
msgstr "ПереконайтеÑÑ, що ви його зберегли, бо ви не зможете отримати доÑтуп до нього знову."
msgid "Make sure you're logged into the account that owns the projects you'd like to import."
-msgstr "ПереконайтеÑÑ, що ви ввійшли за допомогою облікового запиÑу, Ñкому належать проекти, що потрібно імпортувати."
+msgstr "ПереконайтеÑÑ, що ви ввійшли за допомогою облікового запиÑу, Ñкому належать проєкти, що потрібно імпортувати."
msgid "Make this epic confidential"
msgstr ""
@@ -15152,7 +15705,7 @@ msgid "Manage milestones"
msgstr ""
msgid "Manage project labels"
-msgstr "ÐšÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð¼Ñ–Ñ‚ÐºÐ°Ð¼Ð¸ проекту"
+msgstr "ÐšÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð¼Ñ–Ñ‚ÐºÐ°Ð¼Ð¸ проєкту"
msgid "Manage storage usage"
msgstr ""
@@ -15202,6 +15755,12 @@ msgstr "Відмітити Ð½Ð°Ð³Ð°Ð´ÑƒÐ²Ð°Ð½Ð½Ñ Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð¸Ð¼"
msgid "Mark as done"
msgstr "Відмітити Ñк виконано"
+msgid "Mark as draft"
+msgstr ""
+
+msgid "Mark as ready"
+msgstr ""
+
msgid "Mark as resolved"
msgstr "Позначити Ñк вирішене"
@@ -15215,7 +15774,7 @@ msgid "Markdown"
msgstr "Markdown"
msgid "Markdown Help"
-msgstr ""
+msgstr "Довідка по розмітці Markdown"
msgid "Markdown enabled"
msgstr "Markdown увімкнено"
@@ -15223,6 +15782,24 @@ msgstr "Markdown увімкнено"
msgid "Markdown is supported"
msgstr "Markdown підтримуєтьÑÑ"
+msgid "MarkdownEditor|Add a link (%{modifierKey}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add a link (%{modifier_key}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifierKey}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifier_key}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifierKey}I)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifier_key}I)"
+msgstr ""
+
msgid "Marked For Deletion At - %{deletion_time}"
msgstr ""
@@ -15284,7 +15861,7 @@ msgid "MattermostService|Suggestions:"
msgstr "Пропозиції:"
msgid "MattermostService|This service allows users to perform common operations on this project by entering slash commands in Mattermost."
-msgstr "Цей ÑÐµÑ€Ð²Ñ–Ñ Ð´Ð¾Ð·Ð²Ð¾Ð»ÑÑ” кориÑтувачам виконувати загальні операції в цьому проекті шлÑхом вводу команд із коÑою риÑкою (/) в Mattermost."
+msgstr "Цей ÑÐµÑ€Ð²Ñ–Ñ Ð´Ð¾Ð·Ð²Ð¾Ð»ÑÑ” кориÑтувачам виконувати загальні операції в цьому проєкті шлÑхом вводу команд із коÑою риÑкою (/) в Mattermost."
msgid "Max Group Export Download requests per minute per user"
msgstr ""
@@ -15307,8 +15884,26 @@ msgstr ""
msgid "Max access level"
msgstr "МакÑимальний рівень доÑтупу"
-msgid "Max seats used"
-msgstr "МакÑимальна кількіÑÑ‚ÑŒ викориÑтаних міÑць"
+msgid "Max role"
+msgstr ""
+
+msgid "Max size 15 MB"
+msgstr ""
+
+msgid "Maximum Conan package file size in bytes"
+msgstr ""
+
+msgid "Maximum Maven package file size in bytes"
+msgstr ""
+
+msgid "Maximum NPM package file size in bytes"
+msgstr ""
+
+msgid "Maximum NuGet package file size in bytes"
+msgstr ""
+
+msgid "Maximum PyPI package file size in bytes"
+msgstr ""
msgid "Maximum Users:"
msgstr "МакÑимальна КількіÑÑ‚ÑŒ КориÑтувачів:"
@@ -15439,6 +16034,18 @@ msgstr ""
msgid "Members with access to %{strong_start}%{group_name}%{strong_end}"
msgstr "УчаÑники із доÑтупом до %{strong_start}%{group_name}%{strong_end}"
+msgid "Members|%{time} by %{user}"
+msgstr ""
+
+msgid "Members|Expired"
+msgstr ""
+
+msgid "Members|No expiration set"
+msgstr ""
+
+msgid "Members|in %{time}"
+msgstr ""
+
msgid "Memory Usage"
msgstr "ВикориÑÑ‚Ð°Ð½Ð½Ñ Ð¿Ð°Ð¼â€™ÑÑ‚Ñ–"
@@ -15509,7 +16116,7 @@ msgid "Merge request approvals"
msgstr "Ð—Ð°Ñ‚Ð²ÐµÑ€Ð´Ð¶ÐµÐ½Ð½Ñ Ð·Ð°Ð¿Ð¸Ñ‚Ñ–Ð² на злиттÑ"
msgid "Merge request approvals allow you to set the number of necessary approvals and predefine a list of approvers that will need to approve every merge request in a project."
-msgstr "Ð—Ð°Ñ‚Ð²ÐµÑ€Ð´Ð¶ÐµÐ½Ð½Ñ Ð·Ð°Ð¿Ð¸Ñ‚Ñ–Ð² на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð´Ð¾Ð·Ð²Ð¾Ð»ÑÑŽÑ‚ÑŒ вÑтановити кількіÑÑ‚ÑŒ необхідних затверджень та попередньо визначити ÑпиÑок затверджуючих оÑіб, Ñкі повинні будуть затверджувати кожен запит на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ñƒ проекті."
+msgstr "Ð—Ð°Ñ‚Ð²ÐµÑ€Ð´Ð¶ÐµÐ½Ð½Ñ Ð·Ð°Ð¿Ð¸Ñ‚Ñ–Ð² на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð´Ð¾Ð·Ð²Ð¾Ð»ÑÑŽÑ‚ÑŒ вÑтановити кількіÑÑ‚ÑŒ необхідних затверджень та попередньо визначити ÑпиÑок затверджуючих оÑіб, Ñкі повинні будуть затверджувати кожен запит на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ñƒ проєкті."
msgid "Merge request dependencies"
msgstr "ЗалежноÑÑ‚Ñ– запиту на злиттÑ"
@@ -15524,7 +16131,7 @@ msgid "Merge requests approvals"
msgstr ""
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
-msgstr "Запит на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ â€” це ÑпоÑіб запропонувати Ñвої зміни до проекту Ñ– обговорити Ñ—Ñ… із іншими"
+msgstr "Запит на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ â€” це ÑпоÑіб запропонувати Ñвої зміни до проєкту Ñ– обговорити Ñ—Ñ… із іншими"
msgid "Merge requests are read-only in a secondary Geo node"
msgstr "Запити на об'Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ð´Ð¾Ñтупні лише Ð´Ð»Ñ Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ Ð½Ð° вторинному вузлі Geo"
@@ -15625,9 +16232,6 @@ msgstr "ÐžÐ±Ð³Ð¾Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð±ÑƒÐ´Ðµ закрито"
msgid "MergeRequests|Thread will be unresolved"
msgstr "ÐžÐ±Ð³Ð¾Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð±ÑƒÐ´Ðµ повторно відкрито"
-msgid "MergeRequests|Toggle comments for this file"
-msgstr "Увімкнути або вимкнути коментарі Ð´Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ файлу"
-
msgid "MergeRequests|View file @ %{commitId}"
msgstr "ПереглÑнути файл @ %{commitId}"
@@ -15688,6 +16292,9 @@ msgstr "Зливає цей запит на злиттÑ, коли конвеєÑ
msgid "Merging immediately isn't recommended as it may negatively impact the existing merge train. Read the %{docsLinkStart}documentation%{docsLinkEnd} for more information."
msgstr "БезпоÑереднє Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð½Ðµ рекомендуєтьÑÑ Ñ‚Ð°Ðº Ñк може негативно вплинути на Ñ–Ñнуючий ланцюжок змін. Прочитайте %{docsLinkStart}документацію%{docsLinkEnd} Ð´Ð»Ñ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ Ð´Ð¾Ð´Ð°Ñ‚ÐºÐ¾Ð²Ð¾Ñ— інформації."
+msgid "Message"
+msgstr ""
+
msgid "Messages"
msgstr "ПовідомленнÑ"
@@ -15876,10 +16483,10 @@ msgstr ""
msgid "Metrics|Edit metric"
msgid_plural "Metrics|Edit metrics"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
+msgstr[0] "Редагувати метрику"
+msgstr[1] "Редагувати метрики"
+msgstr[2] "Редагувати метрик"
+msgstr[3] "Редагувати метрик"
msgid "Metrics|Expand panel"
msgstr ""
@@ -16077,18 +16684,12 @@ msgstr[1] "Етапи"
msgstr[2] "Етапів"
msgstr[3] "Етапів"
-msgid "Milestone does not support burnup charts"
-msgstr ""
-
msgid "Milestone lists not available with your current license"
msgstr "СпиÑки етапів не доÑтупні з вашою поточною ліцензією"
msgid "Milestone lists show all issues from the selected milestone."
msgstr "У ÑпиÑках етапу відображаютьÑÑ Ð²ÑÑ– задачі Ð´Ð»Ñ Ð²Ð¸Ð±Ñ€Ð°Ð½Ð¾Ð³Ð¾ етапу."
-msgid "Milestone must have a start and due date"
-msgstr ""
-
msgid "MilestoneSidebar|Closed:"
msgstr "Закрито:"
@@ -16192,7 +16793,7 @@ msgid "Milestones|Promote to Group Milestone"
msgstr ""
msgid "Milestones|Promoting %{milestoneTitle} will make it available for all projects inside %{groupName}. Existing project milestones with the same title will be merged."
-msgstr "ПеренеÑÐµÐ½Ð½Ñ %{milestoneTitle} на рівень групи зробить його доÑтупним Ð´Ð»Ñ Ð²ÑÑ–Ñ… проектів в групі %{groupName}. ІÑнуючі проектні етапи з такими ж заголовками будуть об'єднані."
+msgstr "ПеренеÑÐµÐ½Ð½Ñ %{milestoneTitle} на рівень групи зробить його доÑтупним Ð´Ð»Ñ Ð²ÑÑ–Ñ… проєктів в групі %{groupName}. ІÑнуючі проєктні етапи з такими ж заголовками будуть об'єднані."
msgid "Milestones|Reopen Milestone"
msgstr ""
@@ -16234,7 +16835,7 @@ msgid "Mirror user"
msgstr "КориÑтувач Ð´Ð»Ñ Ð²Ñ–Ð´Ð´Ð·ÐµÑ€ÐºÐ°Ð»ÐµÐ½Ð½Ñ"
msgid "Mirrored branches will have this prefix. If you enabled 'Only mirror protected branches' you need to include this prefix on protected branches in this project or nothing will be mirrored."
-msgstr "Віддзеркалені гілки матимуть цей префікÑ. Якщо ви увімкнули \"Віддзеркалювати лише захищені гілки\" вам необхідно буде включити цей Ð¿Ñ€ÐµÑ„Ñ–ÐºÑ Ñƒ захищені гілки цього проекту, інакше нічого не буде віддзеркалено."
+msgstr "Віддзеркалені гілки матимуть цей префікÑ. Якщо ви увімкнули \"Віддзеркалювати лише захищені гілки\" вам необхідно буде включити цей Ð¿Ñ€ÐµÑ„Ñ–ÐºÑ Ñƒ захищені гілки цього проєкту, інакше нічого не буде віддзеркалено."
msgid "Mirrored repositories"
msgstr "Віддзеркалені репозиторії"
@@ -16258,7 +16859,7 @@ msgid "Missing OAuth configuration for GitHub."
msgstr ""
msgid "Missing OS"
-msgstr ""
+msgstr "ВідÑÑƒÑ‚Ð½Ñ ÐžÐ¡"
msgid "Missing arch"
msgstr ""
@@ -16309,7 +16910,7 @@ msgid "Monitoring"
msgstr "Моніторинг"
msgid "Month"
-msgstr ""
+msgstr "МіÑÑць"
msgid "Months"
msgstr "МіÑÑці"
@@ -16342,7 +16943,7 @@ msgid "More information is available|here"
msgstr "тут"
msgid "More information."
-msgstr ""
+msgstr "Докладніше."
msgid "More than %{number_commits_distance} commits different with %{default_branch}"
msgstr "Ð Ñ–Ð·Ð½Ð¸Ñ†Ñ Ñ–Ð· %{default_branch} Ñкладає більше %{number_commits_distance} комітів"
@@ -16369,13 +16970,13 @@ msgid "Move selection up"
msgstr "ПереміÑтити Ð²Ð¸Ð´Ñ–Ð»ÐµÐ½Ð½Ñ Ð²Ð³Ð¾Ñ€Ñƒ"
msgid "Move this issue to another project."
-msgstr "ПереміÑтити цю задачу до іншого проекту."
+msgstr "ПереміÑтити цю задачу до іншого проєкту."
msgid "MoveIssue|Cannot move issue due to insufficient permissions!"
msgstr "Ðеможливо переміÑтити задачу через недоÑтатній набір дозволів!"
msgid "MoveIssue|Cannot move issue to project it originates from!"
-msgstr "Ðеможливо перенеÑти задачу до проекту, в Ñкому вона знаходитьÑÑ!"
+msgstr "Ðеможливо перенеÑти задачу до проєкту, в Ñкому вона знаходитьÑÑ!"
msgid "Moved issue to %{label} column in the board."
msgstr "Переміщено задачу в колонку %{label} на дошці."
@@ -16429,7 +17030,7 @@ msgid "My Awesome Group"
msgstr ""
msgid "My company or team"
-msgstr ""
+msgstr "ÐœÐ¾Ñ ÐºÐ¾Ð¼Ð¿Ð°Ð½Ñ–Ñ Ð°Ð±Ð¾ команда"
msgid "My-Reaction"
msgstr ""
@@ -16444,7 +17045,7 @@ msgid "Name has already been taken"
msgstr "Ð†Ð¼â€™Ñ Ð²Ð¶Ðµ викориÑтовуєтьÑÑ"
msgid "Name is required"
-msgstr ""
+msgstr "Ð†Ð¼â€™Ñ Ð¾Ð±Ð¾Ð²Ê¼Ñзкове"
msgid "Name new label"
msgstr "Ðазвіть нову мітку"
@@ -16455,6 +17056,9 @@ msgstr "Ім’Ñ:"
msgid "Namespace"
msgstr "ПроÑÑ‚Ñ–Ñ€ імен"
+msgid "Namespace ID:"
+msgstr ""
+
msgid "Namespace is empty"
msgstr "ПроÑÑ‚Ñ–Ñ€ імен порожній"
@@ -16519,7 +17123,7 @@ msgid "NetworkPolicies|%{strongOpen}any%{strongClose} port"
msgstr ""
msgid "NetworkPolicies|.yaml"
-msgstr ""
+msgstr ".yaml"
msgid "NetworkPolicies|.yaml mode"
msgstr ""
@@ -16539,6 +17143,9 @@ msgstr ""
msgid "NetworkPolicies|Allow all outbound traffic from %{selector} to %{ruleSelector} on %{ports}"
msgstr ""
+msgid "NetworkPolicies|Are you sure you want to delete this policy? This action cannot be undone."
+msgstr ""
+
msgid "NetworkPolicies|Choose whether to enforce this policy."
msgstr ""
@@ -16548,12 +17155,21 @@ msgstr ""
msgid "NetworkPolicies|Define this policy's location, conditions and actions."
msgstr ""
+msgid "NetworkPolicies|Delete policy"
+msgstr ""
+
+msgid "NetworkPolicies|Delete policy: %{policy}"
+msgstr ""
+
msgid "NetworkPolicies|Deny all traffic"
msgstr ""
msgid "NetworkPolicies|Description"
msgstr ""
+msgid "NetworkPolicies|Edit policy"
+msgstr ""
+
msgid "NetworkPolicies|Editor mode"
msgstr ""
@@ -16581,6 +17197,9 @@ msgstr ""
msgid "NetworkPolicies|Name"
msgstr "Ðазва"
+msgid "NetworkPolicies|Namespace"
+msgstr ""
+
msgid "NetworkPolicies|Network Policy"
msgstr ""
@@ -16632,6 +17251,9 @@ msgstr ""
msgid "NetworkPolicies|Rules"
msgstr ""
+msgid "NetworkPolicies|Save changes"
+msgstr ""
+
msgid "NetworkPolicies|Something went wrong, failed to update policy"
msgstr ""
@@ -16644,6 +17266,9 @@ msgstr ""
msgid "NetworkPolicies|Traffic that does not match any rule will be blocked."
msgstr ""
+msgid "NetworkPolicies|Unable to parse policy"
+msgstr ""
+
msgid "NetworkPolicies|YAML editor"
msgstr ""
@@ -16759,6 +17384,9 @@ msgstr "Ðова вимога"
msgid "New Snippet"
msgstr "Ðовий Ñніпет"
+msgid "New Test Case"
+msgstr ""
+
msgid "New User"
msgstr "Ðовий КориÑтувач"
@@ -16814,7 +17442,7 @@ msgid "New iteration"
msgstr "Ðова ітераціÑ"
msgid "New iteration created"
-msgstr ""
+msgstr "Створено нову ітерацію"
msgid "New label"
msgstr "Ðова мітка"
@@ -16858,6 +17486,9 @@ msgstr "Ðова підгрупа"
msgid "New tag"
msgstr "Ðовий тег"
+msgid "New test case"
+msgstr ""
+
msgid "New users set to external"
msgstr "Ðові кориÑтувачі Ñ” \"зовнішні по замовчанню\""
@@ -16868,7 +17499,7 @@ msgid "New..."
msgstr "Ðовий..."
msgid "Newest first"
-msgstr ""
+msgstr "Спочатку нові"
msgid "Newly registered users will by default be external"
msgstr "За замовчуваннÑм щойно зареєÑтровані кориÑтувачі будуть зовнішніми кориÑтувачами"
@@ -16901,7 +17532,7 @@ msgid "No Epic"
msgstr "Ðемає епіка"
msgid "No Matching Results"
-msgstr ""
+msgstr "Ðемає відповідних результатів"
msgid "No Scopes"
msgstr ""
@@ -16930,8 +17561,8 @@ msgstr "Гілок не знайдено"
msgid "No changes"
msgstr "Ðемає змін"
-msgid "No changes between %{ref_start}%{source_branch}%{ref_end} and %{ref_start}%{target_branch}%{ref_end}"
-msgstr "Ðемає змін між %{ref_start}%{source_branch}%{ref_end} та %{ref_start}%{target_branch}%{ref_end}"
+msgid "No changes between %{sourceBranch} and %{targetBranch}"
+msgstr ""
msgid "No child epics match applied filters"
msgstr ""
@@ -16945,6 +17576,9 @@ msgstr "Ðеможливо з'єднатиÑÑŒ із Ñервером Gitaly, бÑ
msgid "No containers available"
msgstr ""
+msgid "No content to show"
+msgstr ""
+
msgid "No contributions"
msgstr "Ðемає внеÑків"
@@ -16994,16 +17628,16 @@ msgid "No forks are available to you."
msgstr ""
msgid "No grouping"
-msgstr ""
+msgstr "Без групуваннÑ"
msgid "No issues found"
-msgstr ""
+msgstr "Проблем не знайдено"
msgid "No iteration"
-msgstr ""
+msgstr "Ðемає ітерації"
msgid "No iterations to show"
-msgstr ""
+msgstr "Ðемає ітерацій Ð´Ð»Ñ Ð¿Ð¾ÐºÐ°Ð·Ñƒ"
msgid "No job log"
msgstr "Ðемає журналу завданнÑ"
@@ -17020,9 +17654,6 @@ msgstr "Ðемає міток з таким іменем або опиÑом"
msgid "No license. All rights reserved"
msgstr "Ðемає ліцензії. Ð’ÑÑ– права захищені"
-msgid "No licenses found."
-msgstr "Ðе знайдено ліцензій."
-
msgid "No matches found"
msgstr "Збігів не знайдено"
@@ -17035,6 +17666,9 @@ msgstr "Ðемає відповідних результатів"
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No members found"
+msgstr ""
+
msgid "No merge requests found"
msgstr "Ðе знайдено жодного запиту на злиттÑ"
@@ -17056,6 +17690,9 @@ msgstr ""
msgid "No parent group"
msgstr "Ðемає батьківÑької групи"
+msgid "No plan"
+msgstr ""
+
msgid "No pods available"
msgstr "Ðемає доÑтупних pod'ів"
@@ -17093,7 +17730,7 @@ msgid "No schedules"
msgstr "Ðемає розкладів"
msgid "No source selected"
-msgstr ""
+msgstr "Ðе вибрано джерело"
msgid "No stack trace for this error"
msgstr ""
@@ -17105,7 +17742,7 @@ msgid "No start date"
msgstr "Ðемає дати початку"
msgid "No status"
-msgstr ""
+msgstr "Ð¡Ñ‚Ð°Ñ‚ÑƒÑ Ð²Ñ–Ð´Ñутній"
msgid "No template"
msgstr "Шаблон відÑутній"
@@ -17152,6 +17789,12 @@ msgstr "Ðемає"
msgid "Not Implemented"
msgstr "Ðе реалізовано"
+msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+msgstr ""
+
+msgid "Not all browsers support WebAuthn. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even from an unsupported browser."
+msgstr ""
+
msgid "Not all data has been processed yet, the accuracy of the chart for the selected timeframe is limited."
msgstr "Ще не вÑÑ– дані оброблені, тому точніÑÑ‚ÑŒ графіку Ð´Ð»Ñ Ð²Ð¸Ð±Ñ€Ð°Ð½Ð¾Ð³Ð¾ чаÑового проміжку обмежена."
@@ -17159,7 +17802,7 @@ msgid "Not available"
msgstr "ÐедоÑтупний"
msgid "Not available for private projects"
-msgstr "ÐедоÑтупно Ð´Ð»Ñ Ð¿Ñ€Ð¸Ð²Ð°Ñ‚Ð½Ð¸Ñ… проектів"
+msgstr "ÐедоÑтупно Ð´Ð»Ñ Ð¿Ñ€Ð¸Ð²Ð°Ñ‚Ð½Ð¸Ñ… проєктів"
msgid "Not available for protected branches"
msgstr "ÐедоÑтупно Ð´Ð»Ñ Ð·Ð°Ñ…Ð¸Ñ‰ÐµÐ½Ð¸Ñ… гілок"
@@ -17234,7 +17877,7 @@ msgid "Nothing to preview."
msgstr "Дані Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÐ³Ð»Ñду відÑутні."
msgid "Nothing to synchronize"
-msgstr ""
+msgstr "Ðічого Ñинхронізувати"
msgid "Notification events"
msgstr "ÐŸÐ¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾ події"
@@ -17248,6 +17891,9 @@ msgstr "Параметр ÑÐ¿Ð¾Ð²Ñ–Ñ‰ÐµÐ½Ð½Ñ - %{notification_title}"
msgid "Notification settings saved"
msgstr "ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ñповіщень збережено"
+msgid "NotificationEvent|Change reviewer merge request"
+msgstr ""
+
msgid "NotificationEvent|Close issue"
msgstr "Задача закрита"
@@ -17315,7 +17961,7 @@ msgid "Notifications"
msgstr "СповіщеннÑ"
msgid "Notifications have been disabled by the project or group owner"
-msgstr "Ð¡Ð¿Ð¾Ð²Ñ–Ñ‰ÐµÐ½Ð½Ñ Ð±ÑƒÐ»Ð¾ вимкнено влаÑником проекту або групи"
+msgstr "Ð¡Ð¿Ð¾Ð²Ñ–Ñ‰ÐµÐ½Ð½Ñ Ð±ÑƒÐ»Ð¾ вимкнено влаÑником проєкту або групи"
msgid "Notifications off"
msgstr "Ð¡Ð¿Ð¾Ð²Ñ–Ñ‰ÐµÐ½Ð½Ñ Ð²Ð¸Ð¼ÐºÐ½ÐµÐ½Ð¾"
@@ -17366,7 +18012,7 @@ msgid "Number of employees"
msgstr "КількіÑÑ‚ÑŒ Ñпівробітників"
msgid "Number of events"
-msgstr ""
+msgstr "КількіÑÑ‚ÑŒ подій"
msgid "Number of events for this project: %{total_count}."
msgstr ""
@@ -17399,7 +18045,7 @@ msgid "Oh no!"
msgstr "О ні!"
msgid "Oldest first"
-msgstr ""
+msgstr "Спочатку Ñтарі"
msgid "OmniAuth"
msgstr "OmniAuth"
@@ -17410,10 +18056,7 @@ msgstr ""
msgid "On track"
msgstr ""
-msgid "OnDemandScans|Attached branch"
-msgstr ""
-
-msgid "OnDemandScans|Attached branch is where the scan job runs."
+msgid "OnDemandScans|Could not fetch scanner profiles. Please refresh the page, or try again later."
msgstr ""
msgid "OnDemandScans|Could not fetch site profiles. Please refresh the page, or try again later."
@@ -17422,6 +18065,9 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
+msgid "OnDemandScans|Create a new scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Create a new site profile"
msgstr ""
@@ -17434,6 +18080,9 @@ msgstr ""
msgid "OnDemandScans|New on-demand DAST scan"
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 ""
@@ -17443,16 +18092,10 @@ msgstr ""
msgid "OnDemandScans|On-demand scans run outside the DevOps cycle and find vulnerabilities in your projects. %{learnMoreLinkStart}Learn more%{learnMoreLinkEnd}"
msgstr ""
-msgid "OnDemandScans|Only a passive scan can be performed on demand."
-msgstr ""
-
-msgid "OnDemandScans|Passive"
-msgstr ""
-
msgid "OnDemandScans|Run scan"
msgstr ""
-msgid "OnDemandScans|Scan mode"
+msgid "OnDemandScans|Scanner profile"
msgstr ""
msgid "OnDemandScans|Scanner settings"
@@ -17464,9 +18107,15 @@ msgstr ""
msgid "OnDemandScans|Select one of the existing profiles"
msgstr ""
+msgid "OnDemandScans|Site profile"
+msgstr ""
+
msgid "OnDemandScans|Site profiles"
msgstr ""
+msgid "OnDemandScans|Use existing scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Use existing site profile"
msgstr ""
@@ -17480,7 +18129,7 @@ msgid "Once imported, repositories can be mirrored over SSH. Read more %{link_st
msgstr "ПіÑÐ»Ñ Ñ–Ð¼Ð¿Ð¾Ñ€Ñ‚Ñƒ, репозиторії можуть бути віддзеркалені через SSH. ДізнайтеÑÑ Ð±Ñ–Ð»ÑŒÑˆÐµ %{link_start}тут%{link_end}."
msgid "Once removed, the fork relationship cannot be restored and you will no longer be able to send merge requests to the source."
-msgstr "ПіÑÐ»Ñ Ð²Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ Ð·Ð²â€™Ñзок форку не може бути відновлений Ñ– ви більше не зможете відправлÑти запити на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ñƒ вихідний проект."
+msgstr "ПіÑÐ»Ñ Ð²Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ Ð·Ð²â€™Ñзок форку не може бути відновлений Ñ– ви більше не зможете відправлÑти запити на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ñƒ вихідний проєкт."
msgid "Once the exported file is ready, you will receive a notification email with a download link, or you can download it from this page."
msgstr "ПіÑÐ»Ñ Ñ‚Ð¾Ð³Ð¾, Ñк екÑпортований файл буде готовий, ви отримаєте ÑÐ¿Ð¾Ð²Ñ–Ñ‰ÐµÐ½Ð½Ñ ÐµÐ»ÐµÐºÑ‚Ñ€Ð¾Ð½Ð½Ð¾ÑŽ поштою із поÑиланнÑм Ð´Ð»Ñ Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ Ð°Ð±Ð¾ можете завантажити його з цієї Ñторінки."
@@ -17505,7 +18154,7 @@ msgid "One or more of your %{provider} projects cannot be imported into GitLab d
msgstr ""
msgid "One or more of your Google Code projects cannot be imported into GitLab directly because they use Subversion or Mercurial for version control, rather than Git."
-msgstr "Один або декілька ваших проектів Google Code не можна імпортувати безпоÑередньо в GitLab, оÑкільки вони викориÑтовують Subversion або Mercurial Ð´Ð»Ñ ÐºÐ¾Ð½Ñ‚Ñ€Ð¾Ð»ÑŽ верÑій заміÑÑ‚ÑŒ Git."
+msgstr "Один або декілька ваших проєктів Google Code не можна імпортувати безпоÑередньо в GitLab, оÑкільки вони викориÑтовують Subversion або Mercurial Ð´Ð»Ñ ÐºÐ¾Ð½Ñ‚Ñ€Ð¾Ð»ÑŽ верÑій заміÑÑ‚ÑŒ Git."
msgid "One or more of your dependency files are not supported, and the dependency list may be incomplete. Below is a list of supported file types."
msgstr "Один або кілька з ваших файлів залежноÑтей не підтримуютьÑÑ, тому ÑпиÑок залежноÑтей може бути неповним. Ðижче наведено ÑпиÑок підтримуваних типів файлі."
@@ -17526,13 +18175,13 @@ msgid "Only Issue ID or Merge Request ID is required"
msgstr ""
msgid "Only Project Members"
-msgstr "Тільки учаÑники проекту"
+msgstr "Тільки учаÑники проєкту"
msgid "Only active this projects shows up in the search and on the dashboard."
msgstr ""
msgid "Only admins can delete project"
-msgstr "Тільки адмініÑтратори можуть видалÑти проект"
+msgstr "Тільки адмініÑтратори можуть видалÑти проєкт"
msgid "Only mirror protected branches"
msgstr "Віддзеркалювати лише захищені гілки"
@@ -17544,10 +18193,10 @@ msgid "Only proceed if you trust %{idp_url} to control your GitLab account sign
msgstr "Продовжуйте тільки Ñкщо ви довірÑєте %{idp_url} контроль над входом до вашого облікового запиÑу GitLab."
msgid "Only project members can comment."
-msgstr "Тільки учаÑники проекту можуть залишати коментарі."
+msgstr "Тільки учаÑники проєкту можуть залишати коментарі."
msgid "Only project members will be imported. Group members will be skipped."
-msgstr "Лише учаÑника проекту будуть імпортовані. УчаÑники групи будуть пропущені."
+msgstr "Лише учаÑника проєкту будуть імпортовані. УчаÑники групи будуть пропущені."
msgid "Only projects created under a Gold license are available in Security Dashboards."
msgstr ""
@@ -17567,9 +18216,6 @@ msgstr "Відкриті"
msgid "Open Selection"
msgstr "Відкрити виділеннÑ"
-msgid "Open Web IDE"
-msgstr ""
-
msgid "Open comment type dropdown"
msgstr "Випадаючий ÑпиÑок типу коментарів"
@@ -17583,13 +18229,13 @@ msgid "Open in Xcode"
msgstr "Відкрити в Xcode"
msgid "Open in file view"
-msgstr ""
+msgstr "Відкрити файл Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÐ³Ð»Ñду"
msgid "Open issues"
msgstr "Відкриті задачі"
msgid "Open projects"
-msgstr "Відкриті проекти"
+msgstr "Відкриті проєкти"
msgid "Open raw"
msgstr "Відкрити в неформатованому виглÑді"
@@ -17610,7 +18256,7 @@ msgid "Opened %{epicTimeagoDate}"
msgstr ""
msgid "Opened MRs"
-msgstr ""
+msgstr "Відкриті запити на злиттÑ"
msgid "Opened issues"
msgstr "Відкриті задачі"
@@ -17640,10 +18286,10 @@ msgid "Operations Settings"
msgstr "ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð¾Ð¿ÐµÑ€Ð°Ñ†Ñ–Ð¹"
msgid "OperationsDashboard|Add a project to the dashboard"
-msgstr "Додайте проект до панелі керуваннÑ"
+msgstr "Додайте проєкт до панелі керуваннÑ"
msgid "OperationsDashboard|Add projects"
-msgstr "Додати проекти"
+msgstr "Додати проєкти"
msgid "OperationsDashboard|More information"
msgstr "Детальніше"
@@ -17652,7 +18298,7 @@ msgid "OperationsDashboard|Operations Dashboard"
msgstr "Панель ÐºÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð¾Ð¿ÐµÑ€Ð°Ñ†Ñ–Ñми"
msgid "OperationsDashboard|The operations dashboard provides a summary of each project's operational health, including pipeline and alert statuses."
-msgstr "Панель ÐºÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð¾Ð¿ÐµÑ€Ð°Ñ†Ñ–Ñми міÑтить інформацію про Ñтан кожного з проектів разом зі Ñтаном його конвеєрів та попереджень."
+msgstr "Панель ÐºÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð¾Ð¿ÐµÑ€Ð°Ñ†Ñ–Ñми міÑтить інформацію про Ñтан кожного з проєктів разом зі Ñтаном його конвеєрів та попереджень."
msgid "Optional"
msgstr "Ðеобов'Ñзково"
@@ -17675,6 +18321,9 @@ msgstr "Ðбо ви можете вибрати один із запропоно
msgid "Origin"
msgstr "Джерело"
+msgid "Orphaned member"
+msgstr ""
+
msgid "Other Labels"
msgstr "Інші мітки"
@@ -17685,11 +18334,14 @@ msgid "Other merge requests block this MR"
msgstr "Інші запити на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð±Ð»Ð¾ÐºÑƒÑŽÑ‚ÑŒ цей"
msgid "Other versions"
-msgstr ""
+msgstr "Інші верÑÑ–Ñ—"
msgid "Other visibility settings have been disabled by the administrator."
msgstr "Інші Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð²Ð¸Ð´Ð¸Ð¼Ð¾ÑÑ‚Ñ– були вимкнені адмініÑтратором."
+msgid "Our documentation includes an example DevOps Score report."
+msgstr ""
+
msgid "Out-of-compliance with this project's policies and should be removed"
msgstr ""
@@ -17714,6 +18366,9 @@ msgstr "ОглÑд"
msgid "Overwrite diverged branches"
msgstr "ПерезапиÑати розбіжні гілки"
+msgid "Owned by %{image_tag}"
+msgstr ""
+
msgid "Owned by anyone"
msgstr "Ðалежить уÑім"
@@ -17735,6 +18390,9 @@ msgstr ""
msgid "Package deleted successfully"
msgstr "Пакет уÑпішно видалено"
+msgid "Package file size limits"
+msgstr ""
+
msgid "Package recipe already exists"
msgstr ""
@@ -17750,9 +18408,6 @@ msgstr ""
msgid "Package type must be PyPi"
msgstr ""
-msgid "Package was removed"
-msgstr "Пакет був видалений"
-
msgid "PackageRegistry|%{name} version %{version} was created %{datetime}"
msgstr ""
@@ -17894,12 +18549,18 @@ msgstr "NuGet"
msgid "PackageRegistry|NuGet Command"
msgstr "Команда NNGet"
+msgid "PackageRegistry|Package Registry"
+msgstr ""
+
msgid "PackageRegistry|Pip Command"
msgstr "Команда pip"
msgid "PackageRegistry|Pipeline %{link} triggered %{datetime} by %{author}"
msgstr ""
+msgid "PackageRegistry|Publish and share packages for a variety of common package managers. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "PackageRegistry|Published to the %{project} Package Registry %{datetime}"
msgstr ""
@@ -17999,6 +18660,9 @@ msgstr "Пакети та реєÑтри"
msgid "Page not found"
msgstr "Сторінку не знайдено"
+msgid "Page settings"
+msgstr ""
+
msgid "Page was successfully deleted"
msgstr "Сторінку було уÑпішно видалено"
@@ -18140,11 +18804,11 @@ msgstr "Ð’Ñтавити поÑÐ¸Ð»Ð°Ð½Ð½Ñ Ð½Ð° епік"
msgid "Paste issue link"
msgstr "Ð’Ñтавити поÑÐ¸Ð»Ð°Ð½Ð½Ñ Ð½Ð° задачу"
-msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Don't use your private SSH key."
-msgstr "Ð’Ñтавте Ñвій публічний ключ SSH, Ñкий зазвичай знаходитьÑÑ Ñƒ файлі \"~/.ssh/id_ed25519.pub\" або \"~/.ssh/id_rsa.pub\" Ñ– починаєтьÑÑ Ñ–Ð· \"ssh-ed25519\" або \"ssh-rsa\". Ðе викориÑтовуйте Ñвій приватний ключ."
+msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Do not paste your private SSH key, as that can compromise your identity."
+msgstr ""
msgid "Patch to apply"
-msgstr ""
+msgstr "Патч Ð´Ð»Ñ Ð·Ð°ÑтоÑуваннÑ"
msgid "Path"
msgstr "ШлÑÑ…"
@@ -18167,6 +18831,9 @@ msgstr "Призупинені Runner'и не приймають нові зав
msgid "Pending"
msgstr "В очікуванні"
+msgid "Pending comments"
+msgstr ""
+
msgid "People without permission will never get a notification and won't be able to comment."
msgstr "Люди без дозволу ніколи не отримуватимуть Ñповіщень Ñ– не зможуть коментувати."
@@ -18174,7 +18841,7 @@ msgid "People without permission will never get a notification."
msgstr "Люди без дозволу ніколи не отримуватимуть Ñповіщень."
msgid "Percent of users"
-msgstr ""
+msgstr "ВідÑоток кориÑтувачів"
msgid "Percentage"
msgstr "ВідÑоток"
@@ -18183,7 +18850,7 @@ msgid "Perform advanced options such as changing path, transferring, exporting,
msgstr ""
msgid "Perform common operations on GitLab project"
-msgstr "Виконати звичайні операції на проекті GitLab"
+msgstr "Виконати звичайні операції на проєкті GitLab"
msgid "Performance and resource management"
msgstr ""
@@ -18222,7 +18889,7 @@ msgid "Permissions"
msgstr "Права доÑтупу"
msgid "Permissions Help"
-msgstr ""
+msgstr "Довідка щодо дозволів"
msgid "Permissions, LFS, 2FA"
msgstr "Дозволи, LFS, 2FA"
@@ -18231,7 +18898,7 @@ msgid "Personal Access Token"
msgstr "Токену перÑонального доÑтупу"
msgid "Personal project creation is not allowed. Please contact your administrator with questions"
-msgstr "Ð¡Ñ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð¿ÐµÑ€Ñональних проектів не дозволено. Будь лаÑка, звернітьÑÑ Ð´Ð¾ Ñвого адмініÑтратор із питаннÑми"
+msgstr "Ð¡Ñ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð¿ÐµÑ€Ñональних проєктів не дозволено. Будь лаÑка, звернітьÑÑ Ð´Ð¾ Ñвого адмініÑтратор із питаннÑми"
msgid "Phabricator Server Import"
msgstr "Ð†Ð¼Ð¿Ð¾Ñ€Ñ‚ÑƒÐ²Ð°Ñ‚Ñ‚Ñ Ñ–Ð· Ñерверу Phabricator"
@@ -18365,6 +19032,9 @@ msgstr ""
msgid "Pipelines|Build with confidence"
msgstr "Виконуйте збірки із впевненіÑÑ‚ÑŽ"
+msgid "Pipelines|By revoking a trigger you will break any processes making use of it. Are you sure?"
+msgstr ""
+
msgid "Pipelines|CI Lint"
msgstr "Перевірка конфігурації (CI Lint)"
@@ -18377,6 +19047,15 @@ msgstr "ОчиÑтити кеш Runner'ів"
msgid "Pipelines|Continuous Integration can help catch bugs by running your tests automatically, while Continuous Deployment can help you deliver code to your product environment."
msgstr "Безперервна Ñ–Ð½Ñ‚ÐµÐ³Ñ€Ð°Ñ†Ñ–Ñ Ð´Ð¾Ð¿Ð¾Ð¼Ð°Ð³Ð°Ñ” знаходити помилки шлÑхом автоматичного запуÑку теÑтів, а безперервне Ñ€Ð¾Ð·Ð³Ð¾Ñ€Ñ‚Ð°Ð½Ð½Ñ â€” вÑтановлювати код на цільове Ñередовище."
+msgid "Pipelines|Copy trigger token"
+msgstr ""
+
+msgid "Pipelines|Description"
+msgstr ""
+
+msgid "Pipelines|Edit"
+msgstr ""
+
msgid "Pipelines|Get started with Pipelines"
msgstr "Розпочати роботу з Конвеєрами"
@@ -18392,14 +19071,26 @@ msgstr ""
msgid "Pipelines|It is recommended the code is reviewed thoroughly before running this pipeline with the parent project's CI resource."
msgstr ""
+msgid "Pipelines|Last Used"
+msgstr ""
+
msgid "Pipelines|Loading Pipelines"
msgstr "Ð—Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ ÐºÐ¾Ð½Ð²ÐµÑ”Ñ€Ñ–Ð²"
msgid "Pipelines|More Information"
msgstr ""
+msgid "Pipelines|No triggers have been created yet. Add one using the form above."
+msgstr ""
+
+msgid "Pipelines|Owner"
+msgstr ""
+
msgid "Pipelines|Project cache successfully reset."
-msgstr "Кеш проекту уÑпішно очищено."
+msgstr "Кеш проєкту уÑпішно очищено."
+
+msgid "Pipelines|Revoke"
+msgstr ""
msgid "Pipelines|Run Pipeline"
msgstr "ЗапуÑтити Конвеєр"
@@ -18423,7 +19114,16 @@ msgid "Pipelines|This pipeline will run code originating from a forked project m
msgstr ""
msgid "Pipelines|This project is not currently set up to run pipelines."
-msgstr "Цей проект в даний Ñ‡Ð°Ñ Ð½Ðµ налаштований Ð´Ð»Ñ Ð·Ð°Ð¿ÑƒÑку конвеєрів."
+msgstr "Цей проєкт в даний Ñ‡Ð°Ñ Ð½Ðµ налаштований Ð´Ð»Ñ Ð·Ð°Ð¿ÑƒÑку конвеєрів."
+
+msgid "Pipelines|Token"
+msgstr ""
+
+msgid "Pipelines|Trigger user has insufficient permissions to project"
+msgstr ""
+
+msgid "Pipelines|invalid"
+msgstr ""
msgid "Pipelines|parent"
msgstr ""
@@ -18561,16 +19261,16 @@ msgid "PivotalTrackerService|Pivotal Tracker API token."
msgstr "API токен Pivotal Tracker."
msgid "PivotalTrackerService|Project Management Software (Source Commits Endpoint)"
-msgstr "Програмне Ð·Ð°Ð±ÐµÐ·Ð¿ÐµÑ‡ÐµÐ½Ð½Ñ Ð´Ð»Ñ ÐºÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð¿Ñ€Ð¾ÐµÐºÑ‚Ð°Ð¼Ð¸ (кінцева точка Ð´Ð»Ñ ÐºÐ¾Ð¼Ñ–Ñ‚Ñ–Ð²)"
+msgstr "Програмне Ð·Ð°Ð±ÐµÐ·Ð¿ÐµÑ‡ÐµÐ½Ð½Ñ Ð´Ð»Ñ ÐºÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð¿Ñ€Ð¾Ñ”ÐºÑ‚Ð°Ð¼Ð¸ (кінцева точка Ð´Ð»Ñ ÐºÐ¾Ð¼Ñ–Ñ‚Ñ–Ð²)"
msgid "Plain diff"
msgstr "ПроÑте порівнÑннÑ"
msgid "Plan"
-msgstr ""
+msgstr "План"
msgid "Plan:"
-msgstr ""
+msgstr "План:"
msgid "PlantUML"
msgstr "PlantUML"
@@ -18648,7 +19348,7 @@ msgid "Please enter a non-negative number"
msgstr "Будь лаÑка, введіть невід'ємне чиÑло"
msgid "Please enter a number greater than %{number} (from the project settings)"
-msgstr "Будь лаÑка, введіть чиÑло більше за %{number} (із налаштувань проекту)"
+msgstr "Будь лаÑка, введіть чиÑло більше за %{number} (із налаштувань проєкту)"
msgid "Please enter a valid number"
msgstr "Будь лаÑка, введіть дійÑний номер"
@@ -18666,7 +19366,7 @@ msgid "Please follow the Let's Encrypt troubleshooting instructions to re-obtain
msgstr ""
msgid "Please migrate all existing projects to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}"
-msgstr "Будь лаÑка, мігруйте вÑÑ– уÑнуючі проекти на хешоване Ñховище, щоб уникнути проблем із безпекою та забезпечити ціліÑніÑÑ‚ÑŒ даних. %{migrate_link}"
+msgstr "Будь лаÑка, мігруйте вÑÑ– уÑнуючі проєкти на хешоване Ñховище, щоб уникнути проблем із безпекою та забезпечити ціліÑніÑÑ‚ÑŒ даних. %{migrate_link}"
msgid "Please note that this application is not provided by GitLab and you should verify its authenticity before allowing access."
msgstr "Зверніть увагу, що Ñ†Ñ Ð¿Ñ€Ð¾Ð³Ñ€Ð°Ð¼Ð° не Ñ” чаÑтиною GitLab, Ñ– ви повинні впевнитиÑÑ Ñƒ Ñ—Ñ— безпеці, перш ніж надавати доÑтуп."
@@ -18683,11 +19383,11 @@ msgstr "Будь лаÑка, вкажіть дійÑну e-mail адреÑу."
msgid "Please provide attributes to update"
msgstr ""
-msgid "Please refer to %{docs_url}"
+msgid "Please reach out if you have any questions and we'll be happy to assist."
msgstr ""
-msgid "Please retype the email address."
-msgstr "Будь лаÑка, повторно введіть адреÑу електронної пошти."
+msgid "Please refer to %{docs_url}"
+msgstr ""
msgid "Please select"
msgstr "Будь лаÑка, виберіть"
@@ -18716,6 +19416,9 @@ msgstr "Будь лаÑка виберіть хоча б один фільтр,
msgid "Please set a new password before proceeding."
msgstr "Будь лаÑка, вÑтановіть пароль перед продовженнÑм."
+msgid "Please share your feedback about %{featureName} %{linkStart}in this issue%{linkEnd} to help us improve the experience."
+msgstr ""
+
msgid "Please solve the reCAPTCHA"
msgstr "Будь лаÑка, пройдіть reCAPTCHA"
@@ -18771,7 +19474,7 @@ msgid "Preferences|Choose between fixed (max. 1280px) and fluid (%{percentage})
msgstr "Оберіть між фікÑованим (макÑ. 1280 пікÑ.) та адаптивним (%{percentage}) макетом."
msgid "Preferences|Choose what content you want to see on a project’s overview page."
-msgstr "Вибрати вміÑÑ‚ оглÑдової Ñторінки проекту."
+msgstr "Вибрати вміÑÑ‚ оглÑдової Ñторінки проєкту."
msgid "Preferences|Choose what content you want to see on your homepage."
msgstr ""
@@ -18810,7 +19513,7 @@ msgid "Preferences|Navigation theme"
msgstr "Тема навігації"
msgid "Preferences|Project overview content"
-msgstr "ВміÑÑ‚ оглÑдової Ñторінки проекту"
+msgstr "ВміÑÑ‚ оглÑдової Ñторінки проєкту"
msgid "Preferences|Render whitespace characters in the Web IDE"
msgstr "Візуалізувати пробіли в веб-IDE"
@@ -18858,7 +19561,7 @@ msgid "Press %{key}-C to copy"
msgstr "ÐатиÑніть %{key}-C, щоб Ñкопіювати"
msgid "Prev"
-msgstr ""
+msgstr "Ðазад"
msgid "Prevent adding new members to project membership within this group"
msgstr "Заборонити Ð´Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ð½Ð¾Ð²Ð¸Ñ… учаÑників до членÑтва в цій групі"
@@ -18930,7 +19633,7 @@ msgid "Private - Project access must be granted explicitly to each user. If this
msgstr ""
msgid "Private - The group and its projects can only be viewed by members."
-msgstr "Приватна — цю групу та Ñ—Ñ— проекти можуть бачити тільки Ñ—Ñ— кориÑтувачі."
+msgstr "Приватна — цю групу та Ñ—Ñ— проєкти можуть бачити тільки Ñ—Ñ— кориÑтувачі."
msgid "Private group(s)"
msgstr "Приватна група(и)"
@@ -18942,7 +19645,7 @@ msgid "Private projects Minutes cost factor"
msgstr ""
msgid "Private projects can be created in your personal namespace with:"
-msgstr "Приватні проекти можуть бути Ñтворені у вашому перÑональному проÑторі імен з:"
+msgstr "Приватні проєкти можуть бути Ñтворені у вашому перÑональному проÑторі імен з:"
msgid "Proceed"
msgstr "Продовжити"
@@ -19017,7 +19720,10 @@ msgid "Profiles| You are about to permanently delete %{yourAccount}, and all of
msgstr "Ви збираєтеÑÑ Ð¾Ñтаточно видалити %{yourAccount}, а також вÑÑ– задачі, запити на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ñ‚Ð° групи, пов'Ñзані з вашим обліковим запиÑом. ПіÑÐ»Ñ Ð¿Ñ–Ð´Ñ‚Ð²ÐµÑ€Ð´Ð¶ÐµÐ½Ð½Ñ %{deleteAccount}, його неможливо буде відновити."
msgid "Profiles| You are going to change the username %{currentUsernameBold} to %{newUsernameBold}. Profile and projects will be redirected to the %{newUsername} namespace but this redirect will expire once the %{currentUsername} namespace is registered by another user or group. Please update your Git repository remotes as soon as possible."
-msgstr "Ви збираєтеÑÑ Ð·Ð¼Ñ–Ð½Ð¸Ñ‚Ð¸ ім'Ñ ÐºÐ¾Ñ€Ð¸Ñтувача %{currentUsernameBold} на %{newUsernameBold}. Профіль та проекти будуть перенаправлÑтиÑÑ Ð½Ð° проÑÑ‚Ñ–Ñ€ імен %{newUsername}, але таке Ð¿ÐµÑ€ÐµÐ½Ð°Ð¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð½Ñ Ð·Ð°ÐºÑ–Ð½Ñ‡Ð¸Ñ‚ÑŒÑÑ, коли проÑÑ‚Ñ–Ñ€ імен %{currentUsername} буде зареєÑтровано на іншого кориÑтувача або групу. Будь лаÑка, оновіть віддалені адреÑи в репозиторіÑÑ… Git Ñкомога швидше."
+msgstr "Ви збираєтеÑÑ Ð·Ð¼Ñ–Ð½Ð¸Ñ‚Ð¸ ім'Ñ ÐºÐ¾Ñ€Ð¸Ñтувача %{currentUsernameBold} на %{newUsernameBold}. Профіль та проєкти будуть перенаправлÑтиÑÑ Ð½Ð° проÑÑ‚Ñ–Ñ€ імен %{newUsername}, але таке Ð¿ÐµÑ€ÐµÐ½Ð°Ð¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð½Ñ Ð·Ð°ÐºÑ–Ð½Ñ‡Ð¸Ñ‚ÑŒÑÑ, коли проÑÑ‚Ñ–Ñ€ імен %{currentUsername} буде зареєÑтровано на іншого кориÑтувача або групу. Будь лаÑка, оновіть віддалені адреÑи в репозиторіÑÑ… Git Ñкомога швидше."
+
+msgid "Profiles|%{provider} Active"
+msgstr ""
msgid "Profiles|@username"
msgstr "@ім'Ñ ÐºÐ¾Ñ€Ð¸Ñтувача"
@@ -19056,7 +19762,7 @@ msgid "Profiles|Choose file..."
msgstr "Вибрати файл..."
msgid "Profiles|Choose to show contributions of private projects on your public profile without any project, repository or organization information"
-msgstr "Виберіть Ð´Ð»Ñ Ð¿Ð¾ÐºÐ°Ð·Ñƒ внеÑків до приватних репозиторіїв у вашому публічному профілі без інформації про проекти, репозиторії або організації"
+msgstr "Виберіть Ð´Ð»Ñ Ð¿Ð¾ÐºÐ°Ð·Ñƒ внеÑків до приватних репозиторіїв у вашому публічному профілі без інформації про проєкти, репозиторії або організації"
msgid "Profiles|City, country"
msgstr "МіÑто, країна"
@@ -19070,8 +19776,8 @@ msgstr "Клікніть на іконку, щоб активувати вхід
msgid "Profiles|Commit email"
msgstr "ÐдреÑа електронної пошти Ð´Ð»Ñ ÐºÐ¾Ð¼Ñ–Ñ‚Ñ–Ð²"
-msgid "Profiles|Connect"
-msgstr "Приєднати"
+msgid "Profiles|Connect %{provider}"
+msgstr ""
msgid "Profiles|Connected Accounts"
msgstr "Підключені облікові запиÑи"
@@ -19094,6 +19800,9 @@ msgstr "Ð’Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ Ð¾Ð±Ð»Ñ–ÐºÐ¾Ð²Ð¾Ð³Ð¾ запиÑу неÑе наÑту
msgid "Profiles|Disconnect"
msgstr "Від'єднати"
+msgid "Profiles|Disconnect %{provider}"
+msgstr ""
+
msgid "Profiles|Do not show on profile"
msgstr "Ðе відображати у профілі"
@@ -19118,7 +19827,7 @@ msgstr "Токен доÑтупу до каналів уÑпішно перегÐ
msgid "Profiles|Full name"
msgstr "Повне ім'Ñ"
-msgid "Profiles|Give your individual key a title. This will be publically visible."
+msgid "Profiles|Give your individual key a title."
msgstr ""
msgid "Profiles|Include private contributions on my profile"
@@ -19208,8 +19917,8 @@ msgstr ""
msgid "Profiles|The maximum file size allowed is 200KB."
msgstr "МакÑимальний розмір файлу 200КБ."
-msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it?"
-msgstr "Це не Ñхоже на публічниц ключ SSH. Ви впевнені, що хочете його додати?"
+msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it? It will be publicly visible."
+msgstr ""
msgid "Profiles|This email will be displayed on your public profile"
msgstr "Ð¦Ñ ÐµÐ»ÐµÐºÑ‚Ñ€Ð¾Ð½Ð½Ð° адреÑа буде відображатиÑÑ Ñƒ вашому публічному профілі"
@@ -19283,6 +19992,9 @@ msgstr "Тут ви можете завантажити Ñвій аватар а
msgid "Profiles|You don't have access to delete this user."
msgstr "У Ð²Ð°Ñ Ð½ÐµÐ¼Ð°Ñ” доÑтупу Ð´Ð»Ñ Ð²Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ Ñ†ÑŒÐ¾Ð³Ð¾ кориÑтувача."
+msgid "Profiles|You must transfer ownership or delete groups you are an owner of before you can delete your account"
+msgstr ""
+
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr "Вам необхідно змінити влаÑника або видалити ці групи перед тим Ñк видалити ваш обліковий запиÑ."
@@ -19335,7 +20047,7 @@ msgid "Project"
msgstr "Проект"
msgid "Project \"%{name}\" is no longer available. Select another project to continue."
-msgstr "Проект \"%{name}\" більше не доÑтупний. Щоб продовжити виберіть інший проект."
+msgstr "Проект \"%{name}\" більше не доÑтупний. Щоб продовжити виберіть інший проєкт."
msgid "Project %{project_repo} could not be found"
msgstr "Проект %{project_repo} не знайдено"
@@ -19371,16 +20083,16 @@ msgid "Project Audit Events"
msgstr "Проєктні події аудиту"
msgid "Project Badges"
-msgstr "Значки проекту"
+msgstr "Значки проєкту"
msgid "Project Files"
-msgstr "Файли проекту"
+msgstr "Файли проєкту"
msgid "Project ID"
-msgstr "Ідентифікатор проекту"
+msgstr "Ідентифікатор проєкту"
msgid "Project URL"
-msgstr "URL-адреÑа проекту"
+msgstr "URL-адреÑа проєкту"
msgid "Project access must be granted explicitly to each user. If this project is part of a group, access will be granted to members of the group."
msgstr ""
@@ -19389,37 +20101,37 @@ msgid "Project already deleted"
msgstr "Проєкт уже було видалено"
msgid "Project and wiki repositories"
-msgstr "Репозиторії проекту та вікі"
+msgstr "Репозиторії проєкту та вікі"
msgid "Project avatar"
-msgstr "Ðватар проекту"
+msgstr "Ðватар проєкту"
msgid "Project cannot be shared with the group it is in or one of its ancestors."
msgstr "Проект не може бути Ñпільним із групою в Ñку він входить або з одним з Ñ—Ñ— предків."
msgid "Project clone URL"
-msgstr ""
+msgstr "URL Ð´Ð»Ñ ÐºÐ»Ð¾Ð½ÑƒÐ²Ð°Ð½Ð½Ñ Ð¿Ñ€Ð¾Ñ”ÐºÑ‚Ñƒ"
msgid "Project configuration, excluding integrations"
msgstr ""
msgid "Project description (optional)"
-msgstr "ÐžÐ¿Ð¸Ñ Ð¿Ñ€Ð¾ÐµÐºÑ‚Ñƒ (необов'Ñзково)"
+msgstr "ÐžÐ¿Ð¸Ñ Ð¿Ñ€Ð¾Ñ”ÐºÑ‚Ñƒ (необов'Ñзково)"
msgid "Project details"
-msgstr "Деталі проекту"
+msgstr "Деталі проєкту"
msgid "Project does not exist or you don't have permission to perform this action"
msgstr "Проєкт не Ñ–Ñнує або ви не маєте прав на Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ Ñ†Ñ–Ñ”Ñ— дії"
msgid "Project export could not be deleted."
-msgstr "Ðеможливо видалити екÑпорт проекту."
+msgstr "Ðеможливо видалити екÑпорт проєкту."
msgid "Project export enabled"
-msgstr "ЕкÑпорт проекту ввімкнено"
+msgstr "ЕкÑпорт проєкту ввімкнено"
msgid "Project export has been deleted."
-msgstr "ЕкÑпорт проекту видалений."
+msgstr "ЕкÑпорт проєкту видалений."
msgid "Project export link has expired. Please generate a new export from your project settings."
msgstr "ЗакінчивÑÑ Ñ‚ÐµÑ€Ð¼Ñ–Ð½ дії поÑÐ¸Ð»Ð°Ð½Ð½Ñ Ð½Ð° проєкт. Створіть новий екÑпорт в ваших налаштуваннÑÑ… проєкту."
@@ -19428,22 +20140,22 @@ msgid "Project export started. A download link will be sent by email and made av
msgstr ""
msgid "Project has too many %{label_for_message} to search"
-msgstr "Ð’ проекті занадто багато %{label_for_message} Ð´Ð»Ñ Ð¿Ð¾ÑˆÑƒÐºÑƒ"
+msgstr "Ð’ проєкті занадто багато %{label_for_message} Ð´Ð»Ñ Ð¿Ð¾ÑˆÑƒÐºÑƒ"
msgid "Project info:"
-msgstr ""
+msgstr "Ð†Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ñ–Ñ Ð¿Ñ€Ð¾ проєкт:"
msgid "Project is required when cluster_type is :project"
msgstr ""
msgid "Project members"
-msgstr "УчаÑники проекту"
+msgstr "УчаÑники проєкту"
msgid "Project milestone"
msgstr ""
msgid "Project name"
-msgstr "Ðазва проекту"
+msgstr "Ðазва проєкту"
msgid "Project name suffix"
msgstr "Ð¡ÑƒÑ„Ñ–ÐºÑ Ð½Ð°Ð·Ð²Ð¸ проєкту"
@@ -19455,10 +20167,10 @@ msgid "Project order will not be saved as local storage is not available."
msgstr "ПорÑдок проєктів не буде збережено, тому що локальне Ñховище недоÑтупне."
msgid "Project overview"
-msgstr "ОглÑд проекту"
+msgstr "ОглÑд проєкту"
msgid "Project path"
-msgstr "ШлÑÑ… до проекту"
+msgstr "ШлÑÑ… до проєкту"
msgid "Project scanning help page"
msgstr ""
@@ -19470,13 +20182,13 @@ msgid "Project security status help page"
msgstr ""
msgid "Project slug"
-msgstr "ШлÑÑ… проекту"
+msgstr "ШлÑÑ… проєкту"
msgid "Project uploads"
-msgstr "Ð—Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾ÐµÐºÑ‚Ñƒ"
+msgstr "Ð—Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾Ñ”ÐºÑ‚Ñƒ"
msgid "Project visibility level will be changed to match namespace rules when transferring to a group."
-msgstr "Рівень видимоÑÑ‚Ñ– проекту буде змінено відповідно до правил проÑтору імен під Ñ‡Ð°Ñ Ð¿ÐµÑ€ÐµÐ½ÐµÑÐµÐ½Ð½Ñ Ð´Ð¾ групи."
+msgstr "Рівень видимоÑÑ‚Ñ– проєкту буде змінено відповідно до правил проÑтору імен під Ñ‡Ð°Ñ Ð¿ÐµÑ€ÐµÐ½ÐµÑÐµÐ½Ð½Ñ Ð´Ð¾ групи."
msgid "Project was not found or you do not have permission to add this project to Security Dashboards."
msgstr ""
@@ -19488,10 +20200,10 @@ msgid "ProjectActivityRSS|Subscribe"
msgstr "ПідпиÑатиÑÑ"
msgid "ProjectCreationLevel|Allowed to create projects"
-msgstr "Дозволено Ñтворювати проекти"
+msgstr "Дозволено Ñтворювати проєкти"
msgid "ProjectCreationLevel|Default project creation protection"
-msgstr "ЗахиÑÑ‚ Ð´Ð»Ñ ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾ÐµÐºÑ‚Ñ–Ð² за замовчуваннÑм"
+msgstr "ЗахиÑÑ‚ Ð´Ð»Ñ ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾Ñ”ÐºÑ‚Ñ–Ð² за замовчуваннÑм"
msgid "ProjectCreationLevel|Developers + Maintainers"
msgstr "Розробники + керівники"
@@ -19536,19 +20248,19 @@ msgid "ProjectOverview|Unstar"
msgstr "Видалити із обраних"
msgid "ProjectOverview|You have reached your project limit"
-msgstr "Ви доÑÑгли Ñвого ліміту по кількоÑÑ‚Ñ– проектів"
+msgstr "Ви доÑÑгли Ñвого ліміту по кількоÑÑ‚Ñ– проєктів"
msgid "ProjectOverview|You must sign in to star a project"
-msgstr "Ви повинні увійти, щоб додати проект в обрані"
+msgstr "Ви повинні увійти, щоб додати проєкт в обрані"
msgid "ProjectPage|Project ID: %{project_id}"
-msgstr "ID проекту: %{project_id}"
+msgstr "ID проєкту: %{project_id}"
msgid "ProjectSelect| or group"
msgstr "або групу"
msgid "ProjectSelect|Search for project"
-msgstr "Пошук проекту"
+msgstr "Пошук проєкту"
msgid "ProjectService|%{service_title}: status off"
msgstr "%{service_title}: ÑÑ‚Ð°Ñ‚ÑƒÑ Ð²Ð¸Ð¼ÐºÐ½ÐµÐ½Ð¾"
@@ -19593,7 +20305,7 @@ msgid "ProjectService|Event will be triggered when someone adds a comment on a c
msgstr ""
msgid "ProjectService|Perform common operations on GitLab project: %{project_name}"
-msgstr "Виконати звичайні операції на проекті GitLab: %{project_name}"
+msgstr "Виконати звичайні операції на проєкті GitLab: %{project_name}"
msgid "ProjectService|To set up this service:"
msgstr "Ðалаштувати цей ÑервіÑ:"
@@ -19605,7 +20317,7 @@ msgid "ProjectSettings|All discussions must be resolved"
msgstr "Ð’ÑÑ– Ð¾Ð±Ð³Ð¾Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð¿Ð¾Ð²Ð¸Ð½Ð½Ñ– бути завершені"
msgid "ProjectSettings|Allow"
-msgstr ""
+msgstr "Дозволити"
msgid "ProjectSettings|Allow users to make copies of your repository to a new project"
msgstr ""
@@ -19641,7 +20353,7 @@ msgid "ProjectSettings|Container registry"
msgstr "РеєÑÑ‚Ñ€ контейнерів"
msgid "ProjectSettings|Customize your project badges."
-msgstr "Ðалаштувати значки проекту."
+msgstr "Ðалаштувати значки проєкту."
msgid "ProjectSettings|Disable email notifications"
msgstr "Вимкнути ÑÐ¿Ð¾Ð²Ñ–Ñ‰ÐµÐ½Ð½Ñ ÐµÐ»ÐµÐºÑ‚Ñ€Ð¾Ð½Ð½Ð¾ÑŽ поштою"
@@ -19737,7 +20449,7 @@ msgid "ProjectSettings|No merge commits are created"
msgstr "Коміти-Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð½Ðµ ÑтворюютьÑÑ"
msgid "ProjectSettings|Note: the container registry is always visible when a project is public"
-msgstr "Примітка: Ð´Ð»Ñ Ð¿ÑƒÐ±Ð»Ñ–Ñ‡Ð½Ð¸Ñ… проектів реєÑÑ‚Ñ€ контейнерів завжди Ñ” видимим"
+msgstr "Примітка: Ð´Ð»Ñ Ð¿ÑƒÐ±Ð»Ñ–Ñ‡Ð½Ð¸Ñ… проєктів реєÑÑ‚Ñ€ контейнерів завжди Ñ” видимим"
msgid "ProjectSettings|Only signed commits can be pushed to this repository."
msgstr "Тільки підпиÑані коміти можуть бути надіÑлані в цей репозиторій."
@@ -19824,13 +20536,13 @@ msgid "ProjectSettings|This setting is applied on the server level and can be ov
msgstr "Цей параметр заÑтоÑовуєтьÑÑ Ð½Ð° рівні Ñервера та може бути перевизначений адмініÑтратором."
msgid "ProjectSettings|This setting is applied on the server level but has been overridden for this project."
-msgstr "Цей параметр заÑтоÑовуєтьÑÑ Ð½Ð° рівні Ñервера, але його було перевизначено Ð´Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ проекту."
+msgstr "Цей параметр заÑтоÑовуєтьÑÑ Ð½Ð° рівні Ñервера, але його було перевизначено Ð´Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ проєкту."
msgid "ProjectSettings|This setting will be applied to all projects unless overridden by an admin."
-msgstr "Цей параметр буде заÑтоÑовано до вÑÑ–Ñ… проектів, Ñкщо адмініÑтратор не змінить його."
+msgstr "Цей параметр буде заÑтоÑовано до вÑÑ–Ñ… проєктів, Ñкщо адмініÑтратор не змінить його."
msgid "ProjectSettings|This setting will override user notification preferences for all project members."
-msgstr "Це Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð¿ÐµÑ€ÐµÐ²Ð¸Ð·Ð½Ð°Ñ‡Ð¸Ñ‚ÑŒ Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ñповіщень Ð´Ð»Ñ Ð²ÑÑ–Ñ… учаÑників проекту."
+msgstr "Це Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð¿ÐµÑ€ÐµÐ²Ð¸Ð·Ð½Ð°Ñ‡Ð¸Ñ‚ÑŒ Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ñповіщень Ð´Ð»Ñ Ð²ÑÑ–Ñ… учаÑників проєкту."
msgid "ProjectSettings|This will dictate the commit history when you merge a merge request"
msgstr "Це буде регулювати Ñ–Ñторію комітів при зливанні запитів на злиттÑ"
@@ -19871,6 +20583,9 @@ msgstr "Android"
msgid "ProjectTemplates|GitLab Cluster Management"
msgstr ""
+msgid "ProjectTemplates|Gitpod/Spring Petclinic"
+msgstr ""
+
msgid "ProjectTemplates|Go Micro"
msgstr "Go Micro"
@@ -19944,10 +20659,10 @@ msgid "Projects are graded based on the highest severity vulnerability present"
msgstr "Проєкти оцінюютьÑÑ Ð·Ð° найвищим наÑвним рівнем вразливоÑÑ‚Ñ–"
msgid "Projects shared with %{group_name}"
-msgstr "Спільні проекти з %{group_name}"
+msgstr "Спільні проєкти з %{group_name}"
msgid "Projects that belong to a group are prefixed with the group namespace. Existing projects may be moved into a group."
-msgstr "Проекти, що належать до групи, викориÑтовують Ñ—Ñ— ім'Ñ Ñк префікÑ. ІÑнуючі проекти можуть бути переміщені в групу."
+msgstr "Проекти, що належать до групи, викориÑтовують Ñ—Ñ— ім'Ñ Ñк префікÑ. ІÑнуючі проєкти можуть бути переміщені в групу."
msgid "Projects to index"
msgstr "Проекти Ð´Ð»Ñ Ñ–Ð½Ð´ÐµÐºÑуваннÑ"
@@ -19980,37 +20695,37 @@ msgid "ProjectsDropdown|Frequently visited"
msgstr "ЧаÑто відвідувані"
msgid "ProjectsDropdown|Loading projects"
-msgstr "Ð—Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾ÐµÐºÑ‚Ñ–Ð²"
+msgstr "Ð—Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾Ñ”ÐºÑ‚Ñ–Ð²"
msgid "ProjectsDropdown|Projects you visit often will appear here"
msgstr "Проекти, Ñкі ви чаÑто відвідуєте, будуть відображені тут"
msgid "ProjectsDropdown|Search your projects"
-msgstr "Пошук по ваших проектах"
+msgstr "Пошук по ваших проєктах"
msgid "ProjectsDropdown|Something went wrong on our end."
msgstr "ЩоÑÑŒ пішло не так з нашого боку."
msgid "ProjectsDropdown|Sorry, no projects matched your search"
-msgstr "Ðа жаль, по вашоу запиту проектів не знайдено"
+msgstr "Ðа жаль, по вашоу запиту проєктів не знайдено"
msgid "ProjectsDropdown|This feature requires browser localStorage support"
msgstr "Ð¦Ñ Ñ„ÑƒÐ½ÐºÑ†Ñ–Ñ Ð¿Ð¾Ñ‚Ñ€ÐµÐ±ÑƒÑ” підтримки localStorage вашим браузером"
msgid "ProjectsNew|Allows you to immediately clone this project’s repository. Skip this if you plan to push up an existing repository."
-msgstr "ДозволÑÑ” негайно зклонувати репозиторій цього проекту. ПропуÑÑ‚Ñ–Ñ‚ÑŒ, Ñкщо ви плануєте розміÑтити тут вже Ñ–Ñнуючий репозиторій."
+msgstr "ДозволÑÑ” негайно зклонувати репозиторій цього проєкту. ПропуÑÑ‚Ñ–Ñ‚ÑŒ, Ñкщо ви плануєте розміÑтити тут вже Ñ–Ñнуючий репозиторій."
msgid "ProjectsNew|Blank"
msgstr "ПуÑтий"
msgid "ProjectsNew|Blank project"
-msgstr "ПуÑтий проект"
+msgstr "ПуÑтий проєкт"
msgid "ProjectsNew|Connect your external repository to GitLab CI/CD."
msgstr ""
msgid "ProjectsNew|Contact an administrator to enable options for importing your project."
-msgstr "ЗвернітьÑÑ Ð´Ð¾ адмініÑтратора Ð´Ð»Ñ Ð°ÐºÑ‚Ð¸Ð²Ð°Ñ†Ñ–Ñ— варіантів імпорту Ð´Ð»Ñ Ð²Ð°ÑˆÐ¾Ð³Ð¾ проекту."
+msgstr "ЗвернітьÑÑ Ð´Ð¾ адмініÑтратора Ð´Ð»Ñ Ð°ÐºÑ‚Ð¸Ð²Ð°Ñ†Ñ–Ñ— варіантів імпорту Ð´Ð»Ñ Ð²Ð°ÑˆÐ¾Ð³Ð¾ проєкту."
msgid "ProjectsNew|Create"
msgstr "Створити"
@@ -20028,7 +20743,7 @@ msgid "ProjectsNew|Create new project"
msgstr "Створити новий проєкт"
msgid "ProjectsNew|Creating project & repository."
-msgstr "Ð¡Ñ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾ÐµÐºÑ‚Ñƒ та репозиторію."
+msgstr "Ð¡Ñ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾Ñ”ÐºÑ‚Ñƒ та репозиторію."
msgid "ProjectsNew|Description format"
msgstr "Формат опиÑу"
@@ -20037,7 +20752,7 @@ msgid "ProjectsNew|Import"
msgstr "Імпорт"
msgid "ProjectsNew|Import project"
-msgstr "Імпортувати проект"
+msgstr "Імпортувати проєкт"
msgid "ProjectsNew|Initialize repository with a README"
msgstr "Ініціалізувати репозиторій файлом інÑтрукції (README)"
@@ -20049,7 +20764,7 @@ msgid "ProjectsNew|Please wait a moment, this page will automatically refresh wh
msgstr "Будь лаÑка, почекайте, Ñторінку буде оновлено автоматично по завершенню."
msgid "ProjectsNew|Project description %{tag_start}(optional)%{tag_end}"
-msgstr "ÐžÐ¿Ð¸Ñ Ð¿Ñ€Ð¾ÐµÐºÑ‚Ñƒ %{tag_start}(необов’Ñзково)%{tag_end}"
+msgstr "ÐžÐ¿Ð¸Ñ Ð¿Ñ€Ð¾Ñ”ÐºÑ‚Ñƒ %{tag_start}(необов’Ñзково)%{tag_end}"
msgid "ProjectsNew|Run CI/CD for external repository"
msgstr ""
@@ -20061,7 +20776,7 @@ msgid "ProjectsNew|Visibility Level"
msgstr "Рівень видимоÑÑ‚Ñ–"
msgid "ProjectsNew|Want to house several dependent projects under the same namespace? %{link_start}Create a group.%{link_end}"
-msgstr "Хочете розміÑтити декілька залежних проектів в одному проÑторі імен? %{link_start}Створіть групу.%{link_end}"
+msgstr "Хочете розміÑтити декілька залежних проєктів в одному проÑторі імен? %{link_start}Створіть групу.%{link_end}"
msgid "Prometheus"
msgstr "Prometheus"
@@ -20130,7 +20845,7 @@ msgid "PrometheusService|Auto configuration"
msgstr "Ðвтоматична конфігураціÑ"
msgid "PrometheusService|Automatically deploy and configure Prometheus on your clusters to monitor your project’s environments"
-msgstr "Ðвтоматично розгортайте та налаштовуйте Prometheus на ваші клаÑтери Ð´Ð»Ñ Ð¼Ð¾Ð½Ñ–Ñ‚Ð¾Ñ€Ð¸Ð½Ð³Ñƒ Ñередовищ проекту"
+msgstr "Ðвтоматично розгортайте та налаштовуйте Prometheus на ваші клаÑтери Ð´Ð»Ñ Ð¼Ð¾Ð½Ñ–Ñ‚Ð¾Ñ€Ð¸Ð½Ð³Ñƒ Ñередовищ проєкту"
msgid "PrometheusService|Client ID of the IAP secured resource (looks like IAP_CLIENT_ID.apps.googleusercontent.com)"
msgstr ""
@@ -20223,7 +20938,7 @@ msgid "Promote to group label"
msgstr "ПеренеÑти мітку на рівень групи"
msgid "PromoteMilestone|Only project milestones can be promoted."
-msgstr "Лише проектні етапи можуть бути перенеÑені."
+msgstr "Лише проєктні етапи можуть бути перенеÑені."
msgid "PromoteMilestone|Project does not belong to a group."
msgstr "Проект не належить жодній групі."
@@ -20265,7 +20980,7 @@ msgid "Promotions|Don't show me this again"
msgstr "Більше не показувати це"
msgid "Promotions|Epics let you manage your portfolio of projects more efficiently and with less effort by tracking groups of issues that share a theme, across projects and milestones."
-msgstr "Епіки дозволÑÑŽÑ‚ÑŒ вам більш ефективно та з меншими зуÑиллÑми керувати портфелÑми проектів, відÑлідковуючи групи Ñпоріднених задач у етапах та проектах."
+msgstr "Епіки дозволÑÑŽÑ‚ÑŒ вам більш ефективно та з меншими зуÑиллÑми керувати портфелÑми проєктів, відÑлідковуючи групи Ñпоріднених задач у етапах та проєктах."
msgid "Promotions|Improve issues management with Issue weight and GitLab Enterprise Edition."
msgstr ""
@@ -20334,7 +21049,7 @@ msgid "Protected Branch"
msgstr "Захищена гілка"
msgid "Protected Branches"
-msgstr ""
+msgstr "Захищені гілки"
msgid "Protected Environment"
msgstr "Захищене Ñередовище"
@@ -20349,7 +21064,7 @@ msgid "Protected Tag"
msgstr "Захищений тег"
msgid "Protected Tags"
-msgstr ""
+msgstr "Захищені теги"
msgid "Protected branches"
msgstr "Захищені гілки"
@@ -20460,10 +21175,10 @@ msgid "Public"
msgstr "Публічний"
msgid "Public - The group and any public projects can be viewed without any authentication."
-msgstr "Публічна — група та вÑÑ– публічні проекти можуть переглÑдатиÑÑ Ð±ÐµÐ· автентифікації."
+msgstr "Публічна — група та вÑÑ– публічні проєкти можуть переглÑдатиÑÑ Ð±ÐµÐ· автентифікації."
msgid "Public - The project can be accessed without any authentication."
-msgstr "Публічний — проект может переглÑдатиÑÑ Ð±ÐµÐ· автентифікації."
+msgstr "Публічний — проєкт может переглÑдатиÑÑ Ð±ÐµÐ· автентифікації."
msgid "Public Access Help"
msgstr ""
@@ -20480,6 +21195,9 @@ msgstr ""
msgid "Publish to status page"
msgstr ""
+msgid "Published"
+msgstr ""
+
msgid "Published on status page"
msgstr ""
@@ -20523,10 +21241,10 @@ msgid "Push events"
msgstr "Події Ð²Ñ–Ð´Ð¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð½Ñ (push)"
msgid "Push project from command line"
-msgstr "Виконати push проекту за допомогою командного Ñ€Ñдка"
+msgstr "Виконати push проєкту за допомогою командного Ñ€Ñдка"
msgid "Push to create a project"
-msgstr "ÐатиÑніть, щоб Ñтворити проект"
+msgstr "ÐатиÑніть, щоб Ñтворити проєкт"
msgid "PushRule|Committer restriction"
msgstr "ÐžÐ±Ð¼ÐµÐ¶ÐµÐ½Ð½Ñ Ð´Ð»Ñ ÐºÐ¾Ð¼Ñ–Ñ‚Ñ‚ÐµÑ€Ð°"
@@ -20565,7 +21283,7 @@ msgid "PushoverService|Pushover makes it easy to get real-time notifications on
msgstr "Pushover дозволÑÑ” легко отримувати ÑÐ¿Ð¾Ð²Ñ–Ñ‰ÐµÐ½Ð½Ñ Ð² реальному чаÑÑ– на ваших приÑтроÑÑ… Android, iPhone, iPad та комп'ютерах."
msgid "PushoverService|See project %{project_full_name}"
-msgstr "ПереглÑнути проект %{project_full_name}"
+msgstr "ПереглÑнути проєкт %{project_full_name}"
msgid "PushoverService|Total commits count: %{total_commits_count}"
msgstr "Загальна кількіÑÑ‚ÑŒ комітів: %{total_commits_count}"
@@ -20589,7 +21307,7 @@ msgid "Query is valid"
msgstr "Запит є правильним"
msgid "Queued"
-msgstr ""
+msgstr "У черзі"
msgid "Quick actions can be used in the issues description and comment boxes."
msgstr "Швидкі дії можна викориÑтовувати в опиÑах задач Ñ– коментарÑÑ…."
@@ -20597,9 +21315,15 @@ msgstr "Швидкі дії можна викориÑтовувати в опиÑ
msgid "Quick range"
msgstr "Швидкий діапазон"
+msgid "Quickly and easily edit multiple files in your project."
+msgstr ""
+
msgid "README"
msgstr "ІнÑÑ‚Ñ€ÑƒÐºÑ†Ñ–Ñ (README)"
+msgid "Rails"
+msgstr ""
+
msgid "Rake Tasks Help"
msgstr ""
@@ -20613,7 +21337,7 @@ msgid "Re-authentication required"
msgstr "Ðеобхідна повторна автентифікаціÑ"
msgid "Re-verification interval"
-msgstr ""
+msgstr "Інтервал повторної перевірки"
msgid "Read more"
msgstr "Докладніше"
@@ -20646,7 +21370,7 @@ msgid "Recent Activity"
msgstr "ОÑÑ‚Ð°Ð½Ð½Ñ Ð°ÐºÑ‚Ð¸Ð²Ð½Ñ–ÑÑ‚ÑŒ"
msgid "Recent Project Activity"
-msgstr "ОÑÑ‚Ð°Ð½Ð½Ñ Ð¿Ñ€Ð¾ÐµÐºÑ‚Ð½Ð° активніÑÑ‚ÑŒ"
+msgstr "ОÑÑ‚Ð°Ð½Ð½Ñ Ð¿Ñ€Ð¾Ñ”ÐºÑ‚Ð½Ð° активніÑÑ‚ÑŒ"
msgid "Recent Searches Service is unavailable"
msgstr "Ð¡ÐµÑ€Ð²Ñ–Ñ Ð¾Ñтанніх пошуків недоÑтупний"
@@ -20655,7 +21379,7 @@ msgid "Recent searches"
msgstr "ОÑтанні пошукові запити"
msgid "Reconfigure"
-msgstr ""
+msgstr "Переналаштувати"
msgid "Recover hidden stage"
msgstr ""
@@ -20721,12 +21445,15 @@ msgstr "ЗареєÑтруватиÑÑ / Увійти"
msgid "Register Two-Factor Authenticator"
msgstr "ЗареєÑтрувати двофакторний автентифікатор"
-msgid "Register U2F device"
-msgstr "ЗареєÑтрувати приÑтрій U2F"
-
msgid "Register Universal Two-Factor (U2F) Device"
msgstr "ЗареєÑтрувати універÑальний двофакторний приÑтрій (U2F)"
+msgid "Register WebAuthn Device"
+msgstr ""
+
+msgid "Register device"
+msgstr ""
+
msgid "Register for GitLab"
msgstr "ЗареєÑтруватиÑÑ Ð² GitLab"
@@ -20736,9 +21463,6 @@ msgstr "ЗареєÑтруватиÑÑŒ зараз"
msgid "Register with two-factor app"
msgstr "ЗареєÑтрувати за допомогою двофакторного заÑтоÑунку"
-msgid "Registration"
-msgstr "РеєÑтраціÑ"
-
msgid "Registration|Checkout"
msgstr ""
@@ -20857,9 +21581,6 @@ msgstr "Проблема при отриманні деталей релізу"
msgid "Release|Something went wrong while saving the release details"
msgstr "Проблема при збереженні деталей релізу"
-msgid "Remediated: needs review"
-msgstr ""
-
msgid "Remediations"
msgstr ""
@@ -20939,16 +21660,16 @@ msgid "Remove group"
msgstr "Видалити групу"
msgid "Remove iteration"
-msgstr ""
+msgstr "Видалити ітерацію"
msgid "Remove license"
-msgstr ""
+msgstr "Вилучити ліцензію"
msgid "Remove limit"
-msgstr ""
+msgstr "Прибрати обмеженнÑ"
msgid "Remove member"
-msgstr ""
+msgstr "Виключити учаÑника"
msgid "Remove milestone"
msgstr "Видалити етап"
@@ -20965,6 +21686,9 @@ msgstr "Видалити оÑновний вузол"
msgid "Remove priority"
msgstr "Видалити пріоритет"
+msgid "Remove report"
+msgstr ""
+
msgid "Remove secondary node"
msgstr "Видалити вторинний вузол"
@@ -20977,6 +21701,12 @@ msgstr "Видалити Ñтадію"
msgid "Remove time estimate"
msgstr "Видалити запланований чаÑ"
+msgid "Remove user & report"
+msgstr ""
+
+msgid "Remove user from group"
+msgstr ""
+
msgid "Removed"
msgstr "Видалено"
@@ -20987,7 +21717,7 @@ msgid "Removed %{epic_ref} from child epics."
msgstr "Видалено %{epic_ref} із підепіків."
msgid "Removed %{iteration_reference} iteration."
-msgstr ""
+msgstr "Видалено ітерацію %{iteration_reference}."
msgid "Removed %{label_references} %{label_text}."
msgstr "Видалено %{label_references} %{label_text}."
@@ -21032,7 +21762,7 @@ msgid "Removes %{epic_ref} from child epics."
msgstr "ВидалÑÑ” %{epic_ref} з дочірних епіків."
msgid "Removes %{iteration_reference} iteration."
-msgstr ""
+msgstr "ВидалÑєтьÑÑ Ñ–Ñ‚ÐµÑ€Ð°Ñ†Ñ–Ñ %{iteration_reference}."
msgid "Removes %{label_references} %{label_text}."
msgstr "ВидалÑÑ” %{label_references} %{label_text}."
@@ -21058,9 +21788,6 @@ msgstr "ВидалÑÑ” дату завершеннÑ."
msgid "Removes time estimate."
msgstr "ВидалÑÑ” запланований чаÑ."
-msgid "Removing license…"
-msgstr "Ð’Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ Ð»Ñ–Ñ†ÐµÐ½Ð·Ñ–Ñ—â€¦"
-
msgid "Removing this group also removes all child projects, including archived projects, and their resources."
msgstr ""
@@ -21116,7 +21843,7 @@ msgid "Replication enabled"
msgstr ""
msgid "Replication paused"
-msgstr ""
+msgstr "Реплікацію призупинено"
msgid "Reply by email"
msgstr "ВідповіÑти по електнонній пошті"
@@ -21145,6 +21872,9 @@ msgstr "Повідомити адмініÑтратора про порушенÐ
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr "Повідомлено %{timeAgo} кориÑтувачем %{reportedBy}"
+msgid "Reported by %{reporter}"
+msgstr ""
+
msgid "Reporting"
msgstr "ЗвітуваннÑ"
@@ -21233,11 +21963,32 @@ msgstr "результати теÑтів не змінилиÑÑ"
msgid "Repositories"
msgstr "Репозиторії"
+msgid "Repositories Analytics"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download Historic Test Coverage Data"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download historic test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Historic Test Coverage Data is available in raw format (.csv) for further analysis."
+msgstr ""
+
+msgid "RepositoriesAnalytics|Test Code Coverage"
+msgstr ""
+
+msgid "RepositoriesAnalytics|There was an error fetching the projects."
+msgstr ""
+
msgid "Repository"
msgstr "Репозиторій"
msgid "Repository Analytics"
-msgstr ""
+msgstr "Ðналітика репозиторію"
msgid "Repository Graph"
msgstr "Граф репозиторію"
@@ -21246,7 +21997,7 @@ msgid "Repository Settings"
msgstr "ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ñ€ÐµÐ¿Ð¾Ð·Ð¸Ñ‚Ð¾Ñ€Ñ–ÑŽ"
msgid "Repository check"
-msgstr ""
+msgstr "Перевірка репозиторію"
msgid "Repository check was triggered."
msgstr "Перевірку репозиторію запущено."
@@ -21311,9 +22062,15 @@ msgstr ""
msgid "Request parameter %{param} is missing."
msgstr "Параметр запиту %{param} відÑутній."
+msgid "Request review from"
+msgstr ""
+
msgid "Request to link SAML account must be authorized"
msgstr "Запит на зв’ÑÐ·ÑƒÐ²Ð°Ð½Ð½Ñ Ð¾Ð±Ð»Ñ–ÐºÐ¾Ð²Ð¾Ð³Ð¾ запиÑу SAML повинен бути авторизований"
+msgid "Requested"
+msgstr ""
+
msgid "Requested %{time_ago}"
msgstr "Відправлено запит %{time_ago}"
@@ -21324,7 +22081,7 @@ msgid "Requested states are invalid"
msgstr ""
msgid "Requests"
-msgstr ""
+msgstr "Запити"
msgid "Requests Profiles"
msgstr "ÐŸÑ€Ð¾Ñ„Ñ–Ð»ÑŽÐ²Ð°Ð½Ð½Ñ Ð·Ð°Ð¿Ð¸Ñ‚Ñ–Ð²"
@@ -21332,6 +22089,9 @@ msgstr "ÐŸÑ€Ð¾Ñ„Ñ–Ð»ÑŽÐ²Ð°Ð½Ð½Ñ Ð·Ð°Ð¿Ð¸Ñ‚Ñ–Ð²"
msgid "Requests to these domain(s)/address(es) on the local network will be allowed when local requests from hooks and services are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 or 127.0.0.0/28 are supported. Domain wildcards are not supported currently. Use comma, semicolon, or newline to separate multiple entries. The allowlist can hold a maximum of 1000 entries. Domains should use IDNA encoding. Ex: example.com, 192.168.1.1, 127.0.0.0/28, xn--itlab-j1a.com."
msgstr ""
+msgid "Require admin approval for new sign-ups"
+msgstr ""
+
msgid "Require all users in this group to setup Two-factor authentication"
msgstr "Вимагати від вÑÑ–Ñ… кориÑтувачів цієї групи налаштувати двофакторну автентифікацію"
@@ -21392,7 +22152,7 @@ msgid "Requires values to meet regular expression requirements."
msgstr ""
msgid "Resend Request"
-msgstr ""
+msgstr "Повторно надіÑлати запит"
msgid "Resend confirmation email"
msgstr "Повторно відіÑлати Ð¿Ñ–Ð´Ñ‚Ð²ÐµÑ€Ð´Ð¶ÐµÐ½Ð½Ñ Ð¿Ð¾ електронній пошті"
@@ -21425,13 +22185,13 @@ msgid "Reset to project defaults"
msgstr ""
msgid "Resetting the authorization key for this project will require updating the authorization key in every alert source it is enabled in."
-msgstr "Ð¡ÐºÐ¸Ð´Ð°Ð½Ð½Ñ ÐºÐ»ÑŽÑ‡Ð° авторизації Ð´Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ проекту вимагатиме Ð¾Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ ÐºÐ»ÑŽÑ‡Ð° авторизації в кожному із джерел попереджень, в Ñкому він увімкнений."
+msgstr "Ð¡ÐºÐ¸Ð´Ð°Ð½Ð½Ñ ÐºÐ»ÑŽÑ‡Ð° авторизації Ð´Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ проєкту вимагатиме Ð¾Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ ÐºÐ»ÑŽÑ‡Ð° авторизації в кожному із джерел попереджень, в Ñкому він увімкнений."
msgid "Resetting the authorization key will invalidate the previous key. Existing alert configurations will need to be updated with the new key."
msgstr "Ð¡ÐºÐ¸Ð´Ð°Ð½Ð½Ñ ÐºÐ»ÑŽÑ‡Ð° авторизації призведе до ÑкаÑÑƒÐ²Ð°Ð½Ð½Ñ Ð¿Ð¾Ð¿ÐµÑ€ÐµÐ´Ð½ÑŒÐ¾Ð³Ð¾ ключа. ІÑнуючі конфігурації попереджень потрібно буде оновити новим ключем."
msgid "Resolve"
-msgstr ""
+msgstr "Вирішити"
msgid "Resolve all threads in new issue"
msgstr "Вирішити уÑÑ– Ð¾Ð±Ð³Ð¾Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð² новій задачі"
@@ -21458,14 +22218,11 @@ msgid "Resolved all discussions."
msgstr "Ð’ÑÑ– Ð¾Ð±Ð³Ð¾Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð·Ð°Ð²ÐµÑ€ÑˆÐµÐ½Ð¾."
msgid "Resolved by"
-msgstr ""
+msgstr "Вирішено"
msgid "Resolved by %{name}"
msgstr "Вирішено %{name}"
-msgid "Resolved by %{resolvedByName}"
-msgstr "Вирішено %{resolvedByName}"
-
msgid "Resolves IP addresses once and uses them to submit requests"
msgstr "Визначає IP-адреÑи один раз Ñ– викориÑтовує Ñ—Ñ… Ð´Ð»Ñ Ð²Ñ–Ð´Ñ€Ð°Ð²Ð»ÐµÐ½Ð½Ñ Ð·Ð°Ð¿Ð¸Ñ‚Ñ–Ð²"
@@ -21503,7 +22260,7 @@ msgid "Restart Terminal"
msgstr "ПерезапуÑтити термінал"
msgid "Restore"
-msgstr ""
+msgstr "Відновити"
msgid "Restore group"
msgstr "Відновити групу"
@@ -21527,10 +22284,10 @@ msgid "Resume"
msgstr "Продовжити"
msgid "Resync"
-msgstr ""
+msgstr "Повторна ÑинхронізаціÑ"
msgid "Resync all"
-msgstr ""
+msgstr "Повторно Ñинхронізувати вÑе"
msgid "Resync all %{replicableType}"
msgstr ""
@@ -21587,6 +22344,16 @@ msgstr ""
msgid "ReviewApp|Enable Review App"
msgstr ""
+msgid "Reviewer"
+msgid_plural "%d Reviewers"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
+msgid "Reviewer(s)"
+msgstr ""
+
msgid "Reviewing"
msgstr "Перевірка"
@@ -21597,7 +22364,7 @@ msgid "Revoke"
msgstr "Відкликати"
msgid "Revoked"
-msgstr ""
+msgstr "Відкликано"
msgid "Revoked impersonation token %{token_name}!"
msgstr "Відкликано токен Ñ–Ð¼Ñ–Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ %{token_name}!"
@@ -21626,6 +22393,9 @@ msgstr "Відкотити"
msgid "Rook"
msgstr "Rook"
+msgid "Ruby"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -21651,16 +22421,16 @@ msgid "Run untagged jobs"
msgstr "Виконати Ð·Ð°Ð²Ð´Ð°Ð½Ð½Ñ Ð±ÐµÐ· тегів"
msgid "Runner cannot be assigned to other projects"
-msgstr "Runner не може бути призначено Ð´Ð»Ñ Ñ–Ð½ÑˆÐ¸Ñ… проектів"
+msgstr "Runner не може бути призначено Ð´Ð»Ñ Ñ–Ð½ÑˆÐ¸Ñ… проєктів"
msgid "Runner runs jobs from all unassigned projects"
-msgstr "Runner запуÑкає Ð·Ð°Ð²Ð´Ð°Ð½Ð½Ñ Ð·Ñ– вÑÑ–Ñ… непризначених проектів"
+msgstr "Runner запуÑкає Ð·Ð°Ð²Ð´Ð°Ð½Ð½Ñ Ð·Ñ– вÑÑ–Ñ… непризначених проєктів"
msgid "Runner runs jobs from all unassigned projects in its group"
-msgstr "Runner запуÑкає Ð·Ð°Ð²Ð´Ð°Ð½Ð½Ñ Ð·Ñ– вÑÑ–Ñ… непризначених проектів в його групі"
+msgstr "Runner запуÑкає Ð·Ð°Ð²Ð´Ð°Ð½Ð½Ñ Ð·Ñ– вÑÑ–Ñ… непризначених проєктів в його групі"
msgid "Runner runs jobs from assigned projects"
-msgstr "Runner виконує завданні із призначених проектів"
+msgstr "Runner виконує завданні із призначених проєктів"
msgid "Runner token"
msgstr "Токен Runner'а"
@@ -21687,7 +22457,7 @@ msgid "Runners API"
msgstr "API Runner’ів"
msgid "Runners activated for this project"
-msgstr "Runner'и активовані Ð´Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ проекту"
+msgstr "Runner'и активовані Ð´Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ проєкту"
msgid "Runners are processes that pick up and execute jobs for GitLab. Here you can register and see your Runners for this project."
msgstr ""
@@ -21704,6 +22474,63 @@ msgstr "ДоÑтупні Runner'и: %{active_runners_count}"
msgid "Runners page."
msgstr "Сторінка Runner'ів."
+msgid "Runners|Active"
+msgstr ""
+
+msgid "Runners|Architecture"
+msgstr ""
+
+msgid "Runners|Can run untagged jobs"
+msgstr ""
+
+msgid "Runners|Description"
+msgstr ""
+
+msgid "Runners|Group"
+msgstr ""
+
+msgid "Runners|IP Address"
+msgstr ""
+
+msgid "Runners|Last contact"
+msgstr ""
+
+msgid "Runners|Locked to this project"
+msgstr ""
+
+msgid "Runners|Maximum job timeout"
+msgstr ""
+
+msgid "Runners|Name"
+msgstr ""
+
+msgid "Runners|Platform"
+msgstr ""
+
+msgid "Runners|Property Name"
+msgstr ""
+
+msgid "Runners|Protected"
+msgstr ""
+
+msgid "Runners|Revision"
+msgstr ""
+
+msgid "Runners|Shared"
+msgstr ""
+
+msgid "Runners|Specific"
+msgstr ""
+
+msgid "Runners|Tags"
+msgstr ""
+
+msgid "Runners|Value"
+msgstr ""
+
+msgid "Runners|Version"
+msgstr ""
+
msgid "Runners|You have used %{quotaUsed} out of %{quotaLimit} of your shared Runners pipeline minutes."
msgstr "Ви викориÑтали %{quotaUsed} із ваших %{quotaLimit} хвилин Ð´Ð»Ñ ÐºÐ¾Ð½Ð²ÐµÑ”Ñ€Ñ–Ð² загальних runner'ів."
@@ -21716,6 +22543,9 @@ msgstr "ВиконуєтьÑÑ…"
msgid "Runs a number of housekeeping tasks within the current repository, such as compressing file revisions and removing unreachable objects."
msgstr "Виконує Ñ€Ñд задач по очищенню поточного репозиторію, таких Ñк ÑтиÑÐ½ÐµÐ½Ð½Ñ Ñ€ÐµÐ´Ð°ÐºÑ†Ñ–Ð¹ файлів та Ð²Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ Ð½ÐµÐ´Ð¾ÑÑжних об'єктів."
+msgid "SAML"
+msgstr ""
+
msgid "SAML SSO"
msgstr "Єдиний вхід SAML"
@@ -21741,7 +22571,7 @@ msgid "SSH Keys"
msgstr "Ключі SSH"
msgid "SSH Keys Help"
-msgstr ""
+msgstr "Довідка щодо ключів SSH"
msgid "SSH host key fingerprints"
msgstr "Відбитки SSH-ключа хоÑта"
@@ -21767,6 +22597,9 @@ msgstr "Субота"
msgid "Save"
msgstr "Зберегти"
+msgid "Save %{name} size limits"
+msgstr ""
+
msgid "Save Changes"
msgstr "Зберегти зміни"
@@ -21797,9 +22630,6 @@ msgstr "Зберегти розклад конвеєра"
msgid "Save space and find tags in the Container Registry more easily. Enable the cleanup policy to remove stale tags and keep only the ones you need."
msgstr ""
-msgid "Save template"
-msgstr "Зберегти шаблон"
-
msgid "Save variables"
msgstr "Зберегти змінні"
@@ -21810,7 +22640,7 @@ msgid "Saving"
msgstr "ЗбереженнÑ"
msgid "Saving project."
-msgstr "Ð—Ð±ÐµÑ€ÐµÐ¶ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾ÐµÐºÑ‚Ñƒ."
+msgstr "Ð—Ð±ÐµÑ€ÐµÐ¶ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾Ñ”ÐºÑ‚Ñƒ."
msgid "Schedule a new pipeline"
msgstr "Розклад нового конвеєра"
@@ -21842,9 +22672,6 @@ msgstr "ÐŸÐ»Ð°Ð½ÑƒÐ²Ð°Ð½Ð½Ñ ÐºÐ¾Ð½Ð²ÐµÑ”Ñ€Ñ–Ð²"
msgid "Scope"
msgstr "ОблаÑÑ‚ÑŒ дії"
-msgid "Scope not supported with disabled 'users_search' feature!"
-msgstr "ОблаÑÑ‚ÑŒ пошуку не доÑтупна при вимкненій функціональноÑÑ‚Ñ– пошуку кориÑтувача!"
-
msgid "Scoped issue boards"
msgstr "Дошки задач із обмеженою облаÑÑ‚ÑŽ видимоÑÑ‚Ñ–"
@@ -21891,7 +22718,7 @@ msgid "Search an environment spec"
msgstr "Пошук Ñпецифікації Ñередовища"
msgid "Search authors"
-msgstr ""
+msgstr "Пошук авторів"
msgid "Search branches"
msgstr "Пошук у гілках"
@@ -21912,7 +22739,7 @@ msgid "Search by commit title or SHA"
msgstr ""
msgid "Search by message"
-msgstr ""
+msgstr "Шукати за повідомленнÑм"
msgid "Search by name"
msgstr ""
@@ -21933,7 +22760,7 @@ msgid "Search for a user"
msgstr "Пошук кориÑтувача"
msgid "Search for projects, issues, etc."
-msgstr "Пошук в проектах, задачах і т. д."
+msgstr "Пошук в проєктах, задачах і т. д."
msgid "Search for this text"
msgstr "Шукати цей текÑÑ‚"
@@ -21960,20 +22787,17 @@ msgid "Search or jump to…"
msgstr "Шукати чи перейти до…"
msgid "Search project"
-msgstr "Пошук в проекті"
+msgstr "Пошук в проєкті"
msgid "Search projects"
-msgstr "Пошук проектів"
+msgstr "Пошук проєктів"
msgid "Search projects..."
-msgstr "Пошук проектів..."
+msgstr "Пошук проєктів..."
msgid "Search requirements"
msgstr "Пошук Ñеред вимог"
-msgid "Search results…"
-msgstr ""
-
msgid "Search users"
msgstr "Пошук кориÑтувачів"
@@ -21984,7 +22808,7 @@ msgid "Search your project dependencies for their licenses and apply policies."
msgstr ""
msgid "Search your projects"
-msgstr "Пошук у ваших проектах"
+msgstr "Пошук у ваших проєктах"
msgid "SearchAutocomplete|All GitLab"
msgstr "ВеÑÑŒ GitLab"
@@ -22052,6 +22876,13 @@ msgstr[1] "коміти"
msgstr[2] "комітів"
msgstr[3] "комітів"
+msgid "SearchResults|epic"
+msgid_plural "SearchResults|epics"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "SearchResults|issue"
msgid_plural "SearchResults|issues"
msgstr[0] "задача"
@@ -22075,10 +22906,10 @@ msgstr[3] "етапів"
msgid "SearchResults|project"
msgid_plural "SearchResults|projects"
-msgstr[0] "проект"
-msgstr[1] "проекти"
-msgstr[2] "проектів"
-msgstr[3] "проектів"
+msgstr[0] "проєкт"
+msgstr[1] "проєкти"
+msgstr[2] "проєктів"
+msgstr[3] "проєктів"
msgid "SearchResults|snippet"
msgid_plural "SearchResults|snippets"
@@ -22110,14 +22941,14 @@ msgstr ""
msgid "Seat Link is disabled, and cannot be configured through this form."
msgstr ""
-msgid "Seats currently in use"
-msgstr "МіÑцÑ, Ñкі зараз викориÑтовуютьÑÑ"
+msgid "Seats usage data as of %{last_enqueue_time}"
+msgstr ""
-msgid "Seats in license"
-msgstr "КількіÑÑ‚ÑŒ міÑць у ліцензії"
+msgid "Seats usage data is updated every day at 12:00pm UTC"
+msgstr ""
msgid "Secondary"
-msgstr ""
+msgstr "Вторинний"
msgid "Seconds"
msgstr ""
@@ -22126,7 +22957,7 @@ msgid "Secret"
msgstr "Секрет"
msgid "Secret Detection"
-msgstr ""
+msgstr "ВиÑÐ²Ð»ÐµÐ½Ð½Ñ Ñекретів"
msgid "Security"
msgstr "Безпека"
@@ -22167,6 +22998,9 @@ msgstr ""
msgid "SecurityConfiguration|Available for on-demand DAST"
msgstr ""
+msgid "SecurityConfiguration|By default, all analyzers are applied in order to cover all languages across your project, and only run if the language is detected in the Merge Request."
+msgstr ""
+
msgid "SecurityConfiguration|Configure"
msgstr ""
@@ -22197,16 +23031,19 @@ msgstr ""
msgid "SecurityConfiguration|Manage"
msgstr ""
+msgid "SecurityConfiguration|More information"
+msgstr ""
+
msgid "SecurityConfiguration|Not enabled"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|Security Control"
+msgid "SecurityConfiguration|SAST Configuration"
msgstr ""
-msgid "SecurityConfiguration|See documentation"
+msgid "SecurityConfiguration|Security Control"
msgstr ""
msgid "SecurityConfiguration|Status"
@@ -22218,6 +23055,9 @@ msgstr ""
msgid "SecurityConfiguration|Using custom settings. You won't receive automatic updates on this variable. %{anchorStart}Restore to default%{anchorEnd}"
msgstr ""
+msgid "SecurityConfiguration|View history"
+msgstr ""
+
msgid "SecurityConfiguration|You can quickly enable all security scanning tools by enabling %{linkStart}Auto DevOps%{linkEnd}."
msgstr ""
@@ -22296,9 +23136,6 @@ msgstr ""
msgid "SecurityReports|Learn more about setting up your dashboard"
msgstr ""
-msgid "SecurityReports|Load more vulnerabilities"
-msgstr ""
-
msgid "SecurityReports|Monitor vulnerabilities in your code"
msgstr ""
@@ -22438,7 +23275,7 @@ msgid "See metrics"
msgstr "ПереглÑнути метрики"
msgid "See the affected projects in the GitLab admin panel"
-msgstr "ПереглÑнути уÑÑ– уражені проекти на панелі адмініÑтратора GitLab"
+msgstr "ПереглÑнути уÑÑ– уражені проєкти на панелі адмініÑтратора GitLab"
msgid "See what's new at GitLab"
msgstr ""
@@ -22453,7 +23290,7 @@ msgid "Select Git revision"
msgstr ""
msgid "Select GitLab project to link with your Slack team"
-msgstr "Виберіть проект GitLab Ð´Ð»Ñ Ð·Ð²â€™ÑÐ·ÑƒÐ²Ð°Ð½Ð½Ñ Ñ–Ð· вашою командою Slack"
+msgstr "Виберіть проєкт GitLab Ð´Ð»Ñ Ð·Ð²â€™ÑÐ·ÑƒÐ²Ð°Ð½Ð½Ñ Ñ–Ð· вашою командою Slack"
msgid "Select Page"
msgstr "Вибрати Ñторінку"
@@ -22471,16 +23308,16 @@ msgid "Select a label"
msgstr "Вибрати мітку"
msgid "Select a namespace to fork the project"
-msgstr "Виберіть проÑÑ‚Ñ–Ñ€ імен Ð´Ð»Ñ Ñ„Ð¾Ñ€ÐºÑƒ проекту"
+msgstr "Виберіть проÑÑ‚Ñ–Ñ€ імен Ð´Ð»Ñ Ñ„Ð¾Ñ€ÐºÑƒ проєкту"
msgid "Select a new namespace"
msgstr "Вибрати новий проÑÑ‚Ñ–Ñ€ імен"
msgid "Select a project"
-msgstr "Вибрати проект"
+msgstr "Вибрати проєкт"
msgid "Select a project to read Insights configuration file"
-msgstr "Вибрати проект, щоб прочитати файл конфігурації ÑтатиÑтики (Insights)"
+msgstr "Вибрати проєкт, щоб прочитати файл конфігурації ÑтатиÑтики (Insights)"
msgid "Select a reason"
msgstr ""
@@ -22504,7 +23341,7 @@ msgid "Select an existing Kubernetes cluster or create a new one"
msgstr "Виберіть Ñ–Ñнуючий клаÑтер Kubernetes або Ñтворіть новий"
msgid "Select assignee"
-msgstr ""
+msgstr "Виберіть виконавцÑ"
msgid "Select branch"
msgstr "Виберіть гілку"
@@ -22522,7 +23359,7 @@ msgid "Select file"
msgstr "Оберіть файл"
msgid "Select group or project"
-msgstr "Вибрати групу чи проект"
+msgstr "Вибрати групу чи проєкт"
msgid "Select groups to replicate"
msgstr ""
@@ -22543,22 +23380,22 @@ msgid "Select milestone"
msgstr "Вибрати етап"
msgid "Select private project"
-msgstr "Вибрати приватний проект"
+msgstr "Вибрати приватний проєкт"
msgid "Select project"
-msgstr "Вибрати проект"
+msgstr "Вибрати проєкт"
msgid "Select project and zone to choose machine type"
-msgstr "Вибрати проект та зону Ð´Ð»Ñ Ð²Ð¸Ð±Ð¾Ñ€Ñƒ типу машини"
+msgstr "Вибрати проєкт та зону Ð´Ð»Ñ Ð²Ð¸Ð±Ð¾Ñ€Ñƒ типу машини"
msgid "Select project to choose zone"
-msgstr "Вибрати проект Ð´Ð»Ñ Ð²Ð¸Ð±Ð¾Ñ€Ñƒ зони"
+msgstr "Вибрати проєкт Ð´Ð»Ñ Ð²Ð¸Ð±Ð¾Ñ€Ñƒ зони"
msgid "Select projects"
-msgstr "Вибрати проекти"
+msgstr "Вибрати проєкти"
msgid "Select projects you want to import."
-msgstr "Виберіть проекти, Ñкі ви хочете імпортувати."
+msgstr "Виберіть проєкти, Ñкі ви хочете імпортувати."
msgid "Select required regulatory standard"
msgstr ""
@@ -22578,26 +23415,26 @@ msgstr ""
msgid "Select status"
msgstr ""
-msgid "Select strategy activation method"
+msgid "Select strategy activation method."
msgstr ""
msgid "Select subscription"
-msgstr ""
+msgstr "Виберіть підпиÑку"
msgid "Select target branch"
msgstr "Вибір цільової гілки"
msgid "Select the branch you want to set as the default for this project. All merge requests and commits will automatically be made against this branch unless you specify a different one."
-msgstr "Виберіть гілку по замовчанню Ð´Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ проекту. Ð’ÑÑ– запити на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ñ‚Ð° коміти будуть автоматично зроблені в ній, Ñкщо ви тільки не виберете іншу."
+msgstr "Виберіть гілку по замовчанню Ð´Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ проєкту. Ð’ÑÑ– запити на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ñ‚Ð° коміти будуть автоматично зроблені в ній, Ñкщо ви тільки не виберете іншу."
msgid "Select the custom project template source group."
-msgstr "Вкажіть групу, де розміщені влаÑні шаблони проектів."
+msgstr "Вкажіть групу, де розміщені влаÑні шаблони проєктів."
-msgid "Select timeframe"
-msgstr "Вибрати проміжок чаÑу"
+msgid "Select the environment scope for this feature flag."
+msgstr ""
msgid "Select timezone"
-msgstr ""
+msgstr "Обрати чаÑовий поÑÑ"
msgid "Select type"
msgstr ""
@@ -22606,10 +23443,10 @@ msgid "Select user"
msgstr "Вибрати кориÑтувача"
msgid "Selected commits"
-msgstr ""
+msgstr "Вибрані коміти"
msgid "Selected levels cannot be used by non-admin users for groups, projects or snippets. If the public level is restricted, user profiles are only visible to logged in users."
-msgstr "Вибрані рівні не можуть викориÑтовуватиÑÑ Ð½ÐµÐ°Ð´Ð¼Ñ–Ð½Ñ–Ñтраторами Ð´Ð»Ñ Ð³Ñ€ÑƒÐ¿, проектів або Ñніпетів. Якщо публічний рівень обмежений, профілі кориÑтувачів відображаютьÑÑ Ð»Ð¸ÑˆÐµ Ð´Ð»Ñ Ð·Ð°Ñ€ÐµÑ”Ñтрованих кориÑтувачів."
+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 ""
@@ -22666,7 +23503,7 @@ msgid "Send email notification"
msgstr ""
msgid "Send message"
-msgstr ""
+msgstr "ÐадіÑлати повідомленнÑ"
msgid "Send report"
msgstr "ÐадіÑлати звіт"
@@ -22825,7 +23662,7 @@ msgid "Set a password on your account to pull or push via %{protocol}."
msgstr "Ð’Ñтановіть пароль Ð´Ð»Ñ Ñвого облікового запиÑу, щоб мати можливіÑÑ‚ÑŒ відправлÑти та отримувати через %{protocol}."
msgid "Set a template repository for projects in this group"
-msgstr "Вибрати шаблон репозиторію Ð´Ð»Ñ Ð¿Ñ€Ð¾ÐµÐºÑ‚Ñ–Ð² у цій групі"
+msgstr "Вибрати шаблон репозиторію Ð´Ð»Ñ Ð¿Ñ€Ð¾Ñ”ÐºÑ‚Ñ–Ð² у цій групі"
msgid "Set an instance-wide domain that will be available to all clusters when installing Knative."
msgstr ""
@@ -22840,6 +23677,9 @@ msgid "Set instance-wide template repository"
msgstr "Ð’Ñтановити репозиторій шаблонів Ð´Ð»Ñ Ð²Ñього інÑтанÑу"
msgid "Set iteration"
+msgstr "Ð’Ñтановити ітерацію"
+
+msgid "Set limit to 0 to allow any file size."
msgstr ""
msgid "Set max session time for web terminal."
@@ -22882,7 +23722,7 @@ msgid "Set the duration for which the jobs will be considered as old and expired
msgstr ""
msgid "Set the iteration to %{iteration_reference}."
-msgstr ""
+msgstr "Ð’Ñтановлено ітерацію %{iteration_reference}."
msgid "Set the maximum file size for each job's artifacts"
msgstr "Ð’Ñтановити макÑимальний розмір файлу Ð´Ð»Ñ Ð°Ñ€Ñ‚ÐµÑ„Ð°ÐºÑ‚Ñ–Ð² кожного завданнÑ"
@@ -22920,11 +23760,14 @@ msgstr "Ðвтоматично налаштувати %{type} Runner"
msgid "Set up a %{type} Runner manually"
msgstr "Ðалаштуйте %{type} runner вручну"
+msgid "Set up a hardware device as a second factor to sign in."
+msgstr ""
+
msgid "Set up assertions/attributes/claims (email, first_name, last_name) and NameID according to %{docsLinkStart}the documentation %{icon}%{docsLinkEnd}"
msgstr "Ðалаштуйте твердженнÑ/атрибути (email, ім'Ñ, прізвище) Ñ– NameID відповідно до %{docsLinkStart} документації %{icon}%{docsLinkEnd}"
-msgid "Set up new U2F device"
-msgstr "Ðалаштувати новий приÑтрій U2F"
+msgid "Set up new device"
+msgstr ""
msgid "Set up new password"
msgstr "Ð’Ñтановити новий пароль"
@@ -22933,7 +23776,7 @@ msgid "Set up pipeline subscriptions for this project."
msgstr ""
msgid "Set up your project to automatically push and/or pull changes to/from another repository. Branches, tags, and commits will be synced automatically."
-msgstr "Ðалаштуйте Ñвій проект, щоб автоматично відправлÑти/отримувати зміни з іншого репозиторію. Гілки, теги та коміти автоматично будуть ÑинхронізуватиÑÑ."
+msgstr "Ðалаштуйте Ñвій проєкт, щоб автоматично відправлÑти/отримувати зміни з іншого репозиторію. Гілки, теги та коміти автоматично будуть ÑинхронізуватиÑÑ."
msgid "Set weight"
msgstr "Ð’Ñтановити вагу"
@@ -22992,6 +23835,9 @@ msgstr "Ð’Ñтановлює запланований Ñ‡Ð°Ñ %{time_estimate}."
msgid "Sets weight to %{weight}."
msgstr "Ð’Ñтановлювє вагу рівну %{weight}."
+msgid "Setting this to 0 means using the system default timeout value."
+msgstr ""
+
msgid "Settings"
msgstr "ÐалаштуваннÑ"
@@ -23007,6 +23853,15 @@ msgstr ""
msgid "Severity"
msgstr ""
+msgid "SeverityWidget|Severity"
+msgstr ""
+
+msgid "SeverityWidget|Severity: %{severity}"
+msgstr ""
+
+msgid "SeverityWidget|There was an error while updating severity."
+msgstr ""
+
msgid "Shards (%{shards})"
msgstr "Сегменти (%{shards})"
@@ -23023,7 +23878,7 @@ msgid "Shared Runners"
msgstr "Загальні Runner'и"
msgid "Shared projects"
-msgstr "Спільні проекти"
+msgstr "Спільні проєкти"
msgid "Shared runners help link"
msgstr "Допомога по загальним runner'ам"
@@ -23052,11 +23907,14 @@ msgstr "Показати вÑÑ–Ñ… учаÑників"
msgid "Show all requirements."
msgstr "Показати вÑÑ– вимоги."
+msgid "Show all test cases."
+msgstr ""
+
msgid "Show archived projects"
-msgstr "Показати архівовані проекти"
+msgstr "Показати архівовані проєкти"
msgid "Show archived projects only"
-msgstr "Показувати лише архівовані проекти"
+msgstr "Показувати лише архівовані проєкти"
msgid "Show command"
msgstr "Показати команду"
@@ -23064,6 +23922,9 @@ msgstr "Показати команду"
msgid "Show comments"
msgstr "Показати коментарі"
+msgid "Show comments on this file"
+msgstr ""
+
msgid "Show comments only"
msgstr "Показати тільки коментарі"
@@ -23074,13 +23935,13 @@ msgid "Show complete raw log"
msgstr "Показати повний неформатований журнал"
msgid "Show details"
-msgstr ""
+msgstr "Показати подробиці"
msgid "Show file browser"
msgstr "Показати файловий менеджер"
msgid "Show file contents"
-msgstr ""
+msgstr "Показати вміÑÑ‚ файлу"
msgid "Show latest version"
msgstr "Показати оÑтанню верÑÑ–ÑŽ"
@@ -23089,7 +23950,7 @@ msgid "Show list"
msgstr "Показати ÑпиÑок"
msgid "Show me everything"
-msgstr ""
+msgstr "Показати мені вÑе"
msgid "Show me how to add a pipeline"
msgstr ""
@@ -23109,6 +23970,12 @@ msgstr "Показати батьківÑькі Ñторінки"
msgid "Show parent subgroups"
msgstr "Показати батьківÑькі підгрупи"
+msgid "Show the Closed list"
+msgstr ""
+
+msgid "Show the Open list"
+msgstr ""
+
msgid "Show whitespace changes"
msgstr "Показати зміни пробілів"
@@ -23156,9 +24023,6 @@ msgstr "Поруч"
msgid "Sidebar|Assign health status"
msgstr ""
-msgid "Sidebar|Change weight"
-msgstr "Змінити вагу"
-
msgid "Sidebar|Health status"
msgstr ""
@@ -23304,10 +24168,10 @@ msgid "SlackService|See list of available commands in Slack after setting up thi
msgstr "ПереглÑньте ÑпиÑок уÑÑ–Ñ… доÑтупних команд у Slack піÑÐ»Ñ Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ñ†ÑŒÐ¾Ð³Ð¾ ÑервіÑу шлÑхом вводу"
msgid "SlackService|This service allows users to perform common operations on this project by entering slash commands in Slack."
-msgstr "Цей ÑÐµÑ€Ð²Ñ–Ñ Ð´Ð¾Ð·Ð²Ð¾Ð»ÑÑ” кориÑтувачам виконувати загальні операції в цьому проекті шлÑхом вводу команд із коÑою риÑкою (/) в Slack."
+msgstr "Цей ÑÐµÑ€Ð²Ñ–Ñ Ð´Ð¾Ð·Ð²Ð¾Ð»ÑÑ” кориÑтувачам виконувати загальні операції в цьому проєкті шлÑхом вводу команд із коÑою риÑкою (/) в Slack."
msgid "Slower but makes sure the project workspace is pristine as it clones the repository from scratch for every job"
-msgstr "Повільніше, але гарантує, що робоча облаÑÑ‚ÑŒ проекту чиÑтою, оÑкільки воно клонує Ñховище з Ð½ÑƒÐ»Ñ Ð´Ð»Ñ ÐºÐ¾Ð¶Ð½Ð¾Ð³Ð¾ завданнÑ"
+msgstr "Повільніше, але гарантує, що робоча облаÑÑ‚ÑŒ проєкту чиÑтою, оÑкільки воно клонує Ñховище з Ð½ÑƒÐ»Ñ Ð´Ð»Ñ ÐºÐ¾Ð¶Ð½Ð¾Ð³Ð¾ завданнÑ"
msgid "Smartcard"
msgstr "Смарт-карта"
@@ -23342,6 +24206,9 @@ msgstr "Ðемає Ñніпетів Ð´Ð»Ñ Ð²Ñ–Ð´Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ."
msgid "Snippets|Add another file %{num}/%{total}"
msgstr ""
+msgid "Snippets|Authored %{time_ago} by %{author}"
+msgstr ""
+
msgid "Snippets|Delete file"
msgstr ""
@@ -23352,7 +24219,7 @@ msgid "Snippets|File"
msgstr "Файл"
msgid "Snippets|Files"
-msgstr ""
+msgstr "Файли"
msgid "Snippets|Give your file a name to add code highlighting, e.g. example.rb for Ruby"
msgstr ""
@@ -23369,6 +24236,9 @@ msgstr "Snowplow"
msgid "Solution"
msgstr ""
+msgid "Some changes are not shown"
+msgstr ""
+
msgid "Some child epics may be hidden due to applied filters"
msgstr ""
@@ -23541,19 +24411,19 @@ msgid "Something went wrong, unable to add %{project} to dashboard"
msgstr "Проблема, не вдалоÑÑ Ð´Ð¾Ð´Ð°Ñ‚Ð¸ %{project} до панелі керуваннÑ"
msgid "Something went wrong, unable to add projects to dashboard"
-msgstr "СталаÑÑ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ°, не вдалоÑÑ Ð´Ð¾Ð´Ð°Ñ‚Ð¸ проекти до панелі"
+msgstr "СталаÑÑ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ°, не вдалоÑÑ Ð´Ð¾Ð´Ð°Ñ‚Ð¸ проєкти до панелі"
msgid "Something went wrong, unable to delete project"
msgstr ""
msgid "Something went wrong, unable to get projects"
-msgstr "Помилка, не вдалоÑÑ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ñ‚Ð¸ проекти"
+msgstr "Помилка, не вдалоÑÑ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ñ‚Ð¸ проєкти"
msgid "Something went wrong, unable to search projects"
-msgstr "Помилка, не вдалоÑÑ Ð·Ð´Ñ–Ð¹Ð½Ñтити пошук проектів"
+msgstr "Помилка, не вдалоÑÑ Ð·Ð´Ñ–Ð¹Ð½Ñтити пошук проєктів"
msgid "Something went wrong."
-msgstr ""
+msgstr "ЩоÑÑŒ пішло не так."
msgid "Something went wrong. Please try again."
msgstr "ЩоÑÑŒ пішло не так. Будь лаÑка Ñпробуйте ще раз."
@@ -23565,7 +24435,7 @@ msgid "Sorry, no epics matched your search"
msgstr "Вибачте, жоден епік не задовольнÑÑ” критеріÑм вашого пошуку"
msgid "Sorry, no projects matched your search"
-msgstr "Ðа жаль жоден проект не задовольнÑÑ” критеріÑм вашого пошуку"
+msgstr "Ðа жаль жоден проєкт не задовольнÑÑ” критеріÑм вашого пошуку"
msgid "Sorry, you have exceeded the maximum browsable page number. Please use the API to explore further."
msgstr ""
@@ -23735,6 +24605,12 @@ msgstr "Джерело"
msgid "Source (branch or tag)"
msgstr "Джерело (гілка або тег)"
+msgid "Source Branch"
+msgstr ""
+
+msgid "Source branch: %{source_branch_open}%{source_branch}%{source_branch_close}"
+msgstr ""
+
msgid "Source code"
msgstr "Код"
@@ -23859,16 +24735,16 @@ msgid "Starred Projects"
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 "Перейдіть до Ñторінки проекту та натиÑніть іконку із зірочкою. Тоді цей проект з’ÑвитьÑÑ Ð½Ð° цій Ñторінці."
+msgstr "Перейдіть до Ñторінки проєкту та натиÑніть іконку із зірочкою. Тоді цей проєкт з’ÑвитьÑÑ Ð½Ð° цій Ñторінці."
msgid "StarredProjectsEmptyState|You don't have starred projects yet."
-msgstr "Ви не маєте проектів доданих у обране."
+msgstr "Ви не маєте проєктів доданих у обране."
msgid "Starrers"
msgstr "Додали в обране"
@@ -23877,7 +24753,7 @@ msgid "Stars"
msgstr "У обраному"
msgid "Start Date"
-msgstr ""
+msgstr "Дата початку"
msgid "Start Web Terminal"
msgstr "ЗапуÑтити Веб-Термінал"
@@ -23900,11 +24776,8 @@ msgstr "Розпочати перевірку"
msgid "Start and due date"
msgstr "Дата початку та завершеннÑ"
-msgid "Start by choosing a group to see how your team is spending time. You can then drill down to the project level."
-msgstr "Розпочніть із вибору групи Ð´Ð»Ñ Ñ‚Ð¾Ð³Ð¾, щоб побачити на що ваша команда витрачає чаÑ. Далі ви зможете переходити на рівень проектів."
-
msgid "Start by choosing a group to start exploring the merge requests in that group. You can then proceed to filter by projects, labels, milestones and authors."
-msgstr "Розпочніть із вибору групи Ð´Ð»Ñ Ñ‚Ð¾Ð³Ð¾ що переглÑдати Ñ—Ñ— запити на злиттÑ. Далі ви зможете накладати фільтри за проектами, мітками, етапами та авторами."
+msgstr "Розпочніть із вибору групи Ð´Ð»Ñ Ñ‚Ð¾Ð³Ð¾ що переглÑдати Ñ—Ñ— запити на злиттÑ. Далі ви зможете накладати фільтри за проєктами, мітками, етапами та авторами."
msgid "Start cleanup"
msgstr "Почати очищеннÑ"
@@ -23955,7 +24828,7 @@ msgid "Started asynchronous removal of all repository check states."
msgstr "ÐÑинхронне Ð²Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ ÑƒÑÑ–Ñ… Ñтанів перевірок репозиторіїв запущено."
msgid "Started:"
-msgstr ""
+msgstr "Розпочато:"
msgid "Starting..."
msgstr "ЗапуÑк..."
@@ -23984,18 +24857,27 @@ msgstr ""
msgid "StaticSiteEditor|3. Assign a person to review and accept the merge request."
msgstr ""
+msgid "StaticSiteEditor|A link to view the merge request will appear once ready."
+msgstr ""
+
msgid "StaticSiteEditor|An error occurred while submitting your changes."
msgstr ""
msgid "StaticSiteEditor|Branch could not be created."
msgstr ""
+msgid "StaticSiteEditor|Copy update"
+msgstr ""
+
msgid "StaticSiteEditor|Could not commit the content changes."
msgstr ""
msgid "StaticSiteEditor|Could not create merge request."
msgstr ""
+msgid "StaticSiteEditor|Creating your merge request"
+msgstr ""
+
msgid "StaticSiteEditor|Incompatible file content"
msgstr ""
@@ -24017,6 +24899,9 @@ msgstr ""
msgid "StaticSiteEditor|View documentation"
msgstr ""
+msgid "StaticSiteEditor|You can set an assignee to get your changes reviewed and deployed once your merge request is created."
+msgstr ""
+
msgid "StaticSiteEditor|Your merge request has been created"
msgstr ""
@@ -24141,20 +25026,20 @@ msgid "Subkeys"
msgstr "Підключі"
msgid "Submit"
-msgstr ""
+msgstr "ÐадіÑлати"
msgid "Submit %{humanized_resource_name}"
msgstr ""
-msgid "Submit Changes"
-msgstr ""
-
msgid "Submit a review"
-msgstr ""
+msgstr "ÐадіÑлати відгук"
msgid "Submit as spam"
msgstr "Позначити Ñк Ñпам"
+msgid "Submit changes"
+msgstr ""
+
msgid "Submit feedback"
msgstr "ÐадіÑлати відгук"
@@ -24180,7 +25065,7 @@ msgid "Subscribe at group level"
msgstr "ПідпиÑатиÑÑ Ð½Ð° рівні групи"
msgid "Subscribe at project level"
-msgstr "ПідпиÑатиÑÑ Ð½Ð° рівні проекту"
+msgstr "ПідпиÑатиÑÑ Ð½Ð° рівні проєкту"
msgid "Subscribe to RSS feed"
msgstr "ПідпиÑатиÑÑ Ð½Ð° RSS-канал"
@@ -24282,7 +25167,7 @@ msgid "SubscriptionTable|Usage count is performed once a day at 12:00 PM."
msgstr "Облік викориÑÑ‚Ð°Ð½Ð½Ñ Ð²Ð¸ÐºÐ¾Ð½ÑƒÑ”Ñ‚ÑŒÑÑ Ð¾Ð´Ð¸Ð½ раз на день о 12:00."
msgid "Subscriptions"
-msgstr ""
+msgstr "ПідпиÑки"
msgid "Subtracted"
msgstr "ВіднÑто"
@@ -24308,6 +25193,9 @@ msgstr "УÑпішно деактивовано"
msgid "Successfully deleted U2F device."
msgstr "УÑпішно видалено приÑтрій U2F."
+msgid "Successfully deleted WebAuthn device."
+msgstr ""
+
msgid "Successfully removed email."
msgstr "УÑпішно видалено адреÑу електронної пошти."
@@ -24450,7 +25338,7 @@ msgid "Sync information"
msgstr "Ð†Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ñ–Ñ Ð¿Ñ€Ð¾ Ñинхронізацію"
msgid "Synced"
-msgstr ""
+msgstr "Синхронізовано"
msgid "Synchronization disabled"
msgstr ""
@@ -24495,7 +25383,7 @@ msgid "Tag name"
msgstr "Ðазва тегу"
msgid "Tag name is required"
-msgstr ""
+msgstr "Ðеобхідно вказати назву тегу"
msgid "Tag this commit."
msgstr "Додати тег до цього коміту."
@@ -24626,9 +25514,6 @@ msgstr "Шаблон"
msgid "Template to append to all Service Desk issues"
msgstr "Шаблон Ð´Ð»Ñ Ð´Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ð´Ð¾ вÑÑ–Ñ… задач Service Desk"
-msgid "Template was successfully saved."
-msgstr "Шаблон уÑпішно збережено."
-
msgid "Templates"
msgstr "Шаблони"
@@ -24713,32 +25598,50 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "Test failed."
-msgstr "ТеÑÑ‚ не пройдено."
+msgid "Test settings"
+msgstr ""
+
+msgid "TestCases|New Test Case"
+msgstr ""
+
+msgid "TestCases|New test case"
+msgstr ""
+
+msgid "TestCases|Search test cases"
+msgstr ""
+
+msgid "TestCases|Something went wrong while creating a test case."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching count of test cases."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching test cases list."
+msgstr ""
-msgid "Test settings and save changes"
-msgstr "ПротеÑтувати налаштуванні та зберегти зміни"
+msgid "TestCases|Submit test case"
+msgstr ""
msgid "TestHooks|Ensure one of your projects has merge requests."
-msgstr "ПереконайтеÑÑ, що один із ваших проектів має запити на злиттÑ."
+msgstr "ПереконайтеÑÑ, що один із ваших проєктів має запити на злиттÑ."
msgid "TestHooks|Ensure the project has CI jobs."
-msgstr "ПереконайтеÑÑ, що проект має CI завданнÑ."
+msgstr "ПереконайтеÑÑ, що проєкт має CI завданнÑ."
msgid "TestHooks|Ensure the project has CI pipelines."
-msgstr "ПереконайтеÑÑ, що проект має CI конвеєри."
+msgstr "ПереконайтеÑÑ, що проєкт має CI конвеєри."
msgid "TestHooks|Ensure the project has deployments."
msgstr ""
msgid "TestHooks|Ensure the project has issues."
-msgstr "ПереконайтеÑÑ, що проект має задачі."
+msgstr "ПереконайтеÑÑ, що проєкт має задачі."
msgid "TestHooks|Ensure the project has merge requests."
-msgstr "ПереконайтеÑÑ, що проект має запити на злиттÑ."
+msgstr "ПереконайтеÑÑ, що проєкт має запити на злиттÑ."
msgid "TestHooks|Ensure the project has notes."
-msgstr "ПереконайтеÑÑ, що проект має нотатки."
+msgstr "ПереконайтеÑÑ, що проєкт має нотатки."
msgid "TestHooks|Ensure the wiki is enabled and has pages."
msgstr "ПереконайтеÑÑ, що вікі увімкнено Ñ– вона має Ñторінки."
@@ -24782,6 +25685,9 @@ msgstr "ТеÑти"
msgid "Thank you for signing up for your free trial! You will get additional instructions in your inbox shortly."
msgstr "ДÑкуємо, що зареєÑтрувалиÑÑŒ на безкоштовну пробну верÑÑ–ÑŽ! Ðезабаром ви отримаєте додаткові вказівки у поштовій Ñкриньці."
+msgid "Thank you for your business."
+msgstr ""
+
msgid "Thank you for your feedback!"
msgstr ""
@@ -24829,10 +25735,10 @@ msgid "The GitLab user to which the Jira user %{jiraDisplayName} will be mapped"
msgstr ""
msgid "The Issue Tracker is the place to add things that need to be improved or solved in a project"
-msgstr "Трекер задач — це міÑце, де можна додати речі, Ñкі потрібно покращити або розв’Ñзати в проекті"
+msgstr "Трекер задач — це міÑце, де можна додати речі, Ñкі потрібно покращити або розв’Ñзати в проєкті"
msgid "The Issue Tracker is the place to add things that need to be improved or solved in a project. You can register or sign in to create issues for this project."
-msgstr "Трекер задач — це міÑце, де можна додати речі, Ñкі потрібно покращити або розв’Ñзати в проекті. Ви можете зареєÑтруватиÑÑ Ð°Ð±Ð¾ увійти, щоб Ñтворювати задачу в цьому проекті."
+msgstr "Трекер задач — це міÑце, де можна додати речі, Ñкі потрібно покращити або розв’Ñзати в проєкті. Ви можете зареєÑтруватиÑÑ Ð°Ð±Ð¾ увійти, щоб Ñтворювати задачу в цьому проєкті."
msgid "The Prometheus server responded with \"bad request\". Please check your queries are correct and are supported in your Prometheus version. %{documentationLink}"
msgstr ""
@@ -24843,9 +25749,6 @@ msgstr ""
msgid "The URL to use for connecting to Elasticsearch. Use a comma-separated list to support clustering (e.g., \"http://localhost:9200, http://localhost:9201\")."
msgstr "URL-адреÑа Ð´Ð»Ñ Ð¿Ñ–Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð½Ñ Ð´Ð¾ Elasticsearch. ВикориÑтовуйте ÑпиÑок, розділений комами, Ð´Ð»Ñ Ð¿Ñ–Ð´Ñ‚Ñ€Ð¸Ð¼ÐºÐ¸ клаÑтеризації (наприклад: \"http://localhost:9200, http://localhost:9201\")."
-msgid "The Web IDE offers advanced syntax highlighting capabilities and more."
-msgstr ""
-
msgid "The X509 Certificate to use when mutual TLS is required to communicate with the external authorization service. If left blank, the server certificate is still validated when accessing over HTTPS."
msgstr "Сертифікат X509 викориÑтовуєтьÑÑ Ð´Ð»Ñ Ð²Ð·Ð°Ñ”Ð¼Ð½Ð¾Ñ— перевірки автентичноÑÑ‚Ñ– TLS Ñ– необхідний Ð´Ð»Ñ Ð·Ð²'Ñзку з зовнішньою Ñлужбою авторизації. Якщо залишити порожнім, Ñертифікат Ñервера буде перевірÑтиÑÑŒ при доÑтупі через HTTPS."
@@ -24859,7 +25762,7 @@ msgid "The associated issue #%{issueId} has been closed as the error is now reso
msgstr ""
msgid "The branch for this project has no active pipeline configuration."
-msgstr "Ð¦Ñ Ð³Ñ–Ð»ÐºÐ° Ð´Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ проекту не має активної конфігурації конвеєра."
+msgstr "Ð¦Ñ Ð³Ñ–Ð»ÐºÐ° Ð´Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ проєкту не має активної конфігурації конвеєра."
msgid "The branch or tag does not exist"
msgstr ""
@@ -24898,7 +25801,7 @@ msgid "The default CI configuration path for new projects."
msgstr "ШлÑÑ… конфігурації CI за замовчуваннÑм Ð´Ð»Ñ Ð½Ð¾Ð²Ð¸Ñ… проєктів."
msgid "The dependency list details information about the components used within your project."
-msgstr "СпиÑок залежноÑтей міÑтить детальну інформацію про компоненти, що викориÑтовуютьÑÑ Ñƒ вашому проекті."
+msgstr "СпиÑок залежноÑтей міÑтить детальну інформацію про компоненти, що викориÑтовуютьÑÑ Ñƒ вашому проєкті."
msgid "The deployment of this job to %{environmentLink} did not succeed."
msgstr "Ð Ð¾Ð·Ð³Ð¾Ñ€Ñ‚Ð°Ð½Ð½Ñ Ñ†ÑŒÐ¾Ð³Ð¾ Ð·Ð°Ð²Ð´Ð°Ð½Ð½Ñ Ð½Ð° %{environmentLink} не уÑпішне."
@@ -24958,17 +25861,20 @@ msgstr "Зв'Ñзок форку видалено."
msgid "The form contains the following error:"
msgstr ""
+msgid "The form contains the following warning:"
+msgstr ""
+
msgid "The global settings require you to enable Two-Factor Authentication for your account."
msgstr "Глобальні Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð²Ð¸Ð¼Ð°Ð³Ð°ÑŽÑ‚ÑŒ, щоб ви увімкнули двофакторну автентифікацію Ð´Ð»Ñ Ñвого облікового запиÑу."
msgid "The group and any internal projects can be viewed by any logged in user."
-msgstr "Ð¦Ñ Ð³Ñ€ÑƒÐ¿Ð° та вÑÑ– Ñ—Ñ— внутрішні проекти можуть бути переглÑнуті будь Ñким кориÑтувачем, що здійÑнив вхід у ÑиÑтему."
+msgstr "Ð¦Ñ Ð³Ñ€ÑƒÐ¿Ð° та вÑÑ– Ñ—Ñ— внутрішні проєкти можуть бути переглÑнуті будь Ñким кориÑтувачем, що здійÑнив вхід у ÑиÑтему."
msgid "The group and any public projects can be viewed without any authentication."
-msgstr "Ð¦Ñ Ð³Ñ€ÑƒÐ¿Ð° та будь-Ñкі проекти можуть переглÑдатиÑÑ Ð±ÐµÐ· жодної автентифікації."
+msgstr "Ð¦Ñ Ð³Ñ€ÑƒÐ¿Ð° та будь-Ñкі проєкти можуть переглÑдатиÑÑ Ð±ÐµÐ· жодної автентифікації."
msgid "The group and its projects can only be viewed by members."
-msgstr "Ð¦Ñ Ð³Ñ€ÑƒÐ¿Ð° та Ñ—Ñ— проекти видимі тільки Ð´Ð»Ñ ÑƒÑ‡Ð°Ñників."
+msgstr "Ð¦Ñ Ð³Ñ€ÑƒÐ¿Ð° та Ñ—Ñ— проєкти видимі тільки Ð´Ð»Ñ ÑƒÑ‡Ð°Ñників."
msgid "The group can be fully restored"
msgstr "Цю групу можна повніÑÑ‚ÑŽ відновити"
@@ -25064,7 +25970,7 @@ msgid "The pipeline has been deleted"
msgstr "Конвеєр було видалено"
msgid "The pipelines schedule runs pipelines in the future, repeatedly, for specific branches or tags. Those scheduled pipelines will inherit limited project access based on their associated user."
-msgstr "Розклад конвеєрів запуÑкає Ñ—Ñ… в майбутньому, Ð´Ð»Ñ Ð¿ÐµÐ²Ð½Ð¸Ñ… гілок або тегів. Заплановані конвеєри уÑпадковують Ð¾Ð±Ð¼ÐµÐ¶ÐµÐ½Ð½Ñ Ð½Ð° доÑтуп до проекту на оÑнові пов'Ñзаного з ними кориÑтувача."
+msgstr "Розклад конвеєрів запуÑкає Ñ—Ñ… в майбутньому, Ð´Ð»Ñ Ð¿ÐµÐ²Ð½Ð¸Ñ… гілок або тегів. Заплановані конвеєри уÑпадковують Ð¾Ð±Ð¼ÐµÐ¶ÐµÐ½Ð½Ñ Ð½Ð° доÑтуп до проєкту на оÑнові пов'Ñзаного з ними кориÑтувача."
msgid "The planning stage shows the time from the previous step to pushing your first commit. This time will be added automatically once you push your first commit."
msgstr "Ð¡Ñ‚Ð°Ð´Ñ–Ñ ÐŸÐ»Ð°Ð½ÑƒÐ²Ð°Ð½Ð½Ñ Ð²Ñ–Ð´Ð¾Ð±Ñ€Ð°Ð¶Ð°Ñ” Ñ‡Ð°Ñ Ð²Ñ–Ð´ попереднього кроку до першого коміту. ДодаєтьÑÑ Ð°Ð²Ñ‚Ð¾Ð¼Ð°Ñ‚Ð¸Ñ‡Ð½Ð¾, Ñк тільки відправитьÑÑ Ð¿ÐµÑ€ÑˆÐ¸Ð¹ коміт."
@@ -25072,32 +25978,29 @@ msgstr "Ð¡Ñ‚Ð°Ð´Ñ–Ñ ÐŸÐ»Ð°Ð½ÑƒÐ²Ð°Ð½Ð½Ñ Ð²Ñ–Ð´Ð¾Ð±Ñ€Ð°Ð¶Ð°Ñ” Ñ‡Ð°Ñ Ð²Ñ–Ð´ пÐ
msgid "The private key to use when a client certificate is provided. This value is encrypted at rest."
msgstr "Приватний ключ, Ñкий викориÑтовуєтьÑÑ Ð¿Ñ€Ð¸ наданні клієнтÑького Ñертифіката. Його Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð·Ð°ÑˆÐ¸Ñ„Ñ€Ð¾Ð²Ð°Ð½Ð¾."
-msgid "The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr "Ð¡Ñ‚Ð°Ð´Ñ–Ñ Production показує загальний Ñ‡Ð°Ñ Ð¼Ñ–Ð¶ ÑтвореннÑм задачі та розгортаннÑм коду у production. Дані будуть автоматично додані піÑÐ»Ñ Ð·Ð°Ð²ÐµÑ€ÑˆÐµÐ½Ð½Ñ Ð¿Ð¾Ð²Ð½Ð¾Ñ— ідеї до production циклу."
-
msgid "The project can be accessed by any logged in user."
-msgstr "ДоÑтуп до проекту можливий будь-Ñким зареєÑтрованим кориÑтувачем."
+msgstr "ДоÑтуп до проєкту можливий будь-Ñким зареєÑтрованим кориÑтувачем."
msgid "The project can be accessed by any user who is logged in."
-msgstr "ДоÑтуп до цього проекту Ñ” в будь-Ñкого кориÑтувача, Ñкий увійшов у ÑиÑтему."
+msgstr "ДоÑтуп до цього проєкту Ñ” в будь-Ñкого кориÑтувача, Ñкий увійшов у ÑиÑтему."
msgid "The project can be accessed by anyone, regardless of authentication."
-msgstr "ДоÑтуп до проекту Ñ” в будь-кого, незалежно від автентифікації."
+msgstr "ДоÑтуп до проєкту Ñ” в будь-кого, незалежно від автентифікації."
msgid "The project can be accessed without any authentication."
-msgstr "ДоÑтуп до проекту можливий без будь-Ñкої перевірки автентичноÑÑ‚Ñ–."
+msgstr "ДоÑтуп до проєкту можливий без будь-Ñкої перевірки автентичноÑÑ‚Ñ–."
msgid "The project has already been added to your dashboard."
msgstr ""
msgid "The project is accessible only by members of the project. Access must be granted explicitly to each user."
-msgstr "Цей проект доÑтупний тільки Ð´Ð»Ñ Ð¹Ð¾Ð³Ð¾ учаÑників. ДоÑтуп може бути надано тільки безпоÑередньо кожному кориÑтувачу."
+msgstr "Цей проєкт доÑтупний тільки Ð´Ð»Ñ Ð¹Ð¾Ð³Ð¾ учаÑників. ДоÑтуп може бути надано тільки безпоÑередньо кожному кориÑтувачу."
msgid "The project is still being deleted. Please try again later."
msgstr "Проект вÑе ще видалÑєтьÑÑ. Будь лаÑка, Ñпробуйте знову."
msgid "The project was successfully forked."
-msgstr "УÑпішно Ñтворено форк проекту."
+msgstr "УÑпішно Ñтворено форк проєкту."
msgid "The project was successfully imported."
msgstr "Проект уÑпішно імпортовано."
@@ -25111,14 +26014,14 @@ msgstr "Віддалене дзеркало зайнÑло забагато ча
msgid "The remote repository is being updated..."
msgstr "Віддалений репозиторій в процеÑÑ– оновленнÑ..."
-msgid "The repository can be commited to, and issues, comments and other entities can be created."
+msgid "The repository can be committed to, and issues, comments and other entities can be created."
msgstr ""
msgid "The repository for this project does not exist."
-msgstr "Репозиторій Ð´Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ проекту не Ñ–Ñнує."
+msgstr "Репозиторій Ð´Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ проєкту не Ñ–Ñнує."
msgid "The repository for this project is empty"
-msgstr "Репозиторій цього проекту порожній"
+msgstr "Репозиторій цього проєкту порожній"
msgid "The repository is being updated..."
msgstr "Репозиторій оновлюєтьÑÑ..."
@@ -25145,7 +26048,7 @@ msgid "The snippet is visible only to me."
msgstr "Цей Ñніпет Ñ” видим лише Ð´Ð»Ñ Ð¼ÐµÐ½Ðµ."
msgid "The snippet is visible only to project members."
-msgstr "Цей Ñніпет видимий тільки Ð´Ð»Ñ ÑƒÑ‡Ð°Ñників проекту."
+msgstr "Цей Ñніпет видимий тільки Ð´Ð»Ñ ÑƒÑ‡Ð°Ñників проєкту."
msgid "The snippet is visible to any logged in user."
msgstr "Цей Ñніпет видимий Ð´Ð»Ñ Ð±ÑƒÐ´ÑŒ-Ñкого зареєÑтрованого кориÑтувача."
@@ -25165,9 +26068,6 @@ msgstr "Ð¡Ñ‚Ð°Ð´Ñ–Ñ Ð¢ÐµÑÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð¿Ð¾ÐºÐ°Ð·ÑƒÑ” чаÑ, Ñкий GitLab
msgid "The time taken by each data entry gathered by that stage."
msgstr "ЧаÑ, витрачений на кожен елемент, зібраний на цій Ñтадії."
-msgid "The total stage shows the time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The update action will time out after %{number_of_minutes} minutes. For big repositories, use a clone/push combination."
msgstr "Ð§Ð°Ñ Ð´Ñ–Ñ— Ð¾Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ñплине через %{number_of_minutes} хвилин. Ð”Ð»Ñ Ð²ÐµÐ»Ð¸ÐºÐ¸Ñ… репозиторіїв викориÑтовуйте комбінацію clone/push."
@@ -25181,13 +26081,13 @@ msgid "The user is being deleted."
msgstr "КориÑтувач видалÑєтьÑÑ."
msgid "The user map has been saved. Continue by selecting the projects you want to import."
-msgstr "Мапу кориÑтувачів збережено. Ð”Ð»Ñ Ð¿Ñ€Ð¾Ð´Ð¾Ð²Ð¶ÐµÐ½Ð½Ñ Ð²Ð¸Ð±ÐµÑ€Ñ–Ñ‚ÑŒ проекти Ð´Ð»Ñ Ñ–Ð¼Ð¿Ð¾Ñ€Ñ‚Ñƒ."
+msgstr "Мапу кориÑтувачів збережено. Ð”Ð»Ñ Ð¿Ñ€Ð¾Ð´Ð¾Ð²Ð¶ÐµÐ½Ð½Ñ Ð²Ð¸Ð±ÐµÑ€Ñ–Ñ‚ÑŒ проєкти Ð´Ð»Ñ Ñ–Ð¼Ð¿Ð¾Ñ€Ñ‚Ñƒ."
msgid "The user map is a JSON document mapping the Google Code users that participated on your projects to the way their email addresses and usernames will be imported into GitLab. You can change this by changing the value on the right hand side of %{code_open}:%{code_close}. Be sure to preserve the surrounding double quotes, other punctuation and the email address or username on the left hand side."
msgstr ""
msgid "The user map is a mapping of the FogBugz users that participated on your projects to the way their email address and usernames will be imported into GitLab. You can change this by populating the table below."
-msgstr "Мапа кориÑтувачів — це правила Ñ–Ð¼Ð¿Ð¾Ñ€Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ ÐºÐ¾Ñ€Ð¸Ñтувачів FogBugz, Ñкі приймали учаÑÑ‚ÑŒ у ваших проектах до Gitlab (зокрема Ñ—Ñ… імен та Ð°Ð´Ñ€ÐµÑ ÐµÐ»ÐµÐºÑ‚Ñ€Ð¾Ð½Ð½Ð¾Ñ— пошти). Ви можете вноÑити зміни шлÑхом Ð·Ð°Ð¿Ð¾Ð²Ð½ÐµÐ½Ð½Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ– нижче."
+msgstr "Мапа кориÑтувачів — це правила Ñ–Ð¼Ð¿Ð¾Ñ€Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ ÐºÐ¾Ñ€Ð¸Ñтувачів FogBugz, Ñкі приймали учаÑÑ‚ÑŒ у ваших проєктах до Gitlab (зокрема Ñ—Ñ… імен та Ð°Ð´Ñ€ÐµÑ ÐµÐ»ÐµÐºÑ‚Ñ€Ð¾Ð½Ð½Ð¾Ñ— пошти). Ви можете вноÑити зміни шлÑхом Ð·Ð°Ð¿Ð¾Ð²Ð½ÐµÐ½Ð½Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ– нижче."
msgid "The user you are trying to deactivate has been active in the past %{minimum_inactive_days} days and cannot be deactivated"
msgstr "КориÑтувач Ñкого ви збираєтеÑÑ Ð´ÐµÐ°ÐºÑ‚Ð¸Ð²ÑƒÐ²Ð°Ñ‚Ð¸ був активним протÑгом оÑтанніх %{minimum_inactive_days} днів Ñ– не може бути деактивований"
@@ -25226,11 +26126,14 @@ msgid "There are no SSH keys with access to your account."
msgstr "Ðемає SSH ключів, що мають доÑтуп до вашого облікового запиÑу."
msgid "There are no archived projects yet"
-msgstr "Ðаразі немає жодного архівованого проекту"
+msgstr "Ðаразі немає жодного архівованого проєкту"
msgid "There are no archived requirements"
msgstr "Ðемає жодних архівних вимог"
+msgid "There are no archived test cases"
+msgstr ""
+
msgid "There are no changes"
msgstr "Зміни відÑутні"
@@ -25247,7 +26150,7 @@ msgid "There are no commits yet."
msgstr ""
msgid "There are no custom project templates set up for this GitLab instance. They are enabled from GitLab's Admin Area. Contact your GitLab instance administrator to setup custom project templates."
-msgstr "ВлаÑні шаблони проектів не налаштовані Ð´Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ Ñерверу GitLab. Вони активуютьÑÑ Ð½Ð° Ñторінці адмініÑÑ‚Ñ€ÑƒÐ²Ð°Ð½Ð½Ñ GitLab. ЗвернітьÑÑ Ð´Ð¾ адмініÑтратора GitLab Ð´Ð»Ñ Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð²Ð»Ð°Ñних шаблонів проектів."
+msgstr "ВлаÑні шаблони проєктів не налаштовані Ð´Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ Ñерверу GitLab. Вони активуютьÑÑ Ð½Ð° Ñторінці адмініÑÑ‚Ñ€ÑƒÐ²Ð°Ð½Ð½Ñ GitLab. ЗвернітьÑÑ Ð´Ð¾ адмініÑтратора GitLab Ð´Ð»Ñ Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð²Ð»Ð°Ñних шаблонів проєктів."
msgid "There are no issues to show"
msgstr "Ðемає задач Ð´Ð»Ñ Ð²Ñ–Ð´Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ"
@@ -25270,6 +26173,9 @@ msgstr "Відкритих запитів на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð½ÐµÐ¼Ð°Ñ”"
msgid "There are no open requirements"
msgstr "Відкриті вимоги відÑутні"
+msgid "There are no open test cases"
+msgstr ""
+
msgid "There are no packages yet"
msgstr "Ðаразі пакети відÑутні"
@@ -25282,6 +26188,9 @@ msgstr ""
msgid "There is a limit of %{ci_project_subscriptions_limit} subscriptions from or to a project."
msgstr ""
+msgid "There is already a To-Do for this design."
+msgstr ""
+
msgid "There is already a repository with that name on disk"
msgstr "Ðа диÑку вже Ñ–Ñнує репозиторій за таким ім’Ñм"
@@ -25300,6 +26209,9 @@ msgstr ""
msgid "There was a problem communicating with your device."
msgstr "Проблема Ð¿Ñ–Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð½Ñ Ð´Ð¾ вашого приÑтрою."
+msgid "There was a problem fetching branches."
+msgstr ""
+
msgid "There was a problem fetching groups."
msgstr ""
@@ -25493,7 +26405,7 @@ msgid "Third party offers"
msgstr "Сторонні пропозиції"
msgid "This %{issuableDisplayName} is locked. Only project members can comment."
-msgstr "Ð¦Ñ %{issuableDisplayName} заблокована. Лише учаÑники проекту можуть коментувати."
+msgstr "Ð¦Ñ %{issuableDisplayName} заблокована. Лише учаÑники проєкту можуть коментувати."
msgid "This %{issuableType} is confidential"
msgstr ""
@@ -25528,9 +26440,15 @@ msgstr ""
msgid "This action can lead to data loss. To prevent accidental actions we ask you to confirm your intention."
msgstr "Ð¦Ñ Ð´Ñ–Ñ Ð¼Ð¾Ð¶Ðµ призвеÑти до втрати даних. Щоб уникнути випадкових дій, проÑимо Ð²Ð°Ñ Ð¿Ñ–Ð´Ñ‚Ð²ÐµÑ€Ð´Ð¸Ñ‚Ð¸ Ñвій намір."
+msgid "This action cannot be undone, and will permanently delete the %{key} SSH key"
+msgstr ""
+
msgid "This action cannot be undone. You will lose the project's repository and all content: issues, merge requests, etc."
msgstr ""
+msgid "This action has been performed too many times. Try again later."
+msgstr ""
+
msgid "This action will %{strongOpen}permanently delete%{strongClose} %{codeOpen}%{project}%{codeClose} %{strongOpen}immediately%{strongClose}, including its repositories and all content: issues, merge requests, etc."
msgstr ""
@@ -25558,9 +26476,6 @@ msgstr "Цей блок поÑилаєтьÑÑ Ñам на Ñебе"
msgid "This board's scope is reduced"
msgstr "ВидиміÑÑ‚ÑŒ цієї дошки обмежена"
-msgid "This branch has changed since you started editing. Would you like to create a new branch?"
-msgstr "Ð¦Ñ Ð³Ñ–Ð»ÐºÐ° була змінена піÑÐ»Ñ Ñ‚Ð¾Ð³Ð¾ моменту, коли ви почали Ñ—Ñ— редагувати. Ви хотіли б Ñтворити нову?"
-
msgid "This chart could not be displayed"
msgstr "Ð¦Ñ Ð´Ñ–Ð°Ð³Ñ€Ð°Ð¼Ð° не може бути відображена"
@@ -25687,15 +26602,9 @@ msgstr "Це ÑпиÑок приÑтроїв, з котрих заходили Ð
msgid "This is a security log of important events involving your account."
msgstr "Це журнал безпеки, Ñкий міÑтить уÑÑ– важливі події пов’Ñзані із вашим обліковим запиÑом."
-msgid "This is the author's first Merge Request to this project."
-msgstr "Це перший запит на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð²Ñ–Ð´ цього автора Ð´Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ проекту."
-
msgid "This is the highest peak of users on your installation since the license started."
msgstr ""
-msgid "This is the maximum number of users that have existed at the same time since the license started. This is the minimum number of seats you will need to buy when you renew your license."
-msgstr "Це макÑимальна кількіÑÑ‚ÑŒ кориÑтувачів, Ñкі Ñ–Ñнували одночаÑно з моменту початку ліцензії. Це мінімальна кількіÑÑ‚ÑŒ міÑць, Ñкі потрібно придбати при продовженні ліцензії."
-
msgid "This is the number of currently active users on your installation, and this is the minimum number you need to purchase when you renew your license."
msgstr ""
@@ -25835,7 +26744,7 @@ msgid "This option is only available on GitLab.com"
msgstr "Ð¦Ñ Ð¼Ð¾Ð¶Ð»Ð¸Ð²Ñ–ÑÑ‚ÑŒ доÑтупна тільки на GitLab.com"
msgid "This page is unavailable because you are not allowed to read information across multiple projects."
-msgstr "Ð¦Ñ Ñторінка недоÑтупна, тому що ви не можете переглÑдати інформацію по кількох проектах."
+msgstr "Ð¦Ñ Ñторінка недоÑтупна, тому що ви не можете переглÑдати інформацію по кількох проєктах."
msgid "This page sends a payload. Go back to the events page to see a newly created event."
msgstr ""
@@ -25856,19 +26765,19 @@ msgid "This project"
msgstr "Цей проєкт"
msgid "This project does not belong to a group and can therefore not make use of group Runners."
-msgstr "Цей проект не входить до жодної групи Ñ– тому не може викориÑтовувати групові Runner’и."
+msgstr "Цей проєкт не входить до жодної групи Ñ– тому не може викориÑтовувати групові Runner’и."
msgid "This project does not have %{service_desk_link_start}Service Desk%{service_desk_link_end} enabled, so the user who created the issue will no longer receive email notifications about new activity."
msgstr ""
msgid "This project does not have a wiki homepage yet"
-msgstr "Ð”Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ проекту немає домашньої Ñторінки вікі"
+msgstr "Ð”Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ проєкту немає домашньої Ñторінки вікі"
msgid "This project has no active access tokens."
msgstr ""
msgid "This project is archived and cannot be commented on."
-msgstr "Цей проект заархівовано і його не можна коментувати."
+msgstr "Цей проєкт заархівовано і його не можна коментувати."
msgid "This project manages its dependencies using %{strong_start}%{manager_name}%{strong_end}"
msgstr ""
@@ -25904,7 +26813,7 @@ msgid "This runner will only run on pipelines triggered on protected branches"
msgstr "Цей runner буде виконуватиÑÑ Ñ‚Ñ–Ð»ÑŒÐºÐ¸ на тих конвеєрах, Ñкі Ñпрацьовують на захищених гілках"
msgid "This setting can be overridden in each project."
-msgstr "Цей параметр можна перевизначати Ð´Ð»Ñ ÐºÐ¾Ð¶Ð½Ð¾Ð³Ð¾ проекту."
+msgstr "Цей параметр можна перевизначати Ð´Ð»Ñ ÐºÐ¾Ð¶Ð½Ð¾Ð³Ð¾ проєкту."
msgid "This setting will update the hostname that is used to generate private commit emails. %{learn_more}"
msgstr "Цей параметр оновить назву хоÑта, Ñка викориÑтовуєтьÑÑ Ð´Ð»Ñ Ð³ÐµÐ½ÐµÑ€Ð°Ñ†Ñ–Ñ— приватних email-Ð°Ð´Ñ€ÐµÑ Ð² підпиÑах комітів. %{learn_more}"
@@ -25916,7 +26825,7 @@ msgid "This suggestion already matches its content."
msgstr ""
msgid "This timeout will take precedence when lower than project-defined timeout and accepts a human readable time input language like \"1 hour\". Values without specification represent seconds."
-msgstr "Цей Ñ‡Ð°Ñ Ð¾Ñ‡Ñ–ÐºÑƒÐ²Ð°Ð½Ð½Ñ Ð¼Ð°Ñ‚Ð¸Ð¼Ðµ перевагу у разі, Ñкщо він менший за той, Ñкий вÑтановлено на рівні проекту, також він підтримує \"людÑкий\" формат, наприклад \"1 hour\" (1 година). Ð—Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð±ÐµÐ· одиниць виміру предÑтавлÑÑŽÑ‚ÑŒ Ñекунди."
+msgstr "Цей Ñ‡Ð°Ñ Ð¾Ñ‡Ñ–ÐºÑƒÐ²Ð°Ð½Ð½Ñ Ð¼Ð°Ñ‚Ð¸Ð¼Ðµ перевагу у разі, Ñкщо він менший за той, Ñкий вÑтановлено на рівні проєкту, також він підтримує \"людÑкий\" формат, наприклад \"1 hour\" (1 година). Ð—Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð±ÐµÐ· одиниць виміру предÑтавлÑÑŽÑ‚ÑŒ Ñекунди."
msgid "This user cannot be unlocked manually from GitLab"
msgstr "Цей кориÑтувач не може бути розблокований вручну в GitLab"
@@ -25927,6 +26836,15 @@ msgstr ""
msgid "This user has no identities"
msgstr "Цей кориÑтувач не має ідентифікацій"
+msgid "This user has previously committed to the %{name} project."
+msgstr ""
+
+msgid "This user has the %{access} role in the %{name} project."
+msgstr ""
+
+msgid "This user is the author of this %{noteable}."
+msgstr ""
+
msgid "This user will be the author of all events in the activity feed that are the result of an update, like new branches being created or new commits being pushed to existing branches."
msgstr "Цей кориÑтувач буде автором вÑÑ–Ñ… подій в Ñтрічці активноÑÑ‚Ñ–, Ñка генеруєтьÑÑ Ð½Ð° оÑнові оновлень, таких Ñк ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð½Ð¾Ð²Ð¸Ñ… гілок чи нових комітів, Ñкі відправлÑтимутьÑÑ Ð² Ñ–Ñнуючі гілки."
@@ -25957,6 +26875,9 @@ msgstr ""
msgid "Threat Monitoring"
msgstr "Моніторинг Загроз"
+msgid "ThreatMonitoring|All Environments"
+msgstr ""
+
msgid "ThreatMonitoring|Anomalous Requests"
msgstr ""
@@ -25984,9 +26905,6 @@ msgstr ""
msgid "ThreatMonitoring|Operations Per Second"
msgstr ""
-msgid "ThreatMonitoring|Overview"
-msgstr ""
-
msgid "ThreatMonitoring|Packet Activity"
msgstr ""
@@ -26005,6 +26923,9 @@ msgstr ""
msgid "ThreatMonitoring|Something went wrong, unable to fetch statistics"
msgstr ""
+msgid "ThreatMonitoring|Statistics"
+msgstr ""
+
msgid "ThreatMonitoring|The firewall is not installed or has been disabled. To view this data, ensure the web application firewall is installed and enabled for your cluster."
msgstr ""
@@ -26320,7 +27241,7 @@ msgid "To further protect your account, consider configuring a two-factor authen
msgstr ""
msgid "To get started you enter your FogBugz URL and login information below. In the next steps, you'll be able to map users and select the projects you want to import."
-msgstr "Ð”Ð»Ñ Ð¿Ð¾Ñ‡Ð°Ñ‚ÐºÑƒ введіть URL-адреÑу FogBugz та параметри входу нижче. Далі ви зможете перенеÑти кориÑтувачів та вибрати проекти Ð´Ð»Ñ Ñ–Ð¼Ð¿Ð¾Ñ€Ñ‚Ñƒ."
+msgstr "Ð”Ð»Ñ Ð¿Ð¾Ñ‡Ð°Ñ‚ÐºÑƒ введіть URL-адреÑу FogBugz та параметри входу нижче. Далі ви зможете перенеÑти кориÑтувачів та вибрати проєкти Ð´Ð»Ñ Ñ–Ð¼Ð¿Ð¾Ñ€Ñ‚Ñƒ."
msgid "To get started, link this page to your Jaeger server, or find out how to %{link_start_tag}install Jaeger%{link_end_tag}"
msgstr "Щоб почати роботу, з'єднайте цю Ñторінку з Ñервером Jaeger, або дізнайтеÑÑ, Ñк %{link_start_tag}вÑтановити Jaeger%{link_end_tag}"
@@ -26341,13 +27262,13 @@ msgid "To keep this project going, create a new issue"
msgstr "Ð”Ð»Ñ Ñ€Ð¾Ð·Ð²Ð¸Ñ‚ÐºÑƒ цього проєкту Ñтворіть нову задачу"
msgid "To keep this project going, create a new merge request"
-msgstr "Ð”Ð»Ñ Ñ€Ð¾Ð·Ð²Ð¸Ñ‚ÐºÑƒ цього проекту Ñтворіть новий запит на злиттÑ"
+msgstr "Ð”Ð»Ñ Ñ€Ð¾Ð·Ð²Ð¸Ñ‚ÐºÑƒ цього проєкту Ñтворіть новий запит на злиттÑ"
msgid "To link Sentry to GitLab, enter your Sentry URL and Auth Token."
msgstr "Ð”Ð»Ñ Ñ–Ð½Ñ‚ÐµÐ³Ñ€Ð°Ñ†Ñ–Ñ— Sentry із Gitlab введіть URL-адреÑу Sentry та токен автентифікації."
msgid "To move or copy an entire GitLab project from another GitLab installation to this one, navigate to the original project's settings page, generate an export file, and upload it here."
-msgstr "Щоб переміÑтити або Ñкопіювати веÑÑŒ проект GitLab з іншої інÑталÑції GitLab до цього, перейдіть на Ñторінку налаштувань оригіналу проекту, Ñтворіть файл екÑпорту та надішліть його Ñюди."
+msgstr "Щоб переміÑтити або Ñкопіювати веÑÑŒ проєкт GitLab з іншої інÑталÑції GitLab до цього, перейдіть на Ñторінку налаштувань оригіналу проєкту, Ñтворіть файл екÑпорту та надішліть його Ñюди."
msgid "To only use CI/CD features for an external repository, choose %{strong_open}CI/CD for external repo%{strong_close}."
msgstr ""
@@ -26362,7 +27283,7 @@ msgid "To protect this issue's confidentiality, %{forkLink} and set the fork's v
msgstr ""
msgid "To protect this issue's confidentiality, a private fork of this project was selected."
-msgstr "Щоб зберегти конфіденційніÑÑ‚ÑŒ цієї задачі, було вибрано приватний форк цього проекту."
+msgstr "Щоб зберегти конфіденційніÑÑ‚ÑŒ цієї задачі, було вибрано приватний форк цього проєкту."
msgid "To receive alerts from manually configured Prometheus services, add the following URL and Authorization key to your Prometheus webhook config file. Learn more about %{linkStart}configuring Prometheus%{linkEnd} to send alerts to GitLab."
msgstr "Ð”Ð»Ñ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ Ð¿Ð¾Ð¿ÐµÑ€ÐµÐ´Ð¶ÐµÐ½ÑŒ від ÑервіÑів Prometheus, Ñкі Ñконфігуровані вручну, додайте наÑтупний URL та ключ авторизаціх до вашого конфігураційного файлу веб-хуків Prometheus. ДізнайтеÑÑ Ð±Ñ–Ð»ÑŒÑˆÐµ про %{linkStart}ÐºÐ¾Ð½Ñ„Ñ–Ð³ÑƒÑ€ÑƒÐ²Ð°Ð½Ñ Prometheus%{linkEnd} Ð´Ð»Ñ Ñ‚Ð¾Ð³Ð¾, щоб відправлÑти Ð¿Ð¾Ð¿ÐµÑ€ÐµÐ´Ð¶ÐµÐ½Ð½Ñ Ñ–Ð· Gitlab."
@@ -26371,10 +27292,10 @@ msgid "To see all the user's personal access tokens you must impersonate them fi
msgstr "Ð”Ð»Ñ Ñ‚Ð¾Ð³Ð¾ щоб бачити уÑÑ– перÑональні токени доÑтупe кориÑтувача вам необхідно Ñпочатку розпочати його імітуваннÑ."
msgid "To see this project's operational details, %{linkStart}upgrade its group plan to Silver%{linkEnd}. You can also remove the project from the dashboard."
-msgstr "Ð”Ð»Ñ Ð¿ÐµÑ€ÐµÐ³Ð»Ñду оперативних даних цього проекту %{linkStart}переведіть його групу на план Silver%{linkEnd}. Ви також можете видалити цей проект із панелі управліннÑ."
+msgstr "Ð”Ð»Ñ Ð¿ÐµÑ€ÐµÐ³Ð»Ñду оперативних даних цього проєкту %{linkStart}переведіть його групу на план Silver%{linkEnd}. Ви також можете видалити цей проєкт із панелі управліннÑ."
msgid "To see this project's operational details, contact an owner of group %{groupName} to upgrade the plan. You can also remove the project from the dashboard."
-msgstr "Щоб переглÑнути оперативні дані цього проекту зв’ÑжітьÑÑ Ñ–Ð· влаÑником групи %{groupName} Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÑ…Ð¾Ð´Ñƒ на вищий тарифний план. Ви також можете видалити цей проект із панелі управліннÑ."
+msgstr "Щоб переглÑнути оперативні дані цього проєкту зв’ÑжітьÑÑ Ñ–Ð· влаÑником групи %{groupName} Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÑ…Ð¾Ð´Ñƒ на вищий тарифний план. Ви також можете видалити цей проєкт із панелі управліннÑ."
msgid "To set up SAML authentication for your group through an identity provider like Azure, Okta, Onelogin, Ping Identity, or your custom SAML 2.0 provider:"
msgstr "Щоб налаштувати автентифікацію SAML Ð´Ð»Ñ Ð²Ð°ÑˆÐ¾Ñ— групи через провайдера ідентифікації такої Ñк Azure, Okta, Onelogin, Ping Identity або вашого влаÑного поÑтачальника SAML 2.0:"
@@ -26386,13 +27307,13 @@ msgid "To simplify the billing process, GitLab will collect user counts in order
msgstr ""
msgid "To specify the notification level per project of a group you belong to, you need to visit project page and change notification level there."
-msgstr "Щоб визначити рівень Ñповіщень Ð´Ð»Ñ Ð¿Ñ€Ð¾ÐµÐºÑ‚Ñ–Ð² груп, до Ñких ви належите, вам потрібно відвідати Ñторінку проекту та змінити рівень Ñповіщень там."
+msgstr "Щоб визначити рівень Ñповіщень Ð´Ð»Ñ Ð¿Ñ€Ð¾Ñ”ÐºÑ‚Ñ–Ð² груп, до Ñких ви належите, вам потрібно відвідати Ñторінку проєкту та змінити рівень Ñповіщень там."
msgid "To start serving your jobs you can add Runners to your group"
msgstr "Ð”Ð»Ñ Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ Ð²Ð°ÑˆÐ¸Ñ… завдань ви можете додати Runner’и до вашої групи"
msgid "To start serving your jobs you can either add specific Runners to your project or use shared Runners"
-msgstr "Щоб почати ваші Ð·Ð°Ð²Ð´Ð°Ð½Ð½Ñ Ð²Ð¸ÐºÐ¾Ð½ÑƒÐ²Ð°Ð»Ð¸ÑÑ, ви можете або додати Ñпеціальні Runner’и до вашого проекту, або викориÑтовувати загальні"
+msgstr "Щоб почати ваші Ð·Ð°Ð²Ð´Ð°Ð½Ð½Ñ Ð²Ð¸ÐºÐ¾Ð½ÑƒÐ²Ð°Ð»Ð¸ÑÑ, ви можете або додати Ñпеціальні Runner’и до вашого проєкту, або викориÑтовувати загальні"
msgid "To unsubscribe from this issue, please paste the following link into your browser:"
msgstr ""
@@ -26400,6 +27321,9 @@ msgstr ""
msgid "To update Snippets with multiple files, you must use the `files` parameter"
msgstr ""
+msgid "To use Gitpod you must first enable the feature in the integrations section of your %{user_prefs}."
+msgstr ""
+
msgid "To view all %{scannedResourcesCount} scanned URLs, please download the CSV file"
msgstr ""
@@ -26433,9 +27357,6 @@ msgstr "Увімкнути чи вимкнути попередній перег
msgid "Toggle Sidebar"
msgstr "Перемикач бічної панелі"
-msgid "Toggle all threads"
-msgstr ""
-
msgid "Toggle backtrace"
msgstr "Увімкнути/вимкнути журнал оÑтанніх подій"
@@ -26460,9 +27381,6 @@ msgstr "Увімкнути/вимкнути Ñмайлики-нагороди"
msgid "Toggle navigation"
msgstr "Переключити навігацію"
-msgid "Toggle project"
-msgstr "Увімкнути/вимкнути проект"
-
msgid "Toggle sidebar"
msgstr "Перемикач бічної панелі"
@@ -26502,6 +27420,9 @@ msgstr ""
msgid "Too many projects enabled. You will need to manage them via the console or the API."
msgstr ""
+msgid "Too much data"
+msgstr ""
+
msgid "Topics (optional)"
msgstr "Теми (додатково)"
@@ -26518,13 +27439,16 @@ msgid "Total artifacts size: %{total_size}"
msgstr "Загальний розмір артефактів: %{total_size}"
msgid "Total cores (CPUs)"
+msgstr "Ð’Ñього Ñдер (ЦП)"
+
+msgid "Total days to completion"
msgstr ""
msgid "Total issues"
msgstr "Ð’Ñього задач"
msgid "Total memory (GB)"
-msgstr ""
+msgstr "Ð’Ñього памʼÑÑ‚Ñ– (ГБ)"
msgid "Total test time for all commits/merges"
msgstr "Загальний чаÑ, щоб перевірити вÑÑ– коміти/злиттÑ"
@@ -26545,16 +27469,16 @@ msgid "Tracing"
msgstr "ВідÑтеженнÑ"
msgid "Track groups of issues that share a theme, across projects and milestones"
-msgstr "ВідÑтежуйте групи задач зі Ñпільною темою з різних проектів та етапів"
+msgstr "ВідÑтежуйте групи задач зі Ñпільною темою з різних проєктів та етапів"
msgid "Track time with quick actions"
msgstr "ВідÑтежуйте Ñ‡Ð°Ñ Ð·Ð° допомогою швидких дій"
msgid "Track your GitLab projects with GitLab for Slack."
-msgstr "ВідÑтежуйте Ñвої проекти GitLab за допомогою GitLab Ð´Ð»Ñ Slack."
+msgstr "ВідÑтежуйте Ñвої проєкти GitLab за допомогою GitLab Ð´Ð»Ñ Slack."
msgid "Track your project with Audit Events."
-msgstr "ВідÑтежуйте події аудиту в Ñвоєму проекті."
+msgstr "ВідÑтежуйте події аудиту в Ñвоєму проєкті."
msgid "Transfer"
msgstr ""
@@ -26563,13 +27487,13 @@ msgid "Transfer ownership"
msgstr ""
msgid "Transfer project"
-msgstr "ПеренеÑти проект"
+msgstr "ПеренеÑти проєкт"
msgid "TransferGroup|Cannot transfer group to one of its subgroup."
msgstr ""
msgid "TransferGroup|Cannot update the path because there are projects under this group that contain Docker images in their Container Registry. Please remove the images from your projects first and try again."
-msgstr "Ðе вдалоÑÑ Ð·Ð¼Ñ–Ð½Ð¸Ñ‚Ð¸ шлÑÑ… тому що в цій групі Ñ” проекти із образами Docker у Ñвоїх РеєÑтрах контейнерів. Будь лаÑка, Ñпочатку видаліть ці образи з ваших проектів Ñ– Ñпробуйте знову."
+msgstr "Ðе вдалоÑÑ Ð·Ð¼Ñ–Ð½Ð¸Ñ‚Ð¸ шлÑÑ… тому що в цій групі Ñ” проєкти із образами Docker у Ñвоїх РеєÑтрах контейнерів. Будь лаÑка, Ñпочатку видаліть ці образи з ваших проєктів Ñ– Ñпробуйте знову."
msgid "TransferGroup|Database is not supported."
msgstr "База даних не підтримуєтьÑÑ."
@@ -26593,16 +27517,16 @@ msgid "TransferGroup|You don't have enough permissions."
msgstr "У Ð²Ð°Ñ Ð½ÐµÐ´Ð¾Ñтатньо прав."
msgid "TransferProject|Cannot move project"
-msgstr "Ðеможливо переміÑтити проект"
+msgstr "Ðеможливо переміÑтити проєкт"
msgid "TransferProject|Please select a new namespace for your project."
-msgstr "Будь лаÑка, виберіть новий проÑÑ‚Ñ–Ñ€ імен Ð´Ð»Ñ Ð²Ð°ÑˆÐ¾Ð³Ð¾ проекту."
+msgstr "Будь лаÑка, виберіть новий проÑÑ‚Ñ–Ñ€ імен Ð´Ð»Ñ Ð²Ð°ÑˆÐ¾Ð³Ð¾ проєкту."
msgid "TransferProject|Project cannot be transferred, because tags are present in its container registry"
msgstr "Проект не може бути переміщений, тому що в реєÑтрі контейнерів приÑутні теги"
msgid "TransferProject|Project with same name or path in target namespace already exists"
-msgstr "Ð’ цільовому проÑторі імен вже Ñ–Ñнує проект із таким же іменем або шлÑхом"
+msgstr "Ð’ цільовому проÑторі імен вже Ñ–Ñнує проєкт із таким же іменем або шлÑхом"
msgid "TransferProject|Root namespace can't be updated if project has NPM packages"
msgstr "Кореневий проÑÑ‚Ñ–Ñ€ імен не може бути змінено, Ñкщо проєкт міÑтить пакети NPM"
@@ -26616,6 +27540,9 @@ msgstr "У виглÑді дерева"
msgid "Trending"
msgstr "ПопулÑрні"
+msgid "Trials|Create a new group to start your GitLab Gold trial."
+msgstr ""
+
msgid "Trials|Go back to GitLab"
msgstr "ПовернутиÑÑ Ð´Ð¾ GitLab"
@@ -26625,6 +27552,15 @@ msgstr ""
msgid "Trials|You can always resume this process by selecting your avatar and choosing 'Start a Gold trial'"
msgstr ""
+msgid "Trials|You can apply your trial to a new group or an existing group."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group or your personal account."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group, an existing group, or your personal account."
+msgstr ""
+
msgid "Trials|You won't get a free trial right now but you can always resume this process by clicking on your avatar and choosing 'Start a free trial'"
msgstr ""
@@ -26694,6 +27630,9 @@ msgstr ""
msgid "Try using a different search term to find the file you are looking for."
msgstr "Спробуйте викориÑтовувати інші Ñлова Ð´Ð»Ñ Ð¿Ð¾ÑˆÑƒÐºÑƒ щоб знайти необхідний вам файл."
+msgid "Trying to communicate with your device. Plug it in (if needed) and press the button on the device now."
+msgstr ""
+
msgid "Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now."
msgstr "ВідбуваєтьÑÑ Ð·'Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ñ–Ð· вашим приÑтроєм. Підключіть його (Ñкщо ви цього ще не зробили) Ñ– натиÑніть кнопку на ньому зараз."
@@ -26767,7 +27706,7 @@ msgid "URL"
msgstr "URL"
msgid "URL is required"
-msgstr ""
+msgstr "URL-адреÑа обов'Ñзкова"
msgid "URL must start with %{codeStart}http://%{codeEnd}, %{codeStart}https://%{codeEnd}, or %{codeStart}ftp://%{codeEnd}"
msgstr ""
@@ -26781,6 +27720,12 @@ msgstr "URL-адреÑа зовнішнього Ñховища, де зберіÐ
msgid "URL or request ID"
msgstr "URL або ідентифікатор запиту"
+msgid "USER %{user} WILL BE REMOVED! Are you sure?"
+msgstr ""
+
+msgid "USER WILL BE BLOCKED! Are you sure?"
+msgstr ""
+
msgid "UTC"
msgstr "UTC"
@@ -26838,11 +27783,8 @@ msgstr "Ðеможливо завантажити порівнÑÐ½Ð½Ñ (diff). %
msgid "Unable to load the merge request widget. Try reloading the page."
msgstr "Ðе вдалоÑÑ Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶Ð¸Ñ‚Ð¸ віджет запиту на злиттÑ. Спробуйте перезавантажити Ñторінку."
-msgid "Unable to resolve"
-msgstr "Ðе вдалоÑÑ Ð²Ð¸Ñ€Ñ–ÑˆÐ¸Ñ‚Ð¸"
-
msgid "Unable to save iteration. Please try again"
-msgstr ""
+msgstr "Ðе вдалоÑÑ Ð·Ð±ÐµÑ€ÐµÐ³Ñ‚Ð¸ ітерацію. Будь лаÑка, Ñпробуйте ще раз"
msgid "Unable to save your changes. Please try again."
msgstr "Ðе вдалоÑÑ Ð·Ð±ÐµÑ€ÐµÐ³Ñ‚Ð¸ ваші зміни. Будь лаÑка, Ñпробуйте знову."
@@ -26884,9 +27826,12 @@ msgid "Undo"
msgstr "СкаÑувати"
msgid "Undo Ignore"
-msgstr ""
+msgstr "СкаÑувати ігноруваннÑ"
msgid "Undo ignore"
+msgstr "СкаÑувати ігноруваннÑ"
+
+msgid "Unexpected error"
msgstr ""
msgid "Unfortunately, your email message to GitLab could not be processed."
@@ -26911,7 +27856,7 @@ msgid "Unknown Error"
msgstr "Ðевідома помилка"
msgid "Unknown cache key"
-msgstr ""
+msgstr "Ðевідомий ключ кешу"
msgid "Unknown encryption strategy: %{encrypted_strategy}!"
msgstr "Ðевідома ÑÑ‚Ñ€Ð°Ñ‚ÐµÐ³Ñ–Ñ ÑˆÐ¸Ñ„Ñ€ÑƒÐ²Ð°Ð½Ð½Ñ: %{encrypted_strategy}!"
@@ -26922,6 +27867,9 @@ msgstr "Ðевідомий формат"
msgid "Unknown response text"
msgstr "Ðевідомий текÑÑ‚ відповіді"
+msgid "Unless otherwise agreed to in writing with GitLab, by clicking \"Upload License\" you agree that your use of GitLab Software is subject to the %{eula_link_start}Terms of Service%{eula_link_end}."
+msgstr ""
+
msgid "Unlimited"
msgstr "Без обмежень"
@@ -27004,7 +27952,7 @@ msgid "Unsubscribe at group level"
msgstr "ВідпиÑатиÑÑ Ð½Ð° рівні групи"
msgid "Unsubscribe at project level"
-msgstr "ВідпиÑатиÑÑ Ð½Ð° рівні проекту"
+msgstr "ВідпиÑатиÑÑ Ð½Ð° рівні проєкту"
msgid "Unsubscribe from %{type}"
msgstr "ВідпиÑатиÑÑ Ð²Ñ–Ð´ %{type}"
@@ -27061,13 +28009,13 @@ msgid "Update it"
msgstr "Оновити це"
msgid "Update iteration"
-msgstr ""
+msgstr "Оновити ітерацію"
msgid "Update now"
msgstr "Оновити зараз"
msgid "Update variable"
-msgstr ""
+msgstr "Оновити змінну"
msgid "Update your bookmarked URLs as filtered/sorted branches URL has been changed."
msgstr "Оновіть Ñвої закладки, тому що URL-адреÑа відфільтрованих чи відÑортованих гілок змінилаÑÑ."
@@ -27076,10 +28024,10 @@ msgid "Update your group name, description, avatar, and visibility."
msgstr "Оновіть Ñ–Ð¼â€™Ñ Ð³Ñ€ÑƒÐ¿Ð¸, опиÑ, аватар та видиміÑÑ‚ÑŒ."
msgid "Update your project name, topics, description and avatar."
-msgstr "Оновіть ім'Ñ Ð¿Ñ€Ð¾ÐµÐºÑ‚Ñƒ, теми, Ð¾Ð¿Ð¸Ñ Ñ‚Ð° аватар."
+msgstr "Оновіть ім'Ñ Ð¿Ñ€Ð¾Ñ”ÐºÑ‚Ñƒ, теми, Ð¾Ð¿Ð¸Ñ Ñ‚Ð° аватар."
msgid "UpdateProject|Cannot rename project because it contains container registry tags!"
-msgstr "Ðеможливо перейменувати проект, тому що він має теги в реєÑтрі контейнерів!"
+msgstr "Ðеможливо перейменувати проєкт, тому що він має теги в реєÑтрі контейнерів!"
msgid "UpdateProject|Could not set the default branch"
msgstr "Ðеможливо вÑтановити гілку за замовчуваннÑм"
@@ -27109,7 +28057,7 @@ msgid "Updated to %{linkStart}chart v%{linkEnd}"
msgstr ""
msgid "Updates"
-msgstr ""
+msgstr "ОновленнÑ"
msgid "Updating"
msgstr "ОновленнÑ"
@@ -27118,7 +28066,7 @@ msgid "Upgrade plan to unlock Canary Deployments feature"
msgstr "Перейдіть на вищий тарифний план, щоб отримати доÑтуп до функціональноÑÑ‚Ñ– Canary Deployments"
msgid "Upgrade your plan"
-msgstr ""
+msgstr "Перейти на вищий тарифний план"
msgid "Upgrade your plan to activate Advanced Search."
msgstr ""
@@ -27145,13 +28093,13 @@ msgid "Upload CSV file"
msgstr "Завантажити CSV файл"
msgid "Upload License"
-msgstr ""
+msgstr "Завантажити ліцензію"
msgid "Upload New File"
msgstr "ÐадіÑлати новий файл"
msgid "Upload New License"
-msgstr ""
+msgstr "Завантажити нову ліцензію"
msgid "Upload a certificate for your domain with all intermediates"
msgstr "Завантажити Ñертифікат Ð´Ð»Ñ Ð²Ð°ÑˆÐ¾Ð³Ð¾ домену з уÑіма проміжними"
@@ -27172,7 +28120,7 @@ msgid "Uploaded on"
msgstr "Завантажено на"
msgid "Uploaded:"
-msgstr ""
+msgstr "Завантажено:"
msgid "Uploading changes to terminal"
msgstr "Ð—Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ Ð·Ð¼Ñ–Ð½ до терміналу"
@@ -27247,7 +28195,7 @@ msgid "UsageQuota|Storage"
msgstr "Сховище"
msgid "UsageQuota|This namespace has no projects which use shared runners"
-msgstr "Цей проÑÑ‚Ñ–Ñ€ імен не міÑтить проектів, що викориÑтовують загальні runner'и"
+msgstr "Цей проÑÑ‚Ñ–Ñ€ імен не міÑтить проєктів, що викориÑтовують загальні runner'и"
msgid "UsageQuota|Unlimited"
msgstr "Без обмежень"
@@ -27259,7 +28207,7 @@ msgid "UsageQuota|Usage Quotas"
msgstr "Квоти на викориÑтаннÑ"
msgid "UsageQuota|Usage of group resources across the projects in the %{strong_start}%{group_name}%{strong_end} group"
-msgstr "ВикориÑÑ‚Ð°Ð½Ð½Ñ Ð³Ñ€ÑƒÐ¿Ð¾Ð²Ð¸Ñ… реÑурÑів у проектах групи %{strong_start}%{group_name}%{strong_end}"
+msgstr "ВикориÑÑ‚Ð°Ð½Ð½Ñ Ð³Ñ€ÑƒÐ¿Ð¾Ð²Ð¸Ñ… реÑурÑів у проєктах групи %{strong_start}%{group_name}%{strong_end}"
msgid "UsageQuota|Usage of resources across your projects"
msgstr ""
@@ -27288,9 +28236,6 @@ msgstr "ВикориÑтовуйте %{code_start}::%{code_end} Ð´Ð»Ñ ÑтвоÑ
msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
msgstr "ВикориÑтовуйте Service Desk Ð´Ð»Ñ Ð·Ð²â€™Ñзку з вашими кориÑтувачами (наприклад, щоб запропонувати клієнтÑьку підтримку) через електронну пошту безпоÑередньо із GitLab"
-msgid "Use a hardware device to add the second factor of authentication."
-msgstr "ВикориÑтовуйте приÑтрій Ð´Ð»Ñ Ð´Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ð´Ñ€ÑƒÐ³Ð¾Ð³Ð¾ фактору автентифікацї."
-
msgid "Use an one time password authenticator on your mobile device or computer to enable two-factor authentication (2FA)."
msgstr "ВикориÑтовуйте одноразовий пароль на вашому мобільному приÑтрої або комп’ютері Ð´Ð»Ñ Ð°ÐºÑ‚Ð¸Ð²Ð°Ñ†Ñ–Ñ— двофакторної автентифікації (2FA)."
@@ -27337,10 +28282,10 @@ msgid "User %{username} was successfully removed."
msgstr "КориÑтувача %{username} уÑпішно видалено."
msgid "User IDs"
-msgstr ""
+msgstr "ID кориÑтувачів"
msgid "User List"
-msgstr ""
+msgstr "СпиÑок кориÑтувачів"
msgid "User OAuth applications"
msgstr "OAuth заÑтоÑунки кориÑтувача"
@@ -27379,7 +28324,7 @@ msgid "User restrictions"
msgstr "ÐžÐ±Ð¼ÐµÐ¶ÐµÐ½Ð½Ñ ÐºÐ¾Ñ€Ð¸Ñтувача"
msgid "User settings"
-msgstr ""
+msgstr "ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ ÐºÐ¾Ñ€Ð¸Ñтувача"
msgid "User was successfully created."
msgstr "КориÑтувача було уÑпішно Ñтворено."
@@ -27388,31 +28333,31 @@ msgid "User was successfully removed from group and any subresources."
msgstr "КориÑтувача було уÑпішно видалено із групи та підреÑурÑів."
msgid "User was successfully removed from project."
-msgstr "КориÑтувача уÑпішно видалено із проекту."
+msgstr "КориÑтувача уÑпішно видалено із проєкту."
msgid "User was successfully updated."
msgstr "КориÑтувача було уÑпішно оновлено."
msgid "UserLists|Add"
-msgstr ""
+msgstr "Додати"
msgid "UserLists|Add Users"
-msgstr ""
+msgstr "Додати кориÑтувачів"
msgid "UserLists|Add users"
-msgstr ""
+msgstr "Додати кориÑтувачів"
msgid "UserLists|Cancel"
-msgstr ""
+msgstr "СкаÑувати"
msgid "UserLists|Create"
-msgstr ""
+msgstr "Створити"
msgid "UserLists|Define a set of users to be used within feature flag strategies"
msgstr ""
msgid "UserLists|Edit"
-msgstr ""
+msgstr "Редагувати"
msgid "UserLists|Edit %{name}"
msgstr ""
@@ -27427,13 +28372,13 @@ msgid "UserLists|Lists allow you to define a set of users to be used with featur
msgstr ""
msgid "UserLists|Name"
-msgstr ""
+msgstr "ІмʼÑ"
msgid "UserLists|New list"
-msgstr ""
+msgstr "Ðовий ÑпиÑок"
msgid "UserLists|Save"
-msgstr ""
+msgstr "Зберегти"
msgid "UserLists|There are no users"
msgstr "Ðемає кориÑтувачів"
@@ -27442,7 +28387,7 @@ msgid "UserLists|User ID"
msgstr ""
msgid "UserLists|User IDs"
-msgstr ""
+msgstr "Ідентифікатори кориÑтувачів"
msgid "UserList|Delete %{name}?"
msgstr "Видалити %{name}?"
@@ -27460,19 +28405,19 @@ msgid "UserProfile|Blocked user"
msgstr "Заблокований кориÑтувач"
msgid "UserProfile|Contributed projects"
-msgstr "ВнеÑки в проекти"
+msgstr "ВнеÑки в проєкти"
msgid "UserProfile|Edit profile"
msgstr "Редагувати профіль"
msgid "UserProfile|Explore public groups to find projects to contribute to."
-msgstr "ПереглÑдайте публічні групи та знаходьте проекти Ð´Ð»Ñ Ñвоїх внеÑків."
+msgstr "ПереглÑдайте публічні групи та знаходьте проєкти Ð´Ð»Ñ Ñвоїх внеÑків."
msgid "UserProfile|Groups"
msgstr "Групи"
msgid "UserProfile|Groups are the best way to manage projects and members."
-msgstr "Групи — це найкращий ÑпоÑіб керувати проектами та учаÑниками."
+msgstr "Групи — це найкращий ÑпоÑіб керувати проєктами та учаÑниками."
msgid "UserProfile|Join or create a group to start contributing by commenting on issues or submitting merge requests!"
msgstr "ПриєднуйтеÑÑŒ до або Ñтворіть групу, щоб почати робити внеÑки через коментарі до задач, а також надÑилаючи запити на злиттÑ!"
@@ -27487,7 +28432,7 @@ msgid "UserProfile|Overview"
msgstr "ОглÑд"
msgid "UserProfile|Personal projects"
-msgstr "ОÑобиÑÑ‚Ñ– проекти"
+msgstr "ОÑобиÑÑ‚Ñ– проєкти"
msgid "UserProfile|Report abuse"
msgstr "Повідомити про зловживаннÑ"
@@ -27499,7 +28444,7 @@ msgid "UserProfile|Snippets in GitLab can either be private, internal, or public
msgstr "Сніпети в GitLab можуть бути приватними, внутрішніми та публічними."
msgid "UserProfile|Star projects to track their progress and show your appreciation."
-msgstr "Додавайте проекти в обране, щоб Ñлідкувати за ними та показати Ñвій інтереÑ."
+msgstr "Додавайте проєкти в обране, щоб Ñлідкувати за ними та показати Ñвій інтереÑ."
msgid "UserProfile|Starred projects"
msgstr "Обрані проєкти"
@@ -27508,16 +28453,16 @@ msgid "UserProfile|Subscribe"
msgstr "ПідпиÑатиÑÑ"
msgid "UserProfile|This user doesn't have any personal projects"
-msgstr "Цей кориÑтувач не має оÑобиÑтих проектів"
+msgstr "Цей кориÑтувач не має оÑобиÑтих проєктів"
msgid "UserProfile|This user has a private profile"
msgstr "Цей кориÑтувач має приватний профіль"
msgid "UserProfile|This user hasn't contributed to any projects"
-msgstr "Цей кориÑтувач не робив внеÑків до жодного із проектів"
+msgstr "Цей кориÑтувач не робив внеÑків до жодного із проєктів"
msgid "UserProfile|This user hasn't starred any projects"
-msgstr "Цей кориÑтувач не має жодного обраного проекту"
+msgstr "Цей кориÑтувач не має жодного обраного проєкту"
msgid "UserProfile|This user is blocked"
msgstr "Цей кориÑтувач заблокований"
@@ -27529,16 +28474,16 @@ msgid "UserProfile|View user in admin area"
msgstr "ПереглÑнути кориÑтувача в адмінці"
msgid "UserProfile|You can create a group for several dependent projects."
-msgstr "Ви можете Ñтворити групу Ð´Ð»Ñ Ð´ÐµÐºÑ–Ð»ÑŒÐºÐ¾Ñ… залежних проектів."
+msgstr "Ви можете Ñтворити групу Ð´Ð»Ñ Ð´ÐµÐºÑ–Ð»ÑŒÐºÐ¾Ñ… залежних проєктів."
msgid "UserProfile|You haven't created any personal projects."
-msgstr "Ви ще не Ñтворили жодного оÑобиÑтого проекту."
+msgstr "Ви ще не Ñтворили жодного оÑобиÑтого проєкту."
msgid "UserProfile|You haven't created any snippets."
msgstr "Ви ще не Ñтворили жодних Ñніпетів."
msgid "UserProfile|Your projects can be available publicly, internally, or privately, at your choice."
-msgstr "За вашим вибором ваші проекти можуть бути доÑтупні публічно, внутрішньо або приватно."
+msgstr "За вашим вибором ваші проєкти можуть бути доÑтупні публічно, внутрішньо або приватно."
msgid "UserProfile|at"
msgstr ""
@@ -27564,15 +28509,15 @@ msgstr "Ім'Ñ ÐºÐ¾Ñ€Ð¸Ñтувача або електронна пошта"
msgid "Users"
msgstr "КориÑтувачі"
-msgid "Users in License:"
+msgid "Users in License"
msgstr ""
+msgid "Users in License:"
+msgstr "КориÑтувачі в ліцензії:"
+
msgid "Users or groups set as approvers in the project's or merge request's settings."
msgstr ""
-msgid "Users outside of license"
-msgstr "КориÑтувачі за межами ліцензії"
-
msgid "Users over License:"
msgstr ""
@@ -27588,9 +28533,6 @@ msgstr "КориÑтувачів уÑпішно додано."
msgid "Users with a Guest role or those who don't belong to a Project or Group will not use a seat from your license."
msgstr ""
-msgid "Users with a Guest role or those who don't belong to any projects or groups don't count towards seats in use."
-msgstr "КориÑтувачі із роллю ГіÑÑ‚ÑŒ або Ñ‚Ñ–, що не належать до жодного проекту або групи не враховуютьÑÑ Ð¿Ñ€Ð¸ підрахунку міÑць."
-
msgid "UsersSelect|%{name} + %{length} more"
msgstr "%{name} + %{length} більше"
@@ -27616,7 +28558,7 @@ msgid "Using required encryption strategy when encrypted field is missing!"
msgstr "ВикориÑтовуєтьÑÑ Ð¾Ð±Ð¾Ð²â€™Ñзкова ÑÑ‚Ñ€Ð°Ñ‚ÐµÐ³Ñ–Ñ ÑˆÐ¸Ñ„Ñ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð¿Ñ€Ð¸ відÑутньому полі Ð´Ð»Ñ Ð·Ð°ÑˆÐ¸Ñ„Ñ€Ð¾Ð²Ð°Ð½Ð¾Ð³Ð¾ значеннÑ!"
msgid "Valid from"
-msgstr ""
+msgstr "Діє з"
msgid "Validate"
msgstr "Перевірити"
@@ -27630,9 +28572,6 @@ msgstr "Перевірити ваш файл конфігурації Gitlab CI"
msgid "Validations failed."
msgstr "Перевірки не пройшли уÑпішно."
-msgid "Validity"
-msgstr "Термін дії"
-
msgid "Value"
msgstr "ЗначеннÑ"
@@ -27651,6 +28590,9 @@ msgstr ""
msgid "Value Stream Name"
msgstr ""
+msgid "ValueStreamAnalyticsStage|We don't have enough data to show this stage."
+msgstr ""
+
msgid "ValueStreamAnalytics|%{days}d"
msgstr ""
@@ -27728,13 +28670,13 @@ msgstr[2] ""
msgstr[3] ""
msgid "View dependency details for your project"
-msgstr "ПереглÑнути інформацію про залежноÑÑ‚Ñ– Ð´Ð»Ñ Ð²Ð°ÑˆÐ¾Ð³Ð¾ проекту"
+msgstr "ПереглÑнути інформацію про залежноÑÑ‚Ñ– Ð´Ð»Ñ Ð²Ð°ÑˆÐ¾Ð³Ð¾ проєкту"
msgid "View deployment"
msgstr "ПереглÑнути розгортаннÑ"
msgid "View details"
-msgstr ""
+msgstr "Докладніше"
msgid "View details: %{details_url}"
msgstr "ПереглÑнути деталі: %{details_url}"
@@ -27798,13 +28740,13 @@ msgid "View log"
msgstr "ПереглÑнути журнал"
msgid "View merge request"
-msgstr ""
+msgstr "ПереглÑнути запити на злиттÑ"
msgid "View open merge request"
msgstr "ПереглÑнути відкритий запит на злиттÑ"
msgid "View page @ "
-msgstr ""
+msgstr "ПереглÑнути Ñторінку @ "
msgid "View performance dashboard."
msgstr ""
@@ -27813,7 +28755,7 @@ msgid "View project"
msgstr "ПереглÑнути проєкти"
msgid "View project labels"
-msgstr "ПереглÑнути мітки проекту"
+msgstr "ПереглÑнути мітки проєкту"
msgid "View replaced file @ "
msgstr "ПереглÑд заміненого файлу @ "
@@ -27831,7 +28773,7 @@ msgid "View the performance dashboard at"
msgstr ""
msgid "View users statistics"
-msgstr ""
+msgstr "ПереглÑд ÑтатиÑтики кориÑтувачів"
msgid "Viewing commit"
msgstr "ПереглÑд коміту"
@@ -27852,7 +28794,7 @@ msgid "Visibility settings have been disabled by the administrator."
msgstr "ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð²Ð¸Ð´Ð¸Ð¼Ð¾ÑÑ‚Ñ– були вимкнені адмініÑтратором."
msgid "Visibility, project features, permissions"
-msgstr "ВидиміÑÑ‚ÑŒ, оÑобливоÑÑ‚Ñ– проекту, дозволи"
+msgstr "ВидиміÑÑ‚ÑŒ, оÑобливоÑÑ‚Ñ– проєкту, дозволи"
msgid "Visibility:"
msgstr "ВидиміÑÑ‚ÑŒ:"
@@ -27870,7 +28812,7 @@ msgid "VisibilityLevel|Unknown"
msgstr "Ðевідомий"
msgid "Visit settings page"
-msgstr ""
+msgstr "Відвідати Ñторінку налаштувань"
msgid "VisualReviewApp|%{stepStart}Step 1%{stepEnd}. Copy the following script:"
msgstr "%{stepStart}Крок 1%{stepEnd}. Скопіюйте наÑтупний Ñкрипт:"
@@ -27911,6 +28853,9 @@ msgstr "ПереглÑд"
msgid "VisualReviewApp|Steps 1 and 2 (and sometimes 3) are performed once by the developer before requesting feedback. Steps 3 (if necessary), 4 is performed by the reviewer each time they perform a review."
msgstr ""
+msgid "Visualization"
+msgstr ""
+
msgid "Vulnerabilities"
msgstr "ВразливоÑÑ‚Ñ–"
@@ -27918,7 +28863,7 @@ msgid "Vulnerabilities over time"
msgstr "ВразливоÑÑ‚Ñ– в чаÑÑ–"
msgid "Vulnerability Report"
-msgstr ""
+msgstr "Звіт про вразливоÑÑ‚Ñ–"
msgid "Vulnerability remediated. Review before resolving."
msgstr "ВразливіÑÑ‚ÑŒ виправлено. ПереглÑньте перед вирішеннÑм."
@@ -27938,35 +28883,32 @@ msgstr "%{formattedStartDate} до Ñьогодні"
msgid "VulnerabilityChart|Severity"
msgstr "Рівень"
-msgid "VulnerabilityManagement|A true-positive and will fix"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Change status"
-msgstr "Змінити ÑтатуÑ"
-
-msgid "VulnerabilityManagement|Confirm"
-msgstr "Підтвердити"
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
+msgstr ""
-msgid "VulnerabilityManagement|Confirmed %{timeago} by %{user}"
-msgstr "Підтверджено %{timeago} кориÑтувачем %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
+msgstr ""
-msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Detected %{timeago} in pipeline %{pipelineLink}"
-msgstr "ВиÑвлено %{timeago} в контейнері %{pipelineLink}"
+msgid "VulnerabilityManagement|A true-positive and will fix"
+msgstr ""
-msgid "VulnerabilityManagement|Dismiss"
-msgstr "Відхилити"
+msgid "VulnerabilityManagement|Change status"
+msgstr "Змінити ÑтатуÑ"
-msgid "VulnerabilityManagement|Dismissed %{timeago} by %{user}"
-msgstr "Відхилено %{timeago} кориÑтувачем %{user}"
+msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
+msgstr ""
-msgid "VulnerabilityManagement|Resolved"
-msgstr "Вирішено"
+msgid "VulnerabilityManagement|Detected"
+msgstr ""
-msgid "VulnerabilityManagement|Resolved %{timeago} by %{user}"
-msgstr "Вирішено %{timeago} кориÑтувачем %{user}"
+msgid "VulnerabilityManagement|Needs triage"
+msgstr ""
msgid "VulnerabilityManagement|Something went wrong while trying to delete the comment. Please try again later."
msgstr ""
@@ -28016,6 +28958,9 @@ msgstr "Вирішені"
msgid "Vulnerability|%{scannerName} (version %{scannerVersion})"
msgstr ""
+msgid "Vulnerability|Activity"
+msgstr ""
+
msgid "Vulnerability|Class"
msgstr "КлаÑ"
@@ -28028,6 +28973,9 @@ msgstr ""
msgid "Vulnerability|Description"
msgstr "ОпиÑ"
+msgid "Vulnerability|Detected"
+msgstr ""
+
msgid "Vulnerability|Evidence"
msgstr "Дані"
@@ -28091,6 +29039,9 @@ msgstr "Увага:"
msgid "Warning: Displaying this diagram might cause performance issues on this page."
msgstr ""
+msgid "We are currently unable to fetch data for the pipeline header."
+msgstr ""
+
msgid "We are currently unable to fetch data for this graph."
msgstr ""
@@ -28130,6 +29081,12 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr "Ми хочемо бути впевнені, що це ви, будь лаÑка, підтвердіть, що ви не робот."
+msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
+msgstr ""
+
+msgid "We would like to inform you that your subscription GitLab Enterprise Edition %{plan_name} is nearing its user limit. You have %{active_user_count} active users, which is almost at the user limit of %{maximum_user_count}."
+msgstr ""
+
msgid "We've found no vulnerabilities"
msgstr "Ми не виÑвили вразливоÑтей"
@@ -28145,6 +29102,12 @@ msgstr "Веб-термінал"
msgid "Web terminal"
msgstr "Веб-термінал"
+msgid "WebAuthn Devices (%{length})"
+msgstr ""
+
+msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
+msgstr ""
+
msgid "WebIDE|Merge request"
msgstr "Запит на злиттÑ"
@@ -28161,10 +29124,10 @@ msgid "Webhooks"
msgstr "Веб-хуки"
msgid "Webhooks Help"
-msgstr ""
+msgstr "Допомога по веб-хукам"
msgid "Webhooks allow you to trigger a URL if, for example, new code is pushed or a new issue is created. You can configure webhooks to listen for specific events like pushes, issues or merge requests. Group webhooks will apply to all projects in a group, allowing you to standardize webhook functionality across your entire group."
-msgstr "Веб-хук дозволÑÑ” вам викликати URL Ñкщо, наприклад, був відправлений новий код або Ñтворено нову задачу. Ви можете налаштувати його так, щоб він реагував на певні події (відправки коду, задачі або запити на злиттÑ). Групові веб-хуки заÑтоÑовуютьÑÑ Ð´Ð¾ вÑÑ–Ñ… проектів в групі Ñ– дозволÑÑŽÑ‚ÑŒ вам Ñтандартизувати Ñ—Ñ… Ð´Ð»Ñ Ð²Ñієї вашої групи."
+msgstr "Веб-хук дозволÑÑ” вам викликати URL Ñкщо, наприклад, був відправлений новий код або Ñтворено нову задачу. Ви можете налаштувати його так, щоб він реагував на певні події (відправки коду, задачі або запити на злиттÑ). Групові веб-хуки заÑтоÑовуютьÑÑ Ð´Ð¾ вÑÑ–Ñ… проєктів в групі Ñ– дозволÑÑŽÑ‚ÑŒ вам Ñтандартизувати Ñ—Ñ… Ð´Ð»Ñ Ð²Ñієї вашої групи."
msgid "Webhooks have moved. They can now be found under the Settings menu."
msgstr ""
@@ -28245,7 +29208,7 @@ msgid "Webhooks|Trigger"
msgstr ""
msgid "Webhooks|URL"
-msgstr ""
+msgstr "URL-адреÑа"
msgid "Webhooks|Use this token to validate received payloads. It will be sent with the request in the X-Gitlab-Token HTTP header."
msgstr ""
@@ -28257,7 +29220,7 @@ msgid "Wednesday"
msgstr "Середа"
msgid "Weekday"
-msgstr ""
+msgstr "Будній день"
msgid "Weeks"
msgstr "Тижні"
@@ -28283,15 +29246,9 @@ msgstr "ЛаÑкаво проÑимо до GitLab, %{first_name}!"
msgid "Welcome to the guided GitLab tour"
msgstr ""
-msgid "Welcome to your Issue Board!"
-msgstr "ЛаÑкаво проÑимо до дошки Ð¾Ð±Ð³Ð¾Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð·Ð°Ð´Ð°Ñ‡!"
-
msgid "Welcome to your issue board!"
msgstr ""
-msgid "We’ve been making changes to %{featureName} and we’d love your feedback %{linkStart}in this issue%{linkEnd} to help us improve the experience."
-msgstr ""
-
msgid "What are you searching for?"
msgstr "Що ви шукаєте?"
@@ -28299,7 +29256,7 @@ msgid "What describes you best?"
msgstr ""
msgid "What's new at GitLab"
-msgstr ""
+msgstr "Що нового в GitLab"
msgid "What’s your experience level?"
msgstr ""
@@ -28308,7 +29265,10 @@ msgid "When a deployment job is successful, skip older deployment jobs that are
msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
-msgstr "Коли runner закріплений (за проектами), його не можна викориÑтовувати в інших проектах"
+msgstr "Коли runner закріплений (за проєктами), його не можна викориÑтовувати в інших проєктах"
+
+msgid "When enabled, any user visiting %{host} and creating an account will have to be explicitly approved by the admin before they can login. This setting is effective only if sign-ups are enabled."
+msgstr ""
msgid "When enabled, any user visiting %{host} will be able to create an account."
msgstr ""
@@ -28320,7 +29280,7 @@ msgid "When enabled, users cannot use GitLab until the terms have been accepted.
msgstr "Якщо увімкнено, кориÑтувачі не можуть викориÑтовувати GitLab, поки вони не приймуть умови."
msgid "When leaving the URL blank, classification labels can still be specified without disabling cross project features or performing external authorization checks."
-msgstr "Якщо залишити URL порожнім, можна вÑтановлювати мітки клаÑифікації без Ð²Ð¸Ð¼ÐºÐ½ÐµÐ½Ð½Ñ Ñ„ÑƒÐ½ÐºÑ†Ñ–Ð¹ проекту та Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ Ð·Ð¾Ð²Ð½Ñ–ÑˆÐ½ÑŒÐ¾Ñ— авторизації."
+msgstr "Якщо залишити URL порожнім, можна вÑтановлювати мітки клаÑифікації без Ð²Ð¸Ð¼ÐºÐ½ÐµÐ½Ð½Ñ Ñ„ÑƒÐ½ÐºÑ†Ñ–Ð¹ проєкту та Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ Ð·Ð¾Ð²Ð½Ñ–ÑˆÐ½ÑŒÐ¾Ñ— авторизації."
msgid "When this merge request is accepted"
msgid_plural "When these merge requests are accepted"
@@ -28387,7 +29347,7 @@ msgid "WikiEmptyIssueMessage|You must be a group member in order to add wiki pag
msgstr ""
msgid "WikiEmptyIssueMessage|You must be a project member in order to add wiki pages. If you have suggestions for how to improve the wiki for this project, consider opening an issue in the %{issues_link}."
-msgstr "Ви маєте бути учаÑником проекту Ð´Ð»Ñ Ñ‚Ð¾Ð³Ð¾, щоб додавати вікі Ñторінки. Якщо у Ð²Ð°Ñ Ñ” пропозиції ÑтоÑовно Ð¿Ð¾ÐºÑ€Ð°Ñ‰ÐµÐ½Ð½Ñ Ð²Ñ–ÐºÑ– цього проекту, відкрийте задачу в %{issues_link}."
+msgstr "Ви маєте бути учаÑником проєкту Ð´Ð»Ñ Ñ‚Ð¾Ð³Ð¾, щоб додавати вікі Ñторінки. Якщо у Ð²Ð°Ñ Ñ” пропозиції ÑтоÑовно Ð¿Ð¾ÐºÑ€Ð°Ñ‰ÐµÐ½Ð½Ñ Ð²Ñ–ÐºÑ– цього проєкту, відкрийте задачу в %{issues_link}."
msgid "WikiEmptyIssueMessage|issue tracker"
msgstr "РеєÑÑ‚Ñ€ задач"
@@ -28399,7 +29359,7 @@ msgid "WikiEmpty|A wiki is where you can store all the details about your group.
msgstr ""
msgid "WikiEmpty|A wiki is where you can store all the details about your project. This can include why you've created it, its principles, how to use it, and so on."
-msgstr "Вікі дозволÑÑ” зберігати інформацію про ваш проект. Ðаприклад причину ÑтвореннÑ, принципи, Ñк його викориÑтовувати Ñ– Ñ‚. д."
+msgstr "Вікі дозволÑÑ” зберігати інформацію про ваш проєкт. Ðаприклад причину ÑтвореннÑ, принципи, Ñк його викориÑтовувати Ñ– Ñ‚. д."
msgid "WikiEmpty|Confluence is enabled"
msgstr "Confluence увімкнено"
@@ -28420,7 +29380,7 @@ msgid "WikiEmpty|The wiki lets you write documentation for your group"
msgstr ""
msgid "WikiEmpty|The wiki lets you write documentation for your project"
-msgstr "Вікі дозволÑÑŽÑ‚ÑŒ пиÑати документацію Ð´Ð»Ñ Ð²Ð°ÑˆÐ¾Ð³Ð¾ проекту"
+msgstr "Вікі дозволÑÑŽÑ‚ÑŒ пиÑати документацію Ð´Ð»Ñ Ð²Ð°ÑˆÐ¾Ð³Ð¾ проєкту"
msgid "WikiEmpty|This group has no wiki pages"
msgstr "Ð’ цій групі немає Ñторінок вікі"
@@ -28432,7 +29392,7 @@ msgid "WikiEmpty|You must be a group member in order to add wiki pages."
msgstr "Ви повинні бути учаÑником групи Ð´Ð»Ñ Ñ‚Ð¾Ð³Ð¾, щоб додавати вікі-Ñторінки."
msgid "WikiEmpty|You must be a project member in order to add wiki pages."
-msgstr "Ви повинні бути учаÑником проекту Ð´Ð»Ñ Ñ‚Ð¾Ð³Ð¾, щоб додавати вікі Ñторінки."
+msgstr "Ви повинні бути учаÑником проєкту Ð´Ð»Ñ Ñ‚Ð¾Ð³Ð¾, щоб додавати вікі Ñторінки."
msgid "WikiEmpty|You've enabled the Confluence Workspace integration. Your wiki will be viewable directly within Confluence. We are hard at work integrating Confluence more seamlessly into GitLab. If you'd like to stay up to date, follow our %{wiki_confluence_epic_link_start}Confluence epic%{wiki_confluence_epic_link_end}."
msgstr ""
@@ -28456,7 +29416,7 @@ msgid "WikiMarkdownDocs|documentation"
msgstr "документації"
msgid "WikiMarkdownTip|To link to a (new) page, simply type %{link_example}"
-msgstr ""
+msgstr "Ð”Ð»Ñ ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð¿Ð¾ÑÐ¸Ð»Ð°Ð½Ð½Ñ Ð½Ð° (нову) Ñторінку, проÑто введіть %{link_example}"
msgid "WikiNewPageTip|Tip: You can specify the full path for the new file. We will automatically create any missing directories."
msgstr "Порада: можна вказати повний шлÑÑ… до нового файлу. Ми автоматично Ñтворимо вÑÑ– відÑутні каталоги."
@@ -28536,6 +29496,9 @@ msgstr "Розгорне на"
msgid "With requirements, you can set criteria to check your products against."
msgstr ""
+msgid "With test cases, you can define conditions for your project to meet in determining quality"
+msgstr ""
+
msgid "Withdraw Access Request"
msgstr "СкаÑувати запит доÑтупу"
@@ -28551,6 +29514,9 @@ msgstr ""
msgid "Workflow Help"
msgstr ""
+msgid "Would you like to create a new branch?"
+msgstr ""
+
msgid "Write"
msgstr "ÐапиÑати"
@@ -28572,6 +29538,9 @@ msgstr "Створіть Ð¾Ð¿Ð¸Ñ Ñ€ÐµÐ»Ñ–Ð·Ñƒ або перетÑгніть Ñ„Ð
msgid "Wrong extern UID provided. Make sure Auth0 is configured correctly."
msgstr "Ðадано неправильний зовнішній UID. Будь лаÑка, налаштуйте Auth0 правильно."
+msgid "YYYY-MM-DD"
+msgstr ""
+
msgid "Yes"
msgstr "Так"
@@ -28582,10 +29551,10 @@ msgid "Yes, add it"
msgstr "Так, додати це"
msgid "Yes, close issue"
-msgstr ""
+msgstr "Так, закрити задачу"
msgid "Yes, delete project"
-msgstr ""
+msgstr "Так, видалити проєкт"
msgid "Yes, let me map Google Code users to full names or GitLab users."
msgstr "Так, дозволити мені зв’Ñзати кориÑтувачів Google Code із повними іменами кориÑтувачів GitLab."
@@ -28629,8 +29598,8 @@ msgstr ""
msgid "You are going to remove the fork relationship from %{project_full_name}. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "You are going to transfer %{project_full_name} to another owner. Are you ABSOLUTELY sure?"
-msgstr "Ви збираєтеÑÑ Ð¿ÐµÑ€ÐµÐ´Ð°Ñ‚Ð¸ проект %{project_full_name} іншому влаÑнику. Ви ÐБСОЛЮТÐО впевнені?"
+msgid "You are going to transfer %{project_full_name} to another namespace. Are you ABSOLUTELY sure?"
+msgstr ""
msgid "You are going to turn off the confidentiality. This means %{strongStart}everyone%{strongEnd} will be able to see and leave a comment on this %{issuableType}."
msgstr ""
@@ -28669,7 +29638,7 @@ msgid "You can %{linkStart}view the blob%{linkEnd} instead."
msgstr "ЗаміÑÑ‚ÑŒ цього ви можете %{linkStart}переглÑнути бінарні дані%{linkEnd}."
msgid "You can also create a project from the command line."
-msgstr "Ви також можете Ñтворити проект із командного Ñ€Ñдка."
+msgstr "Ви також можете Ñтворити проєкт із командного Ñ€Ñдка."
msgid "You can also press &#8984;-Enter"
msgstr "Ви також можете натиÑнути &#8984;-Enter"
@@ -28689,9 +29658,6 @@ msgstr "Також ви можете завантажувати файли з в
msgid "You can always edit this later"
msgstr "Ви завжди можете відредагувати це пізніше"
-msgid "You can apply your Trial to your Personal account or create a New Group."
-msgstr "Ви можете заÑтоÑувати пробну верÑÑ–ÑŽ до ОÑобиÑтого облікового запиÑу або Ñтворити Ðову Групу."
-
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings"
msgstr ""
@@ -28713,12 +29679,18 @@ msgstr "Ви можете легко вÑтановити Runner на клаÑÑ‚
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr "Ви можете фільтрувати за \"днÑми до злиттÑ\", натиÑнувши на колонки в таблиці."
+msgid "You can find more information about GitLab subscriptions in %{subscriptions_doc_link}."
+msgstr ""
+
msgid "You can generate an access token scoped to this project for each application to use the GitLab API."
msgstr ""
msgid "You can get started by cloning the repository or start adding files to it with one of the following options."
msgstr ""
+msgid "You can group test cases using labels. To learn about the future direction of this feature, visit %{linkStart}Quality Management direction page%{linkEnd}."
+msgstr ""
+
msgid "You can invite a new member to %{project_name} or invite another group."
msgstr ""
@@ -28734,6 +29706,9 @@ msgstr "Ви можете переÑуватиÑÑ Ð¿Ð¾ графу за допо
msgid "You can notify the app / group or a project by sending them an email notification"
msgstr ""
+msgid "You can now close this window."
+msgstr ""
+
msgid "You can now export your security dashboard to a CSV report."
msgstr ""
@@ -28744,7 +29719,7 @@ msgid "You can now submit a merge request to get this change into the original b
msgstr "Ви можете тепер відправити запит на злиттÑ, щоб Ñ†Ñ Ð·Ð¼Ñ–Ð½Ð° попала у вихідну гілку."
msgid "You can now submit a merge request to get this change into the original project."
-msgstr "Ви можете тепер відправити запит на злиттÑ, щоб Ñ†Ñ Ð·Ð¼Ñ–Ð½Ð° потрапила у вихідний проект."
+msgstr "Ви можете тепер відправити запит на злиттÑ, щоб Ñ†Ñ Ð·Ð¼Ñ–Ð½Ð° потрапила у вихідний проєкт."
msgid "You can only edit files when you are on a branch"
msgstr "Ви можете редагувати файли, лише перебуваючи у ÑкійÑÑŒ гілці"
@@ -28756,7 +29731,7 @@ msgid "You can only merge once this merge request is approved."
msgstr "Ви можете злити цей запит на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð»Ð¸ÑˆÐµ коли його буде затверджено."
msgid "You can only transfer the project to namespaces you manage."
-msgstr "Ви можете переміщувати проект тільки в проÑтори імен, Ñкими ви керуєте."
+msgstr "Ви можете переміщувати проєкт тільки в проÑтори імен, Ñкими ви керуєте."
msgid "You can only upload one design when dropping onto an existing design."
msgstr ""
@@ -28777,14 +29752,11 @@ msgid "You can set up jobs to only use Runners with specific tags. Separate tags
msgstr "Ви можете налаштувати Ð·Ð°Ð²Ð´Ð°Ð½Ð½Ñ Ð½Ð° викориÑÑ‚Ð°Ð½Ð½Ñ Runnir'ів з конкретними тегами. РозділÑйте теги комами."
msgid "You can specify notification level per group or per project."
-msgstr "Ви можете вказати рівень Ñповіщень на рівні групи або проекту."
+msgstr "Ви можете вказати рівень Ñповіщень на рівні групи або проєкту."
msgid "You can test your .gitlab-ci.yml in %{linkStart}CI Lint%{linkEnd}."
msgstr "Ви можете перевірити Ñвій .gitlab-ci.yml у %{linkStart}CI Lint%{linkEnd}."
-msgid "You can try again using %{begin_link}basic search%{end_link}"
-msgstr "Можна Ñпробувати ще раз, викориÑтовуючи %{begin_link}базовий пошук%{end_link}"
-
msgid "You cannot access the raw file. Please wait a minute."
msgstr "Ви не можете отримати доÑтуп до неформатованого файлу. Будь лаÑка, зачекайте хвилину."
@@ -28825,7 +29797,7 @@ msgid "You do not have permission to leave this %{namespaceType}."
msgstr "У Ð²Ð°Ñ Ð½ÐµÐ¼Ð°Ñ” дозволу залишити це %{namespaceType}."
msgid "You do not have permission to run the Web Terminal. Please contact a project administrator."
-msgstr "Ви не маєте дозволу запуÑкати Веб-термінал. Будь лаÑка, звернітьÑÑ Ð´Ð¾ адмініÑтратора проекту."
+msgstr "Ви не маєте дозволу запуÑкати Веб-термінал. Будь лаÑка, звернітьÑÑ Ð´Ð¾ адмініÑтратора проєкту."
msgid "You do not have permissions to run the import."
msgstr ""
@@ -28836,6 +29808,9 @@ msgstr "У Ð²Ð°Ñ Ð½ÐµÐ¼Ð°Ñ” необхідних прав доÑтупу, щоÐ
msgid "You don't have any U2F devices registered yet."
msgstr "У Ð²Ð°Ñ Ð½ÐµÐ¼Ð°Ñ” жодного зареєÑтрованого U2F приÑтрою."
+msgid "You don't have any WebAuthn devices registered yet."
+msgstr ""
+
msgid "You don't have any active chat names."
msgstr "У Ð²Ð°Ñ Ð½ÐµÐ¼Ð°Ñ” активних імен Ð´Ð»Ñ Ñ‡Ð°Ñ‚Ñ–Ð²."
@@ -28852,7 +29827,7 @@ msgid "You don't have any open merge requests"
msgstr ""
msgid "You don't have any projects available."
-msgstr "У Ð²Ð°Ñ Ð½ÐµÐ¼Ð°Ñ” жодних доÑтупних проектів."
+msgstr "У Ð²Ð°Ñ Ð½ÐµÐ¼Ð°Ñ” жодних доÑтупних проєктів."
msgid "You don't have any recent searches"
msgstr "У Ð²Ð°Ñ Ð½ÐµÐ¼Ð°Ñ” недавніх пошуків"
@@ -28903,13 +29878,13 @@ msgid "You have not added any approvers. Start by adding users or groups."
msgstr "Ви не додали жодної затверджуючої оÑоби. Почніть з Ð´Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ ÐºÐ¾Ñ€Ð¸Ñтувачів або груп."
msgid "You have reached your project limit"
-msgstr "Ви доÑÑгли Ñвого ліміту по кількоÑÑ‚Ñ– проектів"
+msgstr "Ви доÑÑгли Ñвого ліміту по кількоÑÑ‚Ñ– проєктів"
msgid "You have successfully purchased a %{plan} plan subscription for %{seats}. You’ll receive a receipt via email."
msgstr "Ви уÑпішно придбали підпиÑку на план %{plan} на %{seats}. Ви отримаєте чек електронною поштою."
msgid "You haven't added any issues to your project yet"
-msgstr "Ви ще не додавали ніÑких задач до ваших проектів"
+msgstr "Ви ще не додавали ніÑких задач до ваших проєктів"
msgid "You haven't selected any issues yet"
msgstr "Ви ще не вибрали ніÑких задач"
@@ -28923,6 +29898,9 @@ msgstr "Зараз ви можете закрити цей етап."
msgid "You must accept our Terms of Service and privacy policy in order to register an account"
msgstr "Ви повинні прийнÑти правила кориÑÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ ÑервіÑом Ñ– політику конфіденційноÑÑ‚Ñ– Ð´Ð»Ñ Ñ‚Ð¾Ð³Ð¾, щоб Ñтворити обліковий запиÑ"
+msgid "You must be logged in to search across all of GitLab"
+msgstr ""
+
msgid "You must disassociate %{domain} from all clusters it is attached to before deletion."
msgstr ""
@@ -28933,7 +29911,7 @@ msgid "You must have permission to create a project in a group before forking."
msgstr ""
msgid "You must have permission to create a project in a namespace before forking."
-msgstr "Перед ÑтвореннÑм форку у Ð²Ð°Ñ Ð¼Ð°Ñ” бути дозвіл Ñтворювати проекти в ÑкомуÑÑŒ проÑторі імен."
+msgstr "Перед ÑтвореннÑм форку у Ð²Ð°Ñ Ð¼Ð°Ñ” бути дозвіл Ñтворювати проєкти в ÑкомуÑÑŒ проÑторі імен."
msgid "You must provide a valid current password"
msgstr "Вам потрібно вказати дійÑний поточний пароль"
@@ -28962,8 +29940,8 @@ msgstr "Вам потрібен дозвіл"
msgid "You need to be logged in."
msgstr "Ви повинні увійти."
-msgid "You need to register a two-factor authentication app before you can set up a U2F device."
-msgstr "Вам треба зареєÑтрувати програму Ð´Ð»Ñ Ð´Ð²Ð¾Ñ„Ð°ÐºÑ‚Ð¾Ñ€Ð½Ð¾Ñ— автентифікації перед налаштуваннÑм приÑтрою U2F."
+msgid "You need to register a two-factor authentication app before you can set up a device."
+msgstr ""
msgid "You need to set terms to be enforced"
msgstr ""
@@ -28972,7 +29950,7 @@ msgid "You need to specify both an Access Token and a Host URL."
msgstr "Вам необхідно вказати Ñк токен доÑтупу, так Ñ– URL хоÑта."
msgid "You need to upload a GitLab project export archive (ending in .gz)."
-msgstr "Ви повинні завантажити екÑпортований архів проекту Gitlab (що закінчуєтьÑÑ Ð½Ð° .gz)."
+msgstr "Ви повинні завантажити екÑпортований архів проєкту Gitlab (що закінчуєтьÑÑ Ð½Ð° .gz)."
msgid "You need to upload a Google Takeout archive."
msgstr "Вам потрібно завантажити архів Google Takeout."
@@ -28980,6 +29958,9 @@ msgstr "Вам потрібно завантажити архів Google Takeout
msgid "You reached %{usage_in_percent} of %{namespace_name}'s storage capacity (%{used_storage} of %{storage_limit})"
msgstr ""
+msgid "You successfully declined the invitation"
+msgstr ""
+
msgid "You tried to fork %{link_to_the_project} but it failed for the following reason:"
msgstr "Ви намагалиÑÑ Ñтворити Ð²Ñ–Ð´Ð³Ð°Ð»ÑƒÐ¶ÐµÐ½Ð½Ñ (форк) %{link_to_the_project}, але воно не вдалоÑÑ Ð· наÑтупної причини:"
@@ -29020,10 +30001,10 @@ msgid "You won't be able to create new projects because you have reached your pr
msgstr ""
msgid "You won't be able to pull or push project code via %{protocol} until you %{set_password_link} on your account"
-msgstr "Ви не зможете відправлÑти та отримувати код проекту через %{protocol} поки не %{set_password_link} Ð´Ð»Ñ Ð²Ð°ÑˆÐ¾Ð³Ð¾ облікового запиÑу"
+msgstr "Ви не зможете відправлÑти та отримувати код проєкту через %{protocol} поки не %{set_password_link} Ð´Ð»Ñ Ð²Ð°ÑˆÐ¾Ð³Ð¾ облікового запиÑу"
msgid "You won't be able to pull or push project code via SSH until you add an SSH key to your profile"
-msgstr "Ви не зможете відправлÑти та отримувати код проекту через SSH, поки не додаÑте в Ñвій профіль SSH ключ"
+msgstr "Ви не зможете відправлÑти та отримувати код проєкту через SSH, поки не додаÑте в Ñвій профіль SSH ключ"
msgid "You'll be charged for %{true_up_link_start}users over license%{link_end} on a quartely or annual basis, depending on the terms of your agreement."
msgstr ""
@@ -29047,13 +30028,13 @@ msgid "You're at the last commit"
msgstr ""
msgid "You're not allowed to %{tag_start}edit%{tag_end} files in this project directly. Please fork this project, make your changes there, and submit a merge request."
-msgstr "Вам не дозволено %{tag_start}редагувати%{tag_end} файли в цьому проекті. Будь лаÑка, зробіть форк цього проекту, внеÑÑ–Ñ‚ÑŒ туди Ñвої зміни Ñ– Ñтворіть запит на злиттÑ."
+msgstr "Вам не дозволено %{tag_start}редагувати%{tag_end} файли в цьому проєкті. Будь лаÑка, зробіть форк цього проєкту, внеÑÑ–Ñ‚ÑŒ туди Ñвої зміни Ñ– Ñтворіть запит на злиттÑ."
msgid "You're not allowed to make changes to this project directly. A fork of this project has been created that you can make changes in, so you can submit a merge request."
-msgstr "Вам не дозволено вноÑити зміни до цього проекту. Створено форк цього проекту, в Ñкому ви можете Ñ—Ñ… здійÑнити, а потім Ñтворити запит на злиттÑ."
+msgstr "Вам не дозволено вноÑити зміни до цього проєкту. Створено форк цього проєкту, в Ñкому ви можете Ñ—Ñ… здійÑнити, а потім Ñтворити запит на злиттÑ."
msgid "You're not allowed to make changes to this project directly. A fork of this project is being created that you can make changes in, so you can submit a merge request."
-msgstr "Вам не дозволÑєтьÑÑ Ð²Ð½Ð¾Ñити зміни до цього проекту напрÑму. СтворюєтьÑÑ Ñ„Ð¾Ñ€Ðº цього проекту в Ñкому ви можете робити зміни з тим, щоб Ñтворювати запити на злиттÑ."
+msgstr "Вам не дозволÑєтьÑÑ Ð²Ð½Ð¾Ñити зміни до цього проєкту напрÑму. СтворюєтьÑÑ Ñ„Ð¾Ñ€Ðº цього проєкту в Ñкому ви можете робити зміни з тим, щоб Ñтворювати запити на злиттÑ."
msgid "You're only seeing %{startTag}other activity%{endTag} in the feed. To add a comment, switch to one of the following options."
msgstr "Ви бачите лише %{startTag}іншу активніÑÑ‚ÑŒ%{endTag} в каналі. Ð”Ð»Ñ Ð´Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ ÐºÐ¾Ð¼ÐµÐ½Ñ‚Ð°Ñ€Ñ, виберіть одну з наÑтупних опцій."
@@ -29119,7 +30100,7 @@ msgid "Your Groups"
msgstr "Ваші групи"
msgid "Your License"
-msgstr ""
+msgstr "Ваша ліцензіÑ"
msgid "Your Personal Access Tokens will expire in %{days_to_expire} days or less"
msgstr "Термін дії вашого перÑонального токену доÑтупу закінчитьÑÑ Ñ‡ÐµÑ€ÐµÐ· %{days_to_expire} днів або менше"
@@ -29145,12 +30126,15 @@ msgstr "Ваш ÑпиÑок нагадувань"
msgid "Your U2F device did not send a valid JSON response."
msgstr "Ваш приÑтрій U2F не надіÑлав коректну відповідь JSON."
-msgid "Your U2F device needs to be set up. Plug it in (if not already) and click the button on the left."
-msgstr "Ваш приÑтрій U2F має бути налаштований. Підключіть його (Ñкщо ви цього ще не зробили) Ñ– натиÑніть кнопку зліва."
-
msgid "Your U2F device was registered!"
msgstr "Ваш приÑтрій U2F уÑпішно зареєÑтровано!"
+msgid "Your WebAuthn device did not send a valid JSON response."
+msgstr ""
+
+msgid "Your WebAuthn device was registered!"
+msgstr ""
+
msgid "Your access request to the %{source_type} has been withdrawn."
msgstr "Ваш запит на Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ Ð´Ð¾Ñтупу до %{source_type} відкликано."
@@ -29172,6 +30156,9 @@ msgstr "Ваші авторизовані заÑтоÑунки"
msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
msgstr "Ваш браузер не підтримує U2F. Будь лаÑка, викориÑтовйте Google Chrome Ð´Ð»Ñ ÐºÐ¾Ð¼Ð¿'ютера (верÑÑ–ÑŽ 41 або новішу)."
+msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
+msgstr ""
+
msgid "Your changes can be committed to %{branch_name} because a merge request is open."
msgstr "Ваші зміни можуть бути закомічені до %{branch_name}, оÑкільки запит на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð²Ñ–Ð´ÐºÑ€Ð¸Ñ‚Ð¸Ð¹."
@@ -29208,6 +30195,12 @@ msgstr "Ваша панель ÐºÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð±ÑƒÐ»Ð° оновлена. Ви
msgid "Your deployment services will be broken, you will need to manually fix the services after renaming."
msgstr "Ваші ÑервіÑи Ñ€Ð¾Ð·Ð³Ð¾Ñ€Ñ‚Ð°Ð½Ð½Ñ Ð±ÑƒÐ´ÑƒÑ‚ÑŒ порушені, вам необхідно буде вручну Ñ—Ñ… виправити піÑÐ»Ñ Ð¿ÐµÑ€ÐµÐ¹Ð¼ÐµÐ½ÑƒÐ²Ð°Ð½Ð½Ñ."
+msgid "Your device is not compatible with GitLab. Please try another device"
+msgstr ""
+
+msgid "Your device needs to be set up. Plug it in (if needed) and click the button on the left."
+msgstr ""
+
msgid "Your device was successfully set up! Give it a name and register it with the GitLab server."
msgstr "Ваш приÑтрій уÑпішно налаштовано! Дайте йому ім'Ñ Ñ‚Ð° зареєÑтруйте його на Ñервері GitLab."
@@ -29254,7 +30247,7 @@ msgid "Your new personal access token has been created."
msgstr "Ваш новий перÑональний токен доÑтупу Ñтворено."
msgid "Your new project access token has been created."
-msgstr "Ваш новий токен доÑтупу до проекту було Ñтворено."
+msgstr "Ваш новий токен доÑтупу до проєкту було Ñтворено."
msgid "Your password isn't required to view this page. If a password or any other personal details are requested, please contact your administrator to report abuse."
msgstr "Ваш пароль не потрібен Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÐ³Ð»Ñду цієї Ñторінки. Якщо вимагаєтьÑÑ Ð²Ð²ÐµÑти пароль або будь-Ñкі інші оÑобиÑÑ‚Ñ– дані, зв’ÑжітьÑÑ Ð·Ñ– Ñвоїм адмініÑтратором, щоб повідомити про порушеннÑ."
@@ -29269,7 +30262,7 @@ msgid "Your profile"
msgstr "Ваш профіль"
msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it"
-msgstr "Ваш ліміт проектів Ñкладає %{limit}! Будь лаÑка, звернітьÑÑ Ð´Ð¾ адмініÑтратора, щоб його збільшити"
+msgstr "Ваш ліміт проєктів Ñкладає %{limit}! Будь лаÑка, звернітьÑÑ Ð´Ð¾ адмініÑтратора, щоб його збільшити"
msgid "Your projects"
msgstr "Ваші проєкти"
@@ -29321,10 +30314,7 @@ msgstr[2] "близько %d годин"
msgstr[3] "близько %d годин"
msgid "access:"
-msgstr ""
-
-msgid "activated"
-msgstr "активований"
+msgstr "доÑтуп:"
msgid "added %{created_at_timeago}"
msgstr "додано %{created_at_timeago}"
@@ -29336,7 +30326,7 @@ msgid "ago"
msgstr "тому"
msgid "alert"
-msgstr ""
+msgstr "попередженнÑ"
msgid "allowed to fail"
msgstr "невдача дозволена"
@@ -29354,7 +30344,7 @@ msgid "among other things"
msgstr "тощо"
msgid "and"
-msgstr ""
+msgstr "Ñ–"
msgid "any-approver for the merge request already exists"
msgstr ""
@@ -29363,13 +30353,13 @@ msgid "any-approver for the project already exists"
msgstr ""
msgid "approved by: "
-msgstr ""
+msgstr "затверджено кориÑтувачем: "
msgid "archived"
msgstr "заархівовано"
msgid "archived:"
-msgstr ""
+msgstr "архівовано:"
msgid "as %{role}."
msgstr ""
@@ -29378,7 +30368,7 @@ msgid "assign yourself"
msgstr "призначити Ñамому Ñобі"
msgid "at risk"
-msgstr ""
+msgstr "під загрозою"
msgid "attach a new file"
msgstr "прикріпити новий файл"
@@ -29387,7 +30377,7 @@ msgid "authored"
msgstr "автор"
msgid "blocks"
-msgstr ""
+msgstr "блокує"
msgid "branch name"
msgstr "ім'Ñ Ð³Ñ–Ð»ÐºÐ¸"
@@ -29396,10 +30386,22 @@ msgid "by"
msgstr "від"
msgid "by %{user}"
+msgstr "від %{user}"
+
+msgid "cannot be a date in the past"
msgstr ""
msgid "cannot be changed if a personal project has container registry tags."
-msgstr "не може бути змінено Ñкщо в реєÑтрі контейнерів оÑобиÑтого проекту Ñ” теги."
+msgstr "не може бути змінено Ñкщо в реєÑтрі контейнерів оÑобиÑтого проєкту Ñ” теги."
+
+msgid "cannot be changed if shared runners are enabled"
+msgstr ""
+
+msgid "cannot be enabled because parent group does not allow it"
+msgstr ""
+
+msgid "cannot be enabled because parent group has shared Runners disabled"
+msgstr ""
msgid "cannot be enabled unless all domains have TLS certificates"
msgstr "не може бути активовано, Ñкщо не вÑÑ– домени мають Ñертифікати TLS"
@@ -29446,7 +30448,7 @@ msgstr "%{linkStartTag}ДізнайтеÑÑ Ð±Ñ–Ð»ÑŒÑˆÐµ про Ñкануван
msgid "ciReport|%{linkStartTag}Learn more about SAST %{linkEndTag}"
msgstr "%{linkStartTag}ДізнайтеÑÑ Ð±Ñ–Ð»ÑŒÑˆÐµ про SAST%{linkEndTag}"
-msgid "ciReport|%{linkStartTag}Learn more about Secret Scanning %{linkEndTag}"
+msgid "ciReport|%{linkStartTag}Learn more about Secret Detection %{linkEndTag}"
msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about codequality reports %{linkEndTag}"
@@ -29474,7 +30476,7 @@ msgid "ciReport|(is loading, errors when loading results)"
msgstr "(завантажуєтьÑÑ, помилки під Ñ‡Ð°Ñ Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ Ñ€ÐµÐ·ÑƒÐ»ÑŒÑ‚Ð°Ñ‚Ñ–Ð²)"
msgid "ciReport|All projects"
-msgstr "Ð’ÑÑ– проекти"
+msgstr "Ð’ÑÑ– проєкти"
msgid "ciReport|All scanners"
msgstr ""
@@ -29716,7 +30718,7 @@ msgid "disabled"
msgstr "вимкнено"
msgid "does not exist"
-msgstr ""
+msgstr "не Ñ–Ñнує"
msgid "does not have a supported extension. Only %{extension_list} are supported"
msgstr "не підтримує розширеннÑ. ПідтримуютьÑÑ Ð»Ð¸ÑˆÐµ %{extension_list}"
@@ -29725,7 +30727,7 @@ msgid "done"
msgstr "готово"
msgid "download it"
-msgstr ""
+msgstr "завантажити це"
msgid "draft"
msgid_plural "drafts"
@@ -29767,9 +30769,6 @@ msgstr "епік"
msgid "error"
msgstr "помилка"
-msgid "error code:"
-msgstr "код помилки:"
-
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr "%{slash_command} перезапиÑує запланований Ñ‡Ð°Ñ Ð¾Ñтаннім значеннÑм."
@@ -29791,6 +30790,9 @@ msgstr "невдало"
msgid "failed to dismiss associated finding(id=%{finding_id}): %{message}"
msgstr "не вдалоÑÑ Ð²Ñ–Ð´Ñ…Ð¸Ð»Ð¸Ñ‚Ð¸ пов’Ñзану знахідку(id=%{finding_id}): %{message}"
+msgid "failed to revert associated finding(id=%{finding_id}) to detected"
+msgstr ""
+
msgid "file"
msgid_plural "files"
msgstr[0] "файл"
@@ -29833,7 +30835,7 @@ msgid "group"
msgstr "група"
msgid "group members"
-msgstr ""
+msgstr "учаÑники групи"
msgid "groups"
msgstr "групи"
@@ -29872,7 +30874,7 @@ msgid "in group %{link_to_group}"
msgstr "в групі %{link_to_group}"
msgid "in project %{link_to_project}"
-msgstr "в проекті %{link_to_project}"
+msgstr "в проєкті %{link_to_project}"
msgid "instance completed"
msgid_plural "instances completed"
@@ -29906,7 +30908,7 @@ msgid "is invalid because there is upstream lock"
msgstr "неправильний через наÑвніÑÑ‚ÑŒ блокувань на вищих рівнÑÑ…"
msgid "is not"
-msgstr ""
+msgstr "не є"
msgid "is not a descendant of the Group owning the template"
msgstr "не Ñ” нащадком групи, Ñкій належить шаблон"
@@ -29927,7 +30929,7 @@ msgid "is not in the group enforcing Group Managed Account"
msgstr ""
msgid "is read only"
-msgstr ""
+msgstr "лише Ð´Ð»Ñ Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ"
msgid "is too long (%{current_value}). The maximum size is %{max_size}."
msgstr "Ñ” занадто довгим (%{current_value}). МакÑимальний розмір Ñкладає %{max_size}."
@@ -29945,7 +30947,7 @@ msgid "issues at risk"
msgstr ""
msgid "issues need attention"
-msgstr ""
+msgstr "задачі потребують уваги"
msgid "issues on track"
msgstr ""
@@ -29969,7 +30971,7 @@ msgid "jigsaw is not defined"
msgstr "jigsaw не визначено"
msgid "last commit:"
-msgstr ""
+msgstr "оÑтанній коміт:"
msgid "latest"
msgstr "оÑтанній"
@@ -30051,7 +31053,7 @@ msgid "mrWidgetNothingToMerge|Interested parties can even contribute by pushing
msgstr "Зацікавлені Ñторони за бажаннÑм навіть можуть робити внеÑки шлÑхом Ð²Ñ–Ð´Ð¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð½Ñ ÐºÐ¾Ð¼Ñ–Ñ‚Ñ–Ð²."
msgid "mrWidgetNothingToMerge|Merge requests are a place to propose changes you have made to a project and discuss those changes with others."
-msgstr "Запити на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð´Ð¾Ð·Ð²Ð¾Ð»ÑÑŽÑ‚ÑŒ запропонувати зміни Ñкі ви зробили в проекті та обговорити ці зміни з іншими."
+msgstr "Запити на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð´Ð¾Ð·Ð²Ð¾Ð»ÑÑŽÑ‚ÑŒ запропонувати зміни Ñкі ви зробили в проєкті та обговорити ці зміни з іншими."
msgid "mrWidget| Please restore it or use a different %{missingBranchName} branch"
msgstr "Будь лаÑка відновіть Ñ—Ñ— або викориÑтовуйте іншу %{missingBranchName} гілку"
@@ -30297,10 +31299,10 @@ msgid "mrWidget|This merge request is in the process of being merged"
msgstr "Запит на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð² процеÑÑ– виконаннÑ"
msgid "mrWidget|This project is archived, write access has been disabled"
-msgstr "Цей проект заархівований, доÑтуп до запиÑу було відключено"
+msgstr "Цей проєкт заархівований, доÑтуп до запиÑу було відключено"
msgid "mrWidget|To approve this merge request, please enter your password. This project requires all approvals to be authenticated."
-msgstr "Ð”Ð»Ñ Ð·Ð°Ñ‚Ð²ÐµÑ€Ð´Ð¶ÐµÐ½Ð½Ñ Ñ†ÑŒÐ¾Ð³Ð¾ запиту на злиттÑ, введіть ваш пароль. Цей проект вимагає Ð¿Ñ€Ð¾Ñ…Ð¾Ð´Ð¶ÐµÐ½Ð½Ñ Ð°Ð²Ñ‚ÐµÐ½Ñ‚Ð¸Ñ„Ñ–ÐºÐ°Ñ†Ñ–Ñ— Ð´Ð»Ñ Ð²ÑÑ–Ñ… затверджень."
+msgstr "Ð”Ð»Ñ Ð·Ð°Ñ‚Ð²ÐµÑ€Ð´Ð¶ÐµÐ½Ð½Ñ Ñ†ÑŒÐ¾Ð³Ð¾ запиту на злиттÑ, введіть ваш пароль. Цей проєкт вимагає Ð¿Ñ€Ð¾Ñ…Ð¾Ð´Ð¶ÐµÐ½Ð½Ñ Ð°Ð²Ñ‚ÐµÐ½Ñ‚Ð¸Ñ„Ñ–ÐºÐ°Ñ†Ñ–Ñ— Ð´Ð»Ñ Ð²ÑÑ–Ñ… затверджень."
msgid "mrWidget|Use %{linkStart}CI pipelines to test your code%{linkEnd} by simply adding a GitLab CI configuration file to your project. It only takes a minute to make your code more secure and robust."
msgstr ""
@@ -30341,6 +31343,9 @@ msgstr "Ñтворити ланцюжок змін піÑÐ»Ñ ÑƒÑпішного
msgid "must be a root namespace"
msgstr ""
+msgid "must be a valid IPv4 or IPv6 address"
+msgstr ""
+
msgid "must be greater than start date"
msgstr "повинна бути пізніша за дату початку"
@@ -30354,13 +31359,13 @@ msgid "n/a"
msgstr "н/д"
msgid "need attention"
-msgstr ""
+msgstr "потребує уваги"
msgid "needs to be between 10 minutes and 1 month"
msgstr "має бути між 10 хвилинами та 1 міÑÑцем"
msgid "never"
-msgstr ""
+msgstr "ніколи"
msgid "never expires"
msgstr ""
@@ -30369,7 +31374,7 @@ msgid "new merge request"
msgstr "Ðовий запит на злиттÑ"
msgid "no approvers"
-msgstr ""
+msgstr "немає затверджуючих оÑіб"
msgid "no contributions"
msgstr "немає внеÑків"
@@ -30377,6 +31382,9 @@ msgstr "немає внеÑків"
msgid "no expiration"
msgstr ""
+msgid "no name set"
+msgstr ""
+
msgid "no one can merge"
msgstr "ніхто не може виконати злиттÑ"
@@ -30402,7 +31410,7 @@ msgid "nounSeries|%{item}, and %{lastItem}"
msgstr "%{item}, Ñ– %{lastItem}"
msgid "on track"
-msgstr ""
+msgstr "по плану"
msgid "open issue"
msgstr ""
@@ -30449,7 +31457,7 @@ msgid "per day"
msgstr "за день"
msgid "personal access token"
-msgstr ""
+msgstr "оÑобиÑтий токен доÑтупу"
msgid "personal access tokens"
msgstr ""
@@ -30499,10 +31507,10 @@ msgid "project bots cannot be added to other groups / projects"
msgstr ""
msgid "project is read-only"
-msgstr ""
+msgstr "проєкт доÑтупний тільки Ð´Ð»Ñ Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ"
msgid "project members"
-msgstr ""
+msgstr "учаÑники проєкту"
msgid "projects"
msgstr "проєкти"
@@ -30520,7 +31528,7 @@ msgid "register"
msgstr "зареєÑтруватиÑÑ"
msgid "relates to"
-msgstr ""
+msgstr "ÑтоÑуєтьÑÑ"
msgid "released %{time}"
msgstr "випущено %{time}"
@@ -30565,9 +31573,6 @@ msgstr ""
msgid "security Reports|There was an error creating the merge request"
msgstr "помилка при Ñтворенні запиту на злиттÑ"
-msgid "settings saved, but not activated"
-msgstr "Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð·Ð±ÐµÑ€ÐµÐ¶ÐµÐ½Ð¾, але не активовано"
-
msgid "severity|Critical"
msgstr "Критичний"
@@ -30617,7 +31622,7 @@ msgid "source diff"
msgstr "Ñ€Ñ–Ð·Ð½Ð¸Ñ†Ñ Ð² коді"
msgid "specific"
-msgstr ""
+msgstr "конкретний"
msgid "specified top is not part of the tree"
msgstr "вказана вершина не Ñ” чаÑтиною дерева"
@@ -30694,9 +31699,6 @@ msgstr "в ÑпиÑок"
msgid "toggle collapse"
msgstr "згорнути/розгорнути"
-msgid "toggle dropdown"
-msgstr "розкрити чи закрити випадаючий ÑпиÑок"
-
msgid "triggered"
msgstr "запущено"
@@ -30719,11 +31721,14 @@ msgid "uploaded"
msgstr "завантажено"
msgid "uploads"
-msgstr ""
+msgstr "завантаженнÑ"
msgid "user avatar"
msgstr "аватар кориÑтувача"
+msgid "user preferences"
+msgstr ""
+
msgid "username"
msgstr "ім'Ñ ÐºÐ¾Ñ€Ð¸Ñтувача"
@@ -30752,7 +31757,7 @@ msgid "view the blob"
msgstr "переглÑнути бінарні дані"
msgid "view the source"
-msgstr ""
+msgstr "переглÑнути вихідний код"
msgid "vulnerability|Add a comment"
msgstr "Додати коментар"
diff --git a/locale/unfound_translations.rb b/locale/unfound_translations.rb
index 6f7934b4d65..c76518b0f4f 100644
--- a/locale/unfound_translations.rb
+++ b/locale/unfound_translations.rb
@@ -16,3 +16,4 @@ N_('NotificationEvent|Merge merge request')
N_('NotificationEvent|Failed pipeline')
N_('NotificationEvent|Fixed pipeline')
N_('NotificationEvent|New release')
+N_('NotificationEvent|Change reviewer merge request')
diff --git a/locale/ur_PK/gitlab.po b/locale/ur_PK/gitlab.po
index 4d2d49c9829..10b394ca888 100644
--- a/locale/ur_PK/gitlab.po
+++ b/locale/ur_PK/gitlab.po
@@ -14,7 +14,10 @@ msgstr ""
"X-Crowdin-Language: ur-PK\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 6\n"
-"PO-Revision-Date: 2020-09-04 23:01\n"
+"PO-Revision-Date: 2020-10-02 18:41\n"
+
+msgid " %{project_name}#%{issue_iid} &middot; opened %{issue_created} by %{author}"
+msgstr ""
msgid " %{start} to %{end}"
msgstr ""
@@ -74,6 +77,16 @@ msgstr ""
msgid "\"el\" parameter is required for createInstance()"
msgstr ""
+msgid "%d Approval"
+msgid_plural "%d Approvals"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d Package"
+msgid_plural "%d Packages"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d Scanned URL"
msgid_plural "%d Scanned URLs"
msgstr[0] ""
@@ -137,6 +150,11 @@ msgstr[1] ""
msgid "%d commits"
msgstr ""
+msgid "%d completed issue"
+msgid_plural "%d completed issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d contribution"
msgid_plural "%d contributions"
msgstr[0] ""
@@ -147,6 +165,11 @@ msgid_plural "%d days"
msgstr[0] ""
msgstr[1] ""
+msgid "%d day until tags are automatically removed"
+msgid_plural "%d days until tags are automatically removed"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d error"
msgid_plural "%d errors"
msgstr[0] ""
@@ -237,6 +260,16 @@ msgid_plural "%d more comments"
msgstr[0] ""
msgstr[1] ""
+msgid "%d open issue"
+msgid_plural "%d open issues"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d pending comment"
+msgid_plural "%d pending comments"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d personal project will be removed and cannot be restored."
msgid_plural "%d personal projects will be removed and cannot be restored."
msgstr[0] ""
@@ -252,6 +285,11 @@ msgid_plural "%d projects"
msgstr[0] ""
msgstr[1] ""
+msgid "%d project selected"
+msgid_plural "%d projects selected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d request with warnings"
msgid_plural "%d requests with warnings"
msgstr[0] ""
@@ -272,6 +310,11 @@ msgid_plural "%d tags"
msgstr[0] ""
msgstr[1] ""
+msgid "%d tag per image name"
+msgid_plural "%d tags per image name"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d unassigned issue"
msgid_plural "%d unassigned issues"
msgstr[0] ""
@@ -292,6 +335,11 @@ msgid_plural "%d vulnerabilities dismissed"
msgstr[0] ""
msgstr[1] ""
+msgid "%d warning found:"
+msgid_plural "%d warnings found:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%s additional commit has been omitted to prevent performance issues."
msgid_plural "%s additional commits have been omitted to prevent performance issues."
msgstr[0] ""
@@ -330,6 +378,9 @@ msgstr ""
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr ""
+msgid "%{completedCount} completed weight"
+msgstr ""
+
msgid "%{completedWeight} of %{totalWeight} weight completed"
msgstr ""
@@ -378,14 +429,12 @@ msgid_plural "%{count} participants"
msgstr[0] ""
msgstr[1] ""
-msgid "%{count} pending comment"
-msgid_plural "%{count} pending comments"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
+msgid "%{count} total weight"
+msgstr ""
+
msgid "%{dashboard_path} could not be found."
msgstr ""
@@ -440,6 +489,9 @@ msgstr ""
msgid "%{group_name} uses group managed accounts. You need to create a new GitLab account which will be managed by %{group_name}."
msgstr ""
+msgid "%{group_name}&%{epic_iid} &middot; opened %{epic_created} by %{author}"
+msgstr ""
+
msgid "%{host} sign-in from new location"
msgstr ""
@@ -452,7 +504,7 @@ msgstr ""
msgid "%{issuableType} will be removed! Are you sure?"
msgstr ""
-msgid "%{issuesSize} issues with a limit of %{maxIssueCount}"
+msgid "%{issuesCount} issues with a limit of %{maxIssueCount}"
msgstr ""
msgid "%{issuesSize} with a limit of %{maxIssueCount}"
@@ -485,7 +537,7 @@ msgstr ""
msgid "%{labelStart}Namespace:%{labelEnd} %{namespace}"
msgstr ""
-msgid "%{labelStart}Report Type:%{labelEnd} %{reportType}"
+msgid "%{labelStart}Scan Type:%{labelEnd} %{reportType}"
msgstr ""
msgid "%{labelStart}Scanner:%{labelEnd} %{scanner}"
@@ -682,9 +734,6 @@ msgid_plural "%{securityScanner} results are not available because a pipeline ha
msgstr[0] ""
msgstr[1] ""
-msgid "%{service_title} %{message}."
-msgstr ""
-
msgid "%{size} GiB"
msgstr ""
@@ -773,6 +822,12 @@ msgstr ""
msgid "%{timebox_name} should belong either to a project or a group."
msgstr ""
+msgid "%{timebox_type} does not support burnup charts"
+msgstr ""
+
+msgid "%{timebox_type} must have a start and due date"
+msgstr ""
+
msgid "%{title} %{operator} %{threshold}"
msgstr ""
@@ -797,7 +852,7 @@ msgstr ""
msgid "%{total} open issue weight"
msgstr ""
-msgid "%{total} open issues"
+msgid "%{total} warnings found: showing first %{warningsDisplayed}"
msgstr ""
msgid "%{usage_ping_link_start}Learn more%{usage_ping_link_end} about what information is shared with GitLab Inc."
@@ -830,9 +885,6 @@ msgstr ""
msgid "&lt; 1 hour"
msgstr ""
-msgid "&lt;no name set&gt;"
-msgstr ""
-
msgid "&lt;no scopes selected&gt;"
msgstr ""
@@ -863,6 +915,9 @@ msgstr ""
msgid "'%{name}' Value Stream created"
msgstr ""
+msgid "'%{name}' Value Stream deleted"
+msgstr ""
+
msgid "'%{name}' stage already exists"
msgstr ""
@@ -922,6 +977,9 @@ msgstr ""
msgid "+ %{numberOfHiddenAssignees} more"
msgstr ""
+msgid "+ %{numberOfHiddenReviewers} more"
+msgstr ""
+
msgid "+%d more"
msgid_plural "+%d more"
msgstr[0] ""
@@ -982,6 +1040,11 @@ msgid_plural "%d Days"
msgstr[0] ""
msgstr[1] ""
+msgid "1 Issue"
+msgid_plural "%d Issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "1 closed issue"
msgid_plural "%{issues} closed issues"
msgstr[0] ""
@@ -997,6 +1060,11 @@ msgid_plural "%d days"
msgstr[0] ""
msgstr[1] ""
+msgid "1 deploy key"
+msgid_plural "%d deploy keys"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1099,6 +1167,9 @@ msgstr ""
msgid ":%{startLine} to %{endLine}"
msgstr ""
+msgid "A %{incident_docs_start}modified issue%{incident_docs_end} to guide the resolution of incidents."
+msgstr ""
+
msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr ""
@@ -1111,6 +1182,9 @@ msgstr ""
msgid "A GitBook site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
+msgid "A Gitpod configured Webapplication in Spring and Java"
+msgstr ""
+
msgid "A Hexo site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
@@ -1282,9 +1356,15 @@ msgstr ""
msgid "Access expiration date"
msgstr ""
+msgid "Access expires"
+msgstr ""
+
msgid "Access forbidden. Check your access level."
msgstr ""
+msgid "Access granted"
+msgstr ""
+
msgid "Access requests"
msgstr ""
@@ -1294,6 +1374,9 @@ msgstr ""
msgid "Access to Pages websites are controlled based on the user's membership to a given project. By checking this box, users will be required to be logged in to have access to all Pages websites in your instance."
msgstr ""
+msgid "AccessDropdown|Deploy Keys"
+msgstr ""
+
msgid "AccessDropdown|Groups"
msgstr ""
@@ -1411,12 +1494,6 @@ msgstr ""
msgid "Active Sessions"
msgstr ""
-msgid "Active Users:"
-msgstr ""
-
-msgid "Active users"
-msgstr ""
-
msgid "Activity"
msgstr ""
@@ -1584,9 +1661,6 @@ msgstr ""
msgid "Add label(s)"
msgstr ""
-msgid "Add license"
-msgstr ""
-
msgid "Add list"
msgstr ""
@@ -1761,21 +1835,51 @@ msgstr ""
msgid "AdminArea|Bots"
msgstr ""
+msgid "AdminArea|Components"
+msgstr ""
+
msgid "AdminArea|Developer"
msgstr ""
+msgid "AdminArea|Features"
+msgstr ""
+
+msgid "AdminArea|Groups: %{number_of_groups}"
+msgstr ""
+
msgid "AdminArea|Guest"
msgstr ""
msgid "AdminArea|Included Free in license"
msgstr ""
+msgid "AdminArea|Latest groups"
+msgstr ""
+
+msgid "AdminArea|Latest projects"
+msgstr ""
+
+msgid "AdminArea|Latest users"
+msgstr ""
+
msgid "AdminArea|Maintainer"
msgstr ""
+msgid "AdminArea|New group"
+msgstr ""
+
+msgid "AdminArea|New project"
+msgstr ""
+
+msgid "AdminArea|New user"
+msgstr ""
+
msgid "AdminArea|Owner"
msgstr ""
+msgid "AdminArea|Projects: %{number_of_projects}"
+msgstr ""
+
msgid "AdminArea|Reporter"
msgstr ""
@@ -1803,6 +1907,9 @@ msgstr ""
msgid "AdminArea|Users without a Group and Project"
msgstr ""
+msgid "AdminArea|Users: %{number_of_users}"
+msgstr ""
+
msgid "AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running."
msgstr ""
@@ -1821,9 +1928,6 @@ msgstr ""
msgid "AdminProjects|Delete Project %{projectName}?"
msgstr ""
-msgid "AdminProjects|Delete project"
-msgstr ""
-
msgid "AdminSettings|Apply integration settings to all Projects"
msgstr ""
@@ -2061,21 +2165,30 @@ msgstr ""
msgid "AdminUsers|Without projects"
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 ""
msgid "AdminUsers|You cannot remove your own admin rights."
msgstr ""
+msgid "AdminUsers|You must transfer ownership or delete the groups owned by this user before you can delete their account"
+msgstr ""
+
msgid "Administration"
msgstr ""
msgid "Advanced"
msgstr ""
+msgid "Advanced Search"
+msgstr ""
+
+msgid "Advanced Search with Elasticsearch"
+msgstr ""
+
msgid "Advanced Settings"
msgstr ""
@@ -2153,6 +2266,9 @@ msgstr ""
msgid "AlertManagement|Edit"
msgstr ""
+msgid "AlertManagement|Environment"
+msgstr ""
+
msgid "AlertManagement|Events"
msgstr ""
@@ -2165,6 +2281,9 @@ msgstr ""
msgid "AlertManagement|Issue"
msgstr ""
+msgid "AlertManagement|Key"
+msgstr ""
+
msgid "AlertManagement|Low"
msgstr ""
@@ -2258,6 +2377,9 @@ msgstr ""
msgid "AlertManagement|Unknown"
msgstr ""
+msgid "AlertManagement|Value"
+msgstr ""
+
msgid "AlertManagement|View alerts in Opsgenie"
msgstr ""
@@ -2417,6 +2539,9 @@ msgstr ""
msgid "All projects"
msgstr ""
+msgid "All projects selected"
+msgstr ""
+
msgid "All security scans are enabled because %{linkStart}Auto DevOps%{linkEnd} is enabled on this project"
msgstr ""
@@ -2504,6 +2629,9 @@ msgstr ""
msgid "Almost there"
msgstr ""
+msgid "Already blocked"
+msgstr ""
+
msgid "Also called \"Issuer\" or \"Relying party trust identifier\""
msgstr ""
@@ -2558,6 +2686,9 @@ msgstr ""
msgid "An error has occurred"
msgstr ""
+msgid "An error occured while making the changes: %{error}"
+msgstr ""
+
msgid "An error occurred adding a draft to the thread."
msgstr ""
@@ -2585,12 +2716,6 @@ msgstr ""
msgid "An error occurred when toggling the notification subscription"
msgstr ""
-msgid "An error occurred when trying to resolve a comment. Please try again."
-msgstr ""
-
-msgid "An error occurred when trying to resolve a discussion. Please try again."
-msgstr ""
-
msgid "An error occurred when updating the issue weight"
msgstr ""
@@ -2606,12 +2731,6 @@ msgstr ""
msgid "An error occurred while checking group path. Please refresh and try again."
msgstr ""
-msgid "An error occurred while committing your changes."
-msgstr ""
-
-msgid "An error occurred while creating the list. Please try again."
-msgstr ""
-
msgid "An error occurred while decoding the file."
msgstr ""
@@ -2684,25 +2803,19 @@ msgstr ""
msgid "An error occurred while fetching the Service Desk address."
msgstr ""
-msgid "An error occurred while fetching the board issues. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the board lists. Please reload the page."
msgstr ""
msgid "An error occurred while fetching the board lists. Please try again."
msgstr ""
-msgid "An error occurred while fetching the board swimlanes. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the builds."
msgstr ""
msgid "An error occurred while fetching the job log."
msgstr ""
-msgid "An error occurred while fetching the job trace."
+msgid "An error occurred while fetching the job logs."
msgstr ""
msgid "An error occurred while fetching the job."
@@ -2849,9 +2962,6 @@ msgstr ""
msgid "An error occurred while saving assignees"
msgstr ""
-msgid "An error occurred while saving the template. Please check if the template exists."
-msgstr ""
-
msgid "An error occurred while searching for milestones"
msgstr ""
@@ -2870,10 +2980,10 @@ msgstr ""
msgid "An error occurred while updating approvers"
msgstr ""
-msgid "An error occurred while updating the comment"
+msgid "An error occurred while updating labels."
msgstr ""
-msgid "An error occurred while updating the list. Please try again."
+msgid "An error occurred while updating the comment"
msgstr ""
msgid "An error occurred while validating group path"
@@ -2927,6 +3037,9 @@ msgstr ""
msgid "An unknown error occurred while loading this graph."
msgstr ""
+msgid "An unknown error occurred."
+msgstr ""
+
msgid "Analytics"
msgstr ""
@@ -2960,10 +3073,10 @@ msgstr ""
msgid "Any"
msgstr ""
-msgid "Any Author"
+msgid "Any %{header}"
msgstr ""
-msgid "Any Status"
+msgid "Any Author"
msgstr ""
msgid "Any branch"
@@ -3017,6 +3130,9 @@ msgstr ""
msgid "Application ID"
msgstr ""
+msgid "Application limits saved successfully"
+msgstr ""
+
msgid "Application settings saved successfully"
msgstr ""
@@ -3226,6 +3342,9 @@ msgstr ""
msgid "Are you sure you want to close this blocked issue?"
msgstr ""
+msgid "Are you sure you want to delete \"%{name}\" Value Stream?"
+msgstr ""
+
msgid "Are you sure you want to delete %{name}?"
msgstr ""
@@ -3235,6 +3354,9 @@ msgstr ""
msgid "Are you sure you want to delete this %{typeOfComment}?"
msgstr ""
+msgid "Are you sure you want to delete this SSH key?"
+msgstr ""
+
msgid "Are you sure you want to delete this board?"
msgstr ""
@@ -3259,6 +3381,11 @@ msgstr ""
msgid "Are you sure you want to erase this build?"
msgstr ""
+msgid "Are you sure you want to import %d repository?"
+msgid_plural "Are you sure you want to import %d repositories?"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Are you sure you want to lose unsaved changes?"
msgstr ""
@@ -3268,15 +3395,15 @@ msgstr ""
msgid "Are you sure you want to merge immediately?"
msgstr ""
-msgid "Are you sure you want to permanently delete this license?"
-msgstr ""
-
msgid "Are you sure you want to re-deploy this environment?"
msgstr ""
msgid "Are you sure you want to regenerate the public key? You will have to update the public key on the remote server before mirroring will work again."
msgstr ""
+msgid "Are you sure you want to reindex?"
+msgstr ""
+
msgid "Are you sure you want to remove %{group_name}?"
msgstr ""
@@ -3304,6 +3431,9 @@ msgstr ""
msgid "Are you sure you want to revoke this nickname?"
msgstr ""
+msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
+msgstr ""
+
msgid "Are you sure you want to stop this environment?"
msgstr ""
@@ -3325,6 +3455,9 @@ msgstr ""
msgid "Are you sure? The device will be signed out of GitLab and all remember me tokens revoked."
msgstr ""
+msgid "Are you sure? This will invalidate your registered applications and U2F / WebAuthn devices."
+msgstr ""
+
msgid "Are you sure? This will invalidate your registered applications and U2F devices."
msgstr ""
@@ -3343,9 +3476,6 @@ msgstr ""
msgid "Artifacts"
msgstr ""
-msgid "As U2F devices are only supported by a few browsers, we require that you set up a two-factor authentication app before a U2F device. That way you'll always be able to log in - even when you're using an unsupported browser."
-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 ""
@@ -3539,6 +3669,9 @@ msgstr ""
msgid "AuditLogs|Target"
msgstr ""
+msgid "AuditLogs|This month"
+msgstr ""
+
msgid "AuditLogs|User Events"
msgstr ""
@@ -3578,6 +3711,9 @@ msgstr ""
msgid "Authentication via U2F device failed."
msgstr ""
+msgid "Authentication via WebAuthn device failed."
+msgstr ""
+
msgid "Author"
msgstr ""
@@ -3845,15 +3981,6 @@ msgstr ""
msgid "BambooService|You must set up automatic revision labeling and a repository trigger in Bamboo."
msgstr ""
-msgid "BatchComments|Delete all pending comments"
-msgstr ""
-
-msgid "BatchComments|Discard review?"
-msgstr ""
-
-msgid "BatchComments|You're about to discard your review which will delete all of your pending comments. The deleted comments %{strong_start}cannot%{strong_end} be restored."
-msgstr ""
-
msgid "Be careful. Changing the project's namespace can have unintended side effects."
msgstr ""
@@ -3875,6 +4002,9 @@ msgstr ""
msgid "Bi-weekly code coverage"
msgstr ""
+msgid "Billable Users:"
+msgstr ""
+
msgid "Billing"
msgstr ""
@@ -3884,7 +4014,7 @@ msgstr ""
msgid "BillingPlans|@%{user_name} you are currently using the %{plan_name} plan."
msgstr ""
-msgid "BillingPlans|Congratulations, your new trial is activated"
+msgid "BillingPlans|Congratulations, your free trial is activated."
msgstr ""
msgid "BillingPlans|If you would like to downgrade your plan please contact %{support_link_start}Customer Support%{support_link_end}."
@@ -3947,6 +4077,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Block user"
+msgstr ""
+
msgid "Blocked"
msgstr ""
@@ -3962,31 +4095,37 @@ msgstr ""
msgid "Blog"
msgstr ""
-msgid "Board name"
-msgstr ""
-
msgid "Board scope"
msgstr ""
msgid "Board scope affects which issues are displayed for anyone who visits this board"
msgstr ""
-msgid "BoardBlankState|Add default lists"
+msgid "Boards"
msgstr ""
-msgid "BoardBlankState|Add the following default lists to your Issue Board with one click:"
+msgid "Boards and Board Lists"
msgstr ""
-msgid "BoardBlankState|Nevermind, I'll use my own"
+msgid "Boards|An error occurred while creating the issue. Please try again."
msgstr ""
-msgid "BoardBlankState|Starting out with the default set of lists will get you right on the way to making the most of your board."
+msgid "Boards|An error occurred while creating the list. Please try again."
msgstr ""
-msgid "Boards"
+msgid "Boards|An error occurred while fetching issues. Please reload the page."
msgstr ""
-msgid "Boards and Board Lists"
+msgid "Boards|An error occurred while fetching the board issues. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching the board swimlanes. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while moving the issue. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while updating the list. Please try again."
msgstr ""
msgid "Boards|Collapse"
@@ -4013,7 +4152,7 @@ msgstr ""
msgid "Branch %{branch_name} was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr ""
-msgid "Branch has changed"
+msgid "Branch changed"
msgstr ""
msgid "Branch is already taken"
@@ -4319,6 +4458,9 @@ msgstr ""
msgid "CLOSED (MOVED)"
msgstr ""
+msgid "CODEOWNERS rule violation"
+msgstr ""
+
msgid "CONTRIBUTING"
msgstr ""
@@ -4349,9 +4491,6 @@ msgstr ""
msgid "Can't create snippet: %{err}"
msgstr ""
-msgid "Can't edit as source branch was deleted"
-msgstr ""
-
msgid "Can't fetch content for the blob: %{err}"
msgstr ""
@@ -4364,9 +4503,6 @@ msgstr ""
msgid "Can't load mermaid module: %{err}"
msgstr ""
-msgid "Can't remove group members without group managed account"
-msgstr ""
-
msgid "Can't scan the code?"
msgstr ""
@@ -4409,6 +4545,9 @@ msgstr ""
msgid "Cannot create the abuse report. This user has been blocked."
msgstr ""
+msgid "Cannot enable shared runners because parent group does not allow it"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -4514,6 +4653,15 @@ msgstr ""
msgid "Change your password or recover your current one"
msgstr ""
+msgid "ChangeReviewer|Reviewer changed from %{old} to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Reviewer changed to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Unassigned"
+msgstr ""
+
msgid "ChangeTypeActionLabel|Pick into branch"
msgstr ""
@@ -4553,6 +4701,9 @@ msgstr ""
msgid "Changes the title to \"%{title_param}\"."
msgstr ""
+msgid "Changes were successfully made."
+msgstr ""
+
msgid "Changes won't take place until the index is %{link_start}recreated%{link_end}."
msgstr ""
@@ -4958,6 +5109,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove variable"
+msgstr ""
+
msgid "CiVariables|Remove variable row"
msgstr ""
@@ -5036,9 +5190,6 @@ msgstr ""
msgid "Clear due date"
msgstr ""
-msgid "Clear input"
-msgstr ""
-
msgid "Clear recent searches"
msgstr ""
@@ -5087,6 +5238,9 @@ msgstr ""
msgid "Client authentication key password"
msgstr ""
+msgid "Client request timeout"
+msgstr ""
+
msgid "Clients"
msgstr ""
@@ -5171,6 +5325,27 @@ msgstr ""
msgid "Cluster type must be specificed for Stages::ClusterEndpointInserter"
msgstr ""
+msgid "ClusterAgents|Configuration"
+msgstr ""
+
+msgid "ClusterAgents|Connect your cluster with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate Kubernetes with a GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Name"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Agent also requires %{linkStart}enabling the Agent Server%{linkEnd}"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Kubernetes Agent allows an Infrastructure as Code, GitOps approach to integrating Kubernetes clusters with GitLab. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "ClusterAgent|This feature is only available for premium plans"
msgstr ""
@@ -5240,10 +5415,10 @@ msgstr ""
msgid "ClusterIntegration|All installed applications and related resources"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster."
+msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{linkStart}More information%{linkEnd}"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{startLink}More information%{endLink}"
+msgid "ClusterIntegration|Allow GitLab to manage namespaces and service accounts for this cluster."
msgstr ""
msgid "ClusterIntegration|Alternatively, "
@@ -5264,6 +5439,9 @@ msgstr ""
msgid "ClusterIntegration|An error occurred while trying to fetch zone machine types: %{error}"
msgstr ""
+msgid "ClusterIntegration|An unknown error occurred while attempting to connect to Kubernetes."
+msgstr ""
+
msgid "ClusterIntegration|Any project namespaces"
msgstr ""
@@ -5279,6 +5457,9 @@ msgstr ""
msgid "ClusterIntegration|Authenticate with Amazon Web Services"
msgstr ""
+msgid "ClusterIntegration|Authentication Error"
+msgstr ""
+
msgid "ClusterIntegration|Base domain"
msgstr ""
@@ -5297,13 +5478,22 @@ msgstr ""
msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}security group %{externalLinkIcon} %{endLink} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
+msgid "ClusterIntegration|Check your CA certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Check your cluster status"
+msgstr ""
+
+msgid "ClusterIntegration|Check your token"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}subnets %{externalLinkIcon} %{endLink} in your VPC where your worker nodes will run."
+msgid "ClusterIntegration|Choose the %{linkStart}security group %{linkEnd} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
msgstr ""
-msgid "ClusterIntegration|Choose the worker node %{startLink}instance type %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Choose the %{linkStart}subnets %{linkEnd} in your VPC where your worker nodes will run."
+msgstr ""
+
+msgid "ClusterIntegration|Choose the worker node %{linkStart}instance type%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Choose which applications to install on your Kubernetes cluster."
@@ -5315,10 +5505,7 @@ msgstr ""
msgid "ClusterIntegration|Clear cluster cache"
msgstr ""
-msgid "ClusterIntegration|Clear the local cache of namespace and service accounts. This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
-msgstr ""
-
-msgid "ClusterIntegration|Cluster being created"
+msgid "ClusterIntegration|Clear the local cache of namespace and service accounts."
msgstr ""
msgid "ClusterIntegration|Cluster management project (alpha)"
@@ -5330,15 +5517,21 @@ msgstr ""
msgid "ClusterIntegration|Cluster_applications artifact too big. Maximum allowable size: %{human_size}"
msgstr ""
-msgid "ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters."
+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|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}"
+msgid "ClusterIntegration|Clusters connected with a certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Connect cluster with certificate"
msgstr ""
msgid "ClusterIntegration|Connect existing cluster"
msgstr ""
+msgid "ClusterIntegration|Connection Error"
+msgstr ""
+
msgid "ClusterIntegration|Copy API URL"
msgstr ""
@@ -5414,6 +5607,12 @@ msgstr ""
msgid "ClusterIntegration|Deletes all GitLab resources attached to this cluster during removal"
msgstr ""
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared."
+msgstr ""
+
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared. %{linkStart}More information%{linkEnd}"
+msgstr ""
+
msgid "ClusterIntegration|Did you know?"
msgstr ""
@@ -5483,6 +5682,9 @@ msgstr ""
msgid "ClusterIntegration|Fluentd is an open source data collector, which lets you unify the data collection and consumption for a better use and understanding of data. It requires at least one of the following logs to be successfully installed."
msgstr ""
+msgid "ClusterIntegration|GitLab Agent managed clusters"
+msgstr ""
+
msgid "ClusterIntegration|GitLab Container Network Policies"
msgstr ""
@@ -5495,6 +5697,12 @@ msgstr ""
msgid "ClusterIntegration|GitLab Runner connects to the repository and executes CI/CD jobs, pushing results back and deploying applications to production."
msgstr ""
+msgid "ClusterIntegration|GitLab failed to authenticate."
+msgstr ""
+
+msgid "ClusterIntegration|GitLab failed to connect to the cluster."
+msgstr ""
+
msgid "ClusterIntegration|GitLab-managed cluster"
msgstr ""
@@ -5516,6 +5724,9 @@ msgstr ""
msgid "ClusterIntegration|Group cluster"
msgstr ""
+msgid "ClusterIntegration|HTTP Error"
+msgstr ""
+
msgid "ClusterIntegration|Helm Tiller"
msgstr ""
@@ -5549,7 +5760,10 @@ msgstr ""
msgid "ClusterIntegration|Instance type"
msgstr ""
-msgid "ClusterIntegration|Integrate Kubernetes cluster automation"
+msgid "ClusterIntegration|Integrate Kubernetes with a cluster certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Integrate with a cluster certificate"
msgstr ""
msgid "ClusterIntegration|Issuer Email"
@@ -5585,9 +5799,6 @@ msgstr ""
msgid "ClusterIntegration|Knative extends Kubernetes to provide a set of middleware components that are essential to build modern, source-centric, and container-based applications that can run anywhere: on premises, in the cloud, or even in a third-party data center."
msgstr ""
-msgid "ClusterIntegration|Kubernetes cluster"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes cluster is being created..."
msgstr ""
@@ -5600,9 +5811,6 @@ msgstr ""
msgid "ClusterIntegration|Kubernetes clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr ""
-msgid "ClusterIntegration|Kubernetes clusters can be used to deploy applications and to provide Review Apps for this project"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes version"
msgstr ""
@@ -5615,7 +5823,7 @@ msgstr ""
msgid "ClusterIntegration|Learn more about %{help_link_start}zones%{help_link_end}."
msgstr ""
-msgid "ClusterIntegration|Learn more about %{startLink}Regions %{externalLinkIcon}%{endLink}."
+msgid "ClusterIntegration|Learn more about %{linkStart}Regions%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Learn more about Kubernetes"
@@ -5660,12 +5868,18 @@ msgstr ""
msgid "ClusterIntegration|Machine type"
msgstr ""
+msgid "ClusterIntegration|Make sure your API endpoint is correct"
+msgstr ""
+
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create Kubernetes clusters"
msgstr ""
msgid "ClusterIntegration|Manage your Kubernetes cluster by visiting %{provider_link}"
msgstr ""
+msgid "ClusterIntegration|Namespace per environment"
+msgstr ""
+
msgid "ClusterIntegration|No IAM Roles found"
msgstr ""
@@ -5711,6 +5925,9 @@ msgstr ""
msgid "ClusterIntegration|No zones matched your search"
msgstr ""
+msgid "ClusterIntegration|Node calculations use the Kubernetes Metrics API. Make sure your cluster has metrics installed"
+msgstr ""
+
msgid "ClusterIntegration|Number of nodes"
msgstr ""
@@ -5753,6 +5970,9 @@ msgstr ""
msgid "ClusterIntegration|RBAC-enabled cluster"
msgstr ""
+msgid "ClusterIntegration|Read our %{linkStart}help page%{linkEnd} on Kubernetes cluster integration."
+msgstr ""
+
msgid "ClusterIntegration|Read our %{link_start}help page%{link_end} on Kubernetes cluster integration."
msgstr ""
@@ -5855,7 +6075,7 @@ msgstr ""
msgid "ClusterIntegration|Select a VPC to choose a subnet"
msgstr ""
-msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{linkStart}Amazon Web Services %{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select a network to choose a subnetwork"
@@ -5888,7 +6108,7 @@ msgstr ""
msgid "ClusterIntegration|Select project to choose zone"
msgstr ""
-msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select zone"
@@ -5978,9 +6198,18 @@ msgstr ""
msgid "ClusterIntegration|There was a problem authenticating with your cluster. Please ensure your CA Certificate and Token are valid."
msgstr ""
+msgid "ClusterIntegration|There was an HTTP error when connecting to your cluster."
+msgstr ""
+
msgid "ClusterIntegration|This account must have permissions to create a Kubernetes cluster in the %{link_to_container_project} specified below"
msgstr ""
+msgid "ClusterIntegration|This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
+msgstr ""
+
+msgid "ClusterIntegration|This is necessary to clear existing environment-namespace associations from clusters previously managed by GitLab."
+msgstr ""
+
msgid "ClusterIntegration|This option will allow you to install applications on RBAC clusters."
msgstr ""
@@ -6005,9 +6234,21 @@ msgstr ""
msgid "ClusterIntegration|To use a new project, first create one on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}."
msgstr ""
+msgid "ClusterIntegration|Troubleshooting tips:"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Authenticate"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Connect"
+msgstr ""
+
msgid "ClusterIntegration|Uninstall %{appTitle}"
msgstr ""
+msgid "ClusterIntegration|Unknown Error"
+msgstr ""
+
msgid "ClusterIntegration|Update %{appTitle}"
msgstr ""
@@ -6068,7 +6309,7 @@ msgstr ""
msgid "ClusterIntegration|Your cluster API is unreachable. Please ensure your API URL is correct."
msgstr ""
-msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Zone"
@@ -6188,6 +6429,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse all threads"
+msgstr ""
+
msgid "Collapse approvers"
msgstr ""
@@ -6337,7 +6581,7 @@ msgstr ""
msgid "Commit…"
msgstr ""
-msgid "Company"
+msgid "Community forum"
msgstr ""
msgid "Company name"
@@ -6346,6 +6590,9 @@ msgstr ""
msgid "Compare"
msgstr ""
+msgid "Compare %{oldCommitId}...%{newCommitId}"
+msgstr ""
+
msgid "Compare Git revisions"
msgstr ""
@@ -6361,6 +6608,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare submodule commit revisions"
+msgstr ""
+
msgid "Compare with previous version"
msgstr ""
@@ -6496,6 +6746,9 @@ msgstr ""
msgid "Configure the way a user creates a new account."
msgstr ""
+msgid "Configure which lists are shown for anyone who visits this board"
+msgstr ""
+
msgid "Confirm"
msgstr ""
@@ -6721,6 +6974,9 @@ msgstr[1] ""
msgid "ContainerRegistry|Set cleanup policy"
msgstr ""
+msgid "ContainerRegistry|Some tags were not deleted"
+msgstr ""
+
msgid "ContainerRegistry|Something went wrong while fetching the cleanup policy."
msgstr ""
@@ -6760,6 +7016,9 @@ msgstr ""
msgid "ContainerRegistry|Tags with names matching this regex pattern will %{italicStart}expire:%{italicEnd}"
msgstr ""
+msgid "ContainerRegistry|The cleanup policy timed out before it could delete all tags. An administrator can %{adminLinkStart}manually run cleanup now%{adminLinkEnd} or you can wait for the cleanup policy to automatically run again. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "ContainerRegistry|The last tag related to this image was recently removed. This empty image and any associated data will be automatically removed as part of the regular Garbage Collection process. If you have any questions, contact your administrator."
msgstr ""
@@ -6892,6 +7151,9 @@ msgstr ""
msgid "Contributions per group member"
msgstr ""
+msgid "Contributor"
+msgstr ""
+
msgid "Contributors"
msgstr ""
@@ -7021,6 +7283,9 @@ msgstr ""
msgid "Could not change HEAD: branch '%{branch}' does not exist"
msgstr ""
+msgid "Could not commit. An unexpected error occurred."
+msgstr ""
+
msgid "Could not connect to FogBugz, check your URL"
msgstr ""
@@ -7060,6 +7325,9 @@ msgstr ""
msgid "Could not find iteration"
msgstr ""
+msgid "Could not load instance counts. Please refresh the page to try again."
+msgstr ""
+
msgid "Could not remove the trigger."
msgstr ""
@@ -7084,10 +7352,10 @@ msgstr ""
msgid "Could not save prometheus manual configuration"
msgstr ""
-msgid "Could not udpdate wiki page"
+msgid "Could not update the LDAP settings"
msgstr ""
-msgid "Could not update the LDAP settings"
+msgid "Could not update wiki page"
msgstr ""
msgid "Could not upload your designs as one or more files uploaded are not supported."
@@ -7745,6 +8013,9 @@ msgstr ""
msgid "DastProfiles|Are you sure you want to delete this profile?"
msgstr ""
+msgid "DastProfiles|Could not create site validation token. Please refresh the page, or try again later."
+msgstr ""
+
msgid "DastProfiles|Could not create the scanner profile. Please try again."
msgstr ""
@@ -7769,6 +8040,12 @@ msgstr ""
msgid "DastProfiles|Could not fetch site profiles. Please refresh the page, or try again later."
msgstr ""
+msgid "DastProfiles|Could not retrieve site validation status. Please refresh the page, or try again later."
+msgstr ""
+
+msgid "DastProfiles|Could not update the scanner profile. Please try again."
+msgstr ""
+
msgid "DastProfiles|Could not update the site profile. Please try again."
msgstr ""
@@ -7784,7 +8061,7 @@ msgstr ""
msgid "DastProfiles|Download validation text file"
msgstr ""
-msgid "DastProfiles|Edit feature will come soon. Please create a new profile if changes needed"
+msgid "DastProfiles|Edit scanner profile"
msgstr ""
msgid "DastProfiles|Edit site profile"
@@ -7817,6 +8094,9 @@ msgstr ""
msgid "DastProfiles|No profiles created yet"
msgstr ""
+msgid "DastProfiles|Passive"
+msgstr ""
+
msgid "DastProfiles|Please enter a valid URL format, ex: http://www.example.com/home"
msgstr ""
@@ -7832,6 +8112,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan mode"
+msgstr ""
+
msgid "DastProfiles|Scanner Profile"
msgstr ""
@@ -7871,10 +8154,10 @@ msgstr ""
msgid "DastProfiles|Text file validation"
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
+msgid "DastProfiles|The maximum number of minutes allowed for the spider to traverse the site."
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the spider to traverse the site."
+msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
msgstr ""
msgid "DastProfiles|Validate"
@@ -7907,6 +8190,9 @@ msgstr ""
msgid "Date picker"
msgstr ""
+msgid "Date range"
+msgstr ""
+
msgid "Date range cannot exceed %{maxDateRange} days."
msgstr ""
@@ -7931,6 +8217,9 @@ msgstr ""
msgid "Days to merge"
msgstr ""
+msgid "Dear Administrator,"
+msgstr ""
+
msgid "Debug"
msgstr ""
@@ -8042,12 +8331,18 @@ msgstr ""
msgid "Delete"
msgstr ""
+msgid "Delete %{name}"
+msgstr ""
+
msgid "Delete Comment"
msgstr ""
msgid "Delete Snippet"
msgstr ""
+msgid "Delete Value Stream"
+msgstr ""
+
msgid "Delete account"
msgstr ""
@@ -8069,9 +8364,6 @@ msgstr ""
msgid "Delete label: %{label_name} ?"
msgstr ""
-msgid "Delete license"
-msgstr ""
-
msgid "Delete list"
msgstr ""
@@ -8147,15 +8439,6 @@ msgstr ""
msgid "Deleting a project places it into a read-only state until %{date}, at which point the project will be permanently deleted. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "Deleting the license failed."
-msgstr ""
-
-msgid "Deleting the license failed. The license was not found."
-msgstr ""
-
-msgid "Deleting the license failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "Deleting the project will delete its repository and all related resources including issues, merge requests etc."
msgstr ""
@@ -8651,7 +8934,10 @@ msgstr ""
msgid "DesignManagement|The maximum number of designs allowed to be uploaded is %{upload_limit}. Please try again."
msgstr ""
-msgid "DesignManagement|To upload designs, you'll need to enable LFS. %{requirements_link_start}More information%{requirements_link_end}"
+msgid "DesignManagement|There was an error moving your designs. Please upload your designs below."
+msgstr ""
+
+msgid "DesignManagement|To upload designs, you'll need to enable LFS and have admin enable hashed storage. %{requirements_link_start}More information%{requirements_link_end}"
msgstr ""
msgid "DesignManagement|Unresolve thread"
@@ -8663,6 +8949,9 @@ msgstr ""
msgid "DesignManagement|Upload skipped."
msgstr ""
+msgid "DesignManagement|Your designs are being copied and are on their way… Please refresh to update."
+msgstr ""
+
msgid "DesignManagement|and %{moreCount} more."
msgstr ""
@@ -8720,6 +9009,9 @@ msgstr ""
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
+msgid "Direct member"
+msgstr ""
+
msgid "Direction"
msgstr ""
@@ -8768,9 +9060,6 @@ msgstr ""
msgid "Discard draft"
msgstr ""
-msgid "Discard review"
-msgstr ""
-
msgid "DiscordService|Discord Notifications"
msgstr ""
@@ -8839,10 +9128,10 @@ msgstr ""
msgid "Dismiss Merge Request promotion"
msgstr ""
-msgid "Dismiss Selected"
+msgid "Dismiss Value Stream Analytics introduction box"
msgstr ""
-msgid "Dismiss Value Stream Analytics introduction box"
+msgid "Dismiss selected"
msgstr ""
msgid "Dismiss trial promotion"
@@ -8893,9 +9182,6 @@ msgstr ""
msgid "Documents reindexed: %{processed_documents} (%{percentage}%%)"
msgstr ""
-msgid "Doing"
-msgstr ""
-
msgid "Domain"
msgstr ""
@@ -9091,9 +9377,6 @@ msgstr ""
msgid "Edit environment"
msgstr ""
-msgid "Edit file"
-msgstr ""
-
msgid "Edit files in the editor and commit changes here"
msgstr ""
@@ -9106,6 +9389,12 @@ msgstr ""
msgid "Edit identity for %{user_name}"
msgstr ""
+msgid "Edit in Web IDE"
+msgstr ""
+
+msgid "Edit in single-file editor"
+msgstr ""
+
msgid "Edit issues"
msgstr ""
@@ -9133,10 +9422,10 @@ msgstr ""
msgid "Editing"
msgstr ""
-msgid "Elasticsearch"
+msgid "Elasticsearch AWS IAM credentials"
msgstr ""
-msgid "Elasticsearch AWS IAM credentials"
+msgid "Elasticsearch HTTP client timeout value in seconds."
msgstr ""
msgid "Elasticsearch indexing restrictions"
@@ -9145,9 +9434,6 @@ msgstr ""
msgid "Elasticsearch indexing started"
msgstr ""
-msgid "Elasticsearch integration. Elasticsearch AWS IAM."
-msgstr ""
-
msgid "Elasticsearch reindexing is already in progress"
msgstr ""
@@ -9175,9 +9461,6 @@ msgstr ""
msgid "Email Notification"
msgstr ""
-msgid "Email address"
-msgstr ""
-
msgid "Email could not be sent"
msgstr ""
@@ -9241,6 +9524,9 @@ msgstr ""
msgid "Emails sent from Service Desk will have this name"
msgstr ""
+msgid "Emails sent to %{email} will still be supported"
+msgstr ""
+
msgid "Emails separated by comma"
msgstr ""
@@ -9274,9 +9560,18 @@ msgstr ""
msgid "Enable"
msgstr ""
+msgid "Enable %{link_start}Gitpod%{link_end} integration to launch a development environment in your browser directly from GitLab."
+msgstr ""
+
msgid "Enable Auto DevOps"
msgstr ""
+msgid "Enable Gitpod"
+msgstr ""
+
+msgid "Enable Gitpod?"
+msgstr ""
+
msgid "Enable HTML emails"
msgstr ""
@@ -9406,9 +9701,6 @@ msgstr ""
msgid "Encountered an error while rendering: %{err}"
msgstr ""
-msgid "End date"
-msgstr ""
-
msgid "Ends at (UTC)"
msgstr ""
@@ -9568,7 +9860,7 @@ msgstr ""
msgid "EnvironmentsDashboard|The environments dashboard provides a summary of each project's environments' status, including pipeline and alert statuses."
msgstr ""
-msgid "EnvironmentsDashboard|This dashboard displays a maximum of 7 projects and 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
+msgid "EnvironmentsDashboard|This dashboard displays 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
msgstr ""
msgid "Environments|An error occurred while canceling the auto stop, please try again"
@@ -9889,6 +10181,9 @@ msgstr ""
msgid "Error deleting project. Check logs for error details."
msgstr ""
+msgid "Error fetching burnup chart data"
+msgstr ""
+
msgid "Error fetching diverging counts for branches. Please try again."
msgstr ""
@@ -9967,6 +10262,9 @@ msgstr ""
msgid "Error occurred when saving assignees"
msgstr ""
+msgid "Error occurred when saving reviewers"
+msgstr ""
+
msgid "Error occurred when toggling the notification subscription"
msgstr ""
@@ -10219,10 +10517,13 @@ msgstr ""
msgid "Expand all"
msgstr ""
-msgid "Expand approvers"
+msgid "Expand all files"
msgstr ""
-msgid "Expand dropdown"
+msgid "Expand all threads"
+msgstr ""
+
+msgid "Expand approvers"
msgstr ""
msgid "Expand milestones"
@@ -10393,6 +10694,9 @@ msgstr ""
msgid "Failed to create Merge Request. Please try again."
msgstr ""
+msgid "Failed to create To-Do for the design."
+msgstr ""
+
msgid "Failed to create a branch for this issue. Please try again."
msgstr ""
@@ -10432,6 +10736,12 @@ msgstr ""
msgid "Failed to load authors. Please try again."
msgstr ""
+msgid "Failed to load branches. Please try again."
+msgstr ""
+
+msgid "Failed to load deploy keys."
+msgstr ""
+
msgid "Failed to load emoji list."
msgstr ""
@@ -10447,6 +10757,9 @@ msgstr ""
msgid "Failed to load groups & users."
msgstr ""
+msgid "Failed to load groups, users and deploy keys."
+msgstr ""
+
msgid "Failed to load labels. Please try again."
msgstr ""
@@ -10456,6 +10769,12 @@ msgstr ""
msgid "Failed to load related branches"
msgstr ""
+msgid "Failed to load sidebar confidential toggle"
+msgstr ""
+
+msgid "Failed to load sidebar lock status"
+msgstr ""
+
msgid "Failed to load stacktrace."
msgstr ""
@@ -10483,6 +10802,9 @@ msgstr ""
msgid "Failed to publish issue on status page."
msgstr ""
+msgid "Failed to remove To-Do for the design."
+msgstr ""
+
msgid "Failed to remove a Zoom meeting"
msgstr ""
@@ -10525,6 +10847,9 @@ msgstr ""
msgid "Failed to signing using smartcard authentication"
msgstr ""
+msgid "Failed to toggle To-Do for the design."
+msgstr ""
+
msgid "Failed to update branch!"
msgstr ""
@@ -10638,7 +10963,7 @@ msgstr ""
msgid "FeatureFlags|Edit User List"
msgstr ""
-msgid "FeatureFlags|Enable features for specific users and specific environments by defining feature flag strategies."
+msgid "FeatureFlags|Enable features for specific users and environments by configuring feature flag strategies."
msgstr ""
msgid "FeatureFlags|Environment Spec"
@@ -10698,7 +11023,7 @@ msgstr ""
msgid "FeatureFlags|Include additional user IDs"
msgstr ""
-msgid "FeatureFlags|Install a %{docs_link_anchored_start}compatible client library%{docs_link_anchored_end} and specify the API URL, application name, and instance ID during the configuration setup. %{docs_link_start}More Information%{docs_link_end}"
+msgid "FeatureFlags|Install a %{docsLinkAnchoredStart}compatible client library%{docsLinkAnchoredEnd} and specify the API URL, application name, and instance ID during the configuration setup. %{docsLinkStart}More Information%{docsLinkEnd}"
msgstr ""
msgid "FeatureFlags|Instance ID"
@@ -10710,6 +11035,9 @@ msgstr ""
msgid "FeatureFlags|Loading feature flags"
msgstr ""
+msgid "FeatureFlags|Loading user lists"
+msgstr ""
+
msgid "FeatureFlags|More information"
msgstr ""
@@ -10728,7 +11056,7 @@ msgstr ""
msgid "FeatureFlags|New feature flag"
msgstr ""
-msgid "FeatureFlags|New list"
+msgid "FeatureFlags|New user list"
msgstr ""
msgid "FeatureFlags|Percent of users"
@@ -10767,6 +11095,9 @@ msgstr ""
msgid "FeatureFlags|There was an error fetching the feature flags."
msgstr ""
+msgid "FeatureFlags|There was an error fetching the user lists."
+msgstr ""
+
msgid "FeatureFlags|There was an error retrieving user lists"
msgstr ""
@@ -10782,6 +11113,9 @@ msgstr ""
msgid "FeatureFlags|User List"
msgstr ""
+msgid "FeatureFlags|User Lists"
+msgstr ""
+
msgid "FeatureFlag|List"
msgstr ""
@@ -10809,15 +11143,6 @@ msgstr ""
msgid "Fetching incoming email"
msgstr ""
-msgid "Fetching licenses failed."
-msgstr ""
-
-msgid "Fetching licenses failed. The request endpoint was not found."
-msgstr ""
-
-msgid "Fetching licenses failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "File"
msgstr ""
@@ -10920,12 +11245,21 @@ msgstr ""
msgid "Filter by status"
msgstr ""
+msgid "Filter by test cases that are currently archived."
+msgstr ""
+
+msgid "Filter by test cases that are currently opened."
+msgstr ""
+
msgid "Filter by two-factor authentication"
msgstr ""
msgid "Filter by user"
msgstr ""
+msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
+msgstr ""
+
msgid "Filter pipelines"
msgstr ""
@@ -10941,7 +11275,7 @@ msgstr ""
msgid "Filter results..."
msgstr ""
-msgid "Filter your projects by name"
+msgid "Filter your repositories by name"
msgstr ""
msgid "Filter..."
@@ -10950,7 +11284,7 @@ msgstr ""
msgid "Find File"
msgstr ""
-msgid "Find bugs in your code with coverage-guided fuzzing"
+msgid "Find bugs in your code with coverage-guided fuzzing."
msgstr ""
msgid "Find by path"
@@ -10977,9 +11311,6 @@ msgstr ""
msgid "Finish editing this message first!"
msgstr ""
-msgid "Finish review"
-msgstr ""
-
msgid "Finish setting up your dedicated account for %{group_name}."
msgstr ""
@@ -11049,6 +11380,9 @@ msgstr ""
msgid "Footer message"
msgstr ""
+msgid "For a faster browsing experience, some files are collapsed by default."
+msgstr ""
+
msgid "For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
@@ -11058,6 +11392,9 @@ msgstr ""
msgid "For more info, read the documentation."
msgstr ""
+msgid "For more information on how the number of active users is calculated, see the %{self_managed_subscriptions_doc_link} documentation."
+msgstr ""
+
msgid "For more information, go to the "
msgstr ""
@@ -11196,6 +11533,9 @@ msgstr ""
msgid "Generate new token"
msgstr ""
+msgid "Generic package file size in bytes"
+msgstr ""
+
msgid "Geo"
msgstr ""
@@ -11457,6 +11797,9 @@ msgstr ""
msgid "Geo|Please refer to Geo Troubleshooting."
msgstr ""
+msgid "Geo|Primary node"
+msgstr ""
+
msgid "Geo|Project"
msgstr ""
@@ -11499,6 +11842,9 @@ msgstr ""
msgid "Geo|Review replication status, and resynchronize and reverify items with the primary node."
msgstr ""
+msgid "Geo|Secondary node"
+msgstr ""
+
msgid "Geo|Status"
msgstr ""
@@ -11538,6 +11884,9 @@ msgstr ""
msgid "Geo|URL must be a valid url (ex: https://gitlab.com)"
msgstr ""
+msgid "Geo|Undefined"
+msgstr ""
+
msgid "Geo|Unknown state"
msgstr ""
@@ -11613,10 +11962,16 @@ msgstr ""
msgid "GitHub import"
msgstr ""
+msgid "GitLab"
+msgstr ""
+
msgid "GitLab / Unsubscribe"
msgstr ""
-msgid "GitLab Enterprise Edition %{plan}"
+msgid "GitLab API"
+msgstr ""
+
+msgid "GitLab Billing Team."
msgstr ""
msgid "GitLab Group Runners can execute code for all the projects in this group."
@@ -11628,12 +11983,18 @@ msgstr ""
msgid "GitLab Issue"
msgstr ""
+msgid "GitLab Pages"
+msgstr ""
+
msgid "GitLab Service Desk is a simple way to allow people to create issues in your GitLab instance without needing their own user account. It provides a unique email address for end users to create issues in a project, and replies can be sent either through the GitLab interface or by email. End users will only see the thread through email."
msgstr ""
msgid "GitLab Shared Runners execute code of different projects on the same Runner unless you configure GitLab Runner Autoscale with MaxBuilds 1 (which it is on GitLab.com)."
msgstr ""
+msgid "GitLab Shell"
+msgstr ""
+
msgid "GitLab Support Bot"
msgstr ""
@@ -11643,7 +12004,7 @@ msgstr ""
msgid "GitLab User"
msgstr ""
-msgid "GitLab allows you to continue using your license even if you exceed the number of seats you purchased. You will be required to pay for these seats when you renew your license."
+msgid "GitLab Workhorse"
msgstr ""
msgid "GitLab commit"
@@ -11811,6 +12172,21 @@ msgstr ""
msgid "Gitlab Pages"
msgstr ""
+msgid "Gitpod"
+msgstr ""
+
+msgid "Gitpod|Add the URL to your Gitpod instance configured to read your GitLab projects."
+msgstr ""
+
+msgid "Gitpod|Enable Gitpod integration"
+msgstr ""
+
+msgid "Gitpod|Gitpod URL"
+msgstr ""
+
+msgid "Gitpod|e.g. https://gitpod.example.com"
+msgstr ""
+
msgid "Given access %{time_ago}"
msgstr ""
@@ -12318,9 +12694,6 @@ msgstr ""
msgid "GroupSAML|Valid SAML Response"
msgstr ""
-msgid "GroupSAML|With group managed accounts enabled, all the users without a group managed account will be excluded from the group."
-msgstr ""
-
msgid "GroupSAML|With prohibit outer forks flag enabled group members will be able to fork project only inside your group."
msgstr ""
@@ -12534,10 +12907,10 @@ msgstr ""
msgid "GroupsNew|Create group"
msgstr ""
-msgid "GroupsNew|GitLab group export"
+msgid "GroupsNew|Import"
msgstr ""
-msgid "GroupsNew|Import"
+msgid "GroupsNew|Import a GitLab group export file"
msgstr ""
msgid "GroupsNew|Import group"
@@ -12680,6 +13053,9 @@ msgid_plural "Hide charts"
msgstr[0] ""
msgstr[1] ""
+msgid "Hide comments on this file"
+msgstr ""
+
msgid "Hide details"
msgstr ""
@@ -12724,6 +13100,15 @@ msgstr ""
msgid "Highest role:"
msgstr ""
+msgid "HighlightBar|Alert events:"
+msgstr ""
+
+msgid "HighlightBar|Alert start time:"
+msgstr ""
+
+msgid "HighlightBar|Original alert:"
+msgstr ""
+
msgid "History"
msgstr ""
@@ -12901,6 +13286,9 @@ msgstr ""
msgid "If enabled, access to projects will be validated on an external service using their classification label."
msgstr ""
+msgid "If the number of active users exceeds the user limit, you will be charged for the number of %{users_over_license_link} at your next license reconciliation."
+msgstr ""
+
msgid "If there is no previous license or if the previous license has expired, some GitLab functionality will be blocked until a new, valid license is uploaded."
msgstr ""
@@ -12940,9 +13328,6 @@ msgstr ""
msgid "If your HTTP repository is not publicly accessible, add your credentials."
msgstr ""
-msgid "Iglu registry URL (optional)"
-msgstr ""
-
msgid "Ignore"
msgstr ""
@@ -12979,6 +13364,16 @@ msgstr ""
msgid "Import"
msgstr ""
+msgid "Import %d compatible repository"
+msgid_plural "Import %d compatible repositories"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Import %d repository"
+msgid_plural "Import %d repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Import CSV"
msgstr ""
@@ -12988,15 +13383,9 @@ msgstr ""
msgid "Import all compatible projects"
msgstr ""
-msgid "Import all compatible repositories"
-msgstr ""
-
msgid "Import all projects"
msgstr ""
-msgid "Import all repositories"
-msgstr ""
-
msgid "Import an exported GitLab project"
msgstr ""
@@ -13084,6 +13473,9 @@ msgstr ""
msgid "ImportProjects|Error importing repository %{project_safe_import_url} into %{project_full_path} - %{message}"
msgstr ""
+msgid "ImportProjects|Import repositories"
+msgstr ""
+
msgid "ImportProjects|Importing the project failed"
msgstr ""
@@ -13096,7 +13488,7 @@ msgstr ""
msgid "ImportProjects|Requesting your %{provider} repositories failed"
msgstr ""
-msgid "ImportProjects|Select the projects you want to import"
+msgid "ImportProjects|Select the repositories you want to import"
msgstr ""
msgid "ImportProjects|The remote data could not be imported."
@@ -13132,9 +13524,6 @@ msgstr ""
msgid "In order to enable Service Desk for your instance, you must first set up incoming email."
msgstr ""
-msgid "In order to gather accurate feature usage data, it can take 1 to 2 weeks to see your index."
-msgstr ""
-
msgid "In order to personalize your experience with GitLab%{br_tag}we would like to know a bit more about you."
msgstr ""
@@ -13165,18 +13554,30 @@ msgstr ""
msgid "IncidentManagement|Create incident"
msgstr ""
+msgid "IncidentManagement|Critical - S1"
+msgstr ""
+
msgid "IncidentManagement|Date created"
msgstr ""
msgid "IncidentManagement|Display your incidents in a dedicated view"
msgstr ""
+msgid "IncidentManagement|High - S2"
+msgstr ""
+
msgid "IncidentManagement|Incident"
msgstr ""
msgid "IncidentManagement|Incidents"
msgstr ""
+msgid "IncidentManagement|Low - S4"
+msgstr ""
+
+msgid "IncidentManagement|Medium - S3"
+msgstr ""
+
msgid "IncidentManagement|No incidents to display."
msgstr ""
@@ -13189,6 +13590,9 @@ msgstr ""
msgid "IncidentManagement|Published to status page"
msgstr ""
+msgid "IncidentManagement|Severity"
+msgstr ""
+
msgid "IncidentManagement|There are no closed incidents"
msgstr ""
@@ -13198,6 +13602,9 @@ msgstr ""
msgid "IncidentManagement|Unassigned"
msgstr ""
+msgid "IncidentManagement|Unknown"
+msgstr ""
+
msgid "IncidentManagement|Unpublished"
msgstr ""
@@ -13219,6 +13626,15 @@ msgstr ""
msgid "Incidents"
msgstr ""
+msgid "Incident|Alert details"
+msgstr ""
+
+msgid "Incident|Summary"
+msgstr ""
+
+msgid "Incident|There was an issue loading alert data. Please try again."
+msgstr ""
+
msgid "Include a Terms of Service agreement and Privacy Policy that all users must accept."
msgstr ""
@@ -13279,6 +13695,9 @@ msgstr ""
msgid "Information about additional Pages templates and how to install them can be found in our %{pages_getting_started_guide}."
msgstr ""
+msgid "Inherited"
+msgstr ""
+
msgid "Inherited:"
msgstr ""
@@ -13359,7 +13778,22 @@ msgstr ""
msgid "Instance administrators group already exists"
msgstr ""
-msgid "Instance license"
+msgid "InstanceStatistics|Groups"
+msgstr ""
+
+msgid "InstanceStatistics|Issues"
+msgstr ""
+
+msgid "InstanceStatistics|Merge Requests"
+msgstr ""
+
+msgid "InstanceStatistics|Pipelines"
+msgstr ""
+
+msgid "InstanceStatistics|Projects"
+msgstr ""
+
+msgid "InstanceStatistics|Users"
msgstr ""
msgid "Integration"
@@ -13371,6 +13805,12 @@ msgstr ""
msgid "Integrations"
msgstr ""
+msgid "Integrations|%{integration} settings saved and active."
+msgstr ""
+
+msgid "Integrations|%{integration} settings saved, but not active."
+msgstr ""
+
msgid "Integrations|All details"
msgstr ""
@@ -13380,6 +13820,12 @@ msgstr ""
msgid "Integrations|Comment settings:"
msgstr ""
+msgid "Integrations|Connection failed. Please check your settings."
+msgstr ""
+
+msgid "Integrations|Connection successful."
+msgstr ""
+
msgid "Integrations|Default settings are inherited from the group level."
msgstr ""
@@ -13395,6 +13841,15 @@ msgstr ""
msgid "Integrations|Includes commit title and branch"
msgstr ""
+msgid "Integrations|Projects using custom settings will not be impacted unless the project owner chooses to use instance-level defaults."
+msgstr ""
+
+msgid "Integrations|Save settings?"
+msgstr ""
+
+msgid "Integrations|Saving will update the default settings for all projects that are not using custom settings."
+msgstr ""
+
msgid "Integrations|Standard"
msgstr ""
@@ -13527,6 +13982,9 @@ msgstr ""
msgid "Invitation"
msgstr ""
+msgid "Invitation declined"
+msgstr ""
+
msgid "Invite"
msgstr ""
@@ -13578,6 +14036,42 @@ 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|%{linkStart}Read more%{linkEnd} about role permissions"
+msgstr ""
+
+msgid "InviteMembersModal|Access expiration date (optional)"
+msgstr ""
+
+msgid "InviteMembersModal|Cancel"
+msgstr ""
+
+msgid "InviteMembersModal|Choose a role permission"
+msgstr ""
+
+msgid "InviteMembersModal|GitLab member or Email address"
+msgstr ""
+
+msgid "InviteMembersModal|Invite"
+msgstr ""
+
+msgid "InviteMembersModal|Invite team members"
+msgstr ""
+
+msgid "InviteMembersModal|Search for members to invite"
+msgstr ""
+
+msgid "InviteMembersModal|User not invited. Feature coming soon!"
+msgstr ""
+
+msgid "InviteMembersModal|Users were succesfully added"
+msgstr ""
+
+msgid "InviteMembersModal|You're inviting members to the %{group_name} group"
+msgstr ""
+
+msgid "InviteMembers|Invite team members"
+msgstr ""
+
msgid "Invited"
msgstr ""
@@ -13632,10 +14126,13 @@ msgstr ""
msgid "Issue cannot be found."
msgstr ""
+msgid "Issue created from vulnerability %{vulnerability_link}"
+msgstr ""
+
msgid "Issue events"
msgstr ""
-msgid "Issue first depoloyed to production"
+msgid "Issue first deployed to production"
msgstr ""
msgid "Issue label"
@@ -13713,6 +14210,9 @@ msgstr ""
msgid "IssueTracker|Custom issue tracker"
msgstr ""
+msgid "IssueTracker|EWM work items tracker"
+msgstr ""
+
msgid "IssueTracker|Redmine issue tracker"
msgstr ""
@@ -13779,6 +14279,9 @@ msgstr ""
msgid "It looks like you have some draft commits in this branch."
msgstr ""
+msgid "It may be several days before you see feature usage data."
+msgstr ""
+
msgid "It must have a header row and at least two columns: the first column is the issue title and the second column is the issue description. The separator is automatically detected."
msgstr ""
@@ -14061,13 +14564,13 @@ msgstr ""
msgid "Join Zoom meeting"
msgstr ""
-msgid "Jul"
+msgid "Joined %{time_ago}"
msgstr ""
-msgid "July"
+msgid "Jul"
msgstr ""
-msgid "Jump to first unresolved thread"
+msgid "July"
msgstr ""
msgid "Jump to next unresolved thread"
@@ -14103,6 +14606,9 @@ msgstr ""
msgid "Keyboard shortcuts"
msgstr ""
+msgid "KeyboardKey|Ctrl+"
+msgstr ""
+
msgid "Keys"
msgstr ""
@@ -14151,6 +14657,9 @@ msgstr ""
msgid "LDAP Synchronization"
msgstr ""
+msgid "LDAP group settings"
+msgstr ""
+
msgid "LDAP settings"
msgstr ""
@@ -14160,6 +14669,9 @@ msgstr ""
msgid "LDAP sync in progress. This could take a few minutes. Refresh the page to see the changes."
msgstr ""
+msgid "LDAP synchronizations"
+msgstr ""
+
msgid "LFS"
msgstr ""
@@ -14240,7 +14752,16 @@ msgid_plural "Last %d days"
msgstr[0] ""
msgstr[1] ""
-msgid "Last %{days} days"
+msgid "Last 2 weeks"
+msgstr ""
+
+msgid "Last 30 days"
+msgstr ""
+
+msgid "Last 60 days"
+msgstr ""
+
+msgid "Last 90 days"
msgstr ""
msgid "Last Accessed On"
@@ -14318,6 +14839,9 @@ msgstr ""
msgid "Last used on:"
msgstr ""
+msgid "Last week"
+msgstr ""
+
msgid "LastCommit|authored"
msgstr ""
@@ -14333,6 +14857,9 @@ msgstr ""
msgid "Latest pipeline for the most recent commit on this branch"
msgstr ""
+msgid "Launch a ready-to-code development environment for your project."
+msgstr ""
+
msgid "Lead"
msgstr ""
@@ -14713,6 +15240,9 @@ msgstr ""
msgid "List of all merge commits"
msgstr ""
+msgid "List options"
+msgstr ""
+
msgid "List settings"
msgstr ""
@@ -14725,9 +15255,6 @@ msgstr ""
msgid "List your Bitbucket Server repositories"
msgstr ""
-msgid "Lists"
-msgstr ""
-
msgid "Live preview"
msgstr ""
@@ -14974,6 +15501,12 @@ msgstr ""
msgid "Mark as done"
msgstr ""
+msgid "Mark as draft"
+msgstr ""
+
+msgid "Mark as ready"
+msgstr ""
+
msgid "Mark as resolved"
msgstr ""
@@ -14995,6 +15528,24 @@ msgstr ""
msgid "Markdown is supported"
msgstr ""
+msgid "MarkdownEditor|Add a link (%{modifierKey}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add a link (%{modifier_key}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifierKey}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifier_key}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifierKey}I)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifier_key}I)"
+msgstr ""
+
msgid "Marked For Deletion At - %{deletion_time}"
msgstr ""
@@ -15079,7 +15630,25 @@ msgstr ""
msgid "Max access level"
msgstr ""
-msgid "Max seats used"
+msgid "Max role"
+msgstr ""
+
+msgid "Max size 15 MB"
+msgstr ""
+
+msgid "Maximum Conan package file size in bytes"
+msgstr ""
+
+msgid "Maximum Maven package file size in bytes"
+msgstr ""
+
+msgid "Maximum NPM package file size in bytes"
+msgstr ""
+
+msgid "Maximum NuGet package file size in bytes"
+msgstr ""
+
+msgid "Maximum PyPI package file size in bytes"
msgstr ""
msgid "Maximum Users:"
@@ -15211,6 +15780,18 @@ msgstr ""
msgid "Members with access to %{strong_start}%{group_name}%{strong_end}"
msgstr ""
+msgid "Members|%{time} by %{user}"
+msgstr ""
+
+msgid "Members|Expired"
+msgstr ""
+
+msgid "Members|No expiration set"
+msgstr ""
+
+msgid "Members|in %{time}"
+msgstr ""
+
msgid "Memory Usage"
msgstr ""
@@ -15397,9 +15978,6 @@ msgstr ""
msgid "MergeRequests|Thread will be unresolved"
msgstr ""
-msgid "MergeRequests|Toggle comments for this file"
-msgstr ""
-
msgid "MergeRequests|View file @ %{commitId}"
msgstr ""
@@ -15460,6 +16038,9 @@ msgstr ""
msgid "Merging immediately isn't recommended as it may negatively impact the existing merge train. Read the %{docsLinkStart}documentation%{docsLinkEnd} for more information."
msgstr ""
+msgid "Message"
+msgstr ""
+
msgid "Messages"
msgstr ""
@@ -15845,18 +16426,12 @@ msgid_plural "Milestones"
msgstr[0] ""
msgstr[1] ""
-msgid "Milestone does not support burnup charts"
-msgstr ""
-
msgid "Milestone lists not available with your current license"
msgstr ""
msgid "Milestone lists show all issues from the selected milestone."
msgstr ""
-msgid "Milestone must have a start and due date"
-msgstr ""
-
msgid "MilestoneSidebar|Closed:"
msgstr ""
@@ -16223,6 +16798,9 @@ msgstr ""
msgid "Namespace"
msgstr ""
+msgid "Namespace ID:"
+msgstr ""
+
msgid "Namespace is empty"
msgstr ""
@@ -16307,6 +16885,9 @@ msgstr ""
msgid "NetworkPolicies|Allow all outbound traffic from %{selector} to %{ruleSelector} on %{ports}"
msgstr ""
+msgid "NetworkPolicies|Are you sure you want to delete this policy? This action cannot be undone."
+msgstr ""
+
msgid "NetworkPolicies|Choose whether to enforce this policy."
msgstr ""
@@ -16316,12 +16897,21 @@ msgstr ""
msgid "NetworkPolicies|Define this policy's location, conditions and actions."
msgstr ""
+msgid "NetworkPolicies|Delete policy"
+msgstr ""
+
+msgid "NetworkPolicies|Delete policy: %{policy}"
+msgstr ""
+
msgid "NetworkPolicies|Deny all traffic"
msgstr ""
msgid "NetworkPolicies|Description"
msgstr ""
+msgid "NetworkPolicies|Edit policy"
+msgstr ""
+
msgid "NetworkPolicies|Editor mode"
msgstr ""
@@ -16349,6 +16939,9 @@ msgstr ""
msgid "NetworkPolicies|Name"
msgstr ""
+msgid "NetworkPolicies|Namespace"
+msgstr ""
+
msgid "NetworkPolicies|Network Policy"
msgstr ""
@@ -16400,6 +16993,9 @@ msgstr ""
msgid "NetworkPolicies|Rules"
msgstr ""
+msgid "NetworkPolicies|Save changes"
+msgstr ""
+
msgid "NetworkPolicies|Something went wrong, failed to update policy"
msgstr ""
@@ -16412,6 +17008,9 @@ msgstr ""
msgid "NetworkPolicies|Traffic that does not match any rule will be blocked."
msgstr ""
+msgid "NetworkPolicies|Unable to parse policy"
+msgstr ""
+
msgid "NetworkPolicies|YAML editor"
msgstr ""
@@ -16525,6 +17124,9 @@ msgstr ""
msgid "New Snippet"
msgstr ""
+msgid "New Test Case"
+msgstr ""
+
msgid "New User"
msgstr ""
@@ -16624,6 +17226,9 @@ msgstr ""
msgid "New tag"
msgstr ""
+msgid "New test case"
+msgstr ""
+
msgid "New users set to external"
msgstr ""
@@ -16696,7 +17301,7 @@ msgstr ""
msgid "No changes"
msgstr ""
-msgid "No changes between %{ref_start}%{source_branch}%{ref_end} and %{ref_start}%{target_branch}%{ref_end}"
+msgid "No changes between %{sourceBranch} and %{targetBranch}"
msgstr ""
msgid "No child epics match applied filters"
@@ -16711,6 +17316,9 @@ msgstr ""
msgid "No containers available"
msgstr ""
+msgid "No content to show"
+msgstr ""
+
msgid "No contributions"
msgstr ""
@@ -16786,9 +17394,6 @@ msgstr ""
msgid "No license. All rights reserved"
msgstr ""
-msgid "No licenses found."
-msgstr ""
-
msgid "No matches found"
msgstr ""
@@ -16801,6 +17406,9 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No members found"
+msgstr ""
+
msgid "No merge requests found"
msgstr ""
@@ -16822,6 +17430,9 @@ msgstr ""
msgid "No parent group"
msgstr ""
+msgid "No plan"
+msgstr ""
+
msgid "No pods available"
msgstr ""
@@ -16918,6 +17529,12 @@ msgstr ""
msgid "Not Implemented"
msgstr ""
+msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+msgstr ""
+
+msgid "Not all browsers support WebAuthn. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even from an unsupported browser."
+msgstr ""
+
msgid "Not all data has been processed yet, the accuracy of the chart for the selected timeframe is limited."
msgstr ""
@@ -17014,6 +17631,9 @@ msgstr ""
msgid "Notification settings saved"
msgstr ""
+msgid "NotificationEvent|Change reviewer merge request"
+msgstr ""
+
msgid "NotificationEvent|Close issue"
msgstr ""
@@ -17176,10 +17796,7 @@ msgstr ""
msgid "On track"
msgstr ""
-msgid "OnDemandScans|Attached branch"
-msgstr ""
-
-msgid "OnDemandScans|Attached branch is where the scan job runs."
+msgid "OnDemandScans|Could not fetch scanner profiles. Please refresh the page, or try again later."
msgstr ""
msgid "OnDemandScans|Could not fetch site profiles. Please refresh the page, or try again later."
@@ -17188,6 +17805,9 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
+msgid "OnDemandScans|Create a new scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Create a new site profile"
msgstr ""
@@ -17200,6 +17820,9 @@ msgstr ""
msgid "OnDemandScans|New on-demand DAST scan"
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 ""
@@ -17209,16 +17832,10 @@ msgstr ""
msgid "OnDemandScans|On-demand scans run outside the DevOps cycle and find vulnerabilities in your projects. %{learnMoreLinkStart}Learn more%{learnMoreLinkEnd}"
msgstr ""
-msgid "OnDemandScans|Only a passive scan can be performed on demand."
-msgstr ""
-
-msgid "OnDemandScans|Passive"
-msgstr ""
-
msgid "OnDemandScans|Run scan"
msgstr ""
-msgid "OnDemandScans|Scan mode"
+msgid "OnDemandScans|Scanner profile"
msgstr ""
msgid "OnDemandScans|Scanner settings"
@@ -17230,9 +17847,15 @@ msgstr ""
msgid "OnDemandScans|Select one of the existing profiles"
msgstr ""
+msgid "OnDemandScans|Site profile"
+msgstr ""
+
msgid "OnDemandScans|Site profiles"
msgstr ""
+msgid "OnDemandScans|Use existing scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Use existing site profile"
msgstr ""
@@ -17331,9 +17954,6 @@ msgstr ""
msgid "Open Selection"
msgstr ""
-msgid "Open Web IDE"
-msgstr ""
-
msgid "Open comment type dropdown"
msgstr ""
@@ -17439,6 +18059,9 @@ msgstr ""
msgid "Origin"
msgstr ""
+msgid "Orphaned member"
+msgstr ""
+
msgid "Other Labels"
msgstr ""
@@ -17454,6 +18077,9 @@ msgstr ""
msgid "Other visibility settings have been disabled by the administrator."
msgstr ""
+msgid "Our documentation includes an example DevOps Score report."
+msgstr ""
+
msgid "Out-of-compliance with this project's policies and should be removed"
msgstr ""
@@ -17478,6 +18104,9 @@ msgstr ""
msgid "Overwrite diverged branches"
msgstr ""
+msgid "Owned by %{image_tag}"
+msgstr ""
+
msgid "Owned by anyone"
msgstr ""
@@ -17499,6 +18128,9 @@ msgstr ""
msgid "Package deleted successfully"
msgstr ""
+msgid "Package file size limits"
+msgstr ""
+
msgid "Package recipe already exists"
msgstr ""
@@ -17514,9 +18146,6 @@ msgstr ""
msgid "Package type must be PyPi"
msgstr ""
-msgid "Package was removed"
-msgstr ""
-
msgid "PackageRegistry|%{name} version %{version} was created %{datetime}"
msgstr ""
@@ -17658,12 +18287,18 @@ msgstr ""
msgid "PackageRegistry|NuGet Command"
msgstr ""
+msgid "PackageRegistry|Package Registry"
+msgstr ""
+
msgid "PackageRegistry|Pip Command"
msgstr ""
msgid "PackageRegistry|Pipeline %{link} triggered %{datetime} by %{author}"
msgstr ""
+msgid "PackageRegistry|Publish and share packages for a variety of common package managers. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "PackageRegistry|Published to the %{project} Package Registry %{datetime}"
msgstr ""
@@ -17763,6 +18398,9 @@ msgstr ""
msgid "Page not found"
msgstr ""
+msgid "Page settings"
+msgstr ""
+
msgid "Page was successfully deleted"
msgstr ""
@@ -17904,7 +18542,7 @@ msgstr ""
msgid "Paste issue link"
msgstr ""
-msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Don't use your private SSH key."
+msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Do not paste your private SSH key, as that can compromise your identity."
msgstr ""
msgid "Patch to apply"
@@ -17931,6 +18569,9 @@ msgstr ""
msgid "Pending"
msgstr ""
+msgid "Pending comments"
+msgstr ""
+
msgid "People without permission will never get a notification and won't be able to comment."
msgstr ""
@@ -18129,6 +18770,9 @@ msgstr ""
msgid "Pipelines|Build with confidence"
msgstr ""
+msgid "Pipelines|By revoking a trigger you will break any processes making use of it. Are you sure?"
+msgstr ""
+
msgid "Pipelines|CI Lint"
msgstr ""
@@ -18141,6 +18785,15 @@ msgstr ""
msgid "Pipelines|Continuous Integration can help catch bugs by running your tests automatically, while Continuous Deployment can help you deliver code to your product environment."
msgstr ""
+msgid "Pipelines|Copy trigger token"
+msgstr ""
+
+msgid "Pipelines|Description"
+msgstr ""
+
+msgid "Pipelines|Edit"
+msgstr ""
+
msgid "Pipelines|Get started with Pipelines"
msgstr ""
@@ -18156,15 +18809,27 @@ msgstr ""
msgid "Pipelines|It is recommended the code is reviewed thoroughly before running this pipeline with the parent project's CI resource."
msgstr ""
+msgid "Pipelines|Last Used"
+msgstr ""
+
msgid "Pipelines|Loading Pipelines"
msgstr ""
msgid "Pipelines|More Information"
msgstr ""
+msgid "Pipelines|No triggers have been created yet. Add one using the form above."
+msgstr ""
+
+msgid "Pipelines|Owner"
+msgstr ""
+
msgid "Pipelines|Project cache successfully reset."
msgstr ""
+msgid "Pipelines|Revoke"
+msgstr ""
+
msgid "Pipelines|Run Pipeline"
msgstr ""
@@ -18189,6 +18854,15 @@ msgstr ""
msgid "Pipelines|This project is not currently set up to run pipelines."
msgstr ""
+msgid "Pipelines|Token"
+msgstr ""
+
+msgid "Pipelines|Trigger user has insufficient permissions to project"
+msgstr ""
+
+msgid "Pipelines|invalid"
+msgstr ""
+
msgid "Pipelines|parent"
msgstr ""
@@ -18447,10 +19121,10 @@ msgstr ""
msgid "Please provide attributes to update"
msgstr ""
-msgid "Please refer to %{docs_url}"
+msgid "Please reach out if you have any questions and we'll be happy to assist."
msgstr ""
-msgid "Please retype the email address."
+msgid "Please refer to %{docs_url}"
msgstr ""
msgid "Please select"
@@ -18480,6 +19154,9 @@ msgstr ""
msgid "Please set a new password before proceeding."
msgstr ""
+msgid "Please share your feedback about %{featureName} %{linkStart}in this issue%{linkEnd} to help us improve the experience."
+msgstr ""
+
msgid "Please solve the reCAPTCHA"
msgstr ""
@@ -18783,6 +19460,9 @@ msgstr ""
msgid "Profiles| You are going to change the username %{currentUsernameBold} to %{newUsernameBold}. Profile and projects will be redirected to the %{newUsername} namespace but this redirect will expire once the %{currentUsername} namespace is registered by another user or group. Please update your Git repository remotes as soon as possible."
msgstr ""
+msgid "Profiles|%{provider} Active"
+msgstr ""
+
msgid "Profiles|@username"
msgstr ""
@@ -18834,7 +19514,7 @@ msgstr ""
msgid "Profiles|Commit email"
msgstr ""
-msgid "Profiles|Connect"
+msgid "Profiles|Connect %{provider}"
msgstr ""
msgid "Profiles|Connected Accounts"
@@ -18858,6 +19538,9 @@ msgstr ""
msgid "Profiles|Disconnect"
msgstr ""
+msgid "Profiles|Disconnect %{provider}"
+msgstr ""
+
msgid "Profiles|Do not show on profile"
msgstr ""
@@ -18882,7 +19565,7 @@ msgstr ""
msgid "Profiles|Full name"
msgstr ""
-msgid "Profiles|Give your individual key a title. This will be publically visible."
+msgid "Profiles|Give your individual key a title."
msgstr ""
msgid "Profiles|Include private contributions on my profile"
@@ -18972,7 +19655,7 @@ msgstr ""
msgid "Profiles|The maximum file size allowed is 200KB."
msgstr ""
-msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it?"
+msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it? It will be publicly visible."
msgstr ""
msgid "Profiles|This email will be displayed on your public profile"
@@ -19047,6 +19730,9 @@ msgstr ""
msgid "Profiles|You don't have access to delete this user."
msgstr ""
+msgid "Profiles|You must transfer ownership or delete groups you are an owner of before you can delete your account"
+msgstr ""
+
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
@@ -19635,6 +20321,9 @@ msgstr ""
msgid "ProjectTemplates|GitLab Cluster Management"
msgstr ""
+msgid "ProjectTemplates|Gitpod/Spring Petclinic"
+msgstr ""
+
msgid "ProjectTemplates|Go Micro"
msgstr ""
@@ -20244,6 +20933,9 @@ msgstr ""
msgid "Publish to status page"
msgstr ""
+msgid "Published"
+msgstr ""
+
msgid "Published on status page"
msgstr ""
@@ -20361,9 +21053,15 @@ msgstr ""
msgid "Quick range"
msgstr ""
+msgid "Quickly and easily edit multiple files in your project."
+msgstr ""
+
msgid "README"
msgstr ""
+msgid "Rails"
+msgstr ""
+
msgid "Rake Tasks Help"
msgstr ""
@@ -20483,10 +21181,13 @@ msgstr ""
msgid "Register Two-Factor Authenticator"
msgstr ""
-msgid "Register U2F device"
+msgid "Register Universal Two-Factor (U2F) Device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register WebAuthn Device"
+msgstr ""
+
+msgid "Register device"
msgstr ""
msgid "Register for GitLab"
@@ -20498,9 +21199,6 @@ msgstr ""
msgid "Register with two-factor app"
msgstr ""
-msgid "Registration"
-msgstr ""
-
msgid "Registration|Checkout"
msgstr ""
@@ -20617,9 +21315,6 @@ msgstr ""
msgid "Release|Something went wrong while saving the release details"
msgstr ""
-msgid "Remediated: needs review"
-msgstr ""
-
msgid "Remediations"
msgstr ""
@@ -20725,6 +21420,9 @@ msgstr ""
msgid "Remove priority"
msgstr ""
+msgid "Remove report"
+msgstr ""
+
msgid "Remove secondary node"
msgstr ""
@@ -20737,6 +21435,12 @@ msgstr ""
msgid "Remove time estimate"
msgstr ""
+msgid "Remove user & report"
+msgstr ""
+
+msgid "Remove user from group"
+msgstr ""
+
msgid "Removed"
msgstr ""
@@ -20818,9 +21522,6 @@ msgstr ""
msgid "Removes time estimate."
msgstr ""
-msgid "Removing license…"
-msgstr ""
-
msgid "Removing this group also removes all child projects, including archived projects, and their resources."
msgstr ""
@@ -20905,6 +21606,9 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
+msgid "Reported by %{reporter}"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -20991,6 +21695,27 @@ msgstr ""
msgid "Repositories"
msgstr ""
+msgid "Repositories Analytics"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download Historic Test Coverage Data"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download historic test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Historic Test Coverage Data is available in raw format (.csv) for further analysis."
+msgstr ""
+
+msgid "RepositoriesAnalytics|Test Code Coverage"
+msgstr ""
+
+msgid "RepositoriesAnalytics|There was an error fetching the projects."
+msgstr ""
+
msgid "Repository"
msgstr ""
@@ -21069,9 +21794,15 @@ msgstr ""
msgid "Request parameter %{param} is missing."
msgstr ""
+msgid "Request review from"
+msgstr ""
+
msgid "Request to link SAML account must be authorized"
msgstr ""
+msgid "Requested"
+msgstr ""
+
msgid "Requested %{time_ago}"
msgstr ""
@@ -21090,6 +21821,9 @@ msgstr ""
msgid "Requests to these domain(s)/address(es) on the local network will be allowed when local requests from hooks and services are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 or 127.0.0.0/28 are supported. Domain wildcards are not supported currently. Use comma, semicolon, or newline to separate multiple entries. The allowlist can hold a maximum of 1000 entries. Domains should use IDNA encoding. Ex: example.com, 192.168.1.1, 127.0.0.0/28, xn--itlab-j1a.com."
msgstr ""
+msgid "Require admin approval for new sign-ups"
+msgstr ""
+
msgid "Require all users in this group to setup Two-factor authentication"
msgstr ""
@@ -21217,9 +21951,6 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
-msgid "Resolved by %{resolvedByName}"
-msgstr ""
-
msgid "Resolves IP addresses once and uses them to submit requests"
msgstr ""
@@ -21339,6 +22070,14 @@ msgstr ""
msgid "ReviewApp|Enable Review App"
msgstr ""
+msgid "Reviewer"
+msgid_plural "%d Reviewers"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Reviewer(s)"
+msgstr ""
+
msgid "Reviewing"
msgstr ""
@@ -21378,6 +22117,9 @@ msgstr ""
msgid "Rook"
msgstr ""
+msgid "Ruby"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -21456,6 +22198,63 @@ msgstr ""
msgid "Runners page."
msgstr ""
+msgid "Runners|Active"
+msgstr ""
+
+msgid "Runners|Architecture"
+msgstr ""
+
+msgid "Runners|Can run untagged jobs"
+msgstr ""
+
+msgid "Runners|Description"
+msgstr ""
+
+msgid "Runners|Group"
+msgstr ""
+
+msgid "Runners|IP Address"
+msgstr ""
+
+msgid "Runners|Last contact"
+msgstr ""
+
+msgid "Runners|Locked to this project"
+msgstr ""
+
+msgid "Runners|Maximum job timeout"
+msgstr ""
+
+msgid "Runners|Name"
+msgstr ""
+
+msgid "Runners|Platform"
+msgstr ""
+
+msgid "Runners|Property Name"
+msgstr ""
+
+msgid "Runners|Protected"
+msgstr ""
+
+msgid "Runners|Revision"
+msgstr ""
+
+msgid "Runners|Shared"
+msgstr ""
+
+msgid "Runners|Specific"
+msgstr ""
+
+msgid "Runners|Tags"
+msgstr ""
+
+msgid "Runners|Value"
+msgstr ""
+
+msgid "Runners|Version"
+msgstr ""
+
msgid "Runners|You have used %{quotaUsed} out of %{quotaLimit} of your shared Runners pipeline minutes."
msgstr ""
@@ -21468,6 +22267,9 @@ msgstr ""
msgid "Runs a number of housekeeping tasks within the current repository, such as compressing file revisions and removing unreachable objects."
msgstr ""
+msgid "SAML"
+msgstr ""
+
msgid "SAML SSO"
msgstr ""
@@ -21519,6 +22321,9 @@ msgstr ""
msgid "Save"
msgstr ""
+msgid "Save %{name} size limits"
+msgstr ""
+
msgid "Save Changes"
msgstr ""
@@ -21549,9 +22354,6 @@ msgstr ""
msgid "Save space and find tags in the Container Registry more easily. Enable the cleanup policy to remove stale tags and keep only the ones you need."
msgstr ""
-msgid "Save template"
-msgstr ""
-
msgid "Save variables"
msgstr ""
@@ -21594,9 +22396,6 @@ msgstr ""
msgid "Scope"
msgstr ""
-msgid "Scope not supported with disabled 'users_search' feature!"
-msgstr ""
-
msgid "Scoped issue boards"
msgstr ""
@@ -21723,9 +22522,6 @@ msgstr ""
msgid "Search requirements"
msgstr ""
-msgid "Search results…"
-msgstr ""
-
msgid "Search users"
msgstr ""
@@ -21798,6 +22594,11 @@ msgid_plural "SearchResults|commits"
msgstr[0] ""
msgstr[1] ""
+msgid "SearchResults|epic"
+msgid_plural "SearchResults|epics"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "SearchResults|issue"
msgid_plural "SearchResults|issues"
msgstr[0] ""
@@ -21842,10 +22643,10 @@ msgstr ""
msgid "Seat Link is disabled, and cannot be configured through this form."
msgstr ""
-msgid "Seats currently in use"
+msgid "Seats usage data as of %{last_enqueue_time}"
msgstr ""
-msgid "Seats in license"
+msgid "Seats usage data is updated every day at 12:00pm UTC"
msgstr ""
msgid "Secondary"
@@ -21899,6 +22700,9 @@ msgstr ""
msgid "SecurityConfiguration|Available for on-demand DAST"
msgstr ""
+msgid "SecurityConfiguration|By default, all analyzers are applied in order to cover all languages across your project, and only run if the language is detected in the Merge Request."
+msgstr ""
+
msgid "SecurityConfiguration|Configure"
msgstr ""
@@ -21929,16 +22733,19 @@ msgstr ""
msgid "SecurityConfiguration|Manage"
msgstr ""
+msgid "SecurityConfiguration|More information"
+msgstr ""
+
msgid "SecurityConfiguration|Not enabled"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|Security Control"
+msgid "SecurityConfiguration|SAST Configuration"
msgstr ""
-msgid "SecurityConfiguration|See documentation"
+msgid "SecurityConfiguration|Security Control"
msgstr ""
msgid "SecurityConfiguration|Status"
@@ -21950,6 +22757,9 @@ msgstr ""
msgid "SecurityConfiguration|Using custom settings. You won't receive automatic updates on this variable. %{anchorStart}Restore to default%{anchorEnd}"
msgstr ""
+msgid "SecurityConfiguration|View history"
+msgstr ""
+
msgid "SecurityConfiguration|You can quickly enable all security scanning tools by enabling %{linkStart}Auto DevOps%{linkEnd}."
msgstr ""
@@ -22028,9 +22838,6 @@ msgstr ""
msgid "SecurityReports|Learn more about setting up your dashboard"
msgstr ""
-msgid "SecurityReports|Load more vulnerabilities"
-msgstr ""
-
msgid "SecurityReports|Monitor vulnerabilities in your code"
msgstr ""
@@ -22310,7 +23117,7 @@ msgstr ""
msgid "Select status"
msgstr ""
-msgid "Select strategy activation method"
+msgid "Select strategy activation method."
msgstr ""
msgid "Select subscription"
@@ -22325,7 +23132,7 @@ msgstr ""
msgid "Select the custom project template source group."
msgstr ""
-msgid "Select timeframe"
+msgid "Select the environment scope for this feature flag."
msgstr ""
msgid "Select timezone"
@@ -22574,6 +23381,9 @@ msgstr ""
msgid "Set iteration"
msgstr ""
+msgid "Set limit to 0 to allow any file size."
+msgstr ""
+
msgid "Set max session time for web terminal."
msgstr ""
@@ -22652,10 +23462,13 @@ msgstr ""
msgid "Set up a %{type} Runner manually"
msgstr ""
+msgid "Set up a hardware device as a second factor to sign in."
+msgstr ""
+
msgid "Set up assertions/attributes/claims (email, first_name, last_name) and NameID according to %{docsLinkStart}the documentation %{icon}%{docsLinkEnd}"
msgstr ""
-msgid "Set up new U2F device"
+msgid "Set up new device"
msgstr ""
msgid "Set up new password"
@@ -22724,6 +23537,9 @@ msgstr ""
msgid "Sets weight to %{weight}."
msgstr ""
+msgid "Setting this to 0 means using the system default timeout value."
+msgstr ""
+
msgid "Settings"
msgstr ""
@@ -22739,6 +23555,15 @@ msgstr ""
msgid "Severity"
msgstr ""
+msgid "SeverityWidget|Severity"
+msgstr ""
+
+msgid "SeverityWidget|Severity: %{severity}"
+msgstr ""
+
+msgid "SeverityWidget|There was an error while updating severity."
+msgstr ""
+
msgid "Shards (%{shards})"
msgstr ""
@@ -22784,6 +23609,9 @@ msgstr ""
msgid "Show all requirements."
msgstr ""
+msgid "Show all test cases."
+msgstr ""
+
msgid "Show archived projects"
msgstr ""
@@ -22796,6 +23624,9 @@ msgstr ""
msgid "Show comments"
msgstr ""
+msgid "Show comments on this file"
+msgstr ""
+
msgid "Show comments only"
msgstr ""
@@ -22841,6 +23672,12 @@ msgstr ""
msgid "Show parent subgroups"
msgstr ""
+msgid "Show the Closed list"
+msgstr ""
+
+msgid "Show the Open list"
+msgstr ""
+
msgid "Show whitespace changes"
msgstr ""
@@ -22884,9 +23721,6 @@ msgstr ""
msgid "Sidebar|Assign health status"
msgstr ""
-msgid "Sidebar|Change weight"
-msgstr ""
-
msgid "Sidebar|Health status"
msgstr ""
@@ -23070,6 +23904,9 @@ msgstr ""
msgid "Snippets|Add another file %{num}/%{total}"
msgstr ""
+msgid "Snippets|Authored %{time_ago} by %{author}"
+msgstr ""
+
msgid "Snippets|Delete file"
msgstr ""
@@ -23097,6 +23934,9 @@ msgstr ""
msgid "Solution"
msgstr ""
+msgid "Some changes are not shown"
+msgstr ""
+
msgid "Some child epics may be hidden due to applied filters"
msgstr ""
@@ -23463,6 +24303,12 @@ msgstr ""
msgid "Source (branch or tag)"
msgstr ""
+msgid "Source Branch"
+msgstr ""
+
+msgid "Source branch: %{source_branch_open}%{source_branch}%{source_branch_close}"
+msgstr ""
+
msgid "Source code"
msgstr ""
@@ -23628,9 +24474,6 @@ msgstr ""
msgid "Start and due date"
msgstr ""
-msgid "Start by choosing a group to see how your team is spending time. You can then drill down to the project level."
-msgstr ""
-
msgid "Start by choosing a group to start exploring the merge requests in that group. You can then proceed to filter by projects, labels, milestones and authors."
msgstr ""
@@ -23712,18 +24555,27 @@ msgstr ""
msgid "StaticSiteEditor|3. Assign a person to review and accept the merge request."
msgstr ""
+msgid "StaticSiteEditor|A link to view the merge request will appear once ready."
+msgstr ""
+
msgid "StaticSiteEditor|An error occurred while submitting your changes."
msgstr ""
msgid "StaticSiteEditor|Branch could not be created."
msgstr ""
+msgid "StaticSiteEditor|Copy update"
+msgstr ""
+
msgid "StaticSiteEditor|Could not commit the content changes."
msgstr ""
msgid "StaticSiteEditor|Could not create merge request."
msgstr ""
+msgid "StaticSiteEditor|Creating your merge request"
+msgstr ""
+
msgid "StaticSiteEditor|Incompatible file content"
msgstr ""
@@ -23745,6 +24597,9 @@ msgstr ""
msgid "StaticSiteEditor|View documentation"
msgstr ""
+msgid "StaticSiteEditor|You can set an assignee to get your changes reviewed and deployed once your merge request is created."
+msgstr ""
+
msgid "StaticSiteEditor|Your merge request has been created"
msgstr ""
@@ -23874,15 +24729,15 @@ msgstr ""
msgid "Submit %{humanized_resource_name}"
msgstr ""
-msgid "Submit Changes"
-msgstr ""
-
msgid "Submit a review"
msgstr ""
msgid "Submit as spam"
msgstr ""
+msgid "Submit changes"
+msgstr ""
+
msgid "Submit feedback"
msgstr ""
@@ -24036,6 +24891,9 @@ msgstr ""
msgid "Successfully deleted U2F device."
msgstr ""
+msgid "Successfully deleted WebAuthn device."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -24354,9 +25212,6 @@ msgstr ""
msgid "Template to append to all Service Desk issues"
msgstr ""
-msgid "Template was successfully saved."
-msgstr ""
-
msgid "Templates"
msgstr ""
@@ -24435,10 +25290,28 @@ msgid_plural "Test coverage: %d hits"
msgstr[0] ""
msgstr[1] ""
-msgid "Test failed."
+msgid "Test settings"
msgstr ""
-msgid "Test settings and save changes"
+msgid "TestCases|New Test Case"
+msgstr ""
+
+msgid "TestCases|New test case"
+msgstr ""
+
+msgid "TestCases|Search test cases"
+msgstr ""
+
+msgid "TestCases|Something went wrong while creating a test case."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching count of test cases."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching test cases list."
+msgstr ""
+
+msgid "TestCases|Submit test case"
msgstr ""
msgid "TestHooks|Ensure one of your projects has merge requests."
@@ -24504,6 +25377,9 @@ msgstr ""
msgid "Thank you for signing up for your free trial! You will get additional instructions in your inbox shortly."
msgstr ""
+msgid "Thank you for your business."
+msgstr ""
+
msgid "Thank you for your feedback!"
msgstr ""
@@ -24563,9 +25439,6 @@ msgstr ""
msgid "The URL to use for connecting to Elasticsearch. Use a comma-separated list to support clustering (e.g., \"http://localhost:9200, http://localhost:9201\")."
msgstr ""
-msgid "The Web IDE offers advanced syntax highlighting capabilities and more."
-msgstr ""
-
msgid "The X509 Certificate to use when mutual TLS is required to communicate with the external authorization service. If left blank, the server certificate is still validated when accessing over HTTPS."
msgstr ""
@@ -24676,6 +25549,9 @@ msgstr ""
msgid "The form contains the following error:"
msgstr ""
+msgid "The form contains the following warning:"
+msgstr ""
+
msgid "The global settings require you to enable Two-Factor Authentication for your account."
msgstr ""
@@ -24790,9 +25666,6 @@ msgstr ""
msgid "The private key to use when a client certificate is provided. This value is encrypted at rest."
msgstr ""
-msgid "The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The project can be accessed by any logged in user."
msgstr ""
@@ -24829,7 +25702,7 @@ msgstr ""
msgid "The remote repository is being updated..."
msgstr ""
-msgid "The repository can be commited to, and issues, comments and other entities can be created."
+msgid "The repository can be committed to, and issues, comments and other entities can be created."
msgstr ""
msgid "The repository for this project does not exist."
@@ -24883,9 +25756,6 @@ msgstr ""
msgid "The time taken by each data entry gathered by that stage."
msgstr ""
-msgid "The total stage shows the time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The update action will time out after %{number_of_minutes} minutes. For big repositories, use a clone/push combination."
msgstr ""
@@ -24949,6 +25819,9 @@ msgstr ""
msgid "There are no archived requirements"
msgstr ""
+msgid "There are no archived test cases"
+msgstr ""
+
msgid "There are no changes"
msgstr ""
@@ -24988,6 +25861,9 @@ msgstr ""
msgid "There are no open requirements"
msgstr ""
+msgid "There are no open test cases"
+msgstr ""
+
msgid "There are no packages yet"
msgstr ""
@@ -25000,6 +25876,9 @@ msgstr ""
msgid "There is a limit of %{ci_project_subscriptions_limit} subscriptions from or to a project."
msgstr ""
+msgid "There is already a To-Do for this design."
+msgstr ""
+
msgid "There is already a repository with that name on disk"
msgstr ""
@@ -25018,6 +25897,9 @@ msgstr ""
msgid "There was a problem communicating with your device."
msgstr ""
+msgid "There was a problem fetching branches."
+msgstr ""
+
msgid "There was a problem fetching groups."
msgstr ""
@@ -25246,9 +26128,15 @@ msgstr ""
msgid "This action can lead to data loss. To prevent accidental actions we ask you to confirm your intention."
msgstr ""
+msgid "This action cannot be undone, and will permanently delete the %{key} SSH key"
+msgstr ""
+
msgid "This action cannot be undone. You will lose the project's repository and all content: issues, merge requests, etc."
msgstr ""
+msgid "This action has been performed too many times. Try again later."
+msgstr ""
+
msgid "This action will %{strongOpen}permanently delete%{strongClose} %{codeOpen}%{project}%{codeClose} %{strongOpen}immediately%{strongClose}, including its repositories and all content: issues, merge requests, etc."
msgstr ""
@@ -25276,9 +26164,6 @@ msgstr ""
msgid "This board's scope is reduced"
msgstr ""
-msgid "This branch has changed since you started editing. Would you like to create a new branch?"
-msgstr ""
-
msgid "This chart could not be displayed"
msgstr ""
@@ -25405,15 +26290,9 @@ msgstr ""
msgid "This is a security log of important events involving your account."
msgstr ""
-msgid "This is the author's first Merge Request to this project."
-msgstr ""
-
msgid "This is the highest peak of users on your installation since the license started."
msgstr ""
-msgid "This is the maximum number of users that have existed at the same time since the license started. This is the minimum number of seats you will need to buy when you renew your license."
-msgstr ""
-
msgid "This is the number of currently active users on your installation, and this is the minimum number you need to purchase when you renew your license."
msgstr ""
@@ -25645,6 +26524,15 @@ msgstr ""
msgid "This user has no identities"
msgstr ""
+msgid "This user has previously committed to the %{name} project."
+msgstr ""
+
+msgid "This user has the %{access} role in the %{name} project."
+msgstr ""
+
+msgid "This user is the author of this %{noteable}."
+msgstr ""
+
msgid "This user will be the author of all events in the activity feed that are the result of an update, like new branches being created or new commits being pushed to existing branches."
msgstr ""
@@ -25675,6 +26563,9 @@ msgstr ""
msgid "Threat Monitoring"
msgstr ""
+msgid "ThreatMonitoring|All Environments"
+msgstr ""
+
msgid "ThreatMonitoring|Anomalous Requests"
msgstr ""
@@ -25702,9 +26593,6 @@ msgstr ""
msgid "ThreatMonitoring|Operations Per Second"
msgstr ""
-msgid "ThreatMonitoring|Overview"
-msgstr ""
-
msgid "ThreatMonitoring|Packet Activity"
msgstr ""
@@ -25723,6 +26611,9 @@ msgstr ""
msgid "ThreatMonitoring|Something went wrong, unable to fetch statistics"
msgstr ""
+msgid "ThreatMonitoring|Statistics"
+msgstr ""
+
msgid "ThreatMonitoring|The firewall is not installed or has been disabled. To view this data, ensure the web application firewall is installed and enabled for your cluster."
msgstr ""
@@ -26114,6 +27005,9 @@ msgstr ""
msgid "To update Snippets with multiple files, you must use the `files` parameter"
msgstr ""
+msgid "To use Gitpod you must first enable the feature in the integrations section of your %{user_prefs}."
+msgstr ""
+
msgid "To view all %{scannedResourcesCount} scanned URLs, please download the CSV file"
msgstr ""
@@ -26147,9 +27041,6 @@ msgstr ""
msgid "Toggle Sidebar"
msgstr ""
-msgid "Toggle all threads"
-msgstr ""
-
msgid "Toggle backtrace"
msgstr ""
@@ -26174,9 +27065,6 @@ msgstr ""
msgid "Toggle navigation"
msgstr ""
-msgid "Toggle project"
-msgstr ""
-
msgid "Toggle sidebar"
msgstr ""
@@ -26216,6 +27104,9 @@ msgstr ""
msgid "Too many projects enabled. You will need to manage them via the console or the API."
msgstr ""
+msgid "Too much data"
+msgstr ""
+
msgid "Topics (optional)"
msgstr ""
@@ -26234,6 +27125,9 @@ msgstr ""
msgid "Total cores (CPUs)"
msgstr ""
+msgid "Total days to completion"
+msgstr ""
+
msgid "Total issues"
msgstr ""
@@ -26330,6 +27224,9 @@ msgstr ""
msgid "Trending"
msgstr ""
+msgid "Trials|Create a new group to start your GitLab Gold trial."
+msgstr ""
+
msgid "Trials|Go back to GitLab"
msgstr ""
@@ -26339,6 +27236,15 @@ msgstr ""
msgid "Trials|You can always resume this process by selecting your avatar and choosing 'Start a Gold trial'"
msgstr ""
+msgid "Trials|You can apply your trial to a new group or an existing group."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group or your personal account."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group, an existing group, or your personal account."
+msgstr ""
+
msgid "Trials|You won't get a free trial right now but you can always resume this process by clicking on your avatar and choosing 'Start a free trial'"
msgstr ""
@@ -26408,6 +27314,9 @@ msgstr ""
msgid "Try using a different search term to find the file you are looking for."
msgstr ""
+msgid "Trying to communicate with your device. Plug it in (if needed) and press the button on the device now."
+msgstr ""
+
msgid "Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now."
msgstr ""
@@ -26495,6 +27404,12 @@ msgstr ""
msgid "URL or request ID"
msgstr ""
+msgid "USER %{user} WILL BE REMOVED! Are you sure?"
+msgstr ""
+
+msgid "USER WILL BE BLOCKED! Are you sure?"
+msgstr ""
+
msgid "UTC"
msgstr ""
@@ -26552,9 +27467,6 @@ msgstr ""
msgid "Unable to load the merge request widget. Try reloading the page."
msgstr ""
-msgid "Unable to resolve"
-msgstr ""
-
msgid "Unable to save iteration. Please try again"
msgstr ""
@@ -26603,6 +27515,9 @@ msgstr ""
msgid "Undo ignore"
msgstr ""
+msgid "Unexpected error"
+msgstr ""
+
msgid "Unfortunately, your email message to GitLab could not be processed."
msgstr ""
@@ -26636,6 +27551,9 @@ msgstr ""
msgid "Unknown response text"
msgstr ""
+msgid "Unless otherwise agreed to in writing with GitLab, by clicking \"Upload License\" you agree that your use of GitLab Software is subject to the %{eula_link_start}Terms of Service%{eula_link_end}."
+msgstr ""
+
msgid "Unlimited"
msgstr ""
@@ -27002,9 +27920,6 @@ msgstr ""
msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
msgstr ""
-msgid "Use a hardware device to add the second factor of authentication."
-msgstr ""
-
msgid "Use an one time password authenticator on your mobile device or computer to enable two-factor authentication (2FA)."
msgstr ""
@@ -27278,13 +28193,13 @@ msgstr ""
msgid "Users"
msgstr ""
-msgid "Users in License:"
+msgid "Users in License"
msgstr ""
-msgid "Users or groups set as approvers in the project's or merge request's settings."
+msgid "Users in License:"
msgstr ""
-msgid "Users outside of license"
+msgid "Users or groups set as approvers in the project's or merge request's settings."
msgstr ""
msgid "Users over License:"
@@ -27302,9 +28217,6 @@ msgstr ""
msgid "Users with a Guest role or those who don't belong to a Project or Group will not use a seat from your license."
msgstr ""
-msgid "Users with a Guest role or those who don't belong to any projects or groups don't count towards seats in use."
-msgstr ""
-
msgid "UsersSelect|%{name} + %{length} more"
msgstr ""
@@ -27344,9 +28256,6 @@ msgstr ""
msgid "Validations failed."
msgstr ""
-msgid "Validity"
-msgstr ""
-
msgid "Value"
msgstr ""
@@ -27365,6 +28274,9 @@ msgstr ""
msgid "Value Stream Name"
msgstr ""
+msgid "ValueStreamAnalyticsStage|We don't have enough data to show this stage."
+msgstr ""
+
msgid "ValueStreamAnalytics|%{days}d"
msgstr ""
@@ -27621,6 +28533,9 @@ msgstr ""
msgid "VisualReviewApp|Steps 1 and 2 (and sometimes 3) are performed once by the developer before requesting feedback. Steps 3 (if necessary), 4 is performed by the reviewer each time they perform a review."
msgstr ""
+msgid "Visualization"
+msgstr ""
+
msgid "Vulnerabilities"
msgstr ""
@@ -27648,34 +28563,31 @@ msgstr ""
msgid "VulnerabilityChart|Severity"
msgstr ""
-msgid "VulnerabilityManagement|A true-positive and will fix"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Change status"
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|Confirm"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Confirmed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
-msgstr ""
-
-msgid "VulnerabilityManagement|Detected %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|A true-positive and will fix"
msgstr ""
-msgid "VulnerabilityManagement|Dismiss"
+msgid "VulnerabilityManagement|Change status"
msgstr ""
-msgid "VulnerabilityManagement|Dismissed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
msgstr ""
-msgid "VulnerabilityManagement|Resolved"
+msgid "VulnerabilityManagement|Detected"
msgstr ""
-msgid "VulnerabilityManagement|Resolved %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Needs triage"
msgstr ""
msgid "VulnerabilityManagement|Something went wrong while trying to delete the comment. Please try again later."
@@ -27726,6 +28638,9 @@ msgstr ""
msgid "Vulnerability|%{scannerName} (version %{scannerVersion})"
msgstr ""
+msgid "Vulnerability|Activity"
+msgstr ""
+
msgid "Vulnerability|Class"
msgstr ""
@@ -27738,6 +28653,9 @@ msgstr ""
msgid "Vulnerability|Description"
msgstr ""
+msgid "Vulnerability|Detected"
+msgstr ""
+
msgid "Vulnerability|Evidence"
msgstr ""
@@ -27801,6 +28719,9 @@ msgstr ""
msgid "Warning: Displaying this diagram might cause performance issues on this page."
msgstr ""
+msgid "We are currently unable to fetch data for the pipeline header."
+msgstr ""
+
msgid "We are currently unable to fetch data for this graph."
msgstr ""
@@ -27840,6 +28761,12 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
+msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
+msgstr ""
+
+msgid "We would like to inform you that your subscription GitLab Enterprise Edition %{plan_name} is nearing its user limit. You have %{active_user_count} active users, which is almost at the user limit of %{maximum_user_count}."
+msgstr ""
+
msgid "We've found no vulnerabilities"
msgstr ""
@@ -27855,6 +28782,12 @@ msgstr ""
msgid "Web terminal"
msgstr ""
+msgid "WebAuthn Devices (%{length})"
+msgstr ""
+
+msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
+msgstr ""
+
msgid "WebIDE|Merge request"
msgstr ""
@@ -27993,15 +28926,9 @@ msgstr ""
msgid "Welcome to the guided GitLab tour"
msgstr ""
-msgid "Welcome to your Issue Board!"
-msgstr ""
-
msgid "Welcome to your issue board!"
msgstr ""
-msgid "We’ve been making changes to %{featureName} and we’d love your feedback %{linkStart}in this issue%{linkEnd} to help us improve the experience."
-msgstr ""
-
msgid "What are you searching for?"
msgstr ""
@@ -28020,6 +28947,9 @@ msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
msgstr ""
+msgid "When enabled, any user visiting %{host} and creating an account will have to be explicitly approved by the admin before they can login. This setting is effective only if sign-ups are enabled."
+msgstr ""
+
msgid "When enabled, any user visiting %{host} will be able to create an account."
msgstr ""
@@ -28244,6 +29174,9 @@ msgstr ""
msgid "With requirements, you can set criteria to check your products against."
msgstr ""
+msgid "With test cases, you can define conditions for your project to meet in determining quality"
+msgstr ""
+
msgid "Withdraw Access Request"
msgstr ""
@@ -28259,6 +29192,9 @@ msgstr ""
msgid "Workflow Help"
msgstr ""
+msgid "Would you like to create a new branch?"
+msgstr ""
+
msgid "Write"
msgstr ""
@@ -28280,6 +29216,9 @@ msgstr ""
msgid "Wrong extern UID provided. Make sure Auth0 is configured correctly."
msgstr ""
+msgid "YYYY-MM-DD"
+msgstr ""
+
msgid "Yes"
msgstr ""
@@ -28337,7 +29276,7 @@ msgstr ""
msgid "You are going to remove the fork relationship from %{project_full_name}. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "You are going to transfer %{project_full_name} to another owner. Are you ABSOLUTELY sure?"
+msgid "You are going to transfer %{project_full_name} to another namespace. Are you ABSOLUTELY sure?"
msgstr ""
msgid "You are going to turn off the confidentiality. This means %{strongStart}everyone%{strongEnd} will be able to see and leave a comment on this %{issuableType}."
@@ -28397,9 +29336,6 @@ msgstr ""
msgid "You can always edit this later"
msgstr ""
-msgid "You can apply your Trial to your Personal account or create a New Group."
-msgstr ""
-
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings"
msgstr ""
@@ -28421,12 +29357,18 @@ msgstr ""
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
+msgid "You can find more information about GitLab subscriptions in %{subscriptions_doc_link}."
+msgstr ""
+
msgid "You can generate an access token scoped to this project for each application to use the GitLab API."
msgstr ""
msgid "You can get started by cloning the repository or start adding files to it with one of the following options."
msgstr ""
+msgid "You can group test cases using labels. To learn about the future direction of this feature, visit %{linkStart}Quality Management direction page%{linkEnd}."
+msgstr ""
+
msgid "You can invite a new member to %{project_name} or invite another group."
msgstr ""
@@ -28442,6 +29384,9 @@ msgstr ""
msgid "You can notify the app / group or a project by sending them an email notification"
msgstr ""
+msgid "You can now close this window."
+msgstr ""
+
msgid "You can now export your security dashboard to a CSV report."
msgstr ""
@@ -28490,9 +29435,6 @@ msgstr ""
msgid "You can test your .gitlab-ci.yml in %{linkStart}CI Lint%{linkEnd}."
msgstr ""
-msgid "You can try again using %{begin_link}basic search%{end_link}"
-msgstr ""
-
msgid "You cannot access the raw file. Please wait a minute."
msgstr ""
@@ -28544,6 +29486,9 @@ msgstr ""
msgid "You don't have any U2F devices registered yet."
msgstr ""
+msgid "You don't have any WebAuthn devices registered yet."
+msgstr ""
+
msgid "You don't have any active chat names."
msgstr ""
@@ -28631,6 +29576,9 @@ msgstr ""
msgid "You must accept our Terms of Service and privacy policy in order to register an account"
msgstr ""
+msgid "You must be logged in to search across all of GitLab"
+msgstr ""
+
msgid "You must disassociate %{domain} from all clusters it is attached to before deletion."
msgstr ""
@@ -28670,7 +29618,7 @@ msgstr ""
msgid "You need to be logged in."
msgstr ""
-msgid "You need to register a two-factor authentication app before you can set up a U2F device."
+msgid "You need to register a two-factor authentication app before you can set up a device."
msgstr ""
msgid "You need to set terms to be enforced"
@@ -28688,6 +29636,9 @@ msgstr ""
msgid "You reached %{usage_in_percent} of %{namespace_name}'s storage capacity (%{used_storage} of %{storage_limit})"
msgstr ""
+msgid "You successfully declined the invitation"
+msgstr ""
+
msgid "You tried to fork %{link_to_the_project} but it failed for the following reason:"
msgstr ""
@@ -28853,10 +29804,13 @@ msgstr ""
msgid "Your U2F device did not send a valid JSON response."
msgstr ""
-msgid "Your U2F device needs to be set up. Plug it in (if not already) and click the button on the left."
+msgid "Your U2F device was registered!"
msgstr ""
-msgid "Your U2F device was registered!"
+msgid "Your WebAuthn device did not send a valid JSON response."
+msgstr ""
+
+msgid "Your WebAuthn device was registered!"
msgstr ""
msgid "Your access request to the %{source_type} has been withdrawn."
@@ -28880,6 +29834,9 @@ msgstr ""
msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
msgstr ""
+msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
+msgstr ""
+
msgid "Your changes can be committed to %{branch_name} because a merge request is open."
msgstr ""
@@ -28916,6 +29873,12 @@ msgstr ""
msgid "Your deployment services will be broken, you will need to manually fix the services after renaming."
msgstr ""
+msgid "Your device is not compatible with GitLab. Please try another device"
+msgstr ""
+
+msgid "Your device needs to be set up. Plug it in (if needed) and click the button on the left."
+msgstr ""
+
msgid "Your device was successfully set up! Give it a name and register it with the GitLab server."
msgstr ""
@@ -29029,9 +29992,6 @@ msgstr[1] ""
msgid "access:"
msgstr ""
-msgid "activated"
-msgstr ""
-
msgid "added %{created_at_timeago}"
msgstr ""
@@ -29104,9 +30064,21 @@ msgstr ""
msgid "by %{user}"
msgstr ""
+msgid "cannot be a date in the past"
+msgstr ""
+
msgid "cannot be changed if a personal project has container registry tags."
msgstr ""
+msgid "cannot be changed if shared runners are enabled"
+msgstr ""
+
+msgid "cannot be enabled because parent group does not allow it"
+msgstr ""
+
+msgid "cannot be enabled because parent group has shared Runners disabled"
+msgstr ""
+
msgid "cannot be enabled unless all domains have TLS certificates"
msgstr ""
@@ -29152,7 +30124,7 @@ msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about SAST %{linkEndTag}"
msgstr ""
-msgid "ciReport|%{linkStartTag}Learn more about Secret Scanning %{linkEndTag}"
+msgid "ciReport|%{linkStartTag}Learn more about Secret Detection %{linkEndTag}"
msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about codequality reports %{linkEndTag}"
@@ -29467,9 +30439,6 @@ msgstr ""
msgid "error"
msgstr ""
-msgid "error code:"
-msgstr ""
-
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr ""
@@ -29491,6 +30460,9 @@ msgstr ""
msgid "failed to dismiss associated finding(id=%{finding_id}): %{message}"
msgstr ""
+msgid "failed to revert associated finding(id=%{finding_id}) to detected"
+msgstr ""
+
msgid "file"
msgid_plural "files"
msgstr[0] ""
@@ -30033,6 +31005,9 @@ msgstr ""
msgid "must be a root namespace"
msgstr ""
+msgid "must be a valid IPv4 or IPv6 address"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -30069,6 +31044,9 @@ msgstr ""
msgid "no expiration"
msgstr ""
+msgid "no name set"
+msgstr ""
+
msgid "no one can merge"
msgstr ""
@@ -30247,9 +31225,6 @@ msgstr ""
msgid "security Reports|There was an error creating the merge request"
msgstr ""
-msgid "settings saved, but not activated"
-msgstr ""
-
msgid "severity|Critical"
msgstr ""
@@ -30376,9 +31351,6 @@ msgstr ""
msgid "toggle collapse"
msgstr ""
-msgid "toggle dropdown"
-msgstr ""
-
msgid "triggered"
msgstr ""
@@ -30406,6 +31378,9 @@ msgstr ""
msgid "user avatar"
msgstr ""
+msgid "user preferences"
+msgstr ""
+
msgid "username"
msgstr ""
diff --git a/locale/uz_UZ/gitlab.po b/locale/uz_UZ/gitlab.po
index e654b51474b..3151fead0de 100644
--- a/locale/uz_UZ/gitlab.po
+++ b/locale/uz_UZ/gitlab.po
@@ -14,7 +14,10 @@ msgstr ""
"X-Crowdin-Language: uz\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 6\n"
-"PO-Revision-Date: 2020-09-04 23:04\n"
+"PO-Revision-Date: 2020-10-02 18:44\n"
+
+msgid " %{project_name}#%{issue_iid} &middot; opened %{issue_created} by %{author}"
+msgstr ""
msgid " %{start} to %{end}"
msgstr ""
@@ -74,6 +77,16 @@ msgstr ""
msgid "\"el\" parameter is required for createInstance()"
msgstr ""
+msgid "%d Approval"
+msgid_plural "%d Approvals"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d Package"
+msgid_plural "%d Packages"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d Scanned URL"
msgid_plural "%d Scanned URLs"
msgstr[0] ""
@@ -137,6 +150,11 @@ msgstr[1] ""
msgid "%d commits"
msgstr ""
+msgid "%d completed issue"
+msgid_plural "%d completed issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d contribution"
msgid_plural "%d contributions"
msgstr[0] ""
@@ -147,6 +165,11 @@ msgid_plural "%d days"
msgstr[0] ""
msgstr[1] ""
+msgid "%d day until tags are automatically removed"
+msgid_plural "%d days until tags are automatically removed"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d error"
msgid_plural "%d errors"
msgstr[0] ""
@@ -237,6 +260,16 @@ msgid_plural "%d more comments"
msgstr[0] ""
msgstr[1] ""
+msgid "%d open issue"
+msgid_plural "%d open issues"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%d pending comment"
+msgid_plural "%d pending comments"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d personal project will be removed and cannot be restored."
msgid_plural "%d personal projects will be removed and cannot be restored."
msgstr[0] ""
@@ -252,6 +285,11 @@ msgid_plural "%d projects"
msgstr[0] ""
msgstr[1] ""
+msgid "%d project selected"
+msgid_plural "%d projects selected"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d request with warnings"
msgid_plural "%d requests with warnings"
msgstr[0] ""
@@ -272,6 +310,11 @@ msgid_plural "%d tags"
msgstr[0] ""
msgstr[1] ""
+msgid "%d tag per image name"
+msgid_plural "%d tags per image name"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d unassigned issue"
msgid_plural "%d unassigned issues"
msgstr[0] ""
@@ -292,6 +335,11 @@ msgid_plural "%d vulnerabilities dismissed"
msgstr[0] ""
msgstr[1] ""
+msgid "%d warning found:"
+msgid_plural "%d warnings found:"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%s additional commit has been omitted to prevent performance issues."
msgid_plural "%s additional commits have been omitted to prevent performance issues."
msgstr[0] ""
@@ -330,6 +378,9 @@ msgstr ""
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr ""
+msgid "%{completedCount} completed weight"
+msgstr ""
+
msgid "%{completedWeight} of %{totalWeight} weight completed"
msgstr ""
@@ -378,14 +429,12 @@ msgid_plural "%{count} participants"
msgstr[0] ""
msgstr[1] ""
-msgid "%{count} pending comment"
-msgid_plural "%{count} pending comments"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
+msgid "%{count} total weight"
+msgstr ""
+
msgid "%{dashboard_path} could not be found."
msgstr ""
@@ -440,6 +489,9 @@ msgstr ""
msgid "%{group_name} uses group managed accounts. You need to create a new GitLab account which will be managed by %{group_name}."
msgstr ""
+msgid "%{group_name}&%{epic_iid} &middot; opened %{epic_created} by %{author}"
+msgstr ""
+
msgid "%{host} sign-in from new location"
msgstr ""
@@ -452,7 +504,7 @@ msgstr ""
msgid "%{issuableType} will be removed! Are you sure?"
msgstr ""
-msgid "%{issuesSize} issues with a limit of %{maxIssueCount}"
+msgid "%{issuesCount} issues with a limit of %{maxIssueCount}"
msgstr ""
msgid "%{issuesSize} with a limit of %{maxIssueCount}"
@@ -485,7 +537,7 @@ msgstr ""
msgid "%{labelStart}Namespace:%{labelEnd} %{namespace}"
msgstr ""
-msgid "%{labelStart}Report Type:%{labelEnd} %{reportType}"
+msgid "%{labelStart}Scan Type:%{labelEnd} %{reportType}"
msgstr ""
msgid "%{labelStart}Scanner:%{labelEnd} %{scanner}"
@@ -682,9 +734,6 @@ msgid_plural "%{securityScanner} results are not available because a pipeline ha
msgstr[0] ""
msgstr[1] ""
-msgid "%{service_title} %{message}."
-msgstr ""
-
msgid "%{size} GiB"
msgstr ""
@@ -773,6 +822,12 @@ msgstr ""
msgid "%{timebox_name} should belong either to a project or a group."
msgstr ""
+msgid "%{timebox_type} does not support burnup charts"
+msgstr ""
+
+msgid "%{timebox_type} must have a start and due date"
+msgstr ""
+
msgid "%{title} %{operator} %{threshold}"
msgstr ""
@@ -797,7 +852,7 @@ msgstr ""
msgid "%{total} open issue weight"
msgstr ""
-msgid "%{total} open issues"
+msgid "%{total} warnings found: showing first %{warningsDisplayed}"
msgstr ""
msgid "%{usage_ping_link_start}Learn more%{usage_ping_link_end} about what information is shared with GitLab Inc."
@@ -830,9 +885,6 @@ msgstr ""
msgid "&lt; 1 hour"
msgstr ""
-msgid "&lt;no name set&gt;"
-msgstr ""
-
msgid "&lt;no scopes selected&gt;"
msgstr ""
@@ -863,6 +915,9 @@ msgstr ""
msgid "'%{name}' Value Stream created"
msgstr ""
+msgid "'%{name}' Value Stream deleted"
+msgstr ""
+
msgid "'%{name}' stage already exists"
msgstr ""
@@ -922,6 +977,9 @@ msgstr ""
msgid "+ %{numberOfHiddenAssignees} more"
msgstr ""
+msgid "+ %{numberOfHiddenReviewers} more"
+msgstr ""
+
msgid "+%d more"
msgid_plural "+%d more"
msgstr[0] ""
@@ -982,6 +1040,11 @@ msgid_plural "%d Days"
msgstr[0] ""
msgstr[1] ""
+msgid "1 Issue"
+msgid_plural "%d Issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "1 closed issue"
msgid_plural "%{issues} closed issues"
msgstr[0] ""
@@ -997,6 +1060,11 @@ msgid_plural "%d days"
msgstr[0] ""
msgstr[1] ""
+msgid "1 deploy key"
+msgid_plural "%d deploy keys"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1099,6 +1167,9 @@ msgstr ""
msgid ":%{startLine} to %{endLine}"
msgstr ""
+msgid "A %{incident_docs_start}modified issue%{incident_docs_end} to guide the resolution of incidents."
+msgstr ""
+
msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr ""
@@ -1111,6 +1182,9 @@ msgstr ""
msgid "A GitBook site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
+msgid "A Gitpod configured Webapplication in Spring and Java"
+msgstr ""
+
msgid "A Hexo site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
@@ -1282,9 +1356,15 @@ msgstr ""
msgid "Access expiration date"
msgstr ""
+msgid "Access expires"
+msgstr ""
+
msgid "Access forbidden. Check your access level."
msgstr ""
+msgid "Access granted"
+msgstr ""
+
msgid "Access requests"
msgstr ""
@@ -1294,6 +1374,9 @@ msgstr ""
msgid "Access to Pages websites are controlled based on the user's membership to a given project. By checking this box, users will be required to be logged in to have access to all Pages websites in your instance."
msgstr ""
+msgid "AccessDropdown|Deploy Keys"
+msgstr ""
+
msgid "AccessDropdown|Groups"
msgstr ""
@@ -1411,12 +1494,6 @@ msgstr ""
msgid "Active Sessions"
msgstr ""
-msgid "Active Users:"
-msgstr ""
-
-msgid "Active users"
-msgstr ""
-
msgid "Activity"
msgstr ""
@@ -1584,9 +1661,6 @@ msgstr ""
msgid "Add label(s)"
msgstr ""
-msgid "Add license"
-msgstr ""
-
msgid "Add list"
msgstr ""
@@ -1761,21 +1835,51 @@ msgstr ""
msgid "AdminArea|Bots"
msgstr ""
+msgid "AdminArea|Components"
+msgstr ""
+
msgid "AdminArea|Developer"
msgstr ""
+msgid "AdminArea|Features"
+msgstr ""
+
+msgid "AdminArea|Groups: %{number_of_groups}"
+msgstr ""
+
msgid "AdminArea|Guest"
msgstr ""
msgid "AdminArea|Included Free in license"
msgstr ""
+msgid "AdminArea|Latest groups"
+msgstr ""
+
+msgid "AdminArea|Latest projects"
+msgstr ""
+
+msgid "AdminArea|Latest users"
+msgstr ""
+
msgid "AdminArea|Maintainer"
msgstr ""
+msgid "AdminArea|New group"
+msgstr ""
+
+msgid "AdminArea|New project"
+msgstr ""
+
+msgid "AdminArea|New user"
+msgstr ""
+
msgid "AdminArea|Owner"
msgstr ""
+msgid "AdminArea|Projects: %{number_of_projects}"
+msgstr ""
+
msgid "AdminArea|Reporter"
msgstr ""
@@ -1803,6 +1907,9 @@ msgstr ""
msgid "AdminArea|Users without a Group and Project"
msgstr ""
+msgid "AdminArea|Users: %{number_of_users}"
+msgstr ""
+
msgid "AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running."
msgstr ""
@@ -1821,9 +1928,6 @@ msgstr ""
msgid "AdminProjects|Delete Project %{projectName}?"
msgstr ""
-msgid "AdminProjects|Delete project"
-msgstr ""
-
msgid "AdminSettings|Apply integration settings to all Projects"
msgstr ""
@@ -2061,21 +2165,30 @@ msgstr ""
msgid "AdminUsers|Without projects"
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 ""
msgid "AdminUsers|You cannot remove your own admin rights."
msgstr ""
+msgid "AdminUsers|You must transfer ownership or delete the groups owned by this user before you can delete their account"
+msgstr ""
+
msgid "Administration"
msgstr ""
msgid "Advanced"
msgstr ""
+msgid "Advanced Search"
+msgstr ""
+
+msgid "Advanced Search with Elasticsearch"
+msgstr ""
+
msgid "Advanced Settings"
msgstr ""
@@ -2153,6 +2266,9 @@ msgstr ""
msgid "AlertManagement|Edit"
msgstr ""
+msgid "AlertManagement|Environment"
+msgstr ""
+
msgid "AlertManagement|Events"
msgstr ""
@@ -2165,6 +2281,9 @@ msgstr ""
msgid "AlertManagement|Issue"
msgstr ""
+msgid "AlertManagement|Key"
+msgstr ""
+
msgid "AlertManagement|Low"
msgstr ""
@@ -2258,6 +2377,9 @@ msgstr ""
msgid "AlertManagement|Unknown"
msgstr ""
+msgid "AlertManagement|Value"
+msgstr ""
+
msgid "AlertManagement|View alerts in Opsgenie"
msgstr ""
@@ -2417,6 +2539,9 @@ msgstr ""
msgid "All projects"
msgstr ""
+msgid "All projects selected"
+msgstr ""
+
msgid "All security scans are enabled because %{linkStart}Auto DevOps%{linkEnd} is enabled on this project"
msgstr ""
@@ -2504,6 +2629,9 @@ msgstr ""
msgid "Almost there"
msgstr ""
+msgid "Already blocked"
+msgstr ""
+
msgid "Also called \"Issuer\" or \"Relying party trust identifier\""
msgstr ""
@@ -2558,6 +2686,9 @@ msgstr ""
msgid "An error has occurred"
msgstr ""
+msgid "An error occured while making the changes: %{error}"
+msgstr ""
+
msgid "An error occurred adding a draft to the thread."
msgstr ""
@@ -2585,12 +2716,6 @@ msgstr ""
msgid "An error occurred when toggling the notification subscription"
msgstr ""
-msgid "An error occurred when trying to resolve a comment. Please try again."
-msgstr ""
-
-msgid "An error occurred when trying to resolve a discussion. Please try again."
-msgstr ""
-
msgid "An error occurred when updating the issue weight"
msgstr ""
@@ -2606,12 +2731,6 @@ msgstr ""
msgid "An error occurred while checking group path. Please refresh and try again."
msgstr ""
-msgid "An error occurred while committing your changes."
-msgstr ""
-
-msgid "An error occurred while creating the list. Please try again."
-msgstr ""
-
msgid "An error occurred while decoding the file."
msgstr ""
@@ -2684,25 +2803,19 @@ msgstr ""
msgid "An error occurred while fetching the Service Desk address."
msgstr ""
-msgid "An error occurred while fetching the board issues. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the board lists. Please reload the page."
msgstr ""
msgid "An error occurred while fetching the board lists. Please try again."
msgstr ""
-msgid "An error occurred while fetching the board swimlanes. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the builds."
msgstr ""
msgid "An error occurred while fetching the job log."
msgstr ""
-msgid "An error occurred while fetching the job trace."
+msgid "An error occurred while fetching the job logs."
msgstr ""
msgid "An error occurred while fetching the job."
@@ -2849,9 +2962,6 @@ msgstr ""
msgid "An error occurred while saving assignees"
msgstr ""
-msgid "An error occurred while saving the template. Please check if the template exists."
-msgstr ""
-
msgid "An error occurred while searching for milestones"
msgstr ""
@@ -2870,10 +2980,10 @@ msgstr ""
msgid "An error occurred while updating approvers"
msgstr ""
-msgid "An error occurred while updating the comment"
+msgid "An error occurred while updating labels."
msgstr ""
-msgid "An error occurred while updating the list. Please try again."
+msgid "An error occurred while updating the comment"
msgstr ""
msgid "An error occurred while validating group path"
@@ -2927,6 +3037,9 @@ msgstr ""
msgid "An unknown error occurred while loading this graph."
msgstr ""
+msgid "An unknown error occurred."
+msgstr ""
+
msgid "Analytics"
msgstr ""
@@ -2960,10 +3073,10 @@ msgstr ""
msgid "Any"
msgstr ""
-msgid "Any Author"
+msgid "Any %{header}"
msgstr ""
-msgid "Any Status"
+msgid "Any Author"
msgstr ""
msgid "Any branch"
@@ -3017,6 +3130,9 @@ msgstr ""
msgid "Application ID"
msgstr ""
+msgid "Application limits saved successfully"
+msgstr ""
+
msgid "Application settings saved successfully"
msgstr ""
@@ -3226,6 +3342,9 @@ msgstr ""
msgid "Are you sure you want to close this blocked issue?"
msgstr ""
+msgid "Are you sure you want to delete \"%{name}\" Value Stream?"
+msgstr ""
+
msgid "Are you sure you want to delete %{name}?"
msgstr ""
@@ -3235,6 +3354,9 @@ msgstr ""
msgid "Are you sure you want to delete this %{typeOfComment}?"
msgstr ""
+msgid "Are you sure you want to delete this SSH key?"
+msgstr ""
+
msgid "Are you sure you want to delete this board?"
msgstr ""
@@ -3259,6 +3381,11 @@ msgstr ""
msgid "Are you sure you want to erase this build?"
msgstr ""
+msgid "Are you sure you want to import %d repository?"
+msgid_plural "Are you sure you want to import %d repositories?"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Are you sure you want to lose unsaved changes?"
msgstr ""
@@ -3268,15 +3395,15 @@ msgstr ""
msgid "Are you sure you want to merge immediately?"
msgstr ""
-msgid "Are you sure you want to permanently delete this license?"
-msgstr ""
-
msgid "Are you sure you want to re-deploy this environment?"
msgstr ""
msgid "Are you sure you want to regenerate the public key? You will have to update the public key on the remote server before mirroring will work again."
msgstr ""
+msgid "Are you sure you want to reindex?"
+msgstr ""
+
msgid "Are you sure you want to remove %{group_name}?"
msgstr ""
@@ -3304,6 +3431,9 @@ msgstr ""
msgid "Are you sure you want to revoke this nickname?"
msgstr ""
+msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
+msgstr ""
+
msgid "Are you sure you want to stop this environment?"
msgstr ""
@@ -3325,6 +3455,9 @@ msgstr ""
msgid "Are you sure? The device will be signed out of GitLab and all remember me tokens revoked."
msgstr ""
+msgid "Are you sure? This will invalidate your registered applications and U2F / WebAuthn devices."
+msgstr ""
+
msgid "Are you sure? This will invalidate your registered applications and U2F devices."
msgstr ""
@@ -3343,9 +3476,6 @@ msgstr ""
msgid "Artifacts"
msgstr ""
-msgid "As U2F devices are only supported by a few browsers, we require that you set up a two-factor authentication app before a U2F device. That way you'll always be able to log in - even when you're using an unsupported browser."
-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 ""
@@ -3539,6 +3669,9 @@ msgstr ""
msgid "AuditLogs|Target"
msgstr ""
+msgid "AuditLogs|This month"
+msgstr ""
+
msgid "AuditLogs|User Events"
msgstr ""
@@ -3578,6 +3711,9 @@ msgstr ""
msgid "Authentication via U2F device failed."
msgstr ""
+msgid "Authentication via WebAuthn device failed."
+msgstr ""
+
msgid "Author"
msgstr ""
@@ -3845,15 +3981,6 @@ msgstr ""
msgid "BambooService|You must set up automatic revision labeling and a repository trigger in Bamboo."
msgstr ""
-msgid "BatchComments|Delete all pending comments"
-msgstr ""
-
-msgid "BatchComments|Discard review?"
-msgstr ""
-
-msgid "BatchComments|You're about to discard your review which will delete all of your pending comments. The deleted comments %{strong_start}cannot%{strong_end} be restored."
-msgstr ""
-
msgid "Be careful. Changing the project's namespace can have unintended side effects."
msgstr ""
@@ -3875,6 +4002,9 @@ msgstr ""
msgid "Bi-weekly code coverage"
msgstr ""
+msgid "Billable Users:"
+msgstr ""
+
msgid "Billing"
msgstr ""
@@ -3884,7 +4014,7 @@ msgstr ""
msgid "BillingPlans|@%{user_name} you are currently using the %{plan_name} plan."
msgstr ""
-msgid "BillingPlans|Congratulations, your new trial is activated"
+msgid "BillingPlans|Congratulations, your free trial is activated."
msgstr ""
msgid "BillingPlans|If you would like to downgrade your plan please contact %{support_link_start}Customer Support%{support_link_end}."
@@ -3947,6 +4077,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Block user"
+msgstr ""
+
msgid "Blocked"
msgstr ""
@@ -3962,31 +4095,37 @@ msgstr ""
msgid "Blog"
msgstr ""
-msgid "Board name"
-msgstr ""
-
msgid "Board scope"
msgstr ""
msgid "Board scope affects which issues are displayed for anyone who visits this board"
msgstr ""
-msgid "BoardBlankState|Add default lists"
+msgid "Boards"
msgstr ""
-msgid "BoardBlankState|Add the following default lists to your Issue Board with one click:"
+msgid "Boards and Board Lists"
msgstr ""
-msgid "BoardBlankState|Nevermind, I'll use my own"
+msgid "Boards|An error occurred while creating the issue. Please try again."
msgstr ""
-msgid "BoardBlankState|Starting out with the default set of lists will get you right on the way to making the most of your board."
+msgid "Boards|An error occurred while creating the list. Please try again."
msgstr ""
-msgid "Boards"
+msgid "Boards|An error occurred while fetching issues. Please reload the page."
msgstr ""
-msgid "Boards and Board Lists"
+msgid "Boards|An error occurred while fetching the board issues. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching the board swimlanes. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while moving the issue. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while updating the list. Please try again."
msgstr ""
msgid "Boards|Collapse"
@@ -4013,7 +4152,7 @@ msgstr ""
msgid "Branch %{branch_name} was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr ""
-msgid "Branch has changed"
+msgid "Branch changed"
msgstr ""
msgid "Branch is already taken"
@@ -4319,6 +4458,9 @@ msgstr ""
msgid "CLOSED (MOVED)"
msgstr ""
+msgid "CODEOWNERS rule violation"
+msgstr ""
+
msgid "CONTRIBUTING"
msgstr ""
@@ -4349,9 +4491,6 @@ msgstr ""
msgid "Can't create snippet: %{err}"
msgstr ""
-msgid "Can't edit as source branch was deleted"
-msgstr ""
-
msgid "Can't fetch content for the blob: %{err}"
msgstr ""
@@ -4364,9 +4503,6 @@ msgstr ""
msgid "Can't load mermaid module: %{err}"
msgstr ""
-msgid "Can't remove group members without group managed account"
-msgstr ""
-
msgid "Can't scan the code?"
msgstr ""
@@ -4409,6 +4545,9 @@ msgstr ""
msgid "Cannot create the abuse report. This user has been blocked."
msgstr ""
+msgid "Cannot enable shared runners because parent group does not allow it"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -4514,6 +4653,15 @@ msgstr ""
msgid "Change your password or recover your current one"
msgstr ""
+msgid "ChangeReviewer|Reviewer changed from %{old} to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Reviewer changed to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Unassigned"
+msgstr ""
+
msgid "ChangeTypeActionLabel|Pick into branch"
msgstr ""
@@ -4553,6 +4701,9 @@ msgstr ""
msgid "Changes the title to \"%{title_param}\"."
msgstr ""
+msgid "Changes were successfully made."
+msgstr ""
+
msgid "Changes won't take place until the index is %{link_start}recreated%{link_end}."
msgstr ""
@@ -4958,6 +5109,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove variable"
+msgstr ""
+
msgid "CiVariables|Remove variable row"
msgstr ""
@@ -5036,9 +5190,6 @@ msgstr ""
msgid "Clear due date"
msgstr ""
-msgid "Clear input"
-msgstr ""
-
msgid "Clear recent searches"
msgstr ""
@@ -5087,6 +5238,9 @@ msgstr ""
msgid "Client authentication key password"
msgstr ""
+msgid "Client request timeout"
+msgstr ""
+
msgid "Clients"
msgstr ""
@@ -5171,6 +5325,27 @@ msgstr ""
msgid "Cluster type must be specificed for Stages::ClusterEndpointInserter"
msgstr ""
+msgid "ClusterAgents|Configuration"
+msgstr ""
+
+msgid "ClusterAgents|Connect your cluster with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate Kubernetes with a GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Name"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Agent also requires %{linkStart}enabling the Agent Server%{linkEnd}"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Kubernetes Agent allows an Infrastructure as Code, GitOps approach to integrating Kubernetes clusters with GitLab. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "ClusterAgent|This feature is only available for premium plans"
msgstr ""
@@ -5240,10 +5415,10 @@ msgstr ""
msgid "ClusterIntegration|All installed applications and related resources"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster."
+msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{linkStart}More information%{linkEnd}"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{startLink}More information%{endLink}"
+msgid "ClusterIntegration|Allow GitLab to manage namespaces and service accounts for this cluster."
msgstr ""
msgid "ClusterIntegration|Alternatively, "
@@ -5264,6 +5439,9 @@ msgstr ""
msgid "ClusterIntegration|An error occurred while trying to fetch zone machine types: %{error}"
msgstr ""
+msgid "ClusterIntegration|An unknown error occurred while attempting to connect to Kubernetes."
+msgstr ""
+
msgid "ClusterIntegration|Any project namespaces"
msgstr ""
@@ -5279,6 +5457,9 @@ msgstr ""
msgid "ClusterIntegration|Authenticate with Amazon Web Services"
msgstr ""
+msgid "ClusterIntegration|Authentication Error"
+msgstr ""
+
msgid "ClusterIntegration|Base domain"
msgstr ""
@@ -5297,13 +5478,22 @@ msgstr ""
msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}security group %{externalLinkIcon} %{endLink} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
+msgid "ClusterIntegration|Check your CA certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Check your cluster status"
+msgstr ""
+
+msgid "ClusterIntegration|Check your token"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}subnets %{externalLinkIcon} %{endLink} in your VPC where your worker nodes will run."
+msgid "ClusterIntegration|Choose the %{linkStart}security group %{linkEnd} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
msgstr ""
-msgid "ClusterIntegration|Choose the worker node %{startLink}instance type %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Choose the %{linkStart}subnets %{linkEnd} in your VPC where your worker nodes will run."
+msgstr ""
+
+msgid "ClusterIntegration|Choose the worker node %{linkStart}instance type%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Choose which applications to install on your Kubernetes cluster."
@@ -5315,10 +5505,7 @@ msgstr ""
msgid "ClusterIntegration|Clear cluster cache"
msgstr ""
-msgid "ClusterIntegration|Clear the local cache of namespace and service accounts. This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
-msgstr ""
-
-msgid "ClusterIntegration|Cluster being created"
+msgid "ClusterIntegration|Clear the local cache of namespace and service accounts."
msgstr ""
msgid "ClusterIntegration|Cluster management project (alpha)"
@@ -5330,15 +5517,21 @@ msgstr ""
msgid "ClusterIntegration|Cluster_applications artifact too big. Maximum allowable size: %{human_size}"
msgstr ""
-msgid "ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters."
+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|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}"
+msgid "ClusterIntegration|Clusters connected with a certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Connect cluster with certificate"
msgstr ""
msgid "ClusterIntegration|Connect existing cluster"
msgstr ""
+msgid "ClusterIntegration|Connection Error"
+msgstr ""
+
msgid "ClusterIntegration|Copy API URL"
msgstr ""
@@ -5414,6 +5607,12 @@ msgstr ""
msgid "ClusterIntegration|Deletes all GitLab resources attached to this cluster during removal"
msgstr ""
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared."
+msgstr ""
+
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared. %{linkStart}More information%{linkEnd}"
+msgstr ""
+
msgid "ClusterIntegration|Did you know?"
msgstr ""
@@ -5483,6 +5682,9 @@ msgstr ""
msgid "ClusterIntegration|Fluentd is an open source data collector, which lets you unify the data collection and consumption for a better use and understanding of data. It requires at least one of the following logs to be successfully installed."
msgstr ""
+msgid "ClusterIntegration|GitLab Agent managed clusters"
+msgstr ""
+
msgid "ClusterIntegration|GitLab Container Network Policies"
msgstr ""
@@ -5495,6 +5697,12 @@ msgstr ""
msgid "ClusterIntegration|GitLab Runner connects to the repository and executes CI/CD jobs, pushing results back and deploying applications to production."
msgstr ""
+msgid "ClusterIntegration|GitLab failed to authenticate."
+msgstr ""
+
+msgid "ClusterIntegration|GitLab failed to connect to the cluster."
+msgstr ""
+
msgid "ClusterIntegration|GitLab-managed cluster"
msgstr ""
@@ -5516,6 +5724,9 @@ msgstr ""
msgid "ClusterIntegration|Group cluster"
msgstr ""
+msgid "ClusterIntegration|HTTP Error"
+msgstr ""
+
msgid "ClusterIntegration|Helm Tiller"
msgstr ""
@@ -5549,7 +5760,10 @@ msgstr ""
msgid "ClusterIntegration|Instance type"
msgstr ""
-msgid "ClusterIntegration|Integrate Kubernetes cluster automation"
+msgid "ClusterIntegration|Integrate Kubernetes with a cluster certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Integrate with a cluster certificate"
msgstr ""
msgid "ClusterIntegration|Issuer Email"
@@ -5585,9 +5799,6 @@ msgstr ""
msgid "ClusterIntegration|Knative extends Kubernetes to provide a set of middleware components that are essential to build modern, source-centric, and container-based applications that can run anywhere: on premises, in the cloud, or even in a third-party data center."
msgstr ""
-msgid "ClusterIntegration|Kubernetes cluster"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes cluster is being created..."
msgstr ""
@@ -5600,9 +5811,6 @@ msgstr ""
msgid "ClusterIntegration|Kubernetes clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr ""
-msgid "ClusterIntegration|Kubernetes clusters can be used to deploy applications and to provide Review Apps for this project"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes version"
msgstr ""
@@ -5615,7 +5823,7 @@ msgstr ""
msgid "ClusterIntegration|Learn more about %{help_link_start}zones%{help_link_end}."
msgstr ""
-msgid "ClusterIntegration|Learn more about %{startLink}Regions %{externalLinkIcon}%{endLink}."
+msgid "ClusterIntegration|Learn more about %{linkStart}Regions%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Learn more about Kubernetes"
@@ -5660,12 +5868,18 @@ msgstr ""
msgid "ClusterIntegration|Machine type"
msgstr ""
+msgid "ClusterIntegration|Make sure your API endpoint is correct"
+msgstr ""
+
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create Kubernetes clusters"
msgstr ""
msgid "ClusterIntegration|Manage your Kubernetes cluster by visiting %{provider_link}"
msgstr ""
+msgid "ClusterIntegration|Namespace per environment"
+msgstr ""
+
msgid "ClusterIntegration|No IAM Roles found"
msgstr ""
@@ -5711,6 +5925,9 @@ msgstr ""
msgid "ClusterIntegration|No zones matched your search"
msgstr ""
+msgid "ClusterIntegration|Node calculations use the Kubernetes Metrics API. Make sure your cluster has metrics installed"
+msgstr ""
+
msgid "ClusterIntegration|Number of nodes"
msgstr ""
@@ -5753,6 +5970,9 @@ msgstr ""
msgid "ClusterIntegration|RBAC-enabled cluster"
msgstr ""
+msgid "ClusterIntegration|Read our %{linkStart}help page%{linkEnd} on Kubernetes cluster integration."
+msgstr ""
+
msgid "ClusterIntegration|Read our %{link_start}help page%{link_end} on Kubernetes cluster integration."
msgstr ""
@@ -5855,7 +6075,7 @@ msgstr ""
msgid "ClusterIntegration|Select a VPC to choose a subnet"
msgstr ""
-msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{linkStart}Amazon Web Services %{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select a network to choose a subnetwork"
@@ -5888,7 +6108,7 @@ msgstr ""
msgid "ClusterIntegration|Select project to choose zone"
msgstr ""
-msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select zone"
@@ -5978,9 +6198,18 @@ msgstr ""
msgid "ClusterIntegration|There was a problem authenticating with your cluster. Please ensure your CA Certificate and Token are valid."
msgstr ""
+msgid "ClusterIntegration|There was an HTTP error when connecting to your cluster."
+msgstr ""
+
msgid "ClusterIntegration|This account must have permissions to create a Kubernetes cluster in the %{link_to_container_project} specified below"
msgstr ""
+msgid "ClusterIntegration|This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
+msgstr ""
+
+msgid "ClusterIntegration|This is necessary to clear existing environment-namespace associations from clusters previously managed by GitLab."
+msgstr ""
+
msgid "ClusterIntegration|This option will allow you to install applications on RBAC clusters."
msgstr ""
@@ -6005,9 +6234,21 @@ msgstr ""
msgid "ClusterIntegration|To use a new project, first create one on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}."
msgstr ""
+msgid "ClusterIntegration|Troubleshooting tips:"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Authenticate"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Connect"
+msgstr ""
+
msgid "ClusterIntegration|Uninstall %{appTitle}"
msgstr ""
+msgid "ClusterIntegration|Unknown Error"
+msgstr ""
+
msgid "ClusterIntegration|Update %{appTitle}"
msgstr ""
@@ -6068,7 +6309,7 @@ msgstr ""
msgid "ClusterIntegration|Your cluster API is unreachable. Please ensure your API URL is correct."
msgstr ""
-msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Zone"
@@ -6188,6 +6429,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse all threads"
+msgstr ""
+
msgid "Collapse approvers"
msgstr ""
@@ -6337,7 +6581,7 @@ msgstr ""
msgid "Commit…"
msgstr ""
-msgid "Company"
+msgid "Community forum"
msgstr ""
msgid "Company name"
@@ -6346,6 +6590,9 @@ msgstr ""
msgid "Compare"
msgstr ""
+msgid "Compare %{oldCommitId}...%{newCommitId}"
+msgstr ""
+
msgid "Compare Git revisions"
msgstr ""
@@ -6361,6 +6608,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare submodule commit revisions"
+msgstr ""
+
msgid "Compare with previous version"
msgstr ""
@@ -6496,6 +6746,9 @@ msgstr ""
msgid "Configure the way a user creates a new account."
msgstr ""
+msgid "Configure which lists are shown for anyone who visits this board"
+msgstr ""
+
msgid "Confirm"
msgstr ""
@@ -6721,6 +6974,9 @@ msgstr[1] ""
msgid "ContainerRegistry|Set cleanup policy"
msgstr ""
+msgid "ContainerRegistry|Some tags were not deleted"
+msgstr ""
+
msgid "ContainerRegistry|Something went wrong while fetching the cleanup policy."
msgstr ""
@@ -6760,6 +7016,9 @@ msgstr ""
msgid "ContainerRegistry|Tags with names matching this regex pattern will %{italicStart}expire:%{italicEnd}"
msgstr ""
+msgid "ContainerRegistry|The cleanup policy timed out before it could delete all tags. An administrator can %{adminLinkStart}manually run cleanup now%{adminLinkEnd} or you can wait for the cleanup policy to automatically run again. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "ContainerRegistry|The last tag related to this image was recently removed. This empty image and any associated data will be automatically removed as part of the regular Garbage Collection process. If you have any questions, contact your administrator."
msgstr ""
@@ -6892,6 +7151,9 @@ msgstr ""
msgid "Contributions per group member"
msgstr ""
+msgid "Contributor"
+msgstr ""
+
msgid "Contributors"
msgstr ""
@@ -7021,6 +7283,9 @@ msgstr ""
msgid "Could not change HEAD: branch '%{branch}' does not exist"
msgstr ""
+msgid "Could not commit. An unexpected error occurred."
+msgstr ""
+
msgid "Could not connect to FogBugz, check your URL"
msgstr ""
@@ -7060,6 +7325,9 @@ msgstr ""
msgid "Could not find iteration"
msgstr ""
+msgid "Could not load instance counts. Please refresh the page to try again."
+msgstr ""
+
msgid "Could not remove the trigger."
msgstr ""
@@ -7084,10 +7352,10 @@ msgstr ""
msgid "Could not save prometheus manual configuration"
msgstr ""
-msgid "Could not udpdate wiki page"
+msgid "Could not update the LDAP settings"
msgstr ""
-msgid "Could not update the LDAP settings"
+msgid "Could not update wiki page"
msgstr ""
msgid "Could not upload your designs as one or more files uploaded are not supported."
@@ -7745,6 +8013,9 @@ msgstr ""
msgid "DastProfiles|Are you sure you want to delete this profile?"
msgstr ""
+msgid "DastProfiles|Could not create site validation token. Please refresh the page, or try again later."
+msgstr ""
+
msgid "DastProfiles|Could not create the scanner profile. Please try again."
msgstr ""
@@ -7769,6 +8040,12 @@ msgstr ""
msgid "DastProfiles|Could not fetch site profiles. Please refresh the page, or try again later."
msgstr ""
+msgid "DastProfiles|Could not retrieve site validation status. Please refresh the page, or try again later."
+msgstr ""
+
+msgid "DastProfiles|Could not update the scanner profile. Please try again."
+msgstr ""
+
msgid "DastProfiles|Could not update the site profile. Please try again."
msgstr ""
@@ -7784,7 +8061,7 @@ msgstr ""
msgid "DastProfiles|Download validation text file"
msgstr ""
-msgid "DastProfiles|Edit feature will come soon. Please create a new profile if changes needed"
+msgid "DastProfiles|Edit scanner profile"
msgstr ""
msgid "DastProfiles|Edit site profile"
@@ -7817,6 +8094,9 @@ msgstr ""
msgid "DastProfiles|No profiles created yet"
msgstr ""
+msgid "DastProfiles|Passive"
+msgstr ""
+
msgid "DastProfiles|Please enter a valid URL format, ex: http://www.example.com/home"
msgstr ""
@@ -7832,6 +8112,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan mode"
+msgstr ""
+
msgid "DastProfiles|Scanner Profile"
msgstr ""
@@ -7871,10 +8154,10 @@ msgstr ""
msgid "DastProfiles|Text file validation"
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
+msgid "DastProfiles|The maximum number of minutes allowed for the spider to traverse the site."
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the spider to traverse the site."
+msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
msgstr ""
msgid "DastProfiles|Validate"
@@ -7907,6 +8190,9 @@ msgstr ""
msgid "Date picker"
msgstr ""
+msgid "Date range"
+msgstr ""
+
msgid "Date range cannot exceed %{maxDateRange} days."
msgstr ""
@@ -7931,6 +8217,9 @@ msgstr ""
msgid "Days to merge"
msgstr ""
+msgid "Dear Administrator,"
+msgstr ""
+
msgid "Debug"
msgstr ""
@@ -8042,12 +8331,18 @@ msgstr ""
msgid "Delete"
msgstr ""
+msgid "Delete %{name}"
+msgstr ""
+
msgid "Delete Comment"
msgstr ""
msgid "Delete Snippet"
msgstr ""
+msgid "Delete Value Stream"
+msgstr ""
+
msgid "Delete account"
msgstr ""
@@ -8069,9 +8364,6 @@ msgstr ""
msgid "Delete label: %{label_name} ?"
msgstr ""
-msgid "Delete license"
-msgstr ""
-
msgid "Delete list"
msgstr ""
@@ -8147,15 +8439,6 @@ msgstr ""
msgid "Deleting a project places it into a read-only state until %{date}, at which point the project will be permanently deleted. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "Deleting the license failed."
-msgstr ""
-
-msgid "Deleting the license failed. The license was not found."
-msgstr ""
-
-msgid "Deleting the license failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "Deleting the project will delete its repository and all related resources including issues, merge requests etc."
msgstr ""
@@ -8651,7 +8934,10 @@ msgstr ""
msgid "DesignManagement|The maximum number of designs allowed to be uploaded is %{upload_limit}. Please try again."
msgstr ""
-msgid "DesignManagement|To upload designs, you'll need to enable LFS. %{requirements_link_start}More information%{requirements_link_end}"
+msgid "DesignManagement|There was an error moving your designs. Please upload your designs below."
+msgstr ""
+
+msgid "DesignManagement|To upload designs, you'll need to enable LFS and have admin enable hashed storage. %{requirements_link_start}More information%{requirements_link_end}"
msgstr ""
msgid "DesignManagement|Unresolve thread"
@@ -8663,6 +8949,9 @@ msgstr ""
msgid "DesignManagement|Upload skipped."
msgstr ""
+msgid "DesignManagement|Your designs are being copied and are on their way… Please refresh to update."
+msgstr ""
+
msgid "DesignManagement|and %{moreCount} more."
msgstr ""
@@ -8720,6 +9009,9 @@ msgstr ""
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
+msgid "Direct member"
+msgstr ""
+
msgid "Direction"
msgstr ""
@@ -8768,9 +9060,6 @@ msgstr ""
msgid "Discard draft"
msgstr ""
-msgid "Discard review"
-msgstr ""
-
msgid "DiscordService|Discord Notifications"
msgstr ""
@@ -8839,10 +9128,10 @@ msgstr ""
msgid "Dismiss Merge Request promotion"
msgstr ""
-msgid "Dismiss Selected"
+msgid "Dismiss Value Stream Analytics introduction box"
msgstr ""
-msgid "Dismiss Value Stream Analytics introduction box"
+msgid "Dismiss selected"
msgstr ""
msgid "Dismiss trial promotion"
@@ -8893,9 +9182,6 @@ msgstr ""
msgid "Documents reindexed: %{processed_documents} (%{percentage}%%)"
msgstr ""
-msgid "Doing"
-msgstr ""
-
msgid "Domain"
msgstr ""
@@ -9091,9 +9377,6 @@ msgstr ""
msgid "Edit environment"
msgstr ""
-msgid "Edit file"
-msgstr ""
-
msgid "Edit files in the editor and commit changes here"
msgstr ""
@@ -9106,6 +9389,12 @@ msgstr ""
msgid "Edit identity for %{user_name}"
msgstr ""
+msgid "Edit in Web IDE"
+msgstr ""
+
+msgid "Edit in single-file editor"
+msgstr ""
+
msgid "Edit issues"
msgstr ""
@@ -9133,10 +9422,10 @@ msgstr ""
msgid "Editing"
msgstr ""
-msgid "Elasticsearch"
+msgid "Elasticsearch AWS IAM credentials"
msgstr ""
-msgid "Elasticsearch AWS IAM credentials"
+msgid "Elasticsearch HTTP client timeout value in seconds."
msgstr ""
msgid "Elasticsearch indexing restrictions"
@@ -9145,9 +9434,6 @@ msgstr ""
msgid "Elasticsearch indexing started"
msgstr ""
-msgid "Elasticsearch integration. Elasticsearch AWS IAM."
-msgstr ""
-
msgid "Elasticsearch reindexing is already in progress"
msgstr ""
@@ -9175,9 +9461,6 @@ msgstr ""
msgid "Email Notification"
msgstr ""
-msgid "Email address"
-msgstr ""
-
msgid "Email could not be sent"
msgstr ""
@@ -9241,6 +9524,9 @@ msgstr ""
msgid "Emails sent from Service Desk will have this name"
msgstr ""
+msgid "Emails sent to %{email} will still be supported"
+msgstr ""
+
msgid "Emails separated by comma"
msgstr ""
@@ -9274,9 +9560,18 @@ msgstr ""
msgid "Enable"
msgstr ""
+msgid "Enable %{link_start}Gitpod%{link_end} integration to launch a development environment in your browser directly from GitLab."
+msgstr ""
+
msgid "Enable Auto DevOps"
msgstr ""
+msgid "Enable Gitpod"
+msgstr ""
+
+msgid "Enable Gitpod?"
+msgstr ""
+
msgid "Enable HTML emails"
msgstr ""
@@ -9406,9 +9701,6 @@ msgstr ""
msgid "Encountered an error while rendering: %{err}"
msgstr ""
-msgid "End date"
-msgstr ""
-
msgid "Ends at (UTC)"
msgstr ""
@@ -9568,7 +9860,7 @@ msgstr ""
msgid "EnvironmentsDashboard|The environments dashboard provides a summary of each project's environments' status, including pipeline and alert statuses."
msgstr ""
-msgid "EnvironmentsDashboard|This dashboard displays a maximum of 7 projects and 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
+msgid "EnvironmentsDashboard|This dashboard displays 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
msgstr ""
msgid "Environments|An error occurred while canceling the auto stop, please try again"
@@ -9889,6 +10181,9 @@ msgstr ""
msgid "Error deleting project. Check logs for error details."
msgstr ""
+msgid "Error fetching burnup chart data"
+msgstr ""
+
msgid "Error fetching diverging counts for branches. Please try again."
msgstr ""
@@ -9967,6 +10262,9 @@ msgstr ""
msgid "Error occurred when saving assignees"
msgstr ""
+msgid "Error occurred when saving reviewers"
+msgstr ""
+
msgid "Error occurred when toggling the notification subscription"
msgstr ""
@@ -10219,10 +10517,13 @@ msgstr ""
msgid "Expand all"
msgstr ""
-msgid "Expand approvers"
+msgid "Expand all files"
msgstr ""
-msgid "Expand dropdown"
+msgid "Expand all threads"
+msgstr ""
+
+msgid "Expand approvers"
msgstr ""
msgid "Expand milestones"
@@ -10393,6 +10694,9 @@ msgstr ""
msgid "Failed to create Merge Request. Please try again."
msgstr ""
+msgid "Failed to create To-Do for the design."
+msgstr ""
+
msgid "Failed to create a branch for this issue. Please try again."
msgstr ""
@@ -10432,6 +10736,12 @@ msgstr ""
msgid "Failed to load authors. Please try again."
msgstr ""
+msgid "Failed to load branches. Please try again."
+msgstr ""
+
+msgid "Failed to load deploy keys."
+msgstr ""
+
msgid "Failed to load emoji list."
msgstr ""
@@ -10447,6 +10757,9 @@ msgstr ""
msgid "Failed to load groups & users."
msgstr ""
+msgid "Failed to load groups, users and deploy keys."
+msgstr ""
+
msgid "Failed to load labels. Please try again."
msgstr ""
@@ -10456,6 +10769,12 @@ msgstr ""
msgid "Failed to load related branches"
msgstr ""
+msgid "Failed to load sidebar confidential toggle"
+msgstr ""
+
+msgid "Failed to load sidebar lock status"
+msgstr ""
+
msgid "Failed to load stacktrace."
msgstr ""
@@ -10483,6 +10802,9 @@ msgstr ""
msgid "Failed to publish issue on status page."
msgstr ""
+msgid "Failed to remove To-Do for the design."
+msgstr ""
+
msgid "Failed to remove a Zoom meeting"
msgstr ""
@@ -10525,6 +10847,9 @@ msgstr ""
msgid "Failed to signing using smartcard authentication"
msgstr ""
+msgid "Failed to toggle To-Do for the design."
+msgstr ""
+
msgid "Failed to update branch!"
msgstr ""
@@ -10638,7 +10963,7 @@ msgstr ""
msgid "FeatureFlags|Edit User List"
msgstr ""
-msgid "FeatureFlags|Enable features for specific users and specific environments by defining feature flag strategies."
+msgid "FeatureFlags|Enable features for specific users and environments by configuring feature flag strategies."
msgstr ""
msgid "FeatureFlags|Environment Spec"
@@ -10698,7 +11023,7 @@ msgstr ""
msgid "FeatureFlags|Include additional user IDs"
msgstr ""
-msgid "FeatureFlags|Install a %{docs_link_anchored_start}compatible client library%{docs_link_anchored_end} and specify the API URL, application name, and instance ID during the configuration setup. %{docs_link_start}More Information%{docs_link_end}"
+msgid "FeatureFlags|Install a %{docsLinkAnchoredStart}compatible client library%{docsLinkAnchoredEnd} and specify the API URL, application name, and instance ID during the configuration setup. %{docsLinkStart}More Information%{docsLinkEnd}"
msgstr ""
msgid "FeatureFlags|Instance ID"
@@ -10710,6 +11035,9 @@ msgstr ""
msgid "FeatureFlags|Loading feature flags"
msgstr ""
+msgid "FeatureFlags|Loading user lists"
+msgstr ""
+
msgid "FeatureFlags|More information"
msgstr ""
@@ -10728,7 +11056,7 @@ msgstr ""
msgid "FeatureFlags|New feature flag"
msgstr ""
-msgid "FeatureFlags|New list"
+msgid "FeatureFlags|New user list"
msgstr ""
msgid "FeatureFlags|Percent of users"
@@ -10767,6 +11095,9 @@ msgstr ""
msgid "FeatureFlags|There was an error fetching the feature flags."
msgstr ""
+msgid "FeatureFlags|There was an error fetching the user lists."
+msgstr ""
+
msgid "FeatureFlags|There was an error retrieving user lists"
msgstr ""
@@ -10782,6 +11113,9 @@ msgstr ""
msgid "FeatureFlags|User List"
msgstr ""
+msgid "FeatureFlags|User Lists"
+msgstr ""
+
msgid "FeatureFlag|List"
msgstr ""
@@ -10809,15 +11143,6 @@ msgstr ""
msgid "Fetching incoming email"
msgstr ""
-msgid "Fetching licenses failed."
-msgstr ""
-
-msgid "Fetching licenses failed. The request endpoint was not found."
-msgstr ""
-
-msgid "Fetching licenses failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "File"
msgstr ""
@@ -10920,12 +11245,21 @@ msgstr ""
msgid "Filter by status"
msgstr ""
+msgid "Filter by test cases that are currently archived."
+msgstr ""
+
+msgid "Filter by test cases that are currently opened."
+msgstr ""
+
msgid "Filter by two-factor authentication"
msgstr ""
msgid "Filter by user"
msgstr ""
+msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
+msgstr ""
+
msgid "Filter pipelines"
msgstr ""
@@ -10941,7 +11275,7 @@ msgstr ""
msgid "Filter results..."
msgstr ""
-msgid "Filter your projects by name"
+msgid "Filter your repositories by name"
msgstr ""
msgid "Filter..."
@@ -10950,7 +11284,7 @@ msgstr ""
msgid "Find File"
msgstr ""
-msgid "Find bugs in your code with coverage-guided fuzzing"
+msgid "Find bugs in your code with coverage-guided fuzzing."
msgstr ""
msgid "Find by path"
@@ -10977,9 +11311,6 @@ msgstr ""
msgid "Finish editing this message first!"
msgstr ""
-msgid "Finish review"
-msgstr ""
-
msgid "Finish setting up your dedicated account for %{group_name}."
msgstr ""
@@ -11049,6 +11380,9 @@ msgstr ""
msgid "Footer message"
msgstr ""
+msgid "For a faster browsing experience, some files are collapsed by default."
+msgstr ""
+
msgid "For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
@@ -11058,6 +11392,9 @@ msgstr ""
msgid "For more info, read the documentation."
msgstr ""
+msgid "For more information on how the number of active users is calculated, see the %{self_managed_subscriptions_doc_link} documentation."
+msgstr ""
+
msgid "For more information, go to the "
msgstr ""
@@ -11196,6 +11533,9 @@ msgstr ""
msgid "Generate new token"
msgstr ""
+msgid "Generic package file size in bytes"
+msgstr ""
+
msgid "Geo"
msgstr ""
@@ -11457,6 +11797,9 @@ msgstr ""
msgid "Geo|Please refer to Geo Troubleshooting."
msgstr ""
+msgid "Geo|Primary node"
+msgstr ""
+
msgid "Geo|Project"
msgstr ""
@@ -11499,6 +11842,9 @@ msgstr ""
msgid "Geo|Review replication status, and resynchronize and reverify items with the primary node."
msgstr ""
+msgid "Geo|Secondary node"
+msgstr ""
+
msgid "Geo|Status"
msgstr ""
@@ -11538,6 +11884,9 @@ msgstr ""
msgid "Geo|URL must be a valid url (ex: https://gitlab.com)"
msgstr ""
+msgid "Geo|Undefined"
+msgstr ""
+
msgid "Geo|Unknown state"
msgstr ""
@@ -11613,10 +11962,16 @@ msgstr ""
msgid "GitHub import"
msgstr ""
+msgid "GitLab"
+msgstr ""
+
msgid "GitLab / Unsubscribe"
msgstr ""
-msgid "GitLab Enterprise Edition %{plan}"
+msgid "GitLab API"
+msgstr ""
+
+msgid "GitLab Billing Team."
msgstr ""
msgid "GitLab Group Runners can execute code for all the projects in this group."
@@ -11628,12 +11983,18 @@ msgstr ""
msgid "GitLab Issue"
msgstr ""
+msgid "GitLab Pages"
+msgstr ""
+
msgid "GitLab Service Desk is a simple way to allow people to create issues in your GitLab instance without needing their own user account. It provides a unique email address for end users to create issues in a project, and replies can be sent either through the GitLab interface or by email. End users will only see the thread through email."
msgstr ""
msgid "GitLab Shared Runners execute code of different projects on the same Runner unless you configure GitLab Runner Autoscale with MaxBuilds 1 (which it is on GitLab.com)."
msgstr ""
+msgid "GitLab Shell"
+msgstr ""
+
msgid "GitLab Support Bot"
msgstr ""
@@ -11643,7 +12004,7 @@ msgstr ""
msgid "GitLab User"
msgstr ""
-msgid "GitLab allows you to continue using your license even if you exceed the number of seats you purchased. You will be required to pay for these seats when you renew your license."
+msgid "GitLab Workhorse"
msgstr ""
msgid "GitLab commit"
@@ -11811,6 +12172,21 @@ msgstr ""
msgid "Gitlab Pages"
msgstr ""
+msgid "Gitpod"
+msgstr ""
+
+msgid "Gitpod|Add the URL to your Gitpod instance configured to read your GitLab projects."
+msgstr ""
+
+msgid "Gitpod|Enable Gitpod integration"
+msgstr ""
+
+msgid "Gitpod|Gitpod URL"
+msgstr ""
+
+msgid "Gitpod|e.g. https://gitpod.example.com"
+msgstr ""
+
msgid "Given access %{time_ago}"
msgstr ""
@@ -12318,9 +12694,6 @@ msgstr ""
msgid "GroupSAML|Valid SAML Response"
msgstr ""
-msgid "GroupSAML|With group managed accounts enabled, all the users without a group managed account will be excluded from the group."
-msgstr ""
-
msgid "GroupSAML|With prohibit outer forks flag enabled group members will be able to fork project only inside your group."
msgstr ""
@@ -12534,10 +12907,10 @@ msgstr ""
msgid "GroupsNew|Create group"
msgstr ""
-msgid "GroupsNew|GitLab group export"
+msgid "GroupsNew|Import"
msgstr ""
-msgid "GroupsNew|Import"
+msgid "GroupsNew|Import a GitLab group export file"
msgstr ""
msgid "GroupsNew|Import group"
@@ -12680,6 +13053,9 @@ msgid_plural "Hide charts"
msgstr[0] ""
msgstr[1] ""
+msgid "Hide comments on this file"
+msgstr ""
+
msgid "Hide details"
msgstr ""
@@ -12724,6 +13100,15 @@ msgstr ""
msgid "Highest role:"
msgstr ""
+msgid "HighlightBar|Alert events:"
+msgstr ""
+
+msgid "HighlightBar|Alert start time:"
+msgstr ""
+
+msgid "HighlightBar|Original alert:"
+msgstr ""
+
msgid "History"
msgstr ""
@@ -12901,6 +13286,9 @@ msgstr ""
msgid "If enabled, access to projects will be validated on an external service using their classification label."
msgstr ""
+msgid "If the number of active users exceeds the user limit, you will be charged for the number of %{users_over_license_link} at your next license reconciliation."
+msgstr ""
+
msgid "If there is no previous license or if the previous license has expired, some GitLab functionality will be blocked until a new, valid license is uploaded."
msgstr ""
@@ -12940,9 +13328,6 @@ msgstr ""
msgid "If your HTTP repository is not publicly accessible, add your credentials."
msgstr ""
-msgid "Iglu registry URL (optional)"
-msgstr ""
-
msgid "Ignore"
msgstr ""
@@ -12979,6 +13364,16 @@ msgstr ""
msgid "Import"
msgstr ""
+msgid "Import %d compatible repository"
+msgid_plural "Import %d compatible repositories"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Import %d repository"
+msgid_plural "Import %d repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Import CSV"
msgstr ""
@@ -12988,15 +13383,9 @@ msgstr ""
msgid "Import all compatible projects"
msgstr ""
-msgid "Import all compatible repositories"
-msgstr ""
-
msgid "Import all projects"
msgstr ""
-msgid "Import all repositories"
-msgstr ""
-
msgid "Import an exported GitLab project"
msgstr ""
@@ -13084,6 +13473,9 @@ msgstr ""
msgid "ImportProjects|Error importing repository %{project_safe_import_url} into %{project_full_path} - %{message}"
msgstr ""
+msgid "ImportProjects|Import repositories"
+msgstr ""
+
msgid "ImportProjects|Importing the project failed"
msgstr ""
@@ -13096,7 +13488,7 @@ msgstr ""
msgid "ImportProjects|Requesting your %{provider} repositories failed"
msgstr ""
-msgid "ImportProjects|Select the projects you want to import"
+msgid "ImportProjects|Select the repositories you want to import"
msgstr ""
msgid "ImportProjects|The remote data could not be imported."
@@ -13132,9 +13524,6 @@ msgstr ""
msgid "In order to enable Service Desk for your instance, you must first set up incoming email."
msgstr ""
-msgid "In order to gather accurate feature usage data, it can take 1 to 2 weeks to see your index."
-msgstr ""
-
msgid "In order to personalize your experience with GitLab%{br_tag}we would like to know a bit more about you."
msgstr ""
@@ -13165,18 +13554,30 @@ msgstr ""
msgid "IncidentManagement|Create incident"
msgstr ""
+msgid "IncidentManagement|Critical - S1"
+msgstr ""
+
msgid "IncidentManagement|Date created"
msgstr ""
msgid "IncidentManagement|Display your incidents in a dedicated view"
msgstr ""
+msgid "IncidentManagement|High - S2"
+msgstr ""
+
msgid "IncidentManagement|Incident"
msgstr ""
msgid "IncidentManagement|Incidents"
msgstr ""
+msgid "IncidentManagement|Low - S4"
+msgstr ""
+
+msgid "IncidentManagement|Medium - S3"
+msgstr ""
+
msgid "IncidentManagement|No incidents to display."
msgstr ""
@@ -13189,6 +13590,9 @@ msgstr ""
msgid "IncidentManagement|Published to status page"
msgstr ""
+msgid "IncidentManagement|Severity"
+msgstr ""
+
msgid "IncidentManagement|There are no closed incidents"
msgstr ""
@@ -13198,6 +13602,9 @@ msgstr ""
msgid "IncidentManagement|Unassigned"
msgstr ""
+msgid "IncidentManagement|Unknown"
+msgstr ""
+
msgid "IncidentManagement|Unpublished"
msgstr ""
@@ -13219,6 +13626,15 @@ msgstr ""
msgid "Incidents"
msgstr ""
+msgid "Incident|Alert details"
+msgstr ""
+
+msgid "Incident|Summary"
+msgstr ""
+
+msgid "Incident|There was an issue loading alert data. Please try again."
+msgstr ""
+
msgid "Include a Terms of Service agreement and Privacy Policy that all users must accept."
msgstr ""
@@ -13279,6 +13695,9 @@ msgstr ""
msgid "Information about additional Pages templates and how to install them can be found in our %{pages_getting_started_guide}."
msgstr ""
+msgid "Inherited"
+msgstr ""
+
msgid "Inherited:"
msgstr ""
@@ -13359,7 +13778,22 @@ msgstr ""
msgid "Instance administrators group already exists"
msgstr ""
-msgid "Instance license"
+msgid "InstanceStatistics|Groups"
+msgstr ""
+
+msgid "InstanceStatistics|Issues"
+msgstr ""
+
+msgid "InstanceStatistics|Merge Requests"
+msgstr ""
+
+msgid "InstanceStatistics|Pipelines"
+msgstr ""
+
+msgid "InstanceStatistics|Projects"
+msgstr ""
+
+msgid "InstanceStatistics|Users"
msgstr ""
msgid "Integration"
@@ -13371,6 +13805,12 @@ msgstr ""
msgid "Integrations"
msgstr ""
+msgid "Integrations|%{integration} settings saved and active."
+msgstr ""
+
+msgid "Integrations|%{integration} settings saved, but not active."
+msgstr ""
+
msgid "Integrations|All details"
msgstr ""
@@ -13380,6 +13820,12 @@ msgstr ""
msgid "Integrations|Comment settings:"
msgstr ""
+msgid "Integrations|Connection failed. Please check your settings."
+msgstr ""
+
+msgid "Integrations|Connection successful."
+msgstr ""
+
msgid "Integrations|Default settings are inherited from the group level."
msgstr ""
@@ -13395,6 +13841,15 @@ msgstr ""
msgid "Integrations|Includes commit title and branch"
msgstr ""
+msgid "Integrations|Projects using custom settings will not be impacted unless the project owner chooses to use instance-level defaults."
+msgstr ""
+
+msgid "Integrations|Save settings?"
+msgstr ""
+
+msgid "Integrations|Saving will update the default settings for all projects that are not using custom settings."
+msgstr ""
+
msgid "Integrations|Standard"
msgstr ""
@@ -13527,6 +13982,9 @@ msgstr ""
msgid "Invitation"
msgstr ""
+msgid "Invitation declined"
+msgstr ""
+
msgid "Invite"
msgstr ""
@@ -13578,6 +14036,42 @@ 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|%{linkStart}Read more%{linkEnd} about role permissions"
+msgstr ""
+
+msgid "InviteMembersModal|Access expiration date (optional)"
+msgstr ""
+
+msgid "InviteMembersModal|Cancel"
+msgstr ""
+
+msgid "InviteMembersModal|Choose a role permission"
+msgstr ""
+
+msgid "InviteMembersModal|GitLab member or Email address"
+msgstr ""
+
+msgid "InviteMembersModal|Invite"
+msgstr ""
+
+msgid "InviteMembersModal|Invite team members"
+msgstr ""
+
+msgid "InviteMembersModal|Search for members to invite"
+msgstr ""
+
+msgid "InviteMembersModal|User not invited. Feature coming soon!"
+msgstr ""
+
+msgid "InviteMembersModal|Users were succesfully added"
+msgstr ""
+
+msgid "InviteMembersModal|You're inviting members to the %{group_name} group"
+msgstr ""
+
+msgid "InviteMembers|Invite team members"
+msgstr ""
+
msgid "Invited"
msgstr ""
@@ -13632,10 +14126,13 @@ msgstr ""
msgid "Issue cannot be found."
msgstr ""
+msgid "Issue created from vulnerability %{vulnerability_link}"
+msgstr ""
+
msgid "Issue events"
msgstr ""
-msgid "Issue first depoloyed to production"
+msgid "Issue first deployed to production"
msgstr ""
msgid "Issue label"
@@ -13713,6 +14210,9 @@ msgstr ""
msgid "IssueTracker|Custom issue tracker"
msgstr ""
+msgid "IssueTracker|EWM work items tracker"
+msgstr ""
+
msgid "IssueTracker|Redmine issue tracker"
msgstr ""
@@ -13779,6 +14279,9 @@ msgstr ""
msgid "It looks like you have some draft commits in this branch."
msgstr ""
+msgid "It may be several days before you see feature usage data."
+msgstr ""
+
msgid "It must have a header row and at least two columns: the first column is the issue title and the second column is the issue description. The separator is automatically detected."
msgstr ""
@@ -14061,13 +14564,13 @@ msgstr ""
msgid "Join Zoom meeting"
msgstr ""
-msgid "Jul"
+msgid "Joined %{time_ago}"
msgstr ""
-msgid "July"
+msgid "Jul"
msgstr ""
-msgid "Jump to first unresolved thread"
+msgid "July"
msgstr ""
msgid "Jump to next unresolved thread"
@@ -14103,6 +14606,9 @@ msgstr ""
msgid "Keyboard shortcuts"
msgstr ""
+msgid "KeyboardKey|Ctrl+"
+msgstr ""
+
msgid "Keys"
msgstr ""
@@ -14151,6 +14657,9 @@ msgstr ""
msgid "LDAP Synchronization"
msgstr ""
+msgid "LDAP group settings"
+msgstr ""
+
msgid "LDAP settings"
msgstr ""
@@ -14160,6 +14669,9 @@ msgstr ""
msgid "LDAP sync in progress. This could take a few minutes. Refresh the page to see the changes."
msgstr ""
+msgid "LDAP synchronizations"
+msgstr ""
+
msgid "LFS"
msgstr ""
@@ -14240,7 +14752,16 @@ msgid_plural "Last %d days"
msgstr[0] ""
msgstr[1] ""
-msgid "Last %{days} days"
+msgid "Last 2 weeks"
+msgstr ""
+
+msgid "Last 30 days"
+msgstr ""
+
+msgid "Last 60 days"
+msgstr ""
+
+msgid "Last 90 days"
msgstr ""
msgid "Last Accessed On"
@@ -14318,6 +14839,9 @@ msgstr ""
msgid "Last used on:"
msgstr ""
+msgid "Last week"
+msgstr ""
+
msgid "LastCommit|authored"
msgstr ""
@@ -14333,6 +14857,9 @@ msgstr ""
msgid "Latest pipeline for the most recent commit on this branch"
msgstr ""
+msgid "Launch a ready-to-code development environment for your project."
+msgstr ""
+
msgid "Lead"
msgstr ""
@@ -14713,6 +15240,9 @@ msgstr ""
msgid "List of all merge commits"
msgstr ""
+msgid "List options"
+msgstr ""
+
msgid "List settings"
msgstr ""
@@ -14725,9 +15255,6 @@ msgstr ""
msgid "List your Bitbucket Server repositories"
msgstr ""
-msgid "Lists"
-msgstr ""
-
msgid "Live preview"
msgstr ""
@@ -14974,6 +15501,12 @@ msgstr ""
msgid "Mark as done"
msgstr ""
+msgid "Mark as draft"
+msgstr ""
+
+msgid "Mark as ready"
+msgstr ""
+
msgid "Mark as resolved"
msgstr ""
@@ -14995,6 +15528,24 @@ msgstr ""
msgid "Markdown is supported"
msgstr ""
+msgid "MarkdownEditor|Add a link (%{modifierKey}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add a link (%{modifier_key}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifierKey}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifier_key}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifierKey}I)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifier_key}I)"
+msgstr ""
+
msgid "Marked For Deletion At - %{deletion_time}"
msgstr ""
@@ -15079,7 +15630,25 @@ msgstr ""
msgid "Max access level"
msgstr ""
-msgid "Max seats used"
+msgid "Max role"
+msgstr ""
+
+msgid "Max size 15 MB"
+msgstr ""
+
+msgid "Maximum Conan package file size in bytes"
+msgstr ""
+
+msgid "Maximum Maven package file size in bytes"
+msgstr ""
+
+msgid "Maximum NPM package file size in bytes"
+msgstr ""
+
+msgid "Maximum NuGet package file size in bytes"
+msgstr ""
+
+msgid "Maximum PyPI package file size in bytes"
msgstr ""
msgid "Maximum Users:"
@@ -15211,6 +15780,18 @@ msgstr ""
msgid "Members with access to %{strong_start}%{group_name}%{strong_end}"
msgstr ""
+msgid "Members|%{time} by %{user}"
+msgstr ""
+
+msgid "Members|Expired"
+msgstr ""
+
+msgid "Members|No expiration set"
+msgstr ""
+
+msgid "Members|in %{time}"
+msgstr ""
+
msgid "Memory Usage"
msgstr ""
@@ -15397,9 +15978,6 @@ msgstr ""
msgid "MergeRequests|Thread will be unresolved"
msgstr ""
-msgid "MergeRequests|Toggle comments for this file"
-msgstr ""
-
msgid "MergeRequests|View file @ %{commitId}"
msgstr ""
@@ -15460,6 +16038,9 @@ msgstr ""
msgid "Merging immediately isn't recommended as it may negatively impact the existing merge train. Read the %{docsLinkStart}documentation%{docsLinkEnd} for more information."
msgstr ""
+msgid "Message"
+msgstr ""
+
msgid "Messages"
msgstr ""
@@ -15845,18 +16426,12 @@ msgid_plural "Milestones"
msgstr[0] ""
msgstr[1] ""
-msgid "Milestone does not support burnup charts"
-msgstr ""
-
msgid "Milestone lists not available with your current license"
msgstr ""
msgid "Milestone lists show all issues from the selected milestone."
msgstr ""
-msgid "Milestone must have a start and due date"
-msgstr ""
-
msgid "MilestoneSidebar|Closed:"
msgstr ""
@@ -16223,6 +16798,9 @@ msgstr ""
msgid "Namespace"
msgstr ""
+msgid "Namespace ID:"
+msgstr ""
+
msgid "Namespace is empty"
msgstr ""
@@ -16307,6 +16885,9 @@ msgstr ""
msgid "NetworkPolicies|Allow all outbound traffic from %{selector} to %{ruleSelector} on %{ports}"
msgstr ""
+msgid "NetworkPolicies|Are you sure you want to delete this policy? This action cannot be undone."
+msgstr ""
+
msgid "NetworkPolicies|Choose whether to enforce this policy."
msgstr ""
@@ -16316,12 +16897,21 @@ msgstr ""
msgid "NetworkPolicies|Define this policy's location, conditions and actions."
msgstr ""
+msgid "NetworkPolicies|Delete policy"
+msgstr ""
+
+msgid "NetworkPolicies|Delete policy: %{policy}"
+msgstr ""
+
msgid "NetworkPolicies|Deny all traffic"
msgstr ""
msgid "NetworkPolicies|Description"
msgstr ""
+msgid "NetworkPolicies|Edit policy"
+msgstr ""
+
msgid "NetworkPolicies|Editor mode"
msgstr ""
@@ -16349,6 +16939,9 @@ msgstr ""
msgid "NetworkPolicies|Name"
msgstr ""
+msgid "NetworkPolicies|Namespace"
+msgstr ""
+
msgid "NetworkPolicies|Network Policy"
msgstr ""
@@ -16400,6 +16993,9 @@ msgstr ""
msgid "NetworkPolicies|Rules"
msgstr ""
+msgid "NetworkPolicies|Save changes"
+msgstr ""
+
msgid "NetworkPolicies|Something went wrong, failed to update policy"
msgstr ""
@@ -16412,6 +17008,9 @@ msgstr ""
msgid "NetworkPolicies|Traffic that does not match any rule will be blocked."
msgstr ""
+msgid "NetworkPolicies|Unable to parse policy"
+msgstr ""
+
msgid "NetworkPolicies|YAML editor"
msgstr ""
@@ -16525,6 +17124,9 @@ msgstr ""
msgid "New Snippet"
msgstr ""
+msgid "New Test Case"
+msgstr ""
+
msgid "New User"
msgstr ""
@@ -16624,6 +17226,9 @@ msgstr ""
msgid "New tag"
msgstr ""
+msgid "New test case"
+msgstr ""
+
msgid "New users set to external"
msgstr ""
@@ -16696,7 +17301,7 @@ msgstr ""
msgid "No changes"
msgstr ""
-msgid "No changes between %{ref_start}%{source_branch}%{ref_end} and %{ref_start}%{target_branch}%{ref_end}"
+msgid "No changes between %{sourceBranch} and %{targetBranch}"
msgstr ""
msgid "No child epics match applied filters"
@@ -16711,6 +17316,9 @@ msgstr ""
msgid "No containers available"
msgstr ""
+msgid "No content to show"
+msgstr ""
+
msgid "No contributions"
msgstr ""
@@ -16786,9 +17394,6 @@ msgstr ""
msgid "No license. All rights reserved"
msgstr ""
-msgid "No licenses found."
-msgstr ""
-
msgid "No matches found"
msgstr ""
@@ -16801,6 +17406,9 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No members found"
+msgstr ""
+
msgid "No merge requests found"
msgstr ""
@@ -16822,6 +17430,9 @@ msgstr ""
msgid "No parent group"
msgstr ""
+msgid "No plan"
+msgstr ""
+
msgid "No pods available"
msgstr ""
@@ -16918,6 +17529,12 @@ msgstr ""
msgid "Not Implemented"
msgstr ""
+msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+msgstr ""
+
+msgid "Not all browsers support WebAuthn. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even from an unsupported browser."
+msgstr ""
+
msgid "Not all data has been processed yet, the accuracy of the chart for the selected timeframe is limited."
msgstr ""
@@ -17014,6 +17631,9 @@ msgstr ""
msgid "Notification settings saved"
msgstr ""
+msgid "NotificationEvent|Change reviewer merge request"
+msgstr ""
+
msgid "NotificationEvent|Close issue"
msgstr ""
@@ -17176,10 +17796,7 @@ msgstr ""
msgid "On track"
msgstr ""
-msgid "OnDemandScans|Attached branch"
-msgstr ""
-
-msgid "OnDemandScans|Attached branch is where the scan job runs."
+msgid "OnDemandScans|Could not fetch scanner profiles. Please refresh the page, or try again later."
msgstr ""
msgid "OnDemandScans|Could not fetch site profiles. Please refresh the page, or try again later."
@@ -17188,6 +17805,9 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
+msgid "OnDemandScans|Create a new scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Create a new site profile"
msgstr ""
@@ -17200,6 +17820,9 @@ msgstr ""
msgid "OnDemandScans|New on-demand DAST scan"
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 ""
@@ -17209,16 +17832,10 @@ msgstr ""
msgid "OnDemandScans|On-demand scans run outside the DevOps cycle and find vulnerabilities in your projects. %{learnMoreLinkStart}Learn more%{learnMoreLinkEnd}"
msgstr ""
-msgid "OnDemandScans|Only a passive scan can be performed on demand."
-msgstr ""
-
-msgid "OnDemandScans|Passive"
-msgstr ""
-
msgid "OnDemandScans|Run scan"
msgstr ""
-msgid "OnDemandScans|Scan mode"
+msgid "OnDemandScans|Scanner profile"
msgstr ""
msgid "OnDemandScans|Scanner settings"
@@ -17230,9 +17847,15 @@ msgstr ""
msgid "OnDemandScans|Select one of the existing profiles"
msgstr ""
+msgid "OnDemandScans|Site profile"
+msgstr ""
+
msgid "OnDemandScans|Site profiles"
msgstr ""
+msgid "OnDemandScans|Use existing scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Use existing site profile"
msgstr ""
@@ -17331,9 +17954,6 @@ msgstr ""
msgid "Open Selection"
msgstr ""
-msgid "Open Web IDE"
-msgstr ""
-
msgid "Open comment type dropdown"
msgstr ""
@@ -17439,6 +18059,9 @@ msgstr ""
msgid "Origin"
msgstr ""
+msgid "Orphaned member"
+msgstr ""
+
msgid "Other Labels"
msgstr ""
@@ -17454,6 +18077,9 @@ msgstr ""
msgid "Other visibility settings have been disabled by the administrator."
msgstr ""
+msgid "Our documentation includes an example DevOps Score report."
+msgstr ""
+
msgid "Out-of-compliance with this project's policies and should be removed"
msgstr ""
@@ -17478,6 +18104,9 @@ msgstr ""
msgid "Overwrite diverged branches"
msgstr ""
+msgid "Owned by %{image_tag}"
+msgstr ""
+
msgid "Owned by anyone"
msgstr ""
@@ -17499,6 +18128,9 @@ msgstr ""
msgid "Package deleted successfully"
msgstr ""
+msgid "Package file size limits"
+msgstr ""
+
msgid "Package recipe already exists"
msgstr ""
@@ -17514,9 +18146,6 @@ msgstr ""
msgid "Package type must be PyPi"
msgstr ""
-msgid "Package was removed"
-msgstr ""
-
msgid "PackageRegistry|%{name} version %{version} was created %{datetime}"
msgstr ""
@@ -17658,12 +18287,18 @@ msgstr ""
msgid "PackageRegistry|NuGet Command"
msgstr ""
+msgid "PackageRegistry|Package Registry"
+msgstr ""
+
msgid "PackageRegistry|Pip Command"
msgstr ""
msgid "PackageRegistry|Pipeline %{link} triggered %{datetime} by %{author}"
msgstr ""
+msgid "PackageRegistry|Publish and share packages for a variety of common package managers. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "PackageRegistry|Published to the %{project} Package Registry %{datetime}"
msgstr ""
@@ -17763,6 +18398,9 @@ msgstr ""
msgid "Page not found"
msgstr ""
+msgid "Page settings"
+msgstr ""
+
msgid "Page was successfully deleted"
msgstr ""
@@ -17904,7 +18542,7 @@ msgstr ""
msgid "Paste issue link"
msgstr ""
-msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Don't use your private SSH key."
+msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Do not paste your private SSH key, as that can compromise your identity."
msgstr ""
msgid "Patch to apply"
@@ -17931,6 +18569,9 @@ msgstr ""
msgid "Pending"
msgstr ""
+msgid "Pending comments"
+msgstr ""
+
msgid "People without permission will never get a notification and won't be able to comment."
msgstr ""
@@ -18129,6 +18770,9 @@ msgstr ""
msgid "Pipelines|Build with confidence"
msgstr ""
+msgid "Pipelines|By revoking a trigger you will break any processes making use of it. Are you sure?"
+msgstr ""
+
msgid "Pipelines|CI Lint"
msgstr ""
@@ -18141,6 +18785,15 @@ msgstr ""
msgid "Pipelines|Continuous Integration can help catch bugs by running your tests automatically, while Continuous Deployment can help you deliver code to your product environment."
msgstr ""
+msgid "Pipelines|Copy trigger token"
+msgstr ""
+
+msgid "Pipelines|Description"
+msgstr ""
+
+msgid "Pipelines|Edit"
+msgstr ""
+
msgid "Pipelines|Get started with Pipelines"
msgstr ""
@@ -18156,15 +18809,27 @@ msgstr ""
msgid "Pipelines|It is recommended the code is reviewed thoroughly before running this pipeline with the parent project's CI resource."
msgstr ""
+msgid "Pipelines|Last Used"
+msgstr ""
+
msgid "Pipelines|Loading Pipelines"
msgstr ""
msgid "Pipelines|More Information"
msgstr ""
+msgid "Pipelines|No triggers have been created yet. Add one using the form above."
+msgstr ""
+
+msgid "Pipelines|Owner"
+msgstr ""
+
msgid "Pipelines|Project cache successfully reset."
msgstr ""
+msgid "Pipelines|Revoke"
+msgstr ""
+
msgid "Pipelines|Run Pipeline"
msgstr ""
@@ -18189,6 +18854,15 @@ msgstr ""
msgid "Pipelines|This project is not currently set up to run pipelines."
msgstr ""
+msgid "Pipelines|Token"
+msgstr ""
+
+msgid "Pipelines|Trigger user has insufficient permissions to project"
+msgstr ""
+
+msgid "Pipelines|invalid"
+msgstr ""
+
msgid "Pipelines|parent"
msgstr ""
@@ -18447,10 +19121,10 @@ msgstr ""
msgid "Please provide attributes to update"
msgstr ""
-msgid "Please refer to %{docs_url}"
+msgid "Please reach out if you have any questions and we'll be happy to assist."
msgstr ""
-msgid "Please retype the email address."
+msgid "Please refer to %{docs_url}"
msgstr ""
msgid "Please select"
@@ -18480,6 +19154,9 @@ msgstr ""
msgid "Please set a new password before proceeding."
msgstr ""
+msgid "Please share your feedback about %{featureName} %{linkStart}in this issue%{linkEnd} to help us improve the experience."
+msgstr ""
+
msgid "Please solve the reCAPTCHA"
msgstr ""
@@ -18783,6 +19460,9 @@ msgstr ""
msgid "Profiles| You are going to change the username %{currentUsernameBold} to %{newUsernameBold}. Profile and projects will be redirected to the %{newUsername} namespace but this redirect will expire once the %{currentUsername} namespace is registered by another user or group. Please update your Git repository remotes as soon as possible."
msgstr ""
+msgid "Profiles|%{provider} Active"
+msgstr ""
+
msgid "Profiles|@username"
msgstr ""
@@ -18834,7 +19514,7 @@ msgstr ""
msgid "Profiles|Commit email"
msgstr ""
-msgid "Profiles|Connect"
+msgid "Profiles|Connect %{provider}"
msgstr ""
msgid "Profiles|Connected Accounts"
@@ -18858,6 +19538,9 @@ msgstr ""
msgid "Profiles|Disconnect"
msgstr ""
+msgid "Profiles|Disconnect %{provider}"
+msgstr ""
+
msgid "Profiles|Do not show on profile"
msgstr ""
@@ -18882,7 +19565,7 @@ msgstr ""
msgid "Profiles|Full name"
msgstr ""
-msgid "Profiles|Give your individual key a title. This will be publically visible."
+msgid "Profiles|Give your individual key a title."
msgstr ""
msgid "Profiles|Include private contributions on my profile"
@@ -18972,7 +19655,7 @@ msgstr ""
msgid "Profiles|The maximum file size allowed is 200KB."
msgstr ""
-msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it?"
+msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it? It will be publicly visible."
msgstr ""
msgid "Profiles|This email will be displayed on your public profile"
@@ -19047,6 +19730,9 @@ msgstr ""
msgid "Profiles|You don't have access to delete this user."
msgstr ""
+msgid "Profiles|You must transfer ownership or delete groups you are an owner of before you can delete your account"
+msgstr ""
+
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
@@ -19635,6 +20321,9 @@ msgstr ""
msgid "ProjectTemplates|GitLab Cluster Management"
msgstr ""
+msgid "ProjectTemplates|Gitpod/Spring Petclinic"
+msgstr ""
+
msgid "ProjectTemplates|Go Micro"
msgstr ""
@@ -20244,6 +20933,9 @@ msgstr ""
msgid "Publish to status page"
msgstr ""
+msgid "Published"
+msgstr ""
+
msgid "Published on status page"
msgstr ""
@@ -20361,9 +21053,15 @@ msgstr ""
msgid "Quick range"
msgstr ""
+msgid "Quickly and easily edit multiple files in your project."
+msgstr ""
+
msgid "README"
msgstr ""
+msgid "Rails"
+msgstr ""
+
msgid "Rake Tasks Help"
msgstr ""
@@ -20483,10 +21181,13 @@ msgstr ""
msgid "Register Two-Factor Authenticator"
msgstr ""
-msgid "Register U2F device"
+msgid "Register Universal Two-Factor (U2F) Device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register WebAuthn Device"
+msgstr ""
+
+msgid "Register device"
msgstr ""
msgid "Register for GitLab"
@@ -20498,9 +21199,6 @@ msgstr ""
msgid "Register with two-factor app"
msgstr ""
-msgid "Registration"
-msgstr ""
-
msgid "Registration|Checkout"
msgstr ""
@@ -20617,9 +21315,6 @@ msgstr ""
msgid "Release|Something went wrong while saving the release details"
msgstr ""
-msgid "Remediated: needs review"
-msgstr ""
-
msgid "Remediations"
msgstr ""
@@ -20725,6 +21420,9 @@ msgstr ""
msgid "Remove priority"
msgstr ""
+msgid "Remove report"
+msgstr ""
+
msgid "Remove secondary node"
msgstr ""
@@ -20737,6 +21435,12 @@ msgstr ""
msgid "Remove time estimate"
msgstr ""
+msgid "Remove user & report"
+msgstr ""
+
+msgid "Remove user from group"
+msgstr ""
+
msgid "Removed"
msgstr ""
@@ -20818,9 +21522,6 @@ msgstr ""
msgid "Removes time estimate."
msgstr ""
-msgid "Removing license…"
-msgstr ""
-
msgid "Removing this group also removes all child projects, including archived projects, and their resources."
msgstr ""
@@ -20905,6 +21606,9 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
+msgid "Reported by %{reporter}"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -20991,6 +21695,27 @@ msgstr ""
msgid "Repositories"
msgstr ""
+msgid "Repositories Analytics"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download Historic Test Coverage Data"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download historic test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Historic Test Coverage Data is available in raw format (.csv) for further analysis."
+msgstr ""
+
+msgid "RepositoriesAnalytics|Test Code Coverage"
+msgstr ""
+
+msgid "RepositoriesAnalytics|There was an error fetching the projects."
+msgstr ""
+
msgid "Repository"
msgstr ""
@@ -21069,9 +21794,15 @@ msgstr ""
msgid "Request parameter %{param} is missing."
msgstr ""
+msgid "Request review from"
+msgstr ""
+
msgid "Request to link SAML account must be authorized"
msgstr ""
+msgid "Requested"
+msgstr ""
+
msgid "Requested %{time_ago}"
msgstr ""
@@ -21090,6 +21821,9 @@ msgstr ""
msgid "Requests to these domain(s)/address(es) on the local network will be allowed when local requests from hooks and services are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 or 127.0.0.0/28 are supported. Domain wildcards are not supported currently. Use comma, semicolon, or newline to separate multiple entries. The allowlist can hold a maximum of 1000 entries. Domains should use IDNA encoding. Ex: example.com, 192.168.1.1, 127.0.0.0/28, xn--itlab-j1a.com."
msgstr ""
+msgid "Require admin approval for new sign-ups"
+msgstr ""
+
msgid "Require all users in this group to setup Two-factor authentication"
msgstr ""
@@ -21217,9 +21951,6 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
-msgid "Resolved by %{resolvedByName}"
-msgstr ""
-
msgid "Resolves IP addresses once and uses them to submit requests"
msgstr ""
@@ -21339,6 +22070,14 @@ msgstr ""
msgid "ReviewApp|Enable Review App"
msgstr ""
+msgid "Reviewer"
+msgid_plural "%d Reviewers"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "Reviewer(s)"
+msgstr ""
+
msgid "Reviewing"
msgstr ""
@@ -21378,6 +22117,9 @@ msgstr ""
msgid "Rook"
msgstr ""
+msgid "Ruby"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -21456,6 +22198,63 @@ msgstr ""
msgid "Runners page."
msgstr ""
+msgid "Runners|Active"
+msgstr ""
+
+msgid "Runners|Architecture"
+msgstr ""
+
+msgid "Runners|Can run untagged jobs"
+msgstr ""
+
+msgid "Runners|Description"
+msgstr ""
+
+msgid "Runners|Group"
+msgstr ""
+
+msgid "Runners|IP Address"
+msgstr ""
+
+msgid "Runners|Last contact"
+msgstr ""
+
+msgid "Runners|Locked to this project"
+msgstr ""
+
+msgid "Runners|Maximum job timeout"
+msgstr ""
+
+msgid "Runners|Name"
+msgstr ""
+
+msgid "Runners|Platform"
+msgstr ""
+
+msgid "Runners|Property Name"
+msgstr ""
+
+msgid "Runners|Protected"
+msgstr ""
+
+msgid "Runners|Revision"
+msgstr ""
+
+msgid "Runners|Shared"
+msgstr ""
+
+msgid "Runners|Specific"
+msgstr ""
+
+msgid "Runners|Tags"
+msgstr ""
+
+msgid "Runners|Value"
+msgstr ""
+
+msgid "Runners|Version"
+msgstr ""
+
msgid "Runners|You have used %{quotaUsed} out of %{quotaLimit} of your shared Runners pipeline minutes."
msgstr ""
@@ -21468,6 +22267,9 @@ msgstr ""
msgid "Runs a number of housekeeping tasks within the current repository, such as compressing file revisions and removing unreachable objects."
msgstr ""
+msgid "SAML"
+msgstr ""
+
msgid "SAML SSO"
msgstr ""
@@ -21519,6 +22321,9 @@ msgstr ""
msgid "Save"
msgstr ""
+msgid "Save %{name} size limits"
+msgstr ""
+
msgid "Save Changes"
msgstr ""
@@ -21549,9 +22354,6 @@ msgstr ""
msgid "Save space and find tags in the Container Registry more easily. Enable the cleanup policy to remove stale tags and keep only the ones you need."
msgstr ""
-msgid "Save template"
-msgstr ""
-
msgid "Save variables"
msgstr ""
@@ -21594,9 +22396,6 @@ msgstr ""
msgid "Scope"
msgstr ""
-msgid "Scope not supported with disabled 'users_search' feature!"
-msgstr ""
-
msgid "Scoped issue boards"
msgstr ""
@@ -21723,9 +22522,6 @@ msgstr ""
msgid "Search requirements"
msgstr ""
-msgid "Search results…"
-msgstr ""
-
msgid "Search users"
msgstr ""
@@ -21798,6 +22594,11 @@ msgid_plural "SearchResults|commits"
msgstr[0] ""
msgstr[1] ""
+msgid "SearchResults|epic"
+msgid_plural "SearchResults|epics"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "SearchResults|issue"
msgid_plural "SearchResults|issues"
msgstr[0] ""
@@ -21842,10 +22643,10 @@ msgstr ""
msgid "Seat Link is disabled, and cannot be configured through this form."
msgstr ""
-msgid "Seats currently in use"
+msgid "Seats usage data as of %{last_enqueue_time}"
msgstr ""
-msgid "Seats in license"
+msgid "Seats usage data is updated every day at 12:00pm UTC"
msgstr ""
msgid "Secondary"
@@ -21899,6 +22700,9 @@ msgstr ""
msgid "SecurityConfiguration|Available for on-demand DAST"
msgstr ""
+msgid "SecurityConfiguration|By default, all analyzers are applied in order to cover all languages across your project, and only run if the language is detected in the Merge Request."
+msgstr ""
+
msgid "SecurityConfiguration|Configure"
msgstr ""
@@ -21929,16 +22733,19 @@ msgstr ""
msgid "SecurityConfiguration|Manage"
msgstr ""
+msgid "SecurityConfiguration|More information"
+msgstr ""
+
msgid "SecurityConfiguration|Not enabled"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|Security Control"
+msgid "SecurityConfiguration|SAST Configuration"
msgstr ""
-msgid "SecurityConfiguration|See documentation"
+msgid "SecurityConfiguration|Security Control"
msgstr ""
msgid "SecurityConfiguration|Status"
@@ -21950,6 +22757,9 @@ msgstr ""
msgid "SecurityConfiguration|Using custom settings. You won't receive automatic updates on this variable. %{anchorStart}Restore to default%{anchorEnd}"
msgstr ""
+msgid "SecurityConfiguration|View history"
+msgstr ""
+
msgid "SecurityConfiguration|You can quickly enable all security scanning tools by enabling %{linkStart}Auto DevOps%{linkEnd}."
msgstr ""
@@ -22028,9 +22838,6 @@ msgstr ""
msgid "SecurityReports|Learn more about setting up your dashboard"
msgstr ""
-msgid "SecurityReports|Load more vulnerabilities"
-msgstr ""
-
msgid "SecurityReports|Monitor vulnerabilities in your code"
msgstr ""
@@ -22310,7 +23117,7 @@ msgstr ""
msgid "Select status"
msgstr ""
-msgid "Select strategy activation method"
+msgid "Select strategy activation method."
msgstr ""
msgid "Select subscription"
@@ -22325,7 +23132,7 @@ msgstr ""
msgid "Select the custom project template source group."
msgstr ""
-msgid "Select timeframe"
+msgid "Select the environment scope for this feature flag."
msgstr ""
msgid "Select timezone"
@@ -22574,6 +23381,9 @@ msgstr ""
msgid "Set iteration"
msgstr ""
+msgid "Set limit to 0 to allow any file size."
+msgstr ""
+
msgid "Set max session time for web terminal."
msgstr ""
@@ -22652,10 +23462,13 @@ msgstr ""
msgid "Set up a %{type} Runner manually"
msgstr ""
+msgid "Set up a hardware device as a second factor to sign in."
+msgstr ""
+
msgid "Set up assertions/attributes/claims (email, first_name, last_name) and NameID according to %{docsLinkStart}the documentation %{icon}%{docsLinkEnd}"
msgstr ""
-msgid "Set up new U2F device"
+msgid "Set up new device"
msgstr ""
msgid "Set up new password"
@@ -22724,6 +23537,9 @@ msgstr ""
msgid "Sets weight to %{weight}."
msgstr ""
+msgid "Setting this to 0 means using the system default timeout value."
+msgstr ""
+
msgid "Settings"
msgstr ""
@@ -22739,6 +23555,15 @@ msgstr ""
msgid "Severity"
msgstr ""
+msgid "SeverityWidget|Severity"
+msgstr ""
+
+msgid "SeverityWidget|Severity: %{severity}"
+msgstr ""
+
+msgid "SeverityWidget|There was an error while updating severity."
+msgstr ""
+
msgid "Shards (%{shards})"
msgstr ""
@@ -22784,6 +23609,9 @@ msgstr ""
msgid "Show all requirements."
msgstr ""
+msgid "Show all test cases."
+msgstr ""
+
msgid "Show archived projects"
msgstr ""
@@ -22796,6 +23624,9 @@ msgstr ""
msgid "Show comments"
msgstr ""
+msgid "Show comments on this file"
+msgstr ""
+
msgid "Show comments only"
msgstr ""
@@ -22841,6 +23672,12 @@ msgstr ""
msgid "Show parent subgroups"
msgstr ""
+msgid "Show the Closed list"
+msgstr ""
+
+msgid "Show the Open list"
+msgstr ""
+
msgid "Show whitespace changes"
msgstr ""
@@ -22884,9 +23721,6 @@ msgstr ""
msgid "Sidebar|Assign health status"
msgstr ""
-msgid "Sidebar|Change weight"
-msgstr ""
-
msgid "Sidebar|Health status"
msgstr ""
@@ -23070,6 +23904,9 @@ msgstr ""
msgid "Snippets|Add another file %{num}/%{total}"
msgstr ""
+msgid "Snippets|Authored %{time_ago} by %{author}"
+msgstr ""
+
msgid "Snippets|Delete file"
msgstr ""
@@ -23097,6 +23934,9 @@ msgstr ""
msgid "Solution"
msgstr ""
+msgid "Some changes are not shown"
+msgstr ""
+
msgid "Some child epics may be hidden due to applied filters"
msgstr ""
@@ -23463,6 +24303,12 @@ msgstr ""
msgid "Source (branch or tag)"
msgstr ""
+msgid "Source Branch"
+msgstr ""
+
+msgid "Source branch: %{source_branch_open}%{source_branch}%{source_branch_close}"
+msgstr ""
+
msgid "Source code"
msgstr ""
@@ -23628,9 +24474,6 @@ msgstr ""
msgid "Start and due date"
msgstr ""
-msgid "Start by choosing a group to see how your team is spending time. You can then drill down to the project level."
-msgstr ""
-
msgid "Start by choosing a group to start exploring the merge requests in that group. You can then proceed to filter by projects, labels, milestones and authors."
msgstr ""
@@ -23712,18 +24555,27 @@ msgstr ""
msgid "StaticSiteEditor|3. Assign a person to review and accept the merge request."
msgstr ""
+msgid "StaticSiteEditor|A link to view the merge request will appear once ready."
+msgstr ""
+
msgid "StaticSiteEditor|An error occurred while submitting your changes."
msgstr ""
msgid "StaticSiteEditor|Branch could not be created."
msgstr ""
+msgid "StaticSiteEditor|Copy update"
+msgstr ""
+
msgid "StaticSiteEditor|Could not commit the content changes."
msgstr ""
msgid "StaticSiteEditor|Could not create merge request."
msgstr ""
+msgid "StaticSiteEditor|Creating your merge request"
+msgstr ""
+
msgid "StaticSiteEditor|Incompatible file content"
msgstr ""
@@ -23745,6 +24597,9 @@ msgstr ""
msgid "StaticSiteEditor|View documentation"
msgstr ""
+msgid "StaticSiteEditor|You can set an assignee to get your changes reviewed and deployed once your merge request is created."
+msgstr ""
+
msgid "StaticSiteEditor|Your merge request has been created"
msgstr ""
@@ -23874,15 +24729,15 @@ msgstr ""
msgid "Submit %{humanized_resource_name}"
msgstr ""
-msgid "Submit Changes"
-msgstr ""
-
msgid "Submit a review"
msgstr ""
msgid "Submit as spam"
msgstr ""
+msgid "Submit changes"
+msgstr ""
+
msgid "Submit feedback"
msgstr ""
@@ -24036,6 +24891,9 @@ msgstr ""
msgid "Successfully deleted U2F device."
msgstr ""
+msgid "Successfully deleted WebAuthn device."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -24354,9 +25212,6 @@ msgstr ""
msgid "Template to append to all Service Desk issues"
msgstr ""
-msgid "Template was successfully saved."
-msgstr ""
-
msgid "Templates"
msgstr ""
@@ -24435,10 +25290,28 @@ msgid_plural "Test coverage: %d hits"
msgstr[0] ""
msgstr[1] ""
-msgid "Test failed."
+msgid "Test settings"
msgstr ""
-msgid "Test settings and save changes"
+msgid "TestCases|New Test Case"
+msgstr ""
+
+msgid "TestCases|New test case"
+msgstr ""
+
+msgid "TestCases|Search test cases"
+msgstr ""
+
+msgid "TestCases|Something went wrong while creating a test case."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching count of test cases."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching test cases list."
+msgstr ""
+
+msgid "TestCases|Submit test case"
msgstr ""
msgid "TestHooks|Ensure one of your projects has merge requests."
@@ -24504,6 +25377,9 @@ msgstr ""
msgid "Thank you for signing up for your free trial! You will get additional instructions in your inbox shortly."
msgstr ""
+msgid "Thank you for your business."
+msgstr ""
+
msgid "Thank you for your feedback!"
msgstr ""
@@ -24563,9 +25439,6 @@ msgstr ""
msgid "The URL to use for connecting to Elasticsearch. Use a comma-separated list to support clustering (e.g., \"http://localhost:9200, http://localhost:9201\")."
msgstr ""
-msgid "The Web IDE offers advanced syntax highlighting capabilities and more."
-msgstr ""
-
msgid "The X509 Certificate to use when mutual TLS is required to communicate with the external authorization service. If left blank, the server certificate is still validated when accessing over HTTPS."
msgstr ""
@@ -24676,6 +25549,9 @@ msgstr ""
msgid "The form contains the following error:"
msgstr ""
+msgid "The form contains the following warning:"
+msgstr ""
+
msgid "The global settings require you to enable Two-Factor Authentication for your account."
msgstr ""
@@ -24790,9 +25666,6 @@ msgstr ""
msgid "The private key to use when a client certificate is provided. This value is encrypted at rest."
msgstr ""
-msgid "The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The project can be accessed by any logged in user."
msgstr ""
@@ -24829,7 +25702,7 @@ msgstr ""
msgid "The remote repository is being updated..."
msgstr ""
-msgid "The repository can be commited to, and issues, comments and other entities can be created."
+msgid "The repository can be committed to, and issues, comments and other entities can be created."
msgstr ""
msgid "The repository for this project does not exist."
@@ -24883,9 +25756,6 @@ msgstr ""
msgid "The time taken by each data entry gathered by that stage."
msgstr ""
-msgid "The total stage shows the time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The update action will time out after %{number_of_minutes} minutes. For big repositories, use a clone/push combination."
msgstr ""
@@ -24949,6 +25819,9 @@ msgstr ""
msgid "There are no archived requirements"
msgstr ""
+msgid "There are no archived test cases"
+msgstr ""
+
msgid "There are no changes"
msgstr ""
@@ -24988,6 +25861,9 @@ msgstr ""
msgid "There are no open requirements"
msgstr ""
+msgid "There are no open test cases"
+msgstr ""
+
msgid "There are no packages yet"
msgstr ""
@@ -25000,6 +25876,9 @@ msgstr ""
msgid "There is a limit of %{ci_project_subscriptions_limit} subscriptions from or to a project."
msgstr ""
+msgid "There is already a To-Do for this design."
+msgstr ""
+
msgid "There is already a repository with that name on disk"
msgstr ""
@@ -25018,6 +25897,9 @@ msgstr ""
msgid "There was a problem communicating with your device."
msgstr ""
+msgid "There was a problem fetching branches."
+msgstr ""
+
msgid "There was a problem fetching groups."
msgstr ""
@@ -25246,9 +26128,15 @@ msgstr ""
msgid "This action can lead to data loss. To prevent accidental actions we ask you to confirm your intention."
msgstr ""
+msgid "This action cannot be undone, and will permanently delete the %{key} SSH key"
+msgstr ""
+
msgid "This action cannot be undone. You will lose the project's repository and all content: issues, merge requests, etc."
msgstr ""
+msgid "This action has been performed too many times. Try again later."
+msgstr ""
+
msgid "This action will %{strongOpen}permanently delete%{strongClose} %{codeOpen}%{project}%{codeClose} %{strongOpen}immediately%{strongClose}, including its repositories and all content: issues, merge requests, etc."
msgstr ""
@@ -25276,9 +26164,6 @@ msgstr ""
msgid "This board's scope is reduced"
msgstr ""
-msgid "This branch has changed since you started editing. Would you like to create a new branch?"
-msgstr ""
-
msgid "This chart could not be displayed"
msgstr ""
@@ -25405,15 +26290,9 @@ msgstr ""
msgid "This is a security log of important events involving your account."
msgstr ""
-msgid "This is the author's first Merge Request to this project."
-msgstr ""
-
msgid "This is the highest peak of users on your installation since the license started."
msgstr ""
-msgid "This is the maximum number of users that have existed at the same time since the license started. This is the minimum number of seats you will need to buy when you renew your license."
-msgstr ""
-
msgid "This is the number of currently active users on your installation, and this is the minimum number you need to purchase when you renew your license."
msgstr ""
@@ -25645,6 +26524,15 @@ msgstr ""
msgid "This user has no identities"
msgstr ""
+msgid "This user has previously committed to the %{name} project."
+msgstr ""
+
+msgid "This user has the %{access} role in the %{name} project."
+msgstr ""
+
+msgid "This user is the author of this %{noteable}."
+msgstr ""
+
msgid "This user will be the author of all events in the activity feed that are the result of an update, like new branches being created or new commits being pushed to existing branches."
msgstr ""
@@ -25675,6 +26563,9 @@ msgstr ""
msgid "Threat Monitoring"
msgstr ""
+msgid "ThreatMonitoring|All Environments"
+msgstr ""
+
msgid "ThreatMonitoring|Anomalous Requests"
msgstr ""
@@ -25702,9 +26593,6 @@ msgstr ""
msgid "ThreatMonitoring|Operations Per Second"
msgstr ""
-msgid "ThreatMonitoring|Overview"
-msgstr ""
-
msgid "ThreatMonitoring|Packet Activity"
msgstr ""
@@ -25723,6 +26611,9 @@ msgstr ""
msgid "ThreatMonitoring|Something went wrong, unable to fetch statistics"
msgstr ""
+msgid "ThreatMonitoring|Statistics"
+msgstr ""
+
msgid "ThreatMonitoring|The firewall is not installed or has been disabled. To view this data, ensure the web application firewall is installed and enabled for your cluster."
msgstr ""
@@ -26114,6 +27005,9 @@ msgstr ""
msgid "To update Snippets with multiple files, you must use the `files` parameter"
msgstr ""
+msgid "To use Gitpod you must first enable the feature in the integrations section of your %{user_prefs}."
+msgstr ""
+
msgid "To view all %{scannedResourcesCount} scanned URLs, please download the CSV file"
msgstr ""
@@ -26147,9 +27041,6 @@ msgstr ""
msgid "Toggle Sidebar"
msgstr ""
-msgid "Toggle all threads"
-msgstr ""
-
msgid "Toggle backtrace"
msgstr ""
@@ -26174,9 +27065,6 @@ msgstr ""
msgid "Toggle navigation"
msgstr ""
-msgid "Toggle project"
-msgstr ""
-
msgid "Toggle sidebar"
msgstr ""
@@ -26216,6 +27104,9 @@ msgstr ""
msgid "Too many projects enabled. You will need to manage them via the console or the API."
msgstr ""
+msgid "Too much data"
+msgstr ""
+
msgid "Topics (optional)"
msgstr ""
@@ -26234,6 +27125,9 @@ msgstr ""
msgid "Total cores (CPUs)"
msgstr ""
+msgid "Total days to completion"
+msgstr ""
+
msgid "Total issues"
msgstr ""
@@ -26330,6 +27224,9 @@ msgstr ""
msgid "Trending"
msgstr ""
+msgid "Trials|Create a new group to start your GitLab Gold trial."
+msgstr ""
+
msgid "Trials|Go back to GitLab"
msgstr ""
@@ -26339,6 +27236,15 @@ msgstr ""
msgid "Trials|You can always resume this process by selecting your avatar and choosing 'Start a Gold trial'"
msgstr ""
+msgid "Trials|You can apply your trial to a new group or an existing group."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group or your personal account."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group, an existing group, or your personal account."
+msgstr ""
+
msgid "Trials|You won't get a free trial right now but you can always resume this process by clicking on your avatar and choosing 'Start a free trial'"
msgstr ""
@@ -26408,6 +27314,9 @@ msgstr ""
msgid "Try using a different search term to find the file you are looking for."
msgstr ""
+msgid "Trying to communicate with your device. Plug it in (if needed) and press the button on the device now."
+msgstr ""
+
msgid "Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now."
msgstr ""
@@ -26495,6 +27404,12 @@ msgstr ""
msgid "URL or request ID"
msgstr ""
+msgid "USER %{user} WILL BE REMOVED! Are you sure?"
+msgstr ""
+
+msgid "USER WILL BE BLOCKED! Are you sure?"
+msgstr ""
+
msgid "UTC"
msgstr ""
@@ -26552,9 +27467,6 @@ msgstr ""
msgid "Unable to load the merge request widget. Try reloading the page."
msgstr ""
-msgid "Unable to resolve"
-msgstr ""
-
msgid "Unable to save iteration. Please try again"
msgstr ""
@@ -26603,6 +27515,9 @@ msgstr ""
msgid "Undo ignore"
msgstr ""
+msgid "Unexpected error"
+msgstr ""
+
msgid "Unfortunately, your email message to GitLab could not be processed."
msgstr ""
@@ -26636,6 +27551,9 @@ msgstr ""
msgid "Unknown response text"
msgstr ""
+msgid "Unless otherwise agreed to in writing with GitLab, by clicking \"Upload License\" you agree that your use of GitLab Software is subject to the %{eula_link_start}Terms of Service%{eula_link_end}."
+msgstr ""
+
msgid "Unlimited"
msgstr ""
@@ -27002,9 +27920,6 @@ msgstr ""
msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
msgstr ""
-msgid "Use a hardware device to add the second factor of authentication."
-msgstr ""
-
msgid "Use an one time password authenticator on your mobile device or computer to enable two-factor authentication (2FA)."
msgstr ""
@@ -27278,13 +28193,13 @@ msgstr ""
msgid "Users"
msgstr ""
-msgid "Users in License:"
+msgid "Users in License"
msgstr ""
-msgid "Users or groups set as approvers in the project's or merge request's settings."
+msgid "Users in License:"
msgstr ""
-msgid "Users outside of license"
+msgid "Users or groups set as approvers in the project's or merge request's settings."
msgstr ""
msgid "Users over License:"
@@ -27302,9 +28217,6 @@ msgstr ""
msgid "Users with a Guest role or those who don't belong to a Project or Group will not use a seat from your license."
msgstr ""
-msgid "Users with a Guest role or those who don't belong to any projects or groups don't count towards seats in use."
-msgstr ""
-
msgid "UsersSelect|%{name} + %{length} more"
msgstr ""
@@ -27344,9 +28256,6 @@ msgstr ""
msgid "Validations failed."
msgstr ""
-msgid "Validity"
-msgstr ""
-
msgid "Value"
msgstr ""
@@ -27365,6 +28274,9 @@ msgstr ""
msgid "Value Stream Name"
msgstr ""
+msgid "ValueStreamAnalyticsStage|We don't have enough data to show this stage."
+msgstr ""
+
msgid "ValueStreamAnalytics|%{days}d"
msgstr ""
@@ -27621,6 +28533,9 @@ msgstr ""
msgid "VisualReviewApp|Steps 1 and 2 (and sometimes 3) are performed once by the developer before requesting feedback. Steps 3 (if necessary), 4 is performed by the reviewer each time they perform a review."
msgstr ""
+msgid "Visualization"
+msgstr ""
+
msgid "Vulnerabilities"
msgstr ""
@@ -27648,34 +28563,31 @@ msgstr ""
msgid "VulnerabilityChart|Severity"
msgstr ""
-msgid "VulnerabilityManagement|A true-positive and will fix"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Change status"
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|Confirm"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Confirmed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
-msgstr ""
-
-msgid "VulnerabilityManagement|Detected %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|A true-positive and will fix"
msgstr ""
-msgid "VulnerabilityManagement|Dismiss"
+msgid "VulnerabilityManagement|Change status"
msgstr ""
-msgid "VulnerabilityManagement|Dismissed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
msgstr ""
-msgid "VulnerabilityManagement|Resolved"
+msgid "VulnerabilityManagement|Detected"
msgstr ""
-msgid "VulnerabilityManagement|Resolved %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Needs triage"
msgstr ""
msgid "VulnerabilityManagement|Something went wrong while trying to delete the comment. Please try again later."
@@ -27726,6 +28638,9 @@ msgstr ""
msgid "Vulnerability|%{scannerName} (version %{scannerVersion})"
msgstr ""
+msgid "Vulnerability|Activity"
+msgstr ""
+
msgid "Vulnerability|Class"
msgstr ""
@@ -27738,6 +28653,9 @@ msgstr ""
msgid "Vulnerability|Description"
msgstr ""
+msgid "Vulnerability|Detected"
+msgstr ""
+
msgid "Vulnerability|Evidence"
msgstr ""
@@ -27801,6 +28719,9 @@ msgstr ""
msgid "Warning: Displaying this diagram might cause performance issues on this page."
msgstr ""
+msgid "We are currently unable to fetch data for the pipeline header."
+msgstr ""
+
msgid "We are currently unable to fetch data for this graph."
msgstr ""
@@ -27840,6 +28761,12 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
+msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
+msgstr ""
+
+msgid "We would like to inform you that your subscription GitLab Enterprise Edition %{plan_name} is nearing its user limit. You have %{active_user_count} active users, which is almost at the user limit of %{maximum_user_count}."
+msgstr ""
+
msgid "We've found no vulnerabilities"
msgstr ""
@@ -27855,6 +28782,12 @@ msgstr ""
msgid "Web terminal"
msgstr ""
+msgid "WebAuthn Devices (%{length})"
+msgstr ""
+
+msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
+msgstr ""
+
msgid "WebIDE|Merge request"
msgstr ""
@@ -27993,15 +28926,9 @@ msgstr ""
msgid "Welcome to the guided GitLab tour"
msgstr ""
-msgid "Welcome to your Issue Board!"
-msgstr ""
-
msgid "Welcome to your issue board!"
msgstr ""
-msgid "We’ve been making changes to %{featureName} and we’d love your feedback %{linkStart}in this issue%{linkEnd} to help us improve the experience."
-msgstr ""
-
msgid "What are you searching for?"
msgstr ""
@@ -28020,6 +28947,9 @@ msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
msgstr ""
+msgid "When enabled, any user visiting %{host} and creating an account will have to be explicitly approved by the admin before they can login. This setting is effective only if sign-ups are enabled."
+msgstr ""
+
msgid "When enabled, any user visiting %{host} will be able to create an account."
msgstr ""
@@ -28244,6 +29174,9 @@ msgstr ""
msgid "With requirements, you can set criteria to check your products against."
msgstr ""
+msgid "With test cases, you can define conditions for your project to meet in determining quality"
+msgstr ""
+
msgid "Withdraw Access Request"
msgstr ""
@@ -28259,6 +29192,9 @@ msgstr ""
msgid "Workflow Help"
msgstr ""
+msgid "Would you like to create a new branch?"
+msgstr ""
+
msgid "Write"
msgstr ""
@@ -28280,6 +29216,9 @@ msgstr ""
msgid "Wrong extern UID provided. Make sure Auth0 is configured correctly."
msgstr ""
+msgid "YYYY-MM-DD"
+msgstr ""
+
msgid "Yes"
msgstr ""
@@ -28337,7 +29276,7 @@ msgstr ""
msgid "You are going to remove the fork relationship from %{project_full_name}. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "You are going to transfer %{project_full_name} to another owner. Are you ABSOLUTELY sure?"
+msgid "You are going to transfer %{project_full_name} to another namespace. Are you ABSOLUTELY sure?"
msgstr ""
msgid "You are going to turn off the confidentiality. This means %{strongStart}everyone%{strongEnd} will be able to see and leave a comment on this %{issuableType}."
@@ -28397,9 +29336,6 @@ msgstr ""
msgid "You can always edit this later"
msgstr ""
-msgid "You can apply your Trial to your Personal account or create a New Group."
-msgstr ""
-
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings"
msgstr ""
@@ -28421,12 +29357,18 @@ msgstr ""
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
+msgid "You can find more information about GitLab subscriptions in %{subscriptions_doc_link}."
+msgstr ""
+
msgid "You can generate an access token scoped to this project for each application to use the GitLab API."
msgstr ""
msgid "You can get started by cloning the repository or start adding files to it with one of the following options."
msgstr ""
+msgid "You can group test cases using labels. To learn about the future direction of this feature, visit %{linkStart}Quality Management direction page%{linkEnd}."
+msgstr ""
+
msgid "You can invite a new member to %{project_name} or invite another group."
msgstr ""
@@ -28442,6 +29384,9 @@ msgstr ""
msgid "You can notify the app / group or a project by sending them an email notification"
msgstr ""
+msgid "You can now close this window."
+msgstr ""
+
msgid "You can now export your security dashboard to a CSV report."
msgstr ""
@@ -28490,9 +29435,6 @@ msgstr ""
msgid "You can test your .gitlab-ci.yml in %{linkStart}CI Lint%{linkEnd}."
msgstr ""
-msgid "You can try again using %{begin_link}basic search%{end_link}"
-msgstr ""
-
msgid "You cannot access the raw file. Please wait a minute."
msgstr ""
@@ -28544,6 +29486,9 @@ msgstr ""
msgid "You don't have any U2F devices registered yet."
msgstr ""
+msgid "You don't have any WebAuthn devices registered yet."
+msgstr ""
+
msgid "You don't have any active chat names."
msgstr ""
@@ -28631,6 +29576,9 @@ msgstr ""
msgid "You must accept our Terms of Service and privacy policy in order to register an account"
msgstr ""
+msgid "You must be logged in to search across all of GitLab"
+msgstr ""
+
msgid "You must disassociate %{domain} from all clusters it is attached to before deletion."
msgstr ""
@@ -28670,7 +29618,7 @@ msgstr ""
msgid "You need to be logged in."
msgstr ""
-msgid "You need to register a two-factor authentication app before you can set up a U2F device."
+msgid "You need to register a two-factor authentication app before you can set up a device."
msgstr ""
msgid "You need to set terms to be enforced"
@@ -28688,6 +29636,9 @@ msgstr ""
msgid "You reached %{usage_in_percent} of %{namespace_name}'s storage capacity (%{used_storage} of %{storage_limit})"
msgstr ""
+msgid "You successfully declined the invitation"
+msgstr ""
+
msgid "You tried to fork %{link_to_the_project} but it failed for the following reason:"
msgstr ""
@@ -28853,10 +29804,13 @@ msgstr ""
msgid "Your U2F device did not send a valid JSON response."
msgstr ""
-msgid "Your U2F device needs to be set up. Plug it in (if not already) and click the button on the left."
+msgid "Your U2F device was registered!"
msgstr ""
-msgid "Your U2F device was registered!"
+msgid "Your WebAuthn device did not send a valid JSON response."
+msgstr ""
+
+msgid "Your WebAuthn device was registered!"
msgstr ""
msgid "Your access request to the %{source_type} has been withdrawn."
@@ -28880,6 +29834,9 @@ msgstr ""
msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
msgstr ""
+msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
+msgstr ""
+
msgid "Your changes can be committed to %{branch_name} because a merge request is open."
msgstr ""
@@ -28916,6 +29873,12 @@ msgstr ""
msgid "Your deployment services will be broken, you will need to manually fix the services after renaming."
msgstr ""
+msgid "Your device is not compatible with GitLab. Please try another device"
+msgstr ""
+
+msgid "Your device needs to be set up. Plug it in (if needed) and click the button on the left."
+msgstr ""
+
msgid "Your device was successfully set up! Give it a name and register it with the GitLab server."
msgstr ""
@@ -29029,9 +29992,6 @@ msgstr[1] ""
msgid "access:"
msgstr ""
-msgid "activated"
-msgstr ""
-
msgid "added %{created_at_timeago}"
msgstr ""
@@ -29104,9 +30064,21 @@ msgstr ""
msgid "by %{user}"
msgstr ""
+msgid "cannot be a date in the past"
+msgstr ""
+
msgid "cannot be changed if a personal project has container registry tags."
msgstr ""
+msgid "cannot be changed if shared runners are enabled"
+msgstr ""
+
+msgid "cannot be enabled because parent group does not allow it"
+msgstr ""
+
+msgid "cannot be enabled because parent group has shared Runners disabled"
+msgstr ""
+
msgid "cannot be enabled unless all domains have TLS certificates"
msgstr ""
@@ -29152,7 +30124,7 @@ msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about SAST %{linkEndTag}"
msgstr ""
-msgid "ciReport|%{linkStartTag}Learn more about Secret Scanning %{linkEndTag}"
+msgid "ciReport|%{linkStartTag}Learn more about Secret Detection %{linkEndTag}"
msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about codequality reports %{linkEndTag}"
@@ -29467,9 +30439,6 @@ msgstr ""
msgid "error"
msgstr ""
-msgid "error code:"
-msgstr ""
-
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr ""
@@ -29491,6 +30460,9 @@ msgstr ""
msgid "failed to dismiss associated finding(id=%{finding_id}): %{message}"
msgstr ""
+msgid "failed to revert associated finding(id=%{finding_id}) to detected"
+msgstr ""
+
msgid "file"
msgid_plural "files"
msgstr[0] ""
@@ -30033,6 +31005,9 @@ msgstr ""
msgid "must be a root namespace"
msgstr ""
+msgid "must be a valid IPv4 or IPv6 address"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -30069,6 +31044,9 @@ msgstr ""
msgid "no expiration"
msgstr ""
+msgid "no name set"
+msgstr ""
+
msgid "no one can merge"
msgstr ""
@@ -30247,9 +31225,6 @@ msgstr ""
msgid "security Reports|There was an error creating the merge request"
msgstr ""
-msgid "settings saved, but not activated"
-msgstr ""
-
msgid "severity|Critical"
msgstr ""
@@ -30376,9 +31351,6 @@ msgstr ""
msgid "toggle collapse"
msgstr ""
-msgid "toggle dropdown"
-msgstr ""
-
msgid "triggered"
msgstr ""
@@ -30406,6 +31378,9 @@ msgstr ""
msgid "user avatar"
msgstr ""
+msgid "user preferences"
+msgstr ""
+
msgid "username"
msgstr ""
diff --git a/locale/vi_VN/gitlab.po b/locale/vi_VN/gitlab.po
index e2386705446..e14d5f906df 100644
--- a/locale/vi_VN/gitlab.po
+++ b/locale/vi_VN/gitlab.po
@@ -14,7 +14,10 @@ msgstr ""
"X-Crowdin-Language: vi\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 6\n"
-"PO-Revision-Date: 2020-09-04 23:01\n"
+"PO-Revision-Date: 2020-10-02 18:41\n"
+
+msgid " %{project_name}#%{issue_iid} &middot; opened %{issue_created} by %{author}"
+msgstr ""
msgid " %{start} to %{end}"
msgstr ""
@@ -72,6 +75,14 @@ msgstr ""
msgid "\"el\" parameter is required for createInstance()"
msgstr ""
+msgid "%d Approval"
+msgid_plural "%d Approvals"
+msgstr[0] ""
+
+msgid "%d Package"
+msgid_plural "%d Packages"
+msgstr[0] ""
+
msgid "%d Scanned URL"
msgid_plural "%d Scanned URLs"
msgstr[0] ""
@@ -123,6 +134,10 @@ msgstr[0] ""
msgid "%d commits"
msgstr ""
+msgid "%d completed issue"
+msgid_plural "%d completed issues"
+msgstr[0] ""
+
msgid "%d contribution"
msgid_plural "%d contributions"
msgstr[0] ""
@@ -131,6 +146,10 @@ msgid "%d day"
msgid_plural "%d days"
msgstr[0] ""
+msgid "%d day until tags are automatically removed"
+msgid_plural "%d days until tags are automatically removed"
+msgstr[0] ""
+
msgid "%d error"
msgid_plural "%d errors"
msgstr[0] ""
@@ -203,6 +222,14 @@ msgid "%d more comment"
msgid_plural "%d more comments"
msgstr[0] ""
+msgid "%d open issue"
+msgid_plural "%d open issues"
+msgstr[0] ""
+
+msgid "%d pending comment"
+msgid_plural "%d pending comments"
+msgstr[0] ""
+
msgid "%d personal project will be removed and cannot be restored."
msgid_plural "%d personal projects will be removed and cannot be restored."
msgstr[0] ""
@@ -215,6 +242,10 @@ msgid "%d project"
msgid_plural "%d projects"
msgstr[0] ""
+msgid "%d project selected"
+msgid_plural "%d projects selected"
+msgstr[0] ""
+
msgid "%d request with warnings"
msgid_plural "%d requests with warnings"
msgstr[0] ""
@@ -231,6 +262,10 @@ msgid "%d tag"
msgid_plural "%d tags"
msgstr[0] ""
+msgid "%d tag per image name"
+msgid_plural "%d tags per image name"
+msgstr[0] ""
+
msgid "%d unassigned issue"
msgid_plural "%d unassigned issues"
msgstr[0] ""
@@ -247,6 +282,10 @@ msgid "%d vulnerability dismissed"
msgid_plural "%d vulnerabilities dismissed"
msgstr[0] ""
+msgid "%d warning found:"
+msgid_plural "%d warnings found:"
+msgstr[0] ""
+
msgid "%s additional commit has been omitted to prevent performance issues."
msgid_plural "%s additional commits have been omitted to prevent performance issues."
msgstr[0] ""
@@ -284,6 +323,9 @@ msgstr ""
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr ""
+msgid "%{completedCount} completed weight"
+msgstr ""
+
msgid "%{completedWeight} of %{totalWeight} weight completed"
msgstr ""
@@ -329,13 +371,12 @@ msgid "%{count} participant"
msgid_plural "%{count} participants"
msgstr[0] ""
-msgid "%{count} pending comment"
-msgid_plural "%{count} pending comments"
-msgstr[0] ""
-
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
+msgid "%{count} total weight"
+msgstr ""
+
msgid "%{dashboard_path} could not be found."
msgstr ""
@@ -390,6 +431,9 @@ msgstr ""
msgid "%{group_name} uses group managed accounts. You need to create a new GitLab account which will be managed by %{group_name}."
msgstr ""
+msgid "%{group_name}&%{epic_iid} &middot; opened %{epic_created} by %{author}"
+msgstr ""
+
msgid "%{host} sign-in from new location"
msgstr ""
@@ -402,7 +446,7 @@ msgstr ""
msgid "%{issuableType} will be removed! Are you sure?"
msgstr ""
-msgid "%{issuesSize} issues with a limit of %{maxIssueCount}"
+msgid "%{issuesCount} issues with a limit of %{maxIssueCount}"
msgstr ""
msgid "%{issuesSize} with a limit of %{maxIssueCount}"
@@ -435,7 +479,7 @@ msgstr ""
msgid "%{labelStart}Namespace:%{labelEnd} %{namespace}"
msgstr ""
-msgid "%{labelStart}Report Type:%{labelEnd} %{reportType}"
+msgid "%{labelStart}Scan Type:%{labelEnd} %{reportType}"
msgstr ""
msgid "%{labelStart}Scanner:%{labelEnd} %{scanner}"
@@ -625,9 +669,6 @@ msgid "%{securityScanner} result is not available because a pipeline has not bee
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] ""
-msgid "%{service_title} %{message}."
-msgstr ""
-
msgid "%{size} GiB"
msgstr ""
@@ -711,6 +752,12 @@ msgstr ""
msgid "%{timebox_name} should belong either to a project or a group."
msgstr ""
+msgid "%{timebox_type} does not support burnup charts"
+msgstr ""
+
+msgid "%{timebox_type} must have a start and due date"
+msgstr ""
+
msgid "%{title} %{operator} %{threshold}"
msgstr ""
@@ -735,7 +782,7 @@ msgstr ""
msgid "%{total} open issue weight"
msgstr ""
-msgid "%{total} open issues"
+msgid "%{total} warnings found: showing first %{warningsDisplayed}"
msgstr ""
msgid "%{usage_ping_link_start}Learn more%{usage_ping_link_end} about what information is shared with GitLab Inc."
@@ -768,9 +815,6 @@ msgstr ""
msgid "&lt; 1 hour"
msgstr ""
-msgid "&lt;no name set&gt;"
-msgstr ""
-
msgid "&lt;no scopes selected&gt;"
msgstr ""
@@ -801,6 +845,9 @@ msgstr ""
msgid "'%{name}' Value Stream created"
msgstr ""
+msgid "'%{name}' Value Stream deleted"
+msgstr ""
+
msgid "'%{name}' stage already exists"
msgstr ""
@@ -859,6 +906,9 @@ msgstr ""
msgid "+ %{numberOfHiddenAssignees} more"
msgstr ""
+msgid "+ %{numberOfHiddenReviewers} more"
+msgstr ""
+
msgid "+%d more"
msgid_plural "+%d more"
msgstr[0] ""
@@ -913,6 +963,10 @@ msgid "1 Day"
msgid_plural "%d Days"
msgstr[0] ""
+msgid "1 Issue"
+msgid_plural "%d Issues"
+msgstr[0] ""
+
msgid "1 closed issue"
msgid_plural "%{issues} closed issues"
msgstr[0] ""
@@ -925,6 +979,10 @@ msgid "1 day"
msgid_plural "%d days"
msgstr[0] ""
+msgid "1 deploy key"
+msgid_plural "%d deploy keys"
+msgstr[0] ""
+
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] ""
@@ -1018,6 +1076,9 @@ msgstr ""
msgid ":%{startLine} to %{endLine}"
msgstr ""
+msgid "A %{incident_docs_start}modified issue%{incident_docs_end} to guide the resolution of incidents."
+msgstr ""
+
msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr ""
@@ -1030,6 +1091,9 @@ msgstr ""
msgid "A GitBook site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
+msgid "A Gitpod configured Webapplication in Spring and Java"
+msgstr ""
+
msgid "A Hexo site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
@@ -1201,9 +1265,15 @@ msgstr ""
msgid "Access expiration date"
msgstr ""
+msgid "Access expires"
+msgstr ""
+
msgid "Access forbidden. Check your access level."
msgstr ""
+msgid "Access granted"
+msgstr ""
+
msgid "Access requests"
msgstr ""
@@ -1213,6 +1283,9 @@ msgstr ""
msgid "Access to Pages websites are controlled based on the user's membership to a given project. By checking this box, users will be required to be logged in to have access to all Pages websites in your instance."
msgstr ""
+msgid "AccessDropdown|Deploy Keys"
+msgstr ""
+
msgid "AccessDropdown|Groups"
msgstr ""
@@ -1330,12 +1403,6 @@ msgstr ""
msgid "Active Sessions"
msgstr ""
-msgid "Active Users:"
-msgstr ""
-
-msgid "Active users"
-msgstr ""
-
msgid "Activity"
msgstr ""
@@ -1502,9 +1569,6 @@ msgstr ""
msgid "Add label(s)"
msgstr ""
-msgid "Add license"
-msgstr ""
-
msgid "Add list"
msgstr ""
@@ -1679,21 +1743,51 @@ msgstr ""
msgid "AdminArea|Bots"
msgstr ""
+msgid "AdminArea|Components"
+msgstr ""
+
msgid "AdminArea|Developer"
msgstr ""
+msgid "AdminArea|Features"
+msgstr ""
+
+msgid "AdminArea|Groups: %{number_of_groups}"
+msgstr ""
+
msgid "AdminArea|Guest"
msgstr ""
msgid "AdminArea|Included Free in license"
msgstr ""
+msgid "AdminArea|Latest groups"
+msgstr ""
+
+msgid "AdminArea|Latest projects"
+msgstr ""
+
+msgid "AdminArea|Latest users"
+msgstr ""
+
msgid "AdminArea|Maintainer"
msgstr ""
+msgid "AdminArea|New group"
+msgstr ""
+
+msgid "AdminArea|New project"
+msgstr ""
+
+msgid "AdminArea|New user"
+msgstr ""
+
msgid "AdminArea|Owner"
msgstr ""
+msgid "AdminArea|Projects: %{number_of_projects}"
+msgstr ""
+
msgid "AdminArea|Reporter"
msgstr ""
@@ -1721,6 +1815,9 @@ msgstr ""
msgid "AdminArea|Users without a Group and Project"
msgstr ""
+msgid "AdminArea|Users: %{number_of_users}"
+msgstr ""
+
msgid "AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running."
msgstr ""
@@ -1739,9 +1836,6 @@ msgstr ""
msgid "AdminProjects|Delete Project %{projectName}?"
msgstr ""
-msgid "AdminProjects|Delete project"
-msgstr ""
-
msgid "AdminSettings|Apply integration settings to all Projects"
msgstr ""
@@ -1979,21 +2073,30 @@ msgstr ""
msgid "AdminUsers|Without projects"
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 ""
msgid "AdminUsers|You cannot remove your own admin rights."
msgstr ""
+msgid "AdminUsers|You must transfer ownership or delete the groups owned by this user before you can delete their account"
+msgstr ""
+
msgid "Administration"
msgstr ""
msgid "Advanced"
msgstr ""
+msgid "Advanced Search"
+msgstr ""
+
+msgid "Advanced Search with Elasticsearch"
+msgstr ""
+
msgid "Advanced Settings"
msgstr ""
@@ -2070,6 +2173,9 @@ msgstr ""
msgid "AlertManagement|Edit"
msgstr ""
+msgid "AlertManagement|Environment"
+msgstr ""
+
msgid "AlertManagement|Events"
msgstr ""
@@ -2082,6 +2188,9 @@ msgstr ""
msgid "AlertManagement|Issue"
msgstr ""
+msgid "AlertManagement|Key"
+msgstr ""
+
msgid "AlertManagement|Low"
msgstr ""
@@ -2175,6 +2284,9 @@ msgstr ""
msgid "AlertManagement|Unknown"
msgstr ""
+msgid "AlertManagement|Value"
+msgstr ""
+
msgid "AlertManagement|View alerts in Opsgenie"
msgstr ""
@@ -2334,6 +2446,9 @@ msgstr ""
msgid "All projects"
msgstr ""
+msgid "All projects selected"
+msgstr ""
+
msgid "All security scans are enabled because %{linkStart}Auto DevOps%{linkEnd} is enabled on this project"
msgstr ""
@@ -2421,6 +2536,9 @@ msgstr ""
msgid "Almost there"
msgstr ""
+msgid "Already blocked"
+msgstr ""
+
msgid "Also called \"Issuer\" or \"Relying party trust identifier\""
msgstr ""
@@ -2475,6 +2593,9 @@ msgstr ""
msgid "An error has occurred"
msgstr ""
+msgid "An error occured while making the changes: %{error}"
+msgstr ""
+
msgid "An error occurred adding a draft to the thread."
msgstr ""
@@ -2502,12 +2623,6 @@ msgstr ""
msgid "An error occurred when toggling the notification subscription"
msgstr ""
-msgid "An error occurred when trying to resolve a comment. Please try again."
-msgstr ""
-
-msgid "An error occurred when trying to resolve a discussion. Please try again."
-msgstr ""
-
msgid "An error occurred when updating the issue weight"
msgstr ""
@@ -2523,12 +2638,6 @@ msgstr ""
msgid "An error occurred while checking group path. Please refresh and try again."
msgstr ""
-msgid "An error occurred while committing your changes."
-msgstr ""
-
-msgid "An error occurred while creating the list. Please try again."
-msgstr ""
-
msgid "An error occurred while decoding the file."
msgstr ""
@@ -2601,25 +2710,19 @@ msgstr ""
msgid "An error occurred while fetching the Service Desk address."
msgstr ""
-msgid "An error occurred while fetching the board issues. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the board lists. Please reload the page."
msgstr ""
msgid "An error occurred while fetching the board lists. Please try again."
msgstr ""
-msgid "An error occurred while fetching the board swimlanes. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the builds."
msgstr ""
msgid "An error occurred while fetching the job log."
msgstr ""
-msgid "An error occurred while fetching the job trace."
+msgid "An error occurred while fetching the job logs."
msgstr ""
msgid "An error occurred while fetching the job."
@@ -2766,9 +2869,6 @@ msgstr ""
msgid "An error occurred while saving assignees"
msgstr ""
-msgid "An error occurred while saving the template. Please check if the template exists."
-msgstr ""
-
msgid "An error occurred while searching for milestones"
msgstr ""
@@ -2787,10 +2887,10 @@ msgstr ""
msgid "An error occurred while updating approvers"
msgstr ""
-msgid "An error occurred while updating the comment"
+msgid "An error occurred while updating labels."
msgstr ""
-msgid "An error occurred while updating the list. Please try again."
+msgid "An error occurred while updating the comment"
msgstr ""
msgid "An error occurred while validating group path"
@@ -2844,6 +2944,9 @@ msgstr ""
msgid "An unknown error occurred while loading this graph."
msgstr ""
+msgid "An unknown error occurred."
+msgstr ""
+
msgid "Analytics"
msgstr ""
@@ -2877,10 +2980,10 @@ msgstr ""
msgid "Any"
msgstr ""
-msgid "Any Author"
+msgid "Any %{header}"
msgstr ""
-msgid "Any Status"
+msgid "Any Author"
msgstr ""
msgid "Any branch"
@@ -2934,6 +3037,9 @@ msgstr ""
msgid "Application ID"
msgstr ""
+msgid "Application limits saved successfully"
+msgstr ""
+
msgid "Application settings saved successfully"
msgstr ""
@@ -3139,6 +3245,9 @@ msgstr ""
msgid "Are you sure you want to close this blocked issue?"
msgstr ""
+msgid "Are you sure you want to delete \"%{name}\" Value Stream?"
+msgstr ""
+
msgid "Are you sure you want to delete %{name}?"
msgstr ""
@@ -3148,6 +3257,9 @@ msgstr ""
msgid "Are you sure you want to delete this %{typeOfComment}?"
msgstr ""
+msgid "Are you sure you want to delete this SSH key?"
+msgstr ""
+
msgid "Are you sure you want to delete this board?"
msgstr ""
@@ -3172,6 +3284,10 @@ msgstr ""
msgid "Are you sure you want to erase this build?"
msgstr ""
+msgid "Are you sure you want to import %d repository?"
+msgid_plural "Are you sure you want to import %d repositories?"
+msgstr[0] ""
+
msgid "Are you sure you want to lose unsaved changes?"
msgstr ""
@@ -3181,15 +3297,15 @@ msgstr ""
msgid "Are you sure you want to merge immediately?"
msgstr ""
-msgid "Are you sure you want to permanently delete this license?"
-msgstr ""
-
msgid "Are you sure you want to re-deploy this environment?"
msgstr ""
msgid "Are you sure you want to regenerate the public key? You will have to update the public key on the remote server before mirroring will work again."
msgstr ""
+msgid "Are you sure you want to reindex?"
+msgstr ""
+
msgid "Are you sure you want to remove %{group_name}?"
msgstr ""
@@ -3217,6 +3333,9 @@ msgstr ""
msgid "Are you sure you want to revoke this nickname?"
msgstr ""
+msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
+msgstr ""
+
msgid "Are you sure you want to stop this environment?"
msgstr ""
@@ -3238,6 +3357,9 @@ msgstr ""
msgid "Are you sure? The device will be signed out of GitLab and all remember me tokens revoked."
msgstr ""
+msgid "Are you sure? This will invalidate your registered applications and U2F / WebAuthn devices."
+msgstr ""
+
msgid "Are you sure? This will invalidate your registered applications and U2F devices."
msgstr ""
@@ -3256,9 +3378,6 @@ msgstr ""
msgid "Artifacts"
msgstr ""
-msgid "As U2F devices are only supported by a few browsers, we require that you set up a two-factor authentication app before a U2F device. That way you'll always be able to log in - even when you're using an unsupported browser."
-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 ""
@@ -3450,6 +3569,9 @@ msgstr ""
msgid "AuditLogs|Target"
msgstr ""
+msgid "AuditLogs|This month"
+msgstr ""
+
msgid "AuditLogs|User Events"
msgstr ""
@@ -3489,6 +3611,9 @@ msgstr ""
msgid "Authentication via U2F device failed."
msgstr ""
+msgid "Authentication via WebAuthn device failed."
+msgstr ""
+
msgid "Author"
msgstr ""
@@ -3756,15 +3881,6 @@ msgstr ""
msgid "BambooService|You must set up automatic revision labeling and a repository trigger in Bamboo."
msgstr ""
-msgid "BatchComments|Delete all pending comments"
-msgstr ""
-
-msgid "BatchComments|Discard review?"
-msgstr ""
-
-msgid "BatchComments|You're about to discard your review which will delete all of your pending comments. The deleted comments %{strong_start}cannot%{strong_end} be restored."
-msgstr ""
-
msgid "Be careful. Changing the project's namespace can have unintended side effects."
msgstr ""
@@ -3786,6 +3902,9 @@ msgstr ""
msgid "Bi-weekly code coverage"
msgstr ""
+msgid "Billable Users:"
+msgstr ""
+
msgid "Billing"
msgstr ""
@@ -3795,7 +3914,7 @@ msgstr ""
msgid "BillingPlans|@%{user_name} you are currently using the %{plan_name} plan."
msgstr ""
-msgid "BillingPlans|Congratulations, your new trial is activated"
+msgid "BillingPlans|Congratulations, your free trial is activated."
msgstr ""
msgid "BillingPlans|If you would like to downgrade your plan please contact %{support_link_start}Customer Support%{support_link_end}."
@@ -3858,6 +3977,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Block user"
+msgstr ""
+
msgid "Blocked"
msgstr ""
@@ -3873,31 +3995,37 @@ msgstr ""
msgid "Blog"
msgstr ""
-msgid "Board name"
-msgstr ""
-
msgid "Board scope"
msgstr ""
msgid "Board scope affects which issues are displayed for anyone who visits this board"
msgstr ""
-msgid "BoardBlankState|Add default lists"
+msgid "Boards"
+msgstr ""
+
+msgid "Boards and Board Lists"
msgstr ""
-msgid "BoardBlankState|Add the following default lists to your Issue Board with one click:"
+msgid "Boards|An error occurred while creating the issue. Please try again."
msgstr ""
-msgid "BoardBlankState|Nevermind, I'll use my own"
+msgid "Boards|An error occurred while creating the list. Please try again."
msgstr ""
-msgid "BoardBlankState|Starting out with the default set of lists will get you right on the way to making the most of your board."
+msgid "Boards|An error occurred while fetching issues. Please reload the page."
msgstr ""
-msgid "Boards"
+msgid "Boards|An error occurred while fetching the board issues. Please reload the page."
msgstr ""
-msgid "Boards and Board Lists"
+msgid "Boards|An error occurred while fetching the board swimlanes. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while moving the issue. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while updating the list. Please try again."
msgstr ""
msgid "Boards|Collapse"
@@ -3924,7 +4052,7 @@ msgstr ""
msgid "Branch %{branch_name} was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr ""
-msgid "Branch has changed"
+msgid "Branch changed"
msgstr ""
msgid "Branch is already taken"
@@ -4230,6 +4358,9 @@ msgstr ""
msgid "CLOSED (MOVED)"
msgstr ""
+msgid "CODEOWNERS rule violation"
+msgstr ""
+
msgid "CONTRIBUTING"
msgstr ""
@@ -4260,9 +4391,6 @@ msgstr ""
msgid "Can't create snippet: %{err}"
msgstr ""
-msgid "Can't edit as source branch was deleted"
-msgstr ""
-
msgid "Can't fetch content for the blob: %{err}"
msgstr ""
@@ -4275,9 +4403,6 @@ msgstr ""
msgid "Can't load mermaid module: %{err}"
msgstr ""
-msgid "Can't remove group members without group managed account"
-msgstr ""
-
msgid "Can't scan the code?"
msgstr ""
@@ -4320,6 +4445,9 @@ msgstr ""
msgid "Cannot create the abuse report. This user has been blocked."
msgstr ""
+msgid "Cannot enable shared runners because parent group does not allow it"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -4425,6 +4553,15 @@ msgstr ""
msgid "Change your password or recover your current one"
msgstr ""
+msgid "ChangeReviewer|Reviewer changed from %{old} to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Reviewer changed to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Unassigned"
+msgstr ""
+
msgid "ChangeTypeActionLabel|Pick into branch"
msgstr ""
@@ -4464,6 +4601,9 @@ msgstr ""
msgid "Changes the title to \"%{title_param}\"."
msgstr ""
+msgid "Changes were successfully made."
+msgstr ""
+
msgid "Changes won't take place until the index is %{link_start}recreated%{link_end}."
msgstr ""
@@ -4869,6 +5009,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove variable"
+msgstr ""
+
msgid "CiVariables|Remove variable row"
msgstr ""
@@ -4947,9 +5090,6 @@ msgstr ""
msgid "Clear due date"
msgstr ""
-msgid "Clear input"
-msgstr ""
-
msgid "Clear recent searches"
msgstr ""
@@ -4998,6 +5138,9 @@ msgstr ""
msgid "Client authentication key password"
msgstr ""
+msgid "Client request timeout"
+msgstr ""
+
msgid "Clients"
msgstr ""
@@ -5082,6 +5225,27 @@ msgstr ""
msgid "Cluster type must be specificed for Stages::ClusterEndpointInserter"
msgstr ""
+msgid "ClusterAgents|Configuration"
+msgstr ""
+
+msgid "ClusterAgents|Connect your cluster with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate Kubernetes with a GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Name"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Agent also requires %{linkStart}enabling the Agent Server%{linkEnd}"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Kubernetes Agent allows an Infrastructure as Code, GitOps approach to integrating Kubernetes clusters with GitLab. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "ClusterAgent|This feature is only available for premium plans"
msgstr ""
@@ -5151,10 +5315,10 @@ msgstr ""
msgid "ClusterIntegration|All installed applications and related resources"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster."
+msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{linkStart}More information%{linkEnd}"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{startLink}More information%{endLink}"
+msgid "ClusterIntegration|Allow GitLab to manage namespaces and service accounts for this cluster."
msgstr ""
msgid "ClusterIntegration|Alternatively, "
@@ -5175,6 +5339,9 @@ msgstr ""
msgid "ClusterIntegration|An error occurred while trying to fetch zone machine types: %{error}"
msgstr ""
+msgid "ClusterIntegration|An unknown error occurred while attempting to connect to Kubernetes."
+msgstr ""
+
msgid "ClusterIntegration|Any project namespaces"
msgstr ""
@@ -5190,6 +5357,9 @@ msgstr ""
msgid "ClusterIntegration|Authenticate with Amazon Web Services"
msgstr ""
+msgid "ClusterIntegration|Authentication Error"
+msgstr ""
+
msgid "ClusterIntegration|Base domain"
msgstr ""
@@ -5208,13 +5378,22 @@ msgstr ""
msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}security group %{externalLinkIcon} %{endLink} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
+msgid "ClusterIntegration|Check your CA certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Check your cluster status"
+msgstr ""
+
+msgid "ClusterIntegration|Check your token"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}subnets %{externalLinkIcon} %{endLink} in your VPC where your worker nodes will run."
+msgid "ClusterIntegration|Choose the %{linkStart}security group %{linkEnd} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
msgstr ""
-msgid "ClusterIntegration|Choose the worker node %{startLink}instance type %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Choose the %{linkStart}subnets %{linkEnd} in your VPC where your worker nodes will run."
+msgstr ""
+
+msgid "ClusterIntegration|Choose the worker node %{linkStart}instance type%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Choose which applications to install on your Kubernetes cluster."
@@ -5226,10 +5405,7 @@ msgstr ""
msgid "ClusterIntegration|Clear cluster cache"
msgstr ""
-msgid "ClusterIntegration|Clear the local cache of namespace and service accounts. This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
-msgstr ""
-
-msgid "ClusterIntegration|Cluster being created"
+msgid "ClusterIntegration|Clear the local cache of namespace and service accounts."
msgstr ""
msgid "ClusterIntegration|Cluster management project (alpha)"
@@ -5241,15 +5417,21 @@ msgstr ""
msgid "ClusterIntegration|Cluster_applications artifact too big. Maximum allowable size: %{human_size}"
msgstr ""
-msgid "ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters."
+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|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}"
+msgid "ClusterIntegration|Clusters connected with a certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Connect cluster with certificate"
msgstr ""
msgid "ClusterIntegration|Connect existing cluster"
msgstr ""
+msgid "ClusterIntegration|Connection Error"
+msgstr ""
+
msgid "ClusterIntegration|Copy API URL"
msgstr ""
@@ -5325,6 +5507,12 @@ msgstr ""
msgid "ClusterIntegration|Deletes all GitLab resources attached to this cluster during removal"
msgstr ""
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared."
+msgstr ""
+
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared. %{linkStart}More information%{linkEnd}"
+msgstr ""
+
msgid "ClusterIntegration|Did you know?"
msgstr ""
@@ -5394,6 +5582,9 @@ msgstr ""
msgid "ClusterIntegration|Fluentd is an open source data collector, which lets you unify the data collection and consumption for a better use and understanding of data. It requires at least one of the following logs to be successfully installed."
msgstr ""
+msgid "ClusterIntegration|GitLab Agent managed clusters"
+msgstr ""
+
msgid "ClusterIntegration|GitLab Container Network Policies"
msgstr ""
@@ -5406,6 +5597,12 @@ msgstr ""
msgid "ClusterIntegration|GitLab Runner connects to the repository and executes CI/CD jobs, pushing results back and deploying applications to production."
msgstr ""
+msgid "ClusterIntegration|GitLab failed to authenticate."
+msgstr ""
+
+msgid "ClusterIntegration|GitLab failed to connect to the cluster."
+msgstr ""
+
msgid "ClusterIntegration|GitLab-managed cluster"
msgstr ""
@@ -5427,6 +5624,9 @@ msgstr ""
msgid "ClusterIntegration|Group cluster"
msgstr ""
+msgid "ClusterIntegration|HTTP Error"
+msgstr ""
+
msgid "ClusterIntegration|Helm Tiller"
msgstr ""
@@ -5460,7 +5660,10 @@ msgstr ""
msgid "ClusterIntegration|Instance type"
msgstr ""
-msgid "ClusterIntegration|Integrate Kubernetes cluster automation"
+msgid "ClusterIntegration|Integrate Kubernetes with a cluster certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Integrate with a cluster certificate"
msgstr ""
msgid "ClusterIntegration|Issuer Email"
@@ -5496,9 +5699,6 @@ msgstr ""
msgid "ClusterIntegration|Knative extends Kubernetes to provide a set of middleware components that are essential to build modern, source-centric, and container-based applications that can run anywhere: on premises, in the cloud, or even in a third-party data center."
msgstr ""
-msgid "ClusterIntegration|Kubernetes cluster"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes cluster is being created..."
msgstr ""
@@ -5511,9 +5711,6 @@ msgstr ""
msgid "ClusterIntegration|Kubernetes clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr ""
-msgid "ClusterIntegration|Kubernetes clusters can be used to deploy applications and to provide Review Apps for this project"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes version"
msgstr ""
@@ -5526,7 +5723,7 @@ msgstr ""
msgid "ClusterIntegration|Learn more about %{help_link_start}zones%{help_link_end}."
msgstr ""
-msgid "ClusterIntegration|Learn more about %{startLink}Regions %{externalLinkIcon}%{endLink}."
+msgid "ClusterIntegration|Learn more about %{linkStart}Regions%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Learn more about Kubernetes"
@@ -5571,12 +5768,18 @@ msgstr ""
msgid "ClusterIntegration|Machine type"
msgstr ""
+msgid "ClusterIntegration|Make sure your API endpoint is correct"
+msgstr ""
+
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create Kubernetes clusters"
msgstr ""
msgid "ClusterIntegration|Manage your Kubernetes cluster by visiting %{provider_link}"
msgstr ""
+msgid "ClusterIntegration|Namespace per environment"
+msgstr ""
+
msgid "ClusterIntegration|No IAM Roles found"
msgstr ""
@@ -5622,6 +5825,9 @@ msgstr ""
msgid "ClusterIntegration|No zones matched your search"
msgstr ""
+msgid "ClusterIntegration|Node calculations use the Kubernetes Metrics API. Make sure your cluster has metrics installed"
+msgstr ""
+
msgid "ClusterIntegration|Number of nodes"
msgstr ""
@@ -5664,6 +5870,9 @@ msgstr ""
msgid "ClusterIntegration|RBAC-enabled cluster"
msgstr ""
+msgid "ClusterIntegration|Read our %{linkStart}help page%{linkEnd} on Kubernetes cluster integration."
+msgstr ""
+
msgid "ClusterIntegration|Read our %{link_start}help page%{link_end} on Kubernetes cluster integration."
msgstr ""
@@ -5766,7 +5975,7 @@ msgstr ""
msgid "ClusterIntegration|Select a VPC to choose a subnet"
msgstr ""
-msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{linkStart}Amazon Web Services %{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select a network to choose a subnetwork"
@@ -5799,7 +6008,7 @@ msgstr ""
msgid "ClusterIntegration|Select project to choose zone"
msgstr ""
-msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select zone"
@@ -5889,9 +6098,18 @@ msgstr ""
msgid "ClusterIntegration|There was a problem authenticating with your cluster. Please ensure your CA Certificate and Token are valid."
msgstr ""
+msgid "ClusterIntegration|There was an HTTP error when connecting to your cluster."
+msgstr ""
+
msgid "ClusterIntegration|This account must have permissions to create a Kubernetes cluster in the %{link_to_container_project} specified below"
msgstr ""
+msgid "ClusterIntegration|This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
+msgstr ""
+
+msgid "ClusterIntegration|This is necessary to clear existing environment-namespace associations from clusters previously managed by GitLab."
+msgstr ""
+
msgid "ClusterIntegration|This option will allow you to install applications on RBAC clusters."
msgstr ""
@@ -5916,9 +6134,21 @@ msgstr ""
msgid "ClusterIntegration|To use a new project, first create one on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}."
msgstr ""
+msgid "ClusterIntegration|Troubleshooting tips:"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Authenticate"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Connect"
+msgstr ""
+
msgid "ClusterIntegration|Uninstall %{appTitle}"
msgstr ""
+msgid "ClusterIntegration|Unknown Error"
+msgstr ""
+
msgid "ClusterIntegration|Update %{appTitle}"
msgstr ""
@@ -5979,7 +6209,7 @@ msgstr ""
msgid "ClusterIntegration|Your cluster API is unreachable. Please ensure your API URL is correct."
msgstr ""
-msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Zone"
@@ -6099,6 +6329,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse all threads"
+msgstr ""
+
msgid "Collapse approvers"
msgstr ""
@@ -6247,7 +6480,7 @@ msgstr ""
msgid "Commit…"
msgstr ""
-msgid "Company"
+msgid "Community forum"
msgstr ""
msgid "Company name"
@@ -6256,6 +6489,9 @@ msgstr ""
msgid "Compare"
msgstr ""
+msgid "Compare %{oldCommitId}...%{newCommitId}"
+msgstr ""
+
msgid "Compare Git revisions"
msgstr ""
@@ -6271,6 +6507,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare submodule commit revisions"
+msgstr ""
+
msgid "Compare with previous version"
msgstr ""
@@ -6406,6 +6645,9 @@ msgstr ""
msgid "Configure the way a user creates a new account."
msgstr ""
+msgid "Configure which lists are shown for anyone who visits this board"
+msgstr ""
+
msgid "Confirm"
msgstr ""
@@ -6628,6 +6870,9 @@ msgstr[0] ""
msgid "ContainerRegistry|Set cleanup policy"
msgstr ""
+msgid "ContainerRegistry|Some tags were not deleted"
+msgstr ""
+
msgid "ContainerRegistry|Something went wrong while fetching the cleanup policy."
msgstr ""
@@ -6667,6 +6912,9 @@ msgstr ""
msgid "ContainerRegistry|Tags with names matching this regex pattern will %{italicStart}expire:%{italicEnd}"
msgstr ""
+msgid "ContainerRegistry|The cleanup policy timed out before it could delete all tags. An administrator can %{adminLinkStart}manually run cleanup now%{adminLinkEnd} or you can wait for the cleanup policy to automatically run again. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "ContainerRegistry|The last tag related to this image was recently removed. This empty image and any associated data will be automatically removed as part of the regular Garbage Collection process. If you have any questions, contact your administrator."
msgstr ""
@@ -6799,6 +7047,9 @@ msgstr ""
msgid "Contributions per group member"
msgstr ""
+msgid "Contributor"
+msgstr ""
+
msgid "Contributors"
msgstr ""
@@ -6928,6 +7179,9 @@ msgstr ""
msgid "Could not change HEAD: branch '%{branch}' does not exist"
msgstr ""
+msgid "Could not commit. An unexpected error occurred."
+msgstr ""
+
msgid "Could not connect to FogBugz, check your URL"
msgstr ""
@@ -6967,6 +7221,9 @@ msgstr ""
msgid "Could not find iteration"
msgstr ""
+msgid "Could not load instance counts. Please refresh the page to try again."
+msgstr ""
+
msgid "Could not remove the trigger."
msgstr ""
@@ -6991,10 +7248,10 @@ msgstr ""
msgid "Could not save prometheus manual configuration"
msgstr ""
-msgid "Could not udpdate wiki page"
+msgid "Could not update the LDAP settings"
msgstr ""
-msgid "Could not update the LDAP settings"
+msgid "Could not update wiki page"
msgstr ""
msgid "Could not upload your designs as one or more files uploaded are not supported."
@@ -7650,6 +7907,9 @@ msgstr ""
msgid "DastProfiles|Are you sure you want to delete this profile?"
msgstr ""
+msgid "DastProfiles|Could not create site validation token. Please refresh the page, or try again later."
+msgstr ""
+
msgid "DastProfiles|Could not create the scanner profile. Please try again."
msgstr ""
@@ -7674,6 +7934,12 @@ msgstr ""
msgid "DastProfiles|Could not fetch site profiles. Please refresh the page, or try again later."
msgstr ""
+msgid "DastProfiles|Could not retrieve site validation status. Please refresh the page, or try again later."
+msgstr ""
+
+msgid "DastProfiles|Could not update the scanner profile. Please try again."
+msgstr ""
+
msgid "DastProfiles|Could not update the site profile. Please try again."
msgstr ""
@@ -7689,7 +7955,7 @@ msgstr ""
msgid "DastProfiles|Download validation text file"
msgstr ""
-msgid "DastProfiles|Edit feature will come soon. Please create a new profile if changes needed"
+msgid "DastProfiles|Edit scanner profile"
msgstr ""
msgid "DastProfiles|Edit site profile"
@@ -7722,6 +7988,9 @@ msgstr ""
msgid "DastProfiles|No profiles created yet"
msgstr ""
+msgid "DastProfiles|Passive"
+msgstr ""
+
msgid "DastProfiles|Please enter a valid URL format, ex: http://www.example.com/home"
msgstr ""
@@ -7737,6 +8006,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan mode"
+msgstr ""
+
msgid "DastProfiles|Scanner Profile"
msgstr ""
@@ -7776,10 +8048,10 @@ msgstr ""
msgid "DastProfiles|Text file validation"
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
+msgid "DastProfiles|The maximum number of minutes allowed for the spider to traverse the site."
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the spider to traverse the site."
+msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
msgstr ""
msgid "DastProfiles|Validate"
@@ -7812,6 +8084,9 @@ msgstr ""
msgid "Date picker"
msgstr ""
+msgid "Date range"
+msgstr ""
+
msgid "Date range cannot exceed %{maxDateRange} days."
msgstr ""
@@ -7836,6 +8111,9 @@ msgstr ""
msgid "Days to merge"
msgstr ""
+msgid "Dear Administrator,"
+msgstr ""
+
msgid "Debug"
msgstr ""
@@ -7947,12 +8225,18 @@ msgstr ""
msgid "Delete"
msgstr ""
+msgid "Delete %{name}"
+msgstr ""
+
msgid "Delete Comment"
msgstr ""
msgid "Delete Snippet"
msgstr ""
+msgid "Delete Value Stream"
+msgstr ""
+
msgid "Delete account"
msgstr ""
@@ -7974,9 +8258,6 @@ msgstr ""
msgid "Delete label: %{label_name} ?"
msgstr ""
-msgid "Delete license"
-msgstr ""
-
msgid "Delete list"
msgstr ""
@@ -8052,15 +8333,6 @@ msgstr ""
msgid "Deleting a project places it into a read-only state until %{date}, at which point the project will be permanently deleted. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "Deleting the license failed."
-msgstr ""
-
-msgid "Deleting the license failed. The license was not found."
-msgstr ""
-
-msgid "Deleting the license failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "Deleting the project will delete its repository and all related resources including issues, merge requests etc."
msgstr ""
@@ -8550,7 +8822,10 @@ msgstr ""
msgid "DesignManagement|The maximum number of designs allowed to be uploaded is %{upload_limit}. Please try again."
msgstr ""
-msgid "DesignManagement|To upload designs, you'll need to enable LFS. %{requirements_link_start}More information%{requirements_link_end}"
+msgid "DesignManagement|There was an error moving your designs. Please upload your designs below."
+msgstr ""
+
+msgid "DesignManagement|To upload designs, you'll need to enable LFS and have admin enable hashed storage. %{requirements_link_start}More information%{requirements_link_end}"
msgstr ""
msgid "DesignManagement|Unresolve thread"
@@ -8562,6 +8837,9 @@ msgstr ""
msgid "DesignManagement|Upload skipped."
msgstr ""
+msgid "DesignManagement|Your designs are being copied and are on their way… Please refresh to update."
+msgstr ""
+
msgid "DesignManagement|and %{moreCount} more."
msgstr ""
@@ -8619,6 +8897,9 @@ msgstr ""
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
+msgid "Direct member"
+msgstr ""
+
msgid "Direction"
msgstr ""
@@ -8667,9 +8948,6 @@ msgstr ""
msgid "Discard draft"
msgstr ""
-msgid "Discard review"
-msgstr ""
-
msgid "DiscordService|Discord Notifications"
msgstr ""
@@ -8737,10 +9015,10 @@ msgstr ""
msgid "Dismiss Merge Request promotion"
msgstr ""
-msgid "Dismiss Selected"
+msgid "Dismiss Value Stream Analytics introduction box"
msgstr ""
-msgid "Dismiss Value Stream Analytics introduction box"
+msgid "Dismiss selected"
msgstr ""
msgid "Dismiss trial promotion"
@@ -8791,9 +9069,6 @@ msgstr ""
msgid "Documents reindexed: %{processed_documents} (%{percentage}%%)"
msgstr ""
-msgid "Doing"
-msgstr ""
-
msgid "Domain"
msgstr ""
@@ -8989,9 +9264,6 @@ msgstr ""
msgid "Edit environment"
msgstr ""
-msgid "Edit file"
-msgstr ""
-
msgid "Edit files in the editor and commit changes here"
msgstr ""
@@ -9004,6 +9276,12 @@ msgstr ""
msgid "Edit identity for %{user_name}"
msgstr ""
+msgid "Edit in Web IDE"
+msgstr ""
+
+msgid "Edit in single-file editor"
+msgstr ""
+
msgid "Edit issues"
msgstr ""
@@ -9031,10 +9309,10 @@ msgstr ""
msgid "Editing"
msgstr ""
-msgid "Elasticsearch"
+msgid "Elasticsearch AWS IAM credentials"
msgstr ""
-msgid "Elasticsearch AWS IAM credentials"
+msgid "Elasticsearch HTTP client timeout value in seconds."
msgstr ""
msgid "Elasticsearch indexing restrictions"
@@ -9043,9 +9321,6 @@ msgstr ""
msgid "Elasticsearch indexing started"
msgstr ""
-msgid "Elasticsearch integration. Elasticsearch AWS IAM."
-msgstr ""
-
msgid "Elasticsearch reindexing is already in progress"
msgstr ""
@@ -9073,9 +9348,6 @@ msgstr ""
msgid "Email Notification"
msgstr ""
-msgid "Email address"
-msgstr ""
-
msgid "Email could not be sent"
msgstr ""
@@ -9139,6 +9411,9 @@ msgstr ""
msgid "Emails sent from Service Desk will have this name"
msgstr ""
+msgid "Emails sent to %{email} will still be supported"
+msgstr ""
+
msgid "Emails separated by comma"
msgstr ""
@@ -9172,9 +9447,18 @@ msgstr ""
msgid "Enable"
msgstr ""
+msgid "Enable %{link_start}Gitpod%{link_end} integration to launch a development environment in your browser directly from GitLab."
+msgstr ""
+
msgid "Enable Auto DevOps"
msgstr ""
+msgid "Enable Gitpod"
+msgstr ""
+
+msgid "Enable Gitpod?"
+msgstr ""
+
msgid "Enable HTML emails"
msgstr ""
@@ -9304,9 +9588,6 @@ msgstr ""
msgid "Encountered an error while rendering: %{err}"
msgstr ""
-msgid "End date"
-msgstr ""
-
msgid "Ends at (UTC)"
msgstr ""
@@ -9466,7 +9747,7 @@ msgstr ""
msgid "EnvironmentsDashboard|The environments dashboard provides a summary of each project's environments' status, including pipeline and alert statuses."
msgstr ""
-msgid "EnvironmentsDashboard|This dashboard displays a maximum of 7 projects and 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
+msgid "EnvironmentsDashboard|This dashboard displays 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
msgstr ""
msgid "Environments|An error occurred while canceling the auto stop, please try again"
@@ -9787,6 +10068,9 @@ msgstr ""
msgid "Error deleting project. Check logs for error details."
msgstr ""
+msgid "Error fetching burnup chart data"
+msgstr ""
+
msgid "Error fetching diverging counts for branches. Please try again."
msgstr ""
@@ -9865,6 +10149,9 @@ msgstr ""
msgid "Error occurred when saving assignees"
msgstr ""
+msgid "Error occurred when saving reviewers"
+msgstr ""
+
msgid "Error occurred when toggling the notification subscription"
msgstr ""
@@ -10117,10 +10404,13 @@ msgstr ""
msgid "Expand all"
msgstr ""
-msgid "Expand approvers"
+msgid "Expand all files"
msgstr ""
-msgid "Expand dropdown"
+msgid "Expand all threads"
+msgstr ""
+
+msgid "Expand approvers"
msgstr ""
msgid "Expand milestones"
@@ -10291,6 +10581,9 @@ msgstr ""
msgid "Failed to create Merge Request. Please try again."
msgstr ""
+msgid "Failed to create To-Do for the design."
+msgstr ""
+
msgid "Failed to create a branch for this issue. Please try again."
msgstr ""
@@ -10330,6 +10623,12 @@ msgstr ""
msgid "Failed to load authors. Please try again."
msgstr ""
+msgid "Failed to load branches. Please try again."
+msgstr ""
+
+msgid "Failed to load deploy keys."
+msgstr ""
+
msgid "Failed to load emoji list."
msgstr ""
@@ -10345,6 +10644,9 @@ msgstr ""
msgid "Failed to load groups & users."
msgstr ""
+msgid "Failed to load groups, users and deploy keys."
+msgstr ""
+
msgid "Failed to load labels. Please try again."
msgstr ""
@@ -10354,6 +10656,12 @@ msgstr ""
msgid "Failed to load related branches"
msgstr ""
+msgid "Failed to load sidebar confidential toggle"
+msgstr ""
+
+msgid "Failed to load sidebar lock status"
+msgstr ""
+
msgid "Failed to load stacktrace."
msgstr ""
@@ -10381,6 +10689,9 @@ msgstr ""
msgid "Failed to publish issue on status page."
msgstr ""
+msgid "Failed to remove To-Do for the design."
+msgstr ""
+
msgid "Failed to remove a Zoom meeting"
msgstr ""
@@ -10423,6 +10734,9 @@ msgstr ""
msgid "Failed to signing using smartcard authentication"
msgstr ""
+msgid "Failed to toggle To-Do for the design."
+msgstr ""
+
msgid "Failed to update branch!"
msgstr ""
@@ -10535,7 +10849,7 @@ msgstr ""
msgid "FeatureFlags|Edit User List"
msgstr ""
-msgid "FeatureFlags|Enable features for specific users and specific environments by defining feature flag strategies."
+msgid "FeatureFlags|Enable features for specific users and environments by configuring feature flag strategies."
msgstr ""
msgid "FeatureFlags|Environment Spec"
@@ -10595,7 +10909,7 @@ msgstr ""
msgid "FeatureFlags|Include additional user IDs"
msgstr ""
-msgid "FeatureFlags|Install a %{docs_link_anchored_start}compatible client library%{docs_link_anchored_end} and specify the API URL, application name, and instance ID during the configuration setup. %{docs_link_start}More Information%{docs_link_end}"
+msgid "FeatureFlags|Install a %{docsLinkAnchoredStart}compatible client library%{docsLinkAnchoredEnd} and specify the API URL, application name, and instance ID during the configuration setup. %{docsLinkStart}More Information%{docsLinkEnd}"
msgstr ""
msgid "FeatureFlags|Instance ID"
@@ -10607,6 +10921,9 @@ msgstr ""
msgid "FeatureFlags|Loading feature flags"
msgstr ""
+msgid "FeatureFlags|Loading user lists"
+msgstr ""
+
msgid "FeatureFlags|More information"
msgstr ""
@@ -10625,7 +10942,7 @@ msgstr ""
msgid "FeatureFlags|New feature flag"
msgstr ""
-msgid "FeatureFlags|New list"
+msgid "FeatureFlags|New user list"
msgstr ""
msgid "FeatureFlags|Percent of users"
@@ -10664,6 +10981,9 @@ msgstr ""
msgid "FeatureFlags|There was an error fetching the feature flags."
msgstr ""
+msgid "FeatureFlags|There was an error fetching the user lists."
+msgstr ""
+
msgid "FeatureFlags|There was an error retrieving user lists"
msgstr ""
@@ -10679,6 +10999,9 @@ msgstr ""
msgid "FeatureFlags|User List"
msgstr ""
+msgid "FeatureFlags|User Lists"
+msgstr ""
+
msgid "FeatureFlag|List"
msgstr ""
@@ -10706,15 +11029,6 @@ msgstr ""
msgid "Fetching incoming email"
msgstr ""
-msgid "Fetching licenses failed."
-msgstr ""
-
-msgid "Fetching licenses failed. The request endpoint was not found."
-msgstr ""
-
-msgid "Fetching licenses failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "File"
msgstr ""
@@ -10817,12 +11131,21 @@ msgstr ""
msgid "Filter by status"
msgstr ""
+msgid "Filter by test cases that are currently archived."
+msgstr ""
+
+msgid "Filter by test cases that are currently opened."
+msgstr ""
+
msgid "Filter by two-factor authentication"
msgstr ""
msgid "Filter by user"
msgstr ""
+msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
+msgstr ""
+
msgid "Filter pipelines"
msgstr ""
@@ -10838,7 +11161,7 @@ msgstr ""
msgid "Filter results..."
msgstr ""
-msgid "Filter your projects by name"
+msgid "Filter your repositories by name"
msgstr ""
msgid "Filter..."
@@ -10847,7 +11170,7 @@ msgstr ""
msgid "Find File"
msgstr ""
-msgid "Find bugs in your code with coverage-guided fuzzing"
+msgid "Find bugs in your code with coverage-guided fuzzing."
msgstr ""
msgid "Find by path"
@@ -10874,9 +11197,6 @@ msgstr ""
msgid "Finish editing this message first!"
msgstr ""
-msgid "Finish review"
-msgstr ""
-
msgid "Finish setting up your dedicated account for %{group_name}."
msgstr ""
@@ -10946,6 +11266,9 @@ msgstr ""
msgid "Footer message"
msgstr ""
+msgid "For a faster browsing experience, some files are collapsed by default."
+msgstr ""
+
msgid "For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
@@ -10955,6 +11278,9 @@ msgstr ""
msgid "For more info, read the documentation."
msgstr ""
+msgid "For more information on how the number of active users is calculated, see the %{self_managed_subscriptions_doc_link} documentation."
+msgstr ""
+
msgid "For more information, go to the "
msgstr ""
@@ -11093,6 +11419,9 @@ msgstr ""
msgid "Generate new token"
msgstr ""
+msgid "Generic package file size in bytes"
+msgstr ""
+
msgid "Geo"
msgstr ""
@@ -11354,6 +11683,9 @@ msgstr ""
msgid "Geo|Please refer to Geo Troubleshooting."
msgstr ""
+msgid "Geo|Primary node"
+msgstr ""
+
msgid "Geo|Project"
msgstr ""
@@ -11396,6 +11728,9 @@ msgstr ""
msgid "Geo|Review replication status, and resynchronize and reverify items with the primary node."
msgstr ""
+msgid "Geo|Secondary node"
+msgstr ""
+
msgid "Geo|Status"
msgstr ""
@@ -11435,6 +11770,9 @@ msgstr ""
msgid "Geo|URL must be a valid url (ex: https://gitlab.com)"
msgstr ""
+msgid "Geo|Undefined"
+msgstr ""
+
msgid "Geo|Unknown state"
msgstr ""
@@ -11510,10 +11848,16 @@ msgstr ""
msgid "GitHub import"
msgstr ""
+msgid "GitLab"
+msgstr ""
+
msgid "GitLab / Unsubscribe"
msgstr ""
-msgid "GitLab Enterprise Edition %{plan}"
+msgid "GitLab API"
+msgstr ""
+
+msgid "GitLab Billing Team."
msgstr ""
msgid "GitLab Group Runners can execute code for all the projects in this group."
@@ -11525,12 +11869,18 @@ msgstr ""
msgid "GitLab Issue"
msgstr ""
+msgid "GitLab Pages"
+msgstr ""
+
msgid "GitLab Service Desk is a simple way to allow people to create issues in your GitLab instance without needing their own user account. It provides a unique email address for end users to create issues in a project, and replies can be sent either through the GitLab interface or by email. End users will only see the thread through email."
msgstr ""
msgid "GitLab Shared Runners execute code of different projects on the same Runner unless you configure GitLab Runner Autoscale with MaxBuilds 1 (which it is on GitLab.com)."
msgstr ""
+msgid "GitLab Shell"
+msgstr ""
+
msgid "GitLab Support Bot"
msgstr ""
@@ -11540,7 +11890,7 @@ msgstr ""
msgid "GitLab User"
msgstr ""
-msgid "GitLab allows you to continue using your license even if you exceed the number of seats you purchased. You will be required to pay for these seats when you renew your license."
+msgid "GitLab Workhorse"
msgstr ""
msgid "GitLab commit"
@@ -11708,6 +12058,21 @@ msgstr ""
msgid "Gitlab Pages"
msgstr ""
+msgid "Gitpod"
+msgstr ""
+
+msgid "Gitpod|Add the URL to your Gitpod instance configured to read your GitLab projects."
+msgstr ""
+
+msgid "Gitpod|Enable Gitpod integration"
+msgstr ""
+
+msgid "Gitpod|Gitpod URL"
+msgstr ""
+
+msgid "Gitpod|e.g. https://gitpod.example.com"
+msgstr ""
+
msgid "Given access %{time_ago}"
msgstr ""
@@ -12215,9 +12580,6 @@ msgstr ""
msgid "GroupSAML|Valid SAML Response"
msgstr ""
-msgid "GroupSAML|With group managed accounts enabled, all the users without a group managed account will be excluded from the group."
-msgstr ""
-
msgid "GroupSAML|With prohibit outer forks flag enabled group members will be able to fork project only inside your group."
msgstr ""
@@ -12431,10 +12793,10 @@ msgstr ""
msgid "GroupsNew|Create group"
msgstr ""
-msgid "GroupsNew|GitLab group export"
+msgid "GroupsNew|Import"
msgstr ""
-msgid "GroupsNew|Import"
+msgid "GroupsNew|Import a GitLab group export file"
msgstr ""
msgid "GroupsNew|Import group"
@@ -12576,6 +12938,9 @@ msgid "Hide chart"
msgid_plural "Hide charts"
msgstr[0] ""
+msgid "Hide comments on this file"
+msgstr ""
+
msgid "Hide details"
msgstr ""
@@ -12619,6 +12984,15 @@ msgstr ""
msgid "Highest role:"
msgstr ""
+msgid "HighlightBar|Alert events:"
+msgstr ""
+
+msgid "HighlightBar|Alert start time:"
+msgstr ""
+
+msgid "HighlightBar|Original alert:"
+msgstr ""
+
msgid "History"
msgstr ""
@@ -12796,6 +13170,9 @@ msgstr ""
msgid "If enabled, access to projects will be validated on an external service using their classification label."
msgstr ""
+msgid "If the number of active users exceeds the user limit, you will be charged for the number of %{users_over_license_link} at your next license reconciliation."
+msgstr ""
+
msgid "If there is no previous license or if the previous license has expired, some GitLab functionality will be blocked until a new, valid license is uploaded."
msgstr ""
@@ -12835,9 +13212,6 @@ msgstr ""
msgid "If your HTTP repository is not publicly accessible, add your credentials."
msgstr ""
-msgid "Iglu registry URL (optional)"
-msgstr ""
-
msgid "Ignore"
msgstr ""
@@ -12874,6 +13248,14 @@ msgstr ""
msgid "Import"
msgstr ""
+msgid "Import %d compatible repository"
+msgid_plural "Import %d compatible repositories"
+msgstr[0] ""
+
+msgid "Import %d repository"
+msgid_plural "Import %d repositories"
+msgstr[0] ""
+
msgid "Import CSV"
msgstr ""
@@ -12883,15 +13265,9 @@ msgstr ""
msgid "Import all compatible projects"
msgstr ""
-msgid "Import all compatible repositories"
-msgstr ""
-
msgid "Import all projects"
msgstr ""
-msgid "Import all repositories"
-msgstr ""
-
msgid "Import an exported GitLab project"
msgstr ""
@@ -12979,6 +13355,9 @@ msgstr ""
msgid "ImportProjects|Error importing repository %{project_safe_import_url} into %{project_full_path} - %{message}"
msgstr ""
+msgid "ImportProjects|Import repositories"
+msgstr ""
+
msgid "ImportProjects|Importing the project failed"
msgstr ""
@@ -12991,7 +13370,7 @@ msgstr ""
msgid "ImportProjects|Requesting your %{provider} repositories failed"
msgstr ""
-msgid "ImportProjects|Select the projects you want to import"
+msgid "ImportProjects|Select the repositories you want to import"
msgstr ""
msgid "ImportProjects|The remote data could not be imported."
@@ -13027,9 +13406,6 @@ msgstr ""
msgid "In order to enable Service Desk for your instance, you must first set up incoming email."
msgstr ""
-msgid "In order to gather accurate feature usage data, it can take 1 to 2 weeks to see your index."
-msgstr ""
-
msgid "In order to personalize your experience with GitLab%{br_tag}we would like to know a bit more about you."
msgstr ""
@@ -13060,18 +13436,30 @@ msgstr ""
msgid "IncidentManagement|Create incident"
msgstr ""
+msgid "IncidentManagement|Critical - S1"
+msgstr ""
+
msgid "IncidentManagement|Date created"
msgstr ""
msgid "IncidentManagement|Display your incidents in a dedicated view"
msgstr ""
+msgid "IncidentManagement|High - S2"
+msgstr ""
+
msgid "IncidentManagement|Incident"
msgstr ""
msgid "IncidentManagement|Incidents"
msgstr ""
+msgid "IncidentManagement|Low - S4"
+msgstr ""
+
+msgid "IncidentManagement|Medium - S3"
+msgstr ""
+
msgid "IncidentManagement|No incidents to display."
msgstr ""
@@ -13084,6 +13472,9 @@ msgstr ""
msgid "IncidentManagement|Published to status page"
msgstr ""
+msgid "IncidentManagement|Severity"
+msgstr ""
+
msgid "IncidentManagement|There are no closed incidents"
msgstr ""
@@ -13093,6 +13484,9 @@ msgstr ""
msgid "IncidentManagement|Unassigned"
msgstr ""
+msgid "IncidentManagement|Unknown"
+msgstr ""
+
msgid "IncidentManagement|Unpublished"
msgstr ""
@@ -13114,6 +13508,15 @@ msgstr ""
msgid "Incidents"
msgstr ""
+msgid "Incident|Alert details"
+msgstr ""
+
+msgid "Incident|Summary"
+msgstr ""
+
+msgid "Incident|There was an issue loading alert data. Please try again."
+msgstr ""
+
msgid "Include a Terms of Service agreement and Privacy Policy that all users must accept."
msgstr ""
@@ -13174,6 +13577,9 @@ msgstr ""
msgid "Information about additional Pages templates and how to install them can be found in our %{pages_getting_started_guide}."
msgstr ""
+msgid "Inherited"
+msgstr ""
+
msgid "Inherited:"
msgstr ""
@@ -13253,7 +13659,22 @@ msgstr ""
msgid "Instance administrators group already exists"
msgstr ""
-msgid "Instance license"
+msgid "InstanceStatistics|Groups"
+msgstr ""
+
+msgid "InstanceStatistics|Issues"
+msgstr ""
+
+msgid "InstanceStatistics|Merge Requests"
+msgstr ""
+
+msgid "InstanceStatistics|Pipelines"
+msgstr ""
+
+msgid "InstanceStatistics|Projects"
+msgstr ""
+
+msgid "InstanceStatistics|Users"
msgstr ""
msgid "Integration"
@@ -13265,6 +13686,12 @@ msgstr ""
msgid "Integrations"
msgstr ""
+msgid "Integrations|%{integration} settings saved and active."
+msgstr ""
+
+msgid "Integrations|%{integration} settings saved, but not active."
+msgstr ""
+
msgid "Integrations|All details"
msgstr ""
@@ -13274,6 +13701,12 @@ msgstr ""
msgid "Integrations|Comment settings:"
msgstr ""
+msgid "Integrations|Connection failed. Please check your settings."
+msgstr ""
+
+msgid "Integrations|Connection successful."
+msgstr ""
+
msgid "Integrations|Default settings are inherited from the group level."
msgstr ""
@@ -13289,6 +13722,15 @@ msgstr ""
msgid "Integrations|Includes commit title and branch"
msgstr ""
+msgid "Integrations|Projects using custom settings will not be impacted unless the project owner chooses to use instance-level defaults."
+msgstr ""
+
+msgid "Integrations|Save settings?"
+msgstr ""
+
+msgid "Integrations|Saving will update the default settings for all projects that are not using custom settings."
+msgstr ""
+
msgid "Integrations|Standard"
msgstr ""
@@ -13421,6 +13863,9 @@ msgstr ""
msgid "Invitation"
msgstr ""
+msgid "Invitation declined"
+msgstr ""
+
msgid "Invite"
msgstr ""
@@ -13472,6 +13917,42 @@ 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|%{linkStart}Read more%{linkEnd} about role permissions"
+msgstr ""
+
+msgid "InviteMembersModal|Access expiration date (optional)"
+msgstr ""
+
+msgid "InviteMembersModal|Cancel"
+msgstr ""
+
+msgid "InviteMembersModal|Choose a role permission"
+msgstr ""
+
+msgid "InviteMembersModal|GitLab member or Email address"
+msgstr ""
+
+msgid "InviteMembersModal|Invite"
+msgstr ""
+
+msgid "InviteMembersModal|Invite team members"
+msgstr ""
+
+msgid "InviteMembersModal|Search for members to invite"
+msgstr ""
+
+msgid "InviteMembersModal|User not invited. Feature coming soon!"
+msgstr ""
+
+msgid "InviteMembersModal|Users were succesfully added"
+msgstr ""
+
+msgid "InviteMembersModal|You're inviting members to the %{group_name} group"
+msgstr ""
+
+msgid "InviteMembers|Invite team members"
+msgstr ""
+
msgid "Invited"
msgstr ""
@@ -13526,10 +14007,13 @@ msgstr ""
msgid "Issue cannot be found."
msgstr ""
+msgid "Issue created from vulnerability %{vulnerability_link}"
+msgstr ""
+
msgid "Issue events"
msgstr ""
-msgid "Issue first depoloyed to production"
+msgid "Issue first deployed to production"
msgstr ""
msgid "Issue label"
@@ -13607,6 +14091,9 @@ msgstr ""
msgid "IssueTracker|Custom issue tracker"
msgstr ""
+msgid "IssueTracker|EWM work items tracker"
+msgstr ""
+
msgid "IssueTracker|Redmine issue tracker"
msgstr ""
@@ -13673,6 +14160,9 @@ msgstr ""
msgid "It looks like you have some draft commits in this branch."
msgstr ""
+msgid "It may be several days before you see feature usage data."
+msgstr ""
+
msgid "It must have a header row and at least two columns: the first column is the issue title and the second column is the issue description. The separator is automatically detected."
msgstr ""
@@ -13955,13 +14445,13 @@ msgstr ""
msgid "Join Zoom meeting"
msgstr ""
-msgid "Jul"
+msgid "Joined %{time_ago}"
msgstr ""
-msgid "July"
+msgid "Jul"
msgstr ""
-msgid "Jump to first unresolved thread"
+msgid "July"
msgstr ""
msgid "Jump to next unresolved thread"
@@ -13997,6 +14487,9 @@ msgstr ""
msgid "Keyboard shortcuts"
msgstr ""
+msgid "KeyboardKey|Ctrl+"
+msgstr ""
+
msgid "Keys"
msgstr ""
@@ -14045,6 +14538,9 @@ msgstr ""
msgid "LDAP Synchronization"
msgstr ""
+msgid "LDAP group settings"
+msgstr ""
+
msgid "LDAP settings"
msgstr ""
@@ -14054,6 +14550,9 @@ msgstr ""
msgid "LDAP sync in progress. This could take a few minutes. Refresh the page to see the changes."
msgstr ""
+msgid "LDAP synchronizations"
+msgstr ""
+
msgid "LFS"
msgstr ""
@@ -14133,7 +14632,16 @@ msgid "Last %d day"
msgid_plural "Last %d days"
msgstr[0] ""
-msgid "Last %{days} days"
+msgid "Last 2 weeks"
+msgstr ""
+
+msgid "Last 30 days"
+msgstr ""
+
+msgid "Last 60 days"
+msgstr ""
+
+msgid "Last 90 days"
msgstr ""
msgid "Last Accessed On"
@@ -14211,6 +14719,9 @@ msgstr ""
msgid "Last used on:"
msgstr ""
+msgid "Last week"
+msgstr ""
+
msgid "LastCommit|authored"
msgstr ""
@@ -14226,6 +14737,9 @@ msgstr ""
msgid "Latest pipeline for the most recent commit on this branch"
msgstr ""
+msgid "Launch a ready-to-code development environment for your project."
+msgstr ""
+
msgid "Lead"
msgstr ""
@@ -14599,6 +15113,9 @@ msgstr ""
msgid "List of all merge commits"
msgstr ""
+msgid "List options"
+msgstr ""
+
msgid "List settings"
msgstr ""
@@ -14611,9 +15128,6 @@ msgstr ""
msgid "List your Bitbucket Server repositories"
msgstr ""
-msgid "Lists"
-msgstr ""
-
msgid "Live preview"
msgstr ""
@@ -14860,6 +15374,12 @@ msgstr ""
msgid "Mark as done"
msgstr ""
+msgid "Mark as draft"
+msgstr ""
+
+msgid "Mark as ready"
+msgstr ""
+
msgid "Mark as resolved"
msgstr ""
@@ -14881,6 +15401,24 @@ msgstr ""
msgid "Markdown is supported"
msgstr ""
+msgid "MarkdownEditor|Add a link (%{modifierKey}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add a link (%{modifier_key}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifierKey}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifier_key}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifierKey}I)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifier_key}I)"
+msgstr ""
+
msgid "Marked For Deletion At - %{deletion_time}"
msgstr ""
@@ -14965,7 +15503,25 @@ msgstr ""
msgid "Max access level"
msgstr ""
-msgid "Max seats used"
+msgid "Max role"
+msgstr ""
+
+msgid "Max size 15 MB"
+msgstr ""
+
+msgid "Maximum Conan package file size in bytes"
+msgstr ""
+
+msgid "Maximum Maven package file size in bytes"
+msgstr ""
+
+msgid "Maximum NPM package file size in bytes"
+msgstr ""
+
+msgid "Maximum NuGet package file size in bytes"
+msgstr ""
+
+msgid "Maximum PyPI package file size in bytes"
msgstr ""
msgid "Maximum Users:"
@@ -15097,6 +15653,18 @@ msgstr ""
msgid "Members with access to %{strong_start}%{group_name}%{strong_end}"
msgstr ""
+msgid "Members|%{time} by %{user}"
+msgstr ""
+
+msgid "Members|Expired"
+msgstr ""
+
+msgid "Members|No expiration set"
+msgstr ""
+
+msgid "Members|in %{time}"
+msgstr ""
+
msgid "Memory Usage"
msgstr ""
@@ -15283,9 +15851,6 @@ msgstr ""
msgid "MergeRequests|Thread will be unresolved"
msgstr ""
-msgid "MergeRequests|Toggle comments for this file"
-msgstr ""
-
msgid "MergeRequests|View file @ %{commitId}"
msgstr ""
@@ -15346,6 +15911,9 @@ msgstr ""
msgid "Merging immediately isn't recommended as it may negatively impact the existing merge train. Read the %{docsLinkStart}documentation%{docsLinkEnd} for more information."
msgstr ""
+msgid "Message"
+msgstr ""
+
msgid "Messages"
msgstr ""
@@ -15729,18 +16297,12 @@ msgid "Milestone"
msgid_plural "Milestones"
msgstr[0] ""
-msgid "Milestone does not support burnup charts"
-msgstr ""
-
msgid "Milestone lists not available with your current license"
msgstr ""
msgid "Milestone lists show all issues from the selected milestone."
msgstr ""
-msgid "Milestone must have a start and due date"
-msgstr ""
-
msgid "MilestoneSidebar|Closed:"
msgstr ""
@@ -16107,6 +16669,9 @@ msgstr ""
msgid "Namespace"
msgstr ""
+msgid "Namespace ID:"
+msgstr ""
+
msgid "Namespace is empty"
msgstr ""
@@ -16191,6 +16756,9 @@ msgstr ""
msgid "NetworkPolicies|Allow all outbound traffic from %{selector} to %{ruleSelector} on %{ports}"
msgstr ""
+msgid "NetworkPolicies|Are you sure you want to delete this policy? This action cannot be undone."
+msgstr ""
+
msgid "NetworkPolicies|Choose whether to enforce this policy."
msgstr ""
@@ -16200,12 +16768,21 @@ msgstr ""
msgid "NetworkPolicies|Define this policy's location, conditions and actions."
msgstr ""
+msgid "NetworkPolicies|Delete policy"
+msgstr ""
+
+msgid "NetworkPolicies|Delete policy: %{policy}"
+msgstr ""
+
msgid "NetworkPolicies|Deny all traffic"
msgstr ""
msgid "NetworkPolicies|Description"
msgstr ""
+msgid "NetworkPolicies|Edit policy"
+msgstr ""
+
msgid "NetworkPolicies|Editor mode"
msgstr ""
@@ -16233,6 +16810,9 @@ msgstr ""
msgid "NetworkPolicies|Name"
msgstr ""
+msgid "NetworkPolicies|Namespace"
+msgstr ""
+
msgid "NetworkPolicies|Network Policy"
msgstr ""
@@ -16284,6 +16864,9 @@ msgstr ""
msgid "NetworkPolicies|Rules"
msgstr ""
+msgid "NetworkPolicies|Save changes"
+msgstr ""
+
msgid "NetworkPolicies|Something went wrong, failed to update policy"
msgstr ""
@@ -16296,6 +16879,9 @@ msgstr ""
msgid "NetworkPolicies|Traffic that does not match any rule will be blocked."
msgstr ""
+msgid "NetworkPolicies|Unable to parse policy"
+msgstr ""
+
msgid "NetworkPolicies|YAML editor"
msgstr ""
@@ -16408,6 +16994,9 @@ msgstr ""
msgid "New Snippet"
msgstr ""
+msgid "New Test Case"
+msgstr ""
+
msgid "New User"
msgstr ""
@@ -16507,6 +17096,9 @@ msgstr ""
msgid "New tag"
msgstr ""
+msgid "New test case"
+msgstr ""
+
msgid "New users set to external"
msgstr ""
@@ -16579,7 +17171,7 @@ msgstr ""
msgid "No changes"
msgstr ""
-msgid "No changes between %{ref_start}%{source_branch}%{ref_end} and %{ref_start}%{target_branch}%{ref_end}"
+msgid "No changes between %{sourceBranch} and %{targetBranch}"
msgstr ""
msgid "No child epics match applied filters"
@@ -16594,6 +17186,9 @@ msgstr ""
msgid "No containers available"
msgstr ""
+msgid "No content to show"
+msgstr ""
+
msgid "No contributions"
msgstr ""
@@ -16669,9 +17264,6 @@ msgstr ""
msgid "No license. All rights reserved"
msgstr ""
-msgid "No licenses found."
-msgstr ""
-
msgid "No matches found"
msgstr ""
@@ -16684,6 +17276,9 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No members found"
+msgstr ""
+
msgid "No merge requests found"
msgstr ""
@@ -16705,6 +17300,9 @@ msgstr ""
msgid "No parent group"
msgstr ""
+msgid "No plan"
+msgstr ""
+
msgid "No pods available"
msgstr ""
@@ -16801,6 +17399,12 @@ msgstr ""
msgid "Not Implemented"
msgstr ""
+msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+msgstr ""
+
+msgid "Not all browsers support WebAuthn. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even from an unsupported browser."
+msgstr ""
+
msgid "Not all data has been processed yet, the accuracy of the chart for the selected timeframe is limited."
msgstr ""
@@ -16897,6 +17501,9 @@ msgstr ""
msgid "Notification settings saved"
msgstr ""
+msgid "NotificationEvent|Change reviewer merge request"
+msgstr ""
+
msgid "NotificationEvent|Close issue"
msgstr ""
@@ -17059,10 +17666,7 @@ msgstr ""
msgid "On track"
msgstr ""
-msgid "OnDemandScans|Attached branch"
-msgstr ""
-
-msgid "OnDemandScans|Attached branch is where the scan job runs."
+msgid "OnDemandScans|Could not fetch scanner profiles. Please refresh the page, or try again later."
msgstr ""
msgid "OnDemandScans|Could not fetch site profiles. Please refresh the page, or try again later."
@@ -17071,6 +17675,9 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
+msgid "OnDemandScans|Create a new scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Create a new site profile"
msgstr ""
@@ -17083,6 +17690,9 @@ msgstr ""
msgid "OnDemandScans|New on-demand DAST scan"
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 ""
@@ -17092,16 +17702,10 @@ msgstr ""
msgid "OnDemandScans|On-demand scans run outside the DevOps cycle and find vulnerabilities in your projects. %{learnMoreLinkStart}Learn more%{learnMoreLinkEnd}"
msgstr ""
-msgid "OnDemandScans|Only a passive scan can be performed on demand."
-msgstr ""
-
-msgid "OnDemandScans|Passive"
-msgstr ""
-
msgid "OnDemandScans|Run scan"
msgstr ""
-msgid "OnDemandScans|Scan mode"
+msgid "OnDemandScans|Scanner profile"
msgstr ""
msgid "OnDemandScans|Scanner settings"
@@ -17113,9 +17717,15 @@ msgstr ""
msgid "OnDemandScans|Select one of the existing profiles"
msgstr ""
+msgid "OnDemandScans|Site profile"
+msgstr ""
+
msgid "OnDemandScans|Site profiles"
msgstr ""
+msgid "OnDemandScans|Use existing scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Use existing site profile"
msgstr ""
@@ -17213,9 +17823,6 @@ msgstr ""
msgid "Open Selection"
msgstr ""
-msgid "Open Web IDE"
-msgstr ""
-
msgid "Open comment type dropdown"
msgstr ""
@@ -17321,6 +17928,9 @@ msgstr ""
msgid "Origin"
msgstr ""
+msgid "Orphaned member"
+msgstr ""
+
msgid "Other Labels"
msgstr ""
@@ -17336,6 +17946,9 @@ msgstr ""
msgid "Other visibility settings have been disabled by the administrator."
msgstr ""
+msgid "Our documentation includes an example DevOps Score report."
+msgstr ""
+
msgid "Out-of-compliance with this project's policies and should be removed"
msgstr ""
@@ -17360,6 +17973,9 @@ msgstr ""
msgid "Overwrite diverged branches"
msgstr ""
+msgid "Owned by %{image_tag}"
+msgstr ""
+
msgid "Owned by anyone"
msgstr ""
@@ -17381,6 +17997,9 @@ msgstr ""
msgid "Package deleted successfully"
msgstr ""
+msgid "Package file size limits"
+msgstr ""
+
msgid "Package recipe already exists"
msgstr ""
@@ -17396,9 +18015,6 @@ msgstr ""
msgid "Package type must be PyPi"
msgstr ""
-msgid "Package was removed"
-msgstr ""
-
msgid "PackageRegistry|%{name} version %{version} was created %{datetime}"
msgstr ""
@@ -17540,12 +18156,18 @@ msgstr ""
msgid "PackageRegistry|NuGet Command"
msgstr ""
+msgid "PackageRegistry|Package Registry"
+msgstr ""
+
msgid "PackageRegistry|Pip Command"
msgstr ""
msgid "PackageRegistry|Pipeline %{link} triggered %{datetime} by %{author}"
msgstr ""
+msgid "PackageRegistry|Publish and share packages for a variety of common package managers. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "PackageRegistry|Published to the %{project} Package Registry %{datetime}"
msgstr ""
@@ -17645,6 +18267,9 @@ msgstr ""
msgid "Page not found"
msgstr ""
+msgid "Page settings"
+msgstr ""
+
msgid "Page was successfully deleted"
msgstr ""
@@ -17786,7 +18411,7 @@ msgstr ""
msgid "Paste issue link"
msgstr ""
-msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Don't use your private SSH key."
+msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Do not paste your private SSH key, as that can compromise your identity."
msgstr ""
msgid "Patch to apply"
@@ -17813,6 +18438,9 @@ msgstr ""
msgid "Pending"
msgstr ""
+msgid "Pending comments"
+msgstr ""
+
msgid "People without permission will never get a notification and won't be able to comment."
msgstr ""
@@ -18011,6 +18639,9 @@ msgstr ""
msgid "Pipelines|Build with confidence"
msgstr ""
+msgid "Pipelines|By revoking a trigger you will break any processes making use of it. Are you sure?"
+msgstr ""
+
msgid "Pipelines|CI Lint"
msgstr ""
@@ -18023,6 +18654,15 @@ msgstr ""
msgid "Pipelines|Continuous Integration can help catch bugs by running your tests automatically, while Continuous Deployment can help you deliver code to your product environment."
msgstr ""
+msgid "Pipelines|Copy trigger token"
+msgstr ""
+
+msgid "Pipelines|Description"
+msgstr ""
+
+msgid "Pipelines|Edit"
+msgstr ""
+
msgid "Pipelines|Get started with Pipelines"
msgstr ""
@@ -18038,15 +18678,27 @@ msgstr ""
msgid "Pipelines|It is recommended the code is reviewed thoroughly before running this pipeline with the parent project's CI resource."
msgstr ""
+msgid "Pipelines|Last Used"
+msgstr ""
+
msgid "Pipelines|Loading Pipelines"
msgstr ""
msgid "Pipelines|More Information"
msgstr ""
+msgid "Pipelines|No triggers have been created yet. Add one using the form above."
+msgstr ""
+
+msgid "Pipelines|Owner"
+msgstr ""
+
msgid "Pipelines|Project cache successfully reset."
msgstr ""
+msgid "Pipelines|Revoke"
+msgstr ""
+
msgid "Pipelines|Run Pipeline"
msgstr ""
@@ -18071,6 +18723,15 @@ msgstr ""
msgid "Pipelines|This project is not currently set up to run pipelines."
msgstr ""
+msgid "Pipelines|Token"
+msgstr ""
+
+msgid "Pipelines|Trigger user has insufficient permissions to project"
+msgstr ""
+
+msgid "Pipelines|invalid"
+msgstr ""
+
msgid "Pipelines|parent"
msgstr ""
@@ -18329,10 +18990,10 @@ msgstr ""
msgid "Please provide attributes to update"
msgstr ""
-msgid "Please refer to %{docs_url}"
+msgid "Please reach out if you have any questions and we'll be happy to assist."
msgstr ""
-msgid "Please retype the email address."
+msgid "Please refer to %{docs_url}"
msgstr ""
msgid "Please select"
@@ -18362,6 +19023,9 @@ msgstr ""
msgid "Please set a new password before proceeding."
msgstr ""
+msgid "Please share your feedback about %{featureName} %{linkStart}in this issue%{linkEnd} to help us improve the experience."
+msgstr ""
+
msgid "Please solve the reCAPTCHA"
msgstr ""
@@ -18665,6 +19329,9 @@ msgstr ""
msgid "Profiles| You are going to change the username %{currentUsernameBold} to %{newUsernameBold}. Profile and projects will be redirected to the %{newUsername} namespace but this redirect will expire once the %{currentUsername} namespace is registered by another user or group. Please update your Git repository remotes as soon as possible."
msgstr ""
+msgid "Profiles|%{provider} Active"
+msgstr ""
+
msgid "Profiles|@username"
msgstr ""
@@ -18716,7 +19383,7 @@ msgstr ""
msgid "Profiles|Commit email"
msgstr ""
-msgid "Profiles|Connect"
+msgid "Profiles|Connect %{provider}"
msgstr ""
msgid "Profiles|Connected Accounts"
@@ -18740,6 +19407,9 @@ msgstr ""
msgid "Profiles|Disconnect"
msgstr ""
+msgid "Profiles|Disconnect %{provider}"
+msgstr ""
+
msgid "Profiles|Do not show on profile"
msgstr ""
@@ -18764,7 +19434,7 @@ msgstr ""
msgid "Profiles|Full name"
msgstr ""
-msgid "Profiles|Give your individual key a title. This will be publically visible."
+msgid "Profiles|Give your individual key a title."
msgstr ""
msgid "Profiles|Include private contributions on my profile"
@@ -18854,7 +19524,7 @@ msgstr ""
msgid "Profiles|The maximum file size allowed is 200KB."
msgstr ""
-msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it?"
+msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it? It will be publicly visible."
msgstr ""
msgid "Profiles|This email will be displayed on your public profile"
@@ -18929,6 +19599,9 @@ msgstr ""
msgid "Profiles|You don't have access to delete this user."
msgstr ""
+msgid "Profiles|You must transfer ownership or delete groups you are an owner of before you can delete your account"
+msgstr ""
+
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
@@ -19517,6 +20190,9 @@ msgstr ""
msgid "ProjectTemplates|GitLab Cluster Management"
msgstr ""
+msgid "ProjectTemplates|Gitpod/Spring Petclinic"
+msgstr ""
+
msgid "ProjectTemplates|Go Micro"
msgstr ""
@@ -20126,6 +20802,9 @@ msgstr ""
msgid "Publish to status page"
msgstr ""
+msgid "Published"
+msgstr ""
+
msgid "Published on status page"
msgstr ""
@@ -20243,9 +20922,15 @@ msgstr ""
msgid "Quick range"
msgstr ""
+msgid "Quickly and easily edit multiple files in your project."
+msgstr ""
+
msgid "README"
msgstr ""
+msgid "Rails"
+msgstr ""
+
msgid "Rake Tasks Help"
msgstr ""
@@ -20364,10 +21049,13 @@ msgstr ""
msgid "Register Two-Factor Authenticator"
msgstr ""
-msgid "Register U2F device"
+msgid "Register Universal Two-Factor (U2F) Device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register WebAuthn Device"
+msgstr ""
+
+msgid "Register device"
msgstr ""
msgid "Register for GitLab"
@@ -20379,9 +21067,6 @@ msgstr ""
msgid "Register with two-factor app"
msgstr ""
-msgid "Registration"
-msgstr ""
-
msgid "Registration|Checkout"
msgstr ""
@@ -20497,9 +21182,6 @@ msgstr ""
msgid "Release|Something went wrong while saving the release details"
msgstr ""
-msgid "Remediated: needs review"
-msgstr ""
-
msgid "Remediations"
msgstr ""
@@ -20605,6 +21287,9 @@ msgstr ""
msgid "Remove priority"
msgstr ""
+msgid "Remove report"
+msgstr ""
+
msgid "Remove secondary node"
msgstr ""
@@ -20617,6 +21302,12 @@ msgstr ""
msgid "Remove time estimate"
msgstr ""
+msgid "Remove user & report"
+msgstr ""
+
+msgid "Remove user from group"
+msgstr ""
+
msgid "Removed"
msgstr ""
@@ -20698,9 +21389,6 @@ msgstr ""
msgid "Removes time estimate."
msgstr ""
-msgid "Removing license…"
-msgstr ""
-
msgid "Removing this group also removes all child projects, including archived projects, and their resources."
msgstr ""
@@ -20785,6 +21473,9 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
+msgid "Reported by %{reporter}"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -20870,6 +21561,27 @@ msgstr ""
msgid "Repositories"
msgstr ""
+msgid "Repositories Analytics"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download Historic Test Coverage Data"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download historic test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Historic Test Coverage Data is available in raw format (.csv) for further analysis."
+msgstr ""
+
+msgid "RepositoriesAnalytics|Test Code Coverage"
+msgstr ""
+
+msgid "RepositoriesAnalytics|There was an error fetching the projects."
+msgstr ""
+
msgid "Repository"
msgstr ""
@@ -20948,9 +21660,15 @@ msgstr ""
msgid "Request parameter %{param} is missing."
msgstr ""
+msgid "Request review from"
+msgstr ""
+
msgid "Request to link SAML account must be authorized"
msgstr ""
+msgid "Requested"
+msgstr ""
+
msgid "Requested %{time_ago}"
msgstr ""
@@ -20969,6 +21687,9 @@ msgstr ""
msgid "Requests to these domain(s)/address(es) on the local network will be allowed when local requests from hooks and services are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 or 127.0.0.0/28 are supported. Domain wildcards are not supported currently. Use comma, semicolon, or newline to separate multiple entries. The allowlist can hold a maximum of 1000 entries. Domains should use IDNA encoding. Ex: example.com, 192.168.1.1, 127.0.0.0/28, xn--itlab-j1a.com."
msgstr ""
+msgid "Require admin approval for new sign-ups"
+msgstr ""
+
msgid "Require all users in this group to setup Two-factor authentication"
msgstr ""
@@ -21094,9 +21815,6 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
-msgid "Resolved by %{resolvedByName}"
-msgstr ""
-
msgid "Resolves IP addresses once and uses them to submit requests"
msgstr ""
@@ -21215,6 +21933,13 @@ msgstr ""
msgid "ReviewApp|Enable Review App"
msgstr ""
+msgid "Reviewer"
+msgid_plural "%d Reviewers"
+msgstr[0] ""
+
+msgid "Reviewer(s)"
+msgstr ""
+
msgid "Reviewing"
msgstr ""
@@ -21254,6 +21979,9 @@ msgstr ""
msgid "Rook"
msgstr ""
+msgid "Ruby"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -21332,6 +22060,63 @@ msgstr ""
msgid "Runners page."
msgstr ""
+msgid "Runners|Active"
+msgstr ""
+
+msgid "Runners|Architecture"
+msgstr ""
+
+msgid "Runners|Can run untagged jobs"
+msgstr ""
+
+msgid "Runners|Description"
+msgstr ""
+
+msgid "Runners|Group"
+msgstr ""
+
+msgid "Runners|IP Address"
+msgstr ""
+
+msgid "Runners|Last contact"
+msgstr ""
+
+msgid "Runners|Locked to this project"
+msgstr ""
+
+msgid "Runners|Maximum job timeout"
+msgstr ""
+
+msgid "Runners|Name"
+msgstr ""
+
+msgid "Runners|Platform"
+msgstr ""
+
+msgid "Runners|Property Name"
+msgstr ""
+
+msgid "Runners|Protected"
+msgstr ""
+
+msgid "Runners|Revision"
+msgstr ""
+
+msgid "Runners|Shared"
+msgstr ""
+
+msgid "Runners|Specific"
+msgstr ""
+
+msgid "Runners|Tags"
+msgstr ""
+
+msgid "Runners|Value"
+msgstr ""
+
+msgid "Runners|Version"
+msgstr ""
+
msgid "Runners|You have used %{quotaUsed} out of %{quotaLimit} of your shared Runners pipeline minutes."
msgstr ""
@@ -21344,6 +22129,9 @@ msgstr ""
msgid "Runs a number of housekeeping tasks within the current repository, such as compressing file revisions and removing unreachable objects."
msgstr ""
+msgid "SAML"
+msgstr ""
+
msgid "SAML SSO"
msgstr ""
@@ -21395,6 +22183,9 @@ msgstr ""
msgid "Save"
msgstr ""
+msgid "Save %{name} size limits"
+msgstr ""
+
msgid "Save Changes"
msgstr ""
@@ -21425,9 +22216,6 @@ msgstr ""
msgid "Save space and find tags in the Container Registry more easily. Enable the cleanup policy to remove stale tags and keep only the ones you need."
msgstr ""
-msgid "Save template"
-msgstr ""
-
msgid "Save variables"
msgstr ""
@@ -21470,9 +22258,6 @@ msgstr ""
msgid "Scope"
msgstr ""
-msgid "Scope not supported with disabled 'users_search' feature!"
-msgstr ""
-
msgid "Scoped issue boards"
msgstr ""
@@ -21599,9 +22384,6 @@ msgstr ""
msgid "Search requirements"
msgstr ""
-msgid "Search results…"
-msgstr ""
-
msgid "Search users"
msgstr ""
@@ -21671,6 +22453,10 @@ msgid "SearchResults|commit"
msgid_plural "SearchResults|commits"
msgstr[0] ""
+msgid "SearchResults|epic"
+msgid_plural "SearchResults|epics"
+msgstr[0] ""
+
msgid "SearchResults|issue"
msgid_plural "SearchResults|issues"
msgstr[0] ""
@@ -21708,10 +22494,10 @@ msgstr ""
msgid "Seat Link is disabled, and cannot be configured through this form."
msgstr ""
-msgid "Seats currently in use"
+msgid "Seats usage data as of %{last_enqueue_time}"
msgstr ""
-msgid "Seats in license"
+msgid "Seats usage data is updated every day at 12:00pm UTC"
msgstr ""
msgid "Secondary"
@@ -21765,6 +22551,9 @@ msgstr ""
msgid "SecurityConfiguration|Available for on-demand DAST"
msgstr ""
+msgid "SecurityConfiguration|By default, all analyzers are applied in order to cover all languages across your project, and only run if the language is detected in the Merge Request."
+msgstr ""
+
msgid "SecurityConfiguration|Configure"
msgstr ""
@@ -21795,16 +22584,19 @@ msgstr ""
msgid "SecurityConfiguration|Manage"
msgstr ""
+msgid "SecurityConfiguration|More information"
+msgstr ""
+
msgid "SecurityConfiguration|Not enabled"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|Security Control"
+msgid "SecurityConfiguration|SAST Configuration"
msgstr ""
-msgid "SecurityConfiguration|See documentation"
+msgid "SecurityConfiguration|Security Control"
msgstr ""
msgid "SecurityConfiguration|Status"
@@ -21816,6 +22608,9 @@ msgstr ""
msgid "SecurityConfiguration|Using custom settings. You won't receive automatic updates on this variable. %{anchorStart}Restore to default%{anchorEnd}"
msgstr ""
+msgid "SecurityConfiguration|View history"
+msgstr ""
+
msgid "SecurityConfiguration|You can quickly enable all security scanning tools by enabling %{linkStart}Auto DevOps%{linkEnd}."
msgstr ""
@@ -21894,9 +22689,6 @@ msgstr ""
msgid "SecurityReports|Learn more about setting up your dashboard"
msgstr ""
-msgid "SecurityReports|Load more vulnerabilities"
-msgstr ""
-
msgid "SecurityReports|Monitor vulnerabilities in your code"
msgstr ""
@@ -22176,7 +22968,7 @@ msgstr ""
msgid "Select status"
msgstr ""
-msgid "Select strategy activation method"
+msgid "Select strategy activation method."
msgstr ""
msgid "Select subscription"
@@ -22191,7 +22983,7 @@ msgstr ""
msgid "Select the custom project template source group."
msgstr ""
-msgid "Select timeframe"
+msgid "Select the environment scope for this feature flag."
msgstr ""
msgid "Select timezone"
@@ -22440,6 +23232,9 @@ msgstr ""
msgid "Set iteration"
msgstr ""
+msgid "Set limit to 0 to allow any file size."
+msgstr ""
+
msgid "Set max session time for web terminal."
msgstr ""
@@ -22518,10 +23313,13 @@ msgstr ""
msgid "Set up a %{type} Runner manually"
msgstr ""
+msgid "Set up a hardware device as a second factor to sign in."
+msgstr ""
+
msgid "Set up assertions/attributes/claims (email, first_name, last_name) and NameID according to %{docsLinkStart}the documentation %{icon}%{docsLinkEnd}"
msgstr ""
-msgid "Set up new U2F device"
+msgid "Set up new device"
msgstr ""
msgid "Set up new password"
@@ -22590,6 +23388,9 @@ msgstr ""
msgid "Sets weight to %{weight}."
msgstr ""
+msgid "Setting this to 0 means using the system default timeout value."
+msgstr ""
+
msgid "Settings"
msgstr ""
@@ -22605,6 +23406,15 @@ msgstr ""
msgid "Severity"
msgstr ""
+msgid "SeverityWidget|Severity"
+msgstr ""
+
+msgid "SeverityWidget|Severity: %{severity}"
+msgstr ""
+
+msgid "SeverityWidget|There was an error while updating severity."
+msgstr ""
+
msgid "Shards (%{shards})"
msgstr ""
@@ -22650,6 +23460,9 @@ msgstr ""
msgid "Show all requirements."
msgstr ""
+msgid "Show all test cases."
+msgstr ""
+
msgid "Show archived projects"
msgstr ""
@@ -22662,6 +23475,9 @@ msgstr ""
msgid "Show comments"
msgstr ""
+msgid "Show comments on this file"
+msgstr ""
+
msgid "Show comments only"
msgstr ""
@@ -22707,6 +23523,12 @@ msgstr ""
msgid "Show parent subgroups"
msgstr ""
+msgid "Show the Closed list"
+msgstr ""
+
+msgid "Show the Open list"
+msgstr ""
+
msgid "Show whitespace changes"
msgstr ""
@@ -22748,9 +23570,6 @@ msgstr ""
msgid "Sidebar|Assign health status"
msgstr ""
-msgid "Sidebar|Change weight"
-msgstr ""
-
msgid "Sidebar|Health status"
msgstr ""
@@ -22934,6 +23753,9 @@ msgstr ""
msgid "Snippets|Add another file %{num}/%{total}"
msgstr ""
+msgid "Snippets|Authored %{time_ago} by %{author}"
+msgstr ""
+
msgid "Snippets|Delete file"
msgstr ""
@@ -22961,6 +23783,9 @@ msgstr ""
msgid "Solution"
msgstr ""
+msgid "Some changes are not shown"
+msgstr ""
+
msgid "Some child epics may be hidden due to applied filters"
msgstr ""
@@ -23327,6 +24152,12 @@ msgstr ""
msgid "Source (branch or tag)"
msgstr ""
+msgid "Source Branch"
+msgstr ""
+
+msgid "Source branch: %{source_branch_open}%{source_branch}%{source_branch_close}"
+msgstr ""
+
msgid "Source code"
msgstr ""
@@ -23492,9 +24323,6 @@ msgstr ""
msgid "Start and due date"
msgstr ""
-msgid "Start by choosing a group to see how your team is spending time. You can then drill down to the project level."
-msgstr ""
-
msgid "Start by choosing a group to start exploring the merge requests in that group. You can then proceed to filter by projects, labels, milestones and authors."
msgstr ""
@@ -23576,18 +24404,27 @@ msgstr ""
msgid "StaticSiteEditor|3. Assign a person to review and accept the merge request."
msgstr ""
+msgid "StaticSiteEditor|A link to view the merge request will appear once ready."
+msgstr ""
+
msgid "StaticSiteEditor|An error occurred while submitting your changes."
msgstr ""
msgid "StaticSiteEditor|Branch could not be created."
msgstr ""
+msgid "StaticSiteEditor|Copy update"
+msgstr ""
+
msgid "StaticSiteEditor|Could not commit the content changes."
msgstr ""
msgid "StaticSiteEditor|Could not create merge request."
msgstr ""
+msgid "StaticSiteEditor|Creating your merge request"
+msgstr ""
+
msgid "StaticSiteEditor|Incompatible file content"
msgstr ""
@@ -23609,6 +24446,9 @@ msgstr ""
msgid "StaticSiteEditor|View documentation"
msgstr ""
+msgid "StaticSiteEditor|You can set an assignee to get your changes reviewed and deployed once your merge request is created."
+msgstr ""
+
msgid "StaticSiteEditor|Your merge request has been created"
msgstr ""
@@ -23738,15 +24578,15 @@ msgstr ""
msgid "Submit %{humanized_resource_name}"
msgstr ""
-msgid "Submit Changes"
-msgstr ""
-
msgid "Submit a review"
msgstr ""
msgid "Submit as spam"
msgstr ""
+msgid "Submit changes"
+msgstr ""
+
msgid "Submit feedback"
msgstr ""
@@ -23900,6 +24740,9 @@ msgstr ""
msgid "Successfully deleted U2F device."
msgstr ""
+msgid "Successfully deleted WebAuthn device."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -24218,9 +25061,6 @@ msgstr ""
msgid "Template to append to all Service Desk issues"
msgstr ""
-msgid "Template was successfully saved."
-msgstr ""
-
msgid "Templates"
msgstr ""
@@ -24296,10 +25136,28 @@ msgid "Test coverage: %d hit"
msgid_plural "Test coverage: %d hits"
msgstr[0] ""
-msgid "Test failed."
+msgid "Test settings"
+msgstr ""
+
+msgid "TestCases|New Test Case"
+msgstr ""
+
+msgid "TestCases|New test case"
+msgstr ""
+
+msgid "TestCases|Search test cases"
+msgstr ""
+
+msgid "TestCases|Something went wrong while creating a test case."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching count of test cases."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching test cases list."
msgstr ""
-msgid "Test settings and save changes"
+msgid "TestCases|Submit test case"
msgstr ""
msgid "TestHooks|Ensure one of your projects has merge requests."
@@ -24365,6 +25223,9 @@ msgstr ""
msgid "Thank you for signing up for your free trial! You will get additional instructions in your inbox shortly."
msgstr ""
+msgid "Thank you for your business."
+msgstr ""
+
msgid "Thank you for your feedback!"
msgstr ""
@@ -24423,9 +25284,6 @@ msgstr ""
msgid "The URL to use for connecting to Elasticsearch. Use a comma-separated list to support clustering (e.g., \"http://localhost:9200, http://localhost:9201\")."
msgstr ""
-msgid "The Web IDE offers advanced syntax highlighting capabilities and more."
-msgstr ""
-
msgid "The X509 Certificate to use when mutual TLS is required to communicate with the external authorization service. If left blank, the server certificate is still validated when accessing over HTTPS."
msgstr ""
@@ -24535,6 +25393,9 @@ msgstr ""
msgid "The form contains the following error:"
msgstr ""
+msgid "The form contains the following warning:"
+msgstr ""
+
msgid "The global settings require you to enable Two-Factor Authentication for your account."
msgstr ""
@@ -24649,9 +25510,6 @@ msgstr ""
msgid "The private key to use when a client certificate is provided. This value is encrypted at rest."
msgstr ""
-msgid "The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The project can be accessed by any logged in user."
msgstr ""
@@ -24688,7 +25546,7 @@ msgstr ""
msgid "The remote repository is being updated..."
msgstr ""
-msgid "The repository can be commited to, and issues, comments and other entities can be created."
+msgid "The repository can be committed to, and issues, comments and other entities can be created."
msgstr ""
msgid "The repository for this project does not exist."
@@ -24742,9 +25600,6 @@ msgstr ""
msgid "The time taken by each data entry gathered by that stage."
msgstr ""
-msgid "The total stage shows the time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The update action will time out after %{number_of_minutes} minutes. For big repositories, use a clone/push combination."
msgstr ""
@@ -24808,6 +25663,9 @@ msgstr ""
msgid "There are no archived requirements"
msgstr ""
+msgid "There are no archived test cases"
+msgstr ""
+
msgid "There are no changes"
msgstr ""
@@ -24847,6 +25705,9 @@ msgstr ""
msgid "There are no open requirements"
msgstr ""
+msgid "There are no open test cases"
+msgstr ""
+
msgid "There are no packages yet"
msgstr ""
@@ -24859,6 +25720,9 @@ msgstr ""
msgid "There is a limit of %{ci_project_subscriptions_limit} subscriptions from or to a project."
msgstr ""
+msgid "There is already a To-Do for this design."
+msgstr ""
+
msgid "There is already a repository with that name on disk"
msgstr ""
@@ -24877,6 +25741,9 @@ msgstr ""
msgid "There was a problem communicating with your device."
msgstr ""
+msgid "There was a problem fetching branches."
+msgstr ""
+
msgid "There was a problem fetching groups."
msgstr ""
@@ -25105,9 +25972,15 @@ msgstr ""
msgid "This action can lead to data loss. To prevent accidental actions we ask you to confirm your intention."
msgstr ""
+msgid "This action cannot be undone, and will permanently delete the %{key} SSH key"
+msgstr ""
+
msgid "This action cannot be undone. You will lose the project's repository and all content: issues, merge requests, etc."
msgstr ""
+msgid "This action has been performed too many times. Try again later."
+msgstr ""
+
msgid "This action will %{strongOpen}permanently delete%{strongClose} %{codeOpen}%{project}%{codeClose} %{strongOpen}immediately%{strongClose}, including its repositories and all content: issues, merge requests, etc."
msgstr ""
@@ -25135,9 +26008,6 @@ msgstr ""
msgid "This board's scope is reduced"
msgstr ""
-msgid "This branch has changed since you started editing. Would you like to create a new branch?"
-msgstr ""
-
msgid "This chart could not be displayed"
msgstr ""
@@ -25264,15 +26134,9 @@ msgstr ""
msgid "This is a security log of important events involving your account."
msgstr ""
-msgid "This is the author's first Merge Request to this project."
-msgstr ""
-
msgid "This is the highest peak of users on your installation since the license started."
msgstr ""
-msgid "This is the maximum number of users that have existed at the same time since the license started. This is the minimum number of seats you will need to buy when you renew your license."
-msgstr ""
-
msgid "This is the number of currently active users on your installation, and this is the minimum number you need to purchase when you renew your license."
msgstr ""
@@ -25504,6 +26368,15 @@ msgstr ""
msgid "This user has no identities"
msgstr ""
+msgid "This user has previously committed to the %{name} project."
+msgstr ""
+
+msgid "This user has the %{access} role in the %{name} project."
+msgstr ""
+
+msgid "This user is the author of this %{noteable}."
+msgstr ""
+
msgid "This user will be the author of all events in the activity feed that are the result of an update, like new branches being created or new commits being pushed to existing branches."
msgstr ""
@@ -25534,6 +26407,9 @@ msgstr ""
msgid "Threat Monitoring"
msgstr ""
+msgid "ThreatMonitoring|All Environments"
+msgstr ""
+
msgid "ThreatMonitoring|Anomalous Requests"
msgstr ""
@@ -25561,9 +26437,6 @@ msgstr ""
msgid "ThreatMonitoring|Operations Per Second"
msgstr ""
-msgid "ThreatMonitoring|Overview"
-msgstr ""
-
msgid "ThreatMonitoring|Packet Activity"
msgstr ""
@@ -25582,6 +26455,9 @@ msgstr ""
msgid "ThreatMonitoring|Something went wrong, unable to fetch statistics"
msgstr ""
+msgid "ThreatMonitoring|Statistics"
+msgstr ""
+
msgid "ThreatMonitoring|The firewall is not installed or has been disabled. To view this data, ensure the web application firewall is installed and enabled for your cluster."
msgstr ""
@@ -25971,6 +26847,9 @@ msgstr ""
msgid "To update Snippets with multiple files, you must use the `files` parameter"
msgstr ""
+msgid "To use Gitpod you must first enable the feature in the integrations section of your %{user_prefs}."
+msgstr ""
+
msgid "To view all %{scannedResourcesCount} scanned URLs, please download the CSV file"
msgstr ""
@@ -26004,9 +26883,6 @@ msgstr ""
msgid "Toggle Sidebar"
msgstr ""
-msgid "Toggle all threads"
-msgstr ""
-
msgid "Toggle backtrace"
msgstr ""
@@ -26031,9 +26907,6 @@ msgstr ""
msgid "Toggle navigation"
msgstr ""
-msgid "Toggle project"
-msgstr ""
-
msgid "Toggle sidebar"
msgstr ""
@@ -26073,6 +26946,9 @@ msgstr ""
msgid "Too many projects enabled. You will need to manage them via the console or the API."
msgstr ""
+msgid "Too much data"
+msgstr ""
+
msgid "Topics (optional)"
msgstr ""
@@ -26091,6 +26967,9 @@ msgstr ""
msgid "Total cores (CPUs)"
msgstr ""
+msgid "Total days to completion"
+msgstr ""
+
msgid "Total issues"
msgstr ""
@@ -26187,6 +27066,9 @@ msgstr ""
msgid "Trending"
msgstr ""
+msgid "Trials|Create a new group to start your GitLab Gold trial."
+msgstr ""
+
msgid "Trials|Go back to GitLab"
msgstr ""
@@ -26196,6 +27078,15 @@ msgstr ""
msgid "Trials|You can always resume this process by selecting your avatar and choosing 'Start a Gold trial'"
msgstr ""
+msgid "Trials|You can apply your trial to a new group or an existing group."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group or your personal account."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group, an existing group, or your personal account."
+msgstr ""
+
msgid "Trials|You won't get a free trial right now but you can always resume this process by clicking on your avatar and choosing 'Start a free trial'"
msgstr ""
@@ -26265,6 +27156,9 @@ msgstr ""
msgid "Try using a different search term to find the file you are looking for."
msgstr ""
+msgid "Trying to communicate with your device. Plug it in (if needed) and press the button on the device now."
+msgstr ""
+
msgid "Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now."
msgstr ""
@@ -26352,6 +27246,12 @@ msgstr ""
msgid "URL or request ID"
msgstr ""
+msgid "USER %{user} WILL BE REMOVED! Are you sure?"
+msgstr ""
+
+msgid "USER WILL BE BLOCKED! Are you sure?"
+msgstr ""
+
msgid "UTC"
msgstr ""
@@ -26409,9 +27309,6 @@ msgstr ""
msgid "Unable to load the merge request widget. Try reloading the page."
msgstr ""
-msgid "Unable to resolve"
-msgstr ""
-
msgid "Unable to save iteration. Please try again"
msgstr ""
@@ -26460,6 +27357,9 @@ msgstr ""
msgid "Undo ignore"
msgstr ""
+msgid "Unexpected error"
+msgstr ""
+
msgid "Unfortunately, your email message to GitLab could not be processed."
msgstr ""
@@ -26493,6 +27393,9 @@ msgstr ""
msgid "Unknown response text"
msgstr ""
+msgid "Unless otherwise agreed to in writing with GitLab, by clicking \"Upload License\" you agree that your use of GitLab Software is subject to the %{eula_link_start}Terms of Service%{eula_link_end}."
+msgstr ""
+
msgid "Unlimited"
msgstr ""
@@ -26859,9 +27762,6 @@ msgstr ""
msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
msgstr ""
-msgid "Use a hardware device to add the second factor of authentication."
-msgstr ""
-
msgid "Use an one time password authenticator on your mobile device or computer to enable two-factor authentication (2FA)."
msgstr ""
@@ -27135,13 +28035,13 @@ msgstr ""
msgid "Users"
msgstr ""
-msgid "Users in License:"
+msgid "Users in License"
msgstr ""
-msgid "Users or groups set as approvers in the project's or merge request's settings."
+msgid "Users in License:"
msgstr ""
-msgid "Users outside of license"
+msgid "Users or groups set as approvers in the project's or merge request's settings."
msgstr ""
msgid "Users over License:"
@@ -27159,9 +28059,6 @@ msgstr ""
msgid "Users with a Guest role or those who don't belong to a Project or Group will not use a seat from your license."
msgstr ""
-msgid "Users with a Guest role or those who don't belong to any projects or groups don't count towards seats in use."
-msgstr ""
-
msgid "UsersSelect|%{name} + %{length} more"
msgstr ""
@@ -27201,9 +28098,6 @@ msgstr ""
msgid "Validations failed."
msgstr ""
-msgid "Validity"
-msgstr ""
-
msgid "Value"
msgstr ""
@@ -27222,6 +28116,9 @@ msgstr ""
msgid "Value Stream Name"
msgstr ""
+msgid "ValueStreamAnalyticsStage|We don't have enough data to show this stage."
+msgstr ""
+
msgid "ValueStreamAnalytics|%{days}d"
msgstr ""
@@ -27476,6 +28373,9 @@ msgstr ""
msgid "VisualReviewApp|Steps 1 and 2 (and sometimes 3) are performed once by the developer before requesting feedback. Steps 3 (if necessary), 4 is performed by the reviewer each time they perform a review."
msgstr ""
+msgid "Visualization"
+msgstr ""
+
msgid "Vulnerabilities"
msgstr ""
@@ -27503,34 +28403,31 @@ msgstr ""
msgid "VulnerabilityChart|Severity"
msgstr ""
-msgid "VulnerabilityManagement|A true-positive and will fix"
-msgstr ""
-
-msgid "VulnerabilityManagement|Change status"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Confirm"
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|Confirmed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Detected %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|A true-positive and will fix"
msgstr ""
-msgid "VulnerabilityManagement|Dismiss"
+msgid "VulnerabilityManagement|Change status"
msgstr ""
-msgid "VulnerabilityManagement|Dismissed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
msgstr ""
-msgid "VulnerabilityManagement|Resolved"
+msgid "VulnerabilityManagement|Detected"
msgstr ""
-msgid "VulnerabilityManagement|Resolved %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Needs triage"
msgstr ""
msgid "VulnerabilityManagement|Something went wrong while trying to delete the comment. Please try again later."
@@ -27581,6 +28478,9 @@ msgstr ""
msgid "Vulnerability|%{scannerName} (version %{scannerVersion})"
msgstr ""
+msgid "Vulnerability|Activity"
+msgstr ""
+
msgid "Vulnerability|Class"
msgstr ""
@@ -27593,6 +28493,9 @@ msgstr ""
msgid "Vulnerability|Description"
msgstr ""
+msgid "Vulnerability|Detected"
+msgstr ""
+
msgid "Vulnerability|Evidence"
msgstr ""
@@ -27656,6 +28559,9 @@ msgstr ""
msgid "Warning: Displaying this diagram might cause performance issues on this page."
msgstr ""
+msgid "We are currently unable to fetch data for the pipeline header."
+msgstr ""
+
msgid "We are currently unable to fetch data for this graph."
msgstr ""
@@ -27695,6 +28601,12 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
+msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
+msgstr ""
+
+msgid "We would like to inform you that your subscription GitLab Enterprise Edition %{plan_name} is nearing its user limit. You have %{active_user_count} active users, which is almost at the user limit of %{maximum_user_count}."
+msgstr ""
+
msgid "We've found no vulnerabilities"
msgstr ""
@@ -27710,6 +28622,12 @@ msgstr ""
msgid "Web terminal"
msgstr ""
+msgid "WebAuthn Devices (%{length})"
+msgstr ""
+
+msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
+msgstr ""
+
msgid "WebIDE|Merge request"
msgstr ""
@@ -27848,15 +28766,9 @@ msgstr ""
msgid "Welcome to the guided GitLab tour"
msgstr ""
-msgid "Welcome to your Issue Board!"
-msgstr ""
-
msgid "Welcome to your issue board!"
msgstr ""
-msgid "We’ve been making changes to %{featureName} and we’d love your feedback %{linkStart}in this issue%{linkEnd} to help us improve the experience."
-msgstr ""
-
msgid "What are you searching for?"
msgstr ""
@@ -27875,6 +28787,9 @@ msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
msgstr ""
+msgid "When enabled, any user visiting %{host} and creating an account will have to be explicitly approved by the admin before they can login. This setting is effective only if sign-ups are enabled."
+msgstr ""
+
msgid "When enabled, any user visiting %{host} will be able to create an account."
msgstr ""
@@ -28098,6 +29013,9 @@ msgstr ""
msgid "With requirements, you can set criteria to check your products against."
msgstr ""
+msgid "With test cases, you can define conditions for your project to meet in determining quality"
+msgstr ""
+
msgid "Withdraw Access Request"
msgstr ""
@@ -28113,6 +29031,9 @@ msgstr ""
msgid "Workflow Help"
msgstr ""
+msgid "Would you like to create a new branch?"
+msgstr ""
+
msgid "Write"
msgstr ""
@@ -28134,6 +29055,9 @@ msgstr ""
msgid "Wrong extern UID provided. Make sure Auth0 is configured correctly."
msgstr ""
+msgid "YYYY-MM-DD"
+msgstr ""
+
msgid "Yes"
msgstr ""
@@ -28191,7 +29115,7 @@ msgstr ""
msgid "You are going to remove the fork relationship from %{project_full_name}. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "You are going to transfer %{project_full_name} to another owner. Are you ABSOLUTELY sure?"
+msgid "You are going to transfer %{project_full_name} to another namespace. Are you ABSOLUTELY sure?"
msgstr ""
msgid "You are going to turn off the confidentiality. This means %{strongStart}everyone%{strongEnd} will be able to see and leave a comment on this %{issuableType}."
@@ -28251,9 +29175,6 @@ msgstr ""
msgid "You can always edit this later"
msgstr ""
-msgid "You can apply your Trial to your Personal account or create a New Group."
-msgstr ""
-
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings"
msgstr ""
@@ -28275,12 +29196,18 @@ msgstr ""
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
+msgid "You can find more information about GitLab subscriptions in %{subscriptions_doc_link}."
+msgstr ""
+
msgid "You can generate an access token scoped to this project for each application to use the GitLab API."
msgstr ""
msgid "You can get started by cloning the repository or start adding files to it with one of the following options."
msgstr ""
+msgid "You can group test cases using labels. To learn about the future direction of this feature, visit %{linkStart}Quality Management direction page%{linkEnd}."
+msgstr ""
+
msgid "You can invite a new member to %{project_name} or invite another group."
msgstr ""
@@ -28296,6 +29223,9 @@ msgstr ""
msgid "You can notify the app / group or a project by sending them an email notification"
msgstr ""
+msgid "You can now close this window."
+msgstr ""
+
msgid "You can now export your security dashboard to a CSV report."
msgstr ""
@@ -28344,9 +29274,6 @@ msgstr ""
msgid "You can test your .gitlab-ci.yml in %{linkStart}CI Lint%{linkEnd}."
msgstr ""
-msgid "You can try again using %{begin_link}basic search%{end_link}"
-msgstr ""
-
msgid "You cannot access the raw file. Please wait a minute."
msgstr ""
@@ -28398,6 +29325,9 @@ msgstr ""
msgid "You don't have any U2F devices registered yet."
msgstr ""
+msgid "You don't have any WebAuthn devices registered yet."
+msgstr ""
+
msgid "You don't have any active chat names."
msgstr ""
@@ -28485,6 +29415,9 @@ msgstr ""
msgid "You must accept our Terms of Service and privacy policy in order to register an account"
msgstr ""
+msgid "You must be logged in to search across all of GitLab"
+msgstr ""
+
msgid "You must disassociate %{domain} from all clusters it is attached to before deletion."
msgstr ""
@@ -28524,7 +29457,7 @@ msgstr ""
msgid "You need to be logged in."
msgstr ""
-msgid "You need to register a two-factor authentication app before you can set up a U2F device."
+msgid "You need to register a two-factor authentication app before you can set up a device."
msgstr ""
msgid "You need to set terms to be enforced"
@@ -28542,6 +29475,9 @@ msgstr ""
msgid "You reached %{usage_in_percent} of %{namespace_name}'s storage capacity (%{used_storage} of %{storage_limit})"
msgstr ""
+msgid "You successfully declined the invitation"
+msgstr ""
+
msgid "You tried to fork %{link_to_the_project} but it failed for the following reason:"
msgstr ""
@@ -28707,10 +29643,13 @@ msgstr ""
msgid "Your U2F device did not send a valid JSON response."
msgstr ""
-msgid "Your U2F device needs to be set up. Plug it in (if not already) and click the button on the left."
+msgid "Your U2F device was registered!"
msgstr ""
-msgid "Your U2F device was registered!"
+msgid "Your WebAuthn device did not send a valid JSON response."
+msgstr ""
+
+msgid "Your WebAuthn device was registered!"
msgstr ""
msgid "Your access request to the %{source_type} has been withdrawn."
@@ -28734,6 +29673,9 @@ msgstr ""
msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
msgstr ""
+msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
+msgstr ""
+
msgid "Your changes can be committed to %{branch_name} because a merge request is open."
msgstr ""
@@ -28770,6 +29712,12 @@ msgstr ""
msgid "Your deployment services will be broken, you will need to manually fix the services after renaming."
msgstr ""
+msgid "Your device is not compatible with GitLab. Please try another device"
+msgstr ""
+
+msgid "Your device needs to be set up. Plug it in (if needed) and click the button on the left."
+msgstr ""
+
msgid "Your device was successfully set up! Give it a name and register it with the GitLab server."
msgstr ""
@@ -28882,9 +29830,6 @@ msgstr[0] ""
msgid "access:"
msgstr ""
-msgid "activated"
-msgstr ""
-
msgid "added %{created_at_timeago}"
msgstr ""
@@ -28957,9 +29902,21 @@ msgstr ""
msgid "by %{user}"
msgstr ""
+msgid "cannot be a date in the past"
+msgstr ""
+
msgid "cannot be changed if a personal project has container registry tags."
msgstr ""
+msgid "cannot be changed if shared runners are enabled"
+msgstr ""
+
+msgid "cannot be enabled because parent group does not allow it"
+msgstr ""
+
+msgid "cannot be enabled because parent group has shared Runners disabled"
+msgstr ""
+
msgid "cannot be enabled unless all domains have TLS certificates"
msgstr ""
@@ -29005,7 +29962,7 @@ msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about SAST %{linkEndTag}"
msgstr ""
-msgid "ciReport|%{linkStartTag}Learn more about Secret Scanning %{linkEndTag}"
+msgid "ciReport|%{linkStartTag}Learn more about Secret Detection %{linkEndTag}"
msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about codequality reports %{linkEndTag}"
@@ -29317,9 +30274,6 @@ msgstr ""
msgid "error"
msgstr ""
-msgid "error code:"
-msgstr ""
-
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr ""
@@ -29341,6 +30295,9 @@ msgstr ""
msgid "failed to dismiss associated finding(id=%{finding_id}): %{message}"
msgstr ""
+msgid "failed to revert associated finding(id=%{finding_id}) to detected"
+msgstr ""
+
msgid "file"
msgid_plural "files"
msgstr[0] ""
@@ -29879,6 +30836,9 @@ msgstr ""
msgid "must be a root namespace"
msgstr ""
+msgid "must be a valid IPv4 or IPv6 address"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -29915,6 +30875,9 @@ msgstr ""
msgid "no expiration"
msgstr ""
+msgid "no name set"
+msgstr ""
+
msgid "no one can merge"
msgstr ""
@@ -30088,9 +31051,6 @@ msgstr ""
msgid "security Reports|There was an error creating the merge request"
msgstr ""
-msgid "settings saved, but not activated"
-msgstr ""
-
msgid "severity|Critical"
msgstr ""
@@ -30217,9 +31177,6 @@ msgstr ""
msgid "toggle collapse"
msgstr ""
-msgid "toggle dropdown"
-msgstr ""
-
msgid "triggered"
msgstr ""
@@ -30247,6 +31204,9 @@ msgstr ""
msgid "user avatar"
msgstr ""
+msgid "user preferences"
+msgstr ""
+
msgid "username"
msgstr ""
diff --git a/locale/zh_CN/gitlab.po b/locale/zh_CN/gitlab.po
index 743f6e51712..a4d271e26d3 100644
--- a/locale/zh_CN/gitlab.po
+++ b/locale/zh_CN/gitlab.po
@@ -14,7 +14,10 @@ msgstr ""
"X-Crowdin-Language: zh-CN\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 6\n"
-"PO-Revision-Date: 2020-09-05 17:30\n"
+"PO-Revision-Date: 2020-10-02 18:43\n"
+
+msgid " %{project_name}#%{issue_iid} &middot; opened %{issue_created} by %{author}"
+msgstr ""
msgid " %{start} to %{end}"
msgstr "从%{start}到%{end}"
@@ -72,6 +75,14 @@ msgstr "“%{ref}â€ä¸Šä¸å­˜åœ¨â€œ%{path}â€"
msgid "\"el\" parameter is required for createInstance()"
msgstr ""
+msgid "%d Approval"
+msgid_plural "%d Approvals"
+msgstr[0] ""
+
+msgid "%d Package"
+msgid_plural "%d Packages"
+msgstr[0] ""
+
msgid "%d Scanned URL"
msgid_plural "%d Scanned URLs"
msgstr[0] "%d个已扫æçš„URL"
@@ -123,6 +134,10 @@ msgstr[0] "%d 次æ交,"
msgid "%d commits"
msgstr "%d 次æ交"
+msgid "%d completed issue"
+msgid_plural "%d completed issues"
+msgstr[0] ""
+
msgid "%d contribution"
msgid_plural "%d contributions"
msgstr[0] "%d个贡献"
@@ -131,6 +146,10 @@ msgid "%d day"
msgid_plural "%d days"
msgstr[0] "%d天"
+msgid "%d day until tags are automatically removed"
+msgid_plural "%d days until tags are automatically removed"
+msgstr[0] ""
+
msgid "%d error"
msgid_plural "%d errors"
msgstr[0] "%d个错误"
@@ -203,6 +222,14 @@ msgid "%d more comment"
msgid_plural "%d more comments"
msgstr[0] "%d个更多评论"
+msgid "%d open issue"
+msgid_plural "%d open issues"
+msgstr[0] ""
+
+msgid "%d pending comment"
+msgid_plural "%d pending comments"
+msgstr[0] ""
+
msgid "%d personal project will be removed and cannot be restored."
msgid_plural "%d personal projects will be removed and cannot be restored."
msgstr[0] "%d个个人项目将被删除,无法æ¢å¤ã€‚"
@@ -215,6 +242,10 @@ msgid "%d project"
msgid_plural "%d projects"
msgstr[0] "%d个项目"
+msgid "%d project selected"
+msgid_plural "%d projects selected"
+msgstr[0] ""
+
msgid "%d request with warnings"
msgid_plural "%d requests with warnings"
msgstr[0] "%d个带有警告的请求"
@@ -231,6 +262,10 @@ msgid "%d tag"
msgid_plural "%d tags"
msgstr[0] "%d个标签"
+msgid "%d tag per image name"
+msgid_plural "%d tags per image name"
+msgstr[0] ""
+
msgid "%d unassigned issue"
msgid_plural "%d unassigned issues"
msgstr[0] "%d个未分é…的议题"
@@ -247,6 +282,10 @@ msgid "%d vulnerability dismissed"
msgid_plural "%d vulnerabilities dismissed"
msgstr[0] "%d个æ¼æ´žå·²å¿½ç•¥"
+msgid "%d warning found:"
+msgid_plural "%d warnings found:"
+msgstr[0] ""
+
msgid "%s additional commit has been omitted to prevent performance issues."
msgid_plural "%s additional commits have been omitted to prevent performance issues."
msgstr[0] "为æ高页é¢åŠ è½½é€Ÿåº¦åŠæ€§èƒ½ï¼Œå·²çœç•¥äº† %s 次æ交。"
@@ -284,6 +323,9 @@ msgstr "%{code_open}å—ä¿æŠ¤çš„%{code_close}å˜é‡ä»…å¯ç”¨äºŽå—ä¿æŠ¤çš„分æ”
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr "由%{commit_author_link}编写于%{commit_timeago}"
+msgid "%{completedCount} completed weight"
+msgstr ""
+
msgid "%{completedWeight} of %{totalWeight} weight completed"
msgstr "总æƒé‡%{totalWeight}中的%{completedWeight}已完æˆ"
@@ -329,13 +371,12 @@ msgid "%{count} participant"
msgid_plural "%{count} participants"
msgstr[0] "%{count}ä½å‚与者"
-msgid "%{count} pending comment"
-msgid_plural "%{count} pending comments"
-msgstr[0] "%{count}个待处ç†çš„评论"
-
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr "%{count}个相关的%{pluralized_subject}: %{links}"
+msgid "%{count} total weight"
+msgstr ""
+
msgid "%{dashboard_path} could not be found."
msgstr "未找到%{dashboard_path}。"
@@ -390,6 +431,9 @@ 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}使用由群组托管å¸æˆ·ã€‚您需è¦åˆ›å»ºä¸€ä¸ªæ–°çš„GitLabå¸æˆ·ï¼Œè¯¥å¸æˆ·å°†é€šè¿‡%{group_name}组æ¥ç®¡ç†ã€‚"
+msgid "%{group_name}&%{epic_iid} &middot; opened %{epic_created} by %{author}"
+msgstr ""
+
msgid "%{host} sign-in from new location"
msgstr "%{host} 从新ä½ç½®ç™»å½•"
@@ -402,8 +446,8 @@ msgstr "%{integrations_link_start}集æˆ%{link_end}使得将第三方应用程åº
msgid "%{issuableType} will be removed! Are you sure?"
msgstr "%{issuableType} 将被删除ï¼æ‚¨ç¡®å®šå—?"
-msgid "%{issuesSize} issues with a limit of %{maxIssueCount}"
-msgstr "%{issuesSize}个议题,上é™ä¸º%{maxIssueCount}"
+msgid "%{issuesCount} issues with a limit of %{maxIssueCount}"
+msgstr ""
msgid "%{issuesSize} with a limit of %{maxIssueCount}"
msgstr "%{issuesSize}个,上é™ä¸º%{maxIssueCount}"
@@ -435,8 +479,8 @@ msgstr "%{labelStart}方法: %{labelEnd}%{method}"
msgid "%{labelStart}Namespace:%{labelEnd} %{namespace}"
msgstr "%{labelStart}命å空间: %{labelEnd}%{namespace}"
-msgid "%{labelStart}Report Type:%{labelEnd} %{reportType}"
-msgstr "%{labelStart}报告类型: %{labelEnd}%{reportType}"
+msgid "%{labelStart}Scan Type:%{labelEnd} %{reportType}"
+msgstr ""
msgid "%{labelStart}Scanner:%{labelEnd} %{scanner}"
msgstr "%{labelStart}扫æ工具:%{labelEnd} %{scanner}"
@@ -625,9 +669,6 @@ msgid "%{securityScanner} result is not available because a pipeline has not bee
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] "%{securityScanner}无结果,因为自å¯ç”¨ä»¥æ¥å°šæœªè¿è¡Œæµæ°´çº¿ã€‚%{linkStart}è¿è¡Œæµæ°´çº¿%{linkEnd}"
-msgid "%{service_title} %{message}."
-msgstr "%{service_title}%{message}."
-
msgid "%{size} GiB"
msgstr "%{size} GiB"
@@ -711,6 +752,12 @@ msgstr "%{text}å¯ç”¨"
msgid "%{timebox_name} should belong either to a project or a group."
msgstr "%{timebox_name}应该属于一个项目或一个群组。"
+msgid "%{timebox_type} does not support burnup charts"
+msgstr ""
+
+msgid "%{timebox_type} must have a start and due date"
+msgstr ""
+
msgid "%{title} %{operator} %{threshold}"
msgstr "%{title} %{operator} %{threshold}"
@@ -735,8 +782,8 @@ msgstr ""
msgid "%{total} open issue weight"
msgstr "%{total}å¼€å¯è®®é¢˜æƒé‡"
-msgid "%{total} open issues"
-msgstr "%{total}个开å¯ä¸­çš„议题"
+msgid "%{total} warnings found: showing first %{warningsDisplayed}"
+msgstr ""
msgid "%{usage_ping_link_start}Learn more%{usage_ping_link_end} about what information is shared with GitLab Inc."
msgstr "%{usage_ping_link_start}了解更多%{usage_ping_link_end}分享给GitLab Inc.çš„ä¿¡æ¯ã€‚"
@@ -768,9 +815,6 @@ msgstr "%{webhooks_link_start}%{webhook_type}%{link_end}å…许您针对æŸä¸ªç¾¤
msgid "&lt; 1 hour"
msgstr ""
-msgid "&lt;no name set&gt;"
-msgstr "&lt;未设置å称&gt;"
-
msgid "&lt;no scopes selected&gt;"
msgstr "&lt;未选择范围&gt;"
@@ -801,6 +845,9 @@ msgstr "“%{level}â€ä¸æ˜¯æœ‰æ•ˆçš„å¯è§æ€§çº§åˆ«"
msgid "'%{name}' Value Stream created"
msgstr "'%{name}'价值æµå·²åˆ›å»º"
+msgid "'%{name}' Value Stream deleted"
+msgstr ""
+
msgid "'%{name}' stage already exists"
msgstr "“%{name}â€é˜¶æ®µå·²ç»å­˜åœ¨"
@@ -859,6 +906,9 @@ msgstr "+ 其余%{moreCount}项"
msgid "+ %{numberOfHiddenAssignees} more"
msgstr "+ 其余 %{numberOfHiddenAssignees} æ¡"
+msgid "+ %{numberOfHiddenReviewers} more"
+msgstr ""
+
msgid "+%d more"
msgid_plural "+%d more"
msgstr[0] "+其余%d项"
@@ -913,6 +963,10 @@ msgid "1 Day"
msgid_plural "%d Days"
msgstr[0] "%d天"
+msgid "1 Issue"
+msgid_plural "%d Issues"
+msgstr[0] ""
+
msgid "1 closed issue"
msgid_plural "%{issues} closed issues"
msgstr[0] "%{issues}个关闭的议题"
@@ -925,6 +979,10 @@ msgid "1 day"
msgid_plural "%d days"
msgstr[0] "%d天"
+msgid "1 deploy key"
+msgid_plural "%d deploy keys"
+msgstr[0] ""
+
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] "%d 个群组"
@@ -1018,6 +1076,9 @@ msgstr "8å°æ—¶"
msgid ":%{startLine} to %{endLine}"
msgstr ":%{startLine}到%{endLine}"
+msgid "A %{incident_docs_start}modified issue%{incident_docs_end} to guide the resolution of incidents."
+msgstr ""
+
msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr "Runner是一个执行任务的进程。您å¯ä»¥æ ¹æ®éœ€è¦é…置任æ„æ•°é‡çš„Runner。"
@@ -1030,6 +1091,9 @@ msgstr "åˆå¹¶å‰CI/CDæµæ°´çº¿å¿…é¡»è¿è¡Œä¸”æˆåŠŸã€‚"
msgid "A GitBook site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr "一个GitBook站点,它使用NetLifyæ¥ä»£æ›¿Gitlabçš„CI/CD,但ä»ç„¶å…·æœ‰æ‰€æœ‰å…¶ä»–主è¦çš„Gitlab功能。"
+msgid "A Gitpod configured Webapplication in Spring and Java"
+msgstr ""
+
msgid "A Hexo site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr "一个Hexo站点,它使用NetLifyæ¥ä»£æ›¿Gitlabçš„CI/CD,但ä»ç„¶å…·æœ‰æ‰€æœ‰å…¶ä»–主è¦çš„Gitlab功能。"
@@ -1201,9 +1265,15 @@ msgstr "æ‹’ç»è®¿é—®ï¼è¯·æ ¸æŸ¥æ‚¨æ˜¯å¦æœ‰æƒé™å°†éƒ¨ç½²å¯†é’¥æ·»åŠ åˆ°æ­¤ä»“
msgid "Access expiration date"
msgstr "访问过期时间"
+msgid "Access expires"
+msgstr ""
+
msgid "Access forbidden. Check your access level."
msgstr "访问被ç¦æ­¢ã€‚检查您的访问æƒé™ã€‚"
+msgid "Access granted"
+msgstr ""
+
msgid "Access requests"
msgstr ""
@@ -1213,6 +1283,9 @@ msgstr "ä¸å…许访问%{classification_label}"
msgid "Access to Pages websites are controlled based on the user's membership to a given project. By checking this box, users will be required to be logged in to have access to all Pages websites in your instance."
msgstr "Pages网站å¯ä¾æ®ç”¨æˆ·å¯¹é¡¹ç›®çš„æˆå‘˜èº«ä»½è¿›è¡Œè®¿é—®æŽ§åˆ¶ã€‚ 选中此项åŽï¼Œç”¨æˆ·éœ€è¦ç™»å½•æ‰èƒ½è®¿é—®æ‰€æœ‰çš„Pages网站。"
+msgid "AccessDropdown|Deploy Keys"
+msgstr ""
+
msgid "AccessDropdown|Groups"
msgstr "群组"
@@ -1330,12 +1403,6 @@ msgstr "有效的%{type}(%{token_length})"
msgid "Active Sessions"
msgstr "活动会è¯"
-msgid "Active Users:"
-msgstr "活跃用户:"
-
-msgid "Active users"
-msgstr "活跃用户数"
-
msgid "Activity"
msgstr "动æ€"
@@ -1502,9 +1569,6 @@ msgstr ""
msgid "Add label(s)"
msgstr "添加标记"
-msgid "Add license"
-msgstr "添加许å¯è¯"
-
msgid "Add list"
msgstr "添加列表"
@@ -1679,21 +1743,51 @@ msgstr "å·²ç¦ç”¨ç”¨æˆ·"
msgid "AdminArea|Bots"
msgstr "机器人"
+msgid "AdminArea|Components"
+msgstr ""
+
msgid "AdminArea|Developer"
msgstr "å¼€å‘人员"
+msgid "AdminArea|Features"
+msgstr ""
+
+msgid "AdminArea|Groups: %{number_of_groups}"
+msgstr ""
+
msgid "AdminArea|Guest"
msgstr "访客"
msgid "AdminArea|Included Free in license"
msgstr "å…费包å«äºŽè®¸å¯è¯ä¸­"
+msgid "AdminArea|Latest groups"
+msgstr ""
+
+msgid "AdminArea|Latest projects"
+msgstr ""
+
+msgid "AdminArea|Latest users"
+msgstr ""
+
msgid "AdminArea|Maintainer"
msgstr "维护者"
+msgid "AdminArea|New group"
+msgstr ""
+
+msgid "AdminArea|New project"
+msgstr ""
+
+msgid "AdminArea|New user"
+msgstr ""
+
msgid "AdminArea|Owner"
msgstr "所有者"
+msgid "AdminArea|Projects: %{number_of_projects}"
+msgstr ""
+
msgid "AdminArea|Reporter"
msgstr "报告者"
@@ -1721,6 +1815,9 @@ msgstr "用户的最高æƒé™ä¸º"
msgid "AdminArea|Users without a Group and Project"
msgstr "没有群组和项目的用户"
+msgid "AdminArea|Users: %{number_of_users}"
+msgstr ""
+
msgid "AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running."
msgstr "您å³å°†åœæ­¢æ‰€æœ‰ä½œä¸šã€‚这会中断并结æŸæ‰€æœ‰æ­£åœ¨è¿è¡Œçš„作业。"
@@ -1739,9 +1836,6 @@ msgstr "删除"
msgid "AdminProjects|Delete Project %{projectName}?"
msgstr "删除项目 %{projectName}?"
-msgid "AdminProjects|Delete project"
-msgstr "删除项目"
-
msgid "AdminSettings|Apply integration settings to all Projects"
msgstr "将集æˆè®¾ç½®åº”用于所有项目"
@@ -1979,21 +2073,30 @@ msgstr "用户é‡æ–°ç™»å½•åŽï¼Œå…¶å¸æˆ·å°†æ¢å¤ä¸ºå®Œå…¨æœ‰æ•ˆçš„å¸æˆ·"
msgid "AdminUsers|Without projects"
msgstr "无项目"
-msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
-msgstr "您å³å°†æ°¸ä¹…删除用户 %{username}。该用户的议题ã€åˆå¹¶è¯·æ±‚以åŠç›¸å…³çš„群组将被转移到系统的“Ghost用户â€ã€‚为é¿å…æ•°æ®ä¸¢å¤±ï¼Œå»ºè®®æ‚¨ä½¿ç”¨ %{strong_start}ç¦ç”¨ç”¨æˆ·%{strong_end} 功能。一旦您 %{strong_start}删除用户%{strong_end},将无法撤消或æ¢å¤ã€‚"
+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 %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
-msgstr "您å³å°†æ°¸ä¹…删除用户 %{username}。此æ“作会删除该用户的所有议题ã€åˆå¹¶è¯·æ±‚以åŠç›¸å…³çš„群组。为é¿å…æ•°æ®ä¸¢å¤±ï¼Œå»ºè®®æ‚¨ä½¿ç”¨ %{strong_start}ç¦ç”¨ç”¨æˆ·%{strong_end} 功能。一旦您 %{strong_start}删除用户%{strong_end},将无法撤消或æ¢å¤ã€‚"
+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 ""
msgid "AdminUsers|You cannot remove your own admin rights."
msgstr "您ä¸èƒ½åˆ é™¤æ‚¨è‡ªå·±çš„管ç†å‘˜æƒé™ã€‚"
+msgid "AdminUsers|You must transfer ownership or delete the groups owned by this user before you can delete their account"
+msgstr ""
+
msgid "Administration"
msgstr "管ç†"
msgid "Advanced"
msgstr "高级"
+msgid "Advanced Search"
+msgstr ""
+
+msgid "Advanced Search with Elasticsearch"
+msgstr ""
+
msgid "Advanced Settings"
msgstr "高级设置"
@@ -2070,6 +2173,9 @@ msgstr "在 GitLab中直接显示æ¥è‡ªæ‚¨æ‰€æœ‰ç›‘测工具的警报。简化å¯
msgid "AlertManagement|Edit"
msgstr "编辑"
+msgid "AlertManagement|Environment"
+msgstr ""
+
msgid "AlertManagement|Events"
msgstr "事件"
@@ -2082,6 +2188,9 @@ msgstr "ä¿¡æ¯"
msgid "AlertManagement|Issue"
msgstr "议题"
+msgid "AlertManagement|Key"
+msgstr ""
+
msgid "AlertManagement|Low"
msgstr "低"
@@ -2175,6 +2284,9 @@ msgstr "触å‘"
msgid "AlertManagement|Unknown"
msgstr "未知"
+msgid "AlertManagement|Value"
+msgstr ""
+
msgid "AlertManagement|View alerts in Opsgenie"
msgstr "在Opsgenie中查看警报"
@@ -2334,6 +2446,9 @@ msgstr "所有路径都相对于GitLab URL。请ä¸è¦åŒ…å«%{relative_url_link_
msgid "All projects"
msgstr "所有项目"
+msgid "All projects selected"
+msgstr ""
+
msgid "All security scans are enabled because %{linkStart}Auto DevOps%{linkEnd} is enabled on this project"
msgstr "所有安全扫æ都已å¯ç”¨ï¼Œå› ä¸ºæ­¤é¡¹ç›®å·²å¼€å¯äº†%{linkStart}Auto DevOps%{linkEnd}"
@@ -2421,6 +2536,9 @@ msgstr "这里å¯ä»¥æ·»åŠ å’Œç®¡ç† Kubernetes 集群。"
msgid "Almost there"
msgstr "å³å°†å®Œæˆ"
+msgid "Already blocked"
+msgstr ""
+
msgid "Also called \"Issuer\" or \"Relying party trust identifier\""
msgstr "也称为“签å‘者â€æˆ–“ä¾èµ–方信任标识符â€"
@@ -2475,6 +2593,9 @@ msgstr "空GitLab用户字段将在所有问题和注释的æ述中添加FogBug
msgid "An error has occurred"
msgstr "å‘生错误"
+msgid "An error occured while making the changes: %{error}"
+msgstr ""
+
msgid "An error occurred adding a draft to the thread."
msgstr "å‘主题添加è‰ç¨¿æ—¶å‡ºé”™ã€‚"
@@ -2502,12 +2623,6 @@ msgstr "预览 blob 时出错"
msgid "An error occurred when toggling the notification subscription"
msgstr "切æ¢é€šçŸ¥è®¢é˜…æ—¶å‘生错误"
-msgid "An error occurred when trying to resolve a comment. Please try again."
-msgstr "å°è¯•è§£å†³è¯„论时出错。请å†è¯•ä¸€æ¬¡ã€‚"
-
-msgid "An error occurred when trying to resolve a discussion. Please try again."
-msgstr "å°è¯•è§£å†³è®¨è®ºæ—¶å‡ºé”™ã€‚请å†è¯•ä¸€æ¬¡ã€‚"
-
msgid "An error occurred when updating the issue weight"
msgstr "更新议题æƒé‡æ—¶å‘生错误"
@@ -2523,12 +2638,6 @@ msgstr "为å²è¯—添加格å¼åŒ–标题时å‘生错误"
msgid "An error occurred while checking group path. Please refresh and try again."
msgstr "检查群组路径时出错,请刷新页é¢å¹¶é‡è¯•ã€‚"
-msgid "An error occurred while committing your changes."
-msgstr "æ交更改时å‘生错误。"
-
-msgid "An error occurred while creating the list. Please try again."
-msgstr ""
-
msgid "An error occurred while decoding the file."
msgstr "解ç æ–‡ä»¶æ—¶å‘生了错误。"
@@ -2601,26 +2710,20 @@ msgstr "获å–terraform报告时å‘生错误。"
msgid "An error occurred while fetching the Service Desk address."
msgstr "获å–æœåŠ¡å°åœ°å€æ—¶å‘生错误。"
-msgid "An error occurred while fetching the board issues. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the board lists. Please reload the page."
msgstr ""
msgid "An error occurred while fetching the board lists. Please try again."
msgstr "读å–看æ¿åˆ—表时出错。请å†è¯•ä¸€æ¬¡ã€‚"
-msgid "An error occurred while fetching the board swimlanes. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the builds."
msgstr "获å–该构建时å‘生了一个错误。"
msgid "An error occurred while fetching the job log."
msgstr "获å–作业日志时å‘生错误。"
-msgid "An error occurred while fetching the job trace."
-msgstr "获å–作业日志时å‘生错误。"
+msgid "An error occurred while fetching the job logs."
+msgstr ""
msgid "An error occurred while fetching the job."
msgstr "获å–作业详情时å‘生错误"
@@ -2766,9 +2869,6 @@ msgstr "ä¿å­˜LDAP覆盖状æ€æ—¶å‘生错误。请å†è¯•ä¸€æ¬¡ã€‚"
msgid "An error occurred while saving assignees"
msgstr "ä¿å­˜è¢«æŒ‡æ´¾äººæ—¶å‡ºçŽ°é”™è¯¯ã€‚"
-msgid "An error occurred while saving the template. Please check if the template exists."
-msgstr "ä¿å­˜æ¨¡æ¿æ—¶å‡ºé”™ã€‚请检查模æ¿æ˜¯å¦å­˜åœ¨ã€‚"
-
msgid "An error occurred while searching for milestones"
msgstr "æœç´¢é‡Œç¨‹ç¢‘时出错"
@@ -2787,12 +2887,12 @@ msgstr "å–消订阅通知时å‘生错误。"
msgid "An error occurred while updating approvers"
msgstr "更新核准人时å‘生错误"
+msgid "An error occurred while updating labels."
+msgstr ""
+
msgid "An error occurred while updating the comment"
msgstr "更新评论时å‘生错误"
-msgid "An error occurred while updating the list. Please try again."
-msgstr ""
-
msgid "An error occurred while validating group path"
msgstr "验è¯ç¾¤ç»„路径时å‘生错误"
@@ -2844,6 +2944,9 @@ msgstr "åœæ­¢Web终端时å‘生æ„外错误。"
msgid "An unknown error occurred while loading this graph."
msgstr "加载此图表时å‘生未知错误。"
+msgid "An unknown error occurred."
+msgstr ""
+
msgid "Analytics"
msgstr "分æž"
@@ -2877,12 +2980,12 @@ msgstr "å垃圾邮件验è¯"
msgid "Any"
msgstr "任何"
+msgid "Any %{header}"
+msgstr ""
+
msgid "Any Author"
msgstr "任何作者"
-msgid "Any Status"
-msgstr ""
-
msgid "Any branch"
msgstr "任何分支"
@@ -2934,6 +3037,9 @@ msgstr "应用"
msgid "Application ID"
msgstr "应用程åºID"
+msgid "Application limits saved successfully"
+msgstr ""
+
msgid "Application settings saved successfully"
msgstr "应用程åºè®¾ç½®ä¿å­˜æˆåŠŸ"
@@ -3080,7 +3186,7 @@ msgid "Approved the current merge request."
msgstr "批准了当å‰çš„åˆå¹¶è¯·æ±‚。"
msgid "Approved-By"
-msgstr "核准人"
+msgstr "已核准"
msgid "Approver"
msgstr "审批人"
@@ -3139,6 +3245,9 @@ msgstr "确定è¦å–消编辑此评论å—?"
msgid "Are you sure you want to close this blocked issue?"
msgstr "您确定è¦å…³é—­æ­¤è¢«å—阻的议题å—?"
+msgid "Are you sure you want to delete \"%{name}\" Value Stream?"
+msgstr ""
+
msgid "Are you sure you want to delete %{name}?"
msgstr "您确定è¦åˆ é™¤%{name}å—?"
@@ -3148,6 +3257,9 @@ msgstr "确定è¦åˆ é™¤è¿™äº›äº§ç‰©å—?"
msgid "Are you sure you want to delete this %{typeOfComment}?"
msgstr "确实è¦åˆ é™¤æ­¤%{typeOfComment}å—?"
+msgid "Are you sure you want to delete this SSH key?"
+msgstr ""
+
msgid "Are you sure you want to delete this board?"
msgstr "确定è¦åˆ é™¤æ­¤çœ‹æ¿å—?"
@@ -3172,6 +3284,10 @@ msgstr "确定放弃评论å—?"
msgid "Are you sure you want to erase this build?"
msgstr "您确定è¦åˆ é™¤è¿™ä¸ªæž„建å—?"
+msgid "Are you sure you want to import %d repository?"
+msgid_plural "Are you sure you want to import %d repositories?"
+msgstr[0] ""
+
msgid "Are you sure you want to lose unsaved changes?"
msgstr "确定è¦æ”¾å¼ƒæœªä¿å­˜çš„更改å—?"
@@ -3181,15 +3297,15 @@ msgstr "您确定è¦ä¸¢å¼ƒè®®é¢˜ä¿¡æ¯å—?"
msgid "Are you sure you want to merge immediately?"
msgstr "您确定è¦ç«‹å³åˆå¹¶å—?"
-msgid "Are you sure you want to permanently delete this license?"
-msgstr "确定è¦æ°¸ä¹…删除此许å¯è¯ï¼Ÿ"
-
msgid "Are you sure you want to re-deploy this environment?"
msgstr "您确定è¦é‡æ–°éƒ¨ç½²æ­¤çŽ¯å¢ƒå—?"
msgid "Are you sure you want to regenerate the public key? You will have to update the public key on the remote server before mirroring will work again."
msgstr "您确定è¦é‡æ–°ç”Ÿæˆå…¬é’¥å—?在镜åƒå†æ¬¡è¿è¡Œä¹‹å‰ï¼Œæ‚¨å¿…须更新远程æœåŠ¡å™¨ä¸Šçš„公钥。"
+msgid "Are you sure you want to reindex?"
+msgstr ""
+
msgid "Are you sure you want to remove %{group_name}?"
msgstr "确定移除群组 %{group_name} å—?"
@@ -3217,11 +3333,14 @@ msgstr "您确定è¦æ’¤é”€æ­¤%{type}å—?此æ“作ä¸å¯é€†ã€‚"
msgid "Are you sure you want to revoke this nickname?"
msgstr "您确定è¦å–消此昵称?"
+msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
+msgstr ""
+
msgid "Are you sure you want to stop this environment?"
msgstr "是å¦ç¡®å®šç»ˆæ­¢å½“å‰çŽ¯å¢ƒï¼Ÿ"
msgid "Are you sure you want to unlock %{path_lock_path}?"
-msgstr "您确定è¦è§£é” %{path_lock_path} å—?"
+msgstr "您确定è¦è§£é”%{path_lock_path}å—?"
msgid "Are you sure you want to unsubscribe from the %{type}: %{link_to_noteable_text}?"
msgstr "您确定è¦å–消订阅 %{type}:%{link_to_noteable_text}å—?"
@@ -3238,6 +3357,9 @@ msgstr "您确认è¦åˆ é™¤GPG密钥么?删除此GPG密钥ä¸ä¼šå½±å“å·²ç»ç­¾
msgid "Are you sure? The device will be signed out of GitLab and all remember me tokens revoked."
msgstr ""
+msgid "Are you sure? This will invalidate your registered applications and U2F / WebAuthn devices."
+msgstr ""
+
msgid "Are you sure? This will invalidate your registered applications and U2F devices."
msgstr "你确定å—?这将使您的已注册应用和U2F设备失效。"
@@ -3256,9 +3378,6 @@ msgstr "产物已æˆåŠŸåˆ é™¤ã€‚"
msgid "Artifacts"
msgstr "产物"
-msgid "As U2F devices are only supported by a few browsers, we require that you set up a two-factor authentication app before a U2F device. That way you'll always be able to log in - even when you're using an unsupported browser."
-msgstr "由于仅有部分æµè§ˆå™¨æ”¯æŒU2F设备,我们è¦æ±‚您在使用U2F设备之å‰è®¾ç½®ä¸€ä¸ªåŒé‡è®¤è¯åº”用。这样å³ä½¿æ‚¨ä½¿ç”¨ä¸æ”¯æŒU2Fçš„æµè§ˆå™¨æ‚¨ä¹Ÿå¯ä»¥ç™»å½•ã€‚"
-
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 ""
@@ -3450,6 +3569,9 @@ msgstr "项目事件"
msgid "AuditLogs|Target"
msgstr "目标"
+msgid "AuditLogs|This month"
+msgstr ""
+
msgid "AuditLogs|User Events"
msgstr "用户事件"
@@ -3489,6 +3611,9 @@ msgstr "身份验è¯æ–¹æ³•å·²æ›´æ–°"
msgid "Authentication via U2F device failed."
msgstr "通过U2F设备进行身份验è¯å¤±è´¥ã€‚"
+msgid "Authentication via WebAuthn device failed."
+msgstr ""
+
msgid "Author"
msgstr "作者"
@@ -3756,15 +3881,6 @@ msgstr "Bamboo 根地å€ï¼Œä¾‹å¦‚:https://bambo.example.com"
msgid "BambooService|You must set up automatic revision labeling and a repository trigger in Bamboo."
msgstr "您必须在Bamboo中设置自动版本标签和仓库触å‘器。"
-msgid "BatchComments|Delete all pending comments"
-msgstr "删除所有待处ç†çš„评论"
-
-msgid "BatchComments|Discard review?"
-msgstr "放弃评审?"
-
-msgid "BatchComments|You're about to discard your review which will delete all of your pending comments. The deleted comments %{strong_start}cannot%{strong_end} be restored."
-msgstr "您å³å°†æ”¾å¼ƒæ‚¨çš„评审,该æ“作将删除所有待处ç†çš„评论。请注æ„已删除评论 %{strong_start}ä¸èƒ½%{strong_end} æ¢å¤ã€‚"
-
msgid "Be careful. Changing the project's namespace can have unintended side effects."
msgstr "请注æ„,更改项目的命å空间å¯èƒ½ä¼šäº§ç”Ÿéžé¢„期的副作用。"
@@ -3786,6 +3902,9 @@ msgstr "您将在下é¢æ‰¾åˆ°æ‰€æœ‰å…¬å¼€çš„群组。"
msgid "Bi-weekly code coverage"
msgstr "åŒå‘¨ä»£ç è¦†ç›–范围"
+msgid "Billable Users:"
+msgstr ""
+
msgid "Billing"
msgstr "计费"
@@ -3795,8 +3914,8 @@ msgstr "%{group_name}正在使用%{plan_name}计划。"
msgid "BillingPlans|@%{user_name} you are currently using the %{plan_name} plan."
msgstr "@%{user_name}您正在使用%{plan_name}计划。"
-msgid "BillingPlans|Congratulations, your new trial is activated"
-msgstr "æ­å–œï¼Œæ‚¨çš„试用计划已å¯ç”¨"
+msgid "BillingPlans|Congratulations, your free trial is activated."
+msgstr ""
msgid "BillingPlans|If you would like to downgrade your plan please contact %{support_link_start}Customer Support%{support_link_end}."
msgstr "如果您想è¦é™çº§æ‚¨çš„订阅计划,请è”ç³»%{support_link_start}客户支æŒ%{support_link_end}。"
@@ -3858,6 +3977,9 @@ msgstr "从 Bitbucket 导入"
msgid "Blame"
msgstr "Blame"
+msgid "Block user"
+msgstr ""
+
msgid "Blocked"
msgstr "å·²ç¦ç”¨"
@@ -3873,33 +3995,39 @@ msgstr "阻止"
msgid "Blog"
msgstr "åšå®¢"
-msgid "Board name"
-msgstr "看æ¿å称"
-
msgid "Board scope"
msgstr "看æ¿èŒƒå›´"
msgid "Board scope affects which issues are displayed for anyone who visits this board"
msgstr "看æ¿èŒƒå›´ä¼šå½±å“访问此看æ¿çš„人å¯ä»¥æ˜¾ç¤ºå“ªäº›è®®é¢˜"
-msgid "BoardBlankState|Add default lists"
-msgstr "添加默认列表"
-
-msgid "BoardBlankState|Add the following default lists to your Issue Board with one click:"
-msgstr "å•å‡»å°†ä¸‹åˆ—默认列表添加到议题看æ¿ï¼š"
-
-msgid "BoardBlankState|Nevermind, I'll use my own"
-msgstr "ä¸å¿…了,使用自定义列表"
-
-msgid "BoardBlankState|Starting out with the default set of lists will get you right on the way to making the most of your board."
-msgstr "使用默认列表,是您充分利用看æ¿ä½œç”¨çš„起点。"
-
msgid "Boards"
msgstr "看æ¿"
msgid "Boards and Board Lists"
msgstr "看æ¿å’Œçœ‹æ¿åˆ—表"
+msgid "Boards|An error occurred while creating the issue. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while creating the list. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching issues. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching the board issues. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching the board swimlanes. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while moving the issue. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while updating the list. Please try again."
+msgstr ""
+
msgid "Boards|Collapse"
msgstr "收起"
@@ -3924,8 +4052,8 @@ msgstr "未在此项目的仓库中找到 %{branchName} 分支。"
msgid "Branch %{branch_name} was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr ""
-msgid "Branch has changed"
-msgstr "分支已有新å˜æ›´"
+msgid "Branch changed"
+msgstr ""
msgid "Branch is already taken"
msgstr "分支已被采用"
@@ -4230,6 +4358,9 @@ msgstr "已关闭"
msgid "CLOSED (MOVED)"
msgstr "已关闭(已移走)"
+msgid "CODEOWNERS rule violation"
+msgstr ""
+
msgid "CONTRIBUTING"
msgstr "贡献信æ¯"
@@ -4260,9 +4391,6 @@ msgstr "无法应用此建议。"
msgid "Can't create snippet: %{err}"
msgstr "无法创建代ç ç‰‡æ–­: %{err}"
-msgid "Can't edit as source branch was deleted"
-msgstr "由于æºåˆ†æ”¯å·²åˆ é™¤ï¼Œå› æ­¤æ— æ³•ç¼–辑"
-
msgid "Can't fetch content for the blob: %{err}"
msgstr "无法获å–Blob的内容: %{err}"
@@ -4275,9 +4403,6 @@ msgstr "找ä¸åˆ°å˜é‡: ZiteReader"
msgid "Can't load mermaid module: %{err}"
msgstr "无法加载mermaid模å—: %{err}"
-msgid "Can't remove group members without group managed account"
-msgstr "éžç¾¤ç»„托管账户无法删除群组æˆå‘˜"
-
msgid "Can't scan the code?"
msgstr "无法扫æ二维ç ï¼Ÿ"
@@ -4320,6 +4445,9 @@ msgstr "无法创建滥用报告。用户已被删除。"
msgid "Cannot create the abuse report. This user has been blocked."
msgstr "无法创建滥用报告。此用户已被ç¦ç”¨ã€‚"
+msgid "Cannot enable shared runners because parent group does not allow it"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr "ä¸èƒ½åŒæ—¶è¿è¡Œå¤šä¸ªJira导入"
@@ -4345,10 +4473,10 @@ msgid "Cannot modify provider during creation"
msgstr "创建期间无法修改æ供者"
msgid "Cannot promote issue because it does not belong to a group."
-msgstr "ä¸èƒ½æå‡é—®é¢˜ï¼Œå› ä¸ºå®ƒä¸å±žäºŽä¸€ä¸ªç»„。"
+msgstr "ä¸èƒ½å‡çº§é—®é¢˜ï¼Œå› ä¸ºå®ƒä¸å±žäºŽä¸€ä¸ªç»„。"
msgid "Cannot promote issue due to insufficient permissions."
-msgstr "由于æƒé™ä¸è¶³ï¼Œæ— æ³•æå‡è®®é¢˜ã€‚"
+msgstr "由于æƒé™ä¸è¶³ï¼Œæ— æ³•å‡çº§è®®é¢˜ã€‚"
msgid "Cannot refer to a group %{timebox_type} by an internal id!"
msgstr "无法通过内部ID引用群组%{timebox_type}ï¼"
@@ -4425,6 +4553,15 @@ msgstr "更改您的密ç "
msgid "Change your password or recover your current one"
msgstr "更改您的密ç æˆ–æ¢å¤å½“å‰å¯†ç "
+msgid "ChangeReviewer|Reviewer changed from %{old} to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Reviewer changed to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Unassigned"
+msgstr ""
+
msgid "ChangeTypeActionLabel|Pick into branch"
msgstr "选择分支"
@@ -4464,6 +4601,9 @@ msgstr "仅显示部分。点此显示全部。"
msgid "Changes the title to \"%{title_param}\"."
msgstr "将标题更改为“%{title_param}â€ã€‚"
+msgid "Changes were successfully made."
+msgstr ""
+
msgid "Changes won't take place until the index is %{link_start}recreated%{link_end}."
msgstr "在索引%{link_start}é‡æ–°åˆ›å»º%{link_end}之å‰ï¼Œæ›´æ”¹å°†ä¸ä¼šç”Ÿæ•ˆã€‚"
@@ -4869,6 +5009,9 @@ msgstr "éšè—"
msgid "CiVariables|Protected"
msgstr "å—ä¿æŠ¤"
+msgid "CiVariables|Remove variable"
+msgstr ""
+
msgid "CiVariables|Remove variable row"
msgstr "删除å˜é‡è¡Œ"
@@ -4947,9 +5090,6 @@ msgstr "清除图表过滤器"
msgid "Clear due date"
msgstr "清除截止日期"
-msgid "Clear input"
-msgstr "清除输入"
-
msgid "Clear recent searches"
msgstr "清除最近的æœç´¢"
@@ -4998,6 +5138,9 @@ msgstr "客户端认è¯å¯†é’¥"
msgid "Client authentication key password"
msgstr "客户端认è¯å¯†é’¥å¯†ç "
+msgid "Client request timeout"
+msgstr ""
+
msgid "Clients"
msgstr "客户端"
@@ -5082,6 +5225,27 @@ msgstr "集群级别"
msgid "Cluster type must be specificed for Stages::ClusterEndpointInserter"
msgstr "Stages::ClusterEndpointInserter需è¦é›†ç¾¤ç±»åž‹"
+msgid "ClusterAgents|Configuration"
+msgstr ""
+
+msgid "ClusterAgents|Connect your cluster with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate Kubernetes with a GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Name"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Agent also requires %{linkStart}enabling the Agent Server%{linkEnd}"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Kubernetes Agent allows an Infrastructure as Code, GitOps approach to integrating Kubernetes clusters with GitLab. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "ClusterAgent|This feature is only available for premium plans"
msgstr ""
@@ -5151,11 +5315,11 @@ msgstr "所有数æ®å°†è¢«åˆ é™¤ï¼Œæ— æ³•æ¢å¤ã€‚"
msgid "ClusterIntegration|All installed applications and related resources"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster."
-msgstr "å…许 GitLab 管ç†æ­¤é›†ç¾¤çš„命å空间和æœåŠ¡è´¦æˆ·ã€‚"
+msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{linkStart}More information%{linkEnd}"
+msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{startLink}More information%{endLink}"
-msgstr "å…许GitLab管ç†æ­¤ç¾¤é›†çš„命å空间和æœåŠ¡è´¦æˆ·ã€‚%{startLink}更多信æ¯%{endLink}"
+msgid "ClusterIntegration|Allow GitLab to manage namespaces and service accounts for this cluster."
+msgstr ""
msgid "ClusterIntegration|Alternatively, "
msgstr ""
@@ -5175,6 +5339,9 @@ msgstr "å°è¯•èŽ·å–您的项目时å‘生错误:%{error}"
msgid "ClusterIntegration|An error occurred while trying to fetch zone machine types: %{error}"
msgstr "å°è¯•èŽ·å–设备类型时å‘生错误:%{error}"
+msgid "ClusterIntegration|An unknown error occurred while attempting to connect to Kubernetes."
+msgstr ""
+
msgid "ClusterIntegration|Any project namespaces"
msgstr ""
@@ -5190,6 +5357,9 @@ msgstr "通过AWS验è¯"
msgid "ClusterIntegration|Authenticate with Amazon Web Services"
msgstr "通过Amazon网络æœåŠ¡éªŒè¯"
+msgid "ClusterIntegration|Authentication Error"
+msgstr ""
+
msgid "ClusterIntegration|Base domain"
msgstr "基础域"
@@ -5208,14 +5378,23 @@ msgstr "Cert-Manager是一个本地Kubernetesè¯ä¹¦ç®¡ç†æŽ§åˆ¶å™¨ï¼Œå¯ç”¨äºŽé¢
msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
msgstr "è¯ä¹¦æŽˆæƒåŒ…(PEMæ ¼å¼)"
-msgid "ClusterIntegration|Choose the %{startLink}security group %{externalLinkIcon} %{endLink} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
-msgstr "选择应用于弹性网络接å£çš„%{startLink}安全组%{externalLinkIcon}%{endLink},该接å£åœ¨å·¥ä½œèŠ‚点å­ç½‘中创建并由EKS管ç†ã€‚"
+msgid "ClusterIntegration|Check your CA certificate"
+msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}subnets %{externalLinkIcon} %{endLink} in your VPC where your worker nodes will run."
-msgstr "在VPC中选择è¿è¡Œå·¥ä½œèŠ‚点的%{startLink}å­ç½‘%{externalLinkIcon}%{endLink}。"
+msgid "ClusterIntegration|Check your cluster status"
+msgstr ""
+
+msgid "ClusterIntegration|Check your token"
+msgstr ""
+
+msgid "ClusterIntegration|Choose the %{linkStart}security group %{linkEnd} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
+msgstr ""
+
+msgid "ClusterIntegration|Choose the %{linkStart}subnets %{linkEnd} in your VPC where your worker nodes will run."
+msgstr ""
-msgid "ClusterIntegration|Choose the worker node %{startLink}instance type %{externalLinkIcon} %{endLink}."
-msgstr "选择工作节点的%{startLink}实例类型%{externalLinkIcon}%{endLink}。"
+msgid "ClusterIntegration|Choose the worker node %{linkStart}instance type%{linkEnd}."
+msgstr ""
msgid "ClusterIntegration|Choose which applications to install on your Kubernetes cluster."
msgstr ""
@@ -5226,11 +5405,8 @@ msgstr "请选择使用此Kubernetes群集的环境。"
msgid "ClusterIntegration|Clear cluster cache"
msgstr "清除集群缓存"
-msgid "ClusterIntegration|Clear the local cache of namespace and service accounts. This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
-msgstr "清除å称空间和æœåŠ¡å¸æˆ·çš„本地缓存。如集æˆå·²å¤±åŽ»åŒæ­¥ï¼Œåˆ™æ­¤æ“作为必须。缓存将在所需å称空间和æœåŠ¡å¸æˆ·çš„下一个CI作业期间é‡æ–°ç”Ÿæˆã€‚"
-
-msgid "ClusterIntegration|Cluster being created"
-msgstr "正在创建集群"
+msgid "ClusterIntegration|Clear the local cache of namespace and service accounts."
+msgstr ""
msgid "ClusterIntegration|Cluster management project (alpha)"
msgstr "集群管ç†é¡¹ç›®(alpha)"
@@ -5241,15 +5417,21 @@ msgstr "群集å称为必填项。"
msgid "ClusterIntegration|Cluster_applications artifact too big. Maximum allowable size: %{human_size}"
msgstr "Cluster_applications产物太大。å…许的最大大å°: %{human_size}"
-msgid "ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters."
-msgstr "层级中最低且匹é…环境范围的集群将会被使用。例如,项目群集将优先于群组群集。"
-
msgid "ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters. %{linkStart}More information%{linkEnd}"
msgstr "层级中最低且匹é…环境范围的集群将会被使用。例如,项目群集将优先于群组群集。%{linkStart}更多信æ¯%{linkEnd}"
+msgid "ClusterIntegration|Clusters connected with a certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Connect cluster with certificate"
+msgstr ""
+
msgid "ClusterIntegration|Connect existing cluster"
msgstr ""
+msgid "ClusterIntegration|Connection Error"
+msgstr ""
+
msgid "ClusterIntegration|Copy API URL"
msgstr "å¤åˆ¶API地å€"
@@ -5325,6 +5507,12 @@ msgstr "Crossplane支æŒä½¿ç”¨%{codeStart}kubectl%{codeEnd}或%{linkStart}GitLab
msgid "ClusterIntegration|Deletes all GitLab resources attached to this cluster during removal"
msgstr "移除过程中删除此集群中的所有GitLab资æº"
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared."
+msgstr ""
+
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared. %{linkStart}More information%{linkEnd}"
+msgstr ""
+
msgid "ClusterIntegration|Did you know?"
msgstr "你是å¦äº†è§£ï¼Ÿ"
@@ -5394,6 +5582,9 @@ msgstr "Fluentd"
msgid "ClusterIntegration|Fluentd is an open source data collector, which lets you unify the data collection and consumption for a better use and understanding of data. It requires at least one of the following logs to be successfully installed."
msgstr "Fluentd是一个开æºæ•°æ®æ”¶é›†å™¨ï¼Œå¯ä»¥ç»Ÿä¸€æ•°æ®æ”¶é›†å’Œåˆ©ç”¨ï¼Œä»¥ä¾¿æ›´å¥½åœ°ä½¿ç”¨å’Œäº†è§£æ•°æ®ã€‚它è¦æ±‚至少安装一个以下日志。"
+msgid "ClusterIntegration|GitLab Agent managed clusters"
+msgstr ""
+
msgid "ClusterIntegration|GitLab Container Network Policies"
msgstr "GitLab容器网络策略"
@@ -5406,6 +5597,12 @@ msgstr "GitLab Runner"
msgid "ClusterIntegration|GitLab Runner connects to the repository and executes CI/CD jobs, pushing results back and deploying applications to production."
msgstr "GitLab Runner连接到仓库并执行CI/CD作业,返回结果并将应用程åºéƒ¨ç½²åˆ°ç”Ÿäº§çŽ¯å¢ƒã€‚"
+msgid "ClusterIntegration|GitLab failed to authenticate."
+msgstr ""
+
+msgid "ClusterIntegration|GitLab failed to connect to the cluster."
+msgstr ""
+
msgid "ClusterIntegration|GitLab-managed cluster"
msgstr "GitLab管ç†çš„集群"
@@ -5427,6 +5624,9 @@ msgstr "Google Kubernetes Engine 项目"
msgid "ClusterIntegration|Group cluster"
msgstr "群组级集群"
+msgid "ClusterIntegration|HTTP Error"
+msgstr ""
+
msgid "ClusterIntegration|Helm Tiller"
msgstr "Helm Tiller"
@@ -5460,8 +5660,11 @@ msgstr "实例集群"
msgid "ClusterIntegration|Instance type"
msgstr "实例类型"
-msgid "ClusterIntegration|Integrate Kubernetes cluster automation"
-msgstr "集æˆKubernetes集群自动化"
+msgid "ClusterIntegration|Integrate Kubernetes with a cluster certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Integrate with a cluster certificate"
+msgstr ""
msgid "ClusterIntegration|Issuer Email"
msgstr "ç­¾å‘人电å­é‚®ä»¶"
@@ -5496,9 +5699,6 @@ msgstr "Knative域åå·²æˆåŠŸæ›´æ–°ã€‚"
msgid "ClusterIntegration|Knative extends Kubernetes to provide a set of middleware components that are essential to build modern, source-centric, and container-based applications that can run anywhere: on premises, in the cloud, or even in a third-party data center."
msgstr "Knative扩展了Kubernetes,æ供了一组中间件组件,这些组件对于构建å¯åœ¨ä»»ä½•åœ°æ–¹è¿è¡ŒçŽ°ä»£çš„ã€ä»¥å¼€æºä¸ºä¸­å¿ƒå’ŒåŸºäºŽå®¹å™¨çš„应用程åºè‡³å…³é‡è¦ï¼šåœ¨æœ¬åœ°ï¼Œåœ¨äº‘中,甚至在第三方数æ®ä¸­å¿ƒã€‚"
-msgid "ClusterIntegration|Kubernetes cluster"
-msgstr "Kubernetes 集群"
-
msgid "ClusterIntegration|Kubernetes cluster is being created..."
msgstr "正在创建Kubernetes集群..."
@@ -5511,9 +5711,6 @@ msgstr "å·²æˆåŠŸåˆ›å»ºKubernetes集群。"
msgid "ClusterIntegration|Kubernetes clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr "通过Kubernetes群集集æˆï¼Œå¯ä»¥è½»æ¾åœ°ä½¿ç”¨è¯„审应用ã€éƒ¨ç½²åº”用ã€è¿è¡Œæµæ°´çº¿ç­‰ç­‰ã€‚"
-msgid "ClusterIntegration|Kubernetes clusters can be used to deploy applications and to provide Review Apps for this project"
-msgstr "Kubernetes 集群å¯ç”¨äºŽéƒ¨ç½²åº”用程åºå’Œæ供此项目的评审应用"
-
msgid "ClusterIntegration|Kubernetes version"
msgstr "Kubernetes版本"
@@ -5526,8 +5723,8 @@ msgstr "进一步了解 %{help_link_start_machine_type}实例类型%{help_link_e
msgid "ClusterIntegration|Learn more about %{help_link_start}zones%{help_link_end}."
msgstr "进一步了解 %{help_link_start}地域%{help_link_end}。"
-msgid "ClusterIntegration|Learn more about %{startLink}Regions %{externalLinkIcon}%{endLink}."
-msgstr "了解更多关于%{startLink}区域 %{externalLinkIcon}%{endLink}çš„ä¿¡æ¯ã€‚"
+msgid "ClusterIntegration|Learn more about %{linkStart}Regions%{linkEnd}."
+msgstr ""
msgid "ClusterIntegration|Learn more about Kubernetes"
msgstr "了解更多的Kubernetesä¿¡æ¯"
@@ -5571,12 +5768,18 @@ msgstr "记录模å¼"
msgid "ClusterIntegration|Machine type"
msgstr "机器类型"
+msgid "ClusterIntegration|Make sure your API endpoint is correct"
+msgstr ""
+
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create Kubernetes clusters"
msgstr "请确ä¿æ‚¨çš„å¸æˆ·%{link_to_requirements}å¯ä»¥åˆ›å»º Kubernetes 集群"
msgid "ClusterIntegration|Manage your Kubernetes cluster by visiting %{provider_link}"
msgstr "通过访问%{provider_link}管ç†Kubernetes群集"
+msgid "ClusterIntegration|Namespace per environment"
+msgstr ""
+
msgid "ClusterIntegration|No IAM Roles found"
msgstr "未找到IAM角色"
@@ -5622,6 +5825,9 @@ msgstr "未找到å­ç½‘"
msgid "ClusterIntegration|No zones matched your search"
msgstr "未找到您æœç´¢çš„地域"
+msgid "ClusterIntegration|Node calculations use the Kubernetes Metrics API. Make sure your cluster has metrics installed"
+msgstr ""
+
msgid "ClusterIntegration|Number of nodes"
msgstr "节点数é‡"
@@ -5664,6 +5870,9 @@ msgstr "预置角色ARN"
msgid "ClusterIntegration|RBAC-enabled cluster"
msgstr "å¯ç”¨RBAC的群集"
+msgid "ClusterIntegration|Read our %{linkStart}help page%{linkEnd} on Kubernetes cluster integration."
+msgstr ""
+
msgid "ClusterIntegration|Read our %{link_start}help page%{link_end} on Kubernetes cluster integration."
msgstr "请查阅关于Kubernetes集群集æˆçš„%{link_start}帮助页é¢%{link_end}。"
@@ -5766,8 +5975,8 @@ msgstr "请先选择一个区域然åŽé€‰æ‹©å®‰å…¨ç»„"
msgid "ClusterIntegration|Select a VPC to choose a subnet"
msgstr "请先选择一个区域然åŽé€‰æ‹©å­ç½‘"
-msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
-msgstr "请选择EKS集群的VPC。如需使用新的VPC, 请先在%{startLink}Amazon Web Services%{externalLinkIcon}%{endLink}上创建一个。"
+msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{linkStart}Amazon Web Services %{linkEnd}."
+msgstr ""
msgid "ClusterIntegration|Select a network to choose a subnetwork"
msgstr "选择一个网络以选择å­ç½‘"
@@ -5799,8 +6008,8 @@ msgstr "按项目和地域选择实例类型"
msgid "ClusterIntegration|Select project to choose zone"
msgstr "按项目选择地域"
-msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
-msgstr "选择将用于创建EC2节点的密钥对å称。如需è¦ä½¿ç”¨æ–°çš„密钥对å称,请先在%{startLink}Amazon Web Services%{externalLinkIcon}%{endLink}上创建一个。"
+msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
+msgstr ""
msgid "ClusterIntegration|Select zone"
msgstr "选择地域"
@@ -5889,9 +6098,18 @@ msgstr "与当å‰é¡¹ç›®ç›¸å…³è”的命å空间。用于部署看æ¿ã€pod日志
msgid "ClusterIntegration|There was a problem authenticating with your cluster. Please ensure your CA Certificate and Token are valid."
msgstr "群集身份验è¯æ—¶å‡ºçŽ°é—®é¢˜ã€‚请确ä¿æ‚¨çš„CAè¯ä¹¦å’Œä»¤ç‰Œæœ‰æ•ˆã€‚"
+msgid "ClusterIntegration|There was an HTTP error when connecting to your cluster."
+msgstr ""
+
msgid "ClusterIntegration|This account must have permissions to create a Kubernetes cluster in the %{link_to_container_project} specified below"
msgstr "该å¸æˆ·éœ€å…·å¤‡åœ¨å¦‚下指定的%{link_to_container_project}中创建 Kubernetes集群的æƒé™"
+msgid "ClusterIntegration|This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
+msgstr ""
+
+msgid "ClusterIntegration|This is necessary to clear existing environment-namespace associations from clusters previously managed by GitLab."
+msgstr ""
+
msgid "ClusterIntegration|This option will allow you to install applications on RBAC clusters."
msgstr "此选项å…许您在å¯ç”¨RBAC的群集上安装应用程åºã€‚"
@@ -5916,9 +6134,21 @@ msgstr "è¦åˆ é™¤é›†æˆï¼Œè¯·è¾“å…¥%{clusterName}以确认:"
msgid "ClusterIntegration|To use a new project, first create one on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}."
msgstr ""
+msgid "ClusterIntegration|Troubleshooting tips:"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Authenticate"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Connect"
+msgstr ""
+
msgid "ClusterIntegration|Uninstall %{appTitle}"
msgstr "å¸è½½ %{appTitle}"
+msgid "ClusterIntegration|Unknown Error"
+msgstr ""
+
msgid "ClusterIntegration|Update %{appTitle}"
msgstr "æ›´æ–°%{appTitle}"
@@ -5979,8 +6209,8 @@ msgstr "您的å¸æˆ·å¿…须有æƒé™%{link_to_kubernetes_engine}"
msgid "ClusterIntegration|Your cluster API is unreachable. Please ensure your API URL is correct."
msgstr "您的 API 无法访问。请确ä¿æ‚¨çš„ API URL 正确。"
-msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
-msgstr "您的æœåŠ¡è§’色ä¸åŒäºŽè®¤è¯æ—¶ä½¿ç”¨çš„æ供角色。它将å…许Amazon EKSå’ŒKubernetes控制层é¢ä»¥æ‚¨çš„身份管ç†AWS资æºã€‚ è‹¥è¦ä½¿ç”¨æ–°è§’色,首先在%{startLink}Amazon Web Services %{externalLinkIcon}%{endLink}上创建一个角色。"
+msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
+msgstr ""
msgid "ClusterIntegration|Zone"
msgstr "地域"
@@ -6099,6 +6329,9 @@ msgstr "用户世代表显示过去%{months_included}个月内的状况。åªæœ‰
msgid "Collapse"
msgstr "收起"
+msgid "Collapse all threads"
+msgstr ""
+
msgid "Collapse approvers"
msgstr "折å æ ¸å‡†äºº"
@@ -6247,8 +6480,8 @@ msgstr "æ交者:"
msgid "Commit…"
msgstr "æ交..."
-msgid "Company"
-msgstr "å…¬å¸"
+msgid "Community forum"
+msgstr ""
msgid "Company name"
msgstr "å…¬å¸å称"
@@ -6256,6 +6489,9 @@ msgstr "å…¬å¸å称"
msgid "Compare"
msgstr "比较"
+msgid "Compare %{oldCommitId}...%{newCommitId}"
+msgstr ""
+
msgid "Compare Git revisions"
msgstr "比较Gitæ交版本"
@@ -6271,6 +6507,9 @@ msgstr "与上个æ交比较å˜æ›´å†…容"
msgid "Compare changes with the merge request target branch"
msgstr "与åˆå¹¶è¯·æ±‚的目标分支比较å˜æ›´å†…容"
+msgid "Compare submodule commit revisions"
+msgstr ""
+
msgid "Compare with previous version"
msgstr "与以å‰çš„版本比较"
@@ -6406,6 +6645,9 @@ msgstr "é…ç½® %{link} 集æˆã€‚"
msgid "Configure the way a user creates a new account."
msgstr "é…置用户创建新å¸æˆ·çš„æ–¹å¼ã€‚"
+msgid "Configure which lists are shown for anyone who visits this board"
+msgstr ""
+
msgid "Confirm"
msgstr "确认"
@@ -6628,6 +6870,9 @@ msgstr[0] "删除标签"
msgid "ContainerRegistry|Set cleanup policy"
msgstr "设置清ç†ç­–ç•¥"
+msgid "ContainerRegistry|Some tags were not deleted"
+msgstr ""
+
msgid "ContainerRegistry|Something went wrong while fetching the cleanup policy."
msgstr "获å–清ç†æ”¿ç­–时出了错。"
@@ -6667,6 +6912,9 @@ msgstr "å称匹é…此正则表达å¼çš„标签将%{italicStart}被ä¿ç•™:%{ital
msgid "ContainerRegistry|Tags with names matching this regex pattern will %{italicStart}expire:%{italicEnd}"
msgstr "å称匹é…此正则表达å¼çš„标签将%{italicStart}过期:%{italicEnd}"
+msgid "ContainerRegistry|The cleanup policy timed out before it could delete all tags. An administrator can %{adminLinkStart}manually run cleanup now%{adminLinkEnd} or you can wait for the cleanup policy to automatically run again. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "ContainerRegistry|The last tag related to this image was recently removed. This empty image and any associated data will be automatically removed as part of the regular Garbage Collection process. If you have any questions, contact your administrator."
msgstr "与此镜åƒç›¸å…³çš„最åŽä¸€ä¸ªæ ‡ç­¾æœ€è¿‘已被删除。空镜åƒå’Œæ‰€æœ‰ç›¸å…³æ•°æ®å°†ä½œä¸ºå¸¸è§„垃圾收集过程的一部分自动清除。如有任何疑问,请与管ç†å‘˜è”系。"
@@ -6799,6 +7047,9 @@ msgstr "%{calendar_date}的贡献"
msgid "Contributions per group member"
msgstr "群组æˆå‘˜è´¡çŒ®è¯¦æƒ…"
+msgid "Contributor"
+msgstr ""
+
msgid "Contributors"
msgstr "贡献者"
@@ -6928,6 +7179,9 @@ msgstr "无法授æƒèŠå¤©æ˜µç§°ã€‚å†è¯•ä¸€æ¬¡ï¼"
msgid "Could not change HEAD: branch '%{branch}' does not exist"
msgstr "无法更改HEAD:分支“%{branch}â€ä¸å­˜åœ¨"
+msgid "Could not commit. An unexpected error occurred."
+msgstr ""
+
msgid "Could not connect to FogBugz, check your URL"
msgstr "无法连接到 FogBugz,请检查您的 URL"
@@ -6967,6 +7221,9 @@ msgstr "未找到设计."
msgid "Could not find iteration"
msgstr "未找到迭代"
+msgid "Could not load instance counts. Please refresh the page to try again."
+msgstr ""
+
msgid "Could not remove the trigger."
msgstr "无法删除触å‘器。"
@@ -6991,12 +7248,12 @@ msgstr "无法ä¿å­˜é¡¹ç›®ID"
msgid "Could not save prometheus manual configuration"
msgstr "无法ä¿å­˜prometheus手动é…ç½®"
-msgid "Could not udpdate wiki page"
-msgstr ""
-
msgid "Could not update the LDAP settings"
msgstr "无法更新LDAP设置"
+msgid "Could not update wiki page"
+msgstr ""
+
msgid "Could not upload your designs as one or more files uploaded are not supported."
msgstr "无法上传您的设计,因为ä¸æ”¯æŒå·²ä¸Šä¼ ä¸€ä¸ªæˆ–多个的文件。"
@@ -7086,10 +7343,10 @@ msgid "Create commit"
msgstr "创建æ交"
msgid "Create confidential merge request"
-msgstr "创建机密åˆå¹¶è¯·æ±‚"
+msgstr "创建ç§å¯†åˆå¹¶è¯·æ±‚"
msgid "Create confidential merge request and branch"
-msgstr "创建机密åˆå¹¶è¯·æ±‚åŠåˆ†æ”¯"
+msgstr "创建ç§å¯†åˆå¹¶è¯·æ±‚åŠåˆ†æ”¯"
msgid "Create directory"
msgstr "创建目录"
@@ -7650,6 +7907,9 @@ msgstr "无法添加%{invalidProjects}。此仪表æ¿å¯ç”¨äºŽå…¬å¼€é¡¹ç›®ï¼Œä»¥
msgid "DastProfiles|Are you sure you want to delete this profile?"
msgstr ""
+msgid "DastProfiles|Could not create site validation token. Please refresh the page, or try again later."
+msgstr ""
+
msgid "DastProfiles|Could not create the scanner profile. Please try again."
msgstr ""
@@ -7674,6 +7934,12 @@ msgstr ""
msgid "DastProfiles|Could not fetch site profiles. Please refresh the page, or try again later."
msgstr ""
+msgid "DastProfiles|Could not retrieve site validation status. Please refresh the page, or try again later."
+msgstr ""
+
+msgid "DastProfiles|Could not update the scanner profile. Please try again."
+msgstr ""
+
msgid "DastProfiles|Could not update the site profile. Please try again."
msgstr "无法更新站点é…置。请é‡è¯•ã€‚"
@@ -7689,8 +7955,8 @@ msgstr "您è¦æ”¾å¼ƒæ›´æ”¹å—?"
msgid "DastProfiles|Download validation text file"
msgstr ""
-msgid "DastProfiles|Edit feature will come soon. Please create a new profile if changes needed"
-msgstr "编辑功能å³å°†åˆ°æ¥ã€‚如果需è¦æ›´æ”¹è¯·åˆ›å»ºä¸€ä¸ªæ–°çš„é…ç½®"
+msgid "DastProfiles|Edit scanner profile"
+msgstr ""
msgid "DastProfiles|Edit site profile"
msgstr "编辑站点é…ç½®"
@@ -7722,6 +7988,9 @@ msgstr "新建站点é…ç½®"
msgid "DastProfiles|No profiles created yet"
msgstr "尚未创建é…ç½®"
+msgid "DastProfiles|Passive"
+msgstr ""
+
msgid "DastProfiles|Please enter a valid URL format, ex: http://www.example.com/home"
msgstr "请输入一个有效的URLæ ¼å¼ï¼Œä¾‹å¦‚:http://www.example.com/home"
@@ -7737,6 +8006,9 @@ msgstr "将目标站点和扫æ设置的常用设定ä¿å­˜ä¸ºé…置。使用这
msgid "DastProfiles|Save profile"
msgstr "ä¿å­˜é…ç½®"
+msgid "DastProfiles|Scan mode"
+msgstr ""
+
msgid "DastProfiles|Scanner Profile"
msgstr ""
@@ -7776,10 +8048,10 @@ msgstr ""
msgid "DastProfiles|Text file validation"
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
+msgid "DastProfiles|The maximum number of minutes allowed for the spider to traverse the site."
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the spider to traverse the site."
+msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
msgstr ""
msgid "DastProfiles|Validate"
@@ -7812,6 +8084,9 @@ msgstr "日期"
msgid "Date picker"
msgstr "日期选择器"
+msgid "Date range"
+msgstr ""
+
msgid "Date range cannot exceed %{maxDateRange} days."
msgstr "日期范围ä¸èƒ½è¶…过%{maxDateRange}天。"
@@ -7836,6 +8111,9 @@ msgstr "天"
msgid "Days to merge"
msgstr "åˆå¹¶æ‰€éœ€å¤©æ•°"
+msgid "Dear Administrator,"
+msgstr ""
+
msgid "Debug"
msgstr "调试"
@@ -7947,12 +8225,18 @@ msgstr "已延时"
msgid "Delete"
msgstr "删除"
+msgid "Delete %{name}"
+msgstr ""
+
msgid "Delete Comment"
msgstr "删除评论"
msgid "Delete Snippet"
msgstr "删除代ç ç‰‡æ®µ"
+msgid "Delete Value Stream"
+msgstr ""
+
msgid "Delete account"
msgstr ""
@@ -7974,9 +8258,6 @@ msgstr "删除标签"
msgid "Delete label: %{label_name} ?"
msgstr "删除标记: %{label_name}?"
-msgid "Delete license"
-msgstr "删除许å¯è¯"
-
msgid "Delete list"
msgstr "删除列表"
@@ -8052,15 +8333,6 @@ msgstr "删除中"
msgid "Deleting a project places it into a read-only state until %{date}, at which point the project will be permanently deleted. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "Deleting the license failed."
-msgstr "删除许å¯è¯å¤±è´¥ã€‚"
-
-msgid "Deleting the license failed. The license was not found."
-msgstr "删除许å¯è¯å¤±è´¥ã€‚找ä¸åˆ°è®¸å¯è¯ã€‚"
-
-msgid "Deleting the license failed. You are not permitted to perform this action."
-msgstr "删除许å¯è¯å¤±è´¥ã€‚ä¸å…许您执行此æ“作。"
-
msgid "Deleting the project will delete its repository and all related resources including issues, merge requests etc."
msgstr ""
@@ -8550,8 +8822,11 @@ msgstr "选择全部"
msgid "DesignManagement|The maximum number of designs allowed to be uploaded is %{upload_limit}. Please try again."
msgstr "å…许上传的设计最大数é‡ä¸º %{upload_limit}。请å†è¯•ä¸€æ¬¡ã€‚"
-msgid "DesignManagement|To upload designs, you'll need to enable LFS. %{requirements_link_start}More information%{requirements_link_end}"
-msgstr "è¦ä¸Šä¼ è®¾è®¡ï¼Œæ‚¨éœ€è¦å¯ç”¨LFS。%{requirements_link_start}更多信æ¯%{requirements_link_end}"
+msgid "DesignManagement|There was an error moving your designs. Please upload your designs below."
+msgstr ""
+
+msgid "DesignManagement|To upload designs, you'll need to enable LFS and have admin enable hashed storage. %{requirements_link_start}More information%{requirements_link_end}"
+msgstr ""
msgid "DesignManagement|Unresolve thread"
msgstr "将主题置为未解决"
@@ -8562,6 +8837,9 @@ msgstr "上传设计"
msgid "DesignManagement|Upload skipped."
msgstr "上传已跳过。"
+msgid "DesignManagement|Your designs are being copied and are on their way… Please refresh to update."
+msgstr ""
+
msgid "DesignManagement|and %{moreCount} more."
msgstr "以åŠå…¶ä½™%{moreCount}项。"
@@ -8619,6 +8897,9 @@ msgstr ""
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr "获å–差异线时å‘生错误。"
+msgid "Direct member"
+msgstr ""
+
msgid "Direction"
msgstr "æ–¹å‘"
@@ -8667,9 +8948,6 @@ msgstr "放弃对 %{path} 的更改å—?"
msgid "Discard draft"
msgstr "å–消"
-msgid "Discard review"
-msgstr "放弃评审"
-
msgid "DiscordService|Discord Notifications"
msgstr "Discord 通知"
@@ -8737,12 +9015,12 @@ msgstr ""
msgid "Dismiss Merge Request promotion"
msgstr "关闭åˆå¹¶è¯·æ±‚推广"
-msgid "Dismiss Selected"
-msgstr "å–消选择"
-
msgid "Dismiss Value Stream Analytics introduction box"
msgstr "ä¸å†æ˜¾ç¤ºä»·å€¼æµåˆ†æžä»‹ç»æ¡†"
+msgid "Dismiss selected"
+msgstr ""
+
msgid "Dismiss trial promotion"
msgstr "关闭试用推è"
@@ -8791,9 +9069,6 @@ msgstr "常è§çš„身份验è¯æ供商的相关文档"
msgid "Documents reindexed: %{processed_documents} (%{percentage}%%)"
msgstr "文档é‡å»ºç´¢å¼•: %{processed_documents} (%{percentage}%%)"
-msgid "Doing"
-msgstr "进行中"
-
msgid "Domain"
msgstr "域å"
@@ -8989,9 +9264,6 @@ msgstr "编辑æè¿°ä¿¡æ¯"
msgid "Edit environment"
msgstr "编辑环境"
-msgid "Edit file"
-msgstr "编辑文件"
-
msgid "Edit files in the editor and commit changes here"
msgstr "在编辑器中编辑文件并在这里​​æ交å˜æ›´å†…容"
@@ -9004,6 +9276,12 @@ msgstr "编辑群组:%{group_name}"
msgid "Edit identity for %{user_name}"
msgstr "编辑 %{user_name} 的身份信æ¯"
+msgid "Edit in Web IDE"
+msgstr ""
+
+msgid "Edit in single-file editor"
+msgstr ""
+
msgid "Edit issues"
msgstr "编辑议题"
@@ -9031,21 +9309,18 @@ msgstr "编辑于%{timeago}"
msgid "Editing"
msgstr "编辑中"
-msgid "Elasticsearch"
-msgstr "Elasticsearch"
-
msgid "Elasticsearch AWS IAM credentials"
msgstr "Elasticsearch AWS IAM凭æ®"
+msgid "Elasticsearch HTTP client timeout value in seconds."
+msgstr ""
+
msgid "Elasticsearch indexing restrictions"
msgstr "Elasticsearch索引é™åˆ¶"
msgid "Elasticsearch indexing started"
msgstr "Elasticsearch索引已å¯åŠ¨"
-msgid "Elasticsearch integration. Elasticsearch AWS IAM."
-msgstr "Elasticsearch集æˆåŠElasticsearch AWS IAM。"
-
msgid "Elasticsearch reindexing is already in progress"
msgstr "Elasticsearché‡å»ºç´¢å¼•æ­£åœ¨è¿›è¡Œä¸­"
@@ -9073,9 +9348,6 @@ msgstr "电å­é‚®ä»¶%{number}"
msgid "Email Notification"
msgstr "电å­é‚®ä»¶é€šçŸ¥"
-msgid "Email address"
-msgstr "电å­é‚®ä»¶åœ°å€"
-
msgid "Email could not be sent"
msgstr "邮件无法å‘é€"
@@ -9139,6 +9411,9 @@ msgstr "电å­é‚®ä»¶"
msgid "Emails sent from Service Desk will have this name"
msgstr "从æœåŠ¡å°å‘é€çš„电å­é‚®ä»¶å°†å…·æœ‰æ­¤å称"
+msgid "Emails sent to %{email} will still be supported"
+msgstr ""
+
msgid "Emails separated by comma"
msgstr "以逗å·åˆ†éš”的电å­é‚®ä»¶åœ°å€"
@@ -9172,9 +9447,18 @@ msgstr "空文件"
msgid "Enable"
msgstr "å¯ç”¨"
+msgid "Enable %{link_start}Gitpod%{link_end} integration to launch a development environment in your browser directly from GitLab."
+msgstr ""
+
msgid "Enable Auto DevOps"
msgstr "å¯ç”¨Auto DevOps"
+msgid "Enable Gitpod"
+msgstr ""
+
+msgid "Enable Gitpod?"
+msgstr ""
+
msgid "Enable HTML emails"
msgstr "å¯ç”¨ HTML 电å­é‚®ä»¶"
@@ -9304,9 +9588,6 @@ msgstr "此功能仅在 GitLab EE 许å¯ä¸‹å¯ç”¨ã€‚如果è¦å¯ç”¨ï¼Œè¯·ç¡®è®¤å
msgid "Encountered an error while rendering: %{err}"
msgstr "渲染时出现错误: %{err}"
-msgid "End date"
-msgstr "结æŸæ—¥æœŸ"
-
msgid "Ends at (UTC)"
msgstr "结æŸäºŽ(UTC)"
@@ -9466,7 +9747,7 @@ msgstr "删除"
msgid "EnvironmentsDashboard|The environments dashboard provides a summary of each project's environments' status, including pipeline and alert statuses."
msgstr "环境仪表æ¿æä¾›æ¯ä¸ªé¡¹ç›®çŽ¯å¢ƒçŠ¶æ€çš„摘è¦ï¼ŒåŒ…括æµæ°´çº¿å’Œè­¦æŠ¥çŠ¶æ€ã€‚"
-msgid "EnvironmentsDashboard|This dashboard displays a maximum of 7 projects and 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
+msgid "EnvironmentsDashboard|This dashboard displays 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
msgstr ""
msgid "Environments|An error occurred while canceling the auto stop, please try again"
@@ -9737,7 +10018,7 @@ msgid "Epics|These dates affect how your epics appear in the roadmap. Dates from
msgstr "这些日期会影å“å²è¯—在路线图中的显示方å¼ã€‚里程碑日期æ¥è‡ªäºŽå²è¯—故事中的议题所属的里程碑。您还å¯ä»¥è®¾ç½®å›ºå®šæ—¥æœŸæˆ–完全删除它们。"
msgid "Epics|This epic and any containing child epics are confidential and should only be visible to team members with at least Reporter access."
-msgstr "这个å²è¯—和任何包å«å­å²è¯—çš„ä¿¡æ¯å‡ä¸ºæœºå¯†ï¼Œåªèƒ½å¯¹æ‹¥æœ‰è‡³å°‘报告者访问æƒé™çš„团队æˆå‘˜å¯è§ã€‚"
+msgstr "这个å²è¯—和任何包å«å­å²è¯—çš„ä¿¡æ¯å‡ä¸ºç§å¯†ï¼Œåªèƒ½å¯¹æ‹¥æœ‰è‡³å°‘报告者访问æƒé™çš„团队æˆå‘˜å¯è§ã€‚"
msgid "Epics|This will also remove any descendents of %{bStart}%{targetEpicTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}. Are you sure?"
msgstr "该æ“作也会从%{bStart}%{parentEpicTitle}%{bEnd}中移除%{bStart}%{targetEpicTitle}%{bEnd}的所有级别å­å²è¯—。确定继续å—?"
@@ -9787,6 +10068,9 @@ msgstr "删除%{issuableType}时出错"
msgid "Error deleting project. Check logs for error details."
msgstr "删除项目时出错。请检查错误详细信æ¯ã€‚"
+msgid "Error fetching burnup chart data"
+msgstr ""
+
msgid "Error fetching diverging counts for branches. Please try again."
msgstr "获å–分支分å‰æ•°ç›®æ—¶å‡ºé”™ã€‚请é‡è¯•ã€‚"
@@ -9865,6 +10149,9 @@ msgstr "获å–侧边æ æ•°æ®æ—¶å‡ºé”™"
msgid "Error occurred when saving assignees"
msgstr "ä¿å­˜è¢«æŒ‡æ´¾äººæ—¶å‡ºçŽ°é”™è¯¯ã€‚"
+msgid "Error occurred when saving reviewers"
+msgstr ""
+
msgid "Error occurred when toggling the notification subscription"
msgstr "切æ¢é€šçŸ¥è®¢é˜…æ—¶å‘生错误"
@@ -10117,12 +10404,15 @@ msgstr "展开"
msgid "Expand all"
msgstr "展开全部"
+msgid "Expand all files"
+msgstr ""
+
+msgid "Expand all threads"
+msgstr ""
+
msgid "Expand approvers"
msgstr "展开核准人"
-msgid "Expand dropdown"
-msgstr "展开下拉列表"
-
msgid "Expand milestones"
msgstr "展开里程碑"
@@ -10184,7 +10474,7 @@ msgid "Explore projects"
msgstr "æµè§ˆé¡¹ç›®"
msgid "Explore public groups"
-msgstr "æœç´¢å…¬å¼€ç¾¤ç»„"
+msgstr "æµè§ˆå…¬å¼€ç¾¤ç»„"
msgid "Export"
msgstr "导出"
@@ -10291,6 +10581,9 @@ msgstr "无法检查相关分支。"
msgid "Failed to create Merge Request. Please try again."
msgstr "创建åˆå¹¶è¯·æ±‚失败。请é‡è¯•ã€‚"
+msgid "Failed to create To-Do for the design."
+msgstr ""
+
msgid "Failed to create a branch for this issue. Please try again."
msgstr "无法为此问题创建分支。请å†è¯•ä¸€æ¬¡ã€‚"
@@ -10330,6 +10623,12 @@ msgstr "加载指派人失败。请é‡è¯•ã€‚"
msgid "Failed to load authors. Please try again."
msgstr "加载作者失败。请é‡è¯•ã€‚"
+msgid "Failed to load branches. Please try again."
+msgstr ""
+
+msgid "Failed to load deploy keys."
+msgstr ""
+
msgid "Failed to load emoji list."
msgstr "无法加载表情列表。"
@@ -10345,6 +10644,9 @@ msgstr "加载群组活动度é‡æŒ‡æ ‡å¤±è´¥ã€‚请é‡è¯•ã€‚"
msgid "Failed to load groups & users."
msgstr "加载群组和用户失败。"
+msgid "Failed to load groups, users and deploy keys."
+msgstr ""
+
msgid "Failed to load labels. Please try again."
msgstr "加载标记失败。请é‡è¯•ã€‚"
@@ -10354,6 +10656,12 @@ msgstr "加载里程碑失败。请é‡è¯•ã€‚"
msgid "Failed to load related branches"
msgstr "加载相关分支失败"
+msgid "Failed to load sidebar confidential toggle"
+msgstr ""
+
+msgid "Failed to load sidebar lock status"
+msgstr ""
+
msgid "Failed to load stacktrace."
msgstr "加载堆栈跟踪失败。"
@@ -10381,6 +10689,9 @@ msgstr "ä¿æŠ¤çŽ¯å¢ƒå¤±è´¥"
msgid "Failed to publish issue on status page."
msgstr "在状æ€é¡µä¸Šå‘布议题失败。"
+msgid "Failed to remove To-Do for the design."
+msgstr ""
+
msgid "Failed to remove a Zoom meeting"
msgstr "无法删除Zoom会议"
@@ -10423,6 +10734,9 @@ msgstr "无法对此议题设置迭代。请å†è¯•ä¸€é。"
msgid "Failed to signing using smartcard authentication"
msgstr "无法使用智能å¡èº«ä»½éªŒè¯è¿›è¡Œç™»å½•"
+msgid "Failed to toggle To-Do for the design."
+msgstr ""
+
msgid "Failed to update branch!"
msgstr "更新分支失败ï¼"
@@ -10535,8 +10849,8 @@ msgstr "编辑功能标志"
msgid "FeatureFlags|Edit User List"
msgstr "编辑用户列表"
-msgid "FeatureFlags|Enable features for specific users and specific environments by defining feature flag strategies."
-msgstr "通过定义功能标志策略,为特定用户和特定环境å¯ç”¨åŠŸèƒ½ã€‚"
+msgid "FeatureFlags|Enable features for specific users and environments by configuring feature flag strategies."
+msgstr ""
msgid "FeatureFlags|Environment Spec"
msgstr "环境规格"
@@ -10595,8 +10909,8 @@ msgstr "%{scope} çš„éžæ´»åŠ¨æ ‡å¿—"
msgid "FeatureFlags|Include additional user IDs"
msgstr "包括其他用户ID"
-msgid "FeatureFlags|Install a %{docs_link_anchored_start}compatible client library%{docs_link_anchored_end} and specify the API URL, application name, and instance ID during the configuration setup. %{docs_link_start}More Information%{docs_link_end}"
-msgstr "安装%{docs_link_anchored_start}兼容的客户端库%{docs_link_anchored_end} ,并在é…置中指定API URLã€åº”用程åºå称和实例ID。%{docs_link_start}更多信æ¯%{docs_link_end}"
+msgid "FeatureFlags|Install a %{docsLinkAnchoredStart}compatible client library%{docsLinkAnchoredEnd} and specify the API URL, application name, and instance ID during the configuration setup. %{docsLinkStart}More Information%{docsLinkEnd}"
+msgstr ""
msgid "FeatureFlags|Instance ID"
msgstr "实例ID"
@@ -10607,6 +10921,9 @@ msgstr "列表详细信æ¯"
msgid "FeatureFlags|Loading feature flags"
msgstr "加载功能标志"
+msgid "FeatureFlags|Loading user lists"
+msgstr ""
+
msgid "FeatureFlags|More information"
msgstr "更多信æ¯"
@@ -10625,8 +10942,8 @@ msgstr "新建用户列表"
msgid "FeatureFlags|New feature flag"
msgstr "新建功能标志"
-msgid "FeatureFlags|New list"
-msgstr "新建列表"
+msgid "FeatureFlags|New user list"
+msgstr ""
msgid "FeatureFlags|Percent of users"
msgstr "用户百分比"
@@ -10664,6 +10981,9 @@ msgstr "目标环境"
msgid "FeatureFlags|There was an error fetching the feature flags."
msgstr "获å–功能标志时出错。"
+msgid "FeatureFlags|There was an error fetching the user lists."
+msgstr ""
+
msgid "FeatureFlags|There was an error retrieving user lists"
msgstr "获å–用户列表时出错"
@@ -10679,6 +10999,9 @@ msgstr "用户ID"
msgid "FeatureFlags|User List"
msgstr "用户列表"
+msgid "FeatureFlags|User Lists"
+msgstr ""
+
msgid "FeatureFlag|List"
msgstr "列表"
@@ -10706,15 +11029,6 @@ msgstr "2月"
msgid "Fetching incoming email"
msgstr "获å–接收邮件地å€"
-msgid "Fetching licenses failed."
-msgstr "获å–许å¯è¯å¤±è´¥ã€‚"
-
-msgid "Fetching licenses failed. The request endpoint was not found."
-msgstr "获å–许å¯è¯å¤±è´¥ã€‚找ä¸åˆ°è¯·æ±‚端点。"
-
-msgid "Fetching licenses failed. You are not permitted to perform this action."
-msgstr "获å–许å¯è¯å¤±è´¥ã€‚当å‰æƒé™æ— æ³•æ‰§è¡Œæ­¤æ“作。"
-
msgid "File"
msgstr "文件"
@@ -10817,12 +11131,21 @@ msgstr "按当å‰å¼€æ”¾çš„需求过滤。"
msgid "Filter by status"
msgstr "按状æ€è¿‡æ»¤"
+msgid "Filter by test cases that are currently archived."
+msgstr ""
+
+msgid "Filter by test cases that are currently opened."
+msgstr ""
+
msgid "Filter by two-factor authentication"
msgstr "按åŒé‡è®¤è¯è¿‡æ»¤"
msgid "Filter by user"
msgstr "按用户筛选"
+msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
+msgstr ""
+
msgid "Filter pipelines"
msgstr "过滤æµæ°´çº¿"
@@ -10838,8 +11161,8 @@ msgstr "按项目过滤结果"
msgid "Filter results..."
msgstr "过滤结果..."
-msgid "Filter your projects by name"
-msgstr "按å称过滤您的项目"
+msgid "Filter your repositories by name"
+msgstr ""
msgid "Filter..."
msgstr "过滤..."
@@ -10847,8 +11170,8 @@ msgstr "过滤..."
msgid "Find File"
msgstr "查找文件"
-msgid "Find bugs in your code with coverage-guided fuzzing"
-msgstr "通过覆盖率导å‘的模糊测试æ¥æŸ¥æ‰¾ä»£ç ä¸­çš„缺陷"
+msgid "Find bugs in your code with coverage-guided fuzzing."
+msgstr ""
msgid "Find by path"
msgstr "按路径查找"
@@ -10874,9 +11197,6 @@ msgstr "指纹"
msgid "Finish editing this message first!"
msgstr "先完æˆæ­¤æ¶ˆæ¯çš„编辑ï¼"
-msgid "Finish review"
-msgstr "完æˆè¯„审"
-
msgid "Finish setting up your dedicated account for %{group_name}."
msgstr "完æˆæ‚¨çš„%{group_name}专用å¸æˆ·è®¾ç½®ã€‚"
@@ -10946,6 +11266,9 @@ msgstr "字体颜色"
msgid "Footer message"
msgstr "页脚消æ¯"
+msgid "For a faster browsing experience, some files are collapsed by default."
+msgstr ""
+
msgid "For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
@@ -10955,6 +11278,9 @@ msgstr "对于内部项目,任何已登录的用户都å¯ä»¥æŸ¥çœ‹æµæ°´çº¿å¹¶
msgid "For more info, read the documentation."
msgstr "有关详细信æ¯ï¼Œè¯·é˜…读文档。"
+msgid "For more information on how the number of active users is calculated, see the %{self_managed_subscriptions_doc_link} documentation."
+msgstr ""
+
msgid "For more information, go to the "
msgstr "如需了解详细信æ¯ï¼Œè¯·å‚阅"
@@ -11093,6 +11419,9 @@ msgstr "生æˆæ–°çš„导出"
msgid "Generate new token"
msgstr "生æˆæ–°çš„令牌"
+msgid "Generic package file size in bytes"
+msgstr ""
+
msgid "Geo"
msgstr "Geo"
@@ -11354,6 +11683,9 @@ msgstr "待验è¯"
msgid "Geo|Please refer to Geo Troubleshooting."
msgstr "请å‚阅 Geo 疑难解答。"
+msgid "Geo|Primary node"
+msgstr ""
+
msgid "Geo|Project"
msgstr "项目"
@@ -11396,6 +11728,9 @@ msgstr "é‡æ–°æ ¡éªŒæ‰€æœ‰"
msgid "Geo|Review replication status, and resynchronize and reverify items with the primary node."
msgstr "查看å¤åˆ¶çŠ¶æ€å¹¶ä¸Žä¸»è¦èŠ‚点é‡æ–°åŒæ­¥å’Œé‡æ–°éªŒè¯é¡¹ç›®ã€‚"
+msgid "Geo|Secondary node"
+msgstr ""
+
msgid "Geo|Status"
msgstr "状æ€"
@@ -11435,6 +11770,9 @@ msgstr "URLä¸èƒ½ä¸ºç©º"
msgid "Geo|URL must be a valid url (ex: https://gitlab.com)"
msgstr "URL必须是有效的url(例如:https://gitlab.com)"
+msgid "Geo|Undefined"
+msgstr ""
+
msgid "Geo|Unknown state"
msgstr "未知状æ€"
@@ -11510,11 +11848,17 @@ msgstr "GitHub API速率超过é™åˆ¶ã€‚请在%{reset_time}åŽé‡è¯•"
msgid "GitHub import"
msgstr "GitHub导入"
+msgid "GitLab"
+msgstr ""
+
msgid "GitLab / Unsubscribe"
msgstr "å–消订阅"
-msgid "GitLab Enterprise Edition %{plan}"
-msgstr "GitLab ä¼ä¸šç‰ˆ %{plan}"
+msgid "GitLab API"
+msgstr ""
+
+msgid "GitLab Billing Team."
+msgstr ""
msgid "GitLab Group Runners can execute code for all the projects in this group."
msgstr "Gitlab群组Runnerå¯ä»¥ç”¨æ¥è¿è¡Œç¾¤ç»„内所有项目的代ç ã€‚"
@@ -11525,12 +11869,18 @@ msgstr "GitLab导入"
msgid "GitLab Issue"
msgstr "GitLab议题"
+msgid "GitLab Pages"
+msgstr ""
+
msgid "GitLab Service Desk is a simple way to allow people to create issues in your GitLab instance without needing their own user account. It provides a unique email address for end users to create issues in a project, and replies can be sent either through the GitLab interface or by email. End users will only see the thread through email."
msgstr "GitLabæœåŠ¡å°èƒ½å¤Ÿä»¥ç®€å•çš„æ–¹å¼è®©ç”¨æˆ·åœ¨æ‚¨çš„GitLab实例中创建议题,而无需创建账å·ã€‚它为最终用户æ供了在项目中创建问题的唯一电å­é‚®ä»¶åœ°å€ï¼Œå¹¶ä¸”å¯ä»¥é€šè¿‡GitLabç•Œé¢æˆ–通过电å­é‚®ä»¶è¿›è¡Œç­”å¤ã€‚最终用户将仅通过电å­é‚®ä»¶çœ‹åˆ°è¯¥ä¸»é¢˜ã€‚"
msgid "GitLab Shared Runners execute code of different projects on the same Runner unless you configure GitLab Runner Autoscale with MaxBuilds 1 (which it is on GitLab.com)."
msgstr "GitLab 共享è¿è¡Œå™¨å°†åœ¨åŒä¸€ä¸ªè¿è¡Œå™¨ä¸Šæ‰§è¡Œä¸åŒé¡¹ç›®çš„代ç ï¼Œé™¤éžæ‚¨åœ¨GitLab上设置 MaxBuilds为1å’Œ GitLab è¿è¡Œå™¨è‡ªåŠ¨ç¼©æ”¾ã€‚"
+msgid "GitLab Shell"
+msgstr ""
+
msgid "GitLab Support Bot"
msgstr "GitLab支æŒæœºå™¨äºº"
@@ -11540,8 +11890,8 @@ msgstr "GitLab团队æˆå‘˜"
msgid "GitLab User"
msgstr "GitLab用户"
-msgid "GitLab allows you to continue using your license even if you exceed the number of seats you purchased. You will be required to pay for these seats when you renew your license."
-msgstr "å³ä½¿ç³»ç»Ÿä¸­çš„用户数已ç»è¶…过了许å¯ä¸­çš„数目,GitLabä¾ç„¶å…许继续使用当å‰è®¸å¯ã€‚续订许å¯æ—¶ï¼Œæ‚¨éœ€è¦æ”¯ä»˜è¿™äº›ç”¨æˆ·çš„费用。"
+msgid "GitLab Workhorse"
+msgstr ""
msgid "GitLab commit"
msgstr "GitLabæ交"
@@ -11708,6 +12058,21 @@ msgstr "从Gitea导入"
msgid "Gitlab Pages"
msgstr "GitLab Pages"
+msgid "Gitpod"
+msgstr ""
+
+msgid "Gitpod|Add the URL to your Gitpod instance configured to read your GitLab projects."
+msgstr ""
+
+msgid "Gitpod|Enable Gitpod integration"
+msgstr ""
+
+msgid "Gitpod|Gitpod URL"
+msgstr ""
+
+msgid "Gitpod|e.g. https://gitpod.example.com"
+msgstr ""
+
msgid "Given access %{time_ago}"
msgstr "%{time_ago}授æƒè®¿é—®"
@@ -12215,9 +12580,6 @@ msgstr "åˆ‡æ¢ SAML 身份验è¯"
msgid "GroupSAML|Valid SAML Response"
msgstr "有效的SAMLå“应"
-msgid "GroupSAML|With group managed accounts enabled, all the users without a group managed account will be excluded from the group."
-msgstr "å¯ç”¨ç”±ç¾¤ç»„托管å¸æˆ·åŽï¼Œæ‰€æœ‰æ²¡æœ‰ç¾¤ç»„托管å¸æˆ·çš„用户将被从群组中排除在外。"
-
msgid "GroupSAML|With prohibit outer forks flag enabled group members will be able to fork project only inside your group."
msgstr "在ç¦æ­¢å¤–部派生标志å¯ç”¨åŽï¼Œç¾¤ç»„æˆå‘˜å°†åªèƒ½åœ¨æ‚¨çš„群组内派生项目。"
@@ -12431,12 +12793,12 @@ msgstr "创建"
msgid "GroupsNew|Create group"
msgstr "创建群组"
-msgid "GroupsNew|GitLab group export"
-msgstr "GitLab群组导出"
-
msgid "GroupsNew|Import"
msgstr "导入"
+msgid "GroupsNew|Import a GitLab group export file"
+msgstr ""
+
msgid "GroupsNew|Import group"
msgstr "导入群组"
@@ -12576,6 +12938,9 @@ msgid "Hide chart"
msgid_plural "Hide charts"
msgstr[0] "éšè—图表"
+msgid "Hide comments on this file"
+msgstr ""
+
msgid "Hide details"
msgstr "éšè—详情"
@@ -12619,6 +12984,15 @@ msgstr "æ¯ä¸ªåŽŸå§‹è·¯å¾„æ¯åˆ†é’Ÿçš„最大请求数,默认为300. 如è¦ç¦ç
msgid "Highest role:"
msgstr "顶级角色:"
+msgid "HighlightBar|Alert events:"
+msgstr ""
+
+msgid "HighlightBar|Alert start time:"
+msgstr ""
+
+msgid "HighlightBar|Original alert:"
+msgstr ""
+
msgid "History"
msgstr "历å²"
@@ -12796,6 +13170,9 @@ msgstr "如果å¯ç”¨ï¼ŒGitLab将使用Geo处ç†å¯¹è±¡å­˜å‚¨å¤åˆ¶ã€‚ %{linkStart
msgid "If enabled, access to projects will be validated on an external service using their classification label."
msgstr "如果å¯ç”¨ï¼Œåˆ™ä½¿ç”¨å¤–部æœåŠ¡ä¸Šçš„分类标签æ¥éªŒè¯å¯¹é¡¹ç›®çš„访问æƒé™ã€‚"
+msgid "If the number of active users exceeds the user limit, you will be charged for the number of %{users_over_license_link} at your next license reconciliation."
+msgstr ""
+
msgid "If there is no previous license or if the previous license has expired, some GitLab functionality will be blocked until a new, valid license is uploaded."
msgstr "如果之å‰æœªä¸Šä¼ è®¸å¯è¯ï¼Œæˆ–者上一个许å¯è¯å·²è¿‡æœŸï¼Œ 部分GitLab功能将无法使用,直到上传新的有效许å¯è¯ã€‚"
@@ -12835,9 +13212,6 @@ msgstr ""
msgid "If your HTTP repository is not publicly accessible, add your credentials."
msgstr "如果您的HTTP仓库无法公开访问,需在地å€ä¸­æ·»åŠ å‡­æ®ã€‚"
-msgid "Iglu registry URL (optional)"
-msgstr "Iglu注册表网å€(å¯é€‰)"
-
msgid "Ignore"
msgstr "忽略"
@@ -12874,6 +13248,14 @@ msgstr "身份模拟已被ç¦ç”¨"
msgid "Import"
msgstr "导入"
+msgid "Import %d compatible repository"
+msgid_plural "Import %d compatible repositories"
+msgstr[0] ""
+
+msgid "Import %d repository"
+msgid_plural "Import %d repositories"
+msgstr[0] ""
+
msgid "Import CSV"
msgstr "导入CSV"
@@ -12883,15 +13265,9 @@ msgstr "从Gitea导入项目"
msgid "Import all compatible projects"
msgstr "导入所有兼容的项目"
-msgid "Import all compatible repositories"
-msgstr "导入所有兼容的仓库"
-
msgid "Import all projects"
msgstr "导入所有项目"
-msgid "Import all repositories"
-msgstr "导入所有仓库"
-
msgid "Import an exported GitLab project"
msgstr "导入一个从GitLab导出的项目"
@@ -12979,6 +13355,9 @@ msgstr "ç¦æ­¢çš„导入URL: %{message}"
msgid "ImportProjects|Error importing repository %{project_safe_import_url} into %{project_full_path} - %{message}"
msgstr "将仓库 %{project_safe_import_url} 导入到 %{project_full_path} 时出错:%{message}"
+msgid "ImportProjects|Import repositories"
+msgstr ""
+
msgid "ImportProjects|Importing the project failed"
msgstr "导入项目失败"
@@ -12991,8 +13370,8 @@ msgstr ""
msgid "ImportProjects|Requesting your %{provider} repositories failed"
msgstr "获å–您的%{provider}仓库失败"
-msgid "ImportProjects|Select the projects you want to import"
-msgstr "选择è¦å¯¼å…¥çš„项目"
+msgid "ImportProjects|Select the repositories you want to import"
+msgstr ""
msgid "ImportProjects|The remote data could not be imported."
msgstr "无法导入远程数æ®ã€‚"
@@ -13027,9 +13406,6 @@ msgstr "%{time_to_now}åŽ"
msgid "In order to enable Service Desk for your instance, you must first set up incoming email."
msgstr ""
-msgid "In order to gather accurate feature usage data, it can take 1 to 2 weeks to see your index."
-msgstr "为了收集准确的功能使用数æ®ï¼Œå¯èƒ½éœ€è¦1到2周æ‰èƒ½çœ‹åˆ°æ‚¨çš„指数。"
-
msgid "In order to personalize your experience with GitLab%{br_tag}we would like to know a bit more about you."
msgstr "为了能é‡èº«å®šåˆ¶æ‚¨åœ¨GitLab的体验,%{br_tag}我们希望对您有更多了解。"
@@ -13060,18 +13436,30 @@ msgstr "已关闭"
msgid "IncidentManagement|Create incident"
msgstr "创建事件"
+msgid "IncidentManagement|Critical - S1"
+msgstr ""
+
msgid "IncidentManagement|Date created"
msgstr "创建日期"
msgid "IncidentManagement|Display your incidents in a dedicated view"
msgstr ""
+msgid "IncidentManagement|High - S2"
+msgstr ""
+
msgid "IncidentManagement|Incident"
msgstr "事件"
msgid "IncidentManagement|Incidents"
msgstr "事件"
+msgid "IncidentManagement|Low - S4"
+msgstr ""
+
+msgid "IncidentManagement|Medium - S3"
+msgstr ""
+
msgid "IncidentManagement|No incidents to display."
msgstr "没有è¦æ˜¾ç¤ºçš„事件。"
@@ -13084,6 +13472,9 @@ msgstr "å·²å‘布"
msgid "IncidentManagement|Published to status page"
msgstr "å‘布到状æ€é¡µ"
+msgid "IncidentManagement|Severity"
+msgstr ""
+
msgid "IncidentManagement|There are no closed incidents"
msgstr ""
@@ -13093,6 +13484,9 @@ msgstr "显示事件时出错。"
msgid "IncidentManagement|Unassigned"
msgstr "å–消指派"
+msgid "IncidentManagement|Unknown"
+msgstr ""
+
msgid "IncidentManagement|Unpublished"
msgstr "未å‘布"
@@ -13114,6 +13508,15 @@ msgstr "设置外部工具集æˆä»¥æ›´å¥½åœ°ç®¡ç†äº‹ä»¶ã€‚"
msgid "Incidents"
msgstr "事故"
+msgid "Incident|Alert details"
+msgstr ""
+
+msgid "Incident|Summary"
+msgstr ""
+
+msgid "Incident|There was an issue loading alert data. Please try again."
+msgstr ""
+
msgid "Include a Terms of Service agreement and Privacy Policy that all users must accept."
msgstr "包括所有用户必须接å—çš„æœåŠ¡æ¡æ¬¾å议和éšç§æ”¿ç­–。"
@@ -13174,6 +13577,9 @@ msgstr "通知用户没有上传SSH密钥,如果没有SSH秘钥,将无法通
msgid "Information about additional Pages templates and how to install them can be found in our %{pages_getting_started_guide}."
msgstr "其他Pages模æ¿çš„ä¿¡æ¯åŠå®‰è£…指å—å¯ä»¥åœ¨%{pages_getting_started_guide}中找到."
+msgid "Inherited"
+msgstr ""
+
msgid "Inherited:"
msgstr "继承:"
@@ -13253,8 +13659,23 @@ msgstr ""
msgid "Instance administrators group already exists"
msgstr "实例管ç†å‘˜ç»„已存在"
-msgid "Instance license"
-msgstr "实例许å¯è¯"
+msgid "InstanceStatistics|Groups"
+msgstr ""
+
+msgid "InstanceStatistics|Issues"
+msgstr ""
+
+msgid "InstanceStatistics|Merge Requests"
+msgstr ""
+
+msgid "InstanceStatistics|Pipelines"
+msgstr ""
+
+msgid "InstanceStatistics|Projects"
+msgstr ""
+
+msgid "InstanceStatistics|Users"
+msgstr ""
msgid "Integration"
msgstr "集æˆ"
@@ -13265,6 +13686,12 @@ msgstr "集æˆè®¾ç½®"
msgid "Integrations"
msgstr "集æˆ"
+msgid "Integrations|%{integration} settings saved and active."
+msgstr ""
+
+msgid "Integrations|%{integration} settings saved, but not active."
+msgstr ""
+
msgid "Integrations|All details"
msgstr "所有详细信æ¯"
@@ -13274,6 +13701,12 @@ msgstr "评论细节:"
msgid "Integrations|Comment settings:"
msgstr "评论设置:"
+msgid "Integrations|Connection failed. Please check your settings."
+msgstr ""
+
+msgid "Integrations|Connection successful."
+msgstr ""
+
msgid "Integrations|Default settings are inherited from the group level."
msgstr ""
@@ -13289,6 +13722,15 @@ msgstr "包括标准加整个æ交消æ¯ï¼Œæ交哈希和议题ID"
msgid "Integrations|Includes commit title and branch"
msgstr "包括æ交的标题和分支"
+msgid "Integrations|Projects using custom settings will not be impacted unless the project owner chooses to use instance-level defaults."
+msgstr ""
+
+msgid "Integrations|Save settings?"
+msgstr ""
+
+msgid "Integrations|Saving will update the default settings for all projects that are not using custom settings."
+msgstr ""
+
msgid "Integrations|Standard"
msgstr "标准"
@@ -13421,6 +13863,9 @@ msgstr "无效的yaml"
msgid "Invitation"
msgstr "邀请"
+msgid "Invitation declined"
+msgstr ""
+
msgid "Invite"
msgstr "邀请"
@@ -13472,6 +13917,42 @@ 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|%{linkStart}Read more%{linkEnd} about role permissions"
+msgstr ""
+
+msgid "InviteMembersModal|Access expiration date (optional)"
+msgstr ""
+
+msgid "InviteMembersModal|Cancel"
+msgstr ""
+
+msgid "InviteMembersModal|Choose a role permission"
+msgstr ""
+
+msgid "InviteMembersModal|GitLab member or Email address"
+msgstr ""
+
+msgid "InviteMembersModal|Invite"
+msgstr ""
+
+msgid "InviteMembersModal|Invite team members"
+msgstr ""
+
+msgid "InviteMembersModal|Search for members to invite"
+msgstr ""
+
+msgid "InviteMembersModal|User not invited. Feature coming soon!"
+msgstr ""
+
+msgid "InviteMembersModal|Users were succesfully added"
+msgstr ""
+
+msgid "InviteMembersModal|You're inviting members to the %{group_name} group"
+msgstr ""
+
+msgid "InviteMembers|Invite team members"
+msgstr ""
+
msgid "Invited"
msgstr ""
@@ -13506,7 +13987,7 @@ msgid "IssuableStatus|moved"
msgstr "已移动"
msgid "IssuableStatus|promoted"
-msgstr "å·²æå‡"
+msgstr "å·²å‡çº§"
msgid "Issue"
msgstr "议题"
@@ -13526,11 +14007,14 @@ msgstr "问题已å‡çº§ä¸ºå²è¯—。"
msgid "Issue cannot be found."
msgstr "议题无法找到"
+msgid "Issue created from vulnerability %{vulnerability_link}"
+msgstr ""
+
msgid "Issue events"
msgstr "议题事件"
-msgid "Issue first depoloyed to production"
-msgstr "议题首次部署到生产环境"
+msgid "Issue first deployed to production"
+msgstr ""
msgid "Issue label"
msgstr "议题标记"
@@ -13607,6 +14091,9 @@ msgstr "Bugzilla议题跟踪器"
msgid "IssueTracker|Custom issue tracker"
msgstr "自定义议题跟踪器"
+msgid "IssueTracker|EWM work items tracker"
+msgstr ""
+
msgid "IssueTracker|Redmine issue tracker"
msgstr "Redmine议题跟踪器"
@@ -13673,6 +14160,9 @@ msgstr "标题"
msgid "It looks like you have some draft commits in this branch."
msgstr "看起æ¥ä½ åœ¨è¿™ä¸ªåˆ†æ”¯ä¸Šæœ‰ä¸€äº›è‰ç¨¿æ交。"
+msgid "It may be several days before you see feature usage data."
+msgstr ""
+
msgid "It must have a header row and at least two columns: the first column is the issue title and the second column is the issue description. The separator is automatically detected."
msgstr "它必须有标题行和至少有两列:第一æ æ˜¯è®®é¢˜æ ‡é¢˜ï¼Œç¬¬äºŒæ æ˜¯è®®é¢˜æ述。自动检测分隔符。"
@@ -13955,15 +14445,15 @@ msgstr "ç”±"
msgid "Join Zoom meeting"
msgstr "加入Zoom会议"
+msgid "Joined %{time_ago}"
+msgstr ""
+
msgid "Jul"
msgstr "7月"
msgid "July"
msgstr "7月"
-msgid "Jump to first unresolved thread"
-msgstr "跳转到第一个未解决的主题"
-
msgid "Jump to next unresolved thread"
msgstr "跳转到下一个未解决的主题"
@@ -13997,6 +14487,9 @@ msgstr "密钥: %{key}"
msgid "Keyboard shortcuts"
msgstr "å¿«æ·é”®"
+msgid "KeyboardKey|Ctrl+"
+msgstr ""
+
msgid "Keys"
msgstr "é”®"
@@ -14045,6 +14538,9 @@ msgstr "LDAP"
msgid "LDAP Synchronization"
msgstr "LDAPåŒæ­¥"
+msgid "LDAP group settings"
+msgstr ""
+
msgid "LDAP settings"
msgstr "LDAP 设置"
@@ -14054,6 +14550,9 @@ msgstr "LDAP设置已更新"
msgid "LDAP sync in progress. This could take a few minutes. Refresh the page to see the changes."
msgstr "LDAPåŒæ­¥æ­£åœ¨è¿›è¡Œä¸­ã€‚此过程å¯èƒ½éœ€è¦å‡ åˆ†é’Ÿã€‚请刷新页é¢ä»¥æŸ¥çœ‹æ›´æ”¹ã€‚"
+msgid "LDAP synchronizations"
+msgstr ""
+
msgid "LFS"
msgstr "LFS"
@@ -14118,7 +14617,7 @@ msgid "Labels|Promote Label"
msgstr "å‡çº§æ ‡è®°"
msgid "Labels|Promoting %{labelTitle} will make it available for all projects inside %{groupName}. Existing project labels with the same title will be merged. If a group label with the same title exists, it will also be merged. This action cannot be reversed."
-msgstr "æå‡%{labelTitle}将使其å¯ç”¨äºŽ%{groupName}内的所有项目。现有的åŒå项目标记将被åˆå¹¶ã€‚现有的åŒå群组标记也将被åˆå¹¶ã€‚该æ“作ä¸å¯æ’¤é”€ã€‚"
+msgstr "å‡çº§%{labelTitle}将使其å¯ç”¨äºŽ%{groupName}内的所有项目。现有的åŒå项目标记将被åˆå¹¶ã€‚现有的åŒå群组标记也将被åˆå¹¶ã€‚该æ“作ä¸å¯æ’¤é”€ã€‚"
msgid "Labels|and %{count} more"
msgstr "以åŠå…¶ä½™%{count}项"
@@ -14133,8 +14632,17 @@ msgid "Last %d day"
msgid_plural "Last %d days"
msgstr[0] "最近 %d 天"
-msgid "Last %{days} days"
-msgstr "最近%{days}天"
+msgid "Last 2 weeks"
+msgstr ""
+
+msgid "Last 30 days"
+msgstr ""
+
+msgid "Last 60 days"
+msgstr ""
+
+msgid "Last 90 days"
+msgstr ""
msgid "Last Accessed On"
msgstr "最åŽè®¿é—®äºŽ"
@@ -14211,6 +14719,9 @@ msgstr "最åŽä½¿ç”¨"
msgid "Last used on:"
msgstr "上次使用于:"
+msgid "Last week"
+msgstr ""
+
msgid "LastCommit|authored"
msgstr "编辑于"
@@ -14226,6 +14737,9 @@ msgstr "最新更改"
msgid "Latest pipeline for the most recent commit on this branch"
msgstr "此分支上最近æ交的最新æµæ°´çº¿"
+msgid "Launch a ready-to-code development environment for your project."
+msgstr ""
+
msgid "Lead"
msgstr "最高"
@@ -14599,6 +15113,9 @@ msgstr "列出å¯ç”¨ä»“库"
msgid "List of all merge commits"
msgstr ""
+msgid "List options"
+msgstr ""
+
msgid "List settings"
msgstr "列表设置"
@@ -14611,9 +15128,6 @@ msgstr "列表视图"
msgid "List your Bitbucket Server repositories"
msgstr "列出您的 Bitbucket 库"
-msgid "Lists"
-msgstr "列表"
-
msgid "Live preview"
msgstr "实时预览"
@@ -14860,6 +15374,12 @@ msgstr "将待办事项标记为已完æˆã€‚"
msgid "Mark as done"
msgstr "标记为已完æˆ"
+msgid "Mark as draft"
+msgstr ""
+
+msgid "Mark as ready"
+msgstr ""
+
msgid "Mark as resolved"
msgstr "标记为已解决"
@@ -14881,6 +15401,24 @@ msgstr "支æŒMarkdownæ ¼å¼"
msgid "Markdown is supported"
msgstr "支æŒMarkdown"
+msgid "MarkdownEditor|Add a link (%{modifierKey}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add a link (%{modifier_key}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifierKey}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifier_key}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifierKey}I)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifier_key}I)"
+msgstr ""
+
msgid "Marked For Deletion At - %{deletion_time}"
msgstr "标记删除于 - %{deletion_time}"
@@ -14965,8 +15503,26 @@ msgstr "æ¯ä¸ªç”¨æˆ·æ¯åˆ†é’Ÿæœ€å¤§é¡¹ç›®å¯¼å…¥è¯·æ±‚æ•°"
msgid "Max access level"
msgstr "最高访问级别"
-msgid "Max seats used"
-msgstr "已使用的用户数é‡"
+msgid "Max role"
+msgstr ""
+
+msgid "Max size 15 MB"
+msgstr ""
+
+msgid "Maximum Conan package file size in bytes"
+msgstr ""
+
+msgid "Maximum Maven package file size in bytes"
+msgstr ""
+
+msgid "Maximum NPM package file size in bytes"
+msgstr ""
+
+msgid "Maximum NuGet package file size in bytes"
+msgstr ""
+
+msgid "Maximum PyPI package file size in bytes"
+msgstr ""
msgid "Maximum Users:"
msgstr "最大用户数:"
@@ -15097,6 +15653,18 @@ msgstr "群组æˆå‘˜åªèƒ½æŸ¥çœ‹ä»–们有æƒè®¿é—®çš„项目"
msgid "Members with access to %{strong_start}%{group_name}%{strong_end}"
msgstr "有æƒè®¿é—®%{strong_start}%{group_name}%{strong_end}çš„æˆå‘˜"
+msgid "Members|%{time} by %{user}"
+msgstr ""
+
+msgid "Members|Expired"
+msgstr ""
+
+msgid "Members|No expiration set"
+msgstr ""
+
+msgid "Members|in %{time}"
+msgstr ""
+
msgid "Memory Usage"
msgstr "内存使用情况"
@@ -15283,9 +15851,6 @@ msgstr "主题将置为解决状æ€"
msgid "MergeRequests|Thread will be unresolved"
msgstr "主题将置为未解决状æ€"
-msgid "MergeRequests|Toggle comments for this file"
-msgstr "开关此文件的讨论"
-
msgid "MergeRequests|View file @ %{commitId}"
msgstr "查看文件 @ %{commitId}"
@@ -15346,6 +15911,9 @@ msgstr "当æµæ°´çº¿æˆåŠŸæ—¶åˆå¹¶æ­¤åˆå¹¶è¯·æ±‚。"
msgid "Merging immediately isn't recommended as it may negatively impact the existing merge train. Read the %{docsLinkStart}documentation%{docsLinkEnd} for more information."
msgstr "ä¸å»ºè®®ç«‹å³åˆå¹¶ï¼Œå› ä¸ºå®ƒå¯èƒ½å¯¹çŽ°æœ‰åˆå¹¶åˆ—车产生ä¸åˆ©å½±å“。请查阅%{docsLinkStart}文档%{docsLinkEnd}以了解更多信æ¯ã€‚"
+msgid "Message"
+msgstr ""
+
msgid "Messages"
msgstr "消æ¯"
@@ -15729,18 +16297,12 @@ msgid "Milestone"
msgid_plural "Milestones"
msgstr[0] "里程碑"
-msgid "Milestone does not support burnup charts"
-msgstr ""
-
msgid "Milestone lists not available with your current license"
msgstr "当å‰è®¸å¯è¯æ— æ³•ä½¿ç”¨é‡Œç¨‹ç¢‘列表"
msgid "Milestone lists show all issues from the selected milestone."
msgstr "里程碑列表显示所选里程碑的所有议题。"
-msgid "Milestone must have a start and due date"
-msgstr ""
-
msgid "MilestoneSidebar|Closed:"
msgstr "关闭:"
@@ -15841,10 +16403,10 @@ msgid "Milestones|Promote Milestone"
msgstr "å‡çº§é‡Œç¨‹ç¢‘"
msgid "Milestones|Promote to Group Milestone"
-msgstr "æå‡åˆ°ç»„里程碑"
+msgstr "å‡çº§åˆ°ç»„里程碑"
msgid "Milestones|Promoting %{milestoneTitle} will make it available for all projects inside %{groupName}. Existing project milestones with the same title will be merged."
-msgstr "æå‡%{milestoneTitle}åŽï¼Œè¯¥é‡Œç¨‹ç¢‘å°†å¯ç”¨äºŽ%{groupName}群组内的所有项目。如果现有项目里程碑具有相åŒæ ‡é¢˜ï¼Œè¿™äº›é¡¹ç›®é‡Œç¨‹ç¢‘被åˆå¹¶å…¥ç¾¤ç»„里程碑。"
+msgstr "å‡çº§%{milestoneTitle}åŽï¼Œè¯¥é‡Œç¨‹ç¢‘å°†å¯ç”¨äºŽ%{groupName}群组内的所有项目。如果现有项目里程碑具有相åŒæ ‡é¢˜ï¼Œè¿™äº›é¡¹ç›®é‡Œç¨‹ç¢‘被åˆå¹¶å…¥ç¾¤ç»„里程碑。"
msgid "Milestones|Reopen Milestone"
msgstr "é‡å¯é‡Œç¨‹ç¢‘"
@@ -16107,6 +16669,9 @@ msgstr "å称:"
msgid "Namespace"
msgstr "命å空间"
+msgid "Namespace ID:"
+msgstr ""
+
msgid "Namespace is empty"
msgstr "命å空间为空"
@@ -16191,6 +16756,9 @@ msgstr ""
msgid "NetworkPolicies|Allow all outbound traffic from %{selector} to %{ruleSelector} on %{ports}"
msgstr ""
+msgid "NetworkPolicies|Are you sure you want to delete this policy? This action cannot be undone."
+msgstr ""
+
msgid "NetworkPolicies|Choose whether to enforce this policy."
msgstr "选择是å¦å¼ºåˆ¶æ­¤ç­–略。"
@@ -16200,12 +16768,21 @@ msgstr "创建策略"
msgid "NetworkPolicies|Define this policy's location, conditions and actions."
msgstr "定义此策略的ä½ç½®ï¼Œæ¡ä»¶å’Œæ“作。"
+msgid "NetworkPolicies|Delete policy"
+msgstr ""
+
+msgid "NetworkPolicies|Delete policy: %{policy}"
+msgstr ""
+
msgid "NetworkPolicies|Deny all traffic"
msgstr ""
msgid "NetworkPolicies|Description"
msgstr "æè¿°"
+msgid "NetworkPolicies|Edit policy"
+msgstr ""
+
msgid "NetworkPolicies|Editor mode"
msgstr "编辑模å¼"
@@ -16233,6 +16810,9 @@ msgstr "最åŽä¿®æ”¹"
msgid "NetworkPolicies|Name"
msgstr "å称"
+msgid "NetworkPolicies|Namespace"
+msgstr ""
+
msgid "NetworkPolicies|Network Policy"
msgstr "网络政策"
@@ -16284,6 +16864,9 @@ msgstr ""
msgid "NetworkPolicies|Rules"
msgstr "规则"
+msgid "NetworkPolicies|Save changes"
+msgstr ""
+
msgid "NetworkPolicies|Something went wrong, failed to update policy"
msgstr "出现错误,未能更新策略"
@@ -16296,6 +16879,9 @@ msgstr "状æ€"
msgid "NetworkPolicies|Traffic that does not match any rule will be blocked."
msgstr ""
+msgid "NetworkPolicies|Unable to parse policy"
+msgstr ""
+
msgid "NetworkPolicies|YAML editor"
msgstr "YAML编辑"
@@ -16408,6 +16994,9 @@ msgstr "新建需求"
msgid "New Snippet"
msgstr "新建代ç ç‰‡æ®µ"
+msgid "New Test Case"
+msgstr ""
+
msgid "New User"
msgstr "新建用户"
@@ -16421,10 +17010,10 @@ msgid "New changes were added. %{linkStart}Reload the page to review them%{linkE
msgstr "添加了新的å˜æ›´ã€‚ %{linkStart}é‡æ–°åŠ è½½é¡µé¢ä»¥æŸ¥çœ‹%{linkEnd}"
msgid "New confidential epic title "
-msgstr "新建机密å²è¯—标题 "
+msgstr "新建ç§å¯†å²è¯—标题 "
msgid "New confidential issue title"
-msgstr "新建机密议题标题"
+msgstr "新建ç§å¯†è®®é¢˜æ ‡é¢˜"
msgid "New deploy key"
msgstr "新建部署密钥"
@@ -16507,6 +17096,9 @@ msgstr "新建å­ç¾¤ç»„"
msgid "New tag"
msgstr "新建标签"
+msgid "New test case"
+msgstr ""
+
msgid "New users set to external"
msgstr "新用户设置为外部"
@@ -16579,8 +17171,8 @@ msgstr "未å‘现分支"
msgid "No changes"
msgstr "æ— å˜æ›´å†…容"
-msgid "No changes between %{ref_start}%{source_branch}%{ref_end} and %{ref_start}%{target_branch}%{ref_end}"
-msgstr "%{ref_start}%{source_branch}%{ref_end} å’Œ %{ref_start}%{target_branch}%{ref_end} 之间没有产生å˜åŒ–"
+msgid "No changes between %{sourceBranch} and %{targetBranch}"
+msgstr ""
msgid "No child epics match applied filters"
msgstr "没有匹é…当å‰è¿‡æ»¤å™¨çš„å­å²è¯—"
@@ -16594,6 +17186,9 @@ msgstr "无法连接到GitalyæœåŠ¡å™¨ï¼Œè¯·æ£€æŸ¥ç›¸å…³æ—¥å¿—ï¼"
msgid "No containers available"
msgstr "没有å¯ç”¨çš„容器"
+msgid "No content to show"
+msgstr ""
+
msgid "No contributions"
msgstr "无贡献"
@@ -16669,9 +17264,6 @@ msgstr "没有具有此类å称或æ述的标记"
msgid "No license. All rights reserved"
msgstr "未设定许å¯è¯ã€‚版æƒæ‰€æœ‰ã€‚"
-msgid "No licenses found."
-msgstr "未找到许å¯è¯ã€‚"
-
msgid "No matches found"
msgstr "没有找到匹é…项"
@@ -16684,6 +17276,9 @@ msgstr "没有匹é…的结果"
msgid "No matching results for \"%{query}\""
msgstr "没有与“%{query}â€åŒ¹é…的结果"
+msgid "No members found"
+msgstr ""
+
msgid "No merge requests found"
msgstr "找ä¸åˆ°åˆå¹¶è¯·æ±‚"
@@ -16705,6 +17300,9 @@ msgstr "没有与属性匹é…çš„é¢æ¿%{opts}"
msgid "No parent group"
msgstr "父群组ä¸å­˜åœ¨"
+msgid "No plan"
+msgstr ""
+
msgid "No pods available"
msgstr "没有å¯ç”¨çš„pod"
@@ -16801,6 +17399,12 @@ msgstr "æ— "
msgid "Not Implemented"
msgstr "尚未实现"
+msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+msgstr ""
+
+msgid "Not all browsers support WebAuthn. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even from an unsupported browser."
+msgstr ""
+
msgid "Not all data has been processed yet, the accuracy of the chart for the selected timeframe is limited."
msgstr "尚未处ç†æ‰€æœ‰æ•°æ®ï¼Œå› æ­¤æ‰€é€‰æ—¶é—´èŒƒå›´å†…图表的ä¸ä¸€å®šå®Œå…¨å‡†ç¡®ã€‚"
@@ -16897,6 +17501,9 @@ msgstr "通知设置 - %{notification_title}"
msgid "Notification settings saved"
msgstr "通知设置已ä¿å­˜"
+msgid "NotificationEvent|Change reviewer merge request"
+msgstr ""
+
msgid "NotificationEvent|Close issue"
msgstr "关闭议题"
@@ -17059,11 +17666,8 @@ msgstr "Omnibusä¿æŠ¤è·¯å¾„阈值已å¯ç”¨ï¼Œä¸”优先级高于这些设置。ä»
msgid "On track"
msgstr "进度正常"
-msgid "OnDemandScans|Attached branch"
-msgstr "å…³è”分支"
-
-msgid "OnDemandScans|Attached branch is where the scan job runs."
-msgstr "å…³è”分支是扫æ作业è¿è¡ŒçŽ¯å¢ƒã€‚"
+msgid "OnDemandScans|Could not fetch scanner profiles. Please refresh the page, or try again later."
+msgstr ""
msgid "OnDemandScans|Could not fetch site profiles. Please refresh the page, or try again later."
msgstr ""
@@ -17071,6 +17675,9 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr "无法è¿è¡Œæ‰«æ。请é‡è¯•ã€‚"
+msgid "OnDemandScans|Create a new scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Create a new site profile"
msgstr ""
@@ -17083,6 +17690,9 @@ msgstr ""
msgid "OnDemandScans|New on-demand DAST scan"
msgstr "新建按需扫æDAST"
+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 ""
@@ -17092,17 +17702,11 @@ msgstr "按需扫æ"
msgid "OnDemandScans|On-demand scans run outside the DevOps cycle and find vulnerabilities in your projects. %{learnMoreLinkStart}Learn more%{learnMoreLinkEnd}"
msgstr "按需扫æ在DevOps周期之外è¿è¡Œï¼Œå¹¶åœ¨æ‚¨çš„项目中å‘现æ¼æ´žã€‚%{learnMoreLinkStart}了解更多%{learnMoreLinkEnd}"
-msgid "OnDemandScans|Only a passive scan can be performed on demand."
-msgstr "åªæœ‰è¢«åŠ¨æ‰«æå¯ä»¥æŒ‰éœ€æ‰§è¡Œã€‚"
-
-msgid "OnDemandScans|Passive"
-msgstr ""
-
msgid "OnDemandScans|Run scan"
msgstr ""
-msgid "OnDemandScans|Scan mode"
-msgstr "扫æ模å¼"
+msgid "OnDemandScans|Scanner profile"
+msgstr ""
msgid "OnDemandScans|Scanner settings"
msgstr ""
@@ -17113,9 +17717,15 @@ msgstr "计划或立å³å¯¹ç›®æ ‡ç«™ç‚¹è¿è¡Œæ‰«æ。当å‰å¯ç”¨çš„按需扫æ
msgid "OnDemandScans|Select one of the existing profiles"
msgstr ""
+msgid "OnDemandScans|Site profile"
+msgstr ""
+
msgid "OnDemandScans|Site profiles"
msgstr ""
+msgid "OnDemandScans|Use existing scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Use existing site profile"
msgstr ""
@@ -17213,9 +17823,6 @@ msgstr "开放中"
msgid "Open Selection"
msgstr "打开所选项"
-msgid "Open Web IDE"
-msgstr ""
-
msgid "Open comment type dropdown"
msgstr "打开评论类型下拉列表"
@@ -17321,6 +17928,9 @@ msgstr "或者您å¯ä»¥é€‰æ‹©ä¸‹é¢çš„建议颜色之一"
msgid "Origin"
msgstr "æº"
+msgid "Orphaned member"
+msgstr ""
+
msgid "Other Labels"
msgstr "其他标记"
@@ -17336,6 +17946,9 @@ msgstr "其他版本"
msgid "Other visibility settings have been disabled by the administrator."
msgstr "其他å¯è§æ€§è®¾ç½®å·²è¢«ç®¡ç†å‘˜ç¦ç”¨ã€‚"
+msgid "Our documentation includes an example DevOps Score report."
+msgstr ""
+
msgid "Out-of-compliance with this project's policies and should be removed"
msgstr "ä¸ç¬¦åˆè¯¥é¡¹ç›®æ”¿ç­–,应予以删除"
@@ -17360,6 +17973,9 @@ msgstr "概览"
msgid "Overwrite diverged branches"
msgstr "覆盖分å‰åˆ†æ”¯"
+msgid "Owned by %{image_tag}"
+msgstr ""
+
msgid "Owned by anyone"
msgstr "拥有者为任何人"
@@ -17381,6 +17997,9 @@ msgstr "软件包已存在"
msgid "Package deleted successfully"
msgstr "包已æˆåŠŸåˆ é™¤"
+msgid "Package file size limits"
+msgstr ""
+
msgid "Package recipe already exists"
msgstr "软件包构æˆå·²å­˜åœ¨"
@@ -17396,9 +18015,6 @@ msgstr "包类型必须是Nuget"
msgid "Package type must be PyPi"
msgstr "包类型必须是PyPi"
-msgid "Package was removed"
-msgstr "包已被删除"
-
msgid "PackageRegistry|%{name} version %{version} was created %{datetime}"
msgstr "%{name}版 %{version}创建于%{datetime}"
@@ -17540,12 +18156,18 @@ msgstr "NuGet"
msgid "PackageRegistry|NuGet Command"
msgstr "NuGet命令"
+msgid "PackageRegistry|Package Registry"
+msgstr ""
+
msgid "PackageRegistry|Pip Command"
msgstr "Pip命令"
msgid "PackageRegistry|Pipeline %{link} triggered %{datetime} by %{author}"
msgstr "æµæ°´çº¿%{link}ç”±%{author}触å‘于%{datetime}"
+msgid "PackageRegistry|Publish and share packages for a variety of common package managers. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "PackageRegistry|Published to the %{project} Package Registry %{datetime}"
msgstr "于%{datetime}å‘布到%{project}软件包注册表"
@@ -17645,6 +18267,9 @@ msgstr "软件包与镜åƒåº“"
msgid "Page not found"
msgstr "找ä¸åˆ°é¡µé¢"
+msgid "Page settings"
+msgstr ""
+
msgid "Page was successfully deleted"
msgstr "页é¢å·²æˆåŠŸåˆ é™¤"
@@ -17775,10 +18400,10 @@ msgid "Paste a machine public key here. Read more about how to generate it %{lin
msgstr "在此处粘贴计算机公钥。在%{link_start}这里%{link_end}了解更多关于如何产生公钥"
msgid "Paste confidential epic link"
-msgstr "粘贴机密å²è¯—链接"
+msgstr "粘贴ç§å¯†å²è¯—链接"
msgid "Paste confidential issue link"
-msgstr "粘贴机密议题链接"
+msgstr "粘贴ç§å¯†è®®é¢˜é“¾æŽ¥"
msgid "Paste epic link"
msgstr "粘贴å²è¯—链接"
@@ -17786,8 +18411,8 @@ msgstr "粘贴å²è¯—链接"
msgid "Paste issue link"
msgstr "粘贴议题链接"
-msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Don't use your private SSH key."
-msgstr "粘贴您的SSH公钥,通常包å«åœ¨æ–‡ä»¶'~/.ssh/id_ed25519.pub'或'~/.ssh/id_rsa.pub' 中,并以“ssh-ed25519â€æˆ–“ssh-rsaâ€å¼€å¤´ã€‚请ä¸è¦ä½¿ç”¨æ‚¨çš„SSHç§é’¥ã€‚"
+msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Do not paste your private SSH key, as that can compromise your identity."
+msgstr ""
msgid "Patch to apply"
msgstr "è¦åº”用的补ä¸"
@@ -17813,6 +18438,9 @@ msgstr "æš‚åœçš„ Runner ä¸æŽ¥å—新作业"
msgid "Pending"
msgstr "等待中"
+msgid "Pending comments"
+msgstr ""
+
msgid "People without permission will never get a notification and won't be able to comment."
msgstr "æƒé™ä¸è¶³çš„用户将无法收到通知,也无法评论。"
@@ -18011,6 +18639,9 @@ msgstr "您确定è¦è¿è¡Œè¿™æ¡æµæ°´çº¿å—?"
msgid "Pipelines|Build with confidence"
msgstr "自信地构建"
+msgid "Pipelines|By revoking a trigger you will break any processes making use of it. Are you sure?"
+msgstr ""
+
msgid "Pipelines|CI Lint"
msgstr "CI é…置检查(CI Lint)"
@@ -18023,6 +18654,15 @@ msgstr "清除Runner缓存"
msgid "Pipelines|Continuous Integration can help catch bugs by running your tests automatically, while Continuous Deployment can help you deliver code to your product environment."
msgstr "æŒç»­é›†æˆå¯ä»¥é€šè¿‡è‡ªåŠ¨è¿è¡Œæµ‹è¯•æ¥å¸®åŠ©æ£€æµ‹ä»£ç ç¼ºé™·ï¼Œè€ŒæŒç»­éƒ¨ç½²å¯ä»¥å¸®åŠ©æ‚¨å‘生产环境交付代ç ã€‚"
+msgid "Pipelines|Copy trigger token"
+msgstr ""
+
+msgid "Pipelines|Description"
+msgstr ""
+
+msgid "Pipelines|Edit"
+msgstr ""
+
msgid "Pipelines|Get started with Pipelines"
msgstr "æµæ°´çº¿å…¥é—¨"
@@ -18038,15 +18678,27 @@ msgstr "如果您ä¸ç¡®å®šï¼Œè¯·é¡¹ç›®ç»´æŠ¤è€…为您审核。"
msgid "Pipelines|It is recommended the code is reviewed thoroughly before running this pipeline with the parent project's CI resource."
msgstr "建议在使用父项目的CI资æºè¿è¡Œæ­¤æµæ°´çº¿ä¹‹å‰å¯¹ä»£ç è¿›è¡Œè¯¦å°½çš„审核。"
+msgid "Pipelines|Last Used"
+msgstr ""
+
msgid "Pipelines|Loading Pipelines"
msgstr "载入æµæ°´çº¿"
msgid "Pipelines|More Information"
msgstr "更多信æ¯"
+msgid "Pipelines|No triggers have been created yet. Add one using the form above."
+msgstr ""
+
+msgid "Pipelines|Owner"
+msgstr ""
+
msgid "Pipelines|Project cache successfully reset."
msgstr "项目缓存é‡ç½®æˆåŠŸã€‚"
+msgid "Pipelines|Revoke"
+msgstr ""
+
msgid "Pipelines|Run Pipeline"
msgstr "è¿è¡Œæµæ°´çº¿"
@@ -18071,6 +18723,15 @@ msgstr "此管é“å°†è¿è¡Œæºè‡ªæ´¾ç”Ÿé¡¹ç›®åˆå¹¶è¯·æ±‚的代ç ã€‚ è¿™æ„味ç
msgid "Pipelines|This project is not currently set up to run pipelines."
msgstr "此项目当å‰æœªé…ç½®è¿è¡Œæµæ°´çº¿ã€‚"
+msgid "Pipelines|Token"
+msgstr ""
+
+msgid "Pipelines|Trigger user has insufficient permissions to project"
+msgstr ""
+
+msgid "Pipelines|invalid"
+msgstr ""
+
msgid "Pipelines|parent"
msgstr "父级"
@@ -18329,12 +18990,12 @@ msgstr "请æ供有效的电å­é‚®ä»¶åœ°å€ã€‚"
msgid "Please provide attributes to update"
msgstr "请æä¾›è¦æ›´æ–°çš„属性"
+msgid "Please reach out if you have any questions and we'll be happy to assist."
+msgstr ""
+
msgid "Please refer to %{docs_url}"
msgstr "请å‚考%{docs_url}"
-msgid "Please retype the email address."
-msgstr "请å†æ¬¡è¾“入电å­é‚®ä»¶åœ°å€ã€‚"
-
msgid "Please select"
msgstr "请选择"
@@ -18362,6 +19023,9 @@ msgstr "请至少选择一个过滤器æ¥æŸ¥çœ‹ç»“æžœ"
msgid "Please set a new password before proceeding."
msgstr "请设置新密ç ä»¥ç»§ç»­ä¸‹ä¸€æ­¥ã€‚"
+msgid "Please share your feedback about %{featureName} %{linkStart}in this issue%{linkEnd} to help us improve the experience."
+msgstr ""
+
msgid "Please solve the reCAPTCHA"
msgstr "请填写验è¯ç ã€‚"
@@ -18665,6 +19329,9 @@ msgstr "您å³å°†æ°¸ä¹…删除 %{yourAccount},以åŠä¸Žæ‚¨çš„å¸æˆ·å…³è”的所
msgid "Profiles| You are going to change the username %{currentUsernameBold} to %{newUsernameBold}. Profile and projects will be redirected to the %{newUsername} namespace but this redirect will expire once the %{currentUsername} namespace is registered by another user or group. Please update your Git repository remotes as soon as possible."
msgstr "您将更改用户å %{currentUsernameBold} 为 %{newUsernameBold}。é…置文件和项目将é‡å®šå‘到 %{newUsername} 命å空间,但是一旦 %{currentUsername} 命å空间被å¦ä¸€ä¸ªç”¨æˆ·æˆ–组注册,此é‡å®šå‘将过期。请尽快更新您的远端Git仓库。"
+msgid "Profiles|%{provider} Active"
+msgstr ""
+
msgid "Profiles|@username"
msgstr "@用户å"
@@ -18716,8 +19383,8 @@ msgstr "å•å‡»å›¾æ ‡ä»¥ä½¿ç”¨ä»¥ä¸‹æœåŠ¡ä¹‹ä¸€æ¿€æ´»ç™»å½•"
msgid "Profiles|Commit email"
msgstr "æ交邮件"
-msgid "Profiles|Connect"
-msgstr "连接"
+msgid "Profiles|Connect %{provider}"
+msgstr ""
msgid "Profiles|Connected Accounts"
msgstr "å…³è”账户"
@@ -18740,6 +19407,9 @@ msgstr "删除å¸æˆ·å…·æœ‰ä»¥ä¸‹æ•ˆæžœï¼š"
msgid "Profiles|Disconnect"
msgstr "æ–­å¼€"
+msgid "Profiles|Disconnect %{provider}"
+msgstr ""
+
msgid "Profiles|Do not show on profile"
msgstr "ä¸åœ¨ä¸ªäººèµ„料中显示"
@@ -18764,8 +19434,8 @@ msgstr "ä¿¡æ¯åŠ¨æ€ä»¤ç‰Œå·²æˆåŠŸé‡ç½®"
msgid "Profiles|Full name"
msgstr "å…¨å"
-msgid "Profiles|Give your individual key a title. This will be publically visible."
-msgstr "请通过标题给您的个人密钥命å。该标题公开å¯è§ã€‚"
+msgid "Profiles|Give your individual key a title."
+msgstr ""
msgid "Profiles|Include private contributions on my profile"
msgstr "在个人资料中包å«éžå…¬å¼€è´¡çŒ®"
@@ -18854,8 +19524,8 @@ msgstr "姓å更新功能已被管ç†å‘˜ç¦ç”¨ã€‚"
msgid "Profiles|The maximum file size allowed is 200KB."
msgstr "å…许的最大文件大å°ä¸º200KB。"
-msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it?"
-msgstr "这看起æ¥ä¸åƒ SSH 公钥,确定è¦æ·»åŠ å®ƒå—?"
+msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it? It will be publicly visible."
+msgstr ""
msgid "Profiles|This email will be displayed on your public profile"
msgstr "此电å­é‚®ä»¶å°†æ˜¾ç¤ºåœ¨æ‚¨çš„公开个人资料中。"
@@ -18929,6 +19599,9 @@ msgstr "å¯ä»¥åœ¨è¿™é‡Œä¸Šä¼ æ‚¨çš„头åƒæˆ–者从 %{gravatar_link} 修改头åƒ
msgid "Profiles|You don't have access to delete this user."
msgstr "您无æƒåˆ é™¤æ­¤ç”¨æˆ·ã€‚"
+msgid "Profiles|You must transfer ownership or delete groups you are an owner of before you can delete your account"
+msgstr ""
+
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr "您必须转移所有æƒæˆ–删除这些群组,然åŽæ‰èƒ½åˆ é™¤æ‚¨çš„å¸æˆ·ã€‚"
@@ -19209,7 +19882,7 @@ msgid "ProjectService|Event will be triggered when a commit is created/updated"
msgstr "创建/æ›´æ–°æ交时事件将被触å‘"
msgid "ProjectService|Event will be triggered when a confidential issue is created/updated/closed"
-msgstr "机密议题创建/æ›´æ–°/关闭时事件将被触å‘"
+msgstr "ç§å¯†è®®é¢˜åˆ›å»º/æ›´æ–°/关闭时事件将被触å‘"
msgid "ProjectService|Event will be triggered when a deployment finishes"
msgstr "部署结æŸåŽäº‹ä»¶å°†è¢«è§¦å‘"
@@ -19236,7 +19909,7 @@ msgid "ProjectService|Event will be triggered when someone adds a comment"
msgstr "当有人添加评论时事件将被触å‘"
msgid "ProjectService|Event will be triggered when someone adds a comment on a confidential issue"
-msgstr "当有人å‘机密议题添加评论时事件将被触å‘"
+msgstr "当有人å‘ç§å¯†è®®é¢˜æ·»åŠ è¯„论时事件将被触å‘"
msgid "ProjectService|Perform common operations on GitLab project: %{project_name}"
msgstr "在GitLab项目上执行常è§æ“作: %{project_name}"
@@ -19517,6 +20190,9 @@ msgstr "Android"
msgid "ProjectTemplates|GitLab Cluster Management"
msgstr "GitLab集群管ç†"
+msgid "ProjectTemplates|Gitpod/Spring Petclinic"
+msgstr ""
+
msgid "ProjectTemplates|Go Micro"
msgstr "Go Micro"
@@ -19860,10 +20536,10 @@ msgid "Promote"
msgstr "å‡çº§"
msgid "Promote confidential issue to a non-confidential epic"
-msgstr "将机密议题å‡çº§ä¸ºéžæœºå¯†å²è¯—"
+msgstr "å°†ç§å¯†è®®é¢˜å‡çº§ä¸ºéžç§å¯†å²è¯—"
msgid "Promote issue to an epic"
-msgstr "将议题æå‡ä¸ºå²è¯—"
+msgstr "将议题å‡çº§ä¸ºå²è¯—"
msgid "Promote to group label"
msgstr "å‡çº§åˆ°ç¾¤ç»„标记"
@@ -19878,10 +20554,10 @@ msgid "PromoteMilestone|Promotion failed - %{message}"
msgstr "å‡çº§å¤±è´¥ - %{message}"
msgid "Promoted confidential issue to a non-confidential epic. Information in this issue is no longer confidential as epics are public to group members."
-msgstr "将机密问题æå‡ä¸ºéžæœºå¯†å²è¯—。由于å²è¯—对群组æˆå‘˜å…¬å¼€ï¼Œå› æ­¤æ­¤è®®é¢˜ä¸­çš„ä¿¡æ¯ä¸å†æ˜¯æœºå¯†çš„。"
+msgstr "å°†ç§å¯†é—®é¢˜å‡çº§ä¸ºéžç§å¯†å²è¯—。由于å²è¯—对群组æˆå‘˜å…¬å¼€ï¼Œå› æ­¤æ­¤è®®é¢˜ä¸­çš„ä¿¡æ¯ä¸å†æ˜¯ç§å¯†çš„。"
msgid "Promoted issue to an epic."
-msgstr "将议题æå‡ä¸ºå²è¯—."
+msgstr "将议题å‡çº§ä¸ºå²è¯—."
msgid "Promotion is not supported."
msgstr ""
@@ -20126,6 +20802,9 @@ msgstr "公开项目分钟æˆæœ¬ç³»æ•°"
msgid "Publish to status page"
msgstr "å‘布到状æ€é¡µ"
+msgid "Published"
+msgstr ""
+
msgid "Published on status page"
msgstr "å·²å‘布到状æ€é¡µ"
@@ -20243,9 +20922,15 @@ msgstr "快速æ“作å¯ç”¨äºŽè®®é¢˜æ述和评论框。"
msgid "Quick range"
msgstr "å¿«æ·èŒƒå›´"
+msgid "Quickly and easily edit multiple files in your project."
+msgstr ""
+
msgid "README"
msgstr "自述文件"
+msgid "Rails"
+msgstr ""
+
msgid "Rake Tasks Help"
msgstr "Rake任务帮助"
@@ -20364,12 +21049,15 @@ msgstr "注册/登录"
msgid "Register Two-Factor Authenticator"
msgstr "注册åŒé‡è®¤è¯"
-msgid "Register U2F device"
-msgstr "注册U2F设备"
-
msgid "Register Universal Two-Factor (U2F) Device"
msgstr "注册通用åŒé‡è®¤è¯è®¾å¤‡(U2F)"
+msgid "Register WebAuthn Device"
+msgstr ""
+
+msgid "Register device"
+msgstr ""
+
msgid "Register for GitLab"
msgstr "注册GitLabå¸æˆ·"
@@ -20379,9 +21067,6 @@ msgstr "ç«‹å³æ³¨å†Œ"
msgid "Register with two-factor app"
msgstr "使用åŒé‡è®¤è¯åº”用注册"
-msgid "Registration"
-msgstr "注册"
-
msgid "Registration|Checkout"
msgstr "支付"
@@ -20497,9 +21182,6 @@ msgstr "获å–å‘布详细信æ¯æ—¶å‡ºé”™"
msgid "Release|Something went wrong while saving the release details"
msgstr "ä¿å­˜å‘布详细信æ¯æ—¶å‡ºé”™"
-msgid "Remediated: needs review"
-msgstr "已修补:需è¦å®¡æŸ¥"
-
msgid "Remediations"
msgstr "ä¿®å¤æŽªæ–½"
@@ -20605,6 +21287,9 @@ msgstr "删除主节点"
msgid "Remove priority"
msgstr "删除优先级"
+msgid "Remove report"
+msgstr ""
+
msgid "Remove secondary node"
msgstr "删除次è¦èŠ‚点"
@@ -20617,6 +21302,12 @@ msgstr "移除阶段"
msgid "Remove time estimate"
msgstr "删除时间估计"
+msgid "Remove user & report"
+msgstr ""
+
+msgid "Remove user from group"
+msgstr ""
+
msgid "Removed"
msgstr "已删除"
@@ -20698,9 +21389,6 @@ msgstr "删除截止日期."
msgid "Removes time estimate."
msgstr "删除时间估计。"
-msgid "Removing license…"
-msgstr "删除许å¯è¯â€¦"
-
msgid "Removing this group also removes all child projects, including archived projects, and their resources."
msgstr "删除该群组åŒæ—¶ä¼šåˆ é™¤æ‰€æœ‰å­é¡¹ç›®ï¼ŒåŒ…括已归档项目åŠå…¶ç›¸å…³èµ„æºã€‚"
@@ -20785,6 +21473,9 @@ msgstr "å‘管ç†å‘˜æŠ¥å‘Šæ»¥ç”¨è¡Œä¸º"
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr "由%{reportedBy}报告于%{timeAgo}"
+msgid "Reported by %{reporter}"
+msgstr ""
+
msgid "Reporting"
msgstr "报告"
@@ -20870,6 +21561,27 @@ msgstr "未å‘生å˜åŒ–的测试结果"
msgid "Repositories"
msgstr "仓库"
+msgid "Repositories Analytics"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download Historic Test Coverage Data"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download historic test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Historic Test Coverage Data is available in raw format (.csv) for further analysis."
+msgstr ""
+
+msgid "RepositoriesAnalytics|Test Code Coverage"
+msgstr ""
+
+msgid "RepositoriesAnalytics|There was an error fetching the projects."
+msgstr ""
+
msgid "Repository"
msgstr "仓库"
@@ -20948,9 +21660,15 @@ msgstr "请求详情"
msgid "Request parameter %{param} is missing."
msgstr "请求å‚æ•°%{param}缺失。"
+msgid "Request review from"
+msgstr ""
+
msgid "Request to link SAML account must be authorized"
msgstr "链接SAMLå¸æˆ·çš„请求必须ç»è¿‡æŽˆæƒ"
+msgid "Requested"
+msgstr ""
+
msgid "Requested %{time_ago}"
msgstr "请求的 %{time_ago}"
@@ -20969,6 +21687,9 @@ msgstr "请求分æž"
msgid "Requests to these domain(s)/address(es) on the local network will be allowed when local requests from hooks and services are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 or 127.0.0.0/28 are supported. Domain wildcards are not supported currently. Use comma, semicolon, or newline to separate multiple entries. The allowlist can hold a maximum of 1000 entries. Domains should use IDNA encoding. Ex: example.com, 192.168.1.1, 127.0.0.0/28, xn--itlab-j1a.com."
msgstr "当ä¸å…许æ¥è‡ªé’©å­å’ŒæœåŠ¡çš„本地请求时,将å…许对本地网络上这些域/地å€çš„请求。å¯æ”¯æŒIP范围,例如1:0:0:0:0:0:0:0/124或127.0.0.0/28。当å‰ä¸æ”¯æŒåŸŸé€šé…符。多个æ¡ç›®éœ€ä½¿ç”¨é€—å·ï¼Œåˆ†å·æˆ–æ¢è¡Œç¬¦åˆ†éš”。å…许åå•æœ€å¤šå¯å®¹çº³1000个æ¡ç›®ã€‚域应使用IDNAç¼–ç ã€‚例如:example.com,192.168.1.1ã€127.0.0.0/28, xn--itlab-j1a.com。"
+msgid "Require admin approval for new sign-ups"
+msgstr ""
+
msgid "Require all users in this group to setup Two-factor authentication"
msgstr "è¦æ±‚此群组中的所有用户都å¯ç”¨åŒé‡è®¤è¯"
@@ -21094,9 +21815,6 @@ msgstr "解决者"
msgid "Resolved by %{name}"
msgstr "由%{name}解决"
-msgid "Resolved by %{resolvedByName}"
-msgstr "由%{resolvedByName}解决"
-
msgid "Resolves IP addresses once and uses them to submit requests"
msgstr "解æžä¸€æ¬¡IP地å€å¹¶ä½¿ç”¨å®ƒä»¬æ交请求"
@@ -21215,6 +21933,13 @@ msgstr "审阅时间定义为从首次评论到åˆå¹¶æ‰€éœ€æ—¶é—´ã€‚"
msgid "ReviewApp|Enable Review App"
msgstr "å¯ç”¨å®¡é˜…应用"
+msgid "Reviewer"
+msgid_plural "%d Reviewers"
+msgstr[0] ""
+
+msgid "Reviewer(s)"
+msgstr ""
+
msgid "Reviewing"
msgstr "审阅中"
@@ -21254,6 +21979,9 @@ msgstr "回滚"
msgid "Rook"
msgstr "Rook"
+msgid "Ruby"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -21332,6 +22060,63 @@ msgstr "当å‰åœ¨çº¿Runner: %{active_runners_count}"
msgid "Runners page."
msgstr "Runner页é¢."
+msgid "Runners|Active"
+msgstr ""
+
+msgid "Runners|Architecture"
+msgstr ""
+
+msgid "Runners|Can run untagged jobs"
+msgstr ""
+
+msgid "Runners|Description"
+msgstr ""
+
+msgid "Runners|Group"
+msgstr ""
+
+msgid "Runners|IP Address"
+msgstr ""
+
+msgid "Runners|Last contact"
+msgstr ""
+
+msgid "Runners|Locked to this project"
+msgstr ""
+
+msgid "Runners|Maximum job timeout"
+msgstr ""
+
+msgid "Runners|Name"
+msgstr ""
+
+msgid "Runners|Platform"
+msgstr ""
+
+msgid "Runners|Property Name"
+msgstr ""
+
+msgid "Runners|Protected"
+msgstr ""
+
+msgid "Runners|Revision"
+msgstr ""
+
+msgid "Runners|Shared"
+msgstr ""
+
+msgid "Runners|Specific"
+msgstr ""
+
+msgid "Runners|Tags"
+msgstr ""
+
+msgid "Runners|Value"
+msgstr ""
+
+msgid "Runners|Version"
+msgstr ""
+
msgid "Runners|You have used %{quotaUsed} out of %{quotaLimit} of your shared Runners pipeline minutes."
msgstr "您已使用了%{quotaUsed},超出了共享æµæ°´çº¿æ—¶é—´é…é¢é™åˆ¶ï¼ˆ%{quotaLimit} )。"
@@ -21344,6 +22129,9 @@ msgstr "è¿è¡Œä¸­..."
msgid "Runs a number of housekeeping tasks within the current repository, such as compressing file revisions and removing unreachable objects."
msgstr "在当å‰ä»“库中è¿è¡Œä¸€äº›ä¾‹è¡Œç»´æŠ¤ä»»åŠ¡ï¼Œä¾‹å¦‚压缩文件修订和删除无法访问的对象。"
+msgid "SAML"
+msgstr ""
+
msgid "SAML SSO"
msgstr "SAML SSO(å•ç‚¹ç™»å½•)"
@@ -21395,6 +22183,9 @@ msgstr "星期六"
msgid "Save"
msgstr "ä¿å­˜"
+msgid "Save %{name} size limits"
+msgstr ""
+
msgid "Save Changes"
msgstr "ä¿å­˜ä¿®æ”¹"
@@ -21425,9 +22216,6 @@ msgstr "ä¿å­˜æµæ°´çº¿è®¡åˆ’"
msgid "Save space and find tags in the Container Registry more easily. Enable the cleanup policy to remove stale tags and keep only the ones you need."
msgstr "节çœç©ºé—´å¹¶æ›´ä½¿å¾—在容器注册表中查找标签更容易。 å¯ç”¨æ¸…ç†ç­–ç•¥æ¥åˆ é™¤è¿‡æ—¶çš„标签,åªä¿ç•™æ‚¨éœ€è¦çš„标签。"
-msgid "Save template"
-msgstr "ä¿å­˜æ¨¡æ¿"
-
msgid "Save variables"
msgstr "ä¿å­˜å˜é‡"
@@ -21470,9 +22258,6 @@ msgstr "æµæ°´çº¿è®¡åˆ’"
msgid "Scope"
msgstr "范围"
-msgid "Scope not supported with disabled 'users_search' feature!"
-msgstr "范围内ä¸æ”¯æŒç¦ç”¨ users_search 功能ï¼"
-
msgid "Scoped issue boards"
msgstr "指定范围的议题看æ¿"
@@ -21599,9 +22384,6 @@ msgstr "æœç´¢é¡¹ç›®..."
msgid "Search requirements"
msgstr "æœç´¢éœ€æ±‚"
-msgid "Search results…"
-msgstr "æœç´¢ç»“果…"
-
msgid "Search users"
msgstr "æœç´¢ç”¨æˆ·"
@@ -21671,6 +22453,10 @@ msgid "SearchResults|commit"
msgid_plural "SearchResults|commits"
msgstr[0] "æ交"
+msgid "SearchResults|epic"
+msgid_plural "SearchResults|epics"
+msgstr[0] ""
+
msgid "SearchResults|issue"
msgid_plural "SearchResults|issues"
msgstr[0] "议题"
@@ -21708,11 +22494,11 @@ msgstr "座ä½é“¾æŽ¥"
msgid "Seat Link is disabled, and cannot be configured through this form."
msgstr "座ä½é“¾æŽ¥å·²ç¦ç”¨ï¼Œæ— æ³•é€šè¿‡æ­¤è¡¨å•è¿›è¡Œé…置。"
-msgid "Seats currently in use"
-msgstr "当å‰æ­£åœ¨ä½¿ç”¨çš„用户数é‡"
+msgid "Seats usage data as of %{last_enqueue_time}"
+msgstr ""
-msgid "Seats in license"
-msgstr "许å¯è¯ç”¨æˆ·æ•°é‡"
+msgid "Seats usage data is updated every day at 12:00pm UTC"
+msgstr ""
msgid "Secondary"
msgstr "次è¦"
@@ -21765,6 +22551,9 @@ msgstr "创建åˆå¹¶è¯·æ±‚时出错。"
msgid "SecurityConfiguration|Available for on-demand DAST"
msgstr ""
+msgid "SecurityConfiguration|By default, all analyzers are applied in order to cover all languages across your project, and only run if the language is detected in the Merge Request."
+msgstr ""
+
msgid "SecurityConfiguration|Configure"
msgstr "é…ç½®"
@@ -21795,18 +22584,21 @@ msgstr "%{featureName}的功能文档"
msgid "SecurityConfiguration|Manage"
msgstr "管ç†"
+msgid "SecurityConfiguration|More information"
+msgstr ""
+
msgid "SecurityConfiguration|Not enabled"
msgstr "未å¯ç”¨"
+msgid "SecurityConfiguration|SAST Analyzers"
+msgstr ""
+
msgid "SecurityConfiguration|SAST Configuration"
msgstr ""
msgid "SecurityConfiguration|Security Control"
msgstr "安全控制"
-msgid "SecurityConfiguration|See documentation"
-msgstr "查看文档"
-
msgid "SecurityConfiguration|Status"
msgstr "状æ€"
@@ -21816,6 +22608,9 @@ msgstr "测试与åˆè§„"
msgid "SecurityConfiguration|Using custom settings. You won't receive automatic updates on this variable. %{anchorStart}Restore to default%{anchorEnd}"
msgstr "使用自定义设置。您ä¸ä¼šæ”¶åˆ°æ­¤å˜é‡çš„自动更新。 %{anchorStart}还原到默认%{anchorEnd}"
+msgid "SecurityConfiguration|View history"
+msgstr ""
+
msgid "SecurityConfiguration|You can quickly enable all security scanning tools by enabling %{linkStart}Auto DevOps%{linkEnd}."
msgstr "您å¯ä»¥é€šè¿‡å¯ç”¨%{linkStart}Auto DevOps%{linkEnd}æ¥å¿«é€Ÿå¯ç”¨æ‰€æœ‰å®‰å…¨æ‰«æ工具。"
@@ -21894,9 +22689,6 @@ msgstr ""
msgid "SecurityReports|Learn more about setting up your dashboard"
msgstr "了解更多关于仪表æ¿åˆ›å»ºçš„ä¿¡æ¯"
-msgid "SecurityReports|Load more vulnerabilities"
-msgstr "加载更多æ¼æ´ž"
-
msgid "SecurityReports|Monitor vulnerabilities in your code"
msgstr "监控代ç ä¸­çš„æ¼æ´ž"
@@ -22176,8 +22968,8 @@ msgstr "选择开始日期"
msgid "Select status"
msgstr "选择状æ€"
-msgid "Select strategy activation method"
-msgstr "选择策略激活方å¼"
+msgid "Select strategy activation method."
+msgstr ""
msgid "Select subscription"
msgstr "选择订阅"
@@ -22191,8 +22983,8 @@ msgstr "选择当å‰é¡¹ç›®çš„默认分支。除éžå¦è¡ŒæŒ‡å®šï¼Œå¦åˆ™æ‰€æœ‰åˆ
msgid "Select the custom project template source group."
msgstr "选择自定义项目模æ¿æºç¾¤ç»„。"
-msgid "Select timeframe"
-msgstr "选择时间范围"
+msgid "Select the environment scope for this feature flag."
+msgstr ""
msgid "Select timezone"
msgstr "选择时区"
@@ -22440,6 +23232,9 @@ msgstr "设置实例范围的模æ¿ä»“库"
msgid "Set iteration"
msgstr "设置迭代"
+msgid "Set limit to 0 to allow any file size."
+msgstr ""
+
msgid "Set max session time for web terminal."
msgstr "为Web终端设置最长会è¯æ—¶é—´ã€‚"
@@ -22518,11 +23313,14 @@ msgstr "自动设置一个%{type}的Runner"
msgid "Set up a %{type} Runner manually"
msgstr "手动设置%{type} Runner "
+msgid "Set up a hardware device as a second factor to sign in."
+msgstr ""
+
msgid "Set up assertions/attributes/claims (email, first_name, last_name) and NameID according to %{docsLinkStart}the documentation %{icon}%{docsLinkEnd}"
msgstr "æ ¹æ®%{docsLinkStart}文档%{icon}%{docsLinkEnd}设置断言/属性/声明(email,first_name,last_name)和NameID"
-msgid "Set up new U2F device"
-msgstr "设置新的U2F设备"
+msgid "Set up new device"
+msgstr ""
msgid "Set up new password"
msgstr "设置新密ç "
@@ -22590,6 +23388,9 @@ msgstr "将时间估计设置为 %{time_estimate}。"
msgid "Sets weight to %{weight}."
msgstr "å°†æƒé‡è®¾ç½®ä¸º %{weight}。"
+msgid "Setting this to 0 means using the system default timeout value."
+msgstr ""
+
msgid "Settings"
msgstr "设置"
@@ -22605,6 +23406,15 @@ msgstr "设置"
msgid "Severity"
msgstr "严é‡ç¨‹åº¦"
+msgid "SeverityWidget|Severity"
+msgstr ""
+
+msgid "SeverityWidget|Severity: %{severity}"
+msgstr ""
+
+msgid "SeverityWidget|There was an error while updating severity."
+msgstr ""
+
msgid "Shards (%{shards})"
msgstr "分片(%{shards})"
@@ -22650,6 +23460,9 @@ msgstr "显示所有æˆå‘˜"
msgid "Show all requirements."
msgstr "显示所有需求。"
+msgid "Show all test cases."
+msgstr ""
+
msgid "Show archived projects"
msgstr "显示已归档的项目"
@@ -22662,6 +23475,9 @@ msgstr "显示相关命令"
msgid "Show comments"
msgstr "显示评论"
+msgid "Show comments on this file"
+msgstr ""
+
msgid "Show comments only"
msgstr "仅显示评论"
@@ -22707,6 +23523,12 @@ msgstr "查看上级页é¢"
msgid "Show parent subgroups"
msgstr "查看上级å­ç¾¤ç»„"
+msgid "Show the Closed list"
+msgstr ""
+
+msgid "Show the Open list"
+msgstr ""
+
msgid "Show whitespace changes"
msgstr "显示空白å˜æ›´å†…容"
@@ -22748,9 +23570,6 @@ msgstr "并排"
msgid "Sidebar|Assign health status"
msgstr "指定å¥åº·çŠ¶æ€"
-msgid "Sidebar|Change weight"
-msgstr "编辑æƒé‡"
-
msgid "Sidebar|Health status"
msgstr "å¥åº·çŠ¶æ€"
@@ -22934,6 +23753,9 @@ msgstr "没有è¦æ˜¾ç¤ºçš„代ç ç‰‡æ®µã€‚"
msgid "Snippets|Add another file %{num}/%{total}"
msgstr ""
+msgid "Snippets|Authored %{time_ago} by %{author}"
+msgstr ""
+
msgid "Snippets|Delete file"
msgstr ""
@@ -22961,6 +23783,9 @@ msgstr "Snowplow"
msgid "Solution"
msgstr "解决方案"
+msgid "Some changes are not shown"
+msgstr ""
+
msgid "Some child epics may be hidden due to applied filters"
msgstr "æŸäº›å­å²è¯—å¯èƒ½ç”±äºŽåº”用过滤器而被éšè—"
@@ -23327,6 +24152,12 @@ msgstr "æº"
msgid "Source (branch or tag)"
msgstr "æº(分支或标签)"
+msgid "Source Branch"
+msgstr ""
+
+msgid "Source branch: %{source_branch_open}%{source_branch}%{source_branch_close}"
+msgstr ""
+
msgid "Source code"
msgstr "æºä»£ç "
@@ -23492,9 +24323,6 @@ msgstr "å¯åŠ¨è¯„审"
msgid "Start and due date"
msgstr "开始和截止日期"
-msgid "Start by choosing a group to see how your team is spending time. You can then drill down to the project level."
-msgstr "选择一个群组,查看您的团队时间利用情况。然åŽï¼Œæ‚¨å¯ä»¥æ›´è¿›ä¸€æ­¥ï¼Œæ·±å…¥åˆ°é¡¹ç›®çº§åˆ«ã€‚"
-
msgid "Start by choosing a group to start exploring the merge requests in that group. You can then proceed to filter by projects, labels, milestones and authors."
msgstr "首先选择一个群组以开始æµè§ˆè¯¥ç¾¤ç»„中的åˆå¹¶è¯·æ±‚。然åŽæ‚¨å¯ä»¥æŒ‰é¡¹ç›®ã€æ ‡è®°ã€é‡Œç¨‹ç¢‘和作者进行过滤。"
@@ -23576,18 +24404,27 @@ msgstr "2. 添加æè¿°æ¥è§£é‡Šå˜æ›´çš„原因。"
msgid "StaticSiteEditor|3. Assign a person to review and accept the merge request."
msgstr "3. 指派用户审核并接å—åˆå¹¶è¯·æ±‚。"
+msgid "StaticSiteEditor|A link to view the merge request will appear once ready."
+msgstr ""
+
msgid "StaticSiteEditor|An error occurred while submitting your changes."
msgstr "æ交更改时å‘生错误。"
msgid "StaticSiteEditor|Branch could not be created."
msgstr "无法创建分支。"
+msgid "StaticSiteEditor|Copy update"
+msgstr ""
+
msgid "StaticSiteEditor|Could not commit the content changes."
msgstr "无法æ交内容更改。"
msgid "StaticSiteEditor|Could not create merge request."
msgstr "无法创建åˆå¹¶è¯·æ±‚。"
+msgid "StaticSiteEditor|Creating your merge request"
+msgstr ""
+
msgid "StaticSiteEditor|Incompatible file content"
msgstr "文件内容ä¸å…¼å®¹"
@@ -23609,6 +24446,9 @@ msgstr "更新%{sourcePath}文件"
msgid "StaticSiteEditor|View documentation"
msgstr "查看文档"
+msgid "StaticSiteEditor|You can set an assignee to get your changes reviewed and deployed once your merge request is created."
+msgstr ""
+
msgid "StaticSiteEditor|Your merge request has been created"
msgstr "您的åˆå¹¶è¯·æ±‚已创建"
@@ -23738,15 +24578,15 @@ msgstr "æ交"
msgid "Submit %{humanized_resource_name}"
msgstr "æ交%{humanized_resource_name}"
-msgid "Submit Changes"
-msgstr "æ交更改"
-
msgid "Submit a review"
msgstr "æ交评审"
msgid "Submit as spam"
msgstr "垃圾信æ¯ä¸¾æŠ¥"
+msgid "Submit changes"
+msgstr ""
+
msgid "Submit feedback"
msgstr "æ交å馈"
@@ -23900,6 +24740,9 @@ msgstr "å·²æˆåŠŸå†»ç»“"
msgid "Successfully deleted U2F device."
msgstr "æˆåŠŸåˆ é™¤ U2F 设备。"
+msgid "Successfully deleted WebAuthn device."
+msgstr ""
+
msgid "Successfully removed email."
msgstr "æˆåŠŸåˆ é™¤ç”µå­é‚®ä»¶ã€‚"
@@ -24218,9 +25061,6 @@ msgstr "模æ¿"
msgid "Template to append to all Service Desk issues"
msgstr "附加到所有æœåŠ¡å°ç”Ÿæˆè®®é¢˜çš„模æ¿"
-msgid "Template was successfully saved."
-msgstr "模æ¿å·²æˆåŠŸä¿å­˜ã€‚"
-
msgid "Templates"
msgstr "模æ¿"
@@ -24296,11 +25136,29 @@ msgid "Test coverage: %d hit"
msgid_plural "Test coverage: %d hits"
msgstr[0] "测试覆盖率: %d次命中"
-msgid "Test failed."
-msgstr "测试失败。"
+msgid "Test settings"
+msgstr ""
+
+msgid "TestCases|New Test Case"
+msgstr ""
+
+msgid "TestCases|New test case"
+msgstr ""
+
+msgid "TestCases|Search test cases"
+msgstr ""
+
+msgid "TestCases|Something went wrong while creating a test case."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching count of test cases."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching test cases list."
+msgstr ""
-msgid "Test settings and save changes"
-msgstr "测试设置并ä¿å­˜ä¿®æ”¹"
+msgid "TestCases|Submit test case"
+msgstr ""
msgid "TestHooks|Ensure one of your projects has merge requests."
msgstr "ç¡®ä¿æ‚¨çš„任一项目中有åˆå¹¶è¯·æ±‚。"
@@ -24365,6 +25223,9 @@ msgstr "测试"
msgid "Thank you for signing up for your free trial! You will get additional instructions in your inbox shortly."
msgstr "感谢您注册å…费试用版ï¼éšåŽæ‚¨å°†æ”¶åˆ°æœ‰å…³å®‰è£…使用指å—的邮件。"
+msgid "Thank you for your business."
+msgstr ""
+
msgid "Thank you for your feedback!"
msgstr "感谢您的å馈ï¼"
@@ -24423,9 +25284,6 @@ msgstr "在主节点上定义的URL,次è¦èŠ‚点应使用该URL与其è”系。
msgid "The URL to use for connecting to Elasticsearch. Use a comma-separated list to support clustering (e.g., \"http://localhost:9200, http://localhost:9201\")."
msgstr "用于连接到Elasticsearchçš„URL。使用逗å·åˆ†éš”的列表æ¥æ”¯æŒç¾¤é›†(例如,“http://localhost:9200, http://localhost:9201â€)。"
-msgid "The Web IDE offers advanced syntax highlighting capabilities and more."
-msgstr ""
-
msgid "The X509 Certificate to use when mutual TLS is required to communicate with the external authorization service. If left blank, the server certificate is still validated when accessing over HTTPS."
msgstr "在需è¦ç›¸äº’ TLS 与外部授æƒæœåŠ¡é€šä¿¡æ—¶ä½¿ç”¨çš„ X509 è¯ä¹¦ã€‚如果ä¿ç•™ä¸ºç©º, 则在访问 HTTPS æ—¶ä»ç„¶éªŒè¯æœåŠ¡å™¨è¯ä¹¦ã€‚"
@@ -24535,6 +25393,9 @@ msgstr "派生关系已被删除。"
msgid "The form contains the following error:"
msgstr "表å•åŒ…å«ä»¥ä¸‹é”™è¯¯ï¼š"
+msgid "The form contains the following warning:"
+msgstr ""
+
msgid "The global settings require you to enable Two-Factor Authentication for your account."
msgstr "系统设置è¦æ±‚您为å¸æˆ·å¯ç”¨åŒé‡è®¤è¯ã€‚"
@@ -24649,9 +25510,6 @@ msgstr "计划阶段概述了从议题添加到日程到推é€é¦–次æ交的时
msgid "The private key to use when a client certificate is provided. This value is encrypted at rest."
msgstr "æ供客户端è¯ä¹¦æ—¶ä½¿ç”¨çš„ç§é’¥ã€‚该值被加密存储。"
-msgid "The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr "生产阶段概述了从创建一个议题到将代ç éƒ¨ç½²åˆ°ç”Ÿäº§çŽ¯å¢ƒçš„总时间。当完æˆæƒ³æ³•åˆ°éƒ¨ç½²ç”Ÿäº§çš„循环,数æ®å°†è‡ªåŠ¨æ·»åŠ åˆ°æ­¤å¤„。"
-
msgid "The project can be accessed by any logged in user."
msgstr "该项目å…许所有已登录到当å‰GitLabæœåŠ¡å™¨çš„用户访问。"
@@ -24688,8 +25546,8 @@ msgstr "远程仓库镜åƒè¶…时未完æˆã€‚"
msgid "The remote repository is being updated..."
msgstr "远程仓库正在更新......"
-msgid "The repository can be commited to, and issues, comments and other entities can be created."
-msgstr "代ç å¯æ交到仓库,也å¯åˆ›å»ºæ–°çš„议题,评论和其他对象。"
+msgid "The repository can be committed to, and issues, comments and other entities can be created."
+msgstr ""
msgid "The repository for this project does not exist."
msgstr "此项目的仓库ä¸å­˜åœ¨ã€‚"
@@ -24742,9 +25600,6 @@ msgstr "测试阶段概述了 GitLab CI 为相关åˆå¹¶è¯·æ±‚è¿è¡Œæ¯ä¸ªæµæ°´ç
msgid "The time taken by each data entry gathered by that stage."
msgstr "该阶段æ¯æ¡æ•°æ®æ‰€èŠ±çš„时间"
-msgid "The total stage shows the time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr "总体阶段概述了从创建一个议题到将代ç éƒ¨ç½²åˆ°ç”Ÿäº§çŽ¯å¢ƒçš„时间。当完æˆæƒ³æ³•åˆ°éƒ¨ç½²ç”Ÿäº§çš„循环,数æ®å°†è‡ªåŠ¨æ·»åŠ åˆ°æ­¤å¤„。"
-
msgid "The update action will time out after %{number_of_minutes} minutes. For big repositories, use a clone/push combination."
msgstr "æ›´æ–°æ“作将在 %{number_of_minutes} 分钟åŽè¶…时。对于大型仓库,请使用clone/push组åˆã€‚"
@@ -24808,6 +25663,9 @@ msgstr "当å‰å°šæ— å·²å½’档的项目"
msgid "There are no archived requirements"
msgstr "没有已归档的需求"
+msgid "There are no archived test cases"
+msgstr ""
+
msgid "There are no changes"
msgstr "没有å˜åŒ–"
@@ -24847,6 +25705,9 @@ msgstr "没有未关闭的åˆå¹¶è¯·æ±‚"
msgid "There are no open requirements"
msgstr "没有开å¯çš„需求"
+msgid "There are no open test cases"
+msgstr ""
+
msgid "There are no packages yet"
msgstr "还没有包"
@@ -24859,6 +25720,9 @@ msgstr "还没有å˜é‡ã€‚"
msgid "There is a limit of %{ci_project_subscriptions_limit} subscriptions from or to a project."
msgstr "项目的订阅和被订阅数é‡ä¸Šé™ä¸º%{ci_project_subscriptions_limit}。"
+msgid "There is already a To-Do for this design."
+msgstr ""
+
msgid "There is already a repository with that name on disk"
msgstr "ç£ç›˜ä¸Šå·²å­˜åœ¨å…·æœ‰è¯¥å称的仓库"
@@ -24877,6 +25741,9 @@ msgstr "æ•°æ®å¤ªå¤šæ— æ³•è®¡ç®—。请更改您的选择。"
msgid "There was a problem communicating with your device."
msgstr "与您的设备通信时出现问题。"
+msgid "There was a problem fetching branches."
+msgstr ""
+
msgid "There was a problem fetching groups."
msgstr "获å–群组时出现问题。"
@@ -25079,7 +25946,7 @@ msgid "This %{issuable} is locked. Only %{strong_open}project members%{strong_cl
msgstr "æ­¤%{issuable}已被é”定。åªæœ‰%{strong_open}项目æˆå‘˜%{strong_close}æ‰å¯ä»¥å‘表评论。"
msgid "This %{noteableTypeText} is %{confidentialLinkStart}confidential%{linkEnd} and %{lockedLinkStart}locked%{linkEnd}."
-msgstr "æ­¤%{noteableTypeText}为%{confidentialLinkStart}机密的%{linkEnd}且%{lockedLinkStart}é”定的%{linkEnd}。"
+msgstr "æ­¤%{noteableTypeText}为%{confidentialLinkStart}ç§å¯†çš„%{linkEnd}且%{lockedLinkStart}é”定的%{linkEnd}。"
msgid "This %{noteableTypeText} is locked."
msgstr "æ­¤%{noteableTypeText}å·²é”定。"
@@ -25105,9 +25972,15 @@ msgstr "æ­¤URLå·²ç»ç”¨äºŽå¦ä¸€ä¸ªé“¾æŽ¥ï¼›ä¸å…许é‡å¤ URL"
msgid "This action can lead to data loss. To prevent accidental actions we ask you to confirm your intention."
msgstr "æ­¤æ“作å¯èƒ½å¯¼è‡´æ•°æ®ä¸¢å¤±ã€‚为防止æ„外,我们会è¦æ±‚您确认您的æ“作。"
+msgid "This action cannot be undone, and will permanently delete the %{key} SSH key"
+msgstr ""
+
msgid "This action cannot be undone. You will lose the project's repository and all content: issues, merge requests, etc."
msgstr ""
+msgid "This action has been performed too many times. Try again later."
+msgstr ""
+
msgid "This action will %{strongOpen}permanently delete%{strongClose} %{codeOpen}%{project}%{codeClose} %{strongOpen}immediately%{strongClose}, including its repositories and all content: issues, merge requests, etc."
msgstr "æ­¤æ“作将%{strongOpen}ç«‹å³%{strongClose}%{strongOpen}永久删除%{strongClose}%{codeOpen}%{project}%{codeClose},包括其仓库åŠæ‰€æœ‰å†…容:议题,åˆå¹¶è¯·æ±‚等。"
@@ -25135,9 +26008,6 @@ msgstr "该阻塞为自我引用"
msgid "This board's scope is reduced"
msgstr "此看æ¿èŒƒå›´ç¼©å°äº†"
-msgid "This branch has changed since you started editing. Would you like to create a new branch?"
-msgstr "自您开始编辑åŽ, 此分支已更改。您想创建一个新的分支å—?"
-
msgid "This chart could not be displayed"
msgstr "无法显示此图表"
@@ -25253,7 +26123,7 @@ msgid "This is a Premium feature"
msgstr "这是高级版的功能"
msgid "This is a confidential %{noteableTypeText}."
-msgstr "这是一个机密%{noteableTypeText}。"
+msgstr "这是一个ç§å¯†%{noteableTypeText}。"
msgid "This is a delayed job to run in %{remainingTime}"
msgstr "这是一个将在%{remainingTime}åŽè¿è¡Œçš„延时作业。"
@@ -25264,15 +26134,9 @@ msgstr "这是已登录到您å¸æˆ·çš„设备列表。您å¯ä»¥åˆ é™¤ä»»ä½•æ‚¨æ— 
msgid "This is a security log of important events involving your account."
msgstr "这是一个涉åŠæ‚¨çš„å¸æˆ·é‡è¦äº‹ä»¶çš„安全日志。"
-msgid "This is the author's first Merge Request to this project."
-msgstr "这是作者为当å‰é¡¹ç›®è´¡çŒ®çš„第一个åˆå¹¶è¯·æ±‚。"
-
msgid "This is the highest peak of users on your installation since the license started."
msgstr "此数字为自许å¯è¯å¯åŠ¨ä»¥æ¥ç”¨æˆ·æ•°ç›®çš„最高值。"
-msgid "This is the maximum number of users that have existed at the same time since the license started. This is the minimum number of seats you will need to buy when you renew your license."
-msgstr "这是自许å¯è¯å¯ç”¨ä»¥æ¥åŒæ—¶å­˜åœ¨çš„最大用户数。续订许å¯è¯æ—¶ï¼Œæ‚¨æœ€å°‘需è¦è´­ä¹°æ­¤æ•°é‡çš„用户数。"
-
msgid "This is the number of currently active users on your installation, and this is the minimum number you need to purchase when you renew your license."
msgstr "此数目为当å‰æ´»è·ƒç”¨æˆ·çš„æ•°é‡ï¼Œ 也是更新许å¯è¯æ—¶éœ€è¦è´­ä¹°çš„最低数é‡ã€‚"
@@ -25382,7 +26246,7 @@ msgid "This link points to external content"
msgstr "此链接指å‘外部内容"
msgid "This may expose confidential information as the selected fork is in another namespace that can have other members."
-msgstr "æ­¤æ“作å¯èƒ½ä¼šæ³„æ¼æœºå¯†ä¿¡æ¯ï¼Œå› ä¸ºé€‰å®šçš„派生ä½äºŽå¦ä¸€ä¸ªå字空间中,å¯èƒ½åŒ…å«å…¶ä»–æˆå‘˜ã€‚"
+msgstr "æ­¤æ“作å¯èƒ½ä¼šæ³„æ¼ç§å¯†ä¿¡æ¯ï¼Œå› ä¸ºé€‰å®šçš„派生ä½äºŽå¦ä¸€ä¸ªå字空间中,å¯èƒ½åŒ…å«å…¶ä»–æˆå‘˜ã€‚"
msgid "This means you can not push code until you create an empty repository or import existing one."
msgstr "在创建一个空的仓库或导入现有仓库之å‰ï¼Œå°†æ— æ³•æŽ¨é€ä»£ç ã€‚"
@@ -25504,6 +26368,15 @@ msgstr "此用户没有有效的%{type}。"
msgid "This user has no identities"
msgstr "该用户无身份标识"
+msgid "This user has previously committed to the %{name} project."
+msgstr ""
+
+msgid "This user has the %{access} role in the %{name} project."
+msgstr ""
+
+msgid "This user is the author of this %{noteable}."
+msgstr ""
+
msgid "This user will be the author of all events in the activity feed that are the result of an update, like new branches being created or new commits being pushed to existing branches."
msgstr "此用户将æˆä¸ºæ´»åŠ¨æµä¸­æ‰€æœ‰äº‹ä»¶çš„作者,例如创建新分支或者推é€æ–°æ交到现有分支。"
@@ -25534,6 +26407,9 @@ msgstr "找ä¸åˆ°è¦å›žå¤çš„主题"
msgid "Threat Monitoring"
msgstr "å¨èƒç›‘测"
+msgid "ThreatMonitoring|All Environments"
+msgstr ""
+
msgid "ThreatMonitoring|Anomalous Requests"
msgstr "异常请求"
@@ -25561,9 +26437,6 @@ msgstr "未检测到环境"
msgid "ThreatMonitoring|Operations Per Second"
msgstr "æ¯ç§’æ“作数"
-msgid "ThreatMonitoring|Overview"
-msgstr "概览"
-
msgid "ThreatMonitoring|Packet Activity"
msgstr "æ•°æ®åŒ…活动"
@@ -25582,6 +26455,9 @@ msgstr "出现错误,无法获å–环境"
msgid "ThreatMonitoring|Something went wrong, unable to fetch statistics"
msgstr "出现错误,无法获å–统计信æ¯"
+msgid "ThreatMonitoring|Statistics"
+msgstr ""
+
msgid "ThreatMonitoring|The firewall is not installed or has been disabled. To view this data, ensure the web application firewall is installed and enabled for your cluster."
msgstr "防ç«å¢™å°šæœªå®‰è£…或已被ç¦ç”¨ã€‚è¦æŸ¥çœ‹æ­¤æ•°æ®ï¼Œè¯·ç¡®ä¿å®‰è£…网络应用防ç«å¢™å¹¶ä¸ºæ‚¨çš„集群å¯ç”¨ã€‚"
@@ -25930,10 +26806,10 @@ msgid "To preserve performance only %{strong_open}%{display_size} of %{real_size
msgstr "为了ä¿è¯æ€§èƒ½ï¼Œä»…显示文件中的总计%{strong_open}%{real_size}中的%{display_size}%{strong_close}。"
msgid "To protect this issue's confidentiality, %{forkLink} and set the fork's visibility to private."
-msgstr "为了ä¿è¯æ­¤è®®é¢˜çš„机密性,%{forkLink}并将派生项目的å¯è§æ€§è®¾ç½®ä¸ºç§æœ‰ã€‚"
+msgstr "为了ä¿è¯æ­¤è®®é¢˜çš„ç§å¯†æ€§ï¼Œ%{forkLink}并将派生项目的å¯è§æ€§è®¾ç½®ä¸ºç§æœ‰ã€‚"
msgid "To protect this issue's confidentiality, a private fork of this project was selected."
-msgstr "为了ä¿è¯æ­¤è®®é¢˜çš„机密性,选择了该项目的ç§æœ‰æ´¾ç”Ÿã€‚"
+msgstr "为了ä¿è¯æ­¤è®®é¢˜çš„ç§å¯†æ€§ï¼Œé€‰æ‹©äº†è¯¥é¡¹ç›®çš„ç§æœ‰æ´¾ç”Ÿã€‚"
msgid "To receive alerts from manually configured Prometheus services, add the following URL and Authorization key to your Prometheus webhook config file. Learn more about %{linkStart}configuring Prometheus%{linkEnd} to send alerts to GitLab."
msgstr "è¦ä»Žæ‰‹åŠ¨é…置的PrometheusæœåŠ¡æŽ¥æ”¶è­¦æŠ¥ï¼Œè¯·å°†ä»¥ä¸‹URL和授æƒå¯†é’¥æ·»åŠ åˆ°Prometheus webhooké…置文件中。了解更多关于 %{linkStart}é…ç½®Prometheus%{linkEnd} 将警报å‘é€åˆ°GitLab。"
@@ -25971,6 +26847,9 @@ msgstr "è‹¥è¦é€€è®¢æ­¤é—®é¢˜ï¼Œè¯·å°†ä»¥ä¸‹é“¾æŽ¥ç²˜è´´åˆ°æ‚¨çš„æµè§ˆå™¨ï¼š"
msgid "To update Snippets with multiple files, you must use the `files` parameter"
msgstr ""
+msgid "To use Gitpod you must first enable the feature in the integrations section of your %{user_prefs}."
+msgstr ""
+
msgid "To view all %{scannedResourcesCount} scanned URLs, please download the CSV file"
msgstr "è¦æŸ¥çœ‹æ‰€æœ‰%{scannedResourcesCount}已扫æçš„URL,请下载CSV文件"
@@ -26004,9 +26883,6 @@ msgstr "切æ¢Markdown预览"
msgid "Toggle Sidebar"
msgstr "切æ¢ä¾§è¾¹æ "
-msgid "Toggle all threads"
-msgstr "开关所有主题"
-
msgid "Toggle backtrace"
msgstr "切æ¢è°ƒç”¨æ ˆå›žæº¯(backtrace)"
@@ -26031,9 +26907,6 @@ msgstr "切æ¢è¡¨æƒ…符å·èµžèµ"
msgid "Toggle navigation"
msgstr "切æ¢å¯¼èˆª"
-msgid "Toggle project"
-msgstr "切æ¢é¡¹ç›®"
-
msgid "Toggle sidebar"
msgstr "切æ¢è¾¹æ "
@@ -26073,6 +26946,9 @@ msgstr "å¯ç”¨äº†å¤ªå¤šçš„命å空间。您需è¦é€šè¿‡æŽ§åˆ¶å°æˆ–APIæ¥ç®¡ç†
msgid "Too many projects enabled. You will need to manage them via the console or the API."
msgstr "å¯ç”¨äº†å¤ªå¤šçš„项目。您需è¦é€šè¿‡æŽ§åˆ¶å°æˆ–APIæ¥ç®¡ç†å®ƒä»¬ã€‚"
+msgid "Too much data"
+msgstr ""
+
msgid "Topics (optional)"
msgstr "主题(å¯é€‰)"
@@ -26091,6 +26967,9 @@ msgstr "所有产物大å°ï¼š %{total_size}"
msgid "Total cores (CPUs)"
msgstr "总核心(CPU)"
+msgid "Total days to completion"
+msgstr ""
+
msgid "Total issues"
msgstr "总议题数"
@@ -26187,6 +27066,9 @@ msgstr "树形视图"
msgid "Trending"
msgstr "热门"
+msgid "Trials|Create a new group to start your GitLab Gold trial."
+msgstr ""
+
msgid "Trials|Go back to GitLab"
msgstr "返回GitLab"
@@ -26196,6 +27078,15 @@ msgstr "跳过试用(继续使用å…è´¹å¸æˆ·)"
msgid "Trials|You can always resume this process by selecting your avatar and choosing 'Start a Gold trial'"
msgstr "您å¯ä»¥é€šè¿‡ç‚¹å‡»æ‚¨çš„头åƒå’Œé€‰æ‹©â€œå¼€å§‹é‡‘牌试用â€æ¥æ¢å¤æ­¤è¿›ç¨‹ã€‚"
+msgid "Trials|You can apply your trial to a new group or an existing group."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group or your personal account."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group, an existing group, or your personal account."
+msgstr ""
+
msgid "Trials|You won't get a free trial right now but you can always resume this process by clicking on your avatar and choosing 'Start a free trial'"
msgstr "您现在ä¸ä¼šèŽ·å¾—å…费试用,但以åŽå¯ä»¥éšæ—¶ç‚¹å‡»å¤´åƒå¹¶é€‰æ‹©â€œå¼€å§‹å…费试用â€æ¥ç»§ç»­æ­¤æµç¨‹ã€‚"
@@ -26265,6 +27156,9 @@ msgstr "请将第一行ä¿æŒåœ¨52个字符以内,其他行ä¿æŒåœ¨72个字ç¬
msgid "Try using a different search term to find the file you are looking for."
msgstr "å°è¯•ä½¿ç”¨ä¸åŒçš„æœç´¢è¯æŸ¥æ‰¾ä½ æƒ³è¦çš„文件。"
+msgid "Trying to communicate with your device. Plug it in (if needed) and press the button on the device now."
+msgstr ""
+
msgid "Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now."
msgstr "å°è¯•ä¸Žæ‚¨çš„设备通信。请将其æ’入并立å³æŒ‰ä¸‹ä¸Šçš„按钮。"
@@ -26352,6 +27246,12 @@ msgstr "外部存储网å€å°†å­˜å‚¨ä»“库的é™æ€å¯¹è±¡ (例如,档案,åšå
msgid "URL or request ID"
msgstr "URL或请求ID"
+msgid "USER %{user} WILL BE REMOVED! Are you sure?"
+msgstr ""
+
+msgid "USER WILL BE BLOCKED! Are you sure?"
+msgstr ""
+
msgid "UTC"
msgstr "国际标准时间"
@@ -26409,9 +27309,6 @@ msgstr "无法加载差异。 %{button_try_again}"
msgid "Unable to load the merge request widget. Try reloading the page."
msgstr "无法加载åˆå¹¶è¯·æ±‚部件。请å°è¯•é‡æ–°åŠ è½½é¡µé¢ã€‚"
-msgid "Unable to resolve"
-msgstr "无法解决"
-
msgid "Unable to save iteration. Please try again"
msgstr "无法ä¿å­˜è¿­ä»£ã€‚请é‡è¯•"
@@ -26460,6 +27357,9 @@ msgstr "撤销忽略"
msgid "Undo ignore"
msgstr "撤销忽略"
+msgid "Unexpected error"
+msgstr ""
+
msgid "Unfortunately, your email message to GitLab could not be processed."
msgstr "很é—憾,您å‘é€ç»™GitLab的电å­é‚®ä»¶æ— æ³•å¤„ç†ã€‚"
@@ -26493,6 +27393,9 @@ msgstr "未知的格å¼"
msgid "Unknown response text"
msgstr "未知的å“应文本"
+msgid "Unless otherwise agreed to in writing with GitLab, by clicking \"Upload License\" you agree that your use of GitLab Software is subject to the %{eula_link_start}Terms of Service%{eula_link_end}."
+msgstr ""
+
msgid "Unlimited"
msgstr "æ— é™"
@@ -26859,9 +27762,6 @@ msgstr "使用 %{code_start}::%{code_end} 创建 %{link_start}有范围标签集
msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
msgstr "在GitLab内部使用æœåŠ¡å°é€šè¿‡ç”µå­é‚®ä»¶ä¸Žç”¨æˆ·è”系(例如æ供客户支æŒï¼‰"
-msgid "Use a hardware device to add the second factor of authentication."
-msgstr "使用硬件设备添加第二个身份验è¯å› ç´ ã€‚"
-
msgid "Use an one time password authenticator on your mobile device or computer to enable two-factor authentication (2FA)."
msgstr "在您的手机或计算机上使用一次密ç éªŒè¯å™¨å¯ç”¨åŒé‡è®¤è¯ (2FA)。"
@@ -27135,15 +28035,15 @@ msgstr "用户å或邮箱"
msgid "Users"
msgstr "用户"
+msgid "Users in License"
+msgstr ""
+
msgid "Users in License:"
msgstr "许å¯è¯ä¸­çš„用户数:"
msgid "Users or groups set as approvers in the project's or merge request's settings."
msgstr "在项目或åˆå¹¶è¯·æ±‚的设置中设为审批人的用户或群组。"
-msgid "Users outside of license"
-msgstr "超出许å¯æ•°ç›®çš„用户"
-
msgid "Users over License:"
msgstr "超出许å¯è¯çš„用户数:"
@@ -27159,9 +28059,6 @@ msgstr "å·²æˆåŠŸæ·»åŠ ç”¨æˆ·ã€‚"
msgid "Users with a Guest role or those who don't belong to a Project or Group will not use a seat from your license."
msgstr ""
-msgid "Users with a Guest role or those who don't belong to any projects or groups don't count towards seats in use."
-msgstr "具有访客角色的用户或ä¸å±žäºŽä»»ä½•é¡¹ç›®æˆ–群组的用户将ä¸è®¡å…¥ä½¿ç”¨ä¸­çš„用户数é‡ã€‚"
-
msgid "UsersSelect|%{name} + %{length} more"
msgstr "%{name} + 其余%{length}ä½"
@@ -27201,9 +28098,6 @@ msgstr "验è¯æ‚¨çš„GitLab CIé…置文件"
msgid "Validations failed."
msgstr "验è¯å¤±è´¥ã€‚"
-msgid "Validity"
-msgstr "有效期"
-
msgid "Value"
msgstr "值"
@@ -27222,6 +28116,9 @@ msgstr "价值æµåˆ†æžæ¦‚述了项目从想法到产å“实现的å„阶段所需
msgid "Value Stream Name"
msgstr "价值æµå称"
+msgid "ValueStreamAnalyticsStage|We don't have enough data to show this stage."
+msgstr ""
+
msgid "ValueStreamAnalytics|%{days}d"
msgstr "%{days}天"
@@ -27476,6 +28373,9 @@ msgstr "评审"
msgid "VisualReviewApp|Steps 1 and 2 (and sometimes 3) are performed once by the developer before requesting feedback. Steps 3 (if necessary), 4 is performed by the reviewer each time they perform a review."
msgstr "步骤1å’Œ2(有时3)由开å‘者在请求å馈之å‰è¿›è¡Œä¸€æ¬¡ã€‚步骤3(å¿…è¦æ—¶)ã€4由审核者æ¯æ¬¡è¿›è¡Œå®¡æŸ¥æ—¶æ‰§è¡Œã€‚"
+msgid "Visualization"
+msgstr ""
+
msgid "Vulnerabilities"
msgstr "æ¼æ´ž"
@@ -27503,35 +28403,32 @@ msgstr "%{formattedStartDate}到今天"
msgid "VulnerabilityChart|Severity"
msgstr "严é‡çº§åˆ«"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
+msgstr ""
+
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
+msgstr ""
+
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
+msgstr ""
+
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
+msgstr ""
+
msgid "VulnerabilityManagement|A true-positive and will fix"
msgstr "真实æ¼æ´žå¹¶å°†ä¿®å¤"
msgid "VulnerabilityManagement|Change status"
msgstr "更改状æ€"
-msgid "VulnerabilityManagement|Confirm"
-msgstr "确认"
-
-msgid "VulnerabilityManagement|Confirmed %{timeago} by %{user}"
-msgstr "%{timeago}由%{user}确认"
-
msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
msgstr "无法处ç†%{issueReference}: %{errorMessage}。"
-msgid "VulnerabilityManagement|Detected %{timeago} in pipeline %{pipelineLink}"
-msgstr "%{timeago}在æµæ°´çº¿%{pipelineLink}中检测到"
-
-msgid "VulnerabilityManagement|Dismiss"
-msgstr "忽略"
-
-msgid "VulnerabilityManagement|Dismissed %{timeago} by %{user}"
-msgstr "%{timeago}由%{user}忽略"
-
-msgid "VulnerabilityManagement|Resolved"
-msgstr "已解决"
+msgid "VulnerabilityManagement|Detected"
+msgstr ""
-msgid "VulnerabilityManagement|Resolved %{timeago} by %{user}"
-msgstr "由%{user}解决于%{timeago}"
+msgid "VulnerabilityManagement|Needs triage"
+msgstr ""
msgid "VulnerabilityManagement|Something went wrong while trying to delete the comment. Please try again later."
msgstr "试图删除评论时出错。请ç¨åŽå†è¯•ã€‚"
@@ -27581,6 +28478,9 @@ msgstr "已解决"
msgid "Vulnerability|%{scannerName} (version %{scannerVersion})"
msgstr "%{scannerName} (版本 %{scannerVersion})"
+msgid "Vulnerability|Activity"
+msgstr ""
+
msgid "Vulnerability|Class"
msgstr "类型"
@@ -27593,6 +28493,9 @@ msgstr "崩溃地å€"
msgid "Vulnerability|Description"
msgstr "说明"
+msgid "Vulnerability|Detected"
+msgstr ""
+
msgid "Vulnerability|Evidence"
msgstr "è¯æ®"
@@ -27656,6 +28559,9 @@ msgstr "警告:"
msgid "Warning: Displaying this diagram might cause performance issues on this page."
msgstr "警告:显示此图表å¯èƒ½ä¼šå¼•èµ·é¡µé¢çš„性能问题。"
+msgid "We are currently unable to fetch data for the pipeline header."
+msgstr ""
+
msgid "We are currently unable to fetch data for this graph."
msgstr "我们目å‰æ— æ³•èŽ·å–此图表的数æ®ã€‚"
@@ -27695,6 +28601,12 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr "我们è¦ç¡®å®šæ‚¨æ˜¯ä¸æ˜¯æœºå™¨äººã€‚"
+msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
+msgstr ""
+
+msgid "We would like to inform you that your subscription GitLab Enterprise Edition %{plan_name} is nearing its user limit. You have %{active_user_count} active users, which is almost at the user limit of %{maximum_user_count}."
+msgstr ""
+
msgid "We've found no vulnerabilities"
msgstr "未å‘现安全æ¼æ´ž"
@@ -27710,6 +28622,12 @@ msgstr "Web终端"
msgid "Web terminal"
msgstr "Web终端"
+msgid "WebAuthn Devices (%{length})"
+msgstr ""
+
+msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
+msgstr ""
+
msgid "WebIDE|Merge request"
msgstr "åˆå¹¶è¯·æ±‚"
@@ -27848,15 +28766,9 @@ msgstr "欢迎使用GitLab,%{first_name}ï¼"
msgid "Welcome to the guided GitLab tour"
msgstr "欢迎æ¥åˆ°GitLab导览"
-msgid "Welcome to your Issue Board!"
-msgstr "欢迎使用议题看æ¿"
-
msgid "Welcome to your issue board!"
msgstr ""
-msgid "We’ve been making changes to %{featureName} and we’d love your feedback %{linkStart}in this issue%{linkEnd} to help us improve the experience."
-msgstr "我们一直在改进%{featureName}功能。我们欢迎您通过%{linkStart}此议题%{linkEnd}æä¾›å馈,以帮助我们改善用户体验。"
-
msgid "What are you searching for?"
msgstr "您正在æœç´¢ä»€ä¹ˆï¼Ÿ"
@@ -27875,6 +28787,9 @@ msgstr "当部署作业æˆåŠŸæ—¶ï¼Œè·³è¿‡ä»åœ¨ç­‰å¾…的旧部署作业"
msgid "When a runner is locked, it cannot be assigned to other projects"
msgstr "当Runner被é”定时,ä¸èƒ½å°†å…¶åˆ†é…给其他项目"
+msgid "When enabled, any user visiting %{host} and creating an account will have to be explicitly approved by the admin before they can login. This setting is effective only if sign-ups are enabled."
+msgstr ""
+
msgid "When enabled, any user visiting %{host} will be able to create an account."
msgstr "å¯ç”¨åŽï¼Œä»»ä½•è®¿é—®%{host}用户都å¯ä»¥åˆ›å»ºä¸€ä¸ªå¸æˆ·ã€‚"
@@ -28098,6 +29013,9 @@ msgstr "将部署到"
msgid "With requirements, you can set criteria to check your products against."
msgstr "æ过需求,您å¯ä»¥è®¾ç½®æ ‡å‡†æ¥æ£€æŸ¥æ‚¨çš„产å“。"
+msgid "With test cases, you can define conditions for your project to meet in determining quality"
+msgstr ""
+
msgid "Withdraw Access Request"
msgstr "å–消æƒé™ç”³è¯·"
@@ -28113,6 +29031,9 @@ msgstr "“进行中â€é™åˆ¶"
msgid "Workflow Help"
msgstr "工作æµå¸®åŠ©"
+msgid "Would you like to create a new branch?"
+msgstr ""
+
msgid "Write"
msgstr "编辑"
@@ -28134,6 +29055,9 @@ msgstr "编写å‘行说明(Release Notes) 或将文件拖动到此处..."
msgid "Wrong extern UID provided. Make sure Auth0 is configured correctly."
msgstr "æ供了错误的外部UID。请正确é…ç½®Auth0。"
+msgid "YYYY-MM-DD"
+msgstr ""
+
msgid "Yes"
msgstr "是"
@@ -28191,8 +29115,8 @@ msgstr ""
msgid "You are going to remove the fork relationship from %{project_full_name}. Are you ABSOLUTELY sure?"
msgstr "å³å°†åˆ é™¤ä¸Žæºé¡¹ç›®%{project_full_name}的派生关系。确定继续å—?"
-msgid "You are going to transfer %{project_full_name} to another owner. Are you ABSOLUTELY sure?"
-msgstr "å°†è¦æŠŠ %{project_full_name} 转移给å¦ä¸€ä¸ªæ‰€æœ‰è€…。确定执行此æ“作?"
+msgid "You are going to transfer %{project_full_name} to another namespace. Are you ABSOLUTELY sure?"
+msgstr ""
msgid "You are going to turn off the confidentiality. This means %{strongStart}everyone%{strongEnd} will be able to see and leave a comment on this %{issuableType}."
msgstr ""
@@ -28251,9 +29175,6 @@ msgstr "您还å¯ä»¥æŒ‰ç…§ä»¥ä¸‹è¯´æ˜Žä»Žè®¡ç®—机中上传现有文件。"
msgid "You can always edit this later"
msgstr "您也å¯ä»¥ç¨åŽç¼–辑此选项。"
-msgid "You can apply your Trial to your Personal account or create a New Group."
-msgstr "您å¯ä»¥åœ¨æ‚¨çš„个人å¸æˆ·è¯•ç”¨æˆ–创建新群组试用。"
-
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings"
msgstr "您å¯ä»¥åœ¨%{pat_link_start}个人访问令牌%{pat_link_end}设置中创建新的令牌或检查现有的令牌。"
@@ -28275,12 +29196,18 @@ msgstr "å¯ä»¥è½»æ¾åœ°åœ¨Kubernetes集群上安装Runner。 %{link_to_help_page
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr "您å¯ä»¥é€šè¿‡å•å‡»å›¾è¡¨ä¸­çš„列æ¥æŒ‰â€œåˆå¹¶å¤©æ•°â€è¿›è¡Œè¿‡æ»¤ã€‚"
+msgid "You can find more information about GitLab subscriptions in %{subscriptions_doc_link}."
+msgstr ""
+
msgid "You can generate an access token scoped to this project for each application to use the GitLab API."
msgstr "您å¯ä»¥ä¸ºæ¯ä¸ªåº”用程åºç”Ÿæˆé€‚用于此项目的访问令牌,以使用GitLab API。"
msgid "You can get started by cloning the repository or start adding files to it with one of the following options."
msgstr "您å¯ä»¥é€šè¿‡å…‹éš†ä»“库开始或开始以以下方å¼ä¹‹ä¸€æ·»åŠ æ–‡ä»¶ã€‚"
+msgid "You can group test cases using labels. To learn about the future direction of this feature, visit %{linkStart}Quality Management direction page%{linkEnd}."
+msgstr ""
+
msgid "You can invite a new member to %{project_name} or invite another group."
msgstr ""
@@ -28296,6 +29223,9 @@ msgstr "å¯ä»¥ä½¿ç”¨æ–¹å‘键移动图形。"
msgid "You can notify the app / group or a project by sending them an email notification"
msgstr "您å¯ä»¥é€šè¿‡ç”µå­é‚®ä»¶æ¥é€šçŸ¥åº”用程åº/群组或项目"
+msgid "You can now close this window."
+msgstr ""
+
msgid "You can now export your security dashboard to a CSV report."
msgstr "现在你å¯ä»¥å¯¼å‡ºå®‰å…¨ä»ªè¡¨æ¿åˆ°CSV报告。"
@@ -28344,9 +29274,6 @@ msgstr "您å¯ä»¥æŒ‡å®šæ¯ä¸ªç¾¤ç»„或æ¯ä¸ªé¡¹ç›®çš„通知级别。"
msgid "You can test your .gitlab-ci.yml in %{linkStart}CI Lint%{linkEnd}."
msgstr "您也å¯ä»¥é€šè¿‡%{linkStart}Lint%{linkEnd}测试.gitlab-ci.yml."
-msgid "You can try again using %{begin_link}basic search%{end_link}"
-msgstr "您å¯ä»¥ä½¿ç”¨%{begin_link}基本æœç´¢%{end_link}é‡æ–°å°è¯•"
-
msgid "You cannot access the raw file. Please wait a minute."
msgstr "您ä¸èƒ½è®¿é—®åŽŸå§‹æ–‡ä»¶ã€‚请ç¨å€™ã€‚"
@@ -28398,6 +29325,9 @@ msgstr "您没有更改LDAP组åŒæ­¥ä¸­è®¾ç½®çš„相应æƒé™ã€‚"
msgid "You don't have any U2F devices registered yet."
msgstr "您还没有注册任何U2F设备。"
+msgid "You don't have any WebAuthn devices registered yet."
+msgstr ""
+
msgid "You don't have any active chat names."
msgstr "您没有任何活动èŠå¤©ã€‚"
@@ -28485,6 +29415,9 @@ msgstr "你现在å¯ä»¥å…³é—­è¿™ä¸ªé‡Œç¨‹ç¢‘。"
msgid "You must accept our Terms of Service and privacy policy in order to register an account"
msgstr "您必须接å—我们的æœåŠ¡æ¡æ¬¾å’Œéšç§æ”¿ç­–æ‰èƒ½æ³¨å†Œå¸æˆ·"
+msgid "You must be logged in to search across all of GitLab"
+msgstr ""
+
msgid "You must disassociate %{domain} from all clusters it is attached to before deletion."
msgstr "删除å‰æ‚¨å¿…须将%{domain}从所有相关的集群中解除关è”。"
@@ -28524,8 +29457,8 @@ msgstr "需è¦ç›¸å…³çš„æƒé™ã€‚"
msgid "You need to be logged in."
msgstr "您必须先登录。"
-msgid "You need to register a two-factor authentication app before you can set up a U2F device."
-msgstr "在设置U2F设备之å‰ï¼Œæ‚¨éœ€è¦æ³¨å†ŒåŒé‡è®¤è¯åº”用程åºã€‚"
+msgid "You need to register a two-factor authentication app before you can set up a device."
+msgstr ""
msgid "You need to set terms to be enforced"
msgstr "您需è¦å°†æ¡æ¬¾è®¾ä¸ºå¼ºåˆ¶"
@@ -28542,6 +29475,9 @@ msgstr "您需è¦ä¸Šä¼ Google Takeout文件。"
msgid "You reached %{usage_in_percent} of %{namespace_name}'s storage capacity (%{used_storage} of %{storage_limit})"
msgstr "你已使用了%{usage_in_percent}çš„%{namespace_name}存储容é‡(已使用%{storage_limit}总计%{used_storage})"
+msgid "You successfully declined the invitation"
+msgstr ""
+
msgid "You tried to fork %{link_to_the_project} but it failed for the following reason:"
msgstr "您å°è¯•æ´¾ç”Ÿ %{link_to_the_project} 但由于以下原因导致失败:"
@@ -28642,7 +29578,7 @@ msgid "YouTube"
msgstr "YouTube"
msgid "Your %{host} account was signed in to from a new location"
-msgstr "您%{host}上的å¸æˆ·å·²ä»Žä¸€ä¸ªæ–°çš„ä½ç½®ç™»å½•"
+msgstr "您在%{host}上的å¸æˆ·å·²ä»Žä¸€ä¸ªæ–°çš„ä½ç½®ç™»å½•"
msgid "Your %{strong}%{plan_name}%{strong_close} subscription for %{strong}%{namespace_name}%{strong_close} will expire on %{strong}%{expires_on}%{strong_close}."
msgstr "您为%{strong}%{namespace_name}%{strong_close}的%{strong}%{plan_name}%{strong_close}订阅将于%{strong}%{expires_on}%{strong_close}到期。"
@@ -28707,12 +29643,15 @@ msgstr "您的待办事项列表"
msgid "Your U2F device did not send a valid JSON response."
msgstr "您的 U2F 设备没有å‘é€æœ‰æ•ˆçš„ JSON å“应。"
-msgid "Your U2F device needs to be set up. Plug it in (if not already) and click the button on the left."
-msgstr "您的 U2F 设备需è¦è®¾ç½®ã€‚请将将其æ’入,并点击左边的按钮。"
-
msgid "Your U2F device was registered!"
msgstr "您的 U2F 设备已注册ï¼"
+msgid "Your WebAuthn device did not send a valid JSON response."
+msgstr ""
+
+msgid "Your WebAuthn device was registered!"
+msgstr ""
+
msgid "Your access request to the %{source_type} has been withdrawn."
msgstr "您对 %{source_type} 访问请求已被撤消。"
@@ -28734,6 +29673,9 @@ msgstr "您已授æƒçš„应用"
msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
msgstr "您的æµè§ˆå™¨ä¸æ”¯æŒU2F。请使用Google Chromeæ¡Œé¢ç‰ˆï¼ˆ41或更高版本)。"
+msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
+msgstr ""
+
msgid "Your changes can be committed to %{branch_name} because a merge request is open."
msgstr "åˆå¹¶è¯·æ±‚已开å¯ï¼Œå¯ä»¥æ交å˜æ›´åˆ°%{branch_name}。"
@@ -28770,6 +29712,12 @@ msgstr "您的仪表æ¿å·²æ›´æ–°ã€‚ä½ å¯ä»¥%{web_ide_link_start}在这里进行
msgid "Your deployment services will be broken, you will need to manually fix the services after renaming."
msgstr "您的部署æœåŠ¡å°†å¤±æ•ˆï¼Œéœ€è¦åœ¨é‡å‘½ååŽæ‰‹åŠ¨ä¿®å¤æœåŠ¡ã€‚"
+msgid "Your device is not compatible with GitLab. Please try another device"
+msgstr ""
+
+msgid "Your device needs to be set up. Plug it in (if needed) and click the button on the left."
+msgstr ""
+
msgid "Your device was successfully set up! Give it a name and register it with the GitLab server."
msgstr "您的设备已æˆåŠŸè®¾ç½®ï¼è¯·ç»™å®ƒå‘½å并将其注册到GitLabæœåŠ¡å™¨ã€‚"
@@ -28882,9 +29830,6 @@ msgstr[0] "约%då°æ—¶"
msgid "access:"
msgstr "访问:"
-msgid "activated"
-msgstr "已激活"
-
msgid "added %{created_at_timeago}"
msgstr "创建于 %{created_at_timeago}"
@@ -28957,9 +29902,21 @@ msgstr "æ¥è‡ª"
msgid "by %{user}"
msgstr "ç”±%{user}"
+msgid "cannot be a date in the past"
+msgstr ""
+
msgid "cannot be changed if a personal project has container registry tags."
msgstr "如果个人项目具有容器镜åƒåº“标签,则无法更改。"
+msgid "cannot be changed if shared runners are enabled"
+msgstr ""
+
+msgid "cannot be enabled because parent group does not allow it"
+msgstr ""
+
+msgid "cannot be enabled because parent group has shared Runners disabled"
+msgstr ""
+
msgid "cannot be enabled unless all domains have TLS certificates"
msgstr "除éžæ‰€æœ‰åŸŸéƒ½å…·æœ‰TLSè¯ä¹¦ï¼Œå¦åˆ™æ— æ³•å¯ç”¨"
@@ -29005,8 +29962,8 @@ msgstr "%{linkStartTag}了解更多有关ä¾èµ–项扫æçš„ä¿¡æ¯ %{linkEndTag}"
msgid "ciReport|%{linkStartTag}Learn more about SAST %{linkEndTag}"
msgstr "%{linkStartTag}了解更多有关SAST %{linkEndTag}çš„ä¿¡æ¯"
-msgid "ciReport|%{linkStartTag}Learn more about Secret Scanning %{linkEndTag}"
-msgstr "%{linkStartTag}了解更多有关密ç æ‰«æçš„ä¿¡æ¯%{linkEndTag}"
+msgid "ciReport|%{linkStartTag}Learn more about Secret Detection %{linkEndTag}"
+msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about codequality reports %{linkEndTag}"
msgstr "%{linkStartTag}了解有关代ç è´¨é‡æŠ¥å‘Šçš„更多信æ¯%{linkEndTag}"
@@ -29317,9 +30274,6 @@ msgstr "å²è¯—"
msgid "error"
msgstr "错误"
-msgid "error code:"
-msgstr "错误代ç ï¼š"
-
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr "最åŽä¸€æ¬¡%{slash_command} 命令将更新预计时间。"
@@ -29341,6 +30295,9 @@ msgstr "已失败"
msgid "failed to dismiss associated finding(id=%{finding_id}): %{message}"
msgstr "无法忽略关è”çš„å‘现(id=%{finding_id}): %{message}"
+msgid "failed to revert associated finding(id=%{finding_id}) to detected"
+msgstr ""
+
msgid "file"
msgid_plural "files"
msgstr[0] "文件"
@@ -29879,6 +30836,9 @@ msgstr "æµæ°´çº¿æˆåŠŸæ—¶å¯åŠ¨åˆå¹¶é˜Ÿåˆ—"
msgid "must be a root namespace"
msgstr "必须是根命å空间"
+msgid "must be a valid IPv4 or IPv6 address"
+msgstr ""
+
msgid "must be greater than start date"
msgstr "必须大于开始日期"
@@ -29915,6 +30875,9 @@ msgstr "无贡献"
msgid "no expiration"
msgstr "无过期"
+msgid "no name set"
+msgstr ""
+
msgid "no one can merge"
msgstr "没有人å¯ä»¥åˆå¹¶"
@@ -30088,9 +31051,6 @@ msgstr "满足"
msgid "security Reports|There was an error creating the merge request"
msgstr "创建åˆå¹¶è¯·æ±‚时出错"
-msgid "settings saved, but not activated"
-msgstr "设置已ä¿å­˜ï¼Œä½†æœªæ¿€æ´»ã€‚"
-
msgid "severity|Critical"
msgstr "严é‡"
@@ -30217,9 +31177,6 @@ msgstr "到列表中"
msgid "toggle collapse"
msgstr "切æ¢æŠ˜å "
-msgid "toggle dropdown"
-msgstr "切æ¢ä¸‹æ‹‰åˆ—表"
-
msgid "triggered"
msgstr "已触å‘"
@@ -30247,6 +31204,9 @@ msgstr "上传"
msgid "user avatar"
msgstr "用户头åƒ"
+msgid "user preferences"
+msgstr ""
+
msgid "username"
msgstr "用户å"
diff --git a/locale/zh_HK/gitlab.po b/locale/zh_HK/gitlab.po
index 20b7d96bd0f..21add9cc170 100644
--- a/locale/zh_HK/gitlab.po
+++ b/locale/zh_HK/gitlab.po
@@ -14,7 +14,10 @@ msgstr ""
"X-Crowdin-Language: zh-HK\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 6\n"
-"PO-Revision-Date: 2020-09-04 23:04\n"
+"PO-Revision-Date: 2020-10-02 18:43\n"
+
+msgid " %{project_name}#%{issue_iid} &middot; opened %{issue_created} by %{author}"
+msgstr ""
msgid " %{start} to %{end}"
msgstr ""
@@ -72,6 +75,14 @@ msgstr ""
msgid "\"el\" parameter is required for createInstance()"
msgstr ""
+msgid "%d Approval"
+msgid_plural "%d Approvals"
+msgstr[0] ""
+
+msgid "%d Package"
+msgid_plural "%d Packages"
+msgstr[0] ""
+
msgid "%d Scanned URL"
msgid_plural "%d Scanned URLs"
msgstr[0] ""
@@ -123,6 +134,10 @@ msgstr[0] ""
msgid "%d commits"
msgstr "%d 個æ交"
+msgid "%d completed issue"
+msgid_plural "%d completed issues"
+msgstr[0] ""
+
msgid "%d contribution"
msgid_plural "%d contributions"
msgstr[0] ""
@@ -131,6 +146,10 @@ msgid "%d day"
msgid_plural "%d days"
msgstr[0] ""
+msgid "%d day until tags are automatically removed"
+msgid_plural "%d days until tags are automatically removed"
+msgstr[0] ""
+
msgid "%d error"
msgid_plural "%d errors"
msgstr[0] ""
@@ -203,6 +222,14 @@ msgid "%d more comment"
msgid_plural "%d more comments"
msgstr[0] ""
+msgid "%d open issue"
+msgid_plural "%d open issues"
+msgstr[0] ""
+
+msgid "%d pending comment"
+msgid_plural "%d pending comments"
+msgstr[0] ""
+
msgid "%d personal project will be removed and cannot be restored."
msgid_plural "%d personal projects will be removed and cannot be restored."
msgstr[0] ""
@@ -215,6 +242,10 @@ msgid "%d project"
msgid_plural "%d projects"
msgstr[0] ""
+msgid "%d project selected"
+msgid_plural "%d projects selected"
+msgstr[0] ""
+
msgid "%d request with warnings"
msgid_plural "%d requests with warnings"
msgstr[0] ""
@@ -231,6 +262,10 @@ msgid "%d tag"
msgid_plural "%d tags"
msgstr[0] ""
+msgid "%d tag per image name"
+msgid_plural "%d tags per image name"
+msgstr[0] ""
+
msgid "%d unassigned issue"
msgid_plural "%d unassigned issues"
msgstr[0] ""
@@ -247,6 +282,10 @@ msgid "%d vulnerability dismissed"
msgid_plural "%d vulnerabilities dismissed"
msgstr[0] ""
+msgid "%d warning found:"
+msgid_plural "%d warnings found:"
+msgstr[0] ""
+
msgid "%s additional commit has been omitted to prevent performance issues."
msgid_plural "%s additional commits have been omitted to prevent performance issues."
msgstr[0] "為æ高é é¢åŠ è¼‰é€Ÿåº¦åŠæ€§èƒ½ï¼Œå·²çœç•¥äº† %s 次æ交。"
@@ -284,6 +323,9 @@ msgstr ""
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr "ç”± %{commit_author_link} æ交於 %{commit_timeago}"
+msgid "%{completedCount} completed weight"
+msgstr ""
+
msgid "%{completedWeight} of %{totalWeight} weight completed"
msgstr ""
@@ -329,13 +371,12 @@ msgid "%{count} participant"
msgid_plural "%{count} participants"
msgstr[0] "%{count} ä½åƒèˆ‡è€…"
-msgid "%{count} pending comment"
-msgid_plural "%{count} pending comments"
-msgstr[0] "%{count} 個待處ç†è©•è«–"
-
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
+msgid "%{count} total weight"
+msgstr ""
+
msgid "%{dashboard_path} could not be found."
msgstr ""
@@ -390,6 +431,9 @@ msgstr ""
msgid "%{group_name} uses group managed accounts. You need to create a new GitLab account which will be managed by %{group_name}."
msgstr ""
+msgid "%{group_name}&%{epic_iid} &middot; opened %{epic_created} by %{author}"
+msgstr ""
+
msgid "%{host} sign-in from new location"
msgstr ""
@@ -402,7 +446,7 @@ msgstr ""
msgid "%{issuableType} will be removed! Are you sure?"
msgstr "將會移除 %{issuableType}ï¼ç¢ºå®šï¼Ÿ"
-msgid "%{issuesSize} issues with a limit of %{maxIssueCount}"
+msgid "%{issuesCount} issues with a limit of %{maxIssueCount}"
msgstr ""
msgid "%{issuesSize} with a limit of %{maxIssueCount}"
@@ -435,7 +479,7 @@ msgstr ""
msgid "%{labelStart}Namespace:%{labelEnd} %{namespace}"
msgstr ""
-msgid "%{labelStart}Report Type:%{labelEnd} %{reportType}"
+msgid "%{labelStart}Scan Type:%{labelEnd} %{reportType}"
msgstr ""
msgid "%{labelStart}Scanner:%{labelEnd} %{scanner}"
@@ -625,9 +669,6 @@ msgid "%{securityScanner} result is not available because a pipeline has not bee
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] ""
-msgid "%{service_title} %{message}."
-msgstr ""
-
msgid "%{size} GiB"
msgstr ""
@@ -711,6 +752,12 @@ msgstr "%{text} å¯ç”¨"
msgid "%{timebox_name} should belong either to a project or a group."
msgstr ""
+msgid "%{timebox_type} does not support burnup charts"
+msgstr ""
+
+msgid "%{timebox_type} must have a start and due date"
+msgstr ""
+
msgid "%{title} %{operator} %{threshold}"
msgstr ""
@@ -735,7 +782,7 @@ msgstr ""
msgid "%{total} open issue weight"
msgstr ""
-msgid "%{total} open issues"
+msgid "%{total} warnings found: showing first %{warningsDisplayed}"
msgstr ""
msgid "%{usage_ping_link_start}Learn more%{usage_ping_link_end} about what information is shared with GitLab Inc."
@@ -768,9 +815,6 @@ msgstr ""
msgid "&lt; 1 hour"
msgstr ""
-msgid "&lt;no name set&gt;"
-msgstr ""
-
msgid "&lt;no scopes selected&gt;"
msgstr ""
@@ -801,6 +845,9 @@ msgstr ""
msgid "'%{name}' Value Stream created"
msgstr ""
+msgid "'%{name}' Value Stream deleted"
+msgstr ""
+
msgid "'%{name}' stage already exists"
msgstr ""
@@ -859,6 +906,9 @@ msgstr "+ %{moreCount} 更多"
msgid "+ %{numberOfHiddenAssignees} more"
msgstr ""
+msgid "+ %{numberOfHiddenReviewers} more"
+msgstr ""
+
msgid "+%d more"
msgid_plural "+%d more"
msgstr[0] ""
@@ -913,6 +963,10 @@ msgid "1 Day"
msgid_plural "%d Days"
msgstr[0] "%d 天"
+msgid "1 Issue"
+msgid_plural "%d Issues"
+msgstr[0] ""
+
msgid "1 closed issue"
msgid_plural "%{issues} closed issues"
msgstr[0] ""
@@ -925,6 +979,10 @@ msgid "1 day"
msgid_plural "%d days"
msgstr[0] ""
+msgid "1 deploy key"
+msgid_plural "%d deploy keys"
+msgstr[0] ""
+
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] "%d 個群組"
@@ -1018,6 +1076,9 @@ msgstr "8 å°æ™‚"
msgid ":%{startLine} to %{endLine}"
msgstr ""
+msgid "A %{incident_docs_start}modified issue%{incident_docs_end} to guide the resolution of incidents."
+msgstr ""
+
msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr ""
@@ -1030,6 +1091,9 @@ msgstr ""
msgid "A GitBook site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
+msgid "A Gitpod configured Webapplication in Spring and Java"
+msgstr ""
+
msgid "A Hexo site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr ""
@@ -1201,9 +1265,15 @@ msgstr ""
msgid "Access expiration date"
msgstr ""
+msgid "Access expires"
+msgstr ""
+
msgid "Access forbidden. Check your access level."
msgstr ""
+msgid "Access granted"
+msgstr ""
+
msgid "Access requests"
msgstr ""
@@ -1213,6 +1283,9 @@ msgstr ""
msgid "Access to Pages websites are controlled based on the user's membership to a given project. By checking this box, users will be required to be logged in to have access to all Pages websites in your instance."
msgstr ""
+msgid "AccessDropdown|Deploy Keys"
+msgstr ""
+
msgid "AccessDropdown|Groups"
msgstr ""
@@ -1330,12 +1403,6 @@ msgstr ""
msgid "Active Sessions"
msgstr ""
-msgid "Active Users:"
-msgstr ""
-
-msgid "Active users"
-msgstr ""
-
msgid "Activity"
msgstr "活動"
@@ -1502,9 +1569,6 @@ msgstr ""
msgid "Add label(s)"
msgstr "新增標籤"
-msgid "Add license"
-msgstr ""
-
msgid "Add list"
msgstr ""
@@ -1679,21 +1743,51 @@ msgstr ""
msgid "AdminArea|Bots"
msgstr ""
+msgid "AdminArea|Components"
+msgstr ""
+
msgid "AdminArea|Developer"
msgstr ""
+msgid "AdminArea|Features"
+msgstr ""
+
+msgid "AdminArea|Groups: %{number_of_groups}"
+msgstr ""
+
msgid "AdminArea|Guest"
msgstr ""
msgid "AdminArea|Included Free in license"
msgstr ""
+msgid "AdminArea|Latest groups"
+msgstr ""
+
+msgid "AdminArea|Latest projects"
+msgstr ""
+
+msgid "AdminArea|Latest users"
+msgstr ""
+
msgid "AdminArea|Maintainer"
msgstr ""
+msgid "AdminArea|New group"
+msgstr ""
+
+msgid "AdminArea|New project"
+msgstr ""
+
+msgid "AdminArea|New user"
+msgstr ""
+
msgid "AdminArea|Owner"
msgstr ""
+msgid "AdminArea|Projects: %{number_of_projects}"
+msgstr ""
+
msgid "AdminArea|Reporter"
msgstr ""
@@ -1721,6 +1815,9 @@ msgstr ""
msgid "AdminArea|Users without a Group and Project"
msgstr ""
+msgid "AdminArea|Users: %{number_of_users}"
+msgstr ""
+
msgid "AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running."
msgstr "您將åœæ­¢æ‰€æœ‰ä»»å‹™ï¼Œé€™å°‡æœƒæš«åœæ‰€æœ‰æ­£åœ¨é‹è¡Œçš„任務。"
@@ -1739,9 +1836,6 @@ msgstr "刪除"
msgid "AdminProjects|Delete Project %{projectName}?"
msgstr "刪除項目 %{projectName}?"
-msgid "AdminProjects|Delete project"
-msgstr "刪除項目"
-
msgid "AdminSettings|Apply integration settings to all Projects"
msgstr ""
@@ -1979,21 +2073,30 @@ msgstr ""
msgid "AdminUsers|Without projects"
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
+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 ""
msgid "AdminUsers|You cannot remove your own admin rights."
msgstr ""
+msgid "AdminUsers|You must transfer ownership or delete the groups owned by this user before you can delete their account"
+msgstr ""
+
msgid "Administration"
msgstr ""
msgid "Advanced"
msgstr ""
+msgid "Advanced Search"
+msgstr ""
+
+msgid "Advanced Search with Elasticsearch"
+msgstr ""
+
msgid "Advanced Settings"
msgstr ""
@@ -2070,6 +2173,9 @@ msgstr ""
msgid "AlertManagement|Edit"
msgstr ""
+msgid "AlertManagement|Environment"
+msgstr ""
+
msgid "AlertManagement|Events"
msgstr ""
@@ -2082,6 +2188,9 @@ msgstr ""
msgid "AlertManagement|Issue"
msgstr ""
+msgid "AlertManagement|Key"
+msgstr ""
+
msgid "AlertManagement|Low"
msgstr ""
@@ -2175,6 +2284,9 @@ msgstr ""
msgid "AlertManagement|Unknown"
msgstr ""
+msgid "AlertManagement|Value"
+msgstr ""
+
msgid "AlertManagement|View alerts in Opsgenie"
msgstr ""
@@ -2334,6 +2446,9 @@ msgstr ""
msgid "All projects"
msgstr ""
+msgid "All projects selected"
+msgstr ""
+
msgid "All security scans are enabled because %{linkStart}Auto DevOps%{linkEnd} is enabled on this project"
msgstr ""
@@ -2421,6 +2536,9 @@ msgstr "å…許您增加和管ç†Kuberneteså¢é›†ã€‚"
msgid "Almost there"
msgstr ""
+msgid "Already blocked"
+msgstr ""
+
msgid "Also called \"Issuer\" or \"Relying party trust identifier\""
msgstr ""
@@ -2475,6 +2593,9 @@ msgstr ""
msgid "An error has occurred"
msgstr ""
+msgid "An error occured while making the changes: %{error}"
+msgstr ""
+
msgid "An error occurred adding a draft to the thread."
msgstr ""
@@ -2502,12 +2623,6 @@ msgstr "é è¦½ blob 檔案時發生錯誤"
msgid "An error occurred when toggling the notification subscription"
msgstr "切æ›è¨‚閱通知時發生錯誤"
-msgid "An error occurred when trying to resolve a comment. Please try again."
-msgstr ""
-
-msgid "An error occurred when trying to resolve a discussion. Please try again."
-msgstr ""
-
msgid "An error occurred when updating the issue weight"
msgstr "更新議題權é‡æ™‚發生錯誤"
@@ -2523,12 +2638,6 @@ msgstr ""
msgid "An error occurred while checking group path. Please refresh and try again."
msgstr ""
-msgid "An error occurred while committing your changes."
-msgstr ""
-
-msgid "An error occurred while creating the list. Please try again."
-msgstr ""
-
msgid "An error occurred while decoding the file."
msgstr ""
@@ -2601,25 +2710,19 @@ msgstr ""
msgid "An error occurred while fetching the Service Desk address."
msgstr ""
-msgid "An error occurred while fetching the board issues. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the board lists. Please reload the page."
msgstr ""
msgid "An error occurred while fetching the board lists. Please try again."
msgstr ""
-msgid "An error occurred while fetching the board swimlanes. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the builds."
msgstr ""
msgid "An error occurred while fetching the job log."
msgstr ""
-msgid "An error occurred while fetching the job trace."
+msgid "An error occurred while fetching the job logs."
msgstr ""
msgid "An error occurred while fetching the job."
@@ -2766,9 +2869,6 @@ msgstr ""
msgid "An error occurred while saving assignees"
msgstr "儲存指派人時發生錯誤"
-msgid "An error occurred while saving the template. Please check if the template exists."
-msgstr ""
-
msgid "An error occurred while searching for milestones"
msgstr ""
@@ -2787,10 +2887,10 @@ msgstr "å–消訂閱通知時出錯"
msgid "An error occurred while updating approvers"
msgstr ""
-msgid "An error occurred while updating the comment"
+msgid "An error occurred while updating labels."
msgstr ""
-msgid "An error occurred while updating the list. Please try again."
+msgid "An error occurred while updating the comment"
msgstr ""
msgid "An error occurred while validating group path"
@@ -2844,6 +2944,9 @@ msgstr ""
msgid "An unknown error occurred while loading this graph."
msgstr ""
+msgid "An unknown error occurred."
+msgstr ""
+
msgid "Analytics"
msgstr ""
@@ -2877,10 +2980,10 @@ msgstr ""
msgid "Any"
msgstr ""
-msgid "Any Author"
+msgid "Any %{header}"
msgstr ""
-msgid "Any Status"
+msgid "Any Author"
msgstr ""
msgid "Any branch"
@@ -2934,6 +3037,9 @@ msgstr ""
msgid "Application ID"
msgstr ""
+msgid "Application limits saved successfully"
+msgstr ""
+
msgid "Application settings saved successfully"
msgstr ""
@@ -3139,6 +3245,9 @@ msgstr ""
msgid "Are you sure you want to close this blocked issue?"
msgstr ""
+msgid "Are you sure you want to delete \"%{name}\" Value Stream?"
+msgstr ""
+
msgid "Are you sure you want to delete %{name}?"
msgstr ""
@@ -3148,6 +3257,9 @@ msgstr ""
msgid "Are you sure you want to delete this %{typeOfComment}?"
msgstr ""
+msgid "Are you sure you want to delete this SSH key?"
+msgstr ""
+
msgid "Are you sure you want to delete this board?"
msgstr ""
@@ -3172,6 +3284,10 @@ msgstr ""
msgid "Are you sure you want to erase this build?"
msgstr ""
+msgid "Are you sure you want to import %d repository?"
+msgid_plural "Are you sure you want to import %d repositories?"
+msgstr[0] ""
+
msgid "Are you sure you want to lose unsaved changes?"
msgstr ""
@@ -3181,15 +3297,15 @@ msgstr ""
msgid "Are you sure you want to merge immediately?"
msgstr ""
-msgid "Are you sure you want to permanently delete this license?"
-msgstr ""
-
msgid "Are you sure you want to re-deploy this environment?"
msgstr ""
msgid "Are you sure you want to regenerate the public key? You will have to update the public key on the remote server before mirroring will work again."
msgstr ""
+msgid "Are you sure you want to reindex?"
+msgstr ""
+
msgid "Are you sure you want to remove %{group_name}?"
msgstr ""
@@ -3217,6 +3333,9 @@ msgstr ""
msgid "Are you sure you want to revoke this nickname?"
msgstr ""
+msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
+msgstr ""
+
msgid "Are you sure you want to stop this environment?"
msgstr ""
@@ -3238,6 +3357,9 @@ msgstr ""
msgid "Are you sure? The device will be signed out of GitLab and all remember me tokens revoked."
msgstr ""
+msgid "Are you sure? This will invalidate your registered applications and U2F / WebAuthn devices."
+msgstr ""
+
msgid "Are you sure? This will invalidate your registered applications and U2F devices."
msgstr ""
@@ -3256,9 +3378,6 @@ msgstr ""
msgid "Artifacts"
msgstr ""
-msgid "As U2F devices are only supported by a few browsers, we require that you set up a two-factor authentication app before a U2F device. That way you'll always be able to log in - even when you're using an unsupported browser."
-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 ""
@@ -3450,6 +3569,9 @@ msgstr ""
msgid "AuditLogs|Target"
msgstr ""
+msgid "AuditLogs|This month"
+msgstr ""
+
msgid "AuditLogs|User Events"
msgstr ""
@@ -3489,6 +3611,9 @@ msgstr ""
msgid "Authentication via U2F device failed."
msgstr ""
+msgid "Authentication via WebAuthn device failed."
+msgstr ""
+
msgid "Author"
msgstr ""
@@ -3756,15 +3881,6 @@ msgstr ""
msgid "BambooService|You must set up automatic revision labeling and a repository trigger in Bamboo."
msgstr ""
-msgid "BatchComments|Delete all pending comments"
-msgstr ""
-
-msgid "BatchComments|Discard review?"
-msgstr ""
-
-msgid "BatchComments|You're about to discard your review which will delete all of your pending comments. The deleted comments %{strong_start}cannot%{strong_end} be restored."
-msgstr ""
-
msgid "Be careful. Changing the project's namespace can have unintended side effects."
msgstr ""
@@ -3786,6 +3902,9 @@ msgstr ""
msgid "Bi-weekly code coverage"
msgstr ""
+msgid "Billable Users:"
+msgstr ""
+
msgid "Billing"
msgstr ""
@@ -3795,7 +3914,7 @@ msgstr ""
msgid "BillingPlans|@%{user_name} you are currently using the %{plan_name} plan."
msgstr ""
-msgid "BillingPlans|Congratulations, your new trial is activated"
+msgid "BillingPlans|Congratulations, your free trial is activated."
msgstr ""
msgid "BillingPlans|If you would like to downgrade your plan please contact %{support_link_start}Customer Support%{support_link_end}."
@@ -3858,6 +3977,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Block user"
+msgstr ""
+
msgid "Blocked"
msgstr ""
@@ -3873,31 +3995,37 @@ msgstr ""
msgid "Blog"
msgstr ""
-msgid "Board name"
-msgstr ""
-
msgid "Board scope"
msgstr ""
msgid "Board scope affects which issues are displayed for anyone who visits this board"
msgstr ""
-msgid "BoardBlankState|Add default lists"
+msgid "Boards"
msgstr ""
-msgid "BoardBlankState|Add the following default lists to your Issue Board with one click:"
+msgid "Boards and Board Lists"
msgstr ""
-msgid "BoardBlankState|Nevermind, I'll use my own"
+msgid "Boards|An error occurred while creating the issue. Please try again."
msgstr ""
-msgid "BoardBlankState|Starting out with the default set of lists will get you right on the way to making the most of your board."
+msgid "Boards|An error occurred while creating the list. Please try again."
msgstr ""
-msgid "Boards"
+msgid "Boards|An error occurred while fetching issues. Please reload the page."
msgstr ""
-msgid "Boards and Board Lists"
+msgid "Boards|An error occurred while fetching the board issues. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while fetching the board swimlanes. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while moving the issue. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while updating the list. Please try again."
msgstr ""
msgid "Boards|Collapse"
@@ -3924,8 +4052,8 @@ msgstr ""
msgid "Branch %{branch_name} was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr ""
-msgid "Branch has changed"
-msgstr "分支已變更"
+msgid "Branch changed"
+msgstr ""
msgid "Branch is already taken"
msgstr "分支已被採å–"
@@ -4230,6 +4358,9 @@ msgstr ""
msgid "CLOSED (MOVED)"
msgstr ""
+msgid "CODEOWNERS rule violation"
+msgstr ""
+
msgid "CONTRIBUTING"
msgstr ""
@@ -4260,9 +4391,6 @@ msgstr ""
msgid "Can't create snippet: %{err}"
msgstr ""
-msgid "Can't edit as source branch was deleted"
-msgstr ""
-
msgid "Can't fetch content for the blob: %{err}"
msgstr ""
@@ -4275,9 +4403,6 @@ msgstr ""
msgid "Can't load mermaid module: %{err}"
msgstr ""
-msgid "Can't remove group members without group managed account"
-msgstr ""
-
msgid "Can't scan the code?"
msgstr ""
@@ -4320,6 +4445,9 @@ msgstr ""
msgid "Cannot create the abuse report. This user has been blocked."
msgstr ""
+msgid "Cannot enable shared runners because parent group does not allow it"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -4425,6 +4553,15 @@ msgstr ""
msgid "Change your password or recover your current one"
msgstr ""
+msgid "ChangeReviewer|Reviewer changed from %{old} to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Reviewer changed to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Unassigned"
+msgstr ""
+
msgid "ChangeTypeActionLabel|Pick into branch"
msgstr "挑é¸åˆ°åˆ†æ”¯"
@@ -4464,6 +4601,9 @@ msgstr ""
msgid "Changes the title to \"%{title_param}\"."
msgstr "將標題改為「%{title_param}ã€ã€‚"
+msgid "Changes were successfully made."
+msgstr ""
+
msgid "Changes won't take place until the index is %{link_start}recreated%{link_end}."
msgstr ""
@@ -4869,6 +5009,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove variable"
+msgstr ""
+
msgid "CiVariables|Remove variable row"
msgstr ""
@@ -4947,9 +5090,6 @@ msgstr ""
msgid "Clear due date"
msgstr ""
-msgid "Clear input"
-msgstr ""
-
msgid "Clear recent searches"
msgstr ""
@@ -4998,6 +5138,9 @@ msgstr ""
msgid "Client authentication key password"
msgstr ""
+msgid "Client request timeout"
+msgstr ""
+
msgid "Clients"
msgstr ""
@@ -5082,6 +5225,27 @@ msgstr ""
msgid "Cluster type must be specificed for Stages::ClusterEndpointInserter"
msgstr ""
+msgid "ClusterAgents|Configuration"
+msgstr ""
+
+msgid "ClusterAgents|Connect your cluster with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate Kubernetes with a GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Name"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Agent also requires %{linkStart}enabling the Agent Server%{linkEnd}"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Kubernetes Agent allows an Infrastructure as Code, GitOps approach to integrating Kubernetes clusters with GitLab. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "ClusterAgent|This feature is only available for premium plans"
msgstr ""
@@ -5151,10 +5315,10 @@ msgstr ""
msgid "ClusterIntegration|All installed applications and related resources"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster."
+msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{linkStart}More information%{linkEnd}"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{startLink}More information%{endLink}"
+msgid "ClusterIntegration|Allow GitLab to manage namespaces and service accounts for this cluster."
msgstr ""
msgid "ClusterIntegration|Alternatively, "
@@ -5175,6 +5339,9 @@ msgstr ""
msgid "ClusterIntegration|An error occurred while trying to fetch zone machine types: %{error}"
msgstr ""
+msgid "ClusterIntegration|An unknown error occurred while attempting to connect to Kubernetes."
+msgstr ""
+
msgid "ClusterIntegration|Any project namespaces"
msgstr ""
@@ -5190,6 +5357,9 @@ msgstr ""
msgid "ClusterIntegration|Authenticate with Amazon Web Services"
msgstr ""
+msgid "ClusterIntegration|Authentication Error"
+msgstr ""
+
msgid "ClusterIntegration|Base domain"
msgstr ""
@@ -5208,13 +5378,22 @@ msgstr ""
msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}security group %{externalLinkIcon} %{endLink} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
+msgid "ClusterIntegration|Check your CA certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Check your cluster status"
+msgstr ""
+
+msgid "ClusterIntegration|Check your token"
+msgstr ""
+
+msgid "ClusterIntegration|Choose the %{linkStart}security group %{linkEnd} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}subnets %{externalLinkIcon} %{endLink} in your VPC where your worker nodes will run."
+msgid "ClusterIntegration|Choose the %{linkStart}subnets %{linkEnd} in your VPC where your worker nodes will run."
msgstr ""
-msgid "ClusterIntegration|Choose the worker node %{startLink}instance type %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Choose the worker node %{linkStart}instance type%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Choose which applications to install on your Kubernetes cluster."
@@ -5226,10 +5405,7 @@ msgstr ""
msgid "ClusterIntegration|Clear cluster cache"
msgstr ""
-msgid "ClusterIntegration|Clear the local cache of namespace and service accounts. This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
-msgstr ""
-
-msgid "ClusterIntegration|Cluster being created"
+msgid "ClusterIntegration|Clear the local cache of namespace and service accounts."
msgstr ""
msgid "ClusterIntegration|Cluster management project (alpha)"
@@ -5241,15 +5417,21 @@ msgstr ""
msgid "ClusterIntegration|Cluster_applications artifact too big. Maximum allowable size: %{human_size}"
msgstr ""
-msgid "ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters."
+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|Clusters connected with a certificate"
msgstr ""
-msgid "ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters. %{linkStart}More information%{linkEnd}"
+msgid "ClusterIntegration|Connect cluster with certificate"
msgstr ""
msgid "ClusterIntegration|Connect existing cluster"
msgstr ""
+msgid "ClusterIntegration|Connection Error"
+msgstr ""
+
msgid "ClusterIntegration|Copy API URL"
msgstr ""
@@ -5325,6 +5507,12 @@ msgstr ""
msgid "ClusterIntegration|Deletes all GitLab resources attached to this cluster during removal"
msgstr ""
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared."
+msgstr ""
+
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared. %{linkStart}More information%{linkEnd}"
+msgstr ""
+
msgid "ClusterIntegration|Did you know?"
msgstr ""
@@ -5394,6 +5582,9 @@ msgstr ""
msgid "ClusterIntegration|Fluentd is an open source data collector, which lets you unify the data collection and consumption for a better use and understanding of data. It requires at least one of the following logs to be successfully installed."
msgstr ""
+msgid "ClusterIntegration|GitLab Agent managed clusters"
+msgstr ""
+
msgid "ClusterIntegration|GitLab Container Network Policies"
msgstr ""
@@ -5406,6 +5597,12 @@ msgstr ""
msgid "ClusterIntegration|GitLab Runner connects to the repository and executes CI/CD jobs, pushing results back and deploying applications to production."
msgstr ""
+msgid "ClusterIntegration|GitLab failed to authenticate."
+msgstr ""
+
+msgid "ClusterIntegration|GitLab failed to connect to the cluster."
+msgstr ""
+
msgid "ClusterIntegration|GitLab-managed cluster"
msgstr ""
@@ -5427,6 +5624,9 @@ msgstr ""
msgid "ClusterIntegration|Group cluster"
msgstr ""
+msgid "ClusterIntegration|HTTP Error"
+msgstr ""
+
msgid "ClusterIntegration|Helm Tiller"
msgstr ""
@@ -5460,7 +5660,10 @@ msgstr ""
msgid "ClusterIntegration|Instance type"
msgstr ""
-msgid "ClusterIntegration|Integrate Kubernetes cluster automation"
+msgid "ClusterIntegration|Integrate Kubernetes with a cluster certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Integrate with a cluster certificate"
msgstr ""
msgid "ClusterIntegration|Issuer Email"
@@ -5496,9 +5699,6 @@ msgstr ""
msgid "ClusterIntegration|Knative extends Kubernetes to provide a set of middleware components that are essential to build modern, source-centric, and container-based applications that can run anywhere: on premises, in the cloud, or even in a third-party data center."
msgstr ""
-msgid "ClusterIntegration|Kubernetes cluster"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes cluster is being created..."
msgstr ""
@@ -5511,9 +5711,6 @@ msgstr ""
msgid "ClusterIntegration|Kubernetes clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr ""
-msgid "ClusterIntegration|Kubernetes clusters can be used to deploy applications and to provide Review Apps for this project"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes version"
msgstr ""
@@ -5526,7 +5723,7 @@ msgstr ""
msgid "ClusterIntegration|Learn more about %{help_link_start}zones%{help_link_end}."
msgstr ""
-msgid "ClusterIntegration|Learn more about %{startLink}Regions %{externalLinkIcon}%{endLink}."
+msgid "ClusterIntegration|Learn more about %{linkStart}Regions%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Learn more about Kubernetes"
@@ -5571,12 +5768,18 @@ msgstr ""
msgid "ClusterIntegration|Machine type"
msgstr ""
+msgid "ClusterIntegration|Make sure your API endpoint is correct"
+msgstr ""
+
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create Kubernetes clusters"
msgstr ""
msgid "ClusterIntegration|Manage your Kubernetes cluster by visiting %{provider_link}"
msgstr ""
+msgid "ClusterIntegration|Namespace per environment"
+msgstr ""
+
msgid "ClusterIntegration|No IAM Roles found"
msgstr ""
@@ -5622,6 +5825,9 @@ msgstr ""
msgid "ClusterIntegration|No zones matched your search"
msgstr ""
+msgid "ClusterIntegration|Node calculations use the Kubernetes Metrics API. Make sure your cluster has metrics installed"
+msgstr ""
+
msgid "ClusterIntegration|Number of nodes"
msgstr ""
@@ -5664,6 +5870,9 @@ msgstr ""
msgid "ClusterIntegration|RBAC-enabled cluster"
msgstr ""
+msgid "ClusterIntegration|Read our %{linkStart}help page%{linkEnd} on Kubernetes cluster integration."
+msgstr ""
+
msgid "ClusterIntegration|Read our %{link_start}help page%{link_end} on Kubernetes cluster integration."
msgstr ""
@@ -5766,7 +5975,7 @@ msgstr ""
msgid "ClusterIntegration|Select a VPC to choose a subnet"
msgstr ""
-msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{linkStart}Amazon Web Services %{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select a network to choose a subnetwork"
@@ -5799,7 +6008,7 @@ msgstr ""
msgid "ClusterIntegration|Select project to choose zone"
msgstr ""
-msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select zone"
@@ -5889,9 +6098,18 @@ msgstr ""
msgid "ClusterIntegration|There was a problem authenticating with your cluster. Please ensure your CA Certificate and Token are valid."
msgstr ""
+msgid "ClusterIntegration|There was an HTTP error when connecting to your cluster."
+msgstr ""
+
msgid "ClusterIntegration|This account must have permissions to create a Kubernetes cluster in the %{link_to_container_project} specified below"
msgstr ""
+msgid "ClusterIntegration|This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
+msgstr ""
+
+msgid "ClusterIntegration|This is necessary to clear existing environment-namespace associations from clusters previously managed by GitLab."
+msgstr ""
+
msgid "ClusterIntegration|This option will allow you to install applications on RBAC clusters."
msgstr ""
@@ -5916,9 +6134,21 @@ msgstr ""
msgid "ClusterIntegration|To use a new project, first create one on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}."
msgstr ""
+msgid "ClusterIntegration|Troubleshooting tips:"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Authenticate"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Connect"
+msgstr ""
+
msgid "ClusterIntegration|Uninstall %{appTitle}"
msgstr ""
+msgid "ClusterIntegration|Unknown Error"
+msgstr ""
+
msgid "ClusterIntegration|Update %{appTitle}"
msgstr ""
@@ -5979,7 +6209,7 @@ msgstr ""
msgid "ClusterIntegration|Your cluster API is unreachable. Please ensure your API URL is correct."
msgstr ""
-msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Zone"
@@ -6099,6 +6329,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse all threads"
+msgstr ""
+
msgid "Collapse approvers"
msgstr ""
@@ -6247,7 +6480,7 @@ msgstr "æ交者:"
msgid "Commit…"
msgstr ""
-msgid "Company"
+msgid "Community forum"
msgstr ""
msgid "Company name"
@@ -6256,6 +6489,9 @@ msgstr ""
msgid "Compare"
msgstr "比較"
+msgid "Compare %{oldCommitId}...%{newCommitId}"
+msgstr ""
+
msgid "Compare Git revisions"
msgstr ""
@@ -6271,6 +6507,9 @@ msgstr "與最後æ交進行比較"
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare submodule commit revisions"
+msgstr ""
+
msgid "Compare with previous version"
msgstr ""
@@ -6406,6 +6645,9 @@ msgstr ""
msgid "Configure the way a user creates a new account."
msgstr ""
+msgid "Configure which lists are shown for anyone who visits this board"
+msgstr ""
+
msgid "Confirm"
msgstr ""
@@ -6628,6 +6870,9 @@ msgstr[0] ""
msgid "ContainerRegistry|Set cleanup policy"
msgstr ""
+msgid "ContainerRegistry|Some tags were not deleted"
+msgstr ""
+
msgid "ContainerRegistry|Something went wrong while fetching the cleanup policy."
msgstr ""
@@ -6667,6 +6912,9 @@ msgstr ""
msgid "ContainerRegistry|Tags with names matching this regex pattern will %{italicStart}expire:%{italicEnd}"
msgstr ""
+msgid "ContainerRegistry|The cleanup policy timed out before it could delete all tags. An administrator can %{adminLinkStart}manually run cleanup now%{adminLinkEnd} or you can wait for the cleanup policy to automatically run again. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "ContainerRegistry|The last tag related to this image was recently removed. This empty image and any associated data will be automatically removed as part of the regular Garbage Collection process. If you have any questions, contact your administrator."
msgstr ""
@@ -6799,6 +7047,9 @@ msgstr ""
msgid "Contributions per group member"
msgstr ""
+msgid "Contributor"
+msgstr ""
+
msgid "Contributors"
msgstr "è²¢ç»è€…"
@@ -6928,6 +7179,9 @@ msgstr ""
msgid "Could not change HEAD: branch '%{branch}' does not exist"
msgstr ""
+msgid "Could not commit. An unexpected error occurred."
+msgstr ""
+
msgid "Could not connect to FogBugz, check your URL"
msgstr ""
@@ -6967,6 +7221,9 @@ msgstr ""
msgid "Could not find iteration"
msgstr ""
+msgid "Could not load instance counts. Please refresh the page to try again."
+msgstr ""
+
msgid "Could not remove the trigger."
msgstr ""
@@ -6991,10 +7248,10 @@ msgstr ""
msgid "Could not save prometheus manual configuration"
msgstr ""
-msgid "Could not udpdate wiki page"
+msgid "Could not update the LDAP settings"
msgstr ""
-msgid "Could not update the LDAP settings"
+msgid "Could not update wiki page"
msgstr ""
msgid "Could not upload your designs as one or more files uploaded are not supported."
@@ -7650,6 +7907,9 @@ msgstr ""
msgid "DastProfiles|Are you sure you want to delete this profile?"
msgstr ""
+msgid "DastProfiles|Could not create site validation token. Please refresh the page, or try again later."
+msgstr ""
+
msgid "DastProfiles|Could not create the scanner profile. Please try again."
msgstr ""
@@ -7674,6 +7934,12 @@ msgstr ""
msgid "DastProfiles|Could not fetch site profiles. Please refresh the page, or try again later."
msgstr ""
+msgid "DastProfiles|Could not retrieve site validation status. Please refresh the page, or try again later."
+msgstr ""
+
+msgid "DastProfiles|Could not update the scanner profile. Please try again."
+msgstr ""
+
msgid "DastProfiles|Could not update the site profile. Please try again."
msgstr ""
@@ -7689,7 +7955,7 @@ msgstr ""
msgid "DastProfiles|Download validation text file"
msgstr ""
-msgid "DastProfiles|Edit feature will come soon. Please create a new profile if changes needed"
+msgid "DastProfiles|Edit scanner profile"
msgstr ""
msgid "DastProfiles|Edit site profile"
@@ -7722,6 +7988,9 @@ msgstr ""
msgid "DastProfiles|No profiles created yet"
msgstr ""
+msgid "DastProfiles|Passive"
+msgstr ""
+
msgid "DastProfiles|Please enter a valid URL format, ex: http://www.example.com/home"
msgstr ""
@@ -7737,6 +8006,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan mode"
+msgstr ""
+
msgid "DastProfiles|Scanner Profile"
msgstr ""
@@ -7776,10 +8048,10 @@ msgstr ""
msgid "DastProfiles|Text file validation"
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
+msgid "DastProfiles|The maximum number of minutes allowed for the spider to traverse the site."
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the spider to traverse the site."
+msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
msgstr ""
msgid "DastProfiles|Validate"
@@ -7812,6 +8084,9 @@ msgstr ""
msgid "Date picker"
msgstr ""
+msgid "Date range"
+msgstr ""
+
msgid "Date range cannot exceed %{maxDateRange} days."
msgstr ""
@@ -7836,6 +8111,9 @@ msgstr ""
msgid "Days to merge"
msgstr ""
+msgid "Dear Administrator,"
+msgstr ""
+
msgid "Debug"
msgstr ""
@@ -7947,12 +8225,18 @@ msgstr ""
msgid "Delete"
msgstr "刪除"
+msgid "Delete %{name}"
+msgstr ""
+
msgid "Delete Comment"
msgstr ""
msgid "Delete Snippet"
msgstr ""
+msgid "Delete Value Stream"
+msgstr ""
+
msgid "Delete account"
msgstr ""
@@ -7974,9 +8258,6 @@ msgstr ""
msgid "Delete label: %{label_name} ?"
msgstr ""
-msgid "Delete license"
-msgstr ""
-
msgid "Delete list"
msgstr ""
@@ -8052,15 +8333,6 @@ msgstr ""
msgid "Deleting a project places it into a read-only state until %{date}, at which point the project will be permanently deleted. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "Deleting the license failed."
-msgstr ""
-
-msgid "Deleting the license failed. The license was not found."
-msgstr ""
-
-msgid "Deleting the license failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "Deleting the project will delete its repository and all related resources including issues, merge requests etc."
msgstr ""
@@ -8550,7 +8822,10 @@ msgstr ""
msgid "DesignManagement|The maximum number of designs allowed to be uploaded is %{upload_limit}. Please try again."
msgstr ""
-msgid "DesignManagement|To upload designs, you'll need to enable LFS. %{requirements_link_start}More information%{requirements_link_end}"
+msgid "DesignManagement|There was an error moving your designs. Please upload your designs below."
+msgstr ""
+
+msgid "DesignManagement|To upload designs, you'll need to enable LFS and have admin enable hashed storage. %{requirements_link_start}More information%{requirements_link_end}"
msgstr ""
msgid "DesignManagement|Unresolve thread"
@@ -8562,6 +8837,9 @@ msgstr ""
msgid "DesignManagement|Upload skipped."
msgstr ""
+msgid "DesignManagement|Your designs are being copied and are on their way… Please refresh to update."
+msgstr ""
+
msgid "DesignManagement|and %{moreCount} more."
msgstr ""
@@ -8619,6 +8897,9 @@ msgstr ""
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
+msgid "Direct member"
+msgstr ""
+
msgid "Direction"
msgstr ""
@@ -8667,9 +8948,6 @@ msgstr ""
msgid "Discard draft"
msgstr ""
-msgid "Discard review"
-msgstr ""
-
msgid "DiscordService|Discord Notifications"
msgstr ""
@@ -8737,10 +9015,10 @@ msgstr ""
msgid "Dismiss Merge Request promotion"
msgstr ""
-msgid "Dismiss Selected"
+msgid "Dismiss Value Stream Analytics introduction box"
msgstr ""
-msgid "Dismiss Value Stream Analytics introduction box"
+msgid "Dismiss selected"
msgstr ""
msgid "Dismiss trial promotion"
@@ -8791,9 +9069,6 @@ msgstr ""
msgid "Documents reindexed: %{processed_documents} (%{percentage}%%)"
msgstr ""
-msgid "Doing"
-msgstr ""
-
msgid "Domain"
msgstr ""
@@ -8989,9 +9264,6 @@ msgstr ""
msgid "Edit environment"
msgstr ""
-msgid "Edit file"
-msgstr ""
-
msgid "Edit files in the editor and commit changes here"
msgstr ""
@@ -9004,6 +9276,12 @@ msgstr ""
msgid "Edit identity for %{user_name}"
msgstr ""
+msgid "Edit in Web IDE"
+msgstr ""
+
+msgid "Edit in single-file editor"
+msgstr ""
+
msgid "Edit issues"
msgstr "編輯議題"
@@ -9031,10 +9309,10 @@ msgstr ""
msgid "Editing"
msgstr ""
-msgid "Elasticsearch"
+msgid "Elasticsearch AWS IAM credentials"
msgstr ""
-msgid "Elasticsearch AWS IAM credentials"
+msgid "Elasticsearch HTTP client timeout value in seconds."
msgstr ""
msgid "Elasticsearch indexing restrictions"
@@ -9043,9 +9321,6 @@ msgstr ""
msgid "Elasticsearch indexing started"
msgstr ""
-msgid "Elasticsearch integration. Elasticsearch AWS IAM."
-msgstr ""
-
msgid "Elasticsearch reindexing is already in progress"
msgstr ""
@@ -9073,9 +9348,6 @@ msgstr ""
msgid "Email Notification"
msgstr ""
-msgid "Email address"
-msgstr ""
-
msgid "Email could not be sent"
msgstr ""
@@ -9139,6 +9411,9 @@ msgstr ""
msgid "Emails sent from Service Desk will have this name"
msgstr ""
+msgid "Emails sent to %{email} will still be supported"
+msgstr ""
+
msgid "Emails separated by comma"
msgstr ""
@@ -9172,9 +9447,18 @@ msgstr ""
msgid "Enable"
msgstr ""
+msgid "Enable %{link_start}Gitpod%{link_end} integration to launch a development environment in your browser directly from GitLab."
+msgstr ""
+
msgid "Enable Auto DevOps"
msgstr ""
+msgid "Enable Gitpod"
+msgstr ""
+
+msgid "Enable Gitpod?"
+msgstr ""
+
msgid "Enable HTML emails"
msgstr ""
@@ -9304,9 +9588,6 @@ msgstr ""
msgid "Encountered an error while rendering: %{err}"
msgstr ""
-msgid "End date"
-msgstr ""
-
msgid "Ends at (UTC)"
msgstr ""
@@ -9466,7 +9747,7 @@ msgstr ""
msgid "EnvironmentsDashboard|The environments dashboard provides a summary of each project's environments' status, including pipeline and alert statuses."
msgstr ""
-msgid "EnvironmentsDashboard|This dashboard displays a maximum of 7 projects and 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
+msgid "EnvironmentsDashboard|This dashboard displays 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
msgstr ""
msgid "Environments|An error occurred while canceling the auto stop, please try again"
@@ -9787,6 +10068,9 @@ msgstr ""
msgid "Error deleting project. Check logs for error details."
msgstr ""
+msgid "Error fetching burnup chart data"
+msgstr ""
+
msgid "Error fetching diverging counts for branches. Please try again."
msgstr ""
@@ -9865,6 +10149,9 @@ msgstr ""
msgid "Error occurred when saving assignees"
msgstr ""
+msgid "Error occurred when saving reviewers"
+msgstr ""
+
msgid "Error occurred when toggling the notification subscription"
msgstr ""
@@ -10117,10 +10404,13 @@ msgstr ""
msgid "Expand all"
msgstr ""
-msgid "Expand approvers"
+msgid "Expand all files"
+msgstr ""
+
+msgid "Expand all threads"
msgstr ""
-msgid "Expand dropdown"
+msgid "Expand approvers"
msgstr ""
msgid "Expand milestones"
@@ -10291,6 +10581,9 @@ msgstr ""
msgid "Failed to create Merge Request. Please try again."
msgstr ""
+msgid "Failed to create To-Do for the design."
+msgstr ""
+
msgid "Failed to create a branch for this issue. Please try again."
msgstr ""
@@ -10330,6 +10623,12 @@ msgstr ""
msgid "Failed to load authors. Please try again."
msgstr ""
+msgid "Failed to load branches. Please try again."
+msgstr ""
+
+msgid "Failed to load deploy keys."
+msgstr ""
+
msgid "Failed to load emoji list."
msgstr ""
@@ -10345,6 +10644,9 @@ msgstr ""
msgid "Failed to load groups & users."
msgstr ""
+msgid "Failed to load groups, users and deploy keys."
+msgstr ""
+
msgid "Failed to load labels. Please try again."
msgstr ""
@@ -10354,6 +10656,12 @@ msgstr ""
msgid "Failed to load related branches"
msgstr ""
+msgid "Failed to load sidebar confidential toggle"
+msgstr ""
+
+msgid "Failed to load sidebar lock status"
+msgstr ""
+
msgid "Failed to load stacktrace."
msgstr ""
@@ -10381,6 +10689,9 @@ msgstr ""
msgid "Failed to publish issue on status page."
msgstr ""
+msgid "Failed to remove To-Do for the design."
+msgstr ""
+
msgid "Failed to remove a Zoom meeting"
msgstr ""
@@ -10423,6 +10734,9 @@ msgstr ""
msgid "Failed to signing using smartcard authentication"
msgstr ""
+msgid "Failed to toggle To-Do for the design."
+msgstr ""
+
msgid "Failed to update branch!"
msgstr ""
@@ -10535,7 +10849,7 @@ msgstr ""
msgid "FeatureFlags|Edit User List"
msgstr ""
-msgid "FeatureFlags|Enable features for specific users and specific environments by defining feature flag strategies."
+msgid "FeatureFlags|Enable features for specific users and environments by configuring feature flag strategies."
msgstr ""
msgid "FeatureFlags|Environment Spec"
@@ -10595,7 +10909,7 @@ msgstr ""
msgid "FeatureFlags|Include additional user IDs"
msgstr ""
-msgid "FeatureFlags|Install a %{docs_link_anchored_start}compatible client library%{docs_link_anchored_end} and specify the API URL, application name, and instance ID during the configuration setup. %{docs_link_start}More Information%{docs_link_end}"
+msgid "FeatureFlags|Install a %{docsLinkAnchoredStart}compatible client library%{docsLinkAnchoredEnd} and specify the API URL, application name, and instance ID during the configuration setup. %{docsLinkStart}More Information%{docsLinkEnd}"
msgstr ""
msgid "FeatureFlags|Instance ID"
@@ -10607,6 +10921,9 @@ msgstr ""
msgid "FeatureFlags|Loading feature flags"
msgstr ""
+msgid "FeatureFlags|Loading user lists"
+msgstr ""
+
msgid "FeatureFlags|More information"
msgstr ""
@@ -10625,7 +10942,7 @@ msgstr ""
msgid "FeatureFlags|New feature flag"
msgstr ""
-msgid "FeatureFlags|New list"
+msgid "FeatureFlags|New user list"
msgstr ""
msgid "FeatureFlags|Percent of users"
@@ -10664,6 +10981,9 @@ msgstr ""
msgid "FeatureFlags|There was an error fetching the feature flags."
msgstr ""
+msgid "FeatureFlags|There was an error fetching the user lists."
+msgstr ""
+
msgid "FeatureFlags|There was an error retrieving user lists"
msgstr ""
@@ -10679,6 +10999,9 @@ msgstr ""
msgid "FeatureFlags|User List"
msgstr ""
+msgid "FeatureFlags|User Lists"
+msgstr ""
+
msgid "FeatureFlag|List"
msgstr ""
@@ -10706,15 +11029,6 @@ msgstr "二月"
msgid "Fetching incoming email"
msgstr ""
-msgid "Fetching licenses failed."
-msgstr ""
-
-msgid "Fetching licenses failed. The request endpoint was not found."
-msgstr ""
-
-msgid "Fetching licenses failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "File"
msgstr ""
@@ -10817,12 +11131,21 @@ msgstr ""
msgid "Filter by status"
msgstr ""
+msgid "Filter by test cases that are currently archived."
+msgstr ""
+
+msgid "Filter by test cases that are currently opened."
+msgstr ""
+
msgid "Filter by two-factor authentication"
msgstr ""
msgid "Filter by user"
msgstr ""
+msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
+msgstr ""
+
msgid "Filter pipelines"
msgstr ""
@@ -10838,7 +11161,7 @@ msgstr ""
msgid "Filter results..."
msgstr ""
-msgid "Filter your projects by name"
+msgid "Filter your repositories by name"
msgstr ""
msgid "Filter..."
@@ -10847,7 +11170,7 @@ msgstr ""
msgid "Find File"
msgstr ""
-msgid "Find bugs in your code with coverage-guided fuzzing"
+msgid "Find bugs in your code with coverage-guided fuzzing."
msgstr ""
msgid "Find by path"
@@ -10874,9 +11197,6 @@ msgstr ""
msgid "Finish editing this message first!"
msgstr ""
-msgid "Finish review"
-msgstr ""
-
msgid "Finish setting up your dedicated account for %{group_name}."
msgstr ""
@@ -10946,6 +11266,9 @@ msgstr ""
msgid "Footer message"
msgstr ""
+msgid "For a faster browsing experience, some files are collapsed by default."
+msgstr ""
+
msgid "For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
@@ -10955,6 +11278,9 @@ msgstr ""
msgid "For more info, read the documentation."
msgstr ""
+msgid "For more information on how the number of active users is calculated, see the %{self_managed_subscriptions_doc_link} documentation."
+msgstr ""
+
msgid "For more information, go to the "
msgstr ""
@@ -11093,6 +11419,9 @@ msgstr ""
msgid "Generate new token"
msgstr ""
+msgid "Generic package file size in bytes"
+msgstr ""
+
msgid "Geo"
msgstr ""
@@ -11354,6 +11683,9 @@ msgstr ""
msgid "Geo|Please refer to Geo Troubleshooting."
msgstr ""
+msgid "Geo|Primary node"
+msgstr ""
+
msgid "Geo|Project"
msgstr ""
@@ -11396,6 +11728,9 @@ msgstr ""
msgid "Geo|Review replication status, and resynchronize and reverify items with the primary node."
msgstr ""
+msgid "Geo|Secondary node"
+msgstr ""
+
msgid "Geo|Status"
msgstr ""
@@ -11435,6 +11770,9 @@ msgstr ""
msgid "Geo|URL must be a valid url (ex: https://gitlab.com)"
msgstr ""
+msgid "Geo|Undefined"
+msgstr ""
+
msgid "Geo|Unknown state"
msgstr ""
@@ -11510,10 +11848,16 @@ msgstr ""
msgid "GitHub import"
msgstr ""
+msgid "GitLab"
+msgstr ""
+
msgid "GitLab / Unsubscribe"
msgstr ""
-msgid "GitLab Enterprise Edition %{plan}"
+msgid "GitLab API"
+msgstr ""
+
+msgid "GitLab Billing Team."
msgstr ""
msgid "GitLab Group Runners can execute code for all the projects in this group."
@@ -11525,12 +11869,18 @@ msgstr ""
msgid "GitLab Issue"
msgstr ""
+msgid "GitLab Pages"
+msgstr ""
+
msgid "GitLab Service Desk is a simple way to allow people to create issues in your GitLab instance without needing their own user account. It provides a unique email address for end users to create issues in a project, and replies can be sent either through the GitLab interface or by email. End users will only see the thread through email."
msgstr ""
msgid "GitLab Shared Runners execute code of different projects on the same Runner unless you configure GitLab Runner Autoscale with MaxBuilds 1 (which it is on GitLab.com)."
msgstr ""
+msgid "GitLab Shell"
+msgstr ""
+
msgid "GitLab Support Bot"
msgstr ""
@@ -11540,7 +11890,7 @@ msgstr ""
msgid "GitLab User"
msgstr ""
-msgid "GitLab allows you to continue using your license even if you exceed the number of seats you purchased. You will be required to pay for these seats when you renew your license."
+msgid "GitLab Workhorse"
msgstr ""
msgid "GitLab commit"
@@ -11708,6 +12058,21 @@ msgstr ""
msgid "Gitlab Pages"
msgstr ""
+msgid "Gitpod"
+msgstr ""
+
+msgid "Gitpod|Add the URL to your Gitpod instance configured to read your GitLab projects."
+msgstr ""
+
+msgid "Gitpod|Enable Gitpod integration"
+msgstr ""
+
+msgid "Gitpod|Gitpod URL"
+msgstr ""
+
+msgid "Gitpod|e.g. https://gitpod.example.com"
+msgstr ""
+
msgid "Given access %{time_ago}"
msgstr ""
@@ -12215,9 +12580,6 @@ msgstr ""
msgid "GroupSAML|Valid SAML Response"
msgstr ""
-msgid "GroupSAML|With group managed accounts enabled, all the users without a group managed account will be excluded from the group."
-msgstr ""
-
msgid "GroupSAML|With prohibit outer forks flag enabled group members will be able to fork project only inside your group."
msgstr ""
@@ -12431,10 +12793,10 @@ msgstr ""
msgid "GroupsNew|Create group"
msgstr ""
-msgid "GroupsNew|GitLab group export"
+msgid "GroupsNew|Import"
msgstr ""
-msgid "GroupsNew|Import"
+msgid "GroupsNew|Import a GitLab group export file"
msgstr ""
msgid "GroupsNew|Import group"
@@ -12576,6 +12938,9 @@ msgid "Hide chart"
msgid_plural "Hide charts"
msgstr[0] ""
+msgid "Hide comments on this file"
+msgstr ""
+
msgid "Hide details"
msgstr ""
@@ -12619,6 +12984,15 @@ msgstr ""
msgid "Highest role:"
msgstr ""
+msgid "HighlightBar|Alert events:"
+msgstr ""
+
+msgid "HighlightBar|Alert start time:"
+msgstr ""
+
+msgid "HighlightBar|Original alert:"
+msgstr ""
+
msgid "History"
msgstr "æ­·å²ç´€éŒ„"
@@ -12796,6 +13170,9 @@ msgstr ""
msgid "If enabled, access to projects will be validated on an external service using their classification label."
msgstr ""
+msgid "If the number of active users exceeds the user limit, you will be charged for the number of %{users_over_license_link} at your next license reconciliation."
+msgstr ""
+
msgid "If there is no previous license or if the previous license has expired, some GitLab functionality will be blocked until a new, valid license is uploaded."
msgstr ""
@@ -12835,9 +13212,6 @@ msgstr ""
msgid "If your HTTP repository is not publicly accessible, add your credentials."
msgstr ""
-msgid "Iglu registry URL (optional)"
-msgstr ""
-
msgid "Ignore"
msgstr ""
@@ -12874,6 +13248,14 @@ msgstr ""
msgid "Import"
msgstr ""
+msgid "Import %d compatible repository"
+msgid_plural "Import %d compatible repositories"
+msgstr[0] ""
+
+msgid "Import %d repository"
+msgid_plural "Import %d repositories"
+msgstr[0] ""
+
msgid "Import CSV"
msgstr ""
@@ -12883,15 +13265,9 @@ msgstr ""
msgid "Import all compatible projects"
msgstr ""
-msgid "Import all compatible repositories"
-msgstr ""
-
msgid "Import all projects"
msgstr ""
-msgid "Import all repositories"
-msgstr ""
-
msgid "Import an exported GitLab project"
msgstr ""
@@ -12979,6 +13355,9 @@ msgstr ""
msgid "ImportProjects|Error importing repository %{project_safe_import_url} into %{project_full_path} - %{message}"
msgstr ""
+msgid "ImportProjects|Import repositories"
+msgstr ""
+
msgid "ImportProjects|Importing the project failed"
msgstr ""
@@ -12991,7 +13370,7 @@ msgstr ""
msgid "ImportProjects|Requesting your %{provider} repositories failed"
msgstr ""
-msgid "ImportProjects|Select the projects you want to import"
+msgid "ImportProjects|Select the repositories you want to import"
msgstr ""
msgid "ImportProjects|The remote data could not be imported."
@@ -13027,9 +13406,6 @@ msgstr ""
msgid "In order to enable Service Desk for your instance, you must first set up incoming email."
msgstr ""
-msgid "In order to gather accurate feature usage data, it can take 1 to 2 weeks to see your index."
-msgstr ""
-
msgid "In order to personalize your experience with GitLab%{br_tag}we would like to know a bit more about you."
msgstr ""
@@ -13060,18 +13436,30 @@ msgstr ""
msgid "IncidentManagement|Create incident"
msgstr ""
+msgid "IncidentManagement|Critical - S1"
+msgstr ""
+
msgid "IncidentManagement|Date created"
msgstr ""
msgid "IncidentManagement|Display your incidents in a dedicated view"
msgstr ""
+msgid "IncidentManagement|High - S2"
+msgstr ""
+
msgid "IncidentManagement|Incident"
msgstr ""
msgid "IncidentManagement|Incidents"
msgstr ""
+msgid "IncidentManagement|Low - S4"
+msgstr ""
+
+msgid "IncidentManagement|Medium - S3"
+msgstr ""
+
msgid "IncidentManagement|No incidents to display."
msgstr ""
@@ -13084,6 +13472,9 @@ msgstr ""
msgid "IncidentManagement|Published to status page"
msgstr ""
+msgid "IncidentManagement|Severity"
+msgstr ""
+
msgid "IncidentManagement|There are no closed incidents"
msgstr ""
@@ -13093,6 +13484,9 @@ msgstr ""
msgid "IncidentManagement|Unassigned"
msgstr ""
+msgid "IncidentManagement|Unknown"
+msgstr ""
+
msgid "IncidentManagement|Unpublished"
msgstr ""
@@ -13114,6 +13508,15 @@ msgstr ""
msgid "Incidents"
msgstr ""
+msgid "Incident|Alert details"
+msgstr ""
+
+msgid "Incident|Summary"
+msgstr ""
+
+msgid "Incident|There was an issue loading alert data. Please try again."
+msgstr ""
+
msgid "Include a Terms of Service agreement and Privacy Policy that all users must accept."
msgstr ""
@@ -13174,6 +13577,9 @@ msgstr ""
msgid "Information about additional Pages templates and how to install them can be found in our %{pages_getting_started_guide}."
msgstr ""
+msgid "Inherited"
+msgstr ""
+
msgid "Inherited:"
msgstr ""
@@ -13253,7 +13659,22 @@ msgstr ""
msgid "Instance administrators group already exists"
msgstr ""
-msgid "Instance license"
+msgid "InstanceStatistics|Groups"
+msgstr ""
+
+msgid "InstanceStatistics|Issues"
+msgstr ""
+
+msgid "InstanceStatistics|Merge Requests"
+msgstr ""
+
+msgid "InstanceStatistics|Pipelines"
+msgstr ""
+
+msgid "InstanceStatistics|Projects"
+msgstr ""
+
+msgid "InstanceStatistics|Users"
msgstr ""
msgid "Integration"
@@ -13265,6 +13686,12 @@ msgstr ""
msgid "Integrations"
msgstr ""
+msgid "Integrations|%{integration} settings saved and active."
+msgstr ""
+
+msgid "Integrations|%{integration} settings saved, but not active."
+msgstr ""
+
msgid "Integrations|All details"
msgstr ""
@@ -13274,6 +13701,12 @@ msgstr ""
msgid "Integrations|Comment settings:"
msgstr ""
+msgid "Integrations|Connection failed. Please check your settings."
+msgstr ""
+
+msgid "Integrations|Connection successful."
+msgstr ""
+
msgid "Integrations|Default settings are inherited from the group level."
msgstr ""
@@ -13289,6 +13722,15 @@ msgstr ""
msgid "Integrations|Includes commit title and branch"
msgstr ""
+msgid "Integrations|Projects using custom settings will not be impacted unless the project owner chooses to use instance-level defaults."
+msgstr ""
+
+msgid "Integrations|Save settings?"
+msgstr ""
+
+msgid "Integrations|Saving will update the default settings for all projects that are not using custom settings."
+msgstr ""
+
msgid "Integrations|Standard"
msgstr ""
@@ -13421,6 +13863,9 @@ msgstr ""
msgid "Invitation"
msgstr ""
+msgid "Invitation declined"
+msgstr ""
+
msgid "Invite"
msgstr ""
@@ -13472,6 +13917,42 @@ 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|%{linkStart}Read more%{linkEnd} about role permissions"
+msgstr ""
+
+msgid "InviteMembersModal|Access expiration date (optional)"
+msgstr ""
+
+msgid "InviteMembersModal|Cancel"
+msgstr ""
+
+msgid "InviteMembersModal|Choose a role permission"
+msgstr ""
+
+msgid "InviteMembersModal|GitLab member or Email address"
+msgstr ""
+
+msgid "InviteMembersModal|Invite"
+msgstr ""
+
+msgid "InviteMembersModal|Invite team members"
+msgstr ""
+
+msgid "InviteMembersModal|Search for members to invite"
+msgstr ""
+
+msgid "InviteMembersModal|User not invited. Feature coming soon!"
+msgstr ""
+
+msgid "InviteMembersModal|Users were succesfully added"
+msgstr ""
+
+msgid "InviteMembersModal|You're inviting members to the %{group_name} group"
+msgstr ""
+
+msgid "InviteMembers|Invite team members"
+msgstr ""
+
msgid "Invited"
msgstr ""
@@ -13526,10 +14007,13 @@ msgstr ""
msgid "Issue cannot be found."
msgstr ""
+msgid "Issue created from vulnerability %{vulnerability_link}"
+msgstr ""
+
msgid "Issue events"
msgstr "議題事件"
-msgid "Issue first depoloyed to production"
+msgid "Issue first deployed to production"
msgstr ""
msgid "Issue label"
@@ -13607,6 +14091,9 @@ msgstr ""
msgid "IssueTracker|Custom issue tracker"
msgstr ""
+msgid "IssueTracker|EWM work items tracker"
+msgstr ""
+
msgid "IssueTracker|Redmine issue tracker"
msgstr ""
@@ -13673,6 +14160,9 @@ msgstr ""
msgid "It looks like you have some draft commits in this branch."
msgstr ""
+msgid "It may be several days before you see feature usage data."
+msgstr ""
+
msgid "It must have a header row and at least two columns: the first column is the issue title and the second column is the issue description. The separator is automatically detected."
msgstr ""
@@ -13955,15 +14445,15 @@ msgstr ""
msgid "Join Zoom meeting"
msgstr ""
+msgid "Joined %{time_ago}"
+msgstr ""
+
msgid "Jul"
msgstr "七月"
msgid "July"
msgstr "七月"
-msgid "Jump to first unresolved thread"
-msgstr ""
-
msgid "Jump to next unresolved thread"
msgstr ""
@@ -13997,6 +14487,9 @@ msgstr ""
msgid "Keyboard shortcuts"
msgstr ""
+msgid "KeyboardKey|Ctrl+"
+msgstr ""
+
msgid "Keys"
msgstr ""
@@ -14045,6 +14538,9 @@ msgstr ""
msgid "LDAP Synchronization"
msgstr ""
+msgid "LDAP group settings"
+msgstr ""
+
msgid "LDAP settings"
msgstr ""
@@ -14054,6 +14550,9 @@ msgstr ""
msgid "LDAP sync in progress. This could take a few minutes. Refresh the page to see the changes."
msgstr ""
+msgid "LDAP synchronizations"
+msgstr ""
+
msgid "LFS"
msgstr ""
@@ -14133,7 +14632,16 @@ msgid "Last %d day"
msgid_plural "Last %d days"
msgstr[0] "最近 %d 天"
-msgid "Last %{days} days"
+msgid "Last 2 weeks"
+msgstr ""
+
+msgid "Last 30 days"
+msgstr ""
+
+msgid "Last 60 days"
+msgstr ""
+
+msgid "Last 90 days"
msgstr ""
msgid "Last Accessed On"
@@ -14211,6 +14719,9 @@ msgstr ""
msgid "Last used on:"
msgstr ""
+msgid "Last week"
+msgstr ""
+
msgid "LastCommit|authored"
msgstr ""
@@ -14226,6 +14737,9 @@ msgstr ""
msgid "Latest pipeline for the most recent commit on this branch"
msgstr ""
+msgid "Launch a ready-to-code development environment for your project."
+msgstr ""
+
msgid "Lead"
msgstr ""
@@ -14599,6 +15113,9 @@ msgstr ""
msgid "List of all merge commits"
msgstr ""
+msgid "List options"
+msgstr ""
+
msgid "List settings"
msgstr ""
@@ -14611,9 +15128,6 @@ msgstr "列表顯示"
msgid "List your Bitbucket Server repositories"
msgstr ""
-msgid "Lists"
-msgstr ""
-
msgid "Live preview"
msgstr ""
@@ -14860,6 +15374,12 @@ msgstr ""
msgid "Mark as done"
msgstr ""
+msgid "Mark as draft"
+msgstr ""
+
+msgid "Mark as ready"
+msgstr ""
+
msgid "Mark as resolved"
msgstr ""
@@ -14881,6 +15401,24 @@ msgstr ""
msgid "Markdown is supported"
msgstr ""
+msgid "MarkdownEditor|Add a link (%{modifierKey}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add a link (%{modifier_key}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifierKey}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifier_key}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifierKey}I)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifier_key}I)"
+msgstr ""
+
msgid "Marked For Deletion At - %{deletion_time}"
msgstr ""
@@ -14965,7 +15503,25 @@ msgstr ""
msgid "Max access level"
msgstr ""
-msgid "Max seats used"
+msgid "Max role"
+msgstr ""
+
+msgid "Max size 15 MB"
+msgstr ""
+
+msgid "Maximum Conan package file size in bytes"
+msgstr ""
+
+msgid "Maximum Maven package file size in bytes"
+msgstr ""
+
+msgid "Maximum NPM package file size in bytes"
+msgstr ""
+
+msgid "Maximum NuGet package file size in bytes"
+msgstr ""
+
+msgid "Maximum PyPI package file size in bytes"
msgstr ""
msgid "Maximum Users:"
@@ -15097,6 +15653,18 @@ msgstr ""
msgid "Members with access to %{strong_start}%{group_name}%{strong_end}"
msgstr ""
+msgid "Members|%{time} by %{user}"
+msgstr ""
+
+msgid "Members|Expired"
+msgstr ""
+
+msgid "Members|No expiration set"
+msgstr ""
+
+msgid "Members|in %{time}"
+msgstr ""
+
msgid "Memory Usage"
msgstr ""
@@ -15283,9 +15851,6 @@ msgstr ""
msgid "MergeRequests|Thread will be unresolved"
msgstr ""
-msgid "MergeRequests|Toggle comments for this file"
-msgstr ""
-
msgid "MergeRequests|View file @ %{commitId}"
msgstr ""
@@ -15346,6 +15911,9 @@ msgstr ""
msgid "Merging immediately isn't recommended as it may negatively impact the existing merge train. Read the %{docsLinkStart}documentation%{docsLinkEnd} for more information."
msgstr ""
+msgid "Message"
+msgstr ""
+
msgid "Messages"
msgstr ""
@@ -15729,18 +16297,12 @@ msgid "Milestone"
msgid_plural "Milestones"
msgstr[0] ""
-msgid "Milestone does not support burnup charts"
-msgstr ""
-
msgid "Milestone lists not available with your current license"
msgstr "ç›®å‰è¨±å¯è­‰ç„¡æ³•ä½¿ç”¨é‡Œç¨‹ç¢‘列表"
msgid "Milestone lists show all issues from the selected milestone."
msgstr "里程碑列表將顯示所é¸é‡Œç¨‹ç¢‘的所有議題"
-msgid "Milestone must have a start and due date"
-msgstr ""
-
msgid "MilestoneSidebar|Closed:"
msgstr ""
@@ -16107,6 +16669,9 @@ msgstr ""
msgid "Namespace"
msgstr ""
+msgid "Namespace ID:"
+msgstr ""
+
msgid "Namespace is empty"
msgstr ""
@@ -16191,6 +16756,9 @@ msgstr ""
msgid "NetworkPolicies|Allow all outbound traffic from %{selector} to %{ruleSelector} on %{ports}"
msgstr ""
+msgid "NetworkPolicies|Are you sure you want to delete this policy? This action cannot be undone."
+msgstr ""
+
msgid "NetworkPolicies|Choose whether to enforce this policy."
msgstr ""
@@ -16200,12 +16768,21 @@ msgstr ""
msgid "NetworkPolicies|Define this policy's location, conditions and actions."
msgstr ""
+msgid "NetworkPolicies|Delete policy"
+msgstr ""
+
+msgid "NetworkPolicies|Delete policy: %{policy}"
+msgstr ""
+
msgid "NetworkPolicies|Deny all traffic"
msgstr ""
msgid "NetworkPolicies|Description"
msgstr ""
+msgid "NetworkPolicies|Edit policy"
+msgstr ""
+
msgid "NetworkPolicies|Editor mode"
msgstr ""
@@ -16233,6 +16810,9 @@ msgstr ""
msgid "NetworkPolicies|Name"
msgstr ""
+msgid "NetworkPolicies|Namespace"
+msgstr ""
+
msgid "NetworkPolicies|Network Policy"
msgstr ""
@@ -16284,6 +16864,9 @@ msgstr ""
msgid "NetworkPolicies|Rules"
msgstr ""
+msgid "NetworkPolicies|Save changes"
+msgstr ""
+
msgid "NetworkPolicies|Something went wrong, failed to update policy"
msgstr ""
@@ -16296,6 +16879,9 @@ msgstr ""
msgid "NetworkPolicies|Traffic that does not match any rule will be blocked."
msgstr ""
+msgid "NetworkPolicies|Unable to parse policy"
+msgstr ""
+
msgid "NetworkPolicies|YAML editor"
msgstr ""
@@ -16408,6 +16994,9 @@ msgstr ""
msgid "New Snippet"
msgstr ""
+msgid "New Test Case"
+msgstr ""
+
msgid "New User"
msgstr ""
@@ -16507,6 +17096,9 @@ msgstr "æ–°å­ç¾¤çµ„"
msgid "New tag"
msgstr "新增標籤"
+msgid "New test case"
+msgstr ""
+
msgid "New users set to external"
msgstr ""
@@ -16579,7 +17171,7 @@ msgstr ""
msgid "No changes"
msgstr ""
-msgid "No changes between %{ref_start}%{source_branch}%{ref_end} and %{ref_start}%{target_branch}%{ref_end}"
+msgid "No changes between %{sourceBranch} and %{targetBranch}"
msgstr ""
msgid "No child epics match applied filters"
@@ -16594,6 +17186,9 @@ msgstr ""
msgid "No containers available"
msgstr ""
+msgid "No content to show"
+msgstr ""
+
msgid "No contributions"
msgstr ""
@@ -16669,9 +17264,6 @@ msgstr ""
msgid "No license. All rights reserved"
msgstr ""
-msgid "No licenses found."
-msgstr ""
-
msgid "No matches found"
msgstr ""
@@ -16684,6 +17276,9 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No members found"
+msgstr ""
+
msgid "No merge requests found"
msgstr ""
@@ -16705,6 +17300,9 @@ msgstr ""
msgid "No parent group"
msgstr ""
+msgid "No plan"
+msgstr ""
+
msgid "No pods available"
msgstr ""
@@ -16801,6 +17399,12 @@ msgstr "ç„¡"
msgid "Not Implemented"
msgstr ""
+msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+msgstr ""
+
+msgid "Not all browsers support WebAuthn. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even from an unsupported browser."
+msgstr ""
+
msgid "Not all data has been processed yet, the accuracy of the chart for the selected timeframe is limited."
msgstr ""
@@ -16897,6 +17501,9 @@ msgstr ""
msgid "Notification settings saved"
msgstr ""
+msgid "NotificationEvent|Change reviewer merge request"
+msgstr ""
+
msgid "NotificationEvent|Close issue"
msgstr "關閉議題"
@@ -17059,10 +17666,7 @@ msgstr ""
msgid "On track"
msgstr ""
-msgid "OnDemandScans|Attached branch"
-msgstr ""
-
-msgid "OnDemandScans|Attached branch is where the scan job runs."
+msgid "OnDemandScans|Could not fetch scanner profiles. Please refresh the page, or try again later."
msgstr ""
msgid "OnDemandScans|Could not fetch site profiles. Please refresh the page, or try again later."
@@ -17071,6 +17675,9 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
+msgid "OnDemandScans|Create a new scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Create a new site profile"
msgstr ""
@@ -17083,6 +17690,9 @@ msgstr ""
msgid "OnDemandScans|New on-demand DAST scan"
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 ""
@@ -17092,16 +17702,10 @@ msgstr ""
msgid "OnDemandScans|On-demand scans run outside the DevOps cycle and find vulnerabilities in your projects. %{learnMoreLinkStart}Learn more%{learnMoreLinkEnd}"
msgstr ""
-msgid "OnDemandScans|Only a passive scan can be performed on demand."
-msgstr ""
-
-msgid "OnDemandScans|Passive"
-msgstr ""
-
msgid "OnDemandScans|Run scan"
msgstr ""
-msgid "OnDemandScans|Scan mode"
+msgid "OnDemandScans|Scanner profile"
msgstr ""
msgid "OnDemandScans|Scanner settings"
@@ -17113,9 +17717,15 @@ msgstr ""
msgid "OnDemandScans|Select one of the existing profiles"
msgstr ""
+msgid "OnDemandScans|Site profile"
+msgstr ""
+
msgid "OnDemandScans|Site profiles"
msgstr ""
+msgid "OnDemandScans|Use existing scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Use existing site profile"
msgstr ""
@@ -17213,9 +17823,6 @@ msgstr ""
msgid "Open Selection"
msgstr ""
-msgid "Open Web IDE"
-msgstr ""
-
msgid "Open comment type dropdown"
msgstr ""
@@ -17321,6 +17928,9 @@ msgstr ""
msgid "Origin"
msgstr ""
+msgid "Orphaned member"
+msgstr ""
+
msgid "Other Labels"
msgstr ""
@@ -17336,6 +17946,9 @@ msgstr ""
msgid "Other visibility settings have been disabled by the administrator."
msgstr ""
+msgid "Our documentation includes an example DevOps Score report."
+msgstr ""
+
msgid "Out-of-compliance with this project's policies and should be removed"
msgstr ""
@@ -17360,6 +17973,9 @@ msgstr "概覽"
msgid "Overwrite diverged branches"
msgstr ""
+msgid "Owned by %{image_tag}"
+msgstr ""
+
msgid "Owned by anyone"
msgstr ""
@@ -17381,6 +17997,9 @@ msgstr ""
msgid "Package deleted successfully"
msgstr ""
+msgid "Package file size limits"
+msgstr ""
+
msgid "Package recipe already exists"
msgstr ""
@@ -17396,9 +18015,6 @@ msgstr ""
msgid "Package type must be PyPi"
msgstr ""
-msgid "Package was removed"
-msgstr ""
-
msgid "PackageRegistry|%{name} version %{version} was created %{datetime}"
msgstr ""
@@ -17540,12 +18156,18 @@ msgstr ""
msgid "PackageRegistry|NuGet Command"
msgstr ""
+msgid "PackageRegistry|Package Registry"
+msgstr ""
+
msgid "PackageRegistry|Pip Command"
msgstr ""
msgid "PackageRegistry|Pipeline %{link} triggered %{datetime} by %{author}"
msgstr ""
+msgid "PackageRegistry|Publish and share packages for a variety of common package managers. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "PackageRegistry|Published to the %{project} Package Registry %{datetime}"
msgstr ""
@@ -17645,6 +18267,9 @@ msgstr ""
msgid "Page not found"
msgstr ""
+msgid "Page settings"
+msgstr ""
+
msgid "Page was successfully deleted"
msgstr ""
@@ -17786,7 +18411,7 @@ msgstr ""
msgid "Paste issue link"
msgstr ""
-msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Don't use your private SSH key."
+msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Do not paste your private SSH key, as that can compromise your identity."
msgstr ""
msgid "Patch to apply"
@@ -17813,6 +18438,9 @@ msgstr ""
msgid "Pending"
msgstr ""
+msgid "Pending comments"
+msgstr ""
+
msgid "People without permission will never get a notification and won't be able to comment."
msgstr ""
@@ -18011,6 +18639,9 @@ msgstr ""
msgid "Pipelines|Build with confidence"
msgstr ""
+msgid "Pipelines|By revoking a trigger you will break any processes making use of it. Are you sure?"
+msgstr ""
+
msgid "Pipelines|CI Lint"
msgstr ""
@@ -18023,6 +18654,15 @@ msgstr ""
msgid "Pipelines|Continuous Integration can help catch bugs by running your tests automatically, while Continuous Deployment can help you deliver code to your product environment."
msgstr ""
+msgid "Pipelines|Copy trigger token"
+msgstr ""
+
+msgid "Pipelines|Description"
+msgstr ""
+
+msgid "Pipelines|Edit"
+msgstr ""
+
msgid "Pipelines|Get started with Pipelines"
msgstr ""
@@ -18038,15 +18678,27 @@ msgstr ""
msgid "Pipelines|It is recommended the code is reviewed thoroughly before running this pipeline with the parent project's CI resource."
msgstr ""
+msgid "Pipelines|Last Used"
+msgstr ""
+
msgid "Pipelines|Loading Pipelines"
msgstr ""
msgid "Pipelines|More Information"
msgstr ""
+msgid "Pipelines|No triggers have been created yet. Add one using the form above."
+msgstr ""
+
+msgid "Pipelines|Owner"
+msgstr ""
+
msgid "Pipelines|Project cache successfully reset."
msgstr ""
+msgid "Pipelines|Revoke"
+msgstr ""
+
msgid "Pipelines|Run Pipeline"
msgstr ""
@@ -18071,6 +18723,15 @@ msgstr ""
msgid "Pipelines|This project is not currently set up to run pipelines."
msgstr ""
+msgid "Pipelines|Token"
+msgstr ""
+
+msgid "Pipelines|Trigger user has insufficient permissions to project"
+msgstr ""
+
+msgid "Pipelines|invalid"
+msgstr ""
+
msgid "Pipelines|parent"
msgstr ""
@@ -18329,10 +18990,10 @@ msgstr ""
msgid "Please provide attributes to update"
msgstr ""
-msgid "Please refer to %{docs_url}"
+msgid "Please reach out if you have any questions and we'll be happy to assist."
msgstr ""
-msgid "Please retype the email address."
+msgid "Please refer to %{docs_url}"
msgstr ""
msgid "Please select"
@@ -18362,6 +19023,9 @@ msgstr ""
msgid "Please set a new password before proceeding."
msgstr ""
+msgid "Please share your feedback about %{featureName} %{linkStart}in this issue%{linkEnd} to help us improve the experience."
+msgstr ""
+
msgid "Please solve the reCAPTCHA"
msgstr ""
@@ -18665,6 +19329,9 @@ msgstr ""
msgid "Profiles| You are going to change the username %{currentUsernameBold} to %{newUsernameBold}. Profile and projects will be redirected to the %{newUsername} namespace but this redirect will expire once the %{currentUsername} namespace is registered by another user or group. Please update your Git repository remotes as soon as possible."
msgstr ""
+msgid "Profiles|%{provider} Active"
+msgstr ""
+
msgid "Profiles|@username"
msgstr ""
@@ -18716,7 +19383,7 @@ msgstr ""
msgid "Profiles|Commit email"
msgstr ""
-msgid "Profiles|Connect"
+msgid "Profiles|Connect %{provider}"
msgstr ""
msgid "Profiles|Connected Accounts"
@@ -18740,6 +19407,9 @@ msgstr ""
msgid "Profiles|Disconnect"
msgstr ""
+msgid "Profiles|Disconnect %{provider}"
+msgstr ""
+
msgid "Profiles|Do not show on profile"
msgstr ""
@@ -18764,7 +19434,7 @@ msgstr ""
msgid "Profiles|Full name"
msgstr ""
-msgid "Profiles|Give your individual key a title. This will be publically visible."
+msgid "Profiles|Give your individual key a title."
msgstr ""
msgid "Profiles|Include private contributions on my profile"
@@ -18854,7 +19524,7 @@ msgstr ""
msgid "Profiles|The maximum file size allowed is 200KB."
msgstr ""
-msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it?"
+msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it? It will be publicly visible."
msgstr ""
msgid "Profiles|This email will be displayed on your public profile"
@@ -18929,6 +19599,9 @@ msgstr ""
msgid "Profiles|You don't have access to delete this user."
msgstr ""
+msgid "Profiles|You must transfer ownership or delete groups you are an owner of before you can delete your account"
+msgstr ""
+
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
@@ -19517,6 +20190,9 @@ msgstr ""
msgid "ProjectTemplates|GitLab Cluster Management"
msgstr ""
+msgid "ProjectTemplates|Gitpod/Spring Petclinic"
+msgstr ""
+
msgid "ProjectTemplates|Go Micro"
msgstr ""
@@ -20126,6 +20802,9 @@ msgstr ""
msgid "Publish to status page"
msgstr ""
+msgid "Published"
+msgstr ""
+
msgid "Published on status page"
msgstr ""
@@ -20243,9 +20922,15 @@ msgstr ""
msgid "Quick range"
msgstr ""
+msgid "Quickly and easily edit multiple files in your project."
+msgstr ""
+
msgid "README"
msgstr ""
+msgid "Rails"
+msgstr ""
+
msgid "Rake Tasks Help"
msgstr ""
@@ -20364,10 +21049,13 @@ msgstr ""
msgid "Register Two-Factor Authenticator"
msgstr ""
-msgid "Register U2F device"
+msgid "Register Universal Two-Factor (U2F) Device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register WebAuthn Device"
+msgstr ""
+
+msgid "Register device"
msgstr ""
msgid "Register for GitLab"
@@ -20379,9 +21067,6 @@ msgstr ""
msgid "Register with two-factor app"
msgstr ""
-msgid "Registration"
-msgstr ""
-
msgid "Registration|Checkout"
msgstr ""
@@ -20497,9 +21182,6 @@ msgstr ""
msgid "Release|Something went wrong while saving the release details"
msgstr ""
-msgid "Remediated: needs review"
-msgstr ""
-
msgid "Remediations"
msgstr ""
@@ -20605,6 +21287,9 @@ msgstr ""
msgid "Remove priority"
msgstr ""
+msgid "Remove report"
+msgstr ""
+
msgid "Remove secondary node"
msgstr ""
@@ -20617,6 +21302,12 @@ msgstr ""
msgid "Remove time estimate"
msgstr ""
+msgid "Remove user & report"
+msgstr ""
+
+msgid "Remove user from group"
+msgstr ""
+
msgid "Removed"
msgstr ""
@@ -20698,9 +21389,6 @@ msgstr "刪除截止日期"
msgid "Removes time estimate."
msgstr ""
-msgid "Removing license…"
-msgstr ""
-
msgid "Removing this group also removes all child projects, including archived projects, and their resources."
msgstr ""
@@ -20785,6 +21473,9 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
+msgid "Reported by %{reporter}"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -20870,6 +21561,27 @@ msgstr ""
msgid "Repositories"
msgstr ""
+msgid "Repositories Analytics"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download Historic Test Coverage Data"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download historic test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Historic Test Coverage Data is available in raw format (.csv) for further analysis."
+msgstr ""
+
+msgid "RepositoriesAnalytics|Test Code Coverage"
+msgstr ""
+
+msgid "RepositoriesAnalytics|There was an error fetching the projects."
+msgstr ""
+
msgid "Repository"
msgstr "存儲庫"
@@ -20948,9 +21660,15 @@ msgstr ""
msgid "Request parameter %{param} is missing."
msgstr ""
+msgid "Request review from"
+msgstr ""
+
msgid "Request to link SAML account must be authorized"
msgstr ""
+msgid "Requested"
+msgstr ""
+
msgid "Requested %{time_ago}"
msgstr ""
@@ -20969,6 +21687,9 @@ msgstr ""
msgid "Requests to these domain(s)/address(es) on the local network will be allowed when local requests from hooks and services are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 or 127.0.0.0/28 are supported. Domain wildcards are not supported currently. Use comma, semicolon, or newline to separate multiple entries. The allowlist can hold a maximum of 1000 entries. Domains should use IDNA encoding. Ex: example.com, 192.168.1.1, 127.0.0.0/28, xn--itlab-j1a.com."
msgstr ""
+msgid "Require admin approval for new sign-ups"
+msgstr ""
+
msgid "Require all users in this group to setup Two-factor authentication"
msgstr ""
@@ -21094,9 +21815,6 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
-msgid "Resolved by %{resolvedByName}"
-msgstr ""
-
msgid "Resolves IP addresses once and uses them to submit requests"
msgstr ""
@@ -21215,6 +21933,13 @@ msgstr ""
msgid "ReviewApp|Enable Review App"
msgstr ""
+msgid "Reviewer"
+msgid_plural "%d Reviewers"
+msgstr[0] ""
+
+msgid "Reviewer(s)"
+msgstr ""
+
msgid "Reviewing"
msgstr ""
@@ -21254,6 +21979,9 @@ msgstr ""
msgid "Rook"
msgstr ""
+msgid "Ruby"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -21332,6 +22060,63 @@ msgstr ""
msgid "Runners page."
msgstr ""
+msgid "Runners|Active"
+msgstr ""
+
+msgid "Runners|Architecture"
+msgstr ""
+
+msgid "Runners|Can run untagged jobs"
+msgstr ""
+
+msgid "Runners|Description"
+msgstr ""
+
+msgid "Runners|Group"
+msgstr ""
+
+msgid "Runners|IP Address"
+msgstr ""
+
+msgid "Runners|Last contact"
+msgstr ""
+
+msgid "Runners|Locked to this project"
+msgstr ""
+
+msgid "Runners|Maximum job timeout"
+msgstr ""
+
+msgid "Runners|Name"
+msgstr ""
+
+msgid "Runners|Platform"
+msgstr ""
+
+msgid "Runners|Property Name"
+msgstr ""
+
+msgid "Runners|Protected"
+msgstr ""
+
+msgid "Runners|Revision"
+msgstr ""
+
+msgid "Runners|Shared"
+msgstr ""
+
+msgid "Runners|Specific"
+msgstr ""
+
+msgid "Runners|Tags"
+msgstr ""
+
+msgid "Runners|Value"
+msgstr ""
+
+msgid "Runners|Version"
+msgstr ""
+
msgid "Runners|You have used %{quotaUsed} out of %{quotaLimit} of your shared Runners pipeline minutes."
msgstr ""
@@ -21344,6 +22129,9 @@ msgstr ""
msgid "Runs a number of housekeeping tasks within the current repository, such as compressing file revisions and removing unreachable objects."
msgstr ""
+msgid "SAML"
+msgstr ""
+
msgid "SAML SSO"
msgstr ""
@@ -21395,6 +22183,9 @@ msgstr "星期六"
msgid "Save"
msgstr ""
+msgid "Save %{name} size limits"
+msgstr ""
+
msgid "Save Changes"
msgstr ""
@@ -21425,9 +22216,6 @@ msgstr "ä¿å­˜æµæ°´ç·šè¨ˆåŠƒ"
msgid "Save space and find tags in the Container Registry more easily. Enable the cleanup policy to remove stale tags and keep only the ones you need."
msgstr ""
-msgid "Save template"
-msgstr ""
-
msgid "Save variables"
msgstr ""
@@ -21470,9 +22258,6 @@ msgstr "æµæ°´ç·šè¨ˆåŠƒ"
msgid "Scope"
msgstr ""
-msgid "Scope not supported with disabled 'users_search' feature!"
-msgstr ""
-
msgid "Scoped issue boards"
msgstr ""
@@ -21599,9 +22384,6 @@ msgstr ""
msgid "Search requirements"
msgstr ""
-msgid "Search results…"
-msgstr ""
-
msgid "Search users"
msgstr ""
@@ -21671,6 +22453,10 @@ msgid "SearchResults|commit"
msgid_plural "SearchResults|commits"
msgstr[0] ""
+msgid "SearchResults|epic"
+msgid_plural "SearchResults|epics"
+msgstr[0] ""
+
msgid "SearchResults|issue"
msgid_plural "SearchResults|issues"
msgstr[0] ""
@@ -21708,10 +22494,10 @@ msgstr ""
msgid "Seat Link is disabled, and cannot be configured through this form."
msgstr ""
-msgid "Seats currently in use"
+msgid "Seats usage data as of %{last_enqueue_time}"
msgstr ""
-msgid "Seats in license"
+msgid "Seats usage data is updated every day at 12:00pm UTC"
msgstr ""
msgid "Secondary"
@@ -21765,6 +22551,9 @@ msgstr ""
msgid "SecurityConfiguration|Available for on-demand DAST"
msgstr ""
+msgid "SecurityConfiguration|By default, all analyzers are applied in order to cover all languages across your project, and only run if the language is detected in the Merge Request."
+msgstr ""
+
msgid "SecurityConfiguration|Configure"
msgstr ""
@@ -21795,16 +22584,19 @@ msgstr ""
msgid "SecurityConfiguration|Manage"
msgstr ""
+msgid "SecurityConfiguration|More information"
+msgstr ""
+
msgid "SecurityConfiguration|Not enabled"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|Security Control"
+msgid "SecurityConfiguration|SAST Configuration"
msgstr ""
-msgid "SecurityConfiguration|See documentation"
+msgid "SecurityConfiguration|Security Control"
msgstr ""
msgid "SecurityConfiguration|Status"
@@ -21816,6 +22608,9 @@ msgstr ""
msgid "SecurityConfiguration|Using custom settings. You won't receive automatic updates on this variable. %{anchorStart}Restore to default%{anchorEnd}"
msgstr ""
+msgid "SecurityConfiguration|View history"
+msgstr ""
+
msgid "SecurityConfiguration|You can quickly enable all security scanning tools by enabling %{linkStart}Auto DevOps%{linkEnd}."
msgstr ""
@@ -21894,9 +22689,6 @@ msgstr ""
msgid "SecurityReports|Learn more about setting up your dashboard"
msgstr ""
-msgid "SecurityReports|Load more vulnerabilities"
-msgstr ""
-
msgid "SecurityReports|Monitor vulnerabilities in your code"
msgstr ""
@@ -22176,7 +22968,7 @@ msgstr ""
msgid "Select status"
msgstr ""
-msgid "Select strategy activation method"
+msgid "Select strategy activation method."
msgstr ""
msgid "Select subscription"
@@ -22191,7 +22983,7 @@ msgstr ""
msgid "Select the custom project template source group."
msgstr ""
-msgid "Select timeframe"
+msgid "Select the environment scope for this feature flag."
msgstr ""
msgid "Select timezone"
@@ -22440,6 +23232,9 @@ msgstr ""
msgid "Set iteration"
msgstr ""
+msgid "Set limit to 0 to allow any file size."
+msgstr ""
+
msgid "Set max session time for web terminal."
msgstr ""
@@ -22518,10 +23313,13 @@ msgstr ""
msgid "Set up a %{type} Runner manually"
msgstr ""
+msgid "Set up a hardware device as a second factor to sign in."
+msgstr ""
+
msgid "Set up assertions/attributes/claims (email, first_name, last_name) and NameID according to %{docsLinkStart}the documentation %{icon}%{docsLinkEnd}"
msgstr ""
-msgid "Set up new U2F device"
+msgid "Set up new device"
msgstr ""
msgid "Set up new password"
@@ -22590,6 +23388,9 @@ msgstr ""
msgid "Sets weight to %{weight}."
msgstr ""
+msgid "Setting this to 0 means using the system default timeout value."
+msgstr ""
+
msgid "Settings"
msgstr ""
@@ -22605,6 +23406,15 @@ msgstr ""
msgid "Severity"
msgstr ""
+msgid "SeverityWidget|Severity"
+msgstr ""
+
+msgid "SeverityWidget|Severity: %{severity}"
+msgstr ""
+
+msgid "SeverityWidget|There was an error while updating severity."
+msgstr ""
+
msgid "Shards (%{shards})"
msgstr ""
@@ -22650,6 +23460,9 @@ msgstr ""
msgid "Show all requirements."
msgstr ""
+msgid "Show all test cases."
+msgstr ""
+
msgid "Show archived projects"
msgstr ""
@@ -22662,6 +23475,9 @@ msgstr ""
msgid "Show comments"
msgstr ""
+msgid "Show comments on this file"
+msgstr ""
+
msgid "Show comments only"
msgstr "åªé¡¯ç¤ºç•™è¨€"
@@ -22707,6 +23523,12 @@ msgstr ""
msgid "Show parent subgroups"
msgstr ""
+msgid "Show the Closed list"
+msgstr ""
+
+msgid "Show the Open list"
+msgstr ""
+
msgid "Show whitespace changes"
msgstr ""
@@ -22748,9 +23570,6 @@ msgstr ""
msgid "Sidebar|Assign health status"
msgstr ""
-msgid "Sidebar|Change weight"
-msgstr ""
-
msgid "Sidebar|Health status"
msgstr ""
@@ -22934,6 +23753,9 @@ msgstr ""
msgid "Snippets|Add another file %{num}/%{total}"
msgstr ""
+msgid "Snippets|Authored %{time_ago} by %{author}"
+msgstr ""
+
msgid "Snippets|Delete file"
msgstr ""
@@ -22961,6 +23783,9 @@ msgstr ""
msgid "Solution"
msgstr ""
+msgid "Some changes are not shown"
+msgstr ""
+
msgid "Some child epics may be hidden due to applied filters"
msgstr ""
@@ -23327,6 +24152,12 @@ msgstr ""
msgid "Source (branch or tag)"
msgstr ""
+msgid "Source Branch"
+msgstr ""
+
+msgid "Source branch: %{source_branch_open}%{source_branch}%{source_branch_close}"
+msgstr ""
+
msgid "Source code"
msgstr "æºä»£ç¢¼"
@@ -23492,9 +24323,6 @@ msgstr ""
msgid "Start and due date"
msgstr ""
-msgid "Start by choosing a group to see how your team is spending time. You can then drill down to the project level."
-msgstr ""
-
msgid "Start by choosing a group to start exploring the merge requests in that group. You can then proceed to filter by projects, labels, milestones and authors."
msgstr ""
@@ -23576,18 +24404,27 @@ msgstr ""
msgid "StaticSiteEditor|3. Assign a person to review and accept the merge request."
msgstr ""
+msgid "StaticSiteEditor|A link to view the merge request will appear once ready."
+msgstr ""
+
msgid "StaticSiteEditor|An error occurred while submitting your changes."
msgstr ""
msgid "StaticSiteEditor|Branch could not be created."
msgstr ""
+msgid "StaticSiteEditor|Copy update"
+msgstr ""
+
msgid "StaticSiteEditor|Could not commit the content changes."
msgstr ""
msgid "StaticSiteEditor|Could not create merge request."
msgstr ""
+msgid "StaticSiteEditor|Creating your merge request"
+msgstr ""
+
msgid "StaticSiteEditor|Incompatible file content"
msgstr ""
@@ -23609,6 +24446,9 @@ msgstr ""
msgid "StaticSiteEditor|View documentation"
msgstr ""
+msgid "StaticSiteEditor|You can set an assignee to get your changes reviewed and deployed once your merge request is created."
+msgstr ""
+
msgid "StaticSiteEditor|Your merge request has been created"
msgstr ""
@@ -23738,15 +24578,15 @@ msgstr ""
msgid "Submit %{humanized_resource_name}"
msgstr ""
-msgid "Submit Changes"
-msgstr ""
-
msgid "Submit a review"
msgstr ""
msgid "Submit as spam"
msgstr ""
+msgid "Submit changes"
+msgstr ""
+
msgid "Submit feedback"
msgstr "æ交æ„見"
@@ -23900,6 +24740,9 @@ msgstr ""
msgid "Successfully deleted U2F device."
msgstr ""
+msgid "Successfully deleted WebAuthn device."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -24218,9 +25061,6 @@ msgstr ""
msgid "Template to append to all Service Desk issues"
msgstr ""
-msgid "Template was successfully saved."
-msgstr ""
-
msgid "Templates"
msgstr ""
@@ -24296,10 +25136,28 @@ msgid "Test coverage: %d hit"
msgid_plural "Test coverage: %d hits"
msgstr[0] ""
-msgid "Test failed."
+msgid "Test settings"
+msgstr ""
+
+msgid "TestCases|New Test Case"
+msgstr ""
+
+msgid "TestCases|New test case"
+msgstr ""
+
+msgid "TestCases|Search test cases"
+msgstr ""
+
+msgid "TestCases|Something went wrong while creating a test case."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching count of test cases."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching test cases list."
msgstr ""
-msgid "Test settings and save changes"
+msgid "TestCases|Submit test case"
msgstr ""
msgid "TestHooks|Ensure one of your projects has merge requests."
@@ -24365,6 +25223,9 @@ msgstr ""
msgid "Thank you for signing up for your free trial! You will get additional instructions in your inbox shortly."
msgstr ""
+msgid "Thank you for your business."
+msgstr ""
+
msgid "Thank you for your feedback!"
msgstr ""
@@ -24423,9 +25284,6 @@ msgstr ""
msgid "The URL to use for connecting to Elasticsearch. Use a comma-separated list to support clustering (e.g., \"http://localhost:9200, http://localhost:9201\")."
msgstr ""
-msgid "The Web IDE offers advanced syntax highlighting capabilities and more."
-msgstr ""
-
msgid "The X509 Certificate to use when mutual TLS is required to communicate with the external authorization service. If left blank, the server certificate is still validated when accessing over HTTPS."
msgstr ""
@@ -24535,6 +25393,9 @@ msgstr "派生關係已被刪除。"
msgid "The form contains the following error:"
msgstr ""
+msgid "The form contains the following warning:"
+msgstr ""
+
msgid "The global settings require you to enable Two-Factor Authentication for your account."
msgstr ""
@@ -24649,9 +25510,6 @@ msgstr "計劃階段概述了從議題添加到日程到推é€é¦–次æ交的時
msgid "The private key to use when a client certificate is provided. This value is encrypted at rest."
msgstr ""
-msgid "The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr "生產階段概述了從創建議題到將代碼部署到生產環境的時間。當完æˆå®Œæ•´çš„想法到部署生產,數據將自動添加到此處。"
-
msgid "The project can be accessed by any logged in user."
msgstr "該項目å…許已登錄的用戶訪å•ã€‚"
@@ -24688,7 +25546,7 @@ msgstr ""
msgid "The remote repository is being updated..."
msgstr ""
-msgid "The repository can be commited to, and issues, comments and other entities can be created."
+msgid "The repository can be committed to, and issues, comments and other entities can be created."
msgstr ""
msgid "The repository for this project does not exist."
@@ -24742,9 +25600,6 @@ msgstr "測試階段概述了 GitLab CI 為相關åˆä½µè«‹æ±‚é‹è¡Œæ¯å€‹æµæ°´ç
msgid "The time taken by each data entry gathered by that stage."
msgstr "該階段æ¯æ¢æ•¸æ“šæ‰€èŠ±çš„時間"
-msgid "The total stage shows the time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The update action will time out after %{number_of_minutes} minutes. For big repositories, use a clone/push combination."
msgstr ""
@@ -24808,6 +25663,9 @@ msgstr ""
msgid "There are no archived requirements"
msgstr ""
+msgid "There are no archived test cases"
+msgstr ""
+
msgid "There are no changes"
msgstr ""
@@ -24847,6 +25705,9 @@ msgstr ""
msgid "There are no open requirements"
msgstr ""
+msgid "There are no open test cases"
+msgstr ""
+
msgid "There are no packages yet"
msgstr ""
@@ -24859,6 +25720,9 @@ msgstr ""
msgid "There is a limit of %{ci_project_subscriptions_limit} subscriptions from or to a project."
msgstr ""
+msgid "There is already a To-Do for this design."
+msgstr ""
+
msgid "There is already a repository with that name on disk"
msgstr ""
@@ -24877,6 +25741,9 @@ msgstr ""
msgid "There was a problem communicating with your device."
msgstr ""
+msgid "There was a problem fetching branches."
+msgstr ""
+
msgid "There was a problem fetching groups."
msgstr ""
@@ -25105,9 +25972,15 @@ msgstr ""
msgid "This action can lead to data loss. To prevent accidental actions we ask you to confirm your intention."
msgstr ""
+msgid "This action cannot be undone, and will permanently delete the %{key} SSH key"
+msgstr ""
+
msgid "This action cannot be undone. You will lose the project's repository and all content: issues, merge requests, etc."
msgstr ""
+msgid "This action has been performed too many times. Try again later."
+msgstr ""
+
msgid "This action will %{strongOpen}permanently delete%{strongClose} %{codeOpen}%{project}%{codeClose} %{strongOpen}immediately%{strongClose}, including its repositories and all content: issues, merge requests, etc."
msgstr ""
@@ -25135,9 +26008,6 @@ msgstr ""
msgid "This board's scope is reduced"
msgstr ""
-msgid "This branch has changed since you started editing. Would you like to create a new branch?"
-msgstr ""
-
msgid "This chart could not be displayed"
msgstr ""
@@ -25264,15 +26134,9 @@ msgstr ""
msgid "This is a security log of important events involving your account."
msgstr ""
-msgid "This is the author's first Merge Request to this project."
-msgstr ""
-
msgid "This is the highest peak of users on your installation since the license started."
msgstr ""
-msgid "This is the maximum number of users that have existed at the same time since the license started. This is the minimum number of seats you will need to buy when you renew your license."
-msgstr ""
-
msgid "This is the number of currently active users on your installation, and this is the minimum number you need to purchase when you renew your license."
msgstr ""
@@ -25504,6 +26368,15 @@ msgstr ""
msgid "This user has no identities"
msgstr ""
+msgid "This user has previously committed to the %{name} project."
+msgstr ""
+
+msgid "This user has the %{access} role in the %{name} project."
+msgstr ""
+
+msgid "This user is the author of this %{noteable}."
+msgstr ""
+
msgid "This user will be the author of all events in the activity feed that are the result of an update, like new branches being created or new commits being pushed to existing branches."
msgstr ""
@@ -25534,6 +26407,9 @@ msgstr ""
msgid "Threat Monitoring"
msgstr ""
+msgid "ThreatMonitoring|All Environments"
+msgstr ""
+
msgid "ThreatMonitoring|Anomalous Requests"
msgstr ""
@@ -25561,9 +26437,6 @@ msgstr ""
msgid "ThreatMonitoring|Operations Per Second"
msgstr ""
-msgid "ThreatMonitoring|Overview"
-msgstr ""
-
msgid "ThreatMonitoring|Packet Activity"
msgstr ""
@@ -25582,6 +26455,9 @@ msgstr ""
msgid "ThreatMonitoring|Something went wrong, unable to fetch statistics"
msgstr ""
+msgid "ThreatMonitoring|Statistics"
+msgstr ""
+
msgid "ThreatMonitoring|The firewall is not installed or has been disabled. To view this data, ensure the web application firewall is installed and enabled for your cluster."
msgstr ""
@@ -25971,6 +26847,9 @@ msgstr ""
msgid "To update Snippets with multiple files, you must use the `files` parameter"
msgstr ""
+msgid "To use Gitpod you must first enable the feature in the integrations section of your %{user_prefs}."
+msgstr ""
+
msgid "To view all %{scannedResourcesCount} scanned URLs, please download the CSV file"
msgstr ""
@@ -26004,9 +26883,6 @@ msgstr ""
msgid "Toggle Sidebar"
msgstr ""
-msgid "Toggle all threads"
-msgstr ""
-
msgid "Toggle backtrace"
msgstr ""
@@ -26031,9 +26907,6 @@ msgstr ""
msgid "Toggle navigation"
msgstr ""
-msgid "Toggle project"
-msgstr ""
-
msgid "Toggle sidebar"
msgstr ""
@@ -26073,6 +26946,9 @@ msgstr ""
msgid "Too many projects enabled. You will need to manage them via the console or the API."
msgstr ""
+msgid "Too much data"
+msgstr ""
+
msgid "Topics (optional)"
msgstr ""
@@ -26091,6 +26967,9 @@ msgstr ""
msgid "Total cores (CPUs)"
msgstr ""
+msgid "Total days to completion"
+msgstr ""
+
msgid "Total issues"
msgstr ""
@@ -26187,6 +27066,9 @@ msgstr "樹狀顯示"
msgid "Trending"
msgstr ""
+msgid "Trials|Create a new group to start your GitLab Gold trial."
+msgstr ""
+
msgid "Trials|Go back to GitLab"
msgstr ""
@@ -26196,6 +27078,15 @@ msgstr ""
msgid "Trials|You can always resume this process by selecting your avatar and choosing 'Start a Gold trial'"
msgstr ""
+msgid "Trials|You can apply your trial to a new group or an existing group."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group or your personal account."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group, an existing group, or your personal account."
+msgstr ""
+
msgid "Trials|You won't get a free trial right now but you can always resume this process by clicking on your avatar and choosing 'Start a free trial'"
msgstr ""
@@ -26265,6 +27156,9 @@ msgstr ""
msgid "Try using a different search term to find the file you are looking for."
msgstr ""
+msgid "Trying to communicate with your device. Plug it in (if needed) and press the button on the device now."
+msgstr ""
+
msgid "Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now."
msgstr ""
@@ -26352,6 +27246,12 @@ msgstr ""
msgid "URL or request ID"
msgstr ""
+msgid "USER %{user} WILL BE REMOVED! Are you sure?"
+msgstr ""
+
+msgid "USER WILL BE BLOCKED! Are you sure?"
+msgstr ""
+
msgid "UTC"
msgstr ""
@@ -26409,9 +27309,6 @@ msgstr ""
msgid "Unable to load the merge request widget. Try reloading the page."
msgstr ""
-msgid "Unable to resolve"
-msgstr ""
-
msgid "Unable to save iteration. Please try again"
msgstr ""
@@ -26460,6 +27357,9 @@ msgstr ""
msgid "Undo ignore"
msgstr ""
+msgid "Unexpected error"
+msgstr ""
+
msgid "Unfortunately, your email message to GitLab could not be processed."
msgstr ""
@@ -26493,6 +27393,9 @@ msgstr ""
msgid "Unknown response text"
msgstr ""
+msgid "Unless otherwise agreed to in writing with GitLab, by clicking \"Upload License\" you agree that your use of GitLab Software is subject to the %{eula_link_start}Terms of Service%{eula_link_end}."
+msgstr ""
+
msgid "Unlimited"
msgstr ""
@@ -26859,9 +27762,6 @@ msgstr ""
msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
msgstr ""
-msgid "Use a hardware device to add the second factor of authentication."
-msgstr ""
-
msgid "Use an one time password authenticator on your mobile device or computer to enable two-factor authentication (2FA)."
msgstr ""
@@ -27135,13 +28035,13 @@ msgstr ""
msgid "Users"
msgstr ""
-msgid "Users in License:"
+msgid "Users in License"
msgstr ""
-msgid "Users or groups set as approvers in the project's or merge request's settings."
+msgid "Users in License:"
msgstr ""
-msgid "Users outside of license"
+msgid "Users or groups set as approvers in the project's or merge request's settings."
msgstr ""
msgid "Users over License:"
@@ -27159,9 +28059,6 @@ msgstr ""
msgid "Users with a Guest role or those who don't belong to a Project or Group will not use a seat from your license."
msgstr ""
-msgid "Users with a Guest role or those who don't belong to any projects or groups don't count towards seats in use."
-msgstr ""
-
msgid "UsersSelect|%{name} + %{length} more"
msgstr ""
@@ -27201,9 +28098,6 @@ msgstr ""
msgid "Validations failed."
msgstr ""
-msgid "Validity"
-msgstr ""
-
msgid "Value"
msgstr ""
@@ -27222,6 +28116,9 @@ msgstr ""
msgid "Value Stream Name"
msgstr ""
+msgid "ValueStreamAnalyticsStage|We don't have enough data to show this stage."
+msgstr ""
+
msgid "ValueStreamAnalytics|%{days}d"
msgstr ""
@@ -27476,6 +28373,9 @@ msgstr ""
msgid "VisualReviewApp|Steps 1 and 2 (and sometimes 3) are performed once by the developer before requesting feedback. Steps 3 (if necessary), 4 is performed by the reviewer each time they perform a review."
msgstr ""
+msgid "Visualization"
+msgstr ""
+
msgid "Vulnerabilities"
msgstr ""
@@ -27503,34 +28403,31 @@ msgstr ""
msgid "VulnerabilityChart|Severity"
msgstr ""
-msgid "VulnerabilityManagement|A true-positive and will fix"
-msgstr ""
-
-msgid "VulnerabilityManagement|Change status"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Confirm"
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|Confirmed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Detected %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|A true-positive and will fix"
msgstr ""
-msgid "VulnerabilityManagement|Dismiss"
+msgid "VulnerabilityManagement|Change status"
msgstr ""
-msgid "VulnerabilityManagement|Dismissed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
msgstr ""
-msgid "VulnerabilityManagement|Resolved"
+msgid "VulnerabilityManagement|Detected"
msgstr ""
-msgid "VulnerabilityManagement|Resolved %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Needs triage"
msgstr ""
msgid "VulnerabilityManagement|Something went wrong while trying to delete the comment. Please try again later."
@@ -27581,6 +28478,9 @@ msgstr ""
msgid "Vulnerability|%{scannerName} (version %{scannerVersion})"
msgstr ""
+msgid "Vulnerability|Activity"
+msgstr ""
+
msgid "Vulnerability|Class"
msgstr ""
@@ -27593,6 +28493,9 @@ msgstr ""
msgid "Vulnerability|Description"
msgstr ""
+msgid "Vulnerability|Detected"
+msgstr ""
+
msgid "Vulnerability|Evidence"
msgstr ""
@@ -27656,6 +28559,9 @@ msgstr ""
msgid "Warning: Displaying this diagram might cause performance issues on this page."
msgstr ""
+msgid "We are currently unable to fetch data for the pipeline header."
+msgstr ""
+
msgid "We are currently unable to fetch data for this graph."
msgstr ""
@@ -27695,6 +28601,12 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
+msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
+msgstr ""
+
+msgid "We would like to inform you that your subscription GitLab Enterprise Edition %{plan_name} is nearing its user limit. You have %{active_user_count} active users, which is almost at the user limit of %{maximum_user_count}."
+msgstr ""
+
msgid "We've found no vulnerabilities"
msgstr ""
@@ -27710,6 +28622,12 @@ msgstr ""
msgid "Web terminal"
msgstr ""
+msgid "WebAuthn Devices (%{length})"
+msgstr ""
+
+msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
+msgstr ""
+
msgid "WebIDE|Merge request"
msgstr ""
@@ -27848,15 +28766,9 @@ msgstr ""
msgid "Welcome to the guided GitLab tour"
msgstr ""
-msgid "Welcome to your Issue Board!"
-msgstr ""
-
msgid "Welcome to your issue board!"
msgstr ""
-msgid "We’ve been making changes to %{featureName} and we’d love your feedback %{linkStart}in this issue%{linkEnd} to help us improve the experience."
-msgstr ""
-
msgid "What are you searching for?"
msgstr ""
@@ -27875,6 +28787,9 @@ msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
msgstr ""
+msgid "When enabled, any user visiting %{host} and creating an account will have to be explicitly approved by the admin before they can login. This setting is effective only if sign-ups are enabled."
+msgstr ""
+
msgid "When enabled, any user visiting %{host} will be able to create an account."
msgstr ""
@@ -28098,6 +29013,9 @@ msgstr ""
msgid "With requirements, you can set criteria to check your products against."
msgstr ""
+msgid "With test cases, you can define conditions for your project to meet in determining quality"
+msgstr ""
+
msgid "Withdraw Access Request"
msgstr "å–消權é™ç”³è¯·"
@@ -28113,6 +29031,9 @@ msgstr ""
msgid "Workflow Help"
msgstr ""
+msgid "Would you like to create a new branch?"
+msgstr ""
+
msgid "Write"
msgstr "寫"
@@ -28134,6 +29055,9 @@ msgstr ""
msgid "Wrong extern UID provided. Make sure Auth0 is configured correctly."
msgstr ""
+msgid "YYYY-MM-DD"
+msgstr ""
+
msgid "Yes"
msgstr ""
@@ -28191,7 +29115,7 @@ msgstr ""
msgid "You are going to remove the fork relationship from %{project_full_name}. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "You are going to transfer %{project_full_name} to another owner. Are you ABSOLUTELY sure?"
+msgid "You are going to transfer %{project_full_name} to another namespace. Are you ABSOLUTELY sure?"
msgstr ""
msgid "You are going to turn off the confidentiality. This means %{strongStart}everyone%{strongEnd} will be able to see and leave a comment on this %{issuableType}."
@@ -28251,9 +29175,6 @@ msgstr ""
msgid "You can always edit this later"
msgstr ""
-msgid "You can apply your Trial to your Personal account or create a New Group."
-msgstr ""
-
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings"
msgstr ""
@@ -28275,12 +29196,18 @@ msgstr ""
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
+msgid "You can find more information about GitLab subscriptions in %{subscriptions_doc_link}."
+msgstr ""
+
msgid "You can generate an access token scoped to this project for each application to use the GitLab API."
msgstr ""
msgid "You can get started by cloning the repository or start adding files to it with one of the following options."
msgstr ""
+msgid "You can group test cases using labels. To learn about the future direction of this feature, visit %{linkStart}Quality Management direction page%{linkEnd}."
+msgstr ""
+
msgid "You can invite a new member to %{project_name} or invite another group."
msgstr ""
@@ -28296,6 +29223,9 @@ msgstr ""
msgid "You can notify the app / group or a project by sending them an email notification"
msgstr ""
+msgid "You can now close this window."
+msgstr ""
+
msgid "You can now export your security dashboard to a CSV report."
msgstr ""
@@ -28344,9 +29274,6 @@ msgstr ""
msgid "You can test your .gitlab-ci.yml in %{linkStart}CI Lint%{linkEnd}."
msgstr ""
-msgid "You can try again using %{begin_link}basic search%{end_link}"
-msgstr ""
-
msgid "You cannot access the raw file. Please wait a minute."
msgstr ""
@@ -28398,6 +29325,9 @@ msgstr ""
msgid "You don't have any U2F devices registered yet."
msgstr ""
+msgid "You don't have any WebAuthn devices registered yet."
+msgstr ""
+
msgid "You don't have any active chat names."
msgstr ""
@@ -28485,6 +29415,9 @@ msgstr ""
msgid "You must accept our Terms of Service and privacy policy in order to register an account"
msgstr ""
+msgid "You must be logged in to search across all of GitLab"
+msgstr ""
+
msgid "You must disassociate %{domain} from all clusters it is attached to before deletion."
msgstr ""
@@ -28524,7 +29457,7 @@ msgstr "需è¦ç›¸é—œçš„權é™ã€‚"
msgid "You need to be logged in."
msgstr ""
-msgid "You need to register a two-factor authentication app before you can set up a U2F device."
+msgid "You need to register a two-factor authentication app before you can set up a device."
msgstr ""
msgid "You need to set terms to be enforced"
@@ -28542,6 +29475,9 @@ msgstr ""
msgid "You reached %{usage_in_percent} of %{namespace_name}'s storage capacity (%{used_storage} of %{storage_limit})"
msgstr ""
+msgid "You successfully declined the invitation"
+msgstr ""
+
msgid "You tried to fork %{link_to_the_project} but it failed for the following reason:"
msgstr ""
@@ -28707,10 +29643,13 @@ msgstr ""
msgid "Your U2F device did not send a valid JSON response."
msgstr ""
-msgid "Your U2F device needs to be set up. Plug it in (if not already) and click the button on the left."
+msgid "Your U2F device was registered!"
msgstr ""
-msgid "Your U2F device was registered!"
+msgid "Your WebAuthn device did not send a valid JSON response."
+msgstr ""
+
+msgid "Your WebAuthn device was registered!"
msgstr ""
msgid "Your access request to the %{source_type} has been withdrawn."
@@ -28734,6 +29673,9 @@ msgstr ""
msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
msgstr ""
+msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
+msgstr ""
+
msgid "Your changes can be committed to %{branch_name} because a merge request is open."
msgstr ""
@@ -28770,6 +29712,12 @@ msgstr ""
msgid "Your deployment services will be broken, you will need to manually fix the services after renaming."
msgstr ""
+msgid "Your device is not compatible with GitLab. Please try another device"
+msgstr ""
+
+msgid "Your device needs to be set up. Plug it in (if needed) and click the button on the left."
+msgstr ""
+
msgid "Your device was successfully set up! Give it a name and register it with the GitLab server."
msgstr ""
@@ -28882,9 +29830,6 @@ msgstr[0] ""
msgid "access:"
msgstr ""
-msgid "activated"
-msgstr ""
-
msgid "added %{created_at_timeago}"
msgstr ""
@@ -28957,9 +29902,21 @@ msgstr ""
msgid "by %{user}"
msgstr ""
+msgid "cannot be a date in the past"
+msgstr ""
+
msgid "cannot be changed if a personal project has container registry tags."
msgstr ""
+msgid "cannot be changed if shared runners are enabled"
+msgstr ""
+
+msgid "cannot be enabled because parent group does not allow it"
+msgstr ""
+
+msgid "cannot be enabled because parent group has shared Runners disabled"
+msgstr ""
+
msgid "cannot be enabled unless all domains have TLS certificates"
msgstr ""
@@ -29005,7 +29962,7 @@ msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about SAST %{linkEndTag}"
msgstr ""
-msgid "ciReport|%{linkStartTag}Learn more about Secret Scanning %{linkEndTag}"
+msgid "ciReport|%{linkStartTag}Learn more about Secret Detection %{linkEndTag}"
msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about codequality reports %{linkEndTag}"
@@ -29317,9 +30274,6 @@ msgstr ""
msgid "error"
msgstr ""
-msgid "error code:"
-msgstr ""
-
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr ""
@@ -29341,6 +30295,9 @@ msgstr ""
msgid "failed to dismiss associated finding(id=%{finding_id}): %{message}"
msgstr ""
+msgid "failed to revert associated finding(id=%{finding_id}) to detected"
+msgstr ""
+
msgid "file"
msgid_plural "files"
msgstr[0] ""
@@ -29879,6 +30836,9 @@ msgstr ""
msgid "must be a root namespace"
msgstr ""
+msgid "must be a valid IPv4 or IPv6 address"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -29915,6 +30875,9 @@ msgstr ""
msgid "no expiration"
msgstr ""
+msgid "no name set"
+msgstr ""
+
msgid "no one can merge"
msgstr ""
@@ -30088,9 +31051,6 @@ msgstr ""
msgid "security Reports|There was an error creating the merge request"
msgstr ""
-msgid "settings saved, but not activated"
-msgstr ""
-
msgid "severity|Critical"
msgstr ""
@@ -30217,9 +31177,6 @@ msgstr ""
msgid "toggle collapse"
msgstr ""
-msgid "toggle dropdown"
-msgstr ""
-
msgid "triggered"
msgstr ""
@@ -30247,6 +31204,9 @@ msgstr ""
msgid "user avatar"
msgstr ""
+msgid "user preferences"
+msgstr ""
+
msgid "username"
msgstr ""
diff --git a/locale/zh_TW/gitlab.po b/locale/zh_TW/gitlab.po
index 959bb9e22a1..ea50ffd67ff 100644
--- a/locale/zh_TW/gitlab.po
+++ b/locale/zh_TW/gitlab.po
@@ -14,7 +14,10 @@ msgstr ""
"X-Crowdin-Language: zh-TW\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 6\n"
-"PO-Revision-Date: 2020-09-04 23:06\n"
+"PO-Revision-Date: 2020-10-02 18:45\n"
+
+msgid " %{project_name}#%{issue_iid} &middot; opened %{issue_created} by %{author}"
+msgstr ""
msgid " %{start} to %{end}"
msgstr ""
@@ -72,6 +75,14 @@ msgstr "「%{ref}ã€ä¸Šæ²’有「%{path}ã€"
msgid "\"el\" parameter is required for createInstance()"
msgstr ""
+msgid "%d Approval"
+msgid_plural "%d Approvals"
+msgstr[0] ""
+
+msgid "%d Package"
+msgid_plural "%d Packages"
+msgstr[0] ""
+
msgid "%d Scanned URL"
msgid_plural "%d Scanned URLs"
msgstr[0] ""
@@ -123,6 +134,10 @@ msgstr[0] "%d 次æ交,"
msgid "%d commits"
msgstr "%d 次æ交"
+msgid "%d completed issue"
+msgid_plural "%d completed issues"
+msgstr[0] ""
+
msgid "%d contribution"
msgid_plural "%d contributions"
msgstr[0] "%d 個貢ç»"
@@ -131,6 +146,10 @@ msgid "%d day"
msgid_plural "%d days"
msgstr[0] ""
+msgid "%d day until tags are automatically removed"
+msgid_plural "%d days until tags are automatically removed"
+msgstr[0] ""
+
msgid "%d error"
msgid_plural "%d errors"
msgstr[0] ""
@@ -203,6 +222,14 @@ msgid "%d more comment"
msgid_plural "%d more comments"
msgstr[0] "還有 %d 則留言"
+msgid "%d open issue"
+msgid_plural "%d open issues"
+msgstr[0] ""
+
+msgid "%d pending comment"
+msgid_plural "%d pending comments"
+msgstr[0] ""
+
msgid "%d personal project will be removed and cannot be restored."
msgid_plural "%d personal projects will be removed and cannot be restored."
msgstr[0] ""
@@ -215,6 +242,10 @@ msgid "%d project"
msgid_plural "%d projects"
msgstr[0] "%d 個專案"
+msgid "%d project selected"
+msgid_plural "%d projects selected"
+msgstr[0] ""
+
msgid "%d request with warnings"
msgid_plural "%d requests with warnings"
msgstr[0] "%d 個有警告的請求"
@@ -231,6 +262,10 @@ msgid "%d tag"
msgid_plural "%d tags"
msgstr[0] "%d 個標籤"
+msgid "%d tag per image name"
+msgid_plural "%d tags per image name"
+msgstr[0] ""
+
msgid "%d unassigned issue"
msgid_plural "%d unassigned issues"
msgstr[0] ""
@@ -247,6 +282,10 @@ msgid "%d vulnerability dismissed"
msgid_plural "%d vulnerabilities dismissed"
msgstr[0] ""
+msgid "%d warning found:"
+msgid_plural "%d warnings found:"
+msgstr[0] ""
+
msgid "%s additional commit has been omitted to prevent performance issues."
msgid_plural "%s additional commits have been omitted to prevent performance issues."
msgstr[0] "為é¿å…效能å•é¡Œï¼Œå·²éš±è— %s 次é¡å¤–æ交。"
@@ -284,6 +323,9 @@ msgstr ""
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr "ç”± %{commit_author_link} æ交於 %{commit_timeago}"
+msgid "%{completedCount} completed weight"
+msgstr ""
+
msgid "%{completedWeight} of %{totalWeight} weight completed"
msgstr ""
@@ -329,13 +371,12 @@ msgid "%{count} participant"
msgid_plural "%{count} participants"
msgstr[0] "%{count} ä½åƒèˆ‡è€…"
-msgid "%{count} pending comment"
-msgid_plural "%{count} pending comments"
-msgstr[0] "%{count} 則待處ç†ç•™è¨€"
-
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr "%{count} 個相關的 %{pluralized_subject}:%{links}"
+msgid "%{count} total weight"
+msgstr ""
+
msgid "%{dashboard_path} could not be found."
msgstr ""
@@ -390,6 +431,9 @@ msgstr ""
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} 使用群組管ç†å¸³æˆ¶ã€‚您需è¦å»ºç«‹ä¸€å€‹æ–°çš„ GitLab 帳戶,該帳戶將由 %{group_name} 群組管ç†ã€‚"
+msgid "%{group_name}&%{epic_iid} &middot; opened %{epic_created} by %{author}"
+msgstr ""
+
msgid "%{host} sign-in from new location"
msgstr ""
@@ -402,8 +446,8 @@ msgstr ""
msgid "%{issuableType} will be removed! Are you sure?"
msgstr "%{issuableType} 將被刪除ï¼æ‚¨ç¢ºå®šå—Žï¼Ÿ"
-msgid "%{issuesSize} issues with a limit of %{maxIssueCount}"
-msgstr "%{issuesSize} å€‹è­°é¡Œï¼Œä¸Šé™ %{maxIssueCount} 個。"
+msgid "%{issuesCount} issues with a limit of %{maxIssueCount}"
+msgstr ""
msgid "%{issuesSize} with a limit of %{maxIssueCount}"
msgstr ""
@@ -435,7 +479,7 @@ msgstr ""
msgid "%{labelStart}Namespace:%{labelEnd} %{namespace}"
msgstr ""
-msgid "%{labelStart}Report Type:%{labelEnd} %{reportType}"
+msgid "%{labelStart}Scan Type:%{labelEnd} %{reportType}"
msgstr ""
msgid "%{labelStart}Scanner:%{labelEnd} %{scanner}"
@@ -625,9 +669,6 @@ msgid "%{securityScanner} result is not available because a pipeline has not bee
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] ""
-msgid "%{service_title} %{message}."
-msgstr ""
-
msgid "%{size} GiB"
msgstr "%{size} GiB"
@@ -711,6 +752,12 @@ msgstr "%{text} å¯ç”¨"
msgid "%{timebox_name} should belong either to a project or a group."
msgstr ""
+msgid "%{timebox_type} does not support burnup charts"
+msgstr ""
+
+msgid "%{timebox_type} must have a start and due date"
+msgstr ""
+
msgid "%{title} %{operator} %{threshold}"
msgstr "%{title} %{operator} %{threshold}"
@@ -735,8 +782,8 @@ msgstr ""
msgid "%{total} open issue weight"
msgstr "%{total} 開放議題權é‡"
-msgid "%{total} open issues"
-msgstr "%{total} 個開啟中的議題"
+msgid "%{total} warnings found: showing first %{warningsDisplayed}"
+msgstr ""
msgid "%{usage_ping_link_start}Learn more%{usage_ping_link_end} about what information is shared with GitLab Inc."
msgstr "%{usage_ping_link_start}了解更多%{usage_ping_link_end} 分享給 GitLab Inc. 的訊æ¯ã€‚"
@@ -768,9 +815,6 @@ msgstr ""
msgid "&lt; 1 hour"
msgstr ""
-msgid "&lt;no name set&gt;"
-msgstr ""
-
msgid "&lt;no scopes selected&gt;"
msgstr ""
@@ -801,6 +845,9 @@ msgstr "「%{level}ã€ä¸æ˜¯æœ‰æ•ˆçš„å¯è¦‹æ€§ç´šåˆ¥"
msgid "'%{name}' Value Stream created"
msgstr ""
+msgid "'%{name}' Value Stream deleted"
+msgstr ""
+
msgid "'%{name}' stage already exists"
msgstr ""
@@ -859,6 +906,9 @@ msgstr "+ 其餘 %{moreCount} 項"
msgid "+ %{numberOfHiddenAssignees} more"
msgstr "+ 其餘 %{numberOfHiddenAssignees} 項"
+msgid "+ %{numberOfHiddenReviewers} more"
+msgstr ""
+
msgid "+%d more"
msgid_plural "+%d more"
msgstr[0] ""
@@ -913,6 +963,10 @@ msgid "1 Day"
msgid_plural "%d Days"
msgstr[0] "%d天"
+msgid "1 Issue"
+msgid_plural "%d Issues"
+msgstr[0] ""
+
msgid "1 closed issue"
msgid_plural "%{issues} closed issues"
msgstr[0] "%{issues} 個已關閉的議題"
@@ -925,6 +979,10 @@ msgid "1 day"
msgid_plural "%d days"
msgstr[0] "%d天"
+msgid "1 deploy key"
+msgid_plural "%d deploy keys"
+msgstr[0] ""
+
msgid "1 group"
msgid_plural "%d groups"
msgstr[0] "%d 個群組"
@@ -1018,6 +1076,9 @@ msgstr "8å°æ™‚"
msgid ":%{startLine} to %{endLine}"
msgstr ""
+msgid "A %{incident_docs_start}modified issue%{incident_docs_end} to guide the resolution of incidents."
+msgstr ""
+
msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr "「執行器ã€æ˜¯ä¸€å€‹åŸ·è¡Œä½œæ¥­çš„行程。您å¯ä»¥æ ¹æ“šéœ€è¦é…置任æ„個執行器。"
@@ -1030,6 +1091,9 @@ msgstr ""
msgid "A GitBook site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr "一個 GitBook ç«™å°ï¼Œä½¿ç”¨ Netlify 代替 GitLab çš„ CI/CD,但ä»å…·æœ‰æ‰€æœ‰å…¶ä»–主è¦çš„ GitLab 功能。"
+msgid "A Gitpod configured Webapplication in Spring and Java"
+msgstr ""
+
msgid "A Hexo site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features."
msgstr "一個 Hexo ç«™å°ï¼Œä½¿ç”¨ Netlify 代替 GitLab çš„ CI/CD,但ä»å…·æœ‰æ‰€æœ‰å…¶ä»–主è¦çš„ GitLab 功能。"
@@ -1201,9 +1265,15 @@ msgstr "å­˜å–被拒ï¼è«‹æª¢æŸ¥æ‚¨æ˜¯å¦å¯ä»¥åœ¨æ­¤ç‰ˆæœ¬åº«éƒ¨å±¬é‡‘鑰。"
msgid "Access expiration date"
msgstr "å­˜å–éŽæœŸæ™‚é–“"
+msgid "Access expires"
+msgstr ""
+
msgid "Access forbidden. Check your access level."
msgstr "ç¦æ­¢å­˜å–。請檢查您的存å–權é™ã€‚"
+msgid "Access granted"
+msgstr ""
+
msgid "Access requests"
msgstr ""
@@ -1213,6 +1283,9 @@ msgstr "ä¸å…許存å–「%{classification_label}ã€"
msgid "Access to Pages websites are controlled based on the user's membership to a given project. By checking this box, users will be required to be logged in to have access to all Pages websites in your instance."
msgstr ""
+msgid "AccessDropdown|Deploy Keys"
+msgstr ""
+
msgid "AccessDropdown|Groups"
msgstr "群組"
@@ -1330,12 +1403,6 @@ msgstr ""
msgid "Active Sessions"
msgstr "使用中的工作階段"
-msgid "Active Users:"
-msgstr ""
-
-msgid "Active users"
-msgstr ""
-
msgid "Activity"
msgstr "å‹•æ…‹"
@@ -1502,9 +1569,6 @@ msgstr ""
msgid "Add label(s)"
msgstr "加入標籤"
-msgid "Add license"
-msgstr "加入授權æ¢æ¬¾"
-
msgid "Add list"
msgstr "加入列表"
@@ -1679,21 +1743,51 @@ msgstr ""
msgid "AdminArea|Bots"
msgstr ""
+msgid "AdminArea|Components"
+msgstr ""
+
msgid "AdminArea|Developer"
msgstr ""
+msgid "AdminArea|Features"
+msgstr ""
+
+msgid "AdminArea|Groups: %{number_of_groups}"
+msgstr ""
+
msgid "AdminArea|Guest"
msgstr ""
msgid "AdminArea|Included Free in license"
msgstr ""
+msgid "AdminArea|Latest groups"
+msgstr ""
+
+msgid "AdminArea|Latest projects"
+msgstr ""
+
+msgid "AdminArea|Latest users"
+msgstr ""
+
msgid "AdminArea|Maintainer"
msgstr ""
+msgid "AdminArea|New group"
+msgstr ""
+
+msgid "AdminArea|New project"
+msgstr ""
+
+msgid "AdminArea|New user"
+msgstr ""
+
msgid "AdminArea|Owner"
msgstr ""
+msgid "AdminArea|Projects: %{number_of_projects}"
+msgstr ""
+
msgid "AdminArea|Reporter"
msgstr ""
@@ -1721,6 +1815,9 @@ msgstr ""
msgid "AdminArea|Users without a Group and Project"
msgstr ""
+msgid "AdminArea|Users: %{number_of_users}"
+msgstr ""
+
msgid "AdminArea|You’re about to stop all jobs.This will halt all current jobs that are running."
msgstr "您å³å°‡åœæ­¢æ‰€æœ‰ä½œæ¥­ã€‚這會中斷並çµæŸæ‰€æœ‰æ­£åœ¨åŸ·è¡Œçš„作業。"
@@ -1739,9 +1836,6 @@ msgstr "刪除"
msgid "AdminProjects|Delete Project %{projectName}?"
msgstr "刪除專案 %{projectName}?"
-msgid "AdminProjects|Delete project"
-msgstr "刪除專案"
-
msgid "AdminSettings|Apply integration settings to all Projects"
msgstr ""
@@ -1979,21 +2073,30 @@ msgstr ""
msgid "AdminUsers|Without projects"
msgstr "沒有專案"
-msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
-msgstr "您å³å°‡æ°¸ä¹…刪除使用者 %{username}。該使用者的議題ã€åˆä½µè«‹æ±‚以åŠç›¸é—œçš„群組將被轉移到系統的「幽éˆä½¿ç”¨è€…ã€ã€‚為é¿å…資料éºå¤±ï¼Œå»ºè­°æ‚¨ä½¿ç”¨ %{strong_start}å°éŽ–使用者%{strong_end} 功能。一旦您 %{strong_start}刪除使用者%{strong_end},則無法復原。"
+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 %{strong_start}block user%{strong_end} feature instead. Once you %{strong_start}Delete user%{strong_end}, it cannot be undone or recovered."
-msgstr "您å³å°‡æ°¸ä¹…刪除使用者 %{username}。此æ“作會刪除該使用者的所有議題ã€åˆä½µè«‹æ±‚以åŠç›¸é—œçš„群組。為é¿å…資料éºå¤±ï¼Œå»ºè­°æ‚¨ä½¿ç”¨ %{strong_start}å°éŽ–使用者%{strong_end} 功能。一旦您 %{strong_start}刪除使用者%{strong_end},則無法復原。"
+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 ""
msgid "AdminUsers|You cannot remove your own admin rights."
msgstr ""
+msgid "AdminUsers|You must transfer ownership or delete the groups owned by this user before you can delete their account"
+msgstr ""
+
msgid "Administration"
msgstr ""
msgid "Advanced"
msgstr "進階"
+msgid "Advanced Search"
+msgstr ""
+
+msgid "Advanced Search with Elasticsearch"
+msgstr ""
+
msgid "Advanced Settings"
msgstr ""
@@ -2070,6 +2173,9 @@ msgstr ""
msgid "AlertManagement|Edit"
msgstr ""
+msgid "AlertManagement|Environment"
+msgstr ""
+
msgid "AlertManagement|Events"
msgstr ""
@@ -2082,6 +2188,9 @@ msgstr ""
msgid "AlertManagement|Issue"
msgstr ""
+msgid "AlertManagement|Key"
+msgstr ""
+
msgid "AlertManagement|Low"
msgstr ""
@@ -2175,6 +2284,9 @@ msgstr ""
msgid "AlertManagement|Unknown"
msgstr ""
+msgid "AlertManagement|Value"
+msgstr ""
+
msgid "AlertManagement|View alerts in Opsgenie"
msgstr ""
@@ -2334,6 +2446,9 @@ msgstr "所有路徑都相å°æ–¼ GitLab 網å€ã€‚è«‹ä¸è¦åŒ…å«%{relative_url_l
msgid "All projects"
msgstr "所有專案"
+msgid "All projects selected"
+msgstr ""
+
msgid "All security scans are enabled because %{linkStart}Auto DevOps%{linkEnd} is enabled on this project"
msgstr "因為這個專案已開啟 %{linkStart}Auto DevOps%{linkEnd},已啟用所有安全掃æ"
@@ -2421,6 +2536,9 @@ msgstr "讓你能加入åŠç®¡ç† Kubernetes å¢é›†ã€‚"
msgid "Almost there"
msgstr "å³å°‡å®Œæˆ"
+msgid "Already blocked"
+msgstr ""
+
msgid "Also called \"Issuer\" or \"Relying party trust identifier\""
msgstr "也稱為「簽發者ã€æˆ–「信任憑證者信任識別碼ã€"
@@ -2475,6 +2593,9 @@ msgstr "空 GitLab 使用者欄ä½å°‡åœ¨æ‰€æœ‰è­°é¡ŒåŠç•™è¨€çš„æ述中加入
msgid "An error has occurred"
msgstr "發生錯誤"
+msgid "An error occured while making the changes: %{error}"
+msgstr ""
+
msgid "An error occurred adding a draft to the thread."
msgstr "å‘話題加入è‰ç¨¿æ™‚發生錯誤。"
@@ -2502,12 +2623,6 @@ msgstr "é è¦½ blob 時發生錯誤"
msgid "An error occurred when toggling the notification subscription"
msgstr "切æ›é€šçŸ¥è¨‚閱時發生錯誤"
-msgid "An error occurred when trying to resolve a comment. Please try again."
-msgstr "嘗試解決留言時發生錯誤。請å†è©¦ä¸€æ¬¡ã€‚"
-
-msgid "An error occurred when trying to resolve a discussion. Please try again."
-msgstr "嘗試解決討論時發生錯誤。請å†è©¦ä¸€æ¬¡ã€‚"
-
msgid "An error occurred when updating the issue weight"
msgstr "更新議題權é‡æ™‚發生錯誤"
@@ -2523,12 +2638,6 @@ msgstr ""
msgid "An error occurred while checking group path. Please refresh and try again."
msgstr ""
-msgid "An error occurred while committing your changes."
-msgstr "æ交您的變更時發生錯誤。"
-
-msgid "An error occurred while creating the list. Please try again."
-msgstr ""
-
msgid "An error occurred while decoding the file."
msgstr ""
@@ -2601,26 +2710,20 @@ msgstr ""
msgid "An error occurred while fetching the Service Desk address."
msgstr "抓å–æœå‹™å°ä½å€æ™‚發生錯誤。"
-msgid "An error occurred while fetching the board issues. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the board lists. Please reload the page."
msgstr ""
msgid "An error occurred while fetching the board lists. Please try again."
msgstr "抓å–看æ¿åˆ—表時發生錯誤。請å†è©¦ä¸€æ¬¡ã€‚"
-msgid "An error occurred while fetching the board swimlanes. Please reload the page."
-msgstr ""
-
msgid "An error occurred while fetching the builds."
msgstr "抓å–組建時發生錯誤。"
msgid "An error occurred while fetching the job log."
msgstr "抓å–作業日誌時發生錯誤。"
-msgid "An error occurred while fetching the job trace."
-msgstr "抓å–作業追蹤時發生錯誤。"
+msgid "An error occurred while fetching the job logs."
+msgstr ""
msgid "An error occurred while fetching the job."
msgstr "抓å–作業時發生錯誤。"
@@ -2766,9 +2869,6 @@ msgstr "儲存 LDAP 覆蓋狀態時發生錯誤,請é‡è©¦ã€‚"
msgid "An error occurred while saving assignees"
msgstr "儲存å—託人時發生錯誤。"
-msgid "An error occurred while saving the template. Please check if the template exists."
-msgstr "儲存範本時發生錯誤。請檢查範本是å¦å­˜åœ¨ã€‚"
-
msgid "An error occurred while searching for milestones"
msgstr ""
@@ -2787,12 +2887,12 @@ msgstr "å–消訂閱通知時發生錯誤。"
msgid "An error occurred while updating approvers"
msgstr "更新核准者時發生錯誤"
+msgid "An error occurred while updating labels."
+msgstr ""
+
msgid "An error occurred while updating the comment"
msgstr "更新留言時發生錯誤"
-msgid "An error occurred while updating the list. Please try again."
-msgstr ""
-
msgid "An error occurred while validating group path"
msgstr "驗證群組路徑時發生錯誤"
@@ -2844,6 +2944,9 @@ msgstr "åœæ­¢ç¶²é çµ‚端機時發生æ„外錯誤。"
msgid "An unknown error occurred while loading this graph."
msgstr ""
+msgid "An unknown error occurred."
+msgstr ""
+
msgid "Analytics"
msgstr "分æž"
@@ -2877,10 +2980,10 @@ msgstr ""
msgid "Any"
msgstr "任何"
-msgid "Any Author"
+msgid "Any %{header}"
msgstr ""
-msgid "Any Status"
+msgid "Any Author"
msgstr ""
msgid "Any branch"
@@ -2934,6 +3037,9 @@ msgstr ""
msgid "Application ID"
msgstr ""
+msgid "Application limits saved successfully"
+msgstr ""
+
msgid "Application settings saved successfully"
msgstr ""
@@ -3139,6 +3245,9 @@ msgstr "確定è¦å–消編輯此留言嗎?"
msgid "Are you sure you want to close this blocked issue?"
msgstr ""
+msgid "Are you sure you want to delete \"%{name}\" Value Stream?"
+msgstr ""
+
msgid "Are you sure you want to delete %{name}?"
msgstr ""
@@ -3148,6 +3257,9 @@ msgstr "確定è¦åˆªé™¤é€™äº›ç”¢ç‰©å—Žï¼Ÿ"
msgid "Are you sure you want to delete this %{typeOfComment}?"
msgstr "確定è¦åˆªé™¤æ­¤%{typeOfComment}嗎?"
+msgid "Are you sure you want to delete this SSH key?"
+msgstr ""
+
msgid "Are you sure you want to delete this board?"
msgstr "確定è¦åˆªé™¤æ­¤çœ‹æ¿å—Žï¼Ÿ"
@@ -3172,6 +3284,10 @@ msgstr ""
msgid "Are you sure you want to erase this build?"
msgstr "你確定è¦åˆªé™¤é€™å€‹çµ„建嗎?"
+msgid "Are you sure you want to import %d repository?"
+msgid_plural "Are you sure you want to import %d repositories?"
+msgstr[0] ""
+
msgid "Are you sure you want to lose unsaved changes?"
msgstr "確定è¦æ”¾æ£„未儲存的變更嗎?"
@@ -3181,15 +3297,15 @@ msgstr "您確定è¦æ¨æ£„議題資訊嗎?"
msgid "Are you sure you want to merge immediately?"
msgstr "您確定è¦ç«‹å³åˆä½µå—Žï¼Ÿ"
-msgid "Are you sure you want to permanently delete this license?"
-msgstr "您確定è¦æ°¸ä¹…刪除此授權æ¢æ¬¾å—Žï¼Ÿ"
-
msgid "Are you sure you want to re-deploy this environment?"
msgstr ""
msgid "Are you sure you want to regenerate the public key? You will have to update the public key on the remote server before mirroring will work again."
msgstr ""
+msgid "Are you sure you want to reindex?"
+msgstr ""
+
msgid "Are you sure you want to remove %{group_name}?"
msgstr "您確定è¦ç§»é™¤ %{group_name} 嗎?"
@@ -3217,6 +3333,9 @@ msgstr ""
msgid "Are you sure you want to revoke this nickname?"
msgstr ""
+msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
+msgstr ""
+
msgid "Are you sure you want to stop this environment?"
msgstr ""
@@ -3238,6 +3357,9 @@ msgstr ""
msgid "Are you sure? The device will be signed out of GitLab and all remember me tokens revoked."
msgstr ""
+msgid "Are you sure? This will invalidate your registered applications and U2F / WebAuthn devices."
+msgstr ""
+
msgid "Are you sure? This will invalidate your registered applications and U2F devices."
msgstr ""
@@ -3256,9 +3378,6 @@ msgstr ""
msgid "Artifacts"
msgstr ""
-msgid "As U2F devices are only supported by a few browsers, we require that you set up a two-factor authentication app before a U2F device. That way you'll always be able to log in - even when you're using an unsupported browser."
-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 ""
@@ -3450,6 +3569,9 @@ msgstr ""
msgid "AuditLogs|Target"
msgstr ""
+msgid "AuditLogs|This month"
+msgstr ""
+
msgid "AuditLogs|User Events"
msgstr ""
@@ -3489,6 +3611,9 @@ msgstr ""
msgid "Authentication via U2F device failed."
msgstr ""
+msgid "Authentication via WebAuthn device failed."
+msgstr ""
+
msgid "Author"
msgstr ""
@@ -3756,15 +3881,6 @@ msgstr ""
msgid "BambooService|You must set up automatic revision labeling and a repository trigger in Bamboo."
msgstr ""
-msgid "BatchComments|Delete all pending comments"
-msgstr ""
-
-msgid "BatchComments|Discard review?"
-msgstr ""
-
-msgid "BatchComments|You're about to discard your review which will delete all of your pending comments. The deleted comments %{strong_start}cannot%{strong_end} be restored."
-msgstr ""
-
msgid "Be careful. Changing the project's namespace can have unintended side effects."
msgstr ""
@@ -3786,6 +3902,9 @@ msgstr ""
msgid "Bi-weekly code coverage"
msgstr ""
+msgid "Billable Users:"
+msgstr ""
+
msgid "Billing"
msgstr ""
@@ -3795,7 +3914,7 @@ msgstr ""
msgid "BillingPlans|@%{user_name} you are currently using the %{plan_name} plan."
msgstr ""
-msgid "BillingPlans|Congratulations, your new trial is activated"
+msgid "BillingPlans|Congratulations, your free trial is activated."
msgstr ""
msgid "BillingPlans|If you would like to downgrade your plan please contact %{support_link_start}Customer Support%{support_link_end}."
@@ -3858,6 +3977,9 @@ msgstr ""
msgid "Blame"
msgstr ""
+msgid "Block user"
+msgstr ""
+
msgid "Blocked"
msgstr ""
@@ -3873,31 +3995,37 @@ msgstr ""
msgid "Blog"
msgstr ""
-msgid "Board name"
-msgstr ""
-
msgid "Board scope"
msgstr ""
msgid "Board scope affects which issues are displayed for anyone who visits this board"
msgstr ""
-msgid "BoardBlankState|Add default lists"
+msgid "Boards"
+msgstr ""
+
+msgid "Boards and Board Lists"
msgstr ""
-msgid "BoardBlankState|Add the following default lists to your Issue Board with one click:"
+msgid "Boards|An error occurred while creating the issue. Please try again."
msgstr ""
-msgid "BoardBlankState|Nevermind, I'll use my own"
+msgid "Boards|An error occurred while creating the list. Please try again."
msgstr ""
-msgid "BoardBlankState|Starting out with the default set of lists will get you right on the way to making the most of your board."
+msgid "Boards|An error occurred while fetching issues. Please reload the page."
msgstr ""
-msgid "Boards"
+msgid "Boards|An error occurred while fetching the board issues. Please reload the page."
msgstr ""
-msgid "Boards and Board Lists"
+msgid "Boards|An error occurred while fetching the board swimlanes. Please reload the page."
+msgstr ""
+
+msgid "Boards|An error occurred while moving the issue. Please try again."
+msgstr ""
+
+msgid "Boards|An error occurred while updating the list. Please try again."
msgstr ""
msgid "Boards|Collapse"
@@ -3924,7 +4052,7 @@ msgstr ""
msgid "Branch %{branch_name} was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr ""
-msgid "Branch has changed"
+msgid "Branch changed"
msgstr ""
msgid "Branch is already taken"
@@ -4230,6 +4358,9 @@ msgstr ""
msgid "CLOSED (MOVED)"
msgstr ""
+msgid "CODEOWNERS rule violation"
+msgstr ""
+
msgid "CONTRIBUTING"
msgstr ""
@@ -4260,9 +4391,6 @@ msgstr ""
msgid "Can't create snippet: %{err}"
msgstr ""
-msgid "Can't edit as source branch was deleted"
-msgstr ""
-
msgid "Can't fetch content for the blob: %{err}"
msgstr ""
@@ -4275,9 +4403,6 @@ msgstr ""
msgid "Can't load mermaid module: %{err}"
msgstr ""
-msgid "Can't remove group members without group managed account"
-msgstr ""
-
msgid "Can't scan the code?"
msgstr ""
@@ -4320,6 +4445,9 @@ msgstr ""
msgid "Cannot create the abuse report. This user has been blocked."
msgstr ""
+msgid "Cannot enable shared runners because parent group does not allow it"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -4425,6 +4553,15 @@ msgstr ""
msgid "Change your password or recover your current one"
msgstr ""
+msgid "ChangeReviewer|Reviewer changed from %{old} to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Reviewer changed to %{new}"
+msgstr ""
+
+msgid "ChangeReviewer|Unassigned"
+msgstr ""
+
msgid "ChangeTypeActionLabel|Pick into branch"
msgstr ""
@@ -4464,6 +4601,9 @@ msgstr ""
msgid "Changes the title to \"%{title_param}\"."
msgstr ""
+msgid "Changes were successfully made."
+msgstr ""
+
msgid "Changes won't take place until the index is %{link_start}recreated%{link_end}."
msgstr ""
@@ -4869,6 +5009,9 @@ msgstr ""
msgid "CiVariables|Protected"
msgstr ""
+msgid "CiVariables|Remove variable"
+msgstr ""
+
msgid "CiVariables|Remove variable row"
msgstr ""
@@ -4947,9 +5090,6 @@ msgstr ""
msgid "Clear due date"
msgstr ""
-msgid "Clear input"
-msgstr ""
-
msgid "Clear recent searches"
msgstr ""
@@ -4998,6 +5138,9 @@ msgstr ""
msgid "Client authentication key password"
msgstr ""
+msgid "Client request timeout"
+msgstr ""
+
msgid "Clients"
msgstr ""
@@ -5082,6 +5225,27 @@ msgstr ""
msgid "Cluster type must be specificed for Stages::ClusterEndpointInserter"
msgstr ""
+msgid "ClusterAgents|Configuration"
+msgstr ""
+
+msgid "ClusterAgents|Connect your cluster with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate Kubernetes with a GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Integrate with the GitLab Agent"
+msgstr ""
+
+msgid "ClusterAgents|Name"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Agent also requires %{linkStart}enabling the Agent Server%{linkEnd}"
+msgstr ""
+
+msgid "ClusterAgents|The GitLab Kubernetes Agent allows an Infrastructure as Code, GitOps approach to integrating Kubernetes clusters with GitLab. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "ClusterAgent|This feature is only available for premium plans"
msgstr ""
@@ -5151,10 +5315,10 @@ msgstr ""
msgid "ClusterIntegration|All installed applications and related resources"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster."
+msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{linkStart}More information%{linkEnd}"
msgstr ""
-msgid "ClusterIntegration|Allow GitLab to manage namespace and service accounts for this cluster. %{startLink}More information%{endLink}"
+msgid "ClusterIntegration|Allow GitLab to manage namespaces and service accounts for this cluster."
msgstr ""
msgid "ClusterIntegration|Alternatively, "
@@ -5175,6 +5339,9 @@ msgstr ""
msgid "ClusterIntegration|An error occurred while trying to fetch zone machine types: %{error}"
msgstr ""
+msgid "ClusterIntegration|An unknown error occurred while attempting to connect to Kubernetes."
+msgstr ""
+
msgid "ClusterIntegration|Any project namespaces"
msgstr ""
@@ -5190,6 +5357,9 @@ msgstr ""
msgid "ClusterIntegration|Authenticate with Amazon Web Services"
msgstr ""
+msgid "ClusterIntegration|Authentication Error"
+msgstr ""
+
msgid "ClusterIntegration|Base domain"
msgstr ""
@@ -5208,13 +5378,22 @@ msgstr ""
msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}security group %{externalLinkIcon} %{endLink} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
+msgid "ClusterIntegration|Check your CA certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Check your cluster status"
+msgstr ""
+
+msgid "ClusterIntegration|Check your token"
msgstr ""
-msgid "ClusterIntegration|Choose the %{startLink}subnets %{externalLinkIcon} %{endLink} in your VPC where your worker nodes will run."
+msgid "ClusterIntegration|Choose the %{linkStart}security group %{linkEnd} to apply to the EKS-managed Elastic Network Interfaces that are created in your worker node subnets."
msgstr ""
-msgid "ClusterIntegration|Choose the worker node %{startLink}instance type %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Choose the %{linkStart}subnets %{linkEnd} in your VPC where your worker nodes will run."
+msgstr ""
+
+msgid "ClusterIntegration|Choose the worker node %{linkStart}instance type%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Choose which applications to install on your Kubernetes cluster."
@@ -5226,10 +5405,7 @@ msgstr ""
msgid "ClusterIntegration|Clear cluster cache"
msgstr ""
-msgid "ClusterIntegration|Clear the local cache of namespace and service accounts. This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
-msgstr ""
-
-msgid "ClusterIntegration|Cluster being created"
+msgid "ClusterIntegration|Clear the local cache of namespace and service accounts."
msgstr ""
msgid "ClusterIntegration|Cluster management project (alpha)"
@@ -5241,15 +5417,21 @@ msgstr ""
msgid "ClusterIntegration|Cluster_applications artifact too big. Maximum allowable size: %{human_size}"
msgstr ""
-msgid "ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters."
+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|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}"
+msgid "ClusterIntegration|Clusters connected with a certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Connect cluster with certificate"
msgstr ""
msgid "ClusterIntegration|Connect existing cluster"
msgstr ""
+msgid "ClusterIntegration|Connection Error"
+msgstr ""
+
msgid "ClusterIntegration|Copy API URL"
msgstr ""
@@ -5325,6 +5507,12 @@ msgstr ""
msgid "ClusterIntegration|Deletes all GitLab resources attached to this cluster during removal"
msgstr ""
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared."
+msgstr ""
+
+msgid "ClusterIntegration|Deploy each environment to its own namespace. Otherwise, environments within a project share a project-wide namespace. Note that anyone who can trigger a deployment of a namespace can read its secrets. If modified, existing environments will use their current namespaces until the cluster cache is cleared. %{linkStart}More information%{linkEnd}"
+msgstr ""
+
msgid "ClusterIntegration|Did you know?"
msgstr ""
@@ -5394,6 +5582,9 @@ msgstr ""
msgid "ClusterIntegration|Fluentd is an open source data collector, which lets you unify the data collection and consumption for a better use and understanding of data. It requires at least one of the following logs to be successfully installed."
msgstr ""
+msgid "ClusterIntegration|GitLab Agent managed clusters"
+msgstr ""
+
msgid "ClusterIntegration|GitLab Container Network Policies"
msgstr ""
@@ -5406,6 +5597,12 @@ msgstr ""
msgid "ClusterIntegration|GitLab Runner connects to the repository and executes CI/CD jobs, pushing results back and deploying applications to production."
msgstr ""
+msgid "ClusterIntegration|GitLab failed to authenticate."
+msgstr ""
+
+msgid "ClusterIntegration|GitLab failed to connect to the cluster."
+msgstr ""
+
msgid "ClusterIntegration|GitLab-managed cluster"
msgstr ""
@@ -5427,6 +5624,9 @@ msgstr ""
msgid "ClusterIntegration|Group cluster"
msgstr ""
+msgid "ClusterIntegration|HTTP Error"
+msgstr ""
+
msgid "ClusterIntegration|Helm Tiller"
msgstr ""
@@ -5460,7 +5660,10 @@ msgstr ""
msgid "ClusterIntegration|Instance type"
msgstr ""
-msgid "ClusterIntegration|Integrate Kubernetes cluster automation"
+msgid "ClusterIntegration|Integrate Kubernetes with a cluster certificate"
+msgstr ""
+
+msgid "ClusterIntegration|Integrate with a cluster certificate"
msgstr ""
msgid "ClusterIntegration|Issuer Email"
@@ -5496,9 +5699,6 @@ msgstr ""
msgid "ClusterIntegration|Knative extends Kubernetes to provide a set of middleware components that are essential to build modern, source-centric, and container-based applications that can run anywhere: on premises, in the cloud, or even in a third-party data center."
msgstr ""
-msgid "ClusterIntegration|Kubernetes cluster"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes cluster is being created..."
msgstr ""
@@ -5511,9 +5711,6 @@ msgstr ""
msgid "ClusterIntegration|Kubernetes clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr ""
-msgid "ClusterIntegration|Kubernetes clusters can be used to deploy applications and to provide Review Apps for this project"
-msgstr ""
-
msgid "ClusterIntegration|Kubernetes version"
msgstr ""
@@ -5526,7 +5723,7 @@ msgstr ""
msgid "ClusterIntegration|Learn more about %{help_link_start}zones%{help_link_end}."
msgstr ""
-msgid "ClusterIntegration|Learn more about %{startLink}Regions %{externalLinkIcon}%{endLink}."
+msgid "ClusterIntegration|Learn more about %{linkStart}Regions%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Learn more about Kubernetes"
@@ -5571,12 +5768,18 @@ msgstr ""
msgid "ClusterIntegration|Machine type"
msgstr ""
+msgid "ClusterIntegration|Make sure your API endpoint is correct"
+msgstr ""
+
msgid "ClusterIntegration|Make sure your account %{link_to_requirements} to create Kubernetes clusters"
msgstr ""
msgid "ClusterIntegration|Manage your Kubernetes cluster by visiting %{provider_link}"
msgstr ""
+msgid "ClusterIntegration|Namespace per environment"
+msgstr ""
+
msgid "ClusterIntegration|No IAM Roles found"
msgstr ""
@@ -5622,6 +5825,9 @@ msgstr ""
msgid "ClusterIntegration|No zones matched your search"
msgstr ""
+msgid "ClusterIntegration|Node calculations use the Kubernetes Metrics API. Make sure your cluster has metrics installed"
+msgstr ""
+
msgid "ClusterIntegration|Number of nodes"
msgstr ""
@@ -5664,6 +5870,9 @@ msgstr ""
msgid "ClusterIntegration|RBAC-enabled cluster"
msgstr ""
+msgid "ClusterIntegration|Read our %{linkStart}help page%{linkEnd} on Kubernetes cluster integration."
+msgstr ""
+
msgid "ClusterIntegration|Read our %{link_start}help page%{link_end} on Kubernetes cluster integration."
msgstr ""
@@ -5766,7 +5975,7 @@ msgstr ""
msgid "ClusterIntegration|Select a VPC to choose a subnet"
msgstr ""
-msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select a VPC to use for your EKS Cluster resources. To use a new VPC, first create one on %{linkStart}Amazon Web Services %{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select a network to choose a subnetwork"
@@ -5799,7 +6008,7 @@ msgstr ""
msgid "ClusterIntegration|Select project to choose zone"
msgstr ""
-msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Select the key pair name that will be used to create EC2 nodes. To use a new key pair name, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Select zone"
@@ -5889,9 +6098,18 @@ msgstr ""
msgid "ClusterIntegration|There was a problem authenticating with your cluster. Please ensure your CA Certificate and Token are valid."
msgstr ""
+msgid "ClusterIntegration|There was an HTTP error when connecting to your cluster."
+msgstr ""
+
msgid "ClusterIntegration|This account must have permissions to create a Kubernetes cluster in the %{link_to_container_project} specified below"
msgstr ""
+msgid "ClusterIntegration|This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts."
+msgstr ""
+
+msgid "ClusterIntegration|This is necessary to clear existing environment-namespace associations from clusters previously managed by GitLab."
+msgstr ""
+
msgid "ClusterIntegration|This option will allow you to install applications on RBAC clusters."
msgstr ""
@@ -5916,9 +6134,21 @@ msgstr ""
msgid "ClusterIntegration|To use a new project, first create one on %{docsLinkStart}Google Cloud Platform%{docsLinkEnd}."
msgstr ""
+msgid "ClusterIntegration|Troubleshooting tips:"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Authenticate"
+msgstr ""
+
+msgid "ClusterIntegration|Unable to Connect"
+msgstr ""
+
msgid "ClusterIntegration|Uninstall %{appTitle}"
msgstr ""
+msgid "ClusterIntegration|Unknown Error"
+msgstr ""
+
msgid "ClusterIntegration|Update %{appTitle}"
msgstr ""
@@ -5979,7 +6209,7 @@ msgstr ""
msgid "ClusterIntegration|Your cluster API is unreachable. Please ensure your API URL is correct."
msgstr ""
-msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{startLink}Amazon Web Services %{externalLinkIcon} %{endLink}."
+msgid "ClusterIntegration|Your service role is distinct from the provision role used when authenticating. It will allow Amazon EKS and the Kubernetes control plane to manage AWS resources on your behalf. To use a new role, first create one on %{linkStart}Amazon Web Services%{linkEnd}."
msgstr ""
msgid "ClusterIntegration|Zone"
@@ -6099,6 +6329,9 @@ msgstr ""
msgid "Collapse"
msgstr ""
+msgid "Collapse all threads"
+msgstr ""
+
msgid "Collapse approvers"
msgstr ""
@@ -6247,7 +6480,7 @@ msgstr ""
msgid "Commit…"
msgstr ""
-msgid "Company"
+msgid "Community forum"
msgstr ""
msgid "Company name"
@@ -6256,6 +6489,9 @@ msgstr ""
msgid "Compare"
msgstr ""
+msgid "Compare %{oldCommitId}...%{newCommitId}"
+msgstr ""
+
msgid "Compare Git revisions"
msgstr ""
@@ -6271,6 +6507,9 @@ msgstr ""
msgid "Compare changes with the merge request target branch"
msgstr ""
+msgid "Compare submodule commit revisions"
+msgstr ""
+
msgid "Compare with previous version"
msgstr ""
@@ -6406,6 +6645,9 @@ msgstr ""
msgid "Configure the way a user creates a new account."
msgstr ""
+msgid "Configure which lists are shown for anyone who visits this board"
+msgstr ""
+
msgid "Confirm"
msgstr ""
@@ -6628,6 +6870,9 @@ msgstr[0] ""
msgid "ContainerRegistry|Set cleanup policy"
msgstr ""
+msgid "ContainerRegistry|Some tags were not deleted"
+msgstr ""
+
msgid "ContainerRegistry|Something went wrong while fetching the cleanup policy."
msgstr ""
@@ -6667,6 +6912,9 @@ msgstr ""
msgid "ContainerRegistry|Tags with names matching this regex pattern will %{italicStart}expire:%{italicEnd}"
msgstr ""
+msgid "ContainerRegistry|The cleanup policy timed out before it could delete all tags. An administrator can %{adminLinkStart}manually run cleanup now%{adminLinkEnd} or you can wait for the cleanup policy to automatically run again. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "ContainerRegistry|The last tag related to this image was recently removed. This empty image and any associated data will be automatically removed as part of the regular Garbage Collection process. If you have any questions, contact your administrator."
msgstr ""
@@ -6799,6 +7047,9 @@ msgstr ""
msgid "Contributions per group member"
msgstr ""
+msgid "Contributor"
+msgstr ""
+
msgid "Contributors"
msgstr ""
@@ -6928,6 +7179,9 @@ msgstr ""
msgid "Could not change HEAD: branch '%{branch}' does not exist"
msgstr ""
+msgid "Could not commit. An unexpected error occurred."
+msgstr ""
+
msgid "Could not connect to FogBugz, check your URL"
msgstr ""
@@ -6967,6 +7221,9 @@ msgstr ""
msgid "Could not find iteration"
msgstr ""
+msgid "Could not load instance counts. Please refresh the page to try again."
+msgstr ""
+
msgid "Could not remove the trigger."
msgstr ""
@@ -6991,10 +7248,10 @@ msgstr ""
msgid "Could not save prometheus manual configuration"
msgstr ""
-msgid "Could not udpdate wiki page"
+msgid "Could not update the LDAP settings"
msgstr ""
-msgid "Could not update the LDAP settings"
+msgid "Could not update wiki page"
msgstr ""
msgid "Could not upload your designs as one or more files uploaded are not supported."
@@ -7650,6 +7907,9 @@ msgstr ""
msgid "DastProfiles|Are you sure you want to delete this profile?"
msgstr ""
+msgid "DastProfiles|Could not create site validation token. Please refresh the page, or try again later."
+msgstr ""
+
msgid "DastProfiles|Could not create the scanner profile. Please try again."
msgstr ""
@@ -7674,6 +7934,12 @@ msgstr ""
msgid "DastProfiles|Could not fetch site profiles. Please refresh the page, or try again later."
msgstr ""
+msgid "DastProfiles|Could not retrieve site validation status. Please refresh the page, or try again later."
+msgstr ""
+
+msgid "DastProfiles|Could not update the scanner profile. Please try again."
+msgstr ""
+
msgid "DastProfiles|Could not update the site profile. Please try again."
msgstr ""
@@ -7689,7 +7955,7 @@ msgstr ""
msgid "DastProfiles|Download validation text file"
msgstr ""
-msgid "DastProfiles|Edit feature will come soon. Please create a new profile if changes needed"
+msgid "DastProfiles|Edit scanner profile"
msgstr ""
msgid "DastProfiles|Edit site profile"
@@ -7722,6 +7988,9 @@ msgstr ""
msgid "DastProfiles|No profiles created yet"
msgstr ""
+msgid "DastProfiles|Passive"
+msgstr ""
+
msgid "DastProfiles|Please enter a valid URL format, ex: http://www.example.com/home"
msgstr ""
@@ -7737,6 +8006,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan mode"
+msgstr ""
+
msgid "DastProfiles|Scanner Profile"
msgstr ""
@@ -7776,10 +8048,10 @@ msgstr ""
msgid "DastProfiles|Text file validation"
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
+msgid "DastProfiles|The maximum number of minutes allowed for the spider to traverse the site."
msgstr ""
-msgid "DastProfiles|The maximum number of seconds allowed for the spider to traverse the site."
+msgid "DastProfiles|The maximum number of seconds allowed for the site under test to respond to a request."
msgstr ""
msgid "DastProfiles|Validate"
@@ -7812,6 +8084,9 @@ msgstr ""
msgid "Date picker"
msgstr ""
+msgid "Date range"
+msgstr ""
+
msgid "Date range cannot exceed %{maxDateRange} days."
msgstr ""
@@ -7836,6 +8111,9 @@ msgstr ""
msgid "Days to merge"
msgstr ""
+msgid "Dear Administrator,"
+msgstr ""
+
msgid "Debug"
msgstr ""
@@ -7947,12 +8225,18 @@ msgstr ""
msgid "Delete"
msgstr ""
+msgid "Delete %{name}"
+msgstr ""
+
msgid "Delete Comment"
msgstr ""
msgid "Delete Snippet"
msgstr ""
+msgid "Delete Value Stream"
+msgstr ""
+
msgid "Delete account"
msgstr ""
@@ -7974,9 +8258,6 @@ msgstr ""
msgid "Delete label: %{label_name} ?"
msgstr ""
-msgid "Delete license"
-msgstr ""
-
msgid "Delete list"
msgstr ""
@@ -8052,15 +8333,6 @@ msgstr ""
msgid "Deleting a project places it into a read-only state until %{date}, at which point the project will be permanently deleted. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "Deleting the license failed."
-msgstr ""
-
-msgid "Deleting the license failed. The license was not found."
-msgstr ""
-
-msgid "Deleting the license failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "Deleting the project will delete its repository and all related resources including issues, merge requests etc."
msgstr ""
@@ -8550,7 +8822,10 @@ msgstr ""
msgid "DesignManagement|The maximum number of designs allowed to be uploaded is %{upload_limit}. Please try again."
msgstr ""
-msgid "DesignManagement|To upload designs, you'll need to enable LFS. %{requirements_link_start}More information%{requirements_link_end}"
+msgid "DesignManagement|There was an error moving your designs. Please upload your designs below."
+msgstr ""
+
+msgid "DesignManagement|To upload designs, you'll need to enable LFS and have admin enable hashed storage. %{requirements_link_start}More information%{requirements_link_end}"
msgstr ""
msgid "DesignManagement|Unresolve thread"
@@ -8562,6 +8837,9 @@ msgstr ""
msgid "DesignManagement|Upload skipped."
msgstr ""
+msgid "DesignManagement|Your designs are being copied and are on their way… Please refresh to update."
+msgstr ""
+
msgid "DesignManagement|and %{moreCount} more."
msgstr ""
@@ -8619,6 +8897,9 @@ msgstr ""
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
+msgid "Direct member"
+msgstr ""
+
msgid "Direction"
msgstr ""
@@ -8667,9 +8948,6 @@ msgstr ""
msgid "Discard draft"
msgstr ""
-msgid "Discard review"
-msgstr ""
-
msgid "DiscordService|Discord Notifications"
msgstr ""
@@ -8737,10 +9015,10 @@ msgstr ""
msgid "Dismiss Merge Request promotion"
msgstr ""
-msgid "Dismiss Selected"
+msgid "Dismiss Value Stream Analytics introduction box"
msgstr ""
-msgid "Dismiss Value Stream Analytics introduction box"
+msgid "Dismiss selected"
msgstr ""
msgid "Dismiss trial promotion"
@@ -8791,9 +9069,6 @@ msgstr ""
msgid "Documents reindexed: %{processed_documents} (%{percentage}%%)"
msgstr ""
-msgid "Doing"
-msgstr ""
-
msgid "Domain"
msgstr ""
@@ -8989,9 +9264,6 @@ msgstr ""
msgid "Edit environment"
msgstr ""
-msgid "Edit file"
-msgstr ""
-
msgid "Edit files in the editor and commit changes here"
msgstr ""
@@ -9004,6 +9276,12 @@ msgstr ""
msgid "Edit identity for %{user_name}"
msgstr ""
+msgid "Edit in Web IDE"
+msgstr ""
+
+msgid "Edit in single-file editor"
+msgstr ""
+
msgid "Edit issues"
msgstr ""
@@ -9031,10 +9309,10 @@ msgstr ""
msgid "Editing"
msgstr ""
-msgid "Elasticsearch"
+msgid "Elasticsearch AWS IAM credentials"
msgstr ""
-msgid "Elasticsearch AWS IAM credentials"
+msgid "Elasticsearch HTTP client timeout value in seconds."
msgstr ""
msgid "Elasticsearch indexing restrictions"
@@ -9043,9 +9321,6 @@ msgstr ""
msgid "Elasticsearch indexing started"
msgstr ""
-msgid "Elasticsearch integration. Elasticsearch AWS IAM."
-msgstr ""
-
msgid "Elasticsearch reindexing is already in progress"
msgstr ""
@@ -9073,9 +9348,6 @@ msgstr ""
msgid "Email Notification"
msgstr ""
-msgid "Email address"
-msgstr ""
-
msgid "Email could not be sent"
msgstr ""
@@ -9139,6 +9411,9 @@ msgstr ""
msgid "Emails sent from Service Desk will have this name"
msgstr ""
+msgid "Emails sent to %{email} will still be supported"
+msgstr ""
+
msgid "Emails separated by comma"
msgstr ""
@@ -9172,9 +9447,18 @@ msgstr ""
msgid "Enable"
msgstr ""
+msgid "Enable %{link_start}Gitpod%{link_end} integration to launch a development environment in your browser directly from GitLab."
+msgstr ""
+
msgid "Enable Auto DevOps"
msgstr ""
+msgid "Enable Gitpod"
+msgstr ""
+
+msgid "Enable Gitpod?"
+msgstr ""
+
msgid "Enable HTML emails"
msgstr ""
@@ -9304,9 +9588,6 @@ msgstr ""
msgid "Encountered an error while rendering: %{err}"
msgstr ""
-msgid "End date"
-msgstr ""
-
msgid "Ends at (UTC)"
msgstr ""
@@ -9466,7 +9747,7 @@ msgstr ""
msgid "EnvironmentsDashboard|The environments dashboard provides a summary of each project's environments' status, including pipeline and alert statuses."
msgstr ""
-msgid "EnvironmentsDashboard|This dashboard displays a maximum of 7 projects and 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
+msgid "EnvironmentsDashboard|This dashboard displays 3 environments per project, and is linked to the Operations Dashboard. When you add or remove a project from one dashboard, GitLab adds or removes the project from the other. %{readMoreLink}"
msgstr ""
msgid "Environments|An error occurred while canceling the auto stop, please try again"
@@ -9787,6 +10068,9 @@ msgstr ""
msgid "Error deleting project. Check logs for error details."
msgstr ""
+msgid "Error fetching burnup chart data"
+msgstr ""
+
msgid "Error fetching diverging counts for branches. Please try again."
msgstr ""
@@ -9865,6 +10149,9 @@ msgstr ""
msgid "Error occurred when saving assignees"
msgstr ""
+msgid "Error occurred when saving reviewers"
+msgstr ""
+
msgid "Error occurred when toggling the notification subscription"
msgstr ""
@@ -10117,10 +10404,13 @@ msgstr ""
msgid "Expand all"
msgstr ""
-msgid "Expand approvers"
+msgid "Expand all files"
msgstr ""
-msgid "Expand dropdown"
+msgid "Expand all threads"
+msgstr ""
+
+msgid "Expand approvers"
msgstr ""
msgid "Expand milestones"
@@ -10291,6 +10581,9 @@ msgstr ""
msgid "Failed to create Merge Request. Please try again."
msgstr ""
+msgid "Failed to create To-Do for the design."
+msgstr ""
+
msgid "Failed to create a branch for this issue. Please try again."
msgstr ""
@@ -10330,6 +10623,12 @@ msgstr ""
msgid "Failed to load authors. Please try again."
msgstr ""
+msgid "Failed to load branches. Please try again."
+msgstr ""
+
+msgid "Failed to load deploy keys."
+msgstr ""
+
msgid "Failed to load emoji list."
msgstr ""
@@ -10345,6 +10644,9 @@ msgstr ""
msgid "Failed to load groups & users."
msgstr ""
+msgid "Failed to load groups, users and deploy keys."
+msgstr ""
+
msgid "Failed to load labels. Please try again."
msgstr ""
@@ -10354,6 +10656,12 @@ msgstr ""
msgid "Failed to load related branches"
msgstr ""
+msgid "Failed to load sidebar confidential toggle"
+msgstr ""
+
+msgid "Failed to load sidebar lock status"
+msgstr ""
+
msgid "Failed to load stacktrace."
msgstr ""
@@ -10381,6 +10689,9 @@ msgstr ""
msgid "Failed to publish issue on status page."
msgstr ""
+msgid "Failed to remove To-Do for the design."
+msgstr ""
+
msgid "Failed to remove a Zoom meeting"
msgstr ""
@@ -10423,6 +10734,9 @@ msgstr ""
msgid "Failed to signing using smartcard authentication"
msgstr ""
+msgid "Failed to toggle To-Do for the design."
+msgstr ""
+
msgid "Failed to update branch!"
msgstr ""
@@ -10535,7 +10849,7 @@ msgstr ""
msgid "FeatureFlags|Edit User List"
msgstr ""
-msgid "FeatureFlags|Enable features for specific users and specific environments by defining feature flag strategies."
+msgid "FeatureFlags|Enable features for specific users and environments by configuring feature flag strategies."
msgstr ""
msgid "FeatureFlags|Environment Spec"
@@ -10595,7 +10909,7 @@ msgstr ""
msgid "FeatureFlags|Include additional user IDs"
msgstr ""
-msgid "FeatureFlags|Install a %{docs_link_anchored_start}compatible client library%{docs_link_anchored_end} and specify the API URL, application name, and instance ID during the configuration setup. %{docs_link_start}More Information%{docs_link_end}"
+msgid "FeatureFlags|Install a %{docsLinkAnchoredStart}compatible client library%{docsLinkAnchoredEnd} and specify the API URL, application name, and instance ID during the configuration setup. %{docsLinkStart}More Information%{docsLinkEnd}"
msgstr ""
msgid "FeatureFlags|Instance ID"
@@ -10607,6 +10921,9 @@ msgstr ""
msgid "FeatureFlags|Loading feature flags"
msgstr ""
+msgid "FeatureFlags|Loading user lists"
+msgstr ""
+
msgid "FeatureFlags|More information"
msgstr ""
@@ -10625,7 +10942,7 @@ msgstr ""
msgid "FeatureFlags|New feature flag"
msgstr ""
-msgid "FeatureFlags|New list"
+msgid "FeatureFlags|New user list"
msgstr ""
msgid "FeatureFlags|Percent of users"
@@ -10664,6 +10981,9 @@ msgstr ""
msgid "FeatureFlags|There was an error fetching the feature flags."
msgstr ""
+msgid "FeatureFlags|There was an error fetching the user lists."
+msgstr ""
+
msgid "FeatureFlags|There was an error retrieving user lists"
msgstr ""
@@ -10679,6 +10999,9 @@ msgstr ""
msgid "FeatureFlags|User List"
msgstr ""
+msgid "FeatureFlags|User Lists"
+msgstr ""
+
msgid "FeatureFlag|List"
msgstr ""
@@ -10706,15 +11029,6 @@ msgstr ""
msgid "Fetching incoming email"
msgstr ""
-msgid "Fetching licenses failed."
-msgstr ""
-
-msgid "Fetching licenses failed. The request endpoint was not found."
-msgstr ""
-
-msgid "Fetching licenses failed. You are not permitted to perform this action."
-msgstr ""
-
msgid "File"
msgstr ""
@@ -10817,12 +11131,21 @@ msgstr ""
msgid "Filter by status"
msgstr ""
+msgid "Filter by test cases that are currently archived."
+msgstr ""
+
+msgid "Filter by test cases that are currently opened."
+msgstr ""
+
msgid "Filter by two-factor authentication"
msgstr ""
msgid "Filter by user"
msgstr ""
+msgid "Filter parameters are not valid. Make sure that the end date is after the start date."
+msgstr ""
+
msgid "Filter pipelines"
msgstr ""
@@ -10838,7 +11161,7 @@ msgstr ""
msgid "Filter results..."
msgstr ""
-msgid "Filter your projects by name"
+msgid "Filter your repositories by name"
msgstr ""
msgid "Filter..."
@@ -10847,7 +11170,7 @@ msgstr ""
msgid "Find File"
msgstr ""
-msgid "Find bugs in your code with coverage-guided fuzzing"
+msgid "Find bugs in your code with coverage-guided fuzzing."
msgstr ""
msgid "Find by path"
@@ -10874,9 +11197,6 @@ msgstr ""
msgid "Finish editing this message first!"
msgstr ""
-msgid "Finish review"
-msgstr ""
-
msgid "Finish setting up your dedicated account for %{group_name}."
msgstr ""
@@ -10946,6 +11266,9 @@ msgstr ""
msgid "Footer message"
msgstr ""
+msgid "For a faster browsing experience, some files are collapsed by default."
+msgstr ""
+
msgid "For help setting up the Service Desk for your instance, please contact an administrator."
msgstr ""
@@ -10955,6 +11278,9 @@ msgstr ""
msgid "For more info, read the documentation."
msgstr ""
+msgid "For more information on how the number of active users is calculated, see the %{self_managed_subscriptions_doc_link} documentation."
+msgstr ""
+
msgid "For more information, go to the "
msgstr ""
@@ -11093,6 +11419,9 @@ msgstr ""
msgid "Generate new token"
msgstr ""
+msgid "Generic package file size in bytes"
+msgstr ""
+
msgid "Geo"
msgstr "Geo"
@@ -11354,6 +11683,9 @@ msgstr ""
msgid "Geo|Please refer to Geo Troubleshooting."
msgstr ""
+msgid "Geo|Primary node"
+msgstr ""
+
msgid "Geo|Project"
msgstr ""
@@ -11396,6 +11728,9 @@ msgstr ""
msgid "Geo|Review replication status, and resynchronize and reverify items with the primary node."
msgstr ""
+msgid "Geo|Secondary node"
+msgstr ""
+
msgid "Geo|Status"
msgstr ""
@@ -11435,6 +11770,9 @@ msgstr ""
msgid "Geo|URL must be a valid url (ex: https://gitlab.com)"
msgstr ""
+msgid "Geo|Undefined"
+msgstr ""
+
msgid "Geo|Unknown state"
msgstr ""
@@ -11510,10 +11848,16 @@ msgstr ""
msgid "GitHub import"
msgstr ""
+msgid "GitLab"
+msgstr ""
+
msgid "GitLab / Unsubscribe"
msgstr ""
-msgid "GitLab Enterprise Edition %{plan}"
+msgid "GitLab API"
+msgstr ""
+
+msgid "GitLab Billing Team."
msgstr ""
msgid "GitLab Group Runners can execute code for all the projects in this group."
@@ -11525,12 +11869,18 @@ msgstr ""
msgid "GitLab Issue"
msgstr ""
+msgid "GitLab Pages"
+msgstr ""
+
msgid "GitLab Service Desk is a simple way to allow people to create issues in your GitLab instance without needing their own user account. It provides a unique email address for end users to create issues in a project, and replies can be sent either through the GitLab interface or by email. End users will only see the thread through email."
msgstr ""
msgid "GitLab Shared Runners execute code of different projects on the same Runner unless you configure GitLab Runner Autoscale with MaxBuilds 1 (which it is on GitLab.com)."
msgstr ""
+msgid "GitLab Shell"
+msgstr ""
+
msgid "GitLab Support Bot"
msgstr ""
@@ -11540,7 +11890,7 @@ msgstr ""
msgid "GitLab User"
msgstr ""
-msgid "GitLab allows you to continue using your license even if you exceed the number of seats you purchased. You will be required to pay for these seats when you renew your license."
+msgid "GitLab Workhorse"
msgstr ""
msgid "GitLab commit"
@@ -11708,6 +12058,21 @@ msgstr ""
msgid "Gitlab Pages"
msgstr ""
+msgid "Gitpod"
+msgstr ""
+
+msgid "Gitpod|Add the URL to your Gitpod instance configured to read your GitLab projects."
+msgstr ""
+
+msgid "Gitpod|Enable Gitpod integration"
+msgstr ""
+
+msgid "Gitpod|Gitpod URL"
+msgstr ""
+
+msgid "Gitpod|e.g. https://gitpod.example.com"
+msgstr ""
+
msgid "Given access %{time_ago}"
msgstr ""
@@ -12215,9 +12580,6 @@ msgstr ""
msgid "GroupSAML|Valid SAML Response"
msgstr ""
-msgid "GroupSAML|With group managed accounts enabled, all the users without a group managed account will be excluded from the group."
-msgstr ""
-
msgid "GroupSAML|With prohibit outer forks flag enabled group members will be able to fork project only inside your group."
msgstr ""
@@ -12431,10 +12793,10 @@ msgstr ""
msgid "GroupsNew|Create group"
msgstr ""
-msgid "GroupsNew|GitLab group export"
+msgid "GroupsNew|Import"
msgstr ""
-msgid "GroupsNew|Import"
+msgid "GroupsNew|Import a GitLab group export file"
msgstr ""
msgid "GroupsNew|Import group"
@@ -12576,6 +12938,9 @@ msgid "Hide chart"
msgid_plural "Hide charts"
msgstr[0] ""
+msgid "Hide comments on this file"
+msgstr ""
+
msgid "Hide details"
msgstr ""
@@ -12619,6 +12984,15 @@ msgstr ""
msgid "Highest role:"
msgstr ""
+msgid "HighlightBar|Alert events:"
+msgstr ""
+
+msgid "HighlightBar|Alert start time:"
+msgstr ""
+
+msgid "HighlightBar|Original alert:"
+msgstr ""
+
msgid "History"
msgstr ""
@@ -12796,6 +13170,9 @@ msgstr ""
msgid "If enabled, access to projects will be validated on an external service using their classification label."
msgstr ""
+msgid "If the number of active users exceeds the user limit, you will be charged for the number of %{users_over_license_link} at your next license reconciliation."
+msgstr ""
+
msgid "If there is no previous license or if the previous license has expired, some GitLab functionality will be blocked until a new, valid license is uploaded."
msgstr ""
@@ -12835,9 +13212,6 @@ msgstr ""
msgid "If your HTTP repository is not publicly accessible, add your credentials."
msgstr ""
-msgid "Iglu registry URL (optional)"
-msgstr ""
-
msgid "Ignore"
msgstr ""
@@ -12874,6 +13248,14 @@ msgstr ""
msgid "Import"
msgstr ""
+msgid "Import %d compatible repository"
+msgid_plural "Import %d compatible repositories"
+msgstr[0] ""
+
+msgid "Import %d repository"
+msgid_plural "Import %d repositories"
+msgstr[0] ""
+
msgid "Import CSV"
msgstr ""
@@ -12883,15 +13265,9 @@ msgstr ""
msgid "Import all compatible projects"
msgstr ""
-msgid "Import all compatible repositories"
-msgstr ""
-
msgid "Import all projects"
msgstr ""
-msgid "Import all repositories"
-msgstr ""
-
msgid "Import an exported GitLab project"
msgstr ""
@@ -12979,6 +13355,9 @@ msgstr ""
msgid "ImportProjects|Error importing repository %{project_safe_import_url} into %{project_full_path} - %{message}"
msgstr ""
+msgid "ImportProjects|Import repositories"
+msgstr ""
+
msgid "ImportProjects|Importing the project failed"
msgstr ""
@@ -12991,7 +13370,7 @@ msgstr ""
msgid "ImportProjects|Requesting your %{provider} repositories failed"
msgstr ""
-msgid "ImportProjects|Select the projects you want to import"
+msgid "ImportProjects|Select the repositories you want to import"
msgstr ""
msgid "ImportProjects|The remote data could not be imported."
@@ -13027,9 +13406,6 @@ msgstr ""
msgid "In order to enable Service Desk for your instance, you must first set up incoming email."
msgstr ""
-msgid "In order to gather accurate feature usage data, it can take 1 to 2 weeks to see your index."
-msgstr ""
-
msgid "In order to personalize your experience with GitLab%{br_tag}we would like to know a bit more about you."
msgstr ""
@@ -13060,18 +13436,30 @@ msgstr ""
msgid "IncidentManagement|Create incident"
msgstr ""
+msgid "IncidentManagement|Critical - S1"
+msgstr ""
+
msgid "IncidentManagement|Date created"
msgstr ""
msgid "IncidentManagement|Display your incidents in a dedicated view"
msgstr ""
+msgid "IncidentManagement|High - S2"
+msgstr ""
+
msgid "IncidentManagement|Incident"
msgstr ""
msgid "IncidentManagement|Incidents"
msgstr ""
+msgid "IncidentManagement|Low - S4"
+msgstr ""
+
+msgid "IncidentManagement|Medium - S3"
+msgstr ""
+
msgid "IncidentManagement|No incidents to display."
msgstr ""
@@ -13084,6 +13472,9 @@ msgstr ""
msgid "IncidentManagement|Published to status page"
msgstr ""
+msgid "IncidentManagement|Severity"
+msgstr ""
+
msgid "IncidentManagement|There are no closed incidents"
msgstr ""
@@ -13093,6 +13484,9 @@ msgstr ""
msgid "IncidentManagement|Unassigned"
msgstr ""
+msgid "IncidentManagement|Unknown"
+msgstr ""
+
msgid "IncidentManagement|Unpublished"
msgstr ""
@@ -13114,6 +13508,15 @@ msgstr ""
msgid "Incidents"
msgstr ""
+msgid "Incident|Alert details"
+msgstr ""
+
+msgid "Incident|Summary"
+msgstr ""
+
+msgid "Incident|There was an issue loading alert data. Please try again."
+msgstr ""
+
msgid "Include a Terms of Service agreement and Privacy Policy that all users must accept."
msgstr ""
@@ -13174,6 +13577,9 @@ msgstr ""
msgid "Information about additional Pages templates and how to install them can be found in our %{pages_getting_started_guide}."
msgstr ""
+msgid "Inherited"
+msgstr ""
+
msgid "Inherited:"
msgstr ""
@@ -13253,7 +13659,22 @@ msgstr ""
msgid "Instance administrators group already exists"
msgstr ""
-msgid "Instance license"
+msgid "InstanceStatistics|Groups"
+msgstr ""
+
+msgid "InstanceStatistics|Issues"
+msgstr ""
+
+msgid "InstanceStatistics|Merge Requests"
+msgstr ""
+
+msgid "InstanceStatistics|Pipelines"
+msgstr ""
+
+msgid "InstanceStatistics|Projects"
+msgstr ""
+
+msgid "InstanceStatistics|Users"
msgstr ""
msgid "Integration"
@@ -13265,6 +13686,12 @@ msgstr ""
msgid "Integrations"
msgstr ""
+msgid "Integrations|%{integration} settings saved and active."
+msgstr ""
+
+msgid "Integrations|%{integration} settings saved, but not active."
+msgstr ""
+
msgid "Integrations|All details"
msgstr ""
@@ -13274,6 +13701,12 @@ msgstr ""
msgid "Integrations|Comment settings:"
msgstr ""
+msgid "Integrations|Connection failed. Please check your settings."
+msgstr ""
+
+msgid "Integrations|Connection successful."
+msgstr ""
+
msgid "Integrations|Default settings are inherited from the group level."
msgstr ""
@@ -13289,6 +13722,15 @@ msgstr ""
msgid "Integrations|Includes commit title and branch"
msgstr ""
+msgid "Integrations|Projects using custom settings will not be impacted unless the project owner chooses to use instance-level defaults."
+msgstr ""
+
+msgid "Integrations|Save settings?"
+msgstr ""
+
+msgid "Integrations|Saving will update the default settings for all projects that are not using custom settings."
+msgstr ""
+
msgid "Integrations|Standard"
msgstr ""
@@ -13421,6 +13863,9 @@ msgstr ""
msgid "Invitation"
msgstr ""
+msgid "Invitation declined"
+msgstr ""
+
msgid "Invite"
msgstr ""
@@ -13472,6 +13917,42 @@ 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|%{linkStart}Read more%{linkEnd} about role permissions"
+msgstr ""
+
+msgid "InviteMembersModal|Access expiration date (optional)"
+msgstr ""
+
+msgid "InviteMembersModal|Cancel"
+msgstr ""
+
+msgid "InviteMembersModal|Choose a role permission"
+msgstr ""
+
+msgid "InviteMembersModal|GitLab member or Email address"
+msgstr ""
+
+msgid "InviteMembersModal|Invite"
+msgstr ""
+
+msgid "InviteMembersModal|Invite team members"
+msgstr ""
+
+msgid "InviteMembersModal|Search for members to invite"
+msgstr ""
+
+msgid "InviteMembersModal|User not invited. Feature coming soon!"
+msgstr ""
+
+msgid "InviteMembersModal|Users were succesfully added"
+msgstr ""
+
+msgid "InviteMembersModal|You're inviting members to the %{group_name} group"
+msgstr ""
+
+msgid "InviteMembers|Invite team members"
+msgstr ""
+
msgid "Invited"
msgstr ""
@@ -13526,10 +14007,13 @@ msgstr ""
msgid "Issue cannot be found."
msgstr ""
+msgid "Issue created from vulnerability %{vulnerability_link}"
+msgstr ""
+
msgid "Issue events"
msgstr ""
-msgid "Issue first depoloyed to production"
+msgid "Issue first deployed to production"
msgstr ""
msgid "Issue label"
@@ -13607,6 +14091,9 @@ msgstr ""
msgid "IssueTracker|Custom issue tracker"
msgstr ""
+msgid "IssueTracker|EWM work items tracker"
+msgstr ""
+
msgid "IssueTracker|Redmine issue tracker"
msgstr ""
@@ -13673,6 +14160,9 @@ msgstr ""
msgid "It looks like you have some draft commits in this branch."
msgstr ""
+msgid "It may be several days before you see feature usage data."
+msgstr ""
+
msgid "It must have a header row and at least two columns: the first column is the issue title and the second column is the issue description. The separator is automatically detected."
msgstr ""
@@ -13955,15 +14445,15 @@ msgstr ""
msgid "Join Zoom meeting"
msgstr ""
+msgid "Joined %{time_ago}"
+msgstr ""
+
msgid "Jul"
msgstr "7月"
msgid "July"
msgstr "7月"
-msgid "Jump to first unresolved thread"
-msgstr ""
-
msgid "Jump to next unresolved thread"
msgstr ""
@@ -13997,6 +14487,9 @@ msgstr ""
msgid "Keyboard shortcuts"
msgstr ""
+msgid "KeyboardKey|Ctrl+"
+msgstr ""
+
msgid "Keys"
msgstr ""
@@ -14045,6 +14538,9 @@ msgstr ""
msgid "LDAP Synchronization"
msgstr ""
+msgid "LDAP group settings"
+msgstr ""
+
msgid "LDAP settings"
msgstr ""
@@ -14054,6 +14550,9 @@ msgstr ""
msgid "LDAP sync in progress. This could take a few minutes. Refresh the page to see the changes."
msgstr ""
+msgid "LDAP synchronizations"
+msgstr ""
+
msgid "LFS"
msgstr "LFS"
@@ -14133,7 +14632,16 @@ msgid "Last %d day"
msgid_plural "Last %d days"
msgstr[0] ""
-msgid "Last %{days} days"
+msgid "Last 2 weeks"
+msgstr ""
+
+msgid "Last 30 days"
+msgstr ""
+
+msgid "Last 60 days"
+msgstr ""
+
+msgid "Last 90 days"
msgstr ""
msgid "Last Accessed On"
@@ -14211,6 +14719,9 @@ msgstr ""
msgid "Last used on:"
msgstr ""
+msgid "Last week"
+msgstr ""
+
msgid "LastCommit|authored"
msgstr ""
@@ -14226,6 +14737,9 @@ msgstr ""
msgid "Latest pipeline for the most recent commit on this branch"
msgstr ""
+msgid "Launch a ready-to-code development environment for your project."
+msgstr ""
+
msgid "Lead"
msgstr ""
@@ -14599,6 +15113,9 @@ msgstr ""
msgid "List of all merge commits"
msgstr ""
+msgid "List options"
+msgstr ""
+
msgid "List settings"
msgstr ""
@@ -14611,9 +15128,6 @@ msgstr ""
msgid "List your Bitbucket Server repositories"
msgstr ""
-msgid "Lists"
-msgstr ""
-
msgid "Live preview"
msgstr ""
@@ -14860,6 +15374,12 @@ msgstr ""
msgid "Mark as done"
msgstr ""
+msgid "Mark as draft"
+msgstr ""
+
+msgid "Mark as ready"
+msgstr ""
+
msgid "Mark as resolved"
msgstr ""
@@ -14881,6 +15401,24 @@ msgstr ""
msgid "Markdown is supported"
msgstr ""
+msgid "MarkdownEditor|Add a link (%{modifierKey}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add a link (%{modifier_key}K)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifierKey}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add bold text (%{modifier_key}B)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifierKey}I)"
+msgstr ""
+
+msgid "MarkdownEditor|Add italic text (%{modifier_key}I)"
+msgstr ""
+
msgid "Marked For Deletion At - %{deletion_time}"
msgstr ""
@@ -14965,7 +15503,25 @@ msgstr ""
msgid "Max access level"
msgstr ""
-msgid "Max seats used"
+msgid "Max role"
+msgstr ""
+
+msgid "Max size 15 MB"
+msgstr ""
+
+msgid "Maximum Conan package file size in bytes"
+msgstr ""
+
+msgid "Maximum Maven package file size in bytes"
+msgstr ""
+
+msgid "Maximum NPM package file size in bytes"
+msgstr ""
+
+msgid "Maximum NuGet package file size in bytes"
+msgstr ""
+
+msgid "Maximum PyPI package file size in bytes"
msgstr ""
msgid "Maximum Users:"
@@ -15097,6 +15653,18 @@ msgstr ""
msgid "Members with access to %{strong_start}%{group_name}%{strong_end}"
msgstr ""
+msgid "Members|%{time} by %{user}"
+msgstr ""
+
+msgid "Members|Expired"
+msgstr ""
+
+msgid "Members|No expiration set"
+msgstr ""
+
+msgid "Members|in %{time}"
+msgstr ""
+
msgid "Memory Usage"
msgstr ""
@@ -15283,9 +15851,6 @@ msgstr ""
msgid "MergeRequests|Thread will be unresolved"
msgstr ""
-msgid "MergeRequests|Toggle comments for this file"
-msgstr ""
-
msgid "MergeRequests|View file @ %{commitId}"
msgstr ""
@@ -15346,6 +15911,9 @@ msgstr ""
msgid "Merging immediately isn't recommended as it may negatively impact the existing merge train. Read the %{docsLinkStart}documentation%{docsLinkEnd} for more information."
msgstr ""
+msgid "Message"
+msgstr ""
+
msgid "Messages"
msgstr ""
@@ -15729,18 +16297,12 @@ msgid "Milestone"
msgid_plural "Milestones"
msgstr[0] ""
-msgid "Milestone does not support burnup charts"
-msgstr ""
-
msgid "Milestone lists not available with your current license"
msgstr ""
msgid "Milestone lists show all issues from the selected milestone."
msgstr ""
-msgid "Milestone must have a start and due date"
-msgstr ""
-
msgid "MilestoneSidebar|Closed:"
msgstr ""
@@ -16107,6 +16669,9 @@ msgstr ""
msgid "Namespace"
msgstr ""
+msgid "Namespace ID:"
+msgstr ""
+
msgid "Namespace is empty"
msgstr ""
@@ -16191,6 +16756,9 @@ msgstr ""
msgid "NetworkPolicies|Allow all outbound traffic from %{selector} to %{ruleSelector} on %{ports}"
msgstr ""
+msgid "NetworkPolicies|Are you sure you want to delete this policy? This action cannot be undone."
+msgstr ""
+
msgid "NetworkPolicies|Choose whether to enforce this policy."
msgstr ""
@@ -16200,12 +16768,21 @@ msgstr ""
msgid "NetworkPolicies|Define this policy's location, conditions and actions."
msgstr ""
+msgid "NetworkPolicies|Delete policy"
+msgstr ""
+
+msgid "NetworkPolicies|Delete policy: %{policy}"
+msgstr ""
+
msgid "NetworkPolicies|Deny all traffic"
msgstr ""
msgid "NetworkPolicies|Description"
msgstr ""
+msgid "NetworkPolicies|Edit policy"
+msgstr ""
+
msgid "NetworkPolicies|Editor mode"
msgstr ""
@@ -16233,6 +16810,9 @@ msgstr ""
msgid "NetworkPolicies|Name"
msgstr ""
+msgid "NetworkPolicies|Namespace"
+msgstr ""
+
msgid "NetworkPolicies|Network Policy"
msgstr ""
@@ -16284,6 +16864,9 @@ msgstr ""
msgid "NetworkPolicies|Rules"
msgstr ""
+msgid "NetworkPolicies|Save changes"
+msgstr ""
+
msgid "NetworkPolicies|Something went wrong, failed to update policy"
msgstr ""
@@ -16296,6 +16879,9 @@ msgstr ""
msgid "NetworkPolicies|Traffic that does not match any rule will be blocked."
msgstr ""
+msgid "NetworkPolicies|Unable to parse policy"
+msgstr ""
+
msgid "NetworkPolicies|YAML editor"
msgstr ""
@@ -16408,6 +16994,9 @@ msgstr ""
msgid "New Snippet"
msgstr ""
+msgid "New Test Case"
+msgstr ""
+
msgid "New User"
msgstr ""
@@ -16507,6 +17096,9 @@ msgstr ""
msgid "New tag"
msgstr ""
+msgid "New test case"
+msgstr ""
+
msgid "New users set to external"
msgstr ""
@@ -16579,7 +17171,7 @@ msgstr ""
msgid "No changes"
msgstr ""
-msgid "No changes between %{ref_start}%{source_branch}%{ref_end} and %{ref_start}%{target_branch}%{ref_end}"
+msgid "No changes between %{sourceBranch} and %{targetBranch}"
msgstr ""
msgid "No child epics match applied filters"
@@ -16594,6 +17186,9 @@ msgstr ""
msgid "No containers available"
msgstr ""
+msgid "No content to show"
+msgstr ""
+
msgid "No contributions"
msgstr ""
@@ -16669,9 +17264,6 @@ msgstr ""
msgid "No license. All rights reserved"
msgstr ""
-msgid "No licenses found."
-msgstr ""
-
msgid "No matches found"
msgstr ""
@@ -16684,6 +17276,9 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
+msgid "No members found"
+msgstr ""
+
msgid "No merge requests found"
msgstr ""
@@ -16705,6 +17300,9 @@ msgstr ""
msgid "No parent group"
msgstr ""
+msgid "No plan"
+msgstr ""
+
msgid "No pods available"
msgstr ""
@@ -16801,6 +17399,12 @@ msgstr "ç„¡"
msgid "Not Implemented"
msgstr ""
+msgid "Not all browsers support U2F devices. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even when you're using an unsupported browser."
+msgstr ""
+
+msgid "Not all browsers support WebAuthn. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in - even from an unsupported browser."
+msgstr ""
+
msgid "Not all data has been processed yet, the accuracy of the chart for the selected timeframe is limited."
msgstr ""
@@ -16897,6 +17501,9 @@ msgstr ""
msgid "Notification settings saved"
msgstr ""
+msgid "NotificationEvent|Change reviewer merge request"
+msgstr ""
+
msgid "NotificationEvent|Close issue"
msgstr ""
@@ -17059,10 +17666,7 @@ msgstr ""
msgid "On track"
msgstr ""
-msgid "OnDemandScans|Attached branch"
-msgstr ""
-
-msgid "OnDemandScans|Attached branch is where the scan job runs."
+msgid "OnDemandScans|Could not fetch scanner profiles. Please refresh the page, or try again later."
msgstr ""
msgid "OnDemandScans|Could not fetch site profiles. Please refresh the page, or try again later."
@@ -17071,6 +17675,9 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
+msgid "OnDemandScans|Create a new scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Create a new site profile"
msgstr ""
@@ -17083,6 +17690,9 @@ msgstr ""
msgid "OnDemandScans|New on-demand DAST scan"
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 ""
@@ -17092,16 +17702,10 @@ msgstr ""
msgid "OnDemandScans|On-demand scans run outside the DevOps cycle and find vulnerabilities in your projects. %{learnMoreLinkStart}Learn more%{learnMoreLinkEnd}"
msgstr ""
-msgid "OnDemandScans|Only a passive scan can be performed on demand."
-msgstr ""
-
-msgid "OnDemandScans|Passive"
-msgstr ""
-
msgid "OnDemandScans|Run scan"
msgstr ""
-msgid "OnDemandScans|Scan mode"
+msgid "OnDemandScans|Scanner profile"
msgstr ""
msgid "OnDemandScans|Scanner settings"
@@ -17113,9 +17717,15 @@ msgstr ""
msgid "OnDemandScans|Select one of the existing profiles"
msgstr ""
+msgid "OnDemandScans|Site profile"
+msgstr ""
+
msgid "OnDemandScans|Site profiles"
msgstr ""
+msgid "OnDemandScans|Use existing scanner profile"
+msgstr ""
+
msgid "OnDemandScans|Use existing site profile"
msgstr ""
@@ -17213,9 +17823,6 @@ msgstr ""
msgid "Open Selection"
msgstr ""
-msgid "Open Web IDE"
-msgstr ""
-
msgid "Open comment type dropdown"
msgstr ""
@@ -17321,6 +17928,9 @@ msgstr ""
msgid "Origin"
msgstr ""
+msgid "Orphaned member"
+msgstr ""
+
msgid "Other Labels"
msgstr ""
@@ -17336,6 +17946,9 @@ msgstr ""
msgid "Other visibility settings have been disabled by the administrator."
msgstr ""
+msgid "Our documentation includes an example DevOps Score report."
+msgstr ""
+
msgid "Out-of-compliance with this project's policies and should be removed"
msgstr ""
@@ -17360,6 +17973,9 @@ msgstr ""
msgid "Overwrite diverged branches"
msgstr ""
+msgid "Owned by %{image_tag}"
+msgstr ""
+
msgid "Owned by anyone"
msgstr ""
@@ -17381,6 +17997,9 @@ msgstr ""
msgid "Package deleted successfully"
msgstr ""
+msgid "Package file size limits"
+msgstr ""
+
msgid "Package recipe already exists"
msgstr ""
@@ -17396,9 +18015,6 @@ msgstr ""
msgid "Package type must be PyPi"
msgstr ""
-msgid "Package was removed"
-msgstr ""
-
msgid "PackageRegistry|%{name} version %{version} was created %{datetime}"
msgstr ""
@@ -17540,12 +18156,18 @@ msgstr ""
msgid "PackageRegistry|NuGet Command"
msgstr ""
+msgid "PackageRegistry|Package Registry"
+msgstr ""
+
msgid "PackageRegistry|Pip Command"
msgstr ""
msgid "PackageRegistry|Pipeline %{link} triggered %{datetime} by %{author}"
msgstr ""
+msgid "PackageRegistry|Publish and share packages for a variety of common package managers. %{docLinkStart}More information%{docLinkEnd}"
+msgstr ""
+
msgid "PackageRegistry|Published to the %{project} Package Registry %{datetime}"
msgstr ""
@@ -17645,6 +18267,9 @@ msgstr ""
msgid "Page not found"
msgstr ""
+msgid "Page settings"
+msgstr ""
+
msgid "Page was successfully deleted"
msgstr ""
@@ -17786,7 +18411,7 @@ msgstr ""
msgid "Paste issue link"
msgstr ""
-msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Don't use your private SSH key."
+msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Do not paste your private SSH key, as that can compromise your identity."
msgstr ""
msgid "Patch to apply"
@@ -17813,6 +18438,9 @@ msgstr ""
msgid "Pending"
msgstr ""
+msgid "Pending comments"
+msgstr ""
+
msgid "People without permission will never get a notification and won't be able to comment."
msgstr ""
@@ -18011,6 +18639,9 @@ msgstr ""
msgid "Pipelines|Build with confidence"
msgstr ""
+msgid "Pipelines|By revoking a trigger you will break any processes making use of it. Are you sure?"
+msgstr ""
+
msgid "Pipelines|CI Lint"
msgstr ""
@@ -18023,6 +18654,15 @@ msgstr ""
msgid "Pipelines|Continuous Integration can help catch bugs by running your tests automatically, while Continuous Deployment can help you deliver code to your product environment."
msgstr ""
+msgid "Pipelines|Copy trigger token"
+msgstr ""
+
+msgid "Pipelines|Description"
+msgstr ""
+
+msgid "Pipelines|Edit"
+msgstr ""
+
msgid "Pipelines|Get started with Pipelines"
msgstr ""
@@ -18038,15 +18678,27 @@ msgstr ""
msgid "Pipelines|It is recommended the code is reviewed thoroughly before running this pipeline with the parent project's CI resource."
msgstr ""
+msgid "Pipelines|Last Used"
+msgstr ""
+
msgid "Pipelines|Loading Pipelines"
msgstr ""
msgid "Pipelines|More Information"
msgstr ""
+msgid "Pipelines|No triggers have been created yet. Add one using the form above."
+msgstr ""
+
+msgid "Pipelines|Owner"
+msgstr ""
+
msgid "Pipelines|Project cache successfully reset."
msgstr ""
+msgid "Pipelines|Revoke"
+msgstr ""
+
msgid "Pipelines|Run Pipeline"
msgstr ""
@@ -18071,6 +18723,15 @@ msgstr ""
msgid "Pipelines|This project is not currently set up to run pipelines."
msgstr ""
+msgid "Pipelines|Token"
+msgstr ""
+
+msgid "Pipelines|Trigger user has insufficient permissions to project"
+msgstr ""
+
+msgid "Pipelines|invalid"
+msgstr ""
+
msgid "Pipelines|parent"
msgstr ""
@@ -18329,10 +18990,10 @@ msgstr ""
msgid "Please provide attributes to update"
msgstr ""
-msgid "Please refer to %{docs_url}"
+msgid "Please reach out if you have any questions and we'll be happy to assist."
msgstr ""
-msgid "Please retype the email address."
+msgid "Please refer to %{docs_url}"
msgstr ""
msgid "Please select"
@@ -18362,6 +19023,9 @@ msgstr ""
msgid "Please set a new password before proceeding."
msgstr ""
+msgid "Please share your feedback about %{featureName} %{linkStart}in this issue%{linkEnd} to help us improve the experience."
+msgstr ""
+
msgid "Please solve the reCAPTCHA"
msgstr ""
@@ -18665,6 +19329,9 @@ msgstr ""
msgid "Profiles| You are going to change the username %{currentUsernameBold} to %{newUsernameBold}. Profile and projects will be redirected to the %{newUsername} namespace but this redirect will expire once the %{currentUsername} namespace is registered by another user or group. Please update your Git repository remotes as soon as possible."
msgstr ""
+msgid "Profiles|%{provider} Active"
+msgstr ""
+
msgid "Profiles|@username"
msgstr ""
@@ -18716,7 +19383,7 @@ msgstr ""
msgid "Profiles|Commit email"
msgstr ""
-msgid "Profiles|Connect"
+msgid "Profiles|Connect %{provider}"
msgstr ""
msgid "Profiles|Connected Accounts"
@@ -18740,6 +19407,9 @@ msgstr ""
msgid "Profiles|Disconnect"
msgstr ""
+msgid "Profiles|Disconnect %{provider}"
+msgstr ""
+
msgid "Profiles|Do not show on profile"
msgstr ""
@@ -18764,7 +19434,7 @@ msgstr ""
msgid "Profiles|Full name"
msgstr ""
-msgid "Profiles|Give your individual key a title. This will be publically visible."
+msgid "Profiles|Give your individual key a title."
msgstr ""
msgid "Profiles|Include private contributions on my profile"
@@ -18854,7 +19524,7 @@ msgstr ""
msgid "Profiles|The maximum file size allowed is 200KB."
msgstr ""
-msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it?"
+msgid "Profiles|This doesn't look like a public SSH key, are you sure you want to add it? It will be publicly visible."
msgstr ""
msgid "Profiles|This email will be displayed on your public profile"
@@ -18929,6 +19599,9 @@ msgstr ""
msgid "Profiles|You don't have access to delete this user."
msgstr ""
+msgid "Profiles|You must transfer ownership or delete groups you are an owner of before you can delete your account"
+msgstr ""
+
msgid "Profiles|You must transfer ownership or delete these groups before you can delete your account."
msgstr ""
@@ -19517,6 +20190,9 @@ msgstr ""
msgid "ProjectTemplates|GitLab Cluster Management"
msgstr ""
+msgid "ProjectTemplates|Gitpod/Spring Petclinic"
+msgstr ""
+
msgid "ProjectTemplates|Go Micro"
msgstr ""
@@ -20126,6 +20802,9 @@ msgstr ""
msgid "Publish to status page"
msgstr ""
+msgid "Published"
+msgstr ""
+
msgid "Published on status page"
msgstr ""
@@ -20243,9 +20922,15 @@ msgstr ""
msgid "Quick range"
msgstr ""
+msgid "Quickly and easily edit multiple files in your project."
+msgstr ""
+
msgid "README"
msgstr ""
+msgid "Rails"
+msgstr ""
+
msgid "Rake Tasks Help"
msgstr ""
@@ -20364,10 +21049,13 @@ msgstr ""
msgid "Register Two-Factor Authenticator"
msgstr ""
-msgid "Register U2F device"
+msgid "Register Universal Two-Factor (U2F) Device"
msgstr ""
-msgid "Register Universal Two-Factor (U2F) Device"
+msgid "Register WebAuthn Device"
+msgstr ""
+
+msgid "Register device"
msgstr ""
msgid "Register for GitLab"
@@ -20379,9 +21067,6 @@ msgstr ""
msgid "Register with two-factor app"
msgstr ""
-msgid "Registration"
-msgstr ""
-
msgid "Registration|Checkout"
msgstr ""
@@ -20497,9 +21182,6 @@ msgstr ""
msgid "Release|Something went wrong while saving the release details"
msgstr ""
-msgid "Remediated: needs review"
-msgstr ""
-
msgid "Remediations"
msgstr ""
@@ -20605,6 +21287,9 @@ msgstr ""
msgid "Remove priority"
msgstr ""
+msgid "Remove report"
+msgstr ""
+
msgid "Remove secondary node"
msgstr ""
@@ -20617,6 +21302,12 @@ msgstr ""
msgid "Remove time estimate"
msgstr ""
+msgid "Remove user & report"
+msgstr ""
+
+msgid "Remove user from group"
+msgstr ""
+
msgid "Removed"
msgstr ""
@@ -20698,9 +21389,6 @@ msgstr ""
msgid "Removes time estimate."
msgstr ""
-msgid "Removing license…"
-msgstr ""
-
msgid "Removing this group also removes all child projects, including archived projects, and their resources."
msgstr ""
@@ -20785,6 +21473,9 @@ msgstr ""
msgid "Reported %{timeAgo} by %{reportedBy}"
msgstr ""
+msgid "Reported by %{reporter}"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -20870,6 +21561,27 @@ msgstr ""
msgid "Repositories"
msgstr ""
+msgid "Repositories Analytics"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download Historic Test Coverage Data"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download historic test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Download test coverage data (.csv)"
+msgstr ""
+
+msgid "RepositoriesAnalytics|Historic Test Coverage Data is available in raw format (.csv) for further analysis."
+msgstr ""
+
+msgid "RepositoriesAnalytics|Test Code Coverage"
+msgstr ""
+
+msgid "RepositoriesAnalytics|There was an error fetching the projects."
+msgstr ""
+
msgid "Repository"
msgstr ""
@@ -20948,9 +21660,15 @@ msgstr ""
msgid "Request parameter %{param} is missing."
msgstr ""
+msgid "Request review from"
+msgstr ""
+
msgid "Request to link SAML account must be authorized"
msgstr ""
+msgid "Requested"
+msgstr ""
+
msgid "Requested %{time_ago}"
msgstr ""
@@ -20969,6 +21687,9 @@ msgstr ""
msgid "Requests to these domain(s)/address(es) on the local network will be allowed when local requests from hooks and services are not allowed. IP ranges such as 1:0:0:0:0:0:0:0/124 or 127.0.0.0/28 are supported. Domain wildcards are not supported currently. Use comma, semicolon, or newline to separate multiple entries. The allowlist can hold a maximum of 1000 entries. Domains should use IDNA encoding. Ex: example.com, 192.168.1.1, 127.0.0.0/28, xn--itlab-j1a.com."
msgstr ""
+msgid "Require admin approval for new sign-ups"
+msgstr ""
+
msgid "Require all users in this group to setup Two-factor authentication"
msgstr ""
@@ -21094,9 +21815,6 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
-msgid "Resolved by %{resolvedByName}"
-msgstr ""
-
msgid "Resolves IP addresses once and uses them to submit requests"
msgstr ""
@@ -21215,6 +21933,13 @@ msgstr ""
msgid "ReviewApp|Enable Review App"
msgstr ""
+msgid "Reviewer"
+msgid_plural "%d Reviewers"
+msgstr[0] ""
+
+msgid "Reviewer(s)"
+msgstr ""
+
msgid "Reviewing"
msgstr ""
@@ -21254,6 +21979,9 @@ msgstr ""
msgid "Rook"
msgstr ""
+msgid "Ruby"
+msgstr ""
+
msgid "Rule name is already taken."
msgstr ""
@@ -21332,6 +22060,63 @@ msgstr ""
msgid "Runners page."
msgstr ""
+msgid "Runners|Active"
+msgstr ""
+
+msgid "Runners|Architecture"
+msgstr ""
+
+msgid "Runners|Can run untagged jobs"
+msgstr ""
+
+msgid "Runners|Description"
+msgstr ""
+
+msgid "Runners|Group"
+msgstr ""
+
+msgid "Runners|IP Address"
+msgstr ""
+
+msgid "Runners|Last contact"
+msgstr ""
+
+msgid "Runners|Locked to this project"
+msgstr ""
+
+msgid "Runners|Maximum job timeout"
+msgstr ""
+
+msgid "Runners|Name"
+msgstr ""
+
+msgid "Runners|Platform"
+msgstr ""
+
+msgid "Runners|Property Name"
+msgstr ""
+
+msgid "Runners|Protected"
+msgstr ""
+
+msgid "Runners|Revision"
+msgstr ""
+
+msgid "Runners|Shared"
+msgstr ""
+
+msgid "Runners|Specific"
+msgstr ""
+
+msgid "Runners|Tags"
+msgstr ""
+
+msgid "Runners|Value"
+msgstr ""
+
+msgid "Runners|Version"
+msgstr ""
+
msgid "Runners|You have used %{quotaUsed} out of %{quotaLimit} of your shared Runners pipeline minutes."
msgstr ""
@@ -21344,6 +22129,9 @@ msgstr ""
msgid "Runs a number of housekeeping tasks within the current repository, such as compressing file revisions and removing unreachable objects."
msgstr ""
+msgid "SAML"
+msgstr ""
+
msgid "SAML SSO"
msgstr ""
@@ -21395,6 +22183,9 @@ msgstr ""
msgid "Save"
msgstr ""
+msgid "Save %{name} size limits"
+msgstr ""
+
msgid "Save Changes"
msgstr ""
@@ -21425,9 +22216,6 @@ msgstr ""
msgid "Save space and find tags in the Container Registry more easily. Enable the cleanup policy to remove stale tags and keep only the ones you need."
msgstr ""
-msgid "Save template"
-msgstr ""
-
msgid "Save variables"
msgstr ""
@@ -21470,9 +22258,6 @@ msgstr ""
msgid "Scope"
msgstr ""
-msgid "Scope not supported with disabled 'users_search' feature!"
-msgstr ""
-
msgid "Scoped issue boards"
msgstr ""
@@ -21599,9 +22384,6 @@ msgstr ""
msgid "Search requirements"
msgstr ""
-msgid "Search results…"
-msgstr ""
-
msgid "Search users"
msgstr ""
@@ -21671,6 +22453,10 @@ msgid "SearchResults|commit"
msgid_plural "SearchResults|commits"
msgstr[0] ""
+msgid "SearchResults|epic"
+msgid_plural "SearchResults|epics"
+msgstr[0] ""
+
msgid "SearchResults|issue"
msgid_plural "SearchResults|issues"
msgstr[0] ""
@@ -21708,10 +22494,10 @@ msgstr ""
msgid "Seat Link is disabled, and cannot be configured through this form."
msgstr ""
-msgid "Seats currently in use"
+msgid "Seats usage data as of %{last_enqueue_time}"
msgstr ""
-msgid "Seats in license"
+msgid "Seats usage data is updated every day at 12:00pm UTC"
msgstr ""
msgid "Secondary"
@@ -21765,6 +22551,9 @@ msgstr ""
msgid "SecurityConfiguration|Available for on-demand DAST"
msgstr ""
+msgid "SecurityConfiguration|By default, all analyzers are applied in order to cover all languages across your project, and only run if the language is detected in the Merge Request."
+msgstr ""
+
msgid "SecurityConfiguration|Configure"
msgstr ""
@@ -21795,16 +22584,19 @@ msgstr ""
msgid "SecurityConfiguration|Manage"
msgstr ""
+msgid "SecurityConfiguration|More information"
+msgstr ""
+
msgid "SecurityConfiguration|Not enabled"
msgstr ""
-msgid "SecurityConfiguration|SAST Configuration"
+msgid "SecurityConfiguration|SAST Analyzers"
msgstr ""
-msgid "SecurityConfiguration|Security Control"
+msgid "SecurityConfiguration|SAST Configuration"
msgstr ""
-msgid "SecurityConfiguration|See documentation"
+msgid "SecurityConfiguration|Security Control"
msgstr ""
msgid "SecurityConfiguration|Status"
@@ -21816,6 +22608,9 @@ msgstr ""
msgid "SecurityConfiguration|Using custom settings. You won't receive automatic updates on this variable. %{anchorStart}Restore to default%{anchorEnd}"
msgstr ""
+msgid "SecurityConfiguration|View history"
+msgstr ""
+
msgid "SecurityConfiguration|You can quickly enable all security scanning tools by enabling %{linkStart}Auto DevOps%{linkEnd}."
msgstr ""
@@ -21894,9 +22689,6 @@ msgstr ""
msgid "SecurityReports|Learn more about setting up your dashboard"
msgstr ""
-msgid "SecurityReports|Load more vulnerabilities"
-msgstr ""
-
msgid "SecurityReports|Monitor vulnerabilities in your code"
msgstr ""
@@ -22176,7 +22968,7 @@ msgstr ""
msgid "Select status"
msgstr ""
-msgid "Select strategy activation method"
+msgid "Select strategy activation method."
msgstr ""
msgid "Select subscription"
@@ -22191,7 +22983,7 @@ msgstr ""
msgid "Select the custom project template source group."
msgstr ""
-msgid "Select timeframe"
+msgid "Select the environment scope for this feature flag."
msgstr ""
msgid "Select timezone"
@@ -22440,6 +23232,9 @@ msgstr ""
msgid "Set iteration"
msgstr ""
+msgid "Set limit to 0 to allow any file size."
+msgstr ""
+
msgid "Set max session time for web terminal."
msgstr ""
@@ -22518,10 +23313,13 @@ msgstr ""
msgid "Set up a %{type} Runner manually"
msgstr ""
+msgid "Set up a hardware device as a second factor to sign in."
+msgstr ""
+
msgid "Set up assertions/attributes/claims (email, first_name, last_name) and NameID according to %{docsLinkStart}the documentation %{icon}%{docsLinkEnd}"
msgstr ""
-msgid "Set up new U2F device"
+msgid "Set up new device"
msgstr ""
msgid "Set up new password"
@@ -22590,6 +23388,9 @@ msgstr ""
msgid "Sets weight to %{weight}."
msgstr ""
+msgid "Setting this to 0 means using the system default timeout value."
+msgstr ""
+
msgid "Settings"
msgstr ""
@@ -22605,6 +23406,15 @@ msgstr ""
msgid "Severity"
msgstr ""
+msgid "SeverityWidget|Severity"
+msgstr ""
+
+msgid "SeverityWidget|Severity: %{severity}"
+msgstr ""
+
+msgid "SeverityWidget|There was an error while updating severity."
+msgstr ""
+
msgid "Shards (%{shards})"
msgstr ""
@@ -22650,6 +23460,9 @@ msgstr ""
msgid "Show all requirements."
msgstr ""
+msgid "Show all test cases."
+msgstr ""
+
msgid "Show archived projects"
msgstr ""
@@ -22662,6 +23475,9 @@ msgstr ""
msgid "Show comments"
msgstr ""
+msgid "Show comments on this file"
+msgstr ""
+
msgid "Show comments only"
msgstr ""
@@ -22707,6 +23523,12 @@ msgstr ""
msgid "Show parent subgroups"
msgstr ""
+msgid "Show the Closed list"
+msgstr ""
+
+msgid "Show the Open list"
+msgstr ""
+
msgid "Show whitespace changes"
msgstr ""
@@ -22748,9 +23570,6 @@ msgstr ""
msgid "Sidebar|Assign health status"
msgstr ""
-msgid "Sidebar|Change weight"
-msgstr ""
-
msgid "Sidebar|Health status"
msgstr ""
@@ -22934,6 +23753,9 @@ msgstr ""
msgid "Snippets|Add another file %{num}/%{total}"
msgstr ""
+msgid "Snippets|Authored %{time_ago} by %{author}"
+msgstr ""
+
msgid "Snippets|Delete file"
msgstr ""
@@ -22961,6 +23783,9 @@ msgstr ""
msgid "Solution"
msgstr ""
+msgid "Some changes are not shown"
+msgstr ""
+
msgid "Some child epics may be hidden due to applied filters"
msgstr ""
@@ -23327,6 +24152,12 @@ msgstr ""
msgid "Source (branch or tag)"
msgstr ""
+msgid "Source Branch"
+msgstr ""
+
+msgid "Source branch: %{source_branch_open}%{source_branch}%{source_branch_close}"
+msgstr ""
+
msgid "Source code"
msgstr ""
@@ -23492,9 +24323,6 @@ msgstr ""
msgid "Start and due date"
msgstr ""
-msgid "Start by choosing a group to see how your team is spending time. You can then drill down to the project level."
-msgstr ""
-
msgid "Start by choosing a group to start exploring the merge requests in that group. You can then proceed to filter by projects, labels, milestones and authors."
msgstr ""
@@ -23576,18 +24404,27 @@ msgstr ""
msgid "StaticSiteEditor|3. Assign a person to review and accept the merge request."
msgstr ""
+msgid "StaticSiteEditor|A link to view the merge request will appear once ready."
+msgstr ""
+
msgid "StaticSiteEditor|An error occurred while submitting your changes."
msgstr ""
msgid "StaticSiteEditor|Branch could not be created."
msgstr ""
+msgid "StaticSiteEditor|Copy update"
+msgstr ""
+
msgid "StaticSiteEditor|Could not commit the content changes."
msgstr ""
msgid "StaticSiteEditor|Could not create merge request."
msgstr ""
+msgid "StaticSiteEditor|Creating your merge request"
+msgstr ""
+
msgid "StaticSiteEditor|Incompatible file content"
msgstr ""
@@ -23609,6 +24446,9 @@ msgstr ""
msgid "StaticSiteEditor|View documentation"
msgstr ""
+msgid "StaticSiteEditor|You can set an assignee to get your changes reviewed and deployed once your merge request is created."
+msgstr ""
+
msgid "StaticSiteEditor|Your merge request has been created"
msgstr ""
@@ -23738,15 +24578,15 @@ msgstr ""
msgid "Submit %{humanized_resource_name}"
msgstr ""
-msgid "Submit Changes"
-msgstr ""
-
msgid "Submit a review"
msgstr ""
msgid "Submit as spam"
msgstr ""
+msgid "Submit changes"
+msgstr ""
+
msgid "Submit feedback"
msgstr ""
@@ -23900,6 +24740,9 @@ msgstr ""
msgid "Successfully deleted U2F device."
msgstr ""
+msgid "Successfully deleted WebAuthn device."
+msgstr ""
+
msgid "Successfully removed email."
msgstr ""
@@ -24218,9 +25061,6 @@ msgstr ""
msgid "Template to append to all Service Desk issues"
msgstr ""
-msgid "Template was successfully saved."
-msgstr ""
-
msgid "Templates"
msgstr ""
@@ -24296,10 +25136,28 @@ msgid "Test coverage: %d hit"
msgid_plural "Test coverage: %d hits"
msgstr[0] ""
-msgid "Test failed."
+msgid "Test settings"
+msgstr ""
+
+msgid "TestCases|New Test Case"
+msgstr ""
+
+msgid "TestCases|New test case"
+msgstr ""
+
+msgid "TestCases|Search test cases"
+msgstr ""
+
+msgid "TestCases|Something went wrong while creating a test case."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching count of test cases."
+msgstr ""
+
+msgid "TestCases|Something went wrong while fetching test cases list."
msgstr ""
-msgid "Test settings and save changes"
+msgid "TestCases|Submit test case"
msgstr ""
msgid "TestHooks|Ensure one of your projects has merge requests."
@@ -24365,6 +25223,9 @@ msgstr ""
msgid "Thank you for signing up for your free trial! You will get additional instructions in your inbox shortly."
msgstr ""
+msgid "Thank you for your business."
+msgstr ""
+
msgid "Thank you for your feedback!"
msgstr ""
@@ -24423,9 +25284,6 @@ msgstr ""
msgid "The URL to use for connecting to Elasticsearch. Use a comma-separated list to support clustering (e.g., \"http://localhost:9200, http://localhost:9201\")."
msgstr ""
-msgid "The Web IDE offers advanced syntax highlighting capabilities and more."
-msgstr ""
-
msgid "The X509 Certificate to use when mutual TLS is required to communicate with the external authorization service. If left blank, the server certificate is still validated when accessing over HTTPS."
msgstr ""
@@ -24535,6 +25393,9 @@ msgstr ""
msgid "The form contains the following error:"
msgstr ""
+msgid "The form contains the following warning:"
+msgstr ""
+
msgid "The global settings require you to enable Two-Factor Authentication for your account."
msgstr ""
@@ -24649,9 +25510,6 @@ msgstr ""
msgid "The private key to use when a client certificate is provided. This value is encrypted at rest."
msgstr ""
-msgid "The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The project can be accessed by any logged in user."
msgstr ""
@@ -24688,7 +25546,7 @@ msgstr ""
msgid "The remote repository is being updated..."
msgstr ""
-msgid "The repository can be commited to, and issues, comments and other entities can be created."
+msgid "The repository can be committed to, and issues, comments and other entities can be created."
msgstr ""
msgid "The repository for this project does not exist."
@@ -24742,9 +25600,6 @@ msgstr ""
msgid "The time taken by each data entry gathered by that stage."
msgstr ""
-msgid "The total stage shows the time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
-msgstr ""
-
msgid "The update action will time out after %{number_of_minutes} minutes. For big repositories, use a clone/push combination."
msgstr ""
@@ -24808,6 +25663,9 @@ msgstr ""
msgid "There are no archived requirements"
msgstr ""
+msgid "There are no archived test cases"
+msgstr ""
+
msgid "There are no changes"
msgstr ""
@@ -24847,6 +25705,9 @@ msgstr ""
msgid "There are no open requirements"
msgstr ""
+msgid "There are no open test cases"
+msgstr ""
+
msgid "There are no packages yet"
msgstr ""
@@ -24859,6 +25720,9 @@ msgstr ""
msgid "There is a limit of %{ci_project_subscriptions_limit} subscriptions from or to a project."
msgstr ""
+msgid "There is already a To-Do for this design."
+msgstr ""
+
msgid "There is already a repository with that name on disk"
msgstr ""
@@ -24877,6 +25741,9 @@ msgstr ""
msgid "There was a problem communicating with your device."
msgstr ""
+msgid "There was a problem fetching branches."
+msgstr ""
+
msgid "There was a problem fetching groups."
msgstr ""
@@ -25105,9 +25972,15 @@ msgstr ""
msgid "This action can lead to data loss. To prevent accidental actions we ask you to confirm your intention."
msgstr ""
+msgid "This action cannot be undone, and will permanently delete the %{key} SSH key"
+msgstr ""
+
msgid "This action cannot be undone. You will lose the project's repository and all content: issues, merge requests, etc."
msgstr ""
+msgid "This action has been performed too many times. Try again later."
+msgstr ""
+
msgid "This action will %{strongOpen}permanently delete%{strongClose} %{codeOpen}%{project}%{codeClose} %{strongOpen}immediately%{strongClose}, including its repositories and all content: issues, merge requests, etc."
msgstr ""
@@ -25135,9 +26008,6 @@ msgstr ""
msgid "This board's scope is reduced"
msgstr ""
-msgid "This branch has changed since you started editing. Would you like to create a new branch?"
-msgstr ""
-
msgid "This chart could not be displayed"
msgstr ""
@@ -25264,15 +26134,9 @@ msgstr ""
msgid "This is a security log of important events involving your account."
msgstr ""
-msgid "This is the author's first Merge Request to this project."
-msgstr ""
-
msgid "This is the highest peak of users on your installation since the license started."
msgstr ""
-msgid "This is the maximum number of users that have existed at the same time since the license started. This is the minimum number of seats you will need to buy when you renew your license."
-msgstr ""
-
msgid "This is the number of currently active users on your installation, and this is the minimum number you need to purchase when you renew your license."
msgstr ""
@@ -25504,6 +26368,15 @@ msgstr ""
msgid "This user has no identities"
msgstr ""
+msgid "This user has previously committed to the %{name} project."
+msgstr ""
+
+msgid "This user has the %{access} role in the %{name} project."
+msgstr ""
+
+msgid "This user is the author of this %{noteable}."
+msgstr ""
+
msgid "This user will be the author of all events in the activity feed that are the result of an update, like new branches being created or new commits being pushed to existing branches."
msgstr ""
@@ -25534,6 +26407,9 @@ msgstr ""
msgid "Threat Monitoring"
msgstr ""
+msgid "ThreatMonitoring|All Environments"
+msgstr ""
+
msgid "ThreatMonitoring|Anomalous Requests"
msgstr ""
@@ -25561,9 +26437,6 @@ msgstr ""
msgid "ThreatMonitoring|Operations Per Second"
msgstr ""
-msgid "ThreatMonitoring|Overview"
-msgstr ""
-
msgid "ThreatMonitoring|Packet Activity"
msgstr ""
@@ -25582,6 +26455,9 @@ msgstr ""
msgid "ThreatMonitoring|Something went wrong, unable to fetch statistics"
msgstr ""
+msgid "ThreatMonitoring|Statistics"
+msgstr ""
+
msgid "ThreatMonitoring|The firewall is not installed or has been disabled. To view this data, ensure the web application firewall is installed and enabled for your cluster."
msgstr ""
@@ -25971,6 +26847,9 @@ msgstr ""
msgid "To update Snippets with multiple files, you must use the `files` parameter"
msgstr ""
+msgid "To use Gitpod you must first enable the feature in the integrations section of your %{user_prefs}."
+msgstr ""
+
msgid "To view all %{scannedResourcesCount} scanned URLs, please download the CSV file"
msgstr ""
@@ -26004,9 +26883,6 @@ msgstr ""
msgid "Toggle Sidebar"
msgstr ""
-msgid "Toggle all threads"
-msgstr ""
-
msgid "Toggle backtrace"
msgstr ""
@@ -26031,9 +26907,6 @@ msgstr ""
msgid "Toggle navigation"
msgstr ""
-msgid "Toggle project"
-msgstr ""
-
msgid "Toggle sidebar"
msgstr ""
@@ -26073,6 +26946,9 @@ msgstr ""
msgid "Too many projects enabled. You will need to manage them via the console or the API."
msgstr ""
+msgid "Too much data"
+msgstr ""
+
msgid "Topics (optional)"
msgstr ""
@@ -26091,6 +26967,9 @@ msgstr ""
msgid "Total cores (CPUs)"
msgstr ""
+msgid "Total days to completion"
+msgstr ""
+
msgid "Total issues"
msgstr ""
@@ -26187,6 +27066,9 @@ msgstr ""
msgid "Trending"
msgstr ""
+msgid "Trials|Create a new group to start your GitLab Gold trial."
+msgstr ""
+
msgid "Trials|Go back to GitLab"
msgstr ""
@@ -26196,6 +27078,15 @@ msgstr ""
msgid "Trials|You can always resume this process by selecting your avatar and choosing 'Start a Gold trial'"
msgstr ""
+msgid "Trials|You can apply your trial to a new group or an existing group."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group or your personal account."
+msgstr ""
+
+msgid "Trials|You can apply your trial to a new group, an existing group, or your personal account."
+msgstr ""
+
msgid "Trials|You won't get a free trial right now but you can always resume this process by clicking on your avatar and choosing 'Start a free trial'"
msgstr ""
@@ -26265,6 +27156,9 @@ msgstr ""
msgid "Try using a different search term to find the file you are looking for."
msgstr ""
+msgid "Trying to communicate with your device. Plug it in (if needed) and press the button on the device now."
+msgstr ""
+
msgid "Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now."
msgstr ""
@@ -26352,6 +27246,12 @@ msgstr ""
msgid "URL or request ID"
msgstr ""
+msgid "USER %{user} WILL BE REMOVED! Are you sure?"
+msgstr ""
+
+msgid "USER WILL BE BLOCKED! Are you sure?"
+msgstr ""
+
msgid "UTC"
msgstr ""
@@ -26409,9 +27309,6 @@ msgstr ""
msgid "Unable to load the merge request widget. Try reloading the page."
msgstr ""
-msgid "Unable to resolve"
-msgstr ""
-
msgid "Unable to save iteration. Please try again"
msgstr ""
@@ -26460,6 +27357,9 @@ msgstr ""
msgid "Undo ignore"
msgstr ""
+msgid "Unexpected error"
+msgstr ""
+
msgid "Unfortunately, your email message to GitLab could not be processed."
msgstr ""
@@ -26493,6 +27393,9 @@ msgstr ""
msgid "Unknown response text"
msgstr ""
+msgid "Unless otherwise agreed to in writing with GitLab, by clicking \"Upload License\" you agree that your use of GitLab Software is subject to the %{eula_link_start}Terms of Service%{eula_link_end}."
+msgstr ""
+
msgid "Unlimited"
msgstr ""
@@ -26859,9 +27762,6 @@ msgstr ""
msgid "Use Service Desk to connect with your users (e.g. to offer customer support) through email right inside GitLab"
msgstr ""
-msgid "Use a hardware device to add the second factor of authentication."
-msgstr ""
-
msgid "Use an one time password authenticator on your mobile device or computer to enable two-factor authentication (2FA)."
msgstr ""
@@ -27135,13 +28035,13 @@ msgstr ""
msgid "Users"
msgstr ""
-msgid "Users in License:"
+msgid "Users in License"
msgstr ""
-msgid "Users or groups set as approvers in the project's or merge request's settings."
+msgid "Users in License:"
msgstr ""
-msgid "Users outside of license"
+msgid "Users or groups set as approvers in the project's or merge request's settings."
msgstr ""
msgid "Users over License:"
@@ -27159,9 +28059,6 @@ msgstr ""
msgid "Users with a Guest role or those who don't belong to a Project or Group will not use a seat from your license."
msgstr ""
-msgid "Users with a Guest role or those who don't belong to any projects or groups don't count towards seats in use."
-msgstr ""
-
msgid "UsersSelect|%{name} + %{length} more"
msgstr ""
@@ -27201,9 +28098,6 @@ msgstr ""
msgid "Validations failed."
msgstr ""
-msgid "Validity"
-msgstr ""
-
msgid "Value"
msgstr ""
@@ -27222,6 +28116,9 @@ msgstr ""
msgid "Value Stream Name"
msgstr ""
+msgid "ValueStreamAnalyticsStage|We don't have enough data to show this stage."
+msgstr ""
+
msgid "ValueStreamAnalytics|%{days}d"
msgstr ""
@@ -27476,6 +28373,9 @@ msgstr ""
msgid "VisualReviewApp|Steps 1 and 2 (and sometimes 3) are performed once by the developer before requesting feedback. Steps 3 (if necessary), 4 is performed by the reviewer each time they perform a review."
msgstr ""
+msgid "Visualization"
+msgstr ""
+
msgid "Vulnerabilities"
msgstr ""
@@ -27503,34 +28403,31 @@ msgstr ""
msgid "VulnerabilityChart|Severity"
msgstr ""
-msgid "VulnerabilityManagement|A true-positive and will fix"
-msgstr ""
-
-msgid "VulnerabilityManagement|Change status"
+msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Confirm"
+msgid "VulnerabilityManagement|%{statusStart}Detected%{statusEnd} %{timeago} in pipeline %{pipelineLink}"
msgstr ""
-msgid "VulnerabilityManagement|Confirmed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|%{statusStart}Dismissed%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
+msgid "VulnerabilityManagement|%{statusStart}Resolved%{statusEnd} %{timeago} by %{user}"
msgstr ""
-msgid "VulnerabilityManagement|Detected %{timeago} in pipeline %{pipelineLink}"
+msgid "VulnerabilityManagement|A true-positive and will fix"
msgstr ""
-msgid "VulnerabilityManagement|Dismiss"
+msgid "VulnerabilityManagement|Change status"
msgstr ""
-msgid "VulnerabilityManagement|Dismissed %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Could not process %{issueReference}: %{errorMessage}."
msgstr ""
-msgid "VulnerabilityManagement|Resolved"
+msgid "VulnerabilityManagement|Detected"
msgstr ""
-msgid "VulnerabilityManagement|Resolved %{timeago} by %{user}"
+msgid "VulnerabilityManagement|Needs triage"
msgstr ""
msgid "VulnerabilityManagement|Something went wrong while trying to delete the comment. Please try again later."
@@ -27581,6 +28478,9 @@ msgstr ""
msgid "Vulnerability|%{scannerName} (version %{scannerVersion})"
msgstr ""
+msgid "Vulnerability|Activity"
+msgstr ""
+
msgid "Vulnerability|Class"
msgstr ""
@@ -27593,6 +28493,9 @@ msgstr ""
msgid "Vulnerability|Description"
msgstr ""
+msgid "Vulnerability|Detected"
+msgstr ""
+
msgid "Vulnerability|Evidence"
msgstr ""
@@ -27656,6 +28559,9 @@ msgstr ""
msgid "Warning: Displaying this diagram might cause performance issues on this page."
msgstr ""
+msgid "We are currently unable to fetch data for the pipeline header."
+msgstr ""
+
msgid "We are currently unable to fetch data for this graph."
msgstr ""
@@ -27695,6 +28601,12 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
+msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
+msgstr ""
+
+msgid "We would like to inform you that your subscription GitLab Enterprise Edition %{plan_name} is nearing its user limit. You have %{active_user_count} active users, which is almost at the user limit of %{maximum_user_count}."
+msgstr ""
+
msgid "We've found no vulnerabilities"
msgstr ""
@@ -27710,6 +28622,12 @@ msgstr ""
msgid "Web terminal"
msgstr ""
+msgid "WebAuthn Devices (%{length})"
+msgstr ""
+
+msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
+msgstr ""
+
msgid "WebIDE|Merge request"
msgstr ""
@@ -27848,15 +28766,9 @@ msgstr ""
msgid "Welcome to the guided GitLab tour"
msgstr ""
-msgid "Welcome to your Issue Board!"
-msgstr ""
-
msgid "Welcome to your issue board!"
msgstr ""
-msgid "We’ve been making changes to %{featureName} and we’d love your feedback %{linkStart}in this issue%{linkEnd} to help us improve the experience."
-msgstr ""
-
msgid "What are you searching for?"
msgstr ""
@@ -27875,6 +28787,9 @@ msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
msgstr ""
+msgid "When enabled, any user visiting %{host} and creating an account will have to be explicitly approved by the admin before they can login. This setting is effective only if sign-ups are enabled."
+msgstr ""
+
msgid "When enabled, any user visiting %{host} will be able to create an account."
msgstr ""
@@ -28098,6 +29013,9 @@ msgstr ""
msgid "With requirements, you can set criteria to check your products against."
msgstr ""
+msgid "With test cases, you can define conditions for your project to meet in determining quality"
+msgstr ""
+
msgid "Withdraw Access Request"
msgstr ""
@@ -28113,6 +29031,9 @@ msgstr ""
msgid "Workflow Help"
msgstr ""
+msgid "Would you like to create a new branch?"
+msgstr ""
+
msgid "Write"
msgstr ""
@@ -28134,6 +29055,9 @@ msgstr ""
msgid "Wrong extern UID provided. Make sure Auth0 is configured correctly."
msgstr ""
+msgid "YYYY-MM-DD"
+msgstr ""
+
msgid "Yes"
msgstr "是"
@@ -28191,7 +29115,7 @@ msgstr ""
msgid "You are going to remove the fork relationship from %{project_full_name}. Are you ABSOLUTELY sure?"
msgstr ""
-msgid "You are going to transfer %{project_full_name} to another owner. Are you ABSOLUTELY sure?"
+msgid "You are going to transfer %{project_full_name} to another namespace. Are you ABSOLUTELY sure?"
msgstr ""
msgid "You are going to turn off the confidentiality. This means %{strongStart}everyone%{strongEnd} will be able to see and leave a comment on this %{issuableType}."
@@ -28251,9 +29175,6 @@ msgstr ""
msgid "You can always edit this later"
msgstr ""
-msgid "You can apply your Trial to your Personal account or create a New Group."
-msgstr ""
-
msgid "You can create a new one or check them in your %{pat_link_start}personal access tokens%{pat_link_end} settings"
msgstr ""
@@ -28275,12 +29196,18 @@ msgstr ""
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
+msgid "You can find more information about GitLab subscriptions in %{subscriptions_doc_link}."
+msgstr ""
+
msgid "You can generate an access token scoped to this project for each application to use the GitLab API."
msgstr ""
msgid "You can get started by cloning the repository or start adding files to it with one of the following options."
msgstr ""
+msgid "You can group test cases using labels. To learn about the future direction of this feature, visit %{linkStart}Quality Management direction page%{linkEnd}."
+msgstr ""
+
msgid "You can invite a new member to %{project_name} or invite another group."
msgstr ""
@@ -28296,6 +29223,9 @@ msgstr ""
msgid "You can notify the app / group or a project by sending them an email notification"
msgstr ""
+msgid "You can now close this window."
+msgstr ""
+
msgid "You can now export your security dashboard to a CSV report."
msgstr ""
@@ -28344,9 +29274,6 @@ msgstr ""
msgid "You can test your .gitlab-ci.yml in %{linkStart}CI Lint%{linkEnd}."
msgstr ""
-msgid "You can try again using %{begin_link}basic search%{end_link}"
-msgstr ""
-
msgid "You cannot access the raw file. Please wait a minute."
msgstr ""
@@ -28398,6 +29325,9 @@ msgstr ""
msgid "You don't have any U2F devices registered yet."
msgstr ""
+msgid "You don't have any WebAuthn devices registered yet."
+msgstr ""
+
msgid "You don't have any active chat names."
msgstr ""
@@ -28485,6 +29415,9 @@ msgstr ""
msgid "You must accept our Terms of Service and privacy policy in order to register an account"
msgstr ""
+msgid "You must be logged in to search across all of GitLab"
+msgstr ""
+
msgid "You must disassociate %{domain} from all clusters it is attached to before deletion."
msgstr ""
@@ -28524,7 +29457,7 @@ msgstr ""
msgid "You need to be logged in."
msgstr ""
-msgid "You need to register a two-factor authentication app before you can set up a U2F device."
+msgid "You need to register a two-factor authentication app before you can set up a device."
msgstr ""
msgid "You need to set terms to be enforced"
@@ -28542,6 +29475,9 @@ msgstr ""
msgid "You reached %{usage_in_percent} of %{namespace_name}'s storage capacity (%{used_storage} of %{storage_limit})"
msgstr ""
+msgid "You successfully declined the invitation"
+msgstr ""
+
msgid "You tried to fork %{link_to_the_project} but it failed for the following reason:"
msgstr ""
@@ -28707,10 +29643,13 @@ msgstr ""
msgid "Your U2F device did not send a valid JSON response."
msgstr ""
-msgid "Your U2F device needs to be set up. Plug it in (if not already) and click the button on the left."
+msgid "Your U2F device was registered!"
msgstr ""
-msgid "Your U2F device was registered!"
+msgid "Your WebAuthn device did not send a valid JSON response."
+msgstr ""
+
+msgid "Your WebAuthn device was registered!"
msgstr ""
msgid "Your access request to the %{source_type} has been withdrawn."
@@ -28734,6 +29673,9 @@ msgstr ""
msgid "Your browser doesn't support U2F. Please use Google Chrome desktop (version 41 or newer)."
msgstr ""
+msgid "Your browser doesn't support WebAuthn. Please use a supported browser, e.g. Chrome (67+) or Firefox (60+)."
+msgstr ""
+
msgid "Your changes can be committed to %{branch_name} because a merge request is open."
msgstr ""
@@ -28770,6 +29712,12 @@ msgstr ""
msgid "Your deployment services will be broken, you will need to manually fix the services after renaming."
msgstr ""
+msgid "Your device is not compatible with GitLab. Please try another device"
+msgstr ""
+
+msgid "Your device needs to be set up. Plug it in (if needed) and click the button on the left."
+msgstr ""
+
msgid "Your device was successfully set up! Give it a name and register it with the GitLab server."
msgstr ""
@@ -28882,9 +29830,6 @@ msgstr[0] ""
msgid "access:"
msgstr ""
-msgid "activated"
-msgstr ""
-
msgid "added %{created_at_timeago}"
msgstr ""
@@ -28957,9 +29902,21 @@ msgstr "來自"
msgid "by %{user}"
msgstr ""
+msgid "cannot be a date in the past"
+msgstr ""
+
msgid "cannot be changed if a personal project has container registry tags."
msgstr ""
+msgid "cannot be changed if shared runners are enabled"
+msgstr ""
+
+msgid "cannot be enabled because parent group does not allow it"
+msgstr ""
+
+msgid "cannot be enabled because parent group has shared Runners disabled"
+msgstr ""
+
msgid "cannot be enabled unless all domains have TLS certificates"
msgstr ""
@@ -29005,7 +29962,7 @@ msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about SAST %{linkEndTag}"
msgstr ""
-msgid "ciReport|%{linkStartTag}Learn more about Secret Scanning %{linkEndTag}"
+msgid "ciReport|%{linkStartTag}Learn more about Secret Detection %{linkEndTag}"
msgstr ""
msgid "ciReport|%{linkStartTag}Learn more about codequality reports %{linkEndTag}"
@@ -29317,9 +30274,6 @@ msgstr ""
msgid "error"
msgstr ""
-msgid "error code:"
-msgstr ""
-
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
msgstr ""
@@ -29341,6 +30295,9 @@ msgstr ""
msgid "failed to dismiss associated finding(id=%{finding_id}): %{message}"
msgstr ""
+msgid "failed to revert associated finding(id=%{finding_id}) to detected"
+msgstr ""
+
msgid "file"
msgid_plural "files"
msgstr[0] ""
@@ -29879,6 +30836,9 @@ msgstr ""
msgid "must be a root namespace"
msgstr ""
+msgid "must be a valid IPv4 or IPv6 address"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -29915,6 +30875,9 @@ msgstr ""
msgid "no expiration"
msgstr ""
+msgid "no name set"
+msgstr ""
+
msgid "no one can merge"
msgstr ""
@@ -30088,9 +31051,6 @@ msgstr ""
msgid "security Reports|There was an error creating the merge request"
msgstr ""
-msgid "settings saved, but not activated"
-msgstr ""
-
msgid "severity|Critical"
msgstr ""
@@ -30217,9 +31177,6 @@ msgstr ""
msgid "toggle collapse"
msgstr ""
-msgid "toggle dropdown"
-msgstr ""
-
msgid "triggered"
msgstr ""
@@ -30247,6 +31204,9 @@ msgstr ""
msgid "user avatar"
msgstr ""
+msgid "user preferences"
+msgstr ""
+
msgid "username"
msgstr ""
diff --git a/package.json b/package.json
index ca76e4cab0b..eed43d4eb53 100644
--- a/package.json
+++ b/package.json
@@ -42,11 +42,11 @@
"@babel/plugin-syntax-import-meta": "^7.10.1",
"@babel/preset-env": "^7.10.1",
"@gitlab/at.js": "1.5.5",
- "@gitlab/svgs": "1.164.0",
- "@gitlab/ui": "21.3.1",
+ "@gitlab/svgs": "1.171.0",
+ "@gitlab/ui": "21.33.0",
"@gitlab/visual-review-tools": "1.6.1",
- "@rails/actioncable": "^6.0.3-1",
- "@sentry/browser": "^5.22.3",
+ "@rails/actioncable": "^6.0.3-3",
+ "@rails/ujs": "^6.0.3-2",
"@sourcegraph/code-host-integration": "0.0.50",
"@toast-ui/editor": "^2.4.0",
"@toast-ui/vue-editor": "^2.4.0",
@@ -80,7 +80,7 @@
"deckar01-task_list": "^2.3.1",
"diff": "^3.4.0",
"document-register-element": "1.14.3",
- "dompurify": "^2.0.11",
+ "dompurify": "^2.1.1",
"dropzone": "^4.2.0",
"editorconfig": "^0.15.3",
"emoji-regex": "^7.0.3",
@@ -92,14 +92,12 @@
"glob": "^7.1.6",
"graphql": "^14.7.0",
"graphql-tag": "^2.10.1",
- "gray-matter": "^4.0.2",
"immer": "^7.0.7",
"imports-loader": "^0.8.0",
"ipaddr.js": "^1.9.1",
"jed": "^1.1.1",
"jest-transform-graphql": "^2.1.0",
"jquery": "^3.5.0",
- "jquery-ujs": "1.2.2",
"jquery.caret": "^0.3.1",
"jquery.waitforimages": "^2.2.0",
"js-cookie": "^2.2.1",
@@ -107,6 +105,7 @@
"jszip": "^3.1.3",
"jszip-utils": "^0.0.2",
"katex": "^0.10.0",
+ "linkifyjs": "^2.1.9",
"lodash": "^4.17.20",
"marked": "^0.3.12",
"mermaid": "^8.5.2",
@@ -145,11 +144,11 @@
"url-loader": "^3.0.0",
"uuid": "8.1.0",
"visibilityjs": "^1.2.4",
- "vue": "^2.6.10",
+ "vue": "^2.6.12",
"vue-apollo": "^3.0.3",
- "vue-loader": "^15.9.0",
- "vue-router": "^3.4.3",
- "vue-template-compiler": "^2.6.10",
+ "vue-loader": "^15.9.3",
+ "vue-router": "^3.4.7",
+ "vue-template-compiler": "^2.6.12",
"vue-virtual-scroll-list": "^1.4.4",
"vuedraggable": "^2.23.0",
"vuex": "^3.5.1",
@@ -168,9 +167,9 @@
"@vue/test-utils": "1.0.0-beta.30",
"acorn": "^6.3.0",
"axios-mock-adapter": "^1.15.0",
- "babel-jest": "^24.1.0",
- "babel-plugin-dynamic-import-node": "^2.2.0",
- "babel-plugin-istanbul": "^5.1.0",
+ "babel-jest": "^26.5.2",
+ "babel-plugin-dynamic-import-node": "^2.3.3",
+ "babel-plugin-istanbul": "^6.0.0",
"chalk": "^2.4.1",
"commander": "^2.18.0",
"custom-jquery-matchers": "^2.1.0",
@@ -188,11 +187,11 @@
"jasmine-core": "^2.9.0",
"jasmine-diff": "^0.1.3",
"jasmine-jquery": "^2.1.1",
- "jest": "^24.1.0",
+ "jest": "^26.5.2",
"jest-canvas-mock": "^2.1.2",
- "jest-environment-jsdom-sixteen": "^1.0.0",
- "jest-junit": "^6.3.0",
- "jest-util": "^24.0.0",
+ "jest-environment-jsdom": "^26.5.2",
+ "jest-junit": "^12.0.0",
+ "jest-util": "^26.5.2",
"jsdoc": "^3.5.5",
"jsdoc-vue": "^1.0.0",
"karma": "^4.2.0",
@@ -205,7 +204,7 @@
"karma-webpack": "^4.0.2",
"markdownlint-cli": "0.23.2",
"md5": "^2.2.1",
- "node-sass": "^4.12.0",
+ "node-sass": "^4.14.1",
"nodemon": "^2.0.4",
"pixelmatch": "^4.0.2",
"postcss": "^7.0.14",
@@ -215,7 +214,7 @@
"stylelint-config-recommended": "^2.2.0",
"stylelint-scss": "^3.9.2",
"timezone-mock": "^1.0.8",
- "vue-jest": "4.0.0-beta.2",
+ "vue-jest": "4.0.0-rc.0",
"webpack-dev-server": "^3.10.3",
"xhr-mock": "^2.5.1",
"yarn-check-webpack-plugin": "^1.2.0",
@@ -226,8 +225,7 @@
},
"resolutions": {
"chokidar": "^3.4.0",
- "monaco-editor": "0.20.0",
- "vue-jest/ts-jest": "24.0.0"
+ "monaco-editor": "0.20.0"
},
"engines": {
"node": ">=10.13.0",
diff --git a/qa/Gemfile b/qa/Gemfile
index d946b22a0e0..f00f26a5482 100644
--- a/qa/Gemfile
+++ b/qa/Gemfile
@@ -1,7 +1,7 @@
source 'https://rubygems.org'
gem 'gitlab-qa'
-gem 'activesupport', '~> 6.0.3.1' # This should stay in sync with the root's Gemfile
+gem 'activesupport', '~> 6.0.3.3' # This should stay in sync with the root's Gemfile
gem 'capybara', '~> 3.29.0'
gem 'capybara-screenshot', '~> 1.0.23'
gem 'rake', '~> 12.3.3'
diff --git a/qa/Gemfile.lock b/qa/Gemfile.lock
index 2356c90a0af..6cdedc3834d 100644
--- a/qa/Gemfile.lock
+++ b/qa/Gemfile.lock
@@ -2,7 +2,7 @@ GEM
remote: https://rubygems.org/
specs:
abstract_type (0.0.7)
- activesupport (6.0.3.1)
+ activesupport (6.0.3.3)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 0.7, < 2)
minitest (~> 5.1)
@@ -38,7 +38,7 @@ GEM
concord (0.1.5)
adamantium (~> 0.2.0)
equalizer (~> 0.0.9)
- concurrent-ruby (1.1.6)
+ concurrent-ruby (1.1.7)
debase (0.2.4.1)
debase-ruby_core_source (>= 0.10.2)
debase-ruby_core_source (0.10.6)
@@ -52,7 +52,7 @@ GEM
http-accept (1.7.0)
http-cookie (1.0.3)
domain_name (~> 0.5)
- i18n (1.8.2)
+ i18n (1.8.5)
concurrent-ruby (~> 1.0)
ice_nine (0.11.2)
knapsack (1.17.1)
@@ -67,11 +67,11 @@ GEM
mime-types-data (3.2020.0425)
mini_mime (1.0.2)
mini_portile2 (2.4.0)
- minitest (5.14.1)
+ minitest (5.14.2)
netrc (0.11.0)
nokogiri (1.10.9)
mini_portile2 (~> 2.4.0)
- parallel (1.17.0)
+ parallel (1.19.2)
parallel_tests (2.29.0)
parallel
parser (2.7.1.4)
@@ -145,13 +145,13 @@ GEM
procto (~> 0.0.2)
xpath (3.2.0)
nokogiri (~> 1.8)
- zeitwerk (2.3.0)
+ zeitwerk (2.4.0)
PLATFORMS
ruby
DEPENDENCIES
- activesupport (~> 6.0.3.1)
+ activesupport (~> 6.0.3.3)
airborne (~> 0.3.4)
capybara (~> 3.29.0)
capybara-screenshot (~> 1.0.23)
diff --git a/qa/README.md b/qa/README.md
index 7ed4d63a589..5070e1ee9bd 100644
--- a/qa/README.md
+++ b/qa/README.md
@@ -50,7 +50,7 @@ the browser to use. You will need to have Chrome (or Chromium) and
- [Best practices](../doc/development/testing_guide/best_practices.md)
- [Using page objects](../doc/development/testing_guide/end_to_end/page_objects.md)
- [Guidelines](../doc/development/testing_guide/index.md)
- - [Tests with special setup for local environemnts](../doc/development/testing_guide/end_to_end/running_tests_that_require_special_setup.md)
+ - [Tests with special setup for local environments](../doc/development/testing_guide/end_to_end/running_tests_that_require_special_setup.md)
### Run the end-to-end tests in a local development environment
diff --git a/qa/Rakefile b/qa/Rakefile
index 844d8ff898d..1ecce8fdce9 100644
--- a/qa/Rakefile
+++ b/qa/Rakefile
@@ -2,6 +2,7 @@ require_relative 'qa/tools/revoke_all_personal_access_tokens'
require_relative 'qa/tools/delete_subgroups'
require_relative 'qa/tools/generate_perf_testdata'
require_relative 'qa/tools/delete_test_ssh_keys'
+require_relative 'qa/tools/initialize_gitlab_auth'
desc "Revokes all personal access tokens"
task :revoke_personal_access_tokens do
@@ -13,6 +14,11 @@ task :delete_subgroups do
QA::Tools::DeleteSubgroups.new.run
end
+desc "Initialize GitLab with an access token"
+task :initialize_gitlab_auth, [:address] do |t, args|
+ QA::Tools::InitializeGitLabAuth.new(args).run
+end
+
desc "Generate Performance Testdata"
task :generate_perf_testdata, :type do |t, args|
args.with_defaults(type: :all)
diff --git a/qa/qa.rb b/qa/qa.rb
index f6e0ea5d615..f281a4b6ef4 100644
--- a/qa/qa.rb
+++ b/qa/qa.rb
@@ -18,6 +18,7 @@ module QA
autoload :Project, 'qa/flow/project'
autoload :Saml, 'qa/flow/saml'
autoload :User, 'qa/flow/user'
+ autoload :MergeRequest, 'qa/flow/merge_request'
end
##
@@ -91,6 +92,7 @@ module QA
autoload :UserGPG, 'qa/resource/user_gpg'
autoload :Visibility, 'qa/resource/visibility'
autoload :ProjectSnippet, 'qa/resource/project_snippet'
+ autoload :Design, 'qa/resource/design'
module KubernetesCluster
autoload :Base, 'qa/resource/kubernetes_cluster/base'
@@ -190,6 +192,7 @@ module QA
autoload :Projects, 'qa/page/dashboard/projects'
autoload :Groups, 'qa/page/dashboard/groups'
autoload :Welcome, 'qa/page/dashboard/welcome'
+ autoload :Todos, 'qa/page/dashboard/todos'
module Snippet
autoload :New, 'qa/page/dashboard/snippet/new'
@@ -260,6 +263,7 @@ module QA
module Pipeline
autoload :Index, 'qa/page/project/pipeline/index'
autoload :Show, 'qa/page/project/pipeline/show'
+ autoload :New, 'qa/page/project/pipeline/new'
end
module Tag
@@ -371,6 +375,7 @@ module QA
module Snippet
autoload :New, 'qa/page/project/snippet/new'
autoload :Show, 'qa/page/project/snippet/show'
+ autoload :Index, 'qa/page/project/snippet/index'
end
end
@@ -590,10 +595,12 @@ module QA
autoload :Api, 'qa/support/api'
autoload :Dates, 'qa/support/dates'
autoload :Repeater, 'qa/support/repeater'
+ autoload :Run, 'qa/support/run'
autoload :Retrier, 'qa/support/retrier'
autoload :Waiter, 'qa/support/waiter'
autoload :WaitForRequests, 'qa/support/wait_for_requests'
autoload :OTP, 'qa/support/otp'
+ autoload :SSH, 'qa/support/ssh'
end
end
diff --git a/qa/spec/fixtures/banana_sample.gif b/qa/qa/fixtures/designs/banana_sample.gif
index 1322ac92d14..1322ac92d14 100644
--- a/qa/spec/fixtures/banana_sample.gif
+++ b/qa/qa/fixtures/designs/banana_sample.gif
Binary files differ
diff --git a/qa/qa/fixtures/designs/tanuki.jpg b/qa/qa/fixtures/designs/tanuki.jpg
new file mode 100644
index 00000000000..f0df472663e
--- /dev/null
+++ b/qa/qa/fixtures/designs/tanuki.jpg
Binary files differ
diff --git a/qa/qa/fixtures/designs/update/tanuki.jpg b/qa/qa/fixtures/designs/update/tanuki.jpg
new file mode 100644
index 00000000000..162beda6c7b
--- /dev/null
+++ b/qa/qa/fixtures/designs/update/tanuki.jpg
Binary files differ
diff --git a/qa/qa/fixtures/designs/values.png b/qa/qa/fixtures/designs/values.png
new file mode 100644
index 00000000000..9ecb6e7b778
--- /dev/null
+++ b/qa/qa/fixtures/designs/values.png
Binary files differ
diff --git a/qa/qa/flow/login.rb b/qa/qa/flow/login.rb
index d4d5cc2dcfc..d23d8eaf097 100644
--- a/qa/qa/flow/login.rb
+++ b/qa/qa/flow/login.rb
@@ -23,6 +23,7 @@ module QA
end
def sign_in(as: nil, address: :gitlab, skip_page_validation: false)
+ Page::Main::Menu.perform(&:sign_out) if Page::Main::Menu.perform(&:signed_in?)
Runtime::Browser.visit(address, Page::Main::Login)
Page::Main::Login.perform { |login| login.sign_in_using_credentials(user: as, skip_page_validation: skip_page_validation) }
end
diff --git a/qa/qa/flow/merge_request.rb b/qa/qa/flow/merge_request.rb
new file mode 100644
index 00000000000..c26140000fe
--- /dev/null
+++ b/qa/qa/flow/merge_request.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+module QA
+ module Flow
+ module MergeRequest
+ module_function
+
+ def enable_merge_trains
+ Page::Project::Menu.perform(&:go_to_general_settings)
+ Page::Project::Settings::Main.perform(&:expand_merge_requests_settings)
+ Page::Project::Settings::MergeRequest.perform(&:enable_merge_train)
+ end
+ end
+ end
+end
diff --git a/qa/qa/git/repository.rb b/qa/qa/git/repository.rb
index 035946b8471..0f7e4fbbc97 100644
--- a/qa/qa/git/repository.rb
+++ b/qa/qa/git/repository.rb
@@ -2,10 +2,8 @@
require 'cgi'
require 'uri'
-require 'open3'
require 'fileutils'
require 'tmpdir'
-require 'tempfile'
require 'securerandom'
module QA
@@ -13,8 +11,7 @@ module QA
class Repository
include Scenario::Actable
include Support::Repeater
-
- RepositoryCommandError = Class.new(StandardError)
+ include Support::Run
attr_writer :use_lfs, :gpg_key_id
attr_accessor :env_vars
@@ -59,8 +56,12 @@ module QA
self.username, self.password = default_credentials
end
+ def use_default_identity
+ configure_identity('GitLab QA', 'root@gitlab.com')
+ end
+
def clone(opts = '')
- clone_result = run("git clone #{opts} #{uri} ./", max_attempts: 3)
+ clone_result = run_git("git clone #{opts} #{uri} ./", max_attempts: 3)
return clone_result.response unless clone_result.success?
enable_lfs_result = enable_lfs if use_lfs?
@@ -70,7 +71,7 @@ module QA
def checkout(branch_name, new_branch: false)
opts = new_branch ? '-b' : ''
- run(%Q{git checkout #{opts} "#{branch_name}"}).to_s
+ run_git(%Q{git checkout #{opts} "#{branch_name}"}).to_s
end
def shallow_clone
@@ -78,8 +79,8 @@ module QA
end
def configure_identity(name, email)
- run(%Q{git config user.name "#{name}"})
- run(%Q{git config user.email #{email}})
+ run_git(%Q{git config user.name "#{name}"})
+ run_git(%Q{git config user.email #{email}})
end
def commit_file(name, contents, message)
@@ -93,83 +94,82 @@ module QA
::File.write(name, contents)
if use_lfs?
- git_lfs_track_result = run(%Q{git lfs track #{name} --lockable})
+ git_lfs_track_result = run_git(%Q{git lfs track #{name} --lockable})
return git_lfs_track_result.response unless git_lfs_track_result.success?
end
- git_add_result = run(%Q{git add #{name}})
+ git_add_result = run_git(%Q{git add #{name}})
git_lfs_track_result.to_s + git_add_result.to_s
end
def add_tag(tag_name)
- run("git tag #{tag_name}").to_s
+ run_git("git tag #{tag_name}").to_s
end
def delete_tag(tag_name)
- run(%Q{git push origin --delete #{tag_name}}, max_attempts: 3).to_s
+ run_git(%Q{git push origin --delete #{tag_name}}, max_attempts: 3).to_s
end
def commit(message)
- run(%Q{git commit -m "#{message}"}, max_attempts: 3).to_s
+ run_git(%Q{git commit -m "#{message}"}, max_attempts: 3).to_s
end
def commit_with_gpg(message)
- run(%Q{git config user.signingkey #{@gpg_key_id} && git config gpg.program $(command -v gpg) && git commit -S -m "#{message}"}).to_s
+ run_git(%Q{git config user.signingkey #{@gpg_key_id} && git config gpg.program $(command -v gpg) && git commit -S -m "#{message}"}).to_s
end
def current_branch
- run("git rev-parse --abbrev-ref HEAD").to_s
+ run_git("git rev-parse --abbrev-ref HEAD").to_s
end
- def push_changes(branch = 'master')
- run("git push #{uri} #{branch}", max_attempts: 3).to_s
+ def push_changes(branch = 'master', push_options: nil)
+ cmd = ['git push']
+ cmd << push_options_hash_to_string(push_options)
+ cmd << uri
+ cmd << branch
+ run_git(cmd.compact.join(' '), max_attempts: 3).to_s
end
def push_all_branches
- run("git push --all").to_s
+ run_git("git push --all").to_s
end
def push_tags_and_branches(branches)
- run("git push --tags origin #{branches.join(' ')}").to_s
+ run_git("git push --tags origin #{branches.join(' ')}").to_s
end
def merge(branch)
- run("git merge #{branch}")
+ run_git("git merge #{branch}")
end
def init_repository
- run("git init")
+ run_git("git init")
end
def pull(repository = nil, branch = nil)
- run(['git', 'pull', repository, branch].compact.join(' '))
+ run_git(['git', 'pull', repository, branch].compact.join(' '))
end
def commits
- run('git log --oneline').to_s.split("\n")
+ run_git('git log --oneline').to_s.split("\n")
end
def use_ssh_key(key)
- @private_key_file = Tempfile.new("id_#{SecureRandom.hex(8)}")
- File.binwrite(private_key_file, key.private_key)
- File.chmod(0700, private_key_file)
-
- @known_hosts_file = Tempfile.new("known_hosts_#{SecureRandom.hex(8)}")
- keyscan_params = ['-H']
- keyscan_params << "-p #{uri.port}" if uri.port
- keyscan_params << uri.host
- res = run("ssh-keyscan #{keyscan_params.join(' ')} >> #{known_hosts_file.path}")
- return res.response unless res.success?
+ @ssh = Support::SSH.perform do |ssh|
+ ssh.key = key
+ ssh.uri = uri
+ ssh.setup(env: self.env_vars)
+ ssh
+ end
- self.env_vars << %Q{GIT_SSH_COMMAND="ssh -i #{private_key_file.path} -o UserKnownHostsFile=#{known_hosts_file.path}"}
+ self.env_vars << %Q{GIT_SSH_COMMAND="ssh -i #{ssh.private_key_file.path} -o UserKnownHostsFile=#{ssh.known_hosts_file.path}"}
end
def delete_ssh_key
return unless ssh_key_set?
- private_key_file.close(true)
- known_hosts_file.close(true)
+ ssh.delete
end
def push_with_git_protocol(version, file_name, file_content, commit_message = 'Initial commit')
@@ -184,13 +184,13 @@ module QA
def git_protocol=(value)
raise ArgumentError, "Please specify the protocol you would like to use: 0, 1, or 2" unless %w[0 1 2].include?(value.to_s)
- run("git config protocol.version #{value}")
+ run_git("git config protocol.version #{value}")
end
def fetch_supported_git_protocol
# ls-remote is one command known to respond to Git protocol v2 so we use
# it to get output including the version reported via Git tracing
- result = run("git ls-remote #{uri}", env: "GIT_TRACE_PACKET=1", max_attempts: 3)
+ result = run_git("git ls-remote #{uri}", max_attempts: 3, env: [*self.env_vars, "GIT_TRACE_PACKET=1"])
result.response[/git< version (\d+)/, 1] || 'unknown'
end
@@ -205,21 +205,16 @@ module QA
run("cat #{file}").to_s
end
+ def delete_netrc
+ File.delete(netrc_file_path) if File.exist?(netrc_file_path)
+ end
+
private
- attr_reader :uri, :username, :password, :known_hosts_file,
- :private_key_file, :use_lfs
+ attr_reader :uri, :username, :password, :ssh, :use_lfs
alias_method :use_lfs?, :use_lfs
- Result = Struct.new(:command, :exitstatus, :response) do
- alias_method :to_s, :response
-
- def success?
- exitstatus == 0
- end
- end
-
def add_credentials?
return false if !username || !password
return true unless ssh_key_set?
@@ -228,7 +223,7 @@ module QA
end
def ssh_key_set?
- !private_key_file.nil?
+ ssh && !ssh.private_key_file.nil?
end
def enable_lfs
@@ -237,33 +232,11 @@ module QA
touch_gitconfig_result = run("touch #{tmp_home_dir}/.gitconfig")
return touch_gitconfig_result.response unless touch_gitconfig_result.success?
- git_lfs_install_result = run('git lfs install')
+ git_lfs_install_result = run_git('git lfs install')
touch_gitconfig_result.to_s + git_lfs_install_result.to_s
end
- def run(command_str, env: [], max_attempts: 1)
- command = [env_vars, *env, command_str, '2>&1'].compact.join(' ')
- result = nil
-
- repeat_until(max_attempts: max_attempts, raise_on_failure: false) do
- Runtime::Logger.debug "Git: pwd=[#{Dir.pwd}], command=[#{command}]"
- output, status = Open3.capture2e(command)
- output.chomp!
- Runtime::Logger.debug "Git: output=[#{output}], exitstatus=[#{status.exitstatus}]"
-
- result = Result.new(command, status.exitstatus, output)
-
- result.success?
- end
-
- unless result.success?
- raise RepositoryCommandError, "The command #{result.command} failed (#{result.exitstatus}) with the following output:\n#{result.response}"
- end
-
- result
- end
-
def default_credentials
if ::QA::Runtime::User.ldap_user?
[Runtime::User.ldap_username, Runtime::User.ldap_password]
@@ -293,6 +266,23 @@ module QA
@tmp_home_dir ||= File.join(Dir.tmpdir, "qa-netrc-credentials", $$.to_s)
end
+ def push_options_hash_to_string(opts)
+ return if opts.nil?
+
+ prefix = "-o merge_request"
+ opts.each_with_object([]) do |(key, value), options|
+ if value.is_a?(Array)
+ value.each do |item|
+ options << "#{prefix}.#{key}=\"#{item}\""
+ end
+ elsif value == true
+ options << "#{prefix}.#{key}"
+ else
+ options << "#{prefix}.#{key}=\"#{value}\""
+ end
+ end.join(' ')
+ end
+
def netrc_file_path
@netrc_file_path ||= File.join(tmp_home_dir, '.netrc')
end
@@ -304,6 +294,10 @@ module QA
def netrc_already_contains_content?
read_netrc_content.grep(/^#{Regexp.escape(netrc_content)}$/).any?
end
+
+ def run_git(command_str, env: self.env_vars, max_attempts: 1)
+ run(command_str, env: env, max_attempts: max_attempts, log_prefix: 'Git: ')
+ end
end
end
end
diff --git a/qa/qa/page/component/design_management.rb b/qa/qa/page/component/design_management.rb
index a8a24bd3949..fafbda58b07 100644
--- a/qa/qa/page/component/design_management.rb
+++ b/qa/qa/page/component/design_management.rb
@@ -30,6 +30,17 @@ module QA
view 'app/assets/javascripts/design_management/components/list/item.vue' do
element :design_file_name
element :design_image
+ element :design_status_icon
+ end
+
+ view 'app/assets/javascripts/design_management/pages/index.vue' do
+ element :archive_button
+ element :design_checkbox
+ element :design_dropzone_content
+ end
+
+ view 'app/assets/javascripts/design_management/components/delete_button.vue' do
+ element :confirm_archiving_button
end
end
end
@@ -52,12 +63,14 @@ module QA
# It accepts a `class:` option, but that only works for class attributes
# It doesn't work as a CSS selector.
# So instead we use the name attribute as a locator
- page.attach_file("design_file", design_file_path, make_visible: { display: 'block' })
+ within_element(:design_dropzone_content) do
+ page.attach_file("design_file", design_file_path, make_visible: { display: 'block' })
+ end
filename = ::File.basename(design_file_path)
found = wait_until(reload: false, sleep_interval: 1) do
- image = find_element(:design_image)
+ image = find_element(:design_image, filename: filename)
has_element?(:design_file_name, text: filename) &&
image["complete"] &&
@@ -67,15 +80,41 @@ module QA
raise ElementNotFound, %Q(Attempted to attach design "#{filename}" but it did not appear) unless found
end
+ def update_design(filename)
+ filepath = ::File.join('qa', 'fixtures', 'designs', 'update', filename)
+ add_design(filepath)
+ end
+
def click_design(filename)
click_element(:design_file_name, text: filename)
end
+ def select_design(filename)
+ click_element(:design_checkbox, design: filename)
+ end
+
+ def archive_selected_designs
+ click_element(:archive_button)
+ click_element(:confirm_archiving_button)
+ end
+
def has_annotation?(note)
within_element_by_index(:design_discussion_content, 0) do
has_element?(:note_content, text: note)
end
end
+
+ def has_design?(filename)
+ has_element?(:design_file_name, text: filename)
+ end
+
+ def has_created_icon?
+ has_element?(:design_status_icon, status: 'file-addition-solid')
+ end
+
+ def has_modified_icon?
+ has_element?(:design_status_icon, status: 'file-modified-solid')
+ end
end
end
end
diff --git a/qa/qa/page/component/issuable/sidebar.rb b/qa/qa/page/component/issuable/sidebar.rb
index 4e94049efe7..82347ee209a 100644
--- a/qa/qa/page/component/issuable/sidebar.rb
+++ b/qa/qa/page/component/issuable/sidebar.rb
@@ -18,16 +18,29 @@ module QA
element :more_assignees_link
end
- base.view 'app/helpers/dropdowns_helper.rb' do
+ base.view 'app/assets/javascripts/sidebar/components/labels/sidebar_labels.vue' do
+ element :labels_block
+ end
+
+ base.view 'app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/dropdown_value.vue' do
+ element :selected_label_content
+ end
+
+ base.view 'app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/dropdown_contents.vue' do
+ element :labels_dropdown_content
+ end
+
+ base.view 'app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_title.vue' do
+ element :labels_edit_button
+ end
+
+ base.view 'app/assets/javascripts/vue_shared/components/sidebar/labels_select_vue/dropdown_contents_labels_view.vue' do
element :dropdown_input_field
end
base.view 'app/views/shared/issuable/_sidebar.html.haml' do
element :assignee_block
- element :dropdown_menu_labels
- element :edit_labels_link
element :edit_milestone_link
- element :labels_block
element :milestone_block
element :milestone_link
end
@@ -64,7 +77,7 @@ module QA
def has_label?(label)
within_element(:labels_block) do
- !!has_element?(:label, label_name: label)
+ !!has_element?(:selected_label_content, label_name: label)
end
end
@@ -80,23 +93,25 @@ module QA
def select_labels_and_refresh(labels)
Support::Retrier.retry_until do
- click_element(:edit_labels_link)
- has_element?(:dropdown_menu_labels, text: labels.first)
+ click_element(:labels_edit_button)
+ has_element?(:labels_dropdown_content, text: labels.first)
end
labels.each do |label|
- within_element(:dropdown_menu_labels, text: label) do
+ within_element(:labels_dropdown_content) do
send_keys_to_element(:dropdown_input_field, [label, :enter])
end
end
- click_element(:edit_labels_link)
+ click_element(:labels_edit_button)
labels.each do |label|
has_element?(:labels_block, text: label, wait: 0)
end
refresh
+
+ wait_for_requests
end
def toggle_more_assignees_link
diff --git a/qa/qa/page/component/new_snippet.rb b/qa/qa/page/component/new_snippet.rb
index 3e5ae29177a..741a3feb73b 100644
--- a/qa/qa/page/component/new_snippet.rb
+++ b/qa/qa/page/component/new_snippet.rb
@@ -21,18 +21,11 @@ module QA
base.view 'app/assets/javascripts/snippets/components/snippet_blob_edit.vue' do
element :file_name_field
+ element :file_holder_container
end
- base.view 'app/views/shared/form_elements/_description.html.haml' do
- element :issuable_form_description
- end
-
- base.view 'app/views/shared/snippets/_form.html.haml' do
- element :snippet_description_field
- element :description_placeholder
- element :snippet_title_field
- element :file_name_field
- element :submit_button
+ base.view 'app/assets/javascripts/snippets/components/snippet_blob_actions_edit.vue' do
+ element :add_file_button
end
base.view 'app/views/shared/_zen.html.haml' do
@@ -54,12 +47,28 @@ module QA
choose visibility
end
- def fill_file_name(name)
- fill_element :file_name_field, name
+ def fill_file_name(name, file_number = nil)
+ if file_number
+ within_element_by_index(:file_holder_container, file_number - 1) do
+ fill_element(:file_name_field, name)
+ end
+ else
+ fill_element(:file_name_field, name)
+ end
+ end
+
+ def fill_file_content(content, file_number = nil)
+ if file_number
+ within_element_by_index(:file_holder_container, file_number - 1) do
+ text_area.set(content)
+ end
+ else
+ text_area.set content
+ end
end
- def fill_file_content(content)
- text_area.set content
+ def click_add_file
+ click_element(:add_file_button)
end
def click_create_snippet_button
@@ -70,7 +79,7 @@ module QA
private
def text_area
- find('#editor textarea', visible: false)
+ find('.monaco-editor textarea', visible: false)
end
end
end
diff --git a/qa/qa/page/component/note.rb b/qa/qa/page/component/note.rb
index 0e9cdd49519..e6defd2ec0c 100644
--- a/qa/qa/page/component/note.rb
+++ b/qa/qa/page/component/note.rb
@@ -9,9 +9,18 @@ module QA
def self.included(base)
super
+ base.view 'app/assets/javascripts/diffs/components/diff_file_header.vue' do
+ element :toggle_comments_button
+ end
+
+ base.view 'app/assets/javascripts/notes/components/discussion_actions.vue' do
+ element :discussion_reply_tab
+ element :resolve_discussion_button
+ end
+
base.view 'app/assets/javascripts/notes/components/comment_form.vue' do
element :note_dropdown
- element :discussion_option
+ element :discussion_menu_item
end
base.view 'app/assets/javascripts/notes/components/noteable_discussion.vue' do
@@ -23,39 +32,32 @@ module QA
end
base.view 'app/assets/javascripts/notes/components/note_form.vue' do
- element :reply_input
+ element :reply_field
element :reply_comment_button
end
- base.view 'app/assets/javascripts/notes/components/discussion_actions.vue' do
- element :discussion_reply_tab
- element :resolve_discussion_button
- end
-
base.view 'app/assets/javascripts/notes/components/toggle_replies_widget.vue' do
- element :expand_replies
- element :collapse_replies
+ element :expand_replies_button
+ element :collapse_replies_button
end
- base.view 'app/assets/javascripts/diffs/components/diff_file_header.vue' do
- element :toggle_comments_button
+ base.view 'app/assets/javascripts/vue_shared/components/notes/skeleton_note.vue' do
+ element :skeleton_note_placeholder
end
end
- def start_discussion(text)
- fill_element :comment_input, text
- click_element :note_dropdown
- click_element :discussion_option
- click_element :comment_button
+ def collapse_replies
+ click_element :collapse_replies_button
end
- def toggle_comments(position)
- all_elements(:toggle_comments_button, minimum: position)[position - 1].click
+ def edit_comment(text)
+ click_element :note_edit_button
+ fill_element :reply_field, text
+ click_element :reply_comment_button
end
- def type_reply_to_discussion(position, reply_text)
- all_elements(:discussion_reply_tab, minimum: position)[position - 1].click
- fill_element :reply_input, reply_text
+ def expand_replies
+ click_element :expand_replies_button
end
def reply_to_discussion(position, reply_text)
@@ -69,18 +71,24 @@ module QA
end
end
- def collapse_replies
- click_element :collapse_replies
+ def start_discussion(text)
+ fill_element :comment_field, text
+ click_element :note_dropdown
+ click_element :discussion_menu_item
+ click_element :comment_button
end
- def expand_replies
- click_element :expand_replies
+ def toggle_comments(position)
+ all_elements(:toggle_comments_button, minimum: position)[position - 1].click
end
- def edit_comment(text)
- click_element :note_edit_button
- fill_element :reply_input, text
- click_element :reply_comment_button
+ def type_reply_to_discussion(position, reply_text)
+ all_elements(:discussion_reply_tab, minimum: position)[position - 1].click
+ fill_element :reply_field, reply_text
+ end
+
+ def wait_for_loading
+ has_no_element?(:skeleton_note_placeholer)
end
end
end
diff --git a/qa/qa/page/component/select2.rb b/qa/qa/page/component/select2.rb
index 761bbb17168..87aed0105aa 100644
--- a/qa/qa/page/component/select2.rb
+++ b/qa/qa/page/component/select2.rb
@@ -43,6 +43,8 @@ module QA
end
def wait_for_search_to_complete
+ Support::WaitForRequests.wait_for_requests
+
has_css?('.select2-active', wait: 1)
has_no_css?('.select2-active', wait: 30)
end
diff --git a/qa/qa/page/component/snippet.rb b/qa/qa/page/component/snippet.rb
index 2776b6c078e..9a4b06d8ac7 100644
--- a/qa/qa/page/component/snippet.rb
+++ b/qa/qa/page/component/snippet.rb
@@ -98,15 +98,39 @@ module QA
end
end
- def has_file_name?(file_name)
- within_element(:file_title_content) do
- has_text?(file_name)
+ def has_file_name?(file_name, file_number = nil)
+ if file_number
+ within_element_by_index(:file_title_content, file_number - 1) do
+ has_text?(file_name)
+ end
+ else
+ within_element(:file_title_content) do
+ has_text?(file_name)
+ end
end
end
- def has_file_content?(file_content)
- within_element(:file_content) do
- has_text?(file_content)
+ def has_file_content?(file_content, file_number = nil)
+ if file_number
+ within_element_by_index(:file_content, file_number - 1) do
+ has_text?(file_content)
+ end
+ else
+ within_element(:file_content) do
+ has_text?(file_content)
+ end
+ end
+ end
+
+ def has_no_file_content?(file_content, file_number = nil)
+ if file_number
+ within_element_by_index(:file_content, file_number - 1) do
+ has_no_text?(file_content)
+ end
+ else
+ within_element(:file_content) do
+ has_no_text?(file_content)
+ end
end
end
@@ -115,7 +139,7 @@ module QA
end
def click_edit_button
- click_element(:snippet_action_button, action: 'Edit')
+ click_element(:snippet_action_button, Page::Dashboard::Snippet::Edit, action: 'Edit')
end
def click_delete_button
diff --git a/qa/qa/page/dashboard/snippet/edit.rb b/qa/qa/page/dashboard/snippet/edit.rb
index 7802a680c25..37c0747aea4 100644
--- a/qa/qa/page/dashboard/snippet/edit.rb
+++ b/qa/qa/page/dashboard/snippet/edit.rb
@@ -5,16 +5,11 @@ module QA
module Dashboard
module Snippet
class Edit < Page::Base
- view 'app/views/shared/snippets/_form.html.haml' do
- element :submit_button
- end
-
view 'app/assets/javascripts/snippets/components/edit.vue' do
- element :submit_button
+ element :submit_button, required: true
end
def add_to_file_content(content)
- finished_loading?
text_area.set content
text_area.has_text?(content) # wait for changes to take effect
end
@@ -30,7 +25,7 @@ module QA
private
def text_area
- find('#editor textarea', visible: false)
+ find('.monaco-editor textarea', visible: false)
end
end
end
diff --git a/qa/qa/page/dashboard/todos.rb b/qa/qa/page/dashboard/todos.rb
new file mode 100644
index 00000000000..d8baadcf73d
--- /dev/null
+++ b/qa/qa/page/dashboard/todos.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+module QA
+ module Page
+ module Dashboard
+ class Todos < Page::Base
+ include Page::Component::Snippet
+
+ view 'app/views/dashboard/todos/index.html.haml' do
+ element :todos_list_container, required: true
+ end
+
+ view 'app/views/dashboard/todos/_todo.html.haml' do
+ element :todo_item_container
+ element :todo_action_name_content
+ element :todo_target_title_content
+ end
+
+ def has_todo_list?
+ has_element? :todo_item_container
+ end
+
+ def has_latest_todo_item_with_content?(action, title)
+ within_element(:todos_list_container) do
+ within_element_by_index(:todo_item_container, 0) do
+ has_element?(:todo_action_name_content, text: action) && has_element?(:todo_target_title_content, text: title)
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/page/main/sign_up.rb b/qa/qa/page/main/sign_up.rb
index b7808afb209..98bbbc53027 100644
--- a/qa/qa/page/main/sign_up.rb
+++ b/qa/qa/page/main/sign_up.rb
@@ -5,12 +5,12 @@ module QA
module Main
class SignUp < Page::Base
view 'app/views/devise/shared/_signup_box.html.haml' do
- element :new_user_name_field
+ element :new_user_first_name_field
+ element :new_user_last_name_field
element :new_user_username_field
element :new_user_email_field
element :new_user_password_field
element :new_user_register_button
- element :new_user_accept_terms_checkbox
end
view 'app/views/registrations/welcome.html.haml' do
@@ -18,13 +18,12 @@ module QA
end
def sign_up!(user)
- fill_element :new_user_name_field, user.name
+ fill_element :new_user_first_name_field, user.first_name
+ fill_element :new_user_last_name_field, user.last_name
fill_element :new_user_username_field, user.username
fill_element :new_user_email_field, user.email
fill_element :new_user_password_field, user.password
- check_element :new_user_accept_terms_checkbox if has_element?(:new_user_accept_terms_checkbox)
-
signed_in = retry_until do
click_element :new_user_register_button if has_element?(:new_user_register_button)
diff --git a/qa/qa/page/merge_request/show.rb b/qa/qa/page/merge_request/show.rb
index 0b80ba84fa4..164f25389c0 100644
--- a/qa/qa/page/merge_request/show.rb
+++ b/qa/qa/page/merge_request/show.rb
@@ -44,15 +44,23 @@ module QA
element :squash_checkbox
end
- view 'app/assets/javascripts/vue_shared/components/notes/skeleton_note.vue' do
- element :skeleton_note
- end
-
view 'app/views/projects/merge_requests/show.html.haml' do
element :notes_tab
element :diffs_tab
end
+ view 'app/assets/javascripts/diffs/components/compare_dropdown_layout.vue' do
+ element :dropdown_content
+ end
+
+ view 'app/assets/javascripts/diffs/components/compare_versions.vue' do
+ element :target_version_dropdown
+ end
+
+ view 'app/assets/javascripts/diffs/components/diff_file_header.vue' do
+ element :file_name_content
+ end
+
view 'app/assets/javascripts/diffs/components/inline_diff_table_row.vue' do
element :new_diff_line
end
@@ -67,15 +75,13 @@ module QA
view 'app/assets/javascripts/batch_comments/components/review_bar.vue' do
element :review_bar
- element :discard_review
- element :modal_delete_pending_comments
end
view 'app/assets/javascripts/notes/components/note_form.vue' do
element :unresolve_review_discussion_checkbox
element :resolve_review_discussion_checkbox
- element :start_review
- element :comment_now
+ element :start_review_button
+ element :comment_now_button
end
view 'app/assets/javascripts/batch_comments/components/preview_dropdown.vue' do
@@ -83,46 +89,54 @@ module QA
end
def start_review
- click_element :start_review
+ click_element(:start_review_button)
# After clicking the button, wait for it to disappear
# before moving on to the next part of the test
- has_no_element? :start_review
+ has_no_element?(:start_review_button)
+ end
+
+ def click_target_version_dropdown
+ click_element(:target_version_dropdown)
end
def comment_now
- click_element :comment_now
+ click_element(:comment_now_button)
# After clicking the button, wait for it to disappear
# before moving on to the next part of the test
- has_no_element? :comment_now
+ has_no_element?(:comment_now_button)
+ end
+
+ def version_dropdown_content
+ find_element(:dropdown_content).text
end
def submit_pending_reviews
- within_element :review_bar do
- click_element :review_preview_toggle
- click_element :submit_review
+ within_element(:review_bar) do
+ click_element(:review_preview_toggle)
+ click_element(:submit_review)
# After clicking the button, wait for it to disappear
# before moving on to the next part of the test
- has_no_element? :submit_review
+ has_no_element?(:submit_review)
end
end
def discard_pending_reviews
- within_element :review_bar do
- click_element :discard_review
+ within_element(:review_bar) do
+ click_element(:discard_review)
end
- click_element :modal_delete_pending_comments
+ click_element(:modal_delete_pending_comments)
end
def resolve_review_discussion
- scroll_to_element :start_review
- check_element :resolve_review_discussion_checkbox
+ scroll_to_element(:start_review_button)
+ check_element(:resolve_review_discussion_checkbox)
end
def unresolve_review_discussion
- check_element :unresolve_review_discussion_checkbox
+ check_element(:unresolve_review_discussion_checkbox)
end
def add_comment_to_diff(text)
@@ -131,7 +145,7 @@ module QA
end
all_elements(:new_diff_line, minimum: 1).first.hover
click_element(:diff_comment)
- fill_element(:reply_input, text)
+ fill_element(:reply_field, text)
end
def click_discussions_tab
@@ -160,6 +174,10 @@ module QA
has_no_text?('Fast-forward merge is not possible')
end
+ def has_file?(file_name)
+ has_element?(:file_name_content, text: file_name)
+ end
+
def has_merge_button?
refresh
@@ -168,7 +186,7 @@ module QA
def has_pipeline_status?(text)
# Pipelines can be slow, so we wait a bit longer than the usual 10 seconds
- has_element?(:merge_request_pipeline_info_content, text: text, wait: 30)
+ has_element?(:merge_request_pipeline_info_content, text: text, wait: 60)
end
def has_title?(title)
@@ -190,7 +208,7 @@ module QA
!find_element(:squash_checkbox).disabled?
end
- click_element :squash_checkbox
+ click_element(:squash_checkbox)
end
def merge!
@@ -202,7 +220,7 @@ module QA
end
def merged?
- has_element?(:merged_status_content, text: 'The changes were merged into', wait: 30)
+ has_element?(:merged_status_content, text: 'The changes were merged into', wait: 60)
end
# Check if the MR is able to be merged
@@ -235,7 +253,7 @@ module QA
!find_element(:mr_rebase_button).disabled?
end
- click_element :mr_rebase_button
+ click_element(:mr_rebase_button)
success = wait_until do
has_text?('Fast-forward merge without a merge commit')
@@ -251,12 +269,12 @@ module QA
end
def view_email_patches
- click_element :download_dropdown
+ click_element(:download_dropdown)
visit_link_in_element(:download_email_patches)
end
def view_plain_diff
- click_element :download_dropdown
+ click_element(:download_dropdown)
visit_link_in_element(:download_plain_diff)
end
@@ -266,10 +284,6 @@ module QA
end
end
- def wait_for_loading
- has_no_element?(:skeleton_note)
- end
-
def click_open_in_web_ide
click_element(:open_in_web_ide_button)
wait_for_requests
diff --git a/qa/qa/page/profile/accounts/show.rb b/qa/qa/page/profile/accounts/show.rb
index cf7f7d80cfa..84a34d1da78 100644
--- a/qa/qa/page/profile/accounts/show.rb
+++ b/qa/qa/page/profile/accounts/show.rb
@@ -7,6 +7,7 @@ module QA
class Show < Page::Base
view 'app/views/profiles/accounts/show.html.haml' do
element :delete_account_button, required: true
+ element :enable_2fa_button
end
view 'app/assets/javascripts/profile/account/components/delete_account_modal.vue' do
@@ -14,6 +15,10 @@ module QA
element :confirm_delete_account_button
end
+ def click_enable_2fa_button
+ click_element(:enable_2fa_button)
+ end
+
def delete_account(password)
click_element(:delete_account_button)
diff --git a/qa/qa/page/profile/ssh_keys.rb b/qa/qa/page/profile/ssh_keys.rb
index 810877e21ad..8da484003f4 100644
--- a/qa/qa/page/profile/ssh_keys.rb
+++ b/qa/qa/page/profile/ssh_keys.rb
@@ -11,8 +11,9 @@ module QA
element :add_key_button
end
- view 'app/views/profiles/keys/_key_details.html.haml' do
- element :delete_key_button
+ view 'app/helpers/ssh_keys_helper.rb' do
+ element :delete_ssh_key_button
+ element :ssh_key_delete_modal
end
view 'app/views/profiles/keys/_key_table.html.haml' do
@@ -38,8 +39,14 @@ module QA
def remove_key(title)
click_link(title)
- accept_alert do
- click_element(:delete_key_button)
+ click_element(:delete_ssh_key_button)
+
+ # Retrying due to https://gitlab.com/gitlab-org/gitlab/-/issues/255287
+ retry_on_exception do
+ wait_for_animated_element(:ssh_key_delete_modal)
+ within_element(:ssh_key_delete_modal) do
+ click_button('Delete')
+ end
end
end
diff --git a/qa/qa/page/project/issue/show.rb b/qa/qa/page/project/issue/show.rb
index 826acaa2e0a..a02617def9e 100644
--- a/qa/qa/page/project/issue/show.rb
+++ b/qa/qa/page/project/issue/show.rb
@@ -12,7 +12,7 @@ module QA
view 'app/assets/javascripts/notes/components/comment_form.vue' do
element :comment_button
- element :comment_input
+ element :comment_field
end
view 'app/assets/javascripts/notes/components/discussion_filter.vue' do
@@ -43,7 +43,7 @@ module QA
end
view 'app/assets/javascripts/related_issues/components/related_issuable_input.vue' do
- element :add_issue_input
+ element :add_issue_field
end
view 'app/assets/javascripts/related_issues/components/related_issues_block.vue' do
@@ -57,8 +57,8 @@ module QA
def relate_issue(issue)
click_element(:related_issues_plus_button)
- fill_element(:add_issue_input, issue.web_url)
- send_keys_to_element(:add_issue_input, :enter)
+ fill_element(:add_issue_field, issue.web_url)
+ send_keys_to_element(:add_issue_field, :enter)
end
def related_issuable_item
@@ -84,7 +84,7 @@ module QA
# attachment option should be an absolute path
def comment(text, attachment: nil, filter: :all_activities)
method("select_#{filter}_filter").call
- fill_element :comment_input, "#{text}\n"
+ fill_element :comment_field, "#{text}\n"
unless attachment.nil?
QA::Page::Component::Dropzone.new(self, '.new-note')
@@ -125,6 +125,8 @@ module QA
click_element(:title)
click_element :discussion_filter
find_element(:filter_options, text: text).click
+
+ wait_for_loading
end
end
end
diff --git a/qa/qa/page/project/job/show.rb b/qa/qa/page/project/job/show.rb
index 6a657b4ab39..2ecb27e05b2 100644
--- a/qa/qa/page/project/job/show.rb
+++ b/qa/qa/page/project/job/show.rb
@@ -58,6 +58,10 @@ module QA
click_element :retry_button
end
+ def has_job_log?
+ has_element? :job_log_content
+ end
+
private
def loaded?(wait: 60)
@@ -70,3 +74,5 @@ module QA
end
end
end
+
+QA::Page::Project::Job::Show.prepend_if_ee('QA::EE::Page::Project::Job::Show')
diff --git a/qa/qa/page/project/new.rb b/qa/qa/page/project/new.rb
index f6c015f64ea..7e296528795 100644
--- a/qa/qa/page/project/new.rb
+++ b/qa/qa/page/project/new.rb
@@ -23,11 +23,7 @@ module QA
element :visibility_radios, 'visibility_level:' # rubocop:disable QA/ElementWithPattern
end
- view 'app/views/projects/_import_project_pane.html.haml' do
- element :import_github, "icon('github', text: 'GitHub')" # rubocop:disable QA/ElementWithPattern
- end
-
- view 'app/views/projects/project_templates/_built_in_templates.html.haml' do
+ view 'app/views/projects/project_templates/_template.html.haml' do
element :use_template_button
element :template_option_row
end
diff --git a/qa/qa/page/project/operations/kubernetes/index.rb b/qa/qa/page/project/operations/kubernetes/index.rb
index 0c92f9a9f28..114e3ddd46a 100644
--- a/qa/qa/page/project/operations/kubernetes/index.rb
+++ b/qa/qa/page/project/operations/kubernetes/index.rb
@@ -7,11 +7,11 @@ module QA
module Kubernetes
class Index < Page::Base
view 'app/views/clusters/clusters/_empty_state.html.haml' do
- element :add_kubernetes_cluster_button, "link_to s_('ClusterIntegration|Add Kubernetes cluster')" # rubocop:disable QA/ElementWithPattern
+ element :add_kubernetes_cluster_button, "link_to s_('ClusterIntegration|Integrate with a cluster certificate')" # rubocop:disable QA/ElementWithPattern
end
def add_kubernetes_cluster
- click_on 'Add Kubernetes cluster'
+ click_on 'Connect cluster with certificate'
end
def has_cluster?(cluster)
diff --git a/qa/qa/page/project/packages/index.rb b/qa/qa/page/project/packages/index.rb
index 6d55d1d04b6..396d3373b8a 100644
--- a/qa/qa/page/project/packages/index.rb
+++ b/qa/qa/page/project/packages/index.rb
@@ -26,3 +26,5 @@ module QA
end
end
end
+
+QA::Page::Project::Packages::Index.prepend_if_ee('QA::EE::Page::Project::Packages::Index')
diff --git a/qa/qa/page/project/pipeline/index.rb b/qa/qa/page/project/pipeline/index.rb
index aa2ef2f058f..aff2378330a 100644
--- a/qa/qa/page/project/pipeline/index.rb
+++ b/qa/qa/page/project/pipeline/index.rb
@@ -14,6 +14,10 @@ module QA
element :pipeline_retry_button
end
+ view 'app/assets/javascripts/pipelines/components/pipelines_list/nav_controls.vue' do
+ element :run_pipeline_button
+ end
+
def click_on_latest_pipeline
all_elements(:pipeline_url_link, minimum: 1, wait: QA::Support::Repeater::DEFAULT_MAX_WAIT_TIME).first.click
end
@@ -40,8 +44,18 @@ module QA
wait_for_latest_pipeline_success
end
end
+
+ def has_pipeline?
+ has_element? :pipeline_url_link
+ end
+
+ def click_run_pipeline_button
+ click_element :run_pipeline_button, Page::Project::Pipeline::New
+ end
end
end
end
end
end
+
+QA::Page::Project::Pipeline::Index.prepend_if_ee('QA::EE::Page::Project::Pipeline::Index')
diff --git a/qa/qa/page/project/pipeline/new.rb b/qa/qa/page/project/pipeline/new.rb
new file mode 100644
index 00000000000..644a21b46e9
--- /dev/null
+++ b/qa/qa/page/project/pipeline/new.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+module QA
+ module Page
+ module Project
+ module Pipeline
+ class New < QA::Page::Base
+ view 'app/assets/javascripts/pipeline_new/components/pipeline_new_form.vue' do
+ element :run_pipeline_button, required: true
+ end
+
+ def click_run_pipeline_button
+ click_element :run_pipeline_button
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/page/project/pipeline/show.rb b/qa/qa/page/project/pipeline/show.rb
index 57ab7fb4480..0fb5238a308 100644
--- a/qa/qa/page/project/pipeline/show.rb
+++ b/qa/qa/page/project/pipeline/show.rb
@@ -8,7 +8,7 @@ module QA
include Component::CiBadgeLink
view 'app/assets/javascripts/vue_shared/components/header_ci_component.vue' do
- element :pipeline_header, /header class.*ci-header-container.*/ # rubocop:disable QA/ElementWithPattern
+ element :pipeline_header
end
view 'app/assets/javascripts/pipelines/components/graph/graph_component.vue' do
@@ -16,8 +16,9 @@ module QA
end
view 'app/assets/javascripts/pipelines/components/graph/job_item.vue' do
- element :job_component, /class.*ci-job-component.*/ # rubocop:disable QA/ElementWithPattern
+ element :job_item_container
element :job_link
+ element :action_button
end
view 'app/assets/javascripts/pipelines/components/graph/linked_pipeline.vue' do
@@ -34,16 +35,18 @@ module QA
end
def running?(wait: 0)
- within('.ci-header-container') do
+ within_element(:pipeline_header) do
page.has_content?('running', wait: wait)
end
end
def has_build?(name, status: :success, wait: nil)
- within('.pipeline-graph') do
- within('.ci-job-component', text: name) do
+ if status
+ within_element(:job_item_container, text: name) do
has_selector?(".ci-status-icon-#{status}", { wait: wait }.compact)
end
+ else
+ has_element?(:job_item_container, text: name)
end
end
@@ -78,6 +81,12 @@ module QA
def click_on_first_job
first('.js-pipeline-graph-job-link', wait: QA::Support::Repeater::DEFAULT_MAX_WAIT_TIME).click
end
+
+ def click_job_action(job_name)
+ within_element(:job_item_container, text: job_name) do
+ click_element(:action_button)
+ 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 aef9800e876..f2ced668a60 100644
--- a/qa/qa/page/project/settings/ci_variables.rb
+++ b/qa/qa/page/project/settings/ci_variables.rb
@@ -26,6 +26,10 @@ module QA
within_element(:ci_variable_key_field) { find('input').set key }
fill_element :ci_variable_value_field, value
click_ci_variable_save_button
+
+ wait_until(reload: false) do
+ within_element(:ci_variable_table_content) { has_element?(:edit_ci_variable_button) }
+ end
end
def click_add_variable
diff --git a/qa/qa/page/project/show.rb b/qa/qa/page/project/show.rb
index c607b35005e..d81be2803bd 100644
--- a/qa/qa/page/project/show.rb
+++ b/qa/qa/page/project/show.rb
@@ -103,6 +103,8 @@ module QA
end
def click_commit(commit_msg)
+ wait_for_requests
+
within_element(:file_tree_table) do
click_on commit_msg
end
diff --git a/qa/qa/page/project/snippet/index.rb b/qa/qa/page/project/snippet/index.rb
new file mode 100644
index 00000000000..a221abc4196
--- /dev/null
+++ b/qa/qa/page/project/snippet/index.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+module QA
+ module Page
+ module Project
+ module Snippet
+ class Index < Page::Base
+ include Page::Component::Snippet
+
+ view 'app/views/shared/snippets/_snippet.html.haml' do
+ element :snippet_link
+ end
+
+ def has_project_snippet?(title)
+ has_element?(:snippet_link, snippet_title: title)
+ end
+
+ def click_snippet_link(title)
+ within_element(:snippet_link, text: title) do
+ click_link(title)
+ end
+ end
+ end
+ end
+ end
+ end
+end
+
+QA::Page::Project::Snippet::Index.prepend_if_ee('QA::EE::Page::Project::Snippet::Index')
diff --git a/qa/qa/page/project/web_ide/edit.rb b/qa/qa/page/project/web_ide/edit.rb
index 56c8d343cf5..fc33c753230 100644
--- a/qa/qa/page/project/web_ide/edit.rb
+++ b/qa/qa/page/project/web_ide/edit.rb
@@ -73,6 +73,10 @@ module QA
element :project_path_content
end
+ view 'app/assets/javascripts/ide/components/commit_sidebar/message_field.vue' do
+ element :ide_commit_message_field
+ end
+
def has_file?(file_name)
within_element(:file_list) do
page.has_content? file_name
@@ -83,6 +87,10 @@ module QA
has_element?(:project_path_content, project_path: project_path)
end
+ def go_to_project
+ click_element(:project_path_content, Page::Project::Show)
+ end
+
def create_new_file_from_template(file_name, template)
click_element(:new_file, Page::Component::WebIDE::Modal::CreateNewFile)
@@ -115,7 +123,7 @@ module QA
find_element(:commit_sha_content).text
end
- def commit_changes(open_merge_request: false)
+ def commit_changes(commit_message = nil, open_merge_request: false)
# Clicking :begin_commit_button switches from the
# edit to the commit view
click_element(:begin_commit_button)
@@ -133,6 +141,10 @@ module QA
has_element?(:commit_button)
end
+ if commit_message
+ fill_element(:ide_commit_message_field, commit_message)
+ end
+
if open_merge_request
click_element(:commit_button, Page::MergeRequest::New)
else
diff --git a/qa/qa/page/project/wiki/show.rb b/qa/qa/page/project/wiki/show.rb
index cdd18e420d1..61b0d202a76 100644
--- a/qa/qa/page/project/wiki/show.rb
+++ b/qa/qa/page/project/wiki/show.rb
@@ -11,12 +11,12 @@ module QA
view 'app/views/shared/wikis/show.html.haml' do
element :wiki_page_title
element :wiki_page_content
+ element :edit_page_button
end
view 'app/views/shared/wikis/_main_links.html.haml' do
element :new_page_button
element :page_history_button
- element :edit_page_button
end
view 'app/views/shared/empty_states/_wikis.html.haml' do
diff --git a/qa/qa/resource/api_fabricator.rb b/qa/qa/resource/api_fabricator.rb
index d0cbab70983..034feb4e90f 100644
--- a/qa/qa/resource/api_fabricator.rb
+++ b/qa/qa/resource/api_fabricator.rb
@@ -96,15 +96,38 @@ module QA
end
def api_post
- response = post(
- Runtime::API::Request.new(api_client, api_post_path).url,
- api_post_body)
+ if api_post_path == "/graphql"
+ graphql_response = post(
+ Runtime::API::Request.new(api_client, api_post_path).url,
+ query: api_post_body)
- unless response.code == HTTP_STATUS_CREATED
- raise ResourceFabricationFailedError, "Fabrication of #{self.class.name} using the API failed (#{response.code}) with `#{response}`."
+ flattened_response = flatten_hash(parse_body(graphql_response))
+
+ unless graphql_response.code == HTTP_STATUS_OK && flattened_response[:errors].empty?
+ raise ResourceFabricationFailedError, "Fabrication of #{self.class.name} using the API failed (#{graphql_response.code}) with `#{graphql_response}`."
+ end
+
+ flattened_response[:web_url] = flattened_response.delete(:webUrl)
+ flattened_response[:id] = flattened_response.fetch(:id).split('/')[-1]
+
+ process_api_response(flattened_response)
+ else
+ response = post(
+ Runtime::API::Request.new(api_client, api_post_path).url,
+ api_post_body)
+
+ unless response.code == HTTP_STATUS_CREATED
+ raise ResourceFabricationFailedError, "Fabrication of #{self.class.name} using the API failed (#{response.code}) with `#{response}`."
+ end
+
+ process_api_response(parse_body(response))
end
+ end
- process_api_response(parse_body(response))
+ def flatten_hash(param)
+ param.each_pair.reduce({}) do |a, (k, v)|
+ v.is_a?(Hash) ? a.merge(flatten_hash(v)) : a.merge(k.to_sym => v)
+ end
end
def api_delete
diff --git a/qa/qa/resource/design.rb b/qa/qa/resource/design.rb
new file mode 100644
index 00000000000..182985f2d9f
--- /dev/null
+++ b/qa/qa/resource/design.rb
@@ -0,0 +1,34 @@
+# frozen_string_literal: true
+
+module QA
+ module Resource
+ class Design < Base
+ attr_reader :id
+ attr_accessor :filename
+
+ attribute :issue do
+ Issue.fabricate_via_api!
+ end
+
+ def initialize
+ @update = false
+ @filename = 'banana_sample.gif'
+ end
+
+ # TODO This will be replaced as soon as file uploads over GraphQL are implemented
+ def fabricate!
+ issue.visit!
+
+ Page::Project::Issue::Show.perform do |issue|
+ issue.add_design(filepath)
+ end
+ end
+
+ private
+
+ def filepath
+ ::File.absolute_path(::File.join('qa', 'fixtures', 'designs', @filename))
+ end
+ end
+ end
+end
diff --git a/qa/qa/resource/events/base.rb b/qa/qa/resource/events/base.rb
index 91ec0e59e37..4c5f54825b3 100644
--- a/qa/qa/resource/events/base.rb
+++ b/qa/qa/resource/events/base.rb
@@ -9,9 +9,12 @@ module QA
EventNotFoundError = Class.new(RuntimeError)
module Base
- def events(action: nil)
+ def events(action: nil, target_type: nil)
+ query = []
+ query << "action=#{CGI.escape(action)}" if action
+ query << "target_type=#{CGI.escape(target_type)}" if target_type
path = [api_get_events]
- path << "?action=#{CGI.escape(action)}" if action
+ path << "?#{query.join("&")}" unless query.empty?
parse_body(api_get_from("#{path.join}"))
end
diff --git a/qa/qa/resource/events/project.rb b/qa/qa/resource/events/project.rb
index 99c78254f42..8c97f66c663 100644
--- a/qa/qa/resource/events/project.rb
+++ b/qa/qa/resource/events/project.rb
@@ -6,6 +6,13 @@ module QA
module Project
include Events::Base
+ def wait_for_merge(title)
+ QA::Runtime::Logger.debug(%Q[#{self.class.name} - wait_for_merge with title "#{title}"])
+ wait_for_event do
+ events(action: 'accepted', target_type: 'merge_request').any? { |event| event[:target_title] == title }
+ end
+ end
+
def wait_for_push(commit_message)
QA::Runtime::Logger.debug(%Q[#{self.class.name} - wait_for_push with commit message "#{commit_message}"])
wait_for_event do
diff --git a/qa/qa/resource/file.rb b/qa/qa/resource/file.rb
index 76c4c71c48d..f573f3e89f0 100644
--- a/qa/qa/resource/file.rb
+++ b/qa/qa/resource/file.rb
@@ -27,11 +27,14 @@ module QA
Page::Project::Show.perform(&:create_first_new_file!)
- Page::File::Form.perform do |form|
- form.add_name(@name)
- form.add_content(@content)
- form.add_commit_message(@commit_message)
- form.commit_changes
+ Page::Project::WebIDE::Edit.perform do |ide|
+ ide.add_file(@name, @content)
+ ide.commit_changes(@commit_message)
+ ide.go_to_project
+ end
+
+ Page::Project::Show.perform do |project|
+ project.click_file(@name)
end
end
diff --git a/qa/qa/resource/merge_request.rb b/qa/qa/resource/merge_request.rb
index 6c0f4621dd9..dca8fb6dc6b 100644
--- a/qa/qa/resource/merge_request.rb
+++ b/qa/qa/resource/merge_request.rb
@@ -1,6 +1,7 @@
# frozen_string_literal: true
require 'securerandom'
+require 'active_support/core_ext/object/blank'
module QA
module Resource
@@ -17,7 +18,12 @@ module QA
:labels,
:file_name,
:file_content
- attr_writer :no_preparation
+ attr_writer :no_preparation,
+ :wait_for_merge
+
+ attribute :merge_when_pipeline_succeeds
+ attribute :merge_status
+ attribute :state
attribute :project do
Project.fabricate! do |resource|
@@ -58,6 +64,7 @@ module QA
@file_content = "File Added"
@target_new_branch = true
@no_preparation = false
+ @wait_for_merge = true
end
def fabricate!
@@ -80,10 +87,17 @@ module QA
end
def fabricate_via_api!
+ resource_web_url(api_get)
+ rescue ResourceNotFoundError
populate(:target, :source) unless @no_preparation
+
super
end
+ def api_merge_path
+ "/projects/#{project.id}/merge_requests/#{id}/merge"
+ end
+
def api_get_path
"/projects/#{project.id}/merge_requests/#{id}"
end
@@ -100,6 +114,36 @@ module QA
title: @title
}
end
+
+ def merge_via_api!
+ Support::Waiter.wait_until(sleep_interval: 1) do
+ QA::Runtime::Logger.debug("Waiting until merge request with id '#{id}' can be merged")
+
+ reload!.api_resource[:merge_status] == 'can_be_merged'
+ end
+
+ Support::Retrier.retry_on_exception do
+ response = put(Runtime::API::Request.new(api_client, api_merge_path).url)
+
+ unless response.code == HTTP_STATUS_OK
+ raise ResourceUpdateFailedError, "Could not merge. Request returned (#{response.code}): `#{response}`."
+ end
+
+ result = parse_body(response)
+
+ project.wait_for_merge(result[:title]) if @wait_for_merge
+
+ result
+ end
+ end
+
+ private
+
+ def transform_api_resource(api_resource)
+ raise ResourceNotFoundError if api_resource.blank?
+
+ super(api_resource)
+ end
end
end
end
diff --git a/qa/qa/resource/project.rb b/qa/qa/resource/project.rb
index 0025ebb2fd5..163c0b40bb5 100644
--- a/qa/qa/resource/project.rb
+++ b/qa/qa/resource/project.rb
@@ -110,6 +110,10 @@ module QA
response.any? { |file| file[:path] == file_path }
end
+ def has_branch?(branch)
+ has_branches?(Array(branch))
+ end
+
def has_branches?(branches)
branches.all? do |branch|
response = get(Runtime::API::Request.new(api_client, "#{api_repository_branches_path}/#{branch}").url)
@@ -140,6 +144,10 @@ module QA
"#{api_get_path}/members"
end
+ def api_merge_requests_path
+ "#{api_get_path}/merge_requests"
+ end
+
def api_runners_path
"#{api_get_path}/runners"
end
@@ -223,6 +231,14 @@ module QA
result[:import_status]
end
+ def merge_requests
+ parse_body(get(Runtime::API::Request.new(api_client, api_merge_requests_path).url))
+ end
+
+ def merge_request_with_title(title)
+ merge_requests.find { |mr| mr[:title] == title }
+ end
+
def runners(tag_list: nil)
response = if tag_list
get Runtime::API::Request.new(api_client, "#{api_runners_path}?tag_list=#{tag_list.compact.join(',')}").url
diff --git a/qa/qa/resource/project_snippet.rb b/qa/qa/resource/project_snippet.rb
index ce4be6445f1..6fa38baaa91 100644
--- a/qa/qa/resource/project_snippet.rb
+++ b/qa/qa/resource/project_snippet.rb
@@ -21,6 +21,13 @@ module QA
new_snippet.set_visibility(@visibility)
new_snippet.fill_file_name(@file_name)
new_snippet.fill_file_content(@file_content)
+
+ @files.each.with_index(2) do |file, i|
+ new_snippet.click_add_file
+ new_snippet.fill_file_name(file[:name], i)
+ new_snippet.fill_file_content(file[:content], i)
+ end
+
new_snippet.click_create_snippet_button
end
end
diff --git a/qa/qa/resource/repository/push.rb b/qa/qa/resource/repository/push.rb
index 1e5399fcc59..5266f8b9bea 100644
--- a/qa/qa/resource/repository/push.rb
+++ b/qa/qa/resource/repository/push.rb
@@ -11,7 +11,7 @@ module QA
:branch_name, :new_branch, :output, :repository_http_uri,
:repository_ssh_uri, :ssh_key, :user, :use_lfs, :tag_name
- attr_writer :remote_branch, :gpg_key_id
+ attr_writer :remote_branch, :gpg_key_id, :merge_request_push_options
def initialize
@file_name = "file-#{SecureRandom.hex(8)}.txt"
@@ -24,6 +24,7 @@ module QA
@use_lfs = false
@tag_name = nil
@gpg_key_id = nil
+ @merge_request_push_options = nil
end
def remote_branch
@@ -95,7 +96,7 @@ module QA
end
@output += commit_to repository
- @output += repository.push_changes("#{branch_name}:#{remote_branch}")
+ @output += repository.push_changes("#{branch_name}:#{remote_branch}", push_options: @merge_request_push_options)
end
repository.delete_ssh_key
diff --git a/qa/qa/resource/snippet.rb b/qa/qa/resource/snippet.rb
index 39be5e5cb7d..c4ea6447209 100644
--- a/qa/qa/resource/snippet.rb
+++ b/qa/qa/resource/snippet.rb
@@ -11,6 +11,11 @@ module QA
@visibility = 'Public'
@file_content = 'The snippet content'
@file_name = 'New snippet file name'
+ @files = []
+ end
+
+ def add_files
+ yield @files
end
def fabricate!
@@ -22,6 +27,12 @@ module QA
new_page.set_visibility(@visibility)
new_page.fill_file_name(@file_name)
new_page.fill_file_content(@file_content)
+
+ @files.each.with_index(2) do |file, i|
+ new_page.click_add_file
+ new_page.fill_file_name(file[:name], i)
+ new_page.fill_file_content(file[:content], i)
+ end
new_page.click_create_snippet_button
end
end
diff --git a/qa/qa/resource/ssh_key.rb b/qa/qa/resource/ssh_key.rb
index d4e394954ce..fcd0a479fec 100644
--- a/qa/qa/resource/ssh_key.rb
+++ b/qa/qa/resource/ssh_key.rb
@@ -76,6 +76,15 @@ module QA
parse_body(response)[:title].include?(title)
end
end
+
+ private
+
+ def api_get
+ with_paginated_response_body(Runtime::API::Request.new(api_client, '/user/keys', per_page: '100').url) do |page|
+ key = page.find { |key| key[:title] == title }
+ break process_api_response(key) if key
+ end
+ end
end
end
end
diff --git a/qa/qa/resource/user.rb b/qa/qa/resource/user.rb
index 9768fc154a7..5cd4147e154 100644
--- a/qa/qa/resource/user.rb
+++ b/qa/qa/resource/user.rb
@@ -11,6 +11,8 @@ module QA
attribute :id
attribute :name
+ attribute :first_name
+ attribute :last_name
attribute :email
def initialize
@@ -34,6 +36,14 @@ module QA
@name ||= api_resource&.dig(:name) || "QA User #{unique_id}"
end
+ def first_name
+ name.split(' ').first
+ end
+
+ def last_name
+ name.split(' ').drop(1).join(' ')
+ end
+
def email
@email ||= begin
api_email = api_resource&.dig(:email)
diff --git a/qa/qa/runtime/api/request.rb b/qa/qa/runtime/api/request.rb
index 724b499d32f..b58be354103 100644
--- a/qa/qa/runtime/api/request.rb
+++ b/qa/qa/runtime/api/request.rb
@@ -34,7 +34,11 @@ module QA
#
# Returns the relative path to the requested API resource
def request_path(path, version: API_VERSION, **query_string)
- full_path = ::File.join('/api', version, path)
+ full_path = if path == '/graphql'
+ ::File.join('/api', path)
+ else
+ ::File.join('/api', version, path)
+ end
if query_string.any?
full_path << (path.include?('?') ? '&' : '?')
diff --git a/qa/qa/runtime/env.rb b/qa/qa/runtime/env.rb
index c254be4800b..ddaf35a2d65 100644
--- a/qa/qa/runtime/env.rb
+++ b/qa/qa/runtime/env.rb
@@ -24,7 +24,7 @@ module QA
SUPPORTED_FEATURES
end
- def address_matches?(*options)
+ def context_matches?(*options)
return false unless Runtime::Scenario.attributes[:gitlab_address]
opts = {}
@@ -33,29 +33,38 @@ module QA
uri = URI(Runtime::Scenario.gitlab_address)
- if options.any?
- options.each do |option|
- opts[:domain] = 'gitlab' if option == :production
-
- if option.is_a?(Hash) && !option[:subdomain].nil?
- opts.merge!(option)
-
- opts[:subdomain] = case option[:subdomain]
- when Array
- "(#{option[:subdomain].join("|")})."
- when Regexp
- option[:subdomain]
- else
- "(#{option[:subdomain]})."
- end
- end
+ options.each do |option|
+ opts[:domain] = 'gitlab' if option == :production
+
+ if option.is_a?(Hash) && !option[:pipeline].nil? && !ci_project_name.nil?
+ return pipeline_matches?(option[:pipeline])
+
+ elsif option.is_a?(Hash) && !option[:subdomain].nil?
+ opts.merge!(option)
+
+ opts[:subdomain] = case option[:subdomain]
+ when Array
+ "(#{option[:subdomain].join("|")})."
+ when Regexp
+ option[:subdomain]
+ else
+ "(#{option[:subdomain]})."
+ end
end
end
uri.host.match?(/^#{opts[:subdomain]}#{opts[:domain]}#{opts[:tld]}$/)
end
- alias_method :dot_com?, :address_matches?
+ alias_method :dot_com?, :context_matches?
+
+ def pipeline_matches?(pipeline_to_run_in)
+ Array(pipeline_to_run_in).any? { |pipeline| pipeline.to_s.casecmp?(pipeline_from_project_name) }
+ end
+
+ def pipeline_from_project_name
+ ci_project_name.to_s.start_with?('gitlab-qa') ? 'master' : ci_project_name
+ end
def additional_repository_storage
ENV['QA_ADDITIONAL_REPOSITORY_STORAGE']
@@ -81,6 +90,10 @@ module QA
ENV['GITLAB_QA_ADMIN_ACCESS_TOKEN']
end
+ def ci_job_url
+ ENV['CI_JOB_URL']
+ end
+
def ci_project_name
ENV['CI_PROJECT_NAME']
end
diff --git a/qa/qa/runtime/feature.rb b/qa/qa/runtime/feature.rb
index 579c2293c51..a48bc216ac2 100644
--- a/qa/qa/runtime/feature.rb
+++ b/qa/qa/runtime/feature.rb
@@ -1,98 +1,125 @@
# frozen_string_literal: true
+require 'active_support/core_ext/object/blank'
+
module QA
module Runtime
- module Feature
- extend self
- extend Support::Api
+ class Feature
+ class << self
+ # Documentation: https://docs.gitlab.com/ee/api/features.html
- SetFeatureError = Class.new(RuntimeError)
- AuthorizationError = Class.new(RuntimeError)
+ include Support::Api
- def enable(key)
- QA::Runtime::Logger.info("Enabling feature: #{key}")
- set_feature(key, true)
- end
+ SetFeatureError = Class.new(RuntimeError)
+ AuthorizationError = Class.new(RuntimeError)
+ UnknownScopeError = Class.new(RuntimeError)
- def disable(key)
- QA::Runtime::Logger.info("Disabling feature: #{key}")
- set_feature(key, false)
- end
-
- def remove(key)
- request = Runtime::API::Request.new(api_client, "/features/#{key}")
- response = delete(request.url)
- unless response.code == QA::Support::Api::HTTP_STATUS_NO_CONTENT
- raise SetFeatureError, "Deleting feature flag #{key} failed with `#{response}`."
+ def remove(key)
+ request = Runtime::API::Request.new(api_client, "/features/#{key}")
+ response = delete(request.url)
+ unless response.code == QA::Support::Api::HTTP_STATUS_NO_CONTENT
+ raise SetFeatureError, "Deleting feature flag #{key} failed with `#{response}`."
+ end
end
- end
-
- def enable_and_verify(key)
- set_and_verify(key, enable: true)
- end
- def disable_and_verify(key)
- set_and_verify(key, enable: false)
- end
+ def enable(key, **scopes)
+ set_and_verify(key, enable: true, **scopes)
+ end
- def enabled?(key)
- feature = JSON.parse(get_features).find { |flag| flag["name"] == key }
- feature && feature["state"] == "on"
- end
+ def disable(key, **scopes)
+ set_and_verify(key, enable: false, **scopes)
+ end
- def get_features
- request = Runtime::API::Request.new(api_client, "/features")
- response = get(request.url)
- response.body
- end
+ def enabled?(key, **scopes)
+ feature = JSON.parse(get_features).find { |flag| flag['name'] == key.to_s }
+ feature && feature['state'] == 'on' || feature['state'] == 'conditional' && scopes.present? && enabled_scope?(feature['gates'], scopes)
+ end
- private
+ private
- def api_client
- @api_client ||= begin
- if Runtime::Env.admin_personal_access_token
- Runtime::API::Client.new(:gitlab, personal_access_token: Runtime::Env.admin_personal_access_token)
- else
- user = Resource::User.fabricate_via_api! do |user|
- user.username = Runtime::User.admin_username
- user.password = Runtime::User.admin_password
- end
+ def api_client
+ @api_client ||= Runtime::API::Client.as_admin
+ rescue Runtime::API::Client::AuthorizationError => e
+ raise AuthorizationError, "Administrator access is required to enable/disable feature flags. #{e.message}"
+ end
- unless user.admin?
- raise AuthorizationError, "Administrator access is required to enable/disable feature flags. User '#{user.username}' is not an administrator."
+ def enabled_scope?(gates, scopes)
+ scopes.each do |key, value|
+ case key
+ when :project, :group, :user
+ actors = gates.filter { |i| i['key'] == 'actors' }.first['value']
+ break actors.include?("#{key.to_s.capitalize}:#{value.id}")
+ when :feature_group
+ groups = gates.filter { |i| i['key'] == 'groups' }.first['value']
+ break groups.include?(value)
+ else
+ raise UnknownScopeError, "Unknown scope: #{key}"
end
-
- Runtime::API::Client.new(:gitlab, user: user)
end
end
- end
- # Change a feature flag and verify that the change was successful
- # Arguments:
- # key: The feature flag to set (as a string)
- # enable: `true` to enable the flag, `false` to disable it
- def set_and_verify(key, enable:)
- Support::Retrier.retry_on_exception(sleep_interval: 2) do
- enable ? enable(key) : disable(key)
+ def get_features
+ request = Runtime::API::Request.new(api_client, '/features')
+ response = get(request.url)
+ response.body
+ end
- is_enabled = nil
+ # Change a feature flag and verify that the change was successful
+ # Arguments:
+ # key: The feature flag to set (as a string)
+ # enable: `true` to enable the flag, `false` to disable it
+ # scopes: Any scope (user, project, group) to restrict the change to
+ def set_and_verify(key, enable:, **scopes)
+ msg = "#{enable ? 'En' : 'Dis'}abling feature: #{key}"
+ msg += " for scope \"#{scopes_to_s(scopes)}\"" if scopes.present?
+ QA::Runtime::Logger.info(msg)
- QA::Support::Waiter.wait_until(sleep_interval: 1) do
- is_enabled = enabled?(key)
- is_enabled == enable
- end
+ Support::Retrier.retry_on_exception(sleep_interval: 2) do
+ set_feature(key, enable, scopes)
+
+ is_enabled = nil
+
+ QA::Support::Waiter.wait_until(sleep_interval: 1) do
+ is_enabled = enabled?(key, scopes)
+ is_enabled == enable || !enable && scopes.present?
+ end
+
+ if is_enabled == enable
+ QA::Runtime::Logger.info("Successfully #{enable ? 'en' : 'dis'}abled and verified feature flag: #{key}")
+ else
+ raise SetFeatureError, "#{key} was not #{enable ? 'en' : 'dis'}abled!" if enable
- raise SetFeatureError, "#{key} was not #{enable ? 'enabled' : 'disabled'}!" unless is_enabled == enable
+ QA::Runtime::Logger.warn("Feature flag scope was removed but the flag is still enabled globally.")
+ end
+ end
+ end
- QA::Runtime::Logger.info("Successfully #{enable ? 'enabled' : 'disabled'} and verified feature flag: #{key}")
+ def set_feature(key, value, **scopes)
+ scopes[:project] = scopes[:project].full_path if scopes.key?(:project)
+ scopes[:group] = scopes[:group].full_path if scopes.key?(:group)
+ scopes[:user] = scopes[:user].username if scopes.key?(:user)
+ request = Runtime::API::Request.new(api_client, "/features/#{key}")
+ response = post(request.url, scopes.merge({ value: value }))
+ unless response.code == QA::Support::Api::HTTP_STATUS_CREATED
+ raise SetFeatureError, "Setting feature flag #{key} to #{value} failed with `#{response}`."
+ end
end
- end
- def set_feature(key, value)
- request = Runtime::API::Request.new(api_client, "/features/#{key}")
- response = post(request.url, { value: value })
- unless response.code == QA::Support::Api::HTTP_STATUS_CREATED
- raise SetFeatureError, "Setting feature flag #{key} to #{value} failed with `#{response}`."
+ def scopes_to_s(**scopes)
+ key = scopes.each_key.first
+ s = "#{key}: "
+ case key
+ when :project, :group
+ s += scopes[key].full_path
+ when :user
+ s += scopes[key].username
+ when :feature_group
+ s += scopes[key]
+ else
+ raise UnknownScopeError, "Unknown scope: #{key}"
+ end
+
+ s
end
end
end
diff --git a/qa/qa/service/praefect_manager.rb b/qa/qa/service/praefect_manager.rb
index fb2019394b4..3a17acbb317 100644
--- a/qa/qa/service/praefect_manager.rb
+++ b/qa/qa/service/praefect_manager.rb
@@ -387,7 +387,7 @@ module QA
end
def verify_storage_move_to_praefect(repo_path, virtual_storage)
- wait_until_shell_command("docker exec #{@gitlab} bash -c 'tail -n 50 /var/log/gitlab/praefect/current'") do |line|
+ wait_until_shell_command("docker exec #{@praefect} bash -c 'tail -n 50 /var/log/gitlab/praefect/current'") do |line|
log = JSON.parse(line)
log['grpc.method'] == 'ReplicateRepository' && log['virtual_storage'] == virtual_storage && log['relative_path'] == repo_path
diff --git a/qa/qa/specs/features/api/3_create/gitaly/automatic_failover_and_recovery_spec.rb b/qa/qa/specs/features/api/3_create/gitaly/automatic_failover_and_recovery_spec.rb
index aa06947e93b..90f58090ccd 100644
--- a/qa/qa/specs/features/api/3_create/gitaly/automatic_failover_and_recovery_spec.rb
+++ b/qa/qa/specs/features/api/3_create/gitaly/automatic_failover_and_recovery_spec.rb
@@ -22,7 +22,7 @@ module QA
end
end
- after(:context) do
+ after(:context, quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/238187', type: :stale }) do
# Leave the cluster in a suitable state for subsequent tests,
# if there was a problem during the tests here
praefect_manager.reset_primary_to_original
diff --git a/qa/qa/specs/features/api/3_create/gitaly/backend_node_recovery_spec.rb b/qa/qa/specs/features/api/3_create/gitaly/backend_node_recovery_spec.rb
index 4515e76539b..6654a35915f 100644
--- a/qa/qa/specs/features/api/3_create/gitaly/backend_node_recovery_spec.rb
+++ b/qa/qa/specs/features/api/3_create/gitaly/backend_node_recovery_spec.rb
@@ -3,7 +3,7 @@
module QA
RSpec.describe 'Create' do
context 'Gitaly' do
- describe 'Backend node recovery', :orchestrated, :gitaly_cluster, :skip_live_env do
+ describe 'Backend node recovery', :orchestrated, :gitaly_cluster, :skip_live_env, quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/238186', type: :investigating } do
let(:praefect_manager) { Service::PraefectManager.new }
let(:project) do
Resource::Project.fabricate! do |project|
@@ -22,7 +22,7 @@ module QA
praefect_manager.reset_primary_to_original
end
- it 'recovers from dataloss', quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/238186', type: :investigating }, testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/978' do
+ it 'recovers from dataloss', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/978' do
# Create a new project with a commit and wait for it to replicate
praefect_manager.wait_for_replication(project.id)
diff --git a/qa/qa/specs/features/api/3_create/gitaly/changing_repository_storage_spec.rb b/qa/qa/specs/features/api/3_create/gitaly/changing_repository_storage_spec.rb
index 758ba582929..e96b9ad9258 100644
--- a/qa/qa/specs/features/api/3_create/gitaly/changing_repository_storage_spec.rb
+++ b/qa/qa/specs/features/api/3_create/gitaly/changing_repository_storage_spec.rb
@@ -4,7 +4,6 @@ module QA
RSpec.describe 'Create' do
describe 'Changing Gitaly repository storage', :requires_admin do
praefect_manager = Service::PraefectManager.new
- praefect_manager.gitlab = 'gitlab'
shared_examples 'repository storage move' do
it 'confirms a `finished` status after moving project repository storage' do
@@ -28,7 +27,6 @@ module QA
context 'when moving from one Gitaly storage to another', :orchestrated, :repository_storage, testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/973' do
let(:source_storage) { { type: :gitaly, name: 'default' } }
let(:destination_storage) { { type: :gitaly, name: QA::Runtime::Env.additional_repository_storage } }
-
let(:project) do
Resource::Project.fabricate_via_api! do |project|
project.name = 'repo-storage-move-status'
@@ -37,6 +35,10 @@ module QA
end
end
+ before do
+ praefect_manager.gitlab = 'gitlab'
+ end
+
it_behaves_like 'repository storage move'
end
@@ -46,7 +48,6 @@ module QA
context 'when moving from Gitaly to Gitaly Cluster', :requires_praefect, testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/974' do
let(:source_storage) { { type: :gitaly, name: QA::Runtime::Env.non_cluster_repository_storage } }
let(:destination_storage) { { type: :praefect, name: QA::Runtime::Env.praefect_repository_storage } }
-
let(:project) do
Resource::Project.fabricate_via_api! do |project|
project.name = 'repo-storage-move'
@@ -56,6 +57,10 @@ module QA
end
end
+ before do
+ praefect_manager.gitlab = 'gitlab-gitaly-cluster'
+ end
+
it_behaves_like 'repository storage move'
end
end
diff --git a/qa/qa/specs/features/api/3_create/gitaly/distributed_reads_spec.rb b/qa/qa/specs/features/api/3_create/gitaly/distributed_reads_spec.rb
index 29f131ac322..c3cb503ed3f 100644
--- a/qa/qa/specs/features/api/3_create/gitaly/distributed_reads_spec.rb
+++ b/qa/qa/specs/features/api/3_create/gitaly/distributed_reads_spec.rb
@@ -17,12 +17,12 @@ module QA
end
before do
- Runtime::Feature.enable_and_verify('gitaly_distributed_reads')
+ Runtime::Feature.enable(:gitaly_distributed_reads)
praefect_manager.wait_for_replication(project.id)
end
after do
- Runtime::Feature.disable_and_verify('gitaly_distributed_reads')
+ Runtime::Feature.disable(:gitaly_distributed_reads)
end
it 'reads from each node', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/979' do
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
new file mode 100644
index 00000000000..82a06780830
--- /dev/null
+++ b/qa/qa/specs/features/api/3_create/merge_request/push_options_labels_spec.rb
@@ -0,0 +1,64 @@
+# frozen_string_literal: true
+
+module QA
+ RSpec.describe 'Create' do
+ describe 'Merge request push options' 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
+
+ branch = "push-options-test-#{SecureRandom.hex(8)}"
+ title = "MR push options test #{SecureRandom.hex(8)}"
+ commit_message = 'Add README.md'
+
+ project = Resource::Project.fabricate_via_api! do |project|
+ project.name = 'merge-request-push-options'
+ project.initialize_with_readme = true
+ end
+
+ it 'sets labels', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/1032' do
+ Resource::Repository::ProjectPush.fabricate! do |push|
+ push.project = project
+ push.commit_message = commit_message
+ push.branch_name = branch
+ push.merge_request_push_options = {
+ create: true,
+ title: title,
+ label: %w[one two three]
+ }
+ end
+
+ merge_request = project.merge_request_with_title(title)
+
+ expect(merge_request).not_to be_nil, "There was a problem creating the merge request"
+ expect(merge_request[:labels]).to include('one').and include('two').and include('three')
+ end
+
+ context 'when labels are set already' do
+ it 'removes them', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/1033' do
+ Resource::Repository::ProjectPush.fabricate! do |push|
+ push.project = project
+ push.file_content = "Unlabel test #{SecureRandom.hex(8)}"
+ push.commit_message = commit_message
+ push.branch_name = branch
+ push.new_branch = false
+ push.merge_request_push_options = {
+ title: title,
+ unlabel: %w[one three]
+ }
+ end
+
+ merge_request = project.merge_request_with_title(title)
+
+ expect(merge_request).not_to be_nil, "There was a problem creating the merge request"
+
+ aggregate_failures do
+ expect(merge_request[:labels]).to include('two')
+ expect(merge_request[:labels]).not_to include('one')
+ expect(merge_request[:labels]).not_to include('three')
+ end
+ end
+ end
+ end
+ end
+end
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
new file mode 100644
index 00000000000..dde4708874d
--- /dev/null
+++ b/qa/qa/specs/features/api/3_create/merge_request/push_options_mwps_spec.rb
@@ -0,0 +1,124 @@
+# frozen_string_literal: true
+
+module QA
+ RSpec.describe 'Create' do
+ describe 'Merge request push options' 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
+
+ let(:branch) { "push-options-test-#{SecureRandom.hex(8)}" }
+ let(:title) { "MR push options test #{SecureRandom.hex(8)}" }
+
+ let(:project) do
+ Resource::Project.fabricate_via_api! do |project|
+ project.name = 'merge-request-push-options'
+ project.initialize_with_readme = true
+ end
+ end
+
+ let!(:runner) do
+ Resource::Runner.fabricate! do |runner|
+ runner.project = project
+ runner.name = "runner-for-#{project.name}"
+ runner.tags = ["runner-for-#{project.name}"]
+ end
+ end
+
+ after do
+ runner.remove_via_api!
+ end
+
+ it 'sets merge when pipeline succeeds', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/1037' 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
+ no-op:
+ tags:
+ - "runner-for-#{project.name}"
+ script: sleep 999 # Leave the pipeline pending
+ YAML
+ }
+ ]
+ )
+ end
+
+ Resource::Repository::ProjectPush.fabricate! do |push|
+ push.project = project
+ push.branch_name = branch
+ push.merge_request_push_options = {
+ create: true,
+ merge_when_pipeline_succeeds: true,
+ title: title
+ }
+ end
+
+ merge_request = project.merge_request_with_title(title)
+
+ expect(merge_request).not_to be_nil, "There was a problem creating the merge request"
+
+ merge_request = Resource::MergeRequest.fabricate_via_api! do |mr|
+ mr.project = project
+ mr.id = merge_request[:iid]
+ end
+
+ expect(merge_request.state).to eq('opened')
+ expect(merge_request.merge_status).to eq('checking')
+ expect(merge_request.merge_when_pipeline_succeeds).to be true
+ end
+
+ it 'merges when pipeline succeeds', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/1036' 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
+ no-op:
+ tags:
+ - "runner-for-#{project.name}"
+ script: echo 'OK'
+ YAML
+ }
+ ]
+ )
+ end
+
+ Resource::Repository::ProjectPush.fabricate! do |push|
+ push.project = project
+ push.branch_name = branch
+ push.merge_request_push_options = {
+ create: true,
+ merge_when_pipeline_succeeds: true,
+ title: title
+ }
+ end
+
+ merge_request = project.merge_request_with_title(title)
+
+ expect(merge_request).not_to be_nil, "There was a problem creating the merge request"
+ expect(merge_request[:merge_when_pipeline_succeeds]).to be true
+
+ merge_request = Support::Waiter.wait_until(sleep_interval: 5) do
+ mr = Resource::MergeRequest.fabricate_via_api! do |mr|
+ mr.project = project
+ mr.id = merge_request[:iid]
+ end
+
+ next unless mr.state == 'merged'
+
+ mr
+ end
+
+ expect(merge_request.state).to eq('merged')
+ end
+ end
+ end
+end
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
new file mode 100644
index 00000000000..d6bd668fa8a
--- /dev/null
+++ b/qa/qa/specs/features/api/3_create/merge_request/push_options_remove_source_branch_spec.rb
@@ -0,0 +1,45 @@
+# frozen_string_literal: true
+
+module QA
+ RSpec.describe 'Create' do
+ describe 'Merge request push options' 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
+
+ let(:branch) { "push-options-test-#{SecureRandom.hex(8)}" }
+ let(:title) { "MR push options test #{SecureRandom.hex(8)}" }
+
+ let(:project) do
+ Resource::Project.fabricate_via_api! do |project|
+ project.name = 'merge-request-push-options'
+ project.initialize_with_readme = true
+ end
+ end
+
+ it 'removes the source branch', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/1035' do
+ Resource::Repository::ProjectPush.fabricate! do |push|
+ push.project = project
+ push.branch_name = branch
+ push.merge_request_push_options = {
+ create: true,
+ remove_source_branch: true,
+ title: title
+ }
+ end
+
+ merge_request = project.merge_request_with_title(title)
+
+ expect(merge_request).not_to be_nil, "There was a problem creating the merge request"
+
+ merge_request = Resource::MergeRequest.fabricate_via_api! do |mr|
+ mr.project = project
+ mr.id = merge_request[:iid]
+ end.merge_via_api!
+
+ expect(merge_request[:state]).to eq('merged')
+ expect(project).not_to have_branch(branch)
+ end
+ end
+ end
+end
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
new file mode 100644
index 00000000000..6072fd8c1a2
--- /dev/null
+++ b/qa/qa/specs/features/api/3_create/merge_request/push_options_target_branch_spec.rb
@@ -0,0 +1,53 @@
+# frozen_string_literal: true
+
+module QA
+ RSpec.describe 'Create' do
+ describe 'Merge request push options' 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
+
+ let(:title) { "MR push options test #{SecureRandom.hex(8)}" }
+
+ let(:project) do
+ Resource::Project.fabricate_via_api! do |project|
+ project.name = 'merge-request-push-options'
+ project.initialize_with_readme = true
+ end
+ end
+
+ it 'sets a target branch', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/1034' do
+ target_branch = "push-options-test-target-#{SecureRandom.hex(8)}"
+
+ Resource::Repository::ProjectPush.fabricate! do |push|
+ push.project = project
+ push.branch_name = target_branch
+ push.file_content = "Target branch test target branch #{SecureRandom.hex(8)}"
+ end
+
+ Resource::Repository::ProjectPush.fabricate! do |push|
+ push.project = project
+ push.branch_name = "push-options-test-#{SecureRandom.hex(8)}"
+ push.file_content = "Target branch test source branch #{SecureRandom.hex(8)}"
+ push.merge_request_push_options = {
+ create: true,
+ title: title,
+ target: target_branch
+ }
+ end
+
+ merge_request = project.merge_request_with_title(title)
+
+ expect(merge_request).not_to be_nil, "There was a problem creating the merge request"
+ expect(merge_request[:target_branch]).to eq(target_branch)
+
+ merge_request = Resource::MergeRequest.fabricate_via_api! do |mr|
+ mr.project = project
+ mr.id = merge_request[:iid]
+ end.merge_via_api!
+
+ expect(merge_request[:state]).to eq('merged')
+ end
+ end
+ end
+end
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
new file mode 100644
index 00000000000..f49a8a229dc
--- /dev/null
+++ b/qa/qa/specs/features/api/3_create/merge_request/push_options_title_description_spec.rb
@@ -0,0 +1,49 @@
+# frozen_string_literal: true
+
+module QA
+ RSpec.describe 'Create' do
+ describe 'Merge request push options' 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
+
+ let(:project) do
+ Resource::Project.fabricate_via_api! do |project|
+ project.name = 'merge-request-push-options'
+ project.initialize_with_readme = true
+ end
+ end
+
+ it 'sets title and description', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/1038' do
+ description = "This is a test of MR push options"
+ title = "MR push options test #{SecureRandom.hex(8)}"
+
+ Resource::Repository::ProjectPush.fabricate! do |push|
+ push.project = project
+ push.branch_name = "push-options-test-#{SecureRandom.hex(8)}"
+ push.merge_request_push_options = {
+ create: true,
+ title: title,
+ description: description
+ }
+ end
+
+ merge_request = project.merge_request_with_title(title)
+
+ expect(merge_request).not_to be_nil, "There was a problem creating the merge request"
+
+ aggregate_failures do
+ expect(merge_request[:title]).to eq(title)
+ expect(merge_request[:description]).to eq(description)
+ end
+
+ merge_request = Resource::MergeRequest.fabricate_via_api! do |mr|
+ mr.project = project
+ mr.id = merge_request[:iid]
+ end.merge_via_api!
+
+ expect(merge_request[:state]).to eq('merged')
+ end
+ end
+ end
+end
diff --git a/qa/qa/specs/features/api/3_create/repository/default_branch_name_setting_spec.rb b/qa/qa/specs/features/api/3_create/repository/default_branch_name_setting_spec.rb
index af155b22618..f86bbee05c2 100644
--- a/qa/qa/specs/features/api/3_create/repository/default_branch_name_setting_spec.rb
+++ b/qa/qa/specs/features/api/3_create/repository/default_branch_name_setting_spec.rb
@@ -13,7 +13,7 @@ module QA
Runtime::ApplicationSettings.restore_application_settings(:default_branch_name)
end
- it 'sets the default branch name for a new project' do
+ it 'sets the default branch name for a new project', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/1018' do
project = Resource::Project.fabricate_via_api! do |project|
project.name = "default-branch-name"
project.initialize_with_readme = true
@@ -32,7 +32,7 @@ module QA
end
end
- it 'allows a project to be created via the CLI with a different default branch name' do
+ it 'allows a project to be created via the CLI with a different default branch name', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/1019' do
project_name = "default-branch-name-via-cli-#{SecureRandom.hex(8)}"
group = Resource::Group.fabricate_via_api!
diff --git a/qa/qa/specs/features/api/3_create/repository/project_archive_compare_spec.rb b/qa/qa/specs/features/api/3_create/repository/project_archive_compare_spec.rb
index 4bd99b4820e..548933d2cde 100644
--- a/qa/qa/specs/features/api/3_create/repository/project_archive_compare_spec.rb
+++ b/qa/qa/specs/features/api/3_create/repository/project_archive_compare_spec.rb
@@ -28,6 +28,13 @@ module QA
end
end
+ after do
+ # Delete the .netrc file created during this test so that subsequent tests don't try to use the logins
+ Git::Repository.perform do |repository|
+ repository.delete_netrc
+ end
+ end
+
it 'download archives of each user project then check they are different', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/427' do
archive_checksums = {}
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
new file mode 100644
index 00000000000..e81ebd5fa9d
--- /dev/null
+++ b/qa/qa/specs/features/browser_ui/1_manage/login/2fa_ssh_recovery_spec.rb
@@ -0,0 +1,65 @@
+# frozen_string_literal: true
+
+module QA
+ context 'Manage', :requires_admin, :skip_live_env do
+ describe '2FA' do
+ let!(:user) { Resource::User.fabricate_via_api! }
+ let!(:user_api_client) { Runtime::API::Client.new(:gitlab, user: user) }
+ let(:address) { QA::Runtime::Scenario.gitlab_address }
+ let(:uri) { URI.parse(address) }
+ let(:ssh_port) { uri.port == 80 ? '' : '2222' }
+ let!(:ssh_key) do
+ Resource::SSHKey.fabricate_via_api! do |resource|
+ resource.title = "key for ssh tests #{Time.now.to_f}"
+ resource.api_client = user_api_client
+ end
+ end
+
+ before do
+ enable_2fa_for_user(user)
+ end
+
+ it 'allows 2FA code recovery via ssh' do
+ recovery_code = Support::SSH.perform do |ssh|
+ ssh.key = ssh_key
+ ssh.uri = address.gsub(uri.port.to_s, ssh_port)
+ ssh.setup
+ output = ssh.reset_2fa_codes
+ output.scan(/([A-Za-z0-9]{16})\n/).flatten.first
+ end
+
+ Flow::Login.sign_in(as: user, skip_page_validation: true)
+ Page::Main::TwoFactorAuth.perform do |two_fa_auth|
+ two_fa_auth.set_2fa_code(recovery_code)
+ two_fa_auth.click_verify_code_button
+ end
+
+ expect(Page::Main::Menu.perform(&:signed_in?)).to be_truthy
+
+ Page::Main::Menu.perform(&:sign_out)
+ Flow::Login.sign_in(as: user, skip_page_validation: true)
+ Page::Main::TwoFactorAuth.perform do |two_fa_auth|
+ two_fa_auth.set_2fa_code(recovery_code)
+ two_fa_auth.click_verify_code_button
+ end
+
+ expect(page).to have_text('Invalid two-factor code')
+ end
+
+ def enable_2fa_for_user(user)
+ Flow::Login.while_signed_in(as: user) do
+ Page::Main::Menu.perform(&:click_settings_link)
+ Page::Profile::Menu.perform(&:click_account)
+ Page::Profile::Accounts::Show.perform(&:click_enable_2fa_button)
+
+ Page::Profile::TwoFactorAuth.perform do |two_fa_auth|
+ otp = QA::Support::OTP.new(two_fa_auth.otp_secret_content)
+ two_fa_auth.set_pin_code(otp.fresh_otp)
+ two_fa_auth.click_register_2fa_app_button
+ two_fa_auth.click_proceed_button
+ end
+ end
+ end
+ end
+ end
+end
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 bd0d28c86be..e514507fcb6 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
@@ -18,7 +18,7 @@ module QA
QA::Resource::Group.fabricate_via_api! do |group|
group.sandbox = sandbox_group
group.api_client = owner_api_client
- group.name = 'group-with-2fa'
+ group.path = "group-with-2fa-#{SecureRandom.hex(8)}"
end
end
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 a10329d5936..863c394a9f9 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
@@ -41,7 +41,7 @@ module QA
context 'when using attachments in comments', :object_storage do
let(:gif_file_name) { 'banana_sample.gif' }
let(:file_to_attach) do
- File.absolute_path(File.join('spec', 'fixtures', gif_file_name))
+ File.absolute_path(File.join('qa', 'fixtures', 'designs', gif_file_name))
end
before do
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 b011978dce6..c908b1c46a1 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' do
+ RSpec.describe 'Plan', :reliable 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 5f7e28190b2..564cfbb8399 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' do
+ RSpec.describe 'Plan', :reliable 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 489691b4d0c..99d547acb26 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' do
+ RSpec.describe 'Plan', :reliable 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 a2190a8cf41..13761244300 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' do
+ RSpec.describe 'Plan', :reliable do
describe 'Related issues' do
let(:project) do
Resource::Project.fabricate_via_api! do |project|
diff --git a/qa/qa/specs/features/browser_ui/3_create/design_management/add_design_content_spec.rb b/qa/qa/specs/features/browser_ui/3_create/design_management/add_design_content_spec.rb
index ff2b4fa5364..051e8fcecbe 100644
--- a/qa/qa/specs/features/browser_ui/3_create/design_management/add_design_content_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/design_management/add_design_content_spec.rb
@@ -5,7 +5,7 @@ module QA
context 'Design Management' do
let(:issue) { Resource::Issue.fabricate_via_api! }
let(:design_filename) { 'banana_sample.gif' }
- let(:design) { File.absolute_path(File.join('spec', 'fixtures', design_filename)) }
+ let(:design) { File.absolute_path(File.join('qa', 'fixtures', 'designs', design_filename)) }
let(:annotation) { "This design is great!" }
before do
diff --git a/qa/qa/specs/features/browser_ui/3_create/design_management/archive_design_content_spec.rb b/qa/qa/specs/features/browser_ui/3_create/design_management/archive_design_content_spec.rb
new file mode 100644
index 00000000000..7090427e5a4
--- /dev/null
+++ b/qa/qa/specs/features/browser_ui/3_create/design_management/archive_design_content_spec.rb
@@ -0,0 +1,51 @@
+# frozen_string_literal: true
+
+module QA
+ RSpec.describe 'Create' do
+ context 'Design Management' do
+ let(:first_design) { Resource::Design.fabricate! }
+
+ let(:second_design) do
+ Resource::Design.fabricate! do |design|
+ design.issue = first_design.issue
+ design.filename = 'values.png'
+ end
+ end
+
+ let(:third_design) do
+ Resource::Design.fabricate! do |design|
+ design.issue = second_design.issue
+ design.filename = 'tanuki.jpg'
+ end
+ end
+
+ before do
+ Flow::Login.sign_in
+ end
+
+ it 'user archives a design', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/274' do
+ third_design.issue.visit!
+
+ Page::Project::Issue::Show.perform do |issue|
+ issue.select_design(third_design.filename)
+
+ issue.archive_selected_designs
+
+ expect(issue).not_to have_design(third_design.filename)
+ expect(issue).to have_design(first_design.filename)
+ expect(issue).to have_design(second_design.filename)
+ end
+
+ Page::Project::Issue::Show.perform do |issue|
+ issue.select_design(second_design.filename)
+ issue.select_design(first_design.filename)
+
+ issue.archive_selected_designs
+
+ expect(issue).not_to have_design(first_design.filename)
+ expect(issue).not_to have_design(second_design.filename)
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/specs/features/browser_ui/3_create/design_management/modify_design_content_spec.rb b/qa/qa/specs/features/browser_ui/3_create/design_management/modify_design_content_spec.rb
new file mode 100644
index 00000000000..135063b6644
--- /dev/null
+++ b/qa/qa/specs/features/browser_ui/3_create/design_management/modify_design_content_spec.rb
@@ -0,0 +1,30 @@
+# frozen_string_literal: true
+
+module QA
+ RSpec.describe 'Create' do
+ context 'Design Management' do
+ let(:design) do
+ Resource::Design.fabricate! do |design|
+ design.filename = 'tanuki.jpg'
+ end
+ end
+
+ before do
+ Flow::Login.sign_in
+ end
+
+ it 'user adds a design and modifies it', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/273' do
+ design.issue.visit!
+
+ Page::Project::Issue::Show.perform do |issue|
+ expect(issue).to have_created_icon
+ end
+
+ Page::Project::Issue::Show.perform do |issue|
+ issue.update_design(design.filename)
+ expect(issue).to have_modified_icon
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/specs/features/browser_ui/3_create/merge_request/view_merge_request_merge_ref_diff_spec.rb b/qa/qa/specs/features/browser_ui/3_create/merge_request/view_merge_request_merge_ref_diff_spec.rb
new file mode 100644
index 00000000000..7844d0d7ccb
--- /dev/null
+++ b/qa/qa/specs/features/browser_ui/3_create/merge_request/view_merge_request_merge_ref_diff_spec.rb
@@ -0,0 +1,80 @@
+# frozen_string_literal: true
+
+module QA
+ RSpec.describe 'Create', :requires_admin do
+ describe 'View merge request merge-ref diff' do
+ let(:merge_request) do
+ Resource::MergeRequest.fabricate_via_api! do |merge_request|
+ merge_request.title = 'This is a merge request'
+ merge_request.description = '... for viewing merge-ref and merge-base diffs'
+ merge_request.file_content = 'This exists on the source branch only'
+ end
+ end
+
+ let(:new_file_name) { "added_file-#{SecureRandom.hex(8)}.txt" }
+
+ before do
+ commit_to_branch(merge_request.target_branch, new_file_name)
+ commit_to_branch(merge_request.source_branch, new_file_name)
+
+ Flow::Login.sign_in
+ end
+
+ context 'when the feature flag default_merge_ref_for_diffs is enabled' do
+ before do
+ Runtime::Feature.enable('default_merge_ref_for_diffs', project: merge_request.project)
+
+ merge_request.visit!
+ end
+
+ it 'views the merge-ref diff by default' do
+ Page::MergeRequest::Show.perform do |mr_page|
+ mr_page.click_diffs_tab
+ mr_page.click_target_version_dropdown
+
+ expect(mr_page.version_dropdown_content).to include('master (HEAD)')
+ expect(mr_page.version_dropdown_content).not_to include('master (base)')
+ expect(mr_page).to have_file(merge_request.file_name)
+ expect(mr_page).not_to have_file(new_file_name)
+ end
+ end
+ end
+
+ context 'when the feature flag default_merge_ref_for_diffs is disabled' do
+ before do
+ Runtime::Feature.disable('default_merge_ref_for_diffs', project: merge_request.project)
+
+ merge_request.visit!
+ end
+
+ it 'views the merge-base diff by default' do
+ Page::MergeRequest::Show.perform do |mr_page|
+ mr_page.click_diffs_tab
+ mr_page.click_target_version_dropdown
+
+ expect(mr_page.version_dropdown_content).to include('master (HEAD)')
+ expect(mr_page.version_dropdown_content).to include('master (base)')
+ expect(mr_page).to have_file(merge_request.file_name)
+ expect(mr_page).to have_file(new_file_name)
+ end
+ end
+ end
+
+ def commit_to_branch(branch, file)
+ Resource::Repository::Commit.fabricate_via_api! do |commit|
+ commit.project = merge_request.project
+ commit.branch = branch
+ commit.commit_message = "Add new file on #{branch}"
+ commit.add_files(
+ [
+ {
+ file_path: file,
+ content: "This exists on source and target branches"
+ }
+ ]
+ )
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/create_edit_delete_file_via_web_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/create_edit_delete_file_via_web_spec.rb
index 43f4b080c73..5aa5f0fc0a3 100644
--- a/qa/qa/specs/features/browser_ui/3_create/repository/create_edit_delete_file_via_web_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/repository/create_edit_delete_file_via_web_spec.rb
@@ -18,7 +18,6 @@ module QA
file.commit_message = commit_message_for_create
end
- expect(page).to have_content('The file has been successfully created.')
expect(page).to have_content(file_name)
expect(page).to have_content(file_content)
expect(page).to have_content(commit_message_for_create)
diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/protocol_v2_push_http_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/protocol_v2_push_http_spec.rb
index 8ac7285d70c..5781bf8a7f0 100644
--- a/qa/qa/specs/features/browser_ui/3_create/repository/protocol_v2_push_http_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/repository/protocol_v2_push_http_spec.rb
@@ -37,8 +37,10 @@ module QA
project.wait_for_push_new_branch
# Check that the push worked
- expect(page).to have_content(file_name)
- expect(page).to have_content(file_content)
+ Page::Project::Show.perform do |project_page|
+ expect(project_page).to have_file(file_name)
+ expect(project_page).to have_readme_content(file_content)
+ end
# And check that the correct Git protocol was used
expect(git_protocol_reported).to eq(git_protocol)
diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/push_mirroring_lfs_over_http_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/push_mirroring_lfs_over_http_spec.rb
index f96b424d233..45afa252305 100644
--- a/qa/qa/specs/features/browser_ui/3_create/repository/push_mirroring_lfs_over_http_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/repository/push_mirroring_lfs_over_http_spec.rb
@@ -4,7 +4,6 @@ module QA
RSpec.describe 'Create' do
describe 'Push mirror a repository over HTTP' do
it 'configures and syncs LFS objects for a (push) mirrored repository', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/414' do
- Runtime::Feature.enable_and_verify('push_mirror_syncs_lfs')
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.perform(&:sign_in_using_credentials)
@@ -37,8 +36,10 @@ module QA
# Check that the target project has the commit from the source
target_project.visit!
- expect(page).to have_content('README.md')
- expect(page).to have_content('The rendered file could not be displayed because it is stored in LFS')
+ Page::Project::Show.perform do |project_page|
+ expect(project_page).to have_file('README.md')
+ expect(project_page).to have_readme_content('The rendered file could not be displayed because it is stored in LFS')
+ end
end
end
end
diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/push_over_http_file_size_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/push_over_http_file_size_spec.rb
index 2ebab7d2a30..222eb3771ad 100644
--- a/qa/qa/specs/features/browser_ui/3_create/repository/push_over_http_file_size_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/repository/push_over_http_file_size_spec.rb
@@ -41,7 +41,7 @@ module QA
retry_on_fail do
expect { push_new_file('oversize_file_2.bin', wait_for_push: false) }
- .to raise_error(QA::Git::Repository::RepositoryCommandError, /remote: fatal: pack exceeds maximum allowed size/)
+ .to raise_error(QA::Support::Run::CommandError, /remote: fatal: pack exceeds maximum allowed size/)
end
end
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 8b6973e6cea..cf14017b7f1 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
@@ -36,8 +36,10 @@ module QA
project.visit!
- expect(page).to have_content('README.md')
- expect(page).to have_content("This is a test project named #{project.name}")
+ Page::Project::Show.perform do |project_page|
+ expect(project_page).to have_file('README.md')
+ expect(project_page).to have_readme_content("This is a test project named #{project.name}")
+ end
end
end
end
diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/push_protected_branch_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/push_protected_branch_spec.rb
index d20abd658c6..54d00209cc7 100644
--- a/qa/qa/specs/features/browser_ui/3_create/repository/push_protected_branch_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/repository/push_protected_branch_spec.rb
@@ -35,7 +35,7 @@ module QA
roles: Resource::ProtectedBranch::Roles::NO_ONE
})
- expect { push_new_file(branch_name) }.to raise_error(QA::Git::Repository::RepositoryCommandError, /remote: GitLab: You are not allowed to push code to protected branches on this project\.([\s\S]+)\[remote rejected\] #{branch_name} -> #{branch_name} \(pre-receive hook declined\)/)
+ expect { push_new_file(branch_name) }.to raise_error(QA::Support::Run::CommandError, /remote: GitLab: You are not allowed to push code to protected branches on this project\.([\s\S]+)\[remote rejected\] #{branch_name} -> #{branch_name} \(pre-receive hook declined\)/)
end
end
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 ef3b315506f..a3f6d521766 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
@@ -36,6 +36,10 @@ module QA
Flow::Login.sign_in
end
+ after do
+ ssh_key.remove_via_api!
+ end
+
it 'clones, pushes, and pulls a snippet over HTTP, edits via UI', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/826' do
Resource::Repository::Push.fabricate! do |push|
push.repository_http_uri = repository_uri_http
@@ -87,7 +91,7 @@ module QA
repository.init_repository
expect { repository.pull(repository_uri_ssh, branch_name) }
- .to raise_error(QA::Git::Repository::RepositoryCommandError, /fatal: Could not read from remote repository\./)
+ .to raise_error(QA::Support::Run::CommandError, /fatal: Could not read from remote repository\./)
end
end
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 34f6b464f29..be56b870490 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
@@ -36,6 +36,10 @@ module QA
Flow::Login.sign_in
end
+ after do
+ ssh_key.remove_via_api!
+ end
+
it 'clones, pushes, and pulls a project snippet over HTTP, edits via UI', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/833' do
Resource::Repository::Push.fabricate! do |push|
push.repository_http_uri = repository_uri_http
@@ -86,7 +90,7 @@ module QA
repository.init_repository
expect { repository.pull(repository_uri_ssh, branch_name) }
- .to raise_error(QA::Git::Repository::RepositoryCommandError, /fatal: Could not read from remote repository\./)
+ .to raise_error(QA::Support::Run::CommandError, /fatal: Could not read from remote repository\./)
end
end
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
new file mode 100644
index 00000000000..50f2f4789fa
--- /dev/null
+++ b/qa/qa/specs/features/browser_ui/3_create/snippet/create_personal_snippet_with_multiple_files_spec.rb
@@ -0,0 +1,40 @@
+# frozen_string_literal: true
+
+module QA
+ RSpec.describe 'Create' do
+ describe 'Multiple file snippet' do
+ it 'creates a personal snippet with multiple files', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/842' do
+ Flow::Login.sign_in
+
+ Page::Main::Menu.perform do |menu|
+ menu.go_to_more_dropdown_option(:snippets_link)
+ end
+
+ Resource::Snippet.fabricate_via_browser_ui! do |snippet|
+ snippet.title = 'Personal snippet with multiple files'
+ snippet.description = 'Snippet description'
+ snippet.visibility = 'Public'
+ snippet.file_name = 'First file name'
+ snippet.file_content = 'First file content'
+
+ snippet.add_files do |files|
+ files.append(name: 'Second file name', content: 'Second file content')
+ files.append(name: 'Third file name', content: 'Third file content')
+ end
+ end
+
+ Page::Dashboard::Snippet::Show.perform do |snippet|
+ expect(snippet).to have_snippet_title('Personal snippet with multiple files')
+ expect(snippet).to have_snippet_description('Snippet description')
+ expect(snippet).to have_visibility_type(/public/i)
+ expect(snippet).to have_file_name('First file name', 1)
+ expect(snippet).to have_file_content('First file content', 1)
+ expect(snippet).to have_file_name('Second file name', 2)
+ expect(snippet).to have_file_content('Second file content', 2)
+ expect(snippet).to have_file_name('Third file name', 3)
+ expect(snippet).to have_file_content('Third file content', 3)
+ end
+ end
+ end
+ end
+end
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 0a8f6e13b2e..d80fc4c5b95 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
@@ -21,8 +21,8 @@ module QA
expect(snippet).to have_file_name('markdown_file.md')
expect(snippet).to have_file_content('Snippet heading')
expect(snippet).to have_file_content('Gitlab link')
- expect(snippet).not_to have_file_content('###')
- expect(snippet).not_to have_file_content('https://gitlab.com/')
+ expect(snippet).to have_no_file_content('###')
+ expect(snippet).to have_no_file_content('https://gitlab.com/')
end
end
end
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
new file mode 100644
index 00000000000..7b4ec573f53
--- /dev/null
+++ b/qa/qa/specs/features/browser_ui/3_create/snippet/create_project_snippet_with_multiple_files_spec.rb
@@ -0,0 +1,50 @@
+# frozen_string_literal: true
+
+module QA
+ RSpec.describe 'Create' do
+ describe 'Multiple file snippet' do
+ it 'creates a project snippet with multiple files', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/1024' do
+ Flow::Login.sign_in
+
+ Resource::ProjectSnippet.fabricate_via_browser_ui! do |snippet|
+ snippet.title = 'Project snippet with multiple files'
+ snippet.description = 'Snippet description'
+ snippet.visibility = 'Private'
+ snippet.file_name = '01 file name'
+ snippet.file_content = '1 file content'
+
+ # Ten is the limit of files you can have under one snippet at the moment
+ snippet.add_files do |files|
+ (2..10).each do |i|
+ files.append(name: file_name(i), content: file_content(i))
+ end
+ end
+ end
+
+ Page::Dashboard::Snippet::Show.perform do |snippet|
+ aggregate_failures 'file content verification' do
+ expect(snippet).to have_snippet_title('Project snippet with multiple files')
+ expect(snippet).to have_snippet_description('Snippet description')
+ expect(snippet).to have_visibility_type(/private/i)
+
+ (1..10).each do |i|
+ expect(snippet).to have_file_name(file_name(i), i)
+ expect(snippet).to have_file_content(file_content(i), i)
+ end
+ end
+ end
+ end
+
+ # Currently the files are returned in alphabetical order and not in the order they are created.
+ # However, it might soon change - see https://gitlab.com/gitlab-org/gitlab/-/issues/250836.
+ # By using a leading "0" we make sure the test works with either implementation.
+ def file_name(index)
+ "#{index.to_s.rjust(2, '0')} file name"
+ end
+
+ def file_content(index)
+ "#{index} file content"
+ end
+ end
+ end
+end
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 ea821f8b3e6..f7a2e3081fb 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
@@ -10,7 +10,6 @@ module QA
end
end
- let(:web_ide_url) { current_url + '-/ide/project/' + project.path_with_namespace }
let(:file_name) { 'the very first file.txt' }
before do
@@ -18,10 +17,8 @@ module QA
end
it "creates the first file in an empty project via Web IDE", testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/847' do
- # In the first iteration, the test opens Web IDE by modifying the URL to address past regressions.
- # Once the Web IDE button is introduced for empty projects, the test will be modified to go through UI.
- # See https://gitlab.com/gitlab-org/gitlab/-/issues/27915 and https://gitlab.com/gitlab-org/gitlab/-/issues/27535.
- page.visit(web_ide_url)
+ project.visit!
+ Page::Project::Show.perform(&:create_first_new_file!)
Page::Project::WebIDE::Edit.perform do |ide|
ide.create_first_file(file_name)
diff --git a/qa/qa/specs/features/browser_ui/3_create/wiki/project_based_directory_management_spec.rb b/qa/qa/specs/features/browser_ui/3_create/wiki/project_based_directory_management_spec.rb
index e8053600930..4f1d9ac1696 100644
--- a/qa/qa/specs/features/browser_ui/3_create/wiki/project_based_directory_management_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/wiki/project_based_directory_management_spec.rb
@@ -4,7 +4,7 @@ module QA
RSpec.describe 'Create' do
context 'Wiki' do
let(:initial_wiki) { Resource::Wiki::ProjectPage.fabricate_via_api! }
- let(:new_path) { "a/new/path" }
+ let(:new_path) { "a/new/path-with-spaces" }
before do
Flow::Login.sign_in
@@ -23,7 +23,9 @@ module QA
Page::Project::Wiki::Edit.perform(&:click_save_changes)
Page::Project::Wiki::Show.perform do |wiki|
- expect(wiki).to have_directory(new_path)
+ expect(wiki).to have_directory('a')
+ expect(wiki).to have_directory('new')
+ expect(wiki).to have_directory('path with spaces')
end
end
end
diff --git a/qa/qa/specs/features/browser_ui/4_verify/ci_variable/add_remove_ci_variable_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/ci_variable/add_remove_ci_variable_spec.rb
index cc4d0e1f6b5..ccd4d34a916 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
@@ -3,7 +3,7 @@
module QA
RSpec.describe 'Verify' do
describe 'Add or Remove CI variable via UI', :smoke do
- let!(:project) do
+ let(:project) do
Resource::Project.fabricate_via_api! do |project|
project.name = 'project-with-ci-variables'
project.description = 'project with CI variables'
@@ -12,31 +12,27 @@ module QA
before do
Flow::Login.sign_in
+ project.visit!
add_ci_variable
- open_ci_cd_settings
end
it 'user adds a CI variable', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/395' do
- Page::Project::Settings::CICD.perform do |settings|
- settings.expand_ci_variables do |page|
- expect(page).to have_text('VARIABLE_KEY')
- expect(page).not_to have_text('some_CI_variable')
+ Page::Project::Settings::CiVariables.perform do |ci_variable|
+ expect(ci_variable).to have_text('VARIABLE_KEY')
+ expect(ci_variable).to have_no_text('some_CI_variable')
- page.click_reveal_ci_variable_value_button
+ ci_variable.click_reveal_ci_variable_value_button
- expect(page).to have_text('some_CI_variable')
- end
+ expect(ci_variable).to have_text('some_CI_variable')
end
end
it 'user removes a CI variable', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/394' do
- Page::Project::Settings::CICD.perform do |settings|
- settings.expand_ci_variables do |page|
- page.click_edit_ci_variable
- page.click_ci_variable_delete_button
+ Page::Project::Settings::CiVariables.perform do |ci_variable|
+ ci_variable.click_edit_ci_variable
+ ci_variable.click_ci_variable_delete_button
- expect(page).not_to have_text('VARIABLE_KEY')
- end
+ expect(ci_variable).to have_text('There are no variables yet', wait: 60)
end
end
@@ -50,11 +46,6 @@ module QA
ci_variable.masked = false
end
end
-
- def open_ci_cd_settings
- project.visit!
- Page::Project::Menu.perform(&:go_to_ci_cd_settings)
- end
end
end
end
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 326647b25f7..8de739f1559 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', :docker, :runner do
+ RSpec.describe 'Verify', :runner do
describe 'Pipeline creation and processing' do
let(:executor) { "qa-runner-#{Time.now.to_i}" }
let(:max_wait) { 30 }
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
new file mode 100644
index 00000000000..153ccafaa20
--- /dev/null
+++ b/qa/qa/specs/features/browser_ui/4_verify/pipeline/run_pipeline_via_web_only_spec.rb
@@ -0,0 +1,65 @@
+# frozen_string_literal: true
+
+module QA
+ RSpec.describe 'Verify' do
+ describe 'Run pipeline', :requires_admin, :skip_live_env do
+ # [TODO]: Developer to remove :requires_admin and :skip_live_env once FF is removed in https://gitlab.com/gitlab-org/gitlab/-/issues/229632
+
+ context 'with web only rule' do
+ let(:feature_flag) { :new_pipeline_form }
+ let(:job_name) { 'test_job' }
+ let(:project) do
+ Resource::Project.fabricate_via_api! do |project|
+ project.name = 'web-only-pipeline'
+ end
+ end
+
+ let!(: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
+ #{job_name}:
+ tags:
+ - #{project.name}
+ script: echo 'OK'
+ only:
+ - web
+ YAML
+ }
+ ]
+ )
+ end
+ end
+
+ before do
+ Runtime::Feature.enable(feature_flag) # [TODO]: Developer to remove when feature flag is removed
+ Flow::Login.sign_in
+ project.visit!
+ Page::Project::Menu.perform(&:click_ci_cd_pipelines)
+ end
+
+ after do
+ Runtime::Feature.disable(feature_flag) # [TODO]: Developer to remove when feature flag is removed
+ end
+
+ it 'can trigger pipeline', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/946' do
+ Page::Project::Pipeline::Index.perform do |index|
+ expect(index).not_to have_pipeline # should not auto trigger pipeline
+ index.click_run_pipeline_button
+ end
+
+ Page::Project::Pipeline::New.perform(&:click_run_pipeline_button)
+
+ Page::Project::Pipeline::Show.perform do |pipeline|
+ expect(pipeline).to have_job(job_name)
+ end
+ end
+ end
+ end
+ end
+end
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
new file mode 100644
index 00000000000..39d5fbaba6b
--- /dev/null
+++ b/qa/qa/specs/features/browser_ui/4_verify/pipeline/trigger_child_pipeline_with_manual_spec.rb
@@ -0,0 +1,109 @@
+# frozen_string_literal: true
+
+require 'faker'
+
+module QA
+ RSpec.describe 'Verify', :runner, :requires_admin do
+ # [TODO]: Developer to remove :requires_admin once FF is removed in follow up issue
+
+ describe "Trigger child pipeline with 'when:manual'" do
+ let(:feature_flag) { :ci_manual_bridges } # [TODO]: Developer to remove when feature flag is removed
+ let(:executor) { "qa-runner-#{Faker::Alphanumeric.alphanumeric(8)}" }
+
+ let(:project) do
+ Resource::Project.fabricate_via_api! do |project|
+ project.name = 'project-with-pipeline'
+ end
+ end
+
+ let!(:runner) do
+ Resource::Runner.fabricate! do |runner|
+ runner.project = project
+ runner.name = executor
+ runner.tags = [executor]
+ end
+ end
+
+ before do
+ Runtime::Feature.enable(feature_flag) # [TODO]: Developer to remove when feature flag is removed
+ Flow::Login.sign_in
+ add_ci_files
+ project.visit!
+ view_the_last_pipeline
+ end
+
+ after do
+ Runtime::Feature.disable(feature_flag) # [TODO]: Developer to remove when feature flag is removed
+ runner.remove_via_api!
+ end
+
+ it 'can trigger bridge job', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/1049' do
+ Page::Project::Pipeline::Show.perform do |parent_pipeline|
+ expect(parent_pipeline).not_to have_child_pipeline
+
+ parent_pipeline.click_job_action('trigger')
+ Support::Waiter.wait_until { parent_pipeline.has_child_pipeline? }
+ parent_pipeline.expand_child_pipeline
+
+ expect(parent_pipeline).to have_build('child_build', status: nil)
+ end
+ end
+
+ private
+
+ def add_ci_files
+ Resource::Repository::Commit.fabricate_via_api! do |commit|
+ commit.project = project
+ commit.commit_message = 'Add parent and child pipelines CI files.'
+ commit.add_files(
+ [
+ child_ci_file,
+ parent_ci_file
+ ]
+ )
+ end
+ end
+
+ def view_the_last_pipeline
+ Page::Project::Menu.perform(&:click_ci_cd_pipelines)
+ Page::Project::Pipeline::Index.perform(&:wait_for_latest_pipeline_success)
+ Page::Project::Pipeline::Index.perform(&:click_on_latest_pipeline)
+ end
+
+ def parent_ci_file
+ {
+ file_path: '.gitlab-ci.yml',
+ content: <<~YAML
+ build:
+ stage: build
+ tags: ["#{executor}"]
+ script: echo build
+
+ trigger:
+ stage: test
+ when: manual
+ trigger:
+ include: '.child-pipeline.yml'
+
+ deploy:
+ stage: deploy
+ tags: ["#{executor}"]
+ script: echo deploy
+ YAML
+ }
+ end
+
+ def child_ci_file
+ {
+ file_path: '.child-pipeline.yml',
+ content: <<~YAML
+ child_build:
+ stage: build
+ tags: ["#{executor}"]
+ script: echo build
+ YAML
+ }
+ end
+ end
+ end
+end
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 a296d60b27c..9ce87f353d0 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', :docker, :runner do
+ RSpec.describe 'Verify', :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/view_code_coverage_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/testing/view_code_coverage_spec.rb
index f4edaaa84a8..5bfc88e45f2 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', :docker, :runner do
+ RSpec.describe 'Verify', :runner do
describe 'Code coverage statistics' do
let(:simplecov) { '\(\d+.\d+\%\) covered' }
let(:executor) { "qa-runner-#{Time.now.to_i}" }
diff --git a/qa/qa/specs/features/browser_ui/5_package/maven_repository_spec.rb b/qa/qa/specs/features/browser_ui/5_package/maven_repository_spec.rb
index a617f3b3e29..4ca356c9b65 100644
--- a/qa/qa/specs/features/browser_ui/5_package/maven_repository_spec.rb
+++ b/qa/qa/specs/features/browser_ui/5_package/maven_repository_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Package', :docker, :orchestrated, :packages do
+ RSpec.describe 'Package', :orchestrated, :packages do
describe 'Maven Repository' do
include Runtime::Fixtures
diff --git a/qa/qa/specs/features/browser_ui/5_package/npm_registry_spec.rb b/qa/qa/specs/features/browser_ui/5_package/npm_registry_spec.rb
index e97ede35610..817e146adfe 100644
--- a/qa/qa/specs/features/browser_ui/5_package/npm_registry_spec.rb
+++ b/qa/qa/specs/features/browser_ui/5_package/npm_registry_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Package', :docker, :orchestrated, :packages do
+ RSpec.describe 'Package', :orchestrated, :packages do
describe 'NPM registry' do
include Runtime::Fixtures
@@ -21,7 +21,7 @@ module QA
end
end
- it 'publishes an npm package and then deletes it', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/944', quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/247281', type: :investigating } do
+ it 'publishes an npm package and then deletes it', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/944' do
uri = URI.parse(Runtime::Scenario.gitlab_address)
gitlab_host_with_port = "#{uri.host}:#{uri.port}"
gitlab_address_with_port = "#{uri.scheme}://#{uri.host}:#{uri.port}"
@@ -68,7 +68,7 @@ module QA
end
Page::Project::Packages::Index.perform do |index|
- expect(index).to have_content("Package was removed")
+ expect(index).to have_content("Package deleted successfully")
expect(index).to have_no_package(package_name)
end
end
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 18eb52830a2..abac4f2b91d 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', :docker, :runner do
+ RSpec.describe 'Release', :runner do
describe 'Git clone using a deploy key' do
before do
Flow::Login.sign_in
diff --git a/qa/qa/specs/features/browser_ui/6_release/pipeline/parent_child_pipelines_dependent_relationship_spec.rb b/qa/qa/specs/features/browser_ui/6_release/pipeline/parent_child_pipelines_dependent_relationship_spec.rb
index 47a1b3b5670..ece45d093a7 100644
--- a/qa/qa/specs/features/browser_ui/6_release/pipeline/parent_child_pipelines_dependent_relationship_spec.rb
+++ b/qa/qa/specs/features/browser_ui/6_release/pipeline/parent_child_pipelines_dependent_relationship_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Release', :docker, :runner, :reliable do
+ RSpec.describe 'Release', :runner, :reliable do
describe 'Parent-child pipelines dependent relationship' do
let!(:project) do
Resource::Project.fabricate_via_api! do |project|
diff --git a/qa/qa/specs/features/browser_ui/6_release/pipeline/parent_child_pipelines_independent_relationship_spec.rb b/qa/qa/specs/features/browser_ui/6_release/pipeline/parent_child_pipelines_independent_relationship_spec.rb
index 9eb81244aa4..38cee0e62ca 100644
--- a/qa/qa/specs/features/browser_ui/6_release/pipeline/parent_child_pipelines_independent_relationship_spec.rb
+++ b/qa/qa/specs/features/browser_ui/6_release/pipeline/parent_child_pipelines_independent_relationship_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Release', :docker, :runner, :reliable do
+ RSpec.describe 'Release', :runner, :reliable 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/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 53a1c8010af..6d31780f196 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
@@ -15,7 +15,7 @@ module QA
disable_optional_jobs(project)
end
- describe 'Auto DevOps support', :orchestrated, :kubernetes, quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/230927', type: :stale } do
+ describe 'Auto DevOps support', :orchestrated, :kubernetes, quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/251090', type: :stale } do
context 'when rbac is enabled' do
let(:cluster) { Service::KubernetesCluster.new.create! }
@@ -24,6 +24,8 @@ module QA
end
it 'runs auto devops', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/702' do
+ skip('Test requires tunnel: see https://gitlab.com/gitlab-org/gitlab/-/issues/251090')
+
Flow::Login.sign_in
# Set an application secret CI variable (prefixed with K8S_SECRET_)
diff --git a/qa/qa/specs/features/sanity/framework_spec.rb b/qa/qa/specs/features/sanity/framework_spec.rb
index 611c6c7b1ff..feec56478c0 100644
--- a/qa/qa/specs/features/sanity/framework_spec.rb
+++ b/qa/qa/specs/features/sanity/framework_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- context 'Framework sanity checks', :orchestrated, :framework do
+ RSpec.describe 'Framework sanity checks', :orchestrated, :framework do
describe 'Passing orchestrated example' do
it 'succeeds' do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
diff --git a/qa/qa/specs/helpers/quarantine.rb b/qa/qa/specs/helpers/quarantine.rb
index 6a3becf0ee5..d365819057e 100644
--- a/qa/qa/specs/helpers/quarantine.rb
+++ b/qa/qa/specs/helpers/quarantine.rb
@@ -20,7 +20,7 @@ module QA
Quarantine.skip_or_run_quarantined_tests_or_contexts(config.inclusion_filter.rules, example)
if example.metadata.key?(:only)
- skip('Test is not compatible with this environment') unless Runtime::Env.address_matches?(example.metadata[:only])
+ skip('Test is not compatible with this environment or pipeline') unless Runtime::Env.context_matches?(example.metadata[:only])
end
end
end
@@ -55,7 +55,7 @@ module QA
if quarantine_tag&.is_a?(Hash) && quarantine_tag&.key?(:only)
# If the :quarantine hash contains :only, we respect that.
# For instance `quarantine: { only: { subdomain: :staging } }` will only quarantine the test when it runs against staging.
- return unless Runtime::Env.address_matches?(quarantine_tag[:only])
+ return unless Runtime::Env.context_matches?(quarantine_tag[:only])
end
skip(quarantine_message(quarantine_tag))
diff --git a/qa/qa/support/api.rb b/qa/qa/support/api.rb
index 08faacb6db3..5fc36b68e5c 100644
--- a/qa/qa/support/api.rb
+++ b/qa/qa/support/api.rb
@@ -40,7 +40,7 @@ module QA
return_response_or_raise(e)
end
- def put(url, payload)
+ def put(url, payload = nil)
RestClient::Request.execute(
method: :put,
url: url,
diff --git a/qa/qa/support/json_formatter.rb b/qa/qa/support/json_formatter.rb
index f6e40436ec8..0b805cd9eec 100644
--- a/qa/qa/support/json_formatter.rb
+++ b/qa/qa/support/json_formatter.rb
@@ -50,7 +50,8 @@ module QA
pending_message: example.execution_result.pending_message,
testcase: example.metadata[:testcase],
quarantine: example.metadata[:quarantine],
- screenshot: example.metadata[:screenshot]
+ screenshot: example.metadata[:screenshot],
+ ci_job_url: QA::Runtime::Env.ci_job_url
}
end
diff --git a/qa/qa/support/otp.rb b/qa/qa/support/otp.rb
index 0d7c394cf69..0a0dc64a726 100644
--- a/qa/qa/support/otp.rb
+++ b/qa/qa/support/otp.rb
@@ -13,11 +13,14 @@ module QA
# Fetches a fresh OTP and returns it only after rotp provides the same OTP twice
# An OTP is valid for 30 seconds so 70 attempts with 0.5 interval would ensure we complete 1 cycle
- Support::Retrier.retry_until(max_attempts: 70, sleep_interval: 0.5) do
+
+ QA::Runtime::Logger.debug("Fetching a fresh OTP...")
+ Support::Retrier.retry_until(max_attempts: 70, sleep_interval: 0.5, log: false) do
otps << @rotp.now
otps.size >= 3 && otps[-1] == otps[-2] && otps[-1] != otps[-3]
end
+ QA::Runtime::Logger.debug("Fetched OTP: #{otps.last}")
otps.last
end
end
diff --git a/qa/qa/support/retrier.rb b/qa/qa/support/retrier.rb
index f28534e7c11..25dbb42cf6f 100644
--- a/qa/qa/support/retrier.rb
+++ b/qa/qa/support/retrier.rb
@@ -34,15 +34,17 @@ module QA
result
end
- def retry_until(max_attempts: nil, max_duration: nil, reload_page: nil, sleep_interval: 0, raise_on_failure: true, retry_on_exception: false)
+ def retry_until(max_attempts: nil, max_duration: nil, reload_page: nil, sleep_interval: 0, raise_on_failure: true, retry_on_exception: false, log: true)
# For backwards-compatibility
max_attempts = 3 if max_attempts.nil? && max_duration.nil?
- start_msg ||= ["with retry_until:"]
- start_msg << "max_attempts: #{max_attempts};" if max_attempts
- start_msg << "max_duration: #{max_duration};" if max_duration
- start_msg << "reload_page: #{reload_page}; sleep_interval: #{sleep_interval}; raise_on_failure: #{raise_on_failure}; retry_on_exception: #{retry_on_exception}"
- QA::Runtime::Logger.debug(start_msg.join(' '))
+ if log
+ start_msg ||= ["with retry_until:"]
+ start_msg << "max_attempts: #{max_attempts};" if max_attempts
+ start_msg << "max_duration: #{max_duration};" if max_duration
+ start_msg << "reload_page: #{reload_page}; sleep_interval: #{sleep_interval}; raise_on_failure: #{raise_on_failure}; retry_on_exception: #{retry_on_exception}"
+ QA::Runtime::Logger.debug(start_msg.join(' '))
+ end
result = nil
repeat_until(
@@ -51,7 +53,8 @@ module QA
reload_page: reload_page,
sleep_interval: sleep_interval,
raise_on_failure: raise_on_failure,
- retry_on_exception: retry_on_exception
+ retry_on_exception: retry_on_exception,
+ log: log
) do
result = yield
end
diff --git a/qa/qa/support/run.rb b/qa/qa/support/run.rb
new file mode 100644
index 00000000000..a91e7dfd2cb
--- /dev/null
+++ b/qa/qa/support/run.rb
@@ -0,0 +1,43 @@
+# frozen_string_literal: true
+
+require 'open3'
+
+module QA
+ module Support
+ module Run
+ include QA::Support::Repeater
+
+ CommandError = Class.new(StandardError)
+
+ Result = Struct.new(:command, :exitstatus, :response) do
+ alias_method :to_s, :response
+
+ def success?
+ exitstatus == 0 && !response.include?('Error encountered')
+ end
+ end
+
+ def run(command_str, env: [], max_attempts: 1, log_prefix: '')
+ command = [*env, command_str, '2>&1'].compact.join(' ')
+ result = nil
+
+ repeat_until(max_attempts: max_attempts, raise_on_failure: false) do
+ Runtime::Logger.debug "#{log_prefix}pwd=[#{Dir.pwd}], command=[#{command}]"
+ output, status = Open3.capture2e(command)
+ output.chomp!
+ Runtime::Logger.debug "#{log_prefix}output=[#{output}], exitstatus=[#{status.exitstatus}]"
+
+ result = Result.new(command, status.exitstatus, output)
+
+ result.success?
+ end
+
+ unless result.success?
+ raise CommandError, "The command #{result.command} failed (#{result.exitstatus}) with the following output:\n#{result.response}"
+ end
+
+ result
+ end
+ end
+ end
+end
diff --git a/qa/qa/support/ssh.rb b/qa/qa/support/ssh.rb
new file mode 100644
index 00000000000..a5e8e96cb6c
--- /dev/null
+++ b/qa/qa/support/ssh.rb
@@ -0,0 +1,62 @@
+# frozen_string_literal: true
+
+require 'tempfile'
+require 'etc'
+
+module QA
+ module Support
+ class SSH
+ include Scenario::Actable
+ include Support::Run
+
+ attr_accessor :known_hosts_file, :private_key_file, :key
+ attr_reader :uri
+
+ def initialize
+ @private_key_file = Tempfile.new("id_#{SecureRandom.hex(8)}")
+ @known_hosts_file = Tempfile.new("known_hosts_#{SecureRandom.hex(8)}")
+ end
+
+ def uri=(address)
+ @uri = URI(address)
+ end
+
+ def setup(env: nil)
+ File.binwrite(private_key_file, key.private_key)
+ File.chmod(0700, private_key_file)
+
+ keyscan_params = ['-H']
+ keyscan_params << "-p #{uri_port}" if uri_port
+ keyscan_params << uri.host
+
+ res = run("ssh-keyscan #{keyscan_params.join(' ')} >> #{known_hosts_file.path}", env: env, log_prefix: 'SSH: ')
+ return res.response unless res.success?
+
+ true
+ end
+
+ def delete
+ private_key_file.close(true)
+ known_hosts_file.close(true)
+ end
+
+ def reset_2fa_codes
+ ssh_params = [uri.host]
+ ssh_params << "-p #{uri_port}" if uri_port
+ ssh_params << "2fa_recovery_codes"
+
+ run("echo yes | ssh -i #{private_key_file.path} -o UserKnownHostsFile=#{known_hosts_file.path} #{git_user}@#{ssh_params.join(' ')}", log_prefix: 'SSH: ').to_s
+ end
+
+ private
+
+ def uri_port
+ uri.port && (uri.port != 80) ? uri.port : nil
+ end
+
+ def git_user
+ QA::Runtime::Env.running_in_ci? || [443, 80].include?(uri.port) ? 'git' : Etc.getlogin
+ end
+ end
+ end
+end
diff --git a/qa/qa/support/wait_for_requests.rb b/qa/qa/support/wait_for_requests.rb
index 943d7d510df..ebc473a7d86 100644
--- a/qa/qa/support/wait_for_requests.rb
+++ b/qa/qa/support/wait_for_requests.rb
@@ -9,18 +9,14 @@ module QA
def wait_for_requests(skip_finished_loading_check: false)
Waiter.wait_until(log: false) do
- finished_all_ajax_requests? && finished_all_axios_requests? && (!skip_finished_loading_check ? finished_loading?(wait: 1) : true)
+ finished_all_ajax_requests? && (!skip_finished_loading_check ? finished_loading?(wait: 1) : true)
end
- end
-
- def finished_all_axios_requests?
- Capybara.page.evaluate_script('window.pendingRequests || 0').zero? # rubocop:disable Style/NumericPredicate
+ rescue Repeater::WaitExceededError
+ raise $!, 'Page did not fully load. This could be due to an unending async request or loading icon.'
end
def finished_all_ajax_requests?
- return true if Capybara.page.evaluate_script('typeof jQuery === "undefined"')
-
- Capybara.page.evaluate_script('jQuery.active').zero? # rubocop:disable Style/NumericPredicate
+ Capybara.page.evaluate_script('window.pendingRequests || window.pendingRailsUJSRequests || 0').zero? # rubocop:disable Style/NumericPredicate
end
def finished_loading?(wait: DEFAULT_MAX_WAIT_TIME)
diff --git a/qa/qa/tools/initialize_gitlab_auth.rb b/qa/qa/tools/initialize_gitlab_auth.rb
new file mode 100644
index 00000000000..b06ddcab040
--- /dev/null
+++ b/qa/qa/tools/initialize_gitlab_auth.rb
@@ -0,0 +1,30 @@
+# frozen_string_literal: true
+
+require_relative '../../qa'
+
+module QA
+ module Tools
+ # Task to set default password from Runtime::Env.default_password if not set already
+ # Also creates a personal access token
+ # @example
+ # $ bundle exec rake 'initialize_gitlab_auth[http://gitlab.test]'
+ class InitializeGitLabAuth
+ attr_reader :address
+
+ def initialize(address:)
+ @address = address
+ end
+
+ def run
+ Runtime::Scenario.define(:gitlab_address, address)
+
+ puts "Signing in and creating the default password for the root user if it's not set already..."
+ QA::Runtime::Browser.visit(:gitlab, QA::Page::Main::Login)
+ Flow::Login.sign_in
+
+ puts "Creating an API scoped access token for the root user..."
+ puts "Token: #{Resource::PersonalAccessToken.fabricate!.access_token}"
+ end
+ end
+ end
+end
diff --git a/qa/spec/factory/resource/user_spec.rb b/qa/spec/factory/resource/user_spec.rb
index d59ee24c758..1adf3799b0e 100644
--- a/qa/spec/factory/resource/user_spec.rb
+++ b/qa/spec/factory/resource/user_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-describe QA::Resource::User do
+RSpec.describe QA::Resource::User do
describe "#fabricate_via_api!" do
response = Struct.new(:code, :body)
diff --git a/qa/spec/git/location_spec.rb b/qa/spec/git/location_spec.rb
index 0c57291666f..ee714206e4f 100644
--- a/qa/spec/git/location_spec.rb
+++ b/qa/spec/git/location_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-describe QA::Git::Location do
+RSpec.describe QA::Git::Location do
describe '.new' do
context 'when URI starts with ssh://' do
context 'when URI has port' do
diff --git a/qa/spec/git/repository_spec.rb b/qa/spec/git/repository_spec.rb
index 8355c77f493..02bb7783c28 100644
--- a/qa/spec/git/repository_spec.rb
+++ b/qa/spec/git/repository_spec.rb
@@ -1,12 +1,21 @@
# frozen_string_literal: true
-describe QA::Git::Repository do
+RSpec.describe QA::Git::Repository do
include Helpers::StubENV
shared_context 'unresolvable git directory' do
let(:repo_uri) { 'http://foo/bar.git' }
let(:repo_uri_with_credentials) { 'http://root@foo/bar.git' }
- let(:repository) { described_class.new.tap { |r| r.uri = repo_uri } }
+ let(:env_vars) { [%q{HOME="temp"}] }
+ let(:extra_env_vars) { [] }
+ let(:run_params) { { env: env_vars + extra_env_vars, log_prefix: "Git: " } }
+ let(:repository) do
+ described_class.new.tap do |r|
+ r.uri = repo_uri
+ r.env_vars = env_vars
+ end
+ end
+
let(:tmp_git_dir) { Dir.mktmpdir }
let(:tmp_netrc_dir) { Dir.mktmpdir }
@@ -28,14 +37,13 @@ describe QA::Git::Repository do
end
shared_examples 'command with retries' do
- let(:extra_args) { {} }
let(:result_output) { +'Command successful' }
let(:result) { described_class::Result.new(any_args, 0, result_output) }
let(:command_return) { result_output }
context 'when command is successful' do
it 'returns the #run command Result output' do
- expect(repository).to receive(:run).with(command, extra_args.merge(max_attempts: 3)).and_return(result)
+ expect(repository).to receive(:run).with(command, run_params.merge(max_attempts: 3)).and_return(result)
expect(call_method).to eq(command_return)
end
@@ -52,10 +60,10 @@ describe QA::Git::Repository do
end
context 'and retried command is not successful after 3 attempts' do
- it 'raises a RepositoryCommandError exception' do
+ it 'raises a CommandError exception' do
expect(Open3).to receive(:capture2e).and_return([+'FAILURE', double(exitstatus: 42)]).exactly(3).times
- expect { call_method }.to raise_error(described_class::RepositoryCommandError, /The command .* failed \(42\) with the following output:\nFAILURE/)
+ expect { call_method }.to raise_error(QA::Support::Run::CommandError, /The command .* failed \(42\) with the following output:\nFAILURE/)
end
end
end
@@ -117,12 +125,72 @@ describe QA::Git::Repository do
let(:call_method) { repository.push_changes(branch) }
end
end
+
+ context 'with push options' do
+ let(:command) { "git push #{push_options} #{repo_uri_with_credentials} #{branch}" }
+
+ context 'when set to create a merge request' do
+ it_behaves_like 'command with retries' do
+ let(:push_options) { '-o merge_request.create' }
+ let(:call_method) { repository.push_changes(push_options: { create: true }) }
+ end
+ end
+
+ context 'when set to merge when pipeline succeeds' do
+ it_behaves_like 'command with retries' do
+ let(:push_options) { '-o merge_request.merge_when_pipeline_succeeds' }
+ let(:call_method) { repository.push_changes(push_options: { merge_when_pipeline_succeeds: true }) }
+ end
+ end
+
+ context 'when set to remove source branch' do
+ it_behaves_like 'command with retries' do
+ let(:push_options) { '-o merge_request.remove_source_branch' }
+ let(:call_method) { repository.push_changes(push_options: { remove_source_branch: true }) }
+ end
+ end
+
+ context 'when title is given' do
+ it_behaves_like 'command with retries' do
+ let(:push_options) { '-o merge_request.title="Is A Title"' }
+ let(:call_method) { repository.push_changes(push_options: { title: 'Is A Title' }) }
+ end
+ end
+
+ context 'when description is given' do
+ it_behaves_like 'command with retries' do
+ let(:push_options) { '-o merge_request.description="Is A Description"' }
+ let(:call_method) { repository.push_changes(push_options: { description: 'Is A Description' }) }
+ end
+ end
+
+ context 'when target branch is given' do
+ it_behaves_like 'command with retries' do
+ let(:push_options) { '-o merge_request.target="is-a-target-branch"' }
+ let(:call_method) { repository.push_changes(push_options: { target: 'is-a-target-branch' }) }
+ end
+ end
+
+ context 'when a label is given' do
+ it_behaves_like 'command with retries' do
+ let(:push_options) { '-o merge_request.label="is-a-label"' }
+ let(:call_method) { repository.push_changes(push_options: { label: ['is-a-label'] }) }
+ end
+ end
+
+ context 'when two labels are given' do
+ it_behaves_like 'command with retries' do
+ let(:push_options) { '-o merge_request.label="is-a-label" -o merge_request.label="is-another-label"' }
+ let(:call_method) { repository.push_changes(push_options: { label: %w[is-a-label is-another-label] }) }
+ end
+ end
+ end
end
describe '#git_protocol=' do
[0, 1, 2].each do |version|
it "configures git to use protocol version #{version}" do
- expect(repository).to receive(:run).with("git config protocol.version #{version}")
+ expect(repository).to receive(:run).with("git config protocol.version #{version}", run_params.merge(max_attempts: 1))
repository.git_protocol = version
end
@@ -140,7 +208,7 @@ describe QA::Git::Repository do
let(:command) { "git ls-remote #{repo_uri_with_credentials}" }
let(:result_output) { +'packet: git< version 2' }
let(:command_return) { '2' }
- let(:extra_args) { { env: "GIT_TRACE_PACKET=1" } }
+ let(:extra_env_vars) { ["GIT_TRACE_PACKET=1"] }
end
it "reports the detected version" do
diff --git a/qa/spec/page/base_spec.rb b/qa/spec/page/base_spec.rb
index 0cbb0a2b12e..52345876149 100644
--- a/qa/spec/page/base_spec.rb
+++ b/qa/spec/page/base_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-describe QA::Page::Base do
+RSpec.describe QA::Page::Base do
describe 'page helpers' do
it 'exposes helpful page helpers' do
expect(subject).to respond_to :refresh, :wait_until, :scroll_to
diff --git a/qa/spec/page/element_spec.rb b/qa/spec/page/element_spec.rb
index 3f64743ffac..fbf58b5e18a 100644
--- a/qa/spec/page/element_spec.rb
+++ b/qa/spec/page/element_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-describe QA::Page::Element do
+RSpec.describe QA::Page::Element do
describe '#selector' do
it 'transforms element name into QA-specific selector' do
expect(described_class.new(:sign_in_button).selector)
diff --git a/qa/spec/page/logging_spec.rb b/qa/spec/page/logging_spec.rb
index f2ce9fb2cf8..df3447770be 100644
--- a/qa/spec/page/logging_spec.rb
+++ b/qa/spec/page/logging_spec.rb
@@ -3,7 +3,7 @@
require 'capybara/dsl'
require 'logger'
-describe QA::Support::Page::Logging do
+RSpec.describe QA::Support::Page::Logging do
let(:page) { double.as_null_object }
before do
diff --git a/qa/spec/page/validator_spec.rb b/qa/spec/page/validator_spec.rb
index c727cfb686e..cfb36052294 100644
--- a/qa/spec/page/validator_spec.rb
+++ b/qa/spec/page/validator_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-describe QA::Page::Validator do
+RSpec.describe QA::Page::Validator do
describe '#constants' do
subject do
described_class.new(QA::Page::Project)
diff --git a/qa/spec/page/view_spec.rb b/qa/spec/page/view_spec.rb
index 3cb64dcd9c2..3342b387ed1 100644
--- a/qa/spec/page/view_spec.rb
+++ b/qa/spec/page/view_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-describe QA::Page::View do
+RSpec.describe QA::Page::View do
let(:element) do
double('element', name: :something, pattern: /some element/)
end
diff --git a/qa/spec/resource/api_fabricator_spec.rb b/qa/spec/resource/api_fabricator_spec.rb
index eb2bdd1be64..69a95c92332 100644
--- a/qa/spec/resource/api_fabricator_spec.rb
+++ b/qa/spec/resource/api_fabricator_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-describe QA::Resource::ApiFabricator do
+RSpec.describe QA::Resource::ApiFabricator do
let(:resource_without_api_support) do
Class.new do
def self.name
diff --git a/qa/spec/resource/base_spec.rb b/qa/spec/resource/base_spec.rb
index b23de19e1f8..c0bedf794be 100644
--- a/qa/spec/resource/base_spec.rb
+++ b/qa/spec/resource/base_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-describe QA::Resource::Base do
+RSpec.describe QA::Resource::Base do
include Helpers::StubENV
let(:resource) { spy('resource') }
diff --git a/qa/spec/resource/events/base_spec.rb b/qa/spec/resource/events/base_spec.rb
index 9cdf4785092..4df30a970fc 100644
--- a/qa/spec/resource/events/base_spec.rb
+++ b/qa/spec/resource/events/base_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-describe QA::Resource::Events::Base do
+RSpec.describe QA::Resource::Events::Base do
let(:resource) do
Class.new(QA::Resource::Base) do
def api_get_path
diff --git a/qa/spec/resource/events/project_spec.rb b/qa/spec/resource/events/project_spec.rb
index 98da87906fa..88d50749a0a 100644
--- a/qa/spec/resource/events/project_spec.rb
+++ b/qa/spec/resource/events/project_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-describe QA::Resource::Events::Project do
+RSpec.describe QA::Resource::Events::Project do
let(:resource) do
Class.new(QA::Resource::Base) do
def api_get_path
diff --git a/qa/spec/resource/repository/push_spec.rb b/qa/spec/resource/repository/push_spec.rb
index 2f9e4958ae1..2b9c90b3dac 100644
--- a/qa/spec/resource/repository/push_spec.rb
+++ b/qa/spec/resource/repository/push_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-describe QA::Resource::Repository::Push do
+RSpec.describe QA::Resource::Repository::Push do
describe '.files=' do
let(:files) do
[
diff --git a/qa/spec/resource/ssh_key_spec.rb b/qa/spec/resource/ssh_key_spec.rb
index b2b5ec070e1..fd0fda3c1b8 100644
--- a/qa/spec/resource/ssh_key_spec.rb
+++ b/qa/spec/resource/ssh_key_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-describe QA::Resource::SSHKey do
+RSpec.describe QA::Resource::SSHKey do
describe '#key' do
it 'generates a default key' do
expect(subject.key).to be_a(QA::Runtime::Key::RSA)
diff --git a/qa/spec/resource/user_spec.rb b/qa/spec/resource/user_spec.rb
index 5845f7996a3..e7397d9c0bf 100644
--- a/qa/spec/resource/user_spec.rb
+++ b/qa/spec/resource/user_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-describe QA::Resource::User do
+RSpec.describe QA::Resource::User do
let(:api_resource) do
{
name: "GitLab QA",
diff --git a/qa/spec/runtime/api/client_spec.rb b/qa/spec/runtime/api/client_spec.rb
index 6f7020d6595..dd139fda980 100644
--- a/qa/spec/runtime/api/client_spec.rb
+++ b/qa/spec/runtime/api/client_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-describe QA::Runtime::API::Client do
+RSpec.describe QA::Runtime::API::Client do
include Helpers::StubENV
describe 'initialization' do
diff --git a/qa/spec/runtime/api/request_spec.rb b/qa/spec/runtime/api/request_spec.rb
index 8354eff6234..93de2f4a87e 100644
--- a/qa/spec/runtime/api/request_spec.rb
+++ b/qa/spec/runtime/api/request_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-describe QA::Runtime::API::Request do
+RSpec.describe QA::Runtime::API::Request do
let(:client) { QA::Runtime::API::Client.new('http://example.com') }
let(:request) { described_class.new(client, '/users') }
diff --git a/qa/spec/runtime/application_settings_spec.rb b/qa/spec/runtime/application_settings_spec.rb
index e48214b22e6..5c4947f6f70 100644
--- a/qa/spec/runtime/application_settings_spec.rb
+++ b/qa/spec/runtime/application_settings_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-describe QA::Runtime::ApplicationSettings do
+RSpec.describe QA::Runtime::ApplicationSettings do
let(:api_client) { double('QA::Runtime::API::Client') }
let(:request) { Struct.new(:url).new('http://api') }
let(:get_response) { Struct.new(:body).new("{}") }
diff --git a/qa/spec/runtime/env_spec.rb b/qa/spec/runtime/env_spec.rb
index 0cfb9a70c88..3396ae6f0b8 100644
--- a/qa/spec/runtime/env_spec.rb
+++ b/qa/spec/runtime/env_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-describe QA::Runtime::Env do
+RSpec.describe QA::Runtime::Env do
include Helpers::StubENV
shared_examples 'boolean method' do |**kwargs|
@@ -341,7 +341,7 @@ describe QA::Runtime::Env do
end
end
- describe '.address_matches?' do
+ describe '.context_matches?' do
it 'returns true when url has .com' do
QA::Runtime::Scenario.define(:gitlab_address, "https://staging.gitlab.com")
@@ -364,24 +364,24 @@ describe QA::Runtime::Env do
it 'matches multiple subdomains' do
QA::Runtime::Scenario.define(:gitlab_address, "https://staging.gitlab.com")
- expect(described_class.address_matches?(subdomain: [:release, :staging])).to be_truthy
- expect(described_class.address_matches?(:production, subdomain: [:release, :staging])).to be_truthy
+ expect(described_class.context_matches?(subdomain: [:release, :staging])).to be_truthy
+ expect(described_class.context_matches?(:production, subdomain: [:release, :staging])).to be_truthy
end
it 'matches :production' do
QA::Runtime::Scenario.define(:gitlab_address, "https://gitlab.com/")
- expect(described_class.address_matches?(:production)).to be_truthy
+ expect(described_class.context_matches?(:production)).to be_truthy
end
it 'doesnt match with mismatching switches' do
QA::Runtime::Scenario.define(:gitlab_address, 'https://gitlab.test')
aggregate_failures do
- expect(described_class.address_matches?(tld: '.net')).to be_falsey
- expect(described_class.address_matches?(:production)).to be_falsey
- expect(described_class.address_matches?(subdomain: [:staging])).to be_falsey
- expect(described_class.address_matches?(domain: 'example')).to be_falsey
+ expect(described_class.context_matches?(tld: '.net')).to be_falsey
+ expect(described_class.context_matches?(:production)).to be_falsey
+ expect(described_class.context_matches?(subdomain: [:staging])).to be_falsey
+ expect(described_class.context_matches?(domain: 'example')).to be_falsey
end
end
end
@@ -389,7 +389,7 @@ describe QA::Runtime::Env do
it 'returns false for mismatching' do
QA::Runtime::Scenario.define(:gitlab_address, "https://staging.gitlab.com")
- expect(described_class.address_matches?(:production)).to be_falsey
+ expect(described_class.context_matches?(:production)).to be_falsey
end
end
end
diff --git a/qa/spec/runtime/feature_spec.rb b/qa/spec/runtime/feature_spec.rb
index db3c2f65963..39c20dd3070 100644
--- a/qa/spec/runtime/feature_spec.rb
+++ b/qa/spec/runtime/feature_spec.rb
@@ -1,87 +1,215 @@
# frozen_string_literal: true
-describe QA::Runtime::Feature do
+RSpec.describe QA::Runtime::Feature do
let(:api_client) { double('QA::Runtime::API::Client') }
let(:request) { Struct.new(:url).new('http://api') }
let(:response_post) { Struct.new(:code).new(201) }
- let(:response_get) { Struct.new(:code, :body).new(200, '[{ "name": "a-flag", "state": "on" }]') }
before do
allow(described_class).to receive(:api_client).and_return(api_client)
end
- describe '.enable' do
- it 'enables a feature flag' do
- expect(QA::Runtime::API::Request)
- .to receive(:new)
- .with(api_client, "/features/a-flag")
- .and_return(request)
- expect(described_class)
- .to receive(:post)
- .with(request.url, { value: true })
- .and_return(response_post)
-
- subject.enable('a-flag')
- end
+ where(:feature_flag) do
+ ['a_flag', :a_flag]
end
- describe '.enable_and_verify' do
- it 'enables a feature flag' do
- allow(described_class).to receive(:get).and_return(response_get)
+ with_them do
+ shared_examples 'enables a feature flag' do
+ it 'enables a feature flag for a scope' do
+ allow(described_class).to receive(:get)
+ .and_return(Struct.new(:code, :body).new(200, '[{ "name": "a_flag", "state": "on" }]'))
- expect(QA::Runtime::API::Request).to receive(:new)
- .with(api_client, "/features/a-flag").and_return(request)
- expect(described_class).to receive(:post)
- .with(request.url, { value: true }).and_return(response_post)
- expect(QA::Runtime::API::Request).to receive(:new)
- .with(api_client, "/features").and_return(request)
+ expect(QA::Runtime::API::Request).to receive(:new)
+ .with(api_client, "/features/a_flag").and_return(request)
+ expect(described_class).to receive(:post)
+ .with(request.url, { value: true, scope => actor_name }).and_return(response_post)
+ expect(QA::Runtime::API::Request).to receive(:new)
+ .with(api_client, "/features").and_return(request)
+ expect(QA::Runtime::Logger).to receive(:info).with("Enabling feature: a_flag for scope \"#{scope}: #{actor_name}\"")
+ expect(QA::Runtime::Logger).to receive(:info).with("Successfully enabled and verified feature flag: a_flag")
- subject.enable_and_verify('a-flag')
+ described_class.enable(feature_flag, scope => actor)
+ end
end
- end
- describe '.disable' do
- it 'disables a feature flag' do
- expect(QA::Runtime::API::Request)
- .to receive(:new)
- .with(api_client, "/features/a-flag")
- .and_return(request)
- expect(described_class)
- .to receive(:post)
- .with(request.url, { value: false })
- .and_return(response_post)
-
- subject.disable('a-flag')
+ shared_examples 'disables a feature flag' do
+ it 'disables a feature flag for a scope' do
+ allow(described_class).to receive(:get)
+ .and_return(Struct.new(:code, :body).new(200, '[{ "name": "a_flag", "state": "off" }]'))
+
+ expect(QA::Runtime::API::Request).to receive(:new)
+ .with(api_client, "/features/a_flag").and_return(request)
+ expect(described_class).to receive(:post)
+ .with(request.url, { value: false, scope => actor_name }).and_return(response_post)
+ expect(QA::Runtime::API::Request).to receive(:new)
+ .with(api_client, "/features").and_return(request)
+ expect(QA::Runtime::Logger).to receive(:info).with("Disabling feature: a_flag for scope \"#{scope}: #{actor_name}\"")
+ expect(QA::Runtime::Logger).to receive(:info).with("Successfully disabled and verified feature flag: a_flag")
+
+ described_class.disable(feature_flag, scope => actor )
+ end
end
- end
- describe '.disable_and_verify' do
- it 'disables a feature flag' do
- allow(described_class).to receive(:get)
- .and_return(Struct.new(:code, :body).new(200, '[{ "name": "a-flag", "state": "off" }]'))
+ shared_examples 'checks a feature flag' do
+ context 'when the flag is enabled for a scope' do
+ it 'returns the feature flag state' do
+ expect(QA::Runtime::API::Request)
+ .to receive(:new)
+ .with(api_client, "/features")
+ .and_return(request)
+ expect(described_class)
+ .to receive(:get)
+ .and_return(Struct.new(:code, :body).new(200, %Q([{ "name": "a_flag", "state": "conditional", "gates": #{gates} }])))
+
+ expect(described_class.enabled?(feature_flag, scope => actor)).to be_truthy
+ end
+ end
+ end
- expect(QA::Runtime::API::Request).to receive(:new)
- .with(api_client, "/features/a-flag").and_return(request)
- expect(described_class).to receive(:post)
- .with(request.url, { value: false }).and_return(response_post)
- expect(QA::Runtime::API::Request).to receive(:new)
- .with(api_client, "/features").and_return(request)
+ describe '.enable' do
+ it 'enables a feature flag' do
+ allow(described_class).to receive(:get)
+ .and_return(Struct.new(:code, :body).new(200, '[{ "name": "a_flag", "state": "on" }]'))
- subject.disable_and_verify('a-flag')
+ expect(QA::Runtime::API::Request).to receive(:new)
+ .with(api_client, "/features/a_flag").and_return(request)
+ expect(described_class).to receive(:post)
+ .with(request.url, { value: true }).and_return(response_post)
+ expect(QA::Runtime::API::Request).to receive(:new)
+ .with(api_client, "/features").and_return(request)
+
+ described_class.enable(feature_flag)
+ end
+
+ context 'when a project scope is provided' do
+ it_behaves_like 'enables a feature flag' do
+ let(:scope) { :project }
+ let(:actor_name) { 'group-name/project-name' }
+ let(:actor) { Struct.new(:full_path).new(actor_name) }
+ end
+ end
+
+ context 'when a group scope is provided' do
+ it_behaves_like 'enables a feature flag' do
+ let(:scope) { :group }
+ let(:actor_name) { 'group-name' }
+ let(:actor) { Struct.new(:full_path).new(actor_name) }
+ end
+ end
+
+ context 'when a user scope is provided' do
+ it_behaves_like 'enables a feature flag' do
+ let(:scope) { :user }
+ let(:actor_name) { 'user-name' }
+ let(:actor) { Struct.new(:username).new(actor_name) }
+ end
+ end
+
+ context 'when a feature group scope is provided' do
+ it_behaves_like 'enables a feature flag' do
+ let(:scope) { :feature_group }
+ let(:actor_name) { 'foo' }
+ let(:actor) { "foo" }
+ end
+ end
end
- end
- describe '.enabled?' do
- it 'returns a feature flag state' do
- expect(QA::Runtime::API::Request)
- .to receive(:new)
- .with(api_client, "/features")
- .and_return(request)
- expect(described_class)
- .to receive(:get)
- .and_return(response_get)
-
- expect(subject.enabled?('a-flag')).to be_truthy
+ describe '.disable' do
+ it 'disables a feature flag' do
+ allow(described_class).to receive(:get)
+ .and_return(Struct.new(:code, :body).new(200, '[{ "name": "a_flag", "state": "off" }]'))
+
+ expect(QA::Runtime::API::Request).to receive(:new)
+ .with(api_client, "/features/a_flag").and_return(request)
+ expect(described_class).to receive(:post)
+ .with(request.url, { value: false }).and_return(response_post)
+ expect(QA::Runtime::API::Request).to receive(:new)
+ .with(api_client, "/features").and_return(request)
+
+ described_class.disable(feature_flag)
+ end
+
+ context 'when a project scope is provided' do
+ it_behaves_like 'disables a feature flag' do
+ let(:scope) { :project }
+ let(:actor_name) { 'group-name/project-name' }
+ let(:actor) { Struct.new(:full_path).new(actor_name) }
+ end
+ end
+
+ context 'when a group scope is provided' do
+ it_behaves_like 'disables a feature flag' do
+ let(:scope) { :group }
+ let(:actor_name) { 'group-name' }
+ let(:actor) { Struct.new(:full_path).new(actor_name) }
+ end
+ end
+
+ context 'when a user scope is provided' do
+ it_behaves_like 'disables a feature flag' do
+ let(:scope) { :user }
+ let(:actor_name) { 'user-name' }
+ let(:actor) { Struct.new(:username).new(actor_name) }
+ end
+ end
+
+ context 'when a feature group scope is provided' do
+ it_behaves_like 'disables a feature flag' do
+ let(:scope) { :feature_group }
+ let(:actor_name) { 'foo' }
+ let(:actor) { "foo" }
+ end
+ end
+ end
+
+ describe '.enabled?' do
+ it 'returns a feature flag state' do
+ expect(QA::Runtime::API::Request)
+ .to receive(:new)
+ .with(api_client, "/features")
+ .and_return(request)
+ expect(described_class)
+ .to receive(:get)
+ .and_return(Struct.new(:code, :body).new(200, '[{ "name": "a_flag", "state": "on" }]'))
+
+ expect(described_class.enabled?(feature_flag)).to be_truthy
+ end
+
+ context 'when a project scope is provided' do
+ it_behaves_like 'checks a feature flag' do
+ let(:scope) { :project }
+ let(:actor_name) { 'group-name/project-name' }
+ let(:actor) { Struct.new(:full_path, :id).new(actor_name, 270) }
+ let(:gates) { %q([{"key": "actors", "value": ["Project:270"]}]) }
+ end
+ end
+
+ context 'when a group scope is provided' do
+ it_behaves_like 'checks a feature flag' do
+ let(:scope) { :group }
+ let(:actor_name) { 'group-name' }
+ let(:actor) { Struct.new(:full_path, :id).new(actor_name, 33) }
+ let(:gates) { %q([{"key": "actors", "value": ["Group:33"]}]) }
+ end
+ end
+
+ context 'when a user scope is provided' do
+ it_behaves_like 'checks a feature flag' do
+ let(:scope) { :user }
+ let(:actor_name) { 'user-name' }
+ let(:actor) { Struct.new(:full_path, :id).new(actor_name, 13) }
+ let(:gates) { %q([{"key": "actors", "value": ["User:13"]}]) }
+ end
+ end
+
+ context 'when a feature group scope is provided' do
+ it_behaves_like 'checks a feature flag' do
+ let(:scope) { :feature_group }
+ let(:actor_name) { 'foo' }
+ let(:actor) { "foo" }
+ let(:gates) { %q([{"key": "groups", "value": ["foo"]}]) }
+ end
+ end
end
end
end
diff --git a/qa/spec/runtime/key/ecdsa_spec.rb b/qa/spec/runtime/key/ecdsa_spec.rb
index 3f9718e62c5..499233df618 100644
--- a/qa/spec/runtime/key/ecdsa_spec.rb
+++ b/qa/spec/runtime/key/ecdsa_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-describe QA::Runtime::Key::ECDSA do
+RSpec.describe QA::Runtime::Key::ECDSA do
describe '#public_key' do
[256, 384, 521].each do |bits|
it "generates a public #{bits}-bits ECDSA key" do
diff --git a/qa/spec/runtime/key/ed25519_spec.rb b/qa/spec/runtime/key/ed25519_spec.rb
index 08f232260af..e63c7f5deae 100644
--- a/qa/spec/runtime/key/ed25519_spec.rb
+++ b/qa/spec/runtime/key/ed25519_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-describe QA::Runtime::Key::ED25519 do
+RSpec.describe QA::Runtime::Key::ED25519 do
describe '#public_key' do
subject { described_class.new.public_key }
diff --git a/qa/spec/runtime/key/rsa_spec.rb b/qa/spec/runtime/key/rsa_spec.rb
index fcb52f541bf..5b5d8a13fa1 100644
--- a/qa/spec/runtime/key/rsa_spec.rb
+++ b/qa/spec/runtime/key/rsa_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-describe QA::Runtime::Key::RSA do
+RSpec.describe QA::Runtime::Key::RSA do
describe '#public_key' do
subject { described_class.new.public_key }
diff --git a/qa/spec/runtime/logger_spec.rb b/qa/spec/runtime/logger_spec.rb
index 44be3381bff..a888bf1452b 100644
--- a/qa/spec/runtime/logger_spec.rb
+++ b/qa/spec/runtime/logger_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-describe QA::Runtime::Logger do
+RSpec.describe QA::Runtime::Logger do
before do
logger = Logger.new $stdout
logger.level = ::Logger::DEBUG
diff --git a/qa/spec/runtime/namespace_spec.rb b/qa/spec/runtime/namespace_spec.rb
index d24fa509f30..92836862864 100644
--- a/qa/spec/runtime/namespace_spec.rb
+++ b/qa/spec/runtime/namespace_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-describe QA::Runtime::Namespace do
+RSpec.describe QA::Runtime::Namespace do
include Helpers::StubENV
describe '.name' do
diff --git a/qa/spec/runtime/release_spec.rb b/qa/spec/runtime/release_spec.rb
index b5a7dd5269d..b4e278fb546 100644
--- a/qa/spec/runtime/release_spec.rb
+++ b/qa/spec/runtime/release_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-describe QA::Runtime::Release do
+RSpec.describe QA::Runtime::Release do
context 'when release version has extension strategy' do
let(:strategy) { spy('strategy') }
diff --git a/qa/spec/runtime/scenario_spec.rb b/qa/spec/runtime/scenario_spec.rb
index 30ada4529ed..175973b6795 100644
--- a/qa/spec/runtime/scenario_spec.rb
+++ b/qa/spec/runtime/scenario_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-describe QA::Runtime::Scenario do
+RSpec.describe QA::Runtime::Scenario do
subject do
Module.new.extend(described_class)
end
diff --git a/qa/spec/scenario/actable_spec.rb b/qa/spec/scenario/actable_spec.rb
index 589d0c61993..36e9f3de961 100644
--- a/qa/spec/scenario/actable_spec.rb
+++ b/qa/spec/scenario/actable_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-describe QA::Scenario::Actable do
+RSpec.describe QA::Scenario::Actable do
subject do
Class.new do
include QA::Scenario::Actable
diff --git a/qa/spec/scenario/bootable_spec.rb b/qa/spec/scenario/bootable_spec.rb
index e8accb45518..8a96e9bebbf 100644
--- a/qa/spec/scenario/bootable_spec.rb
+++ b/qa/spec/scenario/bootable_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-describe QA::Scenario::Bootable do
+RSpec.describe QA::Scenario::Bootable do
subject do
Class.new(QA::Scenario::Template)
.include(described_class)
diff --git a/qa/spec/scenario/template_spec.rb b/qa/spec/scenario/template_spec.rb
index 65793734548..f07d817ea16 100644
--- a/qa/spec/scenario/template_spec.rb
+++ b/qa/spec/scenario/template_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-describe QA::Scenario::Template do
+RSpec.describe QA::Scenario::Template do
let(:feature) { spy('Runtime::Feature') }
let(:release) { spy('Runtime::Release') }
diff --git a/qa/spec/scenario/test/instance/airgapped_spec.rb b/qa/spec/scenario/test/instance/airgapped_spec.rb
index 0c4167eafff..5e319ba4bbb 100644
--- a/qa/spec/scenario/test/instance/airgapped_spec.rb
+++ b/qa/spec/scenario/test/instance/airgapped_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-describe QA::Scenario::Test::Instance::Airgapped do
+RSpec.describe QA::Scenario::Test::Instance::Airgapped do
describe '#perform' do
it_behaves_like 'a QA scenario class' do
end
diff --git a/qa/spec/scenario/test/instance/all_spec.rb b/qa/spec/scenario/test/instance/all_spec.rb
index 8acd56914c5..875df9a32f5 100644
--- a/qa/spec/scenario/test/instance/all_spec.rb
+++ b/qa/spec/scenario/test/instance/all_spec.rb
@@ -1,5 +1,5 @@
# frozen_string_literal: true
-describe QA::Scenario::Test::Instance::All do
+RSpec.describe QA::Scenario::Test::Instance::All do
it_behaves_like 'a QA scenario class'
end
diff --git a/qa/spec/scenario/test/instance/smoke_spec.rb b/qa/spec/scenario/test/instance/smoke_spec.rb
index 6cc71699be9..09d0df2c479 100644
--- a/qa/spec/scenario/test/instance/smoke_spec.rb
+++ b/qa/spec/scenario/test/instance/smoke_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-describe QA::Scenario::Test::Instance::Smoke do
+RSpec.describe QA::Scenario::Test::Instance::Smoke do
it_behaves_like 'a QA scenario class' do
let(:tags) { [:smoke] }
end
diff --git a/qa/spec/scenario/test/integration/github_spec.rb b/qa/spec/scenario/test/integration/github_spec.rb
index b2d577bd552..b68b06a7b9f 100644
--- a/qa/spec/scenario/test/integration/github_spec.rb
+++ b/qa/spec/scenario/test/integration/github_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-describe QA::Scenario::Test::Integration::Github do
+RSpec.describe QA::Scenario::Test::Integration::Github do
describe '#perform' do
let(:env) { spy('Runtime::Env') }
diff --git a/qa/spec/scenario/test/integration/instance_saml_spec.rb b/qa/spec/scenario/test/integration/instance_saml_spec.rb
index 15f15b2e643..20e860d3e4b 100644
--- a/qa/spec/scenario/test/integration/instance_saml_spec.rb
+++ b/qa/spec/scenario/test/integration/instance_saml_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-describe QA::Scenario::Test::Integration::InstanceSAML do
+RSpec.describe QA::Scenario::Test::Integration::InstanceSAML do
describe '#perform' do
it_behaves_like 'a QA scenario class' do
let(:tags) { [:instance_saml] }
diff --git a/qa/spec/scenario/test/integration/kubernetes_spec.rb b/qa/spec/scenario/test/integration/kubernetes_spec.rb
index 51ee7b9acff..d5885b97343 100644
--- a/qa/spec/scenario/test/integration/kubernetes_spec.rb
+++ b/qa/spec/scenario/test/integration/kubernetes_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-describe QA::Scenario::Test::Integration::Kubernetes do
+RSpec.describe QA::Scenario::Test::Integration::Kubernetes do
describe '#perform' do
it_behaves_like 'a QA scenario class' do
let(:tags) { [:kubernetes] }
diff --git a/qa/spec/scenario/test/integration/ldap_spec.rb b/qa/spec/scenario/test/integration/ldap_spec.rb
index c493cde6c7a..c53302d9bd3 100644
--- a/qa/spec/scenario/test/integration/ldap_spec.rb
+++ b/qa/spec/scenario/test/integration/ldap_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-describe QA::Scenario::Test::Integration::LDAPNoTLS do
+RSpec.describe QA::Scenario::Test::Integration::LDAPNoTLS do
describe '#perform' do
it_behaves_like 'a QA scenario class' do
let(:tags) { [:ldap_no_tls] }
@@ -8,7 +8,7 @@ describe QA::Scenario::Test::Integration::LDAPNoTLS do
end
end
-describe QA::Scenario::Test::Integration::LDAPNoServer do
+RSpec.describe QA::Scenario::Test::Integration::LDAPNoServer do
describe '#perform' do
it_behaves_like 'a QA scenario class' do
let(:tags) { [:ldap_no_server] }
@@ -16,7 +16,7 @@ describe QA::Scenario::Test::Integration::LDAPNoServer do
end
end
-describe QA::Scenario::Test::Integration::LDAPTLS do
+RSpec.describe QA::Scenario::Test::Integration::LDAPTLS do
describe '#perform' do
it_behaves_like 'a QA scenario class' do
let(:tags) { [:ldap_tls] }
diff --git a/qa/spec/scenario/test/integration/mattermost_spec.rb b/qa/spec/scenario/test/integration/mattermost_spec.rb
index 7e4eb6284e8..9532ec35b95 100644
--- a/qa/spec/scenario/test/integration/mattermost_spec.rb
+++ b/qa/spec/scenario/test/integration/mattermost_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-describe QA::Scenario::Test::Integration::Mattermost do
+RSpec.describe QA::Scenario::Test::Integration::Mattermost do
describe '#perform' do
it_behaves_like 'a QA scenario class' do
let(:args) { %w[gitlab_address mattermost_address] }
diff --git a/qa/spec/scenario/test/integration/object_storage_spec.rb b/qa/spec/scenario/test/integration/object_storage_spec.rb
index 8b4367bee32..235dd495687 100644
--- a/qa/spec/scenario/test/integration/object_storage_spec.rb
+++ b/qa/spec/scenario/test/integration/object_storage_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-describe QA::Scenario::Test::Integration::ObjectStorage do
+RSpec.describe QA::Scenario::Test::Integration::ObjectStorage do
describe '#perform' do
it_behaves_like 'a QA scenario class' do
let(:tags) { [:object_storage] }
diff --git a/qa/spec/scenario/test/sanity/framework_spec.rb b/qa/spec/scenario/test/sanity/framework_spec.rb
index a63c59e2995..5ae8b123ec2 100644
--- a/qa/spec/scenario/test/sanity/framework_spec.rb
+++ b/qa/spec/scenario/test/sanity/framework_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-describe QA::Scenario::Test::Sanity::Framework do
+RSpec.describe QA::Scenario::Test::Sanity::Framework do
it_behaves_like 'a QA scenario class' do
let(:tags) { [:framework] }
end
diff --git a/qa/spec/scenario/test/sanity/selectors_spec.rb b/qa/spec/scenario/test/sanity/selectors_spec.rb
index e18babaed63..2a68dd23219 100644
--- a/qa/spec/scenario/test/sanity/selectors_spec.rb
+++ b/qa/spec/scenario/test/sanity/selectors_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-describe QA::Scenario::Test::Sanity::Selectors do
+RSpec.describe QA::Scenario::Test::Sanity::Selectors do
let(:validator) { spy('validator') }
before do
diff --git a/qa/spec/specs/helpers/quarantine_spec.rb b/qa/spec/specs/helpers/quarantine_spec.rb
index 9686a9771c4..41bc3eadff4 100644
--- a/qa/spec/specs/helpers/quarantine_spec.rb
+++ b/qa/spec/specs/helpers/quarantine_spec.rb
@@ -36,7 +36,9 @@ RSpec.configure do |c|
end
end
-describe QA::Specs::Helpers::Quarantine do
+RSpec.describe QA::Specs::Helpers::Quarantine do
+ include Helpers::StubENV
+
describe '.skip_or_run_quarantined_contexts' do
context 'with no tag focused' do
before do
@@ -312,7 +314,7 @@ describe QA::Specs::Helpers::Quarantine do
end
end
- describe 'running against specific environments' do
+ describe 'running against specific environments or pipelines' do
before do
QA::Runtime::Scenario.define(:gitlab_address, 'https://staging.gitlab.com')
described_class.configure_rspec
@@ -400,5 +402,70 @@ describe QA::Specs::Helpers::Quarantine do
expect(group.examples.first.execution_result.pending_message).to match(/[Tt]est.*not compatible.*environment/)
end
+
+ context 'with pipeline constraints' do
+ context 'without CI_PROJECT_NAME set' do
+ before do
+ stub_env('CI_PROJECT_NAME', nil)
+ described_class.configure_rspec
+ end
+
+ it 'runs on any pipeline' do
+ group = describe_successfully do
+ it('runs given a single named pipeline', only: { pipeline: :nightly } ) {}
+ it('runs given an array of pipelines', only: { pipeline: [:canary, :not_nightly] }) {}
+ end
+
+ aggregate_failures do
+ expect(group.examples[0].execution_result.status).to eq(:passed)
+ expect(group.examples[1].execution_result.status).to eq(:passed)
+ end
+ end
+ end
+
+ context 'when a pipeline triggered from master runs in gitlab-qa' do
+ before do
+ stub_env('CI_PROJECT_NAME', 'gitlab-qa')
+ described_class.configure_rspec
+ end
+
+ it 'runs on master pipelines' do
+ group = describe_successfully do
+ it('runs on master pipeline given a single pipeline', only: { pipeline: :master } ) {}
+ it('runs in master given an array of pipelines', only: { pipeline: [:canary, :master] }) {}
+ it('does not run in non-master pipelines', only: { pipeline: [:nightly, :not_nightly, :not_master] } ) {}
+ end
+
+ aggregate_failures do
+ expect(group.examples[0].execution_result.status).to eq(:passed)
+ expect(group.examples[1].execution_result.status).to eq(:passed)
+ expect(group.examples[2].execution_result.status).to eq(:pending)
+ end
+ end
+ end
+
+ context 'with CI_PROJECT_NAME set' do
+ before do
+ stub_env('CI_PROJECT_NAME', 'NIGHTLY')
+ described_class.configure_rspec
+ end
+
+ it 'runs on designated pipeline' do
+ group = describe_successfully do
+ it('runs on nightly', only: { pipeline: :nightly } ) {}
+ it('does not run in not_nightly', only: { pipeline: :not_nightly } ) {}
+ it('runs on nightly given an array', only: { pipeline: [:canary, :nightly] }) {}
+ it('does not run in not_nightly given an array', only: { pipeline: [:not_nightly, :canary] }) {}
+ end
+
+ aggregate_failures do
+ expect(group.examples[0].execution_result.status).to eq(:passed)
+ expect(group.examples[1].execution_result.status).to eq(:pending)
+ expect(group.examples[2].execution_result.status).to eq(:passed)
+ expect(group.examples[3].execution_result.status).to eq(:pending)
+ end
+ end
+ end
+ end
end
end
diff --git a/qa/spec/specs/parallel_runner_spec.rb b/qa/spec/specs/parallel_runner_spec.rb
index 67d94a1f648..c2d28bf81fb 100644
--- a/qa/spec/specs/parallel_runner_spec.rb
+++ b/qa/spec/specs/parallel_runner_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-describe QA::Specs::ParallelRunner do
+RSpec.describe QA::Specs::ParallelRunner do
include Helpers::StubENV
before do
diff --git a/qa/spec/specs/runner_spec.rb b/qa/spec/specs/runner_spec.rb
index 361588fa14f..8171cfcb3e6 100644
--- a/qa/spec/specs/runner_spec.rb
+++ b/qa/spec/specs/runner_spec.rb
@@ -2,7 +2,7 @@
require 'active_support/core_ext/hash'
-describe QA::Specs::Runner do
+RSpec.describe QA::Specs::Runner do
shared_examples 'excludes orchestrated' do
it 'excludes the orchestrated tag and includes default args' do
expect_rspec_runner_arguments(['--tag', '~orchestrated', *described_class::DEFAULT_TEST_PATH_ARGS])
diff --git a/qa/spec/support/repeater_spec.rb b/qa/spec/support/repeater_spec.rb
index b5d5058ef49..18ccbf250cb 100644
--- a/qa/spec/support/repeater_spec.rb
+++ b/qa/spec/support/repeater_spec.rb
@@ -4,7 +4,7 @@ require 'logger'
require 'timecop'
require 'active_support/core_ext/integer/time'
-describe QA::Support::Repeater do
+RSpec.describe QA::Support::Repeater do
before do
logger = ::Logger.new $stdout
logger.level = ::Logger::DEBUG
diff --git a/qa/spec/support/retrier_spec.rb b/qa/spec/support/retrier_spec.rb
index ef1d53e6b65..6f052519516 100644
--- a/qa/spec/support/retrier_spec.rb
+++ b/qa/spec/support/retrier_spec.rb
@@ -3,7 +3,7 @@
require 'logger'
require 'timecop'
-describe QA::Support::Retrier do
+RSpec.describe QA::Support::Retrier do
before do
logger = ::Logger.new $stdout
logger.level = ::Logger::DEBUG
diff --git a/qa/spec/support/run_spec.rb b/qa/spec/support/run_spec.rb
new file mode 100644
index 00000000000..62eed71012e
--- /dev/null
+++ b/qa/spec/support/run_spec.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+RSpec.describe QA::Support::Run do
+ let(:class_instance) { (Class.new { include QA::Support::Run }).new }
+ let(:response) { 'successful response' }
+ let(:command) { 'some command' }
+ let(:expected_result) { described_class::Result.new("#{command} 2>&1", 0, response) }
+
+ it 'runs successfully' do
+ expect(Open3).to receive(:capture2e).and_return([+response, double(exitstatus: 0)])
+
+ expect(class_instance.run(command)).to eq(expected_result)
+ end
+
+ it 'retries twice and succeeds the third time' do
+ allow(Open3).to receive(:capture2e).and_return([+'', double(exitstatus: 1)]).twice
+ allow(Open3).to receive(:capture2e).and_return([+response, double(exitstatus: 0)])
+
+ expect(class_instance.run(command)).to eq(expected_result)
+ end
+
+ it 'raises an exception on 3rd failure' do
+ allow(Open3).to receive(:capture2e).and_return([+'FAILURE', double(exitstatus: 1)]).thrice
+
+ expect { class_instance.run(command) }.to raise_error(QA::Support::Run::CommandError, /The command .* failed \(1\) with the following output:\nFAILURE/)
+ end
+end
diff --git a/qa/spec/support/ssh_spec.rb b/qa/spec/support/ssh_spec.rb
new file mode 100644
index 00000000000..f4d382f8adc
--- /dev/null
+++ b/qa/spec/support/ssh_spec.rb
@@ -0,0 +1,114 @@
+# frozen_string_literal: true
+
+RSpec.describe QA::Support::SSH do
+ let(:key) { Struct.new(:private_key).new('private_key') }
+ let(:known_hosts_file) { Tempfile.new('known_hosts_file') }
+ let(:private_key_file) { Tempfile.new('private_key_file') }
+ let(:result) { QA::Support::Run::Result.new('', 0, '') }
+
+ let(:ssh) do
+ described_class.new.tap do |ssh|
+ ssh.uri = uri
+ ssh.key = key
+ ssh.private_key_file = private_key_file
+ ssh.known_hosts_file = known_hosts_file
+ end
+ end
+
+ shared_examples 'providing correct ports' do
+ context 'when no port specified in uri' do
+ let(:uri) { 'http://foo.com' }
+
+ it 'does not provide port in ssh command' do
+ expect(ssh).to receive(:run).with(expected_ssh_command_no_port, any_args).and_return(result)
+
+ call_method
+ end
+ end
+
+ context 'when port 80 specified in uri' do
+ let(:uri) { 'http://foo.com:80' }
+
+ it 'does not provide port in ssh command' do
+ expect(ssh).to receive(:run).with(expected_ssh_command_no_port, any_args).and_return(result)
+
+ call_method
+ end
+ end
+
+ context 'when other port is specified in uri' do
+ let(:port) { 1234 }
+ let(:uri) { "http://foo.com:#{port}" }
+
+ it "provides other port in ssh command" do
+ expect(ssh).to receive(:run).with(expected_ssh_command_port, any_args).and_return(result)
+
+ call_method
+ end
+ end
+ end
+
+ describe '#setup' do
+ let(:expected_ssh_command_no_port) { "ssh-keyscan -H foo.com >> #{known_hosts_file.path}" }
+ let(:expected_ssh_command_port) { "ssh-keyscan -H -p #{port} foo.com >> #{known_hosts_file.path}" }
+ let(:call_method) { ssh.setup }
+
+ before do
+ allow(File).to receive(:binwrite).with(private_key_file, key.private_key)
+ allow(File).to receive(:chmod).with(0700, private_key_file)
+ end
+
+ it_behaves_like 'providing correct ports'
+ end
+
+ describe '#reset_2fa_codes' do
+ let(:expected_ssh_command_no_port) { "echo yes | ssh -i #{private_key_file.path} -o UserKnownHostsFile=#{known_hosts_file.path} git@foo.com 2fa_recovery_codes" }
+ let(:expected_ssh_command_port) { "echo yes | ssh -i #{private_key_file.path} -o UserKnownHostsFile=#{known_hosts_file.path} git@foo.com -p #{port} 2fa_recovery_codes" }
+ let(:call_method) { ssh.reset_2fa_codes }
+
+ before do
+ allow(ssh).to receive(:git_user).and_return('git')
+ end
+
+ it_behaves_like 'providing correct ports'
+ end
+
+ describe '#git_user' do
+ context 'when running on CI' do
+ let(:uri) { 'http://gitlab.com' }
+
+ before do
+ allow(QA::Runtime::Env).to receive(:running_in_ci?).and_return(true)
+ end
+
+ it 'returns git user' do
+ expect(ssh.send(:git_user)).to eq('git')
+ end
+ end
+
+ context 'when running against environment on a port other than 80 or 443' do
+ let(:uri) { 'http://localhost:3000' }
+
+ before do
+ allow(Etc).to receive(:getlogin).and_return('dummy_username')
+ allow(QA::Runtime::Env).to receive(:running_in_ci?).and_return(false)
+ end
+
+ it 'returns the local user' do
+ expect(ssh.send(:git_user)).to eq('dummy_username')
+ end
+ end
+
+ context 'when running against environment on port 80 and not on CI (docker)' do
+ let(:uri) { 'http://localhost' }
+
+ before do
+ allow(QA::Runtime::Env).to receive(:running_in_ci?).and_return(false)
+ end
+
+ it 'returns git user' do
+ expect(ssh.send(:git_user)).to eq('git')
+ end
+ end
+ end
+end
diff --git a/qa/spec/support/wait_for_requests_spec.rb b/qa/spec/support/wait_for_requests_spec.rb
index 79ee3eb5099..47c35addd9f 100644
--- a/qa/spec/support/wait_for_requests_spec.rb
+++ b/qa/spec/support/wait_for_requests_spec.rb
@@ -1,9 +1,8 @@
# frozen_string_literal: true
-describe QA::Support::WaitForRequests do
+RSpec.describe QA::Support::WaitForRequests do
describe '.wait_for_requests' do
before do
- allow(subject).to receive(:finished_all_axios_requests?).and_return(true)
allow(subject).to receive(:finished_all_ajax_requests?).and_return(true)
allow(subject).to receive(:finished_loading?).and_return(true)
end
diff --git a/qa/spec/support/waiter_spec.rb b/qa/spec/support/waiter_spec.rb
index 35f1e01289a..5b0c2c95d0d 100644
--- a/qa/spec/support/waiter_spec.rb
+++ b/qa/spec/support/waiter_spec.rb
@@ -2,7 +2,7 @@
require 'logger'
-describe QA::Support::Waiter do
+RSpec.describe QA::Support::Waiter do
before do
logger = ::Logger.new $stdout
logger.level = ::Logger::DEBUG
diff --git a/rubocop/cop/api/base.rb b/rubocop/cop/api/base.rb
new file mode 100644
index 00000000000..85b19e9a833
--- /dev/null
+++ b/rubocop/cop/api/base.rb
@@ -0,0 +1,53 @@
+# frozen_string_literal: true
+
+module RuboCop
+ module Cop
+ module API
+ class Base < RuboCop::Cop::Cop
+ # This cop checks that APIs subclass API::Base.
+ #
+ # @example
+ #
+ # # bad
+ # module API
+ # class Projects < Grape::API
+ # end
+ # end
+ #
+ # module API
+ # class Projects < Grape::API::Instance
+ # end
+ # end
+ #
+ # # good
+ # module API
+ # class Projects < ::API::Base
+ # end
+ # end
+ MSG = 'Inherit from ::API::Base instead of Grape::API::Instance or Grape::API. ' \
+ 'For more details check https://gitlab.com/gitlab-org/gitlab/-/issues/215230.'
+
+ def_node_matcher :grape_api, '(const (const {nil? (cbase)} :Grape) :API)'
+ def_node_matcher :grape_api_definition, <<~PATTERN
+ (class
+ (const _ _)
+ {#grape_api (const #grape_api :Instance)}
+ ...
+ )
+ PATTERN
+
+ def on_class(node)
+ grape_api_definition(node) do
+ add_offense(node.children[1])
+ end
+ end
+
+ def autocorrect(node)
+ lambda do |corrector|
+ corrector.replace(node, '::API::Base')
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/rubocop/cop/api/grape_api_instance.rb b/rubocop/cop/api/grape_api_instance.rb
deleted file mode 100644
index de11b9ef3f6..00000000000
--- a/rubocop/cop/api/grape_api_instance.rb
+++ /dev/null
@@ -1,42 +0,0 @@
-# frozen_string_literal: true
-
-module RuboCop
- module Cop
- module API
- class GrapeAPIInstance < RuboCop::Cop::Cop
- # This cop checks that APIs subclass Grape::API::Instance with Grape v1.3+.
- #
- # @example
- #
- # # bad
- # module API
- # class Projects < Grape::API
- # end
- # end
- #
- # # good
- # module API
- # class Projects < Grape::API::Instance
- # end
- # end
- MSG = 'Inherit from Grape::API::Instance instead of Grape::API. ' \
- 'For more details check the https://gitlab.com/gitlab-org/gitlab/-/issues/215230.'
-
- def_node_matcher :grape_api_definition, <<~PATTERN
- (class
- (const _ _)
- (const
- (const nil? :Grape) :API)
- ...
- )
- PATTERN
-
- def on_class(node)
- grape_api_definition(node) do
- add_offense(node.children[1])
- end
- end
- end
- end
- end
-end
diff --git a/rubocop/cop/code_reuse/active_record.rb b/rubocop/cop/code_reuse/active_record.rb
index 8c77c292315..f6b5d66647d 100644
--- a/rubocop/cop/code_reuse/active_record.rb
+++ b/rubocop/cop/code_reuse/active_record.rb
@@ -5,20 +5,20 @@ require_relative '../../code_reuse_helpers'
module RuboCop
module Cop
module CodeReuse
- # Cop that blacklists the use of ActiveRecord methods outside of models.
+ # Cop that denies the use of ActiveRecord methods outside of models.
class ActiveRecord < RuboCop::Cop::Cop
include CodeReuseHelpers
MSG = 'This method can only be used inside an ActiveRecord model: ' \
'https://gitlab.com/gitlab-org/gitlab-foss/issues/49653'
- # Various methods from ActiveRecord::Querying that are blacklisted. We
+ # Various methods from ActiveRecord::Querying that are denied. We
# exclude some generic ones such as `any?` and `first`, as these may
# lead to too many false positives, since `Array` also supports these
# methods.
#
- # The keys of this Hash are the blacklisted method names. The values are
- # booleans that indicate if the method should only be blacklisted if any
+ # The keys of this Hash are the denied method names. The values are
+ # booleans that indicate if the method should only be denied if any
# arguments are provided.
NOT_ALLOWED = {
average: true,
@@ -57,7 +57,6 @@ module RuboCop
references: true,
reorder: true,
rewhere: true,
- sum: false,
take: false,
take!: false,
unscope: false,
@@ -65,9 +64,9 @@ module RuboCop
with: true
}.freeze
- # Directories that allow the use of the blacklisted methods. These
+ # Directories that allow the use of the denied methods. These
# directories are checked relative to both . and ee/
- WHITELISTED_DIRECTORIES = %w[
+ ALLOWED_DIRECTORIES = %w[
app/models
config
danger
@@ -88,7 +87,7 @@ module RuboCop
].freeze
def on_send(node)
- return if in_whitelisted_directory?(node)
+ return if in_allowed_directory?(node)
receiver = node.children[0]
send_name = node.children[1]
@@ -105,12 +104,12 @@ module RuboCop
end
end
- # Returns true if the node resides in one of the whitelisted
+ # Returns true if the node resides in one of the allowed
# directories.
- def in_whitelisted_directory?(node)
+ def in_allowed_directory?(node)
path = file_path_for_node(node)
- WHITELISTED_DIRECTORIES.any? do |directory|
+ ALLOWED_DIRECTORIES.any? do |directory|
path.start_with?(
File.join(rails_root, directory),
File.join(rails_root, 'ee', directory)
@@ -119,12 +118,12 @@ module RuboCop
end
# We can not auto correct code like this, as it requires manual
- # refactoring. Instead, we'll just whitelist the surrounding scope.
+ # refactoring. Instead, we'll just allow the surrounding scope.
#
# Despite this method's presence, you should not use it. This method
- # exists to make it possible to whitelist large chunks of offenses we
+ # exists to make it possible to allow large chunks of offenses we
# can't fix in the short term. If you are writing new code, follow the
- # code reuse guidelines, instead of whitelisting any new offenses.
+ # code reuse guidelines, instead of allowing any new offenses.
def autocorrect(node)
scope = surrounding_scope_of(node)
indent = indentation_of(scope)
@@ -132,7 +131,7 @@ module RuboCop
lambda do |corrector|
# This prevents us from inserting the same enable/disable comment
# for a method or block that has multiple offenses.
- next if whitelisted_scopes.include?(scope)
+ next if allowed_scopes.include?(scope)
corrector.insert_before(
scope.source_range,
@@ -144,7 +143,7 @@ module RuboCop
"\n#{indent}# rubocop: enable #{cop_name}"
)
- whitelisted_scopes << scope
+ allowed_scopes << scope
end
end
@@ -160,8 +159,8 @@ module RuboCop
end
end
- def whitelisted_scopes
- @whitelisted_scopes ||= Set.new
+ def allowed_scopes
+ @allowed_scopes ||= Set.new
end
end
end
diff --git a/rubocop/cop/graphql/gid_expected_type.rb b/rubocop/cop/graphql/gid_expected_type.rb
new file mode 100644
index 00000000000..354c5516752
--- /dev/null
+++ b/rubocop/cop/graphql/gid_expected_type.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+module RuboCop
+ module Cop
+ module Graphql
+ class GIDExpectedType < RuboCop::Cop::Cop
+ MSG = 'Add an expected_type parameter to #object_from_id calls if possible.'
+
+ def_node_search :id_from_object?, <<~PATTERN
+ (send ... :object_from_id (...))
+ PATTERN
+
+ def on_send(node)
+ return unless id_from_object?(node)
+
+ add_offense(node)
+ end
+ end
+ end
+ end
+end
diff --git a/rubocop/cop/graphql/id_type.rb b/rubocop/cop/graphql/id_type.rb
new file mode 100644
index 00000000000..96f90ac136a
--- /dev/null
+++ b/rubocop/cop/graphql/id_type.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+module RuboCop
+ module Cop
+ module Graphql
+ class IDType < RuboCop::Cop::Cop
+ MSG = 'Do not use GraphQL::ID_TYPE, use a specific GlobalIDType instead'
+
+ WHITELISTED_ARGUMENTS = %i[iid full_path project_path group_path target_project_path].freeze
+
+ def_node_search :graphql_id_type?, <<~PATTERN
+ (send nil? :argument (_ #does_not_match?) (const (const nil? :GraphQL) :ID_TYPE) ...)
+ PATTERN
+
+ def on_send(node)
+ return unless graphql_id_type?(node)
+
+ add_offense(node)
+ end
+
+ private
+
+ def does_not_match?(arg)
+ !WHITELISTED_ARGUMENTS.include?(arg)
+ end
+ end
+ end
+ end
+end
diff --git a/rubocop/cop/migration/add_concurrent_foreign_key.rb b/rubocop/cop/migration/add_concurrent_foreign_key.rb
index 236de6224a4..31cf426b2d4 100644
--- a/rubocop/cop/migration/add_concurrent_foreign_key.rb
+++ b/rubocop/cop/migration/add_concurrent_foreign_key.rb
@@ -11,7 +11,11 @@ module RuboCop
MSG = '`add_foreign_key` requires downtime, use `add_concurrent_foreign_key` instead'.freeze
def_node_matcher :false_node?, <<~PATTERN
- (false)
+ (false)
+ PATTERN
+
+ def_node_matcher :with_lock_retries?, <<~PATTERN
+ (:send nil? :with_lock_retries)
PATTERN
def on_send(node)
@@ -19,9 +23,11 @@ module RuboCop
name = node.children[1]
- if name == :add_foreign_key && !not_valid_fk?(node)
- add_offense(node, location: :selector)
- end
+ return unless name == :add_foreign_key
+ return if in_with_lock_retries?(node)
+ return if not_valid_fk?(node)
+
+ add_offense(node, location: :selector)
end
def method_name(node)
@@ -33,6 +39,12 @@ module RuboCop
pair.children[0].children[0] == :validate && false_node?(pair.children[1])
end
end
+
+ def in_with_lock_retries?(node)
+ node.each_ancestor(:block).any? do |parent|
+ with_lock_retries?(parent.to_a.first)
+ end
+ end
end
end
end
diff --git a/rubocop/cop/migration/add_limit_to_text_columns.rb b/rubocop/cop/migration/add_limit_to_text_columns.rb
index b578e73f19e..b2e37ad5137 100644
--- a/rubocop/cop/migration/add_limit_to_text_columns.rb
+++ b/rubocop/cop/migration/add_limit_to_text_columns.rb
@@ -6,6 +6,10 @@ module RuboCop
module Cop
module Migration
# Cop that enforces always adding a limit on text columns
+ #
+ # Text columns starting with `encrypted_` are very likely used
+ # by `attr_encrypted` which controls the text length. Those columns
+ # should not add a text limit.
class AddLimitToTextColumns < RuboCop::Cop::Cop
include MigrationHelpers
@@ -102,6 +106,8 @@ module RuboCop
# Check if there is an `add_text_limit` call for the provided
# table and attribute name
def text_limit_missing?(node, table_name, attribute_name)
+ return false if encrypted_attribute_name?(attribute_name)
+
limit_found = false
node.each_descendant(:send) do |send_node|
@@ -118,6 +124,10 @@ module RuboCop
!limit_found
end
+
+ def encrypted_attribute_name?(attribute_name)
+ attribute_name.to_s.start_with?('encrypted_')
+ end
end
end
end
diff --git a/rubocop/cop/migration/create_table_with_foreign_keys.rb b/rubocop/cop/migration/create_table_with_foreign_keys.rb
index 01cab032049..382a2d6f65b 100644
--- a/rubocop/cop/migration/create_table_with_foreign_keys.rb
+++ b/rubocop/cop/migration/create_table_with_foreign_keys.rb
@@ -9,7 +9,7 @@ module RuboCop
include MigrationHelpers
MSG = 'Creating a table with more than one foreign key at once violates our migration style guide. ' \
- 'For more details check the https://docs.gitlab.com/ce/development/migration_style_guide.html#examples'
+ 'For more details check the https://docs.gitlab.com/ee/development/migration_style_guide.html#examples'
def_node_matcher :create_table_with_block?, <<~PATTERN
(block
diff --git a/rubocop/cop/migration/with_lock_retries_disallowed_method.rb b/rubocop/cop/migration/with_lock_retries_disallowed_method.rb
index a89c33c298b..aef19517a9d 100644
--- a/rubocop/cop/migration/with_lock_retries_disallowed_method.rb
+++ b/rubocop/cop/migration/with_lock_retries_disallowed_method.rb
@@ -29,9 +29,14 @@ module RuboCop
].sort.freeze
MSG = "The method is not allowed to be called within the `with_lock_retries` block, the only allowed methods are: #{ALLOWED_MIGRATION_METHODS.join(', ')}"
+ MSG_ONLY_ONE_FK_ALLOWED = "Avoid adding more than one foreign key within the `with_lock_retries`. See https://docs.gitlab.com/ee/development/migration_style_guide.html#examples"
def_node_matcher :send_node?, <<~PATTERN
- send
+ send
+ PATTERN
+
+ def_node_matcher :add_foreign_key?, <<~PATTERN
+ (send nil? :add_foreign_key ...)
PATTERN
def on_block(node)
@@ -53,6 +58,17 @@ module RuboCop
name = node.children[1]
add_offense(node, location: :expression) unless ALLOWED_MIGRATION_METHODS.include?(name)
+ add_offense(node, location: :selector, message: MSG_ONLY_ONE_FK_ALLOWED) if multiple_fks?(node)
+ end
+
+ def multiple_fks?(node)
+ return unless add_foreign_key?(node)
+
+ count = node.parent.each_descendant(:send).count do |node|
+ add_foreign_key?(node)
+ end
+
+ count > 1
end
end
end
diff --git a/rubocop/cop/rspec/expect_gitlab_tracking.rb b/rubocop/cop/rspec/expect_gitlab_tracking.rb
new file mode 100644
index 00000000000..ba658558705
--- /dev/null
+++ b/rubocop/cop/rspec/expect_gitlab_tracking.rb
@@ -0,0 +1,66 @@
+# frozen_string_literal: true
+
+require 'rack/utils'
+
+module RuboCop
+ module Cop
+ module RSpec
+ # This cop checks for `expect(Gitlab::Tracking).to receive(:event)` usage in specs.
+ # See /spec/support/helpers/snowplow_helpers.rb for details on the replacement.
+ #
+ # @example
+ #
+ # # bad
+ # it 'expects a snowplow event' do
+ # expect(Gitlab::Tracking).to receive(:event).with("Category", "action", ...)
+ # end
+ #
+ # # good
+ # it 'expects a snowplow event', :snowplow do
+ # expect_snowplow_event(category: "Category", action: "action", ...)
+ # end
+ #
+ # # bad
+ # it 'does not expect a snowplow event' do
+ # expect(Gitlab::Tracking).not_to receive(:event)
+ # end
+ #
+ # # good
+ # it 'does not expect a snowplow event', :snowplow do
+ # expect_no_snowplow_event
+ # end
+ class ExpectGitlabTracking < RuboCop::Cop::Cop
+ MSG = 'Do not expect directly on `Gitlab::Tracking#event`, add the `snowplow` annotation and use ' \
+ '`expect_snowplow_event` instead. ' \
+ 'See https://docs.gitlab.com/ee/development/testing_guide/best_practices.html#test-snowplow-events'
+
+ def_node_matcher :expect_gitlab_tracking?, <<~PATTERN
+ (send
+ (send nil? {:expect :allow}
+ (const (const nil? :Gitlab) :Tracking)
+ )
+ ${:to :to_not :not_to}
+ {
+ (
+ send nil? {:receive :have_received} (sym :event) ...
+ )
+
+ (send
+ (send nil? {:receive :have_received} (sym :event)) ...
+ )
+ }
+ ...
+ )
+ PATTERN
+
+ RESTRICT_ON_SEND = [:expect, :allow].freeze
+
+ def on_send(node)
+ return unless expect_gitlab_tracking?(node)
+
+ add_offense(node)
+ end
+ end
+ end
+ end
+end
diff --git a/rubocop/cop/rspec/factory_bot/inline_association.rb b/rubocop/cop/rspec/factory_bot/inline_association.rb
new file mode 100644
index 00000000000..1c2b8b55b46
--- /dev/null
+++ b/rubocop/cop/rspec/factory_bot/inline_association.rb
@@ -0,0 +1,109 @@
+# frozen_string_literal: true
+
+module RuboCop
+ module Cop
+ module RSpec
+ module FactoryBot
+ # This cop encourages the use of inline associations in FactoryBot.
+ # The explicit use of `create` and `build` is discouraged.
+ #
+ # See https://github.com/thoughtbot/factory_bot/blob/master/GETTING_STARTED.md#inline-definition
+ #
+ # @example
+ #
+ # Context:
+ #
+ # Factory.define do
+ # factory :project, class: 'Project'
+ # # EXAMPLE below
+ # end
+ # end
+ #
+ # # bad
+ # creator { create(:user) }
+ # creator { create(:user, :admin) }
+ # creator { build(:user) }
+ # creator { FactoryBot.build(:user) }
+ # creator { ::FactoryBot.build(:user) }
+ # add_attribute(:creator) { build(:user) }
+ #
+ # # good
+ # creator { association(:user) }
+ # creator { association(:user, :admin) }
+ # add_attribute(:creator) { association(:user) }
+ #
+ # # Accepted
+ # after(:build) do |instance|
+ # instance.creator = create(:user)
+ # end
+ #
+ # initialize_with do
+ # create(:project)
+ # end
+ #
+ # creator_id { create(:user).id }
+ #
+ class InlineAssociation < RuboCop::Cop::Cop
+ MSG = 'Prefer inline `association` over `%{type}`. ' \
+ 'See https://docs.gitlab.com/ee/development/testing_guide/best_practices.html#factories'
+
+ REPLACEMENT = 'association'
+
+ def_node_matcher :create_or_build, <<~PATTERN
+ (
+ send
+ ${ nil? (const { nil? (cbase) } :FactoryBot) }
+ ${ :create :build }
+ (sym _)
+ ...
+ )
+ PATTERN
+
+ def_node_matcher :association_definition, <<~PATTERN
+ (block
+ {
+ (send nil? $_)
+ (send nil? :add_attribute (sym $_))
+ }
+ ...
+ )
+ PATTERN
+
+ def_node_matcher :chained_call?, <<~PATTERN
+ (send _ _)
+ PATTERN
+
+ SKIP_NAMES = %i[initialize_with].to_set.freeze
+
+ def on_send(node)
+ _receiver, type = create_or_build(node)
+ return unless type
+ return if chained_call?(node.parent)
+ return unless inside_assocation_definition?(node)
+
+ add_offense(node, message: format(MSG, type: type))
+ end
+
+ def autocorrect(node)
+ lambda do |corrector|
+ receiver, type = create_or_build(node)
+ receiver = "#{receiver.source}." if receiver
+ expression = "#{receiver}#{type}"
+ replacement = node.source.sub(expression, REPLACEMENT)
+ corrector.replace(node.source_range, replacement)
+ end
+ end
+
+ private
+
+ def inside_assocation_definition?(node)
+ node.each_ancestor(:block).any? do |parent|
+ name = association_definition(parent)
+ name && !SKIP_NAMES.include?(name)
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/rubocop/cop/rspec/timecop_travel.rb b/rubocop/cop/rspec/timecop_travel.rb
new file mode 100644
index 00000000000..e5416953af7
--- /dev/null
+++ b/rubocop/cop/rspec/timecop_travel.rb
@@ -0,0 +1,41 @@
+# frozen_string_literal: true
+
+module RuboCop
+ module Cop
+ module RSpec
+ # This cop checks for `Timecop.travel` usage in specs.
+ #
+ # @example
+ #
+ # # bad
+ # Timecop.travel(1.day.ago) { create(:issue) }
+ #
+ # # good
+ # travel_to(1.day.ago) { create(:issue) }
+ #
+ class TimecopTravel < RuboCop::Cop::Cop
+ include MatchRange
+ MESSAGE = 'Do not use `Timecop.travel`, use `travel_to` instead. ' \
+ 'See https://gitlab.com/gitlab-org/gitlab/-/issues/214432 for more info.'
+
+ def_node_matcher :timecop_travel?, <<~PATTERN
+ (send (const nil? :Timecop) :travel _)
+ PATTERN
+
+ def on_send(node)
+ return unless timecop_travel?(node)
+
+ add_offense(node, location: :expression, message: MESSAGE)
+ end
+
+ def autocorrect(node)
+ -> (corrector) do
+ each_match_range(node.source_range, /^(Timecop\.travel)/) do |match_range|
+ corrector.replace(match_range, 'travel_to')
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/rubocop/migration_helpers.rb b/rubocop/migration_helpers.rb
index c26ba88f269..e9533fb65b2 100644
--- a/rubocop/migration_helpers.rb
+++ b/rubocop/migration_helpers.rb
@@ -21,7 +21,7 @@ module RuboCop
TABLE_METHODS = %i(create_table create_table_if_not_exists change_table).freeze
def high_traffic_tables
- @high_traffic_tables ||= rubocop_migrations_config.dig('Migration/UpdateLargeTable', 'DeniedTables')
+ @high_traffic_tables ||= rubocop_migrations_config.dig('Migration/UpdateLargeTable', 'HighTrafficTables')
end
# Returns true if the given node originated from the db/migrate directory.
diff --git a/rubocop/rubocop-migrations.yml b/rubocop/rubocop-migrations.yml
index a919d570ccc..f8ff6e005f9 100644
--- a/rubocop/rubocop-migrations.yml
+++ b/rubocop/rubocop-migrations.yml
@@ -1,6 +1,7 @@
+# Make sure to update the docs if this file moves. Docs URL: https://docs.gitlab.com/ee/development/migration_style_guide.html#when-to-use-the-helper-method
Migration/UpdateLargeTable:
Enabled: true
- DeniedTables: &denied_tables # size in GB (>= 10 GB on GitLab.com as of 02/2020) and/or number of records
+ HighTrafficTables: &high_traffic_tables # size in GB (>= 10 GB on GitLab.com as of 02/2020) and/or number of records
- :audit_events
- :ci_build_trace_sections
- :ci_builds
diff --git a/rubocop/rubocop-usage-data.yml b/rubocop/rubocop-usage-data.yml
index 9f594bc5817..fdfe2a5e1aa 100644
--- a/rubocop/rubocop-usage-data.yml
+++ b/rubocop/rubocop-usage-data.yml
@@ -25,6 +25,8 @@ UsageData/LargeTable:
- :Time
- :SECURE_PRODUCT_TYPES
- :Settings
+ - :CE_MEMOIZED_VALUES
+ - :EE_MEMOIZED_VALUES
CountMethods:
- :count
- :distinct_count
diff --git a/scripts/docs_screenshots.rb b/scripts/docs_screenshots.rb
index e02d67de748..7472d9ea37b 100755
--- a/scripts/docs_screenshots.rb
+++ b/scripts/docs_screenshots.rb
@@ -22,7 +22,7 @@ end
def rename_image(file, milestone)
path = File.dirname(file)
- basename = File.basename(file)
+ basename = File.basename(file, ".*")
final_name = File.join(path, "#{basename}_v#{milestone}.png")
FileUtils.mv(file, final_name)
end
diff --git a/scripts/lint-doc.sh b/scripts/lint-doc.sh
index 4886323c836..87256269de2 100755
--- a/scripts/lint-doc.sh
+++ b/scripts/lint-doc.sh
@@ -40,8 +40,8 @@ then
fi
# Do not use 'README.md', instead use 'index.md'
-# Number of 'README.md's as of 2020-05-28
-NUMBER_READMES=44
+# Number of 'README.md's as of 2020-10-13
+NUMBER_READMES=36
FIND_READMES=$(find doc/ -name "README.md" | wc -l)
echo '=> Checking for new README.md files...'
echo
@@ -77,7 +77,7 @@ function run_locally_or_in_docker() {
$cmd $args
elif hash docker 2>/dev/null
then
- docker run -t -v ${PWD}:/gitlab -w /gitlab --rm registry.gitlab.com/gitlab-org/gitlab-docs:lint ${cmd} ${args}
+ docker run -t -v ${PWD}:/gitlab -w /gitlab --rm registry.gitlab.com/gitlab-org/gitlab-docs/lint:latest ${cmd} ${args}
else
echo
echo " ✖ ERROR: '${cmd}' not found. Install '${cmd}' or Docker to proceed." >&2
diff --git a/scripts/prepare_build.sh b/scripts/prepare_build.sh
index 1243609dc24..e95f20bc26c 100644
--- a/scripts/prepare_build.sh
+++ b/scripts/prepare_build.sh
@@ -2,7 +2,7 @@
export SETUP_DB=${SETUP_DB:-true}
export USE_BUNDLE_INSTALL=${USE_BUNDLE_INSTALL:-true}
-export BUNDLE_INSTALL_FLAGS=${BUNDLE_INSTALL_FLAGS:-"--without=production --without=development --jobs=$(nproc) --path=vendor --retry=3 --quiet"}
+export BUNDLE_INSTALL_FLAGS=${BUNDLE_INSTALL_FLAGS:-"--without=production development --jobs=$(nproc) --path=vendor --retry=3 --quiet"}
if [ "$USE_BUNDLE_INSTALL" != "false" ]; then
bundle --version
@@ -14,10 +14,6 @@ if [ "$USE_BUNDLE_INSTALL" != "false" ]; then
run_timed_command "bundle pristine pg"
fi
-# Only install knapsack after bundle install! Otherwise oddly some native
-# gems could not be found under some circumstance. No idea why, hours wasted.
-run_timed_command "gem install knapsack --no-document"
-
cp config/gitlab.yml.example config/gitlab.yml
sed -i 's/bin_path: \/usr\/bin\/git/bin_path: \/usr\/local\/bin\/git/' config/gitlab.yml
diff --git a/scripts/review_apps/review-apps.sh b/scripts/review_apps/review-apps.sh
index 862c3b4bb62..b8cbe625e5b 100755
--- a/scripts/review_apps/review-apps.sh
+++ b/scripts/review_apps/review-apps.sh
@@ -48,7 +48,13 @@ function delete_release() {
return
fi
- helm_delete_release "${namespace}" "${release}"
+ # Check if helm release exists before attempting to delete
+ # There may be situation where k8s resources exist, but helm release does not,
+ # for example, following a failed helm install.
+ # In such cases, we still want to continue to clean up k8s resources.
+ if deploy_exists "${namespace}" "${release}"; then
+ helm_delete_release "${namespace}" "${release}"
+ fi
kubectl_cleanup_release "${namespace}" "${release}"
}
@@ -131,7 +137,7 @@ function run_task() {
local ruby_cmd="${1}"
local task_runner_pod=$(get_pod "task-runner")
- kubectl exec -it --namespace "${namespace}" "${task_runner_pod}" -- gitlab-rails runner "${ruby_cmd}"
+ kubectl exec --namespace "${namespace}" "${task_runner_pod}" -- gitlab-rails runner "${ruby_cmd}"
}
function disable_sign_ups() {
@@ -144,7 +150,7 @@ function disable_sign_ups() {
# Create the root token
local ruby_cmd="token = User.find_by_username('root').personal_access_tokens.create(scopes: [:api], name: 'Token to disable sign-ups'); token.set_token('${REVIEW_APPS_ROOT_TOKEN}'); begin; token.save!; rescue(ActiveRecord::RecordNotUnique); end"
- run_task "${ruby_cmd}"
+ retry "run_task \"${ruby_cmd}\""
# Disable sign-ups
local signup_enabled=$(retry 'curl --silent --show-error --request PUT --header "PRIVATE-TOKEN: ${REVIEW_APPS_ROOT_TOKEN}" "${CI_ENVIRONMENT_URL}/api/v4/application/settings?signup_enabled=false" | jq ".signup_enabled"')
diff --git a/scripts/slack b/scripts/slack
index 60bc70a8542..293f8070504 100755
--- a/scripts/slack
+++ b/scripts/slack
@@ -1,6 +1,5 @@
#!/bin/bash
-# This is copied from:
-# https://gitlab.com/gitlab-org/gitlab-qa/-/blob/master/bin/slack
+# This is based on https://gitlab.com/gitlab-org/gitlab-qa/-/blob/master/bin/slack
#
# Sends Slack notification MSG to CI_SLACK_WEBHOOK_URL (which needs to be set).
# ICON_EMOJI needs to be set to an icon emoji name (without the `:` around it).
@@ -8,10 +7,11 @@
CHANNEL=$1
MSG=$2
ICON_EMOJI=$3
+USERNAME=$4
-if [ -z "$CHANNEL" ] || [ -z "$CI_SLACK_WEBHOOK_URL" ] || [ -z "$MSG" ] || [ -z "$ICON_EMOJI" ]; then
- echo "Missing argument(s) - Use: $0 channel message icon_emoji"
+if [ -z "$CHANNEL" ] || [ -z "$CI_SLACK_WEBHOOK_URL" ] || [ -z "$MSG" ] || [ -z "$ICON_EMOJI" ] || [ -z "$USERNAME" ]; then
+ echo "Missing argument(s) - Use: $0 channel message icon_emoji username"
echo "and set CI_SLACK_WEBHOOK_URL environment variable."
else
- curl -X POST --data-urlencode 'payload={"channel": "#'"$CHANNEL"'", "username": "GitLab QA Bot", "text": "'"$MSG"'", "icon_emoji": "'":$ICON_EMOJI:"'"}' "$CI_SLACK_WEBHOOK_URL"
+ curl -X POST --data-urlencode 'payload={"channel": "#'"$CHANNEL"'", "username": "'"$USERNAME"'", "text": "'"$MSG"'", "icon_emoji": "'":$ICON_EMOJI:"'"}' "$CI_SLACK_WEBHOOK_URL"
fi
diff --git a/scripts/used-feature-flags b/scripts/used-feature-flags
new file mode 100755
index 00000000000..07b8d2063ef
--- /dev/null
+++ b/scripts/used-feature-flags
@@ -0,0 +1,94 @@
+#!/usr/bin/env ruby
+
+class String
+ def red
+ "\e[31m#{self}\e[0m"
+ end
+
+ def yellow
+ "\e[33m#{self}\e[0m"
+ end
+
+ def green
+ "\e[32m#{self}\e[0m"
+ end
+
+ def bold
+ "\e[1m#{self}\e[0m"
+ end
+end
+
+flags_paths = [
+ 'config/feature_flags/**/*.yml'
+]
+
+# For EE additionally process `ee/` feature flags
+if File.exist?('ee/app/models/license.rb') && !%w[true 1].include?(ENV['FOSS_ONLY'].to_s)
+ flags_paths << 'ee/config/feature_flags/**/*.yml'
+end
+
+all_flags = {}
+additional_flags = Set.new
+
+# Iterate all defined feature flags
+# to discover which were used
+flags_paths.each do |flags_path|
+ puts flags_path
+ Dir.glob(flags_path).each do |path|
+ feature_flag_name = File.basename(path, '.yml')
+
+ all_flags[feature_flag_name] = File.exist?(File.join('tmp', 'feature_flags', feature_flag_name + '.used'))
+ end
+end
+
+# Iterate all used feature flags
+# to discover which flags are undefined
+Dir.glob('tmp/feature_flags/*.used').each do |path|
+ feature_flag_name = File.basename(path, '.used')
+
+ additional_flags.add(feature_flag_name) unless all_flags[feature_flag_name]
+end
+
+used_flags = all_flags.select { |name, used| used }
+unused_flags = all_flags.reject { |name, used| used }
+
+puts "=========================================".green.bold
+puts "Feature Flags usage summary:".green.bold
+puts
+
+puts "- #{all_flags.count + additional_flags.count} was found"
+puts "- #{unused_flags.count} appear(s) to be UNUSED".yellow
+puts "- #{additional_flags.count} appear(s) to be unknown".yellow
+puts "- #{used_flags.count} appear(s) to be used".green
+puts
+
+if additional_flags.count > 0
+ puts "==================================================".green.bold
+ puts "There are feature flags that appears 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
+ puts
+ additional_flags.sort.each do |name|
+ puts "- #{name}".yellow
+ end
+ puts
+end
+
+if unused_flags.count > 0
+ puts "========================================".green.bold
+ puts "These feature flags appears 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
+ puts
+ unused_flags.keys.sort.each do |name|
+ puts "- #{name}".yellow
+ end
+ puts
+ puts "Feature flag usage check failed.".red.bold
+ exit(1)
+end
+
+puts "Everything is fine here!".green
+puts
diff --git a/spec/bin/feature_flag_spec.rb b/spec/bin/feature_flag_spec.rb
index 41117880f95..185a03fc587 100644
--- a/spec/bin/feature_flag_spec.rb
+++ b/spec/bin/feature_flag_spec.rb
@@ -240,5 +240,18 @@ RSpec.describe 'bin/feature-flag' do
end
end
end
+
+ describe '.read_ee_only' do
+ where(:type, :is_ee_only) do
+ :development | false
+ :licensed | true
+ end
+
+ with_them do
+ let(:options) { OpenStruct.new(name: 'foo', type: type) }
+
+ it { expect(described_class.read_ee_only(options)).to eq(is_ee_only) }
+ end
+ end
end
end
diff --git a/spec/channels/application_cable/connection_spec.rb b/spec/channels/application_cable/connection_spec.rb
index e5f7ea1103c..7d60548f780 100644
--- a/spec/channels/application_cable/connection_spec.rb
+++ b/spec/channels/application_cable/connection_spec.rb
@@ -5,27 +5,39 @@ require 'spec_helper'
RSpec.describe ApplicationCable::Connection, :clean_gitlab_redis_shared_state do
let(:session_id) { Rack::Session::SessionId.new('6919a6f1bb119dd7396fadc38fd18d0d') }
- before do
- Gitlab::Redis::SharedState.with do |redis|
- redis.set("session:gitlab:#{session_id.private_id}", Marshal.dump(session_hash))
+ context 'when session cookie is set' do
+ before do
+ Gitlab::Redis::SharedState.with do |redis|
+ redis.set("session:gitlab:#{session_id.private_id}", Marshal.dump(session_hash))
+ end
+
+ cookies[Gitlab::Application.config.session_options[:key]] = session_id.public_id
end
- cookies[Gitlab::Application.config.session_options[:key]] = session_id.public_id
- end
+ context 'when user is logged in' do
+ let(:user) { create(:user) }
+ let(:session_hash) { { 'warden.user.user.key' => [[user.id], user.encrypted_password[0, 29]] } }
+
+ it 'sets current_user' do
+ connect
+
+ expect(connection.current_user).to eq(user)
+ end
- context 'when user is logged in' do
- let(:user) { create(:user) }
- let(:session_hash) { { 'warden.user.user.key' => [[user.id], user.encrypted_password[0, 29]] } }
+ context 'with a stale password' do
+ let(:partial_password_hash) { build(:user, password: 'some_old_password').encrypted_password[0, 29] }
+ let(:session_hash) { { 'warden.user.user.key' => [[user.id], partial_password_hash] } }
- it 'sets current_user' do
- connect
+ it 'sets current_user to nil' do
+ connect
- expect(connection.current_user).to eq(user)
+ expect(connection.current_user).to be_nil
+ end
+ end
end
- context 'with a stale password' do
- let(:partial_password_hash) { build(:user, password: 'some_old_password').encrypted_password[0, 29] }
- let(:session_hash) { { 'warden.user.user.key' => [[user.id], partial_password_hash] } }
+ context 'when user is not logged in' do
+ let(:session_hash) { {} }
it 'sets current_user to nil' do
connect
@@ -35,10 +47,18 @@ RSpec.describe ApplicationCable::Connection, :clean_gitlab_redis_shared_state do
end
end
- context 'when user is not logged in' do
- let(:session_hash) { {} }
+ context 'when session cookie is not set' do
+ it 'sets current_user to nil' do
+ connect
+
+ expect(connection.current_user).to be_nil
+ end
+ end
+ context 'when session cookie is an empty string' do
it 'sets current_user to nil' do
+ cookies[Gitlab::Application.config.session_options[:key]] = ''
+
connect
expect(connection.current_user).to be_nil
diff --git a/spec/config/object_store_settings_spec.rb b/spec/config/object_store_settings_spec.rb
index 36938c74afa..430ba1205cb 100644
--- a/spec/config/object_store_settings_spec.rb
+++ b/spec/config/object_store_settings_spec.rb
@@ -24,6 +24,7 @@ RSpec.describe ObjectStoreSettings do
'lfs' => { 'enabled' => true },
'artifacts' => { 'enabled' => true },
'external_diffs' => { 'enabled' => false },
+ 'pages' => { 'enabled' => true },
'object_store' => {
'enabled' => true,
'connection' => connection,
@@ -39,6 +40,9 @@ RSpec.describe ObjectStoreSettings do
'external_diffs' => {
'bucket' => 'external_diffs',
'enabled' => false
+ },
+ 'pages' => {
+ 'bucket' => 'pages'
}
}
}
@@ -64,6 +68,11 @@ RSpec.describe ObjectStoreSettings do
expect(settings.lfs['object_store']['proxy_download']).to be true
expect(settings.lfs['object_store']['remote_directory']).to eq('lfs-objects')
+ expect(settings.pages['enabled']).to be true
+ expect(settings.pages['object_store']['enabled']).to be true
+ expect(settings.pages['object_store']['connection']).to eq(connection)
+ expect(settings.pages['object_store']['remote_directory']).to eq('pages')
+
expect(settings.external_diffs['enabled']).to be false
expect(settings.external_diffs['object_store']['enabled']).to be false
expect(settings.external_diffs['object_store']['remote_directory']).to eq('external_diffs')
@@ -75,6 +84,12 @@ RSpec.describe ObjectStoreSettings do
expect { subject }.to raise_error(/Object storage for lfs must have a bucket specified/)
end
+ it 'does not raise error if pages bucket is missing' do
+ config['object_store']['objects']['pages'].delete('bucket')
+
+ expect { subject }.not_to raise_error
+ end
+
context 'with legacy config' do
let(:legacy_settings) do
{
diff --git a/spec/controllers/admin/application_settings_controller_spec.rb b/spec/controllers/admin/application_settings_controller_spec.rb
index 4f223811be8..f71f859a704 100644
--- a/spec/controllers/admin/application_settings_controller_spec.rb
+++ b/spec/controllers/admin/application_settings_controller_spec.rb
@@ -15,6 +15,37 @@ RSpec.describe Admin::ApplicationSettingsController do
stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false')
end
+ describe 'GET #integrations' do
+ before do
+ sign_in(admin)
+ end
+
+ context 'when GitLab.com' do
+ before do
+ allow(::Gitlab).to receive(:com?) { true }
+ end
+
+ it 'returns 404' do
+ get :integrations
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+
+ context 'when not GitLab.com' do
+ before do
+ allow(::Gitlab).to receive(:com?) { false }
+ end
+
+ it 'renders correct template' do
+ get :integrations
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to render_template('admin/application_settings/integrations')
+ end
+ end
+ end
+
describe 'GET #usage_data with no access' do
before do
stub_usage_data_connections
@@ -56,6 +87,13 @@ RSpec.describe Admin::ApplicationSettingsController do
sign_in(admin)
end
+ it 'updates the require_admin_approval_after_user_signup setting' do
+ put :update, params: { application_setting: { require_admin_approval_after_user_signup: true } }
+
+ expect(response).to redirect_to(general_admin_application_settings_path)
+ expect(ApplicationSetting.current.require_admin_approval_after_user_signup).to eq(true)
+ end
+
it 'updates the password_authentication_enabled_for_git setting' do
put :update, params: { application_setting: { password_authentication_enabled_for_git: "0" } }
diff --git a/spec/controllers/admin/clusters_controller_spec.rb b/spec/controllers/admin/clusters_controller_spec.rb
index d2a569a9d48..69bdc79c5f5 100644
--- a/spec/controllers/admin/clusters_controller_spec.rb
+++ b/spec/controllers/admin/clusters_controller_spec.rb
@@ -416,6 +416,7 @@ RSpec.describe Admin::ClustersController do
expect(cluster).to be_user
expect(cluster).to be_kubernetes
expect(cluster).to be_platform_kubernetes_rbac
+ expect(cluster).to be_namespace_per_environment
end
end
end
@@ -585,6 +586,7 @@ RSpec.describe Admin::ClustersController do
enabled: false,
name: 'my-new-cluster-name',
managed: false,
+ namespace_per_environment: false,
base_domain: domain
}
}
@@ -599,6 +601,7 @@ RSpec.describe Admin::ClustersController do
expect(cluster.enabled).to be_falsey
expect(cluster.name).to eq('my-new-cluster-name')
expect(cluster).not_to be_managed
+ expect(cluster).not_to be_namespace_per_environment
expect(cluster.domain).to eq('test-domain.com')
end
@@ -624,6 +627,7 @@ RSpec.describe Admin::ClustersController do
enabled: false,
name: 'my-new-cluster-name',
managed: false,
+ namespace_per_environment: false,
domain: domain
}
}
@@ -637,6 +641,7 @@ RSpec.describe Admin::ClustersController do
expect(cluster.enabled).to be_falsey
expect(cluster.name).to eq('my-new-cluster-name')
expect(cluster).not_to be_managed
+ expect(cluster).not_to be_namespace_per_environment
end
end
diff --git a/spec/controllers/admin/hooks_controller_spec.rb b/spec/controllers/admin/hooks_controller_spec.rb
index 8975f746dd7..17c4222530d 100644
--- a/spec/controllers/admin/hooks_controller_spec.rb
+++ b/spec/controllers/admin/hooks_controller_spec.rb
@@ -29,4 +29,12 @@ RSpec.describe Admin::HooksController do
expect(SystemHook.first).to have_attributes(hook_params)
end
end
+
+ describe 'DELETE #destroy' do
+ let!(:hook) { create(:system_hook) }
+ let!(:log) { create(:web_hook_log, web_hook: hook) }
+ let(:params) { { id: hook } }
+
+ it_behaves_like 'Web hook destroyer'
+ end
end
diff --git a/spec/controllers/admin/instance_review_controller_spec.rb b/spec/controllers/admin/instance_review_controller_spec.rb
new file mode 100644
index 00000000000..d15894eeb5d
--- /dev/null
+++ b/spec/controllers/admin/instance_review_controller_spec.rb
@@ -0,0 +1,68 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Admin::InstanceReviewController do
+ include UsageDataHelpers
+
+ let(:admin) { create(:admin) }
+ let(:subscriptions_url) { ::Gitlab::SubscriptionPortal::SUBSCRIPTIONS_URL }
+
+ before do
+ sign_in(admin)
+ end
+
+ context 'GET #index' do
+ let!(:group) { create(:group) }
+ let!(:projects) { create_list(:project, 2, group: group) }
+
+ subject { post :index }
+
+ context 'with usage ping enabled' do
+ before do
+ stub_application_setting(usage_ping_enabled: true)
+ stub_usage_data_connections
+ ::Gitlab::UsageData.data(force_refresh: true)
+ subject
+ end
+
+ it 'redirects to the customers app with correct params' do
+ params = { instance_review: {
+ email: admin.email,
+ last_name: admin.name,
+ version: ::Gitlab::VERSION,
+ users_count: 5,
+ projects_count: 2,
+ groups_count: 1,
+ issues_count: 0,
+ merge_requests_count: 0,
+ internal_pipelines_count: 0,
+ external_pipelines_count: 0,
+ labels_count: 0,
+ milestones_count: 0,
+ snippets_count: 0,
+ notes_count: 0
+ } }.to_query
+
+ expect(response).to redirect_to("#{subscriptions_url}/instance_review?#{params}")
+ end
+ end
+
+ context 'with usage ping disabled' do
+ before do
+ stub_application_setting(usage_ping_enabled: false)
+ subject
+ end
+
+ it 'redirects to the customers app with correct params' do
+ params = { instance_review: {
+ email: admin.email,
+ last_name: admin.name,
+ version: ::Gitlab::VERSION
+ } }.to_query
+
+ expect(response).to redirect_to("#{subscriptions_url}/instance_review?#{params}")
+ end
+ end
+ end
+end
diff --git a/spec/controllers/admin/integrations_controller_spec.rb b/spec/controllers/admin/integrations_controller_spec.rb
index 4b1806a43d2..1a13d016b73 100644
--- a/spec/controllers/admin/integrations_controller_spec.rb
+++ b/spec/controllers/admin/integrations_controller_spec.rb
@@ -20,6 +20,18 @@ RSpec.describe Admin::IntegrationsController do
end
end
end
+
+ context 'when GitLab.com' do
+ before do
+ allow(::Gitlab).to receive(:com?) { true }
+ end
+
+ it 'returns 404' do
+ get :edit, params: { id: Service.available_services_names.sample }
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
end
describe '#update' do
@@ -43,7 +55,7 @@ RSpec.describe Admin::IntegrationsController do
end
it 'calls to PropagateIntegrationWorker' do
- expect(PropagateIntegrationWorker).to have_received(:perform_async).with(integration.id, false)
+ expect(PropagateIntegrationWorker).to have_received(:perform_async).with(integration.id)
end
end
diff --git a/spec/controllers/admin/runners_controller_spec.rb b/spec/controllers/admin/runners_controller_spec.rb
index 013eee19409..3fffc50475c 100644
--- a/spec/controllers/admin/runners_controller_spec.rb
+++ b/spec/controllers/admin/runners_controller_spec.rb
@@ -151,4 +151,21 @@ RSpec.describe Admin::RunnersController do
expect(runner.active).to eq(false)
end
end
+
+ describe 'GET #runner_setup_scripts' do
+ it 'renders the setup scripts' do
+ get :runner_setup_scripts, params: { os: 'linux', arch: 'amd64' }
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response).to have_key("install")
+ expect(json_response).to have_key("register")
+ end
+
+ it 'renders errors if they occur' do
+ get :runner_setup_scripts, params: { os: 'foo', arch: 'bar' }
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ expect(json_response).to have_key("errors")
+ end
+ end
end
diff --git a/spec/controllers/admin/sessions_controller_spec.rb b/spec/controllers/admin/sessions_controller_spec.rb
index 35982e57034..5fa7a7f278d 100644
--- a/spec/controllers/admin/sessions_controller_spec.rb
+++ b/spec/controllers/admin/sessions_controller_spec.rb
@@ -109,7 +109,7 @@ RSpec.describe Admin::SessionsController, :do_not_mock_admin_mode do
# triggering the auth form will request admin mode
get :new
- Timecop.freeze(Gitlab::Auth::CurrentUserMode::ADMIN_MODE_REQUESTED_GRACE_PERIOD.from_now) do
+ travel_to(Gitlab::Auth::CurrentUserMode::ADMIN_MODE_REQUESTED_GRACE_PERIOD.from_now) do
post :create, params: { user: { password: user.password } }
expect(response).to redirect_to(new_admin_session_path)
diff --git a/spec/controllers/admin/users_controller_spec.rb b/spec/controllers/admin/users_controller_spec.rb
index 6301da74f4a..5312a0db7f5 100644
--- a/spec/controllers/admin/users_controller_spec.rb
+++ b/spec/controllers/admin/users_controller_spec.rb
@@ -23,6 +23,12 @@ RSpec.describe Admin::UsersController do
expect(assigns(:users)).to eq([admin])
end
+
+ it 'eager loads authorized projects association' do
+ get :index
+
+ expect(assigns(:users).first.association(:authorized_projects)).to be_loaded
+ end
end
describe 'GET :id' do
@@ -96,6 +102,58 @@ RSpec.describe Admin::UsersController do
end
end
+ describe 'PUT #approve' do
+ let(:user) { create(:user, :blocked_pending_approval) }
+
+ subject { put :approve, params: { id: user.username } }
+
+ context 'when feature is disabled' do
+ before do
+ stub_feature_flags(admin_approval_for_new_user_signups: false)
+ end
+
+ it 'responds with access denied' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+
+ context 'when feature is enabled' do
+ before do
+ stub_feature_flags(admin_approval_for_new_user_signups: true)
+ end
+
+ context 'when successful' do
+ it 'activates the user' do
+ subject
+
+ user.reload
+
+ expect(user).to be_active
+ expect(flash[:notice]).to eq('Successfully approved')
+ end
+ end
+
+ context 'when unsuccessful' do
+ let(:user) { create(:user, :blocked) }
+
+ it 'displays the error' do
+ subject
+
+ expect(flash[:alert]).to eq('The user you are trying to approve is not pending an approval')
+ end
+
+ it 'does not activate the user' do
+ subject
+
+ user.reload
+ expect(user).not_to be_active
+ end
+ end
+ end
+ end
+
describe 'PUT #activate' do
shared_examples 'a request that activates the user' do
it 'activates the user' do
@@ -184,6 +242,17 @@ RSpec.describe Admin::UsersController do
expect(flash[:notice]).to eq('Error occurred. A blocked user cannot be deactivated')
end
end
+
+ context 'for an internal user' do
+ it 'does not deactivate the user' do
+ internal_user = User.alert_bot
+
+ put :deactivate, params: { id: internal_user.username }
+
+ expect(internal_user.reload.deactivated?).to be_falsey
+ expect(flash[:notice]).to eq('Internal users cannot be deactivated')
+ end
+ end
end
describe 'PUT block/:id' do
@@ -321,7 +390,7 @@ RSpec.describe Admin::UsersController do
describe 'POST update' do
context 'when the password has changed' do
- def update_password(user, password = User.random_password, password_confirmation = password)
+ def update_password(user, password = User.random_password, password_confirmation = password, format = :html)
params = {
id: user.to_param,
user: {
@@ -330,7 +399,7 @@ RSpec.describe Admin::UsersController do
}
}
- post :update, params: params
+ post :update, params: params, format: format
end
context 'when admin changes their own password' do
@@ -429,6 +498,23 @@ RSpec.describe Admin::UsersController do
.not_to change { user.reload.encrypted_password }
end
end
+
+ context 'when the update fails' do
+ let(:password) { User.random_password }
+
+ before do
+ expect_next_instance_of(Users::UpdateService) do |service|
+ allow(service).to receive(:execute).and_return({ message: 'failed', status: :error })
+ end
+ end
+
+ it 'returns a 500 error' do
+ expect { update_password(admin, password, password, :json) }
+ .not_to change { admin.reload.password_expired? }
+
+ expect(response).to have_gitlab_http_status(:error)
+ end
+ end
end
context 'admin notes' do
diff --git a/spec/controllers/application_controller_spec.rb b/spec/controllers/application_controller_spec.rb
index 188a4cb04af..d95aac2f386 100644
--- a/spec/controllers/application_controller_spec.rb
+++ b/spec/controllers/application_controller_spec.rb
@@ -416,13 +416,13 @@ RSpec.describe ApplicationController do
end
it 'returns false if the grace period has expired' do
- Timecop.freeze(3.hours.from_now) do
+ travel_to(3.hours.from_now) do
expect(subject).to be_falsey
end
end
it 'returns true if the grace period is still active' do
- Timecop.freeze(1.hour.from_now) do
+ travel_to(1.hour.from_now) do
expect(subject).to be_truthy
end
end
@@ -844,6 +844,8 @@ RSpec.describe ApplicationController do
describe '#set_current_context' do
controller(described_class) do
+ feature_category :issue_tracking
+
def index
Labkit::Context.with_context do |context|
render json: context.to_h
@@ -893,6 +895,12 @@ RSpec.describe ApplicationController do
expect(json_response['meta.caller_id']).to eq('AnonymousController#index')
end
+ it 'sets the feature_category as defined in the controller' do
+ get :index, format: :json
+
+ expect(json_response['meta.feature_category']).to eq('issue_tracking')
+ end
+
it 'assigns the context to a variable for logging' do
get :index, format: :json
diff --git a/spec/controllers/boards/lists_controller_spec.rb b/spec/controllers/boards/lists_controller_spec.rb
index c72d9e5053a..9b09f46d17e 100644
--- a/spec/controllers/boards/lists_controller_spec.rb
+++ b/spec/controllers/boards/lists_controller_spec.rb
@@ -260,6 +260,17 @@ RSpec.describe Boards::ListsController do
end
end
+ context 'with an error service response' do
+ it 'returns an unprocessable entity response' do
+ allow(Boards::Lists::DestroyService).to receive(:new)
+ .and_return(double(execute: ServiceResponse.error(message: 'error')))
+
+ remove_board_list user: user, board: board, list: planning
+
+ expect(response).to have_gitlab_http_status(:unprocessable_entity)
+ end
+ end
+
def remove_board_list(user:, board:, list:)
sign_in(user)
diff --git a/spec/controllers/concerns/controller_with_feature_category/config_spec.rb b/spec/controllers/concerns/controller_with_feature_category/config_spec.rb
deleted file mode 100644
index 9b8ffd2baab..00000000000
--- a/spec/controllers/concerns/controller_with_feature_category/config_spec.rb
+++ /dev/null
@@ -1,53 +0,0 @@
-# frozen_string_literal: true
-
-require "fast_spec_helper"
-require "rspec-parameterized"
-require_relative "../../../../app/controllers/concerns/controller_with_feature_category/config"
-
-RSpec.describe ControllerWithFeatureCategory::Config do
- describe "#matches?" do
- using RSpec::Parameterized::TableSyntax
-
- where(:only_actions, :except_actions, :if_proc, :unless_proc, :test_action, :expected) do
- nil | nil | nil | nil | "action" | true
- [:included] | nil | nil | nil | "action" | false
- [:included] | nil | nil | nil | "included" | true
- nil | [:excluded] | nil | nil | "excluded" | false
- nil | nil | true | nil | "action" | true
- [:included] | nil | true | nil | "action" | false
- [:included] | nil | true | nil | "included" | true
- nil | [:excluded] | true | nil | "excluded" | false
- nil | nil | false | nil | "action" | false
- [:included] | nil | false | nil | "action" | false
- [:included] | nil | false | nil | "included" | false
- nil | [:excluded] | false | nil | "excluded" | false
- nil | nil | nil | true | "action" | false
- [:included] | nil | nil | true | "action" | false
- [:included] | nil | nil | true | "included" | false
- nil | [:excluded] | nil | true | "excluded" | false
- nil | nil | nil | false | "action" | true
- [:included] | nil | nil | false | "action" | false
- [:included] | nil | nil | false | "included" | true
- nil | [:excluded] | nil | false | "excluded" | false
- nil | nil | true | false | "action" | true
- [:included] | nil | true | false | "action" | false
- [:included] | nil | true | false | "included" | true
- nil | [:excluded] | true | false | "excluded" | false
- nil | nil | false | true | "action" | false
- [:included] | nil | false | true | "action" | false
- [:included] | nil | false | true | "included" | false
- nil | [:excluded] | false | true | "excluded" | false
- end
-
- with_them do
- let(:config) do
- if_to_proc = if_proc.nil? ? nil : -> (_) { if_proc }
- unless_to_proc = unless_proc.nil? ? nil : -> (_) { unless_proc }
-
- described_class.new(:category, only_actions, except_actions, if_to_proc, unless_to_proc)
- end
-
- specify { expect(config.matches?(test_action)).to be(expected) }
- end
- end
-end
diff --git a/spec/controllers/concerns/controller_with_feature_category_spec.rb b/spec/controllers/concerns/controller_with_feature_category_spec.rb
index e603a7d14c4..55e84755f5c 100644
--- a/spec/controllers/concerns/controller_with_feature_category_spec.rb
+++ b/spec/controllers/concerns/controller_with_feature_category_spec.rb
@@ -2,7 +2,6 @@
require 'fast_spec_helper'
require_relative "../../../app/controllers/concerns/controller_with_feature_category"
-require_relative "../../../app/controllers/concerns/controller_with_feature_category/config"
RSpec.describe ControllerWithFeatureCategory do
describe ".feature_category_for_action" do
@@ -14,17 +13,15 @@ RSpec.describe ControllerWithFeatureCategory do
let(:controller) do
Class.new(base_controller) do
- feature_category :baz
- feature_category :foo, except: %w(update edit)
- feature_category :bar, only: %w(index show)
- feature_category :quux, only: %w(destroy)
- feature_category :quuz, only: %w(destroy)
+ feature_category :foo, %w(update edit)
+ feature_category :bar, %w(index show)
+ feature_category :quux, %w(destroy)
end
end
let(:subclass) do
Class.new(controller) do
- feature_category :qux, only: %w(index)
+ feature_category :baz, %w(subclass_index)
end
end
@@ -33,34 +30,31 @@ RSpec.describe ControllerWithFeatureCategory do
end
it "returns the expected category", :aggregate_failures do
- expect(controller.feature_category_for_action("update")).to eq(:baz)
- expect(controller.feature_category_for_action("hello")).to eq(:foo)
+ expect(controller.feature_category_for_action("update")).to eq(:foo)
expect(controller.feature_category_for_action("index")).to eq(:bar)
+ expect(controller.feature_category_for_action("destroy")).to eq(:quux)
end
- it "returns the closest match for categories defined in subclasses" do
- expect(subclass.feature_category_for_action("index")).to eq(:qux)
- expect(subclass.feature_category_for_action("show")).to eq(:bar)
+ it "returns the expected category for categories defined in subclasses" do
+ expect(subclass.feature_category_for_action("subclass_index")).to eq(:baz)
end
- it "returns the last defined feature category when multiple match" do
- expect(controller.feature_category_for_action("destroy")).to eq(:quuz)
- end
-
- it "raises an error when using including and excluding the same action" do
+ it "raises an error when defining for the controller and for individual actions" do
expect do
Class.new(base_controller) do
- feature_category :hello, only: [:world], except: [:world]
+ feature_category :hello
+ feature_category :goodbye, [:world]
end
- end.to raise_error(%r(cannot configure both `only` and `except`))
+ end.to raise_error(ArgumentError, "hello is defined for all actions, but other categories are set")
end
- it "raises an error when using unknown arguments" do
+ it "raises an error when multiple calls define the same action" do
expect do
Class.new(base_controller) do
- feature_category :hello, hello: :world
+ feature_category :hello, [:world]
+ feature_category :goodbye, ["world"]
end
- end.to raise_error(%r(unknown arguments))
+ end.to raise_error(ArgumentError, "Actions have multiple feature categories: world")
end
end
end
diff --git a/spec/controllers/concerns/issuable_collections_spec.rb b/spec/controllers/concerns/issuable_collections_spec.rb
index befdd760965..6fa273bf3d7 100644
--- a/spec/controllers/concerns/issuable_collections_spec.rb
+++ b/spec/controllers/concerns/issuable_collections_spec.rb
@@ -3,6 +3,8 @@
require 'spec_helper'
RSpec.describe IssuableCollections do
+ using RSpec::Parameterized::TableSyntax
+
let(:user) { create(:user) }
let(:controller) do
@@ -25,13 +27,35 @@ RSpec.describe IssuableCollections do
end
describe '#page_count_for_relation' do
- let(:params) { { state: 'opened' } }
+ let(:relation) { double(:relation, limit_value: 20) }
+
+ context 'row count is known' do
+ let(:params) { { state: 'opened' } }
+
+ it 'returns the number of pages' do
+ pages = controller.send(:page_count_for_relation, relation, 28)
+
+ expect(pages).to eq(2)
+ end
+ end
+
+ context 'row_count is unknown' do
+ where(:page_param, :expected) do
+ nil | 2
+ 1 | 2
+ '1' | 2
+ 2 | 3
+ end
- it 'returns the number of pages' do
- relation = double(:relation, limit_value: 20)
- pages = controller.send(:page_count_for_relation, relation, 28)
+ with_them do
+ let(:params) { { state: 'opened', page: page_param } }
- expect(pages).to eq(2)
+ it 'returns current page + 1 if the row count is unknown' do
+ pages = controller.send(:page_count_for_relation, relation, -1)
+
+ expect(pages).to eq(expected)
+ end
+ end
end
end
diff --git a/spec/controllers/concerns/redis_tracking_spec.rb b/spec/controllers/concerns/redis_tracking_spec.rb
index 3795fca5576..831f5ad7bb1 100644
--- a/spec/controllers/concerns/redis_tracking_spec.rb
+++ b/spec/controllers/concerns/redis_tracking_spec.rb
@@ -3,15 +3,19 @@
require "spec_helper"
RSpec.describe RedisTracking do
- let(:event_name) { 'g_compliance_dashboard' }
- let(:feature) { 'g_compliance_dashboard_feature' }
+ let(:feature) { 'approval_rule' }
let(:user) { create(:user) }
+ before do
+ skip_feature_flags_yaml_validation
+ end
+
controller(ApplicationController) do
include RedisTracking
skip_before_action :authenticate_user!, only: :show
- track_redis_hll_event :index, :show, name: 'i_analytics_dev_ops_score', feature: :g_compliance_dashboard_feature, feature_default_enabled: true
+ track_redis_hll_event :index, :show, name: 'g_compliance_approval_rules', feature: :approval_rule, feature_default_enabled: true,
+ if: [:custom_condition_one?, :custom_condition_two?]
def index
render html: 'index'
@@ -24,51 +28,94 @@ RSpec.describe RedisTracking do
def show
render html: 'show'
end
- end
- context 'with feature disabled' do
- it 'does not track the event' do
- stub_feature_flags(feature => false)
+ private
- expect(Gitlab::UsageDataCounters::HLLRedisCounter).not_to receive(:track_event)
+ def custom_condition_one?
+ true
+ end
- get :index
+ def custom_condition_two?
+ true
end
end
- context 'with usage ping disabled' do
+ def expect_tracking
+ expect(Gitlab::UsageDataCounters::HLLRedisCounter).to receive(:track_event)
+ .with(instance_of(String), 'g_compliance_approval_rules')
+ end
+
+ def expect_no_tracking
+ expect(Gitlab::UsageDataCounters::HLLRedisCounter).not_to receive(:track_event)
+ end
+
+ context 'with feature disabled' do
it 'does not track the event' do
- stub_feature_flags(feature => true)
- allow(Gitlab::CurrentSettings).to receive(:usage_ping_enabled?).and_return(false)
+ stub_feature_flags(feature => false)
- expect(Gitlab::UsageDataCounters::HLLRedisCounter).not_to receive(:track_event)
+ expect_no_tracking
get :index
end
end
- context 'with feature enabled and usage ping enabled' do
+ context 'with feature enabled' do
before do
stub_feature_flags(feature => true)
- allow(Gitlab::CurrentSettings).to receive(:usage_ping_enabled?).and_return(true)
end
context 'when user is logged in' do
- it 'tracks the event' do
+ before do
sign_in(user)
+ end
- expect(Gitlab::UsageDataCounters::HLLRedisCounter).to receive(:track_event)
+ it 'tracks the event' do
+ expect_tracking
get :index
end
it 'passes default_enabled flag' do
- sign_in(user)
-
expect(controller).to receive(:metric_feature_enabled?).with(feature.to_sym, true)
get :index
end
+
+ it 'tracks the event if DNT is not enabled' do
+ request.headers['DNT'] = '0'
+
+ expect_tracking
+
+ get :index
+ end
+
+ it 'does not track the event if DNT is enabled' do
+ request.headers['DNT'] = '1'
+
+ expect_no_tracking
+
+ get :index
+ end
+
+ it 'does not track the event if the format is not HTML' do
+ expect_no_tracking
+
+ get :index, format: :json
+ end
+
+ it 'does not track the event if a custom condition returns false' do
+ expect(controller).to receive(:custom_condition_two?).and_return(false)
+
+ expect_no_tracking
+
+ get :index
+ end
+
+ it 'does not track the event for untracked actions' do
+ expect_no_tracking
+
+ get :new
+ end
end
context 'when user is not logged in and there is a visitor_id' do
@@ -81,26 +128,18 @@ RSpec.describe RedisTracking do
it 'tracks the event' do
cookies[:visitor_id] = { value: visitor_id, expires: 24.months }
- expect(Gitlab::UsageDataCounters::HLLRedisCounter).to receive(:track_event)
+ expect_tracking
get :show
end
end
context 'when user is not logged in and there is no visitor_id' do
- it 'does not tracks the event' do
- expect(Gitlab::UsageDataCounters::HLLRedisCounter).not_to receive(:track_event)
+ it 'does not track the event' do
+ expect_no_tracking
get :index
end
end
-
- context 'for untracked action' do
- it 'does not tracks the event' do
- expect(Gitlab::UsageDataCounters::HLLRedisCounter).not_to receive(:track_event)
-
- get :new
- end
- end
end
end
diff --git a/spec/controllers/dashboard/labels_controller_spec.rb b/spec/controllers/dashboard/labels_controller_spec.rb
index 415cb821545..e7091664d1a 100644
--- a/spec/controllers/dashboard/labels_controller_spec.rb
+++ b/spec/controllers/dashboard/labels_controller_spec.rb
@@ -3,27 +3,32 @@
require 'spec_helper'
RSpec.describe Dashboard::LabelsController do
- let(:project) { create(:project) }
- let(:user) { create(:user) }
- let!(:label) { create(:label, project: project) }
+ let_it_be(:user) { create(:user) }
+ let_it_be(:project) { create(:project) }
+ let_it_be(:project_2) { create(:project) }
+
+ let_it_be(:label) { create(:label, project: project, title: 'some_label') }
+ let_it_be(:label_with_same_title) { create(:label, project: project_2, title: 'some_label') }
+ let_it_be(:unrelated_label) { create(:label, project: create(:project, :public)) }
+
+ before_all do
+ project.add_reporter(user)
+ project_2.add_reporter(user)
+ end
before do
sign_in(user)
- project.add_reporter(user)
end
describe "#index" do
- let!(:unrelated_label) { create(:label, project: create(:project, :public)) }
-
subject { get :index, format: :json }
- it 'returns global labels for projects the user has a relationship with' do
+ it 'returns labels with unique titles for projects the user has a relationship with' do
subject
expect(json_response).to be_kind_of(Array)
expect(json_response.size).to eq(1)
- expect(json_response[0]["id"]).to be_nil
- expect(json_response[0]["title"]).to eq(label.title)
+ expect(json_response[0]['title']).to eq(label.title)
end
it_behaves_like 'disabled when using an external authorization service'
diff --git a/spec/controllers/dashboard_controller_spec.rb b/spec/controllers/dashboard_controller_spec.rb
index c838affa239..9b78f841cce 100644
--- a/spec/controllers/dashboard_controller_spec.rb
+++ b/spec/controllers/dashboard_controller_spec.rb
@@ -15,6 +15,16 @@ RSpec.describe DashboardController do
describe 'GET issues' do
it_behaves_like 'issuables list meta-data', :issue, :issues
it_behaves_like 'issuables requiring filter', :issues
+
+ it 'lists only incidents and issues' do
+ issue = create(:incident, project: project, author: user)
+ incident = create(:incident, project: project, author: user)
+ create(:quality_test_case, project: project, author: user)
+
+ get :issues, params: { author_id: user.id }
+
+ expect(assigns(:issues)).to match_array([issue, incident])
+ end
end
describe 'GET merge requests' do
diff --git a/spec/controllers/every_controller_spec.rb b/spec/controllers/every_controller_spec.rb
index 4785ee9ed8f..b1519c4ef1e 100644
--- a/spec/controllers/every_controller_spec.rb
+++ b/spec/controllers/every_controller_spec.rb
@@ -17,20 +17,20 @@ RSpec.describe "Every controller" do
.compact
.select { |route| route[:controller].present? && route[:action].present? }
.map { |route| [constantize_controller(route[:controller]), route[:action]] }
- .reject { |route| route.first.nil? || !route.first.include?(ControllerWithFeatureCategory) }
+ .select { |(controller, action)| controller&.include?(ControllerWithFeatureCategory) }
+ .reject { |(controller, action)| controller == ApplicationController || controller == Devise::UnlocksController }
end
let_it_be(:routes_without_category) do
controller_actions.map do |controller, action|
- "#{controller}##{action}" unless controller.feature_category_for_action(action)
+ next if controller.feature_category_for_action(action)
+
+ "#{controller}##{action}"
end.compact
end
it "has feature categories" do
- pending("We'll work on defining categories for all controllers: "\
- "https://gitlab.com/gitlab-com/gl-infra/scalability/-/issues/463")
-
- expect(routes_without_category).to be_empty, "#{routes_without_category.first(10)} did not have a category"
+ expect(routes_without_category).to be_empty, "#{routes_without_category} did not have a category"
end
it "completed controllers don't get new routes without categories" do
@@ -74,9 +74,9 @@ RSpec.describe "Every controller" do
end
def actions_defined_in_feature_category_config(controller)
- feature_category_configs = controller.send(:class_attributes)[:feature_category_config]
- feature_category_configs.map do |config|
- Array(config.send(:only)) + Array(config.send(:except))
- end.flatten.uniq.map(&:to_s)
+ controller.send(:class_attributes)[:feature_category_config]
+ .values
+ .flatten
+ .map(&:to_s)
end
end
diff --git a/spec/controllers/graphql_controller_spec.rb b/spec/controllers/graphql_controller_spec.rb
index 405f1eae482..e4aea688a69 100644
--- a/spec/controllers/graphql_controller_spec.rb
+++ b/spec/controllers/graphql_controller_spec.rb
@@ -98,6 +98,12 @@ RSpec.describe GraphqlController do
expect(assigns(:context)[:is_sessionless_user]).to be false
end
end
+
+ it 'includes request object in context' do
+ post :execute
+
+ expect(assigns(:context)[:request]).to eq request
+ end
end
describe 'Admin Mode' do
@@ -150,9 +156,11 @@ RSpec.describe GraphqlController do
describe '#append_info_to_payload' do
let(:graphql_query) { graphql_query_for('project', { 'fullPath' => 'foo' }, %w(id name)) }
+ let(:mock_store) { { graphql_logs: { foo: :bar } } }
let(:log_payload) { {} }
before do
+ allow(RequestStore).to receive(:store).and_return(mock_store)
allow(controller).to receive(:append_info_to_payload).and_wrap_original do |method, *|
method.call(log_payload)
end
@@ -162,7 +170,7 @@ RSpec.describe GraphqlController do
post :execute, params: { query: graphql_query, operationName: 'Foo' }
expect(controller).to have_received(:append_info_to_payload)
- expect(log_payload.dig(:metadata, :graphql, :operation_name)).to eq('Foo')
+ expect(log_payload.dig(:metadata, :graphql)).to eq({ operation_name: 'Foo', foo: :bar })
end
end
end
diff --git a/spec/controllers/groups/clusters_controller_spec.rb b/spec/controllers/groups/clusters_controller_spec.rb
index 81d5bc7770f..140b7b0f2a8 100644
--- a/spec/controllers/groups/clusters_controller_spec.rb
+++ b/spec/controllers/groups/clusters_controller_spec.rb
@@ -271,6 +271,7 @@ RSpec.describe Groups::ClustersController do
expect(cluster).to be_kubernetes
expect(cluster.provider_gcp).to be_legacy_abac
expect(cluster).to be_managed
+ expect(cluster).to be_namespace_per_environment
end
context 'when legacy_abac param is false' do
@@ -358,6 +359,7 @@ RSpec.describe Groups::ClustersController do
expect(cluster).to be_user
expect(cluster).to be_kubernetes
expect(cluster).to be_managed
+ expect(cluster).to be_namespace_per_environment
end
end
@@ -387,6 +389,7 @@ RSpec.describe Groups::ClustersController do
expect(cluster).to be_user
expect(cluster).to be_kubernetes
expect(cluster).to be_platform_kubernetes_rbac
+ expect(cluster).to be_namespace_per_environment
end
end
@@ -716,6 +719,7 @@ RSpec.describe Groups::ClustersController do
enabled: false,
name: 'my-new-cluster-name',
managed: false,
+ namespace_per_environment: false,
domain: domain
}
}
@@ -729,6 +733,7 @@ RSpec.describe Groups::ClustersController do
expect(cluster.enabled).to be_falsey
expect(cluster.name).to eq('my-new-cluster-name')
expect(cluster).not_to be_managed
+ expect(cluster).not_to be_namespace_per_environment
end
end
diff --git a/spec/controllers/groups/group_links_controller_spec.rb b/spec/controllers/groups/group_links_controller_spec.rb
index 07299382230..c411d9cfb63 100644
--- a/spec/controllers/groups/group_links_controller_spec.rb
+++ b/spec/controllers/groups/group_links_controller_spec.rb
@@ -15,6 +15,21 @@ RSpec.describe Groups::GroupLinksController do
shared_with_group.add_developer(group_member)
end
+ shared_examples 'placeholder is passed as `id` parameter' do |action|
+ it 'returns a 404' do
+ post(
+ action,
+ params: {
+ group_id: shared_group,
+ id: ':id'
+ },
+ format: :json
+ )
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+
describe '#create' do
let(:shared_with_group_id) { shared_with_group.id }
let(:shared_group_access) { GroupGroupLink.default_access }
@@ -125,6 +140,8 @@ RSpec.describe Groups::GroupLinksController do
expect(response).to have_gitlab_http_status(:not_found)
end
end
+
+ include_examples 'placeholder is passed as `id` parameter', :create
end
describe '#update' do
@@ -136,10 +153,15 @@ RSpec.describe Groups::GroupLinksController do
let(:expiry_date) { 1.month.from_now.to_date }
subject do
- post(:update, params: { group_id: shared_group,
- id: link.id,
- group_link: { group_access: Gitlab::Access::GUEST,
- expires_at: expiry_date } })
+ post(
+ :update,
+ params: {
+ group_id: shared_group,
+ id: link.id,
+ group_link: { group_access: Gitlab::Access::GUEST, expires_at: expiry_date }
+ },
+ format: :json
+ )
end
context 'when user has admin access to the shared group' do
@@ -160,6 +182,26 @@ RSpec.describe Groups::GroupLinksController do
expect(link.expires_at).to eq(expiry_date)
end
+ context 'when `expires_at` is set' do
+ it 'returns correct json response' do
+ travel_to Time.now.utc.beginning_of_day
+
+ subject
+
+ expect(json_response).to eq({ "expires_in" => "about 1 month", "expires_soon" => false })
+ end
+ end
+
+ context 'when `expires_at` is not set' do
+ let(:expiry_date) { nil }
+
+ it 'returns empty json response' do
+ subject
+
+ expect(json_response).to be_empty
+ end
+ end
+
it 'updates project permissions' do
expect { subject }.to change { group_member.can?(:create_release, project) }.from(true).to(false)
end
@@ -172,6 +214,8 @@ RSpec.describe Groups::GroupLinksController do
expect(response).to have_gitlab_http_status(:not_found)
end
end
+
+ include_examples 'placeholder is passed as `id` parameter', :update
end
describe '#destroy' do
@@ -207,5 +251,7 @@ RSpec.describe Groups::GroupLinksController do
expect(response).to have_gitlab_http_status(:not_found)
end
end
+
+ include_examples 'placeholder is passed as `id` parameter', :destroy
end
end
diff --git a/spec/controllers/groups/group_members_controller_spec.rb b/spec/controllers/groups/group_members_controller_spec.rb
index 4b9dd3629f1..5425a437c80 100644
--- a/spec/controllers/groups/group_members_controller_spec.rb
+++ b/spec/controllers/groups/group_members_controller_spec.rb
@@ -233,6 +233,42 @@ RSpec.describe Groups::GroupMembersController do
end
end
end
+
+ context 'expiration date' do
+ let(:expiry_date) { 1.month.from_now.to_date }
+
+ before do
+ travel_to Time.now.utc.beginning_of_day
+
+ put(
+ :update,
+ params: {
+ group_member: { expires_at: expiry_date },
+ group_id: group,
+ id: requester
+ },
+ format: :json
+ )
+ end
+
+ context 'when `expires_at` is set' do
+ it 'returns correct json response' do
+ expect(json_response).to eq({
+ "expires_in" => "about 1 month",
+ "expires_soon" => false,
+ "expires_at_formatted" => expiry_date.to_time.in_time_zone.to_s(:medium)
+ })
+ end
+ end
+
+ context 'when `expires_at` is not set' do
+ let(:expiry_date) { nil }
+
+ it 'returns empty json response' do
+ expect(json_response).to be_empty
+ end
+ end
+ end
end
describe 'DELETE destroy' do
@@ -441,7 +477,7 @@ RSpec.describe Groups::GroupMembersController do
group_id: group,
id: membership
},
- format: :js
+ format: :json
expect(response).to have_gitlab_http_status(:ok)
end
diff --git a/spec/controllers/groups/labels_controller_spec.rb b/spec/controllers/groups/labels_controller_spec.rb
index 20ee19b01d1..33041f1af9f 100644
--- a/spec/controllers/groups/labels_controller_spec.rb
+++ b/spec/controllers/groups/labels_controller_spec.rb
@@ -9,6 +9,8 @@ RSpec.describe Groups::LabelsController do
before do
group.add_owner(user)
+ # by default FFs are enabled in specs so we turn it off
+ stub_feature_flags(show_inherited_labels: false)
sign_in(user)
end
@@ -32,11 +34,41 @@ RSpec.describe Groups::LabelsController do
subgroup.add_owner(user)
end
- it 'returns ancestor group labels' do
- get :index, params: { group_id: subgroup, include_ancestor_groups: true, only_group_labels: true }, format: :json
+ RSpec.shared_examples 'returns ancestor group labels' do
+ it 'returns ancestor group labels' do
+ get :index, params: params, format: :json
- label_ids = json_response.map {|label| label['title']}
- expect(label_ids).to match_array([group_label_1.title, subgroup_label_1.title])
+ label_ids = json_response.map {|label| label['title']}
+ expect(label_ids).to match_array([group_label_1.title, subgroup_label_1.title])
+ end
+ end
+
+ context 'when include_ancestor_groups true' do
+ let(:params) { { group_id: subgroup, include_ancestor_groups: true, only_group_labels: true } }
+
+ it_behaves_like 'returns ancestor group labels'
+ end
+
+ context 'when include_ancestor_groups false' do
+ let(:params) { { group_id: subgroup, only_group_labels: true } }
+
+ it 'does not return ancestor group labels', :aggregate_failures do
+ get :index, params: params, format: :json
+
+ label_ids = json_response.map {|label| label['title']}
+ expect(label_ids).to match_array([subgroup_label_1.title])
+ expect(label_ids).not_to include([group_label_1.title])
+ end
+ end
+
+ context 'when show_inherited_labels enabled' do
+ let(:params) { { group_id: subgroup } }
+
+ before do
+ stub_feature_flags(show_inherited_labels: true)
+ end
+
+ it_behaves_like 'returns ancestor group labels'
end
end
@@ -56,4 +88,43 @@ RSpec.describe Groups::LabelsController do
expect(response).to have_gitlab_http_status(:ok)
end
end
+
+ describe 'DELETE #destroy' do
+ context 'when current user has ability to destroy the label' do
+ before do
+ sign_in(user)
+ end
+
+ it 'removes the label' do
+ label = create(:group_label, group: group)
+ delete :destroy, params: { group_id: group.to_param, id: label.to_param }
+
+ expect { label.reload }.to raise_error(ActiveRecord::RecordNotFound)
+ end
+
+ context 'when label is succesfuly destroyed' do
+ it 'redirects to the group labels page' do
+ label = create(:group_label, group: group)
+ delete :destroy, params: { group_id: group.to_param, id: label.to_param }
+
+ expect(response).to redirect_to(group_labels_path)
+ end
+ end
+ end
+
+ context 'when current_user does not have ability to destroy the label' do
+ let(:another_user) { create(:user) }
+
+ before do
+ sign_in(another_user)
+ end
+
+ it 'responds with status 404' do
+ label = create(:group_label, group: group)
+ delete :destroy, params: { group_id: group.to_param, id: label.to_param }
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+ end
end
diff --git a/spec/controllers/groups/milestones_controller_spec.rb b/spec/controllers/groups/milestones_controller_spec.rb
index 5c7b88a218a..2c85fe482e2 100644
--- a/spec/controllers/groups/milestones_controller_spec.rb
+++ b/spec/controllers/groups/milestones_controller_spec.rb
@@ -9,7 +9,6 @@ RSpec.describe Groups::MilestonesController do
let(:user) { create(:user) }
let(:title) { '肯定ä¸æ˜¯ä¸­æ–‡çš„问题' }
let(:milestone) { create(:milestone, project: project) }
- let(:milestone_path) { group_milestone_path(group, milestone.safe_title, title: milestone.title) }
let(:milestone_params) do
{
@@ -25,6 +24,12 @@ RSpec.describe Groups::MilestonesController do
project.add_maintainer(user)
end
+ it_behaves_like 'milestone tabs' do
+ let(:milestone) { create(:milestone, group: group) }
+ let(:milestone_path) { group_milestone_path(group, milestone.iid) }
+ let(:request_params) { { group_id: group, id: milestone.iid } }
+ end
+
describe '#index' do
describe 'as HTML' do
render_views
diff --git a/spec/controllers/groups/registry/repositories_controller_spec.rb b/spec/controllers/groups/registry/repositories_controller_spec.rb
index ddac8fc5002..ae982b02a4f 100644
--- a/spec/controllers/groups/registry/repositories_controller_spec.rb
+++ b/spec/controllers/groups/registry/repositories_controller_spec.rb
@@ -87,7 +87,7 @@ RSpec.describe Groups::Registry::RepositoriesController do
it_behaves_like 'with name parameter'
- it_behaves_like 'a gitlab tracking event', described_class.name, 'list_repositories'
+ 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 ) }
diff --git a/spec/controllers/groups/settings/ci_cd_controller_spec.rb b/spec/controllers/groups/settings/ci_cd_controller_spec.rb
index f11bb66caab..880d5fe8951 100644
--- a/spec/controllers/groups/settings/ci_cd_controller_spec.rb
+++ b/spec/controllers/groups/settings/ci_cd_controller_spec.rb
@@ -225,4 +225,25 @@ RSpec.describe Groups::Settings::CiCdController do
end
end
end
+
+ describe 'GET #runner_setup_scripts' do
+ before do
+ group.add_owner(user)
+ end
+
+ it 'renders the setup scripts' do
+ get :runner_setup_scripts, params: { os: 'linux', arch: 'amd64', group_id: group }
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response).to have_key("install")
+ expect(json_response).to have_key("register")
+ end
+
+ it 'renders errors if they occur' do
+ get :runner_setup_scripts, params: { os: 'foo', arch: 'bar', group_id: group }
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ expect(json_response).to have_key("errors")
+ end
+ end
end
diff --git a/spec/controllers/groups_controller_spec.rb b/spec/controllers/groups_controller_spec.rb
index 35d8c0b7c6d..df7e018b35e 100644
--- a/spec/controllers/groups_controller_spec.rb
+++ b/spec/controllers/groups_controller_spec.rb
@@ -2,18 +2,18 @@
require 'spec_helper'
-RSpec.describe GroupsController do
+RSpec.describe GroupsController, factory_default: :keep do
include ExternalAuthorizationServiceHelpers
- let(:user) { create(:user) }
- let(:admin) { create(:admin) }
- let(:group) { create(:group, :public) }
- let(:project) { create(:project, namespace: group) }
- let!(:group_member) { create(:group_member, group: group, user: user) }
- let!(:owner) { group.add_owner(create(:user)).user }
- let!(:maintainer) { group.add_maintainer(create(:user)).user }
- let!(:developer) { group.add_developer(create(:user)).user }
- let!(:guest) { group.add_guest(create(:user)).user }
+ let_it_be_with_refind(:group) { create_default(:group, :public) }
+ let_it_be_with_refind(:project) { create(:project, namespace: group) }
+ let_it_be(:user) { create(:user) }
+ let_it_be(:admin) { create(:admin) }
+ let_it_be(:group_member) { create(:group_member, group: group, user: user) }
+ let_it_be(:owner) { group.add_owner(create(:user)).user }
+ let_it_be(:maintainer) { group.add_maintainer(create(:user)).user }
+ let_it_be(:developer) { group.add_developer(create(:user)).user }
+ let_it_be(:guest) { group.add_guest(create(:user)).user }
shared_examples 'member with ability to create subgroups' do
it 'renders the new page' do
@@ -57,7 +57,6 @@ RSpec.describe GroupsController do
describe 'GET #show' do
before do
sign_in(user)
- project
end
let(:format) { :html }
@@ -82,7 +81,6 @@ RSpec.describe GroupsController do
describe 'GET #details' do
before do
sign_in(user)
- project
end
let(:format) { :html }
@@ -131,12 +129,9 @@ RSpec.describe GroupsController do
end
describe 'GET #activity' do
- render_views
-
context 'as json' do
before do
sign_in(user)
- project
end
it 'includes events from all projects in group and subgroups', :sidekiq_might_not_need_inline do
@@ -157,10 +152,6 @@ RSpec.describe GroupsController do
end
context 'when user has no permission to see the event' do
- let(:user) { create(:user) }
- let(:group) { create(:group) }
- let(:project) { create(:project, group: group) }
-
let(:project_with_restricted_access) do
create(:project, :public, issues_access_level: ProjectFeature::PRIVATE, group: group)
end
@@ -398,8 +389,8 @@ RSpec.describe GroupsController do
end
describe 'GET #issues', :sidekiq_might_not_need_inline do
- let(:issue_1) { create(:issue, project: project, title: 'foo') }
- let(:issue_2) { create(:issue, project: project, title: 'bar') }
+ let_it_be(:issue_1) { create(:issue, project: project, title: 'foo') }
+ let_it_be(:issue_2) { create(:issue, project: project, title: 'bar') }
before do
create_list(:award_emoji, 3, awardable: issue_2)
@@ -409,6 +400,15 @@ RSpec.describe GroupsController do
sign_in(user)
end
+ it 'lists only incidents and issues' do
+ incident = create(:incident, project: project)
+ create(:quality_test_case, project: project)
+
+ get :issues, params: { id: group.to_param }
+
+ expect(assigns(:issues)).to match_array([issue_1, issue_2, incident])
+ end
+
context 'sorting by votes' do
it 'sorts most popular issues' do
get :issues, params: { id: group.to_param, sort: 'upvotes_desc' }
@@ -551,9 +551,38 @@ RSpec.describe GroupsController do
end
end
- context 'when there is a conflicting group path' do
- render_views
+ context "updating default_branch_name" do
+ let(:example_branch_name) { "example_branch_name" }
+
+ subject(:update_action) do
+ put :update,
+ params: {
+ id: group.to_param,
+ group: { default_branch_name: example_branch_name }
+ }
+ end
+
+ it "updates the attribute" do
+ expect { subject }
+ .to change { group.namespace_settings.reload.default_branch_name }
+ .from(nil)
+ .to(example_branch_name)
+
+ expect(response).to have_gitlab_http_status(:found)
+ end
+ context "to empty string" do
+ let(:example_branch_name) { '' }
+
+ it "does not update the attribute" do
+ subject
+
+ expect(group.namespace_settings.reload.default_branch_name).not_to eq('')
+ end
+ end
+ end
+
+ context 'when there is a conflicting group path' do
let!(:conflict_group) { create(:group, path: SecureRandom.hex(12) ) }
let!(:old_name) { group.name }
@@ -794,6 +823,7 @@ RSpec.describe GroupsController do
context 'when transferring to a subgroup goes right' do
let(:new_parent_group) { create(:group, :public) }
+ let(:group) { create(:group, :public) }
let!(:group_member) { create(:group_member, :owner, group: group, user: user) }
let!(:new_parent_group_member) { create(:group_member, :owner, group: new_parent_group, user: user) }
@@ -805,11 +835,8 @@ RSpec.describe GroupsController do
}
end
- it 'returns a notice' do
+ it 'returns a notice and redirects to the new path' do
expect(flash[:notice]).to eq("Group '#{group.name}' was successfully transferred.")
- end
-
- it 'redirects to the new path' do
expect(response).to redirect_to("/#{new_parent_group.path}/#{group.path}")
end
end
@@ -826,17 +853,15 @@ RSpec.describe GroupsController do
}
end
- it 'returns a notice' do
+ it 'returns a notice and redirects to the new path' do
expect(flash[:notice]).to eq("Group '#{group.name}' was successfully transferred.")
- end
-
- it 'redirects to the new path' do
expect(response).to redirect_to("/#{group.path}")
end
end
context 'When the transfer goes wrong' do
let(:new_parent_group) { create(:group, :public) }
+ let(:group) { create(:group, :public) }
let!(:group_member) { create(:group_member, :owner, group: group, user: user) }
let!(:new_parent_group_member) { create(:group_member, :owner, group: new_parent_group, user: user) }
@@ -850,17 +875,15 @@ RSpec.describe GroupsController do
}
end
- it 'returns an alert' do
+ it 'returns an alert and redirects to the current path' do
expect(flash[:alert]).to eq "Transfer failed: namespace directory cannot be moved"
- end
-
- it 'redirects to the current path' do
expect(response).to redirect_to(edit_group_path(group))
end
end
context 'when the user is not allowed to transfer the group' do
let(:new_parent_group) { create(:group, :public) }
+ let(:group) { create(:group, :public) }
let!(:group_member) { create(:group_member, :guest, group: group, user: user) }
let!(:new_parent_group_member) { create(:group_member, :guest, group: new_parent_group, user: user) }
@@ -879,6 +902,7 @@ RSpec.describe GroupsController do
context 'transferring when a project has container images' do
let(:group) { create(:group, :public, :nested) }
+ let(:project) { create(:project, namespace: group) }
let!(:group_member) { create(:group_member, :owner, group: group, user: user) }
before do
@@ -979,6 +1003,8 @@ RSpec.describe GroupsController do
end
context 'when there is no file available to download' do
+ let(:admin) { create(:admin) }
+
before do
sign_in(admin)
end
@@ -1149,9 +1175,7 @@ RSpec.describe GroupsController do
describe "GET #activity as JSON" do
include DesignManagementTestHelpers
- render_views
- let(:project) { create(:project, :public, group: group) }
let(:other_project) { create(:project, :public, group: group) }
def get_activity
diff --git a/spec/controllers/help_controller_spec.rb b/spec/controllers/help_controller_spec.rb
index 3049396dd0f..9ac42cbc3ec 100644
--- a/spec/controllers/help_controller_spec.rb
+++ b/spec/controllers/help_controller_spec.rb
@@ -3,6 +3,8 @@
require 'spec_helper'
RSpec.describe HelpController do
+ include StubVersion
+
let(:user) { create(:user) }
before do
@@ -108,8 +110,56 @@ RSpec.describe HelpController do
end
it 'renders HTML' do
- expect(response).to render_template('show.html.haml')
- expect(response.media_type).to eq 'text/html'
+ aggregate_failures do
+ expect(response).to render_template('show.html.haml')
+ expect(response.media_type).to eq 'text/html'
+ end
+ end
+ end
+
+ context 'when a custom help_page_documentation_url is set' do
+ before do
+ stub_application_setting(help_page_documentation_base_url: documentation_base_url)
+ stub_version(gitlab_version, 'deadbeaf')
+ end
+
+ subject { get :show, params: { path: path }, format: 'html' }
+
+ let(:gitlab_version) { '13.4.0-ee' }
+ let(:documentation_base_url) { 'https://docs.gitlab.com' }
+ let(:path) { 'ssh/README' }
+
+ it 'redirects user to custom documentation url with a specified version' do
+ is_expected.to redirect_to("#{documentation_base_url}/13.4/ee/#{path}.html")
+ end
+
+ context 'when documentation url ends with a slash' do
+ let(:documentation_base_url) { 'https://docs.gitlab.com/' }
+
+ it 'redirects user to custom documentation url without slash duplicates' do
+ is_expected.to redirect_to("https://docs.gitlab.com/13.4/ee/#{path}.html")
+ end
+ end
+
+ context 'when it is a pre-release' do
+ let(:gitlab_version) { '13.4.0-pre' }
+
+ it 'redirects user to custom documentation url without a version' do
+ is_expected.to redirect_to("#{documentation_base_url}/ee/#{path}.html")
+ end
+ end
+
+ context 'when feature flag is disabled' do
+ before do
+ stub_feature_flags(help_page_documentation_redirect: false)
+ end
+
+ it 'renders HTML' do
+ aggregate_failures do
+ is_expected.to render_template('show.html.haml')
+ expect(response.media_type).to eq 'text/html'
+ end
+ end
end
end
@@ -129,9 +179,12 @@ RSpec.describe HelpController do
path: 'user/img/markdown_logo'
},
format: :png
- expect(response).to be_successful
- expect(response.media_type).to eq 'image/png'
- expect(response.headers['Content-Disposition']).to match(/^inline;/)
+
+ aggregate_failures do
+ expect(response).to be_successful
+ expect(response.media_type).to eq 'image/png'
+ expect(response.headers['Content-Disposition']).to match(/^inline;/)
+ end
end
end
diff --git a/spec/controllers/import/bulk_imports_controller_spec.rb b/spec/controllers/import/bulk_imports_controller_spec.rb
new file mode 100644
index 00000000000..f3850ff844e
--- /dev/null
+++ b/spec/controllers/import/bulk_imports_controller_spec.rb
@@ -0,0 +1,179 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Import::BulkImportsController do
+ let_it_be(:user) { create(:user) }
+
+ before do
+ sign_in(user)
+ end
+
+ context 'when user is signed in' do
+ context 'when bulk_import feature flag is enabled' do
+ before do
+ stub_feature_flags(bulk_import: true)
+ end
+
+ describe 'POST configure' do
+ context 'when no params are passed in' do
+ it 'clears out existing session' do
+ post :configure
+
+ expect(session[:bulk_import_gitlab_access_token]).to be_nil
+ expect(session[:bulk_import_gitlab_url]).to be_nil
+
+ expect(response).to have_gitlab_http_status(:found)
+ expect(response).to redirect_to(status_import_bulk_import_url)
+ end
+ end
+
+ it 'sets the session variables' do
+ token = 'token'
+ url = 'https://gitlab.example'
+
+ post :configure, params: { bulk_import_gitlab_access_token: token, bulk_import_gitlab_url: url }
+
+ expect(session[:bulk_import_gitlab_access_token]).to eq(token)
+ expect(session[:bulk_import_gitlab_url]).to eq(url)
+ expect(response).to have_gitlab_http_status(:found)
+ expect(response).to redirect_to(status_import_bulk_import_url)
+ end
+
+ it 'strips access token with spaces' do
+ token = 'token'
+
+ post :configure, params: { bulk_import_gitlab_access_token: " #{token} " }
+
+ expect(session[:bulk_import_gitlab_access_token]).to eq(token)
+ expect(controller).to redirect_to(status_import_bulk_import_url)
+ end
+ end
+
+ describe 'GET status' do
+ let(:client) { Gitlab::BulkImport::Client.new(uri: 'http://gitlab.example', token: 'token') }
+
+ describe 'serialized group data' do
+ let(:client_response) do
+ [
+ { 'id' => 1, 'full_name' => 'group1', 'full_path' => 'full/path/group1' },
+ { 'id' => 2, 'full_name' => 'group2', 'full_path' => 'full/path/group2' }
+ ]
+ end
+
+ before do
+ allow(controller).to receive(:client).and_return(client)
+ allow(client).to receive(:get).with('groups', top_level_only: true).and_return(client_response)
+ end
+
+ it 'returns serialized group data' do
+ get :status, format: :json
+
+ expect(response.parsed_body).to eq({ importable_data: client_response }.as_json)
+ end
+ end
+
+ context 'when host url is local or not http' do
+ %w[https://localhost:3000 http://192.168.0.1 ftp://testing].each do |url|
+ before do
+ stub_application_setting(allow_local_requests_from_web_hooks_and_services: false)
+
+ session[:bulk_import_gitlab_access_token] = 'test'
+ session[:bulk_import_gitlab_url] = url
+ end
+
+ it 'denies network request' do
+ get :status
+
+ expect(controller).to redirect_to(new_group_path)
+ expect(flash[:alert]).to eq('Specified URL cannot be used: "Only allowed schemes are http, https"')
+ end
+ end
+
+ context 'when local requests are allowed' do
+ %w[https://localhost:3000 http://192.168.0.1].each do |url|
+ before do
+ stub_application_setting(allow_local_requests_from_web_hooks_and_services: true)
+
+ session[:bulk_import_gitlab_access_token] = 'test'
+ session[:bulk_import_gitlab_url] = url
+ end
+
+ it 'allows network request' do
+ get :status
+
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+ end
+ end
+ end
+
+ context 'when connection error occurs' do
+ before do
+ allow(controller).to receive(:client).and_return(client)
+ allow(client).to receive(:get).and_raise(Gitlab::BulkImport::Client::ConnectionError)
+ end
+
+ it 'returns 422' do
+ get :status, format: :json
+
+ expect(response).to have_gitlab_http_status(:unprocessable_entity)
+ end
+
+ it 'clears session' do
+ get :status, format: :json
+
+ expect(session[:gitlab_url]).to be_nil
+ expect(session[:gitlab_access_token]).to be_nil
+ end
+ end
+ end
+ end
+
+ context 'when gitlab_api_imports feature flag is disabled' do
+ before do
+ stub_feature_flags(bulk_import: false)
+ end
+
+ context 'POST configure' do
+ it 'returns 404' do
+ post :configure
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+
+ context 'GET status' do
+ it 'returns 404' do
+ get :status
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+ end
+ end
+
+ context 'when user is signed out' do
+ before do
+ sign_out(user)
+ end
+
+ context 'POST configure' do
+ it 'redirects to sign in page' do
+ post :configure
+
+ expect(response).to have_gitlab_http_status(:found)
+ expect(response).to redirect_to(new_user_session_path)
+ end
+ end
+
+ context 'GET status' do
+ it 'redirects to sign in page' do
+ get :status
+
+ expect(response).to have_gitlab_http_status(:found)
+ expect(response).to redirect_to(new_user_session_path)
+ end
+ end
+ end
+end
diff --git a/spec/controllers/import/manifest_controller_spec.rb b/spec/controllers/import/manifest_controller_spec.rb
index ec8bd45b65c..6b21b45e698 100644
--- a/spec/controllers/import/manifest_controller_spec.rb
+++ b/spec/controllers/import/manifest_controller_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Import::ManifestController do
+RSpec.describe Import::ManifestController, :clean_gitlab_redis_shared_state do
include ImportSpecHelper
let_it_be(:user) { create(:user) }
@@ -16,42 +16,93 @@ RSpec.describe Import::ManifestController do
sign_in(user)
end
- def assign_session_group
- session[:manifest_import_repositories] = []
- session[:manifest_import_group_id] = group.id
+ describe 'POST upload' do
+ context 'with a valid manifest' do
+ it 'saves the manifest and redirects to the status page', :aggregate_failures do
+ post :upload, params: {
+ group_id: group.id,
+ manifest: fixture_file_upload('spec/fixtures/aosp_manifest.xml')
+ }
+
+ metadata = Gitlab::ManifestImport::Metadata.new(user)
+
+ expect(metadata.group_id).to eq(group.id)
+ expect(metadata.repositories.size).to eq(660)
+ expect(metadata.repositories.first).to include(name: 'platform/build', path: 'build/make')
+
+ expect(response).to redirect_to(status_import_manifest_path)
+ end
+ end
+
+ context 'with an invalid manifest' do
+ it 'displays an error' do
+ post :upload, params: {
+ group_id: group.id,
+ manifest: fixture_file_upload('spec/fixtures/invalid_manifest.xml')
+ }
+
+ expect(assigns(:errors)).to be_present
+ end
+ end
+
+ context 'when the user cannot create projects in the group' do
+ it 'displays an error' do
+ sign_in(create(:user))
+
+ post :upload, params: {
+ group_id: group.id,
+ manifest: fixture_file_upload('spec/fixtures/aosp_manifest.xml')
+ }
+
+ expect(assigns(:errors)).to be_present
+ end
+ end
end
describe 'GET status' do
- let(:repo1) { OpenStruct.new(id: 'test1', url: 'http://demo.host/test1') }
- let(:repo2) { OpenStruct.new(id: 'test2', url: 'http://demo.host/test2') }
+ let(:repo1) { { id: 'test1', url: 'http://demo.host/test1' } }
+ let(:repo2) { { id: 'test2', url: 'http://demo.host/test2' } }
let(:repos) { [repo1, repo2] }
- before do
- assign_session_group
+ shared_examples 'status action' do
+ it "returns variables for json request" do
+ project = create(:project, import_type: 'manifest', creator_id: user.id)
- session[:manifest_import_repositories] = repos
- end
+ get :status, format: :json
- it "returns variables for json request" do
- project = create(:project, import_type: 'manifest', creator_id: user.id)
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response.dig("imported_projects", 0, "id")).to eq(project.id)
+ expect(json_response.dig("provider_repos", 0, "id")).to eq(repo1[:id])
+ expect(json_response.dig("provider_repos", 1, "id")).to eq(repo2[:id])
+ expect(json_response.dig("namespaces", 0, "id")).to eq(group.id)
+ end
- get :status, format: :json
+ it "does not show already added project" do
+ project = create(:project, import_type: 'manifest', namespace: user.namespace, import_status: :finished, import_url: repo1[:url])
- expect(response).to have_gitlab_http_status(:ok)
- expect(json_response.dig("imported_projects", 0, "id")).to eq(project.id)
- expect(json_response.dig("provider_repos", 0, "id")).to eq(repo1.id)
- expect(json_response.dig("provider_repos", 1, "id")).to eq(repo2.id)
- expect(json_response.dig("namespaces", 0, "id")).to eq(group.id)
+ get :status, format: :json
+
+ expect(json_response.dig("imported_projects", 0, "id")).to eq(project.id)
+ expect(json_response.dig("provider_repos").length).to eq(1)
+ expect(json_response.dig("provider_repos", 0, "id")).not_to eq(repo1[:id])
+ end
end
- it "does not show already added project" do
- project = create(:project, import_type: 'manifest', namespace: user.namespace, import_status: :finished, import_url: repo1.url)
+ context 'when the data is stored via Gitlab::ManifestImport::Metadata' do
+ before do
+ Gitlab::ManifestImport::Metadata.new(user).save(repos, group.id)
+ end
+
+ include_examples 'status action'
+ end
- get :status, format: :json
+ context 'when the data is stored in the user session' do
+ before do
+ session[:manifest_import_repositories] = repos
+ session[:manifest_import_group_id] = group.id
+ end
- expect(json_response.dig("imported_projects", 0, "id")).to eq(project.id)
- expect(json_response.dig("provider_repos").length).to eq(1)
- expect(json_response.dig("provider_repos", 0, "id")).not_to eq(repo1.id)
+ include_examples 'status action'
end
end
end
diff --git a/spec/controllers/invites_controller_spec.rb b/spec/controllers/invites_controller_spec.rb
index a083cfac981..75a972d2f95 100644
--- a/spec/controllers/invites_controller_spec.rb
+++ b/spec/controllers/invites_controller_spec.rb
@@ -17,8 +17,53 @@ RSpec.describe InvitesController, :snowplow do
}
end
- before do
- controller.instance_variable_set(:@member, member)
+ shared_examples 'invalid token' do
+ context 'when invite token is not valid' do
+ let(:params) { { id: '_bogus_token_' } }
+
+ it 'renders the 404 page' do
+ request
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+ end
+
+ shared_examples "tracks the 'accepted' event for the invitation reminders experiment" do
+ before do
+ stub_experiment(invitation_reminders: true)
+ allow(Gitlab::Experimentation).to receive(:enabled_for_attribute?).with(:invitation_reminders, member.invite_email).and_return(experimental_group)
+ end
+
+ context 'when in the control group' do
+ let(:experimental_group) { false }
+
+ it "tracks the 'accepted' event" do
+ request
+
+ expect_snowplow_event(
+ category: 'Growth::Acquisition::Experiment::InvitationReminders',
+ label: md5_member_global_id,
+ property: 'control_group',
+ action: 'accepted'
+ )
+ end
+ end
+
+ context 'when in the experimental group' do
+ let(:experimental_group) { true }
+
+ it "tracks the 'accepted' event" do
+ request
+
+ expect_snowplow_event(
+ category: 'Growth::Acquisition::Experiment::InvitationReminders',
+ label: md5_member_global_id,
+ property: 'experimental_group',
+ action: 'accepted'
+ )
+ end
+ end
end
describe 'GET #show' do
@@ -39,7 +84,7 @@ RSpec.describe InvitesController, :snowplow do
end
it 'forces re-confirmation if email does not match signed in user' do
- member.invite_email = 'bogus@email.com'
+ member.update!(invite_email: 'bogus@email.com')
expect do
request
@@ -64,8 +109,8 @@ RSpec.describe InvitesController, :snowplow do
it 'tracks the user as experiment group' do
request
- expect_snowplow_event(snowplow_event.merge(action: 'opened'))
- expect_snowplow_event(snowplow_event.merge(action: 'accepted'))
+ expect_snowplow_event(**snowplow_event.merge(action: 'opened'))
+ expect_snowplow_event(**snowplow_event.merge(action: 'accepted'))
end
end
@@ -76,10 +121,13 @@ RSpec.describe InvitesController, :snowplow do
it 'tracks the user as control group' do
request
- expect_snowplow_event(snowplow_event.merge(action: 'opened'))
- expect_snowplow_event(snowplow_event.merge(action: 'accepted'))
+ expect_snowplow_event(**snowplow_event.merge(action: 'opened'))
+ expect_snowplow_event(**snowplow_event.merge(action: 'accepted'))
end
end
+
+ it_behaves_like "tracks the 'accepted' event for the invitation reminders experiment"
+ it_behaves_like 'invalid token'
end
context 'when not logged in' do
@@ -125,7 +173,7 @@ RSpec.describe InvitesController, :snowplow do
it 'tracks the user as experiment group' do
request
- expect_snowplow_event(snowplow_event.merge(action: 'accepted'))
+ expect_snowplow_event(**snowplow_event.merge(action: 'accepted'))
end
end
@@ -136,8 +184,31 @@ RSpec.describe InvitesController, :snowplow do
it 'tracks the user as control group' do
request
- expect_snowplow_event(snowplow_event.merge(action: 'accepted'))
+ expect_snowplow_event(**snowplow_event.merge(action: 'accepted'))
end
end
+
+ it_behaves_like "tracks the 'accepted' event for the invitation reminders experiment"
+ it_behaves_like 'invalid token'
+ end
+
+ describe 'POST #decline for link in UI' do
+ before do
+ sign_in(user)
+ end
+
+ subject(:request) { post :decline, params: params }
+
+ it_behaves_like 'invalid token'
+ end
+
+ describe 'GET #decline for link in email' do
+ before do
+ sign_in(user)
+ end
+
+ subject(:request) { get :decline, params: params }
+
+ it_behaves_like 'invalid token'
end
end
diff --git a/spec/controllers/jira_connect/events_controller_spec.rb b/spec/controllers/jira_connect/events_controller_spec.rb
index d1a2dd6e7af..8a07f69e480 100644
--- a/spec/controllers/jira_connect/events_controller_spec.rb
+++ b/spec/controllers/jira_connect/events_controller_spec.rb
@@ -4,14 +4,20 @@ require 'spec_helper'
RSpec.describe JiraConnect::EventsController do
describe '#installed' do
- subject do
- post :installed, params: {
- clientKey: '1234',
- sharedSecret: 'secret',
+ let(:client_key) { '1234' }
+ let(:shared_secret) { 'secret' }
+ let(:params) do
+ {
+ clientKey: client_key,
+ sharedSecret: shared_secret,
baseUrl: 'https://test.atlassian.net'
}
end
+ subject do
+ post :installed, params: params
+ end
+
it 'saves the jira installation data' do
expect { subject }.to change { JiraConnectInstallation.count }.by(1)
end
@@ -19,15 +25,15 @@ RSpec.describe JiraConnect::EventsController do
it 'saves the correct values' do
subject
- installation = JiraConnectInstallation.find_by_client_key('1234')
+ installation = JiraConnectInstallation.find_by_client_key(client_key)
- expect(installation.shared_secret).to eq('secret')
+ expect(installation.shared_secret).to eq(shared_secret)
expect(installation.base_url).to eq('https://test.atlassian.net')
end
context 'client key already exists' do
it 'returns 422' do
- create(:jira_connect_installation, client_key: '1234')
+ create(:jira_connect_installation, client_key: client_key)
subject
@@ -35,6 +41,23 @@ RSpec.describe JiraConnect::EventsController do
end
end
+ context 'when it is a version update and shared_secret is not sent' do
+ let(:params) do
+ {
+ clientKey: client_key,
+ baseUrl: 'https://test.atlassian.net'
+ }
+ end
+
+ it 'validates the JWT token in authorization header and returns 200 without creating a new installation' do
+ create(:jira_connect_installation, client_key: client_key, shared_secret: shared_secret)
+ request.headers["Authorization"] = "Bearer #{Atlassian::Jwt.encode({ iss: client_key }, shared_secret)}"
+
+ expect { subject }.not_to change { JiraConnectInstallation.count }
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+ end
+
describe '#uninstalled' do
let!(:installation) { create(:jira_connect_installation) }
let(:qsh) { Atlassian::Jwt.create_query_string_hash('https://gitlab.test/events/uninstalled', 'POST', 'https://gitlab.test') }
diff --git a/spec/controllers/profiles_controller_spec.rb b/spec/controllers/profiles_controller_spec.rb
index e08c92da87f..249e6322d1c 100644
--- a/spec/controllers/profiles_controller_spec.rb
+++ b/spec/controllers/profiles_controller_spec.rb
@@ -101,6 +101,19 @@ RSpec.describe ProfilesController, :request_store do
end
end
+ describe 'GET audit_log' do
+ it 'tracks search event', :snowplow do
+ sign_in(user)
+
+ get :audit_log
+
+ expect_snowplow_event(
+ category: 'ProfilesController',
+ action: 'search_audit_event'
+ )
+ end
+ end
+
describe 'PUT update_username' do
let(:namespace) { user.namespace }
let(:gitlab_shell) { Gitlab::Shell.new }
diff --git a/spec/controllers/projects/alert_management_controller_spec.rb b/spec/controllers/projects/alert_management_controller_spec.rb
index 6a1952f949b..d80147b5c59 100644
--- a/spec/controllers/projects/alert_management_controller_spec.rb
+++ b/spec/controllers/projects/alert_management_controller_spec.rb
@@ -42,7 +42,7 @@ RSpec.describe Projects::AlertManagementController do
let(:role) { :reporter }
it 'shows 404' do
- get :index, params: { namespace_id: project.namespace, project_id: project }
+ get :details, params: { namespace_id: project.namespace, project_id: project, id: id }
expect(response).to have_gitlab_http_status(:not_found)
end
diff --git a/spec/controllers/projects/blob_controller_spec.rb b/spec/controllers/projects/blob_controller_spec.rb
index b998dee09b2..a56425c2a22 100644
--- a/spec/controllers/projects/blob_controller_spec.rb
+++ b/spec/controllers/projects/blob_controller_spec.rb
@@ -349,7 +349,7 @@ RSpec.describe Projects::BlobController do
end
it_behaves_like 'tracking unique hll events', :track_editor_edit_actions do
- subject { put :update, params: default_params, format: format }
+ subject(:request) { put :update, params: default_params }
let(:target_id) { 'g_edit_by_sfe' }
let(:expected_type) { instance_of(Integer) }
@@ -465,7 +465,7 @@ RSpec.describe Projects::BlobController do
end
it_behaves_like 'tracking unique hll events', :track_editor_edit_actions do
- subject { post :create, params: default_params, format: format }
+ subject(:request) { post :create, params: default_params }
let(:target_id) { 'g_edit_by_sfe' }
let(:expected_type) { instance_of(Integer) }
diff --git a/spec/controllers/projects/clusters_controller_spec.rb b/spec/controllers/projects/clusters_controller_spec.rb
index 51a451570c5..52cd6869b04 100644
--- a/spec/controllers/projects/clusters_controller_spec.rb
+++ b/spec/controllers/projects/clusters_controller_spec.rb
@@ -251,6 +251,7 @@ RSpec.describe Projects::ClustersController do
cluster: {
name: 'new-cluster',
managed: '1',
+ namespace_per_environment: '0',
provider_gcp_attributes: {
gcp_project_id: 'gcp-project-12345',
legacy_abac: legacy_abac_param
@@ -278,6 +279,7 @@ RSpec.describe Projects::ClustersController do
expect(project.clusters.first).to be_kubernetes
expect(project.clusters.first.provider_gcp).to be_legacy_abac
expect(project.clusters.first.managed?).to be_truthy
+ expect(project.clusters.first.namespace_per_environment?).to be_falsy
end
context 'when legacy_abac param is false' do
@@ -369,6 +371,7 @@ RSpec.describe Projects::ClustersController do
expect(project.clusters.first).to be_user
expect(project.clusters.first).to be_kubernetes
+ expect(project.clusters.first).to be_namespace_per_environment
end
end
@@ -400,6 +403,7 @@ RSpec.describe Projects::ClustersController do
expect(cluster).to be_user
expect(cluster).to be_kubernetes
expect(cluster).to be_platform_kubernetes_rbac
+ expect(cluster).to be_namespace_per_environment
end
end
@@ -726,6 +730,7 @@ RSpec.describe Projects::ClustersController do
enabled: false,
name: 'my-new-cluster-name',
managed: false,
+ namespace_per_environment: false,
platform_kubernetes_attributes: {
namespace: 'my-namespace'
}
@@ -742,6 +747,7 @@ RSpec.describe Projects::ClustersController do
expect(cluster.enabled).to be_falsey
expect(cluster.name).to eq('my-new-cluster-name')
expect(cluster).not_to be_managed
+ expect(cluster).not_to be_namespace_per_environment
expect(cluster.platform_kubernetes.namespace).to eq('my-namespace')
end
diff --git a/spec/controllers/projects/feature_flags_clients_controller_spec.rb b/spec/controllers/projects/feature_flags_clients_controller_spec.rb
new file mode 100644
index 00000000000..f527d2ba430
--- /dev/null
+++ b/spec/controllers/projects/feature_flags_clients_controller_spec.rb
@@ -0,0 +1,57 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Projects::FeatureFlagsClientsController do
+ include Gitlab::Routing
+
+ let_it_be(:project) { create(:project) }
+ let_it_be(:user) { create(:user) }
+
+ describe 'POST reset_token.json' do
+ subject(:reset_token) do
+ post :reset_token,
+ params: { namespace_id: project.namespace, project_id: project },
+ format: :json
+ end
+
+ before do
+ sign_in(user)
+ end
+
+ context 'when user is a project maintainer' do
+ before do
+ project.add_maintainer(user)
+ end
+
+ context 'and feature flags client exist' do
+ it 'regenerates feature flags client token' do
+ project.create_operations_feature_flags_client!
+ expect { reset_token }.to change { project.reload.feature_flags_client_token }
+
+ expect(json_response['token']).to eq(project.feature_flags_client_token)
+ end
+ end
+
+ context 'but feature flags client does not exist' do
+ it 'returns 404' do
+ reset_token
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+ end
+
+ context 'when user is not a project maintainer' do
+ before do
+ project.add_developer(user)
+ end
+
+ it 'returns 404' do
+ reset_token
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+ end
+end
diff --git a/spec/controllers/projects/feature_flags_controller_spec.rb b/spec/controllers/projects/feature_flags_controller_spec.rb
new file mode 100644
index 00000000000..96eeb6f239f
--- /dev/null
+++ b/spec/controllers/projects/feature_flags_controller_spec.rb
@@ -0,0 +1,1604 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Projects::FeatureFlagsController do
+ include Gitlab::Routing
+ include FeatureFlagHelpers
+
+ let_it_be(:project) { create(:project) }
+ let_it_be(:developer) { create(:user) }
+ let_it_be(:reporter) { create(:user) }
+ let(:user) { developer }
+
+ before_all do
+ project.add_developer(developer)
+ project.add_reporter(reporter)
+ end
+
+ before do
+ sign_in(user)
+ end
+
+ describe 'GET index' do
+ render_views
+
+ subject { get(:index, params: view_params) }
+
+ context 'when there is no feature flags' do
+ it 'responds with success' do
+ is_expected.to have_gitlab_http_status(:ok)
+ end
+ end
+
+ context 'for a list of feature flags' do
+ let!(:feature_flags) { create_list(:operations_feature_flag, 50, project: project) }
+
+ it 'responds with success' do
+ is_expected.to have_gitlab_http_status(:ok)
+ end
+ end
+
+ context 'when the user is a reporter' do
+ let(:user) { reporter }
+
+ it 'responds with not found' do
+ is_expected.to have_gitlab_http_status(:not_found)
+ end
+ end
+ end
+
+ describe 'GET #index.json' do
+ subject { get(:index, params: view_params, format: :json) }
+
+ let!(:feature_flag_active) do
+ create(:operations_feature_flag, project: project, active: true, name: 'feature_flag_a')
+ end
+
+ let!(:feature_flag_inactive) do
+ create(:operations_feature_flag, project: project, active: false, name: 'feature_flag_b')
+ end
+
+ it 'returns all feature flags as json response' do
+ subject
+
+ expect(json_response['feature_flags'].count).to eq(2)
+ expect(json_response['feature_flags'].first['name']).to eq(feature_flag_active.name)
+ expect(json_response['feature_flags'].second['name']).to eq(feature_flag_inactive.name)
+ end
+
+ it 'returns CRUD paths' do
+ subject
+
+ expected_edit_path = edit_project_feature_flag_path(project, feature_flag_active)
+ expected_update_path = project_feature_flag_path(project, feature_flag_active)
+ expected_destroy_path = project_feature_flag_path(project, feature_flag_active)
+
+ feature_flag_json = json_response['feature_flags'].first
+
+ expect(feature_flag_json['edit_path']).to eq(expected_edit_path)
+ expect(feature_flag_json['update_path']).to eq(expected_update_path)
+ expect(feature_flag_json['destroy_path']).to eq(expected_destroy_path)
+ end
+
+ it 'returns the summary of feature flags' do
+ subject
+
+ expect(json_response['count']['all']).to eq(2)
+ expect(json_response['count']['enabled']).to eq(1)
+ expect(json_response['count']['disabled']).to eq(1)
+ end
+
+ it 'matches json schema' do
+ is_expected.to match_response_schema('feature_flags')
+ end
+
+ it 'returns false for active when the feature flag is inactive even if it has an active scope' do
+ create(:operations_feature_flag_scope,
+ feature_flag: feature_flag_inactive,
+ environment_scope: 'production',
+ active: true)
+
+ subject
+
+ expect(response).to have_gitlab_http_status(:ok)
+ feature_flag_json = json_response['feature_flags'].second
+
+ expect(feature_flag_json['active']).to eq(false)
+ end
+
+ it 'returns the feature flag iid' do
+ subject
+
+ feature_flag_json = json_response['feature_flags'].first
+
+ expect(feature_flag_json['iid']).to eq(feature_flag_active.iid)
+ end
+
+ context 'when scope is specified' do
+ let(:view_params) do
+ { namespace_id: project.namespace, project_id: project, scope: scope }
+ end
+
+ context 'when all feature flags are requested' do
+ let(:scope) { 'all' }
+
+ it 'returns all feature flags' do
+ subject
+
+ expect(json_response['feature_flags'].count).to eq(2)
+ end
+ end
+
+ context 'when enabled feature flags are requested' do
+ let(:scope) { 'enabled' }
+
+ it 'returns enabled feature flags' do
+ subject
+
+ expect(json_response['feature_flags'].count).to eq(1)
+ expect(json_response['feature_flags'].first['active']).to be_truthy
+ end
+ end
+
+ context 'when disabled feature flags are requested' do
+ let(:scope) { 'disabled' }
+
+ it 'returns disabled feature flags' do
+ subject
+
+ expect(json_response['feature_flags'].count).to eq(1)
+ expect(json_response['feature_flags'].first['active']).to be_falsy
+ end
+ end
+ end
+
+ context 'when feature flags have additional scopes' do
+ let!(:feature_flag_active_scope) do
+ create(:operations_feature_flag_scope,
+ feature_flag: feature_flag_active,
+ environment_scope: 'production',
+ active: false)
+ end
+
+ let!(:feature_flag_inactive_scope) do
+ create(:operations_feature_flag_scope,
+ feature_flag: feature_flag_inactive,
+ environment_scope: 'staging',
+ active: false)
+ end
+
+ it 'returns a correct summary' do
+ subject
+
+ expect(json_response['count']['all']).to eq(2)
+ expect(json_response['count']['enabled']).to eq(1)
+ expect(json_response['count']['disabled']).to eq(1)
+ end
+
+ it 'recognizes feature flag 1 as active' do
+ subject
+
+ expect(json_response['feature_flags'].first['active']).to be_truthy
+ end
+
+ it 'recognizes feature flag 2 as inactive' do
+ subject
+
+ expect(json_response['feature_flags'].second['active']).to be_falsy
+ end
+
+ it 'has ordered scopes' do
+ subject
+
+ expect(json_response['feature_flags'][0]['scopes'][0]['id'])
+ .to be < json_response['feature_flags'][0]['scopes'][1]['id']
+ expect(json_response['feature_flags'][1]['scopes'][0]['id'])
+ .to be < json_response['feature_flags'][1]['scopes'][1]['id']
+ end
+
+ it 'does not have N+1 problem' do
+ recorded = ActiveRecord::QueryRecorder.new { subject }
+
+ related_count = recorded.log
+ .count { |query| query.include?('operations_feature_flag') }
+
+ expect(related_count).to be_within(5).of(2)
+ end
+ end
+
+ context 'with version 1 and 2 feature flags' do
+ let!(:new_version_feature_flag) do
+ create(:operations_feature_flag, :new_version_flag, project: project, name: 'feature_flag_c')
+ end
+
+ it 'returns all feature flags as json response' do
+ subject
+
+ expect(json_response['feature_flags'].count).to eq(3)
+ end
+
+ it 'returns only version 1 flags when new version flags are disabled' do
+ stub_feature_flags(feature_flags_new_version: false)
+
+ subject
+
+ expected = [feature_flag_active.name, feature_flag_inactive.name].sort
+ expect(json_response['feature_flags'].map { |f| f['name'] }.sort).to eq(expected)
+ end
+ end
+ end
+
+ describe 'GET new' do
+ render_views
+
+ subject { get(:new, params: view_params) }
+
+ it 'renders the form' do
+ is_expected.to have_gitlab_http_status(:ok)
+ end
+ end
+
+ describe 'GET #show.json' do
+ subject { get(:show, params: params, format: :json) }
+
+ let!(:feature_flag) do
+ create(:operations_feature_flag, project: project)
+ end
+
+ let(:params) do
+ {
+ namespace_id: project.namespace,
+ project_id: project,
+ iid: feature_flag.iid
+ }
+ end
+
+ it 'returns the feature flag as json response' do
+ subject
+
+ expect(json_response['name']).to eq(feature_flag.name)
+ expect(json_response['active']).to eq(feature_flag.active)
+ expect(json_response['version']).to eq('legacy_flag')
+ end
+
+ it 'matches json schema' do
+ is_expected.to match_response_schema('feature_flag')
+ end
+
+ it 'routes based on iid' do
+ other_project = create(:project)
+ other_project.add_developer(user)
+ other_feature_flag = create(:operations_feature_flag, project: other_project,
+ name: 'other_flag')
+ params = {
+ namespace_id: other_project.namespace,
+ project_id: other_project,
+ iid: other_feature_flag.iid
+ }
+
+ get(:show, params: params, format: :json)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['name']).to eq(other_feature_flag.name)
+ end
+
+ it 'routes based on iid when new version flags are disabled' do
+ stub_feature_flags(feature_flags_new_version: false)
+ other_project = create(:project)
+ other_project.add_developer(user)
+ other_feature_flag = create(:operations_feature_flag, project: other_project,
+ name: 'other_flag')
+ params = {
+ namespace_id: other_project.namespace,
+ project_id: other_project,
+ iid: other_feature_flag.iid
+ }
+
+ get(:show, params: params, format: :json)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['name']).to eq(other_feature_flag.name)
+ end
+
+ context 'when feature flag is not found' do
+ let!(:feature_flag) { }
+
+ let(:params) do
+ {
+ namespace_id: project.namespace,
+ project_id: project,
+ iid: 1
+ }
+ end
+
+ it 'returns 404' do
+ is_expected.to have_gitlab_http_status(:not_found)
+ end
+ end
+
+ context 'when user is reporter' do
+ let(:user) { reporter }
+
+ it 'returns 404' do
+ is_expected.to have_gitlab_http_status(:not_found)
+ end
+ end
+
+ context 'when feature flags have additional scopes' do
+ context 'when there is at least one active scope' do
+ let!(:feature_flag) do
+ create(:operations_feature_flag, project: project, active: false)
+ end
+
+ let!(:feature_flag_scope_production) do
+ create(:operations_feature_flag_scope,
+ feature_flag: feature_flag,
+ environment_scope: 'review/*',
+ active: true)
+ end
+
+ it 'returns false for active' do
+ subject
+
+ expect(json_response['active']).to eq(false)
+ end
+ end
+
+ context 'when all scopes are inactive' do
+ let!(:feature_flag) do
+ create(:operations_feature_flag, project: project, active: false)
+ end
+
+ let!(:feature_flag_scope_production) do
+ create(:operations_feature_flag_scope,
+ feature_flag: feature_flag,
+ environment_scope: 'production',
+ active: false)
+ end
+
+ it 'recognizes the feature flag as inactive' do
+ subject
+
+ expect(json_response['active']).to be_falsy
+ end
+ end
+ end
+
+ context 'with a version 2 feature flag' do
+ let!(:new_version_feature_flag) do
+ create(:operations_feature_flag, :new_version_flag, project: project)
+ end
+
+ let(:params) do
+ {
+ namespace_id: project.namespace,
+ project_id: project,
+ iid: new_version_feature_flag.iid
+ }
+ end
+
+ it 'returns the feature flag' do
+ subject
+
+ expect(json_response['name']).to eq(new_version_feature_flag.name)
+ expect(json_response['active']).to eq(new_version_feature_flag.active)
+ expect(json_response['version']).to eq('new_version_flag')
+ end
+
+ it 'returns a 404 when new version flags are disabled' do
+ stub_feature_flags(feature_flags_new_version: false)
+
+ subject
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+
+ it 'returns strategies ordered by id' do
+ first_strategy = create(:operations_strategy, feature_flag: new_version_feature_flag)
+ second_strategy = create(:operations_strategy, feature_flag: new_version_feature_flag)
+
+ subject
+
+ expect(json_response['strategies'].map { |s| s['id'] }).to eq([first_strategy.id, second_strategy.id])
+ end
+ end
+ end
+
+ describe 'POST create.json' do
+ subject { post(:create, params: params, format: :json) }
+
+ let(:params) do
+ {
+ namespace_id: project.namespace,
+ project_id: project,
+ operations_feature_flag: {
+ name: 'my_feature_flag',
+ active: true
+ }
+ }
+ end
+
+ it 'returns 200' do
+ is_expected.to have_gitlab_http_status(:ok)
+ end
+
+ it 'creates a new feature flag' do
+ subject
+
+ expect(json_response['name']).to eq('my_feature_flag')
+ expect(json_response['active']).to be_truthy
+ end
+
+ it 'creates a default scope' do
+ subject
+
+ expect(json_response['scopes'].count).to eq(1)
+ expect(json_response['scopes'].first['environment_scope']).to eq('*')
+ expect(json_response['scopes'].first['active']).to be_truthy
+ end
+
+ it 'matches json schema' do
+ is_expected.to match_response_schema('feature_flag')
+ end
+
+ context 'when the same named feature flag has already existed' do
+ before do
+ create(:operations_feature_flag, name: 'my_feature_flag', project: project)
+ end
+
+ it 'returns 400' do
+ is_expected.to have_gitlab_http_status(:bad_request)
+ end
+
+ it 'returns an error message' do
+ subject
+
+ expect(json_response['message']).to include('Name has already been taken')
+ end
+ end
+
+ context 'without the active parameter' do
+ let(:params) do
+ {
+ namespace_id: project.namespace,
+ project_id: project,
+ operations_feature_flag: {
+ name: 'my_feature_flag'
+ }
+ }
+ end
+
+ it 'creates a flag with active set to true' do
+ expect { subject }.to change { Operations::FeatureFlag.count }.by(1)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to match_response_schema('feature_flag')
+ expect(json_response['active']).to eq(true)
+ expect(Operations::FeatureFlag.last.active).to eq(true)
+ end
+ end
+
+ context 'when user is reporter' do
+ let(:user) { reporter }
+
+ it 'returns 404' do
+ is_expected.to have_gitlab_http_status(:not_found)
+ end
+ end
+
+ context 'when creates additional scope' do
+ let(:params) do
+ view_params.merge({
+ operations_feature_flag: {
+ name: 'my_feature_flag',
+ active: true,
+ scopes_attributes: [{ environment_scope: '*', active: true },
+ { environment_scope: 'production', active: false }]
+ }
+ })
+ end
+
+ it 'creates feature flag scopes successfully' do
+ expect { subject }.to change { Operations::FeatureFlagScope.count }.by(2)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+
+ it 'creates feature flag scopes in a correct order' do
+ subject
+
+ expect(json_response['scopes'].first['environment_scope']).to eq('*')
+ expect(json_response['scopes'].second['environment_scope']).to eq('production')
+ end
+
+ context 'when default scope is not placed first' do
+ let(:params) do
+ view_params.merge({
+ operations_feature_flag: {
+ name: 'my_feature_flag',
+ active: true,
+ scopes_attributes: [{ environment_scope: 'production', active: false },
+ { environment_scope: '*', active: true }]
+ }
+ })
+ end
+
+ it 'returns 400' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ expect(json_response['message'])
+ .to include('Default scope has to be the first element')
+ end
+ end
+ end
+
+ context 'when creates additional scope with a percentage rollout' do
+ it 'creates a strategy for the scope' do
+ params = view_params.merge({
+ operations_feature_flag: {
+ name: 'my_feature_flag',
+ active: true,
+ scopes_attributes: [{ environment_scope: '*', active: true },
+ { environment_scope: 'production', active: false,
+ strategies: [{ name: 'gradualRolloutUserId',
+ parameters: { groupId: 'default', percentage: '42' } }] }]
+ }
+ })
+
+ post(:create, params: params, format: :json)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ production_strategies_json = json_response['scopes'].second['strategies']
+ expect(production_strategies_json).to eq([{
+ 'name' => 'gradualRolloutUserId',
+ 'parameters' => { "groupId" => "default", "percentage" => "42" }
+ }])
+ end
+ end
+
+ context 'when creates additional scope with a userWithId strategy' do
+ it 'creates a strategy for the scope' do
+ params = view_params.merge({
+ operations_feature_flag: {
+ name: 'my_feature_flag',
+ active: true,
+ scopes_attributes: [{ environment_scope: '*', active: true },
+ { environment_scope: 'production', active: false,
+ strategies: [{ name: 'userWithId',
+ parameters: { userIds: '123,4,6722' } }] }]
+ }
+ })
+
+ post(:create, params: params, format: :json)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ production_strategies_json = json_response['scopes'].second['strategies']
+ expect(production_strategies_json).to eq([{
+ 'name' => 'userWithId',
+ 'parameters' => { "userIds" => "123,4,6722" }
+ }])
+ end
+ end
+
+ context 'when creates an additional scope without a strategy' do
+ it 'creates a default strategy' do
+ params = view_params.merge({
+ operations_feature_flag: {
+ name: 'my_feature_flag',
+ active: true,
+ scopes_attributes: [{ environment_scope: '*', active: true }]
+ }
+ })
+
+ post(:create, params: params, format: :json)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ default_strategies_json = json_response['scopes'].first['strategies']
+ expect(default_strategies_json).to eq([{ "name" => "default", "parameters" => {} }])
+ end
+ end
+
+ context 'when creating a version 2 feature flag' do
+ let(:params) do
+ {
+ namespace_id: project.namespace,
+ project_id: project,
+ operations_feature_flag: {
+ name: 'my_feature_flag',
+ active: true,
+ version: 'new_version_flag'
+ }
+ }
+ end
+
+ it 'creates a new feature flag' do
+ subject
+
+ expect(json_response['name']).to eq('my_feature_flag')
+ expect(json_response['active']).to be_truthy
+ expect(json_response['version']).to eq('new_version_flag')
+ end
+ end
+
+ context 'when creating a version 2 feature flag with strategies and scopes' do
+ let(:params) do
+ {
+ namespace_id: project.namespace,
+ project_id: project,
+ operations_feature_flag: {
+ name: 'my_feature_flag',
+ active: true,
+ version: 'new_version_flag',
+ strategies_attributes: [{
+ name: 'userWithId',
+ parameters: { userIds: 'user1' },
+ scopes_attributes: [{ environment_scope: '*' }]
+ }]
+ }
+ }
+ end
+
+ it 'creates a new feature flag with the strategies and scopes' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['name']).to eq('my_feature_flag')
+ expect(json_response['active']).to eq(true)
+ expect(json_response['strategies'].count).to eq(1)
+
+ strategy_json = json_response['strategies'].first
+ expect(strategy_json).to have_key('id')
+ expect(strategy_json['name']).to eq('userWithId')
+ expect(strategy_json['parameters']).to eq({ 'userIds' => 'user1' })
+ expect(strategy_json['scopes'].count).to eq(1)
+
+ scope_json = strategy_json['scopes'].first
+ expect(scope_json).to have_key('id')
+ expect(scope_json['environment_scope']).to eq('*')
+ end
+ end
+
+ context 'when creating a version 2 feature flag with a gradualRolloutUserId strategy' do
+ let(:params) do
+ {
+ namespace_id: project.namespace,
+ project_id: project,
+ operations_feature_flag: {
+ name: 'my_feature_flag',
+ active: true,
+ version: 'new_version_flag',
+ strategies_attributes: [{
+ name: 'gradualRolloutUserId',
+ parameters: { groupId: 'default', percentage: '15' },
+ scopes_attributes: [{ environment_scope: 'production' }]
+ }]
+ }
+ }
+ end
+
+ it 'creates the new strategy' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:ok)
+
+ strategy_json = json_response['strategies'].first
+ expect(strategy_json['name']).to eq('gradualRolloutUserId')
+ expect(strategy_json['parameters']).to eq({ 'groupId' => 'default', 'percentage' => '15' })
+ expect(strategy_json['scopes'].count).to eq(1)
+
+ scope_json = strategy_json['scopes'].first
+ expect(scope_json['environment_scope']).to eq('production')
+ end
+ end
+
+ context 'when creating a version 2 feature flag with a flexibleRollout strategy' do
+ let(:params) do
+ {
+ namespace_id: project.namespace,
+ project_id: project,
+ operations_feature_flag: {
+ name: 'my_feature_flag',
+ active: true,
+ version: 'new_version_flag',
+ strategies_attributes: [{
+ name: 'flexibleRollout',
+ parameters: { groupId: 'default', rollout: '15', stickiness: 'DEFAULT' },
+ scopes_attributes: [{ environment_scope: 'production' }]
+ }]
+ }
+ }
+ end
+
+ it 'creates the new strategy' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:ok)
+
+ strategy_json = json_response['strategies'].first
+ expect(strategy_json['name']).to eq('flexibleRollout')
+ expect(strategy_json['parameters']).to eq({ 'groupId' => 'default', 'rollout' => '15', 'stickiness' => 'DEFAULT' })
+ expect(strategy_json['scopes'].count).to eq(1)
+
+ scope_json = strategy_json['scopes'].first
+ expect(scope_json['environment_scope']).to eq('production')
+ end
+ end
+
+ context 'when creating a version 2 feature flag with a gitlabUserList strategy' do
+ let!(:user_list) do
+ create(:operations_feature_flag_user_list, project: project,
+ name: 'My List', user_xids: 'user1,user2')
+ end
+
+ let(:params) do
+ {
+ namespace_id: project.namespace,
+ project_id: project,
+ operations_feature_flag: {
+ name: 'my_feature_flag',
+ active: true,
+ version: 'new_version_flag',
+ strategies_attributes: [{
+ name: 'gitlabUserList',
+ parameters: {},
+ user_list_id: user_list.id,
+ scopes_attributes: [{ environment_scope: 'production' }]
+ }]
+ }
+ }
+ end
+
+ it 'creates the new strategy' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['strategies']).to match([a_hash_including({
+ 'name' => 'gitlabUserList',
+ 'parameters' => {},
+ 'user_list' => {
+ 'id' => user_list.id,
+ 'iid' => user_list.iid,
+ 'name' => 'My List',
+ 'user_xids' => 'user1,user2'
+ },
+ 'scopes' => [a_hash_including({
+ 'environment_scope' => 'production'
+ })]
+ })])
+ end
+ end
+
+ context 'when version parameter is invalid' do
+ let(:params) do
+ {
+ namespace_id: project.namespace,
+ project_id: project,
+ operations_feature_flag: {
+ name: 'my_feature_flag',
+ active: true,
+ version: 'bad_version'
+ }
+ }
+ end
+
+ it 'returns a 400' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ expect(json_response).to eq({ 'message' => 'Version is invalid' })
+ expect(Operations::FeatureFlag.count).to eq(0)
+ end
+ end
+
+ context 'when version 2 flags are disabled' do
+ context 'and attempting to create a version 2 flag' do
+ let(:params) do
+ {
+ namespace_id: project.namespace,
+ project_id: project,
+ operations_feature_flag: {
+ name: 'my_feature_flag',
+ active: true,
+ version: 'new_version_flag'
+ }
+ }
+ end
+
+ it 'returns a 400' do
+ stub_feature_flags(feature_flags_new_version: false)
+
+ subject
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ expect(Operations::FeatureFlag.count).to eq(0)
+ end
+ end
+
+ context 'and attempting to create a version 1 flag' do
+ let(:params) do
+ {
+ namespace_id: project.namespace,
+ project_id: project,
+ operations_feature_flag: {
+ name: 'my_feature_flag',
+ active: true
+ }
+ }
+ end
+
+ it 'creates the flag' do
+ stub_feature_flags(feature_flags_new_version: false)
+
+ subject
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(Operations::FeatureFlag.count).to eq(1)
+ expect(json_response['version']).to eq('legacy_flag')
+ end
+ end
+ end
+ end
+
+ describe 'DELETE destroy.json' do
+ subject { delete(:destroy, params: params, format: :json) }
+
+ let!(:feature_flag) { create(:operations_feature_flag, project: project) }
+
+ let(:params) do
+ {
+ namespace_id: project.namespace,
+ project_id: project,
+ iid: feature_flag.iid
+ }
+ end
+
+ it 'returns 200' do
+ is_expected.to have_gitlab_http_status(:ok)
+ end
+
+ it 'deletes one feature flag' do
+ expect { subject }.to change { Operations::FeatureFlag.count }.by(-1)
+ end
+
+ it 'destroys the default scope' do
+ expect { subject }.to change { Operations::FeatureFlagScope.count }.by(-1)
+ end
+
+ it 'matches json schema' do
+ is_expected.to match_response_schema('feature_flag')
+ end
+
+ context 'when user is reporter' do
+ let(:user) { reporter }
+
+ it 'returns 404' do
+ is_expected.to have_gitlab_http_status(:not_found)
+ end
+ end
+
+ context 'when the feature flag does not exist' do
+ let(:params) do
+ {
+ namespace_id: project.namespace,
+ project_id: project,
+ iid: 0
+ }
+ end
+
+ it 'returns not found' do
+ is_expected.to have_gitlab_http_status(:not_found)
+ end
+ end
+
+ context 'when there is an additional scope' do
+ let!(:scope) { create_scope(feature_flag, 'production', false) }
+
+ it 'destroys the default scope and production scope' do
+ expect { subject }.to change { Operations::FeatureFlagScope.count }.by(-2)
+ end
+ end
+
+ context 'with a version 2 flag' do
+ let!(:new_version_flag) { create(:operations_feature_flag, :new_version_flag, project: project) }
+ let(:params) do
+ {
+ namespace_id: project.namespace,
+ project_id: project,
+ iid: new_version_flag.iid
+ }
+ end
+
+ it 'deletes the flag' do
+ expect { subject }.to change { Operations::FeatureFlag.count }.by(-1)
+ end
+
+ context 'when new version flags are disabled' do
+ it 'returns a 404' do
+ stub_feature_flags(feature_flags_new_version: false)
+
+ expect { subject }.not_to change { Operations::FeatureFlag.count }
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+ end
+ end
+
+ describe 'PUT update.json' do
+ def put_request(feature_flag, feature_flag_params)
+ params = {
+ namespace_id: project.namespace,
+ project_id: project,
+ iid: feature_flag.iid,
+ operations_feature_flag: feature_flag_params
+ }
+
+ put(:update, params: params, format: :json, as: :json)
+ end
+
+ before do
+ stub_feature_flags(
+ feature_flags_legacy_read_only: false,
+ feature_flags_legacy_read_only_override: false
+ )
+ end
+
+ subject { put(:update, params: params, format: :json) }
+
+ let!(:feature_flag) do
+ create(:operations_feature_flag,
+ :legacy_flag,
+ name: 'ci_live_trace',
+ active: true,
+ project: project)
+ end
+
+ let(:params) do
+ {
+ namespace_id: project.namespace,
+ project_id: project,
+ iid: feature_flag.iid,
+ operations_feature_flag: {
+ name: 'ci_new_live_trace'
+ }
+ }
+ end
+
+ it 'returns 200' do
+ is_expected.to have_gitlab_http_status(:ok)
+ end
+
+ it 'updates the name of the feature flag name' do
+ subject
+
+ expect(json_response['name']).to eq('ci_new_live_trace')
+ end
+
+ it 'matches json schema' do
+ is_expected.to match_response_schema('feature_flag')
+ end
+
+ context 'when updates active' do
+ let(:params) do
+ {
+ namespace_id: project.namespace,
+ project_id: project,
+ iid: feature_flag.iid,
+ operations_feature_flag: {
+ active: false
+ }
+ }
+ end
+
+ it 'updates active from true to false' do
+ expect { subject }
+ .to change { feature_flag.reload.active }.from(true).to(false)
+ end
+
+ it "does not change default scope's active" do
+ expect { subject }
+ .not_to change { feature_flag.default_scope.reload.active }.from(true)
+ end
+
+ it 'updates active from false to true when an inactive feature flag has an active scope' do
+ feature_flag = create(:operations_feature_flag, project: project, name: 'my_flag', active: false)
+ create(:operations_feature_flag_scope, feature_flag: feature_flag, environment_scope: 'production', active: true)
+
+ put_request(feature_flag, { active: true })
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to match_response_schema('feature_flag')
+ expect(json_response['active']).to eq(true)
+ expect(feature_flag.reload.active).to eq(true)
+ expect(feature_flag.default_scope.reload.active).to eq(false)
+ end
+ end
+
+ context 'when user is reporter' do
+ let(:user) { reporter }
+
+ it 'returns 404' do
+ is_expected.to have_gitlab_http_status(:not_found)
+ end
+ end
+
+ context "when creates an additional scope for production environment" do
+ let(:params) do
+ {
+ namespace_id: project.namespace,
+ project_id: project,
+ iid: feature_flag.iid,
+ operations_feature_flag: {
+ scopes_attributes: [{ environment_scope: 'production', active: false }]
+ }
+ }
+ end
+
+ it 'creates a production scope' do
+ expect { subject }.to change { feature_flag.reload.scopes.count }.by(1)
+
+ expect(json_response['scopes'].last['environment_scope']).to eq('production')
+ expect(json_response['scopes'].last['active']).to be_falsy
+ end
+ end
+
+ context "when creates a default scope" do
+ let(:params) do
+ {
+ namespace_id: project.namespace,
+ project_id: project,
+ iid: feature_flag.iid,
+ operations_feature_flag: {
+ scopes_attributes: [{ environment_scope: '*', active: false }]
+ }
+ }
+ end
+
+ it 'returns 400' do
+ is_expected.to have_gitlab_http_status(:bad_request)
+ end
+ end
+
+ context "when updates a default scope's active value" do
+ let(:params) do
+ {
+ namespace_id: project.namespace,
+ project_id: project,
+ iid: feature_flag.iid,
+ operations_feature_flag: {
+ scopes_attributes: [
+ {
+ id: feature_flag.default_scope.id,
+ environment_scope: '*',
+ active: false
+ }
+ ]
+ }
+ }
+ end
+
+ it "updates successfully" do
+ subject
+
+ expect(json_response['scopes'].first['environment_scope']).to eq('*')
+ expect(json_response['scopes'].first['active']).to be_falsy
+ end
+ end
+
+ context "when changes default scope's spec" do
+ let(:params) do
+ {
+ namespace_id: project.namespace,
+ project_id: project,
+ iid: feature_flag.iid,
+ operations_feature_flag: {
+ scopes_attributes: [
+ {
+ id: feature_flag.default_scope.id,
+ environment_scope: 'review/*'
+ }
+ ]
+ }
+ }
+ end
+
+ it 'returns 400' do
+ is_expected.to have_gitlab_http_status(:bad_request)
+ end
+ end
+
+ context "when destroys the default scope" do
+ let(:params) do
+ {
+ namespace_id: project.namespace,
+ project_id: project,
+ iid: feature_flag.iid,
+ operations_feature_flag: {
+ scopes_attributes: [
+ {
+ id: feature_flag.default_scope.id,
+ _destroy: 1
+ }
+ ]
+ }
+ }
+ end
+
+ it 'raises an error' do
+ expect { subject }.to raise_error(ActiveRecord::ReadOnlyRecord)
+ end
+ end
+
+ context "when destroys a production scope" do
+ let!(:production_scope) { create_scope(feature_flag, 'production', true) }
+ let(:params) do
+ {
+ namespace_id: project.namespace,
+ project_id: project,
+ iid: feature_flag.iid,
+ operations_feature_flag: {
+ scopes_attributes: [
+ {
+ id: production_scope.id,
+ _destroy: 1
+ }
+ ]
+ }
+ }
+ end
+
+ it 'destroys successfully' do
+ subject
+
+ scopes = json_response['scopes']
+ expect(scopes.any? { |scope| scope['environment_scope'] == 'production' })
+ .to be_falsy
+ end
+ end
+
+ describe "updating the strategy" do
+ it 'creates a default strategy' do
+ scope = create_scope(feature_flag, 'production', true, [])
+
+ put_request(feature_flag, scopes_attributes: [{
+ id: scope.id,
+ strategies: [{ name: 'default', parameters: {} }]
+ }])
+
+ expect(response).to have_gitlab_http_status(:ok)
+ scope_json = json_response['scopes'].find do |s|
+ s['environment_scope'] == 'production'
+ end
+ expect(scope_json['strategies']).to eq([{
+ "name" => "default",
+ "parameters" => {}
+ }])
+ end
+
+ it 'creates a gradualRolloutUserId strategy' do
+ scope = create_scope(feature_flag, 'production', true, [])
+
+ put_request(feature_flag, scopes_attributes: [{
+ id: scope.id,
+ strategies: [{ name: 'gradualRolloutUserId',
+ parameters: { groupId: 'default', percentage: "70" } }]
+ }])
+
+ expect(response).to have_gitlab_http_status(:ok)
+ scope_json = json_response['scopes'].find do |s|
+ s['environment_scope'] == 'production'
+ end
+ expect(scope_json['strategies']).to eq([{
+ "name" => "gradualRolloutUserId",
+ "parameters" => {
+ "groupId" => "default",
+ "percentage" => "70"
+ }
+ }])
+ end
+
+ it 'creates a userWithId strategy' do
+ scope = create_scope(feature_flag, 'production', true, [{ name: 'default', parameters: {} }])
+
+ put_request(feature_flag, scopes_attributes: [{
+ id: scope.id,
+ strategies: [{ name: 'userWithId', parameters: { userIds: 'sam,fred' } }]
+ }])
+
+ expect(response).to have_gitlab_http_status(:ok)
+ scope_json = json_response['scopes'].find do |s|
+ s['environment_scope'] == 'production'
+ end
+ expect(scope_json['strategies']).to eq([{
+ "name" => "userWithId",
+ "parameters" => { "userIds" => "sam,fred" }
+ }])
+ end
+
+ it 'updates an existing strategy' do
+ scope = create_scope(feature_flag, 'production', true, [{ name: 'default', parameters: {} }])
+
+ put_request(feature_flag, scopes_attributes: [{
+ id: scope.id,
+ strategies: [{ name: 'gradualRolloutUserId',
+ parameters: { groupId: 'default', percentage: "50" } }]
+ }])
+
+ expect(response).to have_gitlab_http_status(:ok)
+ scope_json = json_response['scopes'].find do |s|
+ s['environment_scope'] == 'production'
+ end
+ expect(scope_json['strategies']).to eq([{
+ "name" => "gradualRolloutUserId",
+ "parameters" => {
+ "groupId" => "default",
+ "percentage" => "50"
+ }
+ }])
+ end
+
+ it 'clears an existing strategy' do
+ scope = create_scope(feature_flag, 'production', true, [{ name: 'default', parameters: {} }])
+
+ put_request(feature_flag, scopes_attributes: [{
+ id: scope.id,
+ strategies: []
+ }])
+
+ expect(response).to have_gitlab_http_status(:ok)
+ scope_json = json_response['scopes'].find do |s|
+ s['environment_scope'] == 'production'
+ end
+ expect(scope_json['strategies']).to eq([])
+ end
+
+ it 'accepts multiple strategies' do
+ scope = create_scope(feature_flag, 'production', true, [{ name: 'default', parameters: {} }])
+
+ put_request(feature_flag, scopes_attributes: [{
+ id: scope.id,
+ strategies: [
+ { name: 'gradualRolloutUserId', parameters: { groupId: 'mygroup', percentage: '55' } },
+ { name: 'userWithId', parameters: { userIds: 'joe' } }
+ ]
+ }])
+
+ expect(response).to have_gitlab_http_status(:ok)
+ scope_json = json_response['scopes'].find do |s|
+ s['environment_scope'] == 'production'
+ end
+ expect(scope_json['strategies'].length).to eq(2)
+ expect(scope_json['strategies']).to include({
+ "name" => "gradualRolloutUserId",
+ "parameters" => { "groupId" => "mygroup", "percentage" => "55" }
+ })
+ expect(scope_json['strategies']).to include({
+ "name" => "userWithId",
+ "parameters" => { "userIds" => "joe" }
+ })
+ end
+
+ it 'does not modify strategies when there is no strategies key in the params' do
+ scope = create_scope(feature_flag, 'production', true, [{ name: 'default', parameters: {} }])
+
+ put_request(feature_flag, scopes_attributes: [{ id: scope.id }])
+
+ expect(response).to have_gitlab_http_status(:ok)
+ scope_json = json_response['scopes'].find do |s|
+ s['environment_scope'] == 'production'
+ end
+ expect(scope_json['strategies']).to eq([{
+ "name" => "default",
+ "parameters" => {}
+ }])
+ end
+
+ it 'leaves an existing strategy when there are no strategies in the params' do
+ scope = create_scope(feature_flag, 'production', true, [{ name: 'gradualRolloutUserId',
+ parameters: { groupId: 'default', percentage: '10' } }])
+
+ put_request(feature_flag, scopes_attributes: [{ id: scope.id }])
+
+ expect(response).to have_gitlab_http_status(:ok)
+ scope_json = json_response['scopes'].find do |s|
+ s['environment_scope'] == 'production'
+ end
+ expect(scope_json['strategies']).to eq([{
+ "name" => "gradualRolloutUserId",
+ "parameters" => { "groupId" => "default", "percentage" => "10" }
+ }])
+ end
+
+ it 'does not accept extra parameters in the strategy params' do
+ scope = create_scope(feature_flag, 'production', true, [{ name: 'default', parameters: {} }])
+
+ put_request(feature_flag, scopes_attributes: [{
+ id: scope.id,
+ strategies: [{ name: 'userWithId', parameters: { userIds: 'joe', groupId: 'default' } }]
+ }])
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ expect(json_response['message']).to eq(["Scopes strategies parameters are invalid"])
+ end
+ end
+
+ context 'when legacy feature flags are set to be read only' do
+ it 'does not update the flag' do
+ stub_feature_flags(feature_flags_legacy_read_only: true)
+
+ put_request(feature_flag, name: 'ci_new_live_trace')
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ expect(json_response['message']).to eq(["Legacy feature flags are read-only"])
+ end
+
+ it 'updates the flag if the legacy read-only override is enabled for a particular project' do
+ stub_feature_flags(
+ feature_flags_legacy_read_only: true,
+ feature_flags_legacy_read_only_override: project
+ )
+
+ put_request(feature_flag, name: 'ci_new_live_trace')
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['name']).to eq('ci_new_live_trace')
+ end
+ end
+
+ context 'with a version 2 feature flag' do
+ let!(:new_version_flag) do
+ create(:operations_feature_flag,
+ :new_version_flag,
+ name: 'new-feature',
+ active: true,
+ project: project)
+ end
+
+ it 'creates a new strategy and scope' do
+ put_request(new_version_flag, strategies_attributes: [{
+ name: 'userWithId',
+ parameters: { userIds: 'user1' },
+ scopes_attributes: [{
+ environment_scope: 'production'
+ }]
+ }])
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['strategies'].count).to eq(1)
+ strategy_json = json_response['strategies'].first
+ expect(strategy_json['name']).to eq('userWithId')
+ expect(strategy_json['parameters']).to eq({
+ 'userIds' => 'user1'
+ })
+ expect(strategy_json['scopes'].count).to eq(1)
+ scope_json = strategy_json['scopes'].first
+ expect(scope_json['environment_scope']).to eq('production')
+ end
+
+ it 'creates a gradualRolloutUserId strategy' do
+ put_request(new_version_flag, strategies_attributes: [{
+ name: 'gradualRolloutUserId',
+ parameters: { groupId: 'default', percentage: '30' }
+ }])
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['strategies'].count).to eq(1)
+ strategy_json = json_response['strategies'].first
+ expect(strategy_json['name']).to eq('gradualRolloutUserId')
+ expect(strategy_json['parameters']).to eq({
+ 'groupId' => 'default',
+ 'percentage' => '30'
+ })
+ expect(strategy_json['scopes']).to eq([])
+ end
+
+ it 'creates a flexibleRollout strategy' do
+ put_request(new_version_flag, strategies_attributes: [{
+ name: 'flexibleRollout',
+ parameters: { groupId: 'default', rollout: '30', stickiness: 'DEFAULT' }
+ }])
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['strategies'].count).to eq(1)
+ strategy_json = json_response['strategies'].first
+ expect(strategy_json['name']).to eq('flexibleRollout')
+ expect(strategy_json['parameters']).to eq({
+ 'groupId' => 'default',
+ 'rollout' => '30',
+ 'stickiness' => 'DEFAULT'
+ })
+ expect(strategy_json['scopes']).to eq([])
+ end
+
+ it 'creates a gitlabUserList strategy' do
+ user_list = create(:operations_feature_flag_user_list, project: project, name: 'My List', user_xids: 'user1,user2')
+
+ put_request(new_version_flag, strategies_attributes: [{
+ name: 'gitlabUserList',
+ parameters: {},
+ user_list_id: user_list.id
+ }])
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['strategies']).to match([a_hash_including({
+ 'id' => an_instance_of(Integer),
+ 'name' => 'gitlabUserList',
+ 'parameters' => {},
+ 'user_list' => {
+ 'id' => user_list.id,
+ 'iid' => user_list.iid,
+ 'name' => 'My List',
+ 'user_xids' => 'user1,user2'
+ },
+ 'scopes' => []
+ })])
+ end
+
+ it 'supports switching the associated user list for an existing gitlabUserList strategy' do
+ user_list = create(:operations_feature_flag_user_list, project: project, name: 'My List', user_xids: 'user1,user2')
+ strategy = create(:operations_strategy, feature_flag: new_version_flag, name: 'gitlabUserList', parameters: {}, user_list: user_list)
+ other_user_list = create(:operations_feature_flag_user_list, project: project, name: 'Other List', user_xids: 'user3')
+
+ put_request(new_version_flag, strategies_attributes: [{
+ id: strategy.id,
+ user_list_id: other_user_list.id
+ }])
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['strategies']).to eq([{
+ 'id' => strategy.id,
+ 'name' => 'gitlabUserList',
+ 'parameters' => {},
+ 'user_list' => {
+ 'id' => other_user_list.id,
+ 'iid' => other_user_list.iid,
+ 'name' => 'Other List',
+ 'user_xids' => 'user3'
+ },
+ 'scopes' => []
+ }])
+ end
+
+ it 'automatically dissociates the user list when switching the type of an existing gitlabUserList strategy' do
+ user_list = create(:operations_feature_flag_user_list, project: project, name: 'My List', user_xids: 'user1,user2')
+ strategy = create(:operations_strategy, feature_flag: new_version_flag, name: 'gitlabUserList', parameters: {}, user_list: user_list)
+
+ put_request(new_version_flag, strategies_attributes: [{
+ id: strategy.id,
+ name: 'gradualRolloutUserId',
+ parameters: {
+ groupId: 'default',
+ percentage: '25'
+ }
+ }])
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['strategies']).to eq([{
+ 'id' => strategy.id,
+ 'name' => 'gradualRolloutUserId',
+ 'parameters' => {
+ 'groupId' => 'default',
+ 'percentage' => '25'
+ },
+ 'scopes' => []
+ }])
+ end
+
+ it 'does not delete a user list when deleting a gitlabUserList strategy' do
+ user_list = create(:operations_feature_flag_user_list, project: project, name: 'My List', user_xids: 'user1,user2')
+ strategy = create(:operations_strategy, feature_flag: new_version_flag, name: 'gitlabUserList', parameters: {}, user_list: user_list)
+
+ put_request(new_version_flag, strategies_attributes: [{
+ id: strategy.id,
+ _destroy: true
+ }])
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['strategies']).to eq([])
+ expect(::Operations::FeatureFlags::Strategy.count).to eq(0)
+ expect(::Operations::FeatureFlags::StrategyUserList.count).to eq(0)
+ expect(::Operations::FeatureFlags::UserList.first).to eq(user_list)
+ end
+
+ it 'returns not found when trying to create a gitlabUserList strategy with an invalid user list id' do
+ put_request(new_version_flag, strategies_attributes: [{
+ name: 'gitlabUserList',
+ parameters: {},
+ user_list_id: 1
+ }])
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+
+ it 'updates an existing strategy' do
+ strategy = create(:operations_strategy, feature_flag: new_version_flag, name: 'default', parameters: {})
+
+ put_request(new_version_flag, strategies_attributes: [{
+ id: strategy.id,
+ name: 'userWithId',
+ parameters: { userIds: 'user2,user3' }
+ }])
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['strategies']).to eq([{
+ 'id' => strategy.id,
+ 'name' => 'userWithId',
+ 'parameters' => { 'userIds' => 'user2,user3' },
+ 'scopes' => []
+ }])
+ end
+
+ it 'updates an existing scope' do
+ strategy = create(:operations_strategy, feature_flag: new_version_flag, name: 'default', parameters: {})
+ scope = create(:operations_scope, strategy: strategy, environment_scope: 'staging')
+
+ put_request(new_version_flag, strategies_attributes: [{
+ id: strategy.id,
+ scopes_attributes: [{
+ id: scope.id,
+ environment_scope: 'sandbox'
+ }]
+ }])
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['strategies'].first['scopes']).to eq([{
+ 'id' => scope.id,
+ 'environment_scope' => 'sandbox'
+ }])
+ end
+
+ it 'deletes an existing strategy' do
+ strategy = create(:operations_strategy, feature_flag: new_version_flag, name: 'default', parameters: {})
+
+ put_request(new_version_flag, strategies_attributes: [{
+ id: strategy.id,
+ _destroy: true
+ }])
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['strategies']).to eq([])
+ end
+
+ it 'deletes an existing scope' do
+ strategy = create(:operations_strategy, feature_flag: new_version_flag, name: 'default', parameters: {})
+ scope = create(:operations_scope, strategy: strategy, environment_scope: 'staging')
+
+ put_request(new_version_flag, strategies_attributes: [{
+ id: strategy.id,
+ scopes_attributes: [{
+ id: scope.id,
+ _destroy: true
+ }]
+ }])
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['strategies'].first['scopes']).to eq([])
+ end
+
+ it 'does not update the flag if version 2 flags are disabled' do
+ stub_feature_flags(feature_flags_new_version: false)
+
+ put_request(new_version_flag, { name: 'some-other-name' })
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ expect(new_version_flag.reload.name).to eq('new-feature')
+ end
+
+ it 'updates the flag when legacy feature flags are set to be read only' do
+ stub_feature_flags(feature_flags_legacy_read_only: true)
+
+ put_request(new_version_flag, name: 'some-other-name')
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(new_version_flag.reload.name).to eq('some-other-name')
+ end
+ end
+ end
+
+ private
+
+ def view_params
+ { namespace_id: project.namespace, project_id: project }
+ end
+end
diff --git a/spec/controllers/projects/feature_flags_user_lists_controller_spec.rb b/spec/controllers/projects/feature_flags_user_lists_controller_spec.rb
new file mode 100644
index 00000000000..e0d1d3765b2
--- /dev/null
+++ b/spec/controllers/projects/feature_flags_user_lists_controller_spec.rb
@@ -0,0 +1,113 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Projects::FeatureFlagsUserListsController do
+ let_it_be(:project) { create(:project) }
+ let_it_be(:reporter) { create(:user) }
+ let_it_be(:developer) { create(:user) }
+
+ before_all do
+ project.add_reporter(reporter)
+ project.add_developer(developer)
+ end
+
+ def request_params(extra_params = {})
+ { namespace_id: project.namespace, project_id: project }.merge(extra_params)
+ end
+
+ describe 'GET #new' do
+ it 'redirects when the user is unauthenticated' do
+ get(:new, params: request_params)
+
+ expect(response).to redirect_to(new_user_session_path)
+ end
+
+ it 'returns not found if the user does not belong to the project' do
+ user = create(:user)
+ sign_in(user)
+
+ get(:new, params: request_params)
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+
+ it 'returns not found for a reporter' do
+ sign_in(reporter)
+
+ get(:new, params: request_params)
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+
+ it 'renders the new page for a developer' do
+ sign_in(developer)
+
+ get(:new, params: request_params)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+ end
+
+ describe 'GET #edit' do
+ before do
+ sign_in(developer)
+ end
+
+ it 'renders the edit page for a developer' do
+ list = create(:operations_feature_flag_user_list, project: project)
+
+ get(:edit, params: request_params(iid: list.iid))
+
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+
+ it 'returns not found with an iid that does not exist' do
+ list = create(:operations_feature_flag_user_list, project: project)
+
+ get(:edit, params: request_params(iid: list.iid + 1))
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+
+ it 'returns not found for a list belonging to a another project' do
+ other_project = create(:project)
+ list = create(:operations_feature_flag_user_list, project: other_project)
+
+ get(:edit, params: request_params(iid: list.iid))
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+
+ describe 'GET #show' do
+ before do
+ sign_in(developer)
+ end
+
+ it 'renders the page for a developer' do
+ list = create(:operations_feature_flag_user_list, project: project)
+
+ get(:show, params: request_params(iid: list.iid))
+
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+
+ it 'returns not found with an iid that does not exist' do
+ list = create(:operations_feature_flag_user_list, project: project)
+
+ get(:show, params: request_params(iid: list.iid + 1))
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+
+ it 'returns not found for a list belonging to a another project' do
+ other_project = create(:project)
+ list = create(:operations_feature_flag_user_list, project: other_project)
+
+ get(:show, params: request_params(iid: list.iid))
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+end
diff --git a/spec/controllers/projects/group_links_controller_spec.rb b/spec/controllers/projects/group_links_controller_spec.rb
index 762ef795f6e..3baadde46dc 100644
--- a/spec/controllers/projects/group_links_controller_spec.rb
+++ b/spec/controllers/projects/group_links_controller_spec.rb
@@ -3,10 +3,10 @@
require 'spec_helper'
RSpec.describe Projects::GroupLinksController do
- let(:group) { create(:group, :private) }
- let(:group2) { create(:group, :private) }
- let(:project) { create(:project, :private, group: group2) }
- let(:user) { create(:user) }
+ let_it_be(:group) { create(:group, :private) }
+ let_it_be(:group2) { create(:group, :private) }
+ let_it_be(:project) { create(:project, :private, group: group2) }
+ let_it_be(:user) { create(:user) }
before do
project.add_maintainer(user)
@@ -142,4 +142,47 @@ RSpec.describe Projects::GroupLinksController do
end
end
end
+
+ describe '#update' do
+ let_it_be(:link) do
+ create(
+ :project_group_link,
+ {
+ project: project,
+ group: group
+ }
+ )
+ end
+
+ let(:expiry_date) { 1.month.from_now.to_date }
+
+ before do
+ travel_to Time.now.utc.beginning_of_day
+
+ put(
+ :update,
+ params: {
+ namespace_id: project.namespace.to_param,
+ project_id: project.to_param,
+ id: link.id,
+ group_link: { group_access: Gitlab::Access::GUEST, expires_at: expiry_date }
+ },
+ format: :json
+ )
+ end
+
+ context 'when `expires_at` is set' do
+ it 'returns correct json response' do
+ expect(json_response).to eq({ "expires_in" => "about 1 month", "expires_soon" => false })
+ end
+ end
+
+ context 'when `expires_at` is not set' do
+ let(:expiry_date) { nil }
+
+ it 'returns empty json response' do
+ expect(json_response).to be_empty
+ end
+ end
+ end
end
diff --git a/spec/controllers/projects/hooks_controller_spec.rb b/spec/controllers/projects/hooks_controller_spec.rb
index bd543cebeec..b9c008d2950 100644
--- a/spec/controllers/projects/hooks_controller_spec.rb
+++ b/spec/controllers/projects/hooks_controller_spec.rb
@@ -48,6 +48,14 @@ RSpec.describe Projects::HooksController do
end
end
+ describe 'DELETE #destroy' do
+ let!(:hook) { create(:project_hook, project: project) }
+ let!(:log) { create(:web_hook_log, web_hook: hook) }
+ let(:params) { { namespace_id: project.namespace, project_id: project, id: hook } }
+
+ it_behaves_like 'Web hook destroyer'
+ end
+
describe '#test' do
let(:hook) { create(:project_hook, project: project) }
diff --git a/spec/controllers/projects/import/jira_controller_spec.rb b/spec/controllers/projects/import/jira_controller_spec.rb
index b82735a56b3..37a7fce0c23 100644
--- a/spec/controllers/projects/import/jira_controller_spec.rb
+++ b/spec/controllers/projects/import/jira_controller_spec.rb
@@ -12,7 +12,6 @@ RSpec.describe Projects::Import::JiraController do
def ensure_correct_config
sign_in(user)
project.add_maintainer(user)
- stub_feature_flags(jira_issue_import: true)
stub_jira_service_test
end
@@ -77,7 +76,6 @@ RSpec.describe Projects::Import::JiraController do
before do
sign_in(user)
project.add_maintainer(user)
- stub_feature_flags(jira_issue_import: true)
end
context 'when Jira service is not enabled for the project' do
diff --git a/spec/controllers/projects/incidents_controller_spec.rb b/spec/controllers/projects/incidents_controller_spec.rb
index 2baae0661cb..ddd15b9b1dd 100644
--- a/spec/controllers/projects/incidents_controller_spec.rb
+++ b/spec/controllers/projects/incidents_controller_spec.rb
@@ -3,44 +3,119 @@
require 'spec_helper'
RSpec.describe Projects::IncidentsController do
- let_it_be(:project) { create(:project) }
+ let_it_be_with_refind(:project) { create(:project) }
let_it_be(:developer) { create(:user) }
let_it_be(:guest) { create(:user) }
+ let_it_be(:anonymous) { nil }
before_all do
- project.add_developer(developer)
project.add_guest(guest)
+ project.add_developer(developer)
+ end
+
+ before do
+ sign_in(user) if user
+ end
+
+ subject { make_request }
+
+ shared_examples 'not found' do
+ include_examples 'returning response status', :not_found
+ end
+
+ shared_examples 'login required' do
+ it 'redirects to the login page' do
+ subject
+
+ expect(response).to redirect_to(new_user_session_path)
+ end
end
describe 'GET #index' do
def make_request
- get :index, params: { namespace_id: project.namespace, project_id: project }
+ get :index, params: project_params
end
- it 'shows the page for user with developer role' do
- sign_in(developer)
- make_request
+ let(:user) { developer }
+
+ it 'shows the page' do
+ subject
expect(response).to have_gitlab_http_status(:ok)
expect(response).to render_template(:index)
end
context 'when user is unauthorized' do
- it 'redirects to the login page' do
- sign_out(developer)
- make_request
+ let(:user) { anonymous }
+
+ it_behaves_like 'login required'
+ end
+
+ context 'when user is a guest' do
+ let(:user) { guest }
+
+ it 'shows the page' do
+ subject
- expect(response).to redirect_to(new_user_session_path)
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to render_template(:index)
end
end
+ end
+
+ describe 'GET #show' do
+ def make_request
+ get :show, params: project_params(id: resource)
+ end
+
+ let_it_be(:resource) { create(:incident, project: project) }
+ let(:user) { developer }
+
+ it 'renders incident page' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to render_template(:show)
+
+ expect(assigns(:incident)).to be_present
+ expect(assigns(:incident).author.association(:status)).to be_loaded
+ expect(assigns(:issue)).to be_present
+ expect(assigns(:noteable)).to eq(assigns(:incident))
+ end
+
+ context 'with non existing id' do
+ let(:resource) { non_existing_record_id }
+
+ it_behaves_like 'not found'
+ end
+
+ context 'for issue' do
+ let_it_be(:resource) { create(:issue, project: project) }
+
+ it_behaves_like 'not found'
+ end
context 'when user is a guest' do
- it 'shows 404' do
- sign_in(guest)
- make_request
+ let(:user) { guest }
- expect(response).to have_gitlab_http_status(:not_found)
+ it 'shows the page' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to render_template(:show)
end
end
+
+ context 'when unauthorized' do
+ let(:user) { anonymous }
+
+ it_behaves_like 'login required'
+ 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/issues_controller_spec.rb b/spec/controllers/projects/issues_controller_spec.rb
index ed5198bf015..f956baa0e22 100644
--- a/spec/controllers/projects/issues_controller_spec.rb
+++ b/spec/controllers/projects/issues_controller_spec.rb
@@ -388,15 +388,23 @@ RSpec.describe Projects::IssuesController do
# Rails router. A controller-style spec matches the wrong route, and
# session['user_return_to'] becomes incorrect.
describe 'Redirect after sign in', type: :request do
- context 'with an AJAX request' do
+ before_all do
+ project.add_developer(user)
+ end
+
+ before do
+ login_as(user)
+ end
+
+ context 'with a JSON request' do
it 'does not store the visited URL' do
- get project_issue_path(project, issue), xhr: true
+ get project_issue_path(project, issue, format: :json)
expect(session['user_return_to']).to be_blank
end
end
- context 'without an AJAX request' do
+ context 'with an HTML request' do
it 'stores the visited URL' do
get project_issue_path(project, issue)
@@ -1642,7 +1650,7 @@ RSpec.describe Projects::IssuesController do
end
it 'allows CSV export' do
- expect(ExportCsvWorker).to receive(:perform_async).with(viewer.id, project.id, anything)
+ expect(IssuableExportCsvWorker).to receive(:perform_async).with(:issue, viewer.id, project.id, anything)
request_csv
@@ -1657,7 +1665,7 @@ RSpec.describe Projects::IssuesController do
it 'redirects to the sign in page' do
request_csv
- expect(ExportCsvWorker).not_to receive(:perform_async)
+ expect(IssuableExportCsvWorker).not_to receive(:perform_async)
expect(response).to redirect_to(new_user_session_path)
end
end
diff --git a/spec/controllers/projects/jobs_controller_spec.rb b/spec/controllers/projects/jobs_controller_spec.rb
index 94cce1964ca..80cb16966e5 100644
--- a/spec/controllers/projects/jobs_controller_spec.rb
+++ b/spec/controllers/projects/jobs_controller_spec.rb
@@ -121,13 +121,6 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state do
expect(response).to have_gitlab_http_status(:ok)
expect(assigns(:build).id).to eq(job.id)
end
-
- it 'has the correct build collection' do
- builds = assigns(:builds).map(&:id)
-
- expect(builds).to include(job.id, second_job.id)
- expect(builds).not_to include(third_job.id)
- end
end
context 'when job does not exist' do
@@ -204,16 +197,40 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state do
context 'with not expiry date' do
let(:job) { create(:ci_build, :success, :artifacts, pipeline: pipeline) }
- it 'exposes needed information' do
- get_show_json
+ context 'when artifacts are unlocked' do
+ before do
+ job.pipeline.unlocked!
+ end
- expect(response).to have_gitlab_http_status(:ok)
- expect(response).to match_response_schema('job/job_details')
- expect(json_response['artifact']['download_path']).to match(%r{artifacts/download})
- expect(json_response['artifact']['browse_path']).to match(%r{artifacts/browse})
- expect(json_response['artifact']).not_to have_key('keep_path')
- expect(json_response['artifact']).not_to have_key('expired')
- expect(json_response['artifact']).not_to have_key('expired_at')
+ it 'exposes needed information' do
+ get_show_json
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to match_response_schema('job/job_details')
+ expect(json_response['artifact']['download_path']).to match(%r{artifacts/download})
+ expect(json_response['artifact']['browse_path']).to match(%r{artifacts/browse})
+ expect(json_response['artifact']).not_to have_key('keep_path')
+ expect(json_response['artifact']).not_to have_key('expired')
+ expect(json_response['artifact']).not_to have_key('expired_at')
+ end
+ end
+
+ context 'when artifacts are locked' do
+ before do
+ job.pipeline.artifacts_locked!
+ end
+
+ it 'exposes needed information' do
+ get_show_json
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to match_response_schema('job/job_details')
+ expect(json_response['artifact']['download_path']).to match(%r{artifacts/download})
+ expect(json_response['artifact']['browse_path']).to match(%r{artifacts/browse})
+ expect(json_response['artifact']).not_to have_key('keep_path')
+ expect(json_response['artifact']).not_to have_key('expired')
+ expect(json_response['artifact']).not_to have_key('expired_at')
+ end
end
end
@@ -740,19 +757,21 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state do
name: 'master', project: project)
sign_in(user)
-
- post_play
end
context 'when job is playable' do
let(:job) { create(:ci_build, :playable, pipeline: pipeline) }
it 'redirects to the played job page' do
+ post_play
+
expect(response).to have_gitlab_http_status(:found)
expect(response).to redirect_to(namespace_project_job_path(id: job.id))
end
it 'transits to pending' do
+ post_play
+
expect(job.reload).to be_pending
end
@@ -760,15 +779,54 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state do
let(:variable_attributes) { [{ key: 'first', secret_value: 'first' }] }
it 'assigns the job variables' do
+ post_play
+
expect(job.reload.job_variables.map(&:key)).to contain_exactly('first')
end
end
+
+ context 'when job is bridge' do
+ let(:downstream_project) { create(:project) }
+ let(:job) { create(:ci_bridge, :playable, pipeline: pipeline, downstream: downstream_project) }
+
+ before do
+ downstream_project.add_developer(user)
+ end
+
+ it 'redirects to the pipeline page' do
+ post_play
+
+ expect(response).to have_gitlab_http_status(:found)
+ expect(response).to redirect_to(pipeline_path(pipeline))
+ builds_namespace_project_pipeline_path(id: pipeline.id)
+ end
+
+ it 'transits to pending' do
+ post_play
+
+ expect(job.reload).to be_pending
+ end
+
+ context 'when FF ci_manual_bridges is disabled' do
+ before do
+ stub_feature_flags(ci_manual_bridges: false)
+ end
+
+ it 'returns 404' do
+ post_play
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+ end
end
context 'when job is not playable' do
let(:job) { create(:ci_build, pipeline: pipeline) }
it 'renders unprocessable_entity' do
+ post_play
+
expect(response).to have_gitlab_http_status(:unprocessable_entity)
end
end
diff --git a/spec/controllers/projects/labels_controller_spec.rb b/spec/controllers/projects/labels_controller_spec.rb
index f213d104747..8a3c55033cb 100644
--- a/spec/controllers/projects/labels_controller_spec.rb
+++ b/spec/controllers/projects/labels_controller_spec.rb
@@ -3,9 +3,9 @@
require 'spec_helper'
RSpec.describe Projects::LabelsController do
- let(:group) { create(:group) }
- let(:project) { create(:project, namespace: group) }
- let(:user) { create(:user) }
+ let_it_be(:group) { create(:group) }
+ let_it_be(:project, reload: true) { create(:project, namespace: group) }
+ let_it_be(:user) { create(:user) }
before do
project.add_maintainer(user)
@@ -14,16 +14,21 @@ RSpec.describe Projects::LabelsController do
end
describe 'GET #index' do
- let!(:label_1) { create(:label, project: project, priority: 1, title: 'Label 1') }
- let!(:label_2) { create(:label, project: project, priority: 3, title: 'Label 2') }
- let!(:label_3) { create(:label, project: project, priority: 1, title: 'Label 3') }
- let!(:label_4) { create(:label, project: project, title: 'Label 4') }
- let!(:label_5) { create(:label, project: project, title: 'Label 5') }
-
- let!(:group_label_1) { create(:group_label, group: group, title: 'Group Label 1') }
- let!(:group_label_2) { create(:group_label, group: group, title: 'Group Label 2') }
- let!(:group_label_3) { create(:group_label, group: group, title: 'Group Label 3') }
- let!(:group_label_4) { create(:group_label, group: group, title: 'Group Label 4') }
+ let_it_be(:label_1) { create(:label, project: project, priority: 1, title: 'Label 1') }
+ let_it_be(:label_2) { create(:label, project: project, priority: 3, title: 'Label 2') }
+ let_it_be(:label_3) { create(:label, project: project, priority: 1, title: 'Label 3') }
+ let_it_be(:label_4) { create(:label, project: project, title: 'Label 4') }
+ let_it_be(:label_5) { create(:label, project: project, title: 'Label 5') }
+
+ let_it_be(:group_label_1) { create(:group_label, group: group, title: 'Group Label 1') }
+ let_it_be(:group_label_2) { create(:group_label, group: group, title: 'Group Label 2') }
+ let_it_be(:group_label_3) { create(:group_label, group: group, title: 'Group Label 3') }
+ let_it_be(:group_label_4) { create(:group_label, group: group, title: 'Group Label 4') }
+
+ let_it_be(:group_labels) { [group_label_3, group_label_4]}
+ let_it_be(:project_labels) { [label_4, label_5]}
+ let_it_be(:group_priority_labels) { [group_label_1, group_label_2]}
+ let_it_be(:project_priority_labels) { [label_1, label_2, label_3]}
before do
create(:label_priority, project: project, label: group_label_1, priority: 3)
@@ -68,6 +73,60 @@ RSpec.describe Projects::LabelsController do
end
end
+ context 'with subgroups' do
+ let_it_be(:subgroup) { create(:group, parent: group) }
+ let_it_be(:subgroup_label_1) { create(:group_label, group: subgroup, title: 'subgroup_label_1') }
+ let_it_be(:subgroup_label_2) { create(:group_label, group: subgroup, title: 'subgroup_label_2') }
+
+ before do
+ project.update!(namespace: subgroup)
+ subgroup.add_owner(user)
+ create(:label_priority, project: project, label: subgroup_label_2, priority: 1)
+ end
+
+ RSpec.shared_examples 'returns ancestor group labels' do
+ it 'returns ancestor group labels', :aggregate_failures do
+ get :index, params: params
+
+ expect(assigns(:labels)).to match_array([subgroup_label_1] + group_labels + project_labels)
+ expect(assigns(:prioritized_labels)).to match_array([subgroup_label_2] + group_priority_labels + project_priority_labels)
+ end
+ end
+
+ context 'when show_inherited_labels disabled' do
+ before do
+ stub_feature_flags(show_inherited_labels: false)
+ end
+
+ context 'when include_ancestor_groups false' do
+ let(:params) { { namespace_id: project.namespace.to_param, project_id: project } }
+
+ it 'does not return ancestor group labels', :aggregate_failures do
+ get :index, params: params
+
+ expect(assigns(:labels)).to match_array([subgroup_label_1] + project_labels)
+ expect(assigns(:prioritized_labels)).to match_array([subgroup_label_2] + project_priority_labels)
+ end
+ end
+
+ context 'when include_ancestor_groups true' do
+ let(:params) { { namespace_id: project.namespace.to_param, project_id: project, include_ancestor_groups: true } }
+
+ it_behaves_like 'returns ancestor group labels'
+ end
+ end
+
+ context 'when show_inherited_labels enabled' do
+ let(:params) { { namespace_id: project.namespace.to_param, project_id: project } }
+
+ before do
+ stub_feature_flags(show_inherited_labels: true)
+ end
+
+ it_behaves_like 'returns ancestor group labels'
+ end
+ end
+
def list_labels
get :index, params: { namespace_id: project.namespace.to_param, project_id: project }
end
@@ -75,7 +134,7 @@ RSpec.describe Projects::LabelsController do
describe 'POST #generate' do
context 'personal project' do
- let(:personal_project) { create(:project, namespace: user.namespace) }
+ let_it_be(:personal_project) { create(:project, namespace: user.namespace) }
it 'creates labels' do
post :generate, params: { namespace_id: personal_project.namespace.to_param, project_id: personal_project }
@@ -116,8 +175,8 @@ RSpec.describe Projects::LabelsController do
end
describe 'POST #promote' do
- let!(:promoted_label_name) { "Promoted Label" }
- let!(:label_1) { create(:label, title: promoted_label_name, project: project) }
+ let_it_be(:promoted_label_name) { "Promoted Label" }
+ let_it_be(:label_1) { create(:label, title: promoted_label_name, project: project) }
context 'not group reporters' do
it 'denies access' do
@@ -196,7 +255,7 @@ RSpec.describe Projects::LabelsController do
end
context 'when requesting a redirected path' do
- let!(:redirect_route) { project.redirect_routes.create(path: project.full_path + 'old') }
+ let_it_be(:redirect_route) { project.redirect_routes.create(path: project.full_path + 'old') }
it 'redirects to the canonical path' do
get :index, params: { namespace_id: project.namespace, project_id: project.to_param + 'old' }
@@ -242,7 +301,7 @@ RSpec.describe Projects::LabelsController do
end
context 'when requesting a redirected path' do
- let!(:redirect_route) { project.redirect_routes.create(path: project.full_path + 'old') }
+ let_it_be(:redirect_route) { project.redirect_routes.create(path: project.full_path + 'old') }
it 'returns not found' do
post :generate, params: { namespace_id: project.namespace, project_id: project.to_param + 'old' }
diff --git a/spec/controllers/projects/merge_requests/conflicts_controller_spec.rb b/spec/controllers/projects/merge_requests/conflicts_controller_spec.rb
index 5f636bd4340..c2cc3d10ea0 100644
--- a/spec/controllers/projects/merge_requests/conflicts_controller_spec.rb
+++ b/spec/controllers/projects/merge_requests/conflicts_controller_spec.rb
@@ -156,7 +156,7 @@ RSpec.describe Projects::MergeRequests::ConflictsController do
expect(json_response).to include('old_path' => path,
'new_path' => path,
- 'blob_icon' => 'file-text-o',
+ 'blob_icon' => 'doc-text',
'blob_path' => a_string_ending_with(path),
'content' => content)
end
diff --git a/spec/controllers/projects/milestones_controller_spec.rb b/spec/controllers/projects/milestones_controller_spec.rb
index fa32d32f552..9e5d41b1075 100644
--- a/spec/controllers/projects/milestones_controller_spec.rb
+++ b/spec/controllers/projects/milestones_controller_spec.rb
@@ -17,7 +17,9 @@ RSpec.describe Projects::MilestonesController do
controller.instance_variable_set(:@project, project)
end
- it_behaves_like 'milestone tabs'
+ it_behaves_like 'milestone tabs' do
+ let(:request_params) { { namespace_id: project.namespace, project_id: project, id: milestone.iid } }
+ end
describe "#show" do
render_views
diff --git a/spec/controllers/projects/pipelines/stages_controller_spec.rb b/spec/controllers/projects/pipelines/stages_controller_spec.rb
index 6e8c08d95a1..a8b328c7563 100644
--- a/spec/controllers/projects/pipelines/stages_controller_spec.rb
+++ b/spec/controllers/projects/pipelines/stages_controller_spec.rb
@@ -5,6 +5,7 @@ require 'spec_helper'
RSpec.describe Projects::Pipelines::StagesController do
let(:user) { create(:user) }
let(:project) { create(:project, :repository) }
+ let(:downstream_project) { create(:project, :repository) }
before do
sign_in(user)
@@ -17,6 +18,7 @@ RSpec.describe Projects::Pipelines::StagesController do
before do
create_manual_build(pipeline, 'test', 'rspec 1/2')
create_manual_build(pipeline, 'test', 'rspec 2/2')
+ create_manual_bridge(pipeline, 'test', 'trigger')
pipeline.reload
end
@@ -32,6 +34,7 @@ RSpec.describe Projects::Pipelines::StagesController do
context 'when user has access' do
before do
project.add_maintainer(user)
+ downstream_project.add_maintainer(user)
end
context 'when the stage does not exists' do
@@ -46,12 +49,12 @@ RSpec.describe Projects::Pipelines::StagesController do
context 'when the stage exists' do
it 'starts all manual jobs' do
- expect(pipeline.builds.manual.count).to eq(2)
+ expect(pipeline.processables.manual.count).to eq(3)
play_manual_stage!
expect(response).to have_gitlab_http_status(:ok)
- expect(pipeline.builds.manual.count).to eq(0)
+ expect(pipeline.processables.manual.count).to eq(0)
end
end
end
@@ -68,5 +71,9 @@ RSpec.describe Projects::Pipelines::StagesController do
def create_manual_build(pipeline, stage, name)
create(:ci_build, :manual, pipeline: pipeline, stage: stage, name: name)
end
+
+ def create_manual_bridge(pipeline, stage, name)
+ create(:ci_bridge, :manual, pipeline: pipeline, stage: stage, name: name, downstream: downstream_project)
+ end
end
end
diff --git a/spec/controllers/projects/pipelines_controller_spec.rb b/spec/controllers/projects/pipelines_controller_spec.rb
index c3be7de25a8..0720124ea57 100644
--- a/spec/controllers/projects/pipelines_controller_spec.rb
+++ b/spec/controllers/projects/pipelines_controller_spec.rb
@@ -1148,4 +1148,84 @@ RSpec.describe Projects::PipelinesController do
}
end
end
+
+ describe 'GET config_variables.json' do
+ let(:result) { YAML.dump(ci_config) }
+
+ before do
+ stub_gitlab_ci_yml_for_sha(sha, result)
+ end
+
+ context 'when sending a valid sha' do
+ let(:sha) { 'master' }
+ let(:ci_config) do
+ {
+ variables: {
+ KEY1: { value: 'val 1', description: 'description 1' }
+ },
+ test: {
+ stage: 'test',
+ script: 'echo'
+ }
+ }
+ end
+
+ it 'returns variable list' do
+ get_config_variables
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['KEY1']).to eq({ 'value' => 'val 1', 'description' => 'description 1' })
+ end
+ end
+
+ context 'when sending an invalid sha' do
+ let(:sha) { 'invalid-sha' }
+ let(:ci_config) { nil }
+
+ it 'returns empty json' do
+ get_config_variables
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response).to eq({})
+ end
+ end
+
+ context 'when sending an invalid config' do
+ let(:sha) { 'master' }
+ let(:ci_config) do
+ {
+ variables: {
+ KEY1: { value: 'val 1', description: 'description 1' }
+ },
+ test: {
+ stage: 'invalid',
+ script: 'echo'
+ }
+ }
+ end
+
+ it 'returns empty result' do
+ get_config_variables
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response).to eq({})
+ end
+ end
+
+ private
+
+ def stub_gitlab_ci_yml_for_sha(sha, result)
+ allow_any_instance_of(Repository)
+ .to receive(:gitlab_ci_yml_for)
+ .with(sha, '.gitlab-ci.yml')
+ .and_return(result)
+ end
+
+ def get_config_variables
+ get :config_variables, params: { namespace_id: project.namespace,
+ project_id: project,
+ sha: sha },
+ format: :json
+ end
+ end
end
diff --git a/spec/controllers/projects/project_members_controller_spec.rb b/spec/controllers/projects/project_members_controller_spec.rb
index ae05e2d2631..74311fa89f3 100644
--- a/spec/controllers/projects/project_members_controller_spec.rb
+++ b/spec/controllers/projects/project_members_controller_spec.rb
@@ -228,6 +228,43 @@ RSpec.describe Projects::ProjectMembersController do
end
end
end
+
+ context 'expiration date' do
+ let(:expiry_date) { 1.month.from_now.to_date }
+
+ before do
+ travel_to Time.now.utc.beginning_of_day
+
+ put(
+ :update,
+ params: {
+ project_member: { expires_at: expiry_date },
+ namespace_id: project.namespace,
+ project_id: project,
+ id: requester
+ },
+ format: :json
+ )
+ end
+
+ context 'when `expires_at` is set' do
+ it 'returns correct json response' do
+ expect(json_response).to eq({
+ "expires_in" => "about 1 month",
+ "expires_soon" => false,
+ "expires_at_formatted" => expiry_date.to_time.in_time_zone.to_s(:medium)
+ })
+ end
+ end
+
+ context 'when `expires_at` is not set' do
+ let(:expiry_date) { nil }
+
+ it 'returns empty json response' do
+ expect(json_response).to be_empty
+ end
+ end
+ end
end
describe 'DELETE destroy' do
@@ -536,4 +573,19 @@ RSpec.describe Projects::ProjectMembersController do
end
end
end
+
+ describe 'POST resend_invite' do
+ let(:member) { create(:project_member, project: project) }
+
+ before do
+ project.add_maintainer(user)
+ sign_in(user)
+ end
+
+ it 'is successful' do
+ post :resend_invite, params: { namespace_id: project.namespace, project_id: project, id: member }
+
+ expect(response).to have_gitlab_http_status(:found)
+ end
+ end
end
diff --git a/spec/controllers/projects/registry/tags_controller_spec.rb b/spec/controllers/projects/registry/tags_controller_spec.rb
index 6adee35b60a..59df9e78a3c 100644
--- a/spec/controllers/projects/registry/tags_controller_spec.rb
+++ b/spec/controllers/projects/registry/tags_controller_spec.rb
@@ -109,7 +109,7 @@ RSpec.describe Projects::Registry::TagsController do
it 'tracks the event' do
expect_delete_tags(%w[test.])
- expect(controller).to receive(:track_event).with(:delete_tag)
+ expect(controller).to receive(:track_event).with(:delete_tag, {})
destroy_tag('test.')
end
diff --git a/spec/controllers/projects/releases/evidences_controller_spec.rb b/spec/controllers/projects/releases/evidences_controller_spec.rb
index d5a9665d6a5..0ec4cdf2a31 100644
--- a/spec/controllers/projects/releases/evidences_controller_spec.rb
+++ b/spec/controllers/projects/releases/evidences_controller_spec.rb
@@ -113,18 +113,6 @@ RSpec.describe Projects::Releases::EvidencesController do
it_behaves_like 'does not show the issue in evidence'
- context 'when the issue is confidential' do
- let(:issue) { create(:issue, :confidential, project: project) }
-
- it_behaves_like 'does not show the issue in evidence'
- end
-
- context 'when the user is the author of the confidential issue' do
- let(:issue) { create(:issue, :confidential, project: project, author: user) }
-
- it_behaves_like 'does not show the issue in evidence'
- end
-
context 'when project is private' do
let(:project) { create(:project, :repository, :private) }
@@ -143,32 +131,16 @@ RSpec.describe Projects::Releases::EvidencesController do
it_behaves_like 'does not show the issue in evidence'
- context 'when the issue is confidential' do
- let(:issue) { create(:issue, :confidential, project: project) }
-
- it_behaves_like 'does not show the issue in evidence'
- end
-
- context 'when the user is the author of the confidential issue' do
- let(:issue) { create(:issue, :confidential, project: project, author: user) }
-
- it_behaves_like 'does not show the issue in evidence'
- end
-
context 'when project is private' do
let(:project) { create(:project, :repository, :private) }
- it 'returns evidence ' do
- subject
-
- expect(json_response).to eq(evidence.summary)
- end
+ it_behaves_like 'does not show the issue in evidence'
end
context 'when project restricts the visibility of issues to project members only' do
let(:project) { create(:project, :repository, :issues_private) }
- it_behaves_like 'evidence not found'
+ it_behaves_like 'does not show the issue in evidence'
end
end
diff --git a/spec/controllers/projects/releases_controller_spec.rb b/spec/controllers/projects/releases_controller_spec.rb
index 45beccfeef5..420d818daeb 100644
--- a/spec/controllers/projects/releases_controller_spec.rb
+++ b/spec/controllers/projects/releases_controller_spec.rb
@@ -194,14 +194,6 @@ RSpec.describe Projects::ReleasesController do
end
end
- context 'when feature flag `release_show_page` is disabled' do
- before do
- stub_feature_flags(release_show_page: false)
- end
-
- it_behaves_like 'not found'
- end
-
context 'when release does not exist' do
let(:tag) { 'non-existent-tag' }
diff --git a/spec/controllers/projects/runners_controller_spec.rb b/spec/controllers/projects/runners_controller_spec.rb
index 66f20bd50c4..2443a823070 100644
--- a/spec/controllers/projects/runners_controller_spec.rb
+++ b/spec/controllers/projects/runners_controller_spec.rb
@@ -73,4 +73,45 @@ RSpec.describe Projects::RunnersController do
expect(runner.active).to eq(false)
end
end
+
+ describe '#toggle_shared_runners' do
+ let(:group) { create(:group) }
+ let(:project) { create(:project, group: group) }
+
+ it 'toggles shared_runners_enabled when the group allows shared runners' do
+ project.update!(shared_runners_enabled: true)
+
+ post :toggle_shared_runners, params: params
+
+ project.reload
+
+ expect(response).to have_gitlab_http_status(:found)
+ expect(project.shared_runners_enabled).to eq(false)
+ end
+
+ it 'toggles shared_runners_enabled when the group disallows shared runners but allows overrides' do
+ group.update!(shared_runners_enabled: false, allow_descendants_override_disabled_shared_runners: true)
+ project.update!(shared_runners_enabled: false)
+
+ post :toggle_shared_runners, params: params
+
+ project.reload
+
+ expect(response).to have_gitlab_http_status(:found)
+ expect(project.shared_runners_enabled).to eq(true)
+ end
+
+ it 'does not enable if the group disallows shared runners' do
+ group.update!(shared_runners_enabled: false, allow_descendants_override_disabled_shared_runners: false)
+ project.update!(shared_runners_enabled: false)
+
+ post :toggle_shared_runners, params: params
+
+ project.reload
+
+ expect(response).to have_gitlab_http_status(:found)
+ expect(project.shared_runners_enabled).to eq(false)
+ expect(flash[:alert]).to eq("Cannot enable shared runners because parent group does not allow it")
+ end
+ end
end
diff --git a/spec/controllers/projects/serverless/functions_controller_spec.rb b/spec/controllers/projects/serverless/functions_controller_spec.rb
index 7f558ad9231..75135839a06 100644
--- a/spec/controllers/projects/serverless/functions_controller_spec.rb
+++ b/spec/controllers/projects/serverless/functions_controller_spec.rb
@@ -206,7 +206,7 @@ RSpec.describe Projects::Serverless::FunctionsController do
context 'on Knative 0.5.0' do
before do
- prepare_knative_stubs(knative_05_service(knative_stub_options))
+ prepare_knative_stubs(knative_05_service(**knative_stub_options))
end
include_examples 'GET #show with valid data'
@@ -214,7 +214,7 @@ RSpec.describe Projects::Serverless::FunctionsController do
context 'on Knative 0.6.0' do
before do
- prepare_knative_stubs(knative_06_service(knative_stub_options))
+ prepare_knative_stubs(knative_06_service(**knative_stub_options))
end
include_examples 'GET #show with valid data'
@@ -222,7 +222,7 @@ RSpec.describe Projects::Serverless::FunctionsController do
context 'on Knative 0.7.0' do
before do
- prepare_knative_stubs(knative_07_service(knative_stub_options))
+ prepare_knative_stubs(knative_07_service(**knative_stub_options))
end
include_examples 'GET #show with valid data'
@@ -230,7 +230,7 @@ RSpec.describe Projects::Serverless::FunctionsController do
context 'on Knative 0.9.0' do
before do
- prepare_knative_stubs(knative_09_service(knative_stub_options))
+ prepare_knative_stubs(knative_09_service(**knative_stub_options))
end
include_examples 'GET #show with valid data'
@@ -275,7 +275,7 @@ RSpec.describe Projects::Serverless::FunctionsController do
context 'on Knative 0.5.0' do
before do
- prepare_knative_stubs(knative_05_service(knative_stub_options))
+ prepare_knative_stubs(knative_05_service(**knative_stub_options))
end
include_examples 'GET #index with data'
@@ -283,7 +283,7 @@ RSpec.describe Projects::Serverless::FunctionsController do
context 'on Knative 0.6.0' do
before do
- prepare_knative_stubs(knative_06_service(knative_stub_options))
+ prepare_knative_stubs(knative_06_service(**knative_stub_options))
end
include_examples 'GET #index with data'
@@ -291,7 +291,7 @@ RSpec.describe Projects::Serverless::FunctionsController do
context 'on Knative 0.7.0' do
before do
- prepare_knative_stubs(knative_07_service(knative_stub_options))
+ prepare_knative_stubs(knative_07_service(**knative_stub_options))
end
include_examples 'GET #index with data'
@@ -299,7 +299,7 @@ RSpec.describe Projects::Serverless::FunctionsController do
context 'on Knative 0.9.0' do
before do
- prepare_knative_stubs(knative_09_service(knative_stub_options))
+ prepare_knative_stubs(knative_09_service(**knative_stub_options))
end
include_examples 'GET #index with data'
diff --git a/spec/controllers/projects/settings/access_tokens_controller_spec.rb b/spec/controllers/projects/settings/access_tokens_controller_spec.rb
index 4743ab2b7c1..ff52b2a765a 100644
--- a/spec/controllers/projects/settings/access_tokens_controller_spec.rb
+++ b/spec/controllers/projects/settings/access_tokens_controller_spec.rb
@@ -5,27 +5,21 @@ require('spec_helper')
RSpec.describe Projects::Settings::AccessTokensController do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project) }
+ let_it_be(:bot_user) { create(:user, :project_bot) }
before_all do
project.add_maintainer(user)
+ project.add_maintainer(bot_user)
end
before do
sign_in(user)
end
- shared_examples 'feature unavailability' do
- context 'when flag is disabled' do
+ shared_examples 'feature unavailable' do
+ context 'user is not a maintainer' do
before do
- stub_feature_flags(resource_access_token: false)
- end
-
- it { is_expected.to have_gitlab_http_status(:not_found) }
- end
-
- context 'when environment is Gitlab.com' do
- before do
- allow(Gitlab).to receive(:com?).and_return(true)
+ project.add_developer(user)
end
it { is_expected.to have_gitlab_http_status(:not_found) }
@@ -35,156 +29,25 @@ RSpec.describe Projects::Settings::AccessTokensController do
describe '#index' do
subject { get :index, params: { namespace_id: project.namespace, project_id: project } }
- it_behaves_like 'feature unavailability'
-
- context 'when feature is available' do
- let_it_be(:bot_user) { create(:user, :project_bot) }
- let_it_be(:active_project_access_token) { create(:personal_access_token, user: bot_user) }
- let_it_be(:inactive_project_access_token) { create(:personal_access_token, :revoked, user: bot_user) }
-
- before_all do
- project.add_maintainer(bot_user)
- end
-
- before do
- enable_feature
- end
-
- it 'retrieves active project access tokens' do
- subject
-
- expect(assigns(:active_project_access_tokens)).to contain_exactly(active_project_access_token)
- end
-
- it 'retrieves inactive project access tokens' do
- subject
-
- expect(assigns(:inactive_project_access_tokens)).to contain_exactly(inactive_project_access_token)
- end
-
- it 'lists all available scopes' do
- subject
-
- expect(assigns(:scopes)).to eq(Gitlab::Auth.resource_bot_scopes)
- end
-
- it 'retrieves newly created personal access token value' do
- token_value = 'random-value'
- allow(PersonalAccessToken).to receive(:redis_getdel).with("#{user.id}:#{project.id}").and_return(token_value)
-
- subject
-
- expect(assigns(:new_project_access_token)).to eq(token_value)
- end
- end
+ it_behaves_like 'feature unavailable'
+ it_behaves_like 'project access tokens available #index'
end
- describe '#create', :clean_gitlab_redis_shared_state do
- subject { post :create, params: { namespace_id: project.namespace, project_id: project }.merge(project_access_token: access_token_params) }
-
- let_it_be(:access_token_params) { {} }
-
- it_behaves_like 'feature unavailability'
-
- context 'when feature is available' do
- let_it_be(:access_token_params) { { name: 'Nerd bot', scopes: ["api"], expires_at: 1.month.since.to_date } }
-
- before do
- enable_feature
- end
-
- def created_token
- PersonalAccessToken.order(:created_at).last
- end
-
- it 'returns success message' do
- subject
-
- expect(response.flash[:notice]).to match(/\AYour new project access token has been created./i)
- end
-
- it 'creates project access token' do
- subject
-
- expect(created_token.name).to eq(access_token_params[:name])
- expect(created_token.scopes).to eq(access_token_params[:scopes])
- expect(created_token.expires_at).to eq(access_token_params[:expires_at])
- end
-
- it 'creates project bot user' do
- subject
-
- expect(created_token.user).to be_project_bot
- end
-
- it 'stores newly created token redis store' do
- expect(PersonalAccessToken).to receive(:redis_store!)
-
- subject
- end
+ describe '#create' do
+ let(:access_token_params) { { name: 'Nerd bot', scopes: ["api"], expires_at: Date.today + 1.month } }
- it { expect { subject }.to change { User.count }.by(1) }
- it { expect { subject }.to change { PersonalAccessToken.count }.by(1) }
-
- context 'when unsuccessful' do
- before do
- allow_next_instance_of(ResourceAccessTokens::CreateService) do |service|
- allow(service).to receive(:execute).and_return ServiceResponse.error(message: 'Failed!')
- end
- end
+ subject { post :create, params: { namespace_id: project.namespace, project_id: project }.merge(project_access_token: access_token_params) }
- it { expect(subject).to render_template(:index) }
- end
- end
+ it_behaves_like 'feature unavailable'
+ it_behaves_like 'project access tokens available #create'
end
- describe '#revoke' do
- subject { put :revoke, params: { namespace_id: project.namespace, project_id: project, id: project_access_token } }
-
- let_it_be(:bot_user) { create(:user, :project_bot) }
- let_it_be(:project_access_token) { create(:personal_access_token, user: bot_user) }
-
- before_all do
- project.add_maintainer(bot_user)
- end
-
- it_behaves_like 'feature unavailability'
+ describe '#revoke', :sidekiq_inline do
+ let(:project_access_token) { create(:personal_access_token, user: bot_user) }
- context 'when feature is available' do
- before do
- enable_feature
- end
-
- it 'revokes token access' do
- subject
-
- expect(project_access_token.reload.revoked?).to be true
- end
-
- it 'removed membership of bot user' do
- subject
-
- expect(project.reload.bots).not_to include(bot_user)
- end
-
- it 'blocks project bot user' do
- subject
-
- expect(bot_user.reload.blocked?).to be true
- 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
- end
- end
+ subject { put :revoke, params: { namespace_id: project.namespace, project_id: project, id: project_access_token } }
- def enable_feature
- allow(Gitlab).to receive(:com?).and_return(false)
- stub_feature_flags(resource_access_token: true)
+ it_behaves_like 'feature unavailable'
+ it_behaves_like 'project access tokens available #revoke'
end
end
diff --git a/spec/controllers/projects/settings/ci_cd_controller_spec.rb b/spec/controllers/projects/settings/ci_cd_controller_spec.rb
index 8498ff49826..7a6e11d53d4 100644
--- a/spec/controllers/projects/settings/ci_cd_controller_spec.rb
+++ b/spec/controllers/projects/settings/ci_cd_controller_spec.rb
@@ -230,6 +230,21 @@ RSpec.describe Projects::Settings::CiCdController do
end
end
+ context 'when forward_deployment_enabled is not specified' do
+ let(:params) { { ci_cd_settings_attributes: { forward_deployment_enabled: false } } }
+
+ before do
+ project.ci_cd_settings.update!(forward_deployment_enabled: nil)
+ end
+
+ it 'sets forward deployment enabled' do
+ subject
+
+ project.reload
+ expect(project.ci_forward_deployment_enabled).to eq(false)
+ end
+ end
+
context 'when max_artifacts_size is specified' do
let(:params) { { max_artifacts_size: 10 } }
@@ -266,4 +281,21 @@ RSpec.describe Projects::Settings::CiCdController do
end
end
end
+
+ describe 'GET #runner_setup_scripts' do
+ it 'renders the setup scripts' do
+ get :runner_setup_scripts, params: { os: 'linux', arch: 'amd64', namespace_id: project.namespace, project_id: project }
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response).to have_key("install")
+ expect(json_response).to have_key("register")
+ end
+
+ it 'renders errors if they occur' do
+ get :runner_setup_scripts, params: { os: 'foo', arch: 'bar', namespace_id: project.namespace, project_id: project }
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ expect(json_response).to have_key("errors")
+ end
+ end
end
diff --git a/spec/controllers/projects/settings/operations_controller_spec.rb b/spec/controllers/projects/settings/operations_controller_spec.rb
index ca1b0d2fe15..9fc9da1265e 100644
--- a/spec/controllers/projects/settings/operations_controller_spec.rb
+++ b/spec/controllers/projects/settings/operations_controller_spec.rb
@@ -6,9 +6,12 @@ RSpec.describe Projects::Settings::OperationsController do
let_it_be(:user) { create(:user) }
let_it_be(:project, reload: true) { create(:project) }
+ before_all do
+ project.add_maintainer(user)
+ end
+
before do
sign_in(user)
- project.add_maintainer(user)
end
shared_examples 'PATCHable' do
@@ -163,10 +166,6 @@ RSpec.describe Projects::Settings::OperationsController do
context 'updating each incident management setting' do
let(:new_incident_management_settings) { {} }
- before do
- project.add_maintainer(user)
- end
-
shared_examples 'a gitlab tracking event' do |params, event_key|
it "creates a gitlab tracking event #{event_key}" do
new_incident_management_settings = params
@@ -194,10 +193,6 @@ RSpec.describe Projects::Settings::OperationsController do
end
describe 'POST #reset_pagerduty_token' do
- before do
- project.add_maintainer(user)
- end
-
context 'with existing incident management setting has active PagerDuty webhook' do
let!(:incident_management_setting) do
create(:project_incident_management_setting, project: project, pagerduty_active: true)
@@ -392,10 +387,6 @@ RSpec.describe Projects::Settings::OperationsController do
end
describe 'POST #reset_alerting_token' do
- before do
- project.add_maintainer(user)
- end
-
context 'with existing alerting setting' do
let!(:alerting_setting) do
create(:project_alerting_setting, project: project)
@@ -478,6 +469,104 @@ RSpec.describe Projects::Settings::OperationsController do
end
end
+ context 'tracing integration' do
+ describe 'GET #show' do
+ context 'with existing setting' do
+ let_it_be(:setting) do
+ create(:project_tracing_setting, project: project)
+ end
+
+ it 'loads existing setting' do
+ get :show, params: project_params(project)
+
+ expect(controller.helpers.tracing_setting).to eq(setting)
+ end
+ end
+
+ context 'without an existing setting' do
+ it 'builds a new setting' do
+ get :show, params: project_params(project)
+
+ expect(controller.helpers.tracing_setting).to be_new_record
+ end
+ end
+ end
+
+ describe 'PATCH #update' do
+ let_it_be(:external_url) { 'https://gitlab.com' }
+ let(:params) do
+ {
+ tracing_setting_attributes: {
+ external_url: external_url
+ }
+ }
+ end
+
+ it_behaves_like 'PATCHable'
+
+ describe 'gitlab tracking', :snowplow do
+ shared_examples 'event tracking' do
+ it 'tracks an event' do
+ expect_snowplow_event(
+ category: 'project:operations:tracing',
+ action: 'external_url_populated'
+ )
+ end
+ end
+
+ shared_examples 'no event tracking' do
+ it 'does not track an event' do
+ expect_no_snowplow_event
+ end
+ end
+
+ before do
+ make_request
+ end
+
+ subject(:make_request) do
+ patch :update, params: project_params(project, params), format: :json
+ end
+
+ context 'without existing setting' do
+ context 'when creating a new setting' do
+ it_behaves_like 'event tracking'
+ end
+
+ context 'with invalid external_url' do
+ let_it_be(:external_url) { nil }
+
+ it_behaves_like 'no event tracking'
+ end
+ end
+
+ context 'with existing setting' do
+ let_it_be(:existing_setting) do
+ create(:project_tracing_setting,
+ project: project,
+ external_url: external_url)
+ end
+
+ context 'when changing external_url' do
+ let_it_be(:external_url) { 'https://example.com' }
+
+ it_behaves_like 'no event tracking'
+ end
+
+ context 'with unchanged external_url' do
+ it_behaves_like 'no event tracking'
+ end
+
+ context 'with invalid external_url' do
+ let_it_be(:external_url) { nil }
+
+ it_behaves_like 'no event tracking'
+ end
+ end
+ end
+ end
+ end
+
private
def project_params(project, params = {})
diff --git a/spec/controllers/projects/snippets_controller_spec.rb b/spec/controllers/projects/snippets_controller_spec.rb
index d0e412dfdb8..6b394fab14c 100644
--- a/spec/controllers/projects/snippets_controller_spec.rb
+++ b/spec/controllers/projects/snippets_controller_spec.rb
@@ -82,215 +82,6 @@ RSpec.describe Projects::SnippetsController do
end
end
- describe 'POST #create' do
- def create_snippet(project, snippet_params = {}, additional_params = {})
- sign_in(user)
-
- project.add_developer(user)
-
- post :create, params: {
- namespace_id: project.namespace.to_param,
- project_id: project,
- project_snippet: { title: 'Title', content: 'Content', description: 'Description' }.merge(snippet_params)
- }.merge(additional_params)
-
- Snippet.last
- end
-
- it 'creates the snippet correctly' do
- snippet = create_snippet(project, visibility_level: Snippet::PRIVATE)
-
- expect(snippet.title).to eq('Title')
- expect(snippet.content).to eq('Content')
- expect(snippet.description).to eq('Description')
- end
-
- context 'when the snippet is spam' do
- before do
- allow_next_instance_of(Spam::AkismetService) do |instance|
- allow(instance).to receive(:spam?).and_return(true)
- end
- end
-
- context 'when the snippet is private' do
- it 'creates the snippet' do
- expect { create_snippet(project, visibility_level: Snippet::PRIVATE) }
- .to change { Snippet.count }.by(1)
- end
- end
-
- context 'when the snippet is public' do
- it 'rejects the snippet' do
- expect { create_snippet(project, visibility_level: Snippet::PUBLIC) }
- .not_to change { Snippet.count }
- expect(response).to render_template(:new)
- end
-
- it 'creates a spam log' do
- expect { create_snippet(project, visibility_level: Snippet::PUBLIC) }
- .to log_spam(title: 'Title', user_id: user.id, noteable_type: 'ProjectSnippet')
- end
-
- it 'renders :new with reCAPTCHA disabled' do
- stub_application_setting(recaptcha_enabled: false)
-
- create_snippet(project, visibility_level: Snippet::PUBLIC)
-
- expect(response).to render_template(:new)
- end
-
- context 'reCAPTCHA enabled' do
- before do
- stub_application_setting(recaptcha_enabled: true)
- end
-
- it 'renders :verify with reCAPTCHA enabled' do
- create_snippet(project, visibility_level: Snippet::PUBLIC)
-
- expect(response).to render_template(:verify)
- end
-
- it 'renders snippet page when reCAPTCHA verified' do
- spammy_title = 'Whatever'
-
- spam_logs = create_list(:spam_log, 2, user: user, title: spammy_title)
- create_snippet(project,
- { visibility_level: Snippet::PUBLIC },
- { spam_log_id: spam_logs.last.id,
- recaptcha_verification: true })
-
- expect(response).to redirect_to(project_snippet_path(project, Snippet.last))
- end
- end
- end
- end
- end
-
- describe 'PUT #update' do
- let(:visibility_level) { Snippet::PUBLIC }
- let(:snippet) { create :project_snippet, author: user, project: project, visibility_level: visibility_level }
-
- def update_snippet(snippet_params = {}, additional_params = {})
- sign_in(user)
-
- project.add_developer(user)
-
- put :update, params: {
- namespace_id: project.namespace.to_param,
- project_id: project,
- id: snippet,
- project_snippet: { title: 'Title', content: 'Content' }.merge(snippet_params)
- }.merge(additional_params)
-
- snippet.reload
- end
-
- context 'when the snippet is spam' do
- before do
- allow_next_instance_of(Spam::AkismetService) do |instance|
- allow(instance).to receive(:spam?).and_return(true)
- end
- end
-
- context 'when the snippet is private' do
- let(:visibility_level) { Snippet::PRIVATE }
-
- it 'updates the snippet' do
- expect { update_snippet(title: 'Foo') }
- .to change { snippet.reload.title }.to('Foo')
- end
- end
-
- context 'when the snippet is public' do
- it 'rejects the snippet' do
- expect { update_snippet(title: 'Foo') }
- .not_to change { snippet.reload.title }
- end
-
- it 'creates a spam log' do
- expect { update_snippet(title: 'Foo') }
- .to log_spam(title: 'Foo', user_id: user.id, noteable_type: 'ProjectSnippet')
- end
-
- it 'renders :edit with reCAPTCHA disabled' do
- stub_application_setting(recaptcha_enabled: false)
-
- update_snippet(title: 'Foo')
-
- expect(response).to render_template(:edit)
- end
-
- context 'reCAPTCHA enabled' do
- before do
- stub_application_setting(recaptcha_enabled: true)
- end
-
- it 'renders :verify with reCAPTCHA enabled' do
- update_snippet(title: 'Foo')
-
- expect(response).to render_template(:verify)
- end
-
- it 'renders snippet page when reCAPTCHA verified' do
- spammy_title = 'Whatever'
-
- spam_logs = create_list(:spam_log, 2, user: user, title: spammy_title)
- snippet = update_snippet({ title: spammy_title },
- { spam_log_id: spam_logs.last.id,
- recaptcha_verification: true })
-
- expect(response).to redirect_to(project_snippet_path(project, snippet))
- end
- end
- end
-
- context 'when the private snippet is made public' do
- let(:visibility_level) { Snippet::PRIVATE }
-
- it 'rejects the snippet' do
- expect { update_snippet(title: 'Foo', visibility_level: Snippet::PUBLIC) }
- .not_to change { snippet.reload.title }
- end
-
- it 'creates a spam log' do
- expect { update_snippet(title: 'Foo', visibility_level: Snippet::PUBLIC) }
- .to log_spam(title: 'Foo', user_id: user.id, noteable_type: 'ProjectSnippet')
- end
-
- it 'renders :edit with reCAPTCHA disabled' do
- stub_application_setting(recaptcha_enabled: false)
-
- update_snippet(title: 'Foo', visibility_level: Snippet::PUBLIC)
-
- expect(response).to render_template(:edit)
- end
-
- context 'reCAPTCHA enabled' do
- before do
- stub_application_setting(recaptcha_enabled: true)
- end
-
- it 'renders :verify' do
- update_snippet(title: 'Foo', visibility_level: Snippet::PUBLIC)
-
- expect(response).to render_template(:verify)
- end
-
- it 'renders snippet page' do
- spammy_title = 'Whatever'
-
- spam_logs = create_list(:spam_log, 2, user: user, title: spammy_title)
- snippet = update_snippet({ title: spammy_title, visibility_level: Snippet::PUBLIC },
- { spam_log_id: spam_logs.last.id,
- recaptcha_verification: true })
-
- expect(response).to redirect_to(project_snippet_path(project, snippet))
- end
- end
- end
- end
- end
-
describe 'POST #mark_as_spam' do
let_it_be(:snippet) { create(:project_snippet, :private, project: project, author: user) }
@@ -329,12 +120,6 @@ RSpec.describe Projects::SnippetsController do
expect(assigns(:snippet)).to eq(project_snippet)
expect(response).to have_gitlab_http_status(:ok)
end
-
- it 'renders the blob from the repository' do
- subject
-
- expect(assigns(:blob)).to eq(project_snippet.blobs.first)
- end
end
%w[show raw].each do |action|
@@ -395,6 +180,16 @@ RSpec.describe Projects::SnippetsController do
end
end
+ describe 'GET #show as JSON' do
+ it 'renders the blob from the repository' do
+ project_snippet = create(:project_snippet, :public, :repository, project: project, author: user)
+
+ get :show, params: { namespace_id: project.namespace, project_id: project, id: project_snippet.to_param }, format: :json
+
+ expect(assigns(:blob)).to eq(project_snippet.blobs.first)
+ end
+ end
+
describe "GET #show for embeddable content" do
let(:project_snippet) { create(:project_snippet, :repository, snippet_permission, project: project, author: user) }
let(:extra_params) { {} }
@@ -533,62 +328,4 @@ RSpec.describe Projects::SnippetsController do
it_behaves_like 'content disposition headers'
end
end
-
- describe 'DELETE #destroy' do
- let_it_be(:snippet) { create(:project_snippet, :private, project: project, author: user) }
-
- let(:params) do
- {
- namespace_id: project.namespace.to_param,
- project_id: project,
- id: snippet.to_param
- }
- end
-
- subject { delete :destroy, params: params }
-
- context 'when current user has ability to destroy the snippet' do
- before do
- sign_in(user)
- end
-
- it 'removes the snippet' do
- subject
-
- expect { snippet.reload }.to raise_error(ActiveRecord::RecordNotFound)
- end
-
- context 'when snippet is succesfuly destroyed' do
- it 'redirects to the project snippets page' do
- subject
-
- expect(response).to redirect_to(project_snippets_path(project))
- end
- end
-
- context 'when snippet is not destroyed' do
- before do
- allow(snippet).to receive(:destroy).and_return(false)
- controller.instance_variable_set(:@snippet, snippet)
- end
-
- it 'renders the snippet page with errors' do
- subject
-
- expect(flash[:alert]).to eq('Failed to remove snippet.')
- expect(response).to redirect_to(project_snippet_path(project, snippet))
- end
- end
- end
-
- context 'when current_user does not have ability to destroy the snippet' do
- it 'responds with status 404' do
- sign_in(other_user)
-
- subject
-
- expect(response).to have_gitlab_http_status(:not_found)
- end
- end
- end
end
diff --git a/spec/controllers/projects/static_site_editor_controller_spec.rb b/spec/controllers/projects/static_site_editor_controller_spec.rb
index 7883c7e6f81..6ea730cbf27 100644
--- a/spec/controllers/projects/static_site_editor_controller_spec.rb
+++ b/spec/controllers/projects/static_site_editor_controller_spec.rb
@@ -5,9 +5,11 @@ require 'spec_helper'
RSpec.describe Projects::StaticSiteEditorController do
let_it_be(:project) { create(:project, :public, :repository) }
let_it_be(:user) { create(:user) }
- let(:data) { instance_double(Hash) }
+ let(:data) { { key: 'value' } }
describe 'GET show' do
+ render_views
+
let(:default_params) do
{
namespace_id: project.namespace,
@@ -50,41 +52,83 @@ RSpec.describe Projects::StaticSiteEditorController do
end
end
- %w[developer maintainer].each do |role|
- context "as #{role}" do
- before_all do
- project.add_role(user, role)
+ context "as developer" do
+ before do
+ allow(Gitlab::UsageDataCounters::StaticSiteEditorCounter).to receive(:increment_views_count)
+ project.add_role(user, 'developer')
+ sign_in(user)
+ get :show, params: default_params
+ end
+
+ it 'increases the views counter' do
+ expect(Gitlab::UsageDataCounters::StaticSiteEditorCounter).to have_received(:increment_views_count)
+ end
+
+ it 'renders the edit page' do
+ expect(response).to render_template(:show)
+ end
+
+ it 'assigns ref and path variables' do
+ expect(assigns(:ref)).to eq('master')
+ expect(assigns(:path)).to eq('README.md')
+ end
+
+ context 'when combination of ref and path is incorrect' do
+ let(:default_params) { super().merge(id: 'unknown') }
+
+ it 'responds with 404 page' do
+ expect(response).to have_gitlab_http_status(:not_found)
end
+ end
+
+ context 'when invalid config file' do
+ let(:service_response) { ServiceResponse.error(message: 'invalid') }
- before do
- sign_in(user)
- get :show, params: default_params
+ it 'redirects to project page and flashes error message' do
+ expect(response).to redirect_to(project_path(project))
+ expect(response).to set_flash[:alert].to('invalid')
end
+ end
- it 'renders the edit page' do
- expect(response).to render_template(:show)
+ context 'with a service response payload containing multiple data types' do
+ let(:data) do
+ {
+ a_string: 'string',
+ an_array: [
+ {
+ foo: 'bar'
+ }
+ ],
+ an_integer: 123,
+ a_hash: {
+ a_deeper_hash: {
+ foo: 'bar'
+ }
+ },
+ a_boolean: true
+ }
end
- it 'assigns a required variables' do
- expect(assigns(:data)).to eq(data)
- expect(assigns(:ref)).to eq('master')
- expect(assigns(:path)).to eq('README.md')
+ let(:assigns_data) { assigns(:data) }
+
+ it 'leaves data values which are strings as strings' do
+ expect(assigns_data[:a_string]).to eq('string')
end
- context 'when combination of ref and path is incorrect' do
- let(:default_params) { super().merge(id: 'unknown') }
+ it 'leaves data values which are integers as integers' do
+ expect(assigns_data[:an_integer]).to eq(123)
+ end
- it 'responds with 404 page' do
- expect(response).to have_gitlab_http_status(:not_found)
- end
+ it 'serializes data values which are booleans to JSON' do
+ expect(assigns_data[:a_boolean]).to eq('true')
end
- context 'when invalid config file' do
- let(:service_response) { ServiceResponse.error(message: 'invalid') }
+ it 'serializes data values which are arrays to JSON' do
+ expect(assigns_data[:an_array]).to eq('[{"foo":"bar"}]')
+ end
- it 'returns 422' do
- expect(response).to have_gitlab_http_status(:unprocessable_entity)
- end
+ it 'serializes data values which are hashes to JSON' do
+ expect(assigns_data[:a_hash]).to eq('{"a_deeper_hash":{"foo":"bar"}}')
end
end
end
diff --git a/spec/controllers/projects/tags_controller_spec.rb b/spec/controllers/projects/tags_controller_spec.rb
index d213d003bed..57760088183 100644
--- a/spec/controllers/projects/tags_controller_spec.rb
+++ b/spec/controllers/projects/tags_controller_spec.rb
@@ -131,4 +131,25 @@ RSpec.describe Projects::TagsController do
end
end
end
+
+ describe 'DELETE #destroy' do
+ let(:tag) { project.repository.add_tag(user, 'fake-tag', 'master') }
+ let(:request) do
+ delete(:destroy, params: { id: tag.name, namespace_id: project.namespace.to_param, project_id: project })
+ end
+
+ before do
+ project.add_developer(user)
+ sign_in(user)
+ end
+
+ it 'deletes tag' do
+ request
+
+ expect(response).to be_successful
+ expect(response.body).to include("Tag was removed")
+
+ expect(project.repository.find_tag(tag.name)).not_to be_present
+ end
+ end
end
diff --git a/spec/controllers/projects/tracings_controller_spec.rb b/spec/controllers/projects/tracings_controller_spec.rb
new file mode 100644
index 00000000000..1f8a68cc861
--- /dev/null
+++ b/spec/controllers/projects/tracings_controller_spec.rb
@@ -0,0 +1,62 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Projects::TracingsController do
+ let_it_be(:user) { create(:user) }
+
+ describe 'GET show' do
+ shared_examples 'user with read access' do |visibility_level|
+ let(:project) { create(:project, visibility_level) }
+
+ %w[developer maintainer].each do |role|
+ context "with a #{visibility_level} project and #{role} role" do
+ before do
+ project.add_role(user, role)
+ end
+
+ it 'renders OK' do
+ get :show, params: { namespace_id: project.namespace, project_id: project }
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to render_template(:show)
+ end
+ end
+ end
+ end
+
+ shared_examples 'user without read access' do |visibility_level|
+ let(:project) { create(:project, visibility_level) }
+
+ %w[guest reporter].each do |role|
+ context "with a #{visibility_level} project and #{role} role" do
+ before do
+ project.add_role(user, role)
+ end
+
+ it 'returns 404' do
+ get :show, params: { namespace_id: project.namespace, project_id: project }
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+ end
+ end
+
+ before do
+ sign_in(user)
+ end
+
+ context 'with maintainer role' do
+ it_behaves_like 'user with read access', :public
+ it_behaves_like 'user with read access', :internal
+ it_behaves_like 'user with read access', :private
+ end
+
+ context 'without maintainer role' do
+ it_behaves_like 'user without read access', :public
+ it_behaves_like 'user without read access', :internal
+ it_behaves_like 'user without read access', :private
+ end
+ end
+end
diff --git a/spec/controllers/projects/web_ide_terminals_controller_spec.rb b/spec/controllers/projects/web_ide_terminals_controller_spec.rb
index 3eb3d5da351..09c471d2885 100644
--- a/spec/controllers/projects/web_ide_terminals_controller_spec.rb
+++ b/spec/controllers/projects/web_ide_terminals_controller_spec.rb
@@ -9,17 +9,20 @@ RSpec.describe Projects::WebIdeTerminalsController do
let_it_be(:developer) { create(:user) }
let_it_be(:reporter) { create(:user) }
let_it_be(:guest) { create(:user) }
- let_it_be(:project) { create(:project, :private, :repository, namespace: owner.namespace) }
+ let_it_be(:project) do
+ create(:project, :private, :repository, namespace: owner.namespace).tap do |project|
+ project.add_maintainer(maintainer)
+ project.add_developer(developer)
+ project.add_reporter(reporter)
+ project.add_guest(guest)
+ end
+ end
+
let(:pipeline) { create(:ci_pipeline, project: project, source: :webide, config_source: :webide_source, user: user) }
let(:job) { create(:ci_build, pipeline: pipeline, user: user, project: project) }
let(:user) { maintainer }
before do
- project.add_maintainer(maintainer)
- project.add_developer(developer)
- project.add_reporter(reporter)
- project.add_guest(guest)
-
sign_in(user)
end
@@ -158,11 +161,11 @@ RSpec.describe Projects::WebIdeTerminalsController do
end
context 'access rights' do
- before do
- subject
+ it_behaves_like 'terminal access rights' do
+ before do
+ subject
+ end
end
-
- it_behaves_like 'terminal access rights'
end
it 'increases the web ide terminal counter' do
diff --git a/spec/controllers/projects_controller_spec.rb b/spec/controllers/projects_controller_spec.rb
index e4374a8f104..0640f9e5724 100644
--- a/spec/controllers/projects_controller_spec.rb
+++ b/spec/controllers/projects_controller_spec.rb
@@ -213,13 +213,13 @@ RSpec.describe ProjectsController do
expect(assigns(:issuable_meta_data)).not_to be_nil
end
- it 'shows customize workflow page if wiki and issues are disabled' do
+ it 'shows activity page if wiki and issues are disabled' do
project.project_feature.update_attribute(:wiki_access_level, ProjectFeature::DISABLED)
project.project_feature.update_attribute(:issues_access_level, ProjectFeature::DISABLED)
get :show, params: { namespace_id: project.namespace, id: project }
- expect(response).to render_template("projects/_customize_workflow")
+ expect(response).to render_template("projects/_activity")
end
it 'shows activity if enabled by user' do
diff --git a/spec/controllers/registrations/experience_levels_controller_spec.rb b/spec/controllers/registrations/experience_levels_controller_spec.rb
index ee1acf3d93d..4be67f29107 100644
--- a/spec/controllers/registrations/experience_levels_controller_spec.rb
+++ b/spec/controllers/registrations/experience_levels_controller_spec.rb
@@ -85,16 +85,49 @@ RSpec.describe Registrations::ExperienceLevelsController do
end
end
- context 'when a namespace_path is sent' do
- it { is_expected.to have_gitlab_http_status(:redirect) }
- it { is_expected.to redirect_to(group_path(namespace)) }
- end
+ describe 'redirection' do
+ let(:project) { build(:project, namespace: namespace, creator: user, path: 'project-path') }
+ let(:issues_board) { build(:board, id: 123, project: project) }
+
+ before do
+ stub_experiment_for_user(
+ onboarding_issues: true,
+ default_to_issues_board: default_to_issues_board_xp?
+ )
+ allow_next_instance_of(LearnGitlab) do |learn_gitlab|
+ allow(learn_gitlab).to receive(:available?).and_return(learn_gitlab_available?)
+ allow(learn_gitlab).to receive(:project).and_return(project)
+ allow(learn_gitlab).to receive(:board).and_return(issues_board)
+ end
+ end
+
+ context 'when namespace_path param is missing' do
+ let(:params) { super().merge(namespace_path: nil) }
+
+ where(
+ default_to_issues_board_xp?: [true, false],
+ learn_gitlab_available?: [true, false]
+ )
- context 'when no namespace_path is sent' do
- let(:params) { super().merge(namespace_path: nil) }
+ with_them do
+ it { is_expected.to redirect_to('/') }
+ end
+ end
- it { is_expected.to have_gitlab_http_status(:redirect) }
- it { is_expected.to redirect_to(root_path) }
+ context 'when we have a namespace_path param' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:default_to_issues_board_xp?, :learn_gitlab_available?, :path) do
+ true | true | '/group-path/project-path/-/boards/123'
+ true | false | '/group-path'
+ false | true | '/group-path'
+ false | false | '/group-path'
+ end
+
+ with_them do
+ it { is_expected.to redirect_to(path) }
+ end
+ end
end
describe 'applying the chosen level' do
diff --git a/spec/controllers/registrations_controller_spec.rb b/spec/controllers/registrations_controller_spec.rb
index 60957dc72e6..501d8d4a78d 100644
--- a/spec/controllers/registrations_controller_spec.rb
+++ b/spec/controllers/registrations_controller_spec.rb
@@ -37,65 +37,123 @@ RSpec.describe RegistrationsController do
expect(response).to redirect_to(new_user_session_path(anchor: 'register-pane'))
end
end
+ end
- context 'with sign up flow and terms_opt_in experiment being enabled' do
- before do
- stub_experiment(signup_flow: true, terms_opt_in: true)
- end
+ describe '#create' do
+ let(:base_user_params) { { first_name: 'first', last_name: 'last', username: 'new_username', email: 'new@user.com', password: 'Any_password' } }
+ let(:user_params) { { user: base_user_params } }
+
+ subject { post(:create, params: user_params) }
- context 'when user is not part of the experiment' do
+ context '`blocked_pending_approval` state' do
+ context 'when the feature is enabled' do
before do
- stub_experiment_for_user(signup_flow: true, terms_opt_in: false)
+ stub_feature_flags(admin_approval_for_new_user_signups: true)
end
- it 'tracks event with right parameters' do
- expect(Gitlab::Tracking).to receive(:event).with(
- 'Growth::Acquisition::Experiment::TermsOptIn',
- 'start',
- label: anything,
- property: 'control_group'
- )
+ context 'when the `require_admin_approval_after_user_signup` setting is turned on' do
+ before do
+ stub_application_setting(require_admin_approval_after_user_signup: true)
+ end
- subject
+ it 'signs up the user in `blocked_pending_approval` state' do
+ subject
+ created_user = User.find_by(email: 'new@user.com')
+
+ expect(created_user).to be_present
+ expect(created_user.blocked_pending_approval?).to eq(true)
+ end
+
+ it 'does not log in the user after sign up' do
+ subject
+
+ expect(controller.current_user).to be_nil
+ end
+
+ it 'shows flash message after signing up' do
+ subject
+
+ expect(response).to redirect_to(new_user_session_path(anchor: 'login-pane'))
+ expect(flash[:notice])
+ .to eq('You have signed up successfully. However, we could not sign you in because your account is awaiting approval from your GitLab administrator.')
+ end
+
+ context 'email confirmation' do
+ context 'when `send_user_confirmation_email` is true' do
+ before do
+ stub_application_setting(send_user_confirmation_email: true)
+ end
+
+ it 'does not send a confirmation email' do
+ expect { subject }
+ .not_to have_enqueued_mail(DeviseMailer, :confirmation_instructions)
+ end
+ end
+ end
+ end
+
+ context 'when the `require_admin_approval_after_user_signup` setting is turned off' do
+ before do
+ stub_application_setting(require_admin_approval_after_user_signup: false)
+ end
+
+ it 'signs up the user in `active` state' do
+ subject
+ created_user = User.find_by(email: 'new@user.com')
+
+ expect(created_user).to be_present
+ expect(created_user.active?).to eq(true)
+ end
+
+ it 'does not show any flash message after signing up' do
+ subject
+
+ expect(flash[:notice]).to be_nil
+ end
+
+ context 'email confirmation' do
+ context 'when `send_user_confirmation_email` is true' do
+ before do
+ stub_application_setting(send_user_confirmation_email: true)
+ end
+
+ it 'sends a confirmation email' do
+ expect { subject }
+ .to have_enqueued_mail(DeviseMailer, :confirmation_instructions)
+ end
+ end
+ end
end
end
- context 'when user is part of the experiment' do
+ context 'when the feature is disabled' do
before do
- stub_experiment_for_user(signup_flow: true, terms_opt_in: true)
+ stub_feature_flags(admin_approval_for_new_user_signups: false)
end
- it 'tracks event with right parameters' do
- expect(Gitlab::Tracking).to receive(:event).with(
- 'Growth::Acquisition::Experiment::TermsOptIn',
- 'start',
- label: anything,
- property: 'experimental_group'
- )
+ context 'when the `require_admin_approval_after_user_signup` setting is turned on' do
+ before do
+ stub_application_setting(require_admin_approval_after_user_signup: true)
+ end
- subject
+ it 'signs up the user in `active` state' do
+ subject
+
+ created_user = User.find_by(email: 'new@user.com')
+ expect(created_user).to be_present
+ expect(created_user.active?).to eq(true)
+ end
end
end
end
- end
-
- describe '#create' do
- let(:base_user_params) { { name: 'new_user', username: 'new_username', email: 'new@user.com', password: 'Any_password' } }
- let(:user_params) { { user: base_user_params } }
context 'email confirmation' do
- around do |example|
- perform_enqueued_jobs do
- example.run
- end
- end
-
context 'when send_user_confirmation_email is false' do
it 'signs the user in' do
stub_application_setting(send_user_confirmation_email: false)
- expect { post(:create, params: user_params) }.not_to change { ActionMailer::Base.deliveries.size }
- expect(subject.current_user).not_to be_nil
+ expect { subject }.not_to have_enqueued_mail(DeviseMailer, :confirmation_instructions)
+ expect(controller.current_user).not_to be_nil
end
end
@@ -111,10 +169,8 @@ RSpec.describe RegistrationsController do
end
it 'does not authenticate the user and sends a confirmation email' do
- post(:create, params: user_params)
-
- expect(ActionMailer::Base.deliveries.last.to.first).to eq(user_params[:user][:email])
- expect(subject.current_user).to be_nil
+ expect { subject }.to have_enqueued_mail(DeviseMailer, :confirmation_instructions)
+ expect(controller.current_user).to be_nil
end
end
@@ -125,9 +181,8 @@ RSpec.describe RegistrationsController do
end
it 'authenticates the user and sends a confirmation email' do
- post(:create, params: user_params)
-
- expect(ActionMailer::Base.deliveries.last.to.first).to eq(user_params[:user][:email])
+ expect { subject }.to have_enqueued_mail(DeviseMailer, :confirmation_instructions)
+ expect(controller.current_user).to be_present
expect(response).to redirect_to(users_sign_up_welcome_path)
end
end
@@ -137,7 +192,7 @@ RSpec.describe RegistrationsController do
it 'redirects to sign_in' do
stub_application_setting(signup_enabled: false)
- expect { post(:create, params: user_params) }.not_to change(User, :count)
+ expect { subject }.not_to change(User, :count)
expect(response).to redirect_to(new_user_session_path)
end
end
@@ -158,14 +213,14 @@ RSpec.describe RegistrationsController do
it 'displays an error when the reCAPTCHA is not solved' do
allow_any_instance_of(described_class).to receive(:verify_recaptcha).and_return(false)
- post(:create, params: user_params)
+ subject
expect(response).to render_template(:new)
expect(flash[:alert]).to eq(_('There was an error with the reCAPTCHA. Please solve the reCAPTCHA again.'))
end
it 'redirects to the welcome page when the reCAPTCHA is solved' do
- post(:create, params: user_params)
+ subject
expect(response).to redirect_to(users_sign_up_welcome_path)
end
@@ -258,102 +313,26 @@ RSpec.describe RegistrationsController do
end
end
- context 'when terms are enforced' do
- before do
- enforce_terms
- end
-
- it 'redirects back with a notice when the checkbox was not checked' do
- post :create, params: user_params
-
- expect(flash[:alert]).to eq(_('You must accept our Terms of Service and privacy policy in order to register an account'))
- end
-
- it 'creates the user with agreement when terms are accepted' do
- post :create, params: user_params.merge(terms_opt_in: '1')
-
- expect(subject.current_user).to be_present
- expect(subject.current_user.terms_accepted?).to be(true)
- end
-
- context 'when experiment terms_opt_in is enabled' do
+ context 'terms of service' do
+ context 'when terms are enforced' do
before do
- stub_experiment(terms_opt_in: true)
- end
-
- context 'when user is part of the experiment' do
- before do
- stub_experiment_for_user(terms_opt_in: true)
- end
-
- it 'creates the user with accepted terms' do
- post :create, params: user_params
-
- expect(subject.current_user).to be_present
- expect(subject.current_user.terms_accepted?).to be(true)
- end
+ enforce_terms
end
- context 'when user is not part of the experiment' do
- before do
- stub_experiment_for_user(terms_opt_in: false)
- end
-
- it 'creates the user without accepted terms' do
- post :create, params: user_params
+ it 'creates the user with accepted terms' do
+ subject
- expect(flash[:alert]).to eq(_('You must accept our Terms of Service and privacy policy in order to register an account'))
- end
+ expect(controller.current_user).to be_present
+ expect(controller.current_user.terms_accepted?).to be(true)
end
end
- end
-
- describe 'tracking data' do
- context 'with sign up flow and terms_opt_in experiment being enabled' do
- subject { post :create, params: user_params }
-
- before do
- stub_experiment(signup_flow: true, terms_opt_in: true)
- end
-
- it 'records user for the terms_opt_in experiment' do
- expect(controller).to receive(:record_experiment_user).with(:terms_opt_in)
+ context 'when terms are not enforced' do
+ it 'creates the user without accepted terms' do
subject
- end
- context 'when user is not part of the experiment' do
- before do
- stub_experiment_for_user(signup_flow: true, terms_opt_in: false)
- end
-
- it 'tracks event with right parameters' do
- expect(Gitlab::Tracking).to receive(:event).with(
- 'Growth::Acquisition::Experiment::TermsOptIn',
- 'end',
- label: anything,
- property: 'control_group'
- )
-
- subject
- end
- end
-
- context 'when user is part of the experiment' do
- before do
- stub_experiment_for_user(signup_flow: true, terms_opt_in: true)
- end
-
- it 'tracks event with right parameters' do
- expect(Gitlab::Tracking).to receive(:event).with(
- 'Growth::Acquisition::Experiment::TermsOptIn',
- 'end',
- label: anything,
- property: 'experimental_group'
- )
-
- subject
- end
+ expect(controller.current_user).to be_present
+ expect(controller.current_user.terms_accepted?).to be(false)
end
end
end
@@ -361,30 +340,21 @@ RSpec.describe RegistrationsController do
it "logs a 'User Created' message" do
expect(Gitlab::AppLogger).to receive(:info).with(/\AUser Created: username=new_username email=new@user.com.+\z/).and_call_original
- post(:create, params: user_params)
+ subject
end
it 'handles when params are new_user' do
post(:create, params: { new_user: base_user_params })
- expect(subject.current_user).not_to be_nil
+ expect(controller.current_user).not_to be_nil
end
- context 'with the experimental signup flow enabled and the user is part of the experimental group' do
- before do
- stub_experiment(signup_flow: true)
- stub_experiment_for_user(signup_flow: true)
- end
-
- let(:base_user_params) { { first_name: 'First', last_name: 'Last', username: 'new_username', email: 'new@user.com', password: 'Any_password' } }
-
- it 'sets name from first and last name' do
- post :create, params: { new_user: base_user_params }
+ it 'sets name from first and last name' do
+ post :create, params: { new_user: base_user_params }
- 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]}")
- end
+ 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]}")
end
end
@@ -507,10 +477,16 @@ RSpec.describe RegistrationsController do
patch :update_registration, params: { user: { role: 'software_developer', setup_for_company: 'false' } }
end
- before do
- sign_in(create(:user))
+ context 'without a signed in user' do
+ it { is_expected.to redirect_to new_user_registration_path }
end
- it { is_expected.to redirect_to(dashboard_projects_path)}
+ context 'with a signed in user' do
+ before do
+ sign_in(create(:user))
+ end
+
+ it { is_expected.to redirect_to(dashboard_projects_path)}
+ end
end
end
diff --git a/spec/controllers/runner_setup_controller_spec.rb b/spec/controllers/runner_setup_controller_spec.rb
new file mode 100644
index 00000000000..0b237500907
--- /dev/null
+++ b/spec/controllers/runner_setup_controller_spec.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe RunnerSetupController do
+ let(:user) { create(:user) }
+
+ before do
+ sign_in(user)
+ end
+
+ describe 'GET #platforms' do
+ it 'renders the platforms' do
+ get :platforms
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response).to have_key("windows")
+ expect(json_response).to have_key("kubernetes")
+ end
+ end
+end
diff --git a/spec/controllers/search_controller_spec.rb b/spec/controllers/search_controller_spec.rb
index f244392bbad..a0cb696828d 100644
--- a/spec/controllers/search_controller_spec.rb
+++ b/spec/controllers/search_controller_spec.rb
@@ -183,7 +183,7 @@ RSpec.describe SearchController do
end
it_behaves_like 'tracking unique hll events', :search_track_unique_users do
- subject { get :show, params: { scope: 'projects', search: 'term' }, format: format }
+ subject(:request) { get :show, params: { scope: 'projects', search: 'term' } }
let(:target_id) { 'i_search_total' }
let(:expected_type) { instance_of(String) }
diff --git a/spec/controllers/sessions_controller_spec.rb b/spec/controllers/sessions_controller_spec.rb
index 688539f2a03..75bcc32e6f3 100644
--- a/spec/controllers/sessions_controller_spec.rb
+++ b/spec/controllers/sessions_controller_spec.rb
@@ -78,6 +78,9 @@ RSpec.describe SessionsController do
end
context 'when using standard authentications' do
+ let(:user) { create(:user) }
+ let(:post_action) { post(:create, params: { user: { login: user.username, password: user.password } }) }
+
context 'invalid password' do
it 'does not authenticate user' do
post(:create, params: { user: { login: 'invalid', password: 'invalid' } })
@@ -87,6 +90,36 @@ RSpec.describe SessionsController do
end
end
+ context 'a blocked user' do
+ it 'does not authenticate the user' do
+ user.block!
+ post_action
+
+ expect(@request.env['warden']).not_to be_authenticated
+ expect(flash[:alert]).to include('Your account has been blocked')
+ end
+ end
+
+ context 'a `blocked pending approval` user' do
+ it 'does not authenticate the user' do
+ user.block_pending_approval!
+ post_action
+
+ expect(@request.env['warden']).not_to be_authenticated
+ expect(flash[:alert]).to include('Your account is pending approval from your GitLab administrator and hence blocked')
+ end
+ end
+
+ context 'an internal user' do
+ it 'does not authenticate the user' do
+ user.ghost!
+ post_action
+
+ expect(@request.env['warden']).not_to be_authenticated
+ expect(flash[:alert]).to include('Your account does not have the required permission to login')
+ end
+ end
+
context 'when using valid password', :clean_gitlab_redis_shared_state do
let(:user) { create(:user) }
let(:user_params) { { login: user.username, password: user.password } }
diff --git a/spec/controllers/snippets_controller_spec.rb b/spec/controllers/snippets_controller_spec.rb
index 6517922d92a..1ccba7f9114 100644
--- a/spec/controllers/snippets_controller_spec.rb
+++ b/spec/controllers/snippets_controller_spec.rb
@@ -4,6 +4,8 @@ require 'spec_helper'
RSpec.describe SnippetsController do
let_it_be(:user) { create(:user) }
+ let_it_be(:other_user) { create(:user) }
+ let_it_be(:public_snippet) { create(:personal_snippet, :public, :repository, author: user) }
describe 'GET #index' do
let(:base_params) { { username: user.username } }
@@ -12,10 +14,6 @@ RSpec.describe SnippetsController do
it_behaves_like 'paginated collection' do
let(:collection) { Snippet.all }
let(:params) { { username: user.username } }
-
- before do
- create(:personal_snippet, :public, author: user)
- end
end
it 'renders snippets of a user when username is present' do
@@ -86,12 +84,6 @@ RSpec.describe SnippetsController do
expect(assigns(:snippet)).to eq(personal_snippet)
expect(response).to have_gitlab_http_status(:ok)
end
-
- it 'renders the blob from the repository' do
- subject
-
- expect(assigns(:blob)).to eq(personal_snippet.blobs.first)
- end
end
context 'when the personal snippet is private' do
@@ -103,8 +95,7 @@ RSpec.describe SnippetsController do
end
context 'when signed in user is not the author' do
- let(:other_author) { create(:author) }
- let(:other_personal_snippet) { create(:personal_snippet, :private, author: other_author) }
+ let(:other_personal_snippet) { create(:personal_snippet, :private, author: other_user) }
it 'responds with status 404' do
get :show, params: { id: other_personal_snippet.to_param }
@@ -164,7 +155,7 @@ RSpec.describe SnippetsController do
end
context 'when the personal snippet is public' do
- let_it_be(:personal_snippet) { create(:personal_snippet, :public, :repository, author: user) }
+ let(:personal_snippet) { public_snippet }
context 'when signed in' do
before do
@@ -172,22 +163,22 @@ RSpec.describe SnippetsController do
end
it_behaves_like 'successful response' do
- subject { get :show, params: { id: personal_snippet.to_param } }
+ subject { get :show, params: { id: public_snippet.to_param } }
end
it 'responds with status 200 when embeddable content is requested' do
- get :show, params: { id: personal_snippet.to_param }, format: :js
+ get :show, params: { id: public_snippet.to_param }, format: :js
- expect(assigns(:snippet)).to eq(personal_snippet)
+ expect(assigns(:snippet)).to eq(public_snippet)
expect(response).to have_gitlab_http_status(:ok)
end
end
context 'when not signed in' do
it 'renders the snippet' do
- get :show, params: { id: personal_snippet.to_param }
+ get :show, params: { id: public_snippet.to_param }
- expect(assigns(:snippet)).to eq(personal_snippet)
+ expect(assigns(:snippet)).to eq(public_snippet)
expect(response).to have_gitlab_http_status(:ok)
end
end
@@ -200,7 +191,7 @@ RSpec.describe SnippetsController do
end
it 'responds with status 404' do
- get :show, params: { id: 'doesntexist' }
+ get :show, params: { id: non_existing_record_id }
expect(response).to have_gitlab_http_status(:not_found)
end
@@ -208,260 +199,43 @@ RSpec.describe SnippetsController do
context 'when not signed in' do
it 'responds with status 404' do
- get :show, params: { id: 'doesntexist' }
+ get :show, params: { id: non_existing_record_id }
expect(response).to redirect_to(new_user_session_path)
end
end
end
- end
-
- describe 'POST #create' do
- def create_snippet(snippet_params = {}, additional_params = {})
- sign_in(user)
-
- post :create, params: {
- personal_snippet: { title: 'Title', content: 'Content', description: 'Description' }.merge(snippet_params)
- }.merge(additional_params)
-
- Snippet.last
- end
-
- it 'creates the snippet correctly' do
- snippet = create_snippet(visibility_level: Snippet::PRIVATE)
-
- expect(snippet.title).to eq('Title')
- expect(snippet.content).to eq('Content')
- expect(snippet.description).to eq('Description')
- end
-
- context 'when user is not allowed to create a personal snippet' do
- let(:user) { create(:user, :external) }
-
- it 'responds with status 404' do
- aggregate_failures do
- expect do
- create_snippet(visibility_level: Snippet::PUBLIC)
- end.not_to change { Snippet.count }
-
- expect(response).to have_gitlab_http_status(:not_found)
- end
- end
- end
-
- context 'when the controller receives the files param' do
- let(:files) { %w(foo bar) }
-
- it 'passes the files param to the snippet create service' do
- expect(Snippets::CreateService).to receive(:new).with(nil, user, hash_including(files: files)).and_call_original
-
- create_snippet({ title: nil }, { files: files })
- end
- end
-
- context 'when the snippet is spam' do
- before do
- allow_next_instance_of(Spam::AkismetService) do |instance|
- allow(instance).to receive(:spam?).and_return(true)
- end
- end
-
- context 'when the snippet is private' do
- it 'creates the snippet' do
- expect { create_snippet(visibility_level: Snippet::PRIVATE) }
- .to change { Snippet.count }.by(1)
- end
- end
-
- context 'when the snippet is public' do
- it 'rejects the snippet' do
- expect { create_snippet(visibility_level: Snippet::PUBLIC) }
- .not_to change { Snippet.count }
- end
-
- it 'creates a spam log' do
- expect { create_snippet(visibility_level: Snippet::PUBLIC) }
- .to log_spam(title: 'Title', user: user, noteable_type: 'PersonalSnippet')
- end
-
- it 'renders :new with reCAPTCHA disabled' do
- stub_application_setting(recaptcha_enabled: false)
-
- create_snippet(visibility_level: Snippet::PUBLIC)
-
- expect(response).to render_template(:new)
- end
-
- context 'reCAPTCHA enabled' do
- before do
- stub_application_setting(recaptcha_enabled: true)
- end
-
- it 'renders :verify' do
- create_snippet(visibility_level: Snippet::PUBLIC)
-
- expect(response).to render_template(:verify)
- end
-
- it 'renders snippet page' do
- spammy_title = 'Whatever'
-
- spam_logs = create_list(:spam_log, 2, user: user, title: spammy_title)
- snippet = create_snippet({ title: spammy_title },
- { spam_log_id: spam_logs.last.id,
- recaptcha_verification: true })
-
- expect(response).to redirect_to(snippet_path(snippet))
- end
- end
- end
- end
- end
-
- describe 'PUT #update' do
- let(:project) { create :project }
- let(:visibility_level) { Snippet::PUBLIC }
- let(:snippet) { create :personal_snippet, author: user, project: project, visibility_level: visibility_level }
-
- def update_snippet(snippet_params = {}, additional_params = {})
- sign_in(user)
-
- put :update, params: {
- id: snippet.id,
- personal_snippet: { title: 'Title', content: 'Content' }.merge(snippet_params)
- }.merge(additional_params)
-
- snippet.reload
- end
-
- context 'when the snippet is spam' do
- before do
- allow_next_instance_of(Spam::AkismetService) do |instance|
- allow(instance).to receive(:spam?).and_return(true)
- end
- end
-
- context 'when the snippet is private' do
- let(:visibility_level) { Snippet::PRIVATE }
-
- it 'updates the snippet' do
- expect { update_snippet(title: 'Foo') }
- .to change { snippet.reload.title }.to('Foo')
- end
- end
-
- context 'when a private snippet is made public' do
- let(:visibility_level) { Snippet::PRIVATE }
-
- it 'rejects the snippet' do
- expect { update_snippet(title: 'Foo', visibility_level: Snippet::PUBLIC) }
- .not_to change { snippet.reload.title }
- end
-
- it 'creates a spam log' do
- expect { update_snippet(title: 'Foo', visibility_level: Snippet::PUBLIC) }
- .to log_spam(title: 'Foo', user: user, noteable_type: 'PersonalSnippet')
- end
-
- it 'renders :edit with reCAPTCHA disabled' do
- stub_application_setting(recaptcha_enabled: false)
-
- update_snippet(title: 'Foo', visibility_level: Snippet::PUBLIC)
-
- expect(response).to render_template(:edit)
- end
-
- context 'reCAPTCHA enabled' do
- before do
- stub_application_setting(recaptcha_enabled: true)
- end
-
- it 'renders :verify' do
- update_snippet(title: 'Foo', visibility_level: Snippet::PUBLIC)
-
- expect(response).to render_template(:verify)
- end
-
- it 'renders snippet page when reCAPTCHA verified' do
- spammy_title = 'Whatever'
-
- spam_logs = create_list(:spam_log, 2, user: user, title: spammy_title)
- snippet = update_snippet({ title: spammy_title, visibility_level: Snippet::PUBLIC },
- { spam_log_id: spam_logs.last.id,
- recaptcha_verification: true })
-
- expect(response).to redirect_to(snippet_path(snippet))
- end
- end
- end
-
- context 'when the snippet is public' do
- it 'rejects the snippet' do
- expect { update_snippet(title: 'Foo') }
- .not_to change { snippet.reload.title }
- end
-
- it 'creates a spam log' do
- expect {update_snippet(title: 'Foo') }
- .to log_spam(title: 'Foo', user: user, noteable_type: 'PersonalSnippet')
- end
-
- it 'renders :edit with reCAPTCHA disabled' do
- stub_application_setting(recaptcha_enabled: false)
-
- update_snippet(title: 'Foo')
-
- expect(response).to render_template(:edit)
- end
-
- context 'recaptcha enabled' do
- before do
- stub_application_setting(recaptcha_enabled: true)
- end
-
- it 'renders :verify' do
- update_snippet(title: 'Foo')
-
- expect(response).to render_template(:verify)
- end
-
- it 'renders snippet page when reCAPTCHA verified' do
- spammy_title = 'Whatever'
- spam_logs = create_list(:spam_log, 2, user: user, title: spammy_title)
- snippet = update_snippet({ title: spammy_title },
- { spam_log_id: spam_logs.last.id,
- recaptcha_verification: true })
+ context 'when requesting JSON' do
+ it 'renders the blob from the repository' do
+ get :show, params: { id: public_snippet.to_param }, format: :json
- expect(response).to redirect_to(snippet_path(snippet))
- end
- end
+ expect(assigns(:blob)).to eq(public_snippet.blobs.first)
end
end
end
describe 'POST #mark_as_spam' do
- let(:snippet) { create(:personal_snippet, :public, author: user) }
-
before do
allow_next_instance_of(Spam::AkismetService) do |instance|
allow(instance).to receive_messages(submit_spam: true)
end
+
stub_application_setting(akismet_enabled: true)
end
def mark_as_spam
admin = create(:admin)
- create(:user_agent_detail, subject: snippet)
+ create(:user_agent_detail, subject: public_snippet)
sign_in(admin)
- post :mark_as_spam, params: { id: snippet.id }
+ post :mark_as_spam, params: { id: public_snippet.id }
end
it 'updates the snippet' do
mark_as_spam
- expect(snippet.reload).not_to be_submittable_as_spam
+ expect(public_snippet.reload).not_to be_submittable_as_spam
end
end
@@ -489,9 +263,7 @@ RSpec.describe SnippetsController do
shared_examples 'CRLF line ending' do
let(:content) { "first line\r\nsecond line\r\nthird line" }
let(:formatted_content) { content.gsub(/\r\n/, "\n") }
- let(:snippet) do
- create(:personal_snippet, :public, :repository, author: user, content: content)
- end
+ let(:snippet) { public_snippet }
before do
allow_next_instance_of(Blob) do |instance|
@@ -560,8 +332,7 @@ RSpec.describe SnippetsController do
end
context 'when signed in user is not the author' do
- let(:other_author) { create(:author) }
- let(:other_personal_snippet) { create(:personal_snippet, :private, author: other_author) }
+ let(:other_personal_snippet) { create(:personal_snippet, :private, author: other_user) }
it 'responds with status 404' do
get :raw, params: { id: other_personal_snippet.to_param }
@@ -605,7 +376,7 @@ RSpec.describe SnippetsController do
end
context 'when the personal snippet is public' do
- let_it_be(:snippet) { create(:personal_snippet, :public, :repository, author: user) }
+ let(:snippet) { public_snippet }
context 'when signed in' do
before do
@@ -632,7 +403,7 @@ RSpec.describe SnippetsController do
end
it 'responds with status 404' do
- get :raw, params: { id: 'doesntexist' }
+ get :raw, params: { id: non_existing_record_id }
expect(response).to have_gitlab_http_status(:not_found)
end
@@ -640,7 +411,7 @@ RSpec.describe SnippetsController do
context 'when not signed in' do
it 'redirects to the sign in path' do
- get :raw, params: { id: 'doesntexist' }
+ get :raw, params: { id: non_existing_record_id }
expect(response).to redirect_to(new_user_session_path)
end
@@ -649,11 +420,10 @@ RSpec.describe SnippetsController do
end
context 'award emoji on snippets' do
- let(:personal_snippet) { create(:personal_snippet, :public, author: user) }
- let(:another_user) { create(:user) }
+ let(:personal_snippet) { public_snippet }
before do
- sign_in(another_user)
+ sign_in(other_user)
end
describe 'POST #toggle_award_emoji' do
@@ -678,66 +448,12 @@ RSpec.describe SnippetsController do
end
describe 'POST #preview_markdown' do
- let(:snippet) { create(:personal_snippet, :public) }
-
it 'renders json in a correct format' do
sign_in(user)
- post :preview_markdown, params: { id: snippet, text: '*Markdown* text' }
+ post :preview_markdown, params: { id: public_snippet, text: '*Markdown* text' }
expect(json_response.keys).to match_array(%w(body references))
end
end
-
- describe 'DELETE #destroy' do
- let!(:snippet) { create :personal_snippet, author: user }
-
- context 'when current user has ability to destroy the snippet' do
- before do
- sign_in(user)
- end
-
- it 'removes the snippet' do
- delete :destroy, params: { id: snippet.to_param }
-
- expect { snippet.reload }.to raise_error(ActiveRecord::RecordNotFound)
- end
-
- context 'when snippet is succesfuly destroyed' do
- it 'redirects to the project snippets page' do
- delete :destroy, params: { id: snippet.to_param }
-
- expect(response).to redirect_to(dashboard_snippets_path)
- end
- end
-
- context 'when snippet is not destroyed' do
- before do
- allow(snippet).to receive(:destroy).and_return(false)
- controller.instance_variable_set(:@snippet, snippet)
- end
-
- it 'renders the snippet page with errors' do
- delete :destroy, params: { id: snippet.to_param }
-
- expect(flash[:alert]).to eq('Failed to remove snippet.')
- expect(response).to redirect_to(snippet_path(snippet))
- end
- end
- end
-
- context 'when current_user does not have ability to destroy the snippet' do
- let(:another_user) { create(:user) }
-
- before do
- sign_in(another_user)
- end
-
- it 'responds with status 404' do
- delete :destroy, params: { id: snippet.to_param }
-
- expect(response).to have_gitlab_http_status(:not_found)
- end
- end
- end
end
diff --git a/spec/db/schema_spec.rb b/spec/db/schema_spec.rb
index 69cd08d82e1..06fafbddced 100644
--- a/spec/db/schema_spec.rb
+++ b/spec/db/schema_spec.rb
@@ -11,7 +11,7 @@ RSpec.describe 'Database schema' do
let(:columns_name_with_jsonb) { retrieve_columns_name_with_jsonb }
# List of columns historically missing a FK, don't add more columns
- # See: https://docs.gitlab.com/ce/development/foreign_keys.html#naming-foreign-keys
+ # See: https://docs.gitlab.com/ee/development/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],
@@ -31,6 +31,7 @@ RSpec.describe 'Database schema' do
ci_trigger_requests: %w[commit_id],
cluster_providers_aws: %w[security_group_id vpc_id access_key_id],
cluster_providers_gcp: %w[gcp_project_id operation_id],
+ compliance_management_frameworks: %w[group_id],
commit_user_mentions: %w[commit_id],
deploy_keys_projects: %w[deploy_key_id],
deployments: %w[deployable_id environment_id user_id],
@@ -237,6 +238,42 @@ RSpec.describe 'Database schema' do
end
end
+ context 'primary keys' do
+ let(:exceptions) do
+ %i(
+ analytics_language_trend_repository_languages
+ approval_project_rules_protected_branches
+ ci_build_trace_sections
+ deployment_merge_requests
+ elasticsearch_indexed_namespaces
+ elasticsearch_indexed_projects
+ issue_assignees
+ issues_prometheus_alert_events
+ issues_self_managed_prometheus_alert_events
+ merge_request_context_commit_diff_files
+ merge_request_diff_commits
+ merge_request_diff_files
+ milestone_releases
+ project_authorizations
+ project_pages_metadata
+ push_event_payloads
+ repository_languages
+ user_interacted_projects
+ users_security_dashboard_projects
+ )
+ end
+
+ it 'expects every table to have a primary key defined' do
+ connection = ActiveRecord::Base.connection
+
+ problematic_tables = connection.tables.select do |table|
+ !connection.primary_key(table).present?
+ end.map(&:to_sym)
+
+ expect(problematic_tables - exceptions).to be_empty
+ end
+ end
+
private
def retrieve_columns_name_with_jsonb
diff --git a/spec/factories/alert_management/alerts.rb b/spec/factories/alert_management/alerts.rb
index d931947fff1..e36e4c38013 100644
--- a/spec/factories/alert_management/alerts.rb
+++ b/spec/factories/alert_management/alerts.rb
@@ -56,22 +56,22 @@ FactoryBot.define do
end
trait :triggered do
- status { AlertManagement::Alert::STATUSES[:triggered] }
+ status { AlertManagement::Alert.status_value(:triggered) }
without_ended_at
end
trait :acknowledged do
- status { AlertManagement::Alert::STATUSES[:acknowledged] }
+ status { AlertManagement::Alert.status_value(:acknowledged) }
without_ended_at
end
trait :resolved do
- status { AlertManagement::Alert::STATUSES[:resolved] }
+ status { AlertManagement::Alert.status_value(:resolved) }
with_ended_at
end
trait :ignored do
- status { AlertManagement::Alert::STATUSES[:ignored] }
+ status { AlertManagement::Alert.status_value(:ignored) }
without_ended_at
end
@@ -100,7 +100,7 @@ FactoryBot.define do
end
trait :prometheus do
- monitoring_tool { Gitlab::AlertManagement::AlertParams::MONITORING_TOOLS[:prometheus] }
+ monitoring_tool { Gitlab::AlertManagement::Payload::MONITORING_TOOLS[:prometheus] }
payload do
{
annotations: {
@@ -123,5 +123,17 @@ FactoryBot.define do
with_description
low
end
+
+ trait :from_payload do
+ after(:build) do |alert|
+ alert_params = ::Gitlab::AlertManagement::Payload.parse(
+ alert.project,
+ alert.payload,
+ monitoring_tool: alert.monitoring_tool
+ ).alert_params
+
+ alert.assign_attributes(alert_params)
+ end
+ end
end
end
diff --git a/spec/factories/alert_management/http_integrations.rb b/spec/factories/alert_management/http_integrations.rb
new file mode 100644
index 00000000000..9311cb3e114
--- /dev/null
+++ b/spec/factories/alert_management/http_integrations.rb
@@ -0,0 +1,14 @@
+# frozen_string_literal: true
+
+FactoryBot.define do
+ factory :alert_management_http_integration, class: 'AlertManagement::HttpIntegration' do
+ project
+ active { true }
+ name { 'DataDog' }
+ endpoint_identifier { SecureRandom.hex(4) }
+
+ trait :inactive do
+ active { false }
+ end
+ end
+end
diff --git a/spec/factories/alerting/alert.rb b/spec/factories/alerting/alert.rb
deleted file mode 100644
index 285bb14efa2..00000000000
--- a/spec/factories/alerting/alert.rb
+++ /dev/null
@@ -1,25 +0,0 @@
-# frozen_string_literal: true
-
-FactoryBot.define do
- factory :alerting_alert, class: 'Gitlab::Alerting::Alert' do
- project
- payload { {} }
-
- transient do
- metric_id { nil }
-
- after(:build) do |alert, evaluator|
- unless alert.payload.key?('startsAt')
- alert.payload['startsAt'] = Time.now.rfc3339
- end
-
- if metric_id = evaluator.metric_id
- alert.payload['labels'] ||= {}
- alert.payload['labels']['gitlab_alert_id'] = metric_id.to_s
- end
- end
- end
-
- skip_create
- end
-end
diff --git a/spec/factories/authentication_event.rb b/spec/factories/authentication_event.rb
new file mode 100644
index 00000000000..ff539c6f5c4
--- /dev/null
+++ b/spec/factories/authentication_event.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+FactoryBot.define do
+ factory :authentication_event do
+ user
+ provider { :standard }
+ user_name { 'Jane Doe' }
+ ip_address { '127.0.0.1' }
+ result { :failed }
+ end
+end
diff --git a/spec/factories/bulk_import.rb b/spec/factories/bulk_import.rb
new file mode 100644
index 00000000000..0231fe7cfef
--- /dev/null
+++ b/spec/factories/bulk_import.rb
@@ -0,0 +1,8 @@
+# frozen_string_literal: true
+
+FactoryBot.define do
+ factory :bulk_import, class: 'BulkImport' do
+ user
+ source_type { :gitlab }
+ end
+end
diff --git a/spec/factories/bulk_import/entities.rb b/spec/factories/bulk_import/entities.rb
new file mode 100644
index 00000000000..3bf6af92d00
--- /dev/null
+++ b/spec/factories/bulk_import/entities.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+FactoryBot.define do
+ factory :bulk_import_entity, class: 'BulkImports::Entity' do
+ bulk_import
+
+ source_type { :group_entity }
+ sequence(:source_full_path) { |n| "source-path-#{n}" }
+
+ sequence(:destination_namespace) { |n| "destination-path-#{n}" }
+ destination_name { 'Imported Entity' }
+
+ trait(:group_entity) do
+ source_type { :group_entity }
+ end
+
+ trait(:project_entity) do
+ source_type { :project_entity }
+ end
+ end
+end
diff --git a/spec/factories/ci/bridge.rb b/spec/factories/ci/bridge.rb
index 5a33a30921b..7727a468633 100644
--- a/spec/factories/ci/bridge.rb
+++ b/spec/factories/ci/bridge.rb
@@ -40,6 +40,10 @@ FactoryBot.define do
end
end
+ trait :created do
+ status { 'created' }
+ end
+
trait :started do
started_at { '2013-10-29 09:51:28 CET' }
end
@@ -62,5 +66,14 @@ FactoryBot.define do
trait :strategy_depend do
options { { trigger: { strategy: 'depend' } } }
end
+
+ trait :manual do
+ status { 'manual' }
+ self.when { 'manual' }
+ end
+
+ trait :playable do
+ manual
+ end
end
end
diff --git a/spec/factories/ci/build_pending_states.rb b/spec/factories/ci/build_pending_states.rb
index 765b7f005b9..eddd74b1068 100644
--- a/spec/factories/ci/build_pending_states.rb
+++ b/spec/factories/ci/build_pending_states.rb
@@ -3,7 +3,7 @@
FactoryBot.define do
factory :ci_build_pending_state, class: 'Ci::BuildPendingState' do
build factory: :ci_build
- trace_checksum { 'crc32:12345678' }
+ trace_checksum { 'crc32:bc614e' }
state { 'success' }
end
end
diff --git a/spec/factories/ci/build_trace_chunks.rb b/spec/factories/ci/build_trace_chunks.rb
index 7c348f4b7e4..d996b41b648 100644
--- a/spec/factories/ci/build_trace_chunks.rb
+++ b/spec/factories/ci/build_trace_chunks.rb
@@ -53,5 +53,18 @@ FactoryBot.define do
trait :fog_without_data do
data_store { :fog }
end
+
+ trait :persisted do
+ data_store { :database}
+
+ transient do
+ initial_data { 'test data' }
+ end
+
+ after(:build) do |chunk, evaluator|
+ Ci::BuildTraceChunks::Database.new.set_data(chunk, evaluator.initial_data)
+ chunk.checksum = chunk.class.crc32(evaluator.initial_data)
+ end
+ end
end
end
diff --git a/spec/factories/ci/builds.rb b/spec/factories/ci/builds.rb
index b3815b53c2b..73920b76025 100644
--- a/spec/factories/ci/builds.rb
+++ b/spec/factories/ci/builds.rb
@@ -384,7 +384,8 @@ FactoryBot.define do
key: 'cache_key',
untracked: false,
paths: ['vendor/*'],
- policy: 'pull-push'
+ policy: 'pull-push',
+ when: 'on_success'
}
}
end
diff --git a/spec/factories/ci/deleted_object.rb b/spec/factories/ci/deleted_object.rb
new file mode 100644
index 00000000000..c91d259ffeb
--- /dev/null
+++ b/spec/factories/ci/deleted_object.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+FactoryBot.define do
+ factory :ci_deleted_object, class: 'Ci::DeletedObject' do
+ pick_up_at { Time.current }
+ store_dir { SecureRandom.uuid }
+ file { fixture_file_upload(Rails.root.join('spec/fixtures/ci_build_artifacts.zip'), 'application/zip') }
+ end
+end
diff --git a/spec/factories/ci/pipelines.rb b/spec/factories/ci/pipelines.rb
index 6174bfbfbb7..4fa5dde4eff 100644
--- a/spec/factories/ci/pipelines.rb
+++ b/spec/factories/ci/pipelines.rb
@@ -15,15 +15,31 @@ FactoryBot.define do
# on pipeline factories to avoid circular references
transient { head_pipeline_of { nil } }
+ transient { child_of { nil } }
+
+ after(:build) do |pipeline, evaluator|
+ if evaluator.child_of
+ pipeline.project = evaluator.child_of.project
+ pipeline.source = :parent_pipeline
+ end
+ end
+
after(:create) do |pipeline, evaluator|
merge_request = evaluator.head_pipeline_of
merge_request&.update!(head_pipeline: pipeline)
+
+ if evaluator.child_of
+ bridge = create(:ci_bridge, pipeline: evaluator.child_of)
+ create(:ci_sources_pipeline,
+ source_job: bridge,
+ pipeline: pipeline)
+ end
end
factory :ci_pipeline do
transient { ci_ref_presence { true } }
- after(:build) do |pipeline, evaluator|
+ before(:create) do |pipeline, evaluator|
pipeline.ensure_ci_ref! if evaluator.ci_ref_presence && pipeline.ci_ref_id.nil?
end
diff --git a/spec/factories/ci/test_case.rb b/spec/factories/ci/test_case.rb
index 0639aac566a..7f99f0e123e 100644
--- a/spec/factories/ci/test_case.rb
+++ b/spec/factories/ci/test_case.rb
@@ -2,6 +2,7 @@
FactoryBot.define do
factory :test_case, class: 'Gitlab::Ci::Reports::TestCase' do
+ suite_name { "rspec" }
name { "test-1" }
classname { "trace" }
file { "spec/trace_spec.rb" }
@@ -25,6 +26,7 @@ FactoryBot.define do
initialize_with do
new(
+ suite_name: suite_name,
name: name,
classname: classname,
file: file,
diff --git a/spec/factories/design_management/designs.rb b/spec/factories/design_management/designs.rb
index 66c33c9ece0..38d0545483c 100644
--- a/spec/factories/design_management/designs.rb
+++ b/spec/factories/design_management/designs.rb
@@ -75,7 +75,7 @@ FactoryBot.define do
end
# Use this trait if you want versions in a particular history, but don't
- # want to pay for gitlay calls.
+ # want to pay for gitaly calls.
trait :with_versions do
transient do
deleted { false }
diff --git a/spec/factories/events.rb b/spec/factories/events.rb
index ecbda5fbfd3..6c9f1ba0137 100644
--- a/spec/factories/events.rb
+++ b/spec/factories/events.rb
@@ -18,6 +18,7 @@ FactoryBot.define do
trait(:destroyed) { action { :destroyed } }
trait(:expired) { action { :expired } }
trait(:archived) { action { :archived } }
+ trait(:approved) { action { :approved } }
factory :closed_issue_event do
action { :closed }
@@ -55,6 +56,16 @@ FactoryBot.define do
action { :created }
target { design }
end
+
+ factory :project_created_event do
+ project factory: :project
+ action { :created }
+ end
+
+ factory :project_imported_event do
+ project factory: [:project, :with_import_url]
+ action { :created }
+ end
end
factory :push_event, class: 'PushEvent' do
diff --git a/spec/factories/group_import_states.rb b/spec/factories/group_import_states.rb
index 0b491d444fa..47d4b480b12 100644
--- a/spec/factories/group_import_states.rb
+++ b/spec/factories/group_import_states.rb
@@ -3,6 +3,7 @@
FactoryBot.define do
factory :group_import_state, class: 'GroupImportState', traits: %i[created] do
association :group, factory: :group
+ association :user, factory: :user
trait :created do
status { 0 }
diff --git a/spec/factories/groups.rb b/spec/factories/groups.rb
index 60d427dde00..17db69e4699 100644
--- a/spec/factories/groups.rb
+++ b/spec/factories/groups.rb
@@ -14,6 +14,8 @@ FactoryBot.define do
# https://gitlab.com/gitlab-org/gitlab-foss/issues/43292
raise "Don't set owner for groups, use `group.add_owner(user)` instead"
end
+
+ create(:namespace_settings, namespace: group)
end
trait :public do
@@ -21,7 +23,7 @@ FactoryBot.define do
end
trait :internal do
- visibility_level {Gitlab::VisibilityLevel::INTERNAL }
+ visibility_level { Gitlab::VisibilityLevel::INTERNAL }
end
trait :private do
diff --git a/spec/factories/instance_statistics/measurement.rb b/spec/factories/instance_statistics/measurement.rb
index fb180c23214..f9398cd3061 100644
--- a/spec/factories/instance_statistics/measurement.rb
+++ b/spec/factories/instance_statistics/measurement.rb
@@ -13,5 +13,13 @@ FactoryBot.define do
trait :group_count do
identifier { :groups }
end
+
+ trait :pipelines_succeeded_count do
+ identifier { :pipelines_succeeded }
+ end
+
+ trait :pipelines_skipped_count do
+ identifier { :pipelines_skipped }
+ end
end
end
diff --git a/spec/factories/issue_email_participants.rb b/spec/factories/issue_email_participants.rb
new file mode 100644
index 00000000000..730e224b01e
--- /dev/null
+++ b/spec/factories/issue_email_participants.rb
@@ -0,0 +1,8 @@
+# frozen_string_literal: true
+
+FactoryBot.define do
+ factory :issue_email_participant do
+ issue
+ email { generate(:email) }
+ end
+end
diff --git a/spec/factories/merge_request_diffs.rb b/spec/factories/merge_request_diffs.rb
index fdb7f52f3bd..481cabdae6d 100644
--- a/spec/factories/merge_request_diffs.rb
+++ b/spec/factories/merge_request_diffs.rb
@@ -2,13 +2,7 @@
FactoryBot.define do
factory :merge_request_diff do
- merge_request do
- build(:merge_request) do |merge_request|
- # MergeRequest should not create a MergeRequestDiff in the callback
- allow(merge_request).to receive(:ensure_merge_request_diff)
- end
- end
-
+ association :merge_request, factory: :merge_request_without_merge_request_diff
state { :collected }
commits_count { 1 }
diff --git a/spec/factories/merge_requests.rb b/spec/factories/merge_requests.rb
index 6836d5d71f0..e5381071228 100644
--- a/spec/factories/merge_requests.rb
+++ b/spec/factories/merge_requests.rb
@@ -164,6 +164,10 @@ FactoryBot.define do
target_branch { generate(:branch) }
end
+ trait :unique_author do
+ author { association(:user) }
+ end
+
trait :with_coverage_reports do
after(:build) do |merge_request|
merge_request.head_pipeline = build(
@@ -286,5 +290,7 @@ FactoryBot.define do
merge_request.update!(labels: evaluator.labels)
end
end
+
+ factory :merge_request_without_merge_request_diff, class: 'MergeRequestWithoutMergeRequestDiff'
end
end
diff --git a/spec/factories/namespaces.rb b/spec/factories/namespaces.rb
index 0dcec086da9..0ec977b8234 100644
--- a/spec/factories/namespaces.rb
+++ b/spec/factories/namespaces.rb
@@ -63,5 +63,13 @@ FactoryBot.define do
)
end
end
+
+ trait :shared_runners_disabled do
+ shared_runners_enabled { false }
+ end
+
+ trait :allow_descendants_override_disabled_shared_runners do
+ allow_descendants_override_disabled_shared_runners { true }
+ end
end
end
diff --git a/spec/factories/packages.rb b/spec/factories/packages.rb
index 52b2a32cd3b..e2c5b000988 100644
--- a/spec/factories/packages.rb
+++ b/spec/factories/packages.rb
@@ -21,6 +21,10 @@ FactoryBot.define do
end
end
+ factory :debian_package do
+ package_type { :debian }
+ end
+
factory :npm_package do
sequence(:name) { |n| "@#{project.root_namespace.path}/package-#{n}"}
version { '1.0.0' }
@@ -91,6 +95,12 @@ FactoryBot.define do
end
end
+ factory :golang_package do
+ sequence(:name) { |n| "golang.org/x/pkg-#{n}"}
+ sequence(:version) { |n| "v1.0.#{n}" }
+ package_type { :golang }
+ end
+
factory :conan_package do
conan_metadatum
@@ -141,160 +151,6 @@ FactoryBot.define do
package
end
- factory :package_file, class: 'Packages::PackageFile' do
- package
-
- file_name { 'somefile.txt' }
-
- transient do
- file_fixture { 'spec/fixtures/packages/conan/recipe_files/conanfile.py' }
- end
-
- after(:build) do |package_file, evaluator|
- package_file.file = fixture_file_upload(evaluator.file_fixture)
- end
-
- factory :conan_package_file do
- package { create(:conan_package, without_package_files: true) }
-
- transient do
- without_loaded_metadatum { false }
- end
-
- trait(:conan_recipe_file) do
- after :create do |package_file, evaluator|
- unless evaluator.without_loaded_metadatum
- create :conan_file_metadatum, :recipe_file, package_file: package_file
- end
- end
-
- file_fixture { 'spec/fixtures/packages/conan/recipe_files/conanfile.py' }
- file_name { 'conanfile.py' }
- file_sha1 { 'be93151dc23ac34a82752444556fe79b32c7a1ad' }
- file_md5 { '12345abcde' }
- size { 400.kilobytes }
- end
-
- trait(:conan_recipe_manifest) do
- after :create do |package_file, evaluator|
- unless evaluator.without_loaded_metadatum
- create :conan_file_metadatum, :recipe_file, package_file: package_file
- end
- end
-
- file_fixture { 'spec/fixtures/packages/conan/recipe_files/conanmanifest.txt' }
- file_name { 'conanmanifest.txt' }
- file_sha1 { 'be93151dc23ac34a82752444556fe79b32c7a1ad' }
- file_md5 { '12345abcde' }
- size { 400.kilobytes }
- end
-
- trait(:conan_package_manifest) do
- after :create do |package_file, evaluator|
- unless evaluator.without_loaded_metadatum
- create :conan_file_metadatum, :package_file, package_file: package_file
- end
- end
-
- file_fixture { 'spec/fixtures/packages/conan/package_files/conanmanifest.txt' }
- file_name { 'conanmanifest.txt' }
- file_sha1 { 'be93151dc23ac34a82752444556fe79b32c7a1ad' }
- file_md5 { '12345abcde' }
- size { 400.kilobytes }
- end
-
- trait(:conan_package_info) do
- after :create do |package_file, evaluator|
- unless evaluator.without_loaded_metadatum
- create :conan_file_metadatum, :package_file, package_file: package_file
- end
- end
-
- file_fixture { 'spec/fixtures/packages/conan/package_files/conaninfo.txt' }
- file_name { 'conaninfo.txt' }
- file_sha1 { 'be93151dc23ac34a82752444556fe79b32c7a1ad' }
- file_md5 { '12345abcde' }
- size { 400.kilobytes }
- end
-
- trait(:conan_package) do
- after :create do |package_file, evaluator|
- unless evaluator.without_loaded_metadatum
- create :conan_file_metadatum, :package_file, package_file: package_file
- end
- end
-
- file_fixture { 'spec/fixtures/packages/conan/package_files/conan_package.tgz' }
- file_name { 'conan_package.tgz' }
- file_sha1 { 'be93151dc23ac34a82752444556fe79b32c7a1ad' }
- file_md5 { '12345abcde' }
- size { 400.kilobytes }
- end
- end
-
- trait(:jar) do
- file_fixture { 'spec/fixtures/packages/maven/my-app-1.0-20180724.124855-1.jar' }
- file_name { 'my-app-1.0-20180724.124855-1.jar' }
- file_sha1 { '4f0bfa298744d505383fbb57c554d4f5c12d88b3' }
- size { 100.kilobytes }
- end
-
- trait(:pom) do
- file_fixture { 'spec/fixtures/packages/maven/my-app-1.0-20180724.124855-1.pom' }
- file_name { 'my-app-1.0-20180724.124855-1.pom' }
- file_sha1 { '19c975abd49e5102ca6c74a619f21e0cf0351c57' }
- size { 200.kilobytes }
- end
-
- trait(:xml) do
- file_fixture { 'spec/fixtures/packages/maven/maven-metadata.xml' }
- file_name { 'maven-metadata.xml' }
- file_sha1 { '42b1bdc80de64953b6876f5a8c644f20204011b0' }
- size { 300.kilobytes }
- end
-
- trait(:npm) do
- file_fixture { 'spec/fixtures/packages/npm/foo-1.0.1.tgz' }
- file_name { 'foo-1.0.1.tgz' }
- file_sha1 { 'be93151dc23ac34a82752444556fe79b32c7a1ad' }
- verified_at { Date.current }
- verification_checksum { '4437b5775e61455588a7e5187a2e5c58c680694260bbe5501c235ec690d17f83' }
- size { 400.kilobytes }
- end
-
- trait(:nuget) do
- package
- file_fixture { 'spec/fixtures/packages/nuget/package.nupkg' }
- file_name { 'package.nupkg' }
- file_sha1 { '5fe852b2a6abd96c22c11fa1ff2fb19d9ce58b57' }
- size { 300.kilobytes }
- end
-
- trait(:pypi) do
- package
- file_fixture { 'spec/fixtures/packages/pypi/sample-project.tar.gz' }
- file_name { 'sample-project-1.0.0.tar.gz' }
- file_sha1 { '2c0cfbed075d3fae226f051f0cc771b533e01aff' }
- file_md5 { '0a7392d24f42f83068fa3767c5310052' }
- file_sha256 { '440e5e148a25331bbd7991575f7d54933c0ebf6cc735a18ee5066ac1381bb590' }
- size { 1149.bytes }
- end
-
- trait(:object_storage) do
- file_store { Packages::PackageFileUploader::Store::REMOTE }
- end
-
- trait(:checksummed) do
- verification_checksum { 'abc' }
- end
-
- trait(:checksum_failure) do
- verification_failure { 'Could not calculate the checksum' }
- end
-
- factory :package_file_with_file, traits: [:jar]
- end
-
factory :maven_metadatum, class: 'Packages::Maven::Metadatum' do
association :package, package_type: :maven
path { 'my/company/app/my-app/1.0-SNAPSHOT' }
diff --git a/spec/factories/packages/package_file.rb b/spec/factories/packages/package_file.rb
new file mode 100644
index 00000000000..bcca48fb086
--- /dev/null
+++ b/spec/factories/packages/package_file.rb
@@ -0,0 +1,165 @@
+# frozen_string_literal: true
+
+FactoryBot.define do
+ factory :package_file, class: 'Packages::PackageFile' do
+ package
+
+ file_name { 'somefile.txt' }
+
+ transient do
+ file_fixture { 'spec/fixtures/packages/conan/recipe_files/conanfile.py' }
+ end
+
+ after(:build) do |package_file, evaluator|
+ package_file.file = fixture_file_upload(evaluator.file_fixture)
+ end
+
+ factory :conan_package_file do
+ package { create(:conan_package, without_package_files: true) }
+
+ transient do
+ without_loaded_metadatum { false }
+ end
+
+ trait(:conan_recipe_file) do
+ after :create do |package_file, evaluator|
+ unless evaluator.without_loaded_metadatum
+ create :conan_file_metadatum, :recipe_file, package_file: package_file
+ end
+ end
+
+ file_fixture { 'spec/fixtures/packages/conan/recipe_files/conanfile.py' }
+ file_name { 'conanfile.py' }
+ file_sha1 { 'be93151dc23ac34a82752444556fe79b32c7a1ad' }
+ file_md5 { '12345abcde' }
+ size { 400.kilobytes }
+ end
+
+ trait(:conan_recipe_manifest) do
+ after :create do |package_file, evaluator|
+ unless evaluator.without_loaded_metadatum
+ create :conan_file_metadatum, :recipe_file, package_file: package_file
+ end
+ end
+
+ file_fixture { 'spec/fixtures/packages/conan/recipe_files/conanmanifest.txt' }
+ file_name { 'conanmanifest.txt' }
+ file_sha1 { 'be93151dc23ac34a82752444556fe79b32c7a1ad' }
+ file_md5 { '12345abcde' }
+ size { 400.kilobytes }
+ end
+
+ trait(:conan_package_manifest) do
+ after :create do |package_file, evaluator|
+ unless evaluator.without_loaded_metadatum
+ create :conan_file_metadatum, :package_file, package_file: package_file
+ end
+ end
+
+ file_fixture { 'spec/fixtures/packages/conan/package_files/conanmanifest.txt' }
+ file_name { 'conanmanifest.txt' }
+ file_sha1 { 'be93151dc23ac34a82752444556fe79b32c7a1ad' }
+ file_md5 { '12345abcde' }
+ size { 400.kilobytes }
+ end
+
+ trait(:conan_package_info) do
+ after :create do |package_file, evaluator|
+ unless evaluator.without_loaded_metadatum
+ create :conan_file_metadatum, :package_file, package_file: package_file
+ end
+ end
+
+ file_fixture { 'spec/fixtures/packages/conan/package_files/conaninfo.txt' }
+ file_name { 'conaninfo.txt' }
+ file_sha1 { 'be93151dc23ac34a82752444556fe79b32c7a1ad' }
+ file_md5 { '12345abcde' }
+ size { 400.kilobytes }
+ end
+
+ trait(:conan_package) do
+ after :create do |package_file, evaluator|
+ unless evaluator.without_loaded_metadatum
+ create :conan_file_metadatum, :package_file, package_file: package_file
+ end
+ end
+
+ file_fixture { 'spec/fixtures/packages/conan/package_files/conan_package.tgz' }
+ file_name { 'conan_package.tgz' }
+ file_sha1 { 'be93151dc23ac34a82752444556fe79b32c7a1ad' }
+ file_md5 { '12345abcde' }
+ size { 400.kilobytes }
+ end
+ end
+
+ trait(:jar) do
+ file_fixture { 'spec/fixtures/packages/maven/my-app-1.0-20180724.124855-1.jar' }
+ file_name { 'my-app-1.0-20180724.124855-1.jar' }
+ file_sha1 { '4f0bfa298744d505383fbb57c554d4f5c12d88b3' }
+ size { 100.kilobytes }
+ end
+
+ trait(:pom) do
+ file_fixture { 'spec/fixtures/packages/maven/my-app-1.0-20180724.124855-1.pom' }
+ file_name { 'my-app-1.0-20180724.124855-1.pom' }
+ file_sha1 { '19c975abd49e5102ca6c74a619f21e0cf0351c57' }
+ size { 200.kilobytes }
+ end
+
+ trait(:xml) do
+ file_fixture { 'spec/fixtures/packages/maven/maven-metadata.xml' }
+ file_name { 'maven-metadata.xml' }
+ file_sha1 { '42b1bdc80de64953b6876f5a8c644f20204011b0' }
+ size { 300.kilobytes }
+ end
+
+ trait(:npm) do
+ file_fixture { 'spec/fixtures/packages/npm/foo-1.0.1.tgz' }
+ file_name { 'foo-1.0.1.tgz' }
+ file_sha1 { 'be93151dc23ac34a82752444556fe79b32c7a1ad' }
+ verified_at { Date.current }
+ verification_checksum { '4437b5775e61455588a7e5187a2e5c58c680694260bbe5501c235ec690d17f83' }
+ size { 400.kilobytes }
+ end
+
+ trait(:nuget) do
+ package
+ file_fixture { 'spec/fixtures/packages/nuget/package.nupkg' }
+ file_name { 'package.nupkg' }
+ file_sha1 { '5fe852b2a6abd96c22c11fa1ff2fb19d9ce58b57' }
+ size { 300.kilobytes }
+ end
+
+ trait(:pypi) do
+ package
+ file_fixture { 'spec/fixtures/packages/pypi/sample-project.tar.gz' }
+ file_name { 'sample-project-1.0.0.tar.gz' }
+ file_sha1 { '2c0cfbed075d3fae226f051f0cc771b533e01aff' }
+ file_md5 { '0a7392d24f42f83068fa3767c5310052' }
+ file_sha256 { '440e5e148a25331bbd7991575f7d54933c0ebf6cc735a18ee5066ac1381bb590' }
+ size { 1149.bytes }
+ end
+
+ trait(:generic) do
+ package
+ file_fixture { 'spec/fixtures/packages/generic/myfile.tar.gz' }
+ file_name { "#{package.name}.tar.gz" }
+ file_sha256 { '440e5e148a25331bbd7991575f7d54933c0ebf6cc735a18ee5066ac1381bb590' }
+ size { 1149.bytes }
+ end
+
+ trait(:object_storage) do
+ file_store { Packages::PackageFileUploader::Store::REMOTE }
+ end
+
+ trait(:checksummed) do
+ verification_checksum { 'abc' }
+ end
+
+ trait(:checksum_failure) do
+ verification_failure { 'Could not calculate the checksum' }
+ end
+
+ factory :package_file_with_file, traits: [:jar]
+ end
+end
diff --git a/spec/factories/pages_deployments.rb b/spec/factories/pages_deployments.rb
index 1bea003d683..f57852a8f94 100644
--- a/spec/factories/pages_deployments.rb
+++ b/spec/factories/pages_deployments.rb
@@ -3,10 +3,11 @@
FactoryBot.define do
factory :pages_deployment, class: 'PagesDeployment' do
project
- file_store { ObjectStorage::SUPPORTED_STORES.first }
- size { 1.megabytes }
- # TODO: replace with proper file uploaded in https://gitlab.com/gitlab-org/gitlab/-/issues/245295
- file { "dummy string" }
+ after(:build) do |deployment, _evaluator|
+ deployment.file = fixture_file_upload(
+ Rails.root.join("spec/fixtures/pages.zip")
+ )
+ end
end
end
diff --git a/spec/factories/project_repository_storage_moves.rb b/spec/factories/project_repository_storage_moves.rb
index 69fb3af45e6..c0068de5f58 100644
--- a/spec/factories/project_repository_storage_moves.rb
+++ b/spec/factories/project_repository_storage_moves.rb
@@ -5,7 +5,6 @@ FactoryBot.define do
project
source_storage_name { 'default' }
- destination_storage_name { 'default' }
trait :scheduled do
state { ProjectRepositoryStorageMove.state_machines[:state].states[:scheduled].value }
diff --git a/spec/factories/project_tracing_settings.rb b/spec/factories/project_tracing_settings.rb
new file mode 100644
index 00000000000..05c1529c18e
--- /dev/null
+++ b/spec/factories/project_tracing_settings.rb
@@ -0,0 +1,8 @@
+# frozen_string_literal: true
+
+FactoryBot.define do
+ factory :project_tracing_setting do
+ project
+ external_url { 'https://example.com' }
+ end
+end
diff --git a/spec/factories/projects.rb b/spec/factories/projects.rb
index 147413557d6..87e4a8e355d 100644
--- a/spec/factories/projects.rb
+++ b/spec/factories/projects.rb
@@ -15,7 +15,7 @@ FactoryBot.define do
# Associations
namespace
- creator { group ? create(:user) : namespace&.owner }
+ creator { group ? association(:user) : namespace&.owner }
transient do
# Nest Project Feature attributes
@@ -285,6 +285,12 @@ FactoryBot.define do
end
end
+ trait :with_import_url do
+ import_finished
+
+ import_url { generate(:url) }
+ end
+
trait(:wiki_enabled) { wiki_access_level { ProjectFeature::ENABLED } }
trait(:wiki_disabled) { wiki_access_level { ProjectFeature::DISABLED } }
trait(:wiki_private) { wiki_access_level { ProjectFeature::PRIVATE } }
diff --git a/spec/factories/prometheus_alert.rb b/spec/factories/prometheus_alert.rb
index 18cf1a20e0d..ad3868c38ed 100644
--- a/spec/factories/prometheus_alert.rb
+++ b/spec/factories/prometheus_alert.rb
@@ -7,11 +7,11 @@ FactoryBot.define do
threshold { 1 }
environment do |alert|
- build(:environment, project: alert.project)
+ association(:environment, project: alert.project)
end
prometheus_metric do |alert|
- build(:prometheus_metric, project: alert.project)
+ association(:prometheus_metric, project: alert.project)
end
trait :with_runbook_url do
diff --git a/spec/factories/prometheus_metrics.rb b/spec/factories/prometheus_metrics.rb
index 83e3845f1c3..503d392a524 100644
--- a/spec/factories/prometheus_metrics.rb
+++ b/spec/factories/prometheus_metrics.rb
@@ -9,6 +9,7 @@ FactoryBot.define do
group { :business }
project
legend { 'legend' }
+ dashboard_path { '.gitlab/dashboards/dashboard_path.yml'}
trait :common do
common { true }
diff --git a/spec/factories/resource_weight_events.rb b/spec/factories/resource_weight_events.rb
deleted file mode 100644
index cb9a34df332..00000000000
--- a/spec/factories/resource_weight_events.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-# frozen_string_literal: true
-
-FactoryBot.define do
- factory :resource_weight_event do
- issue { create(:issue) }
- user { issue&.author || create(:user) }
- end
-end
diff --git a/spec/factories/services.rb b/spec/factories/services.rb
index 9056fd97f13..13997080817 100644
--- a/spec/factories/services.rb
+++ b/spec/factories/services.rb
@@ -81,7 +81,7 @@ FactoryBot.define do
project_key { nil }
end
- after(:build) do |service, evaluator|
+ before(:create) do |service, evaluator|
if evaluator.create_data
create(:jira_tracker_data, service: service,
url: evaluator.url, api_url: evaluator.api_url, jira_issue_transition_id: evaluator.jira_issue_transition_id,
@@ -130,7 +130,7 @@ FactoryBot.define do
new_issue_url { 'http://new-issue.example.com' }
end
- after(:build) do |service, evaluator|
+ before(:create) do |service, evaluator|
if evaluator.create_data
create(:issue_tracker_data, service: service,
project_url: evaluator.project_url, issues_url: evaluator.issues_url, new_issue_url: evaluator.new_issue_url
@@ -151,7 +151,7 @@ FactoryBot.define do
project_identifier_code { 'PRJ-1' }
end
- after(:build) do |service, evaluator|
+ before(:create) do |service, evaluator|
create(:open_project_tracker_data, service: service,
url: evaluator.url, api_url: evaluator.api_url, token: evaluator.token,
closed_status_id: evaluator.closed_status_id, project_identifier_code: evaluator.project_identifier_code
diff --git a/spec/factories/terraform/state.rb b/spec/factories/terraform/state.rb
index 9decc89ef39..d80c1315e28 100644
--- a/spec/factories/terraform/state.rb
+++ b/spec/factories/terraform/state.rb
@@ -17,16 +17,6 @@ FactoryBot.define do
locked_by_user { create(:user) }
end
- trait(:checksummed) do
- with_file
- verification_checksum { 'abc' }
- end
-
- trait(:checksum_failure) do
- with_file
- verification_failure { 'Could not calculate the checksum' }
- end
-
trait :with_version do
after(:create) do |state|
create(:terraform_state_version, :with_file, terraform_state: state)
diff --git a/spec/factories/terraform/state_version.rb b/spec/factories/terraform/state_version.rb
index d1bd78215e3..b45bd01fd3c 100644
--- a/spec/factories/terraform/state_version.rb
+++ b/spec/factories/terraform/state_version.rb
@@ -7,5 +7,13 @@ FactoryBot.define do
sequence(:version)
file { fixture_file_upload('spec/fixtures/terraform/terraform.tfstate', 'application/json') }
+
+ trait(:checksummed) do
+ verification_checksum { 'abc' }
+ end
+
+ trait(:checksum_failure) do
+ verification_failure { 'Could not calculate the checksum' }
+ end
end
end
diff --git a/spec/factories/todos.rb b/spec/factories/todos.rb
index 0b5d00cff67..97a1265c46a 100644
--- a/spec/factories/todos.rb
+++ b/spec/factories/todos.rb
@@ -12,6 +12,10 @@ FactoryBot.define do
action { Todo::ASSIGNED }
end
+ trait :review_requested do
+ action { Todo::REVIEW_REQUESTED }
+ end
+
trait :mentioned do
action { Todo::MENTIONED }
end
diff --git a/spec/factories/usage_data.rb b/spec/factories/usage_data.rb
index 5b20205a235..adca6eabb0e 100644
--- a/spec/factories/usage_data.rb
+++ b/spec/factories/usage_data.rb
@@ -7,12 +7,12 @@ FactoryBot.define do
initialize_with do
projects = create_list(:project, 3)
projects << create(:project, :repository)
+ group = create(:group)
create(:board, project: projects[0])
create(:jira_service, project: projects[0])
create(:jira_service, :without_properties_callback, project: projects[1])
create(:jira_service, :jira_cloud_service, project: projects[2])
- create(:jira_service, :without_properties_callback, project: projects[3],
- properties: { url: 'https://mysite.atlassian.net' })
+ create(:jira_service, :without_properties_callback, project: projects[3], properties: { url: 'https://mysite.atlassian.net' })
jira_label = create(:label, project: projects[0])
create(:jira_import_state, :finished, project: projects[0], label: jira_label, failed_to_import_count: 2, imported_issues_count: 7, total_issue_count: 9)
create(:jira_import_state, :finished, project: projects[1], label: jira_label, imported_issues_count: 3, total_issue_count: 3)
@@ -23,9 +23,11 @@ FactoryBot.define do
create(:service, project: projects[1], type: 'SlackService', active: true)
create(:service, project: projects[2], type: 'SlackService', active: true)
create(:service, project: projects[2], type: 'MattermostService', active: false)
+ create(:service, group: group, project: nil, type: 'MattermostService', active: true)
create(:service, :template, type: 'MattermostService', active: true)
matermost_instance = create(:service, :instance, type: 'MattermostService', active: true)
create(:service, project: projects[1], type: 'MattermostService', active: true, inherit_from_id: matermost_instance.id)
+ create(:service, group: group, project: nil, type: 'SlackService', active: true, inherit_from_id: matermost_instance.id)
create(:service, project: projects[2], type: 'CustomIssueTrackerService', active: true)
create(:project_error_tracking_setting, project: projects[0])
create(:project_error_tracking_setting, project: projects[1], enabled: false)
@@ -50,12 +52,14 @@ FactoryBot.define do
create(:protected_branch, project: projects[0])
create(:protected_branch, name: 'main', project: projects[0])
+ # Tracing
+ create(:project_tracing_setting, project: projects[0])
+
# Incident Labeled Issues
incident_label = create(:label, :incident, project: projects[0])
create(:labeled_issue, project: projects[0], labels: [incident_label])
- incident_group = create(:group)
incident_label_scoped_to_project = create(:label, :incident, project: projects[1])
- incident_label_scoped_to_group = create(:group_label, :incident, group: incident_group)
+ incident_label_scoped_to_group = create(:group_label, :incident, group: group)
create(:labeled_issue, project: projects[1], labels: [incident_label_scoped_to_project])
create(:labeled_issue, project: projects[1], labels: [incident_label_scoped_to_group])
@@ -97,16 +101,19 @@ FactoryBot.define do
create(:grafana_integration, project: projects[1], enabled: true)
create(:grafana_integration, project: projects[2], enabled: false)
- create(:package, project: projects[0])
- create(:package, project: projects[0])
- create(:package, project: projects[1])
+ create(:package, project: projects[0], created_at: 3.days.ago)
+ create(:package, project: projects[0], created_at: 3.days.ago)
+ create(:package, project: projects[1], created_at: 3.days.ago)
create(:package, created_at: 2.months.ago, project: projects[1])
+ # User Preferences
+ create(:user_preference, gitpod_enabled: true)
+
ProjectFeature.first.update_attribute('repository_access_level', 0)
# Create fresh & a month (28-days SMAU) old data
env = create(:environment, project: projects[3])
- [2, 29].each do |n|
+ [3, 31].each do |n|
deployment_options = { created_at: n.days.ago, project: env.project, environment: env }
create(:deployment, :failed, deployment_options)
create(:deployment, :success, deployment_options)
diff --git a/spec/factories/users.rb b/spec/factories/users.rb
index 1a8c5d7e40c..2e5b3be3bf2 100644
--- a/spec/factories/users.rb
+++ b/spec/factories/users.rb
@@ -23,6 +23,14 @@ FactoryBot.define do
after(:build) { |user, _| user.block! }
end
+ trait :blocked_pending_approval do
+ after(:build) { |user, _| user.block_pending_approval! }
+ end
+
+ trait :ldap_blocked do
+ after(:build) { |user, _| user.ldap_block! }
+ end
+
trait :bot do
user_type { :alert_bot }
end
diff --git a/spec/factories/wiki_pages.rb b/spec/factories/wiki_pages.rb
index cc866d336a4..3397277839e 100644
--- a/spec/factories/wiki_pages.rb
+++ b/spec/factories/wiki_pages.rb
@@ -9,7 +9,7 @@ FactoryBot.define do
content { 'Content for wiki page' }
format { :markdown }
message { nil }
- project { association(:project, :wiki_repo) }
+ project { association(:project) }
container { project }
wiki { association(:wiki, container: container) }
page { OpenStruct.new(url_path: title) }
@@ -18,6 +18,7 @@ FactoryBot.define do
initialize_with do
new(wiki, page).tap do |page|
page.attributes = {
+ slug: title&.tr(' ', '-'),
title: title,
content: content,
format: format
diff --git a/spec/factories/wikis.rb b/spec/factories/wikis.rb
index 96578fdcee6..86d98bfd756 100644
--- a/spec/factories/wikis.rb
+++ b/spec/factories/wikis.rb
@@ -3,8 +3,8 @@
FactoryBot.define do
factory :wiki do
transient do
- container { association(:project, :wiki_repo) }
- user { association(:user) }
+ container { association(:project) }
+ user { container.default_owner || association(:user) }
end
initialize_with { Wiki.for_container(container, user) }
@@ -12,7 +12,7 @@ FactoryBot.define do
factory :project_wiki do
transient do
- project { association(:project, :wiki_repo) }
+ project { association(:project) }
end
container { project }
diff --git a/spec/factories_spec.rb b/spec/factories_spec.rb
index f89aeb1c93d..7241af6e8c0 100644
--- a/spec/factories_spec.rb
+++ b/spec/factories_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe 'factories' do
- FactoryBot.factories.each do |factory|
+ shared_examples 'factory' do |factory|
describe "#{factory.name} factory" do
it 'does not raise error when built' do
expect { build(factory.name) }.not_to raise_error
@@ -22,4 +22,32 @@ RSpec.describe 'factories' do
end
end
end
+
+ # FactoryDefault speed up specs by creating associations only once
+ # and reuse them in other factories.
+ #
+ # However, for some factories we cannot use FactoryDefault because the
+ # associations must be unique and cannot be reused.
+ skip_factory_defaults = %i[
+ fork_network_member
+ ].to_set.freeze
+
+ without_fd, with_fd = FactoryBot.factories
+ .partition { |factory| skip_factory_defaults.include?(factory.name) }
+
+ context 'with factory defaults', factory_default: :keep do
+ let_it_be(:namespace) { create_default(:namespace) }
+ let_it_be(:project) { create_default(:project, :repository) }
+ let_it_be(:user) { create_default(:user) }
+
+ with_fd.each do |factory|
+ it_behaves_like 'factory', factory
+ end
+ end
+
+ context 'without factory defaults' do
+ without_fd.each do |factory|
+ it_behaves_like 'factory', factory
+ end
+ end
end
diff --git a/spec/features/admin/admin_groups_spec.rb b/spec/features/admin/admin_groups_spec.rb
index f5c5a73c042..653a45a4bb8 100644
--- a/spec/features/admin/admin_groups_spec.rb
+++ b/spec/features/admin/admin_groups_spec.rb
@@ -194,7 +194,7 @@ RSpec.describe 'Admin Groups' do
expect(page).to have_content('Developer')
end
- accept_confirm { find(:css, 'li', text: current_user.name).find(:css, 'a.btn-remove').click }
+ accept_confirm { find(:css, 'li', text: current_user.name).find(:css, 'a.btn-danger').click }
visit group_group_members_path(group)
diff --git a/spec/features/admin/admin_mode/login_spec.rb b/spec/features/admin/admin_mode/login_spec.rb
index 12046518aac..7cbba9ec674 100644
--- a/spec/features/admin/admin_mode/login_spec.rb
+++ b/spec/features/admin/admin_mode/login_spec.rb
@@ -48,7 +48,7 @@ RSpec.describe 'Admin Mode Login', :clean_gitlab_redis_shared_state, :do_not_moc
it 'allows login with valid code' do
# Cannot reuse the TOTP
- Timecop.travel(30.seconds.from_now) do
+ travel_to(30.seconds.from_now) do
enter_code(user.current_otp)
expect(current_path).to eq admin_root_path
@@ -58,7 +58,7 @@ RSpec.describe 'Admin Mode Login', :clean_gitlab_redis_shared_state, :do_not_moc
it 'blocks login with invalid code' do
# Cannot reuse the TOTP
- Timecop.travel(30.seconds.from_now) do
+ travel_to(30.seconds.from_now) do
enter_code('foo')
expect(page).to have_content('Invalid two-factor code')
@@ -67,7 +67,7 @@ RSpec.describe 'Admin Mode Login', :clean_gitlab_redis_shared_state, :do_not_moc
it 'allows login with invalid code, then valid code' do
# Cannot reuse the TOTP
- Timecop.travel(30.seconds.from_now) do
+ travel_to(30.seconds.from_now) do
enter_code('foo')
expect(page).to have_content('Invalid two-factor code')
@@ -163,7 +163,7 @@ RSpec.describe 'Admin Mode Login', :clean_gitlab_redis_shared_state, :do_not_moc
expect(page).to have_content('Two-Factor Authentication')
# Cannot reuse the TOTP
- Timecop.travel(30.seconds.from_now) do
+ travel_to(30.seconds.from_now) do
enter_code(user.current_otp)
expect(current_path).to eq admin_root_path
@@ -215,7 +215,7 @@ RSpec.describe 'Admin Mode Login', :clean_gitlab_redis_shared_state, :do_not_moc
expect(page).to have_content('Two-Factor Authentication')
# Cannot reuse the TOTP
- Timecop.travel(30.seconds.from_now) do
+ travel_to(30.seconds.from_now) do
enter_code(user.current_otp)
expect(current_path).to eq admin_root_path
diff --git a/spec/features/admin/admin_settings_spec.rb b/spec/features/admin/admin_settings_spec.rb
index 38f0b813183..528dfad606e 100644
--- a/spec/features/admin/admin_settings_spec.rb
+++ b/spec/features/admin/admin_settings_spec.rb
@@ -130,6 +130,38 @@ RSpec.describe 'Admin updates settings', :clean_gitlab_redis_shared_state, :do_n
expect(user_internal_regex['placeholder']).to eq 'Regex pattern'
end
+ context 'Change Sign-up restrictions' do
+ context 'Require Admin approval for new signup setting' do
+ context 'when feature is enabled' do
+ before do
+ stub_feature_flags(admin_approval_for_new_user_signups: true)
+ end
+
+ it 'changes the setting' do
+ page.within('.as-signup') do
+ check 'Require admin approval for new sign-ups'
+ click_button 'Save changes'
+ end
+
+ expect(current_settings.require_admin_approval_after_user_signup).to be_truthy
+ expect(page).to have_content "Application settings saved successfully"
+ end
+ end
+
+ context 'when feature is disabled' do
+ before do
+ stub_feature_flags(admin_approval_for_new_user_signups: false)
+ end
+
+ it 'does not show the the setting' do
+ page.within('.as-signup') do
+ expect(page).not_to have_selector('.application_setting_require_admin_approval_after_user_signup')
+ end
+ end
+ end
+ end
+ end
+
it 'Change Sign-in restrictions' do
page.within('.as-signin') do
fill_in 'Home page URL', with: 'https://about.gitlab.com/'
@@ -497,18 +529,23 @@ RSpec.describe 'Admin updates settings', :clean_gitlab_redis_shared_state, :do_n
end
it 'Change Help page' do
+ stub_feature_flags(help_page_documentation_redirect: true)
+
new_support_url = 'http://example.com/help'
+ new_documentation_url = 'https://docs.gitlab.com'
page.within('.as-help-page') do
fill_in 'Help page text', with: 'Example text'
check 'Hide marketing-related entries from help'
fill_in 'Support page URL', with: new_support_url
+ fill_in 'Documentation pages URL', with: new_documentation_url
click_button 'Save changes'
end
expect(current_settings.help_page_text).to eq "Example text"
expect(current_settings.help_page_hide_commercial_content).to be_truthy
expect(current_settings.help_page_support_url).to eq new_support_url
+ expect(current_settings.help_page_documentation_base_url).to eq new_documentation_url
expect(page).to have_content "Application settings saved successfully"
end
diff --git a/spec/features/admin/admin_users_spec.rb b/spec/features/admin/admin_users_spec.rb
index a37210d2acc..e06e2d14f3c 100644
--- a/spec/features/admin/admin_users_spec.rb
+++ b/spec/features/admin/admin_users_spec.rb
@@ -31,6 +31,7 @@ RSpec.describe "Admin::Users" do
expect(page).to have_content(current_user.last_activity_on.strftime("%e %b, %Y"))
expect(page).to have_content(user.email)
expect(page).to have_content(user.name)
+ expect(page).to have_content('Projects')
expect(page).to have_button('Block')
expect(page).to have_button('Deactivate')
expect(page).to have_button('Delete user')
@@ -48,6 +49,56 @@ RSpec.describe "Admin::Users" do
end
end
+ context 'user project count' do
+ before do
+ project = create(:project)
+ project.add_maintainer(current_user)
+ end
+
+ it 'displays count of users projects' do
+ visit admin_users_path
+
+ expect(page.find("[data-testid='user-project-count-#{current_user.id}']").text).to eq("1")
+ end
+ end
+
+ describe 'tabs' do
+ it 'has multiple tabs to filter users' do
+ expect(page).to have_link('Active', href: admin_users_path)
+ expect(page).to have_link('Admins', href: admin_users_path(filter: 'admins'))
+ expect(page).to have_link('2FA Enabled', href: admin_users_path(filter: 'two_factor_enabled'))
+ expect(page).to have_link('2FA Disabled', href: admin_users_path(filter: 'two_factor_disabled'))
+ expect(page).to have_link('External', href: admin_users_path(filter: 'external'))
+ expect(page).to have_link('Blocked', href: admin_users_path(filter: 'blocked'))
+ expect(page).to have_link('Deactivated', href: admin_users_path(filter: 'deactivated'))
+ expect(page).to have_link('Without projects', href: admin_users_path(filter: 'wop'))
+ end
+
+ context '`Pending approval` tab' do
+ context 'feature is enabled' do
+ before do
+ stub_feature_flags(admin_approval_for_new_user_signups: true)
+ visit admin_users_path
+ end
+
+ it 'shows the `Pending approval` tab' do
+ expect(page).to have_link('Pending approval', href: admin_users_path(filter: 'blocked_pending_approval'))
+ end
+ end
+
+ context 'feature is disabled' do
+ before do
+ stub_feature_flags(admin_approval_for_new_user_signups: false)
+ visit admin_users_path
+ end
+
+ it 'does not show the `Pending approval` tab' do
+ expect(page).not_to have_link('Pending approval', href: admin_users_path(filter: 'blocked_pending_approval'))
+ end
+ end
+ end
+ end
+
describe 'search and sort' do
before do
create(:user, name: 'Foo Bar', last_activity_on: 3.days.ago)
@@ -146,6 +197,27 @@ RSpec.describe "Admin::Users" do
expect(page).to have_content(user.email)
end
end
+
+ describe 'Pending approval filter' do
+ it 'counts users who are pending approval' do
+ create_list(:user, 2, :blocked_pending_approval)
+
+ visit admin_users_path
+
+ page.within('.filter-blocked-pending-approval small') do
+ expect(page).to have_content('2')
+ end
+ end
+
+ it 'filters by users who are pending approval' do
+ user = create(:user, :blocked_pending_approval)
+
+ visit admin_users_path
+ click_link 'Pending approval'
+
+ expect(page).to have_content(user.email)
+ end
+ end
end
describe "GET /admin/users/new" do
@@ -287,6 +359,23 @@ RSpec.describe "Admin::Users" do
expect(page).to have_button('Delete user and contributions')
end
+ context 'user pending approval' do
+ it 'shows user info' do
+ user = create(:user, :blocked_pending_approval)
+
+ visit admin_users_path
+ click_link 'Pending approval'
+ click_link user.name
+
+ expect(page).to have_content(user.name)
+ expect(page).to have_content('Pending approval')
+ expect(page).to have_link('Approve user')
+ expect(page).to have_button('Block user')
+ expect(page).to have_button('Delete user')
+ expect(page).to have_button('Delete user and contributions')
+ end
+ end
+
describe 'Impersonation' do
let(:another_user) { create(:user) }
@@ -606,7 +695,7 @@ RSpec.describe "Admin::Users" do
end
end
- describe 'show user keys' do
+ describe 'show user keys', :js do
let!(:key1) do
create(:key, user: user, title: "ssh-rsa Key1", key: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC4FIEBXGi4bPU8kzxMefudPIJ08/gNprdNTaO9BR/ndy3+58s2HCTw2xCHcsuBmq+TsAqgEidVq4skpqoTMB+Uot5Uzp9z4764rc48dZiI661izoREoKnuRQSsRqUTHg5wrLzwxlQbl1MVfRWQpqiz/5KjBC7yLEb9AbusjnWBk8wvC1bQPQ1uLAauEA7d836tgaIsym9BrLsMVnR4P1boWD3Xp1B1T/ImJwAGHvRmP/ycIqmKdSpMdJXwxcb40efWVj0Ibbe7ii9eeoLdHACqevUZi6fwfbymdow+FeqlkPoHyGg3Cu4vD/D8+8cRc7mE/zGCWcQ15Var83Tczour Key1")
end
@@ -629,7 +718,11 @@ RSpec.describe "Admin::Users" do
expect(page).to have_content(key2.title)
expect(page).to have_content(key2.key)
- click_link 'Remove'
+ click_button 'Delete'
+
+ page.within('.modal') do
+ page.click_button('Delete')
+ end
expect(page).not_to have_content(key2.title)
end
diff --git a/spec/features/admin/admin_uses_repository_checks_spec.rb b/spec/features/admin/admin_uses_repository_checks_spec.rb
index b8851c28531..44642983a36 100644
--- a/spec/features/admin/admin_uses_repository_checks_spec.rb
+++ b/spec/features/admin/admin_uses_repository_checks_spec.rb
@@ -46,7 +46,7 @@ RSpec.describe 'Admin uses repository checks', :request_store, :clean_gitlab_red
)
visit_admin_project_page(project)
- page.within('.alert') do
+ page.within('.gl-alert') do
expect(page.text).to match(/Last repository check \(just now\) failed/)
end
end
diff --git a/spec/features/admin/clusters/eks_spec.rb b/spec/features/admin/clusters/eks_spec.rb
index ef49aebc7c5..ad7122bf182 100644
--- a/spec/features/admin/clusters/eks_spec.rb
+++ b/spec/features/admin/clusters/eks_spec.rb
@@ -13,7 +13,7 @@ RSpec.describe 'Instance-level AWS EKS Cluster', :js do
before do
visit admin_clusters_path
- click_link 'Add Kubernetes cluster'
+ click_link 'Integrate with a cluster certificate'
end
context 'when user creates a cluster on AWS EKS' do
diff --git a/spec/features/admin/dashboard_spec.rb b/spec/features/admin/dashboard_spec.rb
index 4ffa5e3be0b..acb8fb54e11 100644
--- a/spec/features/admin/dashboard_spec.rb
+++ b/spec/features/admin/dashboard_spec.rb
@@ -28,11 +28,9 @@ RSpec.describe 'admin visits dashboard' do
describe 'Users statistic' do
let_it_be(:users_statistics) { create(:users_statistics) }
+ let_it_be(:users_count_label) { Gitlab.ee? ? 'Billable users 71' : 'Active users 71' }
it 'shows correct amounts of users', :aggregate_failures do
- expected_active_users_text = Gitlab.ee? ? 'Active users (Billable users) 71' : 'Active users 71'
-
- sign_in(create(:admin))
visit admin_dashboard_stats_path
expect(page).to have_content('Users without a Group and Project 23')
@@ -42,9 +40,9 @@ RSpec.describe 'admin visits dashboard' do
expect(page).to have_content('Users with highest role Maintainer 6')
expect(page).to have_content('Users with highest role Owner 5')
expect(page).to have_content('Bots 2')
- expect(page).to have_content(expected_active_users_text)
expect(page).to have_content('Blocked users 7')
expect(page).to have_content('Total users 78')
+ expect(page).to have_content(users_count_label)
end
end
end
diff --git a/spec/features/alert_management/alert_details_spec.rb b/spec/features/alert_management/alert_details_spec.rb
new file mode 100644
index 00000000000..d190e4b6939
--- /dev/null
+++ b/spec/features/alert_management/alert_details_spec.rb
@@ -0,0 +1,86 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Alert details', :js do
+ let_it_be(:project) { create(:project) }
+ let_it_be(:developer) { create(:user) }
+ let_it_be(:alert) { create(:alert_management_alert, project: project, status: 'triggered', title: 'Alert') }
+
+ before_all do
+ project.add_developer(developer)
+ end
+
+ before do
+ sign_in(developer)
+
+ visit details_project_alert_management_path(project, alert)
+ wait_for_requests
+ end
+
+ context 'when a developer displays the alert' do
+ it 'shows the alert' do
+ page.within('.alert-management-details') do
+ expect(find('h2')).to have_content(alert.title)
+ end
+ end
+
+ it 'shows the alert tabs' do
+ page.within('.alert-management-details') do
+ alert_tabs = find('[data-testid="alertDetailsTabs"]')
+
+ expect(alert_tabs).to have_content('Alert details')
+ end
+ end
+
+ it 'shows the right sidebar mounted with correct widgets' do
+ page.within('.layout-page') do
+ sidebar = find('.right-sidebar')
+
+ expect(sidebar).to have_selector('.alert-status')
+ expect(sidebar).to have_selector('.alert-assignees')
+ expect(sidebar).to have_content('Triggered')
+ end
+ end
+
+ it 'updates the alert todo button from the right sidebar' do
+ expect(page).to have_selector('[data-testid="alert-todo-button"]')
+ todo_button = find('[data-testid="alert-todo-button"]')
+
+ expect(todo_button).to have_content('Add a To-Do')
+ find('[data-testid="alert-todo-button"]').click
+ wait_for_requests
+
+ expect(todo_button).to have_content('Mark as done')
+ end
+
+ it 'updates the alert status from the right sidebar' do
+ page.within('.alert-status') do
+ alert_status = find('[data-testid="status"]')
+
+ expect(alert_status).to have_content('Triggered')
+
+ find('.btn-link').click
+ find('.gl-new-dropdown-item', text: 'Acknowledged').click
+
+ wait_for_requests
+
+ expect(alert_status).to have_content('Acknowledged')
+ end
+ end
+
+ it 'updates the alert assignee from the right sidebar' do
+ page.within('.right-sidebar') do
+ alert_assignee = find('.alert-assignees')
+
+ expect(alert_assignee).to have_content('None - assign yourself')
+
+ find('[data-testid="unassigned-users"]').click
+
+ wait_for_requests
+
+ expect(alert_assignee).to have_content('Assignee Edit John Doe')
+ end
+ end
+ end
+end
diff --git a/spec/features/alert_management/alert_management_list_spec.rb b/spec/features/alert_management/alert_management_list_spec.rb
new file mode 100644
index 00000000000..c2514d80474
--- /dev/null
+++ b/spec/features/alert_management/alert_management_list_spec.rb
@@ -0,0 +1,58 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Alert Management index', :js do
+ let_it_be(:project) { create(:project) }
+ let_it_be(:developer) { create(:user) }
+ let_it_be(:alert) { create(:alert_management_alert, project: project, status: 'triggered') }
+
+ before_all do
+ project.add_developer(developer)
+ end
+
+ before do
+ sign_in(developer)
+
+ visit project_alert_management_index_path(project)
+ wait_for_requests
+ end
+
+ context 'when a developer displays the alert list and the alert service is not enabled' do
+ it 'shows the alert page title' do
+ expect(page).to have_content('Alerts')
+ end
+
+ it 'shows the empty state by default' do
+ expect(page).to have_content('Surface alerts in GitLab')
+ end
+
+ it 'does not show the filtered search' do
+ page.within('.layout-page') do
+ expect(page).not_to have_css('[data-testid="search-icon"]')
+ end
+ end
+
+ it 'does not show the alert table' do
+ expect(page).not_to have_selector('.gl-table')
+ end
+ end
+
+ context 'when a developer displays the alert list and the alert service is enabled' do
+ let_it_be(:alerts_service) { create(:alerts_service, project: project) }
+
+ it 'shows the alert page title' do
+ expect(page).to have_content('Alerts')
+ end
+
+ it 'shows the filtered search' do
+ page.within('.layout-page') do
+ expect(page).to have_css('[data-testid="search-icon"]')
+ end
+ end
+
+ it 'shows the alert table' do
+ expect(page).to have_selector('.gl-table')
+ end
+ end
+end
diff --git a/spec/features/alert_management/user_filters_alerts_by_status_spec.rb b/spec/features/alert_management/user_filters_alerts_by_status_spec.rb
new file mode 100644
index 00000000000..ee516418cd6
--- /dev/null
+++ b/spec/features/alert_management/user_filters_alerts_by_status_spec.rb
@@ -0,0 +1,56 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'User filters Alert Management table by status', :js do
+ let_it_be(:project) { create(:project) }
+ let_it_be(:developer) { create(:user) }
+ let_it_be(:alerts_service) { create(:alerts_service, project: project) }
+ let_it_be(:alert1, reload: true) { create(:alert_management_alert, :triggered, project: project) }
+ let_it_be(:alert2, reload: true) { create(:alert_management_alert, :acknowledged, project: project) }
+ let_it_be(:alert3, reload: true) { create(:alert_management_alert, :acknowledged, project: project) }
+
+ before_all do
+ project.add_developer(developer)
+ end
+
+ before do
+ sign_in(developer)
+
+ visit project_alert_management_index_path(project)
+ wait_for_requests
+ end
+
+ context 'when a developer displays the alert list and the alert service is enabled they can filter the table by an alert status' do
+ it 'shows the alert table items with alert status of Open by default' do
+ expect(page).to have_selector('.gl-table')
+ expect(page).to have_content('Open 3')
+ end
+
+ it 'shows the alert table items with alert status of Acknowledged' do
+ find('.gl-tab-nav-item', text: 'Acknowledged').click
+
+ expect(page).to have_selector('.gl-tab-nav-item-active')
+ expect(find('.gl-tab-nav-item-active')).to have_content('Acknowledged 2')
+ expect(all('.dropdown-menu-selectable').count).to be(2)
+ end
+
+ it 'shows the alert table items with alert status of Triggered' do
+ find('.gl-tab-nav-item', text: 'Triggered').click
+ wait_for_requests
+
+ expect(page).to have_selector('.gl-tab-nav-item-active')
+ expect(find('.gl-tab-nav-item-active')).to have_content('Triggered 1')
+ expect(all('.dropdown-menu-selectable').count).to be(1)
+ end
+
+ it 'shows the an empty table for a status with no alerts' do
+ find('.gl-tab-nav-item', text: 'Resolved').click
+ wait_for_requests
+
+ expect(page).to have_selector('.gl-tab-nav-item-active')
+ expect(find('.gl-tab-nav-item-active')).to have_content('Resolved 0')
+ expect(page).to have_content('No alerts to display.')
+ end
+ end
+end
diff --git a/spec/features/alert_management/user_searches_alerts_spec.rb b/spec/features/alert_management/user_searches_alerts_spec.rb
new file mode 100644
index 00000000000..568321de025
--- /dev/null
+++ b/spec/features/alert_management/user_searches_alerts_spec.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'User searches Alert Management alerts', :js do
+ let_it_be(:project) { create(:project) }
+ let_it_be(:developer) { create(:user) }
+ let_it_be(:alerts_service) { create(:alerts_service, project: project) }
+ let_it_be(:alert) { create(:alert_management_alert, project: project, status: 'triggered') }
+
+ before_all do
+ project.add_developer(developer)
+ end
+
+ before do
+ sign_in(developer)
+
+ visit project_alert_management_index_path(project)
+ wait_for_requests
+ end
+
+ context 'when a developer displays the alert list and the alert service is enabled they can search an alert' do
+ it 'shows the incident table with an incident for a valid search filter bar' do
+ expect(page).to have_selector('.filtered-search-wrapper')
+ expect(page).to have_selector('.gl-table')
+ expect(page).to have_css('[data-testid="severityField"]')
+ expect(all('tbody tr').count).to be(1)
+ expect(page).not_to have_selector('.empty-state')
+ end
+ end
+end
diff --git a/spec/features/alert_management/user_updates_alert_status_spec.rb b/spec/features/alert_management/user_updates_alert_status_spec.rb
new file mode 100644
index 00000000000..8974796662c
--- /dev/null
+++ b/spec/features/alert_management/user_updates_alert_status_spec.rb
@@ -0,0 +1,36 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'User updates Alert Management status', :js do
+ let_it_be(:project) { create(:project) }
+ let_it_be(:developer) { create(:user) }
+ let_it_be(:alerts_service) { create(:alerts_service, project: project) }
+ let_it_be(:alert) { create(:alert_management_alert, project: project, status: 'triggered') }
+
+ before_all do
+ project.add_developer(developer)
+ end
+
+ before do
+ sign_in(developer)
+
+ visit project_alert_management_index_path(project)
+ wait_for_requests
+ end
+
+ context 'when a developer+ displays the alerts list and the alert service is enabled they can update an alert status' do
+ it 'shows the alert table with an alert status dropdown' do
+ expect(page).to have_selector('.gl-table')
+ expect(find('.dropdown-menu-selectable')).to have_content('Triggered')
+ end
+
+ it 'updates the alert status' do
+ find('.dropdown-menu-selectable').click
+ find('.dropdown-item', text: 'Acknowledged').click
+ wait_for_requests
+
+ expect(find('.dropdown-menu-selectable')).to have_content('Acknowledged')
+ end
+ end
+end
diff --git a/spec/features/alert_management_spec.rb b/spec/features/alert_management_spec.rb
new file mode 100644
index 00000000000..2989f72e356
--- /dev/null
+++ b/spec/features/alert_management_spec.rb
@@ -0,0 +1,62 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Alert management', :js do
+ let_it_be(:project) { create(:project) }
+ let_it_be(:developer) { create(:user) }
+
+ before_all do
+ project.add_developer(developer)
+ end
+
+ context 'when visiting the alert details page' do
+ let!(:alert) { create(:alert_management_alert, :resolved, :with_fingerprint, title: 'dos-test', project: project, **options) }
+ let(:options) { {} }
+
+ before do
+ sign_in(user)
+ end
+
+ context 'when actor has permission to see the alert' do
+ let(:user) { developer }
+
+ it 'shows the alert details' do
+ visit(details_project_alert_management_path(project, alert))
+
+ within('.alert-management-details-table') do
+ expect(page).to have_content(alert.title)
+ end
+ end
+
+ context 'when alert belongs to an environment' do
+ let(:options) { { environment: environment } }
+ let!(:environment) { create(:environment, name: 'production', project: project) }
+
+ it 'shows the environment name' do
+ visit(details_project_alert_management_path(project, alert))
+
+ expect(page).to have_link(environment.name, href: project_environment_path(project, environment))
+ within('.alert-management-details-table') do
+ expect(page).to have_content(environment.name)
+ end
+ end
+
+ context 'when expose_environment_path_in_alert_details feature flag is disabled' do
+ before do
+ stub_feature_flags(expose_environment_path_in_alert_details: false)
+ end
+
+ it 'does not show the environment name' do
+ visit(details_project_alert_management_path(project, alert))
+
+ within('.alert-management-details-table') do
+ expect(page).to have_content(alert.title)
+ expect(page).not_to have_content(environment.name)
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/spec/features/boards/add_issues_modal_spec.rb b/spec/features/boards/add_issues_modal_spec.rb
index d432825e113..00efca5d3a8 100644
--- a/spec/features/boards/add_issues_modal_spec.rb
+++ b/spec/features/boards/add_issues_modal_spec.rb
@@ -79,7 +79,7 @@ RSpec.describe 'Issue Boards add issue modal', :js do
it 'loads issues' do
page.within('.add-issues-modal') do
- page.within('.nav-links') do
+ page.within('.gl-tabs') do
expect(page).to have_content('2')
end
@@ -103,7 +103,13 @@ RSpec.describe 'Issue Boards add issue modal', :js do
click_button 'Cancel'
end
- accept_confirm { first('.board-delete').click }
+ page.within(find('.board:nth-child(2)')) do
+ find('button[title="List settings"]').click
+ end
+
+ page.within(find('.js-board-settings-sidebar')) do
+ accept_confirm { find('[data-testid="remove-list"]').click }
+ end
click_button('Add issues')
@@ -146,7 +152,7 @@ RSpec.describe 'Issue Boards add issue modal', :js do
page.within('.add-issues-modal') do
first('.board-card .board-card-number').click
- page.within('.nav-links') do
+ page.within('.gl-tabs') do
expect(page).to have_content('Selected issues 1')
end
end
diff --git a/spec/features/boards/boards_spec.rb b/spec/features/boards/boards_spec.rb
index e36378bd34e..06ec4e05828 100644
--- a/spec/features/boards/boards_spec.rb
+++ b/spec/features/boards/boards_spec.rb
@@ -24,33 +24,11 @@ RSpec.describe 'Issue Boards', :js do
context 'no lists' do
before do
visit project_board_path(project, board)
- wait_for_requests
- expect(page).to have_selector('.board', count: 3)
- end
-
- it 'shows blank state' do
- expect(page).to have_content('Welcome to your Issue Board!')
- end
-
- it 'shows tooltip on add issues button' do
- button = page.find('.filter-dropdown-container button', text: 'Add issues')
-
- expect(button[:"data-original-title"]).to eq("Please add a list to your board first")
- end
-
- it 'hides the blank state when clicking nevermind button' do
- page.within(find('.board-blank-state')) do
- click_button("Nevermind, I'll use my own")
- end
- expect(page).to have_selector('.board', count: 2)
end
it 'creates default lists' do
lists = ['Open', 'To Do', 'Doing', 'Closed']
- page.within(find('.board-blank-state')) do
- click_button('Add default lists')
- end
wait_for_requests
expect(page).to have_selector('.board', count: 4)
@@ -181,9 +159,7 @@ RSpec.describe 'Issue Boards', :js do
end
it 'allows user to delete board' do
- page.within(find('.board:nth-child(2)')) do
- accept_confirm { find('.board-delete').click }
- end
+ remove_list
wait_for_requests
@@ -196,9 +172,7 @@ RSpec.describe 'Issue Boards', :js do
find('.js-new-board-list').click
- page.within(find('.board:nth-child(2)')) do
- accept_confirm { find('.board-delete').click }
- end
+ remove_list
wait_for_requests
@@ -692,4 +666,14 @@ RSpec.describe 'Issue Boards', :js do
click_button(link_text)
end
end
+
+ def remove_list
+ page.within(find('.board:nth-child(2)')) do
+ find('button[title="List settings"]').click
+ end
+
+ page.within(find('.js-board-settings-sidebar')) do
+ accept_confirm { find('[data-testid="remove-list"]').click }
+ end
+ end
end
diff --git a/spec/features/boards/sidebar_spec.rb b/spec/features/boards/sidebar_spec.rb
index 4b4cb444903..332c90df6d7 100644
--- a/spec/features/boards/sidebar_spec.rb
+++ b/spec/features/boards/sidebar_spec.rb
@@ -229,7 +229,7 @@ RSpec.describe 'Issue Boards', :js do
end
context 'time tracking' do
- let(:compare_meter_tooltip) { find('.time-tracking .time-tracking-content .compare-meter')['data-original-title'] }
+ let(:compare_meter_tooltip) { find('.time-tracking .time-tracking-content .compare-meter')['title'] }
before do
issue2.timelogs.create(time_spent: 14400, user: user)
diff --git a/spec/features/calendar_spec.rb b/spec/features/calendar_spec.rb
index 346f305f0d0..5f58fa420fb 100644
--- a/spec/features/calendar_spec.rb
+++ b/spec/features/calendar_spec.rb
@@ -180,7 +180,7 @@ RSpec.describe 'Contributions Calendar', :js do
before do
push_code_contribution
- Timecop.freeze(Date.yesterday) do
+ travel_to(Date.yesterday) do
Issues::CreateService.new(contributed_project, user, issue_params).execute
end
end
diff --git a/spec/features/clusters/cluster_detail_page_spec.rb b/spec/features/clusters/cluster_detail_page_spec.rb
index 4f7f62d00a5..31d6bcda9e8 100644
--- a/spec/features/clusters/cluster_detail_page_spec.rb
+++ b/spec/features/clusters/cluster_detail_page_spec.rb
@@ -87,6 +87,7 @@ RSpec.describe 'Clusterable > Show page' do
within('#advanced-settings-section') do
expect(page).to have_content('Google Kubernetes Engine')
expect(page).to have_content('Manage your Kubernetes cluster by visiting')
+ expect_common_advanced_options
end
end
end
@@ -117,6 +118,7 @@ RSpec.describe 'Clusterable > Show page' do
within('#advanced-settings-section') do
expect(page).not_to have_content('Google Kubernetes Engine')
expect(page).not_to have_content('Manage your Kubernetes cluster by visiting')
+ expect_common_advanced_options
end
end
end
@@ -176,4 +178,14 @@ RSpec.describe 'Clusterable > Show page' do
let(:cluster) { create(:cluster, :provided_by_user, :instance) }
end
end
+
+ private
+
+ def expect_common_advanced_options
+ aggregate_failures do
+ expect(page).to have_content('Cluster management project')
+ expect(page).to have_content('Clear cluster cache')
+ expect(page).to have_content('Remove Kubernetes cluster integration')
+ end
+ end
end
diff --git a/spec/features/commits_spec.rb b/spec/features/commits_spec.rb
index e66a40720da..97ee891dbb8 100644
--- a/spec/features/commits_spec.rb
+++ b/spec/features/commits_spec.rb
@@ -140,6 +140,7 @@ RSpec.describe 'Commits' do
context 'when accessing internal project with disallowed access', :js do
before do
+ stub_feature_flags(graphql_pipeline_header: false)
project.update(
visibility_level: Gitlab::VisibilityLevel::INTERNAL,
public_builds: false)
diff --git a/spec/features/dashboard/issuables_counter_spec.rb b/spec/features/dashboard/issuables_counter_spec.rb
index 7526a55a3c1..3cb7140d253 100644
--- a/spec/features/dashboard/issuables_counter_spec.rb
+++ b/spec/features/dashboard/issuables_counter_spec.rb
@@ -23,7 +23,7 @@ RSpec.describe 'Navigation bar counter', :use_clean_rails_memory_store_caching d
user.invalidate_cache_counts
- Timecop.travel(3.minutes.from_now) do
+ travel_to(3.minutes.from_now) do
visit issues_path
expect_counters('issues', '0')
@@ -39,7 +39,7 @@ RSpec.describe 'Navigation bar counter', :use_clean_rails_memory_store_caching d
user.invalidate_cache_counts
- Timecop.travel(3.minutes.from_now) do
+ travel_to(3.minutes.from_now) do
visit merge_requests_path
expect_counters('merge_requests', '0')
diff --git a/spec/features/dashboard/merge_requests_spec.rb b/spec/features/dashboard/merge_requests_spec.rb
index 5331b5559d8..952a78ec79a 100644
--- a/spec/features/dashboard/merge_requests_spec.rb
+++ b/spec/features/dashboard/merge_requests_spec.rb
@@ -19,6 +19,12 @@ RSpec.describe 'Dashboard Merge Requests' do
sign_in(current_user)
end
+ it 'disables target branch filter' do
+ visit merge_requests_dashboard_path
+
+ expect(page).not_to have_selector('#js-dropdown-target-branch', visible: false)
+ end
+
context 'new merge request dropdown' do
let(:project_with_disabled_merge_requests) { create(:project, :merge_requests_disabled) }
diff --git a/spec/features/dashboard/todos/todos_filtering_spec.rb b/spec/features/dashboard/todos/todos_filtering_spec.rb
index f60b07c976e..b1464af4194 100644
--- a/spec/features/dashboard/todos/todos_filtering_spec.rb
+++ b/spec/features/dashboard/todos/todos_filtering_spec.rb
@@ -130,6 +130,7 @@ RSpec.describe 'Dashboard > User filters todos', :js do
before do
create(:todo, :build_failed, user: user_1, author: user_2, project: project_1)
create(:todo, :marked, user: user_1, author: user_2, project: project_1, target: issue1)
+ create(:todo, :review_requested, user: user_1, author: user_2, project: project_1, target: issue1)
end
it 'filters by Assigned' do
@@ -138,6 +139,12 @@ RSpec.describe 'Dashboard > User filters todos', :js do
expect_to_see_action(:assigned)
end
+ it 'filters by Review Requested' do
+ filter_action('Review requested')
+
+ expect_to_see_action(:review_requested)
+ end
+
it 'filters by Mentioned' do
filter_action('Mentioned')
@@ -168,6 +175,7 @@ RSpec.describe 'Dashboard > User filters todos', :js do
def expect_to_see_action(action_name)
action_names = {
assigned: ' assigned you ',
+ review_requested: ' requested a review of ',
mentioned: ' mentioned ',
marked: ' added a todo for ',
build_failed: ' build failed for '
diff --git a/spec/features/dashboard/todos/todos_spec.rb b/spec/features/dashboard/todos/todos_spec.rb
index cf773d2caed..0b4fed55f11 100644
--- a/spec/features/dashboard/todos/todos_spec.rb
+++ b/spec/features/dashboard/todos/todos_spec.rb
@@ -197,6 +197,21 @@ RSpec.describe 'Dashboard Todos' do
end
end
end
+
+ context 'review request todo' do
+ let(:merge_request) { create(:merge_request, title: "Fixes issue") }
+
+ before do
+ create(:todo, :review_requested, user: user, project: project, target: merge_request, author: user)
+ visit dashboard_todos_path
+ end
+
+ it 'shows you set yourself as an reviewer message' do
+ page.within('.js-todos-all') do
+ expect(page).to have_content("You requested a review of merge request #{merge_request.to_reference} \"Fixes issue\" at #{project.namespace.owner_name} / #{project.name} from yourself")
+ end
+ end
+ end
end
context 'User has done todos', :js do
@@ -213,7 +228,7 @@ RSpec.describe 'Dashboard Todos' do
describe 'restoring the todo' do
before do
within first('.todo') do
- click_link 'Add a To Do'
+ click_link 'Add a to do'
end
end
@@ -228,7 +243,7 @@ RSpec.describe 'Dashboard Todos' do
end
end
- context 'User has Todos with labels spanning multiple projects' do
+ context 'User has to dos with labels spanning multiple projects' do
before do
label1 = create(:label, project: project)
note1 = create(:note_on_issue, note: "Hello #{label1.to_reference(format: :name)}", noteable_id: issue.id, noteable_type: 'Issue', project: issue.project)
diff --git a/spec/features/discussion_comments/snippets_spec.rb b/spec/features/discussion_comments/snippets_spec.rb
index 50201bbdb21..b2d3fbf4b5d 100644
--- a/spec/features/discussion_comments/snippets_spec.rb
+++ b/spec/features/discussion_comments/snippets_spec.rb
@@ -8,7 +8,6 @@ RSpec.describe 'Thread Comments Snippet', :js do
let_it_be(:snippet) { create(:project_snippet, :private, :repository, project: project, author: user) }
before do
- stub_feature_flags(snippets_vue: false)
project.add_maintainer(user)
sign_in(user)
diff --git a/spec/features/expand_collapse_diffs_spec.rb b/spec/features/expand_collapse_diffs_spec.rb
index e705f2916da..49343cc7a57 100644
--- a/spec/features/expand_collapse_diffs_spec.rb
+++ b/spec/features/expand_collapse_diffs_spec.rb
@@ -7,6 +7,7 @@ RSpec.describe 'Expand and collapse diffs', :js do
let(:project) { create(:project, :repository) }
before do
+ stub_feature_flags(increased_diff_limits: false)
sign_in(create(:admin))
# Ensure that undiffable.md is in .gitattributes
diff --git a/spec/features/file_uploads/maven_package_spec.rb b/spec/features/file_uploads/maven_package_spec.rb
index c873a0e9a36..e87eec58618 100644
--- a/spec/features/file_uploads/maven_package_spec.rb
+++ b/spec/features/file_uploads/maven_package_spec.rb
@@ -25,5 +25,31 @@ RSpec.describe 'Upload a maven package', :api, :js do
it { expect(subject.code).to eq(200) }
end
+ RSpec.shared_examples 'for a maven sha1' do
+ let(:dummy_package) { double(Packages::Package) }
+ let(:api_path) { "/projects/#{project.id}/packages/maven/com/example/my-app/1.0/my-app-1.0-20180724.124855-1.jar.sha1" }
+
+ before do
+ # The sha verification done by the maven api is between:
+ # - the sha256 set by workhorse
+ # - the sha256 of the sha1 of the uploaded package file
+ # We're going to send `file` for the sha1 and stub the sha1 of the package file so that
+ # both sha256 being the same
+ expect(::Packages::PackageFileFinder).to receive(:new).and_return(double(execute!: dummy_package))
+ expect(dummy_package).to receive(:file_sha1).and_return(File.read(file.path))
+ end
+
+ it { expect(subject.code).to eq(204) }
+ end
+
+ RSpec.shared_examples 'for a maven md5' do
+ let(:api_path) { "/projects/#{project.id}/packages/maven/com/example/my-app/1.0/my-app-1.0-20180724.124855-1.jar.md5" }
+ let(:file) { StringIO.new('dummy_package') }
+
+ it { expect(subject.code).to eq(200) }
+ end
+
it_behaves_like 'handling file uploads', 'for a maven package'
+ it_behaves_like 'handling file uploads', 'for a maven sha1'
+ it_behaves_like 'handling file uploads', 'for a maven md5'
end
diff --git a/spec/features/groups/clusters/eks_spec.rb b/spec/features/groups/clusters/eks_spec.rb
index 5a62741250a..c361c502cbb 100644
--- a/spec/features/groups/clusters/eks_spec.rb
+++ b/spec/features/groups/clusters/eks_spec.rb
@@ -19,7 +19,7 @@ RSpec.describe 'Group AWS EKS Cluster', :js do
before do
visit group_clusters_path(group)
- click_link 'Add Kubernetes cluster'
+ click_link 'Integrate with a cluster certificate'
end
context 'when user creates a cluster on AWS EKS' do
diff --git a/spec/features/groups/clusters/user_spec.rb b/spec/features/groups/clusters/user_spec.rb
index 90253451d6b..97f8864aab2 100644
--- a/spec/features/groups/clusters/user_spec.rb
+++ b/spec/features/groups/clusters/user_spec.rb
@@ -25,7 +25,7 @@ RSpec.describe 'User Cluster', :js do
before do
visit group_clusters_path(group)
- click_link 'Add Kubernetes cluster'
+ click_link 'Integrate with a cluster certificate'
click_link 'Connect existing cluster'
end
@@ -66,6 +66,10 @@ RSpec.describe 'User Cluster', :js do
expect(page.find_field('cluster[platform_kubernetes_attributes][authorization_type]', disabled: true)).to be_checked
end
end
+
+ it 'user sees namespace per environment is enabled by default' do
+ expect(page).to have_checked_field('Namespace per environment')
+ end
end
context 'when user filled form with invalid parameters' do
@@ -125,7 +129,7 @@ RSpec.describe 'User Cluster', :js do
it 'user sees creation form with the successful message' do
expect(page).to have_content('Kubernetes cluster integration was successfully removed.')
- expect(page).to have_link('Add Kubernetes cluster')
+ expect(page).to have_link('Integrate with a cluster certificate')
end
end
end
diff --git a/spec/features/groups/members/leave_group_spec.rb b/spec/features/groups/members/leave_group_spec.rb
index 9eb5cc15c5e..32acf7edd2a 100644
--- a/spec/features/groups/members/leave_group_spec.rb
+++ b/spec/features/groups/members/leave_group_spec.rb
@@ -70,7 +70,7 @@ RSpec.describe 'Groups > Members > Leave group' do
visit group_group_members_path(group)
- expect(find(:css, '.project-members-page li', text: user.name)).not_to have_selector(:css, 'a.btn-remove')
+ expect(find(:css, '.project-members-page li', text: user.name)).to have_no_selector(:css, 'a.btn-danger')
end
it 'owner can not leave the group by url param if they are the last owner', :js do
diff --git a/spec/features/groups/members/manage_groups_spec.rb b/spec/features/groups/members/manage_groups_spec.rb
index e3bbbd4d73b..33caa3af36d 100644
--- a/spec/features/groups/members/manage_groups_spec.rb
+++ b/spec/features/groups/members/manage_groups_spec.rb
@@ -6,62 +6,115 @@ RSpec.describe 'Groups > Members > Manage groups', :js do
include Select2Helper
include Spec::Support::Helpers::Features::ListRowsHelpers
- let(:user) { create(:user) }
- let(:shared_with_group) { create(:group) }
- let(:shared_group) { create(:group) }
+ let_it_be(:user) { create(:user) }
before do
stub_feature_flags(vue_group_members_list: false)
- shared_group.add_owner(user)
sign_in(user)
end
- it 'add group to group' do
- visit group_group_members_path(shared_group)
+ context 'when group link does not exist' do
+ let_it_be(:group) { create(:group) }
+ let_it_be(:group_to_add) { create(:group) }
- add_group(shared_with_group.id, 'Reporter')
+ before do
+ group.add_owner(user)
+ visit group_group_members_path(group)
+ end
- click_groups_tab
+ it 'add group to group' do
+ add_group(group_to_add.id, 'Reporter')
- page.within(first_row) do
- expect(page).to have_content(shared_with_group.name)
- expect(page).to have_content('Reporter')
+ click_groups_tab
+
+ page.within(first_row) do
+ expect(page).to have_content(group_to_add.name)
+ expect(page).to have_content('Reporter')
+ end
end
end
- it 'remove group from group' do
- create(:group_group_link, shared_group: shared_group,
- shared_with_group: shared_with_group, group_access: ::Gitlab::Access::DEVELOPER)
+ context 'when group link exists' do
+ let_it_be(:shared_with_group) { create(:group) }
+ let_it_be(:shared_group) { create(:group) }
- visit group_group_members_path(shared_group)
+ let(:additional_link_attrs) { {} }
- click_groups_tab
+ let_it_be(:group_link, refind: true) do
+ create(
+ :group_group_link,
+ shared_group: shared_group,
+ shared_with_group: shared_with_group,
+ group_access: ::Gitlab::Access::DEVELOPER
+ )
+ end
- expect(page).to have_content(shared_with_group.name)
+ before do
+ travel_to Time.now.utc.beginning_of_day
+ group_link.update!(additional_link_attrs)
- accept_confirm do
- find(:css, '#tab-groups li', text: shared_with_group.name).find(:css, 'a.btn-remove').click
+ shared_group.add_owner(user)
+ visit group_group_members_path(shared_group)
end
- expect(page).not_to have_content(shared_with_group.name)
- end
+ it 'remove group from group' do
+ click_groups_tab
+
+ expect(page).to have_content(shared_with_group.name)
+
+ accept_confirm do
+ find(:css, '#tab-groups li', text: shared_with_group.name).find(:css, 'a.btn-danger').click
+ end
+
+ expect(page).not_to have_content(shared_with_group.name)
+ end
- it 'update group to owner level' do
- create(:group_group_link, shared_group: shared_group,
- shared_with_group: shared_with_group, group_access: ::Gitlab::Access::DEVELOPER)
+ it 'update group to owner level' do
+ click_groups_tab
- visit group_group_members_path(shared_group)
+ page.within(first_row) do
+ click_button('Developer')
+ click_link('Maintainer')
- click_groups_tab
+ wait_for_requests
- page.within(first_row) do
- click_button('Developer')
- click_link('Maintainer')
+ expect(page).to have_button('Maintainer')
+ end
+ end
+
+ it 'updates expiry date' do
+ click_groups_tab
+
+ expires_at_field = "member_expires_at_#{shared_with_group.id}"
+ fill_in "member_expires_at_#{shared_with_group.id}", with: 3.days.from_now.to_date
+ find_field(expires_at_field).native.send_keys :enter
wait_for_requests
- expect(page).to have_button('Maintainer')
+ page.within(find('li.group_member')) do
+ expect(page).to have_content('Expires in 3 days')
+ end
+ end
+
+ context 'when expiry date is set' do
+ let(:additional_link_attrs) { { expires_at: 3.days.from_now.to_date } }
+
+ it 'clears expiry date' do
+ click_groups_tab
+
+ page.within(find('li.group_member')) do
+ expect(page).to have_content('Expires in 3 days')
+
+ page.within(find('.js-edit-member-form')) do
+ find('.js-clear-input').click
+ end
+
+ wait_for_requests
+
+ expect(page).not_to have_content('Expires in')
+ end
+ end
end
end
diff --git a/spec/features/groups/members/master_adds_member_with_expiration_date_spec.rb b/spec/features/groups/members/master_adds_member_with_expiration_date_spec.rb
index d94cc85f411..dd708c243a8 100644
--- a/spec/features/groups/members/master_adds_member_with_expiration_date_spec.rb
+++ b/spec/features/groups/members/master_adds_member_with_expiration_date_spec.rb
@@ -6,65 +6,66 @@ RSpec.describe 'Groups > Members > Owner adds member with expiration date', :js
include Select2Helper
include ActiveSupport::Testing::TimeHelpers
- let(:user1) { create(:user, name: 'John Doe') }
- let!(:new_member) { create(:user, name: 'Mary Jane') }
- let(:group) { create(:group) }
+ let_it_be(:user1) { create(:user, name: 'John Doe') }
+ let_it_be(:group) { create(:group) }
+ let(:new_member) { create(:user, name: 'Mary Jane') }
before do
stub_feature_flags(vue_group_members_list: false)
+ travel_to Time.now.utc.beginning_of_day
+
group.add_owner(user1)
sign_in(user1)
end
it 'expiration date is displayed in the members list' do
- travel_to Time.zone.parse('2016-08-06 08:00') do
- date = 4.days.from_now
- visit group_group_members_path(group)
-
- page.within '.invite-users-form' do
- select2(new_member.id, from: '#user_ids', multiple: true)
- fill_in 'expires_at', with: date.to_s(:medium) + "\n"
- click_on 'Invite'
- end
-
- page.within "#group_member_#{group_member_id(new_member)}" do
- expect(page).to have_content('Expires in 4 days')
- end
+ visit group_group_members_path(group)
+
+ page.within '.invite-users-form' do
+ select2(new_member.id, from: '#user_ids', multiple: true)
+
+ fill_in 'expires_at', with: 3.days.from_now.to_date
+ find_field('expires_at').native.send_keys :enter
+
+ click_on 'Invite'
+ end
+
+ page.within "#group_member_#{group_member_id}" do
+ expect(page).to have_content('Expires in 3 days')
end
end
- it 'change expiration date' do
- travel_to Time.zone.parse('2016-08-06 08:00') do
- date = 3.days.from_now
- group.add_developer(new_member)
+ it 'changes expiration date' do
+ group.add_developer(new_member)
+ visit group_group_members_path(group)
+
+ page.within "#group_member_#{group_member_id}" do
+ fill_in 'Expiration date', with: 3.days.from_now.to_date
+ find_field('Expiration date').native.send_keys :enter
- visit group_group_members_path(group)
+ wait_for_requests
- page.within "#group_member_#{group_member_id(new_member)}" do
- find('.js-access-expiration-date').set date.to_s(:medium) + "\n"
- wait_for_requests
- expect(page).to have_content('Expires in 3 days')
- end
+ expect(page).to have_content('Expires in 3 days')
end
end
- it 'remove expiration date' do
- travel_to Time.zone.parse('2016-08-06 08:00') do
- date = 3.days.from_now
- group_member = create(:group_member, :developer, user: new_member, group: group, expires_at: date.to_s(:medium))
+ it 'clears expiration date' do
+ create(:group_member, :developer, user: new_member, group: group, expires_at: 3.days.from_now.to_date)
+ visit group_group_members_path(group)
+
+ page.within "#group_member_#{group_member_id}" do
+ expect(page).to have_content('Expires in 3 days')
+
+ find('.js-clear-input').click
- visit group_group_members_path(group)
+ wait_for_requests
- page.within "#group_member_#{group_member.id}" do
- find('.js-clear-input').click
- wait_for_requests
- expect(page).not_to have_content('Expires in 3 days')
- end
+ expect(page).not_to have_content('Expires in')
end
end
- def group_member_id(user)
+ def group_member_id
group.members.find_by(user_id: new_member).id
end
end
diff --git a/spec/features/groups/navbar_spec.rb b/spec/features/groups/navbar_spec.rb
index 60f1c404e78..e81f2370d10 100644
--- a/spec/features/groups/navbar_spec.rb
+++ b/spec/features/groups/navbar_spec.rb
@@ -72,4 +72,12 @@ RSpec.describe 'Group navbar' do
it_behaves_like 'verified navigation bar'
end
+
+ context 'when invite team members is not available' do
+ it 'does not display the js-invite-members-trigger' do
+ visit group_path(group)
+
+ expect(page).not_to have_selector('.js-invite-members-trigger')
+ end
+ end
end
diff --git a/spec/features/groups/packages_spec.rb b/spec/features/groups/packages_spec.rb
index d81e4aa70cf..60e0c08b3d4 100644
--- a/spec/features/groups/packages_spec.rb
+++ b/spec/features/groups/packages_spec.rb
@@ -48,7 +48,7 @@ RSpec.describe 'Group Packages' do
it 'allows you to navigate to the project page' do
page.within('[data-qa-selector="packages-table"]') do
- click_link project.name
+ find('[data-qa-selector="package-path"]', text: project.name).click
end
expect(page).to have_current_path(project_path(project))
diff --git a/spec/features/groups/show_spec.rb b/spec/features/groups/show_spec.rb
index ec30f34199d..304573ecd6e 100644
--- a/spec/features/groups/show_spec.rb
+++ b/spec/features/groups/show_spec.rb
@@ -184,4 +184,17 @@ RSpec.describe 'Group show page' do
expect(page).to have_selector('.notifications-btn.disabled', visible: true)
end
end
+
+ context 'page og:description' do
+ let(:group) { create(:group, description: '**Lorem** _ipsum_ dolor sit [amet](https://example.com)') }
+ let(:maintainer) { create(:user) }
+
+ before do
+ group.add_maintainer(maintainer)
+ sign_in(maintainer)
+ visit path
+ end
+
+ it_behaves_like 'page meta description', 'Lorem ipsum dolor sit amet'
+ end
end
diff --git a/spec/features/incidents/incident_details_spec.rb b/spec/features/incidents/incident_details_spec.rb
new file mode 100644
index 00000000000..3ec7717b649
--- /dev/null
+++ b/spec/features/incidents/incident_details_spec.rb
@@ -0,0 +1,52 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Incident details', :js do
+ let_it_be(:project) { create(:project) }
+ let_it_be(:developer) { create(:user) }
+ let_it_be(:incident) { create(:incident, project: project, author: developer, description: 'description') }
+
+ before_all do
+ project.add_developer(developer)
+ end
+
+ before do
+ sign_in(developer)
+
+ visit project_issues_incident_path(project, incident)
+ wait_for_requests
+ end
+
+ context 'when a developer+ displays the incident' do
+ it 'shows the incident' do
+ page.within('.issuable-details') do
+ expect(find('h2')).to have_content(incident.title)
+ end
+ end
+
+ it 'does not show design management' do
+ expect(page).not_to have_selector('.js-design-management')
+ end
+
+ it 'shows the incident tabs' do
+ page.within('.issuable-details') do
+ incident_tabs = find('[data-testid="incident-tabs"]')
+
+ expect(find('h2')).to have_content(incident.title)
+ expect(incident_tabs).to have_content('Summary')
+ expect(incident_tabs).to have_content(incident.description)
+ end
+ end
+
+ it 'shows the right sidebar mounted with type issue' do
+ page.within('.layout-page') do
+ sidebar = find('.right-sidebar')
+
+ expect(page).to have_selector('.right-sidebar[data-issuable-type="issue"]')
+ expect(sidebar).to have_selector('.incident-severity')
+ expect(sidebar).not_to have_selector('.milestone')
+ end
+ end
+ end
+end
diff --git a/spec/features/incidents/incidents_list_spec.rb b/spec/features/incidents/incidents_list_spec.rb
new file mode 100644
index 00000000000..c65c83b2804
--- /dev/null
+++ b/spec/features/incidents/incidents_list_spec.rb
@@ -0,0 +1,38 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Incident Management index', :js do
+ let_it_be(:project) { create(:project) }
+ let_it_be(:developer) { create(:user) }
+ let_it_be(:incident) { create(:incident, project: project) }
+
+ before_all do
+ project.add_developer(developer)
+ end
+
+ before do
+ sign_in(developer)
+
+ visit project_incidents_path(project)
+ wait_for_requests
+ end
+
+ context 'when a developer displays the incident list' do
+ it 'shows the status tabs' do
+ expect(page).to have_selector('.gl-tabs')
+ end
+
+ it 'shows the filtered search' do
+ expect(page).to have_selector('.filtered-search-wrapper')
+ end
+
+ it 'shows the alert table' do
+ expect(page).to have_selector('.gl-table')
+ end
+
+ it 'alert page title' do
+ expect(page).to have_content('Incidents')
+ end
+ end
+end
diff --git a/spec/features/incidents/user_creates_new_incident_spec.rb b/spec/features/incidents/user_creates_new_incident_spec.rb
new file mode 100644
index 00000000000..99a137b5852
--- /dev/null
+++ b/spec/features/incidents/user_creates_new_incident_spec.rb
@@ -0,0 +1,55 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Incident Management index', :js do
+ let_it_be(:project) { create(:project) }
+ let_it_be(:developer) { create(:user) }
+ let_it_be(:guest) { create(:user) }
+ let_it_be(:incident) { create(:incident, project: project) }
+
+ before_all do
+ project.add_developer(developer)
+ project.add_guest(guest)
+ end
+
+ shared_examples 'create incident form' do
+ it 'shows the create new issue button' do
+ expect(page).to have_selector('.create-incident-button')
+ end
+
+ it 'when clicked shows the create issue page with the Incident type pre-selected' do
+ find('.create-incident-button').click
+ wait_for_all_requests
+
+ expect(page).to have_selector('.dropdown-menu-toggle')
+ expect(page).to have_selector('.js-issuable-type-filter-dropdown-wrap')
+
+ page.within('.js-issuable-type-filter-dropdown-wrap') do
+ expect(page).to have_content('Incident')
+ end
+ end
+ end
+
+ context 'when a developer displays the incident list' do
+ before do
+ sign_in(developer)
+
+ visit project_incidents_path(project)
+ wait_for_all_requests
+ end
+
+ it_behaves_like 'create incident form'
+ end
+
+ context 'when a guest displays the incident list' do
+ before do
+ sign_in(guest)
+
+ visit project_incidents_path(project)
+ wait_for_all_requests
+ end
+
+ it_behaves_like 'create incident form'
+ end
+end
diff --git a/spec/features/incidents/user_filters_incidents_by_status_spec.rb b/spec/features/incidents/user_filters_incidents_by_status_spec.rb
new file mode 100644
index 00000000000..661c737141b
--- /dev/null
+++ b/spec/features/incidents/user_filters_incidents_by_status_spec.rb
@@ -0,0 +1,59 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'User filters Incident Management table by status', :js do
+ let_it_be(:project) { create(:project) }
+ let_it_be(:developer) { create(:user) }
+
+ before_all do
+ project.add_developer(developer)
+
+ create_list(:incident, 2, project: project, state: 'opened')
+ create(:incident, project: project, state: 'closed')
+ end
+
+ before do
+ sign_in(developer)
+
+ visit project_incidents_path(project)
+ wait_for_requests
+ end
+
+ context 'when a developer displays the incident list they can filter the table by an incident status' do
+ def the_page_shows_the_nav_text_with_correct_count
+ expect(page).to have_selector('.gl-table')
+ expect(page).to have_content('All 3')
+ expect(page).to have_content('Open 2')
+ expect(page).to have_content('Closed 1')
+ end
+
+ it 'shows the incident table items with incident status of Open by default' do
+ expect(find('.gl-tab-nav-item-active')).to have_content('Open 2')
+ expect(all('tbody tr').count).to be(2)
+
+ the_page_shows_the_nav_text_with_correct_count
+ end
+
+ it 'shows the incident table items with incident status of Closed' do
+ find('.gl-tab-nav-item', text: 'Closed').click
+ wait_for_requests
+
+ expect(find('.gl-tab-nav-item-active')).to have_content('Closed 1')
+ expect(all('tbody tr').count).to be(1)
+
+ the_page_shows_the_nav_text_with_correct_count
+ end
+
+ it 'shows the incident table items with all status' do
+ find('.gl-tab-nav-item', text: 'All').click
+ wait_for_requests
+
+ expect(find('.gl-tab-nav-item-active')).to have_content('All 3')
+ expect(all('[data-testid="incident-assignees"]').count).to be(3)
+ expect(all('tbody tr').count).to be(3)
+
+ the_page_shows_the_nav_text_with_correct_count
+ end
+ end
+end
diff --git a/spec/features/incidents/user_searches_incidents_spec.rb b/spec/features/incidents/user_searches_incidents_spec.rb
new file mode 100644
index 00000000000..b8e3ff534c3
--- /dev/null
+++ b/spec/features/incidents/user_searches_incidents_spec.rb
@@ -0,0 +1,30 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'User searches Incident Management incidents', :js do
+ let_it_be(:project) { create(:project) }
+ let_it_be(:developer) { create(:user) }
+ let_it_be(:incident) { create(:incident, project: project) }
+
+ before_all do
+ project.add_developer(developer)
+ end
+
+ before do
+ sign_in(developer)
+
+ visit project_incidents_path(project)
+ wait_for_requests
+ end
+
+ context 'when a developer displays the incident list they can search for an incident' do
+ it 'shows the incident table with an incident for a valid search filter bar' do
+ expect(page).to have_selector('.filtered-search-wrapper')
+ expect(page).to have_selector('.gl-table')
+ expect(page).to have_selector('.incident-severity')
+ expect(all('tbody tr').count).to be(1)
+ expect(page).not_to have_selector('.empty-state')
+ end
+ end
+end
diff --git a/spec/features/invites_spec.rb b/spec/features/invites_spec.rb
index 3954de56eea..8ccaf82536a 100644
--- a/spec/features/invites_spec.rb
+++ b/spec/features/invites_spec.rb
@@ -23,7 +23,8 @@ RSpec.describe 'Group or Project invitations', :aggregate_failures do
end
def fill_in_sign_up_form(new_user)
- fill_in 'new_user_name', with: new_user.name
+ fill_in 'new_user_first_name', with: new_user.first_name
+ fill_in 'new_user_last_name', with: new_user.last_name
fill_in 'new_user_username', with: new_user.username
fill_in 'new_user_email', with: new_user.email
fill_in 'new_user_password', with: new_user.password
@@ -81,10 +82,10 @@ RSpec.describe 'Group or Project invitations', :aggregate_failures do
end
end
- context 'when inviting a user using their email address' do
+ context 'when inviting a user' do
let(:new_user) { build_stubbed(:user) }
let(:invite_email) { new_user.email }
- let(:group_invite) { create(:group_member, :invited, group: group, invite_email: invite_email) }
+ let(:group_invite) { create(:group_member, :invited, group: group, invite_email: invite_email, created_by: owner) }
let!(:project_invite) { create(:project_member, :invited, project: project, invite_email: invite_email) }
context 'when user has not signed in yet' do
@@ -210,30 +211,43 @@ RSpec.describe 'Group or Project invitations', :aggregate_failures do
context 'when declining the invitation' do
let(:send_email_confirmation) { true }
- context 'when signed in' do
- before do
- sign_in(user)
- visit invite_path(group_invite.raw_invite_token)
+ context 'as an existing user' do
+ let(:group_invite) { create(:group_member, user: user, group: group, created_by: owner) }
+
+ context 'when signed in' do
+ before do
+ sign_in(user)
+ visit decline_invite_path(group_invite.raw_invite_token)
+ end
+
+ it 'declines application and redirects to dashboard' do
+ expect(current_path).to eq(dashboard_projects_path)
+ expect(page).to have_content('You have declined the invitation to join group Owned.')
+ expect { group_invite.reload }.to raise_error ActiveRecord::RecordNotFound
+ end
end
- it 'declines application and redirects to dashboard' do
- page.click_link 'Decline'
+ context 'when signed out' do
+ before do
+ visit decline_invite_path(group_invite.raw_invite_token)
+ end
- expect(current_path).to eq(dashboard_projects_path)
- expect(page).to have_content('You have declined the invitation to join group Owned.')
- expect { group_invite.reload }.to raise_error ActiveRecord::RecordNotFound
+ it 'declines application and redirects to sign in page' do
+ expect(current_path).to eq(new_user_session_path)
+ expect(page).to have_content('You have declined the invitation to join group Owned.')
+ expect { group_invite.reload }.to raise_error ActiveRecord::RecordNotFound
+ end
end
end
- context 'when signed out' do
+ context 'as a non-existing user' do
before do
visit decline_invite_path(group_invite.raw_invite_token)
end
- it 'declines application and redirects to sign in page' do
- expect(current_path).to eq(new_user_session_path)
-
- expect(page).to have_content('You have declined the invitation to join group Owned.')
+ it 'declines application and shows a decline page' do
+ expect(current_path).to eq(decline_invite_path(group_invite.raw_invite_token))
+ expect(page).to have_content('You successfully declined the invitation')
expect { group_invite.reload }.to raise_error ActiveRecord::RecordNotFound
end
end
diff --git a/spec/features/issuables/close_reopen_report_toggle_spec.rb b/spec/features/issuables/close_reopen_report_toggle_spec.rb
index 5ea89a7984f..6e99cfb3293 100644
--- a/spec/features/issuables/close_reopen_report_toggle_spec.rb
+++ b/spec/features/issuables/close_reopen_report_toggle_spec.rb
@@ -23,7 +23,15 @@ RSpec.describe 'Issuables Close/Reopen/Report toggle' do
expect(container).to have_content("Close #{human_model_name}")
expect(container).to have_content('Report abuse')
expect(container).to have_content("Report #{human_model_name.pluralize} that are abusive, inappropriate or spam.")
- expect(container).to have_selector('.close-item.droplab-item-selected')
+
+ if issuable.is_a?(MergeRequest)
+ page.within('.js-issuable-close-dropdown') do
+ expect(page).to have_link('Close merge request')
+ end
+ else
+ expect(container).to have_selector('.close-item.droplab-item-selected')
+ end
+
expect(container).to have_selector('.report-item')
expect(container).not_to have_selector('.report-item.droplab-item-selected')
expect(container).not_to have_selector('.reopen-item')
@@ -123,7 +131,7 @@ RSpec.describe 'Issuables Close/Reopen/Report toggle' do
it 'shows only the `Edit` button' do
expect(page).to have_link('Edit')
- expect(page).not_to have_link('Report abuse')
+ expect(page).to have_link('Report abuse')
expect(page).not_to have_button('Close merge request')
expect(page).not_to have_button('Reopen merge request')
end
diff --git a/spec/features/issuables/issuable_list_spec.rb b/spec/features/issuables/issuable_list_spec.rb
index b1ffaaa7c7e..3f00bdc478d 100644
--- a/spec/features/issuables/issuable_list_spec.rb
+++ b/spec/features/issuables/issuable_list_spec.rb
@@ -48,6 +48,14 @@ RSpec.describe 'issuable list', :js do
end
end
+ it 'displays a warning if counting the number of issues times out' do
+ allow_any_instance_of(IssuesFinder).to receive(:count_by_state).and_raise(ActiveRecord::QueryCanceled)
+
+ visit_issuable_list(:issue)
+
+ expect(page).to have_text('Open ? Closed ? All ?')
+ end
+
it "counts merge requests closing issues icons for each issue" do
visit_issuable_list(:issue)
diff --git a/spec/features/issuables/markdown_references/internal_references_spec.rb b/spec/features/issuables/markdown_references/internal_references_spec.rb
index aceaea8d2ed..07d4271eed7 100644
--- a/spec/features/issuables/markdown_references/internal_references_spec.rb
+++ b/spec/features/issuables/markdown_references/internal_references_spec.rb
@@ -25,7 +25,7 @@ RSpec.describe "Internal references", :js do
add_note("##{public_project_issue.to_reference(private_project)}")
end
- context "when user doesn't have access to private project" do
+ context "when user doesn't have access to private project", quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/257832' do
before do
sign_in(public_project_user)
@@ -52,7 +52,7 @@ RSpec.describe "Internal references", :js do
visit(project_issue_path(public_project, public_project_issue))
end
- it "doesn't show any references" do
+ it "doesn't show any references", quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/257832' do
page.within(".issue-details") do
expect(page).not_to have_content("#merge-requests .merge-requests-title")
end
@@ -94,7 +94,7 @@ RSpec.describe "Internal references", :js do
add_note("##{public_project_merge_request.to_reference(private_project)}")
end
- context "when user doesn't have access to private project" do
+ context "when user doesn't have access to private project", quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/257832' do
before do
sign_in(public_project_user)
@@ -121,7 +121,7 @@ RSpec.describe "Internal references", :js do
visit(project_merge_request_path(public_project, public_project_merge_request))
end
- it "doesn't show any references" do
+ it "doesn't show any references", quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/257832' do
page.within(".merge-request-details") do
expect(page).not_to have_content("#merge-requests .merge-requests-title")
end
diff --git a/spec/features/issuables/merge_request_discussion_lock_spec.rb b/spec/features/issuables/merge_request_discussion_lock_spec.rb
new file mode 100644
index 00000000000..4e0265839f6
--- /dev/null
+++ b/spec/features/issuables/merge_request_discussion_lock_spec.rb
@@ -0,0 +1,79 @@
+# frozen_string_literal: true
+# TODO use shared examples to merge this spec with discussion_lock_spec.rb
+# https://gitlab.com/gitlab-org/gitlab/-/issues/255910
+
+require 'spec_helper'
+
+RSpec.describe 'Merge Request Discussion Lock', :js do
+ let(:user) { create(:user) }
+ let(:project) { create(:project, :public, :repository) }
+ let(:merge_request) { create(:merge_request, source_project: project, author: user) }
+
+ before do
+ sign_in(user)
+ end
+
+ context 'when a user is a team member' do
+ before do
+ project.add_developer(user)
+ end
+
+ context 'when the discussion is unlocked' do
+ it 'the user can lock the merge_request' do
+ visit project_merge_request_path(merge_request.project, merge_request)
+
+ expect(find('.issuable-sidebar')).to have_content('Unlocked')
+
+ page.within('.issuable-sidebar') do
+ find('.lock-edit').click
+ click_button('Lock')
+ end
+
+ expect(find('[data-testid="lock-status"]')).to have_content('Locked')
+ end
+ end
+
+ context 'when the discussion is locked' do
+ before do
+ merge_request.update_attribute(:discussion_locked, true)
+ visit project_merge_request_path(merge_request.project, merge_request)
+ end
+
+ it 'the user can unlock the merge_request' do
+ expect(find('.issuable-sidebar')).to have_content('Locked')
+
+ page.within('.issuable-sidebar') do
+ find('.lock-edit').click
+ click_button('Unlock')
+ end
+
+ expect(find('[data-testid="lock-status"]')).to have_content('Unlocked')
+ end
+ end
+ end
+
+ context 'when a user is not a team member' do
+ context 'when the discussion is unlocked' do
+ before do
+ visit project_merge_request_path(merge_request.project, merge_request)
+ end
+
+ it 'the user can not lock the merge_request' do
+ expect(find('.issuable-sidebar')).to have_content('Unlocked')
+ expect(find('.issuable-sidebar')).not_to have_selector('.lock-edit')
+ end
+ end
+
+ context 'when the discussion is locked' do
+ before do
+ merge_request.update_attribute(:discussion_locked, true)
+ visit project_merge_request_path(merge_request.project, merge_request)
+ end
+
+ it 'the user can not unlock the merge_request' do
+ expect(find('.issuable-sidebar')).to have_content('Locked')
+ expect(find('.issuable-sidebar')).not_to have_selector('.lock-edit')
+ end
+ end
+ end
+end
diff --git a/spec/features/issues/csv_spec.rb b/spec/features/issues/csv_spec.rb
index 8d06bf24f8b..c93693ec40a 100644
--- a/spec/features/issues/csv_spec.rb
+++ b/spec/features/issues/csv_spec.rb
@@ -31,13 +31,13 @@ RSpec.describe 'Issues csv' do
end
it 'triggers an email export' do
- expect(ExportCsvWorker).to receive(:perform_async).with(user.id, project.id, hash_including("project_id" => project.id))
+ expect(IssuableExportCsvWorker).to receive(:perform_async).with(:issue, user.id, project.id, hash_including("project_id" => project.id))
request_csv
end
it "doesn't send request params to ExportCsvWorker" do
- expect(ExportCsvWorker).to receive(:perform_async).with(anything, anything, hash_excluding("controller" => anything, "action" => anything))
+ expect(IssuableExportCsvWorker).to receive(:perform_async).with(:issue, anything, anything, hash_excluding("controller" => anything, "action" => anything))
request_csv
end
diff --git a/spec/features/issues/gfm_autocomplete_spec.rb b/spec/features/issues/gfm_autocomplete_spec.rb
index 0165fba9ace..ff78b9e608f 100644
--- a/spec/features/issues/gfm_autocomplete_spec.rb
+++ b/spec/features/issues/gfm_autocomplete_spec.rb
@@ -6,7 +6,9 @@ RSpec.describe 'GFM autocomplete', :js do
let_it_be(:user_xss_title) { 'eve <img src=x onerror=alert(2)&lt;img src=x onerror=alert(1)&gt;' }
let_it_be(:user_xss) { create(:user, name: user_xss_title, username: 'xss.user') }
let_it_be(:user) { create(:user, name: '💃speciąl someone💃', username: 'someone.special') }
- let_it_be(:project) { create(:project) }
+ let_it_be(:group) { create(:group, name: 'Ancestor') }
+ let_it_be(:child_group) { create(:group, parent: group, name: 'My group') }
+ let_it_be(:project) { create(:project, group: child_group) }
let_it_be(:label) { create(:label, project: project, title: 'special+') }
let(:issue) { create(:issue, project: project) }
@@ -530,7 +532,7 @@ RSpec.describe 'GFM autocomplete', :js do
expect(page).to have_selector('.tribute-container', visible: true)
- expect(find('.tribute-container ul', visible: true).text).to have_content(user_xss.username)
+ expect(find('.tribute-container ul', visible: true)).to have_text(user_xss.username)
end
it 'selects the first item for assignee dropdowns' do
@@ -558,6 +560,24 @@ RSpec.describe 'GFM autocomplete', :js do
expect(find('.tribute-container ul', visible: true)).to have_content(user.name)
end
+ context 'when autocompleting for groups' do
+ it 'shows the group when searching for the name of the group' do
+ page.within '.timeline-content-form' do
+ find('#note-body').native.send_keys('@mygroup')
+ end
+
+ expect(find('.tribute-container ul', visible: true)).to have_text('My group')
+ end
+
+ it 'does not show the group when searching for the name of the parent of the group' do
+ page.within '.timeline-content-form' do
+ find('#note-body').native.send_keys('@ancestor')
+ end
+
+ expect(find('.tribute-container ul', visible: true)).not_to have_text('My group')
+ end
+ end
+
context 'if a selected value has special characters' do
it 'wraps the result in double quotes' do
note = find('#note-body')
diff --git a/spec/features/issues/issue_sidebar_spec.rb b/spec/features/issues/issue_sidebar_spec.rb
index 38d11ee2560..94a1de06488 100644
--- a/spec/features/issues/issue_sidebar_spec.rb
+++ b/spec/features/issues/issue_sidebar_spec.rb
@@ -16,129 +16,83 @@ RSpec.describe 'Issue Sidebar' do
sign_in(user)
end
- context 'assignee', :js do
+ context 'when concerning the assignee', :js do
let(:user2) { create(:user) }
let(:issue2) { create(:issue, project: project, author: user2) }
- context 'when invite_members_version_a experiment is enabled' do
- before do
- stub_experiment_for_user(invite_members_version_a: true)
- end
+ include_examples 'issuable invite members experiments' do
+ let(:issuable_path) { project_issue_path(project, issue2) }
+ end
- context 'when user can not see invite members' do
- before do
- project.add_developer(user)
- visit_issue(project, issue2)
+ context 'when user is a developer' do
+ before do
+ project.add_developer(user)
+ visit_issue(project, issue2)
- find('.block.assignee .edit-link').click
+ find('.block.assignee .edit-link').click
- wait_for_requests
- end
+ wait_for_requests
+ end
- it 'does not see link to invite members' do
- page.within '.dropdown-menu-user' do
- expect(page).not_to have_link('Invite Members')
- end
+ it 'shows author in assignee dropdown' do
+ page.within '.dropdown-menu-user' do
+ expect(page).to have_content(user2.name)
end
end
- context 'when user can see invite members' do
- before do
- project.add_maintainer(user)
- visit_issue(project, issue2)
-
- find('.block.assignee .edit-link').click
+ it 'shows author when filtering assignee dropdown' do
+ page.within '.dropdown-menu-user' do
+ find('.dropdown-input-field').set(user2.name)
wait_for_requests
- end
- it 'sees link to invite members' do
- page.within '.dropdown-menu-user' do
- expect(page).to have_link('Invite Members', href: project_project_members_path(project))
- expect(page).to have_selector('[data-track-event="click_invite_members"]')
- expect(page).to have_selector("[data-track-label='edit_assignee']")
- end
+ expect(page).to have_content(user2.name)
end
end
- end
-
- context 'when invite_members_version_a experiment is not enabled' do
- context 'when user is a developer' do
- before do
- project.add_developer(user)
- visit_issue(project, issue2)
- find('.block.assignee .edit-link').click
+ it 'assigns yourself' do
+ find('.block.assignee .dropdown-menu-toggle').click
- wait_for_requests
- end
-
- it 'shows author in assignee dropdown' do
- page.within '.dropdown-menu-user' do
- expect(page).to have_content(user2.name)
- end
- end
+ click_button 'assign yourself'
- it 'shows author when filtering assignee dropdown' do
- page.within '.dropdown-menu-user' do
- find('.dropdown-input-field').native.send_keys user2.name
- sleep 1 # Required to wait for end of input delay
+ wait_for_requests
- wait_for_requests
+ find('.block.assignee .edit-link').click
- expect(page).to have_content(user2.name)
- end
+ page.within '.dropdown-menu-user' do
+ expect(page.find('.dropdown-header')).to be_visible
+ expect(page.find('.dropdown-menu-user-link.is-active')).to have_content(user.name)
end
+ end
- it 'assigns yourself' do
- find('.block.assignee .dropdown-menu-toggle').click
-
- click_button 'assign yourself'
-
- wait_for_requests
+ it 'keeps your filtered term after filtering and dismissing the dropdown' do
+ find('.dropdown-input-field').set(user2.name)
- find('.block.assignee .edit-link').click
+ wait_for_requests
- page.within '.dropdown-menu-user' do
- expect(page.find('.dropdown-header')).to be_visible
- expect(page.find('.dropdown-menu-user-link.is-active')).to have_content(user.name)
- end
+ page.within '.dropdown-menu-user' do
+ expect(page).not_to have_content 'Unassigned'
+ click_link user2.name
end
- it 'keeps your filtered term after filtering and dismissing the dropdown' do
- find('.dropdown-input-field').native.send_keys user2.name
-
- wait_for_requests
-
- page.within '.dropdown-menu-user' do
- expect(page).not_to have_content 'Unassigned'
- click_link user2.name
- end
-
- find('.js-right-sidebar').click
- find('.block.assignee .edit-link').click
+ find('.js-right-sidebar').click
+ find('.block.assignee .edit-link').click
- expect(page.all('.dropdown-menu-user li').length).to eq(1)
- expect(find('.dropdown-input-field').value).to eq(user2.name)
- end
+ expect(page.all('.dropdown-menu-user li').length).to eq(1)
+ expect(find('.dropdown-input-field').value).to eq(user2.name)
end
+ end
- context 'when user is a maintainer' do
- before do
- project.add_maintainer(user)
- visit_issue(project, issue2)
+ it 'shows label text as "Apply" when assignees are changed' do
+ project.add_developer(user)
+ visit_issue(project, issue2)
- find('.block.assignee .edit-link').click
+ find('.block.assignee .edit-link').click
+ wait_for_requests
- wait_for_requests
- end
+ click_on 'Unassigned'
- it 'shows author in assignee dropdown and no invite link' do
- page.within '.dropdown-menu-user' do
- expect(page).not_to have_link('Invite Members')
- end
- end
- end
+ expect(page).to have_link('Apply')
end
end
diff --git a/spec/features/issues/todo_spec.rb b/spec/features/issues/todo_spec.rb
index 3de33049db0..315d1c911a2 100644
--- a/spec/features/issues/todo_spec.rb
+++ b/spec/features/issues/todo_spec.rb
@@ -15,7 +15,7 @@ RSpec.describe 'Manually create a todo item from issue', :js do
it 'creates todo when clicking button' do
page.within '.issuable-sidebar' do
- click_button 'Add a To Do'
+ click_button 'Add a to do'
expect(page).to have_content 'Mark as done'
end
@@ -32,7 +32,7 @@ RSpec.describe 'Manually create a todo item from issue', :js do
it 'marks a todo as done' do
page.within '.issuable-sidebar' do
- click_button 'Add a To Do'
+ click_button 'Add a to do'
click_button 'Mark as done'
end
diff --git a/spec/features/issues/user_edits_issue_spec.rb b/spec/features/issues/user_edits_issue_spec.rb
index 88b8e9624e2..de746415205 100644
--- a/spec/features/issues/user_edits_issue_spec.rb
+++ b/spec/features/issues/user_edits_issue_spec.rb
@@ -6,292 +6,356 @@ RSpec.describe "Issues > User edits issue", :js do
let_it_be(:project) { create(:project_empty_repo, :public) }
let_it_be(:project_with_milestones) { create(:project_empty_repo, :public) }
let_it_be(:user) { create(:user) }
- let_it_be(:issue) { create(:issue, project: project, author: user, assignees: [user]) }
+ let_it_be(:label_assigned) { create(:label, project: project, title: 'verisimilitude') }
+ let_it_be(:label_unassigned) { create(:label, project: project, title: 'syzygy') }
+ let_it_be(:issue) { create(:issue, project: project, author: user, assignees: [user], labels: [label_assigned]) }
let_it_be(:issue_with_milestones) { create(:issue, project: project_with_milestones, author: user, assignees: [user]) }
- let_it_be(:label) { create(:label, project: project) }
let_it_be(:milestone) { create(:milestone, project: project) }
let_it_be(:milestones) { create_list(:milestone, 25, project: project_with_milestones) }
- before do
- project.add_developer(user)
- project_with_milestones.add_developer(user)
- sign_in(user)
- end
-
- context "from edit page" do
+ context 'with authorized user' do
before do
- visit edit_project_issue_path(project, issue)
+ project.add_developer(user)
+ project_with_milestones.add_developer(user)
+ sign_in(user)
end
- it "previews content" do
- form = first(".gfm-form")
-
- page.within(form) do
- fill_in("Description", with: "Bug fixed :smile:")
- click_button("Preview")
+ context "from edit page" do
+ before do
+ visit edit_project_issue_path(project, issue)
end
- expect(form).to have_button("Write")
- end
-
- it 'allows user to select unassigned' do
- visit edit_project_issue_path(project, issue)
-
- expect(page).to have_content "Assignee #{user.name}"
+ it "previews content" do
+ form = first(".gfm-form")
- first('.js-user-search').click
- click_link 'Unassigned'
-
- click_button 'Save changes'
+ page.within(form) do
+ fill_in("Description", with: "Bug fixed :smile:")
+ click_button("Preview")
+ end
- page.within('.assignee') do
- expect(page).to have_content 'None - assign yourself'
+ expect(form).to have_button("Write")
end
- end
- context 'with due date' do
- before do
+ it 'allows user to select unassigned' do
visit edit_project_issue_path(project, issue)
- end
-
- it 'saves with due date' do
- date = Date.today.at_beginning_of_month.tomorrow
- fill_in 'issue_title', with: 'bug 345'
- fill_in 'issue_description', with: 'bug description'
- find('#issuable-due-date').click
-
- page.within '.pika-single' do
- click_button date.day
- end
+ expect(page).to have_content "Assignee #{user.name}"
- expect(find('#issuable-due-date').value).to eq date.to_s
+ first('.js-user-search').click
+ click_link 'Unassigned'
click_button 'Save changes'
- page.within '.issuable-sidebar' do
- expect(page).to have_content date.to_s(:medium)
+ page.within('.assignee') do
+ expect(page).to have_content 'None - assign yourself'
end
end
- it 'warns about version conflict' do
- issue.update(title: "New title")
+ context 'with due date' do
+ before do
+ visit edit_project_issue_path(project, issue)
+ end
- fill_in 'issue_title', with: 'bug 345'
- fill_in 'issue_description', with: 'bug description'
+ it 'saves with due date' do
+ date = Date.today.at_beginning_of_month.tomorrow
- click_button 'Save changes'
+ fill_in 'issue_title', with: 'bug 345'
+ fill_in 'issue_description', with: 'bug description'
+ find('#issuable-due-date').click
- expect(page).to have_content 'Someone edited the issue the same time you did'
- end
- end
- end
+ page.within '.pika-single' do
+ click_button date.day
+ end
- context "from issue#show" do
- before do
- visit project_issue_path(project, issue)
- end
+ expect(find('#issuable-due-date').value).to eq date.to_s
+
+ click_button 'Save changes'
+
+ page.within '.issuable-sidebar' do
+ expect(page).to have_content date.to_s(:medium)
+ end
+ end
- describe 'update labels' do
- it 'will not send ajax request when no data is changed' do
- page.within '.labels' do
- click_on 'Edit'
+ it 'warns about version conflict' do
+ issue.update(title: "New title")
- find('.dropdown-title button').click
+ fill_in 'issue_title', with: 'bug 345'
+ fill_in 'issue_description', with: 'bug description'
- expect(page).not_to have_selector('.block-loading')
- expect(page).not_to have_selector('.gl-spinner')
+ click_button 'Save changes'
+
+ expect(page).to have_content 'Someone edited the issue the same time you did'
end
end
end
- describe 'update assignee' do
- context 'by authorized user' do
- def close_dropdown_menu_if_visible
- find('.dropdown-menu-toggle', visible: :all).tap do |toggle|
- toggle.click if toggle.visible?
+ context "from issue#show" do
+ before do
+ visit project_issue_path(project, issue)
+ end
+
+ describe 'update labels' do
+ it 'will not send ajax request when no data is changed' do
+ page.within '.labels' do
+ click_on 'Edit'
+
+ find('.dropdown-title button').click
+
+ expect(page).not_to have_selector('.block-loading')
+ expect(page).not_to have_selector('.gl-spinner')
end
end
- it 'allows user to select unassigned' do
- visit project_issue_path(project, issue)
+ it 'can add label to issue' do
+ page.within '.block.labels' do
+ expect(page).to have_text('verisimilitude')
+ expect(page).not_to have_text('syzygy')
- page.within('.assignee') do
- expect(page).to have_content "#{user.name}"
+ click_on 'Edit'
- click_link 'Edit'
- click_link 'Unassigned'
- first('.title').click
- expect(page).to have_content 'None - assign yourself'
+ wait_for_requests
+
+ click_on 'syzygy'
+ find('.dropdown-header-button').click
+
+ wait_for_requests
+
+ expect(page).to have_text('verisimilitude')
+ expect(page).to have_text('syzygy')
end
end
- it 'allows user to select an assignee' do
- issue2 = create(:issue, project: project, author: user)
- visit project_issue_path(project, issue2)
+ it 'can remove label from issue by clicking on the label `x` button' do
+ page.within '.block.labels' do
+ expect(page).to have_text('verisimilitude')
+
+ within '.gl-label' do
+ click_button
+ end
+
+ wait_for_requests
- page.within('.assignee') do
- expect(page).to have_content "None"
+ expect(page).not_to have_text('verisimilitude')
end
+ end
+ end
- page.within '.assignee' do
- click_link 'Edit'
+ describe 'update assignee' do
+ context 'by authorized user' do
+ def close_dropdown_menu_if_visible
+ find('.dropdown-menu-toggle', visible: :all).tap do |toggle|
+ toggle.click if toggle.visible?
+ end
end
- page.within '.dropdown-menu-user' do
- click_link user.name
+ it 'allows user to select unassigned' do
+ visit project_issue_path(project, issue)
+
+ page.within('.assignee') do
+ expect(page).to have_content "#{user.name}"
+
+ click_link 'Edit'
+ click_link 'Unassigned'
+ first('.title').click
+ expect(page).to have_content 'None - assign yourself'
+ end
end
- page.within('.assignee') do
- expect(page).to have_content user.name
+ it 'allows user to select an assignee' do
+ issue2 = create(:issue, project: project, author: user)
+ visit project_issue_path(project, issue2)
+
+ page.within('.assignee') do
+ expect(page).to have_content "None"
+ end
+
+ page.within '.assignee' do
+ click_link 'Edit'
+ end
+
+ page.within '.dropdown-menu-user' do
+ click_link user.name
+ end
+
+ page.within('.assignee') do
+ expect(page).to have_content user.name
+ end
end
- end
- it 'allows user to unselect themselves' do
- issue2 = create(:issue, project: project, author: user, assignees: [user])
+ it 'allows user to unselect themselves' do
+ issue2 = create(:issue, project: project, author: user, assignees: [user])
- visit project_issue_path(project, issue2)
+ visit project_issue_path(project, issue2)
- page.within '.assignee' do
- expect(page).to have_content user.name
+ page.within '.assignee' do
+ expect(page).to have_content user.name
- click_link 'Edit'
- click_link user.name
+ click_link 'Edit'
+ click_link user.name
- close_dropdown_menu_if_visible
+ close_dropdown_menu_if_visible
- page.within '.value .assign-yourself' do
- expect(page).to have_content "None"
+ page.within '.value .assign-yourself' do
+ expect(page).to have_content "None"
+ end
end
end
end
- end
- context 'by unauthorized user' do
- let(:guest) { create(:user) }
+ context 'by unauthorized user' do
+ let(:guest) { create(:user) }
- before do
- project.add_guest(guest)
- end
+ before do
+ project.add_guest(guest)
+ end
- it 'shows assignee text' do
- sign_out(:user)
- sign_in(guest)
+ it 'shows assignee text' do
+ sign_out(:user)
+ sign_in(guest)
- visit project_issue_path(project, issue)
- expect(page).to have_content issue.assignees.first.name
+ visit project_issue_path(project, issue)
+ expect(page).to have_content issue.assignees.first.name
+ end
end
end
- end
- describe 'update milestone' do
- context 'by authorized user' do
- it 'allows user to select unassigned' do
- visit project_issue_path(project, issue)
+ describe 'update milestone' do
+ context 'by authorized user' do
+ it 'allows user to select unassigned' do
+ visit project_issue_path(project, issue)
- page.within('.milestone') do
- expect(page).to have_content "None"
- end
+ page.within('.milestone') do
+ expect(page).to have_content "None"
+ end
- find('.block.milestone .edit-link').click
- sleep 2 # wait for ajax stuff to complete
- first('.dropdown-content li').click
- sleep 2
- page.within('.milestone') do
- expect(page).to have_content 'None'
+ find('.block.milestone .edit-link').click
+ sleep 2 # wait for ajax stuff to complete
+ first('.dropdown-content li').click
+ sleep 2
+ page.within('.milestone') do
+ expect(page).to have_content 'None'
+ end
end
- end
- it 'allows user to de-select milestone' do
- visit project_issue_path(project, issue)
+ it 'allows user to de-select milestone' do
+ visit project_issue_path(project, issue)
- page.within('.milestone') do
- click_link 'Edit'
- click_link milestone.title
+ page.within('.milestone') do
+ click_link 'Edit'
+ click_link milestone.title
- page.within '.value' do
- expect(page).to have_content milestone.title
- end
+ page.within '.value' do
+ expect(page).to have_content milestone.title
+ end
- click_link 'Edit'
- click_link milestone.title
+ click_link 'Edit'
+ click_link milestone.title
- page.within '.value' do
- expect(page).to have_content 'None'
+ page.within '.value' do
+ expect(page).to have_content 'None'
+ end
end
end
- end
- it 'allows user to search milestone' do
- visit project_issue_path(project_with_milestones, issue_with_milestones)
+ it 'allows user to search milestone' do
+ visit project_issue_path(project_with_milestones, issue_with_milestones)
- page.within('.milestone') do
- click_link 'Edit'
- wait_for_requests
- # We need to enclose search string in quotes for exact match as all the milestone titles
- # within tests are prefixed with `My title`.
- find('.dropdown-input-field', visible: true).send_keys "\"#{milestones[0].title}\""
- wait_for_requests
+ page.within('.milestone') do
+ click_link 'Edit'
+ wait_for_requests
+ # We need to enclose search string in quotes for exact match as all the milestone titles
+ # within tests are prefixed with `My title`.
+ find('.dropdown-input-field', visible: true).send_keys "\"#{milestones[0].title}\""
+ wait_for_requests
- page.within '.dropdown-content' do
- expect(page).to have_content milestones[0].title
+ page.within '.dropdown-content' do
+ expect(page).to have_content milestones[0].title
+ end
end
end
end
- end
- context 'by unauthorized user' do
- let(:guest) { create(:user) }
+ context 'by unauthorized user' do
+ let(:guest) { create(:user) }
- before do
- project.add_guest(guest)
- issue.milestone = milestone
- issue.save
- end
+ before do
+ project.add_guest(guest)
+ issue.milestone = milestone
+ issue.save
+ end
- it 'shows milestone text' do
- sign_out(:user)
- sign_in(guest)
+ it 'shows milestone text' do
+ sign_out(:user)
+ sign_in(guest)
- visit project_issue_path(project, issue)
- expect(page).to have_content milestone.title
+ visit project_issue_path(project, issue)
+ expect(page).to have_content milestone.title
+ end
end
end
- end
- context 'update due date' do
- it 'adds due date to issue' do
- date = Date.today.at_beginning_of_month + 2.days
+ context 'update due date' do
+ it 'adds due date to issue' do
+ date = Date.today.at_beginning_of_month + 2.days
- page.within '.due_date' do
- click_link 'Edit'
+ page.within '.due_date' do
+ click_link 'Edit'
- page.within '.pika-single' do
- click_button date.day
- end
+ page.within '.pika-single' do
+ click_button date.day
+ end
- wait_for_requests
+ wait_for_requests
- expect(find('.value').text).to have_content date.strftime('%b %-d, %Y')
+ expect(find('.value').text).to have_content date.strftime('%b %-d, %Y')
+ end
end
- end
- it 'removes due date from issue' do
- date = Date.today.at_beginning_of_month + 2.days
+ it 'removes due date from issue' do
+ date = Date.today.at_beginning_of_month + 2.days
- page.within '.due_date' do
- click_link 'Edit'
+ page.within '.due_date' do
+ click_link 'Edit'
- page.within '.pika-single' do
- click_button date.day
+ page.within '.pika-single' do
+ click_button date.day
+ end
+
+ wait_for_requests
+
+ expect(page).to have_no_content 'None'
+
+ click_link 'remove due date'
+ expect(page).to have_content 'None'
end
+ end
+ end
+ end
+ end
- wait_for_requests
+ context 'with unauthorized user' do
+ before do
+ sign_in(user)
+ end
- expect(page).to have_no_content 'None'
+ context "from issue#show" do
+ before do
+ visit project_issue_path(project, issue)
+ end
- click_link 'remove due date'
- expect(page).to have_content 'None'
+ describe 'updating labels' do
+ it 'cannot edit labels' do
+ page.within '.block.labels' do
+ expect(page).not_to have_button('Edit')
+ end
+ end
+
+ it 'cannot remove label with a click as it has no `x` button' do
+ page.within '.block.labels' do
+ within '.gl-label' do
+ expect(page).not_to have_button
+ end
+ end
end
end
end
diff --git a/spec/features/issues/user_sees_live_update_spec.rb b/spec/features/issues/user_sees_live_update_spec.rb
index c9b751715bc..d27cdb774a5 100644
--- a/spec/features/issues/user_sees_live_update_spec.rb
+++ b/spec/features/issues/user_sees_live_update_spec.rb
@@ -39,7 +39,7 @@ RSpec.describe 'Issues > User sees live update', :js do
expect(page).to have_css('.sidebar-item-warning-message')
within('.sidebar-item-warning-message') do
- find('.btn-close').click
+ find('[data-testid="confidential-toggle"]').click
end
wait_for_requests
diff --git a/spec/features/issues/user_views_issue_spec.rb b/spec/features/issues/user_views_issue_spec.rb
index 3f18764aa58..9b1c8be1513 100644
--- a/spec/features/issues/user_views_issue_spec.rb
+++ b/spec/features/issues/user_views_issue_spec.rb
@@ -5,7 +5,7 @@ require "spec_helper"
RSpec.describe "User views issue" do
let_it_be(:project) { create(:project_empty_repo, :public) }
let_it_be(:user) { create(:user) }
- let_it_be(:issue) { create(:issue, project: project, description: "# Description header", author: user) }
+ let_it_be(:issue) { create(:issue, project: project, description: "# Description header\n\n**Lorem** _ipsum_ dolor sit [amet](https://example.com)", author: user) }
let_it_be(:note) { create(:note, noteable: issue, project: project, author: user) }
before_all do
@@ -20,6 +20,8 @@ RSpec.describe "User views issue" do
it { expect(page).to have_header_with_correct_id_and_link(1, "Description header", "description-header") }
+ it_behaves_like 'page meta description', ' Description header Lorem ipsum dolor sit amet'
+
it 'shows the merge request and issue actions', :aggregate_failures do
expect(page).to have_link('New issue')
expect(page).to have_button('Create merge request')
diff --git a/spec/features/labels_hierarchy_spec.rb b/spec/features/labels_hierarchy_spec.rb
index eed9a6d1043..5d141580874 100644
--- a/spec/features/labels_hierarchy_spec.rb
+++ b/spec/features/labels_hierarchy_spec.rb
@@ -17,6 +17,7 @@ RSpec.describe 'Labels Hierarchy', :js do
let!(:project_label_1) { create(:label, project: project_1, title: 'Label_4') }
before do
+ stub_feature_flags(graphql_board_lists: false)
grandparent.add_owner(user)
sign_in(user)
diff --git a/spec/features/merge_request/batch_comments_spec.rb b/spec/features/merge_request/batch_comments_spec.rb
index 40f6482c948..c8fc23bebf9 100644
--- a/spec/features/merge_request/batch_comments_spec.rb
+++ b/spec/features/merge_request/batch_comments_spec.rb
@@ -41,7 +41,6 @@ RSpec.describe 'Merge request > Batch comments', :js do
write_comment
page.within('.review-bar-content') do
- click_button 'Finish review'
click_button 'Submit review'
end
@@ -64,18 +63,6 @@ RSpec.describe 'Merge request > Batch comments', :js do
expect(page).to have_selector('.note:not(.draft-note)', text: 'Line is wrong')
end
- it 'discards review' do
- write_comment
-
- click_button 'Discard review'
-
- click_button 'Delete all pending comments'
-
- wait_for_requests
-
- expect(page).not_to have_selector('.draft-note-component')
- end
-
it 'deletes draft note' do
write_comment
@@ -149,7 +136,6 @@ RSpec.describe 'Merge request > Batch comments', :js do
write_reply_to_discussion(resolve: true)
page.within('.review-bar-content') do
- click_button 'Finish review'
click_button 'Submit review'
end
@@ -192,7 +178,6 @@ RSpec.describe 'Merge request > Batch comments', :js do
write_reply_to_discussion(button_text: 'Start a review', unresolve: true)
page.within('.review-bar-content') do
- click_button 'Finish review'
click_button 'Submit review'
end
diff --git a/spec/features/merge_request/maintainer_edits_fork_spec.rb b/spec/features/merge_request/maintainer_edits_fork_spec.rb
index 0e65cb358da..a98bfd1c8a4 100644
--- a/spec/features/merge_request/maintainer_edits_fork_spec.rb
+++ b/spec/features/merge_request/maintainer_edits_fork_spec.rb
@@ -26,7 +26,12 @@ RSpec.describe 'a maintainer edits files on a source-branch of an MR from a fork
visit project_merge_request_path(target_project, merge_request)
click_link 'Changes'
wait_for_requests
- first('.js-file-title').find('.js-edit-blob').click
+
+ page.within(first('.js-file-title')) do
+ find('.js-diff-more-actions').click
+ find('.js-edit-blob').click
+ end
+
wait_for_requests
end
diff --git a/spec/features/merge_request/user_comments_on_diff_spec.rb b/spec/features/merge_request/user_comments_on_diff_spec.rb
index 3a199951b56..ad1ad067935 100644
--- a/spec/features/merge_request/user_comments_on_diff_spec.rb
+++ b/spec/features/merge_request/user_comments_on_diff_spec.rb
@@ -34,7 +34,8 @@ RSpec.describe 'User comments on a diff', :js do
page.within('.diff-files-holder > div:nth-child(3)') do
expect(page).to have_content('Line is wrong')
- find('.js-btn-vue-toggle-comments').click
+ find('.js-diff-more-actions').click
+ click_button 'Hide comments on this file'
expect(page).not_to have_content('Line is wrong')
end
@@ -67,7 +68,8 @@ RSpec.describe 'User comments on a diff', :js do
# Hide the comment.
page.within('.diff-files-holder > div:nth-child(3)') do
- find('.js-btn-vue-toggle-comments').click
+ find('.js-diff-more-actions').click
+ click_button 'Hide comments on this file'
expect(page).not_to have_content('Line is wrong')
end
@@ -80,7 +82,8 @@ RSpec.describe 'User comments on a diff', :js do
# Show the comment.
page.within('.diff-files-holder > div:nth-child(3)') do
- find('.js-btn-vue-toggle-comments').click
+ find('.js-diff-more-actions').click
+ click_button 'Show comments on this file'
end
# Now both the comments should be shown.
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 affd6f6b7b5..7d55a72c2b1 100644
--- a/spec/features/merge_request/user_edits_assignees_sidebar_spec.rb
+++ b/spec/features/merge_request/user_edits_assignees_sidebar_spec.rb
@@ -20,7 +20,7 @@ RSpec.describe 'Merge request > User edits assignees sidebar', :js do
let(:sidebar_assignee_dropdown_item) { sidebar_assignee_block.find(".dropdown-menu li[data-user-id=\"#{assignee.id}\"]") }
let(:sidebar_assignee_dropdown_tooltip) { sidebar_assignee_dropdown_item.find('a')['data-title'] || '' }
- context 'when invite_members_version_a experiment is not enabled' do
+ context 'when user is an owner' do
before do
stub_const('Autocomplete::UsersFinder::LIMIT', users_find_limit)
@@ -52,12 +52,6 @@ RSpec.describe 'Merge request > User edits assignees sidebar', :js do
it "shows assignee tooltip '#{expected_tooltip}" do
expect(sidebar_assignee_dropdown_tooltip).to eql(expected_tooltip)
end
-
- it 'does not show invite link' do
- page.within '.dropdown-menu-user' do
- expect(page).not_to have_link('Invite Members')
- end
- end
end
end
@@ -74,48 +68,15 @@ RSpec.describe 'Merge request > User edits assignees sidebar', :js do
end
end
- context 'when invite_members_version_a experiment is enabled' do
+ context 'with invite members experiment considerations' do
let_it_be(:user) { create(:user) }
before do
- stub_experiment_for_user(invite_members_version_a: true)
sign_in(user)
end
- context 'when user can not see invite members' do
- before do
- project.add_developer(user)
- visit project_merge_request_path(project, merge_request)
-
- find('.block.assignee .edit-link').click
-
- wait_for_requests
- end
-
- it 'does not see link to invite members' do
- page.within '.dropdown-menu-user' do
- expect(page).not_to have_link('Invite Members')
- end
- end
- end
-
- context 'when user can see invite members' do
- before do
- project.add_maintainer(user)
- visit project_merge_request_path(project, merge_request)
-
- find('.block.assignee .edit-link').click
-
- wait_for_requests
- end
-
- it 'sees link to invite members' do
- page.within '.dropdown-menu-user' do
- expect(page).to have_link('Invite Members', href: project_project_members_path(project))
- expect(page).to have_selector('[data-track-event="click_invite_members"]')
- expect(page).to have_selector("[data-track-label='edit_assignee']")
- end
- end
+ include_examples 'issuable invite members experiments' do
+ let(:issuable_path) { project_merge_request_path(project, merge_request) }
end
end
end
diff --git a/spec/features/merge_request/user_edits_mr_spec.rb b/spec/features/merge_request/user_edits_mr_spec.rb
index 397ca70f4a1..817b4e0b48e 100644
--- a/spec/features/merge_request/user_edits_mr_spec.rb
+++ b/spec/features/merge_request/user_edits_mr_spec.rb
@@ -21,24 +21,6 @@ RSpec.describe 'Merge request > User edits MR' do
it_behaves_like 'an editable merge request'
end
- context 'when merge_request_reviewers is turned on' do
- before do
- stub_feature_flags(merge_request_reviewers: true)
- end
-
- context 'non-fork merge request' do
- include_context 'merge request edit context'
- it_behaves_like 'an editable merge request with reviewers'
- end
-
- context 'for a forked project' do
- let(:source_project) { fork_project(target_project, nil, repository: true) }
-
- include_context 'merge request edit context'
- it_behaves_like 'an editable merge request with reviewers'
- end
- end
-
context 'when merge_request_reviewers is turned off' do
before do
stub_feature_flags(merge_request_reviewers: false)
diff --git a/spec/features/merge_request/user_expands_diff_spec.rb b/spec/features/merge_request/user_expands_diff_spec.rb
index 0340d9ccc3d..0cdc87de761 100644
--- a/spec/features/merge_request/user_expands_diff_spec.rb
+++ b/spec/features/merge_request/user_expands_diff_spec.rb
@@ -7,6 +7,7 @@ RSpec.describe 'User expands diff', :js do
let(:merge_request) { create(:merge_request, source_branch: 'expand-collapse-files', source_project: project, target_project: project) }
before do
+ stub_feature_flags(increased_diff_limits: false)
visit(diffs_project_merge_request_path(project, merge_request))
wait_for_requests
diff --git a/spec/features/merge_request/user_marks_merge_request_as_draft_spec.rb b/spec/features/merge_request/user_marks_merge_request_as_draft_spec.rb
new file mode 100644
index 00000000000..f5bca7cf015
--- /dev/null
+++ b/spec/features/merge_request/user_marks_merge_request_as_draft_spec.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Merge request > User marks merge request as draft', :js do
+ let(:user) { create(:user) }
+ let(:project) { create(:project, :public, :repository) }
+ let(:merge_request) { create(:merge_request, source_project: project) }
+
+ before do
+ project.add_maintainer(user)
+
+ sign_in(user)
+
+ visit project_merge_request_path(project, merge_request)
+ end
+
+ it 'toggles draft status' do
+ click_link 'Mark as draft'
+
+ expect(page).to have_content("Draft: #{merge_request.title}")
+
+ page.within('.detail-page-header-actions') do
+ click_link 'Mark as ready'
+ end
+
+ expect(page).to have_content(merge_request.title)
+ end
+end
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 3dc49fb4dea..444d5371e7a 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
@@ -47,7 +47,7 @@ RSpec.describe 'Merge request > User merges when pipeline succeeds', :js do
it_behaves_like 'Merge when pipeline succeeds activator'
end
- context 'when enabled after pipeline status changed' do
+ context 'when enabled after pipeline status changed', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/258667' do
before do
pipeline.run!
diff --git a/spec/features/merge_request/user_reopens_merge_request_spec.rb b/spec/features/merge_request/user_reopens_merge_request_spec.rb
index 7866ece84ac..4a05a3be59a 100644
--- a/spec/features/merge_request/user_reopens_merge_request_spec.rb
+++ b/spec/features/merge_request/user_reopens_merge_request_spec.rb
@@ -15,7 +15,11 @@ RSpec.describe 'User reopens a merge requests', :js do
end
it 'reopens a merge request' do
- click_button('Reopen merge request', match: :first)
+ find('.js-issuable-close-dropdown .dropdown-toggle').click
+
+ click_link('Reopen merge request', match: :first)
+
+ wait_for_requests
page.within('.status-box') do
expect(page).to have_content('Open')
diff --git a/spec/features/merge_request/user_resolves_wip_mr_spec.rb b/spec/features/merge_request/user_resolves_wip_mr_spec.rb
index a9d4c4df507..b67167252e1 100644
--- a/spec/features/merge_request/user_resolves_wip_mr_spec.rb
+++ b/spec/features/merge_request/user_resolves_wip_mr_spec.rb
@@ -35,7 +35,9 @@ RSpec.describe 'Merge request > User resolves Work in Progress', :js do
expect(page.find('.ci-widget-content')).to have_content("Pipeline ##{pipeline.id}")
expect(page).to have_content "This merge request is still a work in progress."
- click_button('Mark as ready')
+ page.within('.mr-state-widget') do
+ click_button('Mark as ready')
+ end
wait_for_requests
diff --git a/spec/features/merge_request/user_sees_diff_spec.rb b/spec/features/merge_request/user_sees_diff_spec.rb
index 7a3a14e61e3..a7713ed9964 100644
--- a/spec/features/merge_request/user_sees_diff_spec.rb
+++ b/spec/features/merge_request/user_sees_diff_spec.rb
@@ -63,7 +63,7 @@ RSpec.describe 'Merge request > User sees diff', :js do
visit diffs_project_merge_request_path(project, merge_request)
# Throws `Capybara::Poltergeist::InvalidSelector` if we try to use `#hash` syntax
- expect(page).to have_selector("[id=\"#{changelog_id}\"] a.js-edit-blob")
+ expect(page).to have_selector("[id=\"#{changelog_id}\"] .js-edit-blob", visible: false)
end
end
@@ -73,6 +73,7 @@ RSpec.describe 'Merge request > User sees diff', :js do
visit diffs_project_merge_request_path(project, merge_request)
# Throws `Capybara::Poltergeist::InvalidSelector` if we try to use `#hash` syntax
+ find("[id=\"#{changelog_id}\"] .js-diff-more-actions").click
find("[id=\"#{changelog_id}\"] .js-edit-blob").click
expect(page).to have_selector('.js-fork-suggestion-button', count: 1)
diff --git a/spec/features/merge_request/user_sees_page_metadata_spec.rb b/spec/features/merge_request/user_sees_page_metadata_spec.rb
new file mode 100644
index 00000000000..7b3e07152a0
--- /dev/null
+++ b/spec/features/merge_request/user_sees_page_metadata_spec.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Merge request > User sees page metadata' do
+ let(:merge_request) { create(:merge_request, description: '**Lorem** _ipsum_ dolor sit [amet](https://example.com)') }
+ let(:project) { merge_request.target_project }
+ let(:user) { project.creator }
+
+ before do
+ project.add_maintainer(user)
+ sign_in(user)
+ visit project_merge_request_path(project, merge_request)
+ end
+
+ it_behaves_like 'page meta description', 'Lorem ipsum dolor sit amet'
+end
diff --git a/spec/features/merge_request/user_sees_pipelines_spec.rb b/spec/features/merge_request/user_sees_pipelines_spec.rb
index 8e15ba6cf8d..107fc002ebd 100644
--- a/spec/features/merge_request/user_sees_pipelines_spec.rb
+++ b/spec/features/merge_request/user_sees_pipelines_spec.rb
@@ -50,7 +50,7 @@ RSpec.describe 'Merge request > User sees pipelines', :js do
wait_for_requests
- expect(page.find('.js-run-mr-pipeline')).to have_text('Run Pipeline')
+ expect(page.find('[data-testid="run_pipeline_button"]')).to have_text('Run Pipeline')
end
end
@@ -66,7 +66,7 @@ RSpec.describe 'Merge request > User sees pipelines', :js do
wait_for_requests
- expect(page.find('.js-run-mr-pipeline')).to have_text('Run Pipeline')
+ expect(page.find('[data-testid="run_pipeline_button"]')).to have_text('Run Pipeline')
end
end
end
diff --git a/spec/features/merge_request/user_sees_suggest_pipeline_spec.rb b/spec/features/merge_request/user_sees_suggest_pipeline_spec.rb
new file mode 100644
index 00000000000..93807512d9c
--- /dev/null
+++ b/spec/features/merge_request/user_sees_suggest_pipeline_spec.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Merge request > User sees suggest pipeline', :js do
+ let(:merge_request) { create(:merge_request) }
+ let(:project) { merge_request.source_project }
+ let(:user) { project.creator }
+
+ before do
+ stub_application_setting(auto_devops_enabled: false)
+ stub_experiment(suggest_pipeline: true)
+ stub_experiment_for_user(suggest_pipeline: true)
+ project.add_maintainer(user)
+ sign_in(user)
+ visit project_merge_request_path(project, merge_request)
+ end
+
+ it 'shows the suggest pipeline widget and then allows dismissal correctly' do
+ expect(page).to have_content('Are you adding technical debt or code vulnerabilities?')
+
+ page.within '.mr-pipeline-suggest' do
+ find('[data-testid="close"]').click
+ end
+
+ wait_for_requests
+
+ expect(page).not_to have_content('Are you adding technical debt or code vulnerabilities?')
+
+ # Reload so we know the user callout was registered
+ visit page.current_url
+
+ expect(page).not_to have_content('Are you adding technical debt or code vulnerabilities?')
+ end
+end
diff --git a/spec/features/merge_request/user_suggests_changes_on_diff_spec.rb b/spec/features/merge_request/user_suggests_changes_on_diff_spec.rb
index 39495832547..9268190c7e0 100644
--- a/spec/features/merge_request/user_suggests_changes_on_diff_spec.rb
+++ b/spec/features/merge_request/user_suggests_changes_on_diff_spec.rb
@@ -119,7 +119,8 @@ RSpec.describe 'User comments on a diff', :js do
it 'can add and remove suggestions from a batch' do
files.each_with_index do |file, index|
page.within("[id='#{file[:hash]}']") do
- find("button[title='Show full file']").click
+ find('.js-diff-more-actions').click
+ click_button 'Show full file'
wait_for_requests
click_diff_line(find("[id='#{file[:line_code]}']"))
@@ -130,7 +131,9 @@ RSpec.describe 'User comments on a diff', :js do
wait_for_requests
end
end
+ end
+ files.each_with_index do |file, index|
page.within("[id='#{file[:hash]}']") do
expect(page).not_to have_content('Applied')
@@ -247,7 +250,7 @@ RSpec.describe 'User comments on a diff', :js do
end
context 'multiple suggestions in a single note' do
- it 'suggestions are presented' do
+ it 'suggestions are presented', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/258989' do
click_diff_line(find("[id='#{sample_compare.changes[1][:line_code]}']"))
page.within('.js-discussion-note-form') do
diff --git a/spec/features/merge_request/user_views_open_merge_request_spec.rb b/spec/features/merge_request/user_views_open_merge_request_spec.rb
index 448844ae57d..e8998f9457a 100644
--- a/spec/features/merge_request/user_views_open_merge_request_spec.rb
+++ b/spec/features/merge_request/user_views_open_merge_request_spec.rb
@@ -22,7 +22,24 @@ RSpec.describe 'User views an open merge request' do
# returns the whole document, not the node's actual parent element
expect(find(:xpath, "#{node.path}/..").text).to eq(merge_request.description[2..-1])
- expect(page).to have_content(merge_request.title).and have_content(merge_request.description)
+ expect(page).to have_content(merge_request.title)
+ end
+
+ it 'has reviewers in sidebar' do
+ expect(page).to have_css('.reviewer')
+ end
+ end
+
+ context 'when merge_request_reviewers is turned off' do
+ let(:project) { create(:project, :public, :repository) }
+
+ before do
+ stub_feature_flags(merge_request_reviewers: false)
+ visit(merge_request_path(merge_request))
+ end
+
+ it 'has reviewers in sidebar' do
+ expect(page).not_to have_css('.reviewer')
end
end
diff --git a/spec/features/merge_requests/user_filters_by_approvals_spec.rb b/spec/features/merge_requests/user_filters_by_approvals_spec.rb
new file mode 100644
index 00000000000..6dda9ca7952
--- /dev/null
+++ b/spec/features/merge_requests/user_filters_by_approvals_spec.rb
@@ -0,0 +1,82 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Merge Requests > User filters', :js do
+ include FilteredSearchHelpers
+
+ let_it_be(:project) { create(:project, :public, :repository) }
+ let_it_be(:user) { project.creator }
+ let_it_be(:group_user) { create(:user) }
+ let_it_be(:first_user) { create(:user) }
+
+ before do
+ sign_in(user)
+ visit project_merge_requests_path(project)
+ end
+
+ context 'by "approved by"' do
+ let_it_be(:merge_request) { create(:merge_request, title: 'Bugfix3', source_project: project, source_branch: 'bugfix3') }
+
+ let_it_be(:merge_request_with_first_user_approval) do
+ create(:merge_request, source_project: project, title: 'Bugfix5').tap do |mr|
+ create(:approval, merge_request: mr, user: first_user)
+ end
+ end
+
+ let_it_be(:merge_request_with_group_user_approved) do
+ group = create(:group)
+ group.add_developer(group_user)
+
+ create(:merge_request, source_project: project, title: 'Bugfix6', source_branch: 'bugfix6').tap do |mr|
+ create(:approval, merge_request: mr, user: group_user)
+ end
+ end
+
+ context 'filtering by approved-by:none' do
+ it 'applies the filter' do
+ input_filtered_search('approved-by:=none')
+
+ expect(page).to have_issuable_counts(open: 1, closed: 0, all: 1)
+
+ expect(page).not_to have_content 'Bugfix5'
+ expect(page).not_to have_content 'Bugfix6'
+ expect(page).to have_content 'Bugfix3'
+ end
+ end
+
+ context 'filtering by approved-by:any' do
+ it 'applies the filter' do
+ input_filtered_search('approved-by:=any')
+
+ expect(page).to have_issuable_counts(open: 2, closed: 0, all: 2)
+
+ expect(page).to have_content 'Bugfix5'
+ expect(page).not_to have_content 'Bugfix3'
+ end
+ end
+
+ context 'filtering by approved-by:@username' do
+ it 'applies the filter' do
+ input_filtered_search("approved-by:=@#{first_user.username}")
+
+ expect(page).to have_issuable_counts(open: 1, closed: 0, all: 1)
+
+ expect(page).to have_content 'Bugfix5'
+ expect(page).not_to have_content 'Bugfix3'
+ end
+ end
+
+ context 'filtering by an approver from a group' do
+ it 'applies the filter' do
+ input_filtered_search("approved-by:=@#{group_user.username}")
+
+ expect(page).to have_issuable_counts(open: 1, closed: 0, all: 1)
+
+ expect(page).to have_content 'Bugfix6'
+ expect(page).not_to have_content 'Bugfix5'
+ expect(page).not_to have_content 'Bugfix3'
+ end
+ end
+ end
+end
diff --git a/spec/features/merge_requests/user_filters_by_deployments_spec.rb b/spec/features/merge_requests/user_filters_by_deployments_spec.rb
new file mode 100644
index 00000000000..157454d4e10
--- /dev/null
+++ b/spec/features/merge_requests/user_filters_by_deployments_spec.rb
@@ -0,0 +1,93 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Merge Requests > User filters by deployments', :js do
+ include FilteredSearchHelpers
+
+ let!(:project) { create(:project, :public, :repository) }
+ let!(:user) { project.creator }
+ let!(:gstg) { create(:environment, project: project, name: 'gstg') }
+ let!(:gprd) { create(:environment, project: project, name: 'gprd') }
+
+ let(:mr1) do
+ create(
+ :merge_request,
+ :simple,
+ :merged,
+ author: user,
+ source_project: project,
+ target_project: project
+ )
+ end
+
+ let(:mr2) do
+ create(
+ :merge_request,
+ :simple,
+ :merged,
+ author: user,
+ source_project: project,
+ target_project: project
+ )
+ end
+
+ let(:deploy1) do
+ create(
+ :deployment,
+ :success,
+ deployable: nil,
+ environment: gstg,
+ project: project,
+ sha: mr1.diff_head_sha,
+ finished_at: Time.utc(2020, 10, 1, 0, 0)
+ )
+ end
+
+ let(:deploy2) do
+ create(
+ :deployment,
+ :success,
+ deployable: nil,
+ environment: gprd,
+ project: project,
+ sha: mr2.diff_head_sha,
+ finished_at: Time.utc(2020, 10, 2, 0, 0)
+ )
+ end
+
+ before do
+ deploy1.link_merge_requests(MergeRequest.where(id: mr1.id))
+ deploy2.link_merge_requests(MergeRequest.where(id: mr2.id))
+
+ sign_in(user)
+ visit(project_merge_requests_path(project, state: :merged))
+ end
+
+ describe 'filtering by deployed-before' do
+ it 'applies the filter' do
+ input_filtered_search('deployed-before:=2020-10-02')
+
+ expect(page).to have_issuable_counts(open: 0, merged: 1, all: 1)
+ expect(page).to have_content mr1.title
+ end
+ end
+
+ describe 'filtering by deployed-after' do
+ it 'applies the filter' do
+ input_filtered_search('deployed-after:=2020-10-01')
+
+ expect(page).to have_issuable_counts(open: 0, merged: 1, all: 1)
+ expect(page).to have_content mr2.title
+ end
+ end
+
+ describe 'filtering by environment' do
+ it 'applies the filter' do
+ input_filtered_search('environment:=gstg')
+
+ expect(page).to have_issuable_counts(open: 0, merged: 1, all: 1)
+ expect(page).to have_content mr1.title
+ end
+ end
+end
diff --git a/spec/features/merge_requests/user_lists_merge_requests_spec.rb b/spec/features/merge_requests/user_lists_merge_requests_spec.rb
index 4531ef40901..36d28ae2822 100644
--- a/spec/features/merge_requests/user_lists_merge_requests_spec.rb
+++ b/spec/features/merge_requests/user_lists_merge_requests_spec.rb
@@ -8,6 +8,10 @@ RSpec.describe 'Merge requests > User lists merge requests' do
let(:project) { create(:project, :public, :repository) }
let(:user) { create(:user) }
+ let(:user2) { create(:user) }
+ let(:user3) { create(:user) }
+ let(:user4) { create(:user) }
+ let(:user5) { create(:user) }
before do
@fix = create(:merge_request,
@@ -15,6 +19,7 @@ RSpec.describe 'Merge requests > User lists merge requests' do
source_project: project,
source_branch: 'fix',
assignees: [user],
+ reviewers: [user, user2, user3, user4, user5],
milestone: create(:milestone, project: project, due_date: '2013-12-11'),
created_at: 1.minute.ago,
updated_at: 1.minute.ago)
@@ -23,6 +28,7 @@ RSpec.describe 'Merge requests > User lists merge requests' do
source_project: project,
source_branch: 'markdown',
assignees: [user],
+ reviewers: [user, user2, user3, user4],
milestone: create(:milestone, project: project, due_date: '2013-12-12'),
created_at: 2.minutes.ago,
updated_at: 2.minutes.ago)
@@ -34,6 +40,37 @@ RSpec.describe 'Merge requests > User lists merge requests' do
updated_at: 10.seconds.ago)
end
+ context 'when merge_request_reviewers is turned on' do
+ before do
+ stub_feature_flags(merge_request_reviewers: true)
+ visit_merge_requests(project, reviewer_id: user.id)
+ end
+
+ it 'has reviewers in MR list' do
+ expect(page).to have_css('.issuable-reviewers')
+ end
+
+ it 'shows reviewers avatar count badge if more_reviewers_count > 4' do
+ first_issuable_reviewers = first('.issuable-reviewers')
+
+ expect(first_issuable_reviewers).to have_content('2')
+ expect(first_issuable_reviewers).to have_css('.avatar-counter')
+ end
+
+ it 'does not show reviewers avatar count badge if more_reviewers_count <= 4' do
+ expect(page.all('.issuable-reviewers')[1]).not_to have_css('.avatar-counter')
+ end
+ end
+
+ context 'when merge_request_reviewers is turned false' do
+ it 'has no reviewers in MR list' do
+ stub_feature_flags(merge_request_reviewers: false)
+ visit_merge_requests(project, reviewer_id: user.id)
+
+ expect(page).not_to have_css('.issuable-reviewers')
+ end
+ end
+
it 'filters on no assignee' do
visit_merge_requests(project, assignee_id: IssuableFinder::Params::FILTER_NONE)
diff --git a/spec/features/milestone_spec.rb b/spec/features/milestone_spec.rb
index 4a7f14d5a1b..fefa2916c30 100644
--- a/spec/features/milestone_spec.rb
+++ b/spec/features/milestone_spec.rb
@@ -25,7 +25,7 @@ RSpec.describe 'Milestone' do
find('input[name="commit"]').click
- expect(find('.alert-success')).to have_content('Assign some issues to this milestone.')
+ expect(find('[data-testid="no-issues-alert"]')).to have_content('Assign some issues to this milestone.')
expect(page).to have_content('Nov 16, 2016–Dec 16, 2016')
end
end
@@ -37,7 +37,7 @@ RSpec.describe 'Milestone' do
create(:issue, title: "Bugfix1", project: project, milestone: milestone, state: "closed")
visit project_milestone_path(project, milestone)
- expect(find('.alert-success')).to have_content('All issues for this milestone are closed. You may close this milestone now.')
+ expect(find('[data-testid="all-issues-closed-alert"]')).to have_content('All issues for this milestone are closed. You may close this milestone now.')
end
end
diff --git a/spec/features/milestones/user_views_milestone_spec.rb b/spec/features/milestones/user_views_milestone_spec.rb
index 420f8d49483..9c19f842427 100644
--- a/spec/features/milestones/user_views_milestone_spec.rb
+++ b/spec/features/milestones/user_views_milestone_spec.rb
@@ -4,15 +4,27 @@ require 'spec_helper'
RSpec.describe "User views milestone" do
let_it_be(:user) { create(:user) }
- let_it_be(:project) { create(:project) }
- let_it_be(:milestone) { create(:milestone, project: project) }
+ let_it_be(:group) { create(:group) }
+ let_it_be(:project) { create(:project, :repository, group: group) }
+ let_it_be(:milestone) { create(:milestone, project: project, description: '**Lorem** _ipsum_ dolor sit [amet](https://example.com)') }
let_it_be(:labels) { create_list(:label, 2, project: project) }
- before do
+ before_all do
project.add_developer(user)
+ end
+
+ before do
sign_in(user)
end
+ context 'page description' do
+ before do
+ visit(project_milestone_path(project, milestone))
+ end
+
+ it_behaves_like 'page meta description', 'Lorem ipsum dolor sit amet'
+ end
+
it "avoids N+1 database queries" do
issue_params = { project: project, assignees: [user], author: user, milestone: milestone, labels: labels }.freeze
@@ -25,7 +37,7 @@ RSpec.describe "User views milestone" do
expect { visit_milestone }.not_to exceed_query_limit(control)
end
- context 'limiting milestone issues' do
+ context 'issues list', :js do
before_all do
2.times do
create(:issue, milestone: milestone, project: project)
@@ -34,6 +46,28 @@ RSpec.describe "User views milestone" do
end
end
+ context 'for a project milestone' do
+ it 'does not show the project name' do
+ visit(project_milestone_path(project, milestone))
+
+ wait_for_requests
+
+ expect(page.find('#tab-issues')).not_to have_text(project.name)
+ end
+ end
+
+ context 'for a group milestone' do
+ let(:group_milestone) { create(:milestone, group: group) }
+
+ it 'shows the project name' do
+ create(:issue, project: project, milestone: group_milestone)
+
+ visit(group_milestone_path(group, group_milestone))
+
+ expect(page.find('#tab-issues')).to have_text(project.name)
+ end
+ end
+
context 'when issues on milestone are over DISPLAY_ISSUES_LIMIT' do
it "limits issues to display and shows warning" do
stub_const('Milestoneish::DISPLAY_ISSUES_LIMIT', 3)
@@ -56,6 +90,40 @@ RSpec.describe "User views milestone" do
end
end
+ context 'merge requests list', :js do
+ context 'for a project milestone' do
+ it 'does not show the project name' do
+ create(:merge_request, source_project: project, milestone: milestone)
+
+ visit(project_milestone_path(project, milestone))
+
+ within('.js-milestone-tabs') do
+ click_link('Merge Requests')
+ end
+
+ wait_for_requests
+
+ expect(page.find('#tab-merge-requests')).not_to have_text(project.name)
+ end
+ end
+
+ context 'for a group milestone' do
+ let(:group_milestone) { create(:milestone, group: group) }
+
+ it 'shows the project name' do
+ create(:merge_request, source_project: project, milestone: group_milestone)
+
+ visit(group_milestone_path(group, group_milestone))
+
+ within('.js-milestone-tabs') do
+ click_link('Merge Requests')
+ end
+
+ expect(page.find('#tab-merge-requests')).to have_text(project.name)
+ end
+ end
+ end
+
private
def visit_milestone
diff --git a/spec/features/milestones/user_views_milestones_spec.rb b/spec/features/milestones/user_views_milestones_spec.rb
index 3f606577121..f8b4b802a60 100644
--- a/spec/features/milestones/user_views_milestones_spec.rb
+++ b/spec/features/milestones/user_views_milestones_spec.rb
@@ -21,7 +21,7 @@ RSpec.describe "User views milestones" do
.and have_content("Merge Requests")
end
- context "with issues" do
+ context "with issues", :js do
let_it_be(:issue) { create(:issue, project: project, milestone: milestone) }
let_it_be(:closed_issue) { create(:closed_issue, project: project, milestone: milestone) }
@@ -33,7 +33,6 @@ RSpec.describe "User views milestones" do
.and have_selector("#tab-issues li.issuable-row", count: 2)
.and have_content(issue.title)
.and have_content(closed_issue.title)
- .and have_selector("#tab-merge-requests")
end
end
diff --git a/spec/features/operations_sidebar_link_spec.rb b/spec/features/operations_sidebar_link_spec.rb
new file mode 100644
index 00000000000..32e2833dafb
--- /dev/null
+++ b/spec/features/operations_sidebar_link_spec.rb
@@ -0,0 +1,81 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Operations dropdown sidebar' do
+ let_it_be(:project) { create(:project, :repository) }
+ let(:user) { create(:user) }
+
+ before do
+ project.add_role(user, role)
+ sign_in(user)
+ visit project_issues_path(project)
+ end
+
+ context 'user has guest role' do
+ let(:role) { :guest }
+
+ it 'has the correct `Operations` menu items' do
+ expect(page).to have_link(title: 'Incidents', href: project_incidents_path(project))
+
+ expect(page).not_to have_link(title: 'Metrics', href: project_metrics_dashboard_path(project))
+ expect(page).not_to have_link(title: 'Alerts', href: project_alert_management_index_path(project))
+ expect(page).not_to have_link(title: 'Environments', href: project_environments_path(project))
+ expect(page).not_to have_link(title: 'Error Tracking', href: project_error_tracking_index_path(project))
+ expect(page).not_to have_link(title: 'Product Analytics', href: project_product_analytics_path(project))
+ expect(page).not_to have_link(title: 'Serverless', href: project_serverless_functions_path(project))
+ expect(page).not_to have_link(title: 'Logs', href: project_logs_path(project))
+ expect(page).not_to have_link(title: 'Kubernetes', href: project_clusters_path(project))
+ end
+ end
+
+ context 'user has reporter role' do
+ let(:role) { :reporter }
+
+ it 'has the correct `Operations` menu items' do
+ expect(page).to have_link(title: 'Metrics', href: project_metrics_dashboard_path(project))
+ expect(page).to have_link(title: 'Incidents', href: project_incidents_path(project))
+ expect(page).to have_link(title: 'Environments', href: project_environments_path(project))
+ expect(page).to have_link(title: 'Error Tracking', href: project_error_tracking_index_path(project))
+ expect(page).to have_link(title: 'Product Analytics', href: project_product_analytics_path(project))
+
+ expect(page).not_to have_link(title: 'Alerts', href: project_alert_management_index_path(project))
+ expect(page).not_to have_link(title: 'Serverless', href: project_serverless_functions_path(project))
+ expect(page).not_to have_link(title: 'Logs', href: project_logs_path(project))
+ expect(page).not_to have_link(title: 'Kubernetes', href: project_clusters_path(project))
+ end
+ end
+
+ context 'user has developer role' do
+ let(:role) { :developer }
+
+ it 'has the correct `Operations` menu items' do
+ expect(page).to have_link(title: 'Metrics', href: project_metrics_dashboard_path(project))
+ expect(page).to have_link(title: 'Alerts', href: project_alert_management_index_path(project))
+ expect(page).to have_link(title: 'Incidents', href: project_incidents_path(project))
+ expect(page).to have_link(title: 'Environments', href: project_environments_path(project))
+ expect(page).to have_link(title: 'Error Tracking', href: project_error_tracking_index_path(project))
+ expect(page).to have_link(title: 'Product Analytics', href: project_product_analytics_path(project))
+ expect(page).to have_link(title: 'Logs', href: project_logs_path(project))
+
+ expect(page).not_to have_link(title: 'Serverless', href: project_serverless_functions_path(project))
+ expect(page).not_to have_link(title: 'Kubernetes', href: project_clusters_path(project))
+ end
+ end
+
+ context 'user has maintainer role' do
+ let(:role) { :maintainer }
+
+ it 'has the correct `Operations` menu items' do
+ expect(page).to have_link(title: 'Metrics', href: project_metrics_dashboard_path(project))
+ expect(page).to have_link(title: 'Alerts', href: project_alert_management_index_path(project))
+ expect(page).to have_link(title: 'Incidents', href: project_incidents_path(project))
+ expect(page).to have_link(title: 'Environments', href: project_environments_path(project))
+ expect(page).to have_link(title: 'Error Tracking', href: project_error_tracking_index_path(project))
+ expect(page).to have_link(title: 'Product Analytics', href: project_product_analytics_path(project))
+ expect(page).to have_link(title: 'Serverless', href: project_serverless_functions_path(project))
+ expect(page).to have_link(title: 'Logs', href: project_logs_path(project))
+ expect(page).to have_link(title: 'Kubernetes', href: project_clusters_path(project))
+ end
+ end
+end
diff --git a/spec/features/profiles/keys_spec.rb b/spec/features/profiles/keys_spec.rb
index b5e784a749f..23bbe9c1587 100644
--- a/spec/features/profiles/keys_spec.rb
+++ b/spec/features/profiles/keys_spec.rb
@@ -71,21 +71,35 @@ RSpec.describe 'Profile > SSH Keys' do
expect(page).to have_content(key.title)
end
- it 'User removes a key via the key index' do
- create(:key, user: user)
- visit profile_keys_path
+ describe 'User removes a key', :js do
+ shared_examples 'removes key' do
+ it 'removes key' do
+ visit path
+ click_button('Delete')
- click_link('Remove')
+ page.within('.modal') do
+ page.click_button('Delete')
+ end
- expect(page).to have_content('Your SSH keys (0)')
- end
+ expect(page).to have_content('Your SSH keys (0)')
+ end
+ end
- it 'User removes a key via its details page' do
- key = create(:key, user: user)
- visit profile_key_path(key)
+ context 'via the key index' do
+ before do
+ create(:key, user: user)
+ end
+
+ let(:path) { profile_keys_path }
- click_link('Remove')
+ it_behaves_like 'removes key'
+ end
- expect(page).to have_content('Your SSH keys (0)')
+ context 'via its details page' do
+ let(:key) { create(:key, user: user) }
+ let(:path) { profile_keys_path(key) }
+
+ it_behaves_like 'removes key'
+ end
end
end
diff --git a/spec/features/projects/activity/user_sees_design_comment_spec.rb b/spec/features/projects/activity/user_sees_design_comment_spec.rb
index e60deba65f0..3a8e2790858 100644
--- a/spec/features/projects/activity/user_sees_design_comment_spec.rb
+++ b/spec/features/projects/activity/user_sees_design_comment_spec.rb
@@ -12,7 +12,7 @@ RSpec.describe 'Projects > Activity > User sees design comment', :js do
let_it_be(:design) { create(:design, issue: issue) }
let(:design_activity) do
- "#{commenter.name} #{commenter.to_reference} commented on design"
+ "#{commenter.name} #{commenter.to_reference} commented on design #{design.to_reference}"
end
let(:issue_activity) do
diff --git a/spec/features/projects/badges/list_spec.rb b/spec/features/projects/badges/list_spec.rb
index 3382bdcd65f..d1e635f11c0 100644
--- a/spec/features/projects/badges/list_spec.rb
+++ b/spec/features/projects/badges/list_spec.rb
@@ -17,10 +17,10 @@ RSpec.describe 'list of badges' do
expect(page).to have_content 'Markdown'
expect(page).to have_content 'HTML'
expect(page).to have_content 'AsciiDoc'
- expect(page).to have_css('.highlight', count: 3)
+ expect(page).to have_css('.js-syntax-highlight', count: 3)
expect(page).to have_xpath("//img[@alt='pipeline status']")
- page.within('.highlight', match: :first) do
+ page.within('.js-syntax-highlight', match: :first) do
expect(page).to have_content 'badges/master/pipeline.svg'
end
end
@@ -32,10 +32,10 @@ RSpec.describe 'list of badges' do
expect(page).to have_content 'Markdown'
expect(page).to have_content 'HTML'
expect(page).to have_content 'AsciiDoc'
- expect(page).to have_css('.highlight', count: 3)
+ expect(page).to have_css('.js-syntax-highlight', count: 3)
expect(page).to have_xpath("//img[@alt='coverage report']")
- page.within('.highlight', match: :first) do
+ page.within('.js-syntax-highlight', match: :first) do
expect(page).to have_content 'badges/master/coverage.svg'
end
end
diff --git a/spec/features/projects/blobs/edit_spec.rb b/spec/features/projects/blobs/edit_spec.rb
index 5aca994f53e..c30c8dda852 100644
--- a/spec/features/projects/blobs/edit_spec.rb
+++ b/spec/features/projects/blobs/edit_spec.rb
@@ -4,6 +4,7 @@ require 'spec_helper'
RSpec.describe 'Editing file blob', :js do
include TreeHelper
+ include BlobSpecHelpers
let(:project) { create(:project, :public, :repository) }
let(:merge_request) { create(:merge_request, source_project: project, source_branch: 'feature', target_branch: 'master') }
@@ -20,9 +21,18 @@ RSpec.describe 'Editing file blob', :js do
sign_in(user)
end
- def edit_and_commit(commit_changes: true)
+ def edit_and_commit(commit_changes: true, is_diff: false)
+ set_default_button('edit')
+ refresh
wait_for_requests
- find('.js-edit-blob').click
+
+ if is_diff
+ first('.js-diff-more-actions').click
+ click_link('Edit in single-file editor')
+ else
+ click_link('Edit')
+ end
+
fill_editor(content: 'class NextFeature\\nend\\n')
if commit_changes
@@ -38,7 +48,7 @@ RSpec.describe 'Editing file blob', :js do
context 'from MR diff' do
before do
visit diffs_project_merge_request_path(project, merge_request)
- edit_and_commit
+ edit_and_commit(is_diff: true)
end
it 'returns me to the mr' do
diff --git a/spec/features/projects/blobs/user_creates_new_blob_in_new_project_spec.rb b/spec/features/projects/blobs/user_creates_new_blob_in_new_project_spec.rb
index a271a4f43a8..fda2992af8d 100644
--- a/spec/features/projects/blobs/user_creates_new_blob_in_new_project_spec.rb
+++ b/spec/features/projects/blobs/user_creates_new_blob_in_new_project_spec.rb
@@ -2,7 +2,9 @@
require 'spec_helper'
-RSpec.describe 'User creates blob in new project', :js do
+RSpec.describe 'User creates new blob', :js do
+ include WebIdeSpecHelpers
+
let(:user) { create(:user) }
let(:project) { create(:project, :empty_repo) }
@@ -12,16 +14,19 @@ RSpec.describe 'User creates blob in new project', :js do
visit project_path(project)
end
- it 'allows the user to add a new file' do
+ it 'allows the user to add a new file in Web IDE' do
click_link 'New file'
- execute_script("monaco.editor.getModels()[0].setValue('Hello world')")
+ wait_for_requests
+
+ ide_create_new_file('dummy-file', content: "Hello world\n")
- fill_in(:file_name, with: 'dummy-file')
+ ide_commit
- click_button('Commit changes')
+ click_button('Commit')
- expect(page).to have_content('The file has been successfully created')
+ expect(page).to have_content('All changes are committed')
+ expect(project.repository.blob_at('master', 'dummy-file').data).to eql("Hello world\n")
end
end
diff --git a/spec/features/projects/blobs/user_follows_pipeline_suggest_nudge_spec.rb b/spec/features/projects/blobs/user_follows_pipeline_suggest_nudge_spec.rb
index 8b43687c71c..023e00a3e02 100644
--- a/spec/features/projects/blobs/user_follows_pipeline_suggest_nudge_spec.rb
+++ b/spec/features/projects/blobs/user_follows_pipeline_suggest_nudge_spec.rb
@@ -10,7 +10,7 @@ RSpec.describe 'User follows pipeline suggest nudge spec when feature is enabled
describe 'viewing the new blob page' do
before do
- stub_feature_flags(suggest_pipeline: true)
+ stub_experiment_for_user(suggest_pipeline: true)
sign_in(user)
end
diff --git a/spec/features/projects/branches/user_deletes_branch_spec.rb b/spec/features/projects/branches/user_deletes_branch_spec.rb
index 21a1d31bad4..c480c41709c 100644
--- a/spec/features/projects/branches/user_deletes_branch_spec.rb
+++ b/spec/features/projects/branches/user_deletes_branch_spec.rb
@@ -17,7 +17,7 @@ RSpec.describe "User deletes branch", :js do
fill_in("branch-search", with: "improve/awesome").native.send_keys(:enter)
page.within(".js-branch-improve\\/awesome") do
- accept_alert { find(".btn-remove").click }
+ accept_alert { find(".btn-danger").click }
end
wait_for_requests
diff --git a/spec/features/projects/branches_spec.rb b/spec/features/projects/branches_spec.rb
index 0e2444c5434..dcad7ee66a3 100644
--- a/spec/features/projects/branches_spec.rb
+++ b/spec/features/projects/branches_spec.rb
@@ -21,11 +21,11 @@ RSpec.describe 'Branches' do
before do
# Add 4 stale branches
(1..4).reverse_each do |i|
- Timecop.freeze((threshold + i).ago) { create_file(message: "a commit in stale-#{i}", branch_name: "stale-#{i}") }
+ travel_to((threshold + i).ago) { create_file(message: "a commit in stale-#{i}", branch_name: "stale-#{i}") }
end
# Add 6 active branches
(1..6).each do |i|
- Timecop.freeze((threshold - i).ago) { create_file(message: "a commit in active-#{i}", branch_name: "active-#{i}") }
+ travel_to((threshold - i).ago) { create_file(message: "a commit in active-#{i}", branch_name: "active-#{i}") }
end
end
@@ -101,7 +101,7 @@ RSpec.describe 'Branches' do
visit project_branches_filtered_path(project, state: 'all')
expect(all('.all-branches').last).to have_selector('li', count: 20)
- accept_confirm { first('.js-branch-item .btn-remove').click }
+ accept_confirm { first('.js-branch-item .btn-danger').click }
expect(all('.all-branches').last).to have_selector('li', count: 19)
end
@@ -163,7 +163,7 @@ RSpec.describe 'Branches' do
expect(page).to have_content('fix')
expect(find('.all-branches')).to have_selector('li', count: 1)
- accept_confirm { find('.js-branch-fix .btn-remove').click }
+ accept_confirm { find('.js-branch-fix .btn-danger').click }
expect(page).not_to have_content('fix')
expect(find('.all-branches')).to have_selector('li', count: 0)
diff --git a/spec/features/projects/ci/lint_spec.rb b/spec/features/projects/ci/lint_spec.rb
index ce435151b84..eb2efb4357d 100644
--- a/spec/features/projects/ci/lint_spec.rb
+++ b/spec/features/projects/ci/lint_spec.rb
@@ -8,117 +8,88 @@ RSpec.describe 'CI Lint', :js do
let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
- shared_examples 'correct ci linting process' do
- describe 'YAML parsing' do
- shared_examples 'validates the YAML' do
- before do
- stub_feature_flags(ci_lint_vue: false)
- click_on 'Validate'
- end
+ let(:content_selector) { '.content .view-lines' }
- context 'YAML is correct' do
- let(:yaml_content) do
- File.read(Rails.root.join('spec/support/gitlab_stubs/gitlab_ci.yml'))
- end
+ before do
+ stub_feature_flags(ci_lint_vue: false)
+ project.add_developer(user)
+ sign_in(user)
- it 'parses Yaml and displays the jobs' do
- expect(page).to have_content('Status: syntax is correct')
+ visit project_ci_lint_path(project)
+ editor_set_value(yaml_content)
- within "table" do
- aggregate_failures do
- expect(page).to have_content('Job - rspec')
- expect(page).to have_content('Job - spinach')
- expect(page).to have_content('Deploy Job - staging')
- expect(page).to have_content('Deploy Job - production')
- end
- end
- end
- end
+ wait_for('YAML content') do
+ find(content_selector).text.present?
+ end
+ end
- context 'YAML is incorrect' do
- let(:yaml_content) { 'value: cannot have :' }
+ describe 'YAML parsing' do
+ shared_examples 'validates the YAML' do
+ before do
+ stub_feature_flags(ci_lint_vue: false)
+ click_on 'Validate'
+ end
- it 'displays information about an error' do
- expect(page).to have_content('Status: syntax is incorrect')
- expect(page).to have_selector(content_selector, text: yaml_content)
- end
+ context 'YAML is correct' do
+ let(:yaml_content) do
+ File.read(Rails.root.join('spec/support/gitlab_stubs/gitlab_ci.yml'))
end
- end
- it_behaves_like 'validates the YAML'
+ it 'parses Yaml and displays the jobs' do
+ expect(page).to have_content('Status: syntax is correct')
- context 'when Dry Run is checked' do
- before do
- check 'Simulate a pipeline created for the default branch'
+ within "table" do
+ aggregate_failures do
+ expect(page).to have_content('Job - rspec')
+ expect(page).to have_content('Job - spinach')
+ expect(page).to have_content('Deploy Job - staging')
+ expect(page).to have_content('Deploy Job - production')
+ end
+ end
end
-
- it_behaves_like 'validates the YAML'
end
- describe 'YAML revalidate' do
- let(:yaml_content) { 'my yaml content' }
+ context 'YAML is incorrect' do
+ let(:yaml_content) { 'value: cannot have :' }
- it 'loads previous YAML content after validation' do
- expect(page).to have_field('content', with: 'my yaml content', visible: false, type: 'textarea')
+ it 'displays information about an error' do
+ expect(page).to have_content('Status: syntax is incorrect')
+ expect(page).to have_selector(content_selector, text: yaml_content)
end
end
end
- describe 'YAML clearing' do
+ it_behaves_like 'validates the YAML'
+
+ context 'when Dry Run is checked' do
before do
- click_on 'Clear'
+ check 'Simulate a pipeline created for the default branch'
end
- context 'YAML is present' do
- let(:yaml_content) do
- File.read(Rails.root.join('spec/support/gitlab_stubs/gitlab_ci.yml'))
- end
-
- it 'YAML content is cleared' do
- expect(page).to have_field('content', with: '', visible: false, type: 'textarea')
- end
- end
+ it_behaves_like 'validates the YAML'
end
- end
- context 'with ACE editor' do
- it_behaves_like 'correct ci linting process' do
- let(:content_selector) { '.ace_content' }
+ describe 'YAML revalidate' do
+ let(:yaml_content) { 'my yaml content' }
- before do
- stub_feature_flags(monaco_ci: false)
- stub_feature_flags(ci_lint_vue: false)
- project.add_developer(user)
- sign_in(user)
-
- visit project_ci_lint_path(project)
- find('#ci-editor')
- execute_script("ace.edit('ci-editor').setValue(#{yaml_content.to_json});")
-
- # Ace editor updates a hidden textarea and it happens asynchronously
- wait_for('YAML content') do
- find(content_selector).text.present?
- end
+ it 'loads previous YAML content after validation' do
+ expect(page).to have_field('content', with: 'my yaml content', visible: false, type: 'textarea')
end
end
end
- context 'with Editor Lite' do
- it_behaves_like 'correct ci linting process' do
- let(:content_selector) { '.content .view-lines' }
-
- before do
- stub_feature_flags(monaco_ci: true)
- stub_feature_flags(ci_lint_vue: false)
- project.add_developer(user)
- sign_in(user)
+ describe 'YAML clearing' do
+ before do
+ click_on 'Clear'
+ end
- visit project_ci_lint_path(project)
- editor_set_value(yaml_content)
+ context 'YAML is present' do
+ let(:yaml_content) do
+ File.read(Rails.root.join('spec/support/gitlab_stubs/gitlab_ci.yml'))
+ end
- wait_for('YAML content') do
- find(content_selector).text.present?
- end
+ it 'YAML content is cleared' do
+ expect(page).to have_field('content', with: '', visible: false, type: 'textarea')
end
end
end
diff --git a/spec/features/projects/clusters/eks_spec.rb b/spec/features/projects/clusters/eks_spec.rb
index c5feef6c6f3..9f3f331cfab 100644
--- a/spec/features/projects/clusters/eks_spec.rb
+++ b/spec/features/projects/clusters/eks_spec.rb
@@ -19,7 +19,7 @@ RSpec.describe 'AWS EKS Cluster', :js do
before do
visit project_clusters_path(project)
- click_link 'Add Kubernetes cluster'
+ click_link 'Integrate with a cluster certificate'
end
context 'when user creates a cluster on AWS EKS' do
diff --git a/spec/features/projects/clusters/gcp_spec.rb b/spec/features/projects/clusters/gcp_spec.rb
index 04339d20d77..a0519d88532 100644
--- a/spec/features/projects/clusters/gcp_spec.rb
+++ b/spec/features/projects/clusters/gcp_spec.rb
@@ -33,7 +33,7 @@ RSpec.describe 'Gcp Cluster', :js, :do_not_mock_admin_mode do
before do
visit project_clusters_path(project)
- click_link 'Add Kubernetes cluster'
+ click_link 'Integrate with a cluster certificate'
click_link 'Create new cluster'
click_link 'Google GKE'
end
@@ -143,7 +143,7 @@ RSpec.describe 'Gcp Cluster', :js, :do_not_mock_admin_mode do
before do
visit project_clusters_path(project)
- click_link 'Add Kubernetes cluster'
+ click_link 'Connect cluster with certificate'
click_link 'Connect existing cluster'
end
@@ -162,7 +162,7 @@ RSpec.describe 'Gcp Cluster', :js, :do_not_mock_admin_mode do
it 'user sees creation form with the successful message' do
expect(page).to have_content('Kubernetes cluster integration was successfully removed.')
- expect(page).to have_link('Add Kubernetes cluster')
+ expect(page).to have_link('Integrate with a cluster certificate')
end
end
end
@@ -178,7 +178,7 @@ RSpec.describe 'Gcp Cluster', :js, :do_not_mock_admin_mode do
end
it 'user sees offer on cluster create page' do
- click_link 'Add Kubernetes cluster'
+ click_link 'Integrate with a cluster certificate'
expect(page).to have_css('.gcp-signup-offer')
end
@@ -192,10 +192,10 @@ RSpec.describe 'Gcp Cluster', :js, :do_not_mock_admin_mode do
it 'user does not see offer after dismissing' do
expect(page).to have_css('.gcp-signup-offer')
- find('.gcp-signup-offer .close').click
+ find('.gcp-signup-offer .js-close').click
wait_for_requests
- click_link 'Add Kubernetes cluster'
+ click_link 'Integrate with a cluster certificate'
expect(page).not_to have_css('.gcp-signup-offer')
end
diff --git a/spec/features/projects/clusters/user_spec.rb b/spec/features/projects/clusters/user_spec.rb
index 9d0dc65093e..748eba558aa 100644
--- a/spec/features/projects/clusters/user_spec.rb
+++ b/spec/features/projects/clusters/user_spec.rb
@@ -25,7 +25,7 @@ RSpec.describe 'User Cluster', :js do
before do
visit project_clusters_path(project)
- click_link 'Add Kubernetes cluster'
+ click_link 'Integrate with a cluster certificate'
click_link 'Connect existing cluster'
end
@@ -52,6 +52,10 @@ RSpec.describe 'User Cluster', :js do
it 'user sees RBAC is enabled by default' do
expect(page).to have_checked_field('RBAC-enabled cluster')
end
+
+ it 'user sees namespace per environment is enabled by default' do
+ expect(page).to have_checked_field('Namespace per environment')
+ end
end
context 'when user filled form with invalid parameters' do
@@ -112,7 +116,7 @@ RSpec.describe 'User Cluster', :js do
it 'user sees creation form with the successful message' do
expect(page).to have_content('Kubernetes cluster integration was successfully removed.')
- expect(page).to have_link('Add Kubernetes cluster')
+ expect(page).to have_link('Integrate with a cluster certificate')
end
end
end
diff --git a/spec/features/projects/clusters_spec.rb b/spec/features/projects/clusters_spec.rb
index d674fbc457e..6c6e65005f6 100644
--- a/spec/features/projects/clusters_spec.rb
+++ b/spec/features/projects/clusters_spec.rb
@@ -11,7 +11,6 @@ RSpec.describe 'Clusters', :js do
before do
project.add_maintainer(user)
gitlab_sign_in(user)
- stub_feature_flags(clusters_list_redesign: false)
end
context 'when user does not have a cluster and visits cluster index page' do
@@ -20,7 +19,7 @@ RSpec.describe 'Clusters', :js do
end
it 'sees empty state' do
- expect(page).to have_link('Add Kubernetes cluster')
+ expect(page).to have_link('Integrate with a cluster certificate')
expect(page).to have_selector('.empty-state')
end
end
@@ -42,7 +41,7 @@ RSpec.describe 'Clusters', :js do
context 'when user filled form with environment scope' do
before do
- click_link 'Add Kubernetes cluster'
+ click_link 'Connect cluster with certificate'
click_link 'Connect existing cluster'
fill_in 'cluster_name', with: 'staging-cluster'
fill_in 'cluster_environment_scope', with: 'staging/*'
@@ -71,7 +70,7 @@ RSpec.describe 'Clusters', :js do
context 'when user updates duplicated environment scope' do
before do
- click_link 'Add Kubernetes cluster'
+ click_link 'Connect cluster with certificate'
click_link 'Connect existing cluster'
fill_in 'cluster_name', with: 'staging-cluster'
fill_in 'cluster_environment_scope', with: '*'
@@ -117,7 +116,7 @@ RSpec.describe 'Clusters', :js do
context 'when user filled form with environment scope' do
before do
- click_link 'Add Kubernetes cluster'
+ click_link 'Connect cluster with certificate'
click_link 'Create new cluster'
click_link 'Google GKE'
@@ -162,7 +161,7 @@ RSpec.describe 'Clusters', :js do
context 'when user updates duplicated environment scope' do
before do
- click_link 'Add Kubernetes cluster'
+ click_link 'Connect cluster with certificate'
click_link 'Create new cluster'
click_link 'Google GKE'
@@ -196,8 +195,7 @@ RSpec.describe 'Clusters', :js do
end
it 'user sees a table with one cluster' do
- # One is the header row, the other the cluster row
- expect(page).to have_selector('.gl-responsive-table-row', count: 2)
+ expect(page).to have_selector('[data-testid="cluster_list_table"] tbody tr', count: 1)
end
context 'when user clicks on a cluster' do
@@ -216,7 +214,7 @@ RSpec.describe 'Clusters', :js do
before do
visit project_clusters_path(project)
- click_link 'Add Kubernetes cluster'
+ click_link 'Integrate with a cluster certificate'
click_link 'Create new cluster'
end
diff --git a/spec/features/projects/commit/builds_spec.rb b/spec/features/projects/commit/builds_spec.rb
index f97abc5bd8b..00ec9d49a10 100644
--- a/spec/features/projects/commit/builds_spec.rb
+++ b/spec/features/projects/commit/builds_spec.rb
@@ -19,7 +19,7 @@ RSpec.describe 'project commit pipelines', :js do
context 'when no builds triggered yet' do
it 'shows the ID of the first pipeline' do
- page.within('.table-holder') do
+ page.within('.pipelines .ci-table') do
expect(page).to have_content project.ci_pipelines[0].id # pipeline ids
end
end
diff --git a/spec/features/projects/commit/user_comments_on_commit_spec.rb b/spec/features/projects/commit/user_comments_on_commit_spec.rb
index 87a022d74a3..0fa4975bb25 100644
--- a/spec/features/projects/commit/user_comments_on_commit_spec.rb
+++ b/spec/features/projects/commit/user_comments_on_commit_spec.rb
@@ -6,19 +6,22 @@ RSpec.describe "User comments on commit", :js do
include Spec::Support::Helpers::Features::NotesHelpers
include RepoHelpers
- let(:project) { create(:project, :repository) }
- let(:user) { create(:user) }
+ let_it_be(:project) { create(:project, :repository) }
+ let_it_be(:user) { create(:user) }
let(:comment_text) { "XML attached" }
- before do
- sign_in(user)
+ before_all do
project.add_developer(user)
+ end
- visit(project_commit_path(project, sample_commit.id))
+ before do
+ sign_in(user)
end
context "when adding new comment" do
it "adds comment" do
+ visit(project_commit_path(project, sample_commit.id))
+
emoji_code = ":+1:"
page.within(".js-main-target-form") do
@@ -57,6 +60,8 @@ RSpec.describe "User comments on commit", :js do
context "when editing comment" do
before do
+ visit(project_commit_path(project, sample_commit.id))
+
add_note(comment_text)
end
@@ -87,6 +92,8 @@ RSpec.describe "User comments on commit", :js do
context "when deleting comment" do
before do
+ visit(project_commit_path(project, sample_commit.id))
+
add_note(comment_text)
end
@@ -108,4 +115,35 @@ RSpec.describe "User comments on commit", :js do
expect(page).not_to have_css(".note")
end
end
+
+ context 'when checking task lists' do
+ let(:note_with_task) do
+ <<-EOT.strip_heredoc
+
+ - [ ] Task 1
+ EOT
+ end
+
+ before do
+ create(:note_on_commit, project: project, commit_id: sample_commit.id, note: note_with_task, author: user)
+ create(:note_on_commit, project: project, commit_id: sample_commit.id, note: note_with_task, author: user)
+
+ visit(project_commit_path(project, sample_commit.id))
+ end
+
+ it 'allows the tasks to be checked' do
+ expect(page).to have_selector('li.task-list-item', count: 2)
+ expect(page).to have_selector('li.task-list-item input[checked]', count: 0)
+
+ all('.task-list-item-checkbox').each do |checkbox|
+ checkbox.click
+ end
+ wait_for_requests
+
+ visit(project_commit_path(project, sample_commit.id))
+
+ expect(page).to have_selector('li.task-list-item', count: 2)
+ expect(page).to have_selector('li.task-list-item input[checked]', count: 2)
+ end
+ end
end
diff --git a/spec/features/projects/compare_spec.rb b/spec/features/projects/compare_spec.rb
index 865ae3ad8cb..e387ea4d473 100644
--- a/spec/features/projects/compare_spec.rb
+++ b/spec/features/projects/compare_spec.rb
@@ -113,7 +113,7 @@ RSpec.describe "Compare", :js do
click_button('Compare')
- page.within('.alert') do
+ page.within('.gl-alert') do
expect(page).to have_text("Too many changes to show. To preserve performance only 3 of 3+ files are displayed.")
end
end
diff --git a/spec/features/projects/environments/environment_spec.rb b/spec/features/projects/environments/environment_spec.rb
index fa10e429af2..1d7be7fa7a3 100644
--- a/spec/features/projects/environments/environment_spec.rb
+++ b/spec/features/projects/environments/environment_spec.rb
@@ -333,7 +333,7 @@ RSpec.describe 'Environment' do
visit project_branches_filtered_path(project, state: 'all', search: 'feature')
remove_branch_with_hooks(project, user, 'feature') do
- page.within('.js-branch-feature') { find('a.btn-remove').click }
+ page.within('.js-branch-feature') { find('a.btn-danger').click }
end
visit_environment(environment)
diff --git a/spec/features/projects/environments/environments_spec.rb b/spec/features/projects/environments/environments_spec.rb
index 7f2ef61bcbe..8c032660726 100644
--- a/spec/features/projects/environments/environments_spec.rb
+++ b/spec/features/projects/environments/environments_spec.rb
@@ -372,7 +372,7 @@ RSpec.describe 'Environments page', :js do
let(:role) { :developer }
it 'developer creates a new environment with a valid name' do
- within(".top-area") { click_link 'New environment' }
+ within(".environments-section") { click_link 'New environment' }
fill_in('Name', with: 'production')
click_on 'Save'
@@ -380,7 +380,7 @@ RSpec.describe 'Environments page', :js do
end
it 'developer creates a new environmetn with invalid name' do
- within(".top-area") { click_link 'New environment' }
+ within(".environments-section") { click_link 'New environment' }
fill_in('Name', with: 'name,with,commas')
click_on 'Save'
diff --git a/spec/features/projects/feature_flag_user_lists/user_deletes_feature_flag_user_list_spec.rb b/spec/features/projects/feature_flag_user_lists/user_deletes_feature_flag_user_list_spec.rb
new file mode 100644
index 00000000000..2a81c706525
--- /dev/null
+++ b/spec/features/projects/feature_flag_user_lists/user_deletes_feature_flag_user_list_spec.rb
@@ -0,0 +1,63 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'User deletes feature flag user list', :js do
+ let_it_be(:project) { create(:project) }
+ let_it_be(:developer) { create(:user) }
+
+ before do
+ project.add_developer(developer)
+ sign_in(developer)
+ end
+
+ context 'with a list' do
+ before do
+ create(:operations_feature_flag_user_list, project: project, name: 'My List')
+ end
+
+ it 'deletes the list' do
+ visit(project_feature_flags_path(project, scope: 'userLists'))
+
+ delete_user_list_button.click
+ delete_user_list_modal_confirmation_button.click
+
+ expect(page).to have_text('Lists 0')
+ end
+ end
+
+ context 'with a list that is in use' do
+ before do
+ list = create(:operations_feature_flag_user_list, project: project, name: 'My List')
+ feature_flag = create(:operations_feature_flag, :new_version_flag, project: project)
+ create(:operations_strategy, feature_flag: feature_flag, name: 'gitlabUserList', user_list: list)
+ end
+
+ it 'does not delete the list' do
+ visit(project_feature_flags_path(project, scope: 'userLists'))
+
+ delete_user_list_button.click
+ delete_user_list_modal_confirmation_button.click
+
+ expect(page).to have_text('User list is associated with a strategy')
+ expect(page).to have_text('Lists 1')
+ expect(page).to have_text('My List')
+
+ alert_dismiss_button.click
+
+ expect(page).not_to have_text('User list is associated with a strategy')
+ end
+ end
+
+ def delete_user_list_button
+ find("button[data-testid='delete-user-list']")
+ end
+
+ def delete_user_list_modal_confirmation_button
+ find("button[data-testid='modal-confirm']")
+ end
+
+ def alert_dismiss_button
+ find("div[data-testid='serverErrors'] button")
+ end
+end
diff --git a/spec/features/projects/feature_flag_user_lists/user_edits_feature_flag_user_list_spec.rb b/spec/features/projects/feature_flag_user_lists/user_edits_feature_flag_user_list_spec.rb
new file mode 100644
index 00000000000..b37c2780827
--- /dev/null
+++ b/spec/features/projects/feature_flag_user_lists/user_edits_feature_flag_user_list_spec.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'User edits feature flag user list', :js do
+ let_it_be(:project) { create(:project) }
+ let_it_be(:developer) { create(:user) }
+
+ before do
+ project.add_developer(developer)
+ sign_in(developer)
+ end
+
+ it 'prefills the edit form with the list name' do
+ list = create(:operations_feature_flag_user_list, project: project, name: 'My List Name')
+
+ visit(edit_project_feature_flags_user_list_path(project, list))
+
+ expect(page).to have_field 'Name', with: 'My List Name'
+ end
+end
diff --git a/spec/features/projects/feature_flag_user_lists/user_sees_feature_flag_user_list_details_spec.rb b/spec/features/projects/feature_flag_user_lists/user_sees_feature_flag_user_list_details_spec.rb
new file mode 100644
index 00000000000..dfebe6408bd
--- /dev/null
+++ b/spec/features/projects/feature_flag_user_lists/user_sees_feature_flag_user_list_details_spec.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'User sees feature flag user list details', :js do
+ let_it_be(:project) { create(:project) }
+ let_it_be(:developer) { create(:user) }
+
+ before do
+ project.add_developer(developer)
+ sign_in(developer)
+ end
+
+ it 'displays the list name' do
+ list = create(:operations_feature_flag_user_list, project: project, name: 'My List')
+
+ visit(project_feature_flags_user_list_path(project, list))
+
+ expect(page).to have_text('My List')
+ end
+end
diff --git a/spec/features/projects/feature_flags/user_creates_feature_flag_spec.rb b/spec/features/projects/feature_flags/user_creates_feature_flag_spec.rb
new file mode 100644
index 00000000000..830dda737b0
--- /dev/null
+++ b/spec/features/projects/feature_flags/user_creates_feature_flag_spec.rb
@@ -0,0 +1,200 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'User creates feature flag', :js do
+ include FeatureFlagHelpers
+
+ let(:user) { create(:user) }
+ let(:project) { create(:project, namespace: user.namespace) }
+
+ before do
+ project.add_developer(user)
+ stub_feature_flags(feature_flag_permissions: false)
+ sign_in(user)
+ end
+
+ it 'user creates a flag enabled for user ids' do
+ visit(new_project_feature_flag_path(project))
+ set_feature_flag_info('test_feature', 'Test feature')
+ within_strategy_row(1) do
+ select 'User IDs', from: 'Type'
+ fill_in 'User IDs', with: 'user1, user2'
+ environment_plus_button.click
+ environment_search_input.set('production')
+ environment_search_results.first.click
+ end
+ click_button 'Create feature flag'
+
+ expect_user_to_see_feature_flags_index_page
+ expect(page).to have_text('test_feature')
+ end
+
+ it 'user creates a flag with default environment scopes' do
+ visit(new_project_feature_flag_path(project))
+ set_feature_flag_info('test_flag', 'Test flag')
+ within_strategy_row(1) do
+ select 'All users', from: 'Type'
+ end
+ click_button 'Create feature flag'
+
+ expect_user_to_see_feature_flags_index_page
+ expect(page).to have_text('test_flag')
+
+ edit_feature_flag_button.click
+
+ within_strategy_row(1) do
+ expect(page).to have_text('All users')
+ expect(page).to have_text('All environments')
+ end
+ end
+
+ it 'removes the correct strategy when a strategy is deleted' do
+ visit(new_project_feature_flag_path(project))
+ click_button 'Add strategy'
+ within_strategy_row(1) do
+ select 'All users', from: 'Type'
+ end
+ within_strategy_row(2) do
+ select 'Percent of users', from: 'Type'
+ end
+ within_strategy_row(1) do
+ delete_strategy_button.click
+ end
+
+ within_strategy_row(1) do
+ expect(page).to have_select('Type', selected: 'Percent of users')
+ end
+ end
+
+ context 'with new version flags disabled' do
+ before do
+ stub_feature_flags(feature_flags_new_version: false)
+ end
+
+ context 'when creates without changing scopes' do
+ before do
+ visit(new_project_feature_flag_path(project))
+ set_feature_flag_info('ci_live_trace', 'For live trace')
+ click_button 'Create feature flag'
+ expect(page).to have_current_path(project_feature_flags_path(project))
+ end
+
+ it 'shows the created feature flag' do
+ within_feature_flag_row(1) do
+ expect(page.find('.feature-flag-name')).to have_content('ci_live_trace')
+ expect_status_toggle_button_to_be_checked
+
+ within_feature_flag_scopes do
+ expect(page.find('[data-qa-selector="feature-flag-scope-info-badge"]:nth-child(1)')).to have_content('*')
+ end
+ end
+ end
+ end
+
+ context 'when creates with disabling the default scope' do
+ before do
+ visit(new_project_feature_flag_path(project))
+ set_feature_flag_info('ci_live_trace', 'For live trace')
+
+ within_scope_row(1) do
+ within_status { find('.project-feature-toggle').click }
+ end
+
+ click_button 'Create feature flag'
+ end
+
+ it 'shows the created feature flag' do
+ within_feature_flag_row(1) do
+ expect(page.find('.feature-flag-name')).to have_content('ci_live_trace')
+ expect_status_toggle_button_to_be_checked
+
+ within_feature_flag_scopes do
+ expect(page.find('[data-qa-selector="feature-flag-scope-muted-badge"]:nth-child(1)')).to have_content('*')
+ end
+ end
+ end
+ end
+
+ context 'when creates with an additional scope' do
+ before do
+ visit(new_project_feature_flag_path(project))
+ set_feature_flag_info('mr_train', '')
+
+ within_scope_row(2) do
+ within_environment_spec do
+ find('.js-env-search > input').set("review/*")
+ find('.js-create-button').click
+ end
+ end
+
+ within_scope_row(2) do
+ within_status { find('.project-feature-toggle').click }
+ end
+
+ click_button 'Create feature flag'
+ end
+
+ it 'shows the created feature flag' do
+ within_feature_flag_row(1) do
+ expect(page.find('.feature-flag-name')).to have_content('mr_train')
+ expect_status_toggle_button_to_be_checked
+
+ within_feature_flag_scopes do
+ expect(page.find('[data-qa-selector="feature-flag-scope-info-badge"]:nth-child(1)')).to have_content('*')
+ expect(page.find('[data-qa-selector="feature-flag-scope-info-badge"]:nth-child(2)')).to have_content('review/*')
+ end
+ end
+ end
+ end
+
+ context 'when searches an environment name for scope creation' do
+ let!(:environment) { create(:environment, name: 'production', project: project) }
+
+ before do
+ visit(new_project_feature_flag_path(project))
+ set_feature_flag_info('mr_train', '')
+
+ within_scope_row(2) do
+ within_environment_spec do
+ find('.js-env-search > input').set('prod')
+ click_button 'production'
+ end
+ end
+
+ click_button 'Create feature flag'
+ end
+
+ it 'shows the created feature flag' do
+ within_feature_flag_row(1) do
+ expect(page.find('.feature-flag-name')).to have_content('mr_train')
+ expect_status_toggle_button_to_be_checked
+
+ within_feature_flag_scopes do
+ expect(page.find('[data-qa-selector="feature-flag-scope-info-badge"]:nth-child(1)')).to have_content('*')
+ expect(page.find('[data-qa-selector="feature-flag-scope-muted-badge"]:nth-child(2)')).to have_content('production')
+ end
+ end
+ end
+ end
+ end
+
+ private
+
+ def set_feature_flag_info(name, description)
+ fill_in 'Name', with: name
+ fill_in 'Description', with: description
+ end
+
+ def environment_plus_button
+ find('.js-new-environments-dropdown')
+ end
+
+ def environment_search_input
+ find('.js-new-environments-dropdown input')
+ end
+
+ def environment_search_results
+ all('.js-new-environments-dropdown button.dropdown-item')
+ end
+end
diff --git a/spec/features/projects/feature_flags/user_deletes_feature_flag_spec.rb b/spec/features/projects/feature_flags/user_deletes_feature_flag_spec.rb
new file mode 100644
index 00000000000..581709aacee
--- /dev/null
+++ b/spec/features/projects/feature_flags/user_deletes_feature_flag_spec.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'User deletes feature flag', :js do
+ include FeatureFlagHelpers
+
+ let(:user) { create(:user) }
+ let(:project) { create(:project, namespace: user.namespace) }
+
+ let!(:feature_flag) do
+ create_flag(project, 'ci_live_trace', false,
+ description: 'For live trace feature')
+ end
+
+ before do
+ project.add_developer(user)
+ stub_feature_flags(feature_flag_permissions: false)
+ sign_in(user)
+
+ visit(project_feature_flags_path(project))
+
+ find('.js-feature-flag-delete-button').click
+ click_button('Delete feature flag')
+ expect(page).to have_current_path(project_feature_flags_path(project))
+ end
+
+ it 'user does not see feature flag' do
+ expect(page).to have_no_content('ci_live_trace')
+ end
+end
diff --git a/spec/features/projects/feature_flags/user_sees_feature_flag_list_spec.rb b/spec/features/projects/feature_flags/user_sees_feature_flag_list_spec.rb
new file mode 100644
index 00000000000..750f4dc5ef4
--- /dev/null
+++ b/spec/features/projects/feature_flags/user_sees_feature_flag_list_spec.rb
@@ -0,0 +1,147 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'User sees feature flag list', :js do
+ include FeatureFlagHelpers
+
+ let_it_be(:user) { create(:user) }
+ let_it_be(:project) { create(:project, namespace: user.namespace) }
+
+ before_all do
+ project.add_developer(user)
+ end
+
+ before do
+ sign_in(user)
+ end
+
+ context 'with legacy feature flags' do
+ before do
+ create_flag(project, 'ci_live_trace', false).tap do |feature_flag|
+ create_scope(feature_flag, 'review/*', true)
+ end
+ create_flag(project, 'drop_legacy_artifacts', false)
+ create_flag(project, 'mr_train', true).tap do |feature_flag|
+ create_scope(feature_flag, 'production', false)
+ end
+ stub_feature_flags(feature_flags_legacy_read_only_override: false)
+ end
+
+ it 'user sees the first flag' do
+ visit(project_feature_flags_path(project))
+
+ within_feature_flag_row(1) do
+ expect(page.find('.js-feature-flag-id')).to have_content('^1')
+ expect(page.find('.feature-flag-name')).to have_content('ci_live_trace')
+ expect_status_toggle_button_not_to_be_checked
+
+ within_feature_flag_scopes do
+ expect(page.find('[data-qa-selector="feature-flag-scope-muted-badge"]:nth-child(1)')).to have_content('*')
+ expect(page.find('[data-qa-selector="feature-flag-scope-info-badge"]:nth-child(2)')).to have_content('review/*')
+ end
+ end
+ end
+
+ it 'user sees the second flag' do
+ visit(project_feature_flags_path(project))
+
+ within_feature_flag_row(2) do
+ expect(page.find('.js-feature-flag-id')).to have_content('^2')
+ expect(page.find('.feature-flag-name')).to have_content('drop_legacy_artifacts')
+ expect_status_toggle_button_not_to_be_checked
+
+ within_feature_flag_scopes do
+ expect(page.find('[data-qa-selector="feature-flag-scope-muted-badge"]:nth-child(1)')).to have_content('*')
+ end
+ end
+ end
+
+ it 'user sees the third flag' do
+ visit(project_feature_flags_path(project))
+
+ within_feature_flag_row(3) do
+ expect(page.find('.js-feature-flag-id')).to have_content('^3')
+ expect(page.find('.feature-flag-name')).to have_content('mr_train')
+ expect_status_toggle_button_to_be_checked
+
+ within_feature_flag_scopes do
+ expect(page.find('[data-qa-selector="feature-flag-scope-info-badge"]:nth-child(1)')).to have_content('*')
+ expect(page.find('[data-qa-selector="feature-flag-scope-muted-badge"]:nth-child(2)')).to have_content('production')
+ end
+ end
+ end
+
+ it 'user sees the status toggle disabled' do
+ visit(project_feature_flags_path(project))
+
+ within_feature_flag_row(1) do
+ expect_status_toggle_button_to_be_disabled
+ end
+ end
+
+ context 'when legacy feature flags are not read-only' do
+ before do
+ stub_feature_flags(feature_flags_legacy_read_only: false)
+ end
+
+ it 'user updates the status toggle' do
+ visit(project_feature_flags_path(project))
+
+ within_feature_flag_row(1) do
+ status_toggle_button.click
+
+ expect_status_toggle_button_to_be_checked
+ end
+ end
+ end
+
+ context 'when legacy feature flags are read-only but the override is active for a project' do
+ before do
+ stub_feature_flags(
+ feature_flags_legacy_read_only: true,
+ feature_flags_legacy_read_only_override: project
+ )
+ end
+
+ it 'user updates the status toggle' do
+ visit(project_feature_flags_path(project))
+
+ within_feature_flag_row(1) do
+ status_toggle_button.click
+
+ expect_status_toggle_button_to_be_checked
+ end
+ end
+ end
+ end
+
+ context 'with new version flags' do
+ before do
+ create(:operations_feature_flag, :new_version_flag, project: project,
+ name: 'my_flag', active: false)
+ end
+
+ it 'user updates the status toggle' do
+ visit(project_feature_flags_path(project))
+
+ within_feature_flag_row(1) do
+ status_toggle_button.click
+
+ expect_status_toggle_button_to_be_checked
+ end
+ end
+ end
+
+ context 'when there are no feature flags' do
+ before do
+ visit(project_feature_flags_path(project))
+ end
+
+ it 'shows empty page' do
+ expect(page).to have_text 'Get started with feature flags'
+ expect(page).to have_selector('.btn-success', text: 'New feature flag')
+ expect(page).to have_selector('[data-qa-selector="configure_feature_flags_button"]', text: 'Configure')
+ end
+ end
+end
diff --git a/spec/features/projects/feature_flags/user_updates_feature_flag_spec.rb b/spec/features/projects/feature_flags/user_updates_feature_flag_spec.rb
new file mode 100644
index 00000000000..bc2d63e1953
--- /dev/null
+++ b/spec/features/projects/feature_flags/user_updates_feature_flag_spec.rb
@@ -0,0 +1,195 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'User updates feature flag', :js do
+ include FeatureFlagHelpers
+
+ let_it_be(:user) { create(:user) }
+ let_it_be(:project) { create(:project, namespace: user.namespace) }
+
+ before_all do
+ project.add_developer(user)
+ end
+
+ before do
+ stub_feature_flags(
+ feature_flag_permissions: false,
+ feature_flags_legacy_read_only_override: false
+ )
+ sign_in(user)
+ end
+
+ context 'with a new version feature flag' do
+ let!(:feature_flag) do
+ create_flag(project, 'test_flag', false, version: Operations::FeatureFlag.versions['new_version_flag'],
+ description: 'For testing')
+ end
+
+ let!(:strategy) do
+ create(:operations_strategy, feature_flag: feature_flag,
+ name: 'default', parameters: {})
+ end
+
+ let!(:scope) do
+ create(:operations_scope, strategy: strategy, environment_scope: '*')
+ end
+
+ it 'user adds a second strategy' do
+ visit(edit_project_feature_flag_path(project, feature_flag))
+
+ wait_for_requests
+
+ click_button 'Add strategy'
+ within_strategy_row(2) do
+ select 'Percent of users', from: 'Type'
+ fill_in 'Percentage', with: '15'
+ end
+ click_button 'Save changes'
+
+ edit_feature_flag_button.click
+
+ within_strategy_row(1) do
+ expect(page).to have_text 'All users'
+ expect(page).to have_text 'All environments'
+ end
+ within_strategy_row(2) do
+ expect(page).to have_text 'Percent of users'
+ expect(page).to have_field 'Percentage', with: '15'
+ expect(page).to have_text 'All environments'
+ end
+ end
+
+ it 'user toggles the flag on' do
+ visit(edit_project_feature_flag_path(project, feature_flag))
+ status_toggle_button.click
+ click_button 'Save changes'
+
+ within_feature_flag_row(1) do
+ expect_status_toggle_button_to_be_checked
+ end
+ end
+ end
+
+ context 'with a legacy feature flag' do
+ let!(:feature_flag) do
+ create_flag(project, 'ci_live_trace', true,
+ description: 'For live trace feature')
+ end
+
+ let!(:scope) { create_scope(feature_flag, 'review/*', true) }
+
+ context 'when legacy flags are editable' do
+ before do
+ stub_feature_flags(feature_flags_legacy_read_only: false)
+
+ visit(edit_project_feature_flag_path(project, feature_flag))
+ end
+
+ it 'user sees persisted default scope' do
+ within_scope_row(1) do
+ within_environment_spec do
+ expect(page).to have_content('* (All Environments)')
+ end
+
+ within_status do
+ expect(find('.project-feature-toggle')['aria-label'])
+ .to eq('Toggle Status: ON')
+ end
+ end
+ end
+
+ context 'when user updates the status of a scope' do
+ before do
+ within_scope_row(2) do
+ within_status { find('.project-feature-toggle').click }
+ end
+
+ click_button 'Save changes'
+ expect(page).to have_current_path(project_feature_flags_path(project))
+ end
+
+ it 'shows the updated feature flag' do
+ within_feature_flag_row(1) do
+ expect(page.find('.feature-flag-name')).to have_content('ci_live_trace')
+ expect_status_toggle_button_to_be_checked
+
+ within_feature_flag_scopes do
+ expect(page.find('.badge:nth-child(1)')).to have_content('*')
+ expect(page.find('.badge:nth-child(1)')['class']).to include('badge-info')
+ expect(page.find('.badge:nth-child(2)')).to have_content('review/*')
+ expect(page.find('.badge:nth-child(2)')['class']).to include('badge-muted')
+ end
+ end
+ end
+ end
+
+ context 'when user adds a new scope' do
+ before do
+ within_scope_row(3) do
+ within_environment_spec do
+ find('.js-env-search > input').set('production')
+ find('.js-create-button').click
+ end
+ end
+
+ click_button 'Save changes'
+ expect(page).to have_current_path(project_feature_flags_path(project))
+ end
+
+ it 'shows the newly created scope' do
+ within_feature_flag_row(1) do
+ within_feature_flag_scopes do
+ expect(page.find('.badge:nth-child(3)')).to have_content('production')
+ expect(page.find('.badge:nth-child(3)')['class']).to include('badge-muted')
+ end
+ end
+ end
+ end
+
+ context 'when user deletes a scope' do
+ before do
+ within_scope_row(2) do
+ within_delete { find('.js-delete-scope').click }
+ end
+
+ click_button 'Save changes'
+ expect(page).to have_current_path(project_feature_flags_path(project))
+ end
+
+ it 'shows the updated feature flag' do
+ within_feature_flag_row(1) do
+ within_feature_flag_scopes do
+ expect(page).to have_css('.badge:nth-child(1)')
+ expect(page).not_to have_css('.badge:nth-child(2)')
+ end
+ end
+ end
+ end
+ end
+
+ context 'when legacy flags are read-only' do
+ it 'the user cannot edit the flag' do
+ visit(edit_project_feature_flag_path(project, feature_flag))
+
+ expect(page).to have_text 'This feature flag is read-only, and it will be removed in 14.0.'
+ expect(page).to have_css('button.js-ff-submit.disabled')
+ end
+ end
+
+ context 'when legacy flags are read-only, but the override is active for one project' do
+ it 'the user can edit the flag' do
+ stub_feature_flags(feature_flags_legacy_read_only_override: project)
+
+ visit(edit_project_feature_flag_path(project, feature_flag))
+ status_toggle_button.click
+ click_button 'Save changes'
+
+ expect(page).to have_current_path(project_feature_flags_path(project))
+ within_feature_flag_row(1) do
+ expect_status_toggle_button_not_to_be_checked
+ end
+ end
+ end
+ end
+end
diff --git a/spec/features/projects/features_visibility_spec.rb b/spec/features/projects/features_visibility_spec.rb
index 8d3ca9d9fd1..467adb25a17 100644
--- a/spec/features/projects/features_visibility_spec.rb
+++ b/spec/features/projects/features_visibility_spec.rb
@@ -201,7 +201,7 @@ RSpec.describe 'Edit Project Settings' do
visit project_path(project)
- expect(page).to have_content "Customize your workflow!"
+ expect(page).to have_content "joined project"
end
it "hides project activity tabs" do
diff --git a/spec/features/projects/files/project_owner_sees_link_to_create_license_file_in_empty_project_spec.rb b/spec/features/projects/files/project_owner_sees_link_to_create_license_file_in_empty_project_spec.rb
index eed1e7aaf1b..d28e31c08dc 100644
--- a/spec/features/projects/files/project_owner_sees_link_to_create_license_file_in_empty_project_spec.rb
+++ b/spec/features/projects/files/project_owner_sees_link_to_create_license_file_in_empty_project_spec.rb
@@ -3,6 +3,8 @@
require 'spec_helper'
RSpec.describe 'Projects > Files > Project owner sees a link to create a license file in empty project', :js do
+ include WebIdeSpecHelpers
+
let(:project) { create(:project_empty_repo) }
let(:project_maintainer) { project.owner }
@@ -10,36 +12,35 @@ RSpec.describe 'Projects > Files > Project owner sees a link to create a license
sign_in(project_maintainer)
end
- it 'project maintainer creates a license file from a template' do
+ it 'allows project maintainer creates a license file from a template in Web IDE' do
visit project_path(project)
click_on 'Add LICENSE'
- expect(page).to have_content('New file')
- expect(current_path).to eq(
- project_new_blob_path(project, 'master'))
- expect(find('#file_name').value).to eq('LICENSE')
- expect(page).to have_selector('.license-selector')
+ expect(current_path).to eq("/-/ide/project/#{project.full_path}/edit/master/-/LICENSE")
+
+ expect(page).to have_selector('.qa-file-templates-bar')
select_template('MIT License')
- file_content = first('.file-editor')
- expect(file_content).to have_content('MIT License')
- expect(file_content).to have_content("Copyright (c) #{Time.now.year} #{project.namespace.human_name}")
+ expect(ide_editor_value).to have_content('MIT License')
+ expect(ide_editor_value).to have_content("Copyright (c) #{Time.now.year} #{project.namespace.human_name}")
+
+ ide_commit
+
+ click_button('Commit')
+
+ expect(current_path).to eq("/-/ide/project/#{project.full_path}/tree/master/-/")
- fill_in :commit_message, with: 'Add a LICENSE file', visible: true
- click_button 'Commit changes'
+ expect(page).to have_content('All changes are committed')
- expect(current_path).to eq(
- project_blob_path(project, 'master/LICENSE'))
- expect(page).to have_content('MIT License')
- expect(page).to have_content("Copyright (c) #{Time.now.year} #{project.namespace.human_name}")
+ license_file = project.repository.blob_at('master', 'LICENSE').data
+ expect(license_file).to have_content('MIT License')
+ expect(license_file).to have_content("Copyright (c) #{Time.now.year} #{project.namespace.human_name}")
end
def select_template(template)
- page.within('.js-license-selector-wrap') do
- click_button 'Apply a template'
- click_link template
- wait_for_requests
- end
+ click_button 'Choose a template...'
+ click_button template
+ wait_for_requests
end
end
diff --git a/spec/features/projects/files/user_browses_lfs_files_spec.rb b/spec/features/projects/files/user_browses_lfs_files_spec.rb
index ecc56b794b2..3be5ab64834 100644
--- a/spec/features/projects/files/user_browses_lfs_files_spec.rb
+++ b/spec/features/projects/files/user_browses_lfs_files_spec.rb
@@ -66,10 +66,30 @@ RSpec.describe 'Projects > Files > User browses LFS files' do
expect(page).to have_content('History')
expect(page).to have_content('Permalink')
expect(page).to have_content('Replace')
+ expect(page).to have_link('Download')
+
expect(page).not_to have_content('Annotate')
expect(page).not_to have_content('Blame')
- expect(page).not_to have_content('Edit')
- expect(page).to have_link('Download')
+
+ expect(page).not_to have_selector(:link_or_button, text: /^Edit$/)
+ expect(page).to have_selector(:link_or_button, 'Edit in Web IDE')
+ end
+ end
+
+ context 'when feature flag :consolidated_edit_button is off' do
+ before do
+ stub_feature_flags(consolidated_edit_button: false)
+
+ click_link('files')
+ click_link('lfs')
+ click_link('lfs_object.iso')
+ end
+
+ it 'does not show single file edit link' do
+ page.within('.content') do
+ expect(page).to have_selector(:link_or_button, 'Web IDE')
+ expect(page).not_to have_selector(:link_or_button, 'Edit')
+ end
end
end
end
diff --git a/spec/features/projects/files/user_creates_files_spec.rb b/spec/features/projects/files/user_creates_files_spec.rb
index 39bc139656b..fd83547d064 100644
--- a/spec/features/projects/files/user_creates_files_spec.rb
+++ b/spec/features/projects/files/user_creates_files_spec.rb
@@ -3,6 +3,8 @@
require 'spec_helper'
RSpec.describe 'Projects > Files > User creates files', :js do
+ include BlobSpecHelpers
+
let(:fork_message) do
"You're not allowed to make changes to this project directly. "\
"A fork of this project has been created that you can make changes in, so you can submit a merge request."
@@ -103,6 +105,8 @@ RSpec.describe 'Projects > Files > User creates files', :js do
end
it 'creates and commit a new file with new lines at the end of file' do
+ set_default_button('edit')
+
find('#editor')
execute_script('monaco.editor.getModels()[0].setValue("Sample\n\n\n")')
fill_in(:file_name, with: 'not_a_file.md')
@@ -113,7 +117,7 @@ RSpec.describe 'Projects > Files > User creates files', :js do
expect(current_path).to eq(new_file_path)
- find('.js-edit-blob').click
+ click_link('Edit')
find('#editor')
expect(evaluate_script('monaco.editor.getModels()[0].getValue()')).to eq("Sample\n\n\n")
diff --git a/spec/features/projects/files/user_edits_files_spec.rb b/spec/features/projects/files/user_edits_files_spec.rb
index d3e075001c8..c18ff9ddbbc 100644
--- a/spec/features/projects/files/user_edits_files_spec.rb
+++ b/spec/features/projects/files/user_edits_files_spec.rb
@@ -4,6 +4,8 @@ require 'spec_helper'
RSpec.describe 'Projects > Files > User edits files', :js do
include ProjectForksHelper
+ include BlobSpecHelpers
+
let(:project) { create(:project, :repository, name: 'Shop') }
let(:project2) { create(:project, :repository, name: 'Another Project', path: 'another-project') }
let(:project_tree_path_root_ref) { project_tree_path(project, project.repository.root_ref) }
@@ -14,6 +16,10 @@ RSpec.describe 'Projects > Files > User edits files', :js do
sign_in(user)
end
+ after do
+ unset_default_button
+ end
+
shared_examples 'unavailable for an archived project' do
it 'does not show the edit link for an archived project', :js do
project.update!(archived: true)
@@ -39,14 +45,15 @@ RSpec.describe 'Projects > Files > User edits files', :js do
end
it 'inserts a content of a file' do
+ set_default_button('edit')
click_link('.gitignore')
- find('.js-edit-blob').click
+ click_link_or_button('Edit')
find('.file-editor', match: :first)
find('#editor')
- execute_script("monaco.editor.getModels()[0].setValue('*.rbca')")
+ set_editor_value('*.rbca')
- expect(evaluate_script('monaco.editor.getModels()[0].getValue()')).to eq('*.rbca')
+ expect(editor_value).to eq('*.rbca')
end
it 'does not show the edit link if a file is binary' do
@@ -60,12 +67,13 @@ RSpec.describe 'Projects > Files > User edits files', :js do
end
it 'commits an edited file' do
+ set_default_button('edit')
click_link('.gitignore')
- find('.js-edit-blob').click
+ click_link_or_button('Edit')
find('.file-editor', match: :first)
find('#editor')
- execute_script("monaco.editor.getModels()[0].setValue('*.rbca')")
+ set_editor_value('*.rbca')
fill_in(:commit_message, with: 'New commit message', visible: true)
click_button('Commit changes')
@@ -77,13 +85,14 @@ RSpec.describe 'Projects > Files > User edits files', :js do
end
it 'commits an edited file to a new branch' do
+ set_default_button('edit')
click_link('.gitignore')
- find('.js-edit-blob').click
+ click_link_or_button('Edit')
find('.file-editor', match: :first)
find('#editor')
- execute_script("monaco.editor.getModels()[0].setValue('*.rbca')")
+ set_editor_value('*.rbca')
fill_in(:commit_message, with: 'New commit message', visible: true)
fill_in(:branch_name, with: 'new_branch_name', visible: true)
click_button('Commit changes')
@@ -96,12 +105,13 @@ RSpec.describe 'Projects > Files > User edits files', :js do
end
it 'shows the diff of an edited file' do
+ set_default_button('edit')
click_link('.gitignore')
- find('.js-edit-blob').click
+ click_link_or_button('Edit')
find('.file-editor', match: :first)
find('#editor')
- execute_script("monaco.editor.getModels()[0].setValue('*.rbca')")
+ set_editor_value('*.rbca')
click_link('Preview changes')
expect(page).to have_css('.line_holder.new')
@@ -118,8 +128,8 @@ RSpec.describe 'Projects > Files > User edits files', :js do
end
def expect_fork_prompt
- expect(page).to have_link('Fork')
- expect(page).to have_button('Cancel')
+ expect(page).to have_selector(:link_or_button, 'Fork')
+ expect(page).to have_selector(:link_or_button, 'Cancel')
expect(page).to have_content(
"You're not allowed to edit files in this project directly. "\
"Please fork this project, make your changes there, and submit a merge request."
@@ -134,30 +144,32 @@ RSpec.describe 'Projects > Files > User edits files', :js do
end
it 'inserts a content of a file in a forked project', :sidekiq_might_not_need_inline do
+ set_default_button('edit')
click_link('.gitignore')
- click_button('Edit')
+ click_link_or_button('Edit')
expect_fork_prompt
- click_link('Fork')
+ click_link_or_button('Fork project')
expect_fork_status
find('.file-editor', match: :first)
find('#editor')
- execute_script("monaco.editor.getModels()[0].setValue('*.rbca')")
+ set_editor_value('*.rbca')
- expect(evaluate_script('monaco.editor.getModels()[0].getValue()')).to eq('*.rbca')
+ expect(editor_value).to eq('*.rbca')
end
it 'opens the Web IDE in a forked project', :sidekiq_might_not_need_inline do
+ set_default_button('webide')
click_link('.gitignore')
- click_button('Web IDE')
+ click_link_or_button('Web IDE')
expect_fork_prompt
- click_link('Fork')
+ click_link_or_button('Fork project')
expect_fork_status
@@ -166,17 +178,17 @@ RSpec.describe 'Projects > Files > User edits files', :js do
end
it 'commits an edited file in a forked project', :sidekiq_might_not_need_inline do
+ set_default_button('edit')
click_link('.gitignore')
- find('.js-edit-blob').click
+ click_link_or_button('Edit')
expect_fork_prompt
-
- click_link('Fork')
+ click_link_or_button('Fork project')
find('.file-editor', match: :first)
find('#editor')
- execute_script("monaco.editor.getModels()[0].setValue('*.rbca')")
+ set_editor_value('*.rbca')
fill_in(:commit_message, with: 'New commit message', visible: true)
click_button('Commit changes')
@@ -198,14 +210,14 @@ RSpec.describe 'Projects > Files > User edits files', :js do
end
it 'links to the forked project for editing', :sidekiq_might_not_need_inline do
+ set_default_button('edit')
click_link('.gitignore')
- find('.js-edit-blob').click
+ click_link_or_button('Edit')
- expect(page).not_to have_link('Fork')
- expect(page).not_to have_button('Cancel')
+ expect(page).not_to have_link('Fork project')
find('#editor')
- execute_script("monaco.editor.getModels()[0].setValue('*.rbca')")
+ set_editor_value('*.rbca')
fill_in(:commit_message, with: 'Another commit', visible: true)
click_button('Commit changes')
@@ -224,5 +236,116 @@ RSpec.describe 'Projects > Files > User edits files', :js do
let(:project) { project2 }
end
end
+
+ context 'when feature flag :consolidated_edit_button is off' do
+ before do
+ stub_feature_flags(consolidated_edit_button: false)
+ end
+
+ context 'when an user does not have write access', :js do
+ before do
+ project2.add_reporter(user)
+ visit(project2_tree_path_root_ref)
+ wait_for_requests
+ end
+
+ it 'inserts a content of a file in a forked project', :sidekiq_might_not_need_inline do
+ set_default_button('edit')
+ click_link('.gitignore')
+ click_link_or_button('Edit')
+
+ expect_fork_prompt
+
+ click_link_or_button('Fork')
+
+ expect_fork_status
+
+ find('.file-editor', match: :first)
+
+ find('#editor')
+ set_editor_value('*.rbca')
+
+ expect(editor_value).to eq('*.rbca')
+ end
+
+ it 'opens the Web IDE in a forked project', :sidekiq_might_not_need_inline do
+ set_default_button('webide')
+ click_link('.gitignore')
+ click_link_or_button('Web IDE')
+
+ expect_fork_prompt
+
+ click_link_or_button('Fork')
+
+ expect_fork_status
+
+ expect(page).to have_css('.ide-sidebar-project-title', text: "#{project2.name} #{user.namespace.full_path}/#{project2.path}")
+ expect(page).to have_css('.ide .multi-file-tab', text: '.gitignore')
+ end
+
+ it 'commits an edited file in a forked project', :sidekiq_might_not_need_inline do
+ set_default_button('edit')
+ click_link('.gitignore')
+ click_link_or_button('Edit')
+
+ expect_fork_prompt
+
+ click_link_or_button('Fork')
+
+ expect_fork_status
+
+ find('.file-editor', match: :first)
+
+ find('#editor')
+ set_editor_value('*.rbca')
+ fill_in(:commit_message, with: 'New commit message', visible: true)
+ click_button('Commit changes')
+
+ fork = user.fork_of(project2.reload)
+
+ expect(current_path).to eq(project_new_merge_request_path(fork))
+
+ wait_for_requests
+
+ expect(page).to have_content('New commit message')
+ end
+
+ context 'when the user already had a fork of the project', :js do
+ let!(:forked_project) { fork_project(project2, user, namespace: user.namespace, repository: true) }
+
+ before do
+ visit(project2_tree_path_root_ref)
+ wait_for_requests
+ end
+
+ it 'links to the forked project for editing', :sidekiq_might_not_need_inline do
+ set_default_button('edit')
+ click_link('.gitignore')
+ click_link_or_button('Edit')
+
+ expect(page).not_to have_link('Fork')
+
+ find('#editor')
+ set_editor_value('*.rbca')
+ fill_in(:commit_message, with: 'Another commit', visible: true)
+ click_button('Commit changes')
+
+ fork = user.fork_of(project2)
+
+ expect(current_path).to eq(project_new_merge_request_path(fork))
+
+ wait_for_requests
+
+ expect(page).to have_content('Another commit')
+ expect(page).to have_content("From #{forked_project.full_path}")
+ expect(page).to have_content("into #{project2.full_path}")
+ end
+
+ it_behaves_like 'unavailable for an archived project' do
+ let(:project) { project2 }
+ end
+ end
+ end
+ end
end
end
diff --git a/spec/features/projects/issues/design_management/user_links_to_designs_in_issue_spec.rb b/spec/features/projects/issues/design_management/user_links_to_designs_in_issue_spec.rb
index 8d5e99d7e2b..78fb470d4ea 100644
--- a/spec/features/projects/issues/design_management/user_links_to_designs_in_issue_spec.rb
+++ b/spec/features/projects/issues/design_management/user_links_to_designs_in_issue_spec.rb
@@ -90,34 +90,5 @@ RSpec.describe 'viewing issues with design references' do
expect(page).not_to have_link(design_ref_b)
end
end
-
- context 'design management is enabled, but the filter is disabled globally' do
- before do
- enable_design_management
- stub_feature_flags(
- Banzai::Filter::DesignReferenceFilter::FEATURE_FLAG => false
- )
- end
-
- it 'processes design tab links successfully, and design references as issue references', :aggregate_failures do
- visit_page_with_design_references
-
- expect(page).to have_text('The designs I mentioned')
- expect(page).to have_link(design_tab_ref)
- expect(page).to have_link(issue_ref)
- expect(page).not_to have_link(design_ref_a)
- expect(page).not_to have_link(design_ref_b)
- end
- end
-
- context 'design management is enabled, and the filter is enabled for the current project' do
- before do
- stub_feature_flags(
- Banzai::Filter::DesignReferenceFilter::FEATURE_FLAG => public_project
- )
- end
-
- it_behaves_like 'successful use of design link references'
- end
end
end
diff --git a/spec/features/projects/issues/viewing_relocated_issues_spec.rb b/spec/features/projects/issues/viewing_relocated_issues_spec.rb
new file mode 100644
index 00000000000..10d5ad1747c
--- /dev/null
+++ b/spec/features/projects/issues/viewing_relocated_issues_spec.rb
@@ -0,0 +1,40 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'issues canonical link' do
+ include Spec::Support::Helpers::Features::CanonicalLinkHelpers
+
+ let_it_be(:original_project) { create(:project, :public) }
+ let_it_be(:original_issue) { create(:issue, project: original_project) }
+ let_it_be(:canonical_issue) { create(:issue) }
+ let_it_be(:canonical_url) { issue_url(canonical_issue, Gitlab::Application.routes.default_url_options) }
+
+ it "doesn't show the canonical URL" do
+ visit(issue_path(original_issue))
+
+ expect(page).not_to have_any_canonical_links
+ end
+
+ context 'when the issue was moved' do
+ it 'shows the canonical URL' do
+ original_issue.moved_to = canonical_issue
+ original_issue.save!
+
+ visit(issue_path(original_issue))
+
+ expect(page).to have_canonical_link(canonical_url)
+ end
+ end
+
+ context 'when the issue was duplicated' do
+ it 'shows the canonical URL' do
+ original_issue.duplicated_to = canonical_issue
+ original_issue.save!
+
+ visit(issue_path(original_issue))
+
+ expect(page).to have_canonical_link(canonical_url)
+ end
+ end
+end
diff --git a/spec/features/projects/jobs/user_browses_job_spec.rb b/spec/features/projects/jobs/user_browses_job_spec.rb
index b935b99642b..9b199157d79 100644
--- a/spec/features/projects/jobs/user_browses_job_spec.rb
+++ b/spec/features/projects/jobs/user_browses_job_spec.rb
@@ -43,7 +43,7 @@ RSpec.describe 'User browses a job', :js do
wait_for_all_requests
within('.builds-container') do
expect(page).to have_selector(
- ".build-job > a[data-original-title='test - failed - (unknown failure)']")
+ ".build-job > a[title='test - failed - (unknown failure)']")
end
end
end
@@ -55,7 +55,7 @@ RSpec.describe 'User browses a job', :js do
wait_for_all_requests
within('.builds-container') do
expect(page).to have_selector(
- ".build-job > a[data-original-title='test - failed - (unknown failure) (retried)']")
+ ".build-job > a[title='test - failed - (unknown failure) (retried)']")
end
end
end
diff --git a/spec/features/projects/members/groups_with_access_list_spec.rb b/spec/features/projects/members/groups_with_access_list_spec.rb
index 2ee6bc103e9..d59f8eb4b1d 100644
--- a/spec/features/projects/members/groups_with_access_list_spec.rb
+++ b/spec/features/projects/members/groups_with_access_list_spec.rb
@@ -3,20 +3,23 @@
require 'spec_helper'
RSpec.describe 'Projects > Members > Groups with access list', :js do
- let(:user) { create(:user) }
- let(:group) { create(:group, :public) }
- let(:project) { create(:project, :public) }
+ let_it_be(:user) { create(:user) }
+ let_it_be(:group) { create(:group, :public) }
+ let_it_be(:project) { create(:project, :public) }
+
+ let(:additional_link_attrs) { {} }
+ let!(:group_link) { create(:project_group_link, project: project, group: group, **additional_link_attrs) }
before do
- project.add_maintainer(user)
- @group_link = create(:project_group_link, project: project, group: group)
+ travel_to Time.now.utc.beginning_of_day
+ project.add_maintainer(user)
sign_in(user)
visit project_project_members_path(project)
end
it 'updates group access level' do
- click_button @group_link.human_access
+ click_button group_link.human_access
page.within '.dropdown-menu' do
click_link 'Guest'
@@ -30,20 +33,38 @@ RSpec.describe 'Projects > Members > Groups with access list', :js do
end
it 'updates expiry date' do
- tomorrow = Date.today + 3
+ expires_at_field = "member_expires_at_#{group.id}"
+ fill_in expires_at_field, with: 3.days.from_now.to_date
- fill_in "member_expires_at_#{group.id}", with: tomorrow.strftime("%F")
- find('body').click
+ find_field(expires_at_field).native.send_keys :enter
wait_for_requests
page.within(find('li.group_member')) do
- expect(page).to have_content('Expires in')
+ expect(page).to have_content('Expires in 3 days')
+ end
+ end
+
+ context 'when link has expiry date set' do
+ let(:additional_link_attrs) { { expires_at: 3.days.from_now.to_date } }
+
+ it 'clears expiry date' do
+ page.within(find('li.group_member')) do
+ expect(page).to have_content('Expires in 3 days')
+
+ page.within(find('.js-edit-member-form')) do
+ find('.js-clear-input').click
+ end
+
+ wait_for_requests
+
+ expect(page).not_to have_content('Expires in')
+ end
end
end
it 'deletes group link' do
page.within(first('.group_member')) do
- accept_confirm { find('.btn-remove').click }
+ accept_confirm { find('.btn-danger').click }
end
wait_for_requests
diff --git a/spec/features/projects/members/list_spec.rb b/spec/features/projects/members/list_spec.rb
index b32ccb0ccef..36ff461aac2 100644
--- a/spec/features/projects/members/list_spec.rb
+++ b/spec/features/projects/members/list_spec.rb
@@ -102,7 +102,7 @@ RSpec.describe 'Project members list' do
visit_members_page
expect(page).not_to have_selector("#edit_project_member_#{project_member.id}")
- expect(page).not_to have_selector("#project_member_#{project_member.id} .btn-remove")
+ expect(page).to have_no_selector("#project_member_#{project_member.id} .btn-danger")
end
end
diff --git a/spec/features/projects/members/master_adds_member_with_expiration_date_spec.rb b/spec/features/projects/members/master_adds_member_with_expiration_date_spec.rb
index 979bbd57aa3..d69c3f2652c 100644
--- a/spec/features/projects/members/master_adds_member_with_expiration_date_spec.rb
+++ b/spec/features/projects/members/master_adds_member_with_expiration_date_spec.rb
@@ -6,43 +6,64 @@ RSpec.describe 'Projects > Members > Maintainer adds member with expiration date
include Select2Helper
include ActiveSupport::Testing::TimeHelpers
- let(:maintainer) { create(:user) }
- let(:project) { create(:project) }
- let!(:new_member) { create(:user) }
+ let_it_be(:maintainer) { create(:user) }
+ let_it_be(:project) { create(:project) }
+ let(:new_member) { create(:user) }
before do
+ travel_to Time.now.utc.beginning_of_day
+
project.add_maintainer(maintainer)
sign_in(maintainer)
end
it 'expiration date is displayed in the members list' do
- travel_to Time.zone.parse('2016-08-06 08:00') do
- date = 4.days.from_now
- visit project_project_members_path(project)
-
- page.within '.invite-users-form' do
- select2(new_member.id, from: '#user_ids', multiple: true)
- fill_in 'expires_at', with: date.to_s(:medium) + "\n"
- click_on 'Invite'
- end
-
- page.within "#project_member_#{new_member.project_members.first.id}" do
- expect(page).to have_content('Expires in 4 days')
- end
+ visit project_project_members_path(project)
+
+ page.within '.invite-users-form' do
+ select2(new_member.id, from: '#user_ids', multiple: true)
+
+ fill_in 'expires_at', with: 3.days.from_now.to_date
+ find_field('expires_at').native.send_keys :enter
+
+ click_on 'Invite'
+ end
+
+ page.within "#project_member_#{project_member_id}" do
+ expect(page).to have_content('Expires in 3 days')
+ end
+ end
+
+ it 'changes expiration date' do
+ project.team.add_users([new_member.id], :developer, expires_at: Date.today.to_date)
+ visit project_project_members_path(project)
+
+ page.within "#project_member_#{project_member_id}" do
+ fill_in 'Expiration date', with: 3.days.from_now.to_date
+ find_field('Expiration date').native.send_keys :enter
+
+ wait_for_requests
+
+ expect(page).to have_content('Expires in 3 days')
end
end
- it 'change expiration date' do
- travel_to Time.zone.parse('2016-08-06 08:00') do
- date = 3.days.from_now
- project.team.add_users([new_member.id], :developer, expires_at: Date.today.to_s(:medium))
- visit project_project_members_path(project)
-
- page.within "#project_member_#{new_member.project_members.first.id}" do
- find('.js-access-expiration-date').set date.to_s(:medium) + "\n"
- wait_for_requests
- expect(page).to have_content('Expires in 3 days')
- end
+ it 'clears expiration date' do
+ project.team.add_users([new_member.id], :developer, expires_at: 3.days.from_now.to_date)
+ visit project_project_members_path(project)
+
+ page.within "#project_member_#{project_member_id}" do
+ expect(page).to have_content('Expires in 3 days')
+
+ find('.js-clear-input').click
+
+ wait_for_requests
+
+ expect(page).not_to have_content('Expires in')
end
end
+
+ def project_member_id
+ project.members.find_by(user_id: new_member).id
+ end
end
diff --git a/spec/features/projects/navbar_spec.rb b/spec/features/projects/navbar_spec.rb
index 07f65fe62df..4ff3827b240 100644
--- a/spec/features/projects/navbar_spec.rb
+++ b/spec/features/projects/navbar_spec.rb
@@ -12,20 +12,10 @@ RSpec.describe 'Project navbar' do
let_it_be(:project) { create(:project, :repository) }
before do
- stub_feature_flags(project_iterations: false)
-
insert_package_nav(_('Operations'))
project.add_maintainer(user)
sign_in(user)
-
- if Gitlab.ee?
- insert_after_sub_nav_item(
- _('Kubernetes'),
- within: _('Operations'),
- new_sub_nav_item_name: _('Feature Flags')
- )
- end
end
it_behaves_like 'verified navigation bar' do
diff --git a/spec/features/projects/pages_spec.rb b/spec/features/projects/pages_spec.rb
index 243579ee2f7..c3eea0195a6 100644
--- a/spec/features/projects/pages_spec.rb
+++ b/spec/features/projects/pages_spec.rb
@@ -336,7 +336,7 @@ RSpec.shared_examples 'pages settings editing' do
expect(page).not_to have_field(:project_pages_https_only)
expect(page).not_to have_content('Force HTTPS (requires valid certificates)')
- expect(page).not_to have_button('Save')
+ expect(page).to have_button('Save')
end
end
end
diff --git a/spec/features/projects/pipelines/pipeline_spec.rb b/spec/features/projects/pipelines/pipeline_spec.rb
index f59dc5dd074..51826d867cd 100644
--- a/spec/features/projects/pipelines/pipeline_spec.rb
+++ b/spec/features/projects/pipelines/pipeline_spec.rb
@@ -172,10 +172,17 @@ RSpec.describe 'Pipeline', :js do
end
end
- it_behaves_like 'showing user status' do
- let(:user_with_status) { pipeline.user }
+ describe 'pipelines details view' do
+ let!(:status) { create(:user_status, user: pipeline.user, emoji: 'smirk', message: 'Authoring this object') }
- subject { visit project_pipeline_path(project, pipeline) }
+ it 'pipeline header shows the user status and emoji' do
+ visit project_pipeline_path(project, pipeline)
+
+ within '[data-testid="ci-header-content"]' do
+ expect(page).to have_selector("[data-testid='#{status.message}']")
+ expect(page).to have_selector("[data-name='#{status.emoji}']")
+ end
+ end
end
describe 'pipeline graph' do
@@ -400,7 +407,7 @@ RSpec.describe 'Pipeline', :js do
context 'when retrying' do
before do
- find('[data-testid="retryButton"]').click
+ find('[data-testid="retryPipeline"]').click
end
it 'does not show a "Retry" button', :sidekiq_might_not_need_inline do
@@ -902,7 +909,7 @@ RSpec.describe 'Pipeline', :js do
context 'when retrying' do
before do
- find('[data-testid="retryButton"]').click
+ find('[data-testid="retryPipeline"]').click
end
it 'does not show a "Retry" button', :sidekiq_might_not_need_inline do
diff --git a/spec/features/projects/pipelines/pipelines_spec.rb b/spec/features/projects/pipelines/pipelines_spec.rb
index a9c196bb84b..3e78dfc3bc7 100644
--- a/spec/features/projects/pipelines/pipelines_spec.rb
+++ b/spec/features/projects/pipelines/pipelines_spec.rb
@@ -118,7 +118,7 @@ RSpec.describe 'Pipelines', :js do
context 'when canceling' do
before do
find('.js-pipelines-cancel-button').click
- find('.js-modal-primary-action').click
+ click_button 'Stop pipeline'
wait_for_requests
end
@@ -407,7 +407,7 @@ RSpec.describe 'Pipelines', :js do
context 'when canceling' do
before do
find('.js-pipelines-cancel-button').click
- find('.js-modal-primary-action').click
+ click_button 'Stop pipeline'
end
it 'indicates that pipeline was canceled', :sidekiq_might_not_need_inline do
diff --git a/spec/features/projects/releases/user_creates_release_spec.rb b/spec/features/projects/releases/user_creates_release_spec.rb
index 5d05a7e4c91..0a5f7cc7edd 100644
--- a/spec/features/projects/releases/user_creates_release_spec.rb
+++ b/spec/features/projects/releases/user_creates_release_spec.rb
@@ -11,14 +11,11 @@ RSpec.describe 'User creates release', :js do
let_it_be(:user) { create(:user) }
let(:new_page_url) { new_project_release_path(project) }
- let(:show_feature_flag) { true }
before do
- stub_feature_flags(release_show_page: show_feature_flag)
-
project.add_developer(user)
- gitlab_sign_in(user)
+ sign_in(user)
visit new_page_url
@@ -75,14 +72,6 @@ RSpec.describe 'User creates release', :js do
expect(page).to have_current_path(project_release_path(project, release))
end
-
- context 'when the release_show_page feature flag is disabled' do
- let(:show_feature_flag) { false }
-
- it 'redirects to the main "Releases" page' do
- expect(page).to have_current_path(project_releases_path(project))
- end
- end
end
context 'when the "Cancel" button is clicked' do
@@ -108,6 +97,24 @@ RSpec.describe 'User creates release', :js do
end
end
+ context 'when the release notes "Preview" tab is clicked' do
+ before do
+ find_field('Release notes').click
+
+ fill_release_notes('**some** _markdown_ [content](https://example.com)')
+
+ click_on 'Preview'
+
+ wait_for_all_requests
+ end
+
+ it 'renders a preview of the release notes markdown' do
+ within('[data-testid="release-notes"]') do
+ expect(page).to have_text('some markdown content')
+ end
+ end
+ end
+
def fill_out_form_and_submit
fill_tag_name(tag_name)
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 4ed1be6db6b..9115a135aeb 100644
--- a/spec/features/projects/releases/user_views_edit_release_spec.rb
+++ b/spec/features/projects/releases/user_views_edit_release_spec.rb
@@ -6,14 +6,11 @@ RSpec.describe 'User edits Release', :js do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:release) { create(:release, project: project, name: 'The first release' ) }
let_it_be(:user) { create(:user) }
- let(:show_feature_flag) { true }
before do
- stub_feature_flags(release_show_page: show_feature_flag)
-
project.add_developer(user)
- gitlab_sign_in(user)
+ sign_in(user)
visit edit_project_release_path(project, release)
@@ -42,7 +39,7 @@ RSpec.describe 'User edits Release', :js do
it 'renders the edit Release form' do
expect(page).to have_content('Releases are based on Git tags. We recommend tags that use semantic versioning, for example v1.0, v2.0-pre.')
- expect(find_field('Tag name', { disabled: true }).value).to eq(release.tag)
+ expect(find_field('Tag name', disabled: true).value).to eq(release.tag)
expect(find_field('Release title').value).to eq(release.name)
expect(find_field('Release notes').value).to eq(release.description)
@@ -71,42 +68,24 @@ RSpec.describe 'User edits Release', :js do
expect(release.description).to eq('Updated Release notes')
end
- context 'when the release_show_page feature flag is disabled' do
- let(:show_feature_flag) { false }
-
- it 'redirects to the main Releases page when "Cancel" is clicked' do
- fill_out_form_and_click 'Cancel'
-
- expect(page).to have_current_path(project_releases_path(project))
- end
+ it 'redirects to the previous page when "Cancel" is clicked when the url includes a back_url query parameter' do
+ back_path = project_releases_path(project, params: { page: 2 })
+ visit edit_project_release_path(project, release, params: { back_url: back_path })
- it 'redirects to the main Releases page when "Save changes" is clicked' do
- fill_out_form_and_click 'Save changes'
+ fill_out_form_and_click 'Cancel'
- expect(page).to have_current_path(project_releases_path(project))
- end
+ expect(page).to have_current_path(back_path)
end
- context 'when the release_show_page feature flag is enabled' do
- it 'redirects to the previous page when "Cancel" is clicked when the url includes a back_url query parameter' do
- back_path = project_releases_path(project, params: { page: 2 })
- visit edit_project_release_path(project, release, params: { back_url: back_path })
-
- fill_out_form_and_click 'Cancel'
-
- expect(page).to have_current_path(back_path)
- end
-
- it 'redirects to the main Releases page when "Cancel" is clicked when the url does not include a back_url query parameter' do
- fill_out_form_and_click 'Cancel'
+ it 'redirects to the main Releases page when "Cancel" is clicked when the url does not include a back_url query parameter' do
+ fill_out_form_and_click 'Cancel'
- expect(page).to have_current_path(project_releases_path(project))
- end
+ expect(page).to have_current_path(project_releases_path(project))
+ end
- it 'redirects to the dedicated Release page when "Save changes" is clicked' do
- fill_out_form_and_click 'Save changes'
+ it 'redirects to the dedicated Release page when "Save changes" is clicked' do
+ fill_out_form_and_click 'Save changes'
- expect(page).to have_current_path(project_release_path(project, release))
- end
+ expect(page).to have_current_path(project_release_path(project, release))
end
end
diff --git a/spec/features/projects/releases/user_views_release_spec.rb b/spec/features/projects/releases/user_views_release_spec.rb
index c82588746a8..186122536ce 100644
--- a/spec/features/projects/releases/user_views_release_spec.rb
+++ b/spec/features/projects/releases/user_views_release_spec.rb
@@ -4,34 +4,57 @@ require 'spec_helper'
RSpec.describe 'User views Release', :js do
let(:project) { create(:project, :repository) }
- let(:release) { create(:release, project: project, name: 'The first release' ) }
let(:user) { create(:user) }
+ let(:graphql_feature_flag) { true }
+
+ let(:release) do
+ create(:release,
+ project: project,
+ name: 'The first release',
+ description: '**Lorem** _ipsum_ dolor sit [amet](https://example.com)')
+ end
before do
+ stub_feature_flags(graphql_individual_release_page: graphql_feature_flag)
+
project.add_developer(user)
- gitlab_sign_in(user)
+ sign_in(user)
visit project_release_path(project, release)
end
- it 'renders the breadcrumbs' do
- within('.breadcrumbs') do
- expect(page).to have_content("#{project.creator.name} #{project.name} Releases #{release.name}")
+ it_behaves_like 'page meta description', 'Lorem ipsum dolor sit amet'
- expect(page).to have_link(project.creator.name, href: user_path(project.creator))
- expect(page).to have_link(project.name, href: project_path(project))
- expect(page).to have_link('Releases', href: project_releases_path(project))
- expect(page).to have_link(release.name, href: project_release_path(project, release))
+ shared_examples 'release page' do
+ it 'renders the breadcrumbs' do
+ within('.breadcrumbs') do
+ expect(page).to have_content("#{project.creator.name} #{project.name} Releases #{release.name}")
+
+ expect(page).to have_link(project.creator.name, href: user_path(project.creator))
+ expect(page).to have_link(project.name, href: project_path(project))
+ expect(page).to have_link('Releases', href: project_releases_path(project))
+ expect(page).to have_link(release.name, href: project_release_path(project, release))
+ end
end
- end
- it 'renders the release details' do
- within('.release-block') do
- expect(page).to have_content(release.name)
- expect(page).to have_content(release.tag)
- expect(page).to have_content(release.commit.short_id)
- expect(page).to have_content(release.description)
+ it 'renders the release details' do
+ within('.release-block') do
+ expect(page).to have_content(release.name)
+ expect(page).to have_content(release.tag)
+ expect(page).to have_content(release.commit.short_id)
+ expect(page).to have_content('Lorem ipsum dolor sit amet')
+ end
end
end
+
+ describe 'when the graphql_individual_release_page feature flag is enabled' do
+ it_behaves_like 'release page'
+ end
+
+ describe 'when the graphql_individual_release_page feature flag is disabled' do
+ let(:graphql_feature_flag) { false }
+
+ it_behaves_like 'release page'
+ end
end
diff --git a/spec/features/projects/releases/user_views_releases_spec.rb b/spec/features/projects/releases/user_views_releases_spec.rb
index 993d3371904..323c57570c3 100644
--- a/spec/features/projects/releases/user_views_releases_spec.rb
+++ b/spec/features/projects/releases/user_views_releases_spec.rb
@@ -16,7 +16,7 @@ RSpec.describe 'User views releases', :js do
shared_examples 'releases page' do
context('when the user is a maintainer') do
before do
- gitlab_sign_in(maintainer)
+ sign_in(maintainer)
end
it 'sees the release' do
@@ -27,11 +27,23 @@ RSpec.describe 'User views releases', :js do
expect(page).not_to have_content('Upcoming Release')
end
- shared_examples 'asset link tests' do
- context 'when there is a link as an asset' do
- let!(:release_link) { create(:release_link, release: release, url: url ) }
+ context 'when there is a link as an asset' do
+ let!(:release_link) { create(:release_link, release: release, url: url ) }
+ let(:url) { "#{project.web_url}/-/jobs/1/artifacts/download" }
+ let(:direct_asset_link) { Gitlab::Routing.url_helpers.project_release_url(project, release) << release_link.filepath }
+
+ it 'sees the link' do
+ visit project_releases_path(project)
+
+ page.within('.js-assets-list') do
+ expect(page).to have_link release_link.name, href: direct_asset_link
+ expect(page).not_to have_css('[data-testid="external-link-indicator"]')
+ end
+ end
+
+ context 'when there is a link redirect' do
+ let!(:release_link) { create(:release_link, release: release, name: 'linux-amd64 binaries', filepath: '/binaries/linux-amd64', url: url) }
let(:url) { "#{project.web_url}/-/jobs/1/artifacts/download" }
- let(:direct_asset_link) { Gitlab::Routing.url_helpers.project_release_url(project, release) << release_link.filepath }
it 'sees the link' do
visit project_releases_path(project)
@@ -41,51 +53,21 @@ RSpec.describe 'User views releases', :js do
expect(page).not_to have_css('[data-testid="external-link-indicator"]')
end
end
+ end
- context 'when there is a link redirect' do
- let!(:release_link) { create(:release_link, release: release, name: 'linux-amd64 binaries', filepath: '/binaries/linux-amd64', url: url) }
- let(:url) { "#{project.web_url}/-/jobs/1/artifacts/download" }
-
- it 'sees the link' do
- visit project_releases_path(project)
-
- page.within('.js-assets-list') do
- expect(page).to have_link release_link.name, href: direct_asset_link
- expect(page).not_to have_css('[data-testid="external-link-indicator"]')
- end
- end
- end
-
- context 'when url points to external resource' do
- let(:url) { 'http://google.com/download' }
+ context 'when url points to external resource' do
+ let(:url) { 'http://google.com/download' }
- it 'sees that the link is external resource' do
- visit project_releases_path(project)
+ it 'sees that the link is external resource' do
+ visit project_releases_path(project)
- page.within('.js-assets-list') do
- expect(page).to have_css('[data-testid="external-link-indicator"]')
- end
+ page.within('.js-assets-list') do
+ expect(page).to have_css('[data-testid="external-link-indicator"]')
end
end
end
end
- context 'when the release_asset_link_type feature flag is enabled' do
- before do
- stub_feature_flags(release_asset_link_type: true)
- end
-
- it_behaves_like 'asset link tests'
- end
-
- context 'when the release_asset_link_type feature flag is disabled' do
- before do
- stub_feature_flags(release_asset_link_type: false)
- end
-
- it_behaves_like 'asset link tests'
- end
-
context 'with an upcoming release' do
let(:tomorrow) { Time.zone.now + 1.day }
let!(:release) { create(:release, project: project, released_at: tomorrow ) }
@@ -110,7 +92,7 @@ RSpec.describe 'User views releases', :js do
context('when the user is a guest') do
before do
- gitlab_sign_in(guest)
+ sign_in(guest)
end
it 'renders release info except for Git-related data' do
diff --git a/spec/features/projects/settings/pipelines_settings_spec.rb b/spec/features/projects/settings/pipelines_settings_spec.rb
index 0358acc8dcc..ffc0ecc4966 100644
--- a/spec/features/projects/settings/pipelines_settings_spec.rb
+++ b/spec/features/projects/settings/pipelines_settings_spec.rb
@@ -64,7 +64,7 @@ RSpec.describe "Projects > Settings > Pipelines settings" do
it 'updates forward_deployment_enabled' do
visit project_settings_ci_cd_path(project)
- checkbox = find_field('project_forward_deployment_enabled')
+ checkbox = find_field('project_ci_cd_settings_attributes_forward_deployment_enabled')
expect(checkbox).to be_checked
checkbox.set(false)
@@ -79,7 +79,7 @@ RSpec.describe "Projects > Settings > Pipelines settings" do
expect(page).to have_button('Save changes', disabled: false)
end
- checkbox = find_field('project_forward_deployment_enabled')
+ checkbox = find_field('project_ci_cd_settings_attributes_forward_deployment_enabled')
expect(checkbox).not_to be_checked
end
diff --git a/spec/features/projects/settings/registry_settings_spec.rb b/spec/features/projects/settings/registry_settings_spec.rb
index 8e2f97fd6a0..4e1b53ffc87 100644
--- a/spec/features/projects/settings/registry_settings_spec.rb
+++ b/spec/features/projects/settings/registry_settings_spec.rb
@@ -3,27 +3,35 @@
require 'spec_helper'
RSpec.describe 'Project > Settings > CI/CD > Container registry tag expiration policy', :js do
- let(:user) { create(:user) }
- let(:project) { create(:project, namespace: user.namespace, container_registry_enabled: container_registry_enabled) }
+ using RSpec::Parameterized::TableSyntax
+
+ let_it_be(:user) { create(:user) }
+ let_it_be(:project, reload: true) { create(:project, namespace: user.namespace) }
+
let(:container_registry_enabled) { true }
+ let(:container_registry_enabled_on_project) { true }
+
+ subject { visit project_settings_ci_cd_path(project) }
before do
+ project.update!(container_registry_enabled: container_registry_enabled_on_project)
+
sign_in(user)
- stub_container_registry_config(enabled: true)
+ stub_container_registry_config(enabled: container_registry_enabled)
stub_feature_flags(new_variables_ui: false)
end
context 'as owner' do
- before do
- visit project_settings_ci_cd_path(project)
- end
-
it 'shows available section' do
+ subject
+
settings_block = find('#js-registry-policies')
expect(settings_block).to have_text 'Cleanup policy for tags'
end
it 'saves cleanup policy submit the form' do
+ subject
+
within '#js-registry-policies' do
within '.card-body' do
select('7 days until tags are automatically removed', from: 'Expiration interval:')
@@ -40,6 +48,8 @@ RSpec.describe 'Project > Settings > CI/CD > Container registry tag expiration p
end
it 'does not save cleanup policy submit form with invalid regex' do
+ subject
+
within '#js-registry-policies' do
within '.card-body' do
fill_in('Tags with names matching this regex pattern will expire:', with: '*-production')
@@ -53,25 +63,53 @@ RSpec.describe 'Project > Settings > CI/CD > Container registry tag expiration p
end
end
- context 'when registry is disabled' do
- before do
- stub_container_registry_config(enabled: false)
- visit project_settings_ci_cd_path(project)
+ context 'with a project without expiration policy' do
+ where(:application_setting, :feature_flag, :result) do
+ true | true | :available_section
+ true | false | :available_section
+ false | true | :available_section
+ false | false | :disabled_message
end
- it 'does not exists' do
- expect(page).not_to have_selector('#js-registry-policies')
+ with_them do
+ before do
+ project.container_expiration_policy.destroy!
+ stub_feature_flags(container_expiration_policies_historic_entry: false)
+ stub_application_setting(container_expiration_policies_enable_historic_entries: application_setting)
+ stub_feature_flags(container_expiration_policies_historic_entry: project) if feature_flag
+ end
+
+ it 'displays the expected result' do
+ subject
+
+ within '#js-registry-policies' do
+ case result
+ when :available_section
+ expect(find('.card-header')).to have_content('Tag expiration policy')
+ when :disabled_message
+ expect(find('.gl-alert-title')).to have_content('Cleanup policy for tags is disabled')
+ end
+ end
+ end
end
end
- context 'when container registry is disabled on project' do
+ context 'when registry is disabled' do
let(:container_registry_enabled) { false }
- before do
- visit project_settings_ci_cd_path(project)
+ it 'does not exists' do
+ subject
+
+ expect(page).not_to have_selector('#js-registry-policies')
end
+ end
+
+ context 'when container registry is disabled on project' do
+ let(:container_registry_enabled_on_project) { false }
it 'does not exists' do
+ subject
+
expect(page).not_to have_selector('#js-registry-policies')
end
end
diff --git a/spec/features/projects/show/user_manages_notifications_spec.rb b/spec/features/projects/show/user_manages_notifications_spec.rb
index 9d9a75c22be..d444ea27d35 100644
--- a/spec/features/projects/show/user_manages_notifications_spec.rb
+++ b/spec/features/projects/show/user_manages_notifications_spec.rb
@@ -18,7 +18,9 @@ RSpec.describe 'Projects > Show > User manages notifications', :js do
click_notifications_button
click_link 'On mention'
- wait_for_requests
+ page.within('.notification-dropdown') do
+ expect(page).not_to have_css('.gl-spinner')
+ end
click_notifications_button
expect(find('.update-notification.is-active')).to have_content('On mention')
@@ -30,7 +32,9 @@ RSpec.describe 'Projects > Show > User manages notifications', :js do
click_notifications_button
click_link 'Disabled'
- wait_for_requests
+ page.within('.notification-dropdown') do
+ expect(page).not_to have_css('.gl-spinner')
+ end
expect(page).to have_css('.notifications-icon[data-testid="notifications-off-icon"]')
end
diff --git a/spec/features/projects/show/user_sees_setup_shortcut_buttons_spec.rb b/spec/features/projects/show/user_sees_setup_shortcut_buttons_spec.rb
index 81736fefae9..189aa45ff75 100644
--- a/spec/features/projects/show/user_sees_setup_shortcut_buttons_spec.rb
+++ b/spec/features/projects/show/user_sees_setup_shortcut_buttons_spec.rb
@@ -46,21 +46,21 @@ RSpec.describe 'Projects > Show > User sees setup shortcut buttons' do
visit project_path(project)
end
- it '"New file" button linked to new file page' do
+ it '"New file" button linked to IDE new file page' do
page.within('.project-buttons') do
- expect(page).to have_link('New file', href: project_new_blob_path(project, project.default_branch || 'master'))
+ expect(page).to have_link('New file', href: presenter.ide_edit_path(project, project.default_branch || 'master'))
end
end
- it '"Add README" button linked to new file populated for a README' do
+ it '"Add README" button linked to IDE new file populated for a README' do
page.within('.project-buttons') do
- expect(page).to have_link('Add README', href: presenter.add_readme_path)
+ expect(page).to have_link('Add README', href: presenter.add_readme_ide_path)
end
end
- it '"Add license" button linked to new file populated for a license' do
+ it '"Add license" button linked to IDE new file populated for a license' do
page.within('.project-buttons') do
- expect(page).to have_link('Add LICENSE', href: presenter.add_license_path)
+ expect(page).to have_link('Add LICENSE', href: presenter.add_license_ide_path)
end
end
@@ -74,9 +74,9 @@ RSpec.describe 'Projects > Show > User sees setup shortcut buttons' do
visit project_path(project)
end
- it '"New file" button linked to new file page' do
+ it '"New file" button linked to IDE new file page' do
page.within('.project-buttons') do
- expect(page).to have_link('New file', href: project_new_blob_path(project, 'example_branch'))
+ expect(page).to have_link('New file', href: presenter.ide_edit_path(project, 'example_branch'))
end
end
end
@@ -144,7 +144,7 @@ RSpec.describe 'Projects > Show > User sees setup shortcut buttons' do
expect(project.repository.readme).not_to be_nil
page.within('.project-buttons') do
- expect(page).not_to have_link('Add README', href: presenter.add_readme_path)
+ expect(page).not_to have_link('Add README', href: presenter.add_readme_ide_path)
expect(page).to have_link('README', href: presenter.readme_path)
end
end
@@ -164,7 +164,7 @@ RSpec.describe 'Projects > Show > User sees setup shortcut buttons' do
end
context 'when the project does not have a README' do
- it 'shows the "Add README" button' do
+ it 'shows the single file editor "Add README" button' do
allow(project.repository).to receive(:readme).and_return(nil)
visit project_path(project)
@@ -226,7 +226,7 @@ RSpec.describe 'Projects > Show > User sees setup shortcut buttons' do
expect(project.repository.gitlab_ci_yml).to be_nil
page.within('.project-buttons') do
- expect(page).to have_link('Set up CI/CD', href: presenter.add_ci_yml_ide_path)
+ expect(page).to have_link('Set up CI/CD', href: presenter.add_ci_yml_path)
end
end
diff --git a/spec/features/projects/snippets/create_snippet_spec.rb b/spec/features/projects/snippets/create_snippet_spec.rb
index 503246bbdcf..28fe0a0b7e1 100644
--- a/spec/features/projects/snippets/create_snippet_spec.rb
+++ b/spec/features/projects/snippets/create_snippet_spec.rb
@@ -17,115 +17,81 @@ RSpec.describe 'Projects > Snippets > Create Snippet', :js do
let(:file_content) { 'Hello World!' }
let(:md_description) { 'My Snippet **Description**' }
let(:description) { 'My Snippet Description' }
- let(:snippet_title_field) { 'project_snippet_title' }
- shared_examples 'snippet creation' do
- def fill_form
- snippet_fill_in_form(title: title, content: file_content, description: md_description)
- end
-
- it 'shows collapsible description input' do
- collapsed = description_field
+ def fill_form
+ snippet_fill_in_form(title: title, content: file_content, description: md_description)
+ end
- expect(page).not_to have_field(snippet_description_field)
- expect(collapsed).to be_visible
+ before do
+ sign_in(user)
- collapsed.click
+ visit new_project_snippet_path(project)
+ end
- expect(page).to have_field(snippet_description_field)
- expect(collapsed).not_to be_visible
- end
+ it 'shows collapsible description input' do
+ collapsed = snippet_description_field_collapsed
- it 'creates a new snippet' do
- fill_form
- click_button('Create snippet')
- wait_for_requests
+ expect(page).not_to have_field(snippet_description_locator)
+ expect(collapsed).to be_visible
- expect(page).to have_content(title)
- expect(page).to have_content(file_content)
- page.within(snippet_description_view_selector) do
- expect(page).to have_content(description)
- expect(page).to have_selector('strong')
- end
- end
+ collapsed.click
- it 'uploads a file when dragging into textarea' do
- fill_form
- dropzone_file Rails.root.join('spec', 'fixtures', 'banana_sample.gif')
-
- expect(snippet_description_value).to have_content('banana_sample')
+ expect(page).to have_field(snippet_description_locator)
+ expect(collapsed).not_to be_visible
+ end
- click_button('Create snippet')
- wait_for_requests
+ it 'creates a new snippet' do
+ fill_form
+ click_button('Create snippet')
+ wait_for_requests
- link = find('a.no-attachment-icon img[alt="banana_sample"]')['src']
- expect(link).to match(%r{/#{Regexp.escape(project.full_path)}/uploads/\h{32}/banana_sample\.gif\z})
+ expect(page).to have_content(title)
+ expect(page).to have_content(file_content)
+ page.within('.snippet-header .snippet-description') do
+ expect(page).to have_content(description)
+ expect(page).to have_selector('strong')
end
+ end
- context 'when the git operation fails' do
- let(:error) { 'Error creating the snippet' }
-
- before do
- allow_next_instance_of(Snippets::CreateService) do |instance|
- allow(instance).to receive(:create_commit).and_raise(StandardError, error)
- end
+ it 'uploads a file when dragging into textarea' do
+ fill_form
+ dropzone_file Rails.root.join('spec', 'fixtures', 'banana_sample.gif')
- fill_form
+ expect(snippet_description_value).to have_content('banana_sample')
- click_button('Create snippet')
- wait_for_requests
- end
+ click_button('Create snippet')
+ wait_for_requests
- it 'renders the new page and displays the error' do
- expect(page).to have_content(error)
- expect(page).to have_content('New Snippet')
- end
- end
+ link = find('a.no-attachment-icon img[alt="banana_sample"]')['src']
+ expect(link).to match(%r{/#{Regexp.escape(project.full_path)}/uploads/\h{32}/banana_sample\.gif\z})
end
- context 'Vue application' do
- let(:snippet_description_field) { 'snippet-description' }
- let(:snippet_description_view_selector) { '.snippet-header .snippet-description' }
+ context 'when the git operation fails' do
+ let(:error) { 'Error creating the snippet' }
before do
- sign_in(user)
-
- visit new_project_snippet_path(project)
- end
-
- it_behaves_like 'snippet creation'
-
- it 'does not allow submitting the form without title and content' do
- fill_in snippet_title_field, with: title
+ allow_next_instance_of(Snippets::CreateService) do |instance|
+ allow(instance).to receive(:create_commit).and_raise(StandardError, error)
+ end
- expect(page).not_to have_button('Create snippet')
+ fill_form
- snippet_fill_in_form(title: title, content: file_content)
- expect(page).to have_button('Create snippet')
+ click_button('Create snippet')
+ wait_for_requests
end
- end
-
- context 'non-Vue application' do
- let(:snippet_description_field) { 'project_snippet_description' }
- let(:snippet_description_view_selector) { '.snippet-header .description' }
-
- before do
- stub_feature_flags(snippets_vue: false)
- stub_feature_flags(snippets_edit_vue: false)
-
- sign_in(user)
- visit new_project_snippet_path(project)
+ it 'renders the new page and displays the error' do
+ expect(page).to have_content(error)
+ expect(page).to have_content('New Snippet')
end
+ end
- it_behaves_like 'snippet creation'
+ it 'does not allow submitting the form without title and content' do
+ snippet_fill_in_title(title)
- it 'displays validation errors' do
- fill_in snippet_title_field, with: title
- click_button('Create snippet')
- wait_for_requests
+ expect(page).not_to have_button('Create snippet')
- expect(page).to have_selector('#error_explanation')
- end
+ snippet_fill_in_form(title: title, content: file_content)
+ expect(page).to have_button('Create snippet')
end
end
diff --git a/spec/features/projects/snippets/show_spec.rb b/spec/features/projects/snippets/show_spec.rb
index 8fded3cde80..5937ff75457 100644
--- a/spec/features/projects/snippets/show_spec.rb
+++ b/spec/features/projects/snippets/show_spec.rb
@@ -13,8 +13,6 @@ RSpec.describe 'Projects > Snippets > Project snippet', :js do
let_it_be(:snippet) { create(:project_snippet, :repository, project: project, author: user) }
before do
- stub_feature_flags(snippets_vue: false)
-
sign_in(user)
end
@@ -28,12 +26,8 @@ RSpec.describe 'Projects > Snippets > Project snippet', :js do
end
end
- it_behaves_like 'showing user status' do
- let(:file_path) { 'files/ruby/popen.rb' }
- let(:user_with_status) { snippet.author }
-
- subject { visit project_snippet_path(project, snippet) }
- end
+ # it_behaves_like 'showing user status' do
+ # This will be handled in https://gitlab.com/gitlab-org/gitlab/-/issues/262394
it_behaves_like 'does not show New Snippet button' do
let(:file_path) { 'files/ruby/popen.rb' }
diff --git a/spec/features/projects/snippets/user_comments_on_snippet_spec.rb b/spec/features/projects/snippets/user_comments_on_snippet_spec.rb
index 2784fec3dc1..b37d40c0eed 100644
--- a/spec/features/projects/snippets/user_comments_on_snippet_spec.rb
+++ b/spec/features/projects/snippets/user_comments_on_snippet_spec.rb
@@ -8,7 +8,6 @@ RSpec.describe 'Projects > Snippets > User comments on a snippet', :js do
let_it_be(:snippet) { create(:project_snippet, :repository, project: project, author: user) }
before do
- stub_feature_flags(snippets_vue: false)
project.add_maintainer(user)
sign_in(user)
diff --git a/spec/features/projects/snippets/user_deletes_snippet_spec.rb b/spec/features/projects/snippets/user_deletes_snippet_spec.rb
index 44fe9834484..6d526e60512 100644
--- a/spec/features/projects/snippets/user_deletes_snippet_spec.rb
+++ b/spec/features/projects/snippets/user_deletes_snippet_spec.rb
@@ -2,13 +2,12 @@
require 'spec_helper'
-RSpec.describe 'Projects > Snippets > User deletes a snippet' do
+RSpec.describe 'Projects > Snippets > User deletes a snippet', :js do
let(:project) { create(:project) }
- let!(:snippet) { create(:project_snippet, project: project, author: user) }
+ let!(:snippet) { create(:project_snippet, :repository, project: project, author: user) }
let(:user) { create(:user) }
before do
- stub_feature_flags(snippets_vue: false)
project.add_maintainer(user)
sign_in(user)
@@ -16,7 +15,11 @@ RSpec.describe 'Projects > Snippets > User deletes a snippet' do
end
it 'deletes a snippet' do
- first(:link, 'Delete').click
+ expect(page).to have_content(snippet.title)
+
+ click_button('Delete')
+ click_button('Delete snippet')
+ wait_for_requests
expect(page).not_to have_content(snippet.title)
end
diff --git a/spec/features/projects/snippets/user_updates_snippet_spec.rb b/spec/features/projects/snippets/user_updates_snippet_spec.rb
index 193eaa9576a..aa498163f52 100644
--- a/spec/features/projects/snippets/user_updates_snippet_spec.rb
+++ b/spec/features/projects/snippets/user_updates_snippet_spec.rb
@@ -9,9 +9,7 @@ RSpec.describe 'Projects > Snippets > User updates a snippet', :js do
let_it_be(:project) { create(:project, namespace: user.namespace) }
let_it_be(:snippet, reload: true) { create(:project_snippet, :repository, project: project, author: user) }
- let(:snippet_title_field) { 'project_snippet_title' }
-
- def bootstrap_snippet
+ before do
project.add_maintainer(user)
sign_in(user)
@@ -20,64 +18,36 @@ RSpec.describe 'Projects > Snippets > User updates a snippet', :js do
wait_for_all_requests
end
- shared_examples 'snippet update' do
- it 'displays the snippet blob path and content' do
- blob = snippet.blobs.first
-
- aggregate_failures do
- expect(snippet_get_first_blob_path).to eq blob.path
- expect(snippet_get_first_blob_value).to have_content(blob.data.strip)
- end
- end
-
- it 'updates a snippet' do
- fill_in('project_snippet_title', with: 'Snippet new title')
- click_button('Save')
+ it 'displays the snippet blob path and content' do
+ blob = snippet.blobs.first
- expect(page).to have_content('Snippet new title')
- end
-
- context 'when the git operation fails' do
- before do
- allow_next_instance_of(Snippets::UpdateService) do |instance|
- allow(instance).to receive(:create_commit).and_raise(StandardError, 'Error Message')
- end
-
- fill_in(snippet_title_field, with: 'Snippet new title')
- fill_in(snippet_blob_path_field, match: :first, with: 'new_file_name')
-
- click_button('Save')
- end
-
- it 'renders edit page and displays the error' do
- expect(page.find('.flash-container')).to have_content('Error updating the snippet - Error Message')
- expect(page).to have_content('Edit Snippet')
- end
+ aggregate_failures do
+ expect(snippet_get_first_blob_path).to eq blob.path
+ expect(snippet_get_first_blob_value).to have_content(blob.data.strip)
end
end
- context 'Vue application' do
- before do
- bootstrap_snippet
- end
+ it 'updates a snippet' do
+ fill_in('snippet-title', with: 'Snippet new title')
+ click_button('Save')
- it_behaves_like 'snippet update' do
- let(:snippet_blob_path_field) { 'snippet_file_name' }
- let(:snippet_blob_content_selector) { '.file-content' }
- end
+ expect(page).to have_content('Snippet new title')
end
- context 'non-Vue application' do
+ context 'when the git operation fails' do
before do
- stub_feature_flags(snippets_vue: false)
- stub_feature_flags(snippets_edit_vue: false)
+ allow_next_instance_of(Snippets::UpdateService) do |instance|
+ allow(instance).to receive(:create_commit).and_raise(StandardError, 'Error Message')
+ end
- bootstrap_snippet
+ snippet_fill_in_form(title: 'Snippet new title', file_name: 'new_file_name')
+
+ click_button('Save')
end
- it_behaves_like 'snippet update' do
- let(:snippet_blob_path_field) { 'project_snippet_file_name' }
- let(:snippet_blob_content_selector) { '.file-content' }
+ it 'renders edit page and displays the error' do
+ expect(page.find('.flash-container')).to have_content('Error updating the snippet - Error Message')
+ expect(page).to have_content('Edit Snippet')
end
end
end
diff --git a/spec/features/projects/tracings_spec.rb b/spec/features/projects/tracings_spec.rb
new file mode 100644
index 00000000000..c4a4f1382ed
--- /dev/null
+++ b/spec/features/projects/tracings_spec.rb
@@ -0,0 +1,63 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Tracings Content Security Policy' do
+ let_it_be(:project) { create(:project) }
+ let_it_be(:user) { create(:user) }
+
+ subject { response_headers['Content-Security-Policy'] }
+
+ before_all do
+ project.add_maintainer(user)
+ end
+
+ before do
+ sign_in(user)
+ end
+
+ context 'when there is no global config' do
+ before do
+ expect_next_instance_of(Projects::TracingsController) do |controller|
+ expect(controller).to receive(:current_content_security_policy)
+ .and_return(ActionDispatch::ContentSecurityPolicy.new)
+ end
+ end
+
+ it 'does not add CSP directives' do
+ visit project_tracing_path(project)
+
+ is_expected.to be_blank
+ end
+ end
+
+ context 'when a global CSP config exists' do
+ before do
+ csp = ActionDispatch::ContentSecurityPolicy.new do |p|
+ p.frame_src 'https://global-policy.com'
+ end
+
+ expect_next_instance_of(Projects::TracingsController) do |controller|
+ expect(controller).to receive(:current_content_security_policy).and_return(csp)
+ end
+ end
+
+ context 'when external_url is set' do
+ let!(:project_tracing_setting) { create(:project_tracing_setting, project: project) }
+
+ it 'overwrites frame-src' do
+ visit project_tracing_path(project)
+
+ is_expected.to eq("frame-src https://example.com")
+ end
+ end
+
+ context 'when external_url is not set' do
+ it 'uses global policy' do
+ visit project_tracing_path(project)
+
+ is_expected.to eq("frame-src https://global-policy.com")
+ end
+ end
+ end
+end
diff --git a/spec/features/projects/tree/tree_show_spec.rb b/spec/features/projects/tree/tree_show_spec.rb
index bd2af66710a..ca9e0a23888 100644
--- a/spec/features/projects/tree/tree_show_spec.rb
+++ b/spec/features/projects/tree/tree_show_spec.rb
@@ -69,7 +69,7 @@ RSpec.describe 'Projects tree', :js do
# Check last commit
expect(find('.commit-content').text).to include(message)
- expect(find('.commit-sha-group').text).to eq(short_newrev)
+ expect(find('.js-commit-sha-group').text).to eq(short_newrev)
end
end
diff --git a/spec/features/projects/user_sees_sidebar_spec.rb b/spec/features/projects/user_sees_sidebar_spec.rb
index 50d7b353c46..616c5065c07 100644
--- a/spec/features/projects/user_sees_sidebar_spec.rb
+++ b/spec/features/projects/user_sees_sidebar_spec.rb
@@ -128,6 +128,59 @@ RSpec.describe 'Projects > User sees sidebar' do
end
end
+ context 'as anonymous' do
+ let(:project) { create(:project, :public) }
+ let!(:issue) { create(:issue, :opened, project: project, author: user) }
+
+ describe 'project landing page' do
+ before do
+ project.project_feature.update!(
+ builds_access_level: ProjectFeature::DISABLED,
+ merge_requests_access_level: ProjectFeature::DISABLED,
+ repository_access_level: ProjectFeature::DISABLED,
+ issues_access_level: ProjectFeature::DISABLED,
+ wiki_access_level: ProjectFeature::DISABLED
+ )
+ end
+
+ it 'does not show the project file list landing page, but the activity' do
+ visit project_path(project)
+
+ expect(page).not_to have_selector '.project-stats'
+ expect(page).not_to have_selector '.project-last-commit'
+ expect(page).not_to have_selector '.project-show-files'
+ expect(page).to have_selector '.project-show-activity'
+ end
+
+ it 'shows the wiki when enabled' do
+ project.project_feature.update!(wiki_access_level: ProjectFeature::ENABLED)
+
+ visit project_path(project)
+
+ expect(page).to have_selector '.project-show-wiki'
+ end
+
+ it 'shows the issues when enabled' do
+ project.project_feature.update!(issues_access_level: ProjectFeature::ENABLED)
+
+ visit project_path(project)
+
+ expect(page).to have_selector '.issues-list'
+ end
+
+ it 'shows the wiki when wiki and issues are enabled' do
+ project.project_feature.update!(
+ issues_access_level: ProjectFeature::ENABLED,
+ wiki_access_level: ProjectFeature::ENABLED
+ )
+
+ visit project_path(project)
+
+ expect(page).to have_selector '.project-show-wiki'
+ end
+ end
+ end
+
context 'as guest' do
let(:guest) { create(:user) }
let!(:issue) { create(:issue, :opened, project: project, author: guest) }
@@ -145,11 +198,11 @@ RSpec.describe 'Projects > User sees sidebar' do
expect(page).to have_content 'Project'
expect(page).to have_content 'Issues'
expect(page).to have_content 'Wiki'
+ expect(page).to have_content 'Operations'
expect(page).not_to have_content 'Repository'
expect(page).not_to have_content 'CI / CD'
expect(page).not_to have_content 'Merge Requests'
- expect(page).not_to have_content 'Operations'
end
end
@@ -194,13 +247,13 @@ RSpec.describe 'Projects > User sees sidebar' do
expect(page).not_to have_selector '.project-stats'
expect(page).not_to have_selector '.project-last-commit'
expect(page).not_to have_selector '.project-show-files'
- expect(page).to have_selector '.project-show-customize_workflow'
+ expect(page).to have_selector '.project-show-activity'
end
- it 'shows the customize workflow when issues and wiki are disabled' do
+ it 'shows the project activity when issues and wiki are disabled' do
visit project_path(project)
- expect(page).to have_selector '.project-show-customize_workflow'
+ expect(page).to have_selector '.project-show-activity'
end
it 'shows the wiki when enabled' do
diff --git a/spec/features/projects/wiki/markdown_preview_spec.rb b/spec/features/projects/wiki/markdown_preview_spec.rb
deleted file mode 100644
index 8f2fb9e827c..00000000000
--- a/spec/features/projects/wiki/markdown_preview_spec.rb
+++ /dev/null
@@ -1,168 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe 'Projects > Wiki > User previews markdown changes', :js do
- let_it_be(:user) { create(:user) }
- let(:project) { create(:project, :wiki_repo, namespace: user.namespace) }
- let(:wiki_page) { create(:wiki_page, wiki: project.wiki, title: 'home', content: '[some link](other-page)') }
- let(:wiki_content) do
- <<-HEREDOC
-Some text so key event for [ does not trigger an incorrect replacement.
-[regular link](regular)
-[relative link 1](../relative)
-[relative link 2](./relative)
-[relative link 3](./e/f/relative)
-[spaced link](title with spaces)
- HEREDOC
- end
-
- before do
- project.add_maintainer(user)
-
- sign_in(user)
- end
-
- context "while creating a new wiki page" do
- context "when there are no spaces or hyphens in the page name" do
- it "rewrites relative links as expected" do
- create_wiki_page('a/b/c/d', content: wiki_content)
-
- expect(page).to have_content("regular link")
-
- expect(page.html).to include("<a href=\"/#{project.full_path}/-/wikis/regular\">regular link</a>")
- expect(page.html).to include("<a href=\"/#{project.full_path}/-/wikis/a/b/relative\">relative link 1</a>")
- expect(page.html).to include("<a href=\"/#{project.full_path}/-/wikis/a/b/c/relative\">relative link 2</a>")
- expect(page.html).to include("<a href=\"/#{project.full_path}/-/wikis/a/b/c/e/f/relative\">relative link 3</a>")
- expect(page.html).to include("<a href=\"/#{project.full_path}/-/wikis/title%20with%20spaces\">spaced link</a>")
- end
- end
-
- context "when there are spaces in the page name" do
- it "rewrites relative links as expected" do
- create_wiki_page('a page/b page/c page/d page', content: wiki_content)
-
- expect(page).to have_content("regular link")
-
- expect(page.html).to include("<a href=\"/#{project.full_path}/-/wikis/regular\">regular link</a>")
- expect(page.html).to include("<a href=\"/#{project.full_path}/-/wikis/a-page/b-page/relative\">relative link 1</a>")
- expect(page.html).to include("<a href=\"/#{project.full_path}/-/wikis/a-page/b-page/c-page/relative\">relative link 2</a>")
- expect(page.html).to include("<a href=\"/#{project.full_path}/-/wikis/a-page/b-page/c-page/e/f/relative\">relative link 3</a>")
- expect(page.html).to include("<a href=\"/#{project.full_path}/-/wikis/title%20with%20spaces\">spaced link</a>")
- end
- end
-
- context "when there are hyphens in the page name" do
- it "rewrites relative links as expected" do
- create_wiki_page('a-page/b-page/c-page/d-page', content: wiki_content)
-
- expect(page).to have_content("regular link")
-
- expect(page.html).to include("<a href=\"/#{project.full_path}/-/wikis/regular\">regular link</a>")
- expect(page.html).to include("<a href=\"/#{project.full_path}/-/wikis/a-page/b-page/relative\">relative link 1</a>")
- expect(page.html).to include("<a href=\"/#{project.full_path}/-/wikis/a-page/b-page/c-page/relative\">relative link 2</a>")
- expect(page.html).to include("<a href=\"/#{project.full_path}/-/wikis/a-page/b-page/c-page/e/f/relative\">relative link 3</a>")
- expect(page.html).to include("<a href=\"/#{project.full_path}/-/wikis/title%20with%20spaces\">spaced link</a>")
- end
- end
- end
-
- context "while editing a wiki page" do
- context "when there are no spaces or hyphens in the page name" do
- it "rewrites relative links as expected" do
- create_wiki_page('a/b/c/d')
- click_link 'Edit'
-
- fill_in :wiki_content, with: wiki_content
- click_on "Preview"
-
- expect(page).to have_content("regular link")
-
- expect(page.html).to include("<a href=\"/#{project.full_path}/-/wikis/regular\">regular link</a>")
- expect(page.html).to include("<a href=\"/#{project.full_path}/-/wikis/a/b/relative\">relative link 1</a>")
- expect(page.html).to include("<a href=\"/#{project.full_path}/-/wikis/a/b/c/relative\">relative link 2</a>")
- expect(page.html).to include("<a href=\"/#{project.full_path}/-/wikis/a/b/c/e/f/relative\">relative link 3</a>")
- expect(page.html).to include("<a href=\"/#{project.full_path}/-/wikis/title%20with%20spaces\">spaced link</a>")
- end
- end
-
- context "when there are spaces in the page name" do
- it "rewrites relative links as expected" do
- create_wiki_page('a page/b page/c page/d page')
- click_link 'Edit'
-
- fill_in :wiki_content, with: wiki_content
- click_on "Preview"
-
- expect(page).to have_content("regular link")
-
- expect(page.html).to include("<a href=\"/#{project.full_path}/-/wikis/regular\">regular link</a>")
- expect(page.html).to include("<a href=\"/#{project.full_path}/-/wikis/a-page/b-page/relative\">relative link 1</a>")
- expect(page.html).to include("<a href=\"/#{project.full_path}/-/wikis/a-page/b-page/c-page/relative\">relative link 2</a>")
- expect(page.html).to include("<a href=\"/#{project.full_path}/-/wikis/a-page/b-page/c-page/e/f/relative\">relative link 3</a>")
- expect(page.html).to include("<a href=\"/#{project.full_path}/-/wikis/title%20with%20spaces\">spaced link</a>")
- end
- end
-
- context "when there are hyphens in the page name" do
- it "rewrites relative links as expected" do
- create_wiki_page('a-page/b-page/c-page/d-page')
- click_link 'Edit'
-
- fill_in :wiki_content, with: wiki_content
- click_on "Preview"
-
- expect(page).to have_content("regular link")
-
- expect(page.html).to include("<a href=\"/#{project.full_path}/-/wikis/regular\">regular link</a>")
- expect(page.html).to include("<a href=\"/#{project.full_path}/-/wikis/a-page/b-page/relative\">relative link 1</a>")
- expect(page.html).to include("<a href=\"/#{project.full_path}/-/wikis/a-page/b-page/c-page/relative\">relative link 2</a>")
- expect(page.html).to include("<a href=\"/#{project.full_path}/-/wikis/a-page/b-page/c-page/e/f/relative\">relative link 3</a>")
- expect(page.html).to include("<a href=\"/#{project.full_path}/-/wikis/title%20with%20spaces\">spaced link</a>")
- end
- end
-
- context 'when rendering the preview' do
- it 'renders content with CommonMark' do
- create_wiki_page('a-page/b-page/c-page/common-mark')
- click_link 'Edit'
-
- fill_in :wiki_content, with: "1. one\n - sublist\n"
- click_on "Preview"
-
- # the above generates two separate lists (not embedded) in CommonMark
- expect(page).to have_content("sublist")
- expect(page).not_to have_xpath("//ol//li//ul")
- end
- end
- end
-
- it "does not linkify double brackets inside code blocks as expected" do
- wiki_content = <<-HEREDOC
- `[[do_not_linkify]]`
- ```
- [[also_do_not_linkify]]
- ```
- HEREDOC
-
- create_wiki_page('linkify_test', wiki_content)
-
- expect(page).to have_content("do_not_linkify")
-
- expect(page.html).to include('[[do_not_linkify]]')
- expect(page.html).to include('[[also_do_not_linkify]]')
- end
-
- private
-
- def create_wiki_page(path, content = 'content')
- visit project_wiki_path(project, wiki_page)
-
- click_link 'New page'
-
- fill_in :wiki_title, with: path
- fill_in :wiki_content, with: content
-
- click_button 'Create page'
- end
-end
diff --git a/spec/features/projects/wiki/shortcuts_spec.rb b/spec/features/projects/wiki/shortcuts_spec.rb
deleted file mode 100644
index 170e7afb51f..00000000000
--- a/spec/features/projects/wiki/shortcuts_spec.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe 'Wiki shortcuts', :js do
- let(:user) { create(:user) }
- let(:project) { create(:project, :wiki_repo, namespace: user.namespace) }
- let(:wiki_page) { create(:wiki_page, wiki: project.wiki, title: 'home', content: 'Home page') }
-
- before do
- sign_in(user)
- visit project_wiki_path(project, wiki_page)
- end
-
- it 'Visit edit wiki page using "e" keyboard shortcut' do
- find('body').native.send_key('e')
-
- expect(find('.wiki-page-title')).to have_content('Edit Page')
- end
-end
diff --git a/spec/features/projects/wiki/user_creates_wiki_page_spec.rb b/spec/features/projects/wiki/user_creates_wiki_page_spec.rb
deleted file mode 100644
index eba1b63765a..00000000000
--- a/spec/features/projects/wiki/user_creates_wiki_page_spec.rb
+++ /dev/null
@@ -1,360 +0,0 @@
-# frozen_string_literal: true
-
-require "spec_helper"
-
-RSpec.describe "User creates wiki page" do
- include WikiHelpers
-
- let(:user) { create(:user) }
- let(:wiki) { ProjectWiki.new(project, user) }
- let(:project) { create(:project) }
-
- before do
- project.add_maintainer(user)
-
- sign_in(user)
- end
-
- context "when wiki is empty" do
- before do |example|
- visit(project_wikis_path(project))
-
- wait_for_svg_to_be_loaded(example)
-
- click_link "Create your first page"
- end
-
- context "in a user namespace" do
- let(:project) { create(:project, :wiki_repo, namespace: user.namespace) }
-
- it "shows validation error message" do
- page.within(".wiki-form") do
- fill_in(:wiki_content, with: "")
-
- click_on("Create page")
- end
-
- expect(page).to have_content("The form contains the following error:").and have_content("Content can't be blank")
-
- page.within(".wiki-form") do
- fill_in(:wiki_content, with: "[link test](test)")
-
- click_on("Create page")
- end
-
- expect(page).to have_content("Home").and have_content("link test")
-
- click_link("link test")
-
- expect(page).to have_content("Create New Page")
- end
-
- it "shows non-escaped link in the pages list" do
- fill_in(:wiki_title, with: "one/two/three-test")
-
- page.within(".wiki-form") do
- fill_in(:wiki_content, with: "wiki content")
-
- click_on("Create page")
- end
-
- expect(current_path).to include("one/two/three-test")
- expect(page).to have_xpath("//a[@href='/#{project.full_path}/-/wikis/one/two/three-test']")
- end
-
- it "has `Create home` as a commit message", :js do
- wait_for_requests
-
- expect(page).to have_field("wiki[message]", with: "Create home")
- end
-
- it "creates a page from the home page" do
- fill_in(:wiki_content, with: "[test](test)\n[GitLab API doc](api)\n[Rake tasks](raketasks)\n# Wiki header\n")
- fill_in(:wiki_message, with: "Adding links to wiki")
-
- page.within(".wiki-form") do
- click_button("Create page")
- end
-
- expect(current_path).to eq(project_wiki_path(project, "home"))
- expect(page).to have_content("test GitLab API doc Rake tasks Wiki header")
- .and have_content("Home")
- .and have_content("Last edited by #{user.name}")
- .and have_header_with_correct_id_and_link(1, "Wiki header", "wiki-header")
-
- click_link("test")
-
- expect(current_path).to eq(project_wiki_path(project, "test"))
-
- page.within(:css, ".nav-text") do
- expect(page).to have_content("Create New Page")
- end
-
- click_link("Home")
-
- expect(current_path).to eq(project_wiki_path(project, "home"))
-
- click_link("GitLab API")
-
- expect(current_path).to eq(project_wiki_path(project, "api"))
-
- page.within(:css, ".nav-text") do
- expect(page).to have_content("Create")
- end
-
- click_link("Home")
-
- expect(current_path).to eq(project_wiki_path(project, "home"))
-
- click_link("Rake tasks")
-
- expect(current_path).to eq(project_wiki_path(project, "raketasks"))
-
- page.within(:css, ".nav-text") do
- expect(page).to have_content("Create")
- end
- end
-
- it "creates ASCII wiki with LaTeX blocks", :js do
- stub_application_setting(plantuml_url: "http://localhost", plantuml_enabled: true)
-
- ascii_content = <<~MD
- :stem: latexmath
-
- [stem]
- ++++
- \\sqrt{4} = 2
- ++++
-
- another part
-
- [latexmath]
- ++++
- \\beta_x \\gamma
- ++++
-
- stem:[2+2] is 4
- MD
-
- find("#wiki_format option[value=asciidoc]").select_option
-
- fill_in(:wiki_content, with: ascii_content)
-
- page.within(".wiki-form") do
- click_button("Create page")
- end
-
- page.within ".md" do
- expect(page).to have_selector(".katex", count: 3).and have_content("2+2 is 4")
- end
- end
-
- it 'creates a wiki page with Org markup', :aggregate_failures do
- org_content = <<~ORG
- * Heading
- ** Subheading
- [[home][Link to Home]]
- ORG
-
- page.within('.wiki-form') do
- find('#wiki_format option[value=org]').select_option
- fill_in(:wiki_content, with: org_content)
- click_button('Create page')
- end
-
- expect(page).to have_selector('h1', text: 'Heading')
- expect(page).to have_selector('h2', text: 'Subheading')
- expect(page).to have_link('Link to Home', href: "/#{project.full_path}/-/wikis/home")
- end
-
- it_behaves_like 'wiki file attachments'
- end
-
- context "in a group namespace", :js do
- let(:project) { create(:project, :wiki_repo, namespace: create(:group, :public)) }
-
- it "has `Create home` as a commit message" do
- wait_for_requests
-
- expect(page).to have_field("wiki[message]", with: "Create home")
- end
-
- it "creates a page from the home page" do
- page.within(".wiki-form") do
- fill_in(:wiki_content, with: "My awesome wiki!")
-
- click_button("Create page")
- end
-
- expect(page).to have_content("Home")
- .and have_content("Last edited by #{user.name}")
- .and have_content("My awesome wiki!")
- end
- end
- end
-
- context "when wiki is not empty", :js do
- before do
- create(:wiki_page, wiki: wiki, title: 'home', content: 'Home page')
-
- visit(project_wikis_path(project))
- end
-
- context "in a user namespace" do
- let(:project) { create(:project, :wiki_repo, namespace: user.namespace) }
-
- context "via the `new wiki page` page" do
- it "creates a page with a single word" do
- click_link("New page")
-
- page.within(".wiki-form") do
- fill_in(:wiki_title, with: "foo")
- fill_in(:wiki_content, with: "My awesome wiki!")
- end
-
- # Commit message field should have correct value.
- expect(page).to have_field("wiki[message]", with: "Create foo")
-
- click_button("Create page")
-
- expect(page).to have_content("foo")
- .and have_content("Last edited by #{user.name}")
- .and have_content("My awesome wiki!")
- end
-
- it "creates a page with spaces in the name" do
- click_link("New page")
-
- page.within(".wiki-form") do
- fill_in(:wiki_title, with: "Spaces in the name")
- fill_in(:wiki_content, with: "My awesome wiki!")
- end
-
- # Commit message field should have correct value.
- expect(page).to have_field("wiki[message]", with: "Create Spaces in the name")
-
- click_button("Create page")
-
- expect(page).to have_content("Spaces in the name")
- .and have_content("Last edited by #{user.name}")
- .and have_content("My awesome wiki!")
- end
-
- it "creates a page with hyphens in the name" do
- click_link("New page")
-
- page.within(".wiki-form") do
- fill_in(:wiki_title, with: "hyphens-in-the-name")
- fill_in(:wiki_content, with: "My awesome wiki!")
- end
-
- # Commit message field should have correct value.
- expect(page).to have_field("wiki[message]", with: "Create hyphens in the name")
-
- page.within(".wiki-form") do
- fill_in(:wiki_content, with: "My awesome wiki!")
-
- click_button("Create page")
- end
-
- expect(page).to have_content("hyphens in the name")
- .and have_content("Last edited by #{user.name}")
- .and have_content("My awesome wiki!")
- end
- end
-
- it "shows the emoji autocompletion dropdown" do
- click_link("New page")
-
- page.within(".wiki-form") do
- find("#wiki_content").native.send_keys("")
-
- fill_in(:wiki_content, with: ":")
- end
-
- expect(page).to have_selector(".atwho-view")
- end
- end
-
- context "in a group namespace" do
- let(:project) { create(:project, :wiki_repo, namespace: create(:group, :public)) }
-
- context "via the `new wiki page` page" do
- it "creates a page" do
- click_link("New page")
-
- page.within(".wiki-form") do
- fill_in(:wiki_title, with: "foo")
- fill_in(:wiki_content, with: "My awesome wiki!")
- end
-
- # Commit message field should have correct value.
- expect(page).to have_field("wiki[message]", with: "Create foo")
-
- click_button("Create page")
-
- expect(page).to have_content("foo")
- .and have_content("Last edited by #{user.name}")
- .and have_content("My awesome wiki!")
- end
- end
- end
- end
-
- describe 'sidebar feature' do
- context 'when there are some existing pages' do
- before do
- create(:wiki_page, wiki: wiki, title: 'home', content: 'home')
- create(:wiki_page, wiki: wiki, title: 'another', content: 'another')
- end
-
- it 'renders a default sidebar when there is no customized sidebar' do
- visit(project_wikis_path(project))
-
- expect(page).to have_content('another')
- expect(page).not_to have_link('View All Pages')
- end
-
- context 'when there is a customized sidebar' do
- before do
- create(:wiki_page, wiki: wiki, title: '_sidebar', content: 'My customized sidebar')
- end
-
- it 'renders my customized sidebar instead of the default one' do
- visit(project_wikis_path(project))
-
- expect(page).to have_content('My customized sidebar')
- expect(page).not_to have_content('Another')
- end
- end
- end
-
- context 'when there are 15 existing pages' do
- before do
- (1..5).each { |i| create(:wiki_page, wiki: wiki, title: "my page #{i}") }
- (6..10).each { |i| create(:wiki_page, wiki: wiki, title: "parent/my page #{i}") }
- (11..15).each { |i| create(:wiki_page, wiki: wiki, title: "grandparent/parent/my page #{i}") }
- end
-
- it 'shows all pages in the sidebar' do
- visit(project_wikis_path(project))
-
- (1..15).each { |i| expect(page).to have_content("my page #{i}") }
- expect(page).not_to have_link('View All Pages')
- end
-
- context 'when there are more than 15 existing pages' do
- before do
- create(:wiki_page, wiki: wiki, title: 'my page 16')
- end
-
- it 'shows the first 15 pages in the sidebar' do
- visit(project_wikis_path(project))
-
- expect(page).to have_text('my page', count: 15)
- expect(page).to have_link('View All Pages')
- end
- end
- end
- end
-end
diff --git a/spec/features/projects/wiki/user_deletes_wiki_page_spec.rb b/spec/features/projects/wiki/user_deletes_wiki_page_spec.rb
deleted file mode 100644
index a5d865d581b..00000000000
--- a/spec/features/projects/wiki/user_deletes_wiki_page_spec.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe 'User deletes wiki page', :js do
- let(:user) { create(:user) }
- let(:project) { create(:project, :wiki_repo, namespace: user.namespace) }
- let(:wiki_page) { create(:wiki_page, wiki: project.wiki) }
-
- before do
- sign_in(user)
- visit(project_wiki_path(project, wiki_page))
- end
-
- it 'deletes a page' do
- click_on('Edit')
- click_on('Delete')
- find('.modal-footer .btn-danger').click
-
- expect(page).to have_content('Page was successfully deleted')
- end
-end
diff --git a/spec/features/projects/wiki/user_updates_wiki_page_spec.rb b/spec/features/projects/wiki/user_updates_wiki_page_spec.rb
deleted file mode 100644
index fdab63a56b8..00000000000
--- a/spec/features/projects/wiki/user_updates_wiki_page_spec.rb
+++ /dev/null
@@ -1,263 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe 'User updates wiki page' do
- include WikiHelpers
-
- let(:user) { create(:user) }
-
- before do
- project.add_maintainer(user)
- sign_in(user)
- end
-
- context 'when wiki is empty' do
- before do |example|
- visit(project_wikis_path(project))
-
- wait_for_svg_to_be_loaded(example)
-
- click_link "Create your first page"
- end
-
- context 'in a user namespace' do
- let(:project) { create(:project, :wiki_repo) }
-
- it 'redirects back to the home edit page' do
- page.within(:css, '.wiki-form .form-actions') do
- click_on('Cancel')
- end
-
- expect(current_path).to eq wiki_path(project.wiki)
- end
-
- it 'updates a page that has a path', :js do
- fill_in(:wiki_title, with: 'one/two/three-test')
-
- page.within '.wiki-form' do
- fill_in(:wiki_content, with: 'wiki content')
- click_on('Create page')
- end
-
- expect(current_path).to include('one/two/three-test')
- expect(find('.wiki-pages')).to have_content('three')
-
- first(:link, text: 'three').click
-
- expect(find('.nav-text')).to have_content('three')
-
- click_on('Edit')
-
- expect(current_path).to include('one/two/three-test')
- expect(page).to have_content('Edit Page')
-
- fill_in('Content', with: 'Updated Wiki Content')
- click_on('Save changes')
-
- expect(page).to have_content('Updated Wiki Content')
- end
-
- it_behaves_like 'wiki file attachments'
- end
- end
-
- context 'when wiki is not empty' do
- let(:project_wiki) { create(:project_wiki, project: project, user: project.creator) }
- let!(:wiki_page) { create(:wiki_page, wiki: project_wiki, title: 'home', content: 'Home page') }
-
- before do
- visit(project_wikis_path(project))
-
- click_link('Edit')
- end
-
- context 'in a user namespace' do
- let(:project) { create(:project, :wiki_repo) }
-
- it 'updates a page', :js do
- # Commit message field should have correct value.
- expect(page).to have_field('wiki[message]', with: 'Update home')
-
- fill_in(:wiki_content, with: 'My awesome wiki!')
- click_button('Save changes')
-
- expect(page).to have_content('Home')
- expect(page).to have_content("Last edited by #{user.name}")
- expect(page).to have_content('My awesome wiki!')
- end
-
- it 'updates the commit message as the title is changed', :js do
- fill_in(:wiki_title, with: '& < > \ \ { } &')
-
- expect(page).to have_field('wiki[message]', with: 'Update & < > \ \ { } &')
- end
-
- it 'correctly escapes the commit message entities', :js do
- fill_in(:wiki_title, with: 'Wiki title')
-
- expect(page).to have_field('wiki[message]', with: 'Update Wiki title')
- end
-
- it 'shows a validation error message' do
- fill_in(:wiki_content, with: '')
- click_button('Save changes')
-
- expect(page).to have_selector('.wiki-form')
- expect(page).to have_content('Edit Page')
- expect(page).to have_content('The form contains the following error:')
- expect(page).to have_content("Content can't be blank")
- expect(find('textarea#wiki_content').value).to eq('')
- end
-
- it 'shows the emoji autocompletion dropdown', :js do
- find('#wiki_content').native.send_keys('')
- fill_in(:wiki_content, with: ':')
-
- expect(page).to have_selector('.atwho-view')
- end
-
- it 'shows the error message' do
- wiki_page.update(content: 'Update')
-
- click_button('Save changes')
-
- expect(page).to have_content('Someone edited the page the same time you did.')
- end
-
- it 'updates a page' do
- fill_in('Content', with: 'Updated Wiki Content')
- click_on('Save changes')
-
- expect(page).to have_content('Updated Wiki Content')
- end
-
- it 'cancels editing of a page' do
- page.within(:css, '.wiki-form .form-actions') do
- click_on('Cancel')
- end
-
- expect(current_path).to eq(project_wiki_path(project, wiki_page))
- end
-
- it_behaves_like 'wiki file attachments'
- end
-
- context 'in a group namespace' do
- let(:project) { create(:project, :wiki_repo, namespace: create(:group, :public)) }
-
- it 'updates a page', :js do
- # Commit message field should have correct value.
- expect(page).to have_field('wiki[message]', with: 'Update home')
-
- fill_in(:wiki_content, with: 'My awesome wiki!')
-
- click_button('Save changes')
-
- expect(page).to have_content('Home')
- expect(page).to have_content("Last edited by #{user.name}")
- expect(page).to have_content('My awesome wiki!')
- end
-
- it_behaves_like 'wiki file attachments'
- end
- end
-
- context 'when the page is in a subdir' do
- let!(:project) { create(:project, :wiki_repo) }
- let(:project_wiki) { create(:project_wiki, project: project, user: project.creator) }
- let(:page_name) { 'page_name' }
- let(:page_dir) { "foo/bar/#{page_name}" }
- let!(:wiki_page) { create(:wiki_page, wiki: project_wiki, title: page_dir, content: 'Home page') }
-
- before do
- visit(project_wiki_edit_path(project, wiki_page))
- end
-
- it 'moves the page to the root folder' do
- fill_in(:wiki_title, with: "/#{page_name}")
-
- click_button('Save changes')
-
- expect(current_path).to eq(project_wiki_path(project, page_name))
- end
-
- it 'moves the page to other dir' do
- new_page_dir = "foo1/bar1/#{page_name}"
-
- fill_in(:wiki_title, with: new_page_dir)
-
- click_button('Save changes')
-
- expect(current_path).to eq(project_wiki_path(project, new_page_dir))
- end
-
- it 'remains in the same place if title has not changed' do
- original_path = project_wiki_path(project, wiki_page)
-
- fill_in(:wiki_title, with: page_name)
-
- click_button('Save changes')
-
- expect(current_path).to eq(original_path)
- end
-
- it 'can be moved to a different dir with a different name' do
- new_page_dir = "foo1/bar1/new_page_name"
-
- fill_in(:wiki_title, with: new_page_dir)
-
- click_button('Save changes')
-
- expect(current_path).to eq(project_wiki_path(project, new_page_dir))
- end
-
- it 'can be renamed and moved to the root folder' do
- new_name = 'new_page_name'
-
- fill_in(:wiki_title, with: "/#{new_name}")
-
- click_button('Save changes')
-
- expect(current_path).to eq(project_wiki_path(project, new_name))
- end
-
- it 'squishes the title before creating the page' do
- new_page_dir = " foo1 / bar1 / #{page_name} "
-
- fill_in(:wiki_title, with: new_page_dir)
-
- click_button('Save changes')
-
- expect(current_path).to eq(project_wiki_path(project, "foo1/bar1/#{page_name}"))
- end
-
- it_behaves_like 'wiki file attachments'
- end
-
- context 'when an existing page exceeds the content size limit' do
- let_it_be(:project) { create(:project, :wiki_repo) }
- let!(:wiki_page) { create(:wiki_page, wiki: project.wiki, content: "one\ntwo\nthree") }
-
- before do
- stub_application_setting(wiki_page_max_content_bytes: 10)
-
- visit wiki_page_path(wiki_page.wiki, wiki_page, action: :edit)
- end
-
- it 'allows changing the title if the content does not change' do
- fill_in 'Title', with: 'new title'
- click_on 'Save changes'
-
- expect(page).to have_content('Wiki was successfully updated.')
- end
-
- it 'shows a validation error when trying to change the content' do
- fill_in 'Content', with: 'new content'
- click_on 'Save changes'
-
- expect(page).to have_content('The form contains the following error:')
- expect(page).to have_content('Content is too long (11 Bytes). The maximum size is 10 Bytes.')
- end
- end
-end
diff --git a/spec/features/projects/wiki/user_views_wiki_empty_spec.rb b/spec/features/projects/wiki/user_views_wiki_empty_spec.rb
index 0af40a2d760..1f460f39267 100644
--- a/spec/features/projects/wiki/user_views_wiki_empty_spec.rb
+++ b/spec/features/projects/wiki/user_views_wiki_empty_spec.rb
@@ -2,108 +2,86 @@
require 'spec_helper'
-RSpec.describe 'User views empty wiki' do
- let(:user) { create(:user) }
- let(:confluence_link) { 'Enable the Confluence Wiki integration' }
- let(:element) { page.find('.row.empty-state') }
-
- shared_examples 'empty wiki and accessible issues' do
- it 'show "issue tracker" message' do
- visit(project_wikis_path(project))
-
- expect(element).to have_content('This project has no wiki pages')
- expect(element).to have_content('You must be a project member')
- expect(element).to have_content('improve the wiki for this project')
- expect(element).to have_link("issue tracker", href: project_issues_path(project))
- expect(element).to have_link("Suggest wiki improvement", href: new_project_issue_path(project))
- expect(element).to have_no_link(confluence_link)
- end
- end
-
- shared_examples 'empty wiki and non-accessible issues' do
- it 'does not show "issue tracker" message' do
- visit(project_wikis_path(project))
+RSpec.describe 'Project > User views empty wiki' do
+ let_it_be(:user) { create(:user) }
- expect(element).to have_content('This project has no wiki pages')
- expect(element).to have_content('You must be a project member')
- expect(element).to have_no_link('Suggest wiki improvement')
- expect(element).to have_no_link(confluence_link)
- end
- end
+ let(:wiki) { create(:project_wiki, project: project) }
- context 'when user is logged out and issue tracker is public' do
- let(:project) { create(:project, :public, :wiki_repo) }
+ it_behaves_like 'User views empty wiki' do
+ context 'when project is public' do
+ let(:project) { create(:project, :public) }
- it_behaves_like 'empty wiki and accessible issues'
- end
+ it_behaves_like 'empty wiki message', issuable: true
- context 'when user is logged in and not a member' do
- let(:project) { create(:project, :public, :wiki_repo) }
+ context 'when issue tracker is private' do
+ let(:project) { create(:project, :public, :issues_private) }
- before do
- sign_in(user)
- end
+ it_behaves_like 'empty wiki message', issuable: false
+ end
- it_behaves_like 'empty wiki and accessible issues'
- end
+ context 'when issue tracker is disabled' do
+ let(:project) { create(:project, :public, :issues_disabled) }
- context 'when issue tracker is private' do
- let(:project) { create(:project, :public, :wiki_repo, :issues_private) }
+ it_behaves_like 'empty wiki message', issuable: false
+ end
- it_behaves_like 'empty wiki and non-accessible issues'
- end
+ context 'and user is logged in' do
+ before do
+ sign_in(user)
+ end
- context 'when issue tracker is disabled' do
- let(:project) { create(:project, :public, :wiki_repo, :issues_disabled) }
+ context 'and user is not a member' do
+ it_behaves_like 'empty wiki message', issuable: true
+ end
- it_behaves_like 'empty wiki and non-accessible issues'
- end
+ context 'and user is a member' do
+ before do
+ project.add_developer(user)
+ end
- context 'when user is logged in and a member' do
- let(:project) { create(:project, :public) }
-
- before do
- sign_in(user)
- project.add_developer(user)
+ it_behaves_like 'empty wiki message', writable: true, issuable: true
+ end
+ end
end
- it 'shows "create first page" message' do
- visit(project_wikis_path(project))
-
- expect(element).to have_content('your project', count: 2)
+ context 'when project is private' do
+ let(:project) { create(:project, :private) }
- element.click_link 'Create your first page'
+ it_behaves_like 'wiki is not found'
- expect(page).to have_button('Create page')
- end
+ context 'and user is logged in' do
+ before do
+ sign_in(user)
+ end
- it 'does not show the "enable confluence" button' do
- visit(project_wikis_path(project))
+ context 'and user is not a member' do
+ it_behaves_like 'wiki is not found'
+ end
- expect(element).to have_no_link(confluence_link)
- end
- end
+ context 'and user is a member' do
+ before do
+ project.add_developer(user)
+ end
- context 'when user is logged in and an admin' do
- let(:project) { create(:project, :public, :wiki_repo) }
+ it_behaves_like 'empty wiki message', writable: true, issuable: true
+ end
- before do
- sign_in(user)
- project.add_maintainer(user)
- end
-
- it 'shows the "enable confluence" button' do
- visit(project_wikis_path(project))
-
- expect(element).to have_link(confluence_link)
- end
+ context 'and user is a maintainer' do
+ before do
+ project.add_maintainer(user)
+ end
- it 'does not show "enable confluence" button if confluence is already enabled' do
- create(:confluence_service, project: project)
+ it_behaves_like 'empty wiki message', writable: true, issuable: true, confluence: true
- visit(project_wikis_path(project))
+ context 'and Confluence is already enabled' do
+ before do
+ create(:confluence_service, project: project)
+ end
- expect(element).to have_no_link(confluence_link)
+ it_behaves_like 'empty wiki message', writable: true, issuable: true, confluence: false
+ end
+ end
+ end
end
end
end
diff --git a/spec/features/projects/wiki/user_views_wiki_page_spec.rb b/spec/features/projects/wiki/user_views_wiki_page_spec.rb
deleted file mode 100644
index e93689af0aa..00000000000
--- a/spec/features/projects/wiki/user_views_wiki_page_spec.rb
+++ /dev/null
@@ -1,276 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe 'User views a wiki page' do
- include WikiHelpers
-
- let(:user) { create(:user) }
- let(:project) { create(:project, :wiki_repo, namespace: user.namespace) }
- let(:path) { 'image.png' }
- let(:wiki) { project.wiki }
- let(:wiki_page) do
- create(:wiki_page,
- wiki: wiki,
- title: 'home', content: "Look at this [image](#{path})\n\n ![alt text](#{path})")
- end
-
- before do
- project.add_maintainer(user)
- sign_in(user)
- end
-
- context 'when wiki is empty', :js do
- before do
- visit project_wikis_path(project)
-
- wait_for_svg_to_be_loaded
-
- click_link "Create your first page"
-
- fill_in(:wiki_title, with: 'one/two/three-test')
-
- page.within('.wiki-form') do
- fill_in(:wiki_content, with: 'wiki content')
- click_on('Create page')
- end
-
- expect(page).to have_content('Wiki was successfully updated.')
- end
-
- it 'shows the history of a page that has a path' do
- expect(current_path).to include('one/two/three-test')
-
- first(:link, text: 'three').click
- click_on('Page history')
-
- expect(current_path).to include('one/two/three-test')
-
- page.within(:css, '.nav-text') do
- expect(page).to have_content('History')
- end
- end
-
- it 'shows an old version of a page' do
- expect(current_path).to include('one/two/three-test')
- expect(find('.wiki-pages')).to have_content('three')
-
- first(:link, text: 'three').click
-
- expect(find('.nav-text')).to have_content('three')
-
- click_on('Edit')
-
- expect(current_path).to include('one/two/three-test')
- expect(page).to have_content('Edit Page')
-
- fill_in('Content', with: 'Updated Wiki Content')
- click_on('Save changes')
-
- expect(page).to have_content('Wiki was successfully updated.')
-
- click_on('Page history')
-
- within('.nav-text') do
- expect(page).to have_content('History')
- end
-
- within('.wiki-history') do
- expect(page).to have_css('a[href*="?version_id"]', count: 4)
- end
- end
- end
-
- context 'when a page does not have history' do
- before do
- visit(project_wiki_path(project, wiki_page))
- end
-
- it 'shows all the pages' do
- expect(page).to have_content(user.name)
- expect(find('.wiki-pages')).to have_content(wiki_page.title.capitalize)
- end
-
- context 'shows a file stored in a page' do
- let(:path) { upload_file_to_wiki(project, user, 'dk.png') }
-
- it do
- expect(page).to have_xpath("//img[@data-src='#{wiki.wiki_base_path}/#{path}']")
- expect(page).to have_link('image', href: "#{wiki.wiki_base_path}/#{path}")
-
- click_on('image')
-
- expect(current_path).to match("wikis/#{path}")
- expect(page).not_to have_xpath('/html') # Page should render the image which means there is no html involved
- end
- end
-
- it 'shows the creation page if file does not exist' do
- expect(page).to have_link('image', href: "#{wiki.wiki_base_path}/#{path}")
-
- click_on('image')
-
- expect(current_path).to match("wikis/#{path}")
- expect(page).to have_content('Create New Page')
- end
- end
-
- context 'when a page has history' do
- before do
- wiki_page.update(message: 'updated home', content: 'updated [some link](other-page)') # rubocop:disable Rails/SaveBang
- end
-
- it 'shows the page history' do
- visit(project_wiki_path(project, wiki_page))
-
- expect(page).to have_selector('a.btn', text: 'Edit')
-
- click_on('Page history')
-
- expect(page).to have_content(user.name)
- expect(page).to have_content("#{user.username} created page: home")
- expect(page).to have_content('updated home')
- end
-
- it 'does not show the "Edit" button' do
- visit(project_wiki_path(project, wiki_page, version_id: wiki_page.versions.last.id))
-
- expect(page).not_to have_selector('a.btn', text: 'Edit')
- end
-
- context 'show the diff' do
- def expect_diff_links(commit)
- diff_path = wiki_page_path(wiki, wiki_page, version_id: commit, action: :diff)
-
- expect(page).to have_link('Hide whitespace changes', href: "#{diff_path}&w=1")
- expect(page).to have_link('Inline', href: "#{diff_path}&view=inline")
- expect(page).to have_link('Side-by-side', href: "#{diff_path}&view=parallel")
- expect(page).to have_link("View page @ #{commit.short_id}", href: wiki_page_path(wiki, wiki_page, version_id: commit))
- expect(page).to have_css('.diff-file[data-blob-diff-path="%s"]' % diff_path)
- end
-
- it 'links to the correct diffs' do
- visit project_wiki_history_path(project, wiki_page)
-
- commit1 = wiki.commit('HEAD^')
- commit2 = wiki.commit
-
- expect(page).to have_link('created page: home', href: wiki_page_path(wiki, wiki_page, version_id: commit1, action: :diff))
- expect(page).to have_link('updated home', href: wiki_page_path(wiki, wiki_page, version_id: commit2, action: :diff))
- end
-
- it 'between the current and the previous version of a page' do
- commit = wiki.commit
- visit wiki_page_path(wiki, wiki_page, version_id: commit, action: :diff)
-
- expect(page).to have_content('by John Doe')
- expect(page).to have_content('updated home')
- expect(page).to have_content('Showing 1 changed file with 1 addition and 3 deletions')
- expect(page).to have_content('some link')
-
- expect_diff_links(commit)
- end
-
- it 'between two old versions of a page' do
- wiki_page.update(message: 'latest home change', content: 'updated [another link](other-page)') # rubocop:disable Rails/SaveBang:
- commit = wiki.commit('HEAD^')
- visit wiki_page_path(wiki, wiki_page, version_id: commit, action: :diff)
-
- expect(page).to have_content('by John Doe')
- expect(page).to have_content('updated home')
- expect(page).to have_content('Showing 1 changed file with 1 addition and 3 deletions')
- expect(page).to have_content('some link')
- expect(page).not_to have_content('latest home change')
- expect(page).not_to have_content('another link')
-
- expect_diff_links(commit)
- end
-
- it 'for the oldest version of a page' do
- commit = wiki.commit('HEAD^')
- visit wiki_page_path(wiki, wiki_page, version_id: commit, action: :diff)
-
- expect(page).to have_content('by John Doe')
- expect(page).to have_content('created page: home')
- expect(page).to have_content('Showing 1 changed file with 4 additions and 0 deletions')
- expect(page).to have_content('Look at this')
-
- expect_diff_links(commit)
- end
- end
- end
-
- context 'when a page has special characters in its title' do
- let(:title) { '<foo> !@#$%^&*()[]{}=_+\'"\\|<>? <bar>' }
-
- before do
- wiki_page.update(title: title ) # rubocop:disable Rails/SaveBang
- end
-
- it 'preserves the special characters' do
- visit(project_wiki_path(project, wiki_page))
-
- expect(page).to have_css('.wiki-page-title', text: title)
- expect(page).to have_css('.wiki-pages li', text: title)
- end
- end
-
- context 'when a page has XSS in its title or content' do
- let(:title) { '<script>alert("title")<script>' }
-
- before do
- wiki_page.update(title: title, content: 'foo <script>alert("content")</script> bar') # rubocop:disable Rails/SaveBang
- end
-
- it 'safely displays the page' do
- visit(project_wiki_path(project, wiki_page))
-
- expect(page).to have_css('.wiki-page-title', text: title)
- expect(page).to have_content('foo bar')
- end
- end
-
- context 'when a page has XSS in its message' do
- before do
- wiki_page.update(message: '<script>alert(true)<script>', content: 'XSS update') # rubocop:disable Rails/SaveBang
- end
-
- it 'safely displays the message' do
- visit(project_wiki_history_path(project, wiki_page))
-
- expect(page).to have_content('<script>alert(true)<script>')
- end
- end
-
- context 'when page has invalid content encoding' do
- let(:content) { (+'whatever').force_encoding('ISO-8859-1') }
-
- before do
- allow(Gitlab::EncodingHelper).to receive(:encode!).and_return(content)
-
- visit(project_wiki_path(project, wiki_page))
- end
-
- it 'does not show "Edit" button' do
- expect(page).not_to have_selector('a.btn', text: 'Edit')
- end
-
- it 'shows error' do
- page.within(:css, '.flash-notice') do
- expect(page).to have_content('The content of this page is not encoded in UTF-8. Edits can only be made via the Git repository.')
- end
- end
- end
-
- it 'opens a default wiki page', :js do
- visit project_path(project)
-
- find('.shortcuts-wiki').click
-
- wait_for_svg_to_be_loaded
-
- click_link "Create your first page"
-
- expect(page).to have_content('Create New Page')
- end
-end
diff --git a/spec/features/projects/wiki/user_views_wiki_pages_spec.rb b/spec/features/projects/wiki/user_views_wiki_pages_spec.rb
deleted file mode 100644
index 4f29ae0cc8a..00000000000
--- a/spec/features/projects/wiki/user_views_wiki_pages_spec.rb
+++ /dev/null
@@ -1,91 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe 'User views wiki pages' do
- include WikiHelpers
-
- let(:user) { create(:user) }
- let(:project) { create(:project, :wiki_repo, namespace: user.namespace) }
-
- let!(:wiki_page1) do
- create(:wiki_page, wiki: project.wiki, title: '3 home', content: '3')
- end
-
- let!(:wiki_page2) do
- create(:wiki_page, wiki: project.wiki, title: '1 home', content: '1')
- end
-
- let!(:wiki_page3) do
- create(:wiki_page, wiki: project.wiki, title: '2 home', content: '2')
- end
-
- let(:pages) do
- page.find('.wiki-pages-list').all('li').map { |li| li.find('a') }
- end
-
- before do
- project.add_maintainer(user)
- sign_in(user)
- visit(project_wikis_pages_path(project))
- end
-
- context 'ordered by title' do
- let(:pages_ordered_by_title) { [wiki_page2, wiki_page3, wiki_page1] }
-
- context 'asc' do
- it 'pages are displayed in direct order' do
- pages.each.with_index do |page_title, index|
- expect(page_title.text).to eq(pages_ordered_by_title[index].title)
- end
- end
- end
-
- context 'desc' do
- before do
- page.within('.wiki-sort-dropdown') do
- page.find('.rspec-reverse-sort').click
- end
- end
-
- it 'pages are displayed in reversed order' do
- pages.reverse_each.with_index do |page_title, index|
- expect(page_title.text).to eq(pages_ordered_by_title[index].title)
- end
- end
- end
- end
-
- context 'ordered by created_at' do
- let(:pages_ordered_by_created_at) { [wiki_page1, wiki_page2, wiki_page3] }
-
- before do
- page.within('.wiki-sort-dropdown') do
- click_button('Title')
- click_link('Created date')
- end
- end
-
- context 'asc' do
- it 'pages are displayed in direct order' do
- pages.each.with_index do |page_title, index|
- expect(page_title.text).to eq(pages_ordered_by_created_at[index].title)
- end
- end
- end
-
- context 'desc' do
- before do
- page.within('.wiki-sort-dropdown') do
- page.find('.rspec-reverse-sort').click
- end
- end
-
- it 'pages are displayed in reversed order' do
- pages.reverse_each.with_index do |page_title, index|
- expect(page_title.text).to eq(pages_ordered_by_created_at[index].title)
- end
- end
- end
- end
-end
diff --git a/spec/features/projects/wiki/users_views_asciidoc_page_with_includes_spec.rb b/spec/features/projects/wiki/users_views_asciidoc_page_with_includes_spec.rb
deleted file mode 100644
index 5c45e34595f..00000000000
--- a/spec/features/projects/wiki/users_views_asciidoc_page_with_includes_spec.rb
+++ /dev/null
@@ -1,79 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe 'User views AsciiDoc page with includes', :js do
- let_it_be(:user) { create(:user) }
- let_it_be(:wiki_content_selector) { '[data-qa-selector=wiki_page_content]' }
- let(:project) { create(:project, :public, :wiki_repo) }
- let!(:included_wiki_page) { create_wiki_page('included_page', content: 'Content from the included page')}
- let!(:wiki_page) { create_wiki_page('home', content: "Content from the main page.\ninclude::included_page.asciidoc[]") }
-
- def create_wiki_page(title, content:)
- attrs = {
- title: title,
- content: content,
- format: :asciidoc
- }
-
- create(:wiki_page, wiki: project.wiki, **attrs)
- end
-
- before do
- sign_in(user)
- end
-
- context 'when the file being included exists' do
- it 'includes the file contents' do
- visit(project_wiki_path(project, wiki_page))
-
- page.within(:css, wiki_content_selector) do
- expect(page).to have_content('Content from the main page. Content from the included page')
- end
- end
-
- context 'when there are multiple versions of the wiki pages' do
- before do
- included_wiki_page.update(message: 'updated included file', content: 'Updated content from the included page')
- wiki_page.update(message: 'updated wiki page', content: "Updated content from the main page.\ninclude::included_page.asciidoc[]")
- end
-
- let(:latest_version_id) { wiki_page.versions.first.id }
- let(:oldest_version_id) { wiki_page.versions.last.id }
-
- context 'viewing the latest version' do
- it 'includes the latest content' do
- visit(project_wiki_path(project, wiki_page, version_id: latest_version_id))
-
- page.within(:css, wiki_content_selector) do
- expect(page).to have_content('Updated content from the main page. Updated content from the included page')
- end
- end
- end
-
- context 'viewing the original version' do
- it 'includes the content from the original version' do
- visit(project_wiki_path(project, wiki_page, version_id: oldest_version_id))
-
- page.within(:css, wiki_content_selector) do
- expect(page).to have_content('Content from the main page. Content from the included page')
- end
- end
- end
- end
- end
-
- context 'when the file being included does not exist' do
- before do
- included_wiki_page.delete
- end
-
- it 'outputs an error' do
- visit(project_wiki_path(project, wiki_page))
-
- page.within(:css, wiki_content_selector) do
- expect(page).to have_content('Content from the main page. [ERROR: include::included_page.asciidoc[] - unresolved directive]')
- end
- end
- end
-end
diff --git a/spec/features/projects/wikis_spec.rb b/spec/features/projects/wikis_spec.rb
new file mode 100644
index 00000000000..1c66ad81145
--- /dev/null
+++ b/spec/features/projects/wikis_spec.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+require "spec_helper"
+
+RSpec.describe 'Project wikis' do
+ let_it_be(:user) { create(:user) }
+
+ let(:wiki) { create(:project_wiki, user: user, project: project) }
+ let(:project) { create(:project, namespace: user.namespace, creator: user) }
+
+ it_behaves_like 'User creates wiki page'
+ it_behaves_like 'User deletes wiki page'
+ it_behaves_like 'User previews wiki changes'
+ it_behaves_like 'User updates wiki page'
+ it_behaves_like 'User uses wiki shortcuts'
+ it_behaves_like 'User views AsciiDoc page with includes'
+ it_behaves_like 'User views a wiki page'
+ it_behaves_like 'User views wiki pages'
+ it_behaves_like 'User views wiki sidebar'
+end
diff --git a/spec/features/projects_spec.rb b/spec/features/projects_spec.rb
index 970500985ae..6baeb4ce368 100644
--- a/spec/features/projects_spec.rb
+++ b/spec/features/projects_spec.rb
@@ -6,25 +6,35 @@ RSpec.describe 'Project' do
include ProjectForksHelper
include MobileHelpers
- describe 'creating from template' do
+ describe 'template' do
let(:user) { create(:user) }
- let(:template) { Gitlab::ProjectTemplate.find(:rails) }
before do
sign_in user
visit new_project_path
end
- it "allows creation from templates", :js do
- find('#create-from-template-tab').click
- find("label[for=#{template.name}]").click
- fill_in("project_name", with: template.name)
+ shared_examples 'creates from template' do |template, sub_template_tab = nil|
+ it "is created from template", :js do
+ find('#create-from-template-tab').click
+ find(".project-template #{sub_template_tab}").click if sub_template_tab
+ find("label[for=#{template.name}]").click
+ fill_in("project_name", with: template.name)
- page.within '#content-body' do
- click_button "Create project"
+ page.within '#content-body' do
+ click_button "Create project"
+ end
+
+ expect(page).to have_content template.name
end
+ end
- expect(page).to have_content template.name
+ context 'create with project template' do
+ it_behaves_like 'creates from template', Gitlab::ProjectTemplate.find(:rails)
+ end
+
+ context 'create with sample data template' do
+ it_behaves_like 'creates from template', Gitlab::SampleDataTemplate.find(:basic), '.sample-data-templates-tab'
end
end
@@ -99,6 +109,15 @@ RSpec.describe 'Project' do
expect(page).to have_css('.home-panel-description .is-expanded')
end
end
+
+ context 'page description' do
+ before do
+ project.update_attribute(:description, '**Lorem** _ipsum_ dolor sit [amet](https://example.com)')
+ visit path
+ end
+
+ it_behaves_like 'page meta description', 'Lorem ipsum dolor sit amet'
+ end
end
describe 'project topics' do
diff --git a/spec/features/protected_branches_spec.rb b/spec/features/protected_branches_spec.rb
index f0707610c3f..3be01595502 100644
--- a/spec/features/protected_branches_spec.rb
+++ b/spec/features/protected_branches_spec.rb
@@ -9,6 +9,10 @@ RSpec.describe 'Protected Branches', :js do
let(:admin) { create(:admin) }
let(:project) { create(:project, :repository) }
+ before do
+ stub_feature_flags(deploy_keys_on_protected_branches: false)
+ end
+
context 'logged in as developer' do
before do
project.add_developer(user)
@@ -27,7 +31,7 @@ RSpec.describe 'Protected Branches', :js do
fill_in 'branch-search', with: 'fix'
find('#branch-search').native.send_keys(:enter)
- expect(page).to have_css('.btn-remove.disabled')
+ expect(page).to have_css('.btn-danger.disabled')
end
end
end
@@ -163,4 +167,14 @@ RSpec.describe 'Protected Branches', :js do
include_examples "protected branches > access control > CE"
end
end
+
+ context 'when the users for protected branches feature is off' do
+ before do
+ stub_licensed_features(protected_refs_for_users: false)
+ end
+
+ include_examples 'when the deploy_keys_on_protected_branches FF is turned on' do
+ let(:all_dropdown_sections) { %w(Roles Deploy\ Keys) }
+ end
+ end
end
diff --git a/spec/features/reportable_note/snippets_spec.rb b/spec/features/reportable_note/snippets_spec.rb
index 4d61e5d8285..92bf304ac86 100644
--- a/spec/features/reportable_note/snippets_spec.rb
+++ b/spec/features/reportable_note/snippets_spec.rb
@@ -7,7 +7,6 @@ RSpec.describe 'Reportable note on snippets', :js do
let_it_be(:project) { create(:project) }
before do
- stub_feature_flags(snippets_vue: false)
project.add_maintainer(user)
sign_in(user)
end
diff --git a/spec/features/runners_spec.rb b/spec/features/runners_spec.rb
index 0dff4c28270..6e18de3be7b 100644
--- a/spec/features/runners_spec.rb
+++ b/spec/features/runners_spec.rb
@@ -173,9 +173,9 @@ RSpec.describe 'Runners' do
it 'user enables shared runners' do
visit project_runners_path(project)
- click_on 'Enable shared Runners'
+ click_on 'Enable shared runners'
- expect(page.find('.shared-runners-description')).to have_content('Disable shared Runners')
+ expect(page.find('.shared-runners-description')).to have_content('Disable shared runners')
end
end
diff --git a/spec/features/search/user_searches_for_code_spec.rb b/spec/features/search/user_searches_for_code_spec.rb
index 227e75088d2..a88043c98ac 100644
--- a/spec/features/search/user_searches_for_code_spec.rb
+++ b/spec/features/search/user_searches_for_code_spec.rb
@@ -21,6 +21,7 @@ RSpec.describe 'User searches for code' do
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: /master\/files\/js\/application.js/)
end
context 'when on a project page', :js do
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 cfda25b9ab4..5cbfacf4e48 100644
--- a/spec/features/search/user_uses_header_search_field_spec.rb
+++ b/spec/features/search/user_uses_header_search_field_spec.rb
@@ -30,6 +30,8 @@ RSpec.describe 'User uses header search field', :js do
before do
find('#search')
find('body').native.send_keys('s')
+
+ wait_for_all_requests
end
it 'shows the category search dropdown' do
@@ -89,9 +91,7 @@ RSpec.describe 'User uses header search field', :js do
context 'when entering text into the search field' do
it 'does not display the category search dropdown' do
- page.within('.search-input-wrap') do
- fill_in('search', with: scope_name.first(4))
- end
+ fill_in_search(scope_name.first(4))
expect(page).not_to have_selector('.dropdown-header', text: /#{scope_name}/i)
end
@@ -105,9 +105,7 @@ RSpec.describe 'User uses header search field', :js do
end
it 'displays search options' do
- page.within('.search-input-wrap') do
- fill_in('search', with: 'test')
- end
+ fill_in_search('test')
expect(page).to have_selector(scoped_search_link('test'))
end
@@ -140,9 +138,7 @@ RSpec.describe 'User uses header search field', :js do
end
it 'displays search options' do
- page.within('.search-input-wrap') do
- fill_in('search', with: 'test')
- end
+ fill_in_search('test')
expect(page).to have_selector(scoped_search_link('test'))
expect(page).to have_selector(scoped_search_link('test', group_id: group.id))
@@ -157,9 +153,7 @@ RSpec.describe 'User uses header search field', :js do
end
it 'displays search options' do
- page.within('.search-input-wrap') do
- fill_in('search', with: 'test')
- end
+ fill_in_search('test')
expect(page).to have_selector(scoped_search_link('test'))
expect(page).not_to have_selector(scoped_search_link('test', group_id: project.namespace_id))
@@ -182,9 +176,7 @@ RSpec.describe 'User uses header search field', :js do
end
it 'displays search options' do
- page.within('.search-input-wrap') do
- fill_in('search', with: 'test')
- end
+ fill_in_search('test')
expect(page).to have_selector(scoped_search_link('test'))
expect(page).to have_selector(scoped_search_link('test', group_id: group.id))
@@ -208,9 +200,7 @@ RSpec.describe 'User uses header search field', :js do
end
it 'displays search options' do
- page.within('.search-input-wrap') do
- fill_in('search', with: 'test')
- end
+ fill_in_search('test')
expect(page).to have_selector(scoped_search_link('test'))
expect(page).to have_selector(scoped_search_link('test', group_id: subgroup.id))
diff --git a/spec/features/search/user_uses_search_filters_spec.rb b/spec/features/search/user_uses_search_filters_spec.rb
index f39a1f8fe37..080cced21c3 100644
--- a/spec/features/search/user_uses_search_filters_spec.rb
+++ b/spec/features/search/user_uses_search_filters_spec.rb
@@ -12,12 +12,12 @@ RSpec.describe 'User uses search filters', :js do
project.add_reporter(user)
group.add_owner(user)
sign_in(user)
-
- visit(search_path)
end
context 'when filtering by group' do
it 'shows group projects' do
+ visit search_path
+
find('.js-search-group-dropdown').click
wait_for_requests
@@ -36,10 +36,27 @@ RSpec.describe 'User uses search filters', :js do
expect(page).to have_link(group_project.full_name)
end
end
+
+ context 'when the group filter is set' do
+ before do
+ visit search_path(search: "test", group_id: group.id, project_id: project.id)
+ end
+
+ describe 'clear filter button' do
+ it 'removes Group and Project filters' do
+ link = find('[data-testid="group-filter"] .js-search-clear')
+ params = CGI.parse(URI.parse(link[:href]).query)
+
+ expect(params).not_to include(:group_id, :project_id)
+ end
+ end
+ end
end
context 'when filtering by project' do
it 'shows a project' do
+ visit search_path
+
page.within('.project-filter') do
find('.js-search-project-dropdown').click
@@ -50,5 +67,22 @@ RSpec.describe 'User uses search filters', :js do
expect(find('.js-search-project-dropdown')).to have_content(project.full_name)
end
+
+ context 'when the project filter is set' do
+ before do
+ visit search_path(search: "test", project_id: project.id)
+ end
+
+ let(:query) { { project_id: project.id } }
+
+ describe 'clear filter button' do
+ it 'removes Project filters' do
+ link = find('.project-filter .js-search-clear')
+ params = CGI.parse(URI.parse(link[:href]).query)
+
+ expect(params).not_to include(:project_id)
+ end
+ end
+ end
end
end
diff --git a/spec/features/sentry_js_spec.rb b/spec/features/sentry_js_spec.rb
index 1d277ba7b3c..aa0ad17340a 100644
--- a/spec/features/sentry_js_spec.rb
+++ b/spec/features/sentry_js_spec.rb
@@ -12,7 +12,7 @@ RSpec.describe 'Sentry' do
expect(has_requested_sentry).to eq(false)
end
- it 'loads sentry if sentry is enabled' do
+ xit 'loads sentry if sentry is enabled' do
stub_sentry_settings
visit new_user_session_path
diff --git a/spec/features/snippets/internal_snippet_spec.rb b/spec/features/snippets/internal_snippet_spec.rb
index 3ce297ab22d..2fcd11c2a47 100644
--- a/spec/features/snippets/internal_snippet_spec.rb
+++ b/spec/features/snippets/internal_snippet_spec.rb
@@ -3,11 +3,8 @@
require 'spec_helper'
RSpec.describe 'Internal Snippets', :js do
- let(:internal_snippet) { create(:personal_snippet, :internal) }
-
- before do
- stub_feature_flags(snippets_vue: false)
- end
+ let(:internal_snippet) { create(:personal_snippet, :internal, :repository) }
+ let(:content) { internal_snippet.blobs.first.data.strip! }
describe 'normal user' do
before do
@@ -17,13 +14,13 @@ RSpec.describe 'Internal Snippets', :js do
it 'sees internal snippets' do
visit snippet_path(internal_snippet)
- expect(page).to have_content(internal_snippet.content)
+ expect(page).to have_content(content)
end
it 'sees raw internal snippets' do
visit raw_snippet_path(internal_snippet)
- expect(page).to have_content(internal_snippet.content)
+ expect(page).to have_content(content)
end
end
end
diff --git a/spec/features/snippets/notes_on_personal_snippets_spec.rb b/spec/features/snippets/notes_on_personal_snippets_spec.rb
index e98bb22d3ea..ce9a2d1461e 100644
--- a/spec/features/snippets/notes_on_personal_snippets_spec.rb
+++ b/spec/features/snippets/notes_on_personal_snippets_spec.rb
@@ -18,7 +18,6 @@ RSpec.describe 'Comments on personal snippets', :js do
end
before do
- stub_feature_flags(snippets_vue: false)
sign_in user
visit snippet_path(snippet)
diff --git a/spec/features/snippets/private_snippets_spec.rb b/spec/features/snippets/private_snippets_spec.rb
index 6b45f3485e7..03745c1025a 100644
--- a/spec/features/snippets/private_snippets_spec.rb
+++ b/spec/features/snippets/private_snippets_spec.rb
@@ -4,19 +4,18 @@ require 'spec_helper'
RSpec.describe 'Private Snippets', :js do
let(:user) { create(:user) }
+ let(:private_snippet) { create(:personal_snippet, :repository, :private, author: user) }
+ let(:content) { private_snippet.blobs.first.data.strip! }
before do
- stub_feature_flags(snippets_vue: false)
sign_in(user)
end
it 'Private Snippet renders for creator' do
- private_snippet = create(:personal_snippet, :private, author: user)
-
visit snippet_path(private_snippet)
wait_for_requests
- expect(page).to have_content(private_snippet.content)
+ expect(page).to have_content(content)
expect(page).not_to have_css('.js-embed-btn')
expect(page).not_to have_css('.js-share-btn')
end
diff --git a/spec/features/snippets/public_snippets_spec.rb b/spec/features/snippets/public_snippets_spec.rb
index 4b72b33245d..d2dc85a9614 100644
--- a/spec/features/snippets/public_snippets_spec.rb
+++ b/spec/features/snippets/public_snippets_spec.rb
@@ -3,27 +3,24 @@
require 'spec_helper'
RSpec.describe 'Public Snippets', :js do
- before do
- stub_feature_flags(snippets_vue: false)
- end
+ let(:public_snippet) { create(:personal_snippet, :public, :repository) }
+ let(:content) { public_snippet.blobs.first.data.strip! }
it 'Unauthenticated user should see public snippets' do
- public_snippet = create(:personal_snippet, :public)
+ url = Gitlab::UrlBuilder.build(public_snippet)
visit snippet_path(public_snippet)
wait_for_requests
- expect(page).to have_content(public_snippet.content)
- expect(page).to have_css('.js-embed-btn', visible: false)
- expect(page).to have_css('.js-share-btn', visible: false)
- expect(page.find('.js-snippet-url-area')).to be_readonly
+ expect(page).to have_content(content)
+ click_button('Embed')
+ expect(page).to have_field('Embed', readonly: true, with: "<script src=\"#{url}.js\"></script>")
+ expect(page).to have_field('Share', readonly: true, with: url)
end
it 'Unauthenticated user should see raw public snippets' do
- public_snippet = create(:personal_snippet, :public)
-
visit raw_snippet_path(public_snippet)
- expect(page).to have_content(public_snippet.content)
+ expect(page).to have_content(content)
end
end
diff --git a/spec/features/snippets/show_spec.rb b/spec/features/snippets/show_spec.rb
index 981ed12d540..2103d362f94 100644
--- a/spec/features/snippets/show_spec.rb
+++ b/spec/features/snippets/show_spec.rb
@@ -6,10 +6,6 @@ RSpec.describe 'Snippet', :js do
let_it_be(:user) { create(:user) }
let_it_be(:snippet) { create(:personal_snippet, :public, :repository, author: user) }
- before do
- stub_feature_flags(snippets_vue: false)
- end
-
it_behaves_like 'show and render proper snippet blob' do
let(:anchor) { nil }
@@ -20,12 +16,8 @@ RSpec.describe 'Snippet', :js do
end
end
- it_behaves_like 'showing user status' do
- let(:file_path) { 'files/ruby/popen.rb' }
- let(:user_with_status) { snippet.author }
-
- subject { visit snippet_path(snippet) }
- end
+ # it_behaves_like 'showing user status' do
+ # This will be handled in https://gitlab.com/gitlab-org/gitlab/-/issues/262394
it_behaves_like 'does not show New Snippet button' do
let(:file_path) { 'files/ruby/popen.rb' }
diff --git a/spec/features/snippets/spam_snippets_spec.rb b/spec/features/snippets/spam_snippets_spec.rb
index 1483ba4bf8f..54a56ac962c 100644
--- a/spec/features/snippets/spam_snippets_spec.rb
+++ b/spec/features/snippets/spam_snippets_spec.rb
@@ -2,9 +2,11 @@
require 'spec_helper'
-RSpec.shared_examples_for 'snippet editor' do
+RSpec.describe 'snippet editor with spam', skip: "Will be handled in https://gitlab.com/gitlab-org/gitlab/-/issues/217722" do
include_context 'includes Spam constants'
+ let_it_be(:user) { create(:user) }
+
def description_field
find('.js-description-input').find('input,textarea')
end
@@ -119,24 +121,3 @@ RSpec.shared_examples_for 'snippet editor' do
end
end
end
-
-RSpec.describe 'User creates snippet', :js do
- let_it_be(:user) { create(:user) }
-
- context 'Vue application' do
- before do
- stub_feature_flags(snippets_edit_vue: false)
- end
-
- it_behaves_like "snippet editor"
- end
-
- context 'non-Vue application' do
- before do
- stub_feature_flags(snippets_vue: false)
- stub_feature_flags(snippets_edit_vue: false)
- end
-
- it_behaves_like "snippet editor"
- end
-end
diff --git a/spec/features/snippets/user_creates_snippet_spec.rb b/spec/features/snippets/user_creates_snippet_spec.rb
index eabca028b8c..1e51210c2b8 100644
--- a/spec/features/snippets/user_creates_snippet_spec.rb
+++ b/spec/features/snippets/user_creates_snippet_spec.rb
@@ -13,163 +13,127 @@ RSpec.describe 'User creates snippet', :js do
let(:md_description) { 'My Snippet **Description**' }
let(:description) { 'My Snippet Description' }
let(:created_snippet) { Snippet.last }
- let(:snippet_title_field) { 'personal_snippet_title' }
+ let(:snippet_title_field) { 'snippet-title' }
- def description_field
- find('.js-description-input').find('input,textarea')
+ before do
+ sign_in(user)
+
+ visit new_snippet_path
end
- shared_examples 'snippet creation' do
- def fill_form
- snippet_fill_in_form(title: title, content: file_content, description: md_description)
- end
+ def fill_form
+ snippet_fill_in_form(title: title, content: file_content, description: md_description)
+ end
- it 'Authenticated user creates a snippet' do
- fill_form
+ it 'Authenticated user creates a snippet' do
+ fill_form
- click_button('Create snippet')
- wait_for_requests
+ click_button('Create snippet')
+ wait_for_requests
- expect(page).to have_content(title)
- page.within(snippet_description_view_selector) do
- expect(page).to have_content(description)
- expect(page).to have_selector('strong')
- end
- expect(page).to have_content(file_content)
+ expect(page).to have_content(title)
+ page.within(snippet_description_view_selector) do
+ expect(page).to have_content(description)
+ expect(page).to have_selector('strong')
end
+ expect(page).to have_content(file_content)
+ end
- it 'uploads a file when dragging into textarea' do
- fill_form
- dropzone_file Rails.root.join('spec', 'fixtures', 'banana_sample.gif')
-
- expect(snippet_description_value).to have_content('banana_sample')
-
- click_button('Create snippet')
- wait_for_requests
-
- link = find('a.no-attachment-icon img.js-lazy-loaded[alt="banana_sample"]')['src']
- expect(link).to match(%r{/uploads/-/system/personal_snippet/#{Snippet.last.id}/\h{32}/banana_sample\.gif\z})
+ it 'uploads a file when dragging into textarea' do
+ fill_form
+ dropzone_file Rails.root.join('spec', 'fixtures', 'banana_sample.gif')
- reqs = inspect_requests { visit("#{link}?ran=#{SecureRandom.base64(20)}") }
- expect(reqs.first.status_code).to eq(200)
- end
+ expect(snippet_description_value).to have_content('banana_sample')
- context 'when the git operation fails' do
- let(:error) { 'Error creating the snippet' }
+ click_button('Create snippet')
+ wait_for_requests
- before do
- allow_next_instance_of(Snippets::CreateService) do |instance|
- allow(instance).to receive(:create_commit).and_raise(StandardError, error)
- end
+ link = find('a.no-attachment-icon img.js-lazy-loaded[alt="banana_sample"]')['src']
+ expect(link).to match(%r{/uploads/-/system/personal_snippet/#{Snippet.last.id}/\h{32}/banana_sample\.gif\z})
- fill_form
- click_button('Create snippet')
- wait_for_requests
- end
+ reqs = inspect_requests { visit("#{link}?ran=#{SecureRandom.base64(20)}") }
+ expect(reqs.first.status_code).to eq(200)
+ end
- it 'renders the new page and displays the error' do
- expect(page).to have_content(error)
- expect(page).to have_content('New Snippet')
+ context 'when the git operation fails' do
+ let(:error) { 'Error creating the snippet' }
- action = find('form.snippet-form')['action']
- expect(action).to include("/snippets")
- end
- end
-
- context 'when snippets default visibility level is restricted' do
- before do
- stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PRIVATE],
- default_snippet_visibility: Gitlab::VisibilityLevel::PRIVATE)
+ before do
+ allow_next_instance_of(Snippets::CreateService) do |instance|
+ allow(instance).to receive(:create_commit).and_raise(StandardError, error)
end
- it 'creates a snippet using the lowest available visibility level as default' do
- visit new_snippet_path
-
- fill_form
-
- click_button('Create snippet')
- wait_for_requests
-
- expect(find('.blob-content')).to have_content(file_content)
- expect(Snippet.last.visibility_level).to eq(Gitlab::VisibilityLevel::INTERNAL)
- end
+ fill_form
+ click_button('Create snippet')
+ wait_for_requests
end
- it_behaves_like 'personal snippet with references' do
- let(:container) { snippet_description_view_selector }
- let(:md_description) { references }
+ it 'renders the new page and displays the error' do
+ expect(page).to have_content(error)
+ expect(page).to have_content('New Snippet')
- subject do
- fill_form
- click_button('Create snippet')
-
- wait_for_requests
- end
+ action = find('form.snippet-form')['action']
+ expect(action).to include("/snippets")
end
end
- context 'Vue application' do
- let(:snippet_description_field) { 'snippet-description' }
- let(:snippet_description_view_selector) { '.snippet-header .snippet-description' }
-
+ context 'when snippets default visibility level is restricted' do
before do
- sign_in(user)
-
- visit new_snippet_path
+ stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PRIVATE],
+ default_snippet_visibility: Gitlab::VisibilityLevel::PRIVATE)
end
- it_behaves_like 'snippet creation'
+ it 'creates a snippet using the lowest available visibility level as default' do
+ visit new_snippet_path
- it 'validation fails for the first time' do
- fill_in snippet_title_field, with: title
+ fill_form
- expect(page).not_to have_button('Create snippet')
+ click_button('Create snippet')
+ wait_for_requests
- snippet_fill_in_form(title: title, content: file_content)
- expect(page).to have_button('Create snippet')
+ expect(find('.blob-content')).to have_content(file_content)
+ expect(Snippet.last.visibility_level).to eq(Gitlab::VisibilityLevel::INTERNAL)
end
end
- context 'non-Vue application' do
- let(:snippet_description_field) { 'personal_snippet_description' }
- let(:snippet_description_view_selector) { '.snippet-header .description' }
+ it_behaves_like 'personal snippet with references' do
+ let(:container) { snippet_description_view_selector }
+ let(:md_description) { references }
- before do
- stub_feature_flags(snippets_vue: false)
- stub_feature_flags(snippets_edit_vue: false)
-
- sign_in(user)
+ subject do
+ fill_form
+ click_button('Create snippet')
- visit new_snippet_path
+ wait_for_requests
end
+ end
- it_behaves_like 'snippet creation'
+ it 'validation fails for the first time' do
+ fill_in snippet_title_field, with: title
- it 'validation fails for the first time' do
- fill_in snippet_title_field, with: title
- click_button('Create snippet')
+ expect(page).not_to have_button('Create snippet')
- expect(page).to have_selector('#error_explanation')
- end
+ snippet_fill_in_form(title: title, content: file_content)
+ expect(page).to have_button('Create snippet')
+ end
- it 'previews a snippet with file' do
- # Click placeholder first to expand full description field
- description_field.click
- fill_in snippet_description_field, with: 'My Snippet'
- dropzone_file Rails.root.join('spec', 'fixtures', 'banana_sample.gif')
- find('.js-md-preview-button').click
+ it 'previews a snippet with file' do
+ # Click placeholder first to expand full description field
+ snippet_fill_in_description('My Snippet')
+ dropzone_file Rails.root.join('spec', 'fixtures', 'banana_sample.gif')
+ find('.js-md-preview-button').click
- page.within('.md-preview-holder') do
- expect(page).to have_content('My Snippet')
+ page.within('.md-preview-holder') do
+ expect(page).to have_content('My Snippet')
- link = find('a.no-attachment-icon img.js-lazy-loaded[alt="banana_sample"]')['src']
- expect(link).to match(%r{/uploads/-/system/user/#{user.id}/\h{32}/banana_sample\.gif\z})
+ link = find('a.no-attachment-icon img.js-lazy-loaded[alt="banana_sample"]')['src']
+ expect(link).to match(%r{/uploads/-/system/user/#{user.id}/\h{32}/banana_sample\.gif\z})
- # Adds a cache buster for checking if the image exists as Selenium is now handling the cached requests
- # not anymore as requests when they come straight from memory cache.
- reqs = inspect_requests { visit("#{link}?ran=#{SecureRandom.base64(20)}") }
- expect(reqs.first.status_code).to eq(200)
- end
+ # Adds a cache buster for checking if the image exists as Selenium is now handling the cached requests
+ # not anymore as requests when they come straight from memory cache.
+ # accept_confirm is needed because of https://gitlab.com/gitlab-org/gitlab/-/issues/262102
+ reqs = inspect_requests { accept_confirm { visit("#{link}?ran=#{SecureRandom.base64(20)}") } }
+ expect(reqs.first.status_code).to eq(200)
end
end
end
diff --git a/spec/features/snippets/user_deletes_snippet_spec.rb b/spec/features/snippets/user_deletes_snippet_spec.rb
index d7cfc67df13..e896f7eb25b 100644
--- a/spec/features/snippets/user_deletes_snippet_spec.rb
+++ b/spec/features/snippets/user_deletes_snippet_spec.rb
@@ -2,21 +2,23 @@
require 'spec_helper'
-RSpec.describe 'User deletes snippet' do
+RSpec.describe 'User deletes snippet', :js do
let(:user) { create(:user) }
let(:content) { 'puts "test"' }
- let(:snippet) { create(:personal_snippet, :public, content: content, author: user) }
+ let(:snippet) { create(:personal_snippet, :repository, :public, content: content, author: user) }
before do
sign_in(user)
- stub_feature_flags(snippets_vue: false)
-
visit snippet_path(snippet)
end
it 'deletes the snippet' do
- first(:link, 'Delete').click
+ expect(page).to have_content(snippet.title)
+
+ click_button('Delete')
+ click_button('Delete snippet')
+ wait_for_requests
expect(page).not_to have_content(snippet.title)
end
diff --git a/spec/features/snippets/user_edits_snippet_spec.rb b/spec/features/snippets/user_edits_snippet_spec.rb
index 9a83eb58b63..a04c59b53d2 100644
--- a/spec/features/snippets/user_edits_snippet_spec.rb
+++ b/spec/features/snippets/user_edits_snippet_spec.rb
@@ -11,107 +11,77 @@ RSpec.describe 'User edits snippet', :js do
let_it_be(:user) { create(:user) }
let_it_be(:snippet, reload: true) { create(:personal_snippet, :repository, :public, file_name: file_name, content: content, author: user) }
- let(:snippet_title_field) { 'personal_snippet_title' }
+ before do
+ sign_in(user)
- shared_examples 'snippet editing' do
- it 'displays the snippet blob path and content' do
- blob = snippet.blobs.first
-
- aggregate_failures do
- expect(snippet_get_first_blob_path).to eq blob.path
- expect(snippet_get_first_blob_value).to have_content(blob.data.strip)
- end
- end
-
- it 'updates the snippet' do
- fill_in snippet_title_field, with: 'New Snippet Title'
-
- click_button('Save changes')
- wait_for_requests
-
- expect(page).to have_content('New Snippet Title')
- end
-
- it 'updates the snippet with files attached' do
- dropzone_file Rails.root.join('spec', 'fixtures', 'banana_sample.gif')
- expect(snippet_description_value).to have_content('banana_sample')
+ visit edit_snippet_path(snippet)
+ wait_for_all_requests
+ end
- click_button('Save changes')
- wait_for_requests
+ it 'displays the snippet blob path and content' do
+ blob = snippet.blobs.first
- link = find('a.no-attachment-icon img:not(.lazy)[alt="banana_sample"]')['src']
- expect(link).to match(%r{/uploads/-/system/personal_snippet/#{snippet.id}/\h{32}/banana_sample\.gif\z})
+ aggregate_failures do
+ expect(snippet_get_first_blob_path).to eq blob.path
+ expect(snippet_get_first_blob_value).to have_content(blob.data.strip)
end
+ end
- it 'updates the snippet to make it internal' do
- choose 'Internal'
-
- click_button 'Save changes'
- wait_for_requests
+ it 'updates the snippet' do
+ snippet_fill_in_title('New Snippet Title')
+ expect(page).not_to have_selector('.gl-spinner')
- expect(page).to have_no_selector('[data-testid="lock-icon"]')
- expect(page).to have_selector('[data-testid="shield-icon"]')
- end
+ click_button('Save changes')
+ wait_for_requests
- it 'updates the snippet to make it public' do
- choose 'Public'
+ expect(page).to have_content('New Snippet Title')
+ end
- click_button 'Save changes'
- wait_for_requests
+ it 'updates the snippet with files attached' do
+ dropzone_file Rails.root.join('spec', 'fixtures', 'banana_sample.gif')
+ expect(snippet_description_value).to have_content('banana_sample')
- expect(page).to have_no_selector('[data-testid="lock-icon"]')
- expect(page).to have_selector('[data-testid="earth-icon"]')
- end
+ click_button('Save changes')
+ wait_for_requests
- context 'when the git operation fails' do
- before do
- allow_next_instance_of(Snippets::UpdateService) do |instance|
- allow(instance).to receive(:create_commit).and_raise(StandardError, 'Error Message')
- end
+ link = find('a.no-attachment-icon img:not(.lazy)[alt="banana_sample"]')['src']
+ expect(link).to match(%r{/uploads/-/system/personal_snippet/#{snippet.id}/\h{32}/banana_sample\.gif\z})
+ end
- fill_in snippet_title_field, with: 'New Snippet Title'
- fill_in snippet_blob_path_field, with: 'new_file_name', match: :first
+ it 'updates the snippet to make it internal' do
+ snippet_fill_in_visibility('Internal')
- click_button('Save changes')
- end
+ click_button 'Save changes'
+ wait_for_requests
- it 'renders edit page and displays the error' do
- expect(page.find('.flash-container')).to have_content('Error updating the snippet - Error Message')
- expect(page).to have_content('Edit Snippet')
- end
- end
+ expect(page).to have_no_selector('[data-testid="lock-icon"]')
+ expect(page).to have_selector('[data-testid="shield-icon"]')
end
- context 'Vue application' do
- it_behaves_like 'snippet editing' do
- let(:snippet_blob_path_field) { 'snippet_file_name' }
- let(:snippet_blob_content_selector) { '.file-content' }
- let(:snippet_description_field) { 'snippet-description' }
+ it 'updates the snippet to make it public' do
+ snippet_fill_in_visibility('Public')
- before do
- sign_in(user)
+ click_button 'Save changes'
+ wait_for_requests
- visit edit_snippet_path(snippet)
- wait_for_all_requests
- end
- end
+ expect(page).to have_no_selector('[data-testid="lock-icon"]')
+ expect(page).to have_selector('[data-testid="earth-icon"]')
end
- context 'non-Vue application' do
- it_behaves_like 'snippet editing' do
- let(:snippet_blob_path_field) { 'personal_snippet_file_name' }
- let(:snippet_blob_content_selector) { '.file-content' }
- let(:snippet_description_field) { 'personal_snippet_description' }
+ context 'when the git operation fails' do
+ before do
+ allow_next_instance_of(Snippets::UpdateService) do |instance|
+ allow(instance).to receive(:create_commit).and_raise(StandardError, 'Error Message')
+ end
- before do
- stub_feature_flags(snippets_vue: false)
- stub_feature_flags(snippets_edit_vue: false)
+ snippet_fill_in_form(title: 'New Snippet Title', file_name: 'new_file_name')
- sign_in(user)
+ click_button('Save changes')
+ end
- visit edit_snippet_path(snippet)
- wait_for_all_requests
- end
+ it 'renders edit page and displays the error' do
+ expect(page.find('.flash-container')).to have_content('Error updating the snippet - Error Message')
+ expect(page).to have_content('Edit Snippet')
end
end
end
diff --git a/spec/features/snippets_spec.rb b/spec/features/snippets_spec.rb
index 75309ca3e7c..8cdb4bc3344 100644
--- a/spec/features/snippets_spec.rb
+++ b/spec/features/snippets_spec.rb
@@ -18,11 +18,8 @@ RSpec.describe 'Snippets' do
describe 'rendering engine' do
let_it_be(:snippet) { create(:personal_snippet, :public) }
- let(:snippets_vue_feature_flag_enabled) { true }
before do
- stub_feature_flags(snippets_vue: snippets_vue_feature_flag_enabled)
-
visit snippet_path(snippet)
end
@@ -30,14 +27,5 @@ RSpec.describe 'Snippets' do
expect(page).to have_selector('#js-snippet-view')
expect(page).not_to have_selector('.personal-snippets')
end
-
- context 'when feature flag is disabled' do
- let(:snippets_vue_feature_flag_enabled) { false }
-
- it 'renders HAML application and not Vue' do
- expect(page).not_to have_selector('#js-snippet-view')
- expect(page).to have_selector('.personal-snippets')
- end
- end
end
end
diff --git a/spec/features/static_site_editor_spec.rb b/spec/features/static_site_editor_spec.rb
index b67e47b6ac4..03085917d67 100644
--- a/spec/features/static_site_editor_spec.rb
+++ b/spec/features/static_site_editor_spec.rb
@@ -6,18 +6,71 @@ RSpec.describe 'Static Site Editor' do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project, :public, :repository) }
+ let(:sse_path) { project_show_sse_path(project, 'master/README.md') }
+
+ before_all do
+ project.add_developer(user)
+ end
+
before do
- project.add_maintainer(user)
sign_in(user)
+ end
+
+ context "when no config file is present" do
+ before do
+ visit sse_path
+ end
- visit project_show_sse_path(project, 'master/README.md')
+ it 'renders SSE page with all generated config values and default config file values' do
+ node = page.find('#static-site-editor')
+
+ # assert generated config values are present
+ expect(node['data-base-url']).to eq("/#{project.full_path}/-/sse/master%2FREADME.md")
+ expect(node['data-branch']).to eq('master')
+ expect(node['data-commit-id']).to match(/\A[0-9a-f]{40}\z/)
+ expect(node['data-is-supported-content']).to eq('true')
+ expect(node['data-merge-requests-illustration-path'])
+ .to match(%r{/assets/illustrations/merge_requests-.*\.svg})
+ expect(node['data-namespace']).to eq(project.namespace.full_path)
+ expect(node['data-project']).to eq(project.path)
+ expect(node['data-project-id']).to eq(project.id.to_s)
+
+ # assert default config file values are present
+ expect(node['data-image-upload-path']).to eq('source/images')
+ expect(node['data-mounts']).to eq('[{"source":"source","target":""}]')
+ expect(node['data-static-site-generator']).to eq('middleman')
+ end
end
- it 'renders Static Site Editor page with generated and file attributes' do
- # assert generated config value is present
- expect(page).to have_css('#static-site-editor[data-branch="master"]')
+ context "when a config file is present" do
+ let(:config_file_yml) do
+ <<~YAML
+ image_upload_path: custom-image-upload-path
+ mounts:
+ - source: source1
+ target: ""
+ - source: source2
+ target: target2
+ static_site_generator: middleman
+ YAML
+ end
+
+ before do
+ allow_next_instance_of(Repository) do |repository|
+ allow(repository).to receive(:blob_data_at).and_return(config_file_yml)
+ end
+
+ visit sse_path
+ end
+
+ it 'renders Static Site Editor page values read from config file' do
+ node = page.find('#static-site-editor')
- # assert file config value is present
- expect(page).to have_css('#static-site-editor[data-static-site-generator="middleman"]')
+ # assert user-specified config file values are present
+ expected_mounts = '[{"source":"source1","target":""},{"source":"source2","target":"target2"}]'
+ expect(node['data-image-upload-path']).to eq('custom-image-upload-path')
+ expect(node['data-mounts']).to eq(expected_mounts)
+ expect(node['data-static-site-generator']).to eq('middleman')
+ end
end
end
diff --git a/spec/features/tags/developer_deletes_tag_spec.rb b/spec/features/tags/developer_deletes_tag_spec.rb
index de9296bc08e..7c4c6f54685 100644
--- a/spec/features/tags/developer_deletes_tag_spec.rb
+++ b/spec/features/tags/developer_deletes_tag_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Developer deletes tag' do
+RSpec.describe 'Developer deletes tag', :js do
let(:user) { create(:user) }
let(:group) { create(:group) }
let(:project) { create(:project, :repository, namespace: group) }
@@ -13,11 +13,12 @@ RSpec.describe 'Developer deletes tag' do
visit project_tags_path(project)
end
- context 'from the tags list page', :js do
+ context 'from the tags list page' do
it 'deletes the tag' do
expect(page).to have_content 'v1.1.0'
- delete_tag 'v1.1.0'
+ container = page.find('.content .flex-row', text: 'v1.1.0')
+ delete_tag container
expect(page).not_to have_content 'v1.1.0'
end
@@ -29,15 +30,15 @@ RSpec.describe 'Developer deletes tag' do
expect(current_path).to eq(
project_tag_path(project, 'v1.0.0'))
- click_on 'Delete tag'
+ container = page.find('.nav-controls')
+ delete_tag container
- expect(current_path).to eq(
- project_tags_path(project))
+ expect(current_path).to eq("#{project_tags_path(project)}/")
expect(page).not_to have_content 'v1.0.0'
end
end
- context 'when pre-receive hook fails', :js do
+ context 'when pre-receive hook fails' do
before do
allow_next_instance_of(Gitlab::GitalyClient::OperationService) do |instance|
allow(instance).to receive(:rm_tag)
@@ -46,15 +47,17 @@ RSpec.describe 'Developer deletes tag' do
end
it 'shows the error message' do
- delete_tag 'v1.1.0'
+ container = page.find('.content .flex-row', text: 'v1.1.0')
+ delete_tag container
expect(page).to have_content('Do not delete tags')
end
end
- def delete_tag(tag)
- page.within('.content') do
- accept_confirm { find("li > .row-fixed-content.controls a.btn-remove[href='/#{project.full_path}/-/tags/#{tag}']").click }
- end
+ def delete_tag(container)
+ container.find('.js-remove-tag').click
+
+ page.within('.modal') { click_button('Delete tag') }
+ wait_for_requests
end
end
diff --git a/spec/features/tags/developer_views_tags_spec.rb b/spec/features/tags/developer_views_tags_spec.rb
index 4888611472c..6bae53afe6f 100644
--- a/spec/features/tags/developer_views_tags_spec.rb
+++ b/spec/features/tags/developer_views_tags_spec.rb
@@ -3,6 +3,8 @@
require 'spec_helper'
RSpec.describe 'Developer views tags' do
+ include RepoHelpers
+
let(:user) { create(:user) }
let(:group) { create(:group) }
@@ -15,10 +17,13 @@ RSpec.describe 'Developer views tags' do
let(:project) { create(:project_empty_repo, namespace: group) }
before do
- visit project_path(project)
- click_on 'Add README'
- fill_in :commit_message, with: 'Add a README file', visible: true
- click_button 'Commit changes'
+ project.repository.create_file(
+ user,
+ 'README.md',
+ 'Example readme',
+ message: 'Add README',
+ branch_name: 'master')
+
visit project_tags_path(project)
end
diff --git a/spec/features/task_lists_spec.rb b/spec/features/task_lists_spec.rb
index a9cfe794177..0f8daaf8e15 100644
--- a/spec/features/task_lists_spec.rb
+++ b/spec/features/task_lists_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Task Lists' do
+RSpec.describe 'Task Lists', :js do
include Warden::Test::Helpers
let_it_be(:project) { create(:project, :public, :repository) }
@@ -38,41 +38,7 @@ RSpec.describe 'Task Lists' do
MARKDOWN
end
- let(:nested_tasks_markdown) do
- <<-EOT.strip_heredoc
- - [ ] Task a
- - [x] Task a.1
- - [ ] Task a.2
- - [ ] Task b
-
- 1. [ ] Task 1
- 1. [ ] Task 1.1
- 1. [x] Task 1.2
- EOT
- end
-
- let(:commented_tasks_markdown) do
- <<-EOT.strip_heredoc
- <!--
- - [ ] a
- -->
-
- - [ ] b
- EOT
- end
-
- let(:summary_no_blank_line_markdown) do
- <<-EOT.strip_heredoc
- <details>
- <summary>No blank line after summary element breaks task list</summary>
- 1. [ ] People Ops: do such and such
- </details>
-
- * [ ] Task 1
- EOT
- end
-
- before(:all) do
+ before_all do
project.add_maintainer(user)
project.add_guest(user2)
end
@@ -86,7 +52,7 @@ RSpec.describe 'Task Lists' do
end
describe 'for Issues' do
- describe 'multiple tasks', :js do
+ describe 'multiple tasks' do
let!(:issue) { create(:issue, description: markdown, author: user, project: project) }
it 'renders' do
@@ -127,7 +93,7 @@ RSpec.describe 'Task Lists' do
end
end
- describe 'single incomplete task', :js do
+ describe 'single incomplete task' do
let!(:issue) { create(:issue, description: singleIncompleteMarkdown, author: user, project: project) }
it 'renders' do
@@ -146,7 +112,7 @@ RSpec.describe 'Task Lists' do
end
end
- describe 'single complete task', :js do
+ describe 'single complete task' do
let!(:issue) { create(:issue, description: singleCompleteMarkdown, author: user, project: project) }
it 'renders' do
@@ -175,7 +141,7 @@ RSpec.describe 'Task Lists' do
project: project, author: user)
end
- it 'renders for note body', :js do
+ it 'renders for note body' do
visit_issue(project, issue)
expect(page).to have_selector('.note ul.task-list', count: 1)
@@ -183,14 +149,14 @@ RSpec.describe 'Task Lists' do
expect(page).to have_selector('.note ul input[checked]', count: 2)
end
- it 'contains the required selectors', :js do
+ it 'contains the required selectors' do
visit_issue(project, issue)
expect(page).to have_selector('.note .js-task-list-container')
expect(page).to have_selector('.note .js-task-list-container .task-list .task-list-item .task-list-item-checkbox')
end
- it 'is only editable by author', :js do
+ it 'is only editable by author' do
visit_issue(project, issue)
expect(page).to have_selector('.js-task-list-container')
@@ -209,7 +175,7 @@ RSpec.describe 'Task Lists' do
project: project, author: user)
end
- it 'renders for note body', :js do
+ it 'renders for note body' do
visit_issue(project, issue)
expect(page).to have_selector('.note ul.task-list', count: 1)
@@ -224,7 +190,7 @@ RSpec.describe 'Task Lists' do
project: project, author: user)
end
- it 'renders for note body', :js do
+ it 'renders for note body' do
visit_issue(project, issue)
expect(page).to have_selector('.note ul.task-list', count: 1)
@@ -240,7 +206,7 @@ RSpec.describe 'Task Lists' do
end
shared_examples 'multiple tasks' do
- it 'renders for description', :js do
+ it 'renders for description' do
visit_merge_request(project, merge)
wait_for_requests
@@ -249,7 +215,7 @@ RSpec.describe 'Task Lists' do
expect(page).to have_selector('ul input[checked]', count: 2)
end
- it 'contains the required selectors', :js do
+ it 'contains the required selectors' do
visit_merge_request(project, merge)
wait_for_requests
@@ -261,7 +227,7 @@ RSpec.describe 'Task Lists' do
expect(page).to have_selector('form.js-issuable-update')
end
- it 'is only editable by author', :js do
+ it 'is only editable by author' do
visit_merge_request(project, merge)
wait_for_requests
@@ -300,7 +266,7 @@ RSpec.describe 'Task Lists' do
describe 'single incomplete task' do
let!(:merge) { create(:merge_request, :simple, description: singleIncompleteMarkdown, author: user, source_project: project) }
- it 'renders for description', :js do
+ it 'renders for description' do
visit_merge_request(project, merge)
wait_for_requests
@@ -319,7 +285,7 @@ RSpec.describe 'Task Lists' do
describe 'single complete task' do
let!(:merge) { create(:merge_request, :simple, description: singleCompleteMarkdown, author: user, source_project: project) }
- it 'renders for description', :js do
+ it 'renders for description' do
visit_merge_request(project, merge)
wait_for_requests
@@ -337,7 +303,17 @@ RSpec.describe 'Task Lists' do
end
describe 'markdown task edge cases' do
- describe 'commented tasks', :js do
+ describe 'commented tasks' do
+ let(:commented_tasks_markdown) do
+ <<-EOT.strip_heredoc
+ <!--
+ - [ ] a
+ -->
+
+ - [ ] b
+ EOT
+ end
+
let!(:issue) { create(:issue, description: commented_tasks_markdown, author: user, project: project) }
it 'renders' do
@@ -360,7 +336,18 @@ RSpec.describe 'Task Lists' do
end
end
- describe 'summary with no blank line', :js do
+ describe 'summary with no blank line' do
+ let(:summary_no_blank_line_markdown) do
+ <<-EOT.strip_heredoc
+ <details>
+ <summary>No blank line after summary element breaks task list</summary>
+ 1. [ ] People Ops: do such and such
+ </details>
+
+ * [ ] Task 1
+ EOT
+ end
+
let!(:issue) { create(:issue, description: summary_no_blank_line_markdown, author: user, project: project) }
it 'renders' do
@@ -382,5 +369,31 @@ RSpec.describe 'Task Lists' do
expect(page).to have_selector('ul input[checked]', count: 1)
end
end
+
+ describe 'markdown starting with new line character' do
+ let(:markdown_starting_with_new_line) do
+ <<-EOT.strip_heredoc
+
+ - [ ] Task 1
+ EOT
+ end
+
+ let(:merge_request) { create(:merge_request, description: markdown_starting_with_new_line, author: user, source_project: project) }
+
+ it 'allows the task to be checked' do
+ visit project_merge_request_path(project, merge_request)
+ wait_for_requests
+
+ expect(page).to have_selector('ul input[checked]', count: 0)
+
+ find('.task-list-item-checkbox').click
+ wait_for_requests
+
+ visit project_merge_request_path(project, merge_request)
+ wait_for_requests
+
+ expect(page).to have_selector('ul input[checked]', count: 1)
+ end
+ end
end
end
diff --git a/spec/features/triggers_spec.rb b/spec/features/triggers_spec.rb
index 4be27673adf..6fa805d8c74 100644
--- a/spec/features/triggers_spec.rb
+++ b/spec/features/triggers_spec.rb
@@ -19,114 +19,132 @@ RSpec.describe 'Triggers', :js do
visit project_settings_ci_cd_path(@project)
end
- describe 'create trigger workflow' do
- it 'prevents adding new trigger with no description' do
- fill_in 'trigger_description', with: ''
- click_button 'Add trigger'
-
- # See if input has error due to empty value
- expect(page.find('form.gl-show-field-errors .gl-field-error')).to be_visible
- end
+ shared_examples 'triggers page' do
+ describe 'create trigger workflow' do
+ it 'prevents adding new trigger with no description' do
+ fill_in 'trigger_description', with: ''
+ click_button 'Add trigger'
+
+ # See if input has error due to empty value
+ expect(page.find('form.gl-show-field-errors .gl-field-error')).to be_visible
+ end
- it 'adds new trigger with description' do
- fill_in 'trigger_description', with: 'trigger desc'
- click_button 'Add trigger'
+ it 'adds new trigger with description' do
+ fill_in 'trigger_description', with: 'trigger desc'
+ click_button 'Add trigger'
- # See if "trigger creation successful" message displayed and description and owner are correct
- expect(page.find('.flash-notice')).to have_content 'Trigger was created successfully.'
- expect(page.find('.triggers-list')).to have_content 'trigger desc'
- expect(page.find('.triggers-list .trigger-owner')).to have_content user.name
+ aggregate_failures 'display creation notice and trigger is created' do
+ expect(page.find('.flash-notice')).to have_content 'Trigger was created successfully.'
+ expect(page.find('.triggers-list')).to have_content 'trigger desc'
+ expect(page.find('.triggers-list .trigger-owner')).to have_content user.name
+ end
+ end
end
- end
-
- describe 'edit trigger workflow' do
- let(:new_trigger_title) { 'new trigger' }
- it 'click on edit trigger opens edit trigger page' do
- create(:ci_trigger, owner: user, project: @project, description: trigger_title)
- visit project_settings_ci_cd_path(@project)
+ describe 'edit trigger workflow' do
+ let(:new_trigger_title) { 'new trigger' }
- # See if edit page has correct descrption
- find('a[title="Edit"]').send_keys(:return)
- expect(page.find('#trigger_description').value).to have_content 'trigger desc'
- end
+ it 'click on edit trigger opens edit trigger page' do
+ create(:ci_trigger, owner: user, project: @project, description: trigger_title)
+ visit project_settings_ci_cd_path(@project)
- it 'edit trigger and save' do
- create(:ci_trigger, owner: user, project: @project, description: trigger_title)
- visit project_settings_ci_cd_path(@project)
+ # See if edit page has correct descrption
+ find('a[title="Edit"]').send_keys(:return)
+ expect(page.find('#trigger_description').value).to have_content 'trigger desc'
+ end
- # See if edit page opens, then fill in new description and save
- find('a[title="Edit"]').send_keys(:return)
- fill_in 'trigger_description', with: new_trigger_title
- click_button 'Save trigger'
+ it 'edit trigger and save' do
+ create(:ci_trigger, owner: user, project: @project, description: trigger_title)
+ visit project_settings_ci_cd_path(@project)
- # See if "trigger updated successfully" message displayed and description and owner are correct
- expect(page.find('.flash-notice')).to have_content 'Trigger was successfully updated.'
- expect(page.find('.triggers-list')).to have_content new_trigger_title
- expect(page.find('.triggers-list .trigger-owner')).to have_content user.name
- end
- end
+ # See if edit page opens, then fill in new description and save
+ find('a[title="Edit"]').send_keys(:return)
+ fill_in 'trigger_description', with: new_trigger_title
+ click_button 'Save trigger'
- describe 'trigger "Revoke" workflow' do
- before do
- create(:ci_trigger, owner: user2, project: @project, description: trigger_title)
- visit project_settings_ci_cd_path(@project)
+ aggregate_failures 'display update notice and trigger is updated' do
+ expect(page.find('.flash-notice')).to have_content 'Trigger was successfully updated.'
+ expect(page.find('.triggers-list')).to have_content new_trigger_title
+ expect(page.find('.triggers-list .trigger-owner')).to have_content user.name
+ end
+ end
end
- it 'button "Revoke" has correct alert' do
- expected_alert = 'By revoking a trigger you will break any processes making use of it. Are you sure?'
- expect(page.find('a.btn-trigger-revoke')['data-confirm']).to eq expected_alert
- end
+ describe 'trigger "Revoke" workflow' do
+ before do
+ create(:ci_trigger, owner: user2, project: @project, description: trigger_title)
+ visit project_settings_ci_cd_path(@project)
+ end
- it 'revoke trigger' do
- # See if "Revoke" on trigger works post trigger creation
- page.accept_confirm do
- find('a.btn-trigger-revoke').send_keys(:return)
+ it 'button "Revoke" has correct alert' do
+ expected_alert = 'By revoking a trigger you will break any processes making use of it. Are you sure?'
+ expect(page.find('[data-testid="trigger_revoke_button"]')['data-confirm']).to eq expected_alert
end
- expect(page.find('.flash-notice')).to have_content 'Trigger removed'
- expect(page).to have_selector('p.settings-message.text-center.gl-mb-3')
- end
- end
+ it 'revoke trigger' do
+ # See if "Revoke" on trigger works post trigger creation
+ page.accept_confirm do
+ find('[data-testid="trigger_revoke_button"]').send_keys(:return)
+ end
- describe 'show triggers workflow' do
- it 'contains trigger description placeholder' do
- expect(page.find('#trigger_description')['placeholder']).to eq 'Trigger description'
+ aggregate_failures 'trigger is removed' do
+ expect(page.find('.flash-notice')).to have_content 'Trigger removed'
+ expect(page).to have_css('[data-testid="no_triggers_content"]')
+ end
+ end
end
- it 'show "invalid" badge for trigger with owner having insufficient permissions' do
- create(:ci_trigger, owner: guest_user, project: @project, description: trigger_title)
- visit project_settings_ci_cd_path(@project)
+ describe 'show triggers workflow' do
+ it 'contains trigger description placeholder' do
+ expect(page.find('#trigger_description')['placeholder']).to eq 'Trigger description'
+ end
- expect(page.find('.triggers-list')).to have_content 'invalid'
- expect(page.find('.triggers-list')).not_to have_selector('a[title="Edit"]')
- end
+ it 'show "invalid" badge for trigger with owner having insufficient permissions' do
+ create(:ci_trigger, owner: guest_user, project: @project, description: trigger_title)
+ visit project_settings_ci_cd_path(@project)
+
+ aggregate_failures 'has invalid badge and no edit link' do
+ expect(page.find('.triggers-list')).to have_content 'invalid'
+ expect(page.find('.triggers-list')).not_to have_selector('a[title="Edit"]')
+ end
+ end
- it 'do not show "Edit" or full token for not owned trigger' do
- # Create trigger with user different from current_user
- create(:ci_trigger, owner: user2, project: @project, description: trigger_title)
- visit project_settings_ci_cd_path(@project)
+ it 'do not show "Edit" or full token for not owned trigger' do
+ # Create trigger with user different from current_user
+ create(:ci_trigger, owner: user2, project: @project, description: trigger_title)
+ visit project_settings_ci_cd_path(@project)
+
+ aggregate_failures 'shows truncated token, no clipboard button and no edit link' do
+ expect(page.find('.triggers-list')).to have_content(@project.triggers.first.token[0..3])
+ expect(page.find('.triggers-list')).not_to have_selector('[data-testid="clipboard-btn"]')
+ expect(page.find('.triggers-list .trigger-owner')).not_to have_content user.name
+ expect(page.find('.triggers-list')).not_to have_selector('a[title="Edit"]')
+ end
+ end
- # See if trigger not owned by current_user shows only first few token chars and doesn't have copy-to-clipboard button
- expect(page.find('.triggers-list')).to have_content(@project.triggers.first.token[0..3])
- expect(page.find('.triggers-list')).not_to have_selector('button.btn-clipboard')
+ it 'show "Edit" and full token for owned trigger' do
+ create(:ci_trigger, owner: user, project: @project, description: trigger_title)
+ visit project_settings_ci_cd_path(@project)
- # See if trigger owner name doesn't match with current_user and trigger is non-editable
- expect(page.find('.triggers-list .trigger-owner')).not_to have_content user.name
- expect(page.find('.triggers-list')).not_to have_selector('a[title="Edit"]')
+ aggregate_failures 'shows full token, clipboard button and edit link' do
+ expect(page.find('.triggers-list')).to have_content @project.triggers.first.token
+ expect(page.find('.triggers-list')).to have_selector('[data-testid="clipboard-btn"]')
+ expect(page.find('.triggers-list .trigger-owner')).to have_content user.name
+ expect(page.find('.triggers-list')).to have_selector('a[title="Edit"]')
+ end
+ end
end
+ end
- it 'show "Edit" and full token for owned trigger' do
- create(:ci_trigger, owner: user, project: @project, description: trigger_title)
- visit project_settings_ci_cd_path(@project)
-
- # See if trigger shows full token and has copy-to-clipboard button
- expect(page.find('.triggers-list')).to have_content @project.triggers.first.token
- expect(page.find('.triggers-list')).to have_selector('button.btn-clipboard')
+ context 'when ci_pipeline_triggers_settings_vue_ui is enabled' do
+ it_behaves_like 'triggers page'
+ end
- # See if trigger owner name matches with current_user and is editable
- expect(page.find('.triggers-list .trigger-owner')).to have_content user.name
- expect(page.find('.triggers-list')).to have_selector('a[title="Edit"]')
+ context 'when ci_pipeline_triggers_settings_vue_ui is disabled' do
+ before do
+ stub_feature_flags(ci_pipeline_triggers_settings_vue_ui: false)
end
+
+ it_behaves_like 'triggers page'
end
end
diff --git a/spec/features/users/overview_spec.rb b/spec/features/users/overview_spec.rb
index 549087e5950..67216b04504 100644
--- a/spec/features/users/overview_spec.rb
+++ b/spec/features/users/overview_spec.rb
@@ -21,15 +21,15 @@ RSpec.describe 'Overview tab on a user profile', :js do
sign_in user
end
- describe 'activities section' do
- shared_context 'visit overview tab' do
- before do
- visit user.username
- page.find('.js-overview-tab a').click
- wait_for_requests
- end
+ shared_context 'visit overview tab' do
+ before do
+ visit user.username
+ page.find('.js-overview-tab a').click
+ wait_for_requests
end
+ end
+ describe 'activities section' do
describe 'user has no activities' do
include_context 'visit overview tab'
@@ -84,14 +84,6 @@ RSpec.describe 'Overview tab on a user profile', :js do
end
describe 'projects section' do
- shared_context 'visit overview tab' do
- before do
- visit user.username
- page.find('.js-overview-tab a').click
- wait_for_requests
- end
- end
-
describe 'user has no personal projects' do
include_context 'visit overview tab'
@@ -158,4 +150,52 @@ RSpec.describe 'Overview tab on a user profile', :js do
end
end
end
+
+ describe 'bot user' do
+ let(:bot_user) { create(:user, user_type: :security_bot) }
+
+ shared_context "visit bot's overview tab" do
+ before do
+ visit bot_user.username
+ page.find('.js-overview-tab a').click
+ wait_for_requests
+ end
+ end
+
+ describe 'feature flag enabled' do
+ before do
+ stub_feature_flags(security_auto_fix: true)
+ end
+
+ include_context "visit bot's overview tab"
+
+ it "activity panel's title is 'Bot activity'" do
+ page.within('.activities-block') do
+ expect(page).to have_text('Bot activity')
+ end
+ end
+
+ it 'does not show projects panel' do
+ expect(page).not_to have_selector('.projects-block')
+ end
+ end
+
+ describe 'feature flag disabled' do
+ before do
+ stub_feature_flags(security_auto_fix: false)
+ end
+
+ include_context "visit bot's overview tab"
+
+ it "activity panel's title is not 'Bot activity'" do
+ page.within('.activities-block') do
+ expect(page).not_to have_text('Bot activity')
+ end
+ end
+
+ it 'shows projects panel' do
+ expect(page).to have_selector('.projects-block')
+ end
+ end
+ end
end
diff --git a/spec/features/users/show_spec.rb b/spec/features/users/show_spec.rb
index dd5c2442d00..466b7361da9 100644
--- a/spec/features/users/show_spec.rb
+++ b/spec/features/users/show_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe 'User page' do
include ExternalAuthorizationServiceHelpers
- let(:user) { create(:user) }
+ let(:user) { create(:user, bio: '**Lorem** _ipsum_ dolor sit [amet](https://example.com)') }
context 'with public profile' do
it 'shows all the tabs' do
@@ -174,4 +174,54 @@ RSpec.describe 'User page' do
end
end
end
+
+ context 'page description' do
+ before do
+ visit(user_path(user))
+ end
+
+ it_behaves_like 'page meta description', 'Lorem ipsum dolor sit amet'
+ end
+
+ context 'with a bot user' do
+ let(:user) { create(:user, user_type: :security_bot) }
+
+ describe 'feature flag enabled' do
+ before do
+ stub_feature_flags(security_auto_fix: true)
+ end
+
+ it 'only shows Overview and Activity tabs' do
+ visit(user_path(user))
+
+ page.within '.nav-links' do
+ expect(page).to have_link('Overview')
+ expect(page).to have_link('Activity')
+ expect(page).not_to have_link('Groups')
+ expect(page).not_to have_link('Contributed projects')
+ expect(page).not_to have_link('Personal projects')
+ expect(page).not_to have_link('Snippets')
+ end
+ end
+ end
+
+ describe 'feature flag disabled' do
+ before do
+ stub_feature_flags(security_auto_fix: false)
+ end
+
+ it 'only shows Overview and Activity tabs' do
+ visit(user_path(user))
+
+ page.within '.nav-links' do
+ expect(page).to have_link('Overview')
+ expect(page).to have_link('Activity')
+ expect(page).to have_link('Groups')
+ expect(page).to have_link('Contributed projects')
+ expect(page).to have_link('Personal projects')
+ expect(page).to have_link('Snippets')
+ end
+ end
+ end
+ end
end
diff --git a/spec/features/users/signup_spec.rb b/spec/features/users/signup_spec.rb
index 5fd0e677cd0..c59121626f0 100644
--- a/spec/features/users/signup_spec.rb
+++ b/spec/features/users/signup_spec.rb
@@ -7,6 +7,14 @@ RSpec.shared_examples 'Signup' do
let(:new_user) { build_stubbed(:user) }
+ def fill_in_signup_form
+ fill_in 'new_user_username', with: new_user.username
+ fill_in 'new_user_email', with: new_user.email
+ fill_in 'new_user_first_name', with: new_user.first_name
+ fill_in 'new_user_last_name', with: new_user.last_name
+ fill_in 'new_user_password', with: new_user.password
+ end
+
describe 'username validation', :js do
before do
visit new_user_registration_path
@@ -144,20 +152,9 @@ RSpec.shared_examples 'Signup' do
it 'creates the user account and sends a confirmation email' do
visit new_user_registration_path
- fill_in 'new_user_username', with: new_user.username
- fill_in 'new_user_email', with: new_user.email
-
- if Gitlab::Experimentation.enabled?(:signup_flow)
- fill_in 'new_user_first_name', with: new_user.first_name
- fill_in 'new_user_last_name', with: new_user.last_name
- else
- fill_in 'new_user_name', with: new_user.name
- end
-
- fill_in 'new_user_password', with: new_user.password
+ fill_in_signup_form
expect { click_button 'Register' }.to change { User.count }.by(1)
-
expect(current_path).to eq users_almost_there_path
expect(page).to have_content('Please check your email to confirm your account')
end
@@ -171,46 +168,14 @@ RSpec.shared_examples 'Signup' do
it 'creates the user account and sends a confirmation email' do
visit new_user_registration_path
- fill_in 'new_user_username', with: new_user.username
- fill_in 'new_user_email', with: new_user.email
-
- if Gitlab::Experimentation.enabled?(:signup_flow)
- fill_in 'new_user_first_name', with: new_user.first_name
- fill_in 'new_user_last_name', with: new_user.last_name
- else
- fill_in 'new_user_name', with: new_user.name
- end
-
- fill_in 'new_user_password', with: new_user.password
+ fill_in_signup_form
expect { click_button 'Register' }.to change { User.count }.by(1)
-
expect(current_path).to eq users_sign_up_welcome_path
end
end
end
- context "when sigining up with different cased emails" do
- it "creates the user successfully" do
- visit new_user_registration_path
-
- fill_in 'new_user_username', with: new_user.username
- fill_in 'new_user_email', with: new_user.email
-
- if Gitlab::Experimentation.enabled?(:signup_flow)
- fill_in 'new_user_first_name', with: new_user.first_name
- fill_in 'new_user_last_name', with: new_user.last_name
- else
- fill_in 'new_user_name', with: new_user.name
- end
-
- fill_in 'new_user_password', with: new_user.password
- click_button "Register"
-
- expect(current_path).to eq users_sign_up_welcome_path
- end
- end
-
context "when not sending confirmation email" do
before do
stub_application_setting(send_user_confirmation_email: false)
@@ -219,17 +184,7 @@ RSpec.shared_examples 'Signup' do
it 'creates the user account and goes to dashboard' do
visit new_user_registration_path
- fill_in 'new_user_username', with: new_user.username
- fill_in 'new_user_email', with: new_user.email
-
- if Gitlab::Experimentation.enabled?(:signup_flow)
- fill_in 'new_user_first_name', with: new_user.first_name
- fill_in 'new_user_last_name', with: new_user.last_name
- else
- fill_in 'new_user_name', with: new_user.name
- end
-
- fill_in 'new_user_password', with: new_user.password
+ fill_in_signup_form
click_button "Register"
expect(current_path).to eq users_sign_up_welcome_path
@@ -239,20 +194,10 @@ RSpec.shared_examples 'Signup' do
context 'with errors' do
it "displays the errors" do
- existing_user = create(:user)
-
+ create(:user, email: new_user.email)
visit new_user_registration_path
- if Gitlab::Experimentation.enabled?(:signup_flow)
- fill_in 'new_user_first_name', with: new_user.first_name
- fill_in 'new_user_last_name', with: new_user.last_name
- else
- fill_in 'new_user_name', with: new_user.name
- end
-
- fill_in 'new_user_username', with: new_user.username
- fill_in 'new_user_email', with: existing_user.email
- fill_in 'new_user_password', with: new_user.password
+ fill_in_signup_form
click_button "Register"
expect(current_path).to eq user_registration_path
@@ -261,20 +206,10 @@ RSpec.shared_examples 'Signup' do
end
it 'does not redisplay the password' do
- existing_user = create(:user)
-
+ create(:user, email: new_user.email)
visit new_user_registration_path
- if Gitlab::Experimentation.enabled?(:signup_flow)
- fill_in 'new_user_first_name', with: new_user.first_name
- fill_in 'new_user_last_name', with: new_user.last_name
- else
- fill_in 'new_user_name', with: new_user.name
- end
-
- fill_in 'new_user_username', with: new_user.username
- fill_in 'new_user_email', with: existing_user.email
- fill_in 'new_user_password', with: new_user.password
+ fill_in_signup_form
click_button "Register"
expect(current_path).to eq user_registration_path
@@ -287,45 +222,14 @@ RSpec.shared_examples 'Signup' do
enforce_terms
end
- it 'requires the user to check the checkbox' do
+ it 'renders text that the user confirms terms by clicking register' do
visit new_user_registration_path
- fill_in 'new_user_username', with: new_user.username
- fill_in 'new_user_email', with: new_user.email
-
- if Gitlab::Experimentation.enabled?(:signup_flow)
- fill_in 'new_user_first_name', with: new_user.first_name
- fill_in 'new_user_last_name', with: new_user.last_name
- else
- fill_in 'new_user_name', with: new_user.name
- end
-
- fill_in 'new_user_password', with: new_user.password
+ expect(page).to have_content(/By clicking Register, I agree that I have read and accepted the Terms of Use and Privacy Policy/)
+ fill_in_signup_form
click_button 'Register'
- expect(current_path).to eq new_user_session_path
- expect(page).to have_content(/you must accept our terms of service/i)
- end
-
- it 'asks the user to accept terms before going to the dashboard' do
- visit new_user_registration_path
-
- fill_in 'new_user_username', with: new_user.username
- fill_in 'new_user_email', with: new_user.email
-
- if Gitlab::Experimentation.enabled?(:signup_flow)
- fill_in 'new_user_first_name', with: new_user.first_name
- fill_in 'new_user_last_name', with: new_user.last_name
- else
- fill_in 'new_user_name', with: new_user.name
- end
-
- fill_in 'new_user_password', with: new_user.password
- check :terms_opt_in
-
- click_button "Register"
-
expect(current_path).to eq users_sign_up_welcome_path
end
end
@@ -353,17 +257,7 @@ RSpec.shared_examples 'Signup' do
it 'prevents from signing up' do
visit new_user_registration_path
- fill_in 'new_user_username', with: new_user.username
- fill_in 'new_user_email', with: new_user.email
-
- if Gitlab::Experimentation.enabled?(:signup_flow)
- fill_in 'new_user_first_name', with: new_user.first_name
- fill_in 'new_user_last_name', with: new_user.last_name
- else
- fill_in 'new_user_name', with: new_user.name
- end
-
- fill_in 'new_user_password', with: new_user.password
+ fill_in_signup_form
expect { click_button 'Register' }.not_to change { User.count }
expect(page).to have_content('There was an error with the reCAPTCHA. Please solve the reCAPTCHA again.')
@@ -374,17 +268,7 @@ RSpec.shared_examples 'Signup' do
it 'prevents from signing up' do
visit new_user_registration_path
- fill_in 'new_user_username', with: new_user.username
- fill_in 'new_user_email', with: new_user.email
-
- if Gitlab::Experimentation.enabled?(:signup_flow)
- fill_in 'new_user_first_name', with: new_user.first_name
- fill_in 'new_user_last_name', with: new_user.last_name
- else
- fill_in 'new_user_name', with: new_user.name
- end
-
- fill_in 'new_user_password', with: new_user.password
+ fill_in_signup_form
expect { click_button 'Register' }.not_to change { User.count }
expect(page).to have_content('That was a bit too quick! Please resubmit.')
@@ -393,36 +277,27 @@ RSpec.shared_examples 'Signup' do
end
it 'redirects to step 2 of the signup process, sets the role and redirects back' do
- new_user = build_stubbed(:user)
visit new_user_registration_path
- fill_in 'new_user_username', with: new_user.username
- fill_in 'new_user_email', with: new_user.email
-
- if Gitlab::Experimentation.enabled?(:signup_flow)
- fill_in 'new_user_first_name', with: new_user.first_name
- fill_in 'new_user_last_name', with: new_user.last_name
- else
- fill_in 'new_user_name', with: new_user.name
- end
-
- fill_in 'new_user_password', with: new_user.password
+ fill_in_signup_form
click_button 'Register'
+
visit new_project_path
expect(page).to have_current_path(users_sign_up_welcome_path)
select 'Software Developer', from: 'user_role'
click_button 'Get started!'
- new_user = User.find_by_username(new_user.username)
- expect(new_user.software_developer_role?).to be_truthy
- expect(new_user.setup_for_company).to be_nil
+ created_user = User.find_by_username(new_user.username)
+
+ expect(created_user.software_developer_role?).to be_truthy
+ expect(created_user.setup_for_company).to be_nil
expect(page).to have_current_path(new_project_path)
end
end
-RSpec.shared_examples 'Signup name validation' do |field, max_length|
+RSpec.shared_examples 'Signup name validation' do |field, max_length, label|
before do
visit new_user_registration_path
end
@@ -446,10 +321,10 @@ RSpec.shared_examples 'Signup name validation' do |field, max_length|
expect(find('.name')).to have_css '.gl-field-error-outline'
end
- it "shows an error message if the user\'s fullname is longer than #{max_length} characters" do
+ it "shows an error message if the user\'s #{label} is longer than #{max_length} characters" do
fill_in field, with: 'n' * (max_length + 1)
- expect(page).to have_content("Name is too long (maximum is #{max_length} characters).")
+ expect(page).to have_content("#{label} is too long (maximum is #{max_length} characters).")
end
it 'shows an error message if the username contains emojis' do
@@ -467,7 +342,8 @@ RSpec.describe 'With original flow' do
end
it_behaves_like 'Signup'
- it_behaves_like 'Signup name validation', 'new_user_name', 255
+ it_behaves_like 'Signup name validation', 'new_user_first_name', 127, 'First name'
+ it_behaves_like 'Signup name validation', 'new_user_last_name', 127, 'Last name'
end
RSpec.describe 'With experimental flow' do
@@ -477,30 +353,6 @@ RSpec.describe 'With experimental flow' do
end
it_behaves_like 'Signup'
- it_behaves_like 'Signup name validation', 'new_user_first_name', 127
- it_behaves_like 'Signup name validation', 'new_user_last_name', 127
-
- context 'when terms_opt_in experimental is enabled' do
- include TermsHelper
-
- before do
- enforce_terms
- stub_experiment(signup_flow: true, terms_opt_in: true)
- stub_experiment_for_user(signup_flow: true, terms_opt_in: true)
- end
-
- it 'terms are checked by default' do
- new_user = build_stubbed(:user)
-
- visit new_user_registration_path
- fill_in 'new_user_first_name', with: new_user.first_name
- fill_in 'new_user_last_name', with: new_user.last_name
- fill_in 'new_user_username', with: new_user.username
- fill_in 'new_user_email', with: new_user.email
- fill_in 'new_user_password', with: new_user.password
- click_button 'Register'
-
- expect(current_path).to eq users_sign_up_welcome_path
- end
- end
+ it_behaves_like 'Signup name validation', 'new_user_first_name', 127, 'First name'
+ it_behaves_like 'Signup name validation', 'new_user_last_name', 127, 'Last name'
end
diff --git a/spec/features/users/terms_spec.rb b/spec/features/users/terms_spec.rb
index 5275845fe5b..7500f2fe59a 100644
--- a/spec/features/users/terms_spec.rb
+++ b/spec/features/users/terms_spec.rb
@@ -26,6 +26,21 @@ RSpec.describe 'Users > Terms' do
expect(page).not_to have_content('Continue')
end
+ context 'when user is a project bot' do
+ let(:project_bot) { create(:user, :project_bot) }
+
+ before do
+ enforce_terms
+ end
+
+ it 'auto accepts the terms' do
+ visit terms_path
+
+ expect(page).not_to have_content('Accept terms')
+ expect(project_bot.terms_accepted?).to be(true)
+ end
+ end
+
context 'when signed in' do
let(:user) { create(:user) }
diff --git a/spec/finders/alert_management/alerts_finder_spec.rb b/spec/finders/alert_management/alerts_finder_spec.rb
index 926446b31d5..e74f3ac68ed 100644
--- a/spec/finders/alert_management/alerts_finder_spec.rb
+++ b/spec/finders/alert_management/alerts_finder_spec.rb
@@ -39,19 +39,19 @@ RSpec.describe AlertManagement::AlertsFinder, '#execute' do
end
context 'status given' do
- let(:params) { { status: AlertManagement::Alert::STATUSES[:resolved] } }
+ let(:params) { { status: :resolved } }
it { is_expected.to match_array(resolved_alert) }
context 'with an array of statuses' do
let(:triggered_alert) { create(:alert_management_alert) }
- let(:params) { { status: [AlertManagement::Alert::STATUSES[:resolved]] } }
+ let(:params) { { status: [:resolved] } }
it { is_expected.to match_array(resolved_alert) }
end
context 'with no alerts of status' do
- let(:params) { { status: AlertManagement::Alert::STATUSES[:acknowledged] } }
+ let(:params) { { status: :acknowledged } }
it { is_expected.to be_empty }
end
@@ -169,12 +169,6 @@ RSpec.describe AlertManagement::AlertsFinder, '#execute' do
end
context 'when sorting by status' do
- let(:statuses) { AlertManagement::Alert::STATUSES }
- let(:triggered) { statuses[:triggered] }
- let(:acknowledged) { statuses[:acknowledged] }
- let(:resolved) { statuses[:resolved] }
- let(:ignored) { statuses[:ignored] }
-
let_it_be(:alert_triggered) { create(:alert_management_alert, project: project) }
let_it_be(:alert_acknowledged) { create(:alert_management_alert, :acknowledged, project: project) }
let_it_be(:alert_resolved) { create(:alert_management_alert, :resolved, project: project) }
@@ -184,7 +178,7 @@ RSpec.describe AlertManagement::AlertsFinder, '#execute' do
let(:params) { { sort: 'status_asc' } }
it 'sorts by status: Ignored > Resolved > Acknowledged > Triggered' do
- expect(execute.map(&:status).uniq).to eq([ignored, resolved, acknowledged, triggered])
+ expect(execute.map(&:status_name).uniq).to eq([:ignored, :resolved, :acknowledged, :triggered])
end
end
@@ -192,64 +186,83 @@ RSpec.describe AlertManagement::AlertsFinder, '#execute' do
let(:params) { { sort: 'status_desc' } }
it 'sorts by status: Triggered > Acknowledged > Resolved > Ignored' do
- expect(execute.map(&:status).uniq).to eq([triggered, acknowledged, resolved, ignored])
+ expect(execute.map(&:status_name).uniq).to eq([:triggered, :acknowledged, :resolved, :ignored])
end
end
end
end
- end
- context 'search query given' do
- let_it_be(:alert) do
- create(:alert_management_alert,
- :with_fingerprint,
- title: 'Title',
- description: 'Desc',
- service: 'Service',
- monitoring_tool: 'Monitor'
- )
- end
+ context 'search query given' do
+ let_it_be(:alert) do
+ create(:alert_management_alert,
+ :with_fingerprint,
+ project: project,
+ title: 'Title',
+ description: 'Desc',
+ service: 'Service',
+ monitoring_tool: 'Monitor'
+ )
+ end
- before do
- alert.project.add_developer(current_user)
- end
+ context 'searching title' do
+ let(:params) { { search: alert.title } }
- subject { described_class.new(current_user, alert.project, params).execute }
+ it { is_expected.to match_array([alert]) }
+ end
- context 'searching title' do
- let(:params) { { search: alert.title } }
+ context 'searching description' do
+ let(:params) { { search: alert.description } }
- it { is_expected.to match_array([alert]) }
- end
+ it { is_expected.to match_array([alert]) }
+ end
- context 'searching description' do
- let(:params) { { search: alert.description } }
+ context 'searching service' do
+ let(:params) { { search: alert.service } }
- it { is_expected.to match_array([alert]) }
- end
+ it { is_expected.to match_array([alert]) }
+ end
- context 'searching service' do
- let(:params) { { search: alert.service } }
+ context 'searching monitoring tool' do
+ let(:params) { { search: alert.monitoring_tool } }
- it { is_expected.to match_array([alert]) }
- end
+ it { is_expected.to match_array([alert]) }
+ end
- context 'searching monitoring tool' do
- let(:params) { { search: alert.monitoring_tool } }
+ context 'searching something else' do
+ let(:params) { { search: alert.fingerprint } }
- it { is_expected.to match_array([alert]) }
- end
+ it { is_expected.to be_empty }
+ end
- context 'searching something else' do
- let(:params) { { search: alert.fingerprint } }
+ context 'empty search' do
+ let(:params) { { search: ' ' } }
- it { is_expected.to be_empty }
+ it { is_expected.not_to include(alert) }
+ end
end
- context 'empty search' do
- let(:params) { { search: ' ' } }
+ context 'assignee username given' do
+ let_it_be(:assignee) { create(:user) }
+ let_it_be(:alert) { create(:alert_management_alert, project: project, assignees: [assignee]) }
+ let(:params) { { assignee_username: username } }
+
+ context 'with valid assignee_username' do
+ let(:username) { assignee.username }
+
+ it { is_expected.to match_array([alert]) }
+ end
- it { is_expected.to match_array([alert]) }
+ context 'with invalid assignee_username' do
+ let(:username) { 'unknown username' }
+
+ it { is_expected.to be_empty }
+ end
+
+ context 'with empty assignee_username' do
+ let(:username) { ' ' }
+
+ it { is_expected.not_to include(alert) }
+ end
end
end
end
@@ -261,12 +274,12 @@ RSpec.describe AlertManagement::AlertsFinder, '#execute' do
project.add_developer(current_user)
end
- it { is_expected.to match({ 2 => 1, 3 => 1 }) } # one resolved and one ignored
+ it { is_expected.to match(resolved: 1, ignored: 1) }
context 'when filtering params are included' do
- let(:params) { { status: AlertManagement::Alert::STATUSES[:resolved] } }
+ let(:params) { { status: :resolved } }
- it { is_expected.to match({ 2 => 1 }) } # one resolved
+ it { is_expected.to match(resolved: 1) }
end
end
end
diff --git a/spec/finders/ci/pipelines_for_merge_request_finder_spec.rb b/spec/finders/ci/pipelines_for_merge_request_finder_spec.rb
index 196fde5efe0..65f6dc0ba74 100644
--- a/spec/finders/ci/pipelines_for_merge_request_finder_spec.rb
+++ b/spec/finders/ci/pipelines_for_merge_request_finder_spec.rb
@@ -122,7 +122,7 @@ RSpec.describe Ci::PipelinesForMergeRequestFinder do
end
context 'with unsaved merge request' do
- let(:merge_request) { build(:merge_request) }
+ let(:merge_request) { build(:merge_request, source_project: create(:project, :repository)) }
let!(:pipeline) do
create(:ci_empty_pipeline, project: project,
diff --git a/spec/finders/environment_names_finder_spec.rb b/spec/finders/environment_names_finder_spec.rb
new file mode 100644
index 00000000000..9244e4fb369
--- /dev/null
+++ b/spec/finders/environment_names_finder_spec.rb
@@ -0,0 +1,63 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe EnvironmentNamesFinder do
+ describe '#execute' do
+ let!(:group) { create(:group) }
+ let!(:project1) { create(:project, :public, namespace: group) }
+ let!(:project2) { create(:project, :private, namespace: group) }
+ let!(:user) { create(:user) }
+
+ before do
+ create(:environment, name: 'gstg', project: project1)
+ create(:environment, name: 'gprd', project: project1)
+ create(:environment, name: 'gprd', project: project2)
+ create(:environment, name: 'gcny', project: project2)
+ end
+
+ context 'using a group and a group member' do
+ it 'returns environment names for all projects' do
+ group.add_developer(user)
+
+ names = described_class.new(group, user).execute
+
+ expect(names).to eq(%w[gcny gprd gstg])
+ end
+ end
+
+ context 'using a group and a guest' do
+ it 'returns environment names for all public projects' do
+ names = described_class.new(group, user).execute
+
+ expect(names).to eq(%w[gprd gstg])
+ end
+ end
+
+ context 'using a public project and a project member' do
+ it 'returns all the unique environment names' do
+ project1.team.add_developer(user)
+
+ names = described_class.new(project1, user).execute
+
+ expect(names).to eq(%w[gprd gstg])
+ end
+ end
+
+ context 'using a public project and a guest' do
+ it 'returns all the unique environment names' do
+ names = described_class.new(project1, user).execute
+
+ expect(names).to eq(%w[gprd gstg])
+ end
+ end
+
+ context 'using a private project and a guest' do
+ it 'returns all the unique environment names' do
+ names = described_class.new(project2, user).execute
+
+ expect(names).to be_empty
+ end
+ end
+ end
+end
diff --git a/spec/finders/group_labels_finder_spec.rb b/spec/finders/group_labels_finder_spec.rb
deleted file mode 100644
index d65a8fb4fed..00000000000
--- a/spec/finders/group_labels_finder_spec.rb
+++ /dev/null
@@ -1,42 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe GroupLabelsFinder, '#execute' do
- let!(:group) { create(:group) }
- let!(:user) { create(:user) }
- let!(:label1) { create(:group_label, title: 'Foo', description: 'Lorem ipsum', group: group) }
- let!(:label2) { create(:group_label, title: 'Bar', description: 'Fusce consequat', group: group) }
-
- it 'returns all group labels sorted by name if no params' do
- result = described_class.new(user, group).execute
-
- expect(result.to_a).to match_array([label2, label1])
- end
-
- it 'returns all group labels sorted by name desc' do
- result = described_class.new(user, group, sort: 'name_desc').execute
-
- expect(result.to_a).to match_array([label2, label1])
- end
-
- it 'returns group labels that match search' do
- result = described_class.new(user, group, search: 'Foo').execute
-
- expect(result.to_a).to match_array([label1])
- end
-
- it 'returns group labels user subscribed to' do
- label2.subscribe(user)
-
- result = described_class.new(user, group, subscribed: 'true').execute
-
- expect(result.to_a).to match_array([label2])
- end
-
- it 'returns second page of labels' do
- result = described_class.new(user, group, page: '2').execute
-
- expect(result.to_a).to match_array([])
- end
-end
diff --git a/spec/finders/groups_finder_spec.rb b/spec/finders/groups_finder_spec.rb
index 48e4c5dadc9..c9e9328794e 100644
--- a/spec/finders/groups_finder_spec.rb
+++ b/spec/finders/groups_finder_spec.rb
@@ -161,5 +161,61 @@ RSpec.describe GroupsFinder do
end
end
end
+
+ context 'with include parent group descendants' do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:parent_group) { create(:group, :public) }
+ let_it_be(:public_subgroup) { create(:group, :public, parent: parent_group) }
+ let_it_be(:internal_sub_subgroup) { create(:group, :internal, parent: public_subgroup) }
+ let_it_be(:private_sub_subgroup) { create(:group, :private, parent: public_subgroup) }
+ let_it_be(:public_sub_subgroup) { create(:group, :public, parent: public_subgroup) }
+ let(:params) { { include_parent_descendants: true, parent: parent_group } }
+
+ context 'with nil parent' do
+ it 'returns all accessible groups' do
+ params[:parent] = nil
+ expect(described_class.new(user, params).execute).to contain_exactly(
+ parent_group,
+ public_subgroup,
+ internal_sub_subgroup,
+ public_sub_subgroup
+ )
+ end
+ end
+
+ context 'without a user' do
+ it 'only returns the group public descendants' do
+ expect(described_class.new(nil, params).execute).to contain_exactly(
+ public_subgroup,
+ public_sub_subgroup
+ )
+ end
+ end
+
+ context 'when a user is present' do
+ it 'returns the group public and internal descendants' do
+ expect(described_class.new(user, params).execute).to contain_exactly(
+ public_subgroup,
+ public_sub_subgroup,
+ internal_sub_subgroup
+ )
+ end
+ end
+
+ context 'when a parent group member is present' do
+ before do
+ parent_group.add_developer(user)
+ end
+
+ it 'returns all group descendants' do
+ expect(described_class.new(user, params).execute).to contain_exactly(
+ public_subgroup,
+ public_sub_subgroup,
+ internal_sub_subgroup,
+ private_sub_subgroup
+ )
+ end
+ end
+ end
end
end
diff --git a/spec/finders/issues_finder_spec.rb b/spec/finders/issues_finder_spec.rb
index dbf5abe64a5..21bc03011c3 100644
--- a/spec/finders/issues_finder_spec.rb
+++ b/spec/finders/issues_finder_spec.rb
@@ -843,6 +843,16 @@ RSpec.describe IssuesFinder do
expect(finder.row_count).to be_zero
end
+
+ it 'returns -1 if the query times out' do
+ finder = described_class.new(admin)
+
+ expect_next_instance_of(described_class) do |subfinder|
+ expect(subfinder).to receive(:execute).and_raise(ActiveRecord::QueryCanceled)
+ end
+
+ expect(finder.row_count).to eq(-1)
+ end
end
describe '#with_confidentiality_access_check' do
diff --git a/spec/finders/labels_finder_spec.rb b/spec/finders/labels_finder_spec.rb
index 851b9e64db6..e344591dd5d 100644
--- a/spec/finders/labels_finder_spec.rb
+++ b/spec/finders/labels_finder_spec.rb
@@ -42,7 +42,7 @@ RSpec.describe LabelsFinder do
finder = described_class.new(user)
- expect(finder.execute).to eq [group_label_2, group_label_3, project_label_1, group_label_1, project_label_2, project_label_4]
+ expect(finder.execute).to match_array([group_label_2, group_label_3, project_label_1, group_label_1, project_label_2, project_label_4])
end
it 'returns labels available if nil title is supplied' do
@@ -50,7 +50,7 @@ RSpec.describe LabelsFinder do
# params[:title] will return `nil` regardless whether it is specified
finder = described_class.new(user, title: nil)
- expect(finder.execute).to eq [group_label_2, group_label_3, project_label_1, group_label_1, project_label_2, project_label_4]
+ expect(finder.execute).to match_array([group_label_2, group_label_3, project_label_1, group_label_1, project_label_2, project_label_4])
end
end
@@ -60,7 +60,7 @@ RSpec.describe LabelsFinder do
::Projects::UpdateService.new(project_1, user, archived: true).execute
finder = described_class.new(user, **group_params(group_1))
- expect(finder.execute).to eq [group_label_2, group_label_1, project_label_5]
+ expect(finder.execute).to match_array([group_label_2, group_label_1, project_label_5])
end
context 'when only_group_labels is true' do
@@ -69,7 +69,7 @@ RSpec.describe LabelsFinder do
finder = described_class.new(user, only_group_labels: true, **group_params(group_1))
- expect(finder.execute).to eq [group_label_2, group_label_1]
+ expect(finder.execute).to match_array([group_label_2, group_label_1])
end
end
@@ -86,7 +86,7 @@ RSpec.describe LabelsFinder do
it 'returns group labels' do
finder = described_class.new(user, **group_params(empty_group))
- expect(finder.execute).to eq [empty_group_label_1, empty_group_label_2]
+ expect(finder.execute).to match_array([empty_group_label_1, empty_group_label_2])
end
end
end
@@ -98,7 +98,7 @@ RSpec.describe LabelsFinder do
finder = described_class.new(user, **group_params(private_subgroup_1), only_group_labels: true, include_ancestor_groups: true)
- expect(finder.execute).to eq [private_group_label_1, private_subgroup_label_1]
+ expect(finder.execute).to match_array([private_group_label_1, private_subgroup_label_1])
end
it 'ignores labels from groups which user can not read' do
@@ -106,7 +106,7 @@ RSpec.describe LabelsFinder do
finder = described_class.new(user, **group_params(private_subgroup_1), only_group_labels: true, include_ancestor_groups: true)
- expect(finder.execute).to eq [private_subgroup_label_1]
+ expect(finder.execute).to match_array([private_subgroup_label_1])
end
end
@@ -117,7 +117,7 @@ RSpec.describe LabelsFinder do
finder = described_class.new(user, **group_params(private_group_1), only_group_labels: true, include_descendant_groups: true)
- expect(finder.execute).to eq [private_group_label_1, private_subgroup_label_1]
+ expect(finder.execute).to match_array([private_group_label_1, private_subgroup_label_1])
end
it 'ignores labels from groups which user can not read' do
@@ -125,7 +125,7 @@ RSpec.describe LabelsFinder do
finder = described_class.new(user, **group_params(private_group_1), only_group_labels: true, include_descendant_groups: true)
- expect(finder.execute).to eq [private_subgroup_label_1]
+ expect(finder.execute).to match_array([private_subgroup_label_1])
end
end
@@ -140,13 +140,13 @@ RSpec.describe LabelsFinder do
shared_examples 'with full visibility' do
it 'returns all projects labels' do
- expect(finder.execute).to eq [group_label_1, limited_visibility_label, visible_label]
+ expect(finder.execute).to match_array([group_label_1, limited_visibility_label, visible_label])
end
end
shared_examples 'with limited visibility' do
it 'returns only authorized projects labels' do
- expect(finder.execute).to eq [group_label_1, visible_label]
+ expect(finder.execute).to match_array([group_label_1, visible_label])
end
end
@@ -249,7 +249,7 @@ RSpec.describe LabelsFinder do
it 'returns labels available for the project' do
finder = described_class.new(user, project_id: project_1.id)
- expect(finder.execute).to eq [group_label_2, project_label_1, group_label_1]
+ expect(finder.execute).to match_array([group_label_2, project_label_1, group_label_1])
end
context 'as an administrator' do
@@ -272,13 +272,13 @@ RSpec.describe LabelsFinder do
it 'returns label with that title' do
finder = described_class.new(user, title: 'Group Label 2')
- expect(finder.execute).to eq [group_label_2]
+ expect(finder.execute).to match_array([group_label_2])
end
it 'returns label with title alias' do
finder = described_class.new(user, name: 'Group Label 2')
- expect(finder.execute).to eq [group_label_2]
+ expect(finder.execute).to match_array([group_label_2])
end
it 'returns no labels if empty title is supplied' do
@@ -304,19 +304,19 @@ RSpec.describe LabelsFinder do
it 'returns labels with a partially matching title' do
finder = described_class.new(user, search: '(group)')
- expect(finder.execute).to eq [group_label_1]
+ expect(finder.execute).to match_array([group_label_1])
end
it 'returns labels with a partially matching description' do
finder = described_class.new(user, search: 'awesome')
- expect(finder.execute).to eq [project_label_1]
+ expect(finder.execute).to match_array([project_label_1])
end
it 'returns labels matching a single character' do
finder = described_class.new(user, search: '(')
- expect(finder.execute).to eq [group_label_1]
+ expect(finder.execute).to match_array([group_label_1])
end
end
@@ -326,7 +326,7 @@ RSpec.describe LabelsFinder do
finder = described_class.new(user, subscribed: 'true')
- expect(finder.execute).to eq [project_label_1]
+ expect(finder.execute).to match_array([project_label_1])
end
end
diff --git a/spec/finders/merge_requests/by_approvals_finder_spec.rb b/spec/finders/merge_requests/by_approvals_finder_spec.rb
new file mode 100644
index 00000000000..0e1856879f1
--- /dev/null
+++ b/spec/finders/merge_requests/by_approvals_finder_spec.rb
@@ -0,0 +1,82 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe MergeRequests::ByApprovalsFinder do
+ let_it_be(:first_user) { create(:user) }
+ let_it_be(:second_user) { create(:user) }
+ let(:third_user) { create(:user) }
+
+ let_it_be(:merge_request_without_approvals) { create(:merge_request) }
+ let_it_be(:merge_request_with_first_user_approval) do
+ create(:merge_request).tap do |mr|
+ create(:approval, merge_request: mr, user: first_user)
+ end
+ end
+ let_it_be(:merge_request_with_both_approvals) do
+ create(:merge_request).tap do |mr|
+ create(:approval, merge_request: mr, user: first_user)
+ create(:approval, merge_request: mr, user: second_user)
+ end
+ end
+
+ def merge_requests(ids: nil, names: [])
+ described_class.new(names, ids).execute(MergeRequest.all)
+ end
+
+ context 'filter by no approvals' do
+ it 'returns merge requests without approvals' do
+ expected_result = [merge_request_without_approvals]
+
+ expect(merge_requests(ids: 'None')).to match_array(expected_result)
+ expect(merge_requests(names: ['None'])).to match_array(expected_result)
+ end
+ end
+
+ context 'filter by any approvals' do
+ it 'returns merge requests approved by at least one user' do
+ expected_result = [merge_request_with_first_user_approval, merge_request_with_both_approvals]
+
+ expect(merge_requests(ids: 'Any')).to match_array(expected_result)
+ expect(merge_requests(names: ['Any'])).to match_array(expected_result)
+ end
+ end
+
+ context 'filter by specific user approval' do
+ it 'returns merge requests approved by specific user' do
+ expected_result = [merge_request_with_first_user_approval, merge_request_with_both_approvals]
+
+ expect(merge_requests(ids: [first_user.id])).to match_array(expected_result)
+ expect(merge_requests(names: [first_user.username])).to match_array(expected_result)
+ end
+ end
+
+ context 'filter by multiple user approval' do
+ it 'returns merge requests approved by both users' do
+ expected_result = [merge_request_with_both_approvals]
+
+ expect(merge_requests(ids: [first_user.id, second_user.id])).to match_array(expected_result)
+ expect(merge_requests(names: [first_user.username, second_user.username])).to match_array(expected_result)
+ end
+
+ context 'limiting max conditional elements' do
+ it 'returns merge requests approved by both users, considering limit of 2 being defined' do
+ stub_const('MergeRequests::ByApprovalsFinder::MAX_FILTER_ELEMENTS', 2)
+
+ expected_result = [merge_request_with_both_approvals]
+
+ expect(merge_requests(ids: [first_user.id, second_user.id, third_user.id])).to match_array(expected_result)
+ expect(merge_requests(names: [first_user.username, second_user.username, third_user.username])).to match_array(expected_result)
+ end
+ end
+ end
+
+ context 'with empty params' do
+ it 'returns all merge requests' do
+ expected_result = [merge_request_without_approvals, merge_request_with_first_user_approval, merge_request_with_both_approvals]
+
+ expect(merge_requests(ids: [])).to match_array(expected_result)
+ expect(merge_requests(names: [])).to match_array(expected_result)
+ end
+ end
+end
diff --git a/spec/finders/merge_requests_finder_spec.rb b/spec/finders/merge_requests_finder_spec.rb
index 4f86323c7c6..68958e37001 100644
--- a/spec/finders/merge_requests_finder_spec.rb
+++ b/spec/finders/merge_requests_finder_spec.rb
@@ -486,6 +486,83 @@ RSpec.describe MergeRequestsFinder do
expect(merge_requests).to contain_exactly(old_merge_request, new_merge_request)
end
end
+
+ context 'filtering by the merge request deployments' do
+ let(:gstg) { create(:environment, project: project4, name: 'gstg') }
+ let(:gprd) { create(:environment, project: project4, name: 'gprd') }
+
+ let(:mr1) do
+ create(
+ :merge_request,
+ :simple,
+ :merged,
+ author: user,
+ source_project: project4,
+ target_project: project4
+ )
+ end
+
+ let(:mr2) do
+ create(
+ :merge_request,
+ :simple,
+ :merged,
+ author: user,
+ source_project: project4,
+ target_project: project4
+ )
+ end
+
+ let(:deploy1) do
+ create(
+ :deployment,
+ :success,
+ deployable: nil,
+ environment: gstg,
+ project: project4,
+ sha: mr1.diff_head_sha,
+ finished_at: Time.utc(2020, 10, 1, 12, 0)
+ )
+ end
+
+ let(:deploy2) do
+ create(
+ :deployment,
+ :success,
+ deployable: nil,
+ environment: gprd,
+ project: project4,
+ sha: mr2.diff_head_sha,
+ finished_at: Time.utc(2020, 10, 2, 15, 0)
+ )
+ end
+
+ before do
+ deploy1.link_merge_requests(MergeRequest.where(id: mr1.id))
+ deploy2.link_merge_requests(MergeRequest.where(id: mr2.id))
+ end
+
+ it 'filters merge requests deployed to a given environment' do
+ mrs = described_class.new(user, environment: 'gstg').execute
+
+ expect(mrs).to eq([mr1])
+ end
+
+ it 'filters merge requests deployed before a given date' do
+ mrs =
+ described_class.new(user, deployed_before: '2020-10-02').execute
+
+ expect(mrs).to eq([mr1])
+ end
+
+ it 'filters merge requests deployed after a given date' do
+ mrs = described_class
+ .new(user, deployed_after: '2020-10-01 12:00')
+ .execute
+
+ expect(mrs).to eq([mr2])
+ end
+ end
end
describe '#row_count', :request_store do
@@ -500,6 +577,16 @@ RSpec.describe MergeRequestsFinder do
expect(finder.row_count).to eq(1)
end
+
+ it 'returns -1 if the query times out' do
+ finder = described_class.new(user)
+
+ expect_next_instance_of(described_class) do |subfinder|
+ expect(subfinder).to receive(:execute).and_raise(ActiveRecord::QueryCanceled)
+ end
+
+ expect(finder.row_count).to eq(-1)
+ end
end
context 'external authorization' do
diff --git a/spec/finders/packages/generic/package_finder_spec.rb b/spec/finders/packages/generic/package_finder_spec.rb
new file mode 100644
index 00000000000..ed34268e7a9
--- /dev/null
+++ b/spec/finders/packages/generic/package_finder_spec.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe ::Packages::Generic::PackageFinder do
+ let_it_be(:project) { create(:project) }
+ let_it_be(:package) { create(:generic_package, project: project) }
+
+ describe '#execute!' do
+ subject(:finder) { described_class.new(project) }
+
+ it 'finds package by name and version' do
+ found_package = finder.execute!(package.name, package.version)
+
+ expect(found_package).to eq(package)
+ end
+
+ it 'ignores packages with same name but different version' do
+ create(:generic_package, project: project, name: package.name, version: '3.1.4')
+
+ found_package = finder.execute!(package.name, package.version)
+
+ expect(found_package).to eq(package)
+ end
+
+ it 'raises ActiveRecord::RecordNotFound if package is not found' do
+ expect { finder.execute!(package.name, '3.1.4') }
+ .to raise_error(ActiveRecord::RecordNotFound)
+ end
+ end
+end
diff --git a/spec/finders/projects_finder_spec.rb b/spec/finders/projects_finder_spec.rb
index 8ae19757c25..2d712bd44ce 100644
--- a/spec/finders/projects_finder_spec.rb
+++ b/spec/finders/projects_finder_spec.rb
@@ -31,6 +31,10 @@ RSpec.describe ProjectsFinder, :do_not_mock_admin_mode do
let(:use_cte) { true }
let(:finder) { described_class.new(params: params.merge(use_cte: use_cte), current_user: current_user, project_ids_relation: project_ids_relation) }
+ before do
+ stub_feature_flags(project_finder_similarity_sort: false)
+ end
+
subject { finder.execute }
shared_examples 'ProjectFinder#execute examples' do
@@ -304,9 +308,33 @@ RSpec.describe ProjectsFinder, :do_not_mock_admin_mode do
end
describe 'sorting' do
- let(:params) { { sort: 'name_asc' } }
+ context 'when sorting by a field' do
+ let(:params) { { sort: 'name_asc' } }
+
+ it { is_expected.to eq([internal_project, public_project]) }
+ end
- it { is_expected.to eq([internal_project, public_project]) }
+ context 'when sorting by similarity' do
+ let(:params) { { sort: 'similarity', search: 'pro' } }
+
+ let_it_be(:internal_project2) do
+ create(:project, :internal, group: group, name: 'projA', path: 'projA')
+ end
+
+ let_it_be(:internal_project3) do
+ create(:project, :internal, group: group, name: 'projABC', path: 'projABC')
+ end
+
+ let_it_be(:internal_project4) do
+ create(:project, :internal, group: group, name: 'projAB', path: 'projAB')
+ end
+
+ before do
+ stub_feature_flags(project_finder_similarity_sort: true)
+ end
+
+ it { is_expected.to eq([internal_project2, internal_project4, internal_project3]) }
+ end
end
describe 'with admin user' do
diff --git a/spec/finders/releases_finder_spec.rb b/spec/finders/releases_finder_spec.rb
index e8049a9eb81..94b6fe53daa 100644
--- a/spec/finders/releases_finder_spec.rb
+++ b/spec/finders/releases_finder_spec.rb
@@ -77,6 +77,34 @@ RSpec.describe ReleasesFinder do
expect(subject).to eq([v1_1_0, v1_0_0])
end
+ context 'with sorting parameters' do
+ before do
+ v1_1_0.update_attribute(:created_at, 3.days.ago)
+ end
+
+ context 'by default is released_at in descending order' do
+ it { is_expected.to eq([v1_1_0, v1_0_0]) }
+ end
+
+ context 'released_at in ascending order' do
+ let(:params) { { sort: 'asc' } }
+
+ it { is_expected.to eq([v1_0_0, v1_1_0]) }
+ end
+
+ context 'order by created_at in descending order' do
+ let(:params) { { order_by: 'created_at' } }
+
+ it { is_expected.to eq([v1_0_0, v1_1_0]) }
+ end
+
+ context 'order by created_at in ascending order' do
+ let(:params) { { order_by: 'created_at', sort: 'asc' } }
+
+ it { is_expected.to eq([v1_1_0, v1_0_0]) }
+ end
+ end
+
it_behaves_like 'preload'
it_behaves_like 'when tag is nil'
it_behaves_like 'when a tag parameter is passed'
diff --git a/spec/fixtures/api/schemas/entities/group_group_link.json b/spec/fixtures/api/schemas/entities/group_group_link.json
index 4c9aae140d2..bf94bbb3ce4 100644
--- a/spec/fixtures/api/schemas/entities/group_group_link.json
+++ b/spec/fixtures/api/schemas/entities/group_group_link.json
@@ -1,10 +1,20 @@
{
"type": "object",
- "required": ["id", "created_at", "expires_at", "access_level"],
+ "required": [
+ "id",
+ "created_at",
+ "expires_at",
+ "can_update",
+ "can_remove",
+ "access_level",
+ "valid_roles"
+ ],
"properties": {
"id": { "type": "integer" },
"created_at": { "type": "date-time" },
"expires_at": { "type": ["date-time", "null"] },
+ "can_update": { "type": "boolean" },
+ "can_remove": { "type": "boolean" },
"access_level": {
"type": "object",
"required": ["integer_value", "string_value"],
@@ -13,6 +23,7 @@
"string_value": { "type": "string" }
}
},
+ "valid_roles": { "type": "object" },
"shared_with_group": {
"type": "object",
"required": ["id", "name", "full_name", "full_path", "avatar_url", "web_url"],
diff --git a/spec/fixtures/api/schemas/entities/merge_request_basic.json b/spec/fixtures/api/schemas/entities/merge_request_basic.json
index 3c19528d71b..b061176f6a7 100644
--- a/spec/fixtures/api/schemas/entities/merge_request_basic.json
+++ b/spec/fixtures/api/schemas/entities/merge_request_basic.json
@@ -1,6 +1,7 @@
{
"type": "object",
"properties" : {
+ "title": { "type": "string" },
"state": { "type": "string" },
"merge_status": { "type": "string" },
"source_branch_exists": { "type": "boolean" },
diff --git a/spec/fixtures/api/schemas/entities/test_case.json b/spec/fixtures/api/schemas/entities/test_case.json
index 0dd3c5d472f..d731d7eed0a 100644
--- a/spec/fixtures/api/schemas/entities/test_case.json
+++ b/spec/fixtures/api/schemas/entities/test_case.json
@@ -8,6 +8,7 @@
"status": { "type": "string" },
"name": { "type": "string" },
"classname": { "type": "string" },
+ "file": { "type": ["string", "null"] },
"execution_time": { "type": "float" },
"system_output": { "type": ["string", "null"] },
"stack_trace": { "type": ["string", "null"] },
diff --git a/spec/fixtures/api/schemas/entities/trigger.json b/spec/fixtures/api/schemas/entities/trigger.json
new file mode 100644
index 00000000000..5c46142673f
--- /dev/null
+++ b/spec/fixtures/api/schemas/entities/trigger.json
@@ -0,0 +1,39 @@
+{
+ "type": "object",
+ "required": [
+ "description",
+ "owner",
+ "last_used",
+ "has_token_exposed",
+ "token",
+ "can_access_project"
+ ],
+ "properties": {
+ "description": {
+ "type": ["string", "null"]
+ },
+ "owner": {
+ "type": "object",
+ "$ref": "user.json"
+ },
+ "last_used": {
+ "type": ["datetime", "null"]
+ },
+ "token": {
+ "type": "string"
+ },
+ "has_token_exposed": {
+ "type": "boolean"
+ },
+ "can_access_project": {
+ "type": "boolean"
+ },
+ "edit_project_trigger_path": {
+ "type": "string"
+ },
+ "project_trigger_path": {
+ "type": "string"
+ }
+ },
+ "additionalProperties": false
+}
diff --git a/spec/fixtures/api/schemas/environment.json b/spec/fixtures/api/schemas/environment.json
index d1274bea817..7c49b269994 100644
--- a/spec/fixtures/api/schemas/environment.json
+++ b/spec/fixtures/api/schemas/environment.json
@@ -41,8 +41,11 @@
{ "type": "null" },
{ "$ref": "deployment.json" },
{
- "name": { "type": "string" },
- "build_path": { "type": "string" }
+ "type": "object",
+ "properties" : {
+ "name": { "type": "string" },
+ "build_path": { "type": "string" }
+ }
}
]
},
diff --git a/spec/fixtures/api/schemas/feature_flag.json b/spec/fixtures/api/schemas/feature_flag.json
new file mode 100644
index 00000000000..5f8cedc1132
--- /dev/null
+++ b/spec/fixtures/api/schemas/feature_flag.json
@@ -0,0 +1,23 @@
+{
+ "type": "object",
+ "required" : [
+ "id",
+ "name"
+ ],
+ "properties" : {
+ "id": { "type": "integer" },
+ "iid": { "type": ["integer", "null"] },
+ "version": { "type": "string" },
+ "created_at": { "type": "date" },
+ "updated_at": { "type": "date" },
+ "name": { "type": "string" },
+ "active": { "type": "boolean" },
+ "description": { "type": ["string", "null"] },
+ "edit_path": { "type": ["string", "null"] },
+ "update_path": { "type": ["string", "null"] },
+ "destroy_path": { "type": ["string", "null"] },
+ "scopes": { "type": "array", "items": { "$ref": "feature_flag_scope.json" } },
+ "strategies": { "type": "array", "items": { "$ref": "feature_flag_strategy.json" } }
+ },
+ "additionalProperties": false
+}
diff --git a/spec/fixtures/api/schemas/feature_flag_scope.json b/spec/fixtures/api/schemas/feature_flag_scope.json
new file mode 100644
index 00000000000..07c5eed532a
--- /dev/null
+++ b/spec/fixtures/api/schemas/feature_flag_scope.json
@@ -0,0 +1,18 @@
+{
+ "type": "object",
+ "required" : [
+ "id",
+ "environment_scope",
+ "active"
+ ],
+ "properties" : {
+ "id": { "type": "integer" },
+ "environment_scope": { "type": "string" },
+ "active": { "type": "boolean" },
+ "percentage": { "type": ["integer", "null"] },
+ "created_at": { "type": "date" },
+ "updated_at": { "type": "date" },
+ "strategies": { "type": "array", "items": { "$ref": "feature_flag_strategy.json" } }
+ },
+ "additionalProperties": false
+}
diff --git a/spec/fixtures/api/schemas/feature_flag_strategy.json b/spec/fixtures/api/schemas/feature_flag_strategy.json
new file mode 100644
index 00000000000..5a2777dc8ea
--- /dev/null
+++ b/spec/fixtures/api/schemas/feature_flag_strategy.json
@@ -0,0 +1,13 @@
+{
+ "type": "object",
+ "required": [
+ "name"
+ ],
+ "properties": {
+ "name": { "type": "string" },
+ "parameters": {
+ "type": "object"
+ }
+ },
+ "additionalProperties": false
+}
diff --git a/spec/fixtures/api/schemas/feature_flags.json b/spec/fixtures/api/schemas/feature_flags.json
new file mode 100644
index 00000000000..fc5e668c8b0
--- /dev/null
+++ b/spec/fixtures/api/schemas/feature_flags.json
@@ -0,0 +1,13 @@
+{
+ "required": ["feature_flags", "count"],
+ "feature_flags": { "type": "array", "items": { "$ref": "feature_flag.json" } },
+ "count": {
+ "type": "object",
+ "properties" : {
+ "all": { "type": "integer" },
+ "enabled": { "type": "integer" },
+ "disabled": { "type": "integer" }
+ },
+ "additionalProperties": false
+ }
+}
diff --git a/spec/fixtures/api/schemas/feature_flags_client_token.json b/spec/fixtures/api/schemas/feature_flags_client_token.json
new file mode 100644
index 00000000000..115db422d12
--- /dev/null
+++ b/spec/fixtures/api/schemas/feature_flags_client_token.json
@@ -0,0 +1,10 @@
+{
+ "type": "object",
+ "required" : [
+ "token"
+ ],
+ "properties" : {
+ "token": { "type": ["string"] }
+ },
+ "additionalProperties": false
+}
diff --git a/spec/fixtures/api/schemas/group_member.json b/spec/fixtures/api/schemas/group_member.json
index 035c862d229..3425108e46e 100644
--- a/spec/fixtures/api/schemas/group_member.json
+++ b/spec/fixtures/api/schemas/group_member.json
@@ -7,9 +7,9 @@
"access_level",
"requested_at",
"source",
+ "valid_roles",
"can_update",
- "can_remove",
- "can_override"
+ "can_remove"
],
"properties": {
"id": { "type": "integer" },
@@ -18,7 +18,6 @@
"requested_at": { "type": ["date-time", "null"] },
"can_update": { "type": "boolean" },
"can_remove": { "type": "boolean" },
- "can_override": { "type": "boolean" },
"access_level": {
"type": "object",
"required": ["integer_value", "string_value"],
@@ -36,6 +35,7 @@
"web_url": { "type": "string" }
}
},
+ "valid_roles": { "type": "object" },
"created_by": {
"type": "object",
"required": ["name", "web_url"],
@@ -62,7 +62,18 @@
"avatar_url": { "type": ["string", "null"] },
"web_url": { "type": "string" },
"blocked": { "type": "boolean" },
- "two_factor_enabled": { "type": "boolean" }
+ "two_factor_enabled": { "type": "boolean" },
+ "status": {
+ "type": "object",
+ "required": [
+ "emoji",
+ "message_html"
+ ],
+ "properties": {
+ "emoji": { "type": "string" },
+ "message_html": { "type": "string" }
+ }
+ }
}
},
"invite": {
diff --git a/spec/fixtures/api/schemas/public_api/v4/feature_flag.json b/spec/fixtures/api/schemas/public_api/v4/feature_flag.json
new file mode 100644
index 00000000000..0f304e9ee73
--- /dev/null
+++ b/spec/fixtures/api/schemas/public_api/v4/feature_flag.json
@@ -0,0 +1,15 @@
+{
+ "type": "object",
+ "required": ["name"],
+ "properties": {
+ "name": { "type": "string" },
+ "description": { "type": ["string", "null"] },
+ "active": {"type": "boolean" },
+ "version": { "type": "string" },
+ "created_at": { "type": "date" },
+ "updated_at": { "type": "date" },
+ "scopes": { "type": "array", "items": { "$ref": "feature_flag_scope.json" } },
+ "strategies": { "type": "array", "items": { "$ref": "operations/strategy.json" } }
+ },
+ "additionalProperties": false
+}
diff --git a/spec/fixtures/api/schemas/public_api/v4/feature_flag_detailed_scopes.json b/spec/fixtures/api/schemas/public_api/v4/feature_flag_detailed_scopes.json
new file mode 100644
index 00000000000..a11ae5705cc
--- /dev/null
+++ b/spec/fixtures/api/schemas/public_api/v4/feature_flag_detailed_scopes.json
@@ -0,0 +1,22 @@
+{
+ "type": "array",
+ "items": {
+ "type": "object",
+ "required" : [
+ "name",
+ "id",
+ "environment_scope",
+ "active"
+ ],
+ "properties" : {
+ "name": { "type": "string" },
+ "id": { "type": "integer" },
+ "environment_scope": { "type": "string" },
+ "active": { "type": "boolean" },
+ "created_at": { "type": "date" },
+ "updated_at": { "type": "date" },
+ "strategies": { "type": "array", "items": { "$ref": "feature_flag_strategy.json" } }
+ },
+ "additionalProperties": false
+ }
+}
diff --git a/spec/fixtures/api/schemas/public_api/v4/feature_flag_scope.json b/spec/fixtures/api/schemas/public_api/v4/feature_flag_scope.json
new file mode 100644
index 00000000000..18402af482e
--- /dev/null
+++ b/spec/fixtures/api/schemas/public_api/v4/feature_flag_scope.json
@@ -0,0 +1,17 @@
+{
+ "type": "object",
+ "required": [
+ "id",
+ "environment_scope",
+ "active"
+ ],
+ "properties": {
+ "id": { "type": "integer" },
+ "environment_scope": { "type": "string" },
+ "active": { "type": "boolean" },
+ "created_at": { "type": "date" },
+ "updated_at": { "type": "date" },
+ "strategies": { "type": "array", "items": { "$ref": "feature_flag_strategy.json" } }
+ },
+ "additionalProperties": false
+}
diff --git a/spec/fixtures/api/schemas/public_api/v4/feature_flag_scopes.json b/spec/fixtures/api/schemas/public_api/v4/feature_flag_scopes.json
new file mode 100644
index 00000000000..b1a7021db8b
--- /dev/null
+++ b/spec/fixtures/api/schemas/public_api/v4/feature_flag_scopes.json
@@ -0,0 +1,9 @@
+{
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "$ref": "./feature_flag_scope.json"
+ }
+ }
+}
diff --git a/spec/fixtures/api/schemas/public_api/v4/feature_flag_strategy.json b/spec/fixtures/api/schemas/public_api/v4/feature_flag_strategy.json
new file mode 100644
index 00000000000..5a2777dc8ea
--- /dev/null
+++ b/spec/fixtures/api/schemas/public_api/v4/feature_flag_strategy.json
@@ -0,0 +1,13 @@
+{
+ "type": "object",
+ "required": [
+ "name"
+ ],
+ "properties": {
+ "name": { "type": "string" },
+ "parameters": {
+ "type": "object"
+ }
+ },
+ "additionalProperties": false
+}
diff --git a/spec/fixtures/api/schemas/public_api/v4/feature_flags.json b/spec/fixtures/api/schemas/public_api/v4/feature_flags.json
new file mode 100644
index 00000000000..c19df0443d9
--- /dev/null
+++ b/spec/fixtures/api/schemas/public_api/v4/feature_flags.json
@@ -0,0 +1,9 @@
+{
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "$ref": "./feature_flag.json"
+ }
+ }
+}
diff --git a/spec/fixtures/api/schemas/public_api/v4/operations/scope.json b/spec/fixtures/api/schemas/public_api/v4/operations/scope.json
new file mode 100644
index 00000000000..e2b6d1ad6f1
--- /dev/null
+++ b/spec/fixtures/api/schemas/public_api/v4/operations/scope.json
@@ -0,0 +1,9 @@
+{
+ "type": "object",
+ "required": ["environment_scope"],
+ "properties": {
+ "id": { "type": "integer" },
+ "environment_scope": { "type": "string" }
+ },
+ "additionalProperties": false
+}
diff --git a/spec/fixtures/api/schemas/public_api/v4/operations/strategy.json b/spec/fixtures/api/schemas/public_api/v4/operations/strategy.json
new file mode 100644
index 00000000000..f572b1a4f9b
--- /dev/null
+++ b/spec/fixtures/api/schemas/public_api/v4/operations/strategy.json
@@ -0,0 +1,14 @@
+{
+ "type": "object",
+ "required": [
+ "name",
+ "parameters"
+ ],
+ "properties": {
+ "id": { "type": "integer" },
+ "name": { "type": "string" },
+ "parameters": { "type": "object" },
+ "scopes": { "type": "array", "items": { "$ref": "scope.json" } }
+ },
+ "additionalProperties": false
+}
diff --git a/spec/fixtures/api/schemas/public_api/v4/packages/package.json b/spec/fixtures/api/schemas/public_api/v4/packages/package.json
index 757e5fd26b6..08909efd10c 100644
--- a/spec/fixtures/api/schemas/public_api/v4/packages/package.json
+++ b/spec/fixtures/api/schemas/public_api/v4/packages/package.json
@@ -11,6 +11,9 @@
"name": {
"type": "string"
},
+ "conan_package_name": {
+ "type": "string"
+ },
"version": {
"type": "string"
},
diff --git a/spec/fixtures/api/schemas/registry/repository.json b/spec/fixtures/api/schemas/registry/repository.json
index 1f84e787b19..18d2c68ac2f 100644
--- a/spec/fixtures/api/schemas/registry/repository.json
+++ b/spec/fixtures/api/schemas/registry/repository.json
@@ -20,6 +20,9 @@
"created_at": {
"type": "date-time"
},
+ "cleanup_policy_started_at": {
+ "type": "date-time"
+ },
"tags_path": {
"type": "string"
},
diff --git a/spec/fixtures/api/schemas/unleash/unleash.json b/spec/fixtures/api/schemas/unleash/unleash.json
new file mode 100644
index 00000000000..6eaf316bb11
--- /dev/null
+++ b/spec/fixtures/api/schemas/unleash/unleash.json
@@ -0,0 +1,20 @@
+{
+ "additionalProperties": false,
+ "properties": {
+ "features": {
+ "items": {
+ "$ref": "unleash_feature.json"
+ },
+ "minItems": 0,
+ "type": "array"
+ },
+ "version": {
+ "type": "integer"
+ }
+ },
+ "required": [
+ "version",
+ "features"
+ ],
+ "type": "object"
+}
diff --git a/spec/fixtures/api/schemas/unleash/unleash_feature.json b/spec/fixtures/api/schemas/unleash/unleash_feature.json
new file mode 100644
index 00000000000..71d375a5371
--- /dev/null
+++ b/spec/fixtures/api/schemas/unleash/unleash_feature.json
@@ -0,0 +1,27 @@
+{
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "name",
+ "enabled",
+ "strategies"
+ ],
+ "properties": {
+ "name": {
+ "type": "string"
+ },
+ "enabled": {
+ "type": "boolean"
+ },
+ "description": {
+ "type": "string"
+ },
+ "strategies": {
+ "items": {
+ "$ref": "unleash_strategy.json"
+ },
+ "minItems": 1,
+ "type": "array"
+ }
+ }
+}
diff --git a/spec/fixtures/api/schemas/unleash/unleash_strategy.json b/spec/fixtures/api/schemas/unleash/unleash_strategy.json
new file mode 100644
index 00000000000..7b48038ad15
--- /dev/null
+++ b/spec/fixtures/api/schemas/unleash/unleash_strategy.json
@@ -0,0 +1,24 @@
+{
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "name"
+ ],
+ "properties": {
+ "name": {
+ "type": "string"
+ },
+ "parameters": {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "groupId": {
+ "type": "string"
+ },
+ "percentage": {
+ "type": "integer"
+ }
+ }
+ }
+ }
+}
diff --git a/spec/fixtures/invalid_manifest.xml b/spec/fixtures/invalid_manifest.xml
new file mode 100644
index 00000000000..5357329784c
--- /dev/null
+++ b/spec/fixtures/invalid_manifest.xml
@@ -0,0 +1,4 @@
+<manifest>
+ <remote review="invalid-url" />
+ <project name="platform/build"/>
+</manifest>
diff --git a/spec/fixtures/lib/backup/design_repo.bundle b/spec/fixtures/lib/backup/design_repo.bundle
new file mode 100644
index 00000000000..3ed4ad6ab8b
--- /dev/null
+++ b/spec/fixtures/lib/backup/design_repo.bundle
Binary files differ
diff --git a/spec/fixtures/lib/backup/personal_snippet_repo.bundle b/spec/fixtures/lib/backup/personal_snippet_repo.bundle
new file mode 100644
index 00000000000..452cf6a19fe
--- /dev/null
+++ b/spec/fixtures/lib/backup/personal_snippet_repo.bundle
Binary files differ
diff --git a/spec/fixtures/lib/backup/project_repo.bundle b/spec/fixtures/lib/backup/project_repo.bundle
new file mode 100644
index 00000000000..44d4fc56d51
--- /dev/null
+++ b/spec/fixtures/lib/backup/project_repo.bundle
Binary files differ
diff --git a/spec/fixtures/lib/backup/project_snippet_repo.bundle b/spec/fixtures/lib/backup/project_snippet_repo.bundle
new file mode 100644
index 00000000000..c05f8ec9495
--- /dev/null
+++ b/spec/fixtures/lib/backup/project_snippet_repo.bundle
Binary files differ
diff --git a/spec/fixtures/lib/backup/wiki_repo.bundle b/spec/fixtures/lib/backup/wiki_repo.bundle
new file mode 100644
index 00000000000..bcc08dcbe8e
--- /dev/null
+++ b/spec/fixtures/lib/backup/wiki_repo.bundle
Binary files differ
diff --git a/spec/fixtures/lib/gitlab/import_export/sample_data/tree/project.json b/spec/fixtures/lib/gitlab/import_export/sample_data/tree/project.json
new file mode 100644
index 00000000000..12136c6df3b
--- /dev/null
+++ b/spec/fixtures/lib/gitlab/import_export/sample_data/tree/project.json
@@ -0,0 +1 @@
+{"description":"Nisi et repellendus ut enim quo accusamus vel magnam.","import_type":"gitlab_project","creator_id":2147483547,"visibility_level":10,"archived":false,"hooks":[]}
diff --git a/spec/fixtures/lib/gitlab/import_export/sample_data/tree/project/issues.ndjson b/spec/fixtures/lib/gitlab/import_export/sample_data/tree/project/issues.ndjson
new file mode 100644
index 00000000000..efe0d34bcb1
--- /dev/null
+++ b/spec/fixtures/lib/gitlab/import_export/sample_data/tree/project/issues.ndjson
@@ -0,0 +1,10 @@
+{"id":40,"title":"Voluptatem","author_id":22,"project_id":5,"created_at":"2016-06-14T15:02:08.340Z","updated_at":"2016-06-14T15:02:47.967Z","position":0,"branch_name":null,"description":"Aliquam enim illo et possimus.","state":"opened","iid":10,"updated_by_id":null,"confidential":false,"due_date":"2020-08-07","moved_to_id":null,"test_ee_field":"test","issue_assignees":[{"user_id":1,"issue_id":40},{"user_id":15,"issue_id":40},{"user_id":16,"issue_id":40},{"user_id":16,"issue_id":40},{"user_id":6,"issue_id":40}],"award_emoji":[{"id":1,"name":"musical_keyboard","user_id":1,"awardable_type":"Issue","awardable_id":40,"created_at":"2020-01-07T11:55:22.234Z","updated_at":"2020-01-07T11:55:22.234Z"}],"zoom_meetings":[{"id":1,"project_id":5,"issue_id":40,"url":"https://zoom.us/j/123456789","issue_status":1,"created_at":"2016-06-14T15:02:04.418Z","updated_at":"2016-06-14T15:02:04.418Z"}],"milestone":{"id":1,"title":"test milestone","project_id":8,"description":"test milestone","due_date":null,"created_at":"2016-06-14T15:02:04.415Z","updated_at":"2016-06-14T15:02:04.415Z","state":"active","iid":1,"events":[{"id":487,"target_type":"Milestone","target_id":1,"project_id":46,"created_at":"2016-06-14T15:02:04.418Z","updated_at":"2016-06-14T15:02:04.418Z","action":1,"author_id":18}]},"label_links":[{"id":2,"label_id":2,"target_id":40,"target_type":"Issue","created_at":"2016-07-22T08:57:02.840Z","updated_at":"2016-07-22T08:57:02.840Z","label":{"id":2,"title":"test2","color":"#428bca","project_id":8,"created_at":"2016-07-22T08:55:44.161Z","updated_at":"2016-07-22T08:55:44.161Z","template":false,"description":"","type":"ProjectLabel"}},{"id":3,"label_id":3,"target_id":40,"target_type":"Issue","created_at":"2016-07-22T08:57:02.841Z","updated_at":"2016-07-22T08:57:02.841Z","label":{"id":3,"title":"test3","color":"#428bca","group_id":8,"created_at":"2016-07-22T08:55:44.161Z","updated_at":"2016-07-22T08:55:44.161Z","template":false,"description":"","project_id":null,"type":"GroupLabel","priorities":[{"id":1,"project_id":5,"label_id":1,"priority":1,"created_at":"2016-10-18T09:35:43.338Z","updated_at":"2016-10-18T09:35:43.338Z"}]}}],"notes":[{"id":351,"note":"Quo reprehenderit aliquam qui dicta impedit cupiditate eligendi.","note_html":"<p>something else entirely</p>","cached_markdown_version":917504,"noteable_type":"Issue","author_id":26,"created_at":"2016-06-14T15:02:47.770Z","updated_at":"2016-06-14T15:02:47.770Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":40,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"User 4"},"events":[],"award_emoji":[{"id":1,"name":"clapper","user_id":1,"awardable_type":"Note","awardable_id":351,"created_at":"2020-01-07T11:55:22.234Z","updated_at":"2020-01-07T11:55:22.234Z"}]},{"id":352,"note":"Est reprehenderit quas aut aspernatur autem recusandae voluptatem.","noteable_type":"Issue","author_id":25,"created_at":"2016-06-14T15:02:47.795Z","updated_at":"2016-06-14T15:02:47.795Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":40,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"User 3"},"events":[]},{"id":353,"note":"Perspiciatis suscipit voluptates in eius nihil.","noteable_type":"Issue","author_id":22,"created_at":"2016-06-14T15:02:47.823Z","updated_at":"2016-06-14T15:02:47.823Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":40,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"User 0"},"events":[]},{"id":354,"note":"Aut vel voluptas corrupti nisi provident laboriosam magnam aut.","noteable_type":"Issue","author_id":20,"created_at":"2016-06-14T15:02:47.850Z","updated_at":"2016-06-14T15:02:47.850Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":40,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Ottis Schuster II"},"events":[]},{"id":355,"note":"Officia dolore consequatur in saepe cum magni.","noteable_type":"Issue","author_id":16,"created_at":"2016-06-14T15:02:47.876Z","updated_at":"2016-06-14T15:02:47.876Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":40,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Rhett Emmerich IV"},"events":[]},{"id":356,"note":"Cum ipsum rem voluptas eaque et ea.","noteable_type":"Issue","author_id":15,"created_at":"2016-06-14T15:02:47.908Z","updated_at":"2016-06-14T15:02:47.908Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":40,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Burdette Bernier"},"events":[]},{"id":357,"note":"Recusandae excepturi asperiores suscipit autem nostrum.","noteable_type":"Issue","author_id":6,"created_at":"2016-06-14T15:02:47.937Z","updated_at":"2016-06-14T15:02:47.937Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":40,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Ari Wintheiser"},"events":[]},{"id":358,"note":"Et hic est id similique et non nesciunt voluptate.","noteable_type":"Issue","author_id":1,"created_at":"2016-06-14T15:02:47.965Z","updated_at":"2016-06-14T15:02:47.965Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":40,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Administrator"},"events":[]}],"resource_label_events":[{"id":244,"action":"remove","issue_id":40,"merge_request_id":null,"label_id":2,"user_id":1,"created_at":"2018-08-28T08:24:00.494Z","label":{"id":2,"title":"test2","color":"#428bca","project_id":8,"created_at":"2016-07-22T08:55:44.161Z","updated_at":"2016-07-22T08:55:44.161Z","template":false,"description":"","type":"ProjectLabel"}}],"sentry_issue":{"id":1,"issue_id":40,"sentry_issue_identifier":1234567891}}
+{"id":39,"title":"Issue without assignees","author_id":22,"project_id":5,"created_at":"2016-06-14T15:02:08.233Z","updated_at":"2016-06-14T15:02:48.194Z","position":0,"branch_name":null,"description":"Voluptate vel reprehenderit facilis omnis voluptas magnam tenetur.","state":"opened","iid":9,"updated_by_id":null,"confidential":false,"due_date":"2020-08-14","moved_to_id":null,"issue_assignees":[],"milestone":{"id":1,"title":"test milestone","project_id":8,"description":"test milestone","due_date":null,"created_at":"2016-06-14T15:02:04.415Z","updated_at":"2016-06-14T15:02:04.415Z","state":"active","iid":1,"events":[{"id":487,"target_type":"Milestone","target_id":1,"project_id":46,"created_at":"2016-06-14T15:02:04.418Z","updated_at":"2016-06-14T15:02:04.418Z","action":1,"author_id":18}]},"notes":[{"id":359,"note":"Quo eius velit quia et id quam.","noteable_type":"Issue","author_id":26,"created_at":"2016-06-14T15:02:48.009Z","updated_at":"2016-06-14T15:02:48.009Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":39,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"User 4"},"events":[]},{"id":360,"note":"Nulla commodi ratione cumque id autem.","noteable_type":"Issue","author_id":25,"created_at":"2016-06-14T15:02:48.032Z","updated_at":"2016-06-14T15:02:48.032Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":39,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"User 3"},"events":[]},{"id":361,"note":"Illum non ea sed dolores corrupti.","noteable_type":"Issue","author_id":22,"created_at":"2016-06-14T15:02:48.056Z","updated_at":"2016-06-14T15:02:48.056Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":39,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"User 0"},"events":[]},{"id":362,"note":"Facere dolores ipsum dolorum maiores omnis occaecati ab.","noteable_type":"Issue","author_id":20,"created_at":"2016-06-14T15:02:48.082Z","updated_at":"2016-06-14T15:02:48.082Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":39,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Ottis Schuster II"},"events":[]},{"id":363,"note":"Quod laudantium similique sint aut est ducimus.","noteable_type":"Issue","author_id":16,"created_at":"2016-06-14T15:02:48.113Z","updated_at":"2016-06-14T15:02:48.113Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":39,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Rhett Emmerich IV"},"events":[]},{"id":364,"note":"Aut omnis eos esse incidunt vero reiciendis.","noteable_type":"Issue","author_id":15,"created_at":"2016-06-14T15:02:48.139Z","updated_at":"2016-06-14T15:02:48.139Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":39,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Burdette Bernier"},"events":[]},{"id":365,"note":"Beatae dolore et doloremque asperiores sunt.","noteable_type":"Issue","author_id":6,"created_at":"2016-06-14T15:02:48.162Z","updated_at":"2016-06-14T15:02:48.162Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":39,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Ari Wintheiser"},"events":[]},{"id":366,"note":"Doloribus ipsam ex delectus rerum libero recusandae modi repellendus.","noteable_type":"Issue","author_id":1,"created_at":"2016-06-14T15:02:48.192Z","updated_at":"2016-06-14T15:02:48.192Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":39,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Administrator"},"events":[]}]}
+{"id":38,"title":"Quasi adipisci non cupiditate dolorem quo qui earum sed.","author_id":6,"project_id":5,"created_at":"2016-06-14T15:02:08.154Z","updated_at":"2016-06-14T15:02:48.614Z","position":0,"branch_name":null,"description":"Ea recusandae neque autem tempora.","state":"closed","iid":8,"updated_by_id":null,"confidential":false,"due_date":"2020-08-21","moved_to_id":null,"label_links":[{"id":99,"label_id":2,"target_id":38,"target_type":"Issue","created_at":"2016-07-22T08:57:02.840Z","updated_at":"2016-07-22T08:57:02.840Z","label":{"id":2,"title":"test2","color":"#428bca","project_id":8,"created_at":"2016-07-22T08:55:44.161Z","updated_at":"2016-07-22T08:55:44.161Z","template":false,"description":"","type":"ProjectLabel"}}],"notes":[{"id":367,"note":"Accusantium fugiat et eaque quisquam esse corporis.","noteable_type":"Issue","author_id":26,"created_at":"2016-06-14T15:02:48.235Z","updated_at":"2016-06-14T15:02:48.235Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":38,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"User 4"},"events":[]},{"id":368,"note":"Ea labore eum nam qui laboriosam.","noteable_type":"Issue","author_id":25,"created_at":"2016-06-14T15:02:48.261Z","updated_at":"2016-06-14T15:02:48.261Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":38,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"User 3"},"events":[]},{"id":369,"note":"Accusantium quis sed molestiae et.","noteable_type":"Issue","author_id":22,"created_at":"2016-06-14T15:02:48.294Z","updated_at":"2016-06-14T15:02:48.294Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":38,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"User 0"},"events":[]},{"id":370,"note":"Corporis numquam a voluptatem pariatur asperiores dolorem delectus autem.","noteable_type":"Issue","author_id":20,"created_at":"2016-06-14T15:02:48.523Z","updated_at":"2016-06-14T15:02:48.523Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":38,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Ottis Schuster II"},"events":[]},{"id":371,"note":"Ea accusantium maxime voluptas rerum.","noteable_type":"Issue","author_id":16,"created_at":"2016-06-14T15:02:48.546Z","updated_at":"2016-06-14T15:02:48.546Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":38,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Rhett Emmerich IV"},"events":[]},{"id":372,"note":"Pariatur iusto et et excepturi similique ipsam eum.","noteable_type":"Issue","author_id":15,"created_at":"2016-06-14T15:02:48.569Z","updated_at":"2016-06-14T15:02:48.569Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":38,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Burdette Bernier"},"events":[]},{"id":373,"note":"Aliquam et culpa officia iste eius.","noteable_type":"Issue","author_id":6,"created_at":"2016-06-14T15:02:48.591Z","updated_at":"2016-06-14T15:02:48.591Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":38,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Ari Wintheiser"},"events":[]},{"id":374,"note":"Ab id velit id unde laborum.","noteable_type":"Issue","author_id":1,"created_at":"2016-06-14T15:02:48.613Z","updated_at":"2016-06-14T15:02:48.613Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":38,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Administrator"},"events":[]}]}
+{"id":37,"title":"Cupiditate quo aut ducimus minima molestiae vero numquam possimus.","author_id":20,"project_id":5,"created_at":"2016-06-14T15:02:08.051Z","updated_at":"2016-06-14T15:02:48.854Z","position":0,"branch_name":null,"description":"Maiores architecto quos in dolorem.","state":"opened","iid":7,"updated_by_id":null,"confidential":false,"due_date":null,"moved_to_id":null,"notes":[{"id":375,"note":"Quasi fugit qui sed eligendi aut quia.","noteable_type":"Issue","author_id":26,"created_at":"2016-06-14T15:02:48.647Z","updated_at":"2016-06-14T15:02:48.647Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":37,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"User 4"},"events":[]},{"id":376,"note":"Esse nesciunt voluptatem ex vero est consequatur.","noteable_type":"Issue","author_id":25,"created_at":"2016-06-14T15:02:48.674Z","updated_at":"2016-06-14T15:02:48.674Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":37,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"User 3"},"events":[]},{"id":377,"note":"Similique qui quas non aut et velit sequi in.","noteable_type":"Issue","author_id":22,"created_at":"2016-06-14T15:02:48.696Z","updated_at":"2016-06-14T15:02:48.696Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":37,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"User 0"},"events":[]},{"id":378,"note":"Eveniet ut cupiditate repellendus numquam in esse eius.","noteable_type":"Issue","author_id":20,"created_at":"2016-06-14T15:02:48.720Z","updated_at":"2016-06-14T15:02:48.720Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":37,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Ottis Schuster II"},"events":[]},{"id":379,"note":"Velit est dolorem adipisci rerum sed iure.","noteable_type":"Issue","author_id":16,"created_at":"2016-06-14T15:02:48.755Z","updated_at":"2016-06-14T15:02:48.755Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":37,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Rhett Emmerich IV"},"events":[]},{"id":380,"note":"Voluptatem ullam ab ut illo ut quo.","noteable_type":"Issue","author_id":15,"created_at":"2016-06-14T15:02:48.793Z","updated_at":"2016-06-14T15:02:48.793Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":37,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Burdette Bernier"},"events":[]},{"id":381,"note":"Voluptatem impedit beatae quasi ipsa earum consectetur.","noteable_type":"Issue","author_id":6,"created_at":"2016-06-14T15:02:48.823Z","updated_at":"2016-06-14T15:02:48.823Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":37,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Ari Wintheiser"},"events":[]},{"id":382,"note":"Nihil officiis eaque incidunt sunt voluptatum excepturi.","noteable_type":"Issue","author_id":1,"created_at":"2016-06-14T15:02:48.852Z","updated_at":"2016-06-14T15:02:48.852Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":37,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Administrator"},"events":[]}]}
+{"id":36,"title":"Necessitatibus dolor est enim quia rem suscipit quidem voluptas ullam.","author_id":16,"project_id":5,"created_at":"2016-06-14T15:02:07.958Z","updated_at":"2016-06-14T15:02:49.044Z","position":0,"branch_name":null,"description":"Ut aut ut et tenetur velit aut id modi.","state":"opened","iid":6,"updated_by_id":null,"confidential":false,"due_date":null,"moved_to_id":null,"notes":[{"id":383,"note":"Excepturi deleniti sunt rerum nesciunt vero fugiat possimus.","noteable_type":"Issue","author_id":26,"created_at":"2016-06-14T15:02:48.885Z","updated_at":"2016-06-14T15:02:48.885Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":36,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"User 4"},"events":[]},{"id":384,"note":"Et est nemo sed nam sed.","noteable_type":"Issue","author_id":25,"created_at":"2016-06-14T15:02:48.910Z","updated_at":"2016-06-14T15:02:48.910Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":36,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"User 3"},"events":[]},{"id":385,"note":"Animi mollitia nulla facere amet aut quaerat.","noteable_type":"Issue","author_id":22,"created_at":"2016-06-14T15:02:48.934Z","updated_at":"2016-06-14T15:02:48.934Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":36,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"User 0"},"events":[]},{"id":386,"note":"Excepturi id voluptas ut odio officiis omnis.","noteable_type":"Issue","author_id":20,"created_at":"2016-06-14T15:02:48.955Z","updated_at":"2016-06-14T15:02:48.955Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":36,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Ottis Schuster II"},"events":[]},{"id":387,"note":"Molestiae labore officiis magni et eligendi quasi maxime.","noteable_type":"Issue","author_id":16,"created_at":"2016-06-14T15:02:48.978Z","updated_at":"2016-06-14T15:02:48.978Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":36,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Rhett Emmerich IV"},"events":[]},{"id":388,"note":"Officia tenetur praesentium rem nam non.","noteable_type":"Issue","author_id":15,"created_at":"2016-06-14T15:02:49.001Z","updated_at":"2016-06-14T15:02:49.001Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":36,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Burdette Bernier"},"events":[]},{"id":389,"note":"Et et et molestiae reprehenderit.","noteable_type":"Issue","author_id":6,"created_at":"2016-06-14T15:02:49.022Z","updated_at":"2016-06-14T15:02:49.022Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":36,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Ari Wintheiser"},"events":[]},{"id":390,"note":"Aperiam in consequatur est sunt cum quia.","noteable_type":"Issue","author_id":1,"created_at":"2016-06-14T15:02:49.043Z","updated_at":"2016-06-14T15:02:49.043Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":36,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Administrator"},"events":[]}]}
+{"id":35,"title":"Repellat praesentium deserunt maxime incidunt harum porro qui.","author_id":20,"project_id":5,"created_at":"2016-06-14T15:02:07.832Z","updated_at":"2016-06-14T15:02:49.226Z","position":0,"branch_name":null,"description":"Dicta nisi nihil non ipsa velit.","state":"closed","iid":5,"updated_by_id":null,"confidential":false,"due_date":null,"moved_to_id":null,"notes":[{"id":391,"note":"Qui magnam et assumenda quod id dicta necessitatibus.","noteable_type":"Issue","author_id":26,"created_at":"2016-06-14T15:02:49.075Z","updated_at":"2016-06-14T15:02:49.075Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":35,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"User 4"},"events":[]},{"id":392,"note":"Consectetur deserunt possimus dolor est odio.","noteable_type":"Issue","author_id":25,"created_at":"2016-06-14T15:02:49.095Z","updated_at":"2016-06-14T15:02:49.095Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":35,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"User 3"},"events":[]},{"id":393,"note":"Labore nisi quo cumque voluptas consequatur aut qui.","noteable_type":"Issue","author_id":22,"created_at":"2016-06-14T15:02:49.117Z","updated_at":"2016-06-14T15:02:49.117Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":35,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"User 0"},"events":[]},{"id":394,"note":"Et totam facilis voluptas et enim.","noteable_type":"Issue","author_id":20,"created_at":"2016-06-14T15:02:49.138Z","updated_at":"2016-06-14T15:02:49.138Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":35,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Ottis Schuster II"},"events":[]},{"id":395,"note":"Ratione sint pariatur sed omnis eligendi quo libero exercitationem.","noteable_type":"Issue","author_id":16,"created_at":"2016-06-14T15:02:49.160Z","updated_at":"2016-06-14T15:02:49.160Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":35,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Rhett Emmerich IV"},"events":[]},{"id":396,"note":"Iure hic autem id voluptatem.","noteable_type":"Issue","author_id":15,"created_at":"2016-06-14T15:02:49.182Z","updated_at":"2016-06-14T15:02:49.182Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":35,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Burdette Bernier"},"events":[]},{"id":397,"note":"Excepturi eum laboriosam delectus repellendus odio nisi et voluptatem.","noteable_type":"Issue","author_id":6,"created_at":"2016-06-14T15:02:49.205Z","updated_at":"2016-06-14T15:02:49.205Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":35,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Ari Wintheiser"},"events":[]},{"id":398,"note":"Ut quis ex soluta consequatur et blanditiis.","noteable_type":"Issue","author_id":1,"created_at":"2016-06-14T15:02:49.225Z","updated_at":"2016-06-14T15:02:49.225Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":35,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Administrator"},"events":[]}]}
+{"id":34,"title":"Ullam expedita deserunt libero consequatur quia dolor harum perferendis facere quidem.","author_id":1,"project_id":5,"created_at":"2016-06-14T15:02:07.717Z","updated_at":"2016-06-14T15:02:49.416Z","position":0,"branch_name":null,"description":"Ut et explicabo vel voluptatem consequuntur ut sed.","state":"closed","iid":4,"updated_by_id":null,"confidential":false,"due_date":null,"moved_to_id":null,"notes":[{"id":399,"note":"Dolor iste tempora tenetur non vitae maiores voluptatibus.","noteable_type":"Issue","author_id":26,"created_at":"2016-06-14T15:02:49.256Z","updated_at":"2016-06-14T15:02:49.256Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":34,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"User 4"},"events":[]},{"id":400,"note":"Aut sit quidem qui adipisci maxime excepturi iusto.","noteable_type":"Issue","author_id":25,"created_at":"2016-06-14T15:02:49.284Z","updated_at":"2016-06-14T15:02:49.284Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":34,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"User 3"},"events":[]},{"id":401,"note":"Et a necessitatibus autem quidem animi sunt voluptatum rerum.","noteable_type":"Issue","author_id":22,"created_at":"2016-06-14T15:02:49.305Z","updated_at":"2016-06-14T15:02:49.305Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":34,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"User 0"},"events":[]},{"id":402,"note":"Esse laboriosam quo voluptatem quis molestiae.","noteable_type":"Issue","author_id":20,"created_at":"2016-06-14T15:02:49.328Z","updated_at":"2016-06-14T15:02:49.328Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":34,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Ottis Schuster II"},"events":[]},{"id":403,"note":"Nemo magnam distinctio est ut voluptate ea.","noteable_type":"Issue","author_id":16,"created_at":"2016-06-14T15:02:49.350Z","updated_at":"2016-06-14T15:02:49.350Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":34,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Rhett Emmerich IV"},"events":[]},{"id":404,"note":"Omnis sed rerum neque rerum quae quam nulla officiis.","noteable_type":"Issue","author_id":15,"created_at":"2016-06-14T15:02:49.372Z","updated_at":"2016-06-14T15:02:49.372Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":34,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Burdette Bernier"},"events":[]},{"id":405,"note":"Quo soluta dolorem vitae ad consequatur qui aut dicta.","noteable_type":"Issue","author_id":6,"created_at":"2016-06-14T15:02:49.394Z","updated_at":"2016-06-14T15:02:49.394Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":34,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Ari Wintheiser"},"events":[]},{"id":406,"note":"Magni minus est aut aut totam ut.","noteable_type":"Issue","author_id":1,"created_at":"2016-06-14T15:02:49.414Z","updated_at":"2016-06-14T15:02:49.414Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":34,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Administrator"},"events":[]}]}
+{"id":33,"title":"Numquam accusamus eos iste exercitationem magni non inventore.","author_id":26,"project_id":5,"created_at":"2016-06-14T15:02:07.611Z","updated_at":"2016-06-14T15:02:49.661Z","position":0,"branch_name":null,"description":"Non asperiores velit accusantium voluptate.","state":"closed","iid":3,"updated_by_id":null,"confidential":false,"due_date":null,"moved_to_id":null,"notes":[{"id":407,"note":"Quod ea et possimus architecto.","noteable_type":"Issue","author_id":26,"created_at":"2016-06-14T15:02:49.450Z","updated_at":"2016-06-14T15:02:49.450Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":33,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"User 4"},"events":[]},{"id":408,"note":"Reiciendis est et unde perferendis dicta ut praesentium quasi.","noteable_type":"Issue","author_id":25,"created_at":"2016-06-14T15:02:49.503Z","updated_at":"2016-06-14T15:02:49.503Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":33,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"User 3"},"events":[]},{"id":409,"note":"Magni quia odio blanditiis pariatur voluptas.","noteable_type":"Issue","author_id":22,"created_at":"2016-06-14T15:02:49.527Z","updated_at":"2016-06-14T15:02:49.527Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":33,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"User 0"},"events":[]},{"id":410,"note":"Enim quam ut et et et.","noteable_type":"Issue","author_id":20,"created_at":"2016-06-14T15:02:49.551Z","updated_at":"2016-06-14T15:02:49.551Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":33,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Ottis Schuster II"},"events":[]},{"id":411,"note":"Fugit voluptatem ratione maxime expedita.","noteable_type":"Issue","author_id":16,"created_at":"2016-06-14T15:02:49.578Z","updated_at":"2016-06-14T15:02:49.578Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":33,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Rhett Emmerich IV"},"events":[]},{"id":412,"note":"Voluptatem enim aut ipsa et et ducimus.","noteable_type":"Issue","author_id":15,"created_at":"2016-06-14T15:02:49.604Z","updated_at":"2016-06-14T15:02:49.604Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":33,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Burdette Bernier"},"events":[]},{"id":413,"note":"Quia repellat fugiat consectetur quidem.","noteable_type":"Issue","author_id":6,"created_at":"2016-06-14T15:02:49.631Z","updated_at":"2016-06-14T15:02:49.631Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":33,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Ari Wintheiser"},"events":[]},{"id":414,"note":"Corporis ipsum et ea necessitatibus quod assumenda repudiandae quam.","noteable_type":"Issue","author_id":1,"created_at":"2016-06-14T15:02:49.659Z","updated_at":"2016-06-14T15:02:49.659Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":33,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Administrator"},"events":[]}]}
+{"id":32,"title":"Necessitatibus magnam qui at velit consequatur perspiciatis.","author_id":15,"project_id":5,"created_at":"2016-06-14T15:02:07.431Z","updated_at":"2016-06-14T15:02:49.884Z","position":0,"branch_name":null,"description":"Molestiae corporis magnam et fugit aliquid nulla quia.","state":"closed","iid":2,"updated_by_id":null,"confidential":false,"due_date":null,"moved_to_id":null,"notes":[{"id":415,"note":"Nemo consequatur sed blanditiis qui id iure dolores.","noteable_type":"Issue","author_id":26,"created_at":"2016-06-14T15:02:49.694Z","updated_at":"2016-06-14T15:02:49.694Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":32,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"User 4"},"events":[]},{"id":416,"note":"Voluptas ab accusantium dicta in.","noteable_type":"Issue","author_id":25,"created_at":"2016-06-14T15:02:49.718Z","updated_at":"2016-06-14T15:02:49.718Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":32,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"User 3"},"events":[]},{"id":417,"note":"Esse odit qui a et eum ducimus.","noteable_type":"Issue","author_id":22,"created_at":"2016-06-14T15:02:49.741Z","updated_at":"2016-06-14T15:02:49.741Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":32,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"User 0"},"events":[]},{"id":418,"note":"Sequi dolor doloribus ratione placeat repellendus.","noteable_type":"Issue","author_id":20,"created_at":"2016-06-14T15:02:49.767Z","updated_at":"2016-06-14T15:02:49.767Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":32,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Ottis Schuster II"},"events":[]},{"id":419,"note":"Quae aspernatur rem est similique.","noteable_type":"Issue","author_id":16,"created_at":"2016-06-14T15:02:49.796Z","updated_at":"2016-06-14T15:02:49.796Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":32,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Rhett Emmerich IV"},"events":[]},{"id":420,"note":"Voluptate omnis et id rerum non nesciunt laudantium assumenda.","noteable_type":"Issue","author_id":15,"created_at":"2016-06-14T15:02:49.825Z","updated_at":"2016-06-14T15:02:49.825Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":32,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Burdette Bernier"},"events":[]},{"id":421,"note":"Quia enim ab et eligendi.","noteable_type":"Issue","author_id":6,"created_at":"2016-06-14T15:02:49.853Z","updated_at":"2016-06-14T15:02:49.853Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":32,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Ari Wintheiser"},"events":[]},{"id":422,"note":"In fugiat rerum voluptas quas officia.","noteable_type":"Issue","author_id":1,"created_at":"2016-06-14T15:02:49.881Z","updated_at":"2016-06-14T15:02:49.881Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":32,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Administrator"},"events":[]}]}
+{"id":31,"title":"issue_with_timelogs","author_id":16,"project_id":5,"created_at":"2016-06-14T15:02:07.280Z","updated_at":"2016-06-14T15:02:50.134Z","position":0,"branch_name":null,"description":"Quod ad architecto qui est sed quia.","state":"closed","iid":1,"updated_by_id":null,"confidential":false,"due_date":null,"moved_to_id":null,"timelogs":[{"id":1,"time_spent":72000,"user_id":1,"created_at":"2019-12-27T09:15:22.302Z","updated_at":"2019-12-27T09:15:22.302Z","spent_at":"2019-12-27T00:00:00.000Z"}],"notes":[{"id":423,"note":"A mollitia qui iste consequatur eaque iure omnis sunt.","noteable_type":"Issue","author_id":26,"created_at":"2016-06-14T15:02:49.933Z","updated_at":"2016-06-14T15:02:49.933Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":31,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"User 4"},"events":[]},{"id":424,"note":"Eveniet est et blanditiis sequi alias.","noteable_type":"Issue","author_id":25,"created_at":"2016-06-14T15:02:49.965Z","updated_at":"2016-06-14T15:02:49.965Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":31,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"User 3"},"events":[]},{"id":425,"note":"Commodi tempore voluptas doloremque est.","noteable_type":"Issue","author_id":22,"created_at":"2016-06-14T15:02:49.996Z","updated_at":"2016-06-14T15:02:49.996Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":31,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"User 0"},"events":[]},{"id":426,"note":"Quo libero impedit odio debitis rerum aspernatur.","noteable_type":"Issue","author_id":20,"created_at":"2016-06-14T15:02:50.024Z","updated_at":"2016-06-14T15:02:50.024Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":31,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Ottis Schuster II"},"events":[]},{"id":427,"note":"Dolorem voluptatem qui labore deserunt.","noteable_type":"Issue","author_id":16,"created_at":"2016-06-14T15:02:50.049Z","updated_at":"2016-06-14T15:02:50.049Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":31,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Rhett Emmerich IV"},"events":[]},{"id":428,"note":"Est blanditiis laboriosam enim ipsam.","noteable_type":"Issue","author_id":15,"created_at":"2016-06-14T15:02:50.077Z","updated_at":"2016-06-14T15:02:50.077Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":31,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Burdette Bernier"},"events":[]},{"id":429,"note":"Et in voluptatem animi dolorem eos.","noteable_type":"Issue","author_id":6,"created_at":"2016-06-14T15:02:50.107Z","updated_at":"2016-06-14T15:02:50.107Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":31,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Ari Wintheiser"},"events":[]},{"id":430,"note":"Unde culpa voluptate qui sint quos.","noteable_type":"Issue","author_id":1,"created_at":"2016-06-14T15:02:50.132Z","updated_at":"2016-06-14T15:02:50.132Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":31,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Administrator"},"events":[]}]}
diff --git a/spec/fixtures/lib/gitlab/import_export/sample_data/tree/project/labels.ndjson b/spec/fixtures/lib/gitlab/import_export/sample_data/tree/project/labels.ndjson
new file mode 100644
index 00000000000..c36b6970e83
--- /dev/null
+++ b/spec/fixtures/lib/gitlab/import_export/sample_data/tree/project/labels.ndjson
@@ -0,0 +1,2 @@
+{"id":2,"title":"test2","color":"#428bca","project_id":8,"created_at":"2016-07-22T08:55:44.161Z","updated_at":"2016-07-22T08:55:44.161Z","template":false,"description":"","type":"ProjectLabel","priorities":[]}
+{"id":3,"title":"test3","color":"#428bca","group_id":8,"created_at":"2016-07-22T08:55:44.161Z","updated_at":"2016-07-22T08:55:44.161Z","template":false,"description":"","project_id":null,"type":"GroupLabel","priorities":[{"id":1,"project_id":5,"label_id":1,"priority":1,"created_at":"2016-10-18T09:35:43.338Z","updated_at":"2016-10-18T09:35:43.338Z"}]}
diff --git a/spec/fixtures/lib/gitlab/import_export/sample_data/tree/project/milestones.ndjson b/spec/fixtures/lib/gitlab/import_export/sample_data/tree/project/milestones.ndjson
new file mode 100644
index 00000000000..ebb8203ece3
--- /dev/null
+++ b/spec/fixtures/lib/gitlab/import_export/sample_data/tree/project/milestones.ndjson
@@ -0,0 +1,3 @@
+{"id":1,"title":"test milestone","project_id":8,"description":"test milestone","due_date":"2020-08-07","created_at":"2016-06-14T15:02:04.415Z","updated_at":"2016-06-14T15:02:04.415Z","state":"active","iid":1,"events":[{"id":487,"target_type":"Milestone","target_id":1,"project_id":46,"created_at":"2016-06-14T15:02:04.418Z","updated_at":"2016-06-14T15:02:04.418Z","action":1,"author_id":18}]}
+{"id":20,"title":"v4.0","project_id":5,"description":"Totam quam laborum id magnam natus eaque aspernatur.","due_date":"2020-08-14","created_at":"2016-06-14T15:02:04.590Z","updated_at":"2016-06-14T15:02:04.590Z","state":"active","iid":5,"events":[{"id":240,"target_type":"Milestone","target_id":20,"project_id":36,"created_at":"2016-06-14T15:02:04.593Z","updated_at":"2016-06-14T15:02:04.593Z","action":1,"author_id":1},{"id":60,"target_type":"Milestone","target_id":20,"project_id":5,"created_at":"2016-06-14T15:02:04.593Z","updated_at":"2016-06-14T15:02:04.593Z","action":1,"author_id":20}]}
+{"id":19,"title":"v3.0","project_id":5,"description":"Rerum at autem exercitationem ea voluptates harum quam placeat.","due_date":"2020-08-21","created_at":"2016-06-14T15:02:04.583Z","updated_at":"2016-06-14T15:02:04.583Z","state":"active","iid":4,"events":[{"id":241,"target_type":"Milestone","target_id":19,"project_id":36,"created_at":"2016-06-14T15:02:04.585Z","updated_at":"2016-06-14T15:02:04.585Z","action":1,"author_id":1},{"id":59,"target_type":"Milestone","target_id":19,"project_id":5,"created_at":"2016-06-14T15:02:04.585Z","updated_at":"2016-06-14T15:02:04.585Z","action":1,"author_id":25}]}
diff --git a/spec/fixtures/packages/debian/libsample0_1.2.3~alpha2-1_amd64.deb b/spec/fixtures/packages/debian/libsample0_1.2.3~alpha2-1_amd64.deb
new file mode 100644
index 00000000000..c6cac69265a
--- /dev/null
+++ b/spec/fixtures/packages/debian/libsample0_1.2.3~alpha2-1_amd64.deb
@@ -0,0 +1 @@
+empty
diff --git a/spec/fixtures/packages/generic/myfile.tar.gz b/spec/fixtures/packages/generic/myfile.tar.gz
new file mode 100644
index 00000000000..c71b1fef23d
--- /dev/null
+++ b/spec/fixtures/packages/generic/myfile.tar.gz
Binary files differ
diff --git a/spec/frontend/alert_handler_spec.js b/spec/frontend/alert_handler_spec.js
index ba2f4f24aa5..0cee28112a8 100644
--- a/spec/frontend/alert_handler_spec.js
+++ b/spec/frontend/alert_handler_spec.js
@@ -2,18 +2,26 @@ import { setHTMLFixture } from 'helpers/fixtures';
import initAlertHandler from '~/alert_handler';
describe('Alert Handler', () => {
- const ALERT_SELECTOR = 'gl-alert';
- const CLOSE_SELECTOR = 'gl-alert-dismiss';
- const ALERT_HTML = `<div class="${ALERT_SELECTOR}"><button class="${CLOSE_SELECTOR}">Dismiss</button></div>`;
+ const ALERT_CLASS = 'gl-alert';
+ const BANNER_CLASS = 'gl-banner';
+ const DISMISS_CLASS = 'gl-alert-dismiss';
+ const DISMISS_LABEL = 'Dismiss';
- const findFirstAlert = () => document.querySelector(`.${ALERT_SELECTOR}`);
- const findAllAlerts = () => document.querySelectorAll(`.${ALERT_SELECTOR}`);
- const findFirstCloseButton = () => document.querySelector(`.${CLOSE_SELECTOR}`);
+ const generateHtml = parentClass =>
+ `<div class="${parentClass}">
+ <button aria-label="${DISMISS_LABEL}">Dismiss</button>
+ </div>`;
+
+ const findFirstAlert = () => document.querySelector(`.${ALERT_CLASS}`);
+ const findFirstBanner = () => document.querySelector(`.${BANNER_CLASS}`);
+ const findAllAlerts = () => document.querySelectorAll(`.${ALERT_CLASS}`);
+ const findFirstDismissButton = () => document.querySelector(`[aria-label="${DISMISS_LABEL}"]`);
+ const findFirstDismissButtonByClass = () => document.querySelector(`.${DISMISS_CLASS}`);
describe('initAlertHandler', () => {
describe('with one alert', () => {
beforeEach(() => {
- setHTMLFixture(ALERT_HTML);
+ setHTMLFixture(generateHtml(ALERT_CLASS));
initAlertHandler();
});
@@ -22,14 +30,14 @@ describe('Alert Handler', () => {
});
it('should dismiss the alert on click', () => {
- findFirstCloseButton().click();
+ findFirstDismissButton().click();
expect(findFirstAlert()).not.toExist();
});
});
describe('with two alerts', () => {
beforeEach(() => {
- setHTMLFixture(ALERT_HTML + ALERT_HTML);
+ setHTMLFixture(generateHtml(ALERT_CLASS) + generateHtml(ALERT_CLASS));
initAlertHandler();
});
@@ -38,9 +46,46 @@ describe('Alert Handler', () => {
});
it('should dismiss only one alert on click', () => {
- findFirstCloseButton().click();
+ findFirstDismissButton().click();
expect(findAllAlerts()).toHaveLength(1);
});
});
+
+ describe('with a dismissible banner', () => {
+ beforeEach(() => {
+ setHTMLFixture(generateHtml(BANNER_CLASS));
+ initAlertHandler();
+ });
+
+ it('should render the banner', () => {
+ expect(findFirstBanner()).toExist();
+ });
+
+ it('should dismiss the banner on click', () => {
+ findFirstDismissButton().click();
+ expect(findFirstBanner()).not.toExist();
+ });
+ });
+
+ // Dismiss buttons *should* have the correct aria labels, but some of them won't
+ // because legacy code isn't always a11y compliant.
+ // This tests that the fallback for the incorrectly labelled buttons works.
+ describe('with a mislabelled dismiss button', () => {
+ beforeEach(() => {
+ setHTMLFixture(`<div class="${ALERT_CLASS}">
+ <button class="${DISMISS_CLASS}">Dismiss</button>
+ </div>`);
+ initAlertHandler();
+ });
+
+ it('should render the banner', () => {
+ expect(findFirstAlert()).toExist();
+ });
+
+ it('should dismiss the banner on click', () => {
+ findFirstDismissButtonByClass().click();
+ expect(findFirstAlert()).not.toExist();
+ });
+ });
});
});
diff --git a/spec/frontend/alert_management/components/alert_details_spec.js b/spec/frontend/alert_management/components/alert_details_spec.js
index 8aa26dbca3b..f3ebdfc5cc2 100644
--- a/spec/frontend/alert_management/components/alert_details_spec.js
+++ b/spec/frontend/alert_management/components/alert_details_spec.js
@@ -1,54 +1,76 @@
-import { mount, shallowMount } from '@vue/test-utils';
import { GlAlert, GlLoadingIcon } from '@gitlab/ui';
+import { mount, shallowMount } from '@vue/test-utils';
import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
-import AlertDetailsTable from '~/vue_shared/components/alert_details_table.vue';
+import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import AlertDetails from '~/alert_management/components/alert_details.vue';
-import createIssueMutation from '~/alert_management/graphql/mutations/create_issue_from_alert.mutation.graphql';
-import { joinPaths } from '~/lib/utils/url_utility';
+import AlertSummaryRow from '~/alert_management/components/alert_summary_row.vue';
import {
- trackAlertsDetailsViewsOptions,
ALERTS_SEVERITY_LABELS,
+ trackAlertsDetailsViewsOptions,
} from '~/alert_management/constants';
+import createIssueMutation from '~/alert_management/graphql/mutations/create_issue_from_alert.mutation.graphql';
+import { joinPaths } from '~/lib/utils/url_utility';
import Tracking from '~/tracking';
+import AlertDetailsTable from '~/vue_shared/components/alert_details_table.vue';
import mockAlerts from '../mocks/alerts.json';
const mockAlert = mockAlerts[0];
+const environmentName = 'Production';
+const environmentPath = '/fake/path';
describe('AlertDetails', () => {
- let wrapper;
+ let environmentData = {
+ name: environmentName,
+ path: environmentPath,
+ };
+ let glFeatures = { exposeEnvironmentPathInAlertDetails: false };
let mock;
+ let wrapper;
const projectPath = 'root/alerts';
const projectIssuesPath = 'root/alerts/-/issues';
const projectId = '1';
const $router = { replace: jest.fn() };
function mountComponent({ data, loading = false, mountMethod = shallowMount, stubs = {} } = {}) {
- wrapper = mountMethod(AlertDetails, {
- provide: {
- alertId: 'alertId',
- projectPath,
- projectIssuesPath,
- projectId,
- },
- data() {
- return { alert: { ...mockAlert }, sidebarStatus: false, ...data };
- },
- mocks: {
- $apollo: {
- mutate: jest.fn(),
- queries: {
+ wrapper = extendedWrapper(
+ mountMethod(AlertDetails, {
+ provide: {
+ alertId: 'alertId',
+ projectPath,
+ projectIssuesPath,
+ projectId,
+ glFeatures,
+ },
+ data() {
+ return {
alert: {
- loading,
+ ...mockAlert,
+ environment: environmentData,
+ },
+ sidebarStatus: false,
+ ...data,
+ };
+ },
+ mocks: {
+ $apollo: {
+ mutate: jest.fn(),
+ queries: {
+ alert: {
+ loading,
+ },
+ sidebarStatus: {},
},
- sidebarStatus: {},
},
+ $router,
+ $route: { params: {} },
},
- $router,
- $route: { params: {} },
- },
- stubs,
- });
+ stubs: {
+ ...stubs,
+ AlertSummaryRow,
+ },
+ }),
+ );
}
beforeEach(() => {
@@ -62,9 +84,11 @@ describe('AlertDetails', () => {
mock.restore();
});
- const findCreateIncidentBtn = () => wrapper.find('[data-testid="createIncidentBtn"]');
- const findViewIncidentBtn = () => wrapper.find('[data-testid="viewIncidentBtn"]');
- const findIncidentCreationAlert = () => wrapper.find('[data-testid="incidentCreationError"]');
+ const findCreateIncidentBtn = () => wrapper.findByTestId('createIncidentBtn');
+ const findViewIncidentBtn = () => wrapper.findByTestId('viewIncidentBtn');
+ const findIncidentCreationAlert = () => wrapper.findByTestId('incidentCreationError');
+ const findEnvironmentName = () => wrapper.findByTestId('environmentName');
+ const findEnvironmentPath = () => wrapper.findByTestId('environmentPath');
const findDetailsTable = () => wrapper.find(AlertDetailsTable);
describe('Alert details', () => {
@@ -74,7 +98,7 @@ describe('AlertDetails', () => {
});
it('shows an empty state', () => {
- expect(wrapper.find('[data-testid="alertDetailsTabs"]').exists()).toBe(false);
+ expect(wrapper.findByTestId('alertDetailsTabs').exists()).toBe(false);
});
});
@@ -84,28 +108,26 @@ describe('AlertDetails', () => {
});
it('renders a tab with overview information', () => {
- expect(wrapper.find('[data-testid="overview"]').exists()).toBe(true);
+ expect(wrapper.findByTestId('overview').exists()).toBe(true);
});
it('renders a tab with an activity feed', () => {
- expect(wrapper.find('[data-testid="activity"]').exists()).toBe(true);
+ expect(wrapper.findByTestId('activity').exists()).toBe(true);
});
it('renders severity', () => {
- expect(wrapper.find('[data-testid="severity"]').text()).toBe(
+ expect(wrapper.findByTestId('severity').text()).toBe(
ALERTS_SEVERITY_LABELS[mockAlert.severity],
);
});
it('renders a title', () => {
- expect(wrapper.find('[data-testid="title"]').text()).toBe(mockAlert.title);
+ expect(wrapper.findByTestId('title').text()).toBe(mockAlert.title);
});
it('renders a start time', () => {
- expect(wrapper.find('[data-testid="startTimeItem"]').exists()).toBe(true);
- expect(wrapper.find('[data-testid="startTimeItem"]').props().time).toBe(
- mockAlert.startedAt,
- );
+ expect(wrapper.findByTestId('startTimeItem').exists()).toBe(true);
+ expect(wrapper.findByTestId('startTimeItem').props('time')).toBe(mockAlert.startedAt);
});
});
@@ -126,15 +148,47 @@ describe('AlertDetails', () => {
});
it(`${field} is ${isShown ? 'displayed' : 'hidden'} correctly`, () => {
+ const element = wrapper.findByTestId(field);
if (isShown) {
- expect(wrapper.find(`[data-testid="${field}"]`).text()).toBe(data.toString());
+ expect(element.text()).toContain(data.toString());
} else {
- expect(wrapper.find(`[data-testid="${field}"]`).exists()).toBe(false);
+ expect(wrapper.findByTestId(field).exists()).toBe(false);
}
});
});
});
+ describe('environment fields', () => {
+ describe('when exposeEnvironmentPathInAlertDetails is disabled', () => {
+ beforeEach(mountComponent);
+
+ it('should not show the environment', () => {
+ expect(findEnvironmentName().exists()).toBe(false);
+ expect(findEnvironmentPath().exists()).toBe(false);
+ });
+ });
+
+ describe('when exposeEnvironmentPathInAlertDetails is enabled', () => {
+ beforeEach(() => {
+ glFeatures = { exposeEnvironmentPathInAlertDetails: true };
+ mountComponent();
+ });
+
+ it('should show the environment name with link to path', () => {
+ expect(findEnvironmentName().exists()).toBe(false);
+ expect(findEnvironmentPath().text()).toBe(environmentName);
+ expect(findEnvironmentPath().attributes('href')).toBe(environmentPath);
+ });
+
+ it('should only show the environment name if the path is not provided', () => {
+ environmentData = { name: environmentName, path: null };
+ mountComponent();
+ expect(findEnvironmentPath().exists()).toBe(false);
+ expect(findEnvironmentName().text()).toBe(environmentName);
+ });
+ });
+ });
+
describe('Create incident from alert', () => {
it('should display "View incident" button that links the incident page when incident exists', () => {
const issueIid = '3';
@@ -222,7 +276,7 @@ describe('AlertDetails', () => {
mountComponent({
data: { errored: true, sidebarErrorMessage: '<span data-testid="htmlError" />' },
});
- expect(wrapper.find('[data-testid="htmlError"]').exists()).toBe(true);
+ expect(wrapper.findByTestId('htmlError').exists()).toBe(true);
});
it('does not display an error when dismissed', () => {
@@ -232,7 +286,7 @@ describe('AlertDetails', () => {
});
describe('header', () => {
- const findHeader = () => wrapper.find('[data-testid="alert-header"]');
+ const findHeader = () => wrapper.findByTestId('alert-header');
const stubs = { TimeAgoTooltip: { template: '<span>now</span>' } };
describe('individual header fields', () => {
diff --git a/spec/frontend/alert_management/components/alert_management_empty_state_spec.js b/spec/frontend/alert_management/components/alert_management_empty_state_spec.js
index 6712282503d..ddb102339cc 100644
--- a/spec/frontend/alert_management/components/alert_management_empty_state_spec.js
+++ b/spec/frontend/alert_management/components/alert_management_empty_state_spec.js
@@ -1,25 +1,17 @@
import { shallowMount } from '@vue/test-utils';
import { GlEmptyState } from '@gitlab/ui';
import AlertManagementEmptyState from '~/alert_management/components/alert_management_empty_state.vue';
+import defaultProvideValues from '../mocks/alerts_provide_config.json';
describe('AlertManagementEmptyState', () => {
let wrapper;
- function mountComponent({
- props = {
- alertManagementEnabled: false,
- userCanEnableAlertManagement: false,
- },
- stubs = {},
- } = {}) {
+ function mountComponent({ provide = {} } = {}) {
wrapper = shallowMount(AlertManagementEmptyState, {
- propsData: {
- enableAlertManagementPath: '/link',
- alertsHelpUrl: '/link',
- emptyAlertSvgPath: 'illustration/path',
- ...props,
+ provide: {
+ ...defaultProvideValues,
+ ...provide,
},
- stubs,
});
}
@@ -42,7 +34,7 @@ describe('AlertManagementEmptyState', () => {
it('show OpsGenie integration state when OpsGenie mcv is true', () => {
mountComponent({
- props: {
+ provide: {
alertManagementEnabled: false,
userCanEnableAlertManagement: false,
opsgenieMvcEnabled: true,
diff --git a/spec/frontend/alert_management/components/alert_management_list_wrapper_spec.js b/spec/frontend/alert_management/components/alert_management_list_wrapper_spec.js
index c36107c28ce..1d79b10a796 100644
--- a/spec/frontend/alert_management/components/alert_management_list_wrapper_spec.js
+++ b/spec/frontend/alert_management/components/alert_management_list_wrapper_spec.js
@@ -1,33 +1,18 @@
import { shallowMount } from '@vue/test-utils';
import AlertManagementList from '~/alert_management/components/alert_management_list_wrapper.vue';
-import { trackAlertListViewsOptions } from '~/alert_management/constants';
-import mockAlerts from '../mocks/alerts.json';
-import Tracking from '~/tracking';
+import AlertManagementEmptyState from '~/alert_management/components/alert_management_empty_state.vue';
+import AlertManagementTable from '~/alert_management/components/alert_management_table.vue';
+import defaultProvideValues from '../mocks/alerts_provide_config.json';
describe('AlertManagementList', () => {
let wrapper;
- function mountComponent({
- props = {
- alertManagementEnabled: false,
- userCanEnableAlertManagement: false,
- },
- data = {},
- stubs = {},
- } = {}) {
+ function mountComponent({ provide = {} } = {}) {
wrapper = shallowMount(AlertManagementList, {
- propsData: {
- projectPath: 'gitlab-org/gitlab',
- enableAlertManagementPath: '/link',
- alertsHelpUrl: '/link',
- populatingAlertsHelpUrl: '/help/help-page.md#populating-alert-data',
- emptyAlertSvgPath: 'illustration/path',
- ...props,
+ provide: {
+ ...defaultProvideValues,
+ ...provide,
},
- data() {
- return data;
- },
- stubs,
});
}
@@ -41,18 +26,21 @@ describe('AlertManagementList', () => {
}
});
- describe('Snowplow tracking', () => {
- beforeEach(() => {
- jest.spyOn(Tracking, 'event');
+ describe('Alert List Wrapper', () => {
+ it('should show the empty state when alerts are not enabled', () => {
+ expect(wrapper.find(AlertManagementEmptyState).exists()).toBe(true);
+ expect(wrapper.find(AlertManagementTable).exists()).toBe(false);
+ });
+
+ it('should show the alerts table when alerts are enabled', () => {
mountComponent({
- props: { alertManagementEnabled: true, userCanEnableAlertManagement: true },
- data: { alerts: { list: mockAlerts } },
+ provide: {
+ alertManagementEnabled: true,
+ },
});
- });
- it('should track alert list page views', () => {
- const { category, action } = trackAlertListViewsOptions;
- expect(Tracking.event).toHaveBeenCalledWith(category, action);
+ expect(wrapper.find(AlertManagementEmptyState).exists()).toBe(false);
+ expect(wrapper.find(AlertManagementTable).exists()).toBe(true);
});
});
});
diff --git a/spec/frontend/alert_management/components/alert_management_table_spec.js b/spec/frontend/alert_management/components/alert_management_table_spec.js
index bcad415eb19..f7a629142f9 100644
--- a/spec/frontend/alert_management/components/alert_management_table_spec.js
+++ b/spec/frontend/alert_management/components/alert_management_table_spec.js
@@ -1,26 +1,13 @@
import { mount } from '@vue/test-utils';
-import {
- GlTable,
- GlAlert,
- GlLoadingIcon,
- GlDeprecatedDropdown,
- GlDeprecatedDropdownItem,
- GlIcon,
- GlTabs,
- GlTab,
- GlBadge,
- GlPagination,
- GlSearchBoxByType,
- GlAvatar,
-} from '@gitlab/ui';
-import waitForPromises from 'helpers/wait_for_promises';
+import { GlTable, GlAlert, GlLoadingIcon, GlDropdown, GlIcon, GlAvatar } from '@gitlab/ui';
+import axios from 'axios';
+import MockAdapter from 'axios-mock-adapter';
import { visitUrl } from '~/lib/utils/url_utility';
import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue';
import AlertManagementTable from '~/alert_management/components/alert_management_table.vue';
-import { ALERTS_STATUS_TABS, trackAlertStatusUpdateOptions } from '~/alert_management/constants';
-import updateAlertStatus from '~/alert_management/graphql/mutations/update_alert_status.mutation.graphql';
+import FilteredSearchBar from '~/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue';
import mockAlerts from '../mocks/alerts.json';
-import Tracking from '~/tracking';
+import defaultProvideValues from '../mocks/alerts_provide_config.json';
jest.mock('~/lib/utils/url_utility', () => ({
visitUrl: jest.fn().mockName('visitUrlMock'),
@@ -29,26 +16,21 @@ jest.mock('~/lib/utils/url_utility', () => ({
describe('AlertManagementTable', () => {
let wrapper;
+ let mock;
const findAlertsTable = () => wrapper.find(GlTable);
const findAlerts = () => wrapper.findAll('table tbody tr');
const findAlert = () => wrapper.find(GlAlert);
const findLoader = () => wrapper.find(GlLoadingIcon);
- const findStatusDropdown = () => wrapper.find(GlDeprecatedDropdown);
- const findStatusFilterTabs = () => wrapper.findAll(GlTab);
- const findStatusTabs = () => wrapper.find(GlTabs);
- const findStatusFilterBadge = () => wrapper.findAll(GlBadge);
+ const findStatusDropdown = () => wrapper.find(GlDropdown);
const findDateFields = () => wrapper.findAll(TimeAgo);
- const findFirstStatusOption = () => findStatusDropdown().find(GlDeprecatedDropdownItem);
- const findPagination = () => wrapper.find(GlPagination);
- const findSearch = () => wrapper.find(GlSearchBoxByType);
+ const findSearch = () => wrapper.find(FilteredSearchBar);
const findSeverityColumnHeader = () =>
wrapper.find('[data-testid="alert-management-severity-sort"]');
const findFirstIDField = () => wrapper.findAll('[data-testid="idField"]').at(0);
const findAssignees = () => wrapper.findAll('[data-testid="assigneesField"]');
const findSeverityFields = () => wrapper.findAll('[data-testid="severityField"]');
const findIssueFields = () => wrapper.findAll('[data-testid="issueField"]');
- const findAlertError = () => wrapper.find('[data-testid="alert-error"]');
const alertsCount = {
open: 24,
triggered: 20,
@@ -56,26 +38,14 @@ describe('AlertManagementTable', () => {
resolved: 11,
all: 26,
};
- const selectFirstStatusOption = () => {
- findFirstStatusOption().vm.$emit('click');
- return waitForPromises();
- };
-
- function mountComponent({
- props = {
- alertManagementEnabled: false,
- userCanEnableAlertManagement: false,
- },
- data = {},
- loading = false,
- stubs = {},
- } = {}) {
+ function mountComponent({ provide = {}, data = {}, loading = false, stubs = {} } = {}) {
wrapper = mount(AlertManagementTable, {
- propsData: {
- projectPath: 'gitlab-org/gitlab',
- populatingAlertsHelpUrl: '/help/help-page.md#populating-alert-data',
- ...props,
+ provide: {
+ ...defaultProvideValues,
+ alertManagementEnabled: true,
+ userCanEnableAlertManagement: true,
+ ...provide,
},
data() {
return data;
@@ -95,41 +65,21 @@ describe('AlertManagementTable', () => {
});
}
+ beforeEach(() => {
+ mock = new MockAdapter(axios);
+ });
+
afterEach(() => {
if (wrapper) {
wrapper.destroy();
wrapper = null;
}
- });
-
- describe('Status Filter Tabs', () => {
- beforeEach(() => {
- mountComponent({
- props: { alertManagementEnabled: true, userCanEnableAlertManagement: true },
- data: { alerts: mockAlerts, alertsCount },
- loading: false,
- stubs: {
- GlTab: true,
- },
- });
- });
-
- it('should display filter tabs with alerts count badge for each status', () => {
- const tabs = findStatusFilterTabs().wrappers;
- const badges = findStatusFilterBadge();
-
- tabs.forEach((tab, i) => {
- const status = ALERTS_STATUS_TABS[i].status.toLowerCase();
- expect(tab.text()).toContain(ALERTS_STATUS_TABS[i].title);
- expect(badges.at(i).text()).toContain(alertsCount[status]);
- });
- });
+ mock.restore();
});
describe('Alerts table', () => {
it('loading state', () => {
mountComponent({
- props: { alertManagementEnabled: true, userCanEnableAlertManagement: true },
data: { alerts: {}, alertsCount: null },
loading: true,
});
@@ -144,8 +94,7 @@ describe('AlertManagementTable', () => {
it('error state', () => {
mountComponent({
- props: { alertManagementEnabled: true, userCanEnableAlertManagement: true },
- data: { alerts: { errors: ['error'] }, alertsCount: null, hasError: true },
+ data: { alerts: { errors: ['error'] }, alertsCount: null, errored: true },
loading: false,
});
expect(findAlertsTable().exists()).toBe(true);
@@ -161,10 +110,17 @@ describe('AlertManagementTable', () => {
it('empty state', () => {
mountComponent({
- props: { alertManagementEnabled: true, userCanEnableAlertManagement: true },
- data: { alerts: { list: [], pageInfo: {} }, alertsCount: { all: 0 }, hasError: false },
+ data: {
+ alerts: { list: [], pageInfo: {} },
+ alertsCount: { all: 0 },
+ errored: false,
+ isErrorAlertDismissed: false,
+ searchTerm: '',
+ assigneeUsername: '',
+ },
loading: false,
});
+
expect(findAlertsTable().exists()).toBe(true);
expect(findAlertsTable().text()).toContain('No alerts to display');
expect(findLoader().exists()).toBe(false);
@@ -178,8 +134,7 @@ describe('AlertManagementTable', () => {
it('has data state', () => {
mountComponent({
- props: { alertManagementEnabled: true, userCanEnableAlertManagement: true },
- data: { alerts: { list: mockAlerts }, alertsCount, hasError: false },
+ data: { alerts: { list: mockAlerts }, alertsCount, errored: false },
loading: false,
});
expect(findLoader().exists()).toBe(false);
@@ -194,8 +149,7 @@ describe('AlertManagementTable', () => {
it('displays the alert ID and title formatted correctly', () => {
mountComponent({
- props: { alertManagementEnabled: true, userCanEnableAlertManagement: true },
- data: { alerts: { list: mockAlerts }, alertsCount, hasError: false },
+ data: { alerts: { list: mockAlerts }, alertsCount, errored: false },
loading: false,
});
@@ -205,8 +159,7 @@ describe('AlertManagementTable', () => {
it('displays status dropdown', () => {
mountComponent({
- props: { alertManagementEnabled: true, userCanEnableAlertManagement: true },
- data: { alerts: { list: mockAlerts }, alertsCount, hasError: false },
+ data: { alerts: { list: mockAlerts }, alertsCount, errored: false },
loading: false,
});
expect(findStatusDropdown().exists()).toBe(true);
@@ -214,8 +167,7 @@ describe('AlertManagementTable', () => {
it('does not display a dropdown status header', () => {
mountComponent({
- props: { alertManagementEnabled: true, userCanEnableAlertManagement: true },
- data: { alerts: { list: mockAlerts }, alertsCount, hasError: false },
+ data: { alerts: { list: mockAlerts }, alertsCount, errored: false },
loading: false,
});
expect(
@@ -225,27 +177,25 @@ describe('AlertManagementTable', () => {
).toBe(false);
});
- it('shows correct severity icons', () => {
+ it('shows correct severity icons', async () => {
mountComponent({
- props: { alertManagementEnabled: true, userCanEnableAlertManagement: true },
- data: { alerts: { list: mockAlerts }, alertsCount, hasError: false },
+ data: { alerts: { list: mockAlerts }, alertsCount, errored: false },
loading: false,
});
- return wrapper.vm.$nextTick().then(() => {
- expect(wrapper.find(GlTable).exists()).toBe(true);
- expect(
- findAlertsTable()
- .find(GlIcon)
- .classes('icon-critical'),
- ).toBe(true);
- });
+ await wrapper.vm.$nextTick();
+
+ expect(wrapper.find(GlTable).exists()).toBe(true);
+ expect(
+ findAlertsTable()
+ .find(GlIcon)
+ .classes('icon-critical'),
+ ).toBe(true);
});
it('renders severity text', () => {
mountComponent({
- props: { alertManagementEnabled: true, userCanEnableAlertManagement: true },
- data: { alerts: { list: mockAlerts }, alertsCount, hasError: false },
+ data: { alerts: { list: mockAlerts }, alertsCount, errored: false },
loading: false,
});
@@ -258,8 +208,7 @@ describe('AlertManagementTable', () => {
it('renders Unassigned when no assignee(s) present', () => {
mountComponent({
- props: { alertManagementEnabled: true, userCanEnableAlertManagement: true },
- data: { alerts: { list: mockAlerts }, alertsCount, hasError: false },
+ data: { alerts: { list: mockAlerts }, alertsCount, errored: false },
loading: false,
});
@@ -272,8 +221,7 @@ describe('AlertManagementTable', () => {
it('renders user avatar when assignee present', () => {
mountComponent({
- props: { alertManagementEnabled: true, userCanEnableAlertManagement: true },
- data: { alerts: { list: mockAlerts }, alertsCount, hasError: false },
+ data: { alerts: { list: mockAlerts }, alertsCount, errored: false },
loading: false,
});
@@ -290,22 +238,39 @@ describe('AlertManagementTable', () => {
it('navigates to the detail page when alert row is clicked', () => {
mountComponent({
- props: { alertManagementEnabled: true, userCanEnableAlertManagement: true },
- data: { alerts: { list: mockAlerts }, alertsCount, hasError: false },
+ data: { alerts: { list: mockAlerts }, alertsCount, errored: false },
loading: false,
});
+ expect(visitUrl).not.toHaveBeenCalled();
+
findAlerts()
.at(0)
.trigger('click');
- expect(visitUrl).toHaveBeenCalledWith('/1527542/details');
+ expect(visitUrl).toHaveBeenCalledWith('/1527542/details', false);
+ });
+
+ it('navigates to the detail page in new tab when alert row is clicked with the metaKey', () => {
+ mountComponent({
+ data: { alerts: { list: mockAlerts }, alertsCount, errored: false },
+ loading: false,
+ });
+
+ expect(visitUrl).not.toHaveBeenCalled();
+
+ findAlerts()
+ .at(0)
+ .trigger('click', {
+ metaKey: true,
+ });
+
+ expect(visitUrl).toHaveBeenCalledWith('/1527542/details', true);
});
describe('alert issue links', () => {
beforeEach(() => {
mountComponent({
- props: { alertManagementEnabled: true, userCanEnableAlertManagement: true },
- data: { alerts: { list: mockAlerts }, alertsCount, hasError: false },
+ data: { alerts: { list: mockAlerts }, alertsCount, errored: false },
loading: false,
});
});
@@ -335,7 +300,6 @@ describe('AlertManagementTable', () => {
describe('handle date fields', () => {
it('should display time ago dates when values provided', () => {
mountComponent({
- props: { alertManagementEnabled: true, userCanEnableAlertManagement: true },
data: {
alerts: {
list: [
@@ -349,7 +313,7 @@ describe('AlertManagementTable', () => {
],
},
alertsCount,
- hasError: false,
+ errored: false,
},
loading: false,
});
@@ -358,7 +322,6 @@ describe('AlertManagementTable', () => {
it('should not display time ago dates when values not provided', () => {
mountComponent({
- props: { alertManagementEnabled: true, userCanEnableAlertManagement: true },
data: {
alerts: [
{
@@ -369,7 +332,7 @@ describe('AlertManagementTable', () => {
},
],
alertsCount,
- hasError: false,
+ errored: false,
},
loading: false,
});
@@ -383,8 +346,7 @@ describe('AlertManagementTable', () => {
it('should highlight the row when alert is new', () => {
mountComponent({
- props: { alertManagementEnabled: true, userCanEnableAlertManagement: true },
- data: { alerts: { list: [newAlert] }, alertsCount, hasError: false },
+ data: { alerts: { list: [newAlert] }, alertsCount, errored: false },
loading: false,
});
@@ -397,8 +359,7 @@ describe('AlertManagementTable', () => {
it('should not highlight the row when alert is not new', () => {
mountComponent({
- props: { alertManagementEnabled: true, userCanEnableAlertManagement: true },
- data: { alerts: { list: [oldAlert] }, alertsCount, hasError: false },
+ data: { alerts: { list: [oldAlert] }, alertsCount, errored: false },
loading: false,
});
@@ -415,10 +376,9 @@ describe('AlertManagementTable', () => {
describe('sorting the alert list by column', () => {
beforeEach(() => {
mountComponent({
- props: { alertManagementEnabled: true, userCanEnableAlertManagement: true },
data: {
alerts: { list: mockAlerts },
- hasError: false,
+ errored: false,
sort: 'STARTED_AT_DESC',
alertsCount,
},
@@ -438,184 +398,10 @@ describe('AlertManagementTable', () => {
});
});
- describe('updating the alert status', () => {
- const iid = '1527542';
- const mockUpdatedMutationResult = {
- data: {
- updateAlertStatus: {
- errors: [],
- alert: {
- iid,
- status: 'acknowledged',
- },
- },
- },
- };
-
- beforeEach(() => {
- mountComponent({
- props: { alertManagementEnabled: true, userCanEnableAlertManagement: true },
- data: { alerts: { list: mockAlerts }, alertsCount, hasError: false },
- loading: false,
- });
- });
-
- it('calls `$apollo.mutate` with `updateAlertStatus` mutation and variables containing `iid`, `status`, & `projectPath`', () => {
- jest.spyOn(wrapper.vm.$apollo, 'mutate').mockResolvedValue(mockUpdatedMutationResult);
- findFirstStatusOption().vm.$emit('click');
-
- expect(wrapper.vm.$apollo.mutate).toHaveBeenCalledWith({
- mutation: updateAlertStatus,
- variables: {
- iid,
- status: 'TRIGGERED',
- projectPath: 'gitlab-org/gitlab',
- },
- });
- });
-
- describe('when a request fails', () => {
- beforeEach(() => {
- jest.spyOn(wrapper.vm.$apollo, 'mutate').mockReturnValue(Promise.reject(new Error()));
- });
-
- it('shows an error', async () => {
- await selectFirstStatusOption();
-
- expect(findAlertError().text()).toContain(
- 'There was an error while updating the status of the alert.',
- );
- });
-
- it('shows an error when triggered a second time', async () => {
- await selectFirstStatusOption();
-
- wrapper.find(GlAlert).vm.$emit('dismiss');
-
- await wrapper.vm.$nextTick();
-
- // Assert that the error has been dismissed in the setup
- expect(findAlertError().exists()).toBe(false);
-
- await selectFirstStatusOption();
-
- expect(findAlertError().exists()).toBe(true);
- });
- });
-
- it('shows an error when response includes HTML errors', async () => {
- const mockUpdatedMutationErrorResult = {
- data: {
- updateAlertStatus: {
- errors: ['<span data-testid="htmlError" />'],
- alert: {
- iid,
- status: 'acknowledged',
- },
- },
- },
- };
-
- jest.spyOn(wrapper.vm.$apollo, 'mutate').mockResolvedValue(mockUpdatedMutationErrorResult);
-
- await selectFirstStatusOption();
-
- expect(findAlertError().exists()).toBe(true);
- expect(
- findAlertError()
- .find('[data-testid="htmlError"]')
- .exists(),
- ).toBe(true);
- });
- });
-
- describe('Snowplow tracking', () => {
- beforeEach(() => {
- jest.spyOn(Tracking, 'event');
- mountComponent({
- props: { alertManagementEnabled: true, userCanEnableAlertManagement: true },
- data: { alerts: { list: mockAlerts }, alertsCount },
- loading: false,
- });
- });
-
- it('should track alert status updates', () => {
- Tracking.event.mockClear();
- jest.spyOn(wrapper.vm.$apollo, 'mutate').mockResolvedValue({});
- findFirstStatusOption().vm.$emit('click');
- const status = findFirstStatusOption().text();
- setImmediate(() => {
- const { category, action, label } = trackAlertStatusUpdateOptions;
- expect(Tracking.event).toHaveBeenCalledWith(category, action, { label, property: status });
- });
- });
- });
-
- describe('Pagination', () => {
- beforeEach(() => {
- mountComponent({
- props: { alertManagementEnabled: true, userCanEnableAlertManagement: true },
- data: { alerts: { list: mockAlerts, pageInfo: {} }, alertsCount, hasError: false },
- loading: false,
- });
- });
-
- it('does NOT show pagination control when list is smaller than default page size', () => {
- findStatusTabs().vm.$emit('input', 3);
- return wrapper.vm.$nextTick(() => {
- expect(findPagination().exists()).toBe(false);
- });
- });
-
- it('shows pagination control when list is larger than default page size', () => {
- findStatusTabs().vm.$emit('input', 0);
- return wrapper.vm.$nextTick(() => {
- expect(findPagination().exists()).toBe(true);
- });
- });
-
- describe('prevPage', () => {
- it('returns prevPage number', () => {
- findPagination().vm.$emit('input', 3);
-
- return wrapper.vm.$nextTick(() => {
- expect(wrapper.vm.prevPage).toBe(2);
- });
- });
-
- it('returns 0 when it is the first page', () => {
- findPagination().vm.$emit('input', 1);
-
- return wrapper.vm.$nextTick(() => {
- expect(wrapper.vm.prevPage).toBe(0);
- });
- });
- });
-
- describe('nextPage', () => {
- it('returns nextPage number', () => {
- findPagination().vm.$emit('input', 1);
-
- return wrapper.vm.$nextTick(() => {
- expect(wrapper.vm.nextPage).toBe(2);
- });
- });
-
- it('returns `null` when currentPage is already last page', () => {
- findStatusTabs().vm.$emit('input', 3);
- findPagination().vm.$emit('input', 1);
- return wrapper.vm.$nextTick(() => {
- expect(wrapper.vm.nextPage).toBeNull();
- });
- });
- });
- });
-
describe('Search', () => {
beforeEach(() => {
mountComponent({
- props: { alertManagementEnabled: true, userCanEnableAlertManagement: true },
- data: { alerts: { list: mockAlerts }, alertsCount, hasError: false },
+ data: { alerts: { list: mockAlerts }, alertsCount, errored: false },
loading: false,
});
});
@@ -623,13 +409,5 @@ describe('AlertManagementTable', () => {
it('renders the search component', () => {
expect(findSearch().exists()).toBe(true);
});
-
- it('sets the `searchTerm` graphql variable', () => {
- const SEARCH_TERM = 'Simple Alert';
-
- findSearch().vm.$emit('input', SEARCH_TERM);
-
- expect(wrapper.vm.$data.searchTerm).toBe(SEARCH_TERM);
- });
});
});
diff --git a/spec/frontend/alert_management/components/alert_status_spec.js b/spec/frontend/alert_management/components/alert_status_spec.js
new file mode 100644
index 00000000000..f5916b8b265
--- /dev/null
+++ b/spec/frontend/alert_management/components/alert_status_spec.js
@@ -0,0 +1,151 @@
+import { shallowMount } from '@vue/test-utils';
+import { GlDropdown, GlDropdownItem } from '@gitlab/ui';
+import waitForPromises from 'helpers/wait_for_promises';
+import { trackAlertStatusUpdateOptions } from '~/alert_management/constants';
+import AlertManagementStatus from '~/alert_management/components/alert_status.vue';
+import updateAlertStatusMutation from '~/alert_management/graphql/mutations/update_alert_status.mutation.graphql';
+import Tracking from '~/tracking';
+import mockAlerts from '../mocks/alerts.json';
+
+const mockAlert = mockAlerts[0];
+
+describe('AlertManagementStatus', () => {
+ let wrapper;
+ const findStatusDropdown = () => wrapper.find(GlDropdown);
+ const findFirstStatusOption = () => findStatusDropdown().find(GlDropdownItem);
+
+ const selectFirstStatusOption = () => {
+ findFirstStatusOption().vm.$emit('click');
+
+ return waitForPromises();
+ };
+
+ function mountComponent({ props = {}, loading = false, stubs = {} } = {}) {
+ wrapper = shallowMount(AlertManagementStatus, {
+ propsData: {
+ alert: { ...mockAlert },
+ projectPath: 'gitlab-org/gitlab',
+ isSidebar: false,
+ ...props,
+ },
+ mocks: {
+ $apollo: {
+ mutate: jest.fn(),
+ queries: {
+ alert: {
+ loading,
+ },
+ },
+ },
+ },
+ stubs,
+ });
+ }
+
+ beforeEach(() => {
+ mountComponent();
+ });
+
+ afterEach(() => {
+ if (wrapper) {
+ wrapper.destroy();
+ wrapper = null;
+ }
+ });
+
+ describe('updating the alert status', () => {
+ const iid = '1527542';
+ const mockUpdatedMutationResult = {
+ data: {
+ updateAlertStatus: {
+ errors: [],
+ alert: {
+ iid,
+ status: 'acknowledged',
+ },
+ },
+ },
+ };
+
+ beforeEach(() => {
+ mountComponent({});
+ });
+
+ it('calls `$apollo.mutate` with `updateAlertStatus` mutation and variables containing `iid`, `status`, & `projectPath`', () => {
+ jest.spyOn(wrapper.vm.$apollo, 'mutate').mockResolvedValue(mockUpdatedMutationResult);
+ findFirstStatusOption().vm.$emit('click');
+
+ expect(wrapper.vm.$apollo.mutate).toHaveBeenCalledWith({
+ mutation: updateAlertStatusMutation,
+ variables: {
+ iid,
+ status: 'TRIGGERED',
+ projectPath: 'gitlab-org/gitlab',
+ },
+ });
+ });
+
+ describe('when a request fails', () => {
+ beforeEach(() => {
+ jest.spyOn(wrapper.vm.$apollo, 'mutate').mockReturnValue(Promise.reject(new Error()));
+ });
+
+ it('emits an error', async () => {
+ await selectFirstStatusOption();
+
+ expect(wrapper.emitted('alert-error')[0]).toEqual([
+ 'There was an error while updating the status of the alert. Please try again.',
+ ]);
+ });
+
+ it('emits an error when triggered a second time', async () => {
+ await selectFirstStatusOption();
+ await wrapper.vm.$nextTick();
+ await selectFirstStatusOption();
+ // Should emit two errors [0,1]
+ expect(wrapper.emitted('alert-error').length > 1).toBe(true);
+ });
+ });
+
+ it('shows an error when response includes HTML errors', async () => {
+ const mockUpdatedMutationErrorResult = {
+ data: {
+ updateAlertStatus: {
+ errors: ['<span data-testid="htmlError" />'],
+ alert: {
+ iid,
+ status: 'acknowledged',
+ },
+ },
+ },
+ };
+
+ jest.spyOn(wrapper.vm.$apollo, 'mutate').mockResolvedValue(mockUpdatedMutationErrorResult);
+
+ await selectFirstStatusOption();
+
+ expect(wrapper.emitted('alert-error').length > 0).toBe(true);
+ expect(wrapper.emitted('alert-error')[0]).toEqual([
+ 'There was an error while updating the status of the alert. <span data-testid="htmlError" />',
+ ]);
+ });
+ });
+
+ describe('Snowplow tracking', () => {
+ beforeEach(() => {
+ jest.spyOn(Tracking, 'event');
+ mountComponent({});
+ });
+
+ it('should track alert status updates', () => {
+ Tracking.event.mockClear();
+ jest.spyOn(wrapper.vm.$apollo, 'mutate').mockResolvedValue({});
+ findFirstStatusOption().vm.$emit('click');
+ const status = findFirstStatusOption().text();
+ setImmediate(() => {
+ const { category, action, label } = trackAlertStatusUpdateOptions;
+ expect(Tracking.event).toHaveBeenCalledWith(category, action, { label, property: status });
+ });
+ });
+ });
+});
diff --git a/spec/frontend/alert_management/components/alert_summary_row_spec.js b/spec/frontend/alert_management/components/alert_summary_row_spec.js
new file mode 100644
index 00000000000..47c715c089a
--- /dev/null
+++ b/spec/frontend/alert_management/components/alert_summary_row_spec.js
@@ -0,0 +1,40 @@
+import { shallowMount } from '@vue/test-utils';
+import AlertSummaryRow from '~/alert_management/components/alert_summary_row.vue';
+
+const label = 'a label';
+const value = 'a value';
+
+describe('AlertSummaryRow', () => {
+ let wrapper;
+
+ function mountComponent({ mountMethod = shallowMount, props, defaultSlot } = {}) {
+ wrapper = mountMethod(AlertSummaryRow, {
+ propsData: props,
+ scopedSlots: {
+ default: defaultSlot,
+ },
+ });
+ }
+
+ afterEach(() => {
+ if (wrapper) {
+ wrapper.destroy();
+ wrapper = null;
+ }
+ });
+
+ describe('Alert Summary Row', () => {
+ beforeEach(() => {
+ mountComponent({
+ props: {
+ label,
+ },
+ defaultSlot: `<span class="value">${value}</span>`,
+ });
+ });
+
+ it('should display a label and a value', () => {
+ expect(wrapper.text()).toBe(`${label} ${value}`);
+ });
+ });
+});
diff --git a/spec/frontend/alert_management/components/sidebar/alert_managment_sidebar_assignees_spec.js b/spec/frontend/alert_management/components/sidebar/alert_managment_sidebar_assignees_spec.js
index 4c9db02eff4..1d87301aac9 100644
--- a/spec/frontend/alert_management/components/sidebar/alert_managment_sidebar_assignees_spec.js
+++ b/spec/frontend/alert_management/components/sidebar/alert_managment_sidebar_assignees_spec.js
@@ -1,7 +1,7 @@
import { shallowMount } from '@vue/test-utils';
import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
-import { GlDeprecatedDropdownItem } from '@gitlab/ui';
+import { GlDropdownItem } from '@gitlab/ui';
import SidebarAssignee from '~/alert_management/components/sidebar/sidebar_assignee.vue';
import SidebarAssignees from '~/alert_management/components/sidebar/sidebar_assignees.vue';
import AlertSetAssignees from '~/alert_management/graphql/mutations/alert_set_assignees.mutation.graphql';
@@ -106,7 +106,7 @@ describe('Alert Details Sidebar Assignees', () => {
it('renders a unassigned option', async () => {
wrapper.setData({ isDropdownSearching: false });
await wrapper.vm.$nextTick();
- expect(wrapper.find(GlDeprecatedDropdownItem).text()).toBe('Unassigned');
+ expect(wrapper.find(GlDropdownItem).text()).toBe('Unassigned');
});
it('calls `$apollo.mutate` with `AlertSetAssignees` mutation and variables containing `iid`, `assigneeUsernames`, & `projectPath`', async () => {
diff --git a/spec/frontend/alert_management/components/sidebar/alert_sidebar_status_spec.js b/spec/frontend/alert_management/components/sidebar/alert_sidebar_status_spec.js
index a8fe40687e1..bef4a341985 100644
--- a/spec/frontend/alert_management/components/sidebar/alert_sidebar_status_spec.js
+++ b/spec/frontend/alert_management/components/sidebar/alert_sidebar_status_spec.js
@@ -1,8 +1,8 @@
import { mount } from '@vue/test-utils';
-import { GlDeprecatedDropdown, GlDeprecatedDropdownItem, GlLoadingIcon } from '@gitlab/ui';
+import { GlDropdown, GlDropdownItem, GlLoadingIcon } from '@gitlab/ui';
import { trackAlertStatusUpdateOptions } from '~/alert_management/constants';
import AlertSidebarStatus from '~/alert_management/components/sidebar/sidebar_status.vue';
-import updateAlertStatus from '~/alert_management/graphql/mutations/update_alert_status.mutation.graphql';
+import updateAlertStatusMutation from '~/alert_management/graphql/mutations/update_alert_status.mutation.graphql';
import Tracking from '~/tracking';
import mockAlerts from '../../mocks/alerts.json';
@@ -10,9 +10,10 @@ const mockAlert = mockAlerts[0];
describe('Alert Details Sidebar Status', () => {
let wrapper;
- const findStatusDropdown = () => wrapper.find(GlDeprecatedDropdown);
- const findStatusDropdownItem = () => wrapper.find(GlDeprecatedDropdownItem);
+ const findStatusDropdown = () => wrapper.find(GlDropdown);
+ const findStatusDropdownItem = () => wrapper.find(GlDropdownItem);
const findStatusLoadingIcon = () => wrapper.find(GlLoadingIcon);
+ const findStatusDropdownHeader = () => wrapper.find('[data-testid="dropdown-header"]');
function mountComponent({ data, sidebarCollapsed = true, loading = false, stubs = {} } = {}) {
wrapper = mount(AlertSidebarStatus, {
@@ -56,11 +57,7 @@ describe('Alert Details Sidebar Status', () => {
});
it('displays the dropdown status header', () => {
- expect(
- findStatusDropdown()
- .find('.dropdown-title')
- .exists(),
- ).toBe(true);
+ expect(findStatusDropdownHeader().exists()).toBe(true);
});
describe('updating the alert status', () => {
@@ -88,7 +85,7 @@ describe('Alert Details Sidebar Status', () => {
findStatusDropdownItem().vm.$emit('click');
expect(wrapper.vm.$apollo.mutate).toHaveBeenCalledWith({
- mutation: updateAlertStatus,
+ mutation: updateAlertStatusMutation,
variables: {
iid: '1527542',
status: 'TRIGGERED',
diff --git a/spec/frontend/alert_management/components/system_notes/alert_management_system_note_spec.js b/spec/frontend/alert_management/components/system_notes/alert_management_system_note_spec.js
index 8dd663e55d9..65cfc600d76 100644
--- a/spec/frontend/alert_management/components/system_notes/alert_management_system_note_spec.js
+++ b/spec/frontend/alert_management/components/system_notes/alert_management_system_note_spec.js
@@ -1,4 +1,5 @@
import { shallowMount } from '@vue/test-utils';
+import { GlIcon } from '@gitlab/ui';
import SystemNote from '~/alert_management/components/system_notes/system_note.vue';
import mockAlerts from '../../mocks/alerts.json';
@@ -19,6 +20,7 @@ describe('Alert Details System Note', () => {
afterEach(() => {
if (wrapper) {
wrapper.destroy();
+ wrapper = null;
}
});
@@ -29,10 +31,10 @@ describe('Alert Details System Note', () => {
it('renders the correct system note', () => {
const noteId = wrapper.find('.note-wrapper').attributes('id');
- const iconRoute = wrapper.find('use').attributes('href');
+ const iconName = wrapper.find(GlIcon).attributes('name');
expect(noteId).toBe('note_1628');
- expect(iconRoute.includes('user')).toBe(true);
+ expect(iconName).toBe(mockAlert.notes.nodes[0].systemNoteIconName);
});
});
});
diff --git a/spec/frontend/alert_management/mocks/alerts_provide_config.json b/spec/frontend/alert_management/mocks/alerts_provide_config.json
new file mode 100644
index 00000000000..af543e641bc
--- /dev/null
+++ b/spec/frontend/alert_management/mocks/alerts_provide_config.json
@@ -0,0 +1,13 @@
+{
+ "textQuery": "foo",
+ "authorUsernameQuery": "root",
+ "assigneeUsernameQuery": "root",
+ "projectPath": "gitlab-org/gitlab",
+ "enableAlertManagementPath": "/link",
+ "populatingAlertsHelpUrl": "/link",
+ "emptyAlertSvgPath": "/link",
+ "alertManagementEnabled": false,
+ "userCanEnableAlertManagement": false,
+ "opsgenieMvcTargetUrl": "/link",
+ "opsgenieMvcEnabled": false
+} \ No newline at end of file
diff --git a/spec/frontend/alert_settings/__snapshots__/alert_settings_form_spec.js.snap b/spec/frontend/alert_settings/__snapshots__/alert_settings_form_spec.js.snap
index 16e92bf505a..5800b160efe 100644
--- a/spec/frontend/alert_settings/__snapshots__/alert_settings_form_spec.js.snap
+++ b/spec/frontend/alert_settings/__snapshots__/alert_settings_form_spec.js.snap
@@ -2,48 +2,48 @@
exports[`AlertsSettingsForm with default values renders the initial template 1`] = `
"<div>
- <!---->
- <div data-testid=\\"alert-settings-description\\" class=\\"gl-mt-5\\">
- <p>
- <gl-sprintf-stub message=\\"You must provide this URL and authorization key to authorize an external service to send alerts to GitLab. You can provide this URL and key to multiple services. After configuring an external service, alerts from your service will display on the GitLab %{linkStart}Alerts%{linkEnd} page.\\"></gl-sprintf-stub>
- </p>
- <p>
- <gl-sprintf-stub message=\\"Review your external service's documentation to learn where to provide this information to your external service, and the %{linkStart}GitLab documentation%{linkEnd} to learn more about configuring your endpoint.\\"></gl-sprintf-stub>
- </p>
- </div>
+ <integrations-list-stub integrations=\\"[object Object],[object Object]\\"></integrations-list-stub>
<gl-form-stub>
- <gl-form-group-stub label=\\"Integrations\\" label-for=\\"integrations\\" label-class=\\"label-bold\\">
- <gl-form-select-stub options=\\"[object Object],[object Object],[object Object]\\" data-testid=\\"alert-settings-select\\" value=\\"generic\\"></gl-form-select-stub> <span class=\\"gl-text-gray-200\\"><gl-sprintf-stub message=\\"Learn more about our %{linkStart}upcoming integrations%{linkEnd}\\"></gl-sprintf-stub></span>
+ <h5 class=\\"gl-font-lg gl-my-5\\">Add new integrations</h5>
+ <!---->
+ <div data-testid=\\"alert-settings-description\\">
+ <p>
+ <gl-sprintf-stub message=\\"You must provide this URL and authorization key to authorize an external service to send alerts to GitLab. You can provide this URL and key to multiple services. After configuring an external service, alerts from your service will display on the GitLab %{linkStart}Alerts%{linkEnd} page.\\"></gl-sprintf-stub>
+ </p>
+ <p>
+ <gl-sprintf-stub message=\\"Review your external service's documentation to learn where to provide this information to your external service, and the %{linkStart}GitLab documentation%{linkEnd} to learn more about configuring your endpoint.\\"></gl-sprintf-stub>
+ </p>
+ </div>
+ <gl-form-group-stub label-for=\\"integration-type\\" label=\\"Integration\\">
+ <gl-form-select-stub id=\\"integration-type\\" options=\\"[object Object],[object Object],[object Object]\\" data-testid=\\"alert-settings-select\\" value=\\"generic\\"></gl-form-select-stub> <span class=\\"gl-text-gray-500\\"><gl-sprintf-stub message=\\"Learn more about our improvements for %{linkStart}integrations%{linkEnd}\\"></gl-sprintf-stub></span>
</gl-form-group-stub>
- <gl-form-group-stub label=\\"Active\\" label-for=\\"activated\\" label-class=\\"label-bold\\">
+ <gl-form-group-stub label=\\"Active\\" label-for=\\"activated\\">
<toggle-button-stub id=\\"activated\\"></toggle-button-stub>
</gl-form-group-stub>
<!---->
- <gl-form-group-stub label=\\"Webhook URL\\" label-for=\\"url\\" label-class=\\"label-bold\\">
- <gl-form-input-group-stub value=\\"/alerts/notify.json\\" predefinedoptions=\\"[object Object]\\" id=\\"url\\" readonly=\\"\\"></gl-form-input-group-stub> <span class=\\"gl-text-gray-200\\">
+ <gl-form-group-stub label=\\"Webhook URL\\" label-for=\\"url\\">
+ <gl-form-input-group-stub value=\\"/alerts/notify.json\\" predefinedoptions=\\"[object Object]\\" id=\\"url\\" readonly=\\"\\"></gl-form-input-group-stub> <span class=\\"gl-text-gray-500\\">
</span>
</gl-form-group-stub>
- <gl-form-group-stub label=\\"Authorization key\\" label-for=\\"authorization-key\\" label-class=\\"label-bold\\">
+ <gl-form-group-stub label=\\"Authorization key\\" label-for=\\"authorization-key\\">
<gl-form-input-group-stub value=\\"abcedfg123\\" predefinedoptions=\\"[object Object]\\" id=\\"authorization-key\\" readonly=\\"\\" class=\\"gl-mb-2\\"></gl-form-input-group-stub>
- <gl-button-stub category=\\"primary\\" variant=\\"default\\" size=\\"medium\\" icon=\\"\\" disabled=\\"true\\" class=\\"gl-mt-3\\" role=\\"button\\" tabindex=\\"0\\">Reset key</gl-button-stub>
+ <gl-button-stub category=\\"primary\\" variant=\\"default\\" size=\\"medium\\" icon=\\"\\" buttontextclasses=\\"\\" disabled=\\"true\\" class=\\"gl-mt-3\\" role=\\"button\\" tabindex=\\"0\\">Reset key</gl-button-stub>
<gl-modal-stub modalid=\\"authKeyModal\\" titletag=\\"h4\\" modalclass=\\"\\" size=\\"md\\" title=\\"Reset key\\" ok-title=\\"Reset key\\" ok-variant=\\"danger\\">
Resetting the authorization key for this project will require updating the authorization key in every alert source it is enabled in.
</gl-modal-stub>
</gl-form-group-stub>
- <gl-form-group-stub label=\\"Alert test payload\\" label-for=\\"alert-json\\" label-class=\\"label-bold\\">
+ <gl-form-group-stub label=\\"Alert test payload\\" label-for=\\"alert-json\\">
<gl-form-textarea-stub noresize=\\"true\\" id=\\"alert-json\\" disabled=\\"true\\" state=\\"true\\" placeholder=\\"Enter test alert JSON....\\" rows=\\"6\\" max-rows=\\"10\\"></gl-form-textarea-stub>
</gl-form-group-stub>
- <div class=\\"gl-display-flex gl-justify-content-end\\">
- <gl-button-stub category=\\"primary\\" variant=\\"default\\" size=\\"medium\\" icon=\\"\\" disabled=\\"true\\">Test alert payload</gl-button-stub>
- </div>
+ <gl-button-stub category=\\"primary\\" variant=\\"default\\" size=\\"medium\\" icon=\\"\\" buttontextclasses=\\"\\" disabled=\\"true\\">Test alert payload</gl-button-stub>
<div class=\\"footer-block row-content-block gl-display-flex gl-justify-content-space-between\\">
- <gl-button-stub category=\\"primary\\" variant=\\"default\\" size=\\"medium\\" icon=\\"\\" disabled=\\"true\\">
- Cancel
- </gl-button-stub>
- <gl-button-stub category=\\"primary\\" variant=\\"success\\" size=\\"medium\\" icon=\\"\\" disabled=\\"true\\">
+ <gl-button-stub category=\\"primary\\" variant=\\"success\\" size=\\"medium\\" icon=\\"\\" buttontextclasses=\\"\\" disabled=\\"true\\">
Save changes
</gl-button-stub>
+ <gl-button-stub category=\\"primary\\" variant=\\"default\\" size=\\"medium\\" icon=\\"\\" buttontextclasses=\\"\\" disabled=\\"true\\">
+ Cancel
+ </gl-button-stub>
</div>
</gl-form-stub>
</div>"
diff --git a/spec/frontend/alert_settings/alert_settings_form_spec.js b/spec/frontend/alert_settings/alert_settings_form_spec.js
index 87a631bda56..6e1ea31ed6a 100644
--- a/spec/frontend/alert_settings/alert_settings_form_spec.js
+++ b/spec/frontend/alert_settings/alert_settings_form_spec.js
@@ -1,9 +1,12 @@
-import axios from 'axios';
-import MockAdapter from 'axios-mock-adapter';
import { shallowMount } from '@vue/test-utils';
import { GlModal, GlAlert } from '@gitlab/ui';
import AlertsSettingsForm from '~/alerts_settings/components/alerts_settings_form.vue';
+import IntegrationsList from '~/alerts_settings/components/alerts_integrations_list.vue';
import ToggleButton from '~/vue_shared/components/toggle_button.vue';
+import { i18n } from '~/alerts_settings/constants';
+import service from '~/alerts_settings/services';
+
+jest.mock('~/alerts_settings/services');
const PROMETHEUS_URL = '/prometheus/alerts/notify.json';
const GENERIC_URL = '/alerts/notify.json';
@@ -13,7 +16,6 @@ const ACTIVATED = false;
describe('AlertsSettingsForm', () => {
let wrapper;
- let mockAxios;
const createComponent = ({ methods } = {}, data) => {
wrapper = shallowMount(AlertsSettingsForm, {
@@ -53,7 +55,6 @@ describe('AlertsSettingsForm', () => {
const findApiUrl = () => wrapper.find('#api-url');
beforeEach(() => {
- mockAxios = new MockAdapter(axios);
setFixtures(`
<div>
<span class="js-service-active-status fa fa-circle" data-value="true"></span>
@@ -63,7 +64,6 @@ describe('AlertsSettingsForm', () => {
afterEach(() => {
wrapper.destroy();
- mockAxios.restore();
});
describe('with default values', () => {
@@ -76,6 +76,11 @@ describe('AlertsSettingsForm', () => {
});
});
+ it('renders alerts integrations list', () => {
+ createComponent();
+ expect(wrapper.find(IntegrationsList).exists()).toBe(true);
+ });
+
describe('reset key', () => {
it('triggers resetKey method', () => {
const resetKey = jest.fn();
@@ -99,8 +104,7 @@ describe('AlertsSettingsForm', () => {
});
it('shows a alert message on error', () => {
- const formPath = 'some/path';
- mockAxios.onPut(formPath).replyOnce(404);
+ service.updateGenericKey.mockRejectedValueOnce({});
createComponent();
@@ -122,8 +126,7 @@ describe('AlertsSettingsForm', () => {
describe('error is encountered', () => {
it('restores previous value', () => {
- const formPath = 'some/path';
- mockAxios.onPut(formPath).replyOnce(500);
+ service.updateGenericKey.mockRejectedValueOnce({});
createComponent();
return wrapper.vm.resetKey().then(() => {
expect(wrapper.find(ToggleButton).props('value')).toBe(false);
@@ -193,18 +196,34 @@ describe('AlertsSettingsForm', () => {
});
describe('alert service is toggled', () => {
- it('should show a error alert if failed', () => {
- const formPath = 'some/path';
+ describe('error handling', () => {
const toggleService = true;
- mockAxios.onPut(formPath).replyOnce(422, {
- errors: 'Error message to display',
- });
- createComponent();
+ it('should show generic error', async () => {
+ service.updateGenericActive.mockRejectedValueOnce({});
+
+ createComponent();
- return wrapper.vm.toggleActivated(toggleService).then(() => {
+ await wrapper.vm.toggleActivated(toggleService);
expect(wrapper.vm.active).toBe(false);
expect(wrapper.find(GlAlert).attributes('variant')).toBe('danger');
+ expect(wrapper.find(GlAlert).text()).toBe(i18n.errorMsg);
+ });
+
+ it('should show first field specific error when available', async () => {
+ const err1 = "can't be blank";
+ const err2 = 'is not a valid URL';
+ const key = 'api_url';
+ service.updateGenericActive.mockRejectedValueOnce({
+ response: { data: { errors: { [key]: [err1, err2] } } },
+ });
+
+ createComponent();
+
+ await wrapper.vm.toggleActivated(toggleService);
+
+ expect(wrapper.find(GlAlert).text()).toContain(i18n.errorMsg);
+ expect(wrapper.find(GlAlert).text()).toContain(`${key} ${err1}`);
});
});
});
diff --git a/spec/frontend/alert_settings/alerts_integrations_list_spec.js b/spec/frontend/alert_settings/alerts_integrations_list_spec.js
new file mode 100644
index 00000000000..6fc9901db2a
--- /dev/null
+++ b/spec/frontend/alert_settings/alerts_integrations_list_spec.js
@@ -0,0 +1,89 @@
+import { GlTable, GlIcon } from '@gitlab/ui';
+import { mount } from '@vue/test-utils';
+import Tracking from '~/tracking';
+import AlertIntegrationsList, {
+ i18n,
+} from '~/alerts_settings/components/alerts_integrations_list.vue';
+import { trackAlertIntergrationsViewsOptions } from '~/alerts_settings/constants';
+
+const mockIntegrations = [
+ {
+ activated: true,
+ name: 'Integration 1',
+ type: 'HTTP endpoint',
+ },
+ {
+ activated: false,
+ name: 'Integration 2',
+ type: 'HTTP endpoint',
+ },
+];
+
+describe('AlertIntegrationsList', () => {
+ let wrapper;
+
+ function mountComponent(propsData = {}) {
+ wrapper = mount(AlertIntegrationsList, {
+ propsData: {
+ integrations: mockIntegrations,
+ ...propsData,
+ },
+ stubs: {
+ GlIcon: true,
+ },
+ });
+ }
+
+ afterEach(() => {
+ if (wrapper) {
+ wrapper.destroy();
+ wrapper = null;
+ }
+ });
+
+ beforeEach(() => {
+ mountComponent();
+ });
+
+ const findTableComponent = () => wrapper.find(GlTable);
+ const finsStatusCell = () => wrapper.findAll('[data-testid="integration-activated-status"]');
+
+ it('renders a table', () => {
+ expect(findTableComponent().exists()).toBe(true);
+ });
+
+ it('renders an empty state when no integrations provided', () => {
+ mountComponent({ integrations: [] });
+ expect(findTableComponent().text()).toContain(i18n.emptyState);
+ });
+
+ describe('integration status', () => {
+ it('enabled', () => {
+ const cell = finsStatusCell().at(0);
+ const activatedIcon = cell.find(GlIcon);
+ expect(cell.text()).toBe(i18n.status.enabled.name);
+ expect(activatedIcon.attributes('name')).toBe('check-circle-filled');
+ expect(activatedIcon.attributes('title')).toBe(i18n.status.enabled.tooltip);
+ });
+
+ it('disabled', () => {
+ const cell = finsStatusCell().at(1);
+ const notActivatedIcon = cell.find(GlIcon);
+ expect(cell.text()).toBe(i18n.status.disabled.name);
+ expect(notActivatedIcon.attributes('name')).toBe('warning-solid');
+ expect(notActivatedIcon.attributes('title')).toBe(i18n.status.disabled.tooltip);
+ });
+ });
+
+ describe('Snowplow tracking', () => {
+ beforeEach(() => {
+ jest.spyOn(Tracking, 'event');
+ mountComponent();
+ });
+
+ it('should track alert list page views', () => {
+ const { category, action } = trackAlertIntergrationsViewsOptions;
+ expect(Tracking.event).toHaveBeenCalledWith(category, action);
+ });
+ });
+});
diff --git a/spec/frontend/analytics/instance_statistics/apollo_mock_data.js b/spec/frontend/analytics/instance_statistics/apollo_mock_data.js
new file mode 100644
index 00000000000..2e4eaf3fc96
--- /dev/null
+++ b/spec/frontend/analytics/instance_statistics/apollo_mock_data.js
@@ -0,0 +1,30 @@
+const defaultPageInfo = { hasPreviousPage: false, startCursor: null, endCursor: null };
+
+export function getApolloResponse(options = {}) {
+ const {
+ pipelinesTotal = [],
+ pipelinesSucceeded = [],
+ pipelinesFailed = [],
+ pipelinesCanceled = [],
+ pipelinesSkipped = [],
+ hasNextPage = false,
+ } = options;
+ return {
+ data: {
+ pipelinesTotal: { pageInfo: { ...defaultPageInfo, hasNextPage }, nodes: pipelinesTotal },
+ pipelinesSucceeded: {
+ pageInfo: { ...defaultPageInfo, hasNextPage },
+ nodes: pipelinesSucceeded,
+ },
+ pipelinesFailed: { pageInfo: { ...defaultPageInfo, hasNextPage }, nodes: pipelinesFailed },
+ pipelinesCanceled: {
+ pageInfo: { ...defaultPageInfo, hasNextPage },
+ nodes: pipelinesCanceled,
+ },
+ pipelinesSkipped: {
+ pageInfo: { ...defaultPageInfo, hasNextPage },
+ nodes: pipelinesSkipped,
+ },
+ },
+ };
+}
diff --git a/spec/frontend/analytics/instance_statistics/components/__snapshots__/pipelines_chart_spec.js.snap b/spec/frontend/analytics/instance_statistics/components/__snapshots__/pipelines_chart_spec.js.snap
new file mode 100644
index 00000000000..0b3b685a9f2
--- /dev/null
+++ b/spec/frontend/analytics/instance_statistics/components/__snapshots__/pipelines_chart_spec.js.snap
@@ -0,0 +1,161 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`PipelinesChart when fetching more data when the fetchMore query returns data passes the data to the line chart 1`] = `
+Array [
+ Object {
+ "data": Array [
+ Array [
+ "2020-06-01",
+ 21,
+ ],
+ Array [
+ "2020-07-01",
+ 10,
+ ],
+ Array [
+ "2020-08-01",
+ 5,
+ ],
+ ],
+ "name": "Total",
+ },
+ Object {
+ "data": Array [
+ Array [
+ "2020-06-01",
+ 21,
+ ],
+ Array [
+ "2020-07-01",
+ 10,
+ ],
+ Array [
+ "2020-08-01",
+ 5,
+ ],
+ ],
+ "name": "Succeeded",
+ },
+ Object {
+ "data": Array [
+ Array [
+ "2020-06-01",
+ 22,
+ ],
+ Array [
+ "2020-07-01",
+ 41,
+ ],
+ Array [
+ "2020-08-01",
+ 5,
+ ],
+ ],
+ "name": "Failed",
+ },
+ Object {
+ "data": Array [
+ Array [
+ "2020-06-01",
+ 21,
+ ],
+ Array [
+ "2020-07-01",
+ 10,
+ ],
+ Array [
+ "2020-08-01",
+ 5,
+ ],
+ ],
+ "name": "Canceled",
+ },
+ Object {
+ "data": Array [
+ Array [
+ "2020-06-01",
+ 21,
+ ],
+ Array [
+ "2020-07-01",
+ 10,
+ ],
+ Array [
+ "2020-08-01",
+ 5,
+ ],
+ ],
+ "name": "Skipped",
+ },
+]
+`;
+
+exports[`PipelinesChart with data passes the data to the line chart 1`] = `
+Array [
+ Object {
+ "data": Array [
+ Array [
+ "2020-06-01",
+ 22,
+ ],
+ Array [
+ "2020-07-01",
+ 41,
+ ],
+ ],
+ "name": "Total",
+ },
+ Object {
+ "data": Array [
+ Array [
+ "2020-06-01",
+ 21,
+ ],
+ Array [
+ "2020-07-01",
+ 10,
+ ],
+ ],
+ "name": "Succeeded",
+ },
+ Object {
+ "data": Array [
+ Array [
+ "2020-06-01",
+ 21,
+ ],
+ Array [
+ "2020-07-01",
+ 10,
+ ],
+ ],
+ "name": "Failed",
+ },
+ Object {
+ "data": Array [
+ Array [
+ "2020-06-01",
+ 22,
+ ],
+ Array [
+ "2020-07-01",
+ 41,
+ ],
+ ],
+ "name": "Canceled",
+ },
+ Object {
+ "data": Array [
+ Array [
+ "2020-06-01",
+ 22,
+ ],
+ Array [
+ "2020-07-01",
+ 41,
+ ],
+ ],
+ "name": "Skipped",
+ },
+]
+`;
diff --git a/spec/frontend/analytics/instance_statistics/components/app_spec.js b/spec/frontend/analytics/instance_statistics/components/app_spec.js
new file mode 100644
index 00000000000..df13c9f82a9
--- /dev/null
+++ b/spec/frontend/analytics/instance_statistics/components/app_spec.js
@@ -0,0 +1,34 @@
+import { shallowMount } from '@vue/test-utils';
+import InstanceStatisticsApp from '~/analytics/instance_statistics/components/app.vue';
+import InstanceCounts from '~/analytics/instance_statistics/components//instance_counts.vue';
+import PipelinesChart from '~/analytics/instance_statistics/components/pipelines_chart.vue';
+import UsersChart from '~/analytics/instance_statistics/components/users_chart.vue';
+
+describe('InstanceStatisticsApp', () => {
+ let wrapper;
+
+ const createComponent = () => {
+ wrapper = shallowMount(InstanceStatisticsApp);
+ };
+
+ beforeEach(() => {
+ createComponent();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ wrapper = null;
+ });
+
+ it('displays the instance counts component', () => {
+ expect(wrapper.find(InstanceCounts).exists()).toBe(true);
+ });
+
+ it('displays the pipelines chart component', () => {
+ expect(wrapper.find(PipelinesChart).exists()).toBe(true);
+ });
+
+ it('displays the users chart component', () => {
+ expect(wrapper.find(UsersChart).exists()).toBe(true);
+ });
+});
diff --git a/spec/frontend/analytics/instance_statistics/components/instance_counts_spec.js b/spec/frontend/analytics/instance_statistics/components/instance_counts_spec.js
new file mode 100644
index 00000000000..12b5e14b9c4
--- /dev/null
+++ b/spec/frontend/analytics/instance_statistics/components/instance_counts_spec.js
@@ -0,0 +1,54 @@
+import { shallowMount } from '@vue/test-utils';
+import InstanceCounts from '~/analytics/instance_statistics/components/instance_counts.vue';
+import MetricCard from '~/analytics/shared/components/metric_card.vue';
+import { mockInstanceCounts } from '../mock_data';
+
+describe('InstanceCounts', () => {
+ let wrapper;
+
+ const createComponent = ({ loading = false, data = {} } = {}) => {
+ const $apollo = {
+ queries: {
+ counts: {
+ loading,
+ },
+ },
+ };
+
+ wrapper = shallowMount(InstanceCounts, {
+ mocks: { $apollo },
+ data() {
+ return {
+ ...data,
+ };
+ },
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ wrapper = null;
+ });
+
+ const findMetricCard = () => wrapper.find(MetricCard);
+
+ describe('while loading', () => {
+ beforeEach(() => {
+ createComponent({ loading: true });
+ });
+
+ it('displays the metric card with isLoading=true', () => {
+ expect(findMetricCard().props('isLoading')).toBe(true);
+ });
+ });
+
+ describe('with data', () => {
+ beforeEach(() => {
+ createComponent({ data: { counts: mockInstanceCounts } });
+ });
+
+ it('passes the counts data to the metric card', () => {
+ expect(findMetricCard().props('metrics')).toEqual(mockInstanceCounts);
+ });
+ });
+});
diff --git a/spec/frontend/analytics/instance_statistics/components/pipelines_chart_spec.js b/spec/frontend/analytics/instance_statistics/components/pipelines_chart_spec.js
new file mode 100644
index 00000000000..a06d66f783e
--- /dev/null
+++ b/spec/frontend/analytics/instance_statistics/components/pipelines_chart_spec.js
@@ -0,0 +1,189 @@
+import { createLocalVue, shallowMount } from '@vue/test-utils';
+import { GlLineChart } from '@gitlab/ui/dist/charts';
+import { GlAlert } from '@gitlab/ui';
+import VueApollo from 'vue-apollo';
+import createMockApollo from 'jest/helpers/mock_apollo_helper';
+import PipelinesChart from '~/analytics/instance_statistics/components/pipelines_chart.vue';
+import pipelinesStatsQuery from '~/analytics/instance_statistics/graphql/queries/pipeline_stats.query.graphql';
+import ChartSkeletonLoader from '~/vue_shared/components/resizable_chart/skeleton_loader.vue';
+import { mockCountsData1, mockCountsData2 } from '../mock_data';
+import { getApolloResponse } from '../apollo_mock_data';
+
+const localVue = createLocalVue();
+localVue.use(VueApollo);
+
+describe('PipelinesChart', () => {
+ let wrapper;
+ let queryHandler;
+
+ const createApolloProvider = pipelineStatsHandler => {
+ return createMockApollo([[pipelinesStatsQuery, pipelineStatsHandler]]);
+ };
+
+ const createComponent = apolloProvider => {
+ return shallowMount(PipelinesChart, {
+ localVue,
+ apolloProvider,
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ wrapper = null;
+ });
+
+ const findLoader = () => wrapper.find(ChartSkeletonLoader);
+ const findChart = () => wrapper.find(GlLineChart);
+ const findAlert = () => wrapper.find(GlAlert);
+
+ describe('while loading', () => {
+ beforeEach(() => {
+ queryHandler = jest.fn().mockReturnValue(new Promise(() => {}));
+ const apolloProvider = createApolloProvider(queryHandler);
+ wrapper = createComponent(apolloProvider);
+ });
+
+ it('requests data', () => {
+ expect(queryHandler).toBeCalledTimes(1);
+ });
+
+ it('displays the skeleton loader', () => {
+ expect(findLoader().exists()).toBe(true);
+ });
+
+ it('hides the chart', () => {
+ expect(findChart().exists()).toBe(false);
+ });
+
+ it('does not show an error', () => {
+ expect(findAlert().exists()).toBe(false);
+ });
+ });
+
+ describe('without data', () => {
+ beforeEach(() => {
+ const emptyResponse = getApolloResponse();
+ queryHandler = jest.fn().mockResolvedValue(emptyResponse);
+ const apolloProvider = createApolloProvider(queryHandler);
+ wrapper = createComponent(apolloProvider);
+ });
+
+ it('renders an no data message', () => {
+ expect(findAlert().text()).toBe('There is no data available.');
+ });
+
+ it('hides the skeleton loader', () => {
+ expect(findLoader().exists()).toBe(false);
+ });
+
+ it('renders the chart', () => {
+ expect(findChart().exists()).toBe(false);
+ });
+ });
+
+ describe('with data', () => {
+ beforeEach(() => {
+ const response = getApolloResponse({
+ pipelinesTotal: mockCountsData1,
+ pipelinesSucceeded: mockCountsData2,
+ pipelinesFailed: mockCountsData2,
+ pipelinesCanceled: mockCountsData1,
+ pipelinesSkipped: mockCountsData1,
+ });
+ queryHandler = jest.fn().mockResolvedValue(response);
+ const apolloProvider = createApolloProvider(queryHandler);
+ wrapper = createComponent(apolloProvider);
+ });
+
+ it('requests data', () => {
+ expect(queryHandler).toBeCalledTimes(1);
+ });
+
+ it('hides the skeleton loader', () => {
+ expect(findLoader().exists()).toBe(false);
+ });
+
+ it('renders the chart', () => {
+ expect(findChart().exists()).toBe(true);
+ });
+
+ it('passes the data to the line chart', () => {
+ expect(findChart().props('data')).toMatchSnapshot();
+ });
+
+ it('does not show an error', () => {
+ expect(findAlert().exists()).toBe(false);
+ });
+ });
+
+ describe('when fetching more data', () => {
+ const recordedAt = '2020-08-01';
+ describe('when the fetchMore query returns data', () => {
+ beforeEach(async () => {
+ const newData = { recordedAt, count: 5 };
+ const firstResponse = getApolloResponse({
+ pipelinesTotal: mockCountsData2,
+ pipelinesSucceeded: mockCountsData2,
+ pipelinesFailed: mockCountsData1,
+ pipelinesCanceled: mockCountsData2,
+ pipelinesSkipped: mockCountsData2,
+ hasNextPage: true,
+ });
+ const secondResponse = getApolloResponse({
+ pipelinesTotal: [newData],
+ pipelinesSucceeded: [newData],
+ pipelinesFailed: [newData],
+ pipelinesCanceled: [newData],
+ pipelinesSkipped: [newData],
+ hasNextPage: false,
+ });
+ queryHandler = jest
+ .fn()
+ .mockResolvedValueOnce(firstResponse)
+ .mockResolvedValueOnce(secondResponse);
+ const apolloProvider = createApolloProvider(queryHandler);
+ wrapper = createComponent(apolloProvider);
+
+ await wrapper.vm.$nextTick();
+ });
+
+ it('requests data twice', () => {
+ expect(queryHandler).toBeCalledTimes(2);
+ });
+
+ it('passes the data to the line chart', () => {
+ expect(findChart().props('data')).toMatchSnapshot();
+ });
+ });
+
+ describe('when the fetchMore query throws an error', () => {
+ beforeEach(async () => {
+ const response = getApolloResponse({
+ pipelinesTotal: mockCountsData2,
+ pipelinesSucceeded: mockCountsData2,
+ pipelinesFailed: mockCountsData1,
+ pipelinesCanceled: mockCountsData2,
+ pipelinesSkipped: mockCountsData2,
+ hasNextPage: true,
+ });
+ queryHandler = jest.fn().mockResolvedValue(response);
+ const apolloProvider = createApolloProvider(queryHandler);
+ wrapper = createComponent(apolloProvider);
+ jest
+ .spyOn(wrapper.vm.$apollo.queries.pipelineStats, 'fetchMore')
+ .mockImplementation(jest.fn().mockRejectedValue());
+ await wrapper.vm.$nextTick();
+ });
+
+ it('calls fetchMore', () => {
+ expect(wrapper.vm.$apollo.queries.pipelineStats.fetchMore).toHaveBeenCalledTimes(1);
+ });
+
+ it('show an error message', () => {
+ expect(findAlert().text()).toBe(
+ 'Could not load the pipelines chart. Please refresh the page to try again.',
+ );
+ });
+ });
+ });
+});
diff --git a/spec/frontend/analytics/instance_statistics/components/users_chart_spec.js b/spec/frontend/analytics/instance_statistics/components/users_chart_spec.js
new file mode 100644
index 00000000000..7509c1e6626
--- /dev/null
+++ b/spec/frontend/analytics/instance_statistics/components/users_chart_spec.js
@@ -0,0 +1,200 @@
+import { createLocalVue, shallowMount } from '@vue/test-utils';
+import { GlAreaChart } from '@gitlab/ui/dist/charts';
+import { GlAlert } from '@gitlab/ui';
+import VueApollo from 'vue-apollo';
+import createMockApollo from 'jest/helpers/mock_apollo_helper';
+import { useFakeDate } from 'helpers/fake_date';
+import UsersChart from '~/analytics/instance_statistics/components/users_chart.vue';
+import ChartSkeletonLoader from '~/vue_shared/components/resizable_chart/skeleton_loader.vue';
+import usersQuery from '~/analytics/instance_statistics/graphql/queries/users.query.graphql';
+import { mockCountsData2, roundedSortedCountsMonthlyChartData2, mockPageInfo } from '../mock_data';
+
+const localVue = createLocalVue();
+localVue.use(VueApollo);
+
+describe('UsersChart', () => {
+ let wrapper;
+ let queryHandler;
+
+ const mockApolloResponse = ({ loading = false, hasNextPage = false, users }) => ({
+ data: {
+ users: {
+ pageInfo: { ...mockPageInfo, hasNextPage },
+ nodes: users,
+ loading,
+ },
+ },
+ });
+
+ const mockQueryResponse = ({ users, loading = false, hasNextPage = false }) => {
+ const apolloQueryResponse = mockApolloResponse({ loading, hasNextPage, users });
+ if (loading) {
+ return jest.fn().mockReturnValue(new Promise(() => {}));
+ }
+ if (hasNextPage) {
+ return jest
+ .fn()
+ .mockResolvedValueOnce(apolloQueryResponse)
+ .mockResolvedValueOnce(
+ mockApolloResponse({
+ loading,
+ hasNextPage: false,
+ users: [{ recordedAt: '2020-07-21', count: 5 }],
+ }),
+ );
+ }
+ return jest.fn().mockResolvedValue(apolloQueryResponse);
+ };
+
+ const createComponent = ({
+ loadingError = false,
+ loading = false,
+ users = [],
+ hasNextPage = false,
+ } = {}) => {
+ queryHandler = mockQueryResponse({ users, loading, hasNextPage });
+
+ return shallowMount(UsersChart, {
+ props: {
+ startDate: useFakeDate(2020, 9, 26),
+ endDate: useFakeDate(2020, 10, 1),
+ totalDataPoints: mockCountsData2.length,
+ },
+ localVue,
+ apolloProvider: createMockApollo([[usersQuery, queryHandler]]),
+ data() {
+ return { loadingError };
+ },
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ wrapper = null;
+ });
+
+ const findLoader = () => wrapper.find(ChartSkeletonLoader);
+ const findAlert = () => wrapper.find(GlAlert);
+ const findChart = () => wrapper.find(GlAreaChart);
+
+ describe('while loading', () => {
+ beforeEach(() => {
+ wrapper = createComponent({ loading: true });
+ });
+
+ it('displays the skeleton loader', () => {
+ expect(findLoader().exists()).toBe(true);
+ });
+
+ it('hides the chart', () => {
+ expect(findChart().exists()).toBe(false);
+ });
+ });
+
+ describe('without data', () => {
+ beforeEach(async () => {
+ wrapper = createComponent({ users: [] });
+ await wrapper.vm.$nextTick();
+ });
+
+ it('renders an no data message', () => {
+ expect(findAlert().text()).toBe('There is no data available.');
+ });
+
+ it('hides the skeleton loader', () => {
+ expect(findLoader().exists()).toBe(false);
+ });
+
+ it('renders the chart', () => {
+ expect(findChart().exists()).toBe(false);
+ });
+ });
+
+ describe('with data', () => {
+ beforeEach(async () => {
+ wrapper = createComponent({ users: mockCountsData2 });
+ await wrapper.vm.$nextTick();
+ });
+
+ it('hides the skeleton loader', () => {
+ expect(findLoader().exists()).toBe(false);
+ });
+
+ it('renders the chart', () => {
+ expect(findChart().exists()).toBe(true);
+ });
+
+ it('passes the data to the line chart', () => {
+ expect(findChart().props('data')).toEqual([
+ { data: roundedSortedCountsMonthlyChartData2, name: 'Total users' },
+ ]);
+ });
+ });
+
+ describe('with errors', () => {
+ beforeEach(async () => {
+ wrapper = createComponent({ loadingError: true });
+ await wrapper.vm.$nextTick();
+ });
+
+ it('renders an error message', () => {
+ expect(findAlert().text()).toBe(
+ 'Could not load the user chart. Please refresh the page to try again.',
+ );
+ });
+
+ it('hides the skeleton loader', () => {
+ expect(findLoader().exists()).toBe(false);
+ });
+
+ it('renders the chart', () => {
+ expect(findChart().exists()).toBe(false);
+ });
+ });
+
+ describe('when fetching more data', () => {
+ describe('when the fetchMore query returns data', () => {
+ beforeEach(async () => {
+ wrapper = createComponent({
+ users: mockCountsData2,
+ hasNextPage: true,
+ });
+
+ jest.spyOn(wrapper.vm.$apollo.queries.users, 'fetchMore');
+ await wrapper.vm.$nextTick();
+ });
+
+ it('requests data twice', () => {
+ expect(queryHandler).toBeCalledTimes(2);
+ });
+
+ it('calls fetchMore', () => {
+ expect(wrapper.vm.$apollo.queries.users.fetchMore).toHaveBeenCalledTimes(1);
+ });
+ });
+
+ describe('when the fetchMore query throws an error', () => {
+ beforeEach(() => {
+ wrapper = createComponent({
+ users: mockCountsData2,
+ hasNextPage: true,
+ });
+
+ jest
+ .spyOn(wrapper.vm.$apollo.queries.users, 'fetchMore')
+ .mockImplementation(jest.fn().mockRejectedValue());
+ return wrapper.vm.$nextTick();
+ });
+
+ it('calls fetchMore', () => {
+ expect(wrapper.vm.$apollo.queries.users.fetchMore).toHaveBeenCalledTimes(1);
+ });
+
+ it('renders an error message', () => {
+ expect(findAlert().text()).toBe(
+ 'Could not load the user chart. Please refresh the page to try again.',
+ );
+ });
+ });
+ });
+});
diff --git a/spec/frontend/analytics/instance_statistics/mock_data.js b/spec/frontend/analytics/instance_statistics/mock_data.js
new file mode 100644
index 00000000000..b737db4c55f
--- /dev/null
+++ b/spec/frontend/analytics/instance_statistics/mock_data.js
@@ -0,0 +1,42 @@
+export const mockInstanceCounts = [
+ { key: 'projects', value: 10, label: 'Projects' },
+ { key: 'groups', value: 20, label: 'Group' },
+];
+
+export const mockCountsData1 = [
+ { recordedAt: '2020-07-23', count: 52 },
+ { recordedAt: '2020-07-22', count: 40 },
+ { recordedAt: '2020-07-21', count: 31 },
+ { recordedAt: '2020-06-14', count: 23 },
+ { recordedAt: '2020-06-12', count: 20 },
+];
+
+export const countsMonthlyChartData1 = [
+ ['2020-07-01', 41], // average of 2020-07-x items
+ ['2020-06-01', 21.5], // average of 2020-06-x items
+];
+
+export const mockCountsData2 = [
+ { recordedAt: '2020-07-28', count: 10 },
+ { recordedAt: '2020-07-27', count: 9 },
+ { recordedAt: '2020-06-26', count: 14 },
+ { recordedAt: '2020-06-25', count: 23 },
+ { recordedAt: '2020-06-24', count: 25 },
+];
+
+export const countsMonthlyChartData2 = [
+ ['2020-07-01', 9.5], // average of 2020-07-x items
+ ['2020-06-01', 20.666666666666668], // average of 2020-06-x items
+];
+
+export const roundedSortedCountsMonthlyChartData2 = [
+ ['2020-06-01', 21], // average of 2020-06-x items
+ ['2020-07-01', 10], // average of 2020-07-x items
+];
+
+export const mockPageInfo = {
+ hasNextPage: false,
+ hasPreviousPage: false,
+ startCursor: null,
+ endCursor: null,
+};
diff --git a/spec/frontend/analytics/instance_statistics/utils_spec.js b/spec/frontend/analytics/instance_statistics/utils_spec.js
new file mode 100644
index 00000000000..d480238419b
--- /dev/null
+++ b/spec/frontend/analytics/instance_statistics/utils_spec.js
@@ -0,0 +1,84 @@
+import {
+ getAverageByMonth,
+ extractValues,
+ sortByDate,
+} from '~/analytics/instance_statistics/utils';
+import {
+ mockCountsData1,
+ mockCountsData2,
+ countsMonthlyChartData1,
+ countsMonthlyChartData2,
+} from './mock_data';
+
+describe('getAverageByMonth', () => {
+ it('collects data into average by months', () => {
+ expect(getAverageByMonth(mockCountsData1)).toStrictEqual(countsMonthlyChartData1);
+ expect(getAverageByMonth(mockCountsData2)).toStrictEqual(countsMonthlyChartData2);
+ });
+
+ it('it transforms a data point to the first of the month', () => {
+ const item = mockCountsData1[0];
+ const firstOfTheMonth = item.recordedAt.replace(/-[0-9]{2}$/, '-01');
+ expect(getAverageByMonth([item])).toStrictEqual([[firstOfTheMonth, item.count]]);
+ });
+
+ it('it uses sane defaults', () => {
+ expect(getAverageByMonth()).toStrictEqual([]);
+ });
+
+ it('it errors when passing null', () => {
+ expect(() => {
+ getAverageByMonth(null);
+ }).toThrow();
+ });
+
+ describe('when shouldRound = true', () => {
+ const options = { shouldRound: true };
+
+ it('rounds the averages', () => {
+ const roundedData1 = countsMonthlyChartData1.map(([date, avg]) => [date, Math.round(avg)]);
+ const roundedData2 = countsMonthlyChartData2.map(([date, avg]) => [date, Math.round(avg)]);
+ expect(getAverageByMonth(mockCountsData1, options)).toStrictEqual(roundedData1);
+ expect(getAverageByMonth(mockCountsData2, options)).toStrictEqual(roundedData2);
+ });
+ });
+});
+
+describe('extractValues', () => {
+ it('extracts only requested values', () => {
+ const data = { fooBar: { baz: 'quis' }, ignored: 'ignored' };
+ expect(extractValues(data, ['fooBar'], 'foo', 'baz')).toEqual({ bazBar: 'quis' });
+ });
+
+ it('is able to extract multiple values', () => {
+ const data = {
+ fooBar: { baz: 'quis' },
+ fooBaz: { baz: 'quis' },
+ fooQuis: { baz: 'quis' },
+ };
+ expect(extractValues(data, ['fooBar', 'fooBaz', 'fooQuis'], 'foo', 'baz')).toEqual({
+ bazBar: 'quis',
+ bazBaz: 'quis',
+ bazQuis: 'quis',
+ });
+ });
+
+ it('returns empty data set when keys are not found', () => {
+ const data = { foo: { baz: 'quis' }, ignored: 'ignored' };
+ expect(extractValues(data, ['fooBar'], 'foo', 'baz')).toEqual({});
+ });
+
+ it('returns empty data when params are missing', () => {
+ expect(extractValues()).toEqual({});
+ });
+});
+
+describe('sortByDate', () => {
+ it('sorts the array by date', () => {
+ expect(sortByDate(mockCountsData1)).toStrictEqual([...mockCountsData1].reverse());
+ });
+
+ it('does not modify the original array', () => {
+ expect(sortByDate(countsMonthlyChartData1)).not.toBe(countsMonthlyChartData1);
+ });
+});
diff --git a/spec/frontend/analytics/shared/components/metric_card_spec.js b/spec/frontend/analytics/shared/components/metric_card_spec.js
new file mode 100644
index 00000000000..e89d499ed9b
--- /dev/null
+++ b/spec/frontend/analytics/shared/components/metric_card_spec.js
@@ -0,0 +1,129 @@
+import { mount } from '@vue/test-utils';
+import { GlDeprecatedSkeletonLoading as GlSkeletonLoading } from '@gitlab/ui';
+import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
+import MetricCard from '~/analytics/shared/components/metric_card.vue';
+
+const metrics = [
+ { key: 'first_metric', value: 10, label: 'First metric', unit: 'days', link: 'some_link' },
+ { key: 'second_metric', value: 20, label: 'Yet another metric' },
+ { key: 'third_metric', value: null, label: 'Null metric without value', unit: 'parsecs' },
+ { key: 'fourth_metric', value: '-', label: 'Metric without value', unit: 'parsecs' },
+];
+
+const defaultProps = {
+ title: 'My fancy title',
+ isLoading: false,
+ metrics,
+};
+
+describe('MetricCard', () => {
+ let wrapper;
+
+ const factory = (props = defaultProps) => {
+ wrapper = mount(MetricCard, {
+ propsData: {
+ ...defaultProps,
+ ...props,
+ },
+ directives: {
+ GlTooltip: createMockDirective(),
+ },
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ const findTitle = () => wrapper.find({ ref: 'title' });
+ const findLoadingIndicator = () => wrapper.find(GlSkeletonLoading);
+ const findMetricsWrapper = () => wrapper.find({ ref: 'metricsWrapper' });
+ const findMetricItem = () => wrapper.findAll({ ref: 'metricItem' });
+ const findTooltip = () => wrapper.find('[data-testid="tooltip"]');
+
+ describe('template', () => {
+ it('renders the title', () => {
+ factory();
+
+ expect(findTitle().text()).toContain('My fancy title');
+ });
+
+ describe('when isLoading is true', () => {
+ beforeEach(() => {
+ factory({ isLoading: true });
+ });
+
+ it('displays a loading indicator', () => {
+ expect(findLoadingIndicator().exists()).toBe(true);
+ });
+
+ it('does not display the metrics container', () => {
+ expect(findMetricsWrapper().exists()).toBe(false);
+ });
+ });
+
+ describe('when isLoading is false', () => {
+ beforeEach(() => {
+ factory({ isLoading: false });
+ });
+
+ it('does not display a loading indicator', () => {
+ expect(findLoadingIndicator().exists()).toBe(false);
+ });
+
+ it('displays the metrics container', () => {
+ expect(findMetricsWrapper().exists()).toBe(true);
+ });
+
+ it('renders two metrics', () => {
+ expect(findMetricItem()).toHaveLength(metrics.length);
+ });
+
+ describe('with tooltip text', () => {
+ const tooltipText = 'This is a tooltip';
+ const tooltipMetric = {
+ key: 'fifth_metric',
+ value: '-',
+ label: 'Metric with tooltip',
+ unit: 'parsecs',
+ tooltipText,
+ };
+
+ beforeEach(() => {
+ factory({
+ isLoading: false,
+ metrics: [tooltipMetric],
+ });
+ });
+
+ it('will render a tooltip', () => {
+ const tt = getBinding(findTooltip().element, 'gl-tooltip');
+ expect(tt.value.title).toEqual(tooltipText);
+ });
+ });
+
+ describe.each`
+ columnIndex | label | value | unit | link
+ ${0} | ${'First metric'} | ${10} | ${' days'} | ${'some_link'}
+ ${1} | ${'Yet another metric'} | ${20} | ${''} | ${null}
+ ${2} | ${'Null metric without value'} | ${'-'} | ${''} | ${null}
+ ${3} | ${'Metric without value'} | ${'-'} | ${''} | ${null}
+ `('metric columns', ({ columnIndex, label, value, unit, link }) => {
+ it(`renders ${value}${unit} ${label} with URL ${link}`, () => {
+ const allMetricItems = findMetricItem();
+ const metricItem = allMetricItems.at(columnIndex);
+ const text = metricItem.text();
+
+ expect(text).toContain(`${value}${unit}`);
+ expect(text).toContain(label);
+
+ if (link) {
+ expect(metricItem.find('a').attributes('href')).toBe(link);
+ } else {
+ expect(metricItem.find('a').exists()).toBe(false);
+ }
+ });
+ });
+ });
+ });
+});
diff --git a/spec/frontend/api_spec.js b/spec/frontend/api_spec.js
index 3ae0d06162d..9924525929b 100644
--- a/spec/frontend/api_spec.js
+++ b/spec/frontend/api_spec.js
@@ -421,6 +421,25 @@ describe('Api', () => {
});
});
+ describe('addProjectIssueAsTodo', () => {
+ it('adds issue ID as a todo', () => {
+ const projectId = 1;
+ const issueIid = 11;
+ const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/projects/1/issues/11/todo`;
+ mock.onPost(expectedUrl).reply(200, {
+ id: 112,
+ project: {
+ id: 1,
+ },
+ });
+
+ return Api.addProjectIssueAsTodo(projectId, issueIid).then(({ data }) => {
+ expect(data.id).toBe(112);
+ expect(data.project.id).toBe(projectId);
+ });
+ });
+ });
+
describe('newLabel', () => {
it('creates a new label', done => {
const namespace = 'some namespace';
@@ -672,6 +691,27 @@ describe('Api', () => {
});
});
+ describe('pipelineJobs', () => {
+ it('fetches the jobs for a given pipeline', done => {
+ const projectId = 123;
+ const pipelineId = 456;
+ const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/projects/${projectId}/pipelines/${pipelineId}/jobs`;
+ const payload = [
+ {
+ name: 'test',
+ },
+ ];
+ mock.onGet(expectedUrl).reply(httpStatus.OK, payload);
+
+ Api.pipelineJobs(projectId, pipelineId)
+ .then(({ data }) => {
+ expect(data).toEqual(payload);
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+ });
+
describe('createBranch', () => {
it('creates new branch', done => {
const ref = 'master';
@@ -1152,4 +1192,44 @@ describe('Api', () => {
});
});
});
+
+ describe('trackRedisHllUserEvent', () => {
+ const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/usage_data/increment_unique_users`;
+
+ const event = 'dummy_event';
+ const postData = { event };
+ const headers = {
+ 'Content-Type': 'application/json',
+ };
+
+ describe('when usage data increment unique users is called with feature flag disabled', () => {
+ beforeEach(() => {
+ gon.features = { ...gon.features, usageDataApi: false };
+ });
+
+ it('returns null', () => {
+ jest.spyOn(axios, 'post');
+ mock.onPost(expectedUrl).replyOnce(httpStatus.OK, true);
+
+ expect(axios.post).toHaveBeenCalledTimes(0);
+ expect(Api.trackRedisHllUserEvent(event)).toEqual(null);
+ });
+ });
+
+ describe('when usage data increment unique users is called', () => {
+ beforeEach(() => {
+ gon.features = { ...gon.features, usageDataApi: true };
+ });
+
+ it('resolves the Promise', () => {
+ jest.spyOn(axios, 'post');
+ mock.onPost(expectedUrl, { event }).replyOnce(httpStatus.OK, true);
+
+ return Api.trackRedisHllUserEvent(event).then(({ data }) => {
+ expect(data).toEqual(true);
+ expect(axios.post).toHaveBeenCalledWith(expectedUrl, postData, { headers });
+ });
+ });
+ });
+ });
});
diff --git a/spec/frontend/awards_handler_spec.js b/spec/frontend/awards_handler_spec.js
index f0ed18248f0..7fd6a9e7b87 100644
--- a/spec/frontend/awards_handler_spec.js
+++ b/spec/frontend/awards_handler_spec.js
@@ -309,6 +309,30 @@ describe('AwardsHandler', () => {
expect($('[data-name=alien]').is(':visible')).toBe(true);
expect($('.js-emoji-menu-search').val()).toBe('');
});
+
+ it('should fuzzy filter the emoji', async () => {
+ await openAndWaitForEmojiMenu();
+
+ awardsHandler.searchEmojis('sgls');
+
+ expect($('[data-name=angel]').is(':visible')).toBe(false);
+ expect($('[data-name=anger]').is(':visible')).toBe(false);
+ expect($('[data-name=sunglasses]').is(':visible')).toBe(true);
+ });
+
+ it('should filter by emoji description', async () => {
+ await openAndWaitForEmojiMenu();
+
+ awardsHandler.searchEmojis('baby');
+ expect($('[data-name=angel]').is(':visible')).toBe(true);
+ });
+
+ it('should filter by emoji unicode value', async () => {
+ await openAndWaitForEmojiMenu();
+
+ awardsHandler.searchEmojis('👼');
+ expect($('[data-name=angel]').is(':visible')).toBe(true);
+ });
});
describe('emoji menu', () => {
diff --git a/spec/frontend/badges/components/badge_settings_spec.js b/spec/frontend/badges/components/badge_settings_spec.js
index b6a86746598..769be7cb1bd 100644
--- a/spec/frontend/badges/components/badge_settings_spec.js
+++ b/spec/frontend/badges/components/badge_settings_spec.js
@@ -1,117 +1,71 @@
-import Vue from 'vue';
-import { mountComponentWithStore } from 'helpers/vue_mount_component_helper';
+import Vuex from 'vuex';
+import { shallowMount, createLocalVue } from '@vue/test-utils';
+import { GlModal } from '@gitlab/ui';
import store from '~/badges/store';
import BadgeSettings from '~/badges/components/badge_settings.vue';
+import BadgeList from '~/badges/components/badge_list.vue';
+import BadgeListRow from '~/badges/components/badge_list_row.vue';
import { createDummyBadge } from '../dummy_badge';
-describe('BadgeSettings component', () => {
- const Component = Vue.extend(BadgeSettings);
- let vm;
+const localVue = createLocalVue();
+localVue.use(Vuex);
- beforeEach(() => {
- setFixtures(`
- <div id="dummy-element"></div>
- <button
- id="dummy-modal-button"
- type="button"
- data-toggle="modal"
- data-target="#delete-badge-modal"
- >Show modal</button>
- `);
+describe('BadgeSettings component', () => {
+ let wrapper;
+ const badge = createDummyBadge();
- // Can be removed once GlLoadingIcon no longer throws a warning
- jest.spyOn(global.console, 'warn').mockImplementation(() => jest.fn());
+ const createComponent = (isEditing = false) => {
+ store.state.badges = [badge];
+ store.state.kind = 'project';
+ store.state.isEditing = isEditing;
- vm = mountComponentWithStore(Component, {
- el: '#dummy-element',
+ wrapper = shallowMount(BadgeSettings, {
store,
+ localVue,
+ stubs: {
+ 'badge-list': BadgeList,
+ 'badge-list-row': BadgeListRow,
+ },
});
+ };
+
+ beforeEach(() => {
+ createComponent();
});
afterEach(() => {
- vm.$destroy();
+ wrapper.destroy();
});
- it('displays modal if button is clicked', done => {
- const badge = createDummyBadge();
- store.state.badgeInModal = badge;
- const modal = vm.$el.querySelector('#delete-badge-modal');
- const button = document.getElementById('dummy-modal-button');
+ it('displays modal if button for deleting a badge is clicked', async () => {
+ const button = wrapper.find('[data-testid="delete-badge"]');
- button.click();
+ button.vm.$emit('click');
+ await wrapper.vm.$nextTick();
- Vue.nextTick()
- .then(() => {
- expect(modal.innerText).toMatch('Delete badge?');
- const badgeElement = modal.querySelector('img.project-badge');
- expect(badgeElement).not.toBe(null);
- expect(badgeElement.getAttribute('src')).toBe(badge.renderedImageUrl);
- })
- .then(done)
- .catch(done.fail);
+ const modal = wrapper.find(GlModal);
+ expect(modal.isVisible()).toBe(true);
});
it('displays a form to add a badge', () => {
- const form = vm.$el.querySelector('form:nth-of-type(2)');
-
- expect(form).not.toBe(null);
- const button = form.querySelector('.btn-success');
-
- expect(button).not.toBe(null);
- expect(button).toHaveText(/Add badge/);
+ expect(wrapper.find('[data-testid="add-new-badge"]').isVisible()).toBe(true);
});
it('displays badge list', () => {
- const badgeListElement = vm.$el.querySelector('.card');
-
- expect(badgeListElement).not.toBe(null);
- expect(badgeListElement).toBeVisible();
- expect(badgeListElement.innerText).toMatch('Your badges');
+ expect(wrapper.find(BadgeList).isVisible()).toBe(true);
});
describe('when editing', () => {
- beforeEach(done => {
- store.state.isEditing = true;
-
- Vue.nextTick()
- .then(done)
- .catch(done.fail);
+ beforeEach(() => {
+ createComponent(true);
});
it('displays a form to edit a badge', () => {
- const form = vm.$el.querySelector('form:nth-of-type(1)');
-
- expect(form).not.toBe(null);
- const cancelButton = form.querySelector('[data-testid="cancelEditing"]');
-
- expect(cancelButton).not.toBe(null);
- expect(cancelButton).toHaveText(/Cancel/);
- const submitButton = form.querySelector('[data-testid="saveEditing"]');
-
- expect(submitButton).not.toBe(null);
- expect(submitButton).toHaveText(/Save changes/);
+ expect(wrapper.find('[data-testid="edit-badge"]').isVisible()).toBe(true);
});
it('displays no badge list', () => {
- const badgeListElement = vm.$el.querySelector('.card');
-
- expect(badgeListElement).toBeHidden();
- });
- });
-
- describe('methods', () => {
- describe('onSubmitModal', () => {
- it('triggers ', () => {
- jest.spyOn(vm, 'deleteBadge').mockImplementation(() => Promise.resolve());
- const modal = vm.$el.querySelector('#delete-badge-modal');
- const deleteButton = modal.querySelector('.btn-danger');
-
- deleteButton.click();
-
- const badge = store.state.badgeInModal;
-
- expect(vm.deleteBadge).toHaveBeenCalledWith(badge);
- });
+ expect(wrapper.find(BadgeList).isVisible()).toBe(false);
});
});
});
diff --git a/spec/frontend/batch_comments/components/preview_item_spec.js b/spec/frontend/batch_comments/components/preview_item_spec.js
index 2b63ece28ba..8ddad3dacfe 100644
--- a/spec/frontend/batch_comments/components/preview_item_spec.js
+++ b/spec/frontend/batch_comments/components/preview_item_spec.js
@@ -43,22 +43,6 @@ describe('Batch comments draft preview item component', () => {
);
});
- it('adds is last class', () => {
- createComponent(true);
-
- expect(vm.$el.classList).toContain('is-last');
- });
-
- it('scrolls to draft on click', () => {
- createComponent();
-
- jest.spyOn(vm.$store, 'dispatch').mockImplementation();
-
- vm.$el.click();
-
- expect(vm.$store.dispatch).toHaveBeenCalledWith('batchComments/scrollToDraft', vm.draft);
- });
-
describe('for file', () => {
it('renders file path', () => {
createComponent(false, { file_path: 'index.js', file_hash: 'abc', position: {} });
diff --git a/spec/frontend/batch_comments/components/publish_button_spec.js b/spec/frontend/batch_comments/components/publish_button_spec.js
index 4362f62c7f8..4032713150c 100644
--- a/spec/frontend/batch_comments/components/publish_button_spec.js
+++ b/spec/frontend/batch_comments/components/publish_button_spec.js
@@ -29,17 +29,6 @@ describe('Batch comments publish button component', () => {
expect(vm.$store.dispatch).toHaveBeenCalledWith('batchComments/publishReview', undefined);
});
- it('dispatches toggleReviewDropdown when shouldPublish is false on click', () => {
- vm.shouldPublish = false;
-
- vm.$el.click();
-
- expect(vm.$store.dispatch).toHaveBeenCalledWith(
- 'batchComments/toggleReviewDropdown',
- undefined,
- );
- });
-
it('sets loading when isPublishing is true', done => {
vm.$store.state.batchComments.isPublishing = true;
diff --git a/spec/frontend/batch_comments/components/publish_dropdown_spec.js b/spec/frontend/batch_comments/components/publish_dropdown_spec.js
index fb3c532174d..f235867f002 100644
--- a/spec/frontend/batch_comments/components/publish_dropdown_spec.js
+++ b/spec/frontend/batch_comments/components/publish_dropdown_spec.js
@@ -1,96 +1,39 @@
-import Vue from 'vue';
-import { mountComponentWithStore } from 'helpers/vue_mount_component_helper';
+import Vuex from 'vuex';
+import { shallowMount, createLocalVue } from '@vue/test-utils';
+import { GlDropdown, GlDropdownItem } from '@gitlab/ui';
import PreviewDropdown from '~/batch_comments/components/preview_dropdown.vue';
import { createStore } from '~/mr_notes/stores';
import '~/behaviors/markdown/render_gfm';
import { createDraft } from '../mock_data';
+const localVue = createLocalVue();
+localVue.use(Vuex);
+
describe('Batch comments publish dropdown component', () => {
- let vm;
- let Component;
+ let wrapper;
- function createComponent(extendStore = () => {}) {
+ function createComponent() {
const store = createStore();
store.state.batchComments.drafts.push(createDraft(), { ...createDraft(), id: 2 });
- extendStore(store);
-
- vm = mountComponentWithStore(Component, { store });
+ wrapper = shallowMount(PreviewDropdown, {
+ store,
+ });
}
- beforeAll(() => {
- Component = Vue.extend(PreviewDropdown);
- });
-
afterEach(() => {
- vm.$destroy();
- });
-
- it('toggles dropdown when clicking button', done => {
- createComponent();
-
- jest.spyOn(vm.$store, 'dispatch');
-
- vm.$el.querySelector('.review-preview-dropdown-toggle').click();
-
- expect(vm.$store.dispatch).toHaveBeenCalledWith(
- 'batchComments/toggleReviewDropdown',
- expect.anything(),
- );
-
- setImmediate(() => {
- expect(vm.$el.classList).toContain('show');
-
- done();
- });
- });
-
- it('toggles dropdown when clicking body', () => {
- createComponent();
-
- vm.$store.state.batchComments.showPreviewDropdown = true;
-
- jest.spyOn(vm.$store, 'dispatch').mockImplementation();
-
- document.body.click();
-
- expect(vm.$store.dispatch).toHaveBeenCalledWith(
- 'batchComments/toggleReviewDropdown',
- undefined,
- );
+ wrapper.destroy();
});
it('renders list of drafts', () => {
- createComponent(store => {
- Object.assign(store.state.notes, {
- isNotesFetched: true,
- });
- });
-
- expect(vm.$el.querySelectorAll('.dropdown-content li').length).toBe(2);
- });
-
- it('adds is-last class to last item', () => {
- createComponent(store => {
- Object.assign(store.state.notes, {
- isNotesFetched: true,
- });
- });
-
- expect(vm.$el.querySelectorAll('.dropdown-content li')[1].querySelector('.is-last')).not.toBe(
- null,
- );
- });
-
- it('renders draft count in dropdown title', () => {
createComponent();
- expect(vm.$el.querySelector('.dropdown-title').textContent).toContain('2 pending comments');
+ expect(wrapper.findAll(GlDropdownItem).length).toBe(2);
});
- it('renders publish button in footer', () => {
+ it('renders draft count in dropdown title', () => {
createComponent();
- expect(vm.$el.querySelector('.dropdown-footer .js-publish-draft-button')).not.toBe(null);
+ expect(wrapper.find(GlDropdown).props('headerText')).toEqual('2 pending comments');
});
});
diff --git a/spec/frontend/batch_comments/stores/modules/batch_comments/actions_spec.js b/spec/frontend/batch_comments/stores/modules/batch_comments/actions_spec.js
index a6942115649..e66f36aa3a2 100644
--- a/spec/frontend/batch_comments/stores/modules/batch_comments/actions_spec.js
+++ b/spec/frontend/batch_comments/stores/modules/batch_comments/actions_spec.js
@@ -199,42 +199,6 @@ describe('Batch comments store actions', () => {
});
});
- describe('discardReview', () => {
- it('commits mutations', done => {
- const getters = {
- getNotesData: { draftsDiscardPath: TEST_HOST },
- };
- const commit = jest.fn();
- mock.onAny().reply(200);
-
- actions
- .discardReview({ getters, commit })
- .then(() => {
- expect(commit.mock.calls[0]).toEqual(['REQUEST_DISCARD_REVIEW']);
- expect(commit.mock.calls[1]).toEqual(['RECEIVE_DISCARD_REVIEW_SUCCESS']);
- })
- .then(done)
- .catch(done.fail);
- });
-
- it('commits error mutations', done => {
- const getters = {
- getNotesData: { draftsDiscardPath: TEST_HOST },
- };
- const commit = jest.fn();
- mock.onAny().reply(500);
-
- actions
- .discardReview({ getters, commit })
- .then(() => {
- expect(commit.mock.calls[0]).toEqual(['REQUEST_DISCARD_REVIEW']);
- expect(commit.mock.calls[1]).toEqual(['RECEIVE_DISCARD_REVIEW_ERROR']);
- })
- .then(done)
- .catch(done.fail);
- });
- });
-
describe('updateDraft', () => {
let getters;
@@ -284,56 +248,6 @@ describe('Batch comments store actions', () => {
});
});
- describe('toggleReviewDropdown', () => {
- it('dispatches openReviewDropdown', done => {
- testAction(
- actions.toggleReviewDropdown,
- null,
- { showPreviewDropdown: false },
- [],
- [{ type: 'openReviewDropdown' }],
- done,
- );
- });
-
- it('dispatches closeReviewDropdown when showPreviewDropdown is true', done => {
- testAction(
- actions.toggleReviewDropdown,
- null,
- { showPreviewDropdown: true },
- [],
- [{ type: 'closeReviewDropdown' }],
- done,
- );
- });
- });
-
- describe('openReviewDropdown', () => {
- it('commits OPEN_REVIEW_DROPDOWN', done => {
- testAction(
- actions.openReviewDropdown,
- null,
- null,
- [{ type: 'OPEN_REVIEW_DROPDOWN' }],
- [],
- done,
- );
- });
- });
-
- describe('closeReviewDropdown', () => {
- it('commits CLOSE_REVIEW_DROPDOWN', done => {
- testAction(
- actions.closeReviewDropdown,
- null,
- null,
- [{ type: 'CLOSE_REVIEW_DROPDOWN' }],
- [],
- done,
- );
- });
- });
-
describe('expandAllDiscussions', () => {
it('dispatches expandDiscussion for all drafts', done => {
const state = {
@@ -383,9 +297,7 @@ describe('Batch comments store actions', () => {
actions.scrollToDraft({ dispatch, rootGetters }, draft);
- expect(dispatch.mock.calls[0]).toEqual(['closeReviewDropdown']);
-
- expect(dispatch.mock.calls[1]).toEqual([
+ expect(dispatch.mock.calls[0]).toEqual([
'expandDiscussion',
{ discussionId: '1' },
{ root: true },
diff --git a/spec/frontend/batch_comments/stores/modules/batch_comments/mutations_spec.js b/spec/frontend/batch_comments/stores/modules/batch_comments/mutations_spec.js
index a86726269ef..1406f66fd10 100644
--- a/spec/frontend/batch_comments/stores/modules/batch_comments/mutations_spec.js
+++ b/spec/frontend/batch_comments/stores/modules/batch_comments/mutations_spec.js
@@ -89,42 +89,6 @@ describe('Batch comments mutations', () => {
});
});
- describe(types.REQUEST_DISCARD_REVIEW, () => {
- it('sets isDiscarding to true', () => {
- mutations[types.REQUEST_DISCARD_REVIEW](state);
-
- expect(state.isDiscarding).toBe(true);
- });
- });
-
- describe(types.RECEIVE_DISCARD_REVIEW_SUCCESS, () => {
- it('emptys drafts array', () => {
- state.drafts.push('test');
-
- mutations[types.RECEIVE_DISCARD_REVIEW_SUCCESS](state);
-
- expect(state.drafts).toEqual([]);
- });
-
- it('sets isDiscarding to false', () => {
- state.isDiscarding = true;
-
- mutations[types.RECEIVE_DISCARD_REVIEW_SUCCESS](state);
-
- expect(state.isDiscarding).toBe(false);
- });
- });
-
- describe(types.RECEIVE_DISCARD_REVIEW_ERROR, () => {
- it('updates isDiscarding to false', () => {
- state.isDiscarding = true;
-
- mutations[types.RECEIVE_DISCARD_REVIEW_ERROR](state);
-
- expect(state.isDiscarding).toBe(false);
- });
- });
-
describe(types.RECEIVE_DRAFT_UPDATE_SUCCESS, () => {
it('updates draft in store', () => {
state.drafts.push({ id: 1 });
@@ -140,20 +104,4 @@ describe('Batch comments mutations', () => {
]);
});
});
-
- describe(types.OPEN_REVIEW_DROPDOWN, () => {
- it('sets showPreviewDropdown to true', () => {
- mutations[types.OPEN_REVIEW_DROPDOWN](state);
-
- expect(state.showPreviewDropdown).toBe(true);
- });
- });
-
- describe(types.CLOSE_REVIEW_DROPDOWN, () => {
- it('sets showPreviewDropdown to false', () => {
- mutations[types.CLOSE_REVIEW_DROPDOWN](state);
-
- expect(state.showPreviewDropdown).toBe(false);
- });
- });
});
diff --git a/spec/frontend/behaviors/load_startup_css_spec.js b/spec/frontend/behaviors/load_startup_css_spec.js
new file mode 100644
index 00000000000..81222ac5aaa
--- /dev/null
+++ b/spec/frontend/behaviors/load_startup_css_spec.js
@@ -0,0 +1,44 @@
+import { setHTMLFixture } from 'helpers/fixtures';
+import { loadStartupCSS } from '~/behaviors/load_startup_css';
+
+describe('behaviors/load_startup_css', () => {
+ let loadListener;
+
+ const setupListeners = () => {
+ document
+ .querySelectorAll('link')
+ .forEach(x => x.addEventListener('load', () => loadListener(x)));
+ };
+
+ beforeEach(() => {
+ loadListener = jest.fn();
+
+ setHTMLFixture(`
+ <meta charset="utf-8" />
+ <link media="print" src="./lorem-print.css" />
+ <link media="print" src="./ipsum-print.css" />
+ <link media="all" src="./dolar-all.css" />
+ `);
+
+ setupListeners();
+
+ loadStartupCSS();
+ });
+
+ it('does nothing at first', () => {
+ expect(loadListener).not.toHaveBeenCalled();
+ });
+
+ describe('on window load', () => {
+ beforeEach(() => {
+ window.dispatchEvent(new Event('load'));
+ });
+
+ it('dispatches load to the print links', () => {
+ expect(loadListener.mock.calls.map(([el]) => el.getAttribute('src'))).toEqual([
+ './lorem-print.css',
+ './ipsum-print.css',
+ ]);
+ });
+ });
+});
diff --git a/spec/frontend/behaviors/shortcuts/keybindings_spec.js b/spec/frontend/behaviors/shortcuts/keybindings_spec.js
new file mode 100644
index 00000000000..23fea79f828
--- /dev/null
+++ b/spec/frontend/behaviors/shortcuts/keybindings_spec.js
@@ -0,0 +1,66 @@
+import { useLocalStorageSpy } from 'helpers/local_storage_helper';
+
+describe('~/behaviors/shortcuts/keybindings.js', () => {
+ let keysFor;
+ let TOGGLE_PERFORMANCE_BAR;
+ let LOCAL_STORAGE_KEY;
+
+ beforeAll(() => {
+ useLocalStorageSpy();
+ });
+
+ const setupCustomizations = async customizationsAsString => {
+ localStorage.clear();
+
+ if (customizationsAsString) {
+ localStorage.setItem(LOCAL_STORAGE_KEY, customizationsAsString);
+ }
+
+ jest.resetModules();
+ ({ keysFor, TOGGLE_PERFORMANCE_BAR, LOCAL_STORAGE_KEY } = await import(
+ '~/behaviors/shortcuts/keybindings'
+ ));
+ };
+
+ describe('when a command has not been customized', () => {
+ beforeEach(async () => {
+ await setupCustomizations('{}');
+ });
+
+ it('returns the default keybinding for the command', () => {
+ expect(keysFor(TOGGLE_PERFORMANCE_BAR)).toEqual(['p b']);
+ });
+ });
+
+ describe('when a command has been customized', () => {
+ const customization = ['p b a r'];
+
+ beforeEach(async () => {
+ await setupCustomizations(JSON.stringify({ [TOGGLE_PERFORMANCE_BAR]: customization }));
+ });
+
+ it('returns the default keybinding for the command', () => {
+ expect(keysFor(TOGGLE_PERFORMANCE_BAR)).toEqual(customization);
+ });
+ });
+
+ describe("when the localStorage entry isn't valid JSON", () => {
+ beforeEach(async () => {
+ await setupCustomizations('{');
+ });
+
+ it('returns the default keybinding for the command', () => {
+ expect(keysFor(TOGGLE_PERFORMANCE_BAR)).toEqual(['p b']);
+ });
+ });
+
+ describe(`when localStorage doesn't contain the ${LOCAL_STORAGE_KEY} key`, () => {
+ beforeEach(async () => {
+ await setupCustomizations();
+ });
+
+ it('returns the default keybinding for the command', () => {
+ expect(keysFor(TOGGLE_PERFORMANCE_BAR)).toEqual(['p b']);
+ });
+ });
+});
diff --git a/spec/frontend/blob/components/__snapshots__/blob_header_filepath_spec.js.snap b/spec/frontend/blob/components/__snapshots__/blob_header_filepath_spec.js.snap
index 0f5b3cd3f5e..53815820bbe 100644
--- a/spec/frontend/blob/components/__snapshots__/blob_header_filepath_spec.js.snap
+++ b/spec/frontend/blob/components/__snapshots__/blob_header_filepath_spec.js.snap
@@ -27,8 +27,10 @@ exports[`Blob Header Filepath rendering matches the snapshot 1`] = `
</small>
<clipboard-button-stub
+ category="tertiary"
cssclass="btn-clipboard btn-transparent lh-100 position-static"
gfm="\`foo/bar/dummy.md\`"
+ size="medium"
text="foo/bar/dummy.md"
title="Copy file path"
tooltipplacement="top"
diff --git a/spec/frontend/blob/pipeline_tour_success_modal_spec.js b/spec/frontend/blob/pipeline_tour_success_modal_spec.js
index 50db1675e13..a02c968c4b5 100644
--- a/spec/frontend/blob/pipeline_tour_success_modal_spec.js
+++ b/spec/frontend/blob/pipeline_tour_success_modal_spec.js
@@ -16,6 +16,7 @@ describe('PipelineTourSuccessModal', () => {
stubs: {
GlModal,
GlSprintf,
+ 'gl-emoji': '<img/>',
},
});
};
@@ -66,9 +67,11 @@ describe('PipelineTourSuccessModal', () => {
it('has expected structure', () => {
const modal = wrapper.find(GlModal);
const sprintf = modal.find(GlSprintf);
+ const emoji = modal.find('img');
- expect(modal.attributes('title')).toContain("That's it, well done!");
+ expect(wrapper.text()).toContain("That's it, well done!");
expect(sprintf.exists()).toBe(true);
+ expect(emoji.exists()).toBe(true);
});
it('renders the link for codeQualityLink', () => {
diff --git a/spec/frontend/blob/sketch/index_spec.js b/spec/frontend/blob/sketch/index_spec.js
index f5e9da21b2a..cd12d5e17a8 100644
--- a/spec/frontend/blob/sketch/index_spec.js
+++ b/spec/frontend/blob/sketch/index_spec.js
@@ -8,13 +8,6 @@ describe('Sketch viewer', () => {
beforeEach(() => {
loadFixtures('static/sketch_viewer.html');
- window.URL = {
- createObjectURL: jest.fn(() => 'http://foo/bar'),
- };
- });
-
- afterEach(() => {
- window.URL = {};
});
describe('with error message', () => {
diff --git a/spec/frontend/blob/suggest_web_ide_ci/web_ide_alert_spec.js b/spec/frontend/blob/suggest_web_ide_ci/web_ide_alert_spec.js
deleted file mode 100644
index 8dc71f99010..00000000000
--- a/spec/frontend/blob/suggest_web_ide_ci/web_ide_alert_spec.js
+++ /dev/null
@@ -1,67 +0,0 @@
-import MockAdapter from 'axios-mock-adapter';
-import waitForPromises from 'helpers/wait_for_promises';
-import { shallowMount } from '@vue/test-utils';
-import { GlButton, GlAlert } from '@gitlab/ui';
-import axios from '~/lib/utils/axios_utils';
-import WebIdeAlert from '~/blob/suggest_web_ide_ci/components/web_ide_alert.vue';
-
-const dismissEndpoint = '/-/user_callouts';
-const featureId = 'web_ide_alert_dismissed';
-const editPath = 'edit/master/-/.gitlab-ci.yml';
-
-describe('WebIdeAlert', () => {
- let wrapper;
- let mock;
-
- const findButton = () => wrapper.find(GlButton);
- const findAlert = () => wrapper.find(GlAlert);
- const dismissAlert = alertWrapper => alertWrapper.vm.$emit('dismiss');
- const getPostPayload = () => JSON.parse(mock.history.post[0].data);
-
- const createComponent = () => {
- wrapper = shallowMount(WebIdeAlert, {
- propsData: {
- dismissEndpoint,
- featureId,
- editPath,
- },
- });
- };
-
- beforeEach(() => {
- mock = new MockAdapter(axios);
-
- mock.onPost(dismissEndpoint).reply(200);
-
- createComponent();
- });
-
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
-
- mock.restore();
- });
-
- describe('with defaults', () => {
- it('displays alert correctly', () => {
- expect(findAlert().exists()).toBe(true);
- });
-
- it('web ide button link has correct path', () => {
- expect(findButton().attributes('href')).toBe(editPath);
- });
-
- it('dismisses alert correctly', async () => {
- const alertWrapper = findAlert();
-
- dismissAlert(alertWrapper);
-
- await waitForPromises();
-
- expect(alertWrapper.exists()).toBe(false);
- expect(mock.history.post).toHaveLength(1);
- expect(getPostPayload()).toEqual({ feature_name: featureId });
- });
- });
-});
diff --git a/spec/frontend/blob/viewer/index_spec.js b/spec/frontend/blob/viewer/index_spec.js
index 97ac42a10bf..69ec22b1f94 100644
--- a/spec/frontend/blob/viewer/index_spec.js
+++ b/spec/frontend/blob/viewer/index_spec.js
@@ -2,6 +2,7 @@
import $ from 'jquery';
import MockAdapter from 'axios-mock-adapter';
+import { setTestTimeout } from 'helpers/timeout';
import BlobViewer from '~/blob/viewer/index';
import axios from '~/lib/utils/axios_utils';
@@ -13,26 +14,22 @@ describe('Blob viewer', () => {
tooltip: jest.fn(),
};
- preloadFixtures('snippets/show.html');
+ setTestTimeout(2000);
+
+ preloadFixtures('blob/show_readme.html');
beforeEach(() => {
$.fn.extend(jQueryMock);
mock = new MockAdapter(axios);
- loadFixtures('snippets/show.html');
+ loadFixtures('blob/show_readme.html');
$('#modal-upload-blob').remove();
- blob = new BlobViewer();
-
- mock.onGet('http://test.host/-/snippets/1.json?viewer=rich').reply(200, {
- html: '<div>testing</div>',
- });
-
- mock.onGet('http://test.host/-/snippets/1.json?viewer=simple').reply(200, {
+ mock.onGet(/blob\/master\/README\.md/).reply(200, {
html: '<div>testing</div>',
});
- jest.spyOn(axios, 'get');
+ blob = new BlobViewer();
});
afterEach(() => {
@@ -71,12 +68,11 @@ describe('Blob viewer', () => {
});
it('doesnt reload file if already loaded', () => {
- const asyncClick = () =>
- new Promise(resolve => {
- document.querySelector('.js-blob-viewer-switch-btn[data-viewer="simple"]').click();
+ const asyncClick = async () => {
+ document.querySelector('.js-blob-viewer-switch-btn[data-viewer="simple"]').click();
- setImmediate(resolve);
- });
+ await axios.waitForAll();
+ };
return asyncClick()
.then(() => asyncClick())
@@ -163,17 +159,30 @@ describe('Blob viewer', () => {
expect(simpleBtn.blur).toHaveBeenCalled();
});
- it('sends AJAX request when switching to simple view', () => {
- blob.switchToViewer('simple');
-
- expect(axios.get).toHaveBeenCalled();
+ it('makes request for initial view', () => {
+ expect(mock.history).toMatchObject({
+ get: [{ url: expect.stringMatching(/README\.md\?.*viewer=rich/) }],
+ });
});
- it('does not send AJAX request when switching to rich view', () => {
- blob.switchToViewer('simple');
- blob.switchToViewer('rich');
+ describe.each`
+ views
+ ${['simple']}
+ ${['simple', 'rich']}
+ `('when view switches to $views', ({ views }) => {
+ beforeEach(async () => {
+ views.forEach(view => blob.switchToViewer(view));
+ await axios.waitForAll();
+ });
- expect(axios.get.mock.calls.length).toBe(1);
+ it('sends 1 AJAX request for new view', async () => {
+ expect(mock.history).toMatchObject({
+ get: [
+ { url: expect.stringMatching(/README\.md\?.*viewer=rich/) },
+ { url: expect.stringMatching(/README\.md\?.*viewer=simple/) },
+ ],
+ });
+ });
});
});
});
diff --git a/spec/frontend/blob_edit/blob_bundle_spec.js b/spec/frontend/blob_edit/blob_bundle_spec.js
index a105b62586b..eecc54be35b 100644
--- a/spec/frontend/blob_edit/blob_bundle_spec.js
+++ b/spec/frontend/blob_edit/blob_bundle_spec.js
@@ -1,10 +1,25 @@
import $ from 'jquery';
import { mockTracking, unmockTracking } from 'helpers/tracking_helper';
+import waitForPromises from 'helpers/wait_for_promises';
import blobBundle from '~/blob_edit/blob_bundle';
+import EditorLite from '~/blob_edit/edit_blob';
+
jest.mock('~/blob_edit/edit_blob');
describe('BlobBundle', () => {
+ it('does not load EditorLite by default', () => {
+ blobBundle();
+ expect(EditorLite).not.toHaveBeenCalled();
+ });
+
+ it('loads EditorLite for the edit screen', async () => {
+ setFixtures(`<div class="js-edit-blob-form"></div>`);
+ blobBundle();
+ await waitForPromises();
+ expect(EditorLite).toHaveBeenCalled();
+ });
+
describe('No Suggest Popover', () => {
beforeEach(() => {
setFixtures(`
diff --git a/spec/frontend/blob_edit/edit_blob_spec.js b/spec/frontend/blob_edit/edit_blob_spec.js
index 8f92e8498b9..ac8b916e448 100644
--- a/spec/frontend/blob_edit/edit_blob_spec.js
+++ b/spec/frontend/blob_edit/edit_blob_spec.js
@@ -1,3 +1,4 @@
+import waitForPromises from 'helpers/wait_for_promises';
import EditBlob from '~/blob_edit/edit_blob';
import EditorLite from '~/editor/editor_lite';
import MarkdownExtension from '~/editor/editor_markdown_ext';
@@ -7,7 +8,12 @@ jest.mock('~/editor/editor_lite');
jest.mock('~/editor/editor_markdown_ext');
describe('Blob Editing', () => {
- const mockInstance = 'foo';
+ const useMock = jest.fn();
+ const mockInstance = {
+ use: useMock,
+ getValue: jest.fn(),
+ focus: jest.fn(),
+ };
beforeEach(() => {
setFixtures(
`<div class="js-edit-blob-form"><div id="file_path"></div><div id="editor"></div><input id="file-content"></div>`,
@@ -15,36 +21,33 @@ describe('Blob Editing', () => {
jest.spyOn(EditorLite.prototype, 'createInstance').mockReturnValue(mockInstance);
});
- const initEditor = (isMarkdown = false) => {
+ const editorInst = isMarkdown => {
return new EditBlob({
isMarkdown,
- monacoEnabled: true,
});
};
+ const initEditor = async (isMarkdown = false) => {
+ editorInst(isMarkdown);
+ await waitForPromises();
+ };
+
it('loads FileTemplateExtension by default', async () => {
await initEditor();
- expect(EditorLite.prototype.use).toHaveBeenCalledWith(
- expect.arrayContaining([FileTemplateExtension]),
- mockInstance,
- );
+ expect(useMock).toHaveBeenCalledWith(FileTemplateExtension);
});
describe('Markdown', () => {
it('does not load MarkdownExtension by default', async () => {
await initEditor();
- expect(EditorLite.prototype.use).not.toHaveBeenCalledWith(
- expect.arrayContaining([MarkdownExtension]),
- mockInstance,
- );
+ expect(useMock).not.toHaveBeenCalledWith(MarkdownExtension);
});
it('loads MarkdownExtension only for the markdown files', async () => {
await initEditor(true);
- expect(EditorLite.prototype.use).toHaveBeenCalledWith(
- [MarkdownExtension, FileTemplateExtension],
- mockInstance,
- );
+ expect(useMock).toHaveBeenCalledTimes(2);
+ expect(useMock).toHaveBeenNthCalledWith(1, FileTemplateExtension);
+ expect(useMock).toHaveBeenNthCalledWith(2, MarkdownExtension);
});
});
});
diff --git a/spec/frontend/boards/board_blank_state_spec.js b/spec/frontend/boards/board_blank_state_spec.js
deleted file mode 100644
index 3ffdda52f58..00000000000
--- a/spec/frontend/boards/board_blank_state_spec.js
+++ /dev/null
@@ -1,95 +0,0 @@
-import Vue from 'vue';
-import boardsStore from '~/boards/stores/boards_store';
-import BoardBlankState from '~/boards/components/board_blank_state.vue';
-
-describe('Boards blank state', () => {
- let vm;
- let fail = false;
-
- beforeEach(done => {
- const Comp = Vue.extend(BoardBlankState);
-
- boardsStore.create();
-
- jest.spyOn(boardsStore, 'addList').mockImplementation();
- jest.spyOn(boardsStore, 'removeList').mockImplementation();
- jest.spyOn(boardsStore, 'generateDefaultLists').mockImplementation(
- () =>
- new Promise((resolve, reject) => {
- if (fail) {
- reject();
- } else {
- resolve({
- data: [
- {
- id: 1,
- title: 'To Do',
- label: { id: 1 },
- },
- {
- id: 2,
- title: 'Doing',
- label: { id: 2 },
- },
- ],
- });
- }
- }),
- );
-
- vm = new Comp();
-
- setImmediate(() => {
- vm.$mount();
- done();
- });
- });
-
- it('renders pre-defined labels', () => {
- expect(vm.$el.querySelectorAll('.board-blank-state-list li').length).toBe(2);
-
- expect(vm.$el.querySelectorAll('.board-blank-state-list li')[0].textContent.trim()).toEqual(
- 'To Do',
- );
-
- expect(vm.$el.querySelectorAll('.board-blank-state-list li')[1].textContent.trim()).toEqual(
- 'Doing',
- );
- });
-
- it('clears blank state', done => {
- vm.$el.querySelector('.btn-default').click();
-
- setImmediate(() => {
- expect(boardsStore.welcomeIsHidden()).toBeTruthy();
-
- done();
- });
- });
-
- it('creates pre-defined labels', done => {
- vm.$el.querySelector('.btn-success').click();
-
- setImmediate(() => {
- expect(boardsStore.addList).toHaveBeenCalledTimes(2);
- expect(boardsStore.addList).toHaveBeenCalledWith(expect.objectContaining({ title: 'To Do' }));
-
- expect(boardsStore.addList).toHaveBeenCalledWith(expect.objectContaining({ title: 'Doing' }));
-
- done();
- });
- });
-
- it('resets the store if request fails', done => {
- fail = true;
-
- vm.$el.querySelector('.btn-success').click();
-
- setImmediate(() => {
- expect(boardsStore.welcomeIsHidden()).toBeFalsy();
- expect(boardsStore.removeList).toHaveBeenCalledWith(undefined, 'label');
-
- done();
- });
- });
-});
diff --git a/spec/frontend/boards/board_list_new_spec.js b/spec/frontend/boards/board_list_new_spec.js
new file mode 100644
index 00000000000..163611c2197
--- /dev/null
+++ b/spec/frontend/boards/board_list_new_spec.js
@@ -0,0 +1,234 @@
+/* global List */
+/* global ListIssue */
+
+import Vuex from 'vuex';
+import { useFakeRequestAnimationFrame } from 'helpers/fake_request_animation_frame';
+import { createLocalVue, mount } from '@vue/test-utils';
+import eventHub from '~/boards/eventhub';
+import BoardList from '~/boards/components/board_list_new.vue';
+import BoardCard from '~/boards/components/board_card.vue';
+import '~/boards/models/issue';
+import '~/boards/models/list';
+import { listObj, mockIssuesByListId, issues } from './mock_data';
+import defaultState from '~/boards/stores/state';
+
+const localVue = createLocalVue();
+localVue.use(Vuex);
+
+const actions = {
+ fetchIssuesForList: jest.fn(),
+};
+
+const createStore = (state = defaultState) => {
+ return new Vuex.Store({
+ state,
+ actions,
+ });
+};
+
+const createComponent = ({
+ listIssueProps = {},
+ componentProps = {},
+ listProps = {},
+ state = {},
+} = {}) => {
+ const store = createStore({
+ issuesByListId: mockIssuesByListId,
+ issues,
+ pageInfoByListId: {
+ 'gid://gitlab/List/1': { hasNextPage: true },
+ 'gid://gitlab/List/2': {},
+ },
+ listsFlags: {
+ 'gid://gitlab/List/1': {},
+ 'gid://gitlab/List/2': {},
+ },
+ ...state,
+ });
+
+ const list = new List({
+ ...listObj,
+ id: 'gid://gitlab/List/1',
+ ...listProps,
+ doNotFetchIssues: true,
+ });
+ const issue = new ListIssue({
+ title: 'Testing',
+ id: 1,
+ iid: 1,
+ confidential: false,
+ labels: [],
+ assignees: [],
+ ...listIssueProps,
+ });
+ if (!Object.prototype.hasOwnProperty.call(listProps, 'issuesSize')) {
+ list.issuesSize = 1;
+ }
+
+ const component = mount(BoardList, {
+ localVue,
+ propsData: {
+ disabled: false,
+ list,
+ issues: [issue],
+ ...componentProps,
+ },
+ store,
+ provide: {
+ groupId: null,
+ rootPath: '/',
+ },
+ });
+
+ return component;
+};
+
+describe('Board list component', () => {
+ let wrapper;
+ useFakeRequestAnimationFrame();
+
+ describe('When Expanded', () => {
+ beforeEach(() => {
+ wrapper = createComponent();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('renders component', () => {
+ expect(wrapper.find('.board-list-component').exists()).toBe(true);
+ });
+
+ it('renders loading icon', () => {
+ wrapper = createComponent({
+ state: { listsFlags: { 'gid://gitlab/List/1': { isLoading: true } } },
+ });
+
+ expect(wrapper.find('[data-testid="board_list_loading"').exists()).toBe(true);
+ });
+
+ it('renders issues', () => {
+ expect(wrapper.findAll(BoardCard).length).toBe(1);
+ });
+
+ it('sets data attribute with issue id', () => {
+ expect(wrapper.find('.board-card').attributes('data-issue-id')).toBe('1');
+ });
+
+ it('shows new issue form', async () => {
+ wrapper.vm.toggleForm();
+
+ await wrapper.vm.$nextTick();
+ expect(wrapper.find('.board-new-issue-form').exists()).toBe(true);
+ });
+
+ it('shows new issue form after eventhub event', async () => {
+ eventHub.$emit(`toggle-issue-form-${wrapper.vm.list.id}`);
+
+ await wrapper.vm.$nextTick();
+ expect(wrapper.find('.board-new-issue-form').exists()).toBe(true);
+ });
+
+ it('does not show new issue form for closed list', () => {
+ wrapper.setProps({ list: { type: 'closed' } });
+ wrapper.vm.toggleForm();
+
+ expect(wrapper.find('.board-new-issue-form').exists()).toBe(false);
+ });
+
+ it('shows count list item', async () => {
+ wrapper.vm.showCount = true;
+
+ await wrapper.vm.$nextTick();
+ expect(wrapper.find('.board-list-count').exists()).toBe(true);
+
+ expect(wrapper.find('.board-list-count').text()).toBe('Showing all issues');
+ });
+
+ it('sets data attribute with invalid id', async () => {
+ wrapper.vm.showCount = true;
+
+ await wrapper.vm.$nextTick();
+ expect(wrapper.find('.board-list-count').attributes('data-issue-id')).toBe('-1');
+ });
+
+ it('shows how many more issues to load', async () => {
+ wrapper.vm.showCount = true;
+ wrapper.setProps({ list: { issuesSize: 20 } });
+
+ await wrapper.vm.$nextTick();
+ expect(wrapper.find('.board-list-count').text()).toBe('Showing 1 of 20 issues');
+ });
+ });
+
+ describe('load more issues', () => {
+ beforeEach(() => {
+ wrapper = createComponent({
+ listProps: { issuesSize: 25 },
+ });
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('loads more issues after scrolling', () => {
+ wrapper.vm.$refs.list.dispatchEvent(new Event('scroll'));
+
+ expect(actions.fetchIssuesForList).toHaveBeenCalled();
+ });
+
+ it('does not load issues if already loading', () => {
+ wrapper.vm.$refs.list.dispatchEvent(new Event('scroll'));
+ wrapper.vm.$refs.list.dispatchEvent(new Event('scroll'));
+
+ expect(actions.fetchIssuesForList).toHaveBeenCalledTimes(1);
+ });
+
+ it('shows loading more spinner', async () => {
+ wrapper.vm.showCount = true;
+ wrapper.vm.list.loadingMore = true;
+
+ await wrapper.vm.$nextTick();
+ expect(wrapper.find('.board-list-count .gl-spinner').exists()).toBe(true);
+ });
+ });
+
+ describe('max issue count warning', () => {
+ beforeEach(() => {
+ wrapper = createComponent({
+ listProps: { issuesSize: 50 },
+ });
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe('when issue count exceeds max issue count', () => {
+ it('sets background to bg-danger-100', async () => {
+ wrapper.setProps({ list: { issuesSize: 4, maxIssueCount: 3 } });
+
+ await wrapper.vm.$nextTick();
+ expect(wrapper.find('.bg-danger-100').exists()).toBe(true);
+ });
+ });
+
+ describe('when list issue count does NOT exceed list max issue count', () => {
+ it('does not sets background to bg-danger-100', () => {
+ wrapper.setProps({ list: { issuesSize: 2, maxIssueCount: 3 } });
+
+ expect(wrapper.find('.bg-danger-100').exists()).toBe(false);
+ });
+ });
+
+ describe('when list max issue count is 0', () => {
+ it('does not sets background to bg-danger-100', () => {
+ wrapper.setProps({ list: { maxIssueCount: 0 } });
+
+ expect(wrapper.find('.bg-danger-100').exists()).toBe(false);
+ });
+ });
+ });
+});
diff --git a/spec/frontend/boards/board_list_spec.js b/spec/frontend/boards/board_list_spec.js
index 88883ae61d4..0fe3c88f518 100644
--- a/spec/frontend/boards/board_list_spec.js
+++ b/spec/frontend/boards/board_list_spec.js
@@ -44,7 +44,6 @@ const createComponent = ({ done, listIssueProps = {}, componentProps = {}, listP
disabled: false,
list,
issues: list.issues,
- loading: false,
...componentProps,
},
provide: {
@@ -94,7 +93,7 @@ describe('Board list component', () => {
});
it('renders loading icon', () => {
- component.loading = true;
+ component.list.loading = true;
return Vue.nextTick().then(() => {
expect(component.$el.querySelector('.board-list-loading')).not.toBeNull();
diff --git a/spec/frontend/boards/boards_store_spec.js b/spec/frontend/boards/boards_store_spec.js
index 41971137b95..e7c1cf79fdc 100644
--- a/spec/frontend/boards/boards_store_spec.js
+++ b/spec/frontend/boards/boards_store_spec.js
@@ -1,7 +1,7 @@
import AxiosMockAdapter from 'axios-mock-adapter';
import { TEST_HOST } from 'helpers/test_constants';
import axios from '~/lib/utils/axios_utils';
-import boardsStore from '~/boards/stores/boards_store';
+import boardsStore, { gqlClient } from '~/boards/stores/boards_store';
import eventHub from '~/boards/eventhub';
import { listObj, listObjDuplicate } from './mock_data';
@@ -503,11 +503,15 @@ describe('boardsStore', () => {
beforeEach(() => {
requestSpy = jest.fn();
axiosMock.onPut(url).replyOnce(config => requestSpy(config));
+ jest.spyOn(gqlClient, 'mutate').mockReturnValue(Promise.resolve({}));
});
it('makes a request to update the board', () => {
requestSpy.mockReturnValue([200, dummyResponse]);
- const expectedResponse = expect.objectContaining({ data: dummyResponse });
+ const expectedResponse = [
+ expect.objectContaining({ data: dummyResponse }),
+ expect.objectContaining({}),
+ ];
return expect(
boardsStore.createBoard({
@@ -555,11 +559,12 @@ describe('boardsStore', () => {
beforeEach(() => {
requestSpy = jest.fn();
axiosMock.onPost(url).replyOnce(config => requestSpy(config));
+ jest.spyOn(gqlClient, 'mutate').mockReturnValue(Promise.resolve({}));
});
it('makes a request to create a new board', () => {
requestSpy.mockReturnValue([200, dummyResponse]);
- const expectedResponse = expect.objectContaining({ data: dummyResponse });
+ const expectedResponse = dummyResponse;
return expect(boardsStore.createBoard(board))
.resolves.toEqual(expectedResponse)
@@ -740,14 +745,6 @@ describe('boardsStore', () => {
expect(boardsStore.shouldAddBlankState()).toBe(true);
});
- it('adds the blank state', () => {
- boardsStore.addBlankState();
-
- const list = boardsStore.findList('type', 'blank', 'blank');
-
- expect(list).toBeDefined();
- });
-
it('removes list from state', () => {
boardsStore.addList(listObj);
diff --git a/spec/frontend/boards/components/board_configuration_options_spec.js b/spec/frontend/boards/components/board_configuration_options_spec.js
new file mode 100644
index 00000000000..e9a1cb6a4e8
--- /dev/null
+++ b/spec/frontend/boards/components/board_configuration_options_spec.js
@@ -0,0 +1,59 @@
+import { shallowMount } from '@vue/test-utils';
+import BoardConfigurationOptions from '~/boards/components/board_configuration_options.vue';
+
+describe('BoardConfigurationOptions', () => {
+ let wrapper;
+ const board = { hide_backlog_list: false, hide_closed_list: false };
+
+ const defaultProps = {
+ currentBoard: board,
+ board,
+ isNewForm: false,
+ };
+
+ const createComponent = () => {
+ wrapper = shallowMount(BoardConfigurationOptions, {
+ propsData: { ...defaultProps },
+ });
+ };
+
+ beforeEach(() => {
+ createComponent();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ const backlogListCheckbox = el => el.find('[data-testid="backlog-list-checkbox"]');
+ const closedListCheckbox = el => el.find('[data-testid="closed-list-checkbox"]');
+
+ const checkboxAssert = (backlogCheckbox, closedCheckbox) => {
+ expect(backlogListCheckbox(wrapper).attributes('checked')).toEqual(
+ backlogCheckbox ? undefined : 'true',
+ );
+ expect(closedListCheckbox(wrapper).attributes('checked')).toEqual(
+ closedCheckbox ? undefined : 'true',
+ );
+ };
+
+ it.each`
+ backlogCheckboxValue | closedCheckboxValue
+ ${true} | ${true}
+ ${true} | ${false}
+ ${false} | ${true}
+ ${false} | ${false}
+ `(
+ 'renders two checkbox when one is $backlogCheckboxValue and other is $closedCheckboxValue',
+ async ({ backlogCheckboxValue, closedCheckboxValue }) => {
+ await wrapper.setData({
+ hideBacklogList: backlogCheckboxValue,
+ hideClosedList: closedCheckboxValue,
+ });
+
+ return wrapper.vm.$nextTick().then(() => {
+ checkboxAssert(backlogCheckboxValue, closedCheckboxValue);
+ });
+ },
+ );
+});
diff --git a/spec/frontend/boards/components/board_content_spec.js b/spec/frontend/boards/components/board_content_spec.js
index df117d06cdf..09e38001e2e 100644
--- a/spec/frontend/boards/components/board_content_spec.js
+++ b/spec/frontend/boards/components/board_content_spec.js
@@ -23,9 +23,6 @@ describe('BoardContent', () => {
return new Vuex.Store({
getters,
state,
- actions: {
- fetchIssuesForAllLists: () => {},
- },
});
};
diff --git a/spec/frontend/boards/components/sidebar/board_editable_item_spec.js b/spec/frontend/boards/components/sidebar/board_editable_item_spec.js
index 1dbcbd06407..d7df2ff1563 100644
--- a/spec/frontend/boards/components/sidebar/board_editable_item_spec.js
+++ b/spec/frontend/boards/components/sidebar/board_editable_item_spec.js
@@ -96,12 +96,34 @@ describe('boards sidebar remove issue', () => {
expect(findExpanded().isVisible()).toBe(false);
});
- it('emits changed event', async () => {
+ it('emits close event', async () => {
document.body.click();
await wrapper.vm.$nextTick();
- expect(wrapper.emitted().changed[1][0]).toBe(false);
+ expect(wrapper.emitted().close.length).toBe(1);
});
});
+
+ it('emits open when edit button is clicked and edit is initailized to false', async () => {
+ createComponent({ canUpdate: true });
+
+ findEditButton().vm.$emit('click');
+
+ await wrapper.vm.$nextTick();
+
+ expect(wrapper.emitted().open.length).toBe(1);
+ });
+
+ it('does not emits events when collapsing with false `emitEvent`', async () => {
+ createComponent({ canUpdate: true });
+
+ findEditButton().vm.$emit('click');
+
+ await wrapper.vm.$nextTick();
+
+ wrapper.vm.collapse({ emitEvent: false });
+
+ expect(wrapper.emitted().close).toBeUndefined();
+ });
});
diff --git a/spec/frontend/boards/components/sidebar/board_sidebar_labels_select_spec.js b/spec/frontend/boards/components/sidebar/board_sidebar_labels_select_spec.js
new file mode 100644
index 00000000000..da000d21f6a
--- /dev/null
+++ b/spec/frontend/boards/components/sidebar/board_sidebar_labels_select_spec.js
@@ -0,0 +1,143 @@
+import { shallowMount } from '@vue/test-utils';
+import { GlLabel } from '@gitlab/ui';
+import { TEST_HOST } from 'helpers/test_constants';
+import { labels as TEST_LABELS, mockIssue as TEST_ISSUE } from 'jest/boards/mock_data';
+import BoardSidebarLabelsSelect from '~/boards/components/sidebar/board_sidebar_labels_select.vue';
+import BoardEditableItem from '~/boards/components/sidebar/board_editable_item.vue';
+import { getIdFromGraphQLId } from '~/graphql_shared/utils';
+import { createStore } from '~/boards/stores';
+import createFlash from '~/flash';
+
+jest.mock('~/flash');
+
+const TEST_LABELS_PAYLOAD = TEST_LABELS.map(label => ({ ...label, set: true }));
+const TEST_LABELS_TITLES = TEST_LABELS.map(label => label.title);
+
+describe('~/boards/components/sidebar/board_sidebar_labels_select.vue', () => {
+ let wrapper;
+ let store;
+
+ afterEach(() => {
+ wrapper.destroy();
+ store = null;
+ wrapper = null;
+ });
+
+ const createWrapper = ({ labels = [] } = {}) => {
+ store = createStore();
+ store.state.issues = { [TEST_ISSUE.id]: { ...TEST_ISSUE, labels } };
+ store.state.activeId = TEST_ISSUE.id;
+
+ wrapper = shallowMount(BoardSidebarLabelsSelect, {
+ store,
+ provide: {
+ canUpdate: true,
+ labelsFetchPath: TEST_HOST,
+ labelsManagePath: TEST_HOST,
+ labelsFilterBasePath: TEST_HOST,
+ },
+ stubs: {
+ 'board-editable-item': BoardEditableItem,
+ 'labels-select': '<div></div>',
+ },
+ });
+ };
+
+ const findLabelsSelect = () => wrapper.find({ ref: 'labelsSelect' });
+ const findLabelsTitles = () => wrapper.findAll(GlLabel).wrappers.map(item => item.props('title'));
+ const findCollapsed = () => wrapper.find('[data-testid="collapsed-content"]');
+
+ it('renders "None" when no labels are selected', () => {
+ createWrapper();
+
+ expect(findCollapsed().text()).toBe('None');
+ });
+
+ it('renders labels when set', () => {
+ createWrapper({ labels: TEST_LABELS });
+
+ expect(findLabelsTitles()).toEqual(TEST_LABELS_TITLES);
+ });
+
+ describe('when labels are submitted', () => {
+ beforeEach(async () => {
+ createWrapper();
+
+ jest.spyOn(wrapper.vm, 'setActiveIssueLabels').mockImplementation(() => TEST_LABELS);
+ findLabelsSelect().vm.$emit('updateSelectedLabels', TEST_LABELS_PAYLOAD);
+ store.state.issues[TEST_ISSUE.id].labels = TEST_LABELS;
+ await wrapper.vm.$nextTick();
+ });
+
+ it('collapses sidebar and renders labels', () => {
+ expect(findCollapsed().isVisible()).toBe(true);
+ expect(findLabelsTitles()).toEqual(TEST_LABELS_TITLES);
+ });
+
+ it('commits change to the server', () => {
+ expect(wrapper.vm.setActiveIssueLabels).toHaveBeenCalledWith({
+ addLabelIds: TEST_LABELS.map(label => label.id),
+ projectPath: 'gitlab-org/test-subgroup/gitlab-test',
+ removeLabelIds: [],
+ });
+ });
+ });
+
+ describe('when labels are updated over existing labels', () => {
+ const testLabelsPayload = [{ id: 5, set: true }, { id: 7, set: true }];
+ const expectedLabels = [{ id: 5 }, { id: 7 }];
+
+ beforeEach(async () => {
+ createWrapper({ labels: TEST_LABELS });
+
+ jest.spyOn(wrapper.vm, 'setActiveIssueLabels').mockImplementation(() => expectedLabels);
+ findLabelsSelect().vm.$emit('updateSelectedLabels', testLabelsPayload);
+ await wrapper.vm.$nextTick();
+ });
+
+ it('commits change to the server', () => {
+ expect(wrapper.vm.setActiveIssueLabels).toHaveBeenCalledWith({
+ addLabelIds: [5, 7],
+ removeLabelIds: [6],
+ projectPath: 'gitlab-org/test-subgroup/gitlab-test',
+ });
+ });
+ });
+
+ describe('when removing individual labels', () => {
+ const testLabel = TEST_LABELS[0];
+
+ beforeEach(async () => {
+ createWrapper({ labels: [testLabel] });
+
+ jest.spyOn(wrapper.vm, 'setActiveIssueLabels').mockImplementation(() => {});
+ });
+
+ it('commits change to the server', () => {
+ wrapper.find(GlLabel).vm.$emit('close', testLabel);
+
+ expect(wrapper.vm.setActiveIssueLabels).toHaveBeenCalledWith({
+ removeLabelIds: [getIdFromGraphQLId(testLabel.id)],
+ projectPath: 'gitlab-org/test-subgroup/gitlab-test',
+ });
+ });
+ });
+
+ describe('when the mutation fails', () => {
+ beforeEach(async () => {
+ createWrapper({ labels: TEST_LABELS });
+
+ jest.spyOn(wrapper.vm, 'setActiveIssueLabels').mockImplementation(() => {
+ throw new Error(['failed mutation']);
+ });
+ findLabelsSelect().vm.$emit('updateSelectedLabels', [{ id: '?' }]);
+ await wrapper.vm.$nextTick();
+ });
+
+ it('collapses sidebar and renders former issue weight', () => {
+ expect(findCollapsed().isVisible()).toBe(true);
+ expect(findLabelsTitles()).toEqual(TEST_LABELS_TITLES);
+ expect(createFlash).toHaveBeenCalled();
+ });
+ });
+});
diff --git a/spec/frontend/boards/mock_data.js b/spec/frontend/boards/mock_data.js
index 5776332c499..50c0a85fc70 100644
--- a/spec/frontend/boards/mock_data.js
+++ b/spec/frontend/boards/mock_data.js
@@ -108,13 +108,19 @@ const assignees = [
},
];
-const labels = [
+export const labels = [
{
id: 'gid://gitlab/GroupLabel/5',
title: 'Cosync',
color: '#34ebec',
description: null,
},
+ {
+ id: 'gid://gitlab/GroupLabel/6',
+ title: 'Brock',
+ color: '#e082b6',
+ description: null,
+ },
];
export const rawIssue = {
diff --git a/spec/frontend/boards/stores/actions_spec.js b/spec/frontend/boards/stores/actions_spec.js
index bdbcd435708..78e70161121 100644
--- a/spec/frontend/boards/stores/actions_spec.js
+++ b/spec/frontend/boards/stores/actions_spec.js
@@ -6,12 +6,14 @@ import {
mockIssueWithModel,
mockIssue2WithModel,
rawIssue,
+ mockIssues,
+ labels,
} from '../mock_data';
import actions, { gqlClient } from '~/boards/stores/actions';
import * as types from '~/boards/stores/mutation_types';
import { inactiveId, ListType } from '~/boards/constants';
import issueMoveListMutation from '~/boards/queries/issue_move_list.mutation.graphql';
-import { fullBoardId } from '~/boards/boards_util';
+import { fullBoardId, formatListIssues, formatBoardLists } from '~/boards/boards_util';
const expectNotImplemented = action => {
it('is not implemented', () => {
@@ -76,6 +78,80 @@ describe('setActiveId', () => {
});
});
+describe('fetchLists', () => {
+ const state = {
+ endpoints: {
+ fullPath: 'gitlab-org',
+ boardId: 1,
+ },
+ filterParams: {},
+ boardType: 'group',
+ };
+
+ let queryResponse = {
+ data: {
+ group: {
+ board: {
+ hideBacklogList: true,
+ lists: {
+ nodes: [mockLists[1]],
+ },
+ },
+ },
+ },
+ };
+
+ const formattedLists = formatBoardLists(queryResponse.data.group.board.lists);
+
+ it('should commit mutations RECEIVE_BOARD_LISTS_SUCCESS on success', done => {
+ jest.spyOn(gqlClient, 'query').mockResolvedValue(queryResponse);
+
+ testAction(
+ actions.fetchLists,
+ {},
+ state,
+ [
+ {
+ type: types.RECEIVE_BOARD_LISTS_SUCCESS,
+ payload: formattedLists,
+ },
+ ],
+ [{ type: 'showWelcomeList' }],
+ done,
+ );
+ });
+
+ it('dispatch createList action when backlog list does not exist and is not hidden', done => {
+ queryResponse = {
+ data: {
+ group: {
+ board: {
+ hideBacklogList: false,
+ lists: {
+ nodes: [mockLists[1]],
+ },
+ },
+ },
+ },
+ };
+ jest.spyOn(gqlClient, 'query').mockResolvedValue(queryResponse);
+
+ testAction(
+ actions.fetchLists,
+ {},
+ state,
+ [
+ {
+ type: types.RECEIVE_BOARD_LISTS_SUCCESS,
+ payload: formattedLists,
+ },
+ ],
+ [{ type: 'createList', payload: { backlog: true } }, { type: 'showWelcomeList' }],
+ done,
+ );
+ });
+});
+
describe('showWelcomeList', () => {
it('should dispatch addList action', done => {
const state = {
@@ -176,16 +252,26 @@ describe('createList', () => {
describe('moveList', () => {
it('should commit MOVE_LIST mutation and dispatch updateList action', done => {
+ const initialBoardListsState = {
+ 'gid://gitlab/List/1': mockListsWithModel[0],
+ 'gid://gitlab/List/2': mockListsWithModel[1],
+ };
+
const state = {
endpoints: { fullPath: 'gitlab-org', boardId: '1' },
boardType: 'group',
disabled: false,
- boardLists: mockListsWithModel,
+ boardLists: initialBoardListsState,
};
testAction(
actions.moveList,
- { listId: 'gid://gitlab/List/1', newIndex: 1, adjustmentValue: 1 },
+ {
+ listId: 'gid://gitlab/List/1',
+ replacedListId: 'gid://gitlab/List/2',
+ newIndex: 1,
+ adjustmentValue: 1,
+ },
state,
[
{
@@ -196,7 +282,11 @@ describe('moveList', () => {
[
{
type: 'updateList',
- payload: { listId: 'gid://gitlab/List/1', position: 0, backupList: mockListsWithModel },
+ payload: {
+ listId: 'gid://gitlab/List/1',
+ position: 0,
+ backupList: initialBoardListsState,
+ },
},
],
done,
@@ -237,6 +327,99 @@ describe('deleteList', () => {
expectNotImplemented(actions.deleteList);
});
+describe('fetchIssuesForList', () => {
+ const listId = mockLists[0].id;
+
+ const state = {
+ endpoints: {
+ fullPath: 'gitlab-org',
+ boardId: 1,
+ },
+ filterParams: {},
+ boardType: 'group',
+ };
+
+ const mockIssuesNodes = mockIssues.map(issue => ({ node: issue }));
+
+ const pageInfo = {
+ endCursor: '',
+ hasNextPage: false,
+ };
+
+ const queryResponse = {
+ data: {
+ group: {
+ board: {
+ lists: {
+ nodes: [
+ {
+ id: listId,
+ issues: {
+ edges: mockIssuesNodes,
+ pageInfo,
+ },
+ },
+ ],
+ },
+ },
+ },
+ },
+ };
+
+ const formattedIssues = formatListIssues(queryResponse.data.group.board.lists);
+
+ const listPageInfo = {
+ [listId]: pageInfo,
+ };
+
+ it('should commit mutations REQUEST_ISSUES_FOR_LIST and RECEIVE_ISSUES_FOR_LIST_SUCCESS on success', done => {
+ jest.spyOn(gqlClient, 'query').mockResolvedValue(queryResponse);
+
+ testAction(
+ actions.fetchIssuesForList,
+ { listId },
+ state,
+ [
+ {
+ type: types.REQUEST_ISSUES_FOR_LIST,
+ payload: { listId, fetchNext: false },
+ },
+ {
+ type: types.RECEIVE_ISSUES_FOR_LIST_SUCCESS,
+ payload: { listIssues: formattedIssues, listPageInfo, listId },
+ },
+ ],
+ [],
+ done,
+ );
+ });
+
+ it('should commit mutations REQUEST_ISSUES_FOR_LIST and RECEIVE_ISSUES_FOR_LIST_FAILURE on failure', done => {
+ jest.spyOn(gqlClient, 'query').mockResolvedValue(Promise.reject());
+
+ testAction(
+ actions.fetchIssuesForList,
+ { listId },
+ state,
+ [
+ {
+ type: types.REQUEST_ISSUES_FOR_LIST,
+ payload: { listId, fetchNext: false },
+ },
+ { type: types.RECEIVE_ISSUES_FOR_LIST_FAILURE, payload: listId },
+ ],
+ [],
+ done,
+ );
+ });
+});
+
+describe('resetIssues', () => {
+ it('commits RESET_ISSUES mutation', () => {
+ return testAction(actions.resetIssues, {}, {}, [{ type: types.RESET_ISSUES }], []);
+ });
+});
+
describe('moveIssue', () => {
const listIssues = {
'gid://gitlab/List/1': [436, 437],
@@ -418,6 +601,51 @@ describe('addListIssueFailure', () => {
});
});
+describe('setActiveIssueLabels', () => {
+ const state = { issues: { [mockIssue.id]: mockIssue } };
+ const getters = { getActiveIssue: mockIssue };
+ const testLabelIds = labels.map(label => label.id);
+ const input = {
+ addLabelIds: testLabelIds,
+ removeLabelIds: [],
+ projectPath: 'h/b',
+ };
+
+ it('should assign labels on success', done => {
+ jest
+ .spyOn(gqlClient, 'mutate')
+ .mockResolvedValue({ data: { updateIssue: { issue: { labels: { nodes: labels } } } } });
+
+ const payload = {
+ issueId: getters.getActiveIssue.id,
+ prop: 'labels',
+ value: labels,
+ };
+
+ testAction(
+ actions.setActiveIssueLabels,
+ input,
+ { ...state, ...getters },
+ [
+ {
+ type: types.UPDATE_ISSUE_BY_ID,
+ payload,
+ },
+ ],
+ [],
+ done,
+ );
+ });
+
+ it('throws error if fails', async () => {
+ jest
+ .spyOn(gqlClient, 'mutate')
+ .mockResolvedValue({ data: { updateIssue: { errors: ['failed mutation'] } } });
+
+ await expect(actions.setActiveIssueLabels({ getters }, input)).rejects.toThrow(Error);
+ });
+});
+
describe('fetchBacklog', () => {
expectNotImplemented(actions.fetchBacklog);
});
diff --git a/spec/frontend/boards/stores/getters_spec.js b/spec/frontend/boards/stores/getters_spec.js
index 288143a0f21..b987080abab 100644
--- a/spec/frontend/boards/stores/getters_spec.js
+++ b/spec/frontend/boards/stores/getters_spec.js
@@ -1,6 +1,13 @@
import getters from '~/boards/stores/getters';
import { inactiveId } from '~/boards/constants';
-import { mockIssue, mockIssue2, mockIssues, mockIssuesByListId, issues } from '../mock_data';
+import {
+ mockIssue,
+ mockIssue2,
+ mockIssues,
+ mockIssuesByListId,
+ issues,
+ mockListsWithModel,
+} from '../mock_data';
describe('Boards - Getters', () => {
describe('getLabelToggleState', () => {
@@ -130,4 +137,25 @@ describe('Boards - Getters', () => {
);
});
});
+
+ const boardsState = {
+ boardLists: {
+ 'gid://gitlab/List/1': mockListsWithModel[0],
+ 'gid://gitlab/List/2': mockListsWithModel[1],
+ },
+ };
+
+ describe('getListByLabelId', () => {
+ it('returns list for a given label id', () => {
+ expect(getters.getListByLabelId(boardsState)('gid://gitlab/GroupLabel/121')).toEqual(
+ mockListsWithModel[1],
+ );
+ });
+ });
+
+ describe('getListByTitle', () => {
+ it('returns list for a given list title', () => {
+ expect(getters.getListByTitle(boardsState)('To Do')).toEqual(mockListsWithModel[1]);
+ });
+ });
});
diff --git a/spec/frontend/boards/stores/mutations_spec.js b/spec/frontend/boards/stores/mutations_spec.js
index a13a99a507e..6e53f184bb3 100644
--- a/spec/frontend/boards/stores/mutations_spec.js
+++ b/spec/frontend/boards/stores/mutations_spec.js
@@ -2,8 +2,6 @@ import mutations from '~/boards/stores/mutations';
import * as types from '~/boards/stores/mutation_types';
import defaultState from '~/boards/stores/state';
import {
- listObj,
- listObjDuplicate,
mockListsWithModel,
mockLists,
rawIssue,
@@ -22,6 +20,11 @@ const expectNotImplemented = action => {
describe('Board Store Mutations', () => {
let state;
+ const initialBoardListsState = {
+ 'gid://gitlab/List/1': mockListsWithModel[0],
+ 'gid://gitlab/List/2': mockListsWithModel[1],
+ };
+
beforeEach(() => {
state = defaultState();
});
@@ -56,11 +59,19 @@ describe('Board Store Mutations', () => {
describe('RECEIVE_BOARD_LISTS_SUCCESS', () => {
it('Should set boardLists to state', () => {
- const lists = [listObj, listObjDuplicate];
+ mutations[types.RECEIVE_BOARD_LISTS_SUCCESS](state, initialBoardListsState);
+
+ expect(state.boardLists).toEqual(initialBoardListsState);
+ });
+ });
- mutations[types.RECEIVE_BOARD_LISTS_SUCCESS](state, lists);
+ describe('RECEIVE_BOARD_LISTS_FAILURE', () => {
+ it('Should set error in state', () => {
+ mutations[types.RECEIVE_BOARD_LISTS_FAILURE](state);
- expect(state.boardLists).toEqual(lists);
+ expect(state.error).toEqual(
+ 'An error occurred while fetching the board lists. Please reload the page.',
+ );
});
});
@@ -95,7 +106,13 @@ describe('Board Store Mutations', () => {
});
describe('RECEIVE_ADD_LIST_SUCCESS', () => {
- expectNotImplemented(mutations.RECEIVE_ADD_LIST_SUCCESS);
+ it('adds list to boardLists state', () => {
+ mutations.RECEIVE_ADD_LIST_SUCCESS(state, mockListsWithModel[0]);
+
+ expect(state.boardLists).toEqual({
+ [mockListsWithModel[0].id]: mockListsWithModel[0],
+ });
+ });
});
describe('RECEIVE_ADD_LIST_ERROR', () => {
@@ -106,7 +123,7 @@ describe('Board Store Mutations', () => {
it('updates boardLists state with reordered lists', () => {
state = {
...state,
- boardLists: mockListsWithModel,
+ boardLists: initialBoardListsState,
};
mutations.MOVE_LIST(state, {
@@ -114,7 +131,10 @@ describe('Board Store Mutations', () => {
listAtNewIndex: mockListsWithModel[1],
});
- expect(state.boardLists).toEqual([mockListsWithModel[1], mockListsWithModel[0]]);
+ expect(state.boardLists).toEqual({
+ 'gid://gitlab/List/2': mockListsWithModel[1],
+ 'gid://gitlab/List/1': mockListsWithModel[0],
+ });
});
});
@@ -122,13 +142,16 @@ describe('Board Store Mutations', () => {
it('updates boardLists state with previous order and sets error message', () => {
state = {
...state,
- boardLists: [mockListsWithModel[1], mockListsWithModel[0]],
+ boardLists: {
+ 'gid://gitlab/List/2': mockListsWithModel[1],
+ 'gid://gitlab/List/1': mockListsWithModel[0],
+ },
error: undefined,
};
- mutations.UPDATE_LIST_FAILURE(state, mockListsWithModel);
+ mutations.UPDATE_LIST_FAILURE(state, initialBoardListsState);
- expect(state.boardLists).toEqual(mockListsWithModel);
+ expect(state.boardLists).toEqual(initialBoardListsState);
expect(state.error).toEqual('An error occurred while updating the list. Please try again.');
});
});
@@ -145,6 +168,23 @@ describe('Board Store Mutations', () => {
expectNotImplemented(mutations.RECEIVE_REMOVE_LIST_ERROR);
});
+ describe('RESET_ISSUES', () => {
+ it('should remove issues from issuesByListId state', () => {
+ const issuesByListId = {
+ 'gid://gitlab/List/1': [mockIssue.id],
+ };
+
+ state = {
+ ...state,
+ issuesByListId,
+ };
+
+ mutations[types.RESET_ISSUES](state);
+
+ expect(state.issuesByListId).toEqual({ 'gid://gitlab/List/1': [] });
+ });
+ });
+
describe('RECEIVE_ISSUES_FOR_LIST_SUCCESS', () => {
it('updates issuesByListId and issues on state', () => {
const listIssues = {
@@ -156,14 +196,23 @@ describe('Board Store Mutations', () => {
state = {
...state,
- isLoadingIssues: true,
- issuesByListId: {},
+ issuesByListId: {
+ 'gid://gitlab/List/1': [],
+ },
issues: {},
- boardLists: mockListsWithModel,
+ boardLists: initialBoardListsState,
+ };
+
+ const listPageInfo = {
+ 'gid://gitlab/List/1': {
+ endCursor: '',
+ hasNextPage: false,
+ },
};
mutations.RECEIVE_ISSUES_FOR_LIST_SUCCESS(state, {
listIssues: { listData: listIssues, issues },
+ listPageInfo,
listId: 'gid://gitlab/List/1',
});
@@ -172,21 +221,11 @@ describe('Board Store Mutations', () => {
});
});
- describe('REQUEST_ISSUES_FOR_ALL_LISTS', () => {
- it('sets isLoadingIssues to true', () => {
- expect(state.isLoadingIssues).toBe(false);
-
- mutations.REQUEST_ISSUES_FOR_ALL_LISTS(state);
-
- expect(state.isLoadingIssues).toBe(true);
- });
- });
-
describe('RECEIVE_ISSUES_FOR_LIST_FAILURE', () => {
it('sets error message', () => {
state = {
...state,
- boardLists: mockListsWithModel,
+ boardLists: initialBoardListsState,
error: undefined,
};
@@ -200,51 +239,10 @@ describe('Board Store Mutations', () => {
});
});
- describe('RECEIVE_ISSUES_FOR_ALL_LISTS_SUCCESS', () => {
- it('sets isLoadingIssues to false and updates issuesByListId object', () => {
- const listIssues = {
- 'gid://gitlab/List/1': [mockIssue.id],
- };
- const issues = {
- '1': mockIssue,
- };
-
- state = {
- ...state,
- isLoadingIssues: true,
- issuesByListId: {},
- issues: {},
- };
-
- mutations.RECEIVE_ISSUES_FOR_ALL_LISTS_SUCCESS(state, { listData: listIssues, issues });
-
- expect(state.isLoadingIssues).toBe(false);
- expect(state.issuesByListId).toEqual(listIssues);
- expect(state.issues).toEqual(issues);
- });
- });
-
describe('REQUEST_ADD_ISSUE', () => {
expectNotImplemented(mutations.REQUEST_ADD_ISSUE);
});
- describe('RECEIVE_ISSUES_FOR_ALL_LISTS_FAILURE', () => {
- it('sets isLoadingIssues to false and sets error message', () => {
- state = {
- ...state,
- isLoadingIssues: true,
- error: undefined,
- };
-
- mutations.RECEIVE_ISSUES_FOR_ALL_LISTS_FAILURE(state);
-
- expect(state.isLoadingIssues).toBe(false);
- expect(state.error).toEqual(
- 'An error occurred while fetching the board issues. Please reload the page.',
- );
- });
- });
-
describe('UPDATE_ISSUE_BY_ID', () => {
const issueId = '1';
const prop = 'id';
@@ -254,7 +252,6 @@ describe('Board Store Mutations', () => {
beforeEach(() => {
state = {
...state,
- isLoadingIssues: true,
error: undefined,
issues: {
...issue,
@@ -310,7 +307,7 @@ describe('Board Store Mutations', () => {
state = {
...state,
issuesByListId: listIssues,
- boardLists: mockListsWithModel,
+ boardLists: initialBoardListsState,
issues,
};
@@ -358,6 +355,7 @@ describe('Board Store Mutations', () => {
state = {
...state,
issuesByListId: listIssues,
+ boardLists: initialBoardListsState,
};
mutations.MOVE_ISSUE_FAILURE(state, {
@@ -425,6 +423,7 @@ describe('Board Store Mutations', () => {
...state,
issuesByListId: listIssues,
issues,
+ boardLists: initialBoardListsState,
};
mutations.ADD_ISSUE_TO_LIST_FAILURE(state, { list: mockLists[0], issue: mockIssue2 });
diff --git a/spec/frontend/ci_lint/components/ci_lint_results_spec.js b/spec/frontend/ci_lint/components/ci_lint_results_spec.js
new file mode 100644
index 00000000000..37575a988c5
--- /dev/null
+++ b/spec/frontend/ci_lint/components/ci_lint_results_spec.js
@@ -0,0 +1,114 @@
+import { shallowMount, mount } from '@vue/test-utils';
+import { GlTable } from '@gitlab/ui';
+import CiLintResults from '~/ci_lint/components/ci_lint_results.vue';
+import { capitalizeFirstCharacter } from '~/lib/utils/text_utility';
+import { mockJobs, mockErrors, mockWarnings } from '../mock_data';
+
+describe('CI Lint Results', () => {
+ let wrapper;
+
+ const createComponent = (props = {}, mountFn = shallowMount) => {
+ wrapper = mountFn(CiLintResults, {
+ propsData: {
+ valid: true,
+ jobs: mockJobs,
+ errors: [],
+ warnings: [],
+ dryRun: false,
+ ...props,
+ },
+ });
+ };
+
+ const findTable = () => wrapper.find(GlTable);
+ const findByTestId = selector => () => wrapper.find(`[data-testid="ci-lint-${selector}"]`);
+ const findAllByTestId = selector => () => wrapper.findAll(`[data-testid="ci-lint-${selector}"]`);
+ const findErrors = findByTestId('errors');
+ const findWarnings = findByTestId('warnings');
+ const findStatus = findByTestId('status');
+ const findOnlyExcept = findByTestId('only-except');
+ const findLintParameters = findAllByTestId('parameter');
+ const findBeforeScripts = findAllByTestId('before-script');
+ const findScripts = findAllByTestId('script');
+ const findAfterScripts = findAllByTestId('after-script');
+ const filterEmptyScripts = property => mockJobs.filter(job => job[property].length !== 0);
+
+ afterEach(() => {
+ wrapper.destroy();
+ wrapper = null;
+ });
+
+ describe('Invalid results', () => {
+ beforeEach(() => {
+ createComponent({ valid: false, errors: mockErrors, warnings: mockWarnings }, mount);
+ });
+
+ it('does not display the table', () => {
+ expect(findTable().exists()).toBe(false);
+ });
+
+ it('displays the invalid status', () => {
+ expect(findStatus().text()).toBe(`Status: ${wrapper.vm.$options.incorrect.text}`);
+ expect(findStatus().props('variant')).toBe(wrapper.vm.$options.incorrect.variant);
+ });
+
+ it('displays the error message', () => {
+ const [expectedError] = mockErrors;
+
+ expect(findErrors().text()).toBe(expectedError);
+ });
+
+ it('displays the warning message', () => {
+ const [expectedWarning] = mockWarnings;
+
+ expect(findWarnings().exists()).toBe(true);
+ expect(findWarnings().text()).toContain(expectedWarning);
+ });
+ });
+
+ describe('Valid results', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('displays table', () => {
+ expect(findTable().exists()).toBe(true);
+ });
+
+ it('displays the valid status', () => {
+ expect(findStatus().text()).toBe(wrapper.vm.$options.correct.text);
+ expect(findStatus().props('variant')).toBe(wrapper.vm.$options.correct.variant);
+ });
+
+ it('does not display only/expect values with dry run', () => {
+ expect(findOnlyExcept().exists()).toBe(false);
+ });
+ });
+
+ describe('Lint results', () => {
+ beforeEach(() => {
+ createComponent({}, mount);
+ });
+
+ it('formats parameter value', () => {
+ findLintParameters().wrappers.forEach((job, index) => {
+ const { stage } = mockJobs[index];
+ const { name } = mockJobs[index];
+
+ expect(job.text()).toBe(`${capitalizeFirstCharacter(stage)} Job - ${name}`);
+ });
+ });
+
+ it('only shows before scripts when data is present', () => {
+ expect(findBeforeScripts()).toHaveLength(filterEmptyScripts('beforeScript').length);
+ });
+
+ it('only shows script when data is present', () => {
+ expect(findScripts()).toHaveLength(filterEmptyScripts('script').length);
+ });
+
+ it('only shows after script when data is present', () => {
+ expect(findAfterScripts()).toHaveLength(filterEmptyScripts('afterScript').length);
+ });
+ });
+});
diff --git a/spec/frontend/ci_lint/components/ci_lint_spec.js b/spec/frontend/ci_lint/components/ci_lint_spec.js
new file mode 100644
index 00000000000..e617cca499d
--- /dev/null
+++ b/spec/frontend/ci_lint/components/ci_lint_spec.js
@@ -0,0 +1,77 @@
+import { shallowMount } from '@vue/test-utils';
+import EditorLite from '~/vue_shared/components/editor_lite.vue';
+import CiLint from '~/ci_lint/components/ci_lint.vue';
+import lintCIMutation from '~/ci_lint/graphql/mutations/lint_ci.mutation.graphql';
+
+describe('CI Lint', () => {
+ let wrapper;
+
+ const endpoint = '/namespace/project/-/ci/lint';
+ const content =
+ "test_job:\n stage: build\n script: echo 'Building'\n only:\n - web\n - chat\n - pushes\n allow_failure: true ";
+
+ const createComponent = () => {
+ wrapper = shallowMount(CiLint, {
+ data() {
+ return {
+ content,
+ };
+ },
+ propsData: {
+ endpoint,
+ helpPagePath: '/help/ci/lint#pipeline-simulation',
+ },
+ mocks: {
+ $apollo: {
+ mutate: jest.fn(),
+ },
+ },
+ });
+ };
+
+ const findEditor = () => wrapper.find(EditorLite);
+ const findValidateBtn = () => wrapper.find('[data-testid="ci-lint-validate"]');
+ const findClearBtn = () => wrapper.find('[data-testid="ci-lint-clear"]');
+
+ beforeEach(() => {
+ createComponent();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('displays the editor', () => {
+ expect(findEditor().exists()).toBe(true);
+ });
+
+ it('validate action calls mutation correctly', () => {
+ findValidateBtn().vm.$emit('click');
+
+ expect(wrapper.vm.$apollo.mutate).toHaveBeenCalledWith({
+ mutation: lintCIMutation,
+ variables: { content, dry: false, endpoint },
+ });
+ });
+
+ it('validate action calls mutation with dry run', async () => {
+ const dryRunEnabled = true;
+
+ await wrapper.setData({ dryRun: dryRunEnabled });
+
+ findValidateBtn().vm.$emit('click');
+
+ expect(wrapper.vm.$apollo.mutate).toHaveBeenCalledWith({
+ mutation: lintCIMutation,
+ variables: { content, dry: dryRunEnabled, endpoint },
+ });
+ });
+
+ it('content is cleared on clear action', async () => {
+ expect(findEditor().props('value')).toBe(content);
+
+ await findClearBtn().vm.$emit('click');
+
+ expect(findEditor().props('value')).toBe('');
+ });
+});
diff --git a/spec/frontend/ci_lint/components/ci_lint_warnings_spec.js b/spec/frontend/ci_lint/components/ci_lint_warnings_spec.js
new file mode 100644
index 00000000000..6e0a4881e14
--- /dev/null
+++ b/spec/frontend/ci_lint/components/ci_lint_warnings_spec.js
@@ -0,0 +1,54 @@
+import { mount } from '@vue/test-utils';
+import { GlAlert, GlSprintf } from '@gitlab/ui';
+import { trimText } from 'helpers/text_helper';
+import CiLintWarnings from '~/ci_lint/components/ci_lint_warnings.vue';
+
+const warnings = ['warning 1', 'warning 2', 'warning 3'];
+
+describe('CI lint warnings', () => {
+ let wrapper;
+
+ const createComponent = (limit = 25) => {
+ wrapper = mount(CiLintWarnings, {
+ propsData: {
+ warnings,
+ maxWarnings: limit,
+ },
+ });
+ };
+
+ const findWarningAlert = () => wrapper.find(GlAlert);
+ const findWarnings = () => wrapper.findAll('[data-testid="ci-lint-warning"]');
+ const findWarningMessage = () => trimText(wrapper.find(GlSprintf).text());
+
+ afterEach(() => {
+ wrapper.destroy();
+ wrapper = null;
+ });
+
+ it('displays the warning alert', () => {
+ createComponent();
+
+ expect(findWarningAlert().exists()).toBe(true);
+ });
+
+ it('displays all the warnings', () => {
+ createComponent();
+
+ expect(findWarnings()).toHaveLength(warnings.length);
+ });
+
+ it('shows the correct message when the limit is not passed', () => {
+ createComponent();
+
+ expect(findWarningMessage()).toBe(`${warnings.length} warnings found:`);
+ });
+
+ it('shows the correct message when the limit is passed', () => {
+ const limit = 2;
+
+ createComponent(limit);
+
+ expect(findWarningMessage()).toBe(`${warnings.length} warnings found: showing first ${limit}`);
+ });
+});
diff --git a/spec/frontend/ci_lint/mock_data.js b/spec/frontend/ci_lint/mock_data.js
new file mode 100644
index 00000000000..cf7d69dcad3
--- /dev/null
+++ b/spec/frontend/ci_lint/mock_data.js
@@ -0,0 +1,49 @@
+export const mockJobs = [
+ {
+ name: 'job_1',
+ stage: 'build',
+ beforeScript: [],
+ script: ["echo 'Building'"],
+ afterScript: [],
+ tagList: [],
+ environment: null,
+ when: 'on_success',
+ allowFailure: true,
+ only: { refs: ['web', 'chat', 'pushes'] },
+ except: null,
+ },
+ {
+ name: 'multi_project_job',
+ stage: 'test',
+ beforeScript: [],
+ script: [],
+ afterScript: [],
+ tagList: [],
+ environment: null,
+ when: 'on_success',
+ allowFailure: false,
+ only: { refs: ['branches', 'tags'] },
+ except: null,
+ },
+ {
+ name: 'job_2',
+ stage: 'test',
+ beforeScript: ["echo 'before script'"],
+ script: ["echo 'script'"],
+ afterScript: ["echo 'after script"],
+ tagList: [],
+ environment: null,
+ when: 'on_success',
+ allowFailure: false,
+ only: { refs: ['branches@gitlab-org/gitlab'] },
+ except: { refs: ['master@gitlab-org/gitlab', '/^release/.*$/@gitlab-org/gitlab'] },
+ },
+];
+
+export const mockErrors = [
+ '"job_1 job: chosen stage does not exist; available stages are .pre, build, test, deploy, .post"',
+];
+
+export const mockWarnings = [
+ '"jobs:multi_project_job may allow multiple pipelines to run for a single action due to `rules:when` clause with no `workflow:rules` - read more: https://docs.gitlab.com/ee/ci/troubleshooting.html#pipeline-warnings"',
+];
diff --git a/spec/frontend/ci_settings_pipeline_triggers/components/triggers_list_spec.js b/spec/frontend/ci_settings_pipeline_triggers/components/triggers_list_spec.js
new file mode 100644
index 00000000000..e07afb5d736
--- /dev/null
+++ b/spec/frontend/ci_settings_pipeline_triggers/components/triggers_list_spec.js
@@ -0,0 +1,102 @@
+import { mount } from '@vue/test-utils';
+import { GlTable, GlBadge } from '@gitlab/ui';
+import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
+import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
+
+import TriggersList from '~/ci_settings_pipeline_triggers/components/triggers_list.vue';
+import { triggers } from '../mock_data';
+
+describe('TriggersList', () => {
+ let wrapper;
+
+ const createComponent = (props = {}) => {
+ wrapper = mount(TriggersList, {
+ propsData: { triggers, ...props },
+ });
+ };
+
+ const findTable = () => wrapper.find(GlTable);
+ const findHeaderAt = i => wrapper.findAll('thead th').at(i);
+ const findRows = () => wrapper.findAll('tbody tr');
+ const findRowAt = i => findRows().at(i);
+ const findCell = (i, col) =>
+ findRowAt(i)
+ .findAll('td')
+ .at(col);
+ const findClipboardBtn = i => findCell(i, 0).find(ClipboardButton);
+ const findInvalidBadge = i => findCell(i, 0).find(GlBadge);
+ const findEditBtn = i => findRowAt(i).find('[data-testid="edit-btn"]');
+ const findRevokeBtn = i => findRowAt(i).find('[data-testid="trigger_revoke_button"]');
+
+ beforeEach(() => {
+ createComponent();
+
+ return wrapper.vm.$nextTick();
+ });
+
+ it('displays a table with expected headers', () => {
+ const headers = ['Token', 'Description', 'Owner', 'Last Used', ''];
+ headers.forEach((header, i) => {
+ expect(findHeaderAt(i).text()).toBe(header);
+ });
+ });
+
+ it('displays a table with rows', () => {
+ expect(findRows()).toHaveLength(triggers.length);
+
+ const [trigger] = triggers;
+
+ expect(findCell(0, 0).text()).toBe(trigger.token);
+ expect(findCell(0, 1).text()).toBe(trigger.description);
+ expect(findCell(0, 2).text()).toContain(trigger.owner.name);
+ });
+
+ it('displays a "copy to cliboard" button for exposed tokens', () => {
+ expect(findClipboardBtn(0).exists()).toBe(true);
+ expect(findClipboardBtn(0).props('text')).toBe(triggers[0].token);
+
+ expect(findClipboardBtn(1).exists()).toBe(false);
+ });
+
+ it('displays an "invalid" label for tokens without access', () => {
+ expect(findInvalidBadge(0).exists()).toBe(false);
+
+ expect(findInvalidBadge(1).exists()).toBe(true);
+ });
+
+ it('displays a time ago label when last used', () => {
+ expect(findCell(0, 3).text()).toBe('Never');
+
+ expect(
+ findCell(1, 3)
+ .find(TimeAgoTooltip)
+ .props('time'),
+ ).toBe(triggers[1].lastUsed);
+ });
+
+ it('displays actions in a rows', () => {
+ const [data] = triggers;
+
+ expect(findEditBtn(0).attributes('href')).toBe(data.editProjectTriggerPath);
+
+ expect(findRevokeBtn(0).attributes('href')).toBe(data.projectTriggerPath);
+ expect(findRevokeBtn(0).attributes('data-method')).toBe('delete');
+ expect(findRevokeBtn(0).attributes('data-confirm')).toBeTruthy();
+ });
+
+ describe('when there are no triggers set', () => {
+ beforeEach(() => {
+ createComponent({ triggers: [] });
+ });
+
+ it('does not display a table', () => {
+ expect(findTable().exists()).toBe(false);
+ });
+
+ it('displays a message', () => {
+ expect(wrapper.text()).toBe(
+ 'No triggers have been created yet. Add one using the form above.',
+ );
+ });
+ });
+});
diff --git a/spec/frontend/ci_settings_pipeline_triggers/mock_data.js b/spec/frontend/ci_settings_pipeline_triggers/mock_data.js
new file mode 100644
index 00000000000..6813e941e03
--- /dev/null
+++ b/spec/frontend/ci_settings_pipeline_triggers/mock_data.js
@@ -0,0 +1,30 @@
+export const triggers = [
+ {
+ hasTokenExposed: true,
+ token: '0000',
+ description: 'My trigger',
+ owner: {
+ name: 'My User',
+ username: 'user1',
+ path: '/user1',
+ },
+ lastUsed: null,
+ canAccessProject: true,
+ editProjectTriggerPath: '/triggers/1/edit',
+ projectTriggerPath: '/trigger/1',
+ },
+ {
+ hasTokenExposed: false,
+ token: '1111',
+ description: "Anothe user's trigger",
+ owner: {
+ name: 'Someone else',
+ username: 'user2',
+ path: '/user2',
+ },
+ lastUsed: '2020-09-10T08:26:47.410Z',
+ canAccessProject: false,
+ editProjectTriggerPath: '/triggers/1/edit',
+ projectTriggerPath: '/trigger/1',
+ },
+];
diff --git a/spec/frontend/ci_variable_list/components/ci_enviroments_dropdown_spec.js b/spec/frontend/ci_variable_list/components/ci_enviroments_dropdown_spec.js
deleted file mode 100644
index 7785d436834..00000000000
--- a/spec/frontend/ci_variable_list/components/ci_enviroments_dropdown_spec.js
+++ /dev/null
@@ -1,103 +0,0 @@
-import Vuex from 'vuex';
-import { shallowMount, createLocalVue } from '@vue/test-utils';
-import { GlDeprecatedDropdownItem, GlIcon } from '@gitlab/ui';
-import CiEnvironmentsDropdown from '~/ci_variable_list/components/ci_environments_dropdown.vue';
-
-const localVue = createLocalVue();
-localVue.use(Vuex);
-
-describe('Ci environments dropdown', () => {
- let wrapper;
- let store;
-
- const createComponent = term => {
- store = new Vuex.Store({
- getters: {
- joinedEnvironments: () => ['dev', 'prod', 'staging'],
- },
- });
-
- wrapper = shallowMount(CiEnvironmentsDropdown, {
- store,
- localVue,
- propsData: {
- value: term,
- },
- });
- };
-
- const findAllDropdownItems = () => wrapper.findAll(GlDeprecatedDropdownItem);
- const findDropdownItemByIndex = index => wrapper.findAll(GlDeprecatedDropdownItem).at(index);
- const findActiveIconByIndex = index => wrapper.findAll(GlIcon).at(index);
-
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
- describe('No enviroments found', () => {
- beforeEach(() => {
- createComponent('stable');
- });
-
- it('renders create button with search term if enviroments 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 enviroments 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');
- });
- });
-
- describe('Enviroments found', () => {
- beforeEach(() => {
- createComponent('prod');
- });
-
- it('renders only the enviroment searched for', () => {
- expect(findAllDropdownItems()).toHaveLength(1);
- expect(findDropdownItemByIndex(0).text()).toBe('prod');
- });
-
- it('should not display create button', () => {
- const enviroments = findAllDropdownItems().filter(env => env.text().startsWith('Create'));
- expect(enviroments).toHaveLength(0);
- expect(findAllDropdownItems()).toHaveLength(1);
- });
-
- it('should not display empty results message', () => {
- expect(wrapper.find({ ref: 'noMatchingResults' }).exists()).toBe(false);
- });
-
- it('should display active checkmark if active', () => {
- expect(findActiveIconByIndex(0).classes('invisible')).toBe(false);
- });
-
- 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', () => {
- createComponent('newscope');
- findDropdownItemByIndex(1).vm.$emit('click');
- expect(wrapper.emitted('createClicked')).toEqual([['newscope']]);
- });
- });
- });
-});
diff --git a/spec/frontend/ci_variable_list/components/ci_environments_dropdown_spec.js b/spec/frontend/ci_variable_list/components/ci_environments_dropdown_spec.js
new file mode 100644
index 00000000000..7bcd558c60f
--- /dev/null
+++ b/spec/frontend/ci_variable_list/components/ci_environments_dropdown_spec.js
@@ -0,0 +1,107 @@
+import Vuex from 'vuex';
+import { mount, createLocalVue } from '@vue/test-utils';
+import { GlDropdownItem, GlIcon } from '@gitlab/ui';
+import CiEnvironmentsDropdown from '~/ci_variable_list/components/ci_environments_dropdown.vue';
+
+const localVue = createLocalVue();
+localVue.use(Vuex);
+
+describe('Ci environments dropdown', () => {
+ let wrapper;
+ let store;
+
+ const createComponent = term => {
+ store = new Vuex.Store({
+ getters: {
+ joinedEnvironments: () => ['dev', 'prod', 'staging'],
+ },
+ });
+
+ wrapper = mount(CiEnvironmentsDropdown, {
+ store,
+ localVue,
+ propsData: {
+ value: term,
+ },
+ });
+ };
+
+ const findAllDropdownItems = () => wrapper.findAll(GlDropdownItem);
+ const findDropdownItemByIndex = index => wrapper.findAll(GlDropdownItem).at(index);
+ const findActiveIconByIndex = index => findDropdownItemByIndex(index).find(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(() => {
+ createComponent('prod');
+ });
+
+ 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.find({ ref: 'noMatchingResults' }).exists()).toBe(false);
+ });
+
+ it('should display active checkmark if active', () => {
+ expect(findActiveIconByIndex(0).classes('gl-visibility-hidden')).toBe(false);
+ });
+
+ 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', () => {
+ createComponent('newscope');
+ findDropdownItemByIndex(1).vm.$emit('click');
+ expect(wrapper.emitted('createClicked')).toEqual([['newscope']]);
+ });
+ });
+ });
+});
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 ab32fb12058..5c2d096418d 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
@@ -1,6 +1,6 @@
import Vuex from 'vuex';
import { createLocalVue, shallowMount, mount } from '@vue/test-utils';
-import { GlButton, GlFormCombobox } from '@gitlab/ui';
+import { GlButton } from '@gitlab/ui';
import { AWS_ACCESS_KEY_ID } from '~/ci_variable_list/constants';
import CiVariableModal from '~/ci_variable_list/components/ci_variable_modal.vue';
import createStore from '~/ci_variable_list/store';
@@ -18,7 +18,6 @@ describe('Ci variable modal', () => {
store = createStore();
wrapper = method(CiVariableModal, {
attachToDocument: true,
- provide: { glFeatures: { ciKeyAutocomplete: true } },
stubs: {
GlModal: ModalStub,
},
@@ -42,27 +41,6 @@ describe('Ci variable modal', () => {
wrapper.destroy();
});
- describe('Feature flag', () => {
- describe('when off', () => {
- beforeEach(() => {
- createComponent(shallowMount, { provide: { glFeatures: { ciKeyAutocomplete: false } } });
- });
-
- it('does not render the autocomplete dropdown', () => {
- expect(wrapper.find(GlFormCombobox).exists()).toBe(false);
- });
- });
-
- describe('when on', () => {
- beforeEach(() => {
- createComponent(shallowMount);
- });
- it('renders the autocomplete dropdown', () => {
- expect(wrapper.find(GlFormCombobox).exists()).toBe(true);
- });
- });
- });
-
describe('Basic interactions', () => {
beforeEach(() => {
createComponent(shallowMount);
diff --git a/spec/frontend/ci_variable_list/store/getters_spec.js b/spec/frontend/ci_variable_list/store/getters_spec.js
index 7ad96545652..92f22b18763 100644
--- a/spec/frontend/ci_variable_list/store/getters_spec.js
+++ b/spec/frontend/ci_variable_list/store/getters_spec.js
@@ -3,7 +3,7 @@ import mockData from '../services/mock_data';
describe('Ci variable getters', () => {
describe('joinedEnvironments', () => {
- it('should join fetched enviroments with variable environment scopes', () => {
+ it('should join fetched environments with variable environment scopes', () => {
const state = {
environments: ['All (default)', 'staging', 'deployment', 'prod'],
variables: mockData.mockVariableScopes,
diff --git a/spec/frontend/ci_variable_list/store/mutations_spec.js b/spec/frontend/ci_variable_list/store/mutations_spec.js
index 663b3486a17..a333fb7d8f9 100644
--- a/spec/frontend/ci_variable_list/store/mutations_spec.js
+++ b/spec/frontend/ci_variable_list/store/mutations_spec.js
@@ -73,7 +73,7 @@ describe('CI variable list mutations', () => {
});
describe('ADD_WILD_CARD_SCOPE', () => {
- it('should add wild card scope to enviroments array and sort', () => {
+ it('should add wild card scope to environments array and sort', () => {
stateCopy.environments = ['dev', 'staging'];
mutations[types.ADD_WILD_CARD_SCOPE](stateCopy, 'production');
diff --git a/spec/frontend/clusters/components/__snapshots__/applications_spec.js.snap b/spec/frontend/clusters/components/__snapshots__/applications_spec.js.snap
index 3328ec724fd..b6e89281fef 100644
--- a/spec/frontend/clusters/components/__snapshots__/applications_spec.js.snap
+++ b/spec/frontend/clusters/components/__snapshots__/applications_spec.js.snap
@@ -94,7 +94,7 @@ exports[`Applications Prometheus application shows the correct description 1`] =
Prometheus is an open-source monitoring system with
<a
class="gl-link"
- href="https://docs.gitlab.com/ce/user/project/integrations/prometheus.html"
+ href="https://docs.gitlab.com/ee/user/project/integrations/prometheus.html"
rel="noopener noreferrer"
target="_blank"
>
diff --git a/spec/frontend/clusters/components/__snapshots__/remove_cluster_confirmation_spec.js.snap b/spec/frontend/clusters/components/__snapshots__/remove_cluster_confirmation_spec.js.snap
index 93b757e008a..15eeadcc8b8 100644
--- a/spec/frontend/clusters/components/__snapshots__/remove_cluster_confirmation_spec.js.snap
+++ b/spec/frontend/clusters/components/__snapshots__/remove_cluster_confirmation_spec.js.snap
@@ -5,14 +5,17 @@ exports[`Remove cluster confirmation modal renders splitbutton with modal includ
class="gl-display-flex gl-justify-content-end"
>
<div
- class="dropdown b-dropdown gl-dropdown btn-group"
+ class="dropdown b-dropdown gl-new-dropdown btn-group"
+ menu-class="dropdown-menu-large"
>
<button
- class="btn btn-danger"
+ class="btn btn-danger btn-md gl-button split-content-button"
type="button"
>
+ <!---->
+
<span
- class="gl-dropdown-toggle-text"
+ class="gl-new-dropdown-button-text"
>
Remove integration and resources
</span>
@@ -22,7 +25,7 @@ exports[`Remove cluster confirmation modal renders splitbutton with modal includ
<button
aria-expanded="false"
aria-haspopup="true"
- class="btn dropdown-toggle btn-danger dropdown-toggle-split"
+ class="btn dropdown-toggle btn-danger btn-md gl-button gl-dropdown-toggle dropdown-toggle-split"
type="button"
>
<span
@@ -32,29 +35,58 @@ exports[`Remove cluster confirmation modal renders splitbutton with modal includ
</span>
</button>
<ul
- class="dropdown-menu dropdown-menu-selectable dropdown-menu-large"
+ class="dropdown-menu dropdown-menu-large"
role="menu"
tabindex="-1"
>
+ <!---->
+
<li
+ class="gl-new-dropdown-item"
role="presentation"
>
<button
- class="dropdown-item is-active"
+ class="dropdown-item"
role="menuitem"
type="button"
>
- <strong>
- Remove integration and resources
- </strong>
+ <svg
+ class="gl-icon s16 gl-new-dropdown-item-check-icon"
+ data-testid="mobile-issue-close-icon"
+ >
+ <use
+ href="#mobile-issue-close"
+ />
+ </svg>
+
+ <!---->
- <div>
- Deletes all GitLab resources attached to this cluster during removal
+ <!---->
+
+ <div
+ class="gl-new-dropdown-item-text-wrapper"
+ >
+ <p
+ class="gl-new-dropdown-item-text-primary"
+ >
+ <strong>
+ Remove integration and resources
+ </strong>
+
+ <div>
+ Deletes all GitLab resources attached to this cluster during removal
+ </div>
+ </p>
+
+ <!---->
</div>
+
+ <!---->
</button>
</li>
<li
+ class="gl-new-dropdown-divider"
role="presentation"
>
<hr
@@ -64,6 +96,7 @@ exports[`Remove cluster confirmation modal renders splitbutton with modal includ
/>
</li>
<li
+ class="gl-new-dropdown-item"
role="presentation"
>
<button
@@ -71,13 +104,38 @@ exports[`Remove cluster confirmation modal renders splitbutton with modal includ
role="menuitem"
type="button"
>
- <strong>
- Remove integration
- </strong>
+ <svg
+ class="gl-icon s16 gl-new-dropdown-item-check-icon gl-visibility-hidden"
+ data-testid="mobile-issue-close-icon"
+ >
+ <use
+ href="#mobile-issue-close"
+ />
+ </svg>
+
+ <!---->
- <div>
- Removes cluster from project but keeps associated resources
+ <!---->
+
+ <div
+ class="gl-new-dropdown-item-text-wrapper"
+ >
+ <p
+ class="gl-new-dropdown-item-text-primary"
+ >
+ <strong>
+ Remove integration
+ </strong>
+
+ <div>
+ Removes cluster from project but keeps associated resources
+ </div>
+ </p>
+
+ <!---->
</div>
+
+ <!---->
</button>
</li>
diff --git a/spec/frontend/clusters/components/fluentd_output_settings_spec.js b/spec/frontend/clusters/components/fluentd_output_settings_spec.js
index c263679a45c..25db8785edc 100644
--- a/spec/frontend/clusters/components/fluentd_output_settings_spec.js
+++ b/spec/frontend/clusters/components/fluentd_output_settings_spec.js
@@ -1,5 +1,5 @@
import { shallowMount } from '@vue/test-utils';
-import { GlAlert, GlDeprecatedDropdown, GlFormCheckbox } from '@gitlab/ui';
+import { GlAlert, GlDropdown, GlFormCheckbox } from '@gitlab/ui';
import FluentdOutputSettings from '~/clusters/components/fluentd_output_settings.vue';
import { APPLICATION_STATUS, FLUENTD } from '~/clusters/constants';
import eventHub from '~/clusters/event_hub';
@@ -36,7 +36,7 @@ describe('FluentdOutputSettings', () => {
};
const findSaveButton = () => wrapper.find({ ref: 'saveBtn' });
const findCancelButton = () => wrapper.find({ ref: 'cancelBtn' });
- const findProtocolDropdown = () => wrapper.find(GlDeprecatedDropdown);
+ const findProtocolDropdown = () => wrapper.find(GlDropdown);
const findCheckbox = name =>
wrapper.findAll(GlFormCheckbox).wrappers.find(x => x.text() === name);
const findHost = () => wrapper.find('#fluentd-host');
diff --git a/spec/frontend/clusters/components/ingress_modsecurity_settings_spec.js b/spec/frontend/clusters/components/ingress_modsecurity_settings_spec.js
index 3a9a608b2e2..1f07a0b7908 100644
--- a/spec/frontend/clusters/components/ingress_modsecurity_settings_spec.js
+++ b/spec/frontend/clusters/components/ingress_modsecurity_settings_spec.js
@@ -1,5 +1,5 @@
import { shallowMount } from '@vue/test-utils';
-import { GlAlert, GlToggle, GlDeprecatedDropdown } from '@gitlab/ui';
+import { GlAlert, GlToggle, GlDropdown } from '@gitlab/ui';
import IngressModsecuritySettings from '~/clusters/components/ingress_modsecurity_settings.vue';
import { APPLICATION_STATUS, INGRESS } from '~/clusters/constants';
import eventHub from '~/clusters/event_hub';
@@ -28,10 +28,12 @@ describe('IngressModsecuritySettings', () => {
});
};
- const findSaveButton = () => wrapper.find('.btn-success');
- const findCancelButton = () => wrapper.find('[variant="secondary"]');
+ const findSaveButton = () =>
+ wrapper.find('[data-qa-selector="save_ingress_modsecurity_settings"]');
+ const findCancelButton = () =>
+ wrapper.find('[data-qa-selector="cancel_ingress_modsecurity_settings"]');
const findModSecurityToggle = () => wrapper.find(GlToggle);
- const findModSecurityDropdown = () => wrapper.find(GlDeprecatedDropdown);
+ const findModSecurityDropdown = () => wrapper.find(GlDropdown);
describe('when ingress is installed', () => {
beforeEach(() => {
diff --git a/spec/frontend/clusters/components/knative_domain_editor_spec.js b/spec/frontend/clusters/components/knative_domain_editor_spec.js
index 11ebe1b5d61..b7f76211fd6 100644
--- a/spec/frontend/clusters/components/knative_domain_editor_spec.js
+++ b/spec/frontend/clusters/components/knative_domain_editor_spec.js
@@ -1,5 +1,5 @@
import { shallowMount } from '@vue/test-utils';
-import { GlDeprecatedDropdownItem, GlButton } from '@gitlab/ui';
+import { GlDropdownItem, GlButton } from '@gitlab/ui';
import KnativeDomainEditor from '~/clusters/components/knative_domain_editor.vue';
import { APPLICATION_STATUS } from '~/clusters/constants';
@@ -112,7 +112,7 @@ describe('KnativeDomainEditor', () => {
createComponent({ knative: { ...knative, availableDomains: [newDomain] } });
jest.spyOn(wrapper.vm, 'selectDomain');
- wrapper.find(GlDeprecatedDropdownItem).vm.$emit('click');
+ wrapper.find(GlDropdownItem).vm.$emit('click');
return wrapper.vm.$nextTick().then(() => {
expect(wrapper.vm.selectDomain).toHaveBeenCalledWith(newDomain);
diff --git a/spec/frontend/clusters/services/crossplane_provider_stack_spec.js b/spec/frontend/clusters/services/crossplane_provider_stack_spec.js
index 57c538d2650..3e5f8de8e7b 100644
--- a/spec/frontend/clusters/services/crossplane_provider_stack_spec.js
+++ b/spec/frontend/clusters/services/crossplane_provider_stack_spec.js
@@ -1,5 +1,5 @@
import { shallowMount } from '@vue/test-utils';
-import { GlDeprecatedDropdownItem, GlIcon } from '@gitlab/ui';
+import { GlDropdownItem, GlIcon } from '@gitlab/ui';
import CrossplaneProviderStack from '~/clusters/components/crossplane_provider_stack.vue';
describe('CrossplaneProviderStack component', () => {
@@ -37,7 +37,7 @@ describe('CrossplaneProviderStack component', () => {
createComponent({ crossplane });
});
- const findDropdownElements = () => wrapper.findAll(GlDeprecatedDropdownItem);
+ const findDropdownElements = () => wrapper.findAll(GlDropdownItem);
const findFirstDropdownElement = () => findDropdownElements().at(0);
afterEach(() => {
diff --git a/spec/frontend/clusters_list/components/clusters_spec.js b/spec/frontend/clusters_list/components/clusters_spec.js
index 628c35ae839..d61f79071d5 100644
--- a/spec/frontend/clusters_list/components/clusters_spec.js
+++ b/spec/frontend/clusters_list/components/clusters_spec.js
@@ -6,7 +6,7 @@ import {
GlDeprecatedSkeletonLoading as GlSkeletonLoading,
GlTable,
} from '@gitlab/ui';
-import * as Sentry from '@sentry/browser';
+import * as Sentry from '~/sentry/wrapper';
import axios from '~/lib/utils/axios_utils';
import Clusters from '~/clusters_list/components/clusters.vue';
import ClusterStore from '~/clusters_list/store';
@@ -164,18 +164,18 @@ describe('Clusters', () => {
});
it.each`
- nodeSize | lineNumber
- ${'Unknown'} | ${0}
- ${'1'} | ${1}
- ${'2'} | ${2}
- ${'1'} | ${3}
- ${'1'} | ${4}
- ${'Unknown'} | ${5}
- `('renders node size for each cluster', ({ nodeSize, lineNumber }) => {
+ nodeText | lineNumber
+ ${'Unable to Authenticate'} | ${0}
+ ${'1'} | ${1}
+ ${'2'} | ${2}
+ ${'1'} | ${3}
+ ${'1'} | ${4}
+ ${'Unknown Error'} | ${5}
+ `('renders node size for each cluster', ({ nodeText, lineNumber }) => {
const sizes = findTable().findAll('td:nth-child(3)');
const size = sizes.at(lineNumber);
- expect(size.text()).toBe(nodeSize);
+ expect(size.text()).toContain(nodeText);
expect(size.find(GlSkeletonLoading).exists()).toBe(false);
});
});
diff --git a/spec/frontend/clusters_list/components/node_error_help_text_spec.js b/spec/frontend/clusters_list/components/node_error_help_text_spec.js
new file mode 100644
index 00000000000..4d157b3a8ab
--- /dev/null
+++ b/spec/frontend/clusters_list/components/node_error_help_text_spec.js
@@ -0,0 +1,33 @@
+import { shallowMount } from '@vue/test-utils';
+import { GlPopover } from '@gitlab/ui';
+import NodeErrorHelpText from '~/clusters_list/components/node_error_help_text.vue';
+
+describe('NodeErrorHelpText', () => {
+ let wrapper;
+
+ const createWrapper = propsData => {
+ wrapper = shallowMount(NodeErrorHelpText, { propsData, stubs: { GlPopover } });
+ return wrapper.vm.$nextTick();
+ };
+
+ const findPopover = () => wrapper.find(GlPopover);
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it.each`
+ errorType | wrapperText | popoverText
+ ${'authentication_error'} | ${'Unable to Authenticate'} | ${'GitLab failed to authenticate'}
+ ${'connection_error'} | ${'Unable to Connect'} | ${'GitLab failed to connect to the cluster'}
+ ${'http_error'} | ${'Unable to Connect'} | ${'There was an HTTP error when connecting to your cluster'}
+ ${'default'} | ${'Unknown Error'} | ${'An unknown error occurred while attempting to connect to Kubernetes.'}
+ ${'unknown_error_type'} | ${'Unknown Error'} | ${'An unknown error occurred while attempting to connect to Kubernetes.'}
+ ${null} | ${'Unknown Error'} | ${'An unknown error occurred while attempting to connect to Kubernetes.'}
+ `('displays error text', ({ errorType, wrapperText, popoverText }) => {
+ return createWrapper({ errorType, popoverId: 'id' }).then(() => {
+ expect(wrapper.text()).toContain(wrapperText);
+ expect(findPopover().text()).toContain(popoverText);
+ });
+ });
+});
diff --git a/spec/frontend/clusters_list/mock_data.js b/spec/frontend/clusters_list/mock_data.js
index 48af3b91c94..ed32655d10e 100644
--- a/spec/frontend/clusters_list/mock_data.js
+++ b/spec/frontend/clusters_list/mock_data.js
@@ -6,6 +6,11 @@ export const clusterList = [
provider_type: 'gcp',
status: 'creating',
nodes: null,
+ kubernetes_errors: {
+ connection_error: 'authentication_error',
+ node_connection_error: 'connection_error',
+ metrics_connection_error: 'http_error',
+ },
},
{
name: 'My Cluster 2',
@@ -19,6 +24,7 @@ export const clusterList = [
usage: { cpu: '246155922n', memory: '1255212Ki' },
},
],
+ kubernetes_errors: {},
},
{
name: 'My Cluster 3',
@@ -36,6 +42,7 @@ export const clusterList = [
usage: { cpu: '307051934n', memory: '1379136Ki' },
},
],
+ kubernetes_errors: {},
},
{
name: 'My Cluster 4',
@@ -48,6 +55,7 @@ export const clusterList = [
usage: { cpu: '1missingCpuUnit', memory: '1missingMemoryUnit' },
},
],
+ kubernetes_errors: {},
},
{
name: 'My Cluster 5',
@@ -59,12 +67,14 @@ export const clusterList = [
status: { allocatable: { cpu: '1missingCpuUnit', memory: '1missingMemoryUnit' } },
},
],
+ kubernetes_errors: {},
},
{
name: 'My Cluster 6',
environment_scope: '*',
cluster_type: 'project_type',
status: 'cleanup_ongoing',
+ kubernetes_errors: {},
},
];
diff --git a/spec/frontend/clusters_list/store/actions_spec.js b/spec/frontend/clusters_list/store/actions_spec.js
index 053128a179a..3d4e07d00eb 100644
--- a/spec/frontend/clusters_list/store/actions_spec.js
+++ b/spec/frontend/clusters_list/store/actions_spec.js
@@ -1,7 +1,7 @@
import MockAdapter from 'axios-mock-adapter';
import testAction from 'helpers/vuex_action_helper';
import waitForPromises from 'helpers/wait_for_promises';
-import * as Sentry from '@sentry/browser';
+import * as Sentry from '~/sentry/wrapper';
import Poll from '~/lib/utils/poll';
import { deprecatedCreateFlash as flashError } from '~/flash';
import axios from '~/lib/utils/axios_utils';
diff --git a/spec/frontend/code_navigation/components/__snapshots__/popover_spec.js.snap b/spec/frontend/code_navigation/components/__snapshots__/popover_spec.js.snap
index 745a163951a..62b751ec59b 100644
--- a/spec/frontend/code_navigation/components/__snapshots__/popover_spec.js.snap
+++ b/spec/frontend/code_navigation/components/__snapshots__/popover_spec.js.snap
@@ -56,6 +56,7 @@ exports[`Code navigation popover component renders popover 1`] = `
class="popover-body border-top"
>
<gl-button-stub
+ buttontextclasses=""
category="primary"
class="w-100"
data-testid="go-to-definition-btn"
diff --git a/spec/frontend/collapsed_sidebar_todo_spec.js b/spec/frontend/collapsed_sidebar_todo_spec.js
index b1a304fabcd..86f4c450c05 100644
--- a/spec/frontend/collapsed_sidebar_todo_spec.js
+++ b/spec/frontend/collapsed_sidebar_todo_spec.js
@@ -59,7 +59,7 @@ describe('Issuable right sidebar collapsed todo toggle', () => {
it('sets default tooltip title', () => {
expect(
document.querySelector('.js-issuable-todo.sidebar-collapsed-icon').getAttribute('title'),
- ).toBe('Add a To Do');
+ ).toBe('Add a to do');
});
it('toggle todo state', done => {
@@ -125,7 +125,7 @@ describe('Issuable right sidebar collapsed todo toggle', () => {
expect(
document.querySelector('.issuable-sidebar-header .js-issuable-todo').textContent.trim(),
- ).toBe('Add a To Do');
+ ).toBe('Add a to do');
})
.then(done)
.catch(done.fail);
@@ -164,7 +164,7 @@ describe('Issuable right sidebar collapsed todo toggle', () => {
document
.querySelector('.js-issuable-todo.sidebar-collapsed-icon')
.getAttribute('aria-label'),
- ).toBe('Add a To Do');
+ ).toBe('Add a to do');
})
.then(done)
.catch(done.fail);
diff --git a/spec/frontend/commit/commit_pipeline_status_component_spec.js b/spec/frontend/commit/commit_pipeline_status_component_spec.js
index 1086985eec0..625024ee61f 100644
--- a/spec/frontend/commit/commit_pipeline_status_component_spec.js
+++ b/spec/frontend/commit/commit_pipeline_status_component_spec.js
@@ -142,7 +142,7 @@ describe('Commit pipeline status component', () => {
});
it('renders CI icon', () => {
- expect(findCiIcon().attributes('data-original-title')).toEqual('Pipeline: pending');
+ expect(findCiIcon().attributes('title')).toEqual('Pipeline: pending');
expect(findCiIcon().props('status')).toEqual(mockCiStatus);
});
});
@@ -161,7 +161,7 @@ describe('Commit pipeline status component', () => {
});
it('renders not found CI icon', () => {
- expect(findCiIcon().attributes('data-original-title')).toEqual('Pipeline: not found');
+ expect(findCiIcon().attributes('title')).toEqual('Pipeline: not found');
expect(findCiIcon().props('status')).toEqual({
text: 'not found',
icon: 'status_notfound',
diff --git a/spec/frontend/commit/pipelines/pipelines_spec.js b/spec/frontend/commit/pipelines/pipelines_spec.js
index fdf3c2e85f3..a196b66daa0 100644
--- a/spec/frontend/commit/pipelines/pipelines_spec.js
+++ b/spec/frontend/commit/pipelines/pipelines_spec.js
@@ -21,6 +21,10 @@ describe('Pipelines table in Commits and Merge requests', () => {
preloadFixtures(jsonFixtureName);
+ const findRunPipelineBtn = () => vm.$el.querySelector('[data-testid="run_pipeline_button"]');
+ const findRunPipelineBtnMobile = () =>
+ vm.$el.querySelector('[data-testid="run_pipeline_button_mobile"]');
+
beforeEach(() => {
mock = new MockAdapter(axios);
@@ -131,7 +135,8 @@ describe('Pipelines table in Commits and Merge requests', () => {
vm = mountComponent(PipelinesTable, { ...props });
setImmediate(() => {
- expect(vm.$el.querySelector('.js-run-mr-pipeline')).not.toBeNull();
+ expect(findRunPipelineBtn()).not.toBeNull();
+ expect(findRunPipelineBtnMobile()).not.toBeNull();
done();
});
});
@@ -147,7 +152,8 @@ describe('Pipelines table in Commits and Merge requests', () => {
vm = mountComponent(PipelinesTable, { ...props });
setImmediate(() => {
- expect(vm.$el.querySelector('.js-run-mr-pipeline')).toBeNull();
+ expect(findRunPipelineBtn()).toBeNull();
+ expect(findRunPipelineBtnMobile()).toBeNull();
done();
});
});
@@ -157,7 +163,7 @@ describe('Pipelines table in Commits and Merge requests', () => {
const findModal = () =>
document.querySelector('#create-pipeline-for-fork-merge-request-modal');
- beforeEach(() => {
+ beforeEach(done => {
pipelineCopy.flags.detached_merge_request_pipeline = true;
mock.onGet('endpoint.json').reply(200, [pipelineCopy]);
@@ -168,23 +174,46 @@ describe('Pipelines table in Commits and Merge requests', () => {
projectId: '5',
mergeRequestId: 3,
});
- });
- it('updates the loading state', done => {
jest.spyOn(Api, 'postMergeRequestPipeline').mockReturnValue(Promise.resolve());
setImmediate(() => {
- vm.$el.querySelector('.js-run-mr-pipeline').click();
+ done();
+ });
+ });
- vm.$nextTick(() => {
- expect(findModal()).toBeNull();
- expect(vm.state.isRunningMergeRequestPipeline).toBe(true);
+ it('on desktop, shows a loading button', done => {
+ findRunPipelineBtn().click();
- setImmediate(() => {
- expect(vm.state.isRunningMergeRequestPipeline).toBe(false);
+ vm.$nextTick(() => {
+ expect(findModal()).toBeNull();
- done();
- });
+ expect(findRunPipelineBtn().disabled).toBe(true);
+ expect(findRunPipelineBtn().querySelector('.gl-spinner')).not.toBeNull();
+
+ setImmediate(() => {
+ expect(findRunPipelineBtn().disabled).toBe(false);
+ expect(findRunPipelineBtn().querySelector('.gl-spinner')).toBeNull();
+
+ done();
+ });
+ });
+ });
+
+ it('on mobile, shows a loading button', done => {
+ findRunPipelineBtnMobile().click();
+
+ vm.$nextTick(() => {
+ expect(findModal()).toBeNull();
+
+ expect(findModal()).toBeNull();
+ expect(findRunPipelineBtn().querySelector('.gl-spinner')).not.toBeNull();
+
+ setImmediate(() => {
+ expect(findRunPipelineBtn().disabled).toBe(false);
+ expect(findRunPipelineBtn().querySelector('.gl-spinner')).toBeNull();
+
+ done();
});
});
});
@@ -194,7 +223,7 @@ describe('Pipelines table in Commits and Merge requests', () => {
const findModal = () =>
document.querySelector('#create-pipeline-for-fork-merge-request-modal');
- beforeEach(() => {
+ beforeEach(done => {
pipelineCopy.flags.detached_merge_request_pipeline = true;
mock.onGet('endpoint.json').reply(200, [pipelineCopy]);
@@ -207,18 +236,29 @@ describe('Pipelines table in Commits and Merge requests', () => {
sourceProjectFullPath: 'test/parent-project',
targetProjectFullPath: 'test/fork-project',
});
- });
- it('shows a security warning modal', done => {
jest.spyOn(Api, 'postMergeRequestPipeline').mockReturnValue(Promise.resolve());
setImmediate(() => {
- vm.$el.querySelector('.js-run-mr-pipeline').click();
+ done();
+ });
+ });
- vm.$nextTick(() => {
- expect(findModal()).not.toBeNull();
- done();
- });
+ it('on desktop, shows a security warning modal', done => {
+ findRunPipelineBtn().click();
+
+ vm.$nextTick(() => {
+ expect(findModal()).not.toBeNull();
+ done();
+ });
+ });
+
+ it('on mobile, shows a security warning modal', done => {
+ findRunPipelineBtnMobile().click();
+
+ vm.$nextTick(() => {
+ expect(findModal()).not.toBeNull();
+ done();
});
});
});
diff --git a/spec/frontend/confidential_merge_request/components/dropdown_spec.js b/spec/frontend/confidential_merge_request/components/dropdown_spec.js
index 3e95cd6c0d7..401948e24e4 100644
--- a/spec/frontend/confidential_merge_request/components/dropdown_spec.js
+++ b/spec/frontend/confidential_merge_request/components/dropdown_spec.js
@@ -1,5 +1,5 @@
import { mount } from '@vue/test-utils';
-import { GlDeprecatedDropdownItem } from '@gitlab/ui';
+import { GlDropdown, GlDropdownItem } from '@gitlab/ui';
import Dropdown from '~/confidential_merge_request/components/dropdown.vue';
let vm;
@@ -30,27 +30,18 @@ describe('Confidential merge request project dropdown component', () => {
},
]);
- expect(vm.findAll(GlDeprecatedDropdownItem).length).toBe(2);
+ expect(vm.findAll(GlDropdownItem).length).toBe(2);
});
- it('renders selected project icon', () => {
- factory([
- {
- id: 1,
- name: 'test',
- },
- {
- id: 2,
- name: 'test 2',
- },
- ]);
+ it('shows lock icon', () => {
+ factory();
+
+ expect(vm.find(GlDropdown).props('icon')).toBe('lock');
+ });
+
+ it('has dropdown text', () => {
+ factory();
- expect(vm.find('.js-active-project-check').classes()).not.toContain('icon');
- expect(
- vm
- .findAll('.js-active-project-check')
- .at(1)
- .classes(),
- ).toContain('icon');
+ expect(vm.find(GlDropdown).props('text')).toBe('Select private project');
});
});
diff --git a/spec/frontend/create_cluster/eks_cluster/components/create_eks_cluster_spec.js b/spec/frontend/create_cluster/eks_cluster/components/create_eks_cluster_spec.js
index 4bf3ac430f5..e0913fe2e88 100644
--- a/spec/frontend/create_cluster/eks_cluster/components/create_eks_cluster_spec.js
+++ b/spec/frontend/create_cluster/eks_cluster/components/create_eks_cluster_spec.js
@@ -12,6 +12,7 @@ describe('CreateEksCluster', () => {
let vm;
let state;
const gitlabManagedClusterHelpPath = 'gitlab-managed-cluster-help-path';
+ const namespacePerEnvironmentHelpPath = 'namespace-per-environment-help-path';
const accountAndExternalIdsHelpPath = 'account-and-external-id-help-path';
const createRoleArnHelpPath = 'role-arn-help-path';
const kubernetesIntegrationHelpPath = 'kubernetes-integration';
@@ -26,6 +27,7 @@ describe('CreateEksCluster', () => {
vm = shallowMount(CreateEksCluster, {
propsData: {
gitlabManagedClusterHelpPath,
+ namespacePerEnvironmentHelpPath,
accountAndExternalIdsHelpPath,
createRoleArnHelpPath,
externalLinkIcon,
@@ -53,6 +55,12 @@ describe('CreateEksCluster', () => {
);
});
+ it('help url for namespace per environment cluster documentation', () => {
+ expect(vm.find(EksClusterConfigurationForm).props('namespacePerEnvironmentHelpPath')).toBe(
+ namespacePerEnvironmentHelpPath,
+ );
+ });
+
it('help url for gitlab managed cluster documentation', () => {
expect(vm.find(EksClusterConfigurationForm).props('kubernetesIntegrationHelpPath')).toBe(
kubernetesIntegrationHelpPath,
diff --git a/spec/frontend/create_cluster/eks_cluster/components/eks_cluster_configuration_form_spec.js b/spec/frontend/create_cluster/eks_cluster/components/eks_cluster_configuration_form_spec.js
index d7dd7072f67..2600415fc9f 100644
--- a/spec/frontend/create_cluster/eks_cluster/components/eks_cluster_configuration_form_spec.js
+++ b/spec/frontend/create_cluster/eks_cluster/components/eks_cluster_configuration_form_spec.js
@@ -169,6 +169,7 @@ describe('EksClusterConfigurationForm', () => {
store,
propsData: {
gitlabManagedClusterHelpPath: '',
+ namespacePerEnvironmentHelpPath: '',
kubernetesIntegrationHelpPath: '',
externalLinkIcon: '',
},
diff --git a/spec/frontend/create_cluster/eks_cluster/store/actions_spec.js b/spec/frontend/create_cluster/eks_cluster/store/actions_spec.js
index ed753888790..f929216689a 100644
--- a/spec/frontend/create_cluster/eks_cluster/store/actions_spec.js
+++ b/spec/frontend/create_cluster/eks_cluster/store/actions_spec.js
@@ -14,6 +14,7 @@ import {
SET_ROLE,
SET_SECURITY_GROUP,
SET_GITLAB_MANAGED_CLUSTER,
+ SET_NAMESPACE_PER_ENVIRONMENT,
SET_INSTANCE_TYPE,
SET_NODE_COUNT,
REQUEST_CREATE_ROLE,
@@ -40,6 +41,7 @@ describe('EKS Cluster Store Actions', () => {
let instanceType;
let nodeCount;
let gitlabManagedCluster;
+ let namespacePerEnvironment;
let mock;
let state;
let newClusterUrl;
@@ -57,6 +59,7 @@ describe('EKS Cluster Store Actions', () => {
instanceType = 'small-1';
nodeCount = '5';
gitlabManagedCluster = true;
+ namespacePerEnvironment = true;
newClusterUrl = '/clusters/1';
@@ -76,19 +79,20 @@ describe('EKS Cluster Store Actions', () => {
});
it.each`
- action | mutation | payload | payloadDescription
- ${'setClusterName'} | ${SET_CLUSTER_NAME} | ${{ clusterName }} | ${'cluster name'}
- ${'setEnvironmentScope'} | ${SET_ENVIRONMENT_SCOPE} | ${{ environmentScope }} | ${'environment scope'}
- ${'setKubernetesVersion'} | ${SET_KUBERNETES_VERSION} | ${{ kubernetesVersion }} | ${'kubernetes version'}
- ${'setRole'} | ${SET_ROLE} | ${{ role }} | ${'role'}
- ${'setRegion'} | ${SET_REGION} | ${{ region }} | ${'region'}
- ${'setKeyPair'} | ${SET_KEY_PAIR} | ${{ keyPair }} | ${'key pair'}
- ${'setVpc'} | ${SET_VPC} | ${{ vpc }} | ${'vpc'}
- ${'setSubnet'} | ${SET_SUBNET} | ${{ subnet }} | ${'subnet'}
- ${'setSecurityGroup'} | ${SET_SECURITY_GROUP} | ${{ securityGroup }} | ${'securityGroup'}
- ${'setInstanceType'} | ${SET_INSTANCE_TYPE} | ${{ instanceType }} | ${'instance type'}
- ${'setNodeCount'} | ${SET_NODE_COUNT} | ${{ nodeCount }} | ${'node count'}
- ${'setGitlabManagedCluster'} | ${SET_GITLAB_MANAGED_CLUSTER} | ${gitlabManagedCluster} | ${'gitlab managed cluster'}
+ action | mutation | payload | payloadDescription
+ ${'setClusterName'} | ${SET_CLUSTER_NAME} | ${{ clusterName }} | ${'cluster name'}
+ ${'setEnvironmentScope'} | ${SET_ENVIRONMENT_SCOPE} | ${{ environmentScope }} | ${'environment scope'}
+ ${'setKubernetesVersion'} | ${SET_KUBERNETES_VERSION} | ${{ kubernetesVersion }} | ${'kubernetes version'}
+ ${'setRole'} | ${SET_ROLE} | ${{ role }} | ${'role'}
+ ${'setRegion'} | ${SET_REGION} | ${{ region }} | ${'region'}
+ ${'setKeyPair'} | ${SET_KEY_PAIR} | ${{ keyPair }} | ${'key pair'}
+ ${'setVpc'} | ${SET_VPC} | ${{ vpc }} | ${'vpc'}
+ ${'setSubnet'} | ${SET_SUBNET} | ${{ subnet }} | ${'subnet'}
+ ${'setSecurityGroup'} | ${SET_SECURITY_GROUP} | ${{ securityGroup }} | ${'securityGroup'}
+ ${'setInstanceType'} | ${SET_INSTANCE_TYPE} | ${{ instanceType }} | ${'instance type'}
+ ${'setNodeCount'} | ${SET_NODE_COUNT} | ${{ nodeCount }} | ${'node count'}
+ ${'setGitlabManagedCluster'} | ${SET_GITLAB_MANAGED_CLUSTER} | ${gitlabManagedCluster} | ${'gitlab managed cluster'}
+ ${'setNamespacePerEnvironment'} | ${SET_NAMESPACE_PER_ENVIRONMENT} | ${namespacePerEnvironment} | ${'namespace per environment'}
`(`$action commits $mutation with $payloadDescription payload`, data => {
const { action, mutation, payload } = data;
@@ -179,6 +183,7 @@ describe('EKS Cluster Store Actions', () => {
name: clusterName,
environment_scope: environmentScope,
managed: gitlabManagedCluster,
+ namespace_per_environment: namespacePerEnvironment,
provider_aws_attributes: {
kubernetes_version: kubernetesVersion,
region,
@@ -204,6 +209,7 @@ describe('EKS Cluster Store Actions', () => {
selectedInstanceType: instanceType,
nodeCount,
gitlabManagedCluster,
+ namespacePerEnvironment,
});
});
diff --git a/spec/frontend/cycle_analytics/stage_nav_item_spec.js b/spec/frontend/cycle_analytics/stage_nav_item_spec.js
index 1fe80d3b1ce..d577d0b602a 100644
--- a/spec/frontend/cycle_analytics/stage_nav_item_spec.js
+++ b/spec/frontend/cycle_analytics/stage_nav_item_spec.js
@@ -118,7 +118,7 @@ describe('StageNavItem', () => {
expect(wrapper.find('.stage-median').text()).toBe('Not available');
});
it('does not render options menu', () => {
- expect(wrapper.find('.more-actions-toggle').exists()).toBe(false);
+ expect(wrapper.find('[data-testid="more-actions-toggle"]').exists()).toBe(false);
});
});
@@ -135,7 +135,7 @@ describe('StageNavItem', () => {
});
it('does not render options menu', () => {
- expect(wrapper.find('.more-actions-toggle').exists()).toBe(false);
+ expect(wrapper.find('[data-testid="more-actions-toggle"]').exists()).toBe(false);
});
it('can not edit the stage', () => {
diff --git a/spec/frontend/deploy_freeze/components/timezone_dropdown_spec.js b/spec/frontend/deploy_freeze/components/timezone_dropdown_spec.js
index 99cb864ce34..7c1a4ff1085 100644
--- a/spec/frontend/deploy_freeze/components/timezone_dropdown_spec.js
+++ b/spec/frontend/deploy_freeze/components/timezone_dropdown_spec.js
@@ -1,6 +1,6 @@
import Vuex from 'vuex';
import { shallowMount, createLocalVue } from '@vue/test-utils';
-import { GlDeprecatedDropdownItem, GlDropdown } from '@gitlab/ui';
+import { GlDropdownItem, GlDropdown } from '@gitlab/ui';
import TimezoneDropdown from '~/vue_shared/components/timezone_dropdown.vue';
import createStore from '~/deploy_freeze/store';
@@ -29,8 +29,8 @@ describe('Deploy freeze timezone dropdown', () => {
wrapper.setData({ searchTerm });
};
- const findAllDropdownItems = () => wrapper.findAll(GlDeprecatedDropdownItem);
- const findDropdownItemByIndex = index => wrapper.findAll(GlDeprecatedDropdownItem).at(index);
+ const findAllDropdownItems = () => wrapper.findAll(GlDropdownItem);
+ const findDropdownItemByIndex = index => wrapper.findAll(GlDropdownItem).at(index);
afterEach(() => {
wrapper.destroy();
diff --git a/spec/frontend/design_management/components/__snapshots__/design_note_pin_spec.js.snap b/spec/frontend/design_management/components/__snapshots__/design_note_pin_spec.js.snap
index 62a0f675cff..ed8ed3254ba 100644
--- a/spec/frontend/design_management/components/__snapshots__/design_note_pin_spec.js.snap
+++ b/spec/frontend/design_management/components/__snapshots__/design_note_pin_spec.js.snap
@@ -1,23 +1,9 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`Design note pin component should match the snapshot of note when repositioning 1`] = `
-<button
- aria-label="Comment form position"
- class="design-pin gl-absolute gl-display-flex gl-align-items-center gl-justify-content-center gl-p-0 btn-transparent comment-indicator"
- style="left: 10px; top: 10px; cursor: move;"
- type="button"
->
- <gl-icon-stub
- name="image-comment-dark"
- size="24"
- />
-</button>
-`;
-
exports[`Design note pin component should match the snapshot of note with index 1`] = `
<button
aria-label="Comment '1' position"
- class="design-pin gl-absolute gl-display-flex gl-align-items-center gl-justify-content-center gl-p-0 js-image-badge badge badge-pill"
+ class="gl-absolute gl-display-flex gl-align-items-center gl-justify-content-center gl-font-lg gl-outline-0! js-image-badge badge badge-pill"
style="left: 10px; top: 10px;"
type="button"
>
@@ -30,7 +16,7 @@ exports[`Design note pin component should match the snapshot of note with index
exports[`Design note pin component should match the snapshot of note without index 1`] = `
<button
aria-label="Comment form position"
- class="design-pin gl-absolute gl-display-flex gl-align-items-center gl-justify-content-center gl-p-0 btn-transparent comment-indicator"
+ class="gl-absolute gl-display-flex gl-align-items-center gl-justify-content-center gl-font-lg gl-outline-0! btn-transparent comment-indicator gl-p-0"
style="left: 10px; top: 10px;"
type="button"
>
diff --git a/spec/frontend/design_management/components/__snapshots__/design_presentation_spec.js.snap b/spec/frontend/design_management/components/__snapshots__/design_presentation_spec.js.snap
index 189962c5b2e..560533891c9 100644
--- a/spec/frontend/design_management/components/__snapshots__/design_presentation_spec.js.snap
+++ b/spec/frontend/design_management/components/__snapshots__/design_presentation_spec.js.snap
@@ -2,10 +2,10 @@
exports[`Design management design presentation component currentCommentForm is equal to current annotation position when isAnnotating is true 1`] = `
<div
- class="h-100 w-100 p-3 overflow-auto position-relative"
+ class="gl-h-full gl-w-full gl-p-5 overflow-auto gl-relative"
>
<div
- class="h-100 w-100 d-flex align-items-center position-relative"
+ class="gl-h-full gl-w-full gl-display-flex gl-align-items-center gl-relative"
>
<design-image-stub
image="test.jpg"
@@ -25,10 +25,10 @@ exports[`Design management design presentation component currentCommentForm is e
exports[`Design management design presentation component currentCommentForm is null when isAnnotating is false 1`] = `
<div
- class="h-100 w-100 p-3 overflow-auto position-relative"
+ class="gl-h-full gl-w-full gl-p-5 overflow-auto gl-relative"
>
<div
- class="h-100 w-100 d-flex align-items-center position-relative"
+ class="gl-h-full gl-w-full gl-display-flex gl-align-items-center gl-relative"
>
<design-image-stub
image="test.jpg"
@@ -47,10 +47,10 @@ exports[`Design management design presentation component currentCommentForm is n
exports[`Design management design presentation component currentCommentForm is null when isAnnotating is true but annotation position is falsey 1`] = `
<div
- class="h-100 w-100 p-3 overflow-auto position-relative"
+ class="gl-h-full gl-w-full gl-p-5 overflow-auto gl-relative"
>
<div
- class="h-100 w-100 d-flex align-items-center position-relative"
+ class="gl-h-full gl-w-full gl-display-flex gl-align-items-center gl-relative"
>
<design-image-stub
image="test.jpg"
@@ -69,10 +69,10 @@ exports[`Design management design presentation component currentCommentForm is n
exports[`Design management design presentation component renders empty state when no image provided 1`] = `
<div
- class="h-100 w-100 p-3 overflow-auto position-relative"
+ class="gl-h-full gl-w-full gl-p-5 overflow-auto gl-relative"
>
<div
- class="h-100 w-100 d-flex align-items-center position-relative"
+ class="gl-h-full gl-w-full gl-display-flex gl-align-items-center gl-relative"
>
<!---->
@@ -83,10 +83,10 @@ exports[`Design management design presentation component renders empty state whe
exports[`Design management design presentation component renders image and overlay when image provided 1`] = `
<div
- class="h-100 w-100 p-3 overflow-auto position-relative"
+ class="gl-h-full gl-w-full gl-p-5 overflow-auto gl-relative"
>
<div
- class="h-100 w-100 d-flex align-items-center position-relative"
+ class="gl-h-full gl-w-full gl-display-flex gl-align-items-center gl-relative"
>
<design-image-stub
image="test.jpg"
diff --git a/spec/frontend/design_management/components/__snapshots__/design_scaler_spec.js.snap b/spec/frontend/design_management/components/__snapshots__/design_scaler_spec.js.snap
index cb4575cbd11..0679b485f77 100644
--- a/spec/frontend/design_management/components/__snapshots__/design_scaler_spec.js.snap
+++ b/spec/frontend/design_management/components/__snapshots__/design_scaler_spec.js.snap
@@ -10,7 +10,7 @@ exports[`Design management design scaler component minus and reset buttons are d
disabled="disabled"
>
<span
- class="d-flex-center gl-icon s16"
+ class="gl-display-flex gl-justify-content-center gl-align-items-center gl-icon s16"
>
–
@@ -48,7 +48,7 @@ exports[`Design management design scaler component minus and reset buttons are e
class="btn"
>
<span
- class="d-flex-center gl-icon s16"
+ class="gl-display-flex gl-justify-content-center gl-align-items-center gl-icon s16"
>
–
@@ -85,7 +85,7 @@ exports[`Design management design scaler component plus button is disabled when
class="btn"
>
<span
- class="d-flex-center gl-icon s16"
+ class="gl-display-flex gl-justify-content-center gl-align-items-center gl-icon s16"
>
–
diff --git a/spec/frontend/design_management/components/__snapshots__/image_spec.js.snap b/spec/frontend/design_management/components/__snapshots__/image_spec.js.snap
index acaa62b11eb..7cffd3cf3e8 100644
--- a/spec/frontend/design_management/components/__snapshots__/image_spec.js.snap
+++ b/spec/frontend/design_management/components/__snapshots__/image_spec.js.snap
@@ -2,7 +2,7 @@
exports[`Design management large image component renders image 1`] = `
<div
- class="m-auto js-design-image"
+ class="gl-mx-auto gl-my-auto js-design-image"
>
<!---->
@@ -16,7 +16,7 @@ exports[`Design management large image component renders image 1`] = `
exports[`Design management large image component renders loading state 1`] = `
<div
- class="m-auto js-design-image"
+ class="gl-mx-auto gl-my-auto js-design-image"
isloading="true"
>
<!---->
@@ -31,7 +31,7 @@ exports[`Design management large image component renders loading state 1`] = `
exports[`Design management large image component renders media broken icon on error 1`] = `
<gl-icon-stub
- class="text-secondary-100"
+ class="gl-text-gray-200"
name="media-broken"
size="48"
/>
@@ -39,7 +39,7 @@ exports[`Design management large image component renders media broken icon on er
exports[`Design management large image component sets correct classes and styles if imageStyle is set 1`] = `
<div
- class="m-auto js-design-image"
+ class="gl-mx-auto gl-my-auto js-design-image"
>
<!---->
@@ -54,7 +54,7 @@ exports[`Design management large image component sets correct classes and styles
exports[`Design management large image component zoom sets image style when zoomed 1`] = `
<div
- class="m-auto js-design-image"
+ class="gl-mx-auto gl-my-auto js-design-image"
>
<!---->
diff --git a/spec/frontend/design_management/components/design_note_pin_spec.js b/spec/frontend/design_management/components/design_note_pin_spec.js
index 4e045b58a35..a6219923aca 100644
--- a/spec/frontend/design_management/components/design_note_pin_spec.js
+++ b/spec/frontend/design_management/components/design_note_pin_spec.js
@@ -29,21 +29,4 @@ describe('Design note pin component', () => {
createComponent({ label: 1 });
expect(wrapper.element).toMatchSnapshot();
});
-
- it('should match the snapshot of note when repositioning', () => {
- createComponent({ repositioning: true });
- expect(wrapper.element).toMatchSnapshot();
- });
-
- describe('pinStyle', () => {
- it('sets cursor to `move` when repositioning = true', () => {
- createComponent({ repositioning: true });
- expect(wrapper.vm.pinStyle.cursor).toBe('move');
- });
-
- it('does not set cursor when repositioning = false', () => {
- createComponent();
- expect(wrapper.vm.pinStyle.cursor).toBe(undefined);
- });
- });
});
diff --git a/spec/frontend/design_management/components/design_overlay_spec.js b/spec/frontend/design_management/components/design_overlay_spec.js
index 673a09320e5..4ef067e3f5e 100644
--- a/spec/frontend/design_management/components/design_overlay_spec.js
+++ b/spec/frontend/design_management/components/design_overlay_spec.js
@@ -202,7 +202,7 @@ describe('Design overlay component', () => {
{ x: position.x, y: position.y },
{ x: 20, y: 20 },
).then(() => {
- expect(findFirstBadge().attributes().style).toBe('left: 20px; top: 20px; cursor: move;');
+ expect(findFirstBadge().attributes().style).toBe('left: 20px; top: 20px;');
});
});
@@ -300,9 +300,7 @@ describe('Design overlay component', () => {
{ x: position.x, y: position.y },
{ x: 20, y: 20 },
).then(() => {
- expect(findCommentBadge().attributes().style).toBe(
- 'left: 20px; top: 20px; cursor: move;',
- );
+ expect(findCommentBadge().attributes().style).toBe('left: 20px; top: 20px;');
});
});
diff --git a/spec/frontend/design_management/components/design_sidebar_spec.js b/spec/frontend/design_management/components/design_sidebar_spec.js
index 700faa8a70f..60266883fcd 100644
--- a/spec/frontend/design_management/components/design_sidebar_spec.js
+++ b/spec/frontend/design_management/components/design_sidebar_spec.js
@@ -43,7 +43,7 @@ describe('Design management design sidebar component', () => {
const findNewDiscussionDisclaimer = () =>
wrapper.find('[data-testid="new-discussion-disclaimer"]');
- function createComponent(props = {}, { enableTodoButton } = {}) {
+ function createComponent(props = {}) {
wrapper = shallowMount(DesignSidebar, {
propsData: {
design,
@@ -58,9 +58,6 @@ describe('Design management design sidebar component', () => {
},
},
stubs: { GlPopover },
- provide: {
- glFeatures: { designManagementTodoButton: enableTodoButton },
- },
});
}
@@ -80,6 +77,12 @@ describe('Design management design sidebar component', () => {
expect(findParticipants().props('participants')).toHaveLength(1);
});
+ it('renders To-Do button', () => {
+ createComponent();
+
+ expect(wrapper.find(DesignTodoButton).exists()).toBe(true);
+ });
+
describe('when has no discussions', () => {
beforeEach(() => {
createComponent({
@@ -245,23 +248,4 @@ describe('Design management design sidebar component', () => {
expect(Cookies.set).toHaveBeenCalledWith(cookieKey, 'true', { expires: 365 * 10 });
});
});
-
- it('does not render To-Do button by default', () => {
- createComponent();
- expect(wrapper.find(DesignTodoButton).exists()).toBe(false);
- });
-
- describe('when `design_management_todo_button` feature flag is enabled', () => {
- beforeEach(() => {
- createComponent({}, { enableTodoButton: true });
- });
-
- it('renders sidebar root element with no top padding', () => {
- expect(wrapper.classes()).toContain('gl-pt-0');
- });
-
- it('renders To-Do button', () => {
- expect(wrapper.find(DesignTodoButton).exists()).toBe(true);
- });
- });
});
diff --git a/spec/frontend/design_management/components/design_todo_button_spec.js b/spec/frontend/design_management/components/design_todo_button_spec.js
index 451c23f0fea..9ebc6ca26a2 100644
--- a/spec/frontend/design_management/components/design_todo_button_spec.js
+++ b/spec/frontend/design_management/components/design_todo_button_spec.js
@@ -111,7 +111,7 @@ describe('Design management design todo button', () => {
});
it('renders correct button text', () => {
- expect(wrapper.text()).toBe('Add a To-Do');
+ expect(wrapper.text()).toBe('Add a To Do');
});
describe('when clicked', () => {
diff --git a/spec/frontend/design_management/components/list/__snapshots__/item_spec.js.snap b/spec/frontend/design_management/components/list/__snapshots__/item_spec.js.snap
index 822df1f6472..de276bd300b 100644
--- a/spec/frontend/design_management/components/list/__snapshots__/item_spec.js.snap
+++ b/spec/frontend/design_management/components/list/__snapshots__/item_spec.js.snap
@@ -24,6 +24,7 @@ exports[`Design management list item component with notes renders item with mult
<img
alt="test"
class="gl-display-block gl-mx-auto gl-max-w-full mh-100 design-img"
+ data-qa-filename="test"
data-qa-selector="design_image"
src=""
/>
@@ -94,6 +95,7 @@ exports[`Design management list item component with notes renders item with sing
<img
alt="test"
class="gl-display-block gl-mx-auto gl-max-w-full mh-100 design-img"
+ data-qa-filename="test"
data-qa-selector="design_image"
src=""
/>
diff --git a/spec/frontend/design_management/components/toolbar/__snapshots__/design_navigation_spec.js.snap b/spec/frontend/design_management/components/toolbar/__snapshots__/design_navigation_spec.js.snap
index a7d6145285c..5eb86d4f9cb 100644
--- a/spec/frontend/design_management/components/toolbar/__snapshots__/design_navigation_spec.js.snap
+++ b/spec/frontend/design_management/components/toolbar/__snapshots__/design_navigation_spec.js.snap
@@ -4,15 +4,16 @@ exports[`Design management pagination component hides components when designs ar
exports[`Design management pagination component renders navigation buttons 1`] = `
<div
- class="d-flex align-items-center"
+ class="gl-display-flex gl-align-items-center"
>
0 of 2
<gl-button-group-stub
- class="ml-3 mr-3"
+ class="gl-mx-5"
>
<gl-button-stub
+ buttontextclasses=""
category="primary"
class="js-previous-design"
disabled="true"
@@ -23,6 +24,7 @@ exports[`Design management pagination component renders navigation buttons 1`] =
/>
<gl-button-stub
+ buttontextclasses=""
category="primary"
class="js-next-design"
icon="angle-right"
diff --git a/spec/frontend/design_management/components/toolbar/__snapshots__/index_spec.js.snap b/spec/frontend/design_management/components/toolbar/__snapshots__/index_spec.js.snap
index b286a74ebb8..723ac0491a7 100644
--- a/spec/frontend/design_management/components/toolbar/__snapshots__/index_spec.js.snap
+++ b/spec/frontend/design_management/components/toolbar/__snapshots__/index_spec.js.snap
@@ -19,16 +19,16 @@ exports[`Design management toolbar component renders design and updated data 1`]
</a>
<div
- class="overflow-hidden d-flex align-items-center"
+ class="gl-overflow-hidden gl-display-flex gl-align-items-center"
>
<h2
- class="m-0 str-truncated-100 gl-font-base"
+ class="gl-m-0 str-truncated-100 gl-font-base"
>
test.jpg
</h2>
<small
- class="text-secondary"
+ class="gl-text-gray-500"
>
Updated 1 hour ago by Test Name
</small>
@@ -36,11 +36,12 @@ exports[`Design management toolbar component renders design and updated data 1`]
</div>
<design-navigation-stub
- class="ml-auto flex-shrink-0"
+ class="gl-ml-auto gl-flex-shrink-0"
id="1"
/>
<gl-button-stub
+ buttontextclasses=""
category="primary"
href="/-/designs/306/7f747adcd4693afadbe968d7ba7d983349b9012d"
icon="download"
diff --git a/spec/frontend/design_management/components/toolbar/design_navigation_spec.js b/spec/frontend/design_management/components/toolbar/design_navigation_spec.js
index 1c6588a9628..1d9b9c002f9 100644
--- a/spec/frontend/design_management/components/toolbar/design_navigation_spec.js
+++ b/spec/frontend/design_management/components/toolbar/design_navigation_spec.js
@@ -43,7 +43,7 @@ describe('Design management pagination component', () => {
it('renders navigation buttons', () => {
wrapper.setData({
- designs: [{ id: '1' }, { id: '2' }],
+ designCollection: { designs: [{ id: '1' }, { id: '2' }] },
});
return wrapper.vm.$nextTick().then(() => {
@@ -54,7 +54,7 @@ describe('Design management pagination component', () => {
describe('keyboard buttons navigation', () => {
beforeEach(() => {
wrapper.setData({
- designs: [{ filename: '1' }, { filename: '2' }, { filename: '3' }],
+ designCollection: { designs: [{ filename: '1' }, { filename: '2' }, { filename: '3' }] },
});
});
diff --git a/spec/frontend/design_management/components/upload/__snapshots__/button_spec.js.snap b/spec/frontend/design_management/components/upload/__snapshots__/button_spec.js.snap
index 3d7939df28e..eaa7460ae15 100644
--- a/spec/frontend/design_management/components/upload/__snapshots__/button_spec.js.snap
+++ b/spec/frontend/design_management/components/upload/__snapshots__/button_spec.js.snap
@@ -5,6 +5,7 @@ exports[`Design management upload button component renders inverted upload desig
isinverted="true"
>
<gl-button-stub
+ buttontextclasses=""
category="primary"
icon=""
size="small"
@@ -30,6 +31,7 @@ exports[`Design management upload button component renders inverted upload desig
exports[`Design management upload button component renders loading icon 1`] = `
<div>
<gl-button-stub
+ buttontextclasses=""
category="primary"
disabled="true"
icon=""
@@ -62,6 +64,7 @@ exports[`Design management upload button component renders loading icon 1`] = `
exports[`Design management upload button component renders upload design button 1`] = `
<div>
<gl-button-stub
+ buttontextclasses=""
category="primary"
icon=""
size="small"
diff --git a/spec/frontend/design_management/components/upload/__snapshots__/design_dropzone_spec.js.snap b/spec/frontend/design_management/components/upload/__snapshots__/design_dropzone_spec.js.snap
index 9284099b40d..1ca5360fa59 100644
--- a/spec/frontend/design_management/components/upload/__snapshots__/design_dropzone_spec.js.snap
+++ b/spec/frontend/design_management/components/upload/__snapshots__/design_dropzone_spec.js.snap
@@ -2,10 +2,10 @@
exports[`Design management dropzone component when dragging renders correct template when drag event contains files 1`] = `
<div
- class="w-100 position-relative"
+ class="gl-w-full gl-relative"
>
<button
- class="card design-dropzone-card design-dropzone-border w-100 h-100 gl-align-items-center gl-justify-content-center gl-p-3"
+ class="card design-dropzone-card design-dropzone-border gl-w-full gl-h-full gl-align-items-center gl-justify-content-center gl-p-3"
>
<div
class="gl-display-flex gl-align-items-center gl-justify-content-center gl-text-center gl-flex-direction-column"
@@ -39,11 +39,11 @@ exports[`Design management dropzone component when dragging renders correct temp
name="design-dropzone-fade"
>
<div
- class="card design-dropzone-border design-dropzone-overlay w-100 h-100 position-absolute d-flex-center p-3 bg-white"
+ class="card design-dropzone-border design-dropzone-overlay gl-w-full gl-h-full gl-absolute gl-display-flex gl-align-items-center gl-justify-content-center gl-p-3 gl-bg-white"
style=""
>
<div
- class="mw-50 text-center"
+ class="mw-50 gl-text-center"
style="display: none;"
>
<h3
@@ -58,7 +58,7 @@ exports[`Design management dropzone component when dragging renders correct temp
</div>
<div
- class="mw-50 text-center"
+ class="mw-50 gl-text-center"
style=""
>
<h3
@@ -78,10 +78,10 @@ exports[`Design management dropzone component when dragging renders correct temp
exports[`Design management dropzone component when dragging renders correct template when drag event contains files and text 1`] = `
<div
- class="w-100 position-relative"
+ class="gl-w-full gl-relative"
>
<button
- class="card design-dropzone-card design-dropzone-border w-100 h-100 gl-align-items-center gl-justify-content-center gl-p-3"
+ class="card design-dropzone-card design-dropzone-border gl-w-full gl-h-full gl-align-items-center gl-justify-content-center gl-p-3"
>
<div
class="gl-display-flex gl-align-items-center gl-justify-content-center gl-text-center gl-flex-direction-column"
@@ -115,11 +115,11 @@ exports[`Design management dropzone component when dragging renders correct temp
name="design-dropzone-fade"
>
<div
- class="card design-dropzone-border design-dropzone-overlay w-100 h-100 position-absolute d-flex-center p-3 bg-white"
+ class="card design-dropzone-border design-dropzone-overlay gl-w-full gl-h-full gl-absolute gl-display-flex gl-align-items-center gl-justify-content-center gl-p-3 gl-bg-white"
style=""
>
<div
- class="mw-50 text-center"
+ class="mw-50 gl-text-center"
style="display: none;"
>
<h3
@@ -134,7 +134,7 @@ exports[`Design management dropzone component when dragging renders correct temp
</div>
<div
- class="mw-50 text-center"
+ class="mw-50 gl-text-center"
style=""
>
<h3
@@ -154,10 +154,10 @@ exports[`Design management dropzone component when dragging renders correct temp
exports[`Design management dropzone component when dragging renders correct template when drag event contains text 1`] = `
<div
- class="w-100 position-relative"
+ class="gl-w-full gl-relative"
>
<button
- class="card design-dropzone-card design-dropzone-border w-100 h-100 gl-align-items-center gl-justify-content-center gl-p-3"
+ class="card design-dropzone-card design-dropzone-border gl-w-full gl-h-full gl-align-items-center gl-justify-content-center gl-p-3"
>
<div
class="gl-display-flex gl-align-items-center gl-justify-content-center gl-text-center gl-flex-direction-column"
@@ -191,11 +191,11 @@ exports[`Design management dropzone component when dragging renders correct temp
name="design-dropzone-fade"
>
<div
- class="card design-dropzone-border design-dropzone-overlay w-100 h-100 position-absolute d-flex-center p-3 bg-white"
+ class="card design-dropzone-border design-dropzone-overlay gl-w-full gl-h-full gl-absolute gl-display-flex gl-align-items-center gl-justify-content-center gl-p-3 gl-bg-white"
style=""
>
<div
- class="mw-50 text-center"
+ class="mw-50 gl-text-center"
>
<h3
class=""
@@ -209,7 +209,7 @@ exports[`Design management dropzone component when dragging renders correct temp
</div>
<div
- class="mw-50 text-center"
+ class="mw-50 gl-text-center"
style="display: none;"
>
<h3
@@ -229,10 +229,10 @@ exports[`Design management dropzone component when dragging renders correct temp
exports[`Design management dropzone component when dragging renders correct template when drag event is empty 1`] = `
<div
- class="w-100 position-relative"
+ class="gl-w-full gl-relative"
>
<button
- class="card design-dropzone-card design-dropzone-border w-100 h-100 gl-align-items-center gl-justify-content-center gl-p-3"
+ class="card design-dropzone-card design-dropzone-border gl-w-full gl-h-full gl-align-items-center gl-justify-content-center gl-p-3"
>
<div
class="gl-display-flex gl-align-items-center gl-justify-content-center gl-text-center gl-flex-direction-column"
@@ -266,11 +266,11 @@ exports[`Design management dropzone component when dragging renders correct temp
name="design-dropzone-fade"
>
<div
- class="card design-dropzone-border design-dropzone-overlay w-100 h-100 position-absolute d-flex-center p-3 bg-white"
+ class="card design-dropzone-border design-dropzone-overlay gl-w-full gl-h-full gl-absolute gl-display-flex gl-align-items-center gl-justify-content-center gl-p-3 gl-bg-white"
style=""
>
<div
- class="mw-50 text-center"
+ class="mw-50 gl-text-center"
>
<h3
class=""
@@ -284,7 +284,7 @@ exports[`Design management dropzone component when dragging renders correct temp
</div>
<div
- class="mw-50 text-center"
+ class="mw-50 gl-text-center"
style="display: none;"
>
<h3
@@ -304,10 +304,10 @@ exports[`Design management dropzone component when dragging renders correct temp
exports[`Design management dropzone component when dragging renders correct template when dragging stops 1`] = `
<div
- class="w-100 position-relative"
+ class="gl-w-full gl-relative"
>
<button
- class="card design-dropzone-card design-dropzone-border w-100 h-100 gl-align-items-center gl-justify-content-center gl-p-3"
+ class="card design-dropzone-card design-dropzone-border gl-w-full gl-h-full gl-align-items-center gl-justify-content-center gl-p-3"
>
<div
class="gl-display-flex gl-align-items-center gl-justify-content-center gl-text-center gl-flex-direction-column"
@@ -341,11 +341,11 @@ exports[`Design management dropzone component when dragging renders correct temp
name="design-dropzone-fade"
>
<div
- class="card design-dropzone-border design-dropzone-overlay w-100 h-100 position-absolute d-flex-center p-3 bg-white"
+ class="card design-dropzone-border design-dropzone-overlay gl-w-full gl-h-full gl-absolute gl-display-flex gl-align-items-center gl-justify-content-center gl-p-3 gl-bg-white"
style="display: none;"
>
<div
- class="mw-50 text-center"
+ class="mw-50 gl-text-center"
>
<h3
class=""
@@ -359,7 +359,7 @@ exports[`Design management dropzone component when dragging renders correct temp
</div>
<div
- class="mw-50 text-center"
+ class="mw-50 gl-text-center"
style="display: none;"
>
<h3
@@ -379,10 +379,10 @@ exports[`Design management dropzone component when dragging renders correct temp
exports[`Design management dropzone component when no slot provided renders default dropzone card 1`] = `
<div
- class="w-100 position-relative"
+ class="gl-w-full gl-relative"
>
<button
- class="card design-dropzone-card design-dropzone-border w-100 h-100 gl-align-items-center gl-justify-content-center gl-p-3"
+ class="card design-dropzone-card design-dropzone-border gl-w-full gl-h-full gl-align-items-center gl-justify-content-center gl-p-3"
>
<div
class="gl-display-flex gl-align-items-center gl-justify-content-center gl-text-center gl-flex-direction-column"
@@ -416,11 +416,11 @@ exports[`Design management dropzone component when no slot provided renders defa
name="design-dropzone-fade"
>
<div
- class="card design-dropzone-border design-dropzone-overlay w-100 h-100 position-absolute d-flex-center p-3 bg-white"
+ class="card design-dropzone-border design-dropzone-overlay gl-w-full gl-h-full gl-absolute gl-display-flex gl-align-items-center gl-justify-content-center gl-p-3 gl-bg-white"
style="display: none;"
>
<div
- class="mw-50 text-center"
+ class="mw-50 gl-text-center"
>
<h3
class=""
@@ -434,7 +434,7 @@ exports[`Design management dropzone component when no slot provided renders defa
</div>
<div
- class="mw-50 text-center"
+ class="mw-50 gl-text-center"
style="display: none;"
>
<h3
@@ -454,7 +454,7 @@ exports[`Design management dropzone component when no slot provided renders defa
exports[`Design management dropzone component when slot provided renders dropzone with slot content 1`] = `
<div
- class="w-100 position-relative"
+ class="gl-w-full gl-relative"
>
<div>
dropzone slot
@@ -464,11 +464,11 @@ exports[`Design management dropzone component when slot provided renders dropzon
name="design-dropzone-fade"
>
<div
- class="card design-dropzone-border design-dropzone-overlay w-100 h-100 position-absolute d-flex-center p-3 bg-white"
+ class="card design-dropzone-border design-dropzone-overlay gl-w-full gl-h-full gl-absolute gl-display-flex gl-align-items-center gl-justify-content-center gl-p-3 gl-bg-white"
style="display: none;"
>
<div
- class="mw-50 text-center"
+ class="mw-50 gl-text-center"
>
<h3
class=""
@@ -482,7 +482,7 @@ exports[`Design management dropzone component when slot provided renders dropzon
</div>
<div
- class="mw-50 text-center"
+ class="mw-50 gl-text-center"
style="display: none;"
>
<h3
diff --git a/spec/frontend/design_management/mock_data/apollo_mock.js b/spec/frontend/design_management/mock_data/apollo_mock.js
index 1c7806c292f..5e41210221b 100644
--- a/spec/frontend/design_management/mock_data/apollo_mock.js
+++ b/spec/frontend/design_management/mock_data/apollo_mock.js
@@ -4,6 +4,7 @@ export const designListQueryResponse = {
id: '1',
issue: {
designCollection: {
+ copyState: 'READY',
designs: {
nodes: [
{
@@ -50,6 +51,34 @@ export const designListQueryResponse = {
},
};
+export const designUploadMutationCreatedResponse = {
+ data: {
+ designManagementUpload: {
+ designs: [
+ {
+ id: '1',
+ event: 'CREATION',
+ filename: 'fox_1.jpg',
+ },
+ ],
+ },
+ },
+};
+
+export const designUploadMutationUpdatedResponse = {
+ data: {
+ designManagementUpload: {
+ designs: [
+ {
+ id: '1',
+ event: 'MODIFICATION',
+ filename: 'fox_1.jpg',
+ },
+ ],
+ },
+ },
+};
+
export const permissionsQueryResponse = {
data: {
project: {
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 b80b7fdb43e..2d29b79e31c 100644
--- a/spec/frontend/design_management/pages/__snapshots__/index_spec.js.snap
+++ b/spec/frontend/design_management/pages/__snapshots__/index_spec.js.snap
@@ -8,7 +8,7 @@ exports[`Design management index page designs does not render toolbar when there
<!---->
<div
- class="mt-4"
+ class="gl-mt-6"
>
<ol
class="list-unstyled row"
@@ -19,6 +19,7 @@ exports[`Design management index page designs does not render toolbar when there
>
<design-dropzone-stub
class="design-list-item design-list-item-new"
+ data-qa-selector="design_dropzone_content"
hasdesigns="true"
/>
</li>
@@ -91,7 +92,7 @@ exports[`Design management index page designs renders designs list and header wi
data-testid="designs-root"
>
<header
- class="row-content-block border-top-0 p-2 d-flex"
+ class="row-content-block gl-border-t-0 gl-p-3 gl-display-flex"
>
<div
class="gl-display-flex gl-justify-content-space-between gl-align-items-center gl-w-full"
@@ -110,6 +111,7 @@ exports[`Design management index page designs renders designs list and header wi
class="qa-selector-toolbar gl-display-flex gl-align-items-center"
>
<gl-button-stub
+ buttontextclasses=""
category="primary"
class="gl-mr-4 js-select-all"
icon=""
@@ -126,6 +128,7 @@ exports[`Design management index page designs renders designs list and header wi
buttonclass="gl-mr-3"
buttonsize="small"
buttonvariant="warning"
+ data-qa-selector="archive_button"
>
Archive selected
@@ -139,7 +142,7 @@ exports[`Design management index page designs renders designs list and header wi
</header>
<div
- class="mt-4"
+ class="gl-mt-6"
>
<ol
class="list-unstyled row"
@@ -150,6 +153,7 @@ exports[`Design management index page designs renders designs list and header wi
>
<design-dropzone-stub
class="design-list-item design-list-item-new"
+ data-qa-selector="design_dropzone_content"
hasdesigns="true"
/>
</li>
@@ -171,6 +175,8 @@ exports[`Design management index page designs renders designs list and header wi
<input
class="design-checkbox"
+ data-qa-design="design-1-name"
+ data-qa-selector="design_checkbox"
type="checkbox"
/>
</li>
@@ -192,6 +198,8 @@ exports[`Design management index page designs renders designs list and header wi
<input
class="design-checkbox"
+ data-qa-design="design-2-name"
+ data-qa-selector="design_checkbox"
type="checkbox"
/>
</li>
@@ -213,6 +221,8 @@ exports[`Design management index page designs renders designs list and header wi
<input
class="design-checkbox"
+ data-qa-design="design-3-name"
+ data-qa-selector="design_checkbox"
type="checkbox"
/>
</li>
@@ -233,7 +243,7 @@ exports[`Design management index page designs renders error 1`] = `
<!---->
<div
- class="mt-4"
+ class="gl-mt-6"
>
<gl-alert-stub
dismisslabel="Dismiss"
@@ -264,7 +274,7 @@ exports[`Design management index page designs renders loading icon 1`] = `
<!---->
<div
- class="mt-4"
+ class="gl-mt-6"
>
<gl-loading-icon-stub
color="orange"
@@ -287,7 +297,7 @@ exports[`Design management index page when has no designs renders design dropzon
<!---->
<div
- class="mt-4"
+ class="gl-mt-6"
>
<ol
class="list-unstyled row"
@@ -298,6 +308,7 @@ exports[`Design management index page when has no designs renders design dropzon
>
<design-dropzone-stub
class=""
+ data-qa-selector="design_dropzone_content"
/>
</li>
</ol>
diff --git a/spec/frontend/design_management/pages/design/__snapshots__/index_spec.js.snap b/spec/frontend/design_management/pages/design/__snapshots__/index_spec.js.snap
index c849e4d4ed6..3d6c2561ff6 100644
--- a/spec/frontend/design_management/pages/design/__snapshots__/index_spec.js.snap
+++ b/spec/frontend/design_management/pages/design/__snapshots__/index_spec.js.snap
@@ -2,10 +2,10 @@
exports[`Design management design index page renders design index 1`] = `
<div
- class="design-detail js-design-detail fixed-top w-100 position-bottom-0 d-flex justify-content-center flex-column flex-lg-row"
+ class="design-detail js-design-detail fixed-top gl-w-full gl-bottom-0 gl-display-flex gl-justify-content-center gl-flex-direction-column gl-lg-flex-direction-row"
>
<div
- class="d-flex overflow-hidden flex-grow-1 flex-column position-relative"
+ class="gl-display-flex gl-overflow-hidden gl-flex-grow-1 gl-flex-direction-column gl-relative"
>
<design-destroyer-stub
filenames="test.jpg"
@@ -23,16 +23,26 @@ exports[`Design management design index page renders design index 1`] = `
/>
<div
- class="design-scaler-wrapper position-absolute mb-4 d-flex-center"
+ class="design-scaler-wrapper gl-absolute gl-mb-6 gl-display-flex gl-justify-content-center gl-align-items-center"
>
<design-scaler-stub />
</div>
</div>
<div
- class="image-notes"
+ class="image-notes gl-pt-0"
>
- <!---->
+ <div
+ class="gl-py-4 gl-mb-4 gl-display-flex gl-justify-content-space-between gl-align-items-center gl-border-b-1 gl-border-b-solid gl-border-b-gray-100"
+ >
+ <span>
+ To Do
+ </span>
+
+ <design-todo-button-stub
+ design="[object Object]"
+ />
+ </div>
<h2
class="gl-font-weight-bold gl-mt-0"
@@ -67,6 +77,7 @@ exports[`Design management design index page renders design index 1`] = `
/>
<gl-button-stub
+ buttontextclasses=""
category="primary"
class="link-inherit-color gl-text-body gl-text-decoration-none gl-font-weight-bold gl-mb-4"
data-testid="resolved-comments"
@@ -121,10 +132,10 @@ exports[`Design management design index page renders design index 1`] = `
exports[`Design management design index page sets loading state 1`] = `
<div
- class="design-detail js-design-detail fixed-top w-100 position-bottom-0 d-flex justify-content-center flex-column flex-lg-row"
+ class="design-detail js-design-detail fixed-top gl-w-full gl-bottom-0 gl-display-flex gl-justify-content-center gl-flex-direction-column gl-lg-flex-direction-row"
>
<gl-loading-icon-stub
- class="align-self-center"
+ class="gl-align-self-center"
color="orange"
label="Loading"
size="xl"
@@ -134,10 +145,10 @@ exports[`Design management design index page sets loading state 1`] = `
exports[`Design management design index page with error GlAlert is rendered in correct position with correct content 1`] = `
<div
- class="design-detail js-design-detail fixed-top w-100 position-bottom-0 d-flex justify-content-center flex-column flex-lg-row"
+ class="design-detail js-design-detail fixed-top gl-w-full gl-bottom-0 gl-display-flex gl-justify-content-center gl-flex-direction-column gl-lg-flex-direction-row"
>
<div
- class="d-flex overflow-hidden flex-grow-1 flex-column position-relative"
+ class="gl-display-flex gl-overflow-hidden gl-flex-grow-1 gl-flex-direction-column gl-relative"
>
<design-destroyer-stub
filenames="test.jpg"
@@ -146,7 +157,7 @@ exports[`Design management design index page with error GlAlert is rendered in c
/>
<div
- class="p-3"
+ class="gl-p-5"
>
<gl-alert-stub
dismissible="true"
@@ -172,16 +183,26 @@ exports[`Design management design index page with error GlAlert is rendered in c
/>
<div
- class="design-scaler-wrapper position-absolute mb-4 d-flex-center"
+ class="design-scaler-wrapper gl-absolute gl-mb-6 gl-display-flex gl-justify-content-center gl-align-items-center"
>
<design-scaler-stub />
</div>
</div>
<div
- class="image-notes"
+ class="image-notes gl-pt-0"
>
- <!---->
+ <div
+ class="gl-py-4 gl-mb-4 gl-display-flex gl-justify-content-space-between gl-align-items-center gl-border-b-1 gl-border-b-solid gl-border-b-gray-100"
+ >
+ <span>
+ To Do
+ </span>
+
+ <design-todo-button-stub
+ design="[object Object]"
+ />
+ </div>
<h2
class="gl-font-weight-bold gl-mt-0"
diff --git a/spec/frontend/design_management/pages/index_spec.js b/spec/frontend/design_management/pages/index_spec.js
index 661717d29a3..27a91b11448 100644
--- a/spec/frontend/design_management/pages/index_spec.js
+++ b/spec/frontend/design_management/pages/index_spec.js
@@ -4,6 +4,7 @@ import VueDraggable from 'vuedraggable';
import VueRouter from 'vue-router';
import { GlEmptyState } from '@gitlab/ui';
import createMockApollo from 'jest/helpers/mock_apollo_helper';
+import { mockTracking, unmockTracking } from 'helpers/tracking_helper';
import Index from '~/design_management/pages/index.vue';
import uploadDesignQuery from '~/design_management/graphql/mutations/upload_design.mutation.graphql';
import DesignDestroyer from '~/design_management/components/design_destroyer.vue';
@@ -21,6 +22,8 @@ import * as utils from '~/design_management/utils/design_management_utils';
import { DESIGN_DETAIL_LAYOUT_CLASSLIST } from '~/design_management/constants';
import {
designListQueryResponse,
+ designUploadMutationCreatedResponse,
+ designUploadMutationUpdatedResponse,
permissionsQueryResponse,
moveDesignMutationResponse,
reorderedDesigns,
@@ -29,6 +32,7 @@ import {
import getDesignListQuery from '~/design_management/graphql/queries/get_design_list.query.graphql';
import permissionsQuery from '~/design_management/graphql/queries/design_permissions.query.graphql';
import moveDesignMutation from '~/design_management/graphql/mutations/move_design.mutation.graphql';
+import { DESIGN_TRACKING_PAGE_NAME } from '~/design_management/utils/tracking';
jest.mock('~/flash.js');
const mockPageEl = {
@@ -92,6 +96,8 @@ describe('Design management index page', () => {
const findDesignCheckboxes = () => wrapper.findAll('.design-checkbox');
const findSelectAllButton = () => wrapper.find('.js-select-all');
const findToolbar = () => wrapper.find('.qa-selector-toolbar');
+ const findDesignCollectionIsCopying = () =>
+ wrapper.find('[data-testid="design-collection-is-copying"');
const findDeleteButton = () => wrapper.find(DeleteButton);
const findDropzone = () => wrapper.findAll(DesignDropzone).at(0);
const dropzoneClasses = () => findDropzone().classes();
@@ -99,6 +105,7 @@ describe('Design management index page', () => {
const findFirstDropzoneWithDesign = () => wrapper.findAll(DesignDropzone).at(1);
const findDesignsWrapper = () => wrapper.find('[data-testid="designs-root"]');
const findDesigns = () => wrapper.findAll(Design);
+ const draggableAttributes = () => wrapper.find(VueDraggable).vm.$attrs;
async function moveDesigns(localWrapper) {
await jest.runOnlyPendingTimers();
@@ -115,8 +122,8 @@ describe('Design management index page', () => {
function createComponent({
loading = false,
- designs = [],
allVersions = [],
+ designCollection = { designs: mockDesigns, copyState: 'READY' },
createDesign = true,
stubs = {},
mockMutate = jest.fn().mockResolvedValue(),
@@ -124,7 +131,7 @@ describe('Design management index page', () => {
mutate = mockMutate;
const $apollo = {
queries: {
- designs: {
+ designCollection: {
loading,
},
permissions: {
@@ -137,8 +144,8 @@ describe('Design management index page', () => {
wrapper = shallowMount(Index, {
data() {
return {
- designs,
allVersions,
+ designCollection,
permissions: {
createDesign,
},
@@ -200,13 +207,13 @@ describe('Design management index page', () => {
});
it('renders a toolbar with buttons when there are designs', () => {
- createComponent({ designs: mockDesigns, allVersions: [mockVersion] });
+ createComponent({ allVersions: [mockVersion] });
expect(findToolbar().exists()).toBe(true);
});
it('renders designs list and header with upload button', () => {
- createComponent({ designs: mockDesigns, allVersions: [mockVersion] });
+ createComponent({ allVersions: [mockVersion] });
expect(wrapper.element).toMatchSnapshot();
});
@@ -236,7 +243,7 @@ describe('Design management index page', () => {
describe('when has no designs', () => {
beforeEach(() => {
- createComponent();
+ createComponent({ designCollection: { designs: [], copyState: 'READY' } });
});
it('renders design dropzone', () =>
@@ -259,6 +266,21 @@ describe('Design management index page', () => {
}));
});
+ describe('handling design collection copy state', () => {
+ it.each`
+ copyState | isRendered | description
+ ${'IN_PROGRESS'} | ${true} | ${'renders'}
+ ${'READY'} | ${false} | ${'does not render'}
+ ${'ERROR'} | ${false} | ${'does not render'}
+ `(
+ '$description the copying message if design collection copyState is $copyState',
+ ({ copyState, isRendered }) => {
+ createComponent({ designCollection: { designs: [], copyState } });
+ expect(findDesignCollectionIsCopying().exists()).toBe(isRendered);
+ },
+ );
+ });
+
describe('uploading designs', () => {
it('calls mutation on upload', () => {
createComponent({ stubs: { GlEmptyState } });
@@ -282,6 +304,10 @@ describe('Design management index page', () => {
{
__typename: 'Design',
id: expect.anything(),
+ currentUserTodos: {
+ __typename: 'TodoConnection',
+ nodes: [],
+ },
image: '',
imageV432x230: '',
filename: 'test',
@@ -348,7 +374,7 @@ describe('Design management index page', () => {
createComponent({ stubs: { GlEmptyState } });
wrapper.setData({ filesToBeSaved: [{ name: 'test' }] });
- wrapper.vm.onUploadDesignDone();
+ wrapper.vm.onUploadDesignDone(designUploadMutationCreatedResponse);
return wrapper.vm.$nextTick().then(() => {
expect(wrapper.vm.filesToBeSaved).toEqual([]);
expect(wrapper.vm.isSaving).toBeFalsy();
@@ -460,6 +486,34 @@ describe('Design management index page', () => {
expect(createFlash).toHaveBeenCalledWith(message);
});
});
+
+ describe('tracking', () => {
+ let trackingSpy;
+
+ beforeEach(() => {
+ trackingSpy = mockTracking('_category_', undefined, jest.spyOn);
+
+ createComponent({ stubs: { GlEmptyState } });
+ });
+
+ afterEach(() => {
+ unmockTracking();
+ });
+
+ it('tracks design creation', () => {
+ wrapper.vm.onUploadDesignDone(designUploadMutationCreatedResponse);
+
+ expect(trackingSpy).toHaveBeenCalledTimes(1);
+ expect(trackingSpy).toHaveBeenCalledWith(DESIGN_TRACKING_PAGE_NAME, 'create_design');
+ });
+
+ it('tracks design modification', () => {
+ wrapper.vm.onUploadDesignDone(designUploadMutationUpdatedResponse);
+
+ expect(trackingSpy).toHaveBeenCalledTimes(1);
+ expect(trackingSpy).toHaveBeenCalledWith(DESIGN_TRACKING_PAGE_NAME, 'update_design');
+ });
+ });
});
describe('on latest version when has designs', () => {
@@ -531,13 +585,16 @@ describe('Design management index page', () => {
});
it('on latest version when has no designs toolbar buttons are invisible', () => {
- createComponent({ designs: [], allVersions: [mockVersion] });
+ createComponent({
+ designCollection: { designs: [], copyState: 'READY' },
+ allVersions: [mockVersion],
+ });
expect(findToolbar().isVisible()).toBe(false);
});
describe('on non-latest version', () => {
beforeEach(() => {
- createComponent({ designs: mockDesigns, allVersions: [mockVersion] });
+ createComponent({ allVersions: [mockVersion] });
});
it('does not render design checkboxes', async () => {
@@ -626,9 +683,8 @@ describe('Design management index page', () => {
describe('when navigating', () => {
it('ensures fullscreen layout is not applied', () => {
- createComponent(true);
+ createComponent({ loading: true });
- wrapper.vm.$router.push('/');
expect(mockPageEl.classList.remove).toHaveBeenCalledTimes(1);
expect(mockPageEl.classList.remove).toHaveBeenCalledWith(...DESIGN_DETAIL_LAYOUT_CLASSLIST);
});
@@ -637,7 +693,7 @@ describe('Design management index page', () => {
router.replace({
path: '/designs',
});
- createComponent(true);
+ createComponent({ loading: true });
return wrapper.vm.$nextTick().then(() => {
expect(scrollIntoViewMock).toHaveBeenCalled();
@@ -676,6 +732,20 @@ describe('Design management index page', () => {
).toBe('2');
});
+ it('prevents reordering when reorderDesigns mutation is in progress', async () => {
+ createComponentWithApollo({});
+
+ await moveDesigns(wrapper);
+
+ expect(draggableAttributes().disabled).toBe(true);
+
+ await jest.runOnlyPendingTimers(); // kick off the mocked GQL stuff (promises)
+ await wrapper.vm.$nextTick(); // kick off the DOM update
+ await wrapper.vm.$nextTick(); // kick off the DOM update for finally block
+
+ expect(draggableAttributes().disabled).toBe(false);
+ });
+
it('displays flash if mutation had a recoverable error', async () => {
createComponentWithApollo({
moveHandler: jest.fn().mockResolvedValue(moveDesignMutationResponseWithErrors),
diff --git a/spec/frontend/design_management/router_spec.js b/spec/frontend/design_management/router_spec.js
index d4cb9f75a77..fac4f7d368d 100644
--- a/spec/frontend/design_management/router_spec.js
+++ b/spec/frontend/design_management/router_spec.js
@@ -25,7 +25,7 @@ function factory(routeArg) {
mocks: {
$apollo: {
queries: {
- designs: { loading: true },
+ designCollection: { loading: true },
design: { loading: true },
permissions: { loading: true },
},
diff --git a/spec/frontend/design_management/utils/design_management_utils_spec.js b/spec/frontend/design_management/utils/design_management_utils_spec.js
index 7e857d08d25..232cfa2f4ca 100644
--- a/spec/frontend/design_management/utils/design_management_utils_spec.js
+++ b/spec/frontend/design_management/utils/design_management_utils_spec.js
@@ -93,6 +93,10 @@ describe('optimistic responses', () => {
fullPath: '',
notesCount: 0,
event: 'NONE',
+ currentUserTodos: {
+ __typename: 'TodoConnection',
+ nodes: [],
+ },
diffRefs: { __typename: 'DiffRefs', baseSha: '', startSha: '', headSha: '' },
discussions: { __typename: 'DesignDiscussion', nodes: [] },
versions: {
diff --git a/spec/frontend/diff_comments_store_spec.js b/spec/frontend/diff_comments_store_spec.js
deleted file mode 100644
index 6f25c9dd3bc..00000000000
--- a/spec/frontend/diff_comments_store_spec.js
+++ /dev/null
@@ -1,136 +0,0 @@
-/* global CommentsStore */
-
-import '~/diff_notes/models/discussion';
-import '~/diff_notes/models/note';
-import '~/diff_notes/stores/comments';
-
-function createDiscussion(noteId = 1, resolved = true) {
- CommentsStore.create({
- discussionId: 'a',
- noteId,
- canResolve: true,
- resolved,
- resolvedBy: 'test',
- authorName: 'test',
- authorAvatar: 'test',
- noteTruncated: 'test...',
- });
-}
-
-beforeEach(() => {
- CommentsStore.state = {};
-});
-
-describe('New discussion', () => {
- it('creates new discussion', () => {
- expect(Object.keys(CommentsStore.state).length).toBe(0);
- createDiscussion();
-
- expect(Object.keys(CommentsStore.state).length).toBe(1);
- });
-
- it('creates new note in discussion', () => {
- createDiscussion();
- createDiscussion(2);
-
- const discussion = CommentsStore.state.a;
-
- expect(Object.keys(discussion.notes).length).toBe(2);
- });
-});
-
-describe('Get note', () => {
- beforeEach(() => {
- createDiscussion();
- });
-
- it('gets note by ID', () => {
- const note = CommentsStore.get('a', 1);
-
- expect(note).toBeDefined();
- expect(note.id).toBe(1);
- });
-});
-
-describe('Delete discussion', () => {
- beforeEach(() => {
- createDiscussion();
- });
-
- it('deletes discussion by ID', () => {
- CommentsStore.delete('a', 1);
-
- expect(Object.keys(CommentsStore.state).length).toBe(0);
- });
-
- it('deletes discussion when no more notes', () => {
- createDiscussion();
- createDiscussion(2);
-
- expect(Object.keys(CommentsStore.state).length).toBe(1);
- expect(Object.keys(CommentsStore.state.a.notes).length).toBe(2);
-
- CommentsStore.delete('a', 1);
- CommentsStore.delete('a', 2);
-
- expect(Object.keys(CommentsStore.state).length).toBe(0);
- });
-});
-
-describe('Update note', () => {
- beforeEach(() => {
- createDiscussion();
- });
-
- it('updates note to be unresolved', () => {
- CommentsStore.update('a', 1, false, 'test');
-
- const note = CommentsStore.get('a', 1);
-
- expect(note.resolved).toBe(false);
- });
-});
-
-describe('Discussion resolved', () => {
- beforeEach(() => {
- createDiscussion();
- });
-
- it('is resolved with single note', () => {
- const discussion = CommentsStore.state.a;
-
- expect(discussion.isResolved()).toBe(true);
- });
-
- it('is unresolved with 2 notes', () => {
- const discussion = CommentsStore.state.a;
- createDiscussion(2, false);
-
- expect(discussion.isResolved()).toBe(false);
- });
-
- it('is resolved with 2 notes', () => {
- const discussion = CommentsStore.state.a;
- createDiscussion(2);
-
- expect(discussion.isResolved()).toBe(true);
- });
-
- it('resolve all notes', () => {
- const discussion = CommentsStore.state.a;
- createDiscussion(2, false);
-
- discussion.resolveAllNotes();
-
- expect(discussion.isResolved()).toBe(true);
- });
-
- it('unresolve all notes', () => {
- const discussion = CommentsStore.state.a;
- createDiscussion(2);
-
- discussion.unResolveAllNotes();
-
- expect(discussion.isResolved()).toBe(false);
- });
-});
diff --git a/spec/frontend/diffs/components/app_spec.js b/spec/frontend/diffs/components/app_spec.js
index cd3a6aa0e28..86560470ada 100644
--- a/spec/frontend/diffs/components/app_spec.js
+++ b/spec/frontend/diffs/components/app_spec.js
@@ -699,7 +699,7 @@ describe('diffs/components/app', () => {
describe('collapsed files', () => {
it('should render the collapsed files warning if there are any collapsed files', () => {
createComponent({}, ({ state }) => {
- state.diffs.diffFiles = [{ viewer: { collapsed: true } }];
+ state.diffs.diffFiles = [{ viewer: { automaticallyCollapsed: true } }];
});
expect(getCollapsedFilesWarning(wrapper).exists()).toBe(true);
@@ -707,7 +707,7 @@ describe('diffs/components/app', () => {
it('should not render the collapsed files warning if the user has dismissed the alert already', async () => {
createComponent({}, ({ state }) => {
- state.diffs.diffFiles = [{ viewer: { collapsed: true } }];
+ state.diffs.diffFiles = [{ viewer: { automaticallyCollapsed: true } }];
});
expect(getCollapsedFilesWarning(wrapper).exists()).toBe(true);
diff --git a/spec/frontend/diffs/components/collapsed_files_warning_spec.js b/spec/frontend/diffs/components/collapsed_files_warning_spec.js
index 670eab5472f..7bbffb7a1cd 100644
--- a/spec/frontend/diffs/components/collapsed_files_warning_spec.js
+++ b/spec/frontend/diffs/components/collapsed_files_warning_spec.js
@@ -50,7 +50,7 @@ describe('CollapsedFilesWarning', () => {
({ limited, containerClasses }) => {
createComponent({ limited });
- expect(wrapper.classes()).toEqual(containerClasses);
+ expect(wrapper.classes()).toEqual(['col-12'].concat(containerClasses));
},
);
diff --git a/spec/frontend/diffs/components/commit_item_spec.js b/spec/frontend/diffs/components/commit_item_spec.js
index c48445790f7..9e4fcddd1b4 100644
--- a/spec/frontend/diffs/components/commit_item_spec.js
+++ b/spec/frontend/diffs/components/commit_item_spec.js
@@ -25,7 +25,7 @@ describe('diffs/components/commit_item', () => {
const getTitleElement = () => wrapper.find('.commit-row-message.item-title');
const getDescElement = () => wrapper.find('pre.commit-row-description');
const getDescExpandElement = () => wrapper.find('.commit-content .js-toggle-button');
- const getShaElement = () => wrapper.find('.commit-sha-group');
+ const getShaElement = () => wrapper.find('[data-testid="commit-sha-group"]');
const getAvatarElement = () => wrapper.find('.user-avatar-link');
const getCommitterElement = () => wrapper.find('.committer');
const getCommitActionsElement = () => wrapper.find('.commit-actions');
@@ -84,8 +84,8 @@ describe('diffs/components/commit_item', () => {
it('renders commit sha', () => {
const shaElement = getShaElement();
- const labelElement = shaElement.find('.label');
- const buttonElement = shaElement.find('button');
+ const labelElement = shaElement.find('[data-testid="commit-sha-group"] button');
+ const buttonElement = shaElement.find('button.input-group-text');
expect(labelElement.text()).toEqual(commit.short_id);
expect(buttonElement.props('text')).toBe(commit.id);
diff --git a/spec/frontend/diffs/components/diff_file_header_spec.js b/spec/frontend/diffs/components/diff_file_header_spec.js
index a0cad32b9fb..a04486fc5c7 100644
--- a/spec/frontend/diffs/components/diff_file_header_spec.js
+++ b/spec/frontend/diffs/components/diff_file_header_spec.js
@@ -1,9 +1,7 @@
import { shallowMount, createLocalVue } from '@vue/test-utils';
import Vuex from 'vuex';
-import { GlIcon } from '@gitlab/ui';
import { cloneDeep } from 'lodash';
import DiffFileHeader from '~/diffs/components/diff_file_header.vue';
-import EditButton from '~/diffs/components/edit_button.vue';
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
import diffDiscussionsMockData from '../mock_data/diff_discussions';
import { truncateSha } from '~/lib/utils/text_utility';
@@ -22,7 +20,7 @@ const diffFile = Object.freeze(
name: 'base.js',
mode: '100644',
readable_text: true,
- icon: 'file-text-o',
+ icon: 'doc-text',
},
}),
);
@@ -76,15 +74,7 @@ describe('DiffFileHeader component', () => {
const findReplacedFileButton = () => wrapper.find({ ref: 'replacedFileButton' });
const findViewFileButton = () => wrapper.find({ ref: 'viewButton' });
const findCollapseIcon = () => wrapper.find({ ref: 'collapseIcon' });
-
- const findIconByName = iconName => {
- const icons = wrapper.findAll(GlIcon).filter(w => w.props('name') === iconName);
- if (icons.length === 0) return icons;
- if (icons.length > 1) {
- throw new Error(`Multiple icons found for ${iconName}`);
- }
- return icons.at(0);
- };
+ const findEditButton = () => wrapper.find({ ref: 'editButton' });
const createComponent = props => {
mockStoreConfig = cloneDeep(defaultMockStoreConfig);
@@ -203,16 +193,6 @@ describe('DiffFileHeader component', () => {
describe('for any file', () => {
const otherModes = Object.keys(diffViewerModes).filter(m => m !== 'mode_changed');
- it('when edit button emits showForkMessage event it is re-emitted', () => {
- createComponent({
- addMergeRequestButtons: true,
- });
- wrapper.find(EditButton).vm.$emit('showForkMessage');
- return wrapper.vm.$nextTick().then(() => {
- expect(wrapper.emitted().showForkMessage).toBeDefined();
- });
- });
-
it('for mode_changed file mode displays mode changes', () => {
createComponent({
diffFile: {
@@ -271,16 +251,16 @@ describe('DiffFileHeader component', () => {
});
it('should not render edit button', () => {
createComponent({ addMergeRequestButtons: false });
- expect(wrapper.find(EditButton).exists()).toBe(false);
+ expect(findEditButton().exists()).toBe(false);
});
});
describe('when addMergeRequestButtons is true', () => {
describe('without discussions', () => {
- it('renders a disabled toggle discussions button', () => {
+ it('does not render a toggle discussions button', () => {
diffHasDiscussionsResultMock.mockReturnValue(false);
createComponent({ addMergeRequestButtons: true });
- expect(findToggleDiscussionsButton().attributes('disabled')).toBe('true');
+ expect(findToggleDiscussionsButton().exists()).toBe(false);
});
});
@@ -288,7 +268,7 @@ describe('DiffFileHeader component', () => {
it('dispatches toggleFileDiscussionWrappers when user clicks on toggle discussions button', () => {
diffHasDiscussionsResultMock.mockReturnValue(true);
createComponent({ addMergeRequestButtons: true });
- expect(findToggleDiscussionsButton().attributes('disabled')).toBeFalsy();
+ expect(findToggleDiscussionsButton().exists()).toBe(true);
findToggleDiscussionsButton().vm.$emit('click');
expect(
mockStoreConfig.modules.diffs.actions.toggleFileDiscussionWrappers,
@@ -300,7 +280,7 @@ describe('DiffFileHeader component', () => {
createComponent({
addMergeRequestButtons: true,
});
- expect(wrapper.find(EditButton).exists()).toBe(true);
+ expect(findEditButton().exists()).toBe(true);
});
describe('view on environment button', () => {
@@ -334,7 +314,7 @@ describe('DiffFileHeader component', () => {
});
it('should not render edit button', () => {
- expect(wrapper.find(EditButton).exists()).toBe(false);
+ expect(findEditButton().exists()).toBe(false);
});
});
describe('with file blob', () => {
@@ -345,7 +325,7 @@ describe('DiffFileHeader component', () => {
addMergeRequestButtons: true,
});
expect(findViewFileButton().attributes('href')).toBe(viewPath);
- expect(findViewFileButton().attributes('title')).toEqual(
+ expect(findViewFileButton().text()).toEqual(
`View file @ ${diffFile.content_sha.substr(0, 8)}`,
);
});
@@ -375,21 +355,6 @@ describe('DiffFileHeader component', () => {
addMergeRequestButtons: true,
};
- it.each`
- iconName | isShowingFullFile
- ${'doc-expand'} | ${false}
- ${'doc-changes'} | ${true}
- `(
- 'shows $iconName when isShowingFullFile set to $isShowingFullFile',
- ({ iconName, isShowingFullFile }) => {
- createComponent({
- ...fullyNotExpandedFileProps,
- diffFile: { ...fullyNotExpandedFileProps.diffFile, isShowingFullFile },
- });
- expect(findIconByName(iconName).exists()).toBe(true);
- },
- );
-
it('renders expand to full file button if not showing full file already', () => {
createComponent(fullyNotExpandedFileProps);
expect(findExpandButton().exists()).toBe(true);
@@ -455,7 +420,7 @@ describe('DiffFileHeader component', () => {
it('does not show edit button', () => {
createComponent({ diffFile: { ...diffFile, deleted_file: true } });
- expect(wrapper.find(EditButton).exists()).toBe(false);
+ expect(findEditButton().exists()).toBe(false);
});
});
diff --git a/spec/frontend/diffs/components/diff_file_spec.js b/spec/frontend/diffs/components/diff_file_spec.js
index 4f1376e2c73..a6f0d2bf11d 100644
--- a/spec/frontend/diffs/components/diff_file_spec.js
+++ b/spec/frontend/diffs/components/diff_file_spec.js
@@ -37,7 +37,7 @@ describe('DiffFile', () => {
expect(el.querySelectorAll('.diff-content.hidden').length).toEqual(0);
expect(el.querySelector('.js-file-title')).toBeDefined();
- expect(el.querySelector('.btn-clipboard')).toBeDefined();
+ expect(el.querySelector('[data-testid="diff-file-copy-clipboard"]')).toBeDefined();
expect(el.querySelector('.file-title-name').innerText.indexOf(file_path)).toBeGreaterThan(-1);
expect(el.querySelector('.js-syntax-highlight')).toBeDefined();
@@ -47,7 +47,7 @@ describe('DiffFile', () => {
.then(() => {
expect(el.querySelectorAll('.line_content').length).toBe(8);
expect(el.querySelectorAll('.js-line-expansion-content').length).toBe(1);
- triggerEvent('.btn-clipboard');
+ triggerEvent('[data-testid="diff-file-copy-clipboard"]');
})
.then(done)
.catch(done.fail);
@@ -56,11 +56,11 @@ describe('DiffFile', () => {
it('should track a click event on copy to clip board button', done => {
const el = vm.$el;
- expect(el.querySelector('.btn-clipboard')).toBeDefined();
+ expect(el.querySelector('[data-testid="diff-file-copy-clipboard"]')).toBeDefined();
vm.file.renderIt = true;
vm.$nextTick()
.then(() => {
- triggerEvent('.btn-clipboard');
+ triggerEvent('[data-testid="diff-file-copy-clipboard"]');
expect(trackingSpy).toHaveBeenCalledWith('_category_', 'click_copy_file_button', {
label: 'diff_copy_file_path_button',
@@ -181,7 +181,7 @@ describe('DiffFile', () => {
});
it('updates local state when changing file state', done => {
- vm.file.viewer.collapsed = true;
+ vm.file.viewer.automaticallyCollapsed = true;
vm.$nextTick(() => {
expect(vm.isCollapsed).toBe(true);
diff --git a/spec/frontend/diffs/components/diff_row_utils_spec.js b/spec/frontend/diffs/components/diff_row_utils_spec.js
new file mode 100644
index 00000000000..394b6cb1914
--- /dev/null
+++ b/spec/frontend/diffs/components/diff_row_utils_spec.js
@@ -0,0 +1,203 @@
+import * as utils from '~/diffs/components/diff_row_utils';
+import {
+ MATCH_LINE_TYPE,
+ CONTEXT_LINE_TYPE,
+ OLD_NO_NEW_LINE_TYPE,
+ NEW_NO_NEW_LINE_TYPE,
+ EMPTY_CELL_TYPE,
+} from '~/diffs/constants';
+
+const LINE_CODE = 'abc123';
+
+describe('isHighlighted', () => {
+ it('should return true if line is highlighted', () => {
+ const state = { diffs: { highlightedRow: LINE_CODE } };
+ const line = { line_code: LINE_CODE };
+ const isCommented = false;
+ expect(utils.isHighlighted(state, line, isCommented)).toBe(true);
+ });
+
+ it('should return false if line is not highlighted', () => {
+ const state = { diffs: { highlightedRow: 'xxx' } };
+ const line = { line_code: LINE_CODE };
+ const isCommented = false;
+ expect(utils.isHighlighted(state, line, isCommented)).toBe(false);
+ });
+
+ it('should return true if isCommented is true', () => {
+ const state = { diffs: { highlightedRow: 'xxx' } };
+ const line = { line_code: LINE_CODE };
+ const isCommented = true;
+ expect(utils.isHighlighted(state, line, isCommented)).toBe(true);
+ });
+});
+
+describe('isContextLine', () => {
+ it('return true if line type is context', () => {
+ expect(utils.isContextLine(CONTEXT_LINE_TYPE)).toBe(true);
+ });
+
+ it('return false if line type is not context', () => {
+ expect(utils.isContextLine('xxx')).toBe(false);
+ });
+});
+
+describe('isMatchLine', () => {
+ it('return true if line type is match', () => {
+ expect(utils.isMatchLine(MATCH_LINE_TYPE)).toBe(true);
+ });
+
+ it('return false if line type is not match', () => {
+ expect(utils.isMatchLine('xxx')).toBe(false);
+ });
+});
+
+describe('isMetaLine', () => {
+ it.each`
+ type | expectation
+ ${OLD_NO_NEW_LINE_TYPE} | ${true}
+ ${NEW_NO_NEW_LINE_TYPE} | ${true}
+ ${EMPTY_CELL_TYPE} | ${true}
+ ${'xxx'} | ${false}
+ `('should return $expectation if type is $type', ({ type, expectation }) => {
+ expect(utils.isMetaLine(type)).toBe(expectation);
+ });
+});
+
+describe('shouldRenderCommentButton', () => {
+ it('should return false if comment button is not rendered', () => {
+ expect(utils.shouldRenderCommentButton(true, false)).toBe(false);
+ });
+
+ it('should return false if not logged in', () => {
+ expect(utils.shouldRenderCommentButton(false, true)).toBe(false);
+ });
+
+ it('should return true logged in and rendered', () => {
+ expect(utils.shouldRenderCommentButton(true, true)).toBe(true);
+ });
+});
+
+describe('hasDiscussions', () => {
+ it('should return false if line is undefined', () => {
+ expect(utils.hasDiscussions()).toBe(false);
+ });
+
+ it('should return false if discussions is undefined', () => {
+ expect(utils.hasDiscussions({})).toBe(false);
+ });
+
+ it('should return false if discussions has legnth of 0', () => {
+ expect(utils.hasDiscussions({ discussions: [] })).toBe(false);
+ });
+
+ it('should return true if discussions has legnth > 0', () => {
+ expect(utils.hasDiscussions({ discussions: [1] })).toBe(true);
+ });
+});
+
+describe('lineHref', () => {
+ it(`should return #${LINE_CODE}`, () => {
+ expect(utils.lineHref({ line_code: LINE_CODE })).toEqual(`#${LINE_CODE}`);
+ });
+
+ it(`should return '#' if line is undefined`, () => {
+ expect(utils.lineHref()).toEqual('#');
+ });
+
+ it(`should return '#' if line_code is undefined`, () => {
+ expect(utils.lineHref({})).toEqual('#');
+ });
+});
+
+describe('lineCode', () => {
+ it(`should return undefined if line_code is undefined`, () => {
+ expect(utils.lineCode()).toEqual(undefined);
+ expect(utils.lineCode({ left: {} })).toEqual(undefined);
+ expect(utils.lineCode({ right: {} })).toEqual(undefined);
+ });
+
+ it(`should return ${LINE_CODE}`, () => {
+ expect(utils.lineCode({ line_code: LINE_CODE })).toEqual(LINE_CODE);
+ expect(utils.lineCode({ left: { line_code: LINE_CODE } })).toEqual(LINE_CODE);
+ expect(utils.lineCode({ right: { line_code: LINE_CODE } })).toEqual(LINE_CODE);
+ });
+});
+
+describe('classNameMapCell', () => {
+ it.each`
+ line | hll | loggedIn | hovered | expectation
+ ${undefined} | ${true} | ${true} | ${true} | ${[]}
+ ${{ type: 'new' }} | ${false} | ${false} | ${false} | ${['new', { hll: false, 'is-over': false }]}
+ ${{ type: 'new' }} | ${true} | ${true} | ${false} | ${['new', { hll: true, 'is-over': false }]}
+ ${{ type: 'new' }} | ${true} | ${false} | ${true} | ${['new', { hll: true, 'is-over': false }]}
+ ${{ type: 'new' }} | ${true} | ${true} | ${true} | ${['new', { hll: true, 'is-over': true }]}
+ `('should return $expectation', ({ line, hll, loggedIn, hovered, expectation }) => {
+ const classes = utils.classNameMapCell(line, hll, loggedIn, hovered);
+ expect(classes).toEqual(expectation);
+ });
+});
+
+describe('addCommentTooltip', () => {
+ const brokenSymLinkTooltip =
+ 'Commenting on symbolic links that replace or are replaced by files is currently not supported.';
+ const brokenRealTooltip =
+ 'Commenting on files that replace or are replaced by symbolic links is currently not supported.';
+ it('should return default tooltip', () => {
+ expect(utils.addCommentTooltip()).toBeUndefined();
+ });
+
+ it('should return broken symlink tooltip', () => {
+ expect(utils.addCommentTooltip({ commentsDisabled: { wasSymbolic: true } })).toEqual(
+ brokenSymLinkTooltip,
+ );
+ expect(utils.addCommentTooltip({ commentsDisabled: { isSymbolic: true } })).toEqual(
+ brokenSymLinkTooltip,
+ );
+ });
+
+ it('should return broken real tooltip', () => {
+ expect(utils.addCommentTooltip({ commentsDisabled: { wasReal: true } })).toEqual(
+ brokenRealTooltip,
+ );
+ expect(utils.addCommentTooltip({ commentsDisabled: { isReal: true } })).toEqual(
+ brokenRealTooltip,
+ );
+ });
+});
+
+describe('parallelViewLeftLineType', () => {
+ it(`should return ${OLD_NO_NEW_LINE_TYPE}`, () => {
+ expect(utils.parallelViewLeftLineType({ right: { type: NEW_NO_NEW_LINE_TYPE } })).toEqual(
+ OLD_NO_NEW_LINE_TYPE,
+ );
+ });
+
+ it(`should return 'new'`, () => {
+ expect(utils.parallelViewLeftLineType({ left: { type: 'new' } })).toContain('new');
+ });
+
+ it(`should return ${EMPTY_CELL_TYPE}`, () => {
+ expect(utils.parallelViewLeftLineType({})).toContain(EMPTY_CELL_TYPE);
+ });
+
+ it(`should return hll:true`, () => {
+ expect(utils.parallelViewLeftLineType({}, true)[1]).toEqual({ hll: true });
+ });
+});
+
+describe('shouldShowCommentButton', () => {
+ it.each`
+ hover | context | meta | discussions | expectation
+ ${true} | ${false} | ${false} | ${false} | ${true}
+ ${false} | ${false} | ${false} | ${false} | ${false}
+ ${true} | ${true} | ${false} | ${false} | ${false}
+ ${true} | ${true} | ${true} | ${false} | ${false}
+ ${true} | ${true} | ${true} | ${true} | ${false}
+ `(
+ 'should return $expectation when hover is $hover',
+ ({ hover, context, meta, discussions, expectation }) => {
+ expect(utils.shouldShowCommentButton(hover, context, meta, discussions)).toBe(expectation);
+ },
+ );
+});
diff --git a/spec/frontend/diffs/components/diff_table_cell_spec.js b/spec/frontend/diffs/components/diff_table_cell_spec.js
deleted file mode 100644
index 02f5c27eecb..00000000000
--- a/spec/frontend/diffs/components/diff_table_cell_spec.js
+++ /dev/null
@@ -1,279 +0,0 @@
-import { createLocalVue, shallowMount } from '@vue/test-utils';
-import Vuex from 'vuex';
-import { TEST_HOST } from 'helpers/test_constants';
-import DiffTableCell from '~/diffs/components/diff_table_cell.vue';
-import DiffGutterAvatars from '~/diffs/components/diff_gutter_avatars.vue';
-import { LINE_POSITION_RIGHT } from '~/diffs/constants';
-import { createStore } from '~/mr_notes/stores';
-import discussionsMockData from '../mock_data/diff_discussions';
-import diffFileMockData from '../mock_data/diff_file';
-
-const localVue = createLocalVue();
-localVue.use(Vuex);
-
-const TEST_USER_ID = 'abc123';
-const TEST_USER = { id: TEST_USER_ID };
-const TEST_LINE_NUMBER = 1;
-const TEST_LINE_CODE = 'LC_42';
-const TEST_FILE_HASH = diffFileMockData.file_hash;
-
-describe('DiffTableCell', () => {
- const symlinkishFileTooltip =
- 'Commenting on symbolic links that replace or are replaced by files is currently not supported.';
- const realishFileTooltip =
- 'Commenting on files that replace or are replaced by symbolic links is currently not supported.';
- const otherFileTooltip = 'Add a comment to this line';
-
- let wrapper;
- let line;
- let store;
-
- beforeEach(() => {
- store = createStore();
- store.state.notes.userData = TEST_USER;
-
- line = {
- line_code: TEST_LINE_CODE,
- type: 'new',
- old_line: null,
- new_line: 1,
- discussions: [{ ...discussionsMockData }],
- discussionsExpanded: true,
- 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,
- };
- });
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- const setWindowLocation = value => {
- Object.defineProperty(window, 'location', {
- writable: true,
- value,
- });
- };
-
- const createComponent = (props = {}) => {
- wrapper = shallowMount(DiffTableCell, {
- localVue,
- store,
- propsData: {
- line,
- fileHash: TEST_FILE_HASH,
- contextLinesPath: '/context/lines/path',
- isHighlighted: false,
- ...props,
- },
- });
- };
-
- const findTd = () => wrapper.find({ ref: 'td' });
- const findNoteButton = () => wrapper.find({ ref: 'addDiffNoteButton' });
- const findLineNumber = () => wrapper.find({ ref: 'lineNumberRef' });
- const findTooltip = () => wrapper.find({ ref: 'addNoteTooltip' });
- const findAvatars = () => wrapper.find(DiffGutterAvatars);
-
- describe('td', () => {
- it('highlights when isHighlighted true', () => {
- createComponent({ isHighlighted: true });
-
- expect(findTd().classes()).toContain('hll');
- });
-
- it('does not highlight when isHighlighted false', () => {
- createComponent({ isHighlighted: false });
-
- expect(findTd().classes()).not.toContain('hll');
- });
- });
-
- describe('comment button', () => {
- it.each`
- showCommentButton | userData | query | mergeRefHeadComments | expectation
- ${true} | ${TEST_USER} | ${'diff_head=false'} | ${false} | ${true}
- ${true} | ${TEST_USER} | ${'diff_head=true'} | ${true} | ${true}
- ${true} | ${TEST_USER} | ${'diff_head=true'} | ${false} | ${false}
- ${false} | ${TEST_USER} | ${'diff_head=true'} | ${true} | ${false}
- ${false} | ${TEST_USER} | ${'bogus'} | ${true} | ${false}
- ${true} | ${null} | ${''} | ${true} | ${false}
- `(
- 'exists is $expectation - with showCommentButton ($showCommentButton) userData ($userData) query ($query)',
- ({ showCommentButton, userData, query, mergeRefHeadComments, expectation }) => {
- store.state.notes.userData = userData;
- gon.features = { mergeRefHeadComments };
- setWindowLocation({ href: `${TEST_HOST}?${query}` });
- createComponent({ showCommentButton });
-
- wrapper.setData({ isCommentButtonRendered: showCommentButton });
-
- return wrapper.vm.$nextTick().then(() => {
- expect(findNoteButton().exists()).toBe(expectation);
- });
- },
- );
-
- it.each`
- isHover | otherProps | discussions | expectation
- ${true} | ${{}} | ${[]} | ${true}
- ${false} | ${{}} | ${[]} | ${false}
- ${true} | ${{ line: { ...line, type: 'context' } }} | ${[]} | ${false}
- ${true} | ${{ line: { ...line, type: 'old-nonewline' } }} | ${[]} | ${false}
- ${true} | ${{}} | ${[{}]} | ${false}
- `(
- 'visible is $expectation - with isHover ($isHover), discussions ($discussions), otherProps ($otherProps)',
- ({ isHover, otherProps, discussions, expectation }) => {
- line.discussions = discussions;
- createComponent({
- showCommentButton: true,
- isHover,
- ...otherProps,
- });
-
- wrapper.setData({
- isCommentButtonRendered: true,
- });
-
- return wrapper.vm.$nextTick().then(() => {
- expect(findNoteButton().isVisible()).toBe(expectation);
- });
- },
- );
-
- it.each`
- disabled | commentsDisabled
- ${'disabled'} | ${true}
- ${undefined} | ${false}
- `(
- 'has attribute disabled=$disabled when the outer component has prop commentsDisabled=$commentsDisabled',
- ({ disabled, commentsDisabled }) => {
- line.commentsDisabled = commentsDisabled;
-
- createComponent({
- showCommentButton: true,
- isHover: true,
- });
-
- wrapper.setData({ isCommentButtonRendered: true });
-
- return wrapper.vm.$nextTick().then(() => {
- expect(findNoteButton().attributes('disabled')).toBe(disabled);
- });
- },
- );
-
- it.each`
- tooltip | commentsDisabled
- ${symlinkishFileTooltip} | ${{ wasSymbolic: true }}
- ${symlinkishFileTooltip} | ${{ isSymbolic: true }}
- ${realishFileTooltip} | ${{ wasReal: true }}
- ${realishFileTooltip} | ${{ isReal: true }}
- ${otherFileTooltip} | ${false}
- `(
- 'has the correct tooltip when commentsDisabled=$commentsDisabled',
- ({ tooltip, commentsDisabled }) => {
- line.commentsDisabled = commentsDisabled;
-
- createComponent({
- showCommentButton: true,
- isHover: true,
- });
-
- wrapper.setData({ isCommentButtonRendered: true });
-
- return wrapper.vm.$nextTick().then(() => {
- expect(findTooltip().attributes('title')).toBe(tooltip);
- });
- },
- );
- });
-
- describe('line number', () => {
- describe('without lineNumber prop', () => {
- it('does not render', () => {
- createComponent({ lineType: 'old' });
-
- expect(findLineNumber().exists()).toBe(false);
- });
- });
-
- describe('with lineNumber prop', () => {
- describe.each`
- lineProps | expectedHref | expectedClickArg
- ${{ line_code: TEST_LINE_CODE }} | ${`#${TEST_LINE_CODE}`} | ${TEST_LINE_CODE}
- ${{ line_code: undefined }} | ${'#'} | ${undefined}
- ${{ line_code: undefined, left: { line_code: TEST_LINE_CODE } }} | ${'#'} | ${TEST_LINE_CODE}
- ${{ line_code: undefined, right: { line_code: TEST_LINE_CODE } }} | ${'#'} | ${TEST_LINE_CODE}
- `('with line ($lineProps)', ({ lineProps, expectedHref, expectedClickArg }) => {
- beforeEach(() => {
- jest.spyOn(store, 'dispatch').mockImplementation();
- Object.assign(line, lineProps);
- createComponent({ lineNumber: TEST_LINE_NUMBER });
- });
-
- it('renders', () => {
- expect(findLineNumber().exists()).toBe(true);
- expect(findLineNumber().attributes()).toEqual({
- href: expectedHref,
- 'data-linenumber': TEST_LINE_NUMBER.toString(),
- });
- });
-
- it('on click, dispatches setHighlightedRow', () => {
- expect(store.dispatch).not.toHaveBeenCalled();
-
- findLineNumber().trigger('click');
-
- expect(store.dispatch).toHaveBeenCalledWith('diffs/setHighlightedRow', expectedClickArg);
- });
- });
- });
- });
-
- describe('diff-gutter-avatars', () => {
- describe('with showCommentButton', () => {
- beforeEach(() => {
- jest.spyOn(store, 'dispatch').mockImplementation();
-
- createComponent({ showCommentButton: true });
- });
-
- it('renders', () => {
- expect(findAvatars().props()).toEqual({
- discussions: line.discussions,
- discussionsExpanded: line.discussionsExpanded,
- });
- });
-
- it('toggles line discussion', () => {
- expect(store.dispatch).not.toHaveBeenCalled();
-
- findAvatars().vm.$emit('toggleLineDiscussions');
-
- expect(store.dispatch).toHaveBeenCalledWith('diffs/toggleLineDiscussions', {
- lineCode: TEST_LINE_CODE,
- fileHash: TEST_FILE_HASH,
- expanded: !line.discussionsExpanded,
- });
- });
- });
-
- it.each`
- props | lineProps | expectation
- ${{ showCommentButton: true }} | ${{}} | ${true}
- ${{ showCommentButton: false }} | ${{}} | ${false}
- ${{ showCommentButton: true, linePosition: LINE_POSITION_RIGHT }} | ${{ type: null }} | ${false}
- ${{ showCommentButton: true }} | ${{ discussions: [] }} | ${false}
- `(
- 'exists is $expectation - with props ($props), line ($lineProps)',
- ({ props, lineProps, expectation }) => {
- Object.assign(line, lineProps);
- createComponent(props);
-
- expect(findAvatars().exists()).toBe(expectation);
- },
- );
- });
-});
diff --git a/spec/frontend/diffs/components/edit_button_spec.js b/spec/frontend/diffs/components/edit_button_spec.js
deleted file mode 100644
index 71512c1c4af..00000000000
--- a/spec/frontend/diffs/components/edit_button_spec.js
+++ /dev/null
@@ -1,75 +0,0 @@
-import { shallowMount } from '@vue/test-utils';
-import { GlDeprecatedButton } from '@gitlab/ui';
-import EditButton from '~/diffs/components/edit_button.vue';
-
-const editPath = 'test-path';
-
-describe('EditButton', () => {
- let wrapper;
-
- const createComponent = (props = {}) => {
- wrapper = shallowMount(EditButton, {
- propsData: { ...props },
- });
- };
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- it('has correct href attribute', () => {
- createComponent({
- editPath,
- canCurrentUserFork: false,
- });
-
- expect(wrapper.find(GlDeprecatedButton).attributes('href')).toBe(editPath);
- });
-
- it('emits a show fork message event if current user can fork', () => {
- createComponent({
- editPath,
- canCurrentUserFork: true,
- });
- wrapper.find(GlDeprecatedButton).trigger('click');
-
- return wrapper.vm.$nextTick().then(() => {
- expect(wrapper.emitted('showForkMessage')).toBeTruthy();
- });
- });
-
- it('doesnt emit a show fork message event if current user cannot fork', () => {
- createComponent({
- editPath,
- canCurrentUserFork: false,
- });
- wrapper.find(GlDeprecatedButton).trigger('click');
-
- return wrapper.vm.$nextTick().then(() => {
- expect(wrapper.emitted('showForkMessage')).toBeFalsy();
- });
- });
-
- it('doesnt emit a show fork message event if current user can modify blob', () => {
- createComponent({
- editPath,
- canCurrentUserFork: true,
- canModifyBlob: true,
- });
- wrapper.find(GlDeprecatedButton).trigger('click');
-
- return wrapper.vm.$nextTick().then(() => {
- expect(wrapper.emitted('showForkMessage')).toBeFalsy();
- });
- });
-
- it('disables button if editPath is empty', () => {
- createComponent({
- editPath: '',
- canCurrentUserFork: true,
- canModifyBlob: true,
- });
-
- expect(wrapper.find(GlDeprecatedButton).attributes('disabled')).toBe('true');
- });
-});
diff --git a/spec/frontend/diffs/components/inline_diff_table_row_spec.js b/spec/frontend/diffs/components/inline_diff_table_row_spec.js
index 951b3f6258b..c65a39b9083 100644
--- a/spec/frontend/diffs/components/inline_diff_table_row_spec.js
+++ b/spec/frontend/diffs/components/inline_diff_table_row_spec.js
@@ -1,5 +1,4 @@
import { shallowMount } from '@vue/test-utils';
-import { TEST_HOST } from 'helpers/test_constants';
import { createStore } from '~/mr_notes/stores';
import InlineDiffTableRow from '~/diffs/components/inline_diff_table_row.vue';
import DiffGutterAvatars from '~/diffs/components/diff_gutter_avatars.vue';
@@ -28,13 +27,6 @@ describe('InlineDiffTableRow', () => {
});
};
- const setWindowLocation = value => {
- Object.defineProperty(window, 'location', {
- writable: true,
- value,
- });
- };
-
beforeEach(() => {
store = createStore();
store.state.notes.userData = TEST_USER;
@@ -122,22 +114,15 @@ describe('InlineDiffTableRow', () => {
const findNoteButton = () => wrapper.find({ ref: 'addDiffNoteButton' });
it.each`
- userData | query | mergeRefHeadComments | expectation
- ${TEST_USER} | ${'diff_head=false'} | ${false} | ${true}
- ${TEST_USER} | ${'diff_head=true'} | ${true} | ${true}
- ${TEST_USER} | ${'diff_head=true'} | ${false} | ${false}
- ${null} | ${''} | ${true} | ${false}
- `(
- 'exists is $expectation - with userData ($userData) query ($query)',
- ({ userData, query, mergeRefHeadComments, expectation }) => {
- store.state.notes.userData = userData;
- gon.features = { mergeRefHeadComments };
- setWindowLocation({ href: `${TEST_HOST}?${query}` });
- createComponent({}, store);
-
- expect(findNoteButton().exists()).toBe(expectation);
- },
- );
+ userData | expectation
+ ${TEST_USER} | ${true}
+ ${null} | ${false}
+ `('exists is $expectation - with userData ($userData)', ({ userData, expectation }) => {
+ store.state.notes.userData = userData;
+ createComponent({}, store);
+
+ expect(findNoteButton().exists()).toBe(expectation);
+ });
it.each`
isHover | line | expectation
diff --git a/spec/frontend/diffs/components/parallel_diff_table_row_spec.js b/spec/frontend/diffs/components/parallel_diff_table_row_spec.js
index 13c4ce06f18..13031bd8b66 100644
--- a/spec/frontend/diffs/components/parallel_diff_table_row_spec.js
+++ b/spec/frontend/diffs/components/parallel_diff_table_row_spec.js
@@ -1,7 +1,6 @@
import Vue from 'vue';
import { shallowMount } from '@vue/test-utils';
import { createComponentWithStore } from 'helpers/vue_mount_component_helper';
-import { TEST_HOST } from 'helpers/test_constants';
import { createStore } from '~/mr_notes/stores';
import ParallelDiffTableRow from '~/diffs/components/parallel_diff_table_row.vue';
import diffFileMockData from '../mock_data/diff_file';
@@ -186,13 +185,6 @@ describe('ParallelDiffTableRow', () => {
});
};
- const setWindowLocation = value => {
- Object.defineProperty(window, 'location', {
- writable: true,
- value,
- });
- };
-
beforeEach(() => {
// eslint-disable-next-line prefer-destructuring
thisLine = diffFileMockData.parallel_diff_lines[2];
@@ -228,19 +220,15 @@ describe('ParallelDiffTableRow', () => {
const findNoteButton = () => wrapper.find({ ref: 'addDiffNoteButtonLeft' });
it.each`
- hover | line | userData | query | mergeRefHeadComments | expectation
- ${true} | ${{}} | ${TEST_USER} | ${'diff_head=false'} | ${false} | ${true}
- ${true} | ${{ line: { left: null } }} | ${TEST_USER} | ${'diff_head=false'} | ${false} | ${false}
- ${true} | ${{}} | ${TEST_USER} | ${'diff_head=true'} | ${true} | ${true}
- ${true} | ${{}} | ${TEST_USER} | ${'diff_head=true'} | ${false} | ${false}
- ${true} | ${{}} | ${null} | ${''} | ${true} | ${false}
- ${false} | ${{}} | ${TEST_USER} | ${'diff_head=false'} | ${false} | ${false}
+ hover | line | userData | expectation
+ ${true} | ${{}} | ${TEST_USER} | ${true}
+ ${true} | ${{ line: { left: null } }} | ${TEST_USER} | ${false}
+ ${true} | ${{}} | ${null} | ${false}
+ ${false} | ${{}} | ${TEST_USER} | ${false}
`(
- 'exists is $expectation - with userData ($userData) query ($query)',
- async ({ hover, line, userData, query, mergeRefHeadComments, expectation }) => {
+ 'exists is $expectation - with userData ($userData)',
+ async ({ hover, line, userData, expectation }) => {
store.state.notes.userData = userData;
- gon.features = { mergeRefHeadComments };
- setWindowLocation({ href: `${TEST_HOST}?${query}` });
createComponent(line, store);
if (hover) await wrapper.find('.line_holder').trigger('mouseover');
diff --git a/spec/frontend/diffs/mock_data/diff_discussions.js b/spec/frontend/diffs/mock_data/diff_discussions.js
index 711ab543411..eff949bfb0d 100644
--- a/spec/frontend/diffs/mock_data/diff_discussions.js
+++ b/spec/frontend/diffs/mock_data/diff_discussions.js
@@ -260,11 +260,10 @@ export default {
name: 'CHANGELOG',
mode: '100644',
readable_text: true,
- icon: 'file-text-o',
+ icon: 'doc-text',
},
blob_path: 'CHANGELOG',
blob_name: 'CHANGELOG',
- blob_icon: '<i aria-hidden="true" data-hidden="true" class="fa fa-file-text-o fa-fw"></i>',
file_hash: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a',
file_path: 'CHANGELOG.rb',
new_file: false,
diff --git a/spec/frontend/diffs/mock_data/diff_file.js b/spec/frontend/diffs/mock_data/diff_file.js
index c2a4424ee95..d3886819a91 100644
--- a/spec/frontend/diffs/mock_data/diff_file.js
+++ b/spec/frontend/diffs/mock_data/diff_file.js
@@ -7,11 +7,10 @@ export default {
name: 'CHANGELOG',
mode: '100644',
readable_text: true,
- icon: 'file-text-o',
+ icon: 'doc-text',
},
blob_path: 'CHANGELOG',
blob_name: 'CHANGELOG',
- blob_icon: '<i aria-hidden="true" data-hidden="true" class="fa fa-file-text-o fa-fw"></i>',
file_hash: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a',
file_identifier_hash: '928f8286952bda02d674b692addcbe077084663a',
file_path: 'CHANGELOG',
@@ -27,7 +26,7 @@ export default {
viewer: {
name: 'text',
error: null,
- collapsed: false,
+ automaticallyCollapsed: false,
},
added_lines: 2,
removed_lines: 0,
diff --git a/spec/frontend/diffs/mock_data/diff_file_unreadable.js b/spec/frontend/diffs/mock_data/diff_file_unreadable.js
index 8c2df45988e..f6cdca9950a 100644
--- a/spec/frontend/diffs/mock_data/diff_file_unreadable.js
+++ b/spec/frontend/diffs/mock_data/diff_file_unreadable.js
@@ -7,11 +7,10 @@ export default {
name: 'CHANGELOG',
mode: '100644',
readable_text: false,
- icon: 'file-text-o',
+ icon: 'doc-text',
},
blob_path: 'CHANGELOG',
blob_name: 'CHANGELOG',
- blob_icon: '<i aria-hidden="true" data-hidden="true" class="fa fa-file-text-o fa-fw"></i>',
file_hash: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a',
file_path: 'CHANGELOG',
new_file: false,
@@ -26,7 +25,7 @@ export default {
viewer: {
name: 'text',
error: null,
- collapsed: false,
+ automaticallyCollapsed: false,
},
added_lines: 0,
removed_lines: 0,
diff --git a/spec/frontend/diffs/store/actions_spec.js b/spec/frontend/diffs/store/actions_spec.js
index 4f647b0cd41..c3e4ee9c531 100644
--- a/spec/frontend/diffs/store/actions_spec.js
+++ b/spec/frontend/diffs/store/actions_spec.js
@@ -483,14 +483,14 @@ describe('DiffsStoreActions', () => {
id: 1,
renderIt: false,
viewer: {
- collapsed: false,
+ automaticallyCollapsed: false,
},
},
{
id: 2,
renderIt: false,
viewer: {
- collapsed: false,
+ automaticallyCollapsed: false,
},
},
],
@@ -967,7 +967,7 @@ describe('DiffsStoreActions', () => {
{
file_hash: 'HASH',
viewer: {
- collapsed,
+ automaticallyCollapsed: collapsed,
},
renderIt,
},
@@ -1167,7 +1167,7 @@ describe('DiffsStoreActions', () => {
file_hash: 'testhash',
alternate_viewer: { name: updatedViewerName },
};
- const updatedViewer = { name: updatedViewerName, collapsed: false };
+ const updatedViewer = { name: updatedViewerName, automaticallyCollapsed: false };
const testData = [{ rich_text: 'test' }, { rich_text: 'file2' }];
let renamedFile;
let mock;
diff --git a/spec/frontend/diffs/store/getters_spec.js b/spec/frontend/diffs/store/getters_spec.js
index dac5be2d656..0083f1d8b44 100644
--- a/spec/frontend/diffs/store/getters_spec.js
+++ b/spec/frontend/diffs/store/getters_spec.js
@@ -51,13 +51,19 @@ describe('Diffs Module Getters', () => {
describe('hasCollapsedFile', () => {
it('returns true when all files are collapsed', () => {
- localState.diffFiles = [{ viewer: { collapsed: true } }, { viewer: { collapsed: true } }];
+ localState.diffFiles = [
+ { viewer: { automaticallyCollapsed: true } },
+ { viewer: { automaticallyCollapsed: true } },
+ ];
expect(getters.hasCollapsedFile(localState)).toEqual(true);
});
it('returns true when at least one file is collapsed', () => {
- localState.diffFiles = [{ viewer: { collapsed: false } }, { viewer: { collapsed: true } }];
+ localState.diffFiles = [
+ { viewer: { automaticallyCollapsed: false } },
+ { viewer: { automaticallyCollapsed: true } },
+ ];
expect(getters.hasCollapsedFile(localState)).toEqual(true);
});
@@ -139,50 +145,74 @@ describe('Diffs Module Getters', () => {
describe('diffHasExpandedDiscussions', () => {
it('returns true when one of the discussions is expanded', () => {
- discussionMock1.expanded = false;
+ const diffFile = {
+ parallel_diff_lines: [],
+ highlighted_diff_lines: [
+ {
+ discussions: [discussionMock, discussionMock],
+ discussionsExpanded: true,
+ },
+ ],
+ };
- expect(
- getters.diffHasExpandedDiscussions(localState, {
- getDiffFileDiscussions: () => [discussionMock, discussionMock],
- })(diffFileMock),
- ).toEqual(true);
+ expect(getters.diffHasExpandedDiscussions(localState)(diffFile)).toEqual(true);
});
it('returns false when there are no discussions', () => {
- expect(
- getters.diffHasExpandedDiscussions(localState, { getDiffFileDiscussions: () => [] })(
- diffFileMock,
- ),
- ).toEqual(false);
+ const diffFile = {
+ parallel_diff_lines: [],
+ highlighted_diff_lines: [
+ {
+ discussions: [],
+ discussionsExpanded: true,
+ },
+ ],
+ };
+ expect(getters.diffHasExpandedDiscussions(localState)(diffFile)).toEqual(false);
});
it('returns false when no discussion is expanded', () => {
- discussionMock.expanded = false;
- discussionMock1.expanded = false;
+ const diffFile = {
+ parallel_diff_lines: [],
+ highlighted_diff_lines: [
+ {
+ discussions: [discussionMock, discussionMock],
+ discussionsExpanded: false,
+ },
+ ],
+ };
- expect(
- getters.diffHasExpandedDiscussions(localState, {
- getDiffFileDiscussions: () => [discussionMock, discussionMock1],
- })(diffFileMock),
- ).toEqual(false);
+ expect(getters.diffHasExpandedDiscussions(localState)(diffFile)).toEqual(false);
});
});
describe('diffHasDiscussions', () => {
it('returns true when getDiffFileDiscussions returns discussions', () => {
- expect(
- getters.diffHasDiscussions(localState, {
- getDiffFileDiscussions: () => [discussionMock],
- })(diffFileMock),
- ).toEqual(true);
+ const diffFile = {
+ parallel_diff_lines: [],
+ highlighted_diff_lines: [
+ {
+ discussions: [discussionMock, discussionMock],
+ discussionsExpanded: false,
+ },
+ ],
+ };
+
+ expect(getters.diffHasDiscussions(localState)(diffFile)).toEqual(true);
});
it('returns false when getDiffFileDiscussions returns no discussions', () => {
- expect(
- getters.diffHasDiscussions(localState, {
- getDiffFileDiscussions: () => [],
- })(diffFileMock),
- ).toEqual(false);
+ const diffFile = {
+ parallel_diff_lines: [],
+ highlighted_diff_lines: [
+ {
+ discussions: [],
+ discussionsExpanded: false,
+ },
+ ],
+ };
+
+ expect(getters.diffHasDiscussions(localState)(diffFile)).toEqual(false);
});
});
diff --git a/spec/frontend/diffs/store/mutations_spec.js b/spec/frontend/diffs/store/mutations_spec.js
index e1d855ae0cf..a84ad63c695 100644
--- a/spec/frontend/diffs/store/mutations_spec.js
+++ b/spec/frontend/diffs/store/mutations_spec.js
@@ -130,14 +130,14 @@ describe('DiffsStoreMutations', () => {
it('should change the collapsed prop from diffFiles', () => {
const diffFile = {
viewer: {
- collapsed: true,
+ automaticallyCollapsed: true,
},
};
const state = { expandAllFiles: true, diffFiles: [diffFile] };
mutations[types.EXPAND_ALL_FILES](state);
- expect(state.diffFiles[0].viewer.collapsed).toEqual(false);
+ expect(state.diffFiles[0].viewer.automaticallyCollapsed).toEqual(false);
});
});
@@ -933,12 +933,12 @@ describe('DiffsStoreMutations', () => {
describe('SET_FILE_COLLAPSED', () => {
it('sets collapsed', () => {
const state = {
- diffFiles: [{ file_path: 'test', viewer: { collapsed: false } }],
+ diffFiles: [{ file_path: 'test', viewer: { automaticallyCollapsed: false } }],
};
mutations[types.SET_FILE_COLLAPSED](state, { filePath: 'test', collapsed: true });
- expect(state.diffFiles[0].viewer.collapsed).toBe(true);
+ expect(state.diffFiles[0].viewer.automaticallyCollapsed).toBe(true);
});
});
diff --git a/spec/frontend/editor/editor_lite_spec.js b/spec/frontend/editor/editor_lite_spec.js
index e566d3a4b38..bc17435c6d4 100644
--- a/spec/frontend/editor/editor_lite_spec.js
+++ b/spec/frontend/editor/editor_lite_spec.js
@@ -1,4 +1,5 @@
import { editor as monacoEditor, languages as monacoLanguages, Uri } from 'monaco-editor';
+import waitForPromises from 'helpers/wait_for_promises';
import Editor from '~/editor/editor_lite';
import { DEFAULT_THEME, themes } from '~/ide/lib/themes';
import { EDITOR_LITE_INSTANCE_ERROR_NO_EL, URI_PREFIX } from '~/editor/constants';
@@ -253,55 +254,125 @@ describe('Base editor', () => {
const MyExt3 = {
foo: foo2,
};
- beforeEach(() => {
- instance = editor.createInstance({ el: editorEl, blobPath, blobContent });
- });
- it('is extensible with the extensions', () => {
- expect(instance.foo).toBeUndefined();
+ describe('basic functionality', () => {
+ beforeEach(() => {
+ instance = editor.createInstance({ el: editorEl, blobPath, blobContent });
+ });
- editor.use(MyExt1);
- expect(instance.foo).toEqual(foo1);
- });
+ it('is extensible with the extensions', () => {
+ expect(instance.foo).toBeUndefined();
- it('does not fail if no extensions supplied', () => {
- const spy = jest.spyOn(global.console, 'error');
- editor.use();
+ instance.use(MyExt1);
+ expect(instance.foo).toEqual(foo1);
+ });
- expect(spy).not.toHaveBeenCalled();
- });
+ it('does not fail if no extensions supplied', () => {
+ const spy = jest.spyOn(global.console, 'error');
+ instance.use();
- it('is extensible with multiple extensions', () => {
- expect(instance.foo).toBeUndefined();
- expect(instance.bar).toBeUndefined();
+ expect(spy).not.toHaveBeenCalled();
+ });
- editor.use([MyExt1, MyExt2]);
+ it('is extensible with multiple extensions', () => {
+ expect(instance.foo).toBeUndefined();
+ expect(instance.bar).toBeUndefined();
- expect(instance.foo).toEqual(foo1);
- expect(instance.bar).toEqual(bar);
- });
+ instance.use([MyExt1, MyExt2]);
- it('uses the last definition of a method in case of an overlap', () => {
- editor.use([MyExt1, MyExt2, MyExt3]);
- expect(instance).toEqual(
- expect.objectContaining({
- foo: foo2,
- bar,
- }),
- );
+ expect(instance.foo).toEqual(foo1);
+ expect(instance.bar).toEqual(bar);
+ });
+
+ it('uses the last definition of a method in case of an overlap', () => {
+ instance.use([MyExt1, MyExt2, MyExt3]);
+ expect(instance).toEqual(
+ expect.objectContaining({
+ foo: foo2,
+ bar,
+ }),
+ );
+ });
+
+ it('correctly resolves references withing extensions', () => {
+ const FunctionExt = {
+ inst() {
+ return this;
+ },
+ mod() {
+ return this.getModel();
+ },
+ };
+ instance.use(FunctionExt);
+ expect(instance.inst()).toEqual(editor.instances[0]);
+ });
});
- it('correctly resolves references withing extensions', () => {
- const FunctionExt = {
- inst() {
- return this;
- },
- mod() {
- return this.getModel();
- },
+ describe('extensions as an instance parameter', () => {
+ let editorExtensionSpy;
+ const instanceConstructor = (extensions = []) => {
+ return editor.createInstance({
+ el: editorEl,
+ blobPath,
+ blobContent,
+ blobGlobalId,
+ extensions,
+ });
};
- editor.use(FunctionExt);
- expect(instance.inst()).toEqual(editor.instances[0]);
+
+ beforeEach(() => {
+ editorExtensionSpy = jest.spyOn(Editor, 'pushToImportsArray').mockImplementation(arr => {
+ arr.push(
+ Promise.resolve({
+ default: {},
+ }),
+ );
+ });
+ });
+
+ it.each([undefined, [], [''], ''])(
+ 'does not fail and makes no fetch if extensions is %s',
+ () => {
+ instance = instanceConstructor(null);
+ expect(editorExtensionSpy).not.toHaveBeenCalled();
+ },
+ );
+
+ it.each`
+ type | value | callsCount
+ ${'simple string'} | ${'foo'} | ${1}
+ ${'combined string'} | ${'foo, bar'} | ${2}
+ ${'array of strings'} | ${['foo', 'bar']} | ${2}
+ `('accepts $type as an extension parameter', ({ value, callsCount }) => {
+ instance = instanceConstructor(value);
+ expect(editorExtensionSpy).toHaveBeenCalled();
+ expect(editorExtensionSpy.mock.calls).toHaveLength(callsCount);
+ });
+
+ it.each`
+ desc | path | expectation
+ ${'~/editor'} | ${'foo'} | ${'~/editor/foo'}
+ ${'~/CUSTOM_PATH with leading slash'} | ${'/my_custom_path/bar'} | ${'~/my_custom_path/bar'}
+ ${'~/CUSTOM_PATH without leading slash'} | ${'my_custom_path/delta'} | ${'~/my_custom_path/delta'}
+ `('fetches extensions from $desc path', ({ path, expectation }) => {
+ instance = instanceConstructor(path);
+ expect(editorExtensionSpy).toHaveBeenCalledWith(expect.any(Array), expectation);
+ });
+
+ it('emits editor-ready event after all extensions were applied', async () => {
+ const calls = [];
+ const eventSpy = jest.fn().mockImplementation(() => {
+ calls.push('event');
+ });
+ const useSpy = jest.spyOn(editor, 'use').mockImplementation(() => {
+ calls.push('use');
+ });
+ editorEl.addEventListener('editor-ready', eventSpy);
+ instance = instanceConstructor('foo, bar');
+ await waitForPromises();
+ expect(useSpy.mock.calls).toHaveLength(2);
+ expect(calls).toEqual(['use', 'use', 'event']);
+ });
});
describe('multiple instances', () => {
diff --git a/spec/frontend/emoji/emoji_spec.js b/spec/frontend/emoji/emoji_spec.js
index 53c6d0835bc..f528313ef02 100644
--- a/spec/frontend/emoji/emoji_spec.js
+++ b/spec/frontend/emoji/emoji_spec.js
@@ -1,7 +1,6 @@
-import MockAdapter from 'axios-mock-adapter';
import { trimText } from 'helpers/text_helper';
-import axios from '~/lib/utils/axios_utils';
-import { initEmojiMap, glEmojiTag, EMOJI_VERSION } from '~/emoji';
+import { emojiFixtureMap, initEmojiMock, describeEmojiFields } from 'helpers/emoji';
+import { glEmojiTag, searchEmoji, getEmoji } from '~/emoji';
import isEmojiUnicodeSupported, {
isFlagEmoji,
isRainbowFlagEmoji,
@@ -30,37 +29,11 @@ const emptySupportMap = {
1.1: false,
};
-const emojiFixtureMap = {
- bomb: {
- name: 'bomb',
- moji: '💣',
- unicodeVersion: '6.0',
- },
- construction_worker_tone5: {
- name: 'construction_worker_tone5',
- moji: '👷ðŸ¿',
- unicodeVersion: '8.0',
- },
- five: {
- name: 'five',
- moji: '5ï¸âƒ£',
- unicodeVersion: '3.0',
- },
- grey_question: {
- name: 'grey_question',
- moji: 'â”',
- unicodeVersion: '6.0',
- },
-};
-
describe('gl_emoji', () => {
let mock;
- beforeEach(() => {
- mock = new MockAdapter(axios);
- mock.onGet(`/-/emojis/${EMOJI_VERSION}/emojis.json`).reply(200);
-
- return initEmojiMap().catch(() => {});
+ beforeEach(async () => {
+ mock = await initEmojiMock();
});
afterEach(() => {
@@ -378,4 +351,126 @@ describe('gl_emoji', () => {
expect(isSupported).toBeFalsy();
});
});
+
+ describe('getEmoji', () => {
+ const { grey_question } = emojiFixtureMap;
+
+ describe('when query is undefined', () => {
+ it('should return null by default', () => {
+ expect(getEmoji()).toBe(null);
+ });
+
+ it('should return fallback emoji when fallback is true', () => {
+ expect(getEmoji(undefined, true).name).toEqual(grey_question.name);
+ });
+ });
+ });
+
+ describe('searchEmoji', () => {
+ const { atom, grey_question } = emojiFixtureMap;
+ const search = (query, opts) => searchEmoji(query, opts).map(({ name }) => name);
+ const mangle = str => str.slice(0, 1) + str.slice(-1);
+ const partial = str => str.slice(0, 2);
+
+ describe('with default options', () => {
+ const subject = query => search(query);
+
+ describeEmojiFields('with $field', ({ accessor }) => {
+ it(`should match by lower case: ${accessor(atom)}`, () => {
+ expect(subject(accessor(atom))).toContain(atom.name);
+ });
+
+ it(`should match by upper case: ${accessor(atom).toUpperCase()}`, () => {
+ expect(subject(accessor(atom).toUpperCase())).toContain(atom.name);
+ });
+
+ it(`should not match by partial: ${mangle(accessor(atom))}`, () => {
+ expect(subject(mangle(accessor(atom)))).not.toContain(atom.name);
+ });
+ });
+
+ it(`should match by unicode value: ${atom.moji}`, () => {
+ expect(subject(atom.moji)).toContain(atom.name);
+ });
+
+ it('should not return a fallback value', () => {
+ expect(subject('foo bar baz')).toHaveLength(0);
+ });
+
+ it('should not return a fallback value when query is falsey', () => {
+ expect(subject()).toHaveLength(0);
+ });
+ });
+
+ describe('with fuzzy match', () => {
+ const subject = query => search(query, { match: 'fuzzy' });
+
+ describeEmojiFields('with $field', ({ accessor }) => {
+ it(`should match by lower case: ${accessor(atom)}`, () => {
+ expect(subject(accessor(atom))).toContain(atom.name);
+ });
+
+ it(`should match by upper case: ${accessor(atom).toUpperCase()}`, () => {
+ expect(subject(accessor(atom).toUpperCase())).toContain(atom.name);
+ });
+
+ it(`should match by partial: ${mangle(accessor(atom))}`, () => {
+ expect(subject(mangle(accessor(atom)))).toContain(atom.name);
+ });
+ });
+ });
+
+ describe('with contains match', () => {
+ const subject = query => search(query, { match: 'contains' });
+
+ describeEmojiFields('with $field', ({ accessor }) => {
+ it(`should match by lower case: ${accessor(atom)}`, () => {
+ expect(subject(accessor(atom))).toContain(atom.name);
+ });
+
+ it(`should match by upper case: ${accessor(atom).toUpperCase()}`, () => {
+ expect(subject(accessor(atom).toUpperCase())).toContain(atom.name);
+ });
+
+ it(`should match by partial: ${partial(accessor(atom))}`, () => {
+ expect(subject(partial(accessor(atom)))).toContain(atom.name);
+ });
+
+ it(`should not match by mangled: ${mangle(accessor(atom))}`, () => {
+ expect(subject(mangle(accessor(atom)))).not.toContain(atom.name);
+ });
+ });
+ });
+
+ describe('with fallback', () => {
+ const subject = query => search(query, { fallback: true });
+
+ it.each`
+ query
+ ${'foo bar baz'} | ${undefined}
+ `('should return a fallback value when given $query', ({ query }) => {
+ expect(subject(query)).toContain(grey_question.name);
+ });
+ });
+
+ describe('with name and alias fields', () => {
+ const subject = query => search(query, { fields: ['name', 'alias'] });
+
+ it(`should match by name: ${atom.name}`, () => {
+ expect(subject(atom.name)).toContain(atom.name);
+ });
+
+ it(`should match by alias: ${atom.aliases[0]}`, () => {
+ expect(subject(atom.aliases[0])).toContain(atom.name);
+ });
+
+ it(`should not match by description: ${atom.description}`, () => {
+ expect(subject(atom.description)).not.toContain(atom.name);
+ });
+
+ it(`should not match by unicode value: ${atom.moji}`, () => {
+ expect(subject(atom.moji)).not.toContain(atom.name);
+ });
+ });
+ });
});
diff --git a/spec/frontend/environment.js b/spec/frontend/environment.js
index 35ca323f5a9..733bf4378eb 100644
--- a/spec/frontend/environment.js
+++ b/spec/frontend/environment.js
@@ -1,8 +1,8 @@
-/* eslint-disable import/no-commonjs */
+/* eslint-disable import/no-commonjs, max-classes-per-file */
const path = require('path');
const { ErrorWithStack } = require('jest-util');
-const JSDOMEnvironment = require('jest-environment-jsdom-sixteen');
+const JSDOMEnvironment = require('jest-environment-jsdom');
const { TEST_HOST } = require('./helpers/test_constants');
const ROOT_PATH = path.resolve(__dirname, '../..');
@@ -58,6 +58,14 @@ class CustomEnvironment extends JSDOMEnvironment {
measure: () => null,
getEntriesByName: () => [],
});
+
+ this.global.PerformanceObserver = class {
+ /* eslint-disable no-useless-constructor, no-unused-vars, no-empty-function, class-methods-use-this */
+ constructor(callback) {}
+ disconnect() {}
+ observe(element, initObject) {}
+ /* eslint-enable no-useless-constructor, no-unused-vars, no-empty-function, class-methods-use-this */
+ };
}
async teardown() {
diff --git a/spec/frontend/environments/enable_review_app_button_spec.js b/spec/frontend/environments/enable_review_app_button_spec.js
deleted file mode 100644
index 5549a1737fc..00000000000
--- a/spec/frontend/environments/enable_review_app_button_spec.js
+++ /dev/null
@@ -1,31 +0,0 @@
-import { shallowMount, mount } from '@vue/test-utils';
-import ModalCopyButton from '~/vue_shared/components/modal_copy_button.vue';
-import EnableReviewAppButton from '~/environments/components/enable_review_app_button.vue';
-
-describe('Enable Review App Button', () => {
- let wrapper;
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- describe('renders button with text', () => {
- beforeEach(() => {
- wrapper = mount(EnableReviewAppButton);
- });
-
- it('renders Enable Review text', () => {
- expect(wrapper.text()).toBe('Enable review app');
- });
- });
-
- describe('renders the modal', () => {
- beforeEach(() => {
- wrapper = shallowMount(EnableReviewAppButton);
- });
-
- it('renders the copyToClipboard button', () => {
- expect(wrapper.find(ModalCopyButton).exists()).toBe(true);
- });
- });
-});
diff --git a/spec/frontend/environments/enable_review_app_modal_spec.js b/spec/frontend/environments/enable_review_app_modal_spec.js
new file mode 100644
index 00000000000..7ea49a6e1d0
--- /dev/null
+++ b/spec/frontend/environments/enable_review_app_modal_spec.js
@@ -0,0 +1,25 @@
+import { shallowMount } from '@vue/test-utils';
+import ModalCopyButton from '~/vue_shared/components/modal_copy_button.vue';
+import EnableReviewAppButton from '~/environments/components/enable_review_app_modal.vue';
+
+describe('Enable Review App Button', () => {
+ let wrapper;
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe('renders the modal', () => {
+ beforeEach(() => {
+ wrapper = shallowMount(EnableReviewAppButton, {
+ propsData: {
+ modalId: 'fake-id',
+ },
+ });
+ });
+
+ it('renders the copyToClipboard button', () => {
+ expect(wrapper.find(ModalCopyButton).exists()).toBe(true);
+ });
+ });
+});
diff --git a/spec/frontend/environments/environment_actions_spec.js b/spec/frontend/environments/environment_actions_spec.js
index ebdc4923045..d305f5e90bd 100644
--- a/spec/frontend/environments/environment_actions_spec.js
+++ b/spec/frontend/environments/environment_actions_spec.js
@@ -1,14 +1,22 @@
import { shallowMount } from '@vue/test-utils';
import { TEST_HOST } from 'helpers/test_constants';
import { GlLoadingIcon, GlIcon } from '@gitlab/ui';
+import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
import eventHub from '~/environments/event_hub';
import EnvironmentActions from '~/environments/components/environment_actions.vue';
describe('EnvironmentActions Component', () => {
let vm;
+ const findEnvironmentActionsButton = () => vm.find('[data-testid="environment-actions-button"]');
+
beforeEach(() => {
- vm = shallowMount(EnvironmentActions, { propsData: { actions: [] } });
+ vm = shallowMount(EnvironmentActions, {
+ propsData: { actions: [] },
+ directives: {
+ GlTooltip: createMockDirective(),
+ },
+ });
});
afterEach(() => {
@@ -23,6 +31,11 @@ describe('EnvironmentActions Component', () => {
expect(vm.find('.dropdown-new').attributes('aria-label')).toEqual('Deploy to...');
});
+ it('should render a tooltip', () => {
+ const tooltip = getBinding(findEnvironmentActionsButton().element, 'gl-tooltip');
+ expect(tooltip).toBeDefined();
+ });
+
describe('is loading', () => {
beforeEach(() => {
vm.setData({ isLoading: true });
diff --git a/spec/frontend/environments/environments_app_spec.js b/spec/frontend/environments/environments_app_spec.js
index fe32bf918dd..bb114e31063 100644
--- a/spec/frontend/environments/environments_app_spec.js
+++ b/spec/frontend/environments/environments_app_spec.js
@@ -1,9 +1,11 @@
import { mount, shallowMount } from '@vue/test-utils';
import MockAdapter from 'axios-mock-adapter';
-import axios from '~/lib/utils/axios_utils';
+import { extendedWrapper } from 'helpers/vue_test_utils_helper';
+import EnableReviewAppModal from '~/environments/components/enable_review_app_modal.vue';
import Container from '~/environments/components/container.vue';
import EmptyState from '~/environments/components/empty_state.vue';
import EnvironmentsApp from '~/environments/components/environments_app.vue';
+import axios from '~/lib/utils/axios_utils';
import { environment, folder } from './mock_data';
describe('Environment', () => {
@@ -34,12 +36,18 @@ describe('Environment', () => {
});
};
- const createWrapper = (shallow = false) => {
+ const createWrapper = (shallow = false, props = {}) => {
const fn = shallow ? shallowMount : mount;
- wrapper = fn(EnvironmentsApp, { propsData: mockData });
+ wrapper = extendedWrapper(fn(EnvironmentsApp, { propsData: { ...mockData, ...props } }));
return axios.waitForAll();
};
+ const findEnableReviewAppButton = () => wrapper.findByTestId('enable-review-app');
+ const findEnableReviewAppModal = () => wrapper.findAll(EnableReviewAppModal);
+ const findNewEnvironmentButton = () => wrapper.findByTestId('new-environment');
+ const findEnvironmentsTabAvailable = () => wrapper.find('.js-environments-tab-available > a');
+ const findEnvironmentsTabStopped = () => wrapper.find('.js-environments-tab-stopped > a');
+
beforeEach(() => {
mock = new MockAdapter(axios);
});
@@ -59,19 +67,6 @@ describe('Environment', () => {
it('should render the empty state', () => {
expect(wrapper.find(EmptyState).exists()).toBe(true);
});
-
- describe('when it is possible to enable a review app', () => {
- beforeEach(() => {
- mockRequest(200, { environments: [], review_app: { can_setup_review_app: true } });
- return createWrapper();
- });
-
- it('should render the enable review app button', () => {
- expect(wrapper.find('.js-enable-review-app-button').text()).toContain(
- 'Enable review app',
- );
- });
- });
});
describe('with paginated environments', () => {
@@ -86,7 +81,7 @@ describe('Environment', () => {
return createWrapper();
});
- it('should render a conatiner table with environments', () => {
+ it('should render a container table with environments', () => {
const containerTable = wrapper.find(Container);
expect(containerTable.exists()).toBe(true);
@@ -108,9 +103,16 @@ describe('Environment', () => {
it('should make an API request when using tabs', () => {
jest.spyOn(wrapper.vm, 'updateContent').mockImplementation(() => {});
- wrapper.find('.js-environments-tab-stopped').trigger('click');
+ findEnvironmentsTabStopped().trigger('click');
expect(wrapper.vm.updateContent).toHaveBeenCalledWith({ scope: 'stopped', page: '1' });
});
+
+ it('should not make the same API request when clicking on the current scope tab', () => {
+ // component starts at available
+ jest.spyOn(wrapper.vm, 'updateContent').mockImplementation(() => {});
+ findEnvironmentsTabAvailable().trigger('click');
+ expect(wrapper.vm.updateContent).toHaveBeenCalledTimes(0);
+ });
});
});
});
@@ -165,4 +167,65 @@ describe('Environment', () => {
expect(wrapper.find('.text-center > a.btn').text()).toContain('Show all');
});
});
+
+ describe('environment button', () => {
+ describe('when user can create environment', () => {
+ beforeEach(() => {
+ mockRequest(200, { environments: [] });
+ return createWrapper(true);
+ });
+
+ it('should render', () => {
+ expect(findNewEnvironmentButton().exists()).toBe(true);
+ });
+ });
+
+ describe('when user can not create environment', () => {
+ beforeEach(() => {
+ mockRequest(200, { environments: [] });
+ return createWrapper(true, { ...mockData, canCreateEnvironment: false });
+ });
+
+ it('should not render', () => {
+ expect(findNewEnvironmentButton().exists()).toBe(false);
+ });
+ });
+ });
+
+ describe('review app modal', () => {
+ describe('when it is not possible to enable a review app', () => {
+ beforeEach(() => {
+ mockRequest(200, { environments: [] });
+ return createWrapper(true);
+ });
+
+ it('should not render the enable review app button', () => {
+ expect(findEnableReviewAppButton().exists()).toBe(false);
+ });
+
+ it('should not render a review app modal', () => {
+ const modal = findEnableReviewAppModal();
+ expect(modal).toHaveLength(0);
+ expect(modal.exists()).toBe(false);
+ });
+ });
+
+ describe('when it is possible to enable a review app', () => {
+ beforeEach(() => {
+ mockRequest(200, { environments: [], review_app: { can_setup_review_app: true } });
+ return createWrapper(true);
+ });
+
+ it('should render the enable review app button', () => {
+ expect(findEnableReviewAppButton().exists()).toBe(true);
+ expect(findEnableReviewAppButton().text()).toContain('Enable review app');
+ });
+
+ it('should render only one review app modal', () => {
+ const modal = findEnableReviewAppModal();
+ expect(modal).toHaveLength(1);
+ expect(modal.at(0).exists()).toBe(true);
+ });
+ });
+ });
});
diff --git a/spec/frontend/environments/folder/environments_folder_view_spec.js b/spec/frontend/environments/folder/environments_folder_view_spec.js
index f33c8de0094..f55cb851dde 100644
--- a/spec/frontend/environments/folder/environments_folder_view_spec.js
+++ b/spec/frontend/environments/folder/environments_folder_view_spec.js
@@ -1,10 +1,10 @@
+import { GlPagination } from '@gitlab/ui';
import { mount } from '@vue/test-utils';
import MockAdapter from 'axios-mock-adapter';
import { removeBreakLine, removeWhitespace } from 'helpers/text_helper';
-import { GlPagination } from '@gitlab/ui';
-import axios from '~/lib/utils/axios_utils';
-import EnvironmentsFolderViewComponent from '~/environments/folder/environments_folder_view.vue';
import EnvironmentTable from '~/environments/components/environments_table.vue';
+import EnvironmentsFolderViewComponent from '~/environments/folder/environments_folder_view.vue';
+import axios from '~/lib/utils/axios_utils';
import { environmentsList } from '../mock_data';
describe('Environments Folder View', () => {
@@ -46,9 +46,10 @@ describe('Environments Folder View', () => {
wrapper = mount(EnvironmentsFolderViewComponent, { propsData: mockData });
};
- const findEnvironmentsTabAvailable = () => wrapper.find('.js-environments-tab-available');
+ const findEnvironmentsTabAvailable = () =>
+ wrapper.find('[data-testid="environments-tab-available"]');
- const findEnvironmentsTabStopped = () => wrapper.find('.js-environments-tab-stopped');
+ const findEnvironmentsTabStopped = () => wrapper.find('[data-testid="environments-tab-stopped"]');
beforeEach(() => {
mock = new MockAdapter(axios);
@@ -88,9 +89,9 @@ describe('Environments Folder View', () => {
});
it('should render parent folder name', () => {
- expect(removeBreakLine(removeWhitespace(wrapper.find('.js-folder-name').text()))).toContain(
- 'Environments / review',
- );
+ expect(
+ removeBreakLine(removeWhitespace(wrapper.find('[data-testid="folder-name"]').text())),
+ ).toContain('Environments / review');
});
describe('pagination', () => {
diff --git a/spec/frontend/error_tracking_settings/components/error_tracking_form_spec.js b/spec/frontend/error_tracking_settings/components/error_tracking_form_spec.js
index 21edcb7235a..f4a765a3d73 100644
--- a/spec/frontend/error_tracking_settings/components/error_tracking_form_spec.js
+++ b/spec/frontend/error_tracking_settings/components/error_tracking_form_spec.js
@@ -1,7 +1,6 @@
import Vuex from 'vuex';
import { createLocalVue, shallowMount } from '@vue/test-utils';
-import { GlFormInput } from '@gitlab/ui';
-import LoadingButton from '~/vue_shared/components/loading_button.vue';
+import { GlFormInput, GlButton } from '@gitlab/ui';
import ErrorTrackingForm from '~/error_tracking_settings/components/error_tracking_form.vue';
import createStore from '~/error_tracking_settings/store';
import { defaultProps } from '../mock';
@@ -43,7 +42,7 @@ describe('error tracking settings form', () => {
.attributes('id'),
).toBe('error-tracking-token');
- expect(wrapper.findAll(LoadingButton).exists()).toBe(true);
+ expect(wrapper.findAll(GlButton).exists()).toBe(true);
});
it('is rendered with labels and placeholders', () => {
@@ -72,9 +71,10 @@ describe('error tracking settings form', () => {
});
it('shows loading spinner', () => {
- const { label, loading } = wrapper.find(LoadingButton).props();
- expect(loading).toBe(true);
- expect(label).toBe('Connecting');
+ const buttonEl = wrapper.find(GlButton);
+
+ expect(buttonEl.props('loading')).toBe(true);
+ expect(buttonEl.text()).toBe('Connecting');
});
});
diff --git a/spec/frontend/feature_flags/components/configure_feature_flags_modal_spec.js b/spec/frontend/feature_flags/components/configure_feature_flags_modal_spec.js
new file mode 100644
index 00000000000..0e364c47f8d
--- /dev/null
+++ b/spec/frontend/feature_flags/components/configure_feature_flags_modal_spec.js
@@ -0,0 +1,159 @@
+import { shallowMount } from '@vue/test-utils';
+import { GlModal, GlSprintf } from '@gitlab/ui';
+import Component from '~/feature_flags/components/configure_feature_flags_modal.vue';
+import Callout from '~/vue_shared/components/callout.vue';
+
+describe('Configure Feature Flags Modal', () => {
+ const mockEvent = { preventDefault: jest.fn() };
+ const provide = {
+ projectName: 'fakeProjectName',
+ featureFlagsHelpPagePath: '/help/path',
+ featureFlagsClientLibrariesHelpPagePath: '/help/path/#flags',
+ featureFlagsClientExampleHelpPagePath: '/feature-flags#clientexample',
+ unleashApiUrl: '/api/url',
+ };
+
+ const propsData = {
+ instanceId: 'instance-id-token',
+ isRotating: false,
+ hasRotateError: false,
+ canUserRotateToken: true,
+ };
+
+ let wrapper;
+ const factory = (props = {}, { mountFn = shallowMount, ...options } = {}) => {
+ wrapper = mountFn(Component, {
+ provide,
+ stubs: { GlSprintf },
+ propsData: {
+ ...propsData,
+ ...props,
+ },
+ ...options,
+ });
+ };
+
+ const findGlModal = () => wrapper.find(GlModal);
+ const findPrimaryAction = () => findGlModal().props('actionPrimary');
+ const findProjectNameInput = () => wrapper.find('#project_name_verification');
+ const findDangerCallout = () =>
+ wrapper.findAll(Callout).filter(c => c.props('category') === 'danger');
+
+ describe('idle', () => {
+ afterEach(() => wrapper.destroy());
+ beforeEach(factory);
+
+ it('should have Primary and Cancel actions', () => {
+ expect(findGlModal().props('actionCancel').text).toBe('Close');
+ expect(findPrimaryAction().text).toBe('Regenerate instance ID');
+ });
+
+ it('should default disable the primary action', async () => {
+ const [{ disabled }] = findPrimaryAction().attributes;
+ expect(disabled).toBe(true);
+ });
+
+ it('should emit a `token` event when clicking on the Primary action', async () => {
+ findGlModal().vm.$emit('primary', mockEvent);
+ await wrapper.vm.$nextTick();
+ expect(wrapper.emitted('token')).toEqual([[]]);
+ expect(mockEvent.preventDefault).toHaveBeenCalled();
+ });
+
+ it('should clear the project name input after generating the token', async () => {
+ findProjectNameInput().vm.$emit('input', provide.projectName);
+ findGlModal().vm.$emit('primary', mockEvent);
+ await wrapper.vm.$nextTick();
+ expect(findProjectNameInput().attributes('value')).toBe('');
+ });
+
+ it('should provide an input for filling the project name', () => {
+ expect(findProjectNameInput().exists()).toBe(true);
+ expect(findProjectNameInput().attributes('value')).toBe('');
+ });
+
+ it('should display an help text', () => {
+ const help = wrapper.find('p');
+ expect(help.text()).toMatch(/More Information/);
+ });
+
+ it('should have links to the documentation', () => {
+ expect(wrapper.find('[data-testid="help-link"]').attributes('href')).toBe(
+ provide.featureFlagsHelpPagePath,
+ );
+ expect(wrapper.find('[data-testid="help-client-link"]').attributes('href')).toBe(
+ provide.featureFlagsClientLibrariesHelpPagePath,
+ );
+ });
+
+ it('should display one and only one danger callout', () => {
+ const dangerCallout = findDangerCallout();
+ expect(dangerCallout.length).toBe(1);
+ expect(dangerCallout.at(0).props('message')).toMatch(/Regenerating the instance ID/);
+ });
+
+ it('should display a message asking to fill the project name', () => {
+ expect(wrapper.find('[data-testid="prevent-accident-text"]').text()).toMatch(
+ provide.projectName,
+ );
+ });
+
+ it('should display the api URL in an input box', () => {
+ const input = wrapper.find('#api_url');
+ expect(input.element.value).toBe('/api/url');
+ });
+
+ it('should display the instance ID in an input box', () => {
+ const input = wrapper.find('#instance_id');
+ expect(input.element.value).toBe('instance-id-token');
+ });
+ });
+
+ describe('verified', () => {
+ afterEach(() => wrapper.destroy());
+ beforeEach(factory);
+
+ it('should enable the primary action', async () => {
+ findProjectNameInput().vm.$emit('input', provide.projectName);
+ await wrapper.vm.$nextTick();
+ const [{ disabled }] = findPrimaryAction().attributes;
+ expect(disabled).toBe(false);
+ });
+ });
+
+ describe('cannot rotate token', () => {
+ afterEach(() => wrapper.destroy());
+ beforeEach(factory.bind(null, { canUserRotateToken: false }));
+
+ it('should not display the primary action', async () => {
+ expect(findPrimaryAction()).toBe(null);
+ });
+
+ it('shold not display regenerating instance ID', async () => {
+ expect(findDangerCallout().exists()).toBe(false);
+ });
+
+ it('should disable the project name input', async () => {
+ expect(findProjectNameInput().exists()).toBe(false);
+ });
+ });
+
+ describe('has rotate error', () => {
+ afterEach(() => wrapper.destroy());
+ beforeEach(factory.bind(null, { hasRotateError: false }));
+
+ it('should display an error', async () => {
+ expect(wrapper.find('.text-danger')).toExist();
+ expect(wrapper.find('[name="warning"]')).toExist();
+ });
+ });
+
+ describe('is rotating', () => {
+ afterEach(() => wrapper.destroy());
+ beforeEach(factory.bind(null, { isRotating: true }));
+
+ it('should disable the project name input', async () => {
+ expect(findProjectNameInput().attributes('disabled')).toBeTruthy();
+ });
+ });
+});
diff --git a/spec/frontend/feature_flags/components/edit_feature_flag_spec.js b/spec/frontend/feature_flags/components/edit_feature_flag_spec.js
new file mode 100644
index 00000000000..6a394251060
--- /dev/null
+++ b/spec/frontend/feature_flags/components/edit_feature_flag_spec.js
@@ -0,0 +1,183 @@
+import Vuex from 'vuex';
+import { createLocalVue, shallowMount } from '@vue/test-utils';
+import MockAdapter from 'axios-mock-adapter';
+import { GlToggle, GlAlert } from '@gitlab/ui';
+import { TEST_HOST } from 'spec/test_constants';
+import { mockTracking } from 'helpers/tracking_helper';
+import { LEGACY_FLAG, NEW_VERSION_FLAG, NEW_FLAG_ALERT } from '~/feature_flags/constants';
+import Form from '~/feature_flags/components/form.vue';
+import createStore from '~/feature_flags/store/edit';
+import EditFeatureFlag from '~/feature_flags/components/edit_feature_flag.vue';
+import axios from '~/lib/utils/axios_utils';
+
+const localVue = createLocalVue();
+localVue.use(Vuex);
+
+const userCalloutId = 'feature_flags_new_version';
+const userCalloutsPath = `${TEST_HOST}/user_callouts`;
+
+describe('Edit feature flag form', () => {
+ let wrapper;
+ let mock;
+
+ const store = createStore({
+ path: '/feature_flags',
+ endpoint: `${TEST_HOST}/feature_flags.json`,
+ });
+
+ const factory = (opts = {}) => {
+ if (wrapper) {
+ wrapper.destroy();
+ wrapper = null;
+ }
+ wrapper = shallowMount(EditFeatureFlag, {
+ localVue,
+ store,
+ provide: {
+ showUserCallout: true,
+ userCalloutId,
+ userCalloutsPath,
+ glFeatures: {
+ featureFlagsNewVersion: true,
+ },
+ ...opts,
+ },
+ });
+ };
+
+ beforeEach(done => {
+ mock = new MockAdapter(axios);
+ mock.onGet(`${TEST_HOST}/feature_flags.json`).replyOnce(200, {
+ id: 21,
+ iid: 5,
+ active: true,
+ created_at: '2019-01-17T17:27:39.778Z',
+ updated_at: '2019-01-17T17:27:39.778Z',
+ name: 'feature_flag',
+ description: '',
+ version: LEGACY_FLAG,
+ edit_path: '/h5bp/html5-boilerplate/-/feature_flags/21/edit',
+ destroy_path: '/h5bp/html5-boilerplate/-/feature_flags/21',
+ scopes: [
+ {
+ id: 21,
+ active: false,
+ environment_scope: '*',
+ created_at: '2019-01-17T17:27:39.778Z',
+ updated_at: '2019-01-17T17:27:39.778Z',
+ },
+ ],
+ });
+ factory();
+ setImmediate(() => done());
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ mock.restore();
+ });
+
+ const findAlert = () => wrapper.find(GlAlert);
+
+ it('should display the iid', () => {
+ expect(wrapper.find('h3').text()).toContain('^5');
+ });
+
+ it('should render the toggle', () => {
+ expect(wrapper.find(GlToggle).exists()).toBe(true);
+ });
+
+ it('should set the value of the toggle to whether or not the flag is active', () => {
+ expect(wrapper.find(GlToggle).props('value')).toBe(true);
+ });
+
+ it('should not alert users that feature flags are changing soon', () => {
+ expect(findAlert().text()).toContain('GitLab is moving to a new way of managing feature flags');
+ });
+
+ describe('with error', () => {
+ it('should render the error', () => {
+ store.dispatch('receiveUpdateFeatureFlagError', { message: ['The name is required'] });
+ return wrapper.vm.$nextTick(() => {
+ expect(wrapper.find('.alert-danger').exists()).toEqual(true);
+ expect(wrapper.find('.alert-danger').text()).toContain('The name is required');
+ });
+ });
+ });
+
+ describe('without error', () => {
+ it('renders form title', () => {
+ expect(wrapper.text()).toContain('^5 feature_flag');
+ });
+
+ it('should render feature flag form', () => {
+ expect(wrapper.find(Form).exists()).toEqual(true);
+ });
+
+ it('should set the version of the form from the feature flag', () => {
+ expect(wrapper.find(Form).props('version')).toBe(LEGACY_FLAG);
+
+ mock.resetHandlers();
+
+ mock.onGet(`${TEST_HOST}/feature_flags.json`).replyOnce(200, {
+ id: 21,
+ iid: 5,
+ active: true,
+ created_at: '2019-01-17T17:27:39.778Z',
+ updated_at: '2019-01-17T17:27:39.778Z',
+ name: 'feature_flag',
+ description: '',
+ version: NEW_VERSION_FLAG,
+ edit_path: '/h5bp/html5-boilerplate/-/feature_flags/21/edit',
+ destroy_path: '/h5bp/html5-boilerplate/-/feature_flags/21',
+ strategies: [],
+ });
+
+ factory();
+
+ return axios.waitForAll().then(() => {
+ expect(wrapper.find(Form).props('version')).toBe(NEW_VERSION_FLAG);
+ });
+ });
+
+ it('should track when the toggle is clicked', () => {
+ const toggle = wrapper.find(GlToggle);
+ const spy = mockTracking('_category_', toggle.element, jest.spyOn);
+
+ toggle.trigger('click');
+
+ expect(spy).toHaveBeenCalledWith('_category_', 'click_button', {
+ label: 'feature_flag_toggle',
+ });
+ });
+ });
+
+ describe('without new version flags', () => {
+ beforeEach(() => factory({ glFeatures: { featureFlagsNewVersion: false } }));
+
+ it('should alert users that feature flags are changing soon', () => {
+ expect(findAlert().text()).toBe(NEW_FLAG_ALERT);
+ });
+ });
+
+ describe('dismissing new version alert', () => {
+ beforeEach(() => {
+ factory({ glFeatures: { featureFlagsNewVersion: false } });
+ mock.onPost(userCalloutsPath, { feature_name: userCalloutId }).reply(200);
+ findAlert().vm.$emit('dismiss');
+ return wrapper.vm.$nextTick();
+ });
+
+ afterEach(() => {
+ mock.restore();
+ });
+
+ it('should hide the alert', () => {
+ expect(findAlert().exists()).toBe(false);
+ });
+
+ it('should send the dismissal event', () => {
+ expect(mock.history.post.length).toBe(1);
+ });
+ });
+});
diff --git a/spec/frontend/feature_flags/components/environments_dropdown_spec.js b/spec/frontend/feature_flags/components/environments_dropdown_spec.js
new file mode 100644
index 00000000000..917f5f5ccd3
--- /dev/null
+++ b/spec/frontend/feature_flags/components/environments_dropdown_spec.js
@@ -0,0 +1,147 @@
+import MockAdapter from 'axios-mock-adapter';
+import { shallowMount } from '@vue/test-utils';
+import { GlLoadingIcon, GlDeprecatedButton, GlSearchBoxByType } from '@gitlab/ui';
+import { TEST_HOST } from 'spec/test_constants';
+import waitForPromises from 'helpers/wait_for_promises';
+import EnvironmentsDropdown from '~/feature_flags/components/environments_dropdown.vue';
+import axios from '~/lib/utils/axios_utils';
+import httpStatusCodes from '~/lib/utils/http_status';
+
+describe('Feature flags > Environments dropdown ', () => {
+ let wrapper;
+ let mock;
+ const results = ['production', 'staging'];
+ const factory = props => {
+ wrapper = shallowMount(EnvironmentsDropdown, {
+ propsData: {
+ ...props,
+ },
+ provide: {
+ environmentsEndpoint: `${TEST_HOST}/environments.json'`,
+ },
+ });
+ };
+
+ const findEnvironmentSearchInput = () => wrapper.find(GlSearchBoxByType);
+ const findDropdownMenu = () => wrapper.find('.dropdown-menu');
+
+ afterEach(() => {
+ wrapper.destroy();
+ mock.restore();
+ });
+
+ beforeEach(() => {
+ mock = new MockAdapter(axios);
+ });
+
+ describe('without value', () => {
+ it('renders the placeholder', () => {
+ factory();
+ expect(findEnvironmentSearchInput().vm.$attrs.placeholder).toBe('Search an environment spec');
+ });
+ });
+
+ describe('with value', () => {
+ it('sets filter to equal the value', () => {
+ factory({ value: 'production' });
+ expect(findEnvironmentSearchInput().props('value')).toBe('production');
+ });
+ });
+
+ describe('on focus', () => {
+ it('sets results with the received data', async () => {
+ mock.onGet(`${TEST_HOST}/environments.json'`).replyOnce(httpStatusCodes.OK, results);
+ factory();
+ findEnvironmentSearchInput().vm.$emit('focus');
+ await waitForPromises();
+ await wrapper.vm.$nextTick();
+ expect(wrapper.find('.dropdown-content > ul').exists()).toBe(true);
+ expect(wrapper.findAll('.dropdown-content > ul > li').exists()).toBe(true);
+ });
+ });
+
+ describe('on keyup', () => {
+ it('sets results with the received data', async () => {
+ mock.onGet(`${TEST_HOST}/environments.json'`).replyOnce(httpStatusCodes.OK, results);
+ factory();
+ findEnvironmentSearchInput().vm.$emit('keyup');
+ await waitForPromises();
+ await wrapper.vm.$nextTick();
+ expect(wrapper.find('.dropdown-content > ul').exists()).toBe(true);
+ expect(wrapper.findAll('.dropdown-content > ul > li').exists()).toBe(true);
+ });
+ });
+
+ describe('on input change', () => {
+ describe('on success', () => {
+ beforeEach(async () => {
+ mock.onGet(`${TEST_HOST}/environments.json'`).replyOnce(httpStatusCodes.OK, results);
+ factory();
+ findEnvironmentSearchInput().vm.$emit('focus');
+ findEnvironmentSearchInput().vm.$emit('input', 'production');
+ await waitForPromises();
+ await wrapper.vm.$nextTick();
+ });
+
+ it('sets filter value', () => {
+ expect(findEnvironmentSearchInput().props('value')).toBe('production');
+ });
+
+ describe('with received data', () => {
+ it('sets is loading to false', () => {
+ expect(wrapper.vm.isLoading).toBe(false);
+ expect(wrapper.find(GlLoadingIcon).exists()).toBe(false);
+ });
+
+ it('shows the suggestions', () => {
+ expect(findDropdownMenu().exists()).toBe(true);
+ });
+
+ it('emits event when a suggestion is clicked', async () => {
+ const button = wrapper
+ .findAll(GlDeprecatedButton)
+ .filter(b => b.text() === 'production')
+ .at(0);
+ button.vm.$emit('click');
+ await wrapper.vm.$nextTick();
+ expect(wrapper.emitted('selectEnvironment')).toEqual([['production']]);
+ });
+ });
+
+ describe('on click clear button', () => {
+ beforeEach(async () => {
+ wrapper.find(GlDeprecatedButton).vm.$emit('click');
+ await wrapper.vm.$nextTick();
+ });
+
+ it('resets filter value', () => {
+ expect(findEnvironmentSearchInput().props('value')).toBe('');
+ });
+
+ it('closes list of suggestions', () => {
+ expect(wrapper.vm.showSuggestions).toBe(false);
+ });
+ });
+ });
+ });
+
+ describe('on click create button', () => {
+ beforeEach(async () => {
+ mock.onGet(`${TEST_HOST}/environments.json'`).replyOnce(httpStatusCodes.OK, []);
+ factory();
+ findEnvironmentSearchInput().vm.$emit('focus');
+ findEnvironmentSearchInput().vm.$emit('input', 'production');
+ await waitForPromises();
+ await wrapper.vm.$nextTick();
+ });
+
+ it('emits create event', async () => {
+ wrapper
+ .findAll(GlDeprecatedButton)
+ .at(0)
+ .vm.$emit('click');
+ await wrapper.vm.$nextTick();
+ expect(wrapper.emitted('createClicked')).toEqual([['production']]);
+ });
+ });
+});
diff --git a/spec/frontend/feature_flags/components/feature_flags_spec.js b/spec/frontend/feature_flags/components/feature_flags_spec.js
new file mode 100644
index 00000000000..3c1234fea94
--- /dev/null
+++ b/spec/frontend/feature_flags/components/feature_flags_spec.js
@@ -0,0 +1,371 @@
+import { shallowMount, createLocalVue } from '@vue/test-utils';
+import Vuex from 'vuex';
+import MockAdapter from 'axios-mock-adapter';
+import { GlAlert, GlEmptyState, GlLoadingIcon, GlSprintf } from '@gitlab/ui';
+import { TEST_HOST } from 'spec/test_constants';
+import Api from '~/api';
+import createStore from '~/feature_flags/store/index';
+import FeatureFlagsTab from '~/feature_flags/components/feature_flags_tab.vue';
+import FeatureFlagsComponent from '~/feature_flags/components/feature_flags.vue';
+import FeatureFlagsTable from '~/feature_flags/components/feature_flags_table.vue';
+import UserListsTable from '~/feature_flags/components/user_lists_table.vue';
+import ConfigureFeatureFlagsModal from '~/feature_flags/components/configure_feature_flags_modal.vue';
+import { FEATURE_FLAG_SCOPE, USER_LIST_SCOPE } from '~/feature_flags/constants';
+import TablePagination from '~/vue_shared/components/pagination/table_pagination.vue';
+import axios from '~/lib/utils/axios_utils';
+import { getRequestData, userList } from '../mock_data';
+
+const localVue = createLocalVue();
+localVue.use(Vuex);
+
+describe('Feature flags', () => {
+ const mockData = {
+ canUserConfigure: true,
+ csrfToken: 'testToken',
+ featureFlagsClientExampleHelpPagePath: '/help/feature-flags#client-example',
+ featureFlagsClientLibrariesHelpPagePath: '/help/feature-flags#unleash-clients',
+ featureFlagsHelpPagePath: '/help/feature-flags',
+ featureFlagsLimit: '200',
+ featureFlagsLimitExceeded: false,
+ newFeatureFlagPath: 'feature-flags/new',
+ newUserListPath: '/user-list/new',
+ unleashApiUrl: `${TEST_HOST}/api/unleash`,
+ projectName: 'fakeProjectName',
+ errorStateSvgPath: '/assets/illustrations/feature_flag.svg',
+ };
+
+ const mockState = {
+ endpoint: `${TEST_HOST}/endpoint.json`,
+ projectId: '8',
+ unleashApiInstanceId: 'oP6sCNRqtRHmpy1gw2-F',
+ };
+
+ let wrapper;
+ let mock;
+ let store;
+
+ const factory = (provide = mockData, fn = shallowMount) => {
+ store = createStore(mockState);
+ wrapper = fn(FeatureFlagsComponent, {
+ localVue,
+ store,
+ provide,
+ stubs: {
+ FeatureFlagsTab,
+ },
+ });
+ };
+
+ const configureButton = () => wrapper.find('[data-testid="ff-configure-button"]');
+ const newButton = () => wrapper.find('[data-testid="ff-new-button"]');
+ const newUserListButton = () => wrapper.find('[data-testid="ff-new-list-button"]');
+ const limitAlert = () => wrapper.find(GlAlert);
+
+ beforeEach(() => {
+ mock = new MockAdapter(axios);
+ jest.spyOn(Api, 'fetchFeatureFlagUserLists').mockResolvedValue({
+ data: [userList],
+ headers: {
+ 'x-next-page': '2',
+ 'x-page': '1',
+ 'X-Per-Page': '8',
+ 'X-Prev-Page': '',
+ 'X-TOTAL': '40',
+ 'X-Total-Pages': '5',
+ },
+ });
+ });
+
+ afterEach(() => {
+ mock.restore();
+ wrapper.destroy();
+ wrapper = null;
+ });
+
+ describe('when limit exceeded', () => {
+ const provideData = { ...mockData, featureFlagsLimitExceeded: true };
+
+ beforeEach(done => {
+ mock
+ .onGet(`${TEST_HOST}/endpoint.json`, { params: { scope: FEATURE_FLAG_SCOPE, page: '1' } })
+ .reply(200, getRequestData, {});
+ factory(provideData);
+ setImmediate(done);
+ });
+
+ it('makes the new feature flag button do nothing if clicked', () => {
+ expect(newButton().exists()).toBe(true);
+ expect(newButton().props('disabled')).toBe(false);
+ expect(newButton().props('href')).toBe(undefined);
+ });
+
+ it('shows a feature flags limit reached alert', () => {
+ expect(limitAlert().exists()).toBe(true);
+ expect(
+ limitAlert()
+ .find(GlSprintf)
+ .attributes('message'),
+ ).toContain('Feature flags limit reached');
+ });
+
+ describe('when the alert is dismissed', () => {
+ beforeEach(async () => {
+ await limitAlert().vm.$emit('dismiss');
+ });
+
+ it('hides the alert', async () => {
+ expect(limitAlert().exists()).toBe(false);
+ });
+
+ it('re-shows the alert if the new feature flag button is clicked', async () => {
+ await newButton().vm.$emit('click');
+
+ expect(limitAlert().exists()).toBe(true);
+ });
+ });
+ });
+
+ describe('without permissions', () => {
+ const provideData = {
+ ...mockData,
+ canUserConfigure: false,
+ canUserRotateToken: false,
+ newFeatureFlagPath: null,
+ newUserListPath: null,
+ };
+
+ beforeEach(done => {
+ mock
+ .onGet(`${TEST_HOST}/endpoint.json`, { params: { scope: FEATURE_FLAG_SCOPE, page: '1' } })
+ .reply(200, getRequestData, {});
+ factory(provideData);
+ setImmediate(done);
+ });
+
+ it('does not render configure button', () => {
+ expect(configureButton().exists()).toBe(false);
+ });
+
+ it('does not render new feature flag button', () => {
+ expect(newButton().exists()).toBe(false);
+ });
+
+ it('does not render new user list button', () => {
+ expect(newUserListButton().exists()).toBe(false);
+ });
+ });
+
+ describe('loading state', () => {
+ it('renders a loading icon', () => {
+ mock
+ .onGet(`${TEST_HOST}/endpoint.json`, { params: { scope: FEATURE_FLAG_SCOPE, page: '1' } })
+ .replyOnce(200, getRequestData, {});
+
+ factory();
+
+ const loadingElement = wrapper.find(GlLoadingIcon);
+
+ expect(loadingElement.exists()).toBe(true);
+ expect(loadingElement.props('label')).toEqual('Loading feature flags');
+ });
+ });
+
+ describe('successful request', () => {
+ describe('without feature flags', () => {
+ let emptyState;
+
+ beforeEach(async () => {
+ mock.onGet(mockState.endpoint, { params: { scope: FEATURE_FLAG_SCOPE, page: '1' } }).reply(
+ 200,
+ {
+ feature_flags: [],
+ count: {
+ all: 0,
+ enabled: 0,
+ disabled: 0,
+ },
+ },
+ {},
+ );
+
+ factory();
+ await wrapper.vm.$nextTick();
+
+ emptyState = wrapper.find(GlEmptyState);
+ });
+
+ it('should render the empty state', async () => {
+ expect(emptyState.exists()).toBe(true);
+ });
+
+ it('renders configure button', () => {
+ expect(configureButton().exists()).toBe(true);
+ });
+
+ it('renders new feature flag button', () => {
+ expect(newButton().exists()).toBe(true);
+ });
+
+ it('renders new user list button', () => {
+ expect(newUserListButton().exists()).toBe(true);
+ expect(newUserListButton().attributes('href')).toBe('/user-list/new');
+ });
+
+ describe('in feature flags tab', () => {
+ it('renders generic title', () => {
+ expect(emptyState.props('title')).toEqual('Get started with feature flags');
+ });
+ });
+ });
+
+ describe('with paginated feature flags', () => {
+ beforeEach(done => {
+ mock
+ .onGet(mockState.endpoint, { params: { scope: FEATURE_FLAG_SCOPE, page: '1' } })
+ .replyOnce(200, getRequestData, {
+ 'x-next-page': '2',
+ 'x-page': '1',
+ 'X-Per-Page': '2',
+ 'X-Prev-Page': '',
+ 'X-TOTAL': '37',
+ 'X-Total-Pages': '5',
+ });
+
+ factory();
+ jest.spyOn(store, 'dispatch');
+ setImmediate(done);
+ });
+
+ it('should render a table with feature flags', () => {
+ const table = wrapper.find(FeatureFlagsTable);
+ expect(table.exists()).toBe(true);
+ expect(table.props(FEATURE_FLAG_SCOPE)).toEqual(
+ expect.arrayContaining([
+ expect.objectContaining({
+ name: getRequestData.feature_flags[0].name,
+ description: getRequestData.feature_flags[0].description,
+ }),
+ ]),
+ );
+ });
+
+ it('should toggle a flag when receiving the toggle-flag event', () => {
+ const table = wrapper.find(FeatureFlagsTable);
+
+ const [flag] = table.props(FEATURE_FLAG_SCOPE);
+ table.vm.$emit('toggle-flag', flag);
+
+ expect(store.dispatch).toHaveBeenCalledWith('toggleFeatureFlag', flag);
+ });
+
+ it('renders configure button', () => {
+ expect(configureButton().exists()).toBe(true);
+ });
+
+ it('renders new feature flag button', () => {
+ expect(newButton().exists()).toBe(true);
+ });
+
+ it('renders new user list button', () => {
+ expect(newUserListButton().exists()).toBe(true);
+ expect(newUserListButton().attributes('href')).toBe('/user-list/new');
+ });
+
+ describe('pagination', () => {
+ it('should render pagination', () => {
+ expect(wrapper.find(TablePagination).exists()).toBe(true);
+ });
+
+ it('should make an API request when page is clicked', () => {
+ jest.spyOn(wrapper.vm, 'updateFeatureFlagOptions');
+ wrapper.find(TablePagination).vm.change(4);
+
+ expect(wrapper.vm.updateFeatureFlagOptions).toHaveBeenCalledWith({
+ scope: FEATURE_FLAG_SCOPE,
+ page: '4',
+ });
+ });
+
+ it('should make an API request when using tabs', () => {
+ jest.spyOn(wrapper.vm, 'updateFeatureFlagOptions');
+ wrapper.find('[data-testid="user-lists-tab"]').vm.$emit('changeTab');
+
+ expect(wrapper.vm.updateFeatureFlagOptions).toHaveBeenCalledWith({
+ scope: USER_LIST_SCOPE,
+ page: '1',
+ });
+ });
+ });
+ });
+
+ describe('in user lists tab', () => {
+ beforeEach(done => {
+ factory();
+ setImmediate(done);
+ });
+ beforeEach(() => {
+ wrapper.find('[data-testid="user-lists-tab"]').vm.$emit('changeTab');
+ return wrapper.vm.$nextTick();
+ });
+
+ it('should display the user list table', () => {
+ expect(wrapper.find(UserListsTable).exists()).toBe(true);
+ });
+
+ it('should set the user lists to display', () => {
+ expect(wrapper.find(UserListsTable).props('userLists')).toEqual([userList]);
+ });
+ });
+ });
+
+ describe('unsuccessful request', () => {
+ beforeEach(done => {
+ mock
+ .onGet(mockState.endpoint, { params: { scope: FEATURE_FLAG_SCOPE, page: '1' } })
+ .replyOnce(500, {});
+ Api.fetchFeatureFlagUserLists.mockRejectedValueOnce();
+
+ factory();
+ setImmediate(done);
+ });
+
+ it('should render error state', () => {
+ const emptyState = wrapper.find(GlEmptyState);
+ expect(emptyState.props('title')).toEqual('There was an error fetching the feature flags.');
+ expect(emptyState.props('description')).toEqual(
+ 'Try again in a few moments or contact your support team.',
+ );
+ });
+
+ it('renders configure button', () => {
+ expect(configureButton().exists()).toBe(true);
+ });
+
+ it('renders new feature flag button', () => {
+ expect(newButton().exists()).toBe(true);
+ });
+
+ it('renders new user list button', () => {
+ expect(newUserListButton().exists()).toBe(true);
+ expect(newUserListButton().attributes('href')).toBe('/user-list/new');
+ });
+ });
+
+ describe('rotate instance id', () => {
+ beforeEach(done => {
+ mock
+ .onGet(`${TEST_HOST}/endpoint.json`, { params: { scope: FEATURE_FLAG_SCOPE, page: '1' } })
+ .reply(200, getRequestData, {});
+ factory();
+ setImmediate(done);
+ });
+
+ it('should fire the rotate action when a `token` event is received', () => {
+ const actionSpy = jest.spyOn(wrapper.vm, 'rotateInstanceId');
+ const modal = wrapper.find(ConfigureFeatureFlagsModal);
+ modal.vm.$emit('token');
+
+ expect(actionSpy).toHaveBeenCalled();
+ });
+ });
+});
diff --git a/spec/frontend/feature_flags/components/feature_flags_tab_spec.js b/spec/frontend/feature_flags/components/feature_flags_tab_spec.js
new file mode 100644
index 00000000000..bc90c5ceb2d
--- /dev/null
+++ b/spec/frontend/feature_flags/components/feature_flags_tab_spec.js
@@ -0,0 +1,168 @@
+import { mount } from '@vue/test-utils';
+import { GlAlert, GlBadge, GlEmptyState, GlLink, GlLoadingIcon, GlTabs } from '@gitlab/ui';
+import FeatureFlagsTab from '~/feature_flags/components/feature_flags_tab.vue';
+
+const DEFAULT_PROPS = {
+ title: 'test',
+ count: 5,
+ alerts: ['an alert', 'another alert'],
+ isLoading: false,
+ loadingLabel: 'test loading',
+ errorState: false,
+ errorTitle: 'test title',
+ emptyState: true,
+ emptyTitle: 'test empty',
+};
+
+const DEFAULT_PROVIDE = {
+ errorStateSvgPath: '/error.svg',
+ featureFlagsHelpPagePath: '/help/page/path',
+};
+
+describe('feature_flags/components/feature_flags_tab.vue', () => {
+ let wrapper;
+
+ const factory = (props = {}) =>
+ mount(
+ {
+ components: {
+ GlTabs,
+ FeatureFlagsTab,
+ },
+ render(h) {
+ return h(GlTabs, [
+ h(FeatureFlagsTab, { props: this.$attrs, on: this.$listeners }, this.$slots.default),
+ ]);
+ },
+ },
+ {
+ propsData: {
+ ...DEFAULT_PROPS,
+ ...props,
+ },
+ provide: DEFAULT_PROVIDE,
+ slots: {
+ default: '<p data-testid="test-slot">testing</p>',
+ },
+ },
+ );
+
+ afterEach(() => {
+ if (wrapper?.destroy) {
+ wrapper.destroy();
+ }
+
+ wrapper = null;
+ });
+
+ describe('alerts', () => {
+ let alerts;
+
+ beforeEach(() => {
+ wrapper = factory();
+ alerts = wrapper.findAll(GlAlert);
+ });
+
+ it('should show any alerts', () => {
+ expect(alerts).toHaveLength(DEFAULT_PROPS.alerts.length);
+ alerts.wrappers.forEach((alert, i) => expect(alert.text()).toBe(DEFAULT_PROPS.alerts[i]));
+ });
+
+ it('should emit a dismiss event for a dismissed alert', () => {
+ alerts.at(0).vm.$emit('dismiss');
+
+ expect(wrapper.find(FeatureFlagsTab).emitted('dismissAlert')).toEqual([[0]]);
+ });
+ });
+
+ describe('loading', () => {
+ beforeEach(() => {
+ wrapper = factory({ isLoading: true });
+ });
+
+ it('should show a loading icon and nothing else', () => {
+ expect(wrapper.find(GlLoadingIcon).exists()).toBe(true);
+ expect(wrapper.findAll(GlEmptyState)).toHaveLength(0);
+ });
+ });
+
+ describe('error', () => {
+ let emptyState;
+
+ beforeEach(() => {
+ wrapper = factory({ errorState: true });
+ emptyState = wrapper.find(GlEmptyState);
+ });
+
+ it('should show an error state if there has been an error', () => {
+ expect(emptyState.text()).toContain(DEFAULT_PROPS.errorTitle);
+ expect(emptyState.text()).toContain(
+ 'Try again in a few moments or contact your support team.',
+ );
+ expect(emptyState.props('svgPath')).toBe(DEFAULT_PROVIDE.errorStateSvgPath);
+ });
+ });
+
+ describe('empty', () => {
+ let emptyState;
+ let emptyStateLink;
+
+ beforeEach(() => {
+ wrapper = factory({ emptyState: true });
+ emptyState = wrapper.find(GlEmptyState);
+ emptyStateLink = emptyState.find(GlLink);
+ });
+
+ it('should show an empty state if it is empty', () => {
+ expect(emptyState.text()).toContain(DEFAULT_PROPS.emptyTitle);
+ expect(emptyState.text()).toContain(
+ 'Feature flags allow you to configure your code into different flavors by dynamically toggling certain functionality.',
+ );
+ expect(emptyState.props('svgPath')).toBe(DEFAULT_PROVIDE.errorStateSvgPath);
+ expect(emptyStateLink.attributes('href')).toBe(DEFAULT_PROVIDE.featureFlagsHelpPagePath);
+ expect(emptyStateLink.text()).toBe('More information');
+ });
+ });
+
+ describe('slot', () => {
+ let slot;
+
+ beforeEach(async () => {
+ wrapper = factory();
+ await wrapper.vm.$nextTick();
+
+ slot = wrapper.find('[data-testid="test-slot"]');
+ });
+
+ it('should display the passed slot', () => {
+ expect(slot.exists()).toBe(true);
+ expect(slot.text()).toBe('testing');
+ });
+ });
+
+ describe('count', () => {
+ it('should display a count if there is one', async () => {
+ wrapper = factory();
+ await wrapper.vm.$nextTick();
+
+ expect(wrapper.find(GlBadge).text()).toBe(DEFAULT_PROPS.count.toString());
+ });
+ it('should display 0 if there is no count', async () => {
+ wrapper = factory({ count: undefined });
+ await wrapper.vm.$nextTick();
+
+ expect(wrapper.find(GlBadge).text()).toBe('0');
+ });
+ });
+
+ describe('title', () => {
+ it('should show the title', async () => {
+ wrapper = factory();
+ await wrapper.vm.$nextTick();
+
+ expect(wrapper.find('[data-testid="feature-flags-tab-title"]').text()).toBe(
+ DEFAULT_PROPS.title,
+ );
+ });
+ });
+});
diff --git a/spec/frontend/feature_flags/components/feature_flags_table_spec.js b/spec/frontend/feature_flags/components/feature_flags_table_spec.js
new file mode 100644
index 00000000000..a488662470e
--- /dev/null
+++ b/spec/frontend/feature_flags/components/feature_flags_table_spec.js
@@ -0,0 +1,266 @@
+import { shallowMount } from '@vue/test-utils';
+import { GlToggle, GlBadge } from '@gitlab/ui';
+import { trimText } from 'helpers/text_helper';
+import { mockTracking } from 'helpers/tracking_helper';
+import {
+ ROLLOUT_STRATEGY_ALL_USERS,
+ ROLLOUT_STRATEGY_PERCENT_ROLLOUT,
+ ROLLOUT_STRATEGY_USER_ID,
+ ROLLOUT_STRATEGY_GITLAB_USER_LIST,
+ NEW_VERSION_FLAG,
+ LEGACY_FLAG,
+ DEFAULT_PERCENT_ROLLOUT,
+} from '~/feature_flags/constants';
+import FeatureFlagsTable from '~/feature_flags/components/feature_flags_table.vue';
+
+const getDefaultProps = () => ({
+ featureFlags: [
+ {
+ id: 1,
+ iid: 1,
+ active: true,
+ name: 'flag name',
+ description: 'flag description',
+ destroy_path: 'destroy/path',
+ edit_path: 'edit/path',
+ version: LEGACY_FLAG,
+ scopes: [
+ {
+ id: 1,
+ active: true,
+ environmentScope: 'scope',
+ canUpdate: true,
+ protected: false,
+ rolloutStrategy: ROLLOUT_STRATEGY_ALL_USERS,
+ rolloutPercentage: DEFAULT_PERCENT_ROLLOUT,
+ shouldBeDestroyed: false,
+ },
+ ],
+ },
+ ],
+});
+
+describe('Feature flag table', () => {
+ let wrapper;
+ let props;
+
+ const createWrapper = (propsData, opts = {}) => {
+ wrapper = shallowMount(FeatureFlagsTable, {
+ propsData,
+ provide: {
+ csrfToken: 'fakeToken',
+ },
+ ...opts,
+ });
+ };
+
+ beforeEach(() => {
+ props = getDefaultProps();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ wrapper = null;
+ });
+
+ describe('with an active scope and a standard rollout strategy', () => {
+ beforeEach(() => {
+ createWrapper(props);
+ });
+
+ it('Should render a table', () => {
+ expect(wrapper.classes('table-holder')).toBe(true);
+ });
+
+ it('Should render rows', () => {
+ expect(wrapper.find('.gl-responsive-table-row').exists()).toBe(true);
+ });
+
+ it('should render an ID column', () => {
+ expect(wrapper.find('.js-feature-flag-id').exists()).toBe(true);
+ expect(trimText(wrapper.find('.js-feature-flag-id').text())).toEqual('^1');
+ });
+
+ it('Should render a status column', () => {
+ const badge = wrapper.find('[data-testid="feature-flag-status-badge"]');
+
+ expect(badge.exists()).toBe(true);
+ expect(trimText(badge.text())).toEqual('Active');
+ });
+
+ it('Should render a feature flag column', () => {
+ expect(wrapper.find('.js-feature-flag-title').exists()).toBe(true);
+ expect(trimText(wrapper.find('.feature-flag-name').text())).toEqual('flag name');
+
+ expect(trimText(wrapper.find('.feature-flag-description').text())).toEqual(
+ 'flag description',
+ );
+ });
+
+ it('should render an environments specs column', () => {
+ const envColumn = wrapper.find('.js-feature-flag-environments');
+
+ expect(envColumn).toBeDefined();
+ expect(trimText(envColumn.text())).toBe('scope');
+ });
+
+ it('should render an environments specs badge with active class', () => {
+ const envColumn = wrapper.find('.js-feature-flag-environments');
+
+ expect(trimText(envColumn.find(GlBadge).text())).toBe('scope');
+ });
+
+ it('should render an actions column', () => {
+ expect(wrapper.find('.table-action-buttons').exists()).toBe(true);
+ expect(wrapper.find('.js-feature-flag-delete-button').exists()).toBe(true);
+ expect(wrapper.find('.js-feature-flag-edit-button').exists()).toBe(true);
+ expect(wrapper.find('.js-feature-flag-edit-button').attributes('href')).toEqual('edit/path');
+ });
+ });
+
+ describe('when active and with an update toggle', () => {
+ let toggle;
+ let spy;
+
+ beforeEach(() => {
+ props.featureFlags[0].update_path = props.featureFlags[0].destroy_path;
+ createWrapper(props);
+ toggle = wrapper.find(GlToggle);
+ spy = mockTracking('_category_', toggle.element, jest.spyOn);
+ });
+
+ it('should have a toggle', () => {
+ expect(toggle.exists()).toBe(true);
+ expect(toggle.props('value')).toBe(true);
+ });
+
+ it('should trigger a toggle event', () => {
+ toggle.vm.$emit('change');
+ const flag = { ...props.featureFlags[0], active: !props.featureFlags[0].active };
+
+ return wrapper.vm.$nextTick().then(() => {
+ expect(wrapper.emitted('toggle-flag')).toEqual([[flag]]);
+ });
+ });
+
+ it('should track a click', () => {
+ toggle.trigger('click');
+
+ expect(spy).toHaveBeenCalledWith('_category_', 'click_button', {
+ label: 'feature_flag_toggle',
+ });
+ });
+ });
+
+ describe('with an active scope and a percentage rollout strategy', () => {
+ beforeEach(() => {
+ props.featureFlags[0].scopes[0].rolloutStrategy = ROLLOUT_STRATEGY_PERCENT_ROLLOUT;
+ props.featureFlags[0].scopes[0].rolloutPercentage = '54';
+ createWrapper(props);
+ });
+
+ it('should render an environments specs badge with percentage', () => {
+ const envColumn = wrapper.find('.js-feature-flag-environments');
+
+ expect(trimText(envColumn.find(GlBadge).text())).toBe('scope: 54%');
+ });
+ });
+
+ describe('with an inactive scope', () => {
+ beforeEach(() => {
+ props.featureFlags[0].scopes[0].active = false;
+ createWrapper(props);
+ });
+
+ it('should render an environments specs badge with inactive class', () => {
+ const envColumn = wrapper.find('.js-feature-flag-environments');
+
+ expect(trimText(envColumn.find(GlBadge).text())).toBe('scope');
+ });
+ });
+
+ describe('with a new version flag', () => {
+ let badges;
+
+ beforeEach(() => {
+ const newVersionProps = {
+ ...props,
+ featureFlags: [
+ {
+ id: 1,
+ iid: 1,
+ active: true,
+ name: 'flag name',
+ description: 'flag description',
+ destroy_path: 'destroy/path',
+ edit_path: 'edit/path',
+ version: NEW_VERSION_FLAG,
+ scopes: [],
+ strategies: [
+ {
+ name: ROLLOUT_STRATEGY_ALL_USERS,
+ parameters: {},
+ scopes: [{ environment_scope: '*' }],
+ },
+ {
+ name: ROLLOUT_STRATEGY_PERCENT_ROLLOUT,
+ parameters: { percentage: '50' },
+ scopes: [{ environment_scope: 'production' }, { environment_scope: 'staging' }],
+ },
+ {
+ name: ROLLOUT_STRATEGY_USER_ID,
+ parameters: { userIds: '1,2,3,4' },
+ scopes: [{ environment_scope: 'review/*' }],
+ },
+ {
+ name: ROLLOUT_STRATEGY_GITLAB_USER_LIST,
+ parameters: {},
+ user_list: { name: 'test list' },
+ scopes: [{ environment_scope: '*' }],
+ },
+ ],
+ },
+ ],
+ };
+ createWrapper(newVersionProps, {
+ provide: { csrfToken: 'fakeToken', glFeatures: { featureFlagsNewVersion: true } },
+ });
+
+ badges = wrapper.findAll('[data-testid="strategy-badge"]');
+ });
+
+ it('shows All Environments if the environment scope is *', () => {
+ expect(badges.at(0).text()).toContain('All Environments');
+ });
+
+ it('shows the environment scope if another is set', () => {
+ expect(badges.at(1).text()).toContain('production');
+ expect(badges.at(1).text()).toContain('staging');
+ expect(badges.at(2).text()).toContain('review/*');
+ });
+
+ it('shows All Users for the default strategy', () => {
+ expect(badges.at(0).text()).toContain('All Users');
+ });
+
+ it('shows the percent for a percent rollout', () => {
+ expect(badges.at(1).text()).toContain('Percent of users - 50%');
+ });
+
+ it('shows the number of users for users with ID', () => {
+ expect(badges.at(2).text()).toContain('User IDs - 4 users');
+ });
+
+ it('shows the name of a user list for user list', () => {
+ expect(badges.at(3).text()).toContain('User List - test list');
+ });
+ });
+
+ it('renders a feature flag without an iid', () => {
+ delete props.featureFlags[0].iid;
+ createWrapper(props);
+
+ expect(wrapper.find('.js-feature-flag-id').exists()).toBe(true);
+ expect(trimText(wrapper.find('.js-feature-flag-id').text())).toBe('');
+ });
+});
diff --git a/spec/frontend/feature_flags/components/form_spec.js b/spec/frontend/feature_flags/components/form_spec.js
new file mode 100644
index 00000000000..33c7eeb54b7
--- /dev/null
+++ b/spec/frontend/feature_flags/components/form_spec.js
@@ -0,0 +1,493 @@
+import { uniqueId } from 'lodash';
+import { shallowMount } from '@vue/test-utils';
+import { GlFormTextarea, GlFormCheckbox, GlButton } from '@gitlab/ui';
+import Api from '~/api';
+import Form from '~/feature_flags/components/form.vue';
+import EnvironmentsDropdown from '~/feature_flags/components/environments_dropdown.vue';
+import Strategy from '~/feature_flags/components/strategy.vue';
+import {
+ ROLLOUT_STRATEGY_ALL_USERS,
+ ROLLOUT_STRATEGY_PERCENT_ROLLOUT,
+ INTERNAL_ID_PREFIX,
+ DEFAULT_PERCENT_ROLLOUT,
+ LEGACY_FLAG,
+ NEW_VERSION_FLAG,
+} from '~/feature_flags/constants';
+import RelatedIssuesRoot from '~/related_issues/components/related_issues_root.vue';
+import ToggleButton from '~/vue_shared/components/toggle_button.vue';
+import { featureFlag, userList, allUsersStrategy } from '../mock_data';
+
+jest.mock('~/api.js');
+
+describe('feature flag form', () => {
+ let wrapper;
+ const requiredProps = {
+ cancelPath: 'feature_flags',
+ submitText: 'Create',
+ };
+
+ const requiredInjections = {
+ environmentsEndpoint: '/environments.json',
+ projectId: '1',
+ glFeatures: {
+ featureFlagPermissions: true,
+ featureFlagsNewVersion: true,
+ },
+ };
+
+ const factory = (props = {}, provide = {}) => {
+ wrapper = shallowMount(Form, {
+ propsData: { ...requiredProps, ...props },
+ provide: {
+ ...requiredInjections,
+ ...provide,
+ },
+ });
+ };
+
+ beforeEach(() => {
+ Api.fetchFeatureFlagUserLists.mockResolvedValue({ data: [] });
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('should render provided submitText', () => {
+ factory(requiredProps);
+
+ expect(wrapper.find('.js-ff-submit').text()).toEqual(requiredProps.submitText);
+ });
+
+ it('should render provided cancelPath', () => {
+ factory(requiredProps);
+
+ expect(wrapper.find('.js-ff-cancel').attributes('href')).toEqual(requiredProps.cancelPath);
+ });
+
+ it('does not render the related issues widget without the featureFlagIssuesEndpoint', () => {
+ factory(requiredProps);
+
+ expect(wrapper.find(RelatedIssuesRoot).exists()).toBe(false);
+ });
+
+ it('renders the related issues widget when the featureFlagIssuesEndpoint is provided', () => {
+ factory(
+ {},
+ {
+ ...requiredInjections,
+ featureFlagIssuesEndpoint: '/some/endpoint',
+ },
+ );
+
+ expect(wrapper.find(RelatedIssuesRoot).exists()).toBe(true);
+ });
+
+ describe('without provided data', () => {
+ beforeEach(() => {
+ factory(requiredProps);
+ });
+
+ it('should render name input text', () => {
+ expect(wrapper.find('#feature-flag-name').exists()).toBe(true);
+ });
+
+ it('should render description textarea', () => {
+ expect(wrapper.find('#feature-flag-description').exists()).toBe(true);
+ });
+
+ describe('scopes', () => {
+ it('should render scopes table', () => {
+ expect(wrapper.find('.js-scopes-table').exists()).toBe(true);
+ });
+
+ it('should render scopes table with a new row ', () => {
+ expect(wrapper.find('.js-add-new-scope').exists()).toBe(true);
+ });
+
+ describe('status toggle', () => {
+ describe('without filled text input', () => {
+ it('should add a new scope with the text value empty and the status', () => {
+ wrapper.find(ToggleButton).vm.$emit('change', true);
+
+ expect(wrapper.vm.formScopes).toHaveLength(1);
+ expect(wrapper.vm.formScopes[0].active).toEqual(true);
+ expect(wrapper.vm.formScopes[0].environmentScope).toEqual('');
+
+ expect(wrapper.vm.newScope).toEqual('');
+ });
+ });
+
+ it('should be disabled if the feature flag is not active', done => {
+ wrapper.setProps({ active: false });
+ wrapper.vm.$nextTick(() => {
+ expect(wrapper.find(ToggleButton).props('disabledInput')).toBe(true);
+ done();
+ });
+ });
+ });
+ });
+ });
+
+ describe('with provided data', () => {
+ beforeEach(() => {
+ factory({
+ ...requiredProps,
+ name: featureFlag.name,
+ description: featureFlag.description,
+ active: true,
+ version: LEGACY_FLAG,
+ scopes: [
+ {
+ id: 1,
+ active: true,
+ environmentScope: 'scope',
+ canUpdate: true,
+ protected: false,
+ rolloutStrategy: ROLLOUT_STRATEGY_PERCENT_ROLLOUT,
+ rolloutPercentage: '54',
+ rolloutUserIds: '123',
+ shouldIncludeUserIds: true,
+ },
+ {
+ id: 2,
+ active: true,
+ environmentScope: 'scope',
+ canUpdate: false,
+ protected: true,
+ rolloutStrategy: ROLLOUT_STRATEGY_PERCENT_ROLLOUT,
+ rolloutPercentage: '54',
+ rolloutUserIds: '123',
+ shouldIncludeUserIds: true,
+ },
+ ],
+ });
+ });
+
+ describe('scopes', () => {
+ it('should be possible to remove a scope', () => {
+ expect(wrapper.find('.js-feature-flag-delete').exists()).toEqual(true);
+ });
+
+ it('renders empty row to add a new scope', () => {
+ expect(wrapper.find('.js-add-new-scope').exists()).toEqual(true);
+ });
+
+ it('renders the user id checkbox', () => {
+ expect(wrapper.find(GlFormCheckbox).exists()).toBe(true);
+ });
+
+ it('renders the user id text area', () => {
+ expect(wrapper.find(GlFormTextarea).exists()).toBe(true);
+
+ expect(wrapper.find(GlFormTextarea).vm.value).toBe('123');
+ });
+
+ describe('update scope', () => {
+ describe('on click on toggle', () => {
+ it('should update the scope', () => {
+ wrapper.find(ToggleButton).vm.$emit('change', false);
+
+ expect(wrapper.vm.formScopes[0].active).toBe(false);
+ });
+
+ it('should be disabled if the feature flag is not active', done => {
+ wrapper.setProps({ active: false });
+
+ wrapper.vm.$nextTick(() => {
+ expect(wrapper.find(ToggleButton).props('disabledInput')).toBe(true);
+ done();
+ });
+ });
+ });
+ describe('on strategy change', () => {
+ it('should not include user IDs if All Users is selected', () => {
+ const scope = wrapper.find({ ref: 'scopeRow' });
+ scope.find('select').setValue(ROLLOUT_STRATEGY_ALL_USERS);
+ return wrapper.vm.$nextTick().then(() => {
+ expect(scope.find('#rollout-user-id-0').exists()).toBe(false);
+ });
+ });
+ });
+ });
+
+ describe('deleting an existing scope', () => {
+ beforeEach(() => {
+ wrapper.find('.js-delete-scope').vm.$emit('click');
+ });
+
+ it('should add `shouldBeDestroyed` key the clicked scope', () => {
+ expect(wrapper.vm.formScopes[0].shouldBeDestroyed).toBe(true);
+ });
+
+ it('should not render deleted scopes', () => {
+ expect(wrapper.vm.filteredScopes).toEqual([expect.objectContaining({ id: 2 })]);
+ });
+ });
+
+ describe('deleting a new scope', () => {
+ it('should remove the scope from formScopes', () => {
+ factory({
+ ...requiredProps,
+ name: 'feature_flag_1',
+ description: 'this is a feature flag',
+ scopes: [
+ {
+ environmentScope: 'new_scope',
+ active: false,
+ id: uniqueId(INTERNAL_ID_PREFIX),
+ canUpdate: true,
+ protected: false,
+ strategies: [
+ {
+ name: ROLLOUT_STRATEGY_ALL_USERS,
+ parameters: {},
+ },
+ ],
+ },
+ ],
+ });
+
+ wrapper.find('.js-delete-scope').vm.$emit('click');
+
+ expect(wrapper.vm.formScopes).toEqual([]);
+ });
+ });
+
+ describe('with * scope', () => {
+ beforeEach(() => {
+ factory({
+ ...requiredProps,
+ name: 'feature_flag_1',
+ description: 'this is a feature flag',
+ scopes: [
+ {
+ environmentScope: '*',
+ active: false,
+ canUpdate: false,
+ rolloutStrategy: ROLLOUT_STRATEGY_ALL_USERS,
+ rolloutPercentage: DEFAULT_PERCENT_ROLLOUT,
+ },
+ ],
+ });
+ });
+
+ it('renders read only name', () => {
+ expect(wrapper.find('.js-scope-all').exists()).toEqual(true);
+ });
+ });
+
+ describe('without permission to update', () => {
+ it('should have the flag name input disabled', () => {
+ const input = wrapper.find('#feature-flag-name');
+
+ expect(input.element.disabled).toBe(true);
+ });
+
+ it('should have the flag discription text area disabled', () => {
+ const textarea = wrapper.find('#feature-flag-description');
+
+ expect(textarea.element.disabled).toBe(true);
+ });
+
+ it('should have the scope that cannot be updated be disabled', () => {
+ const row = wrapper.findAll('.gl-responsive-table-row').at(2);
+
+ expect(row.find(EnvironmentsDropdown).vm.disabled).toBe(true);
+ expect(row.find(ToggleButton).vm.disabledInput).toBe(true);
+ expect(row.find('.js-delete-scope').exists()).toBe(false);
+ });
+ });
+ });
+
+ describe('on submit', () => {
+ const selectFirstRolloutStrategyOption = dropdownIndex => {
+ wrapper
+ .findAll('select.js-rollout-strategy')
+ .at(dropdownIndex)
+ .findAll('option')
+ .at(1)
+ .setSelected();
+ };
+
+ beforeEach(() => {
+ factory({
+ ...requiredProps,
+ name: 'feature_flag_1',
+ active: true,
+ description: 'this is a feature flag',
+ scopes: [
+ {
+ id: 1,
+ environmentScope: 'production',
+ canUpdate: true,
+ protected: true,
+ active: false,
+ rolloutStrategy: ROLLOUT_STRATEGY_ALL_USERS,
+ rolloutPercentage: DEFAULT_PERCENT_ROLLOUT,
+ rolloutUserIds: '',
+ },
+ ],
+ });
+
+ return wrapper.vm.$nextTick();
+ });
+
+ it('should emit handleSubmit with the updated data', () => {
+ wrapper.find('#feature-flag-name').setValue('feature_flag_2');
+
+ return wrapper.vm
+ .$nextTick()
+ .then(() => {
+ wrapper
+ .find('.js-new-scope-name')
+ .find(EnvironmentsDropdown)
+ .vm.$emit('selectEnvironment', 'review');
+
+ return wrapper.vm.$nextTick();
+ })
+ .then(() => {
+ wrapper
+ .find('.js-add-new-scope')
+ .find(ToggleButton)
+ .vm.$emit('change', true);
+ })
+ .then(() => {
+ wrapper.find(ToggleButton).vm.$emit('change', true);
+ return wrapper.vm.$nextTick();
+ })
+
+ .then(() => {
+ selectFirstRolloutStrategyOption(0);
+ return wrapper.vm.$nextTick();
+ })
+ .then(() => {
+ selectFirstRolloutStrategyOption(2);
+ return wrapper.vm.$nextTick();
+ })
+ .then(() => {
+ wrapper.find('.js-rollout-percentage').setValue('55');
+
+ return wrapper.vm.$nextTick();
+ })
+ .then(() => {
+ wrapper.find({ ref: 'submitButton' }).vm.$emit('click');
+
+ const data = wrapper.emitted().handleSubmit[0][0];
+
+ expect(data.name).toEqual('feature_flag_2');
+ expect(data.description).toEqual('this is a feature flag');
+ expect(data.active).toBe(true);
+
+ expect(data.scopes).toEqual([
+ {
+ id: 1,
+ active: true,
+ environmentScope: 'production',
+ canUpdate: true,
+ protected: true,
+ rolloutStrategy: ROLLOUT_STRATEGY_PERCENT_ROLLOUT,
+ rolloutPercentage: '55',
+ rolloutUserIds: '',
+ shouldIncludeUserIds: false,
+ },
+ {
+ id: expect.any(String),
+ active: false,
+ environmentScope: 'review',
+ canUpdate: true,
+ protected: false,
+ rolloutStrategy: ROLLOUT_STRATEGY_ALL_USERS,
+ rolloutPercentage: DEFAULT_PERCENT_ROLLOUT,
+ rolloutUserIds: '',
+ },
+ {
+ id: expect.any(String),
+ active: true,
+ environmentScope: '',
+ canUpdate: true,
+ protected: false,
+ rolloutStrategy: ROLLOUT_STRATEGY_PERCENT_ROLLOUT,
+ rolloutPercentage: DEFAULT_PERCENT_ROLLOUT,
+ rolloutUserIds: '',
+ shouldIncludeUserIds: false,
+ },
+ ]);
+ });
+ });
+ });
+ });
+
+ describe('with strategies', () => {
+ beforeEach(() => {
+ Api.fetchFeatureFlagUserLists.mockResolvedValue({ data: [userList] });
+ factory({
+ ...requiredProps,
+ name: featureFlag.name,
+ description: featureFlag.description,
+ active: true,
+ version: NEW_VERSION_FLAG,
+ strategies: [
+ {
+ type: ROLLOUT_STRATEGY_PERCENT_ROLLOUT,
+ parameters: { percentage: '30' },
+ scopes: [],
+ },
+ {
+ type: ROLLOUT_STRATEGY_ALL_USERS,
+ parameters: {},
+ scopes: [{ environment_scope: 'review/*' }],
+ },
+ ],
+ });
+ });
+
+ it('should request the user lists on mount', () => {
+ return wrapper.vm.$nextTick(() => {
+ expect(Api.fetchFeatureFlagUserLists).toHaveBeenCalledWith('1');
+ });
+ });
+
+ it('should show the strategy component', () => {
+ const strategy = wrapper.find(Strategy);
+ expect(strategy.exists()).toBe(true);
+ expect(strategy.props('strategy')).toEqual({
+ type: ROLLOUT_STRATEGY_PERCENT_ROLLOUT,
+ parameters: { percentage: '30' },
+ scopes: [],
+ });
+ });
+
+ it('should show one strategy component per strategy', () => {
+ expect(wrapper.findAll(Strategy)).toHaveLength(2);
+ });
+
+ it('adds an all users strategy when clicking the Add button', () => {
+ wrapper.find(GlButton).vm.$emit('click');
+
+ return wrapper.vm.$nextTick().then(() => {
+ const strategies = wrapper.findAll(Strategy);
+
+ expect(strategies).toHaveLength(3);
+ expect(strategies.at(2).props('strategy')).toEqual(allUsersStrategy);
+ });
+ });
+
+ it('should remove a strategy on delete', () => {
+ const strategy = {
+ type: ROLLOUT_STRATEGY_PERCENT_ROLLOUT,
+ parameters: { percentage: '30' },
+ scopes: [],
+ };
+ wrapper.find(Strategy).vm.$emit('delete');
+ return wrapper.vm.$nextTick().then(() => {
+ expect(wrapper.findAll(Strategy)).toHaveLength(1);
+ expect(wrapper.find(Strategy).props('strategy')).not.toEqual(strategy);
+ });
+ });
+
+ it('should provide the user lists to the strategy', () => {
+ expect(wrapper.find(Strategy).props('userLists')).toEqual([userList]);
+ });
+ });
+});
diff --git a/spec/frontend/feature_flags/components/new_environments_dropdown_spec.js b/spec/frontend/feature_flags/components/new_environments_dropdown_spec.js
new file mode 100644
index 00000000000..12dc98fbde8
--- /dev/null
+++ b/spec/frontend/feature_flags/components/new_environments_dropdown_spec.js
@@ -0,0 +1,105 @@
+import { shallowMount } from '@vue/test-utils';
+import MockAdapter from 'axios-mock-adapter';
+import { GlLoadingIcon, GlSearchBoxByType, GlDropdownItem } from '@gitlab/ui';
+import NewEnvironmentsDropdown from '~/feature_flags/components/new_environments_dropdown.vue';
+import axios from '~/lib/utils/axios_utils';
+import httpStatusCodes from '~/lib/utils/http_status';
+
+const TEST_HOST = '/test';
+const TEST_SEARCH = 'production';
+
+describe('New Environments Dropdown', () => {
+ let wrapper;
+ let axiosMock;
+
+ beforeEach(() => {
+ axiosMock = new MockAdapter(axios);
+ wrapper = shallowMount(NewEnvironmentsDropdown, {
+ provide: { environmentsEndpoint: TEST_HOST },
+ });
+ });
+
+ afterEach(() => {
+ axiosMock.restore();
+ if (wrapper) {
+ wrapper.destroy();
+ wrapper = null;
+ }
+ });
+
+ describe('before results', () => {
+ it('should show a loading icon', () => {
+ axiosMock.onGet(TEST_HOST).reply(() => {
+ expect(wrapper.find(GlLoadingIcon).exists()).toBe(true);
+ });
+ wrapper.find(GlSearchBoxByType).vm.$emit('focus');
+ return axios.waitForAll();
+ });
+
+ it('should not show any dropdown items', () => {
+ axiosMock.onGet(TEST_HOST).reply(() => {
+ expect(wrapper.findAll(GlDropdownItem)).toHaveLength(0);
+ });
+ wrapper.find(GlSearchBoxByType).vm.$emit('focus');
+ return axios.waitForAll();
+ });
+ });
+
+ describe('with empty results', () => {
+ let item;
+ beforeEach(() => {
+ axiosMock.onGet(TEST_HOST).reply(200, []);
+ wrapper.find(GlSearchBoxByType).vm.$emit('focus');
+ wrapper.find(GlSearchBoxByType).vm.$emit('input', TEST_SEARCH);
+ return axios
+ .waitForAll()
+ .then(() => wrapper.vm.$nextTick())
+ .then(() => {
+ item = wrapper.find(GlDropdownItem);
+ });
+ });
+
+ it('should display a Create item label', () => {
+ expect(item.text()).toBe('Create production');
+ });
+
+ it('should display that no matching items are found', () => {
+ expect(wrapper.find({ ref: 'noResults' }).exists()).toBe(true);
+ });
+
+ it('should emit a new scope when selected', () => {
+ item.vm.$emit('click');
+ expect(wrapper.emitted('add')).toEqual([[TEST_SEARCH]]);
+ });
+ });
+
+ describe('with results', () => {
+ let items;
+ beforeEach(() => {
+ axiosMock.onGet(TEST_HOST).reply(httpStatusCodes.OK, ['prod', 'production']);
+ wrapper.find(GlSearchBoxByType).vm.$emit('focus');
+ wrapper.find(GlSearchBoxByType).vm.$emit('input', 'prod');
+ return axios.waitForAll().then(() => {
+ items = wrapper.findAll(GlDropdownItem);
+ });
+ });
+
+ it('should display one item per result', () => {
+ expect(items).toHaveLength(2);
+ });
+
+ it('should emit an add if an item is clicked', () => {
+ items.at(0).vm.$emit('click');
+ expect(wrapper.emitted('add')).toEqual([['prod']]);
+ });
+
+ it('should not display a create label', () => {
+ items = items.filter(i => i.text().startsWith('Create'));
+ expect(items).toHaveLength(0);
+ });
+
+ it('should not display a message about no results', () => {
+ expect(wrapper.find({ ref: 'noResults' }).exists()).toBe(false);
+ });
+ });
+});
diff --git a/spec/frontend/feature_flags/components/new_feature_flag_spec.js b/spec/frontend/feature_flags/components/new_feature_flag_spec.js
new file mode 100644
index 00000000000..dbc6e03d922
--- /dev/null
+++ b/spec/frontend/feature_flags/components/new_feature_flag_spec.js
@@ -0,0 +1,136 @@
+import { shallowMount, createLocalVue } from '@vue/test-utils';
+import Vuex from 'vuex';
+import MockAdapter from 'axios-mock-adapter';
+import { GlAlert } from '@gitlab/ui';
+import { TEST_HOST } from 'spec/test_constants';
+import Form from '~/feature_flags/components/form.vue';
+import createStore from '~/feature_flags/store/new';
+import NewFeatureFlag from '~/feature_flags/components/new_feature_flag.vue';
+import {
+ ROLLOUT_STRATEGY_ALL_USERS,
+ DEFAULT_PERCENT_ROLLOUT,
+ NEW_FLAG_ALERT,
+} from '~/feature_flags/constants';
+import axios from '~/lib/utils/axios_utils';
+import { allUsersStrategy } from '../mock_data';
+
+const userCalloutId = 'feature_flags_new_version';
+const userCalloutsPath = `${TEST_HOST}/user_callouts`;
+
+const localVue = createLocalVue();
+localVue.use(Vuex);
+
+describe('New feature flag form', () => {
+ let wrapper;
+
+ const store = createStore({
+ endpoint: `${TEST_HOST}/feature_flags.json`,
+ path: '/feature_flags',
+ });
+
+ const factory = (opts = {}) => {
+ if (wrapper) {
+ wrapper.destroy();
+ wrapper = null;
+ }
+ wrapper = shallowMount(NewFeatureFlag, {
+ localVue,
+ store,
+ provide: {
+ showUserCallout: true,
+ userCalloutId,
+ userCalloutsPath,
+ environmentsEndpoint: 'environments.json',
+ projectId: '8',
+ glFeatures: {
+ featureFlagsNewVersion: true,
+ },
+ ...opts,
+ },
+ });
+ };
+
+ beforeEach(() => {
+ factory();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ const findAlert = () => wrapper.find(GlAlert);
+
+ describe('with error', () => {
+ it('should render the error', () => {
+ store.dispatch('receiveCreateFeatureFlagError', { message: ['The name is required'] });
+ return wrapper.vm.$nextTick(() => {
+ expect(wrapper.find('.alert').exists()).toEqual(true);
+ expect(wrapper.find('.alert').text()).toContain('The name is required');
+ });
+ });
+ });
+
+ it('renders form title', () => {
+ expect(wrapper.find('h3').text()).toEqual('New feature flag');
+ });
+
+ it('should render feature flag form', () => {
+ expect(wrapper.find(Form).exists()).toEqual(true);
+ });
+
+ it('should render default * row', () => {
+ const defaultScope = {
+ id: expect.any(String),
+ environmentScope: '*',
+ active: true,
+ rolloutStrategy: ROLLOUT_STRATEGY_ALL_USERS,
+ rolloutPercentage: DEFAULT_PERCENT_ROLLOUT,
+ rolloutUserIds: '',
+ };
+ expect(wrapper.vm.scopes).toEqual([defaultScope]);
+
+ expect(wrapper.find(Form).props('scopes')).toContainEqual(defaultScope);
+ });
+
+ it('should not alert users that feature flags are changing soon', () => {
+ expect(wrapper.find(GlAlert).exists()).toBe(false);
+ });
+
+ it('has an all users strategy by default', () => {
+ const strategies = wrapper.find(Form).props('strategies');
+
+ expect(strategies).toEqual([allUsersStrategy]);
+ });
+
+ describe('without new version flags', () => {
+ beforeEach(() => factory({ glFeatures: { featureFlagsNewVersion: false } }));
+
+ it('should alert users that feature flags are changing soon', () => {
+ expect(findAlert().text()).toBe(NEW_FLAG_ALERT);
+ });
+ });
+
+ describe('dismissing new version alert', () => {
+ let mock;
+
+ beforeEach(() => {
+ mock = new MockAdapter(axios);
+ mock.onPost(userCalloutsPath, { feature_name: userCalloutId }).reply(200);
+ factory({ glFeatures: { featureFlagsNewVersion: false } });
+ findAlert().vm.$emit('dismiss');
+ return wrapper.vm.$nextTick();
+ });
+
+ afterEach(() => {
+ mock.restore();
+ });
+
+ it('should hide the alert', () => {
+ expect(findAlert().exists()).toBe(false);
+ });
+
+ it('should send the dismissal event', () => {
+ expect(mock.history.post.length).toBe(1);
+ });
+ });
+});
diff --git a/spec/frontend/feature_flags/components/strategies/default_spec.js b/spec/frontend/feature_flags/components/strategies/default_spec.js
new file mode 100644
index 00000000000..1315cd7d735
--- /dev/null
+++ b/spec/frontend/feature_flags/components/strategies/default_spec.js
@@ -0,0 +1,10 @@
+import { shallowMount } from '@vue/test-utils';
+import Default from '~/feature_flags/components/strategies/default.vue';
+
+describe('~/feature_flags/components/strategies/default.vue', () => {
+ it('should emit an empty parameter object on mount', () => {
+ const wrapper = shallowMount(Default);
+
+ expect(wrapper.emitted('change')).toEqual([[{ parameters: {} }]]);
+ });
+});
diff --git a/spec/frontend/feature_flags/components/strategies/flexible_rollout_spec.js b/spec/frontend/feature_flags/components/strategies/flexible_rollout_spec.js
new file mode 100644
index 00000000000..f3f70a325d0
--- /dev/null
+++ b/spec/frontend/feature_flags/components/strategies/flexible_rollout_spec.js
@@ -0,0 +1,116 @@
+import { mount } from '@vue/test-utils';
+import { GlFormInput, GlFormSelect } from '@gitlab/ui';
+import FlexibleRollout from '~/feature_flags/components/strategies/flexible_rollout.vue';
+import ParameterFormGroup from '~/feature_flags/components/strategies/parameter_form_group.vue';
+import { PERCENT_ROLLOUT_GROUP_ID } from '~/feature_flags/constants';
+import { flexibleRolloutStrategy } from '../../mock_data';
+
+const DEFAULT_PROPS = {
+ strategy: flexibleRolloutStrategy,
+};
+
+describe('feature_flags/components/strategies/flexible_rollout.vue', () => {
+ let wrapper;
+ let percentageFormGroup;
+ let percentageInput;
+ let stickinessFormGroup;
+ let stickinessSelect;
+
+ const factory = (props = {}) =>
+ mount(FlexibleRollout, { propsData: { ...DEFAULT_PROPS, ...props } });
+
+ afterEach(() => {
+ if (wrapper?.destroy) {
+ wrapper.destroy();
+ }
+
+ wrapper = null;
+ });
+
+ describe('with valid percentage', () => {
+ beforeEach(() => {
+ wrapper = factory();
+
+ percentageFormGroup = wrapper
+ .find('[data-testid="strategy-flexible-rollout-percentage"]')
+ .find(ParameterFormGroup);
+ percentageInput = percentageFormGroup.find(GlFormInput);
+ stickinessFormGroup = wrapper
+ .find('[data-testid="strategy-flexible-rollout-stickiness"]')
+ .find(ParameterFormGroup);
+ stickinessSelect = stickinessFormGroup.find(GlFormSelect);
+ });
+
+ it('displays the current percentage value', () => {
+ expect(percentageInput.element.value).toBe(flexibleRolloutStrategy.parameters.rollout);
+ });
+
+ it('displays the current stickiness value', () => {
+ expect(stickinessSelect.element.value).toBe(flexibleRolloutStrategy.parameters.stickiness);
+ });
+
+ it('emits a change when the percentage value changes', async () => {
+ percentageInput.setValue('75');
+ await wrapper.vm.$nextTick();
+ expect(wrapper.emitted('change')).toEqual([
+ [
+ {
+ parameters: {
+ rollout: '75',
+ groupId: PERCENT_ROLLOUT_GROUP_ID,
+ stickiness: flexibleRolloutStrategy.parameters.stickiness,
+ },
+ },
+ ],
+ ]);
+ });
+
+ it('emits a change when the stickiness value changes', async () => {
+ stickinessSelect.setValue('USERID');
+ await wrapper.vm.$nextTick();
+ expect(wrapper.emitted('change')).toEqual([
+ [
+ {
+ parameters: {
+ rollout: flexibleRolloutStrategy.parameters.rollout,
+ groupId: PERCENT_ROLLOUT_GROUP_ID,
+ stickiness: 'USERID',
+ },
+ },
+ ],
+ ]);
+ });
+
+ it('does not show errors', () => {
+ expect(percentageFormGroup.attributes('state')).toBe('true');
+ });
+ });
+
+ describe('with percentage that is out of range', () => {
+ beforeEach(() => {
+ wrapper = factory({ strategy: { parameters: { rollout: '101' } } });
+ });
+
+ it('shows errors', () => {
+ const formGroup = wrapper
+ .find('[data-testid="strategy-flexible-rollout-percentage"]')
+ .find(ParameterFormGroup);
+
+ expect(formGroup.attributes('state')).toBeUndefined();
+ });
+ });
+
+ describe('with percentage that is not a whole number', () => {
+ beforeEach(() => {
+ wrapper = factory({ strategy: { parameters: { rollout: '3.14' } } });
+ });
+
+ it('shows errors', () => {
+ const formGroup = wrapper
+ .find('[data-testid="strategy-flexible-rollout-percentage"]')
+ .find(ParameterFormGroup);
+
+ expect(formGroup.attributes('state')).toBeUndefined();
+ });
+ });
+});
diff --git a/spec/frontend/feature_flags/components/strategies/gitlab_user_list_spec.js b/spec/frontend/feature_flags/components/strategies/gitlab_user_list_spec.js
new file mode 100644
index 00000000000..014c6dd98b9
--- /dev/null
+++ b/spec/frontend/feature_flags/components/strategies/gitlab_user_list_spec.js
@@ -0,0 +1,51 @@
+import { mount } from '@vue/test-utils';
+import { GlFormSelect } from '@gitlab/ui';
+import GitlabUserList from '~/feature_flags/components/strategies/gitlab_user_list.vue';
+import { userListStrategy, userList } from '../../mock_data';
+
+const DEFAULT_PROPS = {
+ strategy: userListStrategy,
+ userLists: [userList],
+};
+
+describe('~/feature_flags/components/strategies/gitlab_user_list.vue', () => {
+ let wrapper;
+
+ const factory = (props = {}) =>
+ mount(GitlabUserList, { propsData: { ...DEFAULT_PROPS, ...props } });
+
+ describe('with user lists', () => {
+ beforeEach(() => {
+ wrapper = factory();
+ });
+
+ it('should show the input for userListId with the correct value', () => {
+ const inputWrapper = wrapper.find(GlFormSelect);
+ expect(inputWrapper.exists()).toBe(true);
+ expect(inputWrapper.element.value).toBe('2');
+ });
+
+ it('should emit a change event when altering the userListId', () => {
+ const inputWrapper = wrapper.find(GitlabUserList);
+ inputWrapper.vm.$emit('change', {
+ userListId: '3',
+ });
+ expect(wrapper.emitted('change')).toEqual([
+ [
+ {
+ userListId: '3',
+ },
+ ],
+ ]);
+ });
+ });
+ describe('without user lists', () => {
+ beforeEach(() => {
+ wrapper = factory({ userLists: [] });
+ });
+
+ it('should display a message that there are no user lists', () => {
+ expect(wrapper.text()).toContain('There are no configured user lists');
+ });
+ });
+});
diff --git a/spec/frontend/feature_flags/components/strategies/parameter_form_group_spec.js b/spec/frontend/feature_flags/components/strategies/parameter_form_group_spec.js
new file mode 100644
index 00000000000..a0ffdb1fca0
--- /dev/null
+++ b/spec/frontend/feature_flags/components/strategies/parameter_form_group_spec.js
@@ -0,0 +1,50 @@
+import { mount } from '@vue/test-utils';
+import { GlFormGroup, GlFormInput } from '@gitlab/ui';
+import ParameterFormGroup from '~/feature_flags/components/strategies/parameter_form_group.vue';
+
+describe('~/feature_flags/strategies/parameter_form_group.vue', () => {
+ let wrapper;
+ let formGroup;
+ let slot;
+
+ beforeEach(() => {
+ wrapper = mount(ParameterFormGroup, {
+ propsData: { inputId: 'test-id', label: 'test' },
+ attrs: { description: 'test description' },
+ scopedSlots: {
+ default(props) {
+ return this.$createElement(GlFormInput, {
+ attrs: { id: props.inputId, 'data-testid': 'slot' },
+ });
+ },
+ },
+ });
+
+ formGroup = wrapper.find(GlFormGroup);
+ slot = wrapper.find('[data-testid="slot"]');
+ });
+
+ afterEach(() => {
+ if (wrapper?.destroy) {
+ wrapper.destroy();
+ }
+
+ wrapper = null;
+ });
+
+ it('should display the default slot', () => {
+ expect(slot.exists()).toBe(true);
+ });
+
+ it('should bind the input id to the slot', () => {
+ expect(slot.attributes('id')).toBe('test-id');
+ });
+
+ it('should bind the label-for to the input id', () => {
+ expect(formGroup.find('[for="test-id"]').exists()).toBe(true);
+ });
+
+ it('should bind extra attributes to the form group', () => {
+ expect(formGroup.attributes('description')).toBe('test description');
+ });
+});
diff --git a/spec/frontend/feature_flags/components/strategies/percent_rollout_spec.js b/spec/frontend/feature_flags/components/strategies/percent_rollout_spec.js
new file mode 100644
index 00000000000..de0b439f1c5
--- /dev/null
+++ b/spec/frontend/feature_flags/components/strategies/percent_rollout_spec.js
@@ -0,0 +1,78 @@
+import { mount } from '@vue/test-utils';
+import { GlFormInput } from '@gitlab/ui';
+import PercentRollout from '~/feature_flags/components/strategies/percent_rollout.vue';
+import ParameterFormGroup from '~/feature_flags/components/strategies/parameter_form_group.vue';
+import { PERCENT_ROLLOUT_GROUP_ID } from '~/feature_flags/constants';
+import { percentRolloutStrategy } from '../../mock_data';
+
+const DEFAULT_PROPS = {
+ strategy: percentRolloutStrategy,
+};
+
+describe('~/feature_flags/components/strategies/percent_rollout.vue', () => {
+ let wrapper;
+ let input;
+ let formGroup;
+
+ const factory = (props = {}) =>
+ mount(PercentRollout, { propsData: { ...DEFAULT_PROPS, ...props } });
+
+ afterEach(() => {
+ if (wrapper?.destroy) {
+ wrapper.destroy();
+ }
+
+ wrapper = null;
+ });
+
+ describe('with valid percentage', () => {
+ beforeEach(() => {
+ wrapper = factory();
+
+ input = wrapper.find(GlFormInput);
+ formGroup = wrapper.find(ParameterFormGroup);
+ });
+
+ it('displays the current value', () => {
+ expect(input.element.value).toBe(percentRolloutStrategy.parameters.percentage);
+ });
+
+ it('emits a change when the value changes', async () => {
+ input.setValue('75');
+ await wrapper.vm.$nextTick();
+ expect(wrapper.emitted('change')).toEqual([
+ [{ parameters: { percentage: '75', groupId: PERCENT_ROLLOUT_GROUP_ID } }],
+ ]);
+ });
+
+ it('does not show errors', () => {
+ expect(formGroup.attributes('state')).toBe('true');
+ });
+ });
+
+ describe('with percentage that is out of range', () => {
+ beforeEach(() => {
+ wrapper = factory({ strategy: { parameters: { percentage: '101' } } });
+
+ input = wrapper.find(GlFormInput);
+ formGroup = wrapper.find(ParameterFormGroup);
+ });
+
+ it('shows errors', () => {
+ expect(formGroup.attributes('state')).toBeUndefined();
+ });
+ });
+
+ describe('with percentage that is not a whole number', () => {
+ beforeEach(() => {
+ wrapper = factory({ strategy: { parameters: { percentage: '3.14' } } });
+
+ input = wrapper.find(GlFormInput);
+ formGroup = wrapper.find(ParameterFormGroup);
+ });
+
+ it('shows errors', () => {
+ expect(formGroup.attributes('state')).toBeUndefined();
+ });
+ });
+});
diff --git a/spec/frontend/feature_flags/components/strategies/users_with_id_spec.js b/spec/frontend/feature_flags/components/strategies/users_with_id_spec.js
new file mode 100644
index 00000000000..460df6ef2ec
--- /dev/null
+++ b/spec/frontend/feature_flags/components/strategies/users_with_id_spec.js
@@ -0,0 +1,38 @@
+import { mount } from '@vue/test-utils';
+import { GlFormTextarea } from '@gitlab/ui';
+import UsersWithId from '~/feature_flags/components/strategies/users_with_id.vue';
+import { usersWithIdStrategy } from '../../mock_data';
+
+const DEFAULT_PROPS = {
+ strategy: usersWithIdStrategy,
+};
+
+describe('~/feature_flags/components/users_with_id.vue', () => {
+ let wrapper;
+ let textarea;
+
+ const factory = (props = {}) => mount(UsersWithId, { propsData: { ...DEFAULT_PROPS, ...props } });
+
+ beforeEach(() => {
+ wrapper = factory();
+ textarea = wrapper.find(GlFormTextarea);
+ });
+
+ afterEach(() => {
+ if (wrapper?.destroy) {
+ wrapper.destroy();
+ }
+
+ wrapper = null;
+ });
+
+ it('should display the current value of the parameters', () => {
+ expect(textarea.element.value).toBe(usersWithIdStrategy.parameters.userIds);
+ });
+
+ it('should emit a change event when the IDs change', () => {
+ textarea.setValue('4,5,6');
+
+ expect(wrapper.emitted('change')).toEqual([[{ parameters: { userIds: '4,5,6' } }]]);
+ });
+});
diff --git a/spec/frontend/feature_flags/components/strategy_parameters_spec.js b/spec/frontend/feature_flags/components/strategy_parameters_spec.js
new file mode 100644
index 00000000000..314fb0f21f4
--- /dev/null
+++ b/spec/frontend/feature_flags/components/strategy_parameters_spec.js
@@ -0,0 +1,83 @@
+import { shallowMount } from '@vue/test-utils';
+import { last } from 'lodash';
+import {
+ ROLLOUT_STRATEGY_ALL_USERS,
+ ROLLOUT_STRATEGY_PERCENT_ROLLOUT,
+ ROLLOUT_STRATEGY_USER_ID,
+ ROLLOUT_STRATEGY_GITLAB_USER_LIST,
+} from '~/feature_flags/constants';
+import Default from '~/feature_flags/components/strategies/default.vue';
+import GitlabUserList from '~/feature_flags/components/strategies/gitlab_user_list.vue';
+import PercentRollout from '~/feature_flags/components/strategies/percent_rollout.vue';
+import UsersWithId from '~/feature_flags/components/strategies/users_with_id.vue';
+import StrategyParameters from '~/feature_flags/components/strategy_parameters.vue';
+import { allUsersStrategy, userList } from '../mock_data';
+
+const DEFAULT_PROPS = {
+ strategy: allUsersStrategy,
+ userLists: [userList],
+};
+
+describe('~/feature_flags/components/strategy_parameters.vue', () => {
+ let wrapper;
+
+ const factory = (props = {}) =>
+ shallowMount(StrategyParameters, {
+ propsData: {
+ ...DEFAULT_PROPS,
+ ...props,
+ },
+ });
+
+ afterEach(() => {
+ if (wrapper?.destroy) {
+ wrapper.destroy();
+ }
+
+ wrapper = null;
+ });
+
+ describe.each`
+ name | component
+ ${ROLLOUT_STRATEGY_ALL_USERS} | ${Default}
+ ${ROLLOUT_STRATEGY_PERCENT_ROLLOUT} | ${PercentRollout}
+ ${ROLLOUT_STRATEGY_USER_ID} | ${UsersWithId}
+ ${ROLLOUT_STRATEGY_GITLAB_USER_LIST} | ${GitlabUserList}
+ `('with $name', ({ name, component }) => {
+ let strategy;
+
+ beforeEach(() => {
+ strategy = { name, parameters: {} };
+ wrapper = factory({ strategy });
+ });
+
+ it('should show the correct component', () => {
+ expect(wrapper.contains(component)).toBe(true);
+ });
+
+ it('should emit changes from the lower component', () => {
+ const strategyParameterWrapper = wrapper.find(component);
+
+ strategyParameterWrapper.vm.$emit('change', { parameters: { foo: 'bar' } });
+
+ expect(last(wrapper.emitted('change'))).toEqual([
+ {
+ name,
+ parameters: { foo: 'bar' },
+ },
+ ]);
+ });
+ });
+
+ describe('pass through props', () => {
+ it('should pass through any extra props that might be needed', () => {
+ wrapper = factory({
+ strategy: {
+ name: ROLLOUT_STRATEGY_GITLAB_USER_LIST,
+ },
+ });
+
+ expect(wrapper.find(GitlabUserList).props('userLists')).toEqual([userList]);
+ });
+ });
+});
diff --git a/spec/frontend/feature_flags/components/strategy_spec.js b/spec/frontend/feature_flags/components/strategy_spec.js
new file mode 100644
index 00000000000..7d6700ba184
--- /dev/null
+++ b/spec/frontend/feature_flags/components/strategy_spec.js
@@ -0,0 +1,264 @@
+import { mount } from '@vue/test-utils';
+import { last } from 'lodash';
+import { GlAlert, GlFormSelect, GlLink, GlToken, GlButton } from '@gitlab/ui';
+import {
+ PERCENT_ROLLOUT_GROUP_ID,
+ ROLLOUT_STRATEGY_ALL_USERS,
+ ROLLOUT_STRATEGY_PERCENT_ROLLOUT,
+ ROLLOUT_STRATEGY_FLEXIBLE_ROLLOUT,
+ ROLLOUT_STRATEGY_USER_ID,
+ ROLLOUT_STRATEGY_GITLAB_USER_LIST,
+} from '~/feature_flags/constants';
+import Strategy from '~/feature_flags/components/strategy.vue';
+import NewEnvironmentsDropdown from '~/feature_flags/components/new_environments_dropdown.vue';
+import StrategyParameters from '~/feature_flags/components/strategy_parameters.vue';
+
+import { userList } from '../mock_data';
+
+const provide = {
+ strategyTypeDocsPagePath: 'link-to-strategy-docs',
+ environmentsScopeDocsPath: 'link-scope-docs',
+ environmentsEndpoint: '',
+};
+
+describe('Feature flags strategy', () => {
+ let wrapper;
+
+ const findStrategyParameters = () => wrapper.find(StrategyParameters);
+ const findDocsLinks = () => wrapper.findAll(GlLink);
+
+ const factory = (
+ opts = {
+ propsData: {
+ strategy: {},
+ index: 0,
+ userLists: [userList],
+ },
+ provide,
+ },
+ ) => {
+ if (wrapper) {
+ wrapper.destroy();
+ wrapper = null;
+ }
+ wrapper = mount(Strategy, opts);
+ };
+
+ afterEach(() => {
+ if (wrapper) {
+ wrapper.destroy();
+ wrapper = null;
+ }
+ });
+
+ describe('helper links', () => {
+ const propsData = { strategy: {}, index: 0, userLists: [userList] };
+ factory({ propsData, provide });
+
+ it('should display 2 helper links', () => {
+ const links = findDocsLinks();
+ expect(links.exists()).toBe(true);
+ expect(links.at(0).attributes('href')).toContain('docs');
+ expect(links.at(1).attributes('href')).toContain('docs');
+ });
+ });
+
+ describe.each`
+ name
+ ${ROLLOUT_STRATEGY_ALL_USERS}
+ ${ROLLOUT_STRATEGY_PERCENT_ROLLOUT}
+ ${ROLLOUT_STRATEGY_FLEXIBLE_ROLLOUT}
+ ${ROLLOUT_STRATEGY_USER_ID}
+ ${ROLLOUT_STRATEGY_GITLAB_USER_LIST}
+ `('with strategy $name', ({ name }) => {
+ let propsData;
+ let strategy;
+
+ beforeEach(() => {
+ strategy = { name, parameters: {}, scopes: [] };
+ propsData = { strategy, index: 0 };
+ factory({ propsData, provide });
+ return wrapper.vm.$nextTick();
+ });
+
+ it('should set the select to match the strategy name', () => {
+ expect(wrapper.find(GlFormSelect).element.value).toBe(name);
+ });
+
+ it('should emit a change if the parameters component does', () => {
+ findStrategyParameters().vm.$emit('change', { name, parameters: { test: 'parameters' } });
+ expect(last(wrapper.emitted('change'))).toEqual([
+ { name, parameters: { test: 'parameters' } },
+ ]);
+ });
+ });
+
+ describe('with the gradualRolloutByUserId strategy', () => {
+ let strategy;
+
+ beforeEach(() => {
+ strategy = {
+ name: ROLLOUT_STRATEGY_PERCENT_ROLLOUT,
+ parameters: { percentage: '50', groupId: 'default' },
+ scopes: [{ environmentScope: 'production' }],
+ };
+ const propsData = { strategy, index: 0 };
+ factory({ propsData, provide });
+ });
+
+ it('shows an alert asking users to consider using flexibleRollout instead', () => {
+ expect(wrapper.find(GlAlert).text()).toContain(
+ 'Consider using the more flexible "Percent rollout" strategy instead.',
+ );
+ });
+ });
+
+ describe('with a strategy', () => {
+ describe('with a single environment scope defined', () => {
+ let strategy;
+
+ beforeEach(() => {
+ strategy = {
+ name: ROLLOUT_STRATEGY_PERCENT_ROLLOUT,
+ parameters: { percentage: '50', groupId: 'default' },
+ scopes: [{ environmentScope: 'production' }],
+ };
+ const propsData = { strategy, index: 0 };
+ factory({ propsData, provide });
+ });
+
+ it('should revert to all-environments scope when last scope is removed', () => {
+ const token = wrapper.find(GlToken);
+ token.vm.$emit('close');
+ return wrapper.vm.$nextTick().then(() => {
+ expect(wrapper.findAll(GlToken)).toHaveLength(0);
+ expect(last(wrapper.emitted('change'))).toEqual([
+ {
+ name: ROLLOUT_STRATEGY_PERCENT_ROLLOUT,
+ parameters: { percentage: '50', groupId: PERCENT_ROLLOUT_GROUP_ID },
+ scopes: [{ environmentScope: '*' }],
+ },
+ ]);
+ });
+ });
+ });
+
+ describe('with an all-environments scope defined', () => {
+ let strategy;
+
+ beforeEach(() => {
+ strategy = {
+ name: ROLLOUT_STRATEGY_PERCENT_ROLLOUT,
+ parameters: { percentage: '50', groupId: PERCENT_ROLLOUT_GROUP_ID },
+ scopes: [{ environmentScope: '*' }],
+ };
+ const propsData = { strategy, index: 0 };
+ factory({ propsData, provide });
+ });
+
+ it('should change the parameters if a different strategy is chosen', () => {
+ const select = wrapper.find(GlFormSelect);
+ select.setValue(ROLLOUT_STRATEGY_ALL_USERS);
+ return wrapper.vm.$nextTick().then(() => {
+ expect(last(wrapper.emitted('change'))).toEqual([
+ {
+ name: ROLLOUT_STRATEGY_ALL_USERS,
+ parameters: {},
+ scopes: [{ environmentScope: '*' }],
+ },
+ ]);
+ });
+ });
+
+ it('should display selected scopes', () => {
+ const dropdown = wrapper.find(NewEnvironmentsDropdown);
+ dropdown.vm.$emit('add', 'production');
+ return wrapper.vm.$nextTick().then(() => {
+ expect(wrapper.findAll(GlToken)).toHaveLength(1);
+ expect(wrapper.find(GlToken).text()).toBe('production');
+ });
+ });
+
+ it('should display all selected scopes', () => {
+ const dropdown = wrapper.find(NewEnvironmentsDropdown);
+ dropdown.vm.$emit('add', 'production');
+ dropdown.vm.$emit('add', 'staging');
+ return wrapper.vm.$nextTick().then(() => {
+ const tokens = wrapper.findAll(GlToken);
+ expect(tokens).toHaveLength(2);
+ expect(tokens.at(0).text()).toBe('production');
+ expect(tokens.at(1).text()).toBe('staging');
+ });
+ });
+
+ it('should emit selected scopes', () => {
+ const dropdown = wrapper.find(NewEnvironmentsDropdown);
+ dropdown.vm.$emit('add', 'production');
+ return wrapper.vm.$nextTick().then(() => {
+ expect(last(wrapper.emitted('change'))).toEqual([
+ {
+ name: ROLLOUT_STRATEGY_PERCENT_ROLLOUT,
+ parameters: { percentage: '50', groupId: PERCENT_ROLLOUT_GROUP_ID },
+ scopes: [
+ { environmentScope: '*', shouldBeDestroyed: true },
+ { environmentScope: 'production' },
+ ],
+ },
+ ]);
+ });
+ });
+
+ it('should emit a delete if the delete button is clicked', () => {
+ wrapper.find(GlButton).vm.$emit('click');
+ expect(wrapper.emitted('delete')).toEqual([[]]);
+ });
+ });
+
+ describe('without scopes defined', () => {
+ beforeEach(() => {
+ const strategy = {
+ name: ROLLOUT_STRATEGY_PERCENT_ROLLOUT,
+ parameters: { percentage: '50', groupId: PERCENT_ROLLOUT_GROUP_ID },
+ scopes: [],
+ };
+ const propsData = { strategy, index: 0 };
+ factory({ propsData, provide });
+ });
+
+ it('should display selected scopes', () => {
+ const dropdown = wrapper.find(NewEnvironmentsDropdown);
+ dropdown.vm.$emit('add', 'production');
+ return wrapper.vm.$nextTick().then(() => {
+ expect(wrapper.findAll(GlToken)).toHaveLength(1);
+ expect(wrapper.find(GlToken).text()).toBe('production');
+ });
+ });
+
+ it('should display all selected scopes', () => {
+ const dropdown = wrapper.find(NewEnvironmentsDropdown);
+ dropdown.vm.$emit('add', 'production');
+ dropdown.vm.$emit('add', 'staging');
+ return wrapper.vm.$nextTick().then(() => {
+ const tokens = wrapper.findAll(GlToken);
+ expect(tokens).toHaveLength(2);
+ expect(tokens.at(0).text()).toBe('production');
+ expect(tokens.at(1).text()).toBe('staging');
+ });
+ });
+
+ it('should emit selected scopes', () => {
+ const dropdown = wrapper.find(NewEnvironmentsDropdown);
+ dropdown.vm.$emit('add', 'production');
+ return wrapper.vm.$nextTick().then(() => {
+ expect(last(wrapper.emitted('change'))).toEqual([
+ {
+ name: ROLLOUT_STRATEGY_PERCENT_ROLLOUT,
+ parameters: { percentage: '50', groupId: PERCENT_ROLLOUT_GROUP_ID },
+ scopes: [{ environmentScope: 'production' }],
+ },
+ ]);
+ });
+ });
+ });
+ });
+});
diff --git a/spec/frontend/feature_flags/components/user_lists_table_spec.js b/spec/frontend/feature_flags/components/user_lists_table_spec.js
new file mode 100644
index 00000000000..d6ced3be168
--- /dev/null
+++ b/spec/frontend/feature_flags/components/user_lists_table_spec.js
@@ -0,0 +1,98 @@
+import { mount } from '@vue/test-utils';
+import * as timeago from 'timeago.js';
+import { GlModal } from '@gitlab/ui';
+import UserListsTable from '~/feature_flags/components/user_lists_table.vue';
+import { userList } from '../mock_data';
+
+jest.mock('timeago.js', () => ({
+ format: jest.fn().mockReturnValue('2 weeks ago'),
+ register: jest.fn(),
+}));
+
+describe('User Lists Table', () => {
+ let wrapper;
+ let userLists;
+
+ beforeEach(() => {
+ userLists = new Array(5).fill(userList).map((x, i) => ({ ...x, id: i }));
+ wrapper = mount(UserListsTable, {
+ propsData: { userLists },
+ });
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('should display the details of a user list', () => {
+ expect(wrapper.find('[data-testid="ffUserListName"]').text()).toBe(userList.name);
+ expect(wrapper.find('[data-testid="ffUserListIds"]').text()).toBe(
+ userList.user_xids.replace(/,/g, ', '),
+ );
+ expect(wrapper.find('[data-testid="ffUserListTimestamp"]').text()).toBe('created 2 weeks ago');
+ expect(timeago.format).toHaveBeenCalledWith(userList.created_at);
+ });
+
+ it('should set the title for a tooltip on the created stamp', () => {
+ expect(wrapper.find('[data-testid="ffUserListTimestamp"]').attributes('title')).toBe(
+ 'Feb 4, 2020 8:13am GMT+0000',
+ );
+ });
+
+ it('should display a user list entry per user list', () => {
+ const lists = wrapper.findAll('[data-testid="ffUserList"]');
+ expect(lists).toHaveLength(5);
+ lists.wrappers.forEach(list => {
+ expect(list.find('[data-testid="ffUserListName"]').exists()).toBe(true);
+ expect(list.find('[data-testid="ffUserListIds"]').exists()).toBe(true);
+ expect(list.find('[data-testid="ffUserListTimestamp"]').exists()).toBe(true);
+ });
+ });
+
+ describe('edit button', () => {
+ it('should link to the path for the user list', () => {
+ expect(wrapper.find('[data-testid="edit-user-list"]').attributes('href')).toBe(userList.path);
+ });
+ });
+
+ describe('delete button', () => {
+ it('should display the confirmation modal', () => {
+ const modal = wrapper.find(GlModal);
+
+ wrapper.find('[data-testid="delete-user-list"]').trigger('click');
+
+ return wrapper.vm.$nextTick().then(() => {
+ expect(modal.text()).toContain(`Delete ${userList.name}?`);
+ expect(modal.text()).toContain(`User list ${userList.name} will be removed.`);
+ });
+ });
+ });
+
+ describe('confirmation modal', () => {
+ let modal;
+
+ beforeEach(() => {
+ modal = wrapper.find(GlModal);
+
+ wrapper.find('button').trigger('click');
+
+ return wrapper.vm.$nextTick();
+ });
+
+ it('should emit delete with list on confirmation', () => {
+ modal.find('[data-testid="modal-confirm"]').trigger('click');
+
+ return wrapper.vm.$nextTick().then(() => {
+ expect(wrapper.emitted('delete')).toEqual([[userLists[0]]]);
+ });
+ });
+
+ it('should not emit delete with list when not confirmed', () => {
+ modal.find('button').trigger('click');
+
+ return wrapper.vm.$nextTick().then(() => {
+ expect(wrapper.emitted('delete')).toBeUndefined();
+ });
+ });
+ });
+});
diff --git a/spec/frontend/feature_flags/mock_data.js b/spec/frontend/feature_flags/mock_data.js
new file mode 100644
index 00000000000..ed06ea059a7
--- /dev/null
+++ b/spec/frontend/feature_flags/mock_data.js
@@ -0,0 +1,155 @@
+import {
+ ROLLOUT_STRATEGY_ALL_USERS,
+ ROLLOUT_STRATEGY_PERCENT_ROLLOUT,
+ ROLLOUT_STRATEGY_FLEXIBLE_ROLLOUT,
+ ROLLOUT_STRATEGY_GITLAB_USER_LIST,
+ ROLLOUT_STRATEGY_USER_ID,
+} from '~/feature_flags/constants';
+
+export const featureFlag = {
+ id: 1,
+ active: true,
+ created_at: '2018-12-12T22:07:31.401Z',
+ updated_at: '2018-12-12T22:07:31.401Z',
+ name: 'test flag',
+ description: 'flag for tests',
+ destroy_path: 'feature_flags/1',
+ update_path: 'feature_flags/1',
+ edit_path: 'feature_flags/1/edit',
+ scopes: [
+ {
+ id: 1,
+ active: true,
+ environment_scope: '*',
+ can_update: true,
+ protected: false,
+ created_at: '2019-01-14T06:41:40.987Z',
+ updated_at: '2019-01-14T06:41:40.987Z',
+ strategies: [
+ {
+ name: ROLLOUT_STRATEGY_ALL_USERS,
+ parameters: {},
+ },
+ ],
+ },
+ {
+ id: 2,
+ active: false,
+ environment_scope: 'production',
+ can_update: true,
+ protected: false,
+ created_at: '2019-01-14T06:41:40.987Z',
+ updated_at: '2019-01-14T06:41:40.987Z',
+ strategies: [
+ {
+ name: ROLLOUT_STRATEGY_ALL_USERS,
+ parameters: {},
+ },
+ ],
+ },
+ {
+ id: 3,
+ active: false,
+ environment_scope: 'review/*',
+ can_update: true,
+ protected: false,
+ created_at: '2019-01-14T06:41:40.987Z',
+ updated_at: '2019-01-14T06:41:40.987Z',
+ strategies: [
+ {
+ name: ROLLOUT_STRATEGY_ALL_USERS,
+ parameters: {},
+ },
+ ],
+ },
+ {
+ id: 4,
+ active: true,
+ environment_scope: 'development',
+ can_update: true,
+ protected: false,
+ created_at: '2019-01-14T06:41:40.987Z',
+ updated_at: '2019-01-14T06:41:40.987Z',
+ strategies: [
+ {
+ name: ROLLOUT_STRATEGY_PERCENT_ROLLOUT,
+ parameters: {
+ percentage: '86',
+ },
+ },
+ ],
+ },
+ {
+ id: 5,
+ active: true,
+ environment_scope: 'development',
+ can_update: true,
+ protected: false,
+ created_at: '2019-01-14T06:41:40.987Z',
+ updated_at: '2019-01-14T06:41:40.987Z',
+ strategies: [
+ {
+ name: ROLLOUT_STRATEGY_FLEXIBLE_ROLLOUT,
+ parameters: {
+ rollout: '42',
+ stickiness: 'DEFAULT',
+ },
+ },
+ ],
+ },
+ ],
+};
+
+export const getRequestData = {
+ feature_flags: [featureFlag],
+ count: {
+ all: 1,
+ disabled: 1,
+ enabled: 0,
+ },
+};
+
+export const rotateData = { token: 'oP6sCNRqtRHmpy1gw2-F' };
+
+export const userList = {
+ name: 'test_users',
+ user_xids: 'user3,user4,user5',
+ id: 2,
+ iid: 2,
+ project_id: 1,
+ created_at: '2020-02-04T08:13:10.507Z',
+ updated_at: '2020-02-04T08:13:10.507Z',
+ path: '/path/to/user/list',
+ edit_path: '/path/to/user/list/edit',
+};
+
+export const userListStrategy = {
+ name: ROLLOUT_STRATEGY_GITLAB_USER_LIST,
+ parameters: {},
+ scopes: [],
+ userListId: userList.id,
+};
+
+export const percentRolloutStrategy = {
+ name: ROLLOUT_STRATEGY_PERCENT_ROLLOUT,
+ parameters: { percentage: '50', groupId: 'default' },
+ scopes: [],
+};
+
+export const flexibleRolloutStrategy = {
+ name: ROLLOUT_STRATEGY_FLEXIBLE_ROLLOUT,
+ parameters: { rollout: '50', groupId: 'default', stickiness: 'DEFAULT' },
+ scopes: [],
+};
+
+export const usersWithIdStrategy = {
+ name: ROLLOUT_STRATEGY_USER_ID,
+ parameters: { userIds: '1,2,3' },
+ scopes: [],
+};
+
+export const allUsersStrategy = {
+ name: ROLLOUT_STRATEGY_ALL_USERS,
+ parameters: {},
+ scopes: [],
+};
diff --git a/spec/frontend/feature_flags/store/edit/actions_spec.js b/spec/frontend/feature_flags/store/edit/actions_spec.js
new file mode 100644
index 00000000000..9d764799d09
--- /dev/null
+++ b/spec/frontend/feature_flags/store/edit/actions_spec.js
@@ -0,0 +1,303 @@
+import MockAdapter from 'axios-mock-adapter';
+import testAction from 'helpers/vuex_action_helper';
+import { TEST_HOST } from 'spec/test_constants';
+import {
+ updateFeatureFlag,
+ requestUpdateFeatureFlag,
+ receiveUpdateFeatureFlagSuccess,
+ receiveUpdateFeatureFlagError,
+ fetchFeatureFlag,
+ requestFeatureFlag,
+ receiveFeatureFlagSuccess,
+ receiveFeatureFlagError,
+ toggleActive,
+} from '~/feature_flags/store/edit/actions';
+import state from '~/feature_flags/store/edit/state';
+import { mapStrategiesToRails, mapFromScopesViewModel } from '~/feature_flags/store/helpers';
+import {
+ NEW_VERSION_FLAG,
+ LEGACY_FLAG,
+ ROLLOUT_STRATEGY_ALL_USERS,
+} from '~/feature_flags/constants';
+import * as types from '~/feature_flags/store/edit/mutation_types';
+import axios from '~/lib/utils/axios_utils';
+
+jest.mock('~/lib/utils/url_utility');
+
+describe('Feature flags Edit Module actions', () => {
+ let mockedState;
+
+ beforeEach(() => {
+ mockedState = state({ endpoint: 'feature_flags.json', path: '/feature_flags' });
+ });
+
+ describe('updateFeatureFlag', () => {
+ let mock;
+
+ beforeEach(() => {
+ mockedState.endpoint = `${TEST_HOST}/endpoint.json`;
+ mock = new MockAdapter(axios);
+ });
+
+ afterEach(() => {
+ mock.restore();
+ });
+
+ describe('success', () => {
+ it('dispatches requestUpdateFeatureFlag and receiveUpdateFeatureFlagSuccess ', done => {
+ const featureFlag = {
+ name: 'feature_flag',
+ description: 'feature flag',
+ scopes: [
+ {
+ id: '1',
+ environmentScope: '*',
+ active: true,
+ shouldBeDestroyed: false,
+ canUpdate: true,
+ protected: false,
+ rolloutStrategy: ROLLOUT_STRATEGY_ALL_USERS,
+ },
+ ],
+ version: LEGACY_FLAG,
+ active: true,
+ };
+ mock.onPut(mockedState.endpoint, mapFromScopesViewModel(featureFlag)).replyOnce(200);
+
+ testAction(
+ updateFeatureFlag,
+ featureFlag,
+ mockedState,
+ [],
+ [
+ {
+ type: 'requestUpdateFeatureFlag',
+ },
+ {
+ type: 'receiveUpdateFeatureFlagSuccess',
+ },
+ ],
+ done,
+ );
+ });
+ it('handles new version flags as well', done => {
+ const featureFlag = {
+ name: 'name',
+ description: 'description',
+ active: true,
+ version: NEW_VERSION_FLAG,
+ strategies: [
+ {
+ name: ROLLOUT_STRATEGY_ALL_USERS,
+ parameters: {},
+ id: 1,
+ scopes: [{ id: 1, environmentScope: 'environmentScope', shouldBeDestroyed: false }],
+ shouldBeDestroyed: false,
+ },
+ ],
+ };
+ mock.onPut(mockedState.endpoint, mapStrategiesToRails(featureFlag)).replyOnce(200);
+
+ testAction(
+ updateFeatureFlag,
+ featureFlag,
+ mockedState,
+ [],
+ [
+ {
+ type: 'requestUpdateFeatureFlag',
+ },
+ {
+ type: 'receiveUpdateFeatureFlagSuccess',
+ },
+ ],
+ done,
+ );
+ });
+ });
+
+ describe('error', () => {
+ it('dispatches requestUpdateFeatureFlag and receiveUpdateFeatureFlagError ', done => {
+ mock.onPut(`${TEST_HOST}/endpoint.json`).replyOnce(500, { message: [] });
+
+ testAction(
+ updateFeatureFlag,
+ {
+ name: 'feature_flag',
+ description: 'feature flag',
+ scopes: [{ environment_scope: '*', active: true }],
+ },
+ mockedState,
+ [],
+ [
+ {
+ type: 'requestUpdateFeatureFlag',
+ },
+ {
+ type: 'receiveUpdateFeatureFlagError',
+ payload: { message: [] },
+ },
+ ],
+ done,
+ );
+ });
+ });
+ });
+
+ describe('requestUpdateFeatureFlag', () => {
+ it('should commit REQUEST_UPDATE_FEATURE_FLAG mutation', done => {
+ testAction(
+ requestUpdateFeatureFlag,
+ null,
+ mockedState,
+ [{ type: types.REQUEST_UPDATE_FEATURE_FLAG }],
+ [],
+ done,
+ );
+ });
+ });
+
+ describe('receiveUpdateFeatureFlagSuccess', () => {
+ it('should commit RECEIVE_UPDATE_FEATURE_FLAG_SUCCESS mutation', done => {
+ testAction(
+ receiveUpdateFeatureFlagSuccess,
+ null,
+ mockedState,
+ [
+ {
+ type: types.RECEIVE_UPDATE_FEATURE_FLAG_SUCCESS,
+ },
+ ],
+ [],
+ done,
+ );
+ });
+ });
+
+ describe('receiveUpdateFeatureFlagError', () => {
+ it('should commit RECEIVE_UPDATE_FEATURE_FLAG_ERROR mutation', done => {
+ testAction(
+ receiveUpdateFeatureFlagError,
+ 'There was an error',
+ mockedState,
+ [{ type: types.RECEIVE_UPDATE_FEATURE_FLAG_ERROR, payload: 'There was an error' }],
+ [],
+ done,
+ );
+ });
+ });
+
+ describe('fetchFeatureFlag', () => {
+ let mock;
+
+ beforeEach(() => {
+ mockedState.endpoint = `${TEST_HOST}/endpoint.json`;
+ mock = new MockAdapter(axios);
+ });
+
+ afterEach(() => {
+ mock.restore();
+ });
+
+ describe('success', () => {
+ it('dispatches requestFeatureFlag and receiveFeatureFlagSuccess ', done => {
+ mock.onGet(`${TEST_HOST}/endpoint.json`).replyOnce(200, { id: 1 });
+
+ testAction(
+ fetchFeatureFlag,
+ { id: 1 },
+ mockedState,
+ [],
+ [
+ {
+ type: 'requestFeatureFlag',
+ },
+ {
+ type: 'receiveFeatureFlagSuccess',
+ payload: { id: 1 },
+ },
+ ],
+ done,
+ );
+ });
+ });
+
+ describe('error', () => {
+ it('dispatches requestFeatureFlag and receiveUpdateFeatureFlagError ', done => {
+ mock.onGet(`${TEST_HOST}/endpoint.json`, {}).replyOnce(500, {});
+
+ testAction(
+ fetchFeatureFlag,
+ null,
+ mockedState,
+ [],
+ [
+ {
+ type: 'requestFeatureFlag',
+ },
+ {
+ type: 'receiveFeatureFlagError',
+ },
+ ],
+ done,
+ );
+ });
+ });
+ });
+
+ describe('requestFeatureFlag', () => {
+ it('should commit REQUEST_FEATURE_FLAG mutation', done => {
+ testAction(
+ requestFeatureFlag,
+ null,
+ mockedState,
+ [{ type: types.REQUEST_FEATURE_FLAG }],
+ [],
+ done,
+ );
+ });
+ });
+
+ describe('receiveFeatureFlagSuccess', () => {
+ it('should commit RECEIVE_FEATURE_FLAG_SUCCESS mutation', done => {
+ testAction(
+ receiveFeatureFlagSuccess,
+ { id: 1 },
+ mockedState,
+ [{ type: types.RECEIVE_FEATURE_FLAG_SUCCESS, payload: { id: 1 } }],
+ [],
+ done,
+ );
+ });
+ });
+
+ describe('receiveFeatureFlagError', () => {
+ it('should commit RECEIVE_FEATURE_FLAG_ERROR mutation', done => {
+ testAction(
+ receiveFeatureFlagError,
+ null,
+ mockedState,
+ [
+ {
+ type: types.RECEIVE_FEATURE_FLAG_ERROR,
+ },
+ ],
+ [],
+ done,
+ );
+ });
+ });
+
+ describe('toggelActive', () => {
+ it('should commit TOGGLE_ACTIVE mutation', done => {
+ testAction(
+ toggleActive,
+ true,
+ mockedState,
+ [{ type: types.TOGGLE_ACTIVE, payload: true }],
+ [],
+ done,
+ );
+ });
+ });
+});
diff --git a/spec/frontend/feature_flags/store/edit/mutations_spec.js b/spec/frontend/feature_flags/store/edit/mutations_spec.js
new file mode 100644
index 00000000000..1d817fb8004
--- /dev/null
+++ b/spec/frontend/feature_flags/store/edit/mutations_spec.js
@@ -0,0 +1,134 @@
+import state from '~/feature_flags/store/edit/state';
+import mutations from '~/feature_flags/store/edit/mutations';
+import * as types from '~/feature_flags/store/edit/mutation_types';
+
+describe('Feature flags Edit Module Mutations', () => {
+ let stateCopy;
+
+ beforeEach(() => {
+ stateCopy = state({ endpoint: 'feature_flags.json', path: '/feature_flags' });
+ });
+
+ describe('REQUEST_FEATURE_FLAG', () => {
+ it('should set isLoading to true', () => {
+ mutations[types.REQUEST_FEATURE_FLAG](stateCopy);
+
+ expect(stateCopy.isLoading).toEqual(true);
+ });
+
+ it('should set error to an empty array', () => {
+ mutations[types.REQUEST_FEATURE_FLAG](stateCopy);
+
+ expect(stateCopy.error).toEqual([]);
+ });
+ });
+
+ describe('RECEIVE_FEATURE_FLAG_SUCCESS', () => {
+ const data = {
+ name: '*',
+ description: 'All environments',
+ scopes: [{ id: 1 }],
+ iid: 5,
+ version: 'new_version_flag',
+ strategies: [
+ { id: 1, scopes: [{ environment_scope: '*' }], name: 'default', parameters: {} },
+ ],
+ };
+
+ beforeEach(() => {
+ mutations[types.RECEIVE_FEATURE_FLAG_SUCCESS](stateCopy, data);
+ });
+
+ it('should set isLoading to false', () => {
+ expect(stateCopy.isLoading).toEqual(false);
+ });
+
+ it('should set hasError to false', () => {
+ expect(stateCopy.hasError).toEqual(false);
+ });
+
+ it('should set name with the provided one', () => {
+ expect(stateCopy.name).toEqual(data.name);
+ });
+
+ it('should set description with the provided one', () => {
+ expect(stateCopy.description).toEqual(data.description);
+ });
+
+ it('should set scope with the provided one', () => {
+ expect(stateCopy.scope).toEqual(data.scope);
+ });
+
+ it('should set the iid to the provided one', () => {
+ expect(stateCopy.iid).toEqual(data.iid);
+ });
+
+ it('should set the version to the provided one', () => {
+ expect(stateCopy.version).toBe('new_version_flag');
+ });
+
+ it('should set the strategies to the provided one', () => {
+ expect(stateCopy.strategies).toEqual([
+ {
+ id: 1,
+ scopes: [{ environmentScope: '*', shouldBeDestroyed: false }],
+ name: 'default',
+ parameters: {},
+ shouldBeDestroyed: false,
+ },
+ ]);
+ });
+ });
+
+ describe('RECEIVE_FEATURE_FLAG_ERROR', () => {
+ beforeEach(() => {
+ mutations[types.RECEIVE_FEATURE_FLAG_ERROR](stateCopy);
+ });
+
+ it('should set isLoading to false', () => {
+ expect(stateCopy.isLoading).toEqual(false);
+ });
+
+ it('should set hasError to true', () => {
+ expect(stateCopy.hasError).toEqual(true);
+ });
+ });
+
+ describe('REQUEST_UPDATE_FEATURE_FLAG', () => {
+ beforeEach(() => {
+ mutations[types.REQUEST_UPDATE_FEATURE_FLAG](stateCopy);
+ });
+
+ it('should set isSendingRequest to true', () => {
+ expect(stateCopy.isSendingRequest).toEqual(true);
+ });
+
+ it('should set error to an empty array', () => {
+ expect(stateCopy.error).toEqual([]);
+ });
+ });
+
+ describe('RECEIVE_UPDATE_FEATURE_FLAG_SUCCESS', () => {
+ it('should set isSendingRequest to false', () => {
+ mutations[types.RECEIVE_UPDATE_FEATURE_FLAG_SUCCESS](stateCopy);
+
+ expect(stateCopy.isSendingRequest).toEqual(false);
+ });
+ });
+
+ describe('RECEIVE_UPDATE_FEATURE_FLAG_ERROR', () => {
+ beforeEach(() => {
+ mutations[types.RECEIVE_UPDATE_FEATURE_FLAG_ERROR](stateCopy, {
+ message: ['Name is required'],
+ });
+ });
+
+ it('should set isSendingRequest to false', () => {
+ expect(stateCopy.isSendingRequest).toEqual(false);
+ });
+
+ it('should set error to the given message', () => {
+ expect(stateCopy.error).toEqual(['Name is required']);
+ });
+ });
+});
diff --git a/spec/frontend/feature_flags/store/helpers_spec.js b/spec/frontend/feature_flags/store/helpers_spec.js
new file mode 100644
index 00000000000..301b1d09fcc
--- /dev/null
+++ b/spec/frontend/feature_flags/store/helpers_spec.js
@@ -0,0 +1,514 @@
+import { uniqueId } from 'lodash';
+import {
+ mapToScopesViewModel,
+ mapFromScopesViewModel,
+ createNewEnvironmentScope,
+ mapStrategiesToViewModel,
+ mapStrategiesToRails,
+} from '~/feature_flags/store/helpers';
+import {
+ ROLLOUT_STRATEGY_ALL_USERS,
+ ROLLOUT_STRATEGY_PERCENT_ROLLOUT,
+ ROLLOUT_STRATEGY_USER_ID,
+ PERCENT_ROLLOUT_GROUP_ID,
+ INTERNAL_ID_PREFIX,
+ DEFAULT_PERCENT_ROLLOUT,
+ LEGACY_FLAG,
+ NEW_VERSION_FLAG,
+} from '~/feature_flags/constants';
+
+describe('feature flags helpers spec', () => {
+ describe('mapToScopesViewModel', () => {
+ it('converts the data object from the Rails API into something more usable by Vue', () => {
+ const input = [
+ {
+ id: 3,
+ environment_scope: 'environment_scope',
+ active: true,
+ can_update: true,
+ protected: true,
+ strategies: [
+ {
+ name: ROLLOUT_STRATEGY_PERCENT_ROLLOUT,
+ parameters: {
+ percentage: '56',
+ },
+ },
+ {
+ name: ROLLOUT_STRATEGY_USER_ID,
+ parameters: {
+ userIds: '123,234',
+ },
+ },
+ ],
+
+ _destroy: true,
+ },
+ ];
+
+ const expected = [
+ expect.objectContaining({
+ id: 3,
+ environmentScope: 'environment_scope',
+ active: true,
+ canUpdate: true,
+ protected: true,
+ rolloutStrategy: ROLLOUT_STRATEGY_PERCENT_ROLLOUT,
+ rolloutPercentage: '56',
+ rolloutUserIds: '123, 234',
+ shouldBeDestroyed: true,
+ }),
+ ];
+
+ const actual = mapToScopesViewModel(input);
+
+ expect(actual).toEqual(expected);
+ });
+
+ it('returns Boolean properties even when their Rails counterparts were not provided (are `undefined`)', () => {
+ const input = [
+ {
+ id: 3,
+ environment_scope: 'environment_scope',
+ },
+ ];
+
+ const [result] = mapToScopesViewModel(input);
+
+ expect(result).toEqual(
+ expect.objectContaining({
+ active: false,
+ canUpdate: false,
+ protected: false,
+ shouldBeDestroyed: false,
+ }),
+ );
+ });
+
+ it('returns an empty array if null or undefined is provided as a parameter', () => {
+ expect(mapToScopesViewModel(null)).toEqual([]);
+ expect(mapToScopesViewModel(undefined)).toEqual([]);
+ });
+
+ describe('with user IDs per environment', () => {
+ let oldGon;
+
+ beforeEach(() => {
+ oldGon = window.gon;
+ window.gon = { features: { featureFlagsUsersPerEnvironment: true } };
+ });
+
+ afterEach(() => {
+ window.gon = oldGon;
+ });
+
+ it('sets the user IDs as a comma separated string', () => {
+ const input = [
+ {
+ id: 3,
+ environment_scope: 'environment_scope',
+ active: true,
+ can_update: true,
+ protected: true,
+ strategies: [
+ {
+ name: ROLLOUT_STRATEGY_PERCENT_ROLLOUT,
+ parameters: {
+ percentage: '56',
+ },
+ },
+ {
+ name: ROLLOUT_STRATEGY_USER_ID,
+ parameters: {
+ userIds: '123,234',
+ },
+ },
+ ],
+
+ _destroy: true,
+ },
+ ];
+
+ const expected = [
+ {
+ id: 3,
+ environmentScope: 'environment_scope',
+ active: true,
+ canUpdate: true,
+ protected: true,
+ rolloutStrategy: ROLLOUT_STRATEGY_PERCENT_ROLLOUT,
+ rolloutPercentage: '56',
+ rolloutUserIds: '123, 234',
+ shouldBeDestroyed: true,
+ shouldIncludeUserIds: true,
+ },
+ ];
+
+ const actual = mapToScopesViewModel(input);
+
+ expect(actual).toEqual(expected);
+ });
+ });
+ });
+
+ describe('mapFromScopesViewModel', () => {
+ it('converts the object emitted from the Vue component into an object than is in the right format to be submitted to the Rails API', () => {
+ const input = {
+ name: 'name',
+ description: 'description',
+ active: true,
+ scopes: [
+ {
+ id: 4,
+ environmentScope: 'environmentScope',
+ active: true,
+ canUpdate: true,
+ protected: true,
+ shouldBeDestroyed: true,
+ shouldIncludeUserIds: true,
+ rolloutStrategy: ROLLOUT_STRATEGY_PERCENT_ROLLOUT,
+ rolloutPercentage: '48',
+ rolloutUserIds: '123, 234',
+ },
+ ],
+ };
+
+ const expected = {
+ operations_feature_flag: {
+ name: 'name',
+ description: 'description',
+ active: true,
+ version: LEGACY_FLAG,
+ scopes_attributes: [
+ {
+ id: 4,
+ environment_scope: 'environmentScope',
+ active: true,
+ can_update: true,
+ protected: true,
+ _destroy: true,
+ strategies: [
+ {
+ name: ROLLOUT_STRATEGY_PERCENT_ROLLOUT,
+ parameters: {
+ groupId: PERCENT_ROLLOUT_GROUP_ID,
+ percentage: '48',
+ },
+ },
+ {
+ name: ROLLOUT_STRATEGY_USER_ID,
+ parameters: {
+ userIds: '123,234',
+ },
+ },
+ ],
+ },
+ ],
+ },
+ };
+
+ const actual = mapFromScopesViewModel(input);
+
+ expect(actual).toEqual(expected);
+ });
+
+ it('should strip out internal IDs', () => {
+ const input = {
+ scopes: [{ id: 3 }, { id: uniqueId(INTERNAL_ID_PREFIX) }],
+ };
+
+ const result = mapFromScopesViewModel(input);
+ const [realId, internalId] = result.operations_feature_flag.scopes_attributes;
+
+ expect(realId.id).toBe(3);
+ expect(internalId.id).toBeUndefined();
+ });
+
+ it('returns scopes_attributes as [] if param.scopes is null or undefined', () => {
+ let {
+ operations_feature_flag: { scopes_attributes: actualScopes },
+ } = mapFromScopesViewModel({ scopes: null });
+
+ expect(actualScopes).toEqual([]);
+
+ ({
+ operations_feature_flag: { scopes_attributes: actualScopes },
+ } = mapFromScopesViewModel({ scopes: undefined }));
+
+ expect(actualScopes).toEqual([]);
+ });
+ describe('with user IDs per environment', () => {
+ it('sets the user IDs as a comma separated string', () => {
+ const input = {
+ name: 'name',
+ description: 'description',
+ active: true,
+ scopes: [
+ {
+ id: 4,
+ environmentScope: 'environmentScope',
+ active: true,
+ canUpdate: true,
+ protected: true,
+ shouldBeDestroyed: true,
+ rolloutStrategy: ROLLOUT_STRATEGY_PERCENT_ROLLOUT,
+ rolloutPercentage: '48',
+ rolloutUserIds: '123, 234',
+ shouldIncludeUserIds: true,
+ },
+ ],
+ };
+
+ const expected = {
+ operations_feature_flag: {
+ name: 'name',
+ description: 'description',
+ version: LEGACY_FLAG,
+ active: true,
+ scopes_attributes: [
+ {
+ id: 4,
+ environment_scope: 'environmentScope',
+ active: true,
+ can_update: true,
+ protected: true,
+ _destroy: true,
+ strategies: [
+ {
+ name: ROLLOUT_STRATEGY_PERCENT_ROLLOUT,
+ parameters: {
+ groupId: PERCENT_ROLLOUT_GROUP_ID,
+ percentage: '48',
+ },
+ },
+ {
+ name: ROLLOUT_STRATEGY_USER_ID,
+ parameters: {
+ userIds: '123,234',
+ },
+ },
+ ],
+ },
+ ],
+ },
+ };
+
+ const actual = mapFromScopesViewModel(input);
+
+ expect(actual).toEqual(expected);
+ });
+ });
+ });
+
+ describe('createNewEnvironmentScope', () => {
+ it('should return a new environment scope object populated with the default options', () => {
+ const expected = {
+ environmentScope: '',
+ active: false,
+ id: expect.stringContaining(INTERNAL_ID_PREFIX),
+ rolloutStrategy: ROLLOUT_STRATEGY_ALL_USERS,
+ rolloutPercentage: DEFAULT_PERCENT_ROLLOUT,
+ rolloutUserIds: '',
+ };
+
+ const actual = createNewEnvironmentScope();
+
+ expect(actual).toEqual(expected);
+ });
+
+ it('should return a new environment scope object with overrides applied', () => {
+ const overrides = {
+ environmentScope: 'environmentScope',
+ active: true,
+ };
+
+ const expected = {
+ environmentScope: 'environmentScope',
+ active: true,
+ id: expect.stringContaining(INTERNAL_ID_PREFIX),
+ rolloutStrategy: ROLLOUT_STRATEGY_ALL_USERS,
+ rolloutPercentage: DEFAULT_PERCENT_ROLLOUT,
+ rolloutUserIds: '',
+ };
+
+ const actual = createNewEnvironmentScope(overrides);
+
+ expect(actual).toEqual(expected);
+ });
+
+ it('sets canUpdate and protected when called with featureFlagPermissions=true', () => {
+ expect(createNewEnvironmentScope({}, true)).toEqual(
+ expect.objectContaining({
+ canUpdate: true,
+ protected: false,
+ }),
+ );
+ });
+ });
+
+ describe('mapStrategiesToViewModel', () => {
+ it('should map rails casing to view model casing', () => {
+ expect(
+ mapStrategiesToViewModel([
+ {
+ id: '1',
+ name: 'default',
+ parameters: {},
+ scopes: [
+ {
+ environment_scope: '*',
+ id: '1',
+ },
+ ],
+ },
+ ]),
+ ).toEqual([
+ {
+ id: '1',
+ name: 'default',
+ parameters: {},
+ shouldBeDestroyed: false,
+ scopes: [
+ {
+ shouldBeDestroyed: false,
+ environmentScope: '*',
+ id: '1',
+ },
+ ],
+ },
+ ]);
+ });
+
+ it('inserts spaces between user ids', () => {
+ const strategy = mapStrategiesToViewModel([
+ {
+ id: '1',
+ name: 'userWithId',
+ parameters: { userIds: 'user1,user2,user3' },
+ scopes: [],
+ },
+ ])[0];
+
+ expect(strategy.parameters).toEqual({ userIds: 'user1, user2, user3' });
+ });
+ });
+
+ describe('mapStrategiesToRails', () => {
+ it('should map rails casing to view model casing', () => {
+ expect(
+ mapStrategiesToRails({
+ name: 'test',
+ description: 'test description',
+ version: NEW_VERSION_FLAG,
+ active: true,
+ strategies: [
+ {
+ id: '1',
+ name: 'default',
+ parameters: {},
+ shouldBeDestroyed: true,
+ scopes: [
+ {
+ environmentScope: '*',
+ id: '1',
+ shouldBeDestroyed: true,
+ },
+ ],
+ },
+ ],
+ }),
+ ).toEqual({
+ operations_feature_flag: {
+ name: 'test',
+ description: 'test description',
+ version: NEW_VERSION_FLAG,
+ active: true,
+ strategies_attributes: [
+ {
+ id: '1',
+ name: 'default',
+ parameters: {},
+ _destroy: true,
+ scopes_attributes: [
+ {
+ environment_scope: '*',
+ id: '1',
+ _destroy: true,
+ },
+ ],
+ },
+ ],
+ },
+ });
+ });
+
+ it('should insert a default * scope if there are none', () => {
+ expect(
+ mapStrategiesToRails({
+ name: 'test',
+ description: 'test description',
+ version: NEW_VERSION_FLAG,
+ active: true,
+ strategies: [
+ {
+ id: '1',
+ name: 'default',
+ parameters: {},
+ scopes: [],
+ },
+ ],
+ }),
+ ).toEqual({
+ operations_feature_flag: {
+ name: 'test',
+ description: 'test description',
+ version: NEW_VERSION_FLAG,
+ active: true,
+ strategies_attributes: [
+ {
+ id: '1',
+ name: 'default',
+ parameters: {},
+ scopes_attributes: [
+ {
+ environment_scope: '*',
+ },
+ ],
+ },
+ ],
+ },
+ });
+ });
+
+ it('removes white space between user ids', () => {
+ const result = mapStrategiesToRails({
+ name: 'test',
+ version: NEW_VERSION_FLAG,
+ active: true,
+ strategies: [
+ {
+ id: '1',
+ name: 'userWithId',
+ parameters: { userIds: 'user1, user2, user3' },
+ scopes: [],
+ },
+ ],
+ });
+
+ const strategyAttrs = result.operations_feature_flag.strategies_attributes[0];
+
+ expect(strategyAttrs.parameters).toEqual({ userIds: 'user1,user2,user3' });
+ });
+
+ it('preserves the value of active', () => {
+ const result = mapStrategiesToRails({
+ name: 'test',
+ version: NEW_VERSION_FLAG,
+ active: false,
+ strategies: [],
+ });
+
+ expect(result.operations_feature_flag.active).toBe(false);
+ });
+ });
+});
diff --git a/spec/frontend/feature_flags/store/index/actions_spec.js b/spec/frontend/feature_flags/store/index/actions_spec.js
new file mode 100644
index 00000000000..d223bb2c292
--- /dev/null
+++ b/spec/frontend/feature_flags/store/index/actions_spec.js
@@ -0,0 +1,563 @@
+import MockAdapter from 'axios-mock-adapter';
+import testAction from 'helpers/vuex_action_helper';
+import { TEST_HOST } from 'spec/test_constants';
+import Api from '~/api';
+import {
+ requestFeatureFlags,
+ receiveFeatureFlagsSuccess,
+ receiveFeatureFlagsError,
+ fetchFeatureFlags,
+ setFeatureFlagsOptions,
+ rotateInstanceId,
+ requestRotateInstanceId,
+ receiveRotateInstanceIdSuccess,
+ receiveRotateInstanceIdError,
+ toggleFeatureFlag,
+ updateFeatureFlag,
+ receiveUpdateFeatureFlagSuccess,
+ receiveUpdateFeatureFlagError,
+ requestUserLists,
+ receiveUserListsSuccess,
+ receiveUserListsError,
+ fetchUserLists,
+ deleteUserList,
+ receiveDeleteUserListError,
+ clearAlert,
+} from '~/feature_flags/store/index/actions';
+import { mapToScopesViewModel } from '~/feature_flags/store/helpers';
+import state from '~/feature_flags/store/index/state';
+import * as types from '~/feature_flags/store/index/mutation_types';
+import axios from '~/lib/utils/axios_utils';
+import { getRequestData, rotateData, featureFlag, userList } from '../../mock_data';
+
+jest.mock('~/api.js');
+
+describe('Feature flags actions', () => {
+ let mockedState;
+
+ beforeEach(() => {
+ mockedState = state({});
+ });
+
+ describe('setFeatureFlagsOptions', () => {
+ it('should commit SET_FEATURE_FLAGS_OPTIONS mutation', done => {
+ testAction(
+ setFeatureFlagsOptions,
+ { page: '1', scope: 'all' },
+ mockedState,
+ [{ type: types.SET_FEATURE_FLAGS_OPTIONS, payload: { page: '1', scope: 'all' } }],
+ [],
+ done,
+ );
+ });
+ });
+
+ describe('fetchFeatureFlags', () => {
+ let mock;
+
+ beforeEach(() => {
+ mockedState.endpoint = `${TEST_HOST}/endpoint.json`;
+ mock = new MockAdapter(axios);
+ });
+
+ afterEach(() => {
+ mock.restore();
+ });
+
+ describe('success', () => {
+ it('dispatches requestFeatureFlags and receiveFeatureFlagsSuccess ', done => {
+ mock.onGet(`${TEST_HOST}/endpoint.json`).replyOnce(200, getRequestData, {});
+
+ testAction(
+ fetchFeatureFlags,
+ null,
+ mockedState,
+ [],
+ [
+ {
+ type: 'requestFeatureFlags',
+ },
+ {
+ payload: { data: getRequestData, headers: {} },
+ type: 'receiveFeatureFlagsSuccess',
+ },
+ ],
+ done,
+ );
+ });
+ });
+
+ describe('error', () => {
+ it('dispatches requestFeatureFlags and receiveFeatureFlagsError ', done => {
+ mock.onGet(`${TEST_HOST}/endpoint.json`, {}).replyOnce(500, {});
+
+ testAction(
+ fetchFeatureFlags,
+ null,
+ mockedState,
+ [],
+ [
+ {
+ type: 'requestFeatureFlags',
+ },
+ {
+ type: 'receiveFeatureFlagsError',
+ },
+ ],
+ done,
+ );
+ });
+ });
+ });
+
+ describe('requestFeatureFlags', () => {
+ it('should commit RECEIVE_FEATURE_FLAGS_SUCCESS mutation', done => {
+ testAction(
+ requestFeatureFlags,
+ null,
+ mockedState,
+ [{ type: types.REQUEST_FEATURE_FLAGS }],
+ [],
+ done,
+ );
+ });
+ });
+
+ describe('receiveFeatureFlagsSuccess', () => {
+ it('should commit RECEIVE_FEATURE_FLAGS_SUCCESS mutation', done => {
+ testAction(
+ receiveFeatureFlagsSuccess,
+ { data: getRequestData, headers: {} },
+ mockedState,
+ [
+ {
+ type: types.RECEIVE_FEATURE_FLAGS_SUCCESS,
+ payload: { data: getRequestData, headers: {} },
+ },
+ ],
+ [],
+ done,
+ );
+ });
+ });
+
+ describe('receiveFeatureFlagsError', () => {
+ it('should commit RECEIVE_FEATURE_FLAGS_ERROR mutation', done => {
+ testAction(
+ receiveFeatureFlagsError,
+ null,
+ mockedState,
+ [{ type: types.RECEIVE_FEATURE_FLAGS_ERROR }],
+ [],
+ done,
+ );
+ });
+ });
+
+ describe('fetchUserLists', () => {
+ beforeEach(() => {
+ Api.fetchFeatureFlagUserLists.mockResolvedValue({ data: [userList], headers: {} });
+ });
+
+ describe('success', () => {
+ it('dispatches requestUserLists and receiveUserListsSuccess ', done => {
+ testAction(
+ fetchUserLists,
+ null,
+ mockedState,
+ [],
+ [
+ {
+ type: 'requestUserLists',
+ },
+ {
+ payload: { data: [userList], headers: {} },
+ type: 'receiveUserListsSuccess',
+ },
+ ],
+ done,
+ );
+ });
+ });
+
+ describe('error', () => {
+ it('dispatches requestUserLists and receiveUserListsError ', done => {
+ Api.fetchFeatureFlagUserLists.mockRejectedValue();
+
+ testAction(
+ fetchUserLists,
+ null,
+ mockedState,
+ [],
+ [
+ {
+ type: 'requestUserLists',
+ },
+ {
+ type: 'receiveUserListsError',
+ },
+ ],
+ done,
+ );
+ });
+ });
+ });
+
+ describe('requestUserLists', () => {
+ it('should commit RECEIVE_USER_LISTS_SUCCESS mutation', done => {
+ testAction(
+ requestUserLists,
+ null,
+ mockedState,
+ [{ type: types.REQUEST_USER_LISTS }],
+ [],
+ done,
+ );
+ });
+ });
+
+ describe('receiveUserListsSuccess', () => {
+ it('should commit RECEIVE_USER_LISTS_SUCCESS mutation', done => {
+ testAction(
+ receiveUserListsSuccess,
+ { data: [userList], headers: {} },
+ mockedState,
+ [
+ {
+ type: types.RECEIVE_USER_LISTS_SUCCESS,
+ payload: { data: [userList], headers: {} },
+ },
+ ],
+ [],
+ done,
+ );
+ });
+ });
+
+ describe('receiveUserListsError', () => {
+ it('should commit RECEIVE_USER_LISTS_ERROR mutation', done => {
+ testAction(
+ receiveUserListsError,
+ null,
+ mockedState,
+ [{ type: types.RECEIVE_USER_LISTS_ERROR }],
+ [],
+ done,
+ );
+ });
+ });
+
+ describe('rotateInstanceId', () => {
+ let mock;
+
+ beforeEach(() => {
+ mockedState.rotateEndpoint = `${TEST_HOST}/endpoint.json`;
+ mock = new MockAdapter(axios);
+ });
+
+ afterEach(() => {
+ mock.restore();
+ });
+
+ describe('success', () => {
+ it('dispatches requestRotateInstanceId and receiveRotateInstanceIdSuccess ', done => {
+ mock.onPost(`${TEST_HOST}/endpoint.json`).replyOnce(200, rotateData, {});
+
+ testAction(
+ rotateInstanceId,
+ null,
+ mockedState,
+ [],
+ [
+ {
+ type: 'requestRotateInstanceId',
+ },
+ {
+ payload: { data: rotateData, headers: {} },
+ type: 'receiveRotateInstanceIdSuccess',
+ },
+ ],
+ done,
+ );
+ });
+ });
+
+ describe('error', () => {
+ it('dispatches requestRotateInstanceId and receiveRotateInstanceIdError ', done => {
+ mock.onGet(`${TEST_HOST}/endpoint.json`, {}).replyOnce(500, {});
+
+ testAction(
+ rotateInstanceId,
+ null,
+ mockedState,
+ [],
+ [
+ {
+ type: 'requestRotateInstanceId',
+ },
+ {
+ type: 'receiveRotateInstanceIdError',
+ },
+ ],
+ done,
+ );
+ });
+ });
+ });
+
+ describe('requestRotateInstanceId', () => {
+ it('should commit REQUEST_ROTATE_INSTANCE_ID mutation', done => {
+ testAction(
+ requestRotateInstanceId,
+ null,
+ mockedState,
+ [{ type: types.REQUEST_ROTATE_INSTANCE_ID }],
+ [],
+ done,
+ );
+ });
+ });
+
+ describe('receiveRotateInstanceIdSuccess', () => {
+ it('should commit RECEIVE_ROTATE_INSTANCE_ID_SUCCESS mutation', done => {
+ testAction(
+ receiveRotateInstanceIdSuccess,
+ { data: rotateData, headers: {} },
+ mockedState,
+ [
+ {
+ type: types.RECEIVE_ROTATE_INSTANCE_ID_SUCCESS,
+ payload: { data: rotateData, headers: {} },
+ },
+ ],
+ [],
+ done,
+ );
+ });
+ });
+
+ describe('receiveRotateInstanceIdError', () => {
+ it('should commit RECEIVE_ROTATE_INSTANCE_ID_ERROR mutation', done => {
+ testAction(
+ receiveRotateInstanceIdError,
+ null,
+ mockedState,
+ [{ type: types.RECEIVE_ROTATE_INSTANCE_ID_ERROR }],
+ [],
+ done,
+ );
+ });
+ });
+
+ describe('toggleFeatureFlag', () => {
+ let mock;
+
+ beforeEach(() => {
+ mockedState.featureFlags = getRequestData.feature_flags.map(flag => ({
+ ...flag,
+ scopes: mapToScopesViewModel(flag.scopes || []),
+ }));
+ mock = new MockAdapter(axios);
+ });
+
+ afterEach(() => {
+ mock.restore();
+ });
+ describe('success', () => {
+ it('dispatches updateFeatureFlag and receiveUpdateFeatureFlagSuccess', done => {
+ mock.onPut(featureFlag.update_path).replyOnce(200, featureFlag, {});
+
+ testAction(
+ toggleFeatureFlag,
+ featureFlag,
+ mockedState,
+ [],
+ [
+ {
+ type: 'updateFeatureFlag',
+ payload: featureFlag,
+ },
+ {
+ payload: featureFlag,
+ type: 'receiveUpdateFeatureFlagSuccess',
+ },
+ ],
+ done,
+ );
+ });
+ });
+ describe('error', () => {
+ it('dispatches updateFeatureFlag and receiveUpdateFeatureFlagSuccess', done => {
+ mock.onPut(featureFlag.update_path).replyOnce(500);
+
+ testAction(
+ toggleFeatureFlag,
+ featureFlag,
+ mockedState,
+ [],
+ [
+ {
+ type: 'updateFeatureFlag',
+ payload: featureFlag,
+ },
+ {
+ payload: featureFlag.id,
+ type: 'receiveUpdateFeatureFlagError',
+ },
+ ],
+ done,
+ );
+ });
+ });
+ });
+ describe('updateFeatureFlag', () => {
+ beforeEach(() => {
+ mockedState.featureFlags = getRequestData.feature_flags.map(f => ({
+ ...f,
+ scopes: mapToScopesViewModel(f.scopes || []),
+ }));
+ });
+
+ it('commits UPDATE_FEATURE_FLAG with the given flag', done => {
+ testAction(
+ updateFeatureFlag,
+ featureFlag,
+ mockedState,
+ [
+ {
+ type: 'UPDATE_FEATURE_FLAG',
+ payload: featureFlag,
+ },
+ ],
+ [],
+ done,
+ );
+ });
+ });
+ describe('receiveUpdateFeatureFlagSuccess', () => {
+ beforeEach(() => {
+ mockedState.featureFlags = getRequestData.feature_flags.map(f => ({
+ ...f,
+ scopes: mapToScopesViewModel(f.scopes || []),
+ }));
+ });
+
+ it('commits RECEIVE_UPDATE_FEATURE_FLAG_SUCCESS with the given flag', done => {
+ testAction(
+ receiveUpdateFeatureFlagSuccess,
+ featureFlag,
+ mockedState,
+ [
+ {
+ type: 'RECEIVE_UPDATE_FEATURE_FLAG_SUCCESS',
+ payload: featureFlag,
+ },
+ ],
+ [],
+ done,
+ );
+ });
+ });
+ describe('receiveUpdateFeatureFlagError', () => {
+ beforeEach(() => {
+ mockedState.featureFlags = getRequestData.feature_flags.map(f => ({
+ ...f,
+ scopes: mapToScopesViewModel(f.scopes || []),
+ }));
+ });
+
+ it('commits RECEIVE_UPDATE_FEATURE_FLAG_ERROR with the given flag id', done => {
+ testAction(
+ receiveUpdateFeatureFlagError,
+ featureFlag.id,
+ mockedState,
+ [
+ {
+ type: 'RECEIVE_UPDATE_FEATURE_FLAG_ERROR',
+ payload: featureFlag.id,
+ },
+ ],
+ [],
+ done,
+ );
+ });
+ });
+ describe('deleteUserList', () => {
+ beforeEach(() => {
+ mockedState.userLists = [userList];
+ });
+
+ describe('success', () => {
+ beforeEach(() => {
+ Api.deleteFeatureFlagUserList.mockResolvedValue();
+ });
+
+ it('should refresh the user lists', done => {
+ testAction(
+ deleteUserList,
+ userList,
+ mockedState,
+ [],
+ [{ type: 'requestDeleteUserList', payload: userList }, { type: 'fetchUserLists' }],
+ done,
+ );
+ });
+ });
+
+ describe('error', () => {
+ beforeEach(() => {
+ Api.deleteFeatureFlagUserList.mockRejectedValue({ response: { data: 'some error' } });
+ });
+
+ it('should dispatch receiveDeleteUserListError', done => {
+ testAction(
+ deleteUserList,
+ userList,
+ mockedState,
+ [],
+ [
+ { type: 'requestDeleteUserList', payload: userList },
+ {
+ type: 'receiveDeleteUserListError',
+ payload: { list: userList, error: 'some error' },
+ },
+ ],
+ done,
+ );
+ });
+ });
+ });
+
+ describe('receiveDeleteUserListError', () => {
+ it('should commit RECEIVE_DELETE_USER_LIST_ERROR with the given list', done => {
+ testAction(
+ receiveDeleteUserListError,
+ { list: userList, error: 'mock error' },
+ mockedState,
+ [
+ {
+ type: 'RECEIVE_DELETE_USER_LIST_ERROR',
+ payload: { list: userList, error: 'mock error' },
+ },
+ ],
+ [],
+ done,
+ );
+ });
+ });
+
+ describe('clearAlert', () => {
+ it('should commit RECEIVE_CLEAR_ALERT', done => {
+ const alertIndex = 3;
+
+ testAction(
+ clearAlert,
+ alertIndex,
+ mockedState,
+ [{ type: 'RECEIVE_CLEAR_ALERT', payload: alertIndex }],
+ [],
+ done,
+ );
+ });
+ });
+});
diff --git a/spec/frontend/feature_flags/store/index/mutations_spec.js b/spec/frontend/feature_flags/store/index/mutations_spec.js
new file mode 100644
index 00000000000..376c7b069fa
--- /dev/null
+++ b/spec/frontend/feature_flags/store/index/mutations_spec.js
@@ -0,0 +1,307 @@
+import state from '~/feature_flags/store/index/state';
+import mutations from '~/feature_flags/store/index/mutations';
+import * as types from '~/feature_flags/store/index/mutation_types';
+import { mapToScopesViewModel } from '~/feature_flags/store/helpers';
+import { parseIntPagination, normalizeHeaders } from '~/lib/utils/common_utils';
+import { getRequestData, rotateData, featureFlag, userList } from '../../mock_data';
+
+describe('Feature flags store Mutations', () => {
+ let stateCopy;
+
+ beforeEach(() => {
+ stateCopy = state({});
+ });
+
+ describe('SET_FEATURE_FLAGS_OPTIONS', () => {
+ it('should set provided options', () => {
+ mutations[types.SET_FEATURE_FLAGS_OPTIONS](stateCopy, { page: '1', scope: 'all' });
+
+ expect(stateCopy.options).toEqual({ page: '1', scope: 'all' });
+ });
+ });
+ describe('REQUEST_FEATURE_FLAGS', () => {
+ it('should set isLoading to true', () => {
+ mutations[types.REQUEST_FEATURE_FLAGS](stateCopy);
+
+ expect(stateCopy.isLoading).toEqual(true);
+ });
+ });
+
+ describe('RECEIVE_FEATURE_FLAGS_SUCCESS', () => {
+ const headers = {
+ 'x-next-page': '2',
+ 'x-page': '1',
+ 'X-Per-Page': '2',
+ 'X-Prev-Page': '',
+ 'X-TOTAL': '37',
+ 'X-Total-Pages': '5',
+ };
+
+ beforeEach(() => {
+ mutations[types.RECEIVE_FEATURE_FLAGS_SUCCESS](stateCopy, { data: getRequestData, headers });
+ });
+
+ it('should set isLoading to false', () => {
+ expect(stateCopy.isLoading).toEqual(false);
+ });
+
+ it('should set hasError to false', () => {
+ expect(stateCopy.hasError).toEqual(false);
+ });
+
+ it('should set featureFlags with the transformed data', () => {
+ const expected = getRequestData.feature_flags.map(flag => ({
+ ...flag,
+ scopes: mapToScopesViewModel(flag.scopes || []),
+ }));
+
+ expect(stateCopy.featureFlags).toEqual(expected);
+ });
+
+ it('should set count with the given data', () => {
+ expect(stateCopy.count.featureFlags).toEqual(37);
+ });
+
+ it('should set pagination', () => {
+ expect(stateCopy.pageInfo.featureFlags).toEqual(
+ parseIntPagination(normalizeHeaders(headers)),
+ );
+ });
+ });
+
+ describe('RECEIVE_FEATURE_FLAGS_ERROR', () => {
+ beforeEach(() => {
+ mutations[types.RECEIVE_FEATURE_FLAGS_ERROR](stateCopy);
+ });
+
+ it('should set isLoading to false', () => {
+ expect(stateCopy.isLoading).toEqual(false);
+ });
+
+ it('should set hasError to true', () => {
+ expect(stateCopy.hasError).toEqual(true);
+ });
+ });
+
+ describe('REQUEST_USER_LISTS', () => {
+ it('sets isLoading to true', () => {
+ mutations[types.REQUEST_USER_LISTS](stateCopy);
+ expect(stateCopy.isLoading).toBe(true);
+ });
+ });
+
+ describe('RECEIVE_USER_LISTS_SUCCESS', () => {
+ const headers = {
+ 'x-next-page': '2',
+ 'x-page': '1',
+ 'X-Per-Page': '2',
+ 'X-Prev-Page': '',
+ 'X-TOTAL': '37',
+ 'X-Total-Pages': '5',
+ };
+
+ beforeEach(() => {
+ mutations[types.RECEIVE_USER_LISTS_SUCCESS](stateCopy, { data: [userList], headers });
+ });
+
+ it('sets isLoading to false', () => {
+ expect(stateCopy.isLoading).toBe(false);
+ });
+
+ it('sets userLists to the received userLists', () => {
+ expect(stateCopy.userLists).toEqual([userList]);
+ });
+
+ it('sets pagination info for user lits', () => {
+ expect(stateCopy.pageInfo.userLists).toEqual(parseIntPagination(normalizeHeaders(headers)));
+ });
+
+ it('sets the count for user lists', () => {
+ expect(stateCopy.count.userLists).toBe(parseInt(headers['X-TOTAL'], 10));
+ });
+ });
+
+ describe('RECEIVE_USER_LISTS_ERROR', () => {
+ beforeEach(() => {
+ mutations[types.RECEIVE_USER_LISTS_ERROR](stateCopy);
+ });
+
+ it('should set isLoading to false', () => {
+ expect(stateCopy.isLoading).toEqual(false);
+ });
+
+ it('should set hasError to true', () => {
+ expect(stateCopy.hasError).toEqual(true);
+ });
+ });
+
+ describe('REQUEST_ROTATE_INSTANCE_ID', () => {
+ beforeEach(() => {
+ mutations[types.REQUEST_ROTATE_INSTANCE_ID](stateCopy);
+ });
+
+ it('should set isRotating to true', () => {
+ expect(stateCopy.isRotating).toBe(true);
+ });
+
+ it('should set hasRotateError to false', () => {
+ expect(stateCopy.hasRotateError).toBe(false);
+ });
+ });
+
+ describe('RECEIVE_ROTATE_INSTANCE_ID_SUCCESS', () => {
+ beforeEach(() => {
+ mutations[types.RECEIVE_ROTATE_INSTANCE_ID_SUCCESS](stateCopy, { data: rotateData });
+ });
+
+ it('should set the instance id to the received data', () => {
+ expect(stateCopy.instanceId).toBe(rotateData.token);
+ });
+
+ it('should set isRotating to false', () => {
+ expect(stateCopy.isRotating).toBe(false);
+ });
+
+ it('should set hasRotateError to false', () => {
+ expect(stateCopy.hasRotateError).toBe(false);
+ });
+ });
+
+ describe('RECEIVE_ROTATE_INSTANCE_ID_ERROR', () => {
+ beforeEach(() => {
+ mutations[types.RECEIVE_ROTATE_INSTANCE_ID_ERROR](stateCopy);
+ });
+
+ it('should set isRotating to false', () => {
+ expect(stateCopy.isRotating).toBe(false);
+ });
+
+ it('should set hasRotateError to true', () => {
+ expect(stateCopy.hasRotateError).toBe(true);
+ });
+ });
+
+ describe('UPDATE_FEATURE_FLAG', () => {
+ beforeEach(() => {
+ stateCopy.featureFlags = getRequestData.feature_flags.map(flag => ({
+ ...flag,
+ scopes: mapToScopesViewModel(flag.scopes || []),
+ }));
+ stateCopy.count = { featureFlags: 1, userLists: 0 };
+
+ mutations[types.UPDATE_FEATURE_FLAG](stateCopy, {
+ ...featureFlag,
+ scopes: mapToScopesViewModel(featureFlag.scopes || []),
+ active: false,
+ });
+ });
+
+ it('should update the flag with the matching ID', () => {
+ expect(stateCopy.featureFlags).toEqual([
+ {
+ ...featureFlag,
+ scopes: mapToScopesViewModel(featureFlag.scopes || []),
+ active: false,
+ },
+ ]);
+ });
+ });
+
+ describe('RECEIVE_UPDATE_FEATURE_FLAG_SUCCESS', () => {
+ const runUpdate = (stateCount, flagState, featureFlagUpdateParams) => {
+ stateCopy.featureFlags = getRequestData.feature_flags.map(flag => ({
+ ...flag,
+ ...flagState,
+ scopes: mapToScopesViewModel(flag.scopes || []),
+ }));
+ stateCopy.count.featureFlags = stateCount;
+
+ mutations[types.RECEIVE_UPDATE_FEATURE_FLAG_SUCCESS](stateCopy, {
+ ...featureFlag,
+ ...featureFlagUpdateParams,
+ });
+ };
+
+ it('updates the flag with the matching ID', () => {
+ runUpdate({ all: 1, enabled: 1, disabled: 0 }, { active: true }, { active: false });
+
+ expect(stateCopy.featureFlags).toEqual([
+ {
+ ...featureFlag,
+ scopes: mapToScopesViewModel(featureFlag.scopes || []),
+ active: false,
+ },
+ ]);
+ });
+ });
+
+ describe('RECEIVE_UPDATE_FEATURE_FLAG_ERROR', () => {
+ beforeEach(() => {
+ stateCopy.featureFlags = getRequestData.feature_flags.map(flag => ({
+ ...flag,
+ scopes: mapToScopesViewModel(flag.scopes || []),
+ }));
+ stateCopy.count = { enabled: 1, disabled: 0 };
+
+ mutations[types.RECEIVE_UPDATE_FEATURE_FLAG_ERROR](stateCopy, featureFlag.id);
+ });
+
+ it('should update the flag with the matching ID, toggling active', () => {
+ expect(stateCopy.featureFlags).toEqual([
+ {
+ ...featureFlag,
+ scopes: mapToScopesViewModel(featureFlag.scopes || []),
+ active: false,
+ },
+ ]);
+ });
+ });
+
+ describe('REQUEST_DELETE_USER_LIST', () => {
+ beforeEach(() => {
+ stateCopy.userLists = [userList];
+ mutations[types.REQUEST_DELETE_USER_LIST](stateCopy, userList);
+ });
+
+ it('should remove the deleted list', () => {
+ expect(stateCopy.userLists).not.toContain(userList);
+ });
+ });
+
+ describe('RECEIVE_DELETE_USER_LIST_ERROR', () => {
+ beforeEach(() => {
+ stateCopy.userLists = [];
+ mutations[types.RECEIVE_DELETE_USER_LIST_ERROR](stateCopy, {
+ list: userList,
+ error: 'some error',
+ });
+ });
+
+ it('should set isLoading to false and hasError to false', () => {
+ expect(stateCopy.isLoading).toBe(false);
+ expect(stateCopy.hasError).toBe(false);
+ });
+
+ it('should add the user list back to the list of user lists', () => {
+ expect(stateCopy.userLists).toContain(userList);
+ });
+ });
+
+ describe('RECEIVE_CLEAR_ALERT', () => {
+ it('clears the alert', () => {
+ stateCopy.alerts = ['a server error'];
+
+ mutations[types.RECEIVE_CLEAR_ALERT](stateCopy, 0);
+
+ expect(stateCopy.alerts).toEqual([]);
+ });
+
+ it('clears the alert at the specified index', () => {
+ stateCopy.alerts = ['a server error', 'another error', 'final error'];
+
+ mutations[types.RECEIVE_CLEAR_ALERT](stateCopy, 1);
+
+ expect(stateCopy.alerts).toEqual(['a server error', 'final error']);
+ });
+ });
+});
diff --git a/spec/frontend/feature_flags/store/new/actions_spec.js b/spec/frontend/feature_flags/store/new/actions_spec.js
new file mode 100644
index 00000000000..130c5235aa0
--- /dev/null
+++ b/spec/frontend/feature_flags/store/new/actions_spec.js
@@ -0,0 +1,192 @@
+import MockAdapter from 'axios-mock-adapter';
+import testAction from 'helpers/vuex_action_helper';
+import { TEST_HOST } from 'spec/test_constants';
+import {
+ createFeatureFlag,
+ requestCreateFeatureFlag,
+ receiveCreateFeatureFlagSuccess,
+ receiveCreateFeatureFlagError,
+} from '~/feature_flags/store/new/actions';
+import state from '~/feature_flags/store/new/state';
+import * as types from '~/feature_flags/store/new/mutation_types';
+import {
+ ROLLOUT_STRATEGY_ALL_USERS,
+ ROLLOUT_STRATEGY_PERCENT_ROLLOUT,
+ LEGACY_FLAG,
+ NEW_VERSION_FLAG,
+} from '~/feature_flags/constants';
+import { mapFromScopesViewModel, mapStrategiesToRails } from '~/feature_flags/store/helpers';
+import axios from '~/lib/utils/axios_utils';
+
+jest.mock('~/lib/utils/url_utility');
+
+describe('Feature flags New Module Actions', () => {
+ let mockedState;
+
+ beforeEach(() => {
+ mockedState = state({ endpoint: 'feature_flags.json', path: '/feature_flags' });
+ });
+
+ describe('createFeatureFlag', () => {
+ let mock;
+
+ const actionParams = {
+ name: 'name',
+ description: 'description',
+ active: true,
+ version: LEGACY_FLAG,
+ scopes: [
+ {
+ id: 1,
+ environmentScope: 'environmentScope',
+ active: true,
+ canUpdate: true,
+ protected: true,
+ shouldBeDestroyed: false,
+ rolloutStrategy: ROLLOUT_STRATEGY_ALL_USERS,
+ rolloutPercentage: ROLLOUT_STRATEGY_PERCENT_ROLLOUT,
+ },
+ ],
+ };
+
+ beforeEach(() => {
+ mockedState.endpoint = `${TEST_HOST}/endpoint.json`;
+ mock = new MockAdapter(axios);
+ });
+
+ afterEach(() => {
+ mock.restore();
+ });
+
+ describe('success', () => {
+ it('dispatches requestCreateFeatureFlag and receiveCreateFeatureFlagSuccess ', done => {
+ const convertedActionParams = mapFromScopesViewModel(actionParams);
+
+ mock.onPost(`${TEST_HOST}/endpoint.json`, convertedActionParams).replyOnce(200);
+
+ testAction(
+ createFeatureFlag,
+ actionParams,
+ mockedState,
+ [],
+ [
+ {
+ type: 'requestCreateFeatureFlag',
+ },
+ {
+ type: 'receiveCreateFeatureFlagSuccess',
+ },
+ ],
+ done,
+ );
+ });
+
+ it('sends strategies for new style feature flags', done => {
+ const newVersionFlagParams = {
+ name: 'name',
+ description: 'description',
+ active: true,
+ version: NEW_VERSION_FLAG,
+ strategies: [
+ {
+ name: ROLLOUT_STRATEGY_ALL_USERS,
+ parameters: {},
+ id: 1,
+ scopes: [{ id: 1, environmentScope: 'environmentScope', shouldBeDestroyed: false }],
+ shouldBeDestroyed: false,
+ },
+ ],
+ };
+ mock
+ .onPost(`${TEST_HOST}/endpoint.json`, mapStrategiesToRails(newVersionFlagParams))
+ .replyOnce(200);
+
+ testAction(
+ createFeatureFlag,
+ newVersionFlagParams,
+ mockedState,
+ [],
+ [
+ {
+ type: 'requestCreateFeatureFlag',
+ },
+ {
+ type: 'receiveCreateFeatureFlagSuccess',
+ },
+ ],
+ done,
+ );
+ });
+ });
+
+ describe('error', () => {
+ it('dispatches requestCreateFeatureFlag and receiveCreateFeatureFlagError ', done => {
+ const convertedActionParams = mapFromScopesViewModel(actionParams);
+
+ mock
+ .onPost(`${TEST_HOST}/endpoint.json`, convertedActionParams)
+ .replyOnce(500, { message: [] });
+
+ testAction(
+ createFeatureFlag,
+ actionParams,
+ mockedState,
+ [],
+ [
+ {
+ type: 'requestCreateFeatureFlag',
+ },
+ {
+ type: 'receiveCreateFeatureFlagError',
+ payload: { message: [] },
+ },
+ ],
+ done,
+ );
+ });
+ });
+ });
+
+ describe('requestCreateFeatureFlag', () => {
+ it('should commit REQUEST_CREATE_FEATURE_FLAG mutation', done => {
+ testAction(
+ requestCreateFeatureFlag,
+ null,
+ mockedState,
+ [{ type: types.REQUEST_CREATE_FEATURE_FLAG }],
+ [],
+ done,
+ );
+ });
+ });
+
+ describe('receiveCreateFeatureFlagSuccess', () => {
+ it('should commit RECEIVE_CREATE_FEATURE_FLAG_SUCCESS mutation', done => {
+ testAction(
+ receiveCreateFeatureFlagSuccess,
+ null,
+ mockedState,
+ [
+ {
+ type: types.RECEIVE_CREATE_FEATURE_FLAG_SUCCESS,
+ },
+ ],
+ [],
+ done,
+ );
+ });
+ });
+
+ describe('receiveCreateFeatureFlagError', () => {
+ it('should commit RECEIVE_CREATE_FEATURE_FLAG_ERROR mutation', done => {
+ testAction(
+ receiveCreateFeatureFlagError,
+ 'There was an error',
+ mockedState,
+ [{ type: types.RECEIVE_CREATE_FEATURE_FLAG_ERROR, payload: 'There was an error' }],
+ [],
+ done,
+ );
+ });
+ });
+});
diff --git a/spec/frontend/feature_flags/store/new/mutations_spec.js b/spec/frontend/feature_flags/store/new/mutations_spec.js
new file mode 100644
index 00000000000..e8609a6d116
--- /dev/null
+++ b/spec/frontend/feature_flags/store/new/mutations_spec.js
@@ -0,0 +1,49 @@
+import state from '~/feature_flags/store/new/state';
+import mutations from '~/feature_flags/store/new/mutations';
+import * as types from '~/feature_flags/store/new/mutation_types';
+
+describe('Feature flags New Module Mutations', () => {
+ let stateCopy;
+
+ beforeEach(() => {
+ stateCopy = state({ endpoint: 'feature_flags.json', path: 'feature_flags' });
+ });
+
+ describe('REQUEST_CREATE_FEATURE_FLAG', () => {
+ it('should set isSendingRequest to true', () => {
+ mutations[types.REQUEST_CREATE_FEATURE_FLAG](stateCopy);
+
+ expect(stateCopy.isSendingRequest).toEqual(true);
+ });
+
+ it('should set error to an empty array', () => {
+ mutations[types.REQUEST_CREATE_FEATURE_FLAG](stateCopy);
+
+ expect(stateCopy.error).toEqual([]);
+ });
+ });
+
+ describe('RECEIVE_CREATE_FEATURE_FLAG_SUCCESS', () => {
+ it('should set isSendingRequest to false', () => {
+ mutations[types.RECEIVE_CREATE_FEATURE_FLAG_SUCCESS](stateCopy);
+
+ expect(stateCopy.isSendingRequest).toEqual(false);
+ });
+ });
+
+ describe('RECEIVE_CREATE_FEATURE_FLAG_ERROR', () => {
+ beforeEach(() => {
+ mutations[types.RECEIVE_CREATE_FEATURE_FLAG_ERROR](stateCopy, {
+ message: ['Name is required'],
+ });
+ });
+
+ it('should set isSendingRequest to false', () => {
+ expect(stateCopy.isSendingRequest).toEqual(false);
+ });
+
+ it('should set hasError to true', () => {
+ expect(stateCopy.error).toEqual(['Name is required']);
+ });
+ });
+});
diff --git a/spec/frontend/fixtures/blob.rb b/spec/frontend/fixtures/blob.rb
index 712c3bd9b23..a365ee805af 100644
--- a/spec/frontend/fixtures/blob.rb
+++ b/spec/frontend/fixtures/blob.rb
@@ -33,4 +33,14 @@ RSpec.describe Projects::BlobController, '(JavaScript fixtures)', type: :control
expect(response).to be_successful
end
+
+ it 'blob/show_readme.html' do
+ get(:show, params: {
+ namespace_id: project.namespace,
+ project_id: project,
+ id: 'master/README.md'
+ })
+
+ expect(response).to be_successful
+ end
end
diff --git a/spec/frontend/fixtures/releases.rb b/spec/frontend/fixtures/releases.rb
new file mode 100644
index 00000000000..dc282b49be5
--- /dev/null
+++ b/spec/frontend/fixtures/releases.rb
@@ -0,0 +1,146 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Releases (JavaScript fixtures)' do
+ include ApiHelpers
+ include JavaScriptFixturesHelpers
+
+ let_it_be(:admin) { create(:admin, username: 'administrator', email: 'admin@example.gitlab.com') }
+ let_it_be(:namespace) { create(:namespace, path: 'releases-namespace') }
+ let_it_be(:project) { create(:project, :repository, namespace: namespace, path: 'releases-project') }
+
+ let_it_be(:milestone_12_3) do
+ create(:milestone,
+ id: 123,
+ project: project,
+ title: '12.3',
+ description: 'The 12.3 milestone',
+ start_date: Time.zone.parse('2018-12-10'),
+ due_date: Time.zone.parse('2019-01-10'))
+ end
+
+ let_it_be(:milestone_12_4) do
+ create(:milestone,
+ id: 124,
+ project: project,
+ title: '12.4',
+ description: 'The 12.4 milestone',
+ start_date: Time.zone.parse('2019-01-10'),
+ due_date: Time.zone.parse('2019-02-10'))
+ end
+
+ let_it_be(:open_issues_12_3) do
+ create_list(:issue, 2, milestone: milestone_12_3, project: project)
+ end
+
+ let_it_be(:closed_issues_12_3) do
+ create_list(:issue, 3, :closed, milestone: milestone_12_3, project: project)
+ end
+
+ let_it_be(:open_issues_12_4) do
+ create_list(:issue, 3, milestone: milestone_12_4, project: project)
+ end
+
+ let_it_be(:closed_issues_12_4) do
+ create_list(:issue, 1, :closed, milestone: milestone_12_4, project: project)
+ end
+
+ let_it_be(:release) do
+ create(:release,
+ milestones: [milestone_12_3, milestone_12_4],
+ project: project,
+ tag: 'v1.1',
+ name: 'The first release',
+ author: admin,
+ description: 'Best. Release. **Ever.** :rocket:',
+ created_at: Time.zone.parse('2018-12-3'),
+ released_at: Time.zone.parse('2018-12-10'))
+ end
+
+ let_it_be(:evidence) do
+ create(:evidence,
+ release: release,
+ collected_at: Time.zone.parse('2018-12-03'))
+ end
+
+ let_it_be(:other_link) do
+ create(:release_link,
+ id: 10,
+ release: release,
+ name: 'linux-amd64 binaries',
+ filepath: '/binaries/linux-amd64',
+ url: 'https://downloads.example.com/bin/gitlab-linux-amd64')
+ end
+
+ let_it_be(:runbook_link) do
+ create(:release_link,
+ id: 11,
+ release: release,
+ name: 'Runbook',
+ url: "#{release.project.web_url}/runbook",
+ link_type: :runbook)
+ end
+
+ let_it_be(:package_link) do
+ create(:release_link,
+ id: 12,
+ release: release,
+ name: 'Package',
+ url: 'https://example.com/package',
+ link_type: :package)
+ end
+
+ let_it_be(:image_link) do
+ create(:release_link,
+ id: 13,
+ release: release,
+ name: 'Image',
+ url: 'https://example.com/image',
+ link_type: :image)
+ end
+
+ after(:all) do
+ remove_repository(project)
+ end
+
+ describe API::Releases, type: :request do
+ before(:all) do
+ clean_frontend_fixtures('api/releases/')
+ end
+
+ it 'api/releases/release.json' do
+ get api("/projects/#{project.id}/releases/#{release.tag}", admin)
+
+ expect(response).to be_successful
+ end
+ end
+
+ describe GraphQL::Query, type: :request do
+ include GraphqlHelpers
+
+ all_releases_query_path = 'releases/queries/all_releases.query.graphql'
+ one_release_query_path = 'releases/queries/one_release.query.graphql'
+ fragment_paths = ['releases/queries/release.fragment.graphql']
+
+ before(:all) do
+ clean_frontend_fixtures('graphql/releases/')
+ end
+
+ it "graphql/#{all_releases_query_path}.json" do
+ query = get_graphql_query_as_string(all_releases_query_path, fragment_paths)
+
+ post_graphql(query, current_user: admin, variables: { fullPath: project.full_path })
+
+ expect_graphql_errors_to_be_empty
+ end
+
+ it "graphql/#{one_release_query_path}.json" do
+ query = get_graphql_query_as_string(one_release_query_path, fragment_paths)
+
+ post_graphql(query, current_user: admin, variables: { fullPath: project.full_path, tagName: release.tag })
+
+ expect_graphql_errors_to_be_empty
+ end
+ end
+end
diff --git a/spec/frontend/fixtures/snippet.rb b/spec/frontend/fixtures/snippet.rb
index 26b088bbd88..2e67a2ecfe3 100644
--- a/spec/frontend/fixtures/snippet.rb
+++ b/spec/frontend/fixtures/snippet.rb
@@ -17,7 +17,6 @@ RSpec.describe SnippetsController, '(JavaScript fixtures)', type: :controller do
end
before do
- stub_feature_flags(snippets_vue: false)
sign_in(admin)
allow(Discussion).to receive(:build_discussion_id).and_return(['discussionid:ceterumcenseo'])
end
diff --git a/spec/frontend/fixtures/static/issue_sidebar_label.html b/spec/frontend/fixtures/static/issue_sidebar_label.html
deleted file mode 100644
index ec8fb30f219..00000000000
--- a/spec/frontend/fixtures/static/issue_sidebar_label.html
+++ /dev/null
@@ -1,26 +0,0 @@
-<div class="block labels">
-<div class="sidebar-collapsed-icon js-sidebar-labels-tooltip"></div>
-<div class="title hide-collapsed">
-<a class="edit-link float-right" href="#">
-Edit
-</a>
-</div>
-<div class="selectbox hide-collapsed" style="display: none;">
-<div class="dropdown">
-<button class="dropdown-menu-toggle js-label-select js-multiselect" data-ability-name="issue" data-field-name="issue[label_names][]" data-issue-update="/root/test/issues/2.json" data-labels="/root/test/labels.json" data-project-id="12" data-show-any="true" data-show-no="true" data-toggle="dropdown" type="button">
-<span class="dropdown-toggle-text">
-Label
-</span>
-<i class="fa fa-chevron-down"></i>
-</button>
-<div class="dropdown-menu dropdown-select dropdown-menu-paging dropdown-menu-labels dropdown-menu-selectable">
-<div class="dropdown-page-one">
-<div class="dropdown-content"></div>
-<div class="dropdown-loading">
-<i class="fa fa-spinner fa-spin"></i>
-</div>
-</div>
-</div>
-</div>
-</div>
-</div>
diff --git a/spec/frontend/fixtures/static/pipeline_graph.html b/spec/frontend/fixtures/static/pipeline_graph.html
index 422372bb7d5..d2c30ff9211 100644
--- a/spec/frontend/fixtures/static/pipeline_graph.html
+++ b/spec/frontend/fixtures/static/pipeline_graph.html
@@ -10,7 +10,7 @@ Test
<div class="curve"></div>
<a>
<svg></svg>
-<div class="ci-status-text">
+<div>
stop_review
</div>
</a>
diff --git a/spec/frontend/gfm_auto_complete_spec.js b/spec/frontend/gfm_auto_complete_spec.js
index 6c40b1ba3a7..8da4320d993 100644
--- a/spec/frontend/gfm_auto_complete_spec.js
+++ b/spec/frontend/gfm_auto_complete_spec.js
@@ -1,6 +1,7 @@
/* eslint no-param-reassign: "off" */
import $ from 'jquery';
+import { emojiFixtureMap, initEmojiMock, describeEmojiFields } from 'helpers/emoji';
import '~/lib/utils/jquery_at_who';
import GfmAutoComplete, { membersBeforeSave } from 'ee_else_ce/gfm_auto_complete';
@@ -119,7 +120,7 @@ describe('GfmAutoComplete', () => {
const defaultMatcher = (context, flag, subtext) =>
gfmAutoCompleteCallbacks.matcher.call(context, flag, subtext);
- const flagsUseDefaultMatcher = ['@', '#', '!', '~', '%', '$', '+'];
+ const flagsUseDefaultMatcher = ['@', '#', '!', '~', '%', '$'];
const otherFlags = ['/', ':'];
const flags = flagsUseDefaultMatcher.concat(otherFlags);
@@ -153,6 +154,7 @@ describe('GfmAutoComplete', () => {
'Ñ',
'.',
"'",
+ '+',
'-',
'_',
];
@@ -416,8 +418,9 @@ describe('GfmAutoComplete', () => {
let $textarea;
beforeEach(() => {
+ setFixtures('<textarea></textarea>');
autocomplete = new GfmAutoComplete(dataSources);
- $textarea = $('<textarea></textarea>');
+ $textarea = $('textarea');
autocomplete.setup($textarea, { labels: true });
});
@@ -488,4 +491,114 @@ describe('GfmAutoComplete', () => {
`('$input shows $output.length labels', expectLabels);
});
});
+
+ describe('emoji', () => {
+ const { atom, heart, star } = emojiFixtureMap;
+ const assertInserted = ({ input, subject, emoji }) =>
+ expect(subject).toBe(`:${emoji?.name || input}:`);
+ const assertTemplated = ({ input, subject, emoji, field }) =>
+ expect(subject.replace(/\s+/g, ' ')).toBe(
+ `<li>${field || input} <gl-emoji data-name="${emoji?.name || input}"></gl-emoji> </li>`,
+ );
+
+ let mock;
+
+ beforeEach(async () => {
+ mock = await initEmojiMock();
+
+ await new GfmAutoComplete({}).loadEmojiData({ atwho() {}, trigger() {} }, ':');
+ if (!GfmAutoComplete.glEmojiTag) throw new Error('emoji not loaded');
+ });
+
+ afterEach(() => {
+ mock.restore();
+ });
+
+ describe.each`
+ name | inputFormat | assert
+ ${'insertTemplateFunction'} | ${name => ({ name })} | ${assertInserted}
+ ${'templateFunction'} | ${name => name} | ${assertTemplated}
+ `('Emoji.$name', ({ name, inputFormat, assert }) => {
+ const execute = (accessor, input, emoji) =>
+ assert({
+ input,
+ emoji,
+ field: accessor && accessor(emoji),
+ subject: GfmAutoComplete.Emoji[name](inputFormat(input)),
+ });
+
+ describeEmojiFields('for $field', ({ accessor }) => {
+ it('should work with lowercase', () => {
+ execute(accessor, accessor(atom), atom);
+ });
+
+ it('should work with uppercase', () => {
+ execute(accessor, accessor(atom).toUpperCase(), atom);
+ });
+
+ it('should work with partial value', () => {
+ execute(accessor, accessor(atom).slice(1), atom);
+ });
+ });
+
+ it('should work with unicode value', () => {
+ execute(null, atom.moji, atom);
+ });
+
+ it('should pass through unknown value', () => {
+ execute(null, 'foo bar baz');
+ });
+ });
+
+ const expectEmojiOrder = (first, second) => {
+ const keys = Object.keys(emojiFixtureMap);
+ const firstIndex = keys.indexOf(first);
+ const secondIndex = keys.indexOf(second);
+ expect(firstIndex).toBeGreaterThanOrEqual(0);
+ expect(secondIndex).toBeGreaterThanOrEqual(0);
+ expect(firstIndex).toBeLessThan(secondIndex);
+ };
+
+ describe('Emoji.insertTemplateFunction', () => {
+ it('should map ":heart" to :heart: [regression]', () => {
+ // the bug mapped heart to black_heart because the latter sorted first
+ expectEmojiOrder('black_heart', 'heart');
+
+ const item = GfmAutoComplete.Emoji.insertTemplateFunction({ name: 'heart' });
+ expect(item).toEqual(`:${heart.name}:`);
+ });
+
+ it('should map ":star" to :star: [regression]', () => {
+ // the bug mapped star to custard because the latter sorted first
+ expectEmojiOrder('custard', 'star');
+
+ const item = GfmAutoComplete.Emoji.insertTemplateFunction({ name: 'star' });
+ expect(item).toEqual(`:${star.name}:`);
+ });
+ });
+
+ describe('Emoji.templateFunction', () => {
+ it('should map ":heart" to ⤠[regression]', () => {
+ // the bug mapped heart to black_heart because the latter sorted first
+ expectEmojiOrder('black_heart', 'heart');
+
+ const item = GfmAutoComplete.Emoji.templateFunction('heart')
+ .replace(/(<gl-emoji)\s+(data-name)/, '$1 $2')
+ .replace(/>\s+|\s+</g, s => s.trim());
+ expect(item).toEqual(
+ `<li>${heart.name}<gl-emoji data-name="${heart.name}"></gl-emoji></li>`,
+ );
+ });
+
+ it('should map ":star" to â­ [regression]', () => {
+ // the bug mapped star to custard because the latter sorted first
+ expectEmojiOrder('custard', 'star');
+
+ const item = GfmAutoComplete.Emoji.templateFunction('star')
+ .replace(/(<gl-emoji)\s+(data-name)/, '$1 $2')
+ .replace(/>\s+|\s+</g, s => s.trim());
+ expect(item).toEqual(`<li>${star.name}<gl-emoji data-name="${star.name}"></gl-emoji></li>`);
+ });
+ });
+ });
});
diff --git a/spec/frontend/grafana_integration/components/__snapshots__/grafana_integration_spec.js.snap b/spec/frontend/grafana_integration/components/__snapshots__/grafana_integration_spec.js.snap
index 0befe1aa192..e880f585daa 100644
--- a/spec/frontend/grafana_integration/components/__snapshots__/grafana_integration_spec.js.snap
+++ b/spec/frontend/grafana_integration/components/__snapshots__/grafana_integration_spec.js.snap
@@ -17,6 +17,7 @@ exports[`grafana integration component default state to match the default snapsh
</h3>
<gl-button-stub
+ buttontextclasses=""
category="primary"
class="js-settings-toggle"
icon=""
@@ -92,20 +93,17 @@ exports[`grafana integration component default state to match the default snapsh
</p>
</gl-form-group-stub>
- <div
- class="gl-display-flex gl-justify-content-end"
+ <gl-button-stub
+ buttontextclasses=""
+ category="primary"
+ icon=""
+ size="medium"
+ variant="success"
>
- <gl-button-stub
- category="primary"
- icon=""
- size="medium"
- variant="success"
- >
-
- Save Changes
- </gl-button-stub>
- </div>
+ Save Changes
+
+ </gl-button-stub>
</form>
</div>
</section>
diff --git a/spec/frontend/group_settings/components/shared_runners_form_spec.js b/spec/frontend/group_settings/components/shared_runners_form_spec.js
new file mode 100644
index 00000000000..9e3ee8a2cb1
--- /dev/null
+++ b/spec/frontend/group_settings/components/shared_runners_form_spec.js
@@ -0,0 +1,169 @@
+import { shallowMount } from '@vue/test-utils';
+import { GlLoadingIcon, GlAlert } from '@gitlab/ui';
+import MockAxiosAdapter from 'axios-mock-adapter';
+import waitForPromises from 'helpers/wait_for_promises';
+import SharedRunnersForm from '~/group_settings/components/shared_runners_form.vue';
+import { ENABLED, DISABLED, ALLOW_OVERRIDE } from '~/group_settings/constants';
+import axios from '~/lib/utils/axios_utils';
+
+const TEST_UPDATE_PATH = '/test/update';
+const DISABLED_PAYLOAD = { shared_runners_setting: DISABLED };
+const ENABLED_PAYLOAD = { shared_runners_setting: ENABLED };
+const OVERRIDE_PAYLOAD = { shared_runners_setting: ALLOW_OVERRIDE };
+
+jest.mock('~/flash');
+
+describe('group_settings/components/shared_runners_form', () => {
+ let wrapper;
+ let mock;
+
+ const createComponent = (props = {}) => {
+ wrapper = shallowMount(SharedRunnersForm, {
+ propsData: {
+ updatePath: TEST_UPDATE_PATH,
+ sharedRunnersAvailability: ENABLED,
+ parentSharedRunnersAvailability: null,
+ ...props,
+ },
+ });
+ };
+
+ const findLoadingIcon = () => wrapper.find(GlLoadingIcon);
+ const findErrorAlert = () => wrapper.find(GlAlert);
+ const findEnabledToggle = () => wrapper.find('[data-testid="enable-runners-toggle"]');
+ const findOverrideToggle = () => wrapper.find('[data-testid="override-runners-toggle"]');
+ const changeToggle = toggle => toggle.vm.$emit('change', !toggle.props('value'));
+ const getRequestPayload = () => JSON.parse(mock.history.put[0].data);
+ const isLoadingIconVisible = () => findLoadingIcon().exists();
+
+ beforeEach(() => {
+ mock = new MockAxiosAdapter(axios);
+
+ mock.onPut(TEST_UPDATE_PATH).reply(200);
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ wrapper = null;
+
+ mock.restore();
+ });
+
+ describe('with default', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('loading icon does not exist', () => {
+ expect(isLoadingIconVisible()).toBe(false);
+ });
+
+ it('enabled toggle exists', () => {
+ expect(findEnabledToggle().exists()).toBe(true);
+ });
+
+ it('override toggle does not exist', () => {
+ expect(findOverrideToggle().exists()).toBe(false);
+ });
+ });
+
+ describe('loading icon', () => {
+ it('shows and hides the loading icon on request', async () => {
+ createComponent();
+
+ expect(isLoadingIconVisible()).toBe(false);
+
+ findEnabledToggle().vm.$emit('change', true);
+
+ await wrapper.vm.$nextTick();
+
+ expect(isLoadingIconVisible()).toBe(true);
+
+ await waitForPromises();
+
+ expect(isLoadingIconVisible()).toBe(false);
+ });
+ });
+
+ describe('enable toggle', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('enabling the toggle sends correct payload', async () => {
+ findEnabledToggle().vm.$emit('change', true);
+
+ await waitForPromises();
+
+ expect(getRequestPayload()).toEqual(ENABLED_PAYLOAD);
+ expect(findOverrideToggle().exists()).toBe(false);
+ });
+
+ it('disabling the toggle sends correct payload', async () => {
+ findEnabledToggle().vm.$emit('change', false);
+
+ await waitForPromises();
+
+ expect(getRequestPayload()).toEqual(DISABLED_PAYLOAD);
+ expect(findOverrideToggle().exists()).toBe(true);
+ });
+ });
+
+ describe('override toggle', () => {
+ beforeEach(() => {
+ createComponent({ sharedRunnersAvailability: ALLOW_OVERRIDE });
+ });
+
+ it('enabling the override toggle sends correct payload', async () => {
+ findOverrideToggle().vm.$emit('change', true);
+
+ await waitForPromises();
+
+ expect(getRequestPayload()).toEqual(OVERRIDE_PAYLOAD);
+ });
+
+ it('disabling the override toggle sends correct payload', async () => {
+ findOverrideToggle().vm.$emit('change', false);
+
+ await waitForPromises();
+
+ expect(getRequestPayload()).toEqual(DISABLED_PAYLOAD);
+ });
+ });
+
+ describe('toggle disabled state', () => {
+ it(`toggles are not disabled with setting ${DISABLED}`, () => {
+ createComponent({ sharedRunnersAvailability: DISABLED });
+ expect(findEnabledToggle().props('disabled')).toBe(false);
+ expect(findOverrideToggle().props('disabled')).toBe(false);
+ });
+
+ it('toggles are disabled', () => {
+ createComponent({
+ sharedRunnersAvailability: DISABLED,
+ parentSharedRunnersAvailability: DISABLED,
+ });
+ expect(findEnabledToggle().props('disabled')).toBe(true);
+ expect(findOverrideToggle().props('disabled')).toBe(true);
+ });
+ });
+
+ describe.each`
+ errorObj | message
+ ${{}} | ${'An error occurred while updating configuration. Refresh the page and try again.'}
+ ${{ error: 'Undefined error' }} | ${'Undefined error Refresh the page and try again.'}
+ `(`with error $errorObj`, ({ errorObj, message }) => {
+ beforeEach(async () => {
+ mock.onPut(TEST_UPDATE_PATH).reply(500, errorObj);
+
+ createComponent();
+ changeToggle(findEnabledToggle());
+
+ await waitForPromises();
+ });
+
+ it('error should be shown', () => {
+ expect(findErrorAlert().text()).toBe(message);
+ });
+ });
+});
diff --git a/spec/frontend/groups/components/group_item_spec.js b/spec/frontend/groups/components/group_item_spec.js
index 7eb1c54ddb2..83acbb152b5 100644
--- a/spec/frontend/groups/components/group_item_spec.js
+++ b/spec/frontend/groups/components/group_item_spec.js
@@ -203,7 +203,7 @@ describe('GroupItemComponent', () => {
expect(vm.$el.querySelector('.title a.no-expand')).toBeDefined();
expect(visibilityIconEl).not.toBe(null);
- expect(visibilityIconEl.dataset.originalTitle).toBe(vm.visibilityTooltip);
+ expect(visibilityIconEl.title).toBe(vm.visibilityTooltip);
expect(visibilityIconEl.querySelectorAll('svg').length).toBeGreaterThan(0);
expect(vm.$el.querySelector('.access-type')).toBeDefined();
diff --git a/spec/frontend/groups/components/item_actions_spec.js b/spec/frontend/groups/components/item_actions_spec.js
index f5df8c180d5..d4aa29eaadd 100644
--- a/spec/frontend/groups/components/item_actions_spec.js
+++ b/spec/frontend/groups/components/item_actions_spec.js
@@ -1,84 +1,87 @@
-import Vue from 'vue';
-
-import mountComponent from 'helpers/vue_mount_component_helper';
-import itemActionsComponent from '~/groups/components/item_actions.vue';
+import { shallowMount } from '@vue/test-utils';
+import { GlIcon } from '@gitlab/ui';
+import ItemActions from '~/groups/components/item_actions.vue';
import eventHub from '~/groups/event_hub';
import { mockParentGroupItem, mockChildren } from '../mock_data';
-const createComponent = (group = mockParentGroupItem, parentGroup = mockChildren[0]) => {
- const Component = Vue.extend(itemActionsComponent);
+describe('ItemActions', () => {
+ let wrapper;
+ const parentGroup = mockChildren[0];
- return mountComponent(Component, {
- group,
+ const defaultProps = {
+ group: mockParentGroupItem,
parentGroup,
- });
-};
-
-describe('ItemActionsComponent', () => {
- let vm;
+ };
- beforeEach(() => {
- vm = createComponent();
- });
+ const createComponent = (props = {}) => {
+ wrapper = shallowMount(ItemActions, {
+ propsData: { ...defaultProps, ...props },
+ });
+ };
afterEach(() => {
- vm.$destroy();
+ if (wrapper) {
+ wrapper.destroy();
+ wrapper = null;
+ }
});
- describe('methods', () => {
- describe('onLeaveGroup', () => {
- it('emits `showLeaveGroupModal` event with `group` and `parentGroup` props', () => {
- jest.spyOn(eventHub, '$emit').mockImplementation(() => {});
- vm.onLeaveGroup();
-
- expect(eventHub.$emit).toHaveBeenCalledWith(
- 'showLeaveGroupModal',
- vm.group,
- vm.parentGroup,
- );
- });
- });
- });
+ const findEditGroupBtn = () => wrapper.find('[data-testid="edit-group-btn"]');
+ const findEditGroupIcon = () => findEditGroupBtn().find(GlIcon);
+ const findLeaveGroupBtn = () => wrapper.find('[data-testid="leave-group-btn"]');
+ const findLeaveGroupIcon = () => findLeaveGroupBtn().find(GlIcon);
describe('template', () => {
- it('should render component template correctly', () => {
- expect(vm.$el.classList.contains('controls')).toBeTruthy();
- });
+ it('renders component template correctly', () => {
+ createComponent();
- it('should render Edit Group button with correct attribute values', () => {
- const group = { ...mockParentGroupItem };
- group.canEdit = true;
- const newVm = createComponent(group);
+ expect(wrapper.classes()).toContain('controls');
+ });
- const editBtn = newVm.$el.querySelector('a.edit-group');
+ it('renders "Edit group" button with correct attribute values', () => {
+ const group = {
+ ...mockParentGroupItem,
+ canEdit: true,
+ };
+
+ createComponent({ group });
+
+ expect(findEditGroupBtn().exists()).toBe(true);
+ expect(findEditGroupBtn().classes()).toContain('no-expand');
+ expect(findEditGroupBtn().attributes('href')).toBe(group.editPath);
+ expect(findEditGroupBtn().attributes('aria-label')).toBe('Edit group');
+ expect(findEditGroupBtn().attributes('data-original-title')).toBe('Edit group');
+ expect(findEditGroupIcon().exists()).toBe(true);
+ expect(findEditGroupIcon().props('name')).toBe('settings');
+ });
- expect(editBtn).toBeDefined();
- expect(editBtn.classList.contains('no-expand')).toBeTruthy();
- expect(editBtn.getAttribute('href')).toBe(group.editPath);
- expect(editBtn.getAttribute('aria-label')).toBe('Edit group');
- expect(editBtn.dataset.originalTitle).toBe('Edit group');
- expect(editBtn.querySelectorAll('svg').length).not.toBe(0);
- expect(editBtn.querySelector('svg').getAttribute('data-testid')).toBe('settings-icon');
+ describe('`canLeave` is true', () => {
+ const group = {
+ ...mockParentGroupItem,
+ canLeave: true,
+ };
- newVm.$destroy();
- });
+ beforeEach(() => {
+ createComponent({ group });
+ });
- it('should render Leave Group button with correct attribute values', () => {
- const group = { ...mockParentGroupItem };
- group.canLeave = true;
- const newVm = createComponent(group);
+ it('renders "Leave this group" button with correct attribute values', () => {
+ expect(findLeaveGroupBtn().exists()).toBe(true);
+ expect(findLeaveGroupBtn().classes()).toContain('no-expand');
+ expect(findLeaveGroupBtn().attributes('href')).toBe(group.leavePath);
+ expect(findLeaveGroupBtn().attributes('aria-label')).toBe('Leave this group');
+ expect(findLeaveGroupBtn().attributes('data-original-title')).toBe('Leave this group');
+ expect(findLeaveGroupIcon().exists()).toBe(true);
+ expect(findLeaveGroupIcon().props('name')).toBe('leave');
+ });
- const leaveBtn = newVm.$el.querySelector('a.leave-group');
+ it('emits event on "Leave this group" button click', () => {
+ jest.spyOn(eventHub, '$emit').mockImplementation(() => {});
- expect(leaveBtn).toBeDefined();
- expect(leaveBtn.classList.contains('no-expand')).toBeTruthy();
- expect(leaveBtn.getAttribute('href')).toBe(group.leavePath);
- expect(leaveBtn.getAttribute('aria-label')).toBe('Leave this group');
- expect(leaveBtn.dataset.originalTitle).toBe('Leave this group');
- expect(leaveBtn.querySelectorAll('svg').length).not.toBe(0);
- expect(leaveBtn.querySelector('svg').getAttribute('data-testid')).toBe('leave-icon');
+ findLeaveGroupBtn().trigger('click');
- newVm.$destroy();
+ expect(eventHub.$emit).toHaveBeenCalledWith('showLeaveGroupModal', group, parentGroup);
+ });
});
});
});
diff --git a/spec/frontend/groups/components/item_caret_spec.js b/spec/frontend/groups/components/item_caret_spec.js
index 4ff7482414c..b2915607a06 100644
--- a/spec/frontend/groups/components/item_caret_spec.js
+++ b/spec/frontend/groups/components/item_caret_spec.js
@@ -1,38 +1,48 @@
-import Vue from 'vue';
+import { shallowMount } from '@vue/test-utils';
+import { GlIcon } from '@gitlab/ui';
+import ItemCaret from '~/groups/components/item_caret.vue';
-import mountComponent from 'helpers/vue_mount_component_helper';
-import itemCaretComponent from '~/groups/components/item_caret.vue';
+describe('ItemCaret', () => {
+ let wrapper;
-const createComponent = (isGroupOpen = false) => {
- const Component = Vue.extend(itemCaretComponent);
+ const defaultProps = {
+ isGroupOpen: false,
+ };
- return mountComponent(Component, {
- isGroupOpen,
- });
-};
-
-describe('ItemCaretComponent', () => {
- let vm;
+ const createComponent = (props = {}) => {
+ wrapper = shallowMount(ItemCaret, {
+ propsData: { ...defaultProps, ...props },
+ });
+ };
afterEach(() => {
- vm.$destroy();
+ if (wrapper) {
+ wrapper.destroy();
+ wrapper = null;
+ }
});
+ const findAllGlIcons = () => wrapper.findAll(GlIcon);
+ const findGlIcon = () => wrapper.find(GlIcon);
+
describe('template', () => {
- it('should render component template correctly', () => {
- vm = createComponent();
- expect(vm.$el.classList.contains('folder-caret')).toBeTruthy();
- expect(vm.$el.querySelectorAll('svg').length).toBe(1);
- });
+ it('renders component template correctly', () => {
+ createComponent();
- it('should render caret down icon if `isGroupOpen` prop is `true`', () => {
- vm = createComponent(true);
- expect(vm.$el.querySelector('svg').getAttribute('data-testid')).toBe('angle-down-icon');
+ expect(wrapper.classes()).toContain('folder-caret');
+ expect(findAllGlIcons()).toHaveLength(1);
});
- it('should render caret right icon if `isGroupOpen` prop is `false`', () => {
- vm = createComponent();
- expect(vm.$el.querySelector('svg').getAttribute('data-testid')).toBe('angle-right-icon');
+ it.each`
+ isGroupOpen | icon
+ ${true} | ${'angle-down'}
+ ${false} | ${'angle-right'}
+ `('renders "$icon" icon when `isGroupOpen` is $isGroupOpen', ({ isGroupOpen, icon }) => {
+ createComponent({
+ isGroupOpen,
+ });
+
+ expect(findGlIcon().props('name')).toBe(icon);
});
});
});
diff --git a/spec/frontend/groups/components/item_stats_spec.js b/spec/frontend/groups/components/item_stats_spec.js
index 771643609ec..d8c88a608ac 100644
--- a/spec/frontend/groups/components/item_stats_spec.js
+++ b/spec/frontend/groups/components/item_stats_spec.js
@@ -1,119 +1,50 @@
-import Vue from 'vue';
+import { shallowMount } from '@vue/test-utils';
+import ItemStats from '~/groups/components/item_stats.vue';
+import ItemStatsValue from '~/groups/components/item_stats_value.vue';
-import mountComponent from 'helpers/vue_mount_component_helper';
-import itemStatsComponent from '~/groups/components/item_stats.vue';
-import {
- mockParentGroupItem,
- ITEM_TYPE,
- VISIBILITY_TYPE_ICON,
- GROUP_VISIBILITY_TYPE,
- PROJECT_VISIBILITY_TYPE,
-} from '../mock_data';
+import { mockParentGroupItem, ITEM_TYPE } from '../mock_data';
-const createComponent = (item = mockParentGroupItem) => {
- const Component = Vue.extend(itemStatsComponent);
+describe('ItemStats', () => {
+ let wrapper;
- return mountComponent(Component, {
- item,
- });
-};
-
-describe('ItemStatsComponent', () => {
- describe('computed', () => {
- describe('visibilityIcon', () => {
- it('should return icon class based on `item.visibility` value', () => {
- Object.keys(VISIBILITY_TYPE_ICON).forEach(visibility => {
- const item = { ...mockParentGroupItem, visibility };
- const vm = createComponent(item);
+ const defaultProps = {
+ item: mockParentGroupItem,
+ };
- expect(vm.visibilityIcon).toBe(VISIBILITY_TYPE_ICON[visibility]);
- vm.$destroy();
- });
- });
+ const createComponent = (props = {}) => {
+ wrapper = shallowMount(ItemStats, {
+ propsData: { ...defaultProps, ...props },
});
+ };
- describe('visibilityTooltip', () => {
- it('should return tooltip string for Group based on `item.visibility` value', () => {
- Object.keys(GROUP_VISIBILITY_TYPE).forEach(visibility => {
- const item = { ...mockParentGroupItem, visibility, type: ITEM_TYPE.GROUP };
- const vm = createComponent(item);
-
- expect(vm.visibilityTooltip).toBe(GROUP_VISIBILITY_TYPE[visibility]);
- vm.$destroy();
- });
- });
-
- it('should return tooltip string for Project based on `item.visibility` value', () => {
- Object.keys(PROJECT_VISIBILITY_TYPE).forEach(visibility => {
- const item = { ...mockParentGroupItem, visibility, type: ITEM_TYPE.PROJECT };
- const vm = createComponent(item);
-
- expect(vm.visibilityTooltip).toBe(PROJECT_VISIBILITY_TYPE[visibility]);
- vm.$destroy();
- });
- });
- });
-
- describe('isProject', () => {
- it('should return boolean value representing whether `item.type` is Project or not', () => {
- let item;
- let vm;
-
- item = { ...mockParentGroupItem, type: ITEM_TYPE.PROJECT };
- vm = createComponent(item);
-
- expect(vm.isProject).toBeTruthy();
- vm.$destroy();
-
- item = { ...mockParentGroupItem, type: ITEM_TYPE.GROUP };
- vm = createComponent(item);
-
- expect(vm.isProject).toBeFalsy();
- vm.$destroy();
- });
- });
-
- describe('isGroup', () => {
- it('should return boolean value representing whether `item.type` is Group or not', () => {
- let item;
- let vm;
-
- item = { ...mockParentGroupItem, type: ITEM_TYPE.GROUP };
- vm = createComponent(item);
-
- expect(vm.isGroup).toBeTruthy();
- vm.$destroy();
-
- item = { ...mockParentGroupItem, type: ITEM_TYPE.PROJECT };
- vm = createComponent(item);
-
- expect(vm.isGroup).toBeFalsy();
- vm.$destroy();
- });
- });
+ afterEach(() => {
+ if (wrapper) {
+ wrapper.destroy();
+ wrapper = null;
+ }
});
+ const findItemStatsValue = () => wrapper.find(ItemStatsValue);
+
describe('template', () => {
it('renders component container element correctly', () => {
- const vm = createComponent();
+ createComponent();
- expect(vm.$el.classList.contains('stats')).toBeTruthy();
-
- vm.$destroy();
+ expect(wrapper.classes()).toContain('stats');
});
it('renders start count and last updated information for project item correctly', () => {
- const item = { ...mockParentGroupItem, type: ITEM_TYPE.PROJECT, starCount: 4 };
- const vm = createComponent(item);
-
- const projectStarIconEl = vm.$el.querySelector('.project-stars');
+ const item = {
+ ...mockParentGroupItem,
+ type: ITEM_TYPE.PROJECT,
+ starCount: 4,
+ };
- expect(projectStarIconEl).not.toBeNull();
- expect(projectStarIconEl.querySelectorAll('svg').length).toBeGreaterThan(0);
- expect(projectStarIconEl.querySelectorAll('.stat-value').length).toBeGreaterThan(0);
- expect(vm.$el.querySelectorAll('.last-updated').length).toBeGreaterThan(0);
+ createComponent({ item });
- vm.$destroy();
+ expect(findItemStatsValue().exists()).toBe(true);
+ expect(findItemStatsValue().props('cssClass')).toBe('project-stars');
+ expect(wrapper.contains('.last-updated')).toBe(true);
});
});
});
diff --git a/spec/frontend/groups/components/item_stats_value_spec.js b/spec/frontend/groups/components/item_stats_value_spec.js
index 11246390444..bca233883af 100644
--- a/spec/frontend/groups/components/item_stats_value_spec.js
+++ b/spec/frontend/groups/components/item_stats_value_spec.js
@@ -1,82 +1,67 @@
-import Vue from 'vue';
+import { shallowMount } from '@vue/test-utils';
+import { GlIcon } from '@gitlab/ui';
+import ItemStatsValue from '~/groups/components/item_stats_value.vue';
-import mountComponent from 'helpers/vue_mount_component_helper';
-import itemStatsValueComponent from '~/groups/components/item_stats_value.vue';
+describe('ItemStatsValue', () => {
+ let wrapper;
-const createComponent = ({ title, cssClass, iconName, tooltipPlacement, value }) => {
- const Component = Vue.extend(itemStatsValueComponent);
+ const defaultProps = {
+ title: 'Subgroups',
+ cssClass: 'number-subgroups',
+ iconName: 'folder',
+ tooltipPlacement: 'left',
+ };
- return mountComponent(Component, {
- title,
- cssClass,
- iconName,
- tooltipPlacement,
- value,
+ const createComponent = (props = {}) => {
+ wrapper = shallowMount(ItemStatsValue, {
+ propsData: { ...defaultProps, ...props },
+ });
+ };
+
+ afterEach(() => {
+ if (wrapper) {
+ wrapper.destroy();
+ wrapper = null;
+ }
});
-};
-describe('ItemStatsValueComponent', () => {
- describe('computed', () => {
- let vm;
- const itemConfig = {
- title: 'Subgroups',
- cssClass: 'number-subgroups',
- iconName: 'folder',
- tooltipPlacement: 'left',
- };
+ const findGlIcon = () => wrapper.find(GlIcon);
+ const findStatValue = () => wrapper.find('[data-testid="itemStatValue"]');
- describe('isValuePresent', () => {
- it('returns true if non-empty `value` is present', () => {
- vm = createComponent({ ...itemConfig, value: 10 });
+ describe('template', () => {
+ describe('when `value` is not provided', () => {
+ it('does not render value count', () => {
+ createComponent();
- expect(vm.isValuePresent).toBeTruthy();
+ expect(findStatValue().exists()).toBe(false);
});
+ });
- it('returns false if empty `value` is present', () => {
- vm = createComponent(itemConfig);
-
- expect(vm.isValuePresent).toBeFalsy();
+ describe('when `value` is provided', () => {
+ beforeEach(() => {
+ createComponent({
+ value: 10,
+ });
});
- afterEach(() => {
- vm.$destroy();
+ it('renders component element correctly', () => {
+ expect(wrapper.classes()).toContain('number-subgroups');
});
- });
- });
- describe('template', () => {
- let vm;
- beforeEach(() => {
- vm = createComponent({
- title: 'Subgroups',
- cssClass: 'number-subgroups',
- iconName: 'folder',
- tooltipPlacement: 'left',
- value: 10,
+ it('renders element tooltip correctly', () => {
+ expect(wrapper.attributes('title')).toBe('Subgroups');
+ expect(wrapper.attributes('data-placement')).toBe('left');
});
- });
- afterEach(() => {
- vm.$destroy();
- });
-
- it('renders component element correctly', () => {
- expect(vm.$el.classList.contains('number-subgroups')).toBeTruthy();
- expect(vm.$el.querySelectorAll('svg').length).toBeGreaterThan(0);
- expect(vm.$el.querySelectorAll('.stat-value').length).toBeGreaterThan(0);
- });
-
- it('renders element tooltip correctly', () => {
- expect(vm.$el.dataset.originalTitle).toBe('Subgroups');
- expect(vm.$el.dataset.placement).toBe('left');
- });
-
- it('renders element icon correctly', () => {
- expect(vm.$el.querySelector('svg').getAttribute('data-testid')).toBe('folder-icon');
- });
+ it('renders element icon correctly', () => {
+ expect(findGlIcon().exists()).toBe(true);
+ expect(findGlIcon().props('name')).toBe('folder');
+ });
- it('renders value count correctly', () => {
- expect(vm.$el.querySelector('.stat-value').innerText.trim()).toContain('10');
+ it('renders value count correctly', () => {
+ expect(findStatValue().classes()).toContain('stat-value');
+ expect(findStatValue().text()).toBe('10');
+ });
});
});
});
diff --git a/spec/frontend/groups/components/item_type_icon_spec.js b/spec/frontend/groups/components/item_type_icon_spec.js
index 477c413ddcd..5e7056be218 100644
--- a/spec/frontend/groups/components/item_type_icon_spec.js
+++ b/spec/frontend/groups/components/item_type_icon_spec.js
@@ -1,53 +1,53 @@
-import Vue from 'vue';
-
-import mountComponent from 'helpers/vue_mount_component_helper';
-import itemTypeIconComponent from '~/groups/components/item_type_icon.vue';
+import { shallowMount } from '@vue/test-utils';
+import { GlIcon } from '@gitlab/ui';
+import ItemTypeIcon from '~/groups/components/item_type_icon.vue';
import { ITEM_TYPE } from '../mock_data';
-const createComponent = (itemType = ITEM_TYPE.GROUP, isGroupOpen = false) => {
- const Component = Vue.extend(itemTypeIconComponent);
-
- return mountComponent(Component, {
- itemType,
- isGroupOpen,
- });
-};
+describe('ItemTypeIcon', () => {
+ let wrapper;
-describe('ItemTypeIconComponent', () => {
- describe('template', () => {
- it('should render component template correctly', () => {
- const vm = createComponent();
+ const defaultProps = {
+ itemType: ITEM_TYPE.GROUP,
+ isGroupOpen: false,
+ };
- expect(vm.$el.classList.contains('item-type-icon')).toBeTruthy();
- vm.$destroy();
+ const createComponent = (props = {}) => {
+ wrapper = shallowMount(ItemTypeIcon, {
+ propsData: { ...defaultProps, ...props },
});
+ };
- it('should render folder open or close icon based `isGroupOpen` prop value', () => {
- let vm;
-
- vm = createComponent(ITEM_TYPE.GROUP, true);
+ afterEach(() => {
+ if (wrapper) {
+ wrapper.destroy();
+ wrapper = null;
+ }
+ });
- expect(vm.$el.querySelector('svg').getAttribute('data-testid')).toBe('folder-open-icon');
- vm.$destroy();
+ const findGlIcon = () => wrapper.find(GlIcon);
- vm = createComponent(ITEM_TYPE.GROUP);
+ describe('template', () => {
+ it('renders component template correctly', () => {
+ createComponent();
- expect(vm.$el.querySelector('svg').getAttribute('data-testid')).toBe('folder-o-icon');
- vm.$destroy();
+ expect(wrapper.classes()).toContain('item-type-icon');
});
- it('should render bookmark icon based on `isProject` prop value', () => {
- let vm;
-
- vm = createComponent(ITEM_TYPE.PROJECT);
-
- expect(vm.$el.querySelector('svg').getAttribute('data-testid')).toBe('bookmark-icon');
- vm.$destroy();
-
- vm = createComponent(ITEM_TYPE.GROUP);
-
- expect(vm.$el.querySelector('svg').getAttribute('data-testid')).not.toBe('bookmark-icon');
- vm.$destroy();
- });
+ it.each`
+ type | isGroupOpen | icon
+ ${ITEM_TYPE.GROUP} | ${true} | ${'folder-open'}
+ ${ITEM_TYPE.GROUP} | ${false} | ${'folder-o'}
+ ${ITEM_TYPE.PROJECT} | ${true} | ${'bookmark'}
+ ${ITEM_TYPE.PROJECT} | ${false} | ${'bookmark'}
+ `(
+ 'shows "$icon" icon when `itemType` is "$type" and `isGroupOpen` is $isGroupOpen',
+ ({ type, isGroupOpen, icon }) => {
+ createComponent({
+ itemType: type,
+ isGroupOpen,
+ });
+ expect(findGlIcon().props('name')).toBe(icon);
+ },
+ );
});
});
diff --git a/spec/frontend/groups/members/components/app_spec.js b/spec/frontend/groups/members/components/app_spec.js
new file mode 100644
index 00000000000..de9f30649e9
--- /dev/null
+++ b/spec/frontend/groups/members/components/app_spec.js
@@ -0,0 +1,89 @@
+import { shallowMount, createLocalVue } from '@vue/test-utils';
+import { nextTick } from 'vue';
+import Vuex from 'vuex';
+import { GlAlert } from '@gitlab/ui';
+import App from '~/groups/members/components/app.vue';
+import * as commonUtils from '~/lib/utils/common_utils';
+import {
+ RECEIVE_MEMBER_ROLE_ERROR,
+ HIDE_ERROR,
+} from '~/vuex_shared/modules/members/mutation_types';
+import mutations from '~/vuex_shared/modules/members/mutations';
+
+describe('GroupMembersApp', () => {
+ const localVue = createLocalVue();
+ localVue.use(Vuex);
+
+ let wrapper;
+ let store;
+
+ const createComponent = (state = {}) => {
+ store = new Vuex.Store({
+ state: {
+ showError: true,
+ errorMessage: 'Something went wrong, please try again.',
+ ...state,
+ },
+ mutations,
+ });
+
+ wrapper = shallowMount(App, {
+ localVue,
+ store,
+ });
+ };
+
+ const findAlert = () => wrapper.find(GlAlert);
+
+ beforeEach(() => {
+ commonUtils.scrollToElement = jest.fn();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ store = null;
+ });
+
+ describe('when `showError` is changed to `true`', () => {
+ it('renders and scrolls to error alert', async () => {
+ createComponent({ showError: false, errorMessage: '' });
+
+ store.commit(RECEIVE_MEMBER_ROLE_ERROR);
+
+ await nextTick();
+
+ const alert = findAlert();
+
+ expect(alert.exists()).toBe(true);
+ expect(alert.text()).toBe(
+ "An error occurred while updating the member's role, please try again.",
+ );
+ expect(commonUtils.scrollToElement).toHaveBeenCalledWith(alert.element);
+ });
+ });
+
+ describe('when `showError` is changed to `false`', () => {
+ it('does not render and scroll to error alert', async () => {
+ createComponent();
+
+ store.commit(HIDE_ERROR);
+
+ await nextTick();
+
+ expect(findAlert().exists()).toBe(false);
+ expect(commonUtils.scrollToElement).not.toHaveBeenCalled();
+ });
+ });
+
+ describe('when alert is dismissed', () => {
+ it('hides alert', async () => {
+ createComponent();
+
+ findAlert().vm.$emit('dismiss');
+
+ await nextTick();
+
+ expect(findAlert().exists()).toBe(false);
+ });
+ });
+});
diff --git a/spec/frontend/groups/members/index_spec.js b/spec/frontend/groups/members/index_spec.js
index 70fce0d60fb..2fb7904bcfe 100644
--- a/spec/frontend/groups/members/index_spec.js
+++ b/spec/frontend/groups/members/index_spec.js
@@ -1,5 +1,5 @@
import { createWrapper } from '@vue/test-utils';
-import initGroupMembersApp from '~/groups/members';
+import { initGroupMembersApp } from '~/groups/members';
import GroupMembersApp from '~/groups/members/components/app.vue';
import { membersJsonString, membersParsed } from './mock_data';
@@ -9,7 +9,7 @@ describe('initGroupMembersApp', () => {
let wrapper;
const setup = () => {
- vm = initGroupMembersApp(el);
+ vm = initGroupMembersApp(el, ['account'], () => ({}));
wrapper = createWrapper(vm);
};
@@ -17,14 +17,12 @@ describe('initGroupMembersApp', () => {
el = document.createElement('div');
el.setAttribute('data-members', membersJsonString);
el.setAttribute('data-group-id', '234');
+ el.setAttribute('data-member-path', '/groups/foo-bar/-/group_members/:id');
window.gon = { current_user_id: 123 };
-
- document.body.appendChild(el);
});
afterEach(() => {
- document.body.innerHTML = '';
el = null;
wrapper.destroy();
@@ -63,4 +61,22 @@ describe('initGroupMembersApp', () => {
expect(vm.$store.state.members).toEqual(membersParsed);
});
+
+ it('sets `tableFields` in Vuex store', () => {
+ setup();
+
+ expect(vm.$store.state.tableFields).toEqual(['account']);
+ });
+
+ it('sets `requestFormatter` in Vuex store', () => {
+ setup();
+
+ expect(vm.$store.state.requestFormatter()).toEqual({});
+ });
+
+ it('sets `memberPath` in Vuex store', () => {
+ setup();
+
+ expect(vm.$store.state.memberPath).toBe('/groups/foo-bar/-/group_members/:id');
+ });
});
diff --git a/spec/frontend/groups/members/utils_spec.js b/spec/frontend/groups/members/utils_spec.js
new file mode 100644
index 00000000000..b0921c7642f
--- /dev/null
+++ b/spec/frontend/groups/members/utils_spec.js
@@ -0,0 +1,51 @@
+import { membersJsonString, membersParsed } from './mock_data';
+import {
+ parseDataAttributes,
+ memberRequestFormatter,
+ groupLinkRequestFormatter,
+} from '~/groups/members/utils';
+
+describe('group member utils', () => {
+ describe('parseDataAttributes', () => {
+ let el;
+
+ beforeEach(() => {
+ el = document.createElement('div');
+ el.setAttribute('data-members', membersJsonString);
+ el.setAttribute('data-group-id', '234');
+ });
+
+ afterEach(() => {
+ el = null;
+ });
+
+ it('correctly parses the data attributes', () => {
+ expect(parseDataAttributes(el)).toEqual({
+ members: membersParsed,
+ sourceId: 234,
+ });
+ });
+ });
+
+ describe('memberRequestFormatter', () => {
+ it('returns expected format', () => {
+ expect(
+ memberRequestFormatter({
+ accessLevel: 50,
+ expires_at: '2020-10-16',
+ }),
+ ).toEqual({ group_member: { access_level: 50, expires_at: '2020-10-16' } });
+ });
+ });
+
+ describe('groupLinkRequestFormatter', () => {
+ it('returns expected format', () => {
+ expect(
+ groupLinkRequestFormatter({
+ accessLevel: 50,
+ expires_at: '2020-10-16',
+ }),
+ ).toEqual({ group_link: { group_access: 50, expires_at: '2020-10-16' } });
+ });
+ });
+});
diff --git a/spec/frontend/helpers/dom_shims/create_object_url.js b/spec/frontend/helpers/dom_shims/create_object_url.js
new file mode 100644
index 00000000000..94d060cab08
--- /dev/null
+++ b/spec/frontend/helpers/dom_shims/create_object_url.js
@@ -0,0 +1,3 @@
+URL.createObjectURL = function createObjectURL() {
+ return 'blob:https://gitlab.com/048c7ac1-98de-4a37-ab1b-0206d0ea7e1b';
+};
diff --git a/spec/frontend/helpers/dom_shims/index.js b/spec/frontend/helpers/dom_shims/index.js
index 2ba5701fc77..9b70cb86b8b 100644
--- a/spec/frontend/helpers/dom_shims/index.js
+++ b/spec/frontend/helpers/dom_shims/index.js
@@ -1,3 +1,4 @@
+import './create_object_url';
import './element_scroll_into_view';
import './element_scroll_by';
import './element_scroll_to';
diff --git a/spec/frontend/helpers/emoji.js b/spec/frontend/helpers/emoji.js
new file mode 100644
index 00000000000..e8a93e21818
--- /dev/null
+++ b/spec/frontend/helpers/emoji.js
@@ -0,0 +1,88 @@
+import MockAdapter from 'axios-mock-adapter';
+import axios from '~/lib/utils/axios_utils';
+import { initEmojiMap, EMOJI_VERSION } from '~/emoji';
+
+export const emojiFixtureMap = {
+ atom: {
+ moji: 'âš›',
+ description: 'atom symbol',
+ unicodeVersion: '4.1',
+ aliases: ['atom_symbol'],
+ },
+ bomb: {
+ moji: '💣',
+ unicodeVersion: '6.0',
+ description: 'bomb',
+ },
+ construction_worker_tone5: {
+ moji: '👷ðŸ¿',
+ unicodeVersion: '8.0',
+ description: 'construction worker tone 5',
+ },
+ five: {
+ moji: '5ï¸âƒ£',
+ unicodeVersion: '3.0',
+ description: 'keycap digit five',
+ },
+ grey_question: {
+ moji: 'â”',
+ unicodeVersion: '6.0',
+ description: 'white question mark ornament',
+ },
+
+ // used for regression tests
+ // black_heart MUST come before heart
+ // custard MUST come before star
+ black_heart: {
+ moji: '🖤',
+ unicodeVersion: '1.1',
+ description: 'black heart',
+ },
+ heart: {
+ moji: 'â¤',
+ unicodeVersion: '1.1',
+ description: 'heavy black heart',
+ },
+ custard: {
+ moji: 'ðŸ®',
+ unicodeVersion: '6.0',
+ description: 'custard',
+ },
+ star: {
+ moji: 'â­',
+ unicodeVersion: '5.1',
+ description: 'white medium star',
+ },
+};
+
+Object.keys(emojiFixtureMap).forEach(k => {
+ emojiFixtureMap[k].name = k;
+ if (!emojiFixtureMap[k].aliases) {
+ emojiFixtureMap[k].aliases = [];
+ }
+});
+
+export async function initEmojiMock() {
+ const emojiData = Object.fromEntries(
+ Object.values(emojiFixtureMap).map(m => {
+ const { name: n, moji: e, unicodeVersion: u, category: c, description: d } = m;
+ return [n, { c, e, d, u }];
+ }),
+ );
+
+ const mock = new MockAdapter(axios);
+ mock.onGet(`/-/emojis/${EMOJI_VERSION}/emojis.json`).reply(200, JSON.stringify(emojiData));
+
+ await initEmojiMap();
+
+ return mock;
+}
+
+export function describeEmojiFields(label, tests) {
+ describe.each`
+ field | accessor
+ ${'name'} | ${e => e.name}
+ ${'alias'} | ${e => e.aliases[0]}
+ ${'description'} | ${e => e.description}
+ `(label, tests);
+}
diff --git a/spec/frontend/helpers/experimentation_helper.js b/spec/frontend/helpers/experimentation_helper.js
new file mode 100644
index 00000000000..c08c25155e8
--- /dev/null
+++ b/spec/frontend/helpers/experimentation_helper.js
@@ -0,0 +1,14 @@
+import { merge } from 'lodash';
+
+export function withGonExperiment(experimentKey, value = true) {
+ let origGon;
+
+ beforeEach(() => {
+ origGon = window.gon;
+ window.gon = merge({}, window.gon || {}, { experiments: { [experimentKey]: value } });
+ });
+
+ afterEach(() => {
+ window.gon = origGon;
+ });
+}
diff --git a/spec/frontend/helpers/keep_alive_component_helper.js b/spec/frontend/helpers/keep_alive_component_helper.js
new file mode 100644
index 00000000000..54f40bf9093
--- /dev/null
+++ b/spec/frontend/helpers/keep_alive_component_helper.js
@@ -0,0 +1,29 @@
+import Vue from 'vue';
+
+export function keepAlive(KeptAliveComponent) {
+ return Vue.extend({
+ components: {
+ KeptAliveComponent,
+ },
+ data() {
+ return {
+ view: 'KeptAliveComponent',
+ };
+ },
+ methods: {
+ async activate() {
+ this.view = 'KeptAliveComponent';
+ await this.$nextTick();
+ },
+ async deactivate() {
+ this.view = 'div';
+ await this.$nextTick();
+ },
+ async reactivate() {
+ await this.deactivate();
+ await this.activate();
+ },
+ },
+ template: `<keep-alive><component :is="view"></component></keep-alive>`,
+ });
+}
diff --git a/spec/frontend/helpers/keep_alive_component_helper_spec.js b/spec/frontend/helpers/keep_alive_component_helper_spec.js
new file mode 100644
index 00000000000..dcccc14f396
--- /dev/null
+++ b/spec/frontend/helpers/keep_alive_component_helper_spec.js
@@ -0,0 +1,32 @@
+import { mount } from '@vue/test-utils';
+import { keepAlive } from './keep_alive_component_helper';
+
+const component = {
+ template: '<div>Test Component</div>',
+};
+
+describe('keepAlive', () => {
+ let wrapper;
+
+ beforeEach(() => {
+ wrapper = mount(keepAlive(component));
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('converts a component to a keep-alive component', async () => {
+ const { element } = wrapper.find(component);
+
+ await wrapper.vm.deactivate();
+ expect(wrapper.find(component).exists()).toBe(false);
+
+ await wrapper.vm.activate();
+
+ // assert that when the component is destroyed and re-rendered, the
+ // newly rendered component has the reference to the old component
+ // (i.e. the old component was deactivated and activated)
+ expect(wrapper.find(component).element).toBe(element);
+ });
+});
diff --git a/spec/frontend/helpers/local_storage_helper.js b/spec/frontend/helpers/local_storage_helper.js
index cd39b660bfd..0318b80aaef 100644
--- a/spec/frontend/helpers/local_storage_helper.js
+++ b/spec/frontend/helpers/local_storage_helper.js
@@ -35,7 +35,7 @@ export const createLocalStorageSpy = () => {
clear: jest.fn(() => {
storage = {};
}),
- getItem: jest.fn(key => storage[key]),
+ getItem: jest.fn(key => (key in storage ? storage[key] : null)),
setItem: jest.fn((key, value) => {
storage[key] = value;
}),
diff --git a/spec/frontend/helpers/local_storage_helper_spec.js b/spec/frontend/helpers/local_storage_helper_spec.js
index 6b44ea3a4c3..5d9961e7631 100644
--- a/spec/frontend/helpers/local_storage_helper_spec.js
+++ b/spec/frontend/helpers/local_storage_helper_spec.js
@@ -18,11 +18,11 @@ describe('localStorage helper', () => {
localStorage.removeItem('test', 'testing');
- expect(localStorage.getItem('test')).toBeUndefined();
+ expect(localStorage.getItem('test')).toBe(null);
expect(localStorage.getItem('test2')).toBe('testing');
localStorage.clear();
- expect(localStorage.getItem('test2')).toBeUndefined();
+ expect(localStorage.getItem('test2')).toBe(null);
});
});
diff --git a/spec/frontend/helpers/startup_css_helper_spec.js b/spec/frontend/helpers/startup_css_helper_spec.js
index 7b83f0aefca..1a88e80344e 100644
--- a/spec/frontend/helpers/startup_css_helper_spec.js
+++ b/spec/frontend/helpers/startup_css_helper_spec.js
@@ -1,4 +1,4 @@
-import { waitForCSSLoaded } from '../../../app/assets/javascripts/helpers/startup_css_helper';
+import { waitForCSSLoaded } from '~/helpers/startup_css_helper';
describe('waitForCSSLoaded', () => {
let mockedCallback;
diff --git a/spec/frontend/helpers/vue_test_utils_helper.js b/spec/frontend/helpers/vue_test_utils_helper.js
index 68326e37ae7..ead898f04d3 100644
--- a/spec/frontend/helpers/vue_test_utils_helper.js
+++ b/spec/frontend/helpers/vue_test_utils_helper.js
@@ -33,3 +33,10 @@ export const waitForMutation = (store, expectedMutationType) =>
}
});
});
+
+export const extendedWrapper = wrapper =>
+ Object.defineProperty(wrapper, 'findByTestId', {
+ value(id) {
+ return this.find(`[data-testid="${id}"]`);
+ },
+ });
diff --git a/spec/frontend/helpers/wait_for_text.js b/spec/frontend/helpers/wait_for_text.js
new file mode 100644
index 00000000000..6bed8a90a98
--- /dev/null
+++ b/spec/frontend/helpers/wait_for_text.js
@@ -0,0 +1,3 @@
+import { findByText } from '@testing-library/dom';
+
+export const waitForText = async (text, container = document) => findByText(container, text);
diff --git a/spec/frontend/ide/components/commit_sidebar/actions_spec.js b/spec/frontend/ide/components/commit_sidebar/actions_spec.js
index a303e2b9bee..0003e13c92f 100644
--- a/spec/frontend/ide/components/commit_sidebar/actions_spec.js
+++ b/spec/frontend/ide/components/commit_sidebar/actions_spec.js
@@ -83,12 +83,12 @@ describe('IDE commit sidebar actions', () => {
});
});
- describe('commitToCurrentBranchText', () => {
+ describe('currentBranchText', () => {
it('escapes current branch', () => {
const injectedSrc = '<img src="x" />';
createComponent({ currentBranchId: injectedSrc });
- expect(vm.commitToCurrentBranchText).not.toContain(injectedSrc);
+ expect(vm.currentBranchText).not.toContain(injectedSrc);
});
});
diff --git a/spec/frontend/ide/components/commit_sidebar/form_spec.js b/spec/frontend/ide/components/commit_sidebar/form_spec.js
index 56667d6b03d..abd7e3bb8fc 100644
--- a/spec/frontend/ide/components/commit_sidebar/form_spec.js
+++ b/spec/frontend/ide/components/commit_sidebar/form_spec.js
@@ -7,7 +7,12 @@ import { createStore } from '~/ide/stores';
import consts from '~/ide/stores/modules/commit/constants';
import CommitForm from '~/ide/components/commit_sidebar/form.vue';
import { leftSidebarViews } from '~/ide/constants';
-import { createCodeownersCommitError, createUnexpectedCommitError } from '~/ide/lib/errors';
+import {
+ createCodeownersCommitError,
+ createUnexpectedCommitError,
+ createBranchChangedCommitError,
+ branchAlreadyExistsCommitError,
+} from '~/ide/lib/errors';
describe('IDE commit form', () => {
const Component = Vue.extend(CommitForm);
@@ -290,20 +295,30 @@ describe('IDE commit form', () => {
jest.spyOn(vm.$store, 'dispatch').mockReturnValue(Promise.resolve());
});
- it('updates commit action and commits', async () => {
- store.state.commit.commitError = createCodeownersCommitError('test message');
+ const commitActions = [
+ ['commit/updateCommitAction', consts.COMMIT_TO_NEW_BRANCH],
+ ['commit/commitChanges'],
+ ];
- await vm.$nextTick();
+ it.each`
+ commitError | expectedActions
+ ${createCodeownersCommitError} | ${commitActions}
+ ${createBranchChangedCommitError} | ${commitActions}
+ ${branchAlreadyExistsCommitError} | ${[['commit/addSuffixToBranchName'], ...commitActions]}
+ `(
+ 'updates commit action and commits for error: $commitError',
+ async ({ commitError, expectedActions }) => {
+ store.state.commit.commitError = commitError('test message');
- getByText(document.body, 'Create new branch').click();
+ await vm.$nextTick();
- await waitForPromises();
+ getByText(document.body, 'Create new branch').click();
- expect(vm.$store.dispatch.mock.calls).toEqual([
- ['commit/updateCommitAction', consts.COMMIT_TO_NEW_BRANCH],
- ['commit/commitChanges', undefined],
- ]);
- });
+ await waitForPromises();
+
+ expect(vm.$store.dispatch.mock.calls).toEqual(expectedActions);
+ },
+ );
});
});
diff --git a/spec/frontend/ide/components/ide_review_spec.js b/spec/frontend/ide/components/ide_review_spec.js
index c9ac2ac423d..bcc98669427 100644
--- a/spec/frontend/ide/components/ide_review_spec.js
+++ b/spec/frontend/ide/components/ide_review_spec.js
@@ -1,14 +1,19 @@
import Vue from 'vue';
+import Vuex from 'vuex';
+import { createLocalVue, mount } from '@vue/test-utils';
import IdeReview from '~/ide/components/ide_review.vue';
+import EditorModeDropdown from '~/ide/components/editor_mode_dropdown.vue';
import { createStore } from '~/ide/stores';
-import { createComponentWithStore } from '../../helpers/vue_mount_component_helper';
import { trimText } from '../../helpers/text_helper';
+import { keepAlive } from '../../helpers/keep_alive_component_helper';
import { file } from '../helpers';
import { projectData } from '../mock_data';
+const localVue = createLocalVue();
+localVue.use(Vuex);
+
describe('IDE review mode', () => {
- const Component = Vue.extend(IdeReview);
- let vm;
+ let wrapper;
let store;
beforeEach(() => {
@@ -21,15 +26,53 @@ describe('IDE review mode', () => {
loading: false,
});
- vm = createComponentWithStore(Component, store).$mount();
+ wrapper = mount(keepAlive(IdeReview), {
+ store,
+ localVue,
+ });
});
afterEach(() => {
- vm.$destroy();
+ wrapper.destroy();
});
it('renders list of files', () => {
- expect(vm.$el.textContent).toContain('fileName');
+ expect(wrapper.text()).toContain('fileName');
+ });
+
+ describe('activated', () => {
+ let inititializeSpy;
+
+ beforeEach(async () => {
+ inititializeSpy = jest.spyOn(wrapper.find(IdeReview).vm, 'initialize');
+ store.state.viewer = 'editor';
+
+ await wrapper.vm.reactivate();
+ });
+
+ it('re initializes the component', () => {
+ expect(inititializeSpy).toHaveBeenCalled();
+ });
+
+ it('updates viewer to "diff" by default', () => {
+ expect(store.state.viewer).toBe('diff');
+ });
+
+ describe('merge request is defined', () => {
+ beforeEach(async () => {
+ store.state.currentMergeRequestId = '1';
+ store.state.projects.abcproject.mergeRequests['1'] = {
+ iid: 123,
+ web_url: 'testing123',
+ };
+
+ await wrapper.vm.reactivate();
+ });
+
+ it('updates viewer to "mrdiff"', async () => {
+ expect(store.state.viewer).toBe('mrdiff');
+ });
+ });
});
describe('merge request', () => {
@@ -40,32 +83,27 @@ describe('IDE review mode', () => {
web_url: 'testing123',
};
- return vm.$nextTick();
+ return wrapper.vm.$nextTick();
});
it('renders edit dropdown', () => {
- expect(vm.$el.querySelector('.btn')).not.toBe(null);
+ expect(wrapper.find(EditorModeDropdown).exists()).toBe(true);
});
- it('renders merge request link & IID', () => {
+ it('renders merge request link & IID', async () => {
store.state.viewer = 'mrdiff';
- return vm.$nextTick(() => {
- const link = vm.$el.querySelector('.ide-review-sub-header');
+ await wrapper.vm.$nextTick();
- expect(link.querySelector('a').getAttribute('href')).toBe('testing123');
- expect(trimText(link.textContent)).toBe('Merge request (!123)');
- });
+ expect(trimText(wrapper.text())).toContain('Merge request (!123)');
});
- it('changes text to latest changes when viewer is not mrdiff', () => {
+ it('changes text to latest changes when viewer is not mrdiff', async () => {
store.state.viewer = 'diff';
- return vm.$nextTick(() => {
- expect(trimText(vm.$el.querySelector('.ide-review-sub-header').textContent)).toBe(
- 'Latest changes',
- );
- });
+ await wrapper.vm.$nextTick();
+
+ expect(wrapper.text()).toContain('Latest changes');
});
});
});
diff --git a/spec/frontend/ide/components/ide_side_bar_spec.js b/spec/frontend/ide/components/ide_side_bar_spec.js
index 67257b40879..86e4e8d8f89 100644
--- a/spec/frontend/ide/components/ide_side_bar_spec.js
+++ b/spec/frontend/ide/components/ide_side_bar_spec.js
@@ -1,57 +1,88 @@
-import Vue from 'vue';
-import { createComponentWithStore } from 'helpers/vue_mount_component_helper';
+import { mount, createLocalVue } from '@vue/test-utils';
+import Vuex from 'vuex';
+import { GlSkeletonLoading } from '@gitlab/ui';
import { createStore } from '~/ide/stores';
-import ideSidebar from '~/ide/components/ide_side_bar.vue';
+import IdeSidebar from '~/ide/components/ide_side_bar.vue';
+import IdeTree from '~/ide/components/ide_tree.vue';
+import RepoCommitSection from '~/ide/components/repo_commit_section.vue';
import { leftSidebarViews } from '~/ide/constants';
import { projectData } from '../mock_data';
+const localVue = createLocalVue();
+localVue.use(Vuex);
+
describe('IdeSidebar', () => {
- let vm;
+ let wrapper;
let store;
- beforeEach(() => {
+ function createComponent() {
store = createStore();
- const Component = Vue.extend(ideSidebar);
-
store.state.currentProjectId = 'abcproject';
store.state.projects.abcproject = projectData;
- vm = createComponentWithStore(Component, store).$mount();
- });
+ return mount(IdeSidebar, {
+ store,
+ localVue,
+ });
+ }
afterEach(() => {
- vm.$destroy();
+ wrapper.destroy();
+ wrapper = null;
});
it('renders a sidebar', () => {
- expect(vm.$el.querySelector('.multi-file-commit-panel-inner')).not.toBeNull();
+ wrapper = createComponent();
+
+ expect(wrapper.find('[data-testid="ide-side-bar-inner"]').exists()).toBe(true);
});
- it('renders loading icon component', done => {
- vm.$store.state.loading = true;
+ it('renders loading components', async () => {
+ wrapper = createComponent();
- vm.$nextTick(() => {
- expect(vm.$el.querySelector('.multi-file-loading-container')).not.toBeNull();
- expect(vm.$el.querySelectorAll('.multi-file-loading-container').length).toBe(3);
+ store.state.loading = true;
- done();
- });
+ await wrapper.vm.$nextTick();
+
+ expect(wrapper.findAll(GlSkeletonLoading)).toHaveLength(3);
});
describe('activityBarComponent', () => {
it('renders tree component', () => {
- expect(vm.$el.querySelector('.ide-file-list')).not.toBeNull();
+ wrapper = createComponent();
+
+ expect(wrapper.find(IdeTree).exists()).toBe(true);
});
- it('renders commit component', done => {
- vm.$store.state.currentActivityView = leftSidebarViews.commit.name;
+ it('renders commit component', async () => {
+ wrapper = createComponent();
+
+ store.state.currentActivityView = leftSidebarViews.commit.name;
- vm.$nextTick(() => {
- expect(vm.$el.querySelector('.multi-file-commit-panel-section')).not.toBeNull();
+ await wrapper.vm.$nextTick();
- done();
- });
+ expect(wrapper.find(RepoCommitSection).exists()).toBe(true);
});
});
+
+ it('keeps the current activity view components alive', async () => {
+ wrapper = createComponent();
+
+ const ideTreeComponent = wrapper.find(IdeTree).element;
+
+ store.state.currentActivityView = leftSidebarViews.commit.name;
+
+ await wrapper.vm.$nextTick();
+
+ expect(wrapper.find(IdeTree).exists()).toBe(false);
+ expect(wrapper.find(RepoCommitSection).exists()).toBe(true);
+
+ store.state.currentActivityView = leftSidebarViews.edit.name;
+
+ await wrapper.vm.$nextTick();
+
+ // reference to the elements remains the same, meaning the components were kept alive
+ expect(wrapper.find(IdeTree).element).toEqual(ideTreeComponent);
+ });
});
diff --git a/spec/frontend/ide/components/ide_tree_list_spec.js b/spec/frontend/ide/components/ide_tree_list_spec.js
index 4593ef6049b..dd57a5c5f4d 100644
--- a/spec/frontend/ide/components/ide_tree_list_spec.js
+++ b/spec/frontend/ide/components/ide_tree_list_spec.js
@@ -38,15 +38,9 @@ describe('IDE tree list', () => {
beforeEach(() => {
bootstrapWithTree();
- jest.spyOn(vm, 'updateViewer');
-
vm.$mount();
});
- it('updates viewer on mount', () => {
- expect(vm.updateViewer).toHaveBeenCalledWith('edit');
- });
-
it('renders loading indicator', done => {
store.state.trees['abcproject/master'].loading = true;
@@ -67,8 +61,6 @@ describe('IDE tree list', () => {
beforeEach(() => {
bootstrapWithTree(emptyBranchTree);
- jest.spyOn(vm, 'updateViewer');
-
vm.$mount();
});
diff --git a/spec/frontend/ide/components/ide_tree_spec.js b/spec/frontend/ide/components/ide_tree_spec.js
index 899daa0bf57..ad00dec2e48 100644
--- a/spec/frontend/ide/components/ide_tree_spec.js
+++ b/spec/frontend/ide/components/ide_tree_spec.js
@@ -1,19 +1,22 @@
import Vue from 'vue';
+import Vuex from 'vuex';
+import { mount, createLocalVue } from '@vue/test-utils';
import IdeTree from '~/ide/components/ide_tree.vue';
import { createStore } from '~/ide/stores';
-import { createComponentWithStore } from '../../helpers/vue_mount_component_helper';
+import { keepAlive } from '../../helpers/keep_alive_component_helper';
import { file } from '../helpers';
import { projectData } from '../mock_data';
-describe('IdeRepoTree', () => {
+const localVue = createLocalVue();
+localVue.use(Vuex);
+
+describe('IdeTree', () => {
let store;
- let vm;
+ let wrapper;
beforeEach(() => {
store = createStore();
- const IdeRepoTree = Vue.extend(IdeTree);
-
store.state.currentProjectId = 'abcproject';
store.state.currentBranchId = 'master';
store.state.projects.abcproject = { ...projectData };
@@ -22,14 +25,36 @@ describe('IdeRepoTree', () => {
loading: false,
});
- vm = createComponentWithStore(IdeRepoTree, store).$mount();
+ wrapper = mount(keepAlive(IdeTree), {
+ store,
+ localVue,
+ });
});
afterEach(() => {
- vm.$destroy();
+ wrapper.destroy();
});
it('renders list of files', () => {
- expect(vm.$el.textContent).toContain('fileName');
+ expect(wrapper.text()).toContain('fileName');
+ });
+
+ describe('activated', () => {
+ let inititializeSpy;
+
+ beforeEach(async () => {
+ inititializeSpy = jest.spyOn(wrapper.find(IdeTree).vm, 'initialize');
+ store.state.viewer = 'diff';
+
+ await wrapper.vm.reactivate();
+ });
+
+ it('re initializes the component', () => {
+ expect(inititializeSpy).toHaveBeenCalled();
+ });
+
+ it('updates viewer to "editor" by default', () => {
+ expect(store.state.viewer).toBe('editor');
+ });
});
});
diff --git a/spec/frontend/ide/components/jobs/__snapshots__/stage_spec.js.snap b/spec/frontend/ide/components/jobs/__snapshots__/stage_spec.js.snap
index a65d9e6f78b..faa70982fac 100644
--- a/spec/frontend/ide/components/jobs/__snapshots__/stage_spec.js.snap
+++ b/spec/frontend/ide/components/jobs/__snapshots__/stage_spec.js.snap
@@ -16,8 +16,6 @@ exports[`IDE pipeline stage renders stage details & icon 1`] = `
<strong
class="gl-ml-3 text-truncate"
data-container="body"
- data-original-title=""
- title=""
>
build
diff --git a/spec/frontend/ide/components/jobs/detail/scroll_button_spec.js b/spec/frontend/ide/components/jobs/detail/scroll_button_spec.js
index 42526590ebb..57174181a3d 100644
--- a/spec/frontend/ide/components/jobs/detail/scroll_button_spec.js
+++ b/spec/frontend/ide/components/jobs/detail/scroll_button_spec.js
@@ -31,7 +31,7 @@ describe('IDE job log scroll button', () => {
});
it('returns proper title', () => {
- expect(wrapper.attributes('data-original-title')).toBe(title);
+ expect(wrapper.attributes('title')).toBe(title);
});
});
diff --git a/spec/frontend/ide/components/new_dropdown/upload_spec.js b/spec/frontend/ide/components/new_dropdown/upload_spec.js
index ae497106f73..3f3784dbb3a 100644
--- a/spec/frontend/ide/components/new_dropdown/upload_spec.js
+++ b/spec/frontend/ide/components/new_dropdown/upload_spec.js
@@ -59,14 +59,11 @@ describe('new dropdown upload', () => {
result: 'base64,cGxhaW4gdGV4dA==',
};
const binaryTarget = {
- result: 'base64,w4I=',
+ result: 'base64,8PDw8A==', // ðððð
};
- const textFile = new File(['plain text'], 'textFile');
- const binaryFile = {
- name: 'binaryFile',
- type: 'image/png',
- };
+ const textFile = new File(['plain text'], 'textFile');
+ const binaryFile = new File(['😺'], 'binaryFile');
beforeEach(() => {
jest.spyOn(FileReader.prototype, 'readAsText');
@@ -92,16 +89,16 @@ describe('new dropdown upload', () => {
.catch(done.fail);
});
- it('splits content on base64 if binary', () => {
+ it('creates a blob URL for the content if binary', () => {
vm.createFile(binaryTarget, binaryFile);
- expect(FileReader.prototype.readAsText).not.toHaveBeenCalledWith(textFile);
+ expect(FileReader.prototype.readAsText).not.toHaveBeenCalled();
expect(vm.$emit).toHaveBeenCalledWith('create', {
name: binaryFile.name,
type: 'blob',
- content: binaryTarget.result.split('base64,')[1],
- rawPath: binaryTarget.result,
+ content: 'ðððð',
+ rawPath: 'blob:https://gitlab.com/048c7ac1-98de-4a37-ab1b-0206d0ea7e1b',
});
});
});
diff --git a/spec/frontend/ide/components/repo_commit_section_spec.js b/spec/frontend/ide/components/repo_commit_section_spec.js
index 3b837622720..096079308cd 100644
--- a/spec/frontend/ide/components/repo_commit_section_spec.js
+++ b/spec/frontend/ide/components/repo_commit_section_spec.js
@@ -1,6 +1,7 @@
import { mount } from '@vue/test-utils';
import { createStore } from '~/ide/stores';
import { createRouter } from '~/ide/ide_router';
+import { keepAlive } from '../../helpers/keep_alive_component_helper';
import RepoCommitSection from '~/ide/components/repo_commit_section.vue';
import EmptyState from '~/ide/components/commit_sidebar/empty_state.vue';
import { stageKeys } from '~/ide/constants';
@@ -14,7 +15,7 @@ describe('RepoCommitSection', () => {
let store;
function createComponent() {
- wrapper = mount(RepoCommitSection, { store });
+ wrapper = mount(keepAlive(RepoCommitSection), { store });
}
function setupDefaultState() {
@@ -64,6 +65,7 @@ describe('RepoCommitSection', () => {
afterEach(() => {
wrapper.destroy();
+ wrapper = null;
});
describe('empty state', () => {
@@ -168,4 +170,21 @@ describe('RepoCommitSection', () => {
expect(wrapper.find(EmptyState).exists()).toBe(false);
});
});
+
+ describe('activated', () => {
+ let inititializeSpy;
+
+ beforeEach(async () => {
+ createComponent();
+
+ inititializeSpy = jest.spyOn(wrapper.find(RepoCommitSection).vm, 'initialize');
+ store.state.viewer = 'diff';
+
+ await wrapper.vm.reactivate();
+ });
+
+ it('re initializes the component', () => {
+ expect(inititializeSpy).toHaveBeenCalled();
+ });
+ });
});
diff --git a/spec/frontend/ide/lib/errors_spec.js b/spec/frontend/ide/lib/errors_spec.js
index 8c3fb378302..733d5a5da3c 100644
--- a/spec/frontend/ide/lib/errors_spec.js
+++ b/spec/frontend/ide/lib/errors_spec.js
@@ -2,6 +2,7 @@ import {
createUnexpectedCommitError,
createCodeownersCommitError,
createBranchChangedCommitError,
+ branchAlreadyExistsCommitError,
parseCommitError,
} from '~/ide/lib/errors';
@@ -21,35 +22,22 @@ describe('~/ide/lib/errors', () => {
},
});
- describe('createCodeownersCommitError', () => {
- it('uses given message', () => {
- expect(createCodeownersCommitError(TEST_MESSAGE)).toEqual({
- title: 'CODEOWNERS rule violation',
- messageHTML: TEST_MESSAGE,
- canCreateBranch: true,
- });
- });
+ const NEW_BRANCH_SUFFIX = `<br/><br/>Would you like to create a new branch?`;
+ const AUTOGENERATE_SUFFIX = `<br/><br/>Would you like to try auto-generating a branch name?`;
- it('escapes special chars', () => {
- expect(createCodeownersCommitError(TEST_SPECIAL)).toEqual({
- title: 'CODEOWNERS rule violation',
- messageHTML: TEST_SPECIAL_ESCAPED,
- canCreateBranch: true,
- });
- });
- });
-
- describe('createBranchChangedCommitError', () => {
- it.each`
- message | expectedMessage
- ${TEST_MESSAGE} | ${`${TEST_MESSAGE}<br/><br/>Would you like to create a new branch?`}
- ${TEST_SPECIAL} | ${`${TEST_SPECIAL_ESCAPED}<br/><br/>Would you like to create a new branch?`}
- `('uses given message="$message"', ({ message, expectedMessage }) => {
- expect(createBranchChangedCommitError(message)).toEqual({
- title: 'Branch changed',
- messageHTML: expectedMessage,
- canCreateBranch: true,
- });
+ it.each`
+ fn | title | message | messageHTML
+ ${createCodeownersCommitError} | ${'CODEOWNERS rule violation'} | ${TEST_MESSAGE} | ${TEST_MESSAGE}
+ ${createCodeownersCommitError} | ${'CODEOWNERS rule violation'} | ${TEST_SPECIAL} | ${TEST_SPECIAL_ESCAPED}
+ ${branchAlreadyExistsCommitError} | ${'Branch already exists'} | ${TEST_MESSAGE} | ${`${TEST_MESSAGE}${AUTOGENERATE_SUFFIX}`}
+ ${branchAlreadyExistsCommitError} | ${'Branch already exists'} | ${TEST_SPECIAL} | ${`${TEST_SPECIAL_ESCAPED}${AUTOGENERATE_SUFFIX}`}
+ ${createBranchChangedCommitError} | ${'Branch changed'} | ${TEST_MESSAGE} | ${`${TEST_MESSAGE}${NEW_BRANCH_SUFFIX}`}
+ ${createBranchChangedCommitError} | ${'Branch changed'} | ${TEST_SPECIAL} | ${`${TEST_SPECIAL_ESCAPED}${NEW_BRANCH_SUFFIX}`}
+ `('$fn escapes and uses given message="$message"', ({ fn, title, message, messageHTML }) => {
+ expect(fn(message)).toEqual({
+ title,
+ messageHTML,
+ primaryAction: { text: 'Create new branch', callback: expect.any(Function) },
});
});
@@ -60,7 +48,7 @@ describe('~/ide/lib/errors', () => {
${{}} | ${createUnexpectedCommitError()}
${{ response: {} }} | ${createUnexpectedCommitError()}
${{ response: { data: {} } }} | ${createUnexpectedCommitError()}
- ${createResponseError('test')} | ${createUnexpectedCommitError()}
+ ${createResponseError(TEST_MESSAGE)} | ${createUnexpectedCommitError(TEST_MESSAGE)}
${createResponseError(CODEOWNERS_MESSAGE)} | ${createCodeownersCommitError(CODEOWNERS_MESSAGE)}
${createResponseError(CHANGED_MESSAGE)} | ${createBranchChangedCommitError(CHANGED_MESSAGE)}
`('parses message into error object with "$message"', ({ message, expectation }) => {
diff --git a/spec/frontend/ide/lib/languages/hcl_spec.js b/spec/frontend/ide/lib/languages/hcl_spec.js
new file mode 100644
index 00000000000..a39673a3225
--- /dev/null
+++ b/spec/frontend/ide/lib/languages/hcl_spec.js
@@ -0,0 +1,290 @@
+import { editor } from 'monaco-editor';
+import { registerLanguages } from '~/ide/utils';
+import hcl from '~/ide/lib/languages/hcl';
+
+describe('tokenization for .tf files', () => {
+ beforeEach(() => {
+ registerLanguages(hcl);
+ });
+
+ it.each([
+ ['// Foo', [[{ language: 'hcl', offset: 0, type: 'comment.hcl' }]]],
+ ['/* Bar */', [[{ language: 'hcl', offset: 0, type: 'comment.hcl' }]]],
+ ['/*', [[{ language: 'hcl', offset: 0, type: 'comment.hcl' }]]],
+ [
+ 'foo = "bar"',
+ [
+ [
+ { language: 'hcl', offset: 0, type: 'variable.hcl' },
+ { language: 'hcl', offset: 3, type: '' },
+ { language: 'hcl', offset: 4, type: 'operator.hcl' },
+ { language: 'hcl', offset: 5, type: '' },
+ { language: 'hcl', offset: 6, type: 'string.hcl' },
+ ],
+ ],
+ ],
+ [
+ 'variable "foo" {',
+ [
+ [
+ { language: 'hcl', offset: 0, type: 'type.hcl' },
+ { language: 'hcl', offset: 8, type: '' },
+ { language: 'hcl', offset: 9, type: 'string.hcl' },
+ { language: 'hcl', offset: 14, type: '' },
+ { language: 'hcl', offset: 15, type: 'delimiter.curly.hcl' },
+ ],
+ ],
+ ],
+ [
+ // eslint-disable-next-line no-template-curly-in-string
+ ' api_key = "${var.foo}"',
+ [
+ [
+ { language: 'hcl', offset: 0, type: '' },
+ { language: 'hcl', offset: 2, type: 'variable.hcl' },
+ { language: 'hcl', offset: 9, type: '' },
+ { language: 'hcl', offset: 10, type: 'operator.hcl' },
+ { language: 'hcl', offset: 11, type: '' },
+ { language: 'hcl', offset: 12, type: 'string.hcl' },
+ { language: 'hcl', offset: 13, type: 'delimiter.hcl' },
+ { language: 'hcl', offset: 15, type: 'keyword.var.hcl' },
+ { language: 'hcl', offset: 18, type: 'delimiter.hcl' },
+ { language: 'hcl', offset: 19, type: 'variable.hcl' },
+ { language: 'hcl', offset: 22, type: 'delimiter.hcl' },
+ { language: 'hcl', offset: 23, type: 'string.hcl' },
+ ],
+ ],
+ ],
+ [
+ 'resource "aws_security_group" "firewall" {',
+ [
+ [
+ { language: 'hcl', offset: 0, type: 'type.hcl' },
+ { language: 'hcl', offset: 8, type: '' },
+ { language: 'hcl', offset: 9, type: 'string.hcl' },
+ { language: 'hcl', offset: 29, type: '' },
+ { language: 'hcl', offset: 30, type: 'string.hcl' },
+ { language: 'hcl', offset: 40, type: '' },
+ { language: 'hcl', offset: 41, type: 'delimiter.curly.hcl' },
+ ],
+ ],
+ ],
+ [
+ ' network_interface {',
+ [
+ [
+ { language: 'hcl', offset: 0, type: '' },
+ { language: 'hcl', offset: 2, type: 'identifier.hcl' },
+ { language: 'hcl', offset: 20, type: 'delimiter.curly.hcl' },
+ ],
+ ],
+ ],
+ [
+ 'foo = [1, 2, "foo"]',
+ [
+ [
+ { language: 'hcl', offset: 0, type: 'variable.hcl' },
+ { language: 'hcl', offset: 3, type: '' },
+ { language: 'hcl', offset: 4, type: 'operator.hcl' },
+ { language: 'hcl', offset: 5, type: '' },
+ { language: 'hcl', offset: 6, type: 'delimiter.square.hcl' },
+ { language: 'hcl', offset: 7, type: 'number.hcl' },
+ { language: 'hcl', offset: 8, type: 'delimiter.hcl' },
+ { language: 'hcl', offset: 9, type: '' },
+ { language: 'hcl', offset: 10, type: 'number.hcl' },
+ { language: 'hcl', offset: 11, type: 'delimiter.hcl' },
+ { language: 'hcl', offset: 12, type: '' },
+ { language: 'hcl', offset: 13, type: 'string.hcl' },
+ { language: 'hcl', offset: 18, type: 'delimiter.square.hcl' },
+ ],
+ ],
+ ],
+ [
+ 'resource "foo" "bar" {}',
+ [
+ [
+ { language: 'hcl', offset: 0, type: 'type.hcl' },
+ { language: 'hcl', offset: 8, type: '' },
+ { language: 'hcl', offset: 9, type: 'string.hcl' },
+ { language: 'hcl', offset: 14, type: '' },
+ { language: 'hcl', offset: 15, type: 'string.hcl' },
+ { language: 'hcl', offset: 20, type: '' },
+ { language: 'hcl', offset: 21, type: 'delimiter.curly.hcl' },
+ ],
+ ],
+ ],
+ [
+ 'foo = "bar"',
+ [
+ [
+ { language: 'hcl', offset: 0, type: 'variable.hcl' },
+ { language: 'hcl', offset: 3, type: '' },
+ { language: 'hcl', offset: 4, type: 'operator.hcl' },
+ { language: 'hcl', offset: 5, type: '' },
+ { language: 'hcl', offset: 6, type: 'string.hcl' },
+ ],
+ ],
+ ],
+ [
+ 'bar = 7',
+ [
+ [
+ { language: 'hcl', offset: 0, type: 'variable.hcl' },
+ { language: 'hcl', offset: 3, type: '' },
+ { language: 'hcl', offset: 4, type: 'operator.hcl' },
+ { language: 'hcl', offset: 5, type: '' },
+ { language: 'hcl', offset: 6, type: 'number.hcl' },
+ ],
+ ],
+ ],
+ [
+ 'baz = [1,2,3]',
+ [
+ [
+ { language: 'hcl', offset: 0, type: 'variable.hcl' },
+ { language: 'hcl', offset: 3, type: '' },
+ { language: 'hcl', offset: 4, type: 'operator.hcl' },
+ { language: 'hcl', offset: 5, type: '' },
+ { language: 'hcl', offset: 6, type: 'delimiter.square.hcl' },
+ { language: 'hcl', offset: 7, type: 'number.hcl' },
+ { language: 'hcl', offset: 8, type: 'delimiter.hcl' },
+ { language: 'hcl', offset: 9, type: 'number.hcl' },
+ { language: 'hcl', offset: 10, type: 'delimiter.hcl' },
+ { language: 'hcl', offset: 11, type: 'number.hcl' },
+ { language: 'hcl', offset: 12, type: 'delimiter.square.hcl' },
+ ],
+ ],
+ ],
+ [
+ 'foo = -12',
+ [
+ [
+ { language: 'hcl', offset: 0, type: 'variable.hcl' },
+ { language: 'hcl', offset: 3, type: '' },
+ { language: 'hcl', offset: 4, type: 'operator.hcl' },
+ { language: 'hcl', offset: 5, type: '' },
+ { language: 'hcl', offset: 6, type: 'operator.hcl' },
+ { language: 'hcl', offset: 7, type: 'number.hcl' },
+ ],
+ ],
+ ],
+ [
+ 'bar = 3.14159',
+ [
+ [
+ { language: 'hcl', offset: 0, type: 'variable.hcl' },
+ { language: 'hcl', offset: 3, type: '' },
+ { language: 'hcl', offset: 4, type: 'operator.hcl' },
+ { language: 'hcl', offset: 5, type: '' },
+ { language: 'hcl', offset: 6, type: 'number.float.hcl' },
+ ],
+ ],
+ ],
+ [
+ 'foo = true',
+ [
+ [
+ { language: 'hcl', offset: 0, type: 'variable.hcl' },
+ { language: 'hcl', offset: 3, type: '' },
+ { language: 'hcl', offset: 4, type: 'operator.hcl' },
+ { language: 'hcl', offset: 5, type: '' },
+ { language: 'hcl', offset: 6, type: 'keyword.true.hcl' },
+ ],
+ ],
+ ],
+ [
+ 'foo = false',
+ [
+ [
+ { language: 'hcl', offset: 0, type: 'variable.hcl' },
+ { language: 'hcl', offset: 3, type: '' },
+ { language: 'hcl', offset: 4, type: 'operator.hcl' },
+ { language: 'hcl', offset: 5, type: '' },
+ { language: 'hcl', offset: 6, type: 'keyword.false.hcl' },
+ ],
+ ],
+ ],
+ [
+ // eslint-disable-next-line no-template-curly-in-string
+ 'bar = "${file("bing/bong.txt")}"',
+ [
+ [
+ { language: 'hcl', offset: 0, type: 'variable.hcl' },
+ { language: 'hcl', offset: 3, type: '' },
+ { language: 'hcl', offset: 4, type: 'operator.hcl' },
+ { language: 'hcl', offset: 5, type: '' },
+ { language: 'hcl', offset: 6, type: 'string.hcl' },
+ { language: 'hcl', offset: 7, type: 'delimiter.hcl' },
+ { language: 'hcl', offset: 9, type: 'type.hcl' },
+ { language: 'hcl', offset: 13, type: 'delimiter.parenthesis.hcl' },
+ { language: 'hcl', offset: 14, type: 'string.hcl' },
+ { language: 'hcl', offset: 29, type: 'delimiter.parenthesis.hcl' },
+ { language: 'hcl', offset: 30, type: 'delimiter.hcl' },
+ { language: 'hcl', offset: 31, type: 'string.hcl' },
+ ],
+ ],
+ ],
+ [
+ 'a = 1e-10',
+ [
+ [
+ { language: 'hcl', offset: 0, type: 'variable.hcl' },
+ { language: 'hcl', offset: 1, type: '' },
+ { language: 'hcl', offset: 2, type: 'operator.hcl' },
+ { language: 'hcl', offset: 3, type: '' },
+ { language: 'hcl', offset: 4, type: 'number.float.hcl' },
+ ],
+ ],
+ ],
+ [
+ 'b = 1e+10',
+ [
+ [
+ { language: 'hcl', offset: 0, type: 'variable.hcl' },
+ { language: 'hcl', offset: 1, type: '' },
+ { language: 'hcl', offset: 2, type: 'operator.hcl' },
+ { language: 'hcl', offset: 3, type: '' },
+ { language: 'hcl', offset: 4, type: 'number.float.hcl' },
+ ],
+ ],
+ ],
+ [
+ 'c = 1e10',
+ [
+ [
+ { language: 'hcl', offset: 0, type: 'variable.hcl' },
+ { language: 'hcl', offset: 1, type: '' },
+ { language: 'hcl', offset: 2, type: 'operator.hcl' },
+ { language: 'hcl', offset: 3, type: '' },
+ { language: 'hcl', offset: 4, type: 'number.float.hcl' },
+ ],
+ ],
+ ],
+ [
+ 'd = 1.2e-10',
+ [
+ [
+ { language: 'hcl', offset: 0, type: 'variable.hcl' },
+ { language: 'hcl', offset: 1, type: '' },
+ { language: 'hcl', offset: 2, type: 'operator.hcl' },
+ { language: 'hcl', offset: 3, type: '' },
+ { language: 'hcl', offset: 4, type: 'number.float.hcl' },
+ ],
+ ],
+ ],
+ [
+ 'e = 1.2e+10',
+ [
+ [
+ { language: 'hcl', offset: 0, type: 'variable.hcl' },
+ { language: 'hcl', offset: 1, type: '' },
+ { language: 'hcl', offset: 2, type: 'operator.hcl' },
+ { language: 'hcl', offset: 3, type: '' },
+ { language: 'hcl', offset: 4, type: 'number.float.hcl' },
+ ],
+ ],
+ ],
+ ])('%s', (string, tokens) => {
+ expect(editor.tokenize(string, 'hcl')).toEqual(tokens);
+ });
+});
diff --git a/spec/frontend/ide/stores/actions/file_spec.js b/spec/frontend/ide/stores/actions/file_spec.js
index 974c0715c06..8f7fcc25cf0 100644
--- a/spec/frontend/ide/stores/actions/file_spec.js
+++ b/spec/frontend/ide/stores/actions/file_spec.js
@@ -291,6 +291,20 @@ describe('IDE store file actions', () => {
expect(store.state.openFiles[0].name).toBe(localFile.name);
});
});
+
+ it('does not toggle loading if toggleLoading=false', () => {
+ expect(localFile.loading).toBe(false);
+
+ return store
+ .dispatch('getFileData', {
+ path: localFile.path,
+ makeFileActive: false,
+ toggleLoading: false,
+ })
+ .then(() => {
+ expect(localFile.loading).toBe(true);
+ });
+ });
});
describe('Re-named success', () => {
diff --git a/spec/frontend/ide/stores/getters_spec.js b/spec/frontend/ide/stores/getters_spec.js
index e24f08fa802..5ae87f5f9cd 100644
--- a/spec/frontend/ide/stores/getters_spec.js
+++ b/spec/frontend/ide/stores/getters_spec.js
@@ -449,16 +449,16 @@ describe('IDE store getters', () => {
describe('getAvailableFileName', () => {
it.each`
path | newPath
- ${'foo'} | ${'foo_1'}
+ ${'foo'} | ${'foo-1'}
${'foo__93.png'} | ${'foo__94.png'}
- ${'foo/bar.png'} | ${'foo/bar_1.png'}
+ ${'foo/bar.png'} | ${'foo/bar-1.png'}
${'foo/bar--34.png'} | ${'foo/bar--35.png'}
${'foo/bar 2.png'} | ${'foo/bar 3.png'}
${'foo/bar-621.png'} | ${'foo/bar-622.png'}
- ${'jquery.min.js'} | ${'jquery_1.min.js'}
+ ${'jquery.min.js'} | ${'jquery-1.min.js'}
${'my_spec_22.js.snap'} | ${'my_spec_23.js.snap'}
- ${'subtitles5.mp4.srt'} | ${'subtitles_6.mp4.srt'}
- ${'sample_file.mp3'} | ${'sample_file_1.mp3'}
+ ${'subtitles5.mp4.srt'} | ${'subtitles-6.mp4.srt'}
+ ${'sample-file.mp3'} | ${'sample-file-1.mp3'}
${'Screenshot 2020-05-26 at 10.53.08 PM.png'} | ${'Screenshot 2020-05-26 at 11.53.08 PM.png'}
`('suffixes the path with a number if the path already exists', ({ path, newPath }) => {
localState.entries[path] = file();
diff --git a/spec/frontend/ide/stores/modules/commit/actions_spec.js b/spec/frontend/ide/stores/modules/commit/actions_spec.js
index babc50e54f1..cfe2bddf76c 100644
--- a/spec/frontend/ide/stores/modules/commit/actions_spec.js
+++ b/spec/frontend/ide/stores/modules/commit/actions_spec.js
@@ -76,59 +76,38 @@ describe('IDE commit module actions', () => {
.then(done)
.catch(done.fail);
});
+ });
- it('sets shouldCreateMR to true if "Create new MR" option is visible', done => {
- Object.assign(store.state, {
- shouldHideNewMrOption: false,
- });
+ describe('updateBranchName', () => {
+ let originalGon;
- testAction(
- actions.updateCommitAction,
- {},
- store.state,
- [
- {
- type: mutationTypes.UPDATE_COMMIT_ACTION,
- payload: { commitAction: expect.anything() },
- },
- { type: mutationTypes.TOGGLE_SHOULD_CREATE_MR, payload: true },
- ],
- [],
- done,
- );
+ beforeEach(() => {
+ originalGon = window.gon;
+ window.gon = { current_username: 'johndoe' };
+
+ store.state.currentBranchId = 'master';
});
- it('sets shouldCreateMR to false if "Create new MR" option is hidden', done => {
- Object.assign(store.state, {
- shouldHideNewMrOption: true,
- });
+ afterEach(() => {
+ window.gon = originalGon;
+ });
- testAction(
- actions.updateCommitAction,
- {},
- store.state,
- [
- {
- type: mutationTypes.UPDATE_COMMIT_ACTION,
- payload: { commitAction: expect.anything() },
- },
- { type: mutationTypes.TOGGLE_SHOULD_CREATE_MR, payload: false },
- ],
- [],
- done,
- );
+ it('updates store with new branch name', async () => {
+ await store.dispatch('commit/updateBranchName', 'branch-name');
+
+ expect(store.state.commit.newBranchName).toBe('branch-name');
});
});
- describe('updateBranchName', () => {
- it('updates store with new branch name', done => {
- store
- .dispatch('commit/updateBranchName', 'branch-name')
- .then(() => {
- expect(store.state.commit.newBranchName).toBe('branch-name');
- })
- .then(done)
- .catch(done.fail);
+ describe('addSuffixToBranchName', () => {
+ it('adds suffix to branchName', async () => {
+ jest.spyOn(Math, 'random').mockReturnValue(0.391352525);
+
+ store.state.commit.newBranchName = 'branch-name';
+
+ await store.dispatch('commit/addSuffixToBranchName');
+
+ expect(store.state.commit.newBranchName).toBe('branch-name-39135');
});
});
@@ -318,13 +297,16 @@ describe('IDE commit module actions', () => {
currentBranchId: 'master',
projects: {
abcproject: {
+ default_branch: 'master',
web_url: 'webUrl',
branches: {
master: {
+ name: 'master',
workingReference: '1',
commit: {
id: TEST_COMMIT_SHA,
},
+ can_push: true,
},
},
userPermissions: {
@@ -499,6 +481,16 @@ describe('IDE commit module actions', () => {
.catch(done.fail);
});
+ it('does not redirect to merge request page if shouldCreateMR is checked, but branch is the default branch', async () => {
+ jest.spyOn(eventHub, '$on').mockImplementation();
+
+ store.state.commit.commitAction = consts.COMMIT_TO_CURRENT_BRANCH;
+ store.state.commit.shouldCreateMR = true;
+
+ await store.dispatch('commit/commitChanges');
+ expect(visitUrl).not.toHaveBeenCalled();
+ });
+
it('resets changed files before redirecting', () => {
jest.spyOn(eventHub, '$on').mockImplementation();
diff --git a/spec/frontend/ide/stores/mutations/file_spec.js b/spec/frontend/ide/stores/mutations/file_spec.js
index b53e40be980..d303de6e9ef 100644
--- a/spec/frontend/ide/stores/mutations/file_spec.js
+++ b/spec/frontend/ide/stores/mutations/file_spec.js
@@ -39,20 +39,34 @@ describe('IDE store file mutations', () => {
});
describe('TOGGLE_FILE_OPEN', () => {
- beforeEach(() => {
+ it('adds into opened files', () => {
mutations.TOGGLE_FILE_OPEN(localState, localFile.path);
- });
- it('adds into opened files', () => {
expect(localFile.opened).toBeTruthy();
expect(localState.openFiles.length).toBe(1);
});
- it('removes from opened files', () => {
+ describe('if already open', () => {
+ it('removes from opened files', () => {
+ mutations.TOGGLE_FILE_OPEN(localState, localFile.path);
+ mutations.TOGGLE_FILE_OPEN(localState, localFile.path);
+
+ expect(localFile.opened).toBeFalsy();
+ expect(localState.openFiles.length).toBe(0);
+ });
+ });
+
+ it.each`
+ entry | loading
+ ${{ opened: false }} | ${true}
+ ${{ opened: false, tempFile: true }} | ${false}
+ ${{ opened: true }} | ${false}
+ `('for state: $entry, sets loading=$loading', ({ entry, loading }) => {
+ Object.assign(localFile, entry);
+
mutations.TOGGLE_FILE_OPEN(localState, localFile.path);
- expect(localFile.opened).toBeFalsy();
- expect(localState.openFiles.length).toBe(0);
+ expect(localFile.loading).toBe(loading);
});
});
diff --git a/spec/frontend/ide/stores/utils_spec.js b/spec/frontend/ide/stores/utils_spec.js
index d1eb4304c79..b185013050e 100644
--- a/spec/frontend/ide/stores/utils_spec.js
+++ b/spec/frontend/ide/stores/utils_spec.js
@@ -46,7 +46,7 @@ describe('Multi-file store utils', () => {
path: 'added',
tempFile: true,
content: 'new file content',
- rawPath: 'data:image/png;base64,abc',
+ rawPath: 'blob:https://gitlab.com/048c7ac1-98de-4a37-ab1b-0206d0ea7e1b',
lastCommitSha: '123456789',
},
{ ...file('deletedFile'), path: 'deletedFile', deleted: true },
@@ -77,7 +77,8 @@ describe('Multi-file store utils', () => {
{
action: commitActionTypes.create,
file_path: 'added',
- content: 'new file content',
+ // atob("new file content")
+ content: 'bmV3IGZpbGUgY29udGVudA==',
encoding: 'base64',
last_commit_id: '123456789',
previous_path: undefined,
@@ -117,7 +118,7 @@ describe('Multi-file store utils', () => {
path: 'added',
tempFile: true,
content: 'new file content',
- rawPath: 'data:image/png;base64,abc',
+ rawPath: 'blob:https://gitlab.com/048c7ac1-98de-4a37-ab1b-0206d0ea7e1b',
lastCommitSha: '123456789',
},
],
@@ -148,7 +149,8 @@ describe('Multi-file store utils', () => {
{
action: commitActionTypes.create,
file_path: 'added',
- content: 'new file content',
+ // atob("new file content")
+ content: 'bmV3IGZpbGUgY29udGVudA==',
encoding: 'base64',
last_commit_id: '123456789',
previous_path: undefined,
diff --git a/spec/frontend/ide/utils_spec.js b/spec/frontend/ide/utils_spec.js
index 97dc8217ecc..6cd2128d356 100644
--- a/spec/frontend/ide/utils_spec.js
+++ b/spec/frontend/ide/utils_spec.js
@@ -9,6 +9,7 @@ import {
getPathParents,
getPathParent,
readFileAsDataURL,
+ addNumericSuffix,
} from '~/ide/utils';
describe('WebIDE utils', () => {
@@ -291,4 +292,43 @@ describe('WebIDE utils', () => {
});
});
});
+
+ /*
+ * hello-2425 -> hello-2425
+ * hello.md -> hello-1.md
+ * hello_2.md -> hello_3.md
+ * hello_ -> hello_1
+ * master-patch-22432 -> master-patch-22433
+ * patch_332 -> patch_333
+ */
+
+ describe('addNumericSuffix', () => {
+ it.each`
+ input | output
+ ${'hello'} | ${'hello-1'}
+ ${'hello2'} | ${'hello-3'}
+ ${'hello.md'} | ${'hello-1.md'}
+ ${'hello_2.md'} | ${'hello_3.md'}
+ ${'hello_'} | ${'hello_1'}
+ ${'master-patch-22432'} | ${'master-patch-22433'}
+ ${'patch_332'} | ${'patch_333'}
+ `('adds a numeric suffix to a given filename/branch name: $input', ({ input, output }) => {
+ expect(addNumericSuffix(input)).toBe(output);
+ });
+
+ it.each`
+ input | output
+ ${'hello'} | ${'hello-39135'}
+ ${'hello2'} | ${'hello-39135'}
+ ${'hello.md'} | ${'hello-39135.md'}
+ ${'hello_2.md'} | ${'hello_39135.md'}
+ ${'hello_'} | ${'hello_39135'}
+ ${'master-patch-22432'} | ${'master-patch-39135'}
+ ${'patch_332'} | ${'patch_39135'}
+ `('adds a random suffix if randomize=true is passed for name: $input', ({ input, output }) => {
+ jest.spyOn(Math, 'random').mockReturnValue(0.391352525);
+
+ expect(addNumericSuffix(input, true)).toBe(output);
+ });
+ });
});
diff --git a/spec/frontend/incidents/components/incidents_list_spec.js b/spec/frontend/incidents/components/incidents_list_spec.js
index 307806e0a8a..709f66bb352 100644
--- a/spec/frontend/incidents/components/incidents_list_spec.js
+++ b/spec/frontend/incidents/components/incidents_list_spec.js
@@ -1,28 +1,28 @@
import { mount } from '@vue/test-utils';
-import {
- GlAlert,
- GlLoadingIcon,
- GlTable,
- GlAvatar,
- GlPagination,
- GlSearchBoxByType,
- GlTab,
- GlTabs,
- GlBadge,
- GlEmptyState,
-} from '@gitlab/ui';
+import { GlAlert, GlLoadingIcon, GlTable, GlAvatar, GlEmptyState } from '@gitlab/ui';
+import Tracking from '~/tracking';
import { visitUrl, joinPaths, mergeUrlParams } from '~/lib/utils/url_utility';
import IncidentsList from '~/incidents/components/incidents_list.vue';
import SeverityToken from '~/sidebar/components/severity/severity.vue';
import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
-import { I18N, INCIDENT_STATUS_TABS } from '~/incidents/constants';
+import {
+ I18N,
+ TH_CREATED_AT_TEST_ID,
+ TH_SEVERITY_TEST_ID,
+ TH_PUBLISHED_TEST_ID,
+ trackIncidentCreateNewOptions,
+ trackIncidentListViewsOptions,
+} from '~/incidents/constants';
import mockIncidents from '../mocks/incidents.json';
jest.mock('~/lib/utils/url_utility', () => ({
visitUrl: jest.fn().mockName('visitUrlMock'),
- joinPaths: jest.fn().mockName('joinPaths'),
- mergeUrlParams: jest.fn().mockName('mergeUrlParams'),
+ joinPaths: jest.fn(),
+ mergeUrlParams: jest.fn(),
+ setUrlParams: jest.fn(),
+ updateHistory: jest.fn(),
}));
+jest.mock('~/tracking');
describe('Incidents List', () => {
let wrapper;
@@ -41,23 +41,22 @@ describe('Incidents List', () => {
const findAlert = () => wrapper.find(GlAlert);
const findLoader = () => wrapper.find(GlLoadingIcon);
const findTimeAgo = () => wrapper.findAll(TimeAgoTooltip);
- const findDateColumnHeader = () =>
- wrapper.find('[data-testid="incident-management-created-at-sort"]');
- const findSearch = () => wrapper.find(GlSearchBoxByType);
- const findAssingees = () => wrapper.findAll('[data-testid="incident-assignees"]');
+ const findAssignees = () => wrapper.findAll('[data-testid="incident-assignees"]');
+ const findIncidentSlaHeader = () => wrapper.find('[data-testid="incident-management-sla"]');
const findCreateIncidentBtn = () => wrapper.find('[data-testid="createIncidentBtn"]');
const findClosedIcon = () => wrapper.findAll("[data-testid='incident-closed']");
- const findPagination = () => wrapper.find(GlPagination);
- const findStatusFilterTabs = () => wrapper.findAll(GlTab);
- const findStatusFilterBadge = () => wrapper.findAll(GlBadge);
- const findStatusTabs = () => wrapper.find(GlTabs);
const findEmptyState = () => wrapper.find(GlEmptyState);
const findSeverity = () => wrapper.findAll(SeverityToken);
+ const findIncidentSla = () => wrapper.findAll("[data-testid='incident-sla']");
- function mountComponent({ data = { incidents: [], incidentsCount: {} }, loading = false }) {
+ function mountComponent({ data = {}, loading = false, provide = {} } = {}) {
wrapper = mount(IncidentsList, {
data() {
- return data;
+ return {
+ incidents: [],
+ incidentsCount: {},
+ ...data,
+ };
},
mocks: {
$apollo: {
@@ -73,14 +72,20 @@ describe('Incidents List', () => {
newIssuePath,
incidentTemplateName,
incidentType,
- issuePath: '/project/isssues',
+ issuePath: '/project/issues',
publishedAvailable: true,
emptyListSvgPath,
+ textQuery: '',
+ authorUsernameQuery: '',
+ assigneeUsernameQuery: '',
+ slaFeatureAvailable: true,
+ ...provide,
},
stubs: {
GlButton: true,
GlAvatar: true,
GlEmptyState: true,
+ ServiceLevelAgreementCell: true,
},
});
}
@@ -153,14 +158,14 @@ describe('Incidents List', () => {
describe('Assignees', () => {
it('shows Unassigned when there are no assignees', () => {
expect(
- findAssingees()
+ findAssignees()
.at(0)
.text(),
).toBe(I18N.unassigned);
});
it('renders an avatar component when there is an assignee', () => {
- const avatar = findAssingees()
+ const avatar = findAssignees()
.at(1)
.find(GlAvatar);
const { src, label } = avatar.attributes();
@@ -171,13 +176,6 @@ describe('Incidents List', () => {
expect(src).toBe(avatarUrl);
});
- it('contains a link to the issue details', () => {
- findTableRows()
- .at(0)
- .trigger('click');
- expect(visitUrl).toHaveBeenCalledWith(joinPaths(`/project/isssues/`, mockIncidents[0].iid));
- });
-
it('renders a closed icon for closed incidents', () => {
expect(findClosedIcon().length).toBe(
mockIncidents.filter(({ state }) => state === 'closed').length,
@@ -188,6 +186,44 @@ describe('Incidents List', () => {
it('renders severity per row', () => {
expect(findSeverity().length).toBe(mockIncidents.length);
});
+
+ it('contains a link to the incident details page', async () => {
+ findTableRows()
+ .at(0)
+ .trigger('click');
+ expect(visitUrl).toHaveBeenCalledWith(
+ joinPaths(`/project/issues/incident`, mockIncidents[0].iid),
+ );
+ });
+
+ describe('Incident SLA field', () => {
+ it('displays the column when the feature is available', () => {
+ mountComponent({
+ data: { incidents: { list: mockIncidents } },
+ provide: { slaFeatureAvailable: true },
+ });
+
+ expect(findIncidentSlaHeader().text()).toContain('Time to SLA');
+ });
+
+ it('does not display the column when the feature is not available', () => {
+ mountComponent({
+ data: { incidents: { list: mockIncidents } },
+ provide: { slaFeatureAvailable: false },
+ });
+
+ expect(findIncidentSlaHeader().exists()).toBe(false);
+ });
+
+ it('renders an SLA for each incident', () => {
+ mountComponent({
+ data: { incidents: { list: mockIncidents } },
+ provide: { slaFeatureAvailable: true },
+ });
+
+ expect(findIncidentSla().length).toBe(mockIncidents.length);
+ });
+ });
});
describe('Create Incident', () => {
@@ -198,7 +234,7 @@ describe('Incidents List', () => {
});
});
- it('shows the button linking to new incidents page with prefilled incident template when clicked', () => {
+ it('shows the button linking to new incidents page with pre-filled incident template when clicked', () => {
expect(findCreateIncidentBtn().exists()).toBe(true);
findCreateIncidentBtn().trigger('click');
expect(mergeUrlParams).toHaveBeenCalledWith(
@@ -207,11 +243,10 @@ describe('Incidents List', () => {
);
});
- it('sets button loading on click', () => {
+ it('sets button loading on click', async () => {
findCreateIncidentBtn().vm.$emit('click');
- return wrapper.vm.$nextTick().then(() => {
- expect(findCreateIncidentBtn().attributes('loading')).toBe('true');
- });
+ await wrapper.vm.$nextTick();
+ expect(findCreateIncidentBtn().attributes('loading')).toBe('true');
});
it("doesn't show the button when list is empty", () => {
@@ -221,175 +256,62 @@ describe('Incidents List', () => {
});
expect(findCreateIncidentBtn().exists()).toBe(false);
});
+
+ it('should track create new incident button', async () => {
+ findCreateIncidentBtn().vm.$emit('click');
+ await wrapper.vm.$nextTick();
+ expect(Tracking.event).toHaveBeenCalled();
+ });
});
- describe('Pagination', () => {
+ describe('sorting the incident list by column', () => {
beforeEach(() => {
mountComponent({
- data: {
- incidents: {
- list: mockIncidents,
- pageInfo: { hasNextPage: true, hasPreviousPage: true },
- },
- incidentsCount,
- errored: false,
- },
+ data: { incidents: { list: mockIncidents }, incidentsCount },
loading: false,
});
});
- it('should render pagination', () => {
- expect(wrapper.find(GlPagination).exists()).toBe(true);
- });
-
- describe('prevPage', () => {
- it('returns prevPage button', () => {
- findPagination().vm.$emit('input', 3);
-
- return wrapper.vm.$nextTick(() => {
- expect(
- findPagination()
- .findAll('.page-item')
- .at(0)
- .text(),
- ).toBe('Prev');
- });
- });
-
- it('returns prevPage number', () => {
- findPagination().vm.$emit('input', 3);
-
- return wrapper.vm.$nextTick(() => {
- expect(wrapper.vm.prevPage).toBe(2);
- });
- });
-
- it('returns 0 when it is the first page', () => {
- findPagination().vm.$emit('input', 1);
-
- return wrapper.vm.$nextTick(() => {
- expect(wrapper.vm.prevPage).toBe(0);
- });
- });
- });
-
- describe('nextPage', () => {
- it('returns nextPage button', () => {
- findPagination().vm.$emit('input', 3);
-
- return wrapper.vm.$nextTick(() => {
- expect(
- findPagination()
- .findAll('.page-item')
- .at(1)
- .text(),
- ).toBe('Next');
- });
- });
-
- it('returns nextPage number', () => {
- mountComponent({
- data: {
- incidents: {
- list: [...mockIncidents, ...mockIncidents, ...mockIncidents],
- pageInfo: { hasNextPage: true, hasPreviousPage: true },
- },
- incidentsCount,
- errored: false,
- },
- loading: false,
- });
- findPagination().vm.$emit('input', 1);
-
- return wrapper.vm.$nextTick(() => {
- expect(wrapper.vm.nextPage).toBe(2);
- });
- });
-
- it('returns `null` when currentPage is already last page', () => {
- findStatusTabs().vm.$emit('input', 1);
- findPagination().vm.$emit('input', 1);
- return wrapper.vm.$nextTick(() => {
- expect(wrapper.vm.nextPage).toBeNull();
- });
- });
- });
-
- describe('Search', () => {
- beforeEach(() => {
- mountComponent({
- data: {
- incidents: {
- list: mockIncidents,
- pageInfo: { hasNextPage: true, hasPreviousPage: true },
- },
- incidentsCount,
- errored: false,
- },
- loading: false,
- });
- });
-
- it('renders the search component for incidents', () => {
- expect(findSearch().exists()).toBe(true);
- });
-
- it('sets the `searchTerm` graphql variable', () => {
- const SEARCH_TERM = 'Simple Incident';
-
- findSearch().vm.$emit('input', SEARCH_TERM);
-
- expect(wrapper.vm.$data.searchTerm).toBe(SEARCH_TERM);
- });
- });
-
- describe('Status Filter Tabs', () => {
- beforeEach(() => {
- mountComponent({
- data: { incidents: { list: mockIncidents }, incidentsCount },
- loading: false,
- stubs: {
- GlTab: true,
- },
- });
- });
-
- it('should display filter tabs', () => {
- const tabs = findStatusFilterTabs().wrappers;
-
- tabs.forEach((tab, i) => {
- expect(tab.attributes('data-testid')).toContain(INCIDENT_STATUS_TABS[i].status);
- });
- });
-
- it('should display filter tabs with alerts count badge for each status', () => {
- const tabs = findStatusFilterTabs().wrappers;
- const badges = findStatusFilterBadge();
+ const descSort = 'descending';
+ const ascSort = 'ascending';
+ const noneSort = 'none';
- tabs.forEach((tab, i) => {
- const status = INCIDENT_STATUS_TABS[i].status.toLowerCase();
- expect(tab.attributes('data-testid')).toContain(INCIDENT_STATUS_TABS[i].status);
- expect(badges.at(i).text()).toContain(incidentsCount[status]);
- });
- });
+ it.each`
+ selector | initialSort | firstSort | nextSort
+ ${TH_CREATED_AT_TEST_ID} | ${descSort} | ${ascSort} | ${descSort}
+ ${TH_SEVERITY_TEST_ID} | ${noneSort} | ${descSort} | ${ascSort}
+ ${TH_PUBLISHED_TEST_ID} | ${noneSort} | ${descSort} | ${ascSort}
+ `('updates sort with new direction', async ({ selector, initialSort, firstSort, nextSort }) => {
+ const [[attr, value]] = Object.entries(selector);
+ const columnHeader = () => wrapper.find(`[${attr}="${value}"]`);
+ expect(columnHeader().attributes('aria-sort')).toBe(initialSort);
+ columnHeader().trigger('click');
+ await wrapper.vm.$nextTick();
+ expect(columnHeader().attributes('aria-sort')).toBe(firstSort);
+ columnHeader().trigger('click');
+ await wrapper.vm.$nextTick();
+ expect(columnHeader().attributes('aria-sort')).toBe(nextSort);
});
});
- describe('sorting the incident list by column', () => {
+ describe('Snowplow tracking', () => {
beforeEach(() => {
mountComponent({
- data: { incidents: { list: mockIncidents }, incidentsCount },
+ data: { incidents: { list: mockIncidents }, incidentsCount: {} },
loading: false,
});
});
- it('updates sort with new direction and column key', () => {
- expect(findDateColumnHeader().attributes('aria-sort')).toBe('descending');
+ it('should track incident list views', () => {
+ const { category, action } = trackIncidentListViewsOptions;
+ expect(Tracking.event).toHaveBeenCalledWith(category, action);
+ });
- findDateColumnHeader().trigger('click');
- return wrapper.vm.$nextTick(() => {
- expect(findDateColumnHeader().attributes('aria-sort')).toBe('ascending');
- });
+ it('should track incident creation events', async () => {
+ findCreateIncidentBtn().vm.$emit('click');
+ await wrapper.vm.$nextTick();
+ const { category, action } = trackIncidentCreateNewOptions;
+ expect(Tracking.event).toHaveBeenCalledWith(category, action);
});
});
});
diff --git a/spec/frontend/incidents/mocks/incidents.json b/spec/frontend/incidents/mocks/incidents.json
index 42b3d6d3eb6..07c87a5d43d 100644
--- a/spec/frontend/incidents/mocks/incidents.json
+++ b/spec/frontend/incidents/mocks/incidents.json
@@ -5,7 +5,8 @@
"createdAt": "2020-06-03T15:46:08Z",
"assignees": {},
"state": "opened",
- "severity": "CRITICAL"
+ "severity": "CRITICAL",
+ "slaDueAt": "2020-06-04T12:46:08Z"
},
{
"iid": "14",
@@ -22,7 +23,8 @@
]
},
"state": "opened",
- "severity": "HIGH"
+ "severity": "HIGH",
+ "slaDueAt": null
},
{
"iid": "13",
diff --git a/spec/frontend/incidents_settings/components/__snapshots__/alerts_form_spec.js.snap b/spec/frontend/incidents_settings/components/__snapshots__/alerts_form_spec.js.snap
index cab2165b5db..e4620590e62 100644
--- a/spec/frontend/incidents_settings/components/__snapshots__/alerts_form_spec.js.snap
+++ b/spec/frontend/incidents_settings/components/__snapshots__/alerts_form_spec.js.snap
@@ -93,23 +93,20 @@ exports[`Alert integration settings form default state should match the default
</gl-form-checkbox-stub>
</gl-form-group-stub>
- <div
- class="gl-display-flex gl-justify-content-end"
+ <gl-button-stub
+ buttontextclasses=""
+ category="primary"
+ class="js-no-auto-disable"
+ data-qa-selector="save_changes_button"
+ icon=""
+ size="medium"
+ type="submit"
+ variant="success"
>
- <gl-button-stub
- category="primary"
- class="js-no-auto-disable"
- data-qa-selector="save_changes_button"
- icon=""
- size="medium"
- type="submit"
- variant="success"
- >
-
- Save changes
- </gl-button-stub>
- </div>
+ Save changes
+
+ </gl-button-stub>
</form>
</div>
`;
diff --git a/spec/frontend/incidents_settings/components/__snapshots__/incidents_settings_tabs_spec.js.snap b/spec/frontend/incidents_settings/components/__snapshots__/incidents_settings_tabs_spec.js.snap
index 3ad4c13382d..072e611b9a4 100644
--- a/spec/frontend/incidents_settings/components/__snapshots__/incidents_settings_tabs_spec.js.snap
+++ b/spec/frontend/incidents_settings/components/__snapshots__/incidents_settings_tabs_spec.js.snap
@@ -18,6 +18,7 @@ exports[`IncidentsSettingTabs should render the component 1`] = `
</h4>
<gl-button-stub
+ buttontextclasses=""
category="primary"
class="js-settings-toggle"
icon=""
@@ -57,6 +58,8 @@ exports[`IncidentsSettingTabs should render the component 1`] = `
/>
</gl-tab-stub>
<!---->
+
+ <!---->
</gl-tabs-stub>
</div>
</section>
diff --git a/spec/frontend/incidents_settings/components/__snapshots__/pagerduty_form_spec.js.snap b/spec/frontend/incidents_settings/components/__snapshots__/pagerduty_form_spec.js.snap
index 78bb238fcb6..273356151fc 100644
--- a/spec/frontend/incidents_settings/components/__snapshots__/pagerduty_form_spec.js.snap
+++ b/spec/frontend/incidents_settings/components/__snapshots__/pagerduty_form_spec.js.snap
@@ -23,7 +23,6 @@ exports[`Alert integration settings form should match the default snapshot 1`] =
<gl-form-group-stub
class="col-8 col-md-9 gl-p-0"
label="Webhook URL"
- label-class="label-bold"
label-for="url"
>
<gl-form-input-group-stub
@@ -42,24 +41,21 @@ exports[`Alert integration settings form should match the default snapshot 1`] =
/>
</div>
- <div
- class="gl-display-flex gl-justify-content-end"
+ <gl-button-stub
+ buttontextclasses=""
+ category="primary"
+ class="gl-mt-3"
+ data-testid="webhook-reset-btn"
+ icon=""
+ role="button"
+ size="medium"
+ tabindex="0"
+ variant="default"
>
- <gl-button-stub
- category="primary"
- class="gl-mt-3"
- data-testid="webhook-reset-btn"
- icon=""
- role="button"
- size="medium"
- tabindex="0"
- variant="default"
- >
-
- Reset webhook URL
- </gl-button-stub>
- </div>
+ Reset webhook URL
+
+ </gl-button-stub>
<gl-modal-stub
modalclass=""
@@ -76,22 +72,19 @@ exports[`Alert integration settings form should match the default snapshot 1`] =
</gl-modal-stub>
</gl-form-group-stub>
- <div
- class="gl-display-flex gl-justify-content-end"
+ <gl-button-stub
+ buttontextclasses=""
+ category="primary"
+ class="js-no-auto-disable"
+ icon=""
+ size="medium"
+ type="submit"
+ variant="success"
>
- <gl-button-stub
- category="primary"
- class="js-no-auto-disable"
- icon=""
- size="medium"
- type="submit"
- variant="success"
- >
-
- Save changes
- </gl-button-stub>
- </div>
+ Save changes
+
+ </gl-button-stub>
</form>
</div>
`;
diff --git a/spec/frontend/incidents_settings/components/incidents_settings_tabs_spec.js b/spec/frontend/incidents_settings/components/incidents_settings_tabs_spec.js
index c56b9ed2a69..11b9eda2585 100644
--- a/spec/frontend/incidents_settings/components/incidents_settings_tabs_spec.js
+++ b/spec/frontend/incidents_settings/components/incidents_settings_tabs_spec.js
@@ -6,7 +6,12 @@ describe('IncidentsSettingTabs', () => {
let wrapper;
beforeEach(() => {
- wrapper = shallowMount(IncidentsSettingTabs);
+ wrapper = shallowMount(IncidentsSettingTabs, {
+ provide: {
+ service: {},
+ serviceLevelAgreementSettings: {},
+ },
+ });
});
afterEach(() => {
diff --git a/spec/frontend/integrations/edit/components/confirmation_modal_spec.js b/spec/frontend/integrations/edit/components/confirmation_modal_spec.js
new file mode 100644
index 00000000000..02f311f579f
--- /dev/null
+++ b/spec/frontend/integrations/edit/components/confirmation_modal_spec.js
@@ -0,0 +1,51 @@
+import { shallowMount } from '@vue/test-utils';
+import { GlModal } from '@gitlab/ui';
+import { createStore } from '~/integrations/edit/store';
+
+import ConfirmationModal from '~/integrations/edit/components/confirmation_modal.vue';
+
+describe('ConfirmationModal', () => {
+ let wrapper;
+
+ const createComponent = () => {
+ wrapper = shallowMount(ConfirmationModal, {
+ store: createStore(),
+ });
+ };
+
+ afterEach(() => {
+ if (wrapper) {
+ wrapper.destroy();
+ wrapper = null;
+ }
+ });
+
+ const findGlModal = () => wrapper.find(GlModal);
+
+ describe('template', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('renders GlModal with correct copy', () => {
+ expect(findGlModal().exists()).toBe(true);
+ expect(findGlModal().attributes('title')).toBe('Save settings?');
+ expect(findGlModal().text()).toContain(
+ 'Saving will update the default settings for all projects that are not using custom settings.',
+ );
+ expect(findGlModal().text()).toContain(
+ 'Projects using custom settings will not be impacted unless the project owner chooses to use instance-level defaults.',
+ );
+ });
+
+ it('emits `submit` event when `primary` event is emitted on GlModal', async () => {
+ expect(wrapper.emitted().submit).toBeUndefined();
+
+ findGlModal().vm.$emit('primary');
+
+ await wrapper.vm.$nextTick();
+
+ expect(wrapper.emitted().submit).toHaveLength(1);
+ });
+ });
+});
diff --git a/spec/frontend/integrations/edit/components/integration_form_spec.js b/spec/frontend/integrations/edit/components/integration_form_spec.js
index eeb5d21d62c..efcc727277a 100644
--- a/spec/frontend/integrations/edit/components/integration_form_spec.js
+++ b/spec/frontend/integrations/edit/components/integration_form_spec.js
@@ -4,6 +4,7 @@ import { createStore } from '~/integrations/edit/store';
import IntegrationForm from '~/integrations/edit/components/integration_form.vue';
import OverrideDropdown from '~/integrations/edit/components/override_dropdown.vue';
import ActiveCheckbox from '~/integrations/edit/components/active_checkbox.vue';
+import ConfirmationModal from '~/integrations/edit/components/confirmation_modal.vue';
import JiraTriggerFields from '~/integrations/edit/components/jira_trigger_fields.vue';
import JiraIssuesFields from '~/integrations/edit/components/jira_issues_fields.vue';
import TriggerFields from '~/integrations/edit/components/trigger_fields.vue';
@@ -22,6 +23,7 @@ describe('IntegrationForm', () => {
stubs: {
OverrideDropdown,
ActiveCheckbox,
+ ConfirmationModal,
JiraTriggerFields,
TriggerFields,
},
@@ -40,6 +42,7 @@ describe('IntegrationForm', () => {
const findOverrideDropdown = () => wrapper.find(OverrideDropdown);
const findActiveCheckbox = () => wrapper.find(ActiveCheckbox);
+ const findConfirmationModal = () => wrapper.find(ConfirmationModal);
const findJiraTriggerFields = () => wrapper.find(JiraTriggerFields);
const findJiraIssuesFields = () => wrapper.find(JiraIssuesFields);
const findTriggerFields = () => wrapper.find(TriggerFields);
@@ -63,6 +66,26 @@ describe('IntegrationForm', () => {
});
});
+ describe('integrationLevel is instance', () => {
+ it('renders ConfirmationModal', () => {
+ createComponent({
+ integrationLevel: 'instance',
+ });
+
+ expect(findConfirmationModal().exists()).toBe(true);
+ });
+ });
+
+ describe('integrationLevel is not instance', () => {
+ it('does not render ConfirmationModal', () => {
+ createComponent({
+ integrationLevel: 'project',
+ });
+
+ expect(findConfirmationModal().exists()).toBe(false);
+ });
+ });
+
describe('type is "slack"', () => {
beforeEach(() => {
createComponent({ type: 'slack' });
diff --git a/spec/frontend/integrations/edit/mock_data.js b/spec/frontend/integrations/edit/mock_data.js
index 821972b7698..27ba0768331 100644
--- a/spec/frontend/integrations/edit/mock_data.js
+++ b/spec/frontend/integrations/edit/mock_data.js
@@ -2,6 +2,7 @@ export const mockIntegrationProps = {
id: 25,
initialActivated: true,
showActive: true,
+ editable: true,
triggerFieldsProps: {
initialTriggerCommit: false,
initialTriggerMergeRequest: false,
diff --git a/spec/frontend/invite_member/components/invite_member_modal_spec.js b/spec/frontend/invite_member/components/invite_member_modal_spec.js
new file mode 100644
index 00000000000..1d0adb3ab4c
--- /dev/null
+++ b/spec/frontend/invite_member/components/invite_member_modal_spec.js
@@ -0,0 +1,63 @@
+import { shallowMount } from '@vue/test-utils';
+import { GlLink } from '@gitlab/ui';
+import { mockTracking, unmockTracking, triggerEvent } from 'helpers/tracking_helper';
+import InviteMemberModal from '~/invite_member/components/invite_member_modal.vue';
+
+const memberPath = 'member_path';
+
+const createComponent = () => {
+ return shallowMount(InviteMemberModal, {
+ provide: {
+ membersPath: memberPath,
+ },
+ stubs: {
+ 'gl-emoji': '<img/>',
+ 'gl-modal': '<div><slot name="modal-title"></slot><slot></slot></div>',
+ },
+ });
+};
+
+describe('InviteMemberModal', () => {
+ let wrapper;
+
+ beforeEach(() => {
+ wrapper = createComponent();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ wrapper = null;
+ });
+
+ const findLink = () => wrapper.find(GlLink);
+
+ describe('rendering the modal', () => {
+ it('renders the modal with the correct title', () => {
+ expect(wrapper.text()).toContain("Oops, this feature isn't ready yet");
+ });
+
+ describe('rendering the see who link', () => {
+ it('renders the correct link', () => {
+ expect(findLink().attributes('href')).toBe(memberPath);
+ });
+ });
+ });
+
+ describe('tracking', () => {
+ let trackingSpy;
+
+ afterEach(() => {
+ unmockTracking();
+ });
+
+ it('send an event when go to pipelines is clicked', () => {
+ trackingSpy = mockTracking('_category_', wrapper.element, jest.spyOn);
+
+ triggerEvent(findLink().element);
+
+ expect(trackingSpy).toHaveBeenCalledWith('_category_', 'click_who_can_invite_link', {
+ label: 'invite_members_message',
+ });
+ });
+ });
+});
diff --git a/spec/frontend/invite_member/components/invite_member_trigger_mock_data.js b/spec/frontend/invite_member/components/invite_member_trigger_mock_data.js
new file mode 100644
index 00000000000..9b34a8027e9
--- /dev/null
+++ b/spec/frontend/invite_member/components/invite_member_trigger_mock_data.js
@@ -0,0 +1,7 @@
+const triggerProvides = {
+ displayText: 'Invite member',
+ event: 'click_invite_members_version_b',
+ label: 'edit_assignee',
+};
+
+export default triggerProvides;
diff --git a/spec/frontend/invite_member/components/invite_member_trigger_spec.js b/spec/frontend/invite_member/components/invite_member_trigger_spec.js
new file mode 100644
index 00000000000..57b8918e3da
--- /dev/null
+++ b/spec/frontend/invite_member/components/invite_member_trigger_spec.js
@@ -0,0 +1,48 @@
+import { shallowMount } from '@vue/test-utils';
+import { GlLink } from '@gitlab/ui';
+import { mockTracking, unmockTracking, triggerEvent } from 'helpers/tracking_helper';
+import InviteMemberTrigger from '~/invite_member/components/invite_member_trigger.vue';
+import triggerProvides from './invite_member_trigger_mock_data';
+
+const createComponent = () => {
+ return shallowMount(InviteMemberTrigger, { provide: triggerProvides });
+};
+
+describe('InviteMemberTrigger', () => {
+ let wrapper;
+
+ beforeEach(() => {
+ wrapper = createComponent();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ wrapper = null;
+ });
+
+ const findLink = () => wrapper.find(GlLink);
+
+ describe('displayText', () => {
+ it('includes the correct displayText for the link', () => {
+ expect(findLink().text()).toBe(triggerProvides.displayText);
+ });
+ });
+
+ describe('tracking', () => {
+ let trackingSpy;
+
+ afterEach(() => {
+ unmockTracking();
+ });
+
+ it('send an event when go to pipelines is clicked', () => {
+ trackingSpy = mockTracking('_category_', wrapper.element, jest.spyOn);
+
+ triggerEvent(findLink().element);
+
+ expect(trackingSpy).toHaveBeenCalledWith('_category_', triggerProvides.event, {
+ label: triggerProvides.label,
+ });
+ });
+ });
+});
diff --git a/spec/frontend/invite_members/components/invite_members_modal_spec.js b/spec/frontend/invite_members/components/invite_members_modal_spec.js
new file mode 100644
index 00000000000..0be0fbbde2d
--- /dev/null
+++ b/spec/frontend/invite_members/components/invite_members_modal_spec.js
@@ -0,0 +1,115 @@
+import { shallowMount } from '@vue/test-utils';
+import { GlDropdown, GlDropdownItem, GlDatepicker, GlSprintf, GlLink } from '@gitlab/ui';
+import Api from '~/api';
+import InviteMembersModal from '~/invite_members/components/invite_members_modal.vue';
+
+const groupId = '1';
+const groupName = 'testgroup';
+const accessLevels = { Guest: 10, Reporter: 20, Developer: 30, Maintainer: 40, Owner: 50 };
+const defaultAccessLevel = '10';
+const helpLink = 'https://example.com';
+
+const createComponent = () => {
+ return shallowMount(InviteMembersModal, {
+ propsData: {
+ groupId,
+ groupName,
+ accessLevels,
+ defaultAccessLevel,
+ helpLink,
+ },
+ stubs: {
+ GlSprintf,
+ 'gl-modal': '<div><slot name="modal-footer"></slot><slot></slot></div>',
+ },
+ });
+};
+
+describe('InviteMembersModal', () => {
+ let wrapper;
+
+ afterEach(() => {
+ wrapper.destroy();
+ wrapper = null;
+ });
+
+ const findDropdown = () => wrapper.find(GlDropdown);
+ const findDropdownItems = () => wrapper.findAll(GlDropdownItem);
+ const findDatepicker = () => wrapper.find(GlDatepicker);
+ const findLink = () => wrapper.find(GlLink);
+ const findCancelButton = () => wrapper.find({ ref: 'cancelButton' });
+ const findInviteButton = () => wrapper.find({ ref: 'inviteButton' });
+
+ describe('rendering the modal', () => {
+ beforeEach(() => {
+ wrapper = createComponent();
+ });
+
+ it('renders the modal with the correct title', () => {
+ expect(wrapper.attributes('title')).toBe('Invite team members');
+ });
+
+ it('renders the Cancel button text correctly', () => {
+ expect(findCancelButton().text()).toBe('Cancel');
+ });
+
+ it('renders the Invite button text correctly', () => {
+ expect(findInviteButton().text()).toBe('Invite');
+ });
+
+ describe('rendering the access levels dropdown', () => {
+ it('sets the default dropdown text to the default access level name', () => {
+ expect(findDropdown().attributes('text')).toBe('Guest');
+ });
+
+ it('renders dropdown items for each accessLevel', () => {
+ expect(findDropdownItems()).toHaveLength(5);
+ });
+ });
+
+ describe('rendering the help link', () => {
+ it('renders the correct link', () => {
+ expect(findLink().attributes('href')).toBe(helpLink);
+ });
+ });
+
+ describe('rendering the access expiration date field', () => {
+ it('renders the datepicker', () => {
+ expect(findDatepicker()).toExist();
+ });
+ });
+ });
+
+ describe('submitting the invite form', () => {
+ const postData = {
+ user_id: '1',
+ access_level: '10',
+ expires_at: new Date(),
+ format: 'json',
+ };
+
+ beforeEach(() => {
+ wrapper = createComponent();
+
+ jest.spyOn(Api, 'inviteGroupMember').mockResolvedValue({ data: postData });
+ wrapper.vm.$toast = { show: jest.fn() };
+
+ wrapper.vm.submitForm(postData);
+ });
+
+ it('calls Api inviteGroupMember with the correct params', () => {
+ expect(Api.inviteGroupMember).toHaveBeenCalledWith(groupId, postData);
+ });
+
+ describe('when the invite was sent successfully', () => {
+ const toastMessageSuccessful = 'Users were succesfully added';
+
+ it('displays the successful toastMessage', () => {
+ expect(wrapper.vm.$toast.show).toHaveBeenCalledWith(
+ toastMessageSuccessful,
+ wrapper.vm.toastOptions,
+ );
+ });
+ });
+ });
+});
diff --git a/spec/frontend/invite_members/components/invite_members_trigger_spec.js b/spec/frontend/invite_members/components/invite_members_trigger_spec.js
new file mode 100644
index 00000000000..450d37a9748
--- /dev/null
+++ b/spec/frontend/invite_members/components/invite_members_trigger_spec.js
@@ -0,0 +1,58 @@
+import { shallowMount } from '@vue/test-utils';
+import { GlIcon, GlLink } from '@gitlab/ui';
+import InviteMembersTrigger from '~/invite_members/components/invite_members_trigger.vue';
+
+const displayText = 'Invite team members';
+const icon = 'plus';
+
+const createComponent = (props = {}) => {
+ return shallowMount(InviteMembersTrigger, {
+ propsData: {
+ displayText,
+ ...props,
+ },
+ });
+};
+
+describe('InviteMembersTrigger', () => {
+ let wrapper;
+
+ afterEach(() => {
+ wrapper.destroy();
+ wrapper = null;
+ });
+
+ describe('displayText', () => {
+ const findLink = () => wrapper.find(GlLink);
+
+ beforeEach(() => {
+ wrapper = createComponent();
+ });
+
+ it('includes the correct displayText for the link', () => {
+ expect(findLink().text()).toBe(displayText);
+ });
+ });
+
+ describe('icon', () => {
+ const findIcon = () => wrapper.find(GlIcon);
+
+ it('includes the correct icon when an icon is sent', () => {
+ wrapper = createComponent({ icon });
+
+ expect(findIcon().attributes('name')).toBe(icon);
+ });
+
+ it('does not include an icon when icon is not sent', () => {
+ wrapper = createComponent();
+
+ expect(findIcon().exists()).toBe(false);
+ });
+
+ it('does not include an icon when empty string is sent', () => {
+ wrapper = createComponent({ icon: '' });
+
+ expect(findIcon().exists()).toBe(false);
+ });
+ });
+});
diff --git a/spec/frontend/issuable/related_issues/components/add_issuable_form_spec.js b/spec/frontend/issuable/related_issues/components/add_issuable_form_spec.js
index bfbe4ec8e70..17a195df494 100644
--- a/spec/frontend/issuable/related_issues/components/add_issuable_form_spec.js
+++ b/spec/frontend/issuable/related_issues/components/add_issuable_form_spec.js
@@ -48,7 +48,10 @@ describe('AddIssuableForm', () => {
const input = findFormInput(wrapper);
if (input) input.blur();
- wrapper.destroy();
+ if (wrapper) {
+ wrapper.destroy();
+ wrapper = null;
+ }
});
describe('with data', () => {
diff --git a/spec/frontend/issuable/related_issues/components/issue_token_spec.js b/spec/frontend/issuable/related_issues/components/issue_token_spec.js
index 553721fa783..f2cb9042ba6 100644
--- a/spec/frontend/issuable/related_issues/components/issue_token_spec.js
+++ b/spec/frontend/issuable/related_issues/components/issue_token_spec.js
@@ -1,241 +1,146 @@
-import Vue from 'vue';
+import { shallowMount } from '@vue/test-utils';
import { PathIdSeparator } from '~/related_issues/constants';
-import issueToken from '~/related_issues/components/issue_token.vue';
+import IssueToken from '~/related_issues/components/issue_token.vue';
describe('IssueToken', () => {
const idKey = 200;
const displayReference = 'foo/bar#123';
- const title = 'some title';
- const pathIdSeparator = PathIdSeparator.Issue;
const eventNamespace = 'pendingIssuable';
- let IssueToken;
- let vm;
+ const path = '/foo/bar/issues/123';
+ const pathIdSeparator = PathIdSeparator.Issue;
+ const title = 'some title';
- beforeEach(() => {
- IssueToken = Vue.extend(issueToken);
- });
+ let wrapper;
+
+ const defaultProps = {
+ idKey,
+ displayReference,
+ pathIdSeparator,
+ };
+
+ const createComponent = (props = {}) => {
+ wrapper = shallowMount(IssueToken, {
+ propsData: { ...defaultProps, ...props },
+ });
+ };
afterEach(() => {
- if (vm) {
- vm.$destroy();
+ if (wrapper) {
+ wrapper.destroy();
+ wrapper = null;
}
});
+ const findLink = () => wrapper.find({ ref: 'link' });
+ const findReference = () => wrapper.find({ ref: 'reference' });
+ const findReferenceIcon = () => wrapper.find('[data-testid="referenceIcon"]');
+ const findRemoveBtn = () => wrapper.find('[data-testid="removeBtn"]');
+ const findTitle = () => wrapper.find({ ref: 'title' });
+
describe('with reference supplied', () => {
beforeEach(() => {
- vm = new IssueToken({
- propsData: {
- idKey,
- eventNamespace,
- displayReference,
- pathIdSeparator,
- },
- }).$mount();
+ createComponent();
});
it('shows reference', () => {
- expect(vm.$el.textContent.trim()).toEqual(displayReference);
+ expect(wrapper.text()).toContain(displayReference);
});
it('does not link without path specified', () => {
- expect(vm.$refs.link.tagName.toLowerCase()).toEqual('span');
- expect(vm.$refs.link.getAttribute('href')).toBeNull();
+ expect(findLink().element.tagName).toBe('SPAN');
+ expect(findLink().attributes('href')).toBeUndefined();
});
});
describe('with reference and title supplied', () => {
- beforeEach(() => {
- vm = new IssueToken({
- propsData: {
- idKey,
- eventNamespace,
- displayReference,
- pathIdSeparator,
- title,
- },
- }).$mount();
- });
-
it('shows reference and title', () => {
- expect(vm.$refs.reference.textContent.trim()).toEqual(displayReference);
- expect(vm.$refs.title.textContent.trim()).toEqual(title);
- });
- });
-
- describe('with path supplied', () => {
- const path = '/foo/bar/issues/123';
- beforeEach(() => {
- vm = new IssueToken({
- propsData: {
- idKey,
- eventNamespace,
- displayReference,
- pathIdSeparator,
- title,
- path,
- },
- }).$mount();
- });
+ createComponent({
+ title,
+ });
- it('links reference and title', () => {
- expect(vm.$refs.link.getAttribute('href')).toEqual(path);
+ expect(findReference().text()).toBe(displayReference);
+ expect(findTitle().text()).toBe(title);
});
});
- describe('with state supplied', () => {
- describe("`state: 'opened'`", () => {
- beforeEach(() => {
- vm = new IssueToken({
- propsData: {
- idKey,
- eventNamespace,
- displayReference,
- pathIdSeparator,
- state: 'opened',
- },
- }).$mount();
+ describe('with path and title supplied', () => {
+ it('links reference and title', () => {
+ createComponent({
+ path,
+ title,
});
- it('shows green circle icon', () => {
- expect(vm.$el.querySelector('.issue-token-state-icon-open.fa.fa-circle-o')).toBeDefined();
- });
- });
-
- describe("`state: 'reopened'`", () => {
- beforeEach(() => {
- vm = new IssueToken({
- propsData: {
- idKey,
- eventNamespace,
- displayReference,
- pathIdSeparator,
- state: 'reopened',
- },
- }).$mount();
- });
-
- it('shows green circle icon', () => {
- expect(vm.$el.querySelector('.issue-token-state-icon-open.fa.fa-circle-o')).toBeDefined();
- });
+ expect(findLink().attributes('href')).toBe(path);
});
+ });
- describe("`state: 'closed'`", () => {
- beforeEach(() => {
- vm = new IssueToken({
- propsData: {
- idKey,
- eventNamespace,
- displayReference,
- pathIdSeparator,
- state: 'closed',
- },
- }).$mount();
+ describe('with state supplied', () => {
+ it.each`
+ state | icon | cssClass
+ ${'opened'} | ${'issue-open-m'} | ${'issue-token-state-icon-open'}
+ ${'reopened'} | ${'issue-open-m'} | ${'issue-token-state-icon-open'}
+ ${'closed'} | ${'issue-close'} | ${'issue-token-state-icon-closed'}
+ `('shows "$icon" icon when "$state"', ({ state, icon, cssClass }) => {
+ createComponent({
+ path,
+ state,
});
- it('shows red minus icon', () => {
- expect(vm.$el.querySelector('.issue-token-state-icon-closed.fa.fa-minus')).toBeDefined();
- });
+ expect(findReferenceIcon().props('name')).toBe(icon);
+ expect(findReferenceIcon().classes()).toContain(cssClass);
});
});
describe('with reference, title, state', () => {
const state = 'opened';
- beforeEach(() => {
- vm = new IssueToken({
- propsData: {
- idKey,
- eventNamespace,
- displayReference,
- pathIdSeparator,
- title,
- state,
- },
- }).$mount();
- });
it('shows reference, title, and state', () => {
- const stateIcon = vm.$refs.reference.querySelector('svg');
+ createComponent({
+ title,
+ state,
+ });
- expect(stateIcon.getAttribute('aria-label')).toEqual(state);
- expect(vm.$refs.reference.textContent.trim()).toEqual(displayReference);
- expect(vm.$refs.title.textContent.trim()).toEqual(title);
+ expect(findReferenceIcon().attributes('aria-label')).toBe(state);
+ expect(findReference().text()).toBe(displayReference);
+ expect(findTitle().text()).toBe(title);
});
});
describe('with canRemove', () => {
describe('`canRemove: false` (default)', () => {
- beforeEach(() => {
- vm = new IssueToken({
- propsData: {
- idKey,
- eventNamespace,
- displayReference,
- pathIdSeparator,
- },
- }).$mount();
- });
-
it('does not have remove button', () => {
- expect(vm.$el.querySelector('.issue-token-remove-button')).toBeNull();
+ createComponent();
+
+ expect(findRemoveBtn().exists()).toBe(false);
});
});
describe('`canRemove: true`', () => {
beforeEach(() => {
- vm = new IssueToken({
- propsData: {
- idKey,
- eventNamespace,
- displayReference,
- pathIdSeparator,
- canRemove: true,
- },
- }).$mount();
+ createComponent({
+ eventNamespace,
+ canRemove: true,
+ });
});
it('has remove button', () => {
- expect(vm.$el.querySelector('.issue-token-remove-button')).toBeDefined();
+ expect(findRemoveBtn().exists()).toBe(true);
});
- });
- });
-
- describe('methods', () => {
- beforeEach(() => {
- vm = new IssueToken({
- propsData: {
- idKey,
- eventNamespace,
- displayReference,
- pathIdSeparator,
- },
- }).$mount();
- });
- it('when getting checked', () => {
- jest.spyOn(vm, '$emit').mockImplementation(() => {});
- vm.onRemoveRequest();
+ it('emits event when clicked', () => {
+ findRemoveBtn().trigger('click');
- expect(vm.$emit).toHaveBeenCalledWith('pendingIssuableRemoveRequest', vm.idKey);
- });
- });
+ const emitted = wrapper.emitted(`${eventNamespace}RemoveRequest`);
- describe('tooltip', () => {
- beforeEach(() => {
- vm = new IssueToken({
- propsData: {
- idKey,
- eventNamespace,
- displayReference,
- pathIdSeparator,
- canRemove: true,
- },
- }).$mount();
- });
-
- it('should not be escaped', () => {
- const { originalTitle } = vm.$refs.removeButton.dataset;
+ expect(emitted).toHaveLength(1);
+ expect(emitted[0]).toEqual([idKey]);
+ });
- expect(originalTitle).toEqual(`Remove ${displayReference}`);
+ it('tooltip should not be escaped', () => {
+ expect(findRemoveBtn().attributes('data-original-title')).toBe(
+ `Remove ${displayReference}`,
+ );
+ });
});
});
});
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 0f88e4d71fe..b758b85beef 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
@@ -18,7 +18,10 @@ describe('RelatedIssuesBlock', () => {
const findIssueCountBadgeAddButton = () => wrapper.find(GlButton);
afterEach(() => {
- wrapper.destroy();
+ if (wrapper) {
+ wrapper.destroy();
+ wrapper = null;
+ }
});
describe('with defaults', () => {
diff --git a/spec/frontend/issuable/related_issues/components/related_issues_list_spec.js b/spec/frontend/issuable/related_issues/components/related_issues_list_spec.js
index 6cf0b9d21ea..39bc244297b 100644
--- a/spec/frontend/issuable/related_issues/components/related_issues_list_spec.js
+++ b/spec/frontend/issuable/related_issues/components/related_issues_list_spec.js
@@ -14,7 +14,10 @@ describe('RelatedIssuesList', () => {
let wrapper;
afterEach(() => {
- wrapper.destroy();
+ if (wrapper) {
+ wrapper.destroy();
+ wrapper = null;
+ }
});
describe('with defaults', () => {
diff --git a/spec/frontend/issuable_create/components/issuable_form_spec.js b/spec/frontend/issuable_create/components/issuable_form_spec.js
index e2c6b4d9521..e489d1dae3e 100644
--- a/spec/frontend/issuable_create/components/issuable_form_spec.js
+++ b/spec/frontend/issuable_create/components/issuable_form_spec.js
@@ -79,6 +79,7 @@ describe('IssuableForm', () => {
markdownDocsPath: wrapper.vm.descriptionHelpPath,
addSpacingClasses: false,
showSuggestPopover: true,
+ textareaValue: '',
});
expect(descriptionFieldEl.find('textarea').exists()).toBe(true);
expect(descriptionFieldEl.find('textarea').attributes('placeholder')).toBe(
diff --git a/spec/frontend/issuable_list/mock_data.js b/spec/frontend/issuable_list/mock_data.js
index f6f914a595d..8eab2ca6f94 100644
--- a/spec/frontend/issuable_list/mock_data.js
+++ b/spec/frontend/issuable_list/mock_data.js
@@ -30,13 +30,23 @@ export const mockScopedLabel = {
export const mockLabels = [mockRegularLabel, mockScopedLabel];
+export const mockCurrentUserTodo = {
+ id: 'gid://gitlab/Todo/489',
+ state: 'done',
+};
+
export const mockIssuable = {
iid: '30',
title: 'Dismiss Cipher with no integrity',
- description: null,
+ titleHtml: 'Dismiss Cipher with no integrity',
+ description: 'fortitudinis _fomentis_ dolor mitigari solet.',
+ descriptionHtml: 'fortitudinis <i>fomentis</i> dolor mitigari solet.',
+ state: 'opened',
createdAt: '2020-06-29T13:52:56Z',
updatedAt: '2020-09-10T11:41:13Z',
webUrl: 'http://0.0.0.0:3000/gitlab-org/gitlab-shell/-/issues/30',
+ blocked: false,
+ confidential: false,
author: mockAuthor,
labels: {
nodes: mockLabels,
diff --git a/spec/frontend/issuable_show/components/issuable_body_spec.js b/spec/frontend/issuable_show/components/issuable_body_spec.js
new file mode 100644
index 00000000000..0e4475e8103
--- /dev/null
+++ b/spec/frontend/issuable_show/components/issuable_body_spec.js
@@ -0,0 +1,140 @@
+import { shallowMount } from '@vue/test-utils';
+
+import IssuableBody from '~/issuable_show/components/issuable_body.vue';
+
+import IssuableTitle from '~/issuable_show/components/issuable_title.vue';
+import IssuableDescription from '~/issuable_show/components/issuable_description.vue';
+import IssuableEditForm from '~/issuable_show/components/issuable_edit_form.vue';
+import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
+
+import { mockIssuableShowProps, mockIssuable } from '../mock_data';
+
+jest.mock('~/autosave');
+
+const issuableBodyProps = {
+ ...mockIssuableShowProps,
+ issuable: mockIssuable,
+};
+
+const createComponent = (propsData = issuableBodyProps) =>
+ shallowMount(IssuableBody, {
+ propsData,
+ stubs: {
+ IssuableTitle,
+ IssuableDescription,
+ IssuableEditForm,
+ TimeAgoTooltip,
+ },
+ slots: {
+ 'status-badge': 'Open',
+ 'edit-form-actions': `
+ <button class="js-save">Save changes</button>
+ <button class="js-cancel">Cancel</button>
+ `,
+ },
+ });
+
+describe('IssuableBody', () => {
+ let wrapper;
+
+ beforeEach(() => {
+ wrapper = createComponent();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe('computed', () => {
+ describe('isUpdated', () => {
+ it.each`
+ updatedAt | returnValue
+ ${mockIssuable.updatedAt} | ${true}
+ ${null} | ${false}
+ ${''} | ${false}
+ `(
+ 'returns $returnValue when value of `updateAt` prop is `$updatedAt`',
+ async ({ updatedAt, returnValue }) => {
+ wrapper.setProps({
+ issuable: {
+ ...mockIssuable,
+ updatedAt,
+ },
+ });
+
+ await wrapper.vm.$nextTick();
+
+ expect(wrapper.vm.isUpdated).toBe(returnValue);
+ },
+ );
+ });
+
+ describe('updatedBy', () => {
+ it('returns value of `issuable.updatedBy`', () => {
+ expect(wrapper.vm.updatedBy).toBe(mockIssuable.updatedBy);
+ });
+ });
+ });
+
+ describe('template', () => {
+ it('renders issuable-title component', () => {
+ const titleEl = wrapper.find(IssuableTitle);
+
+ expect(titleEl.exists()).toBe(true);
+ expect(titleEl.props()).toMatchObject({
+ issuable: issuableBodyProps.issuable,
+ statusBadgeClass: issuableBodyProps.statusBadgeClass,
+ statusIcon: issuableBodyProps.statusIcon,
+ enableEdit: issuableBodyProps.enableEdit,
+ });
+ });
+
+ it('renders issuable-description component', () => {
+ const descriptionEl = wrapper.find(IssuableDescription);
+
+ expect(descriptionEl.exists()).toBe(true);
+ expect(descriptionEl.props('issuable')).toEqual(issuableBodyProps.issuable);
+ });
+
+ it('renders issuable edit info', () => {
+ const editedEl = wrapper.find('small');
+ const sanitizedText = editedEl
+ .text()
+ .replace(/\n/g, ' ')
+ .replace(/\s+/g, ' ');
+
+ expect(sanitizedText).toContain('Edited');
+ expect(sanitizedText).toContain('ago');
+ expect(sanitizedText).toContain(`by ${mockIssuable.updatedBy.name}`);
+ });
+
+ it('renders issuable-edit-form when `editFormVisible` prop is true', async () => {
+ wrapper.setProps({
+ editFormVisible: true,
+ });
+
+ await wrapper.vm.$nextTick();
+
+ const editFormEl = wrapper.find(IssuableEditForm);
+ expect(editFormEl.exists()).toBe(true);
+ expect(editFormEl.props()).toMatchObject({
+ issuable: issuableBodyProps.issuable,
+ enableAutocomplete: issuableBodyProps.enableAutocomplete,
+ descriptionPreviewPath: issuableBodyProps.descriptionPreviewPath,
+ descriptionHelpPath: issuableBodyProps.descriptionHelpPath,
+ });
+ expect(editFormEl.find('button.js-save').exists()).toBe(true);
+ expect(editFormEl.find('button.js-cancel').exists()).toBe(true);
+ });
+
+ describe('events', () => {
+ it('component emits `edit-issuable` event bubbled via issuable-title', () => {
+ const issuableTitle = wrapper.find(IssuableTitle);
+
+ issuableTitle.vm.$emit('edit-issuable');
+
+ expect(wrapper.emitted('edit-issuable')).toBeTruthy();
+ });
+ });
+ });
+});
diff --git a/spec/frontend/issuable_show/components/issuable_description_spec.js b/spec/frontend/issuable_show/components/issuable_description_spec.js
new file mode 100644
index 00000000000..1dd8348b098
--- /dev/null
+++ b/spec/frontend/issuable_show/components/issuable_description_spec.js
@@ -0,0 +1,41 @@
+import $ from 'jquery';
+import { shallowMount } from '@vue/test-utils';
+
+import IssuableDescription from '~/issuable_show/components/issuable_description.vue';
+
+import { mockIssuable } from '../mock_data';
+
+const createComponent = (issuable = mockIssuable) =>
+ shallowMount(IssuableDescription, {
+ propsData: { issuable },
+ });
+
+describe('IssuableDescription', () => {
+ let renderGFMSpy;
+ let wrapper;
+
+ beforeEach(() => {
+ renderGFMSpy = jest.spyOn($.fn, 'renderGFM');
+ wrapper = createComponent();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe('mounted', () => {
+ it('calls `renderGFM`', () => {
+ expect(renderGFMSpy).toHaveBeenCalledTimes(1);
+ });
+ });
+
+ describe('methods', () => {
+ describe('renderGFM', () => {
+ it('calls `renderGFM` on container element', () => {
+ wrapper.vm.renderGFM();
+
+ expect(renderGFMSpy).toHaveBeenCalled();
+ });
+ });
+ });
+});
diff --git a/spec/frontend/issuable_show/components/issuable_edit_form_spec.js b/spec/frontend/issuable_show/components/issuable_edit_form_spec.js
new file mode 100644
index 00000000000..352e66cdffe
--- /dev/null
+++ b/spec/frontend/issuable_show/components/issuable_edit_form_spec.js
@@ -0,0 +1,122 @@
+import { shallowMount } from '@vue/test-utils';
+import { GlFormInput } from '@gitlab/ui';
+import MarkdownField from '~/vue_shared/components/markdown/field.vue';
+
+import IssuableEditForm from '~/issuable_show/components/issuable_edit_form.vue';
+import IssuableEventHub from '~/issuable_show/event_hub';
+
+import { mockIssuableShowProps, mockIssuable } from '../mock_data';
+
+const issuableEditFormProps = {
+ issuable: mockIssuable,
+ ...mockIssuableShowProps,
+};
+
+const createComponent = ({ propsData = issuableEditFormProps } = {}) =>
+ shallowMount(IssuableEditForm, {
+ propsData,
+ stubs: {
+ MarkdownField,
+ },
+ slots: {
+ 'edit-form-actions': `
+ <button class="js-save">Save changes</button>
+ <button class="js-cancel">Cancel</button>
+ `,
+ },
+ });
+
+describe('IssuableEditForm', () => {
+ let wrapper;
+ const assertEvent = eventSpy => {
+ expect(eventSpy).toHaveBeenNthCalledWith(1, 'update.issuable', expect.any(Function));
+ expect(eventSpy).toHaveBeenNthCalledWith(2, 'close.form', expect.any(Function));
+ };
+
+ beforeEach(() => {
+ wrapper = createComponent();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe('created', () => {
+ it('binds `update.issuable` and `close.form` event listeners', () => {
+ const eventOnSpy = jest.spyOn(IssuableEventHub, '$on');
+ const wrapperTemp = createComponent();
+
+ assertEvent(eventOnSpy);
+
+ wrapperTemp.destroy();
+ });
+ });
+
+ describe('beforeDestroy', () => {
+ it('unbinds `update.issuable` and `close.form` event listeners', () => {
+ const wrapperTemp = createComponent();
+ const eventOffSpy = jest.spyOn(IssuableEventHub, '$off');
+
+ wrapperTemp.destroy();
+
+ assertEvent(eventOffSpy);
+ });
+ });
+
+ describe('methods', () => {
+ describe('initAutosave', () => {
+ it('initializes `autosaveTitle` and `autosaveDescription` props', () => {
+ expect(wrapper.vm.autosaveTitle).toBeDefined();
+ expect(wrapper.vm.autosaveDescription).toBeDefined();
+ });
+ });
+
+ describe('resetAutosave', () => {
+ it('calls `reset` on `autosaveTitle` and `autosaveDescription` props', () => {
+ jest.spyOn(wrapper.vm.autosaveTitle, 'reset').mockImplementation(jest.fn);
+ jest.spyOn(wrapper.vm.autosaveDescription, 'reset').mockImplementation(jest.fn);
+
+ wrapper.vm.resetAutosave();
+
+ expect(wrapper.vm.autosaveTitle.reset).toHaveBeenCalled();
+ expect(wrapper.vm.autosaveDescription.reset).toHaveBeenCalled();
+ });
+ });
+ });
+
+ describe('template', () => {
+ it('renders title input field', () => {
+ const titleInputEl = wrapper.find('[data-testid="title"]');
+
+ expect(titleInputEl.exists()).toBe(true);
+ expect(titleInputEl.find(GlFormInput).attributes()).toMatchObject({
+ 'aria-label': 'Title',
+ placeholder: 'Title',
+ });
+ });
+
+ it('renders description textarea field', () => {
+ const descriptionEl = wrapper.find('[data-testid="description"]');
+
+ expect(descriptionEl.exists()).toBe(true);
+ expect(descriptionEl.find(MarkdownField).props()).toMatchObject({
+ markdownPreviewPath: issuableEditFormProps.descriptionPreviewPath,
+ markdownDocsPath: issuableEditFormProps.descriptionHelpPath,
+ enableAutocomplete: issuableEditFormProps.enableAutocomplete,
+ textareaValue: mockIssuable.description,
+ });
+ expect(descriptionEl.find('textarea').attributes()).toMatchObject({
+ 'data-supports-quick-actions': 'true',
+ 'aria-label': 'Description',
+ placeholder: 'Write a comment or drag your files here…',
+ });
+ });
+
+ it('renders form actions', () => {
+ const actionsEl = wrapper.find('[data-testid="actions"]');
+
+ expect(actionsEl.find('button.js-save').exists()).toBe(true);
+ expect(actionsEl.find('button.js-cancel').exists()).toBe(true);
+ });
+ });
+});
diff --git a/spec/frontend/issuable_show/components/issuable_header_spec.js b/spec/frontend/issuable_show/components/issuable_header_spec.js
new file mode 100644
index 00000000000..fad8ec8a891
--- /dev/null
+++ b/spec/frontend/issuable_show/components/issuable_header_spec.js
@@ -0,0 +1,132 @@
+import { shallowMount } from '@vue/test-utils';
+import { GlIcon, GlAvatarLabeled } from '@gitlab/ui';
+
+import IssuableHeader from '~/issuable_show/components/issuable_header.vue';
+
+import { mockIssuableShowProps, mockIssuable } from '../mock_data';
+
+const issuableHeaderProps = {
+ ...mockIssuable,
+ ...mockIssuableShowProps,
+};
+
+const createComponent = (propsData = issuableHeaderProps) =>
+ shallowMount(IssuableHeader, {
+ propsData,
+ slots: {
+ 'status-badge': 'Open',
+ 'header-actions': `
+ <button class="js-close">Close issuable</button>
+ <a class="js-new" href="/gitlab-org/gitlab-shell/-/issues/new">New issuable</a>
+ `,
+ },
+ });
+
+describe('IssuableHeader', () => {
+ let wrapper;
+ const findByTestId = testId => wrapper.find(`[data-testid="${testId}"]`);
+
+ beforeEach(() => {
+ wrapper = createComponent();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe('computed', () => {
+ describe('authorId', () => {
+ it('returns numeric ID from GraphQL ID of `author` prop', () => {
+ expect(wrapper.vm.authorId).toBe(1);
+ });
+ });
+ });
+
+ describe('handleRightSidebarToggleClick', () => {
+ beforeEach(() => {
+ setFixtures('<button class="js-toggle-right-sidebar-button">Collapse sidebar</button>');
+ });
+
+ it('dispatches `click` event on sidebar toggle button', () => {
+ wrapper.vm.toggleSidebarButtonEl = document.querySelector('.js-toggle-right-sidebar-button');
+ jest.spyOn(wrapper.vm.toggleSidebarButtonEl, 'dispatchEvent').mockImplementation(jest.fn);
+
+ wrapper.vm.handleRightSidebarToggleClick();
+
+ expect(wrapper.vm.toggleSidebarButtonEl.dispatchEvent).toHaveBeenCalledWith(
+ expect.objectContaining({
+ type: 'click',
+ }),
+ );
+ });
+ });
+
+ describe('template', () => {
+ it('renders issuable status icon and text', () => {
+ const statusBoxEl = findByTestId('status');
+
+ expect(statusBoxEl.exists()).toBe(true);
+ expect(statusBoxEl.find(GlIcon).props('name')).toBe(mockIssuableShowProps.statusIcon);
+ expect(statusBoxEl.text()).toContain('Open');
+ });
+
+ it('renders blocked icon when issuable is blocked', async () => {
+ wrapper.setProps({
+ blocked: true,
+ });
+
+ await wrapper.vm.$nextTick();
+
+ const blockedEl = findByTestId('blocked');
+
+ expect(blockedEl.exists()).toBe(true);
+ expect(blockedEl.find(GlIcon).props('name')).toBe('lock');
+ });
+
+ it('renders confidential icon when issuable is confidential', async () => {
+ wrapper.setProps({
+ confidential: true,
+ });
+
+ await wrapper.vm.$nextTick();
+
+ const confidentialEl = findByTestId('confidential');
+
+ expect(confidentialEl.exists()).toBe(true);
+ expect(confidentialEl.find(GlIcon).props('name')).toBe('eye-slash');
+ });
+
+ it('renders issuable author avatar', () => {
+ const { username, name, webUrl, avatarUrl } = mockIssuable.author;
+ const avatarElAttrs = {
+ 'data-user-id': '1',
+ 'data-username': username,
+ 'data-name': name,
+ href: webUrl,
+ target: '_blank',
+ };
+ const avatarEl = findByTestId('avatar');
+ expect(avatarEl.exists()).toBe(true);
+ expect(avatarEl.attributes()).toMatchObject(avatarElAttrs);
+ expect(avatarEl.find(GlAvatarLabeled).attributes()).toMatchObject({
+ size: '24',
+ src: avatarUrl,
+ label: name,
+ });
+ });
+
+ it('renders sidebar toggle button', () => {
+ const toggleButtonEl = findByTestId('sidebar-toggle');
+
+ expect(toggleButtonEl.exists()).toBe(true);
+ expect(toggleButtonEl.props('icon')).toBe('chevron-double-lg-left');
+ });
+
+ it('renders header actions', () => {
+ const actionsEl = findByTestId('header-actions');
+
+ expect(actionsEl.find('button.js-close').exists()).toBe(true);
+ expect(actionsEl.find('a.js-new').exists()).toBe(true);
+ });
+ });
+});
diff --git a/spec/frontend/issuable_show/components/issuable_show_root_spec.js b/spec/frontend/issuable_show/components/issuable_show_root_spec.js
new file mode 100644
index 00000000000..112e4ccd340
--- /dev/null
+++ b/spec/frontend/issuable_show/components/issuable_show_root_spec.js
@@ -0,0 +1,123 @@
+import { shallowMount } from '@vue/test-utils';
+
+import IssuableShowRoot from '~/issuable_show/components/issuable_show_root.vue';
+
+import IssuableHeader from '~/issuable_show/components/issuable_header.vue';
+import IssuableBody from '~/issuable_show/components/issuable_body.vue';
+import IssuableSidebar from '~/issuable_sidebar/components/issuable_sidebar_root.vue';
+
+import { mockIssuableShowProps, mockIssuable } from '../mock_data';
+
+const createComponent = (propsData = mockIssuableShowProps) =>
+ shallowMount(IssuableShowRoot, {
+ propsData,
+ stubs: {
+ IssuableHeader,
+ IssuableBody,
+ IssuableSidebar,
+ },
+ slots: {
+ 'status-badge': 'Open',
+ 'header-actions': `
+ <button class="js-close">Close issuable</button>
+ <a class="js-new" href="/gitlab-org/gitlab-shell/-/issues/new">New issuable</a>
+ `,
+ 'edit-form-actions': `
+ <button class="js-save">Save changes</button>
+ <button class="js-cancel">Cancel</button>
+ `,
+ 'right-sidebar-items': `
+ <div class="js-todo">
+ To Do <button class="js-add-todo">Add a To Do</button>
+ </div>
+ `,
+ },
+ });
+
+describe('IssuableShowRoot', () => {
+ let wrapper;
+
+ beforeEach(() => {
+ wrapper = createComponent();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe('template', () => {
+ const {
+ statusBadgeClass,
+ statusIcon,
+ enableEdit,
+ enableAutocomplete,
+ editFormVisible,
+ descriptionPreviewPath,
+ descriptionHelpPath,
+ } = mockIssuableShowProps;
+ const { blocked, confidential, createdAt, author } = mockIssuable;
+
+ it('renders component container element with class `issuable-show-container`', () => {
+ expect(wrapper.classes()).toContain('issuable-show-container');
+ });
+
+ it('renders issuable-header component', () => {
+ const issuableHeader = wrapper.find(IssuableHeader);
+
+ expect(issuableHeader.exists()).toBe(true);
+ expect(issuableHeader.props()).toMatchObject({
+ statusBadgeClass,
+ statusIcon,
+ blocked,
+ confidential,
+ createdAt,
+ author,
+ });
+ expect(issuableHeader.find('.issuable-status-box').text()).toContain('Open');
+ expect(issuableHeader.find('.detail-page-header-actions button.js-close').exists()).toBe(
+ true,
+ );
+ expect(issuableHeader.find('.detail-page-header-actions a.js-new').exists()).toBe(true);
+ });
+
+ it('renders issuable-body component', () => {
+ const issuableBody = wrapper.find(IssuableBody);
+
+ expect(issuableBody.exists()).toBe(true);
+ expect(issuableBody.props()).toMatchObject({
+ issuable: mockIssuable,
+ statusBadgeClass,
+ statusIcon,
+ enableEdit,
+ enableAutocomplete,
+ editFormVisible,
+ descriptionPreviewPath,
+ descriptionHelpPath,
+ });
+ });
+
+ it('renders issuable-sidebar component', () => {
+ const issuableSidebar = wrapper.find(IssuableSidebar);
+
+ expect(issuableSidebar.exists()).toBe(true);
+ });
+
+ describe('events', () => {
+ it('component emits `edit-issuable` event bubbled via issuable-body', () => {
+ const issuableBody = wrapper.find(IssuableBody);
+
+ issuableBody.vm.$emit('edit-issuable');
+
+ expect(wrapper.emitted('edit-issuable')).toBeTruthy();
+ });
+
+ it('component emits `sidebar-toggle` event bubbled via issuable-sidebar', () => {
+ const issuableSidebar = wrapper.find(IssuableSidebar);
+
+ issuableSidebar.vm.$emit('sidebar-toggle', true);
+
+ expect(wrapper.emitted('sidebar-toggle')).toBeTruthy();
+ });
+ });
+ });
+});
diff --git a/spec/frontend/issuable_show/components/issuable_title_spec.js b/spec/frontend/issuable_show/components/issuable_title_spec.js
new file mode 100644
index 00000000000..e8621c763b3
--- /dev/null
+++ b/spec/frontend/issuable_show/components/issuable_title_spec.js
@@ -0,0 +1,100 @@
+import { shallowMount } from '@vue/test-utils';
+import { GlIcon, GlButton, GlIntersectionObserver } from '@gitlab/ui';
+import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
+
+import IssuableTitle from '~/issuable_show/components/issuable_title.vue';
+
+import { mockIssuableShowProps, mockIssuable } from '../mock_data';
+
+const issuableTitleProps = {
+ issuable: mockIssuable,
+ ...mockIssuableShowProps,
+};
+
+const createComponent = (propsData = issuableTitleProps) =>
+ shallowMount(IssuableTitle, {
+ propsData,
+ stubs: {
+ transition: true,
+ },
+ slots: {
+ 'status-badge': 'Open',
+ },
+ directives: {
+ GlTooltip: createMockDirective(),
+ },
+ });
+
+describe('IssuableTitle', () => {
+ let wrapper;
+
+ beforeEach(() => {
+ wrapper = createComponent();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe('methods', () => {
+ describe('handleTitleAppear', () => {
+ it('sets value of `stickyTitleVisible` prop to false', () => {
+ wrapper.find(GlIntersectionObserver).vm.$emit('appear');
+
+ expect(wrapper.vm.stickyTitleVisible).toBe(false);
+ });
+ });
+
+ describe('handleTitleDisappear', () => {
+ it('sets value of `stickyTitleVisible` prop to true', () => {
+ wrapper.find(GlIntersectionObserver).vm.$emit('disappear');
+
+ expect(wrapper.vm.stickyTitleVisible).toBe(true);
+ });
+ });
+ });
+
+ describe('template', () => {
+ it('renders issuable title', async () => {
+ const wrapperWithTitle = createComponent({
+ ...mockIssuableShowProps,
+ issuable: {
+ ...mockIssuable,
+ titleHtml: '<b>Sample</b> title',
+ },
+ });
+
+ await wrapperWithTitle.vm.$nextTick();
+ const titleEl = wrapperWithTitle.find('h2');
+
+ expect(titleEl.exists()).toBe(true);
+ expect(titleEl.html()).toBe('<h2 dir="auto" class="title qa-title"><b>Sample</b> title</h2>');
+
+ wrapperWithTitle.destroy();
+ });
+
+ it('renders edit button', () => {
+ const editButtonEl = wrapper.find(GlButton);
+ const tooltip = getBinding(editButtonEl.element, 'gl-tooltip');
+
+ expect(editButtonEl.exists()).toBe(true);
+ expect(editButtonEl.props('icon')).toBe('pencil');
+ expect(editButtonEl.attributes('title')).toBe('Edit title and description');
+ expect(tooltip).toBeDefined();
+ });
+
+ it('renders sticky header when `stickyTitleVisible` prop is true', async () => {
+ wrapper.setData({
+ stickyTitleVisible: true,
+ });
+
+ await wrapper.vm.$nextTick();
+ const stickyHeaderEl = wrapper.find('[data-testid="header"]');
+
+ expect(stickyHeaderEl.exists()).toBe(true);
+ expect(stickyHeaderEl.find(GlIcon).props('name')).toBe(issuableTitleProps.statusIcon);
+ expect(stickyHeaderEl.text()).toContain('Open');
+ expect(stickyHeaderEl.text()).toContain(issuableTitleProps.issuable.title);
+ });
+ });
+});
diff --git a/spec/frontend/issuable_show/mock_data.js b/spec/frontend/issuable_show/mock_data.js
new file mode 100644
index 00000000000..14e5febdc6b
--- /dev/null
+++ b/spec/frontend/issuable_show/mock_data.js
@@ -0,0 +1,34 @@
+import { mockIssuable as issuable } from '../issuable_list/mock_data';
+
+export const mockIssuable = {
+ ...issuable,
+ id: 'gid://gitlab/Issue/30',
+ title: 'Sample title',
+ titleHtml: 'Sample title',
+ description: '# Summary',
+ descriptionHtml:
+ '<h1 data-sourcepos="1:1-1:25" dir="auto">&#x000A;<a id="user-content-magnoque-it-lurida-deus" class="anchor" href="#magnoque-it-lurida-deus" aria-hidden="true"></a>Summary</h1>',
+ state: 'opened',
+ blocked: false,
+ confidential: false,
+ updatedBy: issuable.author,
+ currentUserTodos: {
+ nodes: [
+ {
+ id: 'gid://gitlab/Todo/489',
+ state: 'done',
+ },
+ ],
+ },
+};
+
+export const mockIssuableShowProps = {
+ issuable: mockIssuable,
+ descriptionHelpPath: '/help/user/markdown',
+ descriptionPreviewPath: '/gitlab-org/gitlab-shell/preview_markdown',
+ editFormVisible: false,
+ enableAutocomplete: true,
+ enableEdit: true,
+ statusBadgeClass: 'status-box-open',
+ statusIcon: 'issue-open-m',
+};
diff --git a/spec/frontend/issuable_sidebar/components/issuable_sidebar_root_spec.js b/spec/frontend/issuable_sidebar/components/issuable_sidebar_root_spec.js
new file mode 100644
index 00000000000..7686dad4644
--- /dev/null
+++ b/spec/frontend/issuable_sidebar/components/issuable_sidebar_root_spec.js
@@ -0,0 +1,199 @@
+import { shallowMount } from '@vue/test-utils';
+import { GlBreakpointInstance as bp } from '@gitlab/ui/dist/utils';
+import Cookies from 'js-cookie';
+
+import IssuableSidebarRoot from '~/issuable_sidebar/components/issuable_sidebar_root.vue';
+
+const createComponent = (expanded = true) =>
+ shallowMount(IssuableSidebarRoot, {
+ propsData: {
+ expanded,
+ },
+ slots: {
+ 'right-sidebar-items': `
+ <button class="js-todo">Todo</button>
+ `,
+ },
+ });
+
+describe('IssuableSidebarRoot', () => {
+ let wrapper;
+
+ beforeEach(() => {
+ wrapper = createComponent();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe('watch', () => {
+ describe('isExpanded', () => {
+ it('emits `sidebar-toggle` event on component', async () => {
+ wrapper.setData({
+ isExpanded: false,
+ });
+
+ await wrapper.vm.$nextTick();
+
+ expect(wrapper.emitted('sidebar-toggle')).toBeTruthy();
+ expect(wrapper.emitted('sidebar-toggle')[0]).toEqual([
+ {
+ expanded: false,
+ },
+ ]);
+ });
+ });
+ });
+
+ describe('methods', () => {
+ describe('updatePageContainerClass', () => {
+ beforeEach(() => {
+ setFixtures('<div class="layout-page"></div>');
+ });
+
+ it.each`
+ isExpanded | layoutPageClass
+ ${true} | ${'right-sidebar-expanded'}
+ ${false} | ${'right-sidebar-collapsed'}
+ `(
+ 'set class $layoutPageClass to container element when `isExpanded` prop is $isExpanded',
+ async ({ isExpanded, layoutPageClass }) => {
+ wrapper.setData({
+ isExpanded,
+ });
+
+ await wrapper.vm.$nextTick();
+
+ wrapper.vm.updatePageContainerClass();
+
+ expect(document.querySelector('.layout-page').classList.contains(layoutPageClass)).toBe(
+ true,
+ );
+ },
+ );
+ });
+
+ describe('handleWindowResize', () => {
+ beforeEach(async () => {
+ wrapper.setData({
+ userExpanded: true,
+ });
+
+ await wrapper.vm.$nextTick();
+ });
+
+ it.each`
+ breakpoint | isExpandedValue
+ ${'xs'} | ${false}
+ ${'sm'} | ${false}
+ ${'md'} | ${false}
+ ${'lg'} | ${true}
+ ${'xl'} | ${true}
+ `(
+ 'sets `isExpanded` prop to $isExpandedValue only when current screen size is `lg` or `xl`',
+ async ({ breakpoint, isExpandedValue }) => {
+ jest.spyOn(bp, 'isDesktop').mockReturnValue(breakpoint === 'lg' || breakpoint === 'xl');
+
+ wrapper.vm.handleWindowResize();
+
+ expect(wrapper.vm.isExpanded).toBe(isExpandedValue);
+ },
+ );
+
+ it('calls `updatePageContainerClass` method', () => {
+ jest.spyOn(wrapper.vm, 'updatePageContainerClass');
+
+ wrapper.vm.handleWindowResize();
+
+ expect(wrapper.vm.updatePageContainerClass).toHaveBeenCalled();
+ });
+ });
+
+ describe('handleToggleSidebarClick', () => {
+ beforeEach(async () => {
+ jest.spyOn(Cookies, 'set').mockImplementation(jest.fn());
+ wrapper.setData({
+ isExpanded: true,
+ });
+
+ await wrapper.vm.$nextTick();
+ });
+
+ it('flips value of `isExpanded`', () => {
+ wrapper.vm.handleToggleSidebarClick();
+
+ expect(wrapper.vm.isExpanded).toBe(false);
+ expect(wrapper.vm.userExpanded).toBe(false);
+ });
+
+ it('updates "collapsed_gutter" cookie value', () => {
+ wrapper.vm.handleToggleSidebarClick();
+
+ expect(Cookies.set).toHaveBeenCalledWith('collapsed_gutter', true);
+ });
+
+ it('calls `updatePageContainerClass` method', () => {
+ jest.spyOn(wrapper.vm, 'updatePageContainerClass');
+
+ wrapper.vm.handleWindowResize();
+
+ expect(wrapper.vm.updatePageContainerClass).toHaveBeenCalled();
+ });
+ });
+ });
+
+ describe('template', () => {
+ describe('sidebar expanded', () => {
+ beforeEach(async () => {
+ wrapper.setData({
+ isExpanded: true,
+ });
+
+ await wrapper.vm.$nextTick();
+ });
+
+ it('renders component container element with class `right-sidebar-expanded` when `isExpanded` prop is true', () => {
+ expect(wrapper.classes()).toContain('right-sidebar-expanded');
+ });
+
+ it('renders sidebar toggle button with text and icon', () => {
+ const buttonEl = wrapper.find('button');
+
+ expect(buttonEl.exists()).toBe(true);
+ expect(buttonEl.attributes('title')).toBe('Toggle sidebar');
+ expect(buttonEl.find('span').text()).toBe('Collapse sidebar');
+ expect(buttonEl.find('[data-testid="icon-collapse"]').isVisible()).toBe(true);
+ });
+ });
+
+ describe('sidebar collapsed', () => {
+ beforeEach(async () => {
+ wrapper.setData({
+ isExpanded: false,
+ });
+
+ await wrapper.vm.$nextTick();
+ });
+
+ it('renders component container element with class `right-sidebar-collapsed` when `isExpanded` prop is false', () => {
+ expect(wrapper.classes()).toContain('right-sidebar-collapsed');
+ });
+
+ it('renders sidebar toggle button with text and icon', () => {
+ const buttonEl = wrapper.find('button');
+
+ expect(buttonEl.exists()).toBe(true);
+ expect(buttonEl.attributes('title')).toBe('Toggle sidebar');
+ expect(buttonEl.find('[data-testid="icon-expand"]').isVisible()).toBe(true);
+ });
+ });
+
+ it('renders sidebar items', () => {
+ const sidebarItemsEl = wrapper.find('[data-testid="sidebar-items"]');
+
+ expect(sidebarItemsEl.exists()).toBe(true);
+ expect(sidebarItemsEl.find('button.js-todo').exists()).toBe(true);
+ });
+ });
+});
diff --git a/spec/frontend/issue_show/components/incidents/highlight_bar_spec.js b/spec/frontend/issue_show/components/incidents/highlight_bar_spec.js
index 8d50df5e406..c1ab4433761 100644
--- a/spec/frontend/issue_show/components/incidents/highlight_bar_spec.js
+++ b/spec/frontend/issue_show/components/incidents/highlight_bar_spec.js
@@ -1,4 +1,5 @@
import { shallowMount } from '@vue/test-utils';
+import merge from 'lodash/merge';
import { GlLink } from '@gitlab/ui';
import HighlightBar from '~/issue_show/components/incidents/highlight_bar.vue';
import { formatDate } from '~/lib/utils/datetime_utility';
@@ -9,18 +10,24 @@ describe('Highlight Bar', () => {
let wrapper;
const alert = {
+ iid: 1,
startedAt: '2020-05-29T10:39:22Z',
detailsUrl: 'http://127.0.0.1:3000/root/unique-alerts/-/alert_management/1/details',
eventCount: 1,
title: 'Alert 1',
};
- const mountComponent = () => {
- wrapper = shallowMount(HighlightBar, {
- propsData: {
- alert,
- },
- });
+ const mountComponent = options => {
+ wrapper = shallowMount(
+ HighlightBar,
+ merge(
+ {
+ propsData: { alert },
+ provide: { fullPath: 'test', iid: 1, slaFeatureAvailable: true },
+ },
+ options,
+ ),
+ );
};
beforeEach(() => {
@@ -36,21 +43,52 @@ describe('Highlight Bar', () => {
const findLink = () => wrapper.find(GlLink);
- it('renders a link to the alert page', () => {
- expect(findLink().exists()).toBe(true);
- expect(findLink().attributes('href')).toBe(alert.detailsUrl);
- expect(findLink().text()).toContain(alert.title);
+ describe('empty state', () => {
+ beforeEach(() => {
+ mountComponent({ propsData: { alert: null } });
+ });
+
+ it('renders a empty component', () => {
+ expect(wrapper.isVisible()).toBe(false);
+ });
});
- it('renders formatted start time of the alert', () => {
- const formattedDate = '2020-05-29 UTC';
- formatDate.mockReturnValueOnce(formattedDate);
- mountComponent();
- expect(formatDate).toHaveBeenCalledWith(alert.startedAt, 'yyyy-mm-dd Z');
- expect(wrapper.text()).toContain(formattedDate);
+ describe('alert present', () => {
+ beforeEach(() => {
+ mountComponent();
+ });
+
+ it('renders a link to the alert page', () => {
+ expect(findLink().exists()).toBe(true);
+ expect(findLink().attributes('href')).toBe(alert.detailsUrl);
+ expect(findLink().attributes('title')).toBe(alert.title);
+ expect(findLink().text()).toBe(`#${alert.iid}`);
+ });
+
+ it('renders formatted start time of the alert', () => {
+ const formattedDate = '2020-05-29 UTC';
+ formatDate.mockReturnValueOnce(formattedDate);
+ mountComponent();
+ expect(formatDate).toHaveBeenCalledWith(alert.startedAt, 'yyyy-mm-dd Z');
+ expect(wrapper.text()).toContain(formattedDate);
+ });
+
+ it('renders a number of alert events', () => {
+ expect(wrapper.text()).toContain(alert.eventCount);
+ });
});
- it('renders a number of alert events', () => {
- expect(wrapper.text()).toContain(alert.eventCount);
+ describe('when child data is present', () => {
+ beforeEach(() => {
+ mountComponent({
+ data() {
+ return { hasChildData: true };
+ },
+ });
+ });
+
+ it('renders the highlight bar component', () => {
+ expect(wrapper.isVisible()).toBe(true);
+ });
});
});
diff --git a/spec/frontend/issue_show/components/incidents/incident_tabs_spec.js b/spec/frontend/issue_show/components/incidents/incident_tabs_spec.js
index a51b497cd79..c6200fd69bf 100644
--- a/spec/frontend/issue_show/components/incidents/incident_tabs_spec.js
+++ b/spec/frontend/issue_show/components/incidents/incident_tabs_spec.js
@@ -6,6 +6,8 @@ import { descriptionProps } from '../../mock_data';
import DescriptionComponent from '~/issue_show/components/description.vue';
import HighlightBar from '~/issue_show/components/incidents/highlight_bar.vue';
import AlertDetailsTable from '~/vue_shared/components/alert_details_table.vue';
+import Tracking from '~/tracking';
+import { trackIncidentDetailsViewsOptions } from '~/incidents/constants';
const mockAlert = {
__typename: 'AlertManagementAlert',
@@ -57,7 +59,6 @@ describe('Incident Tabs component', () => {
it('does not show the alert details tab', () => {
expect(findAlertDetailsComponent().exists()).toBe(false);
- expect(findHighlightBarComponent().exists()).toBe(false);
});
});
@@ -79,7 +80,7 @@ describe('Incident Tabs component', () => {
it('renders the alert details table with the correct props', () => {
const alert = { iid: mockAlert.iid };
- expect(findAlertDetailsComponent().props('alert')).toEqual(alert);
+ expect(findAlertDetailsComponent().props('alert')).toMatchObject(alert);
expect(findAlertDetailsComponent().props('loading')).toBe(true);
});
@@ -98,4 +99,16 @@ describe('Incident Tabs component', () => {
expect(findDescriptionComponent().props()).toMatchObject(descriptionProps);
});
});
+
+ describe('Snowplow tracking', () => {
+ beforeEach(() => {
+ jest.spyOn(Tracking, 'event');
+ mountComponent();
+ });
+
+ it('should track incident details views', () => {
+ const { category, action } = trackIncidentDetailsViewsOptions;
+ expect(Tracking.event).toHaveBeenCalledWith(category, action);
+ });
+ });
});
diff --git a/spec/frontend/issue_show/issue_spec.js b/spec/frontend/issue_show/issue_spec.js
index befb670c6cd..c0175e774a2 100644
--- a/spec/frontend/issue_show/issue_spec.js
+++ b/spec/frontend/issue_show/issue_spec.js
@@ -14,12 +14,8 @@ useMockIntersectionObserver();
jest.mock('~/lib/utils/poll');
const setupHTML = initialData => {
- document.body.innerHTML = `
- <div id="js-issuable-app"></div>
- <script id="js-issuable-app-initial-data" type="application/json">
- ${JSON.stringify(initialData)}
- </script>
- `;
+ document.body.innerHTML = `<div id="js-issuable-app"></div>`;
+ document.getElementById('js-issuable-app').dataset.initial = JSON.stringify(initialData);
};
describe('Issue show index', () => {
diff --git a/spec/frontend/jira_import/components/__snapshots__/jira_import_form_spec.js.snap b/spec/frontend/jira_import/components/__snapshots__/jira_import_form_spec.js.snap
index eede5426f42..cd0266068aa 100644
--- a/spec/frontend/jira_import/components/__snapshots__/jira_import_form_spec.js.snap
+++ b/spec/frontend/jira_import/components/__snapshots__/jira_import_form_spec.js.snap
@@ -98,7 +98,7 @@ exports[`JiraImportForm table body shows correct information in each cell 1`] =
</span>
<svg
- class="dropdown-chevron gl-icon s16"
+ class="gl-button-icon dropdown-chevron gl-icon s16"
data-testid="chevron-down-icon"
>
<use
@@ -114,7 +114,7 @@ exports[`JiraImportForm table body shows correct information in each cell 1`] =
<!---->
<div
- class="gl-search-box-by-type gl-m-3"
+ class="gl-search-box-by-type"
>
<svg
class="gl-search-box-by-type-search-icon gl-icon s16"
@@ -209,7 +209,7 @@ exports[`JiraImportForm table body shows correct information in each cell 1`] =
</span>
<svg
- class="dropdown-chevron gl-icon s16"
+ class="gl-button-icon dropdown-chevron gl-icon s16"
data-testid="chevron-down-icon"
>
<use
@@ -225,7 +225,7 @@ exports[`JiraImportForm table body shows correct information in each cell 1`] =
<!---->
<div
- class="gl-search-box-by-type gl-m-3"
+ class="gl-search-box-by-type"
>
<svg
class="gl-search-box-by-type-search-icon gl-icon s16"
diff --git a/spec/frontend/jobs/components/job_container_item_spec.js b/spec/frontend/jobs/components/job_container_item_spec.js
index 9019504d22d..41b399fa32b 100644
--- a/spec/frontend/jobs/components/job_container_item_spec.js
+++ b/spec/frontend/jobs/components/job_container_item_spec.js
@@ -90,7 +90,7 @@ describe('JobContainerItem', () => {
Vue.nextTick()
.then(() => {
- expect(vm.$el.querySelector('.js-job-link').getAttribute('data-original-title')).toEqual(
+ expect(vm.$el.querySelector('.js-job-link').getAttribute('title')).toEqual(
'delayed job - delayed manual action (00:22:17)',
);
})
diff --git a/spec/frontend/jobs/components/log/line_spec.js b/spec/frontend/jobs/components/log/line_spec.js
index c2412a807c3..1a30921fece 100644
--- a/spec/frontend/jobs/components/log/line_spec.js
+++ b/spec/frontend/jobs/components/log/line_spec.js
@@ -2,21 +2,25 @@ import { shallowMount } from '@vue/test-utils';
import Line from '~/jobs/components/log/line.vue';
import LineNumber from '~/jobs/components/log/line_number.vue';
+const httpUrl = 'http://example.com';
+const httpsUrl = 'https://example.com';
+
+const mockProps = ({ text = 'Running with gitlab-runner 12.1.0 (de7731dd)' } = {}) => ({
+ line: {
+ content: [
+ {
+ text,
+ style: 'term-fg-l-green',
+ },
+ ],
+ lineNumber: 0,
+ },
+ path: '/jashkenas/underscore/-/jobs/335',
+});
+
describe('Job Log Line', () => {
let wrapper;
-
- const data = {
- line: {
- content: [
- {
- text: 'Running with gitlab-runner 12.1.0 (de7731dd)',
- style: 'term-fg-l-green',
- },
- ],
- lineNumber: 0,
- },
- path: '/jashkenas/underscore/-/jobs/335',
- };
+ let data;
const createComponent = (props = {}) => {
wrapper = shallowMount(Line, {
@@ -27,6 +31,7 @@ describe('Job Log Line', () => {
};
beforeEach(() => {
+ data = mockProps();
createComponent(data);
});
@@ -45,4 +50,38 @@ describe('Job Log Line', () => {
it('renders the provided style as a class attribute', () => {
expect(wrapper.find('span').classes()).toContain(data.line.content[0].style);
});
+
+ describe('when the line contains a link', () => {
+ const findLink = () => wrapper.find('span a');
+
+ it('renders an http link', () => {
+ createComponent(mockProps({ text: httpUrl }));
+
+ expect(findLink().text()).toBe(httpUrl);
+ expect(findLink().attributes().href).toEqual(httpUrl);
+ });
+
+ it('renders an https link', () => {
+ createComponent(mockProps({ text: httpsUrl }));
+
+ expect(findLink().text()).toBe(httpsUrl);
+ expect(findLink().attributes().href).toEqual(httpsUrl);
+ });
+
+ it('renders a link with rel nofollow and noopener', () => {
+ createComponent(mockProps({ text: httpsUrl }));
+
+ expect(findLink().attributes().rel).toBe('nofollow noopener');
+ });
+
+ test.each`
+ type | text
+ ${'ftp'} | ${'ftp://example.com/file'}
+ ${'email'} | ${'email@example.com'}
+ ${'no scheme'} | ${'example.com/page'}
+ `('does not render a $type link', ({ text }) => {
+ createComponent(mockProps({ text }));
+ expect(findLink().exists()).toBe(false);
+ });
+ });
});
diff --git a/spec/frontend/jobs/store/utils_spec.js b/spec/frontend/jobs/store/utils_spec.js
index 294f88bbc74..e50d304bb08 100644
--- a/spec/frontend/jobs/store/utils_spec.js
+++ b/spec/frontend/jobs/store/utils_spec.js
@@ -35,6 +35,14 @@ describe('Jobs Store Utils', () => {
lines: [],
});
});
+
+ it('pre-closes a section when specified in options', () => {
+ const headerLine = { content: [{ text: 'foo' }], section_options: { collapsed: 'true' } };
+
+ const parsedHeaderLine = parseHeaderLine(headerLine, 2);
+
+ expect(parsedHeaderLine.isClosed).toBe(true);
+ });
});
describe('parseLine', () => {
diff --git a/spec/frontend/labels_issue_sidebar_spec.js b/spec/frontend/labels_issue_sidebar_spec.js
deleted file mode 100644
index f74547c0554..00000000000
--- a/spec/frontend/labels_issue_sidebar_spec.js
+++ /dev/null
@@ -1,98 +0,0 @@
-/* eslint-disable no-new */
-
-import $ from 'jquery';
-import MockAdapter from 'axios-mock-adapter';
-import { shuffle } from 'lodash';
-import axios from '~/lib/utils/axios_utils';
-import IssuableContext from '~/issuable_context';
-import LabelsSelect from '~/labels_select';
-
-import 'select2';
-import '~/api';
-import '~/create_label';
-import '~/users_select';
-
-let saveLabelCount = 0;
-let mock;
-
-function testLabelClicks(labelOrder, done) {
- $('.edit-link')
- .get(0)
- .click();
-
- jest.runOnlyPendingTimers();
-
- setImmediate(() => {
- const labelsInDropdown = $('.dropdown-content a');
-
- expect(labelsInDropdown.length).toBe(10);
-
- const arrayOfLabels = labelsInDropdown.get();
- const randomArrayOfLabels = shuffle(arrayOfLabels);
- randomArrayOfLabels.forEach((label, i) => {
- if (i < saveLabelCount) {
- $(label).click();
- }
- });
-
- $('.edit-link')
- .get(0)
- .click();
-
- setImmediate(() => {
- expect($('.sidebar-collapsed-icon').attr('data-original-title')).toBe(labelOrder);
- done();
- });
- });
-}
-
-describe('Issue dropdown sidebar', () => {
- preloadFixtures('static/issue_sidebar_label.html');
-
- beforeEach(() => {
- loadFixtures('static/issue_sidebar_label.html');
-
- mock = new MockAdapter(axios);
-
- new IssuableContext('{"id":1,"name":"Administrator","username":"root"}');
- new LabelsSelect();
-
- mock.onGet('/root/test/labels.json').reply(() => {
- const labels = Array(10)
- .fill()
- .map((_val, i) => ({
- id: i,
- title: `test ${i}`,
- color: '#5CB85C',
- }));
-
- return [200, labels];
- });
-
- mock.onPut('/root/test/issues/2.json').reply(() => {
- const labels = Array(saveLabelCount)
- .fill()
- .map((_val, i) => ({
- id: i,
- title: `test ${i}`,
- color: '#5CB85C',
- }));
-
- return [200, { labels }];
- });
- });
-
- afterEach(() => {
- mock.restore();
- });
-
- it('changes collapsed tooltip when changing labels when less than 5', done => {
- saveLabelCount = 5;
- testLabelClicks('test 0, test 1, test 2, test 3, test 4', done);
- });
-
- it('changes collapsed tooltip when changing labels when more than 5', done => {
- saveLabelCount = 6;
- testLabelClicks('test 0, test 1, test 2, test 3, test 4, and 1 more', done);
- });
-});
diff --git a/spec/frontend/lib/dompurify_spec.js b/spec/frontend/lib/dompurify_spec.js
new file mode 100644
index 00000000000..ee1971a4931
--- /dev/null
+++ b/spec/frontend/lib/dompurify_spec.js
@@ -0,0 +1,98 @@
+import { sanitize } from '~/lib/dompurify';
+
+// GDK
+const rootGon = {
+ sprite_file_icons: '/assets/icons-123a.svg',
+ sprite_icons: '/assets/icons-456b.svg',
+};
+
+// Production
+const absoluteGon = {
+ sprite_file_icons: `${window.location.protocol}//${window.location.hostname}/assets/icons-123a.svg`,
+ sprite_icons: `${window.location.protocol}//${window.location.hostname}/assets/icons-456b.svg`,
+};
+
+const expectedSanitized = '<svg><use></use></svg>';
+
+const safeUrls = {
+ root: Object.values(rootGon).map(url => `${url}#ellipsis_h`),
+ absolute: Object.values(absoluteGon).map(url => `${url}#ellipsis_h`),
+};
+
+const unsafeUrls = [
+ '/an/evil/url',
+ '../../../evil/url',
+ 'https://evil.url/assets/icons-123a.svg',
+ 'https://evil.url/assets/icons-456b.svg',
+ `https://evil.url/${rootGon.sprite_icons}`,
+ `https://evil.url/${rootGon.sprite_file_icons}`,
+ `https://evil.url/${absoluteGon.sprite_icons}`,
+ `https://evil.url/${absoluteGon.sprite_file_icons}`,
+];
+
+describe('~/lib/dompurify', () => {
+ let originalGon;
+
+ it('uses local configuration when given', () => {
+ // As dompurify uses a "Persistent Configuration", it might
+ // ignore config, this check verifies we respect
+ // https://github.com/cure53/DOMPurify#persistent-configuration
+ expect(sanitize('<br>', { ALLOWED_TAGS: [] })).toBe('');
+ expect(sanitize('<strong></strong>', { ALLOWED_TAGS: [] })).toBe('');
+ });
+
+ describe.each`
+ type | gon
+ ${'root'} | ${rootGon}
+ ${'absolute'} | ${absoluteGon}
+ `('when gon contains $type icon urls', ({ type, gon }) => {
+ beforeAll(() => {
+ originalGon = window.gon;
+ window.gon = gon;
+ });
+
+ afterAll(() => {
+ window.gon = originalGon;
+ });
+
+ it('allows no href attrs', () => {
+ const htmlHref = `<svg><use></use></svg>`;
+ expect(sanitize(htmlHref)).toBe(htmlHref);
+ });
+
+ it.each(safeUrls[type])('allows safe URL %s', url => {
+ const htmlHref = `<svg><use href="${url}"></use></svg>`;
+ expect(sanitize(htmlHref)).toBe(htmlHref);
+
+ const htmlXlink = `<svg><use xlink:href="${url}"></use></svg>`;
+ expect(sanitize(htmlXlink)).toBe(htmlXlink);
+ });
+
+ it.each(unsafeUrls)('sanitizes unsafe URL %s', url => {
+ const htmlHref = `<svg><use href="${url}"></use></svg>`;
+ const htmlXlink = `<svg><use xlink:href="${url}"></use></svg>`;
+
+ expect(sanitize(htmlHref)).toBe(expectedSanitized);
+ expect(sanitize(htmlXlink)).toBe(expectedSanitized);
+ });
+ });
+
+ describe('when gon does not contain icon urls', () => {
+ beforeAll(() => {
+ originalGon = window.gon;
+ window.gon = {};
+ });
+
+ afterAll(() => {
+ window.gon = originalGon;
+ });
+
+ it.each([...safeUrls.root, ...safeUrls.absolute, ...unsafeUrls])('sanitizes URL %s', url => {
+ const htmlHref = `<svg><use href="${url}"></use></svg>`;
+ const htmlXlink = `<svg><use xlink:href="${url}"></use></svg>`;
+
+ expect(sanitize(htmlHref)).toBe(expectedSanitized);
+ expect(sanitize(htmlXlink)).toBe(expectedSanitized);
+ });
+ });
+});
diff --git a/spec/frontend/lib/utils/axios_startup_calls_spec.js b/spec/frontend/lib/utils/axios_startup_calls_spec.js
index e804cae7914..e12bf725560 100644
--- a/spec/frontend/lib/utils/axios_startup_calls_spec.js
+++ b/spec/frontend/lib/utils/axios_startup_calls_spec.js
@@ -111,21 +111,44 @@ describe('setupAxiosStartupCalls', () => {
});
});
- it('removes GitLab Base URL from startup call', async () => {
- const oldGon = window.gon;
- window.gon = { gitlab_url: 'https://example.org/gitlab' };
-
- window.gl.startup_calls = {
- '/startup': {
- fetchCall: mockFetchCall(200),
- },
- };
- setupAxiosStartupCalls(axios);
+ describe('startup call', () => {
+ let oldGon;
+
+ beforeEach(() => {
+ oldGon = window.gon;
+ window.gon = { gitlab_url: 'https://example.org/gitlab' };
+ });
+
+ afterEach(() => {
+ window.gon = oldGon;
+ });
- const { data } = await axios.get('https://example.org/gitlab/startup');
+ it('removes GitLab Base URL from startup call', async () => {
+ window.gl.startup_calls = {
+ '/startup': {
+ fetchCall: mockFetchCall(200),
+ },
+ };
+ setupAxiosStartupCalls(axios);
- expect(data).toEqual(STARTUP_JS_RESPONSE);
+ const { data } = await axios.get('https://example.org/gitlab/startup');
- window.gon = oldGon;
+ expect(data).toEqual(STARTUP_JS_RESPONSE);
+ });
+
+ it('sorts the params in the requested API url', async () => {
+ window.gl.startup_calls = {
+ '/startup?alpha=true&bravo=true': {
+ fetchCall: mockFetchCall(200),
+ },
+ };
+ setupAxiosStartupCalls(axios);
+
+ // Use a full url instead of passing options = { params: { ... } } to axios.get
+ // to ensure the params are listed in the specified order.
+ const { data } = await axios.get('https://example.org/gitlab/startup?bravo=true&alpha=true');
+
+ expect(data).toEqual(STARTUP_JS_RESPONSE);
+ });
});
});
diff --git a/spec/frontend/lib/utils/datetime_utility_spec.js b/spec/frontend/lib/utils/datetime_utility_spec.js
index 5b1fdea058b..b0b0b028761 100644
--- a/spec/frontend/lib/utils/datetime_utility_spec.js
+++ b/spec/frontend/lib/utils/datetime_utility_spec.js
@@ -69,6 +69,34 @@ describe('Date time utils', () => {
});
});
+ describe('formatDateAsMonth', () => {
+ it('should format dash cased date properly', () => {
+ const formattedMonth = datetimeUtility.formatDateAsMonth(new Date('2020-06-28'));
+
+ expect(formattedMonth).toBe('Jun');
+ });
+
+ it('should format return the non-abbreviated month', () => {
+ const formattedMonth = datetimeUtility.formatDateAsMonth(new Date('2020-07-28'), {
+ abbreviated: false,
+ });
+
+ expect(formattedMonth).toBe('July');
+ });
+
+ it('should format date with slashes properly', () => {
+ const formattedMonth = datetimeUtility.formatDateAsMonth(new Date('07/23/2016'));
+
+ expect(formattedMonth).toBe('Jul');
+ });
+
+ it('should format ISO date properly', () => {
+ const formattedMonth = datetimeUtility.formatDateAsMonth('2016-07-23T00:00:00.559Z');
+
+ expect(formattedMonth).toBe('Jul');
+ });
+ });
+
describe('formatDate', () => {
it('should format date properly', () => {
const formattedDate = datetimeUtility.formatDate(new Date('07/23/2016'));
@@ -654,6 +682,20 @@ describe('differenceInSeconds', () => {
});
});
+describe('differenceInMonths', () => {
+ const startDateTime = new Date('2019-07-17T00:00:00.000Z');
+
+ it.each`
+ startDate | endDate | expected
+ ${startDateTime} | ${startDateTime} | ${0}
+ ${startDateTime} | ${new Date('2019-12-17T12:00:00.000Z')} | ${5}
+ ${startDateTime} | ${new Date('2021-02-18T00:00:00.000Z')} | ${19}
+ ${new Date('2021-02-18T00:00:00.000Z')} | ${startDateTime} | ${-19}
+ `('returns $expected for $endDate - $startDate', ({ startDate, endDate, expected }) => {
+ expect(datetimeUtility.differenceInMonths(startDate, endDate)).toBe(expected);
+ });
+});
+
describe('differenceInMilliseconds', () => {
const startDateTime = new Date('2019-07-17T00:00:00.000Z');
@@ -667,3 +709,26 @@ describe('differenceInMilliseconds', () => {
expect(datetimeUtility.differenceInMilliseconds(startDate, endDate)).toBe(expected);
});
});
+
+describe('dateAtFirstDayOfMonth', () => {
+ const date = new Date('2019-07-16T12:00:00.000Z');
+
+ it('returns the date at the first day of the month', () => {
+ const startDate = datetimeUtility.dateAtFirstDayOfMonth(date);
+ const expectedStartDate = new Date('2019-07-01T12:00:00.000Z');
+
+ expect(startDate).toStrictEqual(expectedStartDate);
+ });
+});
+
+describe('datesMatch', () => {
+ const date = new Date('2019-07-17T00:00:00.000Z');
+
+ it.each`
+ date1 | date2 | expected
+ ${date} | ${new Date('2019-07-17T00:00:00.000Z')} | ${true}
+ ${date} | ${new Date('2019-07-17T12:00:00.000Z')} | ${false}
+ `('returns $expected for $date1 matches $date2', ({ date1, date2, expected }) => {
+ expect(datetimeUtility.datesMatch(date1, date2)).toBe(expected);
+ });
+});
diff --git a/spec/frontend/lib/utils/experimentation_spec.js b/spec/frontend/lib/utils/experimentation_spec.js
new file mode 100644
index 00000000000..2c5d2f89297
--- /dev/null
+++ b/spec/frontend/lib/utils/experimentation_spec.js
@@ -0,0 +1,20 @@
+import * as experimentUtils from '~/lib/utils/experimentation';
+
+const TEST_KEY = 'abc';
+
+describe('experiment Utilities', () => {
+ describe('isExperimentEnabled', () => {
+ it.each`
+ experiments | value
+ ${{ [TEST_KEY]: true }} | ${true}
+ ${{ [TEST_KEY]: false }} | ${false}
+ ${{ def: true }} | ${false}
+ ${{}} | ${false}
+ ${null} | ${false}
+ `('returns correct value of $value for experiments=$experiments', ({ experiments, value }) => {
+ window.gon = { experiments };
+
+ expect(experimentUtils.isExperimentEnabled(TEST_KEY)).toEqual(value);
+ });
+ });
+});
diff --git a/spec/frontend/lib/utils/number_utility_spec.js b/spec/frontend/lib/utils/number_utility_spec.js
index 2f8f1092612..f600f2bcd55 100644
--- a/spec/frontend/lib/utils/number_utility_spec.js
+++ b/spec/frontend/lib/utils/number_utility_spec.js
@@ -1,5 +1,6 @@
import {
formatRelevantDigits,
+ bytesToKB,
bytesToKiB,
bytesToMiB,
bytesToGiB,
@@ -54,6 +55,16 @@ describe('Number Utils', () => {
});
});
+ describe('bytesToKB', () => {
+ it.each`
+ input | output
+ ${1000} | ${1}
+ ${1024} | ${1.024}
+ `('returns $output KB for $input bytes', ({ input, output }) => {
+ expect(bytesToKB(input)).toBe(output);
+ });
+ });
+
describe('bytesToKiB', () => {
it('calculates KiB for the given bytes', () => {
expect(bytesToKiB(1024)).toEqual(1);
diff --git a/spec/frontend/lib/utils/text_markdown_spec.js b/spec/frontend/lib/utils/text_markdown_spec.js
index 1aaae80dcdf..43de195c702 100644
--- a/spec/frontend/lib/utils/text_markdown_spec.js
+++ b/spec/frontend/lib/utils/text_markdown_spec.js
@@ -13,6 +13,23 @@ describe('init markdown', () => {
textArea.parentNode.removeChild(textArea);
});
+ describe('insertMarkdownText', () => {
+ it('will not error if selected text is a number', () => {
+ const selected = 2;
+
+ insertMarkdownText({
+ textArea,
+ text: '',
+ tag: '',
+ blockTag: null,
+ selected,
+ wrap: false,
+ });
+
+ expect(textArea.value).toBe(selected.toString());
+ });
+ });
+
describe('textArea', () => {
describe('without selection', () => {
it('inserts the tag on an empty line', () => {
@@ -251,88 +268,10 @@ describe('init markdown', () => {
});
});
- describe('Ace Editor', () => {
- let editor;
-
- beforeEach(() => {
- editor = {
- getSelectionRange: jest.fn().mockReturnValue({
- start: 0,
- end: 0,
- }),
- getValue: jest.fn().mockReturnValue('this is text \n in two lines'),
- insert: jest.fn(),
- navigateLeft: jest.fn(),
- };
- });
-
- it('uses ace editor insert text when editor is passed in', () => {
- insertMarkdownText({
- text: editor.getValue,
- tag: '*',
- blockTag: null,
- selected: '',
- wrap: false,
- editor,
- });
-
- expect(editor.insert).toHaveBeenCalled();
- });
-
- it('adds block tags on line above and below selection', () => {
- const selected = 'this text \n is multiple \n lines';
- const text = `before \n ${selected} \n after`;
-
- insertMarkdownText({
- text,
- tag: '',
- blockTag: '***',
- selected,
- wrap: true,
- editor,
- });
-
- expect(editor.insert).toHaveBeenCalledWith(`***\n${selected}\n***`);
- });
-
- it('uses ace editor to navigate back tag length when nothing is selected', () => {
- insertMarkdownText({
- text: editor.getValue,
- tag: '*',
- blockTag: null,
- selected: '',
- wrap: true,
- editor,
- });
-
- expect(editor.navigateLeft).toHaveBeenCalledWith(1);
- });
-
- it('ace editor does not navigate back when there is selected text', () => {
- insertMarkdownText({
- text: editor.getValue,
- tag: '*',
- blockTag: null,
- selected: 'foobar',
- wrap: true,
- editor,
- });
-
- expect(editor.navigateLeft).not.toHaveBeenCalled();
- });
- });
-
describe('Editor Lite', () => {
let editor;
- let origGon;
beforeEach(() => {
- origGon = window.gon;
- window.gon = {
- features: {
- monacoBlobs: true,
- },
- };
editor = {
getSelection: jest.fn().mockReturnValue({
startLineNumber: 1,
@@ -347,10 +286,6 @@ describe('init markdown', () => {
};
});
- afterEach(() => {
- window.gon = origGon;
- });
-
it('replaces selected text', () => {
insertMarkdownText({
text: editor.getValue,
diff --git a/spec/frontend/lib/utils/url_utility_spec.js b/spec/frontend/lib/utils/url_utility_spec.js
index 869ae274a3f..0f9290e36b5 100644
--- a/spec/frontend/lib/utils/url_utility_spec.js
+++ b/spec/frontend/lib/utils/url_utility_spec.js
@@ -509,6 +509,20 @@ describe('URL utility', () => {
});
});
+ describe('isBlobUrl', () => {
+ it.each`
+ url | valid
+ ${undefined} | ${false}
+ ${'blob:http://gitlab.com/abcd'} | ${true}
+ ${'data:image/png;base64,abcdef'} | ${false}
+ ${'notaurl'} | ${false}
+ ${'../relative_url'} | ${false}
+ ${'<a></a>'} | ${false}
+ `('returns $valid for $url', ({ url, valid }) => {
+ expect(urlUtils.isBlobUrl(url)).toBe(valid);
+ });
+ });
+
describe('relativePathToAbsolute', () => {
it.each`
path | base | result
@@ -664,6 +678,19 @@ describe('URL utility', () => {
});
});
+ describe('cleanLeadingSeparator', () => {
+ it.each`
+ path | expected
+ ${'/foo/bar'} | ${'foo/bar'}
+ ${'foo/bar'} | ${'foo/bar'}
+ ${'//foo/bar'} | ${'foo/bar'}
+ ${'/./foo/bar'} | ${'./foo/bar'}
+ ${''} | ${''}
+ `('$path becomes $expected', ({ path, expected }) => {
+ expect(urlUtils.cleanLeadingSeparator(path)).toBe(expected);
+ });
+ });
+
describe('joinPaths', () => {
it.each`
paths | expected
@@ -688,6 +715,18 @@ describe('URL utility', () => {
});
});
+ describe('stripFinalUrlSegment', () => {
+ it.each`
+ path | expected
+ ${'http://fake.domain/twitter/typeahead-js/-/tags/v0.11.0'} | ${'http://fake.domain/twitter/typeahead-js/-/tags/'}
+ ${'http://fake.domain/bar/cool/-/nested/content'} | ${'http://fake.domain/bar/cool/-/nested/'}
+ ${'http://fake.domain/bar/cool?q="search"'} | ${'http://fake.domain/bar/'}
+ ${'http://fake.domain/bar/cool#link-to-something'} | ${'http://fake.domain/bar/'}
+ `('stripFinalUrlSegment $path => $expected', ({ path, expected }) => {
+ expect(urlUtils.stripFinalUrlSegment(path)).toBe(expected);
+ });
+ });
+
describe('escapeFileUrl', () => {
it('encodes URL excluding the slashes', () => {
expect(urlUtils.escapeFileUrl('/foo-bar/file.md')).toBe('/foo-bar/file.md');
@@ -787,4 +826,36 @@ describe('URL utility', () => {
expect(urlUtils.getHTTPProtocol(url)).toBe(expectation);
});
});
+
+ describe('stripPathTail', () => {
+ it.each`
+ path | expected
+ ${''} | ${''}
+ ${'index.html'} | ${''}
+ ${'/'} | ${'/'}
+ ${'/foo/bar'} | ${'/foo/'}
+ ${'/foo/bar/'} | ${'/foo/bar/'}
+ ${'/foo/bar/index.html'} | ${'/foo/bar/'}
+ `('strips the filename from $path => $expected', ({ path, expected }) => {
+ expect(urlUtils.stripPathTail(path)).toBe(expected);
+ });
+ });
+
+ describe('getURLOrigin', () => {
+ it('when no url passed, returns correct origin from window location', () => {
+ const origin = 'https://foo.bar';
+
+ setWindowLocation({ origin });
+ expect(urlUtils.getURLOrigin()).toBe(origin);
+ });
+
+ it.each`
+ url | expectation
+ ${'not-a-url'} | ${null}
+ ${'wss://example.com'} | ${'wss://example.com'}
+ ${'https://foo.bar/foo/bar'} | ${'https://foo.bar'}
+ `('returns correct origin for $url', ({ url, expectation }) => {
+ expect(urlUtils.getURLOrigin(url)).toBe(expectation);
+ });
+ });
});
diff --git a/spec/frontend/logs/components/environment_logs_spec.js b/spec/frontend/logs/components/environment_logs_spec.js
index 559ce4f9414..e32deaea993 100644
--- a/spec/frontend/logs/components/environment_logs_spec.js
+++ b/spec/frontend/logs/components/environment_logs_spec.js
@@ -1,4 +1,4 @@
-import { GlSprintf, GlIcon, GlDeprecatedDropdown, GlDeprecatedDropdownItem } from '@gitlab/ui';
+import { GlSprintf, GlDropdown, GlDropdownItem } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import EnvironmentLogs from '~/logs/components/environment_logs.vue';
@@ -121,7 +121,7 @@ describe('EnvironmentLogs', () => {
it('displays UI elements', () => {
initWrapper();
- expect(findEnvironmentsDropdown().is(GlDeprecatedDropdown)).toBe(true);
+ expect(findEnvironmentsDropdown().is(GlDropdown)).toBe(true);
expect(findSimpleFilters().exists()).toBe(true);
expect(findLogControlButtons().exists()).toBe(true);
@@ -164,7 +164,7 @@ describe('EnvironmentLogs', () => {
it('displays a disabled environments dropdown', () => {
expect(findEnvironmentsDropdown().attributes('disabled')).toBe('true');
- expect(findEnvironmentsDropdown().findAll(GlDeprecatedDropdownItem).length).toBe(0);
+ expect(findEnvironmentsDropdown().findAll(GlDropdownItem).length).toBe(0);
});
it('does not update buttons state', () => {
@@ -241,7 +241,7 @@ describe('EnvironmentLogs', () => {
});
it('populates environments dropdown', () => {
- const items = findEnvironmentsDropdown().findAll(GlDeprecatedDropdownItem);
+ const items = findEnvironmentsDropdown().findAll(GlDropdownItem);
expect(findEnvironmentsDropdown().props('text')).toBe(mockEnvName);
expect(items.length).toBe(mockEnvironments.length);
mockEnvironments.forEach((env, i) => {
@@ -251,14 +251,14 @@ describe('EnvironmentLogs', () => {
});
it('dropdown has one environment selected', () => {
- const items = findEnvironmentsDropdown().findAll(GlDeprecatedDropdownItem);
+ const items = findEnvironmentsDropdown().findAll(GlDropdownItem);
mockEnvironments.forEach((env, i) => {
const item = items.at(i);
if (item.text() !== mockEnvName) {
- expect(item.find(GlIcon).classes('invisible')).toBe(true);
+ expect(item.find(GlDropdownItem).attributes('ischecked')).toBeFalsy();
} else {
- expect(item.find(GlIcon).classes('invisible')).toBe(false);
+ expect(item.find(GlDropdownItem).attributes('ischecked')).toBeTruthy();
}
});
});
@@ -286,7 +286,7 @@ describe('EnvironmentLogs', () => {
describe('when user clicks', () => {
it('environment name, trace is refreshed', () => {
- const items = findEnvironmentsDropdown().findAll(GlDeprecatedDropdownItem);
+ const items = findEnvironmentsDropdown().findAll(GlDropdownItem);
const index = 1; // any env
expect(dispatch).not.toHaveBeenCalledWith(`${module}/showEnvironment`, expect.anything());
diff --git a/spec/frontend/logs/components/log_simple_filters_spec.js b/spec/frontend/logs/components/log_simple_filters_spec.js
index 1e30a7df559..b819f0d25a8 100644
--- a/spec/frontend/logs/components/log_simple_filters_spec.js
+++ b/spec/frontend/logs/components/log_simple_filters_spec.js
@@ -1,4 +1,4 @@
-import { GlIcon, GlDeprecatedDropdownItem } from '@gitlab/ui';
+import { GlDropdownItem } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import { createStore } from '~/logs/stores';
import { mockPods, mockPodName } from '../mock_data';
@@ -17,7 +17,7 @@ describe('LogSimpleFilters', () => {
const findPodsNoPodsText = () => wrapper.find({ ref: 'noPodsMsg' });
const findPodsDropdownItems = () =>
findPodsDropdown()
- .findAll(GlDeprecatedDropdownItem)
+ .findAll(GlDropdownItem)
.filter(item => !('disabled' in item.attributes()));
const mockPodsLoading = () => {
@@ -114,9 +114,9 @@ describe('LogSimpleFilters', () => {
mockPods.forEach((pod, i) => {
const item = items.at(i);
if (item.text() !== mockPodName) {
- expect(item.find(GlIcon).classes('invisible')).toBe(true);
+ expect(item.find(GlDropdownItem).attributes('ischecked')).toBeFalsy();
} else {
- expect(item.find(GlIcon).classes('invisible')).toBe(false);
+ expect(item.find(GlDropdownItem).attributes('ischecked')).toBeTruthy();
}
});
});
diff --git a/spec/frontend/merge_request_spec.js b/spec/frontend/merge_request_spec.js
index 16f04d032fd..37509f77f71 100644
--- a/spec/frontend/merge_request_spec.js
+++ b/spec/frontend/merge_request_spec.js
@@ -3,8 +3,6 @@ import MockAdapter from 'axios-mock-adapter';
import { TEST_HOST } from 'spec/test_constants';
import axios from '~/lib/utils/axios_utils';
import MergeRequest from '~/merge_request';
-import CloseReopenReportToggle from '~/close_reopen_report_toggle';
-import IssuablesHelper from '~/helpers/issuables_helper';
describe('MergeRequest', () => {
const test = {};
@@ -112,66 +110,7 @@ describe('MergeRequest', () => {
});
});
- describe('class constructor', () => {
- beforeEach(() => {
- jest.spyOn($, 'ajax').mockImplementation();
- });
-
- it('calls .initCloseReopenReport', () => {
- jest.spyOn(IssuablesHelper, 'initCloseReopenReport').mockImplementation(() => {});
-
- new MergeRequest(); // eslint-disable-line no-new
-
- expect(IssuablesHelper.initCloseReopenReport).toHaveBeenCalled();
- });
-
- it('calls .initDroplab', () => {
- const container = {
- querySelector: jest.fn().mockName('container.querySelector'),
- };
- const dropdownTrigger = {};
- const dropdownList = {};
- const button = {};
-
- jest.spyOn(CloseReopenReportToggle.prototype, 'initDroplab').mockImplementation(() => {});
- jest.spyOn(document, 'querySelector').mockReturnValue(container);
-
- container.querySelector
- .mockReturnValueOnce(dropdownTrigger)
- .mockReturnValueOnce(dropdownList)
- .mockReturnValueOnce(button);
-
- new MergeRequest(); // eslint-disable-line no-new
-
- expect(document.querySelector).toHaveBeenCalledWith('.js-issuable-close-dropdown');
- expect(container.querySelector).toHaveBeenCalledWith('.js-issuable-close-toggle');
- expect(container.querySelector).toHaveBeenCalledWith('.js-issuable-close-menu');
- expect(container.querySelector).toHaveBeenCalledWith('.js-issuable-close-button');
- expect(CloseReopenReportToggle.prototype.initDroplab).toHaveBeenCalled();
- });
- });
-
describe('hideCloseButton', () => {
- describe('merge request of another user', () => {
- beforeEach(() => {
- loadFixtures('merge_requests/merge_request_with_task_list.html');
- test.el = document.querySelector('.js-issuable-actions');
- new MergeRequest(); // eslint-disable-line no-new
- MergeRequest.hideCloseButton();
- });
-
- it('hides the dropdown close item and selects the next item', () => {
- const closeItem = test.el.querySelector('li.close-item');
- const smallCloseItem = test.el.querySelector('.js-close-item');
- const reportItem = test.el.querySelector('li.report-item');
-
- expect(closeItem).toHaveClass('hidden');
- expect(smallCloseItem).toHaveClass('hidden');
- expect(reportItem).toHaveClass('droplab-item-selected');
- expect(reportItem).not.toHaveClass('hidden');
- });
- });
-
describe('merge request of current_user', () => {
beforeEach(() => {
loadFixtures('merge_requests/merge_request_of_current_user.html');
@@ -180,10 +119,8 @@ describe('MergeRequest', () => {
});
it('hides the close button', () => {
- const closeButton = test.el.querySelector('.btn-close');
const smallCloseItem = test.el.querySelector('.js-close-item');
- expect(closeButton).toHaveClass('hidden');
expect(smallCloseItem).toHaveClass('hidden');
});
});
diff --git a/spec/frontend/milestones/stores/actions_spec.js b/spec/frontend/milestones/stores/actions_spec.js
new file mode 100644
index 00000000000..ad73d0e4238
--- /dev/null
+++ b/spec/frontend/milestones/stores/actions_spec.js
@@ -0,0 +1,140 @@
+import testAction from 'helpers/vuex_action_helper';
+import createState from '~/milestones/stores/state';
+import * as actions from '~/milestones/stores/actions';
+import * as types from '~/milestones/stores/mutation_types';
+
+let mockProjectMilestonesReturnValue;
+let mockProjectSearchReturnValue;
+
+jest.mock('~/api', () => ({
+ // `__esModule: true` is required when mocking modules with default exports:
+ // https://jestjs.io/docs/en/jest-object#jestmockmodulename-factory-options
+ __esModule: true,
+ default: {
+ projectMilestones: () => mockProjectMilestonesReturnValue,
+ projectSearch: () => mockProjectSearchReturnValue,
+ },
+}));
+
+describe('Milestone combobox Vuex store actions', () => {
+ let state;
+
+ beforeEach(() => {
+ state = createState();
+ });
+
+ describe('setProjectId', () => {
+ it(`commits ${types.SET_PROJECT_ID} with the new project ID`, () => {
+ const projectId = '4';
+ testAction(actions.setProjectId, projectId, state, [
+ { type: types.SET_PROJECT_ID, payload: projectId },
+ ]);
+ });
+ });
+
+ describe('setSelectedMilestones', () => {
+ it(`commits ${types.SET_SELECTED_MILESTONES} with the new selected milestones name`, () => {
+ const selectedMilestones = ['v1.2.3'];
+ testAction(actions.setSelectedMilestones, selectedMilestones, state, [
+ { type: types.SET_SELECTED_MILESTONES, payload: selectedMilestones },
+ ]);
+ });
+ });
+
+ describe('toggleMilestones', () => {
+ const selectedMilestone = 'v1.2.3';
+ it(`commits ${types.ADD_SELECTED_MILESTONE} with the new selected milestone name`, () => {
+ testAction(actions.toggleMilestones, selectedMilestone, state, [
+ { type: types.ADD_SELECTED_MILESTONE, payload: selectedMilestone },
+ ]);
+ });
+
+ it(`commits ${types.REMOVE_SELECTED_MILESTONE} with the new selected milestone name`, () => {
+ state.selectedMilestones = [selectedMilestone];
+ testAction(actions.toggleMilestones, selectedMilestone, state, [
+ { type: types.REMOVE_SELECTED_MILESTONE, payload: selectedMilestone },
+ ]);
+ });
+ });
+
+ describe('search', () => {
+ it(`commits ${types.SET_QUERY} with the new search query`, () => {
+ const query = 'v1.0';
+ testAction(
+ actions.search,
+ query,
+ state,
+ [{ type: types.SET_QUERY, payload: query }],
+ [{ type: 'searchMilestones' }],
+ );
+ });
+ });
+
+ describe('searchMilestones', () => {
+ describe('when the search is successful', () => {
+ const projectSearchApiResponse = { data: [{ title: 'v1.0' }] };
+
+ beforeEach(() => {
+ mockProjectSearchReturnValue = Promise.resolve(projectSearchApiResponse);
+ });
+
+ it(`commits ${types.REQUEST_START}, ${types.RECEIVE_PROJECT_MILESTONES_SUCCESS} with the response from the API, and ${types.REQUEST_FINISH}`, () => {
+ return testAction(actions.searchMilestones, undefined, state, [
+ { type: types.REQUEST_START },
+ { type: types.RECEIVE_PROJECT_MILESTONES_SUCCESS, payload: projectSearchApiResponse },
+ { type: types.REQUEST_FINISH },
+ ]);
+ });
+ });
+
+ describe('when the search fails', () => {
+ const error = new Error('Something went wrong!');
+
+ beforeEach(() => {
+ mockProjectSearchReturnValue = Promise.reject(error);
+ });
+
+ it(`commits ${types.REQUEST_START}, ${types.RECEIVE_PROJECT_MILESTONES_ERROR} with the error object, and ${types.REQUEST_FINISH}`, () => {
+ return testAction(actions.searchMilestones, undefined, state, [
+ { type: types.REQUEST_START },
+ { type: types.RECEIVE_PROJECT_MILESTONES_ERROR, payload: error },
+ { type: types.REQUEST_FINISH },
+ ]);
+ });
+ });
+ });
+
+ describe('fetchMilestones', () => {
+ describe('when the fetch is successful', () => {
+ const projectMilestonesApiResponse = { data: [{ title: 'v1.0' }] };
+
+ beforeEach(() => {
+ mockProjectMilestonesReturnValue = Promise.resolve(projectMilestonesApiResponse);
+ });
+
+ it(`commits ${types.REQUEST_START}, ${types.RECEIVE_PROJECT_MILESTONES_SUCCESS} with the response from the API, and ${types.REQUEST_FINISH}`, () => {
+ return testAction(actions.fetchMilestones, undefined, state, [
+ { type: types.REQUEST_START },
+ { type: types.RECEIVE_PROJECT_MILESTONES_SUCCESS, payload: projectMilestonesApiResponse },
+ { type: types.REQUEST_FINISH },
+ ]);
+ });
+ });
+
+ describe('when the fetch fails', () => {
+ const error = new Error('Something went wrong!');
+
+ beforeEach(() => {
+ mockProjectMilestonesReturnValue = Promise.reject(error);
+ });
+
+ it(`commits ${types.REQUEST_START}, ${types.RECEIVE_PROJECT_MILESTONES_ERROR} with the error object, and ${types.REQUEST_FINISH}`, () => {
+ return testAction(actions.fetchMilestones, undefined, state, [
+ { type: types.REQUEST_START },
+ { type: types.RECEIVE_PROJECT_MILESTONES_ERROR, payload: error },
+ { type: types.REQUEST_FINISH },
+ ]);
+ });
+ });
+ });
+});
diff --git a/spec/frontend/milestones/stores/getter_spec.js b/spec/frontend/milestones/stores/getter_spec.js
new file mode 100644
index 00000000000..df7c3d28e67
--- /dev/null
+++ b/spec/frontend/milestones/stores/getter_spec.js
@@ -0,0 +1,15 @@
+import * as getters from '~/milestones/stores/getters';
+
+describe('Milestone comboxbox Vuex store getters', () => {
+ describe('isLoading', () => {
+ it.each`
+ requestCount | isLoading
+ ${2} | ${true}
+ ${1} | ${true}
+ ${0} | ${false}
+ ${-1} | ${false}
+ `('returns true when at least one request is in progress', ({ requestCount, isLoading }) => {
+ expect(getters.isLoading({ requestCount })).toBe(isLoading);
+ });
+ });
+});
diff --git a/spec/frontend/milestones/stores/mutations_spec.js b/spec/frontend/milestones/stores/mutations_spec.js
new file mode 100644
index 00000000000..8f8ce3c87ad
--- /dev/null
+++ b/spec/frontend/milestones/stores/mutations_spec.js
@@ -0,0 +1,159 @@
+import createState from '~/milestones/stores/state';
+import mutations from '~/milestones/stores/mutations';
+import * as types from '~/milestones/stores/mutation_types';
+
+describe('Milestones combobox Vuex store mutations', () => {
+ let state;
+
+ beforeEach(() => {
+ state = createState();
+ });
+
+ describe('initial state', () => {
+ it('is created with the correct structure and initial values', () => {
+ expect(state).toEqual({
+ projectId: null,
+ groupId: null,
+ query: '',
+ matches: {
+ projectMilestones: {
+ list: [],
+ totalCount: 0,
+ error: null,
+ },
+ },
+ selectedMilestones: [],
+ requestCount: 0,
+ });
+ });
+ });
+
+ describe(`${types.SET_PROJECT_ID}`, () => {
+ it('updates the project ID', () => {
+ const newProjectId = '4';
+ mutations[types.SET_PROJECT_ID](state, newProjectId);
+
+ expect(state.projectId).toBe(newProjectId);
+ });
+ });
+
+ describe(`${types.SET_SELECTED_MILESTONES}`, () => {
+ it('sets the selected milestones', () => {
+ const selectedMilestones = ['v1.2.3'];
+ mutations[types.SET_SELECTED_MILESTONES](state, selectedMilestones);
+
+ expect(state.selectedMilestones).toEqual(['v1.2.3']);
+ });
+ });
+
+ describe(`${types.ADD_SELECTED_MILESTONESs}`, () => {
+ it('adds the selected milestones', () => {
+ const selectedMilestone = 'v1.2.3';
+ mutations[types.ADD_SELECTED_MILESTONE](state, selectedMilestone);
+
+ expect(state.selectedMilestones).toEqual(['v1.2.3']);
+ });
+ });
+
+ describe(`${types.REMOVE_SELECTED_MILESTONES}`, () => {
+ it('removes the selected milestones', () => {
+ const selectedMilestone = 'v1.2.3';
+
+ mutations[types.SET_SELECTED_MILESTONES](state, [selectedMilestone]);
+ expect(state.selectedMilestones).toEqual(['v1.2.3']);
+
+ mutations[types.REMOVE_SELECTED_MILESTONE](state, selectedMilestone);
+ expect(state.selectedMilestones).toEqual([]);
+ });
+ });
+
+ describe(`${types.SET_QUERY}`, () => {
+ it('updates the search query', () => {
+ const newQuery = 'hello';
+ mutations[types.SET_QUERY](state, newQuery);
+
+ expect(state.query).toBe(newQuery);
+ });
+ });
+
+ describe(`${types.REQUEST_START}`, () => {
+ it('increments requestCount by 1', () => {
+ mutations[types.REQUEST_START](state);
+ expect(state.requestCount).toBe(1);
+
+ mutations[types.REQUEST_START](state);
+ expect(state.requestCount).toBe(2);
+
+ mutations[types.REQUEST_START](state);
+ expect(state.requestCount).toBe(3);
+ });
+ });
+
+ describe(`${types.REQUEST_FINISH}`, () => {
+ it('decrements requestCount by 1', () => {
+ state.requestCount = 3;
+
+ mutations[types.REQUEST_FINISH](state);
+ expect(state.requestCount).toBe(2);
+
+ mutations[types.REQUEST_FINISH](state);
+ expect(state.requestCount).toBe(1);
+
+ mutations[types.REQUEST_FINISH](state);
+ expect(state.requestCount).toBe(0);
+ });
+ });
+
+ describe(`${types.RECEIVE_PROJECT_MILESTONES_SUCCESS}`, () => {
+ it('updates state.matches.projectMilestones based on the provided API response', () => {
+ const response = {
+ data: [
+ {
+ title: 'v0.1',
+ },
+ {
+ title: 'v0.2',
+ },
+ ],
+ headers: {
+ 'x-total': 2,
+ },
+ };
+
+ mutations[types.RECEIVE_PROJECT_MILESTONES_SUCCESS](state, response);
+
+ expect(state.matches.projectMilestones).toEqual({
+ list: [
+ {
+ title: 'v0.1',
+ },
+ {
+ title: 'v0.2',
+ },
+ ],
+ error: null,
+ totalCount: 2,
+ });
+ });
+
+ describe(`${types.RECEIVE_PROJECT_MILESTONES_ERROR}`, () => {
+ it('updates state.matches.projectMilestones to an empty state with the error object', () => {
+ const error = new Error('Something went wrong!');
+
+ state.matches.projectMilestones = {
+ list: [{ title: 'v0.1' }],
+ totalCount: 1,
+ error: null,
+ };
+
+ mutations[types.RECEIVE_PROJECT_MILESTONES_ERROR](state, error);
+
+ expect(state.matches.projectMilestones).toEqual({
+ list: [],
+ totalCount: 0,
+ error,
+ });
+ });
+ });
+ });
+});
diff --git a/spec/frontend/mini_pipeline_graph_dropdown_spec.js b/spec/frontend/mini_pipeline_graph_dropdown_spec.js
index 506290834c8..1ecf01894af 100644
--- a/spec/frontend/mini_pipeline_graph_dropdown_spec.js
+++ b/spec/frontend/mini_pipeline_graph_dropdown_spec.js
@@ -69,7 +69,7 @@ describe('Mini Pipeline Graph Dropdown', () => {
html: `<li>
<a class="mini-pipeline-graph-dropdown-item" href="#">
<span class="ci-status-icon ci-status-icon-failed"></span>
- <span class="ci-build-text">build</span>
+ <span>build</span>
</a>
<a class="ci-action-icon-wrapper js-ci-action-icon" href="#"></a>
</li>`,
diff --git a/spec/frontend/monitoring/components/__snapshots__/dashboard_template_spec.js.snap b/spec/frontend/monitoring/components/__snapshots__/dashboard_template_spec.js.snap
index a28ecac00fd..645aca0b157 100644
--- a/spec/frontend/monitoring/components/__snapshots__/dashboard_template_spec.js.snap
+++ b/spec/frontend/monitoring/components/__snapshots__/dashboard_template_spec.js.snap
@@ -52,7 +52,6 @@ exports[`Dashboard template matches the default snapshot 1`] = `
</gl-dropdown-section-header-stub>
<gl-search-box-by-type-stub
- class="gl-m-3"
clearbuttontitle="Clear"
value=""
/>
diff --git a/spec/frontend/monitoring/components/__snapshots__/group_empty_state_spec.js.snap b/spec/frontend/monitoring/components/__snapshots__/group_empty_state_spec.js.snap
index c30fb572826..9b2aa3a5b5b 100644
--- a/spec/frontend/monitoring/components/__snapshots__/group_empty_state_spec.js.snap
+++ b/spec/frontend/monitoring/components/__snapshots__/group_empty_state_spec.js.snap
@@ -1,79 +1,146 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`GroupEmptyState Renders an empty state for BAD_QUERY 1`] = `
-<gl-empty-state-stub
- compact="true"
- primarybuttonlink="/path/to/settings"
- primarybuttontext="Verify configuration"
- svgpath="/path/to/empty-group-illustration.svg"
- title="Query cannot be processed"
-/>
+exports[`GroupEmptyState given state BAD_QUERY passes the expected props to GlEmptyState 1`] = `
+Object {
+ "compact": true,
+ "description": null,
+ "primaryButtonLink": "/path/to/settings",
+ "primaryButtonText": "Verify configuration",
+ "secondaryButtonLink": null,
+ "secondaryButtonText": null,
+ "svgHeight": null,
+ "svgPath": "/path/to/empty-group-illustration.svg",
+ "title": "Query cannot be processed",
+}
`;
-exports[`GroupEmptyState Renders an empty state for BAD_QUERY 2`] = `"The Prometheus server responded with \\"bad request\\". Please check your queries are correct and are supported in your Prometheus version. <a href=\\"/path/to/docs\\">More information</a>"`;
+exports[`GroupEmptyState given state BAD_QUERY renders the slotted content 1`] = `
+<div>
+ <div>
+ The Prometheus server responded with "bad request". Please check your queries are correct and are supported in your Prometheus version.
+ <a
+ href="/path/to/docs"
+ >
+ More information
+ </a>
+ </div>
+</div>
+`;
-exports[`GroupEmptyState Renders an empty state for CONNECTION_FAILED 1`] = `
-<gl-empty-state-stub
- compact="true"
- description="We couldn't reach the Prometheus server. Either the server no longer exists or the configuration details need updating."
- primarybuttonlink="/path/to/settings"
- primarybuttontext="Verify configuration"
- svgpath="/path/to/empty-group-illustration.svg"
- title="Connection failed"
-/>
+exports[`GroupEmptyState given state CONNECTION_FAILED passes the expected props to GlEmptyState 1`] = `
+Object {
+ "compact": true,
+ "description": "We couldn't reach the Prometheus server. Either the server no longer exists or the configuration details need updating.",
+ "primaryButtonLink": "/path/to/settings",
+ "primaryButtonText": "Verify configuration",
+ "secondaryButtonLink": null,
+ "secondaryButtonText": null,
+ "svgHeight": null,
+ "svgPath": "/path/to/empty-group-illustration.svg",
+ "title": "Connection failed",
+}
`;
-exports[`GroupEmptyState Renders an empty state for CONNECTION_FAILED 2`] = `undefined`;
+exports[`GroupEmptyState given state CONNECTION_FAILED renders the slotted content 1`] = `<div />`;
-exports[`GroupEmptyState Renders an empty state for FOO STATE 1`] = `
-<gl-empty-state-stub
- compact="true"
- description="An error occurred while loading the data. Please try again."
- svgpath="/path/to/empty-group-illustration.svg"
- title="An error has occurred"
-/>
+exports[`GroupEmptyState given state FOO STATE passes the expected props to GlEmptyState 1`] = `
+Object {
+ "compact": true,
+ "description": "An error occurred while loading the data. Please try again.",
+ "primaryButtonLink": null,
+ "primaryButtonText": null,
+ "secondaryButtonLink": null,
+ "secondaryButtonText": null,
+ "svgHeight": null,
+ "svgPath": "/path/to/empty-group-illustration.svg",
+ "title": "An error has occurred",
+}
`;
-exports[`GroupEmptyState Renders an empty state for FOO STATE 2`] = `undefined`;
+exports[`GroupEmptyState given state FOO STATE renders the slotted content 1`] = `<div />`;
-exports[`GroupEmptyState Renders an empty state for LOADING 1`] = `
-<gl-empty-state-stub
- compact="true"
- description="Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
- svgpath="/path/to/empty-group-illustration.svg"
- title="Waiting for performance data"
-/>
+exports[`GroupEmptyState given state LOADING passes the expected props to GlEmptyState 1`] = `
+Object {
+ "compact": true,
+ "description": "Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available.",
+ "primaryButtonLink": null,
+ "primaryButtonText": null,
+ "secondaryButtonLink": null,
+ "secondaryButtonText": null,
+ "svgHeight": null,
+ "svgPath": "/path/to/empty-group-illustration.svg",
+ "title": "Waiting for performance data",
+}
`;
-exports[`GroupEmptyState Renders an empty state for LOADING 2`] = `undefined`;
+exports[`GroupEmptyState given state LOADING renders the slotted content 1`] = `<div />`;
-exports[`GroupEmptyState Renders an empty state for NO_DATA 1`] = `
-<gl-empty-state-stub
- compact="true"
- svgpath="/path/to/empty-group-illustration.svg"
- title="No data to display"
-/>
+exports[`GroupEmptyState given state NO_DATA passes the expected props to GlEmptyState 1`] = `
+Object {
+ "compact": true,
+ "description": null,
+ "primaryButtonLink": null,
+ "primaryButtonText": null,
+ "secondaryButtonLink": null,
+ "secondaryButtonText": null,
+ "svgHeight": null,
+ "svgPath": "/path/to/empty-group-illustration.svg",
+ "title": "No data to display",
+}
`;
-exports[`GroupEmptyState Renders an empty state for NO_DATA 2`] = `"The data source is connected, but there is no data to display. <a href=\\"/path/to/docs\\">More information</a>"`;
+exports[`GroupEmptyState given state NO_DATA renders the slotted content 1`] = `
+<div>
+ <div>
+ The data source is connected, but there is no data to display.
+ <a
+ href="/path/to/docs"
+ >
+ More information
+ </a>
+ </div>
+</div>
+`;
-exports[`GroupEmptyState Renders an empty state for TIMEOUT 1`] = `
-<gl-empty-state-stub
- compact="true"
- svgpath="/path/to/empty-group-illustration.svg"
- title="Connection timed out"
-/>
+exports[`GroupEmptyState given state TIMEOUT passes the expected props to GlEmptyState 1`] = `
+Object {
+ "compact": true,
+ "description": null,
+ "primaryButtonLink": null,
+ "primaryButtonText": null,
+ "secondaryButtonLink": null,
+ "secondaryButtonText": null,
+ "svgHeight": null,
+ "svgPath": "/path/to/empty-group-illustration.svg",
+ "title": "Connection timed out",
+}
`;
-exports[`GroupEmptyState Renders an empty state for TIMEOUT 2`] = `"Charts can't be displayed as the request for data has timed out. <a href=\\"/path/to/docs\\">More information</a>"`;
+exports[`GroupEmptyState given state TIMEOUT renders the slotted content 1`] = `
+<div>
+ <div>
+ Charts can't be displayed as the request for data has timed out.
+ <a
+ href="/path/to/docs"
+ >
+ More information
+ </a>
+ </div>
+</div>
+`;
-exports[`GroupEmptyState Renders an empty state for UNKNOWN_ERROR 1`] = `
-<gl-empty-state-stub
- compact="true"
- description="An error occurred while loading the data. Please try again."
- svgpath="/path/to/empty-group-illustration.svg"
- title="An error has occurred"
-/>
+exports[`GroupEmptyState given state UNKNOWN_ERROR passes the expected props to GlEmptyState 1`] = `
+Object {
+ "compact": true,
+ "description": "An error occurred while loading the data. Please try again.",
+ "primaryButtonLink": null,
+ "primaryButtonText": null,
+ "secondaryButtonLink": null,
+ "secondaryButtonText": null,
+ "svgHeight": null,
+ "svgPath": "/path/to/empty-group-illustration.svg",
+ "title": "An error has occurred",
+}
`;
-exports[`GroupEmptyState Renders an empty state for UNKNOWN_ERROR 2`] = `undefined`;
+exports[`GroupEmptyState given state UNKNOWN_ERROR renders the slotted content 1`] = `<div />`;
diff --git a/spec/frontend/monitoring/components/dashboard_panel_spec.js b/spec/frontend/monitoring/components/dashboard_panel_spec.js
index 8947a6c1570..ee0e1fd3176 100644
--- a/spec/frontend/monitoring/components/dashboard_panel_spec.js
+++ b/spec/frontend/monitoring/components/dashboard_panel_spec.js
@@ -38,8 +38,6 @@ import MonitorStackedColumnChart from '~/monitoring/components/charts/stacked_co
import { createStore, monitoringDashboard } from '~/monitoring/stores';
import { createStore as createEmbedGroupStore } from '~/monitoring/stores/embed_group';
-global.URL.createObjectURL = jest.fn();
-
const mocks = {
$toast: {
show: jest.fn(),
@@ -94,6 +92,8 @@ describe('Dashboard Panel', () => {
state = store.state.monitoringDashboard;
axiosMock = new AxiosMockAdapter(axios);
+
+ jest.spyOn(URL, 'createObjectURL');
});
afterEach(() => {
diff --git a/spec/frontend/monitoring/components/group_empty_state_spec.js b/spec/frontend/monitoring/components/group_empty_state_spec.js
index 90bd6f67196..3b94c4c6806 100644
--- a/spec/frontend/monitoring/components/group_empty_state_spec.js
+++ b/spec/frontend/monitoring/components/group_empty_state_spec.js
@@ -1,7 +1,13 @@
+import { GlEmptyState } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import GroupEmptyState from '~/monitoring/components/group_empty_state.vue';
import { metricStates } from '~/monitoring/constants';
+const MockGlEmptyState = {
+ props: GlEmptyState.props,
+ template: '<div><slot name="description"></slot></div>',
+};
+
function createComponent(props) {
return shallowMount(GroupEmptyState, {
propsData: {
@@ -10,11 +16,20 @@ function createComponent(props) {
settingsPath: '/path/to/settings',
svgPath: '/path/to/empty-group-illustration.svg',
},
+ stubs: {
+ GlEmptyState: MockGlEmptyState,
+ },
});
}
describe('GroupEmptyState', () => {
- const supportedStates = [
+ let wrapper;
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe.each([
metricStates.NO_DATA,
metricStates.TIMEOUT,
metricStates.CONNECTION_FAILED,
@@ -22,13 +37,17 @@ describe('GroupEmptyState', () => {
metricStates.LOADING,
metricStates.UNKNOWN_ERROR,
'FOO STATE', // does not fail with unknown states
- ];
+ ])('given state %s', selectedState => {
+ beforeEach(() => {
+ wrapper = createComponent({ selectedState });
+ });
- it.each(supportedStates)('Renders an empty state for %s', selectedState => {
- const wrapper = createComponent({ selectedState });
+ it('renders the slotted content', () => {
+ expect(wrapper.element).toMatchSnapshot();
+ });
- expect(wrapper.element).toMatchSnapshot();
- // slot is not rendered by the stub, test it separately
- expect(wrapper.vm.currentState.slottedDescription).toMatchSnapshot();
+ it('passes the expected props to GlEmptyState', () => {
+ expect(wrapper.find(MockGlEmptyState).props()).toMatchSnapshot();
+ });
});
});
diff --git a/spec/frontend/monitoring/router_spec.js b/spec/frontend/monitoring/router_spec.js
index 8b97c8ed125..2bf2065b178 100644
--- a/spec/frontend/monitoring/router_spec.js
+++ b/spec/frontend/monitoring/router_spec.js
@@ -105,8 +105,7 @@ describe('Monitoring router', () => {
path | currentDashboard
${'/panel/new'} | ${undefined}
${'/dashboard.yml/panel/new'} | ${'dashboard.yml'}
- ${'/config/prometheus/common_metrics.yml/panel/new'} | ${'config/prometheus/common_metrics.yml'}
- ${'/config%2Fprometheus%2Fcommon_metrics.yml/panel/new'} | ${'config/prometheus/common_metrics.yml'}
+ ${'/config%2Fprometheus%2Fcommon_metrics.yml/panel/new'} | ${'config%2Fprometheus%2Fcommon_metrics.yml'}
`('"$path" renders page with dashboard "$currentDashboard"', ({ path, currentDashboard }) => {
const wrapper = createWrapper(BASE_PATH, path);
diff --git a/spec/frontend/notes/components/discussion_counter_spec.js b/spec/frontend/notes/components/discussion_counter_spec.js
index affd6c1d1d2..d82590c7e9e 100644
--- a/spec/frontend/notes/components/discussion_counter_spec.js
+++ b/spec/frontend/notes/components/discussion_counter_spec.js
@@ -1,6 +1,6 @@
import Vuex from 'vuex';
import { shallowMount, createLocalVue } from '@vue/test-utils';
-import { GlIcon } from '@gitlab/ui';
+import { GlButton } from '@gitlab/ui';
import notesModule from '~/notes/stores/modules';
import DiscussionCounter from '~/notes/components/discussion_counter.vue';
import { noteableDataMock, discussionMock, notesDataMock, userDataMock } from '../mock_data';
@@ -9,6 +9,7 @@ import * as types from '~/notes/stores/mutation_types';
describe('DiscussionCounter component', () => {
let store;
let wrapper;
+ let setExpandDiscussionsFn;
const localVue = createLocalVue();
localVue.use(Vuex);
@@ -16,6 +17,7 @@ describe('DiscussionCounter component', () => {
beforeEach(() => {
window.mrTabs = {};
const { state, getters, mutations, actions } = notesModule();
+ setExpandDiscussionsFn = jest.fn().mockImplementation(actions.setExpandDiscussions);
store = new Vuex.Store({
state: {
@@ -24,7 +26,10 @@ describe('DiscussionCounter component', () => {
},
getters,
mutations,
- actions,
+ actions: {
+ ...actions,
+ setExpandDiscussions: setExpandDiscussionsFn,
+ },
});
store.dispatch('setNoteableData', {
...noteableDataMock,
@@ -84,7 +89,7 @@ describe('DiscussionCounter component', () => {
wrapper = shallowMount(DiscussionCounter, { store, localVue });
expect(wrapper.find(`.is-active`).exists()).toBe(isActive);
- expect(wrapper.findAll('[role="group"').length).toBe(groupLength);
+ expect(wrapper.findAll(GlButton)).toHaveLength(groupLength);
});
});
@@ -103,23 +108,22 @@ describe('DiscussionCounter component', () => {
it('calls button handler when clicked', () => {
updateStoreWithExpanded(true);
- wrapper.setMethods({ handleExpandDiscussions: jest.fn() });
- toggleAllButton.trigger('click');
+ toggleAllButton.vm.$emit('click');
- expect(wrapper.vm.handleExpandDiscussions).toHaveBeenCalledTimes(1);
+ expect(setExpandDiscussionsFn).toHaveBeenCalledTimes(1);
});
it('collapses all discussions if expanded', () => {
updateStoreWithExpanded(true);
expect(wrapper.vm.allExpanded).toBe(true);
- expect(toggleAllButton.find(GlIcon).props().name).toBe('angle-up');
+ expect(toggleAllButton.props('icon')).toBe('angle-up');
- toggleAllButton.trigger('click');
+ toggleAllButton.vm.$emit('click');
return wrapper.vm.$nextTick().then(() => {
expect(wrapper.vm.allExpanded).toBe(false);
- expect(toggleAllButton.find(GlIcon).props().name).toBe('angle-down');
+ expect(toggleAllButton.props('icon')).toBe('angle-down');
});
});
@@ -127,13 +131,13 @@ describe('DiscussionCounter component', () => {
updateStoreWithExpanded(false);
expect(wrapper.vm.allExpanded).toBe(false);
- expect(toggleAllButton.find(GlIcon).props().name).toBe('angle-down');
+ expect(toggleAllButton.props('icon')).toBe('angle-down');
- toggleAllButton.trigger('click');
+ toggleAllButton.vm.$emit('click');
return wrapper.vm.$nextTick().then(() => {
expect(wrapper.vm.allExpanded).toBe(true);
- expect(toggleAllButton.find(GlIcon).props().name).toBe('angle-up');
+ expect(toggleAllButton.props('icon')).toBe('angle-up');
});
});
});
diff --git a/spec/frontend/notes/components/discussion_filter_spec.js b/spec/frontend/notes/components/discussion_filter_spec.js
index 91ff796b9de..9f3655c53b9 100644
--- a/spec/frontend/notes/components/discussion_filter_spec.js
+++ b/spec/frontend/notes/components/discussion_filter_spec.js
@@ -25,6 +25,8 @@ describe('DiscussionFilter component', () => {
const filterDiscussion = jest.fn();
+ const findFilter = filterType => wrapper.find(`.dropdown-item[data-filter-type="${filterType}"]`);
+
const mountComponent = () => {
const discussions = [
{
@@ -74,22 +76,22 @@ describe('DiscussionFilter component', () => {
});
it('renders the all filters', () => {
- expect(wrapper.findAll('.dropdown-menu li').length).toBe(discussionFiltersMock.length);
+ expect(wrapper.findAll('.discussion-filter-container .dropdown-item').length).toBe(
+ discussionFiltersMock.length,
+ );
});
it('renders the default selected item', () => {
expect(
wrapper
- .find('#discussion-filter-dropdown')
+ .find('#discussion-filter-dropdown .dropdown-item')
.text()
.trim(),
).toBe(discussionFiltersMock[0].title);
});
it('updates to the selected item', () => {
- const filterItem = wrapper.find(
- `.dropdown-menu li[data-filter-type="${DISCUSSION_FILTER_TYPES.HISTORY}"] button`,
- );
+ const filterItem = findFilter(DISCUSSION_FILTER_TYPES.ALL);
filterItem.trigger('click');
@@ -97,37 +99,37 @@ describe('DiscussionFilter component', () => {
});
it('only updates when selected filter changes', () => {
- wrapper
- .find(`.dropdown-menu li[data-filter-type="${DISCUSSION_FILTER_TYPES.ALL}"] button`)
- .trigger('click');
+ findFilter(DISCUSSION_FILTER_TYPES.ALL).trigger('click');
expect(filterDiscussion).not.toHaveBeenCalled();
});
+ it('disables timeline view if it was enabled', () => {
+ store.state.isTimelineEnabled = true;
+
+ findFilter(DISCUSSION_FILTER_TYPES.HISTORY).trigger('click');
+
+ expect(wrapper.vm.$store.state.isTimelineEnabled).toBe(false);
+ });
+
it('disables commenting when "Show history only" filter is applied', () => {
- const filterItem = wrapper.find(
- `.dropdown-menu li[data-filter-type="${DISCUSSION_FILTER_TYPES.HISTORY}"] button`,
- );
- filterItem.trigger('click');
+ findFilter(DISCUSSION_FILTER_TYPES.HISTORY).trigger('click');
expect(wrapper.vm.$store.state.commentsDisabled).toBe(true);
});
it('enables commenting when "Show history only" filter is not applied', () => {
- const filterItem = wrapper.find(
- `.dropdown-menu li[data-filter-type="${DISCUSSION_FILTER_TYPES.ALL}"] button`,
- );
- filterItem.trigger('click');
+ findFilter(DISCUSSION_FILTER_TYPES.ALL).trigger('click');
expect(wrapper.vm.$store.state.commentsDisabled).toBe(false);
});
it('renders a dropdown divider for the default filter', () => {
const defaultFilter = wrapper.findAll(
- `.dropdown-menu li[data-filter-type="${DISCUSSION_FILTER_TYPES.ALL}"] > *`,
+ `.discussion-filter-container .dropdown-item-wrapper > *`,
);
- expect(defaultFilter.at(defaultFilter.length - 1).classes('dropdown-divider')).toBe(true);
+ expect(defaultFilter.at(1).classes('gl-new-dropdown-divider')).toBe(true);
});
describe('Merge request tabs', () => {
diff --git a/spec/frontend/notes/components/notes_app_spec.js b/spec/frontend/notes/components/notes_app_spec.js
index c6034639a4a..e905a12919e 100644
--- a/spec/frontend/notes/components/notes_app_spec.js
+++ b/spec/frontend/notes/components/notes_app_spec.js
@@ -174,6 +174,23 @@ describe('note_app', () => {
});
});
+ describe('timeline view', () => {
+ beforeEach(() => {
+ setFixtures('<div class="js-discussions-count"></div>');
+
+ axiosMock.onAny().reply(mockData.getIndividualNoteResponse);
+ store.state.commentsDisabled = false;
+ store.state.isTimelineEnabled = true;
+
+ wrapper = mountComponent();
+ return waitForDiscussionsRequest();
+ });
+
+ it('should not render comments form', () => {
+ expect(wrapper.find('.js-main-target-form').exists()).toBe(false);
+ });
+ });
+
describe('while fetching data', () => {
beforeEach(() => {
setFixtures('<div class="js-discussions-count"></div>');
diff --git a/spec/frontend/notes/components/sort_discussion_spec.js b/spec/frontend/notes/components/sort_discussion_spec.js
index 575f1057db2..739e247735d 100644
--- a/spec/frontend/notes/components/sort_discussion_spec.js
+++ b/spec/frontend/notes/components/sort_discussion_spec.js
@@ -46,7 +46,7 @@ describe('Sort Discussion component', () => {
it('calls setDiscussionSortDirection when update is emitted', () => {
findLocalStorageSync().vm.$emit('input', ASC);
- expect(store.dispatch).toHaveBeenCalledWith('setDiscussionSortDirection', ASC);
+ expect(store.dispatch).toHaveBeenCalledWith('setDiscussionSortDirection', { direction: ASC });
});
});
@@ -55,9 +55,11 @@ describe('Sort Discussion component', () => {
it('calls the right actions', () => {
createComponent();
- wrapper.find('.js-newest-first').trigger('click');
+ wrapper.find('.js-newest-first').vm.$emit('click');
- expect(store.dispatch).toHaveBeenCalledWith('setDiscussionSortDirection', DESC);
+ expect(store.dispatch).toHaveBeenCalledWith('setDiscussionSortDirection', {
+ direction: DESC,
+ });
expect(Tracking.event).toHaveBeenCalledWith(undefined, 'change_discussion_sort_direction', {
property: DESC,
});
@@ -67,7 +69,7 @@ describe('Sort Discussion component', () => {
it('shows the "Oldest First" as the dropdown', () => {
createComponent();
- expect(wrapper.find('.js-dropdown-text').text()).toBe('Oldest first');
+ expect(wrapper.find('.js-dropdown-text').props('text')).toBe('Oldest first');
});
});
@@ -79,21 +81,23 @@ describe('Sort Discussion component', () => {
describe('when the dropdown item is clicked', () => {
it('calls the right actions', () => {
- wrapper.find('.js-oldest-first').trigger('click');
+ wrapper.find('.js-oldest-first').vm.$emit('click');
- expect(store.dispatch).toHaveBeenCalledWith('setDiscussionSortDirection', ASC);
+ expect(store.dispatch).toHaveBeenCalledWith('setDiscussionSortDirection', {
+ direction: ASC,
+ });
expect(Tracking.event).toHaveBeenCalledWith(undefined, 'change_discussion_sort_direction', {
property: ASC,
});
});
- it('applies the active class to the correct button in the dropdown', () => {
- expect(wrapper.find('.js-newest-first').classes()).toContain('is-active');
+ it('sets is-checked to true on the active button in the dropdown', () => {
+ expect(wrapper.find('.js-newest-first').props('isChecked')).toBe(true);
});
});
it('shows the "Newest First" as the dropdown', () => {
- expect(wrapper.find('.js-dropdown-text').text()).toBe('Newest first');
+ expect(wrapper.find('.js-dropdown-text').props('text')).toBe('Newest first');
});
});
});
diff --git a/spec/frontend/notes/components/timeline_toggle_spec.js b/spec/frontend/notes/components/timeline_toggle_spec.js
new file mode 100644
index 00000000000..b8df6fc7996
--- /dev/null
+++ b/spec/frontend/notes/components/timeline_toggle_spec.js
@@ -0,0 +1,117 @@
+import { shallowMount, createLocalVue } from '@vue/test-utils';
+import { GlButton } from '@gitlab/ui';
+import Vuex from 'vuex';
+import TimelineToggle, {
+ timelineEnabledTooltip,
+ timelineDisabledTooltip,
+} from '~/notes/components/timeline_toggle.vue';
+import createStore from '~/notes/stores';
+import { ASC, DESC } from '~/notes/constants';
+import { trackToggleTimelineView } from '~/notes/utils';
+import Tracking from '~/tracking';
+
+const localVue = createLocalVue();
+localVue.use(Vuex);
+
+describe('Timeline toggle', () => {
+ let wrapper;
+ let store;
+ const mockEvent = { currentTarget: { blur: jest.fn() } };
+
+ const createComponent = () => {
+ jest.spyOn(store, 'dispatch').mockImplementation();
+ jest.spyOn(Tracking, 'event').mockImplementation();
+
+ wrapper = shallowMount(TimelineToggle, {
+ localVue,
+ store,
+ });
+ };
+
+ const findGlButton = () => wrapper.find(GlButton);
+
+ beforeEach(() => {
+ store = createStore();
+ createComponent();
+ });
+
+ afterEach(() => {
+ if (wrapper) {
+ wrapper.destroy();
+ wrapper = null;
+ }
+ store.dispatch.mockReset();
+ mockEvent.currentTarget.blur.mockReset();
+ Tracking.event.mockReset();
+ });
+
+ describe('ON state', () => {
+ it('should update timeline flag in the store', () => {
+ store.state.isTimelineEnabled = false;
+ findGlButton().vm.$emit('click', mockEvent);
+ expect(store.dispatch).toHaveBeenCalledWith('setTimelineView', true);
+ });
+
+ it('should set sort direction to DESC if not set', () => {
+ store.state.isTimelineEnabled = true;
+ store.state.sortDirection = ASC;
+ findGlButton().vm.$emit('click', mockEvent);
+ expect(store.dispatch).toHaveBeenCalledWith('setDiscussionSortDirection', {
+ direction: DESC,
+ persist: false,
+ });
+ });
+
+ it('should set correct UI state', async () => {
+ store.state.isTimelineEnabled = true;
+ findGlButton().vm.$emit('click', mockEvent);
+ await wrapper.vm.$nextTick();
+ expect(findGlButton().attributes('title')).toBe(timelineEnabledTooltip);
+ expect(findGlButton().attributes('selected')).toBe('true');
+ expect(mockEvent.currentTarget.blur).toHaveBeenCalled();
+ });
+
+ it('should track Snowplow event', async () => {
+ store.state.isTimelineEnabled = true;
+ await wrapper.vm.$nextTick();
+
+ findGlButton().trigger('click');
+
+ const { category, action, label, property, value } = trackToggleTimelineView(true);
+ expect(Tracking.event).toHaveBeenCalledWith(category, action, { label, property, value });
+ });
+ });
+
+ describe('OFF state', () => {
+ it('should update timeline flag in the store', () => {
+ store.state.isTimelineEnabled = true;
+ findGlButton().vm.$emit('click', mockEvent);
+ expect(store.dispatch).toHaveBeenCalledWith('setTimelineView', false);
+ });
+
+ it('should NOT update sort direction', () => {
+ store.state.isTimelineEnabled = false;
+ findGlButton().vm.$emit('click', mockEvent);
+ expect(store.dispatch).not.toHaveBeenCalledWith();
+ });
+
+ it('should set correct UI state', async () => {
+ store.state.isTimelineEnabled = false;
+ findGlButton().vm.$emit('click', mockEvent);
+ await wrapper.vm.$nextTick();
+ expect(findGlButton().attributes('title')).toBe(timelineDisabledTooltip);
+ expect(findGlButton().attributes('selected')).toBe(undefined);
+ expect(mockEvent.currentTarget.blur).toHaveBeenCalled();
+ });
+
+ it('should track Snowplow event', async () => {
+ store.state.isTimelineEnabled = false;
+ await wrapper.vm.$nextTick();
+
+ findGlButton().trigger('click');
+
+ const { category, action, label, property, value } = trackToggleTimelineView(false);
+ expect(Tracking.event).toHaveBeenCalledWith(category, action, { label, property, value });
+ });
+ });
+});
diff --git a/spec/frontend/notes/stores/actions_spec.js b/spec/frontend/notes/stores/actions_spec.js
index 4681f3aa429..920959f41e7 100644
--- a/spec/frontend/notes/stores/actions_spec.js
+++ b/spec/frontend/notes/stores/actions_spec.js
@@ -1144,9 +1144,14 @@ describe('Actions Notes Store', () => {
it('calls the correct mutation with the correct args', done => {
testAction(
actions.setDiscussionSortDirection,
- notesConstants.DESC,
+ { direction: notesConstants.DESC, persist: false },
{},
- [{ type: mutationTypes.SET_DISCUSSIONS_SORT, payload: notesConstants.DESC }],
+ [
+ {
+ type: mutationTypes.SET_DISCUSSIONS_SORT,
+ payload: { direction: notesConstants.DESC, persist: false },
+ },
+ ],
[],
done,
);
diff --git a/spec/frontend/notes/stores/getters_spec.js b/spec/frontend/notes/stores/getters_spec.js
index a07aa45d812..1a369caee49 100644
--- a/spec/frontend/notes/stores/getters_spec.js
+++ b/spec/frontend/notes/stores/getters_spec.js
@@ -6,6 +6,7 @@ import {
noteableDataMock,
individualNote,
collapseNotesMock,
+ discussionMock,
discussion1,
discussion2,
discussion3,
@@ -65,6 +66,18 @@ describe('Getters Notes Store', () => {
it('should return all discussions in the store', () => {
expect(getters.discussions(state)).toEqual([individualNote]);
});
+
+ it('should transform discussion to individual notes in timeline view', () => {
+ state.discussions = [discussionMock];
+ state.isTimelineEnabled = true;
+
+ expect(getters.discussions(state).length).toEqual(discussionMock.notes.length);
+ getters.discussions(state).forEach(discussion => {
+ expect(discussion.individual_note).toBe(true);
+ expect(discussion.id).toBe(discussion.notes[0].id);
+ expect(discussion.created_at).toBe(discussion.notes[0].created_at);
+ });
+ });
});
describe('resolvedDiscussionsById', () => {
diff --git a/spec/frontend/notes/stores/mutation_spec.js b/spec/frontend/notes/stores/mutation_spec.js
index b953bffc4fe..2618c3a53b8 100644
--- a/spec/frontend/notes/stores/mutation_spec.js
+++ b/spec/frontend/notes/stores/mutation_spec.js
@@ -680,9 +680,10 @@ describe('Notes Store mutations', () => {
});
it('sets sort order', () => {
- mutations.SET_DISCUSSIONS_SORT(state, DESC);
+ mutations.SET_DISCUSSIONS_SORT(state, { direction: DESC, persist: false });
expect(state.discussionSortOrder).toBe(DESC);
+ expect(state.persistSortOrder).toBe(false);
});
});
diff --git a/spec/frontend/packages/details/components/__snapshots__/package_title_spec.js.snap b/spec/frontend/packages/details/components/__snapshots__/package_title_spec.js.snap
index 4d9e0af1545..d317264bdae 100644
--- a/spec/frontend/packages/details/components/__snapshots__/package_title_spec.js.snap
+++ b/spec/frontend/packages/details/components/__snapshots__/package_title_spec.js.snap
@@ -2,151 +2,163 @@
exports[`PackageTitle renders with tags 1`] = `
<div
- class="gl-display-flex gl-justify-content-space-between gl-py-3"
+ class="gl-display-flex gl-flex-direction-column"
data-qa-selector="package_title"
>
<div
- class="gl-flex-direction-column"
+ class="gl-display-flex gl-justify-content-space-between gl-py-3"
>
<div
- class="gl-display-flex"
+ class="gl-flex-direction-column"
>
- <!---->
-
<div
- class="gl-display-flex gl-flex-direction-column"
+ class="gl-display-flex"
>
- <h1
- class="gl-font-size-h1 gl-mt-3 gl-mb-2"
- data-testid="title"
- >
- Test package
- </h1>
+ <!---->
<div
- class="gl-display-flex gl-align-items-center gl-text-gray-500 gl-mt-1"
+ class="gl-display-flex gl-flex-direction-column"
>
- <gl-icon-stub
- class="gl-mr-3"
- name="eye"
- size="16"
- />
+ <h1
+ class="gl-font-size-h1 gl-mt-3 gl-mb-2"
+ data-testid="title"
+ >
+ Test package
+ </h1>
- <gl-sprintf-stub
- message="v%{version} published %{timeAgo}"
- />
+ <div
+ class="gl-display-flex gl-align-items-center gl-text-gray-500 gl-mt-1"
+ >
+ <gl-icon-stub
+ class="gl-mr-3"
+ name="eye"
+ size="16"
+ />
+
+ <gl-sprintf-stub
+ message="v%{version} published %{timeAgo}"
+ />
+ </div>
</div>
</div>
- </div>
-
- <div
- class="gl-display-flex gl-flex-wrap gl-align-items-center gl-mt-3"
- >
- <div
- class="gl-display-flex gl-align-items-center gl-mr-5"
- >
- <metadata-item-stub
- data-testid="package-type"
- icon="package"
- link=""
- size="s"
- text="maven"
- />
- </div>
- <div
- class="gl-display-flex gl-align-items-center gl-mr-5"
- >
- <metadata-item-stub
- data-testid="package-size"
- icon="disk"
- link=""
- size="s"
- text="300 bytes"
- />
- </div>
+
<div
- class="gl-display-flex gl-align-items-center gl-mr-5"
+ class="gl-display-flex gl-flex-wrap gl-align-items-center gl-mt-3"
>
- <package-tags-stub
- hidelabel="true"
- tagdisplaylimit="2"
- tags="[object Object],[object Object],[object Object],[object Object]"
- />
+ <div
+ class="gl-display-flex gl-align-items-center gl-mr-5"
+ >
+ <metadata-item-stub
+ data-testid="package-type"
+ icon="package"
+ link=""
+ size="s"
+ text="maven"
+ />
+ </div>
+ <div
+ class="gl-display-flex gl-align-items-center gl-mr-5"
+ >
+ <metadata-item-stub
+ data-testid="package-size"
+ icon="disk"
+ link=""
+ size="s"
+ text="300 bytes"
+ />
+ </div>
+ <div
+ class="gl-display-flex gl-align-items-center gl-mr-5"
+ >
+ <package-tags-stub
+ hidelabel="true"
+ tagdisplaylimit="2"
+ tags="[object Object],[object Object],[object Object],[object Object]"
+ />
+ </div>
</div>
</div>
+
+ <!---->
</div>
- <!---->
+ <p />
</div>
`;
exports[`PackageTitle renders without tags 1`] = `
<div
- class="gl-display-flex gl-justify-content-space-between gl-py-3"
+ class="gl-display-flex gl-flex-direction-column"
data-qa-selector="package_title"
>
<div
- class="gl-flex-direction-column"
+ class="gl-display-flex gl-justify-content-space-between gl-py-3"
>
<div
- class="gl-display-flex"
+ class="gl-flex-direction-column"
>
- <!---->
-
<div
- class="gl-display-flex gl-flex-direction-column"
+ class="gl-display-flex"
>
- <h1
- class="gl-font-size-h1 gl-mt-3 gl-mb-2"
- data-testid="title"
- >
- Test package
- </h1>
+ <!---->
<div
- class="gl-display-flex gl-align-items-center gl-text-gray-500 gl-mt-1"
+ class="gl-display-flex gl-flex-direction-column"
>
- <gl-icon-stub
- class="gl-mr-3"
- name="eye"
- size="16"
- />
+ <h1
+ class="gl-font-size-h1 gl-mt-3 gl-mb-2"
+ data-testid="title"
+ >
+ Test package
+ </h1>
- <gl-sprintf-stub
- message="v%{version} published %{timeAgo}"
- />
+ <div
+ class="gl-display-flex gl-align-items-center gl-text-gray-500 gl-mt-1"
+ >
+ <gl-icon-stub
+ class="gl-mr-3"
+ name="eye"
+ size="16"
+ />
+
+ <gl-sprintf-stub
+ message="v%{version} published %{timeAgo}"
+ />
+ </div>
</div>
</div>
- </div>
-
- <div
- class="gl-display-flex gl-flex-wrap gl-align-items-center gl-mt-3"
- >
- <div
- class="gl-display-flex gl-align-items-center gl-mr-5"
- >
- <metadata-item-stub
- data-testid="package-type"
- icon="package"
- link=""
- size="s"
- text="maven"
- />
- </div>
+
<div
- class="gl-display-flex gl-align-items-center gl-mr-5"
+ class="gl-display-flex gl-flex-wrap gl-align-items-center gl-mt-3"
>
- <metadata-item-stub
- data-testid="package-size"
- icon="disk"
- link=""
- size="s"
- text="300 bytes"
- />
+ <div
+ class="gl-display-flex gl-align-items-center gl-mr-5"
+ >
+ <metadata-item-stub
+ data-testid="package-type"
+ icon="package"
+ link=""
+ size="s"
+ text="maven"
+ />
+ </div>
+ <div
+ class="gl-display-flex gl-align-items-center gl-mr-5"
+ >
+ <metadata-item-stub
+ data-testid="package-size"
+ icon="disk"
+ link=""
+ size="s"
+ text="300 bytes"
+ />
+ </div>
</div>
</div>
+
+ <!---->
</div>
- <!---->
+ <p />
</div>
`;
diff --git a/spec/frontend/packages/details/components/composer_installation_spec.js b/spec/frontend/packages/details/components/composer_installation_spec.js
index c13981fbb87..b44609e8ae7 100644
--- a/spec/frontend/packages/details/components/composer_installation_spec.js
+++ b/spec/frontend/packages/details/components/composer_installation_spec.js
@@ -12,21 +12,23 @@ localVue.use(Vuex);
describe('ComposerInstallation', () => {
let wrapper;
+ let store;
const composerRegistryIncludeStr = 'foo/registry';
const composerPackageIncludeStr = 'foo/package';
- const store = new Vuex.Store({
- state: {
- packageEntity,
- composerHelpPath,
- },
- getters: {
- composerRegistryInclude: () => composerRegistryIncludeStr,
- composerPackageInclude: () => composerPackageIncludeStr,
- },
- });
+ const createStore = (groupExists = true) => {
+ store = new Vuex.Store({
+ state: { packageEntity, composerHelpPath },
+ getters: {
+ composerRegistryInclude: () => composerRegistryIncludeStr,
+ composerPackageInclude: () => composerPackageIncludeStr,
+ groupExists: () => groupExists,
+ },
+ });
+ };
+ const findRootNode = () => wrapper.find('[data-testid="root-node"]');
const findRegistryInclude = () => wrapper.find('[data-testid="registry-include"]');
const findPackageInclude = () => wrapper.find('[data-testid="package-include"]');
const findHelpText = () => wrapper.find('[data-testid="help-text"]');
@@ -42,15 +44,16 @@ describe('ComposerInstallation', () => {
});
}
- beforeEach(() => {
- createComponent();
- });
-
afterEach(() => {
wrapper.destroy();
});
describe('registry include command', () => {
+ beforeEach(() => {
+ createStore();
+ createComponent();
+ });
+
it('uses code_instructions', () => {
const registryIncludeCommand = findRegistryInclude();
expect(registryIncludeCommand.exists()).toBe(true);
@@ -62,11 +65,16 @@ describe('ComposerInstallation', () => {
});
it('has the correct title', () => {
- expect(findRegistryInclude().props('label')).toBe('composer.json registry include');
+ expect(findRegistryInclude().props('label')).toBe('Add composer registry');
});
});
describe('package include command', () => {
+ beforeEach(() => {
+ createStore();
+ createComponent();
+ });
+
it('uses code_instructions', () => {
const registryIncludeCommand = findPackageInclude();
expect(registryIncludeCommand.exists()).toBe(true);
@@ -78,7 +86,7 @@ describe('ComposerInstallation', () => {
});
it('has the correct title', () => {
- expect(findPackageInclude().props('label')).toBe('composer.json require package include');
+ expect(findPackageInclude().props('label')).toBe('Install package version');
});
it('has the correct help text', () => {
@@ -91,4 +99,20 @@ describe('ComposerInstallation', () => {
});
});
});
+
+ describe('root node', () => {
+ it('is normally rendered', () => {
+ createStore();
+ createComponent();
+
+ expect(findRootNode().exists()).toBe(true);
+ });
+
+ it('is not rendered when the group does not exist', () => {
+ createStore(false);
+ createComponent();
+
+ expect(findRootNode().exists()).toBe(false);
+ });
+ });
});
diff --git a/spec/frontend/packages/details/store/getters_spec.js b/spec/frontend/packages/details/store/getters_spec.js
index 0e95ee4cfd3..b8c2138e7f5 100644
--- a/spec/frontend/packages/details/store/getters_spec.js
+++ b/spec/frontend/packages/details/store/getters_spec.js
@@ -15,6 +15,7 @@ import {
pypiSetupCommand,
composerRegistryInclude,
composerPackageInclude,
+ groupExists,
} from '~/packages/details/store/getters';
import {
conanPackage,
@@ -31,7 +32,6 @@ import {
registryUrl,
pypiSetupCommandStr,
} from '../mock_data';
-import { generateConanRecipe } from '~/packages/details/utils';
import { NpmManager } from '~/packages/details/constants';
describe('Getters PackageDetails Store', () => {
@@ -53,8 +53,7 @@ describe('Getters PackageDetails Store', () => {
};
};
- const recipe = generateConanRecipe(conanPackage);
- const conanInstallationCommandStr = `conan install ${recipe} --remote=gitlab`;
+ const conanInstallationCommandStr = `conan install ${conanPackage.name} --remote=gitlab`;
const conanSetupCommandStr = `conan remote add gitlab ${registryUrl}`;
const mavenCommandStr = generateMavenCommand(packageWithoutBuildInfo.maven_metadatum);
@@ -69,11 +68,12 @@ describe('Getters PackageDetails Store', () => {
const nugetInstallationCommandStr = `nuget install ${nugetPackage.name} -Source "GitLab"`;
const nugetSetupCommandStr = `nuget source Add -Name "GitLab" -Source "${registryUrl}" -UserName <your_username> -Password <your_token>`;
- const pypiPipCommandStr = `pip install ${pypiPackage.name} --index-url ${registryUrl}`;
- const composerRegistryIncludeStr = '{"type":"composer","url":"foo"}';
- const composerPackageIncludeStr = JSON.stringify({
- [packageWithoutBuildInfo.name]: packageWithoutBuildInfo.version,
- });
+ const pypiPipCommandStr = `pip install ${pypiPackage.name} --extra-index-url ${registryUrl}`;
+ const composerRegistryIncludeStr =
+ 'composer config repositories.gitlab.com/123 \'{"type": "composer", "url": "foo"}\'';
+ const composerPackageIncludeStr = `composer req ${[packageWithoutBuildInfo.name]}:${
+ packageWithoutBuildInfo.version
+ }`;
describe('packagePipeline', () => {
it('should return the pipeline info when pipeline exists', () => {
@@ -101,7 +101,7 @@ describe('Getters PackageDetails Store', () => {
${packageWithoutBuildInfo} | ${'Maven'}
${npmPackage} | ${'NPM'}
${nugetPackage} | ${'NuGet'}
- ${pypiPackage} | ${'PyPi'}
+ ${pypiPackage} | ${'PyPI'}
`(`package type`, ({ packageEntity, expectedResult }) => {
beforeEach(() => setupState({ packageEntity }));
@@ -223,7 +223,7 @@ describe('Getters PackageDetails Store', () => {
describe('composer string getters', () => {
it('gets the correct composerRegistryInclude command', () => {
- setupState({ composerPath: 'foo' });
+ setupState({ composerPath: 'foo', composerConfigRepositoryName: 'gitlab.com/123' });
expect(composerRegistryInclude(state)).toBe(composerRegistryIncludeStr);
});
@@ -234,4 +234,18 @@ describe('Getters PackageDetails Store', () => {
expect(composerPackageInclude(state)).toBe(composerPackageIncludeStr);
});
});
+
+ describe('check if group', () => {
+ it('is set', () => {
+ setupState({ groupListUrl: '/groups/composer/-/packages' });
+
+ expect(groupExists(state)).toBe(true);
+ });
+
+ it('is not set', () => {
+ setupState({ groupListUrl: '' });
+
+ expect(groupExists(state)).toBe(false);
+ });
+ });
});
diff --git a/spec/frontend/packages/details/utils_spec.js b/spec/frontend/packages/details/utils_spec.js
deleted file mode 100644
index 087888016ee..00000000000
--- a/spec/frontend/packages/details/utils_spec.js
+++ /dev/null
@@ -1,24 +0,0 @@
-import { generateConanRecipe } from '~/packages/details/utils';
-import { conanPackage } from '../mock_data';
-
-describe('Package detail utils', () => {
- describe('generateConanRecipe', () => {
- it('correctly generates the conan recipe', () => {
- const recipe = generateConanRecipe(conanPackage);
-
- expect(recipe).toEqual(conanPackage.recipe);
- });
-
- it('returns an empty recipe when no information is supplied', () => {
- const recipe = generateConanRecipe({});
-
- expect(recipe).toEqual('/@/');
- });
-
- it('recipe returns empty strings for missing metadata', () => {
- const recipe = generateConanRecipe({ name: 'foo', version: '0.0.1' });
-
- expect(recipe).toBe('foo/0.0.1@/');
- });
- });
-});
diff --git a/spec/frontend/packages/list/coming_soon/helpers_spec.js b/spec/frontend/packages/list/coming_soon/helpers_spec.js
deleted file mode 100644
index 4a996bfad76..00000000000
--- a/spec/frontend/packages/list/coming_soon/helpers_spec.js
+++ /dev/null
@@ -1,36 +0,0 @@
-import * as comingSoon from '~/packages/list/coming_soon/helpers';
-import { fakeIssues, asGraphQLResponse, asViewModel } from './mock_data';
-
-jest.mock('~/api.js');
-
-describe('Coming Soon Helpers', () => {
- const [noLabels, acceptingMergeRequestLabel, workflowLabel] = fakeIssues;
-
- describe('toViewModel', () => {
- it('formats a GraphQL response correctly', () => {
- expect(comingSoon.toViewModel(asGraphQLResponse)).toEqual(asViewModel);
- });
- });
-
- describe('findWorkflowLabel', () => {
- it('finds a workflow label', () => {
- expect(comingSoon.findWorkflowLabel(workflowLabel.labels)).toEqual(workflowLabel.labels[0]);
- });
-
- it("returns undefined when there isn't one", () => {
- expect(comingSoon.findWorkflowLabel(noLabels.labels)).toBeUndefined();
- });
- });
-
- describe('findAcceptingContributionsLabel', () => {
- it('finds the correct label when it exists', () => {
- expect(comingSoon.findAcceptingContributionsLabel(acceptingMergeRequestLabel.labels)).toEqual(
- acceptingMergeRequestLabel.labels[0],
- );
- });
-
- it("returns undefined when there isn't one", () => {
- expect(comingSoon.findAcceptingContributionsLabel(noLabels.labels)).toBeUndefined();
- });
- });
-});
diff --git a/spec/frontend/packages/list/coming_soon/mock_data.js b/spec/frontend/packages/list/coming_soon/mock_data.js
deleted file mode 100644
index bb4568e4bd5..00000000000
--- a/spec/frontend/packages/list/coming_soon/mock_data.js
+++ /dev/null
@@ -1,90 +0,0 @@
-export const fakeIssues = [
- {
- id: 1,
- iid: 1,
- title: 'issue one',
- webUrl: 'foo',
- },
- {
- id: 2,
- iid: 2,
- title: 'issue two',
- labels: [{ title: 'Accepting merge requests', color: '#69d100' }],
- milestone: {
- title: '12.10',
- },
- webUrl: 'foo',
- },
- {
- id: 3,
- iid: 3,
- title: 'issue three',
- labels: [{ title: 'workflow::In dev', color: '#428bca' }],
- webUrl: 'foo',
- },
- {
- id: 4,
- iid: 4,
- title: 'issue four',
- labels: [
- { title: 'Accepting merge requests', color: '#69d100' },
- { title: 'workflow::In dev', color: '#428bca' },
- ],
- webUrl: 'foo',
- },
-];
-
-export const asGraphQLResponse = {
- project: {
- issues: {
- nodes: fakeIssues.map(x => ({
- ...x,
- labels: {
- nodes: x.labels,
- },
- })),
- },
- },
-};
-
-export const asViewModel = [
- {
- ...fakeIssues[0],
- labels: [],
- },
- {
- ...fakeIssues[1],
- labels: [
- {
- title: 'Accepting merge requests',
- color: '#69d100',
- scoped: false,
- },
- ],
- },
- {
- ...fakeIssues[2],
- labels: [
- {
- title: 'workflow::In dev',
- color: '#428bca',
- scoped: true,
- },
- ],
- },
- {
- ...fakeIssues[3],
- labels: [
- {
- title: 'workflow::In dev',
- color: '#428bca',
- scoped: true,
- },
- {
- title: 'Accepting merge requests',
- color: '#69d100',
- scoped: false,
- },
- ],
- },
-];
diff --git a/spec/frontend/packages/list/coming_soon/packages_coming_soon_spec.js b/spec/frontend/packages/list/coming_soon/packages_coming_soon_spec.js
deleted file mode 100644
index c4cdadc45e6..00000000000
--- a/spec/frontend/packages/list/coming_soon/packages_coming_soon_spec.js
+++ /dev/null
@@ -1,138 +0,0 @@
-import { GlEmptyState, GlSkeletonLoader, GlLabel } from '@gitlab/ui';
-import { mount, createLocalVue } from '@vue/test-utils';
-import VueApollo, { ApolloQuery } from 'vue-apollo';
-import ComingSoon from '~/packages/list/coming_soon/packages_coming_soon.vue';
-import { TrackingActions } from '~/packages/shared/constants';
-import { asViewModel } from './mock_data';
-import Tracking from '~/tracking';
-
-jest.mock('~/packages/list/coming_soon/helpers.js');
-
-const localVue = createLocalVue();
-localVue.use(VueApollo);
-
-describe('packages_coming_soon', () => {
- let wrapper;
-
- const findSkeletonLoader = () => wrapper.find(GlSkeletonLoader);
- const findAllIssues = () => wrapper.findAll('[data-testid="issue-row"]');
- const findIssuesData = () =>
- findAllIssues().wrappers.map(x => {
- const titleLink = x.find('[data-testid="issue-title-link"]');
- const milestone = x.find('[data-testid="milestone"]');
- const issueIdLink = x.find('[data-testid="issue-id-link"]');
- const labels = x.findAll(GlLabel);
-
- const issueId = Number(issueIdLink.text().substr(1));
-
- return {
- id: issueId,
- iid: issueId,
- title: titleLink.text(),
- webUrl: titleLink.attributes('href'),
- labels: labels.wrappers.map(label => ({
- color: label.props('backgroundColor'),
- title: label.props('title'),
- scoped: label.props('scoped'),
- })),
- ...(milestone.exists() ? { milestone: { title: milestone.text() } } : {}),
- };
- });
- const findIssueTitleLink = () => wrapper.find('[data-testid="issue-title-link"]');
- const findIssueIdLink = () => wrapper.find('[data-testid="issue-id-link"]');
- const findEmptyState = () => wrapper.find(GlEmptyState);
-
- const mountComponent = (testParams = {}) => {
- const $apolloData = {
- loading: testParams.isLoading || false,
- };
-
- wrapper = mount(ComingSoon, {
- localVue,
- propsData: {
- illustration: 'foo',
- projectPath: 'foo',
- suggestedContributionsPath: 'foo',
- },
- stubs: {
- ApolloQuery,
- GlLink: true,
- },
- mocks: {
- $apolloData,
- },
- });
-
- // Mock the GraphQL query result
- wrapper.find(ApolloQuery).setData({
- result: {
- data: testParams.issues || asViewModel,
- },
- });
- };
-
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
- describe('when loading', () => {
- beforeEach(() => mountComponent({ isLoading: true }));
-
- it('renders the skeleton loader', () => {
- expect(findSkeletonLoader().exists()).toBe(true);
- });
- });
-
- describe('when there are no issues', () => {
- beforeEach(() => mountComponent({ issues: [] }));
-
- it('renders the empty state', () => {
- expect(findEmptyState().exists()).toBe(true);
- });
- });
-
- describe('when there are issues', () => {
- beforeEach(() => mountComponent());
-
- it('renders each issue', () => {
- expect(findIssuesData()).toEqual(asViewModel);
- });
- });
-
- describe('tracking', () => {
- const firstIssue = asViewModel[0];
- let eventSpy;
-
- beforeEach(() => {
- eventSpy = jest.spyOn(Tracking, 'event');
- mountComponent();
- });
-
- it('tracks when mounted', () => {
- expect(eventSpy).toHaveBeenCalledWith(undefined, TrackingActions.COMING_SOON_REQUESTED, {});
- });
-
- it('tracks when an issue title link is clicked', () => {
- eventSpy.mockClear();
-
- findIssueTitleLink().vm.$emit('click');
-
- expect(eventSpy).toHaveBeenCalledWith(undefined, TrackingActions.COMING_SOON_LIST, {
- label: firstIssue.title,
- value: firstIssue.iid,
- });
- });
-
- it('tracks when an issue id link is clicked', () => {
- eventSpy.mockClear();
-
- findIssueIdLink().vm.$emit('click');
-
- expect(eventSpy).toHaveBeenCalledWith(undefined, TrackingActions.COMING_SOON_LIST, {
- label: firstIssue.title,
- value: firstIssue.iid,
- });
- });
- });
-});
diff --git a/spec/frontend/packages/list/components/__snapshots__/packages_list_app_spec.js.snap b/spec/frontend/packages/list/components/__snapshots__/packages_list_app_spec.js.snap
index 6ff9376565a..ce3a58c856d 100644
--- a/spec/frontend/packages/list/components/__snapshots__/packages_list_app_spec.js.snap
+++ b/spec/frontend/packages/list/components/__snapshots__/packages_list_app_spec.js.snap
@@ -1,457 +1,461 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`packages_list_app renders 1`] = `
-<b-tabs-stub
- activenavitemclass="gl-tab-nav-item-active gl-tab-nav-item-active-indigo"
- class="gl-tabs"
- contentclass=",gl-tab-content"
- navclass="gl-tabs-nav"
- nofade="true"
- nonavstyle="true"
- tag="div"
->
- <template>
-
- <b-tab-stub
- tag="div"
- title="All"
- titlelinkclass="gl-tab-nav-item"
- >
- <template>
- <div>
- <section
- class="row empty-state text-center"
- >
- <div
- class="col-12"
+<div>
+ <package-title-stub
+ packagehelpurl="foo"
+ />
+
+ <b-tabs-stub
+ activenavitemclass="gl-tab-nav-item-active gl-tab-nav-item-active-indigo"
+ class="gl-tabs"
+ contentclass=",gl-tab-content"
+ navclass="gl-tabs-nav"
+ nofade="true"
+ nonavstyle="true"
+ tag="div"
+ >
+ <template>
+
+ <b-tab-stub
+ tag="div"
+ title="All"
+ titlelinkclass="gl-tab-nav-item"
+ >
+ <template>
+ <div>
+ <section
+ class="row empty-state text-center"
>
<div
- class="svg-250 svg-content"
+ class="col-12"
>
- <img
- alt="There are no packages yet"
- class="gl-max-w-full"
- src="helpSvg"
- />
+ <div
+ class="svg-250 svg-content"
+ >
+ <img
+ alt="There are no packages yet"
+ class="gl-max-w-full"
+ src="helpSvg"
+ />
+ </div>
</div>
- </div>
-
- <div
- class="col-12"
- >
+
<div
- class="text-content gl-mx-auto gl-my-0 gl-p-5"
+ class="col-12"
>
- <h1
- class="h4"
+ <div
+ class="text-content gl-mx-auto gl-my-0 gl-p-5"
>
- There are no packages yet
- </h1>
-
- <p>
- Learn how to
- <b-link-stub
- class="gl-link"
- event="click"
- href="helpUrl"
- routertag="a"
- target="_blank"
+ <h1
+ class="h4"
>
- publish and share your packages
- </b-link-stub>
- with GitLab.
- </p>
-
- <div>
- <!---->
+ There are no packages yet
+ </h1>
- <!---->
+ <p>
+ Learn how to
+ <b-link-stub
+ class="gl-link"
+ event="click"
+ href="helpUrl"
+ routertag="a"
+ target="_blank"
+ >
+ publish and share your packages
+ </b-link-stub>
+ with GitLab.
+ </p>
+
+ <div>
+ <!---->
+
+ <!---->
+ </div>
</div>
</div>
- </div>
- </section>
- </div>
- </template>
- </b-tab-stub>
- <b-tab-stub
- tag="div"
- title="Composer"
- titlelinkclass="gl-tab-nav-item"
- >
- <template>
- <div>
- <section
- class="row empty-state text-center"
- >
- <div
- class="col-12"
+ </section>
+ </div>
+ </template>
+ </b-tab-stub>
+ <b-tab-stub
+ tag="div"
+ title="Composer"
+ titlelinkclass="gl-tab-nav-item"
+ >
+ <template>
+ <div>
+ <section
+ class="row empty-state text-center"
>
<div
- class="svg-250 svg-content"
+ class="col-12"
>
- <img
- alt="There are no Composer packages yet"
- class="gl-max-w-full"
- src="helpSvg"
- />
+ <div
+ class="svg-250 svg-content"
+ >
+ <img
+ alt="There are no Composer packages yet"
+ class="gl-max-w-full"
+ src="helpSvg"
+ />
+ </div>
</div>
- </div>
-
- <div
- class="col-12"
- >
+
<div
- class="text-content gl-mx-auto gl-my-0 gl-p-5"
+ class="col-12"
>
- <h1
- class="h4"
+ <div
+ class="text-content gl-mx-auto gl-my-0 gl-p-5"
>
- There are no Composer packages yet
- </h1>
-
- <p>
- Learn how to
- <b-link-stub
- class="gl-link"
- event="click"
- href="helpUrl"
- routertag="a"
- target="_blank"
+ <h1
+ class="h4"
>
- publish and share your packages
- </b-link-stub>
- with GitLab.
- </p>
-
- <div>
- <!---->
+ There are no Composer packages yet
+ </h1>
- <!---->
+ <p>
+ Learn how to
+ <b-link-stub
+ class="gl-link"
+ event="click"
+ href="helpUrl"
+ routertag="a"
+ target="_blank"
+ >
+ publish and share your packages
+ </b-link-stub>
+ with GitLab.
+ </p>
+
+ <div>
+ <!---->
+
+ <!---->
+ </div>
</div>
</div>
- </div>
- </section>
- </div>
- </template>
- </b-tab-stub>
- <b-tab-stub
- tag="div"
- title="Conan"
- titlelinkclass="gl-tab-nav-item"
- >
- <template>
- <div>
- <section
- class="row empty-state text-center"
- >
- <div
- class="col-12"
+ </section>
+ </div>
+ </template>
+ </b-tab-stub>
+ <b-tab-stub
+ tag="div"
+ title="Conan"
+ titlelinkclass="gl-tab-nav-item"
+ >
+ <template>
+ <div>
+ <section
+ class="row empty-state text-center"
>
<div
- class="svg-250 svg-content"
+ class="col-12"
>
- <img
- alt="There are no Conan packages yet"
- class="gl-max-w-full"
- src="helpSvg"
- />
+ <div
+ class="svg-250 svg-content"
+ >
+ <img
+ alt="There are no Conan packages yet"
+ class="gl-max-w-full"
+ src="helpSvg"
+ />
+ </div>
</div>
- </div>
-
- <div
- class="col-12"
- >
+
<div
- class="text-content gl-mx-auto gl-my-0 gl-p-5"
+ class="col-12"
>
- <h1
- class="h4"
+ <div
+ class="text-content gl-mx-auto gl-my-0 gl-p-5"
>
- There are no Conan packages yet
- </h1>
-
- <p>
- Learn how to
- <b-link-stub
- class="gl-link"
- event="click"
- href="helpUrl"
- routertag="a"
- target="_blank"
+ <h1
+ class="h4"
>
- publish and share your packages
- </b-link-stub>
- with GitLab.
- </p>
-
- <div>
- <!---->
+ There are no Conan packages yet
+ </h1>
- <!---->
+ <p>
+ Learn how to
+ <b-link-stub
+ class="gl-link"
+ event="click"
+ href="helpUrl"
+ routertag="a"
+ target="_blank"
+ >
+ publish and share your packages
+ </b-link-stub>
+ with GitLab.
+ </p>
+
+ <div>
+ <!---->
+
+ <!---->
+ </div>
</div>
</div>
- </div>
- </section>
- </div>
- </template>
- </b-tab-stub>
- <b-tab-stub
- tag="div"
- title="Maven"
- titlelinkclass="gl-tab-nav-item"
- >
- <template>
- <div>
- <section
- class="row empty-state text-center"
- >
- <div
- class="col-12"
+ </section>
+ </div>
+ </template>
+ </b-tab-stub>
+ <b-tab-stub
+ tag="div"
+ title="Maven"
+ titlelinkclass="gl-tab-nav-item"
+ >
+ <template>
+ <div>
+ <section
+ class="row empty-state text-center"
>
<div
- class="svg-250 svg-content"
+ class="col-12"
>
- <img
- alt="There are no Maven packages yet"
- class="gl-max-w-full"
- src="helpSvg"
- />
+ <div
+ class="svg-250 svg-content"
+ >
+ <img
+ alt="There are no Maven packages yet"
+ class="gl-max-w-full"
+ src="helpSvg"
+ />
+ </div>
</div>
- </div>
-
- <div
- class="col-12"
- >
+
<div
- class="text-content gl-mx-auto gl-my-0 gl-p-5"
+ class="col-12"
>
- <h1
- class="h4"
+ <div
+ class="text-content gl-mx-auto gl-my-0 gl-p-5"
>
- There are no Maven packages yet
- </h1>
-
- <p>
- Learn how to
- <b-link-stub
- class="gl-link"
- event="click"
- href="helpUrl"
- routertag="a"
- target="_blank"
+ <h1
+ class="h4"
>
- publish and share your packages
- </b-link-stub>
- with GitLab.
- </p>
-
- <div>
- <!---->
+ There are no Maven packages yet
+ </h1>
+
+ <p>
+ Learn how to
+ <b-link-stub
+ class="gl-link"
+ event="click"
+ href="helpUrl"
+ routertag="a"
+ target="_blank"
+ >
+ publish and share your packages
+ </b-link-stub>
+ with GitLab.
+ </p>
- <!---->
+ <div>
+ <!---->
+
+ <!---->
+ </div>
</div>
</div>
- </div>
- </section>
- </div>
- </template>
- </b-tab-stub>
- <b-tab-stub
- tag="div"
- title="NPM"
- titlelinkclass="gl-tab-nav-item"
- >
- <template>
- <div>
- <section
- class="row empty-state text-center"
- >
- <div
- class="col-12"
+ </section>
+ </div>
+ </template>
+ </b-tab-stub>
+ <b-tab-stub
+ tag="div"
+ title="NPM"
+ titlelinkclass="gl-tab-nav-item"
+ >
+ <template>
+ <div>
+ <section
+ class="row empty-state text-center"
>
<div
- class="svg-250 svg-content"
+ class="col-12"
>
- <img
- alt="There are no NPM packages yet"
- class="gl-max-w-full"
- src="helpSvg"
- />
+ <div
+ class="svg-250 svg-content"
+ >
+ <img
+ alt="There are no NPM packages yet"
+ class="gl-max-w-full"
+ src="helpSvg"
+ />
+ </div>
</div>
- </div>
-
- <div
- class="col-12"
- >
+
<div
- class="text-content gl-mx-auto gl-my-0 gl-p-5"
+ class="col-12"
>
- <h1
- class="h4"
+ <div
+ class="text-content gl-mx-auto gl-my-0 gl-p-5"
>
- There are no NPM packages yet
- </h1>
-
- <p>
- Learn how to
- <b-link-stub
- class="gl-link"
- event="click"
- href="helpUrl"
- routertag="a"
- target="_blank"
+ <h1
+ class="h4"
>
- publish and share your packages
- </b-link-stub>
- with GitLab.
- </p>
-
- <div>
- <!---->
+ There are no NPM packages yet
+ </h1>
+
+ <p>
+ Learn how to
+ <b-link-stub
+ class="gl-link"
+ event="click"
+ href="helpUrl"
+ routertag="a"
+ target="_blank"
+ >
+ publish and share your packages
+ </b-link-stub>
+ with GitLab.
+ </p>
- <!---->
+ <div>
+ <!---->
+
+ <!---->
+ </div>
</div>
</div>
- </div>
- </section>
- </div>
- </template>
- </b-tab-stub>
- <b-tab-stub
- tag="div"
- title="NuGet"
- titlelinkclass="gl-tab-nav-item"
- >
- <template>
- <div>
- <section
- class="row empty-state text-center"
- >
- <div
- class="col-12"
+ </section>
+ </div>
+ </template>
+ </b-tab-stub>
+ <b-tab-stub
+ tag="div"
+ title="NuGet"
+ titlelinkclass="gl-tab-nav-item"
+ >
+ <template>
+ <div>
+ <section
+ class="row empty-state text-center"
>
<div
- class="svg-250 svg-content"
+ class="col-12"
>
- <img
- alt="There are no NuGet packages yet"
- class="gl-max-w-full"
- src="helpSvg"
- />
+ <div
+ class="svg-250 svg-content"
+ >
+ <img
+ alt="There are no NuGet packages yet"
+ class="gl-max-w-full"
+ src="helpSvg"
+ />
+ </div>
</div>
- </div>
-
- <div
- class="col-12"
- >
+
<div
- class="text-content gl-mx-auto gl-my-0 gl-p-5"
+ class="col-12"
>
- <h1
- class="h4"
+ <div
+ class="text-content gl-mx-auto gl-my-0 gl-p-5"
>
- There are no NuGet packages yet
- </h1>
-
- <p>
- Learn how to
- <b-link-stub
- class="gl-link"
- event="click"
- href="helpUrl"
- routertag="a"
- target="_blank"
+ <h1
+ class="h4"
>
- publish and share your packages
- </b-link-stub>
- with GitLab.
- </p>
-
- <div>
- <!---->
+ There are no NuGet packages yet
+ </h1>
+
+ <p>
+ Learn how to
+ <b-link-stub
+ class="gl-link"
+ event="click"
+ href="helpUrl"
+ routertag="a"
+ target="_blank"
+ >
+ publish and share your packages
+ </b-link-stub>
+ with GitLab.
+ </p>
- <!---->
+ <div>
+ <!---->
+
+ <!---->
+ </div>
</div>
</div>
- </div>
- </section>
- </div>
- </template>
- </b-tab-stub>
- <b-tab-stub
- tag="div"
- title="PyPi"
- titlelinkclass="gl-tab-nav-item"
- >
- <template>
- <div>
- <section
- class="row empty-state text-center"
- >
- <div
- class="col-12"
+ </section>
+ </div>
+ </template>
+ </b-tab-stub>
+ <b-tab-stub
+ tag="div"
+ title="PyPI"
+ titlelinkclass="gl-tab-nav-item"
+ >
+ <template>
+ <div>
+ <section
+ class="row empty-state text-center"
>
<div
- class="svg-250 svg-content"
+ class="col-12"
>
- <img
- alt="There are no PyPi packages yet"
- class="gl-max-w-full"
- src="helpSvg"
- />
+ <div
+ class="svg-250 svg-content"
+ >
+ <img
+ alt="There are no PyPI packages yet"
+ class="gl-max-w-full"
+ src="helpSvg"
+ />
+ </div>
</div>
- </div>
-
- <div
- class="col-12"
- >
+
<div
- class="text-content gl-mx-auto gl-my-0 gl-p-5"
+ class="col-12"
>
- <h1
- class="h4"
+ <div
+ class="text-content gl-mx-auto gl-my-0 gl-p-5"
>
- There are no PyPi packages yet
- </h1>
-
- <p>
- Learn how to
- <b-link-stub
- class="gl-link"
- event="click"
- href="helpUrl"
- routertag="a"
- target="_blank"
+ <h1
+ class="h4"
>
- publish and share your packages
- </b-link-stub>
- with GitLab.
- </p>
-
- <div>
- <!---->
+ There are no PyPI packages yet
+ </h1>
+
+ <p>
+ Learn how to
+ <b-link-stub
+ class="gl-link"
+ event="click"
+ href="helpUrl"
+ routertag="a"
+ target="_blank"
+ >
+ publish and share your packages
+ </b-link-stub>
+ with GitLab.
+ </p>
- <!---->
+ <div>
+ <!---->
+
+ <!---->
+ </div>
</div>
</div>
- </div>
- </section>
- </div>
- </template>
- </b-tab-stub>
-
- <!---->
- </template>
- <template>
- <div
- class="gl-display-flex gl-align-self-center gl-py-2 gl-flex-grow-1 gl-justify-content-end"
- >
- <package-filter-stub
- class="mr-1"
- />
-
- <package-sort-stub />
- </div>
- </template>
-</b-tabs-stub>
+ </section>
+ </div>
+ </template>
+ </b-tab-stub>
+ </template>
+ <template>
+ <div
+ class="gl-display-flex gl-align-self-center gl-py-2 gl-flex-grow-1 gl-justify-content-end"
+ >
+ <package-filter-stub
+ class="gl-mr-2"
+ />
+
+ <package-sort-stub />
+ </div>
+ </template>
+ </b-tabs-stub>
+</div>
`;
diff --git a/spec/frontend/packages/list/components/packages_list_app_spec.js b/spec/frontend/packages/list/components/packages_list_app_spec.js
index 19ff4290f50..217096f822a 100644
--- a/spec/frontend/packages/list/components/packages_list_app_spec.js
+++ b/spec/frontend/packages/list/components/packages_list_app_spec.js
@@ -36,6 +36,7 @@ describe('packages_list_app', () => {
resourceId: 'project_id',
emptyListIllustration: 'helpSvg',
emptyListHelpUrl,
+ packageHelpUrl: 'foo',
},
filterQuery,
},
diff --git a/spec/frontend/packages/list/components/packages_title_spec.js b/spec/frontend/packages/list/components/packages_title_spec.js
new file mode 100644
index 00000000000..5e9ebd8ecb0
--- /dev/null
+++ b/spec/frontend/packages/list/components/packages_title_spec.js
@@ -0,0 +1,71 @@
+import { shallowMount } from '@vue/test-utils';
+import PackageTitle from '~/packages/list/components/package_title.vue';
+import TitleArea from '~/vue_shared/components/registry/title_area.vue';
+import MetadataItem from '~/vue_shared/components/registry/metadata_item.vue';
+import { LIST_INTRO_TEXT, LIST_TITLE_TEXT } from '~/packages/list//constants';
+
+describe('PackageTitle', () => {
+ let wrapper;
+ let store;
+
+ const findTitleArea = () => wrapper.find(TitleArea);
+ const findMetadataItem = () => wrapper.find(MetadataItem);
+
+ const mountComponent = (propsData = { packageHelpUrl: 'foo' }) => {
+ wrapper = shallowMount(PackageTitle, {
+ store,
+ propsData,
+ stubs: {
+ TitleArea,
+ },
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ wrapper = null;
+ });
+
+ describe('title area', () => {
+ it('exists', () => {
+ mountComponent();
+
+ expect(findTitleArea().exists()).toBe(true);
+ });
+
+ it('has the correct props', () => {
+ mountComponent();
+
+ expect(findTitleArea().props()).toMatchObject({
+ title: LIST_TITLE_TEXT,
+ infoMessages: [{ text: LIST_INTRO_TEXT, link: 'foo' }],
+ });
+ });
+ });
+
+ describe.each`
+ packagesCount | exist | text
+ ${null} | ${false} | ${''}
+ ${undefined} | ${false} | ${''}
+ ${0} | ${true} | ${'0 Packages'}
+ ${1} | ${true} | ${'1 Package'}
+ ${2} | ${true} | ${'2 Packages'}
+ `('when packagesCount is $packagesCount metadata item', ({ packagesCount, exist, text }) => {
+ beforeEach(() => {
+ mountComponent({ packagesCount, packageHelpUrl: 'foo' });
+ });
+
+ it(`is ${exist} that it exists`, () => {
+ expect(findMetadataItem().exists()).toBe(exist);
+ });
+
+ if (exist) {
+ it('has the correct props', () => {
+ expect(findMetadataItem().props()).toMatchObject({
+ icon: 'package',
+ text,
+ });
+ });
+ }
+ });
+});
diff --git a/spec/frontend/packages/list/stores/mutations_spec.js b/spec/frontend/packages/list/stores/mutations_spec.js
index 563a3dabbb3..0d424a0c011 100644
--- a/spec/frontend/packages/list/stores/mutations_spec.js
+++ b/spec/frontend/packages/list/stores/mutations_spec.js
@@ -18,7 +18,6 @@ describe('Mutations Registry Store', () => {
userCanDelete: '',
emptyListIllustration: 'foo',
emptyListHelpUrl: 'baz',
- comingSoonJson: '{ "project_path": "gitlab-org/gitlab-test" }',
};
const expectedState = {
diff --git a/spec/frontend/packages/mock_data.js b/spec/frontend/packages/mock_data.js
index b95d06428ff..d7494bf85d0 100644
--- a/spec/frontend/packages/mock_data.js
+++ b/spec/frontend/packages/mock_data.js
@@ -84,15 +84,15 @@ export const conanPackage = {
package_channel: 'stable',
package_username: 'conan+conan-package',
},
+ conan_package_name: 'conan-package',
created_at: '2015-12-10',
id: 3,
- name: 'conan-package',
+ name: 'conan-package/1.0.0@conan+conan-package/stable',
project_path: 'foo/bar/baz',
projectPathName: 'foo/bar/baz',
package_files: [],
package_type: 'conan',
project_id: 1,
- recipe: 'conan-package/1.0.0@conan+conan-package/stable',
updated_at: '2015-12-10',
version: '1.0.0',
_links,
diff --git a/spec/frontend/packages/shared/components/__snapshots__/package_list_row_spec.js.snap b/spec/frontend/packages/shared/components/__snapshots__/package_list_row_spec.js.snap
index 6aaefed92d0..5faae5690db 100644
--- a/spec/frontend/packages/shared/components/__snapshots__/package_list_row_spec.js.snap
+++ b/spec/frontend/packages/shared/components/__snapshots__/package_list_row_spec.js.snap
@@ -52,27 +52,6 @@ exports[`packages_list_row renders 1`] = `
<!---->
<div
- class="gl-display-flex gl-align-items-center"
- >
- <gl-icon-stub
- class="gl-ml-3 gl-mr-2 gl-min-w-0"
- name="review-list"
- size="16"
- />
-
- <gl-link-stub
- class="gl-text-body gl-min-w-0"
- data-testid="packages-row-project"
- href="/foo/bar/baz"
- >
- <gl-truncate-stub
- position="end"
- text="foo/bar/baz"
- />
- </gl-link-stub>
- </div>
-
- <div
class="d-flex align-items-center"
data-testid="package-type"
>
@@ -86,6 +65,10 @@ exports[`packages_list_row renders 1`] = `
Maven
</span>
</div>
+
+ <package-path-stub
+ path="foo/bar/baz"
+ />
</div>
</div>
</div>
@@ -118,6 +101,7 @@ exports[`packages_list_row renders 1`] = `
>
<gl-button-stub
aria-label="Remove package"
+ buttontextclasses=""
category="primary"
data-testid="action-delete"
icon="remove"
diff --git a/spec/frontend/packages/shared/components/__snapshots__/publish_method_spec.js.snap b/spec/frontend/packages/shared/components/__snapshots__/publish_method_spec.js.snap
index 9a0c52cee47..acdf7c49ebd 100644
--- a/spec/frontend/packages/shared/components/__snapshots__/publish_method_spec.js.snap
+++ b/spec/frontend/packages/shared/components/__snapshots__/publish_method_spec.js.snap
@@ -32,7 +32,8 @@ exports[`publish_method renders 1`] = `
</gl-link-stub>
<clipboard-button-stub
- cssclass="gl-border-0 gl-py-0 gl-px-2"
+ category="tertiary"
+ size="small"
text="sha-baz"
title="Copy commit SHA"
tooltipplacement="top"
diff --git a/spec/frontend/packages/shared/components/package_list_row_spec.js b/spec/frontend/packages/shared/components/package_list_row_spec.js
index f4eabf7bb67..0d0ea4e2122 100644
--- a/spec/frontend/packages/shared/components/package_list_row_spec.js
+++ b/spec/frontend/packages/shared/components/package_list_row_spec.js
@@ -1,6 +1,7 @@
import { shallowMount } from '@vue/test-utils';
import PackagesListRow from '~/packages/shared/components/package_list_row.vue';
import PackageTags from '~/packages/shared/components/package_tags.vue';
+import PackagePath from '~/packages/shared/components/package_path.vue';
import ListItem from '~/vue_shared/components/registry/list_item.vue';
import { packageList } from '../../mock_data';
@@ -11,7 +12,7 @@ describe('packages_list_row', () => {
const [packageWithoutTags, packageWithTags] = packageList;
const findPackageTags = () => wrapper.find(PackageTags);
- const findProjectLink = () => wrapper.find('[data-testid="packages-row-project"]');
+ const findPackagePath = () => wrapper.find(PackagePath);
const findDeleteButton = () => wrapper.find('[data-testid="action-delete"]');
const findPackageType = () => wrapper.find('[data-testid="package-type"]');
@@ -63,8 +64,9 @@ describe('packages_list_row', () => {
mountComponent({ isGroup: true });
});
- it('has project field', () => {
- expect(findProjectLink().exists()).toBe(true);
+ it('has a package path component', () => {
+ expect(findPackagePath().exists()).toBe(true);
+ expect(findPackagePath().props()).toMatchObject({ path: 'foo/bar/baz' });
});
});
diff --git a/spec/frontend/packages/shared/components/package_path_spec.js b/spec/frontend/packages/shared/components/package_path_spec.js
new file mode 100644
index 00000000000..40d455ac77c
--- /dev/null
+++ b/spec/frontend/packages/shared/components/package_path_spec.js
@@ -0,0 +1,86 @@
+import { shallowMount } from '@vue/test-utils';
+import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
+import PackagePath from '~/packages/shared/components/package_path.vue';
+
+describe('PackagePath', () => {
+ let wrapper;
+
+ const mountComponent = (propsData = { path: 'foo' }) => {
+ wrapper = shallowMount(PackagePath, {
+ propsData,
+ directives: {
+ GlTooltip: createMockDirective(),
+ },
+ });
+ };
+
+ const BASE_ICON = 'base-icon';
+ const ROOT_LINK = 'root-link';
+ const ROOT_CHEVRON = 'root-chevron';
+ const ELLIPSIS_ICON = 'ellipsis-icon';
+ const ELLIPSIS_CHEVRON = 'ellipsis-chevron';
+ const LEAF_LINK = 'leaf-link';
+
+ const findItem = name => wrapper.find(`[data-testid="${name}"]`);
+ const findTooltip = w => getBinding(w.element, 'gl-tooltip');
+
+ afterEach(() => {
+ wrapper.destroy();
+ wrapper = null;
+ });
+
+ describe.each`
+ path | rootUrl | shouldExist | shouldNotExist
+ ${'foo/bar'} | ${'/foo/bar'} | ${[]} | ${[ROOT_CHEVRON, ELLIPSIS_ICON, ELLIPSIS_CHEVRON, LEAF_LINK]}
+ ${'foo/bar/baz'} | ${'/foo/bar'} | ${[ROOT_CHEVRON, LEAF_LINK]} | ${[ELLIPSIS_ICON, ELLIPSIS_CHEVRON]}
+ ${'foo/bar/baz/baz2'} | ${'/foo/bar'} | ${[ROOT_CHEVRON, LEAF_LINK, ELLIPSIS_ICON, ELLIPSIS_CHEVRON]} | ${[]}
+ ${'foo/bar/baz/baz2/bar2'} | ${'/foo/bar'} | ${[ROOT_CHEVRON, LEAF_LINK, ELLIPSIS_ICON, ELLIPSIS_CHEVRON]} | ${[]}
+ `('given path $path', ({ path, shouldExist, shouldNotExist, rootUrl }) => {
+ const pathPieces = path.split('/').slice(1);
+ const hasTooltip = shouldExist.includes(ELLIPSIS_ICON);
+
+ beforeEach(() => {
+ mountComponent({ path });
+ });
+
+ it('should have a base icon', () => {
+ expect(findItem(BASE_ICON).exists()).toBe(true);
+ });
+
+ it('should have a root link', () => {
+ const root = findItem(ROOT_LINK);
+ expect(root.exists()).toBe(true);
+ expect(root.attributes('href')).toBe(rootUrl);
+ });
+
+ if (hasTooltip) {
+ it('should have a tooltip', () => {
+ const tooltip = findTooltip(findItem(ELLIPSIS_ICON));
+ expect(tooltip).toBeDefined();
+ expect(tooltip.value).toMatchObject({
+ title: path,
+ });
+ });
+ }
+
+ if (shouldExist.length) {
+ it.each(shouldExist)(`should have %s`, element => {
+ expect(findItem(element).exists()).toBe(true);
+ });
+ }
+
+ if (shouldNotExist.length) {
+ it.each(shouldNotExist)(`should not have %s`, element => {
+ expect(findItem(element).exists()).toBe(false);
+ });
+ }
+
+ if (shouldExist.includes(LEAF_LINK)) {
+ it('the last link should be the last piece of the path', () => {
+ const leaf = findItem(LEAF_LINK);
+ expect(leaf.attributes('href')).toBe(`/${path}`);
+ expect(leaf.text()).toBe(pathPieces[pathPieces.length - 1]);
+ });
+ }
+ });
+});
diff --git a/spec/frontend/packages/shared/utils_spec.js b/spec/frontend/packages/shared/utils_spec.js
index 1fe90a4827f..3e4ce8eb323 100644
--- a/spec/frontend/packages/shared/utils_spec.js
+++ b/spec/frontend/packages/shared/utils_spec.js
@@ -37,7 +37,7 @@ describe('Packages shared utils', () => {
${'maven'} | ${'Maven'}
${'npm'} | ${'NPM'}
${'nuget'} | ${'NuGet'}
- ${'pypi'} | ${'PyPi'}
+ ${'pypi'} | ${'PyPI'}
${'composer'} | ${'Composer'}
${'foo'} | ${null}
`(`package type`, ({ packageType, expectedResult }) => {
diff --git a/spec/frontend/pages/admin/users/components/__snapshots__/delete_user_modal_spec.js.snap b/spec/frontend/pages/admin/users/components/__snapshots__/delete_user_modal_spec.js.snap
index 2fbc700d4f5..ddeaa2a79db 100644
--- a/spec/frontend/pages/admin/users/components/__snapshots__/delete_user_modal_spec.js.snap
+++ b/spec/frontend/pages/admin/users/components/__snapshots__/delete_user_modal_spec.js.snap
@@ -39,6 +39,7 @@ exports[`User Operation confirmation modal renders modal with form included 1`]
/>
</form>
<gl-button-stub
+ buttontextclasses=""
category="primary"
icon=""
size="medium"
@@ -48,6 +49,7 @@ exports[`User Operation confirmation modal renders modal with form included 1`]
</gl-button-stub>
<gl-button-stub
+ buttontextclasses=""
category="primary"
disabled="true"
icon=""
@@ -60,6 +62,7 @@ exports[`User Operation confirmation modal renders modal with form included 1`]
</gl-button-stub>
<gl-button-stub
+ buttontextclasses=""
category="primary"
disabled="true"
icon=""
diff --git a/spec/frontend/pages/projects/graphs/__snapshots__/code_coverage_spec.js.snap b/spec/frontend/pages/projects/graphs/__snapshots__/code_coverage_spec.js.snap
index 211f4ea20f5..8ccad7d5c22 100644
--- a/spec/frontend/pages/projects/graphs/__snapshots__/code_coverage_spec.js.snap
+++ b/spec/frontend/pages/projects/graphs/__snapshots__/code_coverage_spec.js.snap
@@ -9,65 +9,54 @@ exports[`Code Coverage when fetching data is successful matches the snapshot 1`]
<!---->
- <gl-deprecated-dropdown-stub
+ <gl-dropdown-stub
+ category="tertiary"
+ headertext=""
+ size="medium"
text="rspec"
+ variant="default"
>
- <gl-deprecated-dropdown-item-stub
+ <gl-dropdown-item-stub
+ avatarurl=""
+ iconcolor=""
+ iconname=""
+ iconrightname=""
+ ischecked="true"
+ ischeckitem="true"
+ secondarytext=""
value="rspec"
>
- <div
- class="gl-display-flex"
- >
- <gl-icon-stub
- class="gl-absolute"
- name="mobile-issue-close"
- size="16"
- />
-
- <span
- class="gl-display-flex align-items-center ml-4"
- >
-
- rspec
-
- </span>
- </div>
- </gl-deprecated-dropdown-item-stub>
- <gl-deprecated-dropdown-item-stub
+
+ rspec
+
+ </gl-dropdown-item-stub>
+ <gl-dropdown-item-stub
+ avatarurl=""
+ iconcolor=""
+ iconname=""
+ iconrightname=""
+ ischeckitem="true"
+ secondarytext=""
value="cypress"
>
- <div
- class="gl-display-flex"
- >
- <!---->
-
- <span
- class="gl-display-flex align-items-center ml-4"
- >
-
- cypress
-
- </span>
- </div>
- </gl-deprecated-dropdown-item-stub>
- <gl-deprecated-dropdown-item-stub
+
+ cypress
+
+ </gl-dropdown-item-stub>
+ <gl-dropdown-item-stub
+ avatarurl=""
+ iconcolor=""
+ iconname=""
+ iconrightname=""
+ ischeckitem="true"
+ secondarytext=""
value="karma"
>
- <div
- class="gl-display-flex"
- >
- <!---->
-
- <span
- class="gl-display-flex align-items-center ml-4"
- >
-
- karma
-
- </span>
- </div>
- </gl-deprecated-dropdown-item-stub>
- </gl-deprecated-dropdown-stub>
+
+ karma
+
+ </gl-dropdown-item-stub>
+ </gl-dropdown-stub>
</div>
<gl-area-chart-stub
diff --git a/spec/frontend/pages/projects/graphs/code_coverage_spec.js b/spec/frontend/pages/projects/graphs/code_coverage_spec.js
index 8884f7815ab..4a60c7fd509 100644
--- a/spec/frontend/pages/projects/graphs/code_coverage_spec.js
+++ b/spec/frontend/pages/projects/graphs/code_coverage_spec.js
@@ -1,6 +1,6 @@
import MockAdapter from 'axios-mock-adapter';
import { shallowMount } from '@vue/test-utils';
-import { GlAlert, GlIcon, GlDeprecatedDropdown, GlDeprecatedDropdownItem } from '@gitlab/ui';
+import { GlAlert, GlDropdown, GlDropdownItem } from '@gitlab/ui';
import { GlAreaChart } from '@gitlab/ui/dist/charts';
import waitForPromises from 'helpers/wait_for_promises';
@@ -17,7 +17,7 @@ describe('Code Coverage', () => {
const findAlert = () => wrapper.find(GlAlert);
const findAreaChart = () => wrapper.find(GlAreaChart);
- const findAllDropdownItems = () => wrapper.findAll(GlDeprecatedDropdownItem);
+ const findAllDropdownItems = () => wrapper.findAll(GlDropdownItem);
const findFirstDropdownItem = () => findAllDropdownItems().at(0);
const findSecondDropdownItem = () => findAllDropdownItems().at(1);
@@ -124,7 +124,7 @@ describe('Code Coverage', () => {
});
it('renders the dropdown with all custom names as options', () => {
- expect(wrapper.find(GlDeprecatedDropdown).exists()).toBeDefined();
+ expect(wrapper.find(GlDropdown).exists()).toBeDefined();
expect(findAllDropdownItems()).toHaveLength(codeCoverageMockData.length);
expect(findFirstDropdownItem().text()).toBe(codeCoverageMockData[0].group_name);
});
@@ -145,16 +145,8 @@ describe('Code Coverage', () => {
await wrapper.vm.$nextTick();
- expect(
- findFirstDropdownItem()
- .find(GlIcon)
- .exists(),
- ).toBe(false);
- expect(
- findSecondDropdownItem()
- .find(GlIcon)
- .exists(),
- ).toBe(true);
+ expect(findFirstDropdownItem().attributes('ischecked')).toBeFalsy();
+ expect(findSecondDropdownItem().attributes('ischecked')).toBeTruthy();
});
it('updates the graph data when selecting a different option in dropdown', async () => {
diff --git a/spec/frontend/pages/projects/pipeline_schedules/shared/components/pipeline_schedule_callout_spec.js b/spec/frontend/pages/projects/pipeline_schedules/shared/components/pipeline_schedule_callout_spec.js
index 5a61f9fca69..5da998d9d2d 100644
--- a/spec/frontend/pages/projects/pipeline_schedules/shared/components/pipeline_schedule_callout_spec.js
+++ b/spec/frontend/pages/projects/pipeline_schedules/shared/components/pipeline_schedule_callout_spec.js
@@ -1,23 +1,18 @@
import Vue from 'vue';
import Cookies from 'js-cookie';
import PipelineSchedulesCallout from '~/pages/projects/pipeline_schedules/shared/components/pipeline_schedules_callout.vue';
-import '~/pages/projects/pipeline_schedules/shared/icons/intro_illustration.svg';
-
-jest.mock(
- '~/pages/projects/pipeline_schedules/shared/icons/intro_illustration.svg',
- () => '<svg></svg>',
-);
const PipelineSchedulesCalloutComponent = Vue.extend(PipelineSchedulesCallout);
const cookieKey = 'pipeline_schedules_callout_dismissed';
const docsUrl = 'help/ci/scheduled_pipelines';
+const imageUrl = 'pages/projects/pipeline_schedules/shared/icons/intro_illustration.svg';
describe('Pipeline Schedule Callout', () => {
let calloutComponent;
beforeEach(() => {
setFixtures(`
- <div id='pipeline-schedules-callout' data-docs-url=${docsUrl}></div>
+ <div id='pipeline-schedules-callout' data-docs-url=${docsUrl} data-image-url=${imageUrl}></div>
`);
});
@@ -30,13 +25,13 @@ describe('Pipeline Schedule Callout', () => {
expect(calloutComponent).toBeDefined();
});
- it('correctly sets illustrationSvg', () => {
- expect(calloutComponent.illustrationSvg).toContain('<svg');
- });
-
it('correctly sets docsUrl', () => {
expect(calloutComponent.docsUrl).toContain(docsUrl);
});
+
+ it('correctly sets imageUrl', () => {
+ expect(calloutComponent.imageUrl).toContain(imageUrl);
+ });
});
describe(`when ${cookieKey} cookie is set`, () => {
@@ -68,8 +63,8 @@ describe('Pipeline Schedule Callout', () => {
expect(calloutComponent.$el.querySelector('.bordered-box')).not.toBeNull();
});
- it('renders the callout svg', () => {
- expect(calloutComponent.$el.outerHTML).toContain('<svg');
+ it('renders the callout img', () => {
+ expect(calloutComponent.$el.outerHTML).toContain('<img');
});
it('renders the callout title', () => {
diff --git a/spec/frontend/performance_bar/index_spec.js b/spec/frontend/performance_bar/index_spec.js
index 1517142c21e..bcd2cbbd530 100644
--- a/spec/frontend/performance_bar/index_spec.js
+++ b/spec/frontend/performance_bar/index_spec.js
@@ -9,7 +9,6 @@ describe('performance bar wrapper', () => {
let vm;
beforeEach(() => {
- URL.createObjectURL = jest.fn();
performance.getEntriesByType = jest.fn().mockReturnValue([]);
// clear html so that elements from previous tests don't mess with this test
diff --git a/spec/frontend/pipeline_new/components/pipeline_new_form_spec.js b/spec/frontend/pipeline_new/components/pipeline_new_form_spec.js
index 97a92778f1a..040c0fbecc5 100644
--- a/spec/frontend/pipeline_new/components/pipeline_new_form_spec.js
+++ b/spec/frontend/pipeline_new/components/pipeline_new_form_spec.js
@@ -2,6 +2,7 @@ import { mount, shallowMount } from '@vue/test-utils';
import { GlDropdown, GlDropdownItem, GlForm, GlSprintf } from '@gitlab/ui';
import MockAdapter from 'axios-mock-adapter';
import waitForPromises from 'helpers/wait_for_promises';
+import httpStatusCodes from '~/lib/utils/http_status';
import axios from '~/lib/utils/axios_utils';
import PipelineNewForm from '~/pipeline_new/components/pipeline_new_form.vue';
import { mockRefs, mockParams, mockPostParams, mockProjectId, mockError } from '../mock_data';
@@ -11,7 +12,8 @@ jest.mock('~/lib/utils/url_utility', () => ({
redirectTo: jest.fn(),
}));
-const pipelinesPath = '/root/project/-/pipleines';
+const pipelinesPath = '/root/project/-/pipelines';
+const configVariablesPath = '/root/project/-/pipelines/config_variables';
const postResponse = { id: 1 };
describe('Pipeline New Form', () => {
@@ -28,6 +30,7 @@ describe('Pipeline New Form', () => {
const findVariableRows = () => wrapper.findAll('[data-testid="ci-variable-row"]');
const findRemoveIcons = () => wrapper.findAll('[data-testid="remove-ci-variable-row"]');
const findKeyInputs = () => wrapper.findAll('[data-testid="pipeline-form-ci-variable-key"]');
+ const findValueInputs = () => wrapper.findAll('[data-testid="pipeline-form-ci-variable-value"]');
const findErrorAlert = () => wrapper.find('[data-testid="run-pipeline-error-alert"]');
const findWarningAlert = () => wrapper.find('[data-testid="run-pipeline-warning-alert"]');
const findWarningAlertSummary = () => findWarningAlert().find(GlSprintf);
@@ -39,6 +42,7 @@ describe('Pipeline New Form', () => {
propsData: {
projectId: mockProjectId,
pipelinesPath,
+ configVariablesPath,
refs: mockRefs,
defaultBranch: 'master',
settingsLink: '',
@@ -55,6 +59,7 @@ describe('Pipeline New Form', () => {
beforeEach(() => {
mock = new MockAdapter(axios);
+ mock.onGet(configVariablesPath).reply(httpStatusCodes.OK, {});
});
afterEach(() => {
@@ -66,7 +71,7 @@ describe('Pipeline New Form', () => {
describe('Dropdown with branches and tags', () => {
beforeEach(() => {
- mock.onPost(pipelinesPath).reply(200, postResponse);
+ mock.onPost(pipelinesPath).reply(httpStatusCodes.OK, postResponse);
});
it('displays dropdown with all branches and tags', () => {
@@ -87,17 +92,27 @@ describe('Pipeline New Form', () => {
});
describe('Form', () => {
- beforeEach(() => {
+ beforeEach(async () => {
createComponent('', mockParams, mount);
- mock.onPost(pipelinesPath).reply(200, postResponse);
+ mock.onPost(pipelinesPath).reply(httpStatusCodes.OK, postResponse);
+
+ await waitForPromises();
});
+
it('displays the correct values for the provided query params', async () => {
expect(findDropdown().props('text')).toBe('tag-1');
+ expect(findVariableRows()).toHaveLength(3);
+ });
- await wrapper.vm.$nextTick();
+ it('displays a variable from provided query params', () => {
+ expect(findKeyInputs().at(0).element.value).toBe('test_var');
+ expect(findValueInputs().at(0).element.value).toBe('test_var_val');
+ });
- expect(findVariableRows()).toHaveLength(3);
+ it('displays an empty variable for the user to fill out', async () => {
+ expect(findKeyInputs().at(2).element.value).toBe('');
+ expect(findValueInputs().at(2).element.value).toBe('');
});
it('does not display remove icon for last row', () => {
@@ -124,13 +139,143 @@ describe('Pipeline New Form', () => {
});
it('creates blank variable on input change event', async () => {
- findKeyInputs()
- .at(2)
- .trigger('change');
+ const input = findKeyInputs().at(2);
+ input.element.value = 'test_var_2';
+ input.trigger('change');
await wrapper.vm.$nextTick();
expect(findVariableRows()).toHaveLength(4);
+ expect(findKeyInputs().at(3).element.value).toBe('');
+ expect(findValueInputs().at(3).element.value).toBe('');
+ });
+
+ describe('when the form has been modified', () => {
+ const selectRef = i =>
+ findDropdownItems()
+ .at(i)
+ .vm.$emit('click');
+
+ beforeEach(async () => {
+ const input = findKeyInputs().at(0);
+ input.element.value = 'test_var_2';
+ input.trigger('change');
+
+ findRemoveIcons()
+ .at(1)
+ .trigger('click');
+
+ await wrapper.vm.$nextTick();
+ });
+
+ it('form values are restored when the ref changes', async () => {
+ expect(findVariableRows()).toHaveLength(2);
+
+ selectRef(1);
+ await waitForPromises();
+
+ expect(findVariableRows()).toHaveLength(3);
+ expect(findKeyInputs().at(0).element.value).toBe('test_var');
+ });
+
+ it('form values are restored again when the ref is reverted', async () => {
+ selectRef(1);
+ await waitForPromises();
+
+ selectRef(2);
+ await waitForPromises();
+
+ expect(findVariableRows()).toHaveLength(2);
+ expect(findKeyInputs().at(0).element.value).toBe('test_var_2');
+ });
+ });
+ });
+
+ describe('when feature flag new_pipeline_form_prefilled_vars is enabled', () => {
+ let origGon;
+
+ const mockYmlKey = 'yml_var';
+ const mockYmlValue = 'yml_var_val';
+ const mockYmlDesc = 'A var from yml.';
+
+ beforeAll(() => {
+ origGon = window.gon;
+ window.gon = { features: { newPipelineFormPrefilledVars: true } };
+ });
+
+ afterAll(() => {
+ window.gon = origGon;
+ });
+
+ describe('when yml defines a variable with description', () => {
+ beforeEach(async () => {
+ createComponent('', mockParams, mount);
+
+ mock.onGet(configVariablesPath).reply(httpStatusCodes.OK, {
+ [mockYmlKey]: {
+ value: mockYmlValue,
+ description: mockYmlDesc,
+ },
+ });
+
+ await waitForPromises();
+ });
+
+ it('displays all the variables', async () => {
+ expect(findVariableRows()).toHaveLength(4);
+ });
+
+ it('displays a variable from yml', () => {
+ expect(findKeyInputs().at(0).element.value).toBe(mockYmlKey);
+ expect(findValueInputs().at(0).element.value).toBe(mockYmlValue);
+ });
+
+ it('displays a variable from provided query params', () => {
+ expect(findKeyInputs().at(1).element.value).toBe('test_var');
+ expect(findValueInputs().at(1).element.value).toBe('test_var_val');
+ });
+
+ it('adds a description to the first variable from yml', () => {
+ expect(
+ findVariableRows()
+ .at(0)
+ .text(),
+ ).toContain(mockYmlDesc);
+ });
+
+ it('removes the description when a variable key changes', async () => {
+ findKeyInputs().at(0).element.value = 'yml_var_modified';
+ findKeyInputs()
+ .at(0)
+ .trigger('change');
+
+ await wrapper.vm.$nextTick();
+
+ expect(
+ findVariableRows()
+ .at(0)
+ .text(),
+ ).not.toContain(mockYmlDesc);
+ });
+ });
+
+ describe('when yml defines a variable without description', () => {
+ beforeEach(async () => {
+ createComponent('', mockParams, mount);
+
+ mock.onGet(configVariablesPath).reply(httpStatusCodes.OK, {
+ [mockYmlKey]: {
+ value: mockYmlValue,
+ description: null,
+ },
+ });
+
+ await waitForPromises();
+ });
+
+ it('displays all the variables', async () => {
+ expect(findVariableRows()).toHaveLength(3);
+ });
});
});
@@ -138,7 +283,7 @@ describe('Pipeline New Form', () => {
beforeEach(() => {
createComponent();
- mock.onPost(pipelinesPath).reply(400, mockError);
+ mock.onPost(pipelinesPath).reply(httpStatusCodes.BAD_REQUEST, mockError);
findForm().vm.$emit('submit', dummySubmitEvent);
diff --git a/spec/frontend/pipeline_new/mock_data.js b/spec/frontend/pipeline_new/mock_data.js
index 55286e0ec7e..cdbd6d4437e 100644
--- a/spec/frontend/pipeline_new/mock_data.js
+++ b/spec/frontend/pipeline_new/mock_data.js
@@ -14,9 +14,9 @@ export const mockProjectId = '21';
export const mockPostParams = {
ref: 'tag-1',
- variables: [
- { key: 'test_var', value: 'test_var_val', variable_type: 'env_var' },
- { key: 'test_file', value: 'test_file_val', variable_type: 'file' },
+ variables_attributes: [
+ { key: 'test_var', secret_value: 'test_var_val', variable_type: 'env_var' },
+ { key: 'test_file', secret_value: 'test_file_val', variable_type: 'file' },
],
};
diff --git a/spec/frontend/pipelines/components/dag/dag_graph_spec.js b/spec/frontend/pipelines/components/dag/dag_graph_spec.js
index e312791b01f..7786212cb69 100644
--- a/spec/frontend/pipelines/components/dag/dag_graph_spec.js
+++ b/spec/frontend/pipelines/components/dag/dag_graph_spec.js
@@ -3,7 +3,7 @@ import DagGraph from '~/pipelines/components/dag/dag_graph.vue';
import { IS_HIGHLIGHTED, LINK_SELECTOR, NODE_SELECTOR } from '~/pipelines/components/dag/constants';
import { highlightIn, highlightOut } from '~/pipelines/components/dag/interactions';
import { createSankey } from '~/pipelines/components/dag/drawing_utils';
-import { removeOrphanNodes } from '~/pipelines/components/dag/parsing_utils';
+import { removeOrphanNodes } from '~/pipelines/components/parsing_utils';
import { parsedData } from './mock_data';
describe('The DAG graph', () => {
diff --git a/spec/frontend/pipelines/components/dag/dag_spec.js b/spec/frontend/pipelines/components/dag/dag_spec.js
index 989f6c17197..08a43199594 100644
--- a/spec/frontend/pipelines/components/dag/dag_spec.js
+++ b/spec/frontend/pipelines/components/dag/dag_spec.js
@@ -4,13 +4,8 @@ import Dag from '~/pipelines/components/dag/dag.vue';
import DagGraph from '~/pipelines/components/dag/dag_graph.vue';
import DagAnnotations from '~/pipelines/components/dag/dag_annotations.vue';
-import {
- ADD_NOTE,
- REMOVE_NOTE,
- REPLACE_NOTES,
- PARSE_FAILURE,
- UNSUPPORTED_DATA,
-} from '~/pipelines/components/dag//constants';
+import { ADD_NOTE, REMOVE_NOTE, REPLACE_NOTES } from '~/pipelines/components/dag/constants';
+import { PARSE_FAILURE, UNSUPPORTED_DATA } from '~/pipelines/constants';
import {
mockParsedGraphQLNodes,
tooSmallGraph,
diff --git a/spec/frontend/pipelines/components/dag/drawing_utils_spec.js b/spec/frontend/pipelines/components/dag/drawing_utils_spec.js
index 37a7d07485b..095ded01298 100644
--- a/spec/frontend/pipelines/components/dag/drawing_utils_spec.js
+++ b/spec/frontend/pipelines/components/dag/drawing_utils_spec.js
@@ -1,5 +1,5 @@
import { createSankey } from '~/pipelines/components/dag/drawing_utils';
-import { parseData } from '~/pipelines/components/dag/parsing_utils';
+import { parseData } from '~/pipelines/components/parsing_utils';
import { mockParsedGraphQLNodes } from './mock_data';
describe('DAG visualization drawing utilities', () => {
diff --git a/spec/frontend/pipelines/components/dag/parsing_utils_spec.js b/spec/frontend/pipelines/components/dag/parsing_utils_spec.js
index e93fa8e6760..ceb6b64d4ad 100644
--- a/spec/frontend/pipelines/components/dag/parsing_utils_spec.js
+++ b/spec/frontend/pipelines/components/dag/parsing_utils_spec.js
@@ -5,7 +5,7 @@ import {
parseData,
removeOrphanNodes,
getMaxNodes,
-} from '~/pipelines/components/dag/parsing_utils';
+} from '~/pipelines/components/parsing_utils';
import { createSankey } from '~/pipelines/components/dag/drawing_utils';
import { mockParsedGraphQLNodes } from './mock_data';
diff --git a/spec/frontend/pipelines/graph/graph_component_spec.js b/spec/frontend/pipelines/graph/graph_component_spec.js
index d977db58a0e..062c9759a65 100644
--- a/spec/frontend/pipelines/graph/graph_component_spec.js
+++ b/spec/frontend/pipelines/graph/graph_component_spec.js
@@ -3,23 +3,27 @@ import { mount } from '@vue/test-utils';
import { setHTMLFixture } from 'helpers/fixtures';
import PipelineStore from '~/pipelines/stores/pipeline_store';
import graphComponent from '~/pipelines/components/graph/graph_component.vue';
-import stageColumnComponent from '~/pipelines/components/graph/stage_column_component.vue';
+import StageColumnComponent from '~/pipelines/components/graph/stage_column_component.vue';
import linkedPipelinesColumn from '~/pipelines/components/graph/linked_pipelines_column.vue';
import graphJSON from './mock_data';
import linkedPipelineJSON from './linked_pipelines_mock_data';
import PipelinesMediator from '~/pipelines/pipeline_details_mediator';
describe('graph component', () => {
- const store = new PipelineStore();
- store.storePipeline(linkedPipelineJSON);
- const mediator = new PipelinesMediator({ endpoint: '' });
-
+ let store;
+ let mediator;
let wrapper;
const findExpandPipelineBtn = () => wrapper.find('[data-testid="expandPipelineButton"]');
const findAllExpandPipelineBtns = () => wrapper.findAll('[data-testid="expandPipelineButton"]');
+ const findStageColumns = () => wrapper.findAll(StageColumnComponent);
+ const findStageColumnAt = i => findStageColumns().at(i);
beforeEach(() => {
+ mediator = new PipelinesMediator({ endpoint: '' });
+ store = new PipelineStore();
+ store.storePipeline(linkedPipelineJSON);
+
setHTMLFixture('<div class="layout-page"></div>');
});
@@ -43,7 +47,7 @@ describe('graph component', () => {
});
describe('with data', () => {
- it('should render the graph', () => {
+ beforeEach(() => {
wrapper = mount(graphComponent, {
propsData: {
isLoading: false,
@@ -51,26 +55,17 @@ describe('graph component', () => {
mediator,
},
});
+ });
+ it('renders the graph', () => {
expect(wrapper.find('.js-pipeline-graph').exists()).toBe(true);
-
- expect(wrapper.find(stageColumnComponent).classes()).toContain('no-margin');
-
- expect(
- wrapper
- .findAll(stageColumnComponent)
- .at(1)
- .classes(),
- ).toContain('left-margin');
-
- expect(wrapper.find('.stage-column:nth-child(2) .build:nth-child(1)').classes()).toContain(
- 'left-connector',
- );
-
expect(wrapper.find('.loading-icon').exists()).toBe(false);
-
expect(wrapper.find('.stage-column-list').exists()).toBe(true);
});
+
+ it('renders columns in the graph', () => {
+ expect(findStageColumns()).toHaveLength(graphJSON.details.stages.length);
+ });
});
describe('when linked pipelines are present', () => {
@@ -93,26 +88,26 @@ describe('graph component', () => {
expect(wrapper.find('.fa-spinner').exists()).toBe(false);
});
- it('should include the stage column list', () => {
- expect(wrapper.find(stageColumnComponent).exists()).toBe(true);
- });
-
- it('should include the no-margin class on the first child if there is only one job', () => {
- const firstStageColumnElement = wrapper.find(stageColumnComponent);
-
- expect(firstStageColumnElement.classes()).toContain('no-margin');
+ it('should include the stage column', () => {
+ expect(findStageColumnAt(0).exists()).toBe(true);
});
- it('should include the has-only-one-job class on the first child', () => {
- const firstStageColumnElement = wrapper.find('.stage-column-list .stage-column');
-
- expect(firstStageColumnElement.classes()).toContain('has-only-one-job');
+ it('stage column should have no-margin, gl-mr-26, has-only-one-job classes if there is only one job', () => {
+ expect(findStageColumnAt(0).classes()).toEqual(
+ expect.arrayContaining(['no-margin', 'gl-mr-26', 'has-only-one-job']),
+ );
});
it('should include the left-margin class on the second child', () => {
- const firstStageColumnElement = wrapper.find('.stage-column-list .stage-column:last-child');
+ expect(findStageColumnAt(1).classes('left-margin')).toBe(true);
+ });
- expect(firstStageColumnElement.classes()).toContain('left-margin');
+ it('should include the left-connector class in the build of the second child', () => {
+ expect(
+ findStageColumnAt(1)
+ .find('.build:nth-child(1)')
+ .classes('left-connector'),
+ ).toBe(true);
});
it('should include the js-has-linked-pipelines flag', () => {
@@ -134,12 +129,7 @@ describe('graph component', () => {
describe('stageConnectorClass', () => {
it('it returns left-margin when there is a triggerer', () => {
- expect(
- wrapper
- .findAll(stageColumnComponent)
- .at(1)
- .classes(),
- ).toContain('left-margin');
+ expect(findStageColumnAt(1).classes('left-margin')).toBe(true);
});
});
});
@@ -248,6 +238,16 @@ describe('graph component', () => {
.catch(done.fail);
});
});
+
+ describe('when column requests a refresh', () => {
+ beforeEach(() => {
+ findStageColumnAt(0).vm.$emit('refreshPipelineGraph');
+ });
+
+ it('refreshPipelineGraph is emitted', () => {
+ expect(wrapper.emitted().refreshPipelineGraph).toHaveLength(1);
+ });
+ });
});
});
});
@@ -268,7 +268,7 @@ describe('graph component', () => {
it('should include the first column with a no margin', () => {
const firstColumn = wrapper.find('.stage-column');
- expect(firstColumn.classes()).toContain('no-margin');
+ expect(firstColumn.classes('no-margin')).toBe(true);
});
it('should not render a linked pipelines column', () => {
@@ -278,16 +278,11 @@ describe('graph component', () => {
describe('stageConnectorClass', () => {
it('it returns no-margin when no triggerer and there is one job', () => {
- expect(wrapper.find(stageColumnComponent).classes()).toContain('no-margin');
+ expect(findStageColumnAt(0).classes('no-margin')).toBe(true);
});
it('it returns left-margin when no triggerer and not the first stage', () => {
- expect(
- wrapper
- .findAll(stageColumnComponent)
- .at(1)
- .classes(),
- ).toContain('left-margin');
+ expect(findStageColumnAt(1).classes('left-margin')).toBe(true);
});
});
});
@@ -302,12 +297,9 @@ describe('graph component', () => {
},
});
- expect(
- wrapper
- .find('.stage-column:nth-child(2) .stage-name')
- .text()
- .trim(),
- ).toEqual('Deploy &lt;img src=x onerror=alert(document.domain)&gt;');
+ expect(findStageColumnAt(1).props('title')).toEqual(
+ 'Deploy &lt;img src=x onerror=alert(document.domain)&gt;',
+ );
});
});
});
diff --git a/spec/frontend/pipelines/graph/job_item_spec.js b/spec/frontend/pipelines/graph/job_item_spec.js
index e844cbc5bf8..8aabb2f9cdd 100644
--- a/spec/frontend/pipelines/graph/job_item_spec.js
+++ b/spec/frontend/pipelines/graph/job_item_spec.js
@@ -1,5 +1,4 @@
import { mount } from '@vue/test-utils';
-import { trimText } from 'helpers/text_helper';
import JobItem from '~/pipelines/components/graph/job_item.vue';
describe('pipeline graph job item', () => {
@@ -65,7 +64,7 @@ describe('pipeline graph job item', () => {
expect(wrapper.find('.ci-status-icon-success').exists()).toBe(true);
- expect(trimText(wrapper.find('.ci-status-text').text())).toBe(mockJob.name);
+ expect(wrapper.text()).toBe(mockJob.name);
done();
});
@@ -85,7 +84,7 @@ describe('pipeline graph job item', () => {
expect(wrapper.find('.ci-status-icon-success').exists()).toBe(true);
expect(wrapper.find('a').exists()).toBe(false);
- expect(trimText(wrapper.find('.ci-status-text').text())).toBe(mockJobWithoutDetails.name);
+ expect(wrapper.text()).toBe(mockJobWithoutDetails.name);
});
it('should apply hover class and provided class name', () => {
diff --git a/spec/frontend/pipelines/graph/job_name_component_spec.js b/spec/frontend/pipelines/graph/job_name_component_spec.js
index 3574b66403e..f0aa646b8d7 100644
--- a/spec/frontend/pipelines/graph/job_name_component_spec.js
+++ b/spec/frontend/pipelines/graph/job_name_component_spec.js
@@ -21,12 +21,7 @@ describe('job name component', () => {
});
it('should render the provided name', () => {
- expect(
- wrapper
- .find('.ci-status-text')
- .text()
- .trim(),
- ).toBe(propsData.name);
+ expect(wrapper.text()).toBe(propsData.name);
});
it('should render an icon with the provided status', () => {
diff --git a/spec/frontend/pipelines/header_component_spec.js b/spec/frontend/pipelines/header_component_spec.js
index 5388d624d3c..2e10b0f068c 100644
--- a/spec/frontend/pipelines/header_component_spec.js
+++ b/spec/frontend/pipelines/header_component_spec.js
@@ -1,115 +1,164 @@
import { shallowMount } from '@vue/test-utils';
-import { GlModal } from '@gitlab/ui';
+import { GlModal, GlLoadingIcon } from '@gitlab/ui';
+import MockAdapter from 'axios-mock-adapter';
+import {
+ mockCancelledPipelineHeader,
+ mockFailedPipelineHeader,
+ mockRunningPipelineHeader,
+ mockSuccessfulPipelineHeader,
+} from './mock_data';
+import axios from '~/lib/utils/axios_utils';
import HeaderComponent from '~/pipelines/components/header_component.vue';
-import CiHeader from '~/vue_shared/components/header_ci_component.vue';
-import eventHub from '~/pipelines/event_hub';
describe('Pipeline details header', () => {
let wrapper;
let glModalDirective;
-
- const threeWeeksAgo = new Date();
- threeWeeksAgo.setDate(threeWeeksAgo.getDate() - 21);
+ let mockAxios;
const findDeleteModal = () => wrapper.find(GlModal);
-
- const defaultProps = {
- pipeline: {
- details: {
- status: {
- group: 'failed',
- icon: 'status_failed',
- label: 'failed',
- text: 'failed',
- details_path: 'path',
- },
- },
- id: 123,
- created_at: threeWeeksAgo.toISOString(),
- user: {
- web_url: 'path',
- name: 'Foo',
- username: 'foobar',
- email: 'foo@bar.com',
- avatar_url: 'link',
- },
- retry_path: 'retry',
- cancel_path: 'cancel',
- delete_path: 'delete',
+ const findRetryButton = () => wrapper.find('[data-testid="retryPipeline"]');
+ const findCancelButton = () => wrapper.find('[data-testid="cancelPipeline"]');
+ const findDeleteButton = () => wrapper.find('[data-testid="deletePipeline"]');
+ const findLoadingIcon = () => wrapper.find(GlLoadingIcon);
+
+ const defaultProvideOptions = {
+ pipelineId: 14,
+ pipelineIid: 1,
+ paths: {
+ retry: '/retry',
+ cancel: '/cancel',
+ delete: '/delete',
+ fullProject: '/namespace/my-project',
},
- isLoading: false,
};
- const createComponent = (props = {}) => {
+ const createComponent = (pipelineMock = mockRunningPipelineHeader, { isLoading } = false) => {
glModalDirective = jest.fn();
- wrapper = shallowMount(HeaderComponent, {
- propsData: {
- ...props,
+ const $apollo = {
+ queries: {
+ pipeline: {
+ loading: isLoading,
+ stopPolling: jest.fn(),
+ startPolling: jest.fn(),
+ },
+ },
+ };
+
+ return shallowMount(HeaderComponent, {
+ data() {
+ return {
+ pipeline: pipelineMock,
+ };
+ },
+ provide: {
+ ...defaultProvideOptions,
},
directives: {
glModal: {
- bind(el, { value }) {
+ bind(_, { value }) {
glModalDirective(value);
},
},
},
+ mocks: { $apollo },
});
};
beforeEach(() => {
- jest.spyOn(eventHub, '$emit');
-
- createComponent(defaultProps);
+ mockAxios = new MockAdapter(axios);
+ mockAxios.onGet('*').replyOnce(200);
});
afterEach(() => {
- eventHub.$off();
-
wrapper.destroy();
wrapper = null;
+
+ mockAxios.restore();
});
- it('should render provided pipeline info', () => {
- expect(wrapper.find(CiHeader).props()).toMatchObject({
- status: defaultProps.pipeline.details.status,
- itemId: defaultProps.pipeline.id,
- time: defaultProps.pipeline.created_at,
- user: defaultProps.pipeline.user,
+ describe('initial loading', () => {
+ beforeEach(() => {
+ wrapper = createComponent(null, { isLoading: true });
});
- });
- describe('action buttons', () => {
- it('should not trigger eventHub when nothing happens', () => {
- expect(eventHub.$emit).not.toHaveBeenCalled();
+ it('shows a loading state while graphQL is fetching initial data', () => {
+ expect(findLoadingIcon().exists()).toBe(true);
});
+ });
+
+ describe('visible state', () => {
+ it.each`
+ state | pipelineData | retryValue | cancelValue
+ ${'cancelled'} | ${mockCancelledPipelineHeader} | ${true} | ${false}
+ ${'failed'} | ${mockFailedPipelineHeader} | ${true} | ${false}
+ ${'running'} | ${mockRunningPipelineHeader} | ${false} | ${true}
+ ${'successful'} | ${mockSuccessfulPipelineHeader} | ${false} | ${false}
+ `(
+ 'with a $state pipeline, it will show actions: retry $retryValue and cancel $cancelValue',
+ ({ pipelineData, retryValue, cancelValue }) => {
+ wrapper = createComponent(pipelineData);
+
+ expect(findRetryButton().exists()).toBe(retryValue);
+ expect(findCancelButton().exists()).toBe(cancelValue);
+ },
+ );
+ });
- it('should call postAction when retry button action is clicked', () => {
- wrapper.find('[data-testid="retryButton"]').vm.$emit('click');
+ describe('actions', () => {
+ describe('Retry action', () => {
+ beforeEach(() => {
+ wrapper = createComponent(mockCancelledPipelineHeader);
+ });
- expect(eventHub.$emit).toHaveBeenCalledWith('headerPostAction', 'retry');
- });
+ it('should call axios with the right path when retry button is clicked', async () => {
+ jest.spyOn(axios, 'post');
+ findRetryButton().vm.$emit('click');
- it('should call postAction when cancel button action is clicked', () => {
- wrapper.find('[data-testid="cancelPipeline"]').vm.$emit('click');
+ await wrapper.vm.$nextTick();
- expect(eventHub.$emit).toHaveBeenCalledWith('headerPostAction', 'cancel');
+ expect(axios.post).toHaveBeenCalledWith(defaultProvideOptions.paths.retry);
+ });
});
- it('does not show delete modal', () => {
- expect(findDeleteModal()).not.toBeVisible();
+ describe('Cancel action', () => {
+ beforeEach(() => {
+ wrapper = createComponent(mockRunningPipelineHeader);
+ });
+
+ it('should call axios with the right path when cancel button is clicked', async () => {
+ jest.spyOn(axios, 'post');
+ findCancelButton().vm.$emit('click');
+
+ await wrapper.vm.$nextTick();
+
+ expect(axios.post).toHaveBeenCalledWith(defaultProvideOptions.paths.cancel);
+ });
});
- describe('when delete button action is clicked', () => {
- it('displays delete modal', () => {
+ describe('Delete action', () => {
+ beforeEach(() => {
+ wrapper = createComponent(mockFailedPipelineHeader);
+ });
+
+ it('displays delete modal when clicking on delete and does not call the delete action', async () => {
+ jest.spyOn(axios, 'delete');
+ findDeleteButton().vm.$emit('click');
+
+ await wrapper.vm.$nextTick();
+
expect(findDeleteModal().props('modalId')).toBe(wrapper.vm.$options.DELETE_MODAL_ID);
expect(glModalDirective).toHaveBeenCalledWith(wrapper.vm.$options.DELETE_MODAL_ID);
+ expect(axios.delete).not.toHaveBeenCalled();
});
- it('should call delete when modal is submitted', () => {
+ it('should call delete path when modal is submitted', async () => {
+ jest.spyOn(axios, 'delete');
findDeleteModal().vm.$emit('ok');
- expect(eventHub.$emit).toHaveBeenCalledWith('headerDeleteAction', 'delete');
+ await wrapper.vm.$nextTick();
+
+ expect(axios.delete).toHaveBeenCalledWith(defaultProvideOptions.paths.delete);
});
});
});
diff --git a/spec/frontend/pipelines/legacy_header_component_spec.js b/spec/frontend/pipelines/legacy_header_component_spec.js
new file mode 100644
index 00000000000..fb7feb8898a
--- /dev/null
+++ b/spec/frontend/pipelines/legacy_header_component_spec.js
@@ -0,0 +1,116 @@
+import { shallowMount } from '@vue/test-utils';
+import { GlModal } from '@gitlab/ui';
+import LegacyHeaderComponent from '~/pipelines/components/legacy_header_component.vue';
+import CiHeader from '~/vue_shared/components/header_ci_component.vue';
+import eventHub from '~/pipelines/event_hub';
+
+describe('Pipeline details header', () => {
+ let wrapper;
+ let glModalDirective;
+
+ const threeWeeksAgo = new Date();
+ threeWeeksAgo.setDate(threeWeeksAgo.getDate() - 21);
+
+ const findDeleteModal = () => wrapper.find(GlModal);
+
+ const defaultProps = {
+ pipeline: {
+ details: {
+ status: {
+ group: 'failed',
+ icon: 'status_failed',
+ label: 'failed',
+ text: 'failed',
+ details_path: 'path',
+ },
+ },
+ id: 123,
+ created_at: threeWeeksAgo.toISOString(),
+ user: {
+ web_url: 'path',
+ name: 'Foo',
+ username: 'foobar',
+ email: 'foo@bar.com',
+ avatar_url: 'link',
+ },
+ retry_path: 'retry',
+ cancel_path: 'cancel',
+ delete_path: 'delete',
+ },
+ isLoading: false,
+ };
+
+ const createComponent = (props = {}) => {
+ glModalDirective = jest.fn();
+
+ wrapper = shallowMount(LegacyHeaderComponent, {
+ propsData: {
+ ...props,
+ },
+ directives: {
+ glModal: {
+ bind(el, { value }) {
+ glModalDirective(value);
+ },
+ },
+ },
+ });
+ };
+
+ beforeEach(() => {
+ jest.spyOn(eventHub, '$emit');
+
+ createComponent(defaultProps);
+ });
+
+ afterEach(() => {
+ eventHub.$off();
+
+ wrapper.destroy();
+ wrapper = null;
+ });
+
+ it('should render provided pipeline info', () => {
+ expect(wrapper.find(CiHeader).props()).toMatchObject({
+ status: defaultProps.pipeline.details.status,
+ itemId: defaultProps.pipeline.id,
+ time: defaultProps.pipeline.created_at,
+ user: defaultProps.pipeline.user,
+ });
+ });
+
+ describe('action buttons', () => {
+ it('should not trigger eventHub when nothing happens', () => {
+ expect(eventHub.$emit).not.toHaveBeenCalled();
+ });
+
+ it('should call postAction when retry button action is clicked', () => {
+ wrapper.find('[data-testid="retryButton"]').vm.$emit('click');
+
+ expect(eventHub.$emit).toHaveBeenCalledWith('headerPostAction', 'retry');
+ });
+
+ it('should call postAction when cancel button action is clicked', () => {
+ wrapper.find('[data-testid="cancelPipeline"]').vm.$emit('click');
+
+ expect(eventHub.$emit).toHaveBeenCalledWith('headerPostAction', 'cancel');
+ });
+
+ it('does not show delete modal', () => {
+ expect(findDeleteModal()).not.toBeVisible();
+ });
+
+ describe('when delete button action is clicked', () => {
+ it('displays delete modal', () => {
+ expect(findDeleteModal().props('modalId')).toBe(wrapper.vm.$options.DELETE_MODAL_ID);
+ expect(glModalDirective).toHaveBeenCalledWith(wrapper.vm.$options.DELETE_MODAL_ID);
+ });
+
+ it('should call delete when modal is submitted', () => {
+ findDeleteModal().vm.$emit('ok');
+
+ expect(eventHub.$emit).toHaveBeenCalledWith('headerDeleteAction', 'delete');
+ });
+ });
+ });
+});
diff --git a/spec/frontend/pipelines/mock_data.js b/spec/frontend/pipelines/mock_data.js
index e63efc543f1..2afdbb05107 100644
--- a/spec/frontend/pipelines/mock_data.js
+++ b/spec/frontend/pipelines/mock_data.js
@@ -1,3 +1,7 @@
+const PIPELINE_RUNNING = 'RUNNING';
+const PIPELINE_CANCELED = 'CANCELED';
+const PIPELINE_FAILED = 'FAILED';
+
export const pipelineWithStages = {
id: 20333396,
user: {
@@ -320,6 +324,80 @@ export const pipelineWithStages = {
triggered: [],
};
+const threeWeeksAgo = new Date();
+threeWeeksAgo.setDate(threeWeeksAgo.getDate() - 21);
+
+export const mockPipelineHeader = {
+ detailedStatus: {},
+ id: 123,
+ userPermissions: {
+ destroyPipeline: true,
+ },
+ createdAt: threeWeeksAgo.toISOString(),
+ user: {
+ name: 'Foo',
+ username: 'foobar',
+ email: 'foo@bar.com',
+ avatarUrl: 'link',
+ },
+};
+
+export const mockFailedPipelineHeader = {
+ ...mockPipelineHeader,
+ status: PIPELINE_FAILED,
+ retryable: true,
+ cancelable: false,
+ detailedStatus: {
+ group: 'failed',
+ icon: 'status_failed',
+ label: 'failed',
+ text: 'failed',
+ detailsPath: 'path',
+ },
+};
+
+export const mockRunningPipelineHeader = {
+ ...mockPipelineHeader,
+ status: PIPELINE_RUNNING,
+ retryable: false,
+ cancelable: true,
+ detailedStatus: {
+ group: 'running',
+ icon: 'status_running',
+ label: 'running',
+ text: 'running',
+ detailsPath: 'path',
+ },
+};
+
+export const mockCancelledPipelineHeader = {
+ ...mockPipelineHeader,
+ status: PIPELINE_CANCELED,
+ retryable: true,
+ cancelable: false,
+ detailedStatus: {
+ group: 'cancelled',
+ icon: 'status_cancelled',
+ label: 'cancelled',
+ text: 'cancelled',
+ detailsPath: 'path',
+ },
+};
+
+export const mockSuccessfulPipelineHeader = {
+ ...mockPipelineHeader,
+ status: 'SUCCESS',
+ retryable: false,
+ cancelable: false,
+ detailedStatus: {
+ group: 'success',
+ icon: 'status_success',
+ label: 'success',
+ text: 'success',
+ detailsPath: 'path',
+ },
+};
+
export const stageReply = {
name: 'deploy',
title: 'deploy: running',
diff --git a/spec/frontend/pipelines/pipeline_graph/mock_data.js b/spec/frontend/pipelines/pipeline_graph/mock_data.js
index 5a5d6c021a6..b50932deec6 100644
--- a/spec/frontend/pipelines/pipeline_graph/mock_data.js
+++ b/spec/frontend/pipelines/pipeline_graph/mock_data.js
@@ -1,3 +1,5 @@
+import { createUniqueJobId } from '~/pipelines/utils';
+
export const yamlString = `stages:
- empty
- build
@@ -39,18 +41,20 @@ deploy_a:
script: echo hello
`;
+const jobId1 = createUniqueJobId('build', 'build_1');
+const jobId2 = createUniqueJobId('test', 'test_1');
+const jobId3 = createUniqueJobId('test', 'test_2');
+const jobId4 = createUniqueJobId('deploy', 'deploy_1');
+
export const pipelineData = {
stages: [
{
name: 'build',
- groups: [],
- },
- {
- name: 'build',
groups: [
{
name: 'build_1',
jobs: [{ script: 'echo hello', stage: 'build' }],
+ id: jobId1,
},
],
},
@@ -60,10 +64,12 @@ export const pipelineData = {
{
name: 'test_1',
jobs: [{ script: 'yarn test', stage: 'test' }],
+ id: jobId2,
},
{
name: 'test_2',
jobs: [{ script: 'yarn karma', stage: 'test' }],
+ id: jobId3,
},
],
},
@@ -73,8 +79,15 @@ export const pipelineData = {
{
name: 'deploy_1',
jobs: [{ script: 'yarn magick', stage: 'deploy' }],
+ id: jobId4,
},
],
},
],
+ jobs: {
+ [jobId1]: {},
+ [jobId2]: {},
+ [jobId3]: {},
+ [jobId4]: {},
+ },
};
diff --git a/spec/frontend/pipelines/pipeline_graph/utils_spec.js b/spec/frontend/pipelines/pipeline_graph/utils_spec.js
index dd85c8c2bd0..ade026c7053 100644
--- a/spec/frontend/pipelines/pipeline_graph/utils_spec.js
+++ b/spec/frontend/pipelines/pipeline_graph/utils_spec.js
@@ -1,150 +1,211 @@
-import { preparePipelineGraphData } from '~/pipelines/utils';
+import {
+ preparePipelineGraphData,
+ createUniqueJobId,
+ generateJobNeedsDict,
+} from '~/pipelines/utils';
-describe('preparePipelineGraphData', () => {
- const emptyResponse = { stages: [] };
+describe('utils functions', () => {
+ const emptyResponse = { stages: [], jobs: {} };
const jobName1 = 'build_1';
const jobName2 = 'build_2';
const jobName3 = 'test_1';
const jobName4 = 'deploy_1';
- const job1 = { [jobName1]: { script: 'echo hello', stage: 'build' } };
- const job2 = { [jobName2]: { script: 'echo build', stage: 'build' } };
- const job3 = { [jobName3]: { script: 'echo test', stage: 'test' } };
- const job4 = { [jobName4]: { script: 'echo deploy', stage: 'deploy' } };
-
- describe('returns an object with an empty array of stages if', () => {
- it('no data is passed', () => {
- expect(preparePipelineGraphData({})).toEqual(emptyResponse);
- });
+ const job1 = { script: 'echo hello', stage: 'build' };
+ const job2 = { script: 'echo build', stage: 'build' };
+ const job3 = { script: 'echo test', stage: 'test', needs: [jobName1, jobName2] };
+ const job4 = { script: 'echo deploy', stage: 'deploy', needs: [jobName3] };
+ const userDefinedStage = 'myStage';
- it('no stages are found', () => {
- expect(preparePipelineGraphData({ includes: 'template/myTemplate.gitlab-ci.yml' })).toEqual(
- emptyResponse,
- );
- });
- });
-
- describe('returns the correct array of stages', () => {
- it('when multiple jobs are in the same stage', () => {
- const expectedData = {
- stages: [
+ const pipelineGraphData = {
+ stages: [
+ {
+ name: userDefinedStage,
+ groups: [],
+ },
+ {
+ name: job4.stage,
+ groups: [
{
- name: job1[jobName1].stage,
- groups: [
- {
- name: jobName1,
- jobs: [{ script: job1[jobName1].script, stage: job1[jobName1].stage }],
- },
- {
- name: jobName2,
- jobs: [{ script: job2[jobName2].script, stage: job2[jobName2].stage }],
- },
- ],
+ name: jobName4,
+ jobs: [{ ...job4 }],
+ id: createUniqueJobId(job4.stage, jobName4),
},
],
- };
-
- expect(preparePipelineGraphData({ ...job1, ...job2 })).toEqual(expectedData);
- });
-
- it('when stages are defined by the user', () => {
- const userDefinedStage = 'myStage';
- const userDefinedStage2 = 'myStage2';
-
- const expectedData = {
- stages: [
+ },
+ {
+ name: job1.stage,
+ groups: [
{
- name: userDefinedStage,
- groups: [],
+ name: jobName1,
+ jobs: [{ ...job1 }],
+ id: createUniqueJobId(job1.stage, jobName1),
},
{
- name: userDefinedStage2,
- groups: [],
+ name: jobName2,
+ jobs: [{ ...job2 }],
+ id: createUniqueJobId(job2.stage, jobName2),
},
],
- };
+ },
+ {
+ name: job3.stage,
+ groups: [
+ {
+ name: jobName3,
+ jobs: [{ ...job3 }],
+ id: createUniqueJobId(job3.stage, jobName3),
+ },
+ ],
+ },
+ ],
+ jobs: {
+ [jobName1]: { ...job1, id: createUniqueJobId(job1.stage, jobName1) },
+ [jobName2]: { ...job2, id: createUniqueJobId(job2.stage, jobName2) },
+ [jobName3]: { ...job3, id: createUniqueJobId(job3.stage, jobName3) },
+ [jobName4]: { ...job4, id: createUniqueJobId(job4.stage, jobName4) },
+ },
+ };
- expect(preparePipelineGraphData({ stages: [userDefinedStage, userDefinedStage2] })).toEqual(
- expectedData,
- );
- });
+ describe('preparePipelineGraphData', () => {
+ describe('returns an empty array of stages and empty job objects if', () => {
+ it('no data is passed', () => {
+ expect(preparePipelineGraphData({})).toEqual(emptyResponse);
+ });
- it('by combining user defined stage and job stages, it preserves user defined order', () => {
- const userDefinedStage = 'myStage';
- const userDefinedStageThatOverlaps = 'deploy';
+ it('no stages are found', () => {
+ expect(preparePipelineGraphData({ includes: 'template/myTemplate.gitlab-ci.yml' })).toEqual(
+ emptyResponse,
+ );
+ });
+ });
- const expectedData = {
- stages: [
- {
- name: userDefinedStage,
- groups: [],
- },
- {
- name: job4[jobName4].stage,
- groups: [
- {
- name: jobName4,
- jobs: [{ script: job4[jobName4].script, stage: job4[jobName4].stage }],
- },
- ],
- },
- {
- name: job1[jobName1].stage,
- groups: [
- {
- name: jobName1,
- jobs: [{ script: job1[jobName1].script, stage: job1[jobName1].stage }],
- },
- {
- name: jobName2,
- jobs: [{ script: job2[jobName2].script, stage: job2[jobName2].stage }],
- },
- ],
+ describe('returns the correct array of stages and object of jobs', () => {
+ it('when multiple jobs are in the same stage', () => {
+ const expectedData = {
+ stages: [
+ {
+ name: job1.stage,
+ groups: [
+ {
+ name: jobName1,
+ jobs: [{ ...job1 }],
+ id: createUniqueJobId(job1.stage, jobName1),
+ },
+ {
+ name: jobName2,
+ jobs: [{ ...job2 }],
+ id: createUniqueJobId(job2.stage, jobName2),
+ },
+ ],
+ },
+ ],
+ jobs: {
+ [jobName1]: { ...job1, id: createUniqueJobId(job1.stage, jobName1) },
+ [jobName2]: { ...job2, id: createUniqueJobId(job2.stage, jobName2) },
},
- {
- name: job3[jobName3].stage,
- groups: [
- {
- name: jobName3,
- jobs: [{ script: job3[jobName3].script, stage: job3[jobName3].stage }],
- },
- ],
+ };
+ expect(
+ preparePipelineGraphData({ [jobName1]: { ...job1 }, [jobName2]: { ...job2 } }),
+ ).toEqual(expectedData);
+ });
+
+ it('when stages are defined by the user', () => {
+ const userDefinedStage2 = 'myStage2';
+
+ const expectedData = {
+ stages: [
+ {
+ name: userDefinedStage,
+ groups: [],
+ },
+ {
+ name: userDefinedStage2,
+ groups: [],
+ },
+ ],
+ jobs: {},
+ };
+
+ expect(preparePipelineGraphData({ stages: [userDefinedStage, userDefinedStage2] })).toEqual(
+ expectedData,
+ );
+ });
+
+ it('by combining user defined stage and job stages, it preserves user defined order', () => {
+ const userDefinedStageThatOverlaps = 'deploy';
+
+ expect(
+ preparePipelineGraphData({
+ stages: [userDefinedStage, userDefinedStageThatOverlaps],
+ [jobName1]: { ...job1 },
+ [jobName2]: { ...job2 },
+ [jobName3]: { ...job3 },
+ [jobName4]: { ...job4 },
+ }),
+ ).toEqual(pipelineGraphData);
+ });
+
+ it('with only unique values', () => {
+ const expectedData = {
+ stages: [
+ {
+ name: job1.stage,
+ groups: [
+ {
+ name: jobName1,
+ jobs: [{ ...job1 }],
+ id: createUniqueJobId(job1.stage, jobName1),
+ },
+ ],
+ },
+ ],
+ jobs: {
+ [jobName1]: { ...job1, id: createUniqueJobId(job1.stage, jobName1) },
},
- ],
- };
+ };
- expect(
- preparePipelineGraphData({
- stages: [userDefinedStage, userDefinedStageThatOverlaps],
- ...job1,
- ...job2,
- ...job3,
- ...job4,
- }),
- ).toEqual(expectedData);
+ expect(
+ preparePipelineGraphData({
+ stages: ['build'],
+ [jobName1]: { ...job1 },
+ [jobName1]: { ...job1 },
+ }),
+ ).toEqual(expectedData);
+ });
});
+ });
- it('with only unique values', () => {
- const expectedData = {
- stages: [
- {
- name: job1[jobName1].stage,
- groups: [
- {
- name: jobName1,
- jobs: [{ script: job1[jobName1].script, stage: job1[jobName1].stage }],
- },
- ],
- },
- ],
+ describe('generateJobNeedsDict', () => {
+ it('generates an empty object if it receives no jobs', () => {
+ expect(generateJobNeedsDict({ jobs: {} })).toEqual({});
+ });
+
+ it('generates a dict with empty needs if there are no dependencies', () => {
+ const smallGraph = {
+ jobs: {
+ [jobName1]: { ...job1, id: createUniqueJobId(job1.stage, jobName1) },
+ [jobName2]: { ...job2, id: createUniqueJobId(job2.stage, jobName2) },
+ },
};
- expect(
- preparePipelineGraphData({
- stages: ['build'],
- ...job1,
- ...job1,
- }),
- ).toEqual(expectedData);
+ expect(generateJobNeedsDict(smallGraph)).toEqual({
+ [pipelineGraphData.jobs[jobName1].id]: [],
+ [pipelineGraphData.jobs[jobName2].id]: [],
+ });
+ });
+
+ it('generates a dict where key is the a job and its value is an array of all its needs', () => {
+ const uniqueJobName1 = pipelineGraphData.jobs[jobName1].id;
+ const uniqueJobName2 = pipelineGraphData.jobs[jobName2].id;
+ const uniqueJobName3 = pipelineGraphData.jobs[jobName3].id;
+ const uniqueJobName4 = pipelineGraphData.jobs[jobName4].id;
+
+ expect(generateJobNeedsDict(pipelineGraphData)).toEqual({
+ [uniqueJobName1]: [],
+ [uniqueJobName2]: [],
+ [uniqueJobName3]: [uniqueJobName1, uniqueJobName2],
+ [uniqueJobName4]: [uniqueJobName3, uniqueJobName1, uniqueJobName2],
+ });
});
});
});
diff --git a/spec/frontend/pipelines/pipelines_spec.js b/spec/frontend/pipelines/pipelines_spec.js
index b0ad6bbd228..1298a2a1524 100644
--- a/spec/frontend/pipelines/pipelines_spec.js
+++ b/spec/frontend/pipelines/pipelines_spec.js
@@ -1,9 +1,17 @@
import { mount } from '@vue/test-utils';
import MockAdapter from 'axios-mock-adapter';
import waitForPromises from 'helpers/wait_for_promises';
-import { GlFilteredSearch } from '@gitlab/ui';
+import { GlFilteredSearch, GlButton, GlLoadingIcon } from '@gitlab/ui';
import Api from '~/api';
import axios from '~/lib/utils/axios_utils';
+import NavigationTabs from '~/vue_shared/components/navigation_tabs.vue';
+import TablePagination from '~/vue_shared/components/pagination/table_pagination.vue';
+
+import NavigationControls from '~/pipelines/components/pipelines_list/nav_controls.vue';
+import EmptyState from '~/pipelines/components/pipelines_list/empty_state.vue';
+import BlankState from '~/pipelines/components/pipelines_list/blank_state.vue';
+import PipelinesTableComponent from '~/pipelines/components/pipelines_list/pipelines_table.vue';
+
import PipelinesComponent from '~/pipelines/components/pipelines_list/pipelines.vue';
import Store from '~/pipelines/stores/pipelines_store';
import { pipelineWithStages, stageReply, users, mockSearch, branches } from './mock_data';
@@ -49,6 +57,20 @@ describe('Pipelines', () => {
};
const findFilteredSearch = () => wrapper.find(GlFilteredSearch);
+ const findByTestId = id => wrapper.find(`[data-testid="${id}"]`);
+ const findNavigationTabs = () => wrapper.find(NavigationTabs);
+ const findNavigationControls = () => wrapper.find(NavigationControls);
+ const findTab = tab => findByTestId(`pipelines-tab-${tab}`);
+
+ const findRunPipelineButton = () => findByTestId('run-pipeline-button');
+ const findCiLintButton = () => findByTestId('ci-lint-button');
+ const findCleanCacheButton = () => findByTestId('clear-cache-button');
+
+ const findEmptyState = () => wrapper.find(EmptyState);
+ const findBlankState = () => wrapper.find(BlankState);
+ const findStagesDropdown = () => wrapper.find('.js-builds-dropdown-button');
+
+ const findTablePagination = () => wrapper.find(TablePagination);
const createComponent = (props = defaultProps, methods) => {
wrapper = mount(PipelinesComponent, {
@@ -87,19 +109,19 @@ describe('Pipelines', () => {
});
it('renders tabs', () => {
- expect(wrapper.find('.js-pipelines-tab-all').text()).toContain('All');
+ expect(findTab('all').text()).toContain('All');
});
it('renders Run Pipeline link', () => {
- expect(wrapper.find('.js-run-pipeline').attributes('href')).toBe(paths.newPipelinePath);
+ expect(findRunPipelineButton().attributes('href')).toBe(paths.newPipelinePath);
});
it('renders CI Lint link', () => {
- expect(wrapper.find('.js-ci-lint').attributes('href')).toBe(paths.ciLintPath);
+ expect(findCiLintButton().attributes('href')).toBe(paths.ciLintPath);
});
it('renders Clear Runner Cache button', () => {
- expect(wrapper.find('.js-clear-cache').text()).toBe('Clear Runner Caches');
+ expect(findCleanCacheButton().text()).toBe('Clear Runner Caches');
});
it('renders pipelines table', () => {
@@ -127,23 +149,31 @@ describe('Pipelines', () => {
});
it('renders tabs', () => {
- expect(wrapper.find('.js-pipelines-tab-all').text()).toContain('All');
+ expect(findTab('all').text()).toContain('All');
});
it('renders Run Pipeline link', () => {
- expect(wrapper.find('.js-run-pipeline').attributes('href')).toEqual(paths.newPipelinePath);
+ expect(findRunPipelineButton().attributes('href')).toBe(paths.newPipelinePath);
});
it('renders CI Lint link', () => {
- expect(wrapper.find('.js-ci-lint').attributes('href')).toEqual(paths.ciLintPath);
+ expect(findCiLintButton().attributes('href')).toBe(paths.ciLintPath);
});
it('renders Clear Runner Cache button', () => {
- expect(wrapper.find('.js-clear-cache').text()).toEqual('Clear Runner Caches');
+ expect(findCleanCacheButton().text()).toBe('Clear Runner Caches');
});
it('renders tab empty state', () => {
- expect(wrapper.find('.empty-state h4').text()).toEqual('There are currently no pipelines.');
+ expect(findBlankState().text()).toBe('There are currently no pipelines.');
+ });
+
+ it('renders tab empty state finished scope', () => {
+ wrapper.vm.scope = 'finished';
+
+ return wrapper.vm.$nextTick().then(() => {
+ expect(findBlankState().text()).toBe('There are currently no finished pipelines.');
+ });
});
});
@@ -165,18 +195,23 @@ describe('Pipelines', () => {
});
it('renders empty state', () => {
- expect(wrapper.find('.js-empty-state h4').text()).toEqual('Build with confidence');
-
- expect(wrapper.find('.js-get-started-pipelines').attributes('href')).toEqual(
- paths.helpPagePath,
- );
+ expect(
+ findEmptyState()
+ .find('h4')
+ .text(),
+ ).toBe('Build with confidence');
+ expect(
+ findEmptyState()
+ .find(GlButton)
+ .attributes('href'),
+ ).toBe(paths.helpPagePath);
});
it('does not render tabs nor buttons', () => {
- expect(wrapper.find('.js-pipelines-tab-all').exists()).toBeFalsy();
- expect(wrapper.find('.js-run-pipeline').exists()).toBeFalsy();
- expect(wrapper.find('.js-ci-lint').exists()).toBeFalsy();
- expect(wrapper.find('.js-clear-cache').exists()).toBeFalsy();
+ expect(findTab('all').exists()).toBe(false);
+ expect(findRunPipelineButton().exists()).toBeFalsy();
+ expect(findCiLintButton().exists()).toBeFalsy();
+ expect(findCleanCacheButton().exists()).toBeFalsy();
});
});
@@ -189,20 +224,18 @@ describe('Pipelines', () => {
});
it('renders tabs', () => {
- expect(wrapper.find('.js-pipelines-tab-all').text()).toContain('All');
+ expect(findTab('all').text()).toContain('All');
});
it('renders buttons', () => {
- expect(wrapper.find('.js-run-pipeline').attributes('href')).toEqual(paths.newPipelinePath);
+ expect(findRunPipelineButton().attributes('href')).toBe(paths.newPipelinePath);
- expect(wrapper.find('.js-ci-lint').attributes('href')).toEqual(paths.ciLintPath);
- expect(wrapper.find('.js-clear-cache').text()).toEqual('Clear Runner Caches');
+ expect(findCiLintButton().attributes('href')).toBe(paths.ciLintPath);
+ expect(findCleanCacheButton().text()).toBe('Clear Runner Caches');
});
it('renders error state', () => {
- expect(wrapper.find('.empty-state').text()).toContain(
- 'There was an error fetching the pipelines.',
- );
+ expect(findBlankState().text()).toContain('There was an error fetching the pipelines.');
});
});
});
@@ -218,13 +251,13 @@ describe('Pipelines', () => {
});
it('renders tabs', () => {
- expect(wrapper.find('.js-pipelines-tab-all').text()).toContain('All');
+ expect(findTab('all').text()).toContain('All');
});
it('does not render buttons', () => {
- expect(wrapper.find('.js-run-pipeline').exists()).toBeFalsy();
- expect(wrapper.find('.js-ci-lint').exists()).toBeFalsy();
- expect(wrapper.find('.js-clear-cache').exists()).toBeFalsy();
+ expect(findRunPipelineButton().exists()).toBeFalsy();
+ expect(findCiLintButton().exists()).toBeFalsy();
+ expect(findCleanCacheButton().exists()).toBeFalsy();
});
it('renders pipelines table', () => {
@@ -252,17 +285,17 @@ describe('Pipelines', () => {
});
it('renders tabs', () => {
- expect(wrapper.find('.js-pipelines-tab-all').text()).toContain('All');
+ expect(findTab('all').text()).toContain('All');
});
it('does not render buttons', () => {
- expect(wrapper.find('.js-run-pipeline').exists()).toBeFalsy();
- expect(wrapper.find('.js-ci-lint').exists()).toBeFalsy();
- expect(wrapper.find('.js-clear-cache').exists()).toBeFalsy();
+ expect(findRunPipelineButton().exists()).toBeFalsy();
+ expect(findCiLintButton().exists()).toBeFalsy();
+ expect(findCleanCacheButton().exists()).toBeFalsy();
});
it('renders tab empty state', () => {
- expect(wrapper.find('.empty-state h4').text()).toEqual('There are currently no pipelines.');
+ expect(wrapper.find('.empty-state h4').text()).toBe('There are currently no pipelines.');
});
});
@@ -284,18 +317,22 @@ describe('Pipelines', () => {
});
it('renders empty state without button to set CI', () => {
- expect(wrapper.find('.js-empty-state').text()).toEqual(
+ expect(findEmptyState().text()).toBe(
'This project is not currently set up to run pipelines.',
);
- expect(wrapper.find('.js-get-started-pipelines').exists()).toBeFalsy();
+ expect(
+ findEmptyState()
+ .find(GlButton)
+ .exists(),
+ ).toBeFalsy();
});
it('does not render tabs or buttons', () => {
- expect(wrapper.find('.js-pipelines-tab-all').exists()).toBeFalsy();
- expect(wrapper.find('.js-run-pipeline').exists()).toBeFalsy();
- expect(wrapper.find('.js-ci-lint').exists()).toBeFalsy();
- expect(wrapper.find('.js-clear-cache').exists()).toBeFalsy();
+ expect(findTab('all').exists()).toBe(false);
+ expect(findRunPipelineButton().exists()).toBeFalsy();
+ expect(findCiLintButton().exists()).toBeFalsy();
+ expect(findCleanCacheButton().exists()).toBeFalsy();
});
});
@@ -309,13 +346,13 @@ describe('Pipelines', () => {
});
it('renders tabs', () => {
- expect(wrapper.find('.js-pipelines-tab-all').text()).toContain('All');
+ expect(findTab('all').text()).toContain('All');
});
it('does not renders buttons', () => {
- expect(wrapper.find('.js-run-pipeline').exists()).toBeFalsy();
- expect(wrapper.find('.js-ci-lint').exists()).toBeFalsy();
- expect(wrapper.find('.js-clear-cache').exists()).toBeFalsy();
+ expect(findRunPipelineButton().exists()).toBeFalsy();
+ expect(findCiLintButton().exists()).toBeFalsy();
+ expect(findCleanCacheButton().exists()).toBeFalsy();
});
it('renders error state', () => {
@@ -342,14 +379,20 @@ describe('Pipelines', () => {
);
});
- it('should render navigation tabs', () => {
- expect(wrapper.find('.js-pipelines-tab-all').text()).toContain('All');
-
- expect(wrapper.find('.js-pipelines-tab-finished').text()).toContain('Finished');
-
- expect(wrapper.find('.js-pipelines-tab-branches').text()).toContain('Branches');
+ it('should set up navigation tabs', () => {
+ expect(findNavigationTabs().props('tabs')).toEqual([
+ { name: 'All', scope: 'all', count: '3', isActive: true },
+ { name: 'Finished', scope: 'finished', count: undefined, isActive: false },
+ { name: 'Branches', scope: 'branches', isActive: false },
+ { name: 'Tags', scope: 'tags', isActive: false },
+ ]);
+ });
- expect(wrapper.find('.js-pipelines-tab-tags').text()).toContain('Tags');
+ it('should render navigation tabs', () => {
+ expect(findTab('all').html()).toContain('All');
+ expect(findTab('finished').text()).toContain('Finished');
+ expect(findTab('branches').text()).toContain('Branches');
+ expect(findTab('tags').text()).toContain('Tags');
});
it('should make an API request when using tabs', () => {
@@ -362,7 +405,7 @@ describe('Pipelines', () => {
);
return waitForPromises().then(() => {
- wrapper.find('.js-pipelines-tab-finished').trigger('click');
+ findTab('finished').trigger('click');
expect(updateContentMock).toHaveBeenCalledWith({ scope: 'finished', page: '1' });
});
@@ -401,133 +444,172 @@ describe('Pipelines', () => {
});
});
- describe('methods', () => {
+ describe('User Interaction', () => {
+ let updateContentMock;
+
beforeEach(() => {
jest.spyOn(window.history, 'pushState').mockImplementation(() => null);
});
- describe('onChangeTab', () => {
- it('should set page to 1', () => {
- const updateContentMock = jest.fn(() => {});
- createComponent(
- { hasGitlabCi: true, canCreatePipeline: true, ...paths },
- {
- updateContent: updateContentMock,
- },
- );
+ beforeEach(() => {
+ mock.onGet(paths.endpoint).reply(200, pipelines);
+ createComponent();
- wrapper.vm.onChangeTab('running');
+ updateContentMock = jest.spyOn(wrapper.vm, 'updateContent');
+
+ return waitForPromises();
+ });
+
+ describe('when user changes tabs', () => {
+ it('should set page to 1', () => {
+ findNavigationTabs().vm.$emit('onChangeTab', 'running');
expect(updateContentMock).toHaveBeenCalledWith({ scope: 'running', page: '1' });
});
});
- describe('onChangePage', () => {
+ describe('when user changes page', () => {
it('should update page and keep scope', () => {
- const updateContentMock = jest.fn(() => {});
- createComponent(
- { hasGitlabCi: true, canCreatePipeline: true, ...paths },
- {
- updateContent: updateContentMock,
- },
- );
-
- wrapper.vm.onChangePage(4);
+ findTablePagination().vm.change(4);
expect(updateContentMock).toHaveBeenCalledWith({ scope: wrapper.vm.scope, page: '4' });
});
});
- });
- describe('computed properties', () => {
- beforeEach(() => {
- createComponent();
- });
+ describe('updates results when a staged is clicked', () => {
+ beforeEach(() => {
+ const copyPipeline = { ...pipelineWithStages };
+ copyPipeline.id += 1;
+ mock
+ .onGet('twitter/flight/pipelines.json')
+ .reply(
+ 200,
+ {
+ pipelines: [pipelineWithStages],
+ count: {
+ all: 1,
+ finished: 1,
+ pending: 0,
+ running: 0,
+ },
+ },
+ {
+ 'POLL-INTERVAL': 100,
+ },
+ )
+ .onGet(pipelineWithStages.details.stages[0].dropdown_path)
+ .reply(200, stageReply);
- describe('tabs', () => {
- it('returns default tabs', () => {
- expect(wrapper.vm.tabs).toEqual([
- { name: 'All', scope: 'all', count: undefined, isActive: true },
- { name: 'Finished', scope: 'finished', count: undefined, isActive: false },
- { name: 'Branches', scope: 'branches', isActive: false },
- { name: 'Tags', scope: 'tags', isActive: false },
- ]);
+ createComponent();
});
- });
- describe('emptyTabMessage', () => {
- it('returns message with finished scope', () => {
- wrapper.vm.scope = 'finished';
+ describe('when a request is being made', () => {
+ it('stops polling, cancels the request, & restarts polling', () => {
+ const stopMock = jest.spyOn(wrapper.vm.poll, 'stop');
+ const restartMock = jest.spyOn(wrapper.vm.poll, 'restart');
+ const cancelMock = jest.spyOn(wrapper.vm.service.cancelationSource, 'cancel');
+ mock.onGet('twitter/flight/pipelines.json').reply(200, pipelines);
- return wrapper.vm.$nextTick().then(() => {
- expect(wrapper.vm.emptyTabMessage).toEqual('There are currently no finished pipelines.');
+ return waitForPromises()
+ .then(() => {
+ wrapper.vm.isMakingRequest = true;
+ findStagesDropdown().trigger('click');
+ })
+ .then(() => {
+ expect(cancelMock).toHaveBeenCalled();
+ expect(stopMock).toHaveBeenCalled();
+ expect(restartMock).toHaveBeenCalled();
+ });
});
});
- it('returns message without scope when scope is `all`', () => {
- expect(wrapper.vm.emptyTabMessage).toEqual('There are currently no pipelines.');
+ describe('when no request is being made', () => {
+ it('stops polling & restarts polling', () => {
+ const stopMock = jest.spyOn(wrapper.vm.poll, 'stop');
+ const restartMock = jest.spyOn(wrapper.vm.poll, 'restart');
+ mock.onGet('twitter/flight/pipelines.json').reply(200, pipelines);
+
+ return waitForPromises()
+ .then(() => {
+ findStagesDropdown().trigger('click');
+ expect(stopMock).toHaveBeenCalled();
+ })
+ .then(() => {
+ expect(restartMock).toHaveBeenCalled();
+ });
+ });
});
});
+ });
- describe('stateToRender', () => {
- it('returns loading state when the app is loading', () => {
- expect(wrapper.vm.stateToRender).toEqual('loading');
+ describe('Rendered content', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ describe('displays different content', () => {
+ it('shows loading state when the app is loading', () => {
+ expect(wrapper.find(GlLoadingIcon).exists()).toBe(true);
});
- it('returns error state when app has error', () => {
+ it('shows error state when app has error', () => {
wrapper.vm.hasError = true;
wrapper.vm.isLoading = false;
return wrapper.vm.$nextTick().then(() => {
- expect(wrapper.vm.stateToRender).toEqual('error');
+ expect(findBlankState().props('message')).toBe(
+ 'There was an error fetching the pipelines. Try again in a few moments or contact your support team.',
+ );
});
});
- it('returns table list when app has pipelines', () => {
+ it('shows table list when app has pipelines', () => {
wrapper.vm.isLoading = false;
wrapper.vm.hasError = false;
wrapper.vm.state.pipelines = pipelines.pipelines;
return wrapper.vm.$nextTick().then(() => {
- expect(wrapper.vm.stateToRender).toEqual('tableList');
+ expect(wrapper.find(PipelinesTableComponent).exists()).toBe(true);
});
});
- it('returns empty tab when app does not have pipelines but project has pipelines', () => {
+ it('shows empty tab when app does not have pipelines but project has pipelines', () => {
wrapper.vm.state.count.all = 10;
wrapper.vm.isLoading = false;
return wrapper.vm.$nextTick().then(() => {
- expect(wrapper.vm.stateToRender).toEqual('emptyTab');
+ expect(findBlankState().exists()).toBe(true);
+ expect(findBlankState().props('message')).toBe('There are currently no pipelines.');
});
});
- it('returns empty tab when project has CI', () => {
+ it('shows empty tab when project has CI', () => {
wrapper.vm.isLoading = false;
return wrapper.vm.$nextTick().then(() => {
- expect(wrapper.vm.stateToRender).toEqual('emptyTab');
+ expect(findBlankState().exists()).toBe(true);
+ expect(findBlankState().props('message')).toBe('There are currently no pipelines.');
});
});
- it('returns empty state when project does not have pipelines nor CI', () => {
+ it('shows empty state when project does not have pipelines nor CI', () => {
createComponent({ hasGitlabCi: false, canCreatePipeline: true, ...paths });
wrapper.vm.isLoading = false;
return wrapper.vm.$nextTick().then(() => {
- expect(wrapper.vm.stateToRender).toEqual('emptyState');
+ expect(wrapper.find(EmptyState).exists()).toBe(true);
});
});
});
- describe('shouldRenderTabs', () => {
+ describe('displays tabs', () => {
it('returns true when state is loading & has already made the first request', () => {
wrapper.vm.isLoading = true;
wrapper.vm.hasMadeRequest = true;
return wrapper.vm.$nextTick().then(() => {
- expect(wrapper.vm.shouldRenderTabs).toEqual(true);
+ expect(findNavigationTabs().exists()).toBe(true);
});
});
@@ -537,7 +619,7 @@ describe('Pipelines', () => {
wrapper.vm.hasMadeRequest = true;
return wrapper.vm.$nextTick().then(() => {
- expect(wrapper.vm.shouldRenderTabs).toEqual(true);
+ expect(findNavigationTabs().exists()).toBe(true);
});
});
@@ -547,7 +629,7 @@ describe('Pipelines', () => {
wrapper.vm.hasMadeRequest = true;
return wrapper.vm.$nextTick().then(() => {
- expect(wrapper.vm.shouldRenderTabs).toEqual(true);
+ expect(findNavigationTabs().exists()).toBe(true);
});
});
@@ -557,7 +639,7 @@ describe('Pipelines', () => {
wrapper.vm.hasMadeRequest = true;
return wrapper.vm.$nextTick().then(() => {
- expect(wrapper.vm.shouldRenderTabs).toEqual(true);
+ expect(findNavigationTabs().exists()).toBe(true);
});
});
@@ -565,7 +647,7 @@ describe('Pipelines', () => {
wrapper.vm.hasMadeRequest = false;
return wrapper.vm.$nextTick().then(() => {
- expect(wrapper.vm.shouldRenderTabs).toEqual(false);
+ expect(findNavigationTabs().exists()).toBe(false);
});
});
@@ -576,17 +658,17 @@ describe('Pipelines', () => {
wrapper.vm.hasMadeRequest = true;
return wrapper.vm.$nextTick().then(() => {
- expect(wrapper.vm.shouldRenderTabs).toEqual(false);
+ expect(findNavigationTabs().exists()).toBe(false);
});
});
});
- describe('shouldRenderButtons', () => {
+ describe('displays buttons', () => {
it('returns true when it has paths & has made the first request', () => {
wrapper.vm.hasMadeRequest = true;
return wrapper.vm.$nextTick().then(() => {
- expect(wrapper.vm.shouldRenderButtons).toEqual(true);
+ expect(findNavigationControls().exists()).toBe(true);
});
});
@@ -594,77 +676,12 @@ describe('Pipelines', () => {
wrapper.vm.hasMadeRequest = false;
return wrapper.vm.$nextTick().then(() => {
- expect(wrapper.vm.shouldRenderButtons).toEqual(false);
+ expect(findNavigationControls().exists()).toBe(false);
});
});
});
});
- describe('updates results when a staged is clicked', () => {
- beforeEach(() => {
- const copyPipeline = { ...pipelineWithStages };
- copyPipeline.id += 1;
- mock
- .onGet('twitter/flight/pipelines.json')
- .reply(
- 200,
- {
- pipelines: [pipelineWithStages],
- count: {
- all: 1,
- finished: 1,
- pending: 0,
- running: 0,
- },
- },
- {
- 'POLL-INTERVAL': 100,
- },
- )
- .onGet(pipelineWithStages.details.stages[0].dropdown_path)
- .reply(200, stageReply);
-
- createComponent();
- });
-
- describe('when a request is being made', () => {
- it('stops polling, cancels the request, & restarts polling', () => {
- const stopMock = jest.spyOn(wrapper.vm.poll, 'stop');
- const restartMock = jest.spyOn(wrapper.vm.poll, 'restart');
- const cancelMock = jest.spyOn(wrapper.vm.service.cancelationSource, 'cancel');
- mock.onGet('twitter/flight/pipelines.json').reply(200, pipelines);
-
- return waitForPromises()
- .then(() => {
- wrapper.vm.isMakingRequest = true;
- wrapper.find('.js-builds-dropdown-button').trigger('click');
- })
- .then(() => {
- expect(cancelMock).toHaveBeenCalled();
- expect(stopMock).toHaveBeenCalled();
- expect(restartMock).toHaveBeenCalled();
- });
- });
- });
-
- describe('when no request is being made', () => {
- it('stops polling & restarts polling', () => {
- const stopMock = jest.spyOn(wrapper.vm.poll, 'stop');
- const restartMock = jest.spyOn(wrapper.vm.poll, 'restart');
- mock.onGet('twitter/flight/pipelines.json').reply(200, pipelines);
-
- return waitForPromises()
- .then(() => {
- wrapper.find('.js-builds-dropdown-button').trigger('click');
- expect(stopMock).toHaveBeenCalled();
- })
- .then(() => {
- expect(restartMock).toHaveBeenCalled();
- });
- });
- });
- });
-
describe('Pipeline filters', () => {
let updateContentMock;
diff --git a/spec/frontend/pipelines/pipelines_table_row_spec.js b/spec/frontend/pipelines/pipelines_table_row_spec.js
index 9901f476f1b..32d53c0f1f8 100644
--- a/spec/frontend/pipelines/pipelines_table_row_spec.js
+++ b/spec/frontend/pipelines/pipelines_table_row_spec.js
@@ -181,7 +181,9 @@ describe('Pipelines Table Row', () => {
it('should render the provided actions', () => {
expect(wrapper.find('.js-pipelines-retry-button').exists()).toBe(true);
+ expect(wrapper.find('.js-pipelines-retry-button').attributes('title')).toMatch('Retry');
expect(wrapper.find('.js-pipelines-cancel-button').exists()).toBe(true);
+ expect(wrapper.find('.js-pipelines-cancel-button').attributes('title')).toMatch('Cancel');
const dropdownMenu = wrapper.find('.dropdown-menu');
expect(dropdownMenu.text()).toContain(scheduledJobAction.name);
diff --git a/spec/frontend/pipelines/test_reports/mock_data.js b/spec/frontend/pipelines/test_reports/mock_data.js
index 1d03f0b655f..c3ca1429842 100644
--- a/spec/frontend/pipelines/test_reports/mock_data.js
+++ b/spec/frontend/pipelines/test_reports/mock_data.js
@@ -3,10 +3,29 @@ import { TestStatus } from '~/pipelines/constants';
export default [
{
classname: 'spec.test_spec',
+ file: 'spec/trace_spec.rb',
execution_time: 0,
name: 'Test#skipped text',
stack_trace: null,
status: TestStatus.SKIPPED,
system_output: null,
},
+ {
+ classname: 'spec.test_spec',
+ file: 'spec/trace_spec.rb',
+ execution_time: 0,
+ name: 'Test#error text',
+ stack_trace: null,
+ status: TestStatus.ERROR,
+ system_output: null,
+ },
+ {
+ classname: 'spec.test_spec',
+ file: 'spec/trace_spec.rb',
+ execution_time: 0,
+ name: 'Test#unknown text',
+ stack_trace: null,
+ status: TestStatus.UNKNOWN,
+ system_output: null,
+ },
];
diff --git a/spec/frontend/pipelines/test_reports/test_suite_table_spec.js b/spec/frontend/pipelines/test_reports/test_suite_table_spec.js
index 2feb6aa5799..838e0606375 100644
--- a/spec/frontend/pipelines/test_reports/test_suite_table_spec.js
+++ b/spec/frontend/pipelines/test_reports/test_suite_table_spec.js
@@ -1,6 +1,7 @@
import Vuex from 'vuex';
import { shallowMount, createLocalVue } from '@vue/test-utils';
import { getJSONFixture } from 'helpers/fixtures';
+import { GlButton } from '@gitlab/ui';
import SuiteTable from '~/pipelines/components/test_reports/test_suite_table.vue';
import * as getters from '~/pipelines/stores/test_reports/getters';
import { TestStatus } from '~/pipelines/constants';
@@ -61,18 +62,27 @@ describe('Test reports suite table', () => {
expect(allCaseRows().length).toBe(testCases.length);
});
- it('renders the correct icon for each status', () => {
- const failedTest = testCases.findIndex(x => x.status === TestStatus.FAILED);
- const skippedTest = testCases.findIndex(x => x.status === TestStatus.SKIPPED);
- const successTest = testCases.findIndex(x => x.status === TestStatus.SUCCESS);
+ it.each([
+ TestStatus.ERROR,
+ TestStatus.FAILED,
+ TestStatus.SKIPPED,
+ TestStatus.SUCCESS,
+ 'unknown',
+ ])('renders the correct icon for test case with %s status', status => {
+ const test = testCases.findIndex(x => x.status === status);
+ const row = findCaseRowAtIndex(test);
- const failedRow = findCaseRowAtIndex(failedTest);
- const skippedRow = findCaseRowAtIndex(skippedTest);
- const successRow = findCaseRowAtIndex(successTest);
+ expect(findIconForRow(row, status).exists()).toBe(true);
+ });
+
+ it('renders the file name for the test with a copy button', () => {
+ const { file } = testCases[0];
+ const row = findCaseRowAtIndex(0);
+ const button = row.find(GlButton);
- expect(findIconForRow(failedRow, TestStatus.FAILED).exists()).toBe(true);
- expect(findIconForRow(skippedRow, TestStatus.SKIPPED).exists()).toBe(true);
- expect(findIconForRow(successRow, TestStatus.SUCCESS).exists()).toBe(true);
+ expect(row.text()).toContain(file);
+ expect(button.exists()).toBe(true);
+ expect(button.attributes('data-clipboard-text')).toBe(file);
});
});
});
diff --git a/spec/frontend/project_find_file_spec.js b/spec/frontend/project_find_file_spec.js
index 757a02a04a3..6a50f68a4e9 100644
--- a/spec/frontend/project_find_file_spec.js
+++ b/spec/frontend/project_find_file_spec.js
@@ -1,11 +1,12 @@
import MockAdapter from 'axios-mock-adapter';
import $ from 'jquery';
import { TEST_HOST } from 'helpers/test_constants';
-import { sanitize } from 'dompurify';
+import { sanitize } from '~/lib/dompurify';
import ProjectFindFile from '~/project_find_file';
import axios from '~/lib/utils/axios_utils';
-jest.mock('dompurify', () => ({
+jest.mock('~/lib/dompurify', () => ({
+ addHook: jest.fn(),
sanitize: jest.fn(val => val),
}));
diff --git a/spec/frontend/projects/commit_box/info/load_branches_spec.js b/spec/frontend/projects/commit_box/info/load_branches_spec.js
new file mode 100644
index 00000000000..ebd4ee45dab
--- /dev/null
+++ b/spec/frontend/projects/commit_box/info/load_branches_spec.js
@@ -0,0 +1,68 @@
+import axios from 'axios';
+import waitForPromises from 'helpers/wait_for_promises';
+import MockAdapter from 'axios-mock-adapter';
+import { loadBranches } from '~/projects/commit_box/info/load_branches';
+
+const mockCommitPath = '/commit/abcd/branches';
+const mockBranchesRes =
+ '<a href="/-/commits/master">master</a><span><a href="/-/commits/my-branch">my-branch</a></span>';
+
+describe('~/projects/commit_box/info/load_branches', () => {
+ let mock;
+ let el;
+
+ beforeEach(() => {
+ mock = new MockAdapter(axios);
+ mock.onGet(mockCommitPath).reply(200, mockBranchesRes);
+
+ el = document.createElement('div');
+ el.dataset.commitPath = mockCommitPath;
+ el.innerHTML = '<div class="commit-info branches"><span class="spinner"/></div>';
+ });
+
+ it('loads and renders branches info', async () => {
+ loadBranches(el);
+ await waitForPromises();
+
+ expect(el.innerHTML).toBe(`<div class="commit-info branches">${mockBranchesRes}</div>`);
+ });
+
+ it('does not load when no container is provided', async () => {
+ loadBranches(null);
+ await waitForPromises();
+
+ expect(mock.history.get).toHaveLength(0);
+ });
+
+ describe('when braches request returns unsafe content', () => {
+ beforeEach(() => {
+ mock
+ .onGet(mockCommitPath)
+ .reply(200, '<a onload="alert(\'xss!\');" href="/-/commits/master">master</a>');
+ });
+
+ it('displays sanitized html', async () => {
+ loadBranches(el);
+ await waitForPromises();
+
+ expect(el.innerHTML).toBe(
+ '<div class="commit-info branches"><a href="/-/commits/master">master</a></div>',
+ );
+ });
+ });
+
+ describe('when braches request fails', () => {
+ beforeEach(() => {
+ mock.onGet(mockCommitPath).reply(500, 'Error!');
+ });
+
+ it('attempts to load and renders an error', async () => {
+ loadBranches(el);
+ await waitForPromises();
+
+ expect(el.innerHTML).toBe(
+ '<div class="commit-info branches">Failed to load branches. Please try again.</div>',
+ );
+ });
+ });
+});
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 455467e7b29..a0fd6012546 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
@@ -17,6 +17,7 @@ exports[`Project remove modal initialized matches the snapshot 1`] = `
/>
<gl-button-stub
+ buttontextclasses=""
category="primary"
icon=""
role="button"
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 692b8f6cf52..4630415f61c 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
@@ -18,6 +18,7 @@ exports[`Project remove modal intialized matches the snapshot 1`] = `
/>
<gl-button-stub
+ buttontextclasses=""
category="primary"
icon=""
role="button"
@@ -84,6 +85,7 @@ exports[`Project remove modal intialized matches the snapshot 1`] = `
<template>
<gl-button-stub
+ buttontextclasses=""
category="primary"
class="js-modal-action-cancel"
icon=""
@@ -98,6 +100,7 @@ exports[`Project remove modal intialized matches the snapshot 1`] = `
<!---->
<gl-button-stub
+ buttontextclasses=""
category="primary"
class="js-modal-action-primary"
disabled="true"
diff --git a/spec/frontend/projects/settings/access_dropdown_spec.js b/spec/frontend/projects/settings/access_dropdown_spec.js
index 3b375c5610f..41b9c0c3763 100644
--- a/spec/frontend/projects/settings/access_dropdown_spec.js
+++ b/spec/frontend/projects/settings/access_dropdown_spec.js
@@ -14,6 +14,7 @@ describe('AccessDropdown', () => {
`);
const $dropdown = $('#dummy-dropdown');
$dropdown.data('defaultLabel', defaultLabel);
+ gon.features = { deployKeysOnProtectedBranches: true };
const options = {
$dropdown,
accessLevelsData: {
@@ -37,6 +38,9 @@ describe('AccessDropdown', () => {
{ type: LEVEL_TYPES.GROUP },
{ type: LEVEL_TYPES.GROUP },
{ type: LEVEL_TYPES.GROUP },
+ { type: LEVEL_TYPES.DEPLOY_KEY },
+ { type: LEVEL_TYPES.DEPLOY_KEY },
+ { type: LEVEL_TYPES.DEPLOY_KEY },
];
beforeEach(() => {
@@ -49,7 +53,7 @@ describe('AccessDropdown', () => {
const label = dropdown.toggleLabel();
- expect(label).toBe('1 role, 2 users, 3 groups');
+ expect(label).toBe('1 role, 2 users, 3 deploy keys, 3 groups');
expect($dropdownToggleText).not.toHaveClass('is-default');
});
@@ -122,6 +126,21 @@ describe('AccessDropdown', () => {
expect($dropdownToggleText).not.toHaveClass('is-default');
});
});
+
+ describe('with users and deploy keys', () => {
+ beforeEach(() => {
+ const selectedTypes = [LEVEL_TYPES.DEPLOY_KEY, LEVEL_TYPES.USER];
+ dropdown.setSelectedItems(dummyItems.filter(item => selectedTypes.includes(item.type)));
+ $dropdownToggleText.addClass('is-default');
+ });
+
+ it('displays number of deploy keys', () => {
+ const label = dropdown.toggleLabel();
+
+ expect(label).toBe('2 users, 3 deploy keys');
+ expect($dropdownToggleText).not.toHaveClass('is-default');
+ });
+ });
});
describe('userRowHtml', () => {
diff --git a/spec/frontend/projects/settings_service_desk/components/service_desk_root_spec.js b/spec/frontend/projects/settings_service_desk/components/service_desk_root_spec.js
index 0f3b699f6b2..62aeb4ddee5 100644
--- a/spec/frontend/projects/settings_service_desk/components/service_desk_root_spec.js
+++ b/spec/frontend/projects/settings_service_desk/components/service_desk_root_spec.js
@@ -218,9 +218,7 @@ describe('ServiceDeskRoot', () => {
.$nextTick()
.then(waitForPromises)
.then(() => {
- expect(wrapper.html()).toContain(
- 'An error occurred while saving the template. Please check if the template exists.',
- );
+ expect(wrapper.html()).toContain('An error occured while making the changes:');
});
});
});
diff --git a/spec/frontend/ref/components/ref_selector_spec.js b/spec/frontend/ref/components/ref_selector_spec.js
index 00b1d5cfbe2..5eee22f479e 100644
--- a/spec/frontend/ref/components/ref_selector_spec.js
+++ b/spec/frontend/ref/components/ref_selector_spec.js
@@ -313,7 +313,7 @@ describe('Ref selector component', () => {
findBranchesSection()
.find('[data-testid="section-header"]')
.text(),
- ).toBe('Branches 123');
+ ).toMatchInterpolatedText('Branches 123');
});
it("does not render an error message in the branches section's body", () => {
@@ -392,7 +392,7 @@ describe('Ref selector component', () => {
findTagsSection()
.find('[data-testid="section-header"]')
.text(),
- ).toBe('Tags 456');
+ ).toMatchInterpolatedText('Tags 456');
});
it("does not render an error message in the tags section's body", () => {
@@ -460,7 +460,7 @@ describe('Ref selector component', () => {
findCommitsSection()
.find('[data-testid="section-header"]')
.text(),
- ).toBe('Commits 1');
+ ).toMatchInterpolatedText('Commits 1');
});
it("does not render an error message in the comits section's body", () => {
diff --git a/spec/frontend/registry/explorer/components/details_page/partial_cleanup_alert_spec.js b/spec/frontend/registry/explorer/components/details_page/partial_cleanup_alert_spec.js
new file mode 100644
index 00000000000..17821d8be31
--- /dev/null
+++ b/spec/frontend/registry/explorer/components/details_page/partial_cleanup_alert_spec.js
@@ -0,0 +1,71 @@
+import { shallowMount } from '@vue/test-utils';
+import { GlAlert, GlSprintf } from '@gitlab/ui';
+import component from '~/registry/explorer/components/details_page/partial_cleanup_alert.vue';
+import { DELETE_ALERT_TITLE, DELETE_ALERT_LINK_TEXT } from '~/registry/explorer/constants';
+
+describe('Partial Cleanup alert', () => {
+ let wrapper;
+
+ const findAlert = () => wrapper.find(GlAlert);
+ const findRunLink = () => wrapper.find('[data-testid="run-link"');
+ const findHelpLink = () => wrapper.find('[data-testid="help-link"');
+
+ const mountComponent = () => {
+ wrapper = shallowMount(component, {
+ stubs: { GlSprintf },
+ propsData: {
+ runCleanupPoliciesHelpPagePath: 'foo',
+ cleanupPoliciesHelpPagePath: 'bar',
+ },
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ wrapper = null;
+ });
+
+ it(`gl-alert has the correct properties`, () => {
+ mountComponent();
+
+ expect(findAlert().props()).toMatchObject({
+ title: DELETE_ALERT_TITLE,
+ variant: 'warning',
+ });
+ });
+
+ it('has the right text', () => {
+ mountComponent();
+
+ expect(wrapper.text()).toMatchInterpolatedText(DELETE_ALERT_LINK_TEXT);
+ });
+
+ it('contains run link', () => {
+ mountComponent();
+
+ const link = findRunLink();
+ expect(link.exists()).toBe(true);
+ expect(link.attributes()).toMatchObject({
+ href: 'foo',
+ target: '_blank',
+ });
+ });
+
+ it('contains help link', () => {
+ mountComponent();
+
+ const link = findHelpLink();
+ expect(link.exists()).toBe(true);
+ expect(link.attributes()).toMatchObject({
+ href: 'bar',
+ target: '_blank',
+ });
+ });
+
+ it('GlAlert dismiss event triggers a dismiss event', () => {
+ mountComponent();
+
+ findAlert().vm.$emit('dismiss');
+ expect(wrapper.emitted('dismiss')).toEqual([[]]);
+ });
+});
diff --git a/spec/frontend/registry/explorer/components/list_page/image_list_row_spec.js b/spec/frontend/registry/explorer/components/list_page/image_list_row_spec.js
index c5b4b3fa5d8..ce446e6d93e 100644
--- a/spec/frontend/registry/explorer/components/list_page/image_list_row_spec.js
+++ b/spec/frontend/registry/explorer/components/list_page/image_list_row_spec.js
@@ -9,6 +9,8 @@ import {
ROW_SCHEDULED_FOR_DELETION,
LIST_DELETE_BUTTON_DISABLED,
REMOVE_REPOSITORY_LABEL,
+ ASYNC_DELETE_IMAGE_ERROR_MESSAGE,
+ CLEANUP_TIMED_OUT_ERROR_MESSAGE,
} from '~/registry/explorer/constants';
import { RouterLink } from '../../stubs';
import { imagesListResponse } from '../../mock_data';
@@ -21,6 +23,7 @@ describe('Image List Row', () => {
const findTagsCount = () => wrapper.find('[data-testid="tagsCount"]');
const findDeleteBtn = () => wrapper.find(DeleteButton);
const findClipboardButton = () => wrapper.find(ClipboardButton);
+ const findWarningIcon = () => wrapper.find('[data-testid="warning-icon"]');
const mountComponent = props => {
wrapper = shallowMount(Component, {
@@ -74,6 +77,26 @@ describe('Image List Row', () => {
expect(button.props('text')).toBe(item.location);
expect(button.props('title')).toBe(item.location);
});
+
+ describe('warning icon', () => {
+ it.each`
+ failedDelete | cleanup_policy_started_at | shown | title
+ ${true} | ${true} | ${true} | ${ASYNC_DELETE_IMAGE_ERROR_MESSAGE}
+ ${false} | ${true} | ${true} | ${CLEANUP_TIMED_OUT_ERROR_MESSAGE}
+ ${false} | ${false} | ${false} | ${''}
+ `(
+ 'when failedDelete is $failedDelete and cleanup_policy_started_at is $cleanup_policy_started_at',
+ ({ cleanup_policy_started_at, failedDelete, shown, title }) => {
+ mountComponent({ item: { ...item, failedDelete, cleanup_policy_started_at } });
+ const icon = findWarningIcon();
+ expect(icon.exists()).toBe(shown);
+ if (shown) {
+ const tooltip = getBinding(icon.element, 'gl-tooltip');
+ expect(tooltip.value.title).toBe(title);
+ }
+ },
+ );
+ });
});
describe('delete button', () => {
diff --git a/spec/frontend/registry/explorer/components/list_page/registry_header_spec.js b/spec/frontend/registry/explorer/components/list_page/registry_header_spec.js
index 7a27f8fa431..3c997093d46 100644
--- a/spec/frontend/registry/explorer/components/list_page/registry_header_spec.js
+++ b/spec/frontend/registry/explorer/components/list_page/registry_header_spec.js
@@ -1,5 +1,5 @@
import { shallowMount } from '@vue/test-utils';
-import { GlSprintf, GlLink } from '@gitlab/ui';
+import { GlSprintf } from '@gitlab/ui';
import Component from '~/registry/explorer/components/list_page/registry_header.vue';
import TitleArea from '~/vue_shared/components/registry/title_area.vue';
import {
@@ -19,12 +19,8 @@ describe('registry_header', () => {
const findTitleArea = () => wrapper.find(TitleArea);
const findCommandsSlot = () => wrapper.find('[data-testid="commands-slot"]');
- const findInfoArea = () => wrapper.find('[data-testid="info-area"]');
- const findIntroText = () => wrapper.find('[data-testid="default-intro"]');
const findImagesCountSubHeader = () => wrapper.find('[data-testid="images-count"]');
const findExpirationPolicySubHeader = () => wrapper.find('[data-testid="expiration-policy"]');
- const findDisabledExpirationPolicyMessage = () =>
- wrapper.find('[data-testid="expiration-disabled-message"]');
const mountComponent = (propsData, slots) => {
wrapper = shallowMount(Component, {
@@ -123,44 +119,18 @@ describe('registry_header', () => {
});
});
- describe('info area', () => {
- it('exists', () => {
- mountComponent();
-
- expect(findInfoArea().exists()).toBe(true);
- });
-
+ describe('info messages', () => {
describe('default message', () => {
- beforeEach(() => {
- return mountComponent({ helpPagePath: 'bar' });
- });
-
- it('exists', () => {
- expect(findIntroText().exists()).toBe(true);
- });
-
- it('has the correct copy', () => {
- expect(findIntroText().text()).toMatchInterpolatedText(LIST_INTRO_TEXT);
- });
+ it('is correctly bound to title_area props', () => {
+ mountComponent({ helpPagePath: 'foo' });
- it('has the correct link', () => {
- expect(
- findIntroText()
- .find(GlLink)
- .attributes('href'),
- ).toBe('bar');
+ expect(findTitleArea().props('infoMessages')).toEqual([
+ { text: LIST_INTRO_TEXT, link: 'foo' },
+ ]);
});
});
describe('expiration policy info message', () => {
- describe('when there are no images', () => {
- it('is hidden', () => {
- mountComponent();
-
- expect(findDisabledExpirationPolicyMessage().exists()).toBe(false);
- });
- });
-
describe('when there are images', () => {
describe('when expiration policy is disabled', () => {
beforeEach(() => {
@@ -170,43 +140,27 @@ describe('registry_header', () => {
imagesCount: 1,
});
});
- it('message exist', () => {
- expect(findDisabledExpirationPolicyMessage().exists()).toBe(true);
- });
- it('has the correct copy', () => {
- expect(findDisabledExpirationPolicyMessage().text()).toMatchInterpolatedText(
- EXPIRATION_POLICY_DISABLED_MESSAGE,
- );
- });
- it('has the correct link', () => {
- expect(
- findDisabledExpirationPolicyMessage()
- .find(GlLink)
- .attributes('href'),
- ).toBe('foo');
+ it('the prop is correctly bound', () => {
+ expect(findTitleArea().props('infoMessages')).toEqual([
+ { text: LIST_INTRO_TEXT, link: '' },
+ { text: EXPIRATION_POLICY_DISABLED_MESSAGE, link: 'foo' },
+ ]);
});
});
- describe('when expiration policy is enabled', () => {
+ describe.each`
+ desc | props
+ ${'when there are no images'} | ${{ expirationPolicy: { enabled: false }, imagesCount: 0 }}
+ ${'when expiration policy is enabled'} | ${{ expirationPolicy: { enabled: true }, imagesCount: 1 }}
+ ${'when the expiration policy is completely disabled'} | ${{ expirationPolicy: { enabled: false }, imagesCount: 1, hideExpirationPolicyData: true }}
+ `('$desc', ({ props }) => {
it('message does not exist', () => {
- mountComponent({
- expirationPolicy: { enabled: true },
- imagesCount: 1,
- });
-
- expect(findDisabledExpirationPolicyMessage().exists()).toBe(false);
- });
- });
- describe('when the expiration policy is completely disabled', () => {
- it('message does not exist', () => {
- mountComponent({
- expirationPolicy: { enabled: true },
- imagesCount: 1,
- hideExpirationPolicyData: true,
- });
+ mountComponent(props);
- expect(findDisabledExpirationPolicyMessage().exists()).toBe(false);
+ expect(findTitleArea().props('infoMessages')).toEqual([
+ { text: LIST_INTRO_TEXT, link: '' },
+ ]);
});
});
});
diff --git a/spec/frontend/registry/explorer/pages/details_spec.js b/spec/frontend/registry/explorer/pages/details_spec.js
index 66e8a4aea0d..86b52c4f06a 100644
--- a/spec/frontend/registry/explorer/pages/details_spec.js
+++ b/spec/frontend/registry/explorer/pages/details_spec.js
@@ -3,6 +3,7 @@ import { GlPagination } from '@gitlab/ui';
import Tracking from '~/tracking';
import component from '~/registry/explorer/pages/details.vue';
import DeleteAlert from '~/registry/explorer/components/details_page/delete_alert.vue';
+import PartialCleanupAlert from '~/registry/explorer/components/details_page/partial_cleanup_alert.vue';
import DetailsHeader from '~/registry/explorer/components/details_page/details_header.vue';
import TagsLoader from '~/registry/explorer/components/details_page/tags_loader.vue';
import TagsList from '~/registry/explorer/components/details_page/tags_list.vue';
@@ -30,8 +31,10 @@ describe('Details Page', () => {
const findDeleteAlert = () => wrapper.find(DeleteAlert);
const findDetailsHeader = () => wrapper.find(DetailsHeader);
const findEmptyTagsState = () => wrapper.find(EmptyTagsState);
+ const findPartialCleanupAlert = () => wrapper.find(PartialCleanupAlert);
- const routeId = window.btoa(JSON.stringify({ name: 'foo', tags_path: 'bar' }));
+ const routeIdGenerator = override =>
+ window.btoa(JSON.stringify({ name: 'foo', tags_path: 'bar', ...override }));
const tagsArrayToSelectedTags = tags =>
tags.reduce((acc, c) => {
@@ -39,7 +42,7 @@ describe('Details Page', () => {
return acc;
}, {});
- const mountComponent = options => {
+ const mountComponent = ({ options, routeParams } = {}) => {
wrapper = shallowMount(component, {
store,
stubs: {
@@ -48,7 +51,7 @@ describe('Details Page', () => {
mocks: {
$route: {
params: {
- id: routeId,
+ id: routeIdGenerator(routeParams),
},
},
},
@@ -224,7 +227,7 @@ describe('Details Page', () => {
findDeleteModal().vm.$emit('confirmDelete');
expect(dispatchSpy).toHaveBeenCalledWith('requestDeleteTag', {
tag: store.state.tags[0],
- params: routeId,
+ params: routeIdGenerator(),
});
});
});
@@ -239,7 +242,7 @@ describe('Details Page', () => {
findDeleteModal().vm.$emit('confirmDelete');
expect(dispatchSpy).toHaveBeenCalledWith('requestDeleteTags', {
ids: store.state.tags.map(t => t.name),
- params: routeId,
+ params: routeIdGenerator(),
});
});
});
@@ -273,11 +276,57 @@ describe('Details Page', () => {
it('has the correct props', () => {
store.commit(SET_INITIAL_STATE, { ...config });
mountComponent({
- data: () => ({
- deleteAlertType,
- }),
+ options: {
+ data: () => ({
+ deleteAlertType,
+ }),
+ },
});
expect(findDeleteAlert().props()).toEqual({ ...config, deleteAlertType });
});
});
+
+ describe('Partial Cleanup Alert', () => {
+ const config = {
+ runCleanupPoliciesHelpPagePath: 'foo',
+ cleanupPoliciesHelpPagePath: 'bar',
+ };
+
+ describe('when expiration_policy_started is not null', () => {
+ const routeParams = { cleanup_policy_started_at: Date.now().toString() };
+
+ it('exists', () => {
+ mountComponent({ routeParams });
+
+ expect(findPartialCleanupAlert().exists()).toBe(true);
+ });
+
+ it('has the correct props', () => {
+ store.commit(SET_INITIAL_STATE, { ...config });
+
+ mountComponent({ routeParams });
+
+ expect(findPartialCleanupAlert().props()).toEqual({ ...config });
+ });
+
+ it('dismiss hides the component', async () => {
+ mountComponent({ routeParams });
+
+ expect(findPartialCleanupAlert().exists()).toBe(true);
+ findPartialCleanupAlert().vm.$emit('dismiss');
+
+ await wrapper.vm.$nextTick();
+
+ expect(findPartialCleanupAlert().exists()).toBe(false);
+ });
+ });
+
+ describe('when expiration_policy_started is null', () => {
+ it('the component is hidden', () => {
+ mountComponent();
+
+ expect(findPartialCleanupAlert().exists()).toBe(false);
+ });
+ });
+ });
});
diff --git a/spec/frontend/registry/settings/components/__snapshots__/registry_settings_app_spec.js.snap b/spec/frontend/registry/settings/components/__snapshots__/registry_settings_app_spec.js.snap
deleted file mode 100644
index 11393c89d06..00000000000
--- a/spec/frontend/registry/settings/components/__snapshots__/registry_settings_app_spec.js.snap
+++ /dev/null
@@ -1,7 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`Registry Settings App renders 1`] = `
-<div>
- <settings-form-stub />
-</div>
-`;
diff --git a/spec/frontend/registry/settings/components/registry_settings_app_spec.js b/spec/frontend/registry/settings/components/registry_settings_app_spec.js
index 9551ee72e51..a784396f47a 100644
--- a/spec/frontend/registry/settings/components/registry_settings_app_spec.js
+++ b/spec/frontend/registry/settings/components/registry_settings_app_spec.js
@@ -1,28 +1,35 @@
-import { shallowMount } from '@vue/test-utils';
+import { shallowMount, createLocalVue } from '@vue/test-utils';
+import VueApollo from 'vue-apollo';
import { GlAlert, GlSprintf, GlLink } from '@gitlab/ui';
+import createMockApollo from 'jest/helpers/mock_apollo_helper';
import component from '~/registry/settings/components/registry_settings_app.vue';
+import expirationPolicyQuery from '~/registry/settings/graphql/queries/get_expiration_policy.graphql';
import SettingsForm from '~/registry/settings/components/settings_form.vue';
-import { createStore } from '~/registry/settings/store/';
-import { SET_SETTINGS, SET_INITIAL_STATE } from '~/registry/settings/store/mutation_types';
import { FETCH_SETTINGS_ERROR_MESSAGE } from '~/registry/shared/constants';
import {
UNAVAILABLE_FEATURE_INTRO_TEXT,
UNAVAILABLE_USER_FEATURE_TEXT,
} from '~/registry/settings/constants';
-import { stringifiedFormOptions } from '../../shared/mock_data';
+import { expirationPolicyPayload, emptyExpirationPolicyPayload } from '../mock_data';
+
+const localVue = createLocalVue();
describe('Registry Settings App', () => {
let wrapper;
- let store;
+ let fakeApollo;
+
+ const defaultProvidedValues = {
+ projectPath: 'path',
+ isAdmin: false,
+ adminSettingsPath: 'settingsPath',
+ enableHistoricEntries: false,
+ };
const findSettingsComponent = () => wrapper.find(SettingsForm);
const findAlert = () => wrapper.find(GlAlert);
- const mountComponent = ({ dispatchMock = 'mockResolvedValue' } = {}) => {
- const dispatchSpy = jest.spyOn(store, 'dispatch');
- dispatchSpy[dispatchMock]();
-
+ const mountComponent = (provide = defaultProvidedValues, config) => {
wrapper = shallowMount(component, {
stubs: {
GlSprintf,
@@ -32,71 +39,72 @@ describe('Registry Settings App', () => {
show: jest.fn(),
},
},
- store,
+ provide,
+ ...config,
});
};
- beforeEach(() => {
- store = createStore();
- });
+ const mountComponentWithApollo = ({ provide = defaultProvidedValues, resolver } = {}) => {
+ localVue.use(VueApollo);
+
+ const requestHandlers = [[expirationPolicyQuery, resolver]];
+
+ fakeApollo = createMockApollo(requestHandlers);
+ mountComponent(provide, {
+ localVue,
+ apolloProvider: fakeApollo,
+ });
+
+ return requestHandlers.map(request => request[1]);
+ };
afterEach(() => {
wrapper.destroy();
});
- it('renders', () => {
- store.commit(SET_SETTINGS, { foo: 'bar' });
- mountComponent();
- expect(wrapper.element).toMatchSnapshot();
- });
-
- it('call the store function to load the data on mount', () => {
- mountComponent();
- expect(store.dispatch).toHaveBeenCalledWith('fetchSettings');
- });
+ it('renders the setting form', async () => {
+ const requests = mountComponentWithApollo({
+ resolver: jest.fn().mockResolvedValue(expirationPolicyPayload()),
+ });
+ await Promise.all(requests);
- it('renders the setting form', () => {
- store.commit(SET_SETTINGS, { foo: 'bar' });
- mountComponent();
expect(findSettingsComponent().exists()).toBe(true);
});
describe('the form is disabled', () => {
- beforeEach(() => {
- store.commit(SET_SETTINGS, undefined);
+ it('the form is hidden', () => {
mountComponent();
- });
- it('the form is hidden', () => {
expect(findSettingsComponent().exists()).toBe(false);
});
it('shows an alert', () => {
+ mountComponent();
+
const text = findAlert().text();
expect(text).toContain(UNAVAILABLE_FEATURE_INTRO_TEXT);
expect(text).toContain(UNAVAILABLE_USER_FEATURE_TEXT);
});
describe('an admin is visiting the page', () => {
- beforeEach(() => {
- store.commit(SET_INITIAL_STATE, {
- ...stringifiedFormOptions,
- isAdmin: true,
- adminSettingsPath: 'foo',
- });
- });
-
it('shows the admin part of the alert message', () => {
+ mountComponent({ ...defaultProvidedValues, isAdmin: true });
+
const sprintf = findAlert().find(GlSprintf);
expect(sprintf.text()).toBe('administration settings');
- expect(sprintf.find(GlLink).attributes('href')).toBe('foo');
+ expect(sprintf.find(GlLink).attributes('href')).toBe(
+ defaultProvidedValues.adminSettingsPath,
+ );
});
});
});
describe('fetchSettingsError', () => {
beforeEach(() => {
- mountComponent({ dispatchMock: 'mockRejectedValue' });
+ const requests = mountComponentWithApollo({
+ resolver: jest.fn().mockRejectedValue(new Error('GraphQL error')),
+ });
+ return Promise.all(requests);
});
it('the form is hidden', () => {
@@ -107,4 +115,23 @@ describe('Registry Settings App', () => {
expect(findAlert().html()).toContain(FETCH_SETTINGS_ERROR_MESSAGE);
});
});
+
+ describe('empty API response', () => {
+ it.each`
+ enableHistoricEntries | isShown
+ ${true} | ${true}
+ ${false} | ${false}
+ `('is $isShown that the form is shown', async ({ enableHistoricEntries, isShown }) => {
+ const requests = mountComponentWithApollo({
+ provide: {
+ ...defaultProvidedValues,
+ enableHistoricEntries,
+ },
+ resolver: jest.fn().mockResolvedValue(emptyExpirationPolicyPayload()),
+ });
+ await Promise.all(requests);
+
+ expect(findSettingsComponent().exists()).toBe(isShown);
+ });
+ });
});
diff --git a/spec/frontend/registry/settings/components/settings_form_spec.js b/spec/frontend/registry/settings/components/settings_form_spec.js
index 6f9518808db..4346cfadcc8 100644
--- a/spec/frontend/registry/settings/components/settings_form_spec.js
+++ b/spec/frontend/registry/settings/components/settings_form_spec.js
@@ -1,30 +1,37 @@
-import { shallowMount } from '@vue/test-utils';
+import { shallowMount, createLocalVue } from '@vue/test-utils';
+import VueApollo from 'vue-apollo';
+import createMockApollo from 'jest/helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises';
import Tracking from '~/tracking';
import component from '~/registry/settings/components/settings_form.vue';
import expirationPolicyFields from '~/registry/shared/components/expiration_policy_fields.vue';
-import { createStore } from '~/registry/settings/store/';
+import updateContainerExpirationPolicyMutation from '~/registry/settings/graphql/mutations/update_container_expiration_policy.graphql';
+import expirationPolicyQuery from '~/registry/settings/graphql/queries/get_expiration_policy.graphql';
import {
UPDATE_SETTINGS_ERROR_MESSAGE,
UPDATE_SETTINGS_SUCCESS_MESSAGE,
} from '~/registry/shared/constants';
-import { stringifiedFormOptions } from '../../shared/mock_data';
+import { GlCard, GlLoadingIcon } from '../../shared/stubs';
+import { expirationPolicyPayload, expirationPolicyMutationPayload } from '../mock_data';
+
+const localVue = createLocalVue();
describe('Settings Form', () => {
let wrapper;
- let store;
- let dispatchSpy;
-
- const GlLoadingIcon = { name: 'gl-loading-icon-stub', template: '<svg></svg>' };
- const GlCard = {
- name: 'gl-card-stub',
- template: `
- <div>
- <slot name="header"></slot>
- <slot></slot>
- <slot name="footer"></slot>
- </div>
- `,
+ let fakeApollo;
+
+ const defaultProvidedValues = {
+ projectPath: 'path',
+ };
+
+ const {
+ data: {
+ project: { containerExpirationPolicy },
+ },
+ } = expirationPolicyPayload();
+
+ const defaultProps = {
+ value: { ...containerExpirationPolicy },
};
const trackingPayload = {
@@ -35,14 +42,21 @@ describe('Settings Form', () => {
const findFields = () => wrapper.find(expirationPolicyFields);
const findCancelButton = () => wrapper.find({ ref: 'cancel-button' });
const findSaveButton = () => wrapper.find({ ref: 'save-button' });
- const findLoadingIcon = (parent = wrapper) => parent.find(GlLoadingIcon);
- const mountComponent = (data = {}) => {
+ const mountComponent = ({
+ props = defaultProps,
+ data,
+ config,
+ provide = defaultProvidedValues,
+ mocks,
+ } = {}) => {
wrapper = shallowMount(component, {
stubs: {
GlCard,
GlLoadingIcon,
},
+ propsData: { ...props },
+ provide,
data() {
return {
...data,
@@ -52,15 +66,42 @@ describe('Settings Form', () => {
$toast: {
show: jest.fn(),
},
+ ...mocks,
+ },
+ ...config,
+ });
+ };
+
+ const mountComponentWithApollo = ({ provide = defaultProvidedValues, resolver } = {}) => {
+ localVue.use(VueApollo);
+
+ const requestHandlers = [
+ [updateContainerExpirationPolicyMutation, resolver],
+ [expirationPolicyQuery, jest.fn().mockResolvedValue(expirationPolicyPayload())],
+ ];
+
+ fakeApollo = createMockApollo(requestHandlers);
+
+ fakeApollo.defaultClient.cache.writeQuery({
+ query: expirationPolicyQuery,
+ variables: {
+ projectPath: provide.projectPath,
},
- store,
+ ...expirationPolicyPayload(),
});
+
+ mountComponent({
+ provide,
+ config: {
+ localVue,
+ apolloProvider: fakeApollo,
+ },
+ });
+
+ return requestHandlers.map(resolvers => resolvers[1]);
};
beforeEach(() => {
- store = createStore();
- store.dispatch('setInitialState', stringifiedFormOptions);
- dispatchSpy = jest.spyOn(store, 'dispatch');
jest.spyOn(Tracking, 'event');
});
@@ -72,32 +113,36 @@ describe('Settings Form', () => {
it('v-model change update the settings property', () => {
mountComponent();
findFields().vm.$emit('input', { newValue: 'foo' });
- expect(dispatchSpy).toHaveBeenCalledWith('updateSettings', { settings: 'foo' });
+ expect(wrapper.emitted('input')).toEqual([['foo']]);
});
it('v-model change update the api error property', () => {
const apiErrors = { baz: 'bar' };
- mountComponent({ apiErrors });
+ mountComponent({ data: { apiErrors } });
expect(findFields().props('apiErrors')).toEqual(apiErrors);
findFields().vm.$emit('input', { newValue: 'foo', modified: 'baz' });
expect(findFields().props('apiErrors')).toEqual({});
});
- });
- describe('form', () => {
- let form;
- beforeEach(() => {
- mountComponent();
- form = findForm();
- dispatchSpy.mockReturnValue();
+ it('shows the default option when none are selected', () => {
+ mountComponent({ props: { value: {} } });
+ expect(findFields().props('value')).toEqual({
+ cadence: 'EVERY_DAY',
+ keepN: 'TEN_TAGS',
+ olderThan: 'NINETY_DAYS',
+ });
});
+ });
+ describe('form', () => {
describe('form reset event', () => {
beforeEach(() => {
- form.trigger('reset');
+ mountComponent();
+
+ findForm().trigger('reset');
});
it('calls the appropriate function', () => {
- expect(dispatchSpy).toHaveBeenCalledWith('resetSettings');
+ expect(wrapper.emitted('reset')).toEqual([[]]);
});
it('tracks the reset event', () => {
@@ -108,54 +153,96 @@ describe('Settings Form', () => {
describe('form submit event ', () => {
it('save has type submit', () => {
mountComponent();
+
expect(findSaveButton().attributes('type')).toBe('submit');
});
- it('dispatches the saveSettings action', () => {
- dispatchSpy.mockResolvedValue();
- form.trigger('submit');
- expect(dispatchSpy).toHaveBeenCalledWith('saveSettings');
+ it('dispatches the correct apollo mutation', async () => {
+ const [expirationPolicyMutationResolver] = mountComponentWithApollo({
+ resolver: jest.fn().mockResolvedValue(expirationPolicyMutationPayload()),
+ });
+
+ findForm().trigger('submit');
+ await expirationPolicyMutationResolver();
+ expect(expirationPolicyMutationResolver).toHaveBeenCalled();
});
it('tracks the submit event', () => {
- dispatchSpy.mockResolvedValue();
- form.trigger('submit');
+ mountComponentWithApollo({
+ resolver: jest.fn().mockResolvedValue(expirationPolicyMutationPayload()),
+ });
+
+ findForm().trigger('submit');
+
expect(Tracking.event).toHaveBeenCalledWith(undefined, 'submit_form', trackingPayload);
});
it('show a success toast when submit succeed', async () => {
- dispatchSpy.mockResolvedValue();
- form.trigger('submit');
- await waitForPromises();
+ const handlers = mountComponentWithApollo({
+ resolver: jest.fn().mockResolvedValue(expirationPolicyMutationPayload()),
+ });
+
+ findForm().trigger('submit');
+ await Promise.all(handlers);
+ await wrapper.vm.$nextTick();
+
expect(wrapper.vm.$toast.show).toHaveBeenCalledWith(UPDATE_SETTINGS_SUCCESS_MESSAGE, {
type: 'success',
});
});
describe('when submit fails', () => {
- it('shows an error', async () => {
- dispatchSpy.mockRejectedValue({ response: {} });
- form.trigger('submit');
- await waitForPromises();
- expect(wrapper.vm.$toast.show).toHaveBeenCalledWith(UPDATE_SETTINGS_ERROR_MESSAGE, {
- type: 'error',
+ describe('user recoverable errors', () => {
+ it('when there is an error is shown in a toast', async () => {
+ const handlers = mountComponentWithApollo({
+ resolver: jest
+ .fn()
+ .mockResolvedValue(expirationPolicyMutationPayload({ errors: ['foo'] })),
+ });
+
+ findForm().trigger('submit');
+ await Promise.all(handlers);
+ await wrapper.vm.$nextTick();
+
+ expect(wrapper.vm.$toast.show).toHaveBeenCalledWith('foo', {
+ type: 'error',
+ });
});
});
+ describe('global errors', () => {
+ it('shows an error', async () => {
+ const handlers = mountComponentWithApollo({
+ resolver: jest.fn().mockRejectedValue(expirationPolicyMutationPayload()),
+ });
- it('parses the error messages', async () => {
- dispatchSpy.mockRejectedValue({
- response: {
- data: {
- message: {
- foo: 'bar',
- 'container_expiration_policy.name': ['baz'],
+ findForm().trigger('submit');
+ await Promise.all(handlers);
+ await wrapper.vm.$nextTick();
+ await wrapper.vm.$nextTick();
+
+ expect(wrapper.vm.$toast.show).toHaveBeenCalledWith(UPDATE_SETTINGS_ERROR_MESSAGE, {
+ type: 'error',
+ });
+ });
+
+ it('parses the error messages', async () => {
+ const mutate = jest.fn().mockRejectedValue({
+ graphQLErrors: [
+ {
+ extensions: {
+ problems: [{ path: ['name'], message: 'baz' }],
+ },
},
- },
- },
+ ],
+ });
+ mountComponent({ mocks: { $apollo: { mutate } } });
+
+ findForm().trigger('submit');
+ await waitForPromises();
+ await wrapper.vm.$nextTick();
+
+ expect(findFields().props('apiErrors')).toEqual({ name: 'baz' });
});
- form.trigger('submit');
- await waitForPromises();
- expect(findFields().props('apiErrors')).toEqual({ name: 'baz' });
});
});
});
@@ -163,51 +250,78 @@ describe('Settings Form', () => {
describe('form actions', () => {
describe('cancel button', () => {
- beforeEach(() => {
- store.commit('SET_SETTINGS', { foo: 'bar' });
+ it('has type reset', () => {
mountComponent();
- });
- it('has type reset', () => {
expect(findCancelButton().attributes('type')).toBe('reset');
});
- it('is disabled when isEdited is false', () =>
- wrapper.vm.$nextTick().then(() => {
- expect(findCancelButton().attributes('disabled')).toBe('true');
- }));
-
- it('is disabled isLoading is true', () => {
- store.commit('TOGGLE_LOADING');
- store.commit('UPDATE_SETTINGS', { settings: { foo: 'baz' } });
- return wrapper.vm.$nextTick().then(() => {
- expect(findCancelButton().attributes('disabled')).toBe('true');
- store.commit('TOGGLE_LOADING');
- });
- });
+ it.each`
+ isLoading | isEdited | mutationLoading | isDisabled
+ ${true} | ${true} | ${true} | ${true}
+ ${false} | ${true} | ${true} | ${true}
+ ${false} | ${false} | ${true} | ${true}
+ ${true} | ${false} | ${false} | ${true}
+ ${false} | ${false} | ${false} | ${true}
+ ${false} | ${true} | ${false} | ${false}
+ `(
+ 'when isLoading is $isLoading and isEdited is $isEdited and mutationLoading is $mutationLoading is $isDisabled that the is disabled',
+ ({ isEdited, isLoading, mutationLoading, isDisabled }) => {
+ mountComponent({
+ props: { ...defaultProps, isEdited, isLoading },
+ data: { mutationLoading },
+ });
- it('is enabled when isLoading is false and isEdited is true', () => {
- store.commit('UPDATE_SETTINGS', { settings: { foo: 'baz' } });
- return wrapper.vm.$nextTick().then(() => {
- expect(findCancelButton().attributes('disabled')).toBe(undefined);
- });
- });
+ const expectation = isDisabled ? 'true' : undefined;
+ expect(findCancelButton().attributes('disabled')).toBe(expectation);
+ },
+ );
});
- describe('when isLoading is true', () => {
- beforeEach(() => {
- store.commit('TOGGLE_LOADING');
+ describe('submit button', () => {
+ it('has type submit', () => {
mountComponent();
- });
- afterEach(() => {
- store.commit('TOGGLE_LOADING');
- });
- it('submit button is disabled and shows a spinner', () => {
- const button = findSaveButton();
- expect(button.attributes('disabled')).toBeTruthy();
- expect(findLoadingIcon(button).exists()).toBe(true);
+ expect(findSaveButton().attributes('type')).toBe('submit');
});
+ it.each`
+ isLoading | fieldsAreValid | mutationLoading | isDisabled
+ ${true} | ${true} | ${true} | ${true}
+ ${false} | ${true} | ${true} | ${true}
+ ${false} | ${false} | ${true} | ${true}
+ ${true} | ${false} | ${false} | ${true}
+ ${false} | ${false} | ${false} | ${true}
+ ${false} | ${true} | ${false} | ${false}
+ `(
+ 'when isLoading is $isLoading and fieldsAreValid is $fieldsAreValid and mutationLoading is $mutationLoading is $isDisabled that the is disabled',
+ ({ fieldsAreValid, isLoading, mutationLoading, isDisabled }) => {
+ mountComponent({
+ props: { ...defaultProps, isLoading },
+ data: { mutationLoading, fieldsAreValid },
+ });
+
+ const expectation = isDisabled ? 'true' : undefined;
+ expect(findSaveButton().attributes('disabled')).toBe(expectation);
+ },
+ );
+
+ it.each`
+ isLoading | mutationLoading | showLoading
+ ${true} | ${true} | ${true}
+ ${true} | ${false} | ${true}
+ ${false} | ${true} | ${true}
+ ${false} | ${false} | ${false}
+ `(
+ 'when isLoading is $isLoading and mutationLoading is $mutationLoading is $showLoading that the loading icon is shown',
+ ({ isLoading, mutationLoading, showLoading }) => {
+ mountComponent({
+ props: { ...defaultProps, isLoading },
+ data: { mutationLoading },
+ });
+
+ expect(findSaveButton().props('loading')).toBe(showLoading);
+ },
+ );
});
});
});
diff --git a/spec/frontend/registry/settings/graphql/cache_updated_spec.js b/spec/frontend/registry/settings/graphql/cache_updated_spec.js
new file mode 100644
index 00000000000..e5f69a08285
--- /dev/null
+++ b/spec/frontend/registry/settings/graphql/cache_updated_spec.js
@@ -0,0 +1,56 @@
+import { updateContainerExpirationPolicy } from '~/registry/settings/graphql/utils/cache_update';
+import expirationPolicyQuery from '~/registry/settings/graphql/queries/get_expiration_policy.graphql';
+
+describe('Registry settings cache update', () => {
+ let client;
+
+ const payload = {
+ data: {
+ updateContainerExpirationPolicy: {
+ containerExpirationPolicy: {
+ enabled: true,
+ },
+ },
+ },
+ };
+
+ const cacheMock = {
+ project: {
+ containerExpirationPolicy: {
+ enabled: false,
+ },
+ },
+ };
+
+ const queryAndVariables = {
+ query: expirationPolicyQuery,
+ variables: { projectPath: 'foo' },
+ };
+
+ beforeEach(() => {
+ client = {
+ readQuery: jest.fn().mockReturnValue(cacheMock),
+ writeQuery: jest.fn(),
+ };
+ });
+ describe('Registry settings cache update', () => {
+ it('calls readQuery', () => {
+ updateContainerExpirationPolicy('foo')(client, payload);
+ expect(client.readQuery).toHaveBeenCalledWith(queryAndVariables);
+ });
+
+ it('writes the correct result in the cache', () => {
+ updateContainerExpirationPolicy('foo')(client, payload);
+ expect(client.writeQuery).toHaveBeenCalledWith({
+ ...queryAndVariables,
+ data: {
+ project: {
+ containerExpirationPolicy: {
+ enabled: true,
+ },
+ },
+ },
+ });
+ });
+ });
+});
diff --git a/spec/frontend/registry/settings/mock_data.js b/spec/frontend/registry/settings/mock_data.js
new file mode 100644
index 00000000000..7f3772ce7fe
--- /dev/null
+++ b/spec/frontend/registry/settings/mock_data.js
@@ -0,0 +1,40 @@
+export const expirationPolicyPayload = override => ({
+ data: {
+ project: {
+ containerExpirationPolicy: {
+ cadence: 'EVERY_DAY',
+ enabled: true,
+ keepN: 'TEN_TAGS',
+ nameRegex: 'asdasdssssdfdf',
+ nameRegexKeep: 'sss',
+ olderThan: 'FOURTEEN_DAYS',
+ ...override,
+ },
+ },
+ },
+});
+
+export const emptyExpirationPolicyPayload = () => ({
+ data: {
+ project: {
+ containerExpirationPolicy: {},
+ },
+ },
+});
+
+export const expirationPolicyMutationPayload = ({ override, errors = [] } = {}) => ({
+ data: {
+ updateContainerExpirationPolicy: {
+ containerExpirationPolicy: {
+ cadence: 'EVERY_DAY',
+ enabled: true,
+ keepN: 'TEN_TAGS',
+ nameRegex: 'asdasdssssdfdf',
+ nameRegexKeep: 'sss',
+ olderThan: 'FOURTEEN_DAYS',
+ ...override,
+ },
+ errors,
+ },
+ },
+});
diff --git a/spec/frontend/registry/settings/store/actions_spec.js b/spec/frontend/registry/settings/store/actions_spec.js
deleted file mode 100644
index 51b89f96ef2..00000000000
--- a/spec/frontend/registry/settings/store/actions_spec.js
+++ /dev/null
@@ -1,90 +0,0 @@
-import testAction from 'helpers/vuex_action_helper';
-import Api from '~/api';
-import * as actions from '~/registry/settings/store/actions';
-import * as types from '~/registry/settings/store/mutation_types';
-
-describe('Actions Registry Store', () => {
- describe.each`
- actionName | mutationName | payload
- ${'setInitialState'} | ${types.SET_INITIAL_STATE} | ${'foo'}
- ${'updateSettings'} | ${types.UPDATE_SETTINGS} | ${'foo'}
- ${'toggleLoading'} | ${types.TOGGLE_LOADING} | ${undefined}
- ${'resetSettings'} | ${types.RESET_SETTINGS} | ${undefined}
- `(
- '$actionName invokes $mutationName with payload $payload',
- ({ actionName, mutationName, payload }) => {
- it('should set state', done => {
- testAction(actions[actionName], payload, {}, [{ type: mutationName, payload }], [], done);
- });
- },
- );
-
- describe('receiveSettingsSuccess', () => {
- it('calls SET_SETTINGS', () => {
- testAction(
- actions.receiveSettingsSuccess,
- 'foo',
- {},
- [{ type: types.SET_SETTINGS, payload: 'foo' }],
- [],
- );
- });
- });
-
- describe('fetchSettings', () => {
- const state = {
- projectId: 'bar',
- };
-
- const payload = {
- data: {
- container_expiration_policy: 'foo',
- },
- };
-
- it('should fetch the data from the API', done => {
- Api.project = jest.fn().mockResolvedValue(payload);
- testAction(
- actions.fetchSettings,
- null,
- state,
- [],
- [
- { type: 'toggleLoading' },
- { type: 'receiveSettingsSuccess', payload: payload.data.container_expiration_policy },
- { type: 'toggleLoading' },
- ],
- done,
- );
- });
- });
-
- describe('saveSettings', () => {
- const state = {
- projectId: 'bar',
- settings: 'baz',
- };
-
- const payload = {
- data: {
- tag_expiration_policies: 'foo',
- },
- };
-
- it('should fetch the data from the API', done => {
- Api.updateProject = jest.fn().mockResolvedValue(payload);
- testAction(
- actions.saveSettings,
- null,
- state,
- [],
- [
- { type: 'toggleLoading' },
- { type: 'receiveSettingsSuccess', payload: payload.data.container_expiration_policy },
- { type: 'toggleLoading' },
- ],
- done,
- );
- });
- });
-});
diff --git a/spec/frontend/registry/settings/store/getters_spec.js b/spec/frontend/registry/settings/store/getters_spec.js
deleted file mode 100644
index b781d09466c..00000000000
--- a/spec/frontend/registry/settings/store/getters_spec.js
+++ /dev/null
@@ -1,72 +0,0 @@
-import * as getters from '~/registry/settings/store/getters';
-import * as utils from '~/registry/shared/utils';
-import { formOptions } from '../../shared/mock_data';
-
-describe('Getters registry settings store', () => {
- const settings = {
- enabled: true,
- cadence: 'foo',
- keep_n: 'bar',
- older_than: 'baz',
- name_regex: 'name-foo',
- name_regex_keep: 'name-keep-bar',
- };
-
- describe.each`
- getter | variable | formOption
- ${'getCadence'} | ${'cadence'} | ${'cadence'}
- ${'getKeepN'} | ${'keep_n'} | ${'keepN'}
- ${'getOlderThan'} | ${'older_than'} | ${'olderThan'}
- `('Options getter', ({ getter, variable, formOption }) => {
- beforeEach(() => {
- utils.findDefaultOption = jest.fn();
- });
-
- it(`${getter} returns ${variable} when ${variable} exists in settings`, () => {
- expect(getters[getter]({ settings })).toBe(settings[variable]);
- });
-
- it(`${getter} calls findDefaultOption when ${variable} does not exists in settings`, () => {
- getters[getter]({ settings: {}, formOptions });
- expect(utils.findDefaultOption).toHaveBeenCalledWith(formOptions[formOption]);
- });
- });
-
- describe('getSettings', () => {
- it('returns the content of settings', () => {
- const computedGetters = {
- getCadence: settings.cadence,
- getOlderThan: settings.older_than,
- getKeepN: settings.keep_n,
- };
- expect(getters.getSettings({ settings }, computedGetters)).toEqual(settings);
- });
- });
-
- describe('getIsEdited', () => {
- it('returns false when original is equal to settings', () => {
- const same = { foo: 'bar' };
- expect(getters.getIsEdited({ original: same, settings: same })).toBe(false);
- });
-
- it('returns true when original is different from settings', () => {
- expect(getters.getIsEdited({ original: { foo: 'bar' }, settings: { foo: 'baz' } })).toBe(
- true,
- );
- });
- });
-
- describe('getIsDisabled', () => {
- it.each`
- original | enableHistoricEntries | result
- ${undefined} | ${false} | ${true}
- ${{ foo: 'bar' }} | ${undefined} | ${false}
- ${{}} | ${false} | ${false}
- `(
- 'returns $result when original is $original and enableHistoricEntries is $enableHistoricEntries',
- ({ original, enableHistoricEntries, result }) => {
- expect(getters.getIsDisabled({ original, enableHistoricEntries })).toBe(result);
- },
- );
- });
-});
diff --git a/spec/frontend/registry/settings/store/mutations_spec.js b/spec/frontend/registry/settings/store/mutations_spec.js
deleted file mode 100644
index 1d85e38eb36..00000000000
--- a/spec/frontend/registry/settings/store/mutations_spec.js
+++ /dev/null
@@ -1,80 +0,0 @@
-import mutations from '~/registry/settings/store/mutations';
-import * as types from '~/registry/settings/store/mutation_types';
-import createState from '~/registry/settings/store/state';
-import { formOptions, stringifiedFormOptions } from '../../shared/mock_data';
-
-describe('Mutations Registry Store', () => {
- let mockState;
-
- beforeEach(() => {
- mockState = createState();
- });
-
- describe('SET_INITIAL_STATE', () => {
- it('should set the initial state', () => {
- const payload = {
- projectId: 'foo',
- enableHistoricEntries: false,
- adminSettingsPath: 'foo',
- isAdmin: true,
- };
- const expectedState = { ...mockState, ...payload, formOptions };
- mutations[types.SET_INITIAL_STATE](mockState, {
- ...payload,
- ...stringifiedFormOptions,
- });
-
- expect(mockState).toEqual(expectedState);
- });
- });
-
- describe('UPDATE_SETTINGS', () => {
- it('should update the settings', () => {
- mockState.settings = { foo: 'bar' };
- const payload = { foo: 'baz' };
- const expectedState = { ...mockState, settings: payload };
- mutations[types.UPDATE_SETTINGS](mockState, { settings: payload });
- expect(mockState.settings).toEqual(expectedState.settings);
- });
- });
-
- describe('SET_SETTINGS', () => {
- it('should set the settings and original', () => {
- const payload = { foo: 'baz' };
- const expectedState = { ...mockState, settings: payload };
- mutations[types.SET_SETTINGS](mockState, payload);
- expect(mockState.settings).toEqual(expectedState.settings);
- expect(mockState.original).toEqual(expectedState.settings);
- });
-
- it('should keep the default state when settings is not present', () => {
- const originalSettings = { ...mockState.settings };
- mutations[types.SET_SETTINGS](mockState);
- expect(mockState.settings).toEqual(originalSettings);
- expect(mockState.original).toEqual(undefined);
- });
- });
-
- describe('RESET_SETTINGS', () => {
- it('should copy original over settings', () => {
- mockState.settings = { foo: 'bar' };
- mockState.original = { foo: 'baz' };
- mutations[types.RESET_SETTINGS](mockState);
- expect(mockState.settings).toEqual(mockState.original);
- });
-
- it('if original is undefined it should initialize to empty object', () => {
- mockState.settings = { foo: 'bar' };
- mockState.original = undefined;
- mutations[types.RESET_SETTINGS](mockState);
- expect(mockState.settings).toEqual({});
- });
- });
-
- describe('TOGGLE_LOADING', () => {
- it('should toggle the loading', () => {
- mutations[types.TOGGLE_LOADING](mockState);
- expect(mockState.isLoading).toEqual(true);
- });
- });
-});
diff --git a/spec/frontend/registry/shared/__snapshots__/utils_spec.js.snap b/spec/frontend/registry/shared/__snapshots__/utils_spec.js.snap
new file mode 100644
index 00000000000..032007bba51
--- /dev/null
+++ b/spec/frontend/registry/shared/__snapshots__/utils_spec.js.snap
@@ -0,0 +1,101 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Utils formOptionsGenerator returns an object containing cadence 1`] = `
+Array [
+ Object {
+ "default": true,
+ "key": "EVERY_DAY",
+ "label": "Every day",
+ },
+ Object {
+ "default": false,
+ "key": "EVERY_WEEK",
+ "label": "Every week",
+ },
+ Object {
+ "default": false,
+ "key": "EVERY_TWO_WEEKS",
+ "label": "Every two weeks",
+ },
+ Object {
+ "default": false,
+ "key": "EVERY_MONTH",
+ "label": "Every month",
+ },
+ Object {
+ "default": false,
+ "key": "EVERY_THREE_MONTHS",
+ "label": "Every three months",
+ },
+]
+`;
+
+exports[`Utils formOptionsGenerator returns an object containing keepN 1`] = `
+Array [
+ Object {
+ "default": false,
+ "key": "ONE_TAG",
+ "label": "1 tag per image name",
+ "variable": 1,
+ },
+ Object {
+ "default": false,
+ "key": "FIVE_TAGS",
+ "label": "5 tags per image name",
+ "variable": 5,
+ },
+ Object {
+ "default": true,
+ "key": "TEN_TAGS",
+ "label": "10 tags per image name",
+ "variable": 10,
+ },
+ Object {
+ "default": false,
+ "key": "TWENTY_FIVE_TAGS",
+ "label": "25 tags per image name",
+ "variable": 25,
+ },
+ Object {
+ "default": false,
+ "key": "FIFTY_TAGS",
+ "label": "50 tags per image name",
+ "variable": 50,
+ },
+ Object {
+ "default": false,
+ "key": "ONE_HUNDRED_TAGS",
+ "label": "100 tags per image name",
+ "variable": 100,
+ },
+]
+`;
+
+exports[`Utils formOptionsGenerator returns an object containing olderThan 1`] = `
+Array [
+ Object {
+ "default": false,
+ "key": "SEVEN_DAYS",
+ "label": "7 days until tags are automatically removed",
+ "variable": 7,
+ },
+ Object {
+ "default": false,
+ "key": "FOURTEEN_DAYS",
+ "label": "14 days until tags are automatically removed",
+ "variable": 14,
+ },
+ Object {
+ "default": false,
+ "key": "THIRTY_DAYS",
+ "label": "30 days until tags are automatically removed",
+ "variable": 30,
+ },
+ Object {
+ "default": true,
+ "key": "NINETY_DAYS",
+ "label": "90 days until tags are automatically removed",
+ "variable": 90,
+ },
+]
+`;
diff --git a/spec/frontend/registry/shared/components/expiration_policy_fields_spec.js b/spec/frontend/registry/shared/components/expiration_policy_fields_spec.js
index ee765ffd1c0..bee9bca5369 100644
--- a/spec/frontend/registry/shared/components/expiration_policy_fields_spec.js
+++ b/spec/frontend/registry/shared/components/expiration_policy_fields_spec.js
@@ -40,13 +40,13 @@ describe('Expiration Policy Form', () => {
});
describe.each`
- elementName | modelName | value | disabledByToggle
- ${'toggle'} | ${'enabled'} | ${true} | ${'not disabled'}
- ${'interval'} | ${'older_than'} | ${'foo'} | ${'disabled'}
- ${'schedule'} | ${'cadence'} | ${'foo'} | ${'disabled'}
- ${'latest'} | ${'keep_n'} | ${'foo'} | ${'disabled'}
- ${'name-matching'} | ${'name_regex'} | ${'foo'} | ${'disabled'}
- ${'keep-name'} | ${'name_regex_keep'} | ${'bar'} | ${'disabled'}
+ elementName | modelName | value | disabledByToggle
+ ${'toggle'} | ${'enabled'} | ${true} | ${'not disabled'}
+ ${'interval'} | ${'olderThan'} | ${'foo'} | ${'disabled'}
+ ${'schedule'} | ${'cadence'} | ${'foo'} | ${'disabled'}
+ ${'latest'} | ${'keepN'} | ${'foo'} | ${'disabled'}
+ ${'name-matching'} | ${'nameRegex'} | ${'foo'} | ${'disabled'}
+ ${'keep-name'} | ${'nameRegexKeep'} | ${'bar'} | ${'disabled'}
`(
`${FORM_ELEMENTS_ID_PREFIX}-$elementName form element`,
({ elementName, modelName, value, disabledByToggle }) => {
@@ -128,9 +128,9 @@ describe('Expiration Policy Form', () => {
});
describe.each`
- modelName | elementName
- ${'name_regex'} | ${'name-matching'}
- ${'name_regex_keep'} | ${'keep-name'}
+ modelName | elementName
+ ${'nameRegex'} | ${'name-matching'}
+ ${'nameRegexKeep'} | ${'keep-name'}
`('regex textarea validation', ({ modelName, elementName }) => {
const invalidString = new Array(NAME_REGEX_LENGTH + 2).join(',');
diff --git a/spec/frontend/registry/shared/stubs.js b/spec/frontend/registry/shared/stubs.js
new file mode 100644
index 00000000000..f6b88d70e49
--- /dev/null
+++ b/spec/frontend/registry/shared/stubs.js
@@ -0,0 +1,11 @@
+export const GlLoadingIcon = { name: 'gl-loading-icon-stub', template: '<svg></svg>' };
+export const GlCard = {
+ name: 'gl-card-stub',
+ template: `
+<div>
+ <slot name="header"></slot>
+ <slot></slot>
+ <slot name="footer"></slot>
+</div>
+`,
+};
diff --git a/spec/frontend/registry/shared/utils_spec.js b/spec/frontend/registry/shared/utils_spec.js
new file mode 100644
index 00000000000..edb0c3261be
--- /dev/null
+++ b/spec/frontend/registry/shared/utils_spec.js
@@ -0,0 +1,37 @@
+import {
+ formOptionsGenerator,
+ optionLabelGenerator,
+ olderThanTranslationGenerator,
+} from '~/registry/shared/utils';
+
+describe('Utils', () => {
+ describe('optionLabelGenerator', () => {
+ it('returns an array with a set label', () => {
+ const result = optionLabelGenerator(
+ [{ variable: 1 }, { variable: 2 }],
+ olderThanTranslationGenerator,
+ );
+ expect(result).toEqual([
+ { variable: 1, label: '1 day until tags are automatically removed' },
+ { variable: 2, label: '2 days until tags are automatically removed' },
+ ]);
+ });
+ });
+
+ describe('formOptionsGenerator', () => {
+ it('returns an object containing olderThan', () => {
+ expect(formOptionsGenerator().olderThan).toBeDefined();
+ expect(formOptionsGenerator().olderThan).toMatchSnapshot();
+ });
+
+ it('returns an object containing cadence', () => {
+ expect(formOptionsGenerator().cadence).toBeDefined();
+ expect(formOptionsGenerator().cadence).toMatchSnapshot();
+ });
+
+ it('returns an object containing keepN', () => {
+ expect(formOptionsGenerator().keepN).toBeDefined();
+ expect(formOptionsGenerator().keepN).toMatchSnapshot();
+ });
+ });
+});
diff --git a/spec/frontend/related_merge_requests/components/related_merge_requests_spec.js b/spec/frontend/related_merge_requests/components/related_merge_requests_spec.js
index 1b938c93df8..db33a9cdce1 100644
--- a/spec/frontend/related_merge_requests/components/related_merge_requests_spec.js
+++ b/spec/frontend/related_merge_requests/components/related_merge_requests_spec.js
@@ -19,9 +19,8 @@ describe('RelatedMergeRequests', () => {
mockData = getJSONFixture(FIXTURE_PATH);
// put the fixture in DOM as the component expects
- document.body.innerHTML = `<div id="js-issuable-app-initial-data">${JSON.stringify(
- mockData,
- )}</div>`;
+ document.body.innerHTML = `<div id="js-issuable-app"></div>`;
+ document.getElementById('js-issuable-app').dataset.initial = JSON.stringify(mockData);
mock = new MockAdapter(axios);
mock.onGet(`${API_ENDPOINT}?per_page=100`).reply(200, mockData, { 'x-total': 2 });
diff --git a/spec/frontend/releases/__snapshots__/util_spec.js.snap b/spec/frontend/releases/__snapshots__/util_spec.js.snap
index f56e296d106..25c108e45bc 100644
--- a/spec/frontend/releases/__snapshots__/util_spec.js.snap
+++ b/spec/frontend/releases/__snapshots__/util_spec.js.snap
@@ -1,113 +1,245 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`releases/util.js convertGraphQLResponse matches snapshot 1`] = `
+exports[`releases/util.js convertAllReleasesGraphQLResponse matches snapshot 1`] = `
Object {
"data": Array [
Object {
"_links": Object {
- "editUrl": "http://0.0.0.0:3000/root/release-test/-/releases/v5.10/edit",
- "issuesUrl": null,
- "mergeRequestsUrl": null,
- "self": "http://0.0.0.0:3000/root/release-test/-/releases/v5.10",
- "selfUrl": "http://0.0.0.0:3000/root/release-test/-/releases/v5.10",
+ "editUrl": "http://localhost/releases-namespace/releases-project/-/releases/v1.1/edit",
+ "issuesUrl": "http://localhost/releases-namespace/releases-project/-/issues?release_tag=v1.1&scope=all&state=opened",
+ "mergeRequestsUrl": "http://localhost/releases-namespace/releases-project/-/merge_requests?release_tag=v1.1&scope=all&state=opened",
+ "self": "http://localhost/releases-namespace/releases-project/-/releases/v1.1",
+ "selfUrl": "http://localhost/releases-namespace/releases-project/-/releases/v1.1",
},
"assets": Object {
- "count": 7,
+ "count": 8,
"links": Array [
Object {
- "directAssetUrl": "http://0.0.0.0:3000/root/release-test/-/releases/v5.32/permanent/path/to/runbook",
+ "directAssetUrl": "http://localhost/releases-namespace/releases-project/-/releases/v1.1/binaries/awesome-app-3",
"external": true,
- "id": "gid://gitlab/Releases::Link/69",
- "linkType": "other",
- "name": "An example link",
- "url": "https://example.com/link",
+ "id": "gid://gitlab/Releases::Link/13",
+ "linkType": "image",
+ "name": "Image",
+ "url": "https://example.com/image",
},
Object {
- "directAssetUrl": "https://example.com/package",
+ "directAssetUrl": "http://localhost/releases-namespace/releases-project/-/releases/v1.1/binaries/awesome-app-2",
"external": true,
- "id": "gid://gitlab/Releases::Link/68",
+ "id": "gid://gitlab/Releases::Link/12",
"linkType": "package",
- "name": "An example package link",
+ "name": "Package",
"url": "https://example.com/package",
},
Object {
- "directAssetUrl": "https://example.com/image",
+ "directAssetUrl": "http://localhost/releases-namespace/releases-project/-/releases/v1.1/binaries/awesome-app-1",
+ "external": false,
+ "id": "gid://gitlab/Releases::Link/11",
+ "linkType": "runbook",
+ "name": "Runbook",
+ "url": "http://localhost/releases-namespace/releases-project/runbook",
+ },
+ Object {
+ "directAssetUrl": "http://localhost/releases-namespace/releases-project/-/releases/v1.1/binaries/linux-amd64",
"external": true,
- "id": "gid://gitlab/Releases::Link/67",
- "linkType": "image",
- "name": "An example image",
- "url": "https://example.com/image",
+ "id": "gid://gitlab/Releases::Link/10",
+ "linkType": "other",
+ "name": "linux-amd64 binaries",
+ "url": "https://downloads.example.com/bin/gitlab-linux-amd64",
},
],
"sources": Array [
Object {
"format": "zip",
- "url": "http://0.0.0.0:3000/root/release-test/-/archive/v5.10/release-test-v5.10.zip",
+ "url": "http://localhost/releases-namespace/releases-project/-/archive/v1.1/releases-project-v1.1.zip",
},
Object {
"format": "tar.gz",
- "url": "http://0.0.0.0:3000/root/release-test/-/archive/v5.10/release-test-v5.10.tar.gz",
+ "url": "http://localhost/releases-namespace/releases-project/-/archive/v1.1/releases-project-v1.1.tar.gz",
},
Object {
"format": "tar.bz2",
- "url": "http://0.0.0.0:3000/root/release-test/-/archive/v5.10/release-test-v5.10.tar.bz2",
+ "url": "http://localhost/releases-namespace/releases-project/-/archive/v1.1/releases-project-v1.1.tar.bz2",
},
Object {
"format": "tar",
- "url": "http://0.0.0.0:3000/root/release-test/-/archive/v5.10/release-test-v5.10.tar",
+ "url": "http://localhost/releases-namespace/releases-project/-/archive/v1.1/releases-project-v1.1.tar",
},
],
},
"author": Object {
- "avatarUrl": "/uploads/-/system/user/avatar/1/avatar.png",
- "username": "root",
- "webUrl": "http://0.0.0.0:3000/root",
+ "avatarUrl": "https://www.gravatar.com/avatar/16f8e2050ce10180ca571c2eb19cfce2?s=80&d=identicon",
+ "username": "administrator",
+ "webUrl": "http://localhost/administrator",
},
"commit": Object {
- "shortId": "92e7ea2e",
- "title": "Testing a change.",
+ "shortId": "b83d6e39",
+ "title": "Merge branch 'branch-merged' into 'master'",
},
- "commitPath": "http://0.0.0.0:3000/root/release-test/-/commit/92e7ea2ee4496fe0d00ff69830ba0564d3d1e5a7",
- "descriptionHtml": "<p data-sourcepos=\\"1:1-1:24\\" dir=\\"auto\\">This is version <strong>1.0</strong>!</p>",
+ "commitPath": "http://localhost/releases-namespace/releases-project/-/commit/b83d6e391c22777fca1ed3012fce84f633d7fed0",
+ "descriptionHtml": "<p data-sourcepos=\\"1:1-1:33\\" dir=\\"auto\\">Best. Release. <strong>Ever.</strong> <gl-emoji title=\\"rocket\\" data-name=\\"rocket\\" data-unicode-version=\\"6.0\\">🚀</gl-emoji></p>",
"evidences": Array [
Object {
- "collectedAt": "2020-08-21T20:15:19Z",
- "filepath": "http://0.0.0.0:3000/root/release-test/-/releases/v5.10/evidences/34.json",
- "sha": "22bde8e8b93d870a29ddc339287a1fbb598f45d1396d",
+ "collectedAt": "2018-12-03T00:00:00Z",
+ "filepath": "http://localhost/releases-namespace/releases-project/-/releases/v1.1/evidences/1.json",
+ "sha": "760d6cdfb0879c3ffedec13af470e0f71cf52c6cde4d",
},
],
"milestones": Array [
Object {
- "description": "",
- "id": "gid://gitlab/Milestone/60",
+ "description": "The 12.4 milestone",
+ "id": "gid://gitlab/Milestone/124",
"issueStats": Object {
- "closed": 0,
- "total": 0,
+ "closed": 1,
+ "total": 4,
},
"stats": undefined,
"title": "12.4",
"webPath": undefined,
- "webUrl": "/root/release-test/-/milestones/2",
+ "webUrl": "/releases-namespace/releases-project/-/milestones/2",
},
Object {
- "description": "Milestone 12.3",
- "id": "gid://gitlab/Milestone/59",
+ "description": "The 12.3 milestone",
+ "id": "gid://gitlab/Milestone/123",
"issueStats": Object {
- "closed": 1,
- "total": 2,
+ "closed": 3,
+ "total": 5,
},
"stats": undefined,
"title": "12.3",
"webPath": undefined,
- "webUrl": "/root/release-test/-/milestones/1",
+ "webUrl": "/releases-namespace/releases-project/-/milestones/1",
},
],
- "name": "Release 1.0",
- "releasedAt": "2020-08-21T20:15:18Z",
- "tagName": "v5.10",
- "tagPath": "/root/release-test/-/tags/v5.10",
- "upcomingRelease": false,
+ "name": "The first release",
+ "releasedAt": "2018-12-10T00:00:00Z",
+ "tagName": "v1.1",
+ "tagPath": "/releases-namespace/releases-project/-/tags/v1.1",
+ "upcomingRelease": true,
},
],
+ "paginationInfo": Object {
+ "endCursor": "eyJpZCI6IjEifQ",
+ "hasNextPage": false,
+ "hasPreviousPage": false,
+ "startCursor": "eyJpZCI6IjEifQ",
+ },
+}
+`;
+
+exports[`releases/util.js convertOneReleaseGraphQLResponse matches snapshot 1`] = `
+Object {
+ "data": Object {
+ "_links": Object {
+ "editUrl": "http://localhost/releases-namespace/releases-project/-/releases/v1.1/edit",
+ "issuesUrl": "http://localhost/releases-namespace/releases-project/-/issues?release_tag=v1.1&scope=all&state=opened",
+ "mergeRequestsUrl": "http://localhost/releases-namespace/releases-project/-/merge_requests?release_tag=v1.1&scope=all&state=opened",
+ "self": "http://localhost/releases-namespace/releases-project/-/releases/v1.1",
+ "selfUrl": "http://localhost/releases-namespace/releases-project/-/releases/v1.1",
+ },
+ "assets": Object {
+ "count": 8,
+ "links": Array [
+ Object {
+ "directAssetUrl": "http://localhost/releases-namespace/releases-project/-/releases/v1.1/binaries/awesome-app-3",
+ "external": true,
+ "id": "gid://gitlab/Releases::Link/13",
+ "linkType": "image",
+ "name": "Image",
+ "url": "https://example.com/image",
+ },
+ Object {
+ "directAssetUrl": "http://localhost/releases-namespace/releases-project/-/releases/v1.1/binaries/awesome-app-2",
+ "external": true,
+ "id": "gid://gitlab/Releases::Link/12",
+ "linkType": "package",
+ "name": "Package",
+ "url": "https://example.com/package",
+ },
+ Object {
+ "directAssetUrl": "http://localhost/releases-namespace/releases-project/-/releases/v1.1/binaries/awesome-app-1",
+ "external": false,
+ "id": "gid://gitlab/Releases::Link/11",
+ "linkType": "runbook",
+ "name": "Runbook",
+ "url": "http://localhost/releases-namespace/releases-project/runbook",
+ },
+ Object {
+ "directAssetUrl": "http://localhost/releases-namespace/releases-project/-/releases/v1.1/binaries/linux-amd64",
+ "external": true,
+ "id": "gid://gitlab/Releases::Link/10",
+ "linkType": "other",
+ "name": "linux-amd64 binaries",
+ "url": "https://downloads.example.com/bin/gitlab-linux-amd64",
+ },
+ ],
+ "sources": Array [
+ Object {
+ "format": "zip",
+ "url": "http://localhost/releases-namespace/releases-project/-/archive/v1.1/releases-project-v1.1.zip",
+ },
+ Object {
+ "format": "tar.gz",
+ "url": "http://localhost/releases-namespace/releases-project/-/archive/v1.1/releases-project-v1.1.tar.gz",
+ },
+ Object {
+ "format": "tar.bz2",
+ "url": "http://localhost/releases-namespace/releases-project/-/archive/v1.1/releases-project-v1.1.tar.bz2",
+ },
+ Object {
+ "format": "tar",
+ "url": "http://localhost/releases-namespace/releases-project/-/archive/v1.1/releases-project-v1.1.tar",
+ },
+ ],
+ },
+ "author": Object {
+ "avatarUrl": "https://www.gravatar.com/avatar/16f8e2050ce10180ca571c2eb19cfce2?s=80&d=identicon",
+ "username": "administrator",
+ "webUrl": "http://localhost/administrator",
+ },
+ "commit": Object {
+ "shortId": "b83d6e39",
+ "title": "Merge branch 'branch-merged' into 'master'",
+ },
+ "commitPath": "http://localhost/releases-namespace/releases-project/-/commit/b83d6e391c22777fca1ed3012fce84f633d7fed0",
+ "descriptionHtml": "<p data-sourcepos=\\"1:1-1:33\\" dir=\\"auto\\">Best. Release. <strong>Ever.</strong> <gl-emoji title=\\"rocket\\" data-name=\\"rocket\\" data-unicode-version=\\"6.0\\">🚀</gl-emoji></p>",
+ "evidences": Array [
+ Object {
+ "collectedAt": "2018-12-03T00:00:00Z",
+ "filepath": "http://localhost/releases-namespace/releases-project/-/releases/v1.1/evidences/1.json",
+ "sha": "760d6cdfb0879c3ffedec13af470e0f71cf52c6cde4d",
+ },
+ ],
+ "milestones": Array [
+ Object {
+ "description": "The 12.4 milestone",
+ "id": "gid://gitlab/Milestone/124",
+ "issueStats": Object {
+ "closed": 1,
+ "total": 4,
+ },
+ "stats": undefined,
+ "title": "12.4",
+ "webPath": undefined,
+ "webUrl": "/releases-namespace/releases-project/-/milestones/2",
+ },
+ Object {
+ "description": "The 12.3 milestone",
+ "id": "gid://gitlab/Milestone/123",
+ "issueStats": Object {
+ "closed": 3,
+ "total": 5,
+ },
+ "stats": undefined,
+ "title": "12.3",
+ "webPath": undefined,
+ "webUrl": "/releases-namespace/releases-project/-/milestones/1",
+ },
+ ],
+ "name": "The first release",
+ "releasedAt": "2018-12-10T00:00:00Z",
+ "tagName": "v1.1",
+ "tagPath": "/releases-namespace/releases-project/-/tags/v1.1",
+ "upcomingRelease": true,
+ },
}
`;
diff --git a/spec/frontend/releases/components/app_edit_new_spec.js b/spec/frontend/releases/components/app_edit_new_spec.js
index e9727801c1a..d92bdc3b99a 100644
--- a/spec/frontend/releases/components/app_edit_new_spec.js
+++ b/spec/frontend/releases/components/app_edit_new_spec.js
@@ -3,12 +3,15 @@ import { mount } from '@vue/test-utils';
import { merge } from 'lodash';
import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
+import { getJSONFixture } from 'helpers/fixtures';
import ReleaseEditNewApp from '~/releases/components/app_edit_new.vue';
-import { release as originalRelease, milestones as originalMilestones } from '../mock_data';
import * as commonUtils from '~/lib/utils/common_utils';
import { BACK_URL_PARAM } from '~/releases/constants';
import AssetLinksForm from '~/releases/components/asset_links_form.vue';
+const originalRelease = getJSONFixture('api/releases/release.json');
+const originalMilestones = originalRelease.milestones;
+
describe('Release edit/new component', () => {
let wrapper;
let release;
@@ -17,7 +20,7 @@ describe('Release edit/new component', () => {
let state;
let mock;
- const factory = ({ featureFlags = {}, store: storeUpdates = {} } = {}) => {
+ const factory = async ({ featureFlags = {}, store: storeUpdates = {} } = {}) => {
state = {
release,
markdownDocsPath: 'path/to/markdown/docs',
@@ -65,6 +68,8 @@ describe('Release edit/new component', () => {
},
});
+ await wrapper.vm.$nextTick();
+
wrapper.element.querySelectorAll('input').forEach(input => jest.spyOn(input, 'focus'));
};
@@ -86,7 +91,9 @@ describe('Release edit/new component', () => {
const findForm = () => wrapper.find('form');
describe(`basic functionality tests: all tests unrelated to the "${BACK_URL_PARAM}" parameter`, () => {
- beforeEach(factory);
+ beforeEach(async () => {
+ await factory();
+ });
it('calls initializeRelease when the component is created', () => {
expect(actions.initializeRelease).toHaveBeenCalledTimes(1);
@@ -128,7 +135,9 @@ describe('Release edit/new component', () => {
});
describe(`when the URL does not contain a "${BACK_URL_PARAM}" parameter`, () => {
- beforeEach(factory);
+ beforeEach(async () => {
+ await factory();
+ });
it(`renders a "Cancel" button with an href pointing to "${BACK_URL_PARAM}"`, () => {
const cancelButton = wrapper.find('.js-cancel-button');
@@ -139,12 +148,12 @@ describe('Release edit/new component', () => {
describe(`when the URL contains a "${BACK_URL_PARAM}" parameter`, () => {
const backUrl = 'https://example.gitlab.com/back/url';
- beforeEach(() => {
+ beforeEach(async () => {
commonUtils.getParameterByName = jest
.fn()
.mockImplementation(paramToGet => ({ [BACK_URL_PARAM]: backUrl }[paramToGet]));
- factory();
+ await factory();
});
it('renders a "Cancel" button with an href pointing to the main Releases page', () => {
@@ -154,8 +163,8 @@ describe('Release edit/new component', () => {
});
describe('when creating a new release', () => {
- beforeEach(() => {
- factory({
+ beforeEach(async () => {
+ await factory({
store: {
modules: {
detail: {
@@ -174,7 +183,9 @@ describe('Release edit/new component', () => {
});
describe('when editing an existing release', () => {
- beforeEach(factory);
+ beforeEach(async () => {
+ await factory();
+ });
it('renders the submit button with the text "Save changes"', () => {
expect(findSubmitButton().text()).toBe('Save changes');
@@ -182,33 +193,17 @@ describe('Release edit/new component', () => {
});
describe('asset links form', () => {
- const findAssetLinksForm = () => wrapper.find(AssetLinksForm);
-
- describe('when the release_asset_link_editing feature flag is disabled', () => {
- beforeEach(() => {
- factory({ featureFlags: { releaseAssetLinkEditing: false } });
- });
-
- it('does not render the asset links portion of the form', () => {
- expect(findAssetLinksForm().exists()).toBe(false);
- });
- });
-
- describe('when the release_asset_link_editing feature flag is enabled', () => {
- beforeEach(() => {
- factory({ featureFlags: { releaseAssetLinkEditing: true } });
- });
+ beforeEach(factory);
- it('renders the asset links portion of the form', () => {
- expect(findAssetLinksForm().exists()).toBe(true);
- });
+ it('renders the asset links portion of the form', () => {
+ expect(wrapper.find(AssetLinksForm).exists()).toBe(true);
});
});
describe('validation', () => {
describe('when the form is valid', () => {
- beforeEach(() => {
- factory({
+ beforeEach(async () => {
+ await factory({
store: {
modules: {
detail: {
@@ -227,8 +222,8 @@ describe('Release edit/new component', () => {
});
describe('when the form is invalid', () => {
- beforeEach(() => {
- factory({
+ beforeEach(async () => {
+ await factory({
store: {
modules: {
detail: {
diff --git a/spec/frontend/releases/components/app_index_spec.js b/spec/frontend/releases/components/app_index_spec.js
index bcb87509cc3..9f1577c2f1e 100644
--- a/spec/frontend/releases/components/app_index_spec.js
+++ b/spec/frontend/releases/components/app_index_spec.js
@@ -2,27 +2,33 @@ import { range as rge } from 'lodash';
import Vuex from 'vuex';
import { shallowMount, createLocalVue } from '@vue/test-utils';
import waitForPromises from 'helpers/wait_for_promises';
+import { getJSONFixture } from 'helpers/fixtures';
import ReleasesApp from '~/releases/components/app_index.vue';
import createStore from '~/releases/stores';
import createListModule from '~/releases/stores/modules/list';
import api from '~/api';
-import {
- pageInfoHeadersWithoutPagination,
- pageInfoHeadersWithPagination,
- release2 as release,
- releases,
-} from '../mock_data';
+import { pageInfoHeadersWithoutPagination, pageInfoHeadersWithPagination } from '../mock_data';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
-import TablePagination from '~/vue_shared/components/pagination/table_pagination.vue';
+import ReleasesPagination from '~/releases/components/releases_pagination.vue';
+
+jest.mock('~/lib/utils/common_utils', () => ({
+ ...jest.requireActual('~/lib/utils/common_utils'),
+ getParameterByName: jest.fn().mockImplementation(paramName => {
+ return `${paramName}_param_value`;
+ }),
+}));
const localVue = createLocalVue();
localVue.use(Vuex);
+const release = getJSONFixture('api/releases/release.json');
+const releases = [release];
+
describe('Releases App ', () => {
let wrapper;
let fetchReleaseSpy;
- const releasesPagination = rge(21).map(index => ({
+ const paginatedReleases = rge(21).map(index => ({
...convertObjectPropsToCamelCase(release, { deep: true }),
tagName: `${index}.00`,
}));
@@ -70,9 +76,13 @@ describe('Releases App ', () => {
createComponent();
});
- it('calls fetchRelease with the page parameter', () => {
+ it('calls fetchRelease with the page, before, and after parameters', () => {
expect(fetchReleaseSpy).toHaveBeenCalledTimes(1);
- expect(fetchReleaseSpy).toHaveBeenCalledWith(expect.anything(), { page: null });
+ expect(fetchReleaseSpy).toHaveBeenCalledWith(expect.anything(), {
+ page: 'page_param_value',
+ before: 'before_param_value',
+ after: 'after_param_value',
+ });
});
});
@@ -91,7 +101,7 @@ describe('Releases App ', () => {
expect(wrapper.contains('.js-loading')).toBe(true);
expect(wrapper.contains('.js-empty-state')).toBe(false);
expect(wrapper.contains('.js-success-state')).toBe(false);
- expect(wrapper.contains(TablePagination)).toBe(false);
+ expect(wrapper.contains(ReleasesPagination)).toBe(false);
});
});
@@ -108,7 +118,7 @@ describe('Releases App ', () => {
expect(wrapper.contains('.js-loading')).toBe(false);
expect(wrapper.contains('.js-empty-state')).toBe(false);
expect(wrapper.contains('.js-success-state')).toBe(true);
- expect(wrapper.contains(TablePagination)).toBe(true);
+ expect(wrapper.contains(ReleasesPagination)).toBe(true);
});
});
@@ -116,7 +126,7 @@ describe('Releases App ', () => {
beforeEach(() => {
jest
.spyOn(api, 'releases')
- .mockResolvedValue({ data: releasesPagination, headers: pageInfoHeadersWithPagination });
+ .mockResolvedValue({ data: paginatedReleases, headers: pageInfoHeadersWithPagination });
createComponent();
});
@@ -125,7 +135,7 @@ describe('Releases App ', () => {
expect(wrapper.contains('.js-loading')).toBe(false);
expect(wrapper.contains('.js-empty-state')).toBe(false);
expect(wrapper.contains('.js-success-state')).toBe(true);
- expect(wrapper.contains(TablePagination)).toBe(true);
+ expect(wrapper.contains(ReleasesPagination)).toBe(true);
});
});
@@ -154,7 +164,7 @@ describe('Releases App ', () => {
const newReleasePath = 'path/to/new/release';
beforeEach(() => {
- createComponent({ ...defaultInitialState, newReleasePath });
+ createComponent({ newReleasePath });
});
it('renders the "New release" button', () => {
@@ -174,4 +184,27 @@ describe('Releases App ', () => {
});
});
});
+
+ describe('when the back button is pressed', () => {
+ beforeEach(() => {
+ jest
+ .spyOn(api, 'releases')
+ .mockResolvedValue({ data: releases, headers: pageInfoHeadersWithoutPagination });
+
+ createComponent();
+
+ fetchReleaseSpy.mockClear();
+
+ window.dispatchEvent(new PopStateEvent('popstate'));
+ });
+
+ it('calls fetchRelease with the page parameter', () => {
+ expect(fetchReleaseSpy).toHaveBeenCalledTimes(1);
+ expect(fetchReleaseSpy).toHaveBeenCalledWith(expect.anything(), {
+ page: 'page_param_value',
+ before: 'before_param_value',
+ after: 'after_param_value',
+ });
+ });
+ });
});
diff --git a/spec/frontend/releases/components/app_show_spec.js b/spec/frontend/releases/components/app_show_spec.js
index 502a1053663..181fa0150f1 100644
--- a/spec/frontend/releases/components/app_show_spec.js
+++ b/spec/frontend/releases/components/app_show_spec.js
@@ -1,11 +1,13 @@
import Vuex from 'vuex';
import { shallowMount } from '@vue/test-utils';
-import { GlDeprecatedSkeletonLoading as GlSkeletonLoading } from '@gitlab/ui';
+import { getJSONFixture } from 'helpers/fixtures';
import ReleaseShowApp from '~/releases/components/app_show.vue';
-import { release as originalRelease } from '../mock_data';
+import ReleaseSkeletonLoader from '~/releases/components/release_skeleton_loader.vue';
import ReleaseBlock from '~/releases/components/release_block.vue';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
+const originalRelease = getJSONFixture('api/releases/release.json');
+
describe('Release show component', () => {
let wrapper;
let release;
@@ -33,7 +35,7 @@ describe('Release show component', () => {
wrapper = shallowMount(ReleaseShowApp, { store });
};
- const findLoadingSkeleton = () => wrapper.find(GlSkeletonLoading);
+ const findLoadingSkeleton = () => wrapper.find(ReleaseSkeletonLoader);
const findReleaseBlock = () => wrapper.find(ReleaseBlock);
it('calls fetchRelease when the component is created', () => {
diff --git a/spec/frontend/releases/components/asset_links_form_spec.js b/spec/frontend/releases/components/asset_links_form_spec.js
index 582c0b32716..6794a56debc 100644
--- a/spec/frontend/releases/components/asset_links_form_spec.js
+++ b/spec/frontend/releases/components/asset_links_form_spec.js
@@ -1,7 +1,7 @@
import Vuex from 'vuex';
import { mount, createLocalVue } from '@vue/test-utils';
+import { getJSONFixture } from 'helpers/fixtures';
import AssetLinksForm from '~/releases/components/asset_links_form.vue';
-import { release as originalRelease } from '../mock_data';
import * as commonUtils from '~/lib/utils/common_utils';
import { ENTER_KEY } from '~/lib/utils/keys';
import { ASSET_LINK_TYPE, DEFAULT_ASSET_LINK_TYPE } from '~/releases/constants';
@@ -9,6 +9,8 @@ import { ASSET_LINK_TYPE, DEFAULT_ASSET_LINK_TYPE } from '~/releases/constants';
const localVue = createLocalVue();
localVue.use(Vuex);
+const originalRelease = getJSONFixture('api/releases/release.json');
+
describe('Release edit component', () => {
let wrapper;
let release;
@@ -54,11 +56,6 @@ describe('Release edit component', () => {
wrapper = mount(AssetLinksForm, {
localVue,
store,
- provide: {
- glFeatures: {
- releaseAssetLinkType: true,
- },
- },
});
};
@@ -223,10 +220,18 @@ describe('Release edit component', () => {
});
});
- it('selects the default asset type if no type was provided by the backend', () => {
- const selected = wrapper.find({ ref: 'typeSelect' }).element.value;
+ describe('when no link type was provided by the backend', () => {
+ beforeEach(() => {
+ delete release.assets.links[0].linkType;
+
+ factory({ release });
+ });
+
+ it('selects the default asset type', () => {
+ const selected = wrapper.find({ ref: 'typeSelect' }).element.value;
- expect(selected).toBe(DEFAULT_ASSET_LINK_TYPE);
+ expect(selected).toBe(DEFAULT_ASSET_LINK_TYPE);
+ });
});
});
diff --git a/spec/frontend/releases/components/evidence_block_spec.js b/spec/frontend/releases/components/evidence_block_spec.js
index ba60a79e464..b8c78f90fc2 100644
--- a/spec/frontend/releases/components/evidence_block_spec.js
+++ b/spec/frontend/releases/components/evidence_block_spec.js
@@ -1,11 +1,13 @@
import { mount } from '@vue/test-utils';
import { GlLink, GlIcon } from '@gitlab/ui';
+import { getJSONFixture } from 'helpers/fixtures';
import { truncateSha } from '~/lib/utils/text_utility';
-import { release as originalRelease } from '../mock_data';
import EvidenceBlock from '~/releases/components/evidence_block.vue';
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
+const originalRelease = getJSONFixture('api/releases/release.json');
+
describe('Evidence Block', () => {
let wrapper;
let release;
@@ -35,7 +37,7 @@ describe('Evidence Block', () => {
});
it('renders the title for the dowload link', () => {
- expect(wrapper.find(GlLink).text()).toBe('v1.1.2-evidences-1.json');
+ expect(wrapper.find(GlLink).text()).toBe(`v1.1-evidences-1.json`);
});
it('renders the correct hover text for the download', () => {
@@ -43,7 +45,7 @@ describe('Evidence Block', () => {
});
it('renders the correct file link for download', () => {
- expect(wrapper.find(GlLink).attributes().download).toBe('v1.1.2-evidences-1.json');
+ expect(wrapper.find(GlLink).attributes().download).toBe(`v1.1-evidences-1.json`);
});
describe('sha text', () => {
diff --git a/spec/frontend/releases/components/release_block_assets_spec.js b/spec/frontend/releases/components/release_block_assets_spec.js
index 3453ecbf8ab..126ca27e8a6 100644
--- a/spec/frontend/releases/components/release_block_assets_spec.js
+++ b/spec/frontend/releases/components/release_block_assets_spec.js
@@ -1,10 +1,12 @@
import { mount } from '@vue/test-utils';
import { GlCollapse } from '@gitlab/ui';
import { trimText } from 'helpers/text_helper';
-import { cloneDeep } from 'lodash';
+import { getJSONFixture } from 'helpers/fixtures';
+import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
import ReleaseBlockAssets from '~/releases/components/release_block_assets.vue';
import { ASSET_LINK_TYPE } from '~/releases/constants';
-import { assets } from '../mock_data';
+
+const { assets } = getJSONFixture('api/releases/release.json');
describe('Release block assets', () => {
let wrapper;
@@ -20,9 +22,6 @@ describe('Release block assets', () => {
const createComponent = (propsData = defaultProps) => {
wrapper = mount(ReleaseBlockAssets, {
- provide: {
- glFeatures: { releaseAssetLinkType: true },
- },
propsData,
});
};
@@ -31,7 +30,7 @@ describe('Release block assets', () => {
wrapper.findAll('h5').filter(h5 => h5.text() === sections[type]);
beforeEach(() => {
- defaultProps = { assets: cloneDeep(assets) };
+ defaultProps = { assets: convertObjectPropsToCamelCase(assets, { deep: true }) };
});
describe('with default props', () => {
@@ -43,7 +42,7 @@ describe('Release block assets', () => {
const accordionButton = findAccordionButton();
expect(accordionButton.exists()).toBe(true);
- expect(trimText(accordionButton.text())).toBe('Assets 5');
+ expect(trimText(accordionButton.text())).toBe('Assets 8');
});
it('renders the accordion as expanded by default', () => {
diff --git a/spec/frontend/releases/components/release_block_footer_spec.js b/spec/frontend/releases/components/release_block_footer_spec.js
index bde01cc0e00..f1c0c24f8ca 100644
--- a/spec/frontend/releases/components/release_block_footer_spec.js
+++ b/spec/frontend/releases/components/release_block_footer_spec.js
@@ -1,11 +1,13 @@
import { mount } from '@vue/test-utils';
import { GlLink, GlIcon } from '@gitlab/ui';
import { trimText } from 'helpers/text_helper';
+import { getJSONFixture } from 'helpers/fixtures';
import { cloneDeep } from 'lodash';
import ReleaseBlockFooter from '~/releases/components/release_block_footer.vue';
-import { release as originalRelease } from '../mock_data';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
+const originalRelease = getJSONFixture('api/releases/release.json');
+
const mockFutureDate = new Date(9999, 0, 0).toISOString();
let mockIsFutureRelease = false;
diff --git a/spec/frontend/releases/components/release_block_header_spec.js b/spec/frontend/releases/components/release_block_header_spec.js
index 9c6cbc86d3c..f2159871395 100644
--- a/spec/frontend/releases/components/release_block_header_spec.js
+++ b/spec/frontend/releases/components/release_block_header_spec.js
@@ -1,11 +1,13 @@
import { shallowMount } from '@vue/test-utils';
import { merge } from 'lodash';
import { GlLink } from '@gitlab/ui';
+import { getJSONFixture } from 'helpers/fixtures';
import ReleaseBlockHeader from '~/releases/components/release_block_header.vue';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
-import { release as originalRelease } from '../mock_data';
import { BACK_URL_PARAM } from '~/releases/constants';
+const originalRelease = getJSONFixture('api/releases/release.json');
+
describe('Release block header', () => {
let wrapper;
let release;
@@ -49,7 +51,7 @@ describe('Release block header', () => {
});
it('renders the title as text', () => {
- expect(findHeader().text()).toBe(release.name);
+ expect(findHeader().text()).toContain(release.name);
expect(findHeaderLink().exists()).toBe(false);
});
});
diff --git a/spec/frontend/releases/components/release_block_metadata_spec.js b/spec/frontend/releases/components/release_block_metadata_spec.js
deleted file mode 100644
index 6f184e45600..00000000000
--- a/spec/frontend/releases/components/release_block_metadata_spec.js
+++ /dev/null
@@ -1,67 +0,0 @@
-import { mount } from '@vue/test-utils';
-import { trimText } from 'helpers/text_helper';
-import { cloneDeep } from 'lodash';
-import ReleaseBlockMetadata from '~/releases/components/release_block_metadata.vue';
-import { release as originalRelease } from '../mock_data';
-import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
-
-const mockFutureDate = new Date(9999, 0, 0).toISOString();
-let mockIsFutureRelease = false;
-
-jest.mock('~/vue_shared/mixins/timeago', () => ({
- methods: {
- timeFormatted() {
- return mockIsFutureRelease ? 'in 1 month' : '7 fortnights ago';
- },
- tooltipTitle() {
- return 'February 30, 2401';
- },
- },
-}));
-
-describe('Release block metadata', () => {
- let wrapper;
- let release;
-
- const factory = (releaseUpdates = {}) => {
- wrapper = mount(ReleaseBlockMetadata, {
- propsData: {
- release: {
- ...convertObjectPropsToCamelCase(release, { deep: true }),
- ...releaseUpdates,
- },
- },
- });
- };
-
- beforeEach(() => {
- release = cloneDeep(originalRelease);
- });
-
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- mockIsFutureRelease = false;
- });
-
- const findReleaseDateInfo = () => wrapper.find('.js-release-date-info');
-
- describe('with all props provided', () => {
- beforeEach(() => factory());
-
- it('renders the release time info', () => {
- expect(trimText(findReleaseDateInfo().text())).toBe(`released 7 fortnights ago`);
- });
- });
-
- describe('with a future release date', () => {
- beforeEach(() => {
- mockIsFutureRelease = true;
- factory({ releasedAt: mockFutureDate });
- });
-
- it('renders the release date without the author name', () => {
- expect(trimText(findReleaseDateInfo().text())).toBe(`will be released in 1 month`);
- });
- });
-});
diff --git a/spec/frontend/releases/components/release_block_milestone_info_spec.js b/spec/frontend/releases/components/release_block_milestone_info_spec.js
index 0e79c45b337..45f4eaa01a9 100644
--- a/spec/frontend/releases/components/release_block_milestone_info_spec.js
+++ b/spec/frontend/releases/components/release_block_milestone_info_spec.js
@@ -1,11 +1,13 @@
import { mount } from '@vue/test-utils';
import { GlProgressBar, GlLink, GlBadge, GlButton } from '@gitlab/ui';
import { trimText } from 'helpers/text_helper';
+import { getJSONFixture } from 'helpers/fixtures';
import ReleaseBlockMilestoneInfo from '~/releases/components/release_block_milestone_info.vue';
-import { milestones as originalMilestones } from '../mock_data';
import { MAX_MILESTONES_TO_DISPLAY } from '~/releases/constants';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
+const { milestones: originalMilestones } = getJSONFixture('api/releases/release.json');
+
describe('Release block milestone info', () => {
let wrapper;
let milestones;
@@ -35,7 +37,7 @@ describe('Release block milestone info', () => {
beforeEach(() => factory({ milestones }));
it('renders the correct percentage', () => {
- expect(milestoneProgressBarContainer().text()).toContain('41% complete');
+ expect(milestoneProgressBarContainer().text()).toContain('44% complete');
});
it('renders a progress bar that displays the correct percentage', () => {
@@ -44,14 +46,24 @@ describe('Release block milestone info', () => {
expect(progressBar.exists()).toBe(true);
expect(progressBar.attributes()).toEqual(
expect.objectContaining({
- value: '22',
- max: '54',
+ value: '4',
+ max: '9',
}),
);
});
it('renders a list of links to all associated milestones', () => {
- expect(trimText(milestoneListContainer().text())).toContain('Milestones 13.6 • 13.5');
+ // The API currently returns the milestones in a non-deterministic order,
+ // which causes the frontend fixture used by this test to return the
+ // milestones in one order locally and a different order in the CI pipeline.
+ // This is a bug and is tracked here: https://gitlab.com/gitlab-org/gitlab/-/issues/259012
+ // When this bug is fixed this expectation should be updated to
+ // assert the expected order.
+ const containerText = trimText(milestoneListContainer().text());
+ expect(
+ containerText.includes('Milestones 12.4 • 12.3') ||
+ containerText.includes('Milestones 12.3 • 12.4'),
+ ).toBe(true);
milestones.forEach((m, i) => {
const milestoneLink = milestoneListContainer()
@@ -65,7 +77,7 @@ describe('Release block milestone info', () => {
});
it('renders the "Issues" section with a total count of issues associated to the milestone(s)', () => {
- const totalIssueCount = 54;
+ const totalIssueCount = 9;
const issuesContainerText = trimText(issuesContainer().text());
expect(issuesContainerText).toContain(`Issues ${totalIssueCount}`);
@@ -73,7 +85,7 @@ describe('Release block milestone info', () => {
const badge = issuesContainer().find(GlBadge);
expect(badge.text()).toBe(totalIssueCount.toString());
- expect(issuesContainerText).toContain('Open: 32 • Closed: 22');
+ expect(issuesContainerText).toContain('Open: 5 • Closed: 4');
});
});
diff --git a/spec/frontend/releases/components/release_block_spec.js b/spec/frontend/releases/components/release_block_spec.js
index a7f1388664b..633c6690529 100644
--- a/spec/frontend/releases/components/release_block_spec.js
+++ b/spec/frontend/releases/components/release_block_spec.js
@@ -1,15 +1,16 @@
import $ from 'jquery';
import { mount } from '@vue/test-utils';
-import { GlIcon } from '@gitlab/ui';
+import { getJSONFixture } from 'helpers/fixtures';
import EvidenceBlock from '~/releases/components/evidence_block.vue';
import ReleaseBlock from '~/releases/components/release_block.vue';
import ReleaseBlockFooter from '~/releases/components/release_block_footer.vue';
import timeagoMixin from '~/vue_shared/mixins/timeago';
-import { release as originalRelease } from '../mock_data';
import * as commonUtils from '~/lib/utils/common_utils';
import { BACK_URL_PARAM } from '~/releases/constants';
import * as urlUtility from '~/lib/utils/url_utility';
+const originalRelease = getJSONFixture('api/releases/release.json');
+
describe('Release block', () => {
let wrapper;
let release;
@@ -21,7 +22,6 @@ describe('Release block', () => {
},
provide: {
glFeatures: {
- releaseIssueSummary: true,
...featureFlags,
},
},
@@ -46,7 +46,7 @@ describe('Release block', () => {
beforeEach(() => factory(release));
it("renders the block with an id equal to the release's tag name", () => {
- expect(wrapper.attributes().id).toBe('v0.3');
+ expect(wrapper.attributes().id).toBe(release.tagName);
});
it(`renders an edit button that links to the "Edit release" page with a "${BACK_URL_PARAM}" parameter`, () => {
@@ -69,50 +69,10 @@ describe('Release block', () => {
expect(wrapper.text()).toContain(timeagoMixin.methods.timeFormatted(release.releasedAt));
});
- it('renders number of assets provided', () => {
- expect(wrapper.find('.js-assets-count').text()).toContain(release.assets.count);
- });
-
- it('renders dropdown with the sources', () => {
- expect(wrapper.findAll('.js-sources-dropdown li').length).toEqual(
- release.assets.sources.length,
- );
-
- expect(wrapper.find('.js-sources-dropdown li a').attributes().href).toEqual(
- release.assets.sources[0].url,
- );
-
- expect(wrapper.find('.js-sources-dropdown li a').text()).toContain(
- release.assets.sources[0].format,
- );
- });
-
- it('renders list with the links provided', () => {
- expect(wrapper.findAll('.js-assets-list li').length).toEqual(release.assets.links.length);
-
- expect(wrapper.find('.js-assets-list li a').attributes().href).toEqual(
- release.assets.links[0].directAssetUrl,
- );
-
- expect(wrapper.find('.js-assets-list li a').text()).toContain(release.assets.links[0].name);
- });
-
it('renders author avatar', () => {
expect(wrapper.find('.user-avatar-link').exists()).toBe(true);
});
- describe('external label', () => {
- it('renders external label when link is external', () => {
- expect(wrapper.find('.js-assets-list li a').text()).toContain('external source');
- });
-
- it('does not render external label when link is not external', () => {
- expect(wrapper.find('.js-assets-list li:nth-child(2) a').text()).not.toContain(
- 'external source',
- );
- });
- });
-
it('renders the footer', () => {
expect(wrapper.find(ReleaseBlockFooter).exists()).toBe(true);
});
@@ -171,18 +131,14 @@ describe('Release block', () => {
});
describe('evidence block', () => {
- it('renders the evidence block when the evidence is available and the feature flag is true', () =>
- factory(release, { releaseEvidenceCollection: true }).then(() =>
- expect(wrapper.find(EvidenceBlock).exists()).toBe(true),
- ));
-
- it('does not render the evidence block when the evidence is available but the feature flag is false', () =>
- factory(release, { releaseEvidenceCollection: true }).then(() =>
- expect(wrapper.find(EvidenceBlock).exists()).toBe(true),
- ));
+ it('renders the evidence block when the evidence is available', () => {
+ return factory(release).then(() => {
+ expect(wrapper.find(EvidenceBlock).exists()).toBe(true);
+ });
+ });
it('does not render the evidence block when there is no evidence', () => {
- release.evidenceSha = null;
+ release.evidences = [];
return factory(release).then(() => {
expect(wrapper.find(EvidenceBlock).exists()).toBe(false);
@@ -239,51 +195,4 @@ describe('Release block', () => {
});
});
});
-
- describe('when the releaseIssueSummary feature flag is disabled', () => {
- describe('with default props', () => {
- beforeEach(() => factory(release, { releaseIssueSummary: false }));
-
- it('renders the milestone icon', () => {
- expect(
- milestoneListLabel()
- .find(GlIcon)
- .exists(),
- ).toBe(true);
- });
-
- it('renders the label as "Milestones" if more than one milestone is passed in', () => {
- expect(
- milestoneListLabel()
- .find('.js-label-text')
- .text(),
- ).toEqual('Milestones');
- });
-
- it('renders a link to the milestone with a tooltip', () => {
- const milestone = release.milestones[0];
- const milestoneLink = wrapper.find('.js-milestone-link');
-
- expect(milestoneLink.exists()).toBe(true);
-
- expect(milestoneLink.text()).toBe(milestone.title);
-
- expect(milestoneLink.attributes('href')).toBe(milestone.webUrl);
-
- expect(milestoneLink.attributes('title')).toBe(milestone.description);
- });
- });
-
- it('renders the label as "Milestone" if only a single milestone is passed in', () => {
- release.milestones = release.milestones.slice(0, 1);
-
- return factory(release, { releaseIssueSummary: false }).then(() => {
- expect(
- milestoneListLabel()
- .find('.js-label-text')
- .text(),
- ).toEqual('Milestone');
- });
- });
- });
});
diff --git a/spec/frontend/releases/components/release_skeleton_loader_spec.js b/spec/frontend/releases/components/release_skeleton_loader_spec.js
new file mode 100644
index 00000000000..7fbf864568a
--- /dev/null
+++ b/spec/frontend/releases/components/release_skeleton_loader_spec.js
@@ -0,0 +1,15 @@
+import { mount } from '@vue/test-utils';
+import { GlSkeletonLoader } from '@gitlab/ui';
+import ReleaseSkeletonLoader from '~/releases/components/release_skeleton_loader.vue';
+
+describe('release_skeleton_loader.vue', () => {
+ let wrapper;
+
+ beforeEach(() => {
+ wrapper = mount(ReleaseSkeletonLoader);
+ });
+
+ it('renders a GlSkeletonLoader', () => {
+ expect(wrapper.find(GlSkeletonLoader).exists()).toBe(true);
+ });
+});
diff --git a/spec/frontend/releases/components/releases_pagination_graphql_spec.js b/spec/frontend/releases/components/releases_pagination_graphql_spec.js
index b01a28eb6c3..bba5e532e5e 100644
--- a/spec/frontend/releases/components/releases_pagination_graphql_spec.js
+++ b/spec/frontend/releases/components/releases_pagination_graphql_spec.js
@@ -29,7 +29,7 @@ describe('~/releases/components/releases_pagination_graphql.vue', () => {
listModule.state.graphQlPageInfo = pageInfo;
- listModule.actions.fetchReleasesGraphQl = jest.fn();
+ listModule.actions.fetchReleases = jest.fn();
wrapper = mount(ReleasesPaginationGraphql, {
store: createStore({
@@ -141,8 +141,8 @@ describe('~/releases/components/releases_pagination_graphql.vue', () => {
findNextButton().trigger('click');
});
- it('calls fetchReleasesGraphQl with the correct after cursor', () => {
- expect(listModule.actions.fetchReleasesGraphQl.mock.calls).toEqual([
+ it('calls fetchReleases with the correct after cursor', () => {
+ expect(listModule.actions.fetchReleases.mock.calls).toEqual([
[expect.anything(), { after: cursors.endCursor }],
]);
});
@@ -159,8 +159,8 @@ describe('~/releases/components/releases_pagination_graphql.vue', () => {
findPrevButton().trigger('click');
});
- it('calls fetchReleasesGraphQl with the correct before cursor', () => {
- expect(listModule.actions.fetchReleasesGraphQl.mock.calls).toEqual([
+ it('calls fetchReleases with the correct before cursor', () => {
+ expect(listModule.actions.fetchReleases.mock.calls).toEqual([
[expect.anything(), { before: cursors.startCursor }],
]);
});
diff --git a/spec/frontend/releases/components/releases_pagination_rest_spec.js b/spec/frontend/releases/components/releases_pagination_rest_spec.js
index 4fd3e085fc9..59c0c31413a 100644
--- a/spec/frontend/releases/components/releases_pagination_rest_spec.js
+++ b/spec/frontend/releases/components/releases_pagination_rest_spec.js
@@ -20,9 +20,9 @@ describe('~/releases/components/releases_pagination_rest.vue', () => {
const createComponent = pageInfo => {
listModule = createListModule({ projectId });
- listModule.state.pageInfo = pageInfo;
+ listModule.state.restPageInfo = pageInfo;
- listModule.actions.fetchReleasesRest = jest.fn();
+ listModule.actions.fetchReleases = jest.fn();
wrapper = mount(ReleasesPaginationRest, {
store: createStore({
@@ -57,8 +57,8 @@ describe('~/releases/components/releases_pagination_rest.vue', () => {
findGlPagination().vm.$emit('input', newPage);
});
- it('calls fetchReleasesRest with the correct page', () => {
- expect(listModule.actions.fetchReleasesRest.mock.calls).toEqual([
+ it('calls fetchReleases with the correct page', () => {
+ expect(listModule.actions.fetchReleases.mock.calls).toEqual([
[expect.anything(), { page: newPage }],
]);
});
diff --git a/spec/frontend/releases/mock_data.js b/spec/frontend/releases/mock_data.js
index 58cd69a2f6a..c89182faa44 100644
--- a/spec/frontend/releases/mock_data.js
+++ b/spec/frontend/releases/mock_data.js
@@ -1,139 +1,3 @@
-import { ASSET_LINK_TYPE } from '~/releases/constants';
-
-export const milestones = [
- {
- id: 50,
- iid: 2,
- project_id: 18,
- title: '13.6',
- description: 'The 13.6 milestone!',
- state: 'active',
- created_at: '2019-08-27T17:22:38.280Z',
- updated_at: '2019-08-27T17:22:38.280Z',
- due_date: '2019-09-19',
- start_date: '2019-08-31',
- web_url: 'http://0.0.0.0:3001/root/release-test/-/milestones/2',
- issue_stats: {
- total: 33,
- closed: 19,
- },
- },
- {
- id: 49,
- iid: 1,
- project_id: 18,
- title: '13.5',
- description: 'The 13.5 milestone!',
- state: 'active',
- created_at: '2019-08-26T17:55:48.643Z',
- updated_at: '2019-08-26T17:55:48.643Z',
- due_date: '2019-10-11',
- start_date: '2019-08-19',
- web_url: 'http://0.0.0.0:3001/root/release-test/-/milestones/1',
- issue_stats: {
- total: 21,
- closed: 3,
- },
- },
-];
-
-export const release = {
- name: 'New release',
- tag_name: 'v0.3',
- tag_path: '/root/release-test/-/tags/v0.3',
- description: 'A super nice release!',
- description_html: '<p data-sourcepos="1:1-1:21" dir="auto">A super nice release!</p>',
- created_at: '2019-08-26T17:54:04.952Z',
- released_at: '2019-08-26T17:54:04.807Z',
- author: {
- id: 1,
- name: 'Administrator',
- username: 'root',
- state: 'active',
- avatar_url: 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
- web_url: 'http://0.0.0.0:3001/root',
- },
- commit: {
- id: 'c22b0728d1b465f82898c884d32b01aa642f96c1',
- short_id: 'c22b0728',
- created_at: '2019-08-26T17:47:07.000Z',
- parent_ids: [],
- title: 'Initial commit',
- message: 'Initial commit',
- author_name: 'Administrator',
- author_email: 'admin@example.com',
- authored_date: '2019-08-26T17:47:07.000Z',
- committer_name: 'Administrator',
- committer_email: 'admin@example.com',
- committed_date: '2019-08-26T17:47:07.000Z',
- },
- commit_path: '/root/release-test/commit/c22b0728d1b465f82898c884d32b01aa642f96c1',
- upcoming_release: false,
- milestones,
- evidences: [
- {
- filepath:
- 'https://20592.qa-tunnel.gitlab.info/root/test-deployments/-/releases/v1.1.2/evidences/1.json',
- sha: 'fb3a125fd69a0e5048ebfb0ba43eb32ce4911520dd8d',
- collected_at: '2018-10-19 15:43:20 +0200',
- },
- {
- filepath:
- 'https://20592.qa-tunnel.gitlab.info/root/test-deployments/-/releases/v1.1.2/evidences/2.json',
- sha: '6ebd17a66e6a861175735416e49cf677678029805712dd71bb805c609e2d9108',
- collected_at: '2018-10-19 15:43:20 +0200',
- },
- {
- filepath:
- 'https://20592.qa-tunnel.gitlab.info/root/test-deployments/-/releases/v1.1.2/evidences/3.json',
- sha: '2f65beaf275c3cb4b4e24fb01d481cc475d69c957830833f15338384816b5cba',
- collected_at: '2018-10-19 15:43:20 +0200',
- },
- ],
- assets: {
- count: 5,
- sources: [
- {
- format: 'zip',
- url: 'http://0.0.0.0:3001/root/release-test/-/archive/v0.3/release-test-v0.3.zip',
- },
- {
- format: 'tar.gz',
- url: 'http://0.0.0.0:3001/root/release-test/-/archive/v0.3/release-test-v0.3.tar.gz',
- },
- {
- format: 'tar.bz2',
- url: 'http://0.0.0.0:3001/root/release-test/-/archive/v0.3/release-test-v0.3.tar.bz2',
- },
- {
- format: 'tar',
- url: 'http://0.0.0.0:3001/root/release-test/-/archive/v0.3/release-test-v0.3.tar',
- },
- ],
- links: [
- {
- id: 1,
- name: 'my link',
- url: 'https://google.com',
- direct_asset_url: 'https://redirected.google.com',
- external: true,
- },
- {
- id: 2,
- name: 'my second link',
- url:
- 'https://gitlab.com/gitlab-org/gitlab-foss/-/jobs/artifacts/v11.6.0-rc4/download?job=rspec-mysql+41%2F50',
- direct_asset_url: 'https://redirected.google.com',
- external: false,
- },
- ],
- },
- _links: {
- self: 'http://0.0.0.0:3001/root/release-test/-/releases/v0.3',
- edit_url: 'http://0.0.0.0:3001/root/release-test/-/releases/v0.3/edit',
- },
-};
-
export const pageInfoHeadersWithoutPagination = {
'X-NEXT-PAGE': '',
'X-PAGE': '1',
@@ -151,202 +15,3 @@ export const pageInfoHeadersWithPagination = {
'X-TOTAL': '21',
'X-TOTAL-PAGES': '2',
};
-
-export const assets = {
- count: 5,
- sources: [
- {
- format: 'zip',
- url: 'https://example.gitlab.com/path/to/zip',
- },
- ],
- links: [
- {
- linkType: ASSET_LINK_TYPE.IMAGE,
- url: 'https://example.gitlab.com/path/to/image',
- directAssetUrl: 'https://example.gitlab.com/path/to/image',
- name: 'Example image link',
- },
- {
- linkType: ASSET_LINK_TYPE.PACKAGE,
- url: 'https://example.gitlab.com/path/to/package',
- directAssetUrl: 'https://example.gitlab.com/path/to/package',
- name: 'Example package link',
- },
- {
- linkType: ASSET_LINK_TYPE.RUNBOOK,
- url: 'https://example.gitlab.com/path/to/runbook',
- directAssetUrl: 'https://example.gitlab.com/path/to/runbook',
- name: 'Example runbook link',
- },
- {
- linkType: ASSET_LINK_TYPE.OTHER,
- url: 'https://example.gitlab.com/path/to/link',
- directAssetUrl: 'https://example.gitlab.com/path/to/link',
- name: 'Example link',
- },
- ],
-};
-
-export const release2 = {
- name: 'Bionic Beaver',
- tag_name: '18.04',
- description: '## changelog\n\n* line 1\n* line2',
- description_html: '<div><h2>changelog</h2><ul><li>line1</li<li>line 2</li></ul></div>',
- author_name: 'Release bot',
- author_email: 'release-bot@example.com',
- created_at: '2012-05-28T05:00:00-07:00',
- commit: {
- id: '2695effb5807a22ff3d138d593fd856244e155e7',
- short_id: '2695effb',
- title: 'Initial commit',
- created_at: '2017-07-26T11:08:53.000+02:00',
- parent_ids: ['2a4b78934375d7f53875269ffd4f45fd83a84ebe'],
- message: 'Initial commit',
- author: {
- avatar_url: 'uploads/-/system/user/avatar/johndoe/avatar.png',
- id: 482476,
- name: 'John Doe',
- path: '/johndoe',
- state: 'active',
- status_tooltip_html: null,
- username: 'johndoe',
- web_url: 'https://gitlab.com/johndoe',
- },
- authored_date: '2012-05-28T04:42:42-07:00',
- committer_name: 'Jack Smith',
- committer_email: 'jack@example.com',
- committed_date: '2012-05-28T04:42:42-07:00',
- },
- assets,
-};
-
-export const releases = [release, release2];
-
-export const graphqlReleasesResponse = {
- data: {
- project: {
- releases: {
- count: 39,
- nodes: [
- {
- name: 'Release 1.0',
- tagName: 'v5.10',
- tagPath: '/root/release-test/-/tags/v5.10',
- descriptionHtml:
- '<p data-sourcepos="1:1-1:24" dir="auto">This is version <strong>1.0</strong>!</p>',
- releasedAt: '2020-08-21T20:15:18Z',
- upcomingRelease: false,
- assets: {
- count: 7,
- sources: {
- nodes: [
- {
- format: 'zip',
- url:
- 'http://0.0.0.0:3000/root/release-test/-/archive/v5.10/release-test-v5.10.zip',
- },
- {
- format: 'tar.gz',
- url:
- 'http://0.0.0.0:3000/root/release-test/-/archive/v5.10/release-test-v5.10.tar.gz',
- },
- {
- format: 'tar.bz2',
- url:
- 'http://0.0.0.0:3000/root/release-test/-/archive/v5.10/release-test-v5.10.tar.bz2',
- },
- {
- format: 'tar',
- url:
- 'http://0.0.0.0:3000/root/release-test/-/archive/v5.10/release-test-v5.10.tar',
- },
- ],
- },
- links: {
- nodes: [
- {
- id: 'gid://gitlab/Releases::Link/69',
- name: 'An example link',
- url: 'https://example.com/link',
- directAssetUrl:
- 'http://0.0.0.0:3000/root/release-test/-/releases/v5.32/permanent/path/to/runbook',
- linkType: 'OTHER',
- external: true,
- },
- {
- id: 'gid://gitlab/Releases::Link/68',
- name: 'An example package link',
- url: 'https://example.com/package',
- directAssetUrl: 'https://example.com/package',
- linkType: 'PACKAGE',
- external: true,
- },
- {
- id: 'gid://gitlab/Releases::Link/67',
- name: 'An example image',
- url: 'https://example.com/image',
- directAssetUrl: 'https://example.com/image',
- linkType: 'IMAGE',
- external: true,
- },
- ],
- },
- },
- evidences: {
- nodes: [
- {
- filepath:
- 'http://0.0.0.0:3000/root/release-test/-/releases/v5.10/evidences/34.json',
- collectedAt: '2020-08-21T20:15:19Z',
- sha: '22bde8e8b93d870a29ddc339287a1fbb598f45d1396d',
- },
- ],
- },
- links: {
- editUrl: 'http://0.0.0.0:3000/root/release-test/-/releases/v5.10/edit',
- issuesUrl: null,
- mergeRequestsUrl: null,
- selfUrl: 'http://0.0.0.0:3000/root/release-test/-/releases/v5.10',
- },
- commit: {
- sha: '92e7ea2ee4496fe0d00ff69830ba0564d3d1e5a7',
- webUrl:
- 'http://0.0.0.0:3000/root/release-test/-/commit/92e7ea2ee4496fe0d00ff69830ba0564d3d1e5a7',
- title: 'Testing a change.',
- },
- author: {
- webUrl: 'http://0.0.0.0:3000/root',
- avatarUrl: '/uploads/-/system/user/avatar/1/avatar.png',
- username: 'root',
- },
- milestones: {
- nodes: [
- {
- id: 'gid://gitlab/Milestone/60',
- title: '12.4',
- description: '',
- webPath: '/root/release-test/-/milestones/2',
- stats: {
- totalIssuesCount: 0,
- closedIssuesCount: 0,
- },
- },
- {
- id: 'gid://gitlab/Milestone/59',
- title: '12.3',
- description: 'Milestone 12.3',
- webPath: '/root/release-test/-/milestones/1',
- stats: {
- totalIssuesCount: 2,
- closedIssuesCount: 1,
- },
- },
- ],
- },
- },
- ],
- },
- },
- },
-};
diff --git a/spec/frontend/releases/stores/getters_spec.js b/spec/frontend/releases/stores/getters_spec.js
new file mode 100644
index 00000000000..01e10567cf0
--- /dev/null
+++ b/spec/frontend/releases/stores/getters_spec.js
@@ -0,0 +1,22 @@
+import * as getters from '~/releases/stores/getters';
+
+describe('~/releases/stores/getters.js', () => {
+ it.each`
+ graphqlReleaseData | graphqlReleasesPage | graphqlMilestoneStats | result
+ ${false} | ${false} | ${false} | ${false}
+ ${false} | ${false} | ${true} | ${false}
+ ${false} | ${true} | ${false} | ${false}
+ ${false} | ${true} | ${true} | ${false}
+ ${true} | ${false} | ${false} | ${false}
+ ${true} | ${false} | ${true} | ${false}
+ ${true} | ${true} | ${false} | ${false}
+ ${true} | ${true} | ${true} | ${true}
+ `(
+ 'returns $result with feature flag values graphqlReleaseData=$graphqlReleaseData, graphqlReleasesPage=$graphqlReleasesPage, and graphqlMilestoneStats=$graphqlMilestoneStats',
+ ({ result: expectedResult, ...featureFlags }) => {
+ const actualResult = getters.useGraphQLEndpoint({ featureFlags });
+
+ expect(actualResult).toBe(expectedResult);
+ },
+ );
+});
diff --git a/spec/frontend/releases/stores/modules/detail/actions_spec.js b/spec/frontend/releases/stores/modules/detail/actions_spec.js
index 1b2a705e8f4..d38f6766d4e 100644
--- a/spec/frontend/releases/stores/modules/detail/actions_spec.js
+++ b/spec/frontend/releases/stores/modules/detail/actions_spec.js
@@ -1,10 +1,10 @@
import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
import testAction from 'helpers/vuex_action_helper';
+import { getJSONFixture } from 'helpers/fixtures';
import { cloneDeep } from 'lodash';
import * as actions from '~/releases/stores/modules/detail/actions';
import * as types from '~/releases/stores/modules/detail/mutation_types';
-import { release as originalRelease } from '../../../mock_data';
import createState from '~/releases/stores/modules/detail/state';
import { deprecatedCreateFlash as createFlash } from '~/flash';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
@@ -21,6 +21,8 @@ jest.mock('~/lib/utils/url_utility', () => ({
joinPaths: jest.requireActual('~/lib/utils/url_utility').joinPaths,
}));
+const originalRelease = getJSONFixture('api/releases/release.json');
+
describe('Release detail actions', () => {
let state;
let release;
@@ -32,6 +34,12 @@ describe('Release detail actions', () => {
isExistingRelease: true,
};
+ const rootState = {
+ featureFlags: {
+ graphqlIndividualReleasePage: false,
+ },
+ };
+
state = {
...createState({
projectId: '18',
@@ -42,6 +50,7 @@ describe('Release detail actions', () => {
updateReleaseApiDocsPath: 'path/to/api/docs',
}),
...getters,
+ ...rootState,
...updates,
};
};
@@ -152,7 +161,7 @@ describe('Release detail actions', () => {
});
it(`shows a flash message`, () => {
- return actions.fetchRelease({ commit: jest.fn(), state }).then(() => {
+ return actions.fetchRelease({ commit: jest.fn(), state, rootState: state }).then(() => {
expect(createFlash).toHaveBeenCalledTimes(1);
expect(createFlash).toHaveBeenCalledWith(
'Something went wrong while getting the release details',
@@ -207,6 +216,15 @@ describe('Release detail actions', () => {
});
});
+ describe('updateReleaseGroupMilestones', () => {
+ it(`commits ${types.UPDATE_RELEASE_GROUP_MILESTONES} with the updated release group milestones`, () => {
+ const newReleaseGroupMilestones = ['v0.0', 'v0.1'];
+ return testAction(actions.updateReleaseGroupMilestones, newReleaseGroupMilestones, state, [
+ { type: types.UPDATE_RELEASE_GROUP_MILESTONES, payload: newReleaseGroupMilestones },
+ ]);
+ });
+ });
+
describe('addEmptyAssetLink', () => {
it(`commits ${types.ADD_EMPTY_ASSET_LINK}`, () => {
return testAction(actions.addEmptyAssetLink, undefined, state, [
@@ -265,32 +283,14 @@ describe('Release detail actions', () => {
describe('receiveSaveReleaseSuccess', () => {
it(`commits ${types.RECEIVE_SAVE_RELEASE_SUCCESS}`, () =>
- testAction(actions.receiveSaveReleaseSuccess, undefined, { ...state, featureFlags: {} }, [
+ testAction(actions.receiveSaveReleaseSuccess, release, state, [
{ type: types.RECEIVE_SAVE_RELEASE_SUCCESS },
]));
- describe('when the releaseShowPage feature flag is enabled', () => {
- beforeEach(() => {
- const rootState = { featureFlags: { releaseShowPage: true } };
- actions.receiveSaveReleaseSuccess({ commit: jest.fn(), state, rootState }, release);
- });
-
- it("redirects to the release's dedicated page", () => {
- expect(redirectTo).toHaveBeenCalledTimes(1);
- expect(redirectTo).toHaveBeenCalledWith(release._links.self);
- });
- });
-
- describe('when the releaseShowPage feature flag is disabled', () => {
- beforeEach(() => {
- const rootState = { featureFlags: { releaseShowPage: false } };
- actions.receiveSaveReleaseSuccess({ commit: jest.fn(), state, rootState }, release);
- });
-
- it("redirects to the project's main Releases page", () => {
- expect(redirectTo).toHaveBeenCalledTimes(1);
- expect(redirectTo).toHaveBeenCalledWith(state.releasesPagePath);
- });
+ it("redirects to the release's dedicated page", () => {
+ actions.receiveSaveReleaseSuccess({ commit: jest.fn(), state }, release);
+ expect(redirectTo).toHaveBeenCalledTimes(1);
+ expect(redirectTo).toHaveBeenCalledWith(release._links.self);
});
});
diff --git a/spec/frontend/releases/stores/modules/detail/mutations_spec.js b/spec/frontend/releases/stores/modules/detail/mutations_spec.js
index cd7c6b7d275..f3e84262754 100644
--- a/spec/frontend/releases/stores/modules/detail/mutations_spec.js
+++ b/spec/frontend/releases/stores/modules/detail/mutations_spec.js
@@ -1,10 +1,12 @@
+import { getJSONFixture } from 'helpers/fixtures';
import createState from '~/releases/stores/modules/detail/state';
import mutations from '~/releases/stores/modules/detail/mutations';
import * as types from '~/releases/stores/modules/detail/mutation_types';
-import { release as originalRelease } from '../../../mock_data';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
import { ASSET_LINK_TYPE, DEFAULT_ASSET_LINK_TYPE } from '~/releases/constants';
+const originalRelease = getJSONFixture('api/releases/release.json');
+
describe('Release detail mutations', () => {
let state;
let release;
@@ -30,6 +32,7 @@ describe('Release detail mutations', () => {
name: '',
description: '',
milestones: [],
+ groupMilestones: [],
assets: {
links: [],
},
@@ -112,6 +115,26 @@ describe('Release detail mutations', () => {
});
});
+ describe(`${types.UPDATE_RELEASE_MILESTONES}`, () => {
+ it("updates the release's milestones", () => {
+ state.release = release;
+ const newReleaseMilestones = ['v0.0', 'v0.1'];
+ mutations[types.UPDATE_RELEASE_MILESTONES](state, newReleaseMilestones);
+
+ expect(state.release.milestones).toBe(newReleaseMilestones);
+ });
+ });
+
+ describe(`${types.UPDATE_RELEASE_GROUP_MILESTONES}`, () => {
+ it("updates the release's group milestones", () => {
+ state.release = release;
+ const newReleaseGroupMilestones = ['v0.0', 'v0.1'];
+ mutations[types.UPDATE_RELEASE_GROUP_MILESTONES](state, newReleaseGroupMilestones);
+
+ expect(state.release.groupMilestones).toBe(newReleaseGroupMilestones);
+ });
+ });
+
describe(`${types.REQUEST_SAVE_RELEASE}`, () => {
it('set state.isUpdatingRelease to true', () => {
mutations[types.REQUEST_SAVE_RELEASE](state);
diff --git a/spec/frontend/releases/stores/modules/list/actions_spec.js b/spec/frontend/releases/stores/modules/list/actions_spec.js
index 95e30659d6c..4e235e1d00f 100644
--- a/spec/frontend/releases/stores/modules/list/actions_spec.js
+++ b/spec/frontend/releases/stores/modules/list/actions_spec.js
@@ -1,31 +1,42 @@
import { cloneDeep } from 'lodash';
import testAction from 'helpers/vuex_action_helper';
+import { getJSONFixture } from 'helpers/fixtures';
import {
- requestReleases,
fetchReleases,
- receiveReleasesSuccess,
+ fetchReleasesGraphQl,
+ fetchReleasesRest,
receiveReleasesError,
} from '~/releases/stores/modules/list/actions';
import createState from '~/releases/stores/modules/list/state';
import * as types from '~/releases/stores/modules/list/mutation_types';
import api from '~/api';
-import { gqClient, convertGraphQLResponse } from '~/releases/util';
-import { parseIntPagination, convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
+import { gqClient, convertAllReleasesGraphQLResponse } from '~/releases/util';
import {
- pageInfoHeadersWithoutPagination,
- releases as originalReleases,
- graphqlReleasesResponse as originalGraphqlReleasesResponse,
-} from '../../../mock_data';
+ normalizeHeaders,
+ parseIntPagination,
+ convertObjectPropsToCamelCase,
+} from '~/lib/utils/common_utils';
+import { pageInfoHeadersWithoutPagination } from '../../../mock_data';
import allReleasesQuery from '~/releases/queries/all_releases.query.graphql';
+import { PAGE_SIZE } from '~/releases/constants';
+
+const originalRelease = getJSONFixture('api/releases/release.json');
+const originalReleases = [originalRelease];
+
+const originalGraphqlReleasesResponse = getJSONFixture(
+ 'graphql/releases/queries/all_releases.query.graphql.json',
+);
describe('Releases State actions', () => {
let mockedState;
- let pageInfo;
let releases;
let graphqlReleasesResponse;
const projectPath = 'root/test-project';
const projectId = 19;
+ const before = 'testBeforeCursor';
+ const after = 'testAfterCursor';
+ const page = 2;
beforeEach(() => {
mockedState = {
@@ -33,178 +44,261 @@ describe('Releases State actions', () => {
projectId,
projectPath,
}),
- featureFlags: {
- graphqlReleaseData: true,
- graphqlReleasesPage: true,
- graphqlMilestoneStats: true,
- },
};
- pageInfo = parseIntPagination(pageInfoHeadersWithoutPagination);
releases = convertObjectPropsToCamelCase(originalReleases, { deep: true });
graphqlReleasesResponse = cloneDeep(originalGraphqlReleasesResponse);
});
- describe('requestReleases', () => {
- it('should commit REQUEST_RELEASES mutation', done => {
- testAction(requestReleases, null, mockedState, [{ type: types.REQUEST_RELEASES }], [], done);
+ describe('when all the necessary GraphQL feature flags are enabled', () => {
+ beforeEach(() => {
+ mockedState.useGraphQLEndpoint = true;
+ });
+
+ describe('fetchReleases', () => {
+ it('dispatches fetchReleasesGraphQl with before and after parameters', () => {
+ return testAction(
+ fetchReleases,
+ { before, after, page },
+ mockedState,
+ [],
+ [
+ {
+ type: 'fetchReleasesGraphQl',
+ payload: { before, after },
+ },
+ ],
+ );
+ });
});
});
- describe('fetchReleases', () => {
- describe('success', () => {
- it('dispatches requestReleases and receiveReleasesSuccess', done => {
- jest.spyOn(gqClient, 'query').mockImplementation(({ query, variables }) => {
- expect(query).toBe(allReleasesQuery);
- expect(variables).toEqual({
- fullPath: projectPath,
+ describe('when at least one of the GraphQL feature flags is disabled', () => {
+ beforeEach(() => {
+ mockedState.useGraphQLEndpoint = false;
+ });
+
+ describe('fetchReleases', () => {
+ it('dispatches fetchReleasesRest with a page parameter', () => {
+ return testAction(
+ fetchReleases,
+ { before, after, page },
+ mockedState,
+ [],
+ [
+ {
+ type: 'fetchReleasesRest',
+ payload: { page },
+ },
+ ],
+ );
+ });
+ });
+ });
+
+ describe('fetchReleasesGraphQl', () => {
+ describe('GraphQL query variables', () => {
+ let vuexParams;
+
+ beforeEach(() => {
+ jest.spyOn(gqClient, 'query');
+
+ vuexParams = { dispatch: jest.fn(), commit: jest.fn(), state: mockedState };
+ });
+
+ describe('when neither a before nor an after parameter is provided', () => {
+ beforeEach(() => {
+ fetchReleasesGraphQl(vuexParams, { before: undefined, after: undefined });
+ });
+
+ it('makes a GraphQl query with a first variable', () => {
+ expect(gqClient.query).toHaveBeenCalledWith({
+ query: allReleasesQuery,
+ variables: { fullPath: projectPath, first: PAGE_SIZE },
});
- return Promise.resolve(graphqlReleasesResponse);
});
+ });
- testAction(
- fetchReleases,
+ describe('when only a before parameter is provided', () => {
+ beforeEach(() => {
+ fetchReleasesGraphQl(vuexParams, { before, after: undefined });
+ });
+
+ it('makes a GraphQl query with last and before variables', () => {
+ expect(gqClient.query).toHaveBeenCalledWith({
+ query: allReleasesQuery,
+ variables: { fullPath: projectPath, last: PAGE_SIZE, before },
+ });
+ });
+ });
+
+ describe('when only an after parameter is provided', () => {
+ beforeEach(() => {
+ fetchReleasesGraphQl(vuexParams, { before: undefined, after });
+ });
+
+ it('makes a GraphQl query with first and after variables', () => {
+ expect(gqClient.query).toHaveBeenCalledWith({
+ query: allReleasesQuery,
+ variables: { fullPath: projectPath, first: PAGE_SIZE, after },
+ });
+ });
+ });
+
+ describe('when both before and after parameters are provided', () => {
+ it('throws an error', () => {
+ const callFetchReleasesGraphQl = () => {
+ fetchReleasesGraphQl(vuexParams, { before, after });
+ };
+
+ expect(callFetchReleasesGraphQl).toThrowError(
+ 'Both a `before` and an `after` parameter were provided to fetchReleasesGraphQl. These parameters cannot be used together.',
+ );
+ });
+ });
+ });
+
+ describe('when the request is successful', () => {
+ beforeEach(() => {
+ jest.spyOn(gqClient, 'query').mockResolvedValue(graphqlReleasesResponse);
+ });
+
+ it(`commits ${types.REQUEST_RELEASES} and ${types.RECEIVE_RELEASES_SUCCESS}`, () => {
+ const convertedResponse = convertAllReleasesGraphQLResponse(graphqlReleasesResponse);
+
+ return testAction(
+ fetchReleasesGraphQl,
{},
mockedState,
- [],
[
{
- type: 'requestReleases',
+ type: types.REQUEST_RELEASES,
},
{
- payload: convertGraphQLResponse(graphqlReleasesResponse),
- type: 'receiveReleasesSuccess',
+ type: types.RECEIVE_RELEASES_SUCCESS,
+ payload: {
+ data: convertedResponse.data,
+ graphQlPageInfo: convertedResponse.paginationInfo,
+ },
},
],
- done,
+ [],
);
});
});
- describe('error', () => {
- it('dispatches requestReleases and receiveReleasesError', done => {
- jest.spyOn(gqClient, 'query').mockRejectedValue();
+ describe('when the request fails', () => {
+ beforeEach(() => {
+ jest.spyOn(gqClient, 'query').mockRejectedValue(new Error('Something went wrong!'));
+ });
- testAction(
- fetchReleases,
+ it(`commits ${types.REQUEST_RELEASES} and dispatch receiveReleasesError`, () => {
+ return testAction(
+ fetchReleasesGraphQl,
{},
mockedState,
- [],
[
{
- type: 'requestReleases',
+ type: types.REQUEST_RELEASES,
},
+ ],
+ [
{
type: 'receiveReleasesError',
},
],
- done,
);
});
});
+ });
+
+ describe('fetchReleasesRest', () => {
+ describe('REST query parameters', () => {
+ let vuexParams;
- describe('when the graphqlReleaseData feature flag is disabled', () => {
beforeEach(() => {
- mockedState.featureFlags.graphqlReleasesPage = false;
- });
+ jest
+ .spyOn(api, 'releases')
+ .mockResolvedValue({ data: releases, headers: pageInfoHeadersWithoutPagination });
- describe('success', () => {
- it('dispatches requestReleases and receiveReleasesSuccess', done => {
- jest.spyOn(api, 'releases').mockImplementation((id, options) => {
- expect(id).toBe(projectId);
- expect(options.page).toBe('1');
- return Promise.resolve({ data: releases, headers: pageInfoHeadersWithoutPagination });
- });
+ vuexParams = { dispatch: jest.fn(), commit: jest.fn(), state: mockedState };
+ });
- testAction(
- fetchReleases,
- {},
- mockedState,
- [],
- [
- {
- type: 'requestReleases',
- },
- {
- payload: { data: releases, headers: pageInfoHeadersWithoutPagination },
- type: 'receiveReleasesSuccess',
- },
- ],
- done,
- );
+ describe('when a page parameter is provided', () => {
+ beforeEach(() => {
+ fetchReleasesRest(vuexParams, { page: 2 });
});
- it('dispatches requestReleases and receiveReleasesSuccess on page two', done => {
- jest.spyOn(api, 'releases').mockImplementation((_, options) => {
- expect(options.page).toBe('2');
- return Promise.resolve({ data: releases, headers: pageInfoHeadersWithoutPagination });
- });
-
- testAction(
- fetchReleases,
- { page: '2' },
- mockedState,
- [],
- [
- {
- type: 'requestReleases',
- },
- {
- payload: { data: releases, headers: pageInfoHeadersWithoutPagination },
- type: 'receiveReleasesSuccess',
- },
- ],
- done,
- );
+ it('makes a REST query with a page query parameter', () => {
+ expect(api.releases).toHaveBeenCalledWith(projectId, { page });
});
});
+ });
- describe('error', () => {
- it('dispatches requestReleases and receiveReleasesError', done => {
- jest.spyOn(api, 'releases').mockReturnValue(Promise.reject());
+ describe('when the request is successful', () => {
+ beforeEach(() => {
+ jest
+ .spyOn(api, 'releases')
+ .mockResolvedValue({ data: releases, headers: pageInfoHeadersWithoutPagination });
+ });
- testAction(
- fetchReleases,
- {},
- mockedState,
- [],
- [
- {
- type: 'requestReleases',
- },
- {
- type: 'receiveReleasesError',
+ it(`commits ${types.REQUEST_RELEASES} and ${types.RECEIVE_RELEASES_SUCCESS}`, () => {
+ return testAction(
+ fetchReleasesRest,
+ {},
+ mockedState,
+ [
+ {
+ type: types.REQUEST_RELEASES,
+ },
+ {
+ type: types.RECEIVE_RELEASES_SUCCESS,
+ payload: {
+ data: convertObjectPropsToCamelCase(releases, { deep: true }),
+ restPageInfo: parseIntPagination(
+ normalizeHeaders(pageInfoHeadersWithoutPagination),
+ ),
},
- ],
- done,
- );
- });
+ },
+ ],
+ [],
+ );
});
});
- });
- describe('receiveReleasesSuccess', () => {
- it('should commit RECEIVE_RELEASES_SUCCESS mutation', done => {
- testAction(
- receiveReleasesSuccess,
- { data: releases, headers: pageInfoHeadersWithoutPagination },
- mockedState,
- [{ type: types.RECEIVE_RELEASES_SUCCESS, payload: { pageInfo, data: releases } }],
- [],
- done,
- );
+ describe('when the request fails', () => {
+ beforeEach(() => {
+ jest.spyOn(api, 'releases').mockRejectedValue(new Error('Something went wrong!'));
+ });
+
+ it(`commits ${types.REQUEST_RELEASES} and dispatch receiveReleasesError`, () => {
+ return testAction(
+ fetchReleasesRest,
+ {},
+ mockedState,
+ [
+ {
+ type: types.REQUEST_RELEASES,
+ },
+ ],
+ [
+ {
+ type: 'receiveReleasesError',
+ },
+ ],
+ );
+ });
});
});
describe('receiveReleasesError', () => {
- it('should commit RECEIVE_RELEASES_ERROR mutation', done => {
- testAction(
+ it('should commit RECEIVE_RELEASES_ERROR mutation', () => {
+ return testAction(
receiveReleasesError,
null,
mockedState,
[{ type: types.RECEIVE_RELEASES_ERROR }],
[],
- done,
);
});
});
diff --git a/spec/frontend/releases/stores/modules/list/mutations_spec.js b/spec/frontend/releases/stores/modules/list/mutations_spec.js
index 27ad05846e7..521418cbddb 100644
--- a/spec/frontend/releases/stores/modules/list/mutations_spec.js
+++ b/spec/frontend/releases/stores/modules/list/mutations_spec.js
@@ -1,16 +1,29 @@
+import { getJSONFixture } from 'helpers/fixtures';
import createState from '~/releases/stores/modules/list/state';
import mutations from '~/releases/stores/modules/list/mutations';
import * as types from '~/releases/stores/modules/list/mutation_types';
-import { parseIntPagination } from '~/lib/utils/common_utils';
-import { pageInfoHeadersWithoutPagination, releases } from '../../../mock_data';
+import { parseIntPagination, convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
+import { pageInfoHeadersWithoutPagination } from '../../../mock_data';
+import { convertAllReleasesGraphQLResponse } from '~/releases/util';
+
+const originalRelease = getJSONFixture('api/releases/release.json');
+const originalReleases = [originalRelease];
+
+const graphqlReleasesResponse = getJSONFixture(
+ 'graphql/releases/queries/all_releases.query.graphql.json',
+);
describe('Releases Store Mutations', () => {
let stateCopy;
- let pageInfo;
+ let restPageInfo;
+ let graphQlPageInfo;
+ let releases;
beforeEach(() => {
stateCopy = createState({});
- pageInfo = parseIntPagination(pageInfoHeadersWithoutPagination);
+ restPageInfo = parseIntPagination(pageInfoHeadersWithoutPagination);
+ graphQlPageInfo = convertAllReleasesGraphQLResponse(graphqlReleasesResponse).paginationInfo;
+ releases = convertObjectPropsToCamelCase(originalReleases, { deep: true });
});
describe('REQUEST_RELEASES', () => {
@@ -23,7 +36,11 @@ describe('Releases Store Mutations', () => {
describe('RECEIVE_RELEASES_SUCCESS', () => {
beforeEach(() => {
- mutations[types.RECEIVE_RELEASES_SUCCESS](stateCopy, { pageInfo, data: releases });
+ mutations[types.RECEIVE_RELEASES_SUCCESS](stateCopy, {
+ restPageInfo,
+ graphQlPageInfo,
+ data: releases,
+ });
});
it('sets is loading to false', () => {
@@ -38,18 +55,29 @@ describe('Releases Store Mutations', () => {
expect(stateCopy.releases).toEqual(releases);
});
- it('sets pageInfo', () => {
- expect(stateCopy.pageInfo).toEqual(pageInfo);
+ it('sets restPageInfo', () => {
+ expect(stateCopy.restPageInfo).toEqual(restPageInfo);
+ });
+
+ it('sets graphQlPageInfo', () => {
+ expect(stateCopy.graphQlPageInfo).toEqual(graphQlPageInfo);
});
});
describe('RECEIVE_RELEASES_ERROR', () => {
it('resets data', () => {
+ mutations[types.RECEIVE_RELEASES_SUCCESS](stateCopy, {
+ restPageInfo,
+ graphQlPageInfo,
+ data: releases,
+ });
+
mutations[types.RECEIVE_RELEASES_ERROR](stateCopy);
expect(stateCopy.isLoading).toEqual(false);
expect(stateCopy.releases).toEqual([]);
- expect(stateCopy.pageInfo).toEqual({});
+ expect(stateCopy.restPageInfo).toEqual({});
+ expect(stateCopy.graphQlPageInfo).toEqual({});
});
});
});
diff --git a/spec/frontend/releases/util_spec.js b/spec/frontend/releases/util_spec.js
index f40e5729188..e7b7766c0d0 100644
--- a/spec/frontend/releases/util_spec.js
+++ b/spec/frontend/releases/util_spec.js
@@ -1,6 +1,19 @@
import { cloneDeep } from 'lodash';
-import { releaseToApiJson, apiJsonToRelease, convertGraphQLResponse } from '~/releases/util';
-import { graphqlReleasesResponse as originalGraphqlReleasesResponse } from './mock_data';
+import { getJSONFixture } from 'helpers/fixtures';
+import {
+ releaseToApiJson,
+ apiJsonToRelease,
+ convertGraphQLRelease,
+ convertAllReleasesGraphQLResponse,
+ convertOneReleaseGraphQLResponse,
+} from '~/releases/util';
+
+const originalAllReleasesQueryResponse = getJSONFixture(
+ 'graphql/releases/queries/all_releases.query.graphql.json',
+);
+const originalOneReleaseQueryResponse = getJSONFixture(
+ 'graphql/releases/queries/one_release.query.graphql.json',
+);
describe('releases/util.js', () => {
describe('releaseToApiJson', () => {
@@ -103,54 +116,61 @@ describe('releases/util.js', () => {
});
});
- describe('convertGraphQLResponse', () => {
- let graphqlReleasesResponse;
- let converted;
+ describe('convertGraphQLRelease', () => {
+ let releaseFromResponse;
+ let convertedRelease;
beforeEach(() => {
- graphqlReleasesResponse = cloneDeep(originalGraphqlReleasesResponse);
- converted = convertGraphQLResponse(graphqlReleasesResponse);
- });
-
- it('matches snapshot', () => {
- expect(converted).toMatchSnapshot();
+ releaseFromResponse = cloneDeep(originalOneReleaseQueryResponse).data.project.release;
+ convertedRelease = convertGraphQLRelease(releaseFromResponse);
});
describe('assets', () => {
it("handles asset links that don't have a linkType", () => {
- expect(converted.data[0].assets.links[0].linkType).not.toBeUndefined();
+ expect(convertedRelease.assets.links[0].linkType).not.toBeUndefined();
- delete graphqlReleasesResponse.data.project.releases.nodes[0].assets.links.nodes[0]
- .linkType;
+ delete releaseFromResponse.assets.links.nodes[0].linkType;
- converted = convertGraphQLResponse(graphqlReleasesResponse);
+ convertedRelease = convertGraphQLRelease(releaseFromResponse);
- expect(converted.data[0].assets.links[0].linkType).toBeUndefined();
+ expect(convertedRelease.assets.links[0].linkType).toBeUndefined();
});
});
describe('_links', () => {
it("handles releases that don't have any links", () => {
- expect(converted.data[0]._links.selfUrl).not.toBeUndefined();
+ expect(convertedRelease._links.selfUrl).not.toBeUndefined();
- delete graphqlReleasesResponse.data.project.releases.nodes[0].links;
+ delete releaseFromResponse.links;
- converted = convertGraphQLResponse(graphqlReleasesResponse);
+ convertedRelease = convertGraphQLRelease(releaseFromResponse);
- expect(converted.data[0]._links.selfUrl).toBeUndefined();
+ expect(convertedRelease._links.selfUrl).toBeUndefined();
});
});
describe('commit', () => {
it("handles releases that don't have any commit info", () => {
- expect(converted.data[0].commit).not.toBeUndefined();
+ expect(convertedRelease.commit).not.toBeUndefined();
- delete graphqlReleasesResponse.data.project.releases.nodes[0].commit;
+ delete releaseFromResponse.commit;
- converted = convertGraphQLResponse(graphqlReleasesResponse);
+ convertedRelease = convertGraphQLRelease(releaseFromResponse);
- expect(converted.data[0].commit).toBeUndefined();
+ expect(convertedRelease.commit).toBeUndefined();
});
});
});
+
+ describe('convertAllReleasesGraphQLResponse', () => {
+ it('matches snapshot', () => {
+ expect(convertAllReleasesGraphQLResponse(originalAllReleasesQueryResponse)).toMatchSnapshot();
+ });
+ });
+
+ describe('convertOneReleaseGraphQLResponse', () => {
+ it('matches snapshot', () => {
+ expect(convertOneReleaseGraphQLResponse(originalOneReleaseQueryResponse)).toMatchSnapshot();
+ });
+ });
});
diff --git a/spec/frontend/repository/components/__snapshots__/last_commit_spec.js.snap b/spec/frontend/repository/components/__snapshots__/last_commit_spec.js.snap
index cf2e6b00800..aaa8bf168f2 100644
--- a/spec/frontend/repository/components/__snapshots__/last_commit_spec.js.snap
+++ b/spec/frontend/repository/components/__snapshots__/last_commit_spec.js.snap
@@ -77,24 +77,31 @@ exports[`Repository last commit component renders commit widget 1`] = `
</gl-link-stub>
</div>
- <div
- class="commit-sha-group d-flex"
+ <gl-button-group-stub
+ class="gl-ml-4 js-commit-sha-group"
>
- <div
- class="label label-monospace monospace"
+ <gl-button-stub
+ buttontextclasses=""
+ category="primary"
+ class="gl-font-monospace"
+ data-testid="last-commit-id-label"
+ icon=""
+ label="true"
+ size="medium"
+ variant="default"
>
-
- 12345678
-
- </div>
+ 12345678
+ </gl-button-stub>
<clipboard-button-stub
- cssclass="btn-default"
+ category="secondary"
+ class="input-group-text"
+ size="medium"
text="123456789"
title="Copy commit SHA"
- tooltipplacement="bottom"
+ tooltipplacement="top"
/>
- </div>
+ </gl-button-group-stub>
</div>
</div>
</div>
@@ -181,24 +188,31 @@ exports[`Repository last commit component renders the signature HTML as returned
</gl-link-stub>
</div>
- <div
- class="commit-sha-group d-flex"
+ <gl-button-group-stub
+ class="gl-ml-4 js-commit-sha-group"
>
- <div
- class="label label-monospace monospace"
+ <gl-button-stub
+ buttontextclasses=""
+ category="primary"
+ class="gl-font-monospace"
+ data-testid="last-commit-id-label"
+ icon=""
+ label="true"
+ size="medium"
+ variant="default"
>
-
- 12345678
-
- </div>
+ 12345678
+ </gl-button-stub>
<clipboard-button-stub
- cssclass="btn-default"
+ category="secondary"
+ class="input-group-text"
+ size="medium"
text="123456789"
title="Copy commit SHA"
- tooltipplacement="bottom"
+ tooltipplacement="top"
/>
- </div>
+ </gl-button-group-stub>
</div>
</div>
</div>
diff --git a/spec/frontend/repository/components/breadcrumbs_spec.js b/spec/frontend/repository/components/breadcrumbs_spec.js
index ca4120576f5..38e5c9aaca5 100644
--- a/spec/frontend/repository/components/breadcrumbs_spec.js
+++ b/spec/frontend/repository/components/breadcrumbs_spec.js
@@ -1,5 +1,5 @@
import { shallowMount, RouterLinkStub } from '@vue/test-utils';
-import { GlDeprecatedDropdown } from '@gitlab/ui';
+import { GlDropdown } from '@gitlab/ui';
import Breadcrumbs from '~/repository/components/breadcrumbs.vue';
let vm;
@@ -61,7 +61,7 @@ describe('Repository breadcrumbs component', () => {
vm.setData({ userPermissions: { forkProject: false, createMergeRequestIn: false } });
return vm.vm.$nextTick(() => {
- expect(vm.find(GlDeprecatedDropdown).exists()).toBe(false);
+ expect(vm.find(GlDropdown).exists()).toBe(false);
});
});
@@ -71,7 +71,7 @@ describe('Repository breadcrumbs component', () => {
vm.setData({ userPermissions: { forkProject: true, createMergeRequestIn: true } });
return vm.vm.$nextTick(() => {
- expect(vm.find(GlDeprecatedDropdown).exists()).toBe(true);
+ expect(vm.find(GlDropdown).exists()).toBe(true);
});
});
});
diff --git a/spec/frontend/repository/components/last_commit_spec.js b/spec/frontend/repository/components/last_commit_spec.js
index c14a7f0e061..ccba0982c26 100644
--- a/spec/frontend/repository/components/last_commit_spec.js
+++ b/spec/frontend/repository/components/last_commit_spec.js
@@ -78,7 +78,7 @@ describe('Repository last commit component', () => {
factory();
return vm.vm.$nextTick(() => {
- expect(vm.find('.label-monospace').text()).toEqual('12345678');
+ expect(vm.find('[data-testid="last-commit-id-label"]').text()).toEqual('12345678');
});
});
diff --git a/spec/frontend/repository/components/preview/__snapshots__/index_spec.js.snap b/spec/frontend/repository/components/preview/__snapshots__/index_spec.js.snap
index 69b7a3931f8..23c06dc5e68 100644
--- a/spec/frontend/repository/components/preview/__snapshots__/index_spec.js.snap
+++ b/spec/frontend/repository/components/preview/__snapshots__/index_spec.js.snap
@@ -10,9 +10,10 @@ exports[`Repository file preview component renders file HTML 1`] = `
<div
class="file-header-content"
>
- <i
+ <gl-icon-stub
aria-hidden="true"
- class="fa fa-file-text-o fa-fw"
+ name="doc-text"
+ size="16"
/>
<gl-link-stub
diff --git a/spec/frontend/repository/log_tree_spec.js b/spec/frontend/repository/log_tree_spec.js
index 954424b5c8a..ddc95feccd6 100644
--- a/spec/frontend/repository/log_tree_spec.js
+++ b/spec/frontend/repository/log_tree_spec.js
@@ -84,6 +84,14 @@ describe('fetchLogsTree', () => {
expect(axios.get.mock.calls.length).toEqual(1);
}));
+ it('calls axios for each path', () =>
+ Promise.all([
+ fetchLogsTree(client, '', '0', resolver),
+ fetchLogsTree(client, '/test', '0', resolver),
+ ]).then(() => {
+ expect(axios.get.mock.calls.length).toEqual(2);
+ }));
+
it('calls entry resolver', () =>
fetchLogsTree(client, '', '0', resolver).then(() => {
expect(resolver.resolve).toHaveBeenCalledWith(
diff --git a/spec/frontend/repository/utils/icon_spec.js b/spec/frontend/repository/utils/icon_spec.js
deleted file mode 100644
index 3d84705f7ea..00000000000
--- a/spec/frontend/repository/utils/icon_spec.js
+++ /dev/null
@@ -1,23 +0,0 @@
-import { getIconName } from '~/repository/utils/icon';
-
-describe('getIconName', () => {
- // Tests the returning font awesome icon name
- // We only test one for each file type to save testing a lot of different
- // file types
- it.each`
- type | path | icon
- ${'tree'} | ${''} | ${'folder'}
- ${'commit'} | ${''} | ${'archive'}
- ${'file'} | ${'test.pdf'} | ${'file-pdf-o'}
- ${'file'} | ${'test.jpg'} | ${'file-image-o'}
- ${'file'} | ${'test.zip'} | ${'file-archive-o'}
- ${'file'} | ${'test.mp3'} | ${'file-audio-o'}
- ${'file'} | ${'test.flv'} | ${'file-video-o'}
- ${'file'} | ${'test.dotx'} | ${'file-word-o'}
- ${'file'} | ${'test.xlsb'} | ${'file-excel-o'}
- ${'file'} | ${'test.ppam'} | ${'file-powerpoint-o'}
- ${'file'} | ${'test.js'} | ${'file-text-o'}
- `('returns $icon for $type with path $path', ({ type, path, icon }) => {
- expect(getIconName(type, path)).toEqual(icon);
- });
-});
diff --git a/spec/frontend/right_sidebar_spec.js b/spec/frontend/right_sidebar_spec.js
index d80d80152a5..3490a99afb4 100644
--- a/spec/frontend/right_sidebar_spec.js
+++ b/spec/frontend/right_sidebar_spec.js
@@ -6,7 +6,9 @@ import Sidebar from '~/right_sidebar';
let $aside = null;
let $toggle = null;
-let $icon = null;
+let $toggleContainer = null;
+let $expandIcon = null;
+let $collapseIcon = null;
let $page = null;
let $labelsIcon = null;
@@ -15,10 +17,11 @@ const assertSidebarState = state => {
const shouldBeCollapsed = state === 'collapsed';
expect($aside.hasClass('right-sidebar-expanded')).toBe(shouldBeExpanded);
expect($page.hasClass('right-sidebar-expanded')).toBe(shouldBeExpanded);
- expect($icon.hasClass('fa-angle-double-right')).toBe(shouldBeExpanded);
+ expect($toggleContainer.data('is-expanded')).toBe(shouldBeExpanded);
+ expect($expandIcon.hasClass('hidden')).toBe(shouldBeExpanded);
expect($aside.hasClass('right-sidebar-collapsed')).toBe(shouldBeCollapsed);
expect($page.hasClass('right-sidebar-collapsed')).toBe(shouldBeCollapsed);
- expect($icon.hasClass('fa-angle-double-left')).toBe(shouldBeCollapsed);
+ expect($collapseIcon.hasClass('hidden')).toBe(shouldBeCollapsed);
};
describe('RightSidebar', () => {
@@ -33,7 +36,9 @@ describe('RightSidebar', () => {
new Sidebar(); // eslint-disable-line no-new
$aside = $('.right-sidebar');
$page = $('.layout-page');
- $icon = $aside.find('i');
+ $toggleContainer = $('.js-sidebar-toggle-container');
+ $expandIcon = $aside.find('.js-sidebar-expand');
+ $collapseIcon = $aside.find('.js-sidebar-collapse');
$toggle = $aside.find('.js-sidebar-toggle');
$labelsIcon = $aside.find('.sidebar-collapsed-icon');
});
diff --git a/spec/frontend/search/components/state_filter_spec.js b/spec/frontend/search/components/state_filter_spec.js
deleted file mode 100644
index 26344f2b592..00000000000
--- a/spec/frontend/search/components/state_filter_spec.js
+++ /dev/null
@@ -1,104 +0,0 @@
-import { shallowMount } from '@vue/test-utils';
-import { GlDropdown, GlDropdownItem } from '@gitlab/ui';
-import StateFilter from '~/search/state_filter/components/state_filter.vue';
-import {
- FILTER_STATES,
- SCOPES,
- FILTER_STATES_BY_SCOPE,
- FILTER_TEXT,
-} from '~/search/state_filter/constants';
-import * as urlUtils from '~/lib/utils/url_utility';
-
-jest.mock('~/lib/utils/url_utility', () => ({
- visitUrl: jest.fn(),
- setUrlParams: jest.fn(),
-}));
-
-function createComponent(props = { scope: 'issues' }) {
- return shallowMount(StateFilter, {
- propsData: {
- ...props,
- },
- });
-}
-
-describe('StateFilter', () => {
- let wrapper;
-
- beforeEach(() => {
- wrapper = createComponent();
- });
-
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
- const findGlDropdown = () => wrapper.find(GlDropdown);
- const findGlDropdownItems = () => findGlDropdown().findAll(GlDropdownItem);
- const findDropdownItemsText = () => findGlDropdownItems().wrappers.map(w => w.text());
- const firstDropDownItem = () => findGlDropdownItems().at(0);
-
- describe('template', () => {
- describe.each`
- scope | showStateDropdown
- ${'issues'} | ${true}
- ${'merge_requests'} | ${true}
- ${'projects'} | ${false}
- ${'milestones'} | ${false}
- ${'users'} | ${false}
- ${'notes'} | ${false}
- ${'wiki_blobs'} | ${false}
- ${'blobs'} | ${false}
- `(`state dropdown`, ({ scope, showStateDropdown }) => {
- beforeEach(() => {
- wrapper = createComponent({ scope });
- });
-
- it(`does${showStateDropdown ? '' : ' not'} render when scope is ${scope}`, () => {
- expect(findGlDropdown().exists()).toBe(showStateDropdown);
- });
- });
-
- describe.each`
- state | label
- ${FILTER_STATES.ANY.value} | ${FILTER_TEXT}
- ${FILTER_STATES.OPEN.value} | ${FILTER_STATES.OPEN.label}
- ${FILTER_STATES.CLOSED.value} | ${FILTER_STATES.CLOSED.label}
- ${FILTER_STATES.MERGED.value} | ${FILTER_STATES.MERGED.label}
- `(`filter text`, ({ state, label }) => {
- describe(`when state is ${state}`, () => {
- beforeEach(() => {
- wrapper = createComponent({ scope: 'issues', state });
- });
-
- it(`sets dropdown label to ${label}`, () => {
- expect(findGlDropdown().attributes('text')).toBe(label);
- });
- });
- });
-
- describe('Filter options', () => {
- it('renders a dropdown item for each filterOption', () => {
- expect(findDropdownItemsText()).toStrictEqual(
- FILTER_STATES_BY_SCOPE[SCOPES.ISSUES].map(v => {
- return v.label;
- }),
- );
- });
-
- it('clicking a dropdown item calls setUrlParams', () => {
- const state = FILTER_STATES[Object.keys(FILTER_STATES)[0]].value;
- firstDropDownItem().vm.$emit('click');
-
- expect(urlUtils.setUrlParams).toHaveBeenCalledWith({ state });
- });
-
- it('clicking a dropdown item calls visitUrl', () => {
- firstDropDownItem().vm.$emit('click');
-
- expect(urlUtils.visitUrl).toHaveBeenCalled();
- });
- });
- });
-});
diff --git a/spec/frontend/search/dropdown_filter/components/dropdown_filter_spec.js b/spec/frontend/search/dropdown_filter/components/dropdown_filter_spec.js
new file mode 100644
index 00000000000..4a6b5cebe1c
--- /dev/null
+++ b/spec/frontend/search/dropdown_filter/components/dropdown_filter_spec.js
@@ -0,0 +1,196 @@
+import Vuex from 'vuex';
+import { createLocalVue, shallowMount } from '@vue/test-utils';
+import { GlDropdown, GlDropdownItem } from '@gitlab/ui';
+import * as urlUtils from '~/lib/utils/url_utility';
+import initStore from '~/search/store';
+import DropdownFilter from '~/search/dropdown_filter/components/dropdown_filter.vue';
+import stateFilterData from '~/search/dropdown_filter/constants/state_filter_data';
+import confidentialFilterData from '~/search/dropdown_filter/constants/confidential_filter_data';
+import { MOCK_QUERY } from '../mock_data';
+
+jest.mock('~/lib/utils/url_utility', () => ({
+ visitUrl: jest.fn(),
+ setUrlParams: jest.fn(),
+}));
+
+const localVue = createLocalVue();
+localVue.use(Vuex);
+
+describe('DropdownFilter', () => {
+ let wrapper;
+ let store;
+
+ const createStore = options => {
+ store = initStore({ query: MOCK_QUERY, ...options });
+ };
+
+ const createComponent = (props = { filterData: stateFilterData }) => {
+ wrapper = shallowMount(DropdownFilter, {
+ localVue,
+ store,
+ propsData: {
+ ...props,
+ },
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ wrapper = null;
+ store = null;
+ });
+
+ const findGlDropdown = () => wrapper.find(GlDropdown);
+ const findGlDropdownItems = () => findGlDropdown().findAll(GlDropdownItem);
+ const findDropdownItemsText = () => findGlDropdownItems().wrappers.map(w => w.text());
+ const firstDropDownItem = () => findGlDropdownItems().at(0);
+
+ describe('StatusFilter', () => {
+ describe('template', () => {
+ describe.each`
+ scope | showDropdown
+ ${'issues'} | ${true}
+ ${'merge_requests'} | ${true}
+ ${'projects'} | ${false}
+ ${'milestones'} | ${false}
+ ${'users'} | ${false}
+ ${'notes'} | ${false}
+ ${'wiki_blobs'} | ${false}
+ ${'blobs'} | ${false}
+ `(`dropdown`, ({ scope, showDropdown }) => {
+ beforeEach(() => {
+ createStore({ query: { ...MOCK_QUERY, scope } });
+ createComponent();
+ });
+
+ it(`does${showDropdown ? '' : ' not'} render when scope is ${scope}`, () => {
+ expect(findGlDropdown().exists()).toBe(showDropdown);
+ });
+ });
+
+ describe.each`
+ initialFilter | label
+ ${stateFilterData.filters.ANY.value} | ${`Any ${stateFilterData.header}`}
+ ${stateFilterData.filters.OPEN.value} | ${stateFilterData.filters.OPEN.label}
+ ${stateFilterData.filters.CLOSED.value} | ${stateFilterData.filters.CLOSED.label}
+ `(`filter text`, ({ initialFilter, label }) => {
+ describe(`when initialFilter is ${initialFilter}`, () => {
+ beforeEach(() => {
+ createStore({ query: { ...MOCK_QUERY, [stateFilterData.filterParam]: initialFilter } });
+ createComponent();
+ });
+
+ it(`sets dropdown label to ${label}`, () => {
+ expect(findGlDropdown().attributes('text')).toBe(label);
+ });
+ });
+ });
+ });
+
+ describe('Filter options', () => {
+ beforeEach(() => {
+ createStore();
+ createComponent();
+ });
+
+ it('renders a dropdown item for each filterOption', () => {
+ expect(findDropdownItemsText()).toStrictEqual(
+ stateFilterData.filterByScope[stateFilterData.scopes.ISSUES].map(v => {
+ return v.label;
+ }),
+ );
+ });
+
+ it('clicking a dropdown item calls setUrlParams', () => {
+ const filter = stateFilterData.filters[Object.keys(stateFilterData.filters)[0]].value;
+ firstDropDownItem().vm.$emit('click');
+
+ expect(urlUtils.setUrlParams).toHaveBeenCalledWith({
+ [stateFilterData.filterParam]: filter,
+ });
+ });
+
+ it('clicking a dropdown item calls visitUrl', () => {
+ firstDropDownItem().vm.$emit('click');
+
+ expect(urlUtils.visitUrl).toHaveBeenCalled();
+ });
+ });
+ });
+
+ describe('ConfidentialFilter', () => {
+ describe('template', () => {
+ describe.each`
+ scope | showDropdown
+ ${'issues'} | ${true}
+ ${'merge_requests'} | ${false}
+ ${'projects'} | ${false}
+ ${'milestones'} | ${false}
+ ${'users'} | ${false}
+ ${'notes'} | ${false}
+ ${'wiki_blobs'} | ${false}
+ ${'blobs'} | ${false}
+ `(`dropdown`, ({ scope, showDropdown }) => {
+ beforeEach(() => {
+ createStore({ query: { ...MOCK_QUERY, scope } });
+ createComponent({ filterData: confidentialFilterData });
+ });
+
+ it(`does${showDropdown ? '' : ' not'} render when scope is ${scope}`, () => {
+ expect(findGlDropdown().exists()).toBe(showDropdown);
+ });
+ });
+
+ describe.each`
+ initialFilter | label
+ ${confidentialFilterData.filters.ANY.value} | ${`Any ${confidentialFilterData.header}`}
+ ${confidentialFilterData.filters.CONFIDENTIAL.value} | ${confidentialFilterData.filters.CONFIDENTIAL.label}
+ ${confidentialFilterData.filters.NOT_CONFIDENTIAL.value} | ${confidentialFilterData.filters.NOT_CONFIDENTIAL.label}
+ `(`filter text`, ({ initialFilter, label }) => {
+ describe(`when initialFilter is ${initialFilter}`, () => {
+ beforeEach(() => {
+ createStore({
+ query: { ...MOCK_QUERY, [confidentialFilterData.filterParam]: initialFilter },
+ });
+ createComponent({ filterData: confidentialFilterData });
+ });
+
+ it(`sets dropdown label to ${label}`, () => {
+ expect(findGlDropdown().attributes('text')).toBe(label);
+ });
+ });
+ });
+ });
+ });
+
+ describe('Filter options', () => {
+ beforeEach(() => {
+ createStore();
+ createComponent({ filterData: confidentialFilterData });
+ });
+
+ it('renders a dropdown item for each filterOption', () => {
+ expect(findDropdownItemsText()).toStrictEqual(
+ confidentialFilterData.filterByScope[confidentialFilterData.scopes.ISSUES].map(v => {
+ return v.label;
+ }),
+ );
+ });
+
+ it('clicking a dropdown item calls setUrlParams', () => {
+ const filter =
+ confidentialFilterData.filters[Object.keys(confidentialFilterData.filters)[0]].value;
+ firstDropDownItem().vm.$emit('click');
+
+ expect(urlUtils.setUrlParams).toHaveBeenCalledWith({
+ [confidentialFilterData.filterParam]: filter,
+ });
+ });
+
+ it('clicking a dropdown item calls visitUrl', () => {
+ firstDropDownItem().vm.$emit('click');
+
+ expect(urlUtils.visitUrl).toHaveBeenCalled();
+ });
+ });
+});
diff --git a/spec/frontend/search/dropdown_filter/mock_data.js b/spec/frontend/search/dropdown_filter/mock_data.js
new file mode 100644
index 00000000000..f11ab3d9951
--- /dev/null
+++ b/spec/frontend/search/dropdown_filter/mock_data.js
@@ -0,0 +1,5 @@
+export const MOCK_QUERY = {
+ scope: 'issues',
+ state: 'all',
+ confidential: null,
+};
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 f4ac2f57261..02d5ca6bdb3 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
@@ -15,13 +15,16 @@ exports[`self monitor component When the self monitor project has not been creat
</h4>
- <gl-deprecated-button-stub
+ <gl-button-stub
+ buttontextclasses=""
+ category="primary"
class="js-settings-toggle"
- size="md"
- variant="secondary"
+ icon=""
+ size="medium"
+ variant="default"
>
Expand
- </gl-deprecated-button-stub>
+ </gl-button-stub>
<p
class="js-section-sub-header"
@@ -56,6 +59,7 @@ exports[`self monitor component When the self monitor project has not been creat
<gl-modal-stub
cancel-title="Cancel"
+ category="primary"
modalclass=""
modalid="delete-self-monitor-modal"
ok-title="Delete project"
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 ec5f7b0a394..618cc16cdf4 100644
--- a/spec/frontend/self_monitor/components/self_monitor_form_spec.js
+++ b/spec/frontend/self_monitor/components/self_monitor_form_spec.js
@@ -1,5 +1,5 @@
import { shallowMount } from '@vue/test-utils';
-import { GlDeprecatedButton } from '@gitlab/ui';
+import { GlButton } from '@gitlab/ui';
import { TEST_HOST } from 'helpers/test_constants';
import SelfMonitor from '~/self_monitor/components/self_monitor_form.vue';
import { createStore } from '~/self_monitor/store';
@@ -42,7 +42,7 @@ describe('self monitor component', () => {
it('renders as an expand button by default', () => {
wrapper = shallowMount(SelfMonitor, { store });
- const button = wrapper.find(GlDeprecatedButton);
+ const button = wrapper.find(GlButton);
expect(button.text()).toBe('Expand');
});
diff --git a/spec/frontend/sentry/sentry_config_spec.js b/spec/frontend/sentry/sentry_config_spec.js
index bcc7f29b98d..ed30e4774d9 100644
--- a/spec/frontend/sentry/sentry_config_spec.js
+++ b/spec/frontend/sentry/sentry_config_spec.js
@@ -1,4 +1,4 @@
-import * as Sentry from '@sentry/browser';
+import * as Sentry from '~/sentry/wrapper';
import SentryConfig from '~/sentry/sentry_config';
describe('SentryConfig', () => {
diff --git a/spec/frontend/serverless/components/__snapshots__/empty_state_spec.js.snap b/spec/frontend/serverless/components/__snapshots__/empty_state_spec.js.snap
index 22689080063..6b3d65ff037 100644
--- a/spec/frontend/serverless/components/__snapshots__/empty_state_spec.js.snap
+++ b/spec/frontend/serverless/components/__snapshots__/empty_state_spec.js.snap
@@ -11,7 +11,7 @@ exports[`EmptyStateComponent should render content 1`] = `
<p>In order to start using functions as a service, you must first install Knative on your Kubernetes cluster. <gl-link-stub href=\\"/help\\">More information</gl-link-stub>
</p>
<div>
- <gl-button-stub category=\\"primary\\" variant=\\"success\\" size=\\"medium\\" icon=\\"\\" href=\\"/clusters\\">Install Knative</gl-button-stub>
+ <gl-button-stub category=\\"primary\\" variant=\\"success\\" size=\\"medium\\" icon=\\"\\" buttontextclasses=\\"\\" href=\\"/clusters\\">Install Knative</gl-button-stub>
<!---->
</div>
</div>
diff --git a/spec/frontend/serverless/components/missing_prometheus_spec.js b/spec/frontend/serverless/components/missing_prometheus_spec.js
index 9ca4a45dd5f..0bd2e96a068 100644
--- a/spec/frontend/serverless/components/missing_prometheus_spec.js
+++ b/spec/frontend/serverless/components/missing_prometheus_spec.js
@@ -1,4 +1,4 @@
-import { GlDeprecatedButton } from '@gitlab/ui';
+import { GlButton } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import { createStore } from '~/serverless/store';
import missingPrometheusComponent from '~/serverless/components/missing_prometheus.vue';
@@ -24,7 +24,7 @@ describe('missingPrometheusComponent', () => {
'Function invocation metrics require Prometheus to be installed first.',
);
- expect(wrapper.find(GlDeprecatedButton).attributes('variant')).toBe('success');
+ expect(wrapper.find(GlButton).attributes('variant')).toBe('success');
});
it('should render no prometheus data message', () => {
diff --git a/spec/frontend/serverless/components/url_spec.js b/spec/frontend/serverless/components/url_spec.js
index 36dc9e73c74..92e4938c2cd 100644
--- a/spec/frontend/serverless/components/url_spec.js
+++ b/spec/frontend/serverless/components/url_spec.js
@@ -19,7 +19,7 @@ describe('urlComponent', () => {
expect(vm.$el.classList.contains('clipboard-group')).toBe(true);
expect(wrapper.find(ClipboardButton).attributes('text')).toEqual(uri);
- expect(vm.$el.querySelector('.url-text-field').innerHTML).toEqual(uri);
+ expect(vm.$el.querySelector('[data-testid="url-text-field"]').innerHTML).toContain(uri);
vm.$destroy();
});
diff --git a/spec/frontend/sidebar/assignee_title_spec.js b/spec/frontend/sidebar/assignee_title_spec.js
index 92fabaa664e..b5d1e5216f8 100644
--- a/spec/frontend/sidebar/assignee_title_spec.js
+++ b/spec/frontend/sidebar/assignee_title_spec.js
@@ -11,6 +11,7 @@ describe('AssigneeTitle component', () => {
propsData: {
numberOfAssignees: 0,
editable: false,
+ changing: false,
...props,
},
});
@@ -62,6 +63,22 @@ describe('AssigneeTitle component', () => {
});
});
+ describe('when changing is false', () => {
+ it('renders "Edit"', () => {
+ wrapper = createComponent({ editable: true });
+
+ expect(wrapper.find('[data-test-id="edit-link"]').text()).toEqual('Edit');
+ });
+ });
+
+ describe('when changing is true', () => {
+ it('renders "Edit"', () => {
+ wrapper = createComponent({ editable: true, changing: true });
+
+ expect(wrapper.find('[data-test-id="edit-link"]').text()).toEqual('Apply');
+ });
+ });
+
it('does not render spinner by default', () => {
wrapper = createComponent({
numberOfAssignees: 0,
diff --git a/spec/frontend/sidebar/components/time_tracking/time_tracker_spec.js b/spec/frontend/sidebar/components/time_tracking/time_tracker_spec.js
index 1f028f74423..5307be0bf58 100644
--- a/spec/frontend/sidebar/components/time_tracking/time_tracker_spec.js
+++ b/spec/frontend/sidebar/components/time_tracking/time_tracker_spec.js
@@ -155,8 +155,7 @@ describe('Issuable Time Tracker', () => {
it('should show the correct tooltip text', done => {
Vue.nextTick(() => {
expect(vm.showComparisonState).toBe(true);
- const $title = vm.$el.querySelector('.time-tracking-content .compare-meter').dataset
- .originalTitle;
+ const $title = vm.$el.querySelector('.time-tracking-content .compare-meter').title;
expect($title).toBe('Time remaining: 26h 23m');
done();
diff --git a/spec/frontend/sidebar/confidential/edit_form_buttons_spec.js b/spec/frontend/sidebar/confidential/edit_form_buttons_spec.js
index 2f11c6a07c2..8c868205295 100644
--- a/spec/frontend/sidebar/confidential/edit_form_buttons_spec.js
+++ b/spec/frontend/sidebar/confidential/edit_form_buttons_spec.js
@@ -1,5 +1,4 @@
import { shallowMount } from '@vue/test-utils';
-import { GlLoadingIcon } from '@gitlab/ui';
import waitForPromises from 'helpers/wait_for_promises';
import EditFormButtons from '~/sidebar/components/confidential/edit_form_buttons.vue';
import eventHub from '~/sidebar/event_hub';
@@ -56,11 +55,11 @@ describe('Edit Form Buttons', () => {
});
it('disables the toggle button', () => {
- expect(findConfidentialToggle().attributes('disabled')).toBe('disabled');
+ expect(findConfidentialToggle().props('disabled')).toBe(true);
});
- it('finds the GlLoadingIcon', () => {
- expect(wrapper.find(GlLoadingIcon).exists()).toBe(true);
+ it('sets loading on the toggle button', () => {
+ expect(findConfidentialToggle().props('loading')).toBe(true);
});
});
@@ -99,7 +98,7 @@ describe('Edit Form Buttons', () => {
describe('when succeeds', () => {
beforeEach(() => {
createComponent({ data: { isLoading: false }, props: { confidential: true } });
- findConfidentialToggle().trigger('click');
+ findConfidentialToggle().vm.$emit('click', new Event('click'));
});
it('dispatches the correct action', () => {
@@ -109,9 +108,9 @@ describe('Edit Form Buttons', () => {
});
});
- it('resets loading', () => {
+ it('resets loading on the toggle button', () => {
return waitForPromises().then(() => {
- expect(wrapper.find(GlLoadingIcon).exists()).toBe(false);
+ expect(findConfidentialToggle().props('loading')).toBe(false);
});
});
@@ -135,7 +134,7 @@ describe('Edit Form Buttons', () => {
props: { confidential: true },
resolved: false,
});
- findConfidentialToggle().trigger('click');
+ findConfidentialToggle().vm.$emit('click', new Event('click'));
});
it('calls flash with the correct message', () => {
diff --git a/spec/frontend/sidebar/lock/edit_form_buttons_spec.js b/spec/frontend/sidebar/lock/edit_form_buttons_spec.js
index de1da3456f8..913646c8f8d 100644
--- a/spec/frontend/sidebar/lock/edit_form_buttons_spec.js
+++ b/spec/frontend/sidebar/lock/edit_form_buttons_spec.js
@@ -1,5 +1,4 @@
-import { shallowMount } from '@vue/test-utils';
-import { GlLoadingIcon } from '@gitlab/ui';
+import { mount } from '@vue/test-utils';
import EditFormButtons from '~/sidebar/components/lock/edit_form_buttons.vue';
import eventHub from '~/sidebar/event_hub';
import { deprecatedCreateFlash as flash } from '~/flash';
@@ -22,7 +21,6 @@ describe('EditFormButtons', () => {
};
const findLockToggle = () => wrapper.find('[data-testid="lock-toggle"]');
- const findGlLoadingIcon = () => wrapper.find(GlLoadingIcon);
const createComponent = ({ props = {}, data = {}, resolved = true }) => {
store = issuableType === ISSUABLE_TYPE_ISSUE ? createStore() : createMrStore();
@@ -33,7 +31,7 @@ describe('EditFormButtons', () => {
jest.spyOn(store, 'dispatch').mockRejectedValue();
}
- wrapper = shallowMount(EditFormButtons, {
+ wrapper = mount(EditFormButtons, {
store,
provide: {
fullPath: '',
@@ -78,8 +76,8 @@ describe('EditFormButtons', () => {
expect(findLockToggle().attributes('disabled')).toBe('disabled');
});
- it('displays the GlLoadingIcon', () => {
- expect(findGlLoadingIcon().exists()).toBe(true);
+ it('sets loading on the toggle button', () => {
+ expect(findLockToggle().props('loading')).toBe(true);
});
});
@@ -121,7 +119,7 @@ describe('EditFormButtons', () => {
it('resets loading', async () => {
await wrapper.vm.$nextTick().then(() => {
- expect(findGlLoadingIcon().exists()).toBe(false);
+ expect(findLockToggle().props('loading')).toBe(false);
});
});
@@ -156,7 +154,7 @@ describe('EditFormButtons', () => {
it('resets loading', async () => {
await wrapper.vm.$nextTick().then(() => {
- expect(findGlLoadingIcon().exists()).toBe(false);
+ expect(findLockToggle().props('loading')).toBe(false);
});
});
diff --git a/spec/frontend/sidebar/lock/issuable_lock_form_spec.js b/spec/frontend/sidebar/lock/issuable_lock_form_spec.js
index ab1423a9bbb..e8091dcb51d 100644
--- a/spec/frontend/sidebar/lock/issuable_lock_form_spec.js
+++ b/spec/frontend/sidebar/lock/issuable_lock_form_spec.js
@@ -1,5 +1,6 @@
import { shallowMount } from '@vue/test-utils';
import { mockTracking, triggerEvent } from 'helpers/tracking_helper';
+import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
import IssuableLockForm from '~/sidebar/components/lock/issuable_lock_form.vue';
import EditForm from '~/sidebar/components/lock/edit_form.vue';
import createStore from '~/notes/stores';
@@ -19,6 +20,8 @@ describe('IssuableLockForm', () => {
const findLockStatus = () => wrapper.find('[data-testid="lock-status"]');
const findEditLink = () => wrapper.find('[data-testid="edit-link"]');
const findEditForm = () => wrapper.find(EditForm);
+ const findSidebarLockStatusTooltip = () =>
+ getBinding(findSidebarCollapseIcon().element, 'gl-tooltip');
const initStore = isLocked => {
if (issuableType === ISSUABLE_TYPE_ISSUE) {
@@ -37,6 +40,9 @@ describe('IssuableLockForm', () => {
isEditable: true,
...props,
},
+ directives: {
+ GlTooltip: createMockDirective(),
+ },
});
};
@@ -125,6 +131,13 @@ describe('IssuableLockForm', () => {
expect(findEditForm().exists()).toBe(true);
});
});
+
+ it('renders a tooltip with the lock status text', () => {
+ const tooltip = findSidebarLockStatusTooltip();
+
+ expect(tooltip).toBeDefined();
+ expect(tooltip.value.title).toBe(isLocked ? 'Locked' : 'Unlocked');
+ });
});
});
});
diff --git a/spec/frontend/sidebar/reviewer_title_spec.js b/spec/frontend/sidebar/reviewer_title_spec.js
new file mode 100644
index 00000000000..eae266688d5
--- /dev/null
+++ b/spec/frontend/sidebar/reviewer_title_spec.js
@@ -0,0 +1,116 @@
+import { shallowMount } from '@vue/test-utils';
+import { GlLoadingIcon } from '@gitlab/ui';
+import { mockTracking, triggerEvent } from 'helpers/tracking_helper';
+import Component from '~/sidebar/components/reviewers/reviewer_title.vue';
+
+describe('ReviewerTitle component', () => {
+ let wrapper;
+
+ const createComponent = props => {
+ return shallowMount(Component, {
+ propsData: {
+ numberOfReviewers: 0,
+ editable: false,
+ ...props,
+ },
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ wrapper = null;
+ });
+
+ describe('reviewer title', () => {
+ it('renders reviewer', () => {
+ wrapper = createComponent({
+ numberOfReviewers: 1,
+ editable: false,
+ });
+
+ expect(wrapper.vm.$el.innerText.trim()).toEqual('Reviewer');
+ });
+
+ it('renders 2 reviewers', () => {
+ wrapper = createComponent({
+ numberOfReviewers: 2,
+ editable: false,
+ });
+
+ expect(wrapper.vm.$el.innerText.trim()).toEqual('2 Reviewers');
+ });
+ });
+
+ describe('gutter toggle', () => {
+ it('does not show toggle by default', () => {
+ wrapper = createComponent({
+ numberOfReviewers: 2,
+ editable: false,
+ });
+
+ expect(wrapper.vm.$el.querySelector('.gutter-toggle')).toBeNull();
+ });
+
+ it('shows toggle when showToggle is true', () => {
+ wrapper = createComponent({
+ numberOfReviewers: 2,
+ editable: false,
+ showToggle: true,
+ });
+
+ expect(wrapper.vm.$el.querySelector('.gutter-toggle')).toEqual(expect.any(Object));
+ });
+ });
+
+ it('does not render spinner by default', () => {
+ wrapper = createComponent({
+ numberOfReviewers: 0,
+ editable: false,
+ });
+
+ expect(wrapper.find(GlLoadingIcon).exists()).toBeFalsy();
+ });
+
+ it('renders spinner when loading', () => {
+ wrapper = createComponent({
+ loading: true,
+ numberOfReviewers: 0,
+ editable: false,
+ });
+
+ expect(wrapper.find(GlLoadingIcon).exists()).toBeTruthy();
+ });
+
+ it('does not render edit link when not editable', () => {
+ wrapper = createComponent({
+ numberOfReviewers: 0,
+ editable: false,
+ });
+
+ expect(wrapper.vm.$el.querySelector('.edit-link')).toBeNull();
+ });
+
+ it('renders edit link when editable', () => {
+ wrapper = createComponent({
+ numberOfReviewers: 0,
+ editable: true,
+ });
+
+ expect(wrapper.vm.$el.querySelector('.edit-link')).not.toBeNull();
+ });
+
+ it('tracks the event when edit is clicked', () => {
+ wrapper = createComponent({
+ numberOfReviewers: 0,
+ editable: true,
+ });
+
+ const spy = mockTracking('_category_', wrapper.element, jest.spyOn);
+ triggerEvent('.js-sidebar-dropdown-toggle');
+
+ expect(spy).toHaveBeenCalledWith('_category_', 'click_edit_button', {
+ label: 'right_sidebar',
+ property: 'reviewer',
+ });
+ });
+});
diff --git a/spec/frontend/sidebar/reviewers_spec.js b/spec/frontend/sidebar/reviewers_spec.js
new file mode 100644
index 00000000000..effcac266f0
--- /dev/null
+++ b/spec/frontend/sidebar/reviewers_spec.js
@@ -0,0 +1,169 @@
+import { mount } from '@vue/test-utils';
+import { trimText } from 'helpers/text_helper';
+import { GlIcon } from '@gitlab/ui';
+import Reviewer from '~/sidebar/components/reviewers/reviewers.vue';
+import UsersMock from './mock_data';
+import UsersMockHelper from '../helpers/user_mock_data_helper';
+
+describe('Reviewer component', () => {
+ const getDefaultProps = () => ({
+ rootPath: 'http://localhost:3000',
+ users: [],
+ editable: false,
+ });
+ let wrapper;
+
+ const createWrapper = (propsData = getDefaultProps()) => {
+ wrapper = mount(Reviewer, {
+ propsData,
+ });
+ };
+
+ const findCollapsedChildren = () => wrapper.findAll('.sidebar-collapsed-icon > *');
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe('No reviewers/users', () => {
+ it('displays no reviewer icon when collapsed', () => {
+ createWrapper();
+ const collapsedChildren = findCollapsedChildren();
+ const userIcon = collapsedChildren.at(0).find(GlIcon);
+
+ expect(collapsedChildren.length).toBe(1);
+ expect(collapsedChildren.at(0).attributes('aria-label')).toBe('None');
+ expect(userIcon.exists()).toBe(true);
+ expect(userIcon.props('name')).toBe('user');
+ });
+ });
+
+ describe('One reviewer/user', () => {
+ it('displays one reviewer icon when collapsed', () => {
+ createWrapper({
+ ...getDefaultProps(),
+ users: [UsersMock.user],
+ });
+
+ const collapsedChildren = findCollapsedChildren();
+ const reviewer = collapsedChildren.at(0);
+
+ expect(collapsedChildren.length).toBe(1);
+ expect(reviewer.find('.avatar').attributes('src')).toBe(UsersMock.user.avatar);
+ expect(reviewer.find('.avatar').attributes('alt')).toBe(`${UsersMock.user.name}'s avatar`);
+
+ expect(trimText(reviewer.find('.author').text())).toBe(UsersMock.user.name);
+ });
+ });
+
+ describe('Two or more reviewers/users', () => {
+ it('displays two reviewer icons when collapsed', () => {
+ const users = UsersMockHelper.createNumberRandomUsers(2);
+ createWrapper({
+ ...getDefaultProps(),
+ users,
+ });
+
+ const collapsedChildren = findCollapsedChildren();
+
+ expect(collapsedChildren.length).toBe(2);
+
+ const first = collapsedChildren.at(0);
+
+ expect(first.find('.avatar').attributes('src')).toBe(users[0].avatar_url);
+ expect(first.find('.avatar').attributes('alt')).toBe(`${users[0].name}'s avatar`);
+
+ expect(trimText(first.find('.author').text())).toBe(users[0].name);
+
+ const second = collapsedChildren.at(1);
+
+ expect(second.find('.avatar').attributes('src')).toBe(users[1].avatar_url);
+ expect(second.find('.avatar').attributes('alt')).toBe(`${users[1].name}'s avatar`);
+
+ expect(trimText(second.find('.author').text())).toBe(users[1].name);
+ });
+
+ it('displays one reviewer icon and counter when collapsed', () => {
+ const users = UsersMockHelper.createNumberRandomUsers(3);
+ createWrapper({
+ ...getDefaultProps(),
+ users,
+ });
+
+ const collapsedChildren = findCollapsedChildren();
+
+ expect(collapsedChildren.length).toBe(2);
+
+ const first = collapsedChildren.at(0);
+
+ expect(first.find('.avatar').attributes('src')).toBe(users[0].avatar_url);
+ expect(first.find('.avatar').attributes('alt')).toBe(`${users[0].name}'s avatar`);
+
+ expect(trimText(first.find('.author').text())).toBe(users[0].name);
+
+ const second = collapsedChildren.at(1);
+
+ expect(trimText(second.find('.avatar-counter').text())).toBe('+2');
+ });
+
+ it('Shows two reviewers', () => {
+ const users = UsersMockHelper.createNumberRandomUsers(2);
+ createWrapper({
+ ...getDefaultProps(),
+ users,
+ editable: true,
+ });
+
+ expect(wrapper.findAll('.user-item').length).toBe(users.length);
+ expect(wrapper.find('.user-list-more').exists()).toBe(false);
+ });
+
+ it('shows sorted reviewer where "can merge" users are sorted first', () => {
+ const users = UsersMockHelper.createNumberRandomUsers(3);
+ users[0].can_merge = false;
+ users[1].can_merge = false;
+ users[2].can_merge = true;
+
+ createWrapper({
+ ...getDefaultProps(),
+ users,
+ editable: true,
+ });
+
+ expect(wrapper.vm.sortedReviewers[0].can_merge).toBe(true);
+ });
+
+ it('passes the sorted reviewers to the uncollapsed-reviewer-list', () => {
+ const users = UsersMockHelper.createNumberRandomUsers(3);
+ users[0].can_merge = false;
+ users[1].can_merge = false;
+ users[2].can_merge = true;
+
+ createWrapper({
+ ...getDefaultProps(),
+ users,
+ });
+
+ const userItems = wrapper.findAll('.user-list .user-item a');
+
+ expect(userItems.length).toBe(3);
+ expect(userItems.at(0).attributes('title')).toBe(users[2].name);
+ });
+
+ it('passes the sorted reviewers to the collapsed-reviewer-list', () => {
+ const users = UsersMockHelper.createNumberRandomUsers(3);
+ users[0].can_merge = false;
+ users[1].can_merge = false;
+ users[2].can_merge = true;
+
+ createWrapper({
+ ...getDefaultProps(),
+ users,
+ });
+
+ const collapsedButton = wrapper.find('.sidebar-collapsed-user button');
+
+ expect(trimText(collapsedButton.text())).toBe(users[2].name);
+ });
+ });
+});
diff --git a/spec/frontend/sidebar/sidebar_assignees_spec.js b/spec/frontend/sidebar/sidebar_assignees_spec.js
index 88e2d2c9514..dc4560d2ae8 100644
--- a/spec/frontend/sidebar/sidebar_assignees_spec.js
+++ b/spec/frontend/sidebar/sidebar_assignees_spec.js
@@ -20,6 +20,7 @@ describe('sidebar assignees', () => {
mediator,
field: '',
projectPath: 'projectPath',
+ changing: false,
...props,
},
provide: {
diff --git a/spec/frontend/sidebar/sidebar_labels_spec.js b/spec/frontend/sidebar/sidebar_labels_spec.js
index 29333a344e1..7a687ffa761 100644
--- a/spec/frontend/sidebar/sidebar_labels_spec.js
+++ b/spec/frontend/sidebar/sidebar_labels_spec.js
@@ -1,6 +1,5 @@
-import { createLocalVue, shallowMount } from '@vue/test-utils';
+import { shallowMount } from '@vue/test-utils';
import AxiosMockAdapter from 'axios-mock-adapter';
-import Vuex from 'vuex';
import {
mockLabels,
mockRegularLabel,
@@ -9,17 +8,11 @@ import axios from '~/lib/utils/axios_utils';
import SidebarLabels from '~/sidebar/components/labels/sidebar_labels.vue';
import { DropdownVariant } from '~/vue_shared/components/sidebar/labels_select_vue/constants';
import LabelsSelect from '~/vue_shared/components/sidebar/labels_select_vue/labels_select_root.vue';
-import labelsSelectModule from '~/vue_shared/components/sidebar/labels_select_vue/store';
-
-const localVue = createLocalVue();
-localVue.use(Vuex);
describe('sidebar labels', () => {
let axiosMock;
let wrapper;
- const store = new Vuex.Store(labelsSelectModule());
-
const defaultProps = {
allowLabelCreate: true,
allowLabelEdit: true,
@@ -39,11 +32,9 @@ describe('sidebar labels', () => {
const mountComponent = () => {
wrapper = shallowMount(SidebarLabels, {
- localVue,
provide: {
...defaultProps,
},
- store,
});
};
@@ -81,7 +72,7 @@ describe('sidebar labels', () => {
});
});
- describe('when labels are changed', () => {
+ describe('when labels are updated', () => {
beforeEach(() => {
mountComponent();
});
@@ -114,7 +105,27 @@ describe('sidebar labels', () => {
const expected = {
[defaultProps.issuableType]: {
- label_ids: [27, 28, 40],
+ label_ids: [27, 28, 29, 40],
+ },
+ };
+
+ expect(axiosMock.history.put[0].data).toEqual(JSON.stringify(expected));
+ });
+ });
+
+ describe('when label `x` is clicked', () => {
+ beforeEach(() => {
+ mountComponent();
+ });
+
+ it('makes an API call to update labels', async () => {
+ findLabelsSelect().vm.$emit('onLabelRemove', 27);
+
+ await axios.waitForAll();
+
+ const expected = {
+ [defaultProps.issuableType]: {
+ label_ids: [26, 28, 29],
},
};
diff --git a/spec/frontend/sidebar/sidebar_store_spec.js b/spec/frontend/sidebar/sidebar_store_spec.js
index 6d063a7cfcf..7c18222f300 100644
--- a/spec/frontend/sidebar/sidebar_store_spec.js
+++ b/spec/frontend/sidebar/sidebar_store_spec.js
@@ -57,16 +57,40 @@ describe('Sidebar store', () => {
expect(testContext.store.isFetching.assignees).toBe(true);
});
- it('adds a new assignee', () => {
- testContext.store.addAssignee(ASSIGNEE);
+ it('resets changing when resetChanging is called', () => {
+ testContext.store.changing = true;
+
+ testContext.store.resetChanging();
- expect(testContext.store.assignees.length).toEqual(1);
+ expect(testContext.store.changing).toBe(false);
});
- it('removes an assignee', () => {
- testContext.store.removeAssignee(ASSIGNEE);
+ describe('when it adds a new assignee', () => {
+ beforeEach(() => {
+ testContext.store.addAssignee(ASSIGNEE);
+ });
- expect(testContext.store.assignees.length).toEqual(0);
+ it('adds a new assignee', () => {
+ expect(testContext.store.assignees).toHaveLength(1);
+ });
+
+ it('sets changing to true', () => {
+ expect(testContext.store.changing).toBe(true);
+ });
+ });
+
+ describe('when it removes an assignee', () => {
+ beforeEach(() => {
+ testContext.store.removeAssignee(ASSIGNEE);
+ });
+
+ it('removes an assignee', () => {
+ expect(testContext.store.assignees).toHaveLength(0);
+ });
+
+ it('sets changing to true', () => {
+ expect(testContext.store.changing).toBe(true);
+ });
});
it('finds an existent assignee', () => {
@@ -86,6 +110,7 @@ describe('Sidebar store', () => {
testContext.store.removeAllAssignees();
expect(testContext.store.assignees.length).toEqual(0);
+ expect(testContext.store.changing).toBe(true);
});
it('sets participants data', () => {
diff --git a/spec/frontend/snippet/snippet_bundle_spec.js b/spec/frontend/snippet/snippet_bundle_spec.js
deleted file mode 100644
index 208d2fea804..00000000000
--- a/spec/frontend/snippet/snippet_bundle_spec.js
+++ /dev/null
@@ -1,87 +0,0 @@
-import { setHTMLFixture } from 'helpers/fixtures';
-import Editor from '~/editor/editor_lite';
-import initEditor from '~/snippet/snippet_bundle';
-
-jest.mock('~/editor/editor_lite', () => jest.fn());
-
-describe('Snippet editor', () => {
- let editorEl;
- let contentEl;
- let fileNameEl;
- let form;
-
- const mockName = 'foo.bar';
- const mockContent = 'Foo Bar';
- const updatedMockContent = 'New Foo Bar';
-
- const mockEditor = {
- updateModelLanguage: jest.fn(),
- getValue: jest.fn().mockReturnValueOnce(updatedMockContent),
- };
- const createInstance = jest.fn().mockImplementation(() => ({ ...mockEditor }));
- Editor.mockImplementation(() => ({
- createInstance,
- }));
-
- function setUpFixture(name, content) {
- setHTMLFixture(`
- <div class="snippet-form-holder">
- <form>
- <input class="js-snippet-file-name" type="text" value="${name}">
- <input class="snippet-file-content" type="hidden" value="${content}">
- <pre id="editor"></pre>
- </form>
- </div>
- `);
- }
-
- function bootstrap(name = '', content = '') {
- setUpFixture(name, content);
- editorEl = document.getElementById('editor');
- contentEl = document.querySelector('.snippet-file-content');
- fileNameEl = document.querySelector('.js-snippet-file-name');
- form = document.querySelector('.snippet-form-holder form');
-
- initEditor();
- }
-
- function createEvent(name) {
- return new Event(name, {
- view: window,
- bubbles: true,
- cancelable: true,
- });
- }
-
- beforeEach(() => {
- bootstrap(mockName, mockContent);
- });
-
- it('correctly initializes Editor', () => {
- expect(createInstance).toHaveBeenCalledWith({
- el: editorEl,
- blobPath: mockName,
- blobContent: mockContent,
- });
- });
-
- it('listens to file name changes and updates syntax highlighting of code', () => {
- expect(mockEditor.updateModelLanguage).not.toHaveBeenCalled();
-
- const event = createEvent('change');
-
- fileNameEl.value = updatedMockContent;
- fileNameEl.dispatchEvent(event);
-
- expect(mockEditor.updateModelLanguage).toHaveBeenCalledWith(updatedMockContent);
- });
-
- it('listens to form submit event and populates the hidden field with most recent version of the content', () => {
- expect(contentEl.value).toBe(mockContent);
-
- const event = createEvent('submit');
-
- form.dispatchEvent(event);
- expect(contentEl.value).toBe(updatedMockContent);
- });
-});
diff --git a/spec/frontend/snippet/snippet_edit_spec.js b/spec/frontend/snippet/snippet_edit_spec.js
deleted file mode 100644
index 7c12c0cac03..00000000000
--- a/spec/frontend/snippet/snippet_edit_spec.js
+++ /dev/null
@@ -1,44 +0,0 @@
-import '~/snippet/snippet_edit';
-import { triggerDOMEvent } from 'jest/helpers/dom_events_helper';
-import { SnippetEditInit } from '~/snippets';
-import initSnippet from '~/snippet/snippet_bundle';
-
-jest.mock('~/snippet/snippet_bundle');
-jest.mock('~/snippets');
-
-describe('Snippet edit form initialization', () => {
- const setFF = flag => {
- gon.features = { snippetsEditVue: flag };
- };
- let features;
-
- beforeEach(() => {
- features = gon.features;
- setFixtures('<div class="snippet-form"></div>');
- });
-
- afterEach(() => {
- gon.features = features;
- });
-
- it.each`
- name | flag | isVue
- ${'Regular'} | ${false} | ${false}
- ${'Vue'} | ${true} | ${true}
- `('correctly initializes $name Snippet Edit form', ({ flag, isVue }) => {
- initSnippet.mockClear();
- SnippetEditInit.mockClear();
-
- setFF(flag);
-
- triggerDOMEvent('DOMContentLoaded');
-
- if (isVue) {
- expect(initSnippet).not.toHaveBeenCalled();
- expect(SnippetEditInit).toHaveBeenCalled();
- } else {
- expect(initSnippet).toHaveBeenCalled();
- expect(SnippetEditInit).not.toHaveBeenCalled();
- }
- });
-});
diff --git a/spec/frontend/snippets/components/__snapshots__/snippet_blob_edit_spec.js.snap b/spec/frontend/snippets/components/__snapshots__/snippet_blob_edit_spec.js.snap
index 1cf1ee74ddf..b0c253bca65 100644
--- a/spec/frontend/snippets/components/__snapshots__/snippet_blob_edit_spec.js.snap
+++ b/spec/frontend/snippets/components/__snapshots__/snippet_blob_edit_spec.js.snap
@@ -3,15 +3,18 @@
exports[`Snippet Blob Edit component with loaded blob matches snapshot 1`] = `
<div
class="file-holder snippet"
+ data-qa-selector="file_holder_container"
>
<blob-header-edit-stub
candelete="true"
data-qa-selector="file_name_field"
id="blob_local_7_file_path"
+ showdelete="true"
value="foo/bar/test.md"
/>
- <blob-content-edit-stub
+ <editor-lite-stub
+ editoroptions="[object Object]"
fileglobalid="blob_local_7"
filename="foo/bar/test.md"
value="Lorem ipsum dolar sit amet,
diff --git a/spec/frontend/snippets/components/__snapshots__/snippet_description_edit_spec.js.snap b/spec/frontend/snippets/components/__snapshots__/snippet_description_edit_spec.js.snap
index 3b101e9e815..93684ed48ee 100644
--- a/spec/frontend/snippets/components/__snapshots__/snippet_description_edit_spec.js.snap
+++ b/spec/frontend/snippets/components/__snapshots__/snippet_description_edit_spec.js.snap
@@ -24,7 +24,7 @@ exports[`Snippet Description Edit component rendering matches the snapshot 1`] =
</div>
<div
- class="js-vue-markdown-field md-area position-relative js-expanded gfm-form"
+ class="js-vue-markdown-field md-area position-relative gfm-form js-expanded"
>
<markdown-header-stub
linecontent=""
diff --git a/spec/frontend/snippets/components/edit_spec.js b/spec/frontend/snippets/components/edit_spec.js
index b6abb9f389a..c1fad8cebe6 100644
--- a/spec/frontend/snippets/components/edit_spec.js
+++ b/spec/frontend/snippets/components/edit_spec.js
@@ -148,17 +148,17 @@ describe('Snippet Edit app', () => {
// Ideally we wouldn't call this method directly, but we don't have a way to trigger
// apollo responses yet.
- const loadSnippet = (...edges) => {
- if (edges.length) {
+ const loadSnippet = (...nodes) => {
+ if (nodes.length) {
wrapper.setData({
- snippet: edges[0],
+ snippet: nodes[0],
});
}
wrapper.vm.onSnippetFetch({
data: {
snippets: {
- edges,
+ nodes,
},
},
});
diff --git a/spec/frontend/snippets/components/snippet_blob_actions_edit_spec.js b/spec/frontend/snippets/components/snippet_blob_actions_edit_spec.js
index 8b2051008d7..055168a1711 100644
--- a/spec/frontend/snippets/components/snippet_blob_actions_edit_spec.js
+++ b/spec/frontend/snippets/components/snippet_blob_actions_edit_spec.js
@@ -19,17 +19,12 @@ const TEST_BLOBS_UNLOADED = TEST_BLOBS.map(blob => ({ ...blob, content: '', isLo
describe('snippets/components/snippet_blob_actions_edit', () => {
let wrapper;
- const createComponent = (props = {}, snippetMultipleFiles = true) => {
+ const createComponent = (props = {}) => {
wrapper = shallowMount(SnippetBlobActionsEdit, {
propsData: {
initBlobs: TEST_BLOBS,
...props,
},
- provide: {
- glFeatures: {
- snippetMultipleFiles,
- },
- },
});
};
@@ -69,28 +64,24 @@ describe('snippets/components/snippet_blob_actions_edit', () => {
wrapper = null;
});
- describe.each`
- featureFlag | label | showDelete | showAdd
- ${true} | ${'Files'} | ${true} | ${true}
- ${false} | ${'File'} | ${false} | ${false}
- `('with feature flag = $featureFlag', ({ featureFlag, label, showDelete, showAdd }) => {
+ describe('multi-file snippets rendering', () => {
beforeEach(() => {
- createComponent({}, featureFlag);
+ createComponent();
});
it('renders label', () => {
- expect(findLabel().text()).toBe(label);
+ expect(findLabel().text()).toBe('Files');
});
- it(`renders delete button (show=${showDelete})`, () => {
+ it(`renders delete button (show=true)`, () => {
expect(findFirstBlobEdit().props()).toMatchObject({
- showDelete,
+ showDelete: true,
canDelete: true,
});
});
- it(`renders add button (show=${showAdd})`, () => {
- expect(findAddButton().exists()).toBe(showAdd);
+ it(`renders add button (show=true)`, () => {
+ expect(findAddButton().exists()).toBe(true);
});
});
diff --git a/spec/frontend/snippets/components/snippet_blob_edit_spec.js b/spec/frontend/snippets/components/snippet_blob_edit_spec.js
index fc4da46d722..9d0311fd682 100644
--- a/spec/frontend/snippets/components/snippet_blob_edit_spec.js
+++ b/spec/frontend/snippets/components/snippet_blob_edit_spec.js
@@ -5,7 +5,7 @@ import waitForPromises from 'helpers/wait_for_promises';
import { TEST_HOST } from 'helpers/test_constants';
import SnippetBlobEdit from '~/snippets/components/snippet_blob_edit.vue';
import BlobHeaderEdit from '~/blob/components/blob_edit_header.vue';
-import BlobContentEdit from '~/blob/components/blob_edit_content.vue';
+import EditorLite from '~/vue_shared/components/editor_lite.vue';
import axios from '~/lib/utils/axios_utils';
import { joinPaths } from '~/lib/utils/url_utility';
import { deprecatedCreateFlash as createFlash } from '~/flash';
@@ -48,7 +48,7 @@ describe('Snippet Blob Edit component', () => {
const findLoadingIcon = () => wrapper.find(GlLoadingIcon);
const findHeader = () => wrapper.find(BlobHeaderEdit);
- const findContent = () => wrapper.find(BlobContentEdit);
+ const findContent = () => wrapper.find(EditorLite);
const getLastUpdatedArgs = () => {
const event = wrapper.emitted()['blob-updated'];
@@ -156,7 +156,7 @@ describe('Snippet Blob Edit component', () => {
});
it('shows blob header', () => {
- const { canDelete = true, showDelete = false } = props;
+ const { canDelete = true, showDelete = true } = props;
expect(findHeader().props()).toMatchObject({
canDelete,
@@ -172,11 +172,13 @@ describe('Snippet Blob Edit component', () => {
expect(findContent().exists()).toBe(showContent);
if (showContent) {
- expect(findContent().props()).toEqual({
- value: TEST_BLOB_LOADED.content,
- fileGlobalId: TEST_BLOB_LOADED.id,
- fileName: TEST_BLOB_LOADED.path,
- });
+ expect(findContent().props()).toEqual(
+ expect.objectContaining({
+ value: TEST_BLOB_LOADED.content,
+ fileGlobalId: TEST_BLOB_LOADED.id,
+ fileName: TEST_BLOB_LOADED.path,
+ }),
+ );
}
});
});
diff --git a/spec/frontend/snippets/components/snippet_blob_view_spec.js b/spec/frontend/snippets/components/snippet_blob_view_spec.js
index 9c4b2734a3f..1ccecd7b5ba 100644
--- a/spec/frontend/snippets/components/snippet_blob_view_spec.js
+++ b/spec/frontend/snippets/components/snippet_blob_view_spec.js
@@ -140,10 +140,10 @@ describe('Blob Embeddable', () => {
async ({ snippetBlobs, currentBlob, expectedContent }) => {
const apolloData = {
snippets: {
- edges: [
+ nodes: [
{
- node: {
- blobs: snippetBlobs,
+ blobs: {
+ nodes: snippetBlobs,
},
},
],
diff --git a/spec/frontend/snippets_spec.js b/spec/frontend/snippets_spec.js
deleted file mode 100644
index 6c39ff0da27..00000000000
--- a/spec/frontend/snippets_spec.js
+++ /dev/null
@@ -1,70 +0,0 @@
-import snippetEmbed from '~/snippet/snippet_embed';
-import { loadHTMLFixture } from './helpers/fixtures';
-
-describe('Snippets', () => {
- let embedBtn;
- let snippetUrlArea;
- let shareBtn;
- let scriptTag;
-
- const snippetUrl = 'http://test.host/-/snippets/1';
-
- beforeEach(() => {
- loadHTMLFixture('snippets/show.html');
-
- embedBtn = document.querySelector('.js-embed-btn');
- snippetUrlArea = document.querySelector('.js-snippet-url-area');
- shareBtn = document.querySelector('.js-share-btn');
- });
-
- it('selects the fields content when it is clicked', () => {
- jest.spyOn(snippetUrlArea, 'select');
- snippetEmbed();
-
- expect(snippetUrlArea.select).not.toHaveBeenCalled();
- snippetUrlArea.dispatchEvent(new Event('click'));
- expect(snippetUrlArea.select).toHaveBeenCalled();
- });
-
- describe('when the snippet url does not include params', () => {
- beforeEach(() => {
- snippetEmbed();
-
- scriptTag = `<script src="${snippetUrl}.js"></script>`;
- });
-
- it('shows the script tag as default', () => {
- expect(snippetUrlArea.value).toEqual(scriptTag);
- });
-
- it('sets the proper url depending on the button clicked', () => {
- shareBtn.dispatchEvent(new Event('click'));
- expect(snippetUrlArea.value).toEqual(snippetUrl);
-
- embedBtn.dispatchEvent(new Event('click'));
- expect(snippetUrlArea.value).toEqual(scriptTag);
- });
- });
-
- describe('when the snippet url includes params', () => {
- beforeEach(() => {
- scriptTag = `<script src="${snippetUrl}.js?foo=bar"></script>`;
- snippetUrlArea.value = scriptTag;
- snippetUrlArea.dataset.url = `${snippetUrl}?foo=bar`;
-
- snippetEmbed();
- });
-
- it('shows the script tag as default', () => {
- expect(snippetUrlArea.value).toEqual(scriptTag);
- });
-
- it('sets the proper url depending on the button clicked', () => {
- shareBtn.dispatchEvent(new Event('click'));
- expect(snippetUrlArea.value).toEqual(`${snippetUrl}?foo=bar`);
-
- embedBtn.dispatchEvent(new Event('click'));
- expect(snippetUrlArea.value).toEqual(scriptTag);
- });
- });
-});
diff --git a/spec/frontend/static_site_editor/components/edit_meta_controls_spec.js b/spec/frontend/static_site_editor/components/edit_meta_controls_spec.js
new file mode 100644
index 00000000000..191f91be076
--- /dev/null
+++ b/spec/frontend/static_site_editor/components/edit_meta_controls_spec.js
@@ -0,0 +1,99 @@
+import { shallowMount } from '@vue/test-utils';
+
+import { useLocalStorageSpy } from 'helpers/local_storage_helper';
+import { GlFormInput, GlFormTextarea } from '@gitlab/ui';
+
+import EditMetaControls from '~/static_site_editor/components/edit_meta_controls.vue';
+
+import { mergeRequestMeta } from '../mock_data';
+
+describe('~/static_site_editor/components/edit_meta_controls.vue', () => {
+ useLocalStorageSpy();
+
+ let wrapper;
+ let mockSelect;
+ let mockGlFormInputTitleInstance;
+ const { title, description } = mergeRequestMeta;
+ const newTitle = 'New title';
+ const newDescription = 'New description';
+
+ const buildWrapper = (propsData = {}) => {
+ wrapper = shallowMount(EditMetaControls, {
+ propsData: {
+ title,
+ description,
+ ...propsData,
+ },
+ });
+ };
+
+ const buildMocks = () => {
+ mockSelect = jest.fn();
+ mockGlFormInputTitleInstance = { $el: { select: mockSelect } };
+ wrapper.vm.$refs.title = mockGlFormInputTitleInstance;
+ };
+
+ const findGlFormInputTitle = () => wrapper.find(GlFormInput);
+ const findGlFormTextAreaDescription = () => wrapper.find(GlFormTextarea);
+
+ beforeEach(() => {
+ buildWrapper();
+ buildMocks();
+
+ return wrapper.vm.$nextTick();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ wrapper = null;
+ });
+
+ it('renders the title input', () => {
+ expect(findGlFormInputTitle().exists()).toBe(true);
+ });
+
+ it('renders the description input', () => {
+ expect(findGlFormTextAreaDescription().exists()).toBe(true);
+ });
+
+ it('forwards the title prop to the title input', () => {
+ expect(findGlFormInputTitle().attributes().value).toBe(title);
+ });
+
+ it('forwards the description prop to the description input', () => {
+ expect(findGlFormTextAreaDescription().attributes().value).toBe(description);
+ });
+
+ it('calls select on the title input when mounted', () => {
+ expect(mockGlFormInputTitleInstance.$el.select).toHaveBeenCalled();
+ });
+
+ describe('when inputs change', () => {
+ const storageKey = 'sse-merge-request-meta-local-storage-editable';
+
+ afterEach(() => {
+ localStorage.removeItem(storageKey);
+ });
+
+ it.each`
+ findFn | key | value
+ ${findGlFormInputTitle} | ${'title'} | ${newTitle}
+ ${findGlFormTextAreaDescription} | ${'description'} | ${newDescription}
+ `('emits updated settings when $findFn input updates', ({ key, value, findFn }) => {
+ findFn().vm.$emit('input', value);
+
+ const newSettings = { ...mergeRequestMeta, [key]: value };
+
+ expect(wrapper.emitted('updateSettings')[0][0]).toMatchObject(newSettings);
+ });
+
+ it('should remember the input changes', () => {
+ findGlFormInputTitle().vm.$emit('input', newTitle);
+ findGlFormTextAreaDescription().vm.$emit('input', newDescription);
+
+ const newSettings = { title: newTitle, description: newDescription };
+
+ expect(localStorage.setItem).toHaveBeenCalledWith(storageKey, JSON.stringify(newSettings));
+ });
+ });
+});
diff --git a/spec/frontend/static_site_editor/components/edit_meta_modal_spec.js b/spec/frontend/static_site_editor/components/edit_meta_modal_spec.js
new file mode 100644
index 00000000000..7a5685033f3
--- /dev/null
+++ b/spec/frontend/static_site_editor/components/edit_meta_modal_spec.js
@@ -0,0 +1,80 @@
+import { shallowMount } from '@vue/test-utils';
+
+import { GlModal } from '@gitlab/ui';
+
+import EditMetaModal from '~/static_site_editor/components/edit_meta_modal.vue';
+import EditMetaControls from '~/static_site_editor/components/edit_meta_controls.vue';
+
+import { sourcePath, mergeRequestMeta } from '../mock_data';
+
+describe('~/static_site_editor/components/edit_meta_modal.vue', () => {
+ let wrapper;
+ let resetCachedEditable;
+ let mockEditMetaControlsInstance;
+ const { title, description } = mergeRequestMeta;
+
+ const buildWrapper = (propsData = {}) => {
+ wrapper = shallowMount(EditMetaModal, {
+ propsData: {
+ sourcePath,
+ ...propsData,
+ },
+ });
+ };
+
+ const buildMocks = () => {
+ resetCachedEditable = jest.fn();
+ mockEditMetaControlsInstance = { resetCachedEditable };
+ wrapper.vm.$refs.editMetaControls = mockEditMetaControlsInstance;
+ };
+
+ const findGlModal = () => wrapper.find(GlModal);
+ const findEditMetaControls = () => wrapper.find(EditMetaControls);
+
+ beforeEach(() => {
+ buildWrapper();
+ buildMocks();
+
+ return wrapper.vm.$nextTick();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ wrapper = null;
+ });
+
+ it('renders the modal', () => {
+ expect(findGlModal().exists()).toBe(true);
+ });
+
+ it('renders the edit meta controls', () => {
+ expect(findEditMetaControls().exists()).toBe(true);
+ });
+
+ it('contains the sourcePath in the title', () => {
+ expect(findEditMetaControls().props('title')).toContain(sourcePath);
+ });
+
+ it('forwards the title prop', () => {
+ expect(findEditMetaControls().props('title')).toBe(title);
+ });
+
+ it('forwards the description prop', () => {
+ expect(findEditMetaControls().props('description')).toBe(description);
+ });
+
+ it('emits the primary event with mergeRequestMeta', () => {
+ findGlModal().vm.$emit('primary', mergeRequestMeta);
+ expect(wrapper.emitted('primary')).toEqual([[mergeRequestMeta]]);
+ });
+
+ it('calls resetCachedEditable on EditMetaControls when primary emits', () => {
+ findGlModal().vm.$emit('primary', mergeRequestMeta);
+ expect(mockEditMetaControlsInstance.resetCachedEditable).toHaveBeenCalled();
+ });
+
+ it('emits the hide event', () => {
+ findGlModal().vm.$emit('hide');
+ expect(wrapper.emitted('hide')).toEqual([[]]);
+ });
+});
diff --git a/spec/frontend/static_site_editor/components/front_matter_controls_spec.js b/spec/frontend/static_site_editor/components/front_matter_controls_spec.js
index 82e8fad643e..8001f2fbd29 100644
--- a/spec/frontend/static_site_editor/components/front_matter_controls_spec.js
+++ b/spec/frontend/static_site_editor/components/front_matter_controls_spec.js
@@ -5,18 +5,11 @@ import { humanize } from '~/lib/utils/text_utility';
import FrontMatterControls from '~/static_site_editor/components/front_matter_controls.vue';
+import { sourceContentHeaderObjYAML as settings } from '../mock_data';
+
describe('~/static_site_editor/components/front_matter_controls.vue', () => {
let wrapper;
- // TODO Refactor and update `sourceContentHeaderObjYAML` in mock_data when !41230 lands
- const settings = {
- layout: 'handbook-page-toc',
- title: 'Handbook',
- twitter_image: '/images/tweets/handbook-gitlab.png',
- suppress_header: true,
- extra_css: ['sales-and-free-trial-common.css', 'form-to-resource.css'],
- };
-
const buildWrapper = (propsData = {}) => {
wrapper = shallowMount(FrontMatterControls, {
propsData: {
diff --git a/spec/frontend/static_site_editor/graphql/resolvers/has_submitted_changes_spec.js b/spec/frontend/static_site_editor/graphql/resolvers/has_submitted_changes_spec.js
new file mode 100644
index 00000000000..0670b240a3f
--- /dev/null
+++ b/spec/frontend/static_site_editor/graphql/resolvers/has_submitted_changes_spec.js
@@ -0,0 +1,27 @@
+import appDataQuery from '~/static_site_editor/graphql/queries/app_data.query.graphql';
+import hasSubmittedChanges from '~/static_site_editor/graphql/resolvers/has_submitted_changes';
+
+describe('static_site_editor/graphql/resolvers/has_submitted_changes', () => {
+ it('updates the cache with the data passed in input', () => {
+ const cachedData = { appData: { original: 'foo' } };
+ const newValue = { input: { hasSubmittedChanges: true } };
+
+ const cache = {
+ readQuery: jest.fn().mockReturnValue(cachedData),
+ writeQuery: jest.fn(),
+ };
+ hasSubmittedChanges(null, newValue, { cache });
+
+ expect(cache.readQuery).toHaveBeenCalledWith({ query: appDataQuery });
+ expect(cache.writeQuery).toHaveBeenCalledWith({
+ query: appDataQuery,
+ data: {
+ appData: {
+ __typename: 'AppData',
+ original: 'foo',
+ hasSubmittedChanges: true,
+ },
+ },
+ });
+ });
+});
diff --git a/spec/frontend/static_site_editor/mock_data.js b/spec/frontend/static_site_editor/mock_data.js
index d861f6c9cd7..0b08e290227 100644
--- a/spec/frontend/static_site_editor/mock_data.js
+++ b/spec/frontend/static_site_editor/mock_data.js
@@ -2,11 +2,17 @@ export const sourceContentHeaderYAML = `---
layout: handbook-page-toc
title: Handbook
twitter_image: /images/tweets/handbook-gitlab.png
+suppress_header: true
+extra_css:
+ - sales-and-free-trial-common.css
+ - form-to-resource.css
---`;
export const sourceContentHeaderObjYAML = {
layout: 'handbook-page-toc',
title: 'Handbook',
twitter_image: '/images/tweets/handbook-gitlab.png',
+ suppress_header: true,
+ extra_css: ['sales-and-free-trial-common.css', 'form-to-resource.css'],
};
export const sourceContentSpacing = `\n`;
export const sourceContentBody = `## On this page
@@ -23,7 +29,10 @@ export const username = 'gitlabuser';
export const projectId = '123456';
export const returnUrl = 'https://www.gitlab.com';
export const sourcePath = 'foobar.md.html';
-
+export const mergeRequestMeta = {
+ title: `Update ${sourcePath} file`,
+ description: 'Copy update',
+};
export const savedContentMeta = {
branch: {
label: 'foobar',
diff --git a/spec/frontend/static_site_editor/pages/home_spec.js b/spec/frontend/static_site_editor/pages/home_spec.js
index 41f8a1075c0..2c69e884005 100644
--- a/spec/frontend/static_site_editor/pages/home_spec.js
+++ b/spec/frontend/static_site_editor/pages/home_spec.js
@@ -1,12 +1,13 @@
-import Vuex from 'vuex';
import { shallowMount, createLocalVue } from '@vue/test-utils';
import { mockTracking, unmockTracking } from 'helpers/tracking_helper';
import Home from '~/static_site_editor/pages/home.vue';
import SkeletonLoader from '~/static_site_editor/components/skeleton_loader.vue';
import EditArea from '~/static_site_editor/components/edit_area.vue';
+import EditMetaModal from '~/static_site_editor/components/edit_meta_modal.vue';
import InvalidContentMessage from '~/static_site_editor/components/invalid_content_message.vue';
import SubmitChangesError from '~/static_site_editor/components/submit_changes_error.vue';
import submitContentChangesMutation from '~/static_site_editor/graphql/mutations/submit_content_changes.mutation.graphql';
+import hasSubmittedChangesMutation from '~/static_site_editor/graphql/mutations/has_submitted_changes.mutation.graphql';
import { SUCCESS_ROUTE } from '~/static_site_editor/router/constants';
import { TRACKING_ACTION_INITIALIZE_EDITOR } from '~/static_site_editor/constants';
@@ -17,15 +18,15 @@ import {
sourceContentTitle as title,
sourcePath,
username,
+ mergeRequestMeta,
savedContentMeta,
submitChangesError,
trackingCategory,
+ images,
} from '../mock_data';
const localVue = createLocalVue();
-localVue.use(Vuex);
-
describe('static_site_editor/pages/home', () => {
let wrapper;
let store;
@@ -33,6 +34,19 @@ describe('static_site_editor/pages/home', () => {
let $router;
let mutateMock;
let trackingSpy;
+ const defaultAppData = {
+ isSupportedContent: true,
+ hasSubmittedChanges: false,
+ returnUrl,
+ project,
+ username,
+ sourcePath,
+ };
+ const hasSubmittedChangesMutationPayload = {
+ data: {
+ appData: { ...defaultAppData, hasSubmittedChanges: true },
+ },
+ };
const buildApollo = (queries = {}) => {
mutateMock = jest.fn();
@@ -64,7 +78,7 @@ describe('static_site_editor/pages/home', () => {
},
data() {
return {
- appData: { isSupportedContent: true, returnUrl, project, username, sourcePath },
+ appData: { ...defaultAppData },
sourceContent: { title, content },
...data,
};
@@ -73,6 +87,7 @@ describe('static_site_editor/pages/home', () => {
};
const findEditArea = () => wrapper.find(EditArea);
+ const findEditMetaModal = () => wrapper.find(EditMetaModal);
const findInvalidContentMessage = () => wrapper.find(InvalidContentMessage);
const findSkeletonLoader = () => wrapper.find(SkeletonLoader);
const findSubmitChangesError = () => wrapper.find(SubmitChangesError);
@@ -140,24 +155,51 @@ describe('static_site_editor/pages/home', () => {
});
it('displays invalid content message when content is not supported', () => {
- buildWrapper({ appData: { isSupportedContent: false } });
+ buildWrapper({ appData: { ...defaultAppData, isSupportedContent: false } });
expect(findInvalidContentMessage().exists()).toBe(true);
});
it('does not display invalid content message when content is supported', () => {
- buildWrapper({ appData: { isSupportedContent: true } });
+ buildWrapper();
expect(findInvalidContentMessage().exists()).toBe(false);
});
- describe('when submitting changes fails', () => {
- beforeEach(() => {
- mutateMock.mockRejectedValue(new Error(submitChangesError));
+ it('renders an EditMetaModal component', () => {
+ buildWrapper();
+
+ expect(findEditMetaModal().exists()).toBe(true);
+ });
+ describe('when preparing submission', () => {
+ it('calls the show method when the edit-area submit event is emitted', () => {
buildWrapper();
+
+ const mockInstance = { show: jest.fn() };
+ wrapper.vm.$refs.editMetaModal = mockInstance;
+
findEditArea().vm.$emit('submit', { content });
+ return wrapper.vm.$nextTick().then(() => {
+ expect(mockInstance.show).toHaveBeenCalled();
+ });
+ });
+ });
+
+ describe('when submitting changes fails', () => {
+ const setupMutateMock = () => {
+ mutateMock
+ .mockResolvedValueOnce(hasSubmittedChangesMutationPayload)
+ .mockRejectedValueOnce(new Error(submitChangesError));
+ };
+
+ beforeEach(() => {
+ setupMutateMock();
+
+ buildWrapper({ content });
+ findEditMetaModal().vm.$emit('primary', mergeRequestMeta);
+
return wrapper.vm.$nextTick();
});
@@ -166,6 +208,8 @@ describe('static_site_editor/pages/home', () => {
});
it('retries submitting changes when retry button is clicked', () => {
+ setupMutateMock();
+
findSubmitChangesError().vm.$emit('retry');
expect(mutateMock).toHaveBeenCalled();
@@ -180,26 +224,35 @@ describe('static_site_editor/pages/home', () => {
});
});
- it('does not display submit changes error when an error does not exist', () => {
- buildWrapper();
-
- expect(findSubmitChangesError().exists()).toBe(false);
- });
-
describe('when submitting changes succeeds', () => {
const newContent = `new ${content}`;
beforeEach(() => {
- mutateMock.mockResolvedValueOnce({ data: { submitContentChanges: savedContentMeta } });
+ mutateMock.mockResolvedValueOnce(hasSubmittedChangesMutationPayload).mockResolvedValueOnce({
+ data: {
+ submitContentChanges: savedContentMeta,
+ },
+ });
- buildWrapper();
- findEditArea().vm.$emit('submit', { content: newContent });
+ buildWrapper({ content: newContent, images });
+ findEditMetaModal().vm.$emit('primary', mergeRequestMeta);
return wrapper.vm.$nextTick();
});
+ it('dispatches hasSubmittedChanges mutation', () => {
+ expect(mutateMock).toHaveBeenNthCalledWith(1, {
+ mutation: hasSubmittedChangesMutation,
+ variables: {
+ input: {
+ hasSubmittedChanges: true,
+ },
+ },
+ });
+ });
+
it('dispatches submitContentChanges mutation', () => {
- expect(mutateMock).toHaveBeenCalledWith({
+ expect(mutateMock).toHaveBeenNthCalledWith(2, {
mutation: submitContentChangesMutation,
variables: {
input: {
@@ -207,6 +260,8 @@ describe('static_site_editor/pages/home', () => {
project,
sourcePath,
username,
+ images,
+ mergeRequestMeta,
},
},
});
@@ -217,6 +272,12 @@ describe('static_site_editor/pages/home', () => {
});
});
+ it('does not display submit changes error when an error does not exist', () => {
+ buildWrapper();
+
+ expect(findSubmitChangesError().exists()).toBe(false);
+ });
+
it('tracks when editor is initialized on the mounted lifecycle hook', () => {
buildWrapper();
expect(trackingSpy).toHaveBeenCalledWith(
diff --git a/spec/frontend/static_site_editor/pages/success_spec.js b/spec/frontend/static_site_editor/pages/success_spec.js
index 3e19e2413e7..3fc69dc4586 100644
--- a/spec/frontend/static_site_editor/pages/success_spec.js
+++ b/spec/frontend/static_site_editor/pages/success_spec.js
@@ -1,10 +1,10 @@
import { shallowMount } from '@vue/test-utils';
-import { GlEmptyState, GlButton } from '@gitlab/ui';
+import { GlButton, GlEmptyState, GlLoadingIcon } from '@gitlab/ui';
import Success from '~/static_site_editor/pages/success.vue';
import { savedContentMeta, returnUrl, sourcePath } from '../mock_data';
import { HOME_ROUTE } from '~/static_site_editor/router/constants';
-describe('static_site_editor/pages/success', () => {
+describe('~/static_site_editor/pages/success.vue', () => {
const mergeRequestsIllustrationPath = 'illustrations/merge_requests.svg';
let wrapper;
let router;
@@ -15,14 +15,15 @@ describe('static_site_editor/pages/success', () => {
};
};
- const buildWrapper = (data = {}) => {
+ const buildWrapper = (data = {}, appData = {}) => {
wrapper = shallowMount(Success, {
mocks: {
$router: router,
},
stubs: {
- GlEmptyState,
GlButton,
+ GlEmptyState,
+ GlLoadingIcon,
},
propsData: {
mergeRequestsIllustrationPath,
@@ -33,6 +34,8 @@ describe('static_site_editor/pages/success', () => {
appData: {
returnUrl,
sourcePath,
+ hasSubmittedChanges: true,
+ ...appData,
},
...data,
};
@@ -40,8 +43,9 @@ describe('static_site_editor/pages/success', () => {
});
};
- const findEmptyState = () => wrapper.find(GlEmptyState);
const findReturnUrlButton = () => wrapper.find(GlButton);
+ const findEmptyState = () => wrapper.find(GlEmptyState);
+ const findLoadingIcon = () => wrapper.find(GlLoadingIcon);
beforeEach(() => {
buildRouter();
@@ -52,50 +56,76 @@ describe('static_site_editor/pages/success', () => {
wrapper = null;
});
- it('renders empty state with a link to the created merge request', () => {
- buildWrapper();
+ describe('when savedContentMeta is valid', () => {
+ it('renders empty state with a link to the created merge request', () => {
+ buildWrapper();
+
+ expect(findEmptyState().exists()).toBe(true);
+ expect(findEmptyState().props()).toMatchObject({
+ primaryButtonText: 'View merge request',
+ primaryButtonLink: savedContentMeta.mergeRequest.url,
+ title: 'Your merge request has been created',
+ svgPath: mergeRequestsIllustrationPath,
+ svgHeight: 146,
+ });
+ });
- expect(findEmptyState().exists()).toBe(true);
- expect(findEmptyState().props()).toMatchObject({
- primaryButtonText: 'View merge request',
- primaryButtonLink: savedContentMeta.mergeRequest.url,
- title: 'Your merge request has been created',
- svgPath: mergeRequestsIllustrationPath,
+ it('displays merge request instructions in the empty state', () => {
+ buildWrapper();
+
+ expect(findEmptyState().text()).toContain(
+ 'To see your changes live you will need to do the following things:',
+ );
+ expect(findEmptyState().text()).toContain('1. Add a clear title to describe the change.');
+ expect(findEmptyState().text()).toContain(
+ '2. Add a description to explain why the change is being made.',
+ );
+ expect(findEmptyState().text()).toContain(
+ '3. Assign a person to review and accept the merge request.',
+ );
});
- });
- it('displays merge request instructions in the empty state', () => {
- buildWrapper();
-
- expect(findEmptyState().text()).toContain(
- 'To see your changes live you will need to do the following things:',
- );
- expect(findEmptyState().text()).toContain('1. Add a clear title to describe the change.');
- expect(findEmptyState().text()).toContain(
- '2. Add a description to explain why the change is being made.',
- );
- expect(findEmptyState().text()).toContain(
- '3. Assign a person to review and accept the merge request.',
- );
- });
+ it('displays return to site button', () => {
+ buildWrapper();
+
+ expect(findReturnUrlButton().text()).toBe('Return to site');
+ expect(findReturnUrlButton().attributes().href).toBe(returnUrl);
+ });
- it('displays return to site button', () => {
- buildWrapper();
+ it('displays source path', () => {
+ buildWrapper();
- expect(findReturnUrlButton().text()).toBe('Return to site');
- expect(findReturnUrlButton().attributes().href).toBe(returnUrl);
+ expect(wrapper.text()).toContain(`Update ${sourcePath} file`);
+ });
});
- it('displays source path', () => {
- buildWrapper();
+ describe('when savedContentMeta is invalid', () => {
+ it('renders empty state with a loader', () => {
+ buildWrapper({ savedContentMeta: null });
- expect(wrapper.text()).toContain(`Update ${sourcePath} file`);
- });
+ expect(findEmptyState().exists()).toBe(true);
+ expect(findEmptyState().props()).toMatchObject({
+ title: 'Creating your merge request',
+ svgPath: mergeRequestsIllustrationPath,
+ });
+ expect(findLoadingIcon().exists()).toBe(true);
+ });
- it('redirects to the HOME route when content has not been submitted', () => {
- buildWrapper({ savedContentMeta: null });
+ it('displays helper info in the empty state', () => {
+ buildWrapper({ savedContentMeta: null });
- expect(router.push).toHaveBeenCalledWith(HOME_ROUTE);
- expect(wrapper.html()).toBe('');
+ expect(findEmptyState().text()).toContain(
+ 'You can set an assignee to get your changes reviewed and deployed once your merge request is created',
+ );
+ expect(findEmptyState().text()).toContain(
+ 'A link to view the merge request will appear once ready',
+ );
+ });
+
+ it('redirects to the HOME route when content has not been submitted', () => {
+ buildWrapper({ savedContentMeta: null }, { hasSubmittedChanges: false });
+
+ expect(router.push).toHaveBeenCalledWith(HOME_ROUTE);
+ });
});
});
diff --git a/spec/frontend/static_site_editor/services/front_matterify_spec.js b/spec/frontend/static_site_editor/services/front_matterify_spec.js
new file mode 100644
index 00000000000..dbaedc30849
--- /dev/null
+++ b/spec/frontend/static_site_editor/services/front_matterify_spec.js
@@ -0,0 +1,47 @@
+import {
+ sourceContentYAML as content,
+ sourceContentHeaderObjYAML as yamlFrontMatterObj,
+ sourceContentSpacing as spacing,
+ sourceContentBody as body,
+} from '../mock_data';
+
+import { frontMatterify, stringify } from '~/static_site_editor/services/front_matterify';
+
+describe('static_site_editor/services/front_matterify', () => {
+ const frontMatterifiedContent = {
+ source: content,
+ matter: yamlFrontMatterObj,
+ spacing,
+ content: body,
+ delimiter: '---',
+ type: 'yaml',
+ };
+ const frontMatterifiedBody = {
+ source: body,
+ matter: null,
+ spacing: null,
+ content: body,
+ delimiter: null,
+ type: null,
+ };
+
+ describe('frontMatterify', () => {
+ it.each`
+ frontMatterified | target
+ ${frontMatterify(content)} | ${frontMatterifiedContent}
+ ${frontMatterify(body)} | ${frontMatterifiedBody}
+ `('returns $target from $frontMatterified', ({ frontMatterified, target }) => {
+ expect(frontMatterified).toEqual(target);
+ });
+ });
+
+ describe('stringify', () => {
+ it.each`
+ stringified | target
+ ${stringify(frontMatterifiedContent)} | ${content}
+ ${stringify(frontMatterifiedBody)} | ${body}
+ `('returns $target from $stringified', ({ stringified, target }) => {
+ expect(stringified).toBe(target);
+ });
+ });
+});
diff --git a/spec/frontend/static_site_editor/services/submit_content_changes_spec.js b/spec/frontend/static_site_editor/services/submit_content_changes_spec.js
index d464e6b1895..5018da7300b 100644
--- a/spec/frontend/static_site_editor/services/submit_content_changes_spec.js
+++ b/spec/frontend/static_site_editor/services/submit_content_changes_spec.js
@@ -19,6 +19,7 @@ import {
commitBranchResponse,
commitMultipleResponse,
createMergeRequestResponse,
+ mergeRequestMeta,
sourcePath,
sourceContentYAML as content,
trackingCategory,
@@ -28,11 +29,20 @@ import {
jest.mock('~/static_site_editor/services/generate_branch_name');
describe('submitContentChanges', () => {
- const mergeRequestTitle = `Update ${sourcePath} file`;
const branch = 'branch-name';
let trackingSpy;
let origPage;
+ const buildPayload = (overrides = {}) => ({
+ username,
+ projectId,
+ sourcePath,
+ content,
+ images,
+ mergeRequestMeta,
+ ...overrides,
+ });
+
beforeEach(() => {
jest.spyOn(Api, 'createBranch').mockResolvedValue({ data: commitBranchResponse });
jest.spyOn(Api, 'commitMultiple').mockResolvedValue({ data: commitMultipleResponse });
@@ -53,7 +63,7 @@ describe('submitContentChanges', () => {
});
it('creates a branch named after the username and target branch', () => {
- return submitContentChanges({ username, projectId }).then(() => {
+ return submitContentChanges(buildPayload()).then(() => {
expect(Api.createBranch).toHaveBeenCalledWith(projectId, {
ref: DEFAULT_TARGET_BRANCH,
branch,
@@ -64,16 +74,16 @@ describe('submitContentChanges', () => {
it('notifies error when branch could not be created', () => {
Api.createBranch.mockRejectedValueOnce();
- return expect(submitContentChanges({ username, projectId })).rejects.toThrow(
+ return expect(submitContentChanges(buildPayload())).rejects.toThrow(
SUBMIT_CHANGES_BRANCH_ERROR,
);
});
it('commits the content changes to the branch when creating branch succeeds', () => {
- return submitContentChanges({ username, projectId, sourcePath, content, images }).then(() => {
+ return submitContentChanges(buildPayload()).then(() => {
expect(Api.commitMultiple).toHaveBeenCalledWith(projectId, {
branch,
- commit_message: mergeRequestTitle,
+ commit_message: mergeRequestMeta.title,
actions: [
{
action: 'update',
@@ -93,16 +103,11 @@ describe('submitContentChanges', () => {
it('does not commit an image if it has been removed from the content', () => {
const contentWithoutImages = '## Content without images';
- return submitContentChanges({
- username,
- projectId,
- sourcePath,
- content: contentWithoutImages,
- images,
- }).then(() => {
+ const payload = buildPayload({ content: contentWithoutImages });
+ return submitContentChanges(payload).then(() => {
expect(Api.commitMultiple).toHaveBeenCalledWith(projectId, {
branch,
- commit_message: mergeRequestTitle,
+ commit_message: mergeRequestMeta.title,
actions: [
{
action: 'update',
@@ -117,17 +122,19 @@ describe('submitContentChanges', () => {
it('notifies error when content could not be committed', () => {
Api.commitMultiple.mockRejectedValueOnce();
- return expect(submitContentChanges({ username, projectId, images })).rejects.toThrow(
+ return expect(submitContentChanges(buildPayload())).rejects.toThrow(
SUBMIT_CHANGES_COMMIT_ERROR,
);
});
- it('creates a merge request when commiting changes succeeds', () => {
- return submitContentChanges({ username, projectId, sourcePath, content, images }).then(() => {
+ it('creates a merge request when committing changes succeeds', () => {
+ return submitContentChanges(buildPayload()).then(() => {
+ const { title, description } = mergeRequestMeta;
expect(Api.createProjectMergeRequest).toHaveBeenCalledWith(
projectId,
convertObjectPropsToSnakeCase({
- title: mergeRequestTitle,
+ title,
+ description,
targetBranch: DEFAULT_TARGET_BRANCH,
sourceBranch: branch,
}),
@@ -138,7 +145,7 @@ describe('submitContentChanges', () => {
it('notifies error when merge request could not be created', () => {
Api.createProjectMergeRequest.mockRejectedValueOnce();
- return expect(submitContentChanges({ username, projectId, images })).rejects.toThrow(
+ return expect(submitContentChanges(buildPayload())).rejects.toThrow(
SUBMIT_CHANGES_MERGE_REQUEST_ERROR,
);
});
@@ -147,11 +154,9 @@ describe('submitContentChanges', () => {
let result;
beforeEach(() => {
- return submitContentChanges({ username, projectId, sourcePath, content, images }).then(
- _result => {
- result = _result;
- },
- );
+ return submitContentChanges(buildPayload()).then(_result => {
+ result = _result;
+ });
});
it('returns the branch name', () => {
@@ -179,7 +184,7 @@ describe('submitContentChanges', () => {
describe('sends the correct tracking event', () => {
beforeEach(() => {
- return submitContentChanges({ username, projectId, sourcePath, content, images });
+ return submitContentChanges(buildPayload());
});
it('for committing changes', () => {
diff --git a/spec/frontend/static_site_editor/services/templater_spec.js b/spec/frontend/static_site_editor/services/templater_spec.js
index 1e7ae872b7e..cb3a0a0c106 100644
--- a/spec/frontend/static_site_editor/services/templater_spec.js
+++ b/spec/frontend/static_site_editor/services/templater_spec.js
@@ -39,6 +39,10 @@ Below this line is a codeblock of the same HTML that should be ignored and prese
<p>Some paragraph...</p>
</div>
\`\`\`
+
+Below this line is a iframe that should be ignored and preserved
+
+<iframe></iframe>
`;
const sourceTemplated = `Below this line is a simple ERB (single-line erb block) example.
@@ -87,6 +91,10 @@ Below this line is a codeblock of the same HTML that should be ignored and prese
<p>Some paragraph...</p>
</div>
\`\`\`
+
+Below this line is a iframe that should be ignored and preserved
+
+<iframe></iframe>
`;
it.each`
diff --git a/spec/frontend/test_setup.js b/spec/frontend/test_setup.js
index 544c19da57b..eebec7de9d4 100644
--- a/spec/frontend/test_setup.js
+++ b/spec/frontend/test_setup.js
@@ -1,4 +1,6 @@
import Vue from 'vue';
+import 'jquery';
+
import * as jqueryMatchers from 'custom-jquery-matchers';
import { config as testUtilsConfig } from '@vue/test-utils';
import Translate from '~/vue_shared/translate';
@@ -9,7 +11,6 @@ import customMatchers from './matchers';
import './helpers/dom_shims';
import './helpers/jquery';
-import '~/commons/jquery';
import '~/commons/bootstrap';
process.on('unhandledRejection', global.promiseRejectionHandler);
diff --git a/spec/frontend/tracking_spec.js b/spec/frontend/tracking_spec.js
index e2d39ffeaf0..8c2bef60e74 100644
--- a/spec/frontend/tracking_spec.js
+++ b/spec/frontend/tracking_spec.js
@@ -28,7 +28,7 @@ describe('Tracking', () => {
respectDoNotTrack: true,
forceSecureTracker: true,
eventMethod: 'post',
- contexts: { webPage: true },
+ contexts: { webPage: true, performanceTiming: true },
formTracking: false,
linkClickTracking: false,
});
diff --git a/spec/frontend/user_lists/components/add_user_modal_spec.js b/spec/frontend/user_lists/components/add_user_modal_spec.js
new file mode 100644
index 00000000000..82ce195d7cd
--- /dev/null
+++ b/spec/frontend/user_lists/components/add_user_modal_spec.js
@@ -0,0 +1,50 @@
+import { mount } from '@vue/test-utils';
+import AddUserModal from '~/user_lists/components/add_user_modal.vue';
+
+describe('Add User Modal', () => {
+ let wrapper;
+
+ const click = testId => wrapper.find(`[data-testid="${testId}"]`).trigger('click');
+
+ beforeEach(() => {
+ wrapper = mount(AddUserModal, {
+ propsData: { visible: true },
+ });
+ });
+
+ it('should explain the format of user IDs to enter', () => {
+ expect(wrapper.find('[data-testid="add-userids-description"]').text()).toContain(
+ 'Enter a comma separated list of user IDs',
+ );
+ });
+
+ describe('events', () => {
+ beforeEach(() => {
+ wrapper.find('#add-user-ids').setValue('1, 2, 3, 4');
+ });
+
+ it('should emit the users entered when Add Users is clicked', () => {
+ click('confirm-add-user-ids');
+ expect(wrapper.emitted('addUsers')).toContainEqual(['1, 2, 3, 4']);
+ });
+
+ it('should clear the input after emitting', async () => {
+ click('confirm-add-user-ids');
+ await wrapper.vm.$nextTick();
+
+ expect(wrapper.find('#add-user-ids').element.value).toBe('');
+ });
+
+ it('should not emit the users entered if cancel is clicked', () => {
+ click('cancel-add-user-ids');
+ expect(wrapper.emitted('addUsers')).toBeUndefined();
+ });
+
+ it('should clear the input after cancelling', async () => {
+ click('cancel-add-user-ids');
+ await wrapper.vm.$nextTick();
+
+ expect(wrapper.find('#add-user-ids').element.value).toBe('');
+ });
+ });
+});
diff --git a/spec/frontend/user_lists/components/edit_user_list_spec.js b/spec/frontend/user_lists/components/edit_user_list_spec.js
new file mode 100644
index 00000000000..51a38e12916
--- /dev/null
+++ b/spec/frontend/user_lists/components/edit_user_list_spec.js
@@ -0,0 +1,150 @@
+import Vue from 'vue';
+import Vuex from 'vuex';
+import { createLocalVue, mount } from '@vue/test-utils';
+import { GlAlert, GlLoadingIcon } from '@gitlab/ui';
+import waitForPromises from 'helpers/wait_for_promises';
+import Api from '~/api';
+import createStore from '~/user_lists/store/edit';
+import EditUserList from '~/user_lists/components/edit_user_list.vue';
+import UserListForm from '~/user_lists/components/user_list_form.vue';
+import { userList } from '../../feature_flags/mock_data';
+import { redirectTo } from '~/lib/utils/url_utility';
+
+jest.mock('~/api');
+jest.mock('~/lib/utils/url_utility');
+
+const localVue = createLocalVue(Vue);
+localVue.use(Vuex);
+
+describe('user_lists/components/edit_user_list', () => {
+ let wrapper;
+
+ const setInputValue = value => wrapper.find('[data-testid="user-list-name"]').setValue(value);
+
+ const click = button => wrapper.find(`[data-testid="${button}"]`).trigger('click');
+ const clickSave = () => click('save-user-list');
+
+ const destroy = () => wrapper?.destroy();
+
+ const factory = () => {
+ destroy();
+
+ wrapper = mount(EditUserList, {
+ localVue,
+ store: createStore({ projectId: '1', userListIid: '2' }),
+ provide: {
+ userListsDocsPath: '/docs/user_lists',
+ },
+ });
+ };
+
+ afterEach(() => {
+ destroy();
+ });
+
+ describe('loading', () => {
+ beforeEach(() => {
+ Api.fetchFeatureFlagUserList.mockReturnValue(new Promise(() => {}));
+ factory();
+ });
+
+ it('should show a loading icon', () => {
+ expect(wrapper.find(GlLoadingIcon).exists()).toBe(true);
+ });
+ });
+
+ describe('loading error', () => {
+ const message = 'error creating list';
+ let alert;
+
+ beforeEach(async () => {
+ Api.fetchFeatureFlagUserList.mockRejectedValue({ message });
+ factory();
+ await waitForPromises();
+
+ alert = wrapper.find(GlAlert);
+ });
+
+ it('should show a flash with the error respopnse', () => {
+ expect(alert.text()).toContain(message);
+ });
+
+ it('should not be dismissible', async () => {
+ expect(alert.props('dismissible')).toBe(false);
+ });
+
+ it('should not show a user list form', () => {
+ expect(wrapper.find(UserListForm).exists()).toBe(false);
+ });
+ });
+
+ describe('update', () => {
+ beforeEach(() => {
+ Api.fetchFeatureFlagUserList.mockResolvedValue({ data: userList });
+ factory();
+
+ return wrapper.vm.$nextTick();
+ });
+
+ it('should link to the documentation', () => {
+ const link = wrapper.find('[data-testid="user-list-docs-link"]');
+ expect(link.attributes('href')).toBe('/docs/user_lists');
+ });
+
+ it('should link the cancel button to the user list details path', () => {
+ const link = wrapper.find('[data-testid="user-list-cancel"]');
+ expect(link.attributes('href')).toBe(userList.path);
+ });
+
+ it('should show the user list name in the title', () => {
+ expect(wrapper.find('[data-testid="user-list-title"]').text()).toBe(`Edit ${userList.name}`);
+ });
+
+ describe('success', () => {
+ beforeEach(() => {
+ Api.updateFeatureFlagUserList.mockResolvedValue({ data: userList });
+ setInputValue('test');
+ clickSave();
+ return wrapper.vm.$nextTick();
+ });
+
+ it('should create a user list with the entered name', () => {
+ expect(Api.updateFeatureFlagUserList).toHaveBeenCalledWith('1', {
+ name: 'test',
+ iid: userList.iid,
+ });
+ });
+
+ it('should redirect to the feature flag details page', () => {
+ expect(redirectTo).toHaveBeenCalledWith(userList.path);
+ });
+ });
+
+ describe('error', () => {
+ let alert;
+ let message;
+
+ beforeEach(async () => {
+ message = 'error creating list';
+ Api.updateFeatureFlagUserList.mockRejectedValue({ message });
+ setInputValue('test');
+ clickSave();
+ await waitForPromises();
+
+ alert = wrapper.find(GlAlert);
+ });
+
+ it('should show a flash with the error respopnse', () => {
+ expect(alert.text()).toContain(message);
+ });
+
+ it('should dismiss the error if dismiss is clicked', async () => {
+ alert.find('button').trigger('click');
+
+ await wrapper.vm.$nextTick();
+
+ expect(alert.exists()).toBe(false);
+ });
+ });
+ });
+});
diff --git a/spec/frontend/user_lists/components/new_user_list_spec.js b/spec/frontend/user_lists/components/new_user_list_spec.js
new file mode 100644
index 00000000000..62fb0ca0859
--- /dev/null
+++ b/spec/frontend/user_lists/components/new_user_list_spec.js
@@ -0,0 +1,93 @@
+import { mount, createLocalVue } from '@vue/test-utils';
+import Vue from 'vue';
+import Vuex from 'vuex';
+import { GlAlert } from '@gitlab/ui';
+import waitForPromises from 'helpers/wait_for_promises';
+import Api from '~/api';
+import createStore from '~/user_lists/store/new';
+import NewUserList from '~/user_lists/components/new_user_list.vue';
+import { redirectTo } from '~/lib/utils/url_utility';
+import { userList } from '../../feature_flags/mock_data';
+
+jest.mock('~/api');
+jest.mock('~/lib/utils/url_utility');
+
+const localVue = createLocalVue(Vue);
+localVue.use(Vuex);
+
+describe('user_lists/components/new_user_list', () => {
+ let wrapper;
+
+ const setInputValue = value => wrapper.find('[data-testid="user-list-name"]').setValue(value);
+
+ const click = button => wrapper.find(`[data-testid="${button}"]`).trigger('click');
+
+ beforeEach(() => {
+ wrapper = mount(NewUserList, {
+ localVue,
+ store: createStore({ projectId: '1' }),
+ provide: {
+ featureFlagsPath: '/feature_flags',
+ userListsDocsPath: '/docs/user_lists',
+ },
+ });
+ });
+
+ it('should link to the documentation', () => {
+ const link = wrapper.find('[data-testid="user-list-docs-link"]');
+ expect(link.attributes('href')).toBe('/docs/user_lists');
+ });
+
+ it('should link the cancel buton back to feature flags', () => {
+ const cancel = wrapper.find('[data-testid="user-list-cancel"');
+ expect(cancel.attributes('href')).toBe('/feature_flags');
+ });
+
+ describe('create', () => {
+ describe('success', () => {
+ beforeEach(() => {
+ Api.createFeatureFlagUserList.mockResolvedValue({ data: userList });
+ setInputValue('test');
+ click('save-user-list');
+ return wrapper.vm.$nextTick();
+ });
+
+ it('should create a user list with the entered name', () => {
+ expect(Api.createFeatureFlagUserList).toHaveBeenCalledWith('1', {
+ name: 'test',
+ user_xids: '',
+ });
+ });
+
+ it('should redirect to the feature flag details page', () => {
+ expect(redirectTo).toHaveBeenCalledWith(userList.path);
+ });
+ });
+
+ describe('error', () => {
+ let alert;
+
+ beforeEach(async () => {
+ Api.createFeatureFlagUserList.mockRejectedValue({ message: 'error creating list' });
+ setInputValue('test');
+ click('save-user-list');
+
+ await waitForPromises();
+
+ alert = wrapper.find(GlAlert);
+ });
+
+ it('should show a flash with the error respopnse', () => {
+ expect(alert.text()).toContain('error creating list');
+ });
+
+ it('should dismiss the error when the dismiss button is clicked', async () => {
+ alert.find('button').trigger('click');
+
+ await wrapper.vm.$nextTick();
+
+ expect(alert.exists()).toBe(false);
+ });
+ });
+ });
+});
diff --git a/spec/frontend/user_lists/components/user_list_form_spec.js b/spec/frontend/user_lists/components/user_list_form_spec.js
new file mode 100644
index 00000000000..42f7659600e
--- /dev/null
+++ b/spec/frontend/user_lists/components/user_list_form_spec.js
@@ -0,0 +1,40 @@
+import { mount } from '@vue/test-utils';
+import Form from '~/user_lists/components/user_list_form.vue';
+import { userList } from '../../feature_flags/mock_data';
+
+describe('user_lists/components/user_list_form', () => {
+ let wrapper;
+ let input;
+
+ beforeEach(() => {
+ wrapper = mount(Form, {
+ propsData: {
+ cancelPath: '/cancel',
+ saveButtonLabel: 'Save',
+ userListsDocsPath: '/docs',
+ userList,
+ },
+ });
+
+ input = wrapper.find('[data-testid="user-list-name"]');
+ });
+
+ it('should set the name to the name of the given user list', () => {
+ expect(input.element.value).toBe(userList.name);
+ });
+
+ it('should link to the user lists docs', () => {
+ expect(wrapper.find('[data-testid="user-list-docs-link"]').attributes('href')).toBe('/docs');
+ });
+
+ it('should emit an updated user list when save is clicked', () => {
+ input.setValue('test');
+ wrapper.find('[data-testid="save-user-list"]').trigger('click');
+
+ expect(wrapper.emitted('submit')).toEqual([[{ ...userList, name: 'test' }]]);
+ });
+
+ it('should set the cancel button to the passed url', () => {
+ expect(wrapper.find('[data-testid="user-list-cancel"]').attributes('href')).toBe('/cancel');
+ });
+});
diff --git a/spec/frontend/user_lists/components/user_list_spec.js b/spec/frontend/user_lists/components/user_list_spec.js
new file mode 100644
index 00000000000..5f9b7967846
--- /dev/null
+++ b/spec/frontend/user_lists/components/user_list_spec.js
@@ -0,0 +1,196 @@
+import Vue from 'vue';
+import Vuex from 'vuex';
+import { mount } from '@vue/test-utils';
+import { uniq } from 'lodash';
+import { GlAlert, GlEmptyState, GlLoadingIcon } from '@gitlab/ui';
+import Api from '~/api';
+import { parseUserIds, stringifyUserIds } from '~/user_lists/store/utils';
+import createStore from '~/user_lists/store/show';
+import UserList from '~/user_lists/components/user_list.vue';
+import { userList } from '../../feature_flags/mock_data';
+
+jest.mock('~/api');
+
+Vue.use(Vuex);
+
+describe('User List', () => {
+ let wrapper;
+
+ const click = testId => wrapper.find(`[data-testid="${testId}"]`).trigger('click');
+
+ const findUserIds = () => wrapper.findAll('[data-testid="user-id"]');
+
+ const destroy = () => wrapper?.destroy();
+
+ const factory = () => {
+ destroy();
+
+ wrapper = mount(UserList, {
+ store: createStore({ projectId: '1', userListIid: '2' }),
+ propsData: {
+ emptyStatePath: '/empty_state.svg',
+ },
+ });
+ };
+
+ describe('loading', () => {
+ let resolveFn;
+
+ beforeEach(() => {
+ Api.fetchFeatureFlagUserList.mockReturnValue(
+ new Promise(resolve => {
+ resolveFn = resolve;
+ }),
+ );
+ factory();
+ });
+
+ afterEach(() => {
+ resolveFn();
+ });
+
+ it('shows a loading icon', () => {
+ expect(wrapper.find(GlLoadingIcon).exists()).toBe(true);
+ });
+ });
+
+ describe('success', () => {
+ let userIds;
+
+ beforeEach(() => {
+ userIds = parseUserIds(userList.user_xids);
+ Api.fetchFeatureFlagUserList.mockResolvedValueOnce({ data: userList });
+ factory();
+
+ return wrapper.vm.$nextTick();
+ });
+
+ it('requests the user list on mount', () => {
+ expect(Api.fetchFeatureFlagUserList).toHaveBeenCalledWith('1', '2');
+ });
+
+ it('shows the list name', () => {
+ expect(wrapper.find('h3').text()).toBe(userList.name);
+ });
+
+ it('shows an add users button', () => {
+ expect(wrapper.find('[data-testid="add-users"]').text()).toBe('Add Users');
+ });
+
+ it('shows an edit list button', () => {
+ expect(wrapper.find('[data-testid="edit-user-list"]').text()).toBe('Edit');
+ });
+
+ it('shows a row for every id', () => {
+ expect(wrapper.findAll('[data-testid="user-id-row"]')).toHaveLength(userIds.length);
+ });
+
+ it('shows one id on each row', () => {
+ findUserIds().wrappers.forEach((w, i) => expect(w.text()).toBe(userIds[i]));
+ });
+
+ it('shows a delete button for every row', () => {
+ expect(wrapper.findAll('[data-testid="delete-user-id"]')).toHaveLength(userIds.length);
+ });
+
+ describe('adding users', () => {
+ const newIds = ['user3', 'user4', 'user5', 'test', 'example', 'foo'];
+ let receivedUserIds;
+ let parsedReceivedUserIds;
+
+ beforeEach(async () => {
+ Api.updateFeatureFlagUserList.mockResolvedValue(userList);
+ click('add-users');
+ await wrapper.vm.$nextTick();
+ wrapper.find('#add-user-ids').setValue(`${stringifyUserIds(newIds)},`);
+ click('confirm-add-user-ids');
+ await wrapper.vm.$nextTick();
+ [[, { user_xids: receivedUserIds }]] = Api.updateFeatureFlagUserList.mock.calls;
+ parsedReceivedUserIds = parseUserIds(receivedUserIds);
+ });
+
+ it('should add user IDs to the user list', () => {
+ newIds.forEach(id => expect(receivedUserIds).toContain(id));
+ });
+
+ it('should not remove existing user ids', () => {
+ userIds.forEach(id => expect(receivedUserIds).toContain(id));
+ });
+
+ it('should not submit empty IDs', () => {
+ parsedReceivedUserIds.forEach(id => expect(id).not.toBe(''));
+ });
+
+ it('should not create duplicate entries', () => {
+ expect(uniq(parsedReceivedUserIds)).toEqual(parsedReceivedUserIds);
+ });
+
+ it('should display the new IDs', () => {
+ const userIdWrappers = findUserIds();
+ newIds.forEach(id => {
+ const userIdWrapper = userIdWrappers.wrappers.find(w => w.text() === id);
+ expect(userIdWrapper.exists()).toBe(true);
+ });
+ });
+ });
+
+ describe('deleting users', () => {
+ let receivedUserIds;
+
+ beforeEach(async () => {
+ Api.updateFeatureFlagUserList.mockResolvedValue(userList);
+ click('delete-user-id');
+ await wrapper.vm.$nextTick();
+ [[, { user_xids: receivedUserIds }]] = Api.updateFeatureFlagUserList.mock.calls;
+ });
+
+ it('should remove the ID clicked', () => {
+ expect(receivedUserIds).not.toContain(userIds[0]);
+ });
+
+ it('should not display the deleted user', () => {
+ const userIdWrappers = findUserIds();
+ const userIdWrapper = userIdWrappers.wrappers.find(w => w.text() === userIds[0]);
+ expect(userIdWrapper).toBeUndefined();
+ });
+ });
+ });
+
+ describe('error', () => {
+ const findAlert = () => wrapper.find(GlAlert);
+
+ beforeEach(() => {
+ Api.fetchFeatureFlagUserList.mockRejectedValue();
+ factory();
+
+ return wrapper.vm.$nextTick();
+ });
+
+ it('displays the alert message', () => {
+ const alert = findAlert();
+ expect(alert.text()).toBe('Something went wrong on our end. Please try again!');
+ });
+
+ it('can dismiss the alert', async () => {
+ const alert = findAlert();
+ alert.find('button').trigger('click');
+
+ await wrapper.vm.$nextTick();
+
+ expect(alert.exists()).toBe(false);
+ });
+ });
+
+ describe('empty list', () => {
+ beforeEach(() => {
+ Api.fetchFeatureFlagUserList.mockResolvedValueOnce({ data: { ...userList, user_xids: '' } });
+ factory();
+
+ return wrapper.vm.$nextTick();
+ });
+
+ it('displays an empty state', () => {
+ expect(wrapper.find(GlEmptyState).exists()).toBe(true);
+ });
+ });
+});
diff --git a/spec/frontend/user_lists/store/edit/actions_spec.js b/spec/frontend/user_lists/store/edit/actions_spec.js
new file mode 100644
index 00000000000..7f0fb8e5401
--- /dev/null
+++ b/spec/frontend/user_lists/store/edit/actions_spec.js
@@ -0,0 +1,121 @@
+import testAction from 'helpers/vuex_action_helper';
+import Api from '~/api';
+import createState from '~/user_lists/store/edit/state';
+import * as types from '~/user_lists/store/edit/mutation_types';
+import * as actions from '~/user_lists/store/edit/actions';
+import { redirectTo } from '~/lib/utils/url_utility';
+import { userList } from '../../../feature_flags/mock_data';
+
+jest.mock('~/api');
+jest.mock('~/lib/utils/url_utility');
+
+describe('User Lists Edit Actions', () => {
+ let state;
+
+ beforeEach(() => {
+ state = createState({ projectId: '1', userListIid: '2' });
+ });
+
+ describe('fetchUserList', () => {
+ describe('success', () => {
+ beforeEach(() => {
+ Api.fetchFeatureFlagUserList.mockResolvedValue({ data: userList });
+ });
+
+ it('should commit RECEIVE_USER_LIST_SUCCESS', () => {
+ return testAction(
+ actions.fetchUserList,
+ undefined,
+ state,
+ [
+ { type: types.REQUEST_USER_LIST },
+ { type: types.RECEIVE_USER_LIST_SUCCESS, payload: userList },
+ ],
+ [],
+ () => expect(Api.fetchFeatureFlagUserList).toHaveBeenCalledWith('1', '2'),
+ );
+ });
+ });
+
+ describe('error', () => {
+ let error;
+ beforeEach(() => {
+ error = { response: { data: { message: ['error'] } } };
+ Api.fetchFeatureFlagUserList.mockRejectedValue(error);
+ });
+
+ it('should commit RECEIVE_USER_LIST_ERROR', () => {
+ return testAction(
+ actions.fetchUserList,
+ undefined,
+ state,
+ [
+ { type: types.REQUEST_USER_LIST },
+ { type: types.RECEIVE_USER_LIST_ERROR, payload: ['error'] },
+ ],
+ [],
+ () => expect(Api.fetchFeatureFlagUserList).toHaveBeenCalledWith('1', '2'),
+ );
+ });
+ });
+ });
+
+ describe('dismissErrorAlert', () => {
+ it('should commit DISMISS_ERROR_ALERT', () => {
+ return testAction(actions.dismissErrorAlert, undefined, state, [
+ { type: types.DISMISS_ERROR_ALERT },
+ ]);
+ });
+ });
+
+ describe('updateUserList', () => {
+ let updatedList;
+
+ beforeEach(() => {
+ updatedList = {
+ ...userList,
+ name: 'new',
+ };
+ });
+ describe('success', () => {
+ beforeEach(() => {
+ Api.updateFeatureFlagUserList.mockResolvedValue({ data: userList });
+ state.userList = userList;
+ });
+
+ it('should commit RECEIVE_USER_LIST_SUCCESS', () => {
+ return testAction(actions.updateUserList, updatedList, state, [], [], () => {
+ expect(Api.updateFeatureFlagUserList).toHaveBeenCalledWith('1', {
+ name: updatedList.name,
+ iid: updatedList.iid,
+ });
+ expect(redirectTo).toHaveBeenCalledWith(userList.path);
+ });
+ });
+ });
+
+ describe('error', () => {
+ let error;
+
+ beforeEach(() => {
+ error = { message: 'error' };
+ Api.updateFeatureFlagUserList.mockRejectedValue(error);
+ });
+
+ it('should commit RECEIVE_USER_LIST_ERROR', () => {
+ return testAction(
+ actions.updateUserList,
+ updatedList,
+ state,
+ [{ type: types.RECEIVE_USER_LIST_ERROR, payload: ['error'] }],
+ [],
+ () =>
+ expect(Api.updateFeatureFlagUserList).toHaveBeenCalledWith('1', {
+ name: updatedList.name,
+ iid: updatedList.iid,
+ }),
+ );
+ });
+ });
+ });
+});
diff --git a/spec/frontend/user_lists/store/edit/mutations_spec.js b/spec/frontend/user_lists/store/edit/mutations_spec.js
new file mode 100644
index 00000000000..3d4d2a59717
--- /dev/null
+++ b/spec/frontend/user_lists/store/edit/mutations_spec.js
@@ -0,0 +1,61 @@
+import statuses from '~/user_lists/constants/edit';
+import createState from '~/user_lists/store/edit/state';
+import * as types from '~/user_lists/store/edit/mutation_types';
+import mutations from '~/user_lists/store/edit/mutations';
+import { userList } from '../../../feature_flags/mock_data';
+
+describe('User List Edit Mutations', () => {
+ let state;
+
+ beforeEach(() => {
+ state = createState({ projectId: '1', userListIid: '2' });
+ });
+
+ describe(types.REQUEST_USER_LIST, () => {
+ beforeEach(() => {
+ mutations[types.REQUEST_USER_LIST](state);
+ });
+
+ it('sets the state to loading', () => {
+ expect(state.status).toBe(statuses.LOADING);
+ });
+ });
+
+ describe(types.RECEIVE_USER_LIST_SUCCESS, () => {
+ beforeEach(() => {
+ mutations[types.RECEIVE_USER_LIST_SUCCESS](state, userList);
+ });
+
+ it('sets the state to success', () => {
+ expect(state.status).toBe(statuses.SUCCESS);
+ });
+
+ it('sets the user list to the one received', () => {
+ expect(state.userList).toEqual(userList);
+ });
+ });
+
+ describe(types.RECIEVE_USER_LIST_ERROR, () => {
+ beforeEach(() => {
+ mutations[types.RECEIVE_USER_LIST_ERROR](state, ['network error']);
+ });
+
+ it('sets the state to error', () => {
+ expect(state.status).toBe(statuses.ERROR);
+ });
+
+ it('sets the error message to the recieved one', () => {
+ expect(state.errorMessage).toEqual(['network error']);
+ });
+ });
+
+ describe(types.DISMISS_ERROR_ALERT, () => {
+ beforeEach(() => {
+ mutations[types.DISMISS_ERROR_ALERT](state);
+ });
+
+ it('sets the state to error dismissed', () => {
+ expect(state.status).toBe(statuses.UNSYNCED);
+ });
+ });
+});
diff --git a/spec/frontend/user_lists/store/new/actions_spec.js b/spec/frontend/user_lists/store/new/actions_spec.js
new file mode 100644
index 00000000000..9cc6212a125
--- /dev/null
+++ b/spec/frontend/user_lists/store/new/actions_spec.js
@@ -0,0 +1,69 @@
+import testAction from 'helpers/vuex_action_helper';
+import Api from '~/api';
+import createState from '~/user_lists/store/new/state';
+import * as types from '~/user_lists/store/new/mutation_types';
+import * as actions from '~/user_lists/store/new/actions';
+import { redirectTo } from '~/lib/utils/url_utility';
+import { userList } from '../../../feature_flags/mock_data';
+
+jest.mock('~/api');
+jest.mock('~/lib/utils/url_utility');
+
+describe('User Lists Edit Actions', () => {
+ let state;
+
+ beforeEach(() => {
+ state = createState({ projectId: '1' });
+ });
+
+ describe('dismissErrorAlert', () => {
+ it('should commit DISMISS_ERROR_ALERT', () => {
+ return testAction(actions.dismissErrorAlert, undefined, state, [
+ { type: types.DISMISS_ERROR_ALERT },
+ ]);
+ });
+ });
+
+ describe('createUserList', () => {
+ let createdList;
+
+ beforeEach(() => {
+ createdList = {
+ ...userList,
+ name: 'new',
+ };
+ });
+ describe('success', () => {
+ beforeEach(() => {
+ Api.createFeatureFlagUserList.mockResolvedValue({ data: userList });
+ });
+
+ it('should redirect to the user list page', () => {
+ return testAction(actions.createUserList, createdList, state, [], [], () => {
+ expect(Api.createFeatureFlagUserList).toHaveBeenCalledWith('1', createdList);
+ expect(redirectTo).toHaveBeenCalledWith(userList.path);
+ });
+ });
+ });
+
+ describe('error', () => {
+ let error;
+
+ beforeEach(() => {
+ error = { message: 'error' };
+ Api.createFeatureFlagUserList.mockRejectedValue(error);
+ });
+
+ it('should commit RECEIVE_USER_LIST_ERROR', () => {
+ return testAction(
+ actions.createUserList,
+ createdList,
+ state,
+ [{ type: types.RECEIVE_CREATE_USER_LIST_ERROR, payload: ['error'] }],
+ [],
+ () => expect(Api.createFeatureFlagUserList).toHaveBeenCalledWith('1', createdList),
+ );
+ });
+ });
+ });
+});
diff --git a/spec/frontend/user_lists/store/new/mutations_spec.js b/spec/frontend/user_lists/store/new/mutations_spec.js
new file mode 100644
index 00000000000..89e8a83eb25
--- /dev/null
+++ b/spec/frontend/user_lists/store/new/mutations_spec.js
@@ -0,0 +1,38 @@
+import createState from '~/user_lists/store/new/state';
+import * as types from '~/user_lists/store/new/mutation_types';
+import mutations from '~/user_lists/store/new/mutations';
+
+describe('User List Edit Mutations', () => {
+ let state;
+
+ beforeEach(() => {
+ state = createState({ projectId: '1' });
+ });
+
+ describe(types.RECIEVE_USER_LIST_ERROR, () => {
+ beforeEach(() => {
+ mutations[types.RECEIVE_CREATE_USER_LIST_ERROR](state, ['network error']);
+ });
+
+ it('sets the error message to the recieved one', () => {
+ expect(state.errorMessage).toEqual(['network error']);
+ });
+
+ it('sets the error message to the recevied API message if present', () => {
+ const message = ['name is blank', 'name is too short'];
+
+ mutations[types.RECEIVE_CREATE_USER_LIST_ERROR](state, message);
+ expect(state.errorMessage).toEqual(message);
+ });
+ });
+
+ describe(types.DISMISS_ERROR_ALERT, () => {
+ beforeEach(() => {
+ mutations[types.DISMISS_ERROR_ALERT](state);
+ });
+
+ it('clears the error message', () => {
+ expect(state.errorMessage).toBe('');
+ });
+ });
+});
diff --git a/spec/frontend/user_lists/store/show/actions_spec.js b/spec/frontend/user_lists/store/show/actions_spec.js
new file mode 100644
index 00000000000..25a6b9ec0e4
--- /dev/null
+++ b/spec/frontend/user_lists/store/show/actions_spec.js
@@ -0,0 +1,117 @@
+import testAction from 'helpers/vuex_action_helper';
+import { userList } from 'jest/feature_flags/mock_data';
+import Api from '~/api';
+import { stringifyUserIds } from '~/user_lists/store/utils';
+import createState from '~/user_lists/store/show/state';
+import * as types from '~/user_lists/store/show/mutation_types';
+import * as actions from '~/user_lists/store/show/actions';
+
+jest.mock('~/api');
+
+describe('User Lists Show Actions', () => {
+ let mockState;
+
+ beforeEach(() => {
+ mockState = createState({ projectId: '1', userListIid: '2' });
+ });
+
+ describe('fetchUserList', () => {
+ it('commits REQUEST_USER_LIST and RECEIVE_USER_LIST_SUCCESS on success', () => {
+ Api.fetchFeatureFlagUserList.mockResolvedValue({ data: userList });
+ return testAction(
+ actions.fetchUserList,
+ undefined,
+ mockState,
+ [
+ { type: types.REQUEST_USER_LIST },
+ { type: types.RECEIVE_USER_LIST_SUCCESS, payload: userList },
+ ],
+ [],
+ () => expect(Api.fetchFeatureFlagUserList).toHaveBeenCalledWith('1', '2'),
+ );
+ });
+
+ it('commits REQUEST_USER_LIST and RECEIVE_USER_LIST_ERROR on error', () => {
+ Api.fetchFeatureFlagUserList.mockRejectedValue({ message: 'fail' });
+ return testAction(
+ actions.fetchUserList,
+ undefined,
+ mockState,
+ [{ type: types.REQUEST_USER_LIST }, { type: types.RECEIVE_USER_LIST_ERROR }],
+ [],
+ );
+ });
+ });
+
+ describe('dismissErrorAlert', () => {
+ it('commits DISMISS_ERROR_ALERT', () => {
+ return testAction(
+ actions.dismissErrorAlert,
+ undefined,
+ mockState,
+ [{ type: types.DISMISS_ERROR_ALERT }],
+ [],
+ );
+ });
+ });
+
+ describe('addUserIds', () => {
+ it('adds the given IDs and tries to update the user list', () => {
+ return testAction(
+ actions.addUserIds,
+ '1,2,3',
+ mockState,
+ [{ type: types.ADD_USER_IDS, payload: '1,2,3' }],
+ [{ type: 'updateUserList' }],
+ );
+ });
+ });
+
+ describe('removeUserId', () => {
+ it('removes the given ID and tries to update the user list', () => {
+ return testAction(
+ actions.removeUserId,
+ 'user3',
+ mockState,
+ [{ type: types.REMOVE_USER_ID, payload: 'user3' }],
+ [{ type: 'updateUserList' }],
+ );
+ });
+ });
+
+ describe('updateUserList', () => {
+ beforeEach(() => {
+ mockState.userList = userList;
+ mockState.userIds = ['user1', 'user2', 'user3'];
+ });
+
+ it('commits REQUEST_USER_LIST and RECEIVE_USER_LIST_SUCCESS on success', () => {
+ Api.updateFeatureFlagUserList.mockResolvedValue({ data: userList });
+ return testAction(
+ actions.updateUserList,
+ undefined,
+ mockState,
+ [
+ { type: types.REQUEST_USER_LIST },
+ { type: types.RECEIVE_USER_LIST_SUCCESS, payload: userList },
+ ],
+ [],
+ () =>
+ expect(Api.updateFeatureFlagUserList).toHaveBeenCalledWith('1', {
+ ...userList,
+ user_xids: stringifyUserIds(mockState.userIds),
+ }),
+ );
+ });
+ it('commits REQUEST_USER_LIST and RECEIVE_USER_LIST_ERROR on error', () => {
+ Api.updateFeatureFlagUserList.mockRejectedValue({ message: 'fail' });
+ return testAction(
+ actions.updateUserList,
+ undefined,
+ mockState,
+ [{ type: types.REQUEST_USER_LIST }, { type: types.RECEIVE_USER_LIST_ERROR }],
+ [],
+ );
+ });
+ });
+});
diff --git a/spec/frontend/user_lists/store/show/mutations_spec.js b/spec/frontend/user_lists/store/show/mutations_spec.js
new file mode 100644
index 00000000000..364cc6a0225
--- /dev/null
+++ b/spec/frontend/user_lists/store/show/mutations_spec.js
@@ -0,0 +1,86 @@
+import { uniq } from 'lodash';
+import { userList } from 'jest/feature_flags/mock_data';
+import createState from '~/user_lists/store/show/state';
+import mutations from '~/user_lists/store/show/mutations';
+import { states } from '~/user_lists/constants/show';
+import * as types from '~/user_lists/store/show/mutation_types';
+
+describe('User Lists Show Mutations', () => {
+ let mockState;
+
+ beforeEach(() => {
+ mockState = createState({ projectId: '1', userListIid: '2' });
+ });
+
+ describe(types.REQUEST_USER_LIST, () => {
+ it('puts us in the loading state', () => {
+ mutations[types.REQUEST_USER_LIST](mockState);
+
+ expect(mockState.state).toBe(states.LOADING);
+ });
+ });
+
+ describe(types.RECEIVE_USER_LIST_SUCCESS, () => {
+ beforeEach(() => {
+ mutations[types.RECEIVE_USER_LIST_SUCCESS](mockState, userList);
+ });
+
+ it('sets the state to LOADED', () => {
+ expect(mockState.state).toBe(states.SUCCESS);
+ });
+
+ it('sets the active user list', () => {
+ expect(mockState.userList).toEqual(userList);
+ });
+
+ it('splits the user IDs into an Array', () => {
+ expect(mockState.userIds).toEqual(userList.user_xids.split(','));
+ });
+
+ it('sets user IDs to an empty Array if an empty string is received', () => {
+ mutations[types.RECEIVE_USER_LIST_SUCCESS](mockState, { ...userList, user_xids: '' });
+ expect(mockState.userIds).toEqual([]);
+ });
+ });
+ describe(types.RECEIVE_USER_LIST_ERROR, () => {
+ it('sets the state to error', () => {
+ mutations[types.RECEIVE_USER_LIST_ERROR](mockState);
+ expect(mockState.state).toBe(states.ERROR);
+ });
+ });
+ describe(types.ADD_USER_IDS, () => {
+ const newIds = ['user3', 'test1', '1', '3', ''];
+
+ beforeEach(() => {
+ mutations[types.RECEIVE_USER_LIST_SUCCESS](mockState, userList);
+ mutations[types.ADD_USER_IDS](mockState, newIds.join(', '));
+ });
+
+ it('adds the new IDs to the state unless empty', () => {
+ newIds.filter(id => id).forEach(id => expect(mockState.userIds).toContain(id));
+ });
+
+ it('does not add duplicate IDs to the state', () => {
+ expect(mockState.userIds).toEqual(uniq(mockState.userIds));
+ });
+ });
+ describe(types.REMOVE_USER_ID, () => {
+ let userIds;
+ let removedId;
+
+ beforeEach(() => {
+ mutations[types.RECEIVE_USER_LIST_SUCCESS](mockState, userList);
+ userIds = mockState.userIds;
+ removedId = 'user3';
+ mutations[types.REMOVE_USER_ID](mockState, removedId);
+ });
+
+ it('should remove the given id', () => {
+ expect(mockState).not.toContain(removedId);
+ });
+
+ it('should leave the rest of the IDs alone', () => {
+ userIds.filter(id => id !== removedId).forEach(id => expect(mockState.userIds).toContain(id));
+ });
+ });
+});
diff --git a/spec/frontend/user_lists/store/utils_spec.js b/spec/frontend/user_lists/store/utils_spec.js
new file mode 100644
index 00000000000..9547b463eec
--- /dev/null
+++ b/spec/frontend/user_lists/store/utils_spec.js
@@ -0,0 +1,23 @@
+import { parseUserIds, stringifyUserIds } from '~/user_lists/store/utils';
+
+describe('User List Store Utils', () => {
+ describe('parseUserIds', () => {
+ it('should split comma-seperated user IDs into an array', () => {
+ expect(parseUserIds('1,2,3')).toEqual(['1', '2', '3']);
+ });
+
+ it('should filter whitespace before the comma', () => {
+ expect(parseUserIds('1\t,2 ,3')).toEqual(['1', '2', '3']);
+ });
+
+ it('should filter whitespace after the comma', () => {
+ expect(parseUserIds('1,\t2, 3')).toEqual(['1', '2', '3']);
+ });
+ });
+
+ describe('stringifyUserIds', () => {
+ it('should convert a list of user IDs into a comma-separated string', () => {
+ expect(stringifyUserIds(['1', '2', '3'])).toBe('1,2,3');
+ });
+ });
+});
diff --git a/spec/frontend/vue_mr_widget/components/mr_widget_author_time_spec.js b/spec/frontend/vue_mr_widget/components/mr_widget_author_time_spec.js
index 58ed92298bf..78efcb6e695 100644
--- a/spec/frontend/vue_mr_widget/components/mr_widget_author_time_spec.js
+++ b/spec/frontend/vue_mr_widget/components/mr_widget_author_time_spec.js
@@ -35,9 +35,7 @@ describe('MrWidgetAuthorTime', () => {
});
it('renders provided time', () => {
- expect(vm.$el.querySelector('time').getAttribute('data-original-title')).toEqual(
- '2017-03-23T23:02:00.807Z',
- );
+ expect(vm.$el.querySelector('time').getAttribute('title')).toEqual('2017-03-23T23:02:00.807Z');
expect(vm.$el.querySelector('time').textContent.trim()).toEqual('12 hours ago');
});
diff --git a/spec/frontend/vue_mr_widget/components/mr_widget_header_spec.js b/spec/frontend/vue_mr_widget/components/mr_widget_header_spec.js
index caea9a757ae..015f8bbac51 100644
--- a/spec/frontend/vue_mr_widget/components/mr_widget_header_spec.js
+++ b/spec/frontend/vue_mr_widget/components/mr_widget_header_spec.js
@@ -130,7 +130,7 @@ describe('MRWidgetHeader', () => {
});
it('renders clipboard button', () => {
- expect(vm.$el.querySelector('.btn-clipboard')).not.toEqual(null);
+ expect(vm.$el.querySelector('[data-testid="mr-widget-copy-clipboard"]')).not.toEqual(null);
});
it('renders target branch', () => {
diff --git a/spec/frontend/vue_mr_widget/components/mr_widget_rebase_spec.js b/spec/frontend/vue_mr_widget/components/mr_widget_rebase_spec.js
index 6ec30493f8b..9923434a7dd 100644
--- a/spec/frontend/vue_mr_widget/components/mr_widget_rebase_spec.js
+++ b/spec/frontend/vue_mr_widget/components/mr_widget_rebase_spec.js
@@ -6,6 +6,10 @@ import component from '~/vue_merge_request_widget/components/states/mr_widget_re
describe('Merge request widget rebase component', () => {
let Component;
let vm;
+
+ const findRebaseMessageEl = () => vm.$el.querySelector('[data-testid="rebase-message"]');
+ const findRebaseMessageElText = () => findRebaseMessageEl().textContent.trim();
+
beforeEach(() => {
Component = Vue.extend(component);
});
@@ -21,9 +25,7 @@ describe('Merge request widget rebase component', () => {
service: {},
});
- expect(
- vm.$el.querySelector('.rebase-state-find-class-convention span').textContent.trim(),
- ).toContain('Rebase in progress');
+ expect(findRebaseMessageElText()).toContain('Rebase in progress');
});
});
@@ -39,9 +41,7 @@ describe('Merge request widget rebase component', () => {
});
it('it should render rebase button and warning message', () => {
- const text = vm.$el
- .querySelector('.rebase-state-find-class-convention span')
- .textContent.trim();
+ const text = findRebaseMessageElText();
expect(text).toContain('Fast-forward merge is not possible.');
expect(text.replace(/\s\s+/g, ' ')).toContain(
@@ -53,9 +53,7 @@ describe('Merge request widget rebase component', () => {
vm.rebasingError = 'Something went wrong!';
Vue.nextTick(() => {
- expect(
- vm.$el.querySelector('.rebase-state-find-class-convention span').textContent.trim(),
- ).toContain('Something went wrong!');
+ expect(findRebaseMessageElText()).toContain('Something went wrong!');
done();
});
});
@@ -72,9 +70,7 @@ describe('Merge request widget rebase component', () => {
service: {},
});
- const text = vm.$el
- .querySelector('.rebase-state-find-class-convention span')
- .textContent.trim();
+ const text = findRebaseMessageElText();
expect(text).toContain('Fast-forward merge is not possible.');
expect(text).toContain('Rebase the source branch onto');
@@ -93,7 +89,7 @@ describe('Merge request widget rebase component', () => {
service: {},
});
- const elem = vm.$el.querySelector('.rebase-state-find-class-convention span');
+ const elem = findRebaseMessageEl();
expect(elem.innerHTML).toContain(
`Fast-forward merge is not possible. Rebase the source branch onto <span class="label-branch">${targetBranch}</span> to allow this merge request to be merged.`,
diff --git a/spec/frontend/vue_mr_widget/components/states/mr_widget_auto_merge_failed_spec.js b/spec/frontend/vue_mr_widget/components/states/mr_widget_auto_merge_failed_spec.js
index 98af44b0975..aae9b8660e2 100644
--- a/spec/frontend/vue_mr_widget/components/states/mr_widget_auto_merge_failed_spec.js
+++ b/spec/frontend/vue_mr_widget/components/states/mr_widget_auto_merge_failed_spec.js
@@ -1,12 +1,12 @@
import { shallowMount } from '@vue/test-utils';
-import { GlLoadingIcon } from '@gitlab/ui';
+import { GlLoadingIcon, GlButton } from '@gitlab/ui';
import AutoMergeFailedComponent from '~/vue_merge_request_widget/components/states/mr_widget_auto_merge_failed.vue';
import eventHub from '~/vue_merge_request_widget/event_hub';
describe('MRWidgetAutoMergeFailed', () => {
let wrapper;
const mergeError = 'This is the merge error';
- const findButton = () => wrapper.find('button');
+ const findButton = () => wrapper.find(GlButton);
const createComponent = (props = {}) => {
wrapper = shallowMount(AutoMergeFailedComponent, {
@@ -38,17 +38,13 @@ describe('MRWidgetAutoMergeFailed', () => {
it('emits event and shows loading icon when button is clicked', () => {
jest.spyOn(eventHub, '$emit');
- findButton().trigger('click');
+ findButton().vm.$emit('click');
expect(eventHub.$emit.mock.calls[0][0]).toBe('MRWidgetUpdateRequested');
return wrapper.vm.$nextTick(() => {
- expect(findButton().attributes('disabled')).toEqual('disabled');
- expect(
- findButton()
- .find(GlLoadingIcon)
- .exists(),
- ).toBe(true);
+ expect(findButton().attributes('disabled')).toBe('true');
+ expect(wrapper.find(GlLoadingIcon).exists()).toBe(true);
});
});
});
diff --git a/spec/frontend/vue_mr_widget/components/states/mr_widget_merged_spec.js b/spec/frontend/vue_mr_widget/components/states/mr_widget_merged_spec.js
index 1921599ae95..9b51e8583ba 100644
--- a/spec/frontend/vue_mr_widget/components/states/mr_widget_merged_spec.js
+++ b/spec/frontend/vue_mr_widget/components/states/mr_widget_merged_spec.js
@@ -212,8 +212,6 @@ describe('MRWidgetMerged', () => {
});
it('should use mergedEvent mergedAt as tooltip title', () => {
- expect(vm.$el.querySelector('time').getAttribute('data-original-title')).toBe(
- 'Jan 24, 2018 1:02pm GMT+0000',
- );
+ expect(vm.$el.querySelector('time').getAttribute('title')).toBe('Jan 24, 2018 1:02pm GMT+0000');
});
});
diff --git a/spec/frontend/vue_mr_widget/components/states/mr_widget_ready_to_merge_spec.js b/spec/frontend/vue_mr_widget/components/states/mr_widget_ready_to_merge_spec.js
index 5eb24315ca6..9057ffaea45 100644
--- a/spec/frontend/vue_mr_widget/components/states/mr_widget_ready_to_merge_spec.js
+++ b/spec/frontend/vue_mr_widget/components/states/mr_widget_ready_to_merge_spec.js
@@ -101,8 +101,6 @@ describe('ReadyToMerge', () => {
expect(vm.isMakingRequest).toBeFalsy();
expect(vm.isMergingImmediately).toBeFalsy();
expect(vm.commitMessage).toBe(vm.mr.commitMessage);
- expect(vm.successSvg).toBeDefined();
- expect(vm.warningSvg).toBeDefined();
});
});
@@ -494,19 +492,6 @@ describe('ReadyToMerge', () => {
});
});
- it('hides close button', done => {
- jest.spyOn(vm.service, 'poll').mockReturnValue(returnPromise('merged'));
- jest.spyOn(vm, 'initiateRemoveSourceBranchPolling').mockImplementation(() => {});
-
- vm.handleMergePolling(() => {}, () => {});
-
- setImmediate(() => {
- expect(document.querySelector('.btn-close').classList.contains('hidden')).toBeTruthy();
-
- done();
- });
- });
-
it('updates merge request count badge', done => {
jest.spyOn(vm.service, 'poll').mockReturnValue(returnPromise('merged'));
jest.spyOn(vm, 'initiateRemoveSourceBranchPolling').mockImplementation(() => {});
diff --git a/spec/frontend/vue_mr_widget/components/states/mr_widget_squash_before_merge_spec.js b/spec/frontend/vue_mr_widget/components/states/mr_widget_squash_before_merge_spec.js
index 4c213899dbd..5326d63cb8a 100644
--- a/spec/frontend/vue_mr_widget/components/states/mr_widget_squash_before_merge_spec.js
+++ b/spec/frontend/vue_mr_widget/components/states/mr_widget_squash_before_merge_spec.js
@@ -1,5 +1,6 @@
import { createLocalVue, shallowMount } from '@vue/test-utils';
import SquashBeforeMerge from '~/vue_merge_request_widget/components/states/squash_before_merge.vue';
+import { SQUASH_BEFORE_MERGE } from '~/vue_merge_request_widget/i18n';
const localVue = createLocalVue();
@@ -85,7 +86,7 @@ describe('Squash before merge component', () => {
});
describe('tooltip', () => {
- const tooltipTitle = () => findLabel().element.dataset.title;
+ const tooltipTitle = () => findLabel().attributes('title');
it('does not render when isDisabled is false', () => {
createComponent({
@@ -101,7 +102,7 @@ describe('Squash before merge component', () => {
isDisabled: true,
});
- expect(tooltipTitle()).toBe('Required in this project.');
+ expect(tooltipTitle()).toBe(SQUASH_BEFORE_MERGE.tooltipTitle);
});
});
diff --git a/spec/frontend/vue_mr_widget/deployment/deployment_actions_spec.js b/spec/frontend/vue_mr_widget/deployment/deployment_actions_spec.js
index 1711efb5512..13c0665f929 100644
--- a/spec/frontend/vue_mr_widget/deployment/deployment_actions_spec.js
+++ b/spec/frontend/vue_mr_widget/deployment/deployment_actions_spec.js
@@ -31,10 +31,7 @@ describe('DeploymentAction component', () => {
wrapper.destroy();
}
- wrapper = mount(DeploymentActions, {
- ...options,
- provide: { glFeatures: { deployFromFooter: true } },
- });
+ wrapper = mount(DeploymentActions, options);
};
const findStopButton = () => wrapper.find('.js-stop-env');
diff --git a/spec/frontend/vue_mr_widget/deployment/deployment_spec.js b/spec/frontend/vue_mr_widget/deployment/deployment_spec.js
index ce395de3b5d..17d7fcc4bff 100644
--- a/spec/frontend/vue_mr_widget/deployment/deployment_spec.js
+++ b/spec/frontend/vue_mr_widget/deployment/deployment_spec.js
@@ -19,10 +19,7 @@ describe('Deployment component', () => {
if (wrapper && wrapper.destroy) {
wrapper.destroy();
}
- wrapper = mount(DeploymentComponent, {
- ...options,
- provide: { glFeatures: { deployFromFooter: true } },
- });
+ wrapper = mount(DeploymentComponent, options);
};
beforeEach(() => {
diff --git a/spec/frontend/vue_mr_widget/mock_data.js b/spec/frontend/vue_mr_widget/mock_data.js
index 4688af30269..144283dc507 100644
--- a/spec/frontend/vue_mr_widget/mock_data.js
+++ b/spec/frontend/vue_mr_widget/mock_data.js
@@ -262,6 +262,7 @@ export default {
merge_trains_enabled: true,
merge_trains_count: 3,
merge_train_index: 1,
+ security_reports_docs_path: 'security-reports-docs-path',
};
export const mockStore = {
diff --git a/spec/frontend/vue_mr_widget/mr_widget_options_spec.js b/spec/frontend/vue_mr_widget/mr_widget_options_spec.js
index a2ade44b7c4..25c967996e3 100644
--- a/spec/frontend/vue_mr_widget/mr_widget_options_spec.js
+++ b/spec/frontend/vue_mr_widget/mr_widget_options_spec.js
@@ -1,6 +1,8 @@
import Vue from 'vue';
import MockAdapter from 'axios-mock-adapter';
import mountComponent from 'helpers/vue_mount_component_helper';
+import { withGonExperiment } from 'helpers/experimentation_helper';
+import Api from '~/api';
import axios from '~/lib/utils/axios_utils';
import mrWidgetOptions from '~/vue_merge_request_widget/mr_widget_options.vue';
import eventHub from '~/vue_merge_request_widget/event_hub';
@@ -50,13 +52,13 @@ describe('mrWidgetOptions', () => {
gon.features = {};
});
- const createComponent = () => {
+ const createComponent = (mrData = mockData) => {
if (vm) {
vm.$destroy();
}
vm = mountComponent(MrWidgetOptions, {
- mrData: { ...mockData },
+ mrData: { ...mrData },
});
return axios.waitForAll();
@@ -64,6 +66,7 @@ describe('mrWidgetOptions', () => {
const findSuggestPipeline = () => vm.$el.querySelector('[data-testid="mr-suggest-pipeline"]');
const findSuggestPipelineButton = () => findSuggestPipeline().querySelector('button');
+ const findSecurityMrWidget = () => vm.$el.querySelector('[data-testid="security-mr-widget"]');
describe('default', () => {
beforeEach(() => {
@@ -533,7 +536,7 @@ describe('mrWidgetOptions', () => {
const tooltip = vm.$el.querySelector('[data-testid="question-o-icon"]');
expect(vm.$el.textContent).toContain('Deletes source branch');
- expect(tooltip.getAttribute('data-original-title')).toBe(
+ expect(tooltip.getAttribute('title')).toBe(
'A user with write access to the source branch selected this option',
);
@@ -812,43 +815,96 @@ describe('mrWidgetOptions', () => {
});
});
- describe('given suggestPipeline feature flag is enabled', () => {
+ describe('security widget', () => {
+ describe.each`
+ context | hasPipeline | reportType | isFlagEnabled | shouldRender
+ ${'security report and flag enabled'} | ${true} | ${'sast'} | ${true} | ${true}
+ ${'security report and flag disabled'} | ${true} | ${'sast'} | ${false} | ${false}
+ ${'no security report and flag enabled'} | ${true} | ${'foo'} | ${true} | ${false}
+ ${'no pipeline and flag enabled'} | ${false} | ${'sast'} | ${true} | ${false}
+ `('given $context', ({ hasPipeline, reportType, isFlagEnabled, shouldRender }) => {
+ beforeEach(() => {
+ gon.features.coreSecurityMrWidget = isFlagEnabled;
+
+ if (hasPipeline) {
+ jest.spyOn(Api, 'pipelineJobs').mockResolvedValue({
+ data: [{ artifacts: [{ file_type: reportType }] }],
+ });
+ }
+
+ return createComponent({
+ ...mockData,
+ ...(hasPipeline ? {} : { pipeline: undefined }),
+ });
+ });
+
+ if (shouldRender) {
+ it('renders', () => {
+ expect(findSecurityMrWidget()).toEqual(expect.any(HTMLElement));
+ });
+ } else {
+ it('does not render', () => {
+ expect(findSecurityMrWidget()).toBeNull();
+ });
+ }
+ });
+ });
+
+ describe('suggestPipeline Experiment', () => {
beforeEach(() => {
mock.onAny().reply(200);
// This is needed because some grandchildren Bootstrap components throw warnings
// https://gitlab.com/gitlab-org/gitlab/issues/208458
jest.spyOn(console, 'warn').mockImplementation();
+ });
- gon.features = { suggestPipeline: true };
+ describe('given experiment is enabled', () => {
+ withGonExperiment('suggestPipeline');
- createComponent();
+ beforeEach(() => {
+ createComponent();
- vm.mr.hasCI = false;
- });
+ vm.mr.hasCI = false;
+ });
- it('should suggest pipelines when none exist', () => {
- expect(findSuggestPipeline()).toEqual(expect.any(Element));
- });
+ it('should suggest pipelines when none exist', () => {
+ expect(findSuggestPipeline()).toEqual(expect.any(Element));
+ });
- it.each([
- { isDismissedSuggestPipeline: true },
- { mergeRequestAddCiConfigPath: null },
- { hasCI: true },
- ])('with %s, should not suggest pipeline', async obj => {
- Object.assign(vm.mr, obj);
+ it.each([
+ { isDismissedSuggestPipeline: true },
+ { mergeRequestAddCiConfigPath: null },
+ { hasCI: true },
+ ])('with %s, should not suggest pipeline', async obj => {
+ Object.assign(vm.mr, obj);
- await vm.$nextTick();
+ await vm.$nextTick();
- expect(findSuggestPipeline()).toBeNull();
+ expect(findSuggestPipeline()).toBeNull();
+ });
+
+ it('should allow dismiss of the suggest pipeline message', async () => {
+ findSuggestPipelineButton().click();
+
+ await vm.$nextTick();
+
+ expect(findSuggestPipeline()).toBeNull();
+ });
});
- it('should allow dismiss of the suggest pipeline message', async () => {
- findSuggestPipelineButton().click();
+ describe('given suggestPipeline experiment is not enabled', () => {
+ withGonExperiment('suggestPipeline', false);
- await vm.$nextTick();
+ beforeEach(() => {
+ createComponent();
- expect(findSuggestPipeline()).toBeNull();
+ vm.mr.hasCI = false;
+ });
+
+ it('should not suggest pipelines when none exist', () => {
+ expect(findSuggestPipeline()).toBeNull();
+ });
});
});
});
diff --git a/spec/frontend/vue_mr_widget/stores/mr_widget_store_spec.js b/spec/frontend/vue_mr_widget/stores/mr_widget_store_spec.js
index b691a366a0f..f73f78d6f6e 100644
--- a/spec/frontend/vue_mr_widget/stores/mr_widget_store_spec.js
+++ b/spec/frontend/vue_mr_widget/stores/mr_widget_store_spec.js
@@ -118,27 +118,33 @@ describe('MergeRequestStore', () => {
describe('setPaths', () => {
it('should set the add ci config path', () => {
- store.setData({ ...mockData });
+ store.setPaths({ ...mockData });
expect(store.mergeRequestAddCiConfigPath).toBe('/group2/project2/new/pipeline');
});
it('should set humanAccess=Maintainer when user has that role', () => {
- store.setData({ ...mockData });
+ store.setPaths({ ...mockData });
expect(store.humanAccess).toBe('Maintainer');
});
it('should set pipelinesEmptySvgPath', () => {
- store.setData({ ...mockData });
+ store.setPaths({ ...mockData });
expect(store.pipelinesEmptySvgPath).toBe('/path/to/svg');
});
it('should set newPipelinePath', () => {
- store.setData({ ...mockData });
+ store.setPaths({ ...mockData });
expect(store.newPipelinePath).toBe('/group2/project2/pipelines/new');
});
+
+ it('should set securityReportsDocsPath', () => {
+ store.setPaths({ ...mockData });
+
+ expect(store.securityReportsDocsPath).toBe('security-reports-docs-path');
+ });
});
});
diff --git a/spec/frontend/vue_shared/components/__snapshots__/awards_list_spec.js.snap b/spec/frontend/vue_shared/components/__snapshots__/awards_list_spec.js.snap
index 19671d425a9..82503e5a025 100644
--- a/spec/frontend/vue_shared/components/__snapshots__/awards_list_spec.js.snap
+++ b/spec/frontend/vue_shared/components/__snapshots__/awards_list_spec.js.snap
@@ -228,9 +228,11 @@ exports[`vue_shared/components/awards_list default matches snapshot 1`] = `
/>
</span>
- <i
- aria-hidden="true"
- class="fa fa-spinner fa-spin award-control-icon award-control-icon-loading"
+ <gl-loading-icon-stub
+ class="award-control-icon-loading"
+ color="dark"
+ label="Loading"
+ size="md"
/>
</button>
</div>
diff --git a/spec/frontend/vue_shared/components/__snapshots__/clone_dropdown_spec.js.snap b/spec/frontend/vue_shared/components/__snapshots__/clone_dropdown_spec.js.snap
index dfd114a2d1c..ec4a81054db 100644
--- a/spec/frontend/vue_shared/components/__snapshots__/clone_dropdown_spec.js.snap
+++ b/spec/frontend/vue_shared/components/__snapshots__/clone_dropdown_spec.js.snap
@@ -39,6 +39,7 @@ exports[`Clone Dropdown Button rendering matches the snapshot 1`] = `
tag="div"
>
<gl-button-stub
+ buttontextclasses=""
category="primary"
class="d-inline-flex"
data-clipboard-text="ssh://foo.bar"
@@ -80,6 +81,7 @@ exports[`Clone Dropdown Button rendering matches the snapshot 1`] = `
tag="div"
>
<gl-button-stub
+ buttontextclasses=""
category="primary"
class="d-inline-flex"
data-clipboard-text="http://foo.bar"
diff --git a/spec/frontend/vue_shared/components/__snapshots__/editor_lite_spec.js.snap b/spec/frontend/vue_shared/components/__snapshots__/editor_lite_spec.js.snap
new file mode 100644
index 00000000000..26785855369
--- /dev/null
+++ b/spec/frontend/vue_shared/components/__snapshots__/editor_lite_spec.js.snap
@@ -0,0 +1,14 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Editor Lite component rendering matches the snapshot 1`] = `
+<div
+ data-editor-loading=""
+ id="editor-lite-snippet_777"
+>
+ <pre
+ class="editor-loading-content"
+ >
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit.
+ </pre>
+</div>
+`;
diff --git a/spec/frontend/vue_shared/components/__snapshots__/expand_button_spec.js.snap b/spec/frontend/vue_shared/components/__snapshots__/expand_button_spec.js.snap
index c2b97f1e7f9..19a649089e0 100644
--- a/spec/frontend/vue_shared/components/__snapshots__/expand_button_spec.js.snap
+++ b/spec/frontend/vue_shared/components/__snapshots__/expand_button_spec.js.snap
@@ -11,7 +11,7 @@ exports[`Expand button on click when short text is provided renders button after
<!---->
<svg
- class="gl-icon s16"
+ class="gl-button-icon gl-icon s16"
data-testid="ellipsis_h-icon"
>
<use
@@ -39,7 +39,7 @@ exports[`Expand button on click when short text is provided renders button after
<!---->
<svg
- class="gl-icon s16"
+ class="gl-button-icon gl-icon s16"
data-testid="ellipsis_h-icon"
>
<use
@@ -62,7 +62,7 @@ exports[`Expand button when short text is provided renders button before text 1`
<!---->
<svg
- class="gl-icon s16"
+ class="gl-button-icon gl-icon s16"
data-testid="ellipsis_h-icon"
>
<use
@@ -90,7 +90,7 @@ exports[`Expand button when short text is provided renders button before text 1`
<!---->
<svg
- class="gl-icon s16"
+ class="gl-button-icon gl-icon s16"
data-testid="ellipsis_h-icon"
>
<use
diff --git a/spec/frontend/vue_shared/components/__snapshots__/split_button_spec.js.snap b/spec/frontend/vue_shared/components/__snapshots__/split_button_spec.js.snap
index fcb9c4b8b02..8eb0e8f9550 100644
--- a/spec/frontend/vue_shared/components/__snapshots__/split_button_spec.js.snap
+++ b/spec/frontend/vue_shared/components/__snapshots__/split_button_spec.js.snap
@@ -1,15 +1,23 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`SplitButton renders actionItems 1`] = `
-<gl-deprecated-dropdown-stub
- menu-class="dropdown-menu-selectable "
+<gl-dropdown-stub
+ category="tertiary"
+ headertext=""
+ menu-class=""
+ size="medium"
split="true"
text="professor"
- variant="secondary"
+ variant="default"
>
- <gl-deprecated-dropdown-item-stub
- active="true"
- active-class="is-active"
+ <gl-dropdown-item-stub
+ avatarurl=""
+ iconcolor=""
+ iconname=""
+ iconrightname=""
+ ischecked="true"
+ ischeckitem="true"
+ secondarytext=""
>
<strong>
professor
@@ -18,11 +26,16 @@ exports[`SplitButton renders actionItems 1`] = `
<div>
very symphonic
</div>
- </gl-deprecated-dropdown-item-stub>
+ </gl-dropdown-item-stub>
- <gl-deprecated-dropdown-divider-stub />
- <gl-deprecated-dropdown-item-stub
- active-class="is-active"
+ <gl-dropdown-divider-stub />
+ <gl-dropdown-item-stub
+ avatarurl=""
+ iconcolor=""
+ iconname=""
+ iconrightname=""
+ ischeckitem="true"
+ secondarytext=""
>
<strong>
captain
@@ -31,8 +44,8 @@ exports[`SplitButton renders actionItems 1`] = `
<div>
warp drive
</div>
- </gl-deprecated-dropdown-item-stub>
+ </gl-dropdown-item-stub>
<!---->
-</gl-deprecated-dropdown-stub>
+</gl-dropdown-stub>
`;
diff --git a/spec/frontend/vue_shared/components/actions_button_spec.js b/spec/frontend/vue_shared/components/actions_button_spec.js
index 4dde9d726d1..6e7ed9d612b 100644
--- a/spec/frontend/vue_shared/components/actions_button_spec.js
+++ b/spec/frontend/vue_shared/components/actions_button_spec.js
@@ -1,5 +1,5 @@
import { shallowMount } from '@vue/test-utils';
-import { GlDropdown, GlLink } from '@gitlab/ui';
+import { GlDropdown, GlButton } from '@gitlab/ui';
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
import ActionsButton from '~/vue_shared/components/actions_button.vue';
@@ -9,7 +9,12 @@ const TEST_ACTION = {
secondaryText: 'Lorem ipsum.',
tooltip: '',
href: '/sample',
- attrs: { 'data-test': '123' },
+ attrs: {
+ 'data-test': '123',
+ category: 'secondary',
+ href: '/sample',
+ variant: 'default',
+ },
};
const TEST_ACTION_2 = {
key: 'action2',
@@ -40,8 +45,8 @@ describe('Actions button component', () => {
return directiveBinding.value;
};
- const findLink = () => wrapper.find(GlLink);
- const findLinkTooltip = () => getTooltip(findLink());
+ const findButton = () => wrapper.find(GlButton);
+ const findButtonTooltip = () => getTooltip(findButton());
const findDropdown = () => wrapper.find(GlDropdown);
const findDropdownTooltip = () => getTooltip(findDropdown());
const parseDropdownItems = () =>
@@ -63,7 +68,7 @@ describe('Actions button component', () => {
};
});
const clickOn = (child, evt = new Event('click')) => child.vm.$emit('click', evt);
- const clickLink = (...args) => clickOn(findLink(), ...args);
+ const clickLink = (...args) => clickOn(findButton(), ...args);
const clickDropdown = (...args) => clickOn(findDropdown(), ...args);
describe('with 1 action', () => {
@@ -76,22 +81,19 @@ describe('Actions button component', () => {
});
it('should render single button', () => {
- const link = findLink();
-
- expect(link.attributes()).toEqual({
- class: expect.any(String),
+ expect(findButton().attributes()).toMatchObject({
href: TEST_ACTION.href,
...TEST_ACTION.attrs,
});
- expect(link.text()).toBe(TEST_ACTION.text);
+ expect(findButton().text()).toBe(TEST_ACTION.text);
});
it('should have tooltip', () => {
- expect(findLinkTooltip()).toBe(TEST_ACTION.tooltip);
+ expect(findButtonTooltip()).toBe(TEST_ACTION.tooltip);
});
it('should have attrs', () => {
- expect(findLink().attributes()).toMatchObject(TEST_ACTION.attrs);
+ expect(findButton().attributes()).toMatchObject(TEST_ACTION.attrs);
});
it('can click', () => {
@@ -103,7 +105,7 @@ describe('Actions button component', () => {
it('should have tooltip', () => {
createComponent({ actions: [{ ...TEST_ACTION, tooltip: TEST_TOOLTIP }] });
- expect(findLinkTooltip()).toBe(TEST_TOOLTIP);
+ expect(findButtonTooltip()).toBe(TEST_TOOLTIP);
});
});
diff --git a/spec/frontend/vue_shared/components/alert_detail_table_spec.js b/spec/frontend/vue_shared/components/alert_detail_table_spec.js
deleted file mode 100644
index 9c38ccad8a7..00000000000
--- a/spec/frontend/vue_shared/components/alert_detail_table_spec.js
+++ /dev/null
@@ -1,74 +0,0 @@
-import { mount } from '@vue/test-utils';
-import { GlTable, GlLoadingIcon } from '@gitlab/ui';
-import AlertDetailsTable from '~/vue_shared/components/alert_details_table.vue';
-
-const mockAlert = {
- iid: '1527542',
- title: 'SyntaxError: Invalid or unexpected token',
- severity: 'CRITICAL',
- eventCount: 7,
- createdAt: '2020-04-17T23:18:14.996Z',
- startedAt: '2020-04-17T23:18:14.996Z',
- endedAt: '2020-04-17T23:18:14.996Z',
- status: 'TRIGGERED',
- assignees: { nodes: [] },
- notes: { nodes: [] },
- todos: { nodes: [] },
-};
-
-describe('AlertDetails', () => {
- let wrapper;
-
- function mountComponent(propsData = {}) {
- wrapper = mount(AlertDetailsTable, {
- propsData: {
- alert: mockAlert,
- loading: false,
- ...propsData,
- },
- });
- }
-
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
- const findTableComponent = () => wrapper.find(GlTable);
-
- describe('Alert details', () => {
- describe('empty state', () => {
- beforeEach(() => {
- mountComponent({ alert: null });
- });
-
- it('shows an empty state when no alert is provided', () => {
- expect(wrapper.text()).toContain('No alert data to display.');
- });
- });
-
- describe('loading state', () => {
- beforeEach(() => {
- mountComponent({ loading: true });
- });
-
- it('displays a loading state when loading', () => {
- expect(wrapper.find(GlLoadingIcon).exists()).toBe(true);
- });
- });
-
- describe('with table data', () => {
- beforeEach(() => {
- mountComponent();
- });
-
- it('renders a table', () => {
- expect(findTableComponent().exists()).toBe(true);
- });
-
- it('renders a cell based on alert data', () => {
- expect(findTableComponent().text()).toContain('SyntaxError: Invalid or unexpected token');
- });
- });
- });
-});
diff --git a/spec/frontend/vue_shared/components/alert_details_table_spec.js b/spec/frontend/vue_shared/components/alert_details_table_spec.js
new file mode 100644
index 00000000000..dff307e92c2
--- /dev/null
+++ b/spec/frontend/vue_shared/components/alert_details_table_spec.js
@@ -0,0 +1,139 @@
+import { GlLoadingIcon, GlTable } from '@gitlab/ui';
+import { mount } from '@vue/test-utils';
+import AlertDetailsTable from '~/vue_shared/components/alert_details_table.vue';
+
+const mockAlert = {
+ iid: '1527542',
+ title: 'SyntaxError: Invalid or unexpected token',
+ severity: 'CRITICAL',
+ eventCount: 7,
+ createdAt: '2020-04-17T23:18:14.996Z',
+ startedAt: '2020-04-17T23:18:14.996Z',
+ endedAt: '2020-04-17T23:18:14.996Z',
+ status: 'TRIGGERED',
+ assignees: { nodes: [] },
+ notes: { nodes: [] },
+ todos: { nodes: [] },
+ hosts: ['host1', 'host2'],
+ __typename: 'AlertManagementAlert',
+};
+
+const environmentName = 'Production';
+const environmentPath = '/fake/path';
+
+describe('AlertDetails', () => {
+ let environmentData = { name: environmentName, path: environmentPath };
+ let glFeatures = { exposeEnvironmentPathInAlertDetails: false };
+ let wrapper;
+
+ function mountComponent(propsData = {}) {
+ wrapper = mount(AlertDetailsTable, {
+ provide: {
+ glFeatures,
+ },
+ propsData: {
+ alert: {
+ ...mockAlert,
+ environment: environmentData,
+ },
+ loading: false,
+ ...propsData,
+ },
+ });
+ }
+
+ afterEach(() => {
+ wrapper.destroy();
+ wrapper = null;
+ });
+
+ const findTableComponent = () => wrapper.find(GlTable);
+ const findTableKeys = () => findTableComponent().findAll('tbody td:first-child');
+ const findTableFieldValueByKey = fieldKey =>
+ findTableComponent()
+ .findAll('tbody tr')
+ .filter(row => row.text().includes(fieldKey))
+ .at(0)
+ .find('td:nth-child(2)');
+ const findTableField = (fields, fieldName) => fields.filter(row => row.text() === fieldName);
+
+ describe('Alert details', () => {
+ describe('empty state', () => {
+ beforeEach(() => {
+ mountComponent({ alert: null });
+ });
+
+ it('shows an empty state when no alert is provided', () => {
+ expect(wrapper.text()).toContain('No alert data to display.');
+ });
+ });
+
+ describe('loading state', () => {
+ beforeEach(() => {
+ mountComponent({ loading: true });
+ });
+
+ it('displays a loading state when loading', () => {
+ expect(wrapper.find(GlLoadingIcon).exists()).toBe(true);
+ });
+ });
+
+ describe('with table data', () => {
+ beforeEach(mountComponent);
+
+ it('renders a table', () => {
+ expect(findTableComponent().exists()).toBe(true);
+ });
+
+ it('renders a cell based on alert data', () => {
+ expect(findTableComponent().text()).toContain('SyntaxError: Invalid or unexpected token');
+ });
+
+ it('should show allowed alert fields', () => {
+ const fields = findTableKeys();
+
+ expect(findTableField(fields, 'Iid').exists()).toBe(true);
+ expect(findTableField(fields, 'Title').exists()).toBe(true);
+ expect(findTableField(fields, 'Severity').exists()).toBe(true);
+ expect(findTableField(fields, 'Status').exists()).toBe(true);
+ expect(findTableField(fields, 'Hosts').exists()).toBe(true);
+ expect(findTableField(fields, 'Environment').exists()).toBe(false);
+ });
+
+ it('should not show disallowed and flaggedAllowed alert fields', () => {
+ const fields = findTableKeys();
+
+ expect(findTableField(fields, 'Typename').exists()).toBe(false);
+ expect(findTableField(fields, 'Todos').exists()).toBe(false);
+ expect(findTableField(fields, 'Notes').exists()).toBe(false);
+ expect(findTableField(fields, 'Assignees').exists()).toBe(false);
+ expect(findTableField(fields, 'Environment').exists()).toBe(false);
+ });
+ });
+
+ describe('when exposeEnvironmentPathInAlertDetails is enabled', () => {
+ beforeEach(() => {
+ glFeatures = { exposeEnvironmentPathInAlertDetails: true };
+ mountComponent();
+ });
+
+ it('should show flaggedAllowed alert fields', () => {
+ const fields = findTableKeys();
+
+ expect(findTableField(fields, 'Environment').exists()).toBe(true);
+ });
+
+ it('should display only the name for the environment', () => {
+ expect(findTableFieldValueByKey('Iid').text()).toBe('1527542');
+ expect(findTableFieldValueByKey('Environment').text()).toBe(environmentName);
+ });
+
+ it('should not display the environment row if there is not data', () => {
+ environmentData = { name: null, path: null };
+ mountComponent();
+
+ expect(findTableFieldValueByKey('Environment').text()).toBeFalsy();
+ });
+ });
+ });
+});
diff --git a/spec/frontend/vue_shared/components/clipboard_button_spec.js b/spec/frontend/vue_shared/components/clipboard_button_spec.js
index 7f0b7ba8cf8..51a2653befc 100644
--- a/spec/frontend/vue_shared/components/clipboard_button_spec.js
+++ b/spec/frontend/vue_shared/components/clipboard_button_spec.js
@@ -1,5 +1,5 @@
import { shallowMount } from '@vue/test-utils';
-import { GlDeprecatedButton, GlIcon } from '@gitlab/ui';
+import { GlButton } from '@gitlab/ui';
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
describe('clipboard button', () => {
@@ -26,9 +26,8 @@ describe('clipboard button', () => {
});
it('renders a button for clipboard', () => {
- expect(wrapper.find(GlDeprecatedButton).exists()).toBe(true);
+ expect(wrapper.find(GlButton).exists()).toBe(true);
expect(wrapper.attributes('data-clipboard-text')).toBe('copy me');
- expect(wrapper.find(GlIcon).props('name')).toBe('copy-to-clipboard');
});
it('should have a tooltip with default values', () => {
diff --git a/spec/frontend/vue_shared/components/confirm_modal_spec.js b/spec/frontend/vue_shared/components/confirm_modal_spec.js
index 5d92af64de0..8456ca9d125 100644
--- a/spec/frontend/vue_shared/components/confirm_modal_spec.js
+++ b/spec/frontend/vue_shared/components/confirm_modal_spec.js
@@ -86,6 +86,22 @@ describe('vue_shared/components/confirm_modal', () => {
expect(findForm().element.submit).not.toHaveBeenCalled();
});
+ describe('with handleSubmit prop', () => {
+ const handleSubmit = jest.fn();
+ beforeEach(() => {
+ createComponent({ handleSubmit });
+ findModal().vm.$emit('primary');
+ });
+
+ it('will call handleSubmit', () => {
+ expect(handleSubmit).toHaveBeenCalled();
+ });
+
+ it('does not submit the form', () => {
+ expect(findForm().element.submit).not.toHaveBeenCalled();
+ });
+ });
+
describe('when modal submitted', () => {
beforeEach(() => {
findModal().vm.$emit('primary');
diff --git a/spec/frontend/vue_shared/components/deprecated_modal_2_spec.js b/spec/frontend/vue_shared/components/deprecated_modal_2_spec.js
index b201a9acdd4..c37a44df6f8 100644
--- a/spec/frontend/vue_shared/components/deprecated_modal_2_spec.js
+++ b/spec/frontend/vue_shared/components/deprecated_modal_2_spec.js
@@ -78,7 +78,7 @@ describe('DeprecatedModal2', () => {
});
it('sets the primary button text', () => {
- const primaryButton = vm.$el.querySelector('.modal-footer button:last-of-type');
+ const primaryButton = vm.$el.querySelector('.js-modal-primary-action .gl-button-text');
expect(primaryButton.innerHTML.trim()).toBe(props.footerPrimaryButtonText);
});
diff --git a/spec/frontend/vue_shared/components/dropdown/dropdown_search_input_spec.js b/spec/frontend/vue_shared/components/dropdown/dropdown_search_input_spec.js
index efa30bf6605..ec553c52236 100644
--- a/spec/frontend/vue_shared/components/dropdown/dropdown_search_input_spec.js
+++ b/spec/frontend/vue_shared/components/dropdown/dropdown_search_input_spec.js
@@ -29,7 +29,7 @@ describe('DropdownSearchInputComponent', () => {
});
it('renders search icon element', () => {
- expect(wrapper.find('.fa-search.dropdown-input-search').exists()).toBe(true);
+ expect(wrapper.find('.dropdown-input-search[data-testid="search-icon"]').exists()).toBe(true);
});
it('displays custom placeholder text', () => {
diff --git a/spec/frontend/vue_shared/components/editor_lite_spec.js b/spec/frontend/vue_shared/components/editor_lite_spec.js
new file mode 100644
index 00000000000..52502fcf64f
--- /dev/null
+++ b/spec/frontend/vue_shared/components/editor_lite_spec.js
@@ -0,0 +1,144 @@
+import { shallowMount } from '@vue/test-utils';
+import { nextTick } from 'vue';
+import EditorLite from '~/vue_shared/components/editor_lite.vue';
+import Editor from '~/editor/editor_lite';
+
+jest.mock('~/editor/editor_lite');
+
+describe('Editor Lite component', () => {
+ let wrapper;
+ const onDidChangeModelContent = jest.fn();
+ const updateModelLanguage = jest.fn();
+ const getValue = jest.fn();
+ const setValue = jest.fn();
+ const value = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.';
+ const fileName = 'lorem.txt';
+ const fileGlobalId = 'snippet_777';
+ const createInstanceMock = jest.fn().mockImplementation(() => ({
+ onDidChangeModelContent,
+ updateModelLanguage,
+ getValue,
+ setValue,
+ dispose: jest.fn(),
+ }));
+ Editor.mockImplementation(() => {
+ return {
+ createInstance: createInstanceMock,
+ };
+ });
+ function createComponent(props = {}) {
+ wrapper = shallowMount(EditorLite, {
+ propsData: {
+ value,
+ fileName,
+ fileGlobalId,
+ ...props,
+ },
+ });
+ }
+
+ beforeEach(() => {
+ 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('[id^="editor-lite-"]').exists()).toBe(true);
+ });
+
+ it('initialises Editor Lite instance', () => {
+ const el = wrapper.find({ ref: 'editor' }).element;
+ expect(createInstanceMock).toHaveBeenCalledWith({
+ el,
+ blobPath: fileName,
+ blobGlobalId: fileGlobalId,
+ blobContent: value,
+ extensions: null,
+ });
+ });
+
+ 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]]);
+ });
+
+ it('emits editor-ready event when the Editor Lite is ready', async () => {
+ const el = wrapper.find({ ref: 'editor' }).element;
+ expect(wrapper.emitted()['editor-ready']).toBeUndefined();
+
+ await el.dispatchEvent(new Event('editor-ready'));
+
+ expect(wrapper.emitted()['editor-ready']).toBeDefined();
+ });
+
+ describe('reaction to the value update', () => {
+ it('reacts to the changes in the passed value', async () => {
+ const newValue = 'New Value';
+
+ wrapper.setProps({
+ value: newValue,
+ });
+
+ await nextTick();
+ expect(setValue).toHaveBeenCalledWith(newValue);
+ });
+
+ it("does not update value if the passed one is exactly the same as the editor's content", async () => {
+ const newValue = `${value}`; // to make sure we're creating a new String with the same content and not just a reference
+
+ wrapper.setProps({
+ value: newValue,
+ });
+
+ await nextTick();
+ expect(setValue).not.toHaveBeenCalled();
+ });
+ });
+ });
+});
diff --git a/spec/frontend/vue_shared/components/filtered_search_bar/store/modules/filters/actions_spec.js b/spec/frontend/vue_shared/components/filtered_search_bar/store/modules/filters/actions_spec.js
new file mode 100644
index 00000000000..1dd5f08e76a
--- /dev/null
+++ b/spec/frontend/vue_shared/components/filtered_search_bar/store/modules/filters/actions_spec.js
@@ -0,0 +1,448 @@
+import axios from 'axios';
+import MockAdapter from 'axios-mock-adapter';
+import testAction from 'helpers/vuex_action_helper';
+import { mockBranches } from 'jest/vue_shared/components/filtered_search_bar/mock_data';
+import * as actions from '~/vue_shared/components/filtered_search_bar/store/modules/filters/actions';
+import * as types from '~/vue_shared/components/filtered_search_bar/store/modules/filters/mutation_types';
+import initialState from '~/vue_shared/components/filtered_search_bar/store/modules/filters/state';
+import httpStatusCodes from '~/lib/utils/http_status';
+import { deprecatedCreateFlash as createFlash } from '~/flash';
+import Api from '~/api';
+import { filterMilestones, filterUsers, filterLabels } from './mock_data';
+
+const milestonesEndpoint = 'fake_milestones_endpoint';
+const labelsEndpoint = 'fake_labels_endpoint';
+const groupEndpoint = 'fake_group_endpoint';
+const projectEndpoint = 'fake_project_endpoint';
+
+jest.mock('~/flash');
+
+describe('Filters actions', () => {
+ let state;
+ let mock;
+ let mockDispatch;
+ let mockCommit;
+
+ beforeEach(() => {
+ state = initialState();
+ mock = new MockAdapter(axios);
+
+ mockDispatch = jest.fn().mockResolvedValue();
+ mockCommit = jest.fn();
+ });
+
+ afterEach(() => {
+ mock.restore();
+ });
+
+ describe('initialize', () => {
+ const initialData = {
+ milestonesEndpoint,
+ labelsEndpoint,
+ groupEndpoint,
+ projectEndpoint,
+ selectedAuthor: 'Mr cool',
+ selectedMilestone: 'NEXT',
+ };
+
+ it('does not dispatch', () => {
+ const result = actions.initialize(
+ {
+ state,
+ dispatch: mockDispatch,
+ commit: mockCommit,
+ },
+ initialData,
+ );
+ expect(result).toBeUndefined();
+ expect(mockDispatch).not.toHaveBeenCalled();
+ });
+
+ it(`commits the ${types.SET_SELECTED_FILTERS}`, () => {
+ actions.initialize(
+ {
+ state,
+ dispatch: mockDispatch,
+ commit: mockCommit,
+ },
+ initialData,
+ );
+ expect(mockCommit).toHaveBeenCalledWith(types.SET_SELECTED_FILTERS, initialData);
+ });
+ });
+
+ describe('setFilters', () => {
+ const nextFilters = {
+ selectedAuthor: 'Mr cool',
+ selectedMilestone: 'NEXT',
+ };
+
+ it('dispatches the root/setFilters action', () => {
+ return testAction(
+ actions.setFilters,
+ nextFilters,
+ state,
+ [
+ {
+ payload: nextFilters,
+ type: types.SET_SELECTED_FILTERS,
+ },
+ ],
+ [
+ {
+ type: 'setFilters',
+ payload: nextFilters,
+ },
+ ],
+ );
+ });
+ });
+
+ describe('setEndpoints', () => {
+ it('sets the api paths', () => {
+ return testAction(
+ actions.setEndpoints,
+ { milestonesEndpoint, labelsEndpoint, groupEndpoint, projectEndpoint },
+ state,
+ [
+ { payload: 'fake_milestones_endpoint', type: types.SET_MILESTONES_ENDPOINT },
+ { payload: 'fake_labels_endpoint', type: types.SET_LABELS_ENDPOINT },
+ { payload: 'fake_group_endpoint', type: types.SET_GROUP_ENDPOINT },
+ { payload: 'fake_project_endpoint', type: types.SET_PROJECT_ENDPOINT },
+ ],
+ [],
+ );
+ });
+ });
+
+ describe('fetchBranches', () => {
+ describe('success', () => {
+ beforeEach(() => {
+ const url = Api.buildUrl(Api.createBranchPath).replace(
+ ':id',
+ encodeURIComponent(projectEndpoint),
+ );
+ mock.onGet(url).replyOnce(httpStatusCodes.OK, mockBranches);
+ });
+
+ it('dispatches RECEIVE_BRANCHES_SUCCESS with received data', () => {
+ return testAction(
+ actions.fetchBranches,
+ null,
+ { ...state, projectEndpoint },
+ [
+ { type: types.REQUEST_BRANCHES },
+ { type: types.RECEIVE_BRANCHES_SUCCESS, payload: mockBranches },
+ ],
+ [],
+ ).then(({ data }) => {
+ expect(data).toBe(mockBranches);
+ });
+ });
+ });
+
+ describe('error', () => {
+ beforeEach(() => {
+ mock.onAny().replyOnce(httpStatusCodes.SERVICE_UNAVAILABLE);
+ });
+
+ it('dispatches RECEIVE_BRANCHES_ERROR', () => {
+ return testAction(
+ actions.fetchBranches,
+ null,
+ state,
+ [
+ { type: types.REQUEST_BRANCHES },
+ {
+ type: types.RECEIVE_BRANCHES_ERROR,
+ payload: httpStatusCodes.SERVICE_UNAVAILABLE,
+ },
+ ],
+ [],
+ ).then(() => expect(createFlash).toHaveBeenCalled());
+ });
+ });
+ });
+
+ describe('fetchAuthors', () => {
+ let restoreVersion;
+ beforeEach(() => {
+ restoreVersion = gon.api_version;
+ gon.api_version = 'v1';
+ });
+
+ afterEach(() => {
+ gon.api_version = restoreVersion;
+ });
+
+ describe('success', () => {
+ beforeEach(() => {
+ mock.onAny().replyOnce(httpStatusCodes.OK, filterUsers);
+ });
+
+ it('dispatches RECEIVE_AUTHORS_SUCCESS with received data and groupEndpoint set', () => {
+ return testAction(
+ actions.fetchAuthors,
+ null,
+ { ...state, groupEndpoint },
+ [
+ { type: types.REQUEST_AUTHORS },
+ { type: types.RECEIVE_AUTHORS_SUCCESS, payload: filterUsers },
+ ],
+ [],
+ ).then(({ data }) => {
+ expect(mock.history.get[0].url).toBe('/api/v1/groups/fake_group_endpoint/members');
+ expect(data).toBe(filterUsers);
+ });
+ });
+
+ it('dispatches RECEIVE_AUTHORS_SUCCESS with received data and projectEndpoint set', () => {
+ return testAction(
+ actions.fetchAuthors,
+ null,
+ { ...state, projectEndpoint },
+ [
+ { type: types.REQUEST_AUTHORS },
+ { type: types.RECEIVE_AUTHORS_SUCCESS, payload: filterUsers },
+ ],
+ [],
+ ).then(({ data }) => {
+ expect(mock.history.get[0].url).toBe('/api/v1/projects/fake_project_endpoint/users');
+ expect(data).toBe(filterUsers);
+ });
+ });
+ });
+
+ describe('error', () => {
+ beforeEach(() => {
+ mock.onAny().replyOnce(httpStatusCodes.SERVICE_UNAVAILABLE);
+ });
+
+ it('dispatches RECEIVE_AUTHORS_ERROR and groupEndpoint set', () => {
+ return testAction(
+ actions.fetchAuthors,
+ null,
+ { ...state, groupEndpoint },
+ [
+ { type: types.REQUEST_AUTHORS },
+ {
+ type: types.RECEIVE_AUTHORS_ERROR,
+ payload: httpStatusCodes.SERVICE_UNAVAILABLE,
+ },
+ ],
+ [],
+ ).then(() => {
+ expect(mock.history.get[0].url).toBe('/api/v1/groups/fake_group_endpoint/members');
+ expect(createFlash).toHaveBeenCalled();
+ });
+ });
+
+ it('dispatches RECEIVE_AUTHORS_ERROR and projectEndpoint set', () => {
+ return testAction(
+ actions.fetchAuthors,
+ null,
+ { ...state, projectEndpoint },
+ [
+ { type: types.REQUEST_AUTHORS },
+ {
+ type: types.RECEIVE_AUTHORS_ERROR,
+ payload: httpStatusCodes.SERVICE_UNAVAILABLE,
+ },
+ ],
+ [],
+ ).then(() => {
+ expect(mock.history.get[0].url).toBe('/api/v1/projects/fake_project_endpoint/users');
+ expect(createFlash).toHaveBeenCalled();
+ });
+ });
+ });
+ });
+
+ describe('fetchMilestones', () => {
+ describe('success', () => {
+ beforeEach(() => {
+ mock.onGet(milestonesEndpoint).replyOnce(httpStatusCodes.OK, filterMilestones);
+ });
+
+ it('dispatches RECEIVE_MILESTONES_SUCCESS with received data', () => {
+ return testAction(
+ actions.fetchMilestones,
+ null,
+ { ...state, milestonesEndpoint },
+ [
+ { type: types.REQUEST_MILESTONES },
+ { type: types.RECEIVE_MILESTONES_SUCCESS, payload: filterMilestones },
+ ],
+ [],
+ ).then(({ data }) => {
+ expect(data).toBe(filterMilestones);
+ });
+ });
+ });
+
+ describe('error', () => {
+ beforeEach(() => {
+ mock.onAny().replyOnce(httpStatusCodes.SERVICE_UNAVAILABLE);
+ });
+
+ it('dispatches RECEIVE_MILESTONES_ERROR', () => {
+ return testAction(
+ actions.fetchMilestones,
+ null,
+ state,
+ [
+ { type: types.REQUEST_MILESTONES },
+ {
+ type: types.RECEIVE_MILESTONES_ERROR,
+ payload: httpStatusCodes.SERVICE_UNAVAILABLE,
+ },
+ ],
+ [],
+ ).then(() => expect(createFlash).toHaveBeenCalled());
+ });
+ });
+ });
+
+ describe('fetchAssignees', () => {
+ describe('success', () => {
+ let restoreVersion;
+ beforeEach(() => {
+ mock.onAny().replyOnce(httpStatusCodes.OK, filterUsers);
+ restoreVersion = gon.api_version;
+ gon.api_version = 'v1';
+ });
+
+ afterEach(() => {
+ gon.api_version = restoreVersion;
+ });
+
+ it('dispatches RECEIVE_ASSIGNEES_SUCCESS with received data and groupEndpoint set', () => {
+ return testAction(
+ actions.fetchAssignees,
+ null,
+ { ...state, milestonesEndpoint, groupEndpoint },
+ [
+ { type: types.REQUEST_ASSIGNEES },
+ { type: types.RECEIVE_ASSIGNEES_SUCCESS, payload: filterUsers },
+ ],
+ [],
+ ).then(({ data }) => {
+ expect(mock.history.get[0].url).toBe('/api/v1/groups/fake_group_endpoint/members');
+ expect(data).toBe(filterUsers);
+ });
+ });
+
+ it('dispatches RECEIVE_ASSIGNEES_SUCCESS with received data and projectEndpoint set', () => {
+ return testAction(
+ actions.fetchAssignees,
+ null,
+ { ...state, milestonesEndpoint, projectEndpoint },
+ [
+ { type: types.REQUEST_ASSIGNEES },
+ { type: types.RECEIVE_ASSIGNEES_SUCCESS, payload: filterUsers },
+ ],
+ [],
+ ).then(({ data }) => {
+ expect(mock.history.get[0].url).toBe('/api/v1/projects/fake_project_endpoint/users');
+ expect(data).toBe(filterUsers);
+ });
+ });
+ });
+
+ describe('error', () => {
+ let restoreVersion;
+ beforeEach(() => {
+ mock.onAny().replyOnce(httpStatusCodes.SERVICE_UNAVAILABLE);
+ restoreVersion = gon.api_version;
+ gon.api_version = 'v1';
+ });
+
+ afterEach(() => {
+ gon.api_version = restoreVersion;
+ });
+
+ it('dispatches RECEIVE_ASSIGNEES_ERROR and groupEndpoint set', () => {
+ return testAction(
+ actions.fetchAssignees,
+ null,
+ { ...state, groupEndpoint },
+ [
+ { type: types.REQUEST_ASSIGNEES },
+ {
+ type: types.RECEIVE_ASSIGNEES_ERROR,
+ payload: httpStatusCodes.SERVICE_UNAVAILABLE,
+ },
+ ],
+ [],
+ ).then(() => {
+ expect(mock.history.get[0].url).toBe('/api/v1/groups/fake_group_endpoint/members');
+ expect(createFlash).toHaveBeenCalled();
+ });
+ });
+
+ it('dispatches RECEIVE_ASSIGNEES_ERROR and projectEndpoint set', () => {
+ return testAction(
+ actions.fetchAssignees,
+ null,
+ { ...state, projectEndpoint },
+ [
+ { type: types.REQUEST_ASSIGNEES },
+ {
+ type: types.RECEIVE_ASSIGNEES_ERROR,
+ payload: httpStatusCodes.SERVICE_UNAVAILABLE,
+ },
+ ],
+ [],
+ ).then(() => {
+ expect(mock.history.get[0].url).toBe('/api/v1/projects/fake_project_endpoint/users');
+ expect(createFlash).toHaveBeenCalled();
+ });
+ });
+ });
+ });
+
+ describe('fetchLabels', () => {
+ describe('success', () => {
+ beforeEach(() => {
+ mock.onGet(labelsEndpoint).replyOnce(httpStatusCodes.OK, filterLabels);
+ });
+
+ it('dispatches RECEIVE_LABELS_SUCCESS with received data', () => {
+ return testAction(
+ actions.fetchLabels,
+ null,
+ { ...state, labelsEndpoint },
+ [
+ { type: types.REQUEST_LABELS },
+ { type: types.RECEIVE_LABELS_SUCCESS, payload: filterLabels },
+ ],
+ [],
+ ).then(({ data }) => {
+ expect(data).toBe(filterLabels);
+ });
+ });
+ });
+
+ describe('error', () => {
+ beforeEach(() => {
+ mock.onAny().replyOnce(httpStatusCodes.SERVICE_UNAVAILABLE);
+ });
+
+ it('dispatches RECEIVE_LABELS_ERROR', () => {
+ return testAction(
+ actions.fetchLabels,
+ null,
+ state,
+ [
+ { type: types.REQUEST_LABELS },
+ {
+ type: types.RECEIVE_LABELS_ERROR,
+ payload: httpStatusCodes.SERVICE_UNAVAILABLE,
+ },
+ ],
+ [],
+ ).then(() => expect(createFlash).toHaveBeenCalled());
+ });
+ });
+ });
+});
diff --git a/spec/frontend/vue_shared/components/filtered_search_bar/store/modules/filters/mock_data.js b/spec/frontend/vue_shared/components/filtered_search_bar/store/modules/filters/mock_data.js
new file mode 100644
index 00000000000..6afac9f752a
--- /dev/null
+++ b/spec/frontend/vue_shared/components/filtered_search_bar/store/modules/filters/mock_data.js
@@ -0,0 +1,50 @@
+export const filterMilestones = [
+ { id: 1, title: 'None', name: 'Any' },
+ { id: 101, title: 'Any', name: 'None' },
+ { id: 1001, title: 'v1.0', name: 'v1.0' },
+ { id: 10101, title: 'v0.0', name: 'v0.0' },
+];
+
+export const filterUsers = [
+ {
+ id: 31,
+ name: 'VSM User2',
+ username: 'vsm-user-2-1589776313',
+ state: 'active',
+ avatar_url:
+ 'https://www.gravatar.com/avatar/762398957a8c6e04eed16da88098899d?s=80\u0026d=identicon',
+ web_url: 'http://127.0.0.1:3001/vsm-user-2-1589776313',
+ access_level: 30,
+ expires_at: null,
+ },
+ {
+ id: 32,
+ name: 'VSM User3',
+ username: 'vsm-user-3-1589776313',
+ state: 'active',
+ avatar_url:
+ 'https://www.gravatar.com/avatar/f78932237e8a5c5376b65a709824802f?s=80\u0026d=identicon',
+ web_url: 'http://127.0.0.1:3001/vsm-user-3-1589776313',
+ access_level: 30,
+ expires_at: null,
+ },
+ {
+ id: 33,
+ name: 'VSM User4',
+ username: 'vsm-user-4-1589776313',
+ state: 'active',
+ avatar_url:
+ 'https://www.gravatar.com/avatar/ab506dc600d1a941e4d77d5ceeeba73f?s=80\u0026d=identicon',
+ web_url: 'http://127.0.0.1:3001/vsm-user-4-1589776313',
+ access_level: 30,
+ expires_at: null,
+ },
+];
+
+export const filterLabels = [
+ { id: 194, title: 'Afterfunc-Phureforge-781', color: '#990000', text_color: '#FFFFFF' },
+ { id: 10, title: 'Afternix', color: '#16ecf2', text_color: '#FFFFFF' },
+ { id: 176, title: 'Panasync-Pens-266', color: '#990000', text_color: '#FFFFFF' },
+ { id: 79, title: 'Passat', color: '#f1a3d4', text_color: '#333333' },
+ { id: 197, title: 'Phast-Onesync-395', color: '#990000', text_color: '#FFFFFF' },
+];
diff --git a/spec/frontend/vue_shared/components/filtered_search_bar/store/modules/filters/mutations_spec.js b/spec/frontend/vue_shared/components/filtered_search_bar/store/modules/filters/mutations_spec.js
new file mode 100644
index 00000000000..263a4ee178f
--- /dev/null
+++ b/spec/frontend/vue_shared/components/filtered_search_bar/store/modules/filters/mutations_spec.js
@@ -0,0 +1,116 @@
+import { get } from 'lodash';
+import { mockBranches } from 'jest/vue_shared/components/filtered_search_bar/mock_data';
+import initialState from '~/vue_shared/components/filtered_search_bar/store/modules/filters/state';
+import mutations from '~/vue_shared/components/filtered_search_bar/store/modules/filters/mutations';
+import * as types from '~/vue_shared/components/filtered_search_bar/store/modules/filters/mutation_types';
+import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
+import { filterMilestones, filterUsers, filterLabels } from './mock_data';
+
+let state = null;
+
+const branches = mockBranches.map(convertObjectPropsToCamelCase);
+const milestones = filterMilestones.map(convertObjectPropsToCamelCase);
+const users = filterUsers.map(convertObjectPropsToCamelCase);
+const labels = filterLabels.map(convertObjectPropsToCamelCase);
+
+const filterValue = { value: 'foo' };
+
+describe('Filters mutations', () => {
+ const errorCode = 500;
+ beforeEach(() => {
+ state = initialState();
+ });
+
+ afterEach(() => {
+ state = null;
+ });
+
+ it.each`
+ mutation | stateKey | value
+ ${types.SET_MILESTONES_ENDPOINT} | ${'milestonesEndpoint'} | ${'new-milestone-endpoint'}
+ ${types.SET_LABELS_ENDPOINT} | ${'labelsEndpoint'} | ${'new-label-endpoint'}
+ ${types.SET_GROUP_ENDPOINT} | ${'groupEndpoint'} | ${'new-group-endpoint'}
+ `('$mutation will set $stateKey=$value', ({ mutation, stateKey, value }) => {
+ mutations[mutation](state, value);
+
+ expect(state[stateKey]).toEqual(value);
+ });
+
+ it.each`
+ mutation | stateKey | filterName | value
+ ${types.SET_SELECTED_FILTERS} | ${'branches.source.selected'} | ${'selectedSourceBranch'} | ${null}
+ ${types.SET_SELECTED_FILTERS} | ${'branches.source.selected'} | ${'selectedSourceBranch'} | ${filterValue}
+ ${types.SET_SELECTED_FILTERS} | ${'branches.source.selectedList'} | ${'selectedSourceBranchList'} | ${[]}
+ ${types.SET_SELECTED_FILTERS} | ${'branches.source.selectedList'} | ${'selectedSourceBranchList'} | ${[filterValue]}
+ ${types.SET_SELECTED_FILTERS} | ${'branches.target.selected'} | ${'selectedTargetBranch'} | ${null}
+ ${types.SET_SELECTED_FILTERS} | ${'branches.target.selected'} | ${'selectedTargetBranch'} | ${filterValue}
+ ${types.SET_SELECTED_FILTERS} | ${'branches.target.selectedList'} | ${'selectedTargetBranchList'} | ${[]}
+ ${types.SET_SELECTED_FILTERS} | ${'branches.target.selectedList'} | ${'selectedTargetBranchList'} | ${[filterValue]}
+ ${types.SET_SELECTED_FILTERS} | ${'authors.selected'} | ${'selectedAuthor'} | ${null}
+ ${types.SET_SELECTED_FILTERS} | ${'authors.selected'} | ${'selectedAuthor'} | ${filterValue}
+ ${types.SET_SELECTED_FILTERS} | ${'authors.selectedList'} | ${'selectedAuthorList'} | ${[]}
+ ${types.SET_SELECTED_FILTERS} | ${'authors.selectedList'} | ${'selectedAuthorList'} | ${[filterValue]}
+ ${types.SET_SELECTED_FILTERS} | ${'milestones.selected'} | ${'selectedMilestone'} | ${null}
+ ${types.SET_SELECTED_FILTERS} | ${'milestones.selected'} | ${'selectedMilestone'} | ${filterValue}
+ ${types.SET_SELECTED_FILTERS} | ${'milestones.selectedList'} | ${'selectedMilestoneList'} | ${[]}
+ ${types.SET_SELECTED_FILTERS} | ${'milestones.selectedList'} | ${'selectedMilestoneList'} | ${[filterValue]}
+ ${types.SET_SELECTED_FILTERS} | ${'assignees.selected'} | ${'selectedAssignee'} | ${null}
+ ${types.SET_SELECTED_FILTERS} | ${'assignees.selected'} | ${'selectedAssignee'} | ${filterValue}
+ ${types.SET_SELECTED_FILTERS} | ${'assignees.selectedList'} | ${'selectedAssigneeList'} | ${[]}
+ ${types.SET_SELECTED_FILTERS} | ${'assignees.selectedList'} | ${'selectedAssigneeList'} | ${[filterValue]}
+ ${types.SET_SELECTED_FILTERS} | ${'labels.selected'} | ${'selectedLabel'} | ${null}
+ ${types.SET_SELECTED_FILTERS} | ${'labels.selected'} | ${'selectedLabel'} | ${filterValue}
+ ${types.SET_SELECTED_FILTERS} | ${'labels.selectedList'} | ${'selectedLabelList'} | ${[]}
+ ${types.SET_SELECTED_FILTERS} | ${'labels.selectedList'} | ${'selectedLabelList'} | ${[filterValue]}
+ `(
+ '$mutation will set $stateKey with a given value',
+ ({ mutation, stateKey, filterName, value }) => {
+ mutations[mutation](state, { [filterName]: value });
+
+ expect(get(state, stateKey)).toEqual(value);
+ },
+ );
+
+ it.each`
+ mutation | rootKey | stateKey | value
+ ${types.REQUEST_BRANCHES} | ${'branches'} | ${'isLoading'} | ${true}
+ ${types.RECEIVE_BRANCHES_SUCCESS} | ${'branches'} | ${'isLoading'} | ${false}
+ ${types.RECEIVE_BRANCHES_SUCCESS} | ${'branches'} | ${'data'} | ${branches}
+ ${types.RECEIVE_BRANCHES_SUCCESS} | ${'branches'} | ${'errorCode'} | ${null}
+ ${types.RECEIVE_BRANCHES_ERROR} | ${'branches'} | ${'isLoading'} | ${false}
+ ${types.RECEIVE_BRANCHES_ERROR} | ${'branches'} | ${'data'} | ${[]}
+ ${types.RECEIVE_BRANCHES_ERROR} | ${'branches'} | ${'errorCode'} | ${errorCode}
+ ${types.REQUEST_MILESTONES} | ${'milestones'} | ${'isLoading'} | ${true}
+ ${types.RECEIVE_MILESTONES_SUCCESS} | ${'milestones'} | ${'isLoading'} | ${false}
+ ${types.RECEIVE_MILESTONES_SUCCESS} | ${'milestones'} | ${'data'} | ${milestones}
+ ${types.RECEIVE_MILESTONES_SUCCESS} | ${'milestones'} | ${'errorCode'} | ${null}
+ ${types.RECEIVE_MILESTONES_ERROR} | ${'milestones'} | ${'isLoading'} | ${false}
+ ${types.RECEIVE_MILESTONES_ERROR} | ${'milestones'} | ${'data'} | ${[]}
+ ${types.RECEIVE_MILESTONES_ERROR} | ${'milestones'} | ${'errorCode'} | ${errorCode}
+ ${types.REQUEST_AUTHORS} | ${'authors'} | ${'isLoading'} | ${true}
+ ${types.RECEIVE_AUTHORS_SUCCESS} | ${'authors'} | ${'isLoading'} | ${false}
+ ${types.RECEIVE_AUTHORS_SUCCESS} | ${'authors'} | ${'data'} | ${users}
+ ${types.RECEIVE_AUTHORS_SUCCESS} | ${'authors'} | ${'errorCode'} | ${null}
+ ${types.RECEIVE_AUTHORS_ERROR} | ${'authors'} | ${'isLoading'} | ${false}
+ ${types.RECEIVE_AUTHORS_ERROR} | ${'authors'} | ${'data'} | ${[]}
+ ${types.RECEIVE_AUTHORS_ERROR} | ${'authors'} | ${'errorCode'} | ${errorCode}
+ ${types.REQUEST_LABELS} | ${'labels'} | ${'isLoading'} | ${true}
+ ${types.RECEIVE_LABELS_SUCCESS} | ${'labels'} | ${'isLoading'} | ${false}
+ ${types.RECEIVE_LABELS_SUCCESS} | ${'labels'} | ${'data'} | ${labels}
+ ${types.RECEIVE_LABELS_SUCCESS} | ${'labels'} | ${'errorCode'} | ${null}
+ ${types.RECEIVE_LABELS_ERROR} | ${'labels'} | ${'isLoading'} | ${false}
+ ${types.RECEIVE_LABELS_ERROR} | ${'labels'} | ${'data'} | ${[]}
+ ${types.RECEIVE_LABELS_ERROR} | ${'labels'} | ${'errorCode'} | ${errorCode}
+ ${types.REQUEST_ASSIGNEES} | ${'assignees'} | ${'isLoading'} | ${true}
+ ${types.RECEIVE_ASSIGNEES_SUCCESS} | ${'assignees'} | ${'isLoading'} | ${false}
+ ${types.RECEIVE_ASSIGNEES_SUCCESS} | ${'assignees'} | ${'data'} | ${users}
+ ${types.RECEIVE_ASSIGNEES_SUCCESS} | ${'assignees'} | ${'errorCode'} | ${null}
+ ${types.RECEIVE_ASSIGNEES_ERROR} | ${'assignees'} | ${'isLoading'} | ${false}
+ ${types.RECEIVE_ASSIGNEES_ERROR} | ${'assignees'} | ${'data'} | ${[]}
+ ${types.RECEIVE_ASSIGNEES_ERROR} | ${'assignees'} | ${'errorCode'} | ${errorCode}
+ `('$mutation will set $stateKey with a given value', ({ mutation, rootKey, stateKey, value }) => {
+ mutations[mutation](state, value);
+
+ expect(state[rootKey][stateKey]).toEqual(value);
+ });
+});
diff --git a/spec/frontend/vue_shared/components/filtered_search_bar/store/modules/filters/test_helper.js b/spec/frontend/vue_shared/components/filtered_search_bar/store/modules/filters/test_helper.js
new file mode 100644
index 00000000000..1b7c80a5252
--- /dev/null
+++ b/spec/frontend/vue_shared/components/filtered_search_bar/store/modules/filters/test_helper.js
@@ -0,0 +1,11 @@
+export function getFilterParams(tokens, options = {}) {
+ const { key = 'value', operator = '=', prop = 'title' } = options;
+ return tokens.map(token => {
+ return { [key]: token[prop], operator };
+ });
+}
+
+export function getFilterValues(tokens, options = {}) {
+ const { prop = 'title' } = options;
+ return tokens.map(token => token[prop]);
+}
diff --git a/spec/frontend/vue_shared/components/local_storage_sync_spec.js b/spec/frontend/vue_shared/components/local_storage_sync_spec.js
index 5470171a21e..efa9b5796fb 100644
--- a/spec/frontend/vue_shared/components/local_storage_sync_spec.js
+++ b/spec/frontend/vue_shared/components/local_storage_sync_spec.js
@@ -12,7 +12,9 @@ describe('Local Storage Sync', () => {
};
afterEach(() => {
- wrapper.destroy();
+ if (wrapper) {
+ wrapper.destroy();
+ }
wrapper = null;
localStorage.clear();
});
@@ -45,23 +47,23 @@ describe('Local Storage Sync', () => {
expect(wrapper.emitted('input')).toBeFalsy();
});
- it('saves updated value to localStorage', () => {
- createComponent({
- props: {
- storageKey,
- value: 'ascending',
- },
- });
-
- const newValue = 'descending';
- wrapper.setProps({
- value: newValue,
- });
-
- return wrapper.vm.$nextTick().then(() => {
- expect(localStorage.getItem(storageKey)).toBe(newValue);
- });
- });
+ it.each('foo', 3, true, ['foo', 'bar'], { foo: 'bar' })(
+ 'saves updated value to localStorage',
+ newValue => {
+ createComponent({
+ props: {
+ storageKey,
+ value: 'initial',
+ },
+ });
+
+ wrapper.setProps({ value: newValue });
+
+ return wrapper.vm.$nextTick().then(() => {
+ expect(localStorage.getItem(storageKey)).toBe(String(newValue));
+ });
+ },
+ );
it('does not save default value', () => {
const value = 'ascending';
@@ -124,5 +126,117 @@ describe('Local Storage Sync', () => {
expect(localStorage.getItem(storageKey)).toBe(newValue);
});
});
+
+ it('persists the value by default', async () => {
+ const persistedValue = 'persisted';
+
+ createComponent({
+ props: {
+ storageKey,
+ },
+ });
+
+ wrapper.setProps({ value: persistedValue });
+ await wrapper.vm.$nextTick();
+ expect(localStorage.getItem(storageKey)).toBe(persistedValue);
+ });
+
+ it('does not save a value if persist is set to false', async () => {
+ const notPersistedValue = 'notPersisted';
+
+ createComponent({
+ props: {
+ storageKey,
+ },
+ });
+
+ wrapper.setProps({ persist: false, value: notPersistedValue });
+ await wrapper.vm.$nextTick();
+ expect(localStorage.getItem(storageKey)).not.toBe(notPersistedValue);
+ });
+ });
+
+ describe('with "asJson" prop set to "true"', () => {
+ const storageKey = 'testStorageKey';
+
+ describe.each`
+ value | serializedValue
+ ${null} | ${'null'}
+ ${''} | ${'""'}
+ ${true} | ${'true'}
+ ${false} | ${'false'}
+ ${42} | ${'42'}
+ ${'42'} | ${'"42"'}
+ ${'{ foo: '} | ${'"{ foo: "'}
+ ${['test']} | ${'["test"]'}
+ ${{ foo: 'bar' }} | ${'{"foo":"bar"}'}
+ `('given $value', ({ value, serializedValue }) => {
+ describe('is a new value', () => {
+ beforeEach(() => {
+ createComponent({
+ props: {
+ storageKey,
+ value: 'initial',
+ asJson: true,
+ },
+ });
+
+ wrapper.setProps({ value });
+
+ return wrapper.vm.$nextTick();
+ });
+
+ it('serializes the value correctly to localStorage', () => {
+ expect(localStorage.getItem(storageKey)).toBe(serializedValue);
+ });
+ });
+
+ describe('is already stored', () => {
+ beforeEach(() => {
+ localStorage.setItem(storageKey, serializedValue);
+
+ createComponent({
+ props: {
+ storageKey,
+ value: 'initial',
+ asJson: true,
+ },
+ });
+ });
+
+ it('emits an input event with the deserialized value', () => {
+ expect(wrapper.emitted('input')).toEqual([[value]]);
+ });
+ });
+ });
+
+ describe('with bad JSON in storage', () => {
+ const badJSON = '{ badJSON';
+
+ beforeEach(() => {
+ jest.spyOn(console, 'warn').mockImplementation();
+ localStorage.setItem(storageKey, badJSON);
+
+ createComponent({
+ props: {
+ storageKey,
+ value: 'initial',
+ asJson: true,
+ },
+ });
+ });
+
+ it('should console warn', () => {
+ // eslint-disable-next-line no-console
+ expect(console.warn).toHaveBeenCalledWith(
+ `[gitlab] Failed to deserialize value from localStorage (key=${storageKey})`,
+ badJSON,
+ );
+ });
+
+ it('should not emit an input event', () => {
+ expect(wrapper.emitted('input')).toBeUndefined();
+ });
+ });
});
});
diff --git a/spec/frontend/vue_shared/components/markdown/__snapshots__/suggestion_diff_spec.js.snap b/spec/frontend/vue_shared/components/markdown/__snapshots__/suggestion_diff_spec.js.snap
index cdd7a3ccaf0..b8a9143bc79 100644
--- a/spec/frontend/vue_shared/components/markdown/__snapshots__/suggestion_diff_spec.js.snap
+++ b/spec/frontend/vue_shared/components/markdown/__snapshots__/suggestion_diff_spec.js.snap
@@ -10,6 +10,7 @@ exports[`Suggestion Diff component matches snapshot 1`] = `
helppagepath="path_to_docs"
isapplyingbatch="true"
isbatched="true"
+ suggestionscount="0"
/>
<table
diff --git a/spec/frontend/vue_shared/components/markdown/field_spec.js b/spec/frontend/vue_shared/components/markdown/field_spec.js
index 3da0a35f05a..a2ce6f40193 100644
--- a/spec/frontend/vue_shared/components/markdown/field_spec.js
+++ b/spec/frontend/vue_shared/components/markdown/field_spec.js
@@ -2,11 +2,13 @@ import { mount } from '@vue/test-utils';
import { TEST_HOST, FIXTURES_PATH } from 'spec/test_constants';
import AxiosMockAdapter from 'axios-mock-adapter';
import $ from 'jquery';
-import fieldComponent from '~/vue_shared/components/markdown/field.vue';
+import MarkdownField from '~/vue_shared/components/markdown/field.vue';
import axios from '~/lib/utils/axios_utils';
const markdownPreviewPath = `${TEST_HOST}/preview`;
const markdownDocsPath = `${TEST_HOST}/docs`;
+const textareaValue = 'testing\n123';
+const uploadsPath = 'test/uploads';
function assertMarkdownTabs(isWrite, writeLink, previewLink, wrapper) {
expect(writeLink.element.parentNode.classList.contains('active')).toBe(isWrite);
@@ -14,66 +16,81 @@ function assertMarkdownTabs(isWrite, writeLink, previewLink, wrapper) {
expect(wrapper.find('.md-preview-holder').element.style.display).toBe(isWrite ? 'none' : '');
}
-function createComponent() {
- const wrapper = mount(fieldComponent, {
- propsData: {
- markdownDocsPath,
- markdownPreviewPath,
- isSubmitting: false,
- },
- slots: {
- textarea: '<textarea>testing\n123</textarea>',
- },
- template: `
- <field-component
- markdown-preview-path="${markdownPreviewPath}"
- markdown-docs-path="${markdownDocsPath}"
- :isSubmitting="false"
- >
- <textarea
- slot="textarea"
- v-model="text">
- <slot>this is a test</slot>
- </textarea>
- </field-component>
- `,
- });
- return wrapper;
-}
-
-const getPreviewLink = wrapper => wrapper.find('.nav-links .js-preview-link');
-const getWriteLink = wrapper => wrapper.find('.nav-links .js-write-link');
-const getMarkdownButton = wrapper => wrapper.find('.js-md');
-const getAllMarkdownButtons = wrapper => wrapper.findAll('.js-md');
-const getVideo = wrapper => wrapper.find('video');
-
describe('Markdown field component', () => {
let axiosMock;
+ let subject;
beforeEach(() => {
axiosMock = new AxiosMockAdapter(axios);
+ // window.uploads_path is needed for dropzone to initialize
+ window.uploads_path = uploadsPath;
});
afterEach(() => {
+ subject.destroy();
+ subject = null;
axiosMock.restore();
});
+ function createSubject() {
+ // We actually mount a wrapper component so that we can force Vue to rerender classes in order to test a regression
+ // caused by mixing Vanilla JS and Vue.
+ subject = mount(
+ {
+ components: {
+ MarkdownField,
+ },
+ props: {
+ wrapperClasses: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ },
+ template: `
+<markdown-field :class="wrapperClasses" v-bind="$attrs">
+ <template #textarea>
+ <textarea class="js-gfm-input" :value="$attrs.textareaValue"></textarea>
+ </template>
+</markdown-field>`,
+ },
+ {
+ propsData: {
+ markdownDocsPath,
+ markdownPreviewPath,
+ isSubmitting: false,
+ textareaValue,
+ },
+ },
+ );
+ }
+
+ const getPreviewLink = () => subject.find('.nav-links .js-preview-link');
+ const getWriteLink = () => subject.find('.nav-links .js-write-link');
+ const getMarkdownButton = () => subject.find('.js-md');
+ const getAllMarkdownButtons = () => subject.findAll('.js-md');
+ const getVideo = () => subject.find('video');
+ const getAttachButton = () => subject.find('.button-attach-file');
+ const clickAttachButton = () => getAttachButton().trigger('click');
+ const findDropzone = () => subject.find('.div-dropzone');
+
describe('mounted', () => {
- let wrapper;
const previewHTML = `
<p>markdown preview</p>
<video src="${FIXTURES_PATH}/static/mock-video.mp4" muted="muted"></video>
`;
let previewLink;
let writeLink;
+ let dropzoneSpy;
- afterEach(() => {
- wrapper.destroy();
+ beforeEach(() => {
+ dropzoneSpy = jest.fn();
+ createSubject();
+ findDropzone().element.addEventListener('click', dropzoneSpy);
});
it('renders textarea inside backdrop', () => {
- wrapper = createComponent();
- expect(wrapper.find('.zen-backdrop textarea').element).not.toBeNull();
+ expect(subject.find('.zen-backdrop textarea').element).not.toBeNull();
});
describe('markdown preview', () => {
@@ -82,44 +99,40 @@ describe('Markdown field component', () => {
});
it('sets preview link as active', () => {
- wrapper = createComponent();
- previewLink = getPreviewLink(wrapper);
+ previewLink = getPreviewLink();
previewLink.trigger('click');
- return wrapper.vm.$nextTick().then(() => {
+ return subject.vm.$nextTick().then(() => {
expect(previewLink.element.parentNode.classList.contains('active')).toBeTruthy();
});
});
it('shows preview loading text', () => {
- wrapper = createComponent();
- previewLink = getPreviewLink(wrapper);
+ previewLink = getPreviewLink();
previewLink.trigger('click');
- return wrapper.vm.$nextTick(() => {
- expect(wrapper.find('.md-preview-holder').element.textContent.trim()).toContain(
+ return subject.vm.$nextTick(() => {
+ expect(subject.find('.md-preview-holder').element.textContent.trim()).toContain(
'Loading…',
);
});
});
it('renders markdown preview and GFM', () => {
- wrapper = createComponent();
const renderGFMSpy = jest.spyOn($.fn, 'renderGFM');
- previewLink = getPreviewLink(wrapper);
+ previewLink = getPreviewLink();
previewLink.trigger('click');
return axios.waitFor(markdownPreviewPath).then(() => {
- expect(wrapper.find('.md-preview-holder').element.innerHTML).toContain(previewHTML);
+ expect(subject.find('.md-preview-holder').element.innerHTML).toContain(previewHTML);
expect(renderGFMSpy).toHaveBeenCalled();
});
});
it('calls video.pause() on comment input when isSubmitting is changed to true', () => {
- wrapper = createComponent();
- previewLink = getPreviewLink(wrapper);
+ previewLink = getPreviewLink();
previewLink.trigger('click');
let callPause;
@@ -127,79 +140,107 @@ describe('Markdown field component', () => {
return axios
.waitFor(markdownPreviewPath)
.then(() => {
- const video = getVideo(wrapper);
+ const video = getVideo();
callPause = jest.spyOn(video.element, 'pause').mockImplementation(() => true);
- wrapper.setProps({
- isSubmitting: true,
- markdownPreviewPath,
- markdownDocsPath,
- });
+ subject.setProps({ isSubmitting: true });
- return wrapper.vm.$nextTick();
+ return subject.vm.$nextTick();
})
.then(() => {
expect(callPause).toHaveBeenCalled();
});
});
- it('clicking already active write or preview link does nothing', () => {
- wrapper = createComponent();
- writeLink = getWriteLink(wrapper);
- previewLink = getPreviewLink(wrapper);
+ it('clicking already active write or preview link does nothing', async () => {
+ writeLink = getWriteLink();
+ previewLink = getPreviewLink();
+
+ writeLink.trigger('click');
+ await subject.vm.$nextTick();
+ assertMarkdownTabs(true, writeLink, previewLink, subject);
writeLink.trigger('click');
- return wrapper.vm
- .$nextTick()
- .then(() => assertMarkdownTabs(true, writeLink, previewLink, wrapper))
- .then(() => writeLink.trigger('click'))
- .then(() => wrapper.vm.$nextTick())
- .then(() => assertMarkdownTabs(true, writeLink, previewLink, wrapper))
- .then(() => previewLink.trigger('click'))
- .then(() => wrapper.vm.$nextTick())
- .then(() => assertMarkdownTabs(false, writeLink, previewLink, wrapper))
- .then(() => previewLink.trigger('click'))
- .then(() => wrapper.vm.$nextTick())
- .then(() => assertMarkdownTabs(false, writeLink, previewLink, wrapper));
+ await subject.vm.$nextTick();
+
+ assertMarkdownTabs(true, writeLink, previewLink, subject);
+ previewLink.trigger('click');
+ await subject.vm.$nextTick();
+
+ assertMarkdownTabs(false, writeLink, previewLink, subject);
+ previewLink.trigger('click');
+ await subject.vm.$nextTick();
+
+ assertMarkdownTabs(false, writeLink, previewLink, subject);
});
});
describe('markdown buttons', () => {
it('converts single words', () => {
- wrapper = createComponent();
- const textarea = wrapper.find('textarea').element;
+ const textarea = subject.find('textarea').element;
textarea.setSelectionRange(0, 7);
- const markdownButton = getMarkdownButton(wrapper);
+ const markdownButton = getMarkdownButton();
markdownButton.trigger('click');
- return wrapper.vm.$nextTick(() => {
+ return subject.vm.$nextTick(() => {
expect(textarea.value).toContain('**testing**');
});
});
it('converts a line', () => {
- wrapper = createComponent();
- const textarea = wrapper.find('textarea').element;
+ const textarea = subject.find('textarea').element;
textarea.setSelectionRange(0, 0);
- const markdownButton = getAllMarkdownButtons(wrapper).wrappers[5];
+ const markdownButton = getAllMarkdownButtons().wrappers[5];
markdownButton.trigger('click');
- return wrapper.vm.$nextTick(() => {
+ return subject.vm.$nextTick(() => {
expect(textarea.value).toContain('- testing');
});
});
it('converts multiple lines', () => {
- wrapper = createComponent();
- const textarea = wrapper.find('textarea').element;
+ const textarea = subject.find('textarea').element;
textarea.setSelectionRange(0, 50);
- const markdownButton = getAllMarkdownButtons(wrapper).wrappers[5];
+ const markdownButton = getAllMarkdownButtons().wrappers[5];
markdownButton.trigger('click');
- return wrapper.vm.$nextTick(() => {
+ return subject.vm.$nextTick(() => {
expect(textarea.value).toContain('- testing\n- 123');
});
});
});
+
+ it('should render attach a file button', () => {
+ expect(getAttachButton().text()).toBe('Attach a file');
+ });
+
+ it('should trigger dropzone when attach button is clicked', () => {
+ expect(dropzoneSpy).not.toHaveBeenCalled();
+
+ clickAttachButton();
+
+ expect(dropzoneSpy).toHaveBeenCalled();
+ });
+
+ describe('when textarea has changed', () => {
+ beforeEach(async () => {
+ // Do something to trigger rerendering the class
+ subject.setProps({ wrapperClasses: 'foo' });
+
+ await subject.vm.$nextTick();
+ });
+
+ it('should have rerendered classes and kept gfm-form', () => {
+ expect(subject.classes()).toEqual(expect.arrayContaining(['gfm-form', 'foo']));
+ });
+
+ it('should trigger dropzone when attach button is clicked', () => {
+ expect(dropzoneSpy).not.toHaveBeenCalled();
+
+ clickAttachButton();
+
+ expect(dropzoneSpy).toHaveBeenCalled();
+ });
+ });
});
});
diff --git a/spec/frontend/vue_shared/components/markdown/suggestion_diff_header_spec.js b/spec/frontend/vue_shared/components/markdown/suggestion_diff_header_spec.js
index a521668b15c..b19e74b5b11 100644
--- a/spec/frontend/vue_shared/components/markdown/suggestion_diff_header_spec.js
+++ b/spec/frontend/vue_shared/components/markdown/suggestion_diff_header_spec.js
@@ -57,7 +57,9 @@ describe('Suggestion Diff component', () => {
});
it('renders apply suggestion and add to batch buttons', () => {
- createComponent();
+ createComponent({
+ suggestionsCount: 2,
+ });
const applyBtn = findApplyButton();
const addToBatchBtn = findAddToBatchButton();
@@ -104,7 +106,9 @@ describe('Suggestion Diff component', () => {
describe('when add to batch is clicked', () => {
it('emits addToBatch', () => {
- createComponent();
+ createComponent({
+ suggestionsCount: 2,
+ });
findAddToBatchButton().vm.$emit('click');
diff --git a/spec/frontend/vue_shared/components/members/action_buttons/access_request_action_buttons_spec.js b/spec/frontend/vue_shared/components/members/action_buttons/access_request_action_buttons_spec.js
new file mode 100644
index 00000000000..58cb8ef61d1
--- /dev/null
+++ b/spec/frontend/vue_shared/components/members/action_buttons/access_request_action_buttons_spec.js
@@ -0,0 +1,108 @@
+import { shallowMount } from '@vue/test-utils';
+import AccessRequestActionButtons from '~/vue_shared/components/members/action_buttons/access_request_action_buttons.vue';
+import RemoveMemberButton from '~/vue_shared/components/members/action_buttons/remove_member_button.vue';
+import ApproveAccessRequestButton from '~/vue_shared/components/members/action_buttons/approve_access_request_button.vue';
+import { accessRequest as member } from '../mock_data';
+
+describe('AccessRequestActionButtons', () => {
+ let wrapper;
+
+ const createComponent = (propsData = {}) => {
+ wrapper = shallowMount(AccessRequestActionButtons, {
+ propsData: {
+ member,
+ isCurrentUser: true,
+ ...propsData,
+ },
+ });
+ };
+
+ const findRemoveMemberButton = () => wrapper.find(RemoveMemberButton);
+ const findApproveButton = () => wrapper.find(ApproveAccessRequestButton);
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe('when user has `canRemove` permissions', () => {
+ beforeEach(() => {
+ createComponent({
+ permissions: {
+ canRemove: true,
+ },
+ });
+ });
+
+ 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,
+ 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.name}"`,
+ );
+ });
+ });
+
+ describe('when member is not the current user', () => {
+ it('sets `message` prop correctly', () => {
+ createComponent({
+ isCurrentUser: false,
+ permissions: {
+ canRemove: true,
+ },
+ });
+
+ expect(findRemoveMemberButton().props('message')).toBe(
+ `Are you sure you want to deny ${member.user.name}'s request to join "${member.source.name}"`,
+ );
+ });
+ });
+ });
+
+ describe('when user does not have `canRemove` permissions', () => {
+ it('does not render remove member button', () => {
+ createComponent({
+ permissions: {
+ canRemove: false,
+ },
+ });
+
+ expect(findRemoveMemberButton().exists()).toBe(false);
+ });
+ });
+
+ describe('when user has `canUpdate` permissions', () => {
+ it('renders the approve button', () => {
+ createComponent({
+ permissions: {
+ canUpdate: true,
+ },
+ });
+
+ expect(findApproveButton().exists()).toBe(true);
+ });
+ });
+
+ describe('when user does not have `canUpdate` permissions', () => {
+ it('does not render the approve button', () => {
+ createComponent({
+ permissions: {
+ canUpdate: false,
+ },
+ });
+
+ expect(findApproveButton().exists()).toBe(false);
+ });
+ });
+});
diff --git a/spec/frontend/vue_shared/components/members/action_buttons/approve_access_request_button_spec.js b/spec/frontend/vue_shared/components/members/action_buttons/approve_access_request_button_spec.js
new file mode 100644
index 00000000000..93edaaa400d
--- /dev/null
+++ b/spec/frontend/vue_shared/components/members/action_buttons/approve_access_request_button_spec.js
@@ -0,0 +1,74 @@
+import { shallowMount, createLocalVue } from '@vue/test-utils';
+import Vuex from 'vuex';
+import { GlButton, GlForm } from '@gitlab/ui';
+import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
+import ApproveAccessRequestButton from '~/vue_shared/components/members/action_buttons/approve_access_request_button.vue';
+
+jest.mock('~/lib/utils/csrf', () => ({ token: 'mock-csrf-token' }));
+
+const localVue = createLocalVue();
+localVue.use(Vuex);
+
+describe('ApproveAccessRequestButton', () => {
+ let wrapper;
+
+ const createStore = (state = {}) => {
+ return new Vuex.Store({
+ state: {
+ memberPath: '/groups/foo-bar/-/group_members/:id',
+ ...state,
+ },
+ });
+ };
+
+ const createComponent = (propsData = {}, state) => {
+ wrapper = shallowMount(ApproveAccessRequestButton, {
+ localVue,
+ store: createStore(state),
+ propsData: {
+ memberId: 1,
+ ...propsData,
+ },
+ directives: {
+ GlTooltip: createMockDirective(),
+ },
+ });
+ };
+
+ const findForm = () => wrapper.find(GlForm);
+ const findButton = () => findForm().find(GlButton);
+
+ beforeEach(() => {
+ createComponent();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('displays a tooltip', () => {
+ const button = findButton();
+
+ expect(getBinding(button.element, 'gl-tooltip')).not.toBeUndefined();
+ expect(button.attributes('title')).toBe('Grant access');
+ });
+
+ it('sets `aria-label` attribute', () => {
+ expect(findButton().attributes('aria-label')).toBe('Grant access');
+ });
+
+ it('submits the form when button is clicked', () => {
+ expect(findButton().attributes('type')).toBe('submit');
+ });
+
+ it('displays form with correct action and inputs', () => {
+ const form = findForm();
+
+ expect(form.attributes('action')).toBe(
+ '/groups/foo-bar/-/group_members/1/approve_access_request',
+ );
+ expect(form.find('input[name="authenticity_token"]').attributes('value')).toBe(
+ 'mock-csrf-token',
+ );
+ });
+});
diff --git a/spec/frontend/vue_shared/components/members/action_buttons/invite_action_buttons_spec.js b/spec/frontend/vue_shared/components/members/action_buttons/invite_action_buttons_spec.js
new file mode 100644
index 00000000000..1374cdc6aef
--- /dev/null
+++ b/spec/frontend/vue_shared/components/members/action_buttons/invite_action_buttons_spec.js
@@ -0,0 +1,85 @@
+import { shallowMount } from '@vue/test-utils';
+import InviteActionButtons from '~/vue_shared/components/members/action_buttons/invite_action_buttons.vue';
+import RemoveMemberButton from '~/vue_shared/components/members/action_buttons/remove_member_button.vue';
+import ResendInviteButton from '~/vue_shared/components/members/action_buttons/resend_invite_button.vue';
+import { invite as member } from '../mock_data';
+
+describe('InviteActionButtons', () => {
+ let wrapper;
+
+ const createComponent = (propsData = {}) => {
+ wrapper = shallowMount(InviteActionButtons, {
+ propsData: {
+ member,
+ ...propsData,
+ },
+ });
+ };
+
+ const findRemoveMemberButton = () => wrapper.find(RemoveMemberButton);
+ const findResendInviteButton = () => wrapper.find(ResendInviteButton);
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe('when user has `canRemove` permissions', () => {
+ beforeEach(() => {
+ createComponent({
+ permissions: {
+ canRemove: true,
+ },
+ });
+ });
+
+ it('renders remove member button', () => {
+ expect(findRemoveMemberButton().exists()).toBe(true);
+ });
+
+ it('sets props correctly', () => {
+ expect(findRemoveMemberButton().props()).toEqual({
+ memberId: member.id,
+ message: `Are you sure you want to revoke the invitation for ${member.invite.email} to join "${member.source.name}"`,
+ title: 'Revoke invite',
+ isAccessRequest: false,
+ icon: 'remove',
+ });
+ });
+ });
+
+ describe('when user does not have `canRemove` permissions', () => {
+ it('does not render remove member button', () => {
+ createComponent({
+ permissions: {
+ canRemove: false,
+ },
+ });
+
+ expect(findRemoveMemberButton().exists()).toBe(false);
+ });
+ });
+
+ describe('when user has `canResend` permissions', () => {
+ it('renders resend invite button', () => {
+ createComponent({
+ permissions: {
+ canResend: true,
+ },
+ });
+
+ expect(findResendInviteButton().exists()).toBe(true);
+ });
+ });
+
+ describe('when user does not have `canResend` permissions', () => {
+ it('does not render resend invite button', () => {
+ createComponent({
+ permissions: {
+ canResend: false,
+ },
+ });
+
+ expect(findResendInviteButton().exists()).toBe(false);
+ });
+ });
+});
diff --git a/spec/frontend/vue_shared/components/members/action_buttons/leave_button_spec.js b/spec/frontend/vue_shared/components/members/action_buttons/leave_button_spec.js
new file mode 100644
index 00000000000..00896b23b95
--- /dev/null
+++ b/spec/frontend/vue_shared/components/members/action_buttons/leave_button_spec.js
@@ -0,0 +1,59 @@
+import { shallowMount } from '@vue/test-utils';
+import { GlButton } from '@gitlab/ui';
+import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
+import LeaveButton from '~/vue_shared/components/members/action_buttons/leave_button.vue';
+import LeaveModal from '~/vue_shared/components/members/modals/leave_modal.vue';
+import { LEAVE_MODAL_ID } from '~/vue_shared/components/members/constants';
+import { member } from '../mock_data';
+
+describe('LeaveButton', () => {
+ let wrapper;
+
+ const createComponent = (propsData = {}) => {
+ wrapper = shallowMount(LeaveButton, {
+ propsData: {
+ member,
+ ...propsData,
+ },
+ directives: {
+ GlTooltip: createMockDirective(),
+ GlModal: createMockDirective(),
+ },
+ });
+ };
+
+ const findButton = () => wrapper.find(GlButton);
+
+ beforeEach(() => {
+ createComponent();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('displays a tooltip', () => {
+ const button = findButton();
+
+ expect(getBinding(button.element, 'gl-tooltip')).not.toBeUndefined();
+ expect(button.attributes('title')).toBe('Leave');
+ });
+
+ it('sets `aria-label` attribute', () => {
+ expect(findButton().attributes('aria-label')).toBe('Leave');
+ });
+
+ it('renders leave modal', () => {
+ const leaveModal = wrapper.find(LeaveModal);
+
+ expect(leaveModal.exists()).toBe(true);
+ expect(leaveModal.props('member')).toEqual(member);
+ });
+
+ it('triggers leave modal', () => {
+ const binding = getBinding(findButton().element, 'gl-modal');
+
+ expect(binding).not.toBeUndefined();
+ expect(binding.value).toBe(LEAVE_MODAL_ID);
+ });
+});
diff --git a/spec/frontend/vue_shared/components/members/action_buttons/remove_group_link_button_spec.js b/spec/frontend/vue_shared/components/members/action_buttons/remove_group_link_button_spec.js
new file mode 100644
index 00000000000..84fe1c51773
--- /dev/null
+++ b/spec/frontend/vue_shared/components/members/action_buttons/remove_group_link_button_spec.js
@@ -0,0 +1,64 @@
+import { mount, createLocalVue } from '@vue/test-utils';
+import Vuex from 'vuex';
+import { GlButton } from '@gitlab/ui';
+import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
+import RemoveGroupLinkButton from '~/vue_shared/components/members/action_buttons/remove_group_link_button.vue';
+import { group } from '../mock_data';
+
+const localVue = createLocalVue();
+localVue.use(Vuex);
+
+describe('RemoveGroupLinkButton', () => {
+ let wrapper;
+
+ const actions = {
+ showRemoveGroupLinkModal: jest.fn(),
+ };
+
+ const createStore = () => {
+ return new Vuex.Store({
+ actions,
+ });
+ };
+
+ const createComponent = () => {
+ wrapper = mount(RemoveGroupLinkButton, {
+ localVue,
+ store: createStore(),
+ propsData: {
+ groupLink: group,
+ },
+ directives: {
+ GlTooltip: createMockDirective(),
+ },
+ });
+ };
+
+ const findButton = () => wrapper.find(GlButton);
+
+ beforeEach(() => {
+ createComponent();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ wrapper = null;
+ });
+
+ it('displays a tooltip', () => {
+ const button = findButton();
+
+ expect(getBinding(button.element, 'gl-tooltip')).not.toBeUndefined();
+ expect(button.attributes('title')).toBe('Remove group');
+ });
+
+ it('sets `aria-label` attribute', () => {
+ expect(findButton().attributes('aria-label')).toBe('Remove group');
+ });
+
+ it('calls Vuex action to open remove group link modal when clicked', () => {
+ findButton().trigger('click');
+
+ expect(actions.showRemoveGroupLinkModal).toHaveBeenCalledWith(expect.any(Object), group);
+ });
+});
diff --git a/spec/frontend/vue_shared/components/members/action_buttons/remove_member_button_spec.js b/spec/frontend/vue_shared/components/members/action_buttons/remove_member_button_spec.js
new file mode 100644
index 00000000000..7aa30494234
--- /dev/null
+++ b/spec/frontend/vue_shared/components/members/action_buttons/remove_member_button_spec.js
@@ -0,0 +1,66 @@
+import { shallowMount, createLocalVue } from '@vue/test-utils';
+import Vuex from 'vuex';
+import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
+import RemoveMemberButton from '~/vue_shared/components/members/action_buttons/remove_member_button.vue';
+
+const localVue = createLocalVue();
+localVue.use(Vuex);
+
+describe('RemoveMemberButton', () => {
+ let wrapper;
+
+ const createStore = (state = {}) => {
+ return new Vuex.Store({
+ state: {
+ memberPath: '/groups/foo-bar/-/group_members/:id',
+ ...state,
+ },
+ });
+ };
+
+ const createComponent = (propsData = {}, state) => {
+ wrapper = shallowMount(RemoveMemberButton, {
+ localVue,
+ store: createStore(state),
+ propsData: {
+ memberId: 1,
+ message: 'Are you sure you want to remove John Smith?',
+ title: 'Remove member',
+ isAccessRequest: true,
+ ...propsData,
+ },
+ directives: {
+ GlTooltip: createMockDirective(),
+ },
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('sets attributes on button', () => {
+ createComponent();
+
+ expect(wrapper.attributes()).toMatchObject({
+ 'data-member-path': '/groups/foo-bar/-/group_members/1',
+ 'data-message': 'Are you sure you want to remove John Smith?',
+ 'data-is-access-request': 'true',
+ 'aria-label': 'Remove member',
+ title: 'Remove member',
+ icon: 'remove',
+ });
+ });
+
+ it('displays `title` prop as a tooltip', () => {
+ createComponent();
+
+ expect(getBinding(wrapper.element, 'gl-tooltip')).not.toBeUndefined();
+ });
+
+ it('has CSS class used by `remove_member_modal.vue`', () => {
+ createComponent();
+
+ expect(wrapper.classes()).toContain('js-remove-member-button');
+ });
+});
diff --git a/spec/frontend/vue_shared/components/members/action_buttons/resend_invite_button_spec.js b/spec/frontend/vue_shared/components/members/action_buttons/resend_invite_button_spec.js
new file mode 100644
index 00000000000..859fdd01043
--- /dev/null
+++ b/spec/frontend/vue_shared/components/members/action_buttons/resend_invite_button_spec.js
@@ -0,0 +1,66 @@
+import { shallowMount, createLocalVue } from '@vue/test-utils';
+import Vuex from 'vuex';
+import { GlButton } from '@gitlab/ui';
+import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
+import ResendInviteButton from '~/vue_shared/components/members/action_buttons/resend_invite_button.vue';
+
+jest.mock('~/lib/utils/csrf', () => ({ token: 'mock-csrf-token' }));
+
+const localVue = createLocalVue();
+localVue.use(Vuex);
+
+describe('ResendInviteButton', () => {
+ let wrapper;
+
+ const createStore = (state = {}) => {
+ return new Vuex.Store({
+ state: {
+ memberPath: '/groups/foo-bar/-/group_members/:id',
+ ...state,
+ },
+ });
+ };
+
+ const createComponent = (propsData = {}, state) => {
+ wrapper = shallowMount(ResendInviteButton, {
+ localVue,
+ store: createStore(state),
+ propsData: {
+ memberId: 1,
+ ...propsData,
+ },
+ directives: {
+ GlTooltip: createMockDirective(),
+ },
+ });
+ };
+
+ const findForm = () => wrapper.find('form');
+ const findButton = () => findForm().find(GlButton);
+
+ beforeEach(() => {
+ createComponent();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('displays a tooltip', () => {
+ expect(getBinding(findButton().element, 'gl-tooltip')).not.toBeUndefined();
+ expect(findButton().attributes('title')).toBe('Resend invite');
+ });
+
+ it('submits the form when button is clicked', () => {
+ expect(findButton().attributes('type')).toBe('submit');
+ });
+
+ it('displays form with correct action and inputs', () => {
+ expect(findForm().attributes('action')).toBe('/groups/foo-bar/-/group_members/1/resend_invite');
+ expect(
+ findForm()
+ .find('input[name="authenticity_token"]')
+ .attributes('value'),
+ ).toBe('mock-csrf-token');
+ });
+});
diff --git a/spec/frontend/vue_shared/components/members/action_buttons/user_action_buttons_spec.js b/spec/frontend/vue_shared/components/members/action_buttons/user_action_buttons_spec.js
new file mode 100644
index 00000000000..f766ad5b0d1
--- /dev/null
+++ b/spec/frontend/vue_shared/components/members/action_buttons/user_action_buttons_spec.js
@@ -0,0 +1,89 @@
+import { shallowMount } from '@vue/test-utils';
+import UserActionButtons from '~/vue_shared/components/members/action_buttons/user_action_buttons.vue';
+import RemoveMemberButton from '~/vue_shared/components/members/action_buttons/remove_member_button.vue';
+import LeaveButton from '~/vue_shared/components/members/action_buttons/leave_button.vue';
+import { member, orphanedMember } from '../mock_data';
+
+describe('UserActionButtons', () => {
+ let wrapper;
+
+ const createComponent = (propsData = {}) => {
+ wrapper = shallowMount(UserActionButtons, {
+ propsData: {
+ member,
+ isCurrentUser: false,
+ ...propsData,
+ },
+ });
+ };
+
+ const findRemoveMemberButton = () => wrapper.find(RemoveMemberButton);
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe('when user has `canRemove` permissions', () => {
+ beforeEach(() => {
+ createComponent({
+ permissions: {
+ canRemove: true,
+ },
+ });
+ });
+
+ it('renders remove member button', () => {
+ expect(findRemoveMemberButton().exists()).toBe(true);
+ });
+
+ it('sets props correctly', () => {
+ expect(findRemoveMemberButton().props()).toEqual({
+ memberId: member.id,
+ message: `Are you sure you want to remove ${member.user.name} from "${member.source.name}"`,
+ title: 'Remove member',
+ isAccessRequest: false,
+ icon: 'remove',
+ });
+ });
+
+ describe('when member is orphaned', () => {
+ it('sets `message` prop correctly', () => {
+ createComponent({
+ member: orphanedMember,
+ permissions: {
+ canRemove: true,
+ },
+ });
+
+ expect(findRemoveMemberButton().props('message')).toBe(
+ `Are you sure you want to remove this orphaned member from "${orphanedMember.source.name}"`,
+ );
+ });
+ });
+
+ describe('when member is the current user', () => {
+ it('renders leave button', () => {
+ createComponent({
+ isCurrentUser: true,
+ permissions: {
+ canRemove: true,
+ },
+ });
+
+ expect(wrapper.find(LeaveButton).exists()).toBe(true);
+ });
+ });
+ });
+
+ describe('when user does not have `canRemove` permissions', () => {
+ it('does not render remove member button', () => {
+ createComponent({
+ permissions: {
+ canRemove: false,
+ },
+ });
+
+ expect(findRemoveMemberButton().exists()).toBe(false);
+ });
+ });
+});
diff --git a/spec/frontend/vue_shared/components/members/avatars/group_avatar_spec.js b/spec/frontend/vue_shared/components/members/avatars/group_avatar_spec.js
new file mode 100644
index 00000000000..d6f5773295c
--- /dev/null
+++ b/spec/frontend/vue_shared/components/members/avatars/group_avatar_spec.js
@@ -0,0 +1,46 @@
+import { mount, createWrapper } from '@vue/test-utils';
+import { getByText as getByTextHelper } from '@testing-library/dom';
+import { GlAvatarLink } from '@gitlab/ui';
+import { group as member } from '../mock_data';
+import GroupAvatar from '~/vue_shared/components/members/avatars/group_avatar.vue';
+
+describe('MemberList', () => {
+ let wrapper;
+
+ const group = member.sharedWithGroup;
+
+ const createComponent = (propsData = {}) => {
+ wrapper = mount(GroupAvatar, {
+ propsData: {
+ member,
+ ...propsData,
+ },
+ });
+ };
+
+ const getByText = (text, options) =>
+ createWrapper(getByTextHelper(wrapper.element, text, options));
+
+ beforeEach(() => {
+ createComponent();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('renders link to group', () => {
+ const link = wrapper.find(GlAvatarLink);
+
+ expect(link.exists()).toBe(true);
+ expect(link.attributes('href')).toBe(group.webUrl);
+ });
+
+ it("renders group's full name", () => {
+ expect(getByText(group.fullName).exists()).toBe(true);
+ });
+
+ it("renders group's avatar", () => {
+ expect(wrapper.find('img').attributes('src')).toBe(group.avatarUrl);
+ });
+});
diff --git a/spec/frontend/vue_shared/components/members/avatars/invite_avatar_spec.js b/spec/frontend/vue_shared/components/members/avatars/invite_avatar_spec.js
new file mode 100644
index 00000000000..7948da7eb40
--- /dev/null
+++ b/spec/frontend/vue_shared/components/members/avatars/invite_avatar_spec.js
@@ -0,0 +1,38 @@
+import { mount, createWrapper } from '@vue/test-utils';
+import { getByText as getByTextHelper } from '@testing-library/dom';
+import { invite as member } from '../mock_data';
+import InviteAvatar from '~/vue_shared/components/members/avatars/invite_avatar.vue';
+
+describe('MemberList', () => {
+ let wrapper;
+
+ const { invite } = member;
+
+ const createComponent = (propsData = {}) => {
+ wrapper = mount(InviteAvatar, {
+ propsData: {
+ member,
+ ...propsData,
+ },
+ });
+ };
+
+ const getByText = (text, options) =>
+ createWrapper(getByTextHelper(wrapper.element, text, options));
+
+ beforeEach(() => {
+ createComponent();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('renders email as name', () => {
+ expect(getByText(invite.email).exists()).toBe(true);
+ });
+
+ it('renders avatar', () => {
+ expect(wrapper.find('img').attributes('src')).toBe(invite.avatarUrl);
+ });
+});
diff --git a/spec/frontend/vue_shared/components/members/avatars/user_avatar_spec.js b/spec/frontend/vue_shared/components/members/avatars/user_avatar_spec.js
new file mode 100644
index 00000000000..93d8e640968
--- /dev/null
+++ b/spec/frontend/vue_shared/components/members/avatars/user_avatar_spec.js
@@ -0,0 +1,115 @@
+import { mount, createWrapper } from '@vue/test-utils';
+import { within } from '@testing-library/dom';
+import { GlAvatarLink, GlBadge } from '@gitlab/ui';
+import { member as memberMock, orphanedMember } from '../mock_data';
+import UserAvatar from '~/vue_shared/components/members/avatars/user_avatar.vue';
+
+describe('UserAvatar', () => {
+ let wrapper;
+
+ const { user } = memberMock;
+
+ const createComponent = (propsData = {}) => {
+ wrapper = mount(UserAvatar, {
+ propsData: {
+ member: memberMock,
+ isCurrentUser: false,
+ ...propsData,
+ },
+ });
+ };
+
+ const getByText = (text, options) =>
+ createWrapper(within(wrapper.element).findByText(text, options));
+
+ const findStatusEmoji = emoji => wrapper.find(`gl-emoji[data-name="${emoji}"]`);
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it("renders link to user's profile", () => {
+ createComponent();
+
+ const link = wrapper.find(GlAvatarLink);
+
+ expect(link.exists()).toBe(true);
+ expect(link.attributes()).toMatchObject({
+ href: user.webUrl,
+ 'data-user-id': `${user.id}`,
+ 'data-username': user.username,
+ });
+ });
+
+ it("renders user's name", () => {
+ createComponent();
+
+ expect(getByText(user.name).exists()).toBe(true);
+ });
+
+ it("renders user's username", () => {
+ createComponent();
+
+ expect(getByText(`@${user.username}`).exists()).toBe(true);
+ });
+
+ it("renders user's avatar", () => {
+ createComponent();
+
+ expect(wrapper.find('img').attributes('src')).toBe(user.avatarUrl);
+ });
+
+ describe('when user property does not exist', () => {
+ it('displays an orphaned user', () => {
+ createComponent({ member: orphanedMember });
+
+ expect(getByText('Orphaned member').exists()).toBe(true);
+ });
+ });
+
+ describe('badges', () => {
+ it.each`
+ member | badgeText
+ ${{ ...memberMock, user: { ...memberMock.user, blocked: true } }} | ${'Blocked'}
+ ${{ ...memberMock, user: { ...memberMock.user, twoFactorEnabled: true } }} | ${'2FA'}
+ `('renders the "$badgeText" badge', ({ member, badgeText }) => {
+ createComponent({ member });
+
+ expect(wrapper.find(GlBadge).text()).toBe(badgeText);
+ });
+
+ it('renders the "It\'s you" badge when member is current user', () => {
+ createComponent({ isCurrentUser: true });
+
+ expect(getByText("It's you").exists()).toBe(true);
+ });
+ });
+
+ describe('user status', () => {
+ const emoji = 'island';
+
+ describe('when set', () => {
+ it('displays the status emoji', () => {
+ createComponent({
+ member: {
+ ...memberMock,
+ user: {
+ ...memberMock.user,
+ status: { emoji, messageHtml: 'On vacation' },
+ },
+ },
+ });
+
+ expect(findStatusEmoji(emoji).exists()).toBe(true);
+ });
+ });
+
+ describe('when not set', () => {
+ it('does not display status emoji', () => {
+ createComponent();
+
+ expect(findStatusEmoji(emoji).exists()).toBe(false);
+ });
+ });
+ });
+});
diff --git a/spec/frontend/vue_shared/components/members/mock_data.js b/spec/frontend/vue_shared/components/members/mock_data.js
new file mode 100644
index 00000000000..d7bb8c0d142
--- /dev/null
+++ b/spec/frontend/vue_shared/components/members/mock_data.js
@@ -0,0 +1,70 @@
+export const member = {
+ requestedAt: null,
+ canUpdate: false,
+ canRemove: false,
+ canOverride: false,
+ accessLevel: { integerValue: 50, stringValue: 'Owner' },
+ source: {
+ id: 178,
+ name: 'Foo Bar',
+ webUrl: 'https://gitlab.com/groups/foo-bar',
+ },
+ user: {
+ id: 123,
+ name: 'Administrator',
+ username: 'root',
+ webUrl: 'https://gitlab.com/root',
+ avatarUrl: 'https://www.gravatar.com/avatar/4816142ef496f956a277bedf1a40607b?s=80&d=identicon',
+ blocked: false,
+ twoFactorEnabled: false,
+ },
+ id: 238,
+ createdAt: '2020-07-17T16:22:46.923Z',
+ expiresAt: null,
+ usingLicense: false,
+ groupSso: false,
+ groupManagedAccount: false,
+ validRoles: {
+ Guest: 10,
+ Reporter: 20,
+ Developer: 30,
+ Maintainer: 40,
+ Owner: 50,
+ 'Minimal Access': 5,
+ },
+};
+
+export const group = {
+ accessLevel: { integerValue: 10, stringValue: 'Guest' },
+ sharedWithGroup: {
+ id: 24,
+ name: 'Commit451',
+ avatarUrl: '/uploads/-/system/user/avatar/1/avatar.png?width=40',
+ fullPath: 'parent-group/commit451',
+ fullName: 'Parent group / Commit451',
+ webUrl: 'https://gitlab.com/groups/parent-group/commit451',
+ },
+ id: 3,
+ createdAt: '2020-08-06T15:31:07.662Z',
+ expiresAt: null,
+ validRoles: { Guest: 10, Reporter: 20, Developer: 30, Maintainer: 40, Owner: 50 },
+};
+
+const { user, ...memberNoUser } = member;
+export const invite = {
+ ...memberNoUser,
+ invite: {
+ email: 'jewel@hudsonwalter.biz',
+ avatarUrl: 'https://www.gravatar.com/avatar/cbab7510da7eec2f60f638261b05436d?s=80&d=identicon',
+ canResend: true,
+ },
+};
+
+export const orphanedMember = memberNoUser;
+
+export const accessRequest = {
+ ...member,
+ requestedAt: '2020-07-17T16:22:46.923Z',
+};
+
+export const members = [member];
diff --git a/spec/frontend/vue_shared/components/members/modals/leave_modal_spec.js b/spec/frontend/vue_shared/components/members/modals/leave_modal_spec.js
new file mode 100644
index 00000000000..63de355a3c8
--- /dev/null
+++ b/spec/frontend/vue_shared/components/members/modals/leave_modal_spec.js
@@ -0,0 +1,91 @@
+import { mount, createLocalVue, createWrapper } from '@vue/test-utils';
+import { GlModal, GlForm } from '@gitlab/ui';
+import { nextTick } from 'vue';
+import { within } from '@testing-library/dom';
+import Vuex from 'vuex';
+import LeaveModal from '~/vue_shared/components/members/modals/leave_modal.vue';
+import { LEAVE_MODAL_ID } from '~/vue_shared/components/members/constants';
+import { member } from '../mock_data';
+
+jest.mock('~/lib/utils/csrf', () => ({ token: 'mock-csrf-token' }));
+
+const localVue = createLocalVue();
+localVue.use(Vuex);
+
+describe('LeaveModal', () => {
+ let wrapper;
+
+ const createStore = (state = {}) => {
+ return new Vuex.Store({
+ state: {
+ memberPath: '/groups/foo-bar/-/group_members/:id',
+ ...state,
+ },
+ });
+ };
+
+ const createComponent = (propsData = {}, state) => {
+ wrapper = mount(LeaveModal, {
+ localVue,
+ store: createStore(state),
+ propsData: {
+ member,
+ ...propsData,
+ },
+ attrs: {
+ static: true,
+ visible: true,
+ },
+ });
+ };
+
+ const findModal = () => wrapper.find(GlModal);
+
+ const findForm = () => findModal().find(GlForm);
+
+ const getByText = (text, options) =>
+ createWrapper(within(findModal().element).getByText(text, options));
+
+ beforeEach(async () => {
+ createComponent();
+ await nextTick();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('sets modal ID', () => {
+ expect(findModal().props('modalId')).toBe(LEAVE_MODAL_ID);
+ });
+
+ it('displays modal title', () => {
+ expect(getByText(`Leave "${member.source.name}"`).exists()).toBe(true);
+ });
+
+ it('displays modal body', () => {
+ expect(getByText(`Are you sure you want to leave "${member.source.name}"?`).exists()).toBe(
+ true,
+ );
+ });
+
+ it('displays form with correct action and inputs', () => {
+ const form = findForm();
+
+ expect(form.attributes('action')).toBe('/groups/foo-bar/-/group_members/leave');
+ expect(form.find('input[name="_method"]').attributes('value')).toBe('delete');
+ expect(form.find('input[name="authenticity_token"]').attributes('value')).toBe(
+ 'mock-csrf-token',
+ );
+ });
+
+ it('submits the form when "Leave" button is clicked', () => {
+ const submitSpy = jest.spyOn(findForm().element, 'submit');
+
+ getByText('Leave').trigger('click');
+
+ expect(submitSpy).toHaveBeenCalled();
+
+ submitSpy.mockRestore();
+ });
+});
diff --git a/spec/frontend/vue_shared/components/members/modals/remove_group_link_modal_spec.js b/spec/frontend/vue_shared/components/members/modals/remove_group_link_modal_spec.js
new file mode 100644
index 00000000000..84da051792d
--- /dev/null
+++ b/spec/frontend/vue_shared/components/members/modals/remove_group_link_modal_spec.js
@@ -0,0 +1,106 @@
+import { mount, createLocalVue, createWrapper } from '@vue/test-utils';
+import { GlModal, GlForm } from '@gitlab/ui';
+import { nextTick } from 'vue';
+import { within } from '@testing-library/dom';
+import Vuex from 'vuex';
+import RemoveGroupLinkModal from '~/vue_shared/components/members/modals/remove_group_link_modal.vue';
+import { REMOVE_GROUP_LINK_MODAL_ID } from '~/vue_shared/components/members/constants';
+import { group } from '../mock_data';
+
+jest.mock('~/lib/utils/csrf', () => ({ token: 'mock-csrf-token' }));
+
+const localVue = createLocalVue();
+localVue.use(Vuex);
+
+describe('RemoveGroupLinkModal', () => {
+ let wrapper;
+
+ const actions = {
+ hideRemoveGroupLinkModal: jest.fn(),
+ };
+
+ const createStore = (state = {}) => {
+ return new Vuex.Store({
+ state: {
+ memberPath: '/groups/foo-bar/-/group_links/:id',
+ groupLinkToRemove: group,
+ removeGroupLinkModalVisible: true,
+ ...state,
+ },
+ actions,
+ });
+ };
+
+ const createComponent = state => {
+ wrapper = mount(RemoveGroupLinkModal, {
+ localVue,
+ store: createStore(state),
+ attrs: {
+ static: true,
+ },
+ });
+ };
+
+ const findModal = () => wrapper.find(GlModal);
+ const findForm = () => findModal().find(GlForm);
+ const getByText = (text, options) =>
+ createWrapper(within(findModal().element).getByText(text, options));
+
+ afterEach(() => {
+ wrapper.destroy();
+ wrapper = null;
+ });
+
+ describe('when modal is open', () => {
+ beforeEach(async () => {
+ createComponent();
+ await nextTick();
+ });
+
+ it('sets modal ID', () => {
+ expect(findModal().props('modalId')).toBe(REMOVE_GROUP_LINK_MODAL_ID);
+ });
+
+ it('displays modal title', () => {
+ expect(getByText(`Remove "${group.sharedWithGroup.fullName}"`).exists()).toBe(true);
+ });
+
+ it('displays modal body', () => {
+ expect(
+ getByText(`Are you sure you want to remove "${group.sharedWithGroup.fullName}"?`).exists(),
+ ).toBe(true);
+ });
+
+ it('displays form with correct action and inputs', () => {
+ const form = findForm();
+
+ expect(form.attributes('action')).toBe(`/groups/foo-bar/-/group_links/${group.id}`);
+ expect(form.find('input[name="_method"]').attributes('value')).toBe('delete');
+ expect(form.find('input[name="authenticity_token"]').attributes('value')).toBe(
+ 'mock-csrf-token',
+ );
+ });
+
+ it('submits the form when "Remove group" button is clicked', () => {
+ const submitSpy = jest.spyOn(findForm().element, 'submit');
+
+ getByText('Remove group').trigger('click');
+
+ expect(submitSpy).toHaveBeenCalled();
+
+ submitSpy.mockRestore();
+ });
+
+ it('calls `hideRemoveGroupLinkModal` action when modal is closed', () => {
+ getByText('Cancel').trigger('click');
+
+ expect(actions.hideRemoveGroupLinkModal).toHaveBeenCalled();
+ });
+ });
+
+ it('modal does not show when `removeGroupLinkModalVisible` is `false`', () => {
+ createComponent({ removeGroupLinkModalVisible: false });
+
+ expect(findModal().vm.$attrs.visible).toBe(false);
+ });
+});
diff --git a/spec/frontend/vue_shared/components/members/table/created_at_spec.js b/spec/frontend/vue_shared/components/members/table/created_at_spec.js
new file mode 100644
index 00000000000..cf3821baf44
--- /dev/null
+++ b/spec/frontend/vue_shared/components/members/table/created_at_spec.js
@@ -0,0 +1,61 @@
+import { mount, createWrapper } from '@vue/test-utils';
+import { within } from '@testing-library/dom';
+import { useFakeDate } from 'helpers/fake_date';
+import CreatedAt from '~/vue_shared/components/members/table/created_at.vue';
+import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
+
+describe('CreatedAt', () => {
+ // March 15th, 2020
+ useFakeDate(2020, 2, 15);
+
+ const date = '2020-03-01T00:00:00.000';
+ const dateTimeAgo = '2 weeks ago';
+
+ let wrapper;
+
+ const createComponent = propsData => {
+ wrapper = mount(CreatedAt, {
+ propsData: {
+ date,
+ ...propsData,
+ },
+ });
+ };
+
+ const getByText = (text, options) =>
+ createWrapper(within(wrapper.element).getByText(text, options));
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe('created at text', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('displays created at text', () => {
+ expect(getByText(dateTimeAgo).exists()).toBe(true);
+ });
+
+ it('uses `TimeAgoTooltip` component to display tooltip', () => {
+ expect(wrapper.find(TimeAgoTooltip).exists()).toBe(true);
+ });
+ });
+
+ describe('when `createdBy` prop is provided', () => {
+ it('displays a link to the user that created the member', () => {
+ createComponent({
+ createdBy: {
+ name: 'Administrator',
+ webUrl: 'https://gitlab.com/root',
+ },
+ });
+
+ const link = getByText('Administrator');
+
+ expect(link.exists()).toBe(true);
+ expect(link.attributes('href')).toBe('https://gitlab.com/root');
+ });
+ });
+});
diff --git a/spec/frontend/vue_shared/components/members/table/expires_at_spec.js b/spec/frontend/vue_shared/components/members/table/expires_at_spec.js
new file mode 100644
index 00000000000..95ae251b0fd
--- /dev/null
+++ b/spec/frontend/vue_shared/components/members/table/expires_at_spec.js
@@ -0,0 +1,86 @@
+import { mount, createWrapper } from '@vue/test-utils';
+import { within } from '@testing-library/dom';
+import { useFakeDate } from 'helpers/fake_date';
+import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
+import ExpiresAt from '~/vue_shared/components/members/table/expires_at.vue';
+
+describe('ExpiresAt', () => {
+ // March 15th, 2020
+ useFakeDate(2020, 2, 15);
+
+ let wrapper;
+
+ const createComponent = propsData => {
+ wrapper = mount(ExpiresAt, {
+ propsData,
+ directives: {
+ GlTooltip: createMockDirective(),
+ },
+ });
+ };
+
+ const getByText = (text, options) =>
+ createWrapper(within(wrapper.element).getByText(text, options));
+
+ const getTooltipDirective = elementWrapper => getBinding(elementWrapper.element, 'gl-tooltip');
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe('when no expiration date is set', () => {
+ it('displays "No expiration set"', () => {
+ createComponent({ date: null });
+
+ expect(getByText('No expiration set').exists()).toBe(true);
+ });
+ });
+
+ describe('when expiration date is in the past', () => {
+ let expiredText;
+
+ beforeEach(() => {
+ createComponent({ date: '2019-03-15T00:00:00.000' });
+
+ expiredText = getByText('Expired');
+ });
+
+ it('displays "Expired"', () => {
+ expect(expiredText.exists()).toBe(true);
+ expect(expiredText.classes()).toContain('gl-text-red-500');
+ });
+
+ it('displays tooltip with formatted date', () => {
+ const tooltipDirective = getTooltipDirective(expiredText);
+
+ expect(tooltipDirective).not.toBeUndefined();
+ expect(expiredText.attributes('title')).toBe('Mar 15, 2019 12:00am GMT+0000');
+ });
+ });
+
+ describe('when expiration date is in the future', () => {
+ it.each`
+ date | expected | warningColor
+ ${'2020-03-23T00:00:00.000'} | ${'in 8 days'} | ${false}
+ ${'2020-03-20T00:00:00.000'} | ${'in 5 days'} | ${true}
+ ${'2020-03-16T00:00:00.000'} | ${'in 1 day'} | ${true}
+ ${'2020-03-15T05:00:00.000'} | ${'in about 5 hours'} | ${true}
+ ${'2020-03-15T01:00:00.000'} | ${'in about 1 hour'} | ${true}
+ ${'2020-03-15T00:30:00.000'} | ${'in 30 minutes'} | ${true}
+ ${'2020-03-15T00:01:15.000'} | ${'in 1 minute'} | ${true}
+ ${'2020-03-15T00:00:15.000'} | ${'in less than a minute'} | ${true}
+ `('displays "$expected"', ({ date, expected, warningColor }) => {
+ createComponent({ date });
+
+ const expiredText = getByText(expected);
+
+ expect(expiredText.exists()).toBe(true);
+
+ if (warningColor) {
+ expect(expiredText.classes()).toContain('gl-text-orange-500');
+ } else {
+ expect(expiredText.classes()).not.toContain('gl-text-orange-500');
+ }
+ });
+ });
+});
diff --git a/spec/frontend/vue_shared/components/members/table/member_action_buttons_spec.js b/spec/frontend/vue_shared/components/members/table/member_action_buttons_spec.js
new file mode 100644
index 00000000000..e55d9b6be2a
--- /dev/null
+++ b/spec/frontend/vue_shared/components/members/table/member_action_buttons_spec.js
@@ -0,0 +1,43 @@
+import { shallowMount } from '@vue/test-utils';
+import { MEMBER_TYPES } from '~/vue_shared/components/members/constants';
+import { member as memberMock, group, invite, accessRequest } from '../mock_data';
+import MemberActionButtons from '~/vue_shared/components/members/table/member_action_buttons.vue';
+import UserActionButtons from '~/vue_shared/components/members/action_buttons/user_action_buttons.vue';
+import GroupActionButtons from '~/vue_shared/components/members/action_buttons/group_action_buttons.vue';
+import InviteActionButtons from '~/vue_shared/components/members/action_buttons/invite_action_buttons.vue';
+import AccessRequestActionButtons from '~/vue_shared/components/members/action_buttons/access_request_action_buttons.vue';
+
+describe('MemberActionButtons', () => {
+ let wrapper;
+
+ const createComponent = (propsData = {}) => {
+ wrapper = shallowMount(MemberActionButtons, {
+ propsData: {
+ isCurrentUser: false,
+ permissions: {
+ canRemove: true,
+ },
+ ...propsData,
+ },
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ test.each`
+ memberType | member | expectedComponent | expectedComponentName
+ ${MEMBER_TYPES.user} | ${memberMock} | ${UserActionButtons} | ${'UserActionButtons'}
+ ${MEMBER_TYPES.group} | ${group} | ${GroupActionButtons} | ${'GroupActionButtons'}
+ ${MEMBER_TYPES.invite} | ${invite} | ${InviteActionButtons} | ${'InviteActionButtons'}
+ ${MEMBER_TYPES.accessRequest} | ${accessRequest} | ${AccessRequestActionButtons} | ${'AccessRequestActionButtons'}
+ `(
+ 'renders $expectedComponentName when `memberType` is $memberType',
+ ({ memberType, member, expectedComponent }) => {
+ createComponent({ memberType, member });
+
+ expect(wrapper.find(expectedComponent).exists()).toBe(true);
+ },
+ );
+});
diff --git a/spec/frontend/vue_shared/components/members/table/member_avatar_spec.js b/spec/frontend/vue_shared/components/members/table/member_avatar_spec.js
new file mode 100644
index 00000000000..a171dd830c1
--- /dev/null
+++ b/spec/frontend/vue_shared/components/members/table/member_avatar_spec.js
@@ -0,0 +1,39 @@
+import { shallowMount } from '@vue/test-utils';
+import { MEMBER_TYPES } from '~/vue_shared/components/members/constants';
+import { member as memberMock, group, invite, accessRequest } from '../mock_data';
+import MemberAvatar from '~/vue_shared/components/members/table/member_avatar.vue';
+import UserAvatar from '~/vue_shared/components/members/avatars/user_avatar.vue';
+import GroupAvatar from '~/vue_shared/components/members/avatars/group_avatar.vue';
+import InviteAvatar from '~/vue_shared/components/members/avatars/invite_avatar.vue';
+
+describe('MemberList', () => {
+ let wrapper;
+
+ const createComponent = propsData => {
+ wrapper = shallowMount(MemberAvatar, {
+ propsData: {
+ isCurrentUser: false,
+ ...propsData,
+ },
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ test.each`
+ memberType | member | expectedComponent | expectedComponentName
+ ${MEMBER_TYPES.user} | ${memberMock} | ${UserAvatar} | ${'UserAvatar'}
+ ${MEMBER_TYPES.group} | ${group} | ${GroupAvatar} | ${'GroupAvatar'}
+ ${MEMBER_TYPES.invite} | ${invite} | ${InviteAvatar} | ${'InviteAvatar'}
+ ${MEMBER_TYPES.accessRequest} | ${accessRequest} | ${UserAvatar} | ${'UserAvatar'}
+ `(
+ 'renders $expectedComponentName when `memberType` is $memberType',
+ ({ memberType, member, expectedComponent }) => {
+ createComponent({ memberType, member });
+
+ expect(wrapper.find(expectedComponent).exists()).toBe(true);
+ },
+ );
+});
diff --git a/spec/frontend/vue_shared/components/members/table/member_source_spec.js b/spec/frontend/vue_shared/components/members/table/member_source_spec.js
new file mode 100644
index 00000000000..8b914d76674
--- /dev/null
+++ b/spec/frontend/vue_shared/components/members/table/member_source_spec.js
@@ -0,0 +1,71 @@
+import { mount, createWrapper } from '@vue/test-utils';
+import { getByText as getByTextHelper } from '@testing-library/dom';
+import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
+import MemberSource from '~/vue_shared/components/members/table/member_source.vue';
+
+describe('MemberSource', () => {
+ let wrapper;
+
+ const createComponent = propsData => {
+ wrapper = mount(MemberSource, {
+ propsData: {
+ memberSource: {
+ id: 102,
+ name: 'Foo bar',
+ webUrl: 'https://gitlab.com/groups/foo-bar',
+ },
+ ...propsData,
+ },
+ directives: {
+ GlTooltip: createMockDirective(),
+ },
+ });
+ };
+
+ const getByText = (text, options) =>
+ createWrapper(getByTextHelper(wrapper.element, text, options));
+
+ const getTooltipDirective = elementWrapper => getBinding(elementWrapper.element, 'gl-tooltip');
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe('direct member', () => {
+ it('displays "Direct member"', () => {
+ createComponent({
+ isDirectMember: true,
+ });
+
+ expect(getByText('Direct member').exists()).toBe(true);
+ });
+ });
+
+ describe('inherited member', () => {
+ let sourceGroupLink;
+
+ beforeEach(() => {
+ createComponent({
+ isDirectMember: false,
+ });
+
+ sourceGroupLink = getByText('Foo bar');
+ });
+
+ it('displays a link to source group', () => {
+ createComponent({
+ isDirectMember: false,
+ });
+
+ expect(sourceGroupLink.exists()).toBe(true);
+ expect(sourceGroupLink.attributes('href')).toBe('https://gitlab.com/groups/foo-bar');
+ });
+
+ it('displays tooltip with "Inherited"', () => {
+ const tooltipDirective = getTooltipDirective(sourceGroupLink);
+
+ expect(tooltipDirective).not.toBeUndefined();
+ expect(sourceGroupLink.attributes('title')).toBe('Inherited');
+ });
+ });
+});
diff --git a/spec/frontend/vue_shared/components/members/table/member_table_cell_spec.js b/spec/frontend/vue_shared/components/members/table/member_table_cell_spec.js
new file mode 100644
index 00000000000..ba693975a88
--- /dev/null
+++ b/spec/frontend/vue_shared/components/members/table/member_table_cell_spec.js
@@ -0,0 +1,251 @@
+import { mount, createLocalVue } from '@vue/test-utils';
+import Vuex from 'vuex';
+import { MEMBER_TYPES } from '~/vue_shared/components/members/constants';
+import { member as memberMock, group, invite, accessRequest } from '../mock_data';
+import MembersTableCell from '~/vue_shared/components/members/table/members_table_cell.vue';
+
+describe('MemberList', () => {
+ const WrappedComponent = {
+ props: {
+ memberType: {
+ type: String,
+ required: true,
+ },
+ isDirectMember: {
+ type: Boolean,
+ required: true,
+ },
+ isCurrentUser: {
+ type: Boolean,
+ required: true,
+ },
+ permissions: {
+ type: Object,
+ required: true,
+ },
+ },
+ render(createElement) {
+ return createElement('div', this.memberType);
+ },
+ };
+
+ const localVue = createLocalVue();
+ localVue.use(Vuex);
+ localVue.component('wrapped-component', WrappedComponent);
+
+ const createStore = (state = {}) => {
+ return new Vuex.Store({
+ state: {
+ sourceId: 1,
+ currentUserId: 1,
+ ...state,
+ },
+ });
+ };
+
+ let wrapper;
+
+ const createComponent = (propsData, state = {}) => {
+ wrapper = mount(MembersTableCell, {
+ localVue,
+ propsData,
+ store: createStore(state),
+ scopedSlots: {
+ default: `
+ <wrapped-component
+ :member-type="props.memberType"
+ :is-direct-member="props.isDirectMember"
+ :is-current-user="props.isCurrentUser"
+ :permissions="props.permissions"
+ />
+ `,
+ },
+ });
+ };
+
+ const findWrappedComponent = () => wrapper.find(WrappedComponent);
+
+ const memberCurrentUser = {
+ ...memberMock,
+ user: {
+ ...memberMock.user,
+ id: 1,
+ },
+ };
+
+ const createComponentWithDirectMember = (member = {}) => {
+ createComponent({
+ member: {
+ ...memberMock,
+ source: {
+ ...memberMock.source,
+ id: 1,
+ },
+ ...member,
+ },
+ });
+ };
+ const createComponentWithInheritedMember = (member = {}) => {
+ createComponent({
+ member: { ...memberMock, ...member },
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ wrapper = null;
+ });
+
+ test.each`
+ member | expectedMemberType
+ ${memberMock} | ${MEMBER_TYPES.user}
+ ${group} | ${MEMBER_TYPES.group}
+ ${invite} | ${MEMBER_TYPES.invite}
+ ${accessRequest} | ${MEMBER_TYPES.accessRequest}
+ `(
+ 'sets scoped slot prop `memberType` to $expectedMemberType',
+ ({ member, expectedMemberType }) => {
+ createComponent({ member });
+
+ expect(findWrappedComponent().props('memberType')).toBe(expectedMemberType);
+ },
+ );
+
+ describe('isDirectMember', () => {
+ it('returns `true` when member source has same ID as `sourceId`', () => {
+ createComponentWithDirectMember();
+
+ expect(findWrappedComponent().props('isDirectMember')).toBe(true);
+ });
+
+ it('returns `false` when member is inherited', () => {
+ createComponentWithInheritedMember();
+
+ expect(findWrappedComponent().props('isDirectMember')).toBe(false);
+ });
+
+ it('returns `true` for linked groups', () => {
+ createComponent({
+ member: group,
+ });
+
+ expect(findWrappedComponent().props('isDirectMember')).toBe(true);
+ });
+ });
+
+ describe('isCurrentUser', () => {
+ it('returns `true` when `member.user` has the same ID as `currentUserId`', () => {
+ createComponent({
+ member: memberCurrentUser,
+ });
+
+ expect(findWrappedComponent().props('isCurrentUser')).toBe(true);
+ });
+
+ it('returns `false` when `member.user` does not have the same ID as `currentUserId`', () => {
+ createComponent({
+ member: memberMock,
+ });
+
+ expect(findWrappedComponent().props('isCurrentUser')).toBe(false);
+ });
+ });
+
+ describe('permissions', () => {
+ describe('canRemove', () => {
+ describe('for a direct member', () => {
+ it('returns `true` when `canRemove` is `true`', () => {
+ createComponentWithDirectMember({
+ canRemove: true,
+ });
+
+ expect(findWrappedComponent().props('permissions').canRemove).toBe(true);
+ });
+
+ it('returns `false` when `canRemove` is `false`', () => {
+ createComponentWithDirectMember({
+ canRemove: false,
+ });
+
+ expect(findWrappedComponent().props('permissions').canRemove).toBe(false);
+ });
+ });
+
+ describe('for an inherited member', () => {
+ it('returns `false`', () => {
+ createComponentWithInheritedMember();
+
+ expect(findWrappedComponent().props('permissions').canRemove).toBe(false);
+ });
+ });
+ });
+
+ describe('canResend', () => {
+ describe('when member type is `invite`', () => {
+ it('returns `true` when `canResend` is `true`', () => {
+ createComponent({
+ member: invite,
+ });
+
+ expect(findWrappedComponent().props('permissions').canResend).toBe(true);
+ });
+
+ it('returns `false` when `canResend` is `false`', () => {
+ createComponent({
+ member: {
+ ...invite,
+ invite: {
+ ...invite,
+ canResend: false,
+ },
+ },
+ });
+
+ expect(findWrappedComponent().props('permissions').canResend).toBe(false);
+ });
+ });
+
+ describe('when member type is not `invite`', () => {
+ it('returns `false`', () => {
+ createComponent({ member: memberMock });
+
+ expect(findWrappedComponent().props('permissions').canResend).toBe(false);
+ });
+ });
+ });
+
+ describe('canUpdate', () => {
+ describe('for a direct member', () => {
+ it('returns `true` when `canUpdate` is `true`', () => {
+ createComponentWithDirectMember({
+ canUpdate: true,
+ });
+
+ expect(findWrappedComponent().props('permissions').canUpdate).toBe(true);
+ });
+
+ it('returns `false` when `canUpdate` is `false`', () => {
+ createComponentWithDirectMember({
+ canUpdate: false,
+ });
+
+ expect(findWrappedComponent().props('permissions').canUpdate).toBe(false);
+ });
+
+ it('returns `false` for current user', () => {
+ createComponentWithDirectMember(memberCurrentUser);
+
+ expect(findWrappedComponent().props('permissions').canUpdate).toBe(false);
+ });
+ });
+
+ describe('for an inherited member', () => {
+ it('returns `false`', () => {
+ createComponentWithInheritedMember();
+
+ expect(findWrappedComponent().props('permissions').canUpdate).toBe(false);
+ });
+ });
+ });
+ });
+});
diff --git a/spec/frontend/vue_shared/components/members/table/members_table_spec.js b/spec/frontend/vue_shared/components/members/table/members_table_spec.js
new file mode 100644
index 00000000000..20c1c26d2ee
--- /dev/null
+++ b/spec/frontend/vue_shared/components/members/table/members_table_spec.js
@@ -0,0 +1,141 @@
+import { mount, createLocalVue, createWrapper } from '@vue/test-utils';
+import Vuex from 'vuex';
+import {
+ getByText as getByTextHelper,
+ getByTestId as getByTestIdHelper,
+} from '@testing-library/dom';
+import { GlBadge } from '@gitlab/ui';
+import MembersTable from '~/vue_shared/components/members/table/members_table.vue';
+import MemberAvatar from '~/vue_shared/components/members/table/member_avatar.vue';
+import MemberSource from '~/vue_shared/components/members/table/member_source.vue';
+import ExpiresAt from '~/vue_shared/components/members/table/expires_at.vue';
+import CreatedAt from '~/vue_shared/components/members/table/created_at.vue';
+import RoleDropdown from '~/vue_shared/components/members/table/role_dropdown.vue';
+import MemberActionButtons from '~/vue_shared/components/members/table/member_action_buttons.vue';
+import * as initUserPopovers from '~/user_popovers';
+import { member as memberMock, invite, accessRequest } from '../mock_data';
+
+const localVue = createLocalVue();
+localVue.use(Vuex);
+
+describe('MemberList', () => {
+ let wrapper;
+
+ const createStore = (state = {}) => {
+ return new Vuex.Store({
+ state: {
+ members: [],
+ tableFields: [],
+ sourceId: 1,
+ ...state,
+ },
+ });
+ };
+
+ const createComponent = state => {
+ wrapper = mount(MembersTable, {
+ localVue,
+ store: createStore(state),
+ stubs: [
+ 'member-avatar',
+ 'member-source',
+ 'expires-at',
+ 'created-at',
+ 'member-action-buttons',
+ 'role-dropdown',
+ 'remove-group-link-modal',
+ ],
+ });
+ };
+
+ const getByText = (text, options) =>
+ createWrapper(getByTextHelper(wrapper.element, text, options));
+
+ const getByTestId = (id, options) =>
+ createWrapper(getByTestIdHelper(wrapper.element, id, options));
+
+ afterEach(() => {
+ wrapper.destroy();
+ wrapper = null;
+ });
+
+ describe('fields', () => {
+ const memberCanUpdate = {
+ ...memberMock,
+ canUpdate: true,
+ source: { ...memberMock.source, id: 1 },
+ };
+
+ it.each`
+ field | label | member | expectedComponent
+ ${'account'} | ${'Account'} | ${memberMock} | ${MemberAvatar}
+ ${'source'} | ${'Source'} | ${memberMock} | ${MemberSource}
+ ${'granted'} | ${'Access granted'} | ${memberMock} | ${CreatedAt}
+ ${'invited'} | ${'Invited'} | ${invite} | ${CreatedAt}
+ ${'requested'} | ${'Requested'} | ${accessRequest} | ${CreatedAt}
+ ${'expires'} | ${'Access expires'} | ${memberMock} | ${ExpiresAt}
+ ${'maxRole'} | ${'Max role'} | ${memberCanUpdate} | ${RoleDropdown}
+ ${'expiration'} | ${'Expiration'} | ${memberMock} | ${null}
+ `('renders the $label field', ({ field, label, member, expectedComponent }) => {
+ createComponent({
+ members: [member],
+ tableFields: [field],
+ });
+
+ expect(getByText(label, { selector: '[role="columnheader"]' }).exists()).toBe(true);
+
+ if (expectedComponent) {
+ expect(
+ wrapper
+ .find(`[data-label="${label}"][role="cell"]`)
+ .find(expectedComponent)
+ .exists(),
+ ).toBe(true);
+ }
+ });
+
+ it('renders "Actions" field for screen readers', () => {
+ createComponent({ members: [memberMock], tableFields: ['actions'] });
+
+ const actionField = getByTestId('col-actions');
+
+ expect(actionField.exists()).toBe(true);
+ expect(actionField.classes('gl-sr-only')).toBe(true);
+ expect(
+ wrapper
+ .find(`[data-label="Actions"][role="cell"]`)
+ .find(MemberActionButtons)
+ .exists(),
+ ).toBe(true);
+ });
+ });
+
+ describe('when `members` is an empty array', () => {
+ it('displays a "No members found" message', () => {
+ createComponent();
+
+ expect(getByText('No members found').exists()).toBe(true);
+ });
+ });
+
+ describe('when member can not be updated', () => {
+ it('renders badge in "Max role" field', () => {
+ createComponent({ members: [memberMock], tableFields: ['maxRole'] });
+
+ expect(
+ wrapper
+ .find(`[data-label="Max role"][role="cell"]`)
+ .find(GlBadge)
+ .text(),
+ ).toBe(memberMock.accessLevel.stringValue);
+ });
+ });
+
+ it('initializes user popovers when mounted', () => {
+ const initUserPopoversMock = jest.spyOn(initUserPopovers, 'default');
+
+ createComponent();
+
+ expect(initUserPopoversMock).toHaveBeenCalled();
+ });
+});
diff --git a/spec/frontend/vue_shared/components/members/table/role_dropdown_spec.js b/spec/frontend/vue_shared/components/members/table/role_dropdown_spec.js
new file mode 100644
index 00000000000..1e47953a510
--- /dev/null
+++ b/spec/frontend/vue_shared/components/members/table/role_dropdown_spec.js
@@ -0,0 +1,150 @@
+import { mount, createWrapper, createLocalVue } from '@vue/test-utils';
+import Vuex from 'vuex';
+import { nextTick } from 'vue';
+import { within } from '@testing-library/dom';
+import { GlDropdown, GlDropdownItem } from '@gitlab/ui';
+import { GlBreakpointInstance as bp } from '@gitlab/ui/dist/utils';
+import waitForPromises from 'helpers/wait_for_promises';
+import RoleDropdown from '~/vue_shared/components/members/table/role_dropdown.vue';
+import { member } from '../mock_data';
+
+const localVue = createLocalVue();
+localVue.use(Vuex);
+
+describe('RoleDropdown', () => {
+ let wrapper;
+ let actions;
+ const $toast = {
+ show: jest.fn(),
+ };
+
+ const createStore = () => {
+ actions = {
+ updateMemberRole: jest.fn(() => Promise.resolve()),
+ };
+
+ return new Vuex.Store({ actions });
+ };
+
+ const createComponent = (propsData = {}) => {
+ wrapper = mount(RoleDropdown, {
+ propsData: {
+ member,
+ ...propsData,
+ },
+ localVue,
+ store: createStore(),
+ mocks: {
+ $toast,
+ },
+ });
+ };
+
+ const getDropdownMenu = () => within(wrapper.element).getByRole('menu');
+ const getByTextInDropdownMenu = (text, options = {}) =>
+ createWrapper(within(getDropdownMenu()).getByText(text, options));
+ const getDropdownItemByText = text =>
+ createWrapper(
+ within(getDropdownMenu())
+ .getByText(text, { selector: '[role="menuitem"] p' })
+ .closest('[role="menuitem"]'),
+ );
+ const getCheckedDropdownItem = () =>
+ wrapper
+ .findAll(GlDropdownItem)
+ .wrappers.find(dropdownItemWrapper => dropdownItemWrapper.props('isChecked'));
+
+ const findDropdownToggle = () => wrapper.find('button[aria-haspopup="true"]');
+ const findDropdown = () => wrapper.find(GlDropdown);
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe('when dropdown is open', () => {
+ beforeEach(done => {
+ createComponent();
+
+ findDropdownToggle().trigger('click');
+ wrapper.vm.$root.$on('bv::dropdown::shown', () => {
+ done();
+ });
+ });
+
+ it('renders all valid roles', () => {
+ Object.keys(member.validRoles).forEach(role => {
+ expect(getDropdownItemByText(role).exists()).toBe(true);
+ });
+ });
+
+ it('renders dropdown header', () => {
+ expect(getByTextInDropdownMenu('Change permissions').exists()).toBe(true);
+ });
+
+ it('sets dropdown toggle and checks selected role', () => {
+ expect(findDropdownToggle().text()).toBe('Owner');
+ expect(getCheckedDropdownItem().text()).toBe('Owner');
+ });
+
+ describe('when dropdown item is selected', () => {
+ it('does nothing if the item selected was already selected', () => {
+ getDropdownItemByText('Owner').trigger('click');
+
+ expect(actions.updateMemberRole).not.toHaveBeenCalled();
+ });
+
+ it('calls `updateMemberRole` Vuex action', () => {
+ getDropdownItemByText('Developer').trigger('click');
+
+ expect(actions.updateMemberRole).toHaveBeenCalledWith(expect.any(Object), {
+ memberId: member.id,
+ accessLevel: { integerValue: 30, stringValue: 'Developer' },
+ });
+ });
+
+ it('displays toast when successful', async () => {
+ getDropdownItemByText('Developer').trigger('click');
+
+ await waitForPromises();
+
+ expect($toast.show).toHaveBeenCalledWith('Role updated successfully.');
+ });
+
+ it('disables dropdown while waiting for `updateMemberRole` to resolve', async () => {
+ getDropdownItemByText('Developer').trigger('click');
+
+ await nextTick();
+
+ expect(findDropdown().attributes('disabled')).toBe('disabled');
+
+ await waitForPromises();
+
+ expect(findDropdown().attributes('disabled')).toBeUndefined();
+ });
+ });
+ });
+
+ it("sets initial dropdown toggle value to member's role", () => {
+ createComponent();
+
+ expect(findDropdownToggle().text()).toBe('Owner');
+ });
+
+ it('sets the dropdown alignment to right on mobile', async () => {
+ jest.spyOn(bp, 'isDesktop').mockReturnValue(false);
+ createComponent();
+
+ await nextTick();
+
+ expect(findDropdown().attributes('right')).toBe('true');
+ });
+
+ it('sets the dropdown alignment to left on desktop', async () => {
+ jest.spyOn(bp, 'isDesktop').mockReturnValue(true);
+ createComponent();
+
+ await nextTick();
+
+ expect(findDropdown().attributes('right')).toBeUndefined();
+ });
+});
diff --git a/spec/frontend/vue_shared/components/members/utils_spec.js b/spec/frontend/vue_shared/components/members/utils_spec.js
new file mode 100644
index 00000000000..f183abc08d6
--- /dev/null
+++ b/spec/frontend/vue_shared/components/members/utils_spec.js
@@ -0,0 +1,29 @@
+import { generateBadges } from '~/vue_shared/components/members/utils';
+import { member as memberMock } from './mock_data';
+
+describe('Members Utils', () => {
+ describe('generateBadges', () => {
+ it('has correct properties for each badge', () => {
+ const badges = generateBadges(memberMock, true);
+
+ badges.forEach(badge => {
+ expect(badge).toEqual(
+ expect.objectContaining({
+ show: expect.any(Boolean),
+ text: expect.any(String),
+ variant: expect.stringMatching(/muted|neutral|info|success|danger|warning/),
+ }),
+ );
+ });
+ });
+
+ it.each`
+ member | expected
+ ${memberMock} | ${{ show: true, text: "It's you", variant: 'success' }}
+ ${{ ...memberMock, user: { ...memberMock.user, blocked: true } }} | ${{ show: true, text: 'Blocked', variant: 'danger' }}
+ ${{ ...memberMock, user: { ...memberMock.user, twoFactorEnabled: true } }} | ${{ show: true, text: '2FA', variant: 'info' }}
+ `('returns expected output for "$expected.text" badge', ({ member, expected }) => {
+ expect(generateBadges(member, true)).toContainEqual(expect.objectContaining(expected));
+ });
+ });
+});
diff --git a/spec/frontend/vue_shared/components/paginated_table_with_search_and_tabs/mocks/items.json b/spec/frontend/vue_shared/components/paginated_table_with_search_and_tabs/mocks/items.json
new file mode 100644
index 00000000000..0d85b2bc68a
--- /dev/null
+++ b/spec/frontend/vue_shared/components/paginated_table_with_search_and_tabs/mocks/items.json
@@ -0,0 +1,15 @@
+[
+ {
+ "iid": "1527542",
+ "title": "SyntaxError: Invalid or unexpected token",
+ "createdAt": "2020-04-17T23:18:14.996Z",
+ "assignees": { "nodes": [] }
+ },
+ {
+ "iid": "1527543",
+ "title": "SyntaxError: Invalid or unexpected token by root",
+ "createdAt": "2020-04-17T23:19:14.996Z",
+ "assignees": { "nodes": [] }
+ }
+ ]
+ \ No newline at end of file
diff --git a/spec/frontend/vue_shared/components/paginated_table_with_search_and_tabs/mocks/items_filters.json b/spec/frontend/vue_shared/components/paginated_table_with_search_and_tabs/mocks/items_filters.json
new file mode 100644
index 00000000000..b42ec42d8b8
--- /dev/null
+++ b/spec/frontend/vue_shared/components/paginated_table_with_search_and_tabs/mocks/items_filters.json
@@ -0,0 +1,14 @@
+[
+ {
+ "type": "assignee_username",
+ "value": { "data": "root2" }
+ },
+ {
+ "type": "author_username",
+ "value": { "data": "root" }
+ },
+ {
+ "type": "filtered-search-term",
+ "value": { "data": "bar" }
+ }
+ ] \ No newline at end of file
diff --git a/spec/frontend/vue_shared/components/paginated_table_with_search_and_tabs/paginated_table_with_search_and_tabs_spec.js b/spec/frontend/vue_shared/components/paginated_table_with_search_and_tabs/paginated_table_with_search_and_tabs_spec.js
new file mode 100644
index 00000000000..d943aaf3e5f
--- /dev/null
+++ b/spec/frontend/vue_shared/components/paginated_table_with_search_and_tabs/paginated_table_with_search_and_tabs_spec.js
@@ -0,0 +1,350 @@
+import { mount } from '@vue/test-utils';
+import { GlAlert, GlBadge, GlPagination, GlTabs, GlTab } from '@gitlab/ui';
+import PageWrapper from '~/vue_shared/components/paginated_table_with_search_and_tabs/paginated_table_with_search_and_tabs.vue';
+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 Tracking from '~/tracking';
+import mockItems from './mocks/items.json';
+import mockFilters from './mocks/items_filters.json';
+
+const EmptyStateSlot = {
+ template: '<div class="empty-state">Empty State</div>',
+};
+
+const HeaderActionsSlot = {
+ template: '<div class="header-actions"><button>Action Button</button></div>',
+};
+
+const TitleSlot = {
+ template: '<div>Page Wrapper Title</div>',
+};
+
+const TableSlot = {
+ template: '<table class="gl-table"></table>',
+};
+
+const itemsCount = {
+ opened: 24,
+ closed: 10,
+ all: 34,
+};
+
+const ITEMS_STATUS_TABS = [
+ {
+ title: 'Opened items',
+ status: 'OPENED',
+ filters: ['opened'],
+ },
+ {
+ title: 'Closed items',
+ status: 'CLOSED',
+ filters: ['closed'],
+ },
+ {
+ title: 'All items',
+ status: 'ALL',
+ filters: ['all'],
+ },
+];
+
+describe('AlertManagementEmptyState', () => {
+ let wrapper;
+
+ function mountComponent({ props = {} } = {}) {
+ wrapper = mount(PageWrapper, {
+ provide: {
+ projectPath: '/link',
+ },
+ propsData: {
+ items: [],
+ itemsCount: {},
+ pageInfo: {},
+ statusTabs: [],
+ loading: false,
+ showItems: false,
+ showErrorMsg: false,
+ trackViewsOptions: {},
+ i18n: {},
+ serverErrorMessage: '',
+ filterSearchKey: '',
+ ...props,
+ },
+ slots: {
+ 'emtpy-state': EmptyStateSlot,
+ 'header-actions': HeaderActionsSlot,
+ title: TitleSlot,
+ table: TableSlot,
+ },
+ });
+ }
+
+ beforeEach(() => {
+ mountComponent();
+ });
+
+ afterEach(() => {
+ if (wrapper) {
+ wrapper.destroy();
+ }
+ });
+
+ const EmptyState = () => wrapper.find('.empty-state');
+ const ItemsTable = () => wrapper.find('.gl-table');
+ const ErrorAlert = () => wrapper.find(GlAlert);
+ const Pagination = () => wrapper.find(GlPagination);
+ const Tabs = () => wrapper.find(GlTabs);
+ const ActionButton = () => wrapper.find('.header-actions > button');
+ const Filters = () => wrapper.find(FilteredSearchBar);
+ const findPagination = () => wrapper.find(GlPagination);
+ const findStatusFilterTabs = () => wrapper.findAll(GlTab);
+ const findStatusTabs = () => wrapper.find(GlTabs);
+ const findStatusFilterBadge = () => wrapper.findAll(GlBadge);
+
+ describe('Snowplow tracking', () => {
+ beforeEach(() => {
+ jest.spyOn(Tracking, 'event');
+ mountComponent({
+ props: { trackViewsOptions: { category: 'category', action: 'action' } },
+ });
+ });
+
+ it('should track the items list page views', () => {
+ const { category, action } = wrapper.vm.trackViewsOptions;
+ expect(Tracking.event).toHaveBeenCalledWith(category, action);
+ });
+ });
+
+ describe('Page wrapper with no items', () => {
+ it('renders the empty state if there are no items present', () => {
+ expect(EmptyState().exists()).toBe(true);
+ });
+ });
+
+ describe('Page wrapper with items', () => {
+ it('renders the tabs selection with valid tabs', () => {
+ mountComponent({
+ props: {
+ statusTabs: [{ status: 'opened', title: 'Open' }, { status: 'closed', title: 'Closed' }],
+ },
+ });
+
+ expect(Tabs().exists()).toBe(true);
+ });
+
+ it('renders the header action buttons if present', () => {
+ expect(ActionButton().exists()).toBe(true);
+ });
+
+ it('renders a error alert if there are errors', () => {
+ mountComponent({
+ props: { showErrorMsg: true },
+ });
+
+ expect(ErrorAlert().exists()).toBe(true);
+ });
+
+ it('renders a table of items if items are present', () => {
+ mountComponent({
+ props: { showItems: true, items: mockItems },
+ });
+
+ expect(ItemsTable().exists()).toBe(true);
+ });
+
+ it('renders pagination if there the pagination info object has a next or previous page', () => {
+ mountComponent({
+ props: { pageInfo: { hasNextPage: true } },
+ });
+
+ expect(Pagination().exists()).toBe(true);
+ });
+
+ it('renders the filter set with the tokens according to the prop filterSearchTokens', () => {
+ mountComponent({
+ props: { filterSearchTokens: ['assignee_username'] },
+ });
+
+ expect(Filters().exists()).toBe(true);
+ });
+ });
+
+ describe('Status Filter Tabs', () => {
+ beforeEach(() => {
+ mountComponent({
+ props: { items: mockItems, itemsCount, statusTabs: ITEMS_STATUS_TABS },
+ });
+ });
+
+ it('should display filter tabs', () => {
+ const tabs = findStatusFilterTabs().wrappers;
+
+ tabs.forEach((tab, i) => {
+ expect(tab.attributes('data-testid')).toContain(ITEMS_STATUS_TABS[i].status);
+ });
+ });
+
+ it('should display filter tabs with items count badge for each status', () => {
+ const tabs = findStatusFilterTabs().wrappers;
+ const badges = findStatusFilterBadge();
+
+ tabs.forEach((tab, i) => {
+ const status = ITEMS_STATUS_TABS[i].status.toLowerCase();
+ expect(tab.attributes('data-testid')).toContain(ITEMS_STATUS_TABS[i].status);
+ expect(badges.at(i).text()).toContain(itemsCount[status]);
+ });
+ });
+ });
+
+ describe('Pagination', () => {
+ beforeEach(() => {
+ mountComponent({
+ props: {
+ items: mockItems,
+ itemsCount,
+ statusTabs: ITEMS_STATUS_TABS,
+ pageInfo: { hasNextPage: true },
+ },
+ });
+ });
+
+ it('should render pagination', () => {
+ expect(wrapper.find(GlPagination).exists()).toBe(true);
+ });
+
+ describe('prevPage', () => {
+ it('returns prevPage button', async () => {
+ findPagination().vm.$emit('input', 3);
+
+ await wrapper.vm.$nextTick();
+ expect(
+ findPagination()
+ .findAll('.page-item')
+ .at(0)
+ .text(),
+ ).toBe('Prev');
+ });
+
+ it('returns prevPage number', async () => {
+ findPagination().vm.$emit('input', 3);
+
+ await wrapper.vm.$nextTick();
+ expect(wrapper.vm.previousPage).toBe(2);
+ });
+
+ it('returns 0 when it is the first page', async () => {
+ findPagination().vm.$emit('input', 1);
+
+ await wrapper.vm.$nextTick();
+ expect(wrapper.vm.previousPage).toBe(0);
+ });
+ });
+
+ describe('nextPage', () => {
+ it('returns nextPage button', async () => {
+ findPagination().vm.$emit('input', 3);
+
+ await wrapper.vm.$nextTick();
+ expect(
+ findPagination()
+ .findAll('.page-item')
+ .at(1)
+ .text(),
+ ).toBe('Next');
+ });
+
+ it('returns nextPage number', async () => {
+ mountComponent({
+ props: {
+ items: mockItems,
+ itemsCount,
+ statusTabs: ITEMS_STATUS_TABS,
+ pageInfo: { hasNextPage: true },
+ },
+ });
+ findPagination().vm.$emit('input', 1);
+
+ await wrapper.vm.$nextTick();
+ expect(wrapper.vm.nextPage).toBe(2);
+ });
+
+ it('returns `null` when currentPage is already last page', async () => {
+ findStatusTabs().vm.$emit('input', 1);
+ findPagination().vm.$emit('input', 1);
+ await wrapper.vm.$nextTick();
+ expect(wrapper.vm.nextPage).toBeNull();
+ });
+ });
+ });
+
+ describe('Filtered search component', () => {
+ beforeEach(() => {
+ mountComponent({
+ props: {
+ items: mockItems,
+ itemsCount,
+ statusTabs: ITEMS_STATUS_TABS,
+ filterSearchKey: 'items',
+ },
+ });
+ });
+
+ it('renders the search component for incidents', () => {
+ expect(Filters().props('searchInputPlaceholder')).toBe('Search or filter results…');
+ expect(Filters().props('tokens')).toEqual([
+ {
+ type: 'author_username',
+ icon: 'user',
+ title: 'Author',
+ unique: true,
+ symbol: '@',
+ token: AuthorToken,
+ operators: [{ value: '=', description: 'is', default: 'true' }],
+ fetchPath: '/link',
+ fetchAuthors: expect.any(Function),
+ },
+ {
+ type: 'assignee_username',
+ icon: 'user',
+ title: 'Assignee',
+ unique: true,
+ symbol: '@',
+ token: AuthorToken,
+ operators: [{ value: '=', description: 'is', default: 'true' }],
+ fetchPath: '/link',
+ fetchAuthors: expect.any(Function),
+ },
+ ]);
+ expect(Filters().props('recentSearchesStorageKey')).toBe('items');
+ });
+
+ it('returns correctly applied filter search values', async () => {
+ const searchTerm = 'foo';
+ wrapper.setData({
+ searchTerm,
+ });
+
+ await wrapper.vm.$nextTick();
+ expect(wrapper.vm.filteredSearchValue).toEqual([searchTerm]);
+ });
+
+ it('updates props tied to getIncidents GraphQL query', () => {
+ wrapper.vm.handleFilterItems(mockFilters);
+
+ expect(wrapper.vm.authorUsername).toBe('root');
+ expect(wrapper.vm.assigneeUsername).toEqual('root2');
+ expect(wrapper.vm.searchTerm).toBe(mockFilters[2].value.data);
+ });
+
+ it('updates props `searchTerm` and `authorUsername` with empty values when passed filters param is empty', () => {
+ wrapper.setData({
+ authorUsername: 'foo',
+ searchTerm: 'bar',
+ });
+
+ wrapper.vm.handleFilterItems([]);
+
+ expect(wrapper.vm.authorUsername).toBe('');
+ expect(wrapper.vm.searchTerm).toBe('');
+ });
+ });
+});
diff --git a/spec/frontend/vue_shared/components/registry/__snapshots__/code_instruction_spec.js.snap b/spec/frontend/vue_shared/components/registry/__snapshots__/code_instruction_spec.js.snap
index 16094a42668..ecea151fc8a 100644
--- a/spec/frontend/vue_shared/components/registry/__snapshots__/code_instruction_spec.js.snap
+++ b/spec/frontend/vue_shared/components/registry/__snapshots__/code_instruction_spec.js.snap
@@ -38,7 +38,8 @@ exports[`Package code instruction single line to match the default snapshot 1`]
data-testid="instruction-button"
>
<button
- class="btn input-group-text btn-secondary btn-md btn-default"
+ aria-label="Copy this value"
+ class="btn input-group-text btn-default btn-md gl-button btn-default-secondary btn-icon"
data-clipboard-text="npm i @my-package"
title="Copy npm install command"
type="button"
@@ -46,13 +47,15 @@ exports[`Package code instruction single line to match the default snapshot 1`]
<!---->
<svg
- class="gl-icon s16"
+ class="gl-button-icon gl-icon s16"
data-testid="copy-to-clipboard-icon"
>
<use
href="#copy-to-clipboard"
/>
</svg>
+
+ <!---->
</button>
</span>
</div>
diff --git a/spec/frontend/vue_shared/components/registry/list_item_spec.js b/spec/frontend/vue_shared/components/registry/list_item_spec.js
index e2cfdedb4bf..2a48bf4f2d6 100644
--- a/spec/frontend/vue_shared/components/registry/list_item_spec.js
+++ b/spec/frontend/vue_shared/components/registry/list_item_spec.js
@@ -58,9 +58,9 @@ describe('list item', () => {
describe.each`
slotNames
- ${['details_foo']}
- ${['details_foo', 'details_bar']}
- ${['details_foo', 'details_bar', 'details_baz']}
+ ${['details-foo']}
+ ${['details-foo', 'details-bar']}
+ ${['details-foo', 'details-bar', 'details-baz']}
`('$slotNames details slots', ({ slotNames }) => {
const slotMocks = slotNames.reduce((acc, current) => {
acc[current] = `<div data-testid="${current}" />`;
@@ -89,7 +89,7 @@ describe('list item', () => {
describe('details toggle button', () => {
it('is visible when at least one details slot exists', async () => {
- mountComponent({}, { details_foo: '<span></span>' });
+ mountComponent({}, { 'details-foo': '<span></span>' });
await wrapper.vm.$nextTick();
expect(findToggleDetailsButton().exists()).toBe(true);
});
diff --git a/spec/frontend/vue_shared/components/registry/title_area_spec.js b/spec/frontend/vue_shared/components/registry/title_area_spec.js
index 6740d6097a4..5cb606b58d9 100644
--- a/spec/frontend/vue_shared/components/registry/title_area_spec.js
+++ b/spec/frontend/vue_shared/components/registry/title_area_spec.js
@@ -1,4 +1,4 @@
-import { GlAvatar } from '@gitlab/ui';
+import { GlAvatar, GlSprintf, GlLink } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import component from '~/vue_shared/components/registry/title_area.vue';
@@ -10,10 +10,12 @@ describe('title area', () => {
const findMetadataSlot = name => wrapper.find(`[data-testid="${name}"]`);
const findTitle = () => wrapper.find('[data-testid="title"]');
const findAvatar = () => wrapper.find(GlAvatar);
+ const findInfoMessages = () => wrapper.findAll('[data-testid="info-message"]');
const mountComponent = ({ propsData = { title: 'foo' }, slots } = {}) => {
wrapper = shallowMount(component, {
propsData,
+ stubs: { GlSprintf },
slots: {
'sub-header': '<div data-testid="sub-header" />',
'right-actions': '<div data-testid="right-actions" />',
@@ -77,9 +79,9 @@ describe('title area', () => {
describe.each`
slotNames
- ${['metadata_foo']}
- ${['metadata_foo', 'metadata_bar']}
- ${['metadata_foo', 'metadata_bar', 'metadata_baz']}
+ ${['metadata-foo']}
+ ${['metadata-foo', 'metadata-bar']}
+ ${['metadata-foo', 'metadata-bar', 'metadata-baz']}
`('$slotNames metadata slots', ({ slotNames }) => {
const slotMocks = slotNames.reduce((acc, current) => {
acc[current] = `<div data-testid="${current}" />`;
@@ -95,4 +97,33 @@ describe('title area', () => {
});
});
});
+
+ describe('info-messages', () => {
+ it('shows a message when the props contains one', () => {
+ mountComponent({ propsData: { infoMessages: [{ text: 'foo foo bar bar' }] } });
+
+ const messages = findInfoMessages();
+ expect(messages).toHaveLength(1);
+ expect(messages.at(0).text()).toBe('foo foo bar bar');
+ });
+
+ it('shows a link when the props contains one', () => {
+ mountComponent({
+ propsData: {
+ infoMessages: [{ text: 'foo %{docLinkStart}link%{docLinkEnd}', link: 'bar' }],
+ },
+ });
+
+ const message = findInfoMessages().at(0);
+
+ expect(message.find(GlLink).attributes('href')).toBe('bar');
+ expect(message.text()).toBe('foo link');
+ });
+
+ it('multiple messages generates multiple spans', () => {
+ mountComponent({ propsData: { infoMessages: [{ text: 'foo' }, { text: 'bar' }] } });
+
+ expect(findInfoMessages()).toHaveLength(2);
+ });
+ });
});
diff --git a/spec/frontend/vue_shared/components/rich_content_editor/editor_service_spec.js b/spec/frontend/vue_shared/components/rich_content_editor/editor_service_spec.js
index 16f60b5ff21..0f2f263a776 100644
--- a/spec/frontend/vue_shared/components/rich_content_editor/editor_service_spec.js
+++ b/spec/frontend/vue_shared/components/rich_content_editor/editor_service_spec.js
@@ -4,24 +4,37 @@ import {
removeCustomEventListener,
registerHTMLToMarkdownRenderer,
addImage,
+ insertVideo,
getMarkdown,
getEditorOptions,
} from '~/vue_shared/components/rich_content_editor/services/editor_service';
import buildHTMLToMarkdownRenderer from '~/vue_shared/components/rich_content_editor/services/build_html_to_markdown_renderer';
import buildCustomRenderer from '~/vue_shared/components/rich_content_editor/services/build_custom_renderer';
+import sanitizeHTML from '~/vue_shared/components/rich_content_editor/services/sanitize_html';
jest.mock('~/vue_shared/components/rich_content_editor/services/build_html_to_markdown_renderer');
jest.mock('~/vue_shared/components/rich_content_editor/services/build_custom_renderer');
+jest.mock('~/vue_shared/components/rich_content_editor/services/sanitize_html');
describe('Editor Service', () => {
let mockInstance;
let event;
let handler;
+ const parseHtml = str => {
+ const wrapper = document.createElement('div');
+ wrapper.innerHTML = str;
+ return wrapper.firstChild;
+ };
beforeEach(() => {
mockInstance = {
eventManager: { addEventType: jest.fn(), removeEventHandler: jest.fn(), listen: jest.fn() },
- editor: { exec: jest.fn() },
+ editor: {
+ exec: jest.fn(),
+ isWysiwygMode: jest.fn(),
+ getSquire: jest.fn(),
+ insertText: jest.fn(),
+ },
invoke: jest.fn(),
toMarkOptions: {
renderer: {
@@ -87,6 +100,38 @@ describe('Editor Service', () => {
});
});
+ describe('insertVideo', () => {
+ const mockUrl = 'some/url';
+ const htmlString = `<figure contenteditable="false" class="gl-relative gl-h-0 video_container"><iframe class="gl-absolute gl-top-0 gl-left-0 gl-w-full gl-h-full" width="560" height="315" frameborder="0" src="some/url"></iframe></figure>`;
+ const mockInsertElement = jest.fn();
+
+ beforeEach(() =>
+ mockInstance.editor.getSquire.mockReturnValue({ insertElement: mockInsertElement }),
+ );
+
+ describe('WYSIWYG mode', () => {
+ it('calls the insertElement method on the squire instance with an iFrame element', () => {
+ mockInstance.editor.isWysiwygMode.mockReturnValue(true);
+
+ insertVideo(mockInstance, mockUrl);
+
+ expect(mockInstance.editor.getSquire().insertElement).toHaveBeenCalledWith(
+ parseHtml(htmlString),
+ );
+ });
+ });
+
+ describe('Markdown mode', () => {
+ it('calls the insertText method on the editor instance with the iFrame element HTML', () => {
+ mockInstance.editor.isWysiwygMode.mockReturnValue(false);
+
+ insertVideo(mockInstance, mockUrl);
+
+ expect(mockInstance.editor.insertText).toHaveBeenCalledWith(htmlString);
+ });
+ });
+ });
+
describe('getMarkdown', () => {
it('calls the invoke method on the instance', () => {
getMarkdown(mockInstance);
@@ -143,5 +188,14 @@ describe('Editor Service', () => {
getEditorOptions(externalOptions);
expect(buildCustomRenderer).toHaveBeenCalledWith(externalOptions.customRenderers);
});
+
+ it('uses the internal sanitizeHTML service for HTML sanitization', () => {
+ const options = getEditorOptions();
+ const html = '<div></div>';
+
+ options.customHTMLSanitizer(html);
+
+ expect(sanitizeHTML).toHaveBeenCalledWith(html);
+ });
});
});
diff --git a/spec/frontend/vue_shared/components/rich_content_editor/modals/insert_video_modal_spec.js b/spec/frontend/vue_shared/components/rich_content_editor/modals/insert_video_modal_spec.js
new file mode 100644
index 00000000000..be3a4030b1d
--- /dev/null
+++ b/spec/frontend/vue_shared/components/rich_content_editor/modals/insert_video_modal_spec.js
@@ -0,0 +1,44 @@
+import { shallowMount } from '@vue/test-utils';
+import { GlModal } from '@gitlab/ui';
+import InsertVideoModal from '~/vue_shared/components/rich_content_editor/modals/insert_video_modal.vue';
+
+describe('Insert Video Modal', () => {
+ let wrapper;
+
+ const findModal = () => wrapper.find(GlModal);
+ const findUrlInput = () => wrapper.find({ ref: 'urlInput' });
+
+ const triggerInsertVideo = url => {
+ const preventDefault = jest.fn();
+ findUrlInput().vm.$emit('input', url);
+ findModal().vm.$emit('primary', { preventDefault });
+ };
+
+ beforeEach(() => {
+ wrapper = shallowMount(InsertVideoModal);
+ });
+
+ afterEach(() => wrapper.destroy());
+
+ describe('when content is loaded', () => {
+ it('renders a modal component', () => {
+ expect(findModal().exists()).toBe(true);
+ });
+
+ it('renders an input to add a URL', () => {
+ expect(findUrlInput().exists()).toBe(true);
+ });
+ });
+
+ describe('insert video', () => {
+ it.each`
+ url | emitted
+ ${'https://www.youtube.com/embed/someId'} | ${[['https://www.youtube.com/embed/someId']]}
+ ${'https://www.youtube.com/watch?v=1234'} | ${[['https://www.youtube.com/embed/1234']]}
+ ${'::youtube.com/invalid/url'} | ${undefined}
+ `('formats the url correctly', ({ url, emitted }) => {
+ triggerInsertVideo(url);
+ expect(wrapper.emitted('insertVideo')).toEqual(emitted);
+ });
+ });
+});
diff --git a/spec/frontend/vue_shared/components/rich_content_editor/rich_content_editor_spec.js b/spec/frontend/vue_shared/components/rich_content_editor/rich_content_editor_spec.js
index 3d54db7fe5c..8c2c0413819 100644
--- a/spec/frontend/vue_shared/components/rich_content_editor/rich_content_editor_spec.js
+++ b/spec/frontend/vue_shared/components/rich_content_editor/rich_content_editor_spec.js
@@ -1,6 +1,7 @@
import { shallowMount } from '@vue/test-utils';
import RichContentEditor from '~/vue_shared/components/rich_content_editor/rich_content_editor.vue';
import AddImageModal from '~/vue_shared/components/rich_content_editor/modals/add_image/add_image_modal.vue';
+import InsertVideoModal from '~/vue_shared/components/rich_content_editor/modals/insert_video_modal.vue';
import {
EDITOR_TYPES,
EDITOR_HEIGHT,
@@ -12,6 +13,7 @@ import {
addCustomEventListener,
removeCustomEventListener,
addImage,
+ insertVideo,
registerHTMLToMarkdownRenderer,
getEditorOptions,
} from '~/vue_shared/components/rich_content_editor/services/editor_service';
@@ -21,6 +23,7 @@ jest.mock('~/vue_shared/components/rich_content_editor/services/editor_service',
addCustomEventListener: jest.fn(),
removeCustomEventListener: jest.fn(),
addImage: jest.fn(),
+ insertVideo: jest.fn(),
registerHTMLToMarkdownRenderer: jest.fn(),
getEditorOptions: jest.fn(),
}));
@@ -32,6 +35,7 @@ describe('Rich Content Editor', () => {
const imageRoot = 'path/to/root/';
const findEditor = () => wrapper.find({ ref: 'editor' });
const findAddImageModal = () => wrapper.find(AddImageModal);
+ const findInsertVideoModal = () => wrapper.find(InsertVideoModal);
const buildWrapper = () => {
wrapper = shallowMount(RichContentEditor, {
@@ -122,6 +126,14 @@ describe('Rich Content Editor', () => {
);
});
+ it('adds the CUSTOM_EVENTS.openInsertVideoModal custom event listener', () => {
+ expect(addCustomEventListener).toHaveBeenCalledWith(
+ wrapper.vm.editorApi,
+ CUSTOM_EVENTS.openInsertVideoModal,
+ wrapper.vm.onOpenInsertVideoModal,
+ );
+ });
+
it('registers HTML to markdown renderer', () => {
expect(registerHTMLToMarkdownRenderer).toHaveBeenCalledWith(wrapper.vm.editorApi);
});
@@ -141,6 +153,16 @@ describe('Rich Content Editor', () => {
wrapper.vm.onOpenAddImageModal,
);
});
+
+ it('removes the CUSTOM_EVENTS.openInsertVideoModal custom event listener', () => {
+ wrapper.vm.$destroy();
+
+ expect(removeCustomEventListener).toHaveBeenCalledWith(
+ wrapper.vm.editorApi,
+ CUSTOM_EVENTS.openInsertVideoModal,
+ wrapper.vm.onOpenInsertVideoModal,
+ );
+ });
});
describe('add image modal', () => {
@@ -161,4 +183,23 @@ describe('Rich Content Editor', () => {
expect(addImage).toHaveBeenCalledWith(mockInstance, mockImage);
});
});
+
+ describe('insert video modal', () => {
+ beforeEach(() => {
+ buildWrapper();
+ });
+
+ it('renders an insertVideoModal component', () => {
+ expect(findInsertVideoModal().exists()).toBe(true);
+ });
+
+ it('calls the onInsertVideo method when the insertVideo event is emitted', () => {
+ const mockUrl = 'https://www.youtube.com/embed/someId';
+ const mockInstance = { exec: jest.fn() };
+ wrapper.vm.$refs.editor = mockInstance;
+
+ findInsertVideoModal().vm.$emit('insertVideo', mockUrl);
+ expect(insertVideo).toHaveBeenCalledWith(mockInstance, mockUrl);
+ });
+ });
});
diff --git a/spec/frontend/vue_shared/components/rich_content_editor/services/renderers/render_html_block_spec.js b/spec/frontend/vue_shared/components/rich_content_editor/services/renderers/render_html_block_spec.js
index a6c712eeb31..b31684a400e 100644
--- a/spec/frontend/vue_shared/components/rich_content_editor/services/renderers/render_html_block_spec.js
+++ b/spec/frontend/vue_shared/components/rich_content_editor/services/renderers/render_html_block_spec.js
@@ -1,22 +1,21 @@
import renderer from '~/vue_shared/components/rich_content_editor/services/renderers/render_html_block';
import { buildUneditableHtmlAsTextTokens } from '~/vue_shared/components/rich_content_editor/services/renderers/build_uneditable_token';
-import { normalTextNode } from './mock_data';
+describe('rich_content_editor/services/renderers/render_html_block', () => {
+ const htmlBlockNode = {
+ literal: '<div><h1>Heading</h1><p>Paragraph.</p></div>',
+ type: 'htmlBlock',
+ };
-const htmlBlockNode = {
- firstChild: null,
- literal: '<div><h1>Heading</h1><p>Paragraph.</p></div>',
- type: 'htmlBlock',
-};
-
-describe('Render HTML renderer', () => {
describe('canRender', () => {
- it('should return true when the argument is an html block', () => {
- expect(renderer.canRender(htmlBlockNode)).toBe(true);
- });
-
- it('should return false when the argument is not an html block', () => {
- expect(renderer.canRender(normalTextNode)).toBe(false);
+ it.each`
+ input | result
+ ${htmlBlockNode} | ${true}
+ ${{ literal: '<iframe></iframe>', type: 'htmlBlock' }} | ${true}
+ ${{ literal: '<iframe src="https://www.youtube.com"></iframe>', type: 'htmlBlock' }} | ${false}
+ ${{ literal: '<iframe></iframe>', type: 'text' }} | ${false}
+ `('returns $result when input=$input', ({ input, result }) => {
+ expect(renderer.canRender(input)).toBe(result);
});
});
diff --git a/spec/frontend/vue_shared/components/rich_content_editor/services/sanitize_html_spec.js b/spec/frontend/vue_shared/components/rich_content_editor/services/sanitize_html_spec.js
new file mode 100644
index 00000000000..f2182ef60d7
--- /dev/null
+++ b/spec/frontend/vue_shared/components/rich_content_editor/services/sanitize_html_spec.js
@@ -0,0 +1,11 @@
+import sanitizeHTML from '~/vue_shared/components/rich_content_editor/services/sanitize_html';
+
+describe('rich_content_editor/services/sanitize_html', () => {
+ it.each`
+ input | result
+ ${'<iframe src="https://www.youtube.com"></iframe>'} | ${'<iframe src="https://www.youtube.com"></iframe>'}
+ ${'<iframe src="https://gitlab.com"></iframe>'} | ${''}
+ `('removes iframes if the iframe source origin is not allowed', ({ input, result }) => {
+ expect(sanitizeHTML(input)).toBe(result);
+ });
+});
diff --git a/spec/frontend/vue_shared/components/sidebar/collapsed_calendar_icon_spec.js b/spec/frontend/vue_shared/components/sidebar/collapsed_calendar_icon_spec.js
index 31316a93ecd..240d6cb5a34 100644
--- a/spec/frontend/vue_shared/components/sidebar/collapsed_calendar_icon_spec.js
+++ b/spec/frontend/vue_shared/components/sidebar/collapsed_calendar_icon_spec.js
@@ -18,7 +18,7 @@ describe('collapsedCalendarIcon', () => {
});
it('should hide calendar icon if showIcon', () => {
- expect(vm.$el.querySelector('.fa-calendar')).toBeNull();
+ expect(vm.$el.querySelector('[data-testid="calendar-icon"]')).toBeNull();
});
it('should render text', () => {
diff --git a/spec/frontend/vue_shared/components/sidebar/collapsed_grouped_date_picker_spec.js b/spec/frontend/vue_shared/components/sidebar/collapsed_grouped_date_picker_spec.js
index 65255968bc7..08fc822577e 100644
--- a/spec/frontend/vue_shared/components/sidebar/collapsed_grouped_date_picker_spec.js
+++ b/spec/frontend/vue_shared/components/sidebar/collapsed_grouped_date_picker_spec.js
@@ -80,7 +80,7 @@ describe('collapsedGroupedDatePicker', () => {
it('should have tooltip as `Start and due date`', () => {
const icons = vm.$el.querySelectorAll('.sidebar-collapsed-icon');
- expect(icons[0].dataset.originalTitle).toBe('Start and due date');
+ expect(icons[0].title).toBe('Start and due date');
});
});
});
diff --git a/spec/frontend/vue_shared/components/sidebar/labels_select_vue/dropdown_contents_labels_view_spec.js b/spec/frontend/vue_shared/components/sidebar/labels_select_vue/dropdown_contents_labels_view_spec.js
index 589be0ad7a4..a9350bc059d 100644
--- a/spec/frontend/vue_shared/components/sidebar/labels_select_vue/dropdown_contents_labels_view_spec.js
+++ b/spec/frontend/vue_shared/components/sidebar/labels_select_vue/dropdown_contents_labels_view_spec.js
@@ -69,6 +69,16 @@ describe('DropdownContentsLabelsView', () => {
expect(wrapper.vm.visibleLabels[0].title).toBe('Bug');
});
+ it('returns matching labels with fuzzy filtering', () => {
+ wrapper.setData({
+ searchKey: 'bg',
+ });
+
+ expect(wrapper.vm.visibleLabels.length).toBe(2);
+ expect(wrapper.vm.visibleLabels[0].title).toBe('Bug');
+ expect(wrapper.vm.visibleLabels[1].title).toBe('Boog');
+ });
+
it('returns all labels when `searchKey` is empty', () => {
wrapper.setData({
searchKey: '',
@@ -133,6 +143,19 @@ describe('DropdownContentsLabelsView', () => {
expect(wrapper.vm.currentHighlightItem).toBe(2);
});
+ it('resets the search text when the Enter key is pressed', () => {
+ wrapper.setData({
+ currentHighlightItem: 1,
+ searchKey: 'bug',
+ });
+
+ wrapper.vm.handleKeyDown({
+ keyCode: ENTER_KEY_CODE,
+ });
+
+ expect(wrapper.vm.searchKey).toBe('');
+ });
+
it('calls action `updateSelectedLabels` with currently highlighted label when Enter key is pressed', () => {
jest.spyOn(wrapper.vm, 'updateSelectedLabels').mockImplementation();
wrapper.setData({
diff --git a/spec/frontend/vue_shared/components/sidebar/labels_select_vue/mock_data.js b/spec/frontend/vue_shared/components/sidebar/labels_select_vue/mock_data.js
index e1008d13fc2..9697d6c30f2 100644
--- a/spec/frontend/vue_shared/components/sidebar/labels_select_vue/mock_data.js
+++ b/spec/frontend/vue_shared/components/sidebar/labels_select_vue/mock_data.js
@@ -24,6 +24,13 @@ export const mockLabels = [
color: '#FF0000',
textColor: '#FFFFFF',
},
+ {
+ id: 29,
+ title: 'Boog',
+ description: 'Label for bugs',
+ color: '#FF0000',
+ textColor: '#FFFFFF',
+ },
];
export const mockConfig = {
diff --git a/spec/frontend/vue_shared/components/sidebar/labels_select_vue/store/actions_spec.js b/spec/frontend/vue_shared/components/sidebar/labels_select_vue/store/actions_spec.js
index bfb8e263d81..c742220ba8a 100644
--- a/spec/frontend/vue_shared/components/sidebar/labels_select_vue/store/actions_spec.js
+++ b/spec/frontend/vue_shared/components/sidebar/labels_select_vue/store/actions_spec.js
@@ -259,21 +259,6 @@ describe('LabelsSelect Actions', () => {
});
});
- describe('replaceSelectedLabels', () => {
- it('replaces `state.selectedLabels`', done => {
- const selectedLabels = [{ id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }];
-
- testAction(
- actions.replaceSelectedLabels,
- selectedLabels,
- state,
- [{ type: types.REPLACE_SELECTED_LABELS, payload: selectedLabels }],
- [],
- done,
- );
- });
- });
-
describe('updateSelectedLabels', () => {
it('updates `state.labels` based on provided `labels` param', done => {
const labels = [{ id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }];
diff --git a/spec/frontend/vue_shared/components/sidebar/labels_select_vue/store/mutations_spec.js b/spec/frontend/vue_shared/components/sidebar/labels_select_vue/store/mutations_spec.js
index 3414eec8a63..8081806e314 100644
--- a/spec/frontend/vue_shared/components/sidebar/labels_select_vue/store/mutations_spec.js
+++ b/spec/frontend/vue_shared/components/sidebar/labels_select_vue/store/mutations_spec.js
@@ -152,19 +152,6 @@ describe('LabelsSelect Mutations', () => {
});
});
- describe(`${types.REPLACE_SELECTED_LABELS}`, () => {
- it('replaces `state.selectedLabels`', () => {
- const state = {
- selectedLabels: [{ id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }],
- };
- const newSelectedLabels = [{ id: 2 }, { id: 5 }];
-
- mutations[types.REPLACE_SELECTED_LABELS](state, newSelectedLabels);
-
- expect(state.selectedLabels).toEqual(newSelectedLabels);
- });
- });
-
describe(`${types.UPDATE_SELECTED_LABELS}`, () => {
const labels = [{ id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }];
diff --git a/spec/frontend/vue_shared/components/sidebar/toggle_sidebar_spec.js b/spec/frontend/vue_shared/components/sidebar/toggle_sidebar_spec.js
index 4342f5e2105..f1c3e8a1ddc 100644
--- a/spec/frontend/vue_shared/components/sidebar/toggle_sidebar_spec.js
+++ b/spec/frontend/vue_shared/components/sidebar/toggle_sidebar_spec.js
@@ -11,15 +11,14 @@ describe('toggleSidebar', () => {
});
});
- it('should render << when collapsed', () => {
- expect(vm.$el.querySelector('.fa').classList.contains('fa-angle-double-left')).toEqual(true);
+ it('should render the "chevron-double-lg-left" icon when collapsed', () => {
+ expect(vm.$el.querySelector('[data-testid="chevron-double-lg-left-icon"]')).not.toBeNull();
});
- it('should render >> when collapsed', () => {
+ it('should render the "chevron-double-lg-right" icon when expanded', async () => {
vm.collapsed = false;
- Vue.nextTick(() => {
- expect(vm.$el.querySelector('.fa').classList.contains('fa-angle-double-right')).toEqual(true);
- });
+ await Vue.nextTick();
+ expect(vm.$el.querySelector('[data-testid="chevron-double-lg-right-icon"]')).not.toBeNull();
});
it('should emit toggle event when button clicked', () => {
diff --git a/spec/frontend/vue_shared/components/split_button_spec.js b/spec/frontend/vue_shared/components/split_button_spec.js
index f3bd4c14717..e09bc073042 100644
--- a/spec/frontend/vue_shared/components/split_button_spec.js
+++ b/spec/frontend/vue_shared/components/split_button_spec.js
@@ -1,4 +1,4 @@
-import { GlDeprecatedDropdown, GlDeprecatedDropdownItem } from '@gitlab/ui';
+import { GlDropdown, GlDropdownItem } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import SplitButton from '~/vue_shared/components/split_button.vue';
@@ -25,10 +25,10 @@ describe('SplitButton', () => {
});
};
- const findDropdown = () => wrapper.find(GlDeprecatedDropdown);
+ const findDropdown = () => wrapper.find(GlDropdown);
const findDropdownItem = (index = 0) =>
findDropdown()
- .findAll(GlDeprecatedDropdownItem)
+ .findAll(GlDropdownItem)
.at(index);
const selectItem = index => {
findDropdownItem(index).vm.$emit('click');
diff --git a/spec/frontend/vue_shared/components/todo_button_spec.js b/spec/frontend/vue_shared/components/todo_button_spec.js
index 482b5de11f6..1f8a214d632 100644
--- a/spec/frontend/vue_shared/components/todo_button_spec.js
+++ b/spec/frontend/vue_shared/components/todo_button_spec.js
@@ -33,7 +33,7 @@ describe('Todo Button', () => {
it.each`
label | isTodo
${'Mark as done'} | ${true}
- ${'Add a To-Do'} | ${false}
+ ${'Add a To Do'} | ${false}
`('sets correct label when isTodo is $isTodo', ({ label, isTodo }) => {
createComponent({ isTodo });
diff --git a/spec/frontend/vue_shared/components/user_popover/user_popover_spec.js b/spec/frontend/vue_shared/components/user_popover/user_popover_spec.js
index b43bb6b10e0..c208d7b0226 100644
--- a/spec/frontend/vue_shared/components/user_popover/user_popover_spec.js
+++ b/spec/frontend/vue_shared/components/user_popover/user_popover_spec.js
@@ -21,6 +21,9 @@ describe('User Popover Component', () => {
let wrapper;
beforeEach(() => {
+ window.gon.features = {
+ securityAutoFix: true,
+ };
loadFixtures(fixtureTemplate);
});
@@ -28,6 +31,7 @@ describe('User Popover Component', () => {
wrapper.destroy();
});
+ const findByTestId = testid => wrapper.find(`[data-testid="${testid}"]`);
const findUserStatus = () => wrapper.find('.js-user-status');
const findTarget = () => document.querySelector('.js-user-link');
@@ -196,4 +200,30 @@ describe('User Popover Component', () => {
expect(findUserStatus().exists()).toBe(false);
});
});
+
+ describe('security bot', () => {
+ const SECURITY_BOT_USER = {
+ ...DEFAULT_PROPS.user,
+ name: 'GitLab Security Bot',
+ username: 'GitLab-Security-Bot',
+ websiteUrl: '/security/bot/docs',
+ };
+ const findSecurityBotDocsLink = () => findByTestId('user-popover-bot-docs-link');
+
+ it("shows a link to the bot's documentation", () => {
+ createWrapper({ user: SECURITY_BOT_USER });
+ const securityBotDocsLink = findSecurityBotDocsLink();
+ expect(securityBotDocsLink.exists()).toBe(true);
+ expect(securityBotDocsLink.attributes('href')).toBe(SECURITY_BOT_USER.websiteUrl);
+ });
+
+ it('does not show the link if the feature flag is disabled', () => {
+ window.gon.features = {
+ securityAutoFix: false,
+ };
+ createWrapper({ user: SECURITY_BOT_USER });
+
+ expect(findSecurityBotDocsLink().exists()).toBe(false);
+ });
+ });
});
diff --git a/spec/frontend/vue_shared/components/web_ide_link_spec.js b/spec/frontend/vue_shared/components/web_ide_link_spec.js
index 57f511903d9..8ed072bed13 100644
--- a/spec/frontend/vue_shared/components/web_ide_link_spec.js
+++ b/spec/frontend/vue_shared/components/web_ide_link_spec.js
@@ -3,9 +3,27 @@ import LocalStorageSync from '~/vue_shared/components/local_storage_sync.vue';
import WebIdeLink from '~/vue_shared/components/web_ide_link.vue';
import ActionsButton from '~/vue_shared/components/actions_button.vue';
+const TEST_EDIT_URL = '/gitlab-test/test/-/edit/master/';
const TEST_WEB_IDE_URL = '/-/ide/project/gitlab-test/test/edit/master/-/';
const TEST_GITPOD_URL = 'https://gitpod.test/';
+const ACTION_EDIT = {
+ href: TEST_EDIT_URL,
+ key: 'edit',
+ text: 'Edit',
+ secondaryText: 'Edit this file only.',
+ tooltip: '',
+ attrs: {
+ 'data-qa-selector': 'edit_button',
+ 'data-track-event': 'click_edit',
+ 'data-track-label': 'Edit',
+ },
+};
+const ACTION_EDIT_CONFIRM_FORK = {
+ ...ACTION_EDIT,
+ href: '#modal-confirm-fork-edit',
+ handle: expect.any(Function),
+};
const ACTION_WEB_IDE = {
href: TEST_WEB_IDE_URL,
key: 'webide',
@@ -14,13 +32,16 @@ const ACTION_WEB_IDE = {
text: 'Web IDE',
attrs: {
'data-qa-selector': 'web_ide_button',
+ 'data-track-event': 'click_edit_ide',
+ 'data-track-label': 'Web IDE',
},
};
-const ACTION_WEB_IDE_FORK = {
+const ACTION_WEB_IDE_CONFIRM_FORK = {
...ACTION_WEB_IDE,
- href: '#modal-confirm-fork',
+ href: '#modal-confirm-fork-webide',
handle: expect.any(Function),
};
+const ACTION_WEB_IDE_EDIT_FORK = { ...ACTION_WEB_IDE, text: 'Edit fork in Web IDE' };
const ACTION_GITPOD = {
href: TEST_GITPOD_URL,
key: 'gitpod',
@@ -43,6 +64,7 @@ describe('Web IDE link component', () => {
function createComponent(props) {
wrapper = shallowMount(WebIdeLink, {
propsData: {
+ editUrl: TEST_EDIT_URL,
webIdeUrl: TEST_WEB_IDE_URL,
gitpodUrl: TEST_GITPOD_URL,
...props,
@@ -57,14 +79,36 @@ describe('Web IDE link component', () => {
const findActionsButton = () => wrapper.find(ActionsButton);
const findLocalStorageSync = () => wrapper.find(LocalStorageSync);
- it.each`
- props | expectedActions
- ${{}} | ${[ACTION_WEB_IDE]}
- ${{ needsToFork: true }} | ${[ACTION_WEB_IDE_FORK]}
- ${{ showWebIdeButton: false, showGitpodButton: true, gitpodEnabled: true }} | ${[ACTION_GITPOD]}
- ${{ showWebIdeButton: false, showGitpodButton: true, gitpodEnabled: false }} | ${[ACTION_GITPOD_ENABLE]}
- ${{ showGitpodButton: true, gitpodEnabled: false }} | ${[ACTION_WEB_IDE, ACTION_GITPOD_ENABLE]}
- `('renders actions with props=$props', ({ props, expectedActions }) => {
+ it.each([
+ {
+ props: {},
+ expectedActions: [ACTION_WEB_IDE, ACTION_EDIT],
+ },
+ {
+ props: { isFork: true },
+ expectedActions: [ACTION_WEB_IDE_EDIT_FORK, ACTION_EDIT],
+ },
+ {
+ props: { needsToFork: true },
+ expectedActions: [ACTION_WEB_IDE_CONFIRM_FORK, ACTION_EDIT_CONFIRM_FORK],
+ },
+ {
+ props: { showWebIdeButton: false, showGitpodButton: true, gitpodEnabled: true },
+ expectedActions: [ACTION_EDIT, ACTION_GITPOD],
+ },
+ {
+ props: { showWebIdeButton: false, showGitpodButton: true, gitpodEnabled: false },
+ expectedActions: [ACTION_EDIT, ACTION_GITPOD_ENABLE],
+ },
+ {
+ props: { showGitpodButton: true, gitpodEnabled: false },
+ expectedActions: [ACTION_WEB_IDE, ACTION_EDIT, ACTION_GITPOD_ENABLE],
+ },
+ {
+ props: { showEditButton: false },
+ expectedActions: [ACTION_WEB_IDE],
+ },
+ ])('renders actions with appropriately for given props', ({ props, expectedActions }) => {
createComponent(props);
expect(findActionsButton().props('actions')).toEqual(expectedActions);
@@ -72,7 +116,12 @@ describe('Web IDE link component', () => {
describe('with multiple actions', () => {
beforeEach(() => {
- createComponent({ showWebIdeButton: true, showGitpodButton: true, gitpodEnabled: true });
+ createComponent({
+ showEditButton: false,
+ showWebIdeButton: true,
+ showGitpodButton: true,
+ gitpodEnabled: true,
+ });
});
it('selected Web IDE by default', () => {
diff --git a/spec/frontend/vue_shared/directives/tooltip_spec.js b/spec/frontend/vue_shared/directives/tooltip_spec.js
index 9d3dd3c5f75..4217b8d3c02 100644
--- a/spec/frontend/vue_shared/directives/tooltip_spec.js
+++ b/spec/frontend/vue_shared/directives/tooltip_spec.js
@@ -1,42 +1,59 @@
import $ from 'jquery';
+import { escape } from 'lodash';
import { mount } from '@vue/test-utils';
import tooltip from '~/vue_shared/directives/tooltip';
+const DEFAULT_TOOLTIP_TEMPLATE = '<div v-tooltip :title="tooltip"></div>';
+const HTML_TOOLTIP_TEMPLATE = '<div v-tooltip data-html="true" :title="tooltip"></div>';
+
describe('Tooltip directive', () => {
- let vm;
+ let wrapper;
+
+ function createTooltipContainer({
+ template = DEFAULT_TOOLTIP_TEMPLATE,
+ text = 'some text',
+ } = {}) {
+ wrapper = mount(
+ {
+ directives: { tooltip },
+ data: () => ({ tooltip: text }),
+ template,
+ },
+ { attachToDocument: true },
+ );
+ }
+
+ async function showTooltip() {
+ $(wrapper.vm.$el).tooltip('show');
+ jest.runOnlyPendingTimers();
+ await wrapper.vm.$nextTick();
+ }
+
+ function findTooltipInnerHtml() {
+ return document.querySelector('.tooltip-inner').innerHTML;
+ }
+
+ function findTooltipHtml() {
+ return document.querySelector('.tooltip').innerHTML;
+ }
afterEach(() => {
- if (vm) {
- vm.$destroy();
- }
+ wrapper.destroy();
+ wrapper = null;
});
describe('with a single tooltip', () => {
- beforeEach(() => {
- const wrapper = mount(
- {
- directives: {
- tooltip,
- },
- data() {
- return {
- tooltip: 'some text',
- };
- },
- template: '<div v-tooltip :title="tooltip"></div>',
- },
- { attachToDocument: true },
- );
-
- vm = wrapper.vm;
- });
-
it('should have tooltip plugin applied', () => {
- expect($(vm.$el).data('bs.tooltip')).toBeDefined();
+ createTooltipContainer();
+
+ expect($(wrapper.vm.$el).data('bs.tooltip')).toBeDefined();
});
it('displays the title as tooltip', () => {
- $(vm.$el).tooltip('show');
+ createTooltipContainer();
+
+ $(wrapper.vm.$el).tooltip('show');
+
jest.runOnlyPendingTimers();
const tooltipElement = document.querySelector('.tooltip-inner');
@@ -44,52 +61,98 @@ describe('Tooltip directive', () => {
expect(tooltipElement.textContent).toContain('some text');
});
- it('updates a visible tooltip', () => {
- $(vm.$el).tooltip('show');
+ it.each`
+ condition | template | sanitize
+ ${'does not contain any html'} | ${DEFAULT_TOOLTIP_TEMPLATE} | ${false}
+ ${'contains html'} | ${HTML_TOOLTIP_TEMPLATE} | ${true}
+ `('passes sanitize=$sanitize if the tooltip $condition', ({ template, sanitize }) => {
+ createTooltipContainer({ template });
+
+ expect($(wrapper.vm.$el).data('bs.tooltip').config.sanitize).toEqual(sanitize);
+ });
+
+ it('updates a visible tooltip', async () => {
+ createTooltipContainer();
+
+ $(wrapper.vm.$el).tooltip('show');
jest.runOnlyPendingTimers();
const tooltipElement = document.querySelector('.tooltip-inner');
- vm.tooltip = 'other text';
+ wrapper.vm.tooltip = 'other text';
jest.runOnlyPendingTimers();
+ await wrapper.vm.$nextTick();
+
+ expect(tooltipElement.textContent).toContain('other text');
+ });
+
+ describe('tooltip sanitization', () => {
+ it('reads tooltip content as text if data-html is not passed', async () => {
+ createTooltipContainer({ text: 'sample text<script>alert("XSS!!")</script>' });
- return vm.$nextTick().then(() => {
- expect(tooltipElement.textContent).toContain('other text');
+ await showTooltip();
+
+ const result = findTooltipInnerHtml();
+ expect(result).toEqual('sample text&lt;script&gt;alert("XSS!!")&lt;/script&gt;');
+ });
+
+ it('sanitizes tooltip if data-html is passed', async () => {
+ createTooltipContainer({
+ template: HTML_TOOLTIP_TEMPLATE,
+ text: 'sample text<script>alert("XSS!!")</script>',
+ });
+
+ await showTooltip();
+
+ const result = findTooltipInnerHtml();
+ expect(result).toEqual('sample text');
+ expect(result).not.toContain('XSS!!');
+ });
+
+ it('sanitizes tooltip if data-template is passed', async () => {
+ const tooltipTemplate = escape(
+ '<div class="tooltip" role="tooltip"><div onclick="alert(\'XSS!\')" class="arrow"></div><div class="tooltip-inner"></div></div>',
+ );
+
+ createTooltipContainer({
+ template: `<div v-tooltip :title="tooltip" data-html="false" data-template="${tooltipTemplate}"></div>`,
+ });
+
+ await showTooltip();
+
+ const result = findTooltipHtml();
+ expect(result).toEqual(
+ // objectionable element is removed
+ '<div class="arrow"></div><div class="tooltip-inner">some text</div>',
+ );
+ expect(result).not.toContain('XSS!!');
});
});
});
describe('with multiple tooltips', () => {
beforeEach(() => {
- const wrapper = mount(
- {
- directives: {
- tooltip,
- },
- template: `
- <div>
- <div
- v-tooltip
- class="js-look-for-tooltip"
- title="foo">
- </div>
- <div
- v-tooltip
- title="bar">
- </div>
+ createTooltipContainer({
+ template: `
+ <div>
+ <div
+ v-tooltip
+ class="js-look-for-tooltip"
+ title="foo">
</div>
- `,
- },
- { attachToDocument: true },
- );
-
- vm = wrapper.vm;
+ <div
+ v-tooltip
+ title="bar">
+ </div>
+ </div>
+ `,
+ });
});
it('should have tooltip plugin applied to all instances', () => {
expect(
- $(vm.$el)
+ $(wrapper.vm.$el)
.find('.js-look-for-tooltip')
.data('bs.tooltip'),
).toBeDefined();
diff --git a/spec/frontend/vue_shared/droplab_dropdown_button_spec.js b/spec/frontend/vue_shared/droplab_dropdown_button_spec.js
deleted file mode 100644
index e57c730ecee..00000000000
--- a/spec/frontend/vue_shared/droplab_dropdown_button_spec.js
+++ /dev/null
@@ -1,132 +0,0 @@
-import { mount } from '@vue/test-utils';
-
-import DroplabDropdownButton from '~/vue_shared/components/droplab_dropdown_button.vue';
-
-const mockActions = [
- {
- title: 'Foo',
- description: 'Some foo action',
- },
- {
- title: 'Bar',
- description: 'Some bar action',
- },
-];
-
-const createComponent = ({
- size = '',
- dropdownClass = '',
- actions = mockActions,
- defaultAction = 0,
-}) =>
- mount(DroplabDropdownButton, {
- propsData: {
- size,
- dropdownClass,
- actions,
- defaultAction,
- },
- });
-
-describe('DroplabDropdownButton', () => {
- let wrapper;
-
- beforeEach(() => {
- wrapper = createComponent({});
- });
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- describe('data', () => {
- it('contains `selectedAction` representing value of `defaultAction` prop', () => {
- expect(wrapper.vm.selectedAction).toBe(0);
- });
- });
-
- describe('computed', () => {
- describe('selectedActionTitle', () => {
- it('returns string containing title of selected action', () => {
- wrapper.setData({ selectedAction: 0 });
-
- expect(wrapper.vm.selectedActionTitle).toBe(mockActions[0].title);
-
- wrapper.setData({ selectedAction: 1 });
-
- expect(wrapper.vm.selectedActionTitle).toBe(mockActions[1].title);
- });
- });
-
- describe('buttonSizeClass', () => {
- it('returns string containing button sizing class based on `size` prop', done => {
- const wrapperWithSize = createComponent({
- size: 'sm',
- });
-
- wrapperWithSize.vm.$nextTick(() => {
- expect(wrapperWithSize.vm.buttonSizeClass).toBe('btn-sm');
-
- done();
- wrapperWithSize.destroy();
- });
- });
- });
- });
-
- describe('methods', () => {
- describe('handlePrimaryActionClick', () => {
- it('emits `onActionClick` event on component with selectedAction object as param', () => {
- jest.spyOn(wrapper.vm, '$emit');
-
- wrapper.setData({ selectedAction: 0 });
- wrapper.vm.handlePrimaryActionClick();
-
- expect(wrapper.vm.$emit).toHaveBeenCalledWith('onActionClick', mockActions[0]);
- });
- });
-
- describe('handleActionClick', () => {
- it('emits `onActionSelect` event on component with selectedAction index as param', () => {
- jest.spyOn(wrapper.vm, '$emit');
-
- wrapper.vm.handleActionClick(1);
-
- expect(wrapper.vm.$emit).toHaveBeenCalledWith('onActionSelect', 1);
- });
- });
- });
-
- describe('template', () => {
- it('renders default action button', () => {
- const defaultButton = wrapper.findAll('.btn').at(0);
-
- expect(defaultButton.text()).toBe(mockActions[0].title);
- });
-
- it('renders dropdown button', () => {
- const dropdownButton = wrapper.findAll('.dropdown-toggle').at(0);
-
- expect(dropdownButton.isVisible()).toBe(true);
- });
-
- it('renders dropdown actions', () => {
- const dropdownActions = wrapper.findAll('.dropdown-menu li button');
-
- Array(dropdownActions.length)
- .fill()
- .forEach((_, index) => {
- const actionContent = dropdownActions.at(index).find('.description');
-
- expect(actionContent.find('strong').text()).toBe(mockActions[index].title);
- expect(actionContent.find('p').text()).toBe(mockActions[index].description);
- });
- });
-
- it('renders divider between dropdown actions', () => {
- const dropdownDivider = wrapper.find('.dropdown-menu .divider');
-
- expect(dropdownDivider.isVisible()).toBe(true);
- });
- });
-});
diff --git a/spec/frontend/vue_shared/security_reports/security_reports_app_spec.js b/spec/frontend/vue_shared/security_reports/security_reports_app_spec.js
new file mode 100644
index 00000000000..31bdfc931ac
--- /dev/null
+++ b/spec/frontend/vue_shared/security_reports/security_reports_app_spec.js
@@ -0,0 +1,118 @@
+import { mount } from '@vue/test-utils';
+import Api from '~/api';
+import Flash from '~/flash';
+import SecurityReportsApp from '~/vue_shared/security_reports/security_reports_app.vue';
+
+jest.mock('~/flash');
+
+describe('Grouped security reports app', () => {
+ let wrapper;
+ let mrTabsMock;
+
+ const props = {
+ pipelineId: 123,
+ projectId: 456,
+ securityReportsDocsPath: '/docs',
+ };
+
+ const createComponent = () => {
+ wrapper = mount(SecurityReportsApp, {
+ propsData: { ...props },
+ });
+ };
+
+ const findPipelinesTabAnchor = () => wrapper.find('[data-testid="show-pipelines"]');
+ const findHelpLink = () => wrapper.find('[data-testid="help"]');
+ const setupMrTabsMock = () => {
+ mrTabsMock = { tabShown: jest.fn() };
+ window.mrTabs = mrTabsMock;
+ };
+ const setupMockJobArtifact = reportType => {
+ jest
+ .spyOn(Api, 'pipelineJobs')
+ .mockResolvedValue({ data: [{ artifacts: [{ file_type: reportType }] }] });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ delete window.mrTabs;
+ });
+
+ describe.each(SecurityReportsApp.reportTypes)('given a report type %p', reportType => {
+ beforeEach(() => {
+ window.mrTabs = { tabShown: jest.fn() };
+ setupMockJobArtifact(reportType);
+ createComponent();
+ });
+
+ it('calls the pipelineJobs API correctly', () => {
+ expect(Api.pipelineJobs).toHaveBeenCalledWith(props.projectId, props.pipelineId);
+ });
+
+ it('renders the expected message', () => {
+ expect(wrapper.text()).toMatchInterpolatedText(SecurityReportsApp.i18n.scansHaveRun);
+ });
+
+ describe('clicking the anchor to the pipelines tab', () => {
+ beforeEach(() => {
+ setupMrTabsMock();
+ findPipelinesTabAnchor().trigger('click');
+ });
+
+ it('calls the mrTabs.tabShown global', () => {
+ expect(mrTabsMock.tabShown.mock.calls).toEqual([['pipelines']]);
+ });
+ });
+
+ it('renders a help link', () => {
+ expect(findHelpLink().attributes()).toMatchObject({
+ href: props.securityReportsDocsPath,
+ });
+ });
+ });
+
+ describe('given a report type "foo"', () => {
+ beforeEach(() => {
+ setupMockJobArtifact('foo');
+ createComponent();
+ });
+
+ it('calls the pipelineJobs API correctly', () => {
+ expect(Api.pipelineJobs).toHaveBeenCalledWith(props.projectId, props.pipelineId);
+ });
+
+ it('renders nothing', () => {
+ expect(wrapper.html()).toBe('');
+ });
+ });
+
+ describe('given an error from the API', () => {
+ let error;
+
+ beforeEach(() => {
+ error = new Error('an error');
+ jest.spyOn(Api, 'pipelineJobs').mockRejectedValue(error);
+ createComponent();
+ });
+
+ it('calls the pipelineJobs API correctly', () => {
+ expect(Api.pipelineJobs).toHaveBeenCalledWith(props.projectId, props.pipelineId);
+ });
+
+ it('renders nothing', () => {
+ expect(wrapper.html()).toBe('');
+ });
+
+ it('calls Flash correctly', () => {
+ expect(Flash.mock.calls).toEqual([
+ [
+ {
+ message: SecurityReportsApp.i18n.apiError,
+ captureError: true,
+ error,
+ },
+ ],
+ ]);
+ });
+ });
+});
diff --git a/spec/frontend/vuex_shared/modules/members/actions_spec.js b/spec/frontend/vuex_shared/modules/members/actions_spec.js
new file mode 100644
index 00000000000..833bd4cc175
--- /dev/null
+++ b/spec/frontend/vuex_shared/modules/members/actions_spec.js
@@ -0,0 +1,110 @@
+import { noop } from 'lodash';
+import axios from 'axios';
+import MockAdapter from 'axios-mock-adapter';
+import { members, group } from 'jest/vue_shared/components/members/mock_data';
+import testAction from 'helpers/vuex_action_helper';
+import httpStatusCodes from '~/lib/utils/http_status';
+import * as types from '~/vuex_shared/modules/members/mutation_types';
+import {
+ updateMemberRole,
+ showRemoveGroupLinkModal,
+ hideRemoveGroupLinkModal,
+} from '~/vuex_shared/modules/members/actions';
+
+describe('Vuex members actions', () => {
+ let mock;
+
+ beforeEach(() => {
+ mock = new MockAdapter(axios);
+ });
+
+ afterEach(() => {
+ mock.restore();
+ });
+
+ describe('updateMemberRole', () => {
+ const memberId = members[0].id;
+ const accessLevel = { integerValue: 30, stringValue: 'Developer' };
+
+ const payload = {
+ memberId,
+ accessLevel,
+ };
+ const state = {
+ members,
+ memberPath: '/groups/foo-bar/-/group_members/:id',
+ requestFormatter: noop,
+ removeGroupLinkModalVisible: false,
+ groupLinkToRemove: null,
+ };
+
+ describe('successful request', () => {
+ it(`commits ${types.RECEIVE_MEMBER_ROLE_SUCCESS} mutation`, async () => {
+ let requestPath;
+ mock.onPut().replyOnce(config => {
+ requestPath = config.url;
+ return [httpStatusCodes.OK, {}];
+ });
+
+ await testAction(updateMemberRole, payload, state, [
+ {
+ type: types.RECEIVE_MEMBER_ROLE_SUCCESS,
+ payload,
+ },
+ ]);
+
+ expect(requestPath).toBe('/groups/foo-bar/-/group_members/238');
+ });
+ });
+
+ describe('unsuccessful request', () => {
+ beforeEach(() => {
+ mock.onPut().replyOnce(httpStatusCodes.BAD_REQUEST, { message: 'Bad request' });
+ });
+
+ it(`commits ${types.RECEIVE_MEMBER_ROLE_ERROR} mutation`, async () => {
+ try {
+ await testAction(updateMemberRole, payload, state, [
+ {
+ type: types.RECEIVE_MEMBER_ROLE_SUCCESS,
+ },
+ ]);
+ } catch {
+ // Do nothing
+ }
+ });
+
+ it('throws error', async () => {
+ await expect(testAction(updateMemberRole, payload, state)).rejects.toThrowError();
+ });
+ });
+ });
+
+ describe('Group Link Modal', () => {
+ const state = {
+ removeGroupLinkModalVisible: false,
+ groupLinkToRemove: null,
+ };
+
+ describe('showRemoveGroupLinkModal', () => {
+ it(`commits ${types.SHOW_REMOVE_GROUP_LINK_MODAL} mutation`, () => {
+ testAction(showRemoveGroupLinkModal, group, state, [
+ {
+ type: types.SHOW_REMOVE_GROUP_LINK_MODAL,
+ payload: group,
+ },
+ ]);
+ });
+ });
+
+ describe('hideRemoveGroupLinkModal', () => {
+ it(`commits ${types.HIDE_REMOVE_GROUP_LINK_MODAL} mutation`, () => {
+ testAction(hideRemoveGroupLinkModal, group, state, [
+ {
+ type: types.HIDE_REMOVE_GROUP_LINK_MODAL,
+ },
+ ]);
+ });
+ });
+ });
+});
diff --git a/spec/frontend/vuex_shared/modules/members/mutations_spec.js b/spec/frontend/vuex_shared/modules/members/mutations_spec.js
new file mode 100644
index 00000000000..7338b19cfc9
--- /dev/null
+++ b/spec/frontend/vuex_shared/modules/members/mutations_spec.js
@@ -0,0 +1,90 @@
+import { members, group } from 'jest/vue_shared/components/members/mock_data';
+import mutations from '~/vuex_shared/modules/members/mutations';
+import * as types from '~/vuex_shared/modules/members/mutation_types';
+
+describe('Vuex members mutations', () => {
+ describe(types.RECEIVE_MEMBER_ROLE_SUCCESS, () => {
+ it('updates member', () => {
+ const state = {
+ members,
+ };
+
+ const accessLevel = { integerValue: 30, stringValue: 'Developer' };
+
+ mutations[types.RECEIVE_MEMBER_ROLE_SUCCESS](state, {
+ memberId: members[0].id,
+ accessLevel,
+ });
+
+ expect(state.members[0].accessLevel).toEqual(accessLevel);
+ });
+ });
+
+ describe(types.RECEIVE_MEMBER_ROLE_ERROR, () => {
+ it('shows error message', () => {
+ const state = {
+ showError: false,
+ errorMessage: '',
+ };
+
+ mutations[types.RECEIVE_MEMBER_ROLE_ERROR](state);
+
+ expect(state.showError).toBe(true);
+ expect(state.errorMessage).toBe(
+ "An error occurred while updating the member's role, please try again.",
+ );
+ });
+ });
+
+ describe(types.HIDE_ERROR, () => {
+ it('sets `showError` to `false`', () => {
+ const state = {
+ showError: true,
+ errorMessage: 'foo bar',
+ };
+
+ mutations[types.HIDE_ERROR](state);
+
+ expect(state.showError).toBe(false);
+ });
+
+ it('sets `errorMessage` to an empty string', () => {
+ const state = {
+ showError: true,
+ errorMessage: 'foo bar',
+ };
+
+ mutations[types.HIDE_ERROR](state);
+
+ expect(state.errorMessage).toBe('');
+ });
+ });
+
+ describe(types.SHOW_REMOVE_GROUP_LINK_MODAL, () => {
+ it('sets `removeGroupLinkModalVisible` and `groupLinkToRemove`', () => {
+ const state = {
+ removeGroupLinkModalVisible: false,
+ groupLinkToRemove: null,
+ };
+
+ mutations[types.SHOW_REMOVE_GROUP_LINK_MODAL](state, group);
+
+ expect(state).toEqual({
+ removeGroupLinkModalVisible: true,
+ groupLinkToRemove: group,
+ });
+ });
+ });
+
+ describe(types.HIDE_REMOVE_GROUP_LINK_MODAL, () => {
+ it('sets `removeGroupLinkModalVisible` to `false`', () => {
+ const state = {
+ removeGroupLinkModalVisible: false,
+ };
+
+ mutations[types.HIDE_REMOVE_GROUP_LINK_MODAL](state);
+
+ expect(state.removeGroupLinkModalVisible).toBe(false);
+ });
+ });
+});
diff --git a/spec/frontend/vuex_shared/modules/members/utils_spec.js b/spec/frontend/vuex_shared/modules/members/utils_spec.js
new file mode 100644
index 00000000000..4fc3445dac0
--- /dev/null
+++ b/spec/frontend/vuex_shared/modules/members/utils_spec.js
@@ -0,0 +1,14 @@
+import { members } from 'jest/vue_shared/components/members/mock_data';
+import { findMember } from '~/vuex_shared/modules/members/utils';
+
+describe('Members Vuex utils', () => {
+ describe('findMember', () => {
+ it('finds member by ID', () => {
+ const state = {
+ members,
+ };
+
+ expect(findMember(state, members[0].id)).toEqual(members[0]);
+ });
+ });
+});
diff --git a/spec/frontend/whats_new/components/app_spec.js b/spec/frontend/whats_new/components/app_spec.js
index 59d05f68fdd..77c2ae19d1f 100644
--- a/spec/frontend/whats_new/components/app_spec.js
+++ b/spec/frontend/whats_new/components/app_spec.js
@@ -1,26 +1,30 @@
import { createLocalVue, mount } from '@vue/test-utils';
import Vuex from 'vuex';
import { GlDrawer } from '@gitlab/ui';
+import { mockTracking, unmockTracking, triggerEvent } from 'helpers/tracking_helper';
import App from '~/whats_new/components/app.vue';
const localVue = createLocalVue();
localVue.use(Vuex);
describe('App', () => {
+ const propsData = { storageKey: 'storage-key' };
let wrapper;
let store;
let actions;
let state;
- let propsData = { features: '[ {"title":"Whats New Drawer"} ]' };
+ let trackingSpy;
const buildWrapper = () => {
actions = {
openDrawer: jest.fn(),
closeDrawer: jest.fn(),
+ fetchItems: jest.fn(),
};
state = {
open: true,
+ features: null,
};
store = new Vuex.Store({
@@ -35,12 +39,20 @@ describe('App', () => {
});
};
- beforeEach(() => {
+ beforeEach(async () => {
+ document.body.dataset.page = 'test-page';
+ document.body.dataset.namespaceId = 'namespace-840';
+
+ trackingSpy = mockTracking('_category_', null, jest.spyOn);
buildWrapper();
+
+ wrapper.vm.$store.state.features = [{ title: 'Whats New Drawer', url: 'www.url.com' }];
+ await wrapper.vm.$nextTick();
});
afterEach(() => {
wrapper.destroy();
+ unmockTracking();
});
const getDrawer = () => wrapper.find(GlDrawer);
@@ -50,7 +62,11 @@ describe('App', () => {
});
it('dispatches openDrawer when mounted', () => {
- expect(actions.openDrawer).toHaveBeenCalled();
+ expect(actions.openDrawer).toHaveBeenCalledWith(expect.any(Object), 'storage-key');
+ expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_whats_new_drawer', {
+ label: 'namespace_id',
+ value: 'namespace-840',
+ });
});
it('dispatches closeDrawer when clicking close', () => {
@@ -66,14 +82,24 @@ describe('App', () => {
expect(getDrawer().props('open')).toBe(openState);
});
- it('renders features when provided as props', () => {
+ it('renders features when provided via ajax', () => {
+ expect(actions.fetchItems).toHaveBeenCalled();
expect(wrapper.find('h5').text()).toBe('Whats New Drawer');
});
- it('handles bad json argument gracefully', () => {
- propsData = { features: 'this is not json' };
- buildWrapper();
+ it('send an event when feature item is clicked', () => {
+ trackingSpy = mockTracking('_category_', wrapper.element, jest.spyOn);
- expect(getDrawer().exists()).toBe(true);
+ const link = wrapper.find('[data-testid="whats-new-title-link"]');
+ triggerEvent(link.element);
+
+ expect(trackingSpy.mock.calls[1]).toMatchObject([
+ '_category_',
+ 'click_whats_new_item',
+ {
+ label: 'Whats New Drawer',
+ property: 'www.url.com',
+ },
+ ]);
});
});
diff --git a/spec/frontend/whats_new/store/actions_spec.js b/spec/frontend/whats_new/store/actions_spec.js
index d95453c9175..95ab667d611 100644
--- a/spec/frontend/whats_new/store/actions_spec.js
+++ b/spec/frontend/whats_new/store/actions_spec.js
@@ -1,11 +1,19 @@
import testAction from 'helpers/vuex_action_helper';
+import { useLocalStorageSpy } from 'helpers/local_storage_helper';
+import MockAdapter from 'axios-mock-adapter';
+import waitForPromises from 'helpers/wait_for_promises';
import actions from '~/whats_new/store/actions';
import * as types from '~/whats_new/store/mutation_types';
+import axios from '~/lib/utils/axios_utils';
describe('whats new actions', () => {
describe('openDrawer', () => {
+ useLocalStorageSpy();
+
it('should commit openDrawer', () => {
- testAction(actions.openDrawer, {}, {}, [{ type: types.OPEN_DRAWER }]);
+ testAction(actions.openDrawer, 'storage-key', {}, [{ type: types.OPEN_DRAWER }]);
+
+ expect(window.localStorage.setItem).toHaveBeenCalledWith('storage-key', 'false');
});
});
@@ -14,4 +22,27 @@ describe('whats new actions', () => {
testAction(actions.closeDrawer, {}, {}, [{ type: types.CLOSE_DRAWER }]);
});
});
+
+ describe('fetchItems', () => {
+ let axiosMock;
+
+ beforeEach(async () => {
+ axiosMock = new MockAdapter(axios);
+ axiosMock
+ .onGet('/-/whats_new')
+ .replyOnce(200, [{ title: 'Whats New Drawer', url: 'www.url.com' }]);
+
+ await waitForPromises();
+ });
+
+ afterEach(() => {
+ axiosMock.restore();
+ });
+
+ it('should commit setFeatures', () => {
+ testAction(actions.fetchItems, {}, {}, [
+ { type: types.SET_FEATURES, payload: [{ title: 'Whats New Drawer', url: 'www.url.com' }] },
+ ]);
+ });
+ });
});
diff --git a/spec/frontend/whats_new/store/mutations_spec.js b/spec/frontend/whats_new/store/mutations_spec.js
index 3c33364fed3..feaa1dd2a3b 100644
--- a/spec/frontend/whats_new/store/mutations_spec.js
+++ b/spec/frontend/whats_new/store/mutations_spec.js
@@ -22,4 +22,11 @@ describe('whats new mutations', () => {
expect(state.open).toBe(false);
});
});
+
+ describe('setFeatures', () => {
+ it('sets features to data', () => {
+ mutations[types.SET_FEATURES](state, 'bells and whistles');
+ expect(state.features).toBe('bells and whistles');
+ });
+ });
});
diff --git a/spec/frontend/wikis_spec.js b/spec/frontend/wikis_spec.js
index 3469be4da1c..cf1ea972697 100644
--- a/spec/frontend/wikis_spec.js
+++ b/spec/frontend/wikis_spec.js
@@ -146,7 +146,7 @@ describe('Wikis', () => {
expect(Tracking.event).toHaveBeenCalledWith(trackingPage, 'view_wiki_page', {
label: 'view_wiki_page',
context: {
- schema: 'iglu:com.gitlab/wiki_page_context/jsonschema/1-0-0',
+ schema: 'iglu:com.gitlab/wiki_page_context/jsonschema/1-0-1',
data: trackingContext,
},
});
diff --git a/spec/frontend_integration/.eslintrc.yml b/spec/frontend_integration/.eslintrc.yml
index 26b6f935ffb..2460e218f59 100644
--- a/spec/frontend_integration/.eslintrc.yml
+++ b/spec/frontend_integration/.eslintrc.yml
@@ -4,3 +4,5 @@ settings:
import/resolver:
jest:
jestConfigFile: 'jest.config.integration.js'
+globals:
+ mockServer: false
diff --git a/spec/frontend_integration/ide/__snapshots__/ide_integration_spec.js.snap b/spec/frontend_integration/ide/__snapshots__/ide_integration_spec.js.snap
index 6beb5eab6db..6c120898f01 100644
--- a/spec/frontend_integration/ide/__snapshots__/ide_integration_spec.js.snap
+++ b/spec/frontend_integration/ide/__snapshots__/ide_integration_spec.js.snap
@@ -20,6 +20,7 @@ exports[`WebIDE runs 1`] = `
>
<div
class="multi-file-commit-panel-inner"
+ data-testid="ide-side-bar-inner"
>
<div
class="multi-file-loading-container"
diff --git a/spec/frontend_integration/ide/ide_helper.js b/spec/frontend_integration/ide/ide_helper.js
new file mode 100644
index 00000000000..a43695fea8f
--- /dev/null
+++ b/spec/frontend_integration/ide/ide_helper.js
@@ -0,0 +1,102 @@
+import { findAllByText, fireEvent, getByLabelText, screen } from '@testing-library/dom';
+
+const isFileRowOpen = row => row.matches('.is-open');
+
+const getLeftSidebar = () => screen.getByTestId('left-sidebar');
+
+const clickOnLeftSidebarTab = name => {
+ const sidebar = getLeftSidebar();
+
+ const button = getByLabelText(sidebar, name);
+
+ button.click();
+};
+
+const findMonacoEditor = () =>
+ screen.findByLabelText(/Editor content;/).then(x => x.closest('.monaco-editor'));
+
+const findAndSetEditorValue = async value => {
+ const editor = await findMonacoEditor();
+ const uri = editor.getAttribute('data-uri');
+
+ window.monaco.editor.getModel(uri).setValue(value);
+};
+
+const findTreeBody = () => screen.findByTestId('ide-tree-body', {}, { timeout: 5000 });
+
+const findFileRowContainer = (row = null) =>
+ row ? Promise.resolve(row.parentElement) : findTreeBody();
+
+const findFileChild = async (row, name, index = 0) => {
+ const container = await findFileRowContainer(row);
+ const children = await findAllByText(container, name, { selector: '.file-row-name' });
+
+ return children.map(x => x.closest('.file-row')).find(x => x.dataset.level === index.toString());
+};
+
+const openFileRow = row => {
+ if (!row || isFileRowOpen(row)) {
+ return;
+ }
+
+ row.click();
+};
+
+const findAndTraverseToPath = async (path, index = 0, row = null) => {
+ if (!path) {
+ return row;
+ }
+
+ const [name, ...restOfPath] = path.split('/');
+
+ openFileRow(row);
+
+ const child = await findFileChild(row, name, index);
+
+ return findAndTraverseToPath(restOfPath.join('/'), index + 1, child);
+};
+
+const clickFileRowAction = (row, name) => {
+ fireEvent.mouseOver(row);
+
+ const dropdownButton = getByLabelText(row, 'Create new file or directory');
+ dropdownButton.click();
+
+ const dropdownAction = getByLabelText(dropdownButton.parentNode, name);
+ dropdownAction.click();
+};
+
+const findAndSetFileName = async value => {
+ const nameField = await screen.findByTestId('file-name-field');
+ fireEvent.input(nameField, { target: { value } });
+
+ const createButton = screen.getByText('Create file');
+ createButton.click();
+};
+
+export const createFile = async (path, content) => {
+ const parentPath = path
+ .split('/')
+ .slice(0, -1)
+ .join('/');
+
+ const parentRow = await findAndTraverseToPath(parentPath);
+ clickFileRowAction(parentRow, 'New file');
+
+ await findAndSetFileName(path);
+ await findAndSetEditorValue(content);
+};
+
+export const deleteFile = async path => {
+ const row = await findAndTraverseToPath(path);
+ clickFileRowAction(row, 'Delete');
+};
+
+export const commit = async () => {
+ clickOnLeftSidebarTab('Commit');
+ screen.getByTestId('begin-commit-button').click();
+
+ await screen.findByLabelText(/Commit to .+ branch/).then(x => x.click());
+
+ screen.getByText('Commit').click();
+};
diff --git a/spec/frontend_integration/ide/ide_integration_spec.js b/spec/frontend_integration/ide/ide_integration_spec.js
index 91d89c26ec1..c4d0c4df8de 100644
--- a/spec/frontend_integration/ide/ide_integration_spec.js
+++ b/spec/frontend_integration/ide/ide_integration_spec.js
@@ -1,17 +1,10 @@
-/**
- * WARNING: WIP
- *
- * Please do not copy from this spec or use it as an example for anything.
- *
- * This is in place to iteratively set up the frontend integration testing environment
- * and will be improved upon in a later iteration.
- *
- * See https://gitlab.com/gitlab-org/gitlab/-/issues/208800 for more information.
- */
import { TEST_HOST } from 'helpers/test_constants';
+import { waitForText } from 'helpers/wait_for_text';
import { useOverclockTimers } from 'test_helpers/utils/overclock_timers';
+import { createCommitId } from 'test_helpers/factories/commit_id';
import { initIde } from '~/ide';
import extendStore from '~/ide/stores/extend';
+import * as ideHelper from './ide_helper';
const TEST_DATASET = {
emptyStateSvgPath: '/test/empty_state.svg',
@@ -59,4 +52,38 @@ describe('WebIDE', () => {
expect(root).toMatchSnapshot();
});
+
+ it('user commits changes', async () => {
+ createComponent();
+
+ await ideHelper.createFile('foo/bar/test.txt', 'Lorem ipsum dolar sit');
+ await ideHelper.deleteFile('foo/bar/.gitkeep');
+ await ideHelper.commit();
+
+ const commitId = createCommitId(1);
+ const commitShortId = commitId.slice(0, 8);
+
+ await waitForText('All changes are committed');
+ await waitForText(commitShortId);
+
+ expect(mockServer.db.branches.findBy({ name: 'master' }).commit).toMatchObject({
+ short_id: commitShortId,
+ id: commitId,
+ message: 'Update foo/bar/test.txt\nDeleted foo/bar/.gitkeep',
+ __actions: [
+ {
+ action: 'create',
+ content: 'Lorem ipsum dolar sit\n',
+ encoding: 'text',
+ file_path: 'foo/bar/test.txt',
+ last_commit_id: '',
+ },
+ {
+ action: 'delete',
+ encoding: 'text',
+ file_path: 'foo/bar/.gitkeep',
+ },
+ ],
+ });
+ });
});
diff --git a/spec/frontend_integration/test_helpers/setup/setup_mock_server.js b/spec/frontend_integration/test_helpers/setup/setup_mock_server.js
index 343aeebf88e..43a21deed25 100644
--- a/spec/frontend_integration/test_helpers/setup/setup_mock_server.js
+++ b/spec/frontend_integration/test_helpers/setup/setup_mock_server.js
@@ -1,13 +1,12 @@
import { createMockServer } from '../mock_server';
beforeEach(() => {
+ if (global.mockServer) {
+ global.mockServer.shutdown();
+ }
+
const server = createMockServer();
server.logging = false;
global.mockServer = server;
});
-
-afterEach(() => {
- global.mockServer.shutdown();
- global.mockServer = null;
-});
diff --git a/spec/graphql/features/feature_flag_spec.rb b/spec/graphql/features/feature_flag_spec.rb
index b484663d675..9ebc6e595a6 100644
--- a/spec/graphql/features/feature_flag_spec.rb
+++ b/spec/graphql/features/feature_flag_spec.rb
@@ -12,6 +12,10 @@ RSpec.describe 'Graphql Field feature flags' do
let(:query_string) { '{ item { name } }' }
let(:result) { execute_query(query_type)['data'] }
+ before do
+ skip_feature_flags_yaml_validation
+ end
+
subject { result }
describe 'Feature flagged field' do
diff --git a/spec/graphql/mutations/design_management/move_spec.rb b/spec/graphql/mutations/design_management/move_spec.rb
index 7519347d07c..d17483e69b3 100644
--- a/spec/graphql/mutations/design_management/move_spec.rb
+++ b/spec/graphql/mutations/design_management/move_spec.rb
@@ -29,7 +29,7 @@ RSpec.describe Mutations::DesignManagement::Move do
next_design: next_design&.to_global_id
}.compact
- mutation.resolve(args)
+ mutation.resolve(**args)
end
shared_examples "resource not available" do
diff --git a/spec/graphql/mutations/discussions/toggle_resolve_spec.rb b/spec/graphql/mutations/discussions/toggle_resolve_spec.rb
index d779a2227c1..2e5d41a8f1e 100644
--- a/spec/graphql/mutations/discussions/toggle_resolve_spec.rb
+++ b/spec/graphql/mutations/discussions/toggle_resolve_spec.rb
@@ -50,8 +50,8 @@ RSpec.describe Mutations::Discussions::ToggleResolve do
it 'raises an error' do
expect { subject }.to raise_error(
- Gitlab::Graphql::Errors::ArgumentError,
- "#{discussion.to_global_id} is not a valid ID for Discussion."
+ GraphQL::CoercionError,
+ "\"#{discussion.to_global_id}\" does not represent an instance of Discussion"
)
end
end
diff --git a/spec/graphql/mutations/issues/create_spec.rb b/spec/graphql/mutations/issues/create_spec.rb
new file mode 100644
index 00000000000..57658f6b358
--- /dev/null
+++ b/spec/graphql/mutations/issues/create_spec.rb
@@ -0,0 +1,146 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Mutations::Issues::Create do
+ let_it_be(:project) { create(:project) }
+ let_it_be(:user) { create(:user) }
+ let_it_be(:assignee1) { create(:user) }
+ let_it_be(:assignee2) { create(:user) }
+ let_it_be(:project_label1) { create(:label, project: project) }
+ let_it_be(:project_label2) { create(:label, project: project) }
+ let_it_be(:milestone) { create(:milestone, project: project) }
+ let_it_be(:new_label1) { FFaker::Lorem.word }
+ let_it_be(:new_label2) { new_label1 + 'Extra' }
+
+ let(:expected_attributes) do
+ {
+ title: 'new title',
+ description: 'new description',
+ confidential: true,
+ due_date: Date.tomorrow,
+ discussion_locked: true
+ }
+ end
+
+ let(:mutation_params) do
+ {
+ project_path: project.full_path,
+ milestone_id: milestone.to_global_id,
+ labels: [project_label1.title, project_label2.title, new_label1, new_label2],
+ assignee_ids: [assignee1.to_global_id, assignee2.to_global_id]
+ }.merge(expected_attributes)
+ end
+
+ let(:special_params) do
+ {
+ iid: non_existing_record_id,
+ created_at: 2.days.ago
+ }
+ end
+
+ let(:mutation) { described_class.new(object: nil, context: { current_user: user }, field: nil) }
+ let(:mutated_issue) { subject[:issue] }
+
+ specify { expect(described_class).to require_graphql_authorizations(:create_issue) }
+
+ describe '#resolve' do
+ before do
+ stub_licensed_features(multiple_issue_assignees: false, issue_weights: false)
+ project.add_guest(assignee1)
+ project.add_guest(assignee2)
+ end
+
+ subject { mutation.resolve(mutation_params) }
+
+ context 'when the user does not have permission to create an issue' do
+ it 'raises an error' do
+ expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
+ end
+ end
+
+ context 'when the user can create an issue' do
+ context 'when creating an issue a developer' do
+ before do
+ project.add_developer(user)
+ end
+
+ it 'creates issue with correct values' do
+ expect(mutated_issue).to have_attributes(expected_attributes)
+ expect(mutated_issue.milestone_id).to eq(milestone.id)
+ expect(mutated_issue.labels.pluck(:title)).to eq([project_label1.title, project_label2.title, new_label1, new_label2])
+ expect(mutated_issue.assignees.pluck(:id)).to eq([assignee1.id])
+ end
+
+ context 'when passing in label_ids' do
+ before do
+ mutation_params.delete(:labels)
+ mutation_params.merge!(label_ids: [project_label1.to_global_id, project_label2.to_global_id])
+ end
+
+ it 'creates issue with correct values' do
+ expect(mutated_issue.labels.pluck(:title)).to eq([project_label1.title, project_label2.title])
+ end
+ end
+
+ context 'when trying to create issue with restricted params' do
+ before do
+ mutation_params.merge!(special_params)
+ end
+
+ it 'ignores the special params' do
+ expect(mutated_issue).not_to be_like_time(special_params[:created_at])
+ expect(mutated_issue.iid).not_to eq(special_params[:iid])
+ end
+ end
+ end
+
+ context 'when creating an issue as owner' do
+ let_it_be(:user) { project.owner }
+
+ before do
+ mutation_params.merge!(special_params)
+ end
+
+ it 'sets the special params' do
+ expect(mutated_issue.created_at).to be_like_time(special_params[:created_at])
+ expect(mutated_issue.iid).to eq(special_params[:iid])
+ end
+ end
+ end
+ end
+
+ describe "#ready?" do
+ context 'when passing in both labels and label_ids' do
+ before do
+ mutation_params.merge!(label_ids: [project_label1.to_global_id, project_label2.to_global_id])
+ end
+
+ it 'raises exception when mutually exclusive params are given' do
+ expect { mutation.ready?(mutation_params) }
+ .to raise_error(Gitlab::Graphql::Errors::ArgumentError, /one and only one of/)
+ end
+ end
+
+ context 'when passing only `discussion_to_resolve` param' do
+ before do
+ mutation_params.merge!(discussion_to_resolve: 'abc')
+ end
+
+ it 'raises exception when mutually exclusive params are given' do
+ expect { mutation.ready?(mutation_params) }
+ .to raise_error(Gitlab::Graphql::Errors::ArgumentError, /to resolve a discussion please also provide `merge_request_to_resolve_discussions_of` parameter/)
+ end
+ end
+
+ context 'when passing only `merge_request_to_resolve_discussions_of` param' do
+ before do
+ mutation_params.merge!(merge_request_to_resolve_discussions_of: 'abc')
+ end
+
+ it 'raises exception when mutually exclusive params are given' do
+ expect { mutation.ready?(mutation_params) }.not_to raise_error
+ end
+ end
+ end
+end
diff --git a/spec/graphql/mutations/issues/move_spec.rb b/spec/graphql/mutations/issues/move_spec.rb
new file mode 100644
index 00000000000..c8e9c556a3f
--- /dev/null
+++ b/spec/graphql/mutations/issues/move_spec.rb
@@ -0,0 +1,41 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Mutations::Issues::Move do
+ let_it_be(:issue) { create(:issue) }
+ let_it_be(:user) { create(:user) }
+ let_it_be(:target_project) { create(:project) }
+
+ subject(:mutation) { described_class.new(object: nil, context: { current_user: user }, field: nil) }
+
+ describe '#resolve' do
+ subject(:resolve) { mutation.resolve(project_path: issue.project.full_path, iid: issue.iid, target_project_path: target_project.full_path) }
+
+ it 'raises an error if the resource is not accessible to the user' do
+ expect { resolve }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
+ end
+
+ context 'when user does not have permissions' do
+ before do
+ issue.project.add_developer(user)
+ end
+
+ it 'returns error message' do
+ expect(resolve[:issue]).to eq(nil)
+ expect(resolve[:errors].first).to eq('Cannot move issue due to insufficient permissions!')
+ end
+ end
+
+ context 'when user has sufficient permissions' do
+ before do
+ issue.project.add_developer(user)
+ target_project.add_developer(user)
+ end
+
+ it 'moves issue' do
+ expect(resolve[:issue].project).to eq(target_project)
+ end
+ end
+ end
+end
diff --git a/spec/graphql/mutations/issues/update_spec.rb b/spec/graphql/mutations/issues/update_spec.rb
index 15c15afd9b7..f9f4bdeb6fa 100644
--- a/spec/graphql/mutations/issues/update_spec.rb
+++ b/spec/graphql/mutations/issues/update_spec.rb
@@ -70,6 +70,23 @@ RSpec.describe Mutations::Issues::Update do
end
end
+ context 'when changing state' do
+ let_it_be_with_refind(:issue) { create(:issue, project: project, state: :opened) }
+
+ it 'closes issue' do
+ mutation_params[:state_event] = 'close'
+
+ expect { subject }.to change { issue.reload.state }.from('opened').to('closed')
+ end
+
+ it 'reopens issue' do
+ issue.close
+ mutation_params[:state_event] = 'reopen'
+
+ expect { subject }.to change { issue.reload.state }.from('closed').to('opened')
+ end
+ end
+
context 'when changing labels' do
let_it_be(:label_1) { create(:label, project: project) }
let_it_be(:label_2) { create(:label, project: project) }
diff --git a/spec/graphql/mutations/todos/mark_done_spec.rb b/spec/graphql/mutations/todos/mark_done_spec.rb
index 51ad3e1a5d7..b5f2ff5d044 100644
--- a/spec/graphql/mutations/todos/mark_done_spec.rb
+++ b/spec/graphql/mutations/todos/mark_done_spec.rb
@@ -52,7 +52,8 @@ RSpec.describe Mutations::Todos::MarkDone do
end
it 'ignores invalid GIDs' do
- expect { mutation.resolve(id: 'invalid_gid') }.to raise_error(Gitlab::Graphql::Errors::ArgumentError)
+ expect { mutation.resolve(id: author.to_global_id.to_s) }
+ .to raise_error(::GraphQL::CoercionError)
expect(todo1.reload.state).to eq('pending')
expect(todo2.reload.state).to eq('done')
diff --git a/spec/graphql/mutations/todos/restore_many_spec.rb b/spec/graphql/mutations/todos/restore_many_spec.rb
index b3b3e057745..59995e33f2d 100644
--- a/spec/graphql/mutations/todos/restore_many_spec.rb
+++ b/spec/graphql/mutations/todos/restore_many_spec.rb
@@ -3,6 +3,8 @@
require 'spec_helper'
RSpec.describe Mutations::Todos::RestoreMany do
+ include GraphqlHelpers
+
let_it_be(:current_user) { create(:user) }
let_it_be(:author) { create(:user) }
let_it_be(:other_user) { create(:user) }
@@ -44,8 +46,9 @@ RSpec.describe Mutations::Todos::RestoreMany do
expect_states_were_not_changed
end
- it 'ignores invalid GIDs' do
- expect { mutation.resolve(ids: ['invalid_gid']) }.to raise_error(URI::BadURIError)
+ it 'raises an error with invalid or non-Todo GIDs' do
+ expect { mutation.resolve(ids: [author.to_global_id.to_s]) }
+ .to raise_error(GraphQL::CoercionError)
expect_states_were_not_changed
end
@@ -78,38 +81,12 @@ RSpec.describe Mutations::Todos::RestoreMany do
it 'fails if too many todos are requested for update' do
expect { restore_mutation([todo1] * 51) }.to raise_error(Gitlab::Graphql::Errors::ArgumentError)
end
-
- it 'does not update todos from another app' do
- todo4 = create(:todo)
- todo4_gid = ::URI::GID.parse("gid://otherapp/Todo/#{todo4.id}")
-
- result = mutation.resolve(ids: [todo4_gid.to_s])
-
- expect(result[:updated_ids]).to be_empty
-
- expect_states_were_not_changed
- end
-
- it 'does not update todos from another model' do
- todo4 = create(:todo)
- todo4_gid = ::URI::GID.parse("gid://#{GlobalID.app}/Project/#{todo4.id}")
-
- result = mutation.resolve(ids: [todo4_gid.to_s])
-
- expect(result[:updated_ids]).to be_empty
-
- expect_states_were_not_changed
- end
end
def restore_mutation(todos)
mutation.resolve(ids: todos.map { |todo| global_id_of(todo) } )
end
- def global_id_of(todo)
- todo.to_global_id.to_s
- end
-
def expect_states_were_not_changed
expect(todo1.reload.state).to eq('done')
expect(todo2.reload.state).to eq('pending')
diff --git a/spec/graphql/mutations/todos/restore_spec.rb b/spec/graphql/mutations/todos/restore_spec.rb
index 9043d7a44a8..22fb1bba7a8 100644
--- a/spec/graphql/mutations/todos/restore_spec.rb
+++ b/spec/graphql/mutations/todos/restore_spec.rb
@@ -3,6 +3,8 @@
require 'spec_helper'
RSpec.describe Mutations::Todos::Restore do
+ include GraphqlHelpers
+
let_it_be(:current_user) { create(:user) }
let_it_be(:author) { create(:user) }
let_it_be(:other_user) { create(:user) }
@@ -49,8 +51,9 @@ RSpec.describe Mutations::Todos::Restore do
expect(other_user_todo.reload.state).to eq('done')
end
- it 'ignores invalid GIDs' do
- expect { mutation.resolve(id: 'invalid_gid') }.to raise_error(Gitlab::Graphql::Errors::ArgumentError)
+ it 'raises error for invalid GID' do
+ expect { mutation.resolve(id: author.to_global_id.to_s) }
+ .to raise_error(::GraphQL::CoercionError)
expect(todo1.reload.state).to eq('done')
expect(todo2.reload.state).to eq('pending')
@@ -61,8 +64,4 @@ RSpec.describe Mutations::Todos::Restore do
def restore_mutation(todo)
mutation.resolve(id: global_id_of(todo))
end
-
- def global_id_of(todo)
- todo.to_global_id.to_s
- end
end
diff --git a/spec/graphql/resolvers/admin/analytics/instance_statistics/measurements_resolver_spec.rb b/spec/graphql/resolvers/admin/analytics/instance_statistics/measurements_resolver_spec.rb
index 76854be2daa..c5637d43382 100644
--- a/spec/graphql/resolvers/admin/analytics/instance_statistics/measurements_resolver_spec.rb
+++ b/spec/graphql/resolvers/admin/analytics/instance_statistics/measurements_resolver_spec.rb
@@ -5,9 +5,11 @@ require 'spec_helper'
RSpec.describe Resolvers::Admin::Analytics::InstanceStatistics::MeasurementsResolver do
include GraphqlHelpers
+ let_it_be(:admin_user) { create(:user, :admin) }
+ let(:current_user) { admin_user }
+
describe '#resolve' do
let_it_be(:user) { create(:user) }
- let_it_be(:admin_user) { create(:user, :admin) }
let_it_be(:project_measurement_new) { create(:instance_statistics_measurement, :project_count, recorded_at: 2.days.ago) }
let_it_be(:project_measurement_old) { create(:instance_statistics_measurement, :project_count, recorded_at: 10.days.ago) }
@@ -39,6 +41,37 @@ RSpec.describe Resolvers::Admin::Analytics::InstanceStatistics::MeasurementsReso
end
end
end
+
+ context 'when requesting pipeline counts by pipeline status' do
+ let_it_be(:pipelines_succeeded_measurement) { create(:instance_statistics_measurement, :pipelines_succeeded_count, recorded_at: 2.days.ago) }
+ let_it_be(:pipelines_skipped_measurement) { create(:instance_statistics_measurement, :pipelines_skipped_count, recorded_at: 2.days.ago) }
+
+ subject { resolve_measurements({ identifier: identifier }, { current_user: current_user }) }
+
+ context 'filter for pipelines_succeeded' do
+ let(:identifier) { 'pipelines_succeeded' }
+
+ it { is_expected.to eq([pipelines_succeeded_measurement]) }
+ end
+
+ context 'filter for pipelines_skipped' do
+ let(:identifier) { 'pipelines_skipped' }
+
+ it { is_expected.to eq([pipelines_skipped_measurement]) }
+ end
+
+ context 'filter for pipelines_failed' do
+ let(:identifier) { 'pipelines_failed' }
+
+ it { is_expected.to be_empty }
+ end
+
+ context 'filter for pipelines_canceled' do
+ let(:identifier) { 'pipelines_canceled' }
+
+ it { is_expected.to be_empty }
+ end
+ end
end
def resolve_measurements(args = {}, context = {})
diff --git a/spec/graphql/resolvers/board_lists_resolver_spec.rb b/spec/graphql/resolvers/board_lists_resolver_spec.rb
index fb6a5ccb781..c1d8041a1e0 100644
--- a/spec/graphql/resolvers/board_lists_resolver_spec.rb
+++ b/spec/graphql/resolvers/board_lists_resolver_spec.rb
@@ -101,6 +101,12 @@ RSpec.describe Resolvers::BoardListsResolver do
end
def resolve_board_lists(args: {}, current_user: user)
- resolve(described_class, obj: board, args: args, ctx: { current_user: current_user })
+ context = GraphQL::Query::Context.new(
+ query: OpenStruct.new(schema: nil),
+ values: { current_user: current_user },
+ object: nil
+ )
+
+ resolve(described_class, obj: board, args: args, ctx: context )
end
end
diff --git a/spec/graphql/resolvers/board_resolver_spec.rb b/spec/graphql/resolvers/board_resolver_spec.rb
new file mode 100644
index 00000000000..c70c696005f
--- /dev/null
+++ b/spec/graphql/resolvers/board_resolver_spec.rb
@@ -0,0 +1,72 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Resolvers::BoardResolver do
+ include GraphqlHelpers
+
+ let_it_be(:user) { create(:user) }
+
+ let(:dummy_gid) { 'gid://gitlab/Board/1' }
+
+ shared_examples_for 'group and project boards resolver' do
+ it 'does not create a default board' do
+ expect(resolve_board(id: dummy_gid)).to eq nil
+ end
+
+ it 'calls Boards::ListService' do
+ expect_next_instance_of(Boards::ListService) do |service|
+ expect(service).to receive(:execute).and_return([])
+ end
+
+ resolve_board(id: dummy_gid)
+ end
+
+ it 'requires an ID' do
+ expect do
+ resolve(described_class, obj: board_parent, args: {}, ctx: { current_user: user })
+ end.to raise_error(Gitlab::Graphql::Errors::ArgumentError)
+ end
+
+ context 'when querying for a single board' do
+ let(:board1) { create(:board, name: 'One', resource_parent: board_parent) }
+
+ it 'returns specified board' do
+ expect(resolve_board(id: global_id_of(board1))).to eq board1
+ end
+
+ it 'returns nil if board not found' do
+ outside_parent = create(board_parent.class.underscore.to_sym) # rubocop:disable Rails/SaveBang
+ outside_board = create(:board, name: 'outside board', resource_parent: outside_parent)
+
+ expect(resolve_board(id: global_id_of(outside_board))).to eq nil
+ end
+ end
+ end
+
+ describe '#resolve' do
+ context 'when there is no parent' do
+ let(:board_parent) { nil }
+
+ it 'returns nil if parent is nil' do
+ expect(resolve_board(id: dummy_gid)).to eq(nil)
+ end
+ end
+
+ context 'when project boards' do
+ let(:board_parent) { create(:project, :public, creator_id: user.id, namespace: user.namespace ) }
+
+ it_behaves_like 'group and project boards resolver'
+ end
+
+ context 'when group boards' do
+ let(:board_parent) { create(:group) }
+
+ it_behaves_like 'group and project boards resolver'
+ end
+ end
+
+ def resolve_board(id:)
+ resolve(described_class, obj: board_parent, args: { id: id }, ctx: { current_user: user })
+ end
+end
diff --git a/spec/graphql/resolvers/ci/runner_platforms_resolver_spec.rb b/spec/graphql/resolvers/ci/runner_platforms_resolver_spec.rb
new file mode 100644
index 00000000000..1eb6f363d5b
--- /dev/null
+++ b/spec/graphql/resolvers/ci/runner_platforms_resolver_spec.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Resolvers::Ci::RunnerPlatformsResolver do
+ include GraphqlHelpers
+
+ describe '#resolve' do
+ subject(:resolve_subject) { resolve(described_class) }
+
+ it 'returns all possible runner platforms' do
+ expect(resolve_subject).to include(
+ hash_including(name: :linux), hash_including(name: :osx),
+ hash_including(name: :windows), hash_including(name: :docker),
+ hash_including(name: :kubernetes)
+ )
+ end
+ end
+end
diff --git a/spec/graphql/resolvers/concerns/looks_ahead_spec.rb b/spec/graphql/resolvers/concerns/looks_ahead_spec.rb
index f13823085b8..ebea9e5522b 100644
--- a/spec/graphql/resolvers/concerns/looks_ahead_spec.rb
+++ b/spec/graphql/resolvers/concerns/looks_ahead_spec.rb
@@ -117,20 +117,6 @@ RSpec.describe LooksAhead do
query.result
end
- context 'the feature flag is off' do
- before do
- stub_feature_flags(described_class::FEATURE_FLAG => false)
- end
-
- it_behaves_like 'a working query on the test schema'
-
- it 'does not preload labels on issues' do
- expect(the_user.issues).not_to receive(:preload).with(:labels)
-
- query.result
- end
- end
-
it 'issues fewer queries than the naive approach' do
the_user.reload # ensure no attributes are loaded before we begin
naive = <<-GQL
diff --git a/spec/graphql/resolvers/group_milestones_resolver_spec.rb b/spec/graphql/resolvers/group_milestones_resolver_spec.rb
index 05d0ec38192..d8ff8e9c1f2 100644
--- a/spec/graphql/resolvers/group_milestones_resolver_spec.rb
+++ b/spec/graphql/resolvers/group_milestones_resolver_spec.rb
@@ -15,6 +15,12 @@ RSpec.describe Resolvers::GroupMilestonesResolver do
let_it_be(:now) { Time.now }
let_it_be(:group) { create(:group, :private) }
+ def args(**arguments)
+ satisfy("contain only #{arguments.inspect}") do |passed|
+ expect(passed.compact).to match(arguments)
+ end
+ end
+
before_all do
group.add_developer(current_user)
end
@@ -30,7 +36,7 @@ RSpec.describe Resolvers::GroupMilestonesResolver do
context 'without parameters' do
it 'calls MilestonesFinder to retrieve all milestones' do
expect(MilestonesFinder).to receive(:new)
- .with(ids: nil, group_ids: group.id, state: 'all', start_date: nil, end_date: nil)
+ .with(args(group_ids: group.id, state: 'all'))
.and_call_original
resolve_group_milestones
@@ -43,11 +49,22 @@ RSpec.describe Resolvers::GroupMilestonesResolver do
end_date = start_date + 1.hour
expect(MilestonesFinder).to receive(:new)
- .with(ids: nil, group_ids: group.id, state: 'closed', start_date: start_date, end_date: end_date)
+ .with(args(group_ids: group.id, state: 'closed', start_date: start_date, end_date: end_date))
.and_call_original
resolve_group_milestones(start_date: start_date, end_date: end_date, state: 'closed')
end
+
+ it 'understands the timeframe argument' do
+ start_date = now
+ end_date = start_date + 1.hour
+
+ expect(MilestonesFinder).to receive(:new)
+ .with(args(group_ids: group.id, state: 'closed', start_date: start_date, end_date: end_date))
+ .and_call_original
+
+ resolve_group_milestones(timeframe: { start: start_date, end: end_date }, state: 'closed')
+ end
end
context 'by ids' do
@@ -55,7 +72,7 @@ RSpec.describe Resolvers::GroupMilestonesResolver do
milestone = create(:milestone, group: group)
expect(MilestonesFinder).to receive(:new)
- .with(ids: [milestone.id.to_s], group_ids: group.id, state: 'all', start_date: nil, end_date: nil)
+ .with(args(ids: [milestone.id.to_s], group_ids: group.id, state: 'all'))
.and_call_original
resolve_group_milestones(ids: [milestone.to_global_id])
diff --git a/spec/graphql/resolvers/issues_resolver_spec.rb b/spec/graphql/resolvers/issues_resolver_spec.rb
index db5d009f0e7..3a6507f906c 100644
--- a/spec/graphql/resolvers/issues_resolver_spec.rb
+++ b/spec/graphql/resolvers/issues_resolver_spec.rb
@@ -46,6 +46,13 @@ RSpec.describe Resolvers::IssuesResolver do
expect(resolve_issues(assignee_username: assignee.username)).to contain_exactly(issue2)
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
@@ -58,6 +65,10 @@ RSpec.describe Resolvers::IssuesResolver 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)
@@ -219,6 +230,21 @@ RSpec.describe Resolvers::IssuesResolver do
expect(resolve_issues(sort: :milestone_due_desc).items).to eq([milestone_issue3, milestone_issue2, milestone_issue1])
end
end
+
+ context 'when sorting by severity' do
+ let_it_be(:project) { create(:project) }
+ 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 eq([issue_no_severity, issue_low_severity, issue_high_severity])
+ end
+
+ it 'sorts issues descending' do
+ expect(resolve_issues(sort: :severity_desc)).to eq([issue_high_severity, issue_low_severity, issue_no_severity])
+ end
+ end
end
it 'returns issues user can see' do
@@ -304,6 +330,13 @@ RSpec.describe Resolvers::IssuesResolver do
expect(field.to_graphql.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)
end
diff --git a/spec/graphql/resolvers/project_milestones_resolver_spec.rb b/spec/graphql/resolvers/project_milestones_resolver_spec.rb
index e0b250cfe7c..b641a54393e 100644
--- a/spec/graphql/resolvers/project_milestones_resolver_spec.rb
+++ b/spec/graphql/resolvers/project_milestones_resolver_spec.rb
@@ -13,13 +13,19 @@ RSpec.describe Resolvers::ProjectMilestonesResolver do
project.add_developer(current_user)
end
+ def args(**arguments)
+ satisfy("contain only #{arguments.inspect}") do |passed|
+ expect(passed.compact).to match(arguments)
+ end
+ end
+
def resolve_project_milestones(args = {}, context = { current_user: current_user })
resolve(described_class, obj: project, args: args, ctx: context)
end
it 'calls MilestonesFinder to retrieve all milestones' do
expect(MilestonesFinder).to receive(:new)
- .with(ids: nil, project_ids: project.id, state: 'all', start_date: nil, end_date: nil)
+ .with(args(project_ids: project.id, state: 'all'))
.and_call_original
resolve_project_milestones
@@ -36,7 +42,7 @@ RSpec.describe Resolvers::ProjectMilestonesResolver do
it 'calls MilestonesFinder with correct parameters' do
expect(MilestonesFinder).to receive(:new)
- .with(ids: nil, project_ids: project.id, group_ids: contain_exactly(group, parent_group), state: 'all', start_date: nil, end_date: nil)
+ .with(args(project_ids: project.id, group_ids: contain_exactly(group, parent_group), state: 'all'))
.and_call_original
resolve_project_milestones(include_ancestors: true)
@@ -48,7 +54,7 @@ RSpec.describe Resolvers::ProjectMilestonesResolver do
milestone = create(:milestone, project: project)
expect(MilestonesFinder).to receive(:new)
- .with(ids: [milestone.id.to_s], project_ids: project.id, state: 'all', start_date: nil, end_date: nil)
+ .with(args(ids: [milestone.id.to_s], project_ids: project.id, state: 'all'))
.and_call_original
resolve_project_milestones(ids: [milestone.to_global_id])
@@ -58,7 +64,7 @@ RSpec.describe Resolvers::ProjectMilestonesResolver do
context 'by state' do
it 'calls MilestonesFinder with correct parameters' do
expect(MilestonesFinder).to receive(:new)
- .with(ids: nil, project_ids: project.id, state: 'closed', start_date: nil, end_date: nil)
+ .with(args(project_ids: project.id, state: 'closed'))
.and_call_original
resolve_project_milestones(state: 'closed')
@@ -72,7 +78,7 @@ RSpec.describe Resolvers::ProjectMilestonesResolver do
end_date = Time.now + 5.days
expect(MilestonesFinder).to receive(:new)
- .with(ids: nil, project_ids: project.id, state: 'all', start_date: start_date, end_date: end_date)
+ .with(args(project_ids: project.id, state: 'all', start_date: start_date, end_date: end_date))
.and_call_original
resolve_project_milestones(start_date: start_date, end_date: end_date)
@@ -102,6 +108,51 @@ RSpec.describe Resolvers::ProjectMilestonesResolver do
end.to raise_error(Gitlab::Graphql::Errors::ArgumentError, /Both startDate and endDate/)
end
end
+
+ context 'when passing a timeframe' do
+ it 'calls MilestonesFinder with correct parameters' do
+ start_date = Time.now
+ end_date = Time.now + 5.days
+
+ expect(MilestonesFinder).to receive(:new)
+ .with(args(project_ids: project.id, state: 'all', start_date: start_date, end_date: end_date))
+ .and_call_original
+
+ resolve_project_milestones(timeframe: { start: start_date, end: end_date })
+ end
+ end
+ end
+
+ context 'when title is present' do
+ it 'calls MilestonesFinder with correct parameters' do
+ expect(MilestonesFinder).to receive(:new)
+ .with(args(title: '13.5', state: 'all', project_ids: project.id))
+ .and_call_original
+
+ resolve_project_milestones(title: '13.5')
+ end
+ end
+
+ context 'when search_title is present' do
+ it 'calls MilestonesFinder with correct parameters' do
+ expect(MilestonesFinder).to receive(:new)
+ .with(args(search_title: '13', state: 'all', project_ids: project.id))
+ .and_call_original
+
+ resolve_project_milestones(search_title: '13')
+ end
+ end
+
+ context 'when containing date is present' do
+ it 'calls MilestonesFinder with correct parameters' do
+ t = Time.now
+
+ expect(MilestonesFinder).to receive(:new)
+ .with(args(containing_date: t, state: 'all', project_ids: project.id))
+ .and_call_original
+
+ resolve_project_milestones(containing_date: t)
+ end
end
context 'when user cannot read milestones' do
diff --git a/spec/graphql/resolvers/projects_resolver_spec.rb b/spec/graphql/resolvers/projects_resolver_spec.rb
index d22ffeed740..83a26062957 100644
--- a/spec/graphql/resolvers/projects_resolver_spec.rb
+++ b/spec/graphql/resolvers/projects_resolver_spec.rb
@@ -8,10 +8,14 @@ RSpec.describe Resolvers::ProjectsResolver do
describe '#resolve' do
subject { resolve(described_class, obj: nil, args: filters, ctx: { current_user: current_user }) }
+ let_it_be(:group) { create(:group, name: 'public-group') }
+ let_it_be(:private_group) { create(:group, name: 'private-group') }
let_it_be(:project) { create(:project, :public) }
let_it_be(:other_project) { create(:project, :public) }
+ let_it_be(:group_project) { create(:project, :public, group: group) }
let_it_be(:private_project) { create(:project, :private) }
let_it_be(:other_private_project) { create(:project, :private) }
+ let_it_be(:private_group_project) { create(:project, :private, group: private_group) }
let_it_be(:user) { create(:user) }
@@ -20,6 +24,11 @@ RSpec.describe Resolvers::ProjectsResolver do
before_all do
project.add_developer(user)
private_project.add_developer(user)
+ private_group.add_developer(user)
+ end
+
+ before do
+ stub_feature_flags(project_finder_similarity_sort: false)
end
context 'when user is not logged in' do
@@ -27,7 +36,7 @@ RSpec.describe Resolvers::ProjectsResolver do
context 'when no filters are applied' do
it 'returns all public projects' do
- is_expected.to contain_exactly(project, other_project)
+ is_expected.to contain_exactly(project, other_project, group_project)
end
context 'when search filter is provided' do
@@ -45,6 +54,22 @@ RSpec.describe Resolvers::ProjectsResolver do
is_expected.to be_empty
end
end
+
+ context 'when searchNamespaces filter is provided' do
+ let(:filters) { { search: 'group', search_namespaces: true } }
+
+ it 'returns projects in a matching namespace' do
+ is_expected.to contain_exactly(group_project)
+ end
+ end
+
+ context 'when searchNamespaces filter false' do
+ let(:filters) { { search: 'group', search_namespaces: false } }
+
+ it 'returns ignores namespace matches' do
+ is_expected.to be_empty
+ end
+ end
end
end
@@ -53,7 +78,7 @@ RSpec.describe Resolvers::ProjectsResolver do
context 'when no filters are applied' do
it 'returns all visible projects for the user' do
- is_expected.to contain_exactly(project, other_project, private_project)
+ is_expected.to contain_exactly(project, other_project, group_project, private_project, private_group_project)
end
context 'when search filter is provided' do
@@ -68,7 +93,23 @@ RSpec.describe Resolvers::ProjectsResolver do
let(:filters) { { membership: true } }
it 'returns projects that user is member of' do
- is_expected.to contain_exactly(project, private_project)
+ is_expected.to contain_exactly(project, private_project, private_group_project)
+ end
+ end
+
+ context 'when searchNamespaces filter is provided' do
+ let(:filters) { { search: 'group', search_namespaces: true } }
+
+ it 'returns projects from matching group' do
+ is_expected.to contain_exactly(group_project, private_group_project)
+ end
+ end
+
+ context 'when searchNamespaces filter false' do
+ let(:filters) { { search: 'group', search_namespaces: false } }
+
+ it 'returns ignores namespace matches' do
+ is_expected.to be_empty
end
end
@@ -79,6 +120,24 @@ RSpec.describe Resolvers::ProjectsResolver do
is_expected.to contain_exactly(project)
end
end
+
+ context 'when sort is similarity' do
+ let_it_be(:named_project1) { create(:project, :public, name: 'projAB', path: 'projAB') }
+ let_it_be(:named_project2) { create(:project, :public, name: 'projABC', path: 'projABC') }
+ let_it_be(:named_project3) { create(:project, :public, name: 'projA', path: 'projA') }
+
+ let(:filters) { { search: 'projA', sort: 'similarity' } }
+
+ it 'returns projects in order of similarity to search' do
+ stub_feature_flags(project_finder_similarity_sort: true)
+
+ is_expected.to eq([named_project3, named_project1, named_project2])
+ end
+
+ it 'returns projects not in order of similarity to search if flag is off' do
+ is_expected.not_to eq([named_project3, named_project1, named_project2])
+ end
+ end
end
end
end
diff --git a/spec/graphql/resolvers/snippets/blobs_resolver_spec.rb b/spec/graphql/resolvers/snippets/blobs_resolver_spec.rb
new file mode 100644
index 00000000000..fdbd87c32be
--- /dev/null
+++ b/spec/graphql/resolvers/snippets/blobs_resolver_spec.rb
@@ -0,0 +1,50 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Resolvers::Snippets::BlobsResolver do
+ include GraphqlHelpers
+
+ describe '#resolve' do
+ let_it_be(:current_user) { create(:user) }
+ let_it_be(:snippet) { create(:personal_snippet, :private, :repository, author: current_user) }
+
+ context 'when user is not authorized' do
+ let(:other_user) { create(:user) }
+
+ it 'raises an error' do
+ expect do
+ resolve_blobs(snippet, user: other_user)
+ end.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
+ end
+ end
+
+ context 'when using no filter' do
+ it 'returns all snippet blobs' do
+ expect(resolve_blobs(snippet).map(&:path)).to contain_exactly(*snippet.list_files)
+ end
+ end
+
+ context 'when using filters' do
+ context 'when paths is a single string' do
+ it 'returns an array of files' do
+ path = 'CHANGELOG'
+
+ expect(resolve_blobs(snippet, args: { paths: path }).first.path).to eq(path)
+ end
+ end
+
+ context 'when paths is an array of string' do
+ it 'returns an array of files' do
+ paths = ['CHANGELOG', 'README.md']
+
+ expect(resolve_blobs(snippet, args: { paths: paths }).map(&:path)).to contain_exactly(*paths)
+ end
+ end
+ end
+ end
+
+ def resolve_blobs(snippet, user: current_user, args: {})
+ resolve(described_class, args: args, ctx: { current_user: user }, obj: snippet)
+ end
+end
diff --git a/spec/graphql/resolvers/terraform/states_resolver_spec.rb b/spec/graphql/resolvers/terraform/states_resolver_spec.rb
new file mode 100644
index 00000000000..64b515528cd
--- /dev/null
+++ b/spec/graphql/resolvers/terraform/states_resolver_spec.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Resolvers::Terraform::StatesResolver do
+ include GraphqlHelpers
+
+ it { expect(described_class.type).to eq(Types::Terraform::StateType) }
+ it { expect(described_class.null).to be_truthy }
+
+ describe '#resolve' do
+ let_it_be(:project) { create(:project) }
+
+ let_it_be(:production_state) { create(:terraform_state, project: project) }
+ let_it_be(:staging_state) { create(:terraform_state, project: project) }
+ let_it_be(:other_state) { create(:terraform_state) }
+
+ let(:ctx) { Hash(current_user: user) }
+ let(:user) { create(:user, developer_projects: [project]) }
+
+ subject { resolve(described_class, obj: project, ctx: ctx) }
+
+ it 'returns states associated with the agent' do
+ expect(subject).to contain_exactly(production_state, staging_state)
+ end
+
+ context 'user does not have permission' do
+ let(:user) { create(:user) }
+
+ it { is_expected.to be_empty }
+ end
+ end
+end
diff --git a/spec/graphql/types/alert_management/alert_type_spec.rb b/spec/graphql/types/alert_management/alert_type_spec.rb
index e14c189d4b6..82b48a20708 100644
--- a/spec/graphql/types/alert_management/alert_type_spec.rb
+++ b/spec/graphql/types/alert_management/alert_type_spec.rb
@@ -32,6 +32,7 @@ RSpec.describe GitlabSchema.types['AlertManagementAlert'] do
todos
details_url
prometheus_alert
+ environment
]
expect(described_class).to have_graphql_fields(*expected_fields)
diff --git a/spec/graphql/types/alert_management/status_enum_spec.rb b/spec/graphql/types/alert_management/status_enum_spec.rb
index ac7a8eb53f6..1252efabe4c 100644
--- a/spec/graphql/types/alert_management/status_enum_spec.rb
+++ b/spec/graphql/types/alert_management/status_enum_spec.rb
@@ -9,10 +9,10 @@ RSpec.describe GitlabSchema.types['AlertManagementStatus'] do
using RSpec::Parameterized::TableSyntax
where(:status_name, :status_value) do
- 'TRIGGERED' | 0
- 'ACKNOWLEDGED' | 1
- 'RESOLVED' | 2
- 'IGNORED' | 3
+ 'TRIGGERED' | :triggered
+ 'ACKNOWLEDGED' | :acknowledged
+ 'RESOLVED' | :resolved
+ 'IGNORED' | :ignored
end
with_them do
diff --git a/spec/graphql/types/base_field_spec.rb b/spec/graphql/types/base_field_spec.rb
index bcfbd7f2480..d61ea6aa6e9 100644
--- a/spec/graphql/types/base_field_spec.rb
+++ b/spec/graphql/types/base_field_spec.rb
@@ -126,6 +126,10 @@ RSpec.describe Types::BaseField do
let(:field) { described_class.new(name: 'test', type: GraphQL::STRING_TYPE, feature_flag: flag, null: false) }
let(:context) { {} }
+ before do
+ skip_feature_flags_yaml_validation
+ end
+
it 'returns false if the feature is not enabled' do
stub_feature_flags(flag => false)
diff --git a/spec/graphql/types/ci/detailed_status_type_spec.rb b/spec/graphql/types/ci/detailed_status_type_spec.rb
index 67199848df0..ddb3a1450df 100644
--- a/spec/graphql/types/ci/detailed_status_type_spec.rb
+++ b/spec/graphql/types/ci/detailed_status_type_spec.rb
@@ -8,6 +8,6 @@ RSpec.describe Types::Ci::DetailedStatusType do
it "has all fields" do
expect(described_class).to have_graphql_fields(:group, :icon, :favicon,
:details_path, :has_details,
- :label, :text, :tooltip)
+ :label, :text, :tooltip, :action)
end
end
diff --git a/spec/graphql/types/ci/group_type_spec.rb b/spec/graphql/types/ci/group_type_spec.rb
index 8d547b19af3..d7ce5602612 100644
--- a/spec/graphql/types/ci/group_type_spec.rb
+++ b/spec/graphql/types/ci/group_type_spec.rb
@@ -10,6 +10,7 @@ RSpec.describe Types::Ci::GroupType do
name
size
jobs
+ detailedStatus
]
expect(described_class).to have_graphql_fields(*expected_fields)
diff --git a/spec/graphql/types/ci/job_type_spec.rb b/spec/graphql/types/ci/job_type_spec.rb
index faf3a95cf25..3a54ed2efed 100644
--- a/spec/graphql/types/ci/job_type_spec.rb
+++ b/spec/graphql/types/ci/job_type_spec.rb
@@ -9,6 +9,8 @@ RSpec.describe Types::Ci::JobType do
expected_fields = %i[
name
needs
+ detailedStatus
+ scheduledAt
]
expect(described_class).to have_graphql_fields(*expected_fields)
diff --git a/spec/graphql/types/ci/runner_architecture_type_spec.rb b/spec/graphql/types/ci/runner_architecture_type_spec.rb
new file mode 100644
index 00000000000..527adef8cf9
--- /dev/null
+++ b/spec/graphql/types/ci/runner_architecture_type_spec.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Types::Ci::RunnerArchitectureType do
+ specify { expect(described_class.graphql_name).to eq('RunnerArchitecture') }
+
+ it 'exposes the expected fields' do
+ expected_fields = %i[
+ name
+ download_location
+ ]
+
+ expect(described_class).to have_graphql_fields(*expected_fields)
+ end
+end
diff --git a/spec/graphql/types/ci/runner_platform_type_spec.rb b/spec/graphql/types/ci/runner_platform_type_spec.rb
new file mode 100644
index 00000000000..66b83f607d0
--- /dev/null
+++ b/spec/graphql/types/ci/runner_platform_type_spec.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Types::Ci::RunnerPlatformType do
+ specify { expect(described_class.graphql_name).to eq('RunnerPlatform') }
+
+ it 'exposes the expected fields' do
+ expected_fields = %i[
+ name
+ human_readable_name
+ architectures
+ ]
+
+ expect(described_class).to have_graphql_fields(*expected_fields)
+ end
+end
diff --git a/spec/graphql/types/ci/stage_type_spec.rb b/spec/graphql/types/ci/stage_type_spec.rb
index 0c352ed27aa..9a8d4fa96a3 100644
--- a/spec/graphql/types/ci/stage_type_spec.rb
+++ b/spec/graphql/types/ci/stage_type_spec.rb
@@ -9,6 +9,7 @@ RSpec.describe Types::Ci::StageType do
expected_fields = %i[
name
groups
+ detailedStatus
]
expect(described_class).to have_graphql_fields(*expected_fields)
diff --git a/spec/graphql/types/ci/status_action_type_spec.rb b/spec/graphql/types/ci/status_action_type_spec.rb
new file mode 100644
index 00000000000..8a99068e44f
--- /dev/null
+++ b/spec/graphql/types/ci/status_action_type_spec.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Types::Ci::StatusActionType do
+ specify { expect(described_class.graphql_name).to eq('StatusAction') }
+
+ it 'exposes the expected fields' do
+ expected_fields = %i[
+ buttonTitle
+ icon
+ path
+ method
+ title
+ ]
+
+ expect(described_class).to have_graphql_fields(*expected_fields)
+ end
+end
diff --git a/spec/graphql/types/design_management/design_collection_copy_state_enum_spec.rb b/spec/graphql/types/design_management/design_collection_copy_state_enum_spec.rb
new file mode 100644
index 00000000000..f536d91aeda
--- /dev/null
+++ b/spec/graphql/types/design_management/design_collection_copy_state_enum_spec.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe GitlabSchema.types['DesignCollectionCopyState'] do
+ it { expect(described_class.graphql_name).to eq('DesignCollectionCopyState') }
+
+ it 'exposes the correct event states' do
+ expect(described_class.values.keys).to match_array(%w(READY IN_PROGRESS ERROR))
+ end
+end
diff --git a/spec/graphql/types/design_management/design_collection_type_spec.rb b/spec/graphql/types/design_management/design_collection_type_spec.rb
index 6b1d3a87c2d..83208705249 100644
--- a/spec/graphql/types/design_management/design_collection_type_spec.rb
+++ b/spec/graphql/types/design_management/design_collection_type_spec.rb
@@ -6,7 +6,7 @@ RSpec.describe GitlabSchema.types['DesignCollection'] do
it { expect(described_class).to require_graphql_authorizations(:read_design) }
it 'has the expected fields' do
- expected_fields = %i[project issue designs versions version designAtVersion design]
+ expected_fields = %i[project issue designs versions version designAtVersion design copyState]
expect(described_class).to have_graphql_fields(*expected_fields)
end
diff --git a/spec/graphql/types/environment_type_spec.rb b/spec/graphql/types/environment_type_spec.rb
index abeeeba543f..2220f847e4e 100644
--- a/spec/graphql/types/environment_type_spec.rb
+++ b/spec/graphql/types/environment_type_spec.rb
@@ -7,7 +7,7 @@ RSpec.describe GitlabSchema.types['Environment'] do
it 'has the expected fields' do
expected_fields = %w[
- name id state metrics_dashboard latest_opened_most_severe_alert
+ name id state metrics_dashboard latest_opened_most_severe_alert path
]
expect(described_class).to have_graphql_fields(*expected_fields)
@@ -28,6 +28,7 @@ RSpec.describe GitlabSchema.types['Environment'] do
project(fullPath: "#{project.full_path}") {
environment(name: "#{environment.name}") {
name
+ path
state
}
}
@@ -43,6 +44,18 @@ RSpec.describe GitlabSchema.types['Environment'] do
expect(subject['data']['project']['environment']['name']).to eq(environment.name)
end
+ it 'returns the path when the feature is enabled' do
+ expect(subject['data']['project']['environment']['path']).to eq(
+ Gitlab::Routing.url_helpers.project_environment_path(project, environment)
+ )
+ end
+
+ it 'does not return the path when the feature is disabled' do
+ stub_feature_flags(expose_environment_path_in_alert_details: false)
+
+ expect(subject['data']['project']['environment']['path']).to be_nil
+ end
+
context 'when query alert data for the environment' do
let_it_be(:query) do
%(
diff --git a/spec/graphql/types/global_id_type_spec.rb b/spec/graphql/types/global_id_type_spec.rb
index 2a7b26f66b0..7589b0e285e 100644
--- a/spec/graphql/types/global_id_type_spec.rb
+++ b/spec/graphql/types/global_id_type_spec.rb
@@ -99,8 +99,6 @@ RSpec.describe Types::GlobalIDType do
end
describe 'compatibility' do
- # Simplified schema to test compatibility
-
def query(doc, vars)
GraphQL::Query.new(schema, document: doc, context: {}, variables: vars)
end
@@ -112,6 +110,7 @@ RSpec.describe Types::GlobalIDType do
all_types = [::GraphQL::ID_TYPE, ::Types::GlobalIDType, ::Types::GlobalIDType[::Project]]
shared_examples 'a working query' do
+ # Simplified schema to test compatibility
let!(:schema) do
# capture values so they can be closed over
arg_type = argument_type
@@ -135,10 +134,21 @@ RSpec.describe Types::GlobalIDType do
argument :id, arg_type, required: true
end
+ # This is needed so that all types are always registered as input types
+ field :echo, String, null: true do
+ argument :id, ::GraphQL::ID_TYPE, required: false
+ argument :gid, ::Types::GlobalIDType, required: false
+ argument :pid, ::Types::GlobalIDType[::Project], required: false
+ end
+
def project_by_id(id:)
gid = ::Types::GlobalIDType[::Project].coerce_isolated_input(id)
gid.model_class.find(gid.model_id)
end
+
+ def echo(id: nil, gid: nil, pid: nil)
+ "id: #{id}, gid: #{gid}, pid: #{pid}"
+ end
end)
end
end
@@ -152,7 +162,7 @@ RSpec.describe Types::GlobalIDType do
end
end
- context 'when the argument is declared as ID' do
+ context 'when the client declares the argument as ID the actual argument can be any type' do
let(:document) do
<<-GRAPHQL
query($projectId: ID!){
@@ -163,16 +173,16 @@ RSpec.describe Types::GlobalIDType do
GRAPHQL
end
- let(:argument_type) { ::GraphQL::ID_TYPE }
-
- where(:result_type) { all_types }
+ where(:result_type, :argument_type) do
+ all_types.flat_map { |arg_type| all_types.zip([arg_type].cycle) }
+ end
with_them do
it_behaves_like 'a working query'
end
end
- context 'when the argument is declared as GlobalID' do
+ context 'when the client passes the argument as GlobalID' do
let(:document) do
<<-GRAPHQL
query($projectId: GlobalID!) {
@@ -192,7 +202,7 @@ RSpec.describe Types::GlobalIDType do
end
end
- context 'when the argument is declared as ProjectID' do
+ context 'when the client passes the argument as ProjectID' do
let(:document) do
<<-GRAPHQL
query($projectId: ProjectID!) {
diff --git a/spec/graphql/types/group_type_spec.rb b/spec/graphql/types/group_type_spec.rb
index bf7ddebaf5b..7d14ef87551 100644
--- a/spec/graphql/types/group_type_spec.rb
+++ b/spec/graphql/types/group_type_spec.rb
@@ -17,6 +17,7 @@ RSpec.describe GitlabSchema.types['Group'] do
subgroup_creation_level require_two_factor_authentication
two_factor_grace_period auto_devops_enabled emails_disabled
mentions_disabled parent boards milestones group_members
+ merge_requests
]
expect(described_class).to include_graphql_fields(*expected_fields)
diff --git a/spec/graphql/types/issue_sort_enum_spec.rb b/spec/graphql/types/issue_sort_enum_spec.rb
index 9313d3aee84..4433709d193 100644
--- a/spec/graphql/types/issue_sort_enum_spec.rb
+++ b/spec/graphql/types/issue_sort_enum_spec.rb
@@ -9,7 +9,7 @@ RSpec.describe GitlabSchema.types['IssueSort'] do
it 'exposes all the existing issue sort values' do
expect(described_class.values.keys).to include(
- *%w[DUE_DATE_ASC DUE_DATE_DESC RELATIVE_POSITION_ASC]
+ *%w[DUE_DATE_ASC DUE_DATE_DESC RELATIVE_POSITION_ASC SEVERITY_ASC SEVERITY_DESC]
)
end
end
diff --git a/spec/graphql/types/merge_request_type_spec.rb b/spec/graphql/types/merge_request_type_spec.rb
index 46aebbdabeb..9d901655b7b 100644
--- a/spec/graphql/types/merge_request_type_spec.rb
+++ b/spec/graphql/types/merge_request_type_spec.rb
@@ -27,16 +27,51 @@ RSpec.describe GitlabSchema.types['MergeRequest'] do
upvotes downvotes head_pipeline pipelines task_completion_status
milestone assignees participants subscribed labels discussion_locked time_estimate
total_time_spent reference author merged_at commit_count current_user_todos
- conflicts auto_merge_enabled
+ conflicts auto_merge_enabled approved_by
]
if Gitlab.ee?
expected_fields << 'approved'
expected_fields << 'approvals_left'
expected_fields << 'approvals_required'
- expected_fields << 'approved_by'
end
expect(described_class).to have_graphql_fields(*expected_fields)
end
+
+ describe '#diff_stats_summary' do
+ subject { GitlabSchema.execute(query, context: { current_user: current_user }).as_json }
+
+ let(:current_user) { create :admin }
+ let(:query) do
+ %(
+ {
+ project(fullPath: "#{project.full_path}") {
+ mergeRequests {
+ nodes {
+ diffStatsSummary {
+ additions, deletions
+ }
+ }
+ }
+ }
+ }
+ )
+ end
+
+ let(:project) { create(:project, :public) }
+ let(:merge_request) { create(:merge_request, target_project: project, source_project: project) }
+
+ let(:response) { subject.dig('data', 'project', 'mergeRequests', 'nodes').first['diffStatsSummary'] }
+
+ context 'when MR metrics has additions and deletions' do
+ before do
+ merge_request.metrics.update!(added_lines: 5, removed_lines: 8)
+ end
+
+ it 'pulls out data from metrics object' do
+ expect(response).to match('additions' => 5, 'deletions' => 8)
+ end
+ end
+ end
end
diff --git a/spec/graphql/types/package_type_enum_spec.rb b/spec/graphql/types/package_type_enum_spec.rb
index 80a20a68bc2..407d5786f65 100644
--- a/spec/graphql/types/package_type_enum_spec.rb
+++ b/spec/graphql/types/package_type_enum_spec.rb
@@ -4,6 +4,6 @@ require 'spec_helper'
RSpec.describe GitlabSchema.types['PackageTypeEnum'] do
it 'exposes all package types' do
- expect(described_class.values.keys).to contain_exactly(*%w[MAVEN NPM CONAN NUGET PYPI COMPOSER GENERIC])
+ expect(described_class.values.keys).to contain_exactly(*%w[MAVEN NPM CONAN NUGET PYPI COMPOSER GENERIC GOLANG DEBIAN])
end
end
diff --git a/spec/graphql/types/project_type_spec.rb b/spec/graphql/types/project_type_spec.rb
index 44a89bfa35e..8aa9e1138cc 100644
--- a/spec/graphql/types/project_type_spec.rb
+++ b/spec/graphql/types/project_type_spec.rb
@@ -27,7 +27,7 @@ RSpec.describe GitlabSchema.types['Project'] do
environment boards jira_import_status jira_imports services releases release
alert_management_alerts alert_management_alert alert_management_alert_status_counts
container_expiration_policy service_desk_enabled service_desk_address
- issue_status_counts
+ issue_status_counts terraform_states
]
expect(described_class).to include_graphql_fields(*expected_fields)
@@ -154,5 +154,12 @@ RSpec.describe GitlabSchema.types['Project'] do
it { is_expected.to have_graphql_type(Types::ContainerExpirationPolicyType) }
end
+ describe 'terraform states field' do
+ subject { described_class.fields['terraformStates'] }
+
+ it { is_expected.to have_graphql_type(Types::Terraform::StateType.connection_type) }
+ it { is_expected.to have_graphql_resolver(Resolvers::Terraform::StatesResolver) }
+ end
+
it_behaves_like 'a GraphQL type with labels'
end
diff --git a/spec/graphql/types/query_type_spec.rb b/spec/graphql/types/query_type_spec.rb
index 11f780a4f3f..1d9ca8323f8 100644
--- a/spec/graphql/types/query_type_spec.rb
+++ b/spec/graphql/types/query_type_spec.rb
@@ -22,6 +22,7 @@ RSpec.describe GitlabSchema.types['Query'] do
users
issue
instance_statistics_measurements
+ runner_platforms
]
expect(described_class).to have_graphql_fields(*expected_fields).at_least
@@ -67,8 +68,16 @@ RSpec.describe GitlabSchema.types['Query'] do
describe 'instance_statistics_measurements field' do
subject { described_class.fields['instanceStatisticsMeasurements'] }
- it 'returns issue' do
+ it 'returns instance statistics measurements' do
is_expected.to have_graphql_type(Types::Admin::Analytics::InstanceStatistics::MeasurementType.connection_type)
end
end
+
+ describe 'runner_platforms field' do
+ subject { described_class.fields['runnerPlatforms'] }
+
+ it 'returns runner platforms' do
+ is_expected.to have_graphql_type(Types::Ci::RunnerPlatformType.connection_type)
+ end
+ end
end
diff --git a/spec/graphql/types/range_input_type_spec.rb b/spec/graphql/types/range_input_type_spec.rb
new file mode 100644
index 00000000000..aa6fd72cf13
--- /dev/null
+++ b/spec/graphql/types/range_input_type_spec.rb
@@ -0,0 +1,43 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe ::Types::RangeInputType do
+ let(:of_integer) { ::GraphQL::INT_TYPE }
+
+ context 'parameterized on Integer' do
+ let(:type) { described_class[of_integer] }
+
+ it 'accepts start and end' do
+ input = { start: 1, end: 10 }
+ output = { start: 1, end: 10 }
+
+ expect(type.coerce_isolated_input(input)).to eq(output)
+ end
+
+ it 'rejects inverted ranges' do
+ input = { start: 10, end: 1 }
+
+ expect { type.coerce_isolated_input(input) }.to raise_error(Gitlab::Graphql::Errors::ArgumentError)
+ end
+ end
+
+ it 'follows expected subtyping relationships for instances' do
+ context = GraphQL::Query::Context.new(
+ query: OpenStruct.new(schema: nil),
+ values: {},
+ object: nil
+ )
+ instance = described_class[of_integer].new(context: context, defaults_used: [], ruby_kwargs: {})
+
+ expect(instance).to be_a_kind_of(described_class)
+ expect(instance).to be_a_kind_of(described_class[of_integer])
+ expect(instance).not_to be_a_kind_of(described_class[GraphQL::ID_TYPE])
+ end
+
+ it 'follows expected subtyping relationships for classes' do
+ expect(described_class[of_integer]).to be < described_class
+ expect(described_class[of_integer]).not_to be < described_class[GraphQL::ID_TYPE]
+ expect(described_class[of_integer]).not_to be < described_class[of_integer, false]
+ end
+end
diff --git a/spec/graphql/types/root_storage_statistics_type_spec.rb b/spec/graphql/types/root_storage_statistics_type_spec.rb
index f01c55cbccb..79d474f13ad 100644
--- a/spec/graphql/types/root_storage_statistics_type_spec.rb
+++ b/spec/graphql/types/root_storage_statistics_type_spec.rb
@@ -7,7 +7,8 @@ RSpec.describe GitlabSchema.types['RootStorageStatistics'] do
it 'has all the required fields' do
expect(described_class).to have_graphql_fields(:storage_size, :repository_size, :lfs_objects_size,
- :build_artifacts_size, :packages_size, :wiki_size, :snippets_size)
+ :build_artifacts_size, :packages_size, :wiki_size, :snippets_size,
+ :pipeline_artifacts_size)
end
specify { expect(described_class).to require_graphql_authorizations(:read_statistics) }
diff --git a/spec/graphql/types/snippet_type_spec.rb b/spec/graphql/types/snippet_type_spec.rb
index 86af69f1294..e73665a1b1d 100644
--- a/spec/graphql/types/snippet_type_spec.rb
+++ b/spec/graphql/types/snippet_type_spec.rb
@@ -16,6 +16,15 @@ RSpec.describe GitlabSchema.types['Snippet'] do
expect(described_class).to have_graphql_fields(*expected_fields)
end
+ describe 'blobs field' do
+ subject { described_class.fields['blobs'] }
+
+ it 'returns blobs' do
+ is_expected.to have_graphql_type(Types::Snippets::BlobType.connection_type)
+ is_expected.to have_graphql_resolver(Resolvers::Snippets::BlobsResolver)
+ end
+ end
+
context 'when restricted visibility level is set to public' do
let_it_be(:snippet) { create(:personal_snippet, :repository, :public, author: user) }
@@ -115,7 +124,7 @@ RSpec.describe GitlabSchema.types['Snippet'] do
end
describe '#blob' do
- let(:query_blob) { subject.dig('data', 'snippets', 'edges')[0]['node']['blob'] }
+ let(:query_blob) { subject.dig('data', 'snippets', 'nodes')[0]['blob'] }
subject { GitlabSchema.execute(snippet_query_for(field: 'blob'), context: { current_user: user }).as_json }
@@ -142,9 +151,26 @@ RSpec.describe GitlabSchema.types['Snippet'] do
describe '#blobs' do
let_it_be(:snippet) { create(:personal_snippet, :public, author: user) }
- let(:query_blobs) { subject.dig('data', 'snippets', 'edges')[0]['node']['blobs'] }
+ let(:query_blobs) { subject.dig('data', 'snippets', 'nodes')[0].dig('blobs', 'nodes') }
+ let(:paths) { [] }
+ let(:query) do
+ %(
+ {
+ snippets {
+ nodes {
+ blobs(paths: #{paths}) {
+ nodes {
+ name
+ path
+ }
+ }
+ }
+ }
+ }
+ )
+ end
- subject { GitlabSchema.execute(snippet_query_for(field: 'blobs'), context: { current_user: user }).as_json }
+ subject { GitlabSchema.execute(query, context: { current_user: user }).as_json }
shared_examples 'an array' do
it 'returns an array of snippet blobs' do
@@ -174,6 +200,18 @@ RSpec.describe GitlabSchema.types['Snippet'] do
expect(resulting_blobs_names).to match_array(blobs.map(&:name))
end
+
+ context 'when specific path is set' do
+ let(:paths) { ['CHANGELOG'] }
+
+ it_behaves_like 'an array'
+
+ it 'returns specific files' do
+ resulting_blobs_names = query_blobs.map { |b| b['name'] }
+
+ expect(resulting_blobs_names).to match(paths)
+ end
+ end
end
end
@@ -181,12 +219,10 @@ RSpec.describe GitlabSchema.types['Snippet'] do
%(
{
snippets {
- edges {
- node {
- #{field} {
- name
- path
- }
+ nodes {
+ #{field} {
+ name
+ path
}
}
}
diff --git a/spec/graphql/types/terraform/state_type_spec.rb b/spec/graphql/types/terraform/state_type_spec.rb
new file mode 100644
index 00000000000..51508208046
--- /dev/null
+++ b/spec/graphql/types/terraform/state_type_spec.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe GitlabSchema.types['TerraformState'] do
+ it { expect(described_class.graphql_name).to eq('TerraformState') }
+ it { expect(described_class).to require_graphql_authorizations(:read_terraform_state) }
+
+ describe 'fields' do
+ let(:fields) { %i[id name locked_by_user locked_at created_at updated_at] }
+
+ it { expect(described_class).to have_graphql_fields(fields) }
+
+ it { expect(described_class.fields['id'].type).to be_non_null }
+ it { expect(described_class.fields['name'].type).to be_non_null }
+ it { expect(described_class.fields['lockedByUser'].type).not_to be_non_null }
+ it { expect(described_class.fields['lockedAt'].type).not_to be_non_null }
+ it { expect(described_class.fields['createdAt'].type).to be_non_null }
+ it { expect(described_class.fields['updatedAt'].type).to be_non_null }
+ end
+end
diff --git a/spec/graphql/types/timeframe_type_spec.rb b/spec/graphql/types/timeframe_type_spec.rb
new file mode 100644
index 00000000000..dfde3242897
--- /dev/null
+++ b/spec/graphql/types/timeframe_type_spec.rb
@@ -0,0 +1,38 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe GitlabSchema.types['Timeframe'] do
+ let(:input) { { start: "2018-06-04", end: "2020-10-06" } }
+ let(:output) { { start: Date.parse(input[:start]), end: Date.parse(input[:end]) } }
+
+ it 'coerces ISO-dates into Time objects' do
+ expect(described_class.coerce_isolated_input(input)).to eq(output)
+ end
+
+ it 'rejects invalid input' do
+ input[:start] = 'foo'
+
+ expect { described_class.coerce_isolated_input(input) }
+ .to raise_error(GraphQL::CoercionError)
+ end
+
+ it 'accepts times as input' do
+ with_time = input.merge(start: '2018-06-04T13:48:14Z')
+
+ expect(described_class.coerce_isolated_input(with_time)).to eq(output)
+ end
+
+ it 'requires both ends of the range' do
+ types = described_class.arguments.slice('start', 'end').values.map(&:type)
+
+ expect(types).to all(be_non_null)
+ end
+
+ it 'rejects invalid range' do
+ input.merge!(start: input[:end], end: input[:start])
+
+ expect { described_class.coerce_isolated_input(input) }
+ .to raise_error(::Gitlab::Graphql::Errors::ArgumentError, 'start must be before end')
+ end
+end
diff --git a/spec/haml_lint/linter/documentation_links_spec.rb b/spec/haml_lint/linter/documentation_links_spec.rb
index 68de8317b82..5de455b6e8c 100644
--- a/spec/haml_lint/linter/documentation_links_spec.rb
+++ b/spec/haml_lint/linter/documentation_links_spec.rb
@@ -8,75 +8,85 @@ require Rails.root.join('haml_lint/linter/documentation_links')
RSpec.describe HamlLint::Linter::DocumentationLinks do
include_context 'linter'
- context 'when link_to points to the existing file path' do
- let(:haml) { "= link_to 'Description', help_page_path('README.md')" }
+ shared_examples 'link validation rules' do |link_pattern|
+ context 'when link_to points to the existing file path' do
+ let(:haml) { "= link_to 'Description', #{link_pattern}('README.md')" }
- it { is_expected.not_to report_lint }
- end
+ it { is_expected.not_to report_lint }
+ end
- context 'when link_to points to the existing file with valid anchor' do
- let(:haml) { "= link_to 'Description', help_page_path('README.md', anchor: 'overview'), target: '_blank'" }
+ context 'when link_to points to the existing file with valid anchor' do
+ let(:haml) { "= link_to 'Description', #{link_pattern}('README.md', anchor: 'overview'), target: '_blank'" }
- it { is_expected.not_to report_lint }
- end
+ it { is_expected.not_to report_lint }
+ end
- context 'when link_to points to the existing file path without .md extension' do
- let(:haml) { "= link_to 'Description', help_page_path('README')" }
+ context 'when link_to points to the existing file path without .md extension' do
+ let(:haml) { "= link_to 'Description', #{link_pattern}('README')" }
- it { is_expected.not_to report_lint }
- end
+ it { is_expected.not_to report_lint }
+ end
- context 'when anchor is not correct' do
- let(:haml) { "= link_to 'Description', help_page_path('README.md', anchor: 'wrong')" }
+ context 'when anchor is not correct' do
+ let(:haml) { "= link_to 'Description', #{link_pattern}('README.md', anchor: 'wrong')" }
- it { is_expected.to report_lint }
+ it { is_expected.to report_lint }
- context 'when help_page_path has multiple options' do
- let(:haml) { "= link_to 'Description', help_page_path('README.md', key: :value, anchor: 'wrong')" }
+ context "when #{link_pattern} has multiple options" do
+ let(:haml) { "= link_to 'Description', #{link_pattern}('README.md', key: :value, anchor: 'wrong')" }
+
+ it { is_expected.to report_lint }
+ end
+ end
+
+ context 'when file path is wrong' do
+ let(:haml) { "= link_to 'Description', #{link_pattern}('wrong.md'), target: '_blank'" }
it { is_expected.to report_lint }
end
- end
- context 'when file path is wrong' do
- let(:haml) { "= link_to 'Description', help_page_path('wrong.md'), target: '_blank'" }
+ context 'when link with wrong file path is assigned to a variable' do
+ let(:haml) { "- my_link = link_to 'Description', #{link_pattern}('wrong.md')" }
- it { is_expected.to report_lint }
- end
+ it { is_expected.to report_lint }
+ end
- context 'when link with wrong file path is assigned to a variable' do
- let(:haml) { "- my_link = link_to 'Description', help_page_path('wrong.md')" }
+ context 'when it is a broken code' do
+ let(:haml) { "= I am broken! ]]]]" }
- it { is_expected.to report_lint }
- end
+ it { is_expected.not_to report_lint }
+ end
- context 'when it is a broken code' do
- let(:haml) { "= I am broken! ]]]]" }
+ context 'when anchor belongs to a different element' do
+ let(:haml) { "= link_to 'Description', #{link_pattern}('README.md'), target: (anchor: 'blank')" }
- it { is_expected.not_to report_lint }
- end
+ it { is_expected.not_to report_lint }
+ end
- context 'when anchor belongs to a different element' do
- let(:haml) { "= link_to 'Description', help_page_path('README.md'), target: (anchor: 'blank')" }
+ context "when a simple #{link_pattern}" do
+ let(:haml) { "- url = #{link_pattern}('wrong.md')" }
- it { is_expected.not_to report_lint }
- end
+ it { is_expected.to report_lint }
+ end
- context 'when a simple help_page_path' do
- let(:haml) { "- url = help_page_path('wrong.md')" }
+ context 'when link is not a string' do
+ let(:haml) { "- url = #{link_pattern}(help_url)" }
- it { is_expected.to report_lint }
- end
+ it { is_expected.not_to report_lint }
+ end
- context 'when link is not a string' do
- let(:haml) { "- url = help_page_path(help_url)" }
+ context 'when link is a part of the tag' do
+ let(:haml) { ".data-form{ data: { url: #{link_pattern}('wrong.md') } }" }
- it { is_expected.not_to report_lint }
+ it { is_expected.to report_lint }
+ end
end
- context 'when link is a part of the tag' do
- let(:haml) { ".data-form{ data: { url: help_page_path('wrong.md') } }" }
+ context 'help_page_path' do
+ it_behaves_like 'link validation rules', 'help_page_path'
+ end
- it { is_expected.to report_lint }
+ context 'help_page_url' do
+ it_behaves_like 'link validation rules', 'help_page_url'
end
end
diff --git a/spec/helpers/analytics/unique_visits_helper_spec.rb b/spec/helpers/analytics/unique_visits_helper_spec.rb
index ff9769078c4..ff363e81ac7 100644
--- a/spec/helpers/analytics/unique_visits_helper_spec.rb
+++ b/spec/helpers/analytics/unique_visits_helper_spec.rb
@@ -22,15 +22,6 @@ RSpec.describe Analytics::UniqueVisitsHelper do
helper.track_visit(target_id)
end
- it 'does not track visits if usage ping is disabled' do
- sign_in(current_user)
- expect(Gitlab::CurrentSettings).to receive(:usage_ping_enabled?).and_return(false)
-
- expect_any_instance_of(Gitlab::Analytics::UniqueVisits).not_to receive(:track_visit)
-
- helper.track_visit(target_id)
- end
-
it 'does not track visit if user is not logged in' do
expect_any_instance_of(Gitlab::Analytics::UniqueVisits).not_to receive(:track_visit)
diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb
index ce4e73bdc55..a557e9e04da 100644
--- a/spec/helpers/application_helper_spec.rb
+++ b/spec/helpers/application_helper_spec.rb
@@ -222,6 +222,32 @@ RSpec.describe ApplicationHelper do
end
end
+ describe '#instance_review_permitted?' do
+ let_it_be(:non_admin_user) { create :user }
+ let_it_be(:admin_user) { create :user, :admin }
+
+ before do
+ allow(::Gitlab::CurrentSettings).to receive(:instance_review_permitted?).and_return(app_setting)
+ allow(helper).to receive(:current_user).and_return(current_user)
+ end
+
+ subject { helper.instance_review_permitted? }
+
+ where(app_setting: [true, false], is_admin: [true, false, nil])
+
+ with_them do
+ let(:current_user) do
+ if is_admin.nil?
+ nil
+ else
+ is_admin ? admin_user : non_admin_user
+ end
+ end
+
+ it { is_expected.to be(app_setting && is_admin) }
+ end
+ end
+
describe '#locale_path' do
it 'returns the locale path with an `_`' do
Gitlab::I18n.with_locale('pt-BR') do
diff --git a/spec/helpers/application_settings_helper_spec.rb b/spec/helpers/application_settings_helper_spec.rb
index c5fd88ada8f..7f25721801f 100644
--- a/spec/helpers/application_settings_helper_spec.rb
+++ b/spec/helpers/application_settings_helper_spec.rb
@@ -146,4 +146,24 @@ RSpec.describe ApplicationSettingsHelper do
])
end
end
+
+ describe '.show_documentation_base_url_field?' do
+ subject { helper.show_documentation_base_url_field? }
+
+ before do
+ stub_feature_flags(help_page_documentation_redirect: feature_flag)
+ end
+
+ context 'when feature flag is enabled' do
+ let(:feature_flag) { true }
+
+ it { is_expected.to eq(true) }
+ end
+
+ context 'when feature flag is disabled' do
+ let(:feature_flag) { false }
+
+ it { is_expected.to eq(false) }
+ end
+ end
end
diff --git a/spec/helpers/blob_helper_spec.rb b/spec/helpers/blob_helper_spec.rb
index 06f86e7716a..baa97781efa 100644
--- a/spec/helpers/blob_helper_spec.rb
+++ b/spec/helpers/blob_helper_spec.rb
@@ -5,16 +5,6 @@ require 'spec_helper'
RSpec.describe BlobHelper do
include TreeHelper
- describe '#highlight' do
- it 'wraps highlighted content' do
- expect(helper.highlight('test.rb', '52')).to eq(%q[<pre class="code highlight"><code><span id="LC1" class="line" lang="ruby"><span class="mi">52</span></span></code></pre>])
- end
-
- it 'handles plain version' do
- expect(helper.highlight('test.rb', '52', plain: true)).to eq(%q[<pre class="code highlight"><code><span id="LC1" class="line" lang="">52</span></code></pre>])
- end
- end
-
describe "#sanitize_svg_data" do
let(:input_svg_path) { File.join(Rails.root, 'spec', 'fixtures', 'unsanitized.svg') }
let(:data) { File.read(input_svg_path) }
@@ -455,13 +445,14 @@ RSpec.describe BlobHelper do
end
describe '#ide_fork_and_edit_path' do
- let(:project) { create(:project) }
- let(:current_user) { create(:user) }
- let(:can_push_code) { true }
+ let_it_be(:project) { create(:project) }
+ let_it_be(:user) { create(:user) }
+
+ let(:current_user) { user }
before do
allow(helper).to receive(:current_user).and_return(current_user)
- allow(helper).to receive(:can?).and_return(can_push_code)
+ allow(helper).to receive(:can?).and_return(true)
end
it 'returns path to fork the repo with a redirect param to the full IDE path' do
@@ -482,6 +473,35 @@ RSpec.describe BlobHelper do
end
end
+ describe '#fork_and_edit_path' do
+ let_it_be(:project) { create(:project) }
+ let_it_be(:user) { create(:user) }
+
+ let(:current_user) { user }
+
+ before do
+ allow(helper).to receive(:current_user).and_return(current_user)
+ allow(helper).to receive(:can?).and_return(true)
+ end
+
+ it 'returns path to fork the repo with a redirect param to the full edit path' do
+ uri = URI(helper.fork_and_edit_path(project, "master", ""))
+ params = CGI.unescape(uri.query)
+
+ expect(uri.path).to eq("/#{project.namespace.path}/#{project.path}/-/forks")
+ expect(params).to include("continue[to]=/#{project.namespace.path}/#{project.path}/-/edit/master/")
+ expect(params).to include("namespace_key=#{current_user.namespace.id}")
+ end
+
+ context 'when user is not logged in' do
+ let(:current_user) { nil }
+
+ it 'returns nil' do
+ expect(helper.ide_fork_and_edit_path(project, "master", "")).to be_nil
+ end
+ end
+ end
+
describe '#editing_ci_config?' do
let(:project) { build(:project) }
diff --git a/spec/helpers/boards_helper_spec.rb b/spec/helpers/boards_helper_spec.rb
index a805b96a8cc..b85ebec5545 100644
--- a/spec/helpers/boards_helper_spec.rb
+++ b/spec/helpers/boards_helper_spec.rb
@@ -34,23 +34,58 @@ RSpec.describe BoardsHelper do
end
describe '#board_data' do
- let(:user) { create(:user) }
- let(:board) { create(:board, project: project) }
+ let_it_be(:user) { create(:user) }
+ let_it_be(:board) { create(:board, project: project) }
- before do
- assign(:board, board)
- assign(:project, project)
+ context 'project_board' do
+ before do
+ assign(:project, project)
+ assign(:board, board)
- allow(helper).to receive(:current_user) { user }
- allow(helper).to receive(:can?).with(user, :create_non_backlog_issues, board).and_return(true)
- end
+ allow(helper).to receive(:current_user) { user }
+ allow(helper).to receive(:can?).with(user, :create_non_backlog_issues, board).and_return(true)
+ allow(helper).to receive(:can?).with(user, :admin_issue, board).and_return(true)
+ end
+
+ it 'returns a board_lists_path as lists_endpoint' do
+ expect(helper.board_data[:lists_endpoint]).to eq(board_lists_path(board))
+ end
- it 'returns a board_lists_path as lists_endpoint' do
- expect(helper.board_data[:lists_endpoint]).to eq(board_lists_path(board))
+ it 'returns board type as parent' do
+ expect(helper.board_data[:parent]).to eq('project')
+ end
+
+ it 'returns can_update for user permissions on the board' do
+ expect(helper.board_data[:can_update]).to eq('true')
+ end
+
+ it 'returns required label endpoints' do
+ expect(helper.board_data[:labels_fetch_path]).to eq("/#{project.full_path}/-/labels.json?include_ancestor_groups=true")
+ expect(helper.board_data[:labels_manage_path]).to eq("/#{project.full_path}/-/labels")
+ end
end
- it 'returns board type as parent' do
- expect(helper.board_data[:parent]).to eq('project')
+ context 'group board' do
+ let_it_be(:group) { create(:group, path: 'base') }
+ let_it_be(:board) { create(:board, group: group) }
+
+ before do
+ assign(:group, group)
+ assign(:board, board)
+
+ allow(helper).to receive(:current_user) { user }
+ allow(helper).to receive(:can?).with(user, :create_non_backlog_issues, board).and_return(true)
+ allow(helper).to receive(:can?).with(user, :admin_issue, board).and_return(true)
+ end
+
+ it 'returns correct path for base group' do
+ expect(helper.build_issue_link_base).to eq('/base/:project_path/issues')
+ end
+
+ it 'returns required label endpoints' do
+ expect(helper.board_data[:labels_fetch_path]).to eq("/groups/base/-/labels.json?include_ancestor_groups=true&only_group_labels=true")
+ expect(helper.board_data[:labels_manage_path]).to eq("/groups/base/-/labels")
+ end
end
end
diff --git a/spec/helpers/ci/runners_helper_spec.rb b/spec/helpers/ci/runners_helper_spec.rb
index a006933a2a5..38caae91ef2 100644
--- a/spec/helpers/ci/runners_helper_spec.rb
+++ b/spec/helpers/ci/runners_helper_spec.rb
@@ -53,4 +53,25 @@ RSpec.describe Ci::RunnersHelper do
end
end
end
+
+ describe '#group_shared_runners_settings_data' do
+ let(:group) { create(:group, parent: parent, shared_runners_enabled: false) }
+ let(:parent) { create(:group) }
+
+ it 'returns group data for top level group' do
+ data = group_shared_runners_settings_data(parent)
+
+ expect(data[:update_path]).to eq("/api/v4/groups/#{parent.id}")
+ expect(data[:shared_runners_availability]).to eq('enabled')
+ expect(data[:parent_shared_runners_availability]).to eq(nil)
+ end
+
+ it 'returns group data for child group' do
+ data = group_shared_runners_settings_data(group)
+
+ expect(data[:update_path]).to eq("/api/v4/groups/#{group.id}")
+ expect(data[:shared_runners_availability]).to eq('disabled_and_unoverridable')
+ expect(data[:parent_shared_runners_availability]).to eq('enabled')
+ end
+ end
end
diff --git a/spec/helpers/clusters_helper_spec.rb b/spec/helpers/clusters_helper_spec.rb
index 6164f3b5e8d..6b08b6515cf 100644
--- a/spec/helpers/clusters_helper_spec.rb
+++ b/spec/helpers/clusters_helper_spec.rb
@@ -59,6 +59,24 @@ RSpec.describe ClustersHelper do
end
end
+ describe '#js_cluster_agents_list_data' do
+ let_it_be(:project) { build(:project, :repository) }
+
+ subject { helper.js_cluster_agents_list_data(project) }
+
+ it 'displays project default branch' do
+ expect(subject[:default_branch_name]).to eq(project.default_branch)
+ end
+
+ it 'displays image path' do
+ expect(subject[:empty_state_image]).to match(%r(/illustrations/logos/clusters_empty|svg))
+ end
+
+ it 'displays project path' do
+ expect(subject[:project_path]).to eq(project.full_path)
+ end
+ end
+
describe '#js_clusters_list_data' do
subject { helper.js_clusters_list_data('/path') }
@@ -89,32 +107,6 @@ RSpec.describe ClustersHelper do
end
end
- describe '#provider_icon' do
- it 'will return GCP logo with gcp argument' do
- logo = helper.provider_icon('gcp')
-
- expect(logo).to match(%r(img alt="Google GKE" data-src="|/illustrations/logos/google_gke|svg))
- end
-
- it 'will return AWS logo with aws argument' do
- logo = helper.provider_icon('aws')
-
- expect(logo).to match(%r(img alt="Amazon EKS" data-src="|/illustrations/logos/amazon_eks|svg))
- end
-
- it 'will return default logo with unknown provider' do
- logo = helper.provider_icon('unknown')
-
- expect(logo).to match(%r(img alt="Kubernetes Cluster" data-src="|/illustrations/logos/kubernetes|svg))
- end
-
- it 'will return default logo when provider is empty' do
- logo = helper.provider_icon
-
- expect(logo).to match(%r(img alt="Kubernetes Cluster" data-src="|/illustrations/logos/kubernetes|svg))
- end
- end
-
describe '#cluster_type_label' do
subject { helper.cluster_type_label(cluster_type) }
diff --git a/spec/helpers/container_expiration_policies_helper_spec.rb b/spec/helpers/container_expiration_policies_helper_spec.rb
index b2a03f8d90f..7ad3804e3a9 100644
--- a/spec/helpers/container_expiration_policies_helper_spec.rb
+++ b/spec/helpers/container_expiration_policies_helper_spec.rb
@@ -3,6 +3,8 @@
require 'spec_helper'
RSpec.describe ContainerExpirationPoliciesHelper do
+ using RSpec::Parameterized::TableSyntax
+
describe '#keep_n_options' do
it 'returns keep_n options formatted for dropdown usage' do
expected_result = [
@@ -44,4 +46,27 @@ RSpec.describe ContainerExpirationPoliciesHelper do
expect(helper.older_than_options).to eq(expected_result)
end
end
+
+ describe '#container_expiration_policies_historic_entry_enabled?' do
+ let_it_be(:project) { build_stubbed(:project) }
+
+ subject { helper.container_expiration_policies_historic_entry_enabled?(project) }
+
+ where(:application_setting, :feature_flag, :expected_result) do
+ true | true | true
+ true | false | true
+ false | true | true
+ false | false | false
+ end
+
+ with_them do
+ before do
+ stub_feature_flags(container_expiration_policies_historic_entry: false)
+ stub_application_setting(container_expiration_policies_enable_historic_entries: application_setting)
+ stub_feature_flags(container_expiration_policies_historic_entry: project) if feature_flag
+ end
+
+ it { is_expected.to eq(expected_result) }
+ end
+ end
end
diff --git a/spec/helpers/emails_helper_spec.rb b/spec/helpers/emails_helper_spec.rb
index 96ac4015c77..ef8b342a3f6 100644
--- a/spec/helpers/emails_helper_spec.rb
+++ b/spec/helpers/emails_helper_spec.rb
@@ -361,4 +361,116 @@ RSpec.describe EmailsHelper do
end
end
end
+
+ describe '#change_reviewer_notification_text' do
+ let(:mary) { build(:user, name: 'Mary') }
+ let(:john) { build(:user, name: 'John') }
+ let(:ted) { build(:user, name: 'Ted') }
+
+ context 'to new reviewers only' do
+ let(:previous_reviewers) { [] }
+ let(:new_reviewers) { [john] }
+
+ context 'with no html tag' do
+ let(:expected_output) do
+ 'Reviewer changed to John'
+ end
+
+ it 'returns the expected output' do
+ expect(change_reviewer_notification_text(new_reviewers, previous_reviewers)).to eq(expected_output)
+ end
+ end
+
+ context 'with <strong> tag' do
+ let(:expected_output) do
+ 'Reviewer changed to <strong>John</strong>'
+ end
+
+ it 'returns the expected output' do
+ expect(change_reviewer_notification_text(new_reviewers, previous_reviewers, :strong)).to eq(expected_output)
+ end
+ end
+ end
+
+ context 'from previous reviewers to new reviewers' do
+ let(:previous_reviewers) { [john, mary] }
+ let(:new_reviewers) { [ted] }
+
+ context 'with no html tag' do
+ let(:expected_output) do
+ 'Reviewer changed from John and Mary to Ted'
+ end
+
+ it 'returns the expected output' do
+ expect(change_reviewer_notification_text(new_reviewers, previous_reviewers)).to eq(expected_output)
+ end
+ end
+
+ context 'with <strong> tag' do
+ let(:expected_output) do
+ 'Reviewer changed from <strong>John and Mary</strong> to <strong>Ted</strong>'
+ end
+
+ it 'returns the expected output' do
+ expect(change_reviewer_notification_text(new_reviewers, previous_reviewers, :strong)).to eq(expected_output)
+ end
+ end
+ end
+
+ context 'from previous reviewers to no reviewers' do
+ let(:previous_reviewers) { [john, mary] }
+ let(:new_reviewers) { [] }
+
+ context 'with no html tag' do
+ let(:expected_output) do
+ 'Reviewer changed from John and Mary to Unassigned'
+ end
+
+ it 'returns the expected output' do
+ expect(change_reviewer_notification_text(new_reviewers, previous_reviewers)).to eq(expected_output)
+ end
+ end
+
+ context 'with <strong> tag' do
+ let(:expected_output) do
+ 'Reviewer changed from <strong>John and Mary</strong> to <strong>Unassigned</strong>'
+ end
+
+ it 'returns the expected output' do
+ expect(change_reviewer_notification_text(new_reviewers, previous_reviewers, :strong)).to eq(expected_output)
+ end
+ end
+ end
+
+ context "with a <script> tag in user's name" do
+ let(:previous_reviewers) { [] }
+ let(:new_reviewers) { [fishy_user] }
+ let(:fishy_user) { build(:user, name: "<script>alert('hi')</script>") }
+
+ let(:expected_output) do
+ 'Reviewer changed to <strong>&lt;script&gt;alert(&#39;hi&#39;)&lt;/script&gt;</strong>'
+ end
+
+ it 'escapes the html tag' do
+ expect(change_reviewer_notification_text(new_reviewers, previous_reviewers, :strong)).to eq(expected_output)
+ end
+ end
+
+ context "with url in user's name" do
+ subject(:email_helper) { Object.new.extend(described_class) }
+
+ let(:previous_reviewers) { [] }
+ let(:new_reviewers) { [fishy_user] }
+ let(:fishy_user) { build(:user, name: "example.com") }
+
+ let(:expected_output) do
+ 'Reviewer changed to example_com'
+ end
+
+ it "sanitizes user's name" do
+ expect(email_helper).to receive(:sanitize_name).and_call_original
+ expect(email_helper.change_reviewer_notification_text(new_reviewers, previous_reviewers)).to eq(expected_output)
+ end
+ end
+ end
end
diff --git a/spec/helpers/external_link_helper_spec.rb b/spec/helpers/external_link_helper_spec.rb
index b1a1884d887..f5bb0568824 100644
--- a/spec/helpers/external_link_helper_spec.rb
+++ b/spec/helpers/external_link_helper_spec.rb
@@ -6,12 +6,15 @@ RSpec.describe ExternalLinkHelper do
include IconsHelper
it 'returns external link with icon' do
- expect(external_link('https://gitlab.com', 'https://gitlab.com').to_s)
- .to eq('<a target="_blank" rel="noopener noreferrer" href="https://gitlab.com">https://gitlab.com <i aria-hidden="true" data-hidden="true" class="fa fa-external-link"></i></a>')
+ link = external_link('https://gitlab.com', 'https://gitlab.com').to_s
+ expect(link).to start_with('<a target="_blank" rel="noopener noreferrer" href="https://gitlab.com">https://gitlab.com')
+ expect(link).to include('data-testid="external-link-icon"')
end
it 'allows options when creating external link with icon' do
- expect(external_link('https://gitlab.com', 'https://gitlab.com', { "data-foo": "bar", class: "externalLink" }).to_s)
- .to eq('<a target="_blank" rel="noopener noreferrer" data-foo="bar" class="externalLink" href="https://gitlab.com">https://gitlab.com <i aria-hidden="true" data-hidden="true" class="fa fa-external-link"></i></a>')
+ link = external_link('https://gitlab.com', 'https://gitlab.com', { "data-foo": "bar", class: "externalLink" }).to_s
+
+ expect(link).to start_with('<a target="_blank" rel="noopener noreferrer" data-foo="bar" class="externalLink" href="https://gitlab.com">https://gitlab.com')
+ expect(link).to include('data-testid="external-link-icon"')
end
end
diff --git a/spec/helpers/feature_flags_helper_spec.rb b/spec/helpers/feature_flags_helper_spec.rb
new file mode 100644
index 00000000000..9a080736595
--- /dev/null
+++ b/spec/helpers/feature_flags_helper_spec.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe FeatureFlagsHelper do
+ let_it_be(:project) { create(:project) }
+ let_it_be(:feature_flag) { create(:operations_feature_flag, project: project) }
+ let_it_be(:user) { create(:user) }
+
+ describe '#unleash_api_url' do
+ subject { helper.unleash_api_url(project) }
+
+ it { is_expected.to end_with("/api/v4/feature_flags/unleash/#{project.id}") }
+ end
+
+ describe '#unleash_api_instance_id' do
+ subject { helper.unleash_api_instance_id(project) }
+
+ it { is_expected.not_to be_empty }
+ end
+end
diff --git a/spec/helpers/gitlab_routing_helper_spec.rb b/spec/helpers/gitlab_routing_helper_spec.rb
index 1ad7c7bb9ff..0088f739879 100644
--- a/spec/helpers/gitlab_routing_helper_spec.rb
+++ b/spec/helpers/gitlab_routing_helper_spec.rb
@@ -187,7 +187,7 @@ RSpec.describe GitlabRoutingHelper do
let(:ref) { 'test-ref' }
let(:args) { {} }
- subject { gitlab_raw_snippet_blob_path(snippet, blob.path, ref, args) }
+ subject { gitlab_raw_snippet_blob_path(snippet, blob.path, ref, **args) }
it_behaves_like 'snippet blob raw path'
@@ -222,7 +222,7 @@ RSpec.describe GitlabRoutingHelper do
let(:ref) { 'snippet-test-ref' }
let(:args) { {} }
- subject { gitlab_raw_snippet_blob_url(snippet, blob.path, ref, args) }
+ subject { gitlab_raw_snippet_blob_url(snippet, blob.path, ref, **args) }
it_behaves_like 'snippet blob raw url'
diff --git a/spec/helpers/groups/group_members_helper_spec.rb b/spec/helpers/groups/group_members_helper_spec.rb
index a25bf1c4157..bb92445cb19 100644
--- a/spec/helpers/groups/group_members_helper_spec.rb
+++ b/spec/helpers/groups/group_members_helper_spec.rb
@@ -5,9 +5,15 @@ require "spec_helper"
RSpec.describe Groups::GroupMembersHelper do
include MembersPresentation
- describe '.group_member_select_options' do
- let(:group) { create(:group) }
+ let_it_be(:current_user) { create(:user) }
+ let_it_be(:group) { create(:group) }
+
+ before do
+ allow(helper).to receive(:can?).with(current_user, :owner_access, group).and_return(true)
+ allow(helper).to receive(:current_user).and_return(current_user)
+ end
+ describe '.group_member_select_options' do
before do
helper.instance_variable_set(:@group, group)
end
@@ -28,14 +34,6 @@ RSpec.describe Groups::GroupMembersHelper do
end
describe '#members_data_json' do
- let(:current_user) { create(:user) }
- let(:group) { create(:group) }
-
- before do
- allow(helper).to receive(:can?).with(current_user, :owner_access, group).and_return(true)
- allow(helper).to receive(:current_user).and_return(current_user)
- end
-
shared_examples 'group_members.json' do
it 'matches json schema' do
json = helper.members_data_json(group, present_members([group_member]))
@@ -48,6 +46,14 @@ RSpec.describe Groups::GroupMembersHelper do
let(:group_member) { create(:group_member, group: group, created_by: current_user) }
it_behaves_like 'group_members.json'
+
+ context 'with user status set' do
+ let(:user) { create(:user) }
+ let!(:status) { create(:user_status, user: user) }
+ let(:group_member) { create(:group_member, group: group, user: user, created_by: current_user) }
+
+ it_behaves_like 'group_members.json'
+ end
end
context 'for an invited group member' do
@@ -62,4 +68,36 @@ RSpec.describe Groups::GroupMembersHelper do
it_behaves_like 'group_members.json'
end
end
+
+ describe '#group_members_list_data_attributes' do
+ let(:group_member) { create(:group_member, group: group, created_by: current_user) }
+
+ before do
+ allow(helper).to receive(:group_group_member_path).with(group, ':id').and_return('/groups/foo-bar/-/group_members/:id')
+ end
+
+ it 'returns expected hash' do
+ expect(helper.group_members_list_data_attributes(group, present_members([group_member]))).to include({
+ members: helper.members_data_json(group, present_members([group_member])),
+ member_path: '/groups/foo-bar/-/group_members/:id',
+ group_id: group.id
+ })
+ end
+ end
+
+ describe '#linked_groups_list_data_attributes' do
+ include_context 'group_group_link'
+
+ before do
+ allow(helper).to receive(:group_group_link_path).with(shared_group, ':id').and_return('/groups/foo-bar/-/group_links/:id')
+ end
+
+ it 'returns expected hash' do
+ expect(helper.linked_groups_list_data_attributes(shared_group)).to include({
+ members: helper.linked_groups_data_json(shared_group.shared_with_group_links),
+ member_path: '/groups/foo-bar/-/group_links/:id',
+ group_id: shared_group.id
+ })
+ end
+ end
end
diff --git a/spec/helpers/icons_helper_spec.rb b/spec/helpers/icons_helper_spec.rb
index 872aa821560..94012de3877 100644
--- a/spec/helpers/icons_helper_spec.rb
+++ b/spec/helpers/icons_helper_spec.rb
@@ -114,128 +114,128 @@ RSpec.describe IconsHelper do
end
describe 'file_type_icon_class' do
- it 'returns folder class' do
- expect(file_type_icon_class('folder', 0, 'folder_name')).to eq 'folder'
+ it 'returns folder-o class' do
+ expect(file_type_icon_class('folder', 0, 'folder_name')).to eq 'folder-o'
end
it 'returns share class' do
expect(file_type_icon_class('file', '120000', 'link')).to eq 'share'
end
- it 'returns file-pdf-o class with .pdf' do
- expect(file_type_icon_class('file', 0, 'filename.pdf')).to eq 'file-pdf-o'
+ it 'returns document class with .pdf' do
+ expect(file_type_icon_class('file', 0, 'filename.pdf')).to eq 'document'
end
- it 'returns file-image-o class with .jpg' do
- expect(file_type_icon_class('file', 0, 'filename.jpg')).to eq 'file-image-o'
+ it 'returns doc-image class with .jpg' do
+ expect(file_type_icon_class('file', 0, 'filename.jpg')).to eq 'doc-image'
end
- it 'returns file-image-o class with .JPG' do
- expect(file_type_icon_class('file', 0, 'filename.JPG')).to eq 'file-image-o'
+ it 'returns doc-image class with .JPG' do
+ expect(file_type_icon_class('file', 0, 'filename.JPG')).to eq 'doc-image'
end
- it 'returns file-image-o class with .png' do
- expect(file_type_icon_class('file', 0, 'filename.png')).to eq 'file-image-o'
+ it 'returns doc-image class with .png' do
+ expect(file_type_icon_class('file', 0, 'filename.png')).to eq 'doc-image'
end
- it 'returns file-image-o class with .apng' do
- expect(file_type_icon_class('file', 0, 'filename.apng')).to eq 'file-image-o'
+ it 'returns doc-image class with .apng' do
+ expect(file_type_icon_class('file', 0, 'filename.apng')).to eq 'doc-image'
end
- it 'returns file-image-o class with .webp' do
- expect(file_type_icon_class('file', 0, 'filename.webp')).to eq 'file-image-o'
+ it 'returns doc-image class with .webp' do
+ expect(file_type_icon_class('file', 0, 'filename.webp')).to eq 'doc-image'
end
- it 'returns file-archive-o class with .tar' do
- expect(file_type_icon_class('file', 0, 'filename.tar')).to eq 'file-archive-o'
+ it 'returns doc-compressed class with .tar' do
+ expect(file_type_icon_class('file', 0, 'filename.tar')).to eq 'doc-compressed'
end
- it 'returns file-archive-o class with .TAR' do
- expect(file_type_icon_class('file', 0, 'filename.TAR')).to eq 'file-archive-o'
+ it 'returns doc-compressed class with .TAR' do
+ expect(file_type_icon_class('file', 0, 'filename.TAR')).to eq 'doc-compressed'
end
- it 'returns file-archive-o class with .tar.gz' do
- expect(file_type_icon_class('file', 0, 'filename.tar.gz')).to eq 'file-archive-o'
+ it 'returns doc-compressed class with .tar.gz' do
+ expect(file_type_icon_class('file', 0, 'filename.tar.gz')).to eq 'doc-compressed'
end
- it 'returns file-audio-o class with .mp3' do
- expect(file_type_icon_class('file', 0, 'filename.mp3')).to eq 'file-audio-o'
+ it 'returns volume-up class with .mp3' do
+ expect(file_type_icon_class('file', 0, 'filename.mp3')).to eq 'volume-up'
end
- it 'returns file-audio-o class with .MP3' do
- expect(file_type_icon_class('file', 0, 'filename.MP3')).to eq 'file-audio-o'
+ it 'returns volume-up class with .MP3' do
+ expect(file_type_icon_class('file', 0, 'filename.MP3')).to eq 'volume-up'
end
- it 'returns file-audio-o class with .m4a' do
- expect(file_type_icon_class('file', 0, 'filename.m4a')).to eq 'file-audio-o'
+ it 'returns volume-up class with .m4a' do
+ expect(file_type_icon_class('file', 0, 'filename.m4a')).to eq 'volume-up'
end
- it 'returns file-audio-o class with .wav' do
- expect(file_type_icon_class('file', 0, 'filename.wav')).to eq 'file-audio-o'
+ it 'returns volume-up class with .wav' do
+ expect(file_type_icon_class('file', 0, 'filename.wav')).to eq 'volume-up'
end
- it 'returns file-video-o class with .avi' do
- expect(file_type_icon_class('file', 0, 'filename.avi')).to eq 'file-video-o'
+ it 'returns live-preview class with .avi' do
+ expect(file_type_icon_class('file', 0, 'filename.avi')).to eq 'live-preview'
end
- it 'returns file-video-o class with .AVI' do
- expect(file_type_icon_class('file', 0, 'filename.AVI')).to eq 'file-video-o'
+ it 'returns live-preview class with .AVI' do
+ expect(file_type_icon_class('file', 0, 'filename.AVI')).to eq 'live-preview'
end
- it 'returns file-video-o class with .mp4' do
- expect(file_type_icon_class('file', 0, 'filename.mp4')).to eq 'file-video-o'
+ it 'returns live-preview class with .mp4' do
+ expect(file_type_icon_class('file', 0, 'filename.mp4')).to eq 'live-preview'
end
- it 'returns file-word-o class with .odt' do
- expect(file_type_icon_class('file', 0, 'filename.odt')).to eq 'file-word-o'
+ it 'returns doc-text class with .odt' do
+ expect(file_type_icon_class('file', 0, 'filename.odt')).to eq 'doc-text'
end
- it 'returns file-word-o class with .doc' do
- expect(file_type_icon_class('file', 0, 'filename.doc')).to eq 'file-word-o'
+ it 'returns doc-text class with .doc' do
+ expect(file_type_icon_class('file', 0, 'filename.doc')).to eq 'doc-text'
end
- it 'returns file-word-o class with .DOC' do
- expect(file_type_icon_class('file', 0, 'filename.DOC')).to eq 'file-word-o'
+ it 'returns doc-text class with .DOC' do
+ expect(file_type_icon_class('file', 0, 'filename.DOC')).to eq 'doc-text'
end
- it 'returns file-word-o class with .docx' do
- expect(file_type_icon_class('file', 0, 'filename.docx')).to eq 'file-word-o'
+ it 'returns doc-text class with .docx' do
+ expect(file_type_icon_class('file', 0, 'filename.docx')).to eq 'doc-text'
end
- it 'returns file-excel-o class with .xls' do
- expect(file_type_icon_class('file', 0, 'filename.xls')).to eq 'file-excel-o'
+ it 'returns document class with .xls' do
+ expect(file_type_icon_class('file', 0, 'filename.xls')).to eq 'document'
end
- it 'returns file-excel-o class with .XLS' do
- expect(file_type_icon_class('file', 0, 'filename.XLS')).to eq 'file-excel-o'
+ it 'returns document class with .XLS' do
+ expect(file_type_icon_class('file', 0, 'filename.XLS')).to eq 'document'
end
- it 'returns file-excel-o class with .xlsx' do
- expect(file_type_icon_class('file', 0, 'filename.xlsx')).to eq 'file-excel-o'
+ it 'returns document class with .xlsx' do
+ expect(file_type_icon_class('file', 0, 'filename.xlsx')).to eq 'document'
end
- it 'returns file-excel-o class with .odp' do
- expect(file_type_icon_class('file', 0, 'filename.odp')).to eq 'file-powerpoint-o'
+ it 'returns doc-chart class with .odp' do
+ expect(file_type_icon_class('file', 0, 'filename.odp')).to eq 'doc-chart'
end
- it 'returns file-excel-o class with .ppt' do
- expect(file_type_icon_class('file', 0, 'filename.ppt')).to eq 'file-powerpoint-o'
+ it 'returns doc-chart class with .ppt' do
+ expect(file_type_icon_class('file', 0, 'filename.ppt')).to eq 'doc-chart'
end
- it 'returns file-excel-o class with .PPT' do
- expect(file_type_icon_class('file', 0, 'filename.PPT')).to eq 'file-powerpoint-o'
+ it 'returns doc-chart class with .PPT' do
+ expect(file_type_icon_class('file', 0, 'filename.PPT')).to eq 'doc-chart'
end
- it 'returns file-excel-o class with .pptx' do
- expect(file_type_icon_class('file', 0, 'filename.pptx')).to eq 'file-powerpoint-o'
+ it 'returns doc-chart class with .pptx' do
+ expect(file_type_icon_class('file', 0, 'filename.pptx')).to eq 'doc-chart'
end
- it 'returns file-text-o class with .unknow' do
- expect(file_type_icon_class('file', 0, 'filename.unknow')).to eq 'file-text-o'
+ it 'returns doc-text class with .unknow' do
+ expect(file_type_icon_class('file', 0, 'filename.unknow')).to eq 'doc-text'
end
- it 'returns file-text-o class with no extension' do
- expect(file_type_icon_class('file', 0, 'CHANGELOG')).to eq 'file-text-o'
+ it 'returns doc-text class with no extension' do
+ expect(file_type_icon_class('file', 0, 'CHANGELOG')).to eq 'doc-text'
end
end
diff --git a/spec/helpers/invite_members_helper_spec.rb b/spec/helpers/invite_members_helper_spec.rb
new file mode 100644
index 00000000000..b4e05d67553
--- /dev/null
+++ b/spec/helpers/invite_members_helper_spec.rb
@@ -0,0 +1,77 @@
+# frozen_string_literal: true
+
+require "spec_helper"
+
+RSpec.describe InviteMembersHelper do
+ let_it_be(:project) { create(:project) }
+ let_it_be(:developer) { create(:user, developer_projects: [project]) }
+ let(:owner) { project.owner }
+
+ before do
+ assign(:project, project)
+ end
+
+ describe "#directly_invite_members?" do
+ context 'when the user is an owner' do
+ before do
+ allow(helper).to receive(:current_user) { owner }
+ end
+
+ it 'returns false' do
+ allow(helper).to receive(:experiment_enabled?).with(:invite_members_version_a) { false }
+
+ expect(helper.directly_invite_members?).to eq false
+ end
+
+ it 'returns true' do
+ allow(helper).to receive(:experiment_enabled?).with(:invite_members_version_a) { true }
+
+ expect(helper.directly_invite_members?).to eq true
+ end
+ end
+
+ context 'when the user is a developer' do
+ before do
+ allow(helper).to receive(:current_user) { developer }
+ end
+
+ it 'returns false' do
+ allow(helper).to receive(:experiment_enabled?).with(:invite_members_version_a) { true }
+
+ expect(helper.directly_invite_members?).to eq false
+ end
+ end
+ end
+
+ describe "#indirectly_invite_members?" do
+ context 'when a user is a developer' do
+ before do
+ allow(helper).to receive(:current_user) { developer }
+ end
+
+ it 'returns false' do
+ allow(helper).to receive(:experiment_enabled?).with(:invite_members_version_b) { false }
+
+ expect(helper.indirectly_invite_members?).to eq false
+ end
+
+ it 'returns true' do
+ allow(helper).to receive(:experiment_enabled?).with(:invite_members_version_b) { true }
+
+ expect(helper.indirectly_invite_members?).to eq true
+ end
+ end
+
+ context 'when a user is an owner' do
+ before do
+ allow(helper).to receive(:current_user) { owner }
+ end
+
+ it 'returns false' do
+ allow(helper).to receive(:experiment_enabled?).with(:invite_members_version_b) { true }
+
+ expect(helper.indirectly_invite_members?).to eq false
+ end
+ end
+ end
+end
diff --git a/spec/helpers/issuables_helper_spec.rb b/spec/helpers/issuables_helper_spec.rb
index 89a2a92ea57..e8e5adaa274 100644
--- a/spec/helpers/issuables_helper_spec.rb
+++ b/spec/helpers/issuables_helper_spec.rb
@@ -44,23 +44,6 @@ RSpec.describe IssuablesHelper do
end
end
- describe '#issuable_labels_tooltip' do
- let(:label_entity) { LabelEntity.represent(label).as_json }
- let(:label2_entity) { LabelEntity.represent(label2).as_json }
-
- it 'returns label text with no labels' do
- expect(issuable_labels_tooltip([])).to eq(_('Labels'))
- end
-
- it 'returns label text with labels within max limit' do
- expect(issuable_labels_tooltip([label_entity])).to eq(label[:title])
- end
-
- it 'returns label text with labels exceeding max limit' do
- expect(issuable_labels_tooltip([label_entity, label2_entity], limit: 1)).to eq("#{label[:title]}, and 1 more")
- end
- end
-
describe '#issuables_state_counter_text' do
let(:user) { create(:user) }
@@ -306,6 +289,38 @@ RSpec.describe IssuablesHelper do
end
end
+ describe '#reviewer_sidebar_data' do
+ let(:user) { create(:user) }
+
+ subject { helper.reviewer_sidebar_data(user, merge_request: merge_request) }
+
+ context 'without merge_request' do
+ let(:merge_request) { nil }
+
+ it 'returns hash of reviewer data' do
+ is_expected.to eql({
+ avatar_url: user.avatar_url,
+ name: user.name,
+ username: user.username
+ })
+ end
+ end
+
+ context 'with merge_request' do
+ let(:merge_request) { build(:merge_request) }
+
+ where(can_merge: [true, false])
+
+ with_them do
+ before do
+ allow(merge_request).to receive(:can_be_merged_by?).and_return(can_merge)
+ end
+
+ it { is_expected.to include({ can_merge: can_merge })}
+ end
+ end
+ end
+
describe '#issuable_squash_option?' do
using RSpec::Parameterized::TableSyntax
@@ -337,4 +352,35 @@ RSpec.describe IssuablesHelper do
expect(helper.sidebar_milestone_tooltip_label(milestone)).to eq('&lt;img onerror=alert(1)&gt;<br/>Milestone')
end
end
+
+ describe '#serialize_issuable' do
+ context 'when it is a merge request' do
+ let(:merge_request) { build(:merge_request) }
+ let(:user) { build(:user) }
+
+ before do
+ allow(helper).to receive(:current_user) { user }
+ end
+
+ it 'has suggest_pipeline experiment enabled' do
+ allow(helper).to receive(:experiment_enabled?).with(:suggest_pipeline) { true }
+
+ expect_next_instance_of(MergeRequestSerializer) do |serializer|
+ expect(serializer).to receive(:represent).with(merge_request, { serializer: 'widget', experiment_enabled: :suggest_pipeline })
+ end
+
+ helper.serialize_issuable(merge_request, serializer: 'widget')
+ end
+
+ it 'suggest_pipeline experiment disabled' do
+ allow(helper).to receive(:experiment_enabled?).with(:suggest_pipeline) { false }
+
+ expect_next_instance_of(MergeRequestSerializer) do |serializer|
+ expect(serializer).to receive(:represent).with(merge_request, { serializer: 'widget' })
+ end
+
+ helper.serialize_issuable(merge_request, serializer: 'widget')
+ end
+ end
+ end
end
diff --git a/spec/helpers/issues_helper_spec.rb b/spec/helpers/issues_helper_spec.rb
index 3f84eeb12c2..1ed61bd3144 100644
--- a/spec/helpers/issues_helper_spec.rb
+++ b/spec/helpers/issues_helper_spec.rb
@@ -233,4 +233,25 @@ RSpec.describe IssuesHelper do
expect(helper.show_moved_service_desk_issue_warning?(new_issue)).to be(false)
end
end
+
+ describe '#use_startup_call' do
+ it "returns false when a query param is present" do
+ allow(controller.request).to receive(:query_parameters).and_return({ foo: 'bar' })
+
+ expect(helper.use_startup_call?).to eq(false)
+ end
+
+ it "returns false when user has stored sort preference" do
+ controller.instance_variable_set(:@sort, 'updated_asc')
+
+ expect(helper.use_startup_call?).to eq(false)
+ end
+
+ it 'returns true when request.query_parameters is empty with default sorting preference' do
+ controller.instance_variable_set(:@sort, 'created_date')
+ allow(controller.request).to receive(:query_parameters).and_return({})
+
+ expect(helper.use_startup_call?).to eq(true)
+ end
+ end
end
diff --git a/spec/helpers/labels_helper_spec.rb b/spec/helpers/labels_helper_spec.rb
index 77e1d10354c..b93dc03e434 100644
--- a/spec/helpers/labels_helper_spec.rb
+++ b/spec/helpers/labels_helper_spec.rb
@@ -244,26 +244,6 @@ RSpec.describe LabelsHelper do
end
end
- describe 'label_from_hash' do
- it 'builds a group label with whitelisted attributes' do
- label = label_from_hash({ title: 'foo', color: 'bar', id: 1, group_id: 1 })
-
- expect(label).to be_a(GroupLabel)
- expect(label.id).to be_nil
- expect(label.title).to eq('foo')
- expect(label.color).to eq('bar')
- end
-
- it 'builds a project label with whitelisted attributes' do
- label = label_from_hash({ title: 'foo', color: 'bar', id: 1, project_id: 1 })
-
- expect(label).to be_a(ProjectLabel)
- expect(label.id).to be_nil
- expect(label.title).to eq('foo')
- expect(label.color).to eq('bar')
- end
- end
-
describe '#label_status_tooltip' do
let(:status) { 'unsubscribed'.inquiry }
@@ -291,4 +271,34 @@ RSpec.describe LabelsHelper do
expect(tooltip).to eq('This is an image')
end
end
+
+ describe '#show_labels_full_path?' do
+ let_it_be(:group) { create(:group) }
+ let_it_be(:subgroup) { create(:group, parent: group) }
+ let_it_be(:project) { create(:project, group: group) }
+
+ context 'within a project' do
+ it 'returns truthy' do
+ expect(show_labels_full_path?(project, nil)).to be_truthy
+ end
+ end
+
+ context 'within a subgroup' do
+ it 'returns truthy' do
+ expect(show_labels_full_path?(nil, subgroup)).to be_truthy
+ end
+ end
+
+ context 'within a group' do
+ it 'returns falsey' do
+ expect(show_labels_full_path?(nil, group)).to be_falsey
+ end
+ end
+
+ context 'within the admin area' do
+ it 'returns falsey' do
+ expect(show_labels_full_path?(nil, nil)).to be_falsey
+ end
+ end
+ end
end
diff --git a/spec/helpers/notes_helper_spec.rb b/spec/helpers/notes_helper_spec.rb
index 41511b65cc4..f9b3b535334 100644
--- a/spec/helpers/notes_helper_spec.rb
+++ b/spec/helpers/notes_helper_spec.rb
@@ -5,19 +5,19 @@ require "spec_helper"
RSpec.describe NotesHelper do
include RepoHelpers
- let(:owner) { create(:owner) }
- let(:group) { create(:group) }
- let(:project) { create(:project, namespace: group) }
- let(:maintainer) { create(:user) }
- let(:reporter) { create(:user) }
- let(:guest) { create(:user) }
-
- let(:owner_note) { create(:note, author: owner, project: project) }
- let(:maintainer_note) { create(:note, author: maintainer, project: project) }
- let(:reporter_note) { create(:note, author: reporter, project: project) }
+ let_it_be(:owner) { create(:owner) }
+ let_it_be(:group) { create(:group) }
+ let_it_be(:project) { create(:project, namespace: group) }
+ let_it_be(:maintainer) { create(:user) }
+ let_it_be(:reporter) { create(:user) }
+ let_it_be(:guest) { create(:user) }
+
+ let_it_be(:owner_note) { create(:note, author: owner, project: project) }
+ let_it_be(:maintainer_note) { create(:note, author: maintainer, project: project) }
+ let_it_be(:reporter_note) { create(:note, author: reporter, project: project) }
let!(:notes) { [owner_note, maintainer_note, reporter_note] }
- before do
+ before_all do
group.add_owner(owner)
project.add_maintainer(maintainer)
project.add_reporter(reporter)
@@ -72,14 +72,14 @@ RSpec.describe NotesHelper do
end
describe '#discussion_path' do
- let(:project) { create(:project, :repository) }
+ let_it_be(:project) { create(:project, :repository) }
let(:anchor) { discussion.line_code }
context 'for a merge request discusion' do
- let(:merge_request) { create(:merge_request, source_project: project, target_project: project, importing: true) }
- let!(:merge_request_diff1) { merge_request.merge_request_diffs.create!(head_commit_sha: '6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9') }
- let!(:merge_request_diff2) { merge_request.merge_request_diffs.create!(head_commit_sha: nil) }
- let!(:merge_request_diff3) { merge_request.merge_request_diffs.create!(head_commit_sha: '5937ac0a7beb003549fc5fd26fc247adbce4a52e') }
+ let_it_be(:merge_request) { create(:merge_request, source_project: project, target_project: project, importing: true) }
+ let_it_be(:merge_request_diff1) { merge_request.merge_request_diffs.create!(head_commit_sha: '6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9') }
+ let_it_be(:merge_request_diff2) { merge_request.merge_request_diffs.create!(head_commit_sha: nil) }
+ let_it_be(:merge_request_diff3) { merge_request.merge_request_diffs.create!(head_commit_sha: '5937ac0a7beb003549fc5fd26fc247adbce4a52e') }
context 'for a diff discussion' do
context 'when the discussion is active' do
@@ -229,20 +229,18 @@ RSpec.describe NotesHelper do
end
it 'return project notes path for project snippet' do
- namespace = create(:namespace, path: 'nm')
- @project = create(:project, path: 'test', namespace: namespace)
+ @project = project
@snippet = create(:project_snippet, project: @project)
@noteable = @snippet
- expect(helper.notes_url).to eq("/nm/test/noteable/project_snippet/#{@noteable.id}/notes")
+ expect(helper.notes_url).to eq("/#{project.full_path}/noteable/project_snippet/#{@noteable.id}/notes")
end
it 'return project notes path for other noteables' do
- namespace = create(:namespace, path: 'nm')
- @project = create(:project, path: 'test', namespace: namespace)
+ @project = project
@noteable = create(:issue, project: @project)
- expect(helper.notes_url).to eq("/nm/test/noteable/issue/#{@noteable.id}/notes")
+ expect(helper.notes_url).to eq("/#{@project.full_path}/noteable/issue/#{@noteable.id}/notes")
end
end
@@ -254,19 +252,17 @@ RSpec.describe NotesHelper do
end
it 'return project notes path for project snippet' do
- namespace = create(:namespace, path: 'nm')
- @project = create(:project, path: 'test', namespace: namespace)
+ @project = project
note = create(:note_on_project_snippet, project: @project)
- expect(helper.note_url(note)).to eq("/nm/test/notes/#{note.id}")
+ expect(helper.note_url(note)).to eq("/#{project.full_path}/notes/#{note.id}")
end
it 'return project notes path for other noteables' do
- namespace = create(:namespace, path: 'nm')
- @project = create(:project, path: 'test', namespace: namespace)
+ @project = project
note = create(:note_on_issue, project: @project)
- expect(helper.note_url(note)).to eq("/nm/test/notes/#{note.id}")
+ expect(helper.note_url(note)).to eq("/#{project.full_path}/notes/#{note.id}")
end
end
@@ -279,8 +275,7 @@ RSpec.describe NotesHelper do
end
it 'returns namespace, project and note for project snippet' do
- namespace = create(:namespace, path: 'nm')
- @project = create(:project, path: 'test', namespace: namespace)
+ @project = project
@snippet = create(:project_snippet, project: @project)
@note = create(:note_on_personal_snippet)
@@ -288,8 +283,7 @@ RSpec.describe NotesHelper do
end
it 'returns namespace, project and note path for other noteables' do
- namespace = create(:namespace, path: 'nm')
- @project = create(:project, path: 'test', namespace: namespace)
+ @project = project
@note = create(:note_on_issue, project: @project)
expect(helper.form_resources).to eq([@project, @note])
@@ -297,7 +291,6 @@ RSpec.describe NotesHelper do
end
describe '#noteable_note_url' do
- let(:project) { create(:project) }
let(:issue) { create(:issue, project: project) }
let(:note) { create(:note_on_issue, noteable: issue, project: project) }
diff --git a/spec/helpers/operations_helper_spec.rb b/spec/helpers/operations_helper_spec.rb
index 3dac2cf54dc..8d2fc643caa 100644
--- a/spec/helpers/operations_helper_spec.rb
+++ b/spec/helpers/operations_helper_spec.rb
@@ -35,7 +35,7 @@ RSpec.describe OperationsHelper do
'url' => alerts_service.url,
'authorization_key' => nil,
'form_path' => project_service_path(project, alerts_service),
- 'alerts_setup_url' => help_page_path('user/project/integrations/generic_alerts.md', anchor: 'setting-up-generic-alerts'),
+ 'alerts_setup_url' => help_page_path('operations/incident_management/alert_integrations.md', anchor: 'generic-http-endpoint'),
'alerts_usage_url' => project_alert_management_index_path(project),
'prometheus_form_path' => project_service_path(project, prometheus_service),
'prometheus_reset_key_path' => reset_alerting_token_project_settings_operations_path(project),
@@ -145,7 +145,7 @@ RSpec.describe OperationsHelper do
subject { helper.operations_settings_data }
it 'returns the correct set of data' do
- is_expected.to eq(
+ is_expected.to include(
operations_settings_endpoint: project_settings_operations_path(project),
templates: '[]',
create_issue: 'false',
diff --git a/spec/helpers/packages_helper_spec.rb b/spec/helpers/packages_helper_spec.rb
index 1917c851547..dacd386d01c 100644
--- a/spec/helpers/packages_helper_spec.rb
+++ b/spec/helpers/packages_helper_spec.rb
@@ -52,37 +52,14 @@ RSpec.describe PackagesHelper do
end
end
- describe 'packages_coming_soon_enabled?' do
- it 'returns false when the feature flag is disabled' do
- stub_feature_flags(packages_coming_soon: false)
+ describe 'composer_config_repository_name' do
+ let(:host) { Gitlab.config.gitlab.host }
+ let(:group_id) { 1 }
- expect(helper.packages_coming_soon_enabled?(project)).to eq(false)
- end
-
- it 'returns false when not on dev or gitlab.com' do
- expect(helper.packages_coming_soon_enabled?(project)).to eq(false)
- end
- end
-
- describe 'packages_coming_soon_data' do
- let_it_be(:group) { create(:group) }
-
- before do
- allow(Gitlab).to receive(:dev_env_or_com?) { true }
- end
-
- it 'returns the gitlab project on gitlab.com' do
- allow(Gitlab).to receive(:com?) { true }
-
- expect(helper.packages_coming_soon_data(project)).to include({ project_path: 'gitlab-org/gitlab' })
- end
-
- it 'returns the test project when not on gitlab.com' do
- expect(helper.packages_coming_soon_data(project)).to include({ project_path: 'gitlab-org/gitlab-test' })
- end
+ it 'return global unique composer registry id' do
+ id = helper.composer_config_repository_name(group_id)
- it 'works correctly with a group' do
- expect(helper.packages_coming_soon_data(group)).to include({ project_path: 'gitlab-org/gitlab-test' })
+ expect(id).to eq("#{host}/#{group_id}")
end
end
end
diff --git a/spec/helpers/projects/alert_management_helper_spec.rb b/spec/helpers/projects/alert_management_helper_spec.rb
index 183f0438c35..83b89abde58 100644
--- a/spec/helpers/projects/alert_management_helper_spec.rb
+++ b/spec/helpers/projects/alert_management_helper_spec.rb
@@ -32,7 +32,9 @@ RSpec.describe Projects::AlertManagementHelper do
'populating-alerts-help-url' => 'http://test.host/help/operations/incident_management/index.md#enable-alert-management',
'empty-alert-svg-path' => match_asset_path('/assets/illustrations/alert-management-empty-state.svg'),
'user-can-enable-alert-management' => 'true',
- 'alert-management-enabled' => 'false'
+ 'alert-management-enabled' => 'false',
+ 'text-query': nil,
+ 'assignee-username-query': nil
)
end
end
diff --git a/spec/helpers/projects/incidents_helper_spec.rb b/spec/helpers/projects/incidents_helper_spec.rb
index 0affa67a902..7a8a6d5222f 100644
--- a/spec/helpers/projects/incidents_helper_spec.rb
+++ b/spec/helpers/projects/incidents_helper_spec.rb
@@ -9,18 +9,28 @@ RSpec.describe Projects::IncidentsHelper do
let(:project_path) { project.full_path }
let(:new_issue_path) { new_project_issue_path(project) }
let(:issue_path) { project_issues_path(project) }
+ let(:params) do
+ {
+ search: 'search text',
+ author_username: 'root',
+ assignee_username: 'max.power'
+ }
+ end
describe '#incidents_data' do
- subject(:data) { helper.incidents_data(project) }
+ subject(:data) { helper.incidents_data(project, params) }
it 'returns frontend configuration' do
- expect(data).to match(
+ expect(data).to include(
'project-path' => project_path,
'new-issue-path' => new_issue_path,
'incident-template-name' => 'incident',
'incident-type' => 'incident',
'issue-path' => issue_path,
- 'empty-list-svg-path' => match_asset_path('/assets/illustrations/incident-empty-state.svg')
+ 'empty-list-svg-path' => match_asset_path('/assets/illustrations/incident-empty-state.svg'),
+ 'text-query': 'search text',
+ 'author-username-query': 'root',
+ 'assignee-username-query': 'max.power'
)
end
end
diff --git a/spec/helpers/projects_helper_spec.rb b/spec/helpers/projects_helper_spec.rb
index 2b345ff3ae6..f081cf225b1 100644
--- a/spec/helpers/projects_helper_spec.rb
+++ b/spec/helpers/projects_helper_spec.rb
@@ -5,16 +5,15 @@ require 'spec_helper'
RSpec.describe ProjectsHelper do
include ProjectForksHelper
- let_it_be(:project) { create(:project) }
+ let_it_be_with_reload(:project) { create(:project) }
+ let_it_be_with_refind(:project_with_repo) { create(:project, :repository) }
let_it_be(:user) { create(:user) }
- describe '#project_incident_management_setting' do
- let(:project) { create(:project) }
-
- before do
- helper.instance_variable_set(:@project, project)
- end
+ before do
+ helper.instance_variable_set(:@project, project)
+ end
+ describe '#project_incident_management_setting' do
context 'when incident_management_setting exists' do
let(:project_incident_management_setting) do
create(:project_incident_management_setting, project: project)
@@ -40,20 +39,14 @@ RSpec.describe ProjectsHelper do
end
describe '#error_tracking_setting_project_json' do
- let(:project) { create(:project) }
-
context 'error tracking setting does not exist' do
- before do
- helper.instance_variable_set(:@project, project)
- end
-
it 'returns nil' do
expect(helper.error_tracking_setting_project_json).to be_nil
end
end
context 'error tracking setting exists' do
- let!(:error_tracking_setting) { create(:project_error_tracking_setting, project: project) }
+ let_it_be(:error_tracking_setting) { create(:project_error_tracking_setting, project: project) }
context 'api_url present' do
let(:json) do
@@ -65,24 +58,16 @@ RSpec.describe ProjectsHelper do
}.to_json
end
- before do
- helper.instance_variable_set(:@project, project)
- end
-
it 'returns error tracking json' do
expect(helper.error_tracking_setting_project_json).to eq(json)
end
end
context 'api_url not present' do
- before do
+ it 'returns nil' do
project.error_tracking_setting.api_url = nil
project.error_tracking_setting.enabled = false
- helper.instance_variable_set(:@project, project)
- end
-
- it 'returns nil' do
expect(helper.error_tracking_setting_project_json).to be_nil
end
end
@@ -98,8 +83,7 @@ RSpec.describe ProjectsHelper do
end
describe "can_change_visibility_level?" do
- let(:project) { create(:project) }
- let(:user) { create(:project_member, :reporter, user: create(:user), project: project).user }
+ let_it_be(:user) { create(:project_member, :reporter, user: create(:user), project: project).user }
let(:forked_project) { fork_project(project, user) }
it "returns false if there are no appropriate permissions" do
@@ -142,8 +126,7 @@ RSpec.describe ProjectsHelper do
end
describe '#can_disable_emails?' do
- let(:project) { create(:project) }
- let(:user) { create(:project_member, :maintainer, user: create(:user), project: project).user }
+ let_it_be(:user) { create(:project_member, :maintainer, user: create(:user), project: project).user }
it 'returns true for the project owner' do
allow(helper).to receive(:can?).with(project.owner, :set_emails_disabled, project) { true }
@@ -166,11 +149,7 @@ RSpec.describe ProjectsHelper do
end
describe "readme_cache_key" do
- let(:project) { create(:project, :repository) }
-
- before do
- helper.instance_variable_set(:@project, project)
- end
+ let(:project) { project_with_repo }
it "returns a valid cach key" do
expect(helper.send(:readme_cache_key)).to eq("#{project.full_path}-#{project.commit.id}-readme")
@@ -184,8 +163,7 @@ RSpec.describe ProjectsHelper do
end
describe "#project_list_cache_key", :clean_gitlab_redis_shared_state do
- let(:project) { create(:project, :repository) }
- let(:user) { create(:user) }
+ let(:project) { project_with_repo }
before do
allow(helper).to receive(:current_user).and_return(user)
@@ -249,8 +227,6 @@ RSpec.describe ProjectsHelper do
describe '#load_pipeline_status' do
it 'loads the pipeline status in batch' do
- project = build(:project)
-
helper.load_pipeline_status([project])
# Skip lazy loading of the `pipeline_status` attribute
pipeline_status = project.instance_variable_get('@pipeline_status')
@@ -260,8 +236,6 @@ RSpec.describe ProjectsHelper do
end
describe '#show_no_ssh_key_message?' do
- let(:user) { create(:user) }
-
before do
allow(helper).to receive(:current_user).and_return(user)
end
@@ -282,8 +256,6 @@ RSpec.describe ProjectsHelper do
end
describe '#show_no_password_message?' do
- let(:user) { create(:user) }
-
before do
allow(helper).to receive(:current_user).and_return(user)
end
@@ -424,7 +396,6 @@ RSpec.describe ProjectsHelper do
before do
allow(helper).to receive(:current_user).and_return(user)
- helper.instance_variable_set(:@project, project)
end
context 'when there is no current_user' do
@@ -444,9 +415,6 @@ RSpec.describe ProjectsHelper do
end
describe '#get_project_nav_tabs' do
- let_it_be(:user) { create(:user) }
- let(:project) { create(:project) }
-
before do
allow(helper).to receive(:can?) { true }
end
@@ -524,7 +492,14 @@ RSpec.describe ProjectsHelper do
subject { helper.send(:can_view_operations_tab?, user, project) }
- [:read_environment, :read_cluster, :metrics_dashboard].each do |ability|
+ [
+ :metrics_dashboard,
+ :read_alert_management_alert,
+ :read_environment,
+ :read_issue,
+ :read_sentry_issue,
+ :read_cluster
+ ].each do |ability|
it 'includes operations tab' do
allow(helper).to receive(:can?).and_return(false)
allow(helper).to receive(:can?).with(user, ability, project).and_return(true)
@@ -536,7 +511,6 @@ RSpec.describe ProjectsHelper do
describe '#show_projects' do
let(:projects) do
- create(:project)
Project.all
end
@@ -561,8 +535,8 @@ RSpec.describe ProjectsHelper do
end
end
- describe('#push_to_create_project_command') do
- let(:user) { create(:user, username: 'john') }
+ describe '#push_to_create_project_command' do
+ let(:user) { build_stubbed(:user, username: 'john') }
it 'returns the command to push to create project over HTTP' do
allow(Gitlab::CurrentSettings.current_application_settings).to receive(:enabled_git_access_protocol) { 'http' }
@@ -578,8 +552,6 @@ RSpec.describe ProjectsHelper do
end
describe '#any_projects?' do
- let!(:project) { create(:project) }
-
it 'returns true when projects will be returned' do
expect(helper.any_projects?(Project.all)).to eq(true)
end
@@ -609,7 +581,7 @@ RSpec.describe ProjectsHelper do
end
describe '#git_user_name' do
- let(:user) { double(:user, name: 'John "A" Doe53') }
+ let(:user) { build_stubbed(:user, name: 'John "A" Doe53') }
before do
allow(helper).to receive(:current_user).and_return(user)
@@ -632,8 +604,6 @@ RSpec.describe ProjectsHelper do
end
context 'user logged in' do
- let(:user) { create(:user) }
-
before do
allow(helper).to receive(:current_user).and_return(user)
end
@@ -658,7 +628,6 @@ RSpec.describe ProjectsHelper do
end
describe 'show_xcode_link' do
- let!(:project) { create(:project) }
let(:mac_ua) { 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36' }
let(:ios_ua) { 'Mozilla/5.0 (iPad; CPU OS 5_1_1 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9B206 Safari/7534.48.3' }
@@ -799,7 +768,7 @@ RSpec.describe ProjectsHelper do
describe '#show_auto_devops_implicitly_enabled_banner?' do
using RSpec::Parameterized::TableSyntax
- let(:user) { create(:user) }
+ let_it_be_with_reload(:project_with_auto_devops) { create(:project, :repository, :auto_devops) }
let(:feature_visibilities) do
{
@@ -873,9 +842,9 @@ RSpec.describe ProjectsHelper do
with_them do
let(:project) do
if project_setting.nil?
- create(:project, :repository)
+ project_with_repo
else
- create(:project, :repository, :auto_devops)
+ project_with_auto_devops
end
end
@@ -896,14 +865,8 @@ RSpec.describe ProjectsHelper do
end
describe '#can_import_members?' do
- let(:project) { create(:project) }
- let(:user) { create(:user) }
let(:owner) { project.owner }
- before do
- helper.instance_variable_set(:@project, project)
- end
-
it 'returns false if user cannot admin_project_member' do
allow(helper).to receive(:current_user) { user }
expect(helper.can_import_members?).to eq false
@@ -916,12 +879,6 @@ RSpec.describe ProjectsHelper do
end
describe '#metrics_external_dashboard_url' do
- let(:project) { create(:project) }
-
- before do
- helper.instance_variable_set(:@project, project)
- end
-
context 'metrics_setting exists' do
it 'returns external_dashboard_url' do
metrics_setting = create(:project_metrics_setting, project: project)
@@ -938,12 +895,6 @@ RSpec.describe ProjectsHelper do
end
describe '#grafana_integration_url' do
- let(:project) { create(:project) }
-
- before do
- helper.instance_variable_set(:@project, project)
- end
-
subject { helper.grafana_integration_url }
it { is_expected.to eq(nil) }
@@ -956,12 +907,6 @@ RSpec.describe ProjectsHelper do
end
describe '#grafana_integration_token' do
- let(:project) { create(:project) }
-
- before do
- helper.instance_variable_set(:@project, project)
- end
-
subject { helper.grafana_integration_masked_token }
it { is_expected.to eq(nil) }
@@ -974,12 +919,6 @@ RSpec.describe ProjectsHelper do
end
describe '#grafana_integration_enabled?' do
- let(:project) { create(:project) }
-
- before do
- helper.instance_variable_set(:@project, project)
- end
-
subject { helper.grafana_integration_enabled? }
it { is_expected.to eq(nil) }
@@ -992,7 +931,6 @@ RSpec.describe ProjectsHelper do
end
describe '#project_license_name(project)', :request_store do
- let_it_be(:project) { create(:project) }
let_it_be(:repository) { project.repository }
subject { project_license_name(project) }
diff --git a/spec/helpers/releases_helper_spec.rb b/spec/helpers/releases_helper_spec.rb
index f10a2ed8e60..704e8dc40cb 100644
--- a/spec/helpers/releases_helper_spec.rb
+++ b/spec/helpers/releases_helper_spec.rb
@@ -64,6 +64,7 @@ RSpec.describe ReleasesHelper do
describe '#data_for_edit_release_page' do
it 'has the needed data to display the "edit release" page' do
keys = %i(project_id
+ project_path
tag_name
markdown_preview_path
markdown_docs_path
@@ -80,6 +81,7 @@ RSpec.describe ReleasesHelper do
describe '#data_for_new_release_page' do
it 'has the needed data to display the "new release" page' do
keys = %i(project_id
+ project_path
releases_page_path
markdown_preview_path
markdown_docs_path
@@ -92,5 +94,15 @@ RSpec.describe ReleasesHelper do
expect(helper.data_for_new_release_page.keys).to match_array(keys)
end
end
+
+ describe '#data_for_show_page' do
+ it 'has the needed data to display the individual "release" page' do
+ keys = %i(project_id
+ project_path
+ tag_name)
+
+ expect(helper.data_for_show_page.keys).to match_array(keys)
+ end
+ end
end
end
diff --git a/spec/helpers/search_helper_spec.rb b/spec/helpers/search_helper_spec.rb
index 594c5c11994..6fe071521cd 100644
--- a/spec/helpers/search_helper_spec.rb
+++ b/spec/helpers/search_helper_spec.rb
@@ -29,7 +29,7 @@ RSpec.describe SearchHelper do
end
it "includes Help sections" do
- expect(search_autocomplete_opts("hel").size).to eq(9)
+ expect(search_autocomplete_opts("hel").size).to eq(8)
end
it "includes default sections" do
@@ -73,7 +73,7 @@ RSpec.describe SearchHelper do
expect(result.keys).to match_array(%i[category id label url avatar_url])
end
- it 'includes the first 5 of the users recent issues' do
+ it 'includes the users recently viewed issues' do
recent_issues = instance_double(::Gitlab::Search::RecentIssues)
expect(::Gitlab::Search::RecentIssues).to receive(:new).with(user: user).and_return(recent_issues)
project1 = create(:project, :with_avatar, namespace: user.namespace)
@@ -81,13 +81,11 @@ RSpec.describe SearchHelper do
issue1 = create(:issue, title: 'issue 1', project: project1)
issue2 = create(:issue, title: 'issue 2', project: project2)
- other_issues = create_list(:issue, 5)
-
- expect(recent_issues).to receive(:search).with('the search term').and_return(Issue.id_in_ordered([issue1.id, issue2.id, *other_issues.map(&:id)]))
+ expect(recent_issues).to receive(:search).with('the search term').and_return(Issue.id_in_ordered([issue1.id, issue2.id]))
results = search_autocomplete_opts("the search term")
- expect(results.count).to eq(5)
+ expect(results.count).to eq(2)
expect(results[0]).to include({
category: 'Recent issues',
@@ -106,7 +104,7 @@ RSpec.describe SearchHelper do
})
end
- it 'includes the first 5 of the users recent merge requests' do
+ it 'includes the users recently viewed merge requests' do
recent_merge_requests = instance_double(::Gitlab::Search::RecentMergeRequests)
expect(::Gitlab::Search::RecentMergeRequests).to receive(:new).with(user: user).and_return(recent_merge_requests)
project1 = create(:project, :with_avatar, namespace: user.namespace)
@@ -114,13 +112,11 @@ RSpec.describe SearchHelper do
merge_request1 = create(:merge_request, :unique_branches, title: 'Merge request 1', target_project: project1, source_project: project1)
merge_request2 = create(:merge_request, :unique_branches, title: 'Merge request 2', target_project: project2, source_project: project2)
- other_merge_requests = create_list(:merge_request, 5)
-
- expect(recent_merge_requests).to receive(:search).with('the search term').and_return(MergeRequest.id_in_ordered([merge_request1.id, merge_request2.id, *other_merge_requests.map(&:id)]))
+ expect(recent_merge_requests).to receive(:search).with('the search term').and_return(MergeRequest.id_in_ordered([merge_request1.id, merge_request2.id]))
results = search_autocomplete_opts("the search term")
- expect(results.count).to eq(5)
+ expect(results.count).to eq(2)
expect(results[0]).to include({
category: 'Recent merge requests',
@@ -357,14 +353,6 @@ RSpec.describe SearchHelper do
describe '#show_user_search_tab?' do
subject { show_user_search_tab? }
- context 'when users_search feature is disabled' do
- before do
- stub_feature_flags(users_search: false)
- end
-
- it { is_expected.to eq(false) }
- end
-
context 'when project search' do
before do
@project = :some_project
@@ -399,4 +387,94 @@ RSpec.describe SearchHelper do
end
end
end
+
+ describe '#repository_ref' do
+ let_it_be(:project) { create(:project, :repository) }
+ let(:params) { { repository_ref: 'the-repository-ref-param' } }
+
+ subject { repository_ref(project) }
+
+ it { is_expected.to eq('the-repository-ref-param') }
+
+ context 'when the param :repository_ref is not set' do
+ let(:params) { { repository_ref: nil } }
+
+ it { is_expected.to eq(project.default_branch) }
+ end
+
+ context 'when the repository_ref param is a number' do
+ let(:params) { { repository_ref: 111111 } }
+
+ it { is_expected.to eq('111111') }
+ end
+ end
+
+ describe '#highlight_and_truncate_issue' do
+ let(:description) { 'hello world' }
+ let(:issue) { create(:issue, description: description) }
+ let(:user) { create(:user) }
+
+ before do
+ allow(self).to receive(:current_user).and_return(user)
+ end
+
+ subject { highlight_and_truncate_issue(issue, 'test', {}) }
+
+ context 'when description is not present' do
+ let(:description) { nil }
+
+ it 'does nothing' do
+ expect(self).not_to receive(:simple_search_highlight_and_truncate)
+
+ subject
+ end
+ end
+
+ context 'when description present' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:description, :expected) do
+ 'test' | '<span class="gl-text-black-normal gl-font-weight-bold">test</span>'
+ '<span style="color: blue;">this test should not be blue</span>' | '<span>this <span class="gl-text-black-normal gl-font-weight-bold">test</span> should not be blue</span>'
+ '<a href="#" onclick="alert(\'XSS\')">Click Me test</a>' | '<a href="#">Click Me <span class="gl-text-black-normal gl-font-weight-bold">test</span></a>'
+ '<script type="text/javascript">alert(\'Another XSS\');</script> test' | ' <span class="gl-text-black-normal 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-black-normal 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...'
+ end
+
+ with_them do
+ it 'sanitizes, truncates, and highlights the search term' do
+ expect(subject).to eq(expected)
+ end
+ end
+ end
+ end
+
+ describe '#search_service' do
+ using RSpec::Parameterized::TableSyntax
+
+ subject { search_service }
+
+ before do
+ allow(self).to receive(:current_user).and_return(:the_current_user)
+ end
+
+ where(:confidential, :expected) do
+ '0' | false
+ '1' | true
+ 'yes' | true
+ 'no' | false
+ true | true
+ false | false
+ end
+
+ let(:params) {{ confidential: confidential }}
+
+ with_them do
+ it 'transforms confidentiality param' do
+ expect(::SearchService).to receive(:new).with(:the_current_user, { confidential: expected })
+
+ subject
+ end
+ end
+ end
end
diff --git a/spec/helpers/snippets_helper_spec.rb b/spec/helpers/snippets_helper_spec.rb
index a3244bec56f..5a3c8e37e8c 100644
--- a/spec/helpers/snippets_helper_spec.rb
+++ b/spec/helpers/snippets_helper_spec.rb
@@ -63,32 +63,6 @@ RSpec.describe SnippetsHelper do
end
end
- describe '#snippet_embed_tag' do
- subject { snippet_embed_tag(snippet) }
-
- context 'personal snippets' do
- let(:snippet) { public_personal_snippet }
-
- context 'public' do
- it 'returns a script tag with the snippet full url' do
- expect(subject).to eq(script_embed("http://test.host/-/snippets/#{snippet.id}"))
- end
- end
- end
-
- context 'project snippets' do
- let(:snippet) { public_project_snippet }
-
- it 'returns a script tag with the snippet full url' do
- expect(subject).to eq(script_embed("http://test.host/#{snippet.project.path_with_namespace}/-/snippets/#{snippet.id}"))
- end
- end
-
- def script_embed(url)
- "<script src=\"#{url}.js\"></script>"
- end
- end
-
describe '#download_raw_snippet_button' do
subject { download_raw_snippet_button(snippet) }
@@ -142,28 +116,4 @@ RSpec.describe SnippetsHelper do
end
end
end
-
- describe '#snippet_embed_input' do
- subject { snippet_embed_input(snippet) }
-
- context 'with PersonalSnippet' do
- let(:snippet) { public_personal_snippet }
-
- it 'returns the input component' do
- expect(subject).to eq embed_input(snippet_url(snippet))
- end
- end
-
- context 'with ProjectSnippet' do
- let(:snippet) { public_project_snippet }
-
- it 'returns the input component' do
- expect(subject).to eq embed_input(project_snippet_url(snippet.project, snippet))
- end
- end
-
- def embed_input(url)
- "<input type=\"text\" readonly=\"readonly\" class=\"js-snippet-url-area snippet-embed-input form-control\" data-url=\"#{url}\" value=\"<script src=&quot;#{url}.js&quot;></script>\" autocomplete=\"off\"></input>"
- end
- end
end
diff --git a/spec/helpers/startupjs_helper_spec.rb b/spec/helpers/startupjs_helper_spec.rb
new file mode 100644
index 00000000000..6d61c38d4a5
--- /dev/null
+++ b/spec/helpers/startupjs_helper_spec.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe StartupjsHelper do
+ describe '#page_startup_graphql_calls' do
+ let(:query_location) { 'repository/path_last_commit' }
+ let(:query_content) do
+ File.read(File.join(Rails.root, 'app/graphql/queries', "#{query_location}.query.graphql"))
+ end
+
+ it 'returns an array containing GraphQL Page Startup Calls' do
+ helper.add_page_startup_graphql_call(query_location, { ref: 'foo' })
+
+ startup_graphql_calls = helper.page_startup_graphql_calls
+
+ expect(startup_graphql_calls).to include({ query: query_content, variables: { ref: 'foo' } })
+ end
+ end
+end
diff --git a/spec/helpers/tree_helper_spec.rb b/spec/helpers/tree_helper_spec.rb
index 97b6802dde9..b5d356b985c 100644
--- a/spec/helpers/tree_helper_spec.rb
+++ b/spec/helpers/tree_helper_spec.rb
@@ -167,31 +167,60 @@ RSpec.describe TreeHelper do
end
end
- describe '#vue_ide_link_data' do
+ describe '#web_ide_button_data' do
+ let(:blob) { project.repository.blob_at('refs/heads/master', @path) }
+
before do
+ @path = ''
+ @project = project
+ @ref = sha
+
allow(helper).to receive(:current_user).and_return(nil)
allow(helper).to receive(:can_collaborate_with_project?).and_return(true)
allow(helper).to receive(:can?).and_return(true)
end
- subject { helper.vue_ide_link_data(project, sha) }
+ subject { helper.web_ide_button_data(blob: blob) }
it 'returns a list of attributes related to the project' do
expect(subject).to include(
- ide_base_path: project.full_path,
+ project_path: project.full_path,
+ ref: sha,
+
+ is_fork: false,
needs_to_fork: false,
+ gitpod_enabled: false,
+ is_blob: false,
+
+ show_edit_button: false,
show_web_ide_button: true,
show_gitpod_button: false,
- gitpod_url: "",
- gitpod_enabled: nil
+
+ edit_url: '',
+ web_ide_url: "/-/ide/project/#{project.full_path}/edit/#{sha}",
+ gitpod_url: ''
)
end
+ context 'a blob is passed' do
+ before do
+ @path = 'README.md'
+ end
+
+ it 'returns edit url and webide url for the blob' do
+ expect(subject).to include(
+ show_edit_button: true,
+ edit_url: "/#{project.full_path}/-/edit/#{sha}/#{@path}",
+ web_ide_url: "/-/ide/project/#{project.full_path}/edit/#{sha}/-/#{@path}"
+ )
+ end
+ end
+
context 'user does not have write access but a personal fork exists' do
include ProjectForksHelper
let_it_be(:user) { create(:user) }
- let!(:forked_project) { create(:project, :repository, namespace: user.namespace) }
+ let(:forked_project) { create(:project, :repository, namespace: user.namespace) }
before do
project.add_guest(user)
@@ -200,9 +229,49 @@ RSpec.describe TreeHelper do
allow(helper).to receive(:current_user).and_return(user)
end
- it 'includes ide_base_path: forked_project.full_path' do
+ it 'includes forked project path as project_path' do
+ expect(subject).to include(
+ project_path: forked_project.full_path,
+ is_fork: true,
+ needs_to_fork: false,
+ show_edit_button: false,
+ web_ide_url: "/-/ide/project/#{forked_project.full_path}/edit/#{sha}"
+ )
+ end
+
+ context 'a blob is passed' do
+ before do
+ @path = 'README.md'
+ end
+
+ it 'returns edit url and web ide for the blob in the fork' do
+ expect(subject).to include(
+ is_blob: true,
+ show_edit_button: true,
+ # edit urls are automatically redirected to the fork
+ edit_url: "/#{project.full_path}/-/edit/#{sha}/#{@path}",
+ web_ide_url: "/-/ide/project/#{forked_project.full_path}/edit/#{sha}/-/#{@path}"
+ )
+ end
+ end
+ end
+
+ context 'for archived project' do
+ before do
+ allow(helper).to receive(:can_collaborate_with_project?).and_return(false)
+ allow(helper).to receive(:can?).and_return(false)
+
+ project.update!(archived: true)
+
+ @path = 'README.md'
+ end
+
+ it 'does not show any buttons' do
expect(subject).to include(
- ide_base_path: forked_project.full_path
+ is_blob: true,
+ show_edit_button: false,
+ show_web_ide_button: false,
+ show_gitpod_button: false
)
end
end
@@ -216,11 +285,32 @@ RSpec.describe TreeHelper do
allow(helper).to receive(:current_user).and_return(user)
end
- it 'includes ide_base_path: project.full_path' do
+ it 'includes original project path as project_path' do
expect(subject).to include(
- ide_base_path: project.full_path
+ project_path: project.full_path,
+
+ is_fork: false,
+ needs_to_fork: false,
+
+ show_edit_button: false,
+ web_ide_url: "/-/ide/project/#{project.full_path}/edit/#{sha}"
)
end
+
+ context 'a blob is passed' do
+ before do
+ @path = 'README.md'
+ end
+
+ it 'returns edit url and web ide for the blob in the fork' do
+ expect(subject).to include(
+ is_blob: true,
+ show_edit_button: true,
+ edit_url: "/#{project.full_path}/-/edit/#{sha}/#{@path}",
+ web_ide_url: "/-/ide/project/#{project.full_path}/edit/#{sha}/-/#{@path}"
+ )
+ end
+ end
end
context 'gitpod feature is enabled' do
diff --git a/spec/helpers/user_callouts_helper_spec.rb b/spec/helpers/user_callouts_helper_spec.rb
index a42be3c87fb..bcb0b5c51e7 100644
--- a/spec/helpers/user_callouts_helper_spec.rb
+++ b/spec/helpers/user_callouts_helper_spec.rb
@@ -139,4 +139,26 @@ RSpec.describe UserCalloutsHelper do
helper.render_flash_user_callout(:warning, 'foo', 'bar')
end
end
+
+ describe '.show_feature_flags_new_version?' do
+ subject { helper.show_feature_flags_new_version? }
+
+ let(:user) { create(:user) }
+
+ before do
+ allow(helper).to receive(:current_user).and_return(user)
+ end
+
+ context 'when the feature flags new version info has not been dismissed' do
+ it { is_expected.to be_truthy }
+ end
+
+ context 'when the feature flags new version has been dismissed' do
+ before do
+ create(:user_callout, user: user, feature_name: described_class::FEATURE_FLAGS_NEW_VERSION)
+ end
+
+ it { is_expected.to be_falsy }
+ end
+ end
end
diff --git a/spec/helpers/users_helper_spec.rb b/spec/helpers/users_helper_spec.rb
index 8dfdb23c64b..c9dc3fcff3f 100644
--- a/spec/helpers/users_helper_spec.rb
+++ b/spec/helpers/users_helper_spec.rb
@@ -126,6 +126,16 @@ RSpec.describe UsersHelper do
end
end
+ context 'with a pending approval user' do
+ it 'returns the pending approval badge' do
+ blocked_pending_approval_user = create(:user, :blocked_pending_approval)
+
+ badges = helper.user_badges_in_admin_section(blocked_pending_approval_user)
+
+ expect(filter_ee_badges(badges)).to eq([text: 'Pending approval', variant: 'info'])
+ end
+ end
+
context 'with an admin user' do
it "returns the admin badge" do
admin_user = create(:admin)
@@ -179,6 +189,20 @@ RSpec.describe UsersHelper do
end
end
+ describe '#can_force_email_confirmation?' do
+ subject { helper.can_force_email_confirmation?(user) }
+
+ context 'for a user that is already confirmed' do
+ it { is_expected.to eq(false) }
+ end
+
+ context 'for a user that is not confirmed' do
+ let(:user) { create(:user, :unconfirmed) }
+
+ it { is_expected.to eq(true) }
+ end
+ end
+
describe '#work_information' do
subject { helper.work_information(user) }
diff --git a/spec/helpers/visibility_level_helper_spec.rb b/spec/helpers/visibility_level_helper_spec.rb
index 7ef911131ba..cd1fc70bbc1 100644
--- a/spec/helpers/visibility_level_helper_spec.rb
+++ b/spec/helpers/visibility_level_helper_spec.rb
@@ -47,13 +47,6 @@ RSpec.describe VisibilityLevelHelper do
.to match /group/i
end
end
-
- context 'called with a Snippet' do
- it 'delegates snippets to #snippet_visibility_level_description' do
- expect(visibility_level_description(Gitlab::VisibilityLevel::INTERNAL, project_snippet))
- .to match /snippet/i
- end
- end
end
describe "#project_visibility_level_description" do
@@ -68,23 +61,6 @@ RSpec.describe VisibilityLevelHelper do
end
end
- describe "#snippet_visibility_level_description" do
- it 'describes visibility only for me' do
- expect(snippet_visibility_level_description(Gitlab::VisibilityLevel::PRIVATE, personal_snippet))
- .to eq _('The snippet is visible only to me.')
- end
-
- it 'describes visibility for project members' do
- expect(snippet_visibility_level_description(Gitlab::VisibilityLevel::PRIVATE, project_snippet))
- .to eq _('The snippet is visible only to project members.')
- end
-
- it 'defaults to personal snippet' do
- expect(snippet_visibility_level_description(Gitlab::VisibilityLevel::PRIVATE))
- .to eq _('The snippet is visible only to me.')
- end
- end
-
describe "disallowed_visibility_level?" do
describe "forks" do
let(:project) { create(:project, :internal) }
diff --git a/spec/helpers/whats_new_helper_spec.rb b/spec/helpers/whats_new_helper_spec.rb
index db880163454..80d4ca8ddea 100644
--- a/spec/helpers/whats_new_helper_spec.rb
+++ b/spec/helpers/whats_new_helper_spec.rb
@@ -3,20 +3,49 @@
require 'spec_helper'
RSpec.describe WhatsNewHelper do
- describe '#whats_new_most_recent_release_items' do
- let(:fixture_dir_glob) { Dir.glob(File.join('spec', 'fixtures', 'whats_new', '*.yml')) }
+ describe '#whats_new_storage_key' do
+ subject { helper.whats_new_storage_key }
- it 'returns json from the most recent file' do
- allow(Dir).to receive(:glob).with(Rails.root.join('data', 'whats_new', '*.yml')).and_return(fixture_dir_glob)
+ before do
+ allow(helper).to receive(:whats_new_most_recent_version).and_return(version)
+ end
+
+ context 'when version exist' do
+ let(:version) { '84.0' }
+
+ it { is_expected.to eq('display-whats-new-notification-84.0') }
+ end
+
+ context 'when recent release items do NOT exist' do
+ let(:version) { nil }
+
+ it { is_expected.to be_nil }
+ end
+ end
+
+ describe '#whats_new_most_recent_release_items_count' do
+ subject { helper.whats_new_most_recent_release_items_count }
- expect(helper.whats_new_most_recent_release_items).to include({ title: "bright and sunshinin' day" }.to_json)
+ context 'when recent release items exist' do
+ let(:fixture_dir_glob) { Dir.glob(File.join('spec', 'fixtures', 'whats_new', '*.yml')) }
+
+ it 'returns the count from the most recent file' do
+ expect(Dir).to receive(:glob).with(Rails.root.join('data', 'whats_new', '*.yml')).and_return(fixture_dir_glob)
+
+ expect(subject).to eq(1)
+ end
end
- it 'fails gracefully and logs an error' do
- allow(YAML).to receive(:load_file).and_raise
+ context 'when recent release items do NOT exist' do
+ before do
+ allow(YAML).to receive(:safe_load).and_raise
+
+ expect(Gitlab::ErrorTracking).to receive(:track_exception)
+ end
- expect(Gitlab::ErrorTracking).to receive(:track_exception)
- expect(helper.whats_new_most_recent_release_items).to eq(''.to_json)
+ it 'fails gracefully and logs an error' do
+ expect(subject).to be_nil
+ end
end
end
end
diff --git a/spec/helpers/wiki_helper_spec.rb b/spec/helpers/wiki_helper_spec.rb
index 65a52412f8c..45e1859893f 100644
--- a/spec/helpers/wiki_helper_spec.rb
+++ b/spec/helpers/wiki_helper_spec.rb
@@ -54,14 +54,18 @@ RSpec.describe WikiHelper do
end
describe '#wiki_attachment_upload_url' do
- it 'returns the upload endpoint for project wikis' do
- @wiki = build_stubbed(:project_wiki)
+ let_it_be(:wiki) { build_stubbed(:project_wiki) }
+
+ before do
+ @wiki = wiki
+ end
+ it 'returns the upload endpoint for project wikis' do
expect(helper.wiki_attachment_upload_url).to end_with("/api/v4/projects/#{@wiki.project.id}/wikis/attachments")
end
it 'raises an exception for unsupported wiki containers' do
- @wiki = Wiki.new(User.new)
+ allow(wiki).to receive(:container).and_return(User.new)
expect do
helper.wiki_attachment_upload_url
@@ -131,7 +135,8 @@ RSpec.describe WikiHelper do
'wiki-format' => :markdown,
'wiki-title-size' => 9,
'wiki-content-size' => 4,
- 'wiki-directory-nest-level' => 2
+ 'wiki-directory-nest-level' => 2,
+ 'wiki-container-type' => 'Project'
)
end
diff --git a/spec/initializers/sidekiq_spec.rb b/spec/initializers/sidekiq_spec.rb
new file mode 100644
index 00000000000..e34f59c3427
--- /dev/null
+++ b/spec/initializers/sidekiq_spec.rb
@@ -0,0 +1,45 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'sidekiq' do
+ describe 'enable_reliable_fetch?' do
+ subject { enable_reliable_fetch? }
+
+ context 'when gitlab_sidekiq_reliable_fetcher is enabled' do
+ before do
+ stub_feature_flags(gitlab_sidekiq_reliable_fetcher: true)
+ end
+
+ it { is_expected.to be_truthy }
+ end
+
+ context 'when gitlab_sidekiq_reliable_fetcher is disabled' do
+ before do
+ stub_feature_flags(gitlab_sidekiq_reliable_fetcher: false)
+ end
+
+ it { is_expected.to be_falsey }
+ end
+ end
+
+ describe 'enable_semi_reliable_fetch_mode?' do
+ subject { enable_semi_reliable_fetch_mode? }
+
+ context 'when gitlab_sidekiq_enable_semi_reliable_fetcher is enabled' do
+ before do
+ stub_feature_flags(gitlab_sidekiq_enable_semi_reliable_fetcher: true)
+ end
+
+ it { is_expected.to be_truthy }
+ end
+
+ context 'when gitlab_sidekiq_enable_semi_reliable_fetcher is disabled' do
+ before do
+ stub_feature_flags(gitlab_sidekiq_enable_semi_reliable_fetcher: false)
+ end
+
+ it { is_expected.to be_falsey }
+ end
+ end
+end
diff --git a/spec/lib/api/entities/snippet_spec.rb b/spec/lib/api/entities/snippet_spec.rb
index 068851f7f6c..090f09c9b61 100644
--- a/spec/lib/api/entities/snippet_spec.rb
+++ b/spec/lib/api/entities/snippet_spec.rb
@@ -21,16 +21,6 @@ RSpec.describe ::API::Entities::Snippet do
it { expect(subject[:visibility]).to eq snippet.visibility }
it { expect(subject).to include(:author) }
- context 'with snippet_multiple_files feature disabled' do
- before do
- stub_feature_flags(snippet_multiple_files: false)
- end
-
- it 'does not return files' do
- expect(subject).not_to include(:files)
- end
- end
-
describe 'file_name' do
it 'returns attribute from repository' do
expect(subject[:file_name]).to eq snippet.blobs.first.path
@@ -77,14 +67,6 @@ RSpec.describe ::API::Entities::Snippet do
let(:blob) { snippet.blobs.first }
let(:ref) { blob.repository.root_ref }
- context 'when repository does not exist' do
- it 'does not include the files attribute' do
- allow(snippet).to receive(:repository_exists?).and_return(false)
-
- expect(subject).not_to include(:files)
- end
- end
-
shared_examples 'snippet files' do
let(:file) { subject[:files].first }
@@ -99,6 +81,14 @@ RSpec.describe ::API::Entities::Snippet do
it 'has the raw url' do
expect(file[:raw_url]).to match(raw_url)
end
+
+ context 'when repository does not exist' do
+ it 'returns empty array' do
+ allow(snippet.repository).to receive(:empty?).and_return(true)
+
+ expect(subject[:files]).to be_empty
+ end
+ end
end
context 'with PersonalSnippet' do
diff --git a/spec/lib/api/github/entities_spec.rb b/spec/lib/api/github/entities_spec.rb
new file mode 100644
index 00000000000..00ea60c5d65
--- /dev/null
+++ b/spec/lib/api/github/entities_spec.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe API::Github::Entities do
+ describe API::Github::Entities::User do
+ let(:user) { create(:user, username: username) }
+ let(:username) { 'name_of_user' }
+ let(:gitlab_protocol_and_host) { "#{Gitlab.config.gitlab.protocol}://#{Gitlab.config.gitlab.host}" }
+ let(:expected_user_url) { "#{gitlab_protocol_and_host}/#{username}" }
+ let(:entity) { described_class.new(user) }
+
+ subject { entity.as_json }
+
+ specify :aggregate_failure do
+ expect(subject[:id]).to eq user.id
+ expect(subject[:login]).to eq 'name_of_user'
+ expect(subject[:url]).to eq expected_user_url
+ expect(subject[:html_url]).to eq expected_user_url
+ expect(subject[:avatar_url]).to include('https://www.gravatar.com/avatar')
+ end
+
+ context 'with avatar' do
+ let(:user) { create(:user, :with_avatar, username: username) }
+
+ specify do
+ expect(subject[:avatar_url]).to include("#{gitlab_protocol_and_host}/uploads/-/system/user/avatar/")
+ end
+ end
+ 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 ccf96bcbad6..6d06fc3618d 100644
--- a/spec/lib/api/helpers/packages/dependency_proxy_helpers_spec.rb
+++ b/spec/lib/api/helpers/packages/dependency_proxy_helpers_spec.rb
@@ -24,6 +24,7 @@ RSpec.describe API::Helpers::Packages::DependencyProxyHelpers do
shared_examples 'executing redirect' do
it 'redirects to package registry' do
+ expect(helper).to receive(:track_event).with('npm_request_forward').once
expect(helper).to receive(:registry_url).once
expect(helper).to receive(:redirect).once
expect(helper).to receive(:fallback).never
@@ -63,6 +64,7 @@ RSpec.describe API::Helpers::Packages::DependencyProxyHelpers do
let(:package_type) { pkg_type }
it 'raises an error' do
+ allow(helper).to receive(:track_event)
expect { subject }.to raise_error(ArgumentError, "Can't build registry_url for package_type #{package_type}")
end
end
diff --git a/spec/lib/api/helpers_spec.rb b/spec/lib/api/helpers_spec.rb
index 51a45dff6a4..8e738af0fa3 100644
--- a/spec/lib/api/helpers_spec.rb
+++ b/spec/lib/api/helpers_spec.rb
@@ -191,41 +191,32 @@ RSpec.describe API::Helpers do
describe '#increment_unique_values' do
let(:value) { '9f302fea-f828-4ca9-aef4-e10bd723c0b3' }
- let(:event_name) { 'my_event' }
+ let(:event_name) { 'g_compliance_dashboard' }
let(:unknown_event) { 'unknown' }
let(:feature) { "usage_data_#{event_name}" }
+ before do
+ skip_feature_flags_yaml_validation
+ end
+
context 'with feature enabled' do
before do
stub_feature_flags(feature => true)
end
it 'tracks redis hll event' do
- stub_application_setting(usage_ping_enabled: true)
-
expect(Gitlab::UsageDataCounters::HLLRedisCounter).to receive(:track_event).with(value, event_name)
subject.increment_unique_values(event_name, value)
end
- it 'does not track event usage ping is not enabled' do
- stub_application_setting(usage_ping_enabled: false)
- expect(Gitlab::UsageDataCounters::HLLRedisCounter).not_to receive(:track_event)
-
- subject.increment_unique_values(event_name, value)
- end
-
it 'logs an exception for unknown event' do
- stub_application_setting(usage_ping_enabled: true)
-
expect(Gitlab::AppLogger).to receive(:warn).with("Redis tracking event failed for event: #{unknown_event}, message: Unknown event #{unknown_event}")
subject.increment_unique_values(unknown_event, value)
end
it 'does not track event for nil values' do
- stub_application_setting(usage_ping_enabled: true)
-
expect(Gitlab::UsageDataCounters::HLLRedisCounter).not_to receive(:track_event)
subject.increment_unique_values(unknown_event, nil)
diff --git a/spec/lib/backup/files_spec.rb b/spec/lib/backup/files_spec.rb
index c2dbaac7f15..45cc73974d6 100644
--- a/spec/lib/backup/files_spec.rb
+++ b/spec/lib/backup/files_spec.rb
@@ -30,7 +30,7 @@ RSpec.describe Backup::Files do
let(:timestamp) { Time.utc(2017, 3, 22) }
around do |example|
- Timecop.freeze(timestamp) { example.run }
+ travel_to(timestamp) { example.run }
end
describe 'folders with permission' do
diff --git a/spec/lib/backup/repositories_spec.rb b/spec/lib/backup/repositories_spec.rb
new file mode 100644
index 00000000000..9c139e9f954
--- /dev/null
+++ b/spec/lib/backup/repositories_spec.rb
@@ -0,0 +1,308 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Backup::Repositories do
+ let(:progress) { StringIO.new }
+
+ subject { described_class.new(progress) }
+
+ before do
+ allow(progress).to receive(:puts)
+ allow(progress).to receive(:print)
+
+ allow_next_instance_of(described_class) do |instance|
+ allow(instance).to receive(:progress).and_return(progress)
+ end
+ end
+
+ describe '#dump' do
+ let_it_be(:projects) { create_list(:project, 5, :repository) }
+
+ RSpec.shared_examples 'creates repository bundles' do
+ specify :aggregate_failures do
+ # Add data to the wiki, design repositories, and snippets, so they will be included in the dump.
+ create(:wiki_page, container: project)
+ create(:design, :with_file, issue: create(:issue, project: project))
+ project_snippet = create(:project_snippet, :repository, project: project)
+ personal_snippet = create(:personal_snippet, :repository, author: project.owner)
+
+ subject.dump(max_concurrency: 1, max_storage_concurrency: 1)
+
+ expect(File).to exist(File.join(Gitlab.config.backup.path, 'repositories', project.disk_path + '.bundle'))
+ expect(File).to exist(File.join(Gitlab.config.backup.path, 'repositories', project.disk_path + '.wiki' + '.bundle'))
+ expect(File).to exist(File.join(Gitlab.config.backup.path, 'repositories', project.disk_path + '.design' + '.bundle'))
+ expect(File).to exist(File.join(Gitlab.config.backup.path, 'repositories', personal_snippet.disk_path + '.bundle'))
+ expect(File).to exist(File.join(Gitlab.config.backup.path, 'repositories', project_snippet.disk_path + '.bundle'))
+ end
+ end
+
+ context 'hashed storage' do
+ let_it_be(:project) { create(:project, :repository) }
+
+ it_behaves_like 'creates repository bundles'
+ end
+
+ context 'legacy storage' do
+ let_it_be(:project) { create(:project, :repository, :legacy_storage) }
+
+ it_behaves_like 'creates repository bundles'
+ end
+
+ context 'no concurrency' do
+ it 'creates the expected number of threads' do
+ expect(Thread).not_to receive(:new)
+
+ projects.each do |project|
+ expect(subject).to receive(:dump_project).with(project).and_call_original
+ end
+
+ subject.dump(max_concurrency: 1, max_storage_concurrency: 1)
+ end
+
+ describe 'command failure' do
+ it 'dump_project raises an error' do
+ allow(subject).to receive(:dump_project).and_raise(IOError)
+
+ expect { subject.dump(max_concurrency: 1, max_storage_concurrency: 1) }.to raise_error(IOError)
+ end
+
+ it 'project query raises an error' do
+ allow(Project).to receive_message_chain(:includes, :find_each).and_raise(ActiveRecord::StatementTimeout)
+
+ expect { subject.dump(max_concurrency: 1, max_storage_concurrency: 1) }.to raise_error(ActiveRecord::StatementTimeout)
+ end
+ end
+
+ it 'avoids N+1 database queries' do
+ control_count = ActiveRecord::QueryRecorder.new do
+ subject.dump(max_concurrency: 1, max_storage_concurrency: 1)
+ end.count
+
+ create_list(:project, 2, :repository)
+
+ expect do
+ subject.dump(max_concurrency: 1, max_storage_concurrency: 1)
+ end.not_to exceed_query_limit(control_count)
+ end
+ end
+
+ [4, 10].each do |max_storage_concurrency|
+ context "max_storage_concurrency #{max_storage_concurrency}", quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/241701' do
+ let(:storage_keys) { %w[default test_second_storage] }
+
+ before do
+ allow(Gitlab.config.repositories.storages).to receive(:keys).and_return(storage_keys)
+ end
+
+ it 'creates the expected number of threads' do
+ expect(Thread).to receive(:new)
+ .exactly(storage_keys.length * (max_storage_concurrency + 1)).times
+ .and_call_original
+
+ projects.each do |project|
+ expect(subject).to receive(:dump_project).with(project).and_call_original
+ end
+
+ subject.dump(max_concurrency: 1, max_storage_concurrency: max_storage_concurrency)
+ end
+
+ it 'creates the expected number of threads with extra max concurrency' do
+ expect(Thread).to receive(:new)
+ .exactly(storage_keys.length * (max_storage_concurrency + 1)).times
+ .and_call_original
+
+ projects.each do |project|
+ expect(subject).to receive(:dump_project).with(project).and_call_original
+ end
+
+ subject.dump(max_concurrency: 3, max_storage_concurrency: max_storage_concurrency)
+ end
+
+ describe 'command failure' do
+ it 'dump_project raises an error' do
+ allow(subject).to receive(:dump_project)
+ .and_raise(IOError)
+
+ expect { subject.dump(max_concurrency: 1, max_storage_concurrency: max_storage_concurrency) }.to raise_error(IOError)
+ end
+
+ it 'project query raises an error' do
+ allow(Project).to receive_message_chain(:for_repository_storage, :includes, :find_each).and_raise(ActiveRecord::StatementTimeout)
+
+ expect { subject.dump(max_concurrency: 1, max_storage_concurrency: max_storage_concurrency) }.to raise_error(ActiveRecord::StatementTimeout)
+ end
+
+ context 'misconfigured storages' do
+ let(:storage_keys) { %w[test_second_storage] }
+
+ it 'raises an error' do
+ expect { subject.dump(max_concurrency: 1, max_storage_concurrency: max_storage_concurrency) }.to raise_error(Backup::Error, 'repositories.storages in gitlab.yml is misconfigured')
+ end
+ end
+ end
+
+ it 'avoids N+1 database queries' do
+ control_count = ActiveRecord::QueryRecorder.new do
+ subject.dump(max_concurrency: 1, max_storage_concurrency: max_storage_concurrency)
+ end.count
+
+ create_list(:project, 2, :repository)
+
+ expect do
+ subject.dump(max_concurrency: 1, max_storage_concurrency: max_storage_concurrency)
+ end.not_to exceed_query_limit(control_count)
+ end
+ end
+ end
+ end
+
+ describe '#restore' do
+ let_it_be(:project) { create(:project) }
+ let_it_be(:personal_snippet) { create(:personal_snippet, author: project.owner) }
+ let_it_be(:project_snippet) { create(:project_snippet, project: project, author: project.owner) }
+
+ let(:next_path_to_bundle) do
+ [
+ Rails.root.join('spec/fixtures/lib/backup/project_repo.bundle'),
+ Rails.root.join('spec/fixtures/lib/backup/wiki_repo.bundle'),
+ Rails.root.join('spec/fixtures/lib/backup/design_repo.bundle'),
+ Rails.root.join('spec/fixtures/lib/backup/personal_snippet_repo.bundle'),
+ Rails.root.join('spec/fixtures/lib/backup/project_snippet_repo.bundle')
+ ].to_enum
+ end
+
+ it 'restores repositories from bundles', :aggregate_failures do
+ allow_next_instance_of(described_class::BackupRestore) do |backup_restore|
+ allow(backup_restore).to receive(:path_to_bundle).and_return(next_path_to_bundle.next)
+ end
+
+ subject.restore
+
+ collect_commit_shas = -> (repo) { repo.commits('master', limit: 10).map(&:sha) }
+
+ expect(collect_commit_shas.call(project.repository)).to eq(['393a7d860a5a4c3cc736d7eb00604e3472bb95ec'])
+ expect(collect_commit_shas.call(project.wiki.repository)).to eq(['c74b9948d0088d703ee1fafeddd9ed9add2901ea'])
+ expect(collect_commit_shas.call(project.design_repository)).to eq(['c3cd4d7bd73a51a0f22045c3a4c871c435dc959d'])
+ expect(collect_commit_shas.call(personal_snippet.repository)).to eq(['3b3c067a3bc1d1b695b51e2be30c0f8cf698a06e'])
+ expect(collect_commit_shas.call(project_snippet.repository)).to eq(['6e44ba56a4748be361a841e759c20e421a1651a1'])
+ end
+
+ describe 'command failure' do
+ before do
+ expect(Project).to receive(:find_each).and_yield(project)
+
+ allow_next_instance_of(DesignManagement::Repository) do |repository|
+ allow(repository).to receive(:create_repository) { raise 'Fail in tests' }
+ end
+ allow_next_instance_of(Repository) do |repository|
+ allow(repository).to receive(:create_repository) { raise 'Fail in tests' }
+ end
+ end
+
+ context 'hashed storage' do
+ it 'shows the appropriate error' do
+ subject.restore
+
+ expect(progress).to have_received(:puts).with("[Failed] restoring #{project.full_path} (#{project.disk_path})")
+ end
+ end
+
+ context 'legacy storage' do
+ let_it_be(:project) { create(:project, :legacy_storage) }
+
+ it 'shows the appropriate error' do
+ subject.restore
+
+ expect(progress).to have_received(:puts).with("[Failed] restoring #{project.full_path} (#{project.disk_path})")
+ end
+ end
+ end
+
+ context 'restoring object pools' do
+ it 'schedules restoring of the pool', :sidekiq_might_not_need_inline do
+ pool_repository = create(:pool_repository, :failed)
+ pool_repository.delete_object_pool
+
+ subject.restore
+
+ pool_repository.reload
+ expect(pool_repository).not_to be_failed
+ expect(pool_repository.object_pool.exists?).to be(true)
+ end
+ end
+
+ it 'cleans existing repositories' do
+ success_response = ServiceResponse.success(message: "Valid Snippet Repo")
+ allow(Snippets::RepositoryValidationService).to receive_message_chain(:new, :execute).and_return(success_response)
+
+ expect_next_instance_of(DesignManagement::Repository) do |repository|
+ expect(repository).to receive(:remove)
+ end
+
+ # 4 times = project repo + wiki repo + project_snippet repo + personal_snippet repo
+ expect(Repository).to receive(:new).exactly(4).times.and_wrap_original do |method, *original_args|
+ repository = method.call(*original_args)
+
+ expect(repository).to receive(:remove)
+
+ repository
+ end
+
+ subject.restore
+ end
+
+ context 'restoring snippets' do
+ before do
+ create(:snippet_repository, snippet: personal_snippet)
+ create(:snippet_repository, snippet: project_snippet)
+
+ allow_next_instance_of(described_class::BackupRestore) do |backup_restore|
+ allow(backup_restore).to receive(:path_to_bundle).and_return(next_path_to_bundle.next)
+ end
+ end
+
+ context 'when the repository is valid' do
+ it 'restores the snippet repositories' do
+ subject.restore
+
+ expect(personal_snippet.snippet_repository.persisted?).to be true
+ expect(personal_snippet.repository).to exist
+
+ expect(project_snippet.snippet_repository.persisted?).to be true
+ expect(project_snippet.repository).to exist
+ end
+ end
+
+ context 'when repository is invalid' do
+ before do
+ error_response = ServiceResponse.error(message: "Repository has more than one branch")
+ allow(Snippets::RepositoryValidationService).to receive_message_chain(:new, :execute).and_return(error_response)
+ end
+
+ it 'shows the appropriate error' do
+ subject.restore
+
+ expect(progress).to have_received(:puts).with("Snippet #{personal_snippet.full_path} can't be restored: Repository has more than one branch")
+ expect(progress).to have_received(:puts).with("Snippet #{project_snippet.full_path} can't be restored: Repository has more than one branch")
+ end
+
+ it 'removes the snippets from the DB' do
+ expect { subject.restore }.to change(PersonalSnippet, :count).by(-1)
+ .and change(ProjectSnippet, :count).by(-1)
+ .and change(SnippetRepository, :count).by(-2)
+ end
+
+ it 'removes the repository from disk' do
+ gitlab_shell = Gitlab::Shell.new
+ shard_name = personal_snippet.repository.shard
+ path = personal_snippet.disk_path + '.git'
+
+ subject.restore
+
+ expect(gitlab_shell.repository_exists?(shard_name, path)).to eq false
+ end
+ end
+ end
+ end
+end
diff --git a/spec/lib/backup/repository_spec.rb b/spec/lib/backup/repository_spec.rb
deleted file mode 100644
index 718f38f9452..00000000000
--- a/spec/lib/backup/repository_spec.rb
+++ /dev/null
@@ -1,232 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Backup::Repository do
- let_it_be(:project) { create(:project, :wiki_repo) }
-
- let(:progress) { StringIO.new }
-
- subject { described_class.new(progress) }
-
- before do
- allow(progress).to receive(:puts)
- allow(progress).to receive(:print)
- allow(FileUtils).to receive(:mv).and_return(true)
-
- allow_next_instance_of(described_class) do |instance|
- allow(instance).to receive(:progress).and_return(progress)
- end
- end
-
- describe '#dump' do
- before do
- allow(Gitlab.config.repositories.storages).to receive(:keys).and_return(storage_keys)
- end
-
- let_it_be(:projects) { create_list(:project, 5, :wiki_repo) + [project] }
-
- let(:storage_keys) { %w[default test_second_storage] }
-
- context 'no concurrency' do
- it 'creates the expected number of threads' do
- expect(Thread).not_to receive(:new)
-
- projects.each do |project|
- expect(subject).to receive(:dump_project).with(project).and_call_original
- end
-
- subject.dump(max_concurrency: 1, max_storage_concurrency: 1)
- end
-
- describe 'command failure' do
- it 'dump_project raises an error' do
- allow(subject).to receive(:dump_project).and_raise(IOError)
-
- expect { subject.dump(max_concurrency: 1, max_storage_concurrency: 1) }.to raise_error(IOError)
- end
-
- it 'project query raises an error' do
- allow(Project).to receive_message_chain(:includes, :find_each).and_raise(ActiveRecord::StatementTimeout)
-
- expect { subject.dump(max_concurrency: 1, max_storage_concurrency: 1) }.to raise_error(ActiveRecord::StatementTimeout)
- end
- end
-
- it 'avoids N+1 database queries' do
- control_count = ActiveRecord::QueryRecorder.new do
- subject.dump(max_concurrency: 1, max_storage_concurrency: 1)
- end.count
-
- create_list(:project, 2, :wiki_repo)
-
- expect do
- subject.dump(max_concurrency: 1, max_storage_concurrency: 1)
- end.not_to exceed_query_limit(control_count)
- end
- end
-
- [4, 10].each do |max_storage_concurrency|
- context "max_storage_concurrency #{max_storage_concurrency}", quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/241701' do
- it 'creates the expected number of threads' do
- expect(Thread).to receive(:new)
- .exactly(storage_keys.length * (max_storage_concurrency + 1)).times
- .and_call_original
-
- projects.each do |project|
- expect(subject).to receive(:dump_project).with(project).and_call_original
- end
-
- subject.dump(max_concurrency: 1, max_storage_concurrency: max_storage_concurrency)
- end
-
- it 'creates the expected number of threads with extra max concurrency' do
- expect(Thread).to receive(:new)
- .exactly(storage_keys.length * (max_storage_concurrency + 1)).times
- .and_call_original
-
- projects.each do |project|
- expect(subject).to receive(:dump_project).with(project).and_call_original
- end
-
- subject.dump(max_concurrency: 3, max_storage_concurrency: max_storage_concurrency)
- end
-
- describe 'command failure' do
- it 'dump_project raises an error' do
- allow(subject).to receive(:dump_project)
- .and_raise(IOError)
-
- expect { subject.dump(max_concurrency: 1, max_storage_concurrency: max_storage_concurrency) }.to raise_error(IOError)
- end
-
- it 'project query raises an error' do
- allow(Project).to receive_message_chain(:for_repository_storage, :includes, :find_each).and_raise(ActiveRecord::StatementTimeout)
-
- expect { subject.dump(max_concurrency: 1, max_storage_concurrency: max_storage_concurrency) }.to raise_error(ActiveRecord::StatementTimeout)
- end
-
- context 'misconfigured storages' do
- let(:storage_keys) { %w[test_second_storage] }
-
- it 'raises an error' do
- expect { subject.dump(max_concurrency: 1, max_storage_concurrency: max_storage_concurrency) }.to raise_error(Backup::Error, 'repositories.storages in gitlab.yml is misconfigured')
- end
- end
- end
-
- it 'avoids N+1 database queries' do
- control_count = ActiveRecord::QueryRecorder.new do
- subject.dump(max_concurrency: 1, max_storage_concurrency: max_storage_concurrency)
- end.count
-
- create_list(:project, 2, :wiki_repo)
-
- expect do
- subject.dump(max_concurrency: 1, max_storage_concurrency: max_storage_concurrency)
- end.not_to exceed_query_limit(control_count)
- end
- end
- end
- end
-
- describe '#restore' do
- let(:timestamp) { Time.utc(2017, 3, 22) }
- let(:temp_dirs) do
- Gitlab.config.repositories.storages.map do |name, storage|
- Gitlab::GitalyClient::StorageSettings.allow_disk_access do
- File.join(storage.legacy_disk_path, '..', 'repositories.old.' + timestamp.to_i.to_s)
- end
- end
- end
-
- around do |example|
- Timecop.freeze(timestamp) { example.run }
- end
-
- after do
- temp_dirs.each { |path| FileUtils.rm_rf(path) }
- end
-
- describe 'command failure' do
- before do
- # Allow us to set expectations on the project directly
- expect(Project).to receive(:find_each).and_yield(project)
- expect(project.repository).to receive(:create_repository) { raise 'Fail in tests' }
- end
-
- context 'hashed storage' do
- it 'shows the appropriate error' do
- subject.restore
-
- expect(progress).to have_received(:puts).with("[Failed] restoring #{project.full_path} repository")
- end
- end
-
- context 'legacy storage' do
- let!(:project) { create(:project, :legacy_storage) }
-
- it 'shows the appropriate error' do
- subject.restore
-
- expect(progress).to have_received(:puts).with("[Failed] restoring #{project.full_path} repository")
- end
- end
- end
-
- context 'restoring object pools' do
- it 'schedules restoring of the pool', :sidekiq_might_not_need_inline do
- pool_repository = create(:pool_repository, :failed)
- pool_repository.delete_object_pool
-
- subject.restore
-
- pool_repository.reload
- expect(pool_repository).not_to be_failed
- expect(pool_repository.object_pool.exists?).to be(true)
- end
- end
-
- it 'cleans existing repositories' do
- wiki_repository_spy = spy(:wiki)
-
- allow_next_instance_of(ProjectWiki) do |project_wiki|
- allow(project_wiki).to receive(:repository).and_return(wiki_repository_spy)
- end
-
- expect_next_instance_of(Repository) do |repo|
- expect(repo).to receive(:remove)
- end
-
- subject.restore
-
- expect(wiki_repository_spy).to have_received(:remove)
- end
- end
-
- describe '#empty_repo?' do
- context 'for a wiki' do
- let(:wiki) { create(:project_wiki) }
-
- it 'invalidates the emptiness cache' do
- expect(wiki.repository).to receive(:expire_emptiness_caches).once
-
- subject.send(:empty_repo?, wiki)
- end
-
- context 'wiki repo has content' do
- let!(:wiki_page) { create(:wiki_page, wiki: wiki) }
-
- it 'returns true, regardless of bad cache value' do
- expect(subject.send(:empty_repo?, wiki)).to be(false)
- end
- end
-
- context 'wiki repo does not have content' do
- it 'returns true, regardless of bad cache value' do
- expect(subject.send(:empty_repo?, wiki)).to be_truthy
- end
- end
- end
- end
-end
diff --git a/spec/lib/banzai/filter/design_reference_filter_spec.rb b/spec/lib/banzai/filter/design_reference_filter_spec.rb
index 1b558754932..847c398964a 100644
--- a/spec/lib/banzai/filter/design_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/design_reference_filter_spec.rb
@@ -74,26 +74,6 @@ RSpec.describe Banzai::Filter::DesignReferenceFilter do
it_behaves_like 'a no-op filter'
end
-
- context 'design reference filter is not enabled' do
- before do
- stub_feature_flags(described_class::FEATURE_FLAG => false)
- end
-
- it_behaves_like 'a no-op filter'
-
- it 'issues no queries' do
- expect { process(input_text) }.not_to exceed_query_limit(0)
- end
- end
-
- context 'the filter is enabled for the context project' do
- before do
- stub_feature_flags(described_class::FEATURE_FLAG => project)
- end
-
- it_behaves_like 'a good link reference'
- end
end
end
diff --git a/spec/lib/banzai/filter/external_issue_reference_filter_spec.rb b/spec/lib/banzai/filter/external_issue_reference_filter_spec.rb
index e7b6c910b8a..35ef2abfa63 100644
--- a/spec/lib/banzai/filter/external_issue_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/external_issue_reference_filter_spec.rb
@@ -5,6 +5,8 @@ require 'spec_helper'
RSpec.describe Banzai::Filter::ExternalIssueReferenceFilter do
include FilterSpecHelper
+ let_it_be_with_refind(:project) { create(:project) }
+
shared_examples_for "external issue tracker" do
it_behaves_like 'a reference containing an element node'
@@ -116,7 +118,7 @@ RSpec.describe Banzai::Filter::ExternalIssueReferenceFilter do
end
context "redmine project" do
- let(:project) { create(:redmine_project) }
+ let_it_be(:service) { create(:redmine_service, project: project) }
before do
project.update!(issues_enabled: false)
@@ -138,7 +140,7 @@ RSpec.describe Banzai::Filter::ExternalIssueReferenceFilter do
end
context "youtrack project" do
- let(:project) { create(:youtrack_project) }
+ let_it_be(:service) { create(:youtrack_service, project: project) }
before do
project.update!(issues_enabled: false)
@@ -181,7 +183,7 @@ RSpec.describe Banzai::Filter::ExternalIssueReferenceFilter do
end
context "jira project" do
- let(:project) { create(:jira_project) }
+ let_it_be(:service) { create(:jira_service, project: project) }
let(:reference) { issue.to_reference }
context "with right markdown" do
@@ -210,7 +212,7 @@ RSpec.describe Banzai::Filter::ExternalIssueReferenceFilter do
end
context "ewm project" do
- let_it_be(:project) { create(:ewm_project) }
+ let_it_be(:service) { create(:ewm_service, project: project) }
before do
project.update!(issues_enabled: false)
diff --git a/spec/lib/banzai/filter/inline_grafana_metrics_filter_spec.rb b/spec/lib/banzai/filter/inline_grafana_metrics_filter_spec.rb
index 8bdb24ab08c..d29af311ee5 100644
--- a/spec/lib/banzai/filter/inline_grafana_metrics_filter_spec.rb
+++ b/spec/lib/banzai/filter/inline_grafana_metrics_filter_spec.rb
@@ -32,7 +32,7 @@ RSpec.describe Banzai::Filter::InlineGrafanaMetricsFilter do
it_behaves_like 'a metrics embed filter'
around do |example|
- Timecop.freeze(Time.utc(2019, 3, 17, 13, 10)) { example.run }
+ travel_to(Time.utc(2019, 3, 17, 13, 10)) { example.run }
end
context 'when grafana is not configured' do
diff --git a/spec/lib/banzai/filter/issue_reference_filter_spec.rb b/spec/lib/banzai/filter/issue_reference_filter_spec.rb
index 447802d18a7..4b8b575c1f0 100644
--- a/spec/lib/banzai/filter/issue_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/issue_reference_filter_spec.rb
@@ -296,6 +296,12 @@ RSpec.describe Banzai::Filter::IssueReferenceFilter do
.to eq reference
end
+ it 'link with trailing slash' do
+ doc = reference_filter("Fixed (#{issue_url + "/"}.)")
+
+ expect(doc.to_html).to match(%r{\(<a.+>#{Regexp.escape(issue.to_reference(project))}</a>\.\)})
+ end
+
it 'links with adjacent text' do
doc = reference_filter("Fixed (#{reference}.)")
diff --git a/spec/lib/banzai/filter/milestone_reference_filter_spec.rb b/spec/lib/banzai/filter/milestone_reference_filter_spec.rb
index 62b1711ee57..276fa7952be 100644
--- a/spec/lib/banzai/filter/milestone_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/milestone_reference_filter_spec.rb
@@ -5,9 +5,11 @@ require 'spec_helper'
RSpec.describe Banzai::Filter::MilestoneReferenceFilter do
include FilterSpecHelper
- let(:parent_group) { create(:group, :public) }
- let(:group) { create(:group, :public, parent: parent_group) }
- let(:project) { create(:project, :public, group: group) }
+ let_it_be(:parent_group) { create(:group, :public) }
+ let_it_be(:group) { create(:group, :public, parent: parent_group) }
+ let_it_be(:project) { create(:project, :public, group: group) }
+ let_it_be(:namespace) { create(:namespace) }
+ let_it_be(:another_project) { create(:project, :public, namespace: namespace) }
it 'requires project context' do
expect { described_class.call('') }.to raise_error(ArgumentError, /:project/)
@@ -188,11 +190,9 @@ RSpec.describe Banzai::Filter::MilestoneReferenceFilter do
end
shared_examples 'cross-project / cross-namespace complete reference' do
- let(:namespace) { create(:namespace) }
- let(:another_project) { create(:project, :public, namespace: namespace) }
- let(:milestone) { create(:milestone, project: another_project) }
- let(:reference) { "#{another_project.full_path}%#{milestone.iid}" }
- let!(:result) { reference_filter("See #{reference}") }
+ let_it_be(:milestone) { create(:milestone, project: another_project) }
+ let(:reference) { "#{another_project.full_path}%#{milestone.iid}" }
+ let!(:result) { reference_filter("See #{reference}") }
it 'points to referenced project milestone page' do
expect(result.css('a').first.attr('href')).to eq urls
@@ -226,12 +226,10 @@ RSpec.describe Banzai::Filter::MilestoneReferenceFilter do
end
shared_examples 'cross-project / same-namespace complete reference' do
- let(:namespace) { create(:namespace) }
- let(:project) { create(:project, :public, namespace: namespace) }
- let(:another_project) { create(:project, :public, namespace: namespace) }
- let(:milestone) { create(:milestone, project: another_project) }
- let(:reference) { "#{another_project.full_path}%#{milestone.iid}" }
- let!(:result) { reference_filter("See #{reference}") }
+ let_it_be(:project) { create(:project, :public, namespace: namespace) }
+ let_it_be(:milestone) { create(:milestone, project: another_project) }
+ let(:reference) { "#{another_project.full_path}%#{milestone.iid}" }
+ let!(:result) { reference_filter("See #{reference}") }
it 'points to referenced project milestone page' do
expect(result.css('a').first.attr('href')).to eq urls
@@ -265,12 +263,10 @@ RSpec.describe Banzai::Filter::MilestoneReferenceFilter do
end
shared_examples 'cross project shorthand reference' do
- let(:namespace) { create(:namespace) }
- let(:project) { create(:project, :public, namespace: namespace) }
- let(:another_project) { create(:project, :public, namespace: namespace) }
- let(:milestone) { create(:milestone, project: another_project) }
- let(:reference) { "#{another_project.path}%#{milestone.iid}" }
- let!(:result) { reference_filter("See #{reference}") }
+ let_it_be(:project) { create(:project, :public, namespace: namespace) }
+ let_it_be(:milestone) { create(:milestone, project: another_project) }
+ let(:reference) { "#{another_project.path}%#{milestone.iid}" }
+ let!(:result) { reference_filter("See #{reference}") }
it 'points to referenced project milestone page' do
expect(result.css('a').first.attr('href')).to eq urls
@@ -439,13 +435,13 @@ RSpec.describe Banzai::Filter::MilestoneReferenceFilter do
context 'when milestone is open' do
context 'project milestones' do
- let(:milestone) { create(:milestone, project: project) }
+ let_it_be_with_reload(:milestone) { create(:milestone, project: project) }
include_context 'project milestones'
end
context 'group milestones' do
- let(:milestone) { create(:milestone, group: group) }
+ let_it_be_with_reload(:milestone) { create(:milestone, group: group) }
include_context 'group milestones'
end
@@ -453,13 +449,13 @@ RSpec.describe Banzai::Filter::MilestoneReferenceFilter do
context 'when milestone is closed' do
context 'project milestones' do
- let(:milestone) { create(:milestone, :closed, project: project) }
+ let_it_be_with_reload(:milestone) { create(:milestone, :closed, project: project) }
include_context 'project milestones'
end
context 'group milestones' do
- let(:milestone) { create(:milestone, :closed, group: group) }
+ let_it_be_with_reload(:milestone) { create(:milestone, :closed, group: group) }
include_context 'group milestones'
end
diff --git a/spec/lib/banzai/reference_redactor_spec.rb b/spec/lib/banzai/reference_redactor_spec.rb
index de774267b81..668e427cfa2 100644
--- a/spec/lib/banzai/reference_redactor_spec.rb
+++ b/spec/lib/banzai/reference_redactor_spec.rb
@@ -182,5 +182,12 @@ RSpec.describe Banzai::ReferenceRedactor do
expect(redactor.nodes_visible_to_user([node])).to eq(Set.new([node]))
end
+
+ it 'handles invalid references gracefully' do
+ doc = Nokogiri::HTML.fragment('<a data-reference-type="some_invalid_type"></a>')
+ node = doc.children[0]
+
+ expect(redactor.nodes_visible_to_user([node])).to be_empty
+ end
end
end
diff --git a/spec/lib/feature/definition_spec.rb b/spec/lib/feature/definition_spec.rb
index 49224cf4279..fa0207d829a 100644
--- a/spec/lib/feature/definition_spec.rb
+++ b/spec/lib/feature/definition_spec.rb
@@ -105,6 +105,7 @@ RSpec.describe Feature::Definition do
describe '.load_all!' do
let(:store1) { Dir.mktmpdir('path1') }
let(:store2) { Dir.mktmpdir('path2') }
+ let(:definitions) { {} }
before do
allow(described_class).to receive(:paths).and_return(
@@ -115,28 +116,30 @@ RSpec.describe Feature::Definition do
)
end
+ subject { described_class.send(:load_all!) }
+
it "when there's no feature flags a list of definitions is empty" do
- expect(described_class.load_all!).to be_empty
+ is_expected.to be_empty
end
it "when there's a single feature flag it properly loads them" do
write_feature_flag(store1, path, yaml_content)
- expect(described_class.load_all!).to be_one
+ is_expected.to be_one
end
it "when the same feature flag is stored multiple times raises exception" do
write_feature_flag(store1, path, yaml_content)
write_feature_flag(store2, path, yaml_content)
- expect { described_class.load_all! }
+ expect { subject }
.to raise_error(/Feature flag 'feature_flag' is already defined/)
end
it "when one of the YAMLs is invalid it does raise exception" do
write_feature_flag(store1, path, '{}')
- expect { described_class.load_all! }
+ expect { subject }
.to raise_error(/Feature flag is missing name/)
end
diff --git a/spec/lib/feature_spec.rb b/spec/lib/feature_spec.rb
index acd7d97ac85..5dff9dbd995 100644
--- a/spec/lib/feature_spec.rb
+++ b/spec/lib/feature_spec.rb
@@ -6,6 +6,7 @@ RSpec.describe Feature, stub_feature_flags: false do
before do
# reset Flipper AR-engine
Feature.reset
+ skip_feature_flags_yaml_validation
end
describe '.get' do
@@ -253,6 +254,9 @@ RSpec.describe Feature, stub_feature_flags: false do
end
before do
+ stub_env('LAZILY_CREATE_FEATURE_FLAG', '0')
+
+ allow(Feature::Definition).to receive(:valid_usage!).and_call_original
allow(Feature::Definition).to receive(:definitions) do
{ definition.key => definition }
end
diff --git a/spec/lib/forever_spec.rb b/spec/lib/forever_spec.rb
index 6f6b3055df5..c47c03d6780 100644
--- a/spec/lib/forever_spec.rb
+++ b/spec/lib/forever_spec.rb
@@ -7,7 +7,7 @@ RSpec.describe Forever do
subject { described_class.date }
it 'returns Postgresql future date' do
- Timecop.travel(Date.new(2999, 12, 31)) do
+ travel_to(Date.new(2999, 12, 31)) do
is_expected.to be > Date.today
end
end
diff --git a/spec/lib/gitlab/alert_management/alert_params_spec.rb b/spec/lib/gitlab/alert_management/alert_params_spec.rb
deleted file mode 100644
index c3171be5e29..00000000000
--- a/spec/lib/gitlab/alert_management/alert_params_spec.rb
+++ /dev/null
@@ -1,101 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::AlertManagement::AlertParams do
- let_it_be(:project) { create(:project, :repository, :private) }
-
- describe '.from_generic_alert' do
- let(:started_at) { Time.current.change(usec: 0).rfc3339 }
- let(:default_payload) do
- {
- 'title' => 'Alert title',
- 'description' => 'Description',
- 'monitoring_tool' => 'Monitoring tool name',
- 'service' => 'Service',
- 'hosts' => ['gitlab.com'],
- 'start_time' => started_at,
- 'some' => { 'extra' => { 'payload' => 'here' } }
- }
- end
-
- let(:payload) { default_payload }
-
- subject { described_class.from_generic_alert(project: project, payload: payload) }
-
- it 'returns Alert compatible parameters' do
- is_expected.to eq(
- project_id: project.id,
- title: 'Alert title',
- description: 'Description',
- monitoring_tool: 'Monitoring tool name',
- service: 'Service',
- severity: 'critical',
- hosts: ['gitlab.com'],
- payload: payload,
- started_at: started_at,
- ended_at: nil,
- fingerprint: nil,
- environment: nil
- )
- end
-
- context 'when severity given' do
- let(:payload) { default_payload.merge(severity: 'low') }
-
- it 'returns Alert compatible parameters' do
- expect(subject[:severity]).to eq('low')
- end
- end
-
- context 'when there are no hosts in the payload' do
- let(:payload) { {} }
-
- it 'hosts param is an empty array' do
- expect(subject[:hosts]).to be_empty
- end
- end
- end
-
- describe '.from_prometheus_alert' do
- let(:payload) do
- {
- 'status' => 'firing',
- 'labels' => {
- 'alertname' => 'GitalyFileServerDown',
- 'channel' => 'gitaly',
- 'pager' => 'pagerduty',
- 'severity' => 's1'
- },
- 'annotations' => {
- 'description' => 'Alert description',
- 'runbook' => 'troubleshooting/gitaly-down.md',
- 'title' => 'Alert title'
- },
- 'startsAt' => '2020-04-27T10:10:22.265949279Z',
- 'endsAt' => '0001-01-01T00:00:00Z',
- 'generatorURL' => 'http://8d467bd4607a:9090/graph?g0.expr=vector%281%29&g0.tab=1',
- 'fingerprint' => 'b6ac4d42057c43c1'
- }
- end
-
- let(:parsed_alert) { Gitlab::Alerting::Alert.new(project: project, payload: payload) }
-
- subject { described_class.from_prometheus_alert(project: project, parsed_alert: parsed_alert) }
-
- it 'returns Alert-compatible params' do
- is_expected.to eq(
- project_id: project.id,
- title: 'Alert title',
- description: 'Alert description',
- monitoring_tool: 'Prometheus',
- payload: payload,
- started_at: parsed_alert.starts_at,
- ended_at: parsed_alert.ends_at,
- fingerprint: parsed_alert.gitlab_fingerprint,
- environment: parsed_alert.environment,
- prometheus_alert: parsed_alert.gitlab_alert
- )
- end
- end
-end
diff --git a/spec/lib/gitlab/alert_management/alert_status_counts_spec.rb b/spec/lib/gitlab/alert_management/alert_status_counts_spec.rb
index a2b8f0aa8d4..fceda763717 100644
--- a/spec/lib/gitlab/alert_management/alert_status_counts_spec.rb
+++ b/spec/lib/gitlab/alert_management/alert_status_counts_spec.rb
@@ -18,7 +18,7 @@ RSpec.describe Gitlab::AlertManagement::AlertStatusCounts do
expect(counts.open).to eq(0)
expect(counts.all).to eq(0)
- AlertManagement::Alert::STATUSES.each_key do |status|
+ ::AlertManagement::Alert.status_names.each do |status|
expect(counts.send(status)).to eq(0)
end
end
@@ -39,7 +39,7 @@ RSpec.describe Gitlab::AlertManagement::AlertStatusCounts do
end
context 'when filtering params are included' do
- let(:params) { { status: AlertManagement::Alert::STATUSES[:resolved] } }
+ let(:params) { { status: :resolved } }
it 'returns the correct counts for each status' do
expect(counts.open).to eq(0)
diff --git a/spec/lib/gitlab/alert_management/payload/base_spec.rb b/spec/lib/gitlab/alert_management/payload/base_spec.rb
index e0f63bad05d..0c26e94e596 100644
--- a/spec/lib/gitlab/alert_management/payload/base_spec.rb
+++ b/spec/lib/gitlab/alert_management/payload/base_spec.rb
@@ -120,14 +120,107 @@ RSpec.describe Gitlab::AlertManagement::Payload::Base do
end
describe '#alert_params' do
- before do
- allow(parsed_payload).to receive(:title).and_return('title')
- allow(parsed_payload).to receive(:description).and_return('description')
+ subject { parsed_payload.alert_params }
+
+ context 'with every key' do
+ let_it_be(:raw_payload) { { 'key' => 'value' } }
+ let_it_be(:stubs) do
+ {
+ description: 'description',
+ ends_at: Time.current,
+ environment: create(:environment, project: project),
+ gitlab_fingerprint: 'gitlab_fingerprint',
+ hosts: 'hosts',
+ monitoring_tool: 'monitoring_tool',
+ gitlab_alert: create(:prometheus_alert, project: project),
+ service: 'service',
+ severity: 'critical',
+ starts_at: Time.current,
+ title: 'title'
+ }
+ end
+
+ let(:expected_result) do
+ {
+ description: stubs[:description],
+ ended_at: stubs[:ends_at],
+ environment: stubs[:environment],
+ fingerprint: stubs[:gitlab_fingerprint],
+ hosts: [stubs[:hosts]],
+ monitoring_tool: stubs[:monitoring_tool],
+ payload: raw_payload,
+ project_id: project.id,
+ prometheus_alert: stubs[:gitlab_alert],
+ service: stubs[:service],
+ severity: stubs[:severity],
+ started_at: stubs[:starts_at],
+ title: stubs[:title]
+ }
+ end
+
+ before do
+ allow(parsed_payload).to receive_messages(stubs)
+ end
+
+ it { is_expected.to eq(expected_result) }
+
+ it 'can generate a valid new alert' do
+ expect(::AlertManagement::Alert.new(subject.except(:ended_at))).to be_valid
+ end
end
- subject { parsed_payload.alert_params }
+ context 'with too-long strings' do
+ let_it_be(:stubs) do
+ {
+ description: 'a' * (::AlertManagement::Alert::DESCRIPTION_MAX_LENGTH + 1),
+ hosts: 'b' * (::AlertManagement::Alert::HOSTS_MAX_LENGTH + 1),
+ monitoring_tool: 'c' * (::AlertManagement::Alert::TOOL_MAX_LENGTH + 1),
+ service: 'd' * (::AlertManagement::Alert::SERVICE_MAX_LENGTH + 1),
+ title: 'e' * (::AlertManagement::Alert::TITLE_MAX_LENGTH + 1)
+ }
+ end
- it { is_expected.to eq({ description: 'description', project_id: project.id, title: 'title' }) }
+ before do
+ allow(parsed_payload).to receive_messages(stubs)
+ end
+
+ it do
+ is_expected.to eq({
+ description: stubs[:description].truncate(AlertManagement::Alert::DESCRIPTION_MAX_LENGTH),
+ hosts: ['b' * ::AlertManagement::Alert::HOSTS_MAX_LENGTH],
+ monitoring_tool: stubs[:monitoring_tool].truncate(::AlertManagement::Alert::TOOL_MAX_LENGTH),
+ service: stubs[:service].truncate(::AlertManagement::Alert::SERVICE_MAX_LENGTH),
+ project_id: project.id,
+ title: stubs[:title].truncate(::AlertManagement::Alert::TITLE_MAX_LENGTH)
+ })
+ end
+ end
+
+ context 'with too-long hosts array' do
+ let(:hosts) { %w(abc def ghij) }
+ let(:shortened_hosts) { %w(abc def ghi) }
+
+ before do
+ stub_const('::AlertManagement::Alert::HOSTS_MAX_LENGTH', 9)
+ allow(parsed_payload).to receive(:hosts).and_return(hosts)
+ end
+
+ it { is_expected.to eq(hosts: shortened_hosts, project_id: project.id) }
+
+ context 'with host cut off between elements' do
+ let(:hosts) { %w(abcde fghij) }
+ let(:shortened_hosts) { %w(abcde fghi) }
+
+ it { is_expected.to eq({ hosts: shortened_hosts, project_id: project.id }) }
+ end
+
+ context 'with nested hosts' do
+ let(:hosts) { ['abc', ['de', 'f'], 'g', 'hij'] } # rubocop:disable Style/WordArray
+ let(:shortened_hosts) { %w(abc de f g hi) }
+
+ it { is_expected.to eq({ hosts: shortened_hosts, project_id: project.id }) }
+ end
+ end
end
describe '#gitlab_fingerprint' do
diff --git a/spec/lib/gitlab/alert_management/payload/generic_spec.rb b/spec/lib/gitlab/alert_management/payload/generic_spec.rb
index 538a822503e..b7660462b0d 100644
--- a/spec/lib/gitlab/alert_management/payload/generic_spec.rb
+++ b/spec/lib/gitlab/alert_management/payload/generic_spec.rb
@@ -46,7 +46,7 @@ RSpec.describe Gitlab::AlertManagement::Payload::Generic do
subject { parsed_payload.starts_at }
around do |example|
- Timecop.freeze(current_time) { example.run }
+ travel_to(current_time) { example.run }
end
context 'without start_time' do
@@ -86,4 +86,34 @@ RSpec.describe Gitlab::AlertManagement::Payload::Generic do
it_behaves_like 'parsable alert payload field', 'gitlab_environment_name'
end
+
+ describe '#description' do
+ subject { parsed_payload.description }
+
+ it_behaves_like 'parsable alert payload field', 'description'
+ end
+
+ describe '#ends_at' do
+ let(:current_time) { Time.current.change(usec: 0).utc }
+
+ subject { parsed_payload.ends_at }
+
+ around do |example|
+ travel_to(current_time) { example.run }
+ end
+
+ context 'without end_time' do
+ it { is_expected.to be_nil }
+ end
+
+ context "with end_time" do
+ let(:value) { 10.minutes.ago.change(usec: 0).utc }
+
+ before do
+ raw_payload['end_time'] = value.to_s
+ end
+
+ it { is_expected.to eq(value) }
+ end
+ end
end
diff --git a/spec/lib/gitlab/alerting/alert_spec.rb b/spec/lib/gitlab/alerting/alert_spec.rb
deleted file mode 100644
index b53b71e3f3e..00000000000
--- a/spec/lib/gitlab/alerting/alert_spec.rb
+++ /dev/null
@@ -1,299 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::Alerting::Alert do
- let_it_be(:project) { create(:project) }
-
- let(:alert) { build(:alerting_alert, project: project, payload: payload) }
- let(:payload) { {} }
-
- shared_context 'gitlab alert' do
- let!(:gitlab_alert) { create(:prometheus_alert, project: project) }
- let(:gitlab_alert_id) { gitlab_alert.id }
-
- before do
- payload['labels'] = {
- 'gitlab_alert_id' => gitlab_alert.prometheus_metric_id.to_s,
- 'gitlab_prometheus_alert_id' => gitlab_alert_id
- }
- end
- end
-
- shared_context 'full query' do
- before do
- payload['generatorURL'] = 'http://localhost:9090/graph?g0.expr=vector%281%29'
- end
- end
-
- shared_examples 'invalid alert' do
- it 'is invalid' do
- expect(alert).not_to be_valid
- end
- end
-
- shared_examples 'parse payload' do |*pairs|
- context 'without payload' do
- it { is_expected.to be_nil }
- end
-
- pairs.each do |pair|
- context "with #{pair}" do
- let(:value) { 'some value' }
-
- before do
- section, name = pair.split('/')
- payload[section] = { name => value }
- end
-
- it { is_expected.to eq(value) }
- end
- end
- end
-
- describe '#gitlab_alert' do
- subject { alert.gitlab_alert }
-
- context 'without payload' do
- it { is_expected.to be_nil }
- end
-
- context 'with gitlab alert' do
- include_context 'gitlab alert'
-
- it { is_expected.to eq(gitlab_alert) }
- end
-
- context 'with unknown gitlab alert' do
- include_context 'gitlab alert' do
- let(:gitlab_alert_id) { 'unknown' }
- end
-
- it { is_expected.to be_nil }
- end
-
- context 'when two alerts with the same metric exist' do
- include_context 'gitlab alert'
-
- let!(:second_gitlab_alert) do
- create(:prometheus_alert,
- project: project,
- prometheus_metric_id: gitlab_alert.prometheus_metric_id
- )
- end
-
- context 'alert id given in params' do
- before do
- payload['labels'] = {
- 'gitlab_alert_id' => gitlab_alert.prometheus_metric_id.to_s,
- 'gitlab_prometheus_alert_id' => second_gitlab_alert.id
- }
- end
-
- it { is_expected.to eq(second_gitlab_alert) }
- end
-
- context 'metric id given in params' do
- # This tests the case when two alerts are found, as metric id
- # is not unique.
-
- # Note the metric id was incorrectly named as 'gitlab_alert_id'
- # in PrometheusAlert#to_param.
- before do
- payload['labels'] = { 'gitlab_alert_id' => gitlab_alert.prometheus_metric_id }
- end
-
- it { is_expected.to be_nil }
- end
- end
- end
-
- describe '#title' do
- subject { alert.title }
-
- it_behaves_like 'parse payload',
- 'annotations/title',
- 'annotations/summary',
- 'labels/alertname'
-
- context 'with gitlab alert' do
- include_context 'gitlab alert'
-
- context 'with annotations/title' do
- let(:value) { 'annotation title' }
-
- before do
- payload['annotations'] = { 'title' => value }
- end
-
- it { is_expected.to eq(gitlab_alert.title) }
- end
- end
- end
-
- describe '#description' do
- subject { alert.description }
-
- it_behaves_like 'parse payload', 'annotations/description'
- end
-
- describe '#annotations' do
- subject { alert.annotations }
-
- context 'without payload' do
- it { is_expected.to eq([]) }
- end
-
- context 'with payload' do
- before do
- payload['annotations'] = { 'foo' => 'value1', 'bar' => 'value2' }
- end
-
- it 'parses annotations' do
- expect(subject.size).to eq(2)
- expect(subject.map(&:label)).to eq(%w[foo bar])
- expect(subject.map(&:value)).to eq(%w[value1 value2])
- end
- end
- end
-
- describe '#environment' do
- subject { alert.environment }
-
- context 'without gitlab_alert' do
- it { is_expected.to be_nil }
- end
-
- context 'with gitlab alert' do
- include_context 'gitlab alert'
-
- it { is_expected.to eq(gitlab_alert.environment) }
- end
- end
-
- describe '#starts_at' do
- subject { alert.starts_at }
-
- context 'with empty startsAt' do
- before do
- payload['startsAt'] = nil
- end
-
- it { is_expected.to be_nil }
- end
-
- context 'with invalid startsAt' do
- before do
- payload['startsAt'] = 'invalid'
- end
-
- it { is_expected.to be_nil }
- end
-
- context 'with payload' do
- let(:time) { Time.current.change(usec: 0) }
-
- before do
- payload['startsAt'] = time.rfc3339
- end
-
- it { is_expected.to eq(time) }
- end
- end
-
- describe '#full_query' do
- using RSpec::Parameterized::TableSyntax
-
- subject { alert.full_query }
-
- where(:generator_url, :expected_query) do
- nil | nil
- 'http://localhost' | nil
- 'invalid url' | nil
- 'http://localhost:9090/graph?g1.expr=vector%281%29' | nil
- 'http://localhost:9090/graph?g0.expr=vector%281%29' | 'vector(1)'
- end
-
- with_them do
- before do
- payload['generatorURL'] = generator_url
- end
-
- it { is_expected.to eq(expected_query) }
- end
-
- context 'with gitlab alert' do
- include_context 'gitlab alert'
- include_context 'full query'
-
- it { is_expected.to eq(gitlab_alert.full_query) }
- end
- end
-
- describe '#y_label' do
- subject { alert.y_label }
-
- it_behaves_like 'parse payload', 'annotations/gitlab_y_label'
-
- context 'when y_label is not included in the payload' do
- it_behaves_like 'parse payload', 'annotations/title'
- end
- end
-
- describe '#alert_markdown' do
- subject { alert.alert_markdown }
-
- it_behaves_like 'parse payload', 'annotations/gitlab_incident_markdown'
- end
-
- describe '#gitlab_fingerprint' do
- subject { alert.gitlab_fingerprint }
-
- context 'when the alert is a GitLab managed alert' do
- include_context 'gitlab alert'
-
- it 'returns a fingerprint' do
- plain_fingerprint = [alert.metric_id, alert.starts_at_raw].join('/')
-
- is_expected.to eq(Digest::SHA1.hexdigest(plain_fingerprint))
- end
- end
-
- context 'when the alert is from self managed Prometheus' do
- include_context 'full query'
-
- it 'returns a fingerprint' do
- plain_fingerprint = [alert.starts_at_raw, alert.title, alert.full_query].join('/')
-
- is_expected.to eq(Digest::SHA1.hexdigest(plain_fingerprint))
- end
- end
- end
-
- describe '#valid?' do
- before do
- payload.update(
- 'annotations' => { 'title' => 'some title' },
- 'startsAt' => Time.current.rfc3339
- )
- end
-
- subject { alert }
-
- it { is_expected.to be_valid }
-
- context 'without project' do
- let(:project) { nil }
-
- it { is_expected.not_to be_valid }
- end
-
- context 'without starts_at' do
- before do
- payload['startsAt'] = nil
- end
-
- it { is_expected.not_to be_valid }
- end
- end
-end
diff --git a/spec/lib/gitlab/alerting/notification_payload_parser_spec.rb b/spec/lib/gitlab/alerting/notification_payload_parser_spec.rb
deleted file mode 100644
index ff5ab1116fa..00000000000
--- a/spec/lib/gitlab/alerting/notification_payload_parser_spec.rb
+++ /dev/null
@@ -1,204 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::Alerting::NotificationPayloadParser do
- let_it_be(:project) { build(:project) }
-
- describe '.call' do
- let(:starts_at) { Time.current.change(usec: 0) }
- let(:ends_at) { Time.current.change(usec: 0) }
- let(:payload) do
- {
- 'title' => 'alert title',
- 'start_time' => starts_at.rfc3339,
- 'end_time' => ends_at.rfc3339,
- 'description' => 'Description',
- 'monitoring_tool' => 'Monitoring tool name',
- 'service' => 'Service',
- 'hosts' => ['gitlab.com'],
- 'severity' => 'low'
- }
- end
-
- subject { described_class.call(payload, project) }
-
- it 'returns Prometheus-like payload' do
- is_expected.to eq(
- {
- 'annotations' => {
- 'title' => 'alert title',
- 'description' => 'Description',
- 'monitoring_tool' => 'Monitoring tool name',
- 'service' => 'Service',
- 'hosts' => ['gitlab.com'],
- 'severity' => 'low'
- },
- 'startsAt' => starts_at.rfc3339,
- 'endsAt' => ends_at.rfc3339
- }
- )
- end
-
- context 'when title is blank' do
- before do
- payload[:title] = ''
- end
-
- it 'sets a predefined title' do
- expect(subject.dig('annotations', 'title')).to eq('New: Incident')
- end
- end
-
- context 'when hosts attribute is a string' do
- before do
- payload[:hosts] = 'gitlab.com'
- end
-
- it 'returns hosts as an array of one element' do
- expect(subject.dig('annotations', 'hosts')).to eq(['gitlab.com'])
- end
- end
-
- context 'when the time is in unsupported format' do
- before do
- payload[:start_time] = 'invalid/date/format'
- end
-
- it 'sets startsAt to a current time in RFC3339 format' do
- expect(subject['startsAt']).to eq(starts_at.rfc3339)
- end
- end
-
- context 'when payload is blank' do
- let(:payload) { {} }
-
- it 'returns default parameters' do
- is_expected.to match(
- 'annotations' => {
- 'title' => described_class::DEFAULT_TITLE,
- 'severity' => described_class::DEFAULT_SEVERITY
- },
- 'startsAt' => starts_at.rfc3339
- )
- end
-
- context 'when severity is blank' do
- before do
- payload[:severity] = ''
- end
-
- it 'sets severity to the default ' do
- expect(subject.dig('annotations', 'severity')).to eq(described_class::DEFAULT_SEVERITY)
- end
- end
- end
-
- context 'with fingerprint' do
- before do
- payload[:fingerprint] = data
- end
-
- shared_examples 'fingerprint generation' do
- it 'generates the fingerprint correctly' do
- expect(result).to eq(Gitlab::AlertManagement::Fingerprint.generate(data))
- end
- end
-
- context 'with blank fingerprint' do
- it_behaves_like 'fingerprint generation' do
- let(:data) { ' ' }
- let(:result) { subject.dig('annotations', 'fingerprint') }
- end
- end
-
- context 'with fingerprint given' do
- it_behaves_like 'fingerprint generation' do
- let(:data) { 'fingerprint' }
- let(:result) { subject.dig('annotations', 'fingerprint') }
- end
- end
-
- context 'with array fingerprint given' do
- it_behaves_like 'fingerprint generation' do
- let(:data) { [1, 'fingerprint', 'given'] }
- let(:result) { subject.dig('annotations', 'fingerprint') }
- end
- end
- end
-
- context 'with environment' do
- let(:environment) { create(:environment, project: project) }
-
- before do
- payload[:gitlab_environment_name] = environment.name
- end
-
- it 'sets the environment ' do
- expect(subject.dig('annotations', 'environment')).to eq(environment)
- end
- end
-
- context 'when payload attributes have blank lines' do
- let(:payload) do
- {
- 'title' => '',
- 'start_time' => '',
- 'end_time' => '',
- 'description' => '',
- 'monitoring_tool' => '',
- 'service' => '',
- 'hosts' => ['']
- }
- end
-
- it 'returns default parameters' do
- is_expected.to eq(
- 'annotations' => {
- 'title' => 'New: Incident',
- 'severity' => described_class::DEFAULT_SEVERITY
- },
- 'startsAt' => starts_at.rfc3339
- )
- end
- end
-
- context 'when payload has secondary params' do
- let(:payload) do
- {
- 'description' => 'Description',
- 'additional' => {
- 'params' => {
- '1' => 'Some value 1',
- '2' => 'Some value 2',
- 'blank' => ''
- }
- }
- }
- end
-
- it 'adds secondary params to annotations' do
- is_expected.to eq(
- 'annotations' => {
- 'title' => 'New: Incident',
- 'severity' => described_class::DEFAULT_SEVERITY,
- 'description' => 'Description',
- 'additional.params.1' => 'Some value 1',
- 'additional.params.2' => 'Some value 2'
- },
- 'startsAt' => starts_at.rfc3339
- )
- end
- end
-
- context 'when secondary params hash is too big' do
- before do
- allow(Gitlab::Utils::SafeInlineHash).to receive(:merge_keys!).and_raise(ArgumentError)
- end
-
- it 'catches and re-raises an error' do
- expect { subject }.to raise_error Gitlab::Alerting::NotificationPayloadParser::BadPayloadError, 'The payload is too big'
- end
- end
- end
-end
diff --git a/spec/lib/gitlab/analytics/unique_visits_spec.rb b/spec/lib/gitlab/analytics/unique_visits_spec.rb
index 1432c9ac58f..6ac58e13f4c 100644
--- a/spec/lib/gitlab/analytics/unique_visits_spec.rb
+++ b/spec/lib/gitlab/analytics/unique_visits_spec.rb
@@ -19,7 +19,7 @@ RSpec.describe Gitlab::Analytics::UniqueVisits, :clean_gitlab_redis_shared_state
# Without freezing the time, the test may behave inconsistently
# depending on which day of the week test is run.
reference_time = Time.utc(2020, 6, 1)
- Timecop.freeze(reference_time) { example.run }
+ travel_to(reference_time) { example.run }
end
describe '#track_visit' do
diff --git a/spec/lib/gitlab/auth/auth_finders_spec.rb b/spec/lib/gitlab/auth/auth_finders_spec.rb
index 1ac8ebe1369..2ebde145bfd 100644
--- a/spec/lib/gitlab/auth/auth_finders_spec.rb
+++ b/spec/lib/gitlab/auth/auth_finders_spec.rb
@@ -419,10 +419,30 @@ RSpec.describe Gitlab::Auth::AuthFinders do
expect(find_user_from_web_access_token(:ics)).to eq(user)
end
- it 'returns the user for API requests' do
- set_header('SCRIPT_NAME', '/api/endpoint')
+ context 'for API requests' do
+ it 'returns the user' do
+ set_header('SCRIPT_NAME', '/api/endpoint')
+
+ expect(find_user_from_web_access_token(:api)).to eq(user)
+ end
+
+ it 'returns nil if URL does not start with /api/' do
+ set_header('SCRIPT_NAME', '/relative_root/api/endpoint')
+
+ expect(find_user_from_web_access_token(:api)).to be_nil
+ end
- expect(find_user_from_web_access_token(:api)).to eq(user)
+ context 'when relative_url_root is set' do
+ before do
+ stub_config_setting(relative_url_root: '/relative_root')
+ end
+
+ it 'returns the user' do
+ set_header('SCRIPT_NAME', '/relative_root/api/endpoint')
+
+ expect(find_user_from_web_access_token(:api)).to eq(user)
+ end
+ end
end
end
diff --git a/spec/lib/gitlab/auth/current_user_mode_spec.rb b/spec/lib/gitlab/auth/current_user_mode_spec.rb
index 60b403780c0..ffd7813190a 100644
--- a/spec/lib/gitlab/auth/current_user_mode_spec.rb
+++ b/spec/lib/gitlab/auth/current_user_mode_spec.rb
@@ -121,7 +121,7 @@ RSpec.describe Gitlab::Auth::CurrentUserMode, :do_not_mock_admin_mode, :request_
subject.enable_admin_mode!(password: user.password)
expect(subject.admin_mode?).to be(true), 'admin mode is not active in the present'
- Timecop.freeze(Gitlab::Auth::CurrentUserMode::MAX_ADMIN_MODE_TIME.from_now) do
+ travel_to(Gitlab::Auth::CurrentUserMode::MAX_ADMIN_MODE_TIME.from_now) do
# in the future this will be a new request, simulate by clearing the RequestStore
Gitlab::SafeRequestStore.clear!
diff --git a/spec/lib/gitlab/auth/otp/strategies/devise_spec.rb b/spec/lib/gitlab/auth/otp/strategies/devise_spec.rb
new file mode 100644
index 00000000000..0c88421d456
--- /dev/null
+++ b/spec/lib/gitlab/auth/otp/strategies/devise_spec.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Auth::Otp::Strategies::Devise do
+ let_it_be(:user) { create(:user) }
+ let(:otp_code) { 42 }
+
+ subject(:validate) { described_class.new(user).validate(otp_code) }
+
+ it 'calls Devise' do
+ expect(user).to receive(:validate_and_consume_otp!).with(otp_code)
+
+ validate
+ end
+end
diff --git a/spec/lib/gitlab/auth/otp/strategies/forti_authenticator_spec.rb b/spec/lib/gitlab/auth/otp/strategies/forti_authenticator_spec.rb
new file mode 100644
index 00000000000..18fd6d08057
--- /dev/null
+++ b/spec/lib/gitlab/auth/otp/strategies/forti_authenticator_spec.rb
@@ -0,0 +1,55 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Auth::Otp::Strategies::FortiAuthenticator do
+ let_it_be(:user) { create(:user) }
+ let(:otp_code) { 42 }
+
+ let(:host) { 'forti_authenticator.example.com' }
+ let(:port) { '444' }
+ let(:api_username) { 'janedoe' }
+ let(:api_token) { 's3cr3t' }
+
+ let(:forti_authenticator_auth_url) { "https://#{host}:#{port}/api/v1/auth/" }
+
+ subject(:validate) { described_class.new(user).validate(otp_code) }
+
+ before do
+ stub_feature_flags(forti_authenticator: true)
+
+ stub_forti_authenticator_config(
+ host: host,
+ port: port,
+ username: api_username,
+ token: api_token
+ )
+
+ request_body = { username: user.username,
+ token_code: otp_code }
+
+ stub_request(:post, forti_authenticator_auth_url)
+ .with(body: JSON(request_body), headers: { 'Content-Type' => 'application/json' })
+ .to_return(status: response_status, body: '', headers: {})
+ end
+
+ context 'successful validation' do
+ let(:response_status) { 200 }
+
+ it 'returns success' do
+ expect(validate[:status]).to eq(:success)
+ end
+ end
+
+ context 'unsuccessful validation' do
+ let(:response_status) { 401 }
+
+ it 'returns error' do
+ expect(validate[:status]).to eq(:error)
+ end
+ end
+
+ def stub_forti_authenticator_config(forti_authenticator_settings)
+ allow(::Gitlab.config.forti_authenticator).to(receive_messages(forti_authenticator_settings))
+ end
+end
diff --git a/spec/lib/gitlab/auth/unique_ips_limiter_spec.rb b/spec/lib/gitlab/auth/unique_ips_limiter_spec.rb
index a08055ab852..b239de841b6 100644
--- a/spec/lib/gitlab/auth/unique_ips_limiter_spec.rb
+++ b/spec/lib/gitlab/auth/unique_ips_limiter_spec.rb
@@ -26,7 +26,7 @@ RSpec.describe Gitlab::Auth::UniqueIpsLimiter, :clean_gitlab_redis_shared_state
expect(described_class.update_and_return_ips_count(user.id, 'ip2')).to eq(1)
expect(described_class.update_and_return_ips_count(user.id, 'ip3')).to eq(2)
- Timecop.travel(Time.now.utc + described_class.config.unique_ips_limit_time_window) do
+ travel_to(Time.now.utc + described_class.config.unique_ips_limit_time_window) do
expect(described_class.update_and_return_ips_count(user.id, 'ip4')).to eq(1)
expect(described_class.update_and_return_ips_count(user.id, 'ip5')).to eq(2)
end
diff --git a/spec/lib/gitlab/auth/user_access_denied_reason_spec.rb b/spec/lib/gitlab/auth/user_access_denied_reason_spec.rb
index 5cbd22827c9..d3c6cde5590 100644
--- a/spec/lib/gitlab/auth/user_access_denied_reason_spec.rb
+++ b/spec/lib/gitlab/auth/user_access_denied_reason_spec.rb
@@ -49,5 +49,13 @@ RSpec.describe Gitlab::Auth::UserAccessDeniedReason do
it { is_expected.to match /Your primary email address is not confirmed/ }
end
+
+ context 'when the user is blocked pending approval' do
+ before do
+ user.block_pending_approval!
+ end
+
+ it { is_expected.to eq('Your account is pending approval from your administrator and hence blocked.') }
+ end
end
end
diff --git a/spec/lib/gitlab/auth_spec.rb b/spec/lib/gitlab/auth_spec.rb
index 74360637897..1768ab41a71 100644
--- a/spec/lib/gitlab/auth_spec.rb
+++ b/spec/lib/gitlab/auth_spec.rb
@@ -726,6 +726,12 @@ RSpec.describe Gitlab::Auth, :use_clean_rails_memory_store_caching do
expect( gl_auth.find_with_user_password(username, password) ).not_to eql user
end
+ it 'does not find user in blocked_pending_approval state' do
+ user.block_pending_approval
+
+ expect( gl_auth.find_with_user_password(username, password) ).not_to eql user
+ end
+
context 'with increment_failed_attempts' do
wrong_password = 'incorrect_password'
diff --git a/spec/lib/gitlab/background_migration/add_modified_to_approval_merge_request_rule_spec.rb b/spec/lib/gitlab/background_migration/add_modified_to_approval_merge_request_rule_spec.rb
new file mode 100644
index 00000000000..81b8b5dde08
--- /dev/null
+++ b/spec/lib/gitlab/background_migration/add_modified_to_approval_merge_request_rule_spec.rb
@@ -0,0 +1,61 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::BackgroundMigration::AddModifiedToApprovalMergeRequestRule, schema: 20200817195628 do
+ let(:determine_if_rules_are_modified) { described_class.new }
+
+ let(:namespace) { table(:namespaces).create!(name: 'gitlab', path: 'gitlab') }
+ let(:projects) { table(:projects) }
+ let(:normal_project) { projects.create!(namespace_id: namespace.id) }
+ let(:overridden_project) { projects.create!(namespace_id: namespace.id) }
+ let(:rules) { table(:approval_merge_request_rules) }
+ let(:project_rules) { table(:approval_project_rules) }
+ let(:sources) { table(:approval_merge_request_rule_sources) }
+ let(:merge_requests) { table(:merge_requests) }
+ let(:groups) { table(:namespaces) }
+ let(:mr_groups) { table(:approval_merge_request_rules_groups) }
+ let(:project_groups) { table(:approval_project_rules_groups) }
+
+ before do
+ project_rule = project_rules.create!(project_id: normal_project.id, approvals_required: 3, name: 'test rule')
+ overridden_project_rule = project_rules.create!(project_id: overridden_project.id, approvals_required: 5, name: 'other test rule')
+ overridden_project_rule_two = project_rules.create!(project_id: overridden_project.id, approvals_required: 7, name: 'super cool rule')
+
+ merge_request = merge_requests.create!(target_branch: 'feature', source_branch: 'default', source_project_id: normal_project.id, target_project_id: normal_project.id)
+ overridden_merge_request = merge_requests.create!(target_branch: 'feature-2', source_branch: 'default', source_project_id: overridden_project.id, target_project_id: overridden_project.id)
+
+ merge_rule = rules.create!(merge_request_id: merge_request.id, approvals_required: 3, name: 'test rule')
+ overridden_merge_rule = rules.create!(merge_request_id: overridden_merge_request.id, approvals_required: 6, name: 'other test rule')
+ overridden_merge_rule_two = rules.create!(merge_request_id: overridden_merge_request.id, approvals_required: 7, name: 'super cool rule')
+
+ sources.create!(approval_project_rule_id: project_rule.id, approval_merge_request_rule_id: merge_rule.id)
+ sources.create!(approval_project_rule_id: overridden_project_rule.id, approval_merge_request_rule_id: overridden_merge_rule.id)
+ sources.create!(approval_project_rule_id: overridden_project_rule_two.id, approval_merge_request_rule_id: overridden_merge_rule_two.id)
+
+ group1 = groups.create!(name: "group1", path: "test_group1", type: 'Group')
+ group2 = groups.create!(name: "group2", path: "test_group2", type: 'Group')
+ group3 = groups.create!(name: "group3", path: "test_group3", type: 'Group')
+
+ project_groups.create!(approval_project_rule_id: overridden_project_rule_two.id, group_id: group1.id)
+ project_groups.create!(approval_project_rule_id: overridden_project_rule_two.id, group_id: group2.id)
+ project_groups.create!(approval_project_rule_id: overridden_project_rule_two.id, group_id: group3.id)
+
+ mr_groups.create!(approval_merge_request_rule_id: overridden_merge_rule.id, group_id: group1.id)
+ mr_groups.create!(approval_merge_request_rule_id: overridden_merge_rule_two.id, group_id: group2.id)
+ end
+
+ describe '#perform' do
+ it 'changes the correct rules' do
+ original_count = rules.all.count
+
+ determine_if_rules_are_modified.perform(rules.minimum(:id), rules.maximum(:id))
+
+ results = rules.where(modified_from_project_rule: true)
+
+ expect(results.count).to eq 2
+ expect(results.collect(&:name)).to eq(['other test rule', 'super cool rule'])
+ expect(rules.count).to eq original_count
+ end
+ end
+end
diff --git a/spec/lib/gitlab/background_migration/merge_request_assignees_migration_progress_check_spec.rb b/spec/lib/gitlab/background_migration/merge_request_assignees_migration_progress_check_spec.rb
index a3840e3a22e..85a9c88ebff 100644
--- a/spec/lib/gitlab/background_migration/merge_request_assignees_migration_progress_check_spec.rb
+++ b/spec/lib/gitlab/background_migration/merge_request_assignees_migration_progress_check_spec.rb
@@ -73,7 +73,7 @@ RSpec.describe Gitlab::BackgroundMigration::MergeRequestAssigneesMigrationProgre
described_class.new.perform
- expect(Feature.enabled?(:multiple_merge_request_assignees)).to eq(true)
+ expect(Feature.enabled?(:multiple_merge_request_assignees, type: :licensed)).to eq(true)
end
end
diff --git a/spec/lib/gitlab/background_migration/migrate_u2f_webauthn_spec.rb b/spec/lib/gitlab/background_migration/migrate_u2f_webauthn_spec.rb
new file mode 100644
index 00000000000..33498ffa748
--- /dev/null
+++ b/spec/lib/gitlab/background_migration/migrate_u2f_webauthn_spec.rb
@@ -0,0 +1,65 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::BackgroundMigration::MigrateU2fWebauthn, :migration, schema: 20200925125321 do
+ let(:users) { table(:users) }
+
+ let(:user) { users.create!(email: 'email@email.com', name: 'foo', username: 'foo', projects_limit: 0) }
+
+ let(:u2f_registrations) { table(:u2f_registrations) }
+ let(:webauthn_registrations) { table(:webauthn_registrations) }
+
+ let!(:u2f_registration_not_migrated) { create_u2f_registration(1, 'reg1') }
+ let!(:u2f_registration_not_migrated_no_name) { create_u2f_registration(2, nil, 2) }
+ let!(:u2f_registration_migrated) { create_u2f_registration(3, 'reg3') }
+
+ subject { described_class.new.perform(1, 3) }
+
+ before do
+ converted_credential = convert_credential_for(u2f_registration_migrated)
+ webauthn_registrations.create!(converted_credential)
+ end
+
+ it 'migrates all records' do
+ expect { subject }.to change { webauthn_registrations.count }.from(1).to(3)
+
+ all_webauthn_registrations = webauthn_registrations.all.map(&:attributes)
+
+ [u2f_registration_not_migrated, u2f_registration_not_migrated_no_name].each do |u2f_registration|
+ expected_credential = convert_credential_for(u2f_registration).except(:created_at).stringify_keys
+ expect(all_webauthn_registrations).to include(a_hash_including(expected_credential))
+ end
+ end
+
+ def create_u2f_registration(id, name, counter = 5)
+ device = U2F::FakeU2F.new(FFaker::BaconIpsum.characters(5))
+ u2f_registrations.create!({ id: id,
+ certificate: Base64.strict_encode64(device.cert_raw),
+ key_handle: U2F.urlsafe_encode64(device.key_handle_raw),
+ public_key: Base64.strict_encode64(device.origin_public_key_raw),
+ counter: counter,
+ name: name,
+ user_id: user.id })
+ end
+
+ def convert_credential_for(u2f_registration)
+ converted_credential = WebAuthn::U2fMigrator.new(
+ app_id: Gitlab.config.gitlab.url,
+ certificate: u2f_registration.certificate,
+ key_handle: u2f_registration.key_handle,
+ public_key: u2f_registration.public_key,
+ counter: u2f_registration.counter
+ ).credential
+
+ {
+ credential_xid: Base64.strict_encode64(converted_credential.id),
+ public_key: Base64.strict_encode64(converted_credential.public_key),
+ counter: u2f_registration.counter,
+ name: u2f_registration.name || '',
+ user_id: u2f_registration.user_id,
+ u2f_registration_id: u2f_registration.id,
+ created_at: u2f_registration.created_at
+ }
+ end
+end
diff --git a/spec/lib/gitlab/background_migration/migrate_users_bio_to_user_details_spec.rb b/spec/lib/gitlab/background_migration/migrate_users_bio_to_user_details_spec.rb
index db3cbe7ccdc..3cec5cb4c35 100644
--- a/spec/lib/gitlab/background_migration/migrate_users_bio_to_user_details_spec.rb
+++ b/spec/lib/gitlab/background_migration/migrate_users_bio_to_user_details_spec.rb
@@ -82,21 +82,4 @@ RSpec.describe Gitlab::BackgroundMigration::MigrateUsersBioToUserDetails, :migra
expect(user_detail).to be_nil
end
-
- context 'when `migrate_bio_to_user_details` feature flag is off' do
- before do
- stub_feature_flags(migrate_bio_to_user_details: false)
- end
-
- it 'does nothing' do
- already_existing_user_details = user_details.where(user_id: [
- user_has_different_details.id,
- user_already_has_details.id
- ])
-
- subject
-
- expect(user_details.all).to match_array(already_existing_user_details)
- end
- end
end
diff --git a/spec/lib/gitlab/background_migration/replace_blocked_by_links_spec.rb b/spec/lib/gitlab/background_migration/replace_blocked_by_links_spec.rb
new file mode 100644
index 00000000000..fa4f2d1fd88
--- /dev/null
+++ b/spec/lib/gitlab/background_migration/replace_blocked_by_links_spec.rb
@@ -0,0 +1,36 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::BackgroundMigration::ReplaceBlockedByLinks, schema: 20201015073808 do
+ let(:namespace) { table(:namespaces).create!(name: 'gitlab', path: 'gitlab-org') }
+ let(:project) { table(:projects).create!(namespace_id: namespace.id, name: 'gitlab') }
+ let(:issue1) { table(:issues).create!(project_id: project.id, title: 'a') }
+ let(:issue2) { table(:issues).create!(project_id: project.id, title: 'b') }
+ let(:issue3) { table(:issues).create!(project_id: project.id, title: 'c') }
+ let(:issue_links) { table(:issue_links) }
+ let!(:blocks_link) { issue_links.create!(source_id: issue1.id, target_id: issue2.id, link_type: 1) }
+ let!(:bidirectional_link) { issue_links.create!(source_id: issue2.id, target_id: issue1.id, link_type: 2) }
+ let!(:blocked_link) { issue_links.create!(source_id: issue1.id, target_id: issue3.id, link_type: 2) }
+
+ subject { described_class.new.perform(issue_links.minimum(:id), issue_links.maximum(:id)) }
+
+ it 'deletes issue links where opposite relation already exists' do
+ expect { subject }.to change { issue_links.count }.by(-1)
+ end
+
+ it 'ignores issue links other than blocked_by' do
+ subject
+
+ expect(blocks_link.reload.link_type).to eq(1)
+ end
+
+ it 'updates blocked_by issue links' do
+ subject
+
+ link = blocked_link.reload
+ expect(link.link_type).to eq(1)
+ expect(link.source_id).to eq(issue3.id)
+ expect(link.target_id).to eq(issue1.id)
+ end
+end
diff --git a/spec/lib/gitlab/background_migration/user_mentions/create_resource_user_mention_spec.rb b/spec/lib/gitlab/background_migration/user_mentions/create_resource_user_mention_spec.rb
index 392b44d1a1f..2dae4a65eeb 100644
--- a/spec/lib/gitlab/background_migration/user_mentions/create_resource_user_mention_spec.rb
+++ b/spec/lib/gitlab/background_migration/user_mentions/create_resource_user_mention_spec.rb
@@ -74,14 +74,14 @@ RSpec.describe Gitlab::BackgroundMigration::UserMentions::CreateResourceUserMent
let(:user_mentions) { merge_request_user_mentions }
let(:resource) { merge_request }
- it_behaves_like 'resource mentions migration', MigrateMergeRequestMentionsToDb, MergeRequest
+ it_behaves_like 'resource mentions migration', MigrateMergeRequestMentionsToDb, 'MergeRequest'
context 'when FF disabled' do
before do
stub_feature_flags(migrate_user_mentions: false)
end
- it_behaves_like 'resource migration not run', MigrateMergeRequestMentionsToDb, MergeRequest
+ it_behaves_like 'resource migration not run', MigrateMergeRequestMentionsToDb, 'MergeRequest'
end
end
@@ -103,14 +103,14 @@ RSpec.describe Gitlab::BackgroundMigration::UserMentions::CreateResourceUserMent
let(:user_mentions) { commit_user_mentions }
let(:resource) { commit }
- it_behaves_like 'resource notes mentions migration', MigrateCommitNotesMentionsToDb, Commit
+ it_behaves_like 'resource notes mentions migration', MigrateCommitNotesMentionsToDb, 'Commit'
context 'when FF disabled' do
before do
stub_feature_flags(migrate_user_mentions: false)
end
- it_behaves_like 'resource notes migration not run', MigrateCommitNotesMentionsToDb, Commit
+ it_behaves_like 'resource notes migration not run', MigrateCommitNotesMentionsToDb, 'Commit'
end
end
end
diff --git a/spec/lib/gitlab/bitbucket_import/importer_spec.rb b/spec/lib/gitlab/bitbucket_import/importer_spec.rb
index d4483bf1754..b723c31c4aa 100644
--- a/spec/lib/gitlab/bitbucket_import/importer_spec.rb
+++ b/spec/lib/gitlab/bitbucket_import/importer_spec.rb
@@ -312,7 +312,7 @@ RSpec.describe Gitlab::BitbucketImport::Importer do
# attributes later.
existing_label.reload
- Timecop.freeze(Time.now + 1.minute) do
+ travel_to(Time.now + 1.minute) do
importer.execute
label_after_import = project.labels.find(existing_label.id)
diff --git a/spec/lib/gitlab/bulk_import/client_spec.rb b/spec/lib/gitlab/bulk_import/client_spec.rb
new file mode 100644
index 00000000000..a6f8dd6d194
--- /dev/null
+++ b/spec/lib/gitlab/bulk_import/client_spec.rb
@@ -0,0 +1,95 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::BulkImport::Client do
+ include ImportSpecHelper
+
+ let(:uri) { 'http://gitlab.example' }
+ let(:token) { 'token' }
+ let(:resource) { 'resource' }
+
+ subject { described_class.new(uri: uri, token: token) }
+
+ describe '#get' do
+ let(:response_double) { double(code: 200, success?: true, parsed_response: {}) }
+
+ shared_examples 'performs network request' do
+ it 'performs network request' do
+ expect(Gitlab::HTTP).to receive(:get).with(*expected_args).and_return(response_double)
+
+ subject.get(resource)
+ end
+ end
+
+ describe 'parsed response' do
+ it 'returns parsed response' do
+ response_double = double(code: 200, success?: true, parsed_response: [{ id: 1 }, { id: 2 }])
+
+ allow(Gitlab::HTTP).to receive(:get).and_return(response_double)
+
+ expect(subject.get(resource)).to eq(response_double.parsed_response)
+ end
+ end
+
+ describe 'request query' do
+ include_examples 'performs network request' do
+ let(:expected_args) do
+ [
+ anything,
+ hash_including(
+ query: {
+ page: described_class::DEFAULT_PAGE,
+ per_page: described_class::DEFAULT_PER_PAGE
+ }
+ )
+ ]
+ end
+ end
+ end
+
+ describe 'request headers' do
+ include_examples 'performs network request' do
+ let(:expected_args) do
+ [
+ anything,
+ hash_including(
+ headers: {
+ 'Content-Type' => 'application/json',
+ 'Authorization' => "Bearer #{token}"
+ }
+ )
+ ]
+ end
+ end
+ end
+
+ describe 'request uri' do
+ include_examples 'performs network request' do
+ let(:expected_args) do
+ ['http://gitlab.example:80/api/v4/resource', anything]
+ end
+ end
+ end
+
+ context 'error handling' do
+ context 'when error occurred' do
+ it 'raises ConnectionError' do
+ allow(Gitlab::HTTP).to receive(:get).and_raise(Errno::ECONNREFUSED)
+
+ expect { subject.get(resource) }.to raise_exception(described_class::ConnectionError)
+ end
+ end
+
+ context 'when response is not success' do
+ it 'raises ConnectionError' do
+ response_double = double(code: 503, success?: false)
+
+ allow(Gitlab::HTTP).to receive(:get).and_return(response_double)
+
+ expect { subject.get(resource) }.to raise_exception(described_class::ConnectionError)
+ end
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/checks/matching_merge_request_spec.rb b/spec/lib/gitlab/checks/matching_merge_request_spec.rb
new file mode 100644
index 00000000000..ca7ee784ee3
--- /dev/null
+++ b/spec/lib/gitlab/checks/matching_merge_request_spec.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Checks::MatchingMergeRequest do
+ describe '#match?' do
+ let_it_be(:newrev) { '012345678' }
+ let_it_be(:target_branch) { 'feature' }
+ let_it_be(:project) { create(:project, :repository) }
+ let_it_be(:locked_merge_request) do
+ create(:merge_request,
+ :locked,
+ source_project: project,
+ target_project: project,
+ target_branch: target_branch,
+ in_progress_merge_commit_sha: newrev)
+ end
+
+ subject { described_class.new(newrev, target_branch, project) }
+
+ it 'matches a merge request' do
+ expect(subject.match?).to be true
+ end
+
+ it 'does not match any merge request' do
+ matcher = described_class.new(newrev, 'test', project)
+
+ expect(matcher.match?).to be false
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/ansi2json/line_spec.rb b/spec/lib/gitlab/ci/ansi2json/line_spec.rb
index 8b1cd812a70..d681447a0e8 100644
--- a/spec/lib/gitlab/ci/ansi2json/line_spec.rb
+++ b/spec/lib/gitlab/ci/ansi2json/line_spec.rb
@@ -58,6 +58,15 @@ RSpec.describe Gitlab::Ci::Ansi2json::Line do
end
end
+ describe '#set_section_options' do
+ it 'sets the current section\'s options' do
+ options = { collapsed: true }
+ subject.set_section_options(options)
+
+ expect(subject.to_h[:section_options]).to eq(options)
+ end
+ end
+
describe '#set_as_section_header' do
it 'change the section_header to true' do
expect { subject.set_as_section_header }
diff --git a/spec/lib/gitlab/ci/ansi2json_spec.rb b/spec/lib/gitlab/ci/ansi2json_spec.rb
index cb6949fddc2..c9c0d1a744e 100644
--- a/spec/lib/gitlab/ci/ansi2json_spec.rb
+++ b/spec/lib/gitlab/ci/ansi2json_spec.rb
@@ -229,7 +229,7 @@ RSpec.describe Gitlab::Ci::Ansi2json do
expect(convert_json(trace)).to eq([
{
offset: 0,
- content: [{ text: "section_end:1:2<div>hello</div>" }],
+ content: [{ text: 'section_end:1:2<div>hello</div>' }],
section: 'prepare-script',
section_header: true
},
@@ -329,6 +329,32 @@ RSpec.describe Gitlab::Ci::Ansi2json do
])
end
end
+
+ context 'with section options' do
+ let(:option_section_start) { "section_start:#{section_start_time.to_i}:#{section_name}[collapsed=true,unused_option=123]\r\033[0K"}
+
+ it 'provides section options when set' do
+ trace = "#{option_section_start}hello#{section_end}"
+ expect(convert_json(trace)).to eq([
+ {
+ offset: 0,
+ content: [{ text: 'hello' }],
+ section: 'prepare-script',
+ section_header: true,
+ section_options: {
+ 'collapsed' => 'true',
+ 'unused_option' => '123'
+ }
+ },
+ {
+ offset: 83,
+ content: [],
+ section: 'prepare-script',
+ section_duration: '01:03'
+ }
+ ])
+ end
+ end
end
describe 'incremental updates' do
@@ -339,7 +365,7 @@ RSpec.describe Gitlab::Ci::Ansi2json do
context 'with split word' do
let(:pre_text) { "\e[1mHello " }
- let(:text) { "World" }
+ let(:text) { 'World' }
let(:lines) do
[
@@ -355,7 +381,7 @@ RSpec.describe Gitlab::Ci::Ansi2json do
context 'with split word on second line' do
let(:pre_text) { "Good\nmorning " }
- let(:text) { "World" }
+ let(:text) { 'World' }
let(:lines) do
[
@@ -514,7 +540,7 @@ RSpec.describe Gitlab::Ci::Ansi2json do
end
describe 'trucates' do
- let(:text) { "Hello World" }
+ let(:text) { 'Hello World' }
let(:stream) { StringIO.new(text) }
let(:subject) { described_class.convert(stream) }
@@ -522,11 +548,11 @@ RSpec.describe Gitlab::Ci::Ansi2json do
stream.seek(3, IO::SEEK_SET)
end
- it "returns truncated output" do
+ it 'returns truncated output' do
expect(subject.truncated).to be_truthy
end
- it "does not append output" do
+ it 'does not append output' do
expect(subject.append).to be_falsey
end
end
diff --git a/spec/lib/gitlab/ci/artifact_file_reader_spec.rb b/spec/lib/gitlab/ci/artifact_file_reader_spec.rb
index 83a37655ea9..e982f0eb015 100644
--- a/spec/lib/gitlab/ci/artifact_file_reader_spec.rb
+++ b/spec/lib/gitlab/ci/artifact_file_reader_spec.rb
@@ -18,17 +18,6 @@ RSpec.describe Gitlab::Ci::ArtifactFileReader do
expect(YAML.safe_load(subject).keys).to contain_exactly('rspec', 'time', 'custom')
end
- context 'when FF ci_new_artifact_file_reader is disabled' do
- before do
- stub_feature_flags(ci_new_artifact_file_reader: false)
- end
-
- it 'returns the content at the path' do
- is_expected.to be_present
- expect(YAML.safe_load(subject).keys).to contain_exactly('rspec', 'time', 'custom')
- end
- end
-
context 'when path does not exist' do
let(:path) { 'file/does/not/exist.txt' }
let(:expected_error) do
diff --git a/spec/lib/gitlab/ci/config/entry/bridge_spec.rb b/spec/lib/gitlab/ci/config/entry/bridge_spec.rb
index f33176c3da3..8b2e0410474 100644
--- a/spec/lib/gitlab/ci/config/entry/bridge_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/bridge_spec.rb
@@ -228,4 +228,66 @@ RSpec.describe Gitlab::Ci::Config::Entry::Bridge do
end
end
end
+
+ describe '#manual_action?' do
+ context 'when job is a manual action' do
+ let(:config) { { script: 'deploy', when: 'manual' } }
+
+ it { is_expected.to be_manual_action }
+ end
+
+ context 'when job is not a manual action' do
+ let(:config) { { script: 'deploy' } }
+
+ it { is_expected.not_to be_manual_action }
+ end
+ end
+
+ describe '#ignored?' do
+ context 'when job is a manual action' do
+ context 'when it is not specified if job is allowed to fail' do
+ let(:config) do
+ { script: 'deploy', when: 'manual' }
+ end
+
+ it { is_expected.to be_ignored }
+ end
+
+ context 'when job is allowed to fail' do
+ let(:config) do
+ { script: 'deploy', when: 'manual', allow_failure: true }
+ end
+
+ it { is_expected.to be_ignored }
+ end
+
+ context 'when job is not allowed to fail' do
+ let(:config) do
+ { script: 'deploy', when: 'manual', allow_failure: false }
+ end
+
+ it { is_expected.not_to be_ignored }
+ end
+ end
+
+ context 'when job is not a manual action' do
+ context 'when it is not specified if job is allowed to fail' do
+ let(:config) { { script: 'deploy' } }
+
+ it { is_expected.not_to be_ignored }
+ end
+
+ context 'when job is allowed to fail' do
+ let(:config) { { script: 'deploy', allow_failure: true } }
+
+ it { is_expected.to be_ignored }
+ end
+
+ context 'when job is not allowed to fail' do
+ let(:config) { { script: 'deploy', allow_failure: false } }
+
+ it { is_expected.not_to be_ignored }
+ end
+ end
+ end
end
diff --git a/spec/lib/gitlab/ci/config/entry/cache_spec.rb b/spec/lib/gitlab/ci/config/entry/cache_spec.rb
index 3501812b76e..80427eaa6ee 100644
--- a/spec/lib/gitlab/ci/config/entry/cache_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/cache_spec.rb
@@ -13,18 +13,23 @@ RSpec.describe Gitlab::Ci::Config::Entry::Cache do
context 'when entry config value is correct' do
let(:policy) { nil }
let(:key) { 'some key' }
+ let(:when_config) { nil }
let(:config) do
- { key: key,
+ {
+ key: key,
untracked: true,
- paths: ['some/path/'],
- policy: policy }
+ paths: ['some/path/']
+ }.tap do |config|
+ config[:policy] = policy if policy
+ config[:when] = when_config if when_config
+ end
end
describe '#value' do
shared_examples 'hash key value' do
it 'returns hash value' do
- expect(entry.value).to eq(key: key, untracked: true, paths: ['some/path/'], policy: 'pull-push')
+ expect(entry.value).to eq(key: key, untracked: true, paths: ['some/path/'], policy: 'pull-push', when: 'on_success')
end
end
@@ -49,6 +54,48 @@ RSpec.describe Gitlab::Ci::Config::Entry::Cache do
expect(entry.value).to match(a_hash_including(key: nil))
end
end
+
+ context 'with `policy`' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:policy, :result) do
+ 'pull-push' | 'pull-push'
+ 'push' | 'push'
+ 'pull' | 'pull'
+ 'unknown' | 'unknown' # invalid
+ end
+
+ with_them do
+ it { expect(entry.value).to include(policy: result) }
+ end
+ end
+
+ context 'without `policy`' do
+ it 'assigns policy to default' do
+ expect(entry.value).to include(policy: 'pull-push')
+ end
+ end
+
+ context 'with `when`' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:when_config, :result) do
+ 'on_success' | 'on_success'
+ 'on_failure' | 'on_failure'
+ 'always' | 'always'
+ 'unknown' | 'unknown' # invalid
+ end
+
+ with_them do
+ it { expect(entry.value).to include(when: result) }
+ end
+ end
+
+ context 'without `when`' do
+ it 'assigns when to default' do
+ expect(entry.value).to include(when: 'on_success')
+ end
+ end
end
describe '#valid?' do
@@ -61,28 +108,41 @@ RSpec.describe Gitlab::Ci::Config::Entry::Cache do
end
end
- context 'policy is pull-push' do
- let(:policy) { 'pull-push' }
+ context 'with `policy`' do
+ using RSpec::Parameterized::TableSyntax
- it { is_expected.to be_valid }
- it { expect(entry.value).to include(policy: 'pull-push') }
- end
-
- context 'policy is push' do
- let(:policy) { 'push' }
+ where(:policy, :valid) do
+ 'pull-push' | true
+ 'push' | true
+ 'pull' | true
+ 'unknown' | false
+ end
- it { is_expected.to be_valid }
- it { expect(entry.value).to include(policy: 'push') }
+ with_them do
+ it 'returns expected validity' do
+ expect(entry.valid?).to eq(valid)
+ end
+ end
end
- context 'policy is pull' do
- let(:policy) { 'pull' }
+ context 'with `when`' do
+ using RSpec::Parameterized::TableSyntax
- it { is_expected.to be_valid }
- it { expect(entry.value).to include(policy: 'pull') }
+ where(:when_config, :valid) do
+ 'on_success' | true
+ 'on_failure' | true
+ 'always' | true
+ 'unknown' | false
+ end
+
+ with_them do
+ it 'returns expected validity' do
+ expect(entry.valid?).to eq(valid)
+ end
+ end
end
- context 'when key is missing' do
+ context 'with key missing' do
let(:config) do
{ untracked: true,
paths: ['some/path/'] }
@@ -110,13 +170,21 @@ RSpec.describe Gitlab::Ci::Config::Entry::Cache do
end
context 'when policy is unknown' do
- let(:config) { { policy: "unknown" } }
+ let(:config) { { policy: 'unknown' } }
it 'reports error' do
is_expected.to include('cache policy should be pull-push, push, or pull')
end
end
+ context 'when `when` is unknown' do
+ let(:config) { { when: 'unknown' } }
+
+ it 'reports error' do
+ is_expected.to include('cache when should be on_success, on_failure or always')
+ end
+ end
+
context 'when descendants are invalid' do
context 'with invalid keys' do
let(:config) { { key: 1 } }
diff --git a/spec/lib/gitlab/ci/config/entry/include_spec.rb b/spec/lib/gitlab/ci/config/entry/include_spec.rb
index 3e816f70c03..59f0b0e7a48 100644
--- a/spec/lib/gitlab/ci/config/entry/include_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/include_spec.rb
@@ -61,6 +61,31 @@ RSpec.describe ::Gitlab::Ci::Config::Entry::Include do
end
end
end
+
+ context 'when using "project"' do
+ context 'and specifying "ref" and "file"' do
+ let(:config) { { project: 'my-group/my-pipeline-library', ref: 'master', file: 'test.yml' } }
+
+ it { is_expected.to be_valid }
+ end
+
+ context 'without "ref"' do
+ let(:config) { { project: 'my-group/my-pipeline-library', file: 'test.yml' } }
+
+ it { is_expected.to be_valid }
+ end
+
+ context 'without "file"' do
+ let(:config) { { project: 'my-group/my-pipeline-library' } }
+
+ it { is_expected.not_to be_valid }
+
+ it 'has specific error' do
+ expect(include_entry.errors)
+ .to include('include config must specify the file where to fetch the config from')
+ end
+ end
+ end
end
context 'when value is something else' do
diff --git a/spec/lib/gitlab/ci/config/entry/job_spec.rb b/spec/lib/gitlab/ci/config/entry/job_spec.rb
index ab760b107f8..e0e8bc93770 100644
--- a/spec/lib/gitlab/ci/config/entry/job_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/job_spec.rb
@@ -537,7 +537,7 @@ RSpec.describe Gitlab::Ci::Config::Entry::Job do
it 'overrides default config' do
expect(entry[:image].value).to eq(name: 'some_image')
- expect(entry[:cache].value).to eq(key: 'test', policy: 'pull-push')
+ expect(entry[:cache].value).to eq(key: 'test', policy: 'pull-push', when: 'on_success')
end
end
@@ -552,7 +552,7 @@ RSpec.describe Gitlab::Ci::Config::Entry::Job do
it 'uses config from default entry' do
expect(entry[:image].value).to eq 'specified'
- expect(entry[:cache].value).to eq(key: 'test', policy: 'pull-push')
+ expect(entry[:cache].value).to eq(key: 'test', policy: 'pull-push', when: 'on_success')
end
end
diff --git a/spec/lib/gitlab/ci/config/entry/product/matrix_spec.rb b/spec/lib/gitlab/ci/config/entry/product/matrix_spec.rb
index 39697884e3b..3388ae0af2f 100644
--- a/spec/lib/gitlab/ci/config/entry/product/matrix_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/product/matrix_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'fast_spec_helper'
+require 'spec_helper'
require_dependency 'active_model'
RSpec.describe ::Gitlab::Ci::Config::Entry::Product::Matrix do
@@ -46,33 +46,140 @@ RSpec.describe ::Gitlab::Ci::Config::Entry::Product::Matrix do
end
end
- context 'when entry config has only one variable' do
- let(:config) do
- [
- {
- 'VAR_1' => %w[test]
- }
- ]
+ context 'with one_dimensional_matrix feature flag enabled' do
+ before do
+ stub_feature_flags(one_dimensional_matrix: true)
+ matrix.compose!
end
- describe '#valid?' do
- it { is_expected.not_to be_valid }
- end
+ context 'when entry config has only one variable with multiple values' do
+ let(:config) do
+ [
+ {
+ 'VAR_1' => %w[build test]
+ }
+ ]
+ end
- describe '#errors' do
- it 'returns error about too many jobs' do
- expect(matrix.errors)
- .to include('variables config requires at least 2 items')
+ describe '#valid?' do
+ it { is_expected.to be_valid }
+ end
+
+ describe '#errors' do
+ it 'returns no errors' do
+ expect(matrix.errors)
+ .to be_empty
+ end
+ end
+
+ describe '#value' do
+ before do
+ matrix.compose!
+ end
+
+ it 'returns the value without raising an error' do
+ expect(matrix.value).to eq([{ 'VAR_1' => %w[build test] }])
+ end
end
+
+ context 'when entry config has only one variable with one value' do
+ let(:config) do
+ [
+ {
+ 'VAR_1' => %w[test]
+ }
+ ]
+ end
+
+ describe '#valid?' do
+ it { is_expected.to be_valid }
+ end
+
+ describe '#errors' do
+ it 'returns no errors' do
+ expect(matrix.errors)
+ .to be_empty
+ end
+ end
+
+ describe '#value' do
+ before do
+ matrix.compose!
+ end
+
+ it 'returns the value without raising an error' do
+ expect(matrix.value).to eq([{ 'VAR_1' => %w[test] }])
+ end
+ end
+ end
+ end
+ end
+
+ context 'with one_dimensional_matrix feature flag disabled' do
+ before do
+ stub_feature_flags(one_dimensional_matrix: false)
+ matrix.compose!
end
- describe '#value' do
- before do
- matrix.compose!
+ context 'when entry config has only one variable with multiple values' do
+ let(:config) do
+ [
+ {
+ 'VAR_1' => %w[build test]
+ }
+ ]
end
- it 'returns the value without raising an error' do
- expect(matrix.value).to eq([{ 'VAR_1' => ['test'] }])
+ describe '#valid?' do
+ it { is_expected.not_to be_valid }
+ end
+
+ describe '#errors' do
+ it 'returns error about too many jobs' do
+ expect(matrix.errors)
+ .to include('variables config requires at least 2 items')
+ end
+ end
+
+ describe '#value' do
+ before do
+ matrix.compose!
+ end
+
+ it 'returns the value without raising an error' do
+ expect(matrix.value).to eq([{ 'VAR_1' => %w[build test] }])
+ end
+ end
+
+ context 'when entry config has only one variable with one value' do
+ let(:config) do
+ [
+ {
+ 'VAR_1' => %w[test]
+ }
+ ]
+ end
+
+ describe '#valid?' do
+ it { is_expected.not_to be_valid }
+ end
+
+ describe '#errors' do
+ it 'returns no errors' do
+ expect(matrix.errors)
+ .to include('variables config requires at least 2 items')
+ end
+ end
+
+ describe '#value' do
+ before do
+ matrix.compose!
+ end
+
+ it 'returns the value without raising an error' do
+ expect(matrix.value).to eq([{ 'VAR_1' => %w[test] }])
+ end
+ end
end
end
end
diff --git a/spec/lib/gitlab/ci/config/entry/product/variables_spec.rb b/spec/lib/gitlab/ci/config/entry/product/variables_spec.rb
index 230b001d620..407efb438b5 100644
--- a/spec/lib/gitlab/ci/config/entry/product/variables_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/product/variables_spec.rb
@@ -1,6 +1,7 @@
# frozen_string_literal: true
-require 'fast_spec_helper'
+# After Feature one_dimensional_matrix is removed, this can be changed back to fast_spec_helper
+require 'spec_helper'
require_dependency 'active_model'
RSpec.describe Gitlab::Ci::Config::Entry::Product::Variables do
@@ -45,43 +46,71 @@ RSpec.describe Gitlab::Ci::Config::Entry::Product::Variables do
end
end
- context 'when entry value is not correct' do
- shared_examples 'invalid variables' do |message|
- describe '#errors' do
- it 'saves errors' do
- expect(entry.errors).to include(message)
- end
+ context 'with one_dimensional_matrix feature flag enabled' do
+ context 'with only one variable' do
+ before do
+ stub_feature_flags(one_dimensional_matrix: true)
end
+ let(:config) { { VAR: 'test' } }
describe '#valid?' do
- it 'is not valid' do
- expect(entry).not_to be_valid
+ it 'is valid' do
+ expect(entry).to be_valid
+ end
+ end
+
+ describe '#errors' do
+ it 'does not append errors' do
+ expect(entry.errors).to be_empty
end
end
end
+ end
- context 'with array' do
- let(:config) { [:VAR, 'test'] }
+ context 'with one_dimensional_matrix feature flag disabled' do
+ context 'when entry value is not correct' do
+ before do
+ stub_feature_flags(one_dimensional_matrix: false)
+ end
+ shared_examples 'invalid variables' do |message|
+ describe '#errors' do
+ it 'saves errors' do
+ expect(entry.errors).to include(message)
+ end
+ end
- it_behaves_like 'invalid variables', /should be a hash of key value pairs/
- end
+ describe '#valid?' do
+ it 'is not valid' do
+ expect(entry).not_to be_valid
+ end
+ end
+ end
- context 'with empty array' do
- let(:config) { { VAR: 'test', VAR2: [] } }
+ context 'with array' do
+ let(:config) { [:VAR, 'test'] }
- it_behaves_like 'invalid variables', /should be a hash of key value pairs/
- end
+ it_behaves_like 'invalid variables', /should be a hash of key value pairs/
+ end
- context 'with nested array' do
- let(:config) { { VAR: 'test', VAR2: [1, [2]] } }
+ context 'with empty array' do
+ let(:config) { { VAR: 'test', VAR2: [] } }
- it_behaves_like 'invalid variables', /should be a hash of key value pairs/
- end
+ it_behaves_like 'invalid variables', /should be a hash of key value pairs/
+ end
- context 'with only one variable' do
- let(:config) { { VAR: 'test' } }
+ context 'with nested array' do
+ let(:config) { { VAR: 'test', VAR2: [1, [2]] } }
+
+ it_behaves_like 'invalid variables', /should be a hash of key value pairs/
+ end
- it_behaves_like 'invalid variables', /variables config requires at least 2 items/
+ context 'with one_dimensional_matrix feature flag disabled' do
+ context 'with only one variable' do
+ let(:config) { { VAR: 'test' } }
+
+ it_behaves_like 'invalid variables', /variables config requires at least 2 items/
+ 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 252bda6461d..79716df6b60 100644
--- a/spec/lib/gitlab/ci/config/entry/root_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/root_spec.rb
@@ -127,7 +127,7 @@ RSpec.describe Gitlab::Ci::Config::Entry::Root do
image: { name: 'ruby:2.7' },
services: [{ name: 'postgres:9.1' }, { name: 'mysql:5.5' }],
stage: 'test',
- cache: { key: 'k', untracked: true, paths: ['public/'], policy: 'pull-push' },
+ cache: { key: 'k', untracked: true, paths: ['public/'], policy: 'pull-push', when: 'on_success' },
variables: { 'VAR' => 'root' },
ignore: false,
after_script: ['make clean'],
@@ -141,7 +141,7 @@ RSpec.describe Gitlab::Ci::Config::Entry::Root do
image: { name: 'ruby:2.7' },
services: [{ name: 'postgres:9.1' }, { name: 'mysql:5.5' }],
stage: 'test',
- cache: { key: 'k', untracked: true, paths: ['public/'], policy: 'pull-push' },
+ cache: { key: 'k', untracked: true, paths: ['public/'], policy: 'pull-push', when: 'on_success' },
variables: { 'VAR' => 'root' },
ignore: false,
after_script: ['make clean'],
@@ -156,7 +156,7 @@ RSpec.describe Gitlab::Ci::Config::Entry::Root do
release: { name: "Release $CI_TAG_NAME", tag_name: 'v0.06', description: "./release_changelog.txt" },
image: { name: "ruby:2.7" },
services: [{ name: "postgres:9.1" }, { name: "mysql:5.5" }],
- cache: { key: "k", untracked: true, paths: ["public/"], policy: "pull-push" },
+ cache: { key: "k", untracked: true, paths: ["public/"], policy: "pull-push", when: 'on_success' },
only: { refs: %w(branches tags) },
variables: { 'VAR' => 'job' },
after_script: [],
@@ -203,7 +203,7 @@ RSpec.describe Gitlab::Ci::Config::Entry::Root do
image: { name: 'ruby:2.7' },
services: [{ name: 'postgres:9.1' }, { name: 'mysql:5.5' }],
stage: 'test',
- cache: { key: 'k', untracked: true, paths: ['public/'], policy: "pull-push" },
+ cache: { key: 'k', untracked: true, paths: ['public/'], policy: 'pull-push', when: 'on_success' },
variables: { 'VAR' => 'root' },
ignore: false,
after_script: ['make clean'],
@@ -215,7 +215,7 @@ RSpec.describe Gitlab::Ci::Config::Entry::Root do
image: { name: 'ruby:2.7' },
services: [{ name: 'postgres:9.1' }, { name: 'mysql:5.5' }],
stage: 'test',
- cache: { key: 'k', untracked: true, paths: ['public/'], policy: "pull-push" },
+ cache: { key: 'k', untracked: true, paths: ['public/'], policy: 'pull-push', when: 'on_success' },
variables: { 'VAR' => 'job' },
ignore: false,
after_script: ['make clean'],
@@ -261,7 +261,7 @@ RSpec.describe Gitlab::Ci::Config::Entry::Root do
describe '#cache_value' do
it 'returns correct cache definition' do
- expect(root.cache_value).to eq(key: 'a', policy: 'pull-push')
+ expect(root.cache_value).to eq(key: 'a', policy: 'pull-push', when: 'on_success')
end
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 d6391092f63..ac33f858f43 100644
--- a/spec/lib/gitlab/ci/config/entry/variables_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/variables_spec.rb
@@ -3,56 +3,109 @@
require 'spec_helper'
RSpec.describe Gitlab::Ci::Config::Entry::Variables do
- let(:entry) { described_class.new(config) }
+ subject { described_class.new(config) }
- describe 'validations' do
- context 'when entry config value is correct' do
- let(:config) do
- { 'VARIABLE_1' => 'value 1', 'VARIABLE_2' => 'value 2' }
+ shared_examples 'valid config' do
+ describe '#value' do
+ it 'returns hash with key value strings' do
+ expect(subject.value).to eq result
end
+ end
- describe '#value' do
- it 'returns hash with key value strings' do
- expect(entry.value).to eq config
- end
-
- context 'with numeric keys and values in the config' do
- let(:config) { { 10 => 20 } }
+ describe '#errors' do
+ it 'does not append errors' do
+ expect(subject.errors).to be_empty
+ end
+ end
- it 'converts numeric key and numeric value into strings' do
- expect(entry.value).to eq('10' => '20')
- end
- end
+ describe '#valid?' do
+ it 'is valid' do
+ expect(subject).to be_valid
end
+ end
+ end
- describe '#errors' do
- it 'does not append errors' do
- expect(entry.errors).to be_empty
- end
+ shared_examples 'invalid config' do
+ describe '#valid?' do
+ it 'is not valid' do
+ expect(subject).not_to be_valid
end
+ end
- describe '#valid?' do
- it 'is valid' do
- expect(entry).to be_valid
- end
+ describe '#errors' do
+ it 'saves errors' do
+ expect(subject.errors)
+ .to include /should be a hash of key value pairs/
end
end
+ end
- context 'when entry value is not correct' do
- let(:config) { [:VAR, 'test'] }
+ context 'when entry config value has key-value pairs' do
+ let(:config) do
+ { 'VARIABLE_1' => 'value 1', 'VARIABLE_2' => 'value 2' }
+ end
- describe '#errors' do
- it 'saves errors' do
- expect(entry.errors)
- .to include /should be a hash of key value pairs/
- end
- end
+ let(:result) do
+ { 'VARIABLE_1' => 'value 1', 'VARIABLE_2' => 'value 2' }
+ end
- describe '#valid?' do
- it 'is not valid' do
- expect(entry).not_to be_valid
- end
- end
+ it_behaves_like 'valid config'
+ end
+
+ context 'with numeric keys and values in the config' do
+ let(:config) { { 10 => 20 } }
+ let(:result) do
+ { '10' => '20' }
+ end
+
+ it_behaves_like 'valid config'
+ end
+
+ context 'when entry config value has key-value pair and hash' do
+ let(:config) do
+ { 'VARIABLE_1' => { value: 'value 1', description: 'variable 1' },
+ 'VARIABLE_2' => 'value 2' }
+ end
+
+ let(:result) do
+ { 'VARIABLE_1' => 'value 1', 'VARIABLE_2' => 'value 2' }
+ end
+
+ it_behaves_like 'valid config'
+ end
+
+ context 'when entry value is an array' do
+ let(:config) { [:VAR, 'test'] }
+
+ it_behaves_like 'invalid config'
+ end
+
+ context 'when entry value has hash with other key-pairs' do
+ let(:config) do
+ { 'VARIABLE_1' => { value: 'value 1', hello: 'variable 1' },
+ 'VARIABLE_2' => 'value 2' }
end
+
+ it_behaves_like 'invalid config'
+ end
+
+ context 'when entry config value has hash with nil description' do
+ let(:config) do
+ { 'VARIABLE_1' => { value: 'value 1', description: nil } }
+ end
+
+ it_behaves_like 'invalid config'
+ end
+
+ context 'when entry config value has hash without description' do
+ let(:config) do
+ { 'VARIABLE_1' => { value: 'value 1' } }
+ end
+
+ let(:result) do
+ { 'VARIABLE_1' => 'value 1' }
+ end
+
+ it_behaves_like 'valid config'
end
end
diff --git a/spec/lib/gitlab/ci/cron_parser_spec.rb b/spec/lib/gitlab/ci/cron_parser_spec.rb
index f724825a9cc..dd27b4045c9 100644
--- a/spec/lib/gitlab/ci/cron_parser_spec.rb
+++ b/spec/lib/gitlab/ci/cron_parser_spec.rb
@@ -82,7 +82,7 @@ RSpec.describe Gitlab::Ci::CronParser do
context 'when PST (Pacific Standard Time)' do
it 'converts time in server time zone' do
- Timecop.freeze(Time.utc(2017, 1, 1)) do
+ travel_to(Time.utc(2017, 1, 1)) do
expect(subject.hour).to eq(hour_in_utc)
end
end
@@ -90,7 +90,7 @@ RSpec.describe Gitlab::Ci::CronParser do
context 'when PDT (Pacific Daylight Time)' do
it 'converts time in server time zone' do
- Timecop.freeze(Time.utc(2017, 6, 1)) do
+ travel_to(Time.utc(2017, 6, 1)) do
expect(subject.hour).to eq(hour_in_utc)
end
end
@@ -117,7 +117,7 @@ RSpec.describe Gitlab::Ci::CronParser do
context 'when CET (Central European Time)' do
it 'converts time in server time zone' do
- Timecop.freeze(Time.utc(2017, 1, 1)) do
+ travel_to(Time.utc(2017, 1, 1)) do
expect(subject.hour).to eq(hour_in_utc)
end
end
@@ -125,7 +125,7 @@ RSpec.describe Gitlab::Ci::CronParser do
context 'when CEST (Central European Summer Time)' do
it 'converts time in server time zone' do
- Timecop.freeze(Time.utc(2017, 6, 1)) do
+ travel_to(Time.utc(2017, 6, 1)) do
expect(subject.hour).to eq(hour_in_utc)
end
end
@@ -152,7 +152,7 @@ RSpec.describe Gitlab::Ci::CronParser do
context 'when EST (Eastern Standard Time)' do
it 'converts time in server time zone' do
- Timecop.freeze(Time.utc(2017, 1, 1)) do
+ travel_to(Time.utc(2017, 1, 1)) do
expect(subject.hour).to eq(hour_in_utc)
end
end
@@ -160,7 +160,7 @@ RSpec.describe Gitlab::Ci::CronParser do
context 'when EDT (Eastern Daylight Time)' do
it 'converts time in server time zone' do
- Timecop.freeze(Time.utc(2017, 6, 1)) do
+ travel_to(Time.utc(2017, 6, 1)) do
expect(subject.hour).to eq(hour_in_utc)
end
end
@@ -174,7 +174,7 @@ RSpec.describe Gitlab::Ci::CronParser do
# (e.g. America/Chicago) at the start of the test. Stubbing
# TZ doesn't appear to be enough.
it 'generates day without TZInfo::AmbiguousTime error' do
- Timecop.freeze(Time.utc(2020, 1, 1)) do
+ travel_to(Time.utc(2020, 1, 1)) do
expect(subject.year).to eq(year)
expect(subject.month).to eq(12)
expect(subject.day).to eq(1)
diff --git a/spec/lib/gitlab/ci/lint_spec.rb b/spec/lib/gitlab/ci/lint_spec.rb
index 077c0fd3162..c67f8464123 100644
--- a/spec/lib/gitlab/ci/lint_spec.rb
+++ b/spec/lib/gitlab/ci/lint_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe Gitlab::Ci::Lint do
- let_it_be(:project) { create(:project, :repository) }
+ let(:project) { create(:project, :repository) }
let_it_be(:user) { create(:user) }
let(:lint) { described_class.new(project: project, current_user: user) }
@@ -61,6 +61,43 @@ RSpec.describe Gitlab::Ci::Lint do
end
end
+ shared_examples 'sets merged yaml' do
+ let(:content) do
+ <<~YAML
+ :include:
+ :local: another-gitlab-ci.yml
+ :test_job:
+ :stage: test
+ :script: echo
+ YAML
+ end
+
+ let(:included_content) do
+ <<~YAML
+ :another_job:
+ :script: echo
+ YAML
+ end
+
+ before do
+ project.repository.create_file(
+ project.creator,
+ 'another-gitlab-ci.yml',
+ included_content,
+ message: 'Automatically created another-gitlab-ci.yml',
+ branch_name: 'master'
+ )
+ end
+
+ it 'sets merged_config' do
+ root_config = YAML.safe_load(content, [Symbol])
+ included_config = YAML.safe_load(included_content, [Symbol])
+ expected_config = included_config.merge(root_config).except(:include)
+
+ expect(subject.merged_yaml).to eq(expected_config.to_yaml)
+ end
+ end
+
shared_examples 'content with errors and warnings' do
context 'when content has errors' do
let(:content) do
@@ -173,6 +210,8 @@ RSpec.describe Gitlab::Ci::Lint do
end
end
+ it_behaves_like 'sets merged yaml'
+
include_context 'advanced validations' do
it 'does not catch advanced logical errors' do
expect(subject).to be_valid
@@ -203,6 +242,8 @@ RSpec.describe Gitlab::Ci::Lint do
end
end
+ it_behaves_like 'sets merged yaml'
+
include_context 'advanced validations' do
it 'runs advanced logical validations' do
expect(subject).not_to be_valid
diff --git a/spec/lib/gitlab/ci/parsers/test/junit_spec.rb b/spec/lib/gitlab/ci/parsers/test/junit_spec.rb
index 1f497dea2bf..7da602251a5 100644
--- a/spec/lib/gitlab/ci/parsers/test/junit_spec.rb
+++ b/spec/lib/gitlab/ci/parsers/test/junit_spec.rb
@@ -4,11 +4,12 @@ require 'fast_spec_helper'
RSpec.describe Gitlab::Ci::Parsers::Test::Junit do
describe '#parse!' do
- subject { described_class.new.parse!(junit, test_suite, args) }
+ subject { described_class.new.parse!(junit, test_suite, job: job) }
let(:test_suite) { Gitlab::Ci::Reports::TestSuite.new('rspec') }
let(:test_cases) { flattened_test_cases(test_suite) }
- let(:args) { { job: { id: 1, project: "project" } } }
+ let(:job) { double(max_test_cases_per_report: max_test_cases) }
+ let(:max_test_cases) { 0 }
context 'when data is JUnit style XML' do
context 'when there are no <testcases> in <testsuite>' do
@@ -43,7 +44,7 @@ RSpec.describe Gitlab::Ci::Parsers::Test::Junit do
let(:junit) do
<<-EOF.strip_heredoc
<testsuites>
- <testsuite>
+ <testsuite name='Math'>
<testcase classname='Calculator' name='sumTest1' time='0.01'></testcase>
</testsuite>
</testsuites>
@@ -53,6 +54,7 @@ RSpec.describe Gitlab::Ci::Parsers::Test::Junit do
it 'parses XML and adds a test case to a suite' do
expect { subject }.not_to raise_error
+ expect(test_cases[0].suite_name).to eq('Math')
expect(test_cases[0].classname).to eq('Calculator')
expect(test_cases[0].name).to eq('sumTest1')
expect(test_cases[0].execution_time).to eq(0.01)
@@ -62,7 +64,7 @@ RSpec.describe Gitlab::Ci::Parsers::Test::Junit do
context 'when there is <testcase>' do
let(:junit) do
<<-EOF.strip_heredoc
- <testsuite>
+ <testsuite name='Math'>
<testcase classname='Calculator' name='sumTest1' time='0.01'>
#{testcase_content}
</testcase>
@@ -79,6 +81,7 @@ RSpec.describe Gitlab::Ci::Parsers::Test::Junit do
shared_examples_for '<testcase> XML parser' do |status, output|
it 'parses XML and adds a test case to the suite' do
aggregate_failures do
+ expect(test_case.suite_name).to eq('Math')
expect(test_case.classname).to eq('Calculator')
expect(test_case.name).to eq('sumTest1')
expect(test_case.execution_time).to eq(0.01)
@@ -152,13 +155,15 @@ RSpec.describe Gitlab::Ci::Parsers::Test::Junit do
expect { subject }.not_to raise_error
expect(test_cases.count).to eq(1)
+ expect(test_cases.first.suite_name).to eq("XXX\\FrontEnd\\WebBundle\\Tests\\Controller\\LogControllerTest")
+ expect(test_cases.first.name).to eq("testIndexAction")
end
end
context 'when there are two test cases' do
let(:junit) do
<<-EOF.strip_heredoc
- <testsuite>
+ <testsuite name='Math'>
<testcase classname='Calculator' name='sumTest1' time='0.01'></testcase>
<testcase classname='Calculator' name='sumTest2' time='0.02'></testcase>
</testsuite>
@@ -168,9 +173,11 @@ RSpec.describe Gitlab::Ci::Parsers::Test::Junit do
it 'parses XML and adds test cases to a suite' do
expect { subject }.not_to raise_error
+ expect(test_cases[0].suite_name).to eq('Math')
expect(test_cases[0].classname).to eq('Calculator')
expect(test_cases[0].name).to eq('sumTest1')
expect(test_cases[0].execution_time).to eq(0.01)
+ expect(test_cases[1].suite_name).to eq('Math')
expect(test_cases[1].classname).to eq('Calculator')
expect(test_cases[1].name).to eq('sumTest2')
expect(test_cases[1].execution_time).to eq(0.02)
@@ -181,7 +188,7 @@ RSpec.describe Gitlab::Ci::Parsers::Test::Junit do
let(:junit) do
<<-EOF.strip_heredoc
<testsuites>
- <testsuite>
+ <testsuite name='Math'>
<testcase classname='Calculator' name='sumTest1' time='0.01'></testcase>
<testcase classname='Calculator' name='sumTest2' time='0.02'></testcase>
</testsuite>
@@ -196,18 +203,81 @@ RSpec.describe Gitlab::Ci::Parsers::Test::Junit do
it 'parses XML and adds test cases to a suite' do
expect { subject }.not_to raise_error
- expect(test_cases[0].classname).to eq('Calculator')
- expect(test_cases[0].name).to eq('sumTest1')
- expect(test_cases[0].execution_time).to eq(0.01)
- expect(test_cases[1].classname).to eq('Calculator')
- expect(test_cases[1].name).to eq('sumTest2')
- expect(test_cases[1].execution_time).to eq(0.02)
- expect(test_cases[2].classname).to eq('Statemachine')
- expect(test_cases[2].name).to eq('happy path')
- expect(test_cases[2].execution_time).to eq(100)
- expect(test_cases[3].classname).to eq('Statemachine')
- expect(test_cases[3].name).to eq('unhappy path')
- expect(test_cases[3].execution_time).to eq(200)
+ expect(test_cases).to contain_exactly(
+ have_attributes(
+ suite_name: 'Math',
+ classname: 'Calculator',
+ name: 'sumTest1',
+ execution_time: 0.01
+ ),
+ have_attributes(
+ suite_name: 'Math',
+ classname: 'Calculator',
+ name: 'sumTest2',
+ execution_time: 0.02
+ ),
+ have_attributes(
+ suite_name: test_suite.name, # Defaults to test suite instance's name
+ classname: 'Statemachine',
+ name: 'happy path',
+ execution_time: 100
+ ),
+ have_attributes(
+ suite_name: test_suite.name, # Defaults to test suite instance's name
+ classname: 'Statemachine',
+ name: 'unhappy path',
+ execution_time: 200
+ )
+ )
+ end
+ end
+
+ context 'when number of test cases exceeds the max_test_cases limit' do
+ let(:max_test_cases) { 1 }
+
+ shared_examples_for 'rejecting too many test cases' do
+ it 'attaches an error to the TestSuite object' do
+ expect { subject }.not_to raise_error
+ expect(test_suite.suite_error).to eq("JUnit data parsing failed: number of test cases exceeded the limit of #{max_test_cases}")
+ end
+ end
+
+ context 'and test cases are unique' do
+ let(:junit) do
+ <<-EOF.strip_heredoc
+ <testsuites>
+ <testsuite>
+ <testcase classname='Calculator' name='sumTest1' time='0.01'></testcase>
+ <testcase classname='Calculator' name='sumTest2' time='0.02'></testcase>
+ </testsuite>
+ <testsuite>
+ <testcase classname='Statemachine' name='happy path' time='100'></testcase>
+ <testcase classname='Statemachine' name='unhappy path' time='200'></testcase>
+ </testsuite>
+ </testsuites>
+ EOF
+ end
+
+ it_behaves_like 'rejecting too many test cases'
+ end
+
+ context 'and test cases are duplicates' do
+ let(:junit) do
+ <<-EOF.strip_heredoc
+ <testsuites>
+ <testsuite>
+ <testcase classname='Calculator' name='sumTest1' time='0.01'></testcase>
+ <testcase classname='Calculator' name='sumTest2' time='0.02'></testcase>
+ </testsuite>
+ <testsuite>
+ <testcase classname='Calculator' name='sumTest1' time='0.01'></testcase>
+ <testcase classname='Calculator' name='sumTest2' time='0.02'></testcase>
+ </testsuite>
+ </testsuites>
+ EOF
+ end
+
+ it_behaves_like 'rejecting too many test cases'
end
end
end
@@ -296,9 +366,7 @@ RSpec.describe Gitlab::Ci::Parsers::Test::Junit do
expect(test_cases[0].has_attachment?).to be_truthy
expect(test_cases[0].attachment).to eq("some/path.png")
- expect(test_cases[0].job).to be_present
- expect(test_cases[0].job[:id]).to eq(1)
- expect(test_cases[0].job[:project]).to eq("project")
+ expect(test_cases[0].job).to eq(job)
end
end
diff --git a/spec/lib/gitlab/ci/pipeline/seed/build/cache_spec.rb b/spec/lib/gitlab/ci/pipeline/seed/build/cache_spec.rb
index 74c014b6408..570706bfaac 100644
--- a/spec/lib/gitlab/ci/pipeline/seed/build/cache_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/seed/build/cache_spec.rb
@@ -224,7 +224,8 @@ RSpec.describe Gitlab::Ci::Pipeline::Seed::Build::Cache do
key: 'a-key',
paths: ['vendor/ruby'],
untracked: true,
- policy: 'push'
+ policy: 'push',
+ when: 'on_success'
}
end
diff --git a/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb b/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb
index 34df0e86a18..0b961336f3f 100644
--- a/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb
@@ -3,9 +3,9 @@
require 'spec_helper'
RSpec.describe Gitlab::Ci::Pipeline::Seed::Build do
- let(:project) { create(:project, :repository) }
- let(:head_sha) { project.repository.head_commit.id }
- let(:pipeline) { create(:ci_empty_pipeline, project: project, sha: head_sha) }
+ let_it_be(:project) { create(:project, :repository) }
+ let_it_be(:head_sha) { project.repository.head_commit.id }
+ let(:pipeline) { build(:ci_empty_pipeline, project: project, sha: head_sha) }
let(:attributes) { { name: 'rspec', ref: 'master', scheduling_type: :stage } }
let(:previous_stages) { [] }
@@ -503,7 +503,7 @@ RSpec.describe Gitlab::Ci::Pipeline::Seed::Build do
using RSpec::Parameterized
let(:pipeline) do
- build(:ci_empty_pipeline, ref: 'deploy', tag: false, source: source)
+ build(:ci_empty_pipeline, ref: 'deploy', tag: false, source: source, project: project)
end
context 'matches' do
@@ -766,7 +766,7 @@ RSpec.describe Gitlab::Ci::Pipeline::Seed::Build do
context 'with a matching changes: rule' do
let(:pipeline) do
- create(:ci_pipeline, project: project).tap do |pipeline|
+ build(:ci_pipeline, project: project).tap do |pipeline|
stub_pipeline_modified_paths(pipeline, %w[app/models/ci/pipeline.rb spec/models/ci/pipeline_spec.rb .gitlab-ci.yml])
end
end
diff --git a/spec/lib/gitlab/ci/reports/test_case_spec.rb b/spec/lib/gitlab/ci/reports/test_case_spec.rb
index 7fb208213c1..a142846fc18 100644
--- a/spec/lib/gitlab/ci/reports/test_case_spec.rb
+++ b/spec/lib/gitlab/ci/reports/test_case_spec.rb
@@ -6,39 +6,26 @@ RSpec.describe Gitlab::Ci::Reports::TestCase do
describe '#initialize' do
let(:test_case) { described_class.new(params) }
- context 'when both classname and name are given' do
- context 'when test case is passed' do
- let(:job) { build(:ci_build) }
- let(:params) { attributes_for(:test_case).merge!(job: job) }
-
- it 'initializes an instance' do
- expect { test_case }.not_to raise_error
-
- expect(test_case.name).to eq('test-1')
- expect(test_case.classname).to eq('trace')
- expect(test_case.file).to eq('spec/trace_spec.rb')
- expect(test_case.execution_time).to eq(1.23)
- expect(test_case.status).to eq(described_class::STATUS_SUCCESS)
- expect(test_case.system_output).to be_nil
- expect(test_case.job).to be_present
- end
- end
+ context 'when required params are given' do
+ let(:job) { build(:ci_build) }
+ let(:params) { attributes_for(:test_case).merge!(job: job) }
- context 'when test case is failed' do
- let(:job) { build(:ci_build) }
- let(:params) { attributes_for(:test_case, :failed).merge!(job: job) }
-
- it 'initializes an instance' do
- expect { test_case }.not_to raise_error
-
- expect(test_case.name).to eq('test-1')
- expect(test_case.classname).to eq('trace')
- expect(test_case.file).to eq('spec/trace_spec.rb')
- expect(test_case.execution_time).to eq(1.23)
- expect(test_case.status).to eq(described_class::STATUS_FAILED)
- expect(test_case.system_output)
- .to eq('Failure/Error: is_expected.to eq(300) expected: 300 got: -100')
- end
+ it 'initializes an instance', :aggregate_failures do
+ expect { test_case }.not_to raise_error
+
+ expect(test_case).to have_attributes(
+ suite_name: params[:suite_name],
+ name: params[:name],
+ classname: params[:classname],
+ file: params[:file],
+ execution_time: params[:execution_time],
+ status: params[:status],
+ system_output: params[:system_output],
+ job: params[:job]
+ )
+
+ key = "#{test_case.suite_name}_#{test_case.classname}_#{test_case.name}"
+ expect(test_case.key).to eq(Digest::SHA256.hexdigest(key))
end
end
@@ -53,6 +40,10 @@ RSpec.describe Gitlab::Ci::Reports::TestCase do
end
end
+ context 'when suite_name is missing' do
+ it_behaves_like 'param is missing', :suite_name
+ end
+
context 'when classname is missing' do
it_behaves_like 'param is missing', :classname
end
diff --git a/spec/lib/gitlab/ci/reports/test_suite_spec.rb b/spec/lib/gitlab/ci/reports/test_suite_spec.rb
index 15fa78444e5..50d1595da73 100644
--- a/spec/lib/gitlab/ci/reports/test_suite_spec.rb
+++ b/spec/lib/gitlab/ci/reports/test_suite_spec.rb
@@ -229,6 +229,20 @@ RSpec.describe Gitlab::Ci::Reports::TestSuite do
end
end
+ describe '#each_test_case' do
+ before do
+ test_suite.add_test_case(test_case_success)
+ test_suite.add_test_case(test_case_failed)
+ test_suite.add_test_case(test_case_skipped)
+ test_suite.add_test_case(test_case_error)
+ end
+
+ it 'yields each test case to given block' do
+ expect { |b| test_suite.each_test_case(&b) }
+ .to yield_successive_args(test_case_success, test_case_failed, test_case_skipped, test_case_error)
+ end
+ end
+
Gitlab::Ci::Reports::TestCase::STATUS_TYPES.each do |status_type|
describe "##{status_type}_count" do
subject { test_suite.public_send("#{status_type}_count") }
diff --git a/spec/lib/gitlab/ci/runner/backoff_spec.rb b/spec/lib/gitlab/ci/runner/backoff_spec.rb
new file mode 100644
index 00000000000..f147d69f7cd
--- /dev/null
+++ b/spec/lib/gitlab/ci/runner/backoff_spec.rb
@@ -0,0 +1,126 @@
+# frozen_string_literal: true
+
+require 'fast_spec_helper'
+require 'rspec-parameterized'
+require 'active_support/testing/time_helpers'
+
+RSpec.describe Gitlab::Ci::Runner::Backoff do
+ include ActiveSupport::Testing::TimeHelpers
+
+ describe '#duration' do
+ it 'returns backoff duration from start' do
+ freeze_time do
+ described_class.new(5.minutes.ago).then do |backoff|
+ expect(backoff.duration).to eq 5.minutes
+ end
+ end
+ end
+
+ it 'returns an integer value' do
+ freeze_time do
+ described_class.new(5.seconds.ago).then do |backoff|
+ expect(backoff.duration).to be 5
+ end
+ end
+ end
+
+ it 'returns the smallest number greater than or equal to duration' do
+ freeze_time do
+ described_class.new(0.5.seconds.ago).then do |backoff|
+ expect(backoff.duration).to be 1
+ end
+ end
+ end
+ end
+
+ describe '#slot' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:started, :slot) do
+ 0 | 0
+ 0.1 | 0
+ 0.9 | 0
+ 1 | 0
+ 1.1 | 0
+ 1.9 | 0
+ 2 | 0
+ 2.9 | 0
+ 3 | 0
+ 4 | 1
+ 5 | 1
+ 6 | 1
+ 7 | 1
+ 8 | 2
+ 9 | 2
+ 9.9 | 2
+ 10 | 2
+ 15 | 2
+ 16 | 3
+ 31 | 3
+ 32 | 4
+ 63 | 4
+ 64 | 5
+ 127 | 5
+ 128 | 6
+ 250 | 6
+ 310 | 7
+ 520 | 8
+ 999 | 8
+ end
+
+ with_them do
+ it 'falls into an appropaite backoff slot' do
+ freeze_time do
+ backoff = described_class.new(started.seconds.ago)
+ expect(backoff.slot).to eq slot
+ end
+ end
+ end
+ end
+
+ describe '#to_seconds' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:started, :backoff) do
+ 0 | 1
+ 0.1 | 1
+ 0.9 | 1
+ 1 | 1
+ 1.1 | 1
+ 1.9 | 1
+ 2 | 1
+ 3 | 1
+ 4 | 2
+ 5 | 2
+ 6 | 2
+ 6.5 | 2
+ 7 | 2
+ 8 | 4
+ 9 | 4
+ 9.9 | 4
+ 10 | 4
+ 15 | 4
+ 16 | 8
+ 31 | 8
+ 32 | 16
+ 63 | 16
+ 64 | 32
+ 127 | 32
+ 128 | 64
+ 250 | 64
+ 310 | 64
+ 520 | 64
+ 999 | 64
+ end
+
+ with_them do
+ it 'calculates backoff based on an appropriate slot' do
+ freeze_time do
+ described_class.new(started.seconds.ago).then do |delay|
+ expect(delay.to_seconds).to eq backoff
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/status/bridge/common_spec.rb b/spec/lib/gitlab/ci/status/bridge/common_spec.rb
index 92600b21afc..37524afc83d 100644
--- a/spec/lib/gitlab/ci/status/bridge/common_spec.rb
+++ b/spec/lib/gitlab/ci/status/bridge/common_spec.rb
@@ -30,15 +30,6 @@ RSpec.describe Gitlab::Ci::Status::Bridge::Common do
it { expect(subject).to have_details }
it { expect(subject.details_path).to include "pipelines/#{downstream_pipeline.id}" }
-
- context 'when ci_bridge_pipeline_details is disabled' do
- before do
- stub_feature_flags(ci_bridge_pipeline_details: false)
- end
-
- it { expect(subject).not_to have_details }
- it { expect(subject.details_path).to be_nil }
- end
end
context 'when user does not have access to read downstream pipeline' do
diff --git a/spec/lib/gitlab/ci/status/bridge/factory_spec.rb b/spec/lib/gitlab/ci/status/bridge/factory_spec.rb
index 021b777a0ff..d27bb98ba9a 100644
--- a/spec/lib/gitlab/ci/status/bridge/factory_spec.rb
+++ b/spec/lib/gitlab/ci/status/bridge/factory_spec.rb
@@ -15,7 +15,7 @@ RSpec.describe Gitlab::Ci::Status::Bridge::Factory do
end
context 'when bridge is created' do
- let(:bridge) { create(:ci_bridge) }
+ let(:bridge) { create_bridge(:created) }
it 'matches correct core status' do
expect(factory.core_status).to be_a Gitlab::Ci::Status::Created
@@ -32,7 +32,7 @@ RSpec.describe Gitlab::Ci::Status::Bridge::Factory do
end
context 'when bridge is failed' do
- let(:bridge) { create(:ci_bridge, :failed) }
+ let(:bridge) { create_bridge(:failed) }
it 'matches correct core status' do
expect(factory.core_status).to be_a Gitlab::Ci::Status::Failed
@@ -70,4 +70,61 @@ RSpec.describe Gitlab::Ci::Status::Bridge::Factory do
end
end
end
+
+ context 'when bridge is a manual action' do
+ let(:bridge) { create_bridge(:playable) }
+
+ it 'matches correct core status' do
+ expect(factory.core_status).to be_a Gitlab::Ci::Status::Manual
+ end
+
+ it 'matches correct extended statuses' do
+ expect(factory.extended_statuses)
+ .to eq [Gitlab::Ci::Status::Bridge::Manual,
+ Gitlab::Ci::Status::Bridge::Play,
+ Gitlab::Ci::Status::Bridge::Action]
+ end
+
+ it 'fabricates action detailed status' do
+ expect(status).to be_a Gitlab::Ci::Status::Bridge::Action
+ end
+
+ it 'fabricates status with correct details' do
+ expect(status.text).to eq s_('CiStatusText|manual')
+ expect(status.group).to eq 'manual'
+ expect(status.icon).to eq 'status_manual'
+ expect(status.favicon).to eq 'favicon_status_manual'
+ expect(status.illustration).to include(:image, :size, :title, :content)
+ expect(status.label).to include 'manual play action'
+ expect(status).not_to have_details
+ expect(status.action_path).to include 'play'
+ end
+
+ context 'when user has ability to play action' do
+ before do
+ bridge.downstream_project.add_developer(user)
+ end
+
+ it 'fabricates status that has action' do
+ expect(status).to have_action
+ end
+ end
+
+ context 'when user does not have ability to play action' do
+ it 'fabricates status that has no action' do
+ expect(status).not_to have_action
+ end
+ end
+ end
+
+ private
+
+ def create_bridge(trait)
+ upstream_project = create(:project, :repository)
+ downstream_project = create(:project, :repository)
+ upstream_pipeline = create(:ci_pipeline, :running, project: upstream_project)
+ trigger = { trigger: { project: downstream_project.full_path, branch: 'feature' } }
+
+ create(:ci_bridge, trait, options: trigger, pipeline: upstream_pipeline)
+ end
end
diff --git a/spec/lib/gitlab/ci/status/canceled_spec.rb b/spec/lib/gitlab/ci/status/canceled_spec.rb
index a35efae5c57..7fae76f61ea 100644
--- a/spec/lib/gitlab/ci/status/canceled_spec.rb
+++ b/spec/lib/gitlab/ci/status/canceled_spec.rb
@@ -26,4 +26,8 @@ RSpec.describe Gitlab::Ci::Status::Canceled do
describe '#group' do
it { expect(subject.group).to eq 'canceled' }
end
+
+ describe '#details_path' do
+ it { expect(subject.details_path).to be_nil }
+ end
end
diff --git a/spec/lib/gitlab/ci/status/created_spec.rb b/spec/lib/gitlab/ci/status/created_spec.rb
index 1ddced923f6..1e54d1ed8c5 100644
--- a/spec/lib/gitlab/ci/status/created_spec.rb
+++ b/spec/lib/gitlab/ci/status/created_spec.rb
@@ -26,4 +26,8 @@ RSpec.describe Gitlab::Ci::Status::Created do
describe '#group' do
it { expect(subject.group).to eq 'created' }
end
+
+ describe '#details_path' do
+ it { expect(subject.details_path).to be_nil }
+ end
end
diff --git a/spec/lib/gitlab/ci/status/failed_spec.rb b/spec/lib/gitlab/ci/status/failed_spec.rb
index e8bd728b740..f3f3304b04d 100644
--- a/spec/lib/gitlab/ci/status/failed_spec.rb
+++ b/spec/lib/gitlab/ci/status/failed_spec.rb
@@ -26,4 +26,8 @@ RSpec.describe Gitlab::Ci::Status::Failed do
describe '#group' do
it { expect(subject.group).to eq 'failed' }
end
+
+ describe '#details_path' do
+ it { expect(subject.details_path).to be_nil }
+ end
end
diff --git a/spec/lib/gitlab/ci/status/pending_spec.rb b/spec/lib/gitlab/ci/status/pending_spec.rb
index 0e47b19d9c1..1c062a0133d 100644
--- a/spec/lib/gitlab/ci/status/pending_spec.rb
+++ b/spec/lib/gitlab/ci/status/pending_spec.rb
@@ -26,4 +26,8 @@ RSpec.describe Gitlab::Ci::Status::Pending do
describe '#group' do
it { expect(subject.group).to eq 'pending' }
end
+
+ describe '#details_path' do
+ it { expect(subject.details_path).to be_nil }
+ end
end
diff --git a/spec/lib/gitlab/ci/status/preparing_spec.rb b/spec/lib/gitlab/ci/status/preparing_spec.rb
index 6d33eb77560..ec1850c1959 100644
--- a/spec/lib/gitlab/ci/status/preparing_spec.rb
+++ b/spec/lib/gitlab/ci/status/preparing_spec.rb
@@ -26,4 +26,8 @@ RSpec.describe Gitlab::Ci::Status::Preparing do
describe '#group' do
it { expect(subject.group).to eq 'preparing' }
end
+
+ describe '#details_path' do
+ it { expect(subject.details_path).to be_nil }
+ end
end
diff --git a/spec/lib/gitlab/ci/status/running_spec.rb b/spec/lib/gitlab/ci/status/running_spec.rb
index fbc7bfd81b3..e40d696ee4d 100644
--- a/spec/lib/gitlab/ci/status/running_spec.rb
+++ b/spec/lib/gitlab/ci/status/running_spec.rb
@@ -26,4 +26,8 @@ RSpec.describe Gitlab::Ci::Status::Running do
describe '#group' do
it { expect(subject.group).to eq 'running' }
end
+
+ describe '#details_path' do
+ it { expect(subject.details_path).to be_nil }
+ end
end
diff --git a/spec/lib/gitlab/ci/status/scheduled_spec.rb b/spec/lib/gitlab/ci/status/scheduled_spec.rb
index 4a1dae937ca..8a923faf3f9 100644
--- a/spec/lib/gitlab/ci/status/scheduled_spec.rb
+++ b/spec/lib/gitlab/ci/status/scheduled_spec.rb
@@ -26,4 +26,8 @@ RSpec.describe Gitlab::Ci::Status::Scheduled do
describe '#group' do
it { expect(subject.group).to eq 'scheduled' }
end
+
+ describe '#details_path' do
+ it { expect(subject.details_path).to be_nil }
+ end
end
diff --git a/spec/lib/gitlab/ci/status/skipped_spec.rb b/spec/lib/gitlab/ci/status/skipped_spec.rb
index f402bbe5221..ac3c2f253f7 100644
--- a/spec/lib/gitlab/ci/status/skipped_spec.rb
+++ b/spec/lib/gitlab/ci/status/skipped_spec.rb
@@ -26,4 +26,8 @@ RSpec.describe Gitlab::Ci::Status::Skipped do
describe '#group' do
it { expect(subject.group).to eq 'skipped' }
end
+
+ describe '#details_path' do
+ it { expect(subject.details_path).to be_nil }
+ end
end
diff --git a/spec/lib/gitlab/ci/status/success_spec.rb b/spec/lib/gitlab/ci/status/success_spec.rb
index 2d1c50448d4..f2069334abd 100644
--- a/spec/lib/gitlab/ci/status/success_spec.rb
+++ b/spec/lib/gitlab/ci/status/success_spec.rb
@@ -26,4 +26,8 @@ RSpec.describe Gitlab::Ci::Status::Success do
describe '#group' do
it { expect(subject.group).to eq 'success' }
end
+
+ describe '#details_path' do
+ it { expect(subject.details_path).to be_nil }
+ end
end
diff --git a/spec/lib/gitlab/ci/status/waiting_for_resource_spec.rb b/spec/lib/gitlab/ci/status/waiting_for_resource_spec.rb
index de18198c6c2..bb6139accaf 100644
--- a/spec/lib/gitlab/ci/status/waiting_for_resource_spec.rb
+++ b/spec/lib/gitlab/ci/status/waiting_for_resource_spec.rb
@@ -26,4 +26,8 @@ RSpec.describe Gitlab::Ci::Status::WaitingForResource do
describe '#group' do
it { expect(subject.group).to eq 'waiting-for-resource' }
end
+
+ describe '#details_path' do
+ it { expect(subject.details_path).to be_nil }
+ end
end
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
new file mode 100644
index 00000000000..8df739d9245
--- /dev/null
+++ b/spec/lib/gitlab/ci/templates/Terraform/base_gitlab_ci_yaml_spec.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Terraform/Base.latest.gitlab-ci.yml' do
+ subject(:template) { Gitlab::Template::GitlabCiYmlTemplate.find('Terraform/Base.latest') }
+
+ describe 'the created pipeline' do
+ let(:user) { create(:admin) }
+ let(:default_branch) { 'master' }
+ let(:pipeline_branch) { default_branch }
+ let(:project) { create(:project, :custom_repo, files: { 'README.md' => '' }) }
+ let(:service) { Ci::CreatePipelineService.new(project, user, ref: pipeline_branch ) }
+ let(:pipeline) { service.execute!(:push) }
+ let(:build_names) { pipeline.builds.pluck(:name) }
+
+ before do
+ stub_ci_pipeline_yaml_file(template.content)
+ allow_any_instance_of(Ci::BuildScheduleWorker).to receive(:perform).and_return(true)
+ allow(project).to receive(:default_branch).and_return(default_branch)
+ end
+
+ it 'does not create any jobs' do
+ expect(build_names).to be_empty
+ 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
new file mode 100644
index 00000000000..5eec021b9d7
--- /dev/null
+++ b/spec/lib/gitlab/ci/templates/terraform_latest_gitlab_ci_yaml_spec.rb
@@ -0,0 +1,46 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Terraform.latest.gitlab-ci.yml' do
+ before do
+ allow(Gitlab::Template::GitlabCiYmlTemplate).to receive(:excluded_patterns).and_return([])
+ end
+
+ subject(:template) { Gitlab::Template::GitlabCiYmlTemplate.find('Terraform.latest') }
+
+ describe 'the created pipeline' do
+ let_it_be(:user) { create(:admin) }
+
+ let(:default_branch) { 'master' }
+ let(:pipeline_branch) { default_branch }
+ let(:project) { create(:project, :custom_repo, files: { 'README.md' => '' }) }
+ let(:service) { Ci::CreatePipelineService.new(project, user, ref: pipeline_branch ) }
+ let(:pipeline) { service.execute!(:push) }
+ let(:build_names) { pipeline.builds.pluck(:name) }
+
+ before do
+ stub_ci_pipeline_yaml_file(template.content)
+ allow_any_instance_of(Ci::BuildScheduleWorker).to receive(:perform).and_return(true)
+ allow(project).to receive(:default_branch).and_return(default_branch)
+ end
+
+ context 'on master branch' do
+ it 'creates init, validate and build jobs' do
+ expect(build_names).to include('init', 'validate', 'build', 'deploy')
+ end
+ end
+
+ context 'outside the master branch' do
+ let(:pipeline_branch) { 'patch-1' }
+
+ before do
+ project.repository.create_branch(pipeline_branch)
+ end
+
+ it 'does not creates a deploy and a test job' do
+ expect(build_names).not_to include('deploy')
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/trace/checksum_spec.rb b/spec/lib/gitlab/ci/trace/checksum_spec.rb
new file mode 100644
index 00000000000..794794c3f69
--- /dev/null
+++ b/spec/lib/gitlab/ci/trace/checksum_spec.rb
@@ -0,0 +1,121 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Ci::Trace::Checksum do
+ let(:build) { create(:ci_build, :running) }
+
+ subject { described_class.new(build) }
+
+ context 'when build pending state exists' do
+ before do
+ create(:ci_build_pending_state, build: build, trace_checksum: 'crc32:d4777540')
+ end
+
+ context 'when matching persisted trace chunks exist' do
+ before do
+ create_chunk(index: 0, data: 'a' * 128.kilobytes)
+ create_chunk(index: 1, data: 'b' * 128.kilobytes)
+ create_chunk(index: 2, data: 'ccccccccccccccccc')
+ end
+
+ it 'calculates combined trace chunks CRC32 correctly' do
+ expect(subject.chunks_crc32).to eq 3564598592
+ expect(subject).to be_valid
+ end
+ end
+
+ context 'when trace chunks were persisted in a wrong order' do
+ before do
+ create_chunk(index: 0, data: 'b' * 128.kilobytes)
+ create_chunk(index: 1, data: 'a' * 128.kilobytes)
+ create_chunk(index: 2, data: 'ccccccccccccccccc')
+ end
+
+ it 'makes trace checksum invalid' do
+ expect(subject).not_to be_valid
+ end
+ end
+
+ context 'when one of the trace chunks is missing' do
+ before do
+ create_chunk(index: 0, data: 'a' * 128.kilobytes)
+ create_chunk(index: 2, data: 'ccccccccccccccccc')
+ end
+
+ it 'makes trace checksum invalid' do
+ expect(subject).not_to be_valid
+ end
+ end
+
+ context 'when checksums of persisted trace chunks do not match' do
+ before do
+ create_chunk(index: 0, data: 'a' * 128.kilobytes)
+ create_chunk(index: 1, data: 'X' * 128.kilobytes)
+ create_chunk(index: 2, data: 'ccccccccccccccccc')
+ end
+
+ it 'makes trace checksum invalid' do
+ expect(subject).not_to be_valid
+ end
+ end
+
+ context 'when persisted trace chunks are missing' do
+ it 'makes trace checksum invalid' do
+ expect(subject.state_crc32).to eq 3564598592
+ expect(subject).not_to be_valid
+ end
+ end
+ end
+
+ context 'when build pending state is missing' do
+ describe '#state_crc32' do
+ it 'returns nil' do
+ expect(subject.state_crc32).to be_nil
+ end
+ end
+
+ describe '#valid?' do
+ it { is_expected.not_to be_valid }
+ end
+ end
+
+ describe '#trace_chunks' do
+ before do
+ create_chunk(index: 0, data: 'abcdefg')
+ end
+
+ it 'does not load raw_data from a database store' do
+ subject.trace_chunks.first.then do |chunk|
+ expect(chunk).to be_database
+ expect { chunk.raw_data }
+ .to raise_error ActiveModel::MissingAttributeError
+ end
+ end
+ end
+
+ describe '#last_chunk' do
+ context 'when there are no chunks' do
+ it 'returns nil' do
+ expect(subject.last_chunk).to be_nil
+ end
+ end
+
+ context 'when there are multiple chunks' do
+ before do
+ create_chunk(index: 1, data: '1234')
+ create_chunk(index: 0, data: 'abcd')
+ end
+
+ it 'returns chunk with the highest index' do
+ expect(subject.last_chunk.chunk_index).to eq 1
+ end
+ end
+ end
+
+ def create_chunk(index:, data:)
+ create(:ci_build_trace_chunk, :persisted, build: build,
+ chunk_index: index,
+ initial_data: data)
+ end
+end
diff --git a/spec/lib/gitlab/ci/trace/metrics_spec.rb b/spec/lib/gitlab/ci/trace/metrics_spec.rb
new file mode 100644
index 00000000000..6518d0ab075
--- /dev/null
+++ b/spec/lib/gitlab/ci/trace/metrics_spec.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Ci::Trace::Metrics, :prometheus do
+ describe '#increment_trace_bytes' do
+ context 'when incrementing by more than one' do
+ it 'increments a single counter' do
+ subject.increment_trace_bytes(10)
+ subject.increment_trace_bytes(20)
+ subject.increment_trace_bytes(30)
+
+ expect(described_class.trace_bytes.get).to eq 60
+ expect(described_class.trace_bytes.values.count).to eq 1
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/trace_spec.rb b/spec/lib/gitlab/ci/trace_spec.rb
index 171877dbaee..92bf2519588 100644
--- a/spec/lib/gitlab/ci/trace_spec.rb
+++ b/spec/lib/gitlab/ci/trace_spec.rb
@@ -2,8 +2,9 @@
require 'spec_helper'
-RSpec.describe Gitlab::Ci::Trace, :clean_gitlab_redis_shared_state do
- let(:build) { create(:ci_build) }
+RSpec.describe Gitlab::Ci::Trace, :clean_gitlab_redis_shared_state, factory_default: :keep do
+ let_it_be(:project) { create_default(:project) }
+ let_it_be_with_reload(:build) { create(:ci_build) }
let(:trace) { described_class.new(build) }
describe "associations" do
@@ -32,6 +33,16 @@ RSpec.describe Gitlab::Ci::Trace, :clean_gitlab_redis_shared_state do
expect(artifact2.job.trace.raw).to eq(test_data)
end
+
+ it 'reloads the trace in case of a chunk error' do
+ chunk_error = described_class::ChunkedIO::FailedToGetChunkError
+
+ allow_any_instance_of(described_class::Stream)
+ .to receive(:raw).and_raise(chunk_error)
+
+ expect(build).to receive(:reset).and_return(build)
+ expect { trace.raw }.to raise_error(chunk_error)
+ end
end
context 'when live trace feature is disabled' do
@@ -111,4 +122,13 @@ RSpec.describe Gitlab::Ci::Trace, :clean_gitlab_redis_shared_state do
end
end
end
+
+ describe '#lock' do
+ it 'acquires an exclusive lease on the trace' do
+ trace.lock do
+ expect { trace.lock }
+ .to raise_error described_class::LockedError
+ end
+ end
+ end
end
diff --git a/spec/lib/gitlab/ci/yaml_processor/result_spec.rb b/spec/lib/gitlab/ci/yaml_processor/result_spec.rb
new file mode 100644
index 00000000000..7e3cd7ec254
--- /dev/null
+++ b/spec/lib/gitlab/ci/yaml_processor/result_spec.rb
@@ -0,0 +1,45 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+module Gitlab
+ module Ci
+ class YamlProcessor
+ RSpec.describe Result do
+ include StubRequests
+
+ let(:user) { create(:user) }
+ let(:ci_config) { Gitlab::Ci::Config.new(config_content, user: user) }
+ let(:result) { described_class.new(ci_config: ci_config, warnings: ci_config&.warnings) }
+
+ describe '#merged_yaml' do
+ subject(:merged_yaml) { result.merged_yaml }
+
+ let(:config_content) do
+ YAML.dump(
+ include: { remote: 'https://example.com/sample.yml' },
+ test: { stage: 'test', script: 'echo' }
+ )
+ end
+
+ let(:included_yml) do
+ YAML.dump(
+ another_test: { stage: 'test', script: 'echo 2' }
+ )
+ end
+
+ before do
+ stub_full_request('https://example.com/sample.yml').to_return(body: included_yml)
+ end
+
+ it 'returns expanded yaml config' do
+ expanded_config = YAML.safe_load(merged_yaml, [Symbol])
+ included_config = YAML.safe_load(included_yml, [Symbol])
+
+ expect(expanded_config).to include(*included_config.keys)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/yaml_processor_spec.rb b/spec/lib/gitlab/ci/yaml_processor_spec.rb
index d596494a987..fb6395e888a 100644
--- a/spec/lib/gitlab/ci/yaml_processor_spec.rb
+++ b/spec/lib/gitlab/ci/yaml_processor_spec.rb
@@ -1361,7 +1361,8 @@ module Gitlab
paths: ["logs/", "binaries/"],
untracked: true,
key: 'key',
- policy: 'pull-push'
+ policy: 'pull-push',
+ when: 'on_success'
)
end
@@ -1383,7 +1384,8 @@ module Gitlab
paths: ["logs/", "binaries/"],
untracked: true,
key: { files: ['file'] },
- policy: 'pull-push'
+ policy: 'pull-push',
+ when: 'on_success'
)
end
@@ -1402,7 +1404,8 @@ module Gitlab
paths: ['logs/', 'binaries/'],
untracked: true,
key: 'key',
- policy: 'pull-push'
+ policy: 'pull-push',
+ when: 'on_success'
)
end
@@ -1425,7 +1428,8 @@ module Gitlab
paths: ['logs/', 'binaries/'],
untracked: true,
key: { files: ['file'] },
- policy: 'pull-push'
+ policy: 'pull-push',
+ when: 'on_success'
)
end
@@ -1448,7 +1452,8 @@ module Gitlab
paths: ['logs/', 'binaries/'],
untracked: true,
key: { files: ['file'], prefix: 'prefix' },
- policy: 'pull-push'
+ policy: 'pull-push',
+ when: 'on_success'
)
end
@@ -1468,7 +1473,8 @@ module Gitlab
paths: ["test/"],
untracked: false,
key: 'local',
- policy: 'pull-push'
+ policy: 'pull-push',
+ when: 'on_success'
)
end
end
@@ -2240,47 +2246,49 @@ module Gitlab
end
describe 'with parent-child pipeline' do
+ let(:config) do
+ YAML.dump({
+ build1: { stage: 'build', script: 'test' },
+ test1: {
+ stage: 'test',
+ trigger: {
+ include: includes
+ }
+ }
+ })
+ end
+
context 'when artifact and job are specified' do
- let(:config) do
- YAML.dump({
- build1: { stage: 'build', script: 'test' },
- test1: { stage: 'test', trigger: {
- include: [{ artifact: 'generated.yml', job: 'build1' }]
- } }
- })
- end
+ let(:includes) { [{ artifact: 'generated.yml', job: 'build1' }] }
it { is_expected.to be_valid }
end
- context 'when job is not specified specified while artifact is' do
- let(:config) do
- YAML.dump({
- build1: { stage: 'build', script: 'test' },
- test1: { stage: 'test', trigger: {
- include: [{ artifact: 'generated.yml' }]
- } }
- })
- end
+ context 'when job is not specified while artifact is' do
+ let(:includes) { [{ artifact: 'generated.yml' }] }
it_behaves_like 'returns errors', /include config must specify the job where to fetch the artifact from/
end
- context 'when include is a string' do
- let(:config) do
- YAML.dump({
- build1: { stage: 'build', script: 'test' },
- test1: {
- stage: 'test',
- trigger: {
- include: 'generated.yml'
- }
- }
- })
+ context 'when project and file are specified' do
+ let(:includes) do
+ [{ file: 'generated.yml', project: 'my-namespace/my-project' }]
end
it { is_expected.to be_valid }
end
+
+ context 'when file is not specified while project is' do
+ let(:includes) { [{ project: 'something' }] }
+
+ it_behaves_like 'returns errors', /include config must specify the file where to fetch the config from/
+ end
+
+ context 'when include is a string' do
+ let(:includes) { 'generated.yml' }
+
+ it { is_expected.to be_valid }
+ end
end
describe "Error handling" do
@@ -2457,13 +2465,13 @@ module Gitlab
context 'returns errors if variables is not a map' do
let(:config) { YAML.dump({ variables: "test", rspec: { script: "test" } }) }
- it_behaves_like 'returns errors', 'variables config should be a hash of key value pairs'
+ it_behaves_like 'returns errors', 'variables config should be a hash of key value pairs, value can be a hash'
end
context 'returns errors if variables is not a map of key-value strings' do
let(:config) { YAML.dump({ variables: { test: false }, rspec: { script: "test" } }) }
- it_behaves_like 'returns errors', 'variables config should be a hash of key value pairs'
+ it_behaves_like 'returns errors', 'variables config should be a hash of key value pairs, value can be a hash'
end
context 'returns errors if job when is not on_success, on_failure or always' do
diff --git a/spec/lib/gitlab/cleanup/orphan_lfs_file_references_spec.rb b/spec/lib/gitlab/cleanup/orphan_lfs_file_references_spec.rb
index efdfc0a980b..6b568320953 100644
--- a/spec/lib/gitlab/cleanup/orphan_lfs_file_references_spec.rb
+++ b/spec/lib/gitlab/cleanup/orphan_lfs_file_references_spec.rb
@@ -42,12 +42,24 @@ RSpec.describe Gitlab::Cleanup::OrphanLfsFileReferences do
expect(null_logger).to receive(:info).with("Looking for orphan LFS files for project #{project.name_with_namespace}")
expect(null_logger).to receive(:info).with("Removed invalid references: 1")
expect(ProjectCacheWorker).to receive(:perform_async).with(project.id, [], [:lfs_objects_size])
+ expect(service).to receive(:remove_orphan_references).and_call_original
expect { service.run! }.to change { project.lfs_objects.count }.from(2).to(1)
expect(LfsObjectsProject.exists?(invalid_reference.id)).to be_falsey
end
+ it 'does nothing if the project has no LFS objects' do
+ expect(null_logger).to receive(:info).with(/Looking for orphan LFS files/)
+ expect(null_logger).to receive(:info).with(/Nothing to do/)
+
+ project.lfs_objects_projects.delete_all
+
+ expect(service).not_to receive(:remove_orphan_references)
+
+ service.run!
+ end
+
context 'LFS object is in design repository' do
before do
expect(project.design_repository).to receive(:exists?).and_return(true)
diff --git a/spec/lib/gitlab/closing_issue_extractor_spec.rb b/spec/lib/gitlab/closing_issue_extractor_spec.rb
index f2bc6390032..37349c30224 100644
--- a/spec/lib/gitlab/closing_issue_extractor_spec.rb
+++ b/spec/lib/gitlab/closing_issue_extractor_spec.rb
@@ -3,18 +3,16 @@
require 'spec_helper'
RSpec.describe Gitlab::ClosingIssueExtractor do
- let(:project) { create(:project) }
- let(:project2) { create(:project) }
- let(:forked_project) { Projects::ForkService.new(project, project2.creator).execute }
- let(:issue) { create(:issue, project: project) }
- let(:issue2) { create(:issue, project: project2) }
+ let_it_be_with_reload(:project) { create(:project) }
+ let_it_be(:project2) { create(:project) }
+ let_it_be(:issue) { create(:issue, project: project) }
+ let_it_be(:issue2) { create(:issue, project: project2) }
let(:reference) { issue.to_reference }
let(:cross_reference) { issue2.to_reference(project) }
- let(:fork_cross_reference) { issue.to_reference(forked_project) }
subject { described_class.new(project, project.creator) }
- before do
+ before_all do
project.add_developer(project.creator)
project.add_developer(project2.creator)
project2.add_maintainer(project.creator)
@@ -325,6 +323,9 @@ RSpec.describe Gitlab::ClosingIssueExtractor do
end
context "with a cross-project fork reference" do
+ let(:forked_project) { Projects::ForkService.new(project, project2.creator).execute }
+ let(:fork_cross_reference) { issue.to_reference(forked_project) }
+
subject { described_class.new(forked_project, forked_project.creator) }
it do
@@ -348,8 +349,8 @@ RSpec.describe Gitlab::ClosingIssueExtractor do
end
context 'with multiple references' do
- let(:other_issue) { create(:issue, project: project) }
- let(:third_issue) { create(:issue, project: project) }
+ let_it_be(:other_issue) { create(:issue, project: project) }
+ let_it_be(:third_issue) { create(:issue, project: project) }
let(:reference2) { other_issue.to_reference }
let(:reference3) { third_issue.to_reference }
diff --git a/spec/lib/gitlab/code_navigation_path_spec.rb b/spec/lib/gitlab/code_navigation_path_spec.rb
index 4dc864b158d..206541f7c0d 100644
--- a/spec/lib/gitlab/code_navigation_path_spec.rb
+++ b/spec/lib/gitlab/code_navigation_path_spec.rb
@@ -16,10 +16,6 @@ RSpec.describe Gitlab::CodeNavigationPath do
subject { described_class.new(project, commit_sha).full_json_path_for(path) }
- before do
- stub_feature_flags(code_navigation: project)
- end
-
context 'when a pipeline exist for a sha' do
it 'returns path to a file in the artifact' do
expect(subject).to eq(lsif_path)
@@ -41,15 +37,5 @@ RSpec.describe Gitlab::CodeNavigationPath do
expect(subject).to eq(lsif_path)
end
end
-
- context 'when code_navigation feature is disabled' do
- before do
- stub_feature_flags(code_navigation: false)
- end
-
- it 'returns nil' do
- expect(subject).to be_nil
- end
- end
end
end
diff --git a/spec/lib/gitlab/config/entry/composable_array_spec.rb b/spec/lib/gitlab/config/entry/composable_array_spec.rb
new file mode 100644
index 00000000000..77766cb3b0a
--- /dev/null
+++ b/spec/lib/gitlab/config/entry/composable_array_spec.rb
@@ -0,0 +1,69 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Config::Entry::ComposableArray, :aggregate_failures do
+ let(:valid_config) do
+ [
+ {
+ DATABASE_SECRET: 'passw0rd'
+ },
+ {
+ API_TOKEN: 'passw0rd2'
+ }
+ ]
+ end
+
+ let(:config) { valid_config }
+ let(:entry) { described_class.new(config) }
+
+ before do
+ allow(entry).to receive(:composable_class).and_return(Gitlab::Config::Entry::Node)
+ end
+
+ describe '#valid?' do
+ it 'is valid' do
+ expect(entry).to be_valid
+ end
+
+ context 'is invalid' do
+ let(:config) { { hello: :world } }
+
+ it { expect(entry).not_to be_valid }
+ end
+ end
+
+ describe '#compose!' do
+ before do
+ entry.compose!
+ end
+
+ it 'composes child entry with configured value' do
+ expect(entry.value).to eq(config)
+ end
+
+ it 'composes child entries with configured values' do
+ expect(entry[0]).to be_a(Gitlab::Config::Entry::Node)
+ expect(entry[0].description).to eq('node definition')
+ expect(entry[0].key).to eq('node')
+ expect(entry[0].metadata).to eq({})
+ expect(entry[0].parent.class).to eq(Gitlab::Config::Entry::ComposableArray)
+ expect(entry[0].value).to eq(DATABASE_SECRET: 'passw0rd')
+ expect(entry[1]).to be_a(Gitlab::Config::Entry::Node)
+ expect(entry[1].description).to eq('node definition')
+ expect(entry[1].key).to eq('node')
+ expect(entry[1].metadata).to eq({})
+ expect(entry[1].parent.class).to eq(Gitlab::Config::Entry::ComposableArray)
+ expect(entry[1].value).to eq(API_TOKEN: 'passw0rd2')
+ end
+
+ describe '#descendants' do
+ it 'creates descendant nodes' do
+ expect(entry.descendants.first).to be_a(Gitlab::Config::Entry::Node)
+ expect(entry.descendants.first.value).to eq(DATABASE_SECRET: 'passw0rd')
+ expect(entry.descendants.second).to be_a(Gitlab::Config::Entry::Node)
+ expect(entry.descendants.second.value).to eq(API_TOKEN: 'passw0rd2')
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/config/entry/composable_hash_spec.rb b/spec/lib/gitlab/config/entry/composable_hash_spec.rb
new file mode 100644
index 00000000000..15bbf2047c5
--- /dev/null
+++ b/spec/lib/gitlab/config/entry/composable_hash_spec.rb
@@ -0,0 +1,108 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Config::Entry::ComposableHash, :aggregate_failures do
+ let(:valid_config) do
+ {
+ DATABASE_SECRET: 'passw0rd',
+ API_TOKEN: 'passw0rd2'
+ }
+ end
+
+ let(:config) { valid_config }
+
+ shared_examples 'composes a hash' do
+ describe '#valid?' do
+ it 'is valid' do
+ expect(entry).to be_valid
+ end
+
+ context 'is invalid' do
+ let(:config) { %w[one two] }
+
+ it { expect(entry).not_to be_valid }
+ end
+ end
+
+ describe '#value' do
+ context 'when config is a hash' do
+ it 'returns key value' do
+ expect(entry.value).to eq config
+ end
+ end
+ end
+
+ describe '#compose!' do
+ before do
+ entry.compose!
+ end
+
+ it 'composes child entry with configured value' do
+ expect(entry.value).to eq(config)
+ end
+
+ it 'composes child entries with configured values' do
+ expect(entry[:DATABASE_SECRET]).to be_a(Gitlab::Config::Entry::Node)
+ expect(entry[:DATABASE_SECRET].description).to eq('DATABASE_SECRET node definition')
+ expect(entry[:DATABASE_SECRET].key).to eq(:DATABASE_SECRET)
+ expect(entry[:DATABASE_SECRET].metadata).to eq(name: :DATABASE_SECRET)
+ expect(entry[:DATABASE_SECRET].parent.class).to eq(Gitlab::Config::Entry::ComposableHash)
+ expect(entry[:DATABASE_SECRET].value).to eq('passw0rd')
+ expect(entry[:API_TOKEN]).to be_a(Gitlab::Config::Entry::Node)
+ expect(entry[:API_TOKEN].description).to eq('API_TOKEN node definition')
+ expect(entry[:API_TOKEN].key).to eq(:API_TOKEN)
+ expect(entry[:API_TOKEN].metadata).to eq(name: :API_TOKEN)
+ expect(entry[:API_TOKEN].parent.class).to eq(Gitlab::Config::Entry::ComposableHash)
+ expect(entry[:API_TOKEN].value).to eq('passw0rd2')
+ end
+
+ describe '#descendants' do
+ it 'creates descendant nodes' do
+ expect(entry.descendants.first).to be_a(Gitlab::Config::Entry::Node)
+ expect(entry.descendants.first.value).to eq('passw0rd')
+ expect(entry.descendants.second).to be_a(Gitlab::Config::Entry::Node)
+ expect(entry.descendants.second.value).to eq('passw0rd2')
+ end
+ end
+ end
+ end
+
+ context 'when ComposableHash is instantiated' do
+ let(:entry) { described_class.new(config) }
+
+ before do
+ allow(entry).to receive(:composable_class).and_return(Gitlab::Config::Entry::Node)
+ end
+
+ it_behaves_like 'composes a hash'
+ end
+
+ context 'when ComposableHash entry is configured in the parent class' do
+ let(:composable_hash_parent_class) do
+ Class.new(Gitlab::Config::Entry::Node) do
+ include ::Gitlab::Config::Entry::Configurable
+
+ entry :secrets, ::Gitlab::Config::Entry::ComposableHash,
+ description: 'Configured secrets for this job',
+ inherit: false,
+ default: { hello: :world },
+ metadata: { composable_class: Gitlab::Config::Entry::Node }
+ end
+ end
+
+ let(:entry) do
+ parent_entry = composable_hash_parent_class.new(secrets: config)
+ parent_entry.compose!
+
+ parent_entry[:secrets]
+ end
+
+ it_behaves_like 'composes a hash'
+
+ it 'creates entry with configuration from parent class' do
+ expect(entry.default).to eq({ hello: :world })
+ expect(entry.metadata).to eq(composable_class: Gitlab::Config::Entry::Node)
+ end
+ end
+end
diff --git a/spec/lib/gitlab/conflict/file_spec.rb b/spec/lib/gitlab/conflict/file_spec.rb
index b54fe40bb5f..80bd517ec92 100644
--- a/spec/lib/gitlab/conflict/file_spec.rb
+++ b/spec/lib/gitlab/conflict/file_spec.rb
@@ -262,7 +262,7 @@ RSpec.describe Gitlab::Conflict::File do
end
it 'includes the blob icon for the file' do
- expect(conflict_file.as_json[:blob_icon]).to eq('file-text-o')
+ expect(conflict_file.as_json[:blob_icon]).to eq('doc-text')
end
context 'with the full_content option passed' do
diff --git a/spec/lib/gitlab/cycle_analytics/events_spec.rb b/spec/lib/gitlab/cycle_analytics/events_spec.rb
index e0a8e2c17a3..a31f34d82d7 100644
--- a/spec/lib/gitlab/cycle_analytics/events_spec.rb
+++ b/spec/lib/gitlab/cycle_analytics/events_spec.rb
@@ -2,16 +2,20 @@
require 'spec_helper'
-RSpec.describe 'cycle analytics events' do
- let(:project) { create(:project, :repository) }
+RSpec.describe 'cycle analytics events', :aggregate_failures do
+ let_it_be(:project) { create(:project, :repository) }
+ let_it_be(:user) { create(:user, :admin) }
let(:from_date) { 10.days.ago }
- let(:user) { create(:user, :admin) }
let!(:context) { create(:issue, project: project, created_at: 2.days.ago) }
let(:events) do
- CycleAnalytics::ProjectLevel.new(project, options: { from: from_date, current_user: user })[stage].events
+ CycleAnalytics::ProjectLevel
+ .new(project, options: { from: from_date, current_user: user })[stage]
+ .events
end
+ let(:event) { events.first }
+
before do
setup(context)
end
@@ -19,36 +23,15 @@ RSpec.describe 'cycle analytics events' do
describe '#issue_events' do
let(:stage) { :issue }
- it 'has the total time' do
- expect(events.first[:total_time]).not_to be_empty
- end
-
- it 'has a title' do
- expect(events.first[:title]).to eq(context.title)
- end
-
- it 'has the URL' do
- expect(events.first[:url]).not_to be_nil
- end
-
- it 'has an iid' do
- expect(events.first[:iid]).to eq(context.iid.to_s)
- end
-
- it 'has a created_at timestamp' do
- expect(events.first[:created_at]).to end_with('ago')
- end
-
- it "has the author's URL" do
- expect(events.first[:author][:web_url]).not_to be_nil
- end
-
- it "has the author's avatar URL" do
- expect(events.first[:author][:avatar_url]).not_to be_nil
- end
-
- it "has the author's name" do
- expect(events.first[:author][:name]).to eq(context.author.name)
+ it 'has correct attributes' do
+ expect(event[:total_time]).not_to be_empty
+ expect(event[:title]).to eq(context.title)
+ expect(event[:url]).not_to be_nil
+ expect(event[:iid]).to eq(context.iid.to_s)
+ expect(event[:created_at]).to end_with('ago')
+ expect(event[:author][:web_url]).not_to be_nil
+ expect(event[:author][:avatar_url]).not_to be_nil
+ expect(event[:author][:name]).to eq(context.author.name)
end
end
@@ -59,36 +42,15 @@ RSpec.describe 'cycle analytics events' do
create_commit_referencing_issue(context)
end
- it 'has the total time' do
- expect(events.first[:total_time]).not_to be_empty
- end
-
- it 'has a title' do
- expect(events.first[:title]).to eq(context.title)
- end
-
- it 'has the URL' do
- expect(events.first[:url]).not_to be_nil
- end
-
- it 'has an iid' do
- expect(events.first[:iid]).to eq(context.iid.to_s)
- end
-
- it 'has a created_at timestamp' do
- expect(events.first[:created_at]).to end_with('ago')
- end
-
- it "has the author's URL" do
- expect(events.first[:author][:web_url]).not_to be_nil
- end
-
- it "has the author's avatar URL" do
- expect(events.first[:author][:avatar_url]).not_to be_nil
- end
-
- it "has the author's name" do
- expect(events.first[:author][:name]).to eq(context.author.name)
+ it 'has correct attributes' do
+ expect(event[:total_time]).not_to be_empty
+ expect(event[:title]).to eq(context.title)
+ expect(event[:url]).not_to be_nil
+ expect(event[:iid]).to eq(context.iid.to_s)
+ expect(event[:created_at]).to end_with('ago')
+ expect(event[:author][:web_url]).not_to be_nil
+ expect(event[:author][:avatar_url]).not_to be_nil
+ expect(event[:author][:name]).to eq(context.author.name)
end
end
@@ -100,32 +62,14 @@ RSpec.describe 'cycle analytics events' do
create_commit_referencing_issue(context)
end
- it 'has the total time' do
- expect(events.first[:total_time]).not_to be_empty
- end
-
- it 'has a title' do
- expect(events.first[:title]).to eq('Awesome merge_request')
- end
-
- it 'has an iid' do
- expect(events.first[:iid]).to eq(context.iid.to_s)
- end
-
- it 'has a created_at timestamp' do
- expect(events.first[:created_at]).to end_with('ago')
- end
-
- it "has the author's URL" do
- expect(events.first[:author][:web_url]).not_to be_nil
- end
-
- it "has the author's avatar URL" do
- expect(events.first[:author][:avatar_url]).not_to be_nil
- end
-
- it "has the author's name" do
- expect(events.first[:author][:name]).to eq(MergeRequest.first.author.name)
+ it 'has correct attributes' do
+ expect(event[:total_time]).not_to be_empty
+ expect(event[:title]).to eq('Awesome merge_request')
+ expect(event[:iid]).to eq(context.iid.to_s)
+ expect(event[:created_at]).to end_with('ago')
+ expect(event[:author][:web_url]).not_to be_nil
+ expect(event[:author][:avatar_url]).not_to be_nil
+ expect(event[:author][:name]).to eq(MergeRequest.first.author.name)
end
end
@@ -152,40 +96,16 @@ RSpec.describe 'cycle analytics events' do
merge_merge_requests_closing_issue(user, project, context)
end
- it 'has the name' do
- expect(events.first[:name]).not_to be_nil
- end
-
- it 'has the ID' do
- expect(events.first[:id]).not_to be_nil
- end
-
- it 'has the URL' do
- expect(events.first[:url]).not_to be_nil
- end
-
- it 'has the branch name' do
- expect(events.first[:branch]).not_to be_nil
- end
-
- it 'has the branch URL' do
- expect(events.first[:branch][:url]).not_to be_nil
- end
-
- it 'has the short SHA' do
- expect(events.first[:short_sha]).not_to be_nil
- end
-
- it 'has the commit URL' do
- expect(events.first[:commit_url]).not_to be_nil
- end
-
- it 'has the date' do
- expect(events.first[:date]).not_to be_nil
- end
-
- it 'has the total time' do
- expect(events.first[:total_time]).not_to be_empty
+ it 'has correct attributes' do
+ expect(event[:name]).not_to be_nil
+ expect(event[:id]).not_to be_nil
+ expect(event[:url]).not_to be_nil
+ expect(event[:branch]).not_to be_nil
+ expect(event[:branch][:url]).not_to be_nil
+ expect(event[:short_sha]).not_to be_nil
+ expect(event[:commit_url]).not_to be_nil
+ expect(event[:date]).not_to be_nil
+ expect(event[:total_time]).not_to be_empty
end
end
@@ -197,40 +117,16 @@ RSpec.describe 'cycle analytics events' do
merge_merge_requests_closing_issue(user, project, context)
end
- it 'has the total time' do
- expect(events.first[:total_time]).not_to be_empty
- end
-
- it 'has a title' do
- expect(events.first[:title]).to eq('Awesome merge_request')
- end
-
- it 'has an iid' do
- expect(events.first[:iid]).to eq(context.iid.to_s)
- end
-
- it 'has the URL' do
- expect(events.first[:url]).not_to be_nil
- end
-
- it 'has a state' do
- expect(events.first[:state]).not_to be_nil
- end
-
- it 'has a created_at timestamp' do
- expect(events.first[:created_at]).not_to be_nil
- end
-
- it "has the author's URL" do
- expect(events.first[:author][:web_url]).not_to be_nil
- end
-
- it "has the author's avatar URL" do
- expect(events.first[:author][:avatar_url]).not_to be_nil
- end
-
- it "has the author's name" do
- expect(events.first[:author][:name]).to eq(MergeRequest.first.author.name)
+ it 'has correct attributes' do
+ expect(event[:total_time]).not_to be_empty
+ expect(event[:title]).to eq('Awesome merge_request')
+ expect(event[:iid]).to eq(context.iid.to_s)
+ expect(event[:url]).not_to be_nil
+ expect(event[:state]).not_to be_nil
+ expect(event[:created_at]).not_to be_nil
+ expect(event[:author][:web_url]).not_to be_nil
+ expect(event[:author][:avatar_url]).not_to be_nil
+ expect(event[:author][:name]).to eq(MergeRequest.first.author.name)
end
end
@@ -257,58 +153,25 @@ RSpec.describe 'cycle analytics events' do
deploy_master(user, project)
end
- it 'has the name' do
- expect(events.first[:name]).not_to be_nil
- end
-
- it 'has the ID' do
- expect(events.first[:id]).not_to be_nil
- end
-
- it 'has the URL' do
- expect(events.first[:url]).not_to be_nil
- end
-
- it 'has the branch name' do
- expect(events.first[:branch]).not_to be_nil
- end
-
- it 'has the branch URL' do
- expect(events.first[:branch][:url]).not_to be_nil
- end
-
- it 'has the short SHA' do
- expect(events.first[:short_sha]).not_to be_nil
- end
-
- it 'has the commit URL' do
- expect(events.first[:commit_url]).not_to be_nil
- end
-
- it 'has the date' do
- expect(events.first[:date]).not_to be_nil
- end
-
- it 'has the total time' do
- expect(events.first[:total_time]).not_to be_empty
- end
-
- it "has the author's URL" do
- expect(events.first[:author][:web_url]).not_to be_nil
- end
-
- it "has the author's avatar URL" do
- expect(events.first[:author][:avatar_url]).not_to be_nil
- end
-
- it "has the author's name" do
- expect(events.first[:author][:name]).to eq(MergeRequest.first.author.name)
+ it 'has correct attributes' do
+ expect(event[:name]).not_to be_nil
+ expect(event[:id]).not_to be_nil
+ expect(event[:url]).not_to be_nil
+ expect(event[:branch]).not_to be_nil
+ expect(event[:branch][:url]).not_to be_nil
+ expect(event[:short_sha]).not_to be_nil
+ expect(event[:commit_url]).not_to be_nil
+ expect(event[:date]).not_to be_nil
+ expect(event[:total_time]).not_to be_empty
+ expect(event[:author][:web_url]).not_to be_nil
+ expect(event[:author][:avatar_url]).not_to be_nil
+ expect(event[:author][:name]).to eq(MergeRequest.first.author.name)
end
end
def setup(context)
milestone = create(:milestone, project: project)
- context.update(milestone: milestone)
+ context.update!(milestone: milestone)
mr = create_merge_request_closing_issue(user, project, context, commit_message: "References #{context.to_reference}")
ProcessCommitWorker.new.perform(project.id, user.id, mr.commits.last.to_hash)
diff --git a/spec/lib/gitlab/danger/commit_linter_spec.rb b/spec/lib/gitlab/danger/commit_linter_spec.rb
index c31522c538d..882cede759b 100644
--- a/spec/lib/gitlab/danger/commit_linter_spec.rb
+++ b/spec/lib/gitlab/danger/commit_linter_spec.rb
@@ -323,6 +323,16 @@ RSpec.describe Gitlab::Danger::CommitLinter do
end
end
+ context 'when message includes a value that is surrounded by backticks' do
+ let(:commit_message) { "A commit message `%20`" }
+
+ it 'does not add a problem' do
+ expect(commit_linter).not_to receive(:add_problem)
+
+ commit_linter.lint
+ end
+ end
+
context 'when message includes a short reference' do
[
'A commit message to fix #1234',
@@ -336,7 +346,9 @@ RSpec.describe Gitlab::Danger::CommitLinter do
'A commit message to fix gitlab-org/gitlab#1234',
'A commit message to fix gitlab-org/gitlab!1234',
'A commit message to fix gitlab-org/gitlab&1234',
- 'A commit message to fix gitlab-org/gitlab%1234'
+ 'A commit message to fix gitlab-org/gitlab%1234',
+ 'A commit message to fix "gitlab-org/gitlab%1234"',
+ 'A commit message to fix `gitlab-org/gitlab%1234'
].each do |message|
let(:commit_message) { message }
diff --git a/spec/lib/gitlab/danger/helper_spec.rb b/spec/lib/gitlab/danger/helper_spec.rb
index c7d55c396ef..509649f08c6 100644
--- a/spec/lib/gitlab/danger/helper_spec.rb
+++ b/spec/lib/gitlab/danger/helper_spec.rb
@@ -284,7 +284,8 @@ RSpec.describe Gitlab::Danger::Helper do
'.codeclimate.yml' | [:engineering_productivity]
'.gitlab/CODEOWNERS' | [:engineering_productivity]
- 'lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml' | [:backend]
+ 'lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml' | [:ci_template]
+ 'lib/gitlab/ci/templates/dotNET-Core.yml' | [:ci_template]
'ee/FOO_VERSION' | [:unknown]
@@ -376,6 +377,7 @@ RSpec.describe Gitlab::Danger::Helper do
:none | ''
:qa | '~QA'
:engineering_productivity | '~"Engineering Productivity" for CI, Danger'
+ :ci_template | '~"ci::templates"'
end
with_them do
@@ -435,6 +437,28 @@ RSpec.describe Gitlab::Danger::Helper do
end
end
+ describe '#draft_mr?' do
+ it 'returns false when `gitlab_helper` is unavailable' do
+ expect(helper).to receive(:gitlab_helper).and_return(nil)
+
+ expect(helper).not_to be_draft_mr
+ end
+
+ it 'returns true for a draft MR' do
+ expect(fake_gitlab).to receive(:mr_json)
+ .and_return('title' => 'Draft: My MR title')
+
+ expect(helper).to be_draft_mr
+ end
+
+ it 'returns false for non draft MR' do
+ expect(fake_gitlab).to receive(:mr_json)
+ .and_return('title' => 'My MR title')
+
+ expect(helper).not_to be_draft_mr
+ end
+ end
+
describe '#cherry_pick_mr?' do
it 'returns false when `gitlab_helper` is unavailable' do
expect(helper).to receive(:gitlab_helper).and_return(nil)
diff --git a/spec/lib/gitlab/danger/roulette_spec.rb b/spec/lib/gitlab/danger/roulette_spec.rb
index b471e17e2e7..1a900dfba22 100644
--- a/spec/lib/gitlab/danger/roulette_spec.rb
+++ b/spec/lib/gitlab/danger/roulette_spec.rb
@@ -4,10 +4,13 @@ require 'webmock/rspec'
require 'timecop'
require 'gitlab/danger/roulette'
+require 'active_support/testing/time_helpers'
RSpec.describe Gitlab::Danger::Roulette do
+ include ActiveSupport::Testing::TimeHelpers
+
around do |example|
- Timecop.freeze(Time.utc(2020, 06, 22, 10)) { example.run }
+ travel_to(Time.utc(2020, 06, 22, 10)) { example.run }
end
let(:backend_available) { true }
@@ -67,14 +70,30 @@ RSpec.describe Gitlab::Danger::Roulette do
)
end
- let(:teammate_json) do
+ let(:ci_template_reviewer) do
+ Gitlab::Danger::Teammate.new(
+ 'username' => 'ci-template-maintainer',
+ 'name' => 'CI Template engineer',
+ 'role' => '~"ci::templates"',
+ 'projects' => { 'gitlab' => 'reviewer ci_template' },
+ 'available' => true,
+ 'tz_offset_hours' => 2.0
+ )
+ end
+
+ let(:teammates) do
[
backend_maintainer.to_h,
frontend_maintainer.to_h,
frontend_reviewer.to_h,
software_engineer_in_test.to_h,
- engineering_productivity_reviewer.to_h
- ].to_json
+ engineering_productivity_reviewer.to_h,
+ ci_template_reviewer.to_h
+ ]
+ end
+
+ let(:teammate_json) do
+ teammates.to_json
end
subject(:roulette) { Object.new.extend(described_class) }
@@ -162,6 +181,14 @@ RSpec.describe Gitlab::Danger::Roulette do
end
end
+ context 'when change contains CI/CD Template category' do
+ let(:categories) { [:ci_template] }
+
+ it 'assigns CI/CD Template reviewer and fallback to backend maintainer' do
+ expect(spins).to eq([described_class::Spin.new(:ci_template, ci_template_reviewer, backend_maintainer, false, false)])
+ end
+ end
+
context 'when change contains test category' do
let(:categories) { [:test] }
@@ -210,6 +237,69 @@ RSpec.describe Gitlab::Danger::Roulette do
end
end
end
+
+ describe 'reviewer suggestion probability' do
+ let(:reviewer) { teammate_with_capability('reviewer', 'reviewer backend') }
+ let(:hungry_reviewer) { teammate_with_capability('hungry_reviewer', 'reviewer backend', hungry: true) }
+ let(:traintainer) { teammate_with_capability('traintainer', 'trainee_maintainer backend') }
+ let(:hungry_traintainer) { teammate_with_capability('hungry_traintainer', 'trainee_maintainer backend', hungry: true) }
+ let(:teammates) do
+ [
+ reviewer.to_h,
+ hungry_reviewer.to_h,
+ traintainer.to_h,
+ hungry_traintainer.to_h
+ ]
+ end
+
+ let(:categories) { [:backend] }
+
+ # This test is testing probability with inherent randomness.
+ # The variance is inversely related to sample size
+ # Given large enough sample size, the variance would be smaller,
+ # but the test would take longer.
+ # Given smaller sample size, the variance would be larger,
+ # but the test would take less time.
+ let!(:sample_size) { 500 }
+ let!(:variance) { 0.1 }
+
+ before do
+ # This test needs actual randomness to simulate probabilities
+ allow(subject).to receive(:new_random).and_return(Random.new)
+ WebMock
+ .stub_request(:get, described_class::ROULETTE_DATA_URL)
+ .to_return(body: teammate_json)
+ end
+
+ it 'has 1:2:3:4 probability of picking reviewer, hungry_reviewer, traintainer, hungry_traintainer' do
+ picks = Array.new(sample_size).map do
+ spins = subject.spin(project, categories, timezone_experiment: timezone_experiment)
+ spins.first.reviewer.name
+ end
+
+ expect(probability(picks, 'reviewer')).to be_within(variance).of(0.1)
+ expect(probability(picks, 'hungry_reviewer')).to be_within(variance).of(0.2)
+ expect(probability(picks, 'traintainer')).to be_within(variance).of(0.3)
+ expect(probability(picks, 'hungry_traintainer')).to be_within(variance).of(0.4)
+ end
+
+ def probability(picks, role)
+ picks.count(role).to_f / picks.length
+ end
+
+ def teammate_with_capability(name, capability, hungry: false)
+ Gitlab::Danger::Teammate.new(
+ {
+ 'name' => name,
+ 'projects' => {
+ 'gitlab' => capability
+ },
+ 'available' => true,
+ 'hungry' => hungry
+ }
+ )
+ end
+ end
end
RSpec::Matchers.define :match_teammates do |expected|
@@ -265,7 +355,8 @@ RSpec.describe Gitlab::Danger::Roulette do
frontend_reviewer,
frontend_maintainer,
software_engineer_in_test,
- engineering_productivity_reviewer
+ engineering_productivity_reviewer,
+ ci_template_reviewer
])
end
diff --git a/spec/lib/gitlab/danger/teammate_spec.rb b/spec/lib/gitlab/danger/teammate_spec.rb
index 6fd32493d6b..eebe14ed5e1 100644
--- a/spec/lib/gitlab/danger/teammate_spec.rb
+++ b/spec/lib/gitlab/danger/teammate_spec.rb
@@ -4,6 +4,7 @@ require 'timecop'
require 'rspec-parameterized'
require 'gitlab/danger/teammate'
+require 'active_support/testing/time_helpers'
RSpec.describe Gitlab::Danger::Teammate do
using RSpec::Parameterized::TableSyntax
@@ -148,8 +149,10 @@ RSpec.describe Gitlab::Danger::Teammate do
end
describe '#local_hour' do
+ include ActiveSupport::Testing::TimeHelpers
+
around do |example|
- Timecop.freeze(Time.utc(2020, 6, 23, 10)) { example.run }
+ travel_to(Time.utc(2020, 6, 23, 10)) { example.run }
end
context 'when author is given' do
diff --git a/spec/lib/gitlab/data_builder/deployment_spec.rb b/spec/lib/gitlab/data_builder/deployment_spec.rb
index 155e66e2fcd..8fb7ab25b17 100644
--- a/spec/lib/gitlab/data_builder/deployment_spec.rb
+++ b/spec/lib/gitlab/data_builder/deployment_spec.rb
@@ -19,7 +19,7 @@ RSpec.describe Gitlab::DataBuilder::Deployment do
deployment = create(:deployment, status: :failed, environment: environment, sha: commit.sha, project: project)
deployable = deployment.deployable
expected_deployable_url = Gitlab::Routing.url_helpers.project_job_url(deployable.project, deployable)
- expected_user_url = Gitlab::Routing.url_helpers.user_url(deployment.user)
+ expected_user_url = Gitlab::Routing.url_helpers.user_url(deployment.deployed_by)
expected_commit_url = Gitlab::UrlBuilder.build(commit)
data = described_class.build(deployment)
@@ -30,7 +30,7 @@ RSpec.describe Gitlab::DataBuilder::Deployment do
expect(data[:environment]).to eq("somewhere")
expect(data[:project]).to eq(project.hook_attrs)
expect(data[:short_sha]).to eq(deployment.short_sha)
- expect(data[:user]).to eq(deployment.user.hook_attrs)
+ expect(data[:user]).to eq(deployment.deployed_by.hook_attrs)
expect(data[:user_url]).to eq(expected_user_url)
expect(data[:commit_url]).to eq(expected_commit_url)
expect(data[:commit_title]).to eq(commit.title)
diff --git a/spec/lib/gitlab/database/background_migration_job_spec.rb b/spec/lib/gitlab/database/background_migration_job_spec.rb
index dd5bf8b512f..42695925a1c 100644
--- a/spec/lib/gitlab/database/background_migration_job_spec.rb
+++ b/spec/lib/gitlab/database/background_migration_job_spec.rb
@@ -85,7 +85,7 @@ RSpec.describe Gitlab::Database::BackgroundMigrationJob do
let!(:job1) { create(:background_migration_job, :succeeded, created_at: initial_time, updated_at: initial_time) }
it 'does not update non-pending jobs' do
- Timecop.freeze(initial_time + 1.day) do
+ travel_to(initial_time + 1.day) do
expect { described_class.mark_all_as_succeeded('TestJob', [1, 100]) }
.to change { described_class.succeeded.count }.from(1).to(2)
end
diff --git a/spec/lib/gitlab/database/batch_count_spec.rb b/spec/lib/gitlab/database/batch_count_spec.rb
index 71d3666602f..31a8b4afa03 100644
--- a/spec/lib/gitlab/database/batch_count_spec.rb
+++ b/spec/lib/gitlab/database/batch_count_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe Gitlab::Database::BatchCount do
let_it_be(:fallback) { ::Gitlab::Database::BatchCounter::FALLBACK }
- let_it_be(:small_batch_size) { ::Gitlab::Database::BatchCounter::MIN_REQUIRED_BATCH_SIZE - 1 }
+ let_it_be(:small_batch_size) { calculate_batch_size(::Gitlab::Database::BatchCounter::MIN_REQUIRED_BATCH_SIZE) }
let(:model) { Issue }
let(:column) { :author_id }
@@ -22,6 +22,12 @@ RSpec.describe Gitlab::Database::BatchCount do
allow(ActiveRecord::Base.connection).to receive(:transaction_open?).and_return(in_transaction)
end
+ def calculate_batch_size(batch_size)
+ zero_offset_modifier = -1
+
+ batch_size + zero_offset_modifier
+ end
+
shared_examples 'disallowed configurations' do |method|
it 'returns fallback if start is bigger than finish' do
expect(described_class.public_send(method, *args, start: 1, finish: 0)).to eq(fallback)
@@ -45,6 +51,46 @@ RSpec.describe Gitlab::Database::BatchCount do
end
end
+ shared_examples 'when batch fetch query is canceled' do
+ let(:batch_size) { 22_000 }
+ let(:relation) { instance_double(ActiveRecord::Relation) }
+
+ it 'reduces batch size by half and retry fetch' do
+ too_big_batch_relation_mock = instance_double(ActiveRecord::Relation)
+ allow(model).to receive_message_chain(:select, public_send: relation)
+ allow(relation).to receive(:where).with("id" => 0..calculate_batch_size(batch_size)).and_return(too_big_batch_relation_mock)
+ allow(too_big_batch_relation_mock).to receive(:send).and_raise(ActiveRecord::QueryCanceled)
+
+ expect(relation).to receive(:where).with("id" => 0..calculate_batch_size(batch_size / 2)).and_return(double(send: 1))
+
+ subject.call(model, column, batch_size: batch_size, start: 0)
+ end
+
+ context 'when all retries fail' do
+ let(:batch_count_query) { 'SELECT COUNT(id) FROM relation WHERE id BETWEEN 0 and 1' }
+
+ before do
+ allow(model).to receive_message_chain(:select, :public_send, where: relation)
+ allow(relation).to receive(:send).and_raise(ActiveRecord::QueryCanceled.new('query timed out'))
+ allow(relation).to receive(:to_sql).and_return(batch_count_query)
+ end
+
+ it 'logs failing query' do
+ expect(Gitlab::AppJsonLogger).to receive(:error).with(
+ event: 'batch_count',
+ relation: model.table_name,
+ operation: operation,
+ operation_args: operation_args,
+ start: 0,
+ mode: mode,
+ query: batch_count_query,
+ message: 'Query has been canceled with message: query timed out'
+ )
+ expect(subject.call(model, column, batch_size: batch_size, start: 0)).to eq(-1)
+ end
+ end
+ end
+
describe '#batch_count' do
it 'counts table' do
expect(described_class.batch_count(model)).to eq(5)
@@ -86,10 +132,11 @@ RSpec.describe Gitlab::Database::BatchCount do
it "defaults the batch size to #{Gitlab::Database::BatchCounter::DEFAULT_BATCH_SIZE}" do
min_id = model.minimum(:id)
+ relation = instance_double(ActiveRecord::Relation)
+ allow(model).to receive_message_chain(:select, public_send: relation)
+ batch_end_id = min_id + calculate_batch_size(Gitlab::Database::BatchCounter::DEFAULT_BATCH_SIZE)
- expect_next_instance_of(Gitlab::Database::BatchCounter) do |batch_counter|
- expect(batch_counter).to receive(:batch_fetch).with(min_id, Gitlab::Database::BatchCounter::DEFAULT_BATCH_SIZE + min_id, :itself).once.and_call_original
- end
+ expect(relation).to receive(:where).with("id" => min_id..batch_end_id).and_return(double(send: 1))
described_class.batch_count(model)
end
@@ -98,6 +145,15 @@ RSpec.describe Gitlab::Database::BatchCount do
subject { described_class.batch_count(model) }
end
+ it_behaves_like 'when batch fetch query is canceled' do
+ let(:mode) { :itself }
+ let(:operation) { :count }
+ let(:operation_args) { nil }
+ let(:column) { nil }
+
+ subject { described_class.method(:batch_count) }
+ end
+
context 'disallowed_configurations' do
include_examples 'disallowed configurations', :batch_count do
let(:args) { [Issue] }
@@ -108,6 +164,24 @@ RSpec.describe Gitlab::Database::BatchCount do
expect { described_class.batch_count(model.distinct(column)) }.to raise_error 'Use distinct count for optimized distinct counting'
end
end
+
+ context 'when a relation is grouped' do
+ let!(:one_more_issue) { create(:issue, author: user, project: model.first.project) }
+
+ before do
+ stub_const('Gitlab::Database::BatchCounter::MIN_REQUIRED_BATCH_SIZE', 1)
+ end
+
+ context 'count by default column' do
+ let(:count) do
+ described_class.batch_count(model.group(column), batch_size: 2)
+ end
+
+ it 'counts grouped records' do
+ expect(count).to eq({ user.id => 4, another_user.id => 2 })
+ end
+ end
+ end
end
describe '#batch_distinct_count' do
@@ -151,10 +225,11 @@ RSpec.describe Gitlab::Database::BatchCount do
it "defaults the batch size to #{Gitlab::Database::BatchCounter::DEFAULT_DISTINCT_BATCH_SIZE}" do
min_id = model.minimum(:id)
+ relation = instance_double(ActiveRecord::Relation)
+ allow(model).to receive_message_chain(:select, public_send: relation)
+ batch_end_id = min_id + calculate_batch_size(Gitlab::Database::BatchCounter::DEFAULT_DISTINCT_BATCH_SIZE)
- expect_next_instance_of(Gitlab::Database::BatchCounter) do |batch_counter|
- expect(batch_counter).to receive(:batch_fetch).with(min_id, Gitlab::Database::BatchCounter::DEFAULT_DISTINCT_BATCH_SIZE + min_id, :distinct).once.and_call_original
- end
+ expect(relation).to receive(:where).with("id" => min_id..batch_end_id).and_return(double(send: 1))
described_class.batch_distinct_count(model)
end
@@ -175,6 +250,33 @@ RSpec.describe Gitlab::Database::BatchCount do
end.to raise_error 'Use distinct count only with non id fields'
end
end
+
+ context 'when a relation is grouped' do
+ let!(:one_more_issue) { create(:issue, author: user, project: model.first.project) }
+
+ before do
+ stub_const('Gitlab::Database::BatchCounter::MIN_REQUIRED_BATCH_SIZE', 1)
+ end
+
+ context 'distinct count by non-unique column' do
+ let(:count) do
+ described_class.batch_distinct_count(model.group(column), :project_id, batch_size: 2)
+ end
+
+ it 'counts grouped records' do
+ expect(count).to eq({ user.id => 3, another_user.id => 2 })
+ end
+ end
+ end
+
+ it_behaves_like 'when batch fetch query is canceled' do
+ let(:mode) { :distinct }
+ let(:operation) { :count }
+ let(:operation_args) { nil }
+ let(:column) { nil }
+
+ subject { described_class.method(:batch_distinct_count) }
+ end
end
describe '#batch_sum' do
@@ -209,10 +311,11 @@ RSpec.describe Gitlab::Database::BatchCount do
it "defaults the batch size to #{Gitlab::Database::BatchCounter::DEFAULT_SUM_BATCH_SIZE}" do
min_id = model.minimum(:id)
+ relation = instance_double(ActiveRecord::Relation)
+ allow(model).to receive_message_chain(:select, public_send: relation)
+ batch_end_id = min_id + calculate_batch_size(Gitlab::Database::BatchCounter::DEFAULT_SUM_BATCH_SIZE)
- expect_next_instance_of(Gitlab::Database::BatchCounter) do |batch_counter|
- expect(batch_counter).to receive(:batch_fetch).with(min_id, Gitlab::Database::BatchCounter::DEFAULT_SUM_BATCH_SIZE + min_id, :itself).once.and_call_original
- end
+ expect(relation).to receive(:where).with("id" => min_id..batch_end_id).and_return(double(send: 1))
described_class.batch_sum(model, column)
end
@@ -226,5 +329,13 @@ RSpec.describe Gitlab::Database::BatchCount do
let(:default_batch_size) { Gitlab::Database::BatchCounter::DEFAULT_SUM_BATCH_SIZE }
let(:small_batch_size) { Gitlab::Database::BatchCounter::DEFAULT_SUM_BATCH_SIZE - 1 }
end
+
+ it_behaves_like 'when batch fetch query is canceled' do
+ let(:mode) { :itself }
+ let(:operation) { :sum }
+ let(:operation_args) { [column] }
+
+ subject { described_class.method(:batch_sum) }
+ end
end
end
diff --git a/spec/lib/gitlab/database/bulk_update_spec.rb b/spec/lib/gitlab/database/bulk_update_spec.rb
new file mode 100644
index 00000000000..f2a7d6e69d8
--- /dev/null
+++ b/spec/lib/gitlab/database/bulk_update_spec.rb
@@ -0,0 +1,139 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Database::BulkUpdate do
+ describe 'error states' do
+ let(:columns) { %i[title] }
+
+ let_it_be(:mapping) do
+ create_default(:user)
+ create_default(:project)
+
+ i_a, i_b = create_list(:issue, 2)
+
+ {
+ i_a => { title: 'Issue a' },
+ i_b => { title: 'Issue b' }
+ }
+ end
+
+ it 'does not raise errors on valid inputs' do
+ expect { described_class.execute(columns, mapping) }.not_to raise_error
+ end
+
+ it 'expects a non-empty list of column names' do
+ expect { described_class.execute([], mapping) }.to raise_error(ArgumentError)
+ end
+
+ it 'expects all columns to be symbols' do
+ expect { described_class.execute([1], mapping) }.to raise_error(ArgumentError)
+ end
+
+ it 'expects all columns to be valid columns on the tables' do
+ expect { described_class.execute([:foo], mapping) }.to raise_error(ArgumentError)
+ end
+
+ it 'refuses to set ID' do
+ expect { described_class.execute([:id], mapping) }.to raise_error(ArgumentError)
+ end
+
+ it 'expects a non-empty mapping' do
+ expect { described_class.execute(columns, []) }.to raise_error(ArgumentError)
+ end
+
+ it 'expects all map values to be Hash instances' do
+ bad_map = mapping.merge(build(:issue) => 2)
+
+ expect { described_class.execute(columns, bad_map) }.to raise_error(ArgumentError)
+ end
+ end
+
+ it 'is possible to update all objects in a single query' do
+ users = create_list(:user, 3)
+ mapping = users.zip(%w(foo bar baz)).to_h do |u, name|
+ [u, { username: name, admin: true }]
+ end
+
+ expect do
+ described_class.execute(%i[username admin], mapping)
+ end.not_to exceed_query_limit(1)
+
+ # We have optimistically updated the values
+ expect(users).to all(be_admin)
+ expect(users.map(&:username)).to eq(%w(foo bar baz))
+
+ users.each(&:reset)
+
+ # The values are correct on reset
+ expect(users).to all(be_admin)
+ expect(users.map(&:username)).to eq(%w(foo bar baz))
+ end
+
+ it 'is possible to update heterogeneous sets' do
+ create_default(:user)
+ create_default(:project)
+
+ mr_a = create(:merge_request)
+ i_a, i_b = create_list(:issue, 2)
+
+ mapping = {
+ mr_a => { title: 'MR a' },
+ i_a => { title: 'Issue a' },
+ i_b => { title: 'Issue b' }
+ }
+
+ expect do
+ described_class.execute(%i[title], mapping)
+ end.not_to exceed_query_limit(2)
+
+ expect([mr_a, i_a, i_b].map { |x| x.reset.title })
+ .to eq(['MR a', 'Issue a', 'Issue b'])
+ end
+
+ shared_examples 'basic functionality' do
+ it 'sets multiple values' do
+ create_default(:user)
+ create_default(:project)
+
+ i_a, i_b = create_list(:issue, 2)
+
+ mapping = {
+ i_a => { title: 'Issue a' },
+ i_b => { title: 'Issue b' }
+ }
+
+ described_class.execute(%i[title], mapping)
+
+ expect([i_a, i_b].map { |x| x.reset.title })
+ .to eq(['Issue a', 'Issue b'])
+ end
+ end
+
+ include_examples 'basic functionality'
+
+ context 'when prepared statements are configured differently to the normal test environment' do
+ # rubocop: disable RSpec/LeakyConstantDeclaration
+ # This cop is disabled because you cannot call establish_connection on
+ # an anonymous class.
+ class ActiveRecordBasePreparedStatementsInverted < ActiveRecord::Base
+ def self.abstract_class?
+ true # So it gets its own connection
+ end
+ end
+ # rubocop: enable RSpec/LeakyConstantDeclaration
+
+ before_all do
+ c = ActiveRecord::Base.connection.instance_variable_get(:@config)
+ inverted = c.merge(prepared_statements: !ActiveRecord::Base.connection.prepared_statements)
+ ActiveRecordBasePreparedStatementsInverted.establish_connection(inverted)
+ end
+
+ before do
+ allow(ActiveRecord::Base).to receive(:connection_specification_name)
+ .and_return(ActiveRecordBasePreparedStatementsInverted.connection_specification_name)
+ end
+
+ include_examples 'basic functionality'
+ end
+end
diff --git a/spec/lib/gitlab/database/concurrent_reindex_spec.rb b/spec/lib/gitlab/database/concurrent_reindex_spec.rb
deleted file mode 100644
index 4e2c3f547d4..00000000000
--- a/spec/lib/gitlab/database/concurrent_reindex_spec.rb
+++ /dev/null
@@ -1,207 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::Database::ConcurrentReindex, '#execute' do
- subject { described_class.new(index_name, logger: logger) }
-
- let(:table_name) { '_test_reindex_table' }
- let(:column_name) { '_test_column' }
- let(:index_name) { '_test_reindex_index' }
- let(:logger) { double('logger', debug: nil, info: nil, error: nil ) }
- let(:connection) { ActiveRecord::Base.connection }
-
- before do
- connection.execute(<<~SQL)
- CREATE TABLE #{table_name} (
- id serial NOT NULL PRIMARY KEY,
- #{column_name} integer NOT NULL);
-
- CREATE INDEX #{index_name} ON #{table_name} (#{column_name});
- SQL
- end
-
- context 'when the index does not exist' do
- before do
- connection.execute(<<~SQL)
- DROP INDEX #{index_name}
- SQL
- end
-
- it 'raises an error' do
- expect { subject.execute }.to raise_error(described_class::ReindexError, /does not exist/)
- end
- end
-
- context 'when the index is unique' do
- before do
- connection.execute(<<~SQL)
- DROP INDEX #{index_name};
- CREATE UNIQUE INDEX #{index_name} ON #{table_name} (#{column_name})
- SQL
- end
-
- it 'raises an error' do
- expect do
- subject.execute
- end.to raise_error(described_class::ReindexError, /UNIQUE indexes are currently not supported/)
- end
- end
-
- context 'replacing the original index with a rebuilt copy' do
- let(:replacement_name) { 'tmp_reindex__test_reindex_index' }
- let(:replaced_name) { 'old_reindex__test_reindex_index' }
-
- let(:create_index) { "CREATE INDEX CONCURRENTLY #{replacement_name} ON public.#{table_name} USING btree (#{column_name})" }
- let(:drop_index) { "DROP INDEX CONCURRENTLY IF EXISTS #{replacement_name}" }
-
- let!(:original_index) { find_index_create_statement }
-
- before do
- allow(subject).to receive(:connection).and_return(connection)
- allow(subject).to receive(:disable_statement_timeout).and_yield
- end
-
- it 'replaces the existing index with an identical index' do
- expect(subject).to receive(:disable_statement_timeout).exactly(3).times.and_yield
-
- expect_to_execute_concurrently_in_order(drop_index)
- expect_to_execute_concurrently_in_order(create_index)
-
- expect_next_instance_of(::Gitlab::Database::WithLockRetries) do |instance|
- expect(instance).to receive(:run).with(raise_on_exhaustion: true).and_yield
- end
-
- expect_to_execute_in_order("ALTER INDEX #{index_name} RENAME TO #{replaced_name}")
- expect_to_execute_in_order("ALTER INDEX #{replacement_name} RENAME TO #{index_name}")
- expect_to_execute_in_order("ALTER INDEX #{replaced_name} RENAME TO #{replacement_name}")
-
- expect_to_execute_concurrently_in_order(drop_index)
-
- subject.execute
-
- check_index_exists
- end
-
- context 'when a dangling index is left from a previous run' do
- before do
- connection.execute("CREATE INDEX #{replacement_name} ON #{table_name} (#{column_name})")
- end
-
- it 'replaces the existing index with an identical index' do
- expect(subject).to receive(:disable_statement_timeout).exactly(3).times.and_yield
-
- expect_to_execute_concurrently_in_order(drop_index)
- expect_to_execute_concurrently_in_order(create_index)
-
- expect_next_instance_of(::Gitlab::Database::WithLockRetries) do |instance|
- expect(instance).to receive(:run).with(raise_on_exhaustion: true).and_yield
- end
-
- expect_to_execute_in_order("ALTER INDEX #{index_name} RENAME TO #{replaced_name}")
- expect_to_execute_in_order("ALTER INDEX #{replacement_name} RENAME TO #{index_name}")
- expect_to_execute_in_order("ALTER INDEX #{replaced_name} RENAME TO #{replacement_name}")
-
- expect_to_execute_concurrently_in_order(drop_index)
-
- subject.execute
-
- check_index_exists
- end
- end
-
- context 'when it fails to create the replacement index' do
- it 'safely cleans up and signals the error' do
- expect_to_execute_concurrently_in_order(drop_index)
-
- expect(connection).to receive(:execute).with(create_index).ordered
- .and_raise(ActiveRecord::ConnectionTimeoutError, 'connect timeout')
-
- expect_to_execute_concurrently_in_order(drop_index)
-
- expect { subject.execute }.to raise_error(described_class::ReindexError, /connect timeout/)
-
- check_index_exists
- end
- end
-
- context 'when the replacement index is not valid' do
- it 'safely cleans up and signals the error' do
- expect_to_execute_concurrently_in_order(drop_index)
- expect_to_execute_concurrently_in_order(create_index)
-
- expect(subject).to receive(:replacement_index_valid?).and_return(false)
-
- expect_to_execute_concurrently_in_order(drop_index)
-
- expect { subject.execute }.to raise_error(described_class::ReindexError, /replacement index was created as INVALID/)
-
- check_index_exists
- end
- end
-
- context 'when a database error occurs while swapping the indexes' do
- it 'safely cleans up and signals the error' do
- expect_to_execute_concurrently_in_order(drop_index)
- expect_to_execute_concurrently_in_order(create_index)
-
- expect_next_instance_of(::Gitlab::Database::WithLockRetries) do |instance|
- expect(instance).to receive(:run).with(raise_on_exhaustion: true).and_yield
- end
-
- expect(connection).to receive(:execute).ordered
- .with("ALTER INDEX #{index_name} RENAME TO #{replaced_name}")
- .and_raise(ActiveRecord::ConnectionTimeoutError, 'connect timeout')
-
- expect_to_execute_concurrently_in_order(drop_index)
-
- expect { subject.execute }.to raise_error(described_class::ReindexError, /connect timeout/)
-
- check_index_exists
- end
- end
-
- context 'when with_lock_retries fails to acquire the lock' do
- it 'safely cleans up and signals the error' do
- expect_to_execute_concurrently_in_order(drop_index)
- expect_to_execute_concurrently_in_order(create_index)
-
- expect_next_instance_of(::Gitlab::Database::WithLockRetries) do |instance|
- expect(instance).to receive(:run).with(raise_on_exhaustion: true)
- .and_raise(::Gitlab::Database::WithLockRetries::AttemptsExhaustedError, 'exhausted')
- end
-
- expect_to_execute_concurrently_in_order(drop_index)
-
- expect { subject.execute }.to raise_error(described_class::ReindexError, /exhausted/)
-
- check_index_exists
- end
- end
- end
-
- def expect_to_execute_concurrently_in_order(sql)
- # Indexes cannot be created CONCURRENTLY in a transaction. Since the tests are wrapped in transactions,
- # verify the original call but pass through the non-concurrent form.
- expect(connection).to receive(:execute).with(sql).ordered.and_wrap_original do |method, sql|
- method.call(sql.sub(/CONCURRENTLY/, ''))
- end
- end
-
- def expect_to_execute_in_order(sql)
- expect(connection).to receive(:execute).with(sql).ordered.and_call_original
- end
-
- def find_index_create_statement
- ActiveRecord::Base.connection.select_value(<<~SQL)
- SELECT indexdef
- FROM pg_indexes
- WHERE schemaname = 'public'
- AND indexname = #{ActiveRecord::Base.connection.quote(index_name)}
- SQL
- end
-
- def check_index_exists
- expect(find_index_create_statement).to eq(original_index)
- end
-end
diff --git a/spec/lib/gitlab/database/migration_helpers_spec.rb b/spec/lib/gitlab/database/migration_helpers_spec.rb
index 0bdcca630aa..a8edcc5f7e5 100644
--- a/spec/lib/gitlab/database/migration_helpers_spec.rb
+++ b/spec/lib/gitlab/database/migration_helpers_spec.rb
@@ -699,6 +699,7 @@ RSpec.describe Gitlab::Database::MigrationHelpers do
expect(model).to receive(:copy_indexes).with(:users, :old, :new)
expect(model).to receive(:copy_foreign_keys).with(:users, :old, :new)
+ expect(model).to receive(:copy_check_constraints).with(:users, :old, :new)
model.rename_column_concurrently(:users, :old, :new)
end
@@ -761,6 +762,9 @@ RSpec.describe Gitlab::Database::MigrationHelpers do
expect(model).to receive(:change_column_default)
.with(:users, :new, old_column.default)
+ expect(model).to receive(:copy_check_constraints)
+ .with(:users, :old, :new)
+
model.rename_column_concurrently(:users, :old, :new)
end
end
@@ -856,6 +860,7 @@ RSpec.describe Gitlab::Database::MigrationHelpers do
expect(model).to receive(:copy_indexes).with(:users, :new, :old)
expect(model).to receive(:copy_foreign_keys).with(:users, :new, :old)
+ expect(model).to receive(:copy_check_constraints).with(:users, :new, :old)
model.undo_cleanup_concurrent_column_rename(:users, :old, :new)
end
@@ -894,6 +899,9 @@ RSpec.describe Gitlab::Database::MigrationHelpers do
expect(model).to receive(:change_column_default)
.with(:users, :old, new_column.default)
+ expect(model).to receive(:copy_check_constraints)
+ .with(:users, :new, :old)
+
model.undo_cleanup_concurrent_column_rename(:users, :old, :new)
end
end
@@ -925,6 +933,19 @@ RSpec.describe Gitlab::Database::MigrationHelpers do
end
end
+ describe '#undo_change_column_type_concurrently' do
+ it 'reverses the operations of change_column_type_concurrently' do
+ expect(model).to receive(:check_trigger_permissions!).with(:users)
+
+ expect(model).to receive(:remove_rename_triggers_for_postgresql)
+ .with(:users, /trigger_.{12}/)
+
+ expect(model).to receive(:remove_column).with(:users, "old_for_type_change")
+
+ model.undo_change_column_type_concurrently(:users, :old)
+ end
+ end
+
describe '#cleanup_concurrent_column_type_change' do
it 'cleans up the type changing procedure' do
expect(model).to receive(:cleanup_concurrent_column_rename)
@@ -937,6 +958,94 @@ RSpec.describe Gitlab::Database::MigrationHelpers do
end
end
+ describe '#undo_cleanup_concurrent_column_type_change' do
+ context 'in a transaction' do
+ it 'raises RuntimeError' do
+ allow(model).to receive(:transaction_open?).and_return(true)
+
+ expect { model.undo_cleanup_concurrent_column_type_change(:users, :old, :new) }
+ .to raise_error(RuntimeError)
+ end
+ end
+
+ context 'outside a transaction' do
+ let(:temp_column) { "old_for_type_change" }
+
+ let(:temp_undo_cleanup_column) do
+ identifier = "users_old_for_type_change"
+ hashed_identifier = Digest::SHA256.hexdigest(identifier).first(10)
+ "tmp_undo_cleanup_column_#{hashed_identifier}"
+ end
+
+ let(:trigger_name) { model.rename_trigger_name(:users, :old, :old_for_type_change) }
+
+ before do
+ allow(model).to receive(:transaction_open?).and_return(false)
+ end
+
+ it 'reverses the operations of cleanup_concurrent_column_type_change' do
+ expect(model).to receive(:check_trigger_permissions!).with(:users)
+
+ expect(model).to receive(:create_column_from).with(
+ :users,
+ :old,
+ temp_undo_cleanup_column,
+ type: :string,
+ batch_column_name: :id,
+ type_cast_function: nil
+ ).and_return(true)
+
+ expect(model).to receive(:rename_column)
+ .with(:users, :old, temp_column)
+
+ expect(model).to receive(:rename_column)
+ .with(:users, temp_undo_cleanup_column, :old)
+
+ expect(model).to receive(:install_rename_triggers_for_postgresql)
+ .with(trigger_name, '"users"', '"old"', '"old_for_type_change"')
+
+ model.undo_cleanup_concurrent_column_type_change(:users, :old, :string)
+ end
+
+ it 'passes the type_cast_function and batch_column_name' do
+ expect(model).to receive(:column_exists?).with(:users, :other_batch_column).and_return(true)
+ expect(model).to receive(:check_trigger_permissions!).with(:users)
+
+ expect(model).to receive(:create_column_from).with(
+ :users,
+ :old,
+ temp_undo_cleanup_column,
+ type: :string,
+ batch_column_name: :other_batch_column,
+ type_cast_function: :custom_type_cast_function
+ ).and_return(true)
+
+ expect(model).to receive(:rename_column)
+ .with(:users, :old, temp_column)
+
+ expect(model).to receive(:rename_column)
+ .with(:users, temp_undo_cleanup_column, :old)
+
+ expect(model).to receive(:install_rename_triggers_for_postgresql)
+ .with(trigger_name, '"users"', '"old"', '"old_for_type_change"')
+
+ model.undo_cleanup_concurrent_column_type_change(
+ :users,
+ :old,
+ :string,
+ type_cast_function: :custom_type_cast_function,
+ batch_column_name: :other_batch_column
+ )
+ end
+
+ it 'raises an error with invalid batch_column_name' do
+ expect do
+ model.undo_cleanup_concurrent_column_type_change(:users, :old, :new, batch_column_name: :invalid)
+ end.to raise_error(RuntimeError, /Column invalid does not exist on users/)
+ end
+ end
+ end
+
describe '#install_rename_triggers_for_postgresql' do
it 'installs the triggers for PostgreSQL' do
expect(model).to receive(:execute)
@@ -1128,7 +1237,65 @@ RSpec.describe Gitlab::Database::MigrationHelpers do
name: 'index_on_issues_gl_project_id',
length: [],
order: [],
- opclasses: { 'gl_project_id' => 'bar' })
+ opclass: { 'gl_project_id' => 'bar' })
+
+ model.copy_indexes(:issues, :project_id, :gl_project_id)
+ end
+ end
+
+ context 'using an index with multiple columns and custom operator classes' do
+ it 'copies the index' do
+ index = double(:index,
+ columns: %w(project_id foobar),
+ name: 'index_on_issues_project_id_foobar',
+ using: :gin,
+ where: nil,
+ opclasses: { 'project_id' => 'bar', 'foobar' => :gin_trgm_ops },
+ unique: false,
+ lengths: [],
+ orders: [])
+
+ allow(model).to receive(:indexes_for).with(:issues, 'project_id')
+ .and_return([index])
+
+ expect(model).to receive(:add_concurrent_index)
+ .with(:issues,
+ %w(gl_project_id foobar),
+ unique: false,
+ name: 'index_on_issues_gl_project_id_foobar',
+ length: [],
+ order: [],
+ opclass: { 'gl_project_id' => 'bar', 'foobar' => :gin_trgm_ops },
+ using: :gin)
+
+ model.copy_indexes(:issues, :project_id, :gl_project_id)
+ end
+ end
+
+ context 'using an index with multiple columns and a custom operator class on the non affected column' do
+ it 'copies the index' do
+ index = double(:index,
+ columns: %w(project_id foobar),
+ name: 'index_on_issues_project_id_foobar',
+ using: :gin,
+ where: nil,
+ opclasses: { 'foobar' => :gin_trgm_ops },
+ unique: false,
+ lengths: [],
+ orders: [])
+
+ allow(model).to receive(:indexes_for).with(:issues, 'project_id')
+ .and_return([index])
+
+ expect(model).to receive(:add_concurrent_index)
+ .with(:issues,
+ %w(gl_project_id foobar),
+ unique: false,
+ name: 'index_on_issues_gl_project_id_foobar',
+ length: [],
+ order: [],
+ opclass: { 'foobar' => :gin_trgm_ops },
+ using: :gin)
model.copy_indexes(:issues, :project_id, :gl_project_id)
end
@@ -1400,15 +1567,32 @@ RSpec.describe Gitlab::Database::MigrationHelpers do
)
end
- after do
- 'DROP INDEX IF EXISTS test_index;'
- end
-
it 'returns true if an index exists' do
expect(model.index_exists_by_name?(:projects, 'test_index'))
.to be_truthy
end
end
+
+ context 'when an index exists for a table with the same name in another schema' do
+ before do
+ ActiveRecord::Base.connection.execute(
+ 'CREATE SCHEMA new_test_schema'
+ )
+
+ ActiveRecord::Base.connection.execute(
+ 'CREATE TABLE new_test_schema.projects (id integer, name character varying)'
+ )
+
+ ActiveRecord::Base.connection.execute(
+ 'CREATE INDEX test_index_on_name ON new_test_schema.projects (LOWER(name));'
+ )
+ end
+
+ it 'returns false if the index does not exist in the current schema' do
+ expect(model.index_exists_by_name?(:projects, 'test_index_on_name'))
+ .to be_falsy
+ end
+ end
end
describe '#create_or_update_plan_limit' do
@@ -1863,11 +2047,17 @@ RSpec.describe Gitlab::Database::MigrationHelpers do
ActiveRecord::Base.connection.execute(
'ALTER TABLE projects ADD CONSTRAINT check_1 CHECK (char_length(path) <= 5) NOT VALID'
)
- end
- after do
ActiveRecord::Base.connection.execute(
- 'ALTER TABLE projects DROP CONSTRAINT IF EXISTS check_1'
+ 'CREATE SCHEMA new_test_schema'
+ )
+
+ ActiveRecord::Base.connection.execute(
+ 'CREATE TABLE new_test_schema.projects (id integer, name character varying)'
+ )
+
+ ActiveRecord::Base.connection.execute(
+ 'ALTER TABLE new_test_schema.projects ADD CONSTRAINT check_2 CHECK (char_length(name) <= 5)'
)
end
@@ -1885,6 +2075,11 @@ RSpec.describe Gitlab::Database::MigrationHelpers 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
@@ -2086,6 +2281,138 @@ RSpec.describe Gitlab::Database::MigrationHelpers do
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
diff --git a/spec/lib/gitlab/database/obsolete_ignored_columns_spec.rb b/spec/lib/gitlab/database/obsolete_ignored_columns_spec.rb
index 034bf966db7..8a35d8149ad 100644
--- a/spec/lib/gitlab/database/obsolete_ignored_columns_spec.rb
+++ b/spec/lib/gitlab/database/obsolete_ignored_columns_spec.rb
@@ -52,7 +52,7 @@ RSpec.describe Gitlab::Database::ObsoleteIgnoredColumns do
describe '#execute' do
it 'returns a list of class names and columns pairs' do
- Timecop.freeze(REMOVE_DATE) do
+ travel_to(REMOVE_DATE) do
expect(subject.execute).to eq([
['Testing::A', {
'unused' => IgnorableColumns::ColumnIgnore.new(Date.parse('2019-01-01'), '12.0'),
diff --git a/spec/lib/gitlab/database/partitioning/monthly_strategy_spec.rb b/spec/lib/gitlab/database/partitioning/monthly_strategy_spec.rb
index 334cac653cf..885eef5723e 100644
--- a/spec/lib/gitlab/database/partitioning/monthly_strategy_spec.rb
+++ b/spec/lib/gitlab/database/partitioning/monthly_strategy_spec.rb
@@ -47,7 +47,7 @@ RSpec.describe Gitlab::Database::Partitioning::MonthlyStrategy do
let(:partitioning_key) { :created_at }
around do |example|
- Timecop.freeze(Date.parse('2020-08-22')) { example.run }
+ travel_to(Date.parse('2020-08-22')) { example.run }
end
context 'with existing partitions' do
diff --git a/spec/lib/gitlab/database/partitioning_migration_helpers/backfill_partitioned_table_spec.rb b/spec/lib/gitlab/database/partitioning_migration_helpers/backfill_partitioned_table_spec.rb
index ec3d0a6dbcb..c43b51e10a0 100644
--- a/spec/lib/gitlab/database/partitioning_migration_helpers/backfill_partitioned_table_spec.rb
+++ b/spec/lib/gitlab/database/partitioning_migration_helpers/backfill_partitioned_table_spec.rb
@@ -116,23 +116,6 @@ RSpec.describe Gitlab::Database::PartitioningMigrationHelpers::BackfillPartition
expect(jobs_updated).to eq(1)
end
- context 'when the feature flag is disabled' do
- let(:mock_connection) { double('connection') }
-
- before do
- allow(subject).to receive(:connection).and_return(mock_connection)
- stub_feature_flags(backfill_partitioned_audit_events: false)
- end
-
- it 'exits without attempting to copy data' do
- expect(mock_connection).not_to receive(:execute)
-
- subject.perform(1, 100, source_table, destination_table, unique_key)
-
- expect(destination_model.count).to eq(0)
- end
- end
-
context 'when the job is run within an explicit transaction block' do
let(:mock_connection) { double('connection') }
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 44ef0b307fe..147637cf471 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
@@ -213,7 +213,7 @@ RSpec.describe Gitlab::Database::PartitioningMigrationHelpers::TableManagementHe
it 'creates partitions including the next month from today' do
today = Date.new(2020, 5, 8)
- Timecop.freeze(today) do
+ travel_to(today) do
migration.partition_table_by_date source_table, partition_column, min_date: min_date
expect_range_partitions_for(partitioned_table, {
@@ -233,7 +233,7 @@ RSpec.describe Gitlab::Database::PartitioningMigrationHelpers::TableManagementHe
context 'without min_date, max_date' do
it 'creates partitions for the current and next month' do
current_date = Date.new(2020, 05, 22)
- Timecop.freeze(current_date.to_time) do
+ travel_to(current_date.to_time) do
migration.partition_table_by_date source_table, partition_column
expect_range_partitions_for(partitioned_table, {
@@ -514,6 +514,7 @@ RSpec.describe Gitlab::Database::PartitioningMigrationHelpers::TableManagementHe
allow(migration).to receive(:table_exists?).with(partitioned_table).and_return(true)
allow(migration).to receive(:copy_missed_records)
allow(migration).to receive(:execute).with(/VACUUM/)
+ allow(migration).to receive(:execute).with(/^(RE)?SET/)
end
it 'finishes remaining jobs for the correct table' do
@@ -567,6 +568,7 @@ RSpec.describe Gitlab::Database::PartitioningMigrationHelpers::TableManagementHe
allow(Gitlab::BackgroundMigration).to receive(:steal)
allow(migration).to receive(:execute).with(/VACUUM/)
+ allow(migration).to receive(:execute).with(/^(RE)?SET/)
end
it 'idempotently cleans up after failed background migrations' do
diff --git a/spec/lib/gitlab/database/postgres_index_spec.rb b/spec/lib/gitlab/database/postgres_index_spec.rb
new file mode 100644
index 00000000000..1da67a5a6c0
--- /dev/null
+++ b/spec/lib/gitlab/database/postgres_index_spec.rb
@@ -0,0 +1,116 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Database::PostgresIndex do
+ before do
+ ActiveRecord::Base.connection.execute(<<~SQL)
+ CREATE INDEX foo_idx ON public.users (name);
+ CREATE UNIQUE INDEX bar_key ON public.users (id);
+
+ CREATE TABLE example_table (id serial primary key);
+ SQL
+ end
+
+ def find(name)
+ described_class.by_identifier(name)
+ end
+
+ describe '.by_identifier' do
+ it 'finds the index' do
+ expect(find('public.foo_idx')).to be_a(Gitlab::Database::PostgresIndex)
+ end
+
+ it 'raises an error if not found' do
+ expect { find('public.idontexist') }.to raise_error(ActiveRecord::RecordNotFound)
+ end
+
+ it 'raises ArgumentError if given a non-fully qualified index name' do
+ expect { find('foo') }.to raise_error(ArgumentError, /not fully qualified/)
+ end
+ end
+
+ describe '.regular' do
+ it 'only non-unique indexes' do
+ expect(described_class.regular).to all(have_attributes(unique: false))
+ end
+
+ it 'only non partitioned indexes ' do
+ expect(described_class.regular).to all(have_attributes(partitioned: false))
+ end
+
+ it 'only indexes that dont serve an exclusion constraint' do
+ expect(described_class.regular).to all(have_attributes(exclusion: false))
+ end
+ end
+
+ describe '.not_match' do
+ it 'excludes indexes matching the given regex' do
+ expect(described_class.not_match('^bar_k').map(&:name)).to all(match(/^(?!bar_k).*/))
+ end
+
+ it 'matches indexes without this prefix regex' do
+ expect(described_class.not_match('^bar_k')).not_to be_empty
+ end
+ end
+
+ describe '.random_few' do
+ it 'limits to two records by default' do
+ expect(described_class.random_few(2).size).to eq(2)
+ end
+ end
+
+ describe '#unique?' do
+ it 'returns true for a unique index' do
+ expect(find('public.bar_key')).to be_unique
+ end
+
+ it 'returns false for a regular, non-unique index' do
+ expect(find('public.foo_idx')).not_to be_unique
+ end
+
+ it 'returns true for a primary key index' do
+ expect(find('public.example_table_pkey')).to be_unique
+ end
+ end
+
+ describe '#valid_index?' do
+ it 'returns true if the index is invalid' do
+ expect(find('public.foo_idx')).to be_valid_index
+ end
+
+ it 'returns false if the index is marked as invalid' do
+ ActiveRecord::Base.connection.execute(<<~SQL)
+ UPDATE pg_index SET indisvalid=false
+ FROM pg_class
+ WHERE pg_class.relname = 'foo_idx' AND pg_index.indexrelid = pg_class.oid
+ SQL
+
+ expect(find('public.foo_idx')).not_to be_valid_index
+ end
+ end
+
+ describe '#to_s' do
+ it 'returns the index name' do
+ expect(find('public.foo_idx').to_s).to eq('foo_idx')
+ end
+ end
+
+ describe '#name' do
+ it 'returns the name' do
+ expect(find('public.foo_idx').name).to eq('foo_idx')
+ end
+ end
+
+ describe '#schema' do
+ it 'returns the index schema' do
+ expect(find('public.foo_idx').schema).to eq('public')
+ end
+ end
+
+ describe '#definition' do
+ it 'returns the index definition' do
+ expect(find('public.foo_idx').definition).to eq('CREATE INDEX foo_idx ON public.users USING btree (name)')
+ end
+ end
+end
diff --git a/spec/lib/gitlab/database/reindexing/concurrent_reindex_spec.rb b/spec/lib/gitlab/database/reindexing/concurrent_reindex_spec.rb
new file mode 100644
index 00000000000..2d6765aac2e
--- /dev/null
+++ b/spec/lib/gitlab/database/reindexing/concurrent_reindex_spec.rb
@@ -0,0 +1,255 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Database::Reindexing::ConcurrentReindex, '#perform' do
+ subject { described_class.new(index, logger: logger) }
+
+ let(:table_name) { '_test_reindex_table' }
+ let(:column_name) { '_test_column' }
+ let(:index_name) { '_test_reindex_index' }
+ let(:index) { instance_double(Gitlab::Database::PostgresIndex, indexrelid: 42, name: index_name, schema: 'public', partitioned?: false, unique?: false, exclusion?: false, definition: 'CREATE INDEX _test_reindex_index ON public._test_reindex_table USING btree (_test_column)') }
+ let(:logger) { double('logger', debug: nil, info: nil, error: nil ) }
+ let(:connection) { ActiveRecord::Base.connection }
+
+ before do
+ connection.execute(<<~SQL)
+ CREATE TABLE #{table_name} (
+ id serial NOT NULL PRIMARY KEY,
+ #{column_name} integer NOT NULL);
+
+ CREATE INDEX #{index.name} ON #{table_name} (#{column_name});
+ SQL
+ end
+
+ context 'when the index is unique' do
+ before do
+ allow(index).to receive(:unique?).and_return(true)
+ end
+
+ it 'raises an error' do
+ expect do
+ subject.perform
+ end.to raise_error(described_class::ReindexError, /UNIQUE indexes are currently not supported/)
+ end
+ end
+
+ context 'when the index is partitioned' do
+ before do
+ allow(index).to receive(:partitioned?).and_return(true)
+ end
+
+ it 'raises an error' do
+ expect do
+ subject.perform
+ end.to raise_error(described_class::ReindexError, /partitioned indexes are currently not supported/)
+ end
+ end
+
+ context 'when the index serves an exclusion constraint' do
+ before do
+ allow(index).to receive(:exclusion?).and_return(true)
+ end
+
+ it 'raises an error' do
+ expect do
+ subject.perform
+ end.to raise_error(described_class::ReindexError, /indexes serving an exclusion constraint are currently not supported/)
+ end
+ end
+
+ context 'when the index is a lingering temporary index from a previous reindexing run' do
+ context 'with the temporary index prefix' do
+ let(:index_name) { 'tmp_reindex_something' }
+
+ it 'raises an error' do
+ expect do
+ subject.perform
+ end.to raise_error(described_class::ReindexError, /left-over temporary index/)
+ end
+ end
+
+ context 'with the replaced index prefix' do
+ let(:index_name) { 'old_reindex_something' }
+
+ it 'raises an error' do
+ expect do
+ subject.perform
+ end.to raise_error(described_class::ReindexError, /left-over temporary index/)
+ end
+ end
+ end
+
+ context 'replacing the original index with a rebuilt copy' do
+ let(:replacement_name) { 'tmp_reindex_42' }
+ let(:replaced_name) { 'old_reindex_42' }
+
+ let(:create_index) { "CREATE INDEX CONCURRENTLY #{replacement_name} ON public.#{table_name} USING btree (#{column_name})" }
+ let(:drop_index) do
+ <<~SQL
+ DROP INDEX CONCURRENTLY
+ IF EXISTS "public"."#{replacement_name}"
+ SQL
+ end
+
+ let!(:original_index) { find_index_create_statement }
+
+ it 'integration test: executing full index replacement without mocks' do
+ allow(connection).to receive(:execute).and_wrap_original do |method, sql|
+ method.call(sql.sub(/CONCURRENTLY/, ''))
+ end
+
+ subject.perform
+
+ check_index_exists
+ end
+
+ context 'mocked specs' do
+ before do
+ allow(subject).to receive(:connection).and_return(connection)
+ allow(connection).to receive(:execute).and_call_original
+ end
+
+ it 'replaces the existing index with an identical index' do
+ expect(connection).to receive(:execute).with('SET statement_timeout TO \'21600s\'').twice
+
+ expect_to_execute_concurrently_in_order(create_index)
+
+ expect_next_instance_of(::Gitlab::Database::WithLockRetries) do |instance|
+ expect(instance).to receive(:run).with(raise_on_exhaustion: true).and_yield
+ end
+
+ expect_index_rename(index.name, replaced_name)
+ expect_index_rename(replacement_name, index.name)
+ expect_index_rename(replaced_name, replacement_name)
+
+ expect_to_execute_concurrently_in_order(drop_index)
+
+ subject.perform
+
+ check_index_exists
+ end
+
+ context 'when a dangling index is left from a previous run' do
+ before do
+ connection.execute("CREATE INDEX #{replacement_name} ON #{table_name} (#{column_name})")
+ end
+
+ it 'replaces the existing index with an identical index' do
+ expect(connection).to receive(:execute).with('SET statement_timeout TO \'21600s\'').exactly(3).times
+
+ expect_to_execute_concurrently_in_order(drop_index)
+ expect_to_execute_concurrently_in_order(create_index)
+
+ expect_next_instance_of(::Gitlab::Database::WithLockRetries) do |instance|
+ expect(instance).to receive(:run).with(raise_on_exhaustion: true).and_yield
+ end
+
+ expect_index_rename(index.name, replaced_name)
+ expect_index_rename(replacement_name, index.name)
+ expect_index_rename(replaced_name, replacement_name)
+
+ expect_to_execute_concurrently_in_order(drop_index)
+
+ subject.perform
+
+ check_index_exists
+ end
+ end
+
+ context 'when it fails to create the replacement index' do
+ it 'safely cleans up and signals the error' do
+ expect(connection).to receive(:execute).with(create_index).ordered
+ .and_raise(ActiveRecord::ConnectionTimeoutError, 'connect timeout')
+
+ expect_to_execute_concurrently_in_order(drop_index)
+
+ expect { subject.perform }.to raise_error(ActiveRecord::ConnectionTimeoutError, /connect timeout/)
+
+ check_index_exists
+ end
+ end
+
+ context 'when the replacement index is not valid' do
+ it 'safely cleans up and signals the error' do
+ replacement_index = double('replacement index', valid_index?: false)
+ allow(Gitlab::Database::PostgresIndex).to receive(:find_by).with(schema: 'public', name: replacement_name).and_return(nil, replacement_index)
+
+ expect_to_execute_concurrently_in_order(create_index)
+
+ expect_to_execute_concurrently_in_order(drop_index)
+
+ expect { subject.perform }.to raise_error(described_class::ReindexError, /replacement index was created as INVALID/)
+
+ check_index_exists
+ end
+ end
+
+ context 'when a database error occurs while swapping the indexes' do
+ it 'safely cleans up and signals the error' do
+ replacement_index = double('replacement index', valid_index?: true)
+ allow(Gitlab::Database::PostgresIndex).to receive(:find_by).with(schema: 'public', name: replacement_name).and_return(nil, replacement_index)
+
+ expect_to_execute_concurrently_in_order(create_index)
+
+ expect_next_instance_of(::Gitlab::Database::WithLockRetries) do |instance|
+ expect(instance).to receive(:run).with(raise_on_exhaustion: true).and_yield
+ end
+
+ expect_index_rename(index.name, replaced_name).and_raise(ActiveRecord::ConnectionTimeoutError, 'connect timeout')
+
+ expect_to_execute_concurrently_in_order(drop_index)
+
+ expect { subject.perform }.to raise_error(ActiveRecord::ConnectionTimeoutError, /connect timeout/)
+
+ check_index_exists
+ end
+ end
+
+ context 'when with_lock_retries fails to acquire the lock' do
+ it 'safely cleans up and signals the error' do
+ expect_to_execute_concurrently_in_order(create_index)
+
+ expect_next_instance_of(::Gitlab::Database::WithLockRetries) do |instance|
+ expect(instance).to receive(:run).with(raise_on_exhaustion: true)
+ .and_raise(::Gitlab::Database::WithLockRetries::AttemptsExhaustedError, 'exhausted')
+ end
+
+ expect_to_execute_concurrently_in_order(drop_index)
+
+ expect { subject.perform }.to raise_error(::Gitlab::Database::WithLockRetries::AttemptsExhaustedError, /exhausted/)
+
+ check_index_exists
+ end
+ end
+ end
+ end
+
+ def expect_to_execute_concurrently_in_order(sql)
+ # Indexes cannot be created CONCURRENTLY in a transaction. Since the tests are wrapped in transactions,
+ # verify the original call but pass through the non-concurrent form.
+ expect(connection).to receive(:execute).with(sql).ordered.and_wrap_original do |method, sql|
+ method.call(sql.sub(/CONCURRENTLY/, ''))
+ end
+ end
+
+ def expect_index_rename(from, to)
+ expect(connection).to receive(:execute).with(<<~SQL).ordered
+ ALTER INDEX "public"."#{from}"
+ RENAME TO "#{to}"
+ SQL
+ end
+
+ def find_index_create_statement
+ ActiveRecord::Base.connection.select_value(<<~SQL)
+ SELECT indexdef
+ FROM pg_indexes
+ WHERE schemaname = 'public'
+ AND indexname = #{ActiveRecord::Base.connection.quote(index.name)}
+ SQL
+ end
+
+ def check_index_exists
+ expect(find_index_create_statement).to eq(original_index)
+ end
+end
diff --git a/spec/lib/gitlab/database/reindexing/coordinator_spec.rb b/spec/lib/gitlab/database/reindexing/coordinator_spec.rb
new file mode 100644
index 00000000000..f45d959c0de
--- /dev/null
+++ b/spec/lib/gitlab/database/reindexing/coordinator_spec.rb
@@ -0,0 +1,68 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Database::Reindexing::Coordinator do
+ include ExclusiveLeaseHelpers
+
+ describe '.perform' do
+ subject { described_class.new(indexes).perform }
+
+ let(:indexes) { [instance_double(Gitlab::Database::PostgresIndex), instance_double(Gitlab::Database::PostgresIndex)] }
+ let(:reindexers) { [instance_double(Gitlab::Database::Reindexing::ConcurrentReindex), instance_double(Gitlab::Database::Reindexing::ConcurrentReindex)] }
+
+ let!(:lease) { stub_exclusive_lease(lease_key, uuid, timeout: lease_timeout) }
+ let(:lease_key) { 'gitlab/database/reindexing/coordinator' }
+ let(:lease_timeout) { 1.day }
+ let(:uuid) { 'uuid' }
+
+ before do
+ allow(Gitlab::Database::Reindexing::ReindexAction).to receive(:keep_track_of).and_yield
+
+ indexes.zip(reindexers).each do |index, reindexer|
+ allow(Gitlab::Database::Reindexing::ConcurrentReindex).to receive(:new).with(index).and_return(reindexer)
+ allow(reindexer).to receive(:perform)
+ end
+ end
+
+ it 'performs concurrent reindexing for each index' do
+ indexes.zip(reindexers).each do |index, reindexer|
+ expect(Gitlab::Database::Reindexing::ConcurrentReindex).to receive(:new).with(index).ordered.and_return(reindexer)
+ expect(reindexer).to receive(:perform)
+ end
+
+ subject
+ end
+
+ it 'keeps track of actions and creates ReindexAction records' do
+ indexes.each do |index|
+ expect(Gitlab::Database::Reindexing::ReindexAction).to receive(:keep_track_of).with(index).and_yield
+ end
+
+ subject
+ end
+
+ context 'locking' do
+ it 'acquires a lock while reindexing' do
+ indexes.each do |index|
+ expect(lease).to receive(:try_obtain).ordered.and_return(uuid)
+ action = instance_double(Gitlab::Database::Reindexing::ConcurrentReindex)
+ expect(Gitlab::Database::Reindexing::ConcurrentReindex).to receive(:new).ordered.with(index).and_return(action)
+ expect(action).to receive(:perform).ordered
+ expect(Gitlab::ExclusiveLease).to receive(:cancel).ordered.with(lease_key, uuid)
+ end
+
+ subject
+ end
+
+ it 'does does not perform reindexing actions if lease is not granted' do
+ indexes.each do |index|
+ expect(lease).to receive(:try_obtain).ordered.and_return(false)
+ expect(Gitlab::Database::Reindexing::ConcurrentReindex).not_to receive(:new)
+ end
+
+ subject
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/database/reindexing/reindex_action_spec.rb b/spec/lib/gitlab/database/reindexing/reindex_action_spec.rb
new file mode 100644
index 00000000000..efb5b8463a1
--- /dev/null
+++ b/spec/lib/gitlab/database/reindexing/reindex_action_spec.rb
@@ -0,0 +1,86 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Database::Reindexing::ReindexAction, '.keep_track_of' do
+ let(:index) { double('index', identifier: 'public.something', ondisk_size_bytes: 10240, reload: nil) }
+ let(:size_after) { 512 }
+
+ it 'yields to the caller' do
+ expect { |b| described_class.keep_track_of(index, &b) }.to yield_control
+ end
+
+ def find_record
+ described_class.find_by(index_identifier: index.identifier)
+ end
+
+ it 'creates the record with a start time and updates its end time' do
+ freeze_time do
+ described_class.keep_track_of(index) do
+ expect(find_record.action_start).to be_within(1.second).of(Time.zone.now)
+
+ travel(10.seconds)
+ end
+
+ duration = find_record.action_end - find_record.action_start
+
+ expect(duration).to be_within(1.second).of(10.seconds)
+ end
+ end
+
+ it 'creates the record with its status set to :started and updates its state to :finished' do
+ described_class.keep_track_of(index) do
+ expect(find_record).to be_started
+ end
+
+ expect(find_record).to be_finished
+ end
+
+ it 'creates the record with the indexes start size and updates its end size' do
+ described_class.keep_track_of(index) do
+ expect(find_record.ondisk_size_bytes_start).to eq(index.ondisk_size_bytes)
+
+ expect(index).to receive(:reload).once
+ allow(index).to receive(:ondisk_size_bytes).and_return(size_after)
+ end
+
+ expect(find_record.ondisk_size_bytes_end).to eq(size_after)
+ end
+
+ context 'in case of errors' do
+ it 'sets the state to failed' do
+ expect do
+ described_class.keep_track_of(index) do
+ raise 'something went wrong'
+ end
+ end.to raise_error(/something went wrong/)
+
+ expect(find_record).to be_failed
+ end
+
+ it 'records the end time' do
+ freeze_time do
+ expect do
+ described_class.keep_track_of(index) do
+ raise 'something went wrong'
+ end
+ end.to raise_error(/something went wrong/)
+
+ expect(find_record.action_end).to be_within(1.second).of(Time.zone.now)
+ end
+ end
+
+ it 'records the resulting index size' do
+ expect(index).to receive(:reload).once
+ allow(index).to receive(:ondisk_size_bytes).and_return(size_after)
+
+ expect do
+ described_class.keep_track_of(index) do
+ raise 'something went wrong'
+ end
+ end.to raise_error(/something went wrong/)
+
+ expect(find_record.ondisk_size_bytes_end).to eq(size_after)
+ end
+ end
+end
diff --git a/spec/lib/gitlab/database/reindexing_spec.rb b/spec/lib/gitlab/database/reindexing_spec.rb
new file mode 100644
index 00000000000..86b3c029944
--- /dev/null
+++ b/spec/lib/gitlab/database/reindexing_spec.rb
@@ -0,0 +1,32 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Database::Reindexing do
+ include ExclusiveLeaseHelpers
+
+ describe '.perform' do
+ subject { described_class.perform(indexes) }
+
+ let(:coordinator) { instance_double(Gitlab::Database::Reindexing::Coordinator) }
+ let(:indexes) { double }
+
+ it 'delegates to Coordinator' do
+ expect(Gitlab::Database::Reindexing::Coordinator).to receive(:new).with(indexes).and_return(coordinator)
+ expect(coordinator).to receive(:perform)
+
+ subject
+ end
+ end
+
+ describe '.candidate_indexes' do
+ subject { described_class.candidate_indexes }
+
+ it 'retrieves regular indexes that are no left-overs from previous runs' do
+ result = double
+ expect(Gitlab::Database::PostgresIndex).to receive_message_chain('regular.not_match.not_match').with(no_args).with('^tmp_reindex_').with('^old_reindex_').and_return(result)
+
+ expect(subject).to eq(result)
+ end
+ end
+end
diff --git a/spec/lib/gitlab/database/similarity_score_spec.rb b/spec/lib/gitlab/database/similarity_score_spec.rb
index e36a4f610e1..cf75e5a72d9 100644
--- a/spec/lib/gitlab/database/similarity_score_spec.rb
+++ b/spec/lib/gitlab/database/similarity_score_spec.rb
@@ -90,4 +90,15 @@ RSpec.describe Gitlab::Database::SimilarityScore do
expect(subject).to eq(%w[different same gitlab-danger])
end
end
+
+ describe 'annotation' do
+ it 'annotates the generated SQL expression' do
+ expression = Gitlab::Database::SimilarityScore.build_expression(search: 'test', rules: [
+ { column: Arel.sql('path'), multiplier: 1 },
+ { column: Arel.sql('name'), multiplier: 0.8 }
+ ])
+
+ expect(Gitlab::Database::SimilarityScore).to be_order_by_similarity(expression)
+ end
+ end
end
diff --git a/spec/lib/gitlab/database/with_lock_retries_spec.rb b/spec/lib/gitlab/database/with_lock_retries_spec.rb
index 2cc6e175500..220ae705e71 100644
--- a/spec/lib/gitlab/database/with_lock_retries_spec.rb
+++ b/spec/lib/gitlab/database/with_lock_retries_spec.rb
@@ -104,9 +104,69 @@ RSpec.describe Gitlab::Database::WithLockRetries do
end
context 'after 3 iterations' do
- let(:retry_count) { 4 }
+ it_behaves_like 'retriable exclusive lock on `projects`' do
+ let(:retry_count) { 4 }
+ end
+
+ context 'setting the idle transaction timeout' do
+ context 'when there is no outer transaction: disable_ddl_transaction! is set in the migration' do
+ it 'does not disable the idle transaction timeout' do
+ allow(ActiveRecord::Base.connection).to receive(:transaction_open?).and_return(false)
+ allow(subject).to receive(:run_block_with_transaction).once.and_raise(ActiveRecord::LockWaitTimeout)
+ allow(subject).to receive(:run_block_with_transaction).once
+
+ expect(subject).not_to receive(:disable_idle_in_transaction_timeout)
+
+ subject.run {}
+ end
+ end
- it_behaves_like 'retriable exclusive lock on `projects`'
+ context 'when there is outer transaction: disable_ddl_transaction! is not set in the migration' do
+ it 'disables the idle transaction timeout so the code can sleep and retry' do
+ allow(ActiveRecord::Base.connection).to receive(:transaction_open?).and_return(true)
+
+ n = 0
+ allow(subject).to receive(:run_block_with_transaction).twice do
+ n += 1
+ raise(ActiveRecord::LockWaitTimeout) if n == 1
+ end
+
+ expect(subject).to receive(:disable_idle_in_transaction_timeout).once
+
+ subject.run {}
+ end
+ end
+ end
+ end
+
+ context 'after the retries are exhausted' do
+ let(:timing_configuration) do
+ [
+ [1.second, 1.second]
+ ]
+ end
+
+ context 'when there is no outer transaction: disable_ddl_transaction! is set in the migration' do
+ it 'does not disable the lock_timeout' do
+ allow(ActiveRecord::Base.connection).to receive(:transaction_open?).and_return(false)
+ allow(subject).to receive(:run_block_with_transaction).once.and_raise(ActiveRecord::LockWaitTimeout)
+
+ expect(subject).not_to receive(:disable_lock_timeout)
+
+ subject.run {}
+ end
+ end
+
+ context 'when there is outer transaction: disable_ddl_transaction! is not set in the migration' do
+ it 'disables the lock_timeout' do
+ allow(ActiveRecord::Base.connection).to receive(:transaction_open?).and_return(true)
+ allow(subject).to receive(:run_block_with_transaction).once.and_raise(ActiveRecord::LockWaitTimeout)
+
+ expect(subject).to receive(:disable_lock_timeout)
+
+ subject.run {}
+ end
+ end
end
context 'after the retries, without setting lock_timeout' do
diff --git a/spec/lib/gitlab/database_spec.rb b/spec/lib/gitlab/database_spec.rb
index 420aa0a8df6..3175040167b 100644
--- a/spec/lib/gitlab/database_spec.rb
+++ b/spec/lib/gitlab/database_spec.rb
@@ -39,6 +39,12 @@ RSpec.describe Gitlab::Database do
end
end
+ describe '.system_id' do
+ it 'returns the PostgreSQL system identifier' do
+ expect(described_class.system_id).to be_an_instance_of(Integer)
+ end
+ end
+
describe '.postgresql?' do
subject { described_class.postgresql? }
@@ -70,25 +76,6 @@ RSpec.describe Gitlab::Database do
end
end
- describe '.postgresql_9_or_less?' do
- it 'returns true when using postgresql 8.4' do
- allow(described_class).to receive(:version).and_return('8.4')
- expect(described_class.postgresql_9_or_less?).to eq(true)
- end
-
- it 'returns true when using PostgreSQL 9.6' do
- allow(described_class).to receive(:version).and_return('9.6')
-
- expect(described_class.postgresql_9_or_less?).to eq(true)
- end
-
- it 'returns false when using PostgreSQL 10 or newer' do
- allow(described_class).to receive(:version).and_return('10')
-
- expect(described_class.postgresql_9_or_less?).to eq(false)
- end
- end
-
describe '.postgresql_minimum_supported_version?' do
it 'returns false when using PostgreSQL 10' do
allow(described_class).to receive(:version).and_return('10')
@@ -150,68 +137,6 @@ RSpec.describe Gitlab::Database do
end
end
- describe '.pg_wal_lsn_diff' do
- it 'returns old name when using PostgreSQL 9.6' do
- allow(described_class).to receive(:version).and_return('9.6')
-
- expect(described_class.pg_wal_lsn_diff).to eq('pg_xlog_location_diff')
- end
-
- it 'returns new name when using PostgreSQL 10 or newer' do
- allow(described_class).to receive(:version).and_return('10')
-
- expect(described_class.pg_wal_lsn_diff).to eq('pg_wal_lsn_diff')
- end
- end
-
- describe '.pg_current_wal_insert_lsn' do
- it 'returns old name when using PostgreSQL 9.6' do
- allow(described_class).to receive(:version).and_return('9.6')
-
- expect(described_class.pg_current_wal_insert_lsn).to eq('pg_current_xlog_insert_location')
- end
-
- it 'returns new name when using PostgreSQL 10 or newer' do
- allow(described_class).to receive(:version).and_return('10')
-
- expect(described_class.pg_current_wal_insert_lsn).to eq('pg_current_wal_insert_lsn')
- end
- end
-
- describe '.pg_last_wal_receive_lsn' do
- it 'returns old name when using PostgreSQL 9.6' do
- allow(described_class).to receive(:version).and_return('9.6')
-
- expect(described_class.pg_last_wal_receive_lsn).to eq('pg_last_xlog_receive_location')
- end
-
- it 'returns new name when using PostgreSQL 10 or newer' do
- allow(described_class).to receive(:version).and_return('10')
-
- expect(described_class.pg_last_wal_receive_lsn).to eq('pg_last_wal_receive_lsn')
- end
- end
-
- describe '.pg_last_wal_replay_lsn' do
- it 'returns old name when using PostgreSQL 9.6' do
- allow(described_class).to receive(:version).and_return('9.6')
-
- expect(described_class.pg_last_wal_replay_lsn).to eq('pg_last_xlog_replay_location')
- end
-
- it 'returns new name when using PostgreSQL 10 or newer' do
- allow(described_class).to receive(:version).and_return('10')
-
- expect(described_class.pg_last_wal_replay_lsn).to eq('pg_last_wal_replay_lsn')
- end
- end
-
- describe '.pg_last_xact_replay_timestamp' do
- it 'returns pg_last_xact_replay_timestamp' do
- expect(described_class.pg_last_xact_replay_timestamp).to eq('pg_last_xact_replay_timestamp')
- end
- end
-
describe '.nulls_last_order' do
it { expect(described_class.nulls_last_order('column', 'ASC')).to eq 'column ASC NULLS LAST'}
it { expect(described_class.nulls_last_order('column', 'DESC')).to eq 'column DESC NULLS LAST'}
@@ -433,6 +358,20 @@ RSpec.describe Gitlab::Database do
end
end
+ describe '.get_write_location' do
+ it 'returns a string' do
+ connection = ActiveRecord::Base.connection
+
+ expect(described_class.get_write_location(connection)).to be_a(String)
+ end
+
+ it 'returns nil if there are no results' do
+ connection = double(select_all: [])
+
+ expect(described_class.get_write_location(connection)).to be_nil
+ end
+ end
+
describe '#true_value' do
it 'returns correct value' do
expect(described_class.true_value).to eq "'t'"
diff --git a/spec/lib/gitlab/diff/file_collection/merge_request_diff_batch_spec.rb b/spec/lib/gitlab/diff/file_collection/merge_request_diff_batch_spec.rb
index bd60c24859c..72a66b0451e 100644
--- a/spec/lib/gitlab/diff/file_collection/merge_request_diff_batch_spec.rb
+++ b/spec/lib/gitlab/diff/file_collection/merge_request_diff_batch_spec.rb
@@ -120,7 +120,7 @@ RSpec.describe Gitlab::Diff::FileCollection::MergeRequestDiffBatch do
described_class.new(merge_request.merge_request_diff,
batch_page,
batch_size,
- collection_default_args)
+ **collection_default_args)
end
end
diff --git a/spec/lib/gitlab/diff/highlight_cache_spec.rb b/spec/lib/gitlab/diff/highlight_cache_spec.rb
index 7e926f86096..f6810d7a966 100644
--- a/spec/lib/gitlab/diff/highlight_cache_spec.rb
+++ b/spec/lib/gitlab/diff/highlight_cache_spec.rb
@@ -43,7 +43,8 @@ RSpec.describe Gitlab::Diff::HighlightCache, :clean_gitlab_redis_cache do
describe '#decorate' do
# Manually creates a Diff::File object to avoid triggering the cache on
- # the FileCollection::MergeRequestDiff
+ # the FileCollection::MergeRequestDiff
+ #
let(:diff_file) do
diffs = merge_request.diffs
raw_diff = diffs.diffable.raw_diffs(diffs.diff_options.merge(paths: ['CHANGELOG'])).first
@@ -73,6 +74,37 @@ RSpec.describe Gitlab::Diff::HighlightCache, :clean_gitlab_redis_cache do
expect(rich_texts).to all(be_html_safe)
end
+
+ context "when diff_file is uncached due to default_max_patch_bytes change" do
+ before do
+ expect(cache).to receive(:read_file).at_least(:once).and_return([])
+
+ # Stub out the application's default and current patch size limits. We
+ # want them to be different, and the diff file to be sized between
+ # the 2 values.
+ #
+ diff_file_size_kb = (diff_file.diff.diff.bytesize * 10)
+
+ stub_const("#{diff_file.diff.class}::DEFAULT_MAX_PATCH_BYTES", diff_file_size_kb - 1 )
+ expect(diff_file.diff.class).to receive(:patch_safe_limit_bytes).and_return(diff_file_size_kb + 1)
+ expect(diff_file.diff.class)
+ .to receive(:patch_safe_limit_bytes)
+ .with(diff_file.diff.class::DEFAULT_MAX_PATCH_BYTES)
+ .and_call_original
+ end
+
+ it "manually writes highlighted lines to the cache" do
+ expect(cache).to receive(:write_to_redis_hash).and_call_original
+
+ cache.decorate(diff_file)
+ end
+
+ it "assigns highlighted diff lines to the DiffFile" do
+ expect(diff_file.highlighted_diff_lines.size).to be > 5
+
+ cache.decorate(diff_file)
+ end
+ end
end
shared_examples 'caches missing entries' do
diff --git a/spec/lib/gitlab/email/handler/create_note_handler_spec.rb b/spec/lib/gitlab/email/handler/create_note_handler_spec.rb
index 07b8070be30..ef448ee96a4 100644
--- a/spec/lib/gitlab/email/handler/create_note_handler_spec.rb
+++ b/spec/lib/gitlab/email/handler/create_note_handler_spec.rb
@@ -65,24 +65,15 @@ RSpec.describe Gitlab::Email::Handler::CreateNoteHandler do
end
end
- [true, false].each do |state_tracking_enabled|
- context "and current user can update noteable #{state_tracking_enabled ? 'enabled' : 'disabled'}" do
- before do
- stub_feature_flags(track_resource_state_change_events: state_tracking_enabled)
-
- project.add_developer(user)
- end
+ context "and current user can update noteable" do
+ before do
+ project.add_developer(user)
+ end
- it 'does not raise an error' do
- if state_tracking_enabled
- expect { receiver.execute }.to change { noteable.resource_state_events.count }.by(1)
- else
- # One system note is created for the 'close' event
- expect { receiver.execute }.to change { noteable.notes.count }.by(1)
- end
+ it 'does not raise an error' do
+ expect { receiver.execute }.to change { noteable.resource_state_events.count }.by(1)
- expect(noteable.reload).to be_closed
- end
+ expect(noteable.reload).to be_closed
end
end
end
diff --git a/spec/lib/gitlab/exclusive_lease_helpers_spec.rb b/spec/lib/gitlab/exclusive_lease_helpers_spec.rb
index 01e2fe8ce17..40669f06371 100644
--- a/spec/lib/gitlab/exclusive_lease_helpers_spec.rb
+++ b/spec/lib/gitlab/exclusive_lease_helpers_spec.rb
@@ -25,13 +25,17 @@ RSpec.describe Gitlab::ExclusiveLeaseHelpers, :clean_gitlab_redis_shared_state d
let!(:lease) { stub_exclusive_lease(unique_key, 'uuid') }
it 'calls the given block' do
- expect { |b| class_instance.in_lock(unique_key, &b) }.to yield_with_args(false)
+ expect { |b| class_instance.in_lock(unique_key, &b) }
+ .to yield_with_args(false, an_instance_of(described_class::SleepingLock))
end
it 'calls the given block continuously' do
- expect { |b| class_instance.in_lock(unique_key, &b) }.to yield_with_args(false)
- expect { |b| class_instance.in_lock(unique_key, &b) }.to yield_with_args(false)
- expect { |b| class_instance.in_lock(unique_key, &b) }.to yield_with_args(false)
+ expect { |b| class_instance.in_lock(unique_key, &b) }
+ .to yield_with_args(false, an_instance_of(described_class::SleepingLock))
+ expect { |b| class_instance.in_lock(unique_key, &b) }
+ .to yield_with_args(false, an_instance_of(described_class::SleepingLock))
+ expect { |b| class_instance.in_lock(unique_key, &b) }
+ .to yield_with_args(false, an_instance_of(described_class::SleepingLock))
end
it 'cancels the exclusive lease after the block' do
@@ -74,7 +78,8 @@ RSpec.describe Gitlab::ExclusiveLeaseHelpers, :clean_gitlab_redis_shared_state d
expect(lease).to receive(:try_obtain).exactly(3).times { nil }
expect(lease).to receive(:try_obtain).once { unique_key }
- expect { |b| class_instance.in_lock(unique_key, &b) }.to yield_with_args(true)
+ expect { |b| class_instance.in_lock(unique_key, &b) }
+ .to yield_with_args(true, an_instance_of(described_class::SleepingLock))
end
end
end
diff --git a/spec/lib/gitlab/experimentation_spec.rb b/spec/lib/gitlab/experimentation_spec.rb
index 9bc865f4d29..e93593d348f 100644
--- a/spec/lib/gitlab/experimentation_spec.rb
+++ b/spec/lib/gitlab/experimentation_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Experimentation do
+RSpec.describe Gitlab::Experimentation, :snowplow do
before do
stub_const('Gitlab::Experimentation::EXPERIMENTS', {
test_experiment: {
@@ -69,12 +69,26 @@ RSpec.describe Gitlab::Experimentation do
end
end
+ describe '#push_frontend_experiment' do
+ it 'pushes an experiment to the frontend' do
+ gon = instance_double('gon')
+ experiments = { experiments: { 'myExperiment' => true } }
+
+ stub_experiment_for_user(my_experiment: true)
+ allow(controller).to receive(:gon).and_return(gon)
+
+ expect(gon).to receive(:push).with(experiments, true)
+
+ controller.push_frontend_experiment(:my_experiment)
+ end
+ end
+
describe '#experiment_enabled?' do
subject { controller.experiment_enabled?(:test_experiment) }
context 'cookie is not present' do
- it 'calls Gitlab::Experimentation.enabled_for_user? with the name of the experiment and an experimentation_subject_index of nil' do
- expect(Gitlab::Experimentation).to receive(:enabled_for_user?).with(:test_experiment, nil)
+ it 'calls Gitlab::Experimentation.enabled_for_value? with the name of the experiment and an experimentation_subject_index of nil' do
+ expect(Gitlab::Experimentation).to receive(:enabled_for_value?).with(:test_experiment, nil)
controller.experiment_enabled?(:test_experiment)
end
end
@@ -85,22 +99,22 @@ RSpec.describe Gitlab::Experimentation do
get :index
end
- it 'calls Gitlab::Experimentation.enabled_for_user? with the name of the experiment and an experimentation_subject_index of the modulo 100 of the hex value of the uuid' do
+ it 'calls Gitlab::Experimentation.enabled_for_value? with the name of the experiment and an experimentation_subject_index of the modulo 100 of the hex value of the uuid' do
# 'abcd1234'.hex % 100 = 76
- expect(Gitlab::Experimentation).to receive(:enabled_for_user?).with(:test_experiment, 76)
+ expect(Gitlab::Experimentation).to receive(:enabled_for_value?).with(:test_experiment, 76)
controller.experiment_enabled?(:test_experiment)
end
end
it 'returns true when DNT: 0 is set in the request' do
- allow(Gitlab::Experimentation).to receive(:enabled_for_user?) { true }
+ allow(Gitlab::Experimentation).to receive(:enabled_for_value?) { true }
controller.request.headers['DNT'] = '0'
is_expected.to be_truthy
end
it 'returns false when DNT: 1 is set in the request' do
- allow(Gitlab::Experimentation).to receive(:enabled_for_user?) { true }
+ allow(Gitlab::Experimentation).to receive(:enabled_for_value?) { true }
controller.request.headers['DNT'] = '1'
is_expected.to be_falsy
@@ -127,13 +141,14 @@ RSpec.describe Gitlab::Experimentation do
end
it 'tracks the event with the right parameters' do
- expect(Gitlab::Tracking).to receive(:event).with(
- 'Team',
- 'start',
+ controller.track_experiment_event(:test_experiment, 'start', 1)
+
+ expect_snowplow_event(
+ category: 'Team',
+ action: 'start',
property: 'experimental_group',
- value: 'team_id'
+ value: 1
)
- controller.track_experiment_event(:test_experiment, 'start', 'team_id')
end
end
@@ -143,13 +158,43 @@ RSpec.describe Gitlab::Experimentation do
end
it 'tracks the event with the right parameters' do
- expect(Gitlab::Tracking).to receive(:event).with(
- 'Team',
- 'start',
+ controller.track_experiment_event(:test_experiment, 'start', 1)
+
+ expect_snowplow_event(
+ category: 'Team',
+ action: 'start',
+ property: 'control_group',
+ value: 1
+ )
+ end
+ end
+
+ context 'do not track is disabled' do
+ before do
+ request.headers['DNT'] = '0'
+ end
+
+ it 'does track the event' do
+ controller.track_experiment_event(:test_experiment, 'start', 1)
+
+ expect_snowplow_event(
+ category: 'Team',
+ action: 'start',
property: 'control_group',
- value: 'team_id'
+ value: 1
)
- controller.track_experiment_event(:test_experiment, 'start', 'team_id')
+ end
+ end
+
+ context 'do not track enabled' do
+ before do
+ request.headers['DNT'] = '1'
+ end
+
+ it 'does not track the event' do
+ controller.track_experiment_event(:test_experiment, 'start', 1)
+
+ expect_no_snowplow_event
end
end
end
@@ -160,8 +205,9 @@ RSpec.describe Gitlab::Experimentation do
end
it 'does not track the event' do
- expect(Gitlab::Tracking).not_to receive(:event)
controller.track_experiment_event(:test_experiment, 'start')
+
+ expect_no_snowplow_event
end
end
end
@@ -220,6 +266,36 @@ RSpec.describe Gitlab::Experimentation do
)
end
end
+
+ context 'do not track disabled' do
+ before do
+ request.headers['DNT'] = '0'
+ end
+
+ it 'pushes the right parameters to gon' do
+ controller.frontend_experimentation_tracking_data(:test_experiment, 'start')
+
+ expect(Gon.tracking_data).to eq(
+ {
+ category: 'Team',
+ action: 'start',
+ property: 'control_group'
+ }
+ )
+ end
+ end
+
+ context 'do not track enabled' do
+ before do
+ request.headers['DNT'] = '1'
+ end
+
+ it 'does not push data to gon' do
+ controller.frontend_experimentation_tracking_data(:test_experiment, 'start')
+
+ expect(Gon.method_defined?(:tracking_data)).to be_falsey
+ end
+ end
end
context 'when the experiment is disabled' do
@@ -294,6 +370,39 @@ RSpec.describe Gitlab::Experimentation do
controller.record_experiment_user(:test_experiment)
end
end
+
+ context 'do not track' do
+ before do
+ allow(controller).to receive(:current_user).and_return(user)
+ allow_next_instance_of(described_class) do |instance|
+ allow(instance).to receive(:experiment_enabled?).with(:test_experiment).and_return(false)
+ end
+ end
+
+ context 'is disabled' do
+ before do
+ request.headers['DNT'] = '0'
+ end
+
+ it 'calls add_user on the Experiment model' do
+ expect(::Experiment).to receive(:add_user).with(:test_experiment, :control, user)
+
+ controller.record_experiment_user(:test_experiment)
+ end
+ end
+
+ context 'is enabled' do
+ before do
+ request.headers['DNT'] = '1'
+ end
+
+ it 'does not call add_user on the Experiment model' do
+ expect(::Experiment).not_to receive(:add_user)
+
+ controller.record_experiment_user(:test_experiment)
+ end
+ end
+ end
end
describe '#experiment_tracking_category_and_group' do
@@ -336,8 +445,8 @@ RSpec.describe Gitlab::Experimentation do
end
end
- describe '.enabled_for_user?' do
- subject { described_class.enabled_for_user?(:test_experiment, experimentation_subject_index) }
+ describe '.enabled_for_value?' do
+ subject { described_class.enabled_for_value?(:test_experiment, experimentation_subject_index) }
let(:experimentation_subject_index) { 9 }
@@ -377,4 +486,32 @@ RSpec.describe Gitlab::Experimentation do
end
end
end
+
+ describe '.enabled_for_attribute?' do
+ subject { described_class.enabled_for_attribute?(:test_experiment, attribute) }
+
+ let(:attribute) { 'abcd' } # Digest::SHA1.hexdigest('abcd').hex % 100 = 7
+
+ context 'experiment is disabled' do
+ before do
+ allow(described_class).to receive(:enabled?).and_return(false)
+ end
+
+ it { is_expected.to be false }
+ end
+
+ context 'experiment is enabled' do
+ before do
+ allow(described_class).to receive(:enabled?).and_return(true)
+ end
+
+ it { is_expected.to be true }
+
+ context 'outside enabled ratio' do
+ let(:attribute) { 'abc' } # Digest::SHA1.hexdigest('abc').hex % 100 = 17
+
+ it { is_expected.to be false }
+ end
+ end
+ end
end
diff --git a/spec/lib/gitlab/git/branch_spec.rb b/spec/lib/gitlab/git/branch_spec.rb
index e1bcf4aeeb1..9271f635b14 100644
--- a/spec/lib/gitlab/git/branch_spec.rb
+++ b/spec/lib/gitlab/git/branch_spec.rb
@@ -85,9 +85,9 @@ RSpec.describe Gitlab::Git::Branch, :seed_helper do
}
end
- let(:stale_sha) { Timecop.freeze(Gitlab::Git::Branch::STALE_BRANCH_THRESHOLD.ago - 5.days) { create_commit } }
- let(:active_sha) { Timecop.freeze(Gitlab::Git::Branch::STALE_BRANCH_THRESHOLD.ago + 5.days) { create_commit } }
- let(:future_sha) { Timecop.freeze(100.days.since) { create_commit } }
+ let(:stale_sha) { travel_to(Gitlab::Git::Branch::STALE_BRANCH_THRESHOLD.ago - 5.days) { create_commit } }
+ let(:active_sha) { travel_to(Gitlab::Git::Branch::STALE_BRANCH_THRESHOLD.ago + 5.days) { create_commit } }
+ let(:future_sha) { travel_to(100.days.since) { create_commit } }
before do
repository.create_branch('stale-1', stale_sha)
diff --git a/spec/lib/gitlab/git/diff_collection_spec.rb b/spec/lib/gitlab/git/diff_collection_spec.rb
index b202015464f..1a3c332a21b 100644
--- a/spec/lib/gitlab/git/diff_collection_spec.rb
+++ b/spec/lib/gitlab/git/diff_collection_spec.rb
@@ -9,8 +9,11 @@ RSpec.describe Gitlab::Git::DiffCollection, :seed_helper do
MutatingConstantIterator.class_eval do
include Enumerable
+ attr_reader :size
+
def initialize(count, value)
@count = count
+ @size = count
@value = value
end
@@ -517,21 +520,39 @@ RSpec.describe Gitlab::Git::DiffCollection, :seed_helper do
.to yield_with_args(an_instance_of(Gitlab::Git::Diff))
end
- it 'prunes diffs that are quite big' do
- diff = nil
+ context 'single-file collections' do
+ it 'does not prune diffs' do
+ diff = nil
- subject.each do |d|
- diff = d
+ subject.each do |d|
+ diff = d
+ end
+
+ expect(diff.diff).not_to eq('')
end
+ end
+
+ context 'multi-file collections' do
+ let(:iterator) { [{ diff: 'b' }, { diff: 'a' * 20480 }]}
+
+ it 'prunes diffs that are quite big' do
+ diff = nil
- expect(diff.diff).to eq('')
+ subject.each do |d|
+ diff = d
+ end
+
+ expect(diff.diff).to eq('')
+ end
end
context 'when go over safe limits on files' do
let(:iterator) { [fake_diff(1, 1)] * 4 }
before do
- stub_const('Gitlab::Git::DiffCollection::DEFAULT_LIMITS', { max_files: 2, max_lines: max_lines })
+ allow(Gitlab::Git::DiffCollection)
+ .to receive(:default_limits)
+ .and_return({ max_files: 2, max_lines: max_lines })
end
it 'prunes diffs by default even little ones' do
@@ -556,7 +577,9 @@ RSpec.describe Gitlab::Git::DiffCollection, :seed_helper do
end
before do
- stub_const('Gitlab::Git::DiffCollection::DEFAULT_LIMITS', { max_files: max_files, max_lines: 80 })
+ allow(Gitlab::Git::DiffCollection)
+ .to receive(:default_limits)
+ .and_return({ max_files: max_files, max_lines: 80 })
end
it 'prunes diffs by default even little ones' do
@@ -581,7 +604,9 @@ RSpec.describe Gitlab::Git::DiffCollection, :seed_helper do
end
before do
- stub_const('Gitlab::Git::DiffCollection::DEFAULT_LIMITS', { max_files: max_files, max_lines: 80 })
+ allow(Gitlab::Git::DiffCollection)
+ .to receive(:default_limits)
+ .and_return({ max_files: max_files, max_lines: 80 })
end
it 'prunes diffs by default even little ones' do
@@ -665,8 +690,9 @@ RSpec.describe Gitlab::Git::DiffCollection, :seed_helper do
end
before do
- stub_const('Gitlab::Git::DiffCollection::DEFAULT_LIMITS',
- { max_files: max_files, max_lines: 80 })
+ allow(Gitlab::Git::DiffCollection)
+ .to receive(:default_limits)
+ .and_return({ max_files: max_files, max_lines: 80 })
end
it 'considers size of diffs before the offset for prunning' do
diff --git a/spec/lib/gitlab/git/diff_spec.rb b/spec/lib/gitlab/git/diff_spec.rb
index 117c519e98d..980a52bb61e 100644
--- a/spec/lib/gitlab/git/diff_spec.rb
+++ b/spec/lib/gitlab/git/diff_spec.rb
@@ -284,13 +284,21 @@ EOT
end
describe '#line_count' do
- it 'returns the correct number of lines' do
- diff = described_class.new(gitaly_diff)
+ let(:diff) { described_class.new(gitaly_diff) }
+ it 'returns the correct number of lines' do
expect(diff.line_count).to eq(7)
end
end
+ describe "#diff_bytesize" do
+ let(:diff) { described_class.new(gitaly_diff) }
+
+ it "returns the size of the diff in bytes" do
+ expect(diff.diff_bytesize).to eq(diff.diff.bytesize)
+ end
+ end
+
describe '#too_large?' do
it 'returns true for a diff that is too large' do
diff = described_class.new(diff: 'a' * 204800)
diff --git a/spec/lib/gitlab/git/object_pool_spec.rb b/spec/lib/gitlab/git/object_pool_spec.rb
index c8fbc674c73..e1873c6ddb5 100644
--- a/spec/lib/gitlab/git/object_pool_spec.rb
+++ b/spec/lib/gitlab/git/object_pool_spec.rb
@@ -19,7 +19,7 @@ RSpec.describe Gitlab::Git::ObjectPool do
describe '#create' do
before do
- subject.create
+ subject.create # rubocop:disable Rails/SaveBang
end
context "when the pool doesn't exist yet" do
@@ -31,7 +31,7 @@ RSpec.describe Gitlab::Git::ObjectPool do
context 'when the pool already exists' do
it 'raises an FailedPrecondition' do
expect do
- subject.create
+ subject.create # rubocop:disable Rails/SaveBang
end.to raise_error(GRPC::FailedPrecondition)
end
end
diff --git a/spec/lib/gitlab/git/remote_mirror_spec.rb b/spec/lib/gitlab/git/remote_mirror_spec.rb
index 423c4aa9620..92504b7aafe 100644
--- a/spec/lib/gitlab/git/remote_mirror_spec.rb
+++ b/spec/lib/gitlab/git/remote_mirror_spec.rb
@@ -16,7 +16,7 @@ RSpec.describe Gitlab::Git::RemoteMirror do
.to receive(:update_remote_mirror)
.with(ref_name, ['master'], ssh_key: 'KEY', known_hosts: 'KNOWN HOSTS', keep_divergent_refs: true)
- remote_mirror.update
+ remote_mirror.update # rubocop:disable Rails/SaveBang
end
it 'wraps gitaly errors' do
@@ -24,7 +24,7 @@ RSpec.describe Gitlab::Git::RemoteMirror do
.to receive(:update_remote_mirror)
.and_raise(StandardError)
- expect { remote_mirror.update }.to raise_error(StandardError)
+ expect { remote_mirror.update }.to raise_error(StandardError) # rubocop:disable Rails/SaveBang
end
end
end
diff --git a/spec/lib/gitlab/git/repository_spec.rb b/spec/lib/gitlab/git/repository_spec.rb
index 73eecd3401a..6dfa791f70b 100644
--- a/spec/lib/gitlab/git/repository_spec.rb
+++ b/spec/lib/gitlab/git/repository_spec.rb
@@ -120,7 +120,7 @@ RSpec.describe Gitlab::Git::Repository, :seed_helper do
let(:expected_extension) { 'tar.gz' }
let(:expected_filename) { "#{expected_prefix}.#{expected_extension}" }
- let(:expected_path) { File.join(storage_path, cache_key, expected_filename) }
+ let(:expected_path) { File.join(storage_path, cache_key, "@v2", expected_filename) }
let(:expected_prefix) { "gitlab-git-test-#{ref}-#{SeedRepo::LastCommit::ID}" }
subject(:metadata) { repository.archive_metadata(ref, storage_path, 'gitlab-git-test', format, append_sha: append_sha, path: path) }
@@ -133,12 +133,32 @@ RSpec.describe Gitlab::Git::Repository, :seed_helper do
expect(metadata['ArchivePrefix']).to eq(expected_prefix)
end
- it 'sets ArchivePath to the expected globally-unique path' do
- # This is really important from a security perspective. Think carefully
- # before changing it: https://gitlab.com/gitlab-org/gitlab-foss/issues/45689
- expect(expected_path).to include(File.join(repository.gl_repository, SeedRepo::LastCommit::ID))
+ context 'when :include_lfs_blobs_in_archive feature flag is disabled' do
+ let(:expected_path) { File.join(storage_path, cache_key, expected_filename) }
- expect(metadata['ArchivePath']).to eq(expected_path)
+ before do
+ stub_feature_flags(include_lfs_blobs_in_archive: false)
+ end
+
+ it 'sets ArchivePath to the expected globally-unique path' do
+ # This is really important from a security perspective. Think carefully
+ # before changing it: https://gitlab.com/gitlab-org/gitlab-foss/issues/45689
+ expect(expected_path).to include(File.join(repository.gl_repository, SeedRepo::LastCommit::ID))
+
+ expect(metadata['ArchivePath']).to eq(expected_path)
+ end
+ end
+
+ context 'when :include_lfs_blobs_in_archive feature flag is enabled' do
+ before do
+ stub_feature_flags(include_lfs_blobs_in_archive: true)
+ end
+
+ it 'sets ArchivePath to the expected globally-unique path' do
+ expect(expected_path).to include(File.join(repository.gl_repository, SeedRepo::LastCommit::ID))
+
+ expect(metadata['ArchivePath']).to eq(expected_path)
+ end
end
context 'path is set' do
@@ -1630,13 +1650,14 @@ RSpec.describe Gitlab::Git::Repository, :seed_helper do
let(:right_branch) { 'test-master' }
let(:first_parent_ref) { 'refs/heads/test-master' }
let(:target_ref) { 'refs/merge-requests/999/merge' }
+ let(:allow_conflicts) { false }
before do
repository.create_branch(right_branch, branch_head) unless repository.ref_exists?(first_parent_ref)
end
def merge_to_ref
- repository.merge_to_ref(user, left_sha, right_branch, target_ref, 'Merge message', first_parent_ref)
+ repository.merge_to_ref(user, left_sha, right_branch, target_ref, 'Merge message', first_parent_ref, allow_conflicts)
end
it 'generates a commit in the target_ref' do
@@ -2079,7 +2100,7 @@ RSpec.describe Gitlab::Git::Repository, :seed_helper do
let(:object_pool_rugged) { Rugged::Repository.new(object_pool_path) }
before do
- object_pool.create
+ object_pool.create # rubocop:disable Rails/SaveBang
end
it 'does not raise an error when disconnecting a non-linked repository' do
diff --git a/spec/lib/gitlab/git/rugged_impl/use_rugged_spec.rb b/spec/lib/gitlab/git/rugged_impl/use_rugged_spec.rb
index 4f6a3fb823e..16cea1dc1a3 100644
--- a/spec/lib/gitlab/git/rugged_impl/use_rugged_spec.rb
+++ b/spec/lib/gitlab/git/rugged_impl/use_rugged_spec.rb
@@ -7,7 +7,7 @@ require 'tempfile'
RSpec.describe Gitlab::Git::RuggedImpl::UseRugged, :seed_helper do
let(:project) { create(:project, :repository) }
let(:repository) { project.repository }
- let(:feature_flag_name) { 'feature-flag-name' }
+ let(:feature_flag_name) { wrapper.rugged_feature_keys.first }
let(:temp_gitaly_metadata_file) { create_temporary_gitaly_metadata_file }
before(:all) do
@@ -47,7 +47,7 @@ RSpec.describe Gitlab::Git::RuggedImpl::UseRugged, :seed_helper do
end
end
- context 'when feature flag is not persisted' do
+ context 'when feature flag is not persisted', stub_feature_flags: false do
context 'when running puma with multiple threads' do
before do
allow(subject).to receive(:running_puma_with_multiple_threads?).and_return(true)
diff --git a/spec/lib/gitlab/git/wiki_spec.rb b/spec/lib/gitlab/git/wiki_spec.rb
index a88097705f6..36bff42d937 100644
--- a/spec/lib/gitlab/git/wiki_spec.rb
+++ b/spec/lib/gitlab/git/wiki_spec.rb
@@ -51,6 +51,11 @@ RSpec.describe Gitlab::Git::Wiki do
expect(subject.page(title: 'page1', dir: '').url_path).to eq 'page1'
expect(subject.page(title: 'page1', dir: 'foo').url_path).to eq 'foo/page1'
end
+
+ it 'returns nil for invalid arguments' do
+ expect(subject.page(title: '')).to be_nil
+ expect(subject.page(title: 'foo', version: ':')).to be_nil
+ end
end
describe '#delete_page' do
diff --git a/spec/lib/gitlab/git_access_snippet_spec.rb b/spec/lib/gitlab/git_access_snippet_spec.rb
index 3b8b5fd82c6..8c481cdee08 100644
--- a/spec/lib/gitlab/git_access_snippet_spec.rb
+++ b/spec/lib/gitlab/git_access_snippet_spec.rb
@@ -232,29 +232,6 @@ RSpec.describe Gitlab::GitAccessSnippet do
end
end
- context 'when geo is enabled', if: Gitlab.ee? do
- let(:user) { snippet.author }
- let!(:primary_node) { FactoryBot.create(:geo_node, :primary) }
-
- before do
- allow(::Gitlab::Database).to receive(:read_only?).and_return(true)
- allow(::Gitlab::Geo).to receive(:secondary_with_primary?).and_return(true)
- end
-
- # Without override, push access would return Gitlab::GitAccessResult::CustomAction
- it 'skips geo for snippet' do
- expect { push_access_check }.to raise_forbidden(/You can't push code to a read-only GitLab instance/)
- end
-
- context 'when user is migration bot' do
- let(:user) { migration_bot }
-
- it 'skips geo for snippet' do
- expect { push_access_check }.to raise_forbidden(/You can't push code to a read-only GitLab instance/)
- end
- end
- end
-
context 'when changes are specific' do
let(:changes) { "2d1db523e11e777e49377cfb22d368deec3f0793 ddd0f15ae83993f5cb66a927a28673882e99100b master" }
let(:user) { snippet.author }
@@ -283,7 +260,7 @@ RSpec.describe Gitlab::GitAccessSnippet do
service = double
expect(service).to receive(:validate!).and_return(nil)
- expect(Snippet).to receive(:max_file_limit).with(user).and_return(5)
+ expect(Snippet).to receive(:max_file_limit).and_return(5)
expect(Gitlab::Checks::PushFileCountCheck).to receive(:new).with(anything, hash_including(limit: 5)).and_return(service)
push_access_check
diff --git a/spec/lib/gitlab/git_access_spec.rb b/spec/lib/gitlab/git_access_spec.rb
index 85567ab2e55..21607edbc32 100644
--- a/spec/lib/gitlab/git_access_spec.rb
+++ b/spec/lib/gitlab/git_access_spec.rb
@@ -420,6 +420,13 @@ RSpec.describe Gitlab::GitAccess do
expect { pull_access_check }.to raise_forbidden('Your account has been blocked.')
end
+ it 'disallows users that are blocked pending approval to pull' do
+ project.add_maintainer(user)
+ user.block_pending_approval
+
+ expect { pull_access_check }.to raise_forbidden('Your account is pending approval from your administrator and hence blocked.')
+ end
+
it 'disallows deactivated users to pull' do
project.add_maintainer(user)
user.deactivate!
@@ -428,14 +435,12 @@ RSpec.describe Gitlab::GitAccess do
end
context 'when the project repository does not exist' do
- it 'returns not found' do
+ before do
project.add_guest(user)
- repo = project.repository
- Gitlab::GitalyClient::StorageSettings.allow_disk_access { FileUtils.rm_rf(repo.path) }
-
- # Sanity check for rm_rf
- expect(repo.exists?).to eq(false)
+ allow(project.repository).to receive(:exists?).and_return(false)
+ end
+ it 'returns not found' do
expect { pull_access_check }.to raise_error(Gitlab::GitAccess::NotFoundError, 'A repository for this project does not exist yet.')
end
end
@@ -917,6 +922,12 @@ RSpec.describe Gitlab::GitAccess do
project.add_developer(user)
end
+ it 'disallows users that are blocked pending approval to push' do
+ user.block_pending_approval
+
+ expect { push_access_check }.to raise_forbidden('Your account is pending approval from your administrator and hence blocked.')
+ end
+
it 'does not allow deactivated users to push' do
user.deactivate!
diff --git a/spec/lib/gitlab/git_access_wiki_spec.rb b/spec/lib/gitlab/git_access_wiki_spec.rb
index 688089f4862..b78d99269d3 100644
--- a/spec/lib/gitlab/git_access_wiki_spec.rb
+++ b/spec/lib/gitlab/git_access_wiki_spec.rb
@@ -3,17 +3,17 @@
require 'spec_helper'
RSpec.describe Gitlab::GitAccessWiki do
- let(:access) { described_class.new(user, project, 'web', authentication_abilities: authentication_abilities, redirected_path: redirected_path) }
- let_it_be(:project) { create(:project, :wiki_repo) }
let_it_be(:user) { create(:user) }
+ let_it_be(:project) { create(:project, :wiki_repo) }
+ let_it_be(:wiki) { create(:project_wiki, project: project) }
let(:changes) { ['6f6d7e7ed 570e7b2ab refs/heads/master'] }
+ let(:authentication_abilities) { %i[read_project download_code push_code] }
let(:redirected_path) { nil }
- let(:authentication_abilities) do
- [
- :read_project,
- :download_code,
- :push_code
- ]
+
+ let(:access) do
+ described_class.new(user, wiki, 'web',
+ authentication_abilities: authentication_abilities,
+ redirected_path: redirected_path)
end
describe '#push_access_check' do
@@ -64,7 +64,7 @@ RSpec.describe Gitlab::GitAccessWiki do
context 'when the repository does not exist' do
before do
- allow(project.wiki).to receive(:repository).and_return(double('Repository', exists?: false))
+ allow(wiki.repository).to receive(:exists?).and_return(false)
end
it_behaves_like 'not-found git access' do
diff --git a/spec/lib/gitlab/gitaly_client/commit_service_spec.rb b/spec/lib/gitlab/gitaly_client/commit_service_spec.rb
index 9581b017839..f977fe1638f 100644
--- a/spec/lib/gitlab/gitaly_client/commit_service_spec.rb
+++ b/spec/lib/gitlab/gitaly_client/commit_service_spec.rb
@@ -13,6 +13,10 @@ RSpec.describe Gitlab::GitalyClient::CommitService do
let(:client) { described_class.new(repository) }
describe '#diff_from_parent' do
+ before do
+ stub_feature_flags(increased_diff_limits: false)
+ end
+
context 'when a commit has a parent' do
it 'sends an RPC request with the parent ID as left commit' do
request = Gitaly::CommitDiffRequest.new(
diff --git a/spec/lib/gitlab/gitaly_client/operation_service_spec.rb b/spec/lib/gitlab/gitaly_client/operation_service_spec.rb
index b974f456914..ce01566b870 100644
--- a/spec/lib/gitlab/gitaly_client/operation_service_spec.rb
+++ b/spec/lib/gitlab/gitaly_client/operation_service_spec.rb
@@ -88,9 +88,10 @@ RSpec.describe Gitlab::GitalyClient::OperationService do
let(:source_sha) { 'cfe32cf61b73a0d5e9f13e774abde7ff789b1660' }
let(:ref) { 'refs/merge-requests/x/merge' }
let(:message) { 'validación' }
+ let(:allow_conflicts) { false }
let(:response) { Gitaly::UserMergeToRefResponse.new(commit_id: 'new-commit-id') }
- subject { client.user_merge_to_ref(user, source_sha, nil, ref, message, first_parent_ref) }
+ subject { client.user_merge_to_ref(user, source_sha, nil, ref, message, first_parent_ref, allow_conflicts) }
it 'sends a user_merge_to_ref message' do
expect_any_instance_of(Gitaly::OperationService::Stub)
diff --git a/spec/lib/gitlab/gitpod_spec.rb b/spec/lib/gitlab/gitpod_spec.rb
index f4dda42aeb4..717e396f942 100644
--- a/spec/lib/gitlab/gitpod_spec.rb
+++ b/spec/lib/gitlab/gitpod_spec.rb
@@ -4,30 +4,29 @@ require 'spec_helper'
RSpec.describe Gitlab::Gitpod do
let_it_be(:user) { create(:user) }
- let(:feature_scope) { true }
before do
stub_feature_flags(gitpod: feature_scope)
end
- describe '.feature_conditional?' do
- subject { described_class.feature_conditional? }
-
- context 'when feature is enabled globally' do
- it { is_expected.to be_falsey }
- end
+ describe '.feature_available?' do
+ subject { described_class.feature_available? }
- context 'when feature is enabled only to a resource' do
- let(:feature_scope) { user }
+ context 'when feature has not been set' do
+ let(:feature_scope) { nil }
it { is_expected.to be_truthy }
end
- end
- describe '.feature_available?' do
- subject { described_class.feature_available? }
+ context 'when feature is disabled' do
+ let(:feature_scope) { false }
+
+ it { is_expected.to be_falsey }
+ end
context 'when feature is enabled globally' do
+ let(:feature_scope) { true }
+
it { is_expected.to be_truthy }
end
@@ -43,7 +42,15 @@ RSpec.describe Gitlab::Gitpod do
subject { described_class.feature_enabled?(current_user) }
+ context 'when feature has not been set' do
+ let(:feature_scope) { nil }
+
+ it { is_expected.to be_truthy }
+ end
+
context 'when feature is enabled globally' do
+ let(:feature_scope) { true }
+
it { is_expected.to be_truthy }
end
diff --git a/spec/lib/gitlab/gl_repository/identifier_spec.rb b/spec/lib/gitlab/gl_repository/identifier_spec.rb
index e95aaaa6690..e0622e30e7a 100644
--- a/spec/lib/gitlab/gl_repository/identifier_spec.rb
+++ b/spec/lib/gitlab/gl_repository/identifier_spec.rb
@@ -35,14 +35,14 @@ RSpec.describe Gitlab::GlRepository::Identifier do
it_behaves_like 'parsing gl_repository identifier' do
let(:record_id) { project.id }
let(:identifier) { "wiki-#{record_id}" }
- let(:expected_container) { project }
+ let(:expected_container) { project.wiki }
let(:expected_type) { Gitlab::GlRepository::WIKI }
end
it_behaves_like 'parsing gl_repository identifier' do
let(:record_id) { project.id }
let(:identifier) { "project-#{record_id}-wiki" }
- let(:expected_container) { project }
+ let(:expected_container) { project.wiki }
let(:expected_type) { Gitlab::GlRepository::WIKI }
end
end
@@ -87,7 +87,8 @@ RSpec.describe Gitlab::GlRepository::Identifier do
'project-wibble-wiki',
'wiki-1-project',
'snippet',
- 'project-1-wiki-bar'
+ 'project-1-wiki-bar',
+ 'project-1-project'
]
end
@@ -96,10 +97,5 @@ RSpec.describe Gitlab::GlRepository::Identifier do
expect { described_class.parse(identifier) }.to raise_error(described_class::InvalidIdentifier)
end
end
-
- it 'raises InvalidIdentifier on project-1-project' do
- pending 'https://gitlab.com/gitlab-org/gitlab/-/issues/219192'
- expect { described_class.parse('project-1-project') }.to raise_error(described_class::InvalidIdentifier)
- end
end
end
diff --git a/spec/lib/gitlab/gl_repository/repo_type_spec.rb b/spec/lib/gitlab/gl_repository/repo_type_spec.rb
index 3fa636a1cf0..629e6c96858 100644
--- a/spec/lib/gitlab/gl_repository/repo_type_spec.rb
+++ b/spec/lib/gitlab/gl_repository/repo_type_spec.rb
@@ -41,12 +41,14 @@ RSpec.describe Gitlab::GlRepository::RepoType do
end
describe Gitlab::GlRepository::WIKI do
+ let(:wiki) { project.wiki }
+
it_behaves_like 'a repo type' do
- let(:expected_id) { project.id }
+ let(:expected_id) { wiki.project.id }
let(:expected_identifier) { "wiki-#{expected_id}" }
let(:expected_suffix) { '.wiki' }
- let(:expected_container) { project }
- let(:expected_repository) { ::Repository.new(project.wiki.full_path, project, shard: project.wiki.repository_storage, disk_path: project.wiki.disk_path, repo_type: Gitlab::GlRepository::WIKI) }
+ let(:expected_container) { wiki }
+ let(:expected_repository) { ::Repository.new(wiki.full_path, wiki, shard: wiki.repository_storage, disk_path: wiki.disk_path, repo_type: Gitlab::GlRepository::WIKI) }
end
it 'knows its type' do
diff --git a/spec/lib/gitlab/gl_repository_spec.rb b/spec/lib/gitlab/gl_repository_spec.rb
index 3733d545155..05914f92c01 100644
--- a/spec/lib/gitlab/gl_repository_spec.rb
+++ b/spec/lib/gitlab/gl_repository_spec.rb
@@ -12,7 +12,7 @@ RSpec.describe ::Gitlab::GlRepository do
end
it 'parses a project wiki gl_repository' do
- expect(described_class.parse("wiki-#{project.id}")).to eq([project, project, Gitlab::GlRepository::WIKI])
+ expect(described_class.parse("wiki-#{project.id}")).to eq([project.wiki, project, Gitlab::GlRepository::WIKI])
end
it 'parses a snippet gl_repository' do
diff --git a/spec/lib/gitlab/gon_helper_spec.rb b/spec/lib/gitlab/gon_helper_spec.rb
index 95db6b2b4e0..3d3f381b6d2 100644
--- a/spec/lib/gitlab/gon_helper_spec.rb
+++ b/spec/lib/gitlab/gon_helper_spec.rb
@@ -10,6 +10,10 @@ RSpec.describe Gitlab::GonHelper do
end
describe '#push_frontend_feature_flag' do
+ before do
+ skip_feature_flags_yaml_validation
+ end
+
it 'pushes a feature flag to the frontend' do
gon = instance_double('gon')
thing = stub_feature_flag_gate('thing')
diff --git a/spec/lib/gitlab/grape_logging/loggers/queue_duration_logger_spec.rb b/spec/lib/gitlab/grape_logging/loggers/queue_duration_logger_spec.rb
index e68c1446502..9538c4bae2b 100644
--- a/spec/lib/gitlab/grape_logging/loggers/queue_duration_logger_spec.rb
+++ b/spec/lib/gitlab/grape_logging/loggers/queue_duration_logger_spec.rb
@@ -26,7 +26,7 @@ RSpec.describe Gitlab::GrapeLogging::Loggers::QueueDurationLogger do
end
it 'returns the correct duration in seconds' do
- Timecop.freeze(start_time) do
+ travel_to(start_time) do
subject.before
expect(subject.parameters(mock_request, nil)).to eq( { 'queue_duration_s': 1.hour.to_f })
diff --git a/spec/lib/gitlab/graphql/authorize/authorize_field_service_spec.rb b/spec/lib/gitlab/graphql/authorize/authorize_field_service_spec.rb
index efe6c27c463..7576523ce52 100644
--- a/spec/lib/gitlab/graphql/authorize/authorize_field_service_spec.rb
+++ b/spec/lib/gitlab/graphql/authorize/authorize_field_service_spec.rb
@@ -19,24 +19,29 @@ RSpec.describe Gitlab::Graphql::Authorize::AuthorizeFieldService do
options.reverse_merge!(null: true)
field :test_field, field_type,
authorize: field_authorizations,
- resolve: -> (_, _, _) { resolved_value },
**options
+
+ define_method :test_field do
+ resolved_value
+ end
end
end
- let(:current_user) { double(:current_user) }
-
subject(:service) { described_class.new(field) }
describe '#authorized_resolve' do
- let(:presented_object) { double('presented object') }
- let(:presented_type) { double('parent type', object: presented_object) }
- let(:query_type) { GraphQL::ObjectType.new }
- let(:schema) { GraphQL::Schema.define(query: query_type, mutation: nil)}
- let(:query_context) { OpenStruct.new(schema: schema) }
- let(:context) { GraphQL::Query::Context.new(query: OpenStruct.new(schema: schema, context: query_context), values: { current_user: current_user }, object: nil) }
+ let_it_be(:current_user) { build(:user) }
+ let_it_be(:presented_object) { 'presented object' }
+ let_it_be(:query_type) { GraphQL::ObjectType.new }
+ let_it_be(:schema) { GraphQL::Schema.define(query: query_type, mutation: nil)}
+ let_it_be(:query) { GraphQL::Query.new(schema, document: nil, context: {}, variables: {}) }
+ let_it_be(:context) { GraphQL::Query::Context.new(query: query, values: { current_user: current_user }, object: nil) }
+
+ let(:type_class) { type_with_field(custom_type, :read_field, presented_object) }
+ let(:type_instance) { type_class.authorized_new(presented_object, context) }
+ let(:field) { type_class.fields['testField'].to_graphql }
- subject(:resolved) { service.authorized_resolve.call(presented_type, {}, context) }
+ subject(:resolved) { service.authorized_resolve.call(type_instance, {}, context) }
context 'scalar types' do
shared_examples 'checking permissions on the presented object' do
@@ -48,7 +53,7 @@ RSpec.describe Gitlab::Graphql::Authorize::AuthorizeFieldService do
expect(resolved).to eq('Resolved value')
end
- it "returns nil if the value wasn't authorized" do
+ it 'returns nil if the value was not authorized' do
allow(Ability).to receive(:allowed?).and_return false
expect(resolved).to be_nil
@@ -56,28 +61,28 @@ RSpec.describe Gitlab::Graphql::Authorize::AuthorizeFieldService do
end
context 'when the field is a built-in scalar type' do
- let(:field) { type_with_field(GraphQL::STRING_TYPE, :read_field).fields['testField'].to_graphql }
+ let(:type_class) { type_with_field(GraphQL::STRING_TYPE, :read_field) }
let(:expected_permissions) { [:read_field] }
it_behaves_like 'checking permissions on the presented object'
end
context 'when the field is a list of scalar types' do
- let(:field) { type_with_field([GraphQL::STRING_TYPE], :read_field).fields['testField'].to_graphql }
+ let(:type_class) { type_with_field([GraphQL::STRING_TYPE], :read_field) }
let(:expected_permissions) { [:read_field] }
it_behaves_like 'checking permissions on the presented object'
end
context 'when the field is sub-classed scalar type' do
- let(:field) { type_with_field(Types::TimeType, :read_field).fields['testField'].to_graphql }
+ let(:type_class) { type_with_field(Types::TimeType, :read_field) }
let(:expected_permissions) { [:read_field] }
it_behaves_like 'checking permissions on the presented object'
end
context 'when the field is a list of sub-classed scalar types' do
- let(:field) { type_with_field([Types::TimeType], :read_field).fields['testField'].to_graphql }
+ let(:type_class) { type_with_field([Types::TimeType], :read_field) }
let(:expected_permissions) { [:read_field] }
it_behaves_like 'checking permissions on the presented object'
@@ -86,7 +91,7 @@ RSpec.describe Gitlab::Graphql::Authorize::AuthorizeFieldService do
context 'when the field is a connection' do
context 'when it resolves to nil' do
- let(:field) { type_with_field(Types::QueryType.connection_type, :read_field, nil).fields['testField'].to_graphql }
+ let(:type_class) { type_with_field(Types::QueryType.connection_type, :read_field, nil) }
it 'does not fail when authorizing' do
expect(resolved).to be_nil
@@ -97,7 +102,11 @@ RSpec.describe Gitlab::Graphql::Authorize::AuthorizeFieldService do
context 'when the field is a specific type' do
let(:custom_type) { type(:read_type) }
let(:object_in_field) { double('presented in field') }
- let(:field) { type_with_field(custom_type, :read_field, object_in_field).fields['testField'].to_graphql }
+
+ let(:type_class) { type_with_field(custom_type, :read_field, object_in_field) }
+ let(:type_instance) { type_class.authorized_new(object_in_field, context) }
+
+ subject(:resolved) { service.authorized_resolve.call(type_instance, {}, context) }
it 'checks both field & type permissions' do
spy_ability_check_for(:read_field, object_in_field, passed: true)
@@ -114,7 +123,7 @@ RSpec.describe Gitlab::Graphql::Authorize::AuthorizeFieldService do
end
context 'when the field is not nullable' do
- let(:field) { type_with_field(custom_type, [], object_in_field, null: false).fields['testField'].to_graphql }
+ let(:type_class) { type_with_field(custom_type, :read_field, object_in_field, null: false) }
it 'returns nil when viewing is not allowed' do
spy_ability_check_for(:read_type, object_in_field, passed: false)
@@ -127,7 +136,9 @@ RSpec.describe Gitlab::Graphql::Authorize::AuthorizeFieldService do
let(:object_1) { double('presented in field 1') }
let(:object_2) { double('presented in field 2') }
let(:presented_types) { [double(object: object_1), double(object: object_2)] }
- let(:field) { type_with_field([custom_type], :read_field, presented_types).fields['testField'].to_graphql }
+
+ let(:type_class) { type_with_field([custom_type], :read_field, presented_types) }
+ let(:type_instance) { type_class.authorized_new(presented_types, context) }
it 'checks all permissions' do
allow(Ability).to receive(:allowed?) { true }
diff --git a/spec/lib/gitlab/graphql/markdown_field/resolver_spec.rb b/spec/lib/gitlab/graphql/markdown_field/resolver_spec.rb
deleted file mode 100644
index af604e1c7d5..00000000000
--- a/spec/lib/gitlab/graphql/markdown_field/resolver_spec.rb
+++ /dev/null
@@ -1,33 +0,0 @@
-# frozen_string_literal: true
-require 'spec_helper'
-
-RSpec.describe Gitlab::Graphql::MarkdownField::Resolver do
- include Gitlab::Routing
- let(:resolver) { described_class.new(:note) }
-
- describe '#proc' do
- let(:project) { create(:project, :public) }
- let(:issue) { create(:issue, project: project) }
- let(:note) do
- create(:note,
- note: "Referencing #{issue.to_reference(full: true)}")
- end
-
- it 'renders markdown correctly' do
- expect(resolver.proc.call(note, {}, {})).to include(issue_path(issue))
- end
-
- context 'when the issue is not publicly accessible' do
- let(:project) { create(:project, :private) }
-
- it 'hides the references from users that are not allowed to see the reference' do
- expect(resolver.proc.call(note, {}, {})).not_to include(issue_path(issue))
- end
-
- it 'shows the reference to users that are allowed to see it' do
- expect(resolver.proc.call(note, {}, { current_user: project.owner }))
- .to include(issue_path(issue))
- end
- end
- end
-end
diff --git a/spec/lib/gitlab/graphql/markdown_field_spec.rb b/spec/lib/gitlab/graphql/markdown_field_spec.rb
index e3da925376e..82090f992eb 100644
--- a/spec/lib/gitlab/graphql/markdown_field_spec.rb
+++ b/spec/lib/gitlab/graphql/markdown_field_spec.rb
@@ -2,6 +2,8 @@
require 'spec_helper'
RSpec.describe Gitlab::Graphql::MarkdownField do
+ include Gitlab::Routing
+
describe '.markdown_field' do
it 'creates the field with some default attributes' do
field = class_with_markdown_field(:test_html, null: true, method: :hello).fields['testHtml']
@@ -13,7 +15,7 @@ RSpec.describe Gitlab::Graphql::MarkdownField do
end
context 'developer warnings' do
- let(:expected_error) { /Only `method` is allowed to specify the markdown field/ }
+ let_it_be(:expected_error) { /Only `method` is allowed to specify the markdown field/ }
it 'raises when passing a resolver' do
expect { class_with_markdown_field(:test_html, null: true, resolver: 'not really') }
@@ -27,30 +29,61 @@ RSpec.describe Gitlab::Graphql::MarkdownField do
end
context 'resolving markdown' do
- let(:note) { build(:note, note: '# Markdown!') }
- let(:thing_with_markdown) { double('markdown thing', object: note) }
- let(:expected_markdown) { '<h1 data-sourcepos="1:1-1:11" dir="auto">Markdown!</h1>' }
- let(:query_type) { GraphQL::ObjectType.new }
- let(:schema) { GraphQL::Schema.define(query: query_type, mutation: nil)}
- let(:context) { GraphQL::Query::Context.new(query: OpenStruct.new(schema: schema), values: nil, object: nil) }
+ let_it_be(:note) { build(:note, note: '# Markdown!') }
+ let_it_be(:expected_markdown) { '<h1 data-sourcepos="1:1-1:11" dir="auto">Markdown!</h1>' }
+ let_it_be(:query_type) { GraphQL::ObjectType.new }
+ let_it_be(:schema) { GraphQL::Schema.define(query: query_type, mutation: nil)}
+ let_it_be(:query) { GraphQL::Query.new(schema, document: nil, context: {}, variables: {}) }
+ let_it_be(:context) { GraphQL::Query::Context.new(query: query, values: {}, object: nil) }
+
+ let(:type_class) { class_with_markdown_field(:note_html, null: false) }
+ let(:type_instance) { type_class.authorized_new(note, context) }
+ let(:field) { type_class.fields['noteHtml'] }
it 'renders markdown from the same property as the field name without the `_html` suffix' do
- field = class_with_markdown_field(:note_html, null: false).fields['noteHtml']
+ expect(field.to_graphql.resolve(type_instance, {}, context)).to eq(expected_markdown)
+ end
+
+ context 'when a `method` argument is passed' do
+ let(:type_class) { class_with_markdown_field(:test_html, null: false, method: :note) }
+ let(:field) { type_class.fields['testHtml'] }
- expect(field.to_graphql.resolve(thing_with_markdown, {}, context)).to eq(expected_markdown)
+ it 'renders markdown from a specific property' do
+ expect(field.to_graphql.resolve(type_instance, {}, context)).to eq(expected_markdown)
+ end
end
- it 'renders markdown from a specific property when a `method` argument is passed' do
- field = class_with_markdown_field(:test_html, null: false, method: :note).fields['testHtml']
+ describe 'basic verification that references work' do
+ let_it_be(:project) { create(:project, :public) }
+ let(:issue) { create(:issue, project: project) }
+ let(:note) { build(:note, note: "Referencing #{issue.to_reference(full: true)}") }
+
+ it 'renders markdown correctly' do
+ expect(field.to_graphql.resolve(type_instance, {}, context)).to include(issue_path(issue))
+ end
+
+ context 'when the issue is not publicly accessible' do
+ let_it_be(:project) { create(:project, :private) }
+
+ it 'hides the references from users that are not allowed to see the reference' do
+ expect(field.to_graphql.resolve(type_instance, {}, context)).not_to include(issue_path(issue))
+ end
+
+ it 'shows the reference to users that are allowed to see it' do
+ context = GraphQL::Query::Context.new(query: query, values: { current_user: project.owner }, object: nil)
+ type_instance = type_class.authorized_new(note, context)
- expect(field.to_graphql.resolve(thing_with_markdown, {}, context)).to eq(expected_markdown)
+ expect(field.to_graphql.resolve(type_instance, {}, context)).to include(issue_path(issue))
+ end
+ end
end
end
end
def class_with_markdown_field(name, **args)
- Class.new(GraphQL::Schema::Object) do
+ Class.new(Types::BaseObject) do
prepend Gitlab::Graphql::MarkdownField
+ graphql_name 'MarkdownFieldTest'
markdown_field name, **args
end
diff --git a/spec/lib/gitlab/graphql/pagination/keyset/last_items_spec.rb b/spec/lib/gitlab/graphql/pagination/keyset/last_items_spec.rb
new file mode 100644
index 00000000000..b45bb8b79d9
--- /dev/null
+++ b/spec/lib/gitlab/graphql/pagination/keyset/last_items_spec.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Graphql::Pagination::Keyset::LastItems do
+ let_it_be(:merge_request) { create(:merge_request) }
+ let(:scope) { MergeRequest.order_merged_at_asc.with_order_id_desc }
+
+ subject { described_class.take_items(*args) }
+
+ context 'when the `count` parameter is nil' do
+ let(:args) { [scope, nil] }
+
+ it 'returns a single record' do
+ expect(subject).to eq(merge_request)
+ end
+ end
+
+ context 'when the `count` parameter is given' do
+ let(:args) { [scope, 1] }
+
+ it 'returns an array' do
+ expect(subject).to eq([merge_request])
+ end
+ end
+end
diff --git a/spec/lib/gitlab/graphql/pagination/keyset/order_info_spec.rb b/spec/lib/gitlab/graphql/pagination/keyset/order_info_spec.rb
index 444c10074a0..eb28e6c8c0a 100644
--- a/spec/lib/gitlab/graphql/pagination/keyset/order_info_spec.rb
+++ b/spec/lib/gitlab/graphql/pagination/keyset/order_info_spec.rb
@@ -63,6 +63,29 @@ RSpec.describe Gitlab::Graphql::Pagination::Keyset::OrderInfo do
expect(order_list.first.sort_direction).to eq :desc
end
end
+
+ context 'when ordering by CASE', :aggregate_failuers do
+ let(:relation) { Project.order(Arel::Nodes::Case.new(Project.arel_table[:pending_delete]).when(true).then(100).else(1000).asc) }
+
+ it 'assigns the right attribute name, named function, and direction' do
+ expect(order_list.count).to eq 1
+ expect(order_list.first.attribute_name).to eq 'case_order_value'
+ expect(order_list.first.named_function).to be_kind_of(Arel::Nodes::Case)
+ expect(order_list.first.sort_direction).to eq :asc
+ end
+ end
+
+ context 'when ordering by ARRAY_POSITION', :aggregate_failuers do
+ let(:array_position) { Arel::Nodes::NamedFunction.new('ARRAY_POSITION', [Arel.sql("ARRAY[1,0]::smallint[]"), Project.arel_table[:auto_cancel_pending_pipelines]]) }
+ let(:relation) { Project.order(array_position.asc) }
+
+ it 'assigns the right attribute name, named function, and direction' do
+ expect(order_list.count).to eq 1
+ expect(order_list.first.attribute_name).to eq 'array_position'
+ expect(order_list.first.named_function).to be_kind_of(Arel::Nodes::NamedFunction)
+ expect(order_list.first.sort_direction).to eq :asc
+ end
+ end
end
describe '#validate_ordering' do
diff --git a/spec/lib/gitlab/graphql/pagination/keyset/query_builder_spec.rb b/spec/lib/gitlab/graphql/pagination/keyset/query_builder_spec.rb
index c7e7db4d535..fa631aa5666 100644
--- a/spec/lib/gitlab/graphql/pagination/keyset/query_builder_spec.rb
+++ b/spec/lib/gitlab/graphql/pagination/keyset/query_builder_spec.rb
@@ -136,11 +136,12 @@ RSpec.describe Gitlab::Graphql::Pagination::Keyset::QueryBuilder do
let(:relation) { Project.sorted_by_similarity_desc('test', include_in_select: true) }
let(:arel_table) { Project.arel_table }
let(:decoded_cursor) { { 'similarity' => 0.5, 'id' => 100 } }
+ let(:similarity_function_call) { Gitlab::Database::SimilarityScore::SIMILARITY_FUNCTION_CALL_WITH_ANNOTATION }
let(:similarity_sql) do
[
- '(SIMILARITY(COALESCE("projects"."path", \'\'), \'test\') * CAST(\'1\' AS numeric))',
- '(SIMILARITY(COALESCE("projects"."name", \'\'), \'test\') * CAST(\'0.7\' AS numeric))',
- '(SIMILARITY(COALESCE("projects"."description", \'\'), \'test\') * CAST(\'0.2\' AS numeric))'
+ "(#{similarity_function_call}(COALESCE(\"projects\".\"path\", ''), 'test') * CAST('1' AS numeric))",
+ "(#{similarity_function_call}(COALESCE(\"projects\".\"name\", ''), 'test') * CAST('0.7' AS numeric))",
+ "(#{similarity_function_call}(COALESCE(\"projects\".\"description\", ''), 'test') * CAST('0.2' AS numeric))"
].join(' + ')
end
diff --git a/spec/lib/gitlab/graphql/query_analyzers/logger_analyzer_spec.rb b/spec/lib/gitlab/graphql/query_analyzers/logger_analyzer_spec.rb
index 89d2ab8bb87..c8432513185 100644
--- a/spec/lib/gitlab/graphql/query_analyzers/logger_analyzer_spec.rb
+++ b/spec/lib/gitlab/graphql/query_analyzers/logger_analyzer_spec.rb
@@ -26,7 +26,7 @@ RSpec.describe Gitlab::Graphql::QueryAnalyzers::LoggerAnalyzer do
end
it 'returns a duration in seconds' do
- allow(GraphQL::Analysis).to receive(:analyze_query).and_return([4, 2])
+ allow(GraphQL::Analysis).to receive(:analyze_query).and_return([4, 2, [[], []]])
allow(Gitlab::Metrics::System).to receive(:monotonic_time).and_return(monotonic_time_before, monotonic_time_after)
allow(Gitlab::GraphqlLogger).to receive(:info)
diff --git a/spec/lib/gitlab/group_search_results_spec.rb b/spec/lib/gitlab/group_search_results_spec.rb
index 045c922783a..009f66d2108 100644
--- a/spec/lib/gitlab/group_search_results_spec.rb
+++ b/spec/lib/gitlab/group_search_results_spec.rb
@@ -17,10 +17,17 @@ RSpec.describe Gitlab::GroupSearchResults do
describe 'issues search' do
let_it_be(:opened_result) { create(:issue, :opened, project: project, title: 'foo opened') }
let_it_be(:closed_result) { create(:issue, :closed, project: project, title: 'foo closed') }
+ let_it_be(:confidential_result) { create(:issue, :confidential, project: project, title: 'foo confidential') }
+
let(:query) { 'foo' }
let(:scope) { 'issues' }
+ before do
+ project.add_developer(user)
+ end
+
include_examples 'search results filtered by state'
+ include_examples 'search results filtered by confidential'
end
describe 'merge_requests search' do
diff --git a/spec/lib/gitlab/import_export/all_models.yml b/spec/lib/gitlab/import_export/all_models.yml
index 3126d87a0d6..5ee7fb2adbf 100644
--- a/spec/lib/gitlab/import_export/all_models.yml
+++ b/spec/lib/gitlab/import_export/all_models.yml
@@ -30,6 +30,7 @@ issues:
- metrics
- timelogs
- issuable_severity
+- issuable_sla
- issue_assignees
- closed_by
- epic_issue
@@ -51,6 +52,7 @@ issues:
- status_page_published_incident
- namespace
- note_authors
+- issue_email_participants
events:
- author
- project
@@ -158,6 +160,8 @@ merge_requests:
- assignees
- reviews
- approval_rules
+- approval_merge_request_rule_sources
+- approval_project_rules
- approvals
- approvers
- approver_users
@@ -242,6 +246,7 @@ ci_pipelines:
- latest_builds_report_results
- messages
- pipeline_artifacts
+- latest_statuses
ci_refs:
- project
- ci_pipelines
@@ -300,6 +305,7 @@ protected_branches:
- push_access_levels
- unprotect_access_levels
- approval_project_rules
+- required_code_owners_sections
protected_tags:
- project
- create_access_levels
@@ -408,6 +414,7 @@ project:
- stages
- ci_refs
- builds
+- processables
- runner_projects
- runners
- variables
@@ -465,6 +472,8 @@ project:
- feature_usage
- approval_rules
- approval_merge_request_rules
+- approval_merge_request_rule_sources
+- approval_project_rules
- approvers
- approver_users
- audit_events
@@ -536,6 +545,8 @@ project:
- vulnerability_historical_statistics
- product_analytics_events
- pipeline_artifacts
+- terraform_states
+- alert_management_http_integrations
award_emoji:
- awardable
- user
@@ -703,3 +714,5 @@ system_note_metadata:
- description_version
status_page_published_incident:
- issue
+issuable_sla:
+ - issue
diff --git a/spec/lib/gitlab/import_export/fast_hash_serializer_spec.rb b/spec/lib/gitlab/import_export/fast_hash_serializer_spec.rb
index 93b6f93f0ec..d084b9d7f7e 100644
--- a/spec/lib/gitlab/import_export/fast_hash_serializer_spec.rb
+++ b/spec/lib/gitlab/import_export/fast_hash_serializer_spec.rb
@@ -10,14 +10,17 @@ RSpec.describe Gitlab::ImportExport::FastHashSerializer do
# all items are properly serialized while traversing the simple hash.
subject { Gitlab::Json.parse(Gitlab::Json.generate(described_class.new(project, tree).execute)) }
- let!(:project) { setup_project }
- let(:user) { create(:user) }
+ let_it_be(:user) { create(:user) }
+ let_it_be(:project) { setup_project }
let(:shared) { project.import_export_shared }
let(:reader) { Gitlab::ImportExport::Reader.new(shared: shared) }
let(:tree) { reader.project_tree }
- before do
+ before_all do
project.add_maintainer(user)
+ end
+
+ before do
allow_any_instance_of(MergeRequest).to receive(:source_branch_sha).and_return('ABCD')
allow_any_instance_of(MergeRequest).to receive(:target_branch_sha).and_return('DCBA')
end
@@ -224,7 +227,6 @@ RSpec.describe Gitlab::ImportExport::FastHashSerializer do
group: group,
approvals_before_merge: 1
)
- allow(project).to receive(:commit).and_return(Commit.new(RepoHelpers.sample_commit, project))
issue = create(:issue, assignees: [user], project: project)
snippet = create(:project_snippet, project: project)
diff --git a/spec/lib/gitlab/import_export/group/relation_factory_spec.rb b/spec/lib/gitlab/import_export/group/relation_factory_spec.rb
index eb9a3fa9bd8..6b2f80cc80a 100644
--- a/spec/lib/gitlab/import_export/group/relation_factory_spec.rb
+++ b/spec/lib/gitlab/import_export/group/relation_factory_spec.rb
@@ -5,16 +5,19 @@ require 'spec_helper'
RSpec.describe Gitlab::ImportExport::Group::RelationFactory do
let(:group) { create(:group) }
let(:members_mapper) { double('members_mapper').as_null_object }
- let(:user) { create(:admin) }
+ let(:admin) { create(:admin) }
+ let(:importer_user) { admin }
let(:excluded_keys) { [] }
let(:created_object) do
- described_class.create(relation_sym: relation_sym,
- relation_hash: relation_hash,
- members_mapper: members_mapper,
- object_builder: Gitlab::ImportExport::Group::ObjectBuilder,
- user: user,
- importable: group,
- excluded_keys: excluded_keys)
+ described_class.create(
+ relation_sym: relation_sym,
+ relation_hash: relation_hash,
+ members_mapper: members_mapper,
+ object_builder: Gitlab::ImportExport::Group::ObjectBuilder,
+ user: importer_user,
+ importable: group,
+ excluded_keys: excluded_keys
+ )
end
context 'label object' do
@@ -24,18 +27,18 @@ RSpec.describe Gitlab::ImportExport::Group::RelationFactory do
let(:relation_hash) do
{
- 'id' => 123456,
- 'title' => 'Bruffefunc',
- 'color' => '#1d2da4',
- 'project_id' => nil,
- 'created_at' => '2019-11-20T17:02:20.546Z',
- 'updated_at' => '2019-11-20T17:02:20.546Z',
- 'template' => false,
+ 'id' => 123456,
+ 'title' => 'Bruffefunc',
+ 'color' => '#1d2da4',
+ 'project_id' => nil,
+ 'created_at' => '2019-11-20T17:02:20.546Z',
+ 'updated_at' => '2019-11-20T17:02:20.546Z',
+ 'template' => false,
'description' => 'Description',
- 'group_id' => original_group_id,
- 'type' => 'GroupLabel',
- 'priorities' => [],
- 'textColor' => '#FFFFFF'
+ 'group_id' => original_group_id,
+ 'type' => 'GroupLabel',
+ 'priorities' => [],
+ 'textColor' => '#FFFFFF'
}
end
@@ -60,58 +63,28 @@ RSpec.describe Gitlab::ImportExport::Group::RelationFactory do
end
end
- context 'Notes user references' do
- let(:relation_sym) { :notes }
- let(:new_user) { create(:user) }
- let(:exported_member) do
- {
- 'id' => 111,
- 'access_level' => 30,
- 'source_id' => 1,
- 'source_type' => 'Namespace',
- 'user_id' => 3,
- 'notification_level' => 3,
- 'created_at' => '2016-11-18T09:29:42.634Z',
- 'updated_at' => '2016-11-18T09:29:42.634Z',
- 'user' => {
- 'id' => 999,
- 'email' => new_user.email,
- 'username' => new_user.username
- }
- }
- end
-
+ it_behaves_like 'Notes user references' do
+ let(:importable) { group }
let(:relation_hash) do
{
- 'id' => 4947,
- 'note' => 'note',
+ 'id' => 4947,
+ 'note' => 'note',
'noteable_type' => 'Epic',
- 'author_id' => 999,
- 'created_at' => '2016-11-18T09:29:42.634Z',
- 'updated_at' => '2016-11-18T09:29:42.634Z',
- 'project_id' => 1,
- 'attachment' => {
+ 'author_id' => 999,
+ 'created_at' => '2016-11-18T09:29:42.634Z',
+ 'updated_at' => '2016-11-18T09:29:42.634Z',
+ 'project_id' => 1,
+ 'attachment' => {
'url' => nil
},
- 'noteable_id' => 377,
- 'system' => true,
- 'author' => {
+ 'noteable_id' => 377,
+ 'system' => true,
+ 'author' => {
'name' => 'Administrator'
},
'events' => []
}
end
-
- let(:members_mapper) do
- Gitlab::ImportExport::MembersMapper.new(
- exported_members: [exported_member],
- user: user,
- importable: group)
- end
-
- it 'maps the right author to the imported note' do
- expect(created_object.author).to eq(new_user)
- end
end
def random_id
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 9737a0f39fc..7a9e7d8afba 100644
--- a/spec/lib/gitlab/import_export/import_test_coverage_spec.rb
+++ b/spec/lib/gitlab/import_export/import_test_coverage_spec.rb
@@ -23,6 +23,7 @@ RSpec.describe 'Test coverage of the Project Import' do
project.issues.notes.events
project.issues.notes.events.push_event_payload
project.issues.milestone.events.push_event_payload
+ project.issues.issuable_sla
project.issues.issue_milestones
project.issues.issue_milestones.milestone
project.issues.resource_label_events.label.priorities
diff --git a/spec/lib/gitlab/import_export/json/ndjson_reader_spec.rb b/spec/lib/gitlab/import_export/json/ndjson_reader_spec.rb
index a347d835428..e208a1c383c 100644
--- a/spec/lib/gitlab/import_export/json/ndjson_reader_spec.rb
+++ b/spec/lib/gitlab/import_export/json/ndjson_reader_spec.rb
@@ -102,4 +102,14 @@ RSpec.describe Gitlab::ImportExport::JSON::NdjsonReader do
end
end
end
+
+ describe '#clear_consumed_relations' do
+ let(:dir_path) { fixture }
+
+ subject { ndjson_reader.clear_consumed_relations }
+
+ it 'returns empty set' do
+ expect(subject).to be_empty
+ end
+ end
end
diff --git a/spec/lib/gitlab/import_export/lfs_saver_spec.rb b/spec/lib/gitlab/import_export/lfs_saver_spec.rb
index db76eb9538b..55b4f7479b8 100644
--- a/spec/lib/gitlab/import_export/lfs_saver_spec.rb
+++ b/spec/lib/gitlab/import_export/lfs_saver_spec.rb
@@ -74,14 +74,6 @@ RSpec.describe Gitlab::ImportExport::LfsSaver do
}
)
end
-
- it 'does not save a json file if feature is disabled' do
- stub_feature_flags(export_lfs_objects_projects: false)
-
- saver.save
-
- expect(File.exist?(lfs_json_file)).to eq(false)
- end
end
end
diff --git a/spec/lib/gitlab/import_export/project/relation_factory_spec.rb b/spec/lib/gitlab/import_export/project/relation_factory_spec.rb
index 31cf2362628..50bc6a30044 100644
--- a/spec/lib/gitlab/import_export/project/relation_factory_spec.rb
+++ b/spec/lib/gitlab/import_export/project/relation_factory_spec.rb
@@ -3,19 +3,22 @@
require 'spec_helper'
RSpec.describe Gitlab::ImportExport::Project::RelationFactory do
- let(:group) { create(:group) }
+ let(:group) { create(:group) }
let(:project) { create(:project, :repository, group: group) }
let(:members_mapper) { double('members_mapper').as_null_object }
- let(:user) { create(:admin) }
+ let(:admin) { create(:admin) }
+ let(:importer_user) { admin }
let(:excluded_keys) { [] }
let(:created_object) do
- described_class.create(relation_sym: relation_sym,
- relation_hash: relation_hash,
- object_builder: Gitlab::ImportExport::Project::ObjectBuilder,
- members_mapper: members_mapper,
- user: user,
- importable: project,
- excluded_keys: excluded_keys)
+ described_class.create(
+ relation_sym: relation_sym,
+ relation_hash: relation_hash,
+ object_builder: Gitlab::ImportExport::Project::ObjectBuilder,
+ members_mapper: members_mapper,
+ user: importer_user,
+ importable: project,
+ excluded_keys: excluded_keys
+ )
end
before do
@@ -113,9 +116,9 @@ RSpec.describe Gitlab::ImportExport::Project::RelationFactory do
"created_at" => "2016-11-18T09:29:42.634Z",
"updated_at" => "2016-11-18T09:29:42.634Z",
"user" => {
- "id" => user.id,
- "email" => user.email,
- "username" => user.username
+ "id" => admin.id,
+ "email" => admin.email,
+ "username" => admin.username
}
}
end
@@ -123,7 +126,7 @@ RSpec.describe Gitlab::ImportExport::Project::RelationFactory do
let(:members_mapper) do
Gitlab::ImportExport::MembersMapper.new(
exported_members: [exported_member],
- user: user,
+ user: importer_user,
importable: project)
end
@@ -134,9 +137,9 @@ RSpec.describe Gitlab::ImportExport::Project::RelationFactory do
'source_branch' => "feature_conflict",
'source_project_id' => project.id,
'target_project_id' => project.id,
- 'author_id' => user.id,
- 'assignee_id' => user.id,
- 'updated_by_id' => user.id,
+ 'author_id' => admin.id,
+ 'assignee_id' => admin.id,
+ 'updated_by_id' => admin.id,
'title' => "MR1",
'created_at' => "2016-06-14T15:02:36.568Z",
'updated_at' => "2016-06-14T15:02:56.815Z",
@@ -151,11 +154,11 @@ RSpec.describe Gitlab::ImportExport::Project::RelationFactory do
end
it 'has preloaded author' do
- expect(created_object.author).to equal(user)
+ expect(created_object.author).to equal(admin)
end
it 'has preloaded updated_by' do
- expect(created_object.updated_by).to equal(user)
+ expect(created_object.updated_by).to equal(admin)
end
it 'has preloaded source project' do
@@ -264,27 +267,8 @@ RSpec.describe Gitlab::ImportExport::Project::RelationFactory do
end
end
- context 'Notes user references' do
- let(:relation_sym) { :notes }
- let(:new_user) { create(:user) }
- let(:exported_member) do
- {
- "id" => 111,
- "access_level" => 30,
- "source_id" => 1,
- "source_type" => "Project",
- "user_id" => 3,
- "notification_level" => 3,
- "created_at" => "2016-11-18T09:29:42.634Z",
- "updated_at" => "2016-11-18T09:29:42.634Z",
- "user" => {
- "id" => 999,
- "email" => new_user.email,
- "username" => new_user.username
- }
- }
- end
-
+ it_behaves_like 'Notes user references' do
+ let(:importable) { project }
let(:relation_hash) do
{
"id" => 4947,
@@ -305,17 +289,6 @@ RSpec.describe Gitlab::ImportExport::Project::RelationFactory do
"events" => []
}
end
-
- let(:members_mapper) do
- Gitlab::ImportExport::MembersMapper.new(
- exported_members: [exported_member],
- user: user,
- importable: project)
- end
-
- it 'maps the right author to the imported note' do
- expect(created_object.author).to eq(new_user)
- end
end
context 'encrypted attributes' do
diff --git a/spec/lib/gitlab/import_export/project/sample/date_calculator_spec.rb b/spec/lib/gitlab/import_export/project/sample/date_calculator_spec.rb
new file mode 100644
index 00000000000..82f59245519
--- /dev/null
+++ b/spec/lib/gitlab/import_export/project/sample/date_calculator_spec.rb
@@ -0,0 +1,53 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::ImportExport::Project::Sample::DateCalculator do
+ describe '#closest date to average' do
+ subject { described_class.new(dates).closest_date_to_average }
+
+ context 'when dates are empty' do
+ let(:dates) { [] }
+
+ it { is_expected.to be_nil }
+ end
+
+ context 'when dates are not empty' do
+ let(:dates) { [[nil, '2020-01-01 00:00:00 +0000'], [nil, '2021-01-01 00:00:00 +0000'], [nil, '2022-01-01 23:59:59 +0000']] }
+
+ it { is_expected.to eq(Time.zone.parse('2021-01-01 00:00:00 +0000')) }
+ end
+ end
+
+ describe '#calculate_by_closest_date_to_average' do
+ let(:calculator) { described_class.new([]) }
+ let(:date) { Time.current }
+
+ subject { calculator.calculate_by_closest_date_to_average(date) }
+
+ context 'when average date is nil' do
+ before do
+ allow(calculator).to receive(:closest_date_to_average).and_return(nil)
+ end
+
+ it { is_expected.to eq(date) }
+ end
+
+ context 'when average date is in the past' do
+ before do
+ allow(calculator).to receive(:closest_date_to_average).and_return(date - 365.days)
+ allow(Time).to receive(:current).and_return(date)
+ end
+
+ it { is_expected.to eq(date + 365.days) }
+ end
+
+ context 'when average date is in the future' do
+ before do
+ allow(calculator).to receive(:closest_date_to_average).and_return(date + 10.days)
+ end
+
+ it { is_expected.to eq(date) }
+ end
+ end
+end
diff --git a/spec/lib/gitlab/import_export/project/sample/sample_data_relation_tree_restorer_spec.rb b/spec/lib/gitlab/import_export/project/sample/sample_data_relation_tree_restorer_spec.rb
new file mode 100644
index 00000000000..f173345a4c6
--- /dev/null
+++ b/spec/lib/gitlab/import_export/project/sample/sample_data_relation_tree_restorer_spec.rb
@@ -0,0 +1,87 @@
+# frozen_string_literal: true
+
+# This spec is a lightweight version of:
+# * project/tree_restorer_spec.rb
+#
+# In depth testing is being done in the above specs.
+# This spec tests that restore of the sample project works
+# but does not have 100% relation coverage.
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::ImportExport::Project::Sample::SampleDataRelationTreeRestorer do
+ include_context 'relation tree restorer shared context'
+
+ let(:sample_data_relation_tree_restorer) do
+ described_class.new(
+ user: user,
+ shared: shared,
+ relation_reader: relation_reader,
+ object_builder: object_builder,
+ members_mapper: members_mapper,
+ relation_factory: relation_factory,
+ reader: reader,
+ importable: importable,
+ importable_path: importable_path,
+ importable_attributes: attributes
+ )
+ end
+
+ subject { sample_data_relation_tree_restorer.restore }
+
+ shared_examples 'import project successfully' do
+ it 'restores project tree' do
+ expect(subject).to eq(true)
+ end
+
+ describe 'imported project' do
+ let(:project) { Project.find_by_path('project') }
+
+ before do
+ subject
+ end
+
+ it 'has the project attributes and relations', :aggregate_failures do
+ expect(project.description).to eq('Nisi et repellendus ut enim quo accusamus vel magnam.')
+ expect(project.issues.count).to eq(10)
+ expect(project.milestones.count).to eq(3)
+ expect(project.labels.count).to eq(2)
+ expect(project.project_feature).not_to be_nil
+ end
+
+ it 'has issues with correctly updated due dates' do
+ due_dates = due_dates(project.issues)
+
+ expect(due_dates).to match_array([Date.today - 7.days, Date.today, Date.today + 7.days])
+ end
+
+ it 'has milestones with correctly updated due dates' do
+ due_dates = due_dates(project.milestones)
+
+ expect(due_dates).to match_array([Date.today - 7.days, Date.today, Date.today + 7.days])
+ end
+
+ def due_dates(relations)
+ due_dates = relations.map { |relation| relation['due_date'] }
+ due_dates.compact!
+ due_dates.sort
+ end
+ end
+ end
+
+ context 'when restoring a project' do
+ let(:importable) { create(:project, :builds_enabled, :issues_disabled, name: 'project', path: 'project') }
+ let(:importable_name) { 'project' }
+ let(:importable_path) { 'project' }
+ let(:object_builder) { Gitlab::ImportExport::Project::ObjectBuilder }
+ let(:relation_factory) { Gitlab::ImportExport::Project::RelationFactory }
+ let(:reader) { Gitlab::ImportExport::Reader.new(shared: shared) }
+
+ context 'using ndjson reader' do
+ let(:path) { 'spec/fixtures/lib/gitlab/import_export/sample_data/tree' }
+ let(:relation_reader) { Gitlab::ImportExport::JSON::NdjsonReader.new(path) }
+
+ it_behaves_like 'import project successfully'
+ end
+ end
+end
diff --git a/spec/lib/gitlab/import_export/project/tree_restorer_spec.rb b/spec/lib/gitlab/import_export/project/tree_restorer_spec.rb
index f75494aa7c7..c05968c9a85 100644
--- a/spec/lib/gitlab/import_export/project/tree_restorer_spec.rb
+++ b/spec/lib/gitlab/import_export/project/tree_restorer_spec.rb
@@ -1040,6 +1040,41 @@ RSpec.describe Gitlab::ImportExport::Project::TreeRestorer do
it_behaves_like 'project tree restorer work properly', :legacy_reader, true
it_behaves_like 'project tree restorer work properly', :ndjson_reader, true
+
+ context 'Sample Data JSON' do
+ let(:user) { create(:user) }
+ let!(:project) { create(:project, :builds_disabled, :issues_disabled, name: 'project', path: 'project') }
+ let(:project_tree_restorer) { described_class.new(user: user, shared: shared, project: project) }
+
+ before do
+ setup_import_export_config('sample_data')
+ setup_reader(:ndjson_reader)
+ end
+
+ context 'with sample_data_template' do
+ before do
+ allow(project).to receive_message_chain(:import_data, :data, :dig).with('sample_data') { true }
+ end
+
+ it 'initialize SampleDataRelationTreeRestorer' do
+ expect_next_instance_of(Gitlab::ImportExport::Project::Sample::SampleDataRelationTreeRestorer) do |restorer|
+ expect(restorer).to receive(:restore).and_return(true)
+ end
+
+ expect(project_tree_restorer.restore).to eq(true)
+ end
+ end
+
+ context 'without sample_data_template' do
+ it 'initialize RelationTreeRestorer' do
+ expect_next_instance_of(Gitlab::ImportExport::RelationTreeRestorer) do |restorer|
+ expect(restorer).to receive(:restore).and_return(true)
+ end
+
+ expect(project_tree_restorer.restore).to eq(true)
+ end
+ end
+ end
end
context 'disable ndjson import' do
diff --git a/spec/lib/gitlab/import_export/relation_tree_restorer_spec.rb b/spec/lib/gitlab/import_export/relation_tree_restorer_spec.rb
index ddc96b83208..bd9ac6d6697 100644
--- a/spec/lib/gitlab/import_export/relation_tree_restorer_spec.rb
+++ b/spec/lib/gitlab/import_export/relation_tree_restorer_spec.rb
@@ -10,15 +10,7 @@
require 'spec_helper'
RSpec.describe Gitlab::ImportExport::RelationTreeRestorer do
- include ImportExport::CommonUtil
-
- let(:user) { create(:user) }
- let(:shared) { Gitlab::ImportExport::Shared.new(importable) }
- let(:attributes) { relation_reader.consume_attributes(importable_name) }
-
- let(:members_mapper) do
- Gitlab::ImportExport::MembersMapper.new(exported_members: {}, user: user, importable: importable)
- end
+ include_context 'relation tree restorer shared context'
let(:relation_tree_restorer) do
described_class.new(
diff --git a/spec/lib/gitlab/import_export/repo_restorer_spec.rb b/spec/lib/gitlab/import_export/repo_restorer_spec.rb
index ace4449042e..b32ae60fbcc 100644
--- a/spec/lib/gitlab/import_export/repo_restorer_spec.rb
+++ b/spec/lib/gitlab/import_export/repo_restorer_spec.rb
@@ -36,21 +36,20 @@ RSpec.describe Gitlab::ImportExport::RepoRestorer do
expect(subject.restore).to be_truthy
end
- context 'when the repository creation fails' do
- before do
- allow_next_instance_of(Repositories::DestroyService) do |instance|
+ context 'when the repository already exists' do
+ it 'deletes the existing repository before importing' do
+ allow(project.repository).to receive(:exists?).and_return(true)
+ allow(project.repository).to receive(:path).and_return('repository_path')
+
+ expect_next_instance_of(Repositories::DestroyService) do |instance|
expect(instance).to receive(:execute).and_call_original
end
- end
-
- it 'logs the error' do
- allow(project.repository)
- .to receive(:create_from_bundle)
- .and_raise('9:CreateRepositoryFromBundle: target directory is non-empty')
- expect(shared).to receive(:error).and_call_original
+ expect(shared.logger).to receive(:info).with(
+ message: 'Deleting existing "repository_path" to re-import it.'
+ )
- expect(subject.restore).to be_falsey
+ expect(subject.restore).to be_truthy
end
end
end
diff --git a/spec/lib/gitlab/import_export/safe_model_attributes.yml b/spec/lib/gitlab/import_export/safe_model_attributes.yml
index 5ca7c5b7a91..e3d1f2c9368 100644
--- a/spec/lib/gitlab/import_export/safe_model_attributes.yml
+++ b/spec/lib/gitlab/import_export/safe_model_attributes.yml
@@ -855,3 +855,6 @@ ProjectSecuritySetting:
- auto_fix_sast
- created_at
- updated_at
+IssuableSla:
+ - issue_id
+ - due_at
diff --git a/spec/lib/gitlab/issuables_count_for_state_spec.rb b/spec/lib/gitlab/issuables_count_for_state_spec.rb
index d96152e47ea..a6170c146ab 100644
--- a/spec/lib/gitlab/issuables_count_for_state_spec.rb
+++ b/spec/lib/gitlab/issuables_count_for_state_spec.rb
@@ -4,14 +4,15 @@ require 'spec_helper'
RSpec.describe Gitlab::IssuablesCountForState do
let(:finder) do
- double(:finder, count_by_state: { opened: 2, closed: 1 })
+ double(:finder, current_user: nil, params: {}, count_by_state: { opened: 2, closed: 1 })
end
- let(:counter) { described_class.new(finder) }
+ let(:project) { nil }
+ let(:fast_fail) { nil }
+ let(:counter) { described_class.new(finder, project, fast_fail: fast_fail) }
describe 'project given' do
let(:project) { build(:project) }
- let(:counter) { described_class.new(finder, project) }
it 'provides the project' do
expect(counter.project).to eq(project)
@@ -50,5 +51,19 @@ RSpec.describe Gitlab::IssuablesCountForState do
it 'returns 0 when using an invalid state name as a String' do
expect(counter['kittens']).to be_zero
end
+
+ context 'fast_fail enabled' do
+ let(:fast_fail) { true }
+
+ it 'returns the expected value' do
+ expect(counter[:closed]).to eq(1)
+ end
+
+ it 'returns -1 when the database times out' do
+ expect(finder).to receive(:count_by_state).and_raise(ActiveRecord::QueryCanceled)
+
+ expect(counter[:closed]).to eq(-1)
+ end
+ end
end
end
diff --git a/spec/lib/gitlab/job_waiter_spec.rb b/spec/lib/gitlab/job_waiter_spec.rb
index 7aa0a3485fb..a9edb2b530b 100644
--- a/spec/lib/gitlab/job_waiter_spec.rb
+++ b/spec/lib/gitlab/job_waiter_spec.rb
@@ -2,23 +2,26 @@
require 'spec_helper'
-RSpec.describe Gitlab::JobWaiter do
+RSpec.describe Gitlab::JobWaiter, :redis do
describe '.notify' do
it 'pushes the jid to the named queue' do
- key = 'gitlab:job_waiter:foo'
- jid = 1
+ key = described_class.new.key
- redis = double('redis')
- expect(Gitlab::Redis::SharedState).to receive(:with).and_yield(redis)
- expect(redis).to receive(:lpush).with(key, jid)
+ described_class.notify(key, 123)
- described_class.notify(key, jid)
+ Gitlab::Redis::SharedState.with do |redis|
+ expect(redis.ttl(key)).to be > 0
+ end
end
end
describe '#wait' do
let(:waiter) { described_class.new(2) }
+ before do
+ allow_any_instance_of(described_class).to receive(:wait).and_call_original
+ end
+
it 'returns when all jobs have been completed' do
described_class.notify(waiter.key, 'a')
described_class.notify(waiter.key, 'b')
diff --git a/spec/lib/gitlab/kubernetes/kube_client_spec.rb b/spec/lib/gitlab/kubernetes/kube_client_spec.rb
index 90c11f29855..7b6d143dda9 100644
--- a/spec/lib/gitlab/kubernetes/kube_client_spec.rb
+++ b/spec/lib/gitlab/kubernetes/kube_client_spec.rb
@@ -9,7 +9,7 @@ RSpec.describe Gitlab::Kubernetes::KubeClient do
let(:api_url) { 'https://kubernetes.example.com/prefix' }
let(:kubeclient_options) { { auth_options: { bearer_token: 'xyz' } } }
- let(:client) { described_class.new(api_url, kubeclient_options) }
+ let(:client) { described_class.new(api_url, **kubeclient_options) }
before do
stub_kubeclient_discover(api_url)
@@ -133,7 +133,7 @@ RSpec.describe Gitlab::Kubernetes::KubeClient do
end
it 'falls back to default options, but allows overriding' do
- client = Gitlab::Kubernetes::KubeClient.new(api_url, {})
+ client = described_class.new(api_url)
defaults = Gitlab::Kubernetes::KubeClient::DEFAULT_KUBECLIENT_OPTIONS
expect(client.kubeclient_options[:timeouts]).to eq(defaults[:timeouts])
@@ -347,6 +347,34 @@ RSpec.describe Gitlab::Kubernetes::KubeClient do
end
end
+ describe '#get_ingresses' do
+ let(:extensions_client) { client.extensions_client }
+ let(:networking_client) { client.networking_client }
+
+ include_examples 'redirection not allowed', 'get_ingresses'
+ include_examples 'dns rebinding not allowed', 'get_ingresses'
+
+ it 'delegates to the extensions client' do
+ expect(extensions_client).to receive(:get_ingresses)
+
+ client.get_ingresses
+ end
+
+ context 'extensions does not have deployments for Kubernetes 1.22+ clusters' do
+ before do
+ WebMock
+ .stub_request(:get, api_url + '/apis/extensions/v1beta1')
+ .to_return(kube_response(kube_1_22_extensions_v1beta1_discovery_body))
+ end
+
+ it 'delegates to the apps client' do
+ expect(networking_client).to receive(:get_ingresses)
+
+ client.get_ingresses
+ end
+ end
+ end
+
describe 'istio API group' do
let(:istio_client) { client.istio_client }
diff --git a/spec/lib/gitlab/lfs/client_spec.rb b/spec/lib/gitlab/lfs/client_spec.rb
index 03563a632d6..1c50a2a7500 100644
--- a/spec/lib/gitlab/lfs/client_spec.rb
+++ b/spec/lib/gitlab/lfs/client_spec.rb
@@ -7,6 +7,8 @@ RSpec.describe Gitlab::Lfs::Client do
let(:username) { 'user' }
let(:password) { 'password' }
let(:credentials) { { user: username, password: password, auth_method: 'password' } }
+ let(:git_lfs_content_type) { 'application/vnd.git-lfs+json' }
+ let(:git_lfs_user_agent) { "GitLab #{Gitlab::VERSION} LFS client" }
let(:basic_auth_headers) do
{ 'Authorization' => "Basic #{Base64.strict_encode64("#{username}:#{password}")}" }
@@ -21,6 +23,18 @@ RSpec.describe Gitlab::Lfs::Client do
}
end
+ let(:verify_action) do
+ {
+ "href" => "#{base_url}/some/file/verify",
+ "header" => {
+ "Key" => "value"
+ }
+ }
+ end
+
+ let(:authorized_upload_action) { upload_action.tap { |action| action['header']['Authorization'] = 'foo' } }
+ let(:authorized_verify_action) { verify_action.tap { |action| action['header']['Authorization'] = 'foo' } }
+
subject(:lfs_client) { described_class.new(base_url, credentials: credentials) }
describe '#batch' do
@@ -34,10 +48,10 @@ RSpec.describe Gitlab::Lfs::Client do
).to_return(
status: 200,
body: { 'objects' => 'anything', 'transfer' => 'basic' }.to_json,
- headers: { 'Content-Type' => 'application/vnd.git-lfs+json' }
+ headers: { 'Content-Type' => git_lfs_content_type }
)
- result = lfs_client.batch('upload', objects)
+ result = lfs_client.batch!('upload', objects)
expect(stub).to have_been_requested
expect(result).to eq('objects' => 'anything', 'transfer' => 'basic')
@@ -48,7 +62,7 @@ RSpec.describe Gitlab::Lfs::Client do
it 'raises an error' do
stub_batch(objects: objects, headers: basic_auth_headers).to_return(status: 400)
- expect { lfs_client.batch('upload', objects) }.to raise_error(/Failed/)
+ expect { lfs_client.batch!('upload', objects) }.to raise_error(/Failed/)
end
end
@@ -56,7 +70,7 @@ RSpec.describe Gitlab::Lfs::Client do
it 'raises an error' do
stub_batch(objects: objects, headers: basic_auth_headers).to_return(status: 400)
- expect { lfs_client.batch('upload', objects) }.to raise_error(/Failed/)
+ expect { lfs_client.batch!('upload', objects) }.to raise_error(/Failed/)
end
end
@@ -68,17 +82,23 @@ RSpec.describe Gitlab::Lfs::Client do
).to_return(
status: 200,
body: { 'transfer' => 'carrier-pigeon' }.to_json,
- headers: { 'Content-Type' => 'application/vnd.git-lfs+json' }
+ headers: { 'Content-Type' => git_lfs_content_type }
)
- expect { lfs_client.batch('upload', objects) }.to raise_error(/Unsupported transfer/)
+ expect { lfs_client.batch!('upload', objects) }.to raise_error(/Unsupported transfer/)
end
end
def stub_batch(objects:, headers:, operation: 'upload', transfer: 'basic')
- objects = objects.map { |o| { oid: o.oid, size: o.size } }
+ objects = objects.as_json(only: [:oid, :size])
body = { operation: operation, 'transfers': [transfer], objects: objects }.to_json
+ headers = {
+ 'Accept' => git_lfs_content_type,
+ 'Content-Type' => git_lfs_content_type,
+ 'User-Agent' => git_lfs_user_agent
+ }.merge(headers)
+
stub_request(:post, base_url + '/info/lfs/objects/batch').with(body: body, headers: headers)
end
end
@@ -90,7 +110,7 @@ RSpec.describe Gitlab::Lfs::Client do
it "makes an HTTP PUT with expected parameters" do
stub_upload(object: object, headers: upload_action['header']).to_return(status: 200)
- lfs_client.upload(object, upload_action, authenticated: true)
+ lfs_client.upload!(object, upload_action, authenticated: true)
end
end
@@ -101,7 +121,20 @@ RSpec.describe Gitlab::Lfs::Client do
headers: basic_auth_headers.merge(upload_action['header'])
).to_return(status: 200)
- lfs_client.upload(object, upload_action, authenticated: false)
+ lfs_client.upload!(object, upload_action, authenticated: false)
+
+ expect(stub).to have_been_requested
+ end
+ end
+
+ context 'request is not marked as authenticated but includes an authorization header' do
+ it 'prefers the provided authorization header' do
+ stub = stub_upload(
+ object: object,
+ headers: authorized_upload_action['header']
+ ).to_return(status: 200)
+
+ lfs_client.upload!(object, authorized_upload_action, authenticated: false)
expect(stub).to have_been_requested
end
@@ -110,13 +143,13 @@ RSpec.describe Gitlab::Lfs::Client do
context 'LFS object has no file' do
let(:object) { LfsObject.new }
- it 'makes an HJTT PUT with expected parameters' do
+ it 'makes an HTTP PUT with expected parameters' do
stub = stub_upload(
object: object,
headers: upload_action['header']
).to_return(status: 200)
- lfs_client.upload(object, upload_action, authenticated: true)
+ lfs_client.upload!(object, upload_action, authenticated: true)
expect(stub).to have_been_requested
end
@@ -126,7 +159,7 @@ RSpec.describe Gitlab::Lfs::Client do
it 'raises an error' do
stub_upload(object: object, headers: upload_action['header']).to_return(status: 400)
- expect { lfs_client.upload(object, upload_action, authenticated: true) }.to raise_error(/Failed/)
+ expect { lfs_client.upload!(object, upload_action, authenticated: true) }.to raise_error(/Failed/)
end
end
@@ -134,15 +167,88 @@ RSpec.describe Gitlab::Lfs::Client do
it 'raises an error' do
stub_upload(object: object, headers: upload_action['header']).to_return(status: 500)
- expect { lfs_client.upload(object, upload_action, authenticated: true) }.to raise_error(/Failed/)
+ expect { lfs_client.upload!(object, upload_action, authenticated: true) }.to raise_error(/Failed/)
end
end
def stub_upload(object:, headers:)
+ headers = {
+ 'Content-Type' => 'application/octet-stream',
+ 'Content-Length' => object.size.to_s,
+ 'User-Agent' => git_lfs_user_agent
+ }.merge(headers)
+
stub_request(:put, upload_action['href']).with(
body: object.file.read,
headers: headers.merge('Content-Length' => object.size.to_s)
)
end
end
+
+ describe "#verify" do
+ let_it_be(:object) { create(:lfs_object) }
+
+ context 'server returns 200 OK to an authenticated request' do
+ it "makes an HTTP POST with expected parameters" do
+ stub_verify(object: object, headers: verify_action['header']).to_return(status: 200)
+
+ lfs_client.verify!(object, verify_action, authenticated: true)
+ end
+ end
+
+ context 'server returns 200 OK to an unauthenticated request' do
+ it "makes an HTTP POST with expected parameters" do
+ stub = stub_verify(
+ object: object,
+ headers: basic_auth_headers.merge(upload_action['header'])
+ ).to_return(status: 200)
+
+ lfs_client.verify!(object, verify_action, authenticated: false)
+
+ expect(stub).to have_been_requested
+ end
+ end
+
+ context 'request is not marked as authenticated but includes an authorization header' do
+ it 'prefers the provided authorization header' do
+ stub = stub_verify(
+ object: object,
+ headers: authorized_verify_action['header']
+ ).to_return(status: 200)
+
+ lfs_client.verify!(object, authorized_verify_action, authenticated: false)
+
+ expect(stub).to have_been_requested
+ end
+ end
+
+ context 'server returns 400 error' do
+ it 'raises an error' do
+ stub_verify(object: object, headers: verify_action['header']).to_return(status: 400)
+
+ expect { lfs_client.verify!(object, verify_action, authenticated: true) }.to raise_error(/Failed/)
+ end
+ end
+
+ context 'server returns 500 error' do
+ it 'raises an error' do
+ stub_verify(object: object, headers: verify_action['header']).to_return(status: 500)
+
+ expect { lfs_client.verify!(object, verify_action, authenticated: true) }.to raise_error(/Failed/)
+ end
+ end
+
+ def stub_verify(object:, headers:)
+ headers = {
+ 'Accept' => git_lfs_content_type,
+ 'Content-Type' => git_lfs_content_type,
+ 'User-Agent' => git_lfs_user_agent
+ }.merge(headers)
+
+ stub_request(:post, verify_action['href']).with(
+ body: object.to_json(only: [:oid, :size]),
+ headers: headers
+ )
+ end
+ end
end
diff --git a/spec/lib/gitlab/lfs_token_spec.rb b/spec/lib/gitlab/lfs_token_spec.rb
index 9b8b2c1417a..4b40e8960b2 100644
--- a/spec/lib/gitlab/lfs_token_spec.rb
+++ b/spec/lib/gitlab/lfs_token_spec.rb
@@ -104,7 +104,7 @@ RSpec.describe Gitlab::LfsToken, :clean_gitlab_redis_shared_state do
# Needs to be at least LfsToken::DEFAULT_EXPIRE_TIME + 60 seconds
# in order to check whether it is valid 1 minute after it has expired
- Timecop.freeze(Time.now + described_class::DEFAULT_EXPIRE_TIME + 60) do
+ travel_to(Time.now + described_class::DEFAULT_EXPIRE_TIME + 60) do
expect(lfs_token.token_valid?(expired_token)).to be false
end
end
diff --git a/spec/lib/gitlab/manifest_import/manifest_spec.rb b/spec/lib/gitlab/manifest_import/manifest_spec.rb
index 2e8753b0880..352120c079d 100644
--- a/spec/lib/gitlab/manifest_import/manifest_spec.rb
+++ b/spec/lib/gitlab/manifest_import/manifest_spec.rb
@@ -12,19 +12,7 @@ RSpec.describe Gitlab::ManifestImport::Manifest do
end
context 'missing or invalid attributes' do
- let(:file) { Tempfile.new('foo') }
-
- before do
- content = <<~EOS
- <manifest>
- <remote review="invalid-url" />
- <project name="platform/build"/>
- </manifest>
- EOS
-
- file.write(content)
- file.rewind
- end
+ let(:file) { File.open(Rails.root.join('spec/fixtures/invalid_manifest.xml')) }
it { expect(manifest.valid?).to be false }
diff --git a/spec/lib/gitlab/manifest_import/metadata_spec.rb b/spec/lib/gitlab/manifest_import/metadata_spec.rb
new file mode 100644
index 00000000000..c8158d3e148
--- /dev/null
+++ b/spec/lib/gitlab/manifest_import/metadata_spec.rb
@@ -0,0 +1,62 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::ManifestImport::Metadata, :clean_gitlab_redis_shared_state do
+ let(:user) { double(id: 1) }
+ let(:repositories) do
+ [
+ { id: 'test1', url: 'http://demo.host/test1' },
+ { id: 'test2', url: 'http://demo.host/test2' }
+ ]
+ end
+
+ describe '#save' do
+ it 'stores data in Redis with an expiry of EXPIRY_TIME' do
+ status = described_class.new(user)
+ repositories_key = 'manifest_import:metadata:user:1:repositories'
+ group_id_key = 'manifest_import:metadata:user:1:group_id'
+
+ status.save(repositories, 2)
+
+ Gitlab::Redis::SharedState.with do |redis|
+ expect(redis.ttl(repositories_key)).to be_within(5).of(described_class::EXPIRY_TIME)
+ expect(redis.ttl(group_id_key)).to be_within(5).of(described_class::EXPIRY_TIME)
+ end
+ end
+ end
+
+ describe '#repositories' do
+ it 'allows repositories to round-trip with symbol keys' do
+ status = described_class.new(user)
+
+ status.save(repositories, 2)
+
+ expect(status.repositories).to eq(repositories)
+ end
+
+ it 'uses the fallback when there is nothing in Redis' do
+ fallback = { manifest_import_repositories: repositories }
+ status = described_class.new(user, fallback: fallback)
+
+ expect(status.repositories).to eq(repositories)
+ end
+ end
+
+ describe '#group_id' do
+ it 'returns the group ID as an integer' do
+ status = described_class.new(user)
+
+ status.save(repositories, 2)
+
+ expect(status.group_id).to eq(2)
+ end
+
+ it 'uses the fallback when there is nothing in Redis' do
+ fallback = { manifest_import_group_id: 3 }
+ status = described_class.new(user, fallback: fallback)
+
+ expect(status.group_id).to eq(3)
+ end
+ end
+end
diff --git a/spec/lib/gitlab/metrics/dashboard/importers/prometheus_metrics_spec.rb b/spec/lib/gitlab/metrics/dashboard/importers/prometheus_metrics_spec.rb
index 09d5e048f6a..ff8f5797f9d 100644
--- a/spec/lib/gitlab/metrics/dashboard/importers/prometheus_metrics_spec.rb
+++ b/spec/lib/gitlab/metrics/dashboard/importers/prometheus_metrics_spec.rb
@@ -8,9 +8,16 @@ RSpec.describe Gitlab::Metrics::Dashboard::Importers::PrometheusMetrics do
describe '#execute' do
let(:project) { create(:project) }
let(:dashboard_path) { 'path/to/dashboard.yml' }
+ let(:prometheus_adapter) { double('adapter', clear_prometheus_reactive_cache!: nil) }
subject { described_class.new(dashboard_hash, project: project, dashboard_path: dashboard_path) }
+ before do
+ allow_next_instance_of(::Clusters::Applications::ScheduleUpdateService) do |update_service|
+ allow(update_service).to receive(:execute)
+ end
+ end
+
context 'valid dashboard' do
let(:dashboard_hash) { load_sample_dashboard }
@@ -21,20 +28,32 @@ RSpec.describe Gitlab::Metrics::Dashboard::Importers::PrometheusMetrics do
end
context 'with existing metrics' do
+ let(:existing_metric_attributes) do
+ {
+ project: project,
+ identifier: 'metric_b',
+ title: 'overwrite',
+ y_label: 'overwrite',
+ query: 'overwrite',
+ unit: 'overwrite',
+ legend: 'overwrite',
+ dashboard_path: dashboard_path
+ }
+ end
+
let!(:existing_metric) do
- create(:prometheus_metric, {
- project: project,
- identifier: 'metric_b',
- title: 'overwrite',
- y_label: 'overwrite',
- query: 'overwrite',
- unit: 'overwrite',
- legend: 'overwrite'
- })
+ create(:prometheus_metric, existing_metric_attributes)
+ end
+
+ let!(:existing_alert) do
+ alert = create(:prometheus_alert, project: project, prometheus_metric: existing_metric)
+ existing_metric.prometheus_alerts << alert
+
+ alert
end
it 'updates existing PrometheusMetrics' do
- described_class.new(dashboard_hash, project: project, dashboard_path: dashboard_path).execute
+ subject.execute
expect(existing_metric.reload.attributes.with_indifferent_access).to include({
title: 'Super Chart B',
@@ -49,6 +68,15 @@ RSpec.describe Gitlab::Metrics::Dashboard::Importers::PrometheusMetrics do
expect { subject.execute }.to change { PrometheusMetric.count }.by(2)
end
+ it 'updates affected environments' do
+ expect(::Clusters::Applications::ScheduleUpdateService).to receive(:new).with(
+ existing_alert.environment.cluster_prometheus_adapter,
+ project
+ ).and_return(double('ScheduleUpdateService', execute: true))
+
+ subject.execute
+ end
+
context 'with stale metrics' do
let!(:stale_metric) do
create(:prometheus_metric,
@@ -59,11 +87,45 @@ RSpec.describe Gitlab::Metrics::Dashboard::Importers::PrometheusMetrics do
)
end
+ let!(:stale_alert) do
+ alert = create(:prometheus_alert, project: project, prometheus_metric: stale_metric)
+ stale_metric.prometheus_alerts << alert
+
+ alert
+ end
+
+ it 'updates existing PrometheusMetrics' do
+ subject.execute
+
+ expect(existing_metric.reload.attributes.with_indifferent_access).to include({
+ title: 'Super Chart B',
+ y_label: 'y_label',
+ query: 'query',
+ unit: 'unit',
+ legend: 'Legend Label'
+ })
+ end
+
it 'deletes stale metrics' do
subject.execute
expect { stale_metric.reload }.to raise_error(ActiveRecord::RecordNotFound)
end
+
+ it 'deletes stale alert' do
+ subject.execute
+
+ expect { stale_alert.reload }.to raise_error(ActiveRecord::RecordNotFound)
+ end
+
+ it 'updates affected environments' do
+ expect(::Clusters::Applications::ScheduleUpdateService).to receive(:new).with(
+ existing_alert.environment.cluster_prometheus_adapter,
+ project
+ ).and_return(double('ScheduleUpdateService', execute: true))
+
+ subject.execute
+ end
end
end
end
diff --git a/spec/lib/gitlab/metrics/requests_rack_middleware_spec.rb b/spec/lib/gitlab/metrics/requests_rack_middleware_spec.rb
index 69b779d36eb..631325402d9 100644
--- a/spec/lib/gitlab/metrics/requests_rack_middleware_spec.rb
+++ b/spec/lib/gitlab/metrics/requests_rack_middleware_spec.rb
@@ -22,7 +22,7 @@ RSpec.describe Gitlab::Metrics::RequestsRackMiddleware do
end
it 'increments requests count' do
- expect(described_class).to receive_message_chain(:http_request_total, :increment).with(method: 'get')
+ expect(described_class).to receive_message_chain(:http_request_total, :increment).with(method: 'get', status: 200, feature_category: 'unknown')
subject.call(env)
end
@@ -32,75 +32,55 @@ RSpec.describe Gitlab::Metrics::RequestsRackMiddleware do
end
it 'measures execution time' do
- expect(described_class).to receive_message_chain(:http_request_duration_seconds, :observe).with({ status: '200', method: 'get' }, a_positive_execution_time)
+ expect(described_class).to receive_message_chain(:http_request_duration_seconds, :observe).with({ method: 'get' }, a_positive_execution_time)
Timecop.scale(3600) { subject.call(env) }
end
context 'request is a health check endpoint' do
- it 'increments health endpoint counter' do
- env['PATH_INFO'] = '/-/liveness'
+ ['/-/liveness', '/-/liveness/', '/-/%6D%65%74%72%69%63%73'].each do |path|
+ context "when path is #{path}" do
+ before do
+ env['PATH_INFO'] = path
+ end
- expect(described_class).to receive_message_chain(:http_health_requests_total, :increment).with(method: 'get')
+ it 'increments health endpoint counter rather than overall counter' do
+ expect(described_class).to receive_message_chain(:http_health_requests_total, :increment).with(method: 'get', status: 200)
+ expect(described_class).not_to receive(:http_request_total)
- subject.call(env)
- end
-
- context 'with trailing slash' do
- before do
- env['PATH_INFO'] = '/-/liveness/'
- end
-
- it 'increments health endpoint counter' do
- expect(described_class).to receive_message_chain(:http_health_requests_total, :increment).with(method: 'get')
-
- subject.call(env)
- end
- end
-
- context 'with percent encoded values' do
- before do
- env['PATH_INFO'] = '/-/%6D%65%74%72%69%63%73' # /-/metrics
- end
+ subject.call(env)
+ end
- it 'increments health endpoint counter' do
- expect(described_class).to receive_message_chain(:http_health_requests_total, :increment).with(method: 'get')
+ it 'does not record the request duration' do
+ expect(described_class).not_to receive(:http_request_duration_seconds)
- subject.call(env)
+ subject.call(env)
+ end
end
end
end
context 'request is not a health check endpoint' do
- it 'does not increment health endpoint counter' do
- env['PATH_INFO'] = '/-/ordinary-requests'
-
- expect(described_class).not_to receive(:http_health_requests_total)
-
- subject.call(env)
- end
-
- context 'path info is a root path' do
- before do
- env['PATH_INFO'] = '/-/'
- end
-
- it 'does not increment health endpoint counter' do
- expect(described_class).not_to receive(:http_health_requests_total)
-
- subject.call(env)
- end
- end
-
- context 'path info is a subpath' do
- before do
- env['PATH_INFO'] = '/-/health/subpath'
- end
-
- it 'does not increment health endpoint counter' do
- expect(described_class).not_to receive(:http_health_requests_total)
-
- subject.call(env)
+ ['/-/ordinary-requests', '/-/', '/-/health/subpath'].each do |path|
+ context "when path is #{path}" do
+ before do
+ env['PATH_INFO'] = path
+ end
+
+ it 'increments overall counter rather than health endpoint counter' do
+ expect(described_class).to receive_message_chain(:http_request_total, :increment).with(method: 'get', status: 200, feature_category: 'unknown')
+ expect(described_class).not_to receive(:http_health_requests_total)
+
+ subject.call(env)
+ end
+
+ it 'records the request duration' do
+ expect(described_class)
+ .to receive_message_chain(:http_request_duration_seconds, :observe)
+ .with({ method: 'get' }, a_positive_execution_time)
+
+ subject.call(env)
+ end
end
end
end
@@ -121,7 +101,7 @@ RSpec.describe Gitlab::Metrics::RequestsRackMiddleware do
end
it 'increments requests count' do
- expect(described_class).to receive_message_chain(:http_request_total, :increment).with(method: 'get')
+ expect(described_class).to receive_message_chain(:http_request_total, :increment).with(method: 'get', status: 'undefined', feature_category: 'unknown')
expect { subject.call(env) }.to raise_error(StandardError)
end
@@ -133,13 +113,32 @@ RSpec.describe Gitlab::Metrics::RequestsRackMiddleware do
end
end
+ context 'when a feature category header is present' do
+ before do
+ allow(app).to receive(:call).and_return([200, { described_class::FEATURE_CATEGORY_HEADER => 'issue_tracking' }, nil])
+ end
+
+ it 'adds the feature category to the labels for http_request_total' do
+ expect(described_class).to receive_message_chain(:http_request_total, :increment).with(method: 'get', status: 200, feature_category: 'issue_tracking')
+
+ subject.call(env)
+ end
+
+ it 'does not record a feature category for health check endpoints' do
+ env['PATH_INFO'] = '/-/liveness'
+
+ expect(described_class).to receive_message_chain(:http_health_requests_total, :increment).with(method: 'get', status: 200)
+ expect(described_class).not_to receive(:http_request_total)
+
+ subject.call(env)
+ end
+ end
+
describe '.initialize_http_request_duration_seconds' do
it "sets labels" do
expected_labels = []
- described_class::HTTP_METHODS.each do |method, statuses|
- statuses.each do |status|
- expected_labels << { method: method, status: status.to_s }
- end
+ described_class::HTTP_METHODS.each do |method|
+ expected_labels << { method: method }
end
described_class.initialize_http_request_duration_seconds
diff --git a/spec/lib/gitlab/middleware/go_spec.rb b/spec/lib/gitlab/middleware/go_spec.rb
index 1fffef53a82..7bac041cd65 100644
--- a/spec/lib/gitlab/middleware/go_spec.rb
+++ b/spec/lib/gitlab/middleware/go_spec.rb
@@ -135,6 +135,17 @@ RSpec.describe Gitlab::Middleware::Go do
it_behaves_like 'unauthorized'
end
+
+ context 'with a blacklisted ip' do
+ it 'returns forbidden' do
+ expect(Gitlab::Auth).to receive(:find_for_git_client).and_raise(Gitlab::Auth::IpBlacklisted)
+ response = go
+
+ expect(response[0]).to eq(403)
+ expect(response[1]['Content-Length']).to be_nil
+ expect(response[2]).to eq([''])
+ end
+ end
end
end
end
@@ -176,10 +187,11 @@ RSpec.describe Gitlab::Middleware::Go do
it 'returns 404' do
response = go
+
expect(response[0]).to eq(404)
expect(response[1]['Content-Type']).to eq('text/html')
expected_body = %{<html><body>go get #{Gitlab.config.gitlab.url}/#{project.full_path}</body></html>}
- expect(response[2].body).to eq([expected_body])
+ expect(response[2]).to eq([expected_body])
end
end
@@ -251,7 +263,7 @@ RSpec.describe Gitlab::Middleware::Go do
expect(response[0]).to eq(200)
expect(response[1]['Content-Type']).to eq('text/html')
expected_body = %{<html><head><meta name="go-import" content="#{Gitlab.config.gitlab.host}/#{path} git #{repository_url}" /><meta name="go-source" content="#{Gitlab.config.gitlab.host}/#{path} #{project_url} #{project_url}/-/tree/#{branch}{/dir} #{project_url}/-/blob/#{branch}{/dir}/{file}#L{line}" /></head><body>go get #{Gitlab.config.gitlab.url}/#{path}</body></html>}
- expect(response[2].body).to eq([expected_body])
+ expect(response[2]).to eq([expected_body])
end
end
end
diff --git a/spec/lib/gitlab/middleware/handle_null_bytes_spec.rb b/spec/lib/gitlab/middleware/handle_null_bytes_spec.rb
new file mode 100644
index 00000000000..76a5174817e
--- /dev/null
+++ b/spec/lib/gitlab/middleware/handle_null_bytes_spec.rb
@@ -0,0 +1,88 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require "rack/test"
+
+RSpec.describe Gitlab::Middleware::HandleNullBytes do
+ let(:null_byte) { "\u0000" }
+ let(:error_400) { [400, {}, ["Bad Request"]] }
+ let(:app) { double(:app) }
+
+ subject { described_class.new(app) }
+
+ before do
+ allow(app).to receive(:call) do |args|
+ args
+ end
+ end
+
+ def env_for(params = {})
+ Rack::MockRequest.env_for('/', { params: params })
+ end
+
+ context 'with null bytes in params' do
+ it 'rejects null bytes in a top level param' do
+ env = env_for(name: "null#{null_byte}byte")
+
+ expect(subject.call(env)).to eq error_400
+ end
+
+ it "responds with 400 BadRequest for hashes with strings" do
+ env = env_for(name: { inner_key: "I am #{null_byte} bad" })
+
+ expect(subject.call(env)).to eq error_400
+ end
+
+ it "responds with 400 BadRequest for arrays with strings" do
+ env = env_for(name: ["I am #{null_byte} bad"])
+
+ expect(subject.call(env)).to eq error_400
+ end
+
+ it "responds with 400 BadRequest for arrays containing hashes with string values" do
+ env = env_for(name: [
+ {
+ inner_key: "I am #{null_byte} bad"
+ }
+ ])
+
+ expect(subject.call(env)).to eq error_400
+ end
+
+ it "gives up and does not 400 with too deeply nested params" do
+ env = env_for(name: [
+ {
+ inner_key: { deeper_key: [{ hash_inside_array_key: "I am #{null_byte} bad" }] }
+ }
+ ])
+
+ expect(subject.call(env)).not_to eq error_400
+ end
+ end
+
+ context 'without null bytes in params' do
+ it "does not respond with a 400 for strings" do
+ env = env_for(name: "safe name")
+
+ expect(subject.call(env)).not_to eq error_400
+ end
+
+ it "does not respond with a 400 with no params" do
+ env = env_for
+
+ expect(subject.call(env)).not_to eq error_400
+ end
+ end
+
+ context 'when disabled via env flag' do
+ before do
+ stub_env('REJECT_NULL_BYTES', '1')
+ end
+
+ it 'does not respond with a 400 no matter what' do
+ env = env_for(name: "null#{null_byte}byte")
+
+ expect(subject.call(env)).not_to eq error_400
+ end
+ end
+end
diff --git a/spec/lib/gitlab/middleware/rails_queue_duration_spec.rb b/spec/lib/gitlab/middleware/rails_queue_duration_spec.rb
index cdb48024531..a9dae72f4db 100644
--- a/spec/lib/gitlab/middleware/rails_queue_duration_spec.rb
+++ b/spec/lib/gitlab/middleware/rails_queue_duration_spec.rb
@@ -38,7 +38,7 @@ RSpec.describe Gitlab::Middleware::RailsQueueDuration do
expect(transaction).to receive(:observe).with(:gitlab_rails_queue_duration_seconds, 1)
- Timecop.freeze(Time.at(3)) do
+ travel_to(Time.at(3)) do
expect(middleware.call(env)).to eq('yay')
end
end
diff --git a/spec/lib/gitlab/middleware/same_site_cookies_spec.rb b/spec/lib/gitlab/middleware/same_site_cookies_spec.rb
index 2d1a9b2eee2..18342fd78ac 100644
--- a/spec/lib/gitlab/middleware/same_site_cookies_spec.rb
+++ b/spec/lib/gitlab/middleware/same_site_cookies_spec.rb
@@ -60,12 +60,12 @@ RSpec.describe Gitlab::Middleware::SameSiteCookies do
end
context 'with no cookies' do
- let(:cookies) { nil }
+ let(:cookies) { "" }
it 'does not add headers' do
response = do_request
- expect(response['Set-Cookie']).to be_nil
+ expect(response['Set-Cookie']).to eq("")
end
end
diff --git a/spec/lib/gitlab/pagination/offset_pagination_spec.rb b/spec/lib/gitlab/pagination/offset_pagination_spec.rb
index be20f0194f7..c9a23170137 100644
--- a/spec/lib/gitlab/pagination/offset_pagination_spec.rb
+++ b/spec/lib/gitlab/pagination/offset_pagination_spec.rb
@@ -13,7 +13,7 @@ RSpec.describe Gitlab::Pagination::OffsetPagination do
let(:request_context) { double("request_context") }
- subject do
+ subject(:paginator) do
described_class.new(request_context)
end
@@ -119,6 +119,34 @@ RSpec.describe Gitlab::Pagination::OffsetPagination do
subject.paginate(resource)
end
end
+
+ it 'does not return the total headers when excluding them' do
+ expect_no_header('X-Total')
+ expect_no_header('X-Total-Pages')
+ expect_header('X-Per-Page', '2')
+ expect_header('X-Page', '1')
+
+ paginator.paginate(resource, exclude_total_headers: true)
+ end
+ end
+
+ context 'when resource is a paginatable array' do
+ let(:resource) { Kaminari.paginate_array(Project.all.to_a) }
+
+ it_behaves_like 'response with pagination headers'
+
+ it 'only returns the requested resources' do
+ expect(paginator.paginate(resource).count).to eq(2)
+ end
+
+ it 'does not return total headers when excluding them' do
+ expect_no_header('X-Total')
+ expect_no_header('X-Total-Pages')
+ expect_header('X-Per-Page', '2')
+ expect_header('X-Page', '1')
+
+ paginator.paginate(resource, exclude_total_headers: true)
+ end
end
end
diff --git a/spec/lib/gitlab/project_search_results_spec.rb b/spec/lib/gitlab/project_search_results_spec.rb
index fe0735b8043..a76ad1f6f4c 100644
--- a/spec/lib/gitlab/project_search_results_spec.rb
+++ b/spec/lib/gitlab/project_search_results_spec.rb
@@ -265,9 +265,15 @@ RSpec.describe Gitlab::ProjectSearchResults do
let_it_be(:project) { create(:project, :public) }
let_it_be(:closed_result) { create(:issue, :closed, project: project, title: 'foo closed') }
let_it_be(:opened_result) { create(:issue, :opened, project: project, title: 'foo opened') }
+ let_it_be(:confidential_result) { create(:issue, :confidential, project: project, title: 'foo confidential') }
let(:query) { 'foo' }
+ before do
+ project.add_developer(user)
+ end
+
include_examples 'search results filtered by state'
+ include_examples 'search results filtered by confidential'
end
end
diff --git a/spec/lib/gitlab/project_template_spec.rb b/spec/lib/gitlab/project_template_spec.rb
index fa45c605b1b..98bd2efdbc6 100644
--- a/spec/lib/gitlab/project_template_spec.rb
+++ b/spec/lib/gitlab/project_template_spec.rb
@@ -8,9 +8,9 @@ RSpec.describe Gitlab::ProjectTemplate do
expected = %w[
rails spring express iosswift dotnetcore android
gomicro gatsby hugo jekyll plainhtml gitbook
- hexo sse_middleman nfhugo nfjekyll nfplainhtml
- nfgitbook nfhexo salesforcedx serverless_framework
- jsonnet cluster_management
+ hexo sse_middleman gitpod_spring_petclinic nfhugo
+ nfjekyll nfplainhtml nfgitbook nfhexo salesforcedx
+ serverless_framework jsonnet cluster_management
]
expect(described_class.all).to be_an(Array)
diff --git a/spec/lib/gitlab/prometheus/queries/additional_metrics_deployment_query_spec.rb b/spec/lib/gitlab/prometheus/queries/additional_metrics_deployment_query_spec.rb
index 8abc944eeb1..b2350eff9f9 100644
--- a/spec/lib/gitlab/prometheus/queries/additional_metrics_deployment_query_spec.rb
+++ b/spec/lib/gitlab/prometheus/queries/additional_metrics_deployment_query_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe Gitlab::Prometheus::Queries::AdditionalMetricsDeploymentQuery do
around do |example|
- Timecop.freeze(Time.local(2008, 9, 1, 12, 0, 0)) { example.run }
+ travel_to(Time.local(2008, 9, 1, 12, 0, 0)) { example.run }
end
include_examples 'additional metrics query' do
diff --git a/spec/lib/gitlab/prometheus/queries/deployment_query_spec.rb b/spec/lib/gitlab/prometheus/queries/deployment_query_spec.rb
index 4683c4eae28..66b93d0dd72 100644
--- a/spec/lib/gitlab/prometheus/queries/deployment_query_spec.rb
+++ b/spec/lib/gitlab/prometheus/queries/deployment_query_spec.rb
@@ -11,7 +11,7 @@ RSpec.describe Gitlab::Prometheus::Queries::DeploymentQuery do
around do |example|
time_without_subsecond_values = Time.local(2008, 9, 1, 12, 0, 0)
- Timecop.freeze(time_without_subsecond_values) { example.run }
+ travel_to(time_without_subsecond_values) { example.run }
end
it 'sends appropriate queries to prometheus' do
diff --git a/spec/lib/gitlab/prometheus/query_variables_spec.rb b/spec/lib/gitlab/prometheus/query_variables_spec.rb
index 1422d48152a..1dbdb892a5d 100644
--- a/spec/lib/gitlab/prometheus/query_variables_spec.rb
+++ b/spec/lib/gitlab/prometheus/query_variables_spec.rb
@@ -4,12 +4,12 @@ require 'spec_helper'
RSpec.describe Gitlab::Prometheus::QueryVariables do
describe '.call' do
+ let_it_be_with_refind(:environment) { create(:environment) }
let(:project) { environment.project }
- let(:environment) { create(:environment) }
let(:slug) { environment.slug }
let(:params) { {} }
- subject { described_class.call(environment, params) }
+ subject { described_class.call(environment, **params) }
it { is_expected.to include(ci_environment_slug: slug) }
it { is_expected.to include(ci_project_name: project.name) }
diff --git a/spec/lib/gitlab/redis/hll_spec.rb b/spec/lib/gitlab/redis/hll_spec.rb
index cbf78f23036..e452e5b2f52 100644
--- a/spec/lib/gitlab/redis/hll_spec.rb
+++ b/spec/lib/gitlab/redis/hll_spec.rb
@@ -39,6 +39,24 @@ RSpec.describe Gitlab::Redis::HLL, :clean_gitlab_redis_shared_state do
end
end
end
+
+ context 'when adding entries' do
+ let(:metric) { 'test-{metric}' }
+
+ it 'supports single value' do
+ track_event(metric, 1)
+
+ expect(count_unique_events([metric])).to eq(1)
+ end
+
+ it 'supports multiple values' do
+ stub_const("#{described_class.name}::HLL_BATCH_SIZE", 2)
+
+ track_event(metric, [1, 2, 3, 4, 5])
+
+ expect(count_unique_events([metric])).to eq(5)
+ end
+ end
end
describe '.count' do
@@ -94,13 +112,13 @@ RSpec.describe Gitlab::Redis::HLL, :clean_gitlab_redis_shared_state do
expect(unique_counts).to eq(4)
end
+ end
- def track_event(key, value, expiry = 1.day)
- described_class.add(key: key, value: value, expiry: expiry)
- end
+ def track_event(key, value, expiry = 1.day)
+ described_class.add(key: key, value: value, expiry: expiry)
+ end
- def count_unique_events(keys)
- described_class.count(keys: keys)
- end
+ def count_unique_events(keys)
+ described_class.count(keys: keys)
end
end
diff --git a/spec/lib/gitlab/regex_spec.rb b/spec/lib/gitlab/regex_spec.rb
index 88c3315150b..1c56e489a94 100644
--- a/spec/lib/gitlab/regex_spec.rb
+++ b/spec/lib/gitlab/regex_spec.rb
@@ -99,6 +99,36 @@ RSpec.describe Gitlab::Regex do
it { is_expected.not_to match('foo-') }
end
+ describe '.build_trace_section_regex' do
+ subject { described_class.build_trace_section_regex }
+
+ context 'without options' do
+ example = "section_start:1600445393032:NAME\r\033\[0K"
+
+ it { is_expected.to match(example) }
+ it { is_expected.to match("section_end:12345678:aBcDeFg1234\r\033\[0K") }
+ it { is_expected.to match("section_start:0:sect_for_alpha-v1.0\r\033\[0K") }
+ it { is_expected.not_to match("section_start:section:0\r\033\[0K") }
+ it { is_expected.not_to match("section_:1600445393032:NAME\r\033\[0K") }
+ it { is_expected.not_to match(example.upcase) }
+ end
+
+ context 'with options' do
+ it { is_expected.to match("section_start:1600445393032:NAME[collapsed=true]\r\033\[0K") }
+ it { is_expected.to match("section_start:1600445393032:NAME[collapsed=true, example_option=false]\r\033\[0K") }
+ it { is_expected.to match("section_start:1600445393032:NAME[collapsed=true,example_option=false]\r\033\[0K") }
+ it { is_expected.to match("section_start:1600445393032:NAME[numeric_option=1234567]\r\033\[0K") }
+ # Without splitting the regex in one for start and one for end,
+ # this is possible, however, it is ignored for section_end.
+ it { is_expected.to match("section_end:1600445393032:NAME[collapsed=true]\r\033\[0K") }
+ it { is_expected.not_to match("section_start:1600445393032:NAME[collapsed=[]]]\r\033\[0K") }
+ it { is_expected.not_to match("section_start:1600445393032:NAME[collapsed = true]\r\033\[0K") }
+ it { is_expected.not_to match("section_start:1600445393032:NAME[collapsed = true, example_option=false]\r\033\[0K") }
+ it { is_expected.not_to match("section_start:1600445393032:NAME[collapsed=true, example_option=false]\r\033\[0K") }
+ it { is_expected.not_to match("section_start:1600445393032:NAME[]\r\033\[0K") }
+ end
+ end
+
describe '.container_repository_name_regex' do
subject { described_class.container_repository_name_regex }
@@ -317,6 +347,22 @@ RSpec.describe Gitlab::Regex do
it { is_expected.not_to match('%2e%2e%2f1.2.3') }
end
+ describe '.nuget_version_regex' do
+ subject { described_class.nuget_version_regex }
+
+ it { is_expected.to match('1.2.3') }
+ it { is_expected.to match('1.2.3.4') }
+ it { is_expected.to match('1.2.3.4-stable.1') }
+ it { is_expected.to match('1.2.3-beta') }
+ it { is_expected.to match('1.2.3-alpha.3') }
+ it { is_expected.to match('1.0.7+r3456') }
+ it { is_expected.not_to match('1') }
+ it { is_expected.not_to match('1.2') }
+ it { is_expected.not_to match('1./2.3') }
+ it { is_expected.not_to match('../../../../../1.2.3') }
+ it { is_expected.not_to match('%2e%2e%2f1.2.3') }
+ end
+
describe '.pypi_version_regex' do
subject { described_class.pypi_version_regex }
@@ -384,6 +430,140 @@ RSpec.describe Gitlab::Regex do
it { is_expected.not_to match('%2e%2e%2f1.2.3') }
end
+ describe '.debian_package_name_regex' do
+ subject { described_class.debian_package_name_regex }
+
+ it { is_expected.to match('0ad') }
+ it { is_expected.to match('g++') }
+ it { is_expected.to match('lua5.1') }
+ it { is_expected.to match('samba') }
+
+ # may not be empty string
+ it { is_expected.not_to match('') }
+ # must start with an alphanumeric character
+ it { is_expected.not_to match('-a') }
+ it { is_expected.not_to match('+a') }
+ it { is_expected.not_to match('.a') }
+ it { is_expected.not_to match('_a') }
+ # only letters, digits and characters '-+._'
+ it { is_expected.not_to match('a~') }
+ it { is_expected.not_to match('aé') }
+
+ # More strict Lintian regex
+ # at least 2 chars
+ it { is_expected.not_to match('a') }
+ # lowercase only
+ it { is_expected.not_to match('Aa') }
+ it { is_expected.not_to match('aA') }
+ # No underscore
+ it { is_expected.not_to match('a_b') }
+ end
+
+ describe '.debian_version_regex' do
+ subject { described_class.debian_version_regex }
+
+ context 'valid versions' do
+ it { is_expected.to match('1.0') }
+ it { is_expected.to match('1.0~alpha1') }
+ it { is_expected.to match('2:4.9.5+dfsg-5+deb10u1') }
+ end
+
+ context 'dpkg errors' do
+ # version string is empty
+ it { is_expected.not_to match('') }
+ # version string has embedded spaces
+ it { is_expected.not_to match('1 0') }
+ # epoch in version is empty
+ it { is_expected.not_to match(':1.0') }
+ # epoch in version is not number
+ it { is_expected.not_to match('a:1.0') }
+ # epoch in version is negative
+ it { is_expected.not_to match('-1:1.0') }
+ # epoch in version is too big
+ it { is_expected.not_to match('9999999999:1.0') }
+ # nothing after colon in version number
+ it { is_expected.not_to match('2:') }
+ # revision number is empty
+ # Note: we are less strict here
+ # it { is_expected.not_to match('1.0-') }
+ # version number is empty
+ it { is_expected.not_to match('-1') }
+ it { is_expected.not_to match('2:-1') }
+ end
+
+ context 'dpkg warnings' do
+ # version number does not start with digit
+ it { is_expected.not_to match('a') }
+ it { is_expected.not_to match('a1.0') }
+ # invalid character in version number
+ it { is_expected.not_to match('1_0') }
+ # invalid character in revision number
+ it { is_expected.not_to match('1.0-1_0') }
+ end
+
+ context 'dpkg accepts' do
+ # dpkg accepts leading or trailing space
+ it { is_expected.not_to match(' 1.0') }
+ it { is_expected.not_to match('1.0 ') }
+ # dpkg accepts multiple colons
+ it { is_expected.not_to match('1:2:3') }
+ end
+ end
+
+ describe '.debian_architecture_regex' do
+ subject { described_class.debian_architecture_regex }
+
+ it { is_expected.to match('amd64') }
+ it { is_expected.to match('kfreebsd-i386') }
+
+ # may not be empty string
+ it { is_expected.not_to match('') }
+ # must start with an alphanumeric
+ it { is_expected.not_to match('-a') }
+ it { is_expected.not_to match('+a') }
+ it { is_expected.not_to match('.a') }
+ it { is_expected.not_to match('_a') }
+ # only letters, digits and characters '-'
+ it { is_expected.not_to match('a+b') }
+ it { is_expected.not_to match('a.b') }
+ it { is_expected.not_to match('a_b') }
+ it { is_expected.not_to match('a~') }
+ it { is_expected.not_to match('aé') }
+
+ # More strict
+ # Enforce lowercase
+ it { is_expected.not_to match('AMD64') }
+ it { is_expected.not_to match('Amd64') }
+ it { is_expected.not_to match('aMD64') }
+ end
+
+ describe '.debian_distribution_regex' do
+ subject { described_class.debian_distribution_regex }
+
+ it { is_expected.to match('buster') }
+ it { is_expected.to match('buster-updates') }
+ it { is_expected.to match('Debian10.5') }
+
+ # Do not allow slash, even if this exists in the wild
+ it { is_expected.not_to match('jessie/updates') }
+
+ # Do not allow Unicode
+ it { is_expected.not_to match('hé') }
+ end
+
+ describe '.debian_component_regex' do
+ subject { described_class.debian_component_regex }
+
+ it { is_expected.to match('main') }
+ it { is_expected.to match('non-free') }
+
+ # Do not allow slash
+ it { is_expected.not_to match('non/free') }
+
+ # Do not allow Unicode
+ it { is_expected.not_to match('hé') }
+ end
+
describe '.semver_regex' do
subject { described_class.semver_regex }
@@ -434,4 +614,45 @@ RSpec.describe Gitlab::Regex do
it { is_expected.not_to match('%2e%2e%2f1.2.3') }
it { is_expected.not_to match('') }
end
+
+ describe '.generic_package_name_regex' do
+ subject { described_class.generic_package_name_regex }
+
+ it { is_expected.to match('123') }
+ it { is_expected.to match('foo') }
+ it { is_expected.to match('foo.bar.baz-2.0-20190901.47283-1') }
+ it { is_expected.not_to match('../../foo') }
+ it { is_expected.not_to match('..\..\foo') }
+ it { is_expected.not_to match('%2f%2e%2e%2f%2essh%2fauthorized_keys') }
+ it { is_expected.not_to match('$foo/bar') }
+ it { is_expected.not_to match('my file name') }
+ it { is_expected.not_to match('!!()()') }
+ end
+
+ describe '.generic_package_file_name_regex' do
+ subject { described_class.generic_package_file_name_regex }
+
+ it { is_expected.to match('123') }
+ it { is_expected.to match('foo') }
+ it { is_expected.to match('foo.bar.baz-2.0-20190901.47283-1.jar') }
+ it { is_expected.not_to match('../../foo') }
+ it { is_expected.not_to match('..\..\foo') }
+ it { is_expected.not_to match('%2f%2e%2e%2f%2essh%2fauthorized_keys') }
+ it { is_expected.not_to match('$foo/bar') }
+ it { is_expected.not_to match('my file name') }
+ it { is_expected.not_to match('!!()()') }
+ end
+
+ describe '.prefixed_semver_regex' do
+ subject { described_class.prefixed_semver_regex }
+
+ it { is_expected.to match('v1.2.3') }
+ it { is_expected.to match('v1.2.3-beta') }
+ it { is_expected.to match('v1.2.3-alpha.3') }
+ it { is_expected.not_to match('v1') }
+ it { is_expected.not_to match('v1.2') }
+ it { is_expected.not_to match('v1./2.3') }
+ it { is_expected.not_to match('v../../../../../1.2.3') }
+ it { is_expected.not_to match('v%2e%2e%2f1.2.3') }
+ end
end
diff --git a/spec/lib/gitlab/relative_positioning/mover_spec.rb b/spec/lib/gitlab/relative_positioning/mover_spec.rb
index c49230c2415..dafd34585a8 100644
--- a/spec/lib/gitlab/relative_positioning/mover_spec.rb
+++ b/spec/lib/gitlab/relative_positioning/mover_spec.rb
@@ -37,18 +37,11 @@ RSpec.describe RelativePositioning::Mover do
end
def set_positions(positions)
- vals = issues.zip(positions).map do |issue, pos|
- issue.relative_position = pos
- "(#{issue.id}, #{pos})"
- end.join(', ')
-
- Issue.connection.exec_query(<<~SQL, 'set-positions')
- WITH cte(cte_id, new_pos) AS (
- SELECT * FROM (VALUES #{vals}) as t (id, pos)
- )
- UPDATE issues SET relative_position = new_pos FROM cte WHERE id = cte_id
- ;
- SQL
+ mapping = issues.zip(positions).to_h do |issue, pos|
+ [issue, { relative_position: pos }]
+ end
+
+ ::Gitlab::Database::BulkUpdate.execute([:relative_position], mapping)
end
def ids_in_position_order
diff --git a/spec/lib/gitlab/repo_path_spec.rb b/spec/lib/gitlab/repo_path_spec.rb
index 05f32459164..912efa6a5db 100644
--- a/spec/lib/gitlab/repo_path_spec.rb
+++ b/spec/lib/gitlab/repo_path_spec.rb
@@ -18,7 +18,7 @@ RSpec.describe ::Gitlab::RepoPath do
end
it 'parses a full wiki project path' do
- expect(described_class.parse(project.wiki.repository.full_path)).to eq([project, project, Gitlab::GlRepository::WIKI, nil])
+ expect(described_class.parse(project.wiki.repository.full_path)).to eq([project.wiki, project, Gitlab::GlRepository::WIKI, nil])
end
it 'parses a personal snippet repository path' do
@@ -36,7 +36,7 @@ RSpec.describe ::Gitlab::RepoPath do
end
it 'parses a relative wiki path' do
- expect(described_class.parse(project.full_path + '.wiki.git')).to eq([project, project, Gitlab::GlRepository::WIKI, nil])
+ expect(described_class.parse(project.full_path + '.wiki.git')).to eq([project.wiki, project, Gitlab::GlRepository::WIKI, nil])
end
it 'parses a relative path starting with /' do
@@ -49,7 +49,7 @@ RSpec.describe ::Gitlab::RepoPath do
end
it 'parses a relative wiki path' do
- expect(described_class.parse(redirect.path + '.wiki.git')).to eq([project, project, Gitlab::GlRepository::WIKI, redirect_route])
+ expect(described_class.parse(redirect.path + '.wiki.git')).to eq([project.wiki, project, Gitlab::GlRepository::WIKI, redirect_route])
end
it 'parses a relative path starting with /' do
diff --git a/spec/lib/gitlab/repository_size_checker_spec.rb b/spec/lib/gitlab/repository_size_checker_spec.rb
index 9b2c02b1190..bd030d81d97 100644
--- a/spec/lib/gitlab/repository_size_checker_spec.rb
+++ b/spec/lib/gitlab/repository_size_checker_spec.rb
@@ -3,14 +3,16 @@
require 'spec_helper'
RSpec.describe Gitlab::RepositorySizeChecker do
+ let_it_be(:namespace) { nil }
let(:current_size) { 0 }
let(:limit) { 50 }
let(:enabled) { true }
subject do
described_class.new(
- current_size_proc: -> { current_size },
- limit: limit,
+ current_size_proc: -> { current_size.megabytes },
+ limit: limit.megabytes,
+ namespace: namespace,
enabled: enabled
)
end
@@ -18,7 +20,7 @@ RSpec.describe Gitlab::RepositorySizeChecker do
describe '#enabled?' do
context 'when enabled' do
it 'returns true' do
- expect(subject.enabled?).to be_truthy
+ expect(subject.enabled?).to eq(true)
end
end
@@ -26,7 +28,7 @@ RSpec.describe Gitlab::RepositorySizeChecker do
let(:limit) { 0 }
it 'returns false' do
- expect(subject.enabled?).to be_falsey
+ expect(subject.enabled?).to eq(false)
end
end
end
@@ -35,59 +37,20 @@ RSpec.describe Gitlab::RepositorySizeChecker do
let(:current_size) { 49 }
it 'returns true when changes go over' do
- expect(subject.changes_will_exceed_size_limit?(2)).to be_truthy
+ expect(subject.changes_will_exceed_size_limit?(2.megabytes)).to eq(true)
end
it 'returns false when changes do not go over' do
- expect(subject.changes_will_exceed_size_limit?(1)).to be_falsey
+ expect(subject.changes_will_exceed_size_limit?(1.megabytes)).to eq(false)
end
end
describe '#above_size_limit?' do
- context 'when size is above the limit' do
- let(:current_size) { 100 }
-
- it 'returns true' do
- expect(subject.above_size_limit?).to be_truthy
- end
- end
-
- it 'returns false when not over the limit' do
- expect(subject.above_size_limit?).to be_falsey
- end
+ include_examples 'checker size above limit'
+ include_examples 'checker size not over limit'
end
describe '#exceeded_size' do
- context 'when current size is below or equal to the limit' do
- let(:current_size) { 50 }
-
- it 'returns zero' do
- expect(subject.exceeded_size).to eq(0)
- end
- end
-
- context 'when current size is over the limit' do
- let(:current_size) { 51 }
-
- it 'returns zero' do
- expect(subject.exceeded_size).to eq(1)
- end
- end
-
- context 'when change size will be over the limit' do
- let(:current_size) { 50 }
-
- it 'returns zero' do
- expect(subject.exceeded_size(1)).to eq(1)
- end
- end
-
- context 'when change size will not be over the limit' do
- let(:current_size) { 49 }
-
- it 'returns zero' do
- expect(subject.exceeded_size(1)).to eq(0)
- end
- end
+ include_examples 'checker size exceeded'
end
end
diff --git a/spec/lib/gitlab/repository_size_error_message_spec.rb b/spec/lib/gitlab/repository_size_error_message_spec.rb
index b6b975143c9..53b5ed5518f 100644
--- a/spec/lib/gitlab/repository_size_error_message_spec.rb
+++ b/spec/lib/gitlab/repository_size_error_message_spec.rb
@@ -3,9 +3,11 @@
require 'spec_helper'
RSpec.describe Gitlab::RepositorySizeErrorMessage do
+ let_it_be(:namespace) { build(:namespace) }
let(:checker) do
Gitlab::RepositorySizeChecker.new(
current_size_proc: -> { 15.megabytes },
+ namespace: namespace,
limit: 10.megabytes
)
end
@@ -13,6 +15,10 @@ RSpec.describe Gitlab::RepositorySizeErrorMessage do
let(:message) { checker.error_message }
let(:base_message) { 'because this repository has exceeded its size limit of 10 MB by 5 MB' }
+ before do
+ allow(namespace).to receive(:total_repository_size_excess).and_return(0)
+ end
+
describe 'error messages' do
describe '#commit_error' do
it 'returns the correct message' do
diff --git a/spec/lib/gitlab/sample_data_template_spec.rb b/spec/lib/gitlab/sample_data_template_spec.rb
new file mode 100644
index 00000000000..7d0d415b3af
--- /dev/null
+++ b/spec/lib/gitlab/sample_data_template_spec.rb
@@ -0,0 +1,66 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::SampleDataTemplate do
+ describe '.all' do
+ it 'returns all templates' do
+ expected = %w[
+ basic
+ serenity_valley
+ ]
+
+ expect(described_class.all).to be_an(Array)
+ expect(described_class.all.map(&:name)).to match_array(expected)
+ end
+ end
+
+ describe '.find' do
+ subject { described_class.find(query) }
+
+ context 'when there is a match' do
+ let(:query) { :basic }
+
+ it { is_expected.to be_a(described_class) }
+ end
+
+ context 'when there is no match' do
+ let(:query) { 'no-match' }
+
+ it { is_expected.to be(nil) }
+ end
+ end
+
+ describe '.archive_directory' do
+ subject { described_class.archive_directory }
+
+ it { is_expected.to be_a Pathname }
+ end
+
+ describe 'validate all templates' do
+ let_it_be(:admin) { create(:admin) }
+
+ described_class.all.each do |template|
+ it "#{template.name} has a valid archive" do
+ archive = template.archive_path
+
+ expect(File.exist?(archive)).to be(true)
+ end
+
+ context 'with valid parameters' do
+ it 'can be imported' do
+ params = {
+ template_name: template.name,
+ namespace_id: admin.namespace.id,
+ path: template.name
+ }
+
+ project = Projects::CreateFromTemplateService.new(admin, params).execute
+
+ expect(project).to be_valid
+ expect(project).to be_persisted
+ end
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/search/recent_issues_spec.rb b/spec/lib/gitlab/search/recent_issues_spec.rb
index 19a41d2aa38..c6d93173dc0 100644
--- a/spec/lib/gitlab/search/recent_issues_spec.rb
+++ b/spec/lib/gitlab/search/recent_issues_spec.rb
@@ -3,8 +3,10 @@
require 'spec_helper'
RSpec.describe ::Gitlab::Search::RecentIssues do
- def create_item(content:, project:)
- create(:issue, title: content, project: project)
+ let(:parent_type) { :project }
+
+ def create_item(content:, parent:)
+ create(:issue, title: content, project: parent)
end
it_behaves_like 'search recent items'
diff --git a/spec/lib/gitlab/search/recent_merge_requests_spec.rb b/spec/lib/gitlab/search/recent_merge_requests_spec.rb
index c6678ce0342..1da3e1425d9 100644
--- a/spec/lib/gitlab/search/recent_merge_requests_spec.rb
+++ b/spec/lib/gitlab/search/recent_merge_requests_spec.rb
@@ -3,8 +3,10 @@
require 'spec_helper'
RSpec.describe ::Gitlab::Search::RecentMergeRequests do
- def create_item(content:, project:)
- create(:merge_request, :unique_branches, title: content, target_project: project, source_project: project)
+ let(:parent_type) { :project }
+
+ def create_item(content:, parent:)
+ create(:merge_request, :unique_branches, title: content, target_project: parent, source_project: parent)
end
it_behaves_like 'search recent items'
diff --git a/spec/lib/gitlab/search_results_spec.rb b/spec/lib/gitlab/search_results_spec.rb
index b4cf6a568b4..57be9e93af2 100644
--- a/spec/lib/gitlab/search_results_spec.rb
+++ b/spec/lib/gitlab/search_results_spec.rb
@@ -11,9 +11,11 @@ RSpec.describe Gitlab::SearchResults do
let_it_be(:issue) { create(:issue, project: project, title: 'foo') }
let_it_be(:milestone) { create(:milestone, project: project, title: 'foo') }
let(:merge_request) { create(:merge_request, source_project: project, title: 'foo') }
+ let(:query) { 'foo' }
let(:filters) { {} }
+ let(:sort) { nil }
- subject(:results) { described_class.new(user, 'foo', Project.order(:id), filters: filters) }
+ subject(:results) { described_class.new(user, query, Project.order(:id), sort: sort, filters: filters) }
context 'as a user with access' do
before do
@@ -58,6 +60,25 @@ RSpec.describe Gitlab::SearchResults do
end
end
+ describe '#highlight_map' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:scope, :expected) do
+ 'projects' | {}
+ 'issues' | {}
+ 'merge_requests' | {}
+ 'milestones' | {}
+ 'users' | {}
+ 'unknown' | {}
+ end
+
+ with_them do
+ it 'returns the expected highlight_map' do
+ expect(results.highlight_map(scope)).to eq(expected)
+ end
+ end
+ end
+
describe '#formatted_limited_count' do
using RSpec::Parameterized::TableSyntax
@@ -137,10 +158,12 @@ RSpec.describe Gitlab::SearchResults do
end
describe '#merge_requests' do
+ let(:scope) { 'merge_requests' }
+
it 'includes project filter by default' do
expect(results).to receive(:project_ids_relation).and_call_original
- results.objects('merge_requests')
+ results.objects(scope)
end
it 'skips project filter if default project context is used' do
@@ -148,24 +171,34 @@ RSpec.describe Gitlab::SearchResults do
expect(results).not_to receive(:project_ids_relation)
- results.objects('merge_requests')
+ results.objects(scope)
end
context 'filtering' do
let!(:opened_result) { create(:merge_request, :opened, source_project: project, title: 'foo opened') }
let!(:closed_result) { create(:merge_request, :closed, source_project: project, title: 'foo closed') }
- let(:scope) { 'merge_requests' }
let(:query) { 'foo' }
include_examples 'search results filtered by state'
end
+
+ context 'ordering' do
+ let(:query) { 'sorted' }
+ let!(:old_result) { create(:merge_request, :opened, source_project: project, source_branch: 'old-1', title: 'sorted old', created_at: 1.month.ago) }
+ let!(:new_result) { create(:merge_request, :opened, source_project: project, source_branch: 'new-1', title: 'sorted recent', created_at: 1.day.ago) }
+ let!(:very_old_result) { create(:merge_request, :opened, source_project: project, source_branch: 'very-old-1', title: 'sorted very old', created_at: 1.year.ago) }
+
+ include_examples 'search results sorted'
+ end
end
describe '#issues' do
+ let(:scope) { 'issues' }
+
it 'includes project filter by default' do
expect(results).to receive(:project_ids_relation).and_call_original
- results.objects('issues')
+ results.objects(scope)
end
it 'skips project filter if default project context is used' do
@@ -173,16 +206,25 @@ RSpec.describe Gitlab::SearchResults do
expect(results).not_to receive(:project_ids_relation)
- results.objects('issues')
+ results.objects(scope)
end
context 'filtering' do
- let(:scope) { 'issues' }
-
let_it_be(:closed_result) { create(:issue, :closed, project: project, title: 'foo closed') }
let_it_be(:opened_result) { create(:issue, :opened, project: project, title: 'foo open') }
+ let_it_be(:confidential_result) { create(:issue, :confidential, project: project, title: 'foo confidential') }
include_examples 'search results filtered by state'
+ include_examples 'search results filtered by confidential'
+ end
+
+ context 'ordering' do
+ let(:query) { 'sorted' }
+ let!(:old_result) { create(:issue, project: project, title: 'sorted old', created_at: 1.month.ago) }
+ let!(:new_result) { create(:issue, project: project, title: 'sorted recent', created_at: 1.day.ago) }
+ let!(:very_old_result) { create(:issue, project: project, title: 'sorted very old', created_at: 1.year.ago) }
+
+ include_examples 'search results sorted'
end
end
diff --git a/spec/lib/gitlab/sidekiq_cluster_spec.rb b/spec/lib/gitlab/sidekiq_cluster_spec.rb
index 5dd913aebb0..5517abe1010 100644
--- a/spec/lib/gitlab/sidekiq_cluster_spec.rb
+++ b/spec/lib/gitlab/sidekiq_cluster_spec.rb
@@ -99,7 +99,7 @@ RSpec.describe Gitlab::SidekiqCluster do
allow(Process).to receive(:spawn).and_return(1)
expect(described_class).to receive(:wait_async).with(1)
- expect(described_class.start_sidekiq(%w(foo), options)).to eq(1)
+ expect(described_class.start_sidekiq(%w(foo), **options)).to eq(1)
end
it 'handles duplicate queue names' do
@@ -109,7 +109,7 @@ RSpec.describe Gitlab::SidekiqCluster do
.and_return(1)
expect(described_class).to receive(:wait_async).with(1)
- expect(described_class.start_sidekiq(%w(foo foo bar baz), options)).to eq(1)
+ expect(described_class.start_sidekiq(%w(foo foo bar baz), **options)).to eq(1)
end
it 'runs the sidekiq process in a new process group' do
@@ -119,7 +119,7 @@ RSpec.describe Gitlab::SidekiqCluster do
.and_return(1)
allow(described_class).to receive(:wait_async)
- expect(described_class.start_sidekiq(%w(foo bar baz), options)).to eq(1)
+ expect(described_class.start_sidekiq(%w(foo bar baz), **options)).to eq(1)
end
end
diff --git a/spec/lib/gitlab/sidekiq_middleware/worker_context/server_spec.rb b/spec/lib/gitlab/sidekiq_middleware/worker_context/server_spec.rb
index bde19fa7552..ca473462d2e 100644
--- a/spec/lib/gitlab/sidekiq_middleware/worker_context/server_spec.rb
+++ b/spec/lib/gitlab/sidekiq_middleware/worker_context/server_spec.rb
@@ -14,6 +14,7 @@ RSpec.describe Gitlab::SidekiqMiddleware::WorkerContext::Server do
include ApplicationWorker
+ feature_category :foo
worker_context user: nil
def perform(identifier, *args)
@@ -56,6 +57,12 @@ RSpec.describe Gitlab::SidekiqMiddleware::WorkerContext::Server do
expect(TestWorker.contexts['identifier'].keys).not_to include('meta.user')
end
+ it 'takes the feature category from the worker' do
+ TestWorker.perform_async('identifier', 1)
+
+ expect(TestWorker.contexts['identifier']).to include('meta.feature_category' => 'foo')
+ end
+
it "doesn't fail for unknown workers" do
expect { OtherWorker.perform_async }.not_to raise_error
end
diff --git a/spec/lib/gitlab/snippet_search_results_spec.rb b/spec/lib/gitlab/snippet_search_results_spec.rb
index e1ae26a4d9e..2177b2be6d6 100644
--- a/spec/lib/gitlab/snippet_search_results_spec.rb
+++ b/spec/lib/gitlab/snippet_search_results_spec.rb
@@ -21,6 +21,12 @@ RSpec.describe Gitlab::SnippetSearchResults do
end
end
+ describe '#highlight_map' do
+ it 'returns the expected highlight map' do
+ expect(results.highlight_map('snippet_titles')).to eq({})
+ end
+ end
+
describe '#objects' do
it 'uses page and per_page to paginate results' do
snippet2 = create(:snippet, :public, content: 'foo', file_name: 'foo')
diff --git a/spec/lib/gitlab/sql/pattern_spec.rb b/spec/lib/gitlab/sql/pattern_spec.rb
index 220ac2ff6da..9bf6f0b82bc 100644
--- a/spec/lib/gitlab/sql/pattern_spec.rb
+++ b/spec/lib/gitlab/sql/pattern_spec.rb
@@ -3,6 +3,43 @@
require 'spec_helper'
RSpec.describe Gitlab::SQL::Pattern do
+ using RSpec::Parameterized::TableSyntax
+
+ describe '.fuzzy_search' do
+ let_it_be(:issue1) { create(:issue, title: 'noise foo noise', description: 'noise bar noise') }
+ let_it_be(:issue2) { create(:issue, title: 'noise baz noise', description: 'noise foo noise') }
+ let_it_be(:issue3) { create(:issue, title: 'Oh', description: 'Ah') }
+
+ subject(:fuzzy_search) { Issue.fuzzy_search(query, columns) }
+
+ where(:query, :columns, :expected) do
+ 'foo' | [Issue.arel_table[:title]] | %i[issue1]
+
+ 'foo' | %i[title] | %i[issue1]
+ 'foo' | %w[title] | %i[issue1]
+ 'foo' | %i[description] | %i[issue2]
+ 'foo' | %i[title description] | %i[issue1 issue2]
+ 'bar' | %i[title description] | %i[issue1]
+ 'baz' | %i[title description] | %i[issue2]
+ 'qux' | %i[title description] | []
+
+ 'oh' | %i[title description] | %i[issue3]
+ 'OH' | %i[title description] | %i[issue3]
+ 'ah' | %i[title description] | %i[issue3]
+ 'AH' | %i[title description] | %i[issue3]
+ 'oh' | %i[title] | %i[issue3]
+ 'ah' | %i[description] | %i[issue3]
+ end
+
+ with_them do
+ let(:expected_issues) { expected.map { |sym| send(sym) } }
+
+ it 'finds the expected issues' do
+ expect(fuzzy_search).to match_array(expected_issues)
+ end
+ end
+ end
+
describe '.to_pattern' do
subject(:to_pattern) { User.to_pattern(query) }
diff --git a/spec/lib/gitlab/static_site_editor/config/file_config/entry/global_spec.rb b/spec/lib/gitlab/static_site_editor/config/file_config/entry/global_spec.rb
new file mode 100644
index 00000000000..9ce6007165b
--- /dev/null
+++ b/spec/lib/gitlab/static_site_editor/config/file_config/entry/global_spec.rb
@@ -0,0 +1,245 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::StaticSiteEditor::Config::FileConfig::Entry::Global do
+ let(:global) { described_class.new(hash) }
+ let(:default_image_upload_path_value) { 'source/images' }
+
+ let(:default_mounts_value) do
+ [
+ {
+ source: 'source',
+ target: ''
+ }
+ ]
+ end
+
+ let(:default_static_site_generator_value) { 'middleman' }
+
+ shared_examples_for 'valid default configuration' do
+ describe '#compose!' do
+ before do
+ global.compose!
+ end
+
+ it 'creates nodes hash' do
+ expect(global.descendants).to be_an Array
+ end
+
+ it 'creates node object for each entry' do
+ expect(global.descendants.count).to eq 3
+ end
+
+ it 'creates node object using valid class' do
+ expect(global.descendants.map(&:class)).to match_array(expected_node_object_classes)
+ end
+
+ it 'sets a description containing "Static Site Editor" for all nodes' do
+ expect(global.descendants.map(&:description)).to all(match(/Static Site Editor/))
+ end
+
+ describe '#leaf?' do
+ it 'is not leaf' do
+ expect(global).not_to be_leaf
+ end
+ end
+ end
+
+ context 'when not composed' do
+ describe '#static_site_generator_value' do
+ it 'returns nil' do
+ expect(global.static_site_generator_value).to be nil
+ end
+ end
+
+ describe '#leaf?' do
+ it 'is leaf' do
+ expect(global).to be_leaf
+ end
+ end
+ end
+
+ context 'when composed' do
+ before do
+ global.compose!
+ end
+
+ describe '#errors' do
+ it 'has no errors' do
+ expect(global.errors).to be_empty
+ end
+ end
+
+ describe '#image_upload_path_value' do
+ it 'returns correct values' do
+ expect(global.image_upload_path_value).to eq(default_image_upload_path_value)
+ end
+ end
+
+ describe '#mounts_value' do
+ it 'returns correct values' do
+ expect(global.mounts_value).to eq(default_mounts_value)
+ end
+ end
+
+ describe '#static_site_generator_value' do
+ it 'returns correct values' do
+ expect(global.static_site_generator_value).to eq(default_static_site_generator_value)
+ end
+ end
+ end
+ end
+
+ describe '.nodes' do
+ it 'returns a hash' do
+ expect(described_class.nodes).to be_a(Hash)
+ end
+
+ context 'when filtering all the entry/node names' do
+ it 'contains the expected node names' do
+ expected_node_names = %i[
+ image_upload_path
+ mounts
+ static_site_generator
+ ]
+ expect(described_class.nodes.keys).to match_array(expected_node_names)
+ end
+ end
+ end
+
+ context 'when configuration is valid' do
+ context 'when some entries defined' do
+ let(:expected_node_object_classes) do
+ [
+ Gitlab::StaticSiteEditor::Config::FileConfig::Entry::ImageUploadPath,
+ Gitlab::StaticSiteEditor::Config::FileConfig::Entry::Mounts,
+ Gitlab::StaticSiteEditor::Config::FileConfig::Entry::StaticSiteGenerator
+ ]
+ end
+
+ let(:hash) do
+ {
+ image_upload_path: default_image_upload_path_value,
+ mounts: default_mounts_value,
+ static_site_generator: default_static_site_generator_value
+ }
+ end
+
+ it_behaves_like 'valid default configuration'
+ end
+ end
+
+ context 'when value is an empty hash' do
+ let(:expected_node_object_classes) do
+ [
+ Gitlab::Config::Entry::Unspecified,
+ Gitlab::Config::Entry::Unspecified,
+ Gitlab::Config::Entry::Unspecified
+ ]
+ end
+
+ let(:hash) { {} }
+
+ it_behaves_like 'valid default configuration'
+ end
+
+ context 'when configuration is not valid' do
+ before do
+ global.compose!
+ end
+
+ context 'when a single entry is invalid' do
+ let(:hash) do
+ { image_upload_path: { not_a_string: true } }
+ end
+
+ describe '#errors' do
+ it 'reports errors' do
+ expect(global.errors)
+ .to include 'image_upload_path config should be a string'
+ end
+ end
+ end
+
+ context 'when a multiple entries are invalid' do
+ let(:hash) do
+ {
+ image_upload_path: { not_a_string: true },
+ static_site_generator: { not_a_string: true }
+ }
+ end
+
+ describe '#errors' do
+ it 'reports errors' do
+ expect(global.errors)
+ .to match_array([
+ 'image_upload_path config should be a string',
+ 'static_site_generator config should be a string',
+ "static_site_generator config should be 'middleman'"
+ ])
+ end
+ end
+ end
+
+ context 'when there is an invalid key' do
+ let(:hash) do
+ { invalid_key: true }
+ end
+
+ describe '#errors' do
+ it 'reports errors' do
+ expect(global.errors)
+ .to include 'global config contains unknown keys: invalid_key'
+ end
+ end
+ end
+ end
+
+ context 'when value is not a hash' do
+ let(:hash) { [] }
+
+ describe '#valid?' do
+ it 'is not valid' do
+ expect(global).not_to be_valid
+ end
+ end
+
+ describe '#errors' do
+ it 'returns error about invalid type' do
+ expect(global.errors.first).to match /should be a hash/
+ end
+ end
+ end
+
+ describe '#specified?' do
+ it 'is concrete entry that is defined' do
+ expect(global.specified?).to be true
+ end
+ end
+
+ describe '#[]' do
+ before do
+ global.compose!
+ end
+
+ let(:hash) do
+ { static_site_generator: default_static_site_generator_value }
+ end
+
+ context 'when entry exists' do
+ it 'returns correct entry' do
+ expect(global[:static_site_generator])
+ .to be_an_instance_of Gitlab::StaticSiteEditor::Config::FileConfig::Entry::StaticSiteGenerator
+ expect(global[:static_site_generator].value).to eq default_static_site_generator_value
+ end
+ end
+
+ context 'when entry does not exist' do
+ it 'always return unspecified node' do
+ expect(global[:some][:unknown][:node])
+ .not_to be_specified
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/static_site_editor/config/file_config/entry/image_upload_path_spec.rb b/spec/lib/gitlab/static_site_editor/config/file_config/entry/image_upload_path_spec.rb
new file mode 100644
index 00000000000..c2b7fbf6f98
--- /dev/null
+++ b/spec/lib/gitlab/static_site_editor/config/file_config/entry/image_upload_path_spec.rb
@@ -0,0 +1,38 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::StaticSiteEditor::Config::FileConfig::Entry::ImageUploadPath do
+ subject(:image_upload_path_entry) { described_class.new(config) }
+
+ describe 'validations' do
+ context 'with a valid config' do
+ let(:config) { 'an-image-upload-path' }
+
+ it { is_expected.to be_valid }
+
+ describe '#value' do
+ it 'returns a image_upload_path key' do
+ expect(image_upload_path_entry.value).to eq config
+ end
+ end
+ end
+
+ context 'with an invalid config' do
+ let(:config) { { not_a_string: true } }
+
+ it { is_expected.not_to be_valid }
+
+ it 'reports errors about wrong type' do
+ expect(image_upload_path_entry.errors)
+ .to include 'image upload path config should be a string'
+ end
+ end
+ end
+
+ describe '.default' do
+ it 'returns default image_upload_path' do
+ expect(described_class.default).to eq 'source/images'
+ end
+ end
+end
diff --git a/spec/lib/gitlab/static_site_editor/config/file_config/entry/mount_spec.rb b/spec/lib/gitlab/static_site_editor/config/file_config/entry/mount_spec.rb
new file mode 100644
index 00000000000..04248fc60a5
--- /dev/null
+++ b/spec/lib/gitlab/static_site_editor/config/file_config/entry/mount_spec.rb
@@ -0,0 +1,101 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::StaticSiteEditor::Config::FileConfig::Entry::Mount do
+ subject(:entry) { described_class.new(config) }
+
+ describe 'validations' do
+ context 'with a valid config' do
+ context 'and target is a non-empty string' do
+ let(:config) do
+ {
+ source: 'source',
+ target: 'sub-site'
+ }
+ end
+
+ it { is_expected.to be_valid }
+
+ describe '#value' do
+ it 'returns mount configuration' do
+ expect(entry.value).to eq config
+ end
+ end
+ end
+
+ context 'and target is an empty string' do
+ let(:config) do
+ {
+ source: 'source',
+ target: ''
+ }
+ end
+
+ it { is_expected.to be_valid }
+
+ describe '#value' do
+ it 'returns mount configuration' do
+ expect(entry.value).to eq config
+ end
+ end
+ end
+ end
+
+ context 'with an invalid config' do
+ context 'when source is not a string' do
+ let(:config) { { source: 123, target: 'target' } }
+
+ it { is_expected.not_to be_valid }
+
+ it 'reports error' do
+ expect(entry.errors)
+ .to include 'mount source should be a string'
+ end
+ end
+
+ context 'when source is not present' do
+ let(:config) { { target: 'target' } }
+
+ it { is_expected.not_to be_valid }
+
+ it 'reports error' do
+ expect(entry.errors)
+ .to include "mount source can't be blank"
+ end
+ end
+
+ context 'when target is not a string' do
+ let(:config) { { source: 'source', target: 123 } }
+
+ it { is_expected.not_to be_valid }
+
+ it 'reports error' do
+ expect(entry.errors)
+ .to include 'mount target should be a string'
+ end
+ end
+
+ context 'when there is an unknown key present' do
+ let(:config) { { test: 100 } }
+
+ it { is_expected.not_to be_valid }
+
+ it 'reports error' do
+ expect(entry.errors)
+ .to include 'mount config contains unknown keys: test'
+ end
+ end
+ end
+ end
+
+ describe '.default' do
+ it 'returns default mount' do
+ expect(described_class.default)
+ .to eq({
+ source: 'source',
+ target: ''
+ })
+ end
+ end
+end
diff --git a/spec/lib/gitlab/static_site_editor/config/file_config/entry/mounts_spec.rb b/spec/lib/gitlab/static_site_editor/config/file_config/entry/mounts_spec.rb
new file mode 100644
index 00000000000..0ae2ece9474
--- /dev/null
+++ b/spec/lib/gitlab/static_site_editor/config/file_config/entry/mounts_spec.rb
@@ -0,0 +1,53 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::StaticSiteEditor::Config::FileConfig::Entry::Mounts do
+ subject(:entry) { described_class.new(config) }
+
+ describe 'validations' do
+ context 'with a valid config' do
+ let(:config) do
+ [
+ {
+ source: 'source',
+ target: ''
+ },
+ {
+ source: 'sub-site/source',
+ target: 'sub-site'
+ }
+ ]
+ end
+
+ it { is_expected.to be_valid }
+
+ describe '#value' do
+ it 'returns mounts configuration' do
+ expect(entry.value).to eq config
+ end
+ end
+ end
+
+ context 'with an invalid config' do
+ let(:config) { { not_an_array: true } }
+
+ it { is_expected.not_to be_valid }
+
+ it 'reports errors about wrong type' do
+ expect(entry.errors)
+ .to include 'mounts config should be a array'
+ end
+ end
+ end
+
+ describe '.default' do
+ it 'returns default mounts' do
+ expect(described_class.default)
+ .to eq([{
+ source: 'source',
+ target: ''
+ }])
+ end
+ end
+end
diff --git a/spec/lib/gitlab/static_site_editor/config/file_config/entry/static_site_generator_spec.rb b/spec/lib/gitlab/static_site_editor/config/file_config/entry/static_site_generator_spec.rb
new file mode 100644
index 00000000000..a9c730218cf
--- /dev/null
+++ b/spec/lib/gitlab/static_site_editor/config/file_config/entry/static_site_generator_spec.rb
@@ -0,0 +1,50 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::StaticSiteEditor::Config::FileConfig::Entry::StaticSiteGenerator do
+ let(:static_site_generator) { described_class.new(config) }
+
+ describe 'validations' do
+ context 'when value is valid' do
+ let(:config) { 'middleman' }
+
+ describe '#value' do
+ it 'returns a static_site_generator key' do
+ expect(static_site_generator.value).to eq config
+ end
+ end
+
+ describe '#valid?' do
+ it 'is valid' do
+ expect(static_site_generator).to be_valid
+ end
+ end
+ end
+
+ context 'when value is invalid' do
+ let(:config) { 'not-a-valid-generator' }
+
+ describe '#valid?' do
+ it 'is not valid' do
+ expect(static_site_generator).not_to be_valid
+ end
+ end
+ end
+
+ context 'when value has a wrong type' do
+ let(:config) { { not_a_string: true } }
+
+ it 'reports errors about wrong type' do
+ expect(static_site_generator.errors)
+ .to include 'static site generator config should be a string'
+ end
+ end
+ end
+
+ describe '.default' do
+ it 'returns default static_site_generator' do
+ expect(described_class.default).to eq 'middleman'
+ end
+ end
+end
diff --git a/spec/lib/gitlab/static_site_editor/config/file_config_spec.rb b/spec/lib/gitlab/static_site_editor/config/file_config_spec.rb
index 594425c2dab..d444d4f1df7 100644
--- a/spec/lib/gitlab/static_site_editor/config/file_config_spec.rb
+++ b/spec/lib/gitlab/static_site_editor/config/file_config_spec.rb
@@ -3,13 +3,85 @@
require 'spec_helper'
RSpec.describe Gitlab::StaticSiteEditor::Config::FileConfig do
- subject(:config) { described_class.new }
+ let(:config) do
+ described_class.new(yml)
+ end
+
+ context 'when config is valid' do
+ context 'when config has valid values' do
+ let(:yml) do
+ <<-EOS
+ static_site_generator: middleman
+ EOS
+ end
+
+ describe '#to_hash_with_defaults' do
+ it 'returns hash created from string' do
+ expect(config.to_hash_with_defaults.fetch(:static_site_generator)).to eq 'middleman'
+ end
+ end
+
+ describe '#valid?' do
+ it 'is valid' do
+ expect(config).to be_valid
+ end
+
+ it 'has no errors' do
+ expect(config.errors).to be_empty
+ end
+ end
+ end
+ end
+
+ context 'when a config entry has an empty value' do
+ let(:yml) { 'static_site_generator: ' }
+
+ describe '#to_hash' do
+ it 'returns default value' do
+ expect(config.to_hash_with_defaults.fetch(:static_site_generator)).to eq 'middleman'
+ end
+ end
+
+ describe '#valid?' do
+ it 'is valid' do
+ expect(config).to be_valid
+ end
+
+ it 'has no errors' do
+ expect(config.errors).to be_empty
+ end
+ end
+ end
+
+ context 'when config is invalid' do
+ context 'when yml is incorrect' do
+ let(:yml) { '// invalid' }
+
+ describe '.new' do
+ it 'raises error' do
+ expect { config }.to raise_error(described_class::ConfigError, /Invalid configuration format/)
+ end
+ end
+ end
+
+ context 'when config value exists but is not a valid value' do
+ let(:yml) { 'static_site_generator: "unsupported-generator"' }
+
+ describe '#valid?' do
+ it 'is not valid' do
+ expect(config).not_to be_valid
+ end
- describe '#data' do
- subject { config.data }
+ it 'has errors' do
+ expect(config.errors).not_to be_empty
+ end
+ end
- it 'returns hardcoded data for now' do
- is_expected.to match(static_site_generator: 'middleman')
+ describe '#errors' do
+ it 'returns an array of strings' do
+ expect(config.errors).to all(be_an_instance_of(String))
+ end
+ end
end
end
end
diff --git a/spec/lib/gitlab/static_site_editor/config/generated_config_spec.rb b/spec/lib/gitlab/static_site_editor/config/generated_config_spec.rb
index 3433a54be9c..2f761b69e60 100644
--- a/spec/lib/gitlab/static_site_editor/config/generated_config_spec.rb
+++ b/spec/lib/gitlab/static_site_editor/config/generated_config_spec.rb
@@ -29,7 +29,7 @@ RSpec.describe Gitlab::StaticSiteEditor::Config::GeneratedConfig do
project: 'project',
project_id: project.id,
return_url: 'http://example.com',
- is_supported_content: 'true',
+ is_supported_content: true,
base_url: '/namespace/project/-/sse/master%2FREADME.md',
merge_requests_illustration_path: %r{illustrations/merge_requests}
})
@@ -65,7 +65,7 @@ RSpec.describe Gitlab::StaticSiteEditor::Config::GeneratedConfig do
stub_feature_flags(sse_erb_support: project)
end
- it { is_expected.to include(is_supported_content: 'true') }
+ it { is_expected.to include(is_supported_content: true) }
end
context 'when feature flag is disabled' do
@@ -75,7 +75,7 @@ RSpec.describe Gitlab::StaticSiteEditor::Config::GeneratedConfig do
stub_feature_flags(sse_erb_support: false)
end
- it { is_expected.to include(is_supported_content: 'false') }
+ it { is_expected.to include(is_supported_content: false) }
end
end
@@ -88,31 +88,31 @@ RSpec.describe Gitlab::StaticSiteEditor::Config::GeneratedConfig do
context 'when branch is not master' do
let(:ref) { 'my-branch' }
- it { is_expected.to include(is_supported_content: 'false') }
+ it { is_expected.to include(is_supported_content: false) }
end
context 'when file does not have a markdown extension' do
let(:path) { 'README.txt' }
- it { is_expected.to include(is_supported_content: 'false') }
+ it { is_expected.to include(is_supported_content: false) }
end
context 'when file does not have an extension' do
let(:path) { 'README' }
- it { is_expected.to include(is_supported_content: 'false') }
+ it { is_expected.to include(is_supported_content: false) }
end
context 'when file does not exist' do
let(:path) { 'UNKNOWN.md' }
- it { is_expected.to include(is_supported_content: 'false') }
+ it { is_expected.to include(is_supported_content: false) }
end
context 'when repository is empty' do
let(:repository) { create(:project_empty_repo).repository }
- it { is_expected.to include(is_supported_content: 'false') }
+ it { is_expected.to include(is_supported_content: false) }
end
context 'when return_url is not a valid URL' do
@@ -132,5 +132,11 @@ RSpec.describe Gitlab::StaticSiteEditor::Config::GeneratedConfig do
it { is_expected.to include(return_url: nil) }
end
+
+ context 'when a commit for the ref cannot be found' do
+ let(:ref) { 'nonexistent-ref' }
+
+ it { is_expected.to include(commit_id: nil) }
+ end
end
end
diff --git a/spec/lib/gitlab/subscription_portal_spec.rb b/spec/lib/gitlab/subscription_portal_spec.rb
new file mode 100644
index 00000000000..351af3c07d2
--- /dev/null
+++ b/spec/lib/gitlab/subscription_portal_spec.rb
@@ -0,0 +1,42 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe ::Gitlab::SubscriptionPortal do
+ describe '.default_subscriptions_url' do
+ subject { described_class.default_subscriptions_url }
+
+ context 'on non test and non dev environments' do
+ before do
+ allow(Rails).to receive_message_chain(:env, :test?).and_return(false)
+ allow(Rails).to receive_message_chain(:env, :development?).and_return(false)
+ end
+
+ it 'returns production subscriptions app URL' do
+ is_expected.to eq('https://customers.gitlab.com')
+ end
+ end
+
+ context 'on dev environment' do
+ before do
+ allow(Rails).to receive_message_chain(:env, :test?).and_return(false)
+ allow(Rails).to receive_message_chain(:env, :development?).and_return(true)
+ end
+
+ it 'returns staging subscriptions app url' do
+ is_expected.to eq('https://customers.stg.gitlab.com')
+ end
+ end
+
+ context 'on test environment' do
+ before do
+ allow(Rails).to receive_message_chain(:env, :test?).and_return(true)
+ allow(Rails).to receive_message_chain(:env, :development?).and_return(false)
+ end
+
+ it 'returns staging subscriptions app url' do
+ is_expected.to eq('https://customers.stg.gitlab.com')
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/themes_spec.rb b/spec/lib/gitlab/themes_spec.rb
index 68ff28becfa..6d03cf496b8 100644
--- a/spec/lib/gitlab/themes_spec.rb
+++ b/spec/lib/gitlab/themes_spec.rb
@@ -47,4 +47,18 @@ RSpec.describe Gitlab::Themes, lib: true do
expect(ids).not_to be_empty
end
end
+
+ describe 'theme.css_filename' do
+ described_class.each do |theme|
+ next unless theme.css_filename
+
+ context "for #{theme.name}" do
+ it 'returns an existing CSS filename' do
+ css_file_path = Rails.root.join('app/assets/stylesheets/themes', theme.css_filename + '.scss')
+
+ expect(File.exist?(css_file_path)).to eq(true)
+ end
+ end
+ end
+ end
end
diff --git a/spec/lib/gitlab/tracking_spec.rb b/spec/lib/gitlab/tracking_spec.rb
index f0bf7b9964f..6ddeaf98370 100644
--- a/spec/lib/gitlab/tracking_spec.rb
+++ b/spec/lib/gitlab/tracking_spec.rb
@@ -47,7 +47,7 @@ RSpec.describe Gitlab::Tracking do
end
around do |example|
- Timecop.freeze(timestamp) { example.run }
+ travel_to(timestamp) { example.run }
end
before do
diff --git a/spec/lib/gitlab/usage_data_counters/editor_unique_counter_spec.rb b/spec/lib/gitlab/usage_data_counters/editor_unique_counter_spec.rb
index 2a674557b76..f2c1d8718d7 100644
--- a/spec/lib/gitlab/usage_data_counters/editor_unique_counter_spec.rb
+++ b/spec/lib/gitlab/usage_data_counters/editor_unique_counter_spec.rb
@@ -41,11 +41,11 @@ RSpec.describe Gitlab::UsageDataCounters::EditorUniqueCounter, :clean_gitlab_red
context 'for web IDE edit actions' do
it_behaves_like 'tracks and counts action' do
def track_action(params)
- described_class.track_web_ide_edit_action(params)
+ described_class.track_web_ide_edit_action(**params)
end
def count_unique(params)
- described_class.count_web_ide_edit_actions(params)
+ described_class.count_web_ide_edit_actions(**params)
end
end
end
@@ -53,11 +53,11 @@ RSpec.describe Gitlab::UsageDataCounters::EditorUniqueCounter, :clean_gitlab_red
context 'for SFE edit actions' do
it_behaves_like 'tracks and counts action' do
def track_action(params)
- described_class.track_sfe_edit_action(params)
+ described_class.track_sfe_edit_action(**params)
end
def count_unique(params)
- described_class.count_sfe_edit_actions(params)
+ described_class.count_sfe_edit_actions(**params)
end
end
end
@@ -65,11 +65,11 @@ RSpec.describe Gitlab::UsageDataCounters::EditorUniqueCounter, :clean_gitlab_red
context 'for snippet editor edit actions' do
it_behaves_like 'tracks and counts action' do
def track_action(params)
- described_class.track_snippet_editor_edit_action(params)
+ described_class.track_snippet_editor_edit_action(**params)
end
def count_unique(params)
- described_class.count_snippet_editor_edit_actions(params)
+ described_class.count_snippet_editor_edit_actions(**params)
end
end
end
diff --git a/spec/lib/gitlab/usage_data_counters/hll_redis_counter_spec.rb b/spec/lib/gitlab/usage_data_counters/hll_redis_counter_spec.rb
index f881da71251..e84c3c17274 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
@@ -15,12 +15,12 @@ RSpec.describe Gitlab::UsageDataCounters::HLLRedisCounter, :clean_gitlab_redis_s
# depending on which day of the week test is run.
# Monday 6th of June
reference_time = Time.utc(2020, 6, 1)
- Timecop.freeze(reference_time) { example.run }
+ travel_to(reference_time) { example.run }
end
describe '.categories' do
it 'gets all unique category names' do
- expect(described_class.categories).to contain_exactly('analytics', 'compliance', 'ide_edit', 'search', 'source_code', 'incident_management', 'issues_edit')
+ expect(described_class.categories).to contain_exactly('analytics', 'compliance', 'ide_edit', 'search', 'source_code', 'incident_management', 'issues_edit', 'testing')
end
end
@@ -238,16 +238,20 @@ RSpec.describe Gitlab::UsageDataCounters::HLLRedisCounter, :clean_gitlab_redis_s
it 'returns the number of unique events for all known events' do
results = {
- 'category1' => {
- 'event1_slot' => 1,
- 'event2_slot' => 1,
- 'category1_total_unique_counts_weekly' => 2,
- 'category1_total_unique_counts_monthly' => 3
- },
- 'category2' => {
- 'event3' => 1,
- 'event4' => 1
- }
+ "category1" => {
+ "event1_slot_weekly" => 1,
+ "event1_slot_monthly" => 1,
+ "event2_slot_weekly" => 1,
+ "event2_slot_monthly" => 2,
+ "category1_total_unique_counts_weekly" => 2,
+ "category1_total_unique_counts_monthly" => 3
+ },
+ "category2" => {
+ "event3_weekly" => 1,
+ "event3_monthly" => 1,
+ "event4_weekly" => 1,
+ "event4_monthly" => 1
+ }
}
expect(subject.unique_events_data).to eq(results)
diff --git a/spec/lib/gitlab/usage_data_counters/issue_activity_unique_counter_spec.rb b/spec/lib/gitlab/usage_data_counters/issue_activity_unique_counter_spec.rb
index 479fe36bcdd..e08dc41d0cc 100644
--- a/spec/lib/gitlab/usage_data_counters/issue_activity_unique_counter_spec.rb
+++ b/spec/lib/gitlab/usage_data_counters/issue_activity_unique_counter_spec.rb
@@ -47,7 +47,7 @@ RSpec.describe Gitlab::UsageDataCounters::IssueActivityUniqueCounter, :clean_git
let(:action) { described_class::ISSUE_TITLE_CHANGED }
def track_action(params)
- described_class.track_issue_title_changed_action(params)
+ described_class.track_issue_title_changed_action(**params)
end
end
end
@@ -57,7 +57,7 @@ RSpec.describe Gitlab::UsageDataCounters::IssueActivityUniqueCounter, :clean_git
let(:action) { described_class::ISSUE_DESCRIPTION_CHANGED }
def track_action(params)
- described_class.track_issue_description_changed_action(params)
+ described_class.track_issue_description_changed_action(**params)
end
end
end
@@ -67,7 +67,7 @@ RSpec.describe Gitlab::UsageDataCounters::IssueActivityUniqueCounter, :clean_git
let(:action) { described_class::ISSUE_ASSIGNEE_CHANGED }
def track_action(params)
- described_class.track_issue_assignee_changed_action(params)
+ described_class.track_issue_assignee_changed_action(**params)
end
end
end
@@ -77,7 +77,7 @@ RSpec.describe Gitlab::UsageDataCounters::IssueActivityUniqueCounter, :clean_git
let(:action) { described_class::ISSUE_MADE_CONFIDENTIAL }
def track_action(params)
- described_class.track_issue_made_confidential_action(params)
+ described_class.track_issue_made_confidential_action(**params)
end
end
end
@@ -87,7 +87,207 @@ RSpec.describe Gitlab::UsageDataCounters::IssueActivityUniqueCounter, :clean_git
let(:action) { described_class::ISSUE_MADE_VISIBLE }
def track_action(params)
- described_class.track_issue_made_visible_action(params)
+ described_class.track_issue_made_visible_action(**params)
+ end
+ end
+ end
+
+ context 'for Issue created actions' do
+ it_behaves_like 'tracks and counts action' do
+ let(:action) { described_class::ISSUE_CREATED }
+
+ def track_action(params)
+ described_class.track_issue_created_action(**params)
+ end
+ end
+ end
+
+ context 'for Issue closed actions' do
+ it_behaves_like 'tracks and counts action' do
+ let(:action) { described_class::ISSUE_CLOSED }
+
+ def track_action(params)
+ described_class.track_issue_closed_action(**params)
+ end
+ end
+ end
+
+ context 'for Issue reopened actions' do
+ it_behaves_like 'tracks and counts action' do
+ let(:action) { described_class::ISSUE_REOPENED }
+
+ def track_action(params)
+ described_class.track_issue_reopened_action(**params)
+ end
+ end
+ end
+
+ context 'for Issue label changed actions' do
+ it_behaves_like 'tracks and counts action' do
+ let(:action) { described_class::ISSUE_LABEL_CHANGED }
+
+ def track_action(params)
+ described_class.track_issue_label_changed_action(**params)
+ end
+ end
+ end
+
+ context 'for Issue cross-referenced actions' do
+ it_behaves_like 'tracks and counts action' do
+ let(:action) { described_class::ISSUE_CROSS_REFERENCED }
+
+ def track_action(params)
+ described_class.track_issue_cross_referenced_action(**params)
+ end
+ end
+ end
+
+ context 'for Issue moved actions' do
+ it_behaves_like 'tracks and counts action' do
+ let(:action) { described_class::ISSUE_MOVED }
+
+ def track_action(params)
+ described_class.track_issue_moved_action(**params)
+ end
+ end
+ end
+
+ context 'for Issue relate actions' do
+ it_behaves_like 'tracks and counts action' do
+ let(:action) { described_class::ISSUE_RELATED }
+
+ def track_action(params)
+ described_class.track_issue_related_action(**params)
+ end
+ end
+ end
+
+ context 'for Issue unrelate actions' do
+ it_behaves_like 'tracks and counts action' do
+ let(:action) { described_class::ISSUE_UNRELATED }
+
+ def track_action(params)
+ described_class.track_issue_unrelated_action(**params)
+ end
+ end
+ end
+
+ context 'for Issue marked as duplicate actions' do
+ it_behaves_like 'tracks and counts action' do
+ let(:action) { described_class::ISSUE_MARKED_AS_DUPLICATE }
+
+ def track_action(params)
+ described_class.track_issue_marked_as_duplicate_action(**params)
+ end
+ end
+ end
+
+ context 'for Issue locked actions' do
+ it_behaves_like 'tracks and counts action' do
+ let(:action) { described_class::ISSUE_LOCKED }
+
+ def track_action(params)
+ described_class.track_issue_locked_action(**params)
+ end
+ end
+ end
+
+ context 'for Issue unlocked actions' do
+ it_behaves_like 'tracks and counts action' do
+ let(:action) { described_class::ISSUE_UNLOCKED }
+
+ def track_action(params)
+ described_class.track_issue_unlocked_action(**params)
+ end
+ end
+ end
+
+ context 'for Issue added to epic actions' do
+ it_behaves_like 'tracks and counts action' do
+ let(:action) { described_class::ISSUE_ADDED_TO_EPIC}
+
+ def track_action(params)
+ described_class.track_issue_added_to_epic_action(**params)
+ end
+ end
+ end
+
+ context 'for Issue removed from epic actions' do
+ it_behaves_like 'tracks and counts action' do
+ let(:action) { described_class::ISSUE_REMOVED_FROM_EPIC}
+
+ def track_action(params)
+ described_class.track_issue_removed_from_epic_action(**params)
+ end
+ end
+ end
+
+ context 'for Issue changed epic actions' do
+ it_behaves_like 'tracks and counts action' do
+ let(:action) { described_class::ISSUE_CHANGED_EPIC}
+
+ def track_action(params)
+ described_class.track_issue_changed_epic_action(**params)
+ end
+ end
+ end
+
+ context 'for Issue designs added actions' do
+ it_behaves_like 'tracks and counts action' do
+ let(:action) { described_class::ISSUE_DESIGNS_ADDED }
+
+ def track_action(params)
+ described_class.track_issue_designs_added_action(**params)
+ end
+ end
+ end
+
+ context 'for Issue designs modified actions' do
+ it_behaves_like 'tracks and counts action' do
+ let(:action) { described_class::ISSUE_DESIGNS_MODIFIED }
+
+ def track_action(params)
+ described_class.track_issue_designs_modified_action(**params)
+ end
+ end
+ end
+
+ context 'for Issue designs removed actions' do
+ it_behaves_like 'tracks and counts action' do
+ let(:action) { described_class::ISSUE_DESIGNS_REMOVED }
+
+ def track_action(params)
+ described_class.track_issue_designs_removed_action(**params)
+ end
+ end
+ end
+
+ context 'for Issue due date changed actions' do
+ it_behaves_like 'tracks and counts action' do
+ let(:action) { described_class::ISSUE_DUE_DATE_CHANGED }
+
+ def track_action(params)
+ described_class.track_issue_due_date_changed_action(**params)
+ end
+ end
+ end
+
+ context 'for Issue time estimate changed actions' do
+ it_behaves_like 'tracks and counts action' do
+ let(:action) { described_class::ISSUE_TIME_ESTIMATE_CHANGED }
+
+ def track_action(params)
+ described_class.track_issue_time_estimate_changed_action(**params)
+ end
+ end
+ end
+
+ context 'for Issue time spent changed actions' do
+ it_behaves_like 'tracks and counts action' do
+ let(:action) { described_class::ISSUE_TIME_SPENT_CHANGED }
+
+ def track_action(params)
+ described_class.track_issue_time_spent_changed_action(**params)
end
end
end
diff --git a/spec/lib/gitlab/usage_data_counters/static_site_editor_counter_spec.rb b/spec/lib/gitlab/usage_data_counters/static_site_editor_counter_spec.rb
new file mode 100644
index 00000000000..aaa576865f6
--- /dev/null
+++ b/spec/lib/gitlab/usage_data_counters/static_site_editor_counter_spec.rb
@@ -0,0 +1,10 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::UsageDataCounters::StaticSiteEditorCounter do
+ it_behaves_like 'a redis usage counter', 'StaticSiteEditor', :views
+
+ it_behaves_like 'a redis usage counter with totals', :static_site_editor,
+ views: 3
+end
diff --git a/spec/lib/gitlab/usage_data_counters/track_unique_events_spec.rb b/spec/lib/gitlab/usage_data_counters/track_unique_events_spec.rb
index 8f5f1347ce8..d1144dd0bc5 100644
--- a/spec/lib/gitlab/usage_data_counters/track_unique_events_spec.rb
+++ b/spec/lib/gitlab/usage_data_counters/track_unique_events_spec.rb
@@ -8,11 +8,11 @@ RSpec.describe Gitlab::UsageDataCounters::TrackUniqueEvents, :clean_gitlab_redis
let(:time) { Time.zone.now }
def track_event(params)
- track_unique_events.track_event(params)
+ track_unique_events.track_event(**params)
end
def count_unique(params)
- track_unique_events.count_unique_events(params)
+ track_unique_events.count_unique_events(**params)
end
context 'tracking an event' do
diff --git a/spec/lib/gitlab/usage_data_spec.rb b/spec/lib/gitlab/usage_data_spec.rb
index 6631a0d3cc6..f64fa2b868d 100644
--- a/spec/lib/gitlab/usage_data_spec.rb
+++ b/spec/lib/gitlab/usage_data_spec.rb
@@ -8,6 +8,7 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do
before do
stub_usage_data_connections
stub_object_store_settings
+ clear_memoized_values(described_class::CE_MEMOIZED_VALUES)
end
describe '.uncached_data' do
@@ -24,17 +25,13 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do
end
it 'clears memoized values' do
- values = %i(issue_minimum_id issue_maximum_id
- project_minimum_id project_maximum_id
- user_minimum_id user_maximum_id unique_visit_service
- deployment_minimum_id deployment_maximum_id
- approval_merge_request_rule_minimum_id
- approval_merge_request_rule_maximum_id)
- values.each do |key|
- expect(described_class).to receive(:clear_memoization).with(key)
- end
+ allow(described_class).to receive(:clear_memoization)
subject
+
+ described_class::CE_MEMOIZED_VALUES.each do |key|
+ expect(described_class).to have_received(:clear_memoization).with(key)
+ end
end
it 'merge_requests_users is included only in montly counters' do
@@ -174,21 +171,29 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do
for_defined_days_back do
user = create(:user)
+ user2 = create(:user)
create(:event, author: user)
create(:group_member, user: user)
+ create(:authentication_event, user: user, provider: :ldapmain, result: :success)
+ create(:authentication_event, user: user2, provider: :ldapsecondary, result: :success)
+ create(:authentication_event, user: user2, provider: :group_saml, result: :success)
+ create(:authentication_event, user: user2, provider: :group_saml, result: :success)
+ create(:authentication_event, user: user, provider: :group_saml, result: :failed)
end
expect(described_class.usage_activity_by_stage_manage({})).to include(
events: 2,
groups: 2,
- users_created: 4,
- omniauth_providers: ['google_oauth2']
+ users_created: 6,
+ omniauth_providers: ['google_oauth2'],
+ user_auth_by_provider: { 'group_saml' => 2, 'ldap' => 4 }
)
expect(described_class.usage_activity_by_stage_manage(described_class.last_28_days_time_period)).to include(
events: 1,
groups: 1,
- users_created: 2,
- omniauth_providers: ['google_oauth2']
+ users_created: 3,
+ omniauth_providers: ['google_oauth2'],
+ user_auth_by_provider: { 'group_saml' => 1, 'ldap' => 2 }
)
end
@@ -244,6 +249,20 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do
)
end
+ it 'includes group imports usage data' do
+ for_defined_days_back do
+ user = create(:user)
+ group = create(:group)
+ group.add_owner(user)
+ create(:group_import_state, group: group, user: user)
+ end
+
+ expect(described_class.usage_activity_by_stage_manage({}))
+ .to include(groups_imported: 2)
+ expect(described_class.usage_activity_by_stage_manage(described_class.last_28_days_time_period))
+ .to include(groups_imported: 1)
+ end
+
def omniauth_providers
[
OpenStruct.new(name: 'google_oauth2'),
@@ -260,17 +279,20 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do
cluster = create(:cluster, user: user)
create(:project, creator: user)
create(:clusters_applications_prometheus, :installed, cluster: cluster)
+ create(:project_tracing_setting)
end
expect(described_class.usage_activity_by_stage_monitor({})).to include(
clusters: 2,
clusters_applications_prometheus: 2,
- operations_dashboard_default_dashboard: 2
+ operations_dashboard_default_dashboard: 2,
+ projects_with_tracing_enabled: 2
)
expect(described_class.usage_activity_by_stage_monitor(described_class.last_28_days_time_period)).to include(
clusters: 1,
clusters_applications_prometheus: 1,
- operations_dashboard_default_dashboard: 1
+ operations_dashboard_default_dashboard: 1,
+ projects_with_tracing_enabled: 1
)
end
end
@@ -415,11 +437,14 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do
expect(count_data[:projects_slack_slash_commands_active]).to eq(1)
expect(count_data[:projects_custom_issue_tracker_active]).to eq(1)
expect(count_data[:projects_mattermost_active]).to eq(1)
+ expect(count_data[:groups_mattermost_active]).to eq(1)
expect(count_data[:templates_mattermost_active]).to eq(1)
expect(count_data[:instances_mattermost_active]).to eq(1)
- expect(count_data[:projects_inheriting_instance_mattermost_active]).to eq(1)
+ expect(count_data[:projects_inheriting_mattermost_active]).to eq(1)
+ expect(count_data[:groups_inheriting_slack_active]).to eq(1)
expect(count_data[:projects_with_repositories_enabled]).to eq(3)
expect(count_data[:projects_with_error_tracking_enabled]).to eq(1)
+ expect(count_data[:projects_with_tracing_enabled]).to eq(1)
expect(count_data[:projects_with_alerts_service_enabled]).to eq(1)
expect(count_data[:projects_with_prometheus_alerts]).to eq(2)
expect(count_data[:projects_with_terraform_reports]).to eq(2)
@@ -472,8 +497,10 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do
expect(count_data[:personal_snippets]).to eq(2)
expect(count_data[:project_snippets]).to eq(4)
+ expect(count_data[:projects_creating_incidents]).to eq(2)
expect(count_data[:projects_with_packages]).to eq(2)
expect(count_data[:packages]).to eq(4)
+ expect(count_data[:user_preferences_user_gitpod_enabled]).to eq(1)
end
it 'gathers object store usage correctly' do
@@ -549,8 +576,17 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do
end
describe '.system_usage_data_monthly' do
+ let_it_be(:project) { create(:project) }
let!(:ud) { build(:usage_data) }
+ before do
+ stub_application_setting(self_monitoring_project: project)
+
+ for_defined_days_back do
+ create(:product_analytics_event, project: project, se_category: 'epics', se_action: 'promote')
+ end
+ end
+
subject { described_class.system_usage_data_monthly }
it 'gathers monthly usage counts correctly' do
@@ -563,6 +599,7 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do
expect(counts_monthly[:personal_snippets]).to eq(1)
expect(counts_monthly[:project_snippets]).to eq(2)
expect(counts_monthly[:packages]).to eq(3)
+ expect(counts_monthly[:promoted_issues]).to eq(1)
end
end
@@ -570,6 +607,7 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do
subject { described_class.usage_counters }
it { is_expected.to include(:kubernetes_agent_gitops_sync) }
+ it { is_expected.to include(:static_site_editor_views) }
end
describe '.usage_data_counters' do
@@ -628,6 +666,7 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do
expect(subject[:gitlab_shared_runners_enabled]).to eq(Gitlab.config.gitlab_ci.shared_runners_enabled)
expect(subject[:web_ide_clientside_preview_enabled]).to eq(Gitlab::CurrentSettings.web_ide_clientside_preview_enabled?)
expect(subject[:grafana_link_enabled]).to eq(Gitlab::CurrentSettings.grafana_enabled?)
+ expect(subject[:gitpod_enabled]).to eq(Gitlab::CurrentSettings.gitpod_enabled?)
end
context 'with embedded Prometheus' do
@@ -657,6 +696,20 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do
expect(subject[:grafana_link_enabled]).to eq(false)
end
end
+
+ context 'with Gitpod' do
+ it 'returns true when is enabled' do
+ stub_application_setting(gitpod_enabled: true)
+
+ expect(subject[:gitpod_enabled]).to eq(true)
+ end
+
+ it 'returns false when is disabled' do
+ stub_application_setting(gitpod_enabled: false)
+
+ expect(subject[:gitpod_enabled]).to eq(false)
+ end
+ end
end
describe '.components_usage_data' do
@@ -670,6 +723,7 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do
expect(subject[:git][:version]).to eq(Gitlab::Git.version)
expect(subject[:database][:adapter]).to eq(Gitlab::Database.adapter_name)
expect(subject[:database][:version]).to eq(Gitlab::Database.version)
+ expect(subject[:database][:pg_system_id]).to eq(Gitlab::Database.system_id)
expect(subject[:mail][:smtp_server]).to eq(ActionMailer::Base.smtp_settings[:address])
expect(subject[:gitaly][:version]).to be_present
expect(subject[:gitaly][:servers]).to be >= 1
@@ -979,9 +1033,9 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do
end
end
- def for_defined_days_back(days: [29, 2])
+ def for_defined_days_back(days: [31, 3])
days.each do |n|
- Timecop.travel(n.days.ago) do
+ travel_to(n.days.ago) do
yield
end
end
@@ -1078,8 +1132,6 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do
subject { described_class.compliance_unique_visits_data }
before do
- described_class.clear_memoization(:unique_visit_service)
-
allow_next_instance_of(::Gitlab::Analytics::UniqueVisits) do |instance|
::Gitlab::Analytics::UniqueVisits.compliance_events.each do |target|
allow(instance).to receive(:unique_visits_for).with(targets: target).and_return(123)
@@ -1110,7 +1162,6 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do
subject { described_class.search_unique_visits_data }
before do
- described_class.clear_memoization(:unique_visit_service)
events = ::Gitlab::UsageDataCounters::HLLRedisCounter.events_for_category('search')
events.each do |event|
allow(::Gitlab::UsageDataCounters::HLLRedisCounter).to receive(:unique_events).with(event_names: event, start_date: 7.days.ago.to_date, end_date: Date.current).and_return(123)
@@ -1136,9 +1187,9 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do
subject { described_class.redis_hll_counters }
let(:categories) { ::Gitlab::UsageDataCounters::HLLRedisCounter.categories }
- let(:ineligible_total_categories) { ['source_code'] }
+ let(:ineligible_total_categories) { %w[source_code testing] }
- it 'has all know_events' do
+ it 'has all known_events' do
expect(subject).to have_key(:redis_hll_counters)
expect(subject[:redis_hll_counters].keys).to match_array(categories)
@@ -1146,11 +1197,13 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do
categories.each do |category|
keys = ::Gitlab::UsageDataCounters::HLLRedisCounter.events_for_category(category)
+ metrics = keys.map { |key| "#{key}_weekly" } + keys.map { |key| "#{key}_monthly" }
+
if ineligible_total_categories.exclude?(category)
- keys.append("#{category}_total_unique_counts_weekly", "#{category}_total_unique_counts_monthly")
+ metrics.append("#{category}_total_unique_counts_weekly", "#{category}_total_unique_counts_monthly")
end
- expect(subject[:redis_hll_counters][category].keys).to match_array(keys)
+ expect(subject[:redis_hll_counters][category].keys).to match_array(metrics)
end
end
end
@@ -1169,6 +1222,8 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do
end
describe '.snowplow_event_counts' do
+ let_it_be(:time_period) { { collector_tstamp: 8.days.ago..1.day.ago } }
+
context 'when self-monitoring project exists' do
let_it_be(:project) { create(:project) }
@@ -1181,14 +1236,14 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do
stub_feature_flags(product_analytics: project)
create(:product_analytics_event, project: project, se_category: 'epics', se_action: 'promote')
- create(:product_analytics_event, project: project, se_category: 'epics', se_action: 'promote', collector_tstamp: 28.days.ago)
+ create(:product_analytics_event, project: project, se_category: 'epics', se_action: 'promote', collector_tstamp: 2.days.ago)
+ create(:product_analytics_event, project: project, se_category: 'epics', se_action: 'promote', collector_tstamp: 9.days.ago)
+
+ create(:product_analytics_event, project: project, se_category: 'foo', se_action: 'bar', collector_tstamp: 2.days.ago)
end
it 'returns promoted_issues for the time period' do
- expect(described_class.snowplow_event_counts[:promoted_issues]).to eq(2)
- expect(described_class.snowplow_event_counts(
- time_period: described_class.last_28_days_time_period(column: :collector_tstamp)
- )[:promoted_issues]).to eq(1)
+ expect(described_class.snowplow_event_counts(time_period)[:promoted_issues]).to eq(1)
end
end
@@ -1198,14 +1253,14 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do
end
it 'returns an empty hash' do
- expect(described_class.snowplow_event_counts).to eq({})
+ expect(described_class.snowplow_event_counts(time_period)).to eq({})
end
end
end
context 'when self-monitoring project does not exist' do
it 'returns an empty hash' do
- expect(described_class.snowplow_event_counts).to eq({})
+ expect(described_class.snowplow_event_counts(time_period)).to eq({})
end
end
end
diff --git a/spec/lib/gitlab/utils/usage_data_spec.rb b/spec/lib/gitlab/utils/usage_data_spec.rb
index 362cbaa78e9..9c0dc69ccd1 100644
--- a/spec/lib/gitlab/utils/usage_data_spec.rb
+++ b/spec/lib/gitlab/utils/usage_data_spec.rb
@@ -212,33 +212,26 @@ RSpec.describe Gitlab::Utils::UsageData do
describe '#track_usage_event' do
let(:value) { '9f302fea-f828-4ca9-aef4-e10bd723c0b3' }
- let(:event_name) { 'my_event' }
+ let(:event_name) { 'incident_management_alert_status_changed' }
let(:unknown_event) { 'unknown' }
let(:feature) { "usage_data_#{event_name}" }
+ before do
+ skip_feature_flags_yaml_validation
+ end
+
context 'with feature enabled' do
before do
stub_feature_flags(feature => true)
end
it 'tracks redis hll event' do
- stub_application_setting(usage_ping_enabled: true)
-
expect(Gitlab::UsageDataCounters::HLLRedisCounter).to receive(:track_event).with(value, event_name)
described_class.track_usage_event(event_name, value)
end
- it 'does not track event when usage ping is not enabled' do
- stub_application_setting(usage_ping_enabled: false)
- expect(Gitlab::UsageDataCounters::HLLRedisCounter).not_to receive(:track_event)
-
- described_class.track_usage_event(event_name, value)
- end
-
it 'raise an error for unknown event' do
- stub_application_setting(usage_ping_enabled: true)
-
expect { described_class.track_usage_event(unknown_event, value) }.to raise_error(Gitlab::UsageDataCounters::HLLRedisCounter::UnknownEvent)
end
end
diff --git a/spec/lib/gitlab/visibility_level_checker_spec.rb b/spec/lib/gitlab/visibility_level_checker_spec.rb
index 833021a22ca..38a7d967c33 100644
--- a/spec/lib/gitlab/visibility_level_checker_spec.rb
+++ b/spec/lib/gitlab/visibility_level_checker_spec.rb
@@ -5,16 +5,13 @@ require 'spec_helper'
RSpec.describe Gitlab::VisibilityLevelChecker do
let(:user) { create(:user) }
let(:project) { create(:project) }
- let(:visibility_level_checker) { }
let(:override_params) { {} }
- subject { described_class.new(user, project, project_params: override_params) }
-
describe '#level_restricted?' do
+ subject(:result) { described_class.new(user, project, project_params: override_params).level_restricted? }
+
context 'when visibility level is allowed' do
it 'returns false with nil for visibility level' do
- result = subject.level_restricted?
-
expect(result.restricted?).to eq(false)
expect(result.visibility_level).to be_nil
end
@@ -25,12 +22,26 @@ RSpec.describe Gitlab::VisibilityLevelChecker do
stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PUBLIC])
end
- it 'returns true and visibility name' do
- project.update!(visibility_level: Gitlab::VisibilityLevel::PUBLIC)
- result = subject.level_restricted?
+ context 'for public project' do
+ before do
+ project.update!(visibility_level: Gitlab::VisibilityLevel::PUBLIC)
+ end
+
+ context 'for non-admin user' do
+ it 'returns true and visibility name' do
+ expect(result.restricted?).to eq(true)
+ expect(result.visibility_level).to eq(Gitlab::VisibilityLevel::PUBLIC)
+ end
+ end
+
+ context 'for admin user' do
+ let(:user) { create(:user, :admin) }
- expect(result.restricted?).to eq(true)
- expect(result.visibility_level).to eq(Gitlab::VisibilityLevel::PUBLIC)
+ it 'returns false and a nil visibility level' do
+ expect(result.restricted?).to eq(false)
+ expect(result.visibility_level).to be_nil
+ end
+ end
end
context 'overridden visibility' do
@@ -50,8 +61,6 @@ RSpec.describe Gitlab::VisibilityLevelChecker do
let(:override_visibility) { 'public' }
it 'returns true and visibility name' do
- result = subject.level_restricted?
-
expect(result.restricted?).to eq(true)
expect(result.visibility_level).to eq(Gitlab::VisibilityLevel::PUBLIC)
end
@@ -61,8 +70,6 @@ RSpec.describe Gitlab::VisibilityLevelChecker do
let(:override_visibility) { 'publik' }
it 'returns false with nil for visibility level' do
- result = subject.level_restricted?
-
expect(result.restricted?).to eq(false)
expect(result.visibility_level).to be_nil
end
@@ -72,8 +79,6 @@ RSpec.describe Gitlab::VisibilityLevelChecker do
let(:override_params) { {} }
it 'returns false with nil for visibility level' do
- result = subject.level_restricted?
-
expect(result.restricted?).to eq(false)
expect(result.visibility_level).to be_nil
end
diff --git a/spec/lib/gitlab/webpack/manifest_spec.rb b/spec/lib/gitlab/webpack/manifest_spec.rb
new file mode 100644
index 00000000000..1427bdd7d4f
--- /dev/null
+++ b/spec/lib/gitlab/webpack/manifest_spec.rb
@@ -0,0 +1,113 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require 'json'
+
+RSpec.describe Gitlab::Webpack::Manifest do
+ let(:manifest) do
+ <<-EOF
+ {
+ "errors": [],
+ "assetsByChunkName": {
+ "entry1": [ "entry1.js", "entry1-a.js" ],
+ "entry2": "entry2.js"
+ }
+ }
+ EOF
+ end
+
+ around do |example|
+ Gitlab::Webpack::Manifest.clear_manifest!
+
+ example.run
+
+ Gitlab::Webpack::Manifest.clear_manifest!
+ end
+
+ shared_examples_for "a valid manifest" do
+ it "returns single entry asset paths from the manifest" do
+ expect(Gitlab::Webpack::Manifest.asset_paths("entry2")).to eq(["/public_path/entry2.js"])
+ end
+
+ it "returns multiple entry asset paths from the manifest" do
+ expect(Gitlab::Webpack::Manifest.asset_paths("entry1")).to eq(["/public_path/entry1.js", "/public_path/entry1-a.js"])
+ end
+
+ it "errors on a missing entry point" do
+ expect { Gitlab::Webpack::Manifest.asset_paths("herp") }.to raise_error(Gitlab::Webpack::Manifest::AssetMissingError)
+ end
+ end
+
+ before do
+ # Test that config variables work while we're here
+ allow(Gitlab.config.webpack.dev_server).to receive_messages(host: 'hostname', port: 2000, https: false)
+ allow(Gitlab.config.webpack).to receive(:manifest_filename).and_return('my_manifest.json')
+ allow(Gitlab.config.webpack).to receive(:public_path).and_return('public_path')
+ allow(Gitlab.config.webpack).to receive(:output_dir).and_return('manifest_output')
+ end
+
+ context "with dev server enabled" do
+ before do
+ allow(Gitlab.config.webpack.dev_server).to receive(:enabled).and_return(true)
+
+ stub_request(:get, "http://hostname:2000/public_path/my_manifest.json").to_return(body: manifest, status: 200)
+ end
+
+ describe ".asset_paths" do
+ it_behaves_like "a valid manifest"
+
+ it "errors if we can't find the manifest" do
+ allow(Gitlab.config.webpack).to receive(:manifest_filename).and_return('broken.json')
+ stub_request(:get, "http://hostname:2000/public_path/broken.json").to_raise(SocketError)
+
+ expect { Gitlab::Webpack::Manifest.asset_paths("entry1") }.to raise_error(Gitlab::Webpack::Manifest::ManifestLoadError)
+ end
+
+ describe "webpack errors" do
+ context "when webpack has 'Module build failed' errors in its manifest" do
+ it "errors" do
+ error_manifest = Gitlab::Json.parse(manifest).merge("errors" => [
+ "somethingModule build failed something",
+ "I am an error"
+ ]).to_json
+ stub_request(:get, "http://hostname:2000/public_path/my_manifest.json").to_return(body: error_manifest, status: 200)
+
+ expect { Gitlab::Webpack::Manifest.asset_paths("entry1") }.to raise_error(Gitlab::Webpack::Manifest::WebpackError)
+ end
+ end
+
+ context "when webpack does not have 'Module build failed' errors in its manifest" do
+ it "does not error" do
+ error_manifest = Gitlab::Json.parse(manifest).merge("errors" => ["something went wrong"]).to_json
+ stub_request(:get, "http://hostname:2000/public_path/my_manifest.json").to_return(body: error_manifest, status: 200)
+
+ expect { Gitlab::Webpack::Manifest.asset_paths("entry1") }.not_to raise_error
+ end
+ end
+
+ it "does not error if errors is present but empty" do
+ error_manifest = Gitlab::Json.parse(manifest).merge("errors" => []).to_json
+ stub_request(:get, "http://hostname:2000/public_path/my_manifest.json").to_return(body: error_manifest, status: 200)
+ expect { Gitlab::Webpack::Manifest.asset_paths("entry1") }.not_to raise_error
+ end
+ end
+ end
+ end
+
+ context "with dev server disabled" do
+ before do
+ allow(Gitlab.config.webpack.dev_server).to receive(:enabled).and_return(false)
+ allow(File).to receive(:read).with(::Rails.root.join("manifest_output/my_manifest.json")).and_return(manifest)
+ end
+
+ describe ".asset_paths" do
+ it_behaves_like "a valid manifest"
+
+ it "errors if we can't find the manifest" do
+ allow(Gitlab.config.webpack).to receive(:manifest_filename).and_return('broken.json')
+ allow(File).to receive(:read).with(::Rails.root.join("manifest_output/broken.json")).and_raise(Errno::ENOENT)
+ expect { Gitlab::Webpack::Manifest.asset_paths("entry1") }.to raise_error(Gitlab::Webpack::Manifest::ManifestLoadError)
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/workhorse_spec.rb b/spec/lib/gitlab/workhorse_spec.rb
index e9733851590..9662ad13631 100644
--- a/spec/lib/gitlab/workhorse_spec.rb
+++ b/spec/lib/gitlab/workhorse_spec.rb
@@ -54,12 +54,44 @@ RSpec.describe Gitlab::Workhorse do
commit_id: metadata['CommitId'],
prefix: metadata['ArchivePrefix'],
format: Gitaly::GetArchiveRequest::Format::ZIP,
- path: path
+ path: path,
+ include_lfs_blobs: true
).to_proto
)
}.deep_stringify_keys)
end
+ context 'when include_lfs_blobs_in_archive is disabled' do
+ before do
+ stub_feature_flags(include_lfs_blobs_in_archive: false)
+ end
+
+ it 'sets include_lfs_blobs to false' do
+ key, command, params = decode_workhorse_header(subject)
+
+ expect(key).to eq('Gitlab-Workhorse-Send-Data')
+ expect(command).to eq('git-archive')
+ expect(params).to eq({
+ 'GitalyServer' => {
+ features: { 'gitaly-feature-foobar' => 'true' },
+ address: Gitlab::GitalyClient.address(project.repository_storage),
+ token: Gitlab::GitalyClient.token(project.repository_storage)
+ },
+ 'ArchivePath' => metadata['ArchivePath'],
+ 'GetArchiveRequest' => Base64.encode64(
+ Gitaly::GetArchiveRequest.new(
+ repository: repository.gitaly_repository,
+ commit_id: metadata['CommitId'],
+ prefix: metadata['ArchivePrefix'],
+ format: Gitaly::GetArchiveRequest::Format::ZIP,
+ path: path,
+ include_lfs_blobs: false
+ ).to_proto
+ )
+ }.deep_stringify_keys)
+ end
+ end
+
context 'when archive caching is disabled' do
let(:cache_disabled) { true }
diff --git a/spec/lib/gitlab_danger_spec.rb b/spec/lib/gitlab_danger_spec.rb
index b534823a888..e332647cf8a 100644
--- a/spec/lib/gitlab_danger_spec.rb
+++ b/spec/lib/gitlab_danger_spec.rb
@@ -9,7 +9,7 @@ RSpec.describe GitlabDanger do
describe '.local_warning_message' do
it 'returns an informational message with rules that can run' do
- expect(described_class.local_warning_message).to eq('==> Only the following Danger rules can be run locally: changes_size, documentation, frozen_string, duplicate_yarn_dependencies, prettier, eslint, karma, database, commit_messages, telemetry, utility_css, pajamas')
+ expect(described_class.local_warning_message).to eq('==> Only the following Danger rules can be run locally: changes_size, documentation, frozen_string, duplicate_yarn_dependencies, prettier, eslint, karma, database, commit_messages, product_analytics, utility_css, pajamas')
end
end
diff --git a/spec/lib/google_api/auth_spec.rb b/spec/lib/google_api/auth_spec.rb
index eeb99bfbb6c..92cb9e494ac 100644
--- a/spec/lib/google_api/auth_spec.rb
+++ b/spec/lib/google_api/auth_spec.rb
@@ -12,12 +12,12 @@ RSpec.describe GoogleApi::Auth do
end
describe '#authorize_url' do
- subject { client.authorize_url }
+ subject { Addressable::URI.parse(client.authorize_url) }
it 'returns authorize_url' do
- is_expected.to start_with('https://accounts.google.com/o/oauth2')
- is_expected.to include(URI.encode(redirect_uri, URI::PATTERN::RESERVED))
- is_expected.to include(URI.encode(redirect_to, URI::PATTERN::RESERVED))
+ expect(subject.to_s).to start_with('https://accounts.google.com/o/oauth2')
+ expect(subject.query_values['state']).to eq(redirect_to)
+ expect(subject.query_values['redirect_uri']).to eq(redirect_uri)
end
end
diff --git a/spec/lib/grafana/time_window_spec.rb b/spec/lib/grafana/time_window_spec.rb
index 9ee65c6cf20..0657bed7b28 100644
--- a/spec/lib/grafana/time_window_spec.rb
+++ b/spec/lib/grafana/time_window_spec.rb
@@ -7,7 +7,7 @@ RSpec.describe Grafana::TimeWindow do
let(:to) { '1552828200000' }
around do |example|
- Timecop.freeze(Time.utc(2019, 3, 17, 13, 10)) { example.run }
+ travel_to(Time.utc(2019, 3, 17, 13, 10)) { example.run }
end
describe '#formatted' do
@@ -37,7 +37,7 @@ RSpec.describe Grafana::RangeWithDefaults do
let(:to) { Grafana::Timestamp.from_ms_since_epoch('1552828200000') }
around do |example|
- Timecop.freeze(Time.utc(2019, 3, 17, 13, 10)) { example.run }
+ travel_to(Time.utc(2019, 3, 17, 13, 10)) { example.run }
end
describe '#to_hash' do
@@ -82,7 +82,7 @@ RSpec.describe Grafana::Timestamp do
let(:timestamp) { Time.at(1552799400) }
around do |example|
- Timecop.freeze(Time.utc(2019, 3, 17, 13, 10)) { example.run }
+ travel_to(Time.utc(2019, 3, 17, 13, 10)) { example.run }
end
describe '#formatted' do
diff --git a/spec/lib/marginalia_spec.rb b/spec/lib/marginalia_spec.rb
index a920f598c24..fa0cd214c7e 100644
--- a/spec/lib/marginalia_spec.rb
+++ b/spec/lib/marginalia_spec.rb
@@ -24,18 +24,6 @@ RSpec.describe 'Marginalia spec' do
end
end
- def stub_feature(value)
- allow(Gitlab::Marginalia).to receive(:cached_feature_enabled?).and_return(value)
- end
-
- def make_request(correlation_id)
- request_env = Rack::MockRequest.env_for('/')
-
- ::Labkit::Correlation::CorrelationId.use_id(correlation_id) do
- MarginaliaTestController.action(:first_user).call(request_env)
- end
- end
-
describe 'For rails web requests' do
let(:correlation_id) { SecureRandom.uuid }
let(:recorded) { ActiveRecord::QueryRecorder.new { make_request(correlation_id) } }
@@ -149,4 +137,17 @@ RSpec.describe 'Marginalia spec' do
end
end
end
+
+ def stub_feature(value)
+ stub_feature_flags(marginalia: value)
+ Gitlab::Marginalia.set_enabled_from_feature_flag
+ end
+
+ def make_request(correlation_id)
+ request_env = Rack::MockRequest.env_for('/')
+
+ ::Labkit::Correlation::CorrelationId.use_id(correlation_id) do
+ MarginaliaTestController.action(:first_user).call(request_env)
+ end
+ end
end
diff --git a/spec/lib/pager_duty/webhook_payload_parser_spec.rb b/spec/lib/pager_duty/webhook_payload_parser_spec.rb
index 0010165318d..54c61b9121c 100644
--- a/spec/lib/pager_duty/webhook_payload_parser_spec.rb
+++ b/spec/lib/pager_duty/webhook_payload_parser_spec.rb
@@ -1,6 +1,7 @@
# frozen_string_literal: true
require 'fast_spec_helper'
+require 'json_schemer'
RSpec.describe PagerDuty::WebhookPayloadParser do
describe '.call' do
@@ -8,36 +9,36 @@ RSpec.describe PagerDuty::WebhookPayloadParser do
File.read(File.join(File.dirname(__FILE__), '../../fixtures/pager_duty/webhook_incident_trigger.json'))
end
+ let(:triggered_event) do
+ {
+ 'event' => 'incident.trigger',
+ 'incident' => {
+ 'url' => 'https://webdemo.pagerduty.com/incidents/PRORDTY',
+ 'incident_number' => 33,
+ 'title' => 'My new incident',
+ 'status' => 'triggered',
+ 'created_at' => '2017-09-26T15:14:36Z',
+ 'urgency' => 'high',
+ 'incident_key' => nil,
+ 'assignees' => [{
+ 'summary' => 'Laura Haley',
+ 'url' => 'https://webdemo.pagerduty.com/users/P553OPV'
+ }],
+ 'impacted_services' => [{
+ 'summary' => 'Production XDB Cluster',
+ 'url' => 'https://webdemo.pagerduty.com/services/PN49J75'
+ }]
+ }
+ }
+ end
+
subject(:parse) { described_class.call(payload) }
context 'when payload is a correct PagerDuty payload' do
let(:payload) { Gitlab::Json.parse(fixture_file) }
it 'returns parsed payload' do
- is_expected.to eq(
- [
- {
- 'event' => 'incident.trigger',
- 'incident' => {
- 'url' => 'https://webdemo.pagerduty.com/incidents/PRORDTY',
- 'incident_number' => 33,
- 'title' => 'My new incident',
- 'status' => 'triggered',
- 'created_at' => '2017-09-26T15:14:36Z',
- 'urgency' => 'high',
- 'incident_key' => nil,
- 'assignees' => [{
- 'summary' => 'Laura Haley',
- 'url' => 'https://webdemo.pagerduty.com/users/P553OPV'
- }],
- 'impacted_services' => [{
- 'summary' => 'Production XDB Cluster',
- 'url' => 'https://webdemo.pagerduty.com/services/PN49J75'
- }]
- }
- }
- ]
- )
+ is_expected.to eq([triggered_event])
end
context 'when assignments summary and html_url are blank' do
@@ -69,11 +70,42 @@ RSpec.describe PagerDuty::WebhookPayloadParser do
end
end
- context 'when payload has no incidents' do
+ context 'when payload schema is invalid' do
let(:payload) { { 'messages' => [{ 'event' => 'incident.trigger' }] } }
it 'returns payload with blank incidents' do
- is_expected.to eq([{ 'event' => 'incident.trigger', 'incident' => {} }])
+ is_expected.to eq([])
+ end
+ end
+
+ context 'when payload consists of two messages' do
+ context 'when one of the messages has no incident data' do
+ let(:payload) do
+ valid_payload = Gitlab::Json.parse(fixture_file)
+ event = { 'event' => 'incident.trigger' }
+ valid_payload['messages'] = valid_payload['messages'].append(event)
+ valid_payload
+ end
+
+ it 'returns parsed payload with valid events only' do
+ is_expected.to eq([triggered_event])
+ end
+ end
+
+ context 'when one of the messages has unknown event' do
+ let(:payload) do
+ valid_payload = Gitlab::Json.parse(fixture_file)
+ event = { 'event' => 'incident.unknown', 'incident' => valid_payload['messages'].first['incident'] }
+ valid_payload['messages'] = valid_payload['messages'].append(event)
+ valid_payload
+ end
+
+ it 'returns parsed payload' do
+ unknown_event = triggered_event.dup
+ unknown_event['event'] = 'incident.unknown'
+
+ is_expected.to contain_exactly(triggered_event, unknown_event)
+ end
end
end
end
diff --git a/spec/lib/safe_zip/extract_spec.rb b/spec/lib/safe_zip/extract_spec.rb
index 30b7e1cdd2c..443430b267d 100644
--- a/spec/lib/safe_zip/extract_spec.rb
+++ b/spec/lib/safe_zip/extract_spec.rb
@@ -15,11 +15,7 @@ RSpec.describe SafeZip::Extract do
describe '#extract' do
subject { object.extract(directories: directories, to: target_path) }
- shared_examples 'extracts archive' do |param|
- before do
- stub_feature_flags(safezip_use_rubyzip: param)
- end
-
+ shared_examples 'extracts archive' do
it 'does extract archive' do
subject
@@ -28,11 +24,7 @@ RSpec.describe SafeZip::Extract do
end
end
- shared_examples 'fails to extract archive' do |param|
- before do
- stub_feature_flags(safezip_use_rubyzip: param)
- end
-
+ shared_examples 'fails to extract archive' do
it 'does not extract archive' do
expect { subject }.to raise_error(SafeZip::Extract::Error)
end
@@ -42,13 +34,7 @@ RSpec.describe SafeZip::Extract do
context "when using #{name} archive" do
let(:archive_name) { name }
- context 'for RubyZip' do
- it_behaves_like 'extracts archive', true
- end
-
- context 'for UnZip' do
- it_behaves_like 'extracts archive', false
- end
+ it_behaves_like 'extracts archive'
end
end
@@ -56,13 +42,7 @@ RSpec.describe SafeZip::Extract do
context "when using #{name} archive" do
let(:archive_name) { name }
- context 'for RubyZip' do
- it_behaves_like 'fails to extract archive', true
- end
-
- context 'for UnZip (UNSAFE)' do
- it_behaves_like 'extracts archive', false
- end
+ it_behaves_like 'fails to extract archive'
end
end
@@ -70,13 +50,7 @@ RSpec.describe SafeZip::Extract do
let(:archive_name) { 'valid-simple.zip' }
let(:directories) { %w(non/existing) }
- context 'for RubyZip' do
- it_behaves_like 'fails to extract archive', true
- end
-
- context 'for UnZip' do
- it_behaves_like 'fails to extract archive', false
- end
+ it_behaves_like 'fails to extract archive'
end
end
end
diff --git a/spec/mailers/abuse_report_mailer_spec.rb b/spec/mailers/abuse_report_mailer_spec.rb
index 4eb616722ac..061f972fd35 100644
--- a/spec/mailers/abuse_report_mailer_spec.rb
+++ b/spec/mailers/abuse_report_mailer_spec.rb
@@ -7,7 +7,7 @@ RSpec.describe AbuseReportMailer do
describe '.notify' do
before do
- stub_application_setting(admin_notification_email: 'admin@example.com')
+ stub_application_setting(abuse_notification_email: 'admin@example.com')
end
let(:report) { create(:abuse_report) }
@@ -17,8 +17,8 @@ RSpec.describe AbuseReportMailer do
it_behaves_like 'appearance header and footer enabled'
it_behaves_like 'appearance header and footer not enabled'
- context 'with admin_notification_email set' do
- it 'sends to the admin_notification_email' do
+ context 'with abuse_notification_email set' do
+ it 'sends to the abuse_notification_email' do
is_expected.to deliver_to 'admin@example.com'
end
@@ -27,9 +27,9 @@ RSpec.describe AbuseReportMailer do
end
end
- context 'with no admin_notification_email set' do
+ context 'with no abuse_notification_email set' do
it 'returns early' do
- stub_application_setting(admin_notification_email: nil)
+ stub_application_setting(abuse_notification_email: nil)
expect { described_class.notify(spy).deliver_now }
.not_to change { ActionMailer::Base.deliveries.count }
diff --git a/spec/mailers/emails/merge_requests_spec.rb b/spec/mailers/emails/merge_requests_spec.rb
index 477fb16400a..9235a946394 100644
--- a/spec/mailers/emails/merge_requests_spec.rb
+++ b/spec/mailers/emails/merge_requests_spec.rb
@@ -33,4 +33,37 @@ RSpec.describe Emails::MergeRequests do
expect(subject).to have_content current_user.name
end
end
+
+ describe '#merge_requests_csv_email' do
+ let(:user) { create(:user) }
+ let(:project) { create(:project) }
+ let(:merge_requests) { create_list(:merge_request, 10) }
+ let(:export_status) do
+ {
+ rows_expected: 10,
+ rows_written: 10,
+ truncated: false
+ }
+ end
+
+ let(:csv_data) { MergeRequests::ExportCsvService.new(MergeRequest.all, project).csv_data }
+
+ subject { Notify.merge_requests_csv_email(user, project, csv_data, export_status) }
+
+ it { expect(subject.subject).to eq("#{project.name} | Exported merge requests") }
+ it { expect(subject.to).to contain_exactly(user.notification_email_for(project.group)) }
+ it { expect(subject).to have_content('Your CSV export of 10 merge requests from project')}
+
+ context 'when truncated' do
+ let(:export_status) do
+ {
+ rows_expected: 10,
+ rows_written: 10,
+ truncated: true
+ }
+ end
+
+ it { expect(subject).to have_content('This attachment has been truncated to avoid exceeding the maximum allowed attachment size of 15MB.') }
+ end
+ end
end
diff --git a/spec/mailers/emails/projects_spec.rb b/spec/mailers/emails/projects_spec.rb
index 599f62a8113..aa5947bf68e 100644
--- a/spec/mailers/emails/projects_spec.rb
+++ b/spec/mailers/emails/projects_spec.rb
@@ -30,107 +30,118 @@ RSpec.describe Emails::Projects do
let_it_be(:user) { create(:user) }
describe '#prometheus_alert_fired_email' do
+ let(:default_title) { Gitlab::AlertManagement::Payload::Generic::DEFAULT_TITLE }
+ let(:payload) { { 'startsAt' => Time.now.rfc3339 } }
+ let(:alert_attributes) { build(:alert_management_alert, :from_payload, payload: payload, project: project).attributes }
+
subject do
- Notify.prometheus_alert_fired_email(project.id, user.id, alert_params)
+ Notify.prometheus_alert_fired_email(project.id, user.id, alert_attributes)
end
- let(:alert_params) do
- { 'startsAt' => Time.now.rfc3339 }
+ context 'missing required attributes' do
+ let(:alert_attributes) { build(:alert_management_alert, :prometheus, :from_payload, payload: payload, project: project).attributes }
+
+ it_behaves_like 'no email'
end
- context 'with a gitlab alert' do
- before do
- alert_params['labels'] = { 'gitlab_alert_id' => alert.prometheus_metric_id.to_s }
- end
+ context 'with minimum required attributes' do
+ let(:payload) { {} }
- let(:title) do
- "#{alert.title} #{alert.computed_operator} #{alert.threshold}"
- end
+ it_behaves_like 'an email sent from GitLab'
+ it_behaves_like 'it should not have Gmail Actions links'
+ it_behaves_like 'a user cannot unsubscribe through footer link'
- let(:metrics_url) do
- metrics_project_environment_url(project, environment)
+ it 'has expected subject' do
+ is_expected.to have_subject("#{project.name} | Alert: #{default_title}")
end
- let(:environment) { alert.environment }
+ it 'has expected content' do
+ is_expected.to have_body_text('An alert has been triggered')
+ is_expected.to have_body_text(project.full_path)
+ is_expected.not_to have_body_text('Description:')
+ is_expected.not_to have_body_text('Environment:')
+ is_expected.not_to have_body_text('Metric:')
+ end
+ end
- let!(:alert) { create(:prometheus_alert, project: project) }
+ context 'with description' do
+ let(:payload) { { 'description' => 'alert description' } }
it_behaves_like 'an email sent from GitLab'
it_behaves_like 'it should not have Gmail Actions links'
it_behaves_like 'a user cannot unsubscribe through footer link'
it 'has expected subject' do
- is_expected.to have_subject("#{project.name} | Alert: #{environment.name}: #{title} for 5 minutes")
+ is_expected.to have_subject("#{project.name} | Alert: #{default_title}")
end
it 'has expected content' do
is_expected.to have_body_text('An alert has been triggered')
is_expected.to have_body_text(project.full_path)
- is_expected.to have_body_text('Environment:')
- is_expected.to have_body_text(environment.name)
- is_expected.to have_body_text('Metric:')
- is_expected.to have_body_text(alert.full_query)
- is_expected.to have_body_text(metrics_url)
+ is_expected.to have_body_text('Description:')
+ is_expected.to have_body_text('alert description')
+ is_expected.not_to have_body_text('Environment:')
+ is_expected.not_to have_body_text('Metric:')
end
-
- it_behaves_like 'shows the incident issues url'
end
- context 'with no payload' do
- let(:alert_params) { {} }
+ context 'with environment' do
+ let_it_be(:environment) { create(:environment, project: project) }
+ let(:payload) { { 'gitlab_environment_name' => environment.name } }
+ let(:metrics_url) { metrics_project_environment_url(project, environment) }
- it_behaves_like 'no email'
- end
+ it_behaves_like 'an email sent from GitLab'
+ it_behaves_like 'it should not have Gmail Actions links'
+ it_behaves_like 'a user cannot unsubscribe through footer link'
- context 'with an unknown alert' do
- before do
- alert_params['labels'] = { 'gitlab_alert_id' => 'unknown' }
+ it 'has expected subject' do
+ is_expected.to have_subject("#{project.name} | Alert: #{environment.name}: #{default_title}")
end
- it_behaves_like 'no email'
+ it 'has expected content' do
+ is_expected.to have_body_text('An alert has been triggered')
+ is_expected.to have_body_text(project.full_path)
+ is_expected.to have_body_text('Environment:')
+ is_expected.to have_body_text(environment.name)
+ is_expected.not_to have_body_text('Description:')
+ is_expected.not_to have_body_text('Metric:')
+ end
end
- context 'with an external alert' do
- let(:title) { 'alert title' }
+ context 'with gitlab alerting rule' do
+ let_it_be(:prometheus_alert) { create(:prometheus_alert, project: project) }
+ let_it_be(:environment) { prometheus_alert.environment }
- let(:metrics_url) do
- metrics_project_environments_url(project)
- end
+ let(:alert_attributes) { build(:alert_management_alert, :prometheus, :from_payload, payload: payload, project: project).attributes }
+ let(:title) { "#{prometheus_alert.title} #{prometheus_alert.computed_operator} #{prometheus_alert.threshold}" }
+ let(:metrics_url) { metrics_project_environment_url(project, environment) }
before do
- alert_params['annotations'] = { 'title' => title }
- alert_params['generatorURL'] = 'http://localhost:9090/graph?g0.expr=vector%281%29&g0.tab=1'
+ payload['labels'] = {
+ 'gitlab_alert_id' => prometheus_alert.prometheus_metric_id,
+ 'alertname' => prometheus_alert.title
+ }
end
it_behaves_like 'an email sent from GitLab'
it_behaves_like 'it should not have Gmail Actions links'
it_behaves_like 'a user cannot unsubscribe through footer link'
+ it_behaves_like 'shows the incident issues url'
it 'has expected subject' do
- is_expected.to have_subject("#{project.name} | Alert: #{title}")
+ is_expected.to have_subject("#{project.name} | Alert: #{environment.name}: #{title} for 5 minutes")
end
it 'has expected content' do
is_expected.to have_body_text('An alert has been triggered')
is_expected.to have_body_text(project.full_path)
+ is_expected.to have_body_text('Environment:')
+ is_expected.to have_body_text(environment.name)
+ is_expected.to have_body_text('Metric:')
+ is_expected.to have_body_text(prometheus_alert.full_query)
+ is_expected.to have_body_text(metrics_url)
is_expected.not_to have_body_text('Description:')
- is_expected.not_to have_body_text('Environment:')
end
-
- context 'with annotated description' do
- let(:description) { 'description' }
-
- before do
- alert_params['annotations']['description'] = description
- end
-
- it 'shows the description' do
- is_expected.to have_body_text('Description:')
- is_expected.to have_body_text(description)
- end
- end
-
- it_behaves_like 'shows the incident issues url'
end
end
end
diff --git a/spec/mailers/notify_spec.rb b/spec/mailers/notify_spec.rb
index b9f95a9eb00..8604939ead9 100644
--- a/spec/mailers/notify_spec.rb
+++ b/spec/mailers/notify_spec.rb
@@ -1508,12 +1508,44 @@ RSpec.describe Notify do
)
end
- describe 'group invitation' do
+ describe 'invitations' do
let(:owner) { create(:user).tap { |u| group.add_user(u, Gitlab::Access::OWNER) } }
let(:group_member) { invite_to_group(group, inviter: inviter) }
let(:inviter) { owner }
- subject { described_class.member_invited_email('group', group_member.id, group_member.invite_token) }
+ subject { described_class.member_invited_email('Group', group_member.id, group_member.invite_token) }
+
+ shared_examples "tracks the 'sent' event for the invitation reminders experiment" do
+ before do
+ stub_experiment(invitation_reminders: true)
+ allow(Gitlab::Experimentation).to receive(:enabled_for_attribute?).with(:invitation_reminders, group_member.invite_email).and_return(experimental_group)
+ end
+
+ it "tracks the 'sent' event", :snowplow do
+ subject.deliver_now
+
+ expect_snowplow_event(
+ category: 'Growth::Acquisition::Experiment::InvitationReminders',
+ label: Digest::MD5.hexdigest(group_member.to_global_id.to_s),
+ property: experimental_group ? 'experimental_group' : 'control_group',
+ action: 'sent'
+ )
+ end
+ end
+
+ describe 'tracking for the invitation reminders experiment' do
+ context 'when invite email is in the experimental group' do
+ let(:experimental_group) { true }
+
+ it_behaves_like "tracks the 'sent' event for the invitation reminders experiment"
+ end
+
+ context 'when invite email is in the control group' do
+ let(:experimental_group) { false }
+
+ it_behaves_like "tracks the 'sent' event for the invitation reminders experiment"
+ end
+ end
context 'when invite_email_experiment is disabled' do
before do
@@ -1608,6 +1640,88 @@ RSpec.describe Notify do
end
end
+ describe 'group invitation reminders' do
+ let_it_be(:inviter) { create(:user).tap { |u| group.add_user(u, Gitlab::Access::OWNER) } }
+
+ let(:group_member) { invite_to_group(group, inviter: inviter) }
+
+ subject { described_class.member_invited_reminder_email('Group', group_member.id, group_member.invite_token, reminder_index) }
+
+ describe 'not sending a reminder' do
+ let(:reminder_index) { 0 }
+
+ context 'member does not exist' do
+ let(:group_member) { double(id: nil, invite_token: nil) }
+
+ it_behaves_like 'no email is sent'
+ end
+
+ context 'member is not created by a user' do
+ before do
+ group_member.update(created_by: nil)
+ end
+
+ it_behaves_like 'no email is sent'
+ end
+
+ context 'member is a known user' do
+ before do
+ group_member.update(user: create(:user))
+ end
+
+ it_behaves_like 'no email is sent'
+ end
+ end
+
+ describe 'the first reminder' do
+ let(:reminder_index) { 0 }
+
+ it_behaves_like 'an email sent from GitLab'
+ it_behaves_like 'it should not have Gmail Actions links'
+ it_behaves_like 'a user cannot unsubscribe through footer link'
+
+ it 'contains all the useful information' do
+ is_expected.to have_subject "#{inviter.name}'s invitation to GitLab is pending"
+ is_expected.to have_body_text group.human_name
+ is_expected.to have_body_text group_member.human_access.downcase
+ is_expected.to have_body_text invite_url(group_member.invite_token)
+ is_expected.to have_body_text decline_invite_url(group_member.invite_token)
+ end
+ end
+
+ describe 'the second reminder' do
+ let(:reminder_index) { 1 }
+
+ it_behaves_like 'an email sent from GitLab'
+ it_behaves_like 'it should not have Gmail Actions links'
+ it_behaves_like 'a user cannot unsubscribe through footer link'
+
+ it 'contains all the useful information' do
+ is_expected.to have_subject "#{inviter.name} is waiting for you to join GitLab"
+ is_expected.to have_body_text group.human_name
+ is_expected.to have_body_text group_member.human_access.downcase
+ is_expected.to have_body_text invite_url(group_member.invite_token)
+ is_expected.to have_body_text decline_invite_url(group_member.invite_token)
+ end
+ end
+
+ describe 'the third reminder' do
+ let(:reminder_index) { 2 }
+
+ it_behaves_like 'an email sent from GitLab'
+ it_behaves_like 'it should not have Gmail Actions links'
+ it_behaves_like 'a user cannot unsubscribe through footer link'
+
+ it 'contains all the useful information' do
+ is_expected.to have_subject "#{inviter.name} is still waiting for you to join GitLab"
+ is_expected.to have_body_text group.human_name
+ is_expected.to have_body_text group_member.human_access.downcase
+ is_expected.to have_body_text invite_url(group_member.invite_token)
+ is_expected.to have_body_text decline_invite_url(group_member.invite_token)
+ end
+ end
+ end
+
describe 'group invitation accepted' do
let(:invited_user) { create(:user, name: 'invited user') }
let(:owner) { create(:user).tap { |u| group.add_user(u, Gitlab::Access::OWNER) } }
diff --git a/spec/migrations/20200929052138_create_initial_versions_for_pre_versioning_terraform_states_spec.rb b/spec/migrations/20200929052138_create_initial_versions_for_pre_versioning_terraform_states_spec.rb
new file mode 100644
index 00000000000..1a618712b32
--- /dev/null
+++ b/spec/migrations/20200929052138_create_initial_versions_for_pre_versioning_terraform_states_spec.rb
@@ -0,0 +1,46 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require Rails.root.join('db', 'post_migrate', '20200929052138_create_initial_versions_for_pre_versioning_terraform_states.rb')
+
+RSpec.describe CreateInitialVersionsForPreVersioningTerraformStates do
+ let(:namespace) { table(:namespaces).create!(name: 'terraform', path: 'terraform') }
+ let(:project) { table(:projects).create!(id: 1, namespace_id: namespace.id) }
+ let(:terraform_state_versions) { table(:terraform_state_versions) }
+
+ def create_state!(project, versioning_enabled:)
+ table(:terraform_states).create!(
+ project_id: project.id,
+ uuid: 'uuid',
+ file_store: 2,
+ file: 'state.tfstate',
+ versioning_enabled: versioning_enabled
+ )
+ end
+
+ describe '#up' do
+ context 'for a state that is already versioned' do
+ let!(:terraform_state) { create_state!(project, versioning_enabled: true) }
+
+ it 'does not insert a version record' do
+ expect { migrate! }.not_to change { terraform_state_versions.count }
+ end
+ end
+
+ context 'for a state that is not yet versioned' do
+ let!(:terraform_state) { create_state!(project, versioning_enabled: false) }
+
+ it 'creates a version using the current state data' do
+ expect { migrate! }.to change { terraform_state_versions.count }.by(1)
+
+ migrated_version = terraform_state_versions.last
+ expect(migrated_version.terraform_state_id).to eq(terraform_state.id)
+ expect(migrated_version.version).to be_zero
+ expect(migrated_version.file_store).to eq(terraform_state.file_store)
+ expect(migrated_version.file).to eq(terraform_state.file)
+ expect(migrated_version.created_at).to be_present
+ expect(migrated_version.updated_at).to be_present
+ end
+ end
+ end
+end
diff --git a/spec/migrations/20201014205300_drop_backfill_jira_tracker_deployment_type_jobs_spec.rb b/spec/migrations/20201014205300_drop_backfill_jira_tracker_deployment_type_jobs_spec.rb
new file mode 100644
index 00000000000..134bea6b666
--- /dev/null
+++ b/spec/migrations/20201014205300_drop_backfill_jira_tracker_deployment_type_jobs_spec.rb
@@ -0,0 +1,58 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require Rails.root.join('db', 'migrate', '20201014205300_drop_backfill_jira_tracker_deployment_type_jobs.rb')
+
+RSpec.describe DropBackfillJiraTrackerDeploymentTypeJobs, :sidekiq, :redis, schema: 2020_10_14_205300 do
+ subject(:migration) { described_class.new }
+
+ describe '#up' do
+ let(:retry_set) { Sidekiq::RetrySet.new }
+ let(:scheduled_set) { Sidekiq::ScheduledSet.new }
+
+ context 'there are only affected jobs on the queue' do
+ let(:payload) { { 'class' => ::BackgroundMigrationWorker, 'args' => [described_class::DROPPED_JOB_CLASS, 1] } }
+ let(:queue_payload) { payload.merge('queue' => described_class::QUEUE) }
+
+ it 'removes enqueued BackfillJiraTrackerDeploymentType background jobs' do
+ Sidekiq::Testing.disable! do # https://github.com/mperham/sidekiq/wiki/testing#api Sidekiq's API does not have a testing mode
+ retry_set.schedule(1.hour.from_now, payload)
+ scheduled_set.schedule(1.hour.from_now, payload)
+ Sidekiq::Client.push(queue_payload)
+
+ expect { migration.up }.to change { Sidekiq::Queue.new(described_class::QUEUE).size }.from(1).to(0)
+ expect(retry_set.size).to eq(0)
+ expect(scheduled_set.size).to eq(0)
+ end
+ end
+ end
+
+ context 'there are not any affected jobs on the queue' do
+ let(:payload) { { 'class' => ::BackgroundMigrationWorker, 'args' => ['SomeOtherClass', 1] } }
+ let(:queue_payload) { payload.merge('queue' => described_class::QUEUE) }
+
+ it 'skips other enqueued jobs' do
+ Sidekiq::Testing.disable! do
+ retry_set.schedule(1.hour.from_now, payload)
+ scheduled_set.schedule(1.hour.from_now, payload)
+ Sidekiq::Client.push(queue_payload)
+
+ expect { migration.up }.not_to change { Sidekiq::Queue.new(described_class::QUEUE).size }
+ expect(retry_set.size).to eq(1)
+ expect(scheduled_set.size).to eq(1)
+ end
+ end
+ end
+
+ context 'other queues' do
+ it 'does not modify them' do
+ Sidekiq::Testing.disable! do
+ Sidekiq::Client.push('queue' => 'other', 'class' => ::BackgroundMigrationWorker, 'args' => ['SomeOtherClass', 1])
+ Sidekiq::Client.push('queue' => 'other', 'class' => ::BackgroundMigrationWorker, 'args' => [described_class::DROPPED_JOB_CLASS, 1])
+
+ expect { migration.up }.not_to change { Sidekiq::Queue.new('other').size }
+ end
+ end
+ end
+ end
+end
diff --git a/spec/migrations/add_partial_index_to_ci_builds_table_on_user_id_name_spec.rb b/spec/migrations/add_partial_index_to_ci_builds_table_on_user_id_name_spec.rb
new file mode 100644
index 00000000000..018d48bea66
--- /dev/null
+++ b/spec/migrations/add_partial_index_to_ci_builds_table_on_user_id_name_spec.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require Rails.root.join('db', 'post_migrate', '20200908064229_add_partial_index_to_ci_builds_table_on_user_id_name.rb')
+
+RSpec.describe AddPartialIndexToCiBuildsTableOnUserIdName do
+ let(:migration) { described_class.new }
+
+ describe '#up' do
+ it 'creates temporary partial index on type' do
+ expect { migration.up }.to change { migration.index_exists?(:ci_builds, [:user_id, :name], name: described_class::INDEX_NAME) }.from(false).to(true)
+ end
+ end
+
+ describe '#down' do
+ it 'removes temporary partial index on type' do
+ migration.up
+
+ expect { migration.down }.to change { migration.index_exists?(:ci_builds, [:user_id, :name], name: described_class::INDEX_NAME) }.from(true).to(false)
+ end
+ end
+end
diff --git a/spec/migrations/backfill_status_page_published_incidents_spec.rb b/spec/migrations/backfill_status_page_published_incidents_spec.rb
index 2b1ab891038..674484cdf0a 100644
--- a/spec/migrations/backfill_status_page_published_incidents_spec.rb
+++ b/spec/migrations/backfill_status_page_published_incidents_spec.rb
@@ -37,7 +37,7 @@ RSpec.describe BackfillStatusPagePublishedIncidents, :migration do
end
it 'creates a StatusPage::PublishedIncident record for each published issue' do
- Timecop.freeze(current_time) do
+ travel_to(current_time) do
expect(incidents.all).to be_empty
migrate!
diff --git a/spec/migrations/cleanup_group_import_states_with_null_user_id_spec.rb b/spec/migrations/cleanup_group_import_states_with_null_user_id_spec.rb
new file mode 100644
index 00000000000..f9285c857de
--- /dev/null
+++ b/spec/migrations/cleanup_group_import_states_with_null_user_id_spec.rb
@@ -0,0 +1,101 @@
+# frozen_string_literal: true
+
+# In order to test the CleanupGroupImportStatesWithNullUserId migration, we need
+# to first create GroupImportState with NULL user_id
+# and then run the migration to check that user_id was populated or record removed
+#
+# The problem is that the CleanupGroupImportStatesWithNullUserId migration comes
+# after the NOT NULL constraint has been added with a previous migration (AddNotNullConstraintToUserOnGroupImportStates)
+# That means that while testing the current class we can not insert GroupImportState records with an
+# invalid user_id as constraint is blocking it from doing so
+#
+# To solve this problem, use SchemaVersionFinder to set schema one version prior to AddNotNullConstraintToUserOnGroupImportStates
+
+require 'spec_helper'
+require Rails.root.join('db', 'post_migrate', '20200907092715_add_not_null_constraint_to_user_on_group_import_states.rb')
+require Rails.root.join('db', 'post_migrate', '20200909161624_cleanup_group_import_states_with_null_user_id.rb')
+
+RSpec.describe CleanupGroupImportStatesWithNullUserId, :migration,
+ schema: MigrationHelpers::SchemaVersionFinder.migration_prior(AddNotNullConstraintToUserOnGroupImportStates) do
+ let(:namespaces_table) { table(:namespaces) }
+ let(:users_table) { table(:users) }
+ let(:group_import_states_table) { table(:group_import_states) }
+ let(:members_table) { table(:members) }
+
+ describe 'Group import states clean up' do
+ context 'when user_id is present' do
+ it 'does not update group_import_state record' do
+ user_1 = users_table.create!(name: 'user1', email: 'user1@example.com', projects_limit: 1)
+ group_1 = namespaces_table.create!(name: 'group_1', path: 'group_1', type: 'Group')
+ create_member(user_id: user_1.id, type: 'GroupMember', source_type: 'Namespace', source_id: group_1.id, access_level: described_class::Group::OWNER)
+ group_import_state_1 = group_import_states_table.create!(group_id: group_1.id, user_id: user_1.id, status: 0)
+
+ expect(group_import_state_1.user_id).to eq(user_1.id)
+
+ disable_migrations_output { migrate! }
+
+ expect(group_import_state_1.reload.user_id).to eq(user_1.id)
+ end
+ end
+
+ context 'when user_id is missing' do
+ it 'updates user_id with group default owner id' do
+ user_2 = users_table.create!(name: 'user2', email: 'user2@example.com', projects_limit: 1)
+ group_2 = namespaces_table.create!(name: 'group_2', path: 'group_2', type: 'Group')
+ create_member(user_id: user_2.id, type: 'GroupMember', source_type: 'Namespace', source_id: group_2.id, access_level: described_class::Group::OWNER)
+ group_import_state_2 = group_import_states_table.create!(group_id: group_2.id, user_id: nil, status: 0)
+
+ disable_migrations_output { migrate! }
+
+ expect(group_import_state_2.reload.user_id).to eq(user_2.id)
+ end
+ end
+
+ context 'when group does not contain any owners' do
+ it 'removes group_import_state record' do
+ group_3 = namespaces_table.create!(name: 'group_3', path: 'group_3', type: 'Group')
+ group_import_state_3 = group_import_states_table.create!(group_id: group_3.id, user_id: nil, status: 0)
+
+ disable_migrations_output { migrate! }
+
+ expect { group_import_state_3.reload }.to raise_error(ActiveRecord::RecordNotFound)
+ end
+ end
+
+ context 'when group has parent' do
+ it 'updates user_id with parent group default owner id' do
+ user = users_table.create!(name: 'user4', email: 'user4@example.com', projects_limit: 1)
+ group_1 = namespaces_table.create!(name: 'group_1', path: 'group_1', type: 'Group')
+ create_member(user_id: user.id, type: 'GroupMember', source_type: 'Namespace', source_id: group_1.id, access_level: described_class::Group::OWNER)
+ group_2 = namespaces_table.create!(name: 'group_2', path: 'group_2', type: 'Group', parent_id: group_1.id)
+ group_import_state = group_import_states_table.create!(group_id: group_2.id, user_id: nil, status: 0)
+
+ disable_migrations_output { migrate! }
+
+ expect(group_import_state.reload.user_id).to eq(user.id)
+ end
+ end
+
+ context 'when group has owner_id' do
+ it 'updates user_id with owner_id' do
+ user = users_table.create!(name: 'user', email: 'user@example.com', projects_limit: 1)
+ group = namespaces_table.create!(name: 'group', path: 'group', type: 'Group', owner_id: user.id)
+ group_import_state = group_import_states_table.create!(group_id: group.id, user_id: nil, status: 0)
+
+ disable_migrations_output { migrate! }
+
+ expect(group_import_state.reload.user_id).to eq(user.id)
+ end
+ end
+ end
+
+ def create_member(options)
+ members_table.create!(
+ {
+ notification_level: 0,
+ ldap: false,
+ override: false
+ }.merge(options)
+ )
+ end
+end
diff --git a/spec/migrations/ensure_filled_file_store_on_package_files_spec.rb b/spec/migrations/ensure_filled_file_store_on_package_files_spec.rb
new file mode 100644
index 00000000000..8a0f51ab27e
--- /dev/null
+++ b/spec/migrations/ensure_filled_file_store_on_package_files_spec.rb
@@ -0,0 +1,40 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require Rails.root.join('db', 'post_migrate', '20200915185707_ensure_filled_file_store_on_package_files.rb')
+
+RSpec.describe EnsureFilledFileStoreOnPackageFiles, schema: 20200910175553 do
+ let!(:packages_package_files) { table(:packages_package_files) }
+ let!(:packages_packages) { table(:packages_packages) }
+ let!(:namespaces) { table(:namespaces) }
+ let!(:projects) { table(:projects) }
+ let!(:namespace) { namespaces.create!(name: 'foo', path: 'foo') }
+ let!(:project) { projects.create!(namespace_id: namespace.id) }
+ let!(:package) { packages_packages.create!(project_id: project.id, name: 'bar', package_type: 1) }
+
+ before do
+ constraint_name = 'check_4c5e6bb0b3'
+
+ # In order to insert a row with a NULL to fill.
+ ActiveRecord::Base.connection.execute "ALTER TABLE packages_package_files DROP CONSTRAINT #{constraint_name}"
+
+ @file_store_1 = packages_package_files.create!(file_store: 1, file_name: 'foo_1', file: 'foo_1', package_id: package.id)
+ @file_store_2 = packages_package_files.create!(file_store: 2, file_name: 'foo_2', file: 'foo_2', package_id: package.id)
+ @file_store_nil = packages_package_files.create!(file_store: nil, file_name: 'foo_nil', file: 'foo_nil', package_id: package.id)
+
+ # revert DB structure
+ ActiveRecord::Base.connection.execute "ALTER TABLE packages_package_files ADD CONSTRAINT #{constraint_name} CHECK ((file_store IS NOT NULL)) NOT VALID"
+ end
+
+ it 'correctly migrates nil file_store to 1' do
+ migrate!
+
+ @file_store_1.reload
+ @file_store_2.reload
+ @file_store_nil.reload
+
+ expect(@file_store_1.file_store).to eq(1) # unchanged
+ expect(@file_store_2.file_store).to eq(2) # unchanged
+ expect(@file_store_nil.file_store).to eq(1) # nil => 1
+ end
+end
diff --git a/spec/migrations/migrate_compliance_framework_enum_to_database_framework_record_spec.rb b/spec/migrations/migrate_compliance_framework_enum_to_database_framework_record_spec.rb
new file mode 100644
index 00000000000..cd2ec81abb7
--- /dev/null
+++ b/spec/migrations/migrate_compliance_framework_enum_to_database_framework_record_spec.rb
@@ -0,0 +1,70 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require Rails.root.join('db', 'post_migrate', '20201005094331_migrate_compliance_framework_enum_to_database_framework_record.rb')
+
+RSpec.describe MigrateComplianceFrameworkEnumToDatabaseFrameworkRecord, schema: 20201005092753 do
+ let(:namespaces) { table(:namespaces) }
+ let(:projects) { table(:projects) }
+ let(:project_compliance_framework_settings) { table(:project_compliance_framework_settings) }
+ let(:compliance_management_frameworks) { table(:compliance_management_frameworks) }
+
+ let(:gdpr_framework) { 1 }
+ let(:sox_framework) { 5 }
+
+ let!(:root_group) { namespaces.create!(type: 'Group', name: 'a', path: 'a') }
+ let!(:sub_group) { namespaces.create!(type: 'Group', name: 'b', path: 'b', parent_id: root_group.id) }
+ let!(:sub_sub_group) { namespaces.create!(type: 'Group', name: 'c', path: 'c', parent_id: sub_group.id) }
+
+ let!(:namespace) { namespaces.create!(name: 'd', path: 'd') }
+
+ let!(:project_on_root_level) { projects.create!(namespace_id: root_group.id) }
+ let!(:project_on_sub_sub_level_1) { projects.create!(namespace_id: sub_sub_group.id) }
+ let!(:project_on_sub_sub_level_2) { projects.create!(namespace_id: sub_sub_group.id) }
+ let!(:project_on_namespace) { projects.create!(namespace_id: namespace.id) }
+
+ let!(:project_on_root_level_compliance_setting) { project_compliance_framework_settings.create!(project_id: project_on_root_level.id, framework: gdpr_framework) }
+ let!(:project_on_sub_sub_level_compliance_setting_1) { project_compliance_framework_settings.create!(project_id: project_on_sub_sub_level_1.id, framework: sox_framework) }
+ let!(:project_on_sub_sub_level_compliance_setting_2) { project_compliance_framework_settings.create!(project_id: project_on_sub_sub_level_2.id, framework: gdpr_framework) }
+ let!(:project_on_namespace_level_compliance_setting) { project_compliance_framework_settings.create!(project_id: project_on_namespace.id, framework: gdpr_framework) }
+
+ subject { described_class.new.up }
+
+ context 'when Gitlab.ee? is true' do
+ before do
+ expect(Gitlab).to receive(:ee?).and_return(true)
+ end
+
+ it 'updates the project settings' do
+ subject
+
+ gdpr_framework = compliance_management_frameworks.find_by(namespace_id: root_group.id, name: 'GDPR')
+ expect(project_on_root_level_compliance_setting.reload.framework_id).to eq(gdpr_framework.id)
+ expect(project_on_sub_sub_level_compliance_setting_2.reload.framework_id).to eq(gdpr_framework.id)
+
+ sox_framework = compliance_management_frameworks.find_by(namespace_id: root_group.id, name: 'SOX')
+ expect(project_on_sub_sub_level_compliance_setting_1.reload.framework_id).to eq(sox_framework.id)
+
+ gdpr_framework = compliance_management_frameworks.find_by(namespace_id: namespace.id, name: 'GDPR')
+ expect(project_on_namespace_level_compliance_setting.reload.framework_id).to eq(gdpr_framework.id)
+ end
+
+ it 'adds two framework records' do
+ subject
+
+ expect(compliance_management_frameworks.count).to eq(3)
+ end
+ end
+
+ context 'when Gitlab.ee? is false' do
+ before do
+ expect(Gitlab).to receive(:ee?).and_return(false)
+ end
+
+ it 'does nothing' do
+ subject
+
+ expect(compliance_management_frameworks.count).to eq(0)
+ end
+ end
+end
diff --git a/spec/migrations/schedule_blocked_by_links_replacement_spec.rb b/spec/migrations/schedule_blocked_by_links_replacement_spec.rb
new file mode 100644
index 00000000000..36610507921
--- /dev/null
+++ b/spec/migrations/schedule_blocked_by_links_replacement_spec.rb
@@ -0,0 +1,37 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require Rails.root.join('db', 'post_migrate', '20201015073808_schedule_blocked_by_links_replacement')
+
+RSpec.describe ScheduleBlockedByLinksReplacement do
+ let(:namespace) { table(:namespaces).create!(name: 'gitlab', path: 'gitlab-org') }
+ let(:project) { table(:projects).create!(namespace_id: namespace.id, name: 'gitlab') }
+ let(:issue1) { table(:issues).create!(project_id: project.id, title: 'a') }
+ let(:issue2) { table(:issues).create!(project_id: project.id, title: 'b') }
+ let(:issue3) { table(:issues).create!(project_id: project.id, title: 'c') }
+ let!(:issue_links) do
+ [
+ table(:issue_links).create!(source_id: issue1.id, target_id: issue2.id, link_type: 1),
+ table(:issue_links).create!(source_id: issue2.id, target_id: issue1.id, link_type: 2),
+ table(:issue_links).create!(source_id: issue1.id, target_id: issue3.id, link_type: 2)
+ ]
+ end
+
+ before do
+ stub_const("#{described_class.name}::BATCH_SIZE", 1)
+ end
+
+ it 'schedules jobs for blocked_by links' do
+ Sidekiq::Testing.fake! do
+ freeze_time do
+ migrate!
+
+ expect(described_class::MIGRATION).to be_scheduled_delayed_migration(
+ 2.minutes, issue_links[1].id, issue_links[1].id)
+ expect(described_class::MIGRATION).to be_scheduled_delayed_migration(
+ 4.minutes, issue_links[2].id, issue_links[2].id)
+ expect(BackgroundMigrationWorker.jobs.size).to eq(2)
+ end
+ end
+ end
+end
diff --git a/spec/migrations/schedule_migrate_u2f_webauthn_spec.rb b/spec/migrations/schedule_migrate_u2f_webauthn_spec.rb
new file mode 100644
index 00000000000..5dc4d676063
--- /dev/null
+++ b/spec/migrations/schedule_migrate_u2f_webauthn_spec.rb
@@ -0,0 +1,58 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require Rails.root.join('db', 'post_migrate', '20200929114107_schedule_migrate_u2f_webauthn.rb')
+
+RSpec.describe ScheduleMigrateU2fWebauthn do
+ let(:migration_name) { described_class::MIGRATION }
+ let(:u2f_registrations) { table(:u2f_registrations) }
+ let(:webauthn_registrations) { table(:webauthn_registrations) }
+
+ let(:users) { table(:users) }
+
+ let(:user) { users.create!(email: 'email@email.com', name: 'foo', username: 'foo', projects_limit: 0) }
+
+ before do
+ stub_const("#{described_class.name}::BATCH_SIZE", 1)
+ end
+
+ context 'when there are u2f registrations' do
+ let!(:u2f_reg_1) { create_u2f_registration(1, 'reg1') }
+ let!(:u2f_reg_2) { create_u2f_registration(2, 'reg2') }
+
+ it 'schedules a background migration' do
+ Sidekiq::Testing.fake! do
+ freeze_time do
+ migrate!
+
+ expect(migration_name).to be_scheduled_delayed_migration(2.minutes, 1, 1)
+ expect(migration_name).to be_scheduled_delayed_migration(4.minutes, 2, 2)
+ expect(BackgroundMigrationWorker.jobs.size).to eq(2)
+ end
+ end
+ end
+ end
+
+ context 'when there are no u2f registrations' do
+ it 'does not schedule background migrations' do
+ Sidekiq::Testing.fake! do
+ freeze_time do
+ migrate!
+
+ expect(BackgroundMigrationWorker.jobs.size).to eq(0)
+ end
+ end
+ end
+ end
+
+ def create_u2f_registration(id, name)
+ device = U2F::FakeU2F.new(FFaker::BaconIpsum.characters(5))
+ u2f_registrations.create!({ id: id,
+ certificate: Base64.strict_encode64(device.cert_raw),
+ key_handle: U2F.urlsafe_encode64(device.key_handle_raw),
+ public_key: Base64.strict_encode64(device.origin_public_key_raw),
+ counter: 5,
+ name: name,
+ user_id: user.id })
+ end
+end
diff --git a/spec/migrations/set_job_waiter_ttl_spec.rb b/spec/migrations/set_job_waiter_ttl_spec.rb
new file mode 100644
index 00000000000..b9cf7c55798
--- /dev/null
+++ b/spec/migrations/set_job_waiter_ttl_spec.rb
@@ -0,0 +1,30 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require Rails.root.join('db', 'post_migrate', '20200930144340_set_job_waiter_ttl.rb')
+
+RSpec.describe SetJobWaiterTtl, :redis do
+ it 'sets TTLs where necessary' do
+ waiter_with_ttl = Gitlab::JobWaiter.new.key
+ waiter_without_ttl = Gitlab::JobWaiter.new.key
+ key_with_ttl = "foo:bar"
+ key_without_ttl = "foo:qux"
+
+ Gitlab::Redis::SharedState.with do |redis|
+ redis.set(waiter_with_ttl, "zzz", ex: 2000)
+ redis.set(waiter_without_ttl, "zzz")
+ redis.set(key_with_ttl, "zzz", ex: 2000)
+ redis.set(key_without_ttl, "zzz")
+
+ described_class.new.up
+
+ # This is the point of the migration. We know the migration uses a TTL of 21_600
+ expect(redis.ttl(waiter_without_ttl)).to be > 20_000
+
+ # Other TTL's should be untouched by the migration
+ expect(redis.ttl(waiter_with_ttl)).to be_between(1000, 2000)
+ expect(redis.ttl(key_with_ttl)).to be_between(1000, 2000)
+ expect(redis.ttl(key_without_ttl)).to eq(-1)
+ end
+ end
+end
diff --git a/spec/models/alert_management/alert_spec.rb b/spec/models/alert_management/alert_spec.rb
index eb9dcca842d..b57062b5fc1 100644
--- a/spec/models/alert_management/alert_spec.rb
+++ b/spec/models/alert_management/alert_spec.rb
@@ -133,7 +133,7 @@ RSpec.describe AlertManagement::Alert do
let(:new_alert) { build(:alert_management_alert, new_status, fingerprint: fingerprint, project: project) }
before do
- existing_alert.public_send(described_class::STATUS_EVENTS[existing_status])
+ existing_alert.change_status_to(existing_status)
end
if params[:valid]
@@ -170,6 +170,12 @@ RSpec.describe AlertManagement::Alert do
it { is_expected.to be_valid }
end
+
+ context 'nested array' do
+ let(:hosts) { ['111.111.111.111', ['111.111.111.111']] }
+
+ it { is_expected.not_to be_valid }
+ end
end
end
@@ -189,14 +195,14 @@ RSpec.describe AlertManagement::Alert do
end
describe '.for_status' do
- let(:status) { AlertManagement::Alert::STATUSES[:resolved] }
+ let(:status) { :resolved }
subject { AlertManagement::Alert.for_status(status) }
it { is_expected.to match_array(resolved_alert) }
context 'with multiple statuses' do
- let(:status) { AlertManagement::Alert::STATUSES.values_at(:resolved, :ignored) }
+ let(:status) { [:resolved, :ignored] }
it { is_expected.to match_array([resolved_alert, ignored_alert]) }
end
@@ -230,6 +236,35 @@ RSpec.describe AlertManagement::Alert do
it { is_expected.to match_array(env_alert) }
end
+ describe '.for_assignee_username' do
+ let_it_be(:alert) { triggered_alert }
+ let_it_be(:assignee) { create(:user) }
+
+ subject { AlertManagement::Alert.for_assignee_username(assignee_username) }
+
+ before_all do
+ alert.update!(assignees: [assignee])
+ end
+
+ context 'when matching assignee_username' do
+ let(:assignee_username) { assignee.username }
+
+ it { is_expected.to contain_exactly(alert) }
+ end
+
+ context 'when unknown assignee_username' do
+ let(:assignee_username) { 'unknown username' }
+
+ it { is_expected.to be_empty }
+ end
+
+ context 'with empty assignee_username' do
+ let(:assignee_username) { ' ' }
+
+ it { is_expected.to be_empty }
+ end
+ end
+
describe '.order_severity_with_open_prometheus_alert' do
subject { described_class.where(project: alert_project).order_severity_with_open_prometheus_alert }
@@ -241,19 +276,6 @@ RSpec.describe AlertManagement::Alert do
it { is_expected.to eq([triggered_critical_alert, triggered_high_alert]) }
end
- describe '.counts_by_status' do
- subject { described_class.counts_by_status }
-
- it do
- is_expected.to eq(
- triggered_alert.status => 1,
- acknowledged_alert.status => 1,
- resolved_alert.status => 1,
- ignored_alert.status => 1
- )
- end
- end
-
describe '.counts_by_project_id' do
subject { described_class.counts_by_project_id }
@@ -278,6 +300,55 @@ RSpec.describe AlertManagement::Alert do
end
end
+ describe '.status_value' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:status, :status_value) do
+ :triggered | 0
+ :acknowledged | 1
+ :resolved | 2
+ :ignored | 3
+ :unknown | nil
+ end
+
+ with_them do
+ it 'returns status value by its name' do
+ expect(described_class.status_value(status)).to eq(status_value)
+ end
+ end
+ end
+
+ describe '.status_name' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:raw_status, :status) do
+ 0 | :triggered
+ 1 | :acknowledged
+ 2 | :resolved
+ 3 | :ignored
+ -1 | nil
+ end
+
+ with_them do
+ it 'returns status name by its values' do
+ expect(described_class.status_name(raw_status)).to eq(status)
+ end
+ end
+ end
+
+ describe '.counts_by_status' do
+ subject { described_class.counts_by_status }
+
+ it do
+ is_expected.to eq(
+ triggered: 1,
+ acknowledged: 1,
+ resolved: 1,
+ ignored: 1
+ )
+ end
+ end
+
describe '.last_prometheus_alert_by_project_id' do
subject { described_class.last_prometheus_alert_by_project_id }
@@ -363,6 +434,24 @@ RSpec.describe AlertManagement::Alert do
end
end
+ describe '.open_status?' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:status, :is_open_status) do
+ :triggered | true
+ :acknowledged | true
+ :resolved | false
+ :ignored | false
+ nil | false
+ end
+
+ with_them do
+ it 'returns true when the status is open status' do
+ expect(described_class.open_status?(status)).to eq(is_open_status)
+ end
+ end
+ end
+
describe '#to_reference' do
it { expect(triggered_alert.to_reference).to eq("^alert##{triggered_alert.iid}") }
end
@@ -453,4 +542,54 @@ RSpec.describe AlertManagement::Alert do
expect { subject }.to change { alert.events }.by(1)
end
end
+
+ describe '#status_event_for' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:for_status, :event) do
+ :triggered | :trigger
+ 'triggered' | :trigger
+ :acknowledged | :acknowledge
+ 'acknowledged' | :acknowledge
+ :resolved | :resolve
+ 'resolved' | :resolve
+ :ignored | :ignore
+ 'ignored' | :ignore
+ :unknown | nil
+ nil | nil
+ '' | nil
+ 1 | nil
+ end
+
+ with_them do
+ let(:alert) { build(:alert_management_alert, project: project) }
+
+ it 'returns event by status name' do
+ expect(alert.status_event_for(for_status)).to eq(event)
+ end
+ end
+ end
+
+ describe '#change_status_to' do
+ let_it_be_with_reload(:alert) { create(:alert_management_alert, project: project) }
+
+ context 'with valid statuses' do
+ it 'changes the status to triggered' do
+ alert.acknowledge! # change to non-triggered status
+ expect { alert.change_status_to(:triggered) }.to change { alert.triggered? }.to(true)
+ end
+
+ %i(acknowledged resolved ignored).each do |status|
+ it "changes the status to #{status}" do
+ expect { alert.change_status_to(status) }.to change { alert.public_send(:"#{status}?") }.to(true)
+ end
+ end
+ end
+
+ context 'with invalid status' do
+ it 'does not change the current status' do
+ expect { alert.change_status_to(nil) }.not_to change { alert.status }
+ end
+ end
+ end
end
diff --git a/spec/models/alert_management/http_integration_spec.rb b/spec/models/alert_management/http_integration_spec.rb
new file mode 100644
index 00000000000..37d67dfe09a
--- /dev/null
+++ b/spec/models/alert_management/http_integration_spec.rb
@@ -0,0 +1,92 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe AlertManagement::HttpIntegration do
+ let_it_be(:project) { create(:project) }
+
+ subject(:integration) { build(:alert_management_http_integration) }
+
+ describe 'associations' do
+ it { is_expected.to belong_to(:project) }
+ end
+
+ describe 'validations' do
+ it { is_expected.to validate_presence_of(:project) }
+ it { is_expected.to validate_presence_of(:name) }
+ it { is_expected.to validate_length_of(:name).is_at_most(255) }
+ it { is_expected.to validate_presence_of(:endpoint_identifier) }
+ it { is_expected.to validate_length_of(:endpoint_identifier).is_at_most(255) }
+
+ context 'when active' do
+ # Using `create` instead of `build` the integration so `token` is set.
+ # Uniqueness spec saves integration with `validate: false` otherwise.
+ subject { create(:alert_management_http_integration) }
+
+ it { is_expected.to validate_uniqueness_of(:endpoint_identifier).scoped_to(:project_id, :active) }
+ end
+
+ context 'when inactive' do
+ subject { create(:alert_management_http_integration, :inactive) }
+
+ it { is_expected.not_to validate_uniqueness_of(:endpoint_identifier).scoped_to(:project_id, :active) }
+ end
+ end
+
+ describe '#token' do
+ subject { integration.token }
+
+ shared_context 'assign token' do |token|
+ let!(:previous_token) { integration.token }
+
+ before do
+ integration.token = token
+ integration.valid?
+ end
+ end
+
+ shared_examples 'valid token' do
+ it { is_expected.to match(/\A\h{32}\z/) }
+ end
+
+ context 'when unsaved' do
+ context 'when unassigned' do
+ before do
+ integration.valid?
+ end
+
+ it_behaves_like 'valid token'
+ end
+
+ context 'when assigned' do
+ include_context 'assign token', 'random_token'
+
+ it_behaves_like 'valid token'
+ it { is_expected.not_to eq('random_token') }
+ end
+ end
+
+ context 'when persisted' do
+ before do
+ integration.save!
+ integration.reload
+ end
+
+ it_behaves_like 'valid token'
+
+ context 'when resetting' do
+ include_context 'assign token', ''
+
+ it_behaves_like 'valid token'
+ it { is_expected.not_to eq(previous_token) }
+ end
+
+ context 'when reassigning' do
+ include_context 'assign token', 'random_token'
+
+ it_behaves_like 'valid token'
+ it { is_expected.to eq(previous_token) }
+ end
+ end
+ end
+end
diff --git a/spec/models/analytics/instance_statistics/measurement_spec.rb b/spec/models/analytics/instance_statistics/measurement_spec.rb
index 4df847ea524..379272cfcb9 100644
--- a/spec/models/analytics/instance_statistics/measurement_spec.rb
+++ b/spec/models/analytics/instance_statistics/measurement_spec.rb
@@ -20,7 +20,11 @@ RSpec.describe Analytics::InstanceStatistics::Measurement, type: :model do
issues: 3,
merge_requests: 4,
groups: 5,
- pipelines: 6
+ pipelines: 6,
+ pipelines_succeeded: 7,
+ pipelines_failed: 8,
+ pipelines_canceled: 9,
+ pipelines_skipped: 10
}.with_indifferent_access)
end
end
@@ -42,4 +46,28 @@ RSpec.describe Analytics::InstanceStatistics::Measurement, type: :model do
it { is_expected.to match_array([measurement_1, measurement_2]) }
end
end
+
+ describe '#measurement_identifier_values' do
+ subject { described_class.measurement_identifier_values.count }
+
+ context 'when the `store_ci_pipeline_counts_by_status` feature flag is off' do
+ let(:expected_count) { Analytics::InstanceStatistics::Measurement.identifiers.size - Analytics::InstanceStatistics::Measurement::EXPERIMENTAL_IDENTIFIERS.size }
+
+ before do
+ stub_feature_flags(store_ci_pipeline_counts_by_status: false)
+ end
+
+ it { is_expected.to eq(expected_count) }
+ end
+
+ context 'when the `store_ci_pipeline_counts_by_status` feature flag is on' do
+ let(:expected_count) { Analytics::InstanceStatistics::Measurement.identifiers.size }
+
+ before do
+ stub_feature_flags(store_ci_pipeline_counts_by_status: true)
+ end
+
+ it { is_expected.to eq(expected_count) }
+ end
+ end
end
diff --git a/spec/models/application_record_spec.rb b/spec/models/application_record_spec.rb
index 5ea1907543a..d080b298e2f 100644
--- a/spec/models/application_record_spec.rb
+++ b/spec/models/application_record_spec.rb
@@ -90,4 +90,12 @@ RSpec.describe ApplicationRecord do
expect(User.at_most(2).count).to eq(2)
end
end
+
+ describe '.where_exists' do
+ it 'produces a WHERE EXISTS query' do
+ user = create(:user)
+
+ expect(User.where_exists(User.limit(1))).to eq([user])
+ end
+ end
end
diff --git a/spec/models/application_setting/term_spec.rb b/spec/models/application_setting/term_spec.rb
index 82347453437..51a6027698f 100644
--- a/spec/models/application_setting/term_spec.rb
+++ b/spec/models/application_setting/term_spec.rb
@@ -17,6 +17,7 @@ RSpec.describe ApplicationSetting::Term do
describe '#accepted_by_user?' do
let(:user) { create(:user) }
+ let(:project_bot) { create(:user, :project_bot) }
let(:term) { create(:term) }
it 'is true when the user accepted the terms' do
@@ -25,6 +26,10 @@ RSpec.describe ApplicationSetting::Term do
expect(term.accepted_by_user?(user)).to be(true)
end
+ it 'is true when user is a bot' do
+ expect(term.accepted_by_user?(project_bot)).to be(true)
+ end
+
it 'is false when the user declined the terms' do
decline_terms(term, user)
diff --git a/spec/models/application_setting_spec.rb b/spec/models/application_setting_spec.rb
index 9f76fb3330d..fb702d10a42 100644
--- a/spec/models/application_setting_spec.rb
+++ b/spec/models/application_setting_spec.rb
@@ -112,6 +112,35 @@ RSpec.describe ApplicationSetting do
it { is_expected.to allow_value(nil).for(:repository_storages_weighted_default) }
it { is_expected.not_to allow_value({ default: 100, shouldntexist: 50 }).for(:repository_storages_weighted) }
+ context 'help_page_documentation_base_url validations' do
+ it { is_expected.to allow_value(nil).for(:help_page_documentation_base_url) }
+ it { is_expected.to allow_value('https://docs.gitlab.com').for(:help_page_documentation_base_url) }
+ it { is_expected.to allow_value('http://127.0.0.1').for(:help_page_documentation_base_url) }
+ it { is_expected.not_to allow_value('docs.gitlab.com').for(:help_page_documentation_base_url) }
+
+ context 'when url length validation' do
+ let(:value) { 'http://'.ljust(length, 'A') }
+
+ context 'when value string length is 255 characters' do
+ let(:length) { 255 }
+
+ it 'allows the value' do
+ is_expected.to allow_value(value).for(:help_page_documentation_base_url)
+ end
+ end
+
+ context 'when value string length exceeds 255 characters' do
+ let(:length) { 256 }
+
+ it 'does not allow the value' do
+ is_expected.not_to allow_value(value)
+ .for(:help_page_documentation_base_url)
+ .with_message('is too long (maximum is 255 characters)')
+ end
+ end
+ end
+ end
+
context 'grafana_url validations' do
before do
subject.instance_variable_set(:@parsed_grafana_url, nil)
@@ -320,7 +349,7 @@ RSpec.describe ApplicationSetting do
end
end
- it_behaves_like 'an object with email-formated attributes', :admin_notification_email do
+ it_behaves_like 'an object with email-formated attributes', :abuse_notification_email do
subject { setting }
end
@@ -778,6 +807,23 @@ RSpec.describe ApplicationSetting do
end
end
+ describe '#instance_review_permitted?', :request_store do
+ subject { setting.instance_review_permitted? }
+
+ before do
+ RequestStore.store[:current_license] = nil
+ expect(Rails.cache).to receive(:fetch).and_return(
+ ::ApplicationSetting::INSTANCE_REVIEW_MIN_USERS + users_over_minimum
+ )
+ end
+
+ where(users_over_minimum: [-1, 0, 1])
+
+ with_them do
+ it { is_expected.to be(users_over_minimum >= 0) }
+ end
+ end
+
describe 'email_restrictions' do
context 'when email restrictions are enabled' do
before do
diff --git a/spec/models/audit_event_spec.rb b/spec/models/audit_event_spec.rb
index a1ed48c57f4..5c87c2e68db 100644
--- a/spec/models/audit_event_spec.rb
+++ b/spec/models/audit_event_spec.rb
@@ -6,6 +6,13 @@ RSpec.describe AuditEvent do
let_it_be(:audit_event) { create(:project_audit_event) }
subject { audit_event }
+ describe 'validations' do
+ include_examples 'validates IP address' do
+ let(:attribute) { :ip_address }
+ let(:object) { create(:audit_event) }
+ end
+ end
+
describe '#as_json' do
context 'ip_address' do
subject { build(:group_audit_event, ip_address: '192.168.1.1').as_json }
diff --git a/spec/models/authentication_event_spec.rb b/spec/models/authentication_event_spec.rb
index 56b0111f2c7..483d45c08be 100644
--- a/spec/models/authentication_event_spec.rb
+++ b/spec/models/authentication_event_spec.rb
@@ -11,5 +11,41 @@ RSpec.describe AuthenticationEvent do
it { is_expected.to validate_presence_of(:provider) }
it { is_expected.to validate_presence_of(:user_name) }
it { is_expected.to validate_presence_of(:result) }
+
+ include_examples 'validates IP address' do
+ let(:attribute) { :ip_address }
+ let(:object) { create(:authentication_event) }
+ end
+ end
+
+ describe 'scopes' do
+ let_it_be(:ldap_event) { create(:authentication_event, provider: :ldapmain, result: :failed) }
+ let_it_be(:google_oauth2) { create(:authentication_event, provider: :google_oauth2, result: :success) }
+
+ describe '.for_provider' do
+ it 'returns events only for the specified provider' do
+ expect(described_class.for_provider(:ldapmain)).to match_array ldap_event
+ end
+ end
+
+ describe '.ldap' do
+ it 'returns all events for an LDAP provider' do
+ expect(described_class.ldap).to match_array ldap_event
+ end
+ end
+ end
+
+ describe '.providers' do
+ before do
+ create(:authentication_event, provider: :ldapmain)
+ create(:authentication_event, provider: :google_oauth2)
+ create(:authentication_event, provider: :standard)
+ create(:authentication_event, provider: :standard)
+ create(:authentication_event, provider: :standard)
+ end
+
+ it 'returns an array of distinct providers' do
+ expect(described_class.providers).to match_array %w(ldapmain google_oauth2 standard)
+ end
end
end
diff --git a/spec/models/blob_viewer/markup_spec.rb b/spec/models/blob_viewer/markup_spec.rb
new file mode 100644
index 00000000000..13b040d62d0
--- /dev/null
+++ b/spec/models/blob_viewer/markup_spec.rb
@@ -0,0 +1,38 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe BlobViewer::Markup do
+ include FakeBlobHelpers
+
+ let(:project) { create(:project, :repository) }
+ let(:blob) { fake_blob(path: 'CHANGELOG.md') }
+
+ subject { described_class.new(blob) }
+
+ describe '#banzai_render_context' do
+ it 'returns context needed for banzai rendering' do
+ expect(subject.banzai_render_context.keys).to eq([:cache_key])
+ end
+
+ context 'when blob does respond to rendered_markup' do
+ before do
+ allow(blob).to receive(:rendered_markup).and_return("some rendered markup")
+ end
+
+ it 'does sets rendered key' do
+ expect(subject.banzai_render_context.keys).to include(:rendered)
+ end
+ end
+
+ context 'when cached_markdown_blob feature flag is disabled' do
+ before do
+ stub_feature_flags(cached_markdown_blob: false)
+ end
+
+ it 'does not set cache_key key' do
+ expect(subject.banzai_render_context.keys).not_to include(:cache_key)
+ end
+ end
+ end
+end
diff --git a/spec/models/bulk_import_spec.rb b/spec/models/bulk_import_spec.rb
new file mode 100644
index 00000000000..1a7e1ed8119
--- /dev/null
+++ b/spec/models/bulk_import_spec.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe BulkImport, type: :model do
+ describe 'associations' do
+ it { is_expected.to belong_to(:user).required }
+ it { is_expected.to have_one(:configuration) }
+ it { is_expected.to have_many(:entities) }
+ end
+
+ describe 'validations' do
+ it { is_expected.to validate_presence_of(:source_type) }
+ it { is_expected.to validate_presence_of(:status) }
+
+ it { is_expected.to define_enum_for(:source_type).with_values(%i[gitlab]) }
+ end
+end
diff --git a/spec/models/bulk_imports/configuration_spec.rb b/spec/models/bulk_imports/configuration_spec.rb
new file mode 100644
index 00000000000..1cbfef631ac
--- /dev/null
+++ b/spec/models/bulk_imports/configuration_spec.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe BulkImports::Configuration, type: :model do
+ describe 'associations' do
+ it { is_expected.to belong_to(:bulk_import).required }
+ end
+
+ describe 'validations' do
+ it { is_expected.to validate_length_of(:url).is_at_most(255) }
+ it { is_expected.to validate_length_of(:access_token).is_at_most(255) }
+
+ it { is_expected.to validate_presence_of(:url) }
+ it { is_expected.to validate_presence_of(:access_token) }
+ end
+end
diff --git a/spec/models/bulk_imports/entity_spec.rb b/spec/models/bulk_imports/entity_spec.rb
new file mode 100644
index 00000000000..ad6e3ec6f30
--- /dev/null
+++ b/spec/models/bulk_imports/entity_spec.rb
@@ -0,0 +1,85 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe BulkImports::Entity, type: :model do
+ describe 'associations' do
+ it { is_expected.to belong_to(:bulk_import).required }
+ it { is_expected.to belong_to(:parent) }
+ it { is_expected.to belong_to(:group) }
+ it { is_expected.to belong_to(:project) }
+ end
+
+ describe 'validations' do
+ it { is_expected.to validate_presence_of(:source_type) }
+ it { is_expected.to validate_presence_of(:source_full_path) }
+ it { is_expected.to validate_presence_of(:destination_name) }
+ it { is_expected.to validate_presence_of(:destination_namespace) }
+
+ it { is_expected.to define_enum_for(:source_type).with_values(%i[group_entity project_entity]) }
+
+ context 'when associated with a group and project' do
+ it 'is invalid' do
+ entity = build(:bulk_import_entity, group: build(:group), project: build(:project))
+
+ expect(entity).not_to be_valid
+ expect(entity.errors).to include(:project, :group)
+ end
+ end
+
+ context 'when not associated with a group or project' do
+ it 'is valid' do
+ entity = build(:bulk_import_entity, group: nil, project: nil)
+
+ expect(entity).to be_valid
+ end
+ end
+
+ context 'when associated with a group and no project' do
+ it 'is valid as a group_entity' do
+ entity = build(:bulk_import_entity, :group_entity, group: build(:group), project: nil)
+
+ expect(entity).to be_valid
+ end
+
+ it 'is invalid as a project_entity' do
+ entity = build(:bulk_import_entity, :project_entity, group: build(:group), project: nil)
+
+ expect(entity).not_to be_valid
+ expect(entity.errors).to include(:group)
+ end
+ end
+
+ context 'when associated with a project and no group' do
+ it 'is valid' do
+ entity = build(:bulk_import_entity, :project_entity, group: nil, project: build(:project))
+
+ expect(entity).to be_valid
+ end
+
+ it 'is invalid as a project_entity' do
+ entity = build(:bulk_import_entity, :group_entity, group: nil, project: build(:project))
+
+ expect(entity).not_to be_valid
+ expect(entity.errors).to include(:project)
+ end
+ end
+
+ context 'when the parent is a group import' do
+ it 'is valid' do
+ entity = build(:bulk_import_entity, parent: build(:bulk_import_entity, :group_entity))
+
+ expect(entity).to be_valid
+ end
+ end
+
+ context 'when the parent is a project import' do
+ it 'is invalid' do
+ entity = build(:bulk_import_entity, parent: build(:bulk_import_entity, :project_entity))
+
+ expect(entity).not_to be_valid
+ expect(entity.errors).to include(:parent)
+ end
+ end
+ end
+end
diff --git a/spec/models/ci/bridge_spec.rb b/spec/models/ci/bridge_spec.rb
index 850fc1ec6e6..c464e176c17 100644
--- a/spec/models/ci/bridge_spec.rb
+++ b/spec/models/ci/bridge_spec.rb
@@ -59,30 +59,20 @@ RSpec.describe Ci::Bridge do
describe 'state machine transitions' do
context 'when bridge points towards downstream' do
- it 'schedules downstream pipeline creation' do
- expect(bridge).to receive(:schedule_downstream_pipeline!)
+ %i[created manual].each do |status|
+ it "schedules downstream pipeline creation when the status is #{status}" do
+ bridge.status = status
- bridge.enqueue!
- end
- end
- end
-
- describe 'state machine transitions' do
- context 'when bridge points towards downstream' do
- it 'schedules downstream pipeline creation' do
- expect(bridge).to receive(:schedule_downstream_pipeline!)
+ expect(bridge).to receive(:schedule_downstream_pipeline!)
- bridge.enqueue!
+ bridge.enqueue!
+ end
end
- end
- end
- describe 'state machine transitions' do
- context 'when bridge points towards downstream' do
- it 'schedules downstream pipeline creation' do
- expect(bridge).to receive(:schedule_downstream_pipeline!)
+ it 'raises error when the status is failed' do
+ bridge.status = :failed
- bridge.enqueue!
+ expect { bridge.enqueue! }.to raise_error(StateMachines::InvalidTransition)
end
end
end
@@ -304,4 +294,67 @@ RSpec.describe Ci::Bridge do
end
end
end
+
+ describe '#play' do
+ let(:downstream_project) { create(:project) }
+ let(:user) { create(:user) }
+ let(:bridge) { create(:ci_bridge, :playable, pipeline: pipeline, downstream: downstream_project) }
+
+ subject { bridge.play(user) }
+
+ before do
+ project.add_maintainer(user)
+ downstream_project.add_maintainer(user)
+ end
+
+ it 'enqueues the bridge' do
+ subject
+
+ expect(bridge).to be_pending
+ end
+ end
+
+ describe '#playable?' do
+ context 'when bridge is a manual action' do
+ subject { build_stubbed(:ci_bridge, :manual).playable? }
+
+ it { is_expected.to be_truthy }
+
+ context 'when FF ci_manual_bridges is disabled' do
+ before do
+ stub_feature_flags(ci_manual_bridges: false)
+ end
+
+ it { is_expected.to be_falsey }
+ end
+ end
+
+ context 'when build is not a manual action' do
+ subject { build_stubbed(:ci_bridge, :created).playable? }
+
+ it { is_expected.to be_falsey }
+ end
+ end
+
+ describe '#action?' do
+ context 'when bridge is a manual action' do
+ subject { build_stubbed(:ci_bridge, :manual).action? }
+
+ it { is_expected.to be_truthy }
+
+ context 'when FF ci_manual_bridges is disabled' do
+ before do
+ stub_feature_flags(ci_manual_bridges: false)
+ end
+
+ it { is_expected.to be_falsey }
+ end
+ end
+
+ context 'when build is not a manual action' do
+ subject { build_stubbed(:ci_bridge, :created).action? }
+
+ it { is_expected.to be_falsey }
+ end
+ end
end
diff --git a/spec/models/ci/build_pending_state_spec.rb b/spec/models/ci/build_pending_state_spec.rb
new file mode 100644
index 00000000000..a546d2aff65
--- /dev/null
+++ b/spec/models/ci/build_pending_state_spec.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Ci::BuildPendingState do
+ describe '#crc32' do
+ context 'when checksum does not exist' do
+ let(:pending_state) do
+ build(:ci_build_pending_state, trace_checksum: nil)
+ end
+
+ it 'returns nil' do
+ expect(pending_state.crc32).to be_nil
+ end
+ end
+
+ context 'when checksum is in hexadecimal' do
+ let(:pending_state) do
+ build(:ci_build_pending_state, trace_checksum: 'crc32:75bcd15')
+ end
+
+ it 'returns decimal representation of the checksum' do
+ expect(pending_state.crc32).to eq 123456789
+ end
+ end
+ end
+end
diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb
index 1e551d9ee33..f1d51324bbf 100644
--- a/spec/models/ci/build_spec.rb
+++ b/spec/models/ci/build_spec.rb
@@ -1109,7 +1109,8 @@ RSpec.describe Ci::Build do
let(:environment) { deployment.environment }
before do
- allow(Deployments::FinishedWorker).to receive(:perform_async)
+ allow(Deployments::LinkMergeRequestWorker).to receive(:perform_async)
+ allow(Deployments::ExecuteHooksWorker).to receive(:perform_async)
end
it 'has deployments record with created status' do
@@ -1129,7 +1130,8 @@ RSpec.describe Ci::Build do
context 'when transits to success' do
before do
- allow(Deployments::SuccessWorker).to receive(:perform_async)
+ allow(Deployments::UpdateEnvironmentWorker).to receive(:perform_async)
+ allow(Deployments::ExecuteHooksWorker).to receive(:perform_async)
build.success!
end
@@ -2305,6 +2307,54 @@ RSpec.describe Ci::Build do
end
end
+ describe '#has_expired_locked_archive_artifacts?' do
+ subject { build.has_expired_locked_archive_artifacts? }
+
+ context 'when build does not have artifacts' do
+ it { is_expected.to eq(nil) }
+ end
+
+ context 'when build has artifacts' do
+ before do
+ create(:ci_job_artifact, :archive, job: build)
+ end
+
+ context 'when artifacts are unlocked' do
+ before do
+ build.pipeline.unlocked!
+ end
+
+ it { is_expected.to eq(false) }
+ end
+
+ context 'when artifacts are locked' do
+ before do
+ build.pipeline.artifacts_locked!
+ end
+
+ context 'when artifacts do not expire' do
+ it { is_expected.to eq(false) }
+ end
+
+ context 'when artifacts expire in the future' do
+ before do
+ build.update!(artifacts_expire_at: 1.day.from_now)
+ end
+
+ it { is_expected.to eq(false) }
+ end
+
+ context 'when artifacts expired in the past' do
+ before do
+ build.update!(artifacts_expire_at: 1.day.ago)
+ end
+
+ it { is_expected.to eq(true) }
+ end
+ end
+ end
+ end
+
describe '#has_expiring_archive_artifacts?' do
context 'when artifacts have expiration date set' do
before do
@@ -2504,94 +2554,6 @@ RSpec.describe Ci::Build do
end
end
- describe 'CHANGED_PAGES variables' do
- let(:route_map_yaml) do
- <<~ROUTEMAP
- - source: 'bar/branch-test.txt'
- public: '/bar/branches'
- - source: 'with space/README.md'
- public: '/README'
- ROUTEMAP
- end
-
- before do
- allow_any_instance_of(Project)
- .to receive(:route_map_for).with(/.+/)
- .and_return(Gitlab::RouteMap.new(route_map_yaml))
- end
-
- context 'with a deployment environment and a merge request' do
- let(:merge_request) { create(:merge_request, source_project: project, target_project: project) }
- let(:environment) { create(:environment, project: merge_request.project, name: "foo-#{project.default_branch}") }
- let(:build) { create(:ci_build, pipeline: pipeline, environment: environment.name) }
-
- let(:full_urls) do
- [
- File.join(environment.external_url, '/bar/branches'),
- File.join(environment.external_url, '/README')
- ]
- end
-
- it 'populates CI_MERGE_REQUEST_CHANGED_PAGES_* variables' do
- expect(subject).to include(
- {
- key: 'CI_MERGE_REQUEST_CHANGED_PAGE_PATHS',
- value: '/bar/branches,/README',
- public: true,
- masked: false
- },
- {
- key: 'CI_MERGE_REQUEST_CHANGED_PAGE_URLS',
- value: full_urls.join(','),
- public: true,
- masked: false
- }
- )
- end
-
- context 'with a deployment environment and no merge request' do
- let(:environment) { create(:environment, project: project, name: "foo-#{project.default_branch}") }
- let(:build) { create(:ci_build, pipeline: pipeline, environment: environment.name) }
-
- it 'does not append CHANGED_PAGES variables' do
- ci_variables = subject.select { |var| var[:key] =~ /MERGE_REQUEST_CHANGED_PAGES/ }
-
- expect(ci_variables).to be_empty
- end
- end
-
- context 'with no deployment environment and a present merge request' do
- let(:merge_request) { create(:merge_request, :with_detached_merge_request_pipeline, source_project: project, target_project: project) }
- let(:build) { create(:ci_build, pipeline: merge_request.all_pipelines.take) }
-
- it 'does not append CHANGED_PAGES variables' do
- ci_variables = subject.select { |var| var[:key] =~ /MERGE_REQUEST_CHANGED_PAGES/ }
-
- expect(ci_variables).to be_empty
- end
- end
-
- context 'with no deployment environment and no merge request' do
- it 'does not append CHANGED_PAGES variables' do
- ci_variables = subject.select { |var| var[:key] =~ /MERGE_REQUEST_CHANGED_PAGES/ }
-
- expect(ci_variables).to be_empty
- end
- end
- end
-
- context 'with the :modified_path_ci_variables feature flag disabled' do
- before do
- stub_feature_flags(modified_path_ci_variables: false)
- end
-
- it 'does not set CI_MERGE_REQUEST_CHANGED_PAGES_* variables' do
- expect(subject.find { |var| var[:key] == 'CI_MERGE_REQUEST_CHANGED_PAGE_PATHS' }).to be_nil
- expect(subject.find { |var| var[:key] == 'CI_MERGE_REQUEST_CHANGED_PAGE_URLS' }).to be_nil
- end
- end
- end
-
context 'when build has user' do
let(:user_variables) do
[
@@ -4652,4 +4614,24 @@ RSpec.describe Ci::Build do
it { is_expected.to be_nil }
end
end
+
+ describe '#run_on_status_commit' do
+ it 'runs provided hook after status commit' do
+ action = spy('action')
+
+ build.run_on_status_commit { action.perform! }
+ build.success!
+
+ expect(action).to have_received(:perform!).once
+ end
+
+ it 'does not run hooks when status has not changed' do
+ action = spy('action')
+
+ build.run_on_status_commit { action.perform! }
+ build.save!
+
+ expect(action).not_to have_received(:perform!)
+ end
+ end
end
diff --git a/spec/models/ci/build_trace_chunk_spec.rb b/spec/models/ci/build_trace_chunk_spec.rb
index fefe5e3bfca..cdbdd2b1d20 100644
--- a/spec/models/ci/build_trace_chunk_spec.rb
+++ b/spec/models/ci/build_trace_chunk_spec.rb
@@ -502,22 +502,12 @@ RSpec.describe Ci::BuildTraceChunk, :clean_gitlab_redis_shared_state do
describe '#persist_data!' do
let(:build) { create(:ci_build, :running) }
- subject { build_trace_chunk.persist_data! }
-
- shared_examples_for 'Atomic operation' do
- context 'when the other process is persisting' do
- let(:lease_key) { "trace_write:#{build_trace_chunk.build.id}:chunks:#{build_trace_chunk.chunk_index}" }
-
- before do
- stub_exclusive_lease_taken(lease_key)
- end
-
- it 'raise an error' do
- expect { subject }.to raise_error('Failed to obtain a lock')
- end
- end
+ before do
+ build_trace_chunk.save!
end
+ subject { build_trace_chunk.persist_data! }
+
context 'when data_store is redis' do
let(:data_store) { :redis }
@@ -548,8 +538,6 @@ RSpec.describe Ci::BuildTraceChunk, :clean_gitlab_redis_shared_state do
expect(build_trace_chunk.reload.checksum).to eq '3398914352'
end
-
- it_behaves_like 'Atomic operation'
end
context 'when data size has not reached CHUNK_SIZE' do
@@ -575,6 +563,62 @@ RSpec.describe Ci::BuildTraceChunk, :clean_gitlab_redis_shared_state do
expect(build_trace_chunk.fog?).to be_truthy
end
end
+
+ context 'when the chunk has been modifed by a different worker' do
+ it 'reloads the chunk before migration' do
+ described_class
+ .find(build_trace_chunk.id)
+ .update!(data_store: :fog)
+
+ build_trace_chunk.persist_data!
+ end
+
+ it 'verifies the operation using optimistic locking' do
+ allow(build_trace_chunk)
+ .to receive(:save!)
+ .and_raise(ActiveRecord::StaleObjectError)
+
+ expect { build_trace_chunk.persist_data! }
+ .to raise_error(described_class::FailedToPersistDataError)
+ end
+
+ it 'does not allow flushing unpersisted chunk' do
+ build_trace_chunk.checksum = '12345'
+
+ expect { build_trace_chunk.persist_data! }
+ .to raise_error(described_class::FailedToPersistDataError,
+ /Modifed build trace chunk detected/)
+ end
+ end
+
+ context 'when the chunk is being locked by a different worker' do
+ let(:metrics) { spy('metrics') }
+
+ it 'does not raise an exception' do
+ lock_chunk do
+ expect { build_trace_chunk.persist_data! }.not_to raise_error
+ end
+ end
+
+ it 'increments stalled chunk trace metric' do
+ allow(build_trace_chunk)
+ .to receive(:metrics)
+ .and_return(metrics)
+
+ lock_chunk { build_trace_chunk.persist_data! }
+
+ expect(metrics)
+ .to have_received(:increment_trace_operation)
+ .with(operation: :stalled)
+ .once
+ end
+
+ def lock_chunk(&block)
+ "trace_write:#{build.id}:chunks:#{chunk_index}".then do |key|
+ build_trace_chunk.in_lock(key, &block)
+ end
+ end
+ end
end
end
@@ -609,8 +653,6 @@ RSpec.describe Ci::BuildTraceChunk, :clean_gitlab_redis_shared_state do
expect(Ci::BuildTraceChunks::Database.new.data(build_trace_chunk)).to be_nil
expect(Ci::BuildTraceChunks::Fog.new.data(build_trace_chunk)).to eq(data)
end
-
- it_behaves_like 'Atomic operation'
end
context 'when data size has not reached CHUNK_SIZE' do
@@ -670,8 +712,6 @@ RSpec.describe Ci::BuildTraceChunk, :clean_gitlab_redis_shared_state do
expect(Ci::BuildTraceChunks::Database.new.data(build_trace_chunk)).to be_nil
expect(Ci::BuildTraceChunks::Fog.new.data(build_trace_chunk)).to eq(data)
end
-
- it_behaves_like 'Atomic operation'
end
context 'when data size has not reached CHUNK_SIZE' do
@@ -779,4 +819,62 @@ RSpec.describe Ci::BuildTraceChunk, :clean_gitlab_redis_shared_state do
it_behaves_like 'deletes all build_trace_chunk and data in redis'
end
end
+
+ describe 'comparable build trace chunks' do
+ describe '#<=>' do
+ context 'when chunks are associated with different builds' do
+ let(:first) { create(:ci_build_trace_chunk, build: build, chunk_index: 1) }
+ let(:second) { create(:ci_build_trace_chunk, chunk_index: 1) }
+
+ it 'returns nil' do
+ expect(first <=> second).to be_nil
+ end
+ end
+
+ context 'when there are two chunks with different indexes' do
+ let(:first) { create(:ci_build_trace_chunk, build: build, chunk_index: 1) }
+ let(:second) { create(:ci_build_trace_chunk, build: build, chunk_index: 0) }
+
+ it 'indicates the the first one is greater than then second' do
+ expect(first <=> second).to eq 1
+ end
+ end
+
+ context 'when there are two chunks with the same index within the same build' do
+ let(:chunk) { create(:ci_build_trace_chunk) }
+
+ it 'indicates the these are equal' do
+ expect(chunk <=> chunk).to be_zero # rubocop:disable Lint/UselessComparison
+ end
+ end
+ end
+
+ describe '#==' do
+ context 'when chunks have the same index' do
+ let(:chunk) { create(:ci_build_trace_chunk) }
+
+ it 'indicates that the chunks are equal' do
+ expect(chunk).to eq chunk
+ end
+ end
+
+ context 'when chunks have different indexes' do
+ let(:first) { create(:ci_build_trace_chunk, build: build, chunk_index: 1) }
+ let(:second) { create(:ci_build_trace_chunk, build: build, chunk_index: 0) }
+
+ it 'indicates that the chunks are not equal' do
+ expect(first).not_to eq second
+ end
+ end
+
+ context 'when chunks are associated with different builds' do
+ let(:first) { create(:ci_build_trace_chunk, build: build, chunk_index: 1) }
+ let(:second) { create(:ci_build_trace_chunk, chunk_index: 1) }
+
+ it 'indicates that the chunks are not equal' do
+ expect(first).not_to eq second
+ end
+ end
+ end
+ end
end
diff --git a/spec/models/ci/deleted_object_spec.rb b/spec/models/ci/deleted_object_spec.rb
new file mode 100644
index 00000000000..cb8911d5027
--- /dev/null
+++ b/spec/models/ci/deleted_object_spec.rb
@@ -0,0 +1,95 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Ci::DeletedObject, :aggregate_failures do
+ describe 'attributes' do
+ it { is_expected.to respond_to(:file) }
+ it { is_expected.to respond_to(:store_dir) }
+ it { is_expected.to respond_to(:file_store) }
+ it { is_expected.to respond_to(:pick_up_at) }
+ end
+
+ describe '.bulk_import' do
+ context 'with data' do
+ let!(:artifact) { create(:ci_job_artifact, :archive, :expired) }
+
+ it 'imports data' do
+ expect { described_class.bulk_import(Ci::JobArtifact.all) }.to change { described_class.count }.by(1)
+
+ deleted_artifact = described_class.first
+
+ expect(deleted_artifact.file_store).to eq(artifact.file_store)
+ expect(deleted_artifact.store_dir).to eq(artifact.file.store_dir.to_s)
+ expect(deleted_artifact.file_identifier).to eq(artifact.file_identifier)
+ expect(deleted_artifact.pick_up_at).to eq(artifact.expire_at)
+ end
+ end
+
+ context 'with invalid data' do
+ let!(:artifact) { create(:ci_job_artifact) }
+
+ it 'does not import anything' do
+ expect(artifact.file_identifier).to be_nil
+
+ expect { described_class.bulk_import([artifact]) }
+ .not_to change { described_class.count }
+ end
+ end
+
+ context 'with empty data' do
+ it 'returns successfully' do
+ expect { described_class.bulk_import([]) }
+ .not_to change { described_class.count }
+ end
+ end
+ end
+
+ context 'ActiveRecord scopes' do
+ let_it_be(:not_ready) { create(:ci_deleted_object, pick_up_at: 1.day.from_now) }
+ let_it_be(:ready) { create(:ci_deleted_object, pick_up_at: 1.day.ago) }
+
+ describe '.ready_for_destruction' do
+ it 'returns objects that are ready' do
+ result = described_class.ready_for_destruction(2)
+
+ expect(result).to contain_exactly(ready)
+ end
+ end
+
+ describe '.lock_for_destruction' do
+ subject(:result) { described_class.lock_for_destruction(10) }
+
+ it 'returns objects that are ready' do
+ expect(result).to contain_exactly(ready)
+ end
+
+ it 'selects only the id' do
+ expect(result.select_values).to contain_exactly(:id)
+ end
+
+ it 'orders by pick_up_at' do
+ expect(result.order_values.map(&:to_sql))
+ .to contain_exactly("\"ci_deleted_objects\".\"pick_up_at\" ASC")
+ end
+
+ it 'applies limit' do
+ expect(result.limit_value).to eq(10)
+ end
+
+ it 'uses select for update' do
+ expect(result.locked?).to eq('FOR UPDATE SKIP LOCKED')
+ end
+ end
+ end
+
+ describe '#delete_file_from_storage' do
+ let(:object) { build(:ci_deleted_object) }
+
+ it 'does not raise errors' do
+ expect(object.file).to receive(:remove!).and_raise(StandardError)
+
+ expect(object.delete_file_from_storage).to be_falsy
+ end
+ end
+end
diff --git a/spec/models/ci/freeze_period_status_spec.rb b/spec/models/ci/freeze_period_status_spec.rb
index 831895cb528..f51381f7a5f 100644
--- a/spec/models/ci/freeze_period_status_spec.rb
+++ b/spec/models/ci/freeze_period_status_spec.rb
@@ -11,7 +11,7 @@ RSpec.describe Ci::FreezePeriodStatus do
shared_examples 'within freeze period' do |time|
it 'is frozen' do
- Timecop.freeze(time) do
+ travel_to(time) do
expect(subject).to be_truthy
end
end
@@ -19,7 +19,7 @@ RSpec.describe Ci::FreezePeriodStatus do
shared_examples 'outside freeze period' do |time|
it 'is not frozen' do
- Timecop.freeze(time) do
+ travel_to(time) do
expect(subject).to be_falsy
end
end
diff --git a/spec/models/ci/job_artifact_spec.rb b/spec/models/ci/job_artifact_spec.rb
index 779839df670..26851c93ac3 100644
--- a/spec/models/ci/job_artifact_spec.rb
+++ b/spec/models/ci/job_artifact_spec.rb
@@ -19,7 +19,7 @@ RSpec.describe Ci::JobArtifact do
it_behaves_like 'having unique enum values'
- it_behaves_like 'UpdateProjectStatistics' do
+ it_behaves_like 'UpdateProjectStatistics', :with_counter_attribute do
let_it_be(:job, reload: true) { create(:ci_build) }
subject { build(:ci_job_artifact, :archive, job: job, size: 107464) }
@@ -44,7 +44,7 @@ RSpec.describe Ci::JobArtifact do
let!(:metrics_report) { create(:ci_job_artifact, :junit) }
let!(:codequality_report) { create(:ci_job_artifact, :codequality) }
- it { is_expected.to eq([metrics_report, codequality_report]) }
+ it { is_expected.to match_array([metrics_report, codequality_report]) }
end
end
diff --git a/spec/models/ci/pipeline_schedule_spec.rb b/spec/models/ci/pipeline_schedule_spec.rb
index 949d5f7bd04..cec3b544e50 100644
--- a/spec/models/ci/pipeline_schedule_spec.rb
+++ b/spec/models/ci/pipeline_schedule_spec.rb
@@ -56,7 +56,7 @@ RSpec.describe Ci::PipelineSchedule do
subject { described_class.runnable_schedules }
let!(:pipeline_schedule) do
- Timecop.freeze(1.day.ago) do
+ travel_to(1.day.ago) do
create(:ci_pipeline_schedule, :hourly)
end
end
@@ -118,7 +118,7 @@ RSpec.describe Ci::PipelineSchedule do
let(:pipeline_schedule) { create(:ci_pipeline_schedule, :every_minute) }
it "updates next_run_at to the sidekiq worker's execution time" do
- Timecop.freeze(Time.zone.parse("2019-06-01 12:18:00+0000")) do
+ travel_to(Time.zone.parse("2019-06-01 12:18:00+0000")) do
expect(pipeline_schedule.next_run_at).to eq(cron_worker_next_run_at)
end
end
diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb
index 228a1e8f7a2..88d08f1ec45 100644
--- a/spec/models/ci/pipeline_spec.rb
+++ b/spec/models/ci/pipeline_spec.rb
@@ -2436,7 +2436,7 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
describe '#retry_failed' do
- let(:latest_status) { pipeline.statuses.latest.pluck(:status) }
+ let(:latest_status) { pipeline.latest_statuses.pluck(:status) }
before do
stub_not_protect_default_branch
@@ -2988,6 +2988,57 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
end
+ describe '#builds_in_self_and_descendants' do
+ subject(:builds) { pipeline.builds_in_self_and_descendants }
+
+ let(:pipeline) { create(:ci_pipeline, project: project) }
+ let!(:build) { create(:ci_build, pipeline: pipeline) }
+
+ context 'when pipeline is standalone' do
+ it 'returns the list of builds' do
+ expect(builds).to contain_exactly(build)
+ end
+ end
+
+ context 'when pipeline is parent of another pipeline' do
+ let(:child_pipeline) { create(:ci_pipeline, child_of: pipeline) }
+ let!(:child_build) { create(:ci_build, pipeline: child_pipeline) }
+
+ it 'returns the list of builds' do
+ expect(builds).to contain_exactly(build, child_build)
+ end
+ end
+
+ context 'when pipeline is parent of another parent pipeline' do
+ let(:child_pipeline) { create(:ci_pipeline, child_of: pipeline) }
+ let!(:child_build) { create(:ci_build, pipeline: child_pipeline) }
+ let(:child_of_child_pipeline) { create(:ci_pipeline, child_of: child_pipeline) }
+ let!(:child_of_child_build) { create(:ci_build, pipeline: child_of_child_pipeline) }
+
+ it 'returns the list of builds' do
+ expect(builds).to contain_exactly(build, child_build, child_of_child_build)
+ end
+ end
+ end
+
+ describe '#build_with_artifacts_in_self_and_descendants' do
+ let!(:build) { create(:ci_build, name: 'test', pipeline: pipeline) }
+ let(:child_pipeline) { create(:ci_pipeline, child_of: pipeline) }
+ let!(:child_build) { create(:ci_build, :artifacts, name: 'test', pipeline: child_pipeline) }
+
+ it 'returns the build with a given name, having artifacts' do
+ expect(pipeline.build_with_artifacts_in_self_and_descendants('test')).to eq(child_build)
+ end
+
+ context 'when same job name is present in both parent and child pipeline' do
+ let!(:build) { create(:ci_build, :artifacts, name: 'test', pipeline: pipeline) }
+
+ it 'returns the job in the parent pipeline' do
+ expect(pipeline.build_with_artifacts_in_self_and_descendants('test')).to eq(build)
+ end
+ end
+ end
+
describe '#find_job_with_archive_artifacts' do
let!(:old_job) { create(:ci_build, name: 'rspec', retried: true, pipeline: pipeline) }
let!(:job_without_artifacts) { create(:ci_build, name: 'rspec', pipeline: pipeline) }
@@ -3628,6 +3679,16 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
expect(builds).to include(rspec, jest)
expect(builds).not_to include(karma)
end
+
+ it 'returns only latest builds' do
+ obsolete = create(:ci_build, name: "jest", coverage: 10.12, pipeline: pipeline, retried: true)
+ retried = create(:ci_build, name: "jest", coverage: 20.11, pipeline: pipeline)
+
+ builds = pipeline.builds_with_coverage
+
+ expect(builds).to include(retried)
+ expect(builds).not_to include(obsolete)
+ end
end
describe '#base_and_ancestors' do
diff --git a/spec/models/ci_platform_metric_spec.rb b/spec/models/ci_platform_metric_spec.rb
index 0b00875df43..f73db713791 100644
--- a/spec/models/ci_platform_metric_spec.rb
+++ b/spec/models/ci_platform_metric_spec.rb
@@ -45,7 +45,7 @@ RSpec.describe CiPlatformMetric do
let(:tomorrow) { today + 1.day }
it 'inserts platform target counts for that day' do
- Timecop.freeze(today) do
+ travel_to(today) do
create(:ci_variable, key: described_class::CI_VARIABLE_KEY, value: 'ECS')
create(:ci_variable, key: described_class::CI_VARIABLE_KEY, value: 'ECS')
create(:ci_variable, key: described_class::CI_VARIABLE_KEY, value: 'FARGATE')
@@ -53,7 +53,7 @@ RSpec.describe CiPlatformMetric do
create(:ci_variable, key: described_class::CI_VARIABLE_KEY, value: 'FARGATE')
described_class.insert_auto_devops_platform_targets!
end
- Timecop.freeze(tomorrow) do
+ travel_to(tomorrow) do
create(:ci_variable, key: described_class::CI_VARIABLE_KEY, value: 'FARGATE')
described_class.insert_auto_devops_platform_targets!
end
@@ -69,7 +69,7 @@ RSpec.describe CiPlatformMetric do
let(:today) { Time.zone.local(1982, 4, 24) }
it 'ignores those values' do
- Timecop.freeze(today) do
+ travel_to(today) do
create(:ci_variable, key: described_class::CI_VARIABLE_KEY, value: 'ECS')
create(:ci_variable, key: described_class::CI_VARIABLE_KEY, value: 'FOO')
create(:ci_variable, key: described_class::CI_VARIABLE_KEY, value: 'BAR')
diff --git a/spec/models/clusters/agent_spec.rb b/spec/models/clusters/agent_spec.rb
index 99de0d1ddf7..148bb3cf870 100644
--- a/spec/models/clusters/agent_spec.rb
+++ b/spec/models/clusters/agent_spec.rb
@@ -13,6 +13,20 @@ RSpec.describe Clusters::Agent do
it { is_expected.to validate_uniqueness_of(:name).scoped_to(:project_id) }
describe 'scopes' do
+ describe '.ordered_by_name' do
+ let(:names) { %w(agent-d agent-b agent-a agent-c) }
+
+ subject { described_class.ordered_by_name }
+
+ before do
+ names.each do |name|
+ create(:cluster_agent, name: name)
+ end
+ end
+
+ it { expect(subject.map(&:name)).to eq(names.sort) }
+ end
+
describe '.with_name' do
let!(:matching_name) { create(:cluster_agent, name: 'matching-name') }
let!(:other_name) { create(:cluster_agent, name: 'other-name') }
diff --git a/spec/models/clusters/applications/fluentd_spec.rb b/spec/models/clusters/applications/fluentd_spec.rb
index be7b4a87947..3bda3e99ec1 100644
--- a/spec/models/clusters/applications/fluentd_spec.rb
+++ b/spec/models/clusters/applications/fluentd_spec.rb
@@ -25,7 +25,7 @@ RSpec.describe Clusters::Applications::Fluentd do
it 'is initialized with fluentd arguments' do
expect(subject.name).to eq('fluentd')
- expect(subject.chart).to eq('stable/fluentd')
+ expect(subject.chart).to eq('fluentd/fluentd')
expect(subject.version).to eq('2.4.0')
expect(subject).to be_rbac
end
diff --git a/spec/models/clusters/applications/ingress_spec.rb b/spec/models/clusters/applications/ingress_spec.rb
index e029283326f..196d57aff7b 100644
--- a/spec/models/clusters/applications/ingress_spec.rb
+++ b/spec/models/clusters/applications/ingress_spec.rb
@@ -135,7 +135,7 @@ RSpec.describe Clusters::Applications::Ingress do
it 'is initialized with ingress arguments' do
expect(subject.name).to eq('ingress')
- expect(subject.chart).to eq('stable/nginx-ingress')
+ expect(subject.chart).to eq('ingress/nginx-ingress')
expect(subject.version).to eq('1.40.2')
expect(subject).to be_rbac
expect(subject.files).to eq(ingress.files)
diff --git a/spec/models/clusters/applications/prometheus_spec.rb b/spec/models/clusters/applications/prometheus_spec.rb
index 82971596176..b450900bee6 100644
--- a/spec/models/clusters/applications/prometheus_spec.rb
+++ b/spec/models/clusters/applications/prometheus_spec.rb
@@ -152,7 +152,7 @@ RSpec.describe Clusters::Applications::Prometheus do
it 'is initialized with 3 arguments' do
expect(subject.name).to eq('prometheus')
- expect(subject.chart).to eq('stable/prometheus')
+ expect(subject.chart).to eq('prometheus/prometheus')
expect(subject.version).to eq('10.4.1')
expect(subject).to be_rbac
expect(subject.files).to eq(prometheus.files)
@@ -240,7 +240,7 @@ RSpec.describe Clusters::Applications::Prometheus do
it 'is initialized with 3 arguments' do
expect(patch_command.name).to eq('prometheus')
- expect(patch_command.chart).to eq('stable/prometheus')
+ expect(patch_command.chart).to eq('prometheus/prometheus')
expect(patch_command.version).to eq('10.4.1')
expect(patch_command.files).to eq(prometheus.files)
end
diff --git a/spec/models/clusters/applications/runner_spec.rb b/spec/models/clusters/applications/runner_spec.rb
index fbabfd25b2f..ef916c73e0b 100644
--- a/spec/models/clusters/applications/runner_spec.rb
+++ b/spec/models/clusters/applications/runner_spec.rb
@@ -69,8 +69,8 @@ RSpec.describe Clusters::Applications::Runner do
expect(values).to include('privileged: true')
expect(values).to include('image: ubuntu:16.04')
expect(values).to include('resources')
- expect(values).to match(/runnerToken: '?#{Regexp.escape(ci_runner.token)}/)
- expect(values).to match(/gitlabUrl: '?#{Regexp.escape(Gitlab::Routing.url_helpers.root_url)}/)
+ expect(values).to match(/runnerToken: ['"]?#{Regexp.escape(ci_runner.token)}/)
+ expect(values).to match(/gitlabUrl: ['"]?#{Regexp.escape(Gitlab::Routing.url_helpers.root_url)}/)
end
context 'without a runner' do
diff --git a/spec/models/clusters/cluster_spec.rb b/spec/models/clusters/cluster_spec.rb
index 024539e34ec..dd9b96f39ad 100644
--- a/spec/models/clusters/cluster_spec.rb
+++ b/spec/models/clusters/cluster_spec.rb
@@ -47,6 +47,7 @@ RSpec.describe Clusters::Cluster, :use_clean_rails_memory_store_caching do
it { is_expected.to delegate_method(:external_hostname).to(:application_ingress).with_prefix }
it { is_expected.to respond_to :project }
+ it { is_expected.to be_namespace_per_environment }
describe 'applications have inverse_of: :cluster option' do
let(:cluster) { create(:cluster) }
diff --git a/spec/models/clusters/platforms/kubernetes_spec.rb b/spec/models/clusters/platforms/kubernetes_spec.rb
index c6a2b67a008..e877ba2ac96 100644
--- a/spec/models/clusters/platforms/kubernetes_spec.rb
+++ b/spec/models/clusters/platforms/kubernetes_spec.rb
@@ -412,7 +412,7 @@ RSpec.describe Clusters::Platforms::Kubernetes do
end
let(:namespace) { "project-namespace" }
- let(:environment) { instance_double(Environment, deployment_namespace: namespace) }
+ let(:environment) { instance_double(Environment, deployment_namespace: namespace, project: service.cluster.project) }
subject { service.calculate_reactive_cache_for(environment) }
@@ -428,6 +428,7 @@ RSpec.describe Clusters::Platforms::Kubernetes do
before do
stub_kubeclient_pods(namespace)
stub_kubeclient_deployments(namespace)
+ stub_kubeclient_ingresses(namespace)
end
it { is_expected.to include(pods: [expected_pod_cached_data]) }
@@ -437,6 +438,7 @@ RSpec.describe Clusters::Platforms::Kubernetes do
before do
stub_kubeclient_pods(namespace, status: 500)
stub_kubeclient_deployments(namespace, status: 500)
+ stub_kubeclient_ingresses(namespace, status: 500)
end
it { expect { subject }.to raise_error(Kubeclient::HttpError) }
@@ -446,6 +448,7 @@ RSpec.describe Clusters::Platforms::Kubernetes do
before do
stub_kubeclient_pods(namespace, status: 404)
stub_kubeclient_deployments(namespace, status: 404)
+ stub_kubeclient_ingresses(namespace, status: 404)
end
it { is_expected.to include(pods: []) }
diff --git a/spec/models/commit_status_spec.rb b/spec/models/commit_status_spec.rb
index 6e23f95af03..877188097fd 100644
--- a/spec/models/commit_status_spec.rb
+++ b/spec/models/commit_status_spec.rb
@@ -493,47 +493,104 @@ RSpec.describe CommitStatus do
end
end
- describe '#group_name' do
- let(:commit_status) do
- build(:commit_status, pipeline: pipeline, stage: 'test')
- end
-
- subject { commit_status.group_name }
+ context 'with the one_dimensional_matrix feature flag disabled' do
+ describe '#group_name' do
+ before do
+ stub_feature_flags(one_dimensional_matrix: false)
+ end
- tests = {
- 'rspec:windows' => 'rspec:windows',
- 'rspec:windows 0' => 'rspec:windows 0',
- 'rspec:windows 0 test' => 'rspec:windows 0 test',
- 'rspec:windows 0 1' => 'rspec:windows',
- 'rspec:windows 0 1 name' => 'rspec:windows name',
- 'rspec:windows 0/1' => 'rspec:windows',
- 'rspec:windows 0/1 name' => 'rspec:windows name',
- 'rspec:windows 0:1' => 'rspec:windows',
- 'rspec:windows 0:1 name' => 'rspec:windows name',
- 'rspec:windows 10000 20000' => 'rspec:windows',
- 'rspec:windows 0 : / 1' => 'rspec:windows',
- 'rspec:windows 0 : / 1 name' => 'rspec:windows name',
- '0 1 name ruby' => 'name ruby',
- '0 :/ 1 name ruby' => 'name ruby',
- 'rspec: [aws]' => 'rspec: [aws]',
- 'rspec: [aws] 0/1' => 'rspec: [aws]',
- 'rspec: [aws, max memory]' => 'rspec',
- 'rspec:linux: [aws, max memory, data]' => 'rspec:linux',
- 'rspec: [inception: [something, other thing], value]' => 'rspec',
- 'rspec:windows 0/1: [name, other]' => 'rspec:windows',
- 'rspec:windows: [name, other] 0/1' => 'rspec:windows',
- 'rspec:windows: [name, 0/1] 0/1' => 'rspec:windows',
- 'rspec:windows: [0/1, name]' => 'rspec:windows',
- 'rspec:windows: [, ]' => 'rspec:windows',
- 'rspec:windows: [name]' => 'rspec:windows: [name]',
- 'rspec:windows: [name,other]' => 'rspec:windows: [name,other]'
- }
+ let(:commit_status) do
+ build(:commit_status, pipeline: pipeline, stage: 'test')
+ end
+
+ subject { commit_status.group_name }
+
+ tests = {
+ 'rspec:windows' => 'rspec:windows',
+ 'rspec:windows 0' => 'rspec:windows 0',
+ 'rspec:windows 0 test' => 'rspec:windows 0 test',
+ 'rspec:windows 0 1' => 'rspec:windows',
+ 'rspec:windows 0 1 name' => 'rspec:windows name',
+ 'rspec:windows 0/1' => 'rspec:windows',
+ 'rspec:windows 0/1 name' => 'rspec:windows name',
+ 'rspec:windows 0:1' => 'rspec:windows',
+ 'rspec:windows 0:1 name' => 'rspec:windows name',
+ 'rspec:windows 10000 20000' => 'rspec:windows',
+ 'rspec:windows 0 : / 1' => 'rspec:windows',
+ 'rspec:windows 0 : / 1 name' => 'rspec:windows name',
+ '0 1 name ruby' => 'name ruby',
+ '0 :/ 1 name ruby' => 'name ruby',
+ 'rspec: [aws]' => 'rspec: [aws]',
+ 'rspec: [aws] 0/1' => 'rspec: [aws]',
+ 'rspec: [aws, max memory]' => 'rspec',
+ 'rspec:linux: [aws, max memory, data]' => 'rspec:linux',
+ 'rspec: [inception: [something, other thing], value]' => 'rspec',
+ 'rspec:windows 0/1: [name, other]' => 'rspec:windows',
+ 'rspec:windows: [name, other] 0/1' => 'rspec:windows',
+ 'rspec:windows: [name, 0/1] 0/1' => 'rspec:windows',
+ 'rspec:windows: [0/1, name]' => 'rspec:windows',
+ 'rspec:windows: [, ]' => 'rspec:windows',
+ 'rspec:windows: [name]' => 'rspec:windows: [name]',
+ 'rspec:windows: [name,other]' => 'rspec:windows: [name,other]'
+ }
+
+ tests.each do |name, group_name|
+ it "'#{name}' puts in '#{group_name}'" do
+ commit_status.name = name
+
+ is_expected.to eq(group_name)
+ end
+ end
+ end
+ end
- tests.each do |name, group_name|
- it "'#{name}' puts in '#{group_name}'" do
- commit_status.name = name
+ context 'with one_dimensional_matrix feature flag enabled' do
+ describe '#group_name' do
+ before do
+ stub_feature_flags(one_dimensional_matrix: true)
+ end
- is_expected.to eq(group_name)
+ let(:commit_status) do
+ build(:commit_status, pipeline: pipeline, stage: 'test')
+ end
+
+ subject { commit_status.group_name }
+
+ tests = {
+ 'rspec:windows' => 'rspec:windows',
+ 'rspec:windows 0' => 'rspec:windows 0',
+ 'rspec:windows 0 test' => 'rspec:windows 0 test',
+ 'rspec:windows 0 1' => 'rspec:windows',
+ 'rspec:windows 0 1 name' => 'rspec:windows name',
+ 'rspec:windows 0/1' => 'rspec:windows',
+ 'rspec:windows 0/1 name' => 'rspec:windows name',
+ 'rspec:windows 0:1' => 'rspec:windows',
+ 'rspec:windows 0:1 name' => 'rspec:windows name',
+ 'rspec:windows 10000 20000' => 'rspec:windows',
+ 'rspec:windows 0 : / 1' => 'rspec:windows',
+ 'rspec:windows 0 : / 1 name' => 'rspec:windows name',
+ '0 1 name ruby' => 'name ruby',
+ '0 :/ 1 name ruby' => 'name ruby',
+ 'rspec: [aws]' => 'rspec',
+ 'rspec: [aws] 0/1' => 'rspec',
+ 'rspec: [aws, max memory]' => 'rspec',
+ 'rspec:linux: [aws, max memory, data]' => 'rspec:linux',
+ 'rspec: [inception: [something, other thing], value]' => 'rspec',
+ 'rspec:windows 0/1: [name, other]' => 'rspec:windows',
+ 'rspec:windows: [name, other] 0/1' => 'rspec:windows',
+ 'rspec:windows: [name, 0/1] 0/1' => 'rspec:windows',
+ 'rspec:windows: [0/1, name]' => 'rspec:windows',
+ 'rspec:windows: [, ]' => 'rspec:windows',
+ 'rspec:windows: [name]' => 'rspec:windows',
+ 'rspec:windows: [name,other]' => 'rspec:windows'
+ }
+
+ tests.each do |name, group_name|
+ it "'#{name}' puts in '#{group_name}'" do
+ commit_status.name = name
+
+ is_expected.to eq(group_name)
+ end
end
end
end
diff --git a/spec/models/concerns/avatarable_spec.rb b/spec/models/concerns/avatarable_spec.rb
index 8a8eeea39dc..5bed2cb9a14 100644
--- a/spec/models/concerns/avatarable_spec.rb
+++ b/spec/models/concerns/avatarable_spec.rb
@@ -21,7 +21,7 @@ RSpec.describe Avatarable do
it 'validates the file size' do
expect(validator).to receive(:validate_each).and_call_original
- project.update(avatar: 'uploads/avatar.png')
+ project.update!(avatar: 'uploads/avatar.png')
end
end
@@ -29,7 +29,7 @@ RSpec.describe Avatarable do
it 'skips validation of file size' do
expect(validator).not_to receive(:validate_each)
- project.update(name: 'Hello world')
+ project.update!(name: 'Hello world')
end
end
end
diff --git a/spec/models/concerns/bulk_insertable_associations_spec.rb b/spec/models/concerns/bulk_insertable_associations_spec.rb
index 5a40639e493..25b13c8233d 100644
--- a/spec/models/concerns/bulk_insertable_associations_spec.rb
+++ b/spec/models/concerns/bulk_insertable_associations_spec.rb
@@ -187,7 +187,7 @@ RSpec.describe BulkInsertableAssociations do
it 'invalidates the parent and returns false' do
build_invalid_items(parent: parent)
- expect(save_with_bulk_inserts(parent, bangify: false)).to be false
+ expect(BulkInsertableAssociations.with_bulk_insert { parent.save }).to be false # rubocop:disable Rails/SaveBang
expect(parent.errors[:bulk_foos].size).to eq(1)
expect(BulkFoo.count).to eq(0)
@@ -211,8 +211,8 @@ RSpec.describe BulkInsertableAssociations do
private
- def save_with_bulk_inserts(entity, bangify: true)
- BulkInsertableAssociations.with_bulk_insert { bangify ? entity.save! : entity.save }
+ def save_with_bulk_inserts(entity)
+ BulkInsertableAssociations.with_bulk_insert { entity.save! }
end
def build_items(parent:, relation: :bulk_foos, count: 10)
diff --git a/spec/models/concerns/cache_markdown_field_spec.rb b/spec/models/concerns/cache_markdown_field_spec.rb
index 440943171c3..37e2f5fb8d4 100644
--- a/spec/models/concerns/cache_markdown_field_spec.rb
+++ b/spec/models/concerns/cache_markdown_field_spec.rb
@@ -285,7 +285,7 @@ RSpec.describe CacheMarkdownField, :clean_gitlab_redis_cache do
it_behaves_like 'a class with cached markdown fields'
describe '#attribute_invalidated?' do
- let(:thing) { klass.create(description: markdown, description_html: html, cached_markdown_version: cache_version) }
+ let(:thing) { klass.create!(description: markdown, description_html: html, cached_markdown_version: cache_version) }
it 'returns true when cached_markdown_version is different' do
thing.cached_markdown_version += 1
@@ -318,7 +318,7 @@ RSpec.describe CacheMarkdownField, :clean_gitlab_redis_cache do
let(:thing) do
# This forces the record to have outdated HTML. We can't use `create` because the `before_create` hook
# would re-render the HTML to the latest version
- klass.create.tap do |thing|
+ klass.create!.tap do |thing|
thing.update_columns(description: markdown, description_html: old_html, cached_markdown_version: old_version)
end
end
@@ -326,7 +326,7 @@ RSpec.describe CacheMarkdownField, :clean_gitlab_redis_cache do
it 'correctly updates cached HTML even if refresh_markdown_cache is called before updating the attribute' do
thing.refresh_markdown_cache
- thing.update(description: updated_markdown)
+ thing.update!(description: updated_markdown)
expect(thing.description_html).to eq(updated_html)
end
diff --git a/spec/models/concerns/case_sensitivity_spec.rb b/spec/models/concerns/case_sensitivity_spec.rb
index 521b47c63fd..5fb7cdb4443 100644
--- a/spec/models/concerns/case_sensitivity_spec.rb
+++ b/spec/models/concerns/case_sensitivity_spec.rb
@@ -12,8 +12,8 @@ RSpec.describe CaseSensitivity do
end
end
- let!(:model_1) { model.create(path: 'mOdEl-1', name: 'mOdEl 1') }
- let!(:model_2) { model.create(path: 'mOdEl-2', name: 'mOdEl 2') }
+ let!(:model_1) { model.create!(path: 'mOdEl-1', name: 'mOdEl 1') }
+ let!(:model_2) { model.create!(path: 'mOdEl-2', name: 'mOdEl 2') }
it 'finds a single instance by a single attribute regardless of case' do
expect(model.iwhere(path: 'MODEL-1')).to contain_exactly(model_1)
diff --git a/spec/models/concerns/checksummable_spec.rb b/spec/models/concerns/checksummable_spec.rb
index b469b2e5c18..3a0387333e8 100644
--- a/spec/models/concerns/checksummable_spec.rb
+++ b/spec/models/concerns/checksummable_spec.rb
@@ -3,17 +3,21 @@
require 'spec_helper'
RSpec.describe Checksummable do
- describe ".hexdigest" do
- let(:fake_class) do
- Class.new do
- include Checksummable
- end
+ subject do
+ Class.new { include Checksummable }
+ end
+
+ describe ".crc32" do
+ it 'returns the CRC32 of data' do
+ expect(subject.crc32('abcd')).to eq 3984772369
end
+ end
+ describe ".hexdigest" do
it 'returns the SHA256 sum of the file' do
expected = Digest::SHA256.file(__FILE__).hexdigest
- expect(fake_class.hexdigest(__FILE__)).to eq(expected)
+ expect(subject.hexdigest(__FILE__)).to eq(expected)
end
end
end
diff --git a/spec/models/concerns/counter_attribute_spec.rb b/spec/models/concerns/counter_attribute_spec.rb
index f23865a5dbb..a19fbae3cfb 100644
--- a/spec/models/concerns/counter_attribute_spec.rb
+++ b/spec/models/concerns/counter_attribute_spec.rb
@@ -12,6 +12,36 @@ RSpec.describe CounterAttribute, :counter_attribute, :clean_gitlab_redis_shared_
let(:model) { CounterAttributeModel.find(project_statistics.id) }
end
+ describe 'after_flush callbacks' do
+ let(:attribute) { model.class.counter_attributes.first}
+
+ subject { model.flush_increments_to_database!(attribute) }
+
+ it 'has registered callbacks' do # defined in :counter_attribute RSpec tag
+ expect(model.class.after_flush_callbacks.size).to eq(1)
+ end
+
+ context 'when there are increments to flush' do
+ before do
+ model.delayed_increment_counter(attribute, 10)
+ end
+
+ it 'executes the callbacks' do
+ subject
+
+ expect(model.flushed).to be_truthy
+ end
+ end
+
+ context 'when there are no increments to flush' do
+ it 'does not execute the callbacks' do
+ subject
+
+ expect(model.flushed).to be_nil
+ end
+ end
+ end
+
describe '.steal_increments' do
let(:increment_key) { 'counters:Model:123:attribute' }
let(:flushed_key) { 'counter:Model:123:attribute:flushed' }
diff --git a/spec/models/concerns/each_batch_spec.rb b/spec/models/concerns/each_batch_spec.rb
index 3c93c8a7a79..8b70753633c 100644
--- a/spec/models/concerns/each_batch_spec.rb
+++ b/spec/models/concerns/each_batch_spec.rb
@@ -18,13 +18,13 @@ RSpec.describe EachBatch do
shared_examples 'each_batch handling' do |kwargs|
it 'yields an ActiveRecord::Relation when a block is given' do
- model.each_batch(kwargs) do |relation|
+ model.each_batch(**kwargs) do |relation|
expect(relation).to be_a_kind_of(ActiveRecord::Relation)
end
end
it 'yields a batch index as the second argument' do
- model.each_batch(kwargs) do |_, index|
+ model.each_batch(**kwargs) do |_, index|
expect(index).to eq(1)
end
end
@@ -32,7 +32,7 @@ RSpec.describe EachBatch do
it 'accepts a custom batch size' do
amount = 0
- model.each_batch(kwargs.merge({ of: 1 })) { amount += 1 }
+ model.each_batch(**kwargs.merge({ of: 1 })) { amount += 1 }
expect(amount).to eq(5)
end
diff --git a/spec/models/concerns/featurable_spec.rb b/spec/models/concerns/featurable_spec.rb
index 31186b5fc77..99acc563950 100644
--- a/spec/models/concerns/featurable_spec.rb
+++ b/spec/models/concerns/featurable_spec.rb
@@ -180,6 +180,6 @@ RSpec.describe Featurable do
def update_all_project_features(project, features, value)
project_feature_attributes = features.map { |f| ["#{f}_access_level", value] }.to_h
- project.project_feature.update(project_feature_attributes)
+ project.project_feature.update!(project_feature_attributes)
end
end
diff --git a/spec/models/concerns/has_user_type_spec.rb b/spec/models/concerns/has_user_type_spec.rb
index 9496bb57b8b..c87bbf24c30 100644
--- a/spec/models/concerns/has_user_type_spec.rb
+++ b/spec/models/concerns/has_user_type_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe User do
specify 'types consistency checks', :aggregate_failures do
expect(described_class::USER_TYPES.keys)
- .to match_array(%w[human ghost alert_bot project_bot support_bot service_user visual_review_bot migration_bot])
+ .to match_array(%w[human ghost alert_bot project_bot support_bot service_user security_bot visual_review_bot migration_bot])
expect(described_class::USER_TYPES).to include(*described_class::BOT_USER_TYPES)
expect(described_class::USER_TYPES).to include(*described_class::NON_INTERNAL_USER_TYPES)
expect(described_class::USER_TYPES).to include(*described_class::INTERNAL_USER_TYPES)
@@ -31,6 +31,12 @@ RSpec.describe User do
end
end
+ describe '.without_bots' do
+ it 'includes everyone except bots' do
+ expect(described_class.without_bots).to match_array(everyone - bots)
+ end
+ end
+
describe '.bots_without_project_bot' do
it 'includes all bots except project_bot' do
expect(described_class.bots_without_project_bot).to match_array(bots - [project_bot])
diff --git a/spec/models/concerns/issuable_spec.rb b/spec/models/concerns/issuable_spec.rb
index 44561e2e55a..ff5b270cf33 100644
--- a/spec/models/concerns/issuable_spec.rb
+++ b/spec/models/concerns/issuable_spec.rb
@@ -69,7 +69,7 @@ RSpec.describe Issuable do
it 'returns nil when author is nil' do
issue.author_id = nil
- issue.save(validate: false)
+ issue.save!(validate: false)
expect(issue.author_name).to eq nil
end
@@ -361,13 +361,13 @@ RSpec.describe Issuable do
end
it 'returns true when a subcription exists and subscribed is true' do
- issue.subscriptions.create(user: user, project: project, subscribed: true)
+ issue.subscriptions.create!(user: user, project: project, subscribed: true)
expect(issue.subscribed?(user, project)).to be_truthy
end
it 'returns false when a subcription exists and subscribed is false' do
- issue.subscriptions.create(user: user, project: project, subscribed: false)
+ issue.subscriptions.create!(user: user, project: project, subscribed: false)
expect(issue.subscribed?(user, project)).to be_falsey
end
@@ -383,13 +383,13 @@ RSpec.describe Issuable do
end
it 'returns true when a subcription exists and subscribed is true' do
- issue.subscriptions.create(user: user, project: project, subscribed: true)
+ issue.subscriptions.create!(user: user, project: project, subscribed: true)
expect(issue.subscribed?(user, project)).to be_truthy
end
it 'returns false when a subcription exists and subscribed is false' do
- issue.subscriptions.create(user: user, project: project, subscribed: false)
+ issue.subscriptions.create!(user: user, project: project, subscribed: false)
expect(issue.subscribed?(user, project)).to be_falsey
end
@@ -437,7 +437,7 @@ RSpec.describe Issuable do
let(:labels) { create_list(:label, 2) }
before do
- issue.update(labels: [labels[1]])
+ issue.update!(labels: [labels[1]])
expect(Gitlab::HookData::IssuableBuilder)
.to receive(:new).with(issue).and_return(builder)
end
@@ -456,7 +456,7 @@ RSpec.describe Issuable do
context 'total_time_spent is updated' do
before do
issue.spend_time(duration: 2, user_id: user.id, spent_at: Time.current)
- issue.save
+ issue.save!
expect(Gitlab::HookData::IssuableBuilder)
.to receive(:new).with(issue).and_return(builder)
end
@@ -497,8 +497,8 @@ RSpec.describe Issuable do
let(:user2) { create(:user) }
before do
- merge_request.update(assignees: [user])
- merge_request.update(assignees: [user, user2])
+ merge_request.update!(assignees: [user])
+ merge_request.update!(assignees: [user, user2])
expect(Gitlab::HookData::IssuableBuilder)
.to receive(:new).with(merge_request).and_return(builder)
end
@@ -554,7 +554,7 @@ RSpec.describe Issuable do
before do
label_link = issue.label_links.find_by(label_id: second_label.id)
label_link.label_id = nil
- label_link.save(validate: false)
+ label_link.save!(validate: false)
end
it 'filters out bad labels' do
@@ -824,7 +824,7 @@ RSpec.describe Issuable do
where(:issuable_type, :supports_time_tracking) do
:issue | true
- :incident | false
+ :incident | true
:merge_request | true
end
@@ -926,58 +926,4 @@ RSpec.describe Issuable do
end
end
end
-
- describe '#update_severity' do
- let(:severity) { 'low' }
-
- subject(:update_severity) { issuable.update_severity(severity) }
-
- context 'when issuable not an incident' do
- %i(issue merge_request).each do |issuable_type|
- let(:issuable) { build_stubbed(issuable_type) }
-
- it { is_expected.to be_nil }
-
- it 'does not set severity' do
- expect { subject }.not_to change(IssuableSeverity, :count)
- end
- end
- end
-
- context 'when issuable is an incident' do
- let!(:issuable) { create(:incident) }
-
- context 'when issuable does not have issuable severity yet' do
- it 'creates new record' do
- expect { update_severity }.to change { IssuableSeverity.where(issue: issuable).count }.to(1)
- end
-
- it 'sets severity to specified value' do
- expect { update_severity }.to change { issuable.severity }.to('low')
- end
- end
-
- context 'when issuable has an issuable severity' do
- let!(:issuable_severity) { create(:issuable_severity, issue: issuable, severity: 'medium') }
-
- it 'does not create new record' do
- expect { update_severity }.not_to change(IssuableSeverity, :count)
- end
-
- it 'updates existing issuable severity' do
- expect { update_severity }.to change { issuable_severity.severity }.to(severity)
- end
- end
-
- context 'when severity value is unsupported' do
- let(:severity) { 'unsupported-severity' }
-
- it 'sets the severity to default value' do
- update_severity
-
- expect(issuable.issuable_severity.severity).to eq(IssuableSeverity::DEFAULT)
- end
- end
- end
- end
end
diff --git a/spec/models/concerns/mentionable_spec.rb b/spec/models/concerns/mentionable_spec.rb
index 758b5aa2ce4..516c0fd75bc 100644
--- a/spec/models/concerns/mentionable_spec.rb
+++ b/spec/models/concerns/mentionable_spec.rb
@@ -177,7 +177,7 @@ RSpec.describe Issue, "Mentionable" do
expect(SystemNoteService).not_to receive(:cross_reference)
- issue.update(description: 'New description')
+ issue.update!(description: 'New description')
issue.create_new_cross_references!
end
@@ -186,7 +186,7 @@ RSpec.describe Issue, "Mentionable" do
expect(SystemNoteService).to receive(:cross_reference).with(issues[1], any_args)
- issue.update(description: issues[1].to_reference)
+ issue.update!(description: issues[1].to_reference)
issue.create_new_cross_references!
end
@@ -196,7 +196,7 @@ RSpec.describe Issue, "Mentionable" do
expect(SystemNoteService).to receive(:cross_reference).with(issues[1], any_args)
- note.update(note: issues[1].to_reference)
+ note.update!(note: issues[1].to_reference)
note.create_new_cross_references!
end
end
diff --git a/spec/models/concerns/milestoneable_spec.rb b/spec/models/concerns/milestoneable_spec.rb
index f5b82e42ad4..c37582cb65d 100644
--- a/spec/models/concerns/milestoneable_spec.rb
+++ b/spec/models/concerns/milestoneable_spec.rb
@@ -61,7 +61,7 @@ RSpec.describe Milestoneable do
it 'returns true with a milestone from the the parent of the issue project group' do
parent = create(:group)
- group.update(parent: parent)
+ group.update!(parent: parent)
milestone = create(:milestone, group: parent)
expect(build_milestoneable(milestone.id).milestone_available?).to be_truthy
diff --git a/spec/models/concerns/milestoneish_spec.rb b/spec/models/concerns/milestoneish_spec.rb
index 58cd054efd5..3b8fc465421 100644
--- a/spec/models/concerns/milestoneish_spec.rb
+++ b/spec/models/concerns/milestoneish_spec.rb
@@ -102,7 +102,7 @@ RSpec.describe Milestone, 'Milestoneish' do
with_them do
before do
- project.update(visibility_level: project_visibility_levels[visibility])
+ project.update!(visibility_level: project_visibility_levels[visibility])
end
it 'returns the proper participants' do
@@ -139,7 +139,7 @@ RSpec.describe Milestone, 'Milestoneish' do
with_them do
before do
- project.update(visibility_level: project_visibility_levels[visibility])
+ project.update!(visibility_level: project_visibility_levels[visibility])
end
it 'returns the proper participants' do
@@ -171,7 +171,7 @@ RSpec.describe Milestone, 'Milestoneish' do
context 'when project is private' do
before do
- project.update(visibility_level: Gitlab::VisibilityLevel::PRIVATE)
+ project.update!(visibility_level: Gitlab::VisibilityLevel::PRIVATE)
end
it 'does not return any merge request for a non member' do
@@ -195,7 +195,7 @@ RSpec.describe Milestone, 'Milestoneish' do
context 'when merge requests are available to project members' do
before do
- project.project_feature.update(merge_requests_access_level: ProjectFeature::PRIVATE)
+ project.project_feature.update!(merge_requests_access_level: ProjectFeature::PRIVATE)
end
it 'does not return any merge request for a non member' do
diff --git a/spec/models/concerns/reactive_caching_spec.rb b/spec/models/concerns/reactive_caching_spec.rb
index b12ad82920f..7e031bdd263 100644
--- a/spec/models/concerns/reactive_caching_spec.rb
+++ b/spec/models/concerns/reactive_caching_spec.rb
@@ -14,6 +14,7 @@ RSpec.describe ReactiveCaching, :use_clean_rails_memory_store_caching do
self.reactive_cache_lifetime = 5.minutes
self.reactive_cache_refresh_interval = 15.seconds
+ self.reactive_cache_work_type = :no_dependency
attr_reader :id
@@ -372,4 +373,14 @@ RSpec.describe ReactiveCaching, :use_clean_rails_memory_store_caching do
it { expect(subject.reactive_cache_hard_limit).to be_nil }
it { expect(subject.reactive_cache_worker_finder).to respond_to(:call) }
end
+
+ describe 'classes including this concern' do
+ it 'sets reactive_cache_work_type' do
+ classes = ObjectSpace.each_object(Class).select do |klass|
+ klass < described_class && klass.name
+ end
+
+ expect(classes).to all(have_attributes(reactive_cache_work_type: be_in(described_class::WORK_TYPE.keys)))
+ end
+ end
end
diff --git a/spec/models/concerns/resolvable_discussion_spec.rb b/spec/models/concerns/resolvable_discussion_spec.rb
index c91ddfee944..c0e5ddc23b1 100644
--- a/spec/models/concerns/resolvable_discussion_spec.rb
+++ b/spec/models/concerns/resolvable_discussion_spec.rb
@@ -553,13 +553,13 @@ RSpec.describe Discussion, ResolvableDiscussion do
let(:time) { Time.current.utc }
before do
- Timecop.freeze(time - 1.second) do
+ travel_to(time - 1.second) do
first_note.resolve!(current_user)
end
- Timecop.freeze(time) do
+ travel_to(time) do
third_note.resolve!(current_user)
end
- Timecop.freeze(time + 1.second) do
+ travel_to(time + 1.second) do
second_note.resolve!(current_user)
end
end
diff --git a/spec/models/concerns/routable_spec.rb b/spec/models/concerns/routable_spec.rb
index 15d754861b2..e4cf68663ef 100644
--- a/spec/models/concerns/routable_spec.rb
+++ b/spec/models/concerns/routable_spec.rb
@@ -22,7 +22,7 @@ RSpec.describe Group, 'Routable' do
end
it 'updates route record on path change' do
- group.update(path: 'wow', name: 'much')
+ group.update!(path: 'wow', name: 'much')
expect(group.route.path).to eq('wow')
expect(group.route.name).to eq('much')
diff --git a/spec/models/concerns/schedulable_spec.rb b/spec/models/concerns/schedulable_spec.rb
index 875c2d80e55..62acd12e267 100644
--- a/spec/models/concerns/schedulable_spec.rb
+++ b/spec/models/concerns/schedulable_spec.rb
@@ -35,7 +35,7 @@ RSpec.describe Schedulable do
context 'for a pipeline_schedule' do
# let! is used to reset the next_run_at value before each spec
let(:object) do
- Timecop.freeze(1.day.ago) do
+ travel_to(1.day.ago) do
create(:ci_pipeline_schedule, :hourly)
end
end
diff --git a/spec/models/concerns/subscribable_spec.rb b/spec/models/concerns/subscribable_spec.rb
index 2a43e748e58..3e52ca5cf63 100644
--- a/spec/models/concerns/subscribable_spec.rb
+++ b/spec/models/concerns/subscribable_spec.rb
@@ -20,13 +20,13 @@ RSpec.describe Subscribable, 'Subscribable' do
end
it 'returns true when a subcription exists and subscribed is true' do
- resource.subscriptions.create(user: user_1, subscribed: true)
+ resource.subscriptions.create!(user: user_1, subscribed: true)
expect(resource.subscribed?(user_1)).to be_truthy
end
it 'returns false when a subcription exists and subscribed is false' do
- resource.subscriptions.create(user: user_1, subscribed: false)
+ resource.subscriptions.create!(user: user_1, subscribed: false)
expect(resource.subscribed?(user_1)).to be_falsey
end
@@ -38,13 +38,13 @@ RSpec.describe Subscribable, 'Subscribable' do
end
it 'returns true when a subcription exists and subscribed is true' do
- resource.subscriptions.create(user: user_1, project: project, subscribed: true)
+ resource.subscriptions.create!(user: user_1, project: project, subscribed: true)
expect(resource.subscribed?(user_1, project)).to be_truthy
end
it 'returns false when a subcription exists and subscribed is false' do
- resource.subscriptions.create(user: user_1, project: project, subscribed: false)
+ resource.subscriptions.create!(user: user_1, project: project, subscribed: false)
expect(resource.subscribed?(user_1, project)).to be_falsey
end
@@ -58,9 +58,9 @@ RSpec.describe Subscribable, 'Subscribable' do
it 'returns the subscribed users' do
user_2 = create(:user)
- resource.subscriptions.create(user: user_1, subscribed: true)
- resource.subscriptions.create(user: user_2, project: project, subscribed: true)
- resource.subscriptions.create(user: create(:user), project: project, subscribed: false)
+ resource.subscriptions.create!(user: user_1, subscribed: true)
+ resource.subscriptions.create!(user: user_2, project: project, subscribed: true)
+ resource.subscriptions.create!(user: create(:user), project: project, subscribed: false)
expect(resource.subscribers(project)).to contain_exactly(user_1, user_2)
end
@@ -113,7 +113,7 @@ RSpec.describe Subscribable, 'Subscribable' do
describe '#unsubscribe' do
context 'without project' do
it 'unsubscribes the given current user' do
- resource.subscriptions.create(user: user_1, subscribed: true)
+ resource.subscriptions.create!(user: user_1, subscribed: true)
expect(resource.subscribed?(user_1)).to be_truthy
resource.unsubscribe(user_1)
@@ -124,7 +124,7 @@ RSpec.describe Subscribable, 'Subscribable' do
context 'with project' do
it 'unsubscribes the given current user' do
- resource.subscriptions.create(user: user_1, project: project, subscribed: true)
+ resource.subscriptions.create!(user: user_1, project: project, subscribed: true)
expect(resource.subscribed?(user_1, project)).to be_truthy
resource.unsubscribe(user_1, project)
@@ -139,7 +139,7 @@ RSpec.describe Subscribable, 'Subscribable' do
context 'when desired_state is set to true' do
context 'when a user is subscribed to the resource' do
it 'keeps the user subscribed' do
- resource.subscriptions.create(user: user_1, subscribed: true, project: resource_project)
+ resource.subscriptions.create!(user: user_1, subscribed: true, project: resource_project)
resource.set_subscription(user_1, true, resource_project)
@@ -159,7 +159,7 @@ RSpec.describe Subscribable, 'Subscribable' do
context 'when desired_state is set to false' do
context 'when a user is subscribed to the resource' do
it 'unsubscribes the user from the resource' do
- resource.subscriptions.create(user: user_1, subscribed: true, project: resource_project)
+ resource.subscriptions.create!(user: user_1, subscribed: true, project: resource_project)
expect { resource.set_subscription(user_1, false, resource_project) }
.to change { resource.subscribed?(user_1, resource_project) }
diff --git a/spec/models/concerns/token_authenticatable_spec.rb b/spec/models/concerns/token_authenticatable_spec.rb
index e0e764fc63c..90e94b5dca9 100644
--- a/spec/models/concerns/token_authenticatable_spec.rb
+++ b/spec/models/concerns/token_authenticatable_spec.rb
@@ -137,7 +137,7 @@ RSpec.describe PersonalAccessToken, 'TokenAuthenticatable' do
subject { PersonalAccessToken.find_by_token(token_value) }
it 'finds the token' do
- personal_access_token.save
+ personal_access_token.save!
expect(subject).to eq(personal_access_token)
end
diff --git a/spec/models/container_expiration_policy_spec.rb b/spec/models/container_expiration_policy_spec.rb
index 588685b04bf..1d9dbe8a867 100644
--- a/spec/models/container_expiration_policy_spec.rb
+++ b/spec/models/container_expiration_policy_spec.rb
@@ -104,6 +104,18 @@ RSpec.describe ContainerExpirationPolicy, type: :model do
end
end
+ describe '.executable' do
+ subject { described_class.executable }
+
+ let_it_be(:policy1) { create(:container_expiration_policy, :runnable) }
+ let_it_be(:container_repository1) { create(:container_repository, project: policy1.project) }
+ let_it_be(:policy2) { create(:container_expiration_policy, :runnable) }
+ let_it_be(:container_repository2) { create(:container_repository, project: policy2.project) }
+ let_it_be(:policy3) { create(:container_expiration_policy, :runnable) }
+
+ it { is_expected.to contain_exactly(policy1, policy2) }
+ end
+
describe '#disable!' do
let_it_be(:container_expiration_policy) { create(:container_expiration_policy) }
diff --git a/spec/models/container_repository_spec.rb b/spec/models/container_repository_spec.rb
index 953f92d103b..2a7aaed5204 100644
--- a/spec/models/container_repository_spec.rb
+++ b/spec/models/container_repository_spec.rb
@@ -184,6 +184,33 @@ RSpec.describe ContainerRepository do
end
end
+ describe '#start_expiration_policy!' do
+ subject { repository.start_expiration_policy! }
+
+ it 'sets the expiration policy started at to now' do
+ Timecop.freeze do
+ expect { subject }
+ .to change { repository.expiration_policy_started_at }.from(nil).to(Time.zone.now)
+ end
+ end
+ end
+
+ describe '#reset_expiration_policy_started_at!' do
+ subject { repository.reset_expiration_policy_started_at! }
+
+ before do
+ repository.start_expiration_policy!
+ end
+
+ it 'resets the expiration policy started at' do
+ started_at = repository.expiration_policy_started_at
+
+ expect(started_at).not_to be_nil
+ expect { subject }
+ .to change { repository.expiration_policy_started_at }.from(started_at).to(nil)
+ end
+ end
+
describe '.build_from_path' do
let(:registry_path) do
ContainerRegistry::Path.new(project.full_path + '/some/image')
diff --git a/spec/models/deploy_token_spec.rb b/spec/models/deploy_token_spec.rb
index 9fd3751be13..60a3e3fc0e2 100644
--- a/spec/models/deploy_token_spec.rb
+++ b/spec/models/deploy_token_spec.rb
@@ -353,4 +353,29 @@ RSpec.describe DeployToken do
end
end
end
+
+ describe '#accessible_projects' do
+ subject { deploy_token.accessible_projects }
+
+ context 'when a deploy token is associated to a project' do
+ let_it_be(:deploy_token) { create(:deploy_token, :project) }
+
+ it 'returns only projects directly associated with the token' do
+ expect(deploy_token).to receive(:projects)
+
+ subject
+ end
+ end
+
+ context 'when a deploy token is associated to a group' do
+ let_it_be(:group) { create(:group) }
+ let_it_be(:deploy_token) { create(:deploy_token, :group, groups: [group]) }
+
+ it 'returns all projects from the group' do
+ expect(group).to receive(:all_projects)
+
+ subject
+ end
+ end
+ end
end
diff --git a/spec/models/deployment_spec.rb b/spec/models/deployment_spec.rb
index 1c7b11257ce..3e855584c38 100644
--- a/spec/models/deployment_spec.rb
+++ b/spec/models/deployment_spec.rb
@@ -98,16 +98,36 @@ RSpec.describe Deployment do
context 'when deployment runs' do
let(:deployment) { create(:deployment) }
- before do
- deployment.run!
- end
-
it 'starts running' do
freeze_time do
+ deployment.run!
+
expect(deployment).to be_running
expect(deployment.finished_at).to be_nil
end
end
+
+ it 'executes Deployments::ExecuteHooksWorker asynchronously' do
+ expect(Deployments::ExecuteHooksWorker)
+ .to receive(:perform_async).with(deployment.id)
+
+ deployment.run!
+ end
+
+ it 'does not execute Deployments::ExecuteHooksWorker when feature is disabled' do
+ stub_feature_flags(ci_send_deployment_hook_when_start: false)
+ expect(Deployments::ExecuteHooksWorker)
+ .not_to receive(:perform_async).with(deployment.id)
+
+ deployment.run!
+ end
+
+ it 'executes Deployments::DropOlderDeploymentsWorker asynchronously' do
+ expect(Deployments::DropOlderDeploymentsWorker)
+ .to receive(:perform_async).once.with(deployment.id)
+
+ deployment.run!
+ end
end
context 'when deployment succeeded' do
@@ -122,15 +142,15 @@ RSpec.describe Deployment do
end
end
- it 'executes Deployments::SuccessWorker asynchronously' do
- expect(Deployments::SuccessWorker)
+ it 'executes Deployments::UpdateEnvironmentWorker asynchronously' do
+ expect(Deployments::UpdateEnvironmentWorker)
.to receive(:perform_async).with(deployment.id)
deployment.succeed!
end
- it 'executes Deployments::FinishedWorker asynchronously' do
- expect(Deployments::FinishedWorker)
+ it 'executes Deployments::ExecuteHooksWorker asynchronously' do
+ expect(Deployments::ExecuteHooksWorker)
.to receive(:perform_async).with(deployment.id)
deployment.succeed!
@@ -149,12 +169,19 @@ RSpec.describe Deployment do
end
end
- it 'executes Deployments::FinishedWorker asynchronously' do
- expect(Deployments::FinishedWorker)
+ it 'executes Deployments::LinkMergeRequestWorker asynchronously' do
+ expect(Deployments::LinkMergeRequestWorker)
.to receive(:perform_async).with(deployment.id)
deployment.drop!
end
+
+ it 'executes Deployments::ExecuteHooksWorker asynchronously' do
+ expect(Deployments::ExecuteHooksWorker)
+ .to receive(:perform_async).with(deployment.id)
+
+ deployment.drop!
+ end
end
context 'when deployment was canceled' do
@@ -169,12 +196,19 @@ RSpec.describe Deployment do
end
end
- it 'executes Deployments::FinishedWorker asynchronously' do
- expect(Deployments::FinishedWorker)
+ it 'executes Deployments::LinkMergeRequestWorker asynchronously' do
+ expect(Deployments::LinkMergeRequestWorker)
.to receive(:perform_async).with(deployment.id)
deployment.cancel!
end
+
+ it 'executes Deployments::ExecuteHooksWorker asynchronously' do
+ expect(Deployments::ExecuteHooksWorker)
+ .to receive(:perform_async).with(deployment.id)
+
+ deployment.cancel!
+ end
end
end
@@ -580,9 +614,10 @@ RSpec.describe Deployment do
expect(deploy).to be_success
end
- it 'schedules SuccessWorker and FinishedWorker when finishing a deploy' do
- expect(Deployments::SuccessWorker).to receive(:perform_async)
- expect(Deployments::FinishedWorker).to receive(:perform_async)
+ it 'schedules workers when finishing a deploy' do
+ expect(Deployments::UpdateEnvironmentWorker).to receive(:perform_async)
+ expect(Deployments::LinkMergeRequestWorker).to receive(:perform_async)
+ expect(Deployments::ExecuteHooksWorker).to receive(:perform_async)
deploy.update_status('success')
end
diff --git a/spec/models/design_management/design_at_version_spec.rb b/spec/models/design_management/design_at_version_spec.rb
index 3c1ff45c53f..220de80a52a 100644
--- a/spec/models/design_management/design_at_version_spec.rb
+++ b/spec/models/design_management/design_at_version_spec.rb
@@ -274,29 +274,6 @@ RSpec.describe DesignManagement::DesignAtVersion do
build(:design_at_version, design: design, version: version).id
end
- describe '.instantiate' do
- context 'when attrs are valid' do
- subject do
- described_class.instantiate(design: design, version: version)
- end
-
- it { is_expected.to be_a(described_class).and(be_valid) }
- end
-
- context 'when attrs are invalid' do
- subject do
- described_class.instantiate(
- design: create(:design),
- version: create(:design_version)
- )
- end
-
- it 'raises a validation error' do
- expect { subject }.to raise_error(ActiveModel::ValidationError)
- end
- end
- end
-
describe '.lazy_find' do
let!(:version_a) do
create(:design_version, designs: create_list(:design, 3, issue: issue))
diff --git a/spec/models/design_management/design_collection_spec.rb b/spec/models/design_management/design_collection_spec.rb
index 8575cc80b5b..bc8330c7dd3 100644
--- a/spec/models/design_management/design_collection_spec.rb
+++ b/spec/models/design_management/design_collection_spec.rb
@@ -101,6 +101,18 @@ RSpec.describe DesignManagement::DesignCollection do
end
end
+ describe "#empty?" do
+ it "is true when the design collection has no designs" do
+ expect(collection).to be_empty
+ end
+
+ it "is false when the design collection has designs" do
+ create(:design, issue: issue)
+
+ expect(collection).not_to be_empty
+ end
+ end
+
describe "#versions" do
it "includes versions for all designs" do
version_1 = create(:design_version)
diff --git a/spec/models/design_management/design_spec.rb b/spec/models/design_management/design_spec.rb
index d4adc0d42d0..2ce9f00a056 100644
--- a/spec/models/design_management/design_spec.rb
+++ b/spec/models/design_management/design_spec.rb
@@ -206,6 +206,15 @@ RSpec.describe DesignManagement::Design do
end
end
+ describe ".build_full_path" do
+ it "builds the full path for a design" do
+ design = build(:design, issue: issue, filename: "hello.jpg")
+ expected_path = "#{DesignManagement.designs_directory}/issue-#{design.issue.iid}/hello.jpg"
+
+ expect(described_class.build_full_path(issue, design)).to eq(expected_path)
+ end
+ end
+
describe '#visible_in?' do
let_it_be(:issue) { create(:issue, project: issue.project) }
diff --git a/spec/models/environment_spec.rb b/spec/models/environment_spec.rb
index 433ede97b82..06d3e9da286 100644
--- a/spec/models/environment_spec.rb
+++ b/spec/models/environment_spec.rb
@@ -312,18 +312,25 @@ RSpec.describe Environment, :use_clean_rails_memory_store_caching do
describe '#update_merge_request_metrics?' do
{
+ 'gprd' => false,
+ 'prod' => true,
+ 'prod-test' => false,
+ 'PROD' => true,
'production' => true,
+ 'production-test' => false,
+ 'PRODUCTION' => true,
'production/eu' => true,
+ 'PRODUCTION/EU' => true,
'production/www.gitlab.com' => true,
'productioneu' => false,
- 'Production' => false,
- 'Production/eu' => false,
+ 'Production' => true,
+ 'Production/eu' => true,
'test-production' => false
}.each do |name, expected_value|
it "returns #{expected_value} for #{name}" do
env = create(:environment, name: name)
- expect(env.update_merge_request_metrics?).to eq(expected_value)
+ expect(env.update_merge_request_metrics?).to eq(expected_value), "Expected the name '#{name}' to result in #{expected_value}, but it didn't."
end
end
end
diff --git a/spec/models/environment_status_spec.rb b/spec/models/environment_status_spec.rb
index a6954fb5d56..09a73a4cdcb 100644
--- a/spec/models/environment_status_spec.rb
+++ b/spec/models/environment_status_spec.rb
@@ -66,18 +66,6 @@ RSpec.describe EnvironmentStatus do
end
end
- describe '#changed_paths' do
- subject { environment_status.changed_urls }
-
- it { is_expected.to contain_exactly("#{environment.external_url}/ruby-style-guide.html", "#{environment.external_url}/html/page.html") }
- end
-
- describe '#changed_urls' do
- subject { environment_status.changed_paths }
-
- it { is_expected.to contain_exactly('ruby-style-guide.html', 'html/page.html') }
- end
-
describe '.for_merge_request' do
let(:admin) { create(:admin) }
let!(:pipeline) { create(:ci_pipeline, sha: sha, merge_requests_as_head_pipeline: [merge_request]) }
diff --git a/spec/models/event_spec.rb b/spec/models/event_spec.rb
index bafcb7a3741..47492715c11 100644
--- a/spec/models/event_spec.rb
+++ b/spec/models/event_spec.rb
@@ -918,6 +918,56 @@ RSpec.describe Event do
expect(destroyed).to eq('deleted')
expect(archived).to eq('archived')
end
+
+ it 'handles correct push_action' do
+ project = create(:project)
+ user = create(:user)
+ project.add_developer(user)
+ push_event = create_push_event(project, user)
+
+ expect(push_event.push_action?).to be true
+ expect(push_event.action_name).to eq('pushed to')
+ end
+
+ context 'handles correct base actions' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:trait, :action_name) do
+ :created | 'created'
+ :updated | 'opened'
+ :closed | 'closed'
+ :reopened | 'opened'
+ :commented | 'commented on'
+ :merged | 'accepted'
+ :joined | 'joined'
+ :left | 'left'
+ :destroyed | 'destroyed'
+ :expired | 'removed due to membership expiration from'
+ :approved | 'approved'
+ end
+
+ with_them do
+ it 'with correct name and method' do
+ event = build(:event, trait)
+
+ expect(event.action_name).to eq(action_name)
+ end
+ end
+ end
+
+ context 'for created_project_action?' do
+ it 'returns created for created event' do
+ action = build(:project_created_event)
+
+ expect(action.action_name).to eq('created')
+ end
+
+ it 'returns imported for imported event' do
+ action = build(:project_imported_event)
+
+ expect(action.action_name).to eq('imported')
+ end
+ end
end
def create_push_event(project, user)
diff --git a/spec/models/group_import_state_spec.rb b/spec/models/group_import_state_spec.rb
index 4404ef64966..469b5c96ac9 100644
--- a/spec/models/group_import_state_spec.rb
+++ b/spec/models/group_import_state_spec.rb
@@ -6,6 +6,7 @@ RSpec.describe GroupImportState do
describe 'validations' do
let_it_be(:group) { create(:group) }
+ it { is_expected.to belong_to(:user).required }
it { is_expected.to validate_presence_of(:group) }
it { is_expected.to validate_presence_of(:status) }
diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb
index 15972f66fd6..cc29e20710a 100644
--- a/spec/models/group_spec.rb
+++ b/spec/models/group_spec.rb
@@ -222,6 +222,50 @@ RSpec.describe Group do
end
end
end
+
+ describe '#two_factor_authentication_allowed' do
+ let_it_be(:group) { create(:group) }
+
+ context 'for a parent group' do
+ it 'is valid' do
+ group.require_two_factor_authentication = true
+
+ expect(group).to be_valid
+ end
+ end
+
+ context 'for a child group' do
+ let(:sub_group) { create(:group, parent: group) }
+
+ it 'is valid when parent group allows' do
+ sub_group.require_two_factor_authentication = true
+
+ expect(sub_group).to be_valid
+ end
+
+ it 'is invalid when parent group blocks' do
+ group.namespace_settings.update!(allow_mfa_for_subgroups: false)
+ sub_group.require_two_factor_authentication = true
+
+ expect(sub_group).to be_invalid
+ expect(sub_group.errors[:require_two_factor_authentication]).to include('is forbidden by a top-level group')
+ end
+ end
+ end
+ end
+
+ describe '.without_integration' do
+ let(:another_group) { create(:group) }
+ let(:instance_integration) { build(:jira_service, :instance) }
+
+ before do
+ create(:jira_service, group: group, project: nil)
+ create(:slack_service, group: another_group, project: nil)
+ end
+
+ it 'returns groups without integration' do
+ expect(Group.without_integration(instance_integration)).to contain_exactly(another_group)
+ end
end
describe '.public_or_visible_to_user' do
@@ -1330,229 +1374,156 @@ RSpec.describe Group do
end
end
- describe '#shared_runners_allowed?' do
- using RSpec::Parameterized::TableSyntax
-
- where(:shared_runners_enabled, :allow_descendants_override, :expected_shared_runners_allowed) do
- true | false | true
- true | true | true
- false | false | false
- false | true | true
- end
-
- with_them do
- let!(:group) { create(:group, shared_runners_enabled: shared_runners_enabled, allow_descendants_override_disabled_shared_runners: allow_descendants_override) }
-
- it 'returns the expected result' do
- expect(group.shared_runners_allowed?).to eq(expected_shared_runners_allowed)
- end
- end
+ def subject_and_reload(*models)
+ subject
+ models.map(&:reload)
end
- describe '#parent_allows_shared_runners?' do
- context 'when parent group is present' do
- using RSpec::Parameterized::TableSyntax
-
- where(:shared_runners_enabled, :allow_descendants_override, :expected_shared_runners_allowed) do
- true | false | true
- true | true | true
- false | false | false
- false | true | true
+ describe '#update_shared_runners_setting!' do
+ context 'enabled' do
+ subject { group.update_shared_runners_setting!('enabled') }
+
+ context 'group that its ancestors have shared runners disabled' do
+ let_it_be(:parent) { create(:group, :shared_runners_disabled) }
+ let_it_be(:group) { create(:group, :shared_runners_disabled, parent: parent) }
+ let_it_be(:project) { create(:project, shared_runners_enabled: false, group: group) }
+
+ it 'raises error and does not enable shared Runners' do
+ expect { subject_and_reload(parent, group, project) }
+ .to raise_error(ActiveRecord::RecordInvalid, 'Validation failed: Shared runners enabled cannot be enabled because parent group has shared Runners disabled')
+ .and not_change { parent.shared_runners_enabled }
+ .and not_change { group.shared_runners_enabled }
+ .and not_change { project.shared_runners_enabled }
+ end
end
- with_them do
- let!(:parent_group) { create(:group, shared_runners_enabled: shared_runners_enabled, allow_descendants_override_disabled_shared_runners: allow_descendants_override) }
- let!(:group) { create(:group, parent: parent_group) }
+ context 'root group with shared runners disabled' do
+ let_it_be(:group) { create(:group, :shared_runners_disabled) }
+ let_it_be(:sub_group) { create(:group, :shared_runners_disabled, parent: group) }
+ let_it_be(:project) { create(:project, shared_runners_enabled: false, group: sub_group) }
- it 'returns the expected result' do
- expect(group.parent_allows_shared_runners?).to eq(expected_shared_runners_allowed)
+ it 'enables shared Runners only for itself' do
+ expect { subject_and_reload(group, sub_group, project) }
+ .to change { group.shared_runners_enabled }.from(false).to(true)
+ .and not_change { sub_group.shared_runners_enabled }
+ .and not_change { project.shared_runners_enabled }
end
end
end
- context 'when parent group is missing' do
- let!(:group) { create(:group) }
-
- it 'returns true' do
- expect(group.parent_allows_shared_runners?).to be_truthy
+ context 'disabled_and_unoverridable' do
+ let_it_be(:group) { create(:group) }
+ let_it_be(:sub_group) { create(:group, :shared_runners_disabled, :allow_descendants_override_disabled_shared_runners, parent: group) }
+ let_it_be(:sub_group_2) { create(:group, parent: group) }
+ let_it_be(:project) { create(:project, group: group, shared_runners_enabled: true) }
+ let_it_be(:project_2) { create(:project, group: sub_group_2, shared_runners_enabled: true) }
+
+ subject { group.update_shared_runners_setting!('disabled_and_unoverridable') }
+
+ it 'disables shared Runners for all descendant groups and projects' do
+ expect { subject_and_reload(group, sub_group, sub_group_2, project, project_2) }
+ .to change { group.shared_runners_enabled }.from(true).to(false)
+ .and not_change { group.allow_descendants_override_disabled_shared_runners }
+ .and not_change { sub_group.shared_runners_enabled }
+ .and change { sub_group.allow_descendants_override_disabled_shared_runners }.from(true).to(false)
+ .and change { sub_group_2.shared_runners_enabled }.from(true).to(false)
+ .and not_change { sub_group_2.allow_descendants_override_disabled_shared_runners }
+ .and change { project.shared_runners_enabled }.from(true).to(false)
+ .and change { project_2.shared_runners_enabled }.from(true).to(false)
+ end
+
+ context 'with override on self' do
+ let_it_be(:group) { create(:group, :shared_runners_disabled, :allow_descendants_override_disabled_shared_runners) }
+
+ it 'disables it' do
+ expect { subject_and_reload(group) }
+ .to not_change { group.shared_runners_enabled }
+ .and change { group.allow_descendants_override_disabled_shared_runners }.from(true).to(false)
+ end
end
end
- end
- describe '#parent_enabled_shared_runners?' do
- subject { group.parent_enabled_shared_runners? }
+ context 'disabled_with_override' do
+ subject { group.update_shared_runners_setting!('disabled_with_override') }
- context 'when parent group is present' do
- context 'When shared Runners are disabled' do
- let!(:parent_group) { create(:group, :shared_runners_disabled) }
- let!(:group) { create(:group, parent: parent_group) }
+ context 'top level group' do
+ let_it_be(:group) { create(:group, :shared_runners_disabled) }
+ let_it_be(:sub_group) { create(:group, :shared_runners_disabled, parent: group) }
+ let_it_be(:project) { create(:project, shared_runners_enabled: false, group: sub_group) }
- it { is_expected.to be_falsy }
+ it 'enables allow descendants to override only for itself' do
+ expect { subject_and_reload(group, sub_group, project) }
+ .to change { group.allow_descendants_override_disabled_shared_runners }.from(false).to(true)
+ .and not_change { group.shared_runners_enabled }
+ .and not_change { sub_group.allow_descendants_override_disabled_shared_runners }
+ .and not_change { sub_group.shared_runners_enabled }
+ .and not_change { project.shared_runners_enabled }
+ end
end
- context 'When shared Runners are enabled' do
- let!(:parent_group) { create(:group) }
- let!(:group) { create(:group, parent: parent_group) }
+ context 'group that its ancestors have shared Runners disabled but allows to override' do
+ let_it_be(:parent) { create(:group, :shared_runners_disabled, :allow_descendants_override_disabled_shared_runners) }
+ let_it_be(:group) { create(:group, :shared_runners_disabled, parent: parent) }
+ let_it_be(:project) { create(:project, shared_runners_enabled: false, group: group) }
- it { is_expected.to be_truthy }
+ it 'enables allow descendants to override' do
+ expect { subject_and_reload(parent, group, project) }
+ .to not_change { parent.allow_descendants_override_disabled_shared_runners }
+ .and not_change { parent.shared_runners_enabled }
+ .and change { group.allow_descendants_override_disabled_shared_runners }.from(false).to(true)
+ .and not_change { group.shared_runners_enabled }
+ .and not_change { project.shared_runners_enabled }
+ end
end
- end
-
- context 'when parent group is missing' do
- let!(:group) { create(:group) }
-
- it { is_expected.to be_truthy }
- end
- end
- describe '#enable_shared_runners!' do
- subject { group.enable_shared_runners! }
+ 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(:group) { create(:group, :shared_runners_disabled, allow_descendants_override_disabled_shared_runners: false, parent: parent) }
- context 'group that its ancestors have shared runners disabled' do
- let_it_be(:parent) { create(:group, :shared_runners_disabled) }
- let_it_be(:group) { create(:group, :shared_runners_disabled, parent: parent) }
- let_it_be(:project) { create(:project, shared_runners_enabled: false, group: group) }
-
- it 'raises error and does not enable shared Runners' do
- expect { subject }
- .to raise_error(described_class::UpdateSharedRunnersError, 'Shared Runners disabled for the parent group')
- .and not_change { parent.reload.shared_runners_enabled }
- .and not_change { group.reload.shared_runners_enabled }
- .and not_change { project.reload.shared_runners_enabled }
+ it 'raises error and does not allow descendants to override' do
+ expect { subject_and_reload(parent, group) }
+ .to raise_error(ActiveRecord::RecordInvalid, 'Validation failed: Allow descendants override disabled shared runners cannot be enabled because parent group does not allow it')
+ .and not_change { parent.allow_descendants_override_disabled_shared_runners }
+ .and not_change { parent.shared_runners_enabled }
+ .and not_change { group.allow_descendants_override_disabled_shared_runners }
+ .and not_change { group.shared_runners_enabled }
+ end
end
- end
- context 'root group with shared runners disabled' do
- let_it_be(:group) { create(:group, :shared_runners_disabled) }
- let_it_be(:sub_group) { create(:group, :shared_runners_disabled, parent: group) }
- let_it_be(:project) { create(:project, shared_runners_enabled: false, group: sub_group) }
+ context 'top level group that has shared Runners enabled' do
+ let_it_be(:group) { create(:group, shared_runners_enabled: true) }
+ let_it_be(:sub_group) { create(:group, shared_runners_enabled: true, parent: group) }
+ let_it_be(:project) { create(:project, shared_runners_enabled: true, group: sub_group) }
- it 'enables shared Runners only for itself' do
- expect { subject }
- .to change { group.reload.shared_runners_enabled }.from(false).to(true)
- .and not_change { sub_group.reload.shared_runners_enabled }
- .and not_change { project.reload.shared_runners_enabled }
+ it 'enables allow descendants to override & disables shared runners everywhere' do
+ expect { subject_and_reload(group, sub_group, project) }
+ .to change { group.shared_runners_enabled }.from(true).to(false)
+ .and change { group.allow_descendants_override_disabled_shared_runners }.from(false).to(true)
+ .and change { sub_group.shared_runners_enabled }.from(true).to(false)
+ .and change { project.shared_runners_enabled }.from(true).to(false)
+ end
end
end
end
- describe '#disable_shared_runners!' do
- let_it_be(:group) { create(:group) }
- let_it_be(:sub_group) { create(:group, :shared_runners_disabled, :allow_descendants_override_disabled_shared_runners, parent: group) }
- let_it_be(:sub_group_2) { create(:group, parent: group) }
- let_it_be(:project) { create(:project, group: group, shared_runners_enabled: true) }
- let_it_be(:project_2) { create(:project, group: sub_group_2, shared_runners_enabled: true) }
-
- subject { group.disable_shared_runners! }
-
- it 'disables shared Runners for all descendant groups and projects' do
- expect { subject }
- .to change { group.reload.shared_runners_enabled }.from(true).to(false)
- .and not_change { group.reload.allow_descendants_override_disabled_shared_runners }
- .and not_change { sub_group.reload.shared_runners_enabled }
- .and not_change { sub_group.reload.allow_descendants_override_disabled_shared_runners }
- .and change { sub_group_2.reload.shared_runners_enabled }.from(true).to(false)
- .and not_change { sub_group_2.reload.allow_descendants_override_disabled_shared_runners }
- .and change { project.reload.shared_runners_enabled }.from(true).to(false)
- .and change { project_2.reload.shared_runners_enabled }.from(true).to(false)
- end
- end
-
- describe '#allow_descendants_override_disabled_shared_runners!' do
- subject { group.allow_descendants_override_disabled_shared_runners! }
-
- context 'top level group' do
- let_it_be(:group) { create(:group, :shared_runners_disabled) }
- let_it_be(:sub_group) { create(:group, :shared_runners_disabled, parent: group) }
- let_it_be(:project) { create(:project, shared_runners_enabled: false, group: sub_group) }
-
- it 'enables allow descendants to override only for itself' do
- expect { subject }
- .to change { group.reload.allow_descendants_override_disabled_shared_runners }.from(false).to(true)
- .and not_change { group.reload.shared_runners_enabled }
- .and not_change { sub_group.reload.allow_descendants_override_disabled_shared_runners }
- .and not_change { sub_group.reload.shared_runners_enabled }
- .and not_change { project.reload.shared_runners_enabled }
- end
- end
-
- context 'group that its ancestors have shared Runners disabled but allows to override' do
- let_it_be(:parent) { create(:group, :shared_runners_disabled, :allow_descendants_override_disabled_shared_runners) }
- let_it_be(:group) { create(:group, :shared_runners_disabled, parent: parent) }
- let_it_be(:project) { create(:project, shared_runners_enabled: false, group: group) }
-
- it 'enables allow descendants to override' do
- expect { subject }
- .to not_change { parent.reload.allow_descendants_override_disabled_shared_runners }
- .and not_change { parent.reload.shared_runners_enabled }
- .and change { group.reload.allow_descendants_override_disabled_shared_runners }.from(false).to(true)
- .and not_change { group.reload.shared_runners_enabled }
- .and not_change { project.reload.shared_runners_enabled }
- end
- 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(:group) { create(:group, :shared_runners_disabled, allow_descendants_override_disabled_shared_runners: false, parent: parent) }
-
- it 'raises error and does not allow descendants to override' do
- expect { subject }
- .to raise_error(described_class::UpdateSharedRunnersError, 'Group level shared Runners not allowed')
- .and not_change { parent.reload.allow_descendants_override_disabled_shared_runners }
- .and not_change { parent.reload.shared_runners_enabled }
- .and not_change { group.reload.allow_descendants_override_disabled_shared_runners }
- .and not_change { group.reload.shared_runners_enabled }
- end
- end
-
- context 'top level group that has shared Runners enabled' do
- let_it_be(:group) { create(:group, shared_runners_enabled: true) }
- let_it_be(:sub_group) { create(:group, :shared_runners_disabled, parent: group) }
- let_it_be(:project) { create(:project, shared_runners_enabled: false, group: sub_group) }
-
- it 'raises error and does not change config' do
- expect { subject }
- .to raise_error(described_class::UpdateSharedRunnersError, 'Shared Runners enabled')
- .and not_change { group.reload.allow_descendants_override_disabled_shared_runners }
- .and not_change { group.reload.shared_runners_enabled }
- .and not_change { sub_group.reload.allow_descendants_override_disabled_shared_runners }
- .and not_change { sub_group.reload.shared_runners_enabled }
- .and not_change { project.reload.shared_runners_enabled }
+ describe "#default_branch_name" do
+ context "group.namespace_settings does not have a default branch name" do
+ it "returns nil" do
+ expect(group.default_branch_name).to be_nil
end
end
- end
- describe '#disallow_descendants_override_disabled_shared_runners!' do
- subject { group.disallow_descendants_override_disabled_shared_runners! }
+ context "group.namespace_settings has a default branch name" do
+ let(:example_branch_name) { "example_branch_name" }
- context 'top level group' do
- let_it_be(:group) { create(:group, :shared_runners_disabled, :allow_descendants_override_disabled_shared_runners ) }
- let_it_be(:sub_group) { create(:group, :shared_runners_disabled, :allow_descendants_override_disabled_shared_runners, parent: group) }
- let_it_be(:project) { create(:project, shared_runners_enabled: true, group: sub_group) }
-
- it 'disables allow project to override for descendants and disables project shared Runners' do
- expect { subject }
- .to not_change { group.reload.shared_runners_enabled }
- .and change { group.reload.allow_descendants_override_disabled_shared_runners }.from(true).to(false)
- .and not_change { sub_group.reload.shared_runners_enabled }
- .and change { sub_group.reload.allow_descendants_override_disabled_shared_runners }.from(true).to(false)
- .and change { project.reload.shared_runners_enabled }.from(true).to(false)
+ before do
+ expect(group.namespace_settings)
+ .to receive(:default_branch_name)
+ .and_return(example_branch_name)
end
- end
-
- context 'top level group that has shared Runners enabled' do
- let_it_be(:group) { create(:group, shared_runners_enabled: true) }
- let_it_be(:sub_group) { create(:group, :shared_runners_disabled, parent: group) }
- let_it_be(:project) { create(:project, shared_runners_enabled: false, group: sub_group) }
- it 'results error and does not change config' do
- expect { subject }
- .to raise_error(described_class::UpdateSharedRunnersError, 'Shared Runners enabled')
- .and not_change { group.reload.allow_descendants_override_disabled_shared_runners }
- .and not_change { group.reload.shared_runners_enabled }
- .and not_change { sub_group.reload.allow_descendants_override_disabled_shared_runners }
- .and not_change { sub_group.reload.shared_runners_enabled }
- .and not_change { project.reload.shared_runners_enabled }
+ it "returns the default branch name" do
+ expect(group.default_branch_name).to eq(example_branch_name)
end
end
end
@@ -1600,4 +1571,24 @@ RSpec.describe Group do
end
end
end
+
+ describe '#parent_allows_two_factor_authentication?' do
+ it 'returns true for top-level group' do
+ expect(group.parent_allows_two_factor_authentication?).to eq(true)
+ end
+
+ context 'for subgroup' do
+ let(:subgroup) { create(:group, parent: group) }
+
+ it 'returns true if parent group allows two factor authentication for its descendants' do
+ expect(subgroup.parent_allows_two_factor_authentication?).to eq(true)
+ end
+
+ it 'returns true if parent group allows two factor authentication for its descendants' do
+ group.namespace_settings.update!(allow_mfa_for_subgroups: false)
+
+ expect(subgroup.parent_allows_two_factor_authentication?).to eq(false)
+ end
+ end
+ end
end
diff --git a/spec/models/import_failure_spec.rb b/spec/models/import_failure_spec.rb
index cdef125e890..9fee1b0ae7b 100644
--- a/spec/models/import_failure_spec.rb
+++ b/spec/models/import_failure_spec.rb
@@ -16,7 +16,7 @@ RSpec.describe ImportFailure do
it 'orders hard failures by newest first' do
older_failure = hard_failure.dup
- Timecop.freeze(1.day.before(hard_failure.created_at)) do
+ travel_to(1.day.before(hard_failure.created_at)) do
older_failure.save!
expect(ImportFailure.hard_failures_by_correlation_id(correlation_id)).to eq([hard_failure, older_failure])
diff --git a/spec/models/integration_spec.rb b/spec/models/integration_spec.rb
index 87ba0f3f7e6..d89b323f525 100644
--- a/spec/models/integration_spec.rb
+++ b/spec/models/integration_spec.rb
@@ -3,26 +3,26 @@
require 'spec_helper'
RSpec.describe Integration do
- let!(:project_1) { create(:project) }
- let!(:project_2) { create(:project) }
- let!(:project_3) { create(:project) }
- let(:instance_integration) { create(:jira_service, :instance) }
+ let_it_be(:project_1) { create(:project) }
+ let_it_be(:project_2) { create(:project) }
+ let_it_be(:project_3) { create(:project) }
+ let_it_be(:instance_integration) { create(:jira_service, :instance) }
before do
create(:jira_service, project: project_1, inherit_from_id: instance_integration.id)
create(:jira_service, project: project_2, inherit_from_id: nil)
- create(:slack_service, project: project_1, inherit_from_id: nil)
+ create(:slack_service, project: project_3, inherit_from_id: nil)
end
- describe '#with_custom_integration_for' do
+ describe '.with_custom_integration_for' do
it 'returns projects with custom integrations' do
expect(Project.with_custom_integration_for(instance_integration)).to contain_exactly(project_2)
end
end
- describe '#ids_without_integration' do
- it 'returns projects ids without an integration' do
- expect(Project.ids_without_integration(instance_integration, 100)).to contain_exactly(project_3.id)
+ describe '.without_integration' do
+ it 'returns projects without integration' do
+ expect(Project.without_integration(instance_integration)).to contain_exactly(project_3)
end
end
end
diff --git a/spec/models/issue/metrics_spec.rb b/spec/models/issue/metrics_spec.rb
index 966e4321378..1d3c09a48b7 100644
--- a/spec/models/issue/metrics_spec.rb
+++ b/spec/models/issue/metrics_spec.rb
@@ -38,7 +38,7 @@ RSpec.describe Issue::Metrics do
context "milestones" do
it "records the first time an issue is associated with a milestone" do
time = Time.current
- Timecop.freeze(time) { subject.update(milestone: create(:milestone, project: project)) }
+ travel_to(time) { subject.update(milestone: create(:milestone, project: project)) }
metrics = subject.metrics
expect(metrics).to be_present
@@ -47,9 +47,9 @@ RSpec.describe Issue::Metrics do
it "does not record the second time an issue is associated with a milestone" do
time = Time.current
- Timecop.freeze(time) { subject.update(milestone: create(:milestone, project: project)) }
- Timecop.freeze(time + 2.hours) { subject.update(milestone: nil) }
- Timecop.freeze(time + 6.hours) { subject.update(milestone: create(:milestone, project: project)) }
+ travel_to(time) { subject.update(milestone: create(:milestone, project: project)) }
+ travel_to(time + 2.hours) { subject.update(milestone: nil) }
+ travel_to(time + 6.hours) { subject.update(milestone: create(:milestone, project: project)) }
metrics = subject.metrics
expect(metrics).to be_present
@@ -61,7 +61,7 @@ RSpec.describe Issue::Metrics do
it "records the first time an issue is associated with a list label" do
list_label = create(:list).label
time = Time.current
- Timecop.freeze(time) { subject.update(label_ids: [list_label.id]) }
+ travel_to(time) { subject.update(label_ids: [list_label.id]) }
metrics = subject.metrics
expect(metrics).to be_present
@@ -71,9 +71,9 @@ RSpec.describe Issue::Metrics do
it "does not record the second time an issue is associated with a list label" do
time = Time.current
first_list_label = create(:list).label
- Timecop.freeze(time) { subject.update(label_ids: [first_list_label.id]) }
+ travel_to(time) { subject.update(label_ids: [first_list_label.id]) }
second_list_label = create(:list).label
- Timecop.freeze(time + 5.hours) { subject.update(label_ids: [second_list_label.id]) }
+ travel_to(time + 5.hours) { subject.update(label_ids: [second_list_label.id]) }
metrics = subject.metrics
expect(metrics).to be_present
diff --git a/spec/models/issue_email_participant_spec.rb b/spec/models/issue_email_participant_spec.rb
new file mode 100644
index 00000000000..f19e65e31f3
--- /dev/null
+++ b/spec/models/issue_email_participant_spec.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe IssueEmailParticipant do
+ describe "Associations" do
+ it { is_expected.to belong_to(:issue) }
+ end
+
+ describe 'Validations' do
+ subject { build(:issue_email_participant) }
+
+ it { is_expected.to validate_presence_of(:issue) }
+ it { is_expected.to validate_presence_of(:email) }
+ it { is_expected.to validate_uniqueness_of(:email).scoped_to([:issue_id]) }
+
+ it_behaves_like 'an object with RFC3696 compliant email-formated attributes', :email
+ end
+end
diff --git a/spec/models/issue_spec.rb b/spec/models/issue_spec.rb
index 283d945157b..16ea2989eda 100644
--- a/spec/models/issue_spec.rb
+++ b/spec/models/issue_spec.rb
@@ -28,10 +28,11 @@ RSpec.describe Issue do
it { is_expected.to have_and_belong_to_many(:prometheus_alert_events) }
it { is_expected.to have_and_belong_to_many(:self_managed_prometheus_alert_events) }
it { is_expected.to have_many(:prometheus_alerts) }
+ it { is_expected.to have_many(:issue_email_participants) }
describe 'versions.most_recent' do
it 'returns the most recent version' do
- issue = create(:issue)
+ issue = create(:issue, project: reusable_project)
create_list(:design_version, 2, issue: issue)
last_version = create(:design_version, issue: issue)
@@ -79,19 +80,19 @@ RSpec.describe Issue do
end
end
- subject { create(:issue) }
+ subject { create(:issue, project: reusable_project) }
describe 'callbacks' do
describe '#ensure_metrics' do
it 'creates metrics after saving' do
- issue = create(:issue)
+ issue = create(:issue, project: reusable_project)
expect(issue.metrics).to be_persisted
expect(Issue::Metrics.count).to eq(1)
end
it 'does not create duplicate metrics for an issue' do
- issue = create(:issue)
+ issue = create(:issue, project: reusable_project)
issue.close!
@@ -102,6 +103,14 @@ RSpec.describe Issue do
it 'records current metrics' do
expect_any_instance_of(Issue::Metrics).to receive(:record!)
+ create(:issue, project: reusable_project)
+ end
+ end
+
+ describe '#record_create_action' do
+ it 'records the creation action after saving' do
+ expect(Gitlab::UsageDataCounters::IssueActivityUniqueCounter).to receive(:track_issue_created_action)
+
create(:issue)
end
end
@@ -111,8 +120,8 @@ RSpec.describe Issue do
subject { described_class.with_alert_management_alerts }
it 'gets only issues with alerts' do
- alert = create(:alert_management_alert, issue: create(:issue))
- issue = create(:issue)
+ alert = create(:alert_management_alert, project: reusable_project, issue: create(:issue, project: reusable_project))
+ issue = create(:issue, project: reusable_project)
expect(subject).to contain_exactly(alert.issue)
expect(subject).not_to include(issue)
@@ -130,10 +139,9 @@ RSpec.describe Issue do
end
describe '.with_issue_type' do
- let_it_be(:project) { create(:project) }
- let_it_be(:issue) { create(:issue, project: project) }
- let_it_be(:incident) { create(:incident, project: project) }
- let_it_be(:test_case) { create(:quality_test_case, project: project) }
+ let_it_be(:issue) { create(:issue, project: reusable_project) }
+ let_it_be(:incident) { create(:incident, project: reusable_project) }
+ let_it_be(:test_case) { create(:quality_test_case, project: reusable_project) }
it 'gives issues with the given issue type' do
expect(described_class.with_issue_type('issue'))
@@ -146,6 +154,24 @@ RSpec.describe Issue do
end
end
+ describe '.order_severity' do
+ let_it_be(:issue_high_severity) { create(:issuable_severity, severity: :high).issue }
+ let_it_be(:issue_low_severity) { create(:issuable_severity, severity: :low).issue }
+ let_it_be(:issue_no_severity) { create(:incident) }
+
+ context 'sorting ascending' do
+ subject { described_class.order_severity_asc }
+
+ it { is_expected.to eq([issue_no_severity, issue_low_severity, issue_high_severity]) }
+ end
+
+ context 'sorting descending' do
+ subject { described_class.order_severity_desc }
+
+ it { is_expected.to eq([issue_high_severity, issue_low_severity, issue_no_severity]) }
+ end
+ end
+
describe '#order_by_position_and_priority' do
let(:project) { reusable_project }
let(:p1) { create(:label, title: 'P1', project: project, priority: 1) }
@@ -195,7 +221,7 @@ RSpec.describe Issue do
end
describe '#close' do
- subject(:issue) { create(:issue, state: 'opened') }
+ subject(:issue) { create(:issue, project: reusable_project, state: 'opened') }
it 'sets closed_at to Time.current when an issue is closed' do
expect { issue.close }.to change { issue.closed_at }.from(nil)
@@ -210,7 +236,7 @@ RSpec.describe Issue do
end
describe '#reopen' do
- let(:issue) { create(:issue, state: 'closed', closed_at: Time.current, closed_by: user) }
+ let(:issue) { create(:issue, project: reusable_project, state: 'closed', closed_at: Time.current, closed_by: user) }
it 'sets closed_at to nil when an issue is reopend' do
expect { issue.reopen }.to change { issue.closed_at }.to(nil)
@@ -293,7 +319,7 @@ RSpec.describe Issue do
end
describe '#assignee_or_author?' do
- let(:issue) { create(:issue) }
+ let(:issue) { create(:issue, project: reusable_project) }
it 'returns true for a user that is assigned to an issue' do
issue.assignees << user
@@ -313,22 +339,21 @@ RSpec.describe Issue do
end
describe '#related_issues' do
- let(:user) { create(:user) }
- let(:authorized_project) { create(:project) }
- let(:authorized_project2) { create(:project) }
- let(:unauthorized_project) { create(:project) }
+ let_it_be(:authorized_project) { create(:project) }
+ let_it_be(:authorized_project2) { create(:project) }
+ let_it_be(:unauthorized_project) { create(:project) }
- let(:authorized_issue_a) { create(:issue, project: authorized_project) }
- let(:authorized_issue_b) { create(:issue, project: authorized_project) }
- let(:authorized_issue_c) { create(:issue, project: authorized_project2) }
+ 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(:unauthorized_issue) { create(:issue, project: unauthorized_project) }
+ let_it_be(:unauthorized_issue) { create(:issue, project: unauthorized_project) }
- let!(:issue_link_a) { create(:issue_link, source: authorized_issue_a, target: authorized_issue_b) }
- let!(:issue_link_b) { create(:issue_link, source: authorized_issue_a, target: unauthorized_issue) }
- let!(:issue_link_c) { create(:issue_link, source: authorized_issue_a, target: authorized_issue_c) }
+ let_it_be(:issue_link_a) { create(:issue_link, source: authorized_issue_a, target: authorized_issue_b) }
+ let_it_be(:issue_link_b) { create(:issue_link, source: authorized_issue_a, target: unauthorized_issue) }
+ let_it_be(:issue_link_c) { create(:issue_link, source: authorized_issue_a, target: authorized_issue_c) }
- before do
+ before_all do
authorized_project.add_developer(user)
authorized_project2.add_developer(user)
end
@@ -366,17 +391,16 @@ RSpec.describe Issue do
end
context 'user is reporter in project issue belongs to' do
- let(:project) { create(:project) }
- let(:issue) { create(:issue, project: project) }
+ let(:issue) { create(:issue, project: reusable_project) }
- before do
- project.add_reporter(user)
+ before_all do
+ reusable_project.add_reporter(user)
end
it { is_expected.to eq true }
context 'issue not persisted' do
- let(:issue) { build(:issue, project: project) }
+ let(:issue) { build(:issue, project: reusable_project) }
it { is_expected.to eq false }
end
@@ -384,7 +408,7 @@ RSpec.describe Issue do
context 'checking destination project also' do
subject { issue.can_move?(user, to_project) }
- let(:to_project) { create(:project) }
+ let_it_be(:to_project) { create(:project) }
context 'destination project allowed' do
before do
@@ -420,7 +444,7 @@ RSpec.describe Issue do
end
describe '#duplicated?' do
- let(:issue) { create(:issue) }
+ let(:issue) { create(:issue, project: reusable_project) }
subject { issue.duplicated? }
@@ -429,7 +453,7 @@ RSpec.describe Issue do
end
context 'issue already duplicated' do
- let(:duplicated_to_issue) { create(:issue) }
+ let(:duplicated_to_issue) { create(:issue, project: reusable_project) }
let(:issue) { create(:issue, duplicated_to: duplicated_to_issue) }
it { is_expected.to eq true }
@@ -440,13 +464,13 @@ RSpec.describe Issue do
subject { issue.from_service_desk? }
context 'when issue author is support bot' do
- let(:issue) { create(:issue, author: ::User.support_bot) }
+ let(:issue) { create(:issue, project: reusable_project, author: ::User.support_bot) }
it { is_expected.to be_truthy }
end
context 'when issue author is not support bot' do
- let(:issue) { create(:issue) }
+ let(:issue) { create(:issue, project: reusable_project) }
it { is_expected.to be_falsey }
end
@@ -495,7 +519,7 @@ RSpec.describe Issue do
end
describe '#has_related_branch?' do
- let(:issue) { create(:issue, title: "Blue Bell Knoll") }
+ let(:issue) { create(:issue, project: reusable_project, title: "Blue Bell Knoll") }
subject { issue.has_related_branch? }
@@ -528,7 +552,7 @@ RSpec.describe Issue do
end
describe "#to_branch_name" do
- let(:issue) { create(:issue, title: 'testing-issue') }
+ let_it_be(:issue) { create(:issue, project: reusable_project, title: 'testing-issue') }
it 'starts with the issue iid' do
expect(issue.to_branch_name).to match(/\A#{issue.iid}-[A-Za-z\-]+\z/)
@@ -539,12 +563,12 @@ RSpec.describe Issue do
end
it "does not contain the issue title if confidential" do
- issue = create(:issue, title: 'testing-issue', confidential: true)
+ issue = create(:issue, project: reusable_project, title: 'testing-issue', confidential: true)
expect(issue.to_branch_name).to match(/confidential-issue\z/)
end
context 'issue title longer than 100 characters' do
- let(:issue) { create(:issue, iid: 999, title: 'Lorem ipsum dolor sit amet consectetur adipiscing elit Mauris sit amet ipsum id lacus custom fringilla convallis') }
+ let_it_be(:issue) { create(:issue, project: reusable_project, iid: 999, title: 'Lorem ipsum dolor sit amet consectetur adipiscing elit Mauris sit amet ipsum id lacus custom fringilla convallis') }
it "truncates branch name to at most 100 characters" do
expect(issue.to_branch_name.length).to be <= 100
@@ -581,15 +605,14 @@ RSpec.describe Issue do
describe '#participants' do
context 'using a public project' do
- let(:project) { create(:project, :public) }
- let(:issue) { create(:issue, project: project) }
+ let_it_be(:issue) { create(:issue, project: reusable_project) }
let!(:note1) do
- create(:note_on_issue, noteable: issue, project: project, note: 'a')
+ create(:note_on_issue, noteable: issue, project: reusable_project, note: 'a')
end
let!(:note2) do
- create(:note_on_issue, noteable: issue, project: project, note: 'b')
+ create(:note_on_issue, noteable: issue, project: reusable_project, note: 'b')
end
it 'includes the issue author' do
@@ -604,8 +627,8 @@ RSpec.describe Issue do
context 'using a private project' do
it 'does not include mentioned users that do not have access to the project' do
project = create(:project)
- user = create(:user)
issue = create(:issue, project: project)
+ user = create(:user)
create(:note_on_issue,
noteable: issue,
@@ -621,10 +644,9 @@ RSpec.describe Issue do
it 'updates when assignees change' do
user1 = create(:user)
user2 = create(:user)
- project = create(:project)
- issue = create(:issue, assignees: [user1], project: project)
- project.add_developer(user1)
- project.add_developer(user2)
+ issue = create(:issue, assignees: [user1], project: reusable_project)
+ reusable_project.add_developer(user1)
+ reusable_project.add_developer(user2)
expect(user1.assigned_open_issues_count).to eq(1)
expect(user2.assigned_open_issues_count).to eq(0)
@@ -638,9 +660,8 @@ RSpec.describe Issue do
end
describe '#visible_to_user?' do
- let(:project) { build(:project) }
+ let(:project) { reusable_project }
let(:issue) { build(:issue, project: project) }
- let(:user) { create(:user) }
subject { issue.visible_to_user?(user) }
@@ -661,6 +682,10 @@ RSpec.describe Issue do
context 'without a user' do
let(:user) { nil }
+ before do
+ project.project_feature.update_attribute(:issues_access_level, ProjectFeature::PUBLIC)
+ end
+
it 'returns true when the issue is publicly visible' do
expect(issue).to receive(:publicly_visible?).and_return(true)
@@ -995,7 +1020,8 @@ RSpec.describe Issue do
with_them do
it 'checks for spam on issues that can be seen anonymously' do
- project = create(:project, visibility_level: visibility_level)
+ project = reusable_project
+ project.update(visibility_level: visibility_level)
issue = create(:issue, project: project, confidential: confidential, description: 'original description')
issue.assign_attributes(new_attributes)
@@ -1016,8 +1042,8 @@ RSpec.describe Issue do
describe '.public_only' do
it 'only returns public issues' do
- public_issue = create(:issue)
- create(:issue, confidential: true)
+ public_issue = create(:issue, project: reusable_project)
+ create(:issue, project: reusable_project, confidential: true)
expect(described_class.public_only).to eq([public_issue])
end
@@ -1025,15 +1051,15 @@ RSpec.describe Issue do
describe '.confidential_only' do
it 'only returns confidential_only issues' do
- create(:issue)
- confidential_issue = create(:issue, confidential: true)
+ create(:issue, project: reusable_project)
+ confidential_issue = create(:issue, project: reusable_project, confidential: true)
expect(described_class.confidential_only).to eq([confidential_issue])
end
end
describe '.by_project_id_and_iid' do
- let_it_be(:issue_a) { create(:issue) }
+ let_it_be(:issue_a) { create(:issue, project: reusable_project) }
let_it_be(:issue_b) { create(:issue, iid: issue_a.iid) }
let_it_be(:issue_c) { create(:issue, project: issue_a.project) }
let_it_be(:issue_d) { create(:issue, project: issue_a.project) }
@@ -1050,8 +1076,8 @@ RSpec.describe Issue do
describe '.service_desk' do
it 'returns the service desk issue' do
- service_desk_issue = create(:issue, author: ::User.support_bot)
- regular_issue = create(:issue)
+ service_desk_issue = create(:issue, project: reusable_project, author: ::User.support_bot)
+ regular_issue = create(:issue, project: reusable_project)
expect(described_class.service_desk).to include(service_desk_issue)
expect(described_class.service_desk).not_to include(regular_issue)
@@ -1064,7 +1090,7 @@ RSpec.describe Issue do
describe "#labels_hook_attrs" do
let(:label) { create(:label) }
- let(:issue) { create(:labeled_issue, labels: [label]) }
+ let(:issue) { create(:labeled_issue, project: reusable_project, labels: [label]) }
it "returns a list of label hook attributes" do
expect(issue.labels_hook_attrs).to eq([label.hook_attrs])
@@ -1073,7 +1099,7 @@ RSpec.describe Issue do
context "relative positioning" do
it_behaves_like "a class that supports relative positioning" do
- let_it_be(:project) { create(:project) }
+ let_it_be(:project) { reusable_project }
let(:factory) { :issue }
let(:default_params) { { project: project } }
end
@@ -1083,7 +1109,7 @@ RSpec.describe Issue do
describe "#previous_updated_at" do
let_it_be(:updated_at) { Time.zone.local(2012, 01, 06) }
- let_it_be(:issue) { create(:issue, updated_at: updated_at) }
+ let_it_be(:issue) { create(:issue, project: reusable_project, updated_at: updated_at) }
it 'returns updated_at value if updated_at did not change at all' do
allow(issue).to receive(:previous_changes).and_return({})
@@ -1121,7 +1147,7 @@ RSpec.describe Issue do
end
describe 'current designs' do
- let(:issue) { create(:issue) }
+ let(:issue) { create(:issue, project: reusable_project) }
subject { issue.designs.current }
@@ -1213,4 +1239,12 @@ RSpec.describe Issue do
expect(issue.allows_reviewers?).to be(false)
end
end
+
+ describe '#issue_type_supports?' do
+ let_it_be(:issue) { create(:issue) }
+
+ it 'raises error when feature is invalid' do
+ expect { issue.issue_type_supports?(:unkown_feature) }.to raise_error(ArgumentError)
+ end
+ end
end
diff --git a/spec/models/iteration_spec.rb b/spec/models/iteration_spec.rb
index 19a1625aad3..e7ec5de0ef1 100644
--- a/spec/models/iteration_spec.rb
+++ b/spec/models/iteration_spec.rb
@@ -119,7 +119,7 @@ RSpec.describe Iteration do
let(:start_date) { 5.days.from_now }
let(:due_date) { 6.days.from_now }
- shared_examples_for 'overlapping dates' do
+ shared_examples_for 'overlapping dates' do |skip_constraint_test: false|
context 'when start_date is in range' do
let(:start_date) { 5.days.from_now }
let(:due_date) { 3.weeks.from_now }
@@ -129,9 +129,11 @@ RSpec.describe Iteration do
expect(subject.errors[:base]).to include('Dates cannot overlap with other existing Iterations')
end
- it 'is not valid even if forced' do
- subject.validate # to generate iid/etc
- expect { subject.save!(validate: false) }.to raise_exception(ActiveRecord::StatementInvalid, /#{constraint_name}/)
+ unless skip_constraint_test
+ it 'is not valid even if forced' do
+ subject.validate # to generate iid/etc
+ expect { subject.save!(validate: false) }.to raise_exception(ActiveRecord::StatementInvalid, /#{constraint_name}/)
+ end
end
end
@@ -144,9 +146,11 @@ RSpec.describe Iteration do
expect(subject.errors[:base]).to include('Dates cannot overlap with other existing Iterations')
end
- it 'is not valid even if forced' do
- subject.validate # to generate iid/etc
- expect { subject.save!(validate: false) }.to raise_exception(ActiveRecord::StatementInvalid, /#{constraint_name}/)
+ unless skip_constraint_test
+ it 'is not valid even if forced' do
+ subject.validate # to generate iid/etc
+ expect { subject.save!(validate: false) }.to raise_exception(ActiveRecord::StatementInvalid, /#{constraint_name}/)
+ end
end
end
@@ -156,9 +160,11 @@ RSpec.describe Iteration do
expect(subject.errors[:base]).to include('Dates cannot overlap with other existing Iterations')
end
- it 'is not valid even if forced' do
- subject.validate # to generate iid/etc
- expect { subject.save!(validate: false) }.to raise_exception(ActiveRecord::StatementInvalid, /#{constraint_name}/)
+ unless skip_constraint_test
+ it 'is not valid even if forced' do
+ subject.validate # to generate iid/etc
+ expect { subject.save!(validate: false) }.to raise_exception(ActiveRecord::StatementInvalid, /#{constraint_name}/)
+ end
end
end
end
@@ -177,6 +183,14 @@ RSpec.describe Iteration do
expect { subject.save! }.not_to raise_exception
end
end
+
+ context 'sub-group' do
+ let(:subgroup) { create(:group, parent: group) }
+
+ subject { build(:iteration, group: subgroup, start_date: start_date, due_date: due_date) }
+
+ it_behaves_like 'overlapping dates', skip_constraint_test: true
+ end
end
context 'project' do
@@ -210,6 +224,17 @@ RSpec.describe Iteration do
end
end
end
+
+ context 'project in a group' do
+ let_it_be(:project) { create(:project, group: create(:group)) }
+ let_it_be(:existing_iteration) { create(:iteration, :skip_project_validation, project: project, start_date: 4.days.from_now, due_date: 1.week.from_now) }
+
+ subject { build(:iteration, :skip_project_validation, project: project, start_date: start_date, due_date: due_date) }
+
+ it_behaves_like 'overlapping dates' do
+ let(:constraint_name) { 'iteration_start_and_due_daterange_project_id_constraint' }
+ end
+ end
end
end
diff --git a/spec/models/member_spec.rb b/spec/models/member_spec.rb
index 90950d93db4..118b1492cd6 100644
--- a/spec/models/member_spec.rb
+++ b/spec/models/member_spec.rb
@@ -212,6 +212,16 @@ RSpec.describe Member do
it { expect(described_class.non_request).to include @accepted_request_member }
end
+ describe '.not_accepted_invitations' do
+ let_it_be(:not_accepted_invitation) { create(:project_member, :invited) }
+ let_it_be(:accepted_invitation) { create(:project_member, :invited, invite_accepted_at: Date.today) }
+
+ subject { described_class.not_accepted_invitations }
+
+ it { is_expected.to include(not_accepted_invitation) }
+ it { is_expected.not_to include(accepted_invitation) }
+ end
+
describe '.not_accepted_invitations_by_user' do
let(:invited_by_user) { create(:project_member, :invited, project: project, created_by: @owner_user) }
@@ -225,6 +235,33 @@ RSpec.describe Member do
it { is_expected.to contain_exactly(invited_by_user) }
end
+ describe '.not_expired' do
+ let_it_be(:expiring_yesterday) { create(:group_member, expires_at: 1.day.from_now) }
+ let_it_be(:expiring_today) { create(:group_member, expires_at: 2.days.from_now) }
+ let_it_be(:expiring_tomorrow) { create(:group_member, expires_at: 3.days.from_now) }
+ let_it_be(:not_expiring) { create(:group_member) }
+
+ subject { described_class.not_expired }
+
+ around do |example|
+ travel_to(2.days.from_now) { example.run }
+ end
+
+ it { is_expected.not_to include(expiring_yesterday, expiring_today) }
+ it { is_expected.to include(expiring_tomorrow, not_expiring) }
+ end
+
+ describe '.last_ten_days_excluding_today' do
+ let_it_be(:created_today) { create(:group_member, created_at: Date.today.beginning_of_day) }
+ let_it_be(:created_yesterday) { create(:group_member, created_at: 1.day.ago) }
+ let_it_be(:created_eleven_days_ago) { create(:group_member, created_at: 11.days.ago) }
+
+ subject { described_class.last_ten_days_excluding_today }
+
+ it { is_expected.to include(created_yesterday) }
+ it { is_expected.not_to include(created_today, created_eleven_days_ago) }
+ end
+
describe '.search_invite_email' do
it 'returns only members the matching e-mail' do
create(:group_member, :invited)
@@ -683,6 +720,45 @@ RSpec.describe Member do
end
end
+ describe '#send_invitation_reminder' do
+ subject { member.send_invitation_reminder(0) }
+
+ context 'an invited group member' do
+ let!(:member) { create(:group_member, :invited) }
+
+ it 'sends a reminder' do
+ expect_any_instance_of(NotificationService).to receive(:invite_member_reminder).with(member, member.raw_invite_token, 0)
+
+ subject
+ end
+ end
+
+ context 'an invited member without a raw invite token set' do
+ let!(:member) { create(:group_member, :invited) }
+
+ before do
+ member.instance_variable_set(:@raw_invite_token, nil)
+ allow_any_instance_of(NotificationService).to receive(:invite_member_reminder)
+ end
+
+ it 'generates a new token' do
+ expect(member).to receive(:generate_invite_token!)
+
+ subject
+ end
+ end
+
+ context 'an uninvited member' do
+ let!(:member) { create(:group_member) }
+
+ it 'does not send a reminder' do
+ expect_any_instance_of(NotificationService).not_to receive(:invite_member_reminder)
+
+ subject
+ end
+ end
+ end
+
describe "#invite_to_unknown_user?" do
subject { member.invite_to_unknown_user? }
diff --git a/spec/models/merge_request_diff_spec.rb b/spec/models/merge_request_diff_spec.rb
index 2c64201e84d..6706083fd91 100644
--- a/spec/models/merge_request_diff_spec.rb
+++ b/spec/models/merge_request_diff_spec.rb
@@ -180,6 +180,17 @@ RSpec.describe MergeRequestDiff do
expect(diff.external_diff_store).to eq(file_store)
end
+ it 'migrates a nil diff file' do
+ expect(diff).not_to be_stored_externally
+ MergeRequestDiffFile.where(merge_request_diff_id: diff.id).update_all(diff: nil)
+
+ stub_external_diffs_setting(enabled: true)
+
+ diff.migrate_files_to_external_storage!
+
+ expect(diff).to be_stored_externally
+ end
+
it 'safely handles a transaction error when migrating to external storage' do
expect(diff).not_to be_stored_externally
expect(diff.external_diff).not_to be_exists
@@ -646,13 +657,32 @@ RSpec.describe MergeRequestDiff do
expect(diff_with_commits.commit_shas).to all(match(/\h{40}/))
end
- context 'with limit attribute' do
+ shared_examples 'limited number of shas' do
it 'returns limited number of shas' do
expect(diff_with_commits.commit_shas(limit: 2).size).to eq(2)
expect(diff_with_commits.commit_shas(limit: 100).size).to eq(29)
expect(diff_with_commits.commit_shas.size).to eq(29)
end
end
+
+ context 'with limit attribute' do
+ it_behaves_like 'limited number of shas'
+ end
+
+ context 'with preloaded diff commits' do
+ before do
+ # preloads the merge_request_diff_commits association
+ diff_with_commits.merge_request_diff_commits.to_a
+ end
+
+ it_behaves_like 'limited number of shas'
+
+ it 'does not trigger any query' do
+ count = ActiveRecord::QueryRecorder.new { diff_with_commits.commit_shas(limit: 2) }.count
+
+ expect(count).to eq(0)
+ end
+ end
end
describe '#compare_with' do
@@ -865,4 +895,25 @@ RSpec.describe MergeRequestDiff do
expect(subject.lines_count).to eq 189
end
end
+
+ describe '.latest_diff_for_merge_requests' do
+ let_it_be(:merge_request_1) { create(:merge_request_without_merge_request_diff) }
+ let_it_be(:merge_request_1_diff_1) { create(:merge_request_diff, merge_request: merge_request_1, created_at: 3.days.ago) }
+ let_it_be(:merge_request_1_diff_2) { create(:merge_request_diff, merge_request: merge_request_1, created_at: 1.day.ago) }
+
+ let_it_be(:merge_request_2) { create(:merge_request_without_merge_request_diff) }
+ let_it_be(:merge_request_2_diff_1) { create(:merge_request_diff, merge_request: merge_request_2, created_at: 3.days.ago) }
+
+ let_it_be(:merge_request_3) { create(:merge_request_without_merge_request_diff) }
+
+ subject { described_class.latest_diff_for_merge_requests([merge_request_1, merge_request_2]) }
+
+ it 'loads the latest merge_request_diff record for the given merge requests' do
+ expect(subject).to match_array([merge_request_1_diff_2, merge_request_2_diff_1])
+ end
+
+ it 'loads nothing if the merge request has no diff record' do
+ expect(described_class.latest_diff_for_merge_requests(merge_request_3)).to be_empty
+ end
+ end
end
diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb
index 98f709a0610..ddb3ffdda2f 100644
--- a/spec/models/merge_request_spec.rb
+++ b/spec/models/merge_request_spec.rb
@@ -2358,48 +2358,43 @@ RSpec.describe MergeRequest, factory_default: :keep do
end
end
- context 'when state event tracking is disabled' do
+ context 'when no metrics or merge event exists' do
+ let(:user) { create(:user) }
+ let(:merge_request) { create(:merge_request, :merged) }
+
before do
- stub_feature_flags(track_resource_state_change_events: false)
+ merge_request.metrics.destroy!
end
- context 'when merging note is persisted, but no metrics or merge event exists' do
- let(:user) { create(:user) }
- let(:merge_request) { create(:merge_request, :merged) }
-
+ context 'when resource event for the merge exists' do
before do
- merge_request.metrics.destroy!
-
SystemNoteService.change_status(merge_request,
merge_request.target_project,
user,
merge_request.state, nil)
end
- it 'returns merging note creation date' do
+ it 'returns the resource event creation date' do
expect(merge_request.reload.metrics).to be_nil
expect(merge_request.merge_event).to be_nil
- expect(merge_request.notes.count).to eq(1)
- expect(merge_request.merged_at).to eq(merge_request.notes.first.created_at)
+ expect(merge_request.resource_state_events.count).to eq(1)
+ expect(merge_request.merged_at).to eq(merge_request.resource_state_events.first.created_at)
end
end
- end
-
- context 'when state event tracking is enabled' do
- let(:user) { create(:user) }
- let(:merge_request) { create(:merge_request, :merged) }
-
- before do
- merge_request.metrics.destroy!
- SystemNoteService.change_status(merge_request,
- merge_request.target_project,
- user,
- merge_request.state, nil)
- end
+ context 'when system note for the merge exists' do
+ before do
+ # We do not create these system notes anymore but we need this to work for existing MRs
+ # that used system notes instead of resource state events
+ create(:note, :system, noteable: merge_request, note: 'merged')
+ end
- it 'does not create a system note' do
- expect(merge_request.notes).to be_empty
+ it 'returns the merging note creation date' do
+ expect(merge_request.reload.metrics).to be_nil
+ expect(merge_request.merge_event).to be_nil
+ expect(merge_request.notes.count).to eq(1)
+ expect(merge_request.merged_at).to eq(merge_request.notes.first.created_at)
+ end
end
end
end
@@ -3525,6 +3520,25 @@ RSpec.describe MergeRequest, factory_default: :keep do
end
end
+ describe '#merge_base_pipeline' do
+ let(:merge_request) do
+ create(:merge_request, :with_merge_request_pipeline)
+ end
+
+ let(:merge_base_pipeline) do
+ create(:ci_pipeline, ref: merge_request.target_branch, sha: merge_request.target_branch_sha)
+ end
+
+ before do
+ merge_base_pipeline
+ merge_request.update_head_pipeline
+ end
+
+ it 'returns a pipeline pointing to a commit on the target ref' do
+ expect(merge_request.merge_base_pipeline).to eq(merge_base_pipeline)
+ end
+ end
+
describe '#has_commits?' do
it 'returns true when merge request diff has commits' do
allow(subject.merge_request_diff).to receive(:commits_count)
@@ -4214,14 +4228,26 @@ RSpec.describe MergeRequest, factory_default: :keep do
it 'returns true' do
expect(subject.diffable_merge_ref?).to eq(true)
end
- end
- end
- context 'merge request cannot be merged' do
- it 'returns false' do
- subject.mark_as_unchecked!
+ context 'merge request cannot be merged' do
+ before do
+ subject.mark_as_unchecked!
+ end
+
+ it 'returns false' do
+ expect(subject.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
- expect(subject.diffable_merge_ref?).to eq(false)
+ it 'returns false' do
+ expect(subject.diffable_merge_ref?).to eq(false)
+ end
+ end
+ end
end
end
end
@@ -4261,24 +4287,6 @@ RSpec.describe MergeRequest, factory_default: :keep do
end
end
- describe '#allows_reviewers?' do
- it 'returns false without merge_request_reviewers feature' do
- stub_feature_flags(merge_request_reviewers: false)
-
- merge_request = build_stubbed(:merge_request)
-
- expect(merge_request.allows_reviewers?).to be(false)
- end
-
- it 'returns true with merge_request_reviewers feature' do
- stub_feature_flags(merge_request_reviewers: true)
-
- merge_request = build_stubbed(:merge_request)
-
- expect(merge_request.allows_reviewers?).to be(true)
- end
- end
-
describe '#merge_ref_head' do
let(:merge_request) { create(:merge_request) }
@@ -4304,4 +4312,36 @@ RSpec.describe MergeRequest, factory_default: :keep do
end
end
end
+
+ describe '#allows_reviewers?' do
+ it 'returns false without merge_request_reviewers feature' do
+ stub_feature_flags(merge_request_reviewers: false)
+
+ merge_request = build_stubbed(:merge_request)
+
+ expect(merge_request.allows_reviewers?).to be(false)
+ end
+
+ it 'returns true with merge_request_reviewers feature' do
+ stub_feature_flags(merge_request_reviewers: true)
+
+ merge_request = build_stubbed(:merge_request)
+
+ expect(merge_request.allows_reviewers?).to be(true)
+ end
+ end
+
+ describe '#update_and_mark_in_progress_merge_commit_sha' do
+ let(:ref) { subject.target_project.repository.commit.id }
+
+ before do
+ expect(subject.target_project).to receive(:mark_primary_write_location)
+ end
+
+ it 'updates commit ID' do
+ expect { subject.update_and_mark_in_progress_merge_commit_sha(ref) }
+ .to change { subject.in_progress_merge_commit_sha }
+ .from(nil).to(ref)
+ end
+ end
end
diff --git a/spec/models/milestone_release_spec.rb b/spec/models/milestone_release_spec.rb
index 3c781545d8a..b2a174f1d90 100644
--- a/spec/models/milestone_release_spec.rb
+++ b/spec/models/milestone_release_spec.rb
@@ -10,8 +10,8 @@ RSpec.describe MilestoneRelease do
subject { build(:milestone_release, release: release, milestone: milestone) }
describe 'associations' do
- it { is_expected.to belong_to(:milestone) }
it { is_expected.to belong_to(:release) }
+ it { is_expected.to belong_to(:milestone) }
end
context 'when trying to create the same record in milestone_releases twice' do
diff --git a/spec/models/namespace_setting_spec.rb b/spec/models/namespace_setting_spec.rb
index 257d78dfa2c..c6e8d5b129c 100644
--- a/spec/models/namespace_setting_spec.rb
+++ b/spec/models/namespace_setting_spec.rb
@@ -3,5 +3,71 @@
require 'spec_helper'
RSpec.describe NamespaceSetting, type: :model do
- it { is_expected.to belong_to(:namespace) }
+ # Relationships
+ #
+ describe "Associations" do
+ it { is_expected.to belong_to(:namespace) }
+ end
+
+ describe "validations" do
+ describe "#default_branch_name_content" do
+ let_it_be(:group) { create(:group) }
+
+ let(:namespace_settings) { group.namespace_settings }
+
+ shared_examples "doesn't return an error" do
+ it "doesn't return an error" do
+ expect(namespace_settings.valid?).to be_truthy
+ expect(namespace_settings.errors.full_messages).to be_empty
+ end
+ end
+
+ context "when not set" do
+ it_behaves_like "doesn't return an error"
+ end
+
+ context "when set" do
+ before do
+ namespace_settings.default_branch_name = "example_branch_name"
+ end
+
+ it_behaves_like "doesn't return an error"
+ end
+
+ context "when an empty string" do
+ before do
+ namespace_settings.default_branch_name = ''
+ end
+
+ it "returns an error" do
+ expect(namespace_settings.valid?).to be_falsey
+ expect(namespace_settings.errors.full_messages).not_to be_empty
+ end
+ end
+ end
+
+ describe '#allow_mfa_for_group' do
+ let(:settings) { group.namespace_settings }
+
+ context 'group is top-level group' do
+ let(:group) { create(:group) }
+
+ it 'is valid' do
+ settings.allow_mfa_for_subgroups = false
+
+ expect(settings).to be_valid
+ end
+ end
+
+ context 'group is a subgroup' do
+ let(:group) { create(:group, parent: create(:group)) }
+
+ it 'is invalid' do
+ settings.allow_mfa_for_subgroups = false
+
+ expect(settings).to be_invalid
+ end
+ end
+ end
+ end
end
diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb
index ca1f06370d4..91b18f346c6 100644
--- a/spec/models/namespace_spec.rb
+++ b/spec/models/namespace_spec.rb
@@ -855,13 +855,49 @@ RSpec.describe Namespace do
end
describe '#all_projects' do
- let(:group) { create(:group) }
- let(:child) { create(:group, parent: group) }
- let!(:project1) { create(:project_empty_repo, namespace: group) }
- let!(:project2) { create(:project_empty_repo, namespace: child) }
+ shared_examples 'all projects for a namespace' do
+ let(:namespace) { create(:namespace) }
+ let(:child) { create(:group, parent: namespace) }
+ let!(:project1) { create(:project_empty_repo, namespace: namespace) }
+ let!(:project2) { create(:project_empty_repo, namespace: child) }
+
+ it { expect(namespace.all_projects.to_a).to match_array([project2, project1]) }
+ it { expect(child.all_projects.to_a).to match_array([project2]) }
+ end
+
+ shared_examples 'all project examples' do
+ include_examples 'all projects for a namespace'
+
+ context 'when namespace is a group' do
+ let_it_be(:namespace) { create(:group) }
+
+ include_examples 'all projects for a namespace'
+ end
- it { expect(group.all_projects.to_a).to match_array([project2, project1]) }
- it { expect(child.all_projects.to_a).to match_array([project2]) }
+ context 'when namespace is a user namespace' do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:user_namespace) { create(:namespace, owner: user) }
+ let_it_be(:project) { create(:project, namespace: user_namespace) }
+
+ it { expect(user_namespace.all_projects.to_a).to match_array([project]) }
+ end
+ end
+
+ context 'with recursive approach' do
+ before do
+ stub_feature_flags(recursive_approach_for_all_projects: true)
+ end
+
+ include_examples 'all project examples'
+ end
+
+ context 'with route path wildcard approach' do
+ before do
+ stub_feature_flags(recursive_approach_for_all_projects: false)
+ end
+
+ include_examples 'all project examples'
+ end
end
describe '#all_pipelines' do
@@ -1320,4 +1356,140 @@ RSpec.describe Namespace do
end
end
end
+
+ describe '#shared_runners_setting' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:shared_runners_enabled, :allow_descendants_override_disabled_shared_runners, :shared_runners_setting) do
+ true | true | 'enabled'
+ true | false | 'enabled'
+ false | true | 'disabled_with_override'
+ false | false | 'disabled_and_unoverridable'
+ end
+
+ with_them do
+ let(:namespace) { build(:namespace, shared_runners_enabled: shared_runners_enabled, allow_descendants_override_disabled_shared_runners: allow_descendants_override_disabled_shared_runners)}
+
+ it 'returns the result' do
+ expect(namespace.shared_runners_setting).to eq(shared_runners_setting)
+ end
+ end
+ end
+
+ describe '#shared_runners_setting_higher_than?' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:shared_runners_enabled, :allow_descendants_override_disabled_shared_runners, :other_setting, :result) do
+ true | true | 'enabled' | false
+ true | true | 'disabled_with_override' | true
+ true | true | 'disabled_and_unoverridable' | true
+ false | true | 'enabled' | false
+ false | true | 'disabled_with_override' | false
+ false | true | 'disabled_and_unoverridable' | true
+ false | false | 'enabled' | false
+ false | false | 'disabled_with_override' | false
+ false | false | 'disabled_and_unoverridable' | false
+ end
+
+ with_them do
+ let(:namespace) { build(:namespace, shared_runners_enabled: shared_runners_enabled, allow_descendants_override_disabled_shared_runners: allow_descendants_override_disabled_shared_runners)}
+
+ it 'returns the result' do
+ expect(namespace.shared_runners_setting_higher_than?(other_setting)).to eq(result)
+ end
+ end
+ end
+
+ describe 'validation #changing_shared_runners_enabled_is_allowed' do
+ context 'without a parent' do
+ let(:namespace) { build(:namespace, shared_runners_enabled: true) }
+
+ it 'is valid' do
+ expect(namespace).to be_valid
+ end
+ end
+
+ context 'with a parent' do
+ context 'when parent has shared runners disabled' do
+ let(:parent) { create(:namespace, :shared_runners_disabled) }
+ let(:sub_namespace) { build(:namespace, shared_runners_enabled: true, parent_id: parent.id) }
+
+ it 'is invalid' do
+ expect(sub_namespace).to be_invalid
+ expect(sub_namespace.errors[:shared_runners_enabled]).to include('cannot be enabled because parent group has shared Runners disabled')
+ end
+ end
+
+ context 'when parent has shared runners disabled but allows override' do
+ let(:parent) { create(:namespace, :shared_runners_disabled, :allow_descendants_override_disabled_shared_runners) }
+ let(:sub_namespace) { build(:namespace, shared_runners_enabled: true, parent_id: parent.id) }
+
+ it 'is valid' do
+ expect(sub_namespace).to be_valid
+ end
+ end
+
+ context 'when parent has shared runners enabled' do
+ let(:parent) { create(:namespace, shared_runners_enabled: true) }
+ let(:sub_namespace) { build(:namespace, shared_runners_enabled: true, parent_id: parent.id) }
+
+ it 'is valid' do
+ expect(sub_namespace).to be_valid
+ end
+ end
+ end
+ end
+
+ describe 'validation #changing_allow_descendants_override_disabled_shared_runners_is_allowed' do
+ context 'without a parent' do
+ context 'with shared runners disabled' do
+ let(:namespace) { build(:namespace, :allow_descendants_override_disabled_shared_runners, :shared_runners_disabled) }
+
+ it 'is valid' do
+ expect(namespace).to be_valid
+ end
+ end
+
+ context 'with shared runners enabled' do
+ let(:namespace) { create(:namespace) }
+
+ it 'is invalid' do
+ namespace.allow_descendants_override_disabled_shared_runners = true
+
+ expect(namespace).to be_invalid
+ expect(namespace.errors[:allow_descendants_override_disabled_shared_runners]).to include('cannot be changed if shared runners are enabled')
+ end
+ end
+ end
+
+ context 'with a parent' do
+ context 'when parent does not allow shared runners' do
+ let(:parent) { create(:namespace, :shared_runners_disabled) }
+ let(:sub_namespace) { build(:namespace, :shared_runners_disabled, :allow_descendants_override_disabled_shared_runners, parent_id: parent.id) }
+
+ it 'is invalid' do
+ expect(sub_namespace).to be_invalid
+ expect(sub_namespace.errors[:allow_descendants_override_disabled_shared_runners]).to include('cannot be enabled because parent group does not allow it')
+ end
+ end
+
+ context 'when parent allows shared runners and setting to true' do
+ let(:parent) { create(:namespace, shared_runners_enabled: true) }
+ let(:sub_namespace) { build(:namespace, :shared_runners_disabled, :allow_descendants_override_disabled_shared_runners, parent_id: parent.id) }
+
+ it 'is valid' do
+ expect(sub_namespace).to be_valid
+ end
+ end
+
+ context 'when parent allows shared runners and setting to false' do
+ let(:parent) { create(:namespace, shared_runners_enabled: true) }
+ let(:sub_namespace) { build(:namespace, :shared_runners_disabled, allow_descendants_override_disabled_shared_runners: false, parent_id: parent.id) }
+
+ it 'is valid' do
+ expect(sub_namespace).to be_valid
+ end
+ end
+ end
+ end
end
diff --git a/spec/models/notification_setting_spec.rb b/spec/models/notification_setting_spec.rb
index 0f765d6b09b..bc50e2af373 100644
--- a/spec/models/notification_setting_spec.rb
+++ b/spec/models/notification_setting_spec.rb
@@ -175,6 +175,7 @@ RSpec.describe NotificationSetting do
:reopen_merge_request,
:close_merge_request,
:reassign_merge_request,
+ :change_reviewer_merge_request,
:merge_merge_request,
:failed_pipeline,
:success_pipeline,
diff --git a/spec/models/operations/feature_flag_spec.rb b/spec/models/operations/feature_flag_spec.rb
index db432e73355..b4e941f2856 100644
--- a/spec/models/operations/feature_flag_spec.rb
+++ b/spec/models/operations/feature_flag_spec.rb
@@ -25,7 +25,7 @@ RSpec.describe Operations::FeatureFlag do
context 'a version 1 feature flag' do
it 'is valid if associated with Operations::FeatureFlagScope models' do
project = create(:project)
- feature_flag = described_class.create({ name: 'test', project: project, version: 1,
+ feature_flag = described_class.create!({ name: 'test', project: project, version: 1,
scopes_attributes: [{ environment_scope: '*', active: false }] })
expect(feature_flag).to be_valid
@@ -33,9 +33,10 @@ RSpec.describe Operations::FeatureFlag do
it 'is invalid if associated with Operations::FeatureFlags::Strategy models' do
project = create(:project)
- feature_flag = described_class.create({ name: 'test', project: project, version: 1,
+ feature_flag = described_class.new({ name: 'test', project: project, version: 1,
strategies_attributes: [{ name: 'default', parameters: {} }] })
+ expect(feature_flag.valid?).to eq(false)
expect(feature_flag.errors.messages).to eq({
version_associations: ["version 1 feature flags may not have strategies"]
})
@@ -45,9 +46,10 @@ RSpec.describe Operations::FeatureFlag do
context 'a version 2 feature flag' do
it 'is invalid if associated with Operations::FeatureFlagScope models' do
project = create(:project)
- feature_flag = described_class.create({ name: 'test', project: project, version: 2,
+ feature_flag = described_class.new({ name: 'test', project: project, version: 2,
scopes_attributes: [{ environment_scope: '*', active: false }] })
+ expect(feature_flag.valid?).to eq(false)
expect(feature_flag.errors.messages).to eq({
version_associations: ["version 2 feature flags may not have scopes"]
})
@@ -55,7 +57,7 @@ RSpec.describe Operations::FeatureFlag do
it 'is valid if associated with Operations::FeatureFlags::Strategy models' do
project = create(:project)
- feature_flag = described_class.create({ name: 'test', project: project, version: 2,
+ feature_flag = described_class.create!({ name: 'test', project: project, version: 2,
strategies_attributes: [{ name: 'default', parameters: {} }] })
expect(feature_flag).to be_valid
@@ -75,7 +77,7 @@ RSpec.describe Operations::FeatureFlag do
it 'defaults to 1 if unspecified' do
project = create(:project)
- feature_flag = described_class.create(name: 'my_flag', project: project, active: true)
+ feature_flag = described_class.create!(name: 'my_flag', project: project, active: true)
expect(feature_flag).to be_valid
expect(feature_flag.version_before_type_cast).to eq(1)
@@ -113,14 +115,14 @@ RSpec.describe Operations::FeatureFlag do
context 'with a version 1 feature flag' do
it 'creates a default scope' do
- feature_flag = described_class.create({ name: 'test', project: project, scopes_attributes: [], version: 1 })
+ feature_flag = described_class.create!({ name: 'test', project: project, scopes_attributes: [], version: 1 })
expect(feature_flag.scopes.count).to eq(1)
expect(feature_flag.scopes.first.environment_scope).to eq('*')
end
it 'allows specifying the default scope in the parameters' do
- feature_flag = described_class.create({ name: 'test', project: project,
+ feature_flag = described_class.create!({ name: 'test', project: project,
scopes_attributes: [{ environment_scope: '*', active: false },
{ environment_scope: 'review/*', active: true }], version: 1 })
@@ -131,7 +133,7 @@ RSpec.describe Operations::FeatureFlag do
context 'with a version 2 feature flag' do
it 'does not create a default scope' do
- feature_flag = described_class.create({ name: 'test', project: project, scopes_attributes: [], version: 2 })
+ feature_flag = described_class.create!({ name: 'test', project: project, scopes_attributes: [], version: 2 })
expect(feature_flag.scopes).to eq([])
end
diff --git a/spec/models/operations/feature_flags/strategy_spec.rb b/spec/models/operations/feature_flags/strategy_spec.rb
index 04e3ef26e9d..0ecb49e75f3 100644
--- a/spec/models/operations/feature_flags/strategy_spec.rb
+++ b/spec/models/operations/feature_flags/strategy_spec.rb
@@ -4,11 +4,12 @@ require 'spec_helper'
RSpec.describe Operations::FeatureFlags::Strategy do
let_it_be(:project) { create(:project) }
+ let_it_be(:feature_flag) { create(:operations_feature_flag, project: project) }
describe 'validations' do
it do
is_expected.to validate_inclusion_of(:name)
- .in_array(%w[default gradualRolloutUserId userWithId gitlabUserList])
+ .in_array(%w[default gradualRolloutUserId flexibleRollout userWithId gitlabUserList])
.with_message('strategy name is invalid')
end
@@ -19,7 +20,6 @@ RSpec.describe Operations::FeatureFlags::Strategy do
end
with_them do
it 'skips parameters validation' do
- feature_flag = create(:operations_feature_flag, project: project)
strategy = described_class.create(feature_flag: feature_flag,
name: invalid_name, parameters: { bad: 'params' })
@@ -36,7 +36,6 @@ RSpec.describe Operations::FeatureFlags::Strategy do
end
with_them do
it 'must have valid parameters for the strategy' do
- feature_flag = create(:operations_feature_flag, project: project)
strategy = described_class.create(feature_flag: feature_flag,
name: 'gradualRolloutUserId', parameters: invalid_parameters)
@@ -45,7 +44,6 @@ RSpec.describe Operations::FeatureFlags::Strategy do
end
it 'allows the parameters in any order' do
- feature_flag = create(:operations_feature_flag, project: project)
strategy = described_class.create(feature_flag: feature_flag,
name: 'gradualRolloutUserId',
parameters: { percentage: '10', groupId: 'mygroup' })
@@ -55,13 +53,12 @@ RSpec.describe Operations::FeatureFlags::Strategy do
describe 'percentage' do
where(:invalid_value) do
- [50, 40.0, { key: "value" }, "garbage", "00", "01", "101", "-1", "-10", "0100",
- "1000", "10.0", "5%", "25%", "100hi", "e100", "30m", " ", "\r\n", "\n", "\t",
- "\n10", "20\n", "\n100", "100\n", "\n ", nil]
+ [50, 40.0, { key: "value" }, "garbage", "101", "-1", "-10", "1000", "10.0", "5%", "25%",
+ "100hi", "e100", "30m", " ", "\r\n", "\n", "\t", "\n10", "20\n", "\n100", "100\n",
+ "\n ", nil]
end
with_them do
it 'must be a string value between 0 and 100 inclusive and without a percentage sign' do
- feature_flag = create(:operations_feature_flag, project: project)
strategy = described_class.create(feature_flag: feature_flag,
name: 'gradualRolloutUserId',
parameters: { groupId: 'mygroup', percentage: invalid_value })
@@ -75,7 +72,6 @@ RSpec.describe Operations::FeatureFlags::Strategy do
end
with_them do
it 'must be a string value between 0 and 100 inclusive and without a percentage sign' do
- feature_flag = create(:operations_feature_flag, project: project)
strategy = described_class.create(feature_flag: feature_flag,
name: 'gradualRolloutUserId',
parameters: { groupId: 'mygroup', percentage: valid_value })
@@ -92,7 +88,6 @@ RSpec.describe Operations::FeatureFlags::Strategy do
end
with_them do
it 'must be a string value of up to 32 lowercase characters' do
- feature_flag = create(:operations_feature_flag, project: project)
strategy = described_class.create(feature_flag: feature_flag,
name: 'gradualRolloutUserId',
parameters: { groupId: invalid_value, percentage: '40' })
@@ -106,7 +101,6 @@ RSpec.describe Operations::FeatureFlags::Strategy do
end
with_them do
it 'must be a string value of up to 32 lowercase characters' do
- feature_flag = create(:operations_feature_flag, project: project)
strategy = described_class.create(feature_flag: feature_flag,
name: 'gradualRolloutUserId',
parameters: { groupId: valid_value, percentage: '40' })
@@ -117,13 +111,132 @@ RSpec.describe Operations::FeatureFlags::Strategy do
end
end
+ context 'when the strategy name is flexibleRollout' do
+ valid_parameters = { rollout: '40', groupId: 'mygroup', stickiness: 'DEFAULT' }
+ where(invalid_parameters: [
+ nil,
+ {},
+ *valid_parameters.to_a.combination(1).to_a.map { |p| p.to_h },
+ *valid_parameters.to_a.combination(2).to_a.map { |p| p.to_h },
+ { **valid_parameters, userIds: '4' },
+ { **valid_parameters, extra: nil }
+ ])
+ with_them do
+ it 'must have valid parameters for the strategy' do
+ strategy = described_class.create(feature_flag: feature_flag,
+ name: 'flexibleRollout',
+ parameters: invalid_parameters)
+
+ expect(strategy.errors[:parameters]).to eq(['parameters are invalid'])
+ end
+ end
+
+ [
+ [:rollout, '10'],
+ [:stickiness, 'DEFAULT'],
+ [:groupId, 'mygroup']
+ ].permutation(3).each do |parameters|
+ it "allows the parameters in the order #{parameters.map { |p| p.first }.join(', ')}" do
+ strategy = described_class.create(feature_flag: feature_flag,
+ name: 'flexibleRollout',
+ parameters: Hash[parameters])
+
+ expect(strategy.errors[:parameters]).to be_empty
+ end
+ end
+
+ describe 'rollout' do
+ where(invalid_value: [50, 40.0, { key: "value" }, "garbage", "101", "-1", " ", "-10",
+ "1000", "10.0", "5%", "25%", "100hi", "e100", "30m", "\r\n",
+ "\n", "\t", "\n10", "20\n", "\n100", "100\n", "\n ", nil])
+ with_them do
+ it 'must be a string value between 0 and 100 inclusive and without a percentage sign' do
+ parameters = { stickiness: 'DEFAULT', groupId: 'mygroup', rollout: invalid_value }
+ strategy = described_class.create(feature_flag: feature_flag,
+ name: 'flexibleRollout',
+ parameters: parameters)
+
+ expect(strategy.errors[:parameters]).to eq([
+ 'rollout must be a string between 0 and 100 inclusive'
+ ])
+ end
+ end
+
+ where(valid_value: %w[0 1 10 38 100 93])
+ with_them do
+ it 'must be a string value between 0 and 100 inclusive and without a percentage sign' do
+ parameters = { stickiness: 'DEFAULT', groupId: 'mygroup', rollout: valid_value }
+ strategy = described_class.create(feature_flag: feature_flag,
+ name: 'flexibleRollout',
+ parameters: parameters)
+
+ expect(strategy.errors[:parameters]).to eq([])
+ end
+ end
+ end
+
+ describe 'groupId' do
+ where(invalid_value: [nil, 4, 50.0, {}, 'spaces bad', 'bad$', '%bad', '<bad', 'bad>',
+ '!bad', '.bad', 'Bad', 'bad1', "", " ", "b" * 33, "ba_d", "ba\nd"])
+ with_them do
+ it 'must be a string value of up to 32 lowercase characters' do
+ parameters = { stickiness: 'DEFAULT', groupId: invalid_value, rollout: '40' }
+ strategy = described_class.create(feature_flag: feature_flag,
+ name: 'flexibleRollout',
+ parameters: parameters)
+
+ expect(strategy.errors[:parameters]).to eq(['groupId parameter is invalid'])
+ end
+ end
+
+ where(valid_value: ["somegroup", "anothergroup", "okay", "g", "a" * 32])
+ with_them do
+ it 'must be a string value of up to 32 lowercase characters' do
+ parameters = { stickiness: 'DEFAULT', groupId: valid_value, rollout: '40' }
+ strategy = described_class.create(feature_flag: feature_flag,
+ name: 'flexibleRollout',
+ parameters: parameters)
+
+ expect(strategy.errors[:parameters]).to eq([])
+ end
+ end
+ end
+
+ describe 'stickiness' do
+ where(invalid_value: [nil, " ", "default", "DEFAULT\n", "UserId", "USER", "USERID "])
+ with_them do
+ it 'must be a string representing a supported stickiness setting' do
+ parameters = { stickiness: invalid_value, groupId: 'mygroup', rollout: '40' }
+ strategy = described_class.create(feature_flag: feature_flag,
+ name: 'flexibleRollout',
+ parameters: parameters)
+
+ expect(strategy.errors[:parameters]).to eq([
+ 'stickiness parameter must be DEFAULT, USERID, SESSIONID, or RANDOM'
+ ])
+ end
+ end
+
+ where(valid_value: %w[DEFAULT USERID SESSIONID RANDOM])
+ with_them do
+ it 'must be a string representing a supported stickiness setting' do
+ parameters = { stickiness: valid_value, groupId: 'mygroup', rollout: '40' }
+ strategy = described_class.create(feature_flag: feature_flag,
+ name: 'flexibleRollout',
+ parameters: parameters)
+
+ expect(strategy.errors[:parameters]).to eq([])
+ end
+ end
+ end
+ end
+
context 'when the strategy name is userWithId' do
where(:invalid_parameters) do
[nil, { userIds: 'sam', percentage: '40' }, { userIds: 'sam', some: 'param' }, { percentage: '40' }, {}]
end
with_them do
it 'must have valid parameters for the strategy' do
- feature_flag = create(:operations_feature_flag, project: project)
strategy = described_class.create(feature_flag: feature_flag,
name: 'userWithId', parameters: invalid_parameters)
@@ -140,7 +253,6 @@ RSpec.describe Operations::FeatureFlags::Strategy do
end
with_them do
it 'is valid with a string of comma separated values' do
- feature_flag = create(:operations_feature_flag, project: project)
strategy = described_class.create(feature_flag: feature_flag,
name: 'userWithId', parameters: { userIds: valid_value })
@@ -155,7 +267,6 @@ RSpec.describe Operations::FeatureFlags::Strategy do
end
with_them do
it 'is invalid' do
- feature_flag = create(:operations_feature_flag, project: project)
strategy = described_class.create(feature_flag: feature_flag,
name: 'userWithId', parameters: { userIds: invalid_value })
@@ -173,7 +284,6 @@ RSpec.describe Operations::FeatureFlags::Strategy do
end
with_them do
it 'must be empty' do
- feature_flag = create(:operations_feature_flag, project: project)
strategy = described_class.create(feature_flag: feature_flag,
name: 'default',
parameters: invalid_value)
@@ -183,7 +293,6 @@ RSpec.describe Operations::FeatureFlags::Strategy do
end
it 'must be empty' do
- feature_flag = create(:operations_feature_flag, project: project)
strategy = described_class.create(feature_flag: feature_flag,
name: 'default',
parameters: {})
@@ -198,7 +307,6 @@ RSpec.describe Operations::FeatureFlags::Strategy do
end
with_them do
it 'must be empty' do
- feature_flag = create(:operations_feature_flag, project: project)
strategy = described_class.create(feature_flag: feature_flag,
name: 'gitlabUserList',
parameters: invalid_value)
@@ -208,7 +316,6 @@ RSpec.describe Operations::FeatureFlags::Strategy do
end
it 'must be empty' do
- feature_flag = create(:operations_feature_flag, project: project)
strategy = described_class.create(feature_flag: feature_flag,
name: 'gitlabUserList',
parameters: {})
@@ -221,7 +328,6 @@ RSpec.describe Operations::FeatureFlags::Strategy do
describe 'associations' do
context 'when name is gitlabUserList' do
it 'is valid when associated with a user list' do
- feature_flag = create(:operations_feature_flag, project: project)
user_list = create(:operations_feature_flag_user_list, project: project)
strategy = described_class.create(feature_flag: feature_flag,
name: 'gitlabUserList',
@@ -232,7 +338,6 @@ RSpec.describe Operations::FeatureFlags::Strategy do
end
it 'is invalid without a user list' do
- feature_flag = create(:operations_feature_flag, project: project)
strategy = described_class.create(feature_flag: feature_flag,
name: 'gitlabUserList',
parameters: {})
@@ -242,7 +347,6 @@ RSpec.describe Operations::FeatureFlags::Strategy do
it 'is invalid when associated with a user list from another project' do
other_project = create(:project)
- feature_flag = create(:operations_feature_flag, project: project)
user_list = create(:operations_feature_flag_user_list, project: other_project)
strategy = described_class.create(feature_flag: feature_flag,
name: 'gitlabUserList',
@@ -255,7 +359,6 @@ RSpec.describe Operations::FeatureFlags::Strategy do
context 'when name is default' do
it 'is invalid when associated with a user list' do
- feature_flag = create(:operations_feature_flag, project: project)
user_list = create(:operations_feature_flag_user_list, project: project)
strategy = described_class.create(feature_flag: feature_flag,
name: 'default',
@@ -266,7 +369,6 @@ RSpec.describe Operations::FeatureFlags::Strategy do
end
it 'is valid without a user list' do
- feature_flag = create(:operations_feature_flag, project: project)
strategy = described_class.create(feature_flag: feature_flag,
name: 'default',
parameters: {})
@@ -277,7 +379,6 @@ RSpec.describe Operations::FeatureFlags::Strategy do
context 'when name is userWithId' do
it 'is invalid when associated with a user list' do
- feature_flag = create(:operations_feature_flag, project: project)
user_list = create(:operations_feature_flag_user_list, project: project)
strategy = described_class.create(feature_flag: feature_flag,
name: 'userWithId',
@@ -288,7 +389,6 @@ RSpec.describe Operations::FeatureFlags::Strategy do
end
it 'is valid without a user list' do
- feature_flag = create(:operations_feature_flag, project: project)
strategy = described_class.create(feature_flag: feature_flag,
name: 'userWithId',
parameters: { userIds: 'user1' })
@@ -299,7 +399,6 @@ RSpec.describe Operations::FeatureFlags::Strategy do
context 'when name is gradualRolloutUserId' do
it 'is invalid when associated with a user list' do
- feature_flag = create(:operations_feature_flag, project: project)
user_list = create(:operations_feature_flag_user_list, project: project)
strategy = described_class.create(feature_flag: feature_flag,
name: 'gradualRolloutUserId',
@@ -310,7 +409,6 @@ RSpec.describe Operations::FeatureFlags::Strategy do
end
it 'is valid without a user list' do
- feature_flag = create(:operations_feature_flag, project: project)
strategy = described_class.create(feature_flag: feature_flag,
name: 'gradualRolloutUserId',
parameters: { groupId: 'default', percentage: '10' })
@@ -318,6 +416,30 @@ RSpec.describe Operations::FeatureFlags::Strategy do
expect(strategy.errors[:user_list]).to be_empty
end
end
+
+ context 'when name is flexibleRollout' do
+ it 'is invalid when associated with a user list' do
+ user_list = create(:operations_feature_flag_user_list, project: project)
+ strategy = described_class.create(feature_flag: feature_flag,
+ name: 'flexibleRollout',
+ user_list: user_list,
+ parameters: { groupId: 'default',
+ rollout: '10',
+ stickiness: 'DEFAULT' })
+
+ expect(strategy.errors[:user_list]).to eq(['must be blank'])
+ end
+
+ it 'is valid without a user list' do
+ strategy = described_class.create(feature_flag: feature_flag,
+ name: 'flexibleRollout',
+ parameters: { groupId: 'default',
+ rollout: '10',
+ stickiness: 'DEFAULT' })
+
+ expect(strategy.errors[:user_list]).to be_empty
+ end
+ end
end
end
end
diff --git a/spec/models/packages/package_spec.rb b/spec/models/packages/package_spec.rb
index ea1f75d04e7..ca408303524 100644
--- a/spec/models/packages/package_spec.rb
+++ b/spec/models/packages/package_spec.rb
@@ -108,6 +108,20 @@ RSpec.describe Packages::Package, type: :model do
it { is_expected.not_to allow_value('.foobar').for(:name) }
it { is_expected.not_to allow_value('%foo%bar').for(:name) }
end
+
+ context 'generic package' do
+ subject { build_stubbed(:generic_package) }
+
+ it { is_expected.to allow_value('123').for(:name) }
+ it { is_expected.to allow_value('foo').for(:name) }
+ it { is_expected.to allow_value('foo.bar.baz-2.0-20190901.47283-1').for(:name) }
+ it { is_expected.not_to allow_value('../../foo').for(:name) }
+ it { is_expected.not_to allow_value('..\..\foo').for(:name) }
+ it { is_expected.not_to allow_value('%2f%2e%2e%2f%2essh%2fauthorized_keys').for(:name) }
+ it { is_expected.not_to allow_value('$foo/bar').for(:name) }
+ it { is_expected.not_to allow_value('my file name').for(:name) }
+ it { is_expected.not_to allow_value('!!().for(:name)().for(:name)').for(:name) }
+ end
end
describe '#version' do
@@ -257,7 +271,12 @@ RSpec.describe Packages::Package, type: :model do
end
it_behaves_like 'validating version to be SemVer compliant for', :npm_package
- it_behaves_like 'validating version to be SemVer compliant for', :nuget_package
+
+ context 'nuget package' do
+ it_behaves_like 'validating version to be SemVer compliant for', :nuget_package
+
+ it { is_expected.to allow_value('1.2.3.4').for(:version) }
+ end
end
describe '#package_already_taken' do
@@ -497,6 +516,14 @@ RSpec.describe Packages::Package, type: :model do
it { is_expected.to match_array([package1, package2]) }
end
+
+ describe '.with_normalized_pypi_name' do
+ let_it_be(:pypi_package) { create(:pypi_package, name: 'Foo.bAr---BAZ_buz') }
+
+ subject { described_class.with_normalized_pypi_name('foo-bar-baz-buz') }
+
+ it { is_expected.to match_array([pypi_package]) }
+ end
end
describe '.select_distinct_name' do
diff --git a/spec/models/pages_deployment_spec.rb b/spec/models/pages_deployment_spec.rb
index eafff1ed59a..5d26ade740e 100644
--- a/spec/models/pages_deployment_spec.rb
+++ b/spec/models/pages_deployment_spec.rb
@@ -18,4 +18,21 @@ RSpec.describe PagesDeployment do
expect(create(:pages_deployment)).to be_valid
end
end
+
+ describe 'default for file_store' do
+ it 'uses local store when object storage is not enabled' do
+ expect(build(:pages_deployment).file_store).to eq(ObjectStorage::Store::LOCAL)
+ end
+
+ it 'uses remote store when object storage is enabled' do
+ stub_pages_object_storage(::Pages::DeploymentUploader)
+
+ expect(build(:pages_deployment).file_store).to eq(ObjectStorage::Store::REMOTE)
+ end
+ end
+
+ it 'saves size along with the file' do
+ deployment = create(:pages_deployment)
+ expect(deployment.size).to eq(deployment.file.size)
+ end
end
diff --git a/spec/models/plan_limits_spec.rb b/spec/models/plan_limits_spec.rb
index bc6398de9a4..67fb11f34e0 100644
--- a/spec/models/plan_limits_spec.rb
+++ b/spec/models/plan_limits_spec.rb
@@ -199,6 +199,7 @@ RSpec.describe PlanLimits do
ci_max_artifact_size_secret_detection
ci_max_artifact_size_requirements
ci_max_artifact_size_coverage_fuzzing
+ ci_max_artifact_size_api_fuzzing
]
end
diff --git a/spec/models/preloaders/merge_request_diff_preloader_spec.rb b/spec/models/preloaders/merge_request_diff_preloader_spec.rb
new file mode 100644
index 00000000000..9a76d42e73f
--- /dev/null
+++ b/spec/models/preloaders/merge_request_diff_preloader_spec.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Preloaders::MergeRequestDiffPreloader do
+ let_it_be(:merge_request_1) { create(:merge_request) }
+ let_it_be(:merge_request_2) { create(:merge_request) }
+ let_it_be(:merge_request_3) { create(:merge_request_without_merge_request_diff) }
+
+ let(:merge_requests) { [merge_request_1, merge_request_2, merge_request_3] }
+
+ def trigger(merge_requests)
+ Array(merge_requests).each(&:merge_request_diff)
+ end
+
+ def merge_requests_with_preloaded_diff
+ described_class.new(MergeRequest.where(id: merge_requests.map(&:id)).to_a).preload_all
+ end
+
+ it 'does not trigger N+1 queries' do
+ # warmup
+ trigger(merge_requests_with_preloaded_diff)
+
+ first_merge_request = merge_requests_with_preloaded_diff.first
+ clean_merge_requests = merge_requests_with_preloaded_diff
+
+ expect { trigger(clean_merge_requests) }.to issue_same_number_of_queries_as { trigger(first_merge_request) }
+ end
+end
diff --git a/spec/models/project_feature_usage_spec.rb b/spec/models/project_feature_usage_spec.rb
index 908b98ee9c2..d55d41fab85 100644
--- a/spec/models/project_feature_usage_spec.rb
+++ b/spec/models/project_feature_usage_spec.rb
@@ -48,7 +48,7 @@ RSpec.describe ProjectFeatureUsage, type: :model do
feature_usage.log_jira_dvcs_integration_usage
first_logged_at = feature_usage.jira_dvcs_cloud_last_sync_at
- Timecop.freeze(1.hour.from_now) do
+ travel_to(1.hour.from_now) do
ProjectFeatureUsage.new(project_id: project.id).log_jira_dvcs_integration_usage
end
diff --git a/spec/models/project_repository_spec.rb b/spec/models/project_repository_spec.rb
index 6852ca0097d..eba908b0fdb 100644
--- a/spec/models/project_repository_spec.rb
+++ b/spec/models/project_repository_spec.rb
@@ -8,6 +8,11 @@ RSpec.describe ProjectRepository do
it { is_expected.to belong_to(:project) }
end
+ it_behaves_like 'shardable scopes' do
+ let_it_be(:record_1) { create(:project_repository) }
+ let_it_be(:record_2, reload: true) { create(:project_repository) }
+ end
+
describe '.find_project' do
it 'finds project by disk path' do
project = create(:project)
diff --git a/spec/models/project_repository_storage_move_spec.rb b/spec/models/project_repository_storage_move_spec.rb
index 3e679c8af4d..d32867efb39 100644
--- a/spec/models/project_repository_storage_move_spec.rb
+++ b/spec/models/project_repository_storage_move_spec.rb
@@ -43,6 +43,18 @@ RSpec.describe ProjectRepositoryStorageMove, type: :model do
end
end
+ describe 'defaults' do
+ context 'destination_storage_name' do
+ subject { build(:project_repository_storage_move) }
+
+ it 'picks storage from ApplicationSetting' do
+ expect(Gitlab::CurrentSettings).to receive(:pick_repository_storage).and_return('picked').at_least(:once)
+
+ expect(subject.destination_storage_name).to eq('picked')
+ end
+ end
+ end
+
describe 'state transitions' do
let(:project) { create(:project) }
diff --git a/spec/models/project_services/chat_message/deployment_message_spec.rb b/spec/models/project_services/chat_message/deployment_message_spec.rb
index 9c361f90ae0..6bdf2120b36 100644
--- a/spec/models/project_services/chat_message/deployment_message_spec.rb
+++ b/spec/models/project_services/chat_message/deployment_message_spec.rb
@@ -70,6 +70,17 @@ RSpec.describe ChatMessage::DeploymentMessage do
expect(message.pretext).to eq('Deploy to staging unknown')
end
+
+ it 'returns a message for a running deployment' do
+ data = {
+ status: 'running',
+ environment: 'production'
+ }
+
+ message = described_class.new(data)
+
+ expect(message.pretext).to eq('Starting deploy to production')
+ end
end
describe '#attachments' do
diff --git a/spec/models/project_services/chat_message/issue_message_spec.rb b/spec/models/project_services/chat_message/issue_message_spec.rb
index 051f4780ba4..4701ef3e49e 100644
--- a/spec/models/project_services/chat_message/issue_message_spec.rb
+++ b/spec/models/project_services/chat_message/issue_message_spec.rb
@@ -44,7 +44,7 @@ RSpec.describe ChatMessage::IssueMessage do
context 'open' do
it 'returns a message regarding opening of issues' do
expect(subject.pretext).to eq(
- '[<http://somewhere.com|project_name>] Issue opened by Test User (test.user)')
+ '[<http://somewhere.com|project_name>] Issue <http://url.com|#100 Issue title> opened by Test User (test.user)')
expect(subject.attachments).to eq([
{
title: "#100 Issue title",
@@ -91,7 +91,7 @@ RSpec.describe ChatMessage::IssueMessage do
context 'open' do
it 'returns a message regarding opening of issues' do
expect(subject.pretext).to eq(
- '[[project_name](http://somewhere.com)] Issue opened by Test User (test.user)')
+ '[[project_name](http://somewhere.com)] Issue [#100 Issue title](http://url.com) opened by Test User (test.user)')
expect(subject.attachments).to eq('issue description')
expect(subject.activity).to eq({
title: 'Issue opened by Test User (test.user)',
diff --git a/spec/models/project_services/prometheus_service_spec.rb b/spec/models/project_services/prometheus_service_spec.rb
index 16837e2b93a..76fc5a826c9 100644
--- a/spec/models/project_services/prometheus_service_spec.rb
+++ b/spec/models/project_services/prometheus_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe PrometheusService, :use_clean_rails_memory_store_caching do
+RSpec.describe PrometheusService, :use_clean_rails_memory_store_caching, :snowplow do
include PrometheusHelpers
include ReactiveCachingHelpers
@@ -421,18 +421,16 @@ RSpec.describe PrometheusService, :use_clean_rails_memory_store_caching do
context "enabling manual_configuration" do
it "tracks enable event" do
service.update!(manual_configuration: false)
-
- expect(Gitlab::Tracking).to receive(:event).with('cluster:services:prometheus', 'enabled_manual_prometheus')
-
service.update!(manual_configuration: true)
+
+ expect_snowplow_event(category: 'cluster:services:prometheus', action: 'enabled_manual_prometheus')
end
it "tracks disable event" do
service.update!(manual_configuration: true)
-
- expect(Gitlab::Tracking).to receive(:event).with('cluster:services:prometheus', 'disabled_manual_prometheus')
-
service.update!(manual_configuration: false)
+
+ expect_snowplow_event(category: 'cluster:services:prometheus', action: 'disabled_manual_prometheus')
end
end
end
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index fe971832695..53a213891e9 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -72,6 +72,7 @@ RSpec.describe Project do
it { is_expected.to have_one(:last_event).class_name('Event') }
it { is_expected.to have_one(:forked_from_project).through(:fork_network_member) }
it { is_expected.to have_one(:auto_devops).class_name('ProjectAutoDevops') }
+ it { is_expected.to have_one(:tracing_setting).class_name('ProjectTracingSetting') }
it { is_expected.to have_one(:error_tracking_setting).class_name('ErrorTracking::ProjectErrorTrackingSetting') }
it { is_expected.to have_one(:project_setting) }
it { is_expected.to have_one(:alerting_setting).class_name('Alerting::ProjectAlertingSetting') }
@@ -116,6 +117,7 @@ RSpec.describe Project do
it { is_expected.to have_many(:prometheus_alert_events) }
it { is_expected.to have_many(:self_managed_prometheus_alert_events) }
it { is_expected.to have_many(:alert_management_alerts) }
+ it { is_expected.to have_many(:alert_management_http_integrations) }
it { is_expected.to have_many(:jira_imports) }
it { is_expected.to have_many(:metrics_users_starred_dashboards).inverse_of(:project) }
it { is_expected.to have_many(:repository_storage_moves) }
@@ -123,6 +125,7 @@ RSpec.describe Project do
it { is_expected.to have_many(:packages).class_name('Packages::Package') }
it { is_expected.to have_many(:package_files).class_name('Packages::PackageFile') }
it { is_expected.to have_many(:pipeline_artifacts) }
+ it { is_expected.to have_many(:terraform_states).class_name('Terraform::State').inverse_of(:project) }
# GitLab Pages
it { is_expected.to have_many(:pages_domains) }
@@ -133,6 +136,7 @@ RSpec.describe Project do
let_it_be(:container) { create(:project, :repository, path: 'somewhere') }
let(:stubbed_container) { build_stubbed(:project) }
let(:expected_full_path) { "#{container.namespace.full_path}/somewhere" }
+ let(:expected_lfs_enabled) { true }
end
it_behaves_like 'model with wiki' do
@@ -4329,7 +4333,7 @@ RSpec.describe Project do
end
it 'schedules HashedStorage::ProjectMigrateWorker with delayed start when the wiki repo is in use' do
- Gitlab::ReferenceCounter.new(Gitlab::GlRepository::WIKI.identifier_for_container(project)).increase
+ Gitlab::ReferenceCounter.new(Gitlab::GlRepository::WIKI.identifier_for_container(project.wiki)).increase
expect(HashedStorage::ProjectMigrateWorker).to receive(:perform_in)
@@ -4975,15 +4979,21 @@ RSpec.describe Project do
context "with an empty repository" do
let_it_be(:project) { create(:project_empty_repo) }
- context "Gitlab::CurrentSettings.default_branch_name is unavailable" do
+ context "group.default_branch_name is available" do
+ let(:project_group) { create(:group) }
+ let(:project) { create(:project, path: 'avatar', namespace: project_group) }
+
before do
expect(Gitlab::CurrentSettings)
+ .not_to receive(:default_branch_name)
+
+ expect(project.group)
.to receive(:default_branch_name)
- .and_return(nil)
+ .and_return('example_branch')
end
- it "returns that value" do
- expect(project.default_branch).to be_nil
+ it "returns the group default value" do
+ expect(project.default_branch).to eq("example_branch")
end
end
@@ -4991,11 +5001,23 @@ RSpec.describe Project do
before do
expect(Gitlab::CurrentSettings)
.to receive(:default_branch_name)
- .and_return('example_branch')
+ .and_return(example_branch_name)
end
- it "returns that value" do
- expect(project.default_branch).to eq("example_branch")
+ context "is missing or nil" do
+ let(:example_branch_name) { nil }
+
+ it "returns nil" do
+ expect(project.default_branch).to be_nil
+ end
+ end
+
+ context "is present" do
+ let(:example_branch_name) { "example_branch_name" }
+
+ it "returns the expected branch name" do
+ expect(project.default_branch).to eq(example_branch_name)
+ end
end
end
end
@@ -5487,12 +5509,13 @@ RSpec.describe Project do
describe '#find_or_initialize_services' do
it 'returns only enabled services' do
allow(Service).to receive(:available_services_names).and_return(%w[prometheus pushover teamcity])
+ allow(Service).to receive(:project_specific_services_names).and_return(%w[asana])
allow(subject).to receive(:disabled_services).and_return(%w[prometheus])
services = subject.find_or_initialize_services
- expect(services.count).to eq(2)
- expect(services.map(&:title)).to eq(['JetBrains TeamCity CI', 'Pushover'])
+ expect(services.count).to eq(3)
+ expect(services.map(&:title)).to eq(['Asana', 'JetBrains TeamCity CI', 'Pushover'])
end
end
@@ -5563,32 +5586,6 @@ RSpec.describe Project do
end
end
- describe '.for_repository_storage' do
- it 'returns the projects for a given repository storage' do
- stub_storage_settings('test_second_storage' => {
- 'path' => TestEnv::SECOND_STORAGE_PATH,
- 'gitaly_address' => Gitlab.config.repositories.storages.default.gitaly_address
- })
- expected_project = create(:project, repository_storage: 'default')
- create(:project, repository_storage: 'test_second_storage')
-
- expect(described_class.for_repository_storage('default')).to eq([expected_project])
- end
- end
-
- describe '.excluding_repository_storage' do
- it 'returns the projects excluding the given repository storage' do
- stub_storage_settings('test_second_storage' => {
- 'path' => TestEnv::SECOND_STORAGE_PATH,
- 'gitaly_address' => Gitlab.config.repositories.storages.default.gitaly_address
- })
- expected_project = create(:project, repository_storage: 'test_second_storage')
- create(:project, repository_storage: 'default')
-
- expect(described_class.excluding_repository_storage('default')).to eq([expected_project])
- end
- end
-
describe '.deployments' do
subject { project.deployments }
@@ -5812,6 +5809,38 @@ RSpec.describe Project do
end
end
+ describe 'validation #changing_shared_runners_enabled_is_allowed' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:shared_runners_setting, :project_shared_runners_enabled, :valid_record) do
+ 'enabled' | true | true
+ 'enabled' | false | true
+ 'disabled_with_override' | true | true
+ 'disabled_with_override' | false | true
+ 'disabled_and_unoverridable' | true | false
+ 'disabled_and_unoverridable' | false | true
+ end
+
+ with_them do
+ let(:group) { create(:group) }
+ let(:project) { build(:project, namespace: group, shared_runners_enabled: project_shared_runners_enabled) }
+
+ before do
+ allow_next_found_instance_of(Group) do |group|
+ allow(group).to receive(:shared_runners_setting).and_return(shared_runners_setting)
+ end
+ end
+
+ it 'validates the configuration' do
+ expect(project.valid?).to eq(valid_record)
+
+ unless valid_record
+ expect(project.errors[:shared_runners_enabled]).to contain_exactly('cannot be enabled because parent group does not allow it')
+ end
+ end
+ end
+ end
+
describe '#mark_pages_as_deployed' do
let(:project) { create(:project) }
let(:artifacts_archive) { create(:ci_job_artifact, project: project) }
diff --git a/spec/models/project_statistics_spec.rb b/spec/models/project_statistics_spec.rb
index 383fabcfffb..9f40dbb3401 100644
--- a/spec/models/project_statistics_spec.rb
+++ b/spec/models/project_statistics_spec.rb
@@ -201,6 +201,23 @@ RSpec.describe ProjectStatistics do
statistics.refresh!(only: [:commit_count])
end
end
+
+ context 'when the database is read-only' do
+ it 'does nothing' do
+ allow(Gitlab::Database).to receive(:read_only?) { true }
+
+ expect(statistics).not_to receive(:update_commit_count)
+ expect(statistics).not_to receive(:update_repository_size)
+ expect(statistics).not_to receive(:update_wiki_size)
+ expect(statistics).not_to receive(:update_lfs_objects_size)
+ expect(statistics).not_to receive(:update_snippets_size)
+ expect(statistics).not_to receive(:save!)
+ expect(Namespaces::ScheduleAggregationWorker)
+ .not_to receive(:perform_async)
+
+ statistics.refresh!
+ end
+ end
end
describe '#update_commit_count' do
@@ -324,22 +341,51 @@ RSpec.describe ProjectStatistics do
describe '.increment_statistic' do
shared_examples 'a statistic that increases storage_size' do
it 'increases the statistic by that amount' do
- expect { described_class.increment_statistic(project.id, stat, 13) }
+ expect { described_class.increment_statistic(project, stat, 13) }
.to change { statistics.reload.send(stat) || 0 }
.by(13)
end
it 'increases also storage size by that amount' do
- expect { described_class.increment_statistic(project.id, stat, 20) }
+ expect { described_class.increment_statistic(project, stat, 20) }
.to change { statistics.reload.storage_size }
.by(20)
end
end
+ shared_examples 'a statistic that increases storage_size asynchronously' do
+ it 'stores the increment temporarily in Redis', :clean_gitlab_redis_shared_state do
+ described_class.increment_statistic(project, stat, 13)
+
+ Gitlab::Redis::SharedState.with do |redis|
+ increment = redis.get(statistics.counter_key(stat))
+ expect(increment.to_i).to eq(13)
+ end
+ end
+
+ it 'schedules a worker to update the statistic and storage_size async' do
+ expect(FlushCounterIncrementsWorker)
+ .to receive(:perform_in)
+ .with(CounterAttribute::WORKER_DELAY, described_class.name, statistics.id, stat)
+
+ expect(FlushCounterIncrementsWorker)
+ .to receive(:perform_in)
+ .with(CounterAttribute::WORKER_DELAY, described_class.name, statistics.id, :storage_size)
+
+ described_class.increment_statistic(project, stat, 20)
+ end
+ end
+
context 'when adjusting :build_artifacts_size' do
let(:stat) { :build_artifacts_size }
- it_behaves_like 'a statistic that increases storage_size'
+ it_behaves_like 'a statistic that increases storage_size asynchronously'
+
+ it_behaves_like 'a statistic that increases storage_size' do
+ before do
+ stub_feature_flags(efficient_counter_attribute: false)
+ end
+ end
end
context 'when adjusting :pipeline_artifacts_size' do
diff --git a/spec/models/project_tracing_setting_spec.rb b/spec/models/project_tracing_setting_spec.rb
new file mode 100644
index 00000000000..a7e4e557b25
--- /dev/null
+++ b/spec/models/project_tracing_setting_spec.rb
@@ -0,0 +1,40 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe ProjectTracingSetting do
+ describe '#external_url' do
+ let_it_be(:project) { create(:project) }
+
+ let(:tracing_setting) { project.build_tracing_setting }
+
+ describe 'Validations' do
+ describe 'external_url' do
+ it 'accepts a valid url' do
+ tracing_setting.external_url = 'https://gitlab.com'
+
+ expect(tracing_setting).to be_valid
+ end
+
+ it 'fails with an invalid url' do
+ tracing_setting.external_url = 'gitlab.com'
+
+ expect(tracing_setting).to be_invalid
+ end
+
+ it 'fails with a blank string' do
+ tracing_setting.external_url = nil
+
+ expect(tracing_setting).to be_invalid
+ end
+
+ it 'sanitizes the url' do
+ tracing_setting.external_url = %{https://replaceme.com/'><script>alert(document.cookie)</script>}
+
+ expect(tracing_setting).to be_valid
+ expect(tracing_setting.external_url).to eq(%{https://replaceme.com/'&gt;})
+ end
+ end
+ end
+ end
+end
diff --git a/spec/models/project_wiki_spec.rb b/spec/models/project_wiki_spec.rb
index 29c3d0e1a73..2e82fcf5511 100644
--- a/spec/models/project_wiki_spec.rb
+++ b/spec/models/project_wiki_spec.rb
@@ -6,6 +6,7 @@ RSpec.describe ProjectWiki do
it_behaves_like 'wiki model' do
let(:wiki_container) { create(:project, :wiki_repo, namespace: user.namespace) }
let(:wiki_container_without_repo) { create(:project, namespace: user.namespace) }
+ let(:wiki_lfs_enabled) { true }
it { is_expected.to delegate_method(:storage).to(:container) }
it { is_expected.to delegate_method(:repository_storage).to(:container) }
diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb
index a3042d619eb..31211f8ff2c 100644
--- a/spec/models/repository_spec.rb
+++ b/spec/models/repository_spec.rb
@@ -2688,7 +2688,7 @@ RSpec.describe Repository do
expect(subject).to be_a(Gitlab::Git::Repository)
expect(subject.relative_path).to eq(project.disk_path + '.wiki.git')
expect(subject.gl_repository).to eq("wiki-#{project.id}")
- expect(subject.gl_project_path).to eq(project.full_path)
+ expect(subject.gl_project_path).to eq(project.wiki.full_path)
end
end
end
@@ -2941,12 +2941,19 @@ RSpec.describe Repository do
expect(snippet.repository.project).to be_nil
end
+ it 'returns the project for a project wiki' do
+ wiki = create(:project_wiki)
+
+ expect(wiki.project).to be(wiki.repository.project)
+ end
+
it 'returns the container if it is a project' do
expect(repository.project).to be(project)
end
it 'returns nil if the container is not a project' do
- expect(repository).to receive(:container).and_return(Group.new)
+ repository.container = Group.new
+
expect(repository.project).to be_nil
end
end
@@ -2981,17 +2988,11 @@ RSpec.describe Repository do
context 'for a project wiki repository' do
let(:repository) { project.wiki.repository }
- it 'returns true when LFS is enabled' do
- stub_lfs_setting(enabled: true)
+ it 'delegates to the project' do
+ expect(project).to receive(:lfs_enabled?).and_return(true)
is_expected.to be_truthy
end
-
- it 'returns false when LFS is disabled' do
- stub_lfs_setting(enabled: false)
-
- is_expected.to be_falsy
- end
end
context 'for a project snippet repository' do
diff --git a/spec/models/resource_label_event_spec.rb b/spec/models/resource_label_event_spec.rb
index 960db31d488..da1fe70c891 100644
--- a/spec/models/resource_label_event_spec.rb
+++ b/spec/models/resource_label_event_spec.rb
@@ -50,26 +50,36 @@ RSpec.describe ResourceLabelEvent, type: :model do
end
end
- describe '#expire_etag_cache' do
- def expect_expiration(issue)
- expect_next_instance_of(Gitlab::EtagCaching::Store) do |instance|
- expect(instance).to receive(:touch)
- .with("/#{issue.project.namespace.to_param}/#{issue.project.to_param}/noteable/issue/#{issue.id}/notes")
+ context 'callbacks' do
+ describe '#usage_metrics' do
+ it 'tracks changed labels' do
+ expect(Gitlab::UsageDataCounters::IssueActivityUniqueCounter).to receive(:track_issue_label_changed_action)
+
+ subject.save!
end
end
- it 'expires resource note etag cache on event save' do
- expect_expiration(subject.issuable)
+ describe '#expire_etag_cache' do
+ def expect_expiration(issue)
+ expect_next_instance_of(Gitlab::EtagCaching::Store) do |instance|
+ expect(instance).to receive(:touch)
+ .with("/#{issue.project.namespace.to_param}/#{issue.project.to_param}/noteable/issue/#{issue.id}/notes")
+ end
+ end
- subject.save!
- end
+ it 'expires resource note etag cache on event save' do
+ expect_expiration(subject.issuable)
- it 'expires resource note etag cache on event destroy' do
- subject.save!
+ subject.save!
+ end
+
+ it 'expires resource note etag cache on event destroy' do
+ subject.save!
- expect_expiration(subject.issuable)
+ expect_expiration(subject.issuable)
- subject.destroy!
+ subject.destroy!
+ end
end
end
diff --git a/spec/models/resource_milestone_event_spec.rb b/spec/models/resource_milestone_event_spec.rb
index 0a5292b2d16..c1761e5b2e8 100644
--- a/spec/models/resource_milestone_event_spec.rb
+++ b/spec/models/resource_milestone_event_spec.rb
@@ -11,6 +11,7 @@ RSpec.describe ResourceMilestoneEvent, type: :model do
it_behaves_like 'timebox resource event validations'
it_behaves_like 'timebox resource event states'
it_behaves_like 'timebox resource event actions'
+ it_behaves_like 'timebox resource tracks issue metrics', :milestone
describe 'associations' do
it { is_expected.to belong_to(:milestone) }
diff --git a/spec/models/resource_state_event_spec.rb b/spec/models/resource_state_event_spec.rb
index fc6575b2db8..b8a93bdbe3b 100644
--- a/spec/models/resource_state_event_spec.rb
+++ b/spec/models/resource_state_event_spec.rb
@@ -39,4 +39,20 @@ RSpec.describe ResourceStateEvent, type: :model do
end
end
end
+
+ context 'callbacks' do
+ describe '#usage_metrics' do
+ it 'tracks closed issues' do
+ expect(Gitlab::UsageDataCounters::IssueActivityUniqueCounter).to receive(:track_issue_closed_action)
+
+ create(described_class.name.underscore.to_sym, issue: issue, state: described_class.states[:closed])
+ end
+
+ it 'tracks reopened issues' do
+ expect(Gitlab::UsageDataCounters::IssueActivityUniqueCounter).to receive(:track_issue_reopened_action)
+
+ create(described_class.name.underscore.to_sym, issue: issue, state: described_class.states[:reopened])
+ end
+ end
+ end
end
diff --git a/spec/models/resource_weight_event_spec.rb b/spec/models/resource_weight_event_spec.rb
deleted file mode 100644
index 8a37883d933..00000000000
--- a/spec/models/resource_weight_event_spec.rb
+++ /dev/null
@@ -1,76 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe ResourceWeightEvent, type: :model do
- it_behaves_like 'a resource event'
- it_behaves_like 'a resource event for issues'
-
- let_it_be(:user1) { create(:user) }
- let_it_be(:user2) { create(:user) }
-
- let_it_be(:issue1) { create(:issue, author: user1) }
- let_it_be(:issue2) { create(:issue, author: user1) }
- let_it_be(:issue3) { create(:issue, author: user2) }
-
- describe 'validations' do
- it { is_expected.not_to allow_value(nil).for(:issue) }
- it { is_expected.to allow_value(nil).for(:weight) }
- end
-
- describe 'associations' do
- it { is_expected.to belong_to(:issue) }
- end
-
- describe '.by_issue' do
- let_it_be(:event1) { create(:resource_weight_event, issue: issue1) }
- let_it_be(:event2) { create(:resource_weight_event, issue: issue2) }
- let_it_be(:event3) { create(:resource_weight_event, issue: issue1) }
-
- it 'returns the expected records for an issue with events' do
- events = ResourceWeightEvent.by_issue(issue1)
-
- expect(events).to contain_exactly(event1, event3)
- end
-
- it 'returns the expected records for an issue with no events' do
- events = ResourceWeightEvent.by_issue(issue3)
-
- expect(events).to be_empty
- end
- end
-
- describe '.created_after' do
- let!(:created_at1) { 1.day.ago }
- let!(:created_at2) { 2.days.ago }
- let!(:created_at3) { 3.days.ago }
-
- let!(:event1) { create(:resource_weight_event, issue: issue1, created_at: created_at1) }
- let!(:event2) { create(:resource_weight_event, issue: issue2, created_at: created_at2) }
- let!(:event3) { create(:resource_weight_event, issue: issue2, created_at: created_at3) }
-
- it 'returns the expected events' do
- events = ResourceWeightEvent.created_after(created_at3)
-
- expect(events).to contain_exactly(event1, event2)
- end
-
- it 'returns no events if time is after last record time' do
- events = ResourceWeightEvent.created_after(1.minute.ago)
-
- expect(events).to be_empty
- end
- end
-
- describe '#discussion_id' do
- let_it_be(:event) { create(:resource_weight_event, issue: issue1, created_at: Time.utc(2019, 12, 30)) }
-
- it 'returns the expected id' do
- allow(Digest::SHA1).to receive(:hexdigest)
- .with("ResourceWeightEvent-#{event.id}-#{user1.id}")
- .and_return('73d167c478')
-
- expect(event.discussion_id).to eq('73d167c478')
- end
- end
-end
diff --git a/spec/models/service_spec.rb b/spec/models/service_spec.rb
index 32e2012e284..db3cf19a03f 100644
--- a/spec/models/service_spec.rb
+++ b/spec/models/service_spec.rb
@@ -320,18 +320,28 @@ RSpec.describe Service do
end
it 'sets service to inactive' do
- service = described_class.build_from_integration(project.id, integration)
+ service = described_class.build_from_integration(integration, project_id: project.id)
expect(service).to be_valid
expect(service.active).to be false
end
end
- context 'when integration is an instance' do
+ context 'when integration is an instance-level integration' do
let(:integration) { create(:jira_service, :instance) }
it 'sets inherit_from_id from integration' do
- service = described_class.build_from_integration(project.id, integration)
+ service = described_class.build_from_integration(integration, project_id: project.id)
+
+ expect(service.inherit_from_id).to eq(integration.id)
+ end
+ end
+
+ context 'when integration is a group-level integration' do
+ let(:integration) { create(:jira_service, group: group, project: nil) }
+
+ it 'sets inherit_from_id from integration' do
+ service = described_class.build_from_integration(integration, project_id: project.id)
expect(service.inherit_from_id).to eq(integration.id)
end
@@ -350,8 +360,8 @@ RSpec.describe Service do
end
shared_examples 'service creation from an integration' do
- it 'creates a correct service' do
- service = described_class.build_from_integration(project.id, integration)
+ it 'creates a correct service for a project integration' do
+ service = described_class.build_from_integration(integration, project_id: project.id)
expect(service).to be_active
expect(service.url).to eq(url)
@@ -360,6 +370,22 @@ RSpec.describe Service do
expect(service.password).to eq(password)
expect(service.template).to eq(false)
expect(service.instance).to eq(false)
+ expect(service.project).to eq(project)
+ expect(service.group).to eq(nil)
+ end
+
+ it 'creates a correct service for a group integration' do
+ service = described_class.build_from_integration(integration, group_id: group.id)
+
+ expect(service).to be_active
+ expect(service.url).to eq(url)
+ expect(service.api_url).to eq(api_url)
+ expect(service.username).to eq(username)
+ expect(service.password).to eq(password)
+ expect(service.template).to eq(false)
+ expect(service.instance).to eq(false)
+ expect(service.project).to eq(nil)
+ expect(service.group).to eq(group)
end
end
@@ -455,13 +481,119 @@ RSpec.describe Service do
expect(described_class.default_integration('JiraService', subgroup)).to eq(group_service)
end
- context 'having a service' do
+ context 'having a service with custom settings' do
let!(:subgroup_service) { create(:jira_service, group_id: subgroup.id, project_id: nil) }
it 'returns the closest group service for a project' do
expect(described_class.default_integration('JiraService', project)).to eq(subgroup_service)
end
end
+
+ context 'having a service inheriting settings' do
+ let!(:subgroup_service) { create(:jira_service, group_id: subgroup.id, project_id: nil, inherit_from_id: group_service.id) }
+
+ it 'returns the closest group service which does not inherit from its parent for a project' do
+ expect(described_class.default_integration('JiraService', project)).to eq(group_service)
+ end
+ end
+ end
+ end
+ end
+ end
+
+ describe '.create_from_active_default_integrations' do
+ context 'with an active service template' do
+ let_it_be(:template_integration) { create(:prometheus_service, :template, api_url: 'https://prometheus.template.com/') }
+
+ it 'creates a service from the template' do
+ described_class.create_from_active_default_integrations(project, :project_id, with_templates: true)
+
+ expect(project.reload.services.size).to eq(1)
+ expect(project.reload.services.first.api_url).to eq(template_integration.api_url)
+ expect(project.reload.services.first.inherit_from_id).to be_nil
+ end
+
+ context 'with an active instance-level integration' do
+ let!(:instance_integration) { create(:prometheus_service, :instance, api_url: 'https://prometheus.instance.com/') }
+
+ it 'creates a service from the instance-level integration' do
+ described_class.create_from_active_default_integrations(project, :project_id, with_templates: true)
+
+ expect(project.reload.services.size).to eq(1)
+ expect(project.reload.services.first.api_url).to eq(instance_integration.api_url)
+ expect(project.reload.services.first.inherit_from_id).to eq(instance_integration.id)
+ end
+
+ context 'passing a group' do
+ it 'creates a service from the instance-level integration' do
+ described_class.create_from_active_default_integrations(group, :group_id)
+
+ expect(group.reload.services.size).to eq(1)
+ expect(group.reload.services.first.api_url).to eq(instance_integration.api_url)
+ expect(group.reload.services.first.inherit_from_id).to eq(instance_integration.id)
+ end
+ end
+
+ context 'with an active group-level integration' do
+ let!(:group_integration) { create(:prometheus_service, group: group, project: nil, api_url: 'https://prometheus.group.com/') }
+
+ it 'creates a service from the group-level integration' do
+ described_class.create_from_active_default_integrations(project, :project_id, with_templates: true)
+
+ expect(project.reload.services.size).to eq(1)
+ expect(project.reload.services.first.api_url).to eq(group_integration.api_url)
+ expect(project.reload.services.first.inherit_from_id).to eq(group_integration.id)
+ end
+
+ context 'passing a group' do
+ let!(:subgroup) { create(:group, parent: group) }
+
+ it 'creates a service from the group-level integration' do
+ described_class.create_from_active_default_integrations(subgroup, :group_id)
+
+ expect(subgroup.reload.services.size).to eq(1)
+ expect(subgroup.reload.services.first.api_url).to eq(group_integration.api_url)
+ expect(subgroup.reload.services.first.inherit_from_id).to eq(group_integration.id)
+ end
+ end
+
+ context 'with an active subgroup' do
+ let!(:subgroup_integration) { create(:prometheus_service, group: subgroup, project: nil, api_url: 'https://prometheus.subgroup.com/') }
+ let!(:subgroup) { create(:group, parent: group) }
+ let(:project) { create(:project, group: subgroup) }
+
+ it 'creates a service from the subgroup-level integration' do
+ described_class.create_from_active_default_integrations(project, :project_id, with_templates: true)
+
+ expect(project.reload.services.size).to eq(1)
+ expect(project.reload.services.first.api_url).to eq(subgroup_integration.api_url)
+ expect(project.reload.services.first.inherit_from_id).to eq(subgroup_integration.id)
+ end
+
+ context 'passing a group' do
+ let!(:sub_subgroup) { create(:group, parent: subgroup) }
+
+ it 'creates a service from the subgroup-level integration' do
+ described_class.create_from_active_default_integrations(sub_subgroup, :group_id)
+
+ expect(sub_subgroup.reload.services.size).to eq(1)
+ expect(sub_subgroup.reload.services.first.api_url).to eq(subgroup_integration.api_url)
+ expect(sub_subgroup.reload.services.first.inherit_from_id).to eq(subgroup_integration.id)
+ end
+
+ context 'having a service inheriting settings' do
+ let!(:subgroup_integration) { create(:prometheus_service, group: subgroup, project: nil, inherit_from_id: group_integration.id, api_url: 'https://prometheus.subgroup.com/') }
+
+ it 'creates a service from the group-level integration' do
+ described_class.create_from_active_default_integrations(sub_subgroup, :group_id)
+
+ expect(sub_subgroup.reload.services.size).to eq(1)
+ expect(sub_subgroup.reload.services.first.api_url).to eq(group_integration.api_url)
+ expect(sub_subgroup.reload.services.first.inherit_from_id).to eq(group_integration.id)
+ end
+ end
+ end
+ end
end
end
end
diff --git a/spec/models/snippet_input_action_spec.rb b/spec/models/snippet_input_action_spec.rb
index 43dc70bea98..0a9ab47f2f0 100644
--- a/spec/models/snippet_input_action_spec.rb
+++ b/spec/models/snippet_input_action_spec.rb
@@ -67,7 +67,7 @@ RSpec.describe SnippetInputAction do
let(:options) { { action: action, file_path: file_path, content: content, previous_path: previous_path } }
let(:expected_options) { options.merge(action: action.to_sym) }
- subject { described_class.new(options).to_commit_action }
+ subject { described_class.new(**options).to_commit_action }
it 'transforms attributes to commit action' do
expect(subject).to eq(expected_options)
diff --git a/spec/models/snippet_repository_spec.rb b/spec/models/snippet_repository_spec.rb
index 95602a4de0e..cdbc1feefce 100644
--- a/spec/models/snippet_repository_spec.rb
+++ b/spec/models/snippet_repository_spec.rb
@@ -13,6 +13,11 @@ RSpec.describe SnippetRepository do
it { is_expected.to belong_to(:snippet) }
end
+ it_behaves_like 'shardable scopes' do
+ let_it_be(:record_1) { create(:snippet_repository) }
+ let_it_be(:record_2, reload: true) { create(:snippet_repository) }
+ end
+
describe '.find_snippet' do
it 'finds snippet by disk path' do
snippet = create(:snippet, author: user)
@@ -35,7 +40,7 @@ RSpec.describe SnippetRepository do
it 'returns nil when files argument is empty' do
expect(snippet.repository).not_to receive(:multi_action)
- operation = snippet_repository.multi_files_action(user, [], commit_opts)
+ operation = snippet_repository.multi_files_action(user, [], **commit_opts)
expect(operation).to be_nil
end
@@ -43,7 +48,7 @@ RSpec.describe SnippetRepository do
it 'returns nil when files argument is nil' do
expect(snippet.repository).not_to receive(:multi_action)
- operation = snippet_repository.multi_files_action(user, nil, commit_opts)
+ operation = snippet_repository.multi_files_action(user, nil, **commit_opts)
expect(operation).to be_nil
end
@@ -60,7 +65,7 @@ RSpec.describe SnippetRepository do
end
expect do
- snippet_repository.multi_files_action(user, data, commit_opts)
+ snippet_repository.multi_files_action(user, data, **commit_opts)
end.not_to raise_error
aggregate_failures do
@@ -77,13 +82,13 @@ RSpec.describe SnippetRepository do
it 'tries to obtain an exclusive lease' do
expect(Gitlab::ExclusiveLease).to receive(:new).with("multi_files_action:#{snippet.id}", anything).and_call_original
- snippet_repository.multi_files_action(user, data, commit_opts)
+ snippet_repository.multi_files_action(user, data, **commit_opts)
end
it 'cancels the lease when the method has finished' do
expect(Gitlab::ExclusiveLease).to receive(:cancel).with("multi_files_action:#{snippet.id}", anything).and_call_original
- snippet_repository.multi_files_action(user, data, commit_opts)
+ snippet_repository.multi_files_action(user, data, **commit_opts)
end
it 'raises an error if the lease cannot be obtained' do
@@ -92,7 +97,7 @@ RSpec.describe SnippetRepository do
end
expect do
- snippet_repository.multi_files_action(user, data, commit_opts)
+ snippet_repository.multi_files_action(user, data, **commit_opts)
end.to raise_error(described_class::CommitError)
end
@@ -114,7 +119,7 @@ RSpec.describe SnippetRepository do
it 'infers the commit action based on the parameters if not present' do
expect(repo).to receive(:multi_action).with(user, hash_including(actions: result))
- snippet_repository.multi_files_action(user, data, commit_opts)
+ snippet_repository.multi_files_action(user, data, **commit_opts)
end
context 'when commit actions are present' do
@@ -128,7 +133,7 @@ RSpec.describe SnippetRepository do
user,
hash_including(actions: array_including(hash_including(action: expected_action)))))
- snippet_repository.multi_files_action(user, data, commit_opts)
+ snippet_repository.multi_files_action(user, data, **commit_opts)
end
end
@@ -149,7 +154,7 @@ RSpec.describe SnippetRepository do
specify do
existing_content = blob_at(snippet, previous_path).data
- snippet_repository.multi_files_action(user, [move_action], commit_opts)
+ snippet_repository.multi_files_action(user, [move_action], **commit_opts)
blob = blob_at(snippet, new_path)
expect(blob).not_to be_nil
@@ -177,7 +182,7 @@ RSpec.describe SnippetRepository do
specify do
last_commit_id = snippet.repository.head_commit.id
- snippet_repository.multi_files_action(user, [update_action], commit_opts)
+ snippet_repository.multi_files_action(user, [update_action], **commit_opts)
expect(snippet.repository.head_commit.id).to eq last_commit_id
end
@@ -214,13 +219,13 @@ RSpec.describe SnippetRepository do
before do
expect(blob_at(snippet, default_name)).to be_nil
- snippet_repository.multi_files_action(user, [new_file], commit_opts)
+ snippet_repository.multi_files_action(user, [new_file], **commit_opts)
expect(blob_at(snippet, default_name)).to be
end
it 'reuses the existing file name' do
- snippet_repository.multi_files_action(user, [existing_file], commit_opts)
+ snippet_repository.multi_files_action(user, [existing_file], **commit_opts)
blob = blob_at(snippet, default_name)
expect(blob.data).to eq existing_file[:content]
@@ -234,7 +239,7 @@ RSpec.describe SnippetRepository do
it 'assigns a new name to the file' do
expect(blob_at(snippet, default_name)).to be_nil
- snippet_repository.multi_files_action(user, [new_file], commit_opts)
+ snippet_repository.multi_files_action(user, [new_file], **commit_opts)
blob = blob_at(snippet, default_name)
expect(blob.data).to eq new_file[:content]
@@ -246,7 +251,7 @@ RSpec.describe SnippetRepository do
before do
expect do
- snippet_repository.multi_files_action(user, data, commit_opts)
+ snippet_repository.multi_files_action(user, data, **commit_opts)
end.not_to raise_error
end
@@ -259,10 +264,10 @@ RSpec.describe SnippetRepository do
before do
# Pre-populate repository with 9 unnamed snippets.
- snippet_repository.multi_files_action(user, pre_populate_data, commit_opts)
+ snippet_repository.multi_files_action(user, pre_populate_data, **commit_opts)
expect do
- snippet_repository.multi_files_action(user, data, commit_opts)
+ snippet_repository.multi_files_action(user, data, **commit_opts)
end.not_to raise_error
end
@@ -274,7 +279,7 @@ RSpec.describe SnippetRepository do
it 'raises a path specific error' do
expect do
- snippet_repository.multi_files_action(user, data, commit_opts)
+ snippet_repository.multi_files_action(user, data, **commit_opts)
end.to raise_error(error)
end
end
diff --git a/spec/models/snippet_spec.rb b/spec/models/snippet_spec.rb
index ab614a6d45c..d74f5faab7f 100644
--- a/spec/models/snippet_spec.rb
+++ b/spec/models/snippet_spec.rb
@@ -666,16 +666,13 @@ RSpec.describe Snippet do
let(:checker) { subject.repository_size_checker }
let(:current_size) { 60 }
+ let(:namespace) { nil }
before do
allow(subject.repository).to receive(:size).and_return(current_size)
end
- it 'sets up size checker', :aggregate_failures do
- expect(checker.current_size).to eq(current_size.megabytes)
- expect(checker.limit).to eq(Gitlab::CurrentSettings.snippet_size_limit)
- expect(checker.enabled?).to be_truthy
- end
+ include_examples 'size checker for snippet'
end
describe '#can_cache_field?' do
@@ -717,19 +714,11 @@ RSpec.describe Snippet do
end
describe '.max_file_limit' do
- subject { described_class.max_file_limit(nil) }
+ subject { described_class.max_file_limit }
it "returns #{Snippet::MAX_FILE_COUNT}" do
expect(subject).to eq Snippet::MAX_FILE_COUNT
end
-
- context 'when feature flag :snippet_multiple_files is disabled' do
- it "returns #{described_class::MAX_SINGLE_FILE_COUNT}" do
- stub_feature_flags(snippet_multiple_files: false)
-
- expect(subject).to eq described_class::MAX_SINGLE_FILE_COUNT
- end
- end
end
describe '#list_files' do
diff --git a/spec/models/snippet_statistics_spec.rb b/spec/models/snippet_statistics_spec.rb
index 8def6a0bbd4..1fb4ed47169 100644
--- a/spec/models/snippet_statistics_spec.rb
+++ b/spec/models/snippet_statistics_spec.rb
@@ -75,15 +75,28 @@ RSpec.describe SnippetStatistics do
end
describe '#refresh!' do
- subject { statistics.refresh! }
-
it 'retrieves and saves statistic data from repository' do
expect(statistics).to receive(:update_commit_count)
expect(statistics).to receive(:update_file_count)
expect(statistics).to receive(:update_repository_size)
expect(statistics).to receive(:save!)
- subject
+ statistics.refresh!
+ end
+
+ context 'when the database is read-only' do
+ it 'does nothing' do
+ allow(Gitlab::Database).to receive(:read_only?) { true }
+
+ expect(statistics).not_to receive(:update_commit_count)
+ expect(statistics).not_to receive(:update_file_count)
+ expect(statistics).not_to receive(:update_repository_size)
+ expect(statistics).not_to receive(:save!)
+ expect(Namespaces::ScheduleAggregationWorker)
+ .not_to receive(:perform_async)
+
+ statistics.refresh!
+ end
end
end
diff --git a/spec/models/terraform/state_spec.rb b/spec/models/terraform/state_spec.rb
index 01ae80a61d1..608c5bdf03a 100644
--- a/spec/models/terraform/state_spec.rb
+++ b/spec/models/terraform/state_spec.rb
@@ -15,7 +15,24 @@ RSpec.describe Terraform::State do
it { is_expected.to validate_presence_of(:project_id) }
before do
- stub_terraform_state_object_storage(Terraform::StateUploader)
+ stub_terraform_state_object_storage
+ end
+
+ describe 'scopes' do
+ describe '.ordered_by_name' do
+ let_it_be(:project) { create(:project) }
+ let(:names) { %w(state_d state_b state_a state_c) }
+
+ subject { described_class.ordered_by_name }
+
+ before do
+ names.each do |name|
+ create(:terraform_state, project: project, name: name)
+ end
+ end
+
+ it { expect(subject.map(&:name)).to eq(names.sort) }
+ end
end
describe '#file' do
@@ -43,7 +60,7 @@ RSpec.describe Terraform::State do
context 'when file is stored locally' do
before do
- stub_terraform_state_object_storage(Terraform::StateUploader, enabled: false)
+ stub_terraform_state_object_storage(enabled: false)
end
it_behaves_like 'mounted file in local store'
@@ -70,11 +87,17 @@ RSpec.describe Terraform::State do
let(:terraform_state) { create(:terraform_state, :with_file) }
it { is_expected.to eq terraform_state.file }
+
+ context 'and a version exists (migration to versioned in progress)' do
+ let!(:migrated_version) { create(:terraform_state_version, terraform_state: terraform_state) }
+
+ it { is_expected.to eq terraform_state.latest_version.file }
+ end
end
end
describe '#update_file!' do
- let(:version) { 2 }
+ let(:version) { 3 }
let(:data) { Hash[terraform_version: '0.12.21'].to_json }
subject { terraform_state.update_file!(CarrierWaveStringFile.new(data), version: version) }
@@ -98,6 +121,33 @@ RSpec.describe Terraform::State do
expect(terraform_state.latest_file.read).to eq(data)
end
+
+ context 'and a version exists (migration to versioned in progress)' do
+ let!(:migrated_version) { create(:terraform_state_version, terraform_state: terraform_state, version: 0) }
+
+ it 'creates a new version, corrects the migrated version number, and marks the state as versioned' do
+ expect { subject }.to change { Terraform::StateVersion.count }
+
+ expect(migrated_version.reload.version).to eq(1)
+ expect(migrated_version.file.read).to eq(terraform_state_file)
+
+ expect(terraform_state.reload.latest_version.version).to eq(version)
+ expect(terraform_state.latest_version.file.read).to eq(data)
+ expect(terraform_state).to be_versioning_enabled
+ end
+
+ context 'the current version cannot be determined' do
+ before do
+ migrated_version.update!(file: CarrierWaveStringFile.new('invalid-json'))
+ end
+
+ it 'uses version - 1 to correct the migrated version number' do
+ expect { subject }.to change { Terraform::StateVersion.count }
+
+ expect(migrated_version.reload.version).to eq(2)
+ end
+ end
+ end
end
end
end
diff --git a/spec/models/terraform/state_version_spec.rb b/spec/models/terraform/state_version_spec.rb
index 72dd29e1571..cc5ea87159d 100644
--- a/spec/models/terraform/state_version_spec.rb
+++ b/spec/models/terraform/state_version_spec.rb
@@ -29,7 +29,7 @@ RSpec.describe Terraform::StateVersion do
subject { create(:terraform_state_version) }
before do
- stub_terraform_state_object_storage(Terraform::StateUploader)
+ stub_terraform_state_object_storage
end
describe '#file' do
diff --git a/spec/models/todo_spec.rb b/spec/models/todo_spec.rb
index 44e81455a67..a9c4c6680cd 100644
--- a/spec/models/todo_spec.rb
+++ b/spec/models/todo_spec.rb
@@ -200,26 +200,42 @@ RSpec.describe Todo do
describe '#self_assigned?' do
let(:user_1) { build(:user) }
- before do
- subject.user = user_1
- subject.author = user_1
- subject.action = Todo::ASSIGNED
- end
+ context 'when self_added' do
+ before do
+ subject.user = user_1
+ subject.author = user_1
+ end
- it 'is true when todo is ASSIGNED and self_added' do
- expect(subject).to be_self_assigned
- end
+ it 'returns true for ASSIGNED' do
+ subject.action = Todo::ASSIGNED
+
+ expect(subject).to be_self_assigned
+ end
- it 'is false when the todo is not ASSIGNED' do
- subject.action = Todo::MENTIONED
+ it 'returns true for REVIEW_REQUESTED' do
+ subject.action = Todo::REVIEW_REQUESTED
- expect(subject).not_to be_self_assigned
+ expect(subject).to be_self_assigned
+ end
+
+ it 'returns false for other action' do
+ subject.action = Todo::MENTIONED
+
+ expect(subject).not_to be_self_assigned
+ end
end
- it 'is false when todo is not self_added' do
- subject.author = build(:user)
+ context 'when todo is not self_added' do
+ before do
+ subject.user = user_1
+ subject.author = build(:user)
+ end
- expect(subject).not_to be_self_assigned
+ it 'returns false' do
+ subject.action = Todo::ASSIGNED
+
+ expect(subject).not_to be_self_assigned
+ end
end
end
@@ -427,7 +443,7 @@ RSpec.describe Todo do
it 'updates updated_at' do
create(:todo, :pending)
- Timecop.freeze(1.day.from_now) do
+ travel_to(1.day.from_now) do
expected_update_date = Time.current.utc
ids = described_class.batch_update(state: :done)
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index 1841288cd4b..64bff5d00aa 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -705,6 +705,34 @@ RSpec.describe User do
end
describe "scopes" do
+ context 'blocked users' do
+ let_it_be(:active_user) { create(:user) }
+ let_it_be(:blocked_user) { create(:user, :blocked) }
+ let_it_be(:ldap_blocked_user) { create(:omniauth_user, :ldap_blocked) }
+ let_it_be(:blocked_pending_approval_user) { create(:user, :blocked_pending_approval) }
+
+ describe '.blocked' do
+ subject { described_class.blocked }
+
+ it 'returns only blocked users' do
+ expect(subject).to include(
+ blocked_user,
+ ldap_blocked_user
+ )
+
+ expect(subject).not_to include(active_user, blocked_pending_approval_user)
+ end
+ end
+
+ describe '.blocked_pending_approval' do
+ subject { described_class.blocked_pending_approval }
+
+ it 'returns only pending approval users' do
+ expect(subject).to contain_exactly(blocked_pending_approval_user)
+ end
+ end
+ end
+
describe ".with_two_factor" do
it "returns users with 2fa enabled via OTP" do
user_with_2fa = create(:user, :two_factor_via_otp)
@@ -1694,6 +1722,24 @@ RSpec.describe User do
end
end
+ describe 'blocking a user pending approval' do
+ let(:user) { create(:user) }
+
+ before do
+ user.block_pending_approval
+ end
+
+ context 'an active user' do
+ it 'can be blocked pending approval' do
+ expect(user.blocked_pending_approval?).to eq(true)
+ end
+
+ it 'behaves like a blocked user' do
+ expect(user.blocked?).to eq(true)
+ end
+ end
+ end
+
describe '.filter_items' do
let(:user) { double }
@@ -1715,6 +1761,12 @@ RSpec.describe User do
expect(described_class.filter_items('blocked')).to include user
end
+ it 'filters by blocked pending approval' do
+ expect(described_class).to receive(:blocked_pending_approval).and_return([user])
+
+ expect(described_class.filter_items('blocked_pending_approval')).to include user
+ end
+
it 'filters by deactivated' do
expect(described_class).to receive(:deactivated).and_return([user])
@@ -2744,6 +2796,14 @@ RSpec.describe User do
it_behaves_like 'eligible for deactivation'
end
+
+ context 'a user who is internal' do
+ it 'returns false' do
+ internal_user = create(:user, :bot)
+
+ expect(internal_user.can_be_deactivated?).to be_falsey
+ end
+ end
end
describe "#contributed_projects" do
@@ -3902,7 +3962,7 @@ RSpec.describe User do
it 'changes the namespace (just to compare to when username is not changed)' do
expect do
- Timecop.freeze(1.second.from_now) do
+ travel_to(1.second.from_now) do
user.update!(username: new_username)
end
end.to change { user.namespace.updated_at }
@@ -4330,28 +4390,32 @@ RSpec.describe User do
describe '#required_terms_not_accepted?' do
let(:user) { build(:user) }
+ let(:project_bot) { create(:user, :project_bot) }
subject { user.required_terms_not_accepted? }
context "when terms are not enforced" do
- it { is_expected.to be_falsy }
+ it { is_expected.to be_falsey }
end
- context "when terms are enforced and accepted by the user" do
+ context "when terms are enforced" do
before do
enforce_terms
- accept_terms(user)
end
- it { is_expected.to be_falsy }
- end
+ it "is not accepted by the user" do
+ expect(subject).to be_truthy
+ end
- context "when terms are enforced but the user has not accepted" do
- before do
- enforce_terms
+ it "is accepted by the user" do
+ accept_terms(user)
+
+ expect(subject).to be_falsey
end
- it { is_expected.to be_truthy }
+ it "auto accepts the term for project bots" do
+ expect(project_bot.required_terms_not_accepted?).to be_falsey
+ end
end
end
@@ -4818,7 +4882,8 @@ RSpec.describe User do
{ state: 'blocked' },
{ user_type: :ghost },
{ user_type: :alert_bot },
- { user_type: :support_bot }
+ { user_type: :support_bot },
+ { user_type: :security_bot }
]
end
@@ -4873,6 +4938,7 @@ RSpec.describe User do
'human' | true
'alert_bot' | false
'support_bot' | false
+ 'security_bot' | false
end
with_them do
@@ -4895,7 +4961,7 @@ RSpec.describe User do
user.block
end
- it { is_expected.to eq User::BLOCKED_MESSAGE }
+ it { is_expected.to eq :blocked }
end
context 'when user is an internal user' do
@@ -4903,7 +4969,7 @@ RSpec.describe User do
user.update(user_type: :ghost)
end
- it { is_expected.to be User::LOGIN_FORBIDDEN }
+ it { is_expected.to be :forbidden }
end
context 'when user is locked' do
@@ -4913,6 +4979,14 @@ RSpec.describe User do
it { is_expected.to be :locked }
end
+
+ context 'when user is blocked pending approval' do
+ before do
+ user.block_pending_approval!
+ end
+
+ it { is_expected.to be :blocked_pending_approval }
+ end
end
describe '#password_required?' do
@@ -4976,9 +5050,11 @@ RSpec.describe User do
it_behaves_like 'bot users', :alert_bot
it_behaves_like 'bot users', :support_bot
it_behaves_like 'bot users', :migration_bot
+ it_behaves_like 'bot users', :security_bot
it_behaves_like 'bot users', :ghost
it_behaves_like 'bot user avatars', :alert_bot, 'alert-bot.png'
it_behaves_like 'bot user avatars', :support_bot, 'support-bot.png'
+ it_behaves_like 'bot user avatars', :security_bot, 'security-bot.png'
end
end
diff --git a/spec/models/wiki_directory_spec.rb b/spec/models/wiki_directory_spec.rb
index 4cac90786eb..9b6cec99ddb 100644
--- a/spec/models/wiki_directory_spec.rb
+++ b/spec/models/wiki_directory_spec.rb
@@ -3,43 +3,97 @@
require 'spec_helper'
RSpec.describe WikiDirectory do
- describe 'validations' do
- subject { build(:wiki_directory) }
+ subject(:directory) { build(:wiki_directory) }
+ describe 'validations' do
it { is_expected.to validate_presence_of(:slug) }
end
+ describe '.group_pages' do
+ let_it_be(:toplevel1) { build(:wiki_page, title: 'aaa-toplevel1') }
+ let_it_be(:toplevel2) { build(:wiki_page, title: 'zzz-toplevel2') }
+ let_it_be(:toplevel3) { build(:wiki_page, title: 'zzz-toplevel3') }
+ let_it_be(:child1) { build(:wiki_page, title: 'parent1/child1') }
+ let_it_be(:child2) { build(:wiki_page, title: 'parent1/child2') }
+ let_it_be(:child3) { build(:wiki_page, title: 'parent2/child3') }
+ let_it_be(:grandchild1) { build(:wiki_page, title: 'parent1/subparent/grandchild1') }
+ let_it_be(:grandchild2) { build(:wiki_page, title: 'parent1/subparent/grandchild2') }
+
+ it 'returns a nested array of entries' do
+ entries = described_class.group_pages(
+ [toplevel1, toplevel2, toplevel3, child1, child2, child3, grandchild1, grandchild2].sort_by(&:title)
+ )
+
+ expect(entries).to match([
+ toplevel1,
+ a_kind_of(WikiDirectory).and(
+ having_attributes(
+ slug: 'parent1', entries: [
+ child1,
+ child2,
+ a_kind_of(WikiDirectory).and(
+ having_attributes(
+ slug: 'parent1/subparent',
+ entries: [grandchild1, grandchild2]
+ )
+ )
+ ]
+ )
+ ),
+ a_kind_of(WikiDirectory).and(
+ having_attributes(
+ slug: 'parent2',
+ entries: [child3]
+ )
+ ),
+ toplevel2,
+ toplevel3
+ ])
+ end
+ end
+
describe '#initialize' do
- context 'when there are pages' do
- let(:pages) { [build(:wiki_page)] }
- let(:directory) { described_class.new('/path_up_to/dir', pages) }
+ context 'when there are entries' do
+ let(:entries) { [build(:wiki_page)] }
+ let(:directory) { described_class.new('/path_up_to/dir', entries) }
it 'sets the slug attribute' do
expect(directory.slug).to eq('/path_up_to/dir')
end
- it 'sets the pages attribute' do
- expect(directory.pages).to eq(pages)
+ it 'sets the entries attribute' do
+ expect(directory.entries).to eq(entries)
end
end
- context 'when there are no pages' do
+ context 'when there are no entries' do
let(:directory) { described_class.new('/path_up_to/dir') }
it 'sets the slug attribute' do
expect(directory.slug).to eq('/path_up_to/dir')
end
- it 'sets the pages attribute to an empty array' do
- expect(directory.pages).to eq([])
+ it 'sets the entries attribute to an empty array' do
+ expect(directory.entries).to eq([])
end
end
end
+ describe '#title' do
+ it 'returns the basename of the directory, with hyphens replaced by spaces' do
+ directory.slug = 'parent'
+ expect(directory.title).to eq('parent')
+
+ directory.slug = 'parent/child'
+ expect(directory.title).to eq('child')
+
+ directory.slug = 'parent/child-foo'
+ expect(directory.title).to eq('child foo')
+ end
+ end
+
describe '#to_partial_path' do
it 'returns the relative path to the partial to be used' do
- directory = build(:wiki_directory)
-
expect(directory.to_partial_path).to eq('../shared/wikis/wiki_directory')
end
end
diff --git a/spec/models/wiki_page_spec.rb b/spec/models/wiki_page_spec.rb
index aa8b9ce58b9..be94eca550c 100644
--- a/spec/models/wiki_page_spec.rb
+++ b/spec/models/wiki_page_spec.rb
@@ -4,16 +4,25 @@ require "spec_helper"
RSpec.describe WikiPage do
let_it_be(:user) { create(:user) }
- let(:container) { create(:project, :wiki_repo) }
- let(:wiki) { Wiki.for_container(container, user) }
- let(:new_page) { build(:wiki_page, wiki: wiki, title: 'test page', content: 'test content') }
+ let_it_be(:container) { create(:project) }
- let(:existing_page) do
- create(:wiki_page, wiki: wiki, title: 'test page', content: 'test content', message: 'test commit')
- wiki.find_page('test page')
+ def create_wiki_page(attrs = {})
+ page = build_wiki_page(attrs)
+
+ page.create(message: (attrs[:message] || 'test commit'))
+
+ container.wiki.find_page(page.slug)
end
- subject { new_page }
+ def build_wiki_page(attrs = {})
+ wiki_page_attrs = { container: container, content: 'test content' }.merge(attrs)
+
+ build(:wiki_page, wiki_page_attrs)
+ end
+
+ def wiki
+ container.wiki
+ end
def disable_front_matter
stub_feature_flags(Gitlab::WikiPages::FrontMatterParser::FEATURE_FLAG => false)
@@ -23,92 +32,16 @@ RSpec.describe WikiPage do
stub_feature_flags(Gitlab::WikiPages::FrontMatterParser::FEATURE_FLAG => thing)
end
- describe '.group_by_directory' do
- context 'when there are no pages' do
- it 'returns an empty array' do
- expect(described_class.group_by_directory(nil)).to eq([])
- expect(described_class.group_by_directory([])).to eq([])
- end
- end
-
- context 'when there are pages' do
- before do
- wiki.create_page('dir_1/dir_1_1/page_3', 'content')
- wiki.create_page('page_1', 'content')
- wiki.create_page('dir_1/page_2', 'content')
- wiki.create_page('dir_2', 'page with dir name')
- wiki.create_page('dir_2/page_5', 'content')
- wiki.create_page('page_6', 'content')
- wiki.create_page('dir_2/page_4', 'content')
- end
-
- let(:page_1) { wiki.find_page('page_1') }
- let(:page_6) { wiki.find_page('page_6') }
- let(:page_dir_2) { wiki.find_page('dir_2') }
-
- let(:dir_1) do
- WikiDirectory.new('dir_1', [wiki.find_page('dir_1/page_2')])
- end
-
- let(:dir_1_1) do
- WikiDirectory.new('dir_1/dir_1_1', [wiki.find_page('dir_1/dir_1_1/page_3')])
- end
-
- let(:dir_2) do
- pages = [wiki.find_page('dir_2/page_5'),
- wiki.find_page('dir_2/page_4')]
- WikiDirectory.new('dir_2', pages)
- end
+ # Use for groups of tests that do not modify their `subject`.
+ #
+ # include_context 'subject is persisted page', title: 'my title'
+ shared_context 'subject is persisted page' do |attrs = {}|
+ let_it_be(:persisted_page) { create_wiki_page(attrs) }
- describe "#list_pages" do
- context 'sort by title' do
- let(:grouped_entries) { described_class.group_by_directory(wiki.list_pages) }
- let(:expected_grouped_entries) { [dir_1_1, dir_1, page_dir_2, dir_2, page_1, page_6] }
-
- it 'returns an array with pages and directories' do
- grouped_entries.each_with_index do |page_or_dir, i|
- expected_page_or_dir = expected_grouped_entries[i]
- expected_slugs = get_slugs(expected_page_or_dir)
- slugs = get_slugs(page_or_dir)
-
- expect(slugs).to match_array(expected_slugs)
- end
- end
- end
-
- context 'sort by created_at' do
- let(:grouped_entries) { described_class.group_by_directory(wiki.list_pages(sort: 'created_at')) }
- let(:expected_grouped_entries) { [dir_1_1, page_1, dir_1, page_dir_2, dir_2, page_6] }
-
- it 'returns an array with pages and directories' do
- grouped_entries.each_with_index do |page_or_dir, i|
- expected_page_or_dir = expected_grouped_entries[i]
- expected_slugs = get_slugs(expected_page_or_dir)
- slugs = get_slugs(page_or_dir)
-
- expect(slugs).to match_array(expected_slugs)
- end
- end
- end
-
- it 'returns an array with retained order with directories at the top' do
- expected_order = ['dir_1/dir_1_1/page_3', 'dir_1/page_2', 'dir_2', 'dir_2/page_4', 'dir_2/page_5', 'page_1', 'page_6']
-
- grouped_entries = described_class.group_by_directory(wiki.list_pages)
-
- actual_order =
- grouped_entries.flat_map do |page_or_dir|
- get_slugs(page_or_dir)
- end
- expect(actual_order).to eq(expected_order)
- end
- end
- end
+ subject { persisted_page }
end
describe '#front_matter' do
- let_it_be(:project) { create(:project) }
- let(:container) { project }
let(:wiki_page) { create(:wiki_page, container: container, content: content) }
shared_examples 'a page without front-matter' do
@@ -230,14 +163,14 @@ RSpec.describe WikiPage do
describe "#initialize" do
context "when initialized with an existing page" do
- subject { existing_page }
+ include_context 'subject is persisted page', title: 'test initialization'
it "sets the slug attribute" do
- expect(subject.slug).to eq("test-page")
+ expect(subject.slug).to eq("test-initialization")
end
it "sets the title attribute" do
- expect(subject.title).to eq("test page")
+ expect(subject.title).to eq("test initialization")
end
it "sets the formatted content attribute" do
@@ -259,6 +192,8 @@ RSpec.describe WikiPage do
end
describe "validations" do
+ subject { build_wiki_page }
+
it "validates presence of title" do
subject.attributes.delete(:title)
@@ -305,7 +240,7 @@ RSpec.describe WikiPage do
end
context 'with an existing page exceeding the limit' do
- subject { existing_page }
+ include_context 'subject is persisted page'
before do
subject
@@ -414,18 +349,22 @@ RSpec.describe WikiPage do
describe "#create" do
let(:attributes) do
{
- title: "Index",
+ title: SecureRandom.hex,
content: "Home Page",
format: "markdown",
message: 'Custom Commit Message'
}
end
+ let(:title) { attributes[:title] }
+
+ subject { build_wiki_page }
+
context "with valid attributes" do
it "saves the wiki page" do
subject.create(attributes)
- expect(wiki.find_page("Index")).not_to be_nil
+ expect(wiki.find_page(title)).not_to be_nil
end
it "returns true" do
@@ -435,7 +374,7 @@ RSpec.describe WikiPage do
it 'saves the wiki page with message' do
subject.create(attributes)
- expect(wiki.find_page("Index").message).to eq 'Custom Commit Message'
+ expect(wiki.find_page(title).message).to eq 'Custom Commit Message'
end
it 'if the title is preceded by a / it is removed' do
@@ -447,9 +386,7 @@ RSpec.describe WikiPage do
context "with invalid attributes" do
it 'does not create the page' do
- subject.create(title: '')
-
- expect(wiki.find_page('New Page')).to be_nil
+ expect { subject.create(title: '') }.not_to change { wiki.list_pages.length }
end
end
end
@@ -458,46 +395,40 @@ RSpec.describe WikiPage do
let(:title) { 'Index v1.2.3' }
describe "#create" do
- let(:attributes) { { title: title, content: "Home Page", format: "markdown" } }
-
- context "with valid attributes" do
- it "saves the wiki page" do
- subject.create(attributes)
+ subject { build_wiki_page }
- expect(wiki.find_page(title)).not_to be_nil
- end
+ it "saves the wiki page and returns true", :aggregate_failures do
+ attributes = { title: title, content: "Home Page", format: "markdown" }
- it "returns true" do
- expect(subject.create(attributes)).to eq(true)
- end
+ expect(subject.create(attributes)).to eq(true)
+ expect(wiki.find_page(title)).not_to be_nil
end
end
describe '#update' do
- subject { create(:wiki_page, wiki: wiki, title: title) }
+ subject { create_wiki_page(title: title) }
+
+ it 'updates the content of the page and returns true', :aggregate_failures do
+ expect(subject.update(content: 'new content')).to be_truthy
- it 'updates the content of the page' do
- subject.update(content: 'new content')
page = wiki.find_page(title)
expect([subject.content, page.content]).to all(eq('new content'))
end
-
- it "returns true" do
- expect(subject.update(content: "more content")).to be_truthy
- end
end
end
describe "#update" do
- subject { existing_page }
+ let!(:original_title) { subject.title }
+
+ subject { create_wiki_page }
context "with valid attributes" do
it "updates the content of the page" do
new_content = "new content"
subject.update(content: new_content)
- page = wiki.find_page('test page')
+ page = wiki.find_page(original_title)
expect([subject.content, page.content]).to all(eq("new content"))
end
@@ -514,10 +445,9 @@ RSpec.describe WikiPage do
describe 'updating front_matter' do
shared_examples 'able to update front-matter' do
it 'updates the wiki-page front-matter' do
- title = subject.title
content = subject.content
subject.update(front_matter: { slugs: ['x'] })
- page = wiki.find_page(title)
+ page = wiki.find_page(original_title)
expect([subject, page]).to all(
have_attributes(
@@ -566,10 +496,9 @@ RSpec.describe WikiPage do
end
it 'updates the wiki-page front-matter and content together' do
- title = subject.title
content = 'totally new content'
subject.update(content: content, front_matter: { slugs: ['x'] })
- page = wiki.find_page(title)
+ page = wiki.find_page(original_title)
expect([subject, page]).to all(
have_attributes(
@@ -598,11 +527,11 @@ RSpec.describe WikiPage do
context 'when renaming a page' do
it 'raises an error if the page already exists' do
- wiki.create_page('Existing Page', 'content')
+ existing_page = create_wiki_page
- expect { subject.update(title: 'Existing Page', content: 'new_content') }.to raise_error(WikiPage::PageRenameError)
- expect(subject.title).to eq 'test page'
- expect(subject.content).to eq 'new_content'
+ expect { subject.update(title: existing_page.title, content: 'new_content') }.to raise_error(WikiPage::PageRenameError)
+ expect(subject.title).to eq original_title
+ expect(subject.content).to eq 'new_content' # We don't revert the content
end
it 'updates the content and rename the file' do
@@ -623,7 +552,7 @@ RSpec.describe WikiPage do
wiki.create_page('foo/Existing Page', 'content')
expect { subject.update(title: 'foo/Existing Page', content: 'new_content') }.to raise_error(WikiPage::PageRenameError)
- expect(subject.title).to eq 'test page'
+ expect(subject.title).to eq original_title
expect(subject.content).to eq 'new_content'
end
@@ -639,20 +568,22 @@ RSpec.describe WikiPage do
expect(page.content).to eq new_content
end
- context 'in subdir' do
- subject { create(:wiki_page, wiki: wiki, title: 'foo/Existing Page') }
-
+ describe 'in subdir' do
it 'moves the page to the root folder if the title is preceded by /' do
- expect(subject.slug).to eq 'foo/Existing-Page'
- expect(subject.update(title: '/Existing Page', content: 'new_content')).to be_truthy
- expect(subject.slug).to eq 'Existing-Page'
+ page = create_wiki_page(title: 'foo/Existing Page')
+
+ expect(page.slug).to eq 'foo/Existing-Page'
+ expect(page.update(title: '/Existing Page', content: 'new_content')).to be_truthy
+ expect(page.slug).to eq 'Existing-Page'
end
it 'does nothing if it has the same title' do
- original_path = subject.slug
+ page = create_wiki_page(title: 'foo/Another Existing Page')
- expect(subject.update(title: 'Existing Page', content: 'new_content')).to be_truthy
- expect(subject.slug).to eq original_path
+ original_path = page.slug
+
+ expect(page.update(title: 'Another Existing Page', content: 'new_content')).to be_truthy
+ expect(page.slug).to eq original_path
end
end
@@ -660,7 +591,7 @@ RSpec.describe WikiPage do
it 'does nothing if the title is preceded by /' do
original_path = subject.slug
- expect(subject.update(title: '/test page', content: 'new_content')).to be_truthy
+ expect(subject.update(title: "/#{subject.title}", content: 'new_content')).to be_truthy
expect(subject.slug).to eq original_path
end
end
@@ -671,7 +602,7 @@ RSpec.describe WikiPage do
expect(subject.update(title: '', content: 'new_content')).to be_falsey
expect(subject.content).to eq 'new_content'
- page = wiki.find_page('test page')
+ page = wiki.find_page(original_title)
expect(page.content).to eq 'test content'
end
@@ -679,21 +610,17 @@ RSpec.describe WikiPage do
end
describe "#delete" do
- subject { existing_page }
-
- it "deletes the page" do
- subject.delete
-
- expect(wiki.list_pages).to be_empty
- end
+ it "deletes the page and returns true", :aggregate_failures do
+ page = create_wiki_page
- it "returns true" do
- expect(subject.delete).to eq(true)
+ expect do
+ expect(page.delete).to eq(true)
+ end.to change { wiki.list_pages.length }.by(-1)
end
end
describe "#versions" do
- subject { existing_page }
+ include_context 'subject is persisted page'
it "returns an array of all commits for the page" do
3.times { |i| subject.update(content: "content #{i}") }
@@ -709,19 +636,21 @@ RSpec.describe WikiPage do
describe '#title_changed?' do
using RSpec::Parameterized::TableSyntax
+ let_it_be(:unsaved_page) { build_wiki_page(title: 'test page') }
+ let_it_be(:existing_page) { create_wiki_page(title: 'test page') }
+ let_it_be(:directory_page) { create_wiki_page(title: 'parent directory/child page') }
+ let_it_be(:page_with_special_characters) { create_wiki_page(title: 'test+page') }
let(:untitled_page) { described_class.new(wiki) }
- let(:directory_page) { create(:wiki_page, title: 'parent directory/child page') }
- let(:page_with_special_characters) { create(:wiki_page, title: 'test+page') }
where(:page, :title, :changed) do
:untitled_page | nil | false
:untitled_page | 'new title' | true
- :new_page | nil | true
- :new_page | 'test page' | true
- :new_page | 'test-page' | true
- :new_page | 'test+page' | true
- :new_page | 'new title' | true
+ :unsaved_page | nil | true
+ :unsaved_page | 'test page' | true
+ :unsaved_page | 'test-page' | true
+ :unsaved_page | 'test+page' | true
+ :unsaved_page | 'new title' | true
:existing_page | nil | false
:existing_page | 'test page' | false
@@ -764,7 +693,7 @@ RSpec.describe WikiPage do
describe '#content_changed?' do
context 'with a new page' do
- subject { new_page }
+ subject { build_wiki_page }
it 'returns true if content is set' do
subject.attributes[:content] = 'new'
@@ -780,7 +709,7 @@ RSpec.describe WikiPage do
end
context 'with an existing page' do
- subject { existing_page }
+ include_context 'subject is persisted page'
it 'returns false' do
expect(subject.content_changed?).to be(false)
@@ -816,17 +745,21 @@ RSpec.describe WikiPage do
describe '#path' do
it 'returns the path when persisted' do
- expect(existing_page.path).to eq('test-page.md')
+ existing_page = create_wiki_page(title: 'path test')
+
+ expect(existing_page.path).to eq('path-test.md')
end
it 'returns nil when not persisted' do
- expect(new_page.path).to be_nil
+ unsaved_page = build_wiki_page(title: 'path test')
+
+ expect(unsaved_page.path).to be_nil
end
end
describe '#directory' do
context 'when the page is at the root directory' do
- subject { existing_page }
+ include_context 'subject is persisted page', title: 'directory test'
it 'returns an empty string' do
expect(subject.directory).to eq('')
@@ -834,7 +767,7 @@ RSpec.describe WikiPage do
end
context 'when the page is inside an actual directory' do
- subject { create(:wiki_page, title: 'dir_1/dir_1_1/file') }
+ include_context 'subject is persisted page', title: 'dir_1/dir_1_1/directory test'
it 'returns the full directory hierarchy' do
expect(subject.directory).to eq('dir_1/dir_1_1')
@@ -843,7 +776,7 @@ RSpec.describe WikiPage do
end
describe '#historical?' do
- subject { existing_page }
+ include_context 'subject is persisted page'
let(:old_version) { subject.versions.last.id }
let(:old_page) { wiki.find_page(subject.title, old_version) }
@@ -883,22 +816,22 @@ RSpec.describe WikiPage do
describe '#persisted?' do
it 'returns true for a persisted page' do
- expect(existing_page).to be_persisted
+ expect(create_wiki_page).to be_persisted
end
it 'returns false for an unpersisted page' do
- expect(new_page).not_to be_persisted
+ expect(build_wiki_page).not_to be_persisted
end
end
describe '#to_partial_path' do
it 'returns the relative path to the partial to be used' do
- expect(subject.to_partial_path).to eq('../shared/wikis/wiki_page')
+ expect(build_wiki_page.to_partial_path).to eq('../shared/wikis/wiki_page')
end
end
describe '#==' do
- subject { existing_page }
+ include_context 'subject is persisted page'
it 'returns true for identical wiki page' do
expect(subject).to eq(subject)
@@ -906,7 +839,7 @@ RSpec.describe WikiPage do
it 'returns true for updated wiki page' do
subject.update(content: "Updated content")
- updated_page = wiki.find_page(existing_page.slug)
+ updated_page = wiki.find_page(subject.slug)
expect(updated_page).not_to be_nil
expect(updated_page).to eq(subject)
@@ -921,7 +854,7 @@ RSpec.describe WikiPage do
end
it 'returns false for page with different slug on same container' do
- other_page = create(:wiki_page, container: subject.container)
+ other_page = create_wiki_page
expect(subject.slug).not_to eq(other_page.slug)
expect(subject.container).to eq(other_page.container)
@@ -929,7 +862,7 @@ RSpec.describe WikiPage do
end
it 'returns false for page with the same slug on a different container' do
- other_page = create(:wiki_page, title: existing_page.slug)
+ other_page = create(:wiki_page, title: subject.slug)
expect(subject.slug).to eq(other_page.slug)
expect(subject.container).not_to eq(other_page.container)
@@ -938,7 +871,7 @@ RSpec.describe WikiPage do
end
describe '#last_commit_sha' do
- subject { existing_page }
+ include_context 'subject is persisted page'
it 'returns commit sha' do
expect(subject.last_commit_sha).to eq subject.last_version.sha
@@ -948,13 +881,15 @@ RSpec.describe WikiPage do
last_commit_sha_before_update = subject.last_commit_sha
subject.update(content: "new content")
- page = wiki.find_page('test page')
+ page = wiki.find_page(subject.title)
expect(page.last_commit_sha).not_to eq last_commit_sha_before_update
end
end
describe '#hook_attrs' do
+ subject { build_wiki_page }
+
it 'adds absolute urls for images in the content' do
subject.attributes[:content] = 'test![WikiPage_Image](/uploads/abc/WikiPage_Image.png)'
@@ -965,19 +900,21 @@ RSpec.describe WikiPage do
describe '#version_commit_timestamp' do
context 'for a new page' do
it 'returns nil' do
- expect(new_page.version_commit_timestamp).to be_nil
+ expect(build_wiki_page.version_commit_timestamp).to be_nil
end
end
context 'for page that exists' do
it 'returns the timestamp of the commit' do
+ existing_page = create_wiki_page
+
expect(existing_page.version_commit_timestamp).to eq(existing_page.version.commit.committed_date)
end
end
end
describe '#diffs' do
- subject { existing_page }
+ include_context 'subject is persisted page'
it 'returns a diff instance' do
diffs = subject.diffs(foo: 'bar')
@@ -993,14 +930,4 @@ RSpec.describe WikiPage do
)
end
end
-
- private
-
- def get_slugs(page_or_dir)
- if page_or_dir.is_a? WikiPage
- [page_or_dir.slug]
- else
- page_or_dir.pages.present? ? page_or_dir.pages.map(&:slug) : []
- end
- end
end
diff --git a/spec/models/wiki_spec.rb b/spec/models/wiki_spec.rb
deleted file mode 100644
index 8dd510a0b98..00000000000
--- a/spec/models/wiki_spec.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-# frozen_string_literal: true
-
-require "spec_helper"
-
-RSpec.describe Wiki do
- describe '.new' do
- it 'verifies that the user is a User' do
- expect { described_class.new(double, 1) }.to raise_error(ArgumentError)
- expect { described_class.new(double, build(:group)) }.to raise_error(ArgumentError)
- expect { described_class.new(double, build(:user)) }.not_to raise_error
- expect { described_class.new(double, nil) }.not_to raise_error
- end
- end
-end
diff --git a/spec/policies/ci/bridge_policy_spec.rb b/spec/policies/ci/bridge_policy_spec.rb
new file mode 100644
index 00000000000..e598e2f7626
--- /dev/null
+++ b/spec/policies/ci/bridge_policy_spec.rb
@@ -0,0 +1,39 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Ci::BridgePolicy do
+ let_it_be(:user, reload: true) { create(:user) }
+ let_it_be(:project, reload: true) { create(:project) }
+ let_it_be(:downstream_project, reload: true) { create(:project, :repository) }
+ let_it_be(:pipeline, reload: true) { create(:ci_empty_pipeline, project: project) }
+ let_it_be(:bridge, reload: true) { create(:ci_bridge, pipeline: pipeline, downstream: downstream_project) }
+
+ let(:policy) do
+ described_class.new(user, bridge)
+ end
+
+ describe '#play_job' do
+ before do
+ fake_access = double('Gitlab::UserAccess')
+ expect(fake_access).to receive(:can_update_branch?).with('master').and_return(can_update_branch)
+ expect(Gitlab::UserAccess).to receive(:new).with(user, container: downstream_project).and_return(fake_access)
+ end
+
+ context 'when user can update the downstream branch' do
+ let(:can_update_branch) { true }
+
+ it 'allows' do
+ expect(policy).to be_allowed :play_job
+ end
+ end
+
+ context 'when user can not update the downstream branch' do
+ let(:can_update_branch) { false }
+
+ it 'does not allow' do
+ expect(policy).not_to be_allowed :play_job
+ end
+ end
+ end
+end
diff --git a/spec/policies/design_management/design_policy_spec.rb b/spec/policies/design_management/design_policy_spec.rb
index 5a74d979ef3..117279d1638 100644
--- a/spec/policies/design_management/design_policy_spec.rb
+++ b/spec/policies/design_management/design_policy_spec.rb
@@ -71,6 +71,11 @@ RSpec.describe DesignManagement::DesignPolicy do
end
end
+ shared_examples_for "read-only design abilities" do
+ it { is_expected.to be_allowed(*guest_design_abilities) }
+ it { is_expected.to be_disallowed(*developer_design_abilities) }
+ end
+
shared_examples_for "design abilities available for members" do
context "for owners" do
let(:current_user) { owner }
@@ -86,8 +91,7 @@ RSpec.describe DesignManagement::DesignPolicy do
end
context "when admin mode disabled" do
- it { is_expected.to be_allowed(*guest_design_abilities) }
- it { is_expected.to be_disallowed(*developer_design_abilities) }
+ it_behaves_like "read-only design abilities"
end
end
@@ -106,16 +110,10 @@ RSpec.describe DesignManagement::DesignPolicy do
context "for reporters" do
let(:current_user) { reporter }
- it { is_expected.to be_allowed(*guest_design_abilities) }
- it { is_expected.to be_disallowed(*developer_design_abilities) }
+ it_behaves_like "read-only design abilities"
end
end
- shared_examples_for "read-only design abilities" do
- it { is_expected.to be_allowed(:read_design) }
- it { is_expected.to be_disallowed(:create_design, :destroy_design) }
- end
-
context "when DesignManagement is not enabled" do
before do
enable_design_management(false)
@@ -135,15 +133,13 @@ RSpec.describe DesignManagement::DesignPolicy do
let_it_be(:project) { create(:project, :private) }
let(:current_user) { guest }
- it { is_expected.to be_allowed(*guest_design_abilities) }
- it { is_expected.to be_disallowed(*developer_design_abilities) }
+ it_behaves_like "read-only design abilities"
end
context "for anonymous users in public projects" do
let(:current_user) { nil }
- it { is_expected.to be_allowed(*guest_design_abilities) }
- it { is_expected.to be_disallowed(*developer_design_abilities) }
+ it_behaves_like "read-only design abilities"
end
context "when the issue is confidential" do
@@ -164,20 +160,6 @@ RSpec.describe DesignManagement::DesignPolicy do
end
end
- context "when the issue is locked" do
- let_it_be(:issue) { create(:issue, :locked, project: project) }
- let(:current_user) { owner }
-
- it_behaves_like "read-only design abilities"
- end
-
- context "when the issue has moved" do
- let_it_be(:issue) { create(:issue, project: project, moved_to: create(:issue)) }
- let(:current_user) { owner }
-
- it_behaves_like "read-only design abilities"
- end
-
context "when the project is archived" do
let_it_be(:project) { create(:project, :public, :archived) }
let_it_be(:issue) { create(:issue, project: project) }
diff --git a/spec/policies/global_policy_spec.rb b/spec/policies/global_policy_spec.rb
index 6cd1c201c62..2f9376f9b0a 100644
--- a/spec/policies/global_policy_spec.rb
+++ b/spec/policies/global_policy_spec.rb
@@ -130,6 +130,24 @@ RSpec.describe GlobalPolicy do
end
end
+ describe 'approving users' do
+ context 'regular user' do
+ it { is_expected.not_to be_allowed(:approve_user) }
+ end
+
+ context 'admin' do
+ let(:current_user) { create(:admin) }
+
+ context 'when admin mode is enabled', :enable_admin_mode do
+ it { is_expected.to be_allowed(:approve_user) }
+ end
+
+ context 'when admin mode is disabled' do
+ it { is_expected.to be_disallowed(:approve_user) }
+ end
+ end
+ end
+
describe 'using project statistics filters' do
context 'regular user' do
it { is_expected.not_to be_allowed(:use_project_statistics_filters) }
@@ -187,6 +205,14 @@ RSpec.describe GlobalPolicy do
it { is_expected.not_to be_allowed(:access_api) }
end
+ context 'user blocked pending approval' do
+ before do
+ current_user.block_pending_approval
+ end
+
+ it { is_expected.not_to be_allowed(:access_api) }
+ end
+
context 'when terms are enforced' do
before do
enforce_terms
@@ -229,12 +255,6 @@ RSpec.describe GlobalPolicy do
it { is_expected.not_to be_allowed(:access_api) }
end
-
- it 'when `inactive_policy_condition` feature flag is turned off' do
- stub_feature_flags(inactive_policy_condition: false)
-
- is_expected.to be_allowed(:access_api)
- end
end
end
@@ -282,6 +302,14 @@ RSpec.describe GlobalPolicy do
it { is_expected.not_to be_allowed(:receive_notifications) }
end
+
+ context 'user blocked pending approval' do
+ before do
+ current_user.block_pending_approval
+ end
+
+ it { is_expected.not_to be_allowed(:receive_notifications) }
+ end
end
describe 'git access' do
@@ -321,12 +349,6 @@ RSpec.describe GlobalPolicy do
end
it { is_expected.not_to be_allowed(:access_git) }
-
- it 'when `inactive_policy_condition` feature flag is turned off' do
- stub_feature_flags(inactive_policy_condition: false)
-
- is_expected.to be_allowed(:access_git)
- end
end
context 'when terms are enforced' do
@@ -356,6 +378,14 @@ RSpec.describe GlobalPolicy do
it { is_expected.to be_allowed(:access_git) }
end
+
+ context 'user blocked pending approval' do
+ before do
+ current_user.block_pending_approval
+ end
+
+ it { is_expected.not_to be_allowed(:access_git) }
+ end
end
describe 'read instance metadata' do
@@ -403,12 +433,6 @@ RSpec.describe GlobalPolicy do
end
it { is_expected.not_to be_allowed(:use_slash_commands) }
-
- it 'when `inactive_policy_condition` feature flag is turned off' do
- stub_feature_flags(inactive_policy_condition: false)
-
- is_expected.to be_allowed(:use_slash_commands)
- end
end
context 'when access locked' do
@@ -430,6 +454,14 @@ RSpec.describe GlobalPolicy do
it { is_expected.not_to be_allowed(:use_slash_commands) }
end
+
+ context 'user blocked pending approval' do
+ before do
+ current_user.block_pending_approval
+ end
+
+ it { is_expected.not_to be_allowed(:use_slash_commands) }
+ end
end
describe 'create_snippet' do
@@ -462,5 +494,13 @@ RSpec.describe GlobalPolicy do
it { is_expected.not_to be_allowed(:log_in) }
end
+
+ context 'user blocked pending approval' do
+ before do
+ current_user.block_pending_approval
+ end
+
+ it { is_expected.not_to be_allowed(:log_in) }
+ end
end
end
diff --git a/spec/policies/group_policy_spec.rb b/spec/policies/group_policy_spec.rb
index dbe444acb58..fecf5f3e4f8 100644
--- a/spec/policies/group_policy_spec.rb
+++ b/spec/policies/group_policy_spec.rb
@@ -812,4 +812,74 @@ RSpec.describe GroupPolicy do
it { is_expected.to be_disallowed(:create_jira_connect_subscription) }
end
end
+
+ describe 'read_package' do
+ context 'admin' do
+ let(:current_user) { admin }
+
+ it { is_expected.to be_allowed(:read_package) }
+ end
+
+ context 'with owner' do
+ let(:current_user) { owner }
+
+ it { is_expected.to be_allowed(:read_package) }
+ end
+
+ context 'with maintainer' do
+ let(:current_user) { maintainer }
+
+ it { is_expected.to be_allowed(:read_package) }
+ end
+
+ context 'with reporter' do
+ let(:current_user) { reporter }
+
+ it { is_expected.to be_allowed(:read_package) }
+ end
+
+ context 'with guest' do
+ let(:current_user) { guest }
+
+ it { is_expected.to be_disallowed(:read_package) }
+ end
+
+ context 'with non member' do
+ let(:current_user) { create(:user) }
+
+ it { is_expected.to be_disallowed(:read_package) }
+ end
+
+ context 'with anonymous' do
+ let(:current_user) { nil }
+
+ it { is_expected.to be_disallowed(:read_package) }
+ end
+ end
+
+ context 'deploy token access' do
+ let!(:group_deploy_token) do
+ create(:group_deploy_token, group: group, deploy_token: deploy_token)
+ end
+
+ subject { described_class.new(deploy_token, group) }
+
+ context 'a deploy token with read_package_registry scope' do
+ let(:deploy_token) { create(:deploy_token, :group, read_package_registry: true) }
+
+ it { is_expected.to be_allowed(:read_package) }
+ it { is_expected.to be_allowed(:read_group) }
+ it { is_expected.to be_disallowed(:create_package) }
+ end
+
+ context 'a deploy token with write_package_registry scope' do
+ let(:deploy_token) { create(:deploy_token, :group, write_package_registry: true) }
+
+ it { is_expected.to be_allowed(:create_package) }
+ it { is_expected.to be_allowed(:read_group) }
+ it { is_expected.to be_disallowed(:destroy_package) }
+ end
+ end
+
+ it_behaves_like 'Self-managed Core resource access tokens'
end
diff --git a/spec/policies/project_policy_spec.rb b/spec/policies/project_policy_spec.rb
index 0c457148b4d..d66ef81efca 100644
--- a/spec/policies/project_policy_spec.rb
+++ b/spec/policies/project_policy_spec.rb
@@ -941,4 +941,6 @@ RSpec.describe ProjectPolicy do
end
end
end
+
+ it_behaves_like 'Self-managed Core resource access tokens'
end
diff --git a/spec/policies/terraform/state_policy_spec.rb b/spec/policies/terraform/state_policy_spec.rb
new file mode 100644
index 00000000000..82152920997
--- /dev/null
+++ b/spec/policies/terraform/state_policy_spec.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Terraform::StatePolicy do
+ let_it_be(:project) { create(:project) }
+ let_it_be(:terraform_state) { create(:terraform_state, project: project)}
+
+ subject { described_class.new(user, terraform_state) }
+
+ describe 'rules' do
+ context 'no access' do
+ let(:user) { create(:user) }
+
+ it { is_expected.to be_disallowed(:read_terraform_state) }
+ it { is_expected.to be_disallowed(:admin_terraform_state) }
+ end
+
+ context 'developer' do
+ let(:user) { create(:user, developer_projects: [project]) }
+
+ it { is_expected.to be_allowed(:read_terraform_state) }
+ it { is_expected.to be_disallowed(:admin_terraform_state) }
+ end
+
+ context 'maintainer' do
+ let(:user) { create(:user, maintainer_projects: [project]) }
+
+ it { is_expected.to be_allowed(:read_terraform_state) }
+ it { is_expected.to be_allowed(:admin_terraform_state) }
+ end
+ end
+end
diff --git a/spec/presenters/ci/pipeline_presenter_spec.rb b/spec/presenters/ci/pipeline_presenter_spec.rb
index 18f79bc930c..5cb9d340e06 100644
--- a/spec/presenters/ci/pipeline_presenter_spec.rb
+++ b/spec/presenters/ci/pipeline_presenter_spec.rb
@@ -5,17 +5,20 @@ require 'spec_helper'
RSpec.describe Ci::PipelinePresenter do
include Gitlab::Routing
- let(:user) { create(:user) }
+ let_it_be(:user) { create(:user) }
+ let_it_be_with_reload(:project) { create(:project, :test_repo) }
+ let_it_be_with_reload(:pipeline) { create(:ci_pipeline, project: project) }
let(:current_user) { user }
- let(:project) { create(:project, :test_repo) }
- let(:pipeline) { create(:ci_pipeline, project: project) }
subject(:presenter) do
described_class.new(pipeline)
end
- before do
+ before_all do
project.add_developer(user)
+ end
+
+ before do
allow(presenter).to receive(:current_user) { current_user }
end
@@ -184,8 +187,8 @@ RSpec.describe Ci::PipelinePresenter do
describe '#all_related_merge_request_text' do
subject { presenter.all_related_merge_request_text }
- let(:mr_1) { create(:merge_request) }
- let(:mr_2) { create(:merge_request) }
+ let_it_be(:mr_1) { create(:merge_request) }
+ let_it_be(:mr_2) { create(:merge_request) }
context 'with zero related merge requests (branch pipeline)' do
it { is_expected.to eq('No related merge requests found.') }
@@ -242,7 +245,7 @@ RSpec.describe Ci::PipelinePresenter do
end
context 'permissions' do
- let(:merge_request) { create(:merge_request, :with_detached_merge_request_pipeline, source_project: project) }
+ let_it_be_with_refind(:merge_request) { create(:merge_request, :with_detached_merge_request_pipeline, source_project: project) }
let(:pipeline) { merge_request.all_pipelines.take }
shared_examples 'private merge requests' do
diff --git a/spec/presenters/event_presenter_spec.rb b/spec/presenters/event_presenter_spec.rb
index 6798be21d28..5a67fd92c9d 100644
--- a/spec/presenters/event_presenter_spec.rb
+++ b/spec/presenters/event_presenter_spec.rb
@@ -38,4 +38,34 @@ RSpec.describe EventPresenter do
it { is_expected.to eq([project, target]) }
end
end
+
+ describe '#target_type_name' do
+ it 'returns design for a design event' do
+ expect(build(:design_event).present).to have_attributes(target_type_name: 'design')
+ end
+
+ it 'returns project for a project event' do
+ expect(build(:project_created_event).present).to have_attributes(target_type_name: 'project')
+ end
+
+ it 'returns milestone for a milestone event' do
+ expect(group_event.present).to have_attributes(target_type_name: 'milestone')
+ end
+ end
+
+ describe '#note_target_type_name' do
+ it 'returns design for an event on a comment on a design' do
+ expect(build(:event, :commented, :for_design).present)
+ .to have_attributes(note_target_type_name: 'design')
+ end
+
+ it 'returns nil for an event without a target' do
+ expect(build(:event).present).to have_attributes(note_target_type_name: be_nil)
+ end
+
+ it 'returns issue for an issue comment event' do
+ expect(build(:event, :commented, target: build(:note_on_issue)).present)
+ .to have_attributes(note_target_type_name: 'issue')
+ end
+ end
end
diff --git a/spec/presenters/label_presenter_spec.rb b/spec/presenters/label_presenter_spec.rb
index cb6e991bd8e..44c68a6102f 100644
--- a/spec/presenters/label_presenter_spec.rb
+++ b/spec/presenters/label_presenter_spec.rb
@@ -91,4 +91,18 @@ RSpec.describe LabelPresenter do
it { is_expected.to eq(label.project.name) }
end
end
+
+ describe '#subject_full_name' do
+ context 'with group label' do
+ subject { group_label.subject_full_name }
+
+ it { is_expected.to eq(group_label.group.full_name) }
+ end
+
+ context 'with project label' do
+ subject { label.subject_full_name }
+
+ it { is_expected.to eq(label.project.full_name) }
+ end
+ end
end
diff --git a/spec/presenters/merge_request_presenter_spec.rb b/spec/presenters/merge_request_presenter_spec.rb
index f1e581efd44..76b77ee0de2 100644
--- a/spec/presenters/merge_request_presenter_spec.rb
+++ b/spec/presenters/merge_request_presenter_spec.rb
@@ -3,9 +3,9 @@
require 'spec_helper'
RSpec.describe MergeRequestPresenter do
- let(:resource) { create(:merge_request, source_project: project) }
- let(:project) { create(:project) }
- let(:user) { create(:user) }
+ let_it_be(:project) { create(:project, :repository) }
+ let_it_be(:resource) { create(:merge_request, source_project: project) }
+ let_it_be(:user) { create(:user) }
describe '#ci_status' do
subject { described_class.new(resource).ci_status }
@@ -73,8 +73,6 @@ RSpec.describe MergeRequestPresenter do
end
describe '#conflict_resolution_path' do
- let(:project) { create :project }
- let(:user) { create :user }
let(:presenter) { described_class.new(resource, current_user: user) }
let(:path) { presenter.conflict_resolution_path }
@@ -107,18 +105,21 @@ RSpec.describe MergeRequestPresenter do
end
context 'issues links' do
- let(:project) { create(:project, :private, :repository, creator: user, namespace: user.namespace) }
- let(:issue_a) { create(:issue, project: project) }
- let(:issue_b) { create(:issue, project: project) }
+ let_it_be(:project) { create(:project, :private, :repository, creator: user, namespace: user.namespace) }
+ let_it_be(:issue_a) { create(:issue, project: project) }
+ let_it_be(:issue_b) { create(:issue, project: project) }
- let(:resource) do
+ let_it_be(:resource) do
create(:merge_request,
source_project: project, target_project: project,
description: "Fixes #{issue_a.to_reference} Related #{issue_b.to_reference}")
end
- before do
+ before_all do
project.add_developer(user)
+ end
+
+ before do
allow(resource.project).to receive(:default_branch)
.and_return(resource.target_branch)
resource.cache_merge_request_closes_issues!
diff --git a/spec/presenters/packages/detail/package_presenter_spec.rb b/spec/presenters/packages/detail/package_presenter_spec.rb
index 3a13aca6c7a..8ece27e9b5f 100644
--- a/spec/presenters/packages/detail/package_presenter_spec.rb
+++ b/spec/presenters/packages/detail/package_presenter_spec.rb
@@ -76,7 +76,7 @@ RSpec.describe ::Packages::Detail::PackagePresenter do
context 'with conan metadata' do
let(:package) { create(:conan_package, project: project) }
- let(:expected_package_details) { super().merge(conan_metadatum: package.conan_metadatum) }
+ let(:expected_package_details) { super().merge(conan_metadatum: package.conan_metadatum, conan_package_name: package.name, name: package.conan_recipe) }
it 'returns conan_metadatum' do
expect(presenter.detail_view).to eq expected_package_details
diff --git a/spec/presenters/project_presenter_spec.rb b/spec/presenters/project_presenter_spec.rb
index 4b4d8ee85db..b7fee5253f8 100644
--- a/spec/presenters/project_presenter_spec.rb
+++ b/spec/presenters/project_presenter_spec.rb
@@ -38,14 +38,33 @@ RSpec.describe ProjectPresenter do
context 'when repository is empty' do
let_it_be(:project) { create(:project_empty_repo, :public) }
- it 'returns activity if user has repository access' do
+ it 'returns wiki if user has repository access and can read wiki, which exists' do
+ allow(project).to receive(:wiki_repository_exists?).and_return(true)
allow(presenter).to receive(:can?).with(nil, :download_code, project).and_return(true)
+ allow(presenter).to receive(:can?).with(nil, :read_wiki, project).and_return(true)
+ allow(presenter).to receive(:can?).with(nil, :read_issue, project).and_return(false)
+
+ expect(presenter.default_view).to eq('wiki')
+ end
+
+ it 'returns activity if user has repository access and can read wiki, which does not exist' do
+ allow(presenter).to receive(:can?).with(nil, :download_code, project).and_return(true)
+ allow(presenter).to receive(:can?).with(nil, :read_wiki, project).and_return(true)
+ allow(presenter).to receive(:can?).with(nil, :read_issue, project).and_return(false)
expect(presenter.default_view).to eq('activity')
end
- it 'returns activity if user does not have repository access' do
- allow(project).to receive(:can?).with(nil, :download_code, project).and_return(false)
+ it 'returns issues if user does not have repository access, but can read issues' do
+ allow(presenter).to receive(:can?).with(nil, :download_code, project).and_return(false)
+ allow(presenter).to receive(:can?).with(nil, :read_issue, project).and_call_original
+
+ expect(presenter.default_view).to eq('projects/issues/issues')
+ end
+
+ it 'returns activity if user can read neither wiki nor issues' do
+ allow(presenter).to receive(:can?).with(nil, :download_code, project).and_return(false)
+ allow(presenter).to receive(:can?).with(nil, :read_issue, project).and_return(false)
expect(presenter.default_view).to eq('activity')
end
@@ -61,8 +80,18 @@ RSpec.describe ProjectPresenter do
expect(presenter.default_view).to eq('files')
end
- it 'returns activity if user does not have repository access' do
+ it 'returns wiki if user does not have repository access and can read wiki, which exists' do
+ allow(project).to receive(:wiki_repository_exists?).and_return(true)
allow(presenter).to receive(:can?).with(nil, :download_code, project).and_return(false)
+ allow(presenter).to receive(:can?).with(nil, :read_wiki, project).and_return(true)
+
+ expect(presenter.default_view).to eq('wiki')
+ end
+
+ it 'returns activity if user does not have repository or wiki access' do
+ allow(presenter).to receive(:can?).with(nil, :download_code, project).and_return(false)
+ allow(presenter).to receive(:can?).with(nil, :read_issue, project).and_return(false)
+ allow(presenter).to receive(:can?).with(nil, :read_wiki, project).and_return(false)
expect(presenter.default_view).to eq('activity')
end
@@ -96,22 +125,25 @@ RSpec.describe ProjectPresenter do
allow(presenter).to receive(:can?).with(user, :download_code, project).and_return(false)
end
- it 'returns wiki if the user has the right policy' do
+ it 'returns wiki if the user has the right policy and the wiki exists' do
+ allow(project).to receive(:wiki_repository_exists?).and_return(true)
allow(presenter).to receive(:can?).with(user, :read_wiki, project).and_return(true)
expect(presenter.default_view).to eq('wiki')
end
- it 'returns customize_workflow if the user does not have the right policy' do
+ it 'returns activity if the user does not have the right policy' do
allow(presenter).to receive(:can?).with(user, :read_wiki, project).and_return(false)
+ allow(presenter).to receive(:can?).with(user, :read_issue, project).and_return(false)
- expect(presenter.default_view).to eq('customize_workflow')
+ expect(presenter.default_view).to eq('activity')
end
end
context 'with issues as a feature available' do
it 'return issues' do
allow(presenter).to receive(:can?).with(user, :download_code, project).and_return(false)
+ allow(presenter).to receive(:can?).with(user, :read_issue, project).and_return(true)
allow(presenter).to receive(:can?).with(user, :read_wiki, project).and_return(false)
expect(presenter.default_view).to eq('projects/issues/issues')
@@ -119,12 +151,13 @@ RSpec.describe ProjectPresenter do
end
context 'with no activity, no wikies and no issues' do
- it 'returns customize_workflow as default' do
+ it 'returns activity as default' do
project.project_feature.update_attribute(:issues_access_level, 0)
allow(presenter).to receive(:can?).with(user, :download_code, project).and_return(false)
allow(presenter).to receive(:can?).with(user, :read_wiki, project).and_return(false)
+ allow(presenter).to receive(:can?).with(user, :read_issue, project).and_return(false)
- expect(presenter.default_view).to eq('customize_workflow')
+ expect(presenter.default_view).to eq('activity')
end
end
end
diff --git a/spec/presenters/projects/prometheus/alert_presenter_spec.rb b/spec/presenters/projects/prometheus/alert_presenter_spec.rb
deleted file mode 100644
index 98dba28829e..00000000000
--- a/spec/presenters/projects/prometheus/alert_presenter_spec.rb
+++ /dev/null
@@ -1,346 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Projects::Prometheus::AlertPresenter do
- include Gitlab::Routing.url_helpers
-
- let_it_be(:project, reload: true) { create(:project) }
-
- let(:presenter) { described_class.new(alert) }
- let(:payload) { {} }
- let(:alert) { create(:alerting_alert, project: project, payload: payload) }
-
- shared_context 'gitlab alert' do
- let(:gitlab_alert) { create(:prometheus_alert, project: project) }
- let(:metric_id) { gitlab_alert.prometheus_metric_id }
-
- let(:alert) do
- create(:alerting_alert, project: project, metric_id: metric_id, payload: payload)
- end
- end
-
- describe '#project_full_path' do
- subject { presenter.project_full_path }
-
- it { is_expected.to eq(project.full_path) }
- end
-
- describe '#start_time' do
- subject { presenter.start_time }
-
- let(:starts_at) { '2020-10-31T14:02:04Z' }
-
- before do
- payload['startsAt'] = starts_at
- end
-
- context 'with valid utc datetime' do
- it { is_expected.to eq('31 October 2020, 2:02PM (UTC)') }
-
- context 'with admin time zone not UTC' do
- before do
- allow(Time).to receive(:zone).and_return(ActiveSupport::TimeZone.new('Perth'))
- end
-
- it { is_expected.to eq('31 October 2020, 2:02PM (UTC)') }
- end
- end
-
- context 'with invalid datetime' do
- let(:starts_at) { 'invalid' }
-
- it { is_expected.to be_nil }
- end
- end
-
- describe '#issue_summary_markdown' do
- let(:markdown_line_break) { ' ' }
-
- subject { presenter.issue_summary_markdown }
-
- context 'without default payload' do
- it do
- is_expected.to eq(
- <<~MARKDOWN.chomp
- **Start time:** #{presenter.start_time}
-
- MARKDOWN
- )
- end
- end
-
- context 'with optional attributes' do
- before do
- payload['annotations'] = {
- 'title' => 'Alert Title',
- 'foo' => 'value1',
- 'bar' => 'value2',
- 'description' => 'Alert Description',
- 'monitoring_tool' => 'monitoring_tool_name',
- 'service' => 'service_name',
- 'hosts' => ['http://localhost:3000', 'http://localhost:3001']
- }
- payload['generatorURL'] = 'http://host?g0.expr=query'
- end
-
- it do
- is_expected.to eq(
- <<~MARKDOWN.chomp
- **Start time:** #{presenter.start_time}#{markdown_line_break}
- **full_query:** `query`#{markdown_line_break}
- **Service:** service_name#{markdown_line_break}
- **Monitoring tool:** monitoring_tool_name#{markdown_line_break}
- **Hosts:** http://localhost:3000 http://localhost:3001
-
- MARKDOWN
- )
- end
- end
-
- context 'when hosts is a string' do
- before do
- payload['annotations'] = { 'hosts' => 'http://localhost:3000' }
- end
-
- it do
- is_expected.to eq(
- <<~MARKDOWN.chomp
- **Start time:** #{presenter.start_time}#{markdown_line_break}
- **Hosts:** http://localhost:3000
-
- MARKDOWN
- )
- end
- end
-
- context 'with embedded metrics' do
- let(:starts_at) { '2018-03-12T09:06:00Z' }
-
- shared_examples_for 'markdown with metrics embed' do
- let(:embed_regex) { /\n\[\]\(#{Regexp.quote(presenter.metrics_dashboard_url)}\)\z/ }
-
- context 'without a starting time available' do
- around do |example|
- Timecop.freeze(starts_at) { example.run }
- end
-
- before do
- payload.delete('startsAt')
- end
-
- it { is_expected.to match(embed_regex) }
- end
-
- context 'with a starting time available' do
- it { is_expected.to match(embed_regex) }
- end
- end
-
- context 'for gitlab-managed prometheus alerts' do
- include_context 'gitlab-managed prometheus alert attributes'
-
- let(:alert) do
- create(:alerting_alert, project: project, metric_id: prometheus_metric_id, payload: payload)
- end
-
- it_behaves_like 'markdown with metrics embed'
- end
-
- context 'for alerts from a self-managed prometheus' do
- include_context 'self-managed prometheus alert attributes'
-
- it_behaves_like 'markdown with metrics embed'
-
- context 'without y_label' do
- let(:y_label) { title }
-
- before do
- payload['annotations'].delete('gitlab_y_label')
- end
-
- it_behaves_like 'markdown with metrics embed'
- end
-
- context 'when not enough information is present for an embed' do
- shared_examples_for 'does not include an embed' do
- it { is_expected.not_to match(/\[\]\(.+\)/) }
- end
-
- context 'without title' do
- before do
- payload['annotations'].delete('title')
- end
-
- it_behaves_like 'does not include an embed'
- end
-
- context 'without environment' do
- before do
- payload['labels'].delete('gitlab_environment_name')
- end
-
- it_behaves_like 'does not include an embed'
- end
-
- context 'without full_query' do
- before do
- payload.delete('generatorURL')
- end
-
- it_behaves_like 'does not include an embed'
- end
- end
- end
- end
- end
-
- describe '#show_performance_dashboard_link?' do
- subject { presenter.show_performance_dashboard_link? }
-
- it { is_expected.to be_falsey }
-
- context 'with gitlab alert' do
- include_context 'gitlab alert'
-
- it { is_expected.to eq(true) }
- end
- end
-
- describe '#show_incident_issues_link?' do
- subject { presenter.show_incident_issues_link? }
-
- it { is_expected.to be_falsey }
-
- context 'create issue setting enabled' do
- before do
- create(:project_incident_management_setting, project: project, create_issue: true)
- end
-
- it { is_expected.to eq(true) }
- end
- end
-
- describe '#details_url' do
- subject { presenter.details_url }
-
- it { is_expected.to eq(nil) }
-
- context 'alert management alert present' do
- let_it_be(:am_alert) { create(:alert_management_alert, project: project) }
- let(:alert) { create(:alerting_alert, project: project, payload: payload, am_alert: am_alert) }
-
- it { is_expected.to eq("http://localhost/#{project.full_path}/-/alert_management/#{am_alert.iid}/details") }
- end
- end
-
- context 'with gitlab alert' do
- include_context 'gitlab alert'
-
- describe '#full_title' do
- let(:query_title) do
- "#{gitlab_alert.title} #{gitlab_alert.computed_operator} #{gitlab_alert.threshold} for 5 minutes"
- end
-
- let(:expected_subject) do
- "#{alert.environment.name}: #{query_title}"
- end
-
- subject { presenter.full_title }
-
- it { is_expected.to eq(expected_subject) }
- end
-
- describe '#metric_query' do
- subject { presenter.metric_query }
-
- it { is_expected.to eq(gitlab_alert.full_query) }
- end
-
- describe '#environment_name' do
- subject { presenter.environment_name }
-
- it { is_expected.to eq(alert.environment.name) }
- end
-
- describe '#performance_dashboard_link' do
- let(:expected_link) { metrics_project_environment_url(project, alert.environment) }
-
- subject { presenter.performance_dashboard_link }
-
- it { is_expected.to eq(expected_link) }
- end
-
- describe '#incident_issues_link' do
- let(:expected_link) { project_issues_url(project, label_name: described_class::INCIDENT_LABEL_NAME) }
-
- subject { presenter.incident_issues_link }
-
- it { is_expected.to eq(expected_link) }
- end
- end
-
- context 'without gitlab alert' do
- describe '#full_title' do
- subject { presenter.full_title }
-
- context 'with title' do
- let(:title) { 'some title' }
-
- before do
- expect(alert).to receive(:title).and_return(title)
- end
-
- it { is_expected.to eq(title) }
- end
-
- context 'without title' do
- it { is_expected.to eq('') }
- end
- end
-
- describe '#metric_query' do
- subject { presenter.metric_query }
-
- it { is_expected.to be_nil }
- end
-
- describe '#environment_name' do
- subject { presenter.environment_name }
-
- it { is_expected.to be_nil }
- end
-
- describe '#performance_dashboard_link' do
- let(:expected_link) { metrics_project_environments_url(project) }
-
- subject { presenter.performance_dashboard_link }
-
- it { is_expected.to eq(expected_link) }
- end
- end
-
- describe '#metrics_dashboard_url' do
- subject { presenter.metrics_dashboard_url }
-
- context 'for a non-prometheus alert' do
- it { is_expected.to be_nil }
- end
-
- context 'for a self-managed prometheus alert' do
- include_context 'self-managed prometheus alert attributes'
-
- let(:prometheus_payload) { payload }
-
- it { is_expected.to eq(dashboard_url_for_alert) }
- end
-
- context 'for a gitlab-managed prometheus alert' do
- include_context 'gitlab-managed prometheus alert attributes'
-
- let(:prometheus_payload) { payload }
-
- it { is_expected.to eq(dashboard_url_for_alert) }
- end
- end
-end
diff --git a/spec/presenters/release_presenter_spec.rb b/spec/presenters/release_presenter_spec.rb
index 5577b3ad2e8..eb4d755205b 100644
--- a/spec/presenters/release_presenter_spec.rb
+++ b/spec/presenters/release_presenter_spec.rb
@@ -57,14 +57,6 @@ RSpec.describe ReleasePresenter do
it 'returns its own url' do
is_expected.to match /#{project_release_url(project, release)}/
end
-
- context 'when release_show_page feature flag is disabled' do
- before do
- stub_feature_flags(release_show_page: false)
- end
-
- it { is_expected.to be_nil }
- end
end
describe '#merge_requests_url' do
diff --git a/spec/presenters/sentry_error_presenter_spec.rb b/spec/presenters/sentry_error_presenter_spec.rb
index af9e7c8a2b2..86e43be1fa7 100644
--- a/spec/presenters/sentry_error_presenter_spec.rb
+++ b/spec/presenters/sentry_error_presenter_spec.rb
@@ -26,4 +26,12 @@ RSpec.describe SentryErrorPresenter do
expect(count).to eq error.frequency.first[1]
end
end
+
+ describe '#project_id' do
+ subject { presenter.project_id }
+
+ it 'returns a global ID of the correct type' do
+ expect(subject).to eq(Gitlab::GlobalId.build(model_name: 'SentryProject', id: error.project_id).to_s)
+ end
+ end
end
diff --git a/spec/presenters/snippet_blob_presenter_spec.rb b/spec/presenters/snippet_blob_presenter_spec.rb
index 915f43fe572..83fe37effc0 100644
--- a/spec/presenters/snippet_blob_presenter_spec.rb
+++ b/spec/presenters/snippet_blob_presenter_spec.rb
@@ -3,70 +3,75 @@
require 'spec_helper'
RSpec.describe SnippetBlobPresenter do
+ let_it_be(:snippet) { create(:personal_snippet, :repository) }
+
+ let(:branch) { snippet.default_branch }
+ let(:blob) { snippet.blobs.first }
+
describe '#rich_data' do
+ let(:data_endpoint_url) { "/-/snippets/#{snippet.id}/raw/#{branch}/#{file}" }
+
before do
allow_next_instance_of(described_class) do |instance|
allow(instance).to receive(:current_user).and_return(nil)
end
+
+ blob.name = File.basename(file)
+ blob.path = file
end
- subject { described_class.new(snippet.blob).rich_data }
+ subject { described_class.new(blob).rich_data }
context 'with PersonalSnippet' do
- let(:snippet) { create(:personal_snippet, :repository) }
-
context 'when blob is binary' do
- it 'returns the HTML associated with the binary' do
- allow(snippet).to receive(:blob).and_return(snippet.repository.blob_at('master', 'files/images/logo-black.png'))
+ let(:file) { 'files/images/logo-black.png' }
+ let(:blob) { blob_at(file) }
+ it 'returns the HTML associated with the binary' do
expect(subject).to include('file-content image_file')
end
end
context 'with markdown format' do
- let(:snippet) { create(:personal_snippet, file_name: 'test.md', content: '*foo*') }
+ let(:file) { 'README.md' }
+ let(:blob) { blob_at(file) }
it 'returns rich markdown content' do
- expected = <<~HTML
- <div class="file-content md">
- <p data-sourcepos="1:1-1:5" dir="auto"><em>foo</em></p>
- </div>
- HTML
-
- expect(subject).to eq(expected)
+ expect(subject).to include('file-content md')
end
end
context 'with notebook format' do
- let(:snippet) { create(:personal_snippet, file_name: 'test.ipynb') }
+ let(:file) { 'test.ipynb' }
it 'returns rich notebook content' do
- expect(subject.strip).to eq %Q(<div class="file-content" data-endpoint="/-/snippets/#{snippet.id}/raw" id="js-notebook-viewer"></div>)
+ expect(subject.strip).to eq %Q(<div class="file-content" data-endpoint="#{data_endpoint_url}" id="js-notebook-viewer"></div>)
end
end
context 'with openapi format' do
- let(:snippet) { create(:personal_snippet, file_name: 'openapi.yml') }
+ let(:file) { 'openapi.yml' }
it 'returns rich openapi content' do
- expect(subject).to eq %Q(<div class="file-content" data-endpoint="/-/snippets/#{snippet.id}/raw" id="js-openapi-viewer"></div>\n)
+ expect(subject).to eq %Q(<div class="file-content" data-endpoint="#{data_endpoint_url}" id="js-openapi-viewer"></div>\n)
end
end
context 'with svg format' do
- let(:snippet) { create(:personal_snippet, file_name: 'test.svg') }
+ let(:file) { 'files/images/wm.svg' }
+ let(:blob) { blob_at(file) }
it 'returns rich svg content' do
result = Nokogiri::HTML::DocumentFragment.parse(subject)
image_tag = result.search('img').first
- expect(image_tag.attr('src')).to include("data:#{snippet.blob.mime_type};base64")
- expect(image_tag.attr('alt')).to eq('test.svg')
+ expect(image_tag.attr('src')).to include("data:#{blob.mime_type};base64")
+ expect(image_tag.attr('alt')).to eq(File.basename(file))
end
end
context 'with other format' do
- let(:snippet) { create(:personal_snippet, file_name: 'test') }
+ let(:file) { 'test' }
it 'does not return no rich content' do
expect(subject).to be_nil
@@ -76,36 +81,41 @@ RSpec.describe SnippetBlobPresenter do
end
describe '#plain_data' do
- let(:snippet) { build(:personal_snippet) }
+ let(:blob) { blob_at(file) }
- subject { described_class.new(snippet.blob).plain_data }
+ subject { described_class.new(blob).plain_data }
- it 'returns nil when the snippet blob is binary' do
- allow(snippet.blob).to receive(:binary?).and_return(true)
+ context 'when blob is binary' do
+ let(:file) { 'files/images/logo-black.png' }
- expect(subject).to be_nil
+ it 'returns nil' do
+ expect(subject).to be_nil
+ end
end
- it 'returns plain content when snippet file is markup' do
- snippet.file_name = 'test.md'
- snippet.content = '*foo*'
+ context 'when blob is markup' do
+ let(:file) { 'README.md' }
- expect(subject).to eq '<span id="LC1" class="line" lang="markdown"><span class="ge">*foo*</span></span>'
+ it 'returns plain content' do
+ expect(subject).to include('<span id="LC1" class="line" lang="markdown">')
+ end
end
- it 'returns highlighted syntax content' do
- snippet.file_name = 'test.rb'
- snippet.content = 'class Foo;end'
+ context 'when blob has syntax' do
+ let(:file) { 'files/ruby/regex.rb' }
- expect(subject)
- .to eq '<span id="LC1" class="line" lang="ruby"><span class="k">class</span> <span class="nc">Foo</span><span class="p">;</span><span class="k">end</span></span>'
+ it 'returns highlighted syntax content' do
+ expect(subject)
+ .to include '<span id="LC1" class="line" lang="ruby"><span class="k">module</span> <span class="nn">Gitlab</span>'
+ end
end
- it 'returns plain text highlighted content' do
- snippet.file_name = 'test'
- snippet.content = 'foo'
+ context 'when blob has plain data' do
+ let(:file) { 'LICENSE' }
- expect(subject).to eq '<span id="LC1" class="line" lang="plaintext">foo</span>'
+ it 'returns plain text highlighted content' do
+ expect(subject).to include('<span id="LC1" class="line" lang="plaintext">The MIT License (MIT)</span>')
+ end
end
end
@@ -115,40 +125,42 @@ RSpec.describe SnippetBlobPresenter do
let_it_be(:personal_snippet) { create(:personal_snippet, :repository, author: user) }
let_it_be(:project_snippet) { create(:project_snippet, :repository, project: project, author: user) }
+ let(:blob) { snippet.blobs.first }
+
before do
project.add_developer(user)
end
describe '#raw_path' do
- subject { described_class.new(snippet.blobs.first, current_user: user).raw_path }
+ subject { described_class.new(blob, current_user: user).raw_path }
it_behaves_like 'snippet blob raw path'
- context 'with snippet_multiple_files feature disabled' do
- before do
- stub_feature_flags(snippet_multiple_files: false)
- end
+ context 'with a snippet without a repository' do
+ let(:personal_snippet) { build(:personal_snippet, author: user, id: 1) }
+ let(:project_snippet) { build(:project_snippet, project: project, author: user, id: 1) }
+ let(:blob) { snippet.blob }
context 'with ProjectSnippet' do
let(:snippet) { project_snippet }
- it 'returns the raw path' do
- expect(subject).to eq "/#{snippet.project.full_path}/-/snippets/#{snippet.id}/raw"
+ it 'returns the raw project snippet path' do
+ expect(subject).to eq("/#{project_snippet.project.full_path}/-/snippets/#{project_snippet.id}/raw")
end
end
context 'with PersonalSnippet' do
let(:snippet) { personal_snippet }
- it 'returns the raw path' do
- expect(subject).to eq "/-/snippets/#{snippet.id}/raw"
+ it 'returns the raw personal snippet path' do
+ expect(subject).to eq("/-/snippets/#{personal_snippet.id}/raw")
end
end
end
end
describe '#raw_url' do
- subject { described_class.new(snippet.blobs.first, current_user: user).raw_url }
+ subject { described_class.new(blob, current_user: user).raw_url }
before do
stub_default_url_options(host: 'test.host')
@@ -156,10 +168,10 @@ RSpec.describe SnippetBlobPresenter do
it_behaves_like 'snippet blob raw url'
- context 'with snippet_multiple_files feature disabled' do
- before do
- stub_feature_flags(snippet_multiple_files: false)
- end
+ context 'with a snippet without a repository' do
+ let(:personal_snippet) { build(:personal_snippet, author: user, id: 1) }
+ let(:project_snippet) { build(:project_snippet, project: project, author: user, id: 1) }
+ let(:blob) { snippet.blob }
context 'with ProjectSnippet' do
let(:snippet) { project_snippet }
@@ -179,4 +191,8 @@ RSpec.describe SnippetBlobPresenter do
end
end
end
+
+ def blob_at(path)
+ snippet.repository.blob_at(branch, path)
+ end
end
diff --git a/spec/presenters/snippet_presenter_spec.rb b/spec/presenters/snippet_presenter_spec.rb
index 681564ed2b0..66c6ba8fa0e 100644
--- a/spec/presenters/snippet_presenter_spec.rb
+++ b/spec/presenters/snippet_presenter_spec.rb
@@ -163,25 +163,4 @@ RSpec.describe SnippetPresenter do
end
end
end
-
- describe '#blobs' do
- let(:snippet) { personal_snippet }
-
- subject { presenter.blobs }
-
- context 'when snippet does not have a repository' do
- it 'returns an array with one SnippetBlob' do
- expect(subject.size).to eq(1)
- expect(subject.first).to eq(snippet.blob)
- end
- end
-
- context 'when snippet has a repository' do
- let(:snippet) { create(:snippet, :repository, author: user) }
-
- it 'returns an array with all repository blobs' do
- expect(subject).to match_array(snippet.blobs)
- end
- end
- end
end
diff --git a/spec/requests/api/admin/instance_clusters_spec.rb b/spec/requests/api/admin/instance_clusters_spec.rb
index b68541b5d92..9d0661089a9 100644
--- a/spec/requests/api/admin/instance_clusters_spec.rb
+++ b/spec/requests/api/admin/instance_clusters_spec.rb
@@ -162,6 +162,7 @@ RSpec.describe ::API::Admin::InstanceClusters do
name: 'test-instance-cluster',
domain: 'domain.example.com',
managed: false,
+ namespace_per_environment: false,
platform_kubernetes_attributes: platform_kubernetes_attributes,
clusterable: clusterable
}
@@ -206,6 +207,7 @@ RSpec.describe ::API::Admin::InstanceClusters do
expect(cluster_result.enabled).to eq(true)
expect(platform_kubernetes.authorization_type).to eq('rbac')
expect(cluster_result.managed).to be_falsy
+ expect(cluster_result.namespace_per_environment).to eq(false)
expect(platform_kubernetes.api_url).to eq("https://example.com")
expect(platform_kubernetes.token).to eq('sample-token')
end
@@ -235,6 +237,22 @@ RSpec.describe ::API::Admin::InstanceClusters do
end
end
+ context 'when namespace_per_environment is not set' do
+ let(:cluster_params) do
+ {
+ name: 'test-cluster',
+ domain: 'domain.example.com',
+ platform_kubernetes_attributes: platform_kubernetes_attributes
+ }
+ end
+
+ it 'defaults to true' do
+ cluster_result = Clusters::Cluster.find(json_response['id'])
+
+ expect(cluster_result).to be_namespace_per_environment
+ end
+ end
+
context 'when an instance cluster already exists' do
it 'allows user to add multiple clusters' do
post api('/admin/clusters/add', admin_user), params: multiple_cluster_params
diff --git a/spec/requests/api/api_guard/response_coercer_middleware_spec.rb b/spec/requests/api/api_guard/response_coercer_middleware_spec.rb
new file mode 100644
index 00000000000..6f3f97fe846
--- /dev/null
+++ b/spec/requests/api/api_guard/response_coercer_middleware_spec.rb
@@ -0,0 +1,55 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe API::APIGuard::ResponseCoercerMiddleware do
+ using RSpec::Parameterized::TableSyntax
+
+ it 'is loaded' do
+ expect(API::API.middleware).to include([:use, described_class])
+ end
+
+ describe '#call' do
+ let(:app) do
+ Class.new(API::API)
+ end
+
+ [
+ nil, 201, 10.5, "test"
+ ].each do |val|
+ it 'returns a String body' do
+ app.get 'bodytest' do
+ status 200
+ env['api.format'] = :binary
+ body val
+ end
+
+ unless val.is_a?(String)
+ expect(Gitlab::ErrorTracking).to receive(:track_and_raise_for_dev_exception).with(instance_of(ArgumentError))
+ end
+
+ get api('/bodytest')
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response.body).to eq(val.to_s)
+ end
+ end
+
+ [100, 204, 304].each do |status|
+ it 'allows nil body' do
+ app.get 'statustest' do
+ status status
+ env['api.format'] = :binary
+ body nil
+ end
+
+ expect(Gitlab::ErrorTracking).not_to receive(:track_and_raise_for_dev_exception)
+
+ get api('/statustest')
+
+ expect(response.status).to eq(status)
+ expect(response.body).to eq('')
+ end
+ end
+ end
+end
diff --git a/spec/requests/api/ci/runner/jobs_artifacts_spec.rb b/spec/requests/api/ci/runner/jobs_artifacts_spec.rb
index 97110b63ff6..71be0c30f5a 100644
--- a/spec/requests/api/ci/runner/jobs_artifacts_spec.rb
+++ b/spec/requests/api/ci/runner/jobs_artifacts_spec.rb
@@ -227,10 +227,6 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do
end
context 'authorize uploading of an lsif artifact' do
- before do
- stub_feature_flags(code_navigation: job.project)
- end
-
it 'adds ProcessLsif header' do
authorize_artifacts_with_token_in_headers(artifact_type: :lsif)
@@ -249,32 +245,6 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do
.to change { Gitlab::UsageDataCounters::HLLRedisCounter.unique_events(tracking_params) }
.by(1)
end
-
- context 'code_navigation feature flag is disabled' do
- before do
- stub_feature_flags(code_navigation: false)
- end
-
- it 'responds with a forbidden error' do
- authorize_artifacts_with_token_in_headers(artifact_type: :lsif)
-
- aggregate_failures do
- expect(response).to have_gitlab_http_status(:forbidden)
- expect(json_response['ProcessLsif']).to be_falsy
- end
- end
-
- it 'does not track code_intelligence usage ping' do
- tracking_params = {
- event_names: 'i_source_code_code_intelligence',
- start_date: Date.yesterday,
- end_date: Date.today
- }
-
- expect { authorize_artifacts_with_token_in_headers(artifact_type: :lsif) }
- .not_to change { Gitlab::UsageDataCounters::HLLRedisCounter.unique_events(tracking_params) }
- end
- end
end
def authorize_artifacts(params = {}, request_headers = headers)
diff --git a/spec/requests/api/ci/runner/jobs_put_spec.rb b/spec/requests/api/ci/runner/jobs_put_spec.rb
index 183a3b26e00..cbefaa2c321 100644
--- a/spec/requests/api/ci/runner/jobs_put_spec.rb
+++ b/spec/requests/api/ci/runner/jobs_put_spec.rb
@@ -46,64 +46,59 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do
end
context 'when status is given' do
- it 'mark job as succeeded' do
+ it 'marks job as succeeded' do
update_job(state: 'success')
- job.reload
- expect(job).to be_success
+ expect(job.reload).to be_success
+ expect(response.header).not_to have_key('X-GitLab-Trace-Update-Interval')
end
- it 'mark job as failed' do
+ it 'marks job as failed' do
update_job(state: 'failed')
- job.reload
- expect(job).to be_failed
+ expect(job.reload).to be_failed
expect(job).to be_unknown_failure
+ expect(response.header).not_to have_key('X-GitLab-Trace-Update-Interval')
end
context 'when failure_reason is script_failure' do
before do
update_job(state: 'failed', failure_reason: 'script_failure')
- job.reload
end
- it { expect(job).to be_script_failure }
+ it { expect(job.reload).to be_script_failure }
end
context 'when failure_reason is runner_system_failure' do
before do
update_job(state: 'failed', failure_reason: 'runner_system_failure')
- job.reload
end
- it { expect(job).to be_runner_system_failure }
+ it { expect(job.reload).to be_runner_system_failure }
end
context 'when failure_reason is unrecognized value' do
before do
update_job(state: 'failed', failure_reason: 'what_is_this')
- job.reload
end
- it { expect(job).to be_unknown_failure }
+ it { expect(job.reload).to be_unknown_failure }
end
context 'when failure_reason is job_execution_timeout' do
before do
update_job(state: 'failed', failure_reason: 'job_execution_timeout')
- job.reload
end
- it { expect(job).to be_job_execution_timeout }
+ it { expect(job.reload).to be_job_execution_timeout }
end
context 'when failure_reason is unmet_prerequisites' do
before do
update_job(state: 'failed', failure_reason: 'unmet_prerequisites')
- job.reload
end
- it { expect(job).to be_unmet_prerequisites }
+ it { expect(job.reload).to be_unmet_prerequisites }
end
context 'when unmigrated live trace chunks exist' do
@@ -119,24 +114,21 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do
expect(job.pending_state).to be_present
expect(response).to have_gitlab_http_status(:accepted)
+ expect(response.header['X-GitLab-Trace-Update-Interval']).to be > 0
end
end
context 'when runner retries request after receiving 202' do
it 'responds with 202 and then with 200', :sidekiq_inline do
- perform_enqueued_jobs do
- update_job(state: 'success', checksum: 'crc32:12345678')
- end
+ update_job(state: 'success', checksum: 'crc32:12345678')
- expect(job.reload.pending_state).to be_present
expect(response).to have_gitlab_http_status(:accepted)
+ expect(job.reload.pending_state).to be_present
- perform_enqueued_jobs do
- update_job(state: 'success', checksum: 'crc32:12345678')
- end
+ update_job(state: 'success', checksum: 'crc32:12345678')
- expect(job.reload.pending_state).not_to be_present
expect(response).to have_gitlab_http_status(:ok)
+ expect(job.reload.pending_state).not_to be_present
end
end
@@ -149,8 +141,9 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do
update_job(state: 'success', checksum: 'crc:12345678')
expect(job.reload).to be_success
- expect(job.pending_state).not_to be_present
+ expect(job.pending_state).to be_present
expect(response).to have_gitlab_http_status(:ok)
+ expect(response.header).not_to have_key('X-GitLab-Trace-Update-Interval')
end
end
end
@@ -248,7 +241,7 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do
end
def update_job_after_time(update_interval = 20.minutes, state = 'running')
- Timecop.travel(job.updated_at + update_interval) do
+ travel_to(job.updated_at + update_interval) do
update_job(job.token, state: state)
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 4fa95f8ebb2..2dc92417892 100644
--- a/spec/requests/api/ci/runner/jobs_request_post_spec.rb
+++ b/spec/requests/api/ci/runner/jobs_request_post_spec.rb
@@ -194,7 +194,8 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do
[{ 'key' => 'cache_key',
'untracked' => false,
'paths' => ['vendor/*'],
- 'policy' => 'pull-push' }]
+ 'policy' => 'pull-push',
+ 'when' => 'on_success' }]
end
let(:expected_features) { { 'trace_sections' => true } }
diff --git a/spec/requests/api/commits_spec.rb b/spec/requests/api/commits_spec.rb
index d34244771ad..d455ed9c194 100644
--- a/spec/requests/api/commits_spec.rb
+++ b/spec/requests/api/commits_spec.rb
@@ -36,13 +36,9 @@ RSpec.describe API::Commits do
end
it 'include correct pagination headers' do
- commit_count = project.repository.count_commits(ref: 'master').to_s
-
get api(route, current_user)
- expect(response).to include_pagination_headers
- expect(response.headers['X-Total']).to eq(commit_count)
- expect(response.headers['X-Page']).to eql('1')
+ expect(response).to include_limited_pagination_headers
end
end
@@ -79,12 +75,10 @@ RSpec.describe API::Commits do
it 'include correct pagination headers' do
commits = project.repository.commits("master", limit: 2)
after = commits.second.created_at
- commit_count = project.repository.count_commits(ref: 'master', after: after).to_s
get api("/projects/#{project_id}/repository/commits?since=#{after.utc.iso8601}", user)
- expect(response).to include_pagination_headers
- expect(response.headers['X-Total']).to eq(commit_count)
+ expect(response).to include_limited_pagination_headers
expect(response.headers['X-Page']).to eql('1')
end
end
@@ -109,12 +103,10 @@ RSpec.describe API::Commits do
it 'include correct pagination headers' do
commits = project.repository.commits("master", limit: 2)
before = commits.second.created_at
- commit_count = project.repository.count_commits(ref: 'master', before: before).to_s
get api("/projects/#{project_id}/repository/commits?until=#{before.utc.iso8601}", user)
- expect(response).to include_pagination_headers
- expect(response.headers['X-Total']).to eq(commit_count)
+ expect(response).to include_limited_pagination_headers
expect(response.headers['X-Page']).to eql('1')
end
end
@@ -137,49 +129,49 @@ RSpec.describe API::Commits do
context "path optional parameter" do
it "returns project commits matching provided path parameter" do
path = 'files/ruby/popen.rb'
- commit_count = project.repository.count_commits(ref: 'master', path: path).to_s
get api("/projects/#{project_id}/repository/commits?path=#{path}", user)
expect(json_response.size).to eq(3)
expect(json_response.first["id"]).to eq("570e7b2abdd848b95f2f578043fc23bd6f6fd24d")
- expect(response).to include_pagination_headers
- expect(response.headers['X-Total']).to eq(commit_count)
+ expect(response).to include_limited_pagination_headers
end
it 'include correct pagination headers' do
path = 'files/ruby/popen.rb'
- commit_count = project.repository.count_commits(ref: 'master', path: path).to_s
get api("/projects/#{project_id}/repository/commits?path=#{path}", user)
- expect(response).to include_pagination_headers
- expect(response.headers['X-Total']).to eq(commit_count)
+ expect(response).to include_limited_pagination_headers
expect(response.headers['X-Page']).to eql('1')
end
end
context 'all optional parameter' do
it 'returns all project commits' do
- commit_count = project.repository.count_commits(all: true)
+ expected_commit_ids = project.repository.commits(nil, all: true, limit: 50).map(&:id)
+
+ get api("/projects/#{project_id}/repository/commits?all=true&per_page=50", user)
- get api("/projects/#{project_id}/repository/commits?all=true", user)
+ commit_ids = json_response.map { |c| c['id'] }
- expect(response).to include_pagination_headers
- expect(response.headers['X-Total']).to eq(commit_count.to_s)
+ expect(response).to include_limited_pagination_headers
+ expect(commit_ids).to eq(expected_commit_ids)
expect(response.headers['X-Page']).to eql('1')
end
end
context 'first_parent optional parameter' do
it 'returns all first_parent commits' do
- commit_count = project.repository.count_commits(ref: SeedRepo::Commit::ID, first_parent: true)
+ expected_commit_ids = project.repository.commits(SeedRepo::Commit::ID, limit: 50, first_parent: true).map(&:id)
- get api("/projects/#{project_id}/repository/commits", user), params: { ref_name: SeedRepo::Commit::ID, first_parent: 'true' }
+ get api("/projects/#{project_id}/repository/commits?per_page=50", user), params: { ref_name: SeedRepo::Commit::ID, first_parent: 'true' }
- expect(response).to include_pagination_headers
- expect(commit_count).to eq(12)
- expect(response.headers['X-Total']).to eq(commit_count.to_s)
+ commit_ids = json_response.map { |c| c['id'] }
+
+ expect(response).to include_limited_pagination_headers
+ expect(expected_commit_ids.size).to eq(12)
+ expect(commit_ids).to eq(expected_commit_ids)
end
end
@@ -209,11 +201,7 @@ RSpec.describe API::Commits do
end
it 'returns correct headers' do
- commit_count = project.repository.count_commits(ref: ref_name).to_s
-
- expect(response).to include_pagination_headers
- expect(response.headers['X-Total']).to eq(commit_count)
- expect(response.headers['X-Page']).to eq('1')
+ expect(response).to include_limited_pagination_headers
expect(response.headers['Link']).to match(/page=1&per_page=5/)
expect(response.headers['Link']).to match(/page=2&per_page=5/)
end
@@ -972,7 +960,7 @@ RSpec.describe API::Commits do
refs.concat(project.repository.tag_names_contains(commit_id).map {|name| ['tag', name]})
expect(response).to have_gitlab_http_status(:ok)
- expect(response).to include_pagination_headers
+ expect(response).to include_limited_pagination_headers
expect(json_response).to be_an Array
expect(json_response.map { |r| [r['type'], r['name']] }.compact).to eq(refs)
end
@@ -1262,7 +1250,7 @@ RSpec.describe API::Commits do
get api(route, current_user)
expect(response).to have_gitlab_http_status(:ok)
- expect(response).to include_pagination_headers
+ expect(response).to include_limited_pagination_headers
expect(json_response.size).to be >= 1
expect(json_response.first.keys).to include 'diff'
end
@@ -1276,7 +1264,7 @@ RSpec.describe API::Commits do
get api(route, current_user)
expect(response).to have_gitlab_http_status(:ok)
- expect(response).to include_pagination_headers
+ expect(response).to include_limited_pagination_headers
expect(json_response.size).to be <= 1
end
end
@@ -1914,7 +1902,7 @@ RSpec.describe API::Commits do
get api("/projects/#{project.id}/repository/commits/#{commit.id}/merge_requests", user)
expect(response).to have_gitlab_http_status(:ok)
- expect(response).to include_pagination_headers
+ expect(response).to include_limited_pagination_headers
expect(json_response.length).to eq(1)
expect(json_response[0]['id']).to eq(merged_mr.id)
end
diff --git a/spec/requests/api/composer_packages_spec.rb b/spec/requests/api/composer_packages_spec.rb
index f5279af0483..ef4682466d5 100644
--- a/spec/requests/api/composer_packages_spec.rb
+++ b/spec/requests/api/composer_packages_spec.rb
@@ -289,6 +289,34 @@ RSpec.describe API::ComposerPackages do
it_behaves_like 'process Composer api request', :developer, :not_found
end
end
+
+ context 'with invalid composer.json' do
+ let(:headers) { basic_auth_header(user.username, personal_access_token.token) }
+ let(:params) { { tag: 'v1.2.99' } }
+ let(:project) { create(:project, :custom_repo, files: files, group: group) }
+
+ before do
+ project.repository.add_tag(user, 'v1.2.99', 'master')
+ end
+
+ context 'with a missing composer.json file' do
+ let(:files) { { 'some_other_file' => '' } }
+
+ it_behaves_like 'process Composer api request', :developer, :unprocessable_entity
+ end
+
+ context 'with an empty composer.json file' do
+ let(:files) { { 'composer.json' => '' } }
+
+ it_behaves_like 'process Composer api request', :developer, :unprocessable_entity
+ end
+
+ context 'with a malformed composer.json file' do
+ let(:files) { { 'composer.json' => 'not_valid_JSON' } }
+
+ it_behaves_like 'process Composer api request', :developer, :unprocessable_entity
+ end
+ end
end
describe 'GET /api/v4/projects/:id/packages/composer/archives/*package_name?sha=:sha' do
diff --git a/spec/requests/api/debian_group_packages_spec.rb b/spec/requests/api/debian_group_packages_spec.rb
new file mode 100644
index 00000000000..8a05d20fb33
--- /dev/null
+++ b/spec/requests/api/debian_group_packages_spec.rb
@@ -0,0 +1,39 @@
+# frozen_string_literal: true
+require 'spec_helper'
+
+RSpec.describe API::DebianGroupPackages do
+ include HttpBasicAuthHelpers
+ include WorkhorseHelpers
+
+ include_context 'Debian repository shared context', :group do
+ describe 'GET groups/:id/-/packages/debian/dists/*distribution/Release.gpg' do
+ let(:url) { "/groups/#{group.id}/-/packages/debian/dists/#{distribution}/Release.gpg" }
+
+ it_behaves_like 'Debian group repository GET endpoint', :not_found, nil
+ end
+
+ describe 'GET groups/:id/-/packages/debian/dists/*distribution/Release' do
+ let(:url) { "/groups/#{group.id}/-/packages/debian/dists/#{distribution}/Release" }
+
+ it_behaves_like 'Debian group repository GET endpoint', :success, 'TODO Release'
+ end
+
+ describe 'GET groups/:id/-/packages/debian/dists/*distribution/InRelease' do
+ let(:url) { "/groups/#{group.id}/-/packages/debian/dists/#{distribution}/InRelease" }
+
+ it_behaves_like 'Debian group repository GET endpoint', :not_found, nil
+ end
+
+ describe 'GET groups/:id/-/packages/debian/dists/*distribution/:component/binary-:architecture/Packages' do
+ let(:url) { "/groups/#{group.id}/-/packages/debian/dists/#{distribution}/#{component}/binary-#{architecture}/Packages" }
+
+ it_behaves_like 'Debian group repository GET endpoint', :success, 'TODO Packages'
+ end
+
+ describe 'GET groups/:id/-/packages/debian/pool/:component/:letter/:source_package/:file_name' do
+ let(:url) { "/groups/#{group.id}/-/packages/debian/pool/#{component}/#{letter}/#{source_package}/#{package_name}_#{package_version}_#{architecture}.deb" }
+
+ it_behaves_like 'Debian group repository GET endpoint', :success, 'TODO File'
+ end
+ end
+end
diff --git a/spec/requests/api/debian_project_packages_spec.rb b/spec/requests/api/debian_project_packages_spec.rb
new file mode 100644
index 00000000000..d2f208d0079
--- /dev/null
+++ b/spec/requests/api/debian_project_packages_spec.rb
@@ -0,0 +1,46 @@
+# frozen_string_literal: true
+require 'spec_helper'
+
+RSpec.describe API::DebianProjectPackages do
+ include HttpBasicAuthHelpers
+ include WorkhorseHelpers
+
+ include_context 'Debian repository shared context', :project do
+ describe 'GET projects/:id/-/packages/debian/dists/*distribution/Release.gpg' do
+ let(:url) { "/projects/#{project.id}/-/packages/debian/dists/#{distribution}/Release.gpg" }
+
+ it_behaves_like 'Debian project repository GET endpoint', :not_found, nil
+ end
+
+ describe 'GET projects/:id/-/packages/debian/dists/*distribution/Release' do
+ let(:url) { "/projects/#{project.id}/-/packages/debian/dists/#{distribution}/Release" }
+
+ it_behaves_like 'Debian project repository GET endpoint', :success, 'TODO Release'
+ end
+
+ describe 'GET projects/:id/-/packages/debian/dists/*distribution/InRelease' do
+ let(:url) { "/projects/#{project.id}/-/packages/debian/dists/#{distribution}/InRelease" }
+
+ it_behaves_like 'Debian project repository GET endpoint', :not_found, nil
+ end
+
+ describe 'GET projects/:id/-/packages/debian/dists/*distribution/:component/binary-:architecture/Packages' do
+ let(:url) { "/projects/#{project.id}/-/packages/debian/dists/#{distribution}/#{component}/binary-#{architecture}/Packages" }
+
+ it_behaves_like 'Debian project repository GET endpoint', :success, 'TODO Packages'
+ end
+
+ describe 'GET projects/:id/-/packages/debian/pool/:component/:letter/:source_package/:file_name' do
+ let(:url) { "/projects/#{project.id}/-/packages/debian/pool/#{component}/#{letter}/#{source_package}/#{package_name}_#{package_version}_#{architecture}.deb" }
+
+ it_behaves_like 'Debian project repository GET endpoint', :success, 'TODO File'
+ end
+
+ describe 'PUT projects/:id/-/packages/debian/incoming/:file_name' do
+ let(:method) { :put }
+ let(:url) { "/projects/#{project.id}/-/packages/debian/incoming/#{file_name}" }
+
+ it_behaves_like 'Debian project repository PUT endpoint', :created, nil
+ end
+ end
+end
diff --git a/spec/requests/api/doorkeeper_access_spec.rb b/spec/requests/api/doorkeeper_access_spec.rb
index f16cd58bb34..77f1dadff46 100644
--- a/spec/requests/api/doorkeeper_access_spec.rb
+++ b/spec/requests/api/doorkeeper_access_spec.rb
@@ -71,4 +71,12 @@ RSpec.describe 'doorkeeper access' do
it_behaves_like 'forbidden request'
end
+
+ context 'when user is blocked pending approval' do
+ before do
+ user.block_pending_approval
+ end
+
+ it_behaves_like 'forbidden request'
+ end
end
diff --git a/spec/requests/api/feature_flag_scopes_spec.rb b/spec/requests/api/feature_flag_scopes_spec.rb
new file mode 100644
index 00000000000..da5b2cbb7ae
--- /dev/null
+++ b/spec/requests/api/feature_flag_scopes_spec.rb
@@ -0,0 +1,319 @@
+# frozen_string_literal: true
+require 'spec_helper'
+
+RSpec.describe API::FeatureFlagScopes do
+ include FeatureFlagHelpers
+
+ let(:project) { create(:project, :repository) }
+ let(:developer) { create(:user) }
+ let(:reporter) { create(:user) }
+ let(:user) { developer }
+
+ before do
+ project.add_developer(developer)
+ project.add_reporter(reporter)
+ end
+
+ shared_examples_for 'check user permission' do
+ context 'when user is reporter' do
+ let(:user) { reporter }
+
+ it 'forbids the request' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ end
+ end
+ end
+
+ shared_examples_for 'not found' do
+ it 'returns Not Found' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+
+ describe 'GET /projects/:id/feature_flag_scopes' do
+ subject do
+ get api("/projects/#{project.id}/feature_flag_scopes", user),
+ params: params
+ end
+
+ let(:feature_flag_1) { create_flag(project, 'flag_1', true) }
+ let(:feature_flag_2) { create_flag(project, 'flag_2', true) }
+
+ before do
+ create_scope(feature_flag_1, 'staging', false)
+ create_scope(feature_flag_1, 'production', true)
+ create_scope(feature_flag_2, 'review/*', false)
+ end
+
+ context 'when environment is production' do
+ let(:params) { { environment: 'production' } }
+
+ it_behaves_like 'check user permission'
+
+ it 'returns all effective feature flags under the environment' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to match_response_schema('public_api/v4/feature_flag_detailed_scopes')
+ expect(json_response.second).to include({ 'name' => 'flag_1', 'active' => true })
+ expect(json_response.first).to include({ 'name' => 'flag_2', 'active' => true })
+ end
+ end
+
+ context 'when environment is staging' do
+ let(:params) { { environment: 'staging' } }
+
+ it 'returns all effective feature flags under the environment' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response.second).to include({ 'name' => 'flag_1', 'active' => false })
+ expect(json_response.first).to include({ 'name' => 'flag_2', 'active' => true })
+ end
+ end
+
+ context 'when environment is review/feature X' do
+ let(:params) { { environment: 'review/feature X' } }
+
+ it 'returns all effective feature flags under the environment' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response.second).to include({ 'name' => 'flag_1', 'active' => true })
+ expect(json_response.first).to include({ 'name' => 'flag_2', 'active' => false })
+ end
+ end
+ end
+
+ describe 'GET /projects/:id/feature_flags/:name/scopes' do
+ subject do
+ get api("/projects/#{project.id}/feature_flags/#{feature_flag.name}/scopes", user)
+ end
+
+ context 'when there are two scopes' do
+ let(:feature_flag) { create_flag(project, 'test') }
+ let!(:additional_scope) { create_scope(feature_flag, 'production', false) }
+
+ it_behaves_like 'check user permission'
+
+ it 'returns scopes of the feature flag' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to match_response_schema('public_api/v4/feature_flag_scopes')
+ expect(json_response.count).to eq(2)
+ expect(json_response.first['environment_scope']).to eq(feature_flag.scopes[0].environment_scope)
+ expect(json_response.second['environment_scope']).to eq(feature_flag.scopes[1].environment_scope)
+ end
+ end
+
+ context 'when there are no feature flags' do
+ let(:feature_flag) { double(:feature_flag, name: 'test') }
+
+ it_behaves_like 'not found'
+ end
+ end
+
+ describe 'POST /projects/:id/feature_flags/:name/scopes' do
+ subject do
+ post api("/projects/#{project.id}/feature_flags/#{feature_flag.name}/scopes", user),
+ params: params
+ end
+
+ let(:params) do
+ {
+ environment_scope: 'staging',
+ active: true,
+ strategies: [{ name: 'userWithId', parameters: { 'userIds': 'a,b,c' } }].to_json
+ }
+ end
+
+ context 'when there is a corresponding feature flag' do
+ let!(:feature_flag) { create(:operations_feature_flag, project: project) }
+
+ it_behaves_like 'check user permission'
+
+ it 'creates a new scope' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:created)
+ expect(response).to match_response_schema('public_api/v4/feature_flag_scope')
+ expect(json_response['environment_scope']).to eq(params[:environment_scope])
+ expect(json_response['active']).to eq(params[:active])
+ expect(json_response['strategies']).to eq(Gitlab::Json.parse(params[:strategies]))
+ end
+
+ context 'when the scope already exists' do
+ before do
+ create_scope(feature_flag, params[:environment_scope])
+ end
+
+ it 'returns error' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ expect(json_response['message']).to include('Scopes environment scope (staging) has already been taken')
+ end
+ end
+ end
+
+ context 'when feature flag is not found' do
+ let(:feature_flag) { double(:feature_flag, name: 'test') }
+
+ it_behaves_like 'not found'
+ end
+ end
+
+ describe 'GET /projects/:id/feature_flags/:name/scopes/:environment_scope' do
+ subject do
+ get api("/projects/#{project.id}/feature_flags/#{feature_flag.name}/scopes/#{environment_scope}",
+ user)
+ end
+
+ let(:environment_scope) { scope.environment_scope }
+
+ shared_examples_for 'successful response' do
+ it 'returns a scope' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to match_response_schema('public_api/v4/feature_flag_scope')
+ expect(json_response['id']).to eq(scope.id)
+ expect(json_response['active']).to eq(scope.active)
+ expect(json_response['environment_scope']).to eq(scope.environment_scope)
+ end
+ end
+
+ context 'when there is a feature flag' do
+ let!(:feature_flag) { create(:operations_feature_flag, project: project) }
+ let(:scope) { feature_flag.default_scope }
+
+ it_behaves_like 'check user permission'
+ it_behaves_like 'successful response'
+
+ context 'when environment scope includes slash' do
+ let!(:scope) { create_scope(feature_flag, 'review/*', false) }
+
+ it_behaves_like 'not found'
+
+ context 'when URL-encoding the environment scope parameter' do
+ let(:environment_scope) { CGI.escape(scope.environment_scope) }
+
+ it_behaves_like 'successful response'
+ end
+ end
+ end
+
+ context 'when there are no feature flags' do
+ let(:feature_flag) { double(:feature_flag, name: 'test') }
+ let(:scope) { double(:feature_flag_scope, environment_scope: 'prd') }
+
+ it_behaves_like 'not found'
+ end
+ end
+
+ describe 'PUT /projects/:id/feature_flags/:name/scopes/:environment_scope' do
+ subject do
+ put api("/projects/#{project.id}/feature_flags/#{feature_flag.name}/scopes/#{environment_scope}",
+ user), params: params
+ end
+
+ let(:environment_scope) { scope.environment_scope }
+
+ let(:params) do
+ {
+ active: true,
+ strategies: [{ name: 'userWithId', parameters: { 'userIds': 'a,b,c' } }].to_json
+ }
+ end
+
+ context 'when there is a corresponding feature flag' do
+ let!(:feature_flag) { create(:operations_feature_flag, project: project) }
+ let(:scope) { create_scope(feature_flag, 'staging', false, [{ name: "default", parameters: {} }]) }
+
+ it_behaves_like 'check user permission'
+
+ it 'returns the updated scope' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to match_response_schema('public_api/v4/feature_flag_scope')
+ expect(json_response['id']).to eq(scope.id)
+ expect(json_response['active']).to eq(params[:active])
+ expect(json_response['strategies']).to eq(Gitlab::Json.parse(params[:strategies]))
+ end
+
+ context 'when there are no corresponding feature flag scopes' do
+ let(:scope) { double(:feature_flag_scope, environment_scope: 'prd') }
+
+ it_behaves_like 'not found'
+ end
+ end
+
+ context 'when there are no corresponding feature flags' do
+ let(:feature_flag) { double(:feature_flag, name: 'test') }
+ let(:scope) { double(:feature_flag_scope, environment_scope: 'prd') }
+
+ it_behaves_like 'not found'
+ end
+ end
+
+ describe 'DELETE /projects/:id/feature_flags/:name/scopes/:environment_scope' do
+ subject do
+ delete api("/projects/#{project.id}/feature_flags/#{feature_flag.name}/scopes/#{environment_scope}",
+ user)
+ end
+
+ let(:environment_scope) { scope.environment_scope }
+
+ shared_examples_for 'successful response' do
+ it 'destroys the scope' do
+ expect { subject }
+ .to change { Operations::FeatureFlagScope.exists?(environment_scope: scope.environment_scope) }
+ .from(true).to(false)
+
+ expect(response).to have_gitlab_http_status(:no_content)
+ end
+ end
+
+ context 'when there is a feature flag' do
+ let!(:feature_flag) { create(:operations_feature_flag, project: project) }
+
+ context 'when there is a targeted scope' do
+ let!(:scope) { create_scope(feature_flag, 'production', false) }
+
+ it_behaves_like 'check user permission'
+ it_behaves_like 'successful response'
+
+ context 'when environment scope includes slash' do
+ let!(:scope) { create_scope(feature_flag, 'review/*', false) }
+
+ it_behaves_like 'not found'
+
+ context 'when URL-encoding the environment scope parameter' do
+ let(:environment_scope) { CGI.escape(scope.environment_scope) }
+
+ it_behaves_like 'successful response'
+ end
+ end
+ end
+
+ context 'when there are no targeted scopes' do
+ let!(:scope) { double(:feature_flag_scope, environment_scope: 'production') }
+
+ it_behaves_like 'not found'
+ end
+ end
+
+ context 'when there are no feature flags' do
+ let(:feature_flag) { double(:feature_flag, name: 'test') }
+ let(:scope) { double(:feature_flag_scope, environment_scope: 'prd') }
+
+ it_behaves_like 'not found'
+ end
+ end
+end
diff --git a/spec/requests/api/feature_flags_spec.rb b/spec/requests/api/feature_flags_spec.rb
new file mode 100644
index 00000000000..90d4a7b8b21
--- /dev/null
+++ b/spec/requests/api/feature_flags_spec.rb
@@ -0,0 +1,1130 @@
+# frozen_string_literal: true
+require 'spec_helper'
+
+RSpec.describe API::FeatureFlags do
+ include FeatureFlagHelpers
+
+ let_it_be(:project) { create(:project) }
+ let_it_be(:developer) { create(:user) }
+ let_it_be(:reporter) { create(:user) }
+ let_it_be(:non_project_member) { create(:user) }
+ let(:user) { developer }
+
+ before_all do
+ project.add_developer(developer)
+ project.add_reporter(reporter)
+ end
+
+ shared_examples_for 'check user permission' do
+ context 'when user is reporter' do
+ let(:user) { reporter }
+
+ it 'forbids the request' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ end
+ end
+ end
+
+ shared_examples_for 'not found' do
+ it 'returns Not Found' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+
+ describe 'GET /projects/:id/feature_flags' do
+ subject { get api("/projects/#{project.id}/feature_flags", user) }
+
+ context 'when there are two feature flags' do
+ let!(:feature_flag_1) do
+ create(:operations_feature_flag, project: project)
+ end
+
+ let!(:feature_flag_2) do
+ create(:operations_feature_flag, project: project)
+ end
+
+ it 'returns feature flags ordered by name' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to match_response_schema('public_api/v4/feature_flags')
+ expect(json_response.count).to eq(2)
+ expect(json_response.first['name']).to eq(feature_flag_1.name)
+ expect(json_response.second['name']).to eq(feature_flag_2.name)
+ end
+
+ it 'returns the legacy flag version' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to match_response_schema('public_api/v4/feature_flags')
+ expect(json_response.map { |f| f['version'] }).to eq(%w[legacy_flag legacy_flag])
+ end
+
+ it 'does not return the legacy flag version when the feature flag is disabled' do
+ stub_feature_flags(feature_flags_new_version: false)
+
+ subject
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to match_response_schema('public_api/v4/feature_flags')
+ expect(json_response.select { |f| f.key?('version') }).to eq([])
+ end
+
+ it 'does not return strategies if the new flag is disabled' do
+ stub_feature_flags(feature_flags_new_version: false)
+
+ subject
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to match_response_schema('public_api/v4/feature_flags')
+ expect(json_response.select { |f| f.key?('strategies') }).to eq([])
+ end
+
+ it 'does not have N+1 problem' do
+ control_count = ActiveRecord::QueryRecorder.new { subject }
+
+ create_list(:operations_feature_flag, 3, project: project)
+
+ expect { get api("/projects/#{project.id}/feature_flags", user) }
+ .not_to exceed_query_limit(control_count)
+ end
+
+ it_behaves_like 'check user permission'
+ end
+
+ context 'with version 2 feature flags' do
+ let!(:feature_flag) do
+ create(:operations_feature_flag, :new_version_flag, project: project, name: 'feature1')
+ end
+
+ let!(:strategy) do
+ create(:operations_strategy, feature_flag: feature_flag, name: 'default', parameters: {})
+ end
+
+ let!(:scope) do
+ create(:operations_scope, strategy: strategy, environment_scope: 'production')
+ end
+
+ it 'returns the feature flags' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to match_response_schema('public_api/v4/feature_flags')
+ expect(json_response).to eq([{
+ 'name' => 'feature1',
+ 'description' => nil,
+ 'active' => true,
+ 'version' => 'new_version_flag',
+ 'updated_at' => feature_flag.updated_at.as_json,
+ 'created_at' => feature_flag.created_at.as_json,
+ 'scopes' => [],
+ 'strategies' => [{
+ 'id' => strategy.id,
+ 'name' => 'default',
+ 'parameters' => {},
+ 'scopes' => [{
+ 'id' => scope.id,
+ 'environment_scope' => 'production'
+ }]
+ }]
+ }])
+ end
+
+ it 'does not return a version 2 flag when the feature flag is disabled' do
+ stub_feature_flags(feature_flags_new_version: false)
+
+ subject
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to match_response_schema('public_api/v4/feature_flags')
+ expect(json_response).to eq([])
+ end
+ end
+
+ context 'with version 1 and 2 feature flags' do
+ it 'returns both versions of flags ordered by name' do
+ create(:operations_feature_flag, project: project, name: 'legacy_flag')
+ feature_flag = create(:operations_feature_flag, :new_version_flag, project: project, name: 'new_version_flag')
+ strategy = create(:operations_strategy, feature_flag: feature_flag, name: 'default', parameters: {})
+ create(:operations_scope, strategy: strategy, environment_scope: 'production')
+
+ subject
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to match_response_schema('public_api/v4/feature_flags')
+ expect(json_response.map { |f| f['name'] }).to eq(%w[legacy_flag new_version_flag])
+ end
+
+ it 'returns only version 1 flags when the feature flag is disabled' do
+ stub_feature_flags(feature_flags_new_version: false)
+ create(:operations_feature_flag, project: project, name: 'legacy_flag')
+ feature_flag = create(:operations_feature_flag, :new_version_flag, project: project, name: 'new_version_flag')
+ strategy = create(:operations_strategy, feature_flag: feature_flag, name: 'default', parameters: {})
+ create(:operations_scope, strategy: strategy, environment_scope: 'production')
+
+ subject
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to match_response_schema('public_api/v4/feature_flags')
+ expect(json_response.map { |f| f['name'] }).to eq(['legacy_flag'])
+ end
+ end
+ end
+
+ describe 'GET /projects/:id/feature_flags/:name' do
+ subject { get api("/projects/#{project.id}/feature_flags/#{feature_flag.name}", user) }
+
+ context 'when there is a feature flag' do
+ let!(:feature_flag) { create_flag(project, 'awesome-feature') }
+
+ it 'returns a feature flag entry' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to match_response_schema('public_api/v4/feature_flag')
+ expect(json_response['name']).to eq(feature_flag.name)
+ expect(json_response['description']).to eq(feature_flag.description)
+ expect(json_response['version']).to eq('legacy_flag')
+ end
+
+ it_behaves_like 'check user permission'
+ end
+
+ context 'with a version 2 feature_flag' do
+ it 'returns the feature flag' do
+ feature_flag = create(:operations_feature_flag, :new_version_flag, project: project, name: 'feature1')
+ strategy = create(:operations_strategy, feature_flag: feature_flag, name: 'default', parameters: {})
+ scope = create(:operations_scope, strategy: strategy, environment_scope: 'production')
+
+ get api("/projects/#{project.id}/feature_flags/feature1", user)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to match_response_schema('public_api/v4/feature_flag')
+ expect(json_response).to eq({
+ 'name' => 'feature1',
+ 'description' => nil,
+ 'active' => true,
+ 'version' => 'new_version_flag',
+ 'updated_at' => feature_flag.updated_at.as_json,
+ 'created_at' => feature_flag.created_at.as_json,
+ 'scopes' => [],
+ 'strategies' => [{
+ 'id' => strategy.id,
+ 'name' => 'default',
+ 'parameters' => {},
+ 'scopes' => [{
+ 'id' => scope.id,
+ 'environment_scope' => 'production'
+ }]
+ }]
+ })
+ end
+
+ it 'returns a 404 when the feature is disabled' do
+ stub_feature_flags(feature_flags_new_version: false)
+ feature_flag = create(:operations_feature_flag, :new_version_flag, project: project, name: 'feature1')
+ strategy = create(:operations_strategy, feature_flag: feature_flag, name: 'default', parameters: {})
+ create(:operations_scope, strategy: strategy, environment_scope: 'production')
+
+ get api("/projects/#{project.id}/feature_flags/feature1", user)
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ expect(json_response).to eq({ 'message' => '404 Not found' })
+ end
+ end
+ end
+
+ describe 'POST /projects/:id/feature_flags' do
+ def scope_default
+ {
+ environment_scope: '*',
+ active: false,
+ strategies: [{ name: 'default', parameters: {} }].to_json
+ }
+ end
+
+ subject do
+ post api("/projects/#{project.id}/feature_flags", user), params: params
+ end
+
+ let(:params) do
+ {
+ name: 'awesome-feature',
+ scopes: [scope_default]
+ }
+ end
+
+ it 'creates a new feature flag' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:created)
+ expect(response).to match_response_schema('public_api/v4/feature_flag')
+
+ feature_flag = project.operations_feature_flags.last
+ expect(feature_flag.name).to eq(params[:name])
+ expect(feature_flag.description).to eq(params[:description])
+ end
+
+ it 'defaults to a version 1 (legacy) feature flag' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:created)
+ expect(response).to match_response_schema('public_api/v4/feature_flag')
+
+ feature_flag = project.operations_feature_flags.last
+ expect(feature_flag.version).to eq('legacy_flag')
+ end
+
+ it_behaves_like 'check user permission'
+
+ it 'returns version' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:created)
+ expect(response).to match_response_schema('public_api/v4/feature_flag')
+ expect(json_response['version']).to eq('legacy_flag')
+ end
+
+ it 'does not return version when new version flags are disabled' do
+ stub_feature_flags(feature_flags_new_version: false)
+
+ subject
+
+ expect(response).to have_gitlab_http_status(:created)
+ expect(response).to match_response_schema('public_api/v4/feature_flag')
+ expect(json_response.key?('version')).to eq(false)
+ end
+
+ context 'with active set to false in the params for a legacy flag' do
+ let(:params) do
+ {
+ name: 'awesome-feature',
+ version: 'legacy_flag',
+ active: 'false',
+ scopes: [scope_default]
+ }
+ end
+
+ it 'creates an inactive feature flag' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:created)
+ expect(response).to match_response_schema('public_api/v4/feature_flag')
+ expect(json_response['active']).to eq(false)
+ end
+ end
+
+ context 'when no scopes passed in parameters' do
+ let(:params) { { name: 'awesome-feature' } }
+
+ it 'creates a new feature flag with active default scope' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:created)
+ feature_flag = project.operations_feature_flags.last
+ expect(feature_flag.default_scope).to be_active
+ end
+ end
+
+ context 'when there is a feature flag with the same name already' do
+ before do
+ create_flag(project, 'awesome-feature')
+ end
+
+ it 'fails to create a new feature flag' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ end
+ end
+
+ context 'when create a feature flag with two scopes' do
+ let(:params) do
+ {
+ name: 'awesome-feature',
+ description: 'this is awesome',
+ scopes: [
+ scope_default,
+ scope_with_user_with_id
+ ]
+ }
+ end
+
+ let(:scope_with_user_with_id) do
+ {
+ environment_scope: 'production',
+ active: true,
+ strategies: [{
+ name: 'userWithId',
+ parameters: { userIds: 'user:1' }
+ }].to_json
+ }
+ end
+
+ it 'creates a new feature flag with two scopes' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:created)
+
+ feature_flag = project.operations_feature_flags.last
+ feature_flag.scopes.ordered.each_with_index do |scope, index|
+ expect(scope.environment_scope).to eq(params[:scopes][index][:environment_scope])
+ expect(scope.active).to eq(params[:scopes][index][:active])
+ expect(scope.strategies).to eq(Gitlab::Json.parse(params[:scopes][index][:strategies]))
+ end
+ end
+ end
+
+ context 'when creating a version 2 feature flag' do
+ it 'creates a new feature flag' do
+ params = {
+ name: 'new-feature',
+ version: 'new_version_flag'
+ }
+
+ post api("/projects/#{project.id}/feature_flags", user), params: params
+
+ expect(response).to have_gitlab_http_status(:created)
+ expect(response).to match_response_schema('public_api/v4/feature_flag')
+ expect(json_response).to match(hash_including({
+ 'name' => 'new-feature',
+ 'description' => nil,
+ 'active' => true,
+ 'version' => 'new_version_flag',
+ 'scopes' => [],
+ 'strategies' => []
+ }))
+
+ feature_flag = project.operations_feature_flags.last
+ expect(feature_flag.name).to eq(params[:name])
+ expect(feature_flag.version).to eq('new_version_flag')
+ end
+
+ it 'creates a new feature flag that is inactive' do
+ params = {
+ name: 'new-feature',
+ version: 'new_version_flag',
+ active: false
+ }
+
+ post api("/projects/#{project.id}/feature_flags", user), params: params
+
+ expect(response).to have_gitlab_http_status(:created)
+ expect(response).to match_response_schema('public_api/v4/feature_flag')
+ expect(json_response['active']).to eq(false)
+
+ feature_flag = project.operations_feature_flags.last
+ expect(feature_flag.active).to eq(false)
+ end
+
+ it 'creates a new feature flag with strategies' do
+ params = {
+ name: 'new-feature',
+ version: 'new_version_flag',
+ strategies: [{
+ name: 'userWithId',
+ parameters: { 'userIds': 'user1' }
+ }]
+ }
+
+ post api("/projects/#{project.id}/feature_flags", user), params: params
+
+ expect(response).to have_gitlab_http_status(:created)
+ expect(response).to match_response_schema('public_api/v4/feature_flag')
+
+ feature_flag = project.operations_feature_flags.last
+ expect(feature_flag.name).to eq(params[:name])
+ expect(feature_flag.version).to eq('new_version_flag')
+ expect(feature_flag.strategies.map { |s| s.slice(:name, :parameters).deep_symbolize_keys }).to eq([{
+ name: 'userWithId',
+ parameters: { userIds: 'user1' }
+ }])
+ end
+
+ it 'creates a new feature flag with gradual rollout strategy with scopes' do
+ params = {
+ name: 'new-feature',
+ version: 'new_version_flag',
+ strategies: [{
+ name: 'gradualRolloutUserId',
+ parameters: { groupId: 'default', percentage: '50' },
+ scopes: [{
+ environment_scope: 'staging'
+ }]
+ }]
+ }
+
+ post api("/projects/#{project.id}/feature_flags", user), params: params
+
+ expect(response).to have_gitlab_http_status(:created)
+ expect(response).to match_response_schema('public_api/v4/feature_flag')
+
+ feature_flag = project.operations_feature_flags.last
+ expect(feature_flag.name).to eq(params[:name])
+ expect(feature_flag.version).to eq('new_version_flag')
+ expect(feature_flag.strategies.map { |s| s.slice(:name, :parameters).deep_symbolize_keys }).to eq([{
+ name: 'gradualRolloutUserId',
+ parameters: { groupId: 'default', percentage: '50' }
+ }])
+ expect(feature_flag.strategies.first.scopes.map { |s| s.slice(:environment_scope).deep_symbolize_keys }).to eq([{
+ environment_scope: 'staging'
+ }])
+ end
+
+ it 'creates a new feature flag with flexible rollout strategy with scopes' do
+ params = {
+ name: 'new-feature',
+ version: 'new_version_flag',
+ strategies: [{
+ name: 'flexibleRollout',
+ parameters: { groupId: 'default', rollout: '50', stickiness: 'DEFAULT' },
+ scopes: [{
+ environment_scope: 'staging'
+ }]
+ }]
+ }
+
+ post api("/projects/#{project.id}/feature_flags", user), params: params
+
+ expect(response).to have_gitlab_http_status(:created)
+ expect(response).to match_response_schema('public_api/v4/feature_flag')
+
+ feature_flag = project.operations_feature_flags.last
+ expect(feature_flag.name).to eq(params[:name])
+ expect(feature_flag.version).to eq('new_version_flag')
+ expect(feature_flag.strategies.map { |s| s.slice(:name, :parameters).deep_symbolize_keys }).to eq([{
+ name: 'flexibleRollout',
+ parameters: { groupId: 'default', rollout: '50', stickiness: 'DEFAULT' }
+ }])
+ expect(feature_flag.strategies.first.scopes.map { |s| s.slice(:environment_scope).deep_symbolize_keys }).to eq([{
+ environment_scope: 'staging'
+ }])
+ end
+
+ it 'returns a 422 when the feature flag is disabled' do
+ stub_feature_flags(feature_flags_new_version: false)
+ params = {
+ name: 'new-feature',
+ version: 'new_version_flag'
+ }
+
+ post api("/projects/#{project.id}/feature_flags", user), params: params
+
+ expect(response).to have_gitlab_http_status(:unprocessable_entity)
+ expect(json_response).to eq({ 'message' => 'Version 2 flags are not enabled for this project' })
+ expect(project.operations_feature_flags.count).to eq(0)
+ end
+ end
+
+ context 'when given invalid parameters' do
+ it 'responds with a 400 when given an invalid version' do
+ params = { name: 'new-feature', version: 'bad_value' }
+
+ post api("/projects/#{project.id}/feature_flags", user), params: params
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ expect(json_response).to eq({ 'message' => 'Version is invalid' })
+ end
+ end
+ end
+
+ describe 'POST /projects/:id/feature_flags/:name/enable' do
+ subject do
+ post api("/projects/#{project.id}/feature_flags/#{params[:name]}/enable", user),
+ params: params
+ end
+
+ let(:params) do
+ {
+ name: 'awesome-feature',
+ environment_scope: 'production',
+ strategy: { name: 'userWithId', parameters: { userIds: 'Project:1' } }.to_json
+ }
+ end
+
+ context 'when feature flag does not exist yet' do
+ it 'creates a new feature flag with the specified scope and strategy' do
+ subject
+
+ feature_flag = project.operations_feature_flags.last
+ scope = feature_flag.scopes.find_by_environment_scope(params[:environment_scope])
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to match_response_schema('public_api/v4/feature_flag')
+ expect(feature_flag.name).to eq(params[:name])
+ expect(scope.strategies).to eq([Gitlab::Json.parse(params[:strategy])])
+ expect(feature_flag.version).to eq('legacy_flag')
+ end
+
+ it 'returns the flag version and strategies in the json response' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to match_response_schema('public_api/v4/feature_flag')
+ expect(json_response.slice('version', 'strategies')).to eq({
+ 'version' => 'legacy_flag',
+ 'strategies' => []
+ })
+ end
+
+ it_behaves_like 'check user permission'
+ end
+
+ context 'when feature flag exists already' do
+ let!(:feature_flag) { create_flag(project, params[:name]) }
+
+ context 'when feature flag scope does not exist yet' do
+ it 'creates a new scope with the specified strategy' do
+ subject
+
+ scope = feature_flag.scopes.find_by_environment_scope(params[:environment_scope])
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(scope.strategies).to eq([Gitlab::Json.parse(params[:strategy])])
+ end
+
+ it_behaves_like 'check user permission'
+ end
+
+ context 'when feature flag scope exists already' do
+ let(:defined_strategy) { { name: 'userWithId', parameters: { userIds: 'Project:2' } } }
+
+ before do
+ create_scope(feature_flag, params[:environment_scope], true, [defined_strategy])
+ end
+
+ it 'adds an additional strategy to the scope' do
+ subject
+
+ scope = feature_flag.scopes.find_by_environment_scope(params[:environment_scope])
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(scope.strategies).to eq([defined_strategy.deep_stringify_keys, Gitlab::Json.parse(params[:strategy])])
+ end
+
+ context 'when the specified strategy exists already' do
+ let(:defined_strategy) { Gitlab::Json.parse(params[:strategy]) }
+
+ it 'does not add a duplicate strategy' do
+ subject
+
+ scope = feature_flag.scopes.find_by_environment_scope(params[:environment_scope])
+ strategy_count = scope.strategies.count { |strategy| strategy['name'] == 'userWithId' }
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(strategy_count).to eq(1)
+ end
+ end
+ end
+ end
+
+ context 'with a version 2 flag' do
+ let!(:feature_flag) { create(:operations_feature_flag, :new_version_flag, project: project, name: params[:name]) }
+
+ it 'does not change the flag and returns an unprocessable_entity response' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:unprocessable_entity)
+ expect(json_response).to eq({ 'message' => 'Version 2 flags not supported' })
+ feature_flag.reload
+ expect(feature_flag.scopes).to eq([])
+ expect(feature_flag.strategies).to eq([])
+ end
+ end
+ end
+
+ describe 'POST /projects/:id/feature_flags/:name/disable' do
+ subject do
+ post api("/projects/#{project.id}/feature_flags/#{params[:name]}/disable", user),
+ params: params
+ end
+
+ let(:params) do
+ {
+ name: 'awesome-feature',
+ environment_scope: 'production',
+ strategy: { name: 'userWithId', parameters: { userIds: 'Project:1' } }.to_json
+ }
+ end
+
+ context 'when feature flag does not exist yet' do
+ it_behaves_like 'not found'
+ end
+
+ context 'when feature flag exists already' do
+ let!(:feature_flag) { create_flag(project, params[:name]) }
+
+ context 'when feature flag scope does not exist yet' do
+ it_behaves_like 'not found'
+ end
+
+ context 'when feature flag scope exists already and has the specified strategy' do
+ let(:defined_strategies) do
+ [
+ { name: 'userWithId', parameters: { userIds: 'Project:1' } },
+ { name: 'userWithId', parameters: { userIds: 'Project:2' } }
+ ]
+ end
+
+ before do
+ create_scope(feature_flag, params[:environment_scope], true, defined_strategies)
+ end
+
+ it 'removes the strategy from the scope' do
+ subject
+
+ scope = feature_flag.scopes.find_by_environment_scope(params[:environment_scope])
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to match_response_schema('public_api/v4/feature_flag')
+ expect(scope.strategies)
+ .to eq([{ name: 'userWithId', parameters: { userIds: 'Project:2' } }.deep_stringify_keys])
+ end
+
+ it 'returns the flag version and strategies in the json response' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to match_response_schema('public_api/v4/feature_flag')
+ expect(json_response.slice('version', 'strategies')).to eq({
+ 'version' => 'legacy_flag',
+ 'strategies' => []
+ })
+ end
+
+ it_behaves_like 'check user permission'
+
+ context 'when strategies become empty array after the removal' do
+ let(:defined_strategies) do
+ [{ name: 'userWithId', parameters: { userIds: 'Project:1' } }]
+ end
+
+ it 'destroys the scope' do
+ subject
+
+ scope = feature_flag.scopes.find_by_environment_scope(params[:environment_scope])
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(scope).to be_nil
+ end
+
+ it_behaves_like 'check user permission'
+ end
+ end
+
+ context 'when scope exists already but cannot find the corresponding strategy' do
+ let(:defined_strategy) { { name: 'userWithId', parameters: { userIds: 'Project:2' } } }
+
+ before do
+ create_scope(feature_flag, params[:environment_scope], true, [defined_strategy])
+ end
+
+ it_behaves_like 'not found'
+ end
+ end
+
+ context 'with a version 2 feature flag' do
+ let!(:feature_flag) { create(:operations_feature_flag, :new_version_flag, project: project, name: params[:name]) }
+
+ it 'does not change the flag and returns an unprocessable_entity response' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:unprocessable_entity)
+ expect(json_response).to eq({ 'message' => 'Version 2 flags not supported' })
+ feature_flag.reload
+ expect(feature_flag.scopes).to eq([])
+ expect(feature_flag.strategies).to eq([])
+ end
+ end
+ end
+
+ describe 'PUT /projects/:id/feature_flags/:name' do
+ context 'with a legacy feature flag' do
+ let!(:feature_flag) do
+ create(:operations_feature_flag, :legacy_flag, project: project,
+ name: 'feature1', description: 'old description')
+ end
+
+ it 'returns a 404 if the feature is disabled' do
+ stub_feature_flags(feature_flags_new_version: false)
+ params = { description: 'new description' }
+
+ put api("/projects/#{project.id}/feature_flags/feature1", user), params: params
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ expect(feature_flag.reload.description).to eq('old description')
+ end
+
+ it 'returns a 422' do
+ params = { description: 'new description' }
+
+ put api("/projects/#{project.id}/feature_flags/feature1", user), params: params
+
+ expect(response).to have_gitlab_http_status(:unprocessable_entity)
+ expect(json_response).to eq({ 'message' => 'PUT operations are not supported for legacy feature flags' })
+ expect(feature_flag.reload.description).to eq('old description')
+ end
+ end
+
+ context 'with a version 2 feature flag' do
+ let!(:feature_flag) do
+ create(:operations_feature_flag, :new_version_flag, project: project, active: true,
+ name: 'feature1', description: 'old description')
+ end
+
+ it 'returns a 404 if the feature is disabled' do
+ stub_feature_flags(feature_flags_new_version: false)
+ params = { description: 'new description' }
+
+ put api("/projects/#{project.id}/feature_flags/feature1", user), params: params
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ expect(feature_flag.reload.description).to eq('old description')
+ end
+
+ it 'returns a 404 if the feature flag does not exist' do
+ params = { description: 'new description' }
+
+ put api("/projects/#{project.id}/feature_flags/other_flag_name", user), params: params
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ expect(feature_flag.reload.description).to eq('old description')
+ end
+
+ it 'forbids a request for a reporter' do
+ params = { description: 'new description' }
+
+ put api("/projects/#{project.id}/feature_flags/feature1", reporter), params: params
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ expect(feature_flag.reload.description).to eq('old description')
+ end
+
+ it 'returns an error for an invalid update of gradual rollout' do
+ strategy = create(:operations_strategy, feature_flag: feature_flag, name: 'default', parameters: {})
+ params = {
+ strategies: [{
+ id: strategy.id,
+ name: 'gradualRolloutUserId',
+ parameters: { bad: 'params' }
+ }]
+ }
+
+ put api("/projects/#{project.id}/feature_flags/feature1", user), params: params
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ expect(json_response['message']).not_to be_nil
+ result = feature_flag.reload.strategies.map { |s| s.slice(:id, :name, :parameters).deep_symbolize_keys }
+ expect(result).to eq([{
+ id: strategy.id,
+ name: 'default',
+ parameters: {}
+ }])
+ end
+
+ it 'returns an error for an invalid update of flexible rollout' do
+ strategy = create(:operations_strategy, feature_flag: feature_flag, name: 'default', parameters: {})
+ params = {
+ strategies: [{
+ id: strategy.id,
+ name: 'flexibleRollout',
+ parameters: { bad: 'params' }
+ }]
+ }
+
+ put api("/projects/#{project.id}/feature_flags/feature1", user), params: params
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ expect(json_response['message']).not_to be_nil
+ result = feature_flag.reload.strategies.map { |s| s.slice(:id, :name, :parameters).deep_symbolize_keys }
+ expect(result).to eq([{
+ id: strategy.id,
+ name: 'default',
+ parameters: {}
+ }])
+ end
+
+ it 'updates the feature flag' do
+ params = { description: 'new description' }
+
+ put api("/projects/#{project.id}/feature_flags/feature1", user), params: params
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to match_response_schema('public_api/v4/feature_flag')
+ expect(feature_flag.reload.description).to eq('new description')
+ end
+
+ it 'updates the flag active value' do
+ params = { active: false }
+
+ put api("/projects/#{project.id}/feature_flags/feature1", user), params: params
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to match_response_schema('public_api/v4/feature_flag')
+ expect(json_response['active']).to eq(false)
+ expect(feature_flag.reload.active).to eq(false)
+ end
+
+ it 'updates the feature flag name' do
+ params = { name: 'new-name' }
+
+ put api("/projects/#{project.id}/feature_flags/feature1", user), params: params
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to match_response_schema('public_api/v4/feature_flag')
+ expect(json_response['name']).to eq('new-name')
+ expect(feature_flag.reload.name).to eq('new-name')
+ end
+
+ it 'ignores a provided version parameter' do
+ params = { description: 'other description', version: 'bad_value' }
+
+ put api("/projects/#{project.id}/feature_flags/feature1", user), params: params
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to match_response_schema('public_api/v4/feature_flag')
+ expect(feature_flag.reload.description).to eq('other description')
+ end
+
+ it 'returns the feature flag json' do
+ params = { description: 'new description' }
+
+ put api("/projects/#{project.id}/feature_flags/feature1", user), params: params
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to match_response_schema('public_api/v4/feature_flag')
+ feature_flag.reload
+ expect(json_response).to eq({
+ 'name' => 'feature1',
+ 'description' => 'new description',
+ 'active' => true,
+ 'created_at' => feature_flag.created_at.as_json,
+ 'updated_at' => feature_flag.updated_at.as_json,
+ 'scopes' => [],
+ 'strategies' => [],
+ 'version' => 'new_version_flag'
+ })
+ end
+
+ it 'updates an existing feature flag strategy to be gradual rollout strategy' do
+ strategy = create(:operations_strategy, feature_flag: feature_flag, name: 'default', parameters: {})
+ params = {
+ strategies: [{
+ id: strategy.id,
+ name: 'gradualRolloutUserId',
+ parameters: { groupId: 'default', percentage: '10' }
+ }]
+ }
+
+ put api("/projects/#{project.id}/feature_flags/feature1", user), params: params
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to match_response_schema('public_api/v4/feature_flag')
+ result = feature_flag.reload.strategies.map { |s| s.slice(:id, :name, :parameters).deep_symbolize_keys }
+ expect(result).to eq([{
+ id: strategy.id,
+ name: 'gradualRolloutUserId',
+ parameters: { groupId: 'default', percentage: '10' }
+ }])
+ end
+
+ it 'updates an existing feature flag strategy to be flexible rollout strategy' do
+ strategy = create(:operations_strategy, feature_flag: feature_flag, name: 'default', parameters: {})
+ params = {
+ strategies: [{
+ id: strategy.id,
+ name: 'flexibleRollout',
+ parameters: { groupId: 'default', rollout: '10', stickiness: 'DEFAULT' }
+ }]
+ }
+
+ put api("/projects/#{project.id}/feature_flags/feature1", user), params: params
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to match_response_schema('public_api/v4/feature_flag')
+ result = feature_flag.reload.strategies.map { |s| s.slice(:id, :name, :parameters).deep_symbolize_keys }
+ expect(result).to eq([{
+ id: strategy.id,
+ name: 'flexibleRollout',
+ parameters: { groupId: 'default', rollout: '10', stickiness: 'DEFAULT' }
+ }])
+ end
+
+ it 'adds a new gradual rollout strategy to a feature flag' do
+ strategy = create(:operations_strategy, feature_flag: feature_flag, name: 'default', parameters: {})
+ params = {
+ strategies: [{
+ name: 'gradualRolloutUserId',
+ parameters: { groupId: 'default', percentage: '10' }
+ }]
+ }
+
+ put api("/projects/#{project.id}/feature_flags/feature1", user), params: params
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to match_response_schema('public_api/v4/feature_flag')
+ result = feature_flag.reload.strategies
+ .map { |s| s.slice(:id, :name, :parameters).deep_symbolize_keys }
+ .sort_by { |s| s[:name] }
+ expect(result.first[:id]).to eq(strategy.id)
+ expect(result.map { |s| s.slice(:name, :parameters) }).to eq([{
+ name: 'default',
+ parameters: {}
+ }, {
+ name: 'gradualRolloutUserId',
+ parameters: { groupId: 'default', percentage: '10' }
+ }])
+ end
+
+ it 'adds a new gradual flexible strategy to a feature flag' do
+ strategy = create(:operations_strategy, feature_flag: feature_flag, name: 'default', parameters: {})
+ params = {
+ strategies: [{
+ name: 'flexibleRollout',
+ parameters: { groupId: 'default', rollout: '10', stickiness: 'DEFAULT' }
+ }]
+ }
+
+ put api("/projects/#{project.id}/feature_flags/feature1", user), params: params
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to match_response_schema('public_api/v4/feature_flag')
+ result = feature_flag.reload.strategies
+ .map { |s| s.slice(:id, :name, :parameters).deep_symbolize_keys }
+ .sort_by { |s| s[:name] }
+ expect(result.first[:id]).to eq(strategy.id)
+ expect(result.map { |s| s.slice(:name, :parameters) }).to eq([{
+ name: 'default',
+ parameters: {}
+ }, {
+ name: 'flexibleRollout',
+ parameters: { groupId: 'default', rollout: '10', stickiness: 'DEFAULT' }
+ }])
+ end
+
+ it 'deletes a feature flag strategy' do
+ strategy_a = create(:operations_strategy, feature_flag: feature_flag, name: 'default', parameters: {})
+ strategy_b = create(:operations_strategy, feature_flag: feature_flag,
+ name: 'userWithId', parameters: { userIds: 'userA,userB' })
+ params = {
+ strategies: [{
+ id: strategy_a.id,
+ name: 'default',
+ parameters: {},
+ _destroy: true
+ }, {
+ id: strategy_b.id,
+ name: 'userWithId',
+ parameters: { userIds: 'userB' }
+ }]
+ }
+
+ put api("/projects/#{project.id}/feature_flags/feature1", user), params: params
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to match_response_schema('public_api/v4/feature_flag')
+ result = feature_flag.reload.strategies
+ .map { |s| s.slice(:id, :name, :parameters).deep_symbolize_keys }
+ .sort_by { |s| s[:name] }
+ expect(result).to eq([{
+ id: strategy_b.id,
+ name: 'userWithId',
+ parameters: { userIds: 'userB' }
+ }])
+ end
+
+ it 'updates an existing feature flag scope' do
+ strategy = create(:operations_strategy, feature_flag: feature_flag, name: 'default', parameters: {})
+ scope = create(:operations_scope, strategy: strategy, environment_scope: '*')
+ params = {
+ strategies: [{
+ id: strategy.id,
+ scopes: [{
+ id: scope.id,
+ environment_scope: 'production'
+ }]
+ }]
+ }
+
+ put api("/projects/#{project.id}/feature_flags/feature1", user), params: params
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to match_response_schema('public_api/v4/feature_flag')
+ result = feature_flag.reload.strategies.first.scopes.map { |s| s.slice(:id, :environment_scope).deep_symbolize_keys }
+ expect(result).to eq([{
+ id: scope.id,
+ environment_scope: 'production'
+ }])
+ end
+
+ it 'deletes an existing feature flag scope' do
+ strategy = create(:operations_strategy, feature_flag: feature_flag, name: 'default', parameters: {})
+ scope = create(:operations_scope, strategy: strategy, environment_scope: '*')
+ params = {
+ strategies: [{
+ id: strategy.id,
+ scopes: [{
+ id: scope.id,
+ _destroy: true
+ }]
+ }]
+ }
+
+ put api("/projects/#{project.id}/feature_flags/feature1", user), params: params
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to match_response_schema('public_api/v4/feature_flag')
+ expect(feature_flag.reload.strategies.first.scopes.count).to eq(0)
+ end
+ end
+ end
+
+ describe 'DELETE /projects/:id/feature_flags/:name' do
+ subject do
+ delete api("/projects/#{project.id}/feature_flags/#{feature_flag.name}", user),
+ params: params
+ end
+
+ let!(:feature_flag) { create(:operations_feature_flag, project: project) }
+ let(:params) { {} }
+
+ it 'destroys the feature flag' do
+ expect { subject }.to change { Operations::FeatureFlag.count }.by(-1)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+
+ it 'returns version' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['version']).to eq('legacy_flag')
+ end
+
+ it 'does not return version when new version flags are disabled' do
+ stub_feature_flags(feature_flags_new_version: false)
+
+ subject
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response.key?('version')).to eq(false)
+ end
+
+ context 'with a version 2 feature flag' do
+ let!(:feature_flag) { create(:operations_feature_flag, :new_version_flag, project: project) }
+
+ it 'destroys the flag' do
+ expect { subject }.to change { Operations::FeatureFlag.count }.by(-1)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+
+ it 'returns a 404 if the feature is disabled' do
+ stub_feature_flags(feature_flags_new_version: false)
+
+ expect { subject }.not_to change { Operations::FeatureFlag.count }
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+ end
+end
diff --git a/spec/requests/api/feature_flags_user_lists_spec.rb b/spec/requests/api/feature_flags_user_lists_spec.rb
new file mode 100644
index 00000000000..469210040dd
--- /dev/null
+++ b/spec/requests/api/feature_flags_user_lists_spec.rb
@@ -0,0 +1,371 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe API::FeatureFlagsUserLists do
+ let_it_be(:project, refind: true) { create(:project) }
+ let_it_be(:developer) { create(:user) }
+ let_it_be(:reporter) { create(:user) }
+
+ before_all do
+ project.add_developer(developer)
+ project.add_reporter(reporter)
+ end
+
+ def create_list(name: 'mylist', user_xids: 'user1')
+ create(:operations_feature_flag_user_list, project: project, name: name, user_xids: user_xids)
+ end
+
+ def disable_repository(project)
+ project.project_feature.update!(
+ repository_access_level: ::ProjectFeature::DISABLED,
+ merge_requests_access_level: ::ProjectFeature::DISABLED,
+ builds_access_level: ::ProjectFeature::DISABLED
+ )
+ end
+
+ describe 'GET /projects/:id/feature_flags_user_lists' do
+ it 'forbids the request for a reporter' do
+ get api("/projects/#{project.id}/feature_flags_user_lists", reporter)
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ end
+
+ it 'returns forbidden if the feature is unavailable' do
+ disable_repository(project)
+
+ get api("/projects/#{project.id}/feature_flags_user_lists", developer)
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ end
+
+ it 'returns all the user lists' do
+ create_list(name: 'list_a', user_xids: 'user1')
+ create_list(name: 'list_b', user_xids: 'user1,user2,user3')
+
+ get api("/projects/#{project.id}/feature_flags_user_lists", developer)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response.map { |list| list['name'] }.sort).to eq(%w[list_a list_b])
+ end
+
+ it 'returns all the data for a user list' do
+ user_list = create_list(name: 'list_a', user_xids: 'user1')
+
+ get api("/projects/#{project.id}/feature_flags_user_lists", developer)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response).to eq([{
+ 'id' => user_list.id,
+ 'iid' => user_list.iid,
+ 'project_id' => project.id,
+ 'created_at' => user_list.created_at.as_json,
+ 'updated_at' => user_list.updated_at.as_json,
+ 'name' => 'list_a',
+ 'user_xids' => 'user1',
+ 'path' => project_feature_flags_user_list_path(user_list.project, user_list),
+ 'edit_path' => edit_project_feature_flags_user_list_path(user_list.project, user_list)
+ }])
+ end
+
+ it 'paginates user lists' do
+ create_list(name: 'list_a', user_xids: 'user1')
+ create_list(name: 'list_b', user_xids: 'user1,user2,user3')
+
+ get api("/projects/#{project.id}/feature_flags_user_lists?page=2&per_page=1", developer)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response.map { |list| list['name'] }).to eq(['list_b'])
+ end
+
+ it 'returns the user lists for only the specified project' do
+ create(:operations_feature_flag_user_list, project: project, name: 'list')
+ other_project = create(:project)
+ create(:operations_feature_flag_user_list, project: other_project, name: 'other_list')
+
+ get api("/projects/#{project.id}/feature_flags_user_lists", developer)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response.map { |list| list['name'] }).to eq(['list'])
+ end
+
+ it 'returns an empty list' do
+ get api("/projects/#{project.id}/feature_flags_user_lists", developer)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response).to eq([])
+ end
+ end
+
+ describe 'GET /projects/:id/feature_flags_user_lists/:iid' do
+ it 'forbids the request for a reporter' do
+ list = create_list
+
+ get api("/projects/#{project.id}/feature_flags_user_lists/#{list.iid}", reporter)
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ end
+
+ it 'returns forbidden if the feature is unavailable' do
+ disable_repository(project)
+ list = create_list
+
+ get api("/projects/#{project.id}/feature_flags_user_lists/#{list.iid}", developer)
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ end
+
+ it 'returns the user list' do
+ list = create_list(name: 'testers', user_xids: 'test1,test2')
+
+ get api("/projects/#{project.id}/feature_flags_user_lists/#{list.iid}", developer)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response).to eq({
+ 'name' => 'testers',
+ 'user_xids' => 'test1,test2',
+ 'id' => list.id,
+ 'iid' => list.iid,
+ 'project_id' => project.id,
+ 'created_at' => list.created_at.as_json,
+ 'updated_at' => list.updated_at.as_json,
+ 'path' => project_feature_flags_user_list_path(list.project, list),
+ 'edit_path' => edit_project_feature_flags_user_list_path(list.project, list)
+ })
+ end
+
+ it 'returns the correct user list identified by the iid' do
+ create_list(name: 'list_a', user_xids: 'test1')
+ list_b = create_list(name: 'list_b', user_xids: 'test2')
+
+ get api("/projects/#{project.id}/feature_flags_user_lists/#{list_b.iid}", developer)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['name']).to eq('list_b')
+ end
+
+ it 'scopes the iid search to the project' do
+ other_project = create(:project)
+ other_project.add_developer(developer)
+ create(:operations_feature_flag_user_list, project: other_project, name: 'other_list')
+ list = create(:operations_feature_flag_user_list, project: project, name: 'list')
+
+ get api("/projects/#{project.id}/feature_flags_user_lists/#{list.iid}", developer)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['name']).to eq('list')
+ end
+
+ it 'returns not found when the list does not exist' do
+ get api("/projects/#{project.id}/feature_flags_user_lists/1", developer)
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ expect(json_response).to eq({ 'message' => '404 Not found' })
+ end
+ end
+
+ describe 'POST /projects/:id/feature_flags_user_lists' do
+ it 'forbids the request for a reporter' do
+ post api("/projects/#{project.id}/feature_flags_user_lists", reporter), params: {
+ name: 'mylist', user_xids: 'user1'
+ }
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ expect(project.operations_feature_flags_user_lists.count).to eq(0)
+ end
+
+ it 'returns forbidden if the feature is unavailable' do
+ disable_repository(project)
+
+ post api("/projects/#{project.id}/feature_flags_user_lists", developer), params: {
+ name: 'mylist', user_xids: 'user1'
+ }
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ end
+
+ it 'creates the flag' do
+ post api("/projects/#{project.id}/feature_flags_user_lists", developer), params: {
+ name: 'mylist', user_xids: 'user1'
+ }
+
+ expect(response).to have_gitlab_http_status(:created)
+ expect(json_response.slice('name', 'user_xids', 'project_id', 'iid')).to eq({
+ 'name' => 'mylist',
+ 'user_xids' => 'user1',
+ 'project_id' => project.id,
+ 'iid' => 1
+ })
+ expect(project.operations_feature_flags_user_lists.count).to eq(1)
+ expect(project.operations_feature_flags_user_lists.last.name).to eq('mylist')
+ end
+
+ it 'requires name' do
+ post api("/projects/#{project.id}/feature_flags_user_lists", developer), params: {
+ user_xids: 'user1'
+ }
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ expect(json_response).to eq({ 'message' => 'name is missing' })
+ expect(project.operations_feature_flags_user_lists.count).to eq(0)
+ end
+
+ it 'requires user_xids' do
+ post api("/projects/#{project.id}/feature_flags_user_lists", developer), params: {
+ name: 'empty_list'
+ }
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ expect(json_response).to eq({ 'message' => 'user_xids is missing' })
+ expect(project.operations_feature_flags_user_lists.count).to eq(0)
+ end
+
+ it 'returns an error when name is already taken' do
+ create_list(name: 'myname')
+ post api("/projects/#{project.id}/feature_flags_user_lists", developer), params: {
+ name: 'myname', user_xids: 'a'
+ }
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ expect(json_response).to eq({ 'message' => ['Name has already been taken'] })
+ expect(project.operations_feature_flags_user_lists.count).to eq(1)
+ end
+
+ it 'does not create a flag for a project of which the developer is not a member' do
+ other_project = create(:project)
+
+ post api("/projects/#{other_project.id}/feature_flags_user_lists", developer), params: {
+ name: 'mylist', user_xids: 'user1'
+ }
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ expect(other_project.operations_feature_flags_user_lists.count).to eq(0)
+ expect(project.operations_feature_flags_user_lists.count).to eq(0)
+ end
+ end
+
+ describe 'PUT /projects/:id/feature_flags_user_lists/:iid' do
+ it 'forbids the request for a reporter' do
+ list = create_list(name: 'original_name')
+
+ put api("/projects/#{project.id}/feature_flags_user_lists/#{list.iid}", reporter), params: {
+ name: 'mylist'
+ }
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ expect(list.reload.name).to eq('original_name')
+ end
+
+ it 'returns forbidden if the feature is unavailable' do
+ list = create_list(name: 'original_name')
+ disable_repository(project)
+
+ put api("/projects/#{project.id}/feature_flags_user_lists/#{list.iid}", developer), params: {
+ name: 'mylist', user_xids: '456,789'
+ }
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ end
+
+ it 'updates the list' do
+ list = create_list(name: 'original_name', user_xids: '123')
+
+ put api("/projects/#{project.id}/feature_flags_user_lists/#{list.iid}", developer), params: {
+ name: 'mylist', user_xids: '456,789'
+ }
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response.slice('name', 'user_xids')).to eq({
+ 'name' => 'mylist',
+ 'user_xids' => '456,789'
+ })
+ expect(list.reload.name).to eq('mylist')
+ end
+
+ it 'preserves attributes not listed in the request' do
+ list = create_list(name: 'original_name', user_xids: '123')
+
+ put api("/projects/#{project.id}/feature_flags_user_lists/#{list.iid}", developer), params: {}
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response.slice('name', 'user_xids')).to eq({
+ 'name' => 'original_name',
+ 'user_xids' => '123'
+ })
+ expect(list.reload.name).to eq('original_name')
+ expect(list.reload.user_xids).to eq('123')
+ end
+
+ it 'returns an error when the update is invalid' do
+ create_list(name: 'taken', user_xids: '123')
+ list = create_list(name: 'original_name', user_xids: '123')
+
+ put api("/projects/#{project.id}/feature_flags_user_lists/#{list.iid}", developer), params: {
+ name: 'taken'
+ }
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ expect(json_response).to eq({ 'message' => ['Name has already been taken'] })
+ end
+
+ it 'returns not found when the list does not exist' do
+ list = create_list(name: 'original_name', user_xids: '123')
+
+ put api("/projects/#{project.id}/feature_flags_user_lists/#{list.iid + 1}", developer), params: {
+ name: 'new_name'
+ }
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ expect(json_response).to eq({ 'message' => '404 Not found' })
+ end
+ end
+
+ describe 'DELETE /projects/:id/feature_flags_user_lists/:iid' do
+ it 'forbids the request for a reporter' do
+ list = create_list
+
+ delete api("/projects/#{project.id}/feature_flags_user_lists/#{list.iid}", reporter)
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ expect(project.operations_feature_flags_user_lists.count).to eq(1)
+ end
+
+ it 'returns forbidden if the feature is unavailable' do
+ list = create_list
+ disable_repository(project)
+
+ delete api("/projects/#{project.id}/feature_flags_user_lists/#{list.iid}", developer)
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ end
+
+ it 'returns not found when the list does not exist' do
+ delete api("/projects/#{project.id}/feature_flags_user_lists/1", developer)
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ expect(json_response).to eq({ 'message' => '404 Not found' })
+ end
+
+ it 'deletes the list' do
+ list = create_list
+
+ delete api("/projects/#{project.id}/feature_flags_user_lists/#{list.iid}", developer)
+
+ expect(response).to have_gitlab_http_status(:no_content)
+ expect(response.body).to be_blank
+ expect(project.operations_feature_flags_user_lists.count).to eq(0)
+ end
+
+ it 'does not delete the list if it is associated with a strategy' do
+ list = create_list
+ feature_flag = create(:operations_feature_flag, :new_version_flag, project: project)
+ create(:operations_strategy, feature_flag: feature_flag, name: 'gitlabUserList', user_list: list)
+
+ delete api("/projects/#{project.id}/feature_flags_user_lists/#{list.iid}", developer)
+
+ expect(response).to have_gitlab_http_status(:conflict)
+ expect(json_response).to eq({ 'message' => ['User list is associated with a strategy'] })
+ expect(list.reload).to be_persisted
+ end
+ end
+end
diff --git a/spec/requests/api/features_spec.rb b/spec/requests/api/features_spec.rb
index 2746e777306..3f443b4f92b 100644
--- a/spec/requests/api/features_spec.rb
+++ b/spec/requests/api/features_spec.rb
@@ -12,6 +12,8 @@ RSpec.describe API::Features, stub_feature_flags: false do
Flipper.register(:perf_team) do |actor|
actor.respond_to?(:admin) && actor.admin?
end
+
+ skip_feature_flags_yaml_validation
end
describe 'GET /features' do
diff --git a/spec/requests/api/files_spec.rb b/spec/requests/api/files_spec.rb
index bb4e88f97f8..f77f127ddc8 100644
--- a/spec/requests/api/files_spec.rb
+++ b/spec/requests/api/files_spec.rb
@@ -747,7 +747,7 @@ RSpec.describe API::Files do
it "updates existing file in project repo with accepts correct last commit id" do
last_commit = Gitlab::Git::Commit
- .last_for_path(project.repository, 'master', URI.unescape(file_path))
+ .last_for_path(project.repository, 'master', Addressable::URI.unencode_component(file_path))
params_with_correct_id = params.merge(last_commit_id: last_commit.id)
put api(route(file_path), user), params: params_with_correct_id
@@ -757,7 +757,7 @@ RSpec.describe API::Files do
it "returns 400 when file path is invalid" do
last_commit = Gitlab::Git::Commit
- .last_for_path(project.repository, 'master', URI.unescape(file_path))
+ .last_for_path(project.repository, 'master', Addressable::URI.unencode_component(file_path))
params_with_correct_id = params.merge(last_commit_id: last_commit.id)
put api(route(rouge_file_path), user), params: params_with_correct_id
@@ -769,7 +769,7 @@ RSpec.describe API::Files do
it_behaves_like 'when path is absolute' do
let(:last_commit) do
Gitlab::Git::Commit
- .last_for_path(project.repository, 'master', URI.unescape(file_path))
+ .last_for_path(project.repository, 'master', Addressable::URI.unencode_component(file_path))
end
let(:params_with_correct_id) { params.merge(last_commit_id: last_commit.id) }
diff --git a/spec/requests/api/generic_packages_spec.rb b/spec/requests/api/generic_packages_spec.rb
index ed852fe75c7..2cb686167f1 100644
--- a/spec/requests/api/generic_packages_spec.rb
+++ b/spec/requests/api/generic_packages_spec.rb
@@ -4,79 +4,432 @@ require 'spec_helper'
RSpec.describe API::GenericPackages do
let_it_be(:personal_access_token) { create(:personal_access_token) }
- let_it_be(:project) { create(:project) }
+ let_it_be(:project, reload: true) { create(:project) }
+ let(:workhorse_token) { JWT.encode({ 'iss' => 'gitlab-workhorse' }, Gitlab::Workhorse.secret, 'HS256') }
+ let(:workhorse_header) { { 'GitLab-Workhorse' => '1.0', Gitlab::Workhorse::INTERNAL_API_REQUEST_HEADER => workhorse_token } }
+ let(:user) { personal_access_token.user }
+ let(:ci_build) { create(:ci_build, :running, user: user) }
- describe 'GET /api/v4/projects/:id/packages/generic/ping' do
- let(:user) { personal_access_token.user }
- let(:auth_token) { personal_access_token.token }
+ def auth_header
+ return {} if user_role == :anonymous
+ case authenticate_with
+ when :personal_access_token
+ personal_access_token_header
+ when :job_token
+ job_token_header
+ when :invalid_personal_access_token
+ personal_access_token_header('wrong token')
+ when :invalid_job_token
+ job_token_header('wrong token')
+ end
+ end
+
+ def personal_access_token_header(value = nil)
+ { Gitlab::Auth::AuthFinders::PRIVATE_TOKEN_HEADER => value || personal_access_token.token }
+ end
+
+ def job_token_header(value = nil)
+ { Gitlab::Auth::AuthFinders::JOB_TOKEN_HEADER => value || ci_build.token }
+ end
+
+ shared_examples 'secure endpoint' do
before do
project.add_developer(user)
end
- context 'packages feature is disabled' do
- it 'responds with 404 Not Found' do
- stub_packages_setting(enabled: false)
+ it 'rejects malicious request' do
+ subject
- ping(personal_access_token: auth_token)
+ expect(response).to have_gitlab_http_status(:bad_request)
+ end
+ end
- expect(response).to have_gitlab_http_status(:not_found)
+ describe 'PUT /api/v4/projects/:id/packages/generic/:package_name/:package_version/:file_name/authorize' do
+ context 'with valid project' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:project_visibility, :user_role, :member?, :authenticate_with, :expected_status) do
+ 'PUBLIC' | :developer | true | :personal_access_token | :success
+ 'PUBLIC' | :guest | true | :personal_access_token | :forbidden
+ 'PUBLIC' | :developer | true | :invalid_personal_access_token | :unauthorized
+ 'PUBLIC' | :guest | true | :invalid_personal_access_token | :unauthorized
+ 'PUBLIC' | :developer | false | :personal_access_token | :forbidden
+ 'PUBLIC' | :guest | false | :personal_access_token | :forbidden
+ 'PUBLIC' | :developer | false | :invalid_personal_access_token | :unauthorized
+ 'PUBLIC' | :guest | false | :invalid_personal_access_token | :unauthorized
+ 'PUBLIC' | :anonymous | false | :none | :unauthorized
+ 'PRIVATE' | :developer | true | :personal_access_token | :success
+ 'PRIVATE' | :guest | true | :personal_access_token | :forbidden
+ 'PRIVATE' | :developer | true | :invalid_personal_access_token | :unauthorized
+ 'PRIVATE' | :guest | true | :invalid_personal_access_token | :unauthorized
+ 'PRIVATE' | :developer | false | :personal_access_token | :not_found
+ 'PRIVATE' | :guest | false | :personal_access_token | :not_found
+ 'PRIVATE' | :developer | false | :invalid_personal_access_token | :unauthorized
+ 'PRIVATE' | :guest | false | :invalid_personal_access_token | :unauthorized
+ 'PRIVATE' | :anonymous | false | :none | :unauthorized
+ 'PUBLIC' | :developer | true | :job_token | :success
+ 'PUBLIC' | :developer | true | :invalid_job_token | :unauthorized
+ 'PUBLIC' | :developer | false | :job_token | :forbidden
+ 'PUBLIC' | :developer | false | :invalid_job_token | :unauthorized
+ 'PRIVATE' | :developer | true | :job_token | :success
+ 'PRIVATE' | :developer | true | :invalid_job_token | :unauthorized
+ 'PRIVATE' | :developer | false | :job_token | :not_found
+ 'PRIVATE' | :developer | false | :invalid_job_token | :unauthorized
+ end
+
+ with_them do
+ before do
+ project.update!(visibility_level: Gitlab::VisibilityLevel.const_get(project_visibility, false))
+ project.send("add_#{user_role}", user) if member? && user_role != :anonymous
+ end
+
+ it "responds with #{params[:expected_status]}" do
+ authorize_upload_file(workhorse_header.merge(auth_header))
+
+ expect(response).to have_gitlab_http_status(expected_status)
+ end
+ end
+ end
+
+ context 'application security' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:param_name, :param_value) do
+ :package_name | 'my-package/../'
+ :package_name | 'my-package%2f%2e%2e%2f'
+ :file_name | '../.ssh%2fauthorized_keys'
+ :file_name | '%2e%2e%2f.ssh%2fauthorized_keys'
+ end
+
+ with_them do
+ subject { authorize_upload_file(workhorse_header.merge(personal_access_token_header), param_name => param_value) }
+
+ it_behaves_like 'secure endpoint'
end
end
context 'generic_packages feature flag is disabled' do
it 'responds with 404 Not Found' do
stub_feature_flags(generic_packages: false)
+ project.add_developer(user)
- ping(personal_access_token: auth_token)
+ authorize_upload_file(workhorse_header.merge(personal_access_token_header))
expect(response).to have_gitlab_http_status(:not_found)
end
end
- context 'generic_packages feature flag is enabled' do
+ def authorize_upload_file(request_headers, package_name: 'mypackage', file_name: 'myfile.tar.gz')
+ url = "/projects/#{project.id}/packages/generic/#{package_name}/0.0.1/#{file_name}/authorize"
+
+ put api(url), headers: request_headers
+ end
+ end
+
+ describe 'PUT /api/v4/projects/:id/packages/generic/:package_name/:package_version/:file_name' do
+ include WorkhorseHelpers
+
+ let(:file_upload) { fixture_file_upload('spec/fixtures/packages/generic/myfile.tar.gz') }
+ let(:params) { { file: file_upload } }
+
+ context 'authentication' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:project_visibility, :user_role, :member?, :authenticate_with, :expected_status) do
+ 'PUBLIC' | :guest | true | :personal_access_token | :forbidden
+ 'PUBLIC' | :developer | true | :invalid_personal_access_token | :unauthorized
+ 'PUBLIC' | :guest | true | :invalid_personal_access_token | :unauthorized
+ 'PUBLIC' | :developer | false | :personal_access_token | :forbidden
+ 'PUBLIC' | :guest | false | :personal_access_token | :forbidden
+ 'PUBLIC' | :developer | false | :invalid_personal_access_token | :unauthorized
+ 'PUBLIC' | :guest | false | :invalid_personal_access_token | :unauthorized
+ 'PUBLIC' | :anonymous | false | :none | :unauthorized
+ 'PRIVATE' | :guest | true | :personal_access_token | :forbidden
+ 'PRIVATE' | :developer | true | :invalid_personal_access_token | :unauthorized
+ 'PRIVATE' | :guest | true | :invalid_personal_access_token | :unauthorized
+ 'PRIVATE' | :developer | false | :personal_access_token | :not_found
+ 'PRIVATE' | :guest | false | :personal_access_token | :not_found
+ 'PRIVATE' | :developer | false | :invalid_personal_access_token | :unauthorized
+ 'PRIVATE' | :guest | false | :invalid_personal_access_token | :unauthorized
+ 'PRIVATE' | :anonymous | false | :none | :unauthorized
+ 'PUBLIC' | :developer | true | :invalid_job_token | :unauthorized
+ 'PUBLIC' | :developer | false | :job_token | :forbidden
+ 'PUBLIC' | :developer | false | :invalid_job_token | :unauthorized
+ 'PRIVATE' | :developer | true | :invalid_job_token | :unauthorized
+ 'PRIVATE' | :developer | false | :job_token | :not_found
+ 'PRIVATE' | :developer | false | :invalid_job_token | :unauthorized
+ end
+
+ with_them do
+ before do
+ project.update!(visibility_level: Gitlab::VisibilityLevel.const_get(project_visibility, false))
+ project.send("add_#{user_role}", user) if member? && user_role != :anonymous
+ end
+
+ it "responds with #{params[:expected_status]}" do
+ headers = workhorse_header.merge(auth_header)
+
+ upload_file(params, headers)
+
+ expect(response).to have_gitlab_http_status(expected_status)
+ end
+ end
+ end
+
+ context 'when user can upload packages and has valid credentials' do
before do
- stub_feature_flags(generic_packages: true)
+ project.add_developer(user)
end
- context 'authenticating using personal access token' do
- it 'responds with 200 OK when valid personal access token is provided' do
- ping(personal_access_token: auth_token)
+ it 'creates package and package file when valid personal access token is used' do
+ headers = workhorse_header.merge(personal_access_token_header)
+
+ expect { upload_file(params, headers) }
+ .to change { project.packages.generic.count }.by(1)
+ .and change { Packages::PackageFile.count }.by(1)
+
+ aggregate_failures do
+ expect(response).to have_gitlab_http_status(:created)
- expect(response).to have_gitlab_http_status(:ok)
+ package = project.packages.generic.last
+ expect(package.name).to eq('mypackage')
+ expect(package.version).to eq('0.0.1')
+ expect(package.build_info).to be_nil
+
+ package_file = package.package_files.last
+ expect(package_file.file_name).to eq('myfile.tar.gz')
end
+ end
+
+ it 'creates package, package file, and package build info when valid job token is used' do
+ headers = workhorse_header.merge(job_token_header)
+
+ expect { upload_file(params, headers) }
+ .to change { project.packages.generic.count }.by(1)
+ .and change { Packages::PackageFile.count }.by(1)
- it 'responds with 401 Unauthorized when invalid personal access token provided' do
- ping(personal_access_token: 'invalid-token')
+ aggregate_failures do
+ expect(response).to have_gitlab_http_status(:created)
- expect(response).to have_gitlab_http_status(:unauthorized)
+ package = project.packages.generic.last
+ expect(package.name).to eq('mypackage')
+ expect(package.version).to eq('0.0.1')
+ expect(package.build_info.pipeline).to eq(ci_build.pipeline)
+
+ package_file = package.package_files.last
+ expect(package_file.file_name).to eq('myfile.tar.gz')
end
end
- context 'authenticating using job token' do
- it 'responds with 200 OK when valid job token is provided' do
- job_token = create(:ci_build, :running, user: user).token
+ context 'event tracking' do
+ subject { upload_file(params, workhorse_header.merge(personal_access_token_header)) }
+
+ it_behaves_like 'a gitlab tracking event', described_class.name, 'push_package'
+ end
+
+ it 'rejects request without a file from workhorse' do
+ headers = workhorse_header.merge(personal_access_token_header)
+ upload_file({}, headers)
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ end
+
+ it 'rejects request without an auth token' do
+ upload_file(params, workhorse_header)
+
+ expect(response).to have_gitlab_http_status(:unauthorized)
+ end
+
+ it 'rejects request without workhorse rewritten fields' do
+ headers = workhorse_header.merge(personal_access_token_header)
+ upload_file(params, headers, send_rewritten_field: false)
- ping(job_token: job_token)
+ expect(response).to have_gitlab_http_status(:bad_request)
+ end
- expect(response).to have_gitlab_http_status(:ok)
+ it 'rejects request if file size is too large' do
+ allow_next_instance_of(UploadedFile) do |uploaded_file|
+ allow(uploaded_file).to receive(:size).and_return(project.actual_limits.generic_packages_max_file_size + 1)
end
- it 'responds with 401 Unauthorized when invalid job token provided' do
- ping(job_token: 'invalid-token')
+ headers = workhorse_header.merge(personal_access_token_header)
+ upload_file(params, headers)
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ end
+
+ it 'rejects request without workhorse header' do
+ expect(Gitlab::ErrorTracking).to receive(:track_exception).once
- expect(response).to have_gitlab_http_status(:unauthorized)
+ upload_file(params, personal_access_token_header)
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ end
+ end
+
+ context 'application security' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:param_name, :param_value) do
+ :package_name | 'my-package/../'
+ :package_name | 'my-package%2f%2e%2e%2f'
+ :file_name | '../.ssh%2fauthorized_keys'
+ :file_name | '%2e%2e%2f.ssh%2fauthorized_keys'
+ end
+
+ with_them do
+ subject { upload_file(params, workhorse_header.merge(personal_access_token_header), param_name => param_value) }
+
+ it_behaves_like 'secure endpoint'
+ end
+ end
+
+ def upload_file(params, request_headers, send_rewritten_field: true, package_name: 'mypackage', file_name: 'myfile.tar.gz')
+ url = "/projects/#{project.id}/packages/generic/#{package_name}/0.0.1/#{file_name}"
+
+ workhorse_finalize(
+ api(url),
+ method: :put,
+ file_key: :file,
+ params: params,
+ headers: request_headers,
+ send_rewritten_field: send_rewritten_field
+ )
+ end
+ end
+
+ describe 'GET /api/v4/projects/:id/packages/generic/:package_name/:package_version/:file_name' do
+ using RSpec::Parameterized::TableSyntax
+
+ let_it_be(:package) { create(:generic_package, project: project) }
+ let_it_be(:package_file) { create(:package_file, :generic, package: package) }
+
+ context 'authentication' do
+ where(:project_visibility, :user_role, :member?, :authenticate_with, :expected_status) do
+ 'PUBLIC' | :developer | true | :personal_access_token | :success
+ 'PUBLIC' | :guest | true | :personal_access_token | :success
+ 'PUBLIC' | :developer | true | :invalid_personal_access_token | :unauthorized
+ 'PUBLIC' | :guest | true | :invalid_personal_access_token | :unauthorized
+ 'PUBLIC' | :developer | false | :personal_access_token | :success
+ 'PUBLIC' | :guest | false | :personal_access_token | :success
+ 'PUBLIC' | :developer | false | :invalid_personal_access_token | :unauthorized
+ 'PUBLIC' | :guest | false | :invalid_personal_access_token | :unauthorized
+ 'PUBLIC' | :anonymous | false | :none | :unauthorized
+ 'PRIVATE' | :developer | true | :personal_access_token | :success
+ 'PRIVATE' | :guest | true | :personal_access_token | :forbidden
+ 'PRIVATE' | :developer | true | :invalid_personal_access_token | :unauthorized
+ 'PRIVATE' | :guest | true | :invalid_personal_access_token | :unauthorized
+ 'PRIVATE' | :developer | false | :personal_access_token | :not_found
+ 'PRIVATE' | :guest | false | :personal_access_token | :not_found
+ 'PRIVATE' | :developer | false | :invalid_personal_access_token | :unauthorized
+ 'PRIVATE' | :guest | false | :invalid_personal_access_token | :unauthorized
+ 'PRIVATE' | :anonymous | false | :none | :unauthorized
+ 'PUBLIC' | :developer | true | :job_token | :success
+ 'PUBLIC' | :developer | true | :invalid_job_token | :unauthorized
+ 'PUBLIC' | :developer | false | :job_token | :success
+ 'PUBLIC' | :developer | false | :invalid_job_token | :unauthorized
+ 'PRIVATE' | :developer | true | :job_token | :success
+ 'PRIVATE' | :developer | true | :invalid_job_token | :unauthorized
+ 'PRIVATE' | :developer | false | :job_token | :not_found
+ 'PRIVATE' | :developer | false | :invalid_job_token | :unauthorized
+ end
+
+ with_them do
+ before do
+ project.update!(visibility_level: Gitlab::VisibilityLevel.const_get(project_visibility, false))
+ project.send("add_#{user_role}", user) if member? && user_role != :anonymous
+ end
+
+ it "responds with #{params[:expected_status]}" do
+ download_file(auth_header)
+
+ expect(response).to have_gitlab_http_status(expected_status)
end
end
end
- def ping(personal_access_token: nil, job_token: nil)
- headers = {
- Gitlab::Auth::AuthFinders::PRIVATE_TOKEN_HEADER => personal_access_token.presence,
- Gitlab::Auth::AuthFinders::JOB_TOKEN_HEADER => job_token.presence
- }.compact
+ context 'event tracking' do
+ before do
+ project.add_developer(user)
+ end
+
+ subject { download_file(personal_access_token_header) }
+
+ it_behaves_like 'a gitlab tracking event', described_class.name, 'pull_package'
+ end
+
+ it 'rejects a malicious file name request' do
+ project.add_developer(user)
+
+ download_file(personal_access_token_header, file_name: '../.ssh%2fauthorized_keys')
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ end
+
+ it 'rejects a malicious file name request' do
+ project.add_developer(user)
+
+ download_file(personal_access_token_header, file_name: '%2e%2e%2f.ssh%2fauthorized_keys')
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ end
+
+ it 'rejects a malicious package name request' do
+ project.add_developer(user)
+
+ download_file(personal_access_token_header, package_name: 'my-package/../')
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ end
+
+ it 'rejects a malicious package name request' do
+ project.add_developer(user)
+
+ download_file(personal_access_token_header, package_name: 'my-package%2f%2e%2e%2f')
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ end
+
+ context 'application security' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:param_name, :param_value) do
+ :package_name | 'my-package/../'
+ :package_name | 'my-package%2f%2e%2e%2f'
+ :file_name | '../.ssh%2fauthorized_keys'
+ :file_name | '%2e%2e%2f.ssh%2fauthorized_keys'
+ end
+
+ with_them do
+ subject { download_file(personal_access_token_header, param_name => param_value) }
+
+ it_behaves_like 'secure endpoint'
+ end
+ end
+
+ it 'responds with 404 Not Found for non existing package' do
+ project.add_developer(user)
+
+ download_file(personal_access_token_header, package_name: 'no-such-package')
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+
+ it 'responds with 404 Not Found for non existing package file' do
+ project.add_developer(user)
+
+ download_file(personal_access_token_header, file_name: 'no-such-file')
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+
+ def download_file(request_headers, package_name: nil, file_name: nil)
+ package_name ||= package.name
+ file_name ||= package_file.file_name
+ url = "/projects/#{project.id}/packages/generic/#{package_name}/#{package.version}/#{file_name}"
- get api('/projects/%d/packages/generic/ping' % project.id), headers: headers
+ get api(url), headers: request_headers
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 0838900eaba..5d5b963fed5 100644
--- a/spec/requests/api/graphql/boards/board_lists_query_spec.rb
+++ b/spec/requests/api/graphql/boards/board_lists_query_spec.rb
@@ -7,8 +7,8 @@ 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(:group) { create(:group, :private) }
+ let_it_be(:project) { create(:project, creator_id: user.id, group: group) }
let_it_be(:project_label) { create(:label, project: project, name: 'Development') }
let_it_be(:project_label2) { create(:label, project: project, name: 'Testing') }
let_it_be(:group_label) { create(:group_label, group: group, name: 'Development') }
@@ -111,12 +111,19 @@ RSpec.describe 'get board lists' do
board_parent.add_reporter(user)
end
- it 'finds the correct list' do
+ 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])
- post_graphql(query("id: \"#{global_id_of(label_list)}\""), current_user: user)
+ post_graphql(query(id: global_id_of(label_list), issueFilters: { labelName: label2.title }), current_user: user)
- expect(lists_data[0]['node']['title']).to eq label_list.title
+ aggregate_failures do
+ list_node = lists_data[0]['node']
+
+ expect(list_node['title']).to eq label_list.title
+ expect(list_node['issuesCount']).to eq 1
+ end
end
end
end
diff --git a/spec/requests/api/graphql/gitlab_schema_spec.rb b/spec/requests/api/graphql/gitlab_schema_spec.rb
index ee7dba545be..fe1c7c15de2 100644
--- a/spec/requests/api/graphql/gitlab_schema_spec.rb
+++ b/spec/requests/api/graphql/gitlab_schema_spec.rb
@@ -190,7 +190,9 @@ RSpec.describe 'GitlabSchema configurations' do
variables: {}.to_s,
complexity: 181,
depth: 13,
- duration_s: 7
+ duration_s: 7,
+ used_fields: an_instance_of(Array),
+ used_deprecated_fields: an_instance_of(Array)
}
expect_any_instance_of(Gitlab::Graphql::QueryAnalyzers::LoggerAnalyzer).to receive(:duration).and_return(7)
diff --git a/spec/requests/api/graphql/group/merge_requests_spec.rb b/spec/requests/api/graphql/group/merge_requests_spec.rb
new file mode 100644
index 00000000000..e9a5e558b1d
--- /dev/null
+++ b/spec/requests/api/graphql/group/merge_requests_spec.rb
@@ -0,0 +1,122 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+# Based on ee/spec/requests/api/epics_spec.rb
+# Should follow closely in order to ensure all situations are covered
+RSpec.describe 'Query.group.mergeRequests' do
+ include GraphqlHelpers
+
+ let_it_be(:group) { create(:group) }
+ let_it_be(:sub_group) { create(:group, parent: group) }
+
+ let_it_be(:project_a) { create(:project, :repository, group: group) }
+ let_it_be(:project_b) { create(:project, :repository, group: group) }
+ let_it_be(:project_c) { create(:project, :repository, group: sub_group) }
+ let_it_be(:project_x) { create(:project, :repository) }
+ let_it_be(:user) { create(:user, developer_projects: [project_x]) }
+
+ let_it_be(:mr_attrs) do
+ { target_branch: 'master' }
+ end
+
+ let_it_be(:mr_traits) do
+ [:unique_branches, :unique_author]
+ end
+
+ let_it_be(:mrs_a, reload: true) { create_list(:merge_request, 2, *mr_traits, **mr_attrs, source_project: project_a) }
+ let_it_be(:mrs_b, reload: true) { create_list(:merge_request, 2, *mr_traits, **mr_attrs, source_project: project_b) }
+ let_it_be(:mrs_c, reload: true) { create_list(:merge_request, 2, *mr_traits, **mr_attrs, source_project: project_c) }
+ let_it_be(:other_mr) { create(:merge_request, source_project: project_x) }
+
+ let(:mrs_data) { graphql_data_at(:group, :merge_requests, :nodes) }
+
+ before do
+ group.add_developer(user)
+ end
+
+ def expected_mrs(mrs)
+ mrs.map { |mr| a_hash_including('id' => global_id_of(mr)) }
+ end
+
+ describe 'not passing any arguments' do
+ let(:query) do
+ <<~GQL
+ query($path: ID!) {
+ group(fullPath: $path) {
+ mergeRequests { nodes { id } }
+ }
+ }
+ GQL
+ end
+
+ it 'can find all merge requests in the group, excluding sub-groups' do
+ post_graphql(query, current_user: user, variables: { path: group.full_path })
+
+ expect(mrs_data).to match_array(expected_mrs(mrs_a + mrs_b))
+ end
+ end
+
+ describe 'restricting by author' do
+ let(:query) do
+ <<~GQL
+ query($path: ID!, $user: String) {
+ group(fullPath: $path) {
+ mergeRequests(authorUsername: $user) { nodes { id author { username } } }
+ }
+ }
+ GQL
+ end
+
+ let(:author) { mrs_b.first.author }
+
+ it 'can find all merge requests with user as author' do
+ post_graphql(query, current_user: user, variables: { user: author.username, path: group.full_path })
+
+ expect(mrs_data).to match_array(expected_mrs([mrs_b.first]))
+ end
+ end
+
+ describe 'restricting by assignee' do
+ let(:query) do
+ <<~GQL
+ query($path: ID!, $user: String) {
+ group(fullPath: $path) {
+ mergeRequests(assigneeUsername: $user) { nodes { id } }
+ }
+ }
+ GQL
+ end
+
+ let_it_be(:assignee) { create(:user) }
+
+ before_all do
+ mrs_b.second.assignees << assignee
+ mrs_a.first.assignees << assignee
+ end
+
+ it 'can find all merge requests assigned to user' do
+ post_graphql(query, current_user: user, variables: { user: assignee.username, path: group.full_path })
+
+ expect(mrs_data).to match_array(expected_mrs([mrs_a.first, mrs_b.second]))
+ end
+ end
+
+ describe 'passing include_subgroups: true' do
+ let(:query) do
+ <<~GQL
+ query($path: ID!) {
+ group(fullPath: $path) {
+ mergeRequests(includeSubgroups: true) { nodes { id } }
+ }
+ }
+ GQL
+ end
+
+ it 'can find all merge requests in the group, including sub-groups' do
+ post_graphql(query, current_user: user, variables: { path: group.full_path })
+
+ expect(mrs_data).to match_array(expected_mrs(mrs_a + mrs_b + mrs_c))
+ end
+ end
+end
diff --git a/spec/requests/api/graphql/instance_statistics_measurements_spec.rb b/spec/requests/api/graphql/instance_statistics_measurements_spec.rb
index b8cbe54534a..5d7dbcf2e3c 100644
--- a/spec/requests/api/graphql/instance_statistics_measurements_spec.rb
+++ b/spec/requests/api/graphql/instance_statistics_measurements_spec.rb
@@ -9,13 +9,16 @@ RSpec.describe 'InstanceStatisticsMeasurements' do
let!(:instance_statistics_measurement_1) { create(:instance_statistics_measurement, :project_count, recorded_at: 20.days.ago, count: 5) }
let!(:instance_statistics_measurement_2) { create(:instance_statistics_measurement, :project_count, recorded_at: 10.days.ago, count: 10) }
- let(:query) { graphql_query_for(:instanceStatisticsMeasurements, 'identifier: PROJECTS', 'nodes { count }') }
+ let(:query) { graphql_query_for(:instanceStatisticsMeasurements, 'identifier: PROJECTS', 'nodes { count identifier }') }
before do
post_graphql(query, current_user: current_user)
end
it 'returns measurement objects' do
- expect(graphql_data.dig('instanceStatisticsMeasurements', 'nodes')).to eq([{ "count" => 10 }, { "count" => 5 }])
+ expect(graphql_data.dig('instanceStatisticsMeasurements', 'nodes')).to eq([
+ { "count" => 10, 'identifier' => 'PROJECTS' },
+ { "count" => 5, 'identifier' => 'PROJECTS' }
+ ])
end
end
diff --git a/spec/requests/api/graphql/mutations/award_emojis/add_spec.rb b/spec/requests/api/graphql/mutations/award_emojis/add_spec.rb
index 1d38bb39d59..3aaebb5095a 100644
--- a/spec/requests/api/graphql/mutations/award_emojis/add_spec.rb
+++ b/spec/requests/api/graphql/mutations/award_emojis/add_spec.rb
@@ -45,8 +45,9 @@ RSpec.describe 'Adding an AwardEmoji' do
it_behaves_like 'a mutation that does not create an AwardEmoji'
- it_behaves_like 'a mutation that returns top-level errors',
- errors: ['Cannot award emoji to this resource']
+ it_behaves_like 'a mutation that returns top-level errors' do
+ let(:match_errors) { include(/was provided invalid value for awardableId/) }
+ end
end
context 'when the given awardable is an Awardable but still cannot be awarded an emoji' do
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 c6e8800de1f..7cd39f93ae7 100644
--- a/spec/requests/api/graphql/mutations/award_emojis/remove_spec.rb
+++ b/spec/requests/api/graphql/mutations/award_emojis/remove_spec.rb
@@ -50,8 +50,9 @@ RSpec.describe 'Removing an AwardEmoji' do
it_behaves_like 'a mutation that does not destroy an AwardEmoji'
- it_behaves_like 'a mutation that returns top-level errors',
- errors: ['Cannot award emoji to this resource']
+ it_behaves_like 'a mutation that returns top-level errors' do
+ let(:match_errors) { include(/was provided invalid value for awardableId/) }
+ end
end
context 'when the given awardable is an Awardable' 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 2df59ce97ca..6910ad80a11 100644
--- a/spec/requests/api/graphql/mutations/award_emojis/toggle_spec.rb
+++ b/spec/requests/api/graphql/mutations/award_emojis/toggle_spec.rb
@@ -44,8 +44,9 @@ RSpec.describe 'Toggling an AwardEmoji' do
it_behaves_like 'a mutation that does not create or destroy an AwardEmoji'
- it_behaves_like 'a mutation that returns top-level errors',
- errors: ['Cannot award emoji to this resource']
+ it_behaves_like 'a mutation that returns top-level errors' do
+ let(:match_errors) { include(/was provided invalid value for awardableId/) }
+ end
end
context 'when the given awardable is an Awardable but still cannot be awarded an emoji' do
diff --git a/spec/requests/api/graphql/mutations/boards/create_spec.rb b/spec/requests/api/graphql/mutations/boards/create_spec.rb
new file mode 100644
index 00000000000..c5f981262ea
--- /dev/null
+++ b/spec/requests/api/graphql/mutations/boards/create_spec.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Mutations::Boards::Create do
+ let_it_be(:parent) { create(:project) }
+ let(:project_path) { parent.full_path }
+ let(:params) do
+ {
+ project_path: project_path,
+ name: name
+ }
+ end
+
+ it_behaves_like 'boards create mutation'
+end
diff --git a/spec/requests/api/graphql/mutations/boards/lists/destroy_spec.rb b/spec/requests/api/graphql/mutations/boards/lists/destroy_spec.rb
new file mode 100644
index 00000000000..42f690f53ed
--- /dev/null
+++ b/spec/requests/api/graphql/mutations/boards/lists/destroy_spec.rb
@@ -0,0 +1,77 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Mutations::Boards::Lists::Destroy do
+ include GraphqlHelpers
+
+ let_it_be(:current_user, reload: true) { create(:user) }
+ let_it_be(:project, reload: true) { create(:project) }
+ let_it_be(:board) { create(:board, project: project) }
+ let_it_be(:list) { create(:list, board: board) }
+ let(:mutation) do
+ variables = {
+ list_id: GitlabSchema.id_from_object(list).to_s
+ }
+
+ graphql_mutation(:destroy_board_list, variables)
+ end
+
+ subject { post_graphql_mutation(mutation, current_user: current_user) }
+
+ def mutation_response
+ graphql_mutation_response(:destroy_board_list)
+ end
+
+ context 'when the user does not have permission' do
+ it_behaves_like 'a mutation that returns a top-level access error'
+
+ it 'does not destroy the list' do
+ expect { subject }.not_to change { List.count }
+ end
+ end
+
+ context 'when the user has permission' do
+ before do
+ project.add_maintainer(current_user)
+ end
+
+ context 'when given id is not for a list' do
+ let_it_be(:list) { build_stubbed(:issue, project: project) }
+
+ it 'returns an error' do
+ subject
+
+ expect(graphql_errors.first['message']).to include('does not represent an instance of List')
+ end
+ end
+
+ context 'when everything is ok' do
+ it 'destroys the list' do
+ expect { subject }.to change { List.count }.from(2).to(1)
+ end
+
+ it 'returns an empty list' do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ expect(mutation_response).to have_key('list')
+ expect(mutation_response['list']).to be_nil
+ end
+ end
+
+ context 'when the list is not destroyable' do
+ let_it_be(:list) { create(:list, board: board, list_type: :backlog) }
+
+ it 'does not destroy the list' do
+ expect { subject }.not_to change { List.count }.from(3)
+ end
+
+ it 'returns an error and not nil list' do
+ subject
+
+ expect(mutation_response['errors']).not_to be_empty
+ expect(mutation_response['list']).not_to be_nil
+ end
+ 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
new file mode 100644
index 00000000000..39b408faa90
--- /dev/null
+++ b/spec/requests/api/graphql/mutations/issues/create_spec.rb
@@ -0,0 +1,48 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Create an issue' do
+ include GraphqlHelpers
+
+ let_it_be(:current_user) { create(:user) }
+ let_it_be(:project) { create(:project) }
+ let_it_be(:assignee1) { create(:user) }
+ let_it_be(:assignee2) { create(:user) }
+ let_it_be(:project_label1) { create(:label, project: project) }
+ let_it_be(:project_label2) { create(:label, project: project) }
+ let_it_be(:milestone) { create(:milestone, project: project) }
+ let_it_be(:new_label1) { FFaker::Lorem.word }
+ let_it_be(:new_label2) { FFaker::Lorem.word }
+
+ let(:input) do
+ {
+ 'title' => 'new title',
+ 'description' => 'new description',
+ 'confidential' => true,
+ 'dueDate' => Date.tomorrow.strftime('%Y-%m-%d')
+ }
+ end
+
+ let(:mutation) { graphql_mutation(:createIssue, input.merge('projectPath' => project.full_path, 'locked' => true)) }
+
+ let(:mutation_response) { graphql_mutation_response(:create_issue) }
+
+ context 'the user is not allowed to create an issue' do
+ it_behaves_like 'a mutation that returns a top-level access error'
+ end
+
+ context 'when user has permissions to create an issue' do
+ before do
+ project.add_developer(current_user)
+ end
+
+ it 'updates the issue' do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ expect(response).to have_gitlab_http_status(:success)
+ expect(mutation_response['issue']).to include(input)
+ expect(mutation_response['issue']).to include('discussionLocked' => true)
+ end
+ end
+end
diff --git a/spec/requests/api/graphql/mutations/issues/move_spec.rb b/spec/requests/api/graphql/mutations/issues/move_spec.rb
new file mode 100644
index 00000000000..5bbaff61edd
--- /dev/null
+++ b/spec/requests/api/graphql/mutations/issues/move_spec.rb
@@ -0,0 +1,73 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Moving an issue' do
+ include GraphqlHelpers
+
+ let_it_be(:user) { create(:user) }
+ let_it_be(:issue) { create(:issue) }
+ let_it_be(:target_project) { create(:project) }
+
+ let(:mutation) do
+ variables = {
+ project_path: issue.project.full_path,
+ target_project_path: target_project.full_path,
+ iid: issue.iid.to_s
+ }
+
+ graphql_mutation(:issue_move, variables,
+ <<-QL.strip_heredoc
+ clientMutationId
+ errors
+ issue {
+ title
+ }
+ QL
+ )
+ end
+
+ def mutation_response
+ graphql_mutation_response(:issue_move)
+ end
+
+ context 'when the user is not allowed to read source project' do
+ it 'returns an error' do
+ error = "The resource that you are attempting to access does not exist or you don't have permission to perform this action"
+ post_graphql_mutation(mutation, current_user: user)
+
+ expect(response).to have_gitlab_http_status(:success)
+ expect(graphql_errors).to include(a_hash_including('message' => error))
+ end
+ end
+
+ context 'when the user is not allowed to move issue to target project' do
+ before do
+ issue.project.add_developer(user)
+ end
+
+ it 'returns an error' do
+ error = "Cannot move issue due to insufficient permissions!"
+ post_graphql_mutation(mutation, current_user: user)
+
+ expect(response).to have_gitlab_http_status(:success)
+ expect(mutation_response['errors'][0]).to eq(error)
+ end
+ end
+
+ context 'when the user is allowed to move issue' do
+ before do
+ issue.project.add_developer(user)
+ target_project.add_developer(user)
+ end
+
+ it 'moves the issue' do
+ post_graphql_mutation(mutation, current_user: user)
+
+ expect(response).to have_gitlab_http_status(:success)
+ expect(mutation_response.dig('issue', 'title')).to eq(issue.title)
+ expect(issue.reload.state).to eq('closed')
+ expect(target_project.issues.find_by_title(issue.title)).to be_present
+ end
+ end
+end
diff --git a/spec/requests/api/graphql/mutations/issues/update_spec.rb b/spec/requests/api/graphql/mutations/issues/update_spec.rb
index af52f9d57a3..71f25dbbe49 100644
--- a/spec/requests/api/graphql/mutations/issues/update_spec.rb
+++ b/spec/requests/api/graphql/mutations/issues/update_spec.rb
@@ -10,13 +10,15 @@ RSpec.describe 'Update of an existing issue' do
let_it_be(:issue) { create(:issue, project: project) }
let(:input) do
{
- project_path: project.full_path,
- iid: issue.iid.to_s,
- locked: true
+ 'iid' => issue.iid.to_s,
+ 'title' => 'new title',
+ 'description' => 'new description',
+ 'confidential' => true,
+ 'dueDate' => Date.tomorrow.strftime('%Y-%m-%d')
}
end
- let(:mutation) { graphql_mutation(:update_issue, input) }
+ let(:mutation) { graphql_mutation(:update_issue, input.merge(project_path: project.full_path, locked: true)) }
let(:mutation_response) { graphql_mutation_response(:update_issue) }
context 'the user is not allowed to update issue' do
@@ -32,9 +34,8 @@ RSpec.describe 'Update of an existing issue' do
post_graphql_mutation(mutation, current_user: current_user)
expect(response).to have_gitlab_http_status(:success)
- expect(mutation_response['issue']).to include(
- 'discussionLocked' => true
- )
+ expect(mutation_response['issue']).to include(input)
+ expect(mutation_response['issue']).to include('discussionLocked' => true)
end
end
end
diff --git a/spec/requests/api/graphql/mutations/metrics/dashboard/annotations/create_spec.rb b/spec/requests/api/graphql/mutations/metrics/dashboard/annotations/create_spec.rb
index 10ca2cf1cf8..81d13b29dde 100644
--- a/spec/requests/api/graphql/mutations/metrics/dashboard/annotations/create_spec.rb
+++ b/spec/requests/api/graphql/mutations/metrics/dashboard/annotations/create_spec.rb
@@ -101,7 +101,9 @@ RSpec.describe Mutations::Metrics::Dashboard::Annotations::Create do
graphql_mutation(:create_annotation, variables)
end
- it_behaves_like 'a mutation that returns top-level errors', errors: ['invalid_id is not a valid GitLab ID.']
+ it_behaves_like 'a mutation that returns top-level errors' do
+ let(:match_errors) { include(/is not a valid Global ID/) }
+ end
end
end
end
@@ -109,7 +111,7 @@ RSpec.describe Mutations::Metrics::Dashboard::Annotations::Create do
context 'when annotation source is cluster' do
let(:mutation) do
variables = {
- cluster_id: GitlabSchema.id_from_object(cluster).to_s,
+ cluster_id: cluster.to_global_id.to_s,
starting_at: starting_at,
ending_at: ending_at,
dashboard_path: dashboard_path,
@@ -188,15 +190,17 @@ RSpec.describe Mutations::Metrics::Dashboard::Annotations::Create do
graphql_mutation(:create_annotation, variables)
end
- it_behaves_like 'a mutation that returns top-level errors', errors: ['invalid_id is not a valid GitLab ID.']
+ it_behaves_like 'a mutation that returns top-level errors' do
+ let(:match_errors) { include(/is not a valid Global ID/) }
+ end
end
end
context 'when both environment_id and cluster_id are provided' do
let(:mutation) do
variables = {
- environment_id: GitlabSchema.id_from_object(environment).to_s,
- cluster_id: GitlabSchema.id_from_object(cluster).to_s,
+ environment_id: environment.to_global_id.to_s,
+ cluster_id: cluster.to_global_id.to_s,
starting_at: starting_at,
ending_at: ending_at,
dashboard_path: dashboard_path,
@@ -210,14 +214,14 @@ RSpec.describe Mutations::Metrics::Dashboard::Annotations::Create do
end
context 'when a non-cluster or environment id is provided' do
+ let(:gid) { { environment_id: project.to_global_id.to_s } }
let(:mutation) do
variables = {
- environment_id: GitlabSchema.id_from_object(project).to_s,
starting_at: starting_at,
ending_at: ending_at,
dashboard_path: dashboard_path,
description: description
- }
+ }.merge!(gid)
graphql_mutation(:create_annotation, variables)
end
@@ -226,6 +230,18 @@ RSpec.describe Mutations::Metrics::Dashboard::Annotations::Create do
project.add_developer(current_user)
end
- it_behaves_like 'a mutation that returns top-level errors', errors: [described_class::INVALID_ANNOTATION_SOURCE_ERROR]
+ describe 'non-environment id' do
+ it_behaves_like 'a mutation that returns top-level errors' do
+ let(:match_errors) { include(/does not represent an instance of Environment/) }
+ end
+ end
+
+ describe 'non-cluster id' do
+ let(:gid) { { cluster_id: project.to_global_id.to_s } }
+
+ it_behaves_like 'a mutation that returns top-level errors' do
+ let(:match_errors) { include(/does not represent an instance of Clusters::Cluster/) }
+ end
+ end
end
end
diff --git a/spec/requests/api/graphql/mutations/notes/create/note_spec.rb b/spec/requests/api/graphql/mutations/notes/create/note_spec.rb
index 391ced7dc98..6d761eb0a54 100644
--- a/spec/requests/api/graphql/mutations/notes/create/note_spec.rb
+++ b/spec/requests/api/graphql/mutations/notes/create/note_spec.rb
@@ -60,6 +60,14 @@ RSpec.describe 'Adding a Note' do
expect(mutation_response['note']['discussion']['id']).to eq(discussion.to_global_id.to_s)
end
+
+ context 'when the discussion_id is not for a Discussion' do
+ let(:discussion) { create(:issue) }
+
+ it_behaves_like 'a mutation that returns top-level errors' do
+ let(:match_errors) { include(/ does not represent an instance of Discussion/) }
+ end
+ end
end
end
end
diff --git a/spec/requests/api/graphql/mutations/notes/update/image_diff_note_spec.rb b/spec/requests/api/graphql/mutations/notes/update/image_diff_note_spec.rb
index 0c00906d6bf..efa2ceb65c2 100644
--- a/spec/requests/api/graphql/mutations/notes/update/image_diff_note_spec.rb
+++ b/spec/requests/api/graphql/mutations/notes/update/image_diff_note_spec.rb
@@ -178,6 +178,12 @@ RSpec.describe 'Updating an image DiffNote' do
it_behaves_like 'a mutation that returns top-level errors', errors: ['body or position arguments are required']
end
+ context 'when the resource is not a Note' do
+ let(:diff_note) { note }
+
+ it_behaves_like 'a Note mutation when the given resource id is not for a Note'
+ end
+
context 'when resource is not a DiffNote on an image' do
let!(:diff_note) { create(:diff_note_on_merge_request, note: original_body) }
diff --git a/spec/requests/api/graphql/mutations/snippets/create_spec.rb b/spec/requests/api/graphql/mutations/snippets/create_spec.rb
index 1bb446de708..d2fa3cfc24f 100644
--- a/spec/requests/api/graphql/mutations/snippets/create_spec.rb
+++ b/spec/requests/api/graphql/mutations/snippets/create_spec.rb
@@ -76,21 +76,25 @@ RSpec.describe 'Creating a Snippet' do
expect(mutation_response['snippet']).to be_nil
end
+
+ it_behaves_like 'spam flag is present'
end
shared_examples 'creates snippet' do
- it 'returns the created Snippet' do
+ it 'returns the created Snippet', :aggregate_failures do
expect do
subject
end.to change { Snippet.count }.by(1)
+ snippet = Snippet.last
+ created_file_1 = snippet.repository.blob_at('HEAD', file_1[:filePath])
+ created_file_2 = snippet.repository.blob_at('HEAD', file_2[:filePath])
+
+ expect(created_file_1.data).to match(file_1[:content])
+ expect(created_file_2.data).to match(file_2[:content])
expect(mutation_response['snippet']['title']).to eq(title)
expect(mutation_response['snippet']['description']).to eq(description)
expect(mutation_response['snippet']['visibilityLevel']).to eq(visibility_level)
- expect(mutation_response['snippet']['blobs'][0]['plainData']).to match(file_1[:content])
- expect(mutation_response['snippet']['blobs'][0]['fileName']).to match(file_1[:file_path])
- expect(mutation_response['snippet']['blobs'][1]['plainData']).to match(file_2[:content])
- expect(mutation_response['snippet']['blobs'][1]['fileName']).to match(file_2[:file_path])
end
context 'when action is invalid' do
@@ -101,6 +105,10 @@ RSpec.describe 'Creating a Snippet' do
end
it_behaves_like 'snippet edit usage data counters'
+ it_behaves_like 'spam flag is present'
+ it_behaves_like 'can raise spam flag' do
+ let(:service) { Snippets::CreateService }
+ end
end
context 'with PersonalSnippet' do
@@ -140,6 +148,9 @@ RSpec.describe 'Creating a Snippet' do
it_behaves_like 'a mutation that returns errors in the response', errors: ["Title can't be blank"]
it_behaves_like 'does not create snippet'
+ it_behaves_like 'can raise spam flag' do
+ let(:service) { Snippets::CreateService }
+ end
end
context 'when there non ActiveRecord errors' do
diff --git a/spec/requests/api/graphql/mutations/snippets/update_spec.rb b/spec/requests/api/graphql/mutations/snippets/update_spec.rb
index 58ce74b9263..21d403c6f73 100644
--- a/spec/requests/api/graphql/mutations/snippets/update_spec.rb
+++ b/spec/requests/api/graphql/mutations/snippets/update_spec.rb
@@ -37,6 +37,8 @@ RSpec.describe 'Updating a Snippet' do
graphql_mutation_response(:update_snippet)
end
+ subject { post_graphql_mutation(mutation, current_user: current_user) }
+
shared_examples 'graphql update actions' do
context 'when the user does not have permission' do
let(:current_user) { create(:user) }
@@ -46,14 +48,14 @@ RSpec.describe 'Updating a Snippet' do
it 'does not update the Snippet' do
expect do
- post_graphql_mutation(mutation, current_user: current_user)
+ subject
end.not_to change { snippet.reload }
end
end
context 'when the user has permission' do
it 'updates the snippet record' do
- post_graphql_mutation(mutation, current_user: current_user)
+ subject
expect(snippet.reload.title).to eq(updated_title)
end
@@ -65,7 +67,7 @@ RSpec.describe 'Updating a Snippet' do
expect(blob_to_update.data).not_to eq updated_content
expect(blob_to_delete).to be_present
- post_graphql_mutation(mutation, current_user: current_user)
+ subject
blob_to_update = blob_at(updated_file)
blob_to_delete = blob_at(deleted_file)
@@ -73,20 +75,25 @@ RSpec.describe 'Updating a Snippet' do
aggregate_failures do
expect(blob_to_update.data).to eq updated_content
expect(blob_to_delete).to be_nil
- expect(blob_in_mutation_response(updated_file)['plainData']).to match(updated_content)
expect(mutation_response['snippet']['title']).to eq(updated_title)
expect(mutation_response['snippet']['description']).to eq(updated_description)
expect(mutation_response['snippet']['visibilityLevel']).to eq('public')
end
end
+ it_behaves_like 'can raise spam flag' do
+ let(:service) { Snippets::UpdateService }
+ end
+
+ it_behaves_like 'spam flag is present'
+
context 'when there are ActiveRecord validation errors' do
let(:updated_title) { '' }
it_behaves_like 'a mutation that returns errors in the response', errors: ["Title can't be blank"]
it 'does not update the Snippet' do
- post_graphql_mutation(mutation, current_user: current_user)
+ subject
expect(snippet.reload.title).to eq(original_title)
end
@@ -95,21 +102,21 @@ RSpec.describe 'Updating a Snippet' do
blob_to_update = blob_at(updated_file)
blob_to_delete = blob_at(deleted_file)
- post_graphql_mutation(mutation, current_user: current_user)
+ subject
aggregate_failures do
expect(blob_at(updated_file).data).to eq blob_to_update.data
expect(blob_at(deleted_file).data).to eq blob_to_delete.data
- expect(blob_in_mutation_response(deleted_file)['plainData']).not_to be_nil
expect(mutation_response['snippet']['title']).to eq(original_title)
expect(mutation_response['snippet']['description']).to eq(original_description)
expect(mutation_response['snippet']['visibilityLevel']).to eq('private')
end
end
- end
- def blob_in_mutation_response(filename)
- mutation_response['snippet']['blobs'].select { |blob| blob['name'] == filename }[0]
+ it_behaves_like 'spam flag is present'
+ it_behaves_like 'can raise spam flag' do
+ let(:service) { Snippets::UpdateService }
+ end
end
def blob_at(filename)
@@ -150,7 +157,7 @@ RSpec.describe 'Updating a Snippet' do
context 'when the author is not a member of the project' do
it 'returns an an error' do
- post_graphql_mutation(mutation, current_user: current_user)
+ subject
errors = json_response['errors']
expect(errors.first['message']).to eq(Gitlab::Graphql::Authorize::AuthorizeResource::RESOURCE_ACCESS_ERROR)
@@ -168,7 +175,7 @@ RSpec.describe 'Updating a Snippet' do
it 'returns an an error' do
project.project_feature.update_attribute(:snippets_access_level, ProjectFeature::DISABLED)
- post_graphql_mutation(mutation, current_user: current_user)
+ subject
errors = json_response['errors']
expect(errors.first['message']).to eq(Gitlab::Graphql::Authorize::AuthorizeResource::RESOURCE_ACCESS_ERROR)
diff --git a/spec/requests/api/graphql/mutations/todos/mark_done_spec.rb b/spec/requests/api/graphql/mutations/todos/mark_done_spec.rb
index 8bf8b96aff5..8a9a0b9e845 100644
--- a/spec/requests/api/graphql/mutations/todos/mark_done_spec.rb
+++ b/spec/requests/api/graphql/mutations/todos/mark_done_spec.rb
@@ -76,15 +76,15 @@ RSpec.describe 'Marking todos done' do
end
context 'when using an invalid gid' do
- let(:input) { { id: 'invalid_gid' } }
- let(:invalid_gid_error) { 'invalid_gid is not a valid GitLab ID.' }
+ let(:input) { { id: GitlabSchema.id_from_object(author).to_s } }
+ let(:invalid_gid_error) { /"#{input[:id]}" does not represent an instance of #{todo1.class}/ }
it 'contains the expected error' do
post_graphql_mutation(mutation, current_user: current_user)
errors = json_response['errors']
expect(errors).not_to be_blank
- expect(errors.first['message']).to eq(invalid_gid_error)
+ expect(errors.first['message']).to match(invalid_gid_error)
expect(todo1.reload.state).to eq('pending')
expect(todo2.reload.state).to eq('done')
diff --git a/spec/requests/api/graphql/mutations/todos/restore_spec.rb b/spec/requests/api/graphql/mutations/todos/restore_spec.rb
index 8451dcdf587..a58c7fc69fc 100644
--- a/spec/requests/api/graphql/mutations/todos/restore_spec.rb
+++ b/spec/requests/api/graphql/mutations/todos/restore_spec.rb
@@ -76,15 +76,15 @@ RSpec.describe 'Restoring Todos' do
end
context 'when using an invalid gid' do
- let(:input) { { id: 'invalid_gid' } }
- let(:invalid_gid_error) { 'invalid_gid is not a valid GitLab ID.' }
+ let(:input) { { id: GitlabSchema.id_from_object(author).to_s } }
+ let(:invalid_gid_error) { /"#{input[:id]}" does not represent an instance of #{todo1.class}/ }
it 'contains the expected error' do
post_graphql_mutation(mutation, current_user: current_user)
errors = json_response['errors']
expect(errors).not_to be_blank
- expect(errors.first['message']).to eq(invalid_gid_error)
+ expect(errors.first['message']).to match(invalid_gid_error)
expect(todo1.reload.state).to eq('done')
expect(todo2.reload.state).to eq('pending')
diff --git a/spec/requests/api/graphql/project/alert_management/alerts_spec.rb b/spec/requests/api/graphql/project/alert_management/alerts_spec.rb
index d3a2e6a1deb..8deed75a466 100644
--- a/spec/requests/api/graphql/project/alert_management/alerts_spec.rb
+++ b/spec/requests/api/graphql/project/alert_management/alerts_spec.rb
@@ -139,6 +139,19 @@ RSpec.describe 'getting Alert Management Alerts' do
it { expect(alerts.size).to eq(0) }
end
end
+
+ context 'assignee_username' do
+ let(:alert) { triggered_alert }
+ let(:assignee) { alert.assignees.first! }
+ let(:params) { { assignee_username: assignee.username } }
+
+ it_behaves_like 'a working graphql query'
+
+ specify do
+ expect(alerts.size).to eq(1)
+ expect(first_alert['iid']).to eq(alert.iid.to_s)
+ end
+ end
end
end
end
diff --git a/spec/requests/api/graphql/project/issue/designs/notes_spec.rb b/spec/requests/api/graphql/project/issue/designs/notes_spec.rb
index 65191e057c7..e25453510d5 100644
--- a/spec/requests/api/graphql/project/issue/designs/notes_spec.rb
+++ b/spec/requests/api/graphql/project/issue/designs/notes_spec.rb
@@ -31,8 +31,8 @@ RSpec.describe 'Getting designs related to an issue' do
post_graphql(query(note_fields), current_user: nil)
designs_data = graphql_data['project']['issue']['designs']['designs']
- design_data = designs_data['edges'].first['node']
- note_data = design_data['notes']['edges'].first['node']
+ design_data = designs_data['nodes'].first
+ note_data = design_data['notes']['nodes'].first
expect(note_data['id']).to eq(note.to_global_id.to_s)
end
@@ -40,14 +40,10 @@ RSpec.describe 'Getting designs related to an issue' do
def query(note_fields = all_graphql_fields_for(Note))
design_node = <<~NODE
designs {
- edges {
- node {
- notes {
- edges {
- node {
- #{note_fields}
- }
- }
+ nodes {
+ notes {
+ nodes {
+ #{note_fields}
}
}
}
diff --git a/spec/requests/api/graphql/project/issues_spec.rb b/spec/requests/api/graphql/project/issues_spec.rb
index 5d4276f47ca..40fec6ba068 100644
--- a/spec/requests/api/graphql/project/issues_spec.rb
+++ b/spec/requests/api/graphql/project/issues_spec.rb
@@ -53,16 +53,37 @@ RSpec.describe 'getting an issue list for a project' do
context 'when limiting the number of results' do
let(:query) do
- graphql_query_for(
- 'project',
- { 'fullPath' => project.full_path },
- "issues(first: 1) { #{fields} }"
- )
+ <<~GQL
+ query($path: ID!, $n: Int) {
+ project(fullPath: $path) {
+ issues(first: $n) { #{fields} }
+ }
+ }
+ GQL
+ end
+
+ let(:issue_limit) { 1 }
+ let(:variables) do
+ { path: project.full_path, n: issue_limit }
end
it_behaves_like 'a working graphql query' do
before do
- post_graphql(query, current_user: current_user)
+ post_graphql(query, current_user: current_user, variables: variables)
+ end
+
+ it 'only returns N issues' do
+ expect(issues_data.size).to eq(issue_limit)
+ end
+ end
+
+ context 'no limit is provided' do
+ let(:issue_limit) { nil }
+
+ it 'returns all issues' do
+ post_graphql(query, current_user: current_user, variables: variables)
+
+ expect(issues_data.size).to be > 1
end
end
@@ -71,7 +92,7 @@ RSpec.describe 'getting an issue list for a project' do
# Newest first, we only want to see the newest checked
expect(Ability).not_to receive(:allowed?).with(current_user, :read_issue, issues.first)
- post_graphql(query, current_user: current_user)
+ post_graphql(query, current_user: current_user, variables: variables)
end
end
diff --git a/spec/requests/api/graphql/project/merge_requests_spec.rb b/spec/requests/api/graphql/project/merge_requests_spec.rb
index 22b003501a1..c737e0b8caf 100644
--- a/spec/requests/api/graphql/project/merge_requests_spec.rb
+++ b/spec/requests/api/graphql/project/merge_requests_spec.rb
@@ -13,6 +13,7 @@ RSpec.describe 'getting merge request listings nested in a project' do
let_it_be(:merge_request_b) { create(:merge_request, :closed, :unique_branches, source_project: project) }
let_it_be(:merge_request_c) { create(:labeled_merge_request, :closed, :unique_branches, source_project: project, labels: [label]) }
let_it_be(:merge_request_d) { create(:merge_request, :locked, :unique_branches, source_project: project) }
+ let_it_be(:merge_request_e) { create(:merge_request, :unique_branches, source_project: project) }
let(:results) { graphql_data.dig('project', 'mergeRequests', 'nodes') }
@@ -118,7 +119,7 @@ RSpec.describe 'getting merge request listings nested in a project' do
context 'there are no search params' do
let(:search_params) { nil }
- let(:mrs) { [merge_request_a, merge_request_b, merge_request_c, merge_request_d] }
+ let(:mrs) { [merge_request_a, merge_request_b, merge_request_c, merge_request_d, merge_request_e] }
it_behaves_like 'searching with parameters'
end
@@ -172,6 +173,28 @@ RSpec.describe 'getting merge request listings nested in a project' do
it_behaves_like 'searching with parameters'
end
+ context 'when requesting `approved_by`' do
+ let(:search_params) { { iids: [merge_request_a.iid.to_s, merge_request_b.iid.to_s] } }
+ let(:extra_iid_for_second_query) { merge_request_c.iid.to_s }
+ let(:requested_fields) { query_graphql_field(:approved_by, nil, query_graphql_field(:nodes, nil, [:username])) }
+
+ def execute_query
+ query = query_merge_requests(requested_fields)
+ post_graphql(query, current_user: current_user)
+ end
+
+ it 'exposes approver username' do
+ merge_request_a.approved_by_users << current_user
+
+ execute_query
+
+ user_data = { 'username' => current_user.username }
+ expect(results).to include(a_hash_including('approvedBy' => { 'nodes' => array_including(user_data) }))
+ end
+
+ include_examples 'N+1 query check'
+ end
+
describe 'fields' do
let(:requested_fields) { nil }
let(:extra_iid_for_second_query) { merge_request_c.iid.to_s }
@@ -209,7 +232,19 @@ RSpec.describe 'getting merge request listings nested in a project' do
include_examples 'N+1 query check'
end
+
+ context 'when requesting `user_notes_count`' do
+ let(:requested_fields) { [:user_notes_count] }
+
+ before do
+ create_list(:note_on_merge_request, 2, noteable: merge_request_a, project: project)
+ create(:note_on_merge_request, noteable: merge_request_c, project: project)
+ end
+
+ include_examples 'N+1 query check'
+ end
end
+
describe 'sorting and pagination' do
let(:data_path) { [:project, :mergeRequests] }
@@ -241,16 +276,50 @@ RSpec.describe 'getting merge request listings nested in a project' do
let(:expected_results) do
[
merge_request_b,
- merge_request_c,
merge_request_d,
+ merge_request_c,
+ merge_request_e,
merge_request_a
].map(&:to_gid).map(&:to_s)
end
before do
- merge_request_c.metrics.update!(merged_at: 5.days.ago)
+ five_days_ago = 5.days.ago
+
+ merge_request_d.metrics.update!(merged_at: five_days_ago)
+
+ # same merged_at, the second order column will decide (merge_request.id)
+ merge_request_c.metrics.update!(merged_at: five_days_ago)
+
merge_request_b.metrics.update!(merged_at: 1.day.ago)
end
+
+ context 'when paginating backwards' do
+ let(:params) { 'first: 2, sort: MERGED_AT_DESC' }
+ let(:page_info) { 'pageInfo { startCursor endCursor }' }
+
+ before do
+ post_graphql(pagination_query(params, page_info), current_user: current_user)
+ end
+
+ it 'paginates backwards correctly' do
+ # first page
+ first_page_response_data = graphql_dig_at(Gitlab::Json.parse(response.body), :data, *data_path, :edges)
+ end_cursor = graphql_dig_at(Gitlab::Json.parse(response.body), :data, :project, :mergeRequests, :pageInfo, :endCursor)
+
+ # second page
+ params = "first: 2, after: \"#{end_cursor}\", sort: MERGED_AT_DESC"
+ post_graphql(pagination_query(params, page_info), current_user: current_user)
+ start_cursor = graphql_dig_at(Gitlab::Json.parse(response.body), :data, :project, :mergeRequests, :pageInfo, :start_cursor)
+
+ # going back to the first page
+
+ params = "last: 2, before: \"#{start_cursor}\", sort: MERGED_AT_DESC"
+ post_graphql(pagination_query(params, page_info), current_user: current_user)
+ backward_paginated_response_data = graphql_dig_at(Gitlab::Json.parse(response.body), :data, *data_path, :edges)
+ expect(first_page_response_data).to eq(backward_paginated_response_data)
+ end
+ end
end
end
end
diff --git a/spec/requests/api/graphql/project/milestones_spec.rb b/spec/requests/api/graphql/project/milestones_spec.rb
new file mode 100644
index 00000000000..2fede4c7285
--- /dev/null
+++ b/spec/requests/api/graphql/project/milestones_spec.rb
@@ -0,0 +1,202 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'getting milestone listings nested in a project' do
+ include GraphqlHelpers
+
+ let_it_be(:today) { Time.now.utc.to_date }
+ let_it_be(:project) { create(:project, :repository, :public) }
+ let_it_be(:current_user) { create(:user) }
+
+ let_it_be(:no_dates) { create(:milestone, project: project, title: 'no dates') }
+ let_it_be(:no_end) { create(:milestone, project: project, title: 'no end', start_date: today - 10.days) }
+ let_it_be(:no_start) { create(:milestone, project: project, title: 'no start', due_date: today - 5.days) }
+ let_it_be(:fully_past) { create(:milestone, project: project, title: 'past', start_date: today - 10.days, due_date: today - 5.days) }
+ let_it_be(:covers_today) { create(:milestone, project: project, title: 'present', start_date: today - 5.days, due_date: today + 5.days) }
+ let_it_be(:fully_future) { create(:milestone, project: project, title: 'future', start_date: today + 5.days, due_date: today + 10.days) }
+ let_it_be(:closed) { create(:milestone, :closed, project: project) }
+
+ let(:results) { graphql_data_at(:project, :milestones, :nodes) }
+
+ let(:search_params) { nil }
+
+ def query_milestones(fields)
+ graphql_query_for(
+ :project,
+ { full_path: project.full_path },
+ query_graphql_field(:milestones, search_params, [
+ query_graphql_field(:nodes, nil, %i[id title])
+ ])
+ )
+ end
+
+ def result_list(expected)
+ expected.map do |milestone|
+ a_hash_including('id' => global_id_of(milestone))
+ end
+ end
+
+ let(:query) do
+ query_milestones(all_graphql_fields_for('Milestone', max_depth: 1))
+ end
+
+ let(:all_milestones) do
+ [no_dates, no_end, no_start, fully_past, fully_future, covers_today, closed]
+ end
+
+ it_behaves_like 'a working graphql query' do
+ before do
+ post_graphql(query, current_user: current_user)
+ end
+ end
+
+ shared_examples 'searching with parameters' do
+ it 'finds the right milestones' do
+ post_graphql(query, current_user: current_user)
+
+ expect(results).to match_array(result_list(expected))
+ end
+ end
+
+ context 'there are no search params' do
+ let(:search_params) { nil }
+ let(:expected) { all_milestones }
+
+ it_behaves_like 'searching with parameters'
+ end
+
+ context 'the search params do not match anything' do
+ let(:search_params) { { title: 'wibble' } }
+ let(:expected) { [] }
+
+ it_behaves_like 'searching with parameters'
+ end
+
+ context 'searching by state:closed' do
+ let(:search_params) { { state: :closed } }
+ let(:expected) { [closed] }
+
+ it_behaves_like 'searching with parameters'
+ end
+
+ context 'searching by state:active' do
+ let(:search_params) { { state: :active } }
+ let(:expected) { all_milestones - [closed] }
+
+ it_behaves_like 'searching with parameters'
+ end
+
+ context 'searching by title' do
+ let(:search_params) { { title: 'no start' } }
+ let(:expected) { [no_start] }
+
+ it_behaves_like 'searching with parameters'
+ end
+
+ context 'searching by search_title' do
+ let(:search_params) { { search_title: 'no' } }
+ let(:expected) { [no_dates, no_start, no_end] }
+
+ it_behaves_like 'searching with parameters'
+ end
+
+ context 'searching by containing_date' do
+ let(:search_params) { { containing_date: (today - 7.days).iso8601 } }
+ let(:expected) { [no_start, no_end, fully_past] }
+
+ it_behaves_like 'searching with parameters'
+ end
+
+ context 'searching by containing_date = today' do
+ let(:search_params) { { containing_date: today.iso8601 } }
+ let(:expected) { [no_end, covers_today] }
+
+ it_behaves_like 'searching with parameters'
+ end
+
+ context 'searching by custom range' do
+ let(:expected) { [no_end, fully_future] }
+ let(:search_params) do
+ {
+ start_date: (today + 6.days).iso8601,
+ end_date: (today + 7.days).iso8601
+ }
+ end
+
+ it_behaves_like 'searching with parameters'
+ end
+
+ context 'using timeframe argument' do
+ let(:expected) { [no_end, fully_future] }
+ let(:search_params) do
+ {
+ timeframe: {
+ start: (today + 6.days).iso8601,
+ end: (today + 7.days).iso8601
+ }
+ }
+ end
+
+ it_behaves_like 'searching with parameters'
+ end
+
+ describe 'timeframe validations' do
+ let(:vars) do
+ {
+ path: project.full_path,
+ start: (today + 6.days).iso8601,
+ end: (today + 7.days).iso8601
+ }
+ end
+
+ it_behaves_like 'a working graphql query' do
+ before do
+ query = <<~GQL
+ query($path: ID!, $start: Date!, $end: Date!) {
+ project(fullPath: $path) {
+ milestones(timeframe: { start: $start, end: $end }) {
+ nodes { id }
+ }
+ }
+ }
+ GQL
+
+ post_graphql(query, current_user: current_user, variables: vars)
+ end
+ end
+
+ it 'is invalid to provide timeframe and start_date/end_date' do
+ query = <<~GQL
+ query($path: ID!, $tstart: Date!, $tend: Date!, $start: Time!, $end: Time!) {
+ project(fullPath: $path) {
+ milestones(timeframe: { start: $tstart, end: $tend }, startDate: $start, endDate: $end) {
+ nodes { id }
+ }
+ }
+ }
+ GQL
+
+ post_graphql(query, current_user: current_user,
+ variables: vars.merge(vars.transform_keys { |k| :"t#{k}" }))
+
+ expect(graphql_errors).to contain_exactly(a_hash_including('message' => include('deprecated in favor of timeframe')))
+ end
+
+ it 'is invalid to invert the timeframe arguments' do
+ query = <<~GQL
+ query($path: ID!, $start: Date!, $end: Date!) {
+ project(fullPath: $path) {
+ milestones(timeframe: { start: $end, end: $start }) {
+ nodes { id }
+ }
+ }
+ }
+ GQL
+
+ post_graphql(query, current_user: current_user, variables: vars)
+
+ expect(graphql_errors).to contain_exactly(a_hash_including('message' => include('start must be before end')))
+ end
+ end
+end
diff --git a/spec/requests/api/graphql/user_query_spec.rb b/spec/requests/api/graphql/user_query_spec.rb
index 2f4dc0a9160..79debd0b7ef 100644
--- a/spec/requests/api/graphql/user_query_spec.rb
+++ b/spec/requests/api/graphql/user_query_spec.rb
@@ -29,15 +29,15 @@ RSpec.describe 'getting user information' do
let_it_be(:unauthorized_user) { create(:user) }
let_it_be(:assigned_mr) do
- create(:merge_request, :unique_branches,
+ create(:merge_request, :unique_branches, :unique_author,
source_project: project_a, assignees: [user])
end
let_it_be(:assigned_mr_b) do
- create(:merge_request, :unique_branches,
+ create(:merge_request, :unique_branches, :unique_author,
source_project: project_b, assignees: [user])
end
let_it_be(:assigned_mr_c) do
- create(:merge_request, :unique_branches,
+ create(:merge_request, :unique_branches, :unique_author,
source_project: project_b, assignees: [user])
end
let_it_be(:authored_mr) do
@@ -133,6 +133,17 @@ RSpec.describe 'getting user information' do
)
end
end
+
+ context 'filtering by author' do
+ let(:author) { assigned_mr_b.author }
+ let(:mr_args) { { author_username: author.username } }
+
+ it 'finds the authored mrs' do
+ expect(assigned_mrs).to contain_exactly(
+ a_hash_including('id' => global_id_of(assigned_mr_b))
+ )
+ end
+ end
end
context 'the current user does not have access' do
@@ -172,6 +183,23 @@ RSpec.describe 'getting user information' do
end
end
+ context 'filtering by assignee' do
+ let(:assignee) { create(:user) }
+ let(:mr_args) { { assignee_username: assignee.username } }
+
+ it 'finds the assigned mrs' do
+ authored_mr.assignees << assignee
+ authored_mr_c.assignees << assignee
+
+ post_graphql(query, current_user: current_user)
+
+ expect(authored_mrs).to contain_exactly(
+ a_hash_including('id' => global_id_of(authored_mr)),
+ a_hash_including('id' => global_id_of(authored_mr_c))
+ )
+ end
+ end
+
context 'filtering by project path and IID' do
let(:mr_args) do
{ project_path: project_b.full_path, iids: [authored_mr_b.iid.to_s] }
@@ -253,8 +281,10 @@ RSpec.describe 'getting user information' do
let(:current_user) { user }
it 'can be found' do
- expect(assigned_mrs).to include(
- a_hash_including('id' => global_id_of(assigned_mr))
+ expect(assigned_mrs).to contain_exactly(
+ a_hash_including('id' => global_id_of(assigned_mr)),
+ a_hash_including('id' => global_id_of(assigned_mr_b)),
+ a_hash_including('id' => global_id_of(assigned_mr_c))
)
end
end
diff --git a/spec/requests/api/graphql_spec.rb b/spec/requests/api/graphql_spec.rb
index ff1a5aa1540..94a66f54e4d 100644
--- a/spec/requests/api/graphql_spec.rb
+++ b/spec/requests/api/graphql_spec.rb
@@ -9,7 +9,15 @@ RSpec.describe 'GraphQL' do
context 'logging' do
shared_examples 'logging a graphql query' do
let(:expected_params) do
- { query_string: query, variables: variables.to_s, duration_s: anything, depth: 1, complexity: 1 }
+ {
+ query_string: query,
+ variables: variables.to_s,
+ duration_s: anything,
+ depth: 1,
+ complexity: 1,
+ used_fields: ['Query.echo'],
+ used_deprecated_fields: []
+ }
end
it 'logs a query with the expected params' do
diff --git a/spec/requests/api/group_clusters_spec.rb b/spec/requests/api/group_clusters_spec.rb
index 068af1485e2..eb21ae9468c 100644
--- a/spec/requests/api/group_clusters_spec.rb
+++ b/spec/requests/api/group_clusters_spec.rb
@@ -172,6 +172,7 @@ RSpec.describe API::GroupClusters do
name: 'test-cluster',
domain: 'domain.example.com',
managed: false,
+ namespace_per_environment: false,
platform_kubernetes_attributes: platform_kubernetes_attributes,
management_project_id: management_project_id
}
@@ -206,6 +207,7 @@ RSpec.describe API::GroupClusters do
expect(cluster_result.domain).to eq('domain.example.com')
expect(cluster_result.managed).to be_falsy
expect(cluster_result.management_project_id).to eq management_project_id
+ expect(cluster_result.namespace_per_environment).to eq(false)
expect(platform_kubernetes.rbac?).to be_truthy
expect(platform_kubernetes.api_url).to eq(api_url)
expect(platform_kubernetes.token).to eq('sample-token')
@@ -237,6 +239,22 @@ RSpec.describe API::GroupClusters do
end
end
+ context 'when namespace_per_environment is not set' do
+ let(:cluster_params) do
+ {
+ name: 'test-cluster',
+ domain: 'domain.example.com',
+ platform_kubernetes_attributes: platform_kubernetes_attributes
+ }
+ end
+
+ it 'defaults to true' do
+ cluster_result = Clusters::Cluster.find(json_response['id'])
+
+ expect(cluster_result).to be_namespace_per_environment
+ end
+ end
+
context 'current user does not have access to management_project_id' do
let(:management_project_id) { create(:project).id }
diff --git a/spec/requests/api/group_container_repositories_spec.rb b/spec/requests/api/group_container_repositories_spec.rb
index 3128becae6d..4584ef37bd0 100644
--- a/spec/requests/api/group_container_repositories_spec.rb
+++ b/spec/requests/api/group_container_repositories_spec.rb
@@ -25,7 +25,6 @@ RSpec.describe API::GroupContainerRepositories do
group.add_reporter(reporter)
group.add_guest(guest)
- stub_feature_flags(container_registry_api: true)
stub_container_registry_config(enabled: true)
root_repository
@@ -44,7 +43,7 @@ RSpec.describe API::GroupContainerRepositories do
let(:object) { group }
end
- it_behaves_like 'a gitlab tracking event', described_class.name, 'list_repositories'
+ it_behaves_like 'a package tracking event', described_class.name, 'list_repositories'
context 'with invalid group id' do
let(:url) { "/groups/#{non_existing_record_id}/registry/repositories" }
diff --git a/spec/requests/api/group_packages_spec.rb b/spec/requests/api/group_packages_spec.rb
index f67cafbd8f5..72ba25c59af 100644
--- a/spec/requests/api/group_packages_spec.rb
+++ b/spec/requests/api/group_packages_spec.rb
@@ -77,7 +77,7 @@ RSpec.describe API::GroupPackages do
it_behaves_like 'returns packages', :group, :owner
it_behaves_like 'returns packages', :group, :maintainer
it_behaves_like 'returns packages', :group, :developer
- it_behaves_like 'rejects packages access', :group, :reporter, :forbidden
+ it_behaves_like 'returns packages', :group, :reporter
it_behaves_like 'rejects packages access', :group, :guest, :forbidden
context 'with subgroup' do
@@ -88,7 +88,7 @@ RSpec.describe API::GroupPackages do
it_behaves_like 'returns packages with subgroups', :group, :owner
it_behaves_like 'returns packages with subgroups', :group, :maintainer
it_behaves_like 'returns packages with subgroups', :group, :developer
- it_behaves_like 'rejects packages access', :group, :reporter, :forbidden
+ it_behaves_like 'returns packages with subgroups', :group, :reporter
it_behaves_like 'rejects packages access', :group, :guest, :forbidden
context 'excluding subgroup' do
@@ -97,7 +97,7 @@ RSpec.describe API::GroupPackages do
it_behaves_like 'returns packages', :group, :owner
it_behaves_like 'returns packages', :group, :maintainer
it_behaves_like 'returns packages', :group, :developer
- it_behaves_like 'rejects packages access', :group, :reporter, :forbidden
+ it_behaves_like 'returns packages', :group, :reporter
it_behaves_like 'rejects packages access', :group, :guest, :forbidden
end
end
diff --git a/spec/requests/api/groups_spec.rb b/spec/requests/api/groups_spec.rb
index da423e986c3..c7756a4fae5 100644
--- a/spec/requests/api/groups_spec.rb
+++ b/spec/requests/api/groups_spec.rb
@@ -1391,6 +1391,139 @@ RSpec.describe API::Groups do
end
end
+ describe 'GET /groups/:id/descendant_groups' do
+ let_it_be(:child_group1) { create(:group, parent: group1) }
+ let_it_be(:private_child_group1) { create(:group, :private, parent: group1) }
+ let_it_be(:sub_child_group1) { create(:group, parent: child_group1) }
+ let_it_be(:child_group2) { create(:group, :private, parent: group2) }
+ let_it_be(:sub_child_group2) { create(:group, :private, parent: child_group2) }
+ let(:response_groups) { json_response.map { |group| group['name'] } }
+
+ context 'when unauthenticated' do
+ it 'returns only public descendants' do
+ get api("/groups/#{group1.id}/descendant_groups")
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to include_pagination_headers
+ expect(json_response).to be_an Array
+ expect(json_response.length).to eq(2)
+ expect(response_groups).to contain_exactly(child_group1.name, sub_child_group1.name)
+ end
+
+ it 'returns 404 for a private group' do
+ get api("/groups/#{group2.id}/descendant_groups")
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+
+ context 'when authenticated as user' do
+ context 'when user is not member of a public group' do
+ it 'returns no descendants for the public group' do
+ get api("/groups/#{group1.id}/descendant_groups", user2)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response).to be_an Array
+ expect(json_response.length).to eq(0)
+ end
+
+ context 'when using all_available in request' do
+ it 'returns public descendants' do
+ get api("/groups/#{group1.id}/descendant_groups", user2), params: { all_available: true }
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response).to be_an Array
+ expect(json_response.length).to eq(2)
+ expect(response_groups).to contain_exactly(child_group1.name, sub_child_group1.name)
+ end
+ end
+ end
+
+ context 'when user is not member of a private group' do
+ it 'returns 404 for the private group' do
+ get api("/groups/#{group2.id}/descendant_groups", user1)
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+
+ context 'when user is member of public group' do
+ before do
+ group1.add_guest(user2)
+ end
+
+ it 'returns private descendants' do
+ get api("/groups/#{group1.id}/descendant_groups", user2)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to include_pagination_headers
+ expect(json_response).to be_an Array
+ expect(json_response.length).to eq(3)
+ expect(response_groups).to contain_exactly(child_group1.name, sub_child_group1.name, private_child_group1.name)
+ end
+
+ context 'when using statistics in request' do
+ it 'does not include statistics' do
+ get api("/groups/#{group1.id}/descendant_groups", user2), params: { statistics: true }
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response).to be_an Array
+ expect(json_response.first).not_to include 'statistics'
+ end
+ end
+ end
+
+ context 'when user is member of private group' do
+ before do
+ group2.add_guest(user1)
+ end
+
+ it 'returns descendants' do
+ get api("/groups/#{group2.id}/descendant_groups", user1)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response).to be_an Array
+ expect(json_response.length).to eq(2)
+ expect(response_groups).to contain_exactly(child_group2.name, sub_child_group2.name)
+ end
+ end
+ end
+
+ context 'when authenticated as admin' do
+ it 'returns private descendants of a public group' do
+ get api("/groups/#{group1.id}/descendant_groups", admin)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response).to be_an Array
+ expect(json_response.length).to eq(3)
+ end
+
+ it 'returns descendants of a private group' do
+ get api("/groups/#{group2.id}/descendant_groups", admin)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response).to be_an Array
+ expect(json_response.length).to eq(2)
+ end
+
+ it 'does not include statistics by default' do
+ get api("/groups/#{group1.id}/descendant_groups", admin)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response).to be_an Array
+ expect(json_response.first).not_to include('statistics')
+ end
+
+ it 'includes statistics if requested' do
+ get api("/groups/#{group1.id}/descendant_groups", admin), params: { statistics: true }
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response).to be_an Array
+ expect(json_response.first).to include('statistics')
+ end
+ end
+ end
+
describe "POST /groups" do
it_behaves_like 'group avatar upload' do
def make_upload_request
diff --git a/spec/requests/api/helpers_spec.rb b/spec/requests/api/helpers_spec.rb
index 9c0ea14e3e3..91d10791541 100644
--- a/spec/requests/api/helpers_spec.rb
+++ b/spec/requests/api/helpers_spec.rb
@@ -9,7 +9,7 @@ RSpec.describe API::Helpers do
include described_class
include TermsHelper
- let(:user) { create(:user) }
+ let_it_be(:user, reload: true) { create(:user) }
let(:admin) { create(:admin) }
let(:key) { create(:key, user: user) }
@@ -243,6 +243,67 @@ RSpec.describe API::Helpers do
end
end
end
+
+ describe "when authenticating using a job token" do
+ let_it_be(:job, reload: true) do
+ create(:ci_build, user: user, status: :running)
+ end
+
+ let(:route_authentication_setting) { {} }
+
+ before do
+ allow_any_instance_of(self.class).to receive(:route_authentication_setting)
+ .and_return(route_authentication_setting)
+ end
+
+ context 'when route is allowed to be authenticated' do
+ let(:route_authentication_setting) { { job_token_allowed: true } }
+
+ it "returns a 401 response for an invalid token" do
+ env[Gitlab::Auth::AuthFinders::JOB_TOKEN_HEADER] = 'invalid token'
+
+ expect { current_user }.to raise_error /401/
+ end
+
+ it "returns a 401 response for a job that's not running" do
+ job.update!(status: :success)
+ env[Gitlab::Auth::AuthFinders::JOB_TOKEN_HEADER] = job.token
+
+ expect { current_user }.to raise_error /401/
+ end
+
+ it "returns a 403 response for a user without access" do
+ env[Gitlab::Auth::AuthFinders::JOB_TOKEN_HEADER] = job.token
+ allow_any_instance_of(Gitlab::UserAccess).to receive(:allowed?).and_return(false)
+
+ expect { current_user }.to raise_error /403/
+ end
+
+ it 'returns a 403 response for a user who is blocked' do
+ user.block!
+ env[Gitlab::Auth::AuthFinders::JOB_TOKEN_HEADER] = job.token
+
+ expect { current_user }.to raise_error /403/
+ end
+
+ it "sets current_user" do
+ env[Gitlab::Auth::AuthFinders::JOB_TOKEN_HEADER] = job.token
+
+ expect(current_user).to eq(user)
+ end
+ end
+
+ context 'when route is not allowed to be authenticated' do
+ let(:route_authentication_setting) { { job_token_allowed: false } }
+
+ it "sets current_user to nil" do
+ env[Gitlab::Auth::AuthFinders::JOB_TOKEN_HEADER] = job.token
+ allow_any_instance_of(Gitlab::UserAccess).to receive(:allowed?).and_return(true)
+
+ expect(current_user).to be_nil
+ end
+ end
+ end
end
describe '.handle_api_exception' do
diff --git a/spec/requests/api/internal/base_spec.rb b/spec/requests/api/internal/base_spec.rb
index 4a0a7c81781..ab5f09305ce 100644
--- a/spec/requests/api/internal/base_spec.rb
+++ b/spec/requests/api/internal/base_spec.rb
@@ -3,6 +3,8 @@
require 'spec_helper'
RSpec.describe API::Internal::Base do
+ include APIInternalBaseHelpers
+
let_it_be(:user, reload: true) { create(:user) }
let_it_be(:project, reload: true) { create(:project, :repository, :wiki_repo) }
let_it_be(:personal_snippet) { create(:personal_snippet, :repository, author: user) }
@@ -48,43 +50,63 @@ RSpec.describe API::Internal::Base do
end
end
- describe 'GET /internal/two_factor_recovery_codes' do
- it 'returns an error message when the key does not exist' do
- post api('/internal/two_factor_recovery_codes'),
- params: {
- secret_token: secret_token,
- key_id: non_existing_record_id
- }
+ shared_examples 'actor key validations' do
+ context 'key id is not provided' do
+ let(:key_id) { nil }
- expect(json_response['success']).to be_falsey
- expect(json_response['message']).to eq('Could not find the given key')
+ it 'returns an error message' do
+ subject
+
+ expect(json_response['success']).to be_falsey
+ expect(json_response['message']).to eq('Could not find a user without a key')
+ end
end
- it 'returns an error message when the key is a deploy key' do
- deploy_key = create(:deploy_key)
+ context 'key does not exist' do
+ let(:key_id) { non_existing_record_id }
- post api('/internal/two_factor_recovery_codes'),
- params: {
- secret_token: secret_token,
- key_id: deploy_key.id
- }
+ it 'returns an error message' do
+ subject
- expect(json_response['success']).to be_falsey
- expect(json_response['message']).to eq('Deploy keys cannot be used to retrieve recovery codes')
+ expect(json_response['success']).to be_falsey
+ expect(json_response['message']).to eq('Could not find the given key')
+ end
+ end
+
+ context 'key without user' do
+ let(:key_id) { create(:key, user: nil).id }
+
+ it 'returns an error message' do
+ subject
+
+ expect(json_response['success']).to be_falsey
+ expect(json_response['message']).to eq('Could not find a user for the given key')
+ end
end
+ end
- it 'returns an error message when the user does not exist' do
- key_without_user = create(:key, user: nil)
+ describe 'GET /internal/two_factor_recovery_codes' do
+ let(:key_id) { key.id }
+ subject do
post api('/internal/two_factor_recovery_codes'),
params: {
secret_token: secret_token,
- key_id: key_without_user.id
+ key_id: key_id
}
+ end
- expect(json_response['success']).to be_falsey
- expect(json_response['message']).to eq('Could not find a user for the given key')
- expect(json_response['recovery_codes']).to be_nil
+ it_behaves_like 'actor key validations'
+
+ context 'key is a deploy key' do
+ let(:key_id) { create(:deploy_key).id }
+
+ it 'returns an error message' do
+ subject
+
+ expect(json_response['success']).to be_falsey
+ expect(json_response['message']).to eq('Deploy keys cannot be used to retrieve recovery codes')
+ end
end
context 'when two-factor is enabled' do
@@ -93,11 +115,7 @@ RSpec.describe API::Internal::Base do
allow_any_instance_of(User)
.to receive(:generate_otp_backup_codes!).and_return(%w(119135e5a3ebce8e 34bd7b74adbc8861))
- post api('/internal/two_factor_recovery_codes'),
- params: {
- secret_token: secret_token,
- key_id: key.id
- }
+ subject
expect(json_response['success']).to be_truthy
expect(json_response['recovery_codes']).to match_array(%w(119135e5a3ebce8e 34bd7b74adbc8861))
@@ -108,11 +126,7 @@ RSpec.describe API::Internal::Base do
it 'returns an error message' do
allow_any_instance_of(User).to receive(:two_factor_enabled?).and_return(false)
- post api('/internal/two_factor_recovery_codes'),
- params: {
- secret_token: secret_token,
- key_id: key.id
- }
+ subject
expect(json_response['success']).to be_falsey
expect(json_response['recovery_codes']).to be_nil
@@ -121,42 +135,27 @@ RSpec.describe API::Internal::Base do
end
describe 'POST /internal/personal_access_token' do
- it 'returns an error message when the key does not exist' do
- post api('/internal/personal_access_token'),
- params: {
- secret_token: secret_token,
- key_id: non_existing_record_id
- }
-
- expect(json_response['success']).to be_falsey
- expect(json_response['message']).to eq('Could not find the given key')
- end
-
- it 'returns an error message when the key is a deploy key' do
- deploy_key = create(:deploy_key)
+ let(:key_id) { key.id }
+ subject do
post api('/internal/personal_access_token'),
params: {
secret_token: secret_token,
- key_id: deploy_key.id
+ key_id: key_id
}
-
- expect(json_response['success']).to be_falsey
- expect(json_response['message']).to eq('Deploy keys cannot be used to create personal access tokens')
end
- it 'returns an error message when the user does not exist' do
- key_without_user = create(:key, user: nil)
+ it_behaves_like 'actor key validations'
- post api('/internal/personal_access_token'),
- params: {
- secret_token: secret_token,
- key_id: key_without_user.id
- }
+ context 'key is a deploy key' do
+ let(:key_id) { create(:deploy_key).id }
- expect(json_response['success']).to be_falsey
- expect(json_response['message']).to eq('Could not find a user for the given key')
- expect(json_response['token']).to be_nil
+ it 'returns an error message' do
+ subject
+
+ expect(json_response['success']).to be_falsey
+ expect(json_response['message']).to eq('Deploy keys cannot be used to create personal access tokens')
+ end
end
it 'returns an error message when given an non existent user' do
@@ -459,7 +458,7 @@ RSpec.describe API::Internal::Base do
end
it_behaves_like 'sets hook env' do
- let(:gl_repository) { Gitlab::GlRepository::WIKI.identifier_for_container(project) }
+ let(:gl_repository) { Gitlab::GlRepository::WIKI.identifier_for_container(project.wiki) }
end
end
@@ -1207,86 +1206,157 @@ RSpec.describe API::Internal::Base do
end
end
- def gl_repository_for(container)
- case container
- when ProjectWiki
- Gitlab::GlRepository::WIKI.identifier_for_container(container.project)
- when Project
- Gitlab::GlRepository::PROJECT.identifier_for_container(container)
- when Snippet
- Gitlab::GlRepository::SNIPPET.identifier_for_container(container)
- else
- nil
+ describe 'POST /internal/two_factor_config' do
+ let(:key_id) { key.id }
+
+ before do
+ stub_feature_flags(two_factor_for_cli: true)
end
- end
- def full_path_for(container)
- case container
- when PersonalSnippet
- "snippets/#{container.id}"
- when ProjectSnippet
- "#{container.project.full_path}/snippets/#{container.id}"
- else
- container.full_path
+ subject do
+ post api('/internal/two_factor_config'),
+ params: {
+ secret_token: secret_token,
+ key_id: key_id
+ }
end
- end
- def pull(key, container, protocol = 'ssh')
- post(
- api("/internal/allowed"),
- params: {
- key_id: key.id,
- project: full_path_for(container),
- gl_repository: gl_repository_for(container),
- action: 'git-upload-pack',
- secret_token: secret_token,
- protocol: protocol
- }
- )
- end
+ it_behaves_like 'actor key validations'
- def push(key, container, protocol = 'ssh', env: nil, changes: nil)
- push_with_path(key,
- full_path: full_path_for(container),
- gl_repository: gl_repository_for(container),
- protocol: protocol,
- env: env,
- changes: changes)
- end
+ context 'when the key is a deploy key' do
+ let(:key) { create(:deploy_key) }
- def push_with_path(key, full_path:, gl_repository: nil, protocol: 'ssh', env: nil, changes: nil)
- changes ||= 'd14d6c0abdd253381df51a723d58691b2ee1ab08 570e7b2abdd848b95f2f578043fc23bd6f6fd24d refs/heads/master'
+ it 'does not required two factor' do
+ subject
- params = {
- changes: changes,
- key_id: key.id,
- project: full_path,
- action: 'git-receive-pack',
- secret_token: secret_token,
- protocol: protocol,
- env: env
- }
- params[:gl_repository] = gl_repository if gl_repository
+ expect(json_response['success']).to be_truthy
+ expect(json_response['two_factor_required']).to be_falsey
+ end
+ end
- post(
- api("/internal/allowed"),
- params: params
- )
+ context 'when two-factor is enabled' do
+ it 'returns user two factor config' do
+ allow_any_instance_of(User).to receive(:two_factor_enabled?).and_return(true)
+
+ subject
+
+ expect(json_response['success']).to be_truthy
+ expect(json_response['two_factor_required']).to be_truthy
+ end
+ end
+
+ context 'when two-factor is not enabled' do
+ it 'returns an error message' do
+ allow_any_instance_of(User).to receive(:two_factor_enabled?).and_return(false)
+
+ subject
+
+ expect(json_response['success']).to be_truthy
+ expect(json_response['two_factor_required']).to be_falsey
+ end
+ end
+
+ context 'two_factor_for_cli feature is disabled' do
+ before do
+ stub_feature_flags(two_factor_for_cli: false)
+ end
+
+ context 'when two-factor is enabled for the user' do
+ it 'returns user two factor config' do
+ allow_any_instance_of(User).to receive(:two_factor_enabled?).and_return(true)
+
+ subject
+
+ expect(json_response['success']).to be_falsey
+ end
+ end
+ end
end
- def archive(key, container)
- post(
- api("/internal/allowed"),
- params: {
- ref: 'master',
- key_id: key.id,
- project: full_path_for(container),
- gl_repository: gl_repository_for(container),
- action: 'git-upload-archive',
- secret_token: secret_token,
- protocol: 'ssh'
- }
- )
+ describe 'POST /internal/two_factor_otp_check' do
+ let(:key_id) { key.id }
+ let(:otp) { '123456'}
+
+ before do
+ stub_feature_flags(two_factor_for_cli: true)
+ end
+
+ subject do
+ post api('/internal/two_factor_otp_check'),
+ params: {
+ secret_token: secret_token,
+ key_id: key_id,
+ otp_attempt: otp
+ }
+ end
+
+ it_behaves_like 'actor key validations'
+
+ context 'when the key is a deploy key' do
+ let(:key_id) { create(:deploy_key).id }
+
+ it 'returns an error message' do
+ subject
+
+ expect(json_response['success']).to be_falsey
+ expect(json_response['message']).to eq('Deploy keys cannot be used for Two Factor')
+ end
+ end
+
+ context 'when the two factor is enabled' do
+ before do
+ allow_any_instance_of(User).to receive(:two_factor_enabled?).and_return(true)
+ end
+
+ context 'when the OTP is valid' do
+ it 'returns success' do
+ allow_any_instance_of(Users::ValidateOtpService).to receive(:execute).with(otp).and_return(status: :success)
+
+ subject
+
+ expect(json_response['success']).to be_truthy
+ end
+ end
+
+ context 'when the OTP is invalid' do
+ it 'is not success' do
+ allow_any_instance_of(Users::ValidateOtpService).to receive(:execute).with(otp).and_return(status: :error)
+
+ subject
+
+ expect(json_response['success']).to be_falsey
+ end
+ end
+ end
+
+ context 'when the two factor is disabled' do
+ before do
+ allow_any_instance_of(User).to receive(:two_factor_enabled?).and_return(false)
+ end
+
+ it 'returns an error message' do
+ subject
+
+ expect(json_response['success']).to be_falsey
+ expect(json_response['message']).to eq 'Two-factor authentication is not enabled for this user'
+ end
+ end
+
+ context 'two_factor_for_cli feature is disabled' do
+ before do
+ stub_feature_flags(two_factor_for_cli: false)
+ end
+
+ context 'when two-factor is enabled for the user' do
+ it 'returns user two factor config' do
+ allow_any_instance_of(User).to receive(:two_factor_enabled?).and_return(true)
+
+ subject
+
+ expect(json_response['success']).to be_falsey
+ end
+ end
+ end
end
def lfs_auth_project(project)
diff --git a/spec/requests/api/internal/lfs_spec.rb b/spec/requests/api/internal/lfs_spec.rb
new file mode 100644
index 00000000000..4739ec62992
--- /dev/null
+++ b/spec/requests/api/internal/lfs_spec.rb
@@ -0,0 +1,93 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe API::Internal::Lfs do
+ include APIInternalBaseHelpers
+
+ let_it_be(:project) { create(:project) }
+ let_it_be(:lfs_object) { create(:lfs_object, :with_file) }
+ let_it_be(:lfs_objects_project) { create(:lfs_objects_project, project: project, lfs_object: lfs_object) }
+ let_it_be(:gl_repository) { "project-#{project.id}" }
+ let_it_be(:filename) { lfs_object.file.path }
+
+ let(:secret_token) { Gitlab::Shell.secret_token }
+
+ describe 'GET /internal/lfs' do
+ let(:valid_params) do
+ { oid: lfs_object.oid, gl_repository: gl_repository, secret_token: secret_token }
+ end
+
+ context 'with invalid auth' do
+ let(:invalid_params) { valid_params.merge!(secret_token: 'invalid_tokne') }
+
+ it 'returns 401' do
+ get api("/internal/lfs"), params: invalid_params
+ end
+ end
+
+ context 'with valid auth' do
+ context 'LFS in local storage' do
+ it 'sends the file' do
+ get api("/internal/lfs"), params: valid_params
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response.headers['Content-Type']).to eq('application/octet-stream')
+ expect(response.headers['Content-Length'].to_i).to eq(File.stat(filename).size)
+ expect(response.body).to eq(File.open(filename, 'rb', &:read))
+ end
+
+ # https://www.rubydoc.info/github/rack/rack/master/Rack/Sendfile
+ it 'delegates sending to Web server' do
+ get api("/internal/lfs"), params: valid_params, env: { 'HTTP_X_SENDFILE_TYPE' => 'X-Sendfile' }
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response.headers['Content-Type']).to eq('application/octet-stream')
+ expect(response.headers['Content-Length'].to_i).to eq(0)
+ expect(response.headers['X-Sendfile']).to be_present
+ expect(response.body).to eq("")
+ end
+
+ it 'retuns 404 for unknown file' do
+ params = valid_params.merge(oid: SecureRandom.hex)
+
+ get api("/internal/lfs"), params: params
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+
+ it 'returns 404 if LFS object does not belong to project' do
+ other_lfs = create(:lfs_object, :with_file)
+ params = valid_params.merge(oid: other_lfs.oid)
+
+ get api("/internal/lfs"), params: params
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+
+ context 'LFS in object storage' do
+ let!(:lfs_object2) { create(:lfs_object, :with_file) }
+ let!(:lfs_objects_project2) { create(:lfs_objects_project, project: project, lfs_object: lfs_object2) }
+ let(:valid_params) do
+ { oid: lfs_object2.oid, gl_repository: gl_repository, secret_token: secret_token }
+ end
+
+ before do
+ stub_lfs_object_storage(enabled: true)
+ lfs_object2.file.migrate!(LfsObjectUploader::Store::REMOTE)
+ end
+
+ it 'notifies Workhorse to send the file' do
+ get api("/internal/lfs"), params: valid_params
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response.headers[Gitlab::Workhorse::SEND_DATA_HEADER]).to start_with("send-url:")
+ expect(response.headers['Content-Type']).to eq('application/octet-stream')
+ expect(response.headers['Content-Length'].to_i).to eq(0)
+ expect(response.body).to eq("")
+ end
+ end
+ end
+ end
+end
diff --git a/spec/requests/api/jobs_spec.rb b/spec/requests/api/jobs_spec.rb
index 2d57146fbc9..c1498e03f76 100644
--- a/spec/requests/api/jobs_spec.rb
+++ b/spec/requests/api/jobs_spec.rb
@@ -465,12 +465,14 @@ RSpec.describe API::Jobs do
end
context 'find proper job' do
+ let(:job_with_artifacts) { job }
+
shared_examples 'a valid file' do
context 'when artifacts are stored locally', :sidekiq_might_not_need_inline do
let(:download_headers) do
{ 'Content-Transfer-Encoding' => 'binary',
'Content-Disposition' =>
- %Q(attachment; filename="#{job.artifacts_file.filename}"; filename*=UTF-8''#{job.artifacts_file.filename}) }
+ %Q(attachment; filename="#{job_with_artifacts.artifacts_file.filename}"; filename*=UTF-8''#{job.artifacts_file.filename}) }
end
it { expect(response).to have_gitlab_http_status(:ok) }
@@ -518,6 +520,18 @@ RSpec.describe API::Jobs do
it_behaves_like 'a valid file'
end
+
+ context 'with job name in a child pipeline' do
+ let(:child_pipeline) { create(:ci_pipeline, child_of: pipeline) }
+ let!(:child_job) { create(:ci_build, :artifacts, :success, name: 'rspec', pipeline: child_pipeline) }
+ let(:job_with_artifacts) { child_job }
+
+ before do
+ get_for_ref('master', child_job.name)
+ end
+
+ it_behaves_like 'a valid file'
+ end
end
end
diff --git a/spec/requests/api/lint_spec.rb b/spec/requests/api/lint_spec.rb
index 4c60c8bd2a3..9890cdc20c0 100644
--- a/spec/requests/api/lint_spec.rb
+++ b/spec/requests/api/lint_spec.rb
@@ -17,23 +17,52 @@ RSpec.describe API::Lint do
expect(json_response['status']).to eq('valid')
expect(json_response['errors']).to eq([])
end
+
+ it 'outputs expanded yaml content' do
+ post api('/ci/lint'), params: { content: yaml_content, include_merged_yaml: true }
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response).to have_key('merged_yaml')
+ end
end
context 'with an invalid .gitlab_ci.yml' do
- it 'responds with errors about invalid syntax' do
- post api('/ci/lint'), params: { content: 'invalid content' }
+ context 'with invalid syntax' do
+ let(:yaml_content) { 'invalid content' }
- expect(response).to have_gitlab_http_status(:ok)
- expect(json_response['status']).to eq('invalid')
- expect(json_response['errors']).to eq(['Invalid configuration format'])
+ it 'responds with errors about invalid syntax' do
+ post api('/ci/lint'), params: { content: yaml_content }
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['status']).to eq('invalid')
+ expect(json_response['errors']).to eq(['Invalid configuration format'])
+ end
+
+ it 'outputs expanded yaml content' do
+ post api('/ci/lint'), params: { content: yaml_content, include_merged_yaml: true }
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response).to have_key('merged_yaml')
+ end
end
- it "responds with errors about invalid configuration" do
- post api('/ci/lint'), params: { content: '{ image: "ruby:2.7", services: ["postgres"] }' }
+ context 'with invalid configuration' do
+ let(:yaml_content) { '{ image: "ruby:2.7", services: ["postgres"] }' }
- expect(response).to have_gitlab_http_status(:ok)
- expect(json_response['status']).to eq('invalid')
- expect(json_response['errors']).to eq(['jobs config should contain at least one visible job'])
+ it 'responds with errors about invalid configuration' do
+ post api('/ci/lint'), params: { content: yaml_content }
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['status']).to eq('invalid')
+ expect(json_response['errors']).to eq(['jobs config should contain at least one visible job'])
+ end
+
+ it 'outputs expanded yaml content' do
+ post api('/ci/lint'), params: { content: yaml_content, include_merged_yaml: true }
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response).to have_key('merged_yaml')
+ end
end
end
@@ -46,4 +75,204 @@ RSpec.describe API::Lint do
end
end
end
+
+ describe 'GET /projects/:id/ci/lint' do
+ subject(:ci_lint) { get api("/projects/#{project.id}/ci/lint", api_user), params: { dry_run: dry_run } }
+
+ let(:project) { create(:project, :repository) }
+ let(:dry_run) { nil }
+
+ RSpec.shared_examples 'valid config' do
+ it 'passes validation' do
+ ci_lint
+
+ included_config = YAML.safe_load(included_content, [Symbol])
+ root_config = YAML.safe_load(yaml_content, [Symbol])
+ expected_yaml = included_config.merge(root_config).except(:include).to_yaml
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response).to be_an Hash
+ expect(json_response['merged_yaml']).to eq(expected_yaml)
+ expect(json_response['valid']).to eq(true)
+ expect(json_response['errors']).to eq([])
+ end
+ end
+
+ RSpec.shared_examples 'invalid config' do
+ it 'responds with errors about invalid configuration' do
+ ci_lint
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['merged_yaml']).to eq(yaml_content)
+ expect(json_response['valid']).to eq(false)
+ expect(json_response['errors']).to eq(['jobs config should contain at least one visible job'])
+ end
+ end
+
+ context 'when unauthenticated' do
+ let_it_be(:api_user) { nil }
+
+ it 'returns authentication error' do
+ ci_lint
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+
+ context 'when authenticated as non-member' do
+ let_it_be(:api_user) { create(:user) }
+
+ let(:yaml_content) do
+ { include: { local: 'another-gitlab-ci.yml' }, test: { stage: 'test', script: 'echo 1' } }.to_yaml
+ end
+
+ context 'when project is private' do
+ before do
+ project.update!(visibility_level: Gitlab::VisibilityLevel::PRIVATE)
+ stub_ci_pipeline_yaml_file(yaml_content)
+ end
+
+ it 'returns authentication error' do
+ ci_lint
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+
+ context 'when project is public' do
+ before do
+ project.update!(visibility_level: Gitlab::VisibilityLevel::PUBLIC)
+ end
+
+ context 'when running as dry run' do
+ let(:dry_run) { true }
+
+ before do
+ stub_ci_pipeline_yaml_file(yaml_content)
+ end
+
+ it 'returns pipeline creation error' do
+ ci_lint
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['merged_yaml']).to eq(nil)
+ expect(json_response['valid']).to eq(false)
+ expect(json_response['errors']).to eq(['Insufficient permissions to create a new pipeline'])
+ end
+ end
+
+ context 'when running static validation' do
+ let(:dry_run) { false }
+
+ let(:included_content) do
+ { another_test: { stage: 'test', script: 'echo 1' } }.to_yaml
+ end
+
+ before do
+ project.repository.create_file(
+ project.creator,
+ '.gitlab-ci.yml',
+ yaml_content,
+ message: 'Automatically created .gitlab-ci.yml',
+ branch_name: 'master'
+ )
+
+ project.repository.create_file(
+ project.creator,
+ 'another-gitlab-ci.yml',
+ included_content,
+ message: 'Automatically created another-gitlab-ci.yml',
+ branch_name: 'master'
+ )
+ end
+
+ it_behaves_like 'valid config'
+ end
+ end
+ end
+
+ context 'when authenticated as project guest' do
+ let_it_be(:api_user) { create(:user) }
+
+ before do
+ project.add_guest(api_user)
+ end
+
+ it 'returns authentication error' do
+ ci_lint
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ end
+ end
+
+ context 'when authenticated as project developer' do
+ let_it_be(:api_user) { create(:user) }
+
+ before do
+ project.add_developer(api_user)
+ end
+
+ context 'with valid .gitlab-ci.yml content' do
+ let(:yaml_content) do
+ { include: { local: 'another-gitlab-ci.yml' }, test: { stage: 'test', script: 'echo 1' } }.to_yaml
+ end
+
+ let(:included_content) do
+ { another_test: { stage: 'test', script: 'echo 1' } }.to_yaml
+ end
+
+ before do
+ project.repository.create_file(
+ project.creator,
+ '.gitlab-ci.yml',
+ yaml_content,
+ message: 'Automatically created .gitlab-ci.yml',
+ branch_name: 'master'
+ )
+
+ project.repository.create_file(
+ project.creator,
+ 'another-gitlab-ci.yml',
+ included_content,
+ message: 'Automatically created another-gitlab-ci.yml',
+ branch_name: 'master'
+ )
+ end
+
+ context 'when running as dry run' do
+ let(:dry_run) { true }
+
+ it_behaves_like 'valid config'
+ end
+
+ context 'when running static validation' do
+ let(:dry_run) { false }
+
+ it_behaves_like 'valid config'
+ end
+ end
+
+ context 'with invalid .gitlab-ci.yml content' do
+ let(:yaml_content) do
+ { image: 'ruby:2.7', services: ['postgres'] }.to_yaml
+ end
+
+ before do
+ stub_ci_pipeline_yaml_file(yaml_content)
+ end
+
+ context 'when running as dry run' do
+ let(:dry_run) { true }
+
+ it_behaves_like 'invalid config'
+ end
+
+ context 'when running static validation' do
+ let(:dry_run) { false }
+
+ it_behaves_like 'invalid config'
+ end
+ end
+ end
+ end
end
diff --git a/spec/requests/api/maven_packages_spec.rb b/spec/requests/api/maven_packages_spec.rb
index 0a23aed109b..37748fe5ea7 100644
--- a/spec/requests/api/maven_packages_spec.rb
+++ b/spec/requests/api/maven_packages_spec.rb
@@ -15,10 +15,13 @@ RSpec.describe API::MavenPackages do
let_it_be(:job, reload: true) { create(:ci_build, user: user, status: :running) }
let_it_be(:deploy_token) { create(:deploy_token, read_package_registry: true, write_package_registry: true) }
let_it_be(:project_deploy_token) { create(:project_deploy_token, deploy_token: deploy_token, project: project) }
+ let_it_be(:deploy_token_for_group) { create(:deploy_token, :group, read_package_registry: true, write_package_registry: true) }
+ let_it_be(:group_deploy_token) { create(:group_deploy_token, deploy_token: deploy_token_for_group, group: group) }
let(:workhorse_token) { JWT.encode({ 'iss' => 'gitlab-workhorse' }, Gitlab::Workhorse.secret, 'HS256') }
let(:headers) { { 'GitLab-Workhorse' => '1.0', Gitlab::Workhorse::INTERNAL_API_REQUEST_HEADER => workhorse_token } }
let(:headers_with_token) { headers.merge('Private-Token' => personal_access_token.token) }
+ let(:group_deploy_token_headers) { { Gitlab::Auth::AuthFinders::DEPLOY_TOKEN_HEADER => deploy_token_for_group.token } }
let(:headers_with_deploy_token) do
headers.merge(
@@ -36,7 +39,7 @@ RSpec.describe API::MavenPackages do
context 'with jar file' do
let_it_be(:package_file) { jar_file }
- it_behaves_like 'a gitlab tracking event', described_class.name, 'pull_package'
+ it_behaves_like 'a package tracking event', described_class.name, 'pull_package'
end
end
@@ -342,6 +345,17 @@ RSpec.describe API::MavenPackages do
it_behaves_like 'downloads with a job token'
it_behaves_like 'downloads with a deploy token'
+
+ context 'with group deploy token' do
+ subject { download_file_with_token(package_file.file_name, {}, group_deploy_token_headers) }
+
+ it 'returns the file' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response.media_type).to eq('application/octet-stream')
+ end
+ end
end
def download_file(file_name, params = {}, request_headers = headers)
@@ -548,7 +562,7 @@ RSpec.describe API::MavenPackages do
allow(uploaded_file).to receive(:size).and_return(project.actual_limits.maven_max_file_size + 1)
end
- upload_file_with_token(params)
+ upload_file_with_token(params: params)
expect(response).to have_gitlab_http_status(:bad_request)
end
@@ -563,19 +577,19 @@ RSpec.describe API::MavenPackages do
context 'without workhorse header' do
let(:workhorse_header) { {} }
- subject { upload_file_with_token(params) }
+ subject { upload_file_with_token(params: params) }
it_behaves_like 'package workhorse uploads'
end
context 'event tracking' do
- subject { upload_file_with_token(params) }
+ subject { upload_file_with_token(params: params) }
- it_behaves_like 'a gitlab tracking event', described_class.name, 'push_package'
+ it_behaves_like 'a package tracking event', described_class.name, 'push_package'
end
it 'creates package and stores package file' do
- expect { upload_file_with_token(params) }.to change { project.packages.count }.by(1)
+ expect { upload_file_with_token(params: params) }.to change { project.packages.count }.by(1)
.and change { Packages::Maven::Metadatum.count }.by(1)
.and change { Packages::PackageFile.count }.by(1)
@@ -584,7 +598,7 @@ RSpec.describe API::MavenPackages do
end
it 'allows upload with running job token' do
- upload_file(params.merge(job_token: job.token))
+ upload_file(params: params.merge(job_token: job.token))
expect(response).to have_gitlab_http_status(:ok)
expect(project.reload.packages.last.build_info.pipeline).to eq job.pipeline
@@ -592,13 +606,13 @@ RSpec.describe API::MavenPackages do
it 'rejects upload without running job token' do
job.update!(status: :failed)
- upload_file(params.merge(job_token: job.token))
+ upload_file(params: params.merge(job_token: job.token))
expect(response).to have_gitlab_http_status(:unauthorized)
end
it 'allows upload with deploy token' do
- upload_file(params, headers_with_deploy_token)
+ upload_file(params: params, request_headers: headers_with_deploy_token)
expect(response).to have_gitlab_http_status(:ok)
end
@@ -612,7 +626,10 @@ RSpec.describe API::MavenPackages do
# We force the id of the deploy token and the user to be the same
unauthorized_deploy_token.update!(id: another_user.id)
- upload_file(params, headers.merge(Gitlab::Auth::AuthFinders::DEPLOY_TOKEN_HEADER => unauthorized_deploy_token.token))
+ upload_file(
+ params: params,
+ request_headers: headers.merge(Gitlab::Auth::AuthFinders::DEPLOY_TOKEN_HEADER => unauthorized_deploy_token.token)
+ )
expect(response).to have_gitlab_http_status(:forbidden)
end
@@ -621,16 +638,43 @@ RSpec.describe API::MavenPackages do
let(:version) { '$%123' }
it 'rejects request' do
- expect { upload_file_with_token(params) }.not_to change { project.packages.count }
+ expect { upload_file_with_token(params: params) }.not_to change { project.packages.count }
expect(response).to have_gitlab_http_status(:bad_request)
expect(json_response['message']).to include('Validation failed')
end
end
+
+ context 'for sha1 file' do
+ let(:dummy_package) { double(Packages::Package) }
+
+ it 'checks the sha1' do
+ # The sha verification done by the maven api is between:
+ # - the sha256 set by workhorse helpers
+ # - the sha256 of the sha1 of the uploaded package file
+ # We're going to send `file_upload` for the sha1 and stub the sha1 of the package file so that
+ # both sha256 being the same
+ expect(::Packages::PackageFileFinder).to receive(:new).and_return(double(execute!: dummy_package))
+ expect(dummy_package).to receive(:file_sha1).and_return(File.read(file_upload.path))
+
+ upload_file_with_token(params: params, file_extension: 'jar.sha1')
+
+ expect(response).to have_gitlab_http_status(:no_content)
+ end
+ end
+
+ context 'for md5 file' do
+ it 'returns an empty body' do
+ upload_file_with_token(params: params, file_extension: 'jar.md5')
+
+ expect(response.body).to eq('')
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+ end
end
- def upload_file(params = {}, request_headers = headers)
- url = "/projects/#{project.id}/packages/maven/com/example/my-app/#{version}/my-app-1.0-20180724.124855-1.jar"
+ def upload_file(params: {}, request_headers: headers, file_extension: 'jar')
+ url = "/projects/#{project.id}/packages/maven/com/example/my-app/#{version}/my-app-1.0-20180724.124855-1.#{file_extension}"
workhorse_finalize(
api(url),
method: :put,
@@ -641,8 +685,8 @@ RSpec.describe API::MavenPackages do
)
end
- def upload_file_with_token(params = {}, request_headers = headers_with_token)
- upload_file(params, request_headers)
+ def upload_file_with_token(params: {}, request_headers: headers_with_token, file_extension: 'jar')
+ upload_file(params: params, request_headers: request_headers, file_extension: file_extension)
end
end
end
diff --git a/spec/requests/api/members_spec.rb b/spec/requests/api/members_spec.rb
index 55b2447fc68..047b9423906 100644
--- a/spec/requests/api/members_spec.rb
+++ b/spec/requests/api/members_spec.rb
@@ -196,6 +196,7 @@ RSpec.describe API::Members do
# Member attributes
expect(json_response['access_level']).to eq(Member::DEVELOPER)
+ expect(json_response['created_at'].to_time).to be_like_time(developer.created_at)
end
end
end
@@ -251,6 +252,36 @@ RSpec.describe API::Members do
expect(json_response['id']).to eq(stranger.id)
expect(json_response['access_level']).to eq(Member::DEVELOPER)
end
+
+ describe 'executes the Members::CreateService for multiple user_ids' do
+ it 'returns success when it successfully create all members' do
+ expect do
+ user_ids = [stranger.id, access_requester.id].join(',')
+
+ post api("/#{source_type.pluralize}/#{source.id}/members", maintainer),
+ params: { user_id: user_ids, access_level: Member::DEVELOPER }
+
+ expect(response).to have_gitlab_http_status(:created)
+ end.to change { source.members.count }.by(2)
+ expect(json_response['status']).to eq('success')
+ end
+
+ it 'returns the error message if there was an error adding members to group' do
+ error_message = 'Unable to find User ID'
+ user_ids = [stranger.id, access_requester.id].join(',')
+
+ allow_next_instance_of(::Members::CreateService) do |service|
+ expect(service).to receive(:execute).with(source).and_return({ status: :error, message: error_message })
+ end
+
+ expect do
+ post api("/#{source_type.pluralize}/#{source.id}/members", maintainer),
+ params: { user_id: user_ids, access_level: Member::DEVELOPER }
+ end.not_to change { source.members.count }
+ expect(json_response['status']).to eq('error')
+ expect(json_response['message']).to eq(error_message)
+ end
+ end
end
context 'access levels' do
diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb
index 2757c56e0fe..506607f4cc2 100644
--- a/spec/requests/api/merge_requests_spec.rb
+++ b/spec/requests/api/merge_requests_spec.rb
@@ -856,6 +856,55 @@ RSpec.describe API::MergeRequests do
expect(json_response.first['id']).to eq merge_request_closed.id
end
+ context 'when filtering by deployments' do
+ let_it_be(:mr) do
+ create(:merge_request, :merged, source_project: project, target_project: project)
+ end
+
+ before do
+ env = create(:environment, project: project, name: 'staging')
+ deploy = create(:deployment, :success, environment: env, deployable: nil)
+
+ deploy.link_merge_requests(MergeRequest.where(id: mr.id))
+ end
+
+ it 'supports getting merge requests deployed to an environment' do
+ get api(endpoint_path, user), params: { environment: 'staging' }
+
+ expect(json_response.first['id']).to eq mr.id
+ end
+
+ it 'does not return merge requests for an environment without deployments' do
+ get api(endpoint_path, user), params: { environment: 'bla' }
+
+ expect_empty_array_response
+ end
+
+ it 'supports getting merge requests deployed after a date' do
+ get api(endpoint_path, user), params: { deployed_after: '1990-01-01' }
+
+ expect(json_response.first['id']).to eq mr.id
+ end
+
+ it 'does not return merge requests not deployed after a given date' do
+ get api(endpoint_path, user), params: { deployed_after: '2100-01-01' }
+
+ expect_empty_array_response
+ end
+
+ it 'supports getting merge requests deployed before a date' do
+ get api(endpoint_path, user), params: { deployed_before: '2100-01-01' }
+
+ expect(json_response.first['id']).to eq mr.id
+ end
+
+ it 'does not return merge requests not deployed before a given date' do
+ get api(endpoint_path, user), params: { deployed_before: '1990-01-01' }
+
+ expect_empty_array_response
+ end
+ end
+
context 'a project which enforces all discussions to be resolved' do
let_it_be(:project) { create(:project, :repository, only_allow_merge_if_all_discussions_are_resolved: true) }
@@ -1140,7 +1189,7 @@ RSpec.describe API::MergeRequests do
context 'when a merge request has more than the changes limit' do
it "returns a string indicating that more changes were made" do
- stub_const('Commit::DIFF_HARD_LIMIT_FILES', 5)
+ allow(Commit).to receive(:diff_hard_limit_files).and_return(5)
merge_request_overflow = create(:merge_request, :simple,
author: user,
diff --git a/spec/requests/api/npm_packages_spec.rb b/spec/requests/api/npm_packages_spec.rb
index 108ea84b7e6..8a3ccd7c6e3 100644
--- a/spec/requests/api/npm_packages_spec.rb
+++ b/spec/requests/api/npm_packages_spec.rb
@@ -88,12 +88,16 @@ RSpec.describe API::NpmPackages do
it_behaves_like 'returning the npm package info'
context 'with unknown package' do
+ subject { get api("/packages/npm/unknown") }
+
it 'returns a redirect' do
- get api("/packages/npm/unknown")
+ subject
expect(response).to have_gitlab_http_status(:found)
expect(response.headers['Location']).to eq('https://registry.npmjs.org/unknown')
end
+
+ it_behaves_like 'a gitlab tracking event', described_class.name, 'npm_request_forward'
end
end
@@ -193,7 +197,7 @@ RSpec.describe API::NpmPackages do
expect(response.media_type).to eq('application/octet-stream')
end
- it_behaves_like 'a gitlab tracking event', described_class.name, 'pull_package'
+ it_behaves_like 'a package tracking event', described_class.name, 'pull_package'
end
context 'private project' do
@@ -301,7 +305,7 @@ RSpec.describe API::NpmPackages do
context 'with access token' do
subject { upload_package_with_token(package_name, params) }
- it_behaves_like 'a gitlab tracking event', described_class.name, 'push_package'
+ it_behaves_like 'a package tracking event', described_class.name, 'push_package'
it 'creates npm package with file' do
expect { subject }
diff --git a/spec/requests/api/project_clusters_spec.rb b/spec/requests/api/project_clusters_spec.rb
index ff35e380476..7b37862af74 100644
--- a/spec/requests/api/project_clusters_spec.rb
+++ b/spec/requests/api/project_clusters_spec.rb
@@ -171,6 +171,7 @@ RSpec.describe API::ProjectClusters do
name: 'test-cluster',
domain: 'domain.example.com',
managed: false,
+ namespace_per_environment: false,
platform_kubernetes_attributes: platform_kubernetes_attributes,
management_project_id: management_project_id
}
@@ -202,6 +203,7 @@ RSpec.describe API::ProjectClusters do
expect(cluster_result.domain).to eq('domain.example.com')
expect(cluster_result.managed).to be_falsy
expect(cluster_result.management_project_id).to eq management_project_id
+ expect(cluster_result.namespace_per_environment).to eq(false)
expect(platform_kubernetes.rbac?).to be_truthy
expect(platform_kubernetes.api_url).to eq(api_url)
expect(platform_kubernetes.namespace).to eq(namespace)
@@ -235,6 +237,22 @@ RSpec.describe API::ProjectClusters do
end
end
+ context 'when namespace_per_environment is not set' do
+ let(:cluster_params) do
+ {
+ name: 'test-cluster',
+ domain: 'domain.example.com',
+ platform_kubernetes_attributes: platform_kubernetes_attributes
+ }
+ end
+
+ it 'defaults to true' do
+ cluster_result = Clusters::Cluster.find(json_response['id'])
+
+ expect(cluster_result).to be_namespace_per_environment
+ end
+ end
+
context 'current user does not have access to management_project_id' do
let(:management_project_id) { create(:project).id }
diff --git a/spec/requests/api/project_container_repositories_spec.rb b/spec/requests/api/project_container_repositories_spec.rb
index 6cf0619cde4..34476b10576 100644
--- a/spec/requests/api/project_container_repositories_spec.rb
+++ b/spec/requests/api/project_container_repositories_spec.rb
@@ -31,7 +31,6 @@ RSpec.describe API::ProjectContainerRepositories do
project.add_reporter(reporter)
project.add_guest(guest)
- stub_feature_flags(container_registry_api: true)
stub_container_registry_config(enabled: true)
root_repository
@@ -45,7 +44,7 @@ RSpec.describe API::ProjectContainerRepositories do
it_behaves_like 'rejected container repository access', :guest, :forbidden
it_behaves_like 'rejected container repository access', :anonymous, :not_found
- it_behaves_like 'a gitlab tracking event', described_class.name, 'list_repositories'
+ it_behaves_like 'a package tracking event', described_class.name, 'list_repositories'
it_behaves_like 'returns repositories for allowed users', :reporter, 'project' do
let(:object) { project }
@@ -57,7 +56,7 @@ RSpec.describe API::ProjectContainerRepositories do
it_behaves_like 'rejected container repository access', :developer, :forbidden
it_behaves_like 'rejected container repository access', :anonymous, :not_found
- it_behaves_like 'a gitlab tracking event', described_class.name, 'delete_repository'
+ it_behaves_like 'a package tracking event', described_class.name, 'delete_repository'
context 'for maintainer' do
let(:api_user) { maintainer }
@@ -86,7 +85,7 @@ RSpec.describe API::ProjectContainerRepositories do
stub_container_registry_tags(repository: root_repository.path, tags: %w(rootA latest))
end
- it_behaves_like 'a gitlab tracking event', described_class.name, 'list_tags'
+ it_behaves_like 'a package tracking event', described_class.name, 'list_tags'
it 'returns a list of tags' do
subject
@@ -114,7 +113,7 @@ RSpec.describe API::ProjectContainerRepositories do
it_behaves_like 'rejected container repository access', :developer, :forbidden
it_behaves_like 'rejected container repository access', :anonymous, :not_found
- it_behaves_like 'a gitlab tracking event', described_class.name, 'delete_tag_bulk'
+ it_behaves_like 'a package tracking event', described_class.name, 'delete_tag_bulk'
end
context 'for maintainer' do
diff --git a/spec/requests/api/project_packages_spec.rb b/spec/requests/api/project_packages_spec.rb
index 2f0d0fc87ec..4c8599d1a20 100644
--- a/spec/requests/api/project_packages_spec.rb
+++ b/spec/requests/api/project_packages_spec.rb
@@ -23,6 +23,19 @@ RSpec.describe API::ProjectPackages do
it_behaves_like 'returns packages', :project, :no_type
end
+ context 'with conan package' do
+ let!(:conan_package) { create(:conan_package, project: project) }
+
+ it 'uses the conan recipe as the package name' do
+ subject
+
+ response_conan_package = json_response.find { |package| package['id'] == conan_package.id }
+
+ expect(response_conan_package['name']).to eq(conan_package.conan_recipe)
+ expect(response_conan_package['conan_package_name']).to eq(conan_package.name)
+ end
+ end
+
context 'project is private' do
let(:project) { create(:project, :private) }
diff --git a/spec/requests/api/project_repository_storage_moves_spec.rb b/spec/requests/api/project_repository_storage_moves_spec.rb
index 4c9e058ef13..ecf4c75b52f 100644
--- a/spec/requests/api/project_repository_storage_moves_spec.rb
+++ b/spec/requests/api/project_repository_storage_moves_spec.rb
@@ -145,10 +145,17 @@ RSpec.describe API::ProjectRepositoryStorageMoves do
context 'destination_storage_name is missing' do
let(:destination_storage_name) { nil }
- it 'returns a validation error' do
+ it 'schedules a project repository storage move' do
create_project_repository_storage_move
- expect(response).to have_gitlab_http_status(:bad_request)
+ storage_move = project.repository_storage_moves.last
+
+ expect(response).to have_gitlab_http_status(:created)
+ expect(response).to match_response_schema('public_api/v4/project_repository_storage_move')
+ expect(json_response['id']).to eq(storage_move.id)
+ expect(json_response['state']).to eq('scheduled')
+ expect(json_response['source_storage_name']).to eq('default')
+ expect(json_response['destination_storage_name']).to be_present
end
end
end
diff --git a/spec/requests/api/project_snippets_spec.rb b/spec/requests/api/project_snippets_spec.rb
index 08c88873078..6a9cf6e16e2 100644
--- a/spec/requests/api/project_snippets_spec.rb
+++ b/spec/requests/api/project_snippets_spec.rb
@@ -6,21 +6,16 @@ RSpec.describe API::ProjectSnippets do
include SnippetHelpers
let_it_be(:project) { create(:project, :public) }
- let_it_be(:user) { create(:user) }
- let_it_be(:admin) { create(:admin) }
let_it_be(:project_no_snippets) { create(:project, :snippets_disabled) }
-
- before do
- project_no_snippets.add_developer(admin)
- project_no_snippets.add_developer(user)
- end
+ let_it_be(:user) { create(:user, developer_projects: [project_no_snippets]) }
+ let_it_be(:admin) { create(:admin, developer_projects: [project_no_snippets]) }
+ let_it_be(:public_snippet, reload: true) { create(:project_snippet, :public, :repository, project: project) }
describe "GET /projects/:project_id/snippets/:id/user_agent_detail" do
- let(:snippet) { create(:project_snippet, :public, project: project) }
- let!(:user_agent_detail) { create(:user_agent_detail, subject: snippet) }
+ let_it_be(:user_agent_detail) { create(:user_agent_detail, subject: public_snippet) }
it 'exposes known attributes' do
- get api("/projects/#{project.id}/snippets/#{snippet.id}/user_agent_detail", admin)
+ get api("/projects/#{project.id}/snippets/#{public_snippet.id}/user_agent_detail", admin)
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['user_agent']).to eq(user_agent_detail.user_agent)
@@ -31,29 +26,27 @@ RSpec.describe API::ProjectSnippets do
it 'respects project scoping' do
other_project = create(:project)
- get api("/projects/#{other_project.id}/snippets/#{snippet.id}/user_agent_detail", admin)
+ get api("/projects/#{other_project.id}/snippets/#{public_snippet.id}/user_agent_detail", admin)
expect(response).to have_gitlab_http_status(:not_found)
end
it "returns unauthorized for non-admin users" do
- get api("/projects/#{snippet.project.id}/snippets/#{snippet.id}/user_agent_detail", user)
+ get api("/projects/#{public_snippet.project.id}/snippets/#{public_snippet.id}/user_agent_detail", user)
expect(response).to have_gitlab_http_status(:forbidden)
end
context 'with snippets disabled' do
it_behaves_like '403 response' do
- let(:request) { get api("/projects/#{project_no_snippets.id}/snippets/123/user_agent_detail", admin) }
+ let(:request) { get api("/projects/#{project_no_snippets.id}/snippets/#{non_existing_record_id}/user_agent_detail", admin) }
end
end
end
describe 'GET /projects/:project_id/snippets/' do
- let(:user) { create(:user) }
-
it 'returns all snippets available to team member' do
project.add_developer(user)
- public_snippet = create(:project_snippet, :public, project: project)
+
internal_snippet = create(:project_snippet, :internal, project: project)
private_snippet = create(:project_snippet, :private, project: project)
@@ -62,8 +55,7 @@ RSpec.describe API::ProjectSnippets 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.size).to eq(3)
- expect(json_response.map { |snippet| snippet['id'] }).to include(public_snippet.id, internal_snippet.id, private_snippet.id)
+ expect(json_response.map { |snippet| snippet['id'] }).to contain_exactly(public_snippet.id, internal_snippet.id, private_snippet.id)
expect(json_response.last).to have_key('web_url')
end
@@ -75,7 +67,7 @@ RSpec.describe API::ProjectSnippets 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.size).to eq(0)
+ expect(json_response.map { |snippet| snippet['id'] }).to contain_exactly(public_snippet.id)
end
context 'with snippets disabled' do
@@ -86,8 +78,7 @@ RSpec.describe API::ProjectSnippets do
end
describe 'GET /projects/:project_id/snippets/:id' do
- let_it_be(:user) { create(:user) }
- let_it_be(:snippet) { create(:project_snippet, :public, :repository, project: project) }
+ let(:snippet) { public_snippet }
it 'returns snippet json' do
get api("/projects/#{project.id}/snippets/#{snippet.id}", user)
@@ -113,12 +104,12 @@ RSpec.describe API::ProjectSnippets do
context 'with snippets disabled' do
it_behaves_like '403 response' do
- let(:request) { get api("/projects/#{project_no_snippets.id}/snippets/123", user) }
+ let(:request) { get api("/projects/#{project_no_snippets.id}/snippets/#{non_existing_record_id}", user) }
end
end
- it_behaves_like 'snippet_multiple_files feature disabled' do
- subject { get api("/projects/#{project.id}/snippets/#{snippet.id}", user) }
+ it_behaves_like 'project snippet access levels' do
+ let(:path) { "/projects/#{snippet.project.id}/snippets/#{snippet.id}" }
end
end
@@ -133,37 +124,35 @@ RSpec.describe API::ProjectSnippets do
let(:file_path) { 'file_1.rb' }
let(:file_content) { 'puts "hello world"' }
- let(:params) { base_params.merge(file_params) }
let(:file_params) { { files: [{ file_path: file_path, content: file_content }] } }
+ let(:params) { base_params.merge(file_params) }
+
+ subject { post api("/projects/#{project.id}/snippets/", actor), params: params }
shared_examples 'project snippet repository actions' do
let(:snippet) { ProjectSnippet.find(json_response['id']) }
- it 'creates repository' do
- subject
-
- expect(snippet.repository.exists?).to be_truthy
- end
-
it 'commit the files to the repository' do
subject
- blob = snippet.repository.blob_at('master', file_path)
+ aggregate_failures do
+ expect(snippet.repository.exists?).to be_truthy
+
+ blob = snippet.repository.blob_at('master', file_path)
- expect(blob.data).to eq file_content
+ expect(blob.data).to eq file_content
+ end
end
end
context 'with an external user' do
- let(:user) { create(:user, :external) }
+ let(:actor) { create(:user, :external) }
context 'that belongs to the project' do
- before do
- project.add_developer(user)
- end
-
it 'creates a new snippet' do
- post api("/projects/#{project.id}/snippets/", user), params: params
+ project.add_developer(actor)
+
+ subject
expect(response).to have_gitlab_http_status(:created)
end
@@ -171,7 +160,7 @@ RSpec.describe API::ProjectSnippets do
context 'that does not belong to the project' do
it 'does not create a new snippet' do
- post api("/projects/#{project.id}/snippets/", user), params: params
+ subject
expect(response).to have_gitlab_http_status(:forbidden)
end
@@ -179,16 +168,17 @@ RSpec.describe API::ProjectSnippets do
end
context 'with a regular user' do
- let(:user) { create(:user) }
+ let(:actor) { user }
- before do
+ before_all do
project.add_developer(user)
+ end
+
+ before do
stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PUBLIC, Gitlab::VisibilityLevel::PRIVATE])
params['visibility'] = 'internal'
end
- subject { post api("/projects/#{project.id}/snippets/", user), params: params }
-
it 'creates a new snippet' do
subject
@@ -205,7 +195,7 @@ RSpec.describe API::ProjectSnippets do
end
context 'with an admin' do
- subject { post api("/projects/#{project.id}/snippets/", admin), params: params }
+ let(:actor) { admin }
it 'creates a new snippet' do
subject
@@ -244,6 +234,8 @@ RSpec.describe API::ProjectSnippets do
end
context 'when save fails because the repository could not be created' do
+ let(:actor) { admin }
+
before do
allow_next_instance_of(Snippets::CreateService) do |instance|
allow(instance).to receive(:create_repository).and_raise(Snippets::CreateService::CreateRepositoryError)
@@ -251,43 +243,44 @@ RSpec.describe API::ProjectSnippets do
end
it 'returns 400' do
- post api("/projects/#{project.id}/snippets", admin), params: params
+ subject
expect(response).to have_gitlab_http_status(:bad_request)
end
end
context 'when the snippet is spam' do
- def create_snippet(project, snippet_params = {})
- project.add_developer(user)
-
- post api("/projects/#{project.id}/snippets", user), params: params.merge(snippet_params)
- end
+ let(:actor) { user }
before do
allow_next_instance_of(Spam::AkismetService) do |instance|
allow(instance).to receive(:spam?).and_return(true)
end
+
+ project.add_developer(user)
end
context 'when the snippet is private' do
it 'creates the snippet' do
- expect { create_snippet(project, visibility: 'private') }
- .to change { Snippet.count }.by(1)
+ params['visibility'] = 'private'
+
+ expect { subject }.to change { Snippet.count }.by(1)
end
end
context 'when the snippet is public' do
- it 'rejects the snippet' do
- expect { create_snippet(project, visibility: 'public') }
- .not_to change { Snippet.count }
+ before do
+ params['visibility'] = 'public'
+ end
+ it 'rejects the snippet' do
+ expect { subject }.not_to change { Snippet.count }
expect(response).to have_gitlab_http_status(:bad_request)
expect(json_response['message']).to eq({ "error" => "Spam detected" })
end
it 'creates a spam log' do
- expect { create_snippet(project, visibility: 'public') }
+ expect { subject }
.to log_spam(title: 'Test Title', user_id: user.id, noteable_type: 'ProjectSnippet')
end
end
@@ -363,7 +356,7 @@ RSpec.describe API::ProjectSnippets do
context 'with snippets disabled' do
it_behaves_like '403 response' do
- let(:request) { put api("/projects/#{project_no_snippets.id}/snippets/123", admin), params: { description: 'foo' } }
+ let(:request) { put api("/projects/#{project_no_snippets.id}/snippets/#{non_existing_record_id}", admin), params: { description: 'foo' } }
end
end
@@ -373,7 +366,7 @@ RSpec.describe API::ProjectSnippets do
end
describe 'DELETE /projects/:project_id/snippets/:id/' do
- let(:snippet) { create(:project_snippet, author: admin, project: project) }
+ let_it_be(:snippet, refind: true) { public_snippet }
it 'deletes snippet' do
delete api("/projects/#{snippet.project.id}/snippets/#{snippet.id}/", admin)
@@ -394,13 +387,13 @@ RSpec.describe API::ProjectSnippets do
context 'with snippets disabled' do
it_behaves_like '403 response' do
- let(:request) { delete api("/projects/#{project_no_snippets.id}/snippets/123", admin) }
+ let(:request) { delete api("/projects/#{project_no_snippets.id}/snippets/#{non_existing_record_id}", admin) }
end
end
end
describe 'GET /projects/:project_id/snippets/:id/raw' do
- let_it_be(:snippet) { create(:project_snippet, :repository, author: admin, project: project) }
+ let_it_be(:snippet) { create(:project_snippet, :repository, :public, author: admin, project: project) }
it 'returns raw text' do
get api("/projects/#{snippet.project.id}/snippets/#{snippet.id}/raw", admin)
@@ -416,9 +409,13 @@ RSpec.describe API::ProjectSnippets do
expect(json_response['message']).to eq('404 Snippet Not Found')
end
+ it_behaves_like 'project snippet access levels' do
+ let(:path) { "/projects/#{snippet.project.id}/snippets/#{snippet.id}/raw" }
+ end
+
context 'with snippets disabled' do
it_behaves_like '403 response' do
- let(:request) { get api("/projects/#{project_no_snippets.id}/snippets/123/raw", admin) }
+ let(:request) { get api("/projects/#{project_no_snippets.id}/snippets/#{non_existing_record_id}/raw", admin) }
end
end
@@ -435,5 +432,9 @@ RSpec.describe API::ProjectSnippets do
it_behaves_like 'raw snippet files' do
let(:api_path) { "/projects/#{snippet.project.id}/snippets/#{snippet_id}/files/#{ref}/#{file_path}/raw" }
end
+
+ it_behaves_like 'project snippet access levels' do
+ let(:path) { "/projects/#{snippet.project.id}/snippets/#{snippet.id}/files/master/%2Egitattributes/raw" }
+ end
end
end
diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb
index 831b0d6e678..2abcb39a1c8 100644
--- a/spec/requests/api/projects_spec.rb
+++ b/spec/requests/api/projects_spec.rb
@@ -1615,6 +1615,7 @@ RSpec.describe API::Projects do
expect(json_response['allow_merge_on_skipped_pipeline']).to eq(project.allow_merge_on_skipped_pipeline)
expect(json_response['only_allow_merge_if_all_discussions_are_resolved']).to eq(project.only_allow_merge_if_all_discussions_are_resolved)
expect(json_response['ci_default_git_depth']).to eq(project.ci_default_git_depth)
+ expect(json_response['ci_forward_deployment_enabled']).to eq(project.ci_forward_deployment_enabled)
expect(json_response['merge_method']).to eq(project.merge_method.to_s)
expect(json_response['readme_url']).to eq(project.readme_url)
expect(json_response).to have_key 'packages_enabled'
@@ -2607,6 +2608,7 @@ RSpec.describe API::Projects do
merge_requests_enabled: true,
merge_method: 'ff',
ci_default_git_depth: 20,
+ ci_forward_deployment_enabled: false,
description: 'new description' }
put api("/projects/#{project3.id}", user4), params: project_param
diff --git a/spec/requests/api/pypi_packages_spec.rb b/spec/requests/api/pypi_packages_spec.rb
index e72ac002f6b..72a470dca4b 100644
--- a/spec/requests/api/pypi_packages_spec.rb
+++ b/spec/requests/api/pypi_packages_spec.rb
@@ -23,24 +23,24 @@ RSpec.describe API::PypiPackages do
using RSpec::Parameterized::TableSyntax
where(:project_visibility_level, :user_role, :member, :user_token, :shared_examples_name, :expected_status) do
- 'PUBLIC' | :developer | true | true | 'PyPi package versions' | :success
- 'PUBLIC' | :guest | true | true | 'PyPi package versions' | :success
- 'PUBLIC' | :developer | true | false | 'PyPi package versions' | :success
- 'PUBLIC' | :guest | true | false | 'PyPi package versions' | :success
- 'PUBLIC' | :developer | false | true | 'PyPi package versions' | :success
- 'PUBLIC' | :guest | false | true | 'PyPi package versions' | :success
- 'PUBLIC' | :developer | false | false | 'PyPi package versions' | :success
- 'PUBLIC' | :guest | false | false | 'PyPi package versions' | :success
- 'PUBLIC' | :anonymous | false | true | 'PyPi package versions' | :success
- 'PRIVATE' | :developer | true | true | 'PyPi package versions' | :success
- 'PRIVATE' | :guest | true | true | 'process PyPi api request' | :forbidden
- 'PRIVATE' | :developer | true | false | 'process PyPi api request' | :unauthorized
- 'PRIVATE' | :guest | true | false | 'process PyPi api request' | :unauthorized
- 'PRIVATE' | :developer | false | true | 'process PyPi api request' | :not_found
- 'PRIVATE' | :guest | false | true | 'process PyPi api request' | :not_found
- 'PRIVATE' | :developer | false | false | 'process PyPi api request' | :unauthorized
- 'PRIVATE' | :guest | false | false | 'process PyPi api request' | :unauthorized
- 'PRIVATE' | :anonymous | false | true | 'process PyPi api request' | :unauthorized
+ 'PUBLIC' | :developer | true | true | 'PyPI package versions' | :success
+ 'PUBLIC' | :guest | true | true | 'PyPI package versions' | :success
+ 'PUBLIC' | :developer | true | false | 'PyPI package versions' | :success
+ 'PUBLIC' | :guest | true | false | 'PyPI package versions' | :success
+ 'PUBLIC' | :developer | false | true | 'PyPI package versions' | :success
+ 'PUBLIC' | :guest | false | true | 'PyPI package versions' | :success
+ 'PUBLIC' | :developer | false | false | 'PyPI package versions' | :success
+ 'PUBLIC' | :guest | false | false | 'PyPI package versions' | :success
+ 'PUBLIC' | :anonymous | false | true | 'PyPI package versions' | :success
+ 'PRIVATE' | :developer | true | true | 'PyPI package versions' | :success
+ 'PRIVATE' | :guest | true | true | 'process PyPI api request' | :forbidden
+ 'PRIVATE' | :developer | true | false | 'process PyPI api request' | :unauthorized
+ 'PRIVATE' | :guest | true | false | 'process PyPI api request' | :unauthorized
+ 'PRIVATE' | :developer | false | true | 'process PyPI api request' | :not_found
+ 'PRIVATE' | :guest | false | true | 'process PyPI api request' | :not_found
+ 'PRIVATE' | :developer | false | false | 'process PyPI api request' | :unauthorized
+ 'PRIVATE' | :guest | false | false | 'process PyPI api request' | :unauthorized
+ 'PRIVATE' | :anonymous | false | true | 'process PyPI api request' | :unauthorized
end
with_them do
@@ -57,6 +57,16 @@ RSpec.describe API::PypiPackages do
end
end
+ context 'with a normalized package name' do
+ let_it_be(:package) { create(:pypi_package, project: project, name: 'my.package') }
+ let(:url) { "/projects/#{project.id}/packages/pypi/simple/my-package" }
+ let(:headers) { basic_auth_header(user.username, personal_access_token.token) }
+
+ subject { get api(url), headers: headers }
+
+ it_behaves_like 'PyPI package versions', :developer, :success
+ end
+
it_behaves_like 'deploy token for package GET requests'
it_behaves_like 'job token for package GET requests'
@@ -76,24 +86,24 @@ RSpec.describe API::PypiPackages do
using RSpec::Parameterized::TableSyntax
where(:project_visibility_level, :user_role, :member, :user_token, :shared_examples_name, :expected_status) do
- 'PUBLIC' | :developer | true | true | 'process PyPi api request' | :success
- 'PUBLIC' | :guest | true | true | 'process PyPi api request' | :forbidden
- 'PUBLIC' | :developer | true | false | 'process PyPi api request' | :unauthorized
- 'PUBLIC' | :guest | true | false | 'process PyPi api request' | :unauthorized
- 'PUBLIC' | :developer | false | true | 'process PyPi api request' | :forbidden
- 'PUBLIC' | :guest | false | true | 'process PyPi api request' | :forbidden
- 'PUBLIC' | :developer | false | false | 'process PyPi api request' | :unauthorized
- 'PUBLIC' | :guest | false | false | 'process PyPi api request' | :unauthorized
- 'PUBLIC' | :anonymous | false | true | 'process PyPi api request' | :unauthorized
- 'PRIVATE' | :developer | true | true | 'process PyPi api request' | :success
- 'PRIVATE' | :guest | true | true | 'process PyPi api request' | :forbidden
- 'PRIVATE' | :developer | true | false | 'process PyPi api request' | :unauthorized
- 'PRIVATE' | :guest | true | false | 'process PyPi api request' | :unauthorized
- 'PRIVATE' | :developer | false | true | 'process PyPi api request' | :not_found
- 'PRIVATE' | :guest | false | true | 'process PyPi api request' | :not_found
- 'PRIVATE' | :developer | false | false | 'process PyPi api request' | :unauthorized
- 'PRIVATE' | :guest | false | false | 'process PyPi api request' | :unauthorized
- 'PRIVATE' | :anonymous | false | true | 'process PyPi api request' | :unauthorized
+ 'PUBLIC' | :developer | true | true | 'process PyPI api request' | :success
+ 'PUBLIC' | :guest | true | true | 'process PyPI api request' | :forbidden
+ 'PUBLIC' | :developer | true | false | 'process PyPI api request' | :unauthorized
+ 'PUBLIC' | :guest | true | false | 'process PyPI api request' | :unauthorized
+ 'PUBLIC' | :developer | false | true | 'process PyPI api request' | :forbidden
+ 'PUBLIC' | :guest | false | true | 'process PyPI api request' | :forbidden
+ 'PUBLIC' | :developer | false | false | 'process PyPI api request' | :unauthorized
+ 'PUBLIC' | :guest | false | false | 'process PyPI api request' | :unauthorized
+ 'PUBLIC' | :anonymous | false | true | 'process PyPI api request' | :unauthorized
+ 'PRIVATE' | :developer | true | true | 'process PyPI api request' | :success
+ 'PRIVATE' | :guest | true | true | 'process PyPI api request' | :forbidden
+ 'PRIVATE' | :developer | true | false | 'process PyPI api request' | :unauthorized
+ 'PRIVATE' | :guest | true | false | 'process PyPI api request' | :unauthorized
+ 'PRIVATE' | :developer | false | true | 'process PyPI api request' | :not_found
+ 'PRIVATE' | :guest | false | true | 'process PyPI api request' | :not_found
+ 'PRIVATE' | :developer | false | false | 'process PyPI api request' | :unauthorized
+ 'PRIVATE' | :guest | false | false | 'process PyPI api request' | :unauthorized
+ 'PRIVATE' | :anonymous | false | true | 'process PyPI api request' | :unauthorized
end
with_them do
@@ -142,24 +152,24 @@ RSpec.describe API::PypiPackages do
using RSpec::Parameterized::TableSyntax
where(:project_visibility_level, :user_role, :member, :user_token, :shared_examples_name, :expected_status) do
- 'PUBLIC' | :developer | true | true | 'PyPi package creation' | :created
- 'PUBLIC' | :guest | true | true | 'process PyPi api request' | :forbidden
- 'PUBLIC' | :developer | true | false | 'process PyPi api request' | :unauthorized
- 'PUBLIC' | :guest | true | false | 'process PyPi api request' | :unauthorized
- 'PUBLIC' | :developer | false | true | 'process PyPi api request' | :forbidden
- 'PUBLIC' | :guest | false | true | 'process PyPi api request' | :forbidden
- 'PUBLIC' | :developer | false | false | 'process PyPi api request' | :unauthorized
- 'PUBLIC' | :guest | false | false | 'process PyPi api request' | :unauthorized
- 'PUBLIC' | :anonymous | false | true | 'process PyPi api request' | :unauthorized
- 'PRIVATE' | :developer | true | true | 'process PyPi api request' | :created
- 'PRIVATE' | :guest | true | true | 'process PyPi api request' | :forbidden
- 'PRIVATE' | :developer | true | false | 'process PyPi api request' | :unauthorized
- 'PRIVATE' | :guest | true | false | 'process PyPi api request' | :unauthorized
- 'PRIVATE' | :developer | false | true | 'process PyPi api request' | :not_found
- 'PRIVATE' | :guest | false | true | 'process PyPi api request' | :not_found
- 'PRIVATE' | :developer | false | false | 'process PyPi api request' | :unauthorized
- 'PRIVATE' | :guest | false | false | 'process PyPi api request' | :unauthorized
- 'PRIVATE' | :anonymous | false | true | 'process PyPi api request' | :unauthorized
+ 'PUBLIC' | :developer | true | true | 'PyPI package creation' | :created
+ 'PUBLIC' | :guest | true | true | 'process PyPI api request' | :forbidden
+ 'PUBLIC' | :developer | true | false | 'process PyPI api request' | :unauthorized
+ 'PUBLIC' | :guest | true | false | 'process PyPI api request' | :unauthorized
+ 'PUBLIC' | :developer | false | true | 'process PyPI api request' | :forbidden
+ 'PUBLIC' | :guest | false | true | 'process PyPI api request' | :forbidden
+ 'PUBLIC' | :developer | false | false | 'process PyPI api request' | :unauthorized
+ 'PUBLIC' | :guest | false | false | 'process PyPI api request' | :unauthorized
+ 'PUBLIC' | :anonymous | false | true | 'process PyPI api request' | :unauthorized
+ 'PRIVATE' | :developer | true | true | 'process PyPI api request' | :created
+ 'PRIVATE' | :guest | true | true | 'process PyPI api request' | :forbidden
+ 'PRIVATE' | :developer | true | false | 'process PyPI api request' | :unauthorized
+ 'PRIVATE' | :guest | true | false | 'process PyPI api request' | :unauthorized
+ 'PRIVATE' | :developer | false | true | 'process PyPI api request' | :not_found
+ 'PRIVATE' | :guest | false | true | 'process PyPI api request' | :not_found
+ 'PRIVATE' | :developer | false | false | 'process PyPI api request' | :unauthorized
+ 'PRIVATE' | :guest | false | false | 'process PyPI api request' | :unauthorized
+ 'PRIVATE' | :anonymous | false | true | 'process PyPI api request' | :unauthorized
end
with_them do
@@ -185,7 +195,7 @@ RSpec.describe API::PypiPackages do
project.update!(visibility_level: Gitlab::VisibilityLevel::PRIVATE)
end
- it_behaves_like 'process PyPi api request', :developer, :bad_request, true
+ it_behaves_like 'process PyPI api request', :developer, :bad_request, true
end
context 'with an invalid package' do
@@ -232,24 +242,24 @@ RSpec.describe API::PypiPackages do
using RSpec::Parameterized::TableSyntax
where(:project_visibility_level, :user_role, :member, :user_token, :shared_examples_name, :expected_status) do
- 'PUBLIC' | :developer | true | true | 'PyPi package download' | :success
- 'PUBLIC' | :guest | true | true | 'PyPi package download' | :success
- 'PUBLIC' | :developer | true | false | 'PyPi package download' | :success
- 'PUBLIC' | :guest | true | false | 'PyPi package download' | :success
- 'PUBLIC' | :developer | false | true | 'PyPi package download' | :success
- 'PUBLIC' | :guest | false | true | 'PyPi package download' | :success
- 'PUBLIC' | :developer | false | false | 'PyPi package download' | :success
- 'PUBLIC' | :guest | false | false | 'PyPi package download' | :success
- 'PUBLIC' | :anonymous | false | true | 'PyPi package download' | :success
- 'PRIVATE' | :developer | true | true | 'PyPi package download' | :success
- 'PRIVATE' | :guest | true | true | 'PyPi package download' | :success
- 'PRIVATE' | :developer | true | false | 'PyPi package download' | :success
- 'PRIVATE' | :guest | true | false | 'PyPi package download' | :success
- 'PRIVATE' | :developer | false | true | 'PyPi package download' | :success
- 'PRIVATE' | :guest | false | true | 'PyPi package download' | :success
- 'PRIVATE' | :developer | false | false | 'PyPi package download' | :success
- 'PRIVATE' | :guest | false | false | 'PyPi package download' | :success
- 'PRIVATE' | :anonymous | false | true | 'PyPi package download' | :success
+ 'PUBLIC' | :developer | true | true | 'PyPI package download' | :success
+ 'PUBLIC' | :guest | true | true | 'PyPI package download' | :success
+ 'PUBLIC' | :developer | true | false | 'PyPI package download' | :success
+ 'PUBLIC' | :guest | true | false | 'PyPI package download' | :success
+ 'PUBLIC' | :developer | false | true | 'PyPI package download' | :success
+ 'PUBLIC' | :guest | false | true | 'PyPI package download' | :success
+ 'PUBLIC' | :developer | false | false | 'PyPI package download' | :success
+ 'PUBLIC' | :guest | false | false | 'PyPI package download' | :success
+ 'PUBLIC' | :anonymous | false | true | 'PyPI package download' | :success
+ 'PRIVATE' | :developer | true | true | 'PyPI package download' | :success
+ 'PRIVATE' | :guest | true | true | 'PyPI package download' | :success
+ 'PRIVATE' | :developer | true | false | 'PyPI package download' | :success
+ 'PRIVATE' | :guest | true | false | 'PyPI package download' | :success
+ 'PRIVATE' | :developer | false | true | 'PyPI package download' | :success
+ 'PRIVATE' | :guest | false | true | 'PyPI package download' | :success
+ 'PRIVATE' | :developer | false | false | 'PyPI package download' | :success
+ 'PRIVATE' | :guest | false | false | 'PyPI package download' | :success
+ 'PRIVATE' | :anonymous | false | true | 'PyPI package download' | :success
end
with_them do
diff --git a/spec/requests/api/releases_spec.rb b/spec/requests/api/releases_spec.rb
index 779ae983886..e78d05835f2 100644
--- a/spec/requests/api/releases_spec.rb
+++ b/spec/requests/api/releases_spec.rb
@@ -53,6 +53,49 @@ RSpec.describe API::Releases do
expect(json_response.second['tag_name']).to eq(release_1.tag)
end
+ RSpec.shared_examples 'release sorting' do |order_by|
+ subject { get api(url, access_level), params: { sort: sort, order_by: order_by } }
+
+ context "sorting by #{order_by}" do
+ context 'ascending order' do
+ let(:sort) { 'asc' }
+
+ it 'returns the sorted releases' do
+ subject
+
+ expect(json_response.map { |release| release['name'] }).to eq(releases.map(&:name))
+ end
+ end
+
+ context 'descending order' do
+ let(:sort) { 'desc' }
+
+ it 'returns the sorted releases' do
+ subject
+
+ expect(json_response.map { |release| release['name'] }).to eq(releases.reverse.map(&:name))
+ end
+ end
+ end
+ end
+
+ context 'return releases in sorted order' do
+ before do
+ release_2.update_attribute(:created_at, 3.days.ago)
+ end
+
+ let(:url) { "/projects/#{project.id}/releases" }
+ let(:access_level) { maintainer }
+
+ it_behaves_like 'release sorting', 'released_at' do
+ let(:releases) { [release_1, release_2] }
+ end
+
+ it_behaves_like 'release sorting', 'created_at' do
+ let(:releases) { [release_2, release_1] }
+ end
+ end
+
it 'matches response schema' do
get api("/projects/#{project.id}/releases", maintainer)
@@ -259,7 +302,7 @@ RSpec.describe API::Releases do
end
it '#collected_at' do
- Timecop.freeze(Time.now.round) do
+ travel_to(Time.now.round) do
get api("/projects/#{project.id}/releases/v0.1", maintainer)
expect(json_response['evidences'].first['collected_at'].to_datetime.to_i).to be_within(1.minute).of(release.evidences.first.created_at.to_i)
@@ -476,7 +519,7 @@ RSpec.describe API::Releases do
it 'sets the released_at to the current time if the released_at parameter is not provided' do
now = Time.zone.parse('2015-08-25 06:00:00Z')
- Timecop.freeze(now) do
+ travel_to(now) do
post api("/projects/#{project.id}/releases", maintainer), params: params
expect(project.releases.last.released_at).to eq(now)
@@ -598,7 +641,7 @@ RSpec.describe API::Releases do
end
end
- context 'when create two assets' do
+ context 'when creating two assets' do
let(:params) do
base_params.merge({
assets: {
@@ -758,6 +801,65 @@ RSpec.describe API::Releases do
expect(response).to have_gitlab_http_status(:conflict)
end
end
+
+ context 'with milestones' do
+ let(:subject) { post api("/projects/#{project.id}/releases", maintainer), params: params }
+ let(:milestone) { create(:milestone, project: project, title: 'v1.0') }
+ let(:returned_milestones) { json_response['milestones'].map {|m| m['title']} }
+
+ before do
+ params.merge!(milestone_params)
+
+ subject
+ end
+
+ context 'with a project milestone' do
+ let(:milestone_params) { { milestones: [milestone.title] } }
+
+ it 'adds the milestone' do
+ expect(response).to have_gitlab_http_status(:created)
+ expect(returned_milestones).to match_array(['v1.0'])
+ end
+ end
+
+ context 'with multiple milestones' do
+ let(:milestone2) { create(:milestone, project: project, title: 'm2') }
+ let(:milestone_params) { { milestones: [milestone.title, milestone2.title] } }
+
+ it 'adds all milestones' do
+ expect(response).to have_gitlab_http_status(:created)
+ expect(returned_milestones).to match_array(['v1.0', 'm2'])
+ end
+ end
+
+ context 'with an empty milestone' do
+ let(:milestone_params) { { milestones: [] } }
+
+ it 'removes all milestones' do
+ expect(response).to have_gitlab_http_status(:created)
+ expect(json_response['milestones']).to be_nil
+ end
+ end
+
+ context 'with a non-existant milestone' do
+ let(:milestone_params) { { milestones: ['xyz'] } }
+
+ it 'returns a 400 error as milestone not found' do
+ expect(response).to have_gitlab_http_status(:bad_request)
+ expect(json_response['message']).to eq("Milestone(s) not found: xyz")
+ end
+ end
+
+ context 'with a milestone from a different project' do
+ let(:milestone) { create(:milestone, title: 'v1.0') }
+ let(:milestone_params) { { milestones: [milestone.title] } }
+
+ it 'returns a 400 error as milestone not found' do
+ expect(response).to have_gitlab_http_status(:bad_request)
+ expect(json_response['message']).to eq("Milestone(s) not found: v1.0")
+ end
+ end
+ end
end
describe 'PUT /projects/:id/releases/:tag_name' do
@@ -863,6 +965,83 @@ RSpec.describe API::Releases do
end
end
end
+
+ context 'with milestones' do
+ let(:returned_milestones) { json_response['milestones'].map {|m| m['title']} }
+
+ subject { put api("/projects/#{project.id}/releases/v0.1", maintainer), params: params }
+
+ context 'when a milestone is passed in' do
+ let(:milestone) { create(:milestone, project: project, title: 'v1.0') }
+ let(:milestone_title) { milestone.title }
+ let(:params) { { milestones: [milestone_title] } }
+
+ before do
+ release.milestones << milestone
+ end
+
+ context 'a different milestone' do
+ let(:milestone_title) { 'v2.0' }
+ let!(:milestone2) { create(:milestone, project: project, title: milestone_title) }
+
+ it 'replaces the milestone' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(returned_milestones).to match_array(['v2.0'])
+ end
+ end
+
+ context 'an identical milestone' do
+ let(:milestone_title) { 'v1.0' }
+
+ it 'does not change the milestone' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(returned_milestones).to match_array(['v1.0'])
+ end
+ end
+
+ context 'an empty milestone' do
+ let(:milestone_title) { nil }
+
+ it 'removes the milestone' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['milestones']).to be_nil
+ end
+ end
+
+ context 'multiple milestones' do
+ context 'with one new' do
+ let!(:milestone2) { create(:milestone, project: project, title: 'milestone2') }
+ let(:params) { { milestones: [milestone.title, milestone2.title] } }
+
+ it 'adds the new milestone' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(returned_milestones).to match_array(['v1.0', 'milestone2'])
+ end
+ end
+
+ context 'with all new' do
+ let!(:milestone2) { create(:milestone, project: project, title: 'milestone2') }
+ let!(:milestone3) { create(:milestone, project: project, title: 'milestone3') }
+ let(:params) { { milestones: [milestone2.title, milestone3.title] } }
+
+ it 'replaces the milestones' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(returned_milestones).to match_array(%w(milestone2 milestone3))
+ end
+ end
+ end
+ end
+ end
end
describe 'DELETE /projects/:id/releases/:tag_name' do
diff --git a/spec/requests/api/repositories_spec.rb b/spec/requests/api/repositories_spec.rb
index 36707f32d04..45bce8c8a5c 100644
--- a/spec/requests/api/repositories_spec.rb
+++ b/spec/requests/api/repositories_spec.rb
@@ -402,7 +402,9 @@ RSpec.describe API::Repositories do
end
it "returns an empty string when the diff overflows" do
- stub_const('Gitlab::Git::DiffCollection::DEFAULT_LIMITS', { max_files: 2, max_lines: 2 })
+ allow(Gitlab::Git::DiffCollection)
+ .to receive(:default_limits)
+ .and_return({ max_files: 2, max_lines: 2 })
get api(route, current_user), params: { from: 'master', to: 'feature' }
diff --git a/spec/requests/api/search_spec.rb b/spec/requests/api/search_spec.rb
index af6731f3015..05cfad9cc62 100644
--- a/spec/requests/api/search_spec.rb
+++ b/spec/requests/api/search_spec.rb
@@ -58,6 +58,17 @@ RSpec.describe API::Search do
end
end
+ shared_examples 'filter by confidentiality' do |scope:, search:|
+ it 'respects confidentiality filtering' do
+ get api(endpoint, user), params: { scope: scope, search: search, confidential: confidential.to_s }
+
+ documents = Gitlab::Json.parse(response.body)
+
+ expect(documents.count).to eq(1)
+ expect(documents.first['confidential']).to eq(confidential)
+ end
+ end
+
describe 'GET /search' do
let(:endpoint) { '/search' }
@@ -137,6 +148,26 @@ RSpec.describe API::Search do
include_examples 'filter by state', scope: :issues, search: 'awesome'
end
end
+
+ context 'filter by confidentiality' do
+ before do
+ stub_feature_flags(search_filter_by_confidential: true)
+ create(:issue, project: project, author: user, title: 'awesome non-confidential issue')
+ create(:issue, :confidential, project: project, author: user, title: 'awesome confidential issue')
+ end
+
+ context 'confidential: true' do
+ let(:confidential) { true }
+
+ include_examples 'filter by confidentiality', scope: :issues, search: 'awesome'
+ end
+
+ context 'confidential: false' do
+ let(:confidential) { false }
+
+ include_examples 'filter by confidentiality', scope: :issues, search: 'awesome'
+ end
+ end
end
context 'for merge_requests scope' do
@@ -231,18 +262,6 @@ RSpec.describe API::Search do
it_behaves_like 'pagination', scope: :users
it_behaves_like 'ping counters', scope: :users
-
- context 'when users search feature is disabled' do
- before do
- stub_feature_flags(users_search: false)
-
- get api(endpoint, user), params: { scope: 'users', search: 'billy' }
- end
-
- it 'returns 400 error' do
- expect(response).to have_gitlab_http_status(:bad_request)
- end
- end
end
context 'for snippet_titles scope' do
@@ -416,18 +435,6 @@ RSpec.describe API::Search do
include_examples 'pagination', scope: :users
end
-
- context 'when users search feature is disabled' do
- before do
- stub_feature_flags(users_search: false)
-
- get api(endpoint, user), params: { scope: 'users', search: 'billy' }
- end
-
- it 'returns 400 error' do
- expect(response).to have_gitlab_http_status(:bad_request)
- end
- end
end
context 'for users scope with group path as id' do
@@ -589,18 +596,6 @@ RSpec.describe API::Search do
include_examples 'pagination', scope: :users
end
-
- context 'when users search feature is disabled' do
- before do
- stub_feature_flags(users_search: false)
-
- get api(endpoint, user), params: { scope: 'users', search: 'billy' }
- end
-
- it 'returns 400 error' do
- expect(response).to have_gitlab_http_status(:bad_request)
- end
- end
end
context 'for notes scope' do
diff --git a/spec/requests/api/services_spec.rb b/spec/requests/api/services_spec.rb
index 5528a0c094f..63ed57c5045 100644
--- a/spec/requests/api/services_spec.rb
+++ b/spec/requests/api/services_spec.rb
@@ -264,4 +264,34 @@ RSpec.describe API::Services do
expect(json_response['properties']['notify_only_broken_pipelines']).to eq(true)
end
end
+
+ describe 'Hangouts Chat service' do
+ let(:service_name) { 'hangouts-chat' }
+ let(:params) do
+ {
+ webhook: 'https://hook.example.com',
+ branches_to_be_notified: 'default'
+ }
+ end
+
+ before do
+ project.create_hangouts_chat_service(
+ active: true,
+ properties: params
+ )
+ end
+
+ it 'accepts branches_to_be_notified for update', :aggregate_failures do
+ put api("/projects/#{project.id}/services/#{service_name}", user), params: params.merge(branches_to_be_notified: 'all')
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['properties']['branches_to_be_notified']).to eq('all')
+ end
+
+ it 'only requires the webhook param' do
+ put api("/projects/#{project.id}/services/#{service_name}", user), params: { webhook: 'https://hook.example.com' }
+
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+ end
end
diff --git a/spec/requests/api/settings_spec.rb b/spec/requests/api/settings_spec.rb
index ef12f6dbed3..8b5f74df8f8 100644
--- a/spec/requests/api/settings_spec.rb
+++ b/spec/requests/api/settings_spec.rb
@@ -96,6 +96,7 @@ RSpec.describe API::Settings, 'Settings' do
help_page_text: 'custom help text',
help_page_hide_commercial_content: true,
help_page_support_url: 'http://example.com/help',
+ help_page_documentation_base_url: 'https://docs.gitlab.com',
project_export_enabled: false,
rsa_key_restriction: ApplicationSetting::FORBIDDEN_KEY_VALUE,
dsa_key_restriction: 2048,
@@ -138,6 +139,7 @@ RSpec.describe API::Settings, 'Settings' do
expect(json_response['help_page_text']).to eq('custom help text')
expect(json_response['help_page_hide_commercial_content']).to be_truthy
expect(json_response['help_page_support_url']).to eq('http://example.com/help')
+ expect(json_response['help_page_documentation_base_url']).to eq('https://docs.gitlab.com')
expect(json_response['project_export_enabled']).to be_falsey
expect(json_response['rsa_key_restriction']).to eq(ApplicationSetting::FORBIDDEN_KEY_VALUE)
expect(json_response['dsa_key_restriction']).to eq(2048)
@@ -413,6 +415,14 @@ RSpec.describe API::Settings, 'Settings' do
end
end
+ it 'supports legacy admin_notification_email' do
+ put api('/application/settings', admin),
+ params: { admin_notification_email: 'test@example.com' }
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['abuse_notification_email']).to eq('test@example.com')
+ end
+
context "missing sourcegraph_url value when sourcegraph_enabled is true" do
it "returns a blank parameter error message" do
put api("/application/settings", admin), params: { sourcegraph_enabled: true }
diff --git a/spec/requests/api/snippets_spec.rb b/spec/requests/api/snippets_spec.rb
index 8d77026d26c..227c53f8fb9 100644
--- a/spec/requests/api/snippets_spec.rb
+++ b/spec/requests/api/snippets_spec.rb
@@ -2,18 +2,28 @@
require 'spec_helper'
-RSpec.describe API::Snippets do
+RSpec.describe API::Snippets, factory_default: :keep do
include SnippetHelpers
- let_it_be(:user) { create(:user) }
+ let_it_be(:admin) { create(:user, :admin) }
+ let_it_be(:user) { create(:user) }
+ let_it_be(:other_user) { create(:user) }
- describe 'GET /snippets/' do
- it 'returns snippets available' do
- public_snippet = create(:personal_snippet, :repository, :public, author: user)
- private_snippet = create(:personal_snippet, :repository, :private, author: user)
- internal_snippet = create(:personal_snippet, :repository, :internal, author: user)
+ let_it_be(:public_snippet) { create(:personal_snippet, :repository, :public, author: user) }
+ let_it_be(:private_snippet) { create(:personal_snippet, :repository, :private, author: user) }
+ let_it_be(:internal_snippet) { create(:personal_snippet, :repository, :internal, author: user) }
+
+ let_it_be(:user_token) { create(:personal_access_token, user: user) }
+ let_it_be(:other_user_token) { create(:personal_access_token, user: other_user) }
+ let_it_be(:project) do
+ create_default(:project, :public).tap do |p|
+ p.add_maintainer(user)
+ end
+ end
- get api("/snippets/", user)
+ describe 'GET /snippets/' do
+ it 'returns snippets available for user' do
+ get api("/snippets/", personal_access_token: user_token)
expect(response).to have_gitlab_http_status(:ok)
expect(response).to include_pagination_headers
@@ -29,9 +39,7 @@ RSpec.describe API::Snippets do
end
it 'hides private snippets from regular user' do
- create(:personal_snippet, :private)
-
- get api("/snippets/", user)
+ get api("/snippets/", personal_access_token: other_user_token)
expect(response).to have_gitlab_http_status(:ok)
expect(response).to include_pagination_headers
@@ -39,21 +47,17 @@ RSpec.describe API::Snippets do
expect(json_response.size).to eq(0)
end
- it 'returns 404 for non-authenticated' do
- create(:personal_snippet, :internal)
-
+ it 'returns 401 for non-authenticated' do
get api("/snippets/")
expect(response).to have_gitlab_http_status(:unauthorized)
end
it 'does not return snippets related to a project with disable feature visibility' do
- project = create(:project)
- create(:project_member, project: project, user: user)
- public_snippet = create(:personal_snippet, :public, author: user, project: project)
+ public_snippet = create(:project_snippet, :public, author: user, project: project)
project.project_feature.update_attribute(:snippets_access_level, 0)
- get api("/snippets/", user)
+ get api("/snippets/", personal_access_token: user_token)
json_response.each do |snippet|
expect(snippet["id"]).not_to eq(public_snippet.id)
@@ -62,10 +66,6 @@ RSpec.describe API::Snippets do
end
describe 'GET /snippets/public' do
- let_it_be(:other_user) { create(:user) }
- let_it_be(:public_snippet) { create(:personal_snippet, :repository, :public, author: user) }
- let_it_be(:private_snippet) { create(:personal_snippet, :repository, :private, author: user) }
- let_it_be(:internal_snippet) { create(:personal_snippet, :repository, :internal, author: user) }
let_it_be(:public_snippet_other) { create(:personal_snippet, :repository, :public, author: other_user) }
let_it_be(:private_snippet_other) { create(:personal_snippet, :repository, :private, author: other_user) }
let_it_be(:internal_snippet_other) { create(:personal_snippet, :repository, :internal, author: other_user) }
@@ -73,8 +73,10 @@ RSpec.describe API::Snippets do
let_it_be(:private_snippet_project) { create(:project_snippet, :repository, :private, author: user) }
let_it_be(:internal_snippet_project) { create(:project_snippet, :repository, :internal, author: user) }
- it 'returns all snippets with public visibility from all users' do
- get api("/snippets/public", user)
+ let(:path) { "/snippets/public" }
+
+ it 'returns only public snippets from all users when authenticated' do
+ get api(path, personal_access_token: user_token)
aggregate_failures do
expect(response).to have_gitlab_http_status(:ok)
@@ -90,20 +92,23 @@ RSpec.describe API::Snippets do
expect(json_response[1]['files'].first).to eq snippet_blob_file(public_snippet.blobs.first)
end
end
- end
-
- describe 'GET /snippets/:id/raw' do
- let_it_be(:author) { create(:user) }
- let_it_be(:snippet) { create(:personal_snippet, :repository, :private, author: author) }
it 'requires authentication' do
- get api("/snippets/#{snippet.id}", nil)
+ get api(path, nil)
expect(response).to have_gitlab_http_status(:unauthorized)
end
+ end
+
+ describe 'GET /snippets/:id/raw' do
+ let(:snippet) { private_snippet }
+
+ it_behaves_like 'snippet access with different users' do
+ let(:path) { "/snippets/#{snippet.id}/raw" }
+ end
it 'returns raw text' do
- get api("/snippets/#{snippet.id}/raw", author)
+ get api("/snippets/#{snippet.id}/raw", personal_access_token: user_token)
expect(response).to have_gitlab_http_status(:ok)
expect(response.media_type).to eq 'text/plain'
@@ -113,69 +118,37 @@ RSpec.describe API::Snippets do
it 'returns 404 for invalid snippet id' do
snippet.destroy!
- get api("/snippets/#{snippet.id}/raw", author)
+ get api("/snippets/#{snippet.id}/raw", personal_access_token: user_token)
expect(response).to have_gitlab_http_status(:not_found)
expect(json_response['message']).to eq('404 Snippet Not Found')
end
- it 'hides private snippets from ordinary users' do
- get api("/snippets/#{snippet.id}/raw", user)
-
- expect(response).to have_gitlab_http_status(:not_found)
- end
-
- it 'shows internal snippets to ordinary users' do
- internal_snippet = create(:personal_snippet, :internal, author: author)
-
- get api("/snippets/#{internal_snippet.id}/raw", user)
-
- expect(response).to have_gitlab_http_status(:ok)
- end
-
it_behaves_like 'snippet blob content' do
- let_it_be(:snippet_with_empty_repo) { create(:personal_snippet, :empty_repo, :private, author: author) }
+ let_it_be(:snippet_with_empty_repo) { create(:personal_snippet, :empty_repo, :private, author: user) }
- subject { get api("/snippets/#{snippet.id}/raw", snippet.author) }
+ subject { get api("/snippets/#{snippet.id}/raw", snippet.author, personal_access_token: user_token) }
end
end
describe 'GET /snippets/:id/files/:ref/:file_path/raw' do
- let_it_be(:snippet) { create(:personal_snippet, :repository, :private) }
+ let_it_be(:snippet) { private_snippet }
it_behaves_like 'raw snippet files' do
let(:api_path) { "/snippets/#{snippet_id}/files/#{ref}/#{file_path}/raw" }
end
- end
-
- describe 'GET /snippets/:id' do
- let_it_be(:admin) { create(:user, :admin) }
- let_it_be(:author) { create(:user) }
- let_it_be(:private_snippet) { create(:personal_snippet, :repository, :private, author: author) }
- let_it_be(:internal_snippet) { create(:personal_snippet, :repository, :internal, author: author) }
- let(:snippet) { private_snippet }
- subject { get api("/snippets/#{snippet.id}", user) }
-
- it 'hides private snippets from an ordinary user' do
- subject
-
- expect(response).to have_gitlab_http_status(:not_found)
+ it_behaves_like 'snippet access with different users' do
+ let(:path) { "/snippets/#{snippet.id}/files/master/%2Egitattributes/raw" }
end
+ end
- context 'without a user' do
- let(:user) { nil }
+ describe 'GET /snippets/:id' do
+ let(:snippet_id) { private_snippet.id }
- it 'requires authentication' do
- subject
-
- expect(response).to have_gitlab_http_status(:unauthorized)
- end
- end
+ subject { get api("/snippets/#{snippet_id}", personal_access_token: user_token) }
context 'with the author' do
- let(:user) { author }
-
it 'returns snippet json' do
subject
@@ -191,18 +164,10 @@ RSpec.describe API::Snippets do
end
end
- context 'with an admin' do
- let(:user) { admin }
-
- it 'shows private snippets to an admin' do
- subject
-
- expect(response).to have_gitlab_http_status(:ok)
- end
-
- it 'returns 404 for invalid snippet id' do
- private_snippet.destroy!
+ context 'with a non-existent snippet ID' do
+ let(:snippet_id) { 0 }
+ it 'returns 404' do
subject
expect(response).to have_gitlab_http_status(:not_found)
@@ -210,18 +175,8 @@ RSpec.describe API::Snippets do
end
end
- context 'with an internal snippet' do
- let(:snippet) { internal_snippet }
-
- it 'shows internal snippets to an ordinary user' do
- subject
-
- expect(response).to have_gitlab_http_status(:ok)
- end
- end
-
- it_behaves_like 'snippet_multiple_files feature disabled' do
- let(:user) { author }
+ it_behaves_like 'snippet access with different users' do
+ let(:path) { "/snippets/#{snippet.id}" }
end
end
@@ -241,7 +196,7 @@ RSpec.describe API::Snippets do
let(:file_params) { { files: [{ file_path: file_path, content: file_content }] } }
let(:extra_params) { {} }
- subject { post api("/snippets/", user), params: params }
+ subject { post api("/snippets/", personal_access_token: user_token), params: params }
shared_examples 'snippet creation' do
let(:snippet) { Snippet.find(json_response["id"]) }
@@ -305,12 +260,9 @@ RSpec.describe API::Snippets do
it_behaves_like 'snippet creation'
- it_behaves_like 'snippet_multiple_files feature disabled' do
- let(:snippet) { Snippet.find(json_response["id"]) }
- end
-
context 'with an external user' do
let(:user) { create(:user, :external) }
+ let(:user_token) { create(:personal_access_token, user: user) }
it 'does not create a new snippet' do
subject
@@ -384,8 +336,6 @@ RSpec.describe API::Snippets do
end
describe 'PUT /snippets/:id' do
- let_it_be(:other_user) { create(:user) }
-
let(:visibility_level) { Snippet::PUBLIC }
let(:snippet) do
create(:personal_snippet, :repository, author: user, visibility_level: visibility_level)
@@ -465,11 +415,10 @@ RSpec.describe API::Snippets do
end
context "when admin" do
- let(:admin) { create(:admin) }
- let(:token) { create(:personal_access_token, user: admin, scopes: [:sudo]) }
+ let_it_be(:token) { create(:personal_access_token, user: admin, scopes: [:sudo]) }
subject do
- put api("/snippets/#{snippet.id}", admin, personal_access_token: token), params: { visibility: 'private', sudo: user.id }
+ put api("/snippets/#{snippet.id}", personal_access_token: token), params: { visibility: 'private', sudo: user.id }
end
context 'when sudo is defined' do
@@ -496,34 +445,32 @@ RSpec.describe API::Snippets do
end
describe 'DELETE /snippets/:id' do
- let!(:public_snippet) { create(:personal_snippet, :public, author: user) }
-
it 'deletes snippet' do
expect do
- delete api("/snippets/#{public_snippet.id}", user)
+ delete api("/snippets/#{public_snippet.id}", personal_access_token: user_token)
expect(response).to have_gitlab_http_status(:no_content)
end.to change { PersonalSnippet.count }.by(-1)
end
it 'returns 404 for invalid snippet id' do
- delete api("/snippets/#{non_existing_record_id}", user)
+ delete api("/snippets/#{non_existing_record_id}", personal_access_token: user_token)
expect(response).to have_gitlab_http_status(:not_found)
expect(json_response['message']).to eq('404 Snippet Not Found')
end
it_behaves_like '412 response' do
- let(:request) { api("/snippets/#{public_snippet.id}", user) }
+ let(:request) { api("/snippets/#{public_snippet.id}", personal_access_token: user_token) }
end
end
describe "GET /snippets/:id/user_agent_detail" do
- let(:admin) { create(:admin) }
- let(:snippet) { create(:personal_snippet, :public, author: user) }
- let!(:user_agent_detail) { create(:user_agent_detail, subject: snippet) }
+ let(:snippet) { public_snippet }
it 'exposes known attributes' do
+ user_agent_detail = create(:user_agent_detail, subject: snippet)
+
get api("/snippets/#{snippet.id}/user_agent_detail", admin)
expect(response).to have_gitlab_http_status(:ok)
diff --git a/spec/requests/api/terraform/state_spec.rb b/spec/requests/api/terraform/state_spec.rb
index 8d128bd911f..aff41ff5974 100644
--- a/spec/requests/api/terraform/state_spec.rb
+++ b/spec/requests/api/terraform/state_spec.rb
@@ -18,7 +18,7 @@ RSpec.describe API::Terraform::State do
let(:state_path) { "/projects/#{project_id}/terraform/state/#{state_name}" }
before do
- stub_terraform_state_object_storage(Terraform::StateUploader)
+ stub_terraform_state_object_storage
end
describe 'GET /projects/:id/terraform/state/:name' do
diff --git a/spec/requests/api/terraform/state_version_spec.rb b/spec/requests/api/terraform/state_version_spec.rb
new file mode 100644
index 00000000000..ade0aacf805
--- /dev/null
+++ b/spec/requests/api/terraform/state_version_spec.rb
@@ -0,0 +1,210 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe API::Terraform::StateVersion do
+ include HttpBasicAuthHelpers
+
+ let_it_be(:project) { create(:project) }
+ let_it_be(:developer) { create(:user, developer_projects: [project]) }
+ let_it_be(:maintainer) { create(:user, maintainer_projects: [project]) }
+ let_it_be(:user_without_access) { create(:user) }
+
+ let_it_be(:state) { create(:terraform_state, project: project) }
+
+ let!(:versions) { create_list(:terraform_state_version, 3, terraform_state: state) }
+
+ let(:current_user) { maintainer }
+ let(:auth_header) { user_basic_auth_header(current_user) }
+ let(:project_id) { project.id }
+ let(:state_name) { state.name }
+ let(:version) { versions.last }
+ let(:version_serial) { version.version }
+ let(:state_version_path) { "/projects/#{project_id}/terraform/state/#{state_name}/versions/#{version_serial}" }
+
+ describe 'GET /projects/:id/terraform/state/:name/versions/:serial' do
+ subject(:request) { get api(state_version_path), headers: auth_header }
+
+ context 'with invalid authentication' do
+ let(:auth_header) { basic_auth_header('bad', 'token') }
+
+ it 'returns unauthorized status' do
+ request
+
+ expect(response).to have_gitlab_http_status(:unauthorized)
+ end
+ end
+
+ context 'with no authentication' do
+ let(:auth_header) { nil }
+
+ it 'returns unauthorized status' do
+ request
+
+ expect(response).to have_gitlab_http_status(:unauthorized)
+ end
+ end
+
+ context 'personal acceess token authentication' do
+ context 'with maintainer permissions' do
+ let(:current_user) { maintainer }
+
+ it 'returns the state contents at the given version' do
+ request
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response.body).to eq(version.file.read)
+ end
+
+ context 'for a project that does not exist' do
+ let(:project_id) { '0000' }
+
+ it 'returns not found status' do
+ request
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+ end
+
+ context 'with developer permissions' do
+ let(:current_user) { developer }
+
+ it 'returns the state contents at the given version' do
+ request
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response.body).to eq(version.file.read)
+ end
+ end
+
+ context 'with no permissions' do
+ let(:current_user) { user_without_access }
+
+ it 'returns not found status' do
+ request
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+ end
+
+ context 'job token authentication' do
+ let(:auth_header) { job_basic_auth_header(job) }
+
+ context 'with maintainer permissions' do
+ let(:job) { create(:ci_build, status: :running, project: project, user: maintainer) }
+
+ it 'returns the state contents at the given version' do
+ request
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response.body).to eq(version.file.read)
+ end
+
+ it 'returns unauthorized status if the the job is not running' do
+ job.update!(status: :failed)
+ request
+
+ expect(response).to have_gitlab_http_status(:unauthorized)
+ end
+
+ context 'for a project that does not exist' do
+ let(:project_id) { '0000' }
+
+ it 'returns not found status' do
+ request
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+ end
+
+ context 'with developer permissions' do
+ let(:job) { create(:ci_build, status: :running, project: project, user: developer) }
+
+ it 'returns the state contents at the given version' do
+ request
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response.body).to eq(version.file.read)
+ end
+ end
+
+ context 'with no permissions' do
+ let(:current_user) { user_without_access }
+ let(:job) { create(:ci_build, status: :running, user: current_user) }
+
+ it 'returns not found status' do
+ request
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+ end
+ end
+
+ describe 'DELETE /projects/:id/terraform/state/:name/versions/:serial' do
+ subject(:request) { delete api(state_version_path), headers: auth_header }
+
+ context 'with invalid authentication' do
+ let(:auth_header) { basic_auth_header('bad', 'token') }
+
+ it 'returns unauthorized status' do
+ request
+
+ expect(response).to have_gitlab_http_status(:unauthorized)
+ end
+ end
+
+ context 'with no authentication' do
+ let(:auth_header) { nil }
+
+ it 'returns unauthorized status' do
+ request
+
+ expect(response).to have_gitlab_http_status(:unauthorized)
+ end
+ end
+
+ context 'with maintainer permissions' do
+ let(:current_user) { maintainer }
+
+ it 'deletes the version' do
+ expect { request }.to change { Terraform::StateVersion.count }.by(-1)
+
+ expect(response).to have_gitlab_http_status(:no_content)
+ end
+
+ context 'version does not exist' do
+ let(:version_serial) { -1 }
+
+ it 'does not delete a version' do
+ expect { request }.to change { Terraform::StateVersion.count }.by(0)
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+ end
+
+ context 'with developer permissions' do
+ let(:current_user) { developer }
+
+ it 'returns forbidden status' do
+ expect { request }.to change { Terraform::StateVersion.count }.by(0)
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ end
+ end
+
+ context 'with no permissions' do
+ let(:current_user) { user_without_access }
+
+ it 'returns not found status' do
+ expect { request }.to change { Terraform::StateVersion.count }.by(0)
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+ end
+end
diff --git a/spec/requests/api/unleash_spec.rb b/spec/requests/api/unleash_spec.rb
new file mode 100644
index 00000000000..0b70d62b093
--- /dev/null
+++ b/spec/requests/api/unleash_spec.rb
@@ -0,0 +1,608 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe API::Unleash do
+ include FeatureFlagHelpers
+
+ let_it_be(:project, refind: true) { create(:project) }
+ let(:project_id) { project.id }
+ let(:params) { }
+ let(:headers) { }
+
+ shared_examples 'authenticated request' do
+ context 'when using instance id' do
+ let(:client) { create(:operations_feature_flags_client, project: project) }
+ let(:params) { { instance_id: client.token } }
+
+ it 'responds with OK' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+
+ context 'when repository is disabled' do
+ before do
+ project.project_feature.update!(
+ repository_access_level: ::ProjectFeature::DISABLED,
+ merge_requests_access_level: ::ProjectFeature::DISABLED,
+ builds_access_level: ::ProjectFeature::DISABLED
+ )
+ end
+
+ it 'responds with forbidden' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+ end
+
+ context 'when repository is private' do
+ before do
+ project.project_feature.update!(
+ repository_access_level: ::ProjectFeature::PRIVATE,
+ merge_requests_access_level: ::ProjectFeature::DISABLED,
+ builds_access_level: ::ProjectFeature::DISABLED
+ )
+ end
+
+ it 'responds with OK' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+ end
+ end
+
+ context 'when using header' do
+ let(:client) { create(:operations_feature_flags_client, project: project) }
+ let(:headers) { { "UNLEASH-INSTANCEID" => client.token }}
+
+ it 'responds with OK' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+ end
+
+ context 'when using bogus instance id' do
+ let(:params) { { instance_id: 'token' } }
+
+ it 'responds with unauthorized' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:unauthorized)
+ end
+ end
+
+ context 'when using not existing project' do
+ let(:project_id) { -5000 }
+ let(:params) { { instance_id: 'token' } }
+
+ it 'responds with unauthorized' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:unauthorized)
+ end
+ end
+ end
+
+ shared_examples_for 'support multiple environments' do
+ let!(:client) { create(:operations_feature_flags_client, project: project) }
+ let!(:base_headers) { { "UNLEASH-INSTANCEID" => client.token } }
+ let!(:headers) { base_headers.merge({ "UNLEASH-APPNAME" => "test" }) }
+
+ let!(:feature_flag_1) do
+ create(:operations_feature_flag, name: "feature_flag_1", project: project, active: true)
+ end
+
+ let!(:feature_flag_2) do
+ create(:operations_feature_flag, name: "feature_flag_2", project: project, active: false)
+ end
+
+ before do
+ create_scope(feature_flag_1, 'production', false)
+ create_scope(feature_flag_2, 'review/*', true)
+ end
+
+ it 'does not have N+1 problem' do
+ control_count = ActiveRecord::QueryRecorder.new { get api(features_url), headers: headers }.count
+
+ create(:operations_feature_flag, name: "feature_flag_3", project: project, active: true)
+
+ expect { get api(features_url), headers: headers }.not_to exceed_query_limit(control_count)
+ end
+
+ context 'when app name is staging' do
+ let(:headers) { base_headers.merge({ "UNLEASH-APPNAME" => "staging" }) }
+
+ it 'returns correct active values' do
+ subject
+
+ feature_flag_1 = json_response['features'].find { |f| f['name'] == 'feature_flag_1' }
+ feature_flag_2 = json_response['features'].find { |f| f['name'] == 'feature_flag_2' }
+
+ expect(feature_flag_1['enabled']).to eq(true)
+ expect(feature_flag_2['enabled']).to eq(false)
+ end
+ end
+
+ context 'when app name is production' do
+ let(:headers) { base_headers.merge({ "UNLEASH-APPNAME" => "production" }) }
+
+ it 'returns correct active values' do
+ subject
+
+ feature_flag_1 = json_response['features'].find { |f| f['name'] == 'feature_flag_1' }
+ feature_flag_2 = json_response['features'].find { |f| f['name'] == 'feature_flag_2' }
+
+ expect(feature_flag_1['enabled']).to eq(false)
+ expect(feature_flag_2['enabled']).to eq(false)
+ end
+ end
+
+ context 'when app name is review/patch-1' do
+ let(:headers) { base_headers.merge({ "UNLEASH-APPNAME" => "review/patch-1" }) }
+
+ it 'returns correct active values' do
+ subject
+
+ feature_flag_1 = json_response['features'].find { |f| f['name'] == 'feature_flag_1' }
+ feature_flag_2 = json_response['features'].find { |f| f['name'] == 'feature_flag_2' }
+
+ expect(feature_flag_1['enabled']).to eq(true)
+ expect(feature_flag_2['enabled']).to eq(false)
+ end
+ end
+
+ context 'when app name is empty' do
+ let(:headers) { base_headers }
+
+ it 'returns empty list' do
+ subject
+
+ expect(json_response['features'].count).to eq(0)
+ end
+ end
+ end
+
+ %w(/feature_flags/unleash/:project_id/features /feature_flags/unleash/:project_id/client/features).each do |features_endpoint|
+ describe "GET #{features_endpoint}" do
+ let(:features_url) { features_endpoint.sub(':project_id', project_id.to_s) }
+ let(:client) { create(:operations_feature_flags_client, project: project) }
+
+ subject { get api(features_url), params: params, headers: headers }
+
+ it_behaves_like 'authenticated request'
+
+ context 'with version 1 (legacy) feature flags' do
+ let(:feature_flag) { create(:operations_feature_flag, project: project, name: 'feature1', active: true, version: 1) }
+
+ it_behaves_like 'support multiple environments'
+
+ context 'with a list of feature flags' do
+ let(:headers) { { "UNLEASH-INSTANCEID" => client.token, "UNLEASH-APPNAME" => "production" } }
+ let!(:enabled_feature_flag) { create(:operations_feature_flag, project: project, name: 'feature1', active: true, version: 1) }
+ let!(:disabled_feature_flag) { create(:operations_feature_flag, project: project, name: 'feature2', active: false, version: 1) }
+
+ it 'responds with a list of features' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['version']).to eq(1)
+ expect(json_response['features']).not_to be_empty
+ expect(json_response['features'].map { |f| f['name'] }.sort).to eq(%w[feature1 feature2])
+ expect(json_response['features'].sort_by {|f| f['name'] }.map { |f| f['enabled'] }).to eq([true, false])
+ end
+
+ it 'matches json schema' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to match_response_schema('unleash/unleash')
+ end
+ end
+
+ it 'returns a feature flag strategy' do
+ create(:operations_feature_flag_scope,
+ feature_flag: feature_flag,
+ environment_scope: 'sandbox',
+ active: true,
+ strategies: [{ name: "gradualRolloutUserId",
+ parameters: { groupId: "default", percentage: "50" } }])
+ headers = { "UNLEASH-INSTANCEID" => client.token, "UNLEASH-APPNAME" => "sandbox" }
+
+ get api(features_url), headers: headers
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['features'].first['enabled']).to eq(true)
+ strategies = json_response['features'].first['strategies']
+ expect(strategies).to eq([{
+ "name" => "gradualRolloutUserId",
+ "parameters" => {
+ "percentage" => "50",
+ "groupId" => "default"
+ }
+ }])
+ end
+
+ it 'returns a default strategy for a scope' do
+ create(:operations_feature_flag_scope, feature_flag: feature_flag, environment_scope: 'sandbox', active: true)
+ headers = { "UNLEASH-INSTANCEID" => client.token, "UNLEASH-APPNAME" => "sandbox" }
+
+ get api(features_url), headers: headers
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['features'].first['enabled']).to eq(true)
+ strategies = json_response['features'].first['strategies']
+ expect(strategies).to eq([{ "name" => "default", "parameters" => {} }])
+ end
+
+ it 'returns multiple strategies for a feature flag' do
+ create(:operations_feature_flag_scope,
+ feature_flag: feature_flag,
+ environment_scope: 'staging',
+ active: true,
+ strategies: [{ name: "userWithId", parameters: { userIds: "max,fred" } },
+ { name: "gradualRolloutUserId",
+ parameters: { groupId: "default", percentage: "50" } }])
+ headers = { "UNLEASH-INSTANCEID" => client.token, "UNLEASH-APPNAME" => "staging" }
+
+ get api(features_url), headers: headers
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['features'].first['enabled']).to eq(true)
+ strategies = json_response['features'].first['strategies'].sort_by { |s| s['name'] }
+ expect(strategies).to eq([{
+ "name" => "gradualRolloutUserId",
+ "parameters" => {
+ "percentage" => "50",
+ "groupId" => "default"
+ }
+ }, {
+ "name" => "userWithId",
+ "parameters" => {
+ "userIds" => "max,fred"
+ }
+ }])
+ end
+
+ it 'returns a disabled feature when the flag is disabled' do
+ flag = create(:operations_feature_flag, project: project, name: 'test_feature', active: false, version: 1)
+ create(:operations_feature_flag_scope, feature_flag: flag, environment_scope: 'production', active: true)
+ headers = { "UNLEASH-INSTANCEID" => client.token, "UNLEASH-APPNAME" => "production" }
+
+ get api(features_url), headers: headers
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['features'].first['enabled']).to eq(false)
+ end
+
+ context "with an inactive scope" do
+ let!(:scope) { create(:operations_feature_flag_scope, feature_flag: feature_flag, environment_scope: 'production', active: false, strategies: [{ name: "default", parameters: {} }]) }
+ let(:headers) { { "UNLEASH-INSTANCEID" => client.token, "UNLEASH-APPNAME" => "production" } }
+
+ it 'returns a disabled feature' do
+ get api(features_url), headers: headers
+
+ expect(response).to have_gitlab_http_status(:ok)
+ feature_json = json_response['features'].first
+ expect(feature_json['enabled']).to eq(false)
+ expect(feature_json['strategies']).to eq([{ 'name' => 'default', 'parameters' => {} }])
+ end
+ end
+ end
+
+ context 'with version 2 feature flags' do
+ it 'does not return a flag without any strategies' do
+ create(:operations_feature_flag, project: project,
+ name: 'feature1', active: true, version: 2)
+
+ get api(features_url), headers: { 'UNLEASH-INSTANCEID' => client.token, 'UNLEASH-APPNAME' => 'production' }
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['features']).to be_empty
+ end
+
+ it 'returns a flag with a default strategy' do
+ feature_flag = create(:operations_feature_flag, project: project,
+ name: 'feature1', active: true, version: 2)
+ strategy = create(:operations_strategy, feature_flag: feature_flag,
+ name: 'default', parameters: {})
+ create(:operations_scope, strategy: strategy, environment_scope: 'production')
+
+ get api(features_url), headers: { 'UNLEASH-INSTANCEID' => client.token, 'UNLEASH-APPNAME' => 'production' }
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['features']).to eq([{
+ 'name' => 'feature1',
+ 'enabled' => true,
+ 'strategies' => [{
+ 'name' => 'default',
+ 'parameters' => {}
+ }]
+ }])
+ end
+
+ it 'returns a flag with a userWithId strategy' do
+ feature_flag = create(:operations_feature_flag, project: project,
+ name: 'feature1', active: true, version: 2)
+ strategy = create(:operations_strategy, feature_flag: feature_flag,
+ name: 'userWithId', parameters: { userIds: 'user123,user456' })
+ create(:operations_scope, strategy: strategy, environment_scope: 'production')
+
+ get api(features_url), headers: { 'UNLEASH-INSTANCEID' => client.token, 'UNLEASH-APPNAME' => 'production' }
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['features']).to eq([{
+ 'name' => 'feature1',
+ 'enabled' => true,
+ 'strategies' => [{
+ 'name' => 'userWithId',
+ 'parameters' => { 'userIds' => 'user123,user456' }
+ }]
+ }])
+ end
+
+ it 'returns a flag with multiple strategies' do
+ feature_flag = create(:operations_feature_flag, project: project,
+ name: 'feature1', active: true, version: 2)
+ strategy_a = create(:operations_strategy, feature_flag: feature_flag,
+ name: 'userWithId', parameters: { userIds: 'user_a,user_b' })
+ strategy_b = create(:operations_strategy, feature_flag: feature_flag,
+ name: 'gradualRolloutUserId', parameters: { groupId: 'default', percentage: '45' })
+ create(:operations_scope, strategy: strategy_a, environment_scope: 'production')
+ create(:operations_scope, strategy: strategy_b, environment_scope: 'production')
+
+ get api(features_url), headers: { 'UNLEASH-INSTANCEID' => client.token, 'UNLEASH-APPNAME' => 'production' }
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['features'].map { |f| f['name'] }.sort).to eq(['feature1'])
+ features_json = json_response['features'].map do |feature|
+ feature.merge(feature.slice('strategies').transform_values { |v| v.sort_by { |s| s['name'] } })
+ end
+ expect(features_json).to eq([{
+ 'name' => 'feature1',
+ 'enabled' => true,
+ 'strategies' => [{
+ 'name' => 'gradualRolloutUserId',
+ 'parameters' => { 'groupId' => 'default', 'percentage' => '45' }
+ }, {
+ 'name' => 'userWithId',
+ 'parameters' => { 'userIds' => 'user_a,user_b' }
+ }]
+ }])
+ end
+
+ it 'returns only flags matching the environment scope' do
+ feature_flag_a = create(:operations_feature_flag, project: project,
+ name: 'feature1', active: true, version: 2)
+ strategy_a = create(:operations_strategy, feature_flag: feature_flag_a)
+ create(:operations_scope, strategy: strategy_a, environment_scope: 'production')
+ feature_flag_b = create(:operations_feature_flag, project: project,
+ name: 'feature2', active: true, version: 2)
+ strategy_b = create(:operations_strategy, feature_flag: feature_flag_b)
+ create(:operations_scope, strategy: strategy_b, environment_scope: 'staging')
+
+ get api(features_url), headers: { 'UNLEASH-INSTANCEID' => client.token, 'UNLEASH-APPNAME' => 'staging' }
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['features'].map { |f| f['name'] }.sort).to eq(['feature2'])
+ expect(json_response['features']).to eq([{
+ 'name' => 'feature2',
+ 'enabled' => true,
+ 'strategies' => [{
+ 'name' => 'default',
+ 'parameters' => {}
+ }]
+ }])
+ end
+
+ it 'returns only strategies matching the environment scope' do
+ feature_flag = create(:operations_feature_flag, project: project,
+ name: 'feature1', active: true, version: 2)
+ strategy_a = create(:operations_strategy, feature_flag: feature_flag,
+ name: 'userWithId', parameters: { userIds: 'user2,user8,user4' })
+ create(:operations_scope, strategy: strategy_a, environment_scope: 'production')
+ strategy_b = create(:operations_strategy, feature_flag: feature_flag,
+ name: 'default', parameters: {})
+ create(:operations_scope, strategy: strategy_b, environment_scope: 'staging')
+
+ get api(features_url), headers: { 'UNLEASH-INSTANCEID' => client.token, 'UNLEASH-APPNAME' => 'production' }
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['features']).to eq([{
+ 'name' => 'feature1',
+ 'enabled' => true,
+ 'strategies' => [{
+ 'name' => 'userWithId',
+ 'parameters' => { 'userIds' => 'user2,user8,user4' }
+ }]
+ }])
+ end
+
+ it 'returns only flags for the given project' do
+ project_b = create(:project)
+ feature_flag_a = create(:operations_feature_flag, project: project, name: 'feature_a', active: true, version: 2)
+ strategy_a = create(:operations_strategy, feature_flag: feature_flag_a)
+ create(:operations_scope, strategy: strategy_a, environment_scope: 'sandbox')
+ feature_flag_b = create(:operations_feature_flag, project: project_b, name: 'feature_b', active: true, version: 2)
+ strategy_b = create(:operations_strategy, feature_flag: feature_flag_b)
+ create(:operations_scope, strategy: strategy_b, environment_scope: 'sandbox')
+
+ get api(features_url), headers: { 'UNLEASH-INSTANCEID' => client.token, 'UNLEASH-APPNAME' => 'sandbox' }
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['features']).to eq([{
+ 'name' => 'feature_a',
+ 'enabled' => true,
+ 'strategies' => [{
+ 'name' => 'default',
+ 'parameters' => {}
+ }]
+ }])
+ end
+
+ it 'returns all strategies with a matching scope' do
+ feature_flag = create(:operations_feature_flag, project: project,
+ name: 'feature1', active: true, version: 2)
+ strategy_a = create(:operations_strategy, feature_flag: feature_flag,
+ name: 'userWithId', parameters: { userIds: 'user2,user8,user4' })
+ create(:operations_scope, strategy: strategy_a, environment_scope: '*')
+ strategy_b = create(:operations_strategy, feature_flag: feature_flag,
+ name: 'default', parameters: {})
+ create(:operations_scope, strategy: strategy_b, environment_scope: 'review/*')
+ strategy_c = create(:operations_strategy, feature_flag: feature_flag,
+ name: 'gradualRolloutUserId', parameters: { groupId: 'default', percentage: '15' })
+ create(:operations_scope, strategy: strategy_c, environment_scope: 'review/patch-1')
+
+ get api(features_url), headers: { 'UNLEASH-INSTANCEID' => client.token, 'UNLEASH-APPNAME' => 'review/patch-1' }
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['features'].first['strategies'].sort_by { |s| s['name'] }).to eq([{
+ 'name' => 'default',
+ 'parameters' => {}
+ }, {
+ 'name' => 'gradualRolloutUserId',
+ 'parameters' => { 'groupId' => 'default', 'percentage' => '15' }
+ }, {
+ 'name' => 'userWithId',
+ 'parameters' => { 'userIds' => 'user2,user8,user4' }
+ }])
+ end
+
+ it 'returns a strategy with more than one matching scope' do
+ feature_flag = create(:operations_feature_flag, project: project,
+ name: 'feature1', active: true, version: 2)
+ strategy = create(:operations_strategy, feature_flag: feature_flag,
+ name: 'default', parameters: {})
+ create(:operations_scope, strategy: strategy, environment_scope: 'production')
+ create(:operations_scope, strategy: strategy, environment_scope: '*')
+
+ get api(features_url), headers: { 'UNLEASH-INSTANCEID' => client.token, 'UNLEASH-APPNAME' => 'production' }
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['features']).to eq([{
+ 'name' => 'feature1',
+ 'enabled' => true,
+ 'strategies' => [{
+ 'name' => 'default',
+ 'parameters' => {}
+ }]
+ }])
+ end
+
+ it 'returns a disabled flag with a matching scope' do
+ feature_flag = create(:operations_feature_flag, project: project,
+ name: 'myfeature', active: false, version: 2)
+ strategy = create(:operations_strategy, feature_flag: feature_flag,
+ name: 'default', parameters: {})
+ create(:operations_scope, strategy: strategy, environment_scope: 'production')
+
+ get api(features_url), headers: { 'UNLEASH-INSTANCEID' => client.token, 'UNLEASH-APPNAME' => 'production' }
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['features']).to eq([{
+ 'name' => 'myfeature',
+ 'enabled' => false,
+ 'strategies' => [{
+ 'name' => 'default',
+ 'parameters' => {}
+ }]
+ }])
+ end
+
+ it 'returns a userWithId strategy for a gitlabUserList strategy' do
+ feature_flag = create(:operations_feature_flag, :new_version_flag, project: project,
+ name: 'myfeature', active: true)
+ user_list = create(:operations_feature_flag_user_list, project: project,
+ name: 'My List', user_xids: 'user1,user2')
+ strategy = create(:operations_strategy, feature_flag: feature_flag,
+ name: 'gitlabUserList', parameters: {}, user_list: user_list)
+ create(:operations_scope, strategy: strategy, environment_scope: 'production')
+
+ get api(features_url), headers: { 'UNLEASH-INSTANCEID' => client.token, 'UNLEASH-APPNAME' => 'production' }
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['features']).to eq([{
+ 'name' => 'myfeature',
+ 'enabled' => true,
+ 'strategies' => [{
+ 'name' => 'userWithId',
+ 'parameters' => { 'userIds' => 'user1,user2' }
+ }]
+ }])
+ end
+ end
+
+ context 'when mixing version 1 and version 2 feature flags' do
+ it 'returns both types of flags when both match' do
+ feature_flag_a = create(:operations_feature_flag, project: project,
+ name: 'feature_a', active: true, version: 2)
+ strategy = create(:operations_strategy, feature_flag: feature_flag_a,
+ name: 'userWithId', parameters: { userIds: 'user8' })
+ create(:operations_scope, strategy: strategy, environment_scope: 'staging')
+ feature_flag_b = create(:operations_feature_flag, project: project,
+ name: 'feature_b', active: true, version: 1)
+ create(:operations_feature_flag_scope, feature_flag: feature_flag_b,
+ active: true, strategies: [{ name: 'default', parameters: {} }], environment_scope: 'staging')
+
+ get api(features_url), headers: { 'UNLEASH-INSTANCEID' => client.token, 'UNLEASH-APPNAME' => 'staging' }
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['features'].sort_by {|f| f['name']}).to eq([{
+ 'name' => 'feature_a',
+ 'enabled' => true,
+ 'strategies' => [{
+ 'name' => 'userWithId',
+ 'parameters' => { 'userIds' => 'user8' }
+ }]
+ }, {
+ 'name' => 'feature_b',
+ 'enabled' => true,
+ 'strategies' => [{
+ 'name' => 'default',
+ 'parameters' => {}
+ }]
+ }])
+ end
+
+ it 'returns legacy flags when only legacy flags match' do
+ feature_flag_a = create(:operations_feature_flag, project: project,
+ name: 'feature_a', active: true, version: 2)
+ strategy = create(:operations_strategy, feature_flag: feature_flag_a,
+ name: 'userWithId', parameters: { userIds: 'user8' })
+ create(:operations_scope, strategy: strategy, environment_scope: 'production')
+ feature_flag_b = create(:operations_feature_flag, project: project,
+ name: 'feature_b', active: true, version: 1)
+ create(:operations_feature_flag_scope, feature_flag: feature_flag_b,
+ active: true, strategies: [{ name: 'default', parameters: {} }], environment_scope: 'staging')
+
+ get api(features_url), headers: { 'UNLEASH-INSTANCEID' => client.token, 'UNLEASH-APPNAME' => 'staging' }
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['features']).to eq([{
+ 'name' => 'feature_b',
+ 'enabled' => true,
+ 'strategies' => [{
+ 'name' => 'default',
+ 'parameters' => {}
+ }]
+ }])
+ end
+ end
+ end
+ end
+
+ describe 'POST /feature_flags/unleash/:project_id/client/register' do
+ subject { post api("/feature_flags/unleash/#{project_id}/client/register"), params: params, headers: headers }
+
+ it_behaves_like 'authenticated request'
+ end
+
+ describe 'POST /feature_flags/unleash/:project_id/client/metrics' do
+ subject { post api("/feature_flags/unleash/#{project_id}/client/metrics"), params: params, headers: headers }
+
+ it_behaves_like 'authenticated request'
+ end
+end
diff --git a/spec/requests/api/usage_data_spec.rb b/spec/requests/api/usage_data_spec.rb
index 46dd54dcc73..4f4f386e9db 100644
--- a/spec/requests/api/usage_data_spec.rb
+++ b/spec/requests/api/usage_data_spec.rb
@@ -66,6 +66,10 @@ RSpec.describe API::UsageData do
end
context 'with unknown event' do
+ before do
+ skip_feature_flags_yaml_validation
+ end
+
it 'returns status ok' do
expect(Gitlab::Redis::HLL).not_to receive(:add)
diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb
index 806b586ef49..7330c89fe77 100644
--- a/spec/requests/api/users_spec.rb
+++ b/spec/requests/api/users_spec.rb
@@ -1460,39 +1460,47 @@ RSpec.describe API::Users, :do_not_mock_admin_mode do
end
describe 'GET /user/:id/gpg_keys' do
- context 'when unauthenticated' do
- it 'returns authentication error' do
- get api("/users/#{user.id}/gpg_keys")
+ it 'returns 404 for non-existing user' do
+ get api('/users/0/gpg_keys')
- expect(response).to have_gitlab_http_status(:unauthorized)
- end
+ expect(response).to have_gitlab_http_status(:not_found)
+ expect(json_response['message']).to eq('404 User Not Found')
end
- context 'when authenticated' do
- it 'returns 404 for non-existing user' do
- get api('/users/0/gpg_keys', admin)
+ it 'returns array of GPG keys' do
+ user.gpg_keys << gpg_key
- expect(response).to have_gitlab_http_status(:not_found)
- expect(json_response['message']).to eq('404 User Not Found')
- end
+ get api("/users/#{user.id}/gpg_keys")
- it 'returns 404 error if key not foud' do
- delete api("/users/#{user.id}/gpg_keys/#{non_existing_record_id}", admin)
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to include_pagination_headers
+ expect(json_response).to be_an Array
+ expect(json_response.first['key']).to eq(gpg_key.key)
+ end
+ end
- expect(response).to have_gitlab_http_status(:not_found)
- expect(json_response['message']).to eq('404 GPG Key Not Found')
- end
+ describe 'GET /user/:id/gpg_keys/:key_id' do
+ it 'returns 404 for non-existing user' do
+ get api('/users/0/gpg_keys/1')
- it 'returns array of GPG keys' do
- user.gpg_keys << gpg_key
+ expect(response).to have_gitlab_http_status(:not_found)
+ expect(json_response['message']).to eq('404 User Not Found')
+ end
- get api("/users/#{user.id}/gpg_keys", admin)
+ it 'returns 404 for non-existing key' do
+ get api("/users/#{user.id}/gpg_keys/0")
- expect(response).to have_gitlab_http_status(:ok)
- expect(response).to include_pagination_headers
- expect(json_response).to be_an Array
- expect(json_response.first['key']).to eq(gpg_key.key)
- end
+ expect(response).to have_gitlab_http_status(:not_found)
+ expect(json_response['message']).to eq('404 GPG Key Not Found')
+ end
+
+ it 'returns a single GPG key' do
+ user.gpg_keys << gpg_key
+
+ get api("/users/#{user.id}/gpg_keys/#{gpg_key.id}")
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['key']).to eq(gpg_key.key)
end
end
@@ -2308,23 +2316,31 @@ RSpec.describe API::Users, :do_not_mock_admin_mode do
end
describe 'POST /users/:id/activate' do
+ subject(:activate) { post api("/users/#{user_id}/activate", api_user) }
+
+ let(:user_id) { user.id }
+
context 'performed by a non-admin user' do
+ let(:api_user) { user }
+
it 'is not authorized to perform the action' do
- post api("/users/#{user.id}/activate", user)
+ activate
expect(response).to have_gitlab_http_status(:forbidden)
end
end
context 'performed by an admin user' do
+ let(:api_user) { admin }
+
context 'for a deactivated user' do
before do
user.deactivate
-
- post api("/users/#{user.id}/activate", admin)
end
it 'activates a deactivated user' do
+ activate
+
expect(response).to have_gitlab_http_status(:created)
expect(user.reload.state).to eq('active')
end
@@ -2333,11 +2349,11 @@ RSpec.describe API::Users, :do_not_mock_admin_mode do
context 'for an active user' do
before do
user.activate
-
- post api("/users/#{user.id}/activate", admin)
end
it 'returns 201' do
+ activate
+
expect(response).to have_gitlab_http_status(:created)
expect(user.reload.state).to eq('active')
end
@@ -2346,11 +2362,11 @@ RSpec.describe API::Users, :do_not_mock_admin_mode do
context 'for a blocked user' do
before do
user.block
-
- post api("/users/#{user.id}/activate", admin)
end
it 'returns 403' do
+ activate
+
expect(response).to have_gitlab_http_status(:forbidden)
expect(json_response['message']).to eq('403 Forbidden - A blocked user must be unblocked to be activated')
expect(user.reload.state).to eq('blocked')
@@ -2360,11 +2376,11 @@ RSpec.describe API::Users, :do_not_mock_admin_mode do
context 'for a ldap blocked user' do
before do
user.ldap_block
-
- post api("/users/#{user.id}/activate", admin)
end
it 'returns 403' do
+ activate
+
expect(response).to have_gitlab_http_status(:forbidden)
expect(json_response['message']).to eq('403 Forbidden - A blocked user must be unblocked to be activated')
expect(user.reload.state).to eq('ldap_blocked')
@@ -2372,8 +2388,10 @@ RSpec.describe API::Users, :do_not_mock_admin_mode do
end
context 'for a user that does not exist' do
+ let(:user_id) { 0 }
+
before do
- post api("/users/0/activate", admin)
+ activate
end
it_behaves_like '404'
@@ -2382,15 +2400,23 @@ RSpec.describe API::Users, :do_not_mock_admin_mode do
end
describe 'POST /users/:id/deactivate' do
+ subject(:deactivate) { post api("/users/#{user_id}/deactivate", api_user) }
+
+ let(:user_id) { user.id }
+
context 'performed by a non-admin user' do
+ let(:api_user) { user }
+
it 'is not authorized to perform the action' do
- post api("/users/#{user.id}/deactivate", user)
+ deactivate
expect(response).to have_gitlab_http_status(:forbidden)
end
end
context 'performed by an admin user' do
+ let(:api_user) { admin }
+
context 'for an active user' do
let(:activity) { {} }
let(:user) { create(:user, **activity) }
@@ -2398,11 +2424,9 @@ RSpec.describe API::Users, :do_not_mock_admin_mode do
context 'with no recent activity' do
let(:activity) { { last_activity_on: ::User::MINIMUM_INACTIVE_DAYS.next.days.ago } }
- before do
- post api("/users/#{user.id}/deactivate", admin)
- end
-
it 'deactivates an active user' do
+ deactivate
+
expect(response).to have_gitlab_http_status(:created)
expect(user.reload.state).to eq('deactivated')
end
@@ -2411,11 +2435,9 @@ RSpec.describe API::Users, :do_not_mock_admin_mode do
context 'with recent activity' do
let(:activity) { { last_activity_on: ::User::MINIMUM_INACTIVE_DAYS.pred.days.ago } }
- before do
- post api("/users/#{user.id}/deactivate", admin)
- end
-
it 'does not deactivate an active user' do
+ deactivate
+
expect(response).to have_gitlab_http_status(:forbidden)
expect(json_response['message']).to eq("403 Forbidden - The user you are trying to deactivate has been active in the past #{::User::MINIMUM_INACTIVE_DAYS} days and cannot be deactivated")
expect(user.reload.state).to eq('active')
@@ -2426,11 +2448,11 @@ RSpec.describe API::Users, :do_not_mock_admin_mode do
context 'for a deactivated user' do
before do
user.deactivate
-
- post api("/users/#{user.id}/deactivate", admin)
end
it 'returns 201' do
+ deactivate
+
expect(response).to have_gitlab_http_status(:created)
expect(user.reload.state).to eq('deactivated')
end
@@ -2439,11 +2461,11 @@ RSpec.describe API::Users, :do_not_mock_admin_mode do
context 'for a blocked user' do
before do
user.block
-
- post api("/users/#{user.id}/deactivate", admin)
end
it 'returns 403' do
+ deactivate
+
expect(response).to have_gitlab_http_status(:forbidden)
expect(json_response['message']).to eq('403 Forbidden - A blocked user cannot be deactivated by the API')
expect(user.reload.state).to eq('blocked')
@@ -2453,20 +2475,33 @@ RSpec.describe API::Users, :do_not_mock_admin_mode do
context 'for a ldap blocked user' do
before do
user.ldap_block
-
- post api("/users/#{user.id}/deactivate", admin)
end
it 'returns 403' do
+ deactivate
+
expect(response).to have_gitlab_http_status(:forbidden)
expect(json_response['message']).to eq('403 Forbidden - A blocked user cannot be deactivated by the API')
expect(user.reload.state).to eq('ldap_blocked')
end
end
+ context 'for an internal user' do
+ let(:user) { User.alert_bot }
+
+ it 'returns 403' do
+ deactivate
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ expect(json_response['message']).to eq('403 Forbidden - An internal user cannot be deactivated by the API')
+ end
+ end
+
context 'for a user that does not exist' do
+ let(:user_id) { 0 }
+
before do
- post api("/users/0/deactivate", admin)
+ deactivate
end
it_behaves_like '404'
@@ -2506,6 +2541,15 @@ RSpec.describe API::Users, :do_not_mock_admin_mode do
expect(json_response['message']).to eq('404 User Not Found')
end
+ it 'returns a 403 error if user is internal' do
+ internal_user = create(:user, :bot)
+
+ post api("/users/#{internal_user.id}/block", admin)
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ expect(json_response['message']).to eq('An internal user cannot be blocked')
+ end
+
it 'returns a 201 if user is already blocked' do
post api("/users/#{blocked_user.id}/block", admin)
diff --git a/spec/requests/git_http_spec.rb b/spec/requests/git_http_spec.rb
index dbba2b35d74..a3bfa7ea33c 100644
--- a/spec/requests/git_http_spec.rb
+++ b/spec/requests/git_http_spec.rb
@@ -90,7 +90,7 @@ RSpec.describe 'Git HTTP requests' do
shared_examples_for 'pulls are allowed' do
it 'allows pulls' do
- download(path, env) do |response|
+ download(path, **env) do |response|
expect(response).to have_gitlab_http_status(:ok)
expect(response.media_type).to eq(Gitlab::Workhorse::INTERNAL_API_CONTENT_TYPE)
end
@@ -99,7 +99,7 @@ RSpec.describe 'Git HTTP requests' do
shared_examples_for 'pushes are allowed' do
it 'allows pushes', :sidekiq_might_not_need_inline do
- upload(path, env) do |response|
+ upload(path, **env) do |response|
expect(response).to have_gitlab_http_status(:ok)
expect(response.media_type).to eq(Gitlab::Workhorse::INTERNAL_API_CONTENT_TYPE)
end
@@ -259,7 +259,7 @@ RSpec.describe 'Git HTTP requests' do
it_behaves_like 'pulls are allowed'
it 'rejects pushes with 403 Forbidden' do
- upload(path, env) do |response|
+ upload(path, **env) do |response|
expect(response).to have_gitlab_http_status(:forbidden)
expect(response.body).to eq(git_access_wiki_error(:write_to_wiki))
end
@@ -347,7 +347,7 @@ RSpec.describe 'Git HTTP requests' do
end
it 'rejects pushes with 403 Forbidden' do
- upload(path, env) do |response|
+ upload(path, **env) do |response|
expect(response).to have_gitlab_http_status(:forbidden)
expect(response.body).to eq(git_access_error(:receive_pack_disabled_over_http))
end
@@ -358,7 +358,7 @@ RSpec.describe 'Git HTTP requests' do
it "rejects pushes with 403 Forbidden" do
allow(Gitlab.config.gitlab_shell).to receive(:upload_pack).and_return(false)
- download(path, env) do |response|
+ download(path, **env) do |response|
expect(response).to have_gitlab_http_status(:forbidden)
expect(response.body).to eq(git_access_error(:upload_pack_disabled_over_http))
end
@@ -370,7 +370,7 @@ RSpec.describe 'Git HTTP requests' do
it_behaves_like 'pulls are allowed'
it 'rejects pushes with 403 Forbidden' do
- upload(path, env) do |response|
+ upload(path, **env) do |response|
expect(response).to have_gitlab_http_status(:forbidden)
expect(response.body).to eq('You are not allowed to push code to this project.')
end
@@ -485,7 +485,7 @@ RSpec.describe 'Git HTTP requests' do
user.block
project.add_maintainer(user)
- download(path, env) do |response|
+ download(path, **env) do |response|
expect(response).to have_gitlab_http_status(:unauthorized)
end
end
@@ -507,7 +507,7 @@ RSpec.describe 'Git HTTP requests' do
it "resets the IP in Rack Attack on download" do
expect(Rack::Attack::Allow2Ban).to receive(:reset).twice
- download(path, env) do
+ download(path, **env) do
expect(response).to have_gitlab_http_status(:ok)
expect(response.media_type).to eq(Gitlab::Workhorse::INTERNAL_API_CONTENT_TYPE)
end
@@ -516,7 +516,7 @@ RSpec.describe 'Git HTTP requests' do
it "resets the IP in Rack Attack on upload" do
expect(Rack::Attack::Allow2Ban).to receive(:reset).twice
- upload(path, env) do
+ upload(path, **env) do
expect(response).to have_gitlab_http_status(:ok)
expect(response.media_type).to eq(Gitlab::Workhorse::INTERNAL_API_CONTENT_TYPE)
end
@@ -525,7 +525,7 @@ RSpec.describe 'Git HTTP requests' do
it 'updates the user last activity', :clean_gitlab_redis_shared_state do
expect(user.last_activity_on).to be_nil
- download(path, env) do |response|
+ download(path, **env) do |response|
expect(user.reload.last_activity_on).to eql(Date.today)
end
end
@@ -699,7 +699,7 @@ RSpec.describe 'Git HTTP requests' do
end
it 'uploads get status 404 with "project was moved" message' do
- upload(path, env) do |response|
+ upload(path, **env) do |response|
expect(response).to have_gitlab_http_status(:ok)
end
end
@@ -917,11 +917,11 @@ RSpec.describe 'Git HTTP requests' do
expect(response).to have_gitlab_http_status(:forbidden)
end
- download(path, env) do |response|
+ download(path, **env) do |response|
expect(response).to have_gitlab_http_status(:forbidden)
end
- upload(path, env) do |response|
+ upload(path, **env) do |response|
expect(response).to have_gitlab_http_status(:forbidden)
end
end
diff --git a/spec/requests/projects/cycle_analytics_events_spec.rb b/spec/requests/projects/cycle_analytics_events_spec.rb
index 4338bfa3759..3f57b8ba67b 100644
--- a/spec/requests/projects/cycle_analytics_events_spec.rb
+++ b/spec/requests/projects/cycle_analytics_events_spec.rb
@@ -12,7 +12,7 @@ RSpec.describe 'value stream analytics events' do
project.add_developer(user)
3.times do |count|
- Timecop.freeze(Time.now + count.days) do
+ travel_to(Time.now + count.days) do
create_cycle
end
end
diff --git a/spec/requests/rack_attack_global_spec.rb b/spec/requests/rack_attack_global_spec.rb
index 444ee478cbb..9fdafc06695 100644
--- a/spec/requests/rack_attack_global_spec.rb
+++ b/spec/requests/rack_attack_global_spec.rb
@@ -68,7 +68,7 @@ RSpec.describe 'Rack Attack global throttles' do
expect_rejection { get url_that_does_not_require_authentication }
- Timecop.travel(period.from_now) do
+ travel_to(period.from_now) do
requests_per_period.times do
get url_that_does_not_require_authentication
expect(response).to have_gitlab_http_status(:ok)
diff --git a/spec/requests/request_profiler_spec.rb b/spec/requests/request_profiler_spec.rb
index 7f9999bf3d2..72689595480 100644
--- a/spec/requests/request_profiler_spec.rb
+++ b/spec/requests/request_profiler_spec.rb
@@ -24,7 +24,7 @@ RSpec.describe 'Request Profiler' do
time = Time.now
path = "/#{project.full_path}"
- Timecop.freeze(time) do
+ travel_to(time) do
get path, params: {}, headers: { 'X-Profile-Token' => Gitlab::RequestProfiler.profile_token, 'X-Profile-Mode' => profile_type }
end
diff --git a/spec/requests/user_activity_spec.rb b/spec/requests/user_activity_spec.rb
index 6f0726dbdc9..148bb2d6fae 100644
--- a/spec/requests/user_activity_spec.rb
+++ b/spec/requests/user_activity_spec.rb
@@ -3,18 +3,6 @@
require 'spec_helper'
RSpec.describe 'Update of user activity' do
- let(:user) { create(:user, last_activity_on: nil) }
-
- before do
- group = create(:group, name: 'group')
- project = create(:project, :public, namespace: group, name: 'project')
-
- create(:issue, project: project, iid: 10)
- create(:merge_request, source_project: project, iid: 15)
-
- project.add_maintainer(user)
- end
-
paths_to_visit = [
'/group',
'/group/project',
@@ -30,85 +18,5 @@ RSpec.describe 'Update of user activity' do
'/group/project/-/merge_requests/15'
]
- context 'without an authenticated user' do
- it 'does not set the last activity cookie' do
- get "/group/project"
-
- expect(response.cookies['user_last_activity_on']).to be_nil
- end
- end
-
- context 'with an authenticated user' do
- before do
- login_as(user)
- end
-
- context 'with a POST request' do
- it 'does not set the last activity cookie' do
- post "/group/project/archive"
-
- expect(response.cookies['user_last_activity_on']).to be_nil
- end
- end
-
- paths_to_visit.each do |path|
- context "on GET to #{path}" do
- it 'updates the last activity date' do
- expect(Users::ActivityService).to receive(:new).and_call_original
-
- get path
-
- expect(user.last_activity_on).to eq(Date.today)
- end
-
- context 'when calling it twice' do
- it 'updates last_activity_on just once' do
- expect(Users::ActivityService).to receive(:new).once.and_call_original
-
- 2.times do
- get path
- end
- end
- end
-
- context 'when last_activity_on is nil' do
- before do
- user.update_attribute(:last_activity_on, nil)
- end
-
- it 'updates the last activity date' do
- expect(user.last_activity_on).to be_nil
-
- get path
-
- expect(user.last_activity_on).to eq(Date.today)
- end
- end
-
- context 'when last_activity_on is stale' do
- before do
- user.update_attribute(:last_activity_on, 2.days.ago.to_date)
- end
-
- it 'updates the last activity date' do
- get path
-
- expect(user.last_activity_on).to eq(Date.today)
- end
- end
-
- context 'when last_activity_on is up to date' do
- before do
- user.update_attribute(:last_activity_on, Date.today)
- end
-
- it 'does not try to update it' do
- expect(Users::ActivityService).not_to receive(:new)
-
- get path
- end
- end
- end
- end
- end
+ it_behaves_like 'updating of user activity', paths_to_visit
end
diff --git a/spec/requests/user_sends_null_bytes_spec.rb b/spec/requests/user_sends_null_bytes_spec.rb
new file mode 100644
index 00000000000..1ddfad40996
--- /dev/null
+++ b/spec/requests/user_sends_null_bytes_spec.rb
@@ -0,0 +1,14 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'User sends null bytes as params' do
+ let(:null_byte) { "\u0000" }
+
+ it 'raises a 400 error' do
+ post '/nonexistent', params: { a: "A #{null_byte} nasty string" }
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ expect(response.body).to eq('Bad Request')
+ end
+end
diff --git a/spec/requests/whats_new_controller_spec.rb b/spec/requests/whats_new_controller_spec.rb
new file mode 100644
index 00000000000..29500a7b5f9
--- /dev/null
+++ b/spec/requests/whats_new_controller_spec.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe WhatsNewController do
+ describe 'whats_new_path' do
+ before do
+ allow_any_instance_of(WhatsNewController).to receive(:whats_new_most_recent_release_items).and_return('items')
+ end
+
+ context 'with whats_new_drawer feature enabled' do
+ before do
+ stub_feature_flags(whats_new_drawer: true)
+ end
+
+ it 'is successful' do
+ get whats_new_path, xhr: true
+
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+ end
+
+ context 'with whats_new_drawer feature disabled' do
+ before do
+ stub_feature_flags(whats_new_drawer: false)
+ end
+
+ it 'returns a 404' do
+ get whats_new_path, xhr: true
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+ end
+end
diff --git a/spec/routing/admin_routing_spec.rb b/spec/routing/admin_routing_spec.rb
index fedafff0d1b..9374df0c4a2 100644
--- a/spec/routing/admin_routing_spec.rb
+++ b/spec/routing/admin_routing_spec.rb
@@ -184,3 +184,9 @@ RSpec.describe Admin::PlanLimitsController, "routing" do
expect(post("/admin/plan_limits")).to route_to('admin/plan_limits#create')
end
end
+
+RSpec.describe Admin::RunnersController, "routing" do
+ it "to #runner_setup_scripts" do
+ expect(get("/admin/runners/runner_setup_scripts")).to route_to('admin/runners#runner_setup_scripts')
+ end
+end
diff --git a/spec/routing/group_routing_spec.rb b/spec/routing/group_routing_spec.rb
index f4d5f899519..9de99b73d23 100644
--- a/spec/routing/group_routing_spec.rb
+++ b/spec/routing/group_routing_spec.rb
@@ -43,6 +43,10 @@ RSpec.shared_examples 'groups routing' do
expect(get("/groups/#{group_path}/-/milestones")).to route_to('groups/milestones#index', group_id: group_path)
end
+ it "to #runner_setup_scripts" do
+ expect(get("/groups/#{group_path}/-/settings/ci_cd/runner_setup_scripts")).to route_to('groups/settings/ci_cd#runner_setup_scripts', group_id: group_path)
+ end
+
it 'routes to the avatars controller' do
expect(delete("/groups/#{group_path}/-/avatar"))
.to route_to(group_id: group_path,
diff --git a/spec/routing/instance_statistics_routing_spec.rb b/spec/routing/instance_statistics_routing_spec.rb
deleted file mode 100644
index 7eec807fb0b..00000000000
--- a/spec/routing/instance_statistics_routing_spec.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe 'Instance Statistics', 'routing' do
- include RSpec::Rails::RequestExampleGroup
-
- it "routes '/-/instance_statistics' to dev ops report" do
- expect(get('/-/instance_statistics')).to redirect_to('/admin/dev_ops_report')
- end
-end
diff --git a/spec/routing/project_routing_spec.rb b/spec/routing/project_routing_spec.rb
index b80baf0aa13..a683dc28f4f 100644
--- a/spec/routing/project_routing_spec.rb
+++ b/spec/routing/project_routing_spec.rb
@@ -306,12 +306,9 @@ RSpec.describe 'project routing' do
end
# raw_project_snippet GET /:project_id/snippets/:id/raw(.:format) snippets#raw
# project_snippets GET /:project_id/snippets(.:format) snippets#index
- # POST /:project_id/snippets(.:format) snippets#create
# new_project_snippet GET /:project_id/snippets/new(.:format) snippets#new
# edit_project_snippet GET /:project_id/snippets/:id/edit(.:format) snippets#edit
# project_snippet GET /:project_id/snippets/:id(.:format) snippets#show
- # PUT /:project_id/snippets/:id(.:format) snippets#update
- # DELETE /:project_id/snippets/:id(.:format) snippets#destroy
describe SnippetsController, 'routing' do
it 'to #raw' do
expect(get('/gitlab/gitlabhq/-/snippets/1/raw')).to route_to('projects/snippets#raw', namespace_id: 'gitlab', project_id: 'gitlabhq', id: '1')
@@ -321,10 +318,6 @@ RSpec.describe 'project routing' do
expect(get('/gitlab/gitlabhq/-/snippets')).to route_to('projects/snippets#index', namespace_id: 'gitlab', project_id: 'gitlabhq')
end
- it 'to #create' do
- expect(post('/gitlab/gitlabhq/-/snippets')).to route_to('projects/snippets#create', namespace_id: 'gitlab', project_id: 'gitlabhq')
- end
-
it 'to #new' do
expect(get('/gitlab/gitlabhq/-/snippets/new')).to route_to('projects/snippets#new', namespace_id: 'gitlab', project_id: 'gitlabhq')
end
@@ -337,14 +330,6 @@ RSpec.describe 'project routing' do
expect(get('/gitlab/gitlabhq/-/snippets/1')).to route_to('projects/snippets#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: '1')
end
- it 'to #update' do
- expect(put('/gitlab/gitlabhq/-/snippets/1')).to route_to('projects/snippets#update', namespace_id: 'gitlab', project_id: 'gitlabhq', id: '1')
- end
-
- it 'to #destroy' do
- expect(delete('/gitlab/gitlabhq/-/snippets/1')).to route_to('projects/snippets#destroy', namespace_id: 'gitlab', project_id: 'gitlabhq', id: '1')
- end
-
it 'to #show from unscope routing' do
expect(get('/gitlab/gitlabhq/snippets/1')).to route_to('projects/snippets#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: '1')
end
@@ -731,6 +716,12 @@ RSpec.describe 'project routing' do
end
end
+ describe Projects::Settings::CiCdController, 'routing' do
+ it "to #runner_setup_scripts" do
+ expect(get("/gitlab/gitlabhq/-/settings/ci_cd/runner_setup_scripts")).to route_to('projects/settings/ci_cd#runner_setup_scripts', namespace_id: 'gitlab', project_id: 'gitlabhq')
+ end
+ end
+
describe Projects::TemplatesController, 'routing' do
describe '#show' do
def show_with_template_type(template_type)
diff --git a/spec/routing/routing_spec.rb b/spec/routing/routing_spec.rb
index 722e687838f..f665dc31ee4 100644
--- a/spec/routing/routing_spec.rb
+++ b/spec/routing/routing_spec.rb
@@ -61,12 +61,9 @@ RSpec.describe "Mounted Apps", "routing" do
end
# snippets GET /snippets(.:format) snippets#index
-# POST /snippets(.:format) snippets#create
# new_snippet GET /snippets/new(.:format) snippets#new
# edit_snippet GET /snippets/:id/edit(.:format) snippets#edit
# snippet GET /snippets/:id(.:format) snippets#show
-# PUT /snippets/:id(.:format) snippets#update
-# DELETE /snippets/:id(.:format) snippets#destroy
RSpec.describe SnippetsController, "routing" do
it "to #raw" do
expect(get("/-/snippets/1/raw")).to route_to('snippets#raw', id: '1')
@@ -76,10 +73,6 @@ RSpec.describe SnippetsController, "routing" do
expect(get("/-/snippets")).to route_to('snippets#index')
end
- it "to #create" do
- expect(post("/-/snippets")).to route_to('snippets#create')
- end
-
it "to #new" do
expect(get("/-/snippets/new")).to route_to('snippets#new')
end
@@ -92,14 +85,6 @@ RSpec.describe SnippetsController, "routing" do
expect(get("/-/snippets/1")).to route_to('snippets#show', id: '1')
end
- it "to #update" do
- expect(put("/-/snippets/1")).to route_to('snippets#update', id: '1')
- end
-
- it "to #destroy" do
- expect(delete("/-/snippets/1")).to route_to('snippets#destroy', id: '1')
- end
-
it 'to #show from unscoped routing' do
expect(get("/snippets/1")).to route_to('snippets#show', id: '1')
end
@@ -119,9 +104,9 @@ RSpec.describe HelpController, "routing" do
path: 'user/markdown',
format: 'md')
- path = '/help/workflow/protected_branches/protected_branches1.png'
+ path = '/help/user/markdown/markdown_logo.png'
expect(get(path)).to route_to('help#show',
- path: 'workflow/protected_branches/protected_branches1',
+ path: 'user/markdown/markdown_logo',
format: 'png')
end
end
@@ -148,6 +133,10 @@ RSpec.describe ProfilesController, "routing" do
it "to #show" do
expect(get("/profile")).to route_to('profiles#show')
end
+
+ it 'to #show from scope routing' do
+ expect(get("/-/profile")).to route_to('profiles#show')
+ end
end
# profile_preferences GET /profile/preferences(.:format) profiles/preferences#show
@@ -374,3 +363,9 @@ RSpec.describe Snippets::BlobsController, "routing" do
.to route_to('snippets/blobs#raw', snippet_id: '1', ref: 'master', path: 'lib/version.rb')
end
end
+
+RSpec.describe RunnerSetupController, 'routing' do
+ it 'to #platforms' do
+ expect(get("/-/runner_setup/platforms")).to route_to('runner_setup#platforms')
+ end
+end
diff --git a/spec/rubocop/cop/api/base_spec.rb b/spec/rubocop/cop/api/base_spec.rb
new file mode 100644
index 00000000000..893bcf49627
--- /dev/null
+++ b/spec/rubocop/cop/api/base_spec.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+require 'fast_spec_helper'
+require 'rubocop'
+require 'rubocop/rspec/support'
+require_relative '../../../../rubocop/cop/api/base'
+
+RSpec.describe RuboCop::Cop::API::Base, type: :rubocop do
+ include CopHelper
+
+ subject(:cop) { described_class.new }
+
+ let(:corrected) do
+ <<~CORRECTED
+ class SomeAPI < ::API::Base
+ end
+ CORRECTED
+ end
+
+ ['Grape::API', '::Grape::API', 'Grape::API::Instance', '::Grape::API::Instance'].each do |offense|
+ it "adds an offense when inheriting from #{offense}" do
+ expect_offense(<<~CODE)
+ class SomeAPI < #{offense}
+ #{'^' * offense.length} #{described_class::MSG}
+ end
+ CODE
+
+ expect_correction(corrected)
+ end
+ end
+
+ it 'does not add an offense when inheriting from BaseAPI' do
+ expect_no_offenses(corrected)
+ end
+end
diff --git a/spec/rubocop/cop/api/grape_api_instance_spec.rb b/spec/rubocop/cop/api/grape_api_instance_spec.rb
deleted file mode 100644
index 74f175cb707..00000000000
--- a/spec/rubocop/cop/api/grape_api_instance_spec.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-# frozen_string_literal: true
-
-require 'fast_spec_helper'
-require 'rubocop'
-require_relative '../../../../rubocop/cop/api/grape_api_instance'
-
-RSpec.describe RuboCop::Cop::API::GrapeAPIInstance do
- include CopHelper
-
- subject(:cop) { described_class.new }
-
- it 'adds an offense when inheriting from Grape::API' do
- inspect_source(<<~CODE)
- class SomeAPI < Grape::API
- end
- CODE
-
- expect(cop.offenses.size).to eq(1)
- end
-
- it 'does not add an offense when inheriting from Grape::API::Instance' do
- inspect_source(<<~CODE)
- class SomeAPI < Grape::API::Instance
- end
- CODE
-
- expect(cop.offenses.size).to be_zero
- end
-end
diff --git a/spec/rubocop/cop/code_reuse/active_record_spec.rb b/spec/rubocop/cop/code_reuse/active_record_spec.rb
index 25eca185f26..e15b9e11aed 100644
--- a/spec/rubocop/cop/code_reuse/active_record_spec.rb
+++ b/spec/rubocop/cop/code_reuse/active_record_spec.rb
@@ -84,7 +84,7 @@ RSpec.describe RuboCop::Cop::CodeReuse::ActiveRecord, type: :rubocop do
SOURCE
end
- it 'autocorrects offenses in instance methods by whitelisting them' do
+ it 'autocorrects offenses in instance methods by allowing them' do
corrected = autocorrect_source(<<~SOURCE)
def foo
User.where
@@ -100,7 +100,7 @@ RSpec.describe RuboCop::Cop::CodeReuse::ActiveRecord, type: :rubocop do
SOURCE
end
- it 'autocorrects offenses in class methods by whitelisting them' do
+ it 'autocorrects offenses in class methods by allowing them' do
corrected = autocorrect_source(<<~SOURCE)
def self.foo
User.where
@@ -116,7 +116,7 @@ RSpec.describe RuboCop::Cop::CodeReuse::ActiveRecord, type: :rubocop do
SOURCE
end
- it 'autocorrects offenses in blocks by whitelisting them' do
+ it 'autocorrects offenses in blocks by allowing them' do
corrected = autocorrect_source(<<~SOURCE)
get '/' do
User.where
diff --git a/spec/rubocop/cop/graphql/gid_expected_type_spec.rb b/spec/rubocop/cop/graphql/gid_expected_type_spec.rb
new file mode 100644
index 00000000000..a81af2aea5d
--- /dev/null
+++ b/spec/rubocop/cop/graphql/gid_expected_type_spec.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+require 'fast_spec_helper'
+require 'rubocop'
+
+require_relative '../../../../rubocop/cop/graphql/gid_expected_type'
+
+RSpec.describe RuboCop::Cop::Graphql::GIDExpectedType, type: :rubocop do
+ include CopHelper
+
+ subject(:cop) { described_class.new }
+
+ it 'adds an offense when there is no expected_type parameter' do
+ inspect_source(<<~TYPE)
+ GitlabSchema.object_from_id(received_id)
+ TYPE
+
+ expect(cop.offenses.size).to eq 1
+ end
+
+ it 'does not add an offense for calls that have an expected_type parameter' do
+ expect_no_offenses(<<~TYPE.strip)
+ GitlabSchema.object_from_id("some_id", expected_type: SomeClass)
+ TYPE
+ end
+end
diff --git a/spec/rubocop/cop/graphql/id_type_spec.rb b/spec/rubocop/cop/graphql/id_type_spec.rb
new file mode 100644
index 00000000000..8767412e282
--- /dev/null
+++ b/spec/rubocop/cop/graphql/id_type_spec.rb
@@ -0,0 +1,36 @@
+# frozen_string_literal: true
+
+require 'fast_spec_helper'
+require 'rubocop'
+
+require_relative '../../../../rubocop/cop/graphql/id_type'
+
+RSpec.describe RuboCop::Cop::Graphql::IDType, type: :rubocop do
+ include CopHelper
+
+ subject(:cop) { described_class.new }
+
+ it 'adds an offense when GraphQL::ID_TYPE is used as a param to #argument' do
+ inspect_source(<<~TYPE)
+ argument :some_arg, GraphQL::ID_TYPE, some: other, params: do_not_matter
+ TYPE
+
+ expect(cop.offenses.size).to eq 1
+ end
+
+ context 'whitelisted arguments' do
+ RuboCop::Cop::Graphql::IDType::WHITELISTED_ARGUMENTS.each do |arg|
+ it "does not add an offense for calls to #argument with #{arg} as argument name" do
+ expect_no_offenses(<<~TYPE.strip)
+ argument #{arg}, GraphQL::ID_TYPE, some: other, params: do_not_matter
+ TYPE
+ end
+ end
+ end
+
+ it 'does not add an offense for calls to #argument without GraphQL::ID_TYPE' do
+ expect_no_offenses(<<~TYPE.strip)
+ argument :some_arg, ::Types::GlobalIDType[::Awardable], some: other, params: do_not_matter
+ TYPE
+ end
+end
diff --git a/spec/rubocop/cop/migration/add_concurrent_foreign_key_spec.rb b/spec/rubocop/cop/migration/add_concurrent_foreign_key_spec.rb
index b43d44dba65..aaf191a1b6b 100644
--- a/spec/rubocop/cop/migration/add_concurrent_foreign_key_spec.rb
+++ b/spec/rubocop/cop/migration/add_concurrent_foreign_key_spec.rb
@@ -36,5 +36,15 @@ RSpec.describe RuboCop::Cop::Migration::AddConcurrentForeignKey, type: :rubocop
expect(cop.offenses).to be_empty
end
+
+ it 'does not register an offense when `add_foreign_key` is within `with_lock_retries`' do
+ inspect_source <<~RUBY
+ with_lock_retries do
+ add_foreign_key :key, :projects, column: :project_id, on_delete: :cascade
+ end
+ RUBY
+
+ expect(cop.offenses).to be_empty
+ end
end
end
diff --git a/spec/rubocop/cop/migration/add_limit_to_text_columns_spec.rb b/spec/rubocop/cop/migration/add_limit_to_text_columns_spec.rb
index 5f0ca419548..0bea7bd7a0c 100644
--- a/spec/rubocop/cop/migration/add_limit_to_text_columns_spec.rb
+++ b/spec/rubocop/cop/migration/add_limit_to_text_columns_spec.rb
@@ -129,6 +129,28 @@ RSpec.describe RuboCop::Cop::Migration::AddLimitToTextColumns, type: :rubocop do
end
end
+ context 'when text columns are used for encryption' do
+ it 'registers no offenses' do
+ expect_no_offenses(<<~RUBY)
+ class TestTextLimits < ActiveRecord::Migration[6.0]
+ DOWNTIME = false
+ disable_ddl_transaction!
+
+ def up
+ create_table :test_text_limits, id: false do |t|
+ t.integer :test_id, null: false
+ t.text :encrypted_name
+ end
+
+ add_column :encrypted_test_text_limits, :encrypted_email, :text
+ add_column_with_default :encrypted_test_text_limits, :encrypted_role, :text, default: 'default'
+ change_column_type_concurrently :encrypted_test_text_limits, :encrypted_test_id, :text
+ end
+ end
+ RUBY
+ end
+ end
+
context 'on down' do
it 'registers no offense' do
expect_no_offenses(<<~RUBY)
diff --git a/spec/rubocop/cop/migration/create_table_with_foreign_keys_spec.rb b/spec/rubocop/cop/migration/create_table_with_foreign_keys_spec.rb
index fa4acc62226..93f43b0feb0 100644
--- a/spec/rubocop/cop/migration/create_table_with_foreign_keys_spec.rb
+++ b/spec/rubocop/cop/migration/create_table_with_foreign_keys_spec.rb
@@ -83,7 +83,7 @@ RSpec.describe RuboCop::Cop::Migration::CreateTableWithForeignKeys, type: :ruboc
context 'with more than one foreign keys' do
let(:offense) do
'Creating a table with more than one foreign key at once violates our migration style guide. ' \
- 'For more details check the https://docs.gitlab.com/ce/development/migration_style_guide.html#examples'
+ 'For more details check the https://docs.gitlab.com/ee/development/migration_style_guide.html#examples'
end
shared_examples 'target to high traffic table' do |dsl_method, table_name|
diff --git a/spec/rubocop/cop/migration/with_lock_retries_disallowed_method_spec.rb b/spec/rubocop/cop/migration/with_lock_retries_disallowed_method_spec.rb
index 11e4d784617..607daf0c9f0 100644
--- a/spec/rubocop/cop/migration/with_lock_retries_disallowed_method_spec.rb
+++ b/spec/rubocop/cop/migration/with_lock_retries_disallowed_method_spec.rb
@@ -53,6 +53,22 @@ RSpec.describe RuboCop::Cop::Migration::WithLockRetriesDisallowedMethod, type: :
expect(cop.offenses.size).to eq(0)
end
+
+ describe 'for `add_foreign_key`' do
+ it 'registers an offense when more than two FKs are added' do
+ message = described_class::MSG_ONLY_ONE_FK_ALLOWED
+
+ expect_offense <<~RUBY
+ with_lock_retries do
+ add_foreign_key :imports, :projects, column: :project_id, on_delete: :cascade
+ ^^^^^^^^^^^^^^^ #{message}
+ add_column :projects, :name, :text
+ add_foreign_key :imports, :users, column: :user_id, on_delete: :cascade
+ ^^^^^^^^^^^^^^^ #{message}
+ end
+ RUBY
+ end
+ end
end
context 'outside of migration' do
diff --git a/spec/rubocop/cop/rspec/expect_gitlab_tracking_spec.rb b/spec/rubocop/cop/rspec/expect_gitlab_tracking_spec.rb
new file mode 100644
index 00000000000..f7adc1373df
--- /dev/null
+++ b/spec/rubocop/cop/rspec/expect_gitlab_tracking_spec.rb
@@ -0,0 +1,65 @@
+# frozen_string_literal: true
+
+require 'fast_spec_helper'
+require 'rubocop'
+require 'rubocop/rspec/support'
+
+require_relative '../../../../rubocop/cop/rspec/expect_gitlab_tracking'
+
+RSpec.describe RuboCop::Cop::RSpec::ExpectGitlabTracking do
+ include CopHelper
+
+ let(:source_file) { 'spec/foo_spec.rb' }
+
+ subject(:cop) { described_class.new }
+
+ good_samples = [
+ 'expect_snowplow_event(category: nil, action: nil)',
+ 'expect_snowplow_event(category: "EventCategory", action: "event_action")',
+ 'expect_snowplow_event(category: "EventCategory", action: "event_action", label: "label", property: "property")',
+ 'expect_no_snowplow_event'
+ ]
+
+ bad_samples = [
+ 'expect(Gitlab::Tracking).to receive(:event)',
+ 'expect(Gitlab::Tracking).to_not receive(:event)',
+ 'expect(Gitlab::Tracking).not_to receive(:event)',
+ 'expect(Gitlab::Tracking).to_not receive(:event).with("EventCategory", "event_action")',
+ 'expect(Gitlab::Tracking).not_to receive(:event).with("EventCategory", "event_action")',
+ 'expect(Gitlab::Tracking).to receive(:event).with("EventCategory", "event_action", label: "label", property: "property")',
+ 'expect(Gitlab::Tracking).to have_received(:event).with("EventCategory", "event_action")',
+ 'expect(Gitlab::Tracking).to_not have_received(:event).with("EventCategory", "event_action")',
+ 'expect(Gitlab::Tracking).not_to have_received(:event).with("EventCategory", "event_action")',
+ 'allow(Gitlab::Tracking).to receive(:event).and_call_original'
+ ]
+
+ good_samples.each do |good|
+ context "good: #{good}" do
+ it 'does not register an offense' do
+ inspect_source(good)
+
+ expect(cop.offenses).to be_empty
+ end
+ end
+ end
+
+ bad_samples.each do |bad|
+ context "bad: #{bad}" do
+ it 'registers an offense', :aggregate_failures do
+ inspect_source(bad, source_file)
+
+ expect(cop.offenses.size).to eq(1)
+ expect(cop.offenses.map(&:line)).to eq([1])
+ expect(cop.highlights).to eq([bad])
+
+ msg = cop.offenses.first.message
+
+ expect(msg).to match(
+ /Do not expect directly on `Gitlab::Tracking#event`/
+ )
+ expect(msg).to match(/add the `snowplow` annotation/)
+ expect(msg).to match(/use `expect_snowplow_event` instead/)
+ end
+ end
+ end
+end
diff --git a/spec/rubocop/cop/rspec/factory_bot/inline_association_spec.rb b/spec/rubocop/cop/rspec/factory_bot/inline_association_spec.rb
new file mode 100644
index 00000000000..70dbe086127
--- /dev/null
+++ b/spec/rubocop/cop/rspec/factory_bot/inline_association_spec.rb
@@ -0,0 +1,132 @@
+# frozen_string_literal: true
+
+require 'fast_spec_helper'
+require 'rspec-parameterized'
+require 'rubocop'
+
+require_relative '../../../../../rubocop/cop/rspec/factory_bot/inline_association'
+
+RSpec.describe RuboCop::Cop::RSpec::FactoryBot::InlineAssociation, type: :rubocop do
+ include CopHelper
+
+ subject(:cop) { described_class.new }
+
+ shared_examples 'offense' do |code_snippet, autocorrected|
+ # We allow `create` or `FactoryBot.create` or `::FactoryBot.create`
+ let(:type) { code_snippet[/^(?:::)?(?:FactoryBot\.)?(\w+)/, 1] }
+ let(:offense_marker) { '^' * code_snippet.size }
+ let(:offense_msg) { msg(type) }
+ let(:offense) { "#{offense_marker} #{offense_msg}" }
+ let(:pristine_source) { source.sub(offense, '') }
+ let(:source) do
+ <<~RUBY
+ FactoryBot.define do
+ factory :project do
+ attribute { #{code_snippet} }
+ #{offense}
+ end
+ end
+ RUBY
+ end
+
+ it 'registers an offense' do
+ expect_offense(source)
+ end
+
+ it 'autocorrects the source' do
+ corrected = autocorrect_source(pristine_source)
+
+ expect(corrected).not_to include(code_snippet)
+ expect(corrected).to include(autocorrected)
+ end
+ end
+
+ shared_examples 'no offense' do |code_snippet|
+ first_line = code_snippet.lines.first.chomp
+
+ context "for `#{first_line}`" do
+ it 'does not register any offenses' do
+ expect_no_offenses <<~RUBY
+ FactoryBot.define do
+ factory :project do
+ #{code_snippet}
+ end
+ end
+ RUBY
+ end
+ end
+ end
+
+ context 'offenses' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:code_snippet, :autocorrected) do
+ # create
+ 'create(:user)' | 'association(:user)'
+ 'FactoryBot.create(:user)' | 'association(:user)'
+ '::FactoryBot.create(:user)' | 'association(:user)'
+ 'create(:user, :admin)' | 'association(:user, :admin)'
+ 'create(:user, name: "any")' | 'association(:user, name: "any")'
+ # build
+ 'build(:user)' | 'association(:user)'
+ 'FactoryBot.build(:user)' | 'association(:user)'
+ '::FactoryBot.build(:user)' | 'association(:user)'
+ 'build(:user, :admin)' | 'association(:user, :admin)'
+ 'build(:user, name: "any")' | 'association(:user, name: "any")'
+ end
+
+ with_them do
+ include_examples 'offense', params[:code_snippet], params[:autocorrected]
+ end
+
+ it 'recognizes `add_attribute`' do
+ expect_offense <<~RUBY
+ FactoryBot.define do
+ factory :project, class: 'Project' do
+ add_attribute(:method) { create(:user) }
+ ^^^^^^^^^^^^^ #{msg(:create)}
+ end
+ end
+ RUBY
+ end
+
+ it 'recognizes `transient` attributes' do
+ expect_offense <<~RUBY
+ FactoryBot.define do
+ factory :project, class: 'Project' do
+ transient do
+ creator { create(:user) }
+ ^^^^^^^^^^^^^ #{msg(:create)}
+ end
+ end
+ end
+ RUBY
+ end
+ end
+
+ context 'no offenses' do
+ include_examples 'no offense', 'association(:user)'
+ include_examples 'no offense', 'association(:user, :admin)'
+ include_examples 'no offense', 'association(:user, name: "any")'
+
+ include_examples 'no offense', <<~RUBY
+ after(:build) do |object|
+ object.user = create(:user)
+ end
+ RUBY
+
+ include_examples 'no offense', <<~RUBY
+ initialize_with do
+ create(:user)
+ end
+ RUBY
+
+ include_examples 'no offense', <<~RUBY
+ user_id { create(:user).id }
+ RUBY
+ end
+
+ def msg(type)
+ format(described_class::MSG, type: type)
+ end
+end
diff --git a/spec/rubocop/cop/rspec/timecop_travel_spec.rb b/spec/rubocop/cop/rspec/timecop_travel_spec.rb
new file mode 100644
index 00000000000..25a8127d40e
--- /dev/null
+++ b/spec/rubocop/cop/rspec/timecop_travel_spec.rb
@@ -0,0 +1,52 @@
+# frozen_string_literal: true
+
+require 'fast_spec_helper'
+
+require 'rubocop'
+require 'rubocop/rspec/support'
+
+require_relative '../../../../rubocop/cop/rspec/timecop_travel'
+
+RSpec.describe RuboCop::Cop::RSpec::TimecopTravel, type: :rubocop do
+ include CopHelper
+
+ subject(:cop) { described_class.new }
+
+ context 'when calling Timecop.travel' do
+ let(:source) do
+ <<~SRC
+ Timecop.travel(1.day.ago) { create(:issue) }
+ SRC
+ end
+
+ let(:corrected_source) do
+ <<~SRC
+ travel_to(1.day.ago) { create(:issue) }
+ SRC
+ end
+
+ it 'registers an offence' do
+ inspect_source(source)
+
+ expect(cop.offenses.size).to eq(1)
+ end
+
+ it 'can autocorrect the source' do
+ expect(autocorrect_source(source)).to eq(corrected_source)
+ end
+ end
+
+ context 'when calling a different method on Timecop' do
+ let(:source) do
+ <<~SRC
+ Timecop.freeze { create(:issue) }
+ SRC
+ end
+
+ it 'does not register an offence' do
+ inspect_source(source)
+
+ expect(cop.offenses).to be_empty
+ end
+ end
+end
diff --git a/spec/serializers/blob_entity_spec.rb b/spec/serializers/blob_entity_spec.rb
index b8c8c4c17de..27c62967755 100644
--- a/spec/serializers/blob_entity_spec.rb
+++ b/spec/serializers/blob_entity_spec.rb
@@ -22,7 +22,7 @@ RSpec.describe BlobEntity do
name: blob.name,
mode: "100644",
readable_text: true,
- icon: "file-text-o",
+ icon: "doc-text",
url: "/#{project.full_path}/-/blob/master/bar/branch-test.txt"
})
end
diff --git a/spec/serializers/ci/trigger_entity_spec.rb b/spec/serializers/ci/trigger_entity_spec.rb
new file mode 100644
index 00000000000..b2f3337d166
--- /dev/null
+++ b/spec/serializers/ci/trigger_entity_spec.rb
@@ -0,0 +1,70 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Ci::TriggerEntity do
+ let(:project) { create(:project) }
+ let(:trigger) { create(:ci_trigger, project: project, token: '237f3604900a4cd71ed06ef13e57b96d') }
+ let(:user) { create(:user) }
+ let(:entity) { described_class.new(trigger, current_user: user, project: project) }
+
+ describe '#as_json' do
+ let(:as_json) { entity.as_json }
+ let(:project_trigger_path) { "/#{project.full_path}/-/triggers/#{trigger.id}" }
+
+ it 'contains required fields' do
+ expect(as_json).to include(
+ :description, :owner, :last_used, :token, :has_token_exposed, :can_access_project
+ )
+ end
+
+ it 'contains user fields' do
+ expect(as_json[:owner].to_json).to match_schema('entities/user')
+ end
+
+ context 'when current user can manage triggers' do
+ before do
+ project.add_maintainer(user)
+ end
+
+ it 'returns short_token as token' do
+ expect(as_json[:token]).to eq(trigger.short_token)
+ end
+
+ it 'contains project_trigger_path' do
+ expect(as_json[:project_trigger_path]).to eq(project_trigger_path)
+ end
+
+ it 'does not contain edit_project_trigger_path' do
+ expect(as_json).not_to include(:edit_project_trigger_path)
+ end
+
+ it 'returns has_token_exposed' do
+ expect(as_json[:has_token_exposed]).to eq(false)
+ end
+ end
+
+ context 'when current user is the owner of the trigger' do
+ before do
+ project.add_maintainer(user)
+ trigger.update!(owner: user)
+ end
+
+ it 'returns token as token' do
+ expect(as_json[:token]).to eq(trigger.token)
+ end
+
+ it 'contains project_trigger_path' do
+ expect(as_json[:project_trigger_path]).to eq(project_trigger_path)
+ end
+
+ it 'contains edit_project_trigger_path' do
+ expect(as_json[:edit_project_trigger_path]).to eq("#{project_trigger_path}/edit")
+ end
+
+ it 'returns has_token_exposed' do
+ expect(as_json[:has_token_exposed]).to eq(true)
+ end
+ end
+ end
+end
diff --git a/spec/serializers/ci/trigger_serializer_spec.rb b/spec/serializers/ci/trigger_serializer_spec.rb
new file mode 100644
index 00000000000..a669a8c3ed0
--- /dev/null
+++ b/spec/serializers/ci/trigger_serializer_spec.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Ci::TriggerSerializer do
+ describe '#represent' do
+ let(:represent) { described_class.new.represent(trigger) }
+
+ let(:trigger) { build_stubbed(:ci_trigger) }
+
+ it 'matches schema' do
+ expect(represent.to_json).to match_schema('entities/trigger')
+ end
+ end
+end
diff --git a/spec/serializers/cluster_serializer_spec.rb b/spec/serializers/cluster_serializer_spec.rb
index 04999975276..e65e97b6ae0 100644
--- a/spec/serializers/cluster_serializer_spec.rb
+++ b/spec/serializers/cluster_serializer_spec.rb
@@ -13,6 +13,7 @@ RSpec.describe ClusterSerializer do
:cluster_type,
:enabled,
:environment_scope,
+ :id,
:gitlab_managed_apps_logs_path,
:enable_advanced_logs_querying,
:kubernetes_errors,
diff --git a/spec/serializers/deployment_entity_spec.rb b/spec/serializers/deployment_entity_spec.rb
index 27673b905d3..588675f5232 100644
--- a/spec/serializers/deployment_entity_spec.rb
+++ b/spec/serializers/deployment_entity_spec.rb
@@ -30,6 +30,10 @@ RSpec.describe DeploymentEntity do
expect(subject[:ref][:name]).to eq 'master'
end
+ it 'exposes status' do
+ expect(subject).to include(:status)
+ end
+
it 'exposes creation date' do
expect(subject).to include(:created_at)
end
diff --git a/spec/serializers/diff_file_base_entity_spec.rb b/spec/serializers/diff_file_base_entity_spec.rb
index 94c39e11790..99dbaff4b7e 100644
--- a/spec/serializers/diff_file_base_entity_spec.rb
+++ b/spec/serializers/diff_file_base_entity_spec.rb
@@ -3,10 +3,24 @@
require 'spec_helper'
RSpec.describe DiffFileBaseEntity do
- let(:project) { create(:project, :repository) }
+ include ProjectForksHelper
+
+ let_it_be(:project) { create(:project, :repository) }
+ let_it_be(:user) { create(:user) }
+
let(:repository) { project.repository }
let(:entity) { described_class.new(diff_file, options).as_json }
+ shared_examples 'nil if removed source branch' do |key|
+ before do
+ allow(merge_request).to receive(:source_branch_exists?).and_return(false)
+ end
+
+ specify do
+ expect(entity[key]).to eq(nil)
+ end
+ end
+
context 'submodule information for a' do
let(:commit_sha) { "" }
let(:commit) { project.commit(commit_sha) }
@@ -67,7 +81,7 @@ RSpec.describe DiffFileBaseEntity do
context 'edit_path' do
let(:diff_file) { merge_request.diffs.diff_files.to_a.last }
- let(:options) { { request: EntityRequest.new(current_user: create(:user)), merge_request: merge_request } }
+ let(:options) { { request: EntityRequest.new(current_user: user), merge_request: merge_request } }
let(:params) { {} }
shared_examples 'a diff file edit path to the source branch' do
@@ -81,16 +95,7 @@ RSpec.describe DiffFileBaseEntity do
let(:params) { { from_merge_request_iid: merge_request.iid } }
it_behaves_like 'a diff file edit path to the source branch'
-
- context 'removed source branch' do
- before do
- allow(merge_request).to receive(:source_branch_exists?).and_return(false)
- end
-
- it do
- expect(entity[:edit_path]).to eq(nil)
- end
- end
+ it_behaves_like 'nil if removed source branch', :edit_path
end
context 'closed' do
@@ -118,4 +123,30 @@ RSpec.describe DiffFileBaseEntity do
end
end
end
+
+ context 'ide_edit_path' do
+ let(:source_project) { project }
+ let(:merge_request) { create(:merge_request, iid: 123, target_project: target_project, source_project: source_project) }
+ let(:diff_file) { merge_request.diffs.diff_files.to_a.last }
+ let(:options) { { request: EntityRequest.new(current_user: user), merge_request: merge_request } }
+ let(:expected_merge_request_path) { "/-/ide/project/#{source_project.full_path}/merge_requests/#{merge_request.iid}" }
+
+ context 'when source_project and target_project are the same' do
+ let(:target_project) { source_project }
+
+ it_behaves_like 'nil if removed source branch', :ide_edit_path
+
+ it 'returns the merge_request ide route' do
+ expect(entity[:ide_edit_path]).to eq expected_merge_request_path
+ end
+ end
+
+ context 'when source_project and target_project are different' do
+ let(:target_project) { fork_project(source_project, source_project.owner, repository: true) }
+
+ it 'returns the merge_request ide route with the target_project as param' do
+ expect(entity[:ide_edit_path]).to eq("#{expected_merge_request_path}?target_project=#{ERB::Util.url_encode(target_project.full_path)}")
+ end
+ end
+ end
end
diff --git a/spec/serializers/diffs_entity_spec.rb b/spec/serializers/diffs_entity_spec.rb
index 7c59e4aed83..5928a1c24b3 100644
--- a/spec/serializers/diffs_entity_spec.rb
+++ b/spec/serializers/diffs_entity_spec.rb
@@ -68,15 +68,5 @@ RSpec.describe DiffsEntity do
end
end
end
-
- context 'when code_navigation feature flag is disabled' do
- it 'does not include code navigation properties' do
- stub_feature_flags(code_navigation: false)
-
- expect(Gitlab::CodeNavigationPath).not_to receive(:new)
-
- expect(subject).not_to include(:definition_path_prefix)
- end
- end
end
end
diff --git a/spec/serializers/discussion_entity_spec.rb b/spec/serializers/discussion_entity_spec.rb
index 306a4fa43a9..e1734d5290f 100644
--- a/spec/serializers/discussion_entity_spec.rb
+++ b/spec/serializers/discussion_entity_spec.rb
@@ -79,13 +79,5 @@ RSpec.describe DiscussionEntity do
:active
)
end
-
- context 'diff_head_compare feature is disabled' do
- it 'does not expose positions and line_codes attributes' do
- stub_feature_flags(merge_ref_head_comments: false)
-
- expect(subject.keys).not_to include(:positions, :line_codes)
- end
- end
end
end
diff --git a/spec/serializers/feature_flag_entity_spec.rb b/spec/serializers/feature_flag_entity_spec.rb
new file mode 100644
index 00000000000..21ecfe59c31
--- /dev/null
+++ b/spec/serializers/feature_flag_entity_spec.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe FeatureFlagEntity do
+ let(:feature_flag) { create(:operations_feature_flag, project: project) }
+ let(:project) { create(:project) }
+ let(:request) { double('request', current_user: user) }
+ let(:user) { create(:user) }
+ let(:entity) { described_class.new(feature_flag, request: request) }
+
+ before do
+ project.add_developer(user)
+ end
+
+ subject { entity.as_json }
+
+ it 'has feature flag attributes' do
+ expect(subject).to include(:id, :active, :created_at, :updated_at,
+ :description, :name, :edit_path, :destroy_path)
+ end
+end
diff --git a/spec/serializers/feature_flag_serializer_spec.rb b/spec/serializers/feature_flag_serializer_spec.rb
new file mode 100644
index 00000000000..fab8ca93b1b
--- /dev/null
+++ b/spec/serializers/feature_flag_serializer_spec.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe FeatureFlagSerializer do
+ let(:serializer) { described_class.new(project: project, current_user: user) }
+ let(:user) { create(:user) }
+ let(:project) { create(:project) }
+ let(:feature_flags) { create_list(:operations_feature_flag, 3) }
+
+ before do
+ project.add_developer(user)
+ end
+
+ describe '#represent' do
+ subject { serializer.represent(feature_flags) }
+
+ it 'includes feature flag attributes' do
+ is_expected.to all(include(:id, :active, :created_at, :updated_at,
+ :description, :name))
+ end
+ end
+end
diff --git a/spec/serializers/feature_flag_summary_entity_spec.rb b/spec/serializers/feature_flag_summary_entity_spec.rb
new file mode 100644
index 00000000000..385a9deb2d7
--- /dev/null
+++ b/spec/serializers/feature_flag_summary_entity_spec.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe FeatureFlagSummaryEntity do
+ let!(:feature_flag) { create(:operations_feature_flag, project: project) }
+ let(:project) { create(:project) }
+ let(:request) { double('request', current_user: user) }
+ let(:user) { create(:user) }
+ let(:entity) { described_class.new(project, request: request) }
+
+ before do
+ project.add_developer(user)
+ end
+
+ subject { entity.as_json }
+
+ it 'has summary information' do
+ expect(subject).to include(:count)
+ end
+end
diff --git a/spec/serializers/feature_flag_summary_serializer_spec.rb b/spec/serializers/feature_flag_summary_serializer_spec.rb
new file mode 100644
index 00000000000..79cef6765f7
--- /dev/null
+++ b/spec/serializers/feature_flag_summary_serializer_spec.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe FeatureFlagSummarySerializer do
+ let(:serializer) { described_class.new(project: project, current_user: user) }
+ let(:user) { create(:user) }
+ let(:project) { create(:project) }
+ let!(:feature_flags) { create(:operations_feature_flag, project: project) }
+
+ before do
+ project.add_developer(user)
+ end
+
+ describe '#represent' do
+ subject { serializer.represent(project) }
+
+ it 'has summary information' do
+ expect(subject).to include(:count)
+ end
+ end
+end
diff --git a/spec/serializers/feature_flags_client_serializer_spec.rb b/spec/serializers/feature_flags_client_serializer_spec.rb
new file mode 100644
index 00000000000..3746142a3f1
--- /dev/null
+++ b/spec/serializers/feature_flags_client_serializer_spec.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe FeatureFlagsClientSerializer do
+ let(:project) { create(:project) }
+ let(:feature_flags_client) { project.create_operations_feature_flags_client! }
+ let(:serializer) { described_class.new }
+
+ describe '#represent_token' do
+ subject { serializer.represent_token(feature_flags_client).to_json }
+
+ it 'includes feature flags client token' do
+ expect(subject).to match_schema('feature_flags_client_token')
+ end
+ end
+end
diff --git a/spec/serializers/group_group_link_entity_spec.rb b/spec/serializers/group_group_link_entity_spec.rb
index 8384563e3e6..9affe4af381 100644
--- a/spec/serializers/group_group_link_entity_spec.rb
+++ b/spec/serializers/group_group_link_entity_spec.rb
@@ -5,9 +5,27 @@ require 'spec_helper'
RSpec.describe GroupGroupLinkEntity do
include_context 'group_group_link'
- subject(:json) { described_class.new(group_group_link).to_json }
+ let_it_be(:current_user) { create(:user) }
+ let(:entity) { described_class.new(group_group_link) }
+
+ before do
+ allow(entity).to receive(:current_user).and_return(current_user)
+ end
it 'matches json schema' do
- expect(json).to match_schema('entities/group_group_link')
+ expect(entity.to_json).to match_schema('entities/group_group_link')
+ end
+
+ context 'a user with :admin_group_member permissions' do
+ before do
+ allow(entity).to receive(:can?).with(current_user, :admin_group_member, shared_group).and_return(true)
+ end
+
+ it 'sets `can_update` and `can_remove` to `true`' do
+ json = entity.as_json
+
+ expect(json[:can_update]).to be true
+ expect(json[:can_remove]).to be true
+ end
end
end
diff --git a/spec/serializers/import/bulk_import_entity_spec.rb b/spec/serializers/import/bulk_import_entity_spec.rb
new file mode 100644
index 00000000000..f35684bef20
--- /dev/null
+++ b/spec/serializers/import/bulk_import_entity_spec.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Import::BulkImportEntity do
+ let(:importable_data) do
+ {
+ 'id' => 1,
+ 'full_name' => 'test',
+ 'full_path' => 'full/path/test',
+ 'foo' => 'bar'
+ }
+ end
+
+ subject { described_class.represent(importable_data).as_json }
+
+ %w[id full_name full_path].each do |attribute|
+ it "exposes #{attribute}" do
+ expect(subject[attribute.to_sym]).to eq(importable_data[attribute])
+ end
+ end
+
+ it 'does not expose unspecified attributes' do
+ expect(subject[:foo]).to be_nil
+ end
+end
diff --git a/spec/serializers/label_serializer_spec.rb b/spec/serializers/label_serializer_spec.rb
index ae1466b16e5..40249450f7f 100644
--- a/spec/serializers/label_serializer_spec.rb
+++ b/spec/serializers/label_serializer_spec.rb
@@ -37,11 +37,12 @@ RSpec.describe LabelSerializer do
subject { serializer.represent_appearance(resource) }
it 'serializes only attributes used for appearance' do
- expect(subject.keys).to eq([:id, :title, :color, :text_color])
+ expect(subject.keys).to eq([:id, :title, :color, :project_id, :text_color])
expect(subject[:id]).to eq(resource.id)
expect(subject[:title]).to eq(resource.title)
expect(subject[:color]).to eq(resource.color)
expect(subject[:text_color]).to eq(resource.text_color)
+ expect(subject[:project_id]).to eq(resource.project_id)
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 51564de6041..031dc729a79 100644
--- a/spec/serializers/merge_request_poll_cached_widget_entity_spec.rb
+++ b/spec/serializers/merge_request_poll_cached_widget_entity_spec.rb
@@ -3,12 +3,11 @@
require 'spec_helper'
RSpec.describe MergeRequestPollCachedWidgetEntity do
- include ProjectForksHelper
using RSpec::Parameterized::TableSyntax
- let(:project) { create :project, :repository }
- let(:resource) { create(:merge_request, source_project: project, target_project: project) }
- let(:user) { create(:user) }
+ let_it_be(:project, refind: true) { create :project, :repository }
+ let_it_be(:resource, refind: true) { create(:merge_request, source_project: project, target_project: project) }
+ let_it_be(:user) { create(:user) }
let(:request) { double('request', current_user: user, project: project) }
@@ -174,8 +173,6 @@ RSpec.describe MergeRequestPollCachedWidgetEntity do
end
context 'when auto merge is not enabled' do
- let(:resource) { create(:merge_request) }
-
it 'returns auto merge related information' do
expect(subject[:auto_merge_enabled]).to be_falsy
end
@@ -215,15 +212,55 @@ RSpec.describe MergeRequestPollCachedWidgetEntity do
expect(subject[:commits_without_merge_commits].size).to eq(12)
end
end
+ end
- context 'when merge request is not mergeable' do
- before do
- allow(resource).to receive(:mergeable?).and_return(false)
+ describe 'pipeline' do
+ let_it_be(:pipeline) { create(:ci_empty_pipeline, project: project, ref: resource.source_branch, sha: resource.source_branch_sha, head_pipeline_of: resource) }
+
+ before do
+ allow_any_instance_of(MergeRequestPresenter).to receive(:can?).and_call_original
+ allow_any_instance_of(MergeRequestPresenter).to receive(:can?).with(user, :read_pipeline, anything).and_return(can_access)
+ end
+
+ context 'when user has access to pipelines' do
+ let(:can_access) { true }
+
+ context 'when is up to date' do
+ let(:req) { double('request', current_user: user, project: project) }
+
+ it 'returns pipeline' do
+ pipeline_payload =
+ MergeRequests::PipelineEntity
+ .represent(pipeline, request: req)
+ .as_json
+
+ expect(subject[:pipeline]).to eq(pipeline_payload)
+ end
+
+ context 'when merge_request_cached_pipeline_serializer is disabled' do
+ it 'does not return pipeline' do
+ stub_feature_flags(merge_request_cached_pipeline_serializer: false)
+
+ expect(subject[:pipeline]).to be_nil
+ end
+ end
+ end
+
+ context 'when user does not have access to pipelines' do
+ let(:can_access) { false }
+ let(:req) { double('request', current_user: user, project: project) }
+
+ it 'does not have pipeline' do
+ expect(subject[:pipeline]).to eq(nil)
+ end
end
- it 'does not have default_squash_commit_message and commits_without_merge_commits' do
- expect(subject[:default_squash_commit_message]).to eq(nil)
- expect(subject[:commits_without_merge_commits]).to eq(nil)
+ context 'when is not up to date' do
+ it 'returns nil' do
+ pipeline.update!(sha: "not up to date")
+
+ expect(subject[:pipeline]).to eq(nil)
+ end
end
end
end
diff --git a/spec/serializers/merge_request_poll_widget_entity_spec.rb b/spec/serializers/merge_request_poll_widget_entity_spec.rb
index 161940dd01a..1e5a8915da0 100644
--- a/spec/serializers/merge_request_poll_widget_entity_spec.rb
+++ b/spec/serializers/merge_request_poll_widget_entity_spec.rb
@@ -44,20 +44,6 @@ RSpec.describe MergeRequestPollWidgetEntity do
expect(subject[:merge_pipeline]).to eq(pipeline_payload)
end
- context 'when merge_request_short_pipeline_serializer is disabled' do
- it 'returns detailed info about pipeline' do
- stub_feature_flags(merge_request_short_pipeline_serializer: false)
-
- pipeline.reload
- pipeline_payload =
- PipelineDetailsEntity
- .represent(pipeline, request: request)
- .as_json
-
- expect(subject[:merge_pipeline]).to eq(pipeline_payload)
- end
- end
-
context 'when user cannot read pipelines on target project' do
before do
project.add_guest(user)
@@ -236,21 +222,16 @@ RSpec.describe MergeRequestPollWidgetEntity do
context 'when is up to date' do
let(:req) { double('request', current_user: user, project: project) }
- it 'returns pipeline' do
- pipeline_payload =
- MergeRequests::PipelineEntity
- .represent(pipeline, request: req)
- .as_json
-
- expect(subject[:pipeline]).to eq(pipeline_payload)
+ it 'does not return pipeline' do
+ expect(subject[:pipeline]).to be_nil
end
- context 'when merge_request_short_pipeline_serializer is disabled' do
+ context 'when merge_request_cached_pipeline_serializer is disabled' do
it 'returns detailed info about pipeline' do
- stub_feature_flags(merge_request_short_pipeline_serializer: false)
+ stub_feature_flags(merge_request_cached_pipeline_serializer: false)
pipeline_payload =
- PipelineDetailsEntity
+ MergeRequests::PipelineEntity
.represent(pipeline, request: req)
.as_json
@@ -276,10 +257,6 @@ RSpec.describe MergeRequestPollWidgetEntity do
let(:result) { false }
let(:req) { double('request', current_user: user, project: project) }
- it 'does not have pipeline' do
- expect(subject[:pipeline]).to eq(nil)
- end
-
it 'does not return ci_status' do
expect(subject[:ci_status]).to eq(nil)
end
diff --git a/spec/serializers/merge_request_widget_entity_spec.rb b/spec/serializers/merge_request_widget_entity_spec.rb
index 1432c4499ae..5cad35eaedf 100644
--- a/spec/serializers/merge_request_widget_entity_spec.rb
+++ b/spec/serializers/merge_request_widget_entity_spec.rb
@@ -88,25 +88,53 @@ RSpec.describe MergeRequestWidgetEntity do
end
describe 'codequality report artifacts', :request_store do
+ let(:merge_base_pipeline) { create(:ci_pipeline, :with_codequality_report, project: project) }
+
before do
project.add_developer(user)
allow(resource).to receive_messages(
+ merge_base_pipeline: merge_base_pipeline,
base_pipeline: pipeline,
head_pipeline: pipeline
)
end
- context "with report artifacts" do
+ context 'with report artifacts' do
let(:pipeline) { create(:ci_pipeline, :with_codequality_report, project: project) }
+ let(:generic_job_id) { pipeline.builds.first.id }
+ let(:merge_base_job_id) { merge_base_pipeline.builds.first.id }
- it "has data entry" do
- expect(subject).to include(:codeclimate)
+ it 'has head_path and base_path entries' do
+ expect(subject[:codeclimate][:head_path]).to be_present
+ expect(subject[:codeclimate][:base_path]).to be_present
+ end
+
+ context 'on pipelines for merged results' do
+ let(:pipeline) { create(:ci_pipeline, :merged_result_pipeline, :with_codequality_report, project: project) }
+
+ context 'with merge_base_pipelines enabled' do
+ it 'returns URLs from the head_pipeline and merge_base_pipeline' do
+ expect(subject[:codeclimate][:head_path]).to include("/jobs/#{generic_job_id}/artifacts/download?file_type=codequality")
+ expect(subject[:codeclimate][:base_path]).to include("/jobs/#{merge_base_job_id}/artifacts/download?file_type=codequality")
+ end
+ end
+
+ context 'with merge_base_pipelines disabled' do
+ before do
+ stub_feature_flags(merge_base_pipelines: false)
+ end
+
+ it 'returns URLs from the head_pipeline and base_pipeline' do
+ expect(subject[:codeclimate][:head_path]).to include("/jobs/#{generic_job_id}/artifacts/download?file_type=codequality")
+ expect(subject[:codeclimate][:base_path]).to include("/jobs/#{generic_job_id}/artifacts/download?file_type=codequality")
+ end
+ end
end
end
- context "without artifacts" do
- it "does not have data entry" do
+ context 'without artifacts' do
+ it 'does not have data entry' do
expect(subject).not_to include(:codeclimate)
end
end
@@ -271,9 +299,7 @@ RSpec.describe MergeRequestWidgetEntity do
describe 'user callouts' do
context 'when suggest pipeline feature is enabled' do
- before do
- stub_feature_flags(suggest_pipeline: true)
- end
+ subject { described_class.new(resource, request: request, experiment_enabled: :suggest_pipeline).as_json }
it 'provides a valid path value for user callout path' do
expect(subject[:user_callouts_path]).to eq '/-/user_callouts'
@@ -307,10 +333,6 @@ RSpec.describe MergeRequestWidgetEntity do
end
context 'when suggest pipeline feature is not enabled' do
- before do
- stub_feature_flags(suggest_pipeline: false)
- end
-
it 'provides no valid value for user callout path' do
expect(subject[:user_callouts_path]).to be_nil
end
@@ -354,4 +376,8 @@ RSpec.describe MergeRequestWidgetEntity do
expect(entity[:rebase_path]).to be_nil
end
end
+
+ it 'has security_reports_docs_path' do
+ expect(subject[:security_reports_docs_path]).not_to be_nil
+ end
end
diff --git a/spec/serializers/paginated_diff_entity_spec.rb b/spec/serializers/paginated_diff_entity_spec.rb
index a2c58baed55..821ed34d3ec 100644
--- a/spec/serializers/paginated_diff_entity_spec.rb
+++ b/spec/serializers/paginated_diff_entity_spec.rb
@@ -31,14 +31,4 @@ RSpec.describe PaginatedDiffEntity do
total_pages: 7
)
end
-
- context 'when code_navigation feature flag is disabled' do
- it 'does not execute Gitlab::CodeNavigationPath' do
- stub_feature_flags(code_navigation: false)
-
- expect(Gitlab::CodeNavigationPath).not_to receive(:new)
-
- subject
- end
- end
end
diff --git a/spec/serializers/pipeline_serializer_spec.rb b/spec/serializers/pipeline_serializer_spec.rb
index b42a4f6ad3f..e0f6ab68034 100644
--- a/spec/serializers/pipeline_serializer_spec.rb
+++ b/spec/serializers/pipeline_serializer_spec.rb
@@ -155,7 +155,7 @@ RSpec.describe PipelineSerializer do
it 'verifies number of queries', :request_store do
recorded = ActiveRecord::QueryRecorder.new { subject }
- expected_queries = Gitlab.ee? ? 43 : 40
+ expected_queries = Gitlab.ee? ? 39 : 36
expect(recorded.count).to be_within(2).of(expected_queries)
expect(recorded.cached_count).to eq(0)
@@ -176,7 +176,7 @@ RSpec.describe PipelineSerializer do
# pipeline. With the same ref this check is cached but if refs are
# different then there is an extra query per ref
# https://gitlab.com/gitlab-org/gitlab-foss/issues/46368
- expected_queries = Gitlab.ee? ? 49 : 46
+ expected_queries = Gitlab.ee? ? 42 : 39
expect(recorded.count).to be_within(2).of(expected_queries)
expect(recorded.cached_count).to eq(0)
@@ -199,11 +199,10 @@ RSpec.describe PipelineSerializer do
it 'verifies number of queries', :request_store do
recorded = ActiveRecord::QueryRecorder.new { subject }
- # 99 queries by default + 2 related to preloading
- # :source_pipeline and :source_job
# Existing numbers are high and require performance optimization
+ # Ongoing issue:
# https://gitlab.com/gitlab-org/gitlab/-/issues/225156
- expected_queries = Gitlab.ee? ? 95 : 86
+ expected_queries = Gitlab.ee? ? 85 : 76
expect(recorded.count).to be_within(2).of(expected_queries)
expect(recorded.cached_count).to eq(0)
diff --git a/spec/serializers/test_case_entity_spec.rb b/spec/serializers/test_case_entity_spec.rb
index 32e9562f4c1..45e63e3feec 100644
--- a/spec/serializers/test_case_entity_spec.rb
+++ b/spec/serializers/test_case_entity_spec.rb
@@ -19,6 +19,7 @@ RSpec.describe TestCaseEntity do
expect(subject[:status]).to eq('success')
expect(subject[:name]).to eq('Test#sum when a is 1 and b is 3 returns summary')
expect(subject[:classname]).to eq('spec.test_spec')
+ expect(subject[:file]).to eq('./spec/test_spec.rb')
expect(subject[:execution_time]).to eq(1.11)
end
end
@@ -30,6 +31,7 @@ RSpec.describe TestCaseEntity do
expect(subject[:status]).to eq('failed')
expect(subject[:name]).to eq('Test#sum when a is 1 and b is 3 returns summary')
expect(subject[:classname]).to eq('spec.test_spec')
+ expect(subject[:file]).to eq('./spec/test_spec.rb')
expect(subject[:execution_time]).to eq(2.22)
end
end
diff --git a/spec/services/admin/propagate_integration_service_spec.rb b/spec/services/admin/propagate_integration_service_spec.rb
index 49d974b7154..5df4d9db8b1 100644
--- a/spec/services/admin/propagate_integration_service_spec.rb
+++ b/spec/services/admin/propagate_integration_service_spec.rb
@@ -10,129 +10,73 @@ RSpec.describe Admin::PropagateIntegrationService do
stub_jira_service_test
end
- let(:excluded_attributes) { %w[id project_id group_id inherit_from_id instance created_at updated_at default] }
- let!(:project) { create(:project) }
- let!(:group) { create(:group) }
- let!(:instance_integration) do
- JiraService.create!(
- instance: true,
- active: true,
- push_events: true,
- url: 'http://update-jira.instance.com',
- username: 'user',
- password: 'secret'
- )
- end
+ let(:group) { create(:group) }
- let!(:inherited_integration) do
- JiraService.create!(
- project: create(:project),
- inherit_from_id: instance_integration.id,
- instance: false,
- active: true,
- push_events: false,
- url: 'http://jira.instance.com',
- username: 'user',
- password: 'secret'
- )
+ let_it_be(:project) { create(:project) }
+ let_it_be(:instance_integration) { create(:jira_service, :instance) }
+ let_it_be(:not_inherited_integration) { create(:jira_service, project: project) }
+ let_it_be(:inherited_integration) do
+ create(:jira_service, project: create(:project), inherit_from_id: instance_integration.id)
end
-
- let!(:not_inherited_integration) do
- JiraService.create!(
- project: create(:project),
- inherit_from_id: nil,
- instance: false,
- active: true,
- push_events: false,
- url: 'http://jira.instance.com',
- username: 'user',
- password: 'secret'
- )
+ let_it_be(:different_type_inherited_integration) do
+ create(:redmine_service, project: project, inherit_from_id: instance_integration.id)
end
- let!(:different_type_inherited_integration) do
- BambooService.create!(
- project: create(:project),
- inherit_from_id: instance_integration.id,
- instance: false,
- active: true,
- push_events: false,
- bamboo_url: 'http://gitlab.com',
- username: 'mic',
- password: 'password',
- build_key: 'build'
- )
- end
+ context 'with inherited integration' do
+ let(:integration) { inherited_integration }
- shared_examples 'inherits settings from integration' do
- it 'updates the inherited integrations' do
- described_class.propagate(instance_integration)
+ it 'calls to PropagateIntegrationProjectWorker' do
+ expect(PropagateIntegrationInheritWorker).to receive(:perform_async)
+ .with(instance_integration.id, inherited_integration.id, inherited_integration.id)
- expect(integration.reload.inherit_from_id).to eq(instance_integration.id)
- expect(integration.attributes.except(*excluded_attributes))
- .to eq(instance_integration.attributes.except(*excluded_attributes))
+ described_class.propagate(instance_integration)
end
+ end
- context 'integration with data fields' do
- let(:excluded_attributes) { %w[id service_id created_at updated_at] }
+ context 'with a project without integration' do
+ let(:another_project) { create(:project) }
- it 'updates the data fields from inherited integrations' do
- described_class.propagate(instance_integration)
+ it 'calls to PropagateIntegrationProjectWorker' do
+ expect(PropagateIntegrationProjectWorker).to receive(:perform_async)
+ .with(instance_integration.id, another_project.id, another_project.id)
- expect(integration.reload.data_fields.attributes.except(*excluded_attributes))
- .to eq(instance_integration.data_fields.attributes.except(*excluded_attributes))
- end
+ described_class.propagate(instance_integration)
end
end
- shared_examples 'does not inherit settings from integration' do
- it 'does not update the not inherited integrations' do
- described_class.propagate(instance_integration)
+ context 'with a group without integration' do
+ it 'calls to PropagateIntegrationProjectWorker' do
+ expect(PropagateIntegrationGroupWorker).to receive(:perform_async)
+ .with(instance_integration.id, group.id, group.id)
- expect(integration.reload.attributes.except(*excluded_attributes))
- .not_to eq(instance_integration.attributes.except(*excluded_attributes))
+ described_class.propagate(instance_integration)
end
end
- context 'update only inherited integrations' do
- it_behaves_like 'inherits settings from integration' do
- let(:integration) { inherited_integration }
- end
-
- it_behaves_like 'does not inherit settings from integration' do
- let(:integration) { not_inherited_integration }
- end
+ context 'for a group-level integration' do
+ let(:group_integration) { create(:jira_service, group: group, project: nil) }
- it_behaves_like 'does not inherit settings from integration' do
- let(:integration) { different_type_inherited_integration }
- end
+ context 'with a project without integration' do
+ let(:another_project) { create(:project, group: group) }
- it_behaves_like 'inherits settings from integration' do
- let(:integration) { project.jira_service }
- end
+ it 'calls to PropagateIntegrationProjectWorker' do
+ expect(PropagateIntegrationProjectWorker).to receive(:perform_async)
+ .with(group_integration.id, another_project.id, another_project.id)
- it_behaves_like 'inherits settings from integration' do
- let(:integration) { Service.find_by(group_id: group.id) }
+ described_class.propagate(group_integration)
+ end
end
- end
- it 'updates project#has_external_issue_tracker for issue tracker services' do
- described_class.propagate(instance_integration)
+ context 'with a group without integration' do
+ let(:subgroup) { create(:group, parent: group) }
- expect(project.reload.has_external_issue_tracker).to eq(true)
- end
-
- it 'updates project#has_external_wiki for external wiki services' do
- instance_integration = ExternalWikiService.create!(
- instance: true,
- active: true,
- push_events: false,
- external_wiki_url: 'http://external-wiki-url.com'
- )
-
- described_class.propagate(instance_integration)
+ it 'calls to PropagateIntegrationGroupWorker' do
+ expect(PropagateIntegrationGroupWorker).to receive(:perform_async)
+ .with(group_integration.id, subgroup.id, subgroup.id)
- expect(project.reload.has_external_wiki).to eq(true)
+ described_class.propagate(group_integration)
+ end
+ end
end
end
end
diff --git a/spec/services/admin/propagate_service_template_spec.rb b/spec/services/admin/propagate_service_template_spec.rb
index 15654653095..d95d31ceaea 100644
--- a/spec/services/admin/propagate_service_template_spec.rb
+++ b/spec/services/admin/propagate_service_template_spec.rb
@@ -4,6 +4,7 @@ require 'spec_helper'
RSpec.describe Admin::PropagateServiceTemplate do
describe '.propagate' do
+ let_it_be(:project) { create(:project) }
let!(:service_template) do
PushoverService.create!(
template: true,
@@ -19,124 +20,40 @@ RSpec.describe Admin::PropagateServiceTemplate do
)
end
- let!(:project) { create(:project) }
- let(:excluded_attributes) { %w[id project_id template created_at updated_at default] }
-
- it 'creates services for projects' do
- expect(project.pushover_service).to be_nil
+ it 'calls to PropagateIntegrationProjectWorker' do
+ expect(PropagateIntegrationProjectWorker).to receive(:perform_async)
+ .with(service_template.id, project.id, project.id)
described_class.propagate(service_template)
-
- expect(project.reload.pushover_service).to be_present
- end
-
- it 'creates services for a project that has another service' do
- BambooService.create!(
- active: true,
- project: project,
- properties: {
- bamboo_url: 'http://gitlab.com',
- username: 'mic',
- password: 'password',
- build_key: 'build'
- }
- )
-
- expect(project.pushover_service).to be_nil
-
- described_class.propagate(service_template)
-
- expect(project.reload.pushover_service).to be_present
- end
-
- it 'does not create the service if it exists already' do
- other_service = BambooService.create!(
- template: true,
- active: true,
- properties: {
- bamboo_url: 'http://gitlab.com',
- username: 'mic',
- password: 'password',
- build_key: 'build'
- }
- )
-
- Service.build_from_integration(project.id, service_template).save!
- Service.build_from_integration(project.id, other_service).save!
-
- expect { described_class.propagate(service_template) }
- .not_to change { Service.count }
end
- it 'creates the service containing the template attributes' do
- described_class.propagate(service_template)
-
- expect(project.pushover_service.properties).to eq(service_template.properties)
-
- expect(project.pushover_service.attributes.except(*excluded_attributes))
- .to eq(service_template.attributes.except(*excluded_attributes))
- end
-
- context 'service with data fields' do
- include JiraServiceHelper
-
- let(:service_template) do
- stub_jira_service_test
-
- JiraService.create!(
- template: true,
+ context 'with a project that has another service' do
+ before do
+ BambooService.create!(
active: true,
- push_events: false,
- url: 'http://jira.instance.com',
- username: 'user',
- password: 'secret'
+ project: project,
+ properties: {
+ bamboo_url: 'http://gitlab.com',
+ username: 'mic',
+ password: 'password',
+ build_key: 'build'
+ }
)
end
- it 'creates the service containing the template attributes' do
- described_class.propagate(service_template)
-
- expect(project.jira_service.attributes.except(*excluded_attributes))
- .to eq(service_template.attributes.except(*excluded_attributes))
-
- excluded_attributes = %w[id service_id created_at updated_at]
- expect(project.jira_service.data_fields.attributes.except(*excluded_attributes))
- .to eq(service_template.data_fields.attributes.except(*excluded_attributes))
- end
- end
-
- describe 'bulk update', :use_sql_query_cache do
- let(:project_total) { 5 }
-
- before do
- stub_const('Admin::PropagateServiceTemplate::BATCH_SIZE', 3)
-
- project_total.times { create(:project) }
+ it 'calls to PropagateIntegrationProjectWorker' do
+ expect(PropagateIntegrationProjectWorker).to receive(:perform_async)
+ .with(service_template.id, project.id, project.id)
described_class.propagate(service_template)
end
-
- it 'creates services for all projects' do
- expect(Service.all.reload.count).to eq(project_total + 2)
- end
- end
-
- describe 'external tracker' do
- it 'updates the project external tracker' do
- service_template.update!(category: 'issue_tracker')
-
- expect { described_class.propagate(service_template) }
- .to change { project.reload.has_external_issue_tracker }.to(true)
- end
end
- describe 'external wiki' do
- it 'updates the project external tracker' do
- service_template.update!(type: 'ExternalWikiService')
+ it 'does not create the service if it exists already' do
+ Service.build_from_integration(service_template, project_id: project.id).save!
- expect { described_class.propagate(service_template) }
- .to change { project.reload.has_external_wiki }.to(true)
- end
+ expect { described_class.propagate(service_template) }
+ .not_to change { Service.count }
end
end
end
diff --git a/spec/services/alert_management/alerts/update_service_spec.rb b/spec/services/alert_management/alerts/update_service_spec.rb
index ee04fc55984..4b47efca9ed 100644
--- a/spec/services/alert_management/alerts/update_service_spec.rb
+++ b/spec/services/alert_management/alerts/update_service_spec.rb
@@ -160,7 +160,7 @@ RSpec.describe AlertManagement::Alerts::UpdateService do
context 'when a status is included' do
let(:params) { { status: new_status } }
- let(:new_status) { AlertManagement::Alert::STATUSES[:acknowledged] }
+ let(:new_status) { :acknowledged }
it 'successfully changes the status' do
expect { response }.to change { alert.acknowledged? }.to(true)
@@ -171,13 +171,13 @@ RSpec.describe AlertManagement::Alerts::UpdateService do
it_behaves_like 'adds a system note'
context 'with unknown status' do
- let(:new_status) { -1 }
+ let(:new_status) { :unknown_status }
it_behaves_like 'error response', 'Invalid status'
end
context 'with resolving status' do
- let(:new_status) { AlertManagement::Alert::STATUSES[:resolved] }
+ let(:new_status) { :resolved }
it 'changes the status' do
expect { response }.to change { alert.resolved? }.to(true)
diff --git a/spec/services/alert_management/process_prometheus_alert_service_spec.rb b/spec/services/alert_management/process_prometheus_alert_service_spec.rb
index b14cc65506a..ae0b8d6d7ac 100644
--- a/spec/services/alert_management/process_prometheus_alert_service_spec.rb
+++ b/spec/services/alert_management/process_prometheus_alert_service_spec.rb
@@ -117,15 +117,19 @@ RSpec.describe AlertManagement::ProcessPrometheusAlertService do
end
context 'when alert cannot be created' do
+ let(:errors) { double(messages: { hosts: ['hosts array is over 255 chars'] })}
+
before do
- payload['annotations']['title'] = 'description' * 50
+ allow(service).to receive(:alert).and_call_original
+ allow(service).to receive_message_chain(:alert, :save).and_return(false)
+ allow(service).to receive_message_chain(:alert, :errors).and_return(errors)
end
it 'writes a warning to the log' do
expect(Gitlab::AppLogger).to receive(:warn).with(
message: 'Unable to create AlertManagement::Alert',
project_id: project.id,
- alert_errors: { title: ["is too long (maximum is 200 characters)"] }
+ alert_errors: { hosts: ['hosts array is over 255 chars'] }
)
execute
@@ -148,28 +152,20 @@ RSpec.describe AlertManagement::ProcessPrometheusAlertService do
expect { execute }.to change { alert.reload.resolved? }.to(true)
end
- [true, false].each do |state_tracking_enabled|
- context 'existing issue' do
- before do
- stub_feature_flags(track_resource_state_change_events: state_tracking_enabled)
- end
-
- let!(:alert) { create(:alert_management_alert, :with_issue, project: project, fingerprint: fingerprint) }
+ context 'existing issue' do
+ let!(:alert) { create(:alert_management_alert, :with_issue, project: project, fingerprint: fingerprint) }
- it 'closes the issue' do
- issue = alert.issue
+ it 'closes the issue' do
+ issue = alert.issue
- expect { execute }
- .to change { issue.reload.state }
- .from('opened')
- .to('closed')
- end
+ expect { execute }
+ .to change { issue.reload.state }
+ .from('opened')
+ .to('closed')
+ end
- if state_tracking_enabled
- specify { expect { execute }.to change(ResourceStateEvent, :count).by(1) }
- else
- specify { expect { execute }.to change(Note, :count).by(1) }
- end
+ it 'creates a resource state event' do
+ expect { execute }.to change(ResourceStateEvent, :count).by(1)
end
end
end
diff --git a/spec/services/audit_event_service_spec.rb b/spec/services/audit_event_service_spec.rb
index 93de2a23edc..3317fcf8444 100644
--- a/spec/services/audit_event_service_spec.rb
+++ b/spec/services/audit_event_service_spec.rb
@@ -57,7 +57,7 @@ RSpec.describe AuditEventService do
let(:audit_service) { described_class.new(user, user, with: 'standard') }
it 'creates an authentication event' do
- expect(AuthenticationEvent).to receive(:create).with(
+ expect(AuthenticationEvent).to receive(:new).with(
user: user,
user_name: user.name,
ip_address: user.current_sign_in_ip,
@@ -67,6 +67,17 @@ RSpec.describe AuditEventService do
audit_service.for_authentication.security_event
end
+
+ it 'tracks exceptions when the event cannot be created' do
+ allow(user).to receive_messages(current_sign_in_ip: 'invalid IP')
+
+ expect(Gitlab::ErrorTracking).to(
+ receive(:track_exception)
+ .with(ActiveRecord::RecordInvalid, audit_event_type: 'AuthenticationEvent').and_call_original
+ )
+
+ audit_service.for_authentication.security_event
+ end
end
end
diff --git a/spec/services/bulk_create_integration_service_spec.rb b/spec/services/bulk_create_integration_service_spec.rb
new file mode 100644
index 00000000000..5d896f78b35
--- /dev/null
+++ b/spec/services/bulk_create_integration_service_spec.rb
@@ -0,0 +1,107 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe BulkCreateIntegrationService do
+ include JiraServiceHelper
+
+ before do
+ stub_jira_service_test
+ end
+
+ let(:excluded_attributes) { %w[id project_id group_id inherit_from_id instance template created_at updated_at] }
+ let!(:instance_integration) { create(:jira_service, :instance) }
+ let!(:template_integration) { create(:jira_service, :template) }
+
+ shared_examples 'creates integration from batch ids' do
+ it 'updates the inherited integrations' do
+ described_class.new(integration, batch, association).execute
+
+ expect(created_integration.attributes.except(*excluded_attributes))
+ .to eq(integration.attributes.except(*excluded_attributes))
+ end
+
+ context 'integration with data fields' do
+ let(:excluded_attributes) { %w[id service_id created_at updated_at] }
+
+ it 'updates the data fields from inherited integrations' do
+ described_class.new(integration, batch, association).execute
+
+ expect(created_integration.reload.data_fields.attributes.except(*excluded_attributes))
+ .to eq(integration.data_fields.attributes.except(*excluded_attributes))
+ end
+ end
+ end
+
+ shared_examples 'updates inherit_from_id' do
+ it 'updates inherit_from_id attributes' do
+ described_class.new(integration, batch, association).execute
+
+ expect(created_integration.reload.inherit_from_id).to eq(integration.id)
+ end
+ end
+
+ shared_examples 'runs project callbacks' do
+ it 'updates projects#has_external_issue_tracker for issue tracker services' do
+ described_class.new(integration, batch, association).execute
+
+ expect(project.reload.has_external_issue_tracker).to eq(true)
+ end
+
+ context 'with an external wiki integration' do
+ let(:integration) do
+ ExternalWikiService.create!(
+ instance: true,
+ active: true,
+ push_events: false,
+ external_wiki_url: 'http://external-wiki-url.com'
+ )
+ end
+
+ it 'updates projects#has_external_wiki for external wiki services' do
+ described_class.new(integration, batch, association).execute
+
+ expect(project.reload.has_external_wiki).to eq(true)
+ end
+ end
+ end
+
+ context 'with an instance-level integration' do
+ let(:integration) { instance_integration }
+
+ context 'with a project association' do
+ let!(:project) { create(:project) }
+ let(:created_integration) { project.jira_service }
+ let(:batch) { Project.all }
+ let(:association) { 'project' }
+
+ it_behaves_like 'creates integration from batch ids'
+ it_behaves_like 'updates inherit_from_id'
+ it_behaves_like 'runs project callbacks'
+ end
+
+ context 'with a group association' do
+ let!(:group) { create(:group) }
+ let(:created_integration) { Service.find_by(group: group) }
+ let(:batch) { Group.all }
+ let(:association) { 'group' }
+
+ it_behaves_like 'creates integration from batch ids'
+ it_behaves_like 'updates inherit_from_id'
+ end
+ end
+
+ context 'with a template integration' do
+ let(:integration) { template_integration }
+
+ context 'with a project association' do
+ let!(:project) { create(:project) }
+ let(:created_integration) { project.jira_service }
+ let(:batch) { Project.all }
+ let(:association) { 'project' }
+
+ it_behaves_like 'creates integration from batch ids'
+ it_behaves_like 'runs project callbacks'
+ end
+ end
+end
diff --git a/spec/services/bulk_update_integration_service_spec.rb b/spec/services/bulk_update_integration_service_spec.rb
new file mode 100644
index 00000000000..2f0bfd31600
--- /dev/null
+++ b/spec/services/bulk_update_integration_service_spec.rb
@@ -0,0 +1,57 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe BulkUpdateIntegrationService do
+ include JiraServiceHelper
+
+ before do
+ stub_jira_service_test
+ end
+
+ let(:excluded_attributes) { %w[id project_id group_id inherit_from_id instance template created_at updated_at] }
+ let!(:instance_integration) do
+ JiraService.create!(
+ instance: true,
+ active: true,
+ push_events: true,
+ url: 'http://update-jira.instance.com',
+ username: 'user',
+ password: 'secret'
+ )
+ end
+
+ let!(:integration) do
+ JiraService.create!(
+ project: create(:project),
+ inherit_from_id: instance_integration.id,
+ instance: false,
+ active: true,
+ push_events: false,
+ url: 'http://jira.instance.com',
+ username: 'user',
+ password: 'secret'
+ )
+ end
+
+ context 'with inherited integration' do
+ it 'updates the integration' do
+ described_class.new(instance_integration, Service.inherit_from_id(instance_integration.id)).execute
+
+ expect(integration.reload.inherit_from_id).to eq(instance_integration.id)
+ expect(integration.attributes.except(*excluded_attributes))
+ .to eq(instance_integration.attributes.except(*excluded_attributes))
+ end
+
+ context 'with integration with data fields' do
+ let(:excluded_attributes) { %w[id service_id created_at updated_at] }
+
+ it 'updates the data fields from the integration' do
+ described_class.new(instance_integration, Service.inherit_from_id(instance_integration.id)).execute
+
+ expect(integration.reload.data_fields.attributes.except(*excluded_attributes))
+ .to eq(instance_integration.data_fields.attributes.except(*excluded_attributes))
+ end
+ end
+ end
+end
diff --git a/spec/services/ci/build_report_result_service_spec.rb b/spec/services/ci/build_report_result_service_spec.rb
index 70bcf74ba43..134b662a72a 100644
--- a/spec/services/ci/build_report_result_service_spec.rb
+++ b/spec/services/ci/build_report_result_service_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe Ci::BuildReportResultService do
- describe "#execute" do
+ describe '#execute', :clean_gitlab_redis_shared_state do
subject(:build_report_result) { described_class.new.execute(build) }
context 'when build is finished' do
@@ -17,6 +17,25 @@ RSpec.describe Ci::BuildReportResultService do
expect(build_report_result.tests_skipped).to eq(0)
expect(build_report_result.tests_duration).to eq(0.010284)
expect(Ci::BuildReportResult.count).to eq(1)
+
+ unique_test_cases_parsed = Gitlab::UsageDataCounters::HLLRedisCounter.unique_events(
+ event_names: described_class::EVENT_NAME,
+ start_date: 2.weeks.ago,
+ end_date: 2.weeks.from_now
+ )
+ expect(unique_test_cases_parsed).to eq(4)
+ end
+
+ context 'when feature flag for tracking is disabled' do
+ before do
+ stub_feature_flags(track_unique_test_cases_parsed: false)
+ end
+
+ it 'creates the report but does not track the event' do
+ expect(Gitlab::UsageDataCounters::HLLRedisCounter).not_to receive(:track_event)
+ expect(build_report_result.tests_name).to eq("test")
+ expect(Ci::BuildReportResult.count).to eq(1)
+ end
end
context 'when data has already been persisted' do
diff --git a/spec/services/ci/create_downstream_pipeline_service_spec.rb b/spec/services/ci/create_downstream_pipeline_service_spec.rb
index a6ea30e4703..0cc380439a7 100644
--- a/spec/services/ci/create_downstream_pipeline_service_spec.rb
+++ b/spec/services/ci/create_downstream_pipeline_service_spec.rb
@@ -325,20 +325,6 @@ RSpec.describe Ci::CreateDownstreamPipelineService, '#execute' do
expect(bridge.reload).to be_success
end
-
- context 'when FF ci_child_of_child_pipeline is disabled' do
- before do
- stub_feature_flags(ci_child_of_child_pipeline: false)
- end
-
- it 'does not create a further child pipeline' do
- expect { service.execute(bridge) }
- .not_to change { Ci::Pipeline.count }
-
- expect(bridge.reload).to be_failed
- expect(bridge.failure_reason).to eq 'bridge_pipeline_is_child_pipeline'
- end
- end
end
context 'when upstream pipeline has a parent pipeline, which has a parent pipeline' do
diff --git a/spec/services/ci/create_pipeline_service/cache_spec.rb b/spec/services/ci/create_pipeline_service/cache_spec.rb
index 614e46f1b1a..1438c2e4aa0 100644
--- a/spec/services/ci/create_pipeline_service/cache_spec.rb
+++ b/spec/services/ci/create_pipeline_service/cache_spec.rb
@@ -36,7 +36,8 @@ RSpec.describe Ci::CreatePipelineService do
'key' => 'a-key',
'paths' => ['logs/', 'binaries/'],
'policy' => 'pull-push',
- 'untracked' => true
+ 'untracked' => true,
+ 'when' => 'on_success'
}
expect(pipeline).to be_persisted
@@ -67,7 +68,8 @@ RSpec.describe Ci::CreatePipelineService do
expected = {
'key' => /[a-f0-9]{40}/,
'paths' => ['logs/'],
- 'policy' => 'pull-push'
+ 'policy' => 'pull-push',
+ 'when' => 'on_success'
}
expect(pipeline).to be_persisted
@@ -82,7 +84,8 @@ RSpec.describe Ci::CreatePipelineService do
expected = {
'key' => /default/,
'paths' => ['logs/'],
- 'policy' => 'pull-push'
+ 'policy' => 'pull-push',
+ 'when' => 'on_success'
}
expect(pipeline).to be_persisted
@@ -114,7 +117,8 @@ RSpec.describe Ci::CreatePipelineService do
expected = {
'key' => /\$ENV_VAR-[a-f0-9]{40}/,
'paths' => ['logs/'],
- 'policy' => 'pull-push'
+ 'policy' => 'pull-push',
+ 'when' => 'on_success'
}
expect(pipeline).to be_persisted
@@ -129,7 +133,8 @@ RSpec.describe Ci::CreatePipelineService do
expected = {
'key' => /\$ENV_VAR-default/,
'paths' => ['logs/'],
- 'policy' => 'pull-push'
+ 'policy' => 'pull-push',
+ 'when' => 'on_success'
}
expect(pipeline).to be_persisted
diff --git a/spec/services/ci/create_pipeline_service/parent_child_pipeline_spec.rb b/spec/services/ci/create_pipeline_service/parent_child_pipeline_spec.rb
index 016a5dfd18b..fb6cdf55be3 100644
--- a/spec/services/ci/create_pipeline_service/parent_child_pipeline_spec.rb
+++ b/spec/services/ci/create_pipeline_service/parent_child_pipeline_spec.rb
@@ -22,7 +22,7 @@ RSpec.describe Ci::CreatePipelineService, '#execute' do
end
shared_examples 'successful creation' do
- it 'creates bridge jobs correctly' do
+ it 'creates bridge jobs correctly', :aggregate_failures do
pipeline = create_pipeline!
test = pipeline.statuses.find_by(name: 'test')
@@ -221,6 +221,65 @@ RSpec.describe Ci::CreatePipelineService, '#execute' do
end
end
end
+
+ context 'when including configs from a project' do
+ context 'when specifying all attributes' do
+ let(:config) do
+ <<~YAML
+ test:
+ script: rspec
+ deploy:
+ variables:
+ CROSS: downstream
+ stage: deploy
+ trigger:
+ include:
+ - project: my-namespace/my-project
+ file: 'path/to/child.yml'
+ ref: 'master'
+ YAML
+ end
+
+ it_behaves_like 'successful creation' do
+ let(:expected_bridge_options) do
+ {
+ 'trigger' => {
+ 'include' => [
+ {
+ 'file' => 'path/to/child.yml',
+ 'project' => 'my-namespace/my-project',
+ 'ref' => 'master'
+ }
+ ]
+ }
+ }
+ end
+ end
+ end
+
+ context 'without specifying file' do
+ let(:config) do
+ <<~YAML
+ test:
+ script: rspec
+ deploy:
+ variables:
+ CROSS: downstream
+ stage: deploy
+ trigger:
+ include:
+ - project: my-namespace/my-project
+ ref: 'master'
+ YAML
+ end
+
+ it_behaves_like 'creation failure' do
+ let(:expected_error) do
+ /include config must specify the file where to fetch the config from/
+ end
+ end
+ end
+ end
end
def create_pipeline!
diff --git a/spec/services/ci/create_pipeline_service_spec.rb b/spec/services/ci/create_pipeline_service_spec.rb
index e0893ed6de3..c28c3449485 100644
--- a/spec/services/ci/create_pipeline_service_spec.rb
+++ b/spec/services/ci/create_pipeline_service_spec.rb
@@ -731,30 +731,11 @@ RSpec.describe Ci::CreatePipelineService do
.and_call_original
end
- context 'when ci_pipeline_rewind_iid is enabled' do
- before do
- stub_feature_flags(ci_pipeline_rewind_iid: true)
- end
-
- it 'rewinds iid' do
- result = execute_service
-
- expect(result).not_to be_persisted
- expect(internal_id.last_value).to eq(0)
- end
- end
-
- context 'when ci_pipeline_rewind_iid is disabled' do
- before do
- stub_feature_flags(ci_pipeline_rewind_iid: false)
- end
-
- it 'does not rewind iid' do
- result = execute_service
+ it 'rewinds iid' do
+ result = execute_service
- expect(result).not_to be_persisted
- expect(internal_id.last_value).to eq(1)
- end
+ expect(result).not_to be_persisted
+ expect(internal_id.last_value).to eq(0)
end
end
end
diff --git a/spec/services/ci/delete_objects_service_spec.rb b/spec/services/ci/delete_objects_service_spec.rb
new file mode 100644
index 00000000000..448f8979681
--- /dev/null
+++ b/spec/services/ci/delete_objects_service_spec.rb
@@ -0,0 +1,133 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Ci::DeleteObjectsService, :aggregate_failure do
+ let(:service) { described_class.new }
+ let(:artifact) { create(:ci_job_artifact, :archive) }
+ let(:data) { [artifact] }
+
+ describe '#execute' do
+ before do
+ Ci::DeletedObject.bulk_import(data)
+ # We disable the check because the specs are wrapped in a transaction
+ allow(service).to receive(:transaction_open?).and_return(false)
+ end
+
+ subject(:execute) { service.execute }
+
+ it 'deletes records' do
+ expect { execute }.to change { Ci::DeletedObject.count }.by(-1)
+ end
+
+ it 'deletes files' do
+ expect { execute }.to change { artifact.file.exists? }
+ end
+
+ context 'when trying to execute without records' do
+ let(:data) { [] }
+
+ it 'does not change the number of objects' do
+ expect { execute }.not_to change { Ci::DeletedObject.count }
+ end
+ end
+
+ context 'when trying to remove the same file multiple times' do
+ let(:objects) { Ci::DeletedObject.all.to_a }
+
+ before do
+ expect(service).to receive(:load_next_batch).twice.and_return(objects)
+ end
+
+ it 'executes successfully' do
+ 2.times { expect(service.execute).to be_truthy }
+ end
+ end
+
+ context 'with artifacts both ready and not ready for deletion' do
+ let(:data) { [] }
+
+ let_it_be(:past_ready) { create(:ci_deleted_object, pick_up_at: 2.days.ago) }
+ let_it_be(:ready) { create(:ci_deleted_object, pick_up_at: 1.day.ago) }
+
+ it 'skips records with pick_up_at in the future' do
+ not_ready = create(:ci_deleted_object, pick_up_at: 1.day.from_now)
+
+ expect { execute }.to change { Ci::DeletedObject.count }.from(3).to(1)
+ expect(not_ready.reload.present?).to be_truthy
+ end
+
+ it 'limits the number of records removed' do
+ stub_const("#{described_class}::BATCH_SIZE", 1)
+
+ expect { execute }.to change { Ci::DeletedObject.count }.by(-1)
+ end
+
+ it 'removes records in order' do
+ stub_const("#{described_class}::BATCH_SIZE", 1)
+
+ execute
+
+ expect { past_ready.reload }.to raise_error(ActiveRecord::RecordNotFound)
+ expect(ready.reload.present?).to be_truthy
+ end
+
+ it 'updates pick_up_at timestamp' do
+ allow(service).to receive(:destroy_everything)
+
+ execute
+
+ expect(past_ready.reload.pick_up_at).to be_like_time(10.minutes.from_now)
+ end
+
+ it 'does not delete objects for which file deletion has failed' do
+ expect(past_ready)
+ .to receive(:delete_file_from_storage)
+ .and_return(false)
+
+ expect(service)
+ .to receive(:load_next_batch)
+ .and_return([past_ready, ready])
+
+ expect { execute }.to change { Ci::DeletedObject.count }.from(2).to(1)
+ expect(past_ready.reload.present?).to be_truthy
+ end
+ end
+
+ context 'with an open database transaction' do
+ it 'raises an exception and does not remove records' do
+ expect(service).to receive(:transaction_open?).and_return(true)
+
+ expect { execute }
+ .to raise_error(Ci::DeleteObjectsService::TransactionInProgressError)
+ .and change { Ci::DeletedObject.count }.by(0)
+ end
+ end
+ end
+
+ describe '#remaining_batches_count' do
+ subject { service.remaining_batches_count(max_batch_count: 3) }
+
+ context 'when there is less than one batch size' do
+ before do
+ Ci::DeletedObject.bulk_import(data)
+ end
+
+ it { is_expected.to eq(1) }
+ end
+
+ context 'when there is more than one batch size' do
+ before do
+ objects_scope = double
+
+ expect(Ci::DeletedObject)
+ .to receive(:ready_for_destruction)
+ .and_return(objects_scope)
+
+ expect(objects_scope).to receive(:size).and_return(110)
+ end
+
+ it { is_expected.to eq(2) }
+ end
+ end
+end
diff --git a/spec/services/ci/destroy_expired_job_artifacts_service_spec.rb b/spec/services/ci/destroy_expired_job_artifacts_service_spec.rb
index 1c96be42a2f..3d5329811ad 100644
--- a/spec/services/ci/destroy_expired_job_artifacts_service_spec.rb
+++ b/spec/services/ci/destroy_expired_job_artifacts_service_spec.rb
@@ -9,9 +9,10 @@ RSpec.describe Ci::DestroyExpiredJobArtifactsService, :clean_gitlab_redis_shared
subject { service.execute }
let(:service) { described_class.new }
- let!(:artifact) { create(:ci_job_artifact, expire_at: 1.day.ago) }
- before do
+ let_it_be(:artifact) { create(:ci_job_artifact, expire_at: 1.day.ago) }
+
+ before(:all) do
artifact.job.pipeline.unlocked!
end
@@ -38,7 +39,9 @@ RSpec.describe Ci::DestroyExpiredJobArtifactsService, :clean_gitlab_redis_shared
end
context 'when artifact is not expired' do
- let!(:artifact) { create(:ci_job_artifact, expire_at: 1.day.since) }
+ before do
+ artifact.update_column(:expire_at, 1.day.since)
+ end
it 'does not destroy expired job artifacts' do
expect { subject }.not_to change { Ci::JobArtifact.count }
@@ -46,7 +49,9 @@ RSpec.describe Ci::DestroyExpiredJobArtifactsService, :clean_gitlab_redis_shared
end
context 'when artifact is permanent' do
- let!(:artifact) { create(:ci_job_artifact, expire_at: nil) }
+ before do
+ artifact.update_column(:expire_at, nil)
+ end
it 'does not destroy expired job artifacts' do
expect { subject }.not_to change { Ci::JobArtifact.count }
diff --git a/spec/services/ci/expire_pipeline_cache_service_spec.rb b/spec/services/ci/expire_pipeline_cache_service_spec.rb
index b5d664947de..8df5d0bc159 100644
--- a/spec/services/ci/expire_pipeline_cache_service_spec.rb
+++ b/spec/services/ci/expire_pipeline_cache_service_spec.rb
@@ -26,9 +26,11 @@ RSpec.describe Ci::ExpirePipelineCacheService do
project = merge_request.target_project
merge_request_pipelines_path = "/#{project.full_path}/-/merge_requests/#{merge_request.iid}/pipelines.json"
+ merge_request_widget_path = "/#{project.full_path}/-/merge_requests/#{merge_request.iid}/cached_widget.json"
allow_any_instance_of(Gitlab::EtagCaching::Store).to receive(:touch)
expect_any_instance_of(Gitlab::EtagCaching::Store).to receive(:touch).with(merge_request_pipelines_path)
+ expect_any_instance_of(Gitlab::EtagCaching::Store).to receive(:touch).with(merge_request_widget_path)
subject.execute(merge_request.all_pipelines.last)
end
diff --git a/spec/services/ci/list_config_variables_service_spec.rb b/spec/services/ci/list_config_variables_service_spec.rb
new file mode 100644
index 00000000000..5cc0481768b
--- /dev/null
+++ b/spec/services/ci/list_config_variables_service_spec.rb
@@ -0,0 +1,77 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Ci::ListConfigVariablesService do
+ let_it_be(:project) { create(:project, :repository) }
+ let(:service) { described_class.new(project) }
+ let(:result) { YAML.dump(ci_config) }
+
+ subject { service.execute(sha) }
+
+ before do
+ stub_gitlab_ci_yml_for_sha(sha, result)
+ end
+
+ context 'when sending a valid sha' do
+ let(:sha) { 'master' }
+ let(:ci_config) do
+ {
+ variables: {
+ KEY1: { value: 'val 1', description: 'description 1' },
+ KEY2: { value: 'val 2', description: '' },
+ KEY3: { value: 'val 3' },
+ KEY4: 'val 4'
+ },
+ test: {
+ stage: 'test',
+ script: 'echo'
+ }
+ }
+ end
+
+ it 'returns variable list' do
+ expect(subject['KEY1']).to eq({ value: 'val 1', description: 'description 1' })
+ expect(subject['KEY2']).to eq({ value: 'val 2', description: '' })
+ expect(subject['KEY3']).to eq({ value: 'val 3', description: nil })
+ expect(subject['KEY4']).to eq({ value: 'val 4', description: nil })
+ end
+ end
+
+ context 'when sending an invalid sha' do
+ let(:sha) { 'invalid-sha' }
+ let(:ci_config) { nil }
+
+ it 'returns empty json' do
+ expect(subject).to eq({})
+ end
+ end
+
+ context 'when sending an invalid config' do
+ let(:sha) { 'master' }
+ let(:ci_config) do
+ {
+ variables: {
+ KEY1: { value: 'val 1', description: 'description 1' }
+ },
+ test: {
+ stage: 'invalid',
+ script: 'echo'
+ }
+ }
+ end
+
+ it 'returns empty result' do
+ expect(subject).to eq({})
+ end
+ end
+
+ private
+
+ def stub_gitlab_ci_yml_for_sha(sha, result)
+ allow_any_instance_of(Repository)
+ .to receive(:gitlab_ci_yml_for)
+ .with(sha, '.gitlab-ci.yml')
+ .and_return(result)
+ end
+end
diff --git a/spec/services/ci/pipeline_processing/shared_processing_service.rb b/spec/services/ci/pipeline_processing/shared_processing_service.rb
index 7de22b6a4cc..bbd7422b435 100644
--- a/spec/services/ci/pipeline_processing/shared_processing_service.rb
+++ b/spec/services/ci/pipeline_processing/shared_processing_service.rb
@@ -259,14 +259,14 @@ RSpec.shared_examples 'Pipeline Processing Service' do
expect(builds_names_and_statuses).to eq({ 'build': 'success', 'rollout10%': 'scheduled' })
- Timecop.travel 2.minutes.from_now do
+ travel_to 2.minutes.from_now do
enqueue_scheduled('rollout10%')
end
succeed_pending
expect(builds_names_and_statuses).to eq({ 'build': 'success', 'rollout10%': 'success', 'rollout100%': 'scheduled' })
- Timecop.travel 2.minutes.from_now do
+ travel_to 2.minutes.from_now do
enqueue_scheduled('rollout100%')
end
succeed_pending
@@ -330,7 +330,7 @@ RSpec.shared_examples 'Pipeline Processing Service' do
expect(builds_names_and_statuses).to eq({ 'build': 'success', 'rollout10%': 'scheduled' })
- Timecop.travel 2.minutes.from_now do
+ travel_to 2.minutes.from_now do
enqueue_scheduled('rollout10%')
end
fail_running_or_pending
@@ -398,7 +398,7 @@ RSpec.shared_examples 'Pipeline Processing Service' do
expect(process_pipeline).to be_truthy
expect(builds_names_and_statuses).to eq({ 'delayed1': 'scheduled', 'delayed2': 'scheduled' })
- Timecop.travel 2.minutes.from_now do
+ travel_to 2.minutes.from_now do
enqueue_scheduled('delayed1')
end
@@ -419,7 +419,7 @@ RSpec.shared_examples 'Pipeline Processing Service' do
expect(process_pipeline).to be_truthy
expect(builds_names_and_statuses).to eq({ 'delayed': 'scheduled' })
- Timecop.travel 2.minutes.from_now do
+ travel_to 2.minutes.from_now do
enqueue_scheduled('delayed')
end
fail_running_or_pending
diff --git a/spec/services/ci/pipeline_processing/shared_processing_service_tests_with_yaml.rb b/spec/services/ci/pipeline_processing/shared_processing_service_tests_with_yaml.rb
index 77645298bc7..2936d6fae4d 100644
--- a/spec/services/ci/pipeline_processing/shared_processing_service_tests_with_yaml.rb
+++ b/spec/services/ci/pipeline_processing/shared_processing_service_tests_with_yaml.rb
@@ -43,12 +43,12 @@ RSpec.shared_context 'Pipeline Processing Service Tests With Yaml' do
{
pipeline: pipeline.status,
stages: pipeline.stages.pluck(:name, :status).to_h,
- jobs: pipeline.statuses.latest.pluck(:name, :status).to_h
+ jobs: pipeline.latest_statuses.pluck(:name, :status).to_h
}
end
def event_on_jobs(event, job_names)
- statuses = pipeline.statuses.latest.by_name(job_names).to_a
+ 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 { |status| status.public_send("#{event}!") }
diff --git a/spec/services/ci/pipelines/create_artifact_service_spec.rb b/spec/services/ci/pipelines/create_artifact_service_spec.rb
index d5e9cf83a6d..6f177889ed3 100644
--- a/spec/services/ci/pipelines/create_artifact_service_spec.rb
+++ b/spec/services/ci/pipelines/create_artifact_service_spec.rb
@@ -35,16 +35,6 @@ RSpec.describe ::Ci::Pipelines::CreateArtifactService do
end
end
- context 'when feature is disabled' do
- it 'does not create a pipeline artifact' do
- stub_feature_flags(coverage_report_view: false)
-
- subject
-
- expect(Ci::PipelineArtifact.count).to eq(0)
- end
- end
-
context 'when pipeline artifact has already been created' do
it 'do not raise an error and do not persist the same artifact twice' do
expect { 2.times { described_class.new.execute(pipeline) } }.not_to raise_error(ActiveRecord::RecordNotUnique)
diff --git a/spec/services/ci/play_bridge_service_spec.rb b/spec/services/ci/play_bridge_service_spec.rb
new file mode 100644
index 00000000000..0482ad4d76f
--- /dev/null
+++ b/spec/services/ci/play_bridge_service_spec.rb
@@ -0,0 +1,56 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Ci::PlayBridgeService, '#execute' do
+ let(:project) { create(:project) }
+ let(:user) { create(:user) }
+ let(:pipeline) { create(:ci_pipeline, project: project) }
+ let(:downstream_project) { create(:project) }
+ let(:bridge) { create(:ci_bridge, :playable, pipeline: pipeline, downstream: downstream_project) }
+ let(:instance) { described_class.new(project, user) }
+
+ subject(:execute_service) { instance.execute(bridge) }
+
+ context 'when user can run the bridge' do
+ before do
+ allow(instance).to receive(:can?).with(user, :play_job, bridge).and_return(true)
+ end
+
+ it 'marks the bridge pending' do
+ execute_service
+
+ expect(bridge.reload).to be_pending
+ end
+
+ it 'enqueues Ci::CreateCrossProjectPipelineWorker' do
+ expect(::Ci::CreateCrossProjectPipelineWorker).to receive(:perform_async).with(bridge.id)
+
+ execute_service
+ end
+
+ it "updates bridge's user" do
+ execute_service
+
+ expect(bridge.reload.user).to eq(user)
+ end
+
+ context 'when bridge is not playable' do
+ let(:bridge) { create(:ci_bridge, :failed, pipeline: pipeline, downstream: downstream_project) }
+
+ it 'raises StateMachines::InvalidTransition' do
+ expect { execute_service }.to raise_error StateMachines::InvalidTransition
+ end
+ end
+ end
+
+ context 'when user can not run the bridge' do
+ before do
+ allow(instance).to receive(:can?).with(user, :play_job, bridge).and_return(false)
+ end
+
+ it 'allows user with developer role to play a bridge' do
+ expect { execute_service }.to raise_error Gitlab::Access::AccessDeniedError
+ end
+ end
+end
diff --git a/spec/services/ci/play_manual_stage_service_spec.rb b/spec/services/ci/play_manual_stage_service_spec.rb
index e30ec8bfda5..3e2a95ee975 100644
--- a/spec/services/ci/play_manual_stage_service_spec.rb
+++ b/spec/services/ci/play_manual_stage_service_spec.rb
@@ -6,6 +6,7 @@ RSpec.describe Ci::PlayManualStageService, '#execute' do
let(:current_user) { create(:user) }
let(:pipeline) { create(:ci_pipeline, user: current_user) }
let(:project) { pipeline.project }
+ let(:downstream_project) { create(:project) }
let(:service) { described_class.new(project, current_user, pipeline: pipeline) }
let(:stage_status) { 'manual' }
@@ -18,40 +19,42 @@ RSpec.describe Ci::PlayManualStageService, '#execute' do
before do
project.add_maintainer(current_user)
+ downstream_project.add_maintainer(current_user)
create_builds_for_stage(status: stage_status)
+ create_bridge_for_stage(status: stage_status)
end
- context 'when pipeline has manual builds' do
+ context 'when pipeline has manual processables' do
before do
service.execute(stage)
end
- it 'starts manual builds from pipeline' do
- expect(pipeline.builds.manual.count).to eq(0)
+ it 'starts manual processables from pipeline' do
+ expect(pipeline.processables.manual.count).to eq(0)
end
- it 'updates manual builds' do
- pipeline.builds.each do |build|
- expect(build.user).to eq(current_user)
+ it 'updates manual processables' do
+ pipeline.processables.each do |processable|
+ expect(processable.user).to eq(current_user)
end
end
end
- context 'when pipeline has no manual builds' do
+ context 'when pipeline has no manual processables' do
let(:stage_status) { 'failed' }
before do
service.execute(stage)
end
- it 'does not update the builds' do
- expect(pipeline.builds.failed.count).to eq(3)
+ it 'does not update the processables' do
+ expect(pipeline.processables.failed.count).to eq(4)
end
end
- context 'when user does not have permission on a specific build' do
+ context 'when user does not have permission on a specific processable' do
before do
- allow_next_instance_of(Ci::Build) do |instance|
+ allow_next_instance_of(Ci::Processable) do |instance|
allow(instance).to receive(:play).and_raise(Gitlab::Access::AccessDeniedError)
end
@@ -60,12 +63,14 @@ RSpec.describe Ci::PlayManualStageService, '#execute' do
it 'logs the error' do
expect(Gitlab::AppLogger).to receive(:error)
- .exactly(stage.builds.manual.count)
+ .exactly(stage.processables.manual.count)
service.execute(stage)
end
end
+ private
+
def create_builds_for_stage(options)
options.merge!({
when: 'manual',
@@ -77,4 +82,17 @@ RSpec.describe Ci::PlayManualStageService, '#execute' do
create_list(:ci_build, 3, options)
end
+
+ def create_bridge_for_stage(options)
+ options.merge!({
+ when: 'manual',
+ pipeline: pipeline,
+ stage: stage.name,
+ stage_id: stage.id,
+ user: pipeline.user,
+ downstream: downstream_project
+ })
+
+ create(:ci_bridge, options)
+ end
end
diff --git a/spec/services/ci/retry_build_service_spec.rb b/spec/services/ci/retry_build_service_spec.rb
index 51741440075..81d56a0e42a 100644
--- a/spec/services/ci/retry_build_service_spec.rb
+++ b/spec/services/ci/retry_build_service_spec.rb
@@ -3,25 +3,32 @@
require 'spec_helper'
RSpec.describe Ci::RetryBuildService do
- let_it_be(:user) { create(:user) }
+ let_it_be(:reporter) { create(:user) }
+ let_it_be(:developer) { create(:user) }
let_it_be(:project) { create(:project, :repository) }
let_it_be(:pipeline) do
create(:ci_pipeline, project: project,
sha: 'b83d6e391c22777fca1ed3012fce84f633d7fed0')
end
- let(:stage) do
+ let_it_be(:stage) do
create(:ci_stage_entity, project: project,
pipeline: pipeline,
name: 'test')
end
- let(:build) { create(:ci_build, pipeline: pipeline, stage_id: stage.id) }
+ let_it_be_with_refind(:build) { create(:ci_build, pipeline: pipeline, stage_id: stage.id) }
+ let(:user) { developer }
let(:service) do
described_class.new(project, user)
end
+ before_all do
+ project.add_developer(developer)
+ project.add_reporter(reporter)
+ end
+
clone_accessors = described_class.clone_accessors
reject_accessors =
@@ -39,7 +46,8 @@ RSpec.describe Ci::RetryBuildService do
job_variables waiting_for_resource_at job_artifacts_metrics_referee
job_artifacts_network_referee job_artifacts_dotenv
job_artifacts_cobertura needs job_artifacts_accessibility
- job_artifacts_requirements job_artifacts_coverage_fuzzing].freeze
+ job_artifacts_requirements job_artifacts_coverage_fuzzing
+ job_artifacts_api_fuzzing].freeze
ignore_accessors =
%i[type lock_version target_url base_tags trace_sections
@@ -53,9 +61,9 @@ RSpec.describe Ci::RetryBuildService do
pipeline_id report_results pending_state pages_deployments].freeze
shared_examples 'build duplication' do
- let(:another_pipeline) { create(:ci_empty_pipeline, project: project) }
+ let_it_be(:another_pipeline) { create(:ci_empty_pipeline, project: project) }
- let(:build) do
+ let_it_be(:build) do
create(:ci_build, :failed, :expired, :erased, :queued, :coverage, :tags,
:allowed_to_fail, :on_tag, :triggered, :teardown_environment, :resource_group,
description: 'my-job', stage: 'test', stage_id: stage.id,
@@ -63,7 +71,7 @@ RSpec.describe Ci::RetryBuildService do
scheduled_at: 10.seconds.since)
end
- before do
+ before_all do
# Test correctly behaviour of deprecated artifact because it can be still in use
stub_feature_flags(drop_license_management_artifact: false)
@@ -81,8 +89,6 @@ RSpec.describe Ci::RetryBuildService do
create(:ci_job_variable, job: build)
create(:ci_build_need, build: build)
-
- build.reload
end
describe 'clone accessors' do
@@ -154,7 +160,7 @@ RSpec.describe Ci::RetryBuildService do
describe '#execute' do
let(:new_build) do
- Timecop.freeze(1.second.from_now) do
+ travel_to(1.second.from_now) do
service.execute(build)
end
end
@@ -162,8 +168,6 @@ RSpec.describe Ci::RetryBuildService do
context 'when user has ability to execute build' do
before do
stub_not_protect_default_branch
-
- project.add_developer(user)
end
it_behaves_like 'build duplication'
@@ -235,7 +239,6 @@ RSpec.describe Ci::RetryBuildService do
context 'when the pipeline is a child pipeline and the bridge is depended' do
let!(:parent_pipeline) { create(:ci_pipeline, project: project) }
- let!(:pipeline) { create(:ci_pipeline, project: project) }
let!(:bridge) { create(:ci_bridge, :strategy_depend, pipeline: parent_pipeline, status: 'success') }
let!(:source_pipeline) { create(:ci_sources_pipeline, pipeline: pipeline, source_job: bridge) }
@@ -248,6 +251,8 @@ RSpec.describe Ci::RetryBuildService do
end
context 'when user does not have ability to execute build' do
+ let(:user) { reporter }
+
it 'raises an error' do
expect { service.execute(build) }
.to raise_error Gitlab::Access::AccessDeniedError
@@ -257,7 +262,7 @@ RSpec.describe Ci::RetryBuildService do
describe '#reprocess' do
let(:new_build) do
- Timecop.freeze(1.second.from_now) do
+ travel_to(1.second.from_now) do
service.reprocess!(build)
end
end
@@ -265,8 +270,6 @@ RSpec.describe Ci::RetryBuildService do
context 'when user has ability to execute build' do
before do
stub_not_protect_default_branch
-
- project.add_developer(user)
end
it_behaves_like 'build duplication'
@@ -316,6 +319,8 @@ RSpec.describe Ci::RetryBuildService do
end
context 'when user does not have ability to execute build' do
+ let(:user) { reporter }
+
it 'raises an error' do
expect { service.reprocess!(build) }
.to raise_error Gitlab::Access::AccessDeniedError
diff --git a/spec/services/ci/update_build_queue_service_spec.rb b/spec/services/ci/update_build_queue_service_spec.rb
index 0f4c0fa5ecb..ebccfdc5140 100644
--- a/spec/services/ci/update_build_queue_service_spec.rb
+++ b/spec/services/ci/update_build_queue_service_spec.rb
@@ -45,21 +45,7 @@ RSpec.describe Ci::UpdateBuildQueueService do
runner.update!(contacted_at: Ci::Runner.recent_queue_deadline)
end
- context 'when ci_update_queues_for_online_runners is enabled' do
- before do
- stub_feature_flags(ci_update_queues_for_online_runners: true)
- end
-
- it_behaves_like 'does not refresh runner'
- end
-
- context 'when ci_update_queues_for_online_runners is disabled' do
- before do
- stub_feature_flags(ci_update_queues_for_online_runners: false)
- end
-
- it_behaves_like 'refreshes runner'
- end
+ it_behaves_like 'does not refresh runner'
end
end
diff --git a/spec/services/ci/update_build_state_service_spec.rb b/spec/services/ci/update_build_state_service_spec.rb
index f5ad732bf7e..2545909bf56 100644
--- a/spec/services/ci/update_build_state_service_spec.rb
+++ b/spec/services/ci/update_build_state_service_spec.rb
@@ -83,9 +83,26 @@ RSpec.describe Ci::UpdateBuildStateService do
{ checksum: 'crc32:12345678', state: 'failed', failure_reason: 'script_failure' }
end
+ context 'when build does not have associated trace chunks' do
+ it 'updates a build status' do
+ result = subject.execute
+
+ expect(build).to be_failed
+ expect(result.status).to eq 200
+ end
+
+ it 'does not increment invalid trace metric' do
+ execute_with_stubbed_metrics!
+
+ expect(metrics)
+ .not_to have_received(:increment_trace_operation)
+ .with(operation: :invalid)
+ end
+ end
+
context 'when build trace has been migrated' do
before do
- create(:ci_build_trace_chunk, :database_with_data, build: build)
+ create(:ci_build_trace_chunk, :persisted, build: build, initial_data: 'abcd')
end
it 'updates a build state' do
@@ -100,6 +117,12 @@ RSpec.describe Ci::UpdateBuildStateService do
expect(result.status).to eq 200
end
+ it 'does not set a backoff value' do
+ result = subject.execute
+
+ expect(result.backoff).to be_nil
+ end
+
it 'increments trace finalized operation metric' do
execute_with_stubbed_metrics!
@@ -107,6 +130,60 @@ RSpec.describe Ci::UpdateBuildStateService do
.to have_received(:increment_trace_operation)
.with(operation: :finalized)
end
+
+ it 'records migration duration in a histogram' do
+ freeze_time do
+ create(:ci_build_pending_state, build: build, created_at: 0.5.seconds.ago)
+
+ execute_with_stubbed_metrics!
+ end
+
+ expect(metrics)
+ .to have_received(:observe_migration_duration)
+ .with(0.5)
+ end
+
+ context 'when trace checksum is not valid' do
+ it 'increments invalid trace metric' do
+ execute_with_stubbed_metrics!
+
+ expect(metrics)
+ .to have_received(:increment_trace_operation)
+ .with(operation: :invalid)
+ end
+ end
+
+ context 'when trace checksum is valid' do
+ let(:params) { { checksum: 'crc32:ed82cd11', state: 'success' } }
+
+ it 'does not increment invalid trace metric' do
+ execute_with_stubbed_metrics!
+
+ expect(metrics)
+ .not_to have_received(:increment_trace_operation)
+ .with(operation: :invalid)
+ end
+ end
+
+ context 'when failed to acquire a build trace lock' do
+ it 'accepts a state update request' do
+ build.trace.lock do
+ result = subject.execute
+
+ expect(result.status).to eq 202
+ end
+ end
+
+ it 'increment locked trace metric' do
+ build.trace.lock do
+ execute_with_stubbed_metrics!
+
+ expect(metrics)
+ .to have_received(:increment_trace_operation)
+ .with(operation: :locked)
+ end
+ end
+ end
end
context 'when build trace has not been migrated yet' do
@@ -126,6 +203,12 @@ RSpec.describe Ci::UpdateBuildStateService do
expect(result.status).to eq 202
end
+ it 'sets a request backoff value' do
+ result = subject.execute
+
+ expect(result.backoff.to_i).to be > 0
+ end
+
it 'schedules live chunks for migration' do
expect(Ci::BuildTraceChunkFlushWorker)
.to receive(:perform_async)
@@ -134,14 +217,6 @@ RSpec.describe Ci::UpdateBuildStateService do
subject.execute
end
- it 'increments trace accepted operation metric' do
- execute_with_stubbed_metrics!
-
- expect(metrics)
- .to have_received(:increment_trace_operation)
- .with(operation: :accepted)
- end
-
it 'creates a pending state record' do
subject.execute
@@ -153,6 +228,22 @@ RSpec.describe Ci::UpdateBuildStateService do
end
end
+ it 'increments trace accepted operation metric' do
+ execute_with_stubbed_metrics!
+
+ expect(metrics)
+ .to have_received(:increment_trace_operation)
+ .with(operation: :accepted)
+ end
+
+ it 'does not increment invalid trace metric' do
+ execute_with_stubbed_metrics!
+
+ expect(metrics)
+ .not_to have_received(:increment_trace_operation)
+ .with(operation: :invalid)
+ end
+
context 'when build pending state is outdated' do
before do
build.create_pending_state(
diff --git a/spec/services/clusters/gcp/finalize_creation_service_spec.rb b/spec/services/clusters/gcp/finalize_creation_service_spec.rb
index be362dc6e23..d8c95a70bd0 100644
--- a/spec/services/clusters/gcp/finalize_creation_service_spec.rb
+++ b/spec/services/clusters/gcp/finalize_creation_service_spec.rb
@@ -83,12 +83,7 @@ RSpec.describe Clusters::Gcp::FinalizeCreationService, '#execute' do
shared_context 'kubernetes information successfully fetched' do
before do
stub_cloud_platform_get_zone_cluster(
- provider.gcp_project_id, provider.zone, cluster.name,
- {
- endpoint: endpoint,
- username: username,
- password: password
- }
+ provider.gcp_project_id, provider.zone, cluster.name, { endpoint: endpoint, username: username, password: password }
)
stub_kubeclient_discover(api_url)
@@ -101,11 +96,9 @@ RSpec.describe Clusters::Gcp::FinalizeCreationService, '#execute' do
stub_kubeclient_get_secret(
api_url,
- {
- metadata_name: secret_name,
- token: Base64.encode64(token),
- namespace: 'default'
- }
+ metadata_name: secret_name,
+ token: Base64.encode64(token),
+ namespace: 'default'
)
stub_kubeclient_put_cluster_role_binding(api_url, 'gitlab-admin')
diff --git a/spec/services/clusters/kubernetes/configure_istio_ingress_service_spec.rb b/spec/services/clusters/kubernetes/configure_istio_ingress_service_spec.rb
index b4402aadc88..f26177a56d0 100644
--- a/spec/services/clusters/kubernetes/configure_istio_ingress_service_spec.rb
+++ b/spec/services/clusters/kubernetes/configure_istio_ingress_service_spec.rb
@@ -26,27 +26,21 @@ RSpec.describe Clusters::Kubernetes::ConfigureIstioIngressService, '#execute' do
stub_kubeclient_get_secret(
api_url,
- {
- metadata_name: "#{namespace}-token",
- token: Base64.encode64('sample-token'),
- namespace: namespace
- }
+ 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'
- }
+ metadata_name: 'istio-ingressgateway-ca-certs',
+ namespace: 'istio-system'
)
stub_kubeclient_get_secret(
api_url,
- {
- metadata_name: 'istio-ingressgateway-certs',
- namespace: 'istio-system'
- }
+ metadata_name: 'istio-ingressgateway-certs',
+ namespace: 'istio-system'
)
stub_kubeclient_put_secret(api_url, 'istio-ingressgateway-ca-certs', namespace: 'istio-system')
diff --git a/spec/services/clusters/kubernetes/create_or_update_namespace_service_spec.rb b/spec/services/clusters/kubernetes/create_or_update_namespace_service_spec.rb
index ee10c59390e..7e3f1fdb379 100644
--- a/spec/services/clusters/kubernetes/create_or_update_namespace_service_spec.rb
+++ b/spec/services/clusters/kubernetes/create_or_update_namespace_service_spec.rb
@@ -41,11 +41,9 @@ RSpec.describe Clusters::Kubernetes::CreateOrUpdateNamespaceService, '#execute'
stub_kubeclient_get_secret(
api_url,
- {
- metadata_name: "#{namespace}-token",
- token: Base64.encode64('sample-token'),
- namespace: namespace
- }
+ metadata_name: "#{namespace}-token",
+ token: Base64.encode64('sample-token'),
+ namespace: namespace
)
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 f3fa6c2c0bb..257e2e53733 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
@@ -160,26 +160,60 @@ RSpec.describe Clusters::Kubernetes::CreateOrUpdateServiceAccountService do
it_behaves_like 'creates service account and token'
- it 'creates a namespaced role binding with edit access' do
- subject
+ context 'kubernetes_cluster_namespace_role_admin FF is enabled' do
+ before do
+ stub_feature_flags(kubernetes_cluster_namespace_role_admin: true)
+ end
+
+ it 'creates a namespaced role binding with admin access' do
+ subject
+
+ 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}" },
+ roleRef: {
+ apiGroup: 'rbac.authorization.k8s.io',
+ kind: 'ClusterRole',
+ name: 'admin'
+ },
+ subjects: [
+ {
+ kind: 'ServiceAccount',
+ name: service_account_name,
+ namespace: namespace
+ }
+ ]
+ )
+ )
+ end
+ end
- 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}" },
- roleRef: {
- apiGroup: 'rbac.authorization.k8s.io',
- kind: 'ClusterRole',
- name: 'edit'
- },
- subjects: [
- {
- kind: 'ServiceAccount',
- name: service_account_name,
- namespace: namespace
- }
- ]
+ context 'kubernetes_cluster_namespace_role_admin FF is disabled' do
+ before do
+ stub_feature_flags(kubernetes_cluster_namespace_role_admin: false)
+ end
+
+ it 'creates a namespaced role binding with edit access' do
+ subject
+
+ 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}" },
+ roleRef: {
+ apiGroup: 'rbac.authorization.k8s.io',
+ kind: 'ClusterRole',
+ name: 'edit'
+ },
+ subjects: [
+ {
+ kind: 'ServiceAccount',
+ name: service_account_name,
+ namespace: namespace
+ }
+ ]
+ )
)
- )
+ end
end
it 'creates a role binding granting crossplane database permissions to the service account' do
diff --git a/spec/services/clusters/kubernetes/fetch_kubernetes_token_service_spec.rb b/spec/services/clusters/kubernetes/fetch_kubernetes_token_service_spec.rb
index c4daae9dbf0..03c402fb066 100644
--- a/spec/services/clusters/kubernetes/fetch_kubernetes_token_service_spec.rb
+++ b/spec/services/clusters/kubernetes/fetch_kubernetes_token_service_spec.rb
@@ -31,11 +31,9 @@ RSpec.describe Clusters::Kubernetes::FetchKubernetesTokenService do
before do
stub_kubeclient_get_secret(
api_url,
- {
- metadata_name: service_account_token_name,
- namespace: namespace,
- token: token
- }
+ metadata_name: service_account_token_name,
+ namespace: namespace,
+ token: token
)
end
@@ -54,11 +52,9 @@ RSpec.describe Clusters::Kubernetes::FetchKubernetesTokenService do
before do
stub_kubeclient_get_secret_not_found_then_found(
api_url,
- {
- metadata_name: service_account_token_name,
- namespace: namespace,
- token: token
- }
+ metadata_name: service_account_token_name,
+ namespace: namespace,
+ token: token
)
end
@@ -79,11 +75,9 @@ RSpec.describe Clusters::Kubernetes::FetchKubernetesTokenService do
before do
stub_kubeclient_get_secret_missing_token_then_with_token(
api_url,
- {
- metadata_name: service_account_token_name,
- namespace: namespace,
- token: token
- }
+ metadata_name: service_account_token_name,
+ namespace: namespace,
+ token: token
)
end
@@ -96,11 +90,9 @@ RSpec.describe Clusters::Kubernetes::FetchKubernetesTokenService do
before do
stub_kubeclient_get_secret(
api_url,
- {
- metadata_name: service_account_token_name,
- namespace: namespace,
- token: nil
- }
+ metadata_name: service_account_token_name,
+ namespace: namespace,
+ token: nil
)
end
diff --git a/spec/services/deployments/after_create_service_spec.rb b/spec/services/deployments/after_create_service_spec.rb
deleted file mode 100644
index 6cdb4c88191..00000000000
--- a/spec/services/deployments/after_create_service_spec.rb
+++ /dev/null
@@ -1,287 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Deployments::AfterCreateService do
- let(:user) { create(:user) }
- let(:project) { create(:project, :repository) }
- let(:options) { { name: 'production' } }
- let(:pipeline) do
- create(
- :ci_pipeline,
- sha: 'b83d6e391c22777fca1ed3012fce84f633d7fed0',
- project: project
- )
- end
-
- let(:job) do
- create(:ci_build,
- :with_deployment,
- pipeline: pipeline,
- ref: 'master',
- tag: false,
- environment: 'production',
- options: { environment: options },
- project: project)
- end
-
- let(:deployment) { job.deployment }
- let(:environment) { deployment.environment }
-
- subject(:service) { described_class.new(deployment) }
-
- before do
- allow(Deployments::FinishedWorker).to receive(:perform_async)
- job.success! # Create/Succeed deployment
- end
-
- describe '#execute' do
- let(:store) { Gitlab::EtagCaching::Store.new }
-
- it 'invalidates the environment etag cache' do
- old_value = store.get(environment.etag_cache_key)
-
- service.execute
-
- expect(store.get(environment.etag_cache_key)).not_to eq(old_value)
- end
-
- it 'creates ref' do
- expect_any_instance_of(Repository)
- .to receive(:create_ref)
- .with(deployment.sha, "refs/environments/production/deployments/#{deployment.iid}")
-
- service.execute
- end
-
- it 'updates merge request metrics' do
- expect_any_instance_of(Deployment)
- .to receive(:update_merge_request_metrics!)
-
- service.execute
- end
-
- it 'returns the deployment' do
- expect(subject.execute).to eq(deployment)
- end
-
- it 'returns the deployment when could not save the environment' do
- allow(environment).to receive(:save).and_return(false)
-
- expect(subject.execute).to eq(deployment)
- end
-
- it 'returns the deployment when environment is stopped' do
- allow(environment).to receive(:stopped?).and_return(true)
-
- expect(subject.execute).to eq(deployment)
- end
-
- context 'when start action is defined' do
- let(:options) { { name: 'production', action: 'start' } }
-
- context 'and environment is stopped' do
- before do
- environment.stop
- end
-
- it 'makes environment available' do
- service.execute
-
- expect(environment.reload).to be_available
- end
- end
- end
-
- context 'when variables are used' do
- let(:options) do
- { name: 'review-apps/$CI_COMMIT_REF_NAME',
- url: 'http://$CI_COMMIT_REF_NAME.review-apps.gitlab.com' }
- end
-
- before do
- environment.update(name: 'review-apps/master')
- job.update(environment: 'review-apps/$CI_COMMIT_REF_NAME')
- end
-
- it 'does not create a new environment' do
- expect { subject.execute }.not_to change { Environment.count }
- end
-
- it 'updates external url' do
- subject.execute
-
- expect(subject.environment.name).to eq('review-apps/master')
- expect(subject.environment.external_url).to eq('http://master.review-apps.gitlab.com')
- end
- end
-
- context 'when auto_stop_in are used' do
- let(:options) do
- { name: 'production', auto_stop_in: '1 day' }
- end
-
- it 'renews auto stop at' do
- freeze_time do
- environment.update!(auto_stop_at: nil)
-
- expect { subject.execute }
- .to change { environment.reset.auto_stop_at&.round }.from(nil).to(1.day.since.round)
- end
- end
- end
- end
-
- describe '#expanded_environment_url' do
- subject { service.send(:expanded_environment_url) }
-
- context 'when yaml environment uses $CI_COMMIT_REF_NAME' do
- let(:job) do
- create(:ci_build,
- :with_deployment,
- pipeline: pipeline,
- ref: 'master',
- environment: 'production',
- project: project,
- options: { environment: { name: 'production', url: 'http://review/$CI_COMMIT_REF_NAME' } })
- end
-
- it { is_expected.to eq('http://review/master') }
- end
-
- context 'when yaml environment uses $CI_ENVIRONMENT_SLUG' do
- let(:job) do
- create(:ci_build,
- :with_deployment,
- pipeline: pipeline,
- ref: 'master',
- environment: 'prod-slug',
- project: project,
- options: { environment: { name: 'prod-slug', url: 'http://review/$CI_ENVIRONMENT_SLUG' } })
- end
-
- it { is_expected.to eq('http://review/prod-slug') }
- end
-
- context 'when yaml environment uses yaml_variables containing symbol keys' do
- let(:job) do
- create(:ci_build,
- :with_deployment,
- pipeline: pipeline,
- yaml_variables: [{ key: :APP_HOST, value: 'host' }],
- environment: 'production',
- project: project,
- options: { environment: { name: 'production', url: 'http://review/$APP_HOST' } })
- end
-
- it { is_expected.to eq('http://review/host') }
- end
-
- context 'when job variables are generated during runtime' do
- let(:job) do
- create(:ci_build,
- :with_deployment,
- pipeline: pipeline,
- environment: 'review/$CI_COMMIT_REF_NAME',
- project: project,
- job_variables: [job_variable],
- options: { environment: { name: 'review/$CI_COMMIT_REF_NAME', url: 'http://$DYNAMIC_ENV_URL' } })
- end
-
- let(:job_variable) do
- build(:ci_job_variable, :dotenv_source, key: 'DYNAMIC_ENV_URL', value: 'abc.test.com')
- end
-
- it 'expands the environment URL from the dynamic variable' do
- is_expected.to eq('http://abc.test.com')
- end
- end
-
- context 'when yaml environment does not have url' do
- let(:job) { create(:ci_build, :with_deployment, pipeline: pipeline, environment: 'staging', project: project) }
-
- it 'returns the external_url from persisted environment' do
- is_expected.to be_nil
- end
- end
- end
-
- describe "merge request metrics" do
- let(:merge_request) { create(:merge_request, target_branch: 'master', source_branch: 'feature', source_project: project) }
-
- context "while updating the 'first_deployed_to_production_at' time" do
- before do
- merge_request.metrics.update!(merged_at: 1.hour.ago)
- end
-
- context "for merge requests merged before the current deploy" do
- it "sets the time if the deploy's environment is 'production'" do
- service.execute
-
- expect(merge_request.reload.metrics.first_deployed_to_production_at).to be_like_time(deployment.finished_at)
- end
-
- context 'when job deploys to staging' do
- let(:job) do
- create(:ci_build,
- :with_deployment,
- pipeline: pipeline,
- ref: 'master',
- tag: false,
- environment: 'staging',
- options: { environment: { name: 'staging' } },
- project: project)
- end
-
- it "doesn't set the time if the deploy's environment is not 'production'" do
- service.execute
-
- expect(merge_request.reload.metrics.first_deployed_to_production_at).to be_nil
- end
- end
-
- it 'does not raise errors if the merge request does not have a metrics record' do
- merge_request.metrics.destroy
-
- expect(merge_request.reload.metrics).to be_nil
- expect { service.execute }.not_to raise_error
- end
- end
-
- context "for merge requests merged before the previous deploy" do
- context "if the 'first_deployed_to_production_at' time is already set" do
- it "does not overwrite the older 'first_deployed_to_production_at' time" do
- # Previous deploy
- service.execute
-
- expect(merge_request.reload.metrics.first_deployed_to_production_at).to be_like_time(deployment.finished_at)
-
- # Current deploy
- Timecop.travel(12.hours.from_now) do
- service.execute
-
- expect(merge_request.reload.metrics.first_deployed_to_production_at).to be_like_time(deployment.finished_at)
- end
- end
- end
-
- context "if the 'first_deployed_to_production_at' time is not already set" do
- it "does not overwrite the older 'first_deployed_to_production_at' time" do
- # Previous deploy
- time = 5.minutes.from_now
- Timecop.freeze(time) { service.execute }
-
- expect(merge_request.reload.metrics.merged_at).to be < merge_request.reload.metrics.first_deployed_to_production_at
-
- previous_time = merge_request.reload.metrics.first_deployed_to_production_at
-
- # Current deploy
- Timecop.freeze(time + 12.hours) { service.execute }
-
- expect(merge_request.reload.metrics.first_deployed_to_production_at).to eq(previous_time)
- end
- end
- end
- end
- end
-end
diff --git a/spec/services/deployments/create_service_spec.rb b/spec/services/deployments/create_service_spec.rb
index d1f977c28d3..2d157c9d114 100644
--- a/spec/services/deployments/create_service_spec.rb
+++ b/spec/services/deployments/create_service_spec.rb
@@ -19,8 +19,9 @@ RSpec.describe Deployments::CreateService do
status: 'success'
)
- expect(Deployments::SuccessWorker).to receive(:perform_async)
- expect(Deployments::FinishedWorker).to receive(:perform_async)
+ expect(Deployments::UpdateEnvironmentWorker).to receive(:perform_async)
+ expect(Deployments::LinkMergeRequestWorker).to receive(:perform_async)
+ expect(Deployments::ExecuteHooksWorker).to receive(:perform_async)
expect(service.execute).to be_persisted
end
@@ -34,8 +35,9 @@ RSpec.describe Deployments::CreateService do
tag: false
)
- expect(Deployments::SuccessWorker).not_to receive(:perform_async)
- expect(Deployments::FinishedWorker).not_to receive(:perform_async)
+ expect(Deployments::UpdateEnvironmentWorker).not_to receive(:perform_async)
+ expect(Deployments::LinkMergeRequestWorker).not_to receive(:perform_async)
+ expect(Deployments::ExecuteHooksWorker).not_to receive(:perform_async)
expect(service.execute).to be_persisted
end
diff --git a/spec/services/deployments/update_environment_service_spec.rb b/spec/services/deployments/update_environment_service_spec.rb
new file mode 100644
index 00000000000..92488c62315
--- /dev/null
+++ b/spec/services/deployments/update_environment_service_spec.rb
@@ -0,0 +1,288 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Deployments::UpdateEnvironmentService do
+ let(:user) { create(:user) }
+ let(:project) { create(:project, :repository) }
+ let(:options) { { name: 'production' } }
+ let(:pipeline) do
+ create(
+ :ci_pipeline,
+ sha: 'b83d6e391c22777fca1ed3012fce84f633d7fed0',
+ project: project
+ )
+ end
+
+ let(:job) do
+ create(:ci_build,
+ :with_deployment,
+ pipeline: pipeline,
+ ref: 'master',
+ tag: false,
+ environment: 'production',
+ options: { environment: options },
+ project: project)
+ end
+
+ let(:deployment) { job.deployment }
+ let(:environment) { deployment.environment }
+
+ subject(:service) { described_class.new(deployment) }
+
+ before do
+ allow(Deployments::LinkMergeRequestWorker).to receive(:perform_async)
+ allow(Deployments::ExecuteHooksWorker).to receive(:perform_async)
+ job.success! # Create/Succeed deployment
+ end
+
+ describe '#execute' do
+ let(:store) { Gitlab::EtagCaching::Store.new }
+
+ it 'invalidates the environment etag cache' do
+ old_value = store.get(environment.etag_cache_key)
+
+ service.execute
+
+ expect(store.get(environment.etag_cache_key)).not_to eq(old_value)
+ end
+
+ it 'creates ref' do
+ expect_any_instance_of(Repository)
+ .to receive(:create_ref)
+ .with(deployment.sha, "refs/environments/production/deployments/#{deployment.iid}")
+
+ service.execute
+ end
+
+ it 'updates merge request metrics' do
+ expect_any_instance_of(Deployment)
+ .to receive(:update_merge_request_metrics!)
+
+ service.execute
+ end
+
+ it 'returns the deployment' do
+ expect(subject.execute).to eq(deployment)
+ end
+
+ it 'returns the deployment when could not save the environment' do
+ allow(environment).to receive(:save).and_return(false)
+
+ expect(subject.execute).to eq(deployment)
+ end
+
+ it 'returns the deployment when environment is stopped' do
+ allow(environment).to receive(:stopped?).and_return(true)
+
+ expect(subject.execute).to eq(deployment)
+ end
+
+ context 'when start action is defined' do
+ let(:options) { { name: 'production', action: 'start' } }
+
+ context 'and environment is stopped' do
+ before do
+ environment.stop
+ end
+
+ it 'makes environment available' do
+ service.execute
+
+ expect(environment.reload).to be_available
+ end
+ end
+ end
+
+ context 'when variables are used' do
+ let(:options) do
+ { name: 'review-apps/$CI_COMMIT_REF_NAME',
+ url: 'http://$CI_COMMIT_REF_NAME.review-apps.gitlab.com' }
+ end
+
+ before do
+ environment.update!(name: 'review-apps/master')
+ job.update!(environment: 'review-apps/$CI_COMMIT_REF_NAME')
+ end
+
+ it 'does not create a new environment' do
+ expect { subject.execute }.not_to change { Environment.count }
+ end
+
+ it 'updates external url' do
+ subject.execute
+
+ expect(subject.environment.name).to eq('review-apps/master')
+ expect(subject.environment.external_url).to eq('http://master.review-apps.gitlab.com')
+ end
+ end
+
+ context 'when auto_stop_in are used' do
+ let(:options) do
+ { name: 'production', auto_stop_in: '1 day' }
+ end
+
+ it 'renews auto stop at' do
+ freeze_time do
+ environment.update!(auto_stop_at: nil)
+
+ expect { subject.execute }
+ .to change { environment.reset.auto_stop_at&.round }.from(nil).to(1.day.since.round)
+ end
+ end
+ end
+ end
+
+ describe '#expanded_environment_url' do
+ subject { service.send(:expanded_environment_url) }
+
+ context 'when yaml environment uses $CI_COMMIT_REF_NAME' do
+ let(:job) do
+ create(:ci_build,
+ :with_deployment,
+ pipeline: pipeline,
+ ref: 'master',
+ environment: 'production',
+ project: project,
+ options: { environment: { name: 'production', url: 'http://review/$CI_COMMIT_REF_NAME' } })
+ end
+
+ it { is_expected.to eq('http://review/master') }
+ end
+
+ context 'when yaml environment uses $CI_ENVIRONMENT_SLUG' do
+ let(:job) do
+ create(:ci_build,
+ :with_deployment,
+ pipeline: pipeline,
+ ref: 'master',
+ environment: 'prod-slug',
+ project: project,
+ options: { environment: { name: 'prod-slug', url: 'http://review/$CI_ENVIRONMENT_SLUG' } })
+ end
+
+ it { is_expected.to eq('http://review/prod-slug') }
+ end
+
+ context 'when yaml environment uses yaml_variables containing symbol keys' do
+ let(:job) do
+ create(:ci_build,
+ :with_deployment,
+ pipeline: pipeline,
+ yaml_variables: [{ key: :APP_HOST, value: 'host' }],
+ environment: 'production',
+ project: project,
+ options: { environment: { name: 'production', url: 'http://review/$APP_HOST' } })
+ end
+
+ it { is_expected.to eq('http://review/host') }
+ end
+
+ context 'when job variables are generated during runtime' do
+ let(:job) do
+ create(:ci_build,
+ :with_deployment,
+ pipeline: pipeline,
+ environment: 'review/$CI_COMMIT_REF_NAME',
+ project: project,
+ job_variables: [job_variable],
+ options: { environment: { name: 'review/$CI_COMMIT_REF_NAME', url: 'http://$DYNAMIC_ENV_URL' } })
+ end
+
+ let(:job_variable) do
+ build(:ci_job_variable, :dotenv_source, key: 'DYNAMIC_ENV_URL', value: 'abc.test.com')
+ end
+
+ it 'expands the environment URL from the dynamic variable' do
+ is_expected.to eq('http://abc.test.com')
+ end
+ end
+
+ context 'when yaml environment does not have url' do
+ let(:job) { create(:ci_build, :with_deployment, pipeline: pipeline, environment: 'staging', project: project) }
+
+ it 'returns the external_url from persisted environment' do
+ is_expected.to be_nil
+ end
+ end
+ end
+
+ describe "merge request metrics" do
+ let(:merge_request) { create(:merge_request, target_branch: 'master', source_branch: 'feature', source_project: project) }
+
+ context "while updating the 'first_deployed_to_production_at' time" do
+ before do
+ merge_request.metrics.update!(merged_at: 1.hour.ago)
+ end
+
+ context "for merge requests merged before the current deploy" do
+ it "sets the time if the deploy's environment is 'production'" do
+ service.execute
+
+ expect(merge_request.reload.metrics.first_deployed_to_production_at).to be_like_time(deployment.finished_at)
+ end
+
+ context 'when job deploys to staging' do
+ let(:job) do
+ create(:ci_build,
+ :with_deployment,
+ pipeline: pipeline,
+ ref: 'master',
+ tag: false,
+ environment: 'staging',
+ options: { environment: { name: 'staging' } },
+ project: project)
+ end
+
+ it "doesn't set the time if the deploy's environment is not 'production'" do
+ service.execute
+
+ expect(merge_request.reload.metrics.first_deployed_to_production_at).to be_nil
+ end
+ end
+
+ it 'does not raise errors if the merge request does not have a metrics record' do
+ merge_request.metrics.destroy!
+
+ expect(merge_request.reload.metrics).to be_nil
+ expect { service.execute }.not_to raise_error
+ end
+ end
+
+ context "for merge requests merged before the previous deploy" do
+ context "if the 'first_deployed_to_production_at' time is already set" do
+ it "does not overwrite the older 'first_deployed_to_production_at' time" do
+ # Previous deploy
+ service.execute
+
+ expect(merge_request.reload.metrics.first_deployed_to_production_at).to be_like_time(deployment.finished_at)
+
+ # Current deploy
+ travel_to(12.hours.from_now) do
+ service.execute
+
+ expect(merge_request.reload.metrics.first_deployed_to_production_at).to be_like_time(deployment.finished_at)
+ end
+ end
+ end
+
+ context "if the 'first_deployed_to_production_at' time is not already set" do
+ it "does not overwrite the older 'first_deployed_to_production_at' time" do
+ # Previous deploy
+ time = 5.minutes.from_now
+ travel_to(time) { service.execute }
+
+ expect(merge_request.reload.metrics.merged_at).to be < merge_request.reload.metrics.first_deployed_to_production_at
+
+ previous_time = merge_request.reload.metrics.first_deployed_to_production_at
+
+ # Current deploy
+ travel_to(time + 12.hours) { service.execute }
+
+ expect(merge_request.reload.metrics.first_deployed_to_production_at).to eq(previous_time)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/spec/services/design_management/copy_design_collection/copy_service_spec.rb b/spec/services/design_management/copy_design_collection/copy_service_spec.rb
new file mode 100644
index 00000000000..e93e5f13fea
--- /dev/null
+++ b/spec/services/design_management/copy_design_collection/copy_service_spec.rb
@@ -0,0 +1,259 @@
+# frozen_string_literal: true
+require 'spec_helper'
+
+RSpec.describe DesignManagement::CopyDesignCollection::CopyService, :clean_gitlab_redis_shared_state do
+ include DesignManagementTestHelpers
+
+ let_it_be(:user) { create(:user) }
+ let_it_be(:project) { create(:project) }
+ let_it_be(:issue, refind: true) { create(:issue, project: project) }
+ let(:target_issue) { create(:issue) }
+
+ subject { described_class.new(project, user, issue: issue, target_issue: target_issue).execute }
+
+ before do
+ enable_design_management
+ end
+
+ shared_examples 'service error' do |message:|
+ it 'returns an error response', :aggregate_failures do
+ expect(subject).to be_kind_of(ServiceResponse)
+ expect(subject).to be_error
+ expect(subject.message).to eq(message)
+ end
+ end
+
+ shared_examples 'service success' do
+ it 'returns a success response', :aggregate_failures do
+ expect(subject).to be_kind_of(ServiceResponse)
+ expect(subject).to be_success
+ end
+ end
+
+ include_examples 'service error', message: 'User cannot copy design collection to issue'
+
+ context 'when user has permission to read the design collection' do
+ before_all do
+ project.add_reporter(user)
+ end
+
+ include_examples 'service error', message: 'User cannot copy design collection to issue'
+
+ context 'when the user also has permission to admin the target issue' do
+ let(:target_repository) { target_issue.project.design_repository }
+
+ before do
+ target_issue.project.add_reporter(user)
+ end
+
+ include_examples 'service error', message: 'Target design collection must first be queued'
+
+ context 'when the target design collection has been queued' do
+ before do
+ target_issue.design_collection.start_copy!
+ end
+
+ include_examples 'service error', message: 'Design collection has no designs'
+
+ context 'when design collection has designs' do
+ let_it_be(:designs) do
+ create_list(:design, 3, :with_lfs_file, :with_relative_position, issue: issue, project: project)
+ end
+
+ context 'when target issue already has designs' do
+ before do
+ create(:design, issue: target_issue, project: target_issue.project)
+ end
+
+ include_examples 'service error', message: 'Target design collection already has designs'
+ end
+
+ include_examples 'service success'
+
+ it 'creates a design repository for the target project' do
+ expect { subject }.to change { target_repository.exists? }.from(false).to(true)
+ end
+
+ context 'when the target project already has a design repository' do
+ before do
+ target_repository.create_if_not_exists
+ end
+
+ include_examples 'service success'
+ end
+
+ it 'copies the designs correctly', :aggregate_failures do
+ expect { subject }.to change { target_issue.designs.count }.by(3)
+
+ old_designs = issue.designs.ordered
+ new_designs = target_issue.designs.ordered
+
+ new_designs.zip(old_designs).each do |new_design, old_design|
+ expect(new_design).to have_attributes(
+ filename: old_design.filename,
+ relative_position: old_design.relative_position,
+ issue: target_issue,
+ project: target_issue.project
+ )
+ end
+ end
+
+ it 'copies the design versions correctly', :aggregate_failures do
+ expect { subject }.to change { target_issue.design_versions.count }.by(3)
+
+ old_versions = issue.design_versions.ordered
+ new_versions = target_issue.design_versions.ordered
+
+ new_versions.zip(old_versions).each do |new_version, old_version|
+ expect(new_version).to have_attributes(
+ created_at: old_version.created_at,
+ author_id: old_version.author_id
+ )
+ expect(new_version.designs.pluck(:filename)).to eq(old_version.designs.pluck(:filename))
+ expect(new_version.actions.pluck(:event)).to eq(old_version.actions.pluck(:event))
+ end
+ end
+
+ it 'copies the design actions correctly', :aggregate_failures do
+ expect { subject }.to change { DesignManagement::Action.count }.by(3)
+
+ old_actions = issue.design_versions.ordered.flat_map(&:actions)
+ new_actions = target_issue.design_versions.ordered.flat_map(&:actions)
+
+ new_actions.zip(old_actions).each do |new_action, old_action|
+ # This is a way to identify if the versions linked to the actions
+ # are correct is to compare design filenames, as the SHA changes.
+ new_design_filenames = new_action.version.designs.ordered.pluck(:filename)
+ old_design_filenames = old_action.version.designs.ordered.pluck(:filename)
+
+ expect(new_design_filenames).to eq(old_design_filenames)
+ expect(new_action.event).to eq(old_action.event)
+ expect(new_action.design.filename).to eq(old_action.design.filename)
+ end
+ end
+
+ it 'copies design notes correctly', :aggregate_failures, :sidekiq_inline do
+ old_notes = [
+ create(:diff_note_on_design, note: 'first note', noteable: designs.first, project: project, author: create(:user)),
+ create(:diff_note_on_design, note: 'second note', noteable: designs.first, project: project, author: create(:user))
+ ]
+ matchers = old_notes.map do |note|
+ have_attributes(
+ note.attributes.slice(
+ :type,
+ :author_id,
+ :note,
+ :position
+ )
+ )
+ end
+
+ expect { subject }.to change { Note.count }.by(2)
+
+ new_notes = target_issue.designs.first.notes.fresh
+
+ expect(new_notes).to match_array(matchers)
+ end
+
+ it 'links the LfsObjects' do
+ expect { subject }.to change { target_issue.project.lfs_objects.count }.by(3)
+ end
+
+ it 'copies the Git repository data', :aggregate_failures do
+ subject
+
+ commit_shas = target_repository.commits('master', limit: 99).map(&:id)
+
+ expect(commit_shas).to include(*target_issue.design_versions.ordered.pluck(:sha))
+ end
+
+ it 'creates a master branch if none previously existed' do
+ expect { subject }.to change { target_repository.branch_names }.from([]).to(['master'])
+ end
+
+ it 'leaves the design collection in the correct copy state' do
+ subject
+
+ expect(target_issue.design_collection).to be_copy_ready
+ end
+
+ describe 'rollback' do
+ before do
+ # Ensure the very last step throws an error
+ expect_next_instance_of(described_class) do |service|
+ expect(service).to receive(:finalize!).and_raise
+ end
+ end
+
+ include_examples 'service error', message: 'Designs were unable to be copied successfully'
+
+ it 'rollsback all PostgreSQL data created', :aggregate_failures do
+ expect { subject }.not_to change {
+ [
+ DesignManagement::Design.count,
+ DesignManagement::Action.count,
+ DesignManagement::Version.count,
+ Note.count
+ ]
+ }
+
+ collections = [
+ target_issue.design_collection,
+ target_issue.designs,
+ target_issue.design_versions
+ ]
+
+ expect(collections).to all(be_empty)
+ end
+
+ it 'does not alter master branch', :aggregate_failures do
+ # Add some Git data to the target_repository, so we are testing
+ # that any original data remains
+ issue_2 = create(:issue, project: target_issue.project)
+ create(:design, :with_file, issue: issue_2, project: target_issue.project)
+
+ expect { subject }.not_to change {
+ expect(target_repository.commits('master', limit: 10).size).to eq(1)
+ }
+ end
+
+ it 'sets the design collection copy state' do
+ subject
+
+ expect(target_issue.design_collection).to be_copy_error
+ end
+ end
+ end
+ end
+ end
+ end
+
+ describe 'Alert if schema changes', :aggregate_failures do
+ let_it_be(:config_file) { Rails.root.join('lib/gitlab/design_management/copy_design_collection_model_attributes.yml') }
+ let_it_be(:config) { YAML.load_file(config_file).symbolize_keys }
+
+ %w(Design Action Version).each do |model|
+ specify do
+ attributes = config["#{model.downcase}_attributes".to_sym] || []
+ ignored_attributes = config["ignore_#{model.downcase}_attributes".to_sym]
+
+ expect(attributes + ignored_attributes).to contain_exactly(
+ *DesignManagement.const_get(model, false).column_names
+ ), failure_message(model)
+ end
+ end
+
+ def failure_message(model)
+ <<-MSG
+ The schema of the `#{model}` model has changed.
+
+ `#{described_class.name}` refers to specific lists of attributes of `#{model}` to either
+ copy or ignore, so that we continue to copy designs correctly after schema changes.
+
+ Please update:
+ #{config_file}
+ to reflect the latest changes to `#{model}`. See that file for more information.
+ MSG
+ end
+ end
+end
diff --git a/spec/services/design_management/copy_design_collection/queue_service_spec.rb b/spec/services/design_management/copy_design_collection/queue_service_spec.rb
new file mode 100644
index 00000000000..2d9ea4633a0
--- /dev/null
+++ b/spec/services/design_management/copy_design_collection/queue_service_spec.rb
@@ -0,0 +1,51 @@
+# frozen_string_literal: true
+require 'spec_helper'
+
+RSpec.describe DesignManagement::CopyDesignCollection::QueueService, :clean_gitlab_redis_shared_state do
+ include DesignManagementTestHelpers
+
+ let_it_be(:user) { create(:user) }
+ let_it_be(:issue) { create(:issue) }
+ let_it_be(:target_issue, refind: true) { create(:issue) }
+ let_it_be(:design) { create(:design, issue: issue, project: issue.project) }
+
+ subject { described_class.new(user, issue, target_issue).execute }
+
+ before do
+ enable_design_management
+ end
+
+ it 'returns an error if user does not have permission' do
+ expect(subject).to be_kind_of(ServiceResponse)
+ expect(subject).to be_error
+ expect(subject.message).to eq('User cannot copy designs to issue')
+ end
+
+ context 'when user has permission' do
+ before_all do
+ issue.project.add_reporter(user)
+ target_issue.project.add_reporter(user)
+ end
+
+ it 'returns an error if design collection copy_state is not queuable' do
+ target_issue.design_collection.start_copy!
+
+ expect(subject).to be_kind_of(ServiceResponse)
+ expect(subject).to be_error
+ expect(subject.message).to eq('Target design collection copy state must be `ready`')
+ end
+
+ it 'sets the design collection copy state' do
+ expect { subject }.to change { target_issue.design_collection.copy_state }.from('ready').to('in_progress')
+ end
+
+ it 'queues a DesignManagement::CopyDesignCollectionWorker' do
+ expect { subject }.to change(DesignManagement::CopyDesignCollectionWorker.jobs, :size).by(1)
+ end
+
+ it 'returns success' do
+ expect(subject).to be_kind_of(ServiceResponse)
+ expect(subject).to be_success
+ end
+ end
+end
diff --git a/spec/services/design_management/delete_designs_service_spec.rb b/spec/services/design_management/delete_designs_service_spec.rb
index ace63b6e59c..ed161b4c8ff 100644
--- a/spec/services/design_management/delete_designs_service_spec.rb
+++ b/spec/services/design_management/delete_designs_service_spec.rb
@@ -80,6 +80,16 @@ RSpec.describe DesignManagement::DeleteDesignsService do
expect { run_service rescue nil }
.not_to change { [counter.totals, Event.count] }
end
+
+ it 'does not log any UsageData metrics' do
+ redis_hll = ::Gitlab::UsageDataCounters::HLLRedisCounter
+ event = Gitlab::UsageDataCounters::IssueActivityUniqueCounter::ISSUE_DESIGNS_REMOVED
+
+ expect { run_service rescue nil }
+ .not_to change { redis_hll.unique_events(event_names: event, start_date: 1.day.ago, end_date: 1.day.from_now) }
+
+ run_service rescue nil
+ end
end
context 'one design is passed' do
@@ -98,6 +108,12 @@ RSpec.describe DesignManagement::DeleteDesignsService do
expect { run_service }.to change { counter.read(:delete) }.by(1)
end
+ it 'updates UsageData for removed designs' do
+ expect(Gitlab::UsageDataCounters::IssueActivityUniqueCounter).to receive(:track_issue_designs_removed_action).with(author: user)
+
+ run_service
+ end
+
it 'creates an event in the activity stream' do
expect { run_service }
.to change { Event.count }.by(1)
@@ -105,7 +121,7 @@ RSpec.describe DesignManagement::DeleteDesignsService do
end
it 'informs the new-version-worker' do
- expect(::DesignManagement::NewVersionWorker).to receive(:perform_async).with(Integer)
+ expect(::DesignManagement::NewVersionWorker).to receive(:perform_async).with(Integer, false)
run_service
end
diff --git a/spec/services/design_management/generate_image_versions_service_spec.rb b/spec/services/design_management/generate_image_versions_service_spec.rb
index 631eec97e5a..749030af97d 100644
--- a/spec/services/design_management/generate_image_versions_service_spec.rb
+++ b/spec/services/design_management/generate_image_versions_service_spec.rb
@@ -52,25 +52,50 @@ RSpec.describe DesignManagement::GenerateImageVersionsService do
end
context 'when an error is encountered when generating the image versions' do
- before do
- expect_next_instance_of(DesignManagement::DesignV432x230Uploader) do |uploader|
- expect(uploader).to receive(:cache!).and_raise(CarrierWave::DownloadError, 'foo')
+ context "CarrierWave::IntegrityError" do
+ before do
+ expect_next_instance_of(DesignManagement::DesignV432x230Uploader) do |uploader|
+ expect(uploader).to receive(:cache!).and_raise(CarrierWave::IntegrityError, 'foo')
+ end
+ end
+
+ it 'logs the exception' do
+ expect(Gitlab::ErrorTracking).to receive(:log_exception).with(
+ instance_of(CarrierWave::IntegrityError),
+ project_id: project.id, version_id: version.id, design_id: version.designs.first.id
+ )
+
+ described_class.new(version).execute
end
- end
- it 'logs the error' do
- expect(Gitlab::AppLogger).to receive(:error).with('foo')
+ it 'logs the error' do
+ expect(Gitlab::AppLogger).to receive(:error).with('foo')
- described_class.new(version).execute
+ described_class.new(version).execute
+ end
end
- it 'tracks the error' do
- expect(Gitlab::ErrorTracking).to receive(:track_exception).with(
- instance_of(CarrierWave::DownloadError),
- project_id: project.id, version_id: version.id, design_id: version.designs.first.id
- )
+ context "CarrierWave::UploadError" do
+ before do
+ expect_next_instance_of(DesignManagement::DesignV432x230Uploader) do |uploader|
+ expect(uploader).to receive(:cache!).and_raise(CarrierWave::UploadError, 'foo')
+ end
+ end
- described_class.new(version).execute
+ it 'logs the error' do
+ expect(Gitlab::AppLogger).to receive(:error).with('foo')
+
+ described_class.new(version).execute
+ end
+
+ it 'tracks the error' do
+ expect(Gitlab::ErrorTracking).to receive(:track_exception).with(
+ instance_of(CarrierWave::UploadError),
+ project_id: project.id, version_id: version.id, design_id: version.designs.first.id
+ )
+
+ described_class.new(version).execute
+ end
end
end
end
diff --git a/spec/services/design_management/save_designs_service_spec.rb b/spec/services/design_management/save_designs_service_spec.rb
index abba5de2c27..f36e68c8dbd 100644
--- a/spec/services/design_management/save_designs_service_spec.rb
+++ b/spec/services/design_management/save_designs_service_spec.rb
@@ -32,7 +32,7 @@ RSpec.describe DesignManagement::SaveDesignsService do
end
allow(::DesignManagement::NewVersionWorker)
- .to receive(:perform_async).with(Integer).and_return(nil)
+ .to receive(:perform_async).with(Integer, false).and_return(nil)
end
def run_service(files_to_upload = nil)
@@ -102,9 +102,11 @@ RSpec.describe DesignManagement::SaveDesignsService do
end
end
- it 'creates a commit, an event in the activity stream and updates the creation count' do
+ it 'creates a commit, an event in the activity stream and updates the creation count', :aggregate_failures do
counter = Gitlab::UsageDataCounters::DesignsCounter
+ expect(Gitlab::UsageDataCounters::IssueActivityUniqueCounter).to receive(:track_issue_designs_added_action).with(author: user)
+
expect { run_service }
.to change { Event.count }.by(1)
.and change { Event.for_design.created_action.count }.by(1)
@@ -128,6 +130,25 @@ RSpec.describe DesignManagement::SaveDesignsService do
expect { run_parallel(blocks) }.to change(DesignManagement::Version, :count).by(parellism)
end
+ context 'when the design collection is in the process of being copied', :clean_gitlab_redis_shared_state do
+ before do
+ issue.design_collection.start_copy!
+ end
+
+ it_behaves_like 'a service error'
+ end
+
+ context 'when the design collection has a copy error', :clean_gitlab_redis_shared_state do
+ before do
+ issue.design_collection.copy_state = 'error'
+ issue.design_collection.send(:set_stored_copy_state!)
+ end
+
+ it 'resets the copy state' do
+ expect { run_service }.to change { issue.design_collection.copy_state }.from('error').to('ready')
+ end
+ end
+
describe 'the response' do
it 'includes designs with the expected properties' do
updated_designs = response[:designs]
@@ -171,6 +192,12 @@ RSpec.describe DesignManagement::SaveDesignsService do
expect(updated_designs.first.versions.size).to eq(2)
end
+ it 'updates UsageData for changed designs' do
+ expect(Gitlab::UsageDataCounters::IssueActivityUniqueCounter).to receive(:track_issue_designs_modified_action).with(author: user)
+
+ run_service
+ end
+
it 'records the correct events' do
counter = Gitlab::UsageDataCounters::DesignsCounter
expect { run_service }
@@ -220,7 +247,7 @@ RSpec.describe DesignManagement::SaveDesignsService do
counter = Gitlab::UsageDataCounters::DesignsCounter
expect(::DesignManagement::NewVersionWorker)
- .to receive(:perform_async).once.with(Integer).and_return(nil)
+ .to receive(:perform_async).once.with(Integer, false).and_return(nil)
expect { run_service }
.to change { Event.count }.by(2)
@@ -254,7 +281,7 @@ RSpec.describe DesignManagement::SaveDesignsService do
design_repository.has_visible_content?
expect(::DesignManagement::NewVersionWorker)
- .to receive(:perform_async).once.with(Integer).and_return(nil)
+ .to receive(:perform_async).once.with(Integer, false).and_return(nil)
expect { service.execute }
.to change { issue.designs.count }.from(0).to(2)
@@ -271,6 +298,14 @@ RSpec.describe DesignManagement::SaveDesignsService do
expect(response[:message]).to match(/only \d+ files are allowed simultaneously/i)
end
end
+
+ context 'when uploading duplicate files' do
+ let(:files) { [rails_sample, dk_png, rails_sample] }
+
+ it 'returns the correct error' do
+ expect(response[:message]).to match('Duplicate filenames are not allowed!')
+ end
+ end
end
context 'when the user is not allowed to upload designs' do
diff --git a/spec/services/feature_flags/create_service_spec.rb b/spec/services/feature_flags/create_service_spec.rb
new file mode 100644
index 00000000000..2cd19000f99
--- /dev/null
+++ b/spec/services/feature_flags/create_service_spec.rb
@@ -0,0 +1,79 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe FeatureFlags::CreateService do
+ let_it_be(:project) { create(:project) }
+ let_it_be(:developer) { create(:user) }
+ let_it_be(:reporter) { create(:user) }
+ let(:user) { developer }
+
+ before_all do
+ project.add_developer(developer)
+ project.add_reporter(reporter)
+ end
+
+ describe '#execute' do
+ subject do
+ described_class.new(project, user, params).execute
+ end
+
+ let(:feature_flag) { subject[:feature_flag] }
+
+ context 'when feature flag can not be created' do
+ let(:params) { {} }
+
+ it 'returns status error' do
+ expect(subject[:status]).to eq(:error)
+ end
+
+ it 'returns validation errors' do
+ expect(subject[:message]).to include("Name can't be blank")
+ end
+
+ it 'does not create audit log' do
+ expect { subject }.not_to change { AuditEvent.count }
+ end
+ end
+
+ context 'when feature flag is saved correctly' do
+ let(:params) do
+ {
+ name: 'feature_flag',
+ description: 'description',
+ scopes_attributes: [{ environment_scope: '*', active: true },
+ { environment_scope: 'production', active: false }]
+ }
+ end
+
+ it 'returns status success' do
+ expect(subject[:status]).to eq(:success)
+ end
+
+ it 'creates feature flag' do
+ expect { subject }.to change { Operations::FeatureFlag.count }.by(1)
+ end
+
+ it 'creates audit event' do
+ expected_message = 'Created feature flag <strong>feature_flag</strong> '\
+ 'with description <strong>"description"</strong>. '\
+ 'Created rule <strong>*</strong> and set it as <strong>active</strong> '\
+ 'with strategies <strong>[{"name"=>"default", "parameters"=>{}}]</strong>. '\
+ 'Created rule <strong>production</strong> and set it as <strong>inactive</strong> '\
+ 'with strategies <strong>[{"name"=>"default", "parameters"=>{}}]</strong>.'
+
+ expect { subject }.to change { AuditEvent.count }.by(1)
+ expect(AuditEvent.last.details[:custom_message]).to eq(expected_message)
+ end
+
+ context 'when user is reporter' do
+ let(:user) { reporter }
+
+ it 'returns error status' do
+ expect(subject[:status]).to eq(:error)
+ expect(subject[:message]).to eq('Access Denied')
+ end
+ end
+ end
+ end
+end
diff --git a/spec/services/feature_flags/destroy_service_spec.rb b/spec/services/feature_flags/destroy_service_spec.rb
new file mode 100644
index 00000000000..b35de02c628
--- /dev/null
+++ b/spec/services/feature_flags/destroy_service_spec.rb
@@ -0,0 +1,61 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe FeatureFlags::DestroyService do
+ include FeatureFlagHelpers
+
+ let_it_be(:project) { create(:project) }
+ let_it_be(:developer) { create(:user) }
+ let_it_be(:reporter) { create(:user) }
+ let(:user) { developer }
+ let!(:feature_flag) { create(:operations_feature_flag, project: project) }
+
+ before_all do
+ project.add_developer(developer)
+ project.add_reporter(reporter)
+ end
+
+ describe '#execute' do
+ subject { described_class.new(project, user, params).execute(feature_flag) }
+
+ let(:audit_event_message) { AuditEvent.last.details[:custom_message] }
+ let(:params) { {} }
+
+ it 'returns status success' do
+ expect(subject[:status]).to eq(:success)
+ end
+
+ it 'destroys feature flag' do
+ expect { subject }.to change { Operations::FeatureFlag.count }.by(-1)
+ end
+
+ it 'creates audit log' do
+ expect { subject }.to change { AuditEvent.count }.by(1)
+ expect(audit_event_message).to eq("Deleted feature flag <strong>#{feature_flag.name}</strong>.")
+ end
+
+ context 'when user is reporter' do
+ let(:user) { reporter }
+
+ it 'returns error status' do
+ expect(subject[:status]).to eq(:error)
+ expect(subject[:message]).to eq('Access Denied')
+ end
+ end
+
+ context 'when feature flag can not be destroyed' do
+ before do
+ allow(feature_flag).to receive(:destroy).and_return(false)
+ end
+
+ it 'returns status error' do
+ expect(subject[:status]).to eq(:error)
+ end
+
+ it 'does not create audit log' do
+ expect { subject }.not_to change { AuditEvent.count }
+ end
+ end
+ end
+end
diff --git a/spec/services/feature_flags/disable_service_spec.rb b/spec/services/feature_flags/disable_service_spec.rb
new file mode 100644
index 00000000000..de0f70bf552
--- /dev/null
+++ b/spec/services/feature_flags/disable_service_spec.rb
@@ -0,0 +1,91 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe FeatureFlags::DisableService do
+ include FeatureFlagHelpers
+
+ let_it_be(:project) { create(:project) }
+ let_it_be(:user) { create(:user) }
+ let(:params) { {} }
+ let(:service) { described_class.new(project, user, params) }
+
+ before_all do
+ project.add_developer(user)
+ end
+
+ describe '#execute' do
+ subject { service.execute }
+
+ context 'with params to disable default strategy on prd scope' do
+ let(:params) do
+ {
+ name: 'awesome',
+ environment_scope: 'prd',
+ strategy: { name: 'userWithId', parameters: { 'userIds': 'User:1' } }.deep_stringify_keys
+ }
+ end
+
+ context 'when there is a persisted feature flag' do
+ let!(:feature_flag) { create_flag(project, params[:name]) }
+
+ context 'when there is a persisted scope' do
+ let!(:scope) do
+ create_scope(feature_flag, params[:environment_scope], true, strategies)
+ end
+
+ context 'when there is a persisted strategy' do
+ let(:strategies) do
+ [
+ { name: 'userWithId', parameters: { 'userIds': 'User:1' } }.deep_stringify_keys,
+ { name: 'userWithId', parameters: { 'userIds': 'User:2' } }.deep_stringify_keys
+ ]
+ end
+
+ it 'deletes the specified strategy' do
+ subject
+
+ scope.reload
+ expect(scope.strategies.count).to eq(1)
+ expect(scope.strategies).not_to include(params[:strategy])
+ end
+
+ context 'when strategies will be empty' do
+ let(:strategies) { [params[:strategy]] }
+
+ it 'deletes the persisted scope' do
+ subject
+
+ expect(feature_flag.scopes.exists?(environment_scope: params[:environment_scope]))
+ .to eq(false)
+ end
+ end
+ end
+
+ context 'when there is no persisted strategy' do
+ let(:strategies) { [{ name: 'default', parameters: {} }] }
+
+ it 'returns error' do
+ expect(subject[:status]).to eq(:error)
+ expect(subject[:message]).to include('Strategy not found')
+ end
+ end
+ end
+
+ context 'when there is no persisted scope' do
+ it 'returns error' do
+ expect(subject[:status]).to eq(:error)
+ expect(subject[:message]).to include('Feature Flag Scope not found')
+ end
+ end
+ end
+
+ context 'when there is no persisted feature flag' do
+ it 'returns error' do
+ expect(subject[:status]).to eq(:error)
+ expect(subject[:message]).to include('Feature Flag not found')
+ end
+ end
+ end
+ end
+end
diff --git a/spec/services/feature_flags/enable_service_spec.rb b/spec/services/feature_flags/enable_service_spec.rb
new file mode 100644
index 00000000000..88c8028f6c5
--- /dev/null
+++ b/spec/services/feature_flags/enable_service_spec.rb
@@ -0,0 +1,153 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe FeatureFlags::EnableService do
+ include FeatureFlagHelpers
+
+ let_it_be(:project) { create(:project) }
+ let_it_be(:user) { create(:user) }
+ let(:params) { {} }
+ let(:service) { described_class.new(project, user, params) }
+
+ before_all do
+ project.add_developer(user)
+ end
+
+ describe '#execute' do
+ subject { service.execute }
+
+ context 'with params to enable default strategy on prd scope' do
+ let(:params) do
+ {
+ name: 'awesome',
+ environment_scope: 'prd',
+ strategy: { name: 'default', parameters: {} }.stringify_keys
+ }
+ end
+
+ context 'when there is no persisted feature flag' do
+ it 'creates a new feature flag with scope' do
+ feature_flag = subject[:feature_flag]
+ scope = feature_flag.scopes.find_by_environment_scope(params[:environment_scope])
+ expect(subject[:status]).to eq(:success)
+ expect(feature_flag.name).to eq(params[:name])
+ expect(feature_flag.default_scope).not_to be_active
+ expect(scope).to be_active
+ expect(scope.strategies).to include(params[:strategy])
+ end
+
+ context 'when params include default scope' do
+ let(:params) do
+ {
+ name: 'awesome',
+ environment_scope: '*',
+ strategy: { name: 'userWithId', parameters: { 'userIds': 'abc' } }.deep_stringify_keys
+ }
+ end
+
+ it 'create a new feature flag with an active default scope with the specified strategy' do
+ feature_flag = subject[:feature_flag]
+ expect(subject[:status]).to eq(:success)
+ expect(feature_flag.default_scope).to be_active
+ expect(feature_flag.default_scope.strategies).to include(params[:strategy])
+ end
+ end
+ end
+
+ context 'when there is a persisted feature flag' do
+ let!(:feature_flag) { create_flag(project, params[:name]) }
+
+ context 'when there is no persisted scope' do
+ it 'creates a new scope for the persisted feature flag' do
+ feature_flag = subject[:feature_flag]
+ scope = feature_flag.scopes.find_by_environment_scope(params[:environment_scope])
+ expect(subject[:status]).to eq(:success)
+ expect(feature_flag.name).to eq(params[:name])
+ expect(scope).to be_active
+ expect(scope.strategies).to include(params[:strategy])
+ end
+ end
+
+ context 'when there is a persisted scope' do
+ let!(:feature_flag_scope) do
+ create_scope(feature_flag, params[:environment_scope], active, strategies)
+ end
+
+ let(:active) { true }
+
+ context 'when the persisted scope does not have the specified strategy yet' do
+ let(:strategies) { [{ name: 'userWithId', parameters: { 'userIds': 'abc' } }] }
+
+ it 'adds the specified strategy to the scope' do
+ subject
+
+ feature_flag_scope.reload
+ expect(feature_flag_scope.strategies).to include(params[:strategy])
+ end
+
+ context 'when the persisted scope is inactive' do
+ let(:active) { false }
+
+ it 'reactivates the scope' do
+ expect { subject }
+ .to change { feature_flag_scope.reload.active }.from(false).to(true)
+ end
+ end
+ end
+
+ context 'when the persisted scope has the specified strategy already' do
+ let(:strategies) { [params[:strategy]] }
+
+ it 'does not add a duplicated strategy to the scope' do
+ expect { subject }
+ .not_to change { feature_flag_scope.reload.strategies.count }
+ end
+ end
+ end
+ end
+ end
+
+ context 'when strategy is not specified in params' do
+ let(:params) do
+ {
+ name: 'awesome',
+ environment_scope: 'prd'
+ }
+ end
+
+ it 'returns error' do
+ expect(subject[:status]).to eq(:error)
+ expect(subject[:message]).to include('Scopes strategies must be an array of strategy hashes')
+ end
+ end
+
+ context 'when environment scope is not specified in params' do
+ let(:params) do
+ {
+ name: 'awesome',
+ strategy: { name: 'default', parameters: {} }.stringify_keys
+ }
+ end
+
+ it 'returns error' do
+ expect(subject[:status]).to eq(:error)
+ expect(subject[:message]).to include("Scopes environment scope can't be blank")
+ end
+ end
+
+ context 'when name is not specified in params' do
+ let(:params) do
+ {
+ environment_scope: 'prd',
+ strategy: { name: 'default', parameters: {} }.stringify_keys
+ }
+ end
+
+ it 'returns error' do
+ expect(subject[:status]).to eq(:error)
+ expect(subject[:message]).to include("Name can't be blank")
+ end
+ end
+ end
+end
diff --git a/spec/services/feature_flags/update_service_spec.rb b/spec/services/feature_flags/update_service_spec.rb
new file mode 100644
index 00000000000..a982dd5166b
--- /dev/null
+++ b/spec/services/feature_flags/update_service_spec.rb
@@ -0,0 +1,250 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe FeatureFlags::UpdateService do
+ let_it_be(:project) { create(:project) }
+ let_it_be(:developer) { create(:user) }
+ let_it_be(:reporter) { create(:user) }
+ let(:user) { developer }
+ let(:feature_flag) { create(:operations_feature_flag, project: project, active: true) }
+
+ before_all do
+ project.add_developer(developer)
+ project.add_reporter(reporter)
+ end
+
+ describe '#execute' do
+ subject { described_class.new(project, user, params).execute(feature_flag) }
+
+ let(:params) { { name: 'new_name' } }
+ let(:audit_event_message) do
+ AuditEvent.last.details[:custom_message]
+ end
+
+ it 'returns success status' do
+ expect(subject[:status]).to eq(:success)
+ end
+
+ it 'creates audit event with correct message' do
+ name_was = feature_flag.name
+
+ expect { subject }.to change { AuditEvent.count }.by(1)
+ expect(audit_event_message).to(
+ eq("Updated feature flag <strong>new_name</strong>. "\
+ "Updated name from <strong>\"#{name_was}\"</strong> "\
+ "to <strong>\"new_name\"</strong>.")
+ )
+ end
+
+ context 'with invalid params' do
+ let(:params) { { name: nil } }
+
+ it 'returns error status' do
+ expect(subject[:status]).to eq(:error)
+ expect(subject[:http_status]).to eq(:bad_request)
+ end
+
+ it 'returns error messages' do
+ expect(subject[:message]).to include("Name can't be blank")
+ end
+
+ it 'does not create audit event' do
+ expect { subject }.not_to change { AuditEvent.count }
+ end
+ end
+
+ context 'when user is reporter' do
+ let(:user) { reporter }
+
+ it 'returns error status' do
+ expect(subject[:status]).to eq(:error)
+ expect(subject[:message]).to eq('Access Denied')
+ end
+ end
+
+ context 'when nothing is changed' do
+ let(:params) { {} }
+
+ it 'returns success status' do
+ expect(subject[:status]).to eq(:success)
+ end
+
+ it 'does not create audit event' do
+ expect { subject }.not_to change { AuditEvent.count }
+ end
+ end
+
+ context 'description is being changed' do
+ let(:params) { { description: 'new description' } }
+
+ it 'creates audit event with changed description' do
+ expect { subject }.to change { AuditEvent.count }.by(1)
+ expect(audit_event_message).to(
+ include("Updated description from <strong>\"\"</strong>"\
+ " to <strong>\"new description\"</strong>.")
+ )
+ end
+ end
+
+ context 'when flag active state is changed' do
+ let(:params) do
+ {
+ active: false
+ }
+ end
+
+ it 'creates audit event about changing active state' do
+ expect { subject }.to change { AuditEvent.count }.by(1)
+ expect(audit_event_message).to(
+ include('Updated active from <strong>"true"</strong> to <strong>"false"</strong>.')
+ )
+ end
+ end
+
+ context 'when scope active state is changed' do
+ let(:params) do
+ {
+ scopes_attributes: [{ id: feature_flag.scopes.first.id, active: false }]
+ }
+ end
+
+ it 'creates audit event about changing active state' do
+ expect { subject }.to change { AuditEvent.count }.by(1)
+ expect(audit_event_message).to(
+ include("Updated rule <strong>*</strong> active state "\
+ "from <strong>true</strong> to <strong>false</strong>.")
+ )
+ end
+ end
+
+ context 'when scope is renamed' do
+ let(:changed_scope) { feature_flag.scopes.create!(environment_scope: 'review', active: true) }
+ let(:params) do
+ {
+ scopes_attributes: [{ id: changed_scope.id, environment_scope: 'staging' }]
+ }
+ end
+
+ it 'creates audit event with changed name' do
+ expect { subject }.to change { AuditEvent.count }.by(1)
+ expect(audit_event_message).to(
+ include("Updated rule <strong>staging</strong> environment scope "\
+ "from <strong>review</strong> to <strong>staging</strong>.")
+ )
+ end
+
+ context 'when scope can not be updated' do
+ let(:params) do
+ {
+ scopes_attributes: [{ id: changed_scope.id, environment_scope: '' }]
+ }
+ end
+
+ it 'returns error status' do
+ expect(subject[:status]).to eq(:error)
+ end
+
+ it 'returns error messages' do
+ expect(subject[:message]).to include("Scopes environment scope can't be blank")
+ end
+
+ it 'does not create audit event' do
+ expect { subject }.not_to change { AuditEvent.count }
+ end
+ end
+ end
+
+ context 'when scope is deleted' do
+ let(:deleted_scope) { feature_flag.scopes.create!(environment_scope: 'review', active: true) }
+ let(:params) do
+ {
+ scopes_attributes: [{ id: deleted_scope.id, '_destroy': true }]
+ }
+ end
+
+ it 'creates audit event with deleted scope' do
+ expect { subject }.to change { AuditEvent.count }.by(1)
+ expect(audit_event_message).to include("Deleted rule <strong>review</strong>.")
+ end
+
+ context 'when scope can not be deleted' do
+ before do
+ allow(deleted_scope).to receive(:destroy).and_return(false)
+ end
+
+ it 'does not create audit event' do
+ expect do
+ subject
+ end.to not_change { AuditEvent.count }.and raise_error(ActiveRecord::RecordNotDestroyed)
+ end
+ end
+ end
+
+ context 'when new scope is being added' do
+ let(:new_environment_scope) { 'review' }
+ let(:params) do
+ {
+ scopes_attributes: [{ environment_scope: new_environment_scope, active: true }]
+ }
+ end
+
+ it 'creates audit event with new scope' do
+ expected = 'Created rule <strong>review</strong> and set it as <strong>active</strong> '\
+ 'with strategies <strong>[{"name"=>"default", "parameters"=>{}}]</strong>.'
+
+ subject
+
+ expect(audit_event_message).to include(expected)
+ end
+
+ context 'when scope can not be created' do
+ let(:new_environment_scope) { '' }
+
+ it 'returns error status' do
+ expect(subject[:status]).to eq(:error)
+ end
+
+ it 'returns error messages' do
+ expect(subject[:message]).to include("Scopes environment scope can't be blank")
+ end
+
+ it 'does not create audit event' do
+ expect { subject }.not_to change { AuditEvent.count }
+ end
+ end
+ end
+
+ context 'when the strategy is changed' do
+ let(:scope) do
+ create(:operations_feature_flag_scope,
+ feature_flag: feature_flag,
+ environment_scope: 'sandbox',
+ strategies: [{ name: "default", parameters: {} }])
+ end
+
+ let(:params) do
+ {
+ scopes_attributes: [{
+ id: scope.id,
+ environment_scope: 'sandbox',
+ strategies: [{
+ name: 'gradualRolloutUserId',
+ parameters: {
+ groupId: 'mygroup',
+ percentage: "40"
+ }
+ }]
+ }]
+ }
+ end
+
+ it 'creates an audit event' do
+ expected = %r{Updated rule <strong>sandbox</strong> strategies from <strong>.*</strong> to <strong>.*</strong>.}
+
+ expect { subject }.to change { AuditEvent.count }.by(1)
+ expect(audit_event_message).to match(expected)
+ end
+ end
+ end
+end
diff --git a/spec/services/git/branch_hooks_service_spec.rb b/spec/services/git/branch_hooks_service_spec.rb
index db25bb766c9..a5290f0be68 100644
--- a/spec/services/git/branch_hooks_service_spec.rb
+++ b/spec/services/git/branch_hooks_service_spec.rb
@@ -429,4 +429,26 @@ RSpec.describe Git::BranchHooksService do
end
end
end
+
+ describe 'Metrics dashboard sync' do
+ context 'with feature flag enabled' do
+ before do
+ Feature.enable(:metrics_dashboards_sync)
+ end
+
+ it 'imports metrics to database' do
+ expect(Metrics::Dashboard::SyncDashboardsWorker).to receive(:perform_async)
+
+ service.execute
+ end
+ end
+
+ context 'with feature flag disabled' do
+ it 'imports metrics to database' do
+ expect(Metrics::Dashboard::SyncDashboardsWorker).to receive(:perform_async)
+
+ service.execute
+ end
+ end
+ end
end
diff --git a/spec/services/git/wiki_push_service_spec.rb b/spec/services/git/wiki_push_service_spec.rb
index 816f20f0bc3..cd38f2e97fb 100644
--- a/spec/services/git/wiki_push_service_spec.rb
+++ b/spec/services/git/wiki_push_service_spec.rb
@@ -254,24 +254,6 @@ RSpec.describe Git::WikiPushService, services: true do
service.execute
end
end
-
- context 'the wiki_events_on_git_push feature is disabled' do
- before do
- stub_feature_flags(wiki_events_on_git_push: false)
- end
-
- it_behaves_like 'a no-op push'
-
- context 'but is enabled for a given container' do
- before do
- stub_feature_flags(wiki_events_on_git_push: wiki.container)
- end
-
- it 'creates events' do
- expect { process_changes { write_new_page } }.to change(Event, :count).by(1)
- end
- end
- end
end
end
diff --git a/spec/services/groups/create_service_spec.rb b/spec/services/groups/create_service_spec.rb
index fc877f45a39..4f5bc3a3d5a 100644
--- a/spec/services/groups/create_service_spec.rb
+++ b/spec/services/groups/create_service_spec.rb
@@ -45,6 +45,15 @@ RSpec.describe Groups::CreateService, '#execute' do
end
end
+ context 'creating a group with `allow_mfa_for_subgroups` attribute' do
+ let(:params) { group_params.merge(allow_mfa_for_subgroups: false) }
+ let(:service) { described_class.new(user, params) }
+
+ it 'creates group without error' do
+ expect(service.execute).to be_persisted
+ end
+ end
+
describe 'creating a top level group' do
let(:service) { described_class.new(user, group_params) }
@@ -138,4 +147,91 @@ RSpec.describe Groups::CreateService, '#execute' do
expect(group.namespace_settings).to be_persisted
end
end
+
+ describe 'create service for the group' do
+ let(:service) { described_class.new(user, group_params) }
+ let(:created_group) { service.execute }
+
+ context 'with an active instance-level integration' do
+ let!(:instance_integration) { create(:prometheus_service, :instance, api_url: 'https://prometheus.instance.com/') }
+
+ it 'creates a service from the instance-level integration' do
+ expect(created_group.services.count).to eq(1)
+ expect(created_group.services.first.api_url).to eq(instance_integration.api_url)
+ expect(created_group.services.first.inherit_from_id).to eq(instance_integration.id)
+ end
+
+ context 'with an active group-level integration' do
+ let(:service) { described_class.new(user, group_params.merge(parent_id: group.id)) }
+ let!(:group_integration) { create(:prometheus_service, group: group, project: nil, api_url: 'https://prometheus.group.com/') }
+ let(:group) do
+ create(:group).tap do |group|
+ group.add_owner(user)
+ end
+ end
+
+ it 'creates a service from the group-level integration' do
+ expect(created_group.services.count).to eq(1)
+ expect(created_group.services.first.api_url).to eq(group_integration.api_url)
+ expect(created_group.services.first.inherit_from_id).to eq(group_integration.id)
+ end
+
+ context 'with an active subgroup' do
+ let(:service) { described_class.new(user, group_params.merge(parent_id: subgroup.id)) }
+ let!(:subgroup_integration) { create(:prometheus_service, group: subgroup, project: nil, api_url: 'https://prometheus.subgroup.com/') }
+ let(:subgroup) do
+ create(:group, parent: group).tap do |subgroup|
+ subgroup.add_owner(user)
+ end
+ end
+
+ it 'creates a service from the subgroup-level integration' do
+ expect(created_group.services.count).to eq(1)
+ expect(created_group.services.first.api_url).to eq(subgroup_integration.api_url)
+ expect(created_group.services.first.inherit_from_id).to eq(subgroup_integration.id)
+ end
+ end
+ end
+ end
+ end
+
+ context 'shared runners configuration' do
+ context 'parent group present' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:shared_runners_config, :descendants_override_disabled_shared_runners_config) do
+ true | false
+ false | false
+ # true | true # invalid at the group level, leaving as comment to make explicit
+ false | true
+ end
+
+ with_them do
+ let!(:group) { create(:group, shared_runners_enabled: shared_runners_config, allow_descendants_override_disabled_shared_runners: descendants_override_disabled_shared_runners_config) }
+ let!(:service) { described_class.new(user, group_params.merge(parent_id: group.id)) }
+
+ before do
+ group.add_owner(user)
+ end
+
+ it 'creates group following the parent config' do
+ new_group = service.execute
+
+ expect(new_group.shared_runners_enabled).to eq(shared_runners_config)
+ expect(new_group.allow_descendants_override_disabled_shared_runners).to eq(descendants_override_disabled_shared_runners_config)
+ end
+ end
+ end
+
+ context 'root group' do
+ let!(:service) { described_class.new(user) }
+
+ it 'follows default config' do
+ new_group = service.execute
+
+ expect(new_group.shared_runners_enabled).to eq(true)
+ expect(new_group.allow_descendants_override_disabled_shared_runners).to eq(false)
+ end
+ end
+ end
end
diff --git a/spec/services/groups/import_export/import_service_spec.rb b/spec/services/groups/import_export/import_service_spec.rb
index 4aac602a6da..f284225e23a 100644
--- a/spec/services/groups/import_export/import_service_spec.rb
+++ b/spec/services/groups/import_export/import_service_spec.rb
@@ -10,6 +10,15 @@ RSpec.describe Groups::ImportExport::ImportService do
context 'when the job can be successfully scheduled' do
subject(:import_service) { described_class.new(group: group, user: user) }
+ it 'creates group import state' do
+ import_service.async_execute
+
+ import_state = group.import_state
+
+ expect(import_state.user).to eq(user)
+ expect(import_state.group).to eq(group)
+ end
+
it 'enqueues an import job' do
expect(GroupImportWorker).to receive(:perform_async).with(user.id, group.id)
diff --git a/spec/services/groups/transfer_service_spec.rb b/spec/services/groups/transfer_service_spec.rb
index 89e4d091ff7..ae04eca3a9f 100644
--- a/spec/services/groups/transfer_service_spec.rb
+++ b/spec/services/groups/transfer_service_spec.rb
@@ -285,6 +285,44 @@ RSpec.describe Groups::TransferService do
end
end
+ context 'shared runners configuration' do
+ before do
+ create(:group_member, :owner, group: new_parent_group, user: user)
+ end
+
+ context 'if parent group has disabled shared runners but allows overrides' do
+ let(:new_parent_group) { create(:group, shared_runners_enabled: false, allow_descendants_override_disabled_shared_runners: true) }
+
+ it 'calls update service' do
+ expect(Groups::UpdateSharedRunnersService).to receive(:new).with(group, user, { shared_runners_setting: 'disabled_with_override' }).and_call_original
+
+ transfer_service.execute(new_parent_group)
+ end
+ end
+
+ context 'if parent group does not allow shared runners' do
+ let(:new_parent_group) { create(:group, shared_runners_enabled: false, allow_descendants_override_disabled_shared_runners: false) }
+
+ it 'calls update service' do
+ expect(Groups::UpdateSharedRunnersService).to receive(:new).with(group, user, { shared_runners_setting: 'disabled_and_unoverridable' }).and_call_original
+
+ transfer_service.execute(new_parent_group)
+ end
+ end
+
+ context 'if parent group allows shared runners' do
+ let(:group) { create(:group, :public, :nested, shared_runners_enabled: false) }
+ let(:new_parent_group) { create(:group, shared_runners_enabled: true) }
+
+ it 'does not call update service and keeps them disabled on the group' do
+ expect(Groups::UpdateSharedRunnersService).not_to receive(:new)
+
+ transfer_service.execute(new_parent_group)
+ expect(group.reload.shared_runners_enabled).to be_falsy
+ end
+ end
+ end
+
context 'when a group is transferred to its subgroup' do
let(:new_parent_group) { create(:group, parent: group) }
@@ -529,6 +567,39 @@ RSpec.describe Groups::TransferService do
end
end
+ context 'when transferring a group with two factor authentication switched on' do
+ before do
+ TestEnv.clean_test_path
+ create(:group_member, :owner, group: new_parent_group, user: user)
+ create(:group, :private, parent: group, require_two_factor_authentication: true)
+ group.update!(require_two_factor_authentication: true)
+ end
+
+ it 'does not update group two factor authentication setting' do
+ transfer_service.execute(new_parent_group)
+
+ expect(group.require_two_factor_authentication).to eq(true)
+ end
+
+ context 'when new parent disallows two factor authentication switched on for descendants' do
+ before do
+ new_parent_group.namespace_settings.update!(allow_mfa_for_subgroups: false)
+ end
+
+ it 'updates group two factor authentication setting' do
+ transfer_service.execute(new_parent_group)
+
+ expect(group.require_two_factor_authentication).to eq(false)
+ end
+
+ it 'schedules update of group two factor authentication setting for descendants' do
+ expect(DisallowTwoFactorForSubgroupsWorker).to receive(:perform_async).with(group.id)
+
+ transfer_service.execute(new_parent_group)
+ end
+ end
+ end
+
context 'when updating the group goes wrong' do
let!(:subgroup1) { create(:group, :public, parent: group) }
let!(:subgroup2) { create(:group, :public, parent: group) }
diff --git a/spec/services/groups/update_service_spec.rb b/spec/services/groups/update_service_spec.rb
index 1e6a8d53354..bc7c066fa04 100644
--- a/spec/services/groups/update_service_spec.rb
+++ b/spec/services/groups/update_service_spec.rb
@@ -283,6 +283,50 @@ RSpec.describe Groups::UpdateService do
end
end
+ context 'change shared Runners config' do
+ let(:group) { create(:group) }
+ let(:project) { create(:project, shared_runners_enabled: true, group: group) }
+
+ subject { described_class.new(group, user, shared_runners_setting: 'disabled_and_unoverridable').execute }
+
+ before do
+ group.add_owner(user)
+ end
+
+ it 'calls the shared runners update service' do
+ expect_any_instance_of(::Groups::UpdateSharedRunnersService).to receive(:execute).and_return({ status: :success })
+
+ expect(subject).to be_truthy
+ end
+
+ it 'handles errors in the shared runners update service' do
+ expect_any_instance_of(::Groups::UpdateSharedRunnersService).to receive(:execute).and_return({ status: :error, message: 'something happened' })
+
+ expect(subject).to be_falsy
+
+ expect(group.errors[:update_shared_runners].first).to eq('something happened')
+ end
+ end
+
+ context 'changes allowing subgroups to establish own 2FA' do
+ let(:group) { create(:group) }
+ let(:params) { { allow_mfa_for_subgroups: false } }
+
+ subject { described_class.new(group, user, params).execute }
+
+ it 'changes settings' do
+ subject
+
+ expect(group.namespace_settings.reload.allow_mfa_for_subgroups).to eq(false)
+ end
+
+ it 'enqueues update subgroups and its members' do
+ expect(DisallowTwoFactorForSubgroupsWorker).to receive(:perform_async).with(group.id)
+
+ subject
+ end
+ end
+
def update_group(group, user, opts)
Groups::UpdateService.new(group, user, opts).execute
end
diff --git a/spec/services/groups/update_shared_runners_service_spec.rb b/spec/services/groups/update_shared_runners_service_spec.rb
index 9fd8477a455..e2838c4ce0b 100644
--- a/spec/services/groups/update_shared_runners_service_spec.rb
+++ b/spec/services/groups/update_shared_runners_service_spec.rb
@@ -13,17 +13,14 @@ RSpec.describe Groups::UpdateSharedRunnersService do
context 'when current_user is not the group owner' do
let_it_be(:group) { create(:group) }
- let(:params) { { shared_runners_enabled: '0' } }
+ let(:params) { { shared_runners_setting: 'enabled' } }
before do
group.add_maintainer(user)
end
it 'results error and does not call any method' do
- expect(group).not_to receive(:enable_shared_runners!)
- expect(group).not_to receive(:disable_shared_runners!)
- expect(group).not_to receive(:allow_descendants_override_disabled_shared_runners!)
- expect(group).not_to receive(:disallow_descendants_override_disabled_shared_runners!)
+ expect(group).not_to receive(:update_shared_runners_setting!)
expect(subject[:status]).to eq(:error)
expect(subject[:message]).to eq('Operation not allowed')
@@ -37,191 +34,60 @@ RSpec.describe Groups::UpdateSharedRunnersService do
end
context 'enable shared Runners' do
- where(:desired_params) do
- ['1', true]
- end
-
- with_them do
- let(:params) { { shared_runners_enabled: desired_params } }
-
- context 'group that its ancestors have shared runners disabled' do
- let_it_be(:parent) { create(:group, :shared_runners_disabled) }
- let_it_be(:group) { create(:group, :shared_runners_disabled, parent: parent) }
-
- it 'results error' do
- expect(subject[:status]).to eq(:error)
- expect(subject[:message]).to eq('Shared Runners disabled for the parent group')
- end
- end
+ let(:params) { { shared_runners_setting: 'enabled' } }
- context 'root group with shared runners disabled' do
- let_it_be(:group) { create(:group, :shared_runners_disabled) }
+ context 'group that its ancestors have shared runners disabled' do
+ let_it_be(:parent) { create(:group, :shared_runners_disabled) }
+ let_it_be(:group) { create(:group, :shared_runners_disabled, parent: parent) }
- it 'receives correct method and succeeds' do
- expect(group).to receive(:enable_shared_runners!)
- expect(group).not_to receive(:disable_shared_runners!)
- expect(group).not_to receive(:allow_descendants_override_disabled_shared_runners!)
- expect(group).not_to receive(:disallow_descendants_override_disabled_shared_runners!)
-
- expect(subject[:status]).to eq(:success)
- end
+ it 'results error' do
+ expect(subject[:status]).to eq(:error)
+ expect(subject[:message]).to eq('Validation failed: Shared runners enabled cannot be enabled because parent group has shared Runners disabled')
end
end
- end
-
- context 'disable shared Runners' do
- let_it_be(:group) { create(:group) }
-
- where(:desired_params) do
- ['0', false]
- end
- with_them do
- let(:params) { { shared_runners_enabled: desired_params } }
+ context 'root group with shared runners disabled' do
+ let_it_be(:group) { create(:group, :shared_runners_disabled) }
it 'receives correct method and succeeds' do
- expect(group).to receive(:disable_shared_runners!)
- expect(group).not_to receive(:enable_shared_runners!)
- expect(group).not_to receive(:allow_descendants_override_disabled_shared_runners!)
- expect(group).not_to receive(:disallow_descendants_override_disabled_shared_runners!)
+ expect(group).to receive(:update_shared_runners_setting!).with('enabled')
expect(subject[:status]).to eq(:success)
end
end
end
- context 'allow descendants to override' do
- where(:desired_params) do
- ['1', true]
- end
-
- with_them do
- let(:params) { { allow_descendants_override_disabled_shared_runners: desired_params } }
-
- context 'top level group' do
- let_it_be(:group) { create(:group, :shared_runners_disabled) }
-
- it 'receives correct method and succeeds' do
- expect(group).to receive(:allow_descendants_override_disabled_shared_runners!)
- expect(group).not_to receive(:disallow_descendants_override_disabled_shared_runners!)
- expect(group).not_to receive(:enable_shared_runners!)
- expect(group).not_to receive(:disable_shared_runners!)
-
- expect(subject[:status]).to eq(:success)
- end
- end
+ context 'disable shared Runners' do
+ let_it_be(:group) { create(:group) }
+ let(:params) { { shared_runners_setting: 'disabled_and_unoverridable' } }
- 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(:group) { create(:group, :shared_runners_disabled, allow_descendants_override_disabled_shared_runners: false, parent: parent) }
+ it 'receives correct method and succeeds' do
+ expect(group).to receive(:update_shared_runners_setting!).with('disabled_and_unoverridable')
- it 'results error' do
- expect(subject[:status]).to eq(:error)
- expect(subject[:message]).to eq('Group level shared Runners not allowed')
- end
- end
+ expect(subject[:status]).to eq(:success)
end
end
- context 'disallow descendants to override' do
- where(:desired_params) do
- ['0', false]
- end
-
- with_them do
- let(:params) { { allow_descendants_override_disabled_shared_runners: desired_params } }
-
- context 'top level group' do
- let_it_be(:group) { create(:group, :shared_runners_disabled, :allow_descendants_override_disabled_shared_runners ) }
-
- it 'receives correct method and succeeds' do
- expect(group).to receive(:disallow_descendants_override_disabled_shared_runners!)
- expect(group).not_to receive(:allow_descendants_override_disabled_shared_runners!)
- expect(group).not_to receive(:enable_shared_runners!)
- expect(group).not_to receive(:disable_shared_runners!)
-
- expect(subject[:status]).to eq(:success)
- end
- end
-
- context 'top level group that has shared Runners enabled' do
- let_it_be(:group) { create(:group, shared_runners_enabled: true) }
-
- it 'results error' do
- expect(subject[:status]).to eq(:error)
- expect(subject[:message]).to eq('Shared Runners enabled')
- end
- end
- end
- end
+ context 'allow descendants to override' do
+ let(:params) { { shared_runners_setting: 'disabled_with_override' } }
- context 'both params are present' do
- context 'shared_runners_enabled: 1 and allow_descendants_override_disabled_shared_runners' do
+ context 'top level group' do
let_it_be(:group) { create(:group, :shared_runners_disabled) }
- let_it_be(:sub_group) { create(:group, :shared_runners_disabled, parent: group) }
- let_it_be(:project) { create(:project, shared_runners_enabled: false, group: sub_group) }
- where(:allow_descendants_override) do
- ['1', true, '0', false]
- end
+ it 'receives correct method and succeeds' do
+ expect(group).to receive(:update_shared_runners_setting!).with('disabled_with_override')
- with_them do
- let(:params) { { shared_runners_enabled: '1', allow_descendants_override_disabled_shared_runners: allow_descendants_override } }
-
- it 'results in an error because shared Runners are enabled' do
- expect { subject }
- .to not_change { group.reload.shared_runners_enabled }
- .and not_change { sub_group.reload.shared_runners_enabled }
- .and not_change { project.reload.shared_runners_enabled }
- .and not_change { group.reload.allow_descendants_override_disabled_shared_runners }
- .and not_change { sub_group.reload.allow_descendants_override_disabled_shared_runners }
- expect(subject[:status]).to eq(:error)
- expect(subject[:message]).to eq('Cannot set shared_runners_enabled to true and allow_descendants_override_disabled_shared_runners')
- end
+ expect(subject[:status]).to eq(:success)
end
end
- context 'shared_runners_enabled: 0 and allow_descendants_override_disabled_shared_runners: 0' do
- let_it_be(:group) { create(:group, :allow_descendants_override_disabled_shared_runners) }
- let_it_be(:sub_group) { create(:group, :shared_runners_disabled, :allow_descendants_override_disabled_shared_runners, parent: group) }
- let_it_be(:sub_group_2) { create(:group, parent: group) }
- let_it_be(:project) { create(:project, group: group, shared_runners_enabled: true) }
- let_it_be(:project_2) { create(:project, group: sub_group_2, shared_runners_enabled: true) }
-
- let(:params) { { shared_runners_enabled: '0', allow_descendants_override_disabled_shared_runners: '0' } }
-
- it 'disables shared Runners and disable allow_descendants_override_disabled_shared_runners' do
- expect { subject }
- .to change { group.reload.shared_runners_enabled }.from(true).to(false)
- .and change { group.reload.allow_descendants_override_disabled_shared_runners }.from(true).to(false)
- .and not_change { sub_group.reload.shared_runners_enabled }
- .and change { sub_group.reload.allow_descendants_override_disabled_shared_runners }.from(true).to(false)
- .and change { sub_group_2.reload.shared_runners_enabled }.from(true).to(false)
- .and not_change { sub_group_2.reload.allow_descendants_override_disabled_shared_runners }
- .and change { project.reload.shared_runners_enabled }.from(true).to(false)
- .and change { project_2.reload.shared_runners_enabled }.from(true).to(false)
- end
- 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(:group) { create(:group, :shared_runners_disabled, allow_descendants_override_disabled_shared_runners: false, parent: parent) }
- context 'shared_runners_enabled: 0 and allow_descendants_override_disabled_shared_runners: 1' do
- let_it_be(:group) { create(:group) }
- let_it_be(:sub_group) { create(:group, :shared_runners_disabled, parent: group) }
- let_it_be(:sub_group_2) { create(:group, parent: group) }
- let_it_be(:project) { create(:project, group: group, shared_runners_enabled: true) }
- let_it_be(:project_2) { create(:project, group: sub_group_2, shared_runners_enabled: true) }
-
- let(:params) { { shared_runners_enabled: '0', allow_descendants_override_disabled_shared_runners: '1' } }
-
- it 'disables shared Runners and enable allow_descendants_override_disabled_shared_runners only for itself' do
- expect { subject }
- .to change { group.reload.shared_runners_enabled }.from(true).to(false)
- .and change { group.reload.allow_descendants_override_disabled_shared_runners }.from(false).to(true)
- .and not_change { sub_group.reload.shared_runners_enabled }
- .and not_change { sub_group.reload.allow_descendants_override_disabled_shared_runners }
- .and change { sub_group_2.reload.shared_runners_enabled }.from(true).to(false)
- .and not_change { sub_group_2.reload.allow_descendants_override_disabled_shared_runners }
- .and change { project.reload.shared_runners_enabled }.from(true).to(false)
- .and change { project_2.reload.shared_runners_enabled }.from(true).to(false)
+ it 'results error' do
+ expect(subject[:status]).to eq(:error)
+ expect(subject[:message]).to eq('Validation failed: Allow descendants override disabled shared runners cannot be enabled because parent group does not allow it')
end
end
end
diff --git a/spec/services/incident_management/create_incident_label_service_spec.rb b/spec/services/incident_management/create_incident_label_service_spec.rb
index 4771dfc9e64..441cddf1d2e 100644
--- a/spec/services/incident_management/create_incident_label_service_spec.rb
+++ b/spec/services/incident_management/create_incident_label_service_spec.rb
@@ -3,65 +3,5 @@
require 'spec_helper'
RSpec.describe IncidentManagement::CreateIncidentLabelService do
- let_it_be(:project) { create(:project, :private) }
- let_it_be(:user) { User.alert_bot }
- let(:service) { described_class.new(project, user) }
-
- subject(:execute) { service.execute }
-
- describe 'execute' do
- let(:incident_label_attributes) { attributes_for(:label, :incident) }
- let(:title) { incident_label_attributes[:title] }
- let(:color) { incident_label_attributes[:color] }
- let(:description) { incident_label_attributes[:description] }
-
- shared_examples 'existing label' do
- it 'returns the existing label' do
- expect { execute }.not_to change(Label, :count)
-
- expect(execute).to be_success
- expect(execute.payload).to eq(label: label)
- end
- end
-
- shared_examples 'new label' do
- it 'creates a new label' do
- expect { execute }.to change(Label, :count).by(1)
-
- label = project.reload.labels.last
- expect(execute).to be_success
- expect(execute.payload).to eq(label: label)
- expect(label.title).to eq(title)
- expect(label.color).to eq(color)
- expect(label.description).to eq(description)
- end
- end
-
- context 'with predefined project label' do
- it_behaves_like 'existing label' do
- let!(:label) { create(:label, project: project, title: title) }
- end
- end
-
- context 'with predefined group label' do
- let(:project) { create(:project, group: group) }
- let(:group) { create(:group) }
-
- it_behaves_like 'existing label' do
- let!(:label) { create(:group_label, group: group, title: title) }
- end
- end
-
- context 'without label' do
- context 'when user has permissions to create labels' do
- it_behaves_like 'new label'
- end
-
- context 'when user has no permissions to create labels' do
- let_it_be(:user) { create(:user) }
-
- it_behaves_like 'new label'
- end
- end
- end
+ it_behaves_like 'incident management label service'
end
diff --git a/spec/services/incident_management/incidents/update_severity_service_spec.rb b/spec/services/incident_management/incidents/update_severity_service_spec.rb
new file mode 100644
index 00000000000..bc1abf82cf2
--- /dev/null
+++ b/spec/services/incident_management/incidents/update_severity_service_spec.rb
@@ -0,0 +1,86 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe IncidentManagement::Incidents::UpdateSeverityService do
+ let_it_be(:user) { create(:user) }
+
+ describe '#execute' do
+ let(:severity) { 'low' }
+ let(:system_note_worker) { ::IncidentManagement::AddSeveritySystemNoteWorker }
+
+ subject(:update_severity) { described_class.new(issuable, user, severity).execute }
+
+ before do
+ allow(system_note_worker).to receive(:perform_async)
+ end
+
+ shared_examples 'adds a system note' do
+ it 'calls AddSeveritySystemNoteWorker' do
+ update_severity
+
+ expect(system_note_worker).to have_received(:perform_async).with(issuable.id, user.id)
+ end
+ end
+
+ context 'when issuable not an incident' do
+ %i(issue merge_request).each do |issuable_type|
+ let(:issuable) { build_stubbed(issuable_type) }
+
+ it { is_expected.to be_nil }
+
+ it 'does not set severity' do
+ expect { update_severity }.not_to change(IssuableSeverity, :count)
+ end
+
+ it 'does not add a system note' do
+ update_severity
+
+ expect(system_note_worker).not_to have_received(:perform_async)
+ end
+ end
+ end
+
+ context 'when issuable is an incident' do
+ let!(:issuable) { create(:incident) }
+
+ context 'when issuable does not have issuable severity yet' do
+ it 'creates new record' do
+ expect { update_severity }.to change { IssuableSeverity.where(issue: issuable).count }.to(1)
+ end
+
+ it 'sets severity to specified value' do
+ expect { update_severity }.to change { issuable.severity }.to('low')
+ end
+
+ it_behaves_like 'adds a system note'
+ end
+
+ context 'when issuable has an issuable severity' do
+ let!(:issuable_severity) { create(:issuable_severity, issue: issuable, severity: 'medium') }
+
+ it 'does not create new record' do
+ expect { update_severity }.not_to change(IssuableSeverity, :count)
+ end
+
+ it 'updates existing issuable severity' do
+ expect { update_severity }.to change { issuable_severity.severity }.to(severity)
+ end
+
+ it_behaves_like 'adds a system note'
+ end
+
+ context 'when severity value is unsupported' do
+ let(:severity) { 'unsupported-severity' }
+
+ it 'sets the severity to default value' do
+ update_severity
+
+ expect(issuable.issuable_severity.severity).to eq(IssuableSeverity::DEFAULT)
+ end
+
+ it_behaves_like 'adds a system note'
+ end
+ end
+ end
+end
diff --git a/spec/services/issuable/bulk_update_service_spec.rb b/spec/services/issuable/bulk_update_service_spec.rb
index 168a80a97c0..f2bc4f717af 100644
--- a/spec/services/issuable/bulk_update_service_spec.rb
+++ b/spec/services/issuable/bulk_update_service_spec.rb
@@ -254,7 +254,7 @@ RSpec.describe Issuable::BulkUpdateService do
describe 'unsubscribe from issues' do
let(:issues) do
create_list(:closed_issue, 2, project: project) do |issue|
- issue.subscriptions.create(user: user, project: project, subscribed: true)
+ issue.subscriptions.create!(user: user, project: project, subscribed: true)
end
end
diff --git a/spec/services/issuable/clone/attributes_rewriter_spec.rb b/spec/services/issuable/clone/attributes_rewriter_spec.rb
index 372e6d480e3..7f434b8b246 100644
--- a/spec/services/issuable/clone/attributes_rewriter_spec.rb
+++ b/spec/services/issuable/clone/attributes_rewriter_spec.rb
@@ -20,7 +20,7 @@ RSpec.describe Issuable::Clone::AttributesRewriter do
group_label = create(:group_label, title: 'group_label', group: group)
create(:label, title: 'label3', project: project2)
- original_issue.update(labels: [project1_label_1, project1_label_2, group_label])
+ original_issue.update!(labels: [project1_label_1, project1_label_2, group_label])
subject.execute
@@ -48,7 +48,7 @@ RSpec.describe Issuable::Clone::AttributesRewriter do
it 'sets milestone to nil when old issue milestone is not in the new project' do
milestone = create(:milestone, title: 'milestone', project: project1)
- original_issue.update(milestone: milestone)
+ original_issue.update!(milestone: milestone)
subject.execute
@@ -59,7 +59,7 @@ RSpec.describe Issuable::Clone::AttributesRewriter do
milestone_project1 = create(:milestone, title: 'milestone', project: project1)
milestone_project2 = create(:milestone, title: 'milestone', project: project2)
- original_issue.update(milestone: milestone_project1)
+ original_issue.update!(milestone: milestone_project1)
subject.execute
@@ -69,7 +69,7 @@ RSpec.describe Issuable::Clone::AttributesRewriter do
it 'copies the milestone when old issue milestone is a group milestone' do
milestone = create(:milestone, title: 'milestone', group: group)
- original_issue.update(milestone: milestone)
+ original_issue.update!(milestone: milestone)
subject.execute
@@ -85,7 +85,7 @@ RSpec.describe Issuable::Clone::AttributesRewriter do
let!(:milestone2_project2) { create(:milestone, title: 'milestone2', project: project2) }
before do
- original_issue.update(milestone: milestone2_project1)
+ original_issue.update!(milestone: milestone2_project1)
create_event(milestone1_project1)
create_event(milestone2_project1)
diff --git a/spec/services/issuable/common_system_notes_service_spec.rb b/spec/services/issuable/common_system_notes_service_spec.rb
index 217550542bb..fc01ee8f672 100644
--- a/spec/services/issuable/common_system_notes_service_spec.rb
+++ b/spec/services/issuable/common_system_notes_service_spec.rb
@@ -19,7 +19,7 @@ RSpec.describe Issuable::CommonSystemNotesService do
before do
issuable.labels << label
- issuable.save
+ issuable.save!
end
it 'creates a resource label event' do
@@ -69,7 +69,7 @@ RSpec.describe Issuable::CommonSystemNotesService do
subject { described_class.new(project, user).execute(issuable, old_labels: [], is_update: false) }
it 'does not create system note for title and description' do
- issuable.save
+ issuable.save!
expect { subject }.not_to change { issuable.notes.count }
end
@@ -78,7 +78,7 @@ RSpec.describe Issuable::CommonSystemNotesService do
label = create(:label, project: project)
issuable.labels << label
- issuable.save
+ issuable.save!
expect { subject }.to change { issuable.resource_label_events.count }.from(0).to(1)
@@ -104,7 +104,7 @@ RSpec.describe Issuable::CommonSystemNotesService do
it 'creates a system note for due_date set' do
issuable.due_date = Date.today
- issuable.save
+ issuable.save!
expect { subject }.to change { issuable.notes.count }.from(0).to(1)
expect(issuable.notes.last.note).to match('changed due date')
diff --git a/spec/services/issues/build_service_spec.rb b/spec/services/issues/build_service_spec.rb
index 93eef8a2732..16433d49ca1 100644
--- a/spec/services/issues/build_service_spec.rb
+++ b/spec/services/issues/build_service_spec.rb
@@ -3,11 +3,14 @@
require 'spec_helper.rb'
RSpec.describe Issues::BuildService do
- let(:project) { create(:project, :repository) }
- let(:user) { create(:user) }
-
- before do
- project.add_developer(user)
+ let_it_be(:project) { create(:project, :repository) }
+ let_it_be(:developer) { create(:user) }
+ let_it_be(:guest) { create(:user) }
+ let(:user) { developer }
+
+ before_all do
+ project.add_developer(developer)
+ project.add_guest(guest)
end
def build_issue(issue_params = {})
@@ -134,31 +137,56 @@ RSpec.describe Issues::BuildService do
end
describe '#execute' do
- it 'builds a new issues with given params' do
- milestone = create(:milestone, project: project)
- issue = build_issue(milestone_id: milestone.id)
+ context 'as developer' do
+ it 'builds a new issues with given params' do
+ milestone = create(:milestone, project: project)
+ issue = build_issue(milestone_id: milestone.id)
- expect(issue.milestone).to eq(milestone)
- end
+ expect(issue.milestone).to eq(milestone)
+ end
- it 'sets milestone to nil if it is not available for the project' do
- milestone = create(:milestone, project: create(:project))
- issue = build_issue(milestone_id: milestone.id)
+ it 'sets milestone to nil if it is not available for the project' do
+ milestone = create(:milestone, project: create(:project))
+ issue = build_issue(milestone_id: milestone.id)
- expect(issue.milestone).to be_nil
+ expect(issue.milestone).to be_nil
+ end
end
- context 'setting issue type' do
- it 'sets the issue_type on the issue' do
- issue = build_issue(issue_type: 'incident')
+ context 'as guest' do
+ let(:user) { guest }
- expect(issue.issue_type).to eq('incident')
+ it 'cannot set milestone' do
+ milestone = create(:milestone, project: project)
+ issue = build_issue(milestone_id: milestone.id)
+
+ expect(issue.milestone).to be_nil
end
- it 'defaults to issue if issue_type not given' do
- issue = build_issue
+ context 'setting issue type' do
+ it 'defaults to issue if issue_type not given' do
+ issue = build_issue
+
+ expect(issue).to be_issue
+ end
+
+ it 'sets issue' do
+ issue = build_issue(issue_type: 'issue')
+
+ expect(issue).to be_issue
+ end
+
+ it 'sets incident' do
+ issue = build_issue(issue_type: 'incident')
- expect(issue.issue_type).to eq('issue')
+ expect(issue).to be_incident
+ end
+
+ it 'cannot set invalid type' do
+ expect do
+ build_issue(issue_type: 'invalid type')
+ end.to raise_error(ArgumentError, "'invalid type' is not a valid issue_type")
+ end
end
end
end
diff --git a/spec/services/issues/close_service_spec.rb b/spec/services/issues/close_service_spec.rb
index 4db6e5cac12..9076fb11c9b 100644
--- a/spec/services/issues/close_service_spec.rb
+++ b/spec/services/issues/close_service_spec.rb
@@ -233,26 +233,11 @@ RSpec.describe Issues::CloseService do
expect(email.subject).to include(issue.title)
end
- context 'when resource state events are disabled' do
- before do
- stub_feature_flags(track_resource_state_change_events: false)
- end
-
- it 'creates system note about the issue being closed' do
- close_issue
-
- note = issue.notes.last
- expect(note.note).to include "closed"
- end
- end
-
- context 'when resource state events are enabled' do
- it 'creates resource state event about the issue being closed' do
- close_issue
+ it 'creates resource state event about the issue being closed' do
+ close_issue
- event = issue.resource_state_events.last
- expect(event.state).to eq('closed')
- end
+ event = issue.resource_state_events.last
+ expect(event.state).to eq('closed')
end
it 'marks todos as done' do
diff --git a/spec/services/issues/move_service_spec.rb b/spec/services/issues/move_service_spec.rb
index c2989dc86cf..ae1454ce9bb 100644
--- a/spec/services/issues/move_service_spec.rb
+++ b/spec/services/issues/move_service_spec.rb
@@ -3,6 +3,8 @@
require 'spec_helper'
RSpec.describe Issues::MoveService do
+ include DesignManagementTestHelpers
+
let_it_be(:user) { create(:user) }
let_it_be(:author) { create(:user) }
let_it_be(:title) { 'Some issue' }
@@ -201,6 +203,47 @@ RSpec.describe Issues::MoveService do
expect(copied_notes.order('id ASC').pluck(:note)).to eq(notes.map(&:note))
end
end
+
+ context 'issue with a design', :clean_gitlab_redis_shared_state do
+ let_it_be(:new_project) { create(:project) }
+ let!(:design) { create(:design, :with_lfs_file, issue: old_issue) }
+ let!(:note) { create(:diff_note_on_design, noteable: design, issue: old_issue, project: old_issue.project) }
+ let(:subject) { move_service.execute(old_issue, new_project) }
+
+ before do
+ enable_design_management
+ end
+
+ it 'calls CopyDesignCollection::QueueService' do
+ expect(DesignManagement::CopyDesignCollection::QueueService).to receive(:new)
+ .with(user, old_issue, kind_of(Issue))
+ .and_call_original
+
+ subject
+ end
+
+ it 'logs if QueueService returns an error', :aggregate_failures do
+ error_message = 'error'
+
+ expect_next_instance_of(DesignManagement::CopyDesignCollection::QueueService) do |service|
+ expect(service).to receive(:execute).and_return(
+ ServiceResponse.error(message: error_message)
+ )
+ end
+ expect(Gitlab::AppLogger).to receive(:error).with(error_message)
+
+ subject
+ end
+
+ # Perform a small integration test to ensure the services and worker
+ # can correctly create designs.
+ it 'copies the design and its notes', :sidekiq_inline, :aggregate_failures do
+ new_issue = subject
+
+ expect(new_issue.designs.size).to eq(1)
+ expect(new_issue.designs.first.notes.size).to eq(1)
+ end
+ end
end
describe 'move permissions' do
diff --git a/spec/services/issues/update_service_spec.rb b/spec/services/issues/update_service_spec.rb
index b3e8fba4e9a..cfda27795c7 100644
--- a/spec/services/issues/update_service_spec.rb
+++ b/spec/services/issues/update_service_spec.rb
@@ -650,7 +650,7 @@ RSpec.describe Issues::UpdateService, :mailer do
context 'when the labels change' do
before do
- Timecop.freeze(1.minute.from_now) do
+ travel_to(1.minute.from_now) do
update_issue(label_ids: [label.id])
end
end
diff --git a/spec/services/jira/requests/projects/list_service_spec.rb b/spec/services/jira/requests/projects/list_service_spec.rb
index 415dd42c795..f7bcfa997df 100644
--- a/spec/services/jira/requests/projects/list_service_spec.rb
+++ b/spec/services/jira/requests/projects/list_service_spec.rb
@@ -45,6 +45,10 @@ RSpec.describe Jira::Requests::Projects::ListService do
end
it 'returns an error response' do
+ expect(Gitlab::ProjectServiceLogger).to receive(:error).with(
+ hash_including(
+ error: hash_including(:exception_class, :exception_message, :exception_backtrace)))
+ .and_call_original
expect(subject.error?).to be_truthy
expect(subject.message).to eq('Jira request error: Timeout::Error')
end
diff --git a/spec/services/keys/last_used_service_spec.rb b/spec/services/keys/last_used_service_spec.rb
index 82b6b05975b..a2cd5ffdd38 100644
--- a/spec/services/keys/last_used_service_spec.rb
+++ b/spec/services/keys/last_used_service_spec.rb
@@ -8,7 +8,7 @@ RSpec.describe Keys::LastUsedService do
key = create(:key, last_used_at: 1.year.ago)
time = Time.zone.now
- Timecop.freeze(time) { described_class.new(key).execute }
+ travel_to(time) { described_class.new(key).execute }
expect(key.reload.last_used_at).to be_like_time(time)
end
diff --git a/spec/services/lfs/push_service_spec.rb b/spec/services/lfs/push_service_spec.rb
index 8e5b98fdc9c..f67284ff48d 100644
--- a/spec/services/lfs/push_service_spec.rb
+++ b/spec/services/lfs/push_service_spec.rb
@@ -19,7 +19,7 @@ RSpec.describe Lfs::PushService do
stub_lfs_batch(lfs_object)
expect(lfs_client)
- .to receive(:upload)
+ .to receive(:upload!)
.with(lfs_object, upload_action_spec(lfs_object), authenticated: true)
expect(service.execute).to eq(status: :success)
@@ -28,7 +28,7 @@ RSpec.describe Lfs::PushService do
it 'does nothing if there are no LFS objects' do
lfs_object.destroy!
- expect(lfs_client).not_to receive(:upload)
+ expect(lfs_client).not_to receive(:upload!)
expect(service.execute).to eq(status: :success)
end
@@ -36,20 +36,39 @@ RSpec.describe Lfs::PushService do
it 'does not upload the object when upload is not requested' do
stub_lfs_batch(lfs_object, upload: false)
- expect(lfs_client).not_to receive(:upload)
+ expect(lfs_client).not_to receive(:upload!)
expect(service.execute).to eq(status: :success)
end
+ it 'verifies the upload if requested' do
+ stub_lfs_batch(lfs_object, verify: true)
+
+ expect(lfs_client).to receive(:upload!)
+ expect(lfs_client)
+ .to receive(:verify!)
+ .with(lfs_object, verify_action_spec(lfs_object), authenticated: true)
+
+ expect(service.execute).to eq(status: :success)
+ end
+
+ it 'skips verification if requested but upload fails' do
+ stub_lfs_batch(lfs_object, verify: true)
+
+ expect(lfs_client).to receive(:upload!) { raise 'failed' }
+ expect(lfs_client).not_to receive(:verify!)
+ expect(service.execute).to eq(status: :error, message: 'failed')
+ end
+
it 'returns a failure when submitting a batch fails' do
- expect(lfs_client).to receive(:batch) { raise 'failed' }
+ expect(lfs_client).to receive(:batch!) { raise 'failed' }
expect(service.execute).to eq(status: :error, message: 'failed')
end
it 'returns a failure when submitting an upload fails' do
stub_lfs_batch(lfs_object)
- expect(lfs_client).to receive(:upload) { raise 'failed' }
+ expect(lfs_client).to receive(:upload!) { raise 'failed' }
expect(service.execute).to eq(status: :error, message: 'failed')
end
@@ -71,23 +90,28 @@ RSpec.describe Lfs::PushService do
create(:lfs_objects_project, project: project, repository_type: type).lfs_object
end
- def stub_lfs_batch(*objects, upload: true)
+ def stub_lfs_batch(*objects, upload: true, verify: false)
expect(lfs_client)
- .to receive(:batch).with('upload', containing_exactly(*objects))
- .and_return('transfer' => 'basic', 'objects' => objects.map { |o| object_spec(o, upload: upload) })
+ .to receive(:batch!).with('upload', containing_exactly(*objects))
+ .and_return('transfer' => 'basic', 'objects' => objects.map { |o| object_spec(o, upload: upload, verify: verify) })
end
- def batch_spec(*objects, upload: true)
+ def batch_spec(*objects, upload: true, verify: false)
{ 'transfer' => 'basic', 'objects' => objects.map {|o| object_spec(o, upload: upload) } }
end
- def object_spec(object, upload: true)
- { 'oid' => object.oid, 'size' => object.size, 'authenticated' => true }.tap do |spec|
- spec['actions'] = { 'upload' => upload_action_spec(object) } if upload
+ def object_spec(object, upload: true, verify: false)
+ { 'oid' => object.oid, 'size' => object.size, 'authenticated' => true, 'actions' => {} }.tap do |spec|
+ spec['actions']['upload'] = upload_action_spec(object) if upload
+ spec['actions']['verify'] = verify_action_spec(object) if verify
end
end
def upload_action_spec(object)
{ 'href' => "https://example.com/#{object.oid}/#{object.size}", 'header' => { 'Key' => 'value' } }
end
+
+ def verify_action_spec(object)
+ { 'href' => "https://example.com/#{object.oid}/#{object.size}/verify", 'header' => { 'Key' => 'value' } }
+ end
end
diff --git a/spec/services/members/destroy_service_spec.rb b/spec/services/members/destroy_service_spec.rb
index 3b3f2f3b95a..4f731ad5852 100644
--- a/spec/services/members/destroy_service_spec.rb
+++ b/spec/services/members/destroy_service_spec.rb
@@ -29,15 +29,15 @@ RSpec.describe Members::DestroyService do
end
it 'destroys the member' do
- expect { described_class.new(current_user).execute(member, opts) }.to change { member.source.members_and_requesters.count }.by(-1)
+ expect { described_class.new(current_user).execute(member, **opts) }.to change { member.source.members_and_requesters.count }.by(-1)
end
it 'destroys member notification_settings' do
if member_user.notification_settings.any?
- expect { described_class.new(current_user).execute(member, opts) }
+ expect { described_class.new(current_user).execute(member, **opts) }
.to change { member_user.notification_settings.count }.by(-1)
else
- expect { described_class.new(current_user).execute(member, opts) }
+ expect { described_class.new(current_user).execute(member, **opts) }
.not_to change { member_user.notification_settings.count }
end
end
@@ -63,7 +63,7 @@ RSpec.describe Members::DestroyService do
expect(service).to receive(:enqueue_unassign_issuables).with(member)
end
- service.execute(member, opts)
+ service.execute(member, **opts)
expect(member_user.assigned_open_merge_requests_count).to be(0)
expect(member_user.assigned_open_issues_count).to be(0)
@@ -83,14 +83,14 @@ RSpec.describe Members::DestroyService do
it 'calls Member#after_decline_request' do
expect_any_instance_of(NotificationService).to receive(:decline_access_request).with(member)
- described_class.new(current_user).execute(member, opts)
+ described_class.new(current_user).execute(member, **opts)
end
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(member_user).execute(member, **opts)
end
end
end
@@ -280,7 +280,6 @@ RSpec.describe Members::DestroyService do
context 'subresources' do
let(:user) { create(:user) }
let(:member_user) { create(:user) }
- let(:opts) { {} }
let(:group) { create(:group, :public) }
let(:subgroup) { create(:group, parent: group) }
@@ -303,7 +302,7 @@ RSpec.describe Members::DestroyService do
group_member = create(:group_member, :developer, group: group, user: member_user)
- described_class.new(user).execute(group_member, opts)
+ described_class.new(user).execute(group_member)
end
it 'removes the project membership' do
@@ -350,7 +349,6 @@ RSpec.describe Members::DestroyService do
context 'deletion of invitations created by deleted project member' do
let(:user) { project.owner }
let(:member_user) { create(:user) }
- let(:opts) { {} }
let(:project) { create(:project) }
@@ -359,7 +357,7 @@ RSpec.describe Members::DestroyService do
project_member = create(:project_member, :maintainer, user: member_user, project: project)
- described_class.new(user).execute(project_member, opts)
+ described_class.new(user).execute(project_member)
end
it 'removes project members invited by deleted user' do
diff --git a/spec/services/members/invitation_reminder_email_service_spec.rb b/spec/services/members/invitation_reminder_email_service_spec.rb
new file mode 100644
index 00000000000..88280869476
--- /dev/null
+++ b/spec/services/members/invitation_reminder_email_service_spec.rb
@@ -0,0 +1,78 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Members::InvitationReminderEmailService do
+ describe 'sending invitation reminders' do
+ subject { described_class.new(invitation).execute }
+
+ let_it_be(:frozen_time) { Date.today.beginning_of_day }
+ let_it_be(:invitation) { build(:group_member, :invited, created_at: frozen_time) }
+
+ context 'when the experiment is disabled' do
+ before do
+ allow(Gitlab::Experimentation).to receive(:enabled_for_attribute?).and_return(false)
+ invitation.expires_at = frozen_time + 2.days
+ end
+
+ it 'does not send an invitation' do
+ travel_to(frozen_time + 1.day) do
+ expect(invitation).not_to receive(:send_invitation_reminder)
+
+ subject
+ end
+ end
+ end
+
+ context 'when the experiment is enabled' do
+ before do
+ allow(Gitlab::Experimentation).to receive(:enabled_for_attribute?).and_return(true)
+ invitation.expires_at = frozen_time + expires_at_days.days if expires_at_days
+ end
+
+ using RSpec::Parameterized::TableSyntax
+
+ where(:expires_at_days, :send_reminder_at_days) do
+ 0 | []
+ 1 | []
+ 2 | [1]
+ 3 | [1, 2]
+ 4 | [1, 2, 3]
+ 5 | [1, 2, 4]
+ 6 | [1, 3, 5]
+ 7 | [1, 3, 5]
+ 8 | [2, 3, 6]
+ 9 | [2, 4, 7]
+ 10 | [2, 4, 8]
+ 11 | [2, 4, 8]
+ 12 | [2, 5, 9]
+ 13 | [2, 5, 10]
+ 14 | [2, 5, 10]
+ 15 | [2, 5, 10]
+ nil | [2, 5, 10]
+ end
+
+ with_them do
+ # Create an invitation today with an expiration date from 0 to 10 days in the future or without an expiration date
+ # We chose 10 days here, because we fetch invitations that were created at most 10 days ago.
+ (0..10).each do |day|
+ it 'sends an invitation reminder only on the expected days' do
+ next if day > (expires_at_days || 10) # We don't need to test after the invitation has already expired
+
+ # We are traveling in a loop from today to 10 days from now
+ travel_to(frozen_time + day.days) do
+ # Given an expiration date and the number of days after the creation of the invitation based on the current day in the loop, a reminder may be sent
+ if (reminder_index = send_reminder_at_days.index(day))
+ expect(invitation).to receive(:send_invitation_reminder).with(reminder_index)
+ else
+ expect(invitation).not_to receive(:send_invitation_reminder)
+ end
+
+ subject
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/spec/services/merge_requests/cleanup_refs_service_spec.rb b/spec/services/merge_requests/cleanup_refs_service_spec.rb
index b38ccee4aa0..a051b3c9355 100644
--- a/spec/services/merge_requests/cleanup_refs_service_spec.rb
+++ b/spec/services/merge_requests/cleanup_refs_service_spec.rb
@@ -35,6 +35,17 @@ RSpec.describe MergeRequests::CleanupRefsService do
end
end
+ context 'when merge request has no head ref' do
+ before do
+ # Simulate a merge request with no head ref
+ merge_request.project.repository.delete_refs(merge_request.ref_path)
+ end
+
+ it 'does not fail' do
+ expect(result[:status]).to eq(:success)
+ end
+ end
+
context 'when merge request has merge ref' do
before do
MergeRequests::MergeToRefService
diff --git a/spec/services/merge_requests/close_service_spec.rb b/spec/services/merge_requests/close_service_spec.rb
index e7ac286f48b..67fb4eaade5 100644
--- a/spec/services/merge_requests/close_service_spec.rb
+++ b/spec/services/merge_requests/close_service_spec.rb
@@ -19,54 +19,45 @@ RSpec.describe MergeRequests::CloseService do
describe '#execute' do
it_behaves_like 'cache counters invalidator'
- [true, false].each do |state_tracking_enabled|
- context "valid params with state_tracking #{state_tracking_enabled ? 'enabled' : 'disabled'}" do
- let(:service) { described_class.new(project, user, {}) }
+ context 'valid params' do
+ let(:service) { described_class.new(project, user, {}) }
- before do
- stub_feature_flags(track_resource_state_change_events: state_tracking_enabled)
-
- allow(service).to receive(:execute_hooks)
+ before do
+ allow(service).to receive(:execute_hooks)
- perform_enqueued_jobs do
- @merge_request = service.execute(merge_request)
- end
+ perform_enqueued_jobs do
+ @merge_request = service.execute(merge_request)
end
+ end
- it { expect(@merge_request).to be_valid }
- it { expect(@merge_request).to be_closed }
+ it { expect(@merge_request).to be_valid }
+ it { expect(@merge_request).to be_closed }
- it 'executes hooks with close action' do
- expect(service).to have_received(:execute_hooks)
- .with(@merge_request, 'close')
- end
+ it 'executes hooks with close action' do
+ expect(service).to have_received(:execute_hooks)
+ .with(@merge_request, 'close')
+ end
- it 'sends email to user2 about assign of new merge_request', :sidekiq_might_not_need_inline do
- email = ActionMailer::Base.deliveries.last
- expect(email.to.first).to eq(user2.email)
- expect(email.subject).to include(merge_request.title)
- end
+ it 'sends email to user2 about assign of new merge_request', :sidekiq_might_not_need_inline do
+ email = ActionMailer::Base.deliveries.last
+ expect(email.to.first).to eq(user2.email)
+ expect(email.subject).to include(merge_request.title)
+ end
- it 'creates system note about merge_request reassign' do
- if state_tracking_enabled
- event = @merge_request.resource_state_events.last
- expect(event.state).to eq('closed')
- else
- note = @merge_request.notes.last
- expect(note.note).to include 'closed'
- end
- end
+ it 'creates a resource event' do
+ event = @merge_request.resource_state_events.last
+ expect(event.state).to eq('closed')
+ end
- it 'marks todos as done' do
- expect(todo.reload).to be_done
- end
+ it 'marks todos as done' do
+ expect(todo.reload).to be_done
+ end
- context 'when auto merge is enabled' do
- let(:merge_request) { create(:merge_request, :merge_when_pipeline_succeeds) }
+ context 'when auto merge is enabled' do
+ let(:merge_request) { create(:merge_request, :merge_when_pipeline_succeeds) }
- it 'cancels the auto merge' do
- expect(@merge_request).not_to be_auto_merge_enabled
- end
+ it 'cancels the auto merge' do
+ expect(@merge_request).not_to be_auto_merge_enabled
end
end
end
diff --git a/spec/services/merge_requests/create_from_issue_service_spec.rb b/spec/services/merge_requests/create_from_issue_service_spec.rb
index fa70ad8c559..86e49fe601c 100644
--- a/spec/services/merge_requests/create_from_issue_service_spec.rb
+++ b/spec/services/merge_requests/create_from_issue_service_spec.rb
@@ -154,7 +154,7 @@ RSpec.describe MergeRequests::CreateFromIssueService do
result = service.execute
- expect(result[:merge_request].label_ids).to eq(label_ids)
+ expect(result[:merge_request].label_ids).to match_array(label_ids)
end
it "inherits milestones" do
diff --git a/spec/services/merge_requests/export_csv_service_spec.rb b/spec/services/merge_requests/export_csv_service_spec.rb
new file mode 100644
index 00000000000..ecb17b3fe77
--- /dev/null
+++ b/spec/services/merge_requests/export_csv_service_spec.rb
@@ -0,0 +1,115 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe MergeRequests::ExportCsvService do
+ let_it_be(:merge_request) { create(:merge_request) }
+ let(:csv) { CSV.parse(subject.csv_data, headers: true).first }
+
+ subject { described_class.new(MergeRequest.where(id: merge_request.id), merge_request.project) }
+
+ describe 'csv_data' do
+ it 'contains the correct information', :aggregate_failures do
+ expect(csv['MR IID']).to eq(merge_request.iid.to_s)
+ expect(csv['Title']).to eq(merge_request.title)
+ expect(csv['State']).to eq(merge_request.state)
+ expect(csv['Description']).to eq(merge_request.description)
+ expect(csv['Source Branch']).to eq(merge_request.source_branch)
+ expect(csv['Target Branch']).to eq(merge_request.target_branch)
+ expect(csv['Source Project ID']).to eq(merge_request.source_project_id.to_s)
+ expect(csv['Target Project ID']).to eq(merge_request.target_project_id.to_s)
+ expect(csv['Author']).to eq(merge_request.author.name)
+ expect(csv['Author Username']).to eq(merge_request.author.username)
+ end
+
+ describe 'assignees' do
+ context 'when assigned' do
+ let_it_be(:merge_request) { create(:merge_request, assignees: create_list(:user, 2)) }
+
+ it 'contains the names of assignees' do
+ expect(csv['Assignees']).to eq(merge_request.assignees.map(&:name).join(', '))
+ end
+
+ it 'contains the usernames of assignees' do
+ expect(csv['Assignee Usernames']).to eq(merge_request.assignees.map(&:username).join(', '))
+ end
+ end
+
+ context 'when not assigned' do
+ it 'returns empty strings' do
+ expect(csv['Assignees']).to eq('')
+ expect(csv['Assignee Usernames']).to eq('')
+ end
+ end
+ end
+
+ describe 'approvers' do
+ context 'when approved' do
+ let_it_be(:merge_request) { create(:merge_request) }
+ let(:approvers) { create_list(:user, 2) }
+
+ before do
+ merge_request.approved_by_users = approvers
+ end
+
+ it 'contains the names of approvers separated by a comma' do
+ expect(csv['Approvers'].split(', ')).to contain_exactly(approvers[0].name, approvers[1].name)
+ end
+
+ it 'contains the usernames of approvers separated by a comma' do
+ expect(csv['Approver Usernames'].split(', ')).to contain_exactly(approvers[0].username, approvers[1].username)
+ end
+ end
+
+ context 'when not approved' do
+ it 'returns empty strings' do
+ expect(csv['Approvers']).to eq('')
+ expect(csv['Approver Usernames']).to eq('')
+ end
+ end
+ end
+
+ describe 'merged user' do
+ context 'MR is merged' do
+ let_it_be(:merge_request) { create(:merge_request, :merged, :with_merged_metrics) }
+
+ it 'is merged' do
+ expect(csv['State']).to eq('merged')
+ end
+
+ it 'has a merged user' do
+ expect(csv['Merged User']).to eq(merge_request.metrics.merged_by.name)
+ expect(csv['Merged Username']).to eq(merge_request.metrics.merged_by.username)
+ end
+ end
+
+ context 'MR is not merged' do
+ it 'returns empty strings' do
+ expect(csv['Merged User']).to eq('')
+ expect(csv['Merged Username']).to eq('')
+ end
+ end
+ end
+
+ describe 'milestone' do
+ context 'milestone is assigned' do
+ let_it_be(:merge_request) { create(:merge_request) }
+ let_it_be(:milestone) { create(:milestone, :active, project: merge_request.project) }
+
+ before do
+ merge_request.update!(milestone_id: milestone.id)
+ end
+
+ it 'contains the milestone ID' do
+ expect(csv['Milestone ID']).to eq(merge_request.milestone.id.to_s)
+ end
+ end
+
+ context 'no milestone is assigned' do
+ it 'returns an empty string' do
+ expect(csv['Milestone ID']).to eq('')
+ end
+ end
+ end
+ end
+end
diff --git a/spec/services/merge_requests/ff_merge_service_spec.rb b/spec/services/merge_requests/ff_merge_service_spec.rb
index 5c44af87470..aec5a3b3fa3 100644
--- a/spec/services/merge_requests/ff_merge_service_spec.rb
+++ b/spec/services/merge_requests/ff_merge_service_spec.rb
@@ -22,74 +22,72 @@ RSpec.describe MergeRequests::FfMergeService do
end
describe '#execute' do
- [true, false].each do |state_tracking_enabled|
- context "valid params with state_tracking #{state_tracking_enabled ? 'enabled' : 'disabled'}" do
- let(:service) { described_class.new(project, user, valid_merge_params) }
-
- def execute_ff_merge
- perform_enqueued_jobs do
- service.execute(merge_request)
- end
+ context 'valid params' do
+ let(:service) { described_class.new(project, user, valid_merge_params) }
+
+ def execute_ff_merge
+ perform_enqueued_jobs do
+ service.execute(merge_request)
end
+ end
- before do
- stub_feature_flags(track_resource_state_change_events: state_tracking_enabled)
+ before do
+ allow(service).to receive(:execute_hooks)
+ end
- allow(service).to receive(:execute_hooks)
- end
+ it "does not create merge commit" do
+ execute_ff_merge
- it "does not create merge commit" do
- execute_ff_merge
+ source_branch_sha = merge_request.source_project.repository.commit(merge_request.source_branch).sha
+ target_branch_sha = merge_request.target_project.repository.commit(merge_request.target_branch).sha
- source_branch_sha = merge_request.source_project.repository.commit(merge_request.source_branch).sha
- target_branch_sha = merge_request.target_project.repository.commit(merge_request.target_branch).sha
+ expect(source_branch_sha).to eq(target_branch_sha)
+ end
- expect(source_branch_sha).to eq(target_branch_sha)
- end
+ it 'keeps the merge request valid' do
+ expect { execute_ff_merge }
+ .not_to change { merge_request.valid? }
+ end
- it 'keeps the merge request valid' do
- expect { execute_ff_merge }
- .not_to change { merge_request.valid? }
- end
+ it 'updates the merge request to merged' do
+ expect { execute_ff_merge }
+ .to change { merge_request.merged? }
+ .from(false)
+ .to(true)
+ end
- it 'updates the merge request to merged' do
- expect { execute_ff_merge }
- .to change { merge_request.merged? }
- .from(false)
- .to(true)
- end
+ it 'sends email to user2 about merge of new merge_request' do
+ execute_ff_merge
- it 'sends email to user2 about merge of new merge_request' do
- execute_ff_merge
+ email = ActionMailer::Base.deliveries.last
+ expect(email.to.first).to eq(user2.email)
+ expect(email.subject).to include(merge_request.title)
+ end
- email = ActionMailer::Base.deliveries.last
- expect(email.to.first).to eq(user2.email)
- expect(email.subject).to include(merge_request.title)
- end
+ it 'creates resource event about merge_request merge' do
+ execute_ff_merge
- it 'creates system note about merge_request merge' do
- execute_ff_merge
+ event = merge_request.resource_state_events.last
+ expect(event.state).to eq('merged')
+ end
- if state_tracking_enabled
- event = merge_request.resource_state_events.last
- expect(event.state).to eq('merged')
- else
- note = merge_request.notes.last
- expect(note.note).to include 'merged'
- end
- end
+ it 'does not update squash_commit_sha if it is not a squash' do
+ expect(merge_request).to receive(:update_and_mark_in_progress_merge_commit_sha).twice.and_call_original
- it 'does not update squash_commit_sha if it is not a squash' do
- expect { execute_ff_merge }.not_to change { merge_request.squash_commit_sha }
- end
+ expect { execute_ff_merge }.not_to change { merge_request.squash_commit_sha }
+ expect(merge_request.in_progress_merge_commit_sha).to be_nil
+ end
- it 'updates squash_commit_sha if it is a squash' do
- merge_request.update!(squash: true)
+ it 'updates squash_commit_sha if it is a squash' do
+ expect(merge_request).to receive(:update_and_mark_in_progress_merge_commit_sha).twice.and_call_original
- expect { execute_ff_merge }
- .to change { merge_request.squash_commit_sha }
- .from(nil)
- end
+ merge_request.update!(squash: true)
+
+ expect { execute_ff_merge }
+ .to change { merge_request.squash_commit_sha }
+ .from(nil)
+
+ expect(merge_request.in_progress_merge_commit_sha).to be_nil
end
end
diff --git a/spec/services/merge_requests/merge_service_spec.rb b/spec/services/merge_requests/merge_service_spec.rb
index 8328f461029..d0e3102f157 100644
--- a/spec/services/merge_requests/merge_service_spec.rb
+++ b/spec/services/merge_requests/merge_service_spec.rb
@@ -20,12 +20,9 @@ RSpec.describe MergeRequests::MergeService do
end
context 'valid params' do
- let(:state_tracking) { true }
-
before do
- stub_feature_flags(track_resource_state_change_events: state_tracking)
-
allow(service).to receive(:execute_hooks)
+ expect(merge_request).to receive(:update_and_mark_in_progress_merge_commit_sha).twice.and_call_original
perform_enqueued_jobs do
service.execute(merge_request)
@@ -47,20 +44,9 @@ RSpec.describe MergeRequests::MergeService do
end
context 'note creation' do
- context 'when resource state event tracking is disabled' do
- let(:state_tracking) { false }
-
- it 'creates system note about merge_request merge' do
- note = merge_request.notes.last
- expect(note.note).to include 'merged'
- end
- end
-
- context 'when resource state event tracking is enabled' do
- it 'creates resource state event about merge_request merge' do
- event = merge_request.resource_state_events.last
- expect(event.state).to eq('merged')
- end
+ it 'creates resource state event about merge_request merge' do
+ event = merge_request.resource_state_events.last
+ expect(event.state).to eq('merged')
end
end
diff --git a/spec/services/merge_requests/merge_to_ref_service_spec.rb b/spec/services/merge_requests/merge_to_ref_service_spec.rb
index b482e8d6724..14ef5b0b772 100644
--- a/spec/services/merge_requests/merge_to_ref_service_spec.rb
+++ b/spec/services/merge_requests/merge_to_ref_service_spec.rb
@@ -252,5 +252,16 @@ RSpec.describe MergeRequests::MergeToRefService do
end
end
end
+
+ context 'allow conflicts to be merged in diff' do
+ let(:params) { { allow_conflicts: true } }
+
+ it 'calls merge_to_ref with allow_conflicts param' do
+ expect(project.repository).to receive(:merge_to_ref)
+ .with(anything, anything, anything, anything, anything, anything, true)
+
+ service.execute(merge_request)
+ end
+ end
end
end
diff --git a/spec/services/merge_requests/mergeability_check_service_spec.rb b/spec/services/merge_requests/mergeability_check_service_spec.rb
index 543da46f883..725fc16fa7c 100644
--- a/spec/services/merge_requests/mergeability_check_service_spec.rb
+++ b/spec/services/merge_requests/mergeability_check_service_spec.rb
@@ -41,16 +41,6 @@ RSpec.describe MergeRequests::MergeabilityCheckService, :clean_gitlab_redis_shar
subject
end
- context 'when merge_ref_head_comments is disabled' do
- it 'does not update diff discussion positions' do
- stub_feature_flags(merge_ref_head_comments: false)
-
- expect(Discussions::CaptureDiffNotePositionsService).not_to receive(:new)
-
- subject
- end
- end
-
it 'updates the merge ref' do
expect { subject }.to change(merge_request, :merge_ref_head).from(nil)
end
@@ -221,11 +211,18 @@ RSpec.describe MergeRequests::MergeabilityCheckService, :clean_gitlab_redis_shar
target_branch: 'conflict-start')
end
- it_behaves_like 'unmergeable merge request'
+ it 'does not change the merge ref HEAD' do
+ expect(merge_request.merge_ref_head).to be_nil
- it 'returns ServiceResponse.error' do
+ 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
+ expect(merge_request.merge_status).to eq('cannot_be_merged')
expect(result).to be_a(ServiceResponse)
expect(result.error?).to be(true)
expect(result.message).to eq('Merge request is not mergeable')
@@ -383,5 +380,27 @@ 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, merge_request.author, { 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, merge_request.author, { allow_conflicts: false }).and_call_original
+
+ subject
+ end
+ end
+ end
end
end
diff --git a/spec/services/merge_requests/refresh_service_spec.rb b/spec/services/merge_requests/refresh_service_spec.rb
index cace1e0bf09..d603cbb16aa 100644
--- a/spec/services/merge_requests/refresh_service_spec.rb
+++ b/spec/services/merge_requests/refresh_service_spec.rb
@@ -367,76 +367,58 @@ RSpec.describe MergeRequests::RefreshService do
end
end
- [true, false].each do |state_tracking_enabled|
- context "push to origin repo target branch with state tracking #{state_tracking_enabled ? 'enabled' : 'disabled'}", :sidekiq_might_not_need_inline do
+ context 'push to origin repo target branch', :sidekiq_might_not_need_inline do
+ context 'when all MRs to the target branch had diffs' do
before do
- stub_feature_flags(track_resource_state_change_events: state_tracking_enabled)
+ service.new(@project, @user).execute(@oldrev, @newrev, 'refs/heads/feature')
+ reload_mrs
end
- context 'when all MRs to the target branch had diffs' do
- before do
- service.new(@project, @user).execute(@oldrev, @newrev, 'refs/heads/feature')
- reload_mrs
- end
+ it 'updates the merge state' do
+ expect(@merge_request).to be_merged
+ expect(@fork_merge_request).to be_merged
+ expect(@build_failed_todo).to be_done
+ expect(@fork_build_failed_todo).to be_done
- it 'updates the merge state' do
- expect(@merge_request).to be_merged
- expect(@fork_merge_request).to be_merged
- expect(@build_failed_todo).to be_done
- expect(@fork_build_failed_todo).to be_done
-
- if state_tracking_enabled
- expect(@merge_request.resource_state_events.last.state).to eq('merged')
- expect(@fork_merge_request.resource_state_events.last.state).to eq('merged')
- else
- expect(@merge_request.notes.last.note).to include('merged')
- expect(@fork_merge_request.notes.last.note).to include('merged')
- end
- end
+ expect(@merge_request.resource_state_events.last.state).to eq('merged')
+ expect(@fork_merge_request.resource_state_events.last.state).to eq('merged')
end
+ end
- context 'when an MR to be closed was empty already' do
- let!(:empty_fork_merge_request) do
- create(:merge_request,
- source_project: @fork_project,
- source_branch: 'master',
- target_branch: 'master',
- target_project: @project)
- end
+ context 'when an MR to be closed was empty already' do
+ let!(:empty_fork_merge_request) do
+ create(:merge_request,
+ source_project: @fork_project,
+ source_branch: 'master',
+ target_branch: 'master',
+ target_project: @project)
+ end
- before do
- # This spec already has a fake push, so pretend that we were targeting
- # feature all along.
- empty_fork_merge_request.update_columns(target_branch: 'feature')
+ before do
+ # This spec already has a fake push, so pretend that we were targeting
+ # feature all along.
+ empty_fork_merge_request.update_columns(target_branch: 'feature')
- service.new(@project, @user).execute(@oldrev, @newrev, 'refs/heads/feature')
- reload_mrs
- empty_fork_merge_request.reload
- end
+ service.new(@project, @user).execute(@oldrev, @newrev, 'refs/heads/feature')
+ reload_mrs
+ empty_fork_merge_request.reload
+ end
- it 'only updates the non-empty MRs' do
- expect(@merge_request).to be_merged
- expect(@fork_merge_request).to be_merged
-
- expect(empty_fork_merge_request).to be_open
- expect(empty_fork_merge_request.merge_request_diff.state).to eq('empty')
- expect(empty_fork_merge_request.notes).to be_empty
-
- if state_tracking_enabled
- expect(@merge_request.resource_state_events.last.state).to eq('merged')
- expect(@fork_merge_request.resource_state_events.last.state).to eq('merged')
- else
- expect(@merge_request.notes.last.note).to include('merged')
- expect(@fork_merge_request.notes.last.note).to include('merged')
- end
- end
+ it 'only updates the non-empty MRs' do
+ expect(@merge_request).to be_merged
+ expect(@fork_merge_request).to be_merged
+
+ expect(empty_fork_merge_request).to be_open
+ expect(empty_fork_merge_request.merge_request_diff.state).to eq('empty')
+ expect(empty_fork_merge_request.notes).to be_empty
+
+ expect(@merge_request.resource_state_events.last.state).to eq('merged')
+ expect(@fork_merge_request.resource_state_events.last.state).to eq('merged')
end
end
- context "manual merge of source branch #{state_tracking_enabled ? 'enabled' : 'disabled'}", :sidekiq_might_not_need_inline do
+ context 'manual merge of source branch', :sidekiq_might_not_need_inline do
before do
- stub_feature_flags(track_resource_state_change_events: state_tracking_enabled)
-
# Merge master -> feature branch
@project.repository.merge(@user, @merge_request.diff_head_sha, @merge_request, 'Test message')
commit = @project.repository.commit('feature')
@@ -445,13 +427,8 @@ RSpec.describe MergeRequests::RefreshService do
end
it 'updates the merge state' do
- if state_tracking_enabled
- expect(@merge_request.resource_state_events.last.state).to eq('merged')
- expect(@fork_merge_request.resource_state_events.last.state).to eq('merged')
- else
- expect(@merge_request.notes.last.note).to include('merged')
- expect(@fork_merge_request.notes.last.note).to include('merged')
- end
+ expect(@merge_request.resource_state_events.last.state).to eq('merged')
+ expect(@fork_merge_request.resource_state_events.last.state).to eq('merged')
expect(@merge_request).to be_merged
expect(@merge_request.diffs.size).to be > 0
@@ -616,29 +593,21 @@ RSpec.describe MergeRequests::RefreshService do
end
end
- [true, false].each do |state_tracking_enabled|
- context "push to origin repo target branch after fork project was removed #{state_tracking_enabled ? 'enabled' : 'disabled'}" do
- before do
- stub_feature_flags(track_resource_state_change_events: state_tracking_enabled)
-
- @fork_project.destroy!
- service.new(@project, @user).execute(@oldrev, @newrev, 'refs/heads/feature')
- reload_mrs
- end
+ context 'push to origin repo target branch after fork project was removed' do
+ before do
+ @fork_project.destroy!
+ service.new(@project, @user).execute(@oldrev, @newrev, 'refs/heads/feature')
+ reload_mrs
+ end
- it 'updates the merge request state' do
- if state_tracking_enabled
- expect(@merge_request.resource_state_events.last.state).to eq('merged')
- else
- expect(@merge_request.notes.last.note).to include('merged')
- end
+ it 'updates the merge request state' do
+ expect(@merge_request.resource_state_events.last.state).to eq('merged')
- expect(@merge_request).to be_merged
- expect(@fork_merge_request).to be_open
- expect(@fork_merge_request.notes).to be_empty
- expect(@build_failed_todo).to be_done
- expect(@fork_build_failed_todo).to be_done
- end
+ expect(@merge_request).to be_merged
+ expect(@fork_merge_request).to be_open
+ expect(@fork_merge_request.notes).to be_empty
+ expect(@build_failed_todo).to be_done
+ expect(@fork_build_failed_todo).to be_done
end
end
@@ -827,10 +796,6 @@ RSpec.describe MergeRequests::RefreshService do
subject { service.execute(oldrev, newrev, 'refs/heads/merge-commit-analyze-before') }
context 'feature enabled' do
- before do
- stub_feature_flags(branch_push_merge_commit_analyze: true)
- end
-
it "updates merge requests' merge_commits" do
expect(Gitlab::BranchPushMergeCommitAnalyzer).to receive(:new).and_wrap_original do |original_method, commits|
expect(commits.map(&:id)).to eq(%w{646ece5cfed840eca0a4feb21bcd6a81bb19bda3 29284d9bcc350bcae005872d0be6edd016e2efb5 5f82584f0a907f3b30cfce5bb8df371454a90051 8a994512e8c8f0dfcf22bb16df6e876be7a61036 689600b91aabec706e657e38ea706ece1ee8268f db46a1c5a5e474aa169b6cdb7a522d891bc4c5f9})
@@ -847,24 +812,6 @@ RSpec.describe MergeRequests::RefreshService do
expect(merge_request_side_branch.merge_commit.id).to eq('29284d9bcc350bcae005872d0be6edd016e2efb5')
end
end
-
- context 'when feature is disabled' do
- before do
- stub_feature_flags(branch_push_merge_commit_analyze: false)
- end
-
- it "does not trigger analysis" do
- expect(Gitlab::BranchPushMergeCommitAnalyzer).not_to receive(:new)
-
- subject
-
- merge_request.reload
- merge_request_side_branch.reload
-
- expect(merge_request.merge_commit).to eq(nil)
- expect(merge_request_side_branch.merge_commit).to eq(nil)
- end
- end
end
describe '#abort_ff_merge_requests_with_when_pipeline_succeeds' do
diff --git a/spec/services/merge_requests/reopen_service_spec.rb b/spec/services/merge_requests/reopen_service_spec.rb
index 0066834180e..ffc2ebb344c 100644
--- a/spec/services/merge_requests/reopen_service_spec.rb
+++ b/spec/services/merge_requests/reopen_service_spec.rb
@@ -20,11 +20,8 @@ RSpec.describe MergeRequests::ReopenService do
context 'valid params' do
let(:service) { described_class.new(project, user, {}) }
- let(:state_tracking) { true }
before do
- stub_feature_flags(track_resource_state_change_events: state_tracking)
-
allow(service).to receive(:execute_hooks)
perform_enqueued_jobs do
@@ -47,20 +44,9 @@ RSpec.describe MergeRequests::ReopenService do
end
context 'note creation' do
- context 'when state event tracking is disabled' do
- let(:state_tracking) { false }
-
- it 'creates system note about merge_request reopen' do
- note = merge_request.notes.last
- expect(note.note).to include 'reopened'
- end
- end
-
- context 'when state event tracking is enabled' do
- it 'creates resource state event about merge_request reopen' do
- event = merge_request.resource_state_events.last
- expect(event.state).to eq('reopened')
- end
+ it 'creates resource state event about merge_request reopen' do
+ event = merge_request.resource_state_events.last
+ expect(event.state).to eq('reopened')
end
end
end
diff --git a/spec/services/merge_requests/update_service_spec.rb b/spec/services/merge_requests/update_service_spec.rb
index 3c3e10495d3..ed8872b71f7 100644
--- a/spec/services/merge_requests/update_service_spec.rb
+++ b/spec/services/merge_requests/update_service_spec.rb
@@ -53,7 +53,7 @@ RSpec.describe MergeRequests::UpdateService, :mailer do
title: 'New title',
description: 'Also please fix',
assignee_ids: [user.id],
- reviewer_ids: [user.id],
+ reviewer_ids: [],
state_event: 'close',
label_ids: [label.id],
target_branch: 'target',
@@ -78,7 +78,7 @@ RSpec.describe MergeRequests::UpdateService, :mailer do
expect(@merge_request).to be_valid
expect(@merge_request.title).to eq('New title')
expect(@merge_request.assignees).to match_array([user])
- expect(@merge_request.reviewers).to match_array([user])
+ expect(@merge_request.reviewers).to match_array([])
expect(@merge_request).to be_closed
expect(@merge_request.labels.count).to eq(1)
expect(@merge_request.labels.first.title).to eq(label.name)
@@ -116,6 +116,7 @@ RSpec.describe MergeRequests::UpdateService, :mailer do
labels: [],
mentioned_users: [user2],
assignees: [user3],
+ reviewers: [],
milestone: nil,
total_time_spent: 0,
description: "FYI #{user2.to_reference}"
@@ -138,6 +139,35 @@ RSpec.describe MergeRequests::UpdateService, :mailer do
expect(note.note).to include "assigned to #{user.to_reference} and unassigned #{user3.to_reference}"
end
+ context 'with reviewers' do
+ let(:opts) { { reviewer_ids: [user2.id] } }
+
+ context 'when merge_request_reviewers feature is disabled' do
+ before(:context) do
+ stub_feature_flags(merge_request_reviewers: false)
+ end
+
+ it 'does not create a system note about merge_request review request' do
+ note = find_note('review requested from')
+
+ expect(note).to be_nil
+ end
+ end
+
+ context 'when merge_request_reviewers feature is enabled' do
+ before(:context) do
+ stub_feature_flags(merge_request_reviewers: true)
+ end
+
+ it 'creates system note about merge_request review request' do
+ note = find_note('requested review from')
+
+ expect(note).not_to be_nil
+ expect(note.note).to include "requested review from #{user2.to_reference}"
+ end
+ end
+ end
+
it 'creates a resource label event' do
event = merge_request.resource_label_events.last
@@ -467,15 +497,15 @@ RSpec.describe MergeRequests::UpdateService, :mailer do
end
context 'when reviewers gets changed' do
- before do
+ it 'marks pending todo as done' do
update_merge_request({ reviewer_ids: [user2.id] })
- end
- it 'marks pending todo as done' do
expect(pending_todo.reload).to be_done
end
it 'creates a pending todo for new review request' do
+ update_merge_request({ reviewer_ids: [user2.id] })
+
attributes = {
project: project,
author: user,
@@ -488,6 +518,17 @@ RSpec.describe MergeRequests::UpdateService, :mailer do
expect(Todo.where(attributes).count).to eq 1
end
+
+ it 'sends email reviewer change notifications to old and new reviewers', :sidekiq_might_not_need_inline do
+ merge_request.reviewers = [user2]
+
+ perform_enqueued_jobs do
+ update_merge_request({ reviewer_ids: [user3.id] })
+ end
+
+ should_email(user2)
+ should_email(user3)
+ end
end
context 'when the milestone is removed' do
@@ -542,7 +583,7 @@ RSpec.describe MergeRequests::UpdateService, :mailer do
context 'when the labels change' do
before do
- Timecop.freeze(1.minute.from_now) do
+ travel_to(1.minute.from_now) do
update_merge_request({ label_ids: [label.id] })
end
end
diff --git a/spec/services/metrics/dashboard/custom_dashboard_service_spec.rb b/spec/services/metrics/dashboard/custom_dashboard_service_spec.rb
index aea9c25d104..5dc30c156ac 100644
--- a/spec/services/metrics/dashboard/custom_dashboard_service_spec.rb
+++ b/spec/services/metrics/dashboard/custom_dashboard_service_spec.rb
@@ -67,6 +67,23 @@ RSpec.describe Metrics::Dashboard::CustomDashboardService, :use_clean_rails_memo
.at_least(:once)
end
+ context 'with metric in database' do
+ let!(:prometheus_metric) do
+ create(:prometheus_metric, project: project, identifier: 'metric_a1', group: 'custom')
+ end
+
+ it 'includes metric_id' do
+ dashboard = described_class.new(*service_params).get_dashboard
+
+ metric_id = dashboard[:dashboard][:panel_groups].find { |panel_group| panel_group[:group] == 'Group A' }
+ .fetch(:panels).find { |panel| panel[:title] == 'Super Chart A1' }
+ .fetch(:metrics).find { |metric| metric[:id] == 'metric_a1' }
+ .fetch(:metric_id)
+
+ expect(metric_id).to eq(prometheus_metric.id)
+ end
+ end
+
context 'and the dashboard is then deleted' do
it 'does not return the previously cached dashboard' do
described_class.new(*service_params).get_dashboard
diff --git a/spec/services/milestones/destroy_service_spec.rb b/spec/services/milestones/destroy_service_spec.rb
index 66c5c504c64..dd68471d927 100644
--- a/spec/services/milestones/destroy_service_spec.rb
+++ b/spec/services/milestones/destroy_service_spec.rb
@@ -45,7 +45,7 @@ RSpec.describe Milestones::DestroyService do
let(:group_milestone) { create(:milestone, group: group) }
before do
- project.update(namespace: group)
+ project.update!(namespace: group)
group.add_developer(user)
end
diff --git a/spec/services/milestones/promote_service_spec.rb b/spec/services/milestones/promote_service_spec.rb
index f0a34241c74..8f4201d8d94 100644
--- a/spec/services/milestones/promote_service_spec.rb
+++ b/spec/services/milestones/promote_service_spec.rb
@@ -23,7 +23,7 @@ RSpec.describe Milestones::PromoteService do
end
it 'raises error if project does not belong to a group' do
- project.update(namespace: user.namespace)
+ project.update!(namespace: user.namespace)
expect { service.execute(milestone) }.to raise_error(described_class::PromoteMilestoneError)
end
diff --git a/spec/services/milestones/transfer_service_spec.rb b/spec/services/milestones/transfer_service_spec.rb
index 4a626fe688a..6f4f55b2bd0 100644
--- a/spec/services/milestones/transfer_service_spec.rb
+++ b/spec/services/milestones/transfer_service_spec.rb
@@ -23,7 +23,7 @@ RSpec.describe Milestones::TransferService do
new_group.add_maintainer(user)
project.add_maintainer(user)
# simulate project transfer
- project.update(group: new_group)
+ project.update!(group: new_group)
end
context 'without existing milestone at the new group level' do
diff --git a/spec/services/namespace_settings/update_service_spec.rb b/spec/services/namespace_settings/update_service_spec.rb
new file mode 100644
index 00000000000..b588bf2034d
--- /dev/null
+++ b/spec/services/namespace_settings/update_service_spec.rb
@@ -0,0 +1,48 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe NamespaceSettings::UpdateService do
+ let(:user) { create(:user) }
+ let(:group) { create(:group) }
+ let(:settings) { {} }
+
+ subject(:service) { described_class.new(user, group, settings) }
+
+ describe "#execute" do
+ context "group has no namespace_settings" do
+ before do
+ group.namespace_settings.destroy!
+ end
+
+ it "builds out a new namespace_settings record" do
+ expect do
+ service.execute
+ end.to change { NamespaceSetting.count }.by(1)
+ end
+ end
+
+ context "group has a namespace_settings" do
+ before do
+ service.execute
+ end
+
+ it "doesn't create a new namespace_setting record" do
+ expect do
+ service.execute
+ end.not_to change { NamespaceSetting.count }
+ end
+ end
+
+ context "updating :default_branch_name" do
+ let(:example_branch_name) { "example_branch_name" }
+ let(:settings) { { default_branch_name: example_branch_name } }
+
+ it "changes settings" do
+ expect { service.execute }
+ .to change { group.namespace_settings.default_branch_name }
+ .from(nil).to(example_branch_name)
+ end
+ end
+ end
+end
diff --git a/spec/services/notes/create_service_spec.rb b/spec/services/notes/create_service_spec.rb
index 7c0d4b756bd..1e5536a2d0b 100644
--- a/spec/services/notes/create_service_spec.rb
+++ b/spec/services/notes/create_service_spec.rb
@@ -163,14 +163,6 @@ RSpec.describe Notes::CreateService do
expect(note.note_diff_file).to be_present
expect(note.diff_note_positions).to be_present
end
-
- it 'does not create diff positions merge_ref_head_comments is disabled' do
- stub_feature_flags(merge_ref_head_comments: false)
-
- expect(Discussions::CaptureDiffNotePositionService).not_to receive(:new)
-
- described_class.new(project_with_repo, user, new_opts).execute
- end
end
context 'when DiffNote is a reply' do
@@ -437,7 +429,7 @@ RSpec.describe Notes::CreateService do
expect do
existing_note
- Timecop.freeze(Time.current + 1.minute) { subject }
+ travel_to(Time.current + 1.minute) { subject }
existing_note.reload
end.to change { existing_note.type }.from(nil).to('DiscussionNote')
diff --git a/spec/services/notes/update_service_spec.rb b/spec/services/notes/update_service_spec.rb
index 47b8ba0cd72..66efdf8abe7 100644
--- a/spec/services/notes/update_service_spec.rb
+++ b/spec/services/notes/update_service_spec.rb
@@ -42,7 +42,7 @@ RSpec.describe Notes::UpdateService do
end
it 'does not update the note when params is blank' do
- Timecop.freeze(1.day.from_now) do
+ travel_to(1.day.from_now) do
expect { update_note({}) }.not_to change { note.reload.updated_at }
end
end
diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb
index 03e24524f9f..caa9961424e 100644
--- a/spec/services/notification_service_spec.rb
+++ b/spec/services/notification_service_spec.rb
@@ -150,6 +150,16 @@ RSpec.describe NotificationService, :mailer do
end
end
+ shared_examples 'participating by reviewer notification' do
+ it 'emails the participant' do
+ issuable.reviewers << participant
+
+ notification_trigger
+
+ should_email(participant)
+ end
+ end
+
shared_examples_for 'participating notifications' do
it_behaves_like 'participating by note notification'
it_behaves_like 'participating by author notification'
@@ -1778,6 +1788,60 @@ RSpec.describe NotificationService, :mailer do
end
end
+ describe '#changed_reviewer_of_merge_request' do
+ let(:merge_request) { create(:merge_request, author: author, source_project: project, reviewers: [reviewer], description: 'cc @participant') }
+
+ let_it_be(:current_user) { create(:user) }
+ let_it_be(:reviewer) { create(:user) }
+
+ before do
+ update_custom_notification(:change_reviewer_merge_request, @u_guest_custom, resource: project)
+ update_custom_notification(:change_reviewer_merge_request, @u_custom_global)
+ end
+
+ it 'sends emails to relevant users only', :aggregate_failures do
+ notification.changed_reviewer_of_merge_request(merge_request, current_user, [reviewer])
+
+ merge_request.reviewers.each { |reviewer| should_email(reviewer) }
+ should_email(merge_request.author)
+ should_email(@u_watcher)
+ should_email(@u_participant_mentioned)
+ should_email(@subscriber)
+ should_email(@watcher_and_subscriber)
+ should_email(@u_guest_watcher)
+ should_email(@u_guest_custom)
+ should_email(@u_custom_global)
+ should_not_email(@unsubscriber)
+ should_not_email(@u_participating)
+ should_not_email(@u_disabled)
+ should_not_email(@u_lazy_participant)
+ end
+
+ it 'adds "review requested" reason for new reviewer' do
+ notification.changed_reviewer_of_merge_request(merge_request, current_user, [reviewer])
+
+ merge_request.reviewers.each do |assignee|
+ email = find_email_for(assignee)
+
+ expect(email).to have_header('X-GitLab-NotificationReason', NotificationReason::REVIEW_REQUESTED)
+ end
+ end
+
+ context 'participating notifications with reviewers' do
+ let(:participant) { create(:user, username: 'user-participant') }
+ let(:issuable) { merge_request }
+ let(:notification_trigger) { notification.changed_reviewer_of_merge_request(merge_request, current_user, [reviewer]) }
+
+ it_behaves_like 'participating notifications'
+ it_behaves_like 'participating by reviewer notification'
+ end
+
+ it_behaves_like 'project emails are disabled' do
+ let(:notification_target) { merge_request }
+ let(:notification_trigger) { notification.changed_reviewer_of_merge_request(merge_request, current_user, [reviewer]) }
+ end
+ end
+
describe '#push_to_merge_request' do
before do
update_custom_notification(:push_to_merge_request, @u_guest_custom, resource: project)
@@ -2229,6 +2293,25 @@ RSpec.describe NotificationService, :mailer do
end
end
+ describe '#invite_member_reminder' do
+ let_it_be(:group_member) { create(:group_member) }
+
+ subject { notification.invite_member_reminder(group_member, 'token', 0) }
+
+ it 'calls the Notify.invite_member_reminder method with the right params' do
+ expect(Notify).to receive(:member_invited_reminder_email).with('Group', group_member.id, 'token', 0).at_least(:once).and_call_original
+
+ subject
+ end
+
+ it 'sends exactly one email' do
+ subject
+
+ expect_delivery_jobs_count(1)
+ expect_enqueud_email('Group', group_member.id, 'token', 0, mail: 'member_invited_reminder_email')
+ end
+ end
+
describe 'GroupMember', :deliver_mails_inline do
let(:added_user) { create(:user) }
@@ -3018,32 +3101,25 @@ RSpec.describe NotificationService, :mailer do
describe '#prometheus_alerts_fired' do
let!(:project) { create(:project) }
- let!(:prometheus_alert) { create(:prometheus_alert, project: project) }
let!(:master) { create(:user) }
let!(:developer) { create(:user) }
+ let(:alert_attributes) { build(:alert_management_alert, project: project).attributes }
before do
project.add_maintainer(master)
end
it 'sends the email to owners and masters' do
- expect(Notify).to receive(:prometheus_alert_fired_email).with(project.id, master.id, prometheus_alert).and_call_original
- expect(Notify).to receive(:prometheus_alert_fired_email).with(project.id, project.owner.id, prometheus_alert).and_call_original
- expect(Notify).not_to receive(:prometheus_alert_fired_email).with(project.id, developer.id, prometheus_alert)
+ expect(Notify).to receive(:prometheus_alert_fired_email).with(project.id, master.id, alert_attributes).and_call_original
+ expect(Notify).to receive(:prometheus_alert_fired_email).with(project.id, project.owner.id, alert_attributes).and_call_original
+ expect(Notify).not_to receive(:prometheus_alert_fired_email).with(project.id, developer.id, alert_attributes)
- subject.prometheus_alerts_fired(prometheus_alert.project, [prometheus_alert])
+ subject.prometheus_alerts_fired(project, [alert_attributes])
end
it_behaves_like 'project emails are disabled' do
- before do
- allow_next_instance_of(::Gitlab::Alerting::Alert) do |instance|
- allow(instance).to receive(:valid?).and_return(true)
- end
- end
-
- let(:alert_params) { { 'labels' => { 'gitlab_alert_id' => 'unknown' } } }
- let(:notification_target) { prometheus_alert.project }
- let(:notification_trigger) { subject.prometheus_alerts_fired(prometheus_alert.project, [alert_params]) }
+ let(:notification_target) { project }
+ let(:notification_trigger) { subject.prometheus_alerts_fired(project, [alert_attributes]) }
around do |example|
perform_enqueued_jobs { example.run }
diff --git a/spec/services/packages/composer/composer_json_service_spec.rb b/spec/services/packages/composer/composer_json_service_spec.rb
index 3996fcea679..378016a6ffb 100644
--- a/spec/services/packages/composer/composer_json_service_spec.rb
+++ b/spec/services/packages/composer/composer_json_service_spec.rb
@@ -23,7 +23,7 @@ RSpec.describe Packages::Composer::ComposerJsonService do
let(:json) { '{ name": "package-name"}' }
it 'raises an error' do
- expect { subject }.to raise_error(/Invalid/)
+ expect { subject }.to raise_error(described_class::InvalidJson, /Invalid/)
end
end
end
@@ -32,7 +32,7 @@ RSpec.describe Packages::Composer::ComposerJsonService do
let(:project) { create(:project, :repository) }
it 'raises an error' do
- expect { subject }.to raise_error(/not found/)
+ expect { subject }.to raise_error(described_class::InvalidJson, /not found/)
end
end
end
diff --git a/spec/services/packages/create_event_service_spec.rb b/spec/services/packages/create_event_service_spec.rb
new file mode 100644
index 00000000000..7e66b430a8c
--- /dev/null
+++ b/spec/services/packages/create_event_service_spec.rb
@@ -0,0 +1,54 @@
+# frozen_string_literal: true
+require 'spec_helper'
+
+RSpec.describe Packages::CreateEventService do
+ let(:scope) { 'container' }
+ let(:event_name) { 'push_package' }
+
+ let(:params) do
+ {
+ scope: scope,
+ event_name: event_name
+ }
+ end
+
+ subject { described_class.new(nil, user, params).execute }
+
+ describe '#execute' do
+ shared_examples 'package event creation' do |originator_type, expected_scope|
+ it 'creates the event' do
+ expect { subject }.to change { Packages::Event.count }.by(1)
+
+ expect(subject.originator_type).to eq(originator_type)
+ expect(subject.originator).to eq(user&.id)
+ expect(subject.event_scope).to eq(expected_scope)
+ expect(subject.event_type).to eq(event_name)
+ end
+ end
+
+ context 'with a user' do
+ let(:user) { create(:user) }
+
+ it_behaves_like 'package event creation', 'user', 'container'
+ end
+
+ context 'with a deploy token' do
+ let(:user) { create(:deploy_token) }
+
+ it_behaves_like 'package event creation', 'deploy_token', 'container'
+ end
+
+ context 'with no user' do
+ let(:user) { nil }
+
+ it_behaves_like 'package event creation', 'guest', 'container'
+ end
+
+ context 'with a package as scope' do
+ let(:user) { nil }
+ let(:scope) { create(:npm_package) }
+
+ it_behaves_like 'package event creation', 'guest', 'npm'
+ end
+ end
+end
diff --git a/spec/services/packages/generic/create_package_file_service_spec.rb b/spec/services/packages/generic/create_package_file_service_spec.rb
new file mode 100644
index 00000000000..0ae109ef996
--- /dev/null
+++ b/spec/services/packages/generic/create_package_file_service_spec.rb
@@ -0,0 +1,54 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Packages::Generic::CreatePackageFileService do
+ let_it_be(:project) { create(:project) }
+ let_it_be(:user) { create(:user) }
+
+ describe '#execute' do
+ let(:sha256) { '440e5e148a25331bbd7991575f7d54933c0ebf6cc735a18ee5066ac1381bb590' }
+ let(:temp_file) { Tempfile.new("test") }
+ let(:file) { UploadedFile.new(temp_file.path, sha256: sha256) }
+ let(:package) { create(:generic_package, project: project) }
+ let(:params) do
+ {
+ package_name: 'mypackage',
+ package_version: '0.0.1',
+ file: file,
+ file_name: 'myfile.tar.gz.1'
+ }
+ end
+
+ before do
+ FileUtils.touch(temp_file)
+ end
+
+ after do
+ FileUtils.rm_f(temp_file)
+ end
+
+ it 'creates package file' do
+ package_service = double
+ package_params = {
+ name: params[:package_name],
+ version: params[:package_version],
+ build: params[:build]
+ }
+ expect(::Packages::Generic::FindOrCreatePackageService).to receive(:new).with(project, user, package_params).and_return(package_service)
+ expect(package_service).to receive(:execute).and_return(package)
+
+ service = described_class.new(project, user, params)
+
+ expect { service.execute }.to change { package.package_files.count }.by(1)
+
+ package_file = package.package_files.last
+ aggregate_failures do
+ expect(package_file.package).to eq(package)
+ expect(package_file.file_name).to eq('myfile.tar.gz.1')
+ expect(package_file.size).to eq(file.size)
+ expect(package_file.file_sha256).to eq(sha256)
+ end
+ end
+ end
+end
diff --git a/spec/services/packages/generic/find_or_create_package_service_spec.rb b/spec/services/packages/generic/find_or_create_package_service_spec.rb
new file mode 100644
index 00000000000..5a9b8b03279
--- /dev/null
+++ b/spec/services/packages/generic/find_or_create_package_service_spec.rb
@@ -0,0 +1,88 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Packages::Generic::FindOrCreatePackageService do
+ let_it_be(:project) { create(:project) }
+ let_it_be(:user) { create(:user) }
+ let_it_be(:ci_build) { create(:ci_build, :running, user: user) }
+
+ let(:params) do
+ {
+ name: 'mypackage',
+ version: '0.0.1'
+ }
+ end
+
+ describe '#execute' do
+ context 'when packages does not exist yet' do
+ it 'creates package' do
+ service = described_class.new(project, user, params)
+
+ expect { service.execute }.to change { project.packages.generic.count }.by(1)
+
+ package = project.packages.generic.last
+
+ aggregate_failures do
+ expect(package.creator).to eq(user)
+ expect(package.name).to eq('mypackage')
+ expect(package.version).to eq('0.0.1')
+ expect(package.build_info).to be_nil
+ end
+ end
+
+ it 'creates package and package build info when build is provided' do
+ service = described_class.new(project, user, params.merge(build: ci_build))
+
+ expect { service.execute }.to change { project.packages.generic.count }.by(1)
+
+ package = project.packages.generic.last
+
+ aggregate_failures do
+ expect(package.creator).to eq(user)
+ expect(package.name).to eq('mypackage')
+ expect(package.version).to eq('0.0.1')
+ expect(package.build_info.pipeline).to eq(ci_build.pipeline)
+ end
+ end
+ end
+
+ context 'when packages already exists' do
+ let!(:package) { project.packages.generic.create!(params) }
+
+ context 'when package was created manually' do
+ it 'finds the package and does not create package build info even if build is provided' do
+ service = described_class.new(project, user, params.merge(build: ci_build))
+
+ expect do
+ found_package = service.execute
+
+ expect(found_package).to eq(package)
+ end.not_to change { project.packages.generic.count }
+
+ expect(package.reload.build_info).to be_nil
+ end
+ end
+
+ context 'when package was created by pipeline' do
+ let(:pipeline) { create(:ci_pipeline, project: project) }
+
+ before do
+ package.create_build_info!(pipeline: pipeline)
+ end
+
+ it 'finds the package and does not change package build info even if build is provided' do
+ service = described_class.new(project, user, params.merge(build: ci_build))
+
+ expect do
+ found_package = service.execute
+
+ expect(found_package).to eq(package)
+ end.not_to change { project.packages.generic.count }
+
+ expect(package.reload.build_info.pipeline).to eq(pipeline)
+ end
+ end
+ end
+ end
+end
diff --git a/spec/services/projects/after_rename_service_spec.rb b/spec/services/projects/after_rename_service_spec.rb
index f03e1ed0e22..a8db87e48d0 100644
--- a/spec/services/projects/after_rename_service_spec.rb
+++ b/spec/services/projects/after_rename_service_spec.rb
@@ -243,7 +243,7 @@ RSpec.describe Projects::AfterRenameService do
def service_execute
# AfterRenameService is called by UpdateService after a successful model.update
# the initialization will include before and after paths values
- project.update(path: path_after_rename)
+ project.update!(path: path_after_rename)
described_class.new(project, path_before: path_before_rename, full_path_before: full_path_before_rename).execute
end
diff --git a/spec/services/projects/alerting/notify_service_spec.rb b/spec/services/projects/alerting/notify_service_spec.rb
index 77a0e330109..809b12910a1 100644
--- a/spec/services/projects/alerting/notify_service_spec.rb
+++ b/spec/services/projects/alerting/notify_service_spec.rb
@@ -62,7 +62,7 @@ RSpec.describe Projects::Alerting::NotifyService do
title: payload_raw.fetch(:title),
started_at: Time.zone.parse(payload_raw.fetch(:start_time)),
severity: payload_raw.fetch(:severity),
- status: AlertManagement::Alert::STATUSES[:triggered],
+ status: AlertManagement::Alert.status_value(:triggered),
events: 1,
hosts: payload_raw.fetch(:hosts),
payload: payload_raw.with_indifferent_access,
@@ -89,6 +89,7 @@ RSpec.describe Projects::Alerting::NotifyService do
it 'creates a system note corresponding to alert creation' do
expect { subject }.to change(Note, :count).by(1)
+ expect(Note.last.note).to include(payload_raw.fetch(:monitoring_tool))
end
context 'existing alert with same fingerprint' do
@@ -127,23 +128,8 @@ RSpec.describe Projects::Alerting::NotifyService do
let(:alert) { create(:alert_management_alert, :with_issue, project: project, fingerprint: fingerprint_sha) }
let(:issue) { alert.issue }
- context 'state_tracking is enabled' do
- before do
- stub_feature_flags(track_resource_state_change_events: true)
- end
-
- it { expect { subject }.to change { issue.reload.state }.from('opened').to('closed') }
- it { expect { subject }.to change(ResourceStateEvent, :count).by(1) }
- end
-
- context 'state_tracking is disabled' do
- before do
- stub_feature_flags(track_resource_state_change_events: false)
- end
-
- it { expect { subject }.to change { issue.reload.state }.from('opened').to('closed') }
- it { expect { subject }.to change(Note, :count).by(1) }
- end
+ it { expect { subject }.to change { issue.reload.state }.from('opened').to('closed') }
+ it { expect { subject }.to change(ResourceStateEvent, :count).by(1) }
end
end
end
@@ -194,7 +180,7 @@ RSpec.describe Projects::Alerting::NotifyService do
title: payload_raw.fetch(:title),
started_at: Time.zone.parse(payload_raw.fetch(:start_time)),
severity: 'critical',
- status: AlertManagement::Alert::STATUSES[:triggered],
+ status: AlertManagement::Alert.status_value(:triggered),
events: 1,
hosts: [],
payload: payload_raw.with_indifferent_access,
@@ -208,15 +194,19 @@ RSpec.describe Projects::Alerting::NotifyService do
environment_id: nil
)
end
+
+ it 'creates a system note corresponding to alert creation' do
+ expect { subject }.to change(Note, :count).by(1)
+ expect(Note.last.note).to include('Generic Alert Endpoint')
+ end
end
end
context 'with overlong payload' do
- let(:payload_raw) do
- {
- title: 'a' * Gitlab::Utils::DeepSize::DEFAULT_MAX_SIZE,
- start_time: starts_at.rfc3339
- }
+ let(:deep_size_object) { instance_double(Gitlab::Utils::DeepSize, valid?: false) }
+
+ before do
+ allow(Gitlab::Utils::DeepSize).to receive(:new).and_return(deep_size_object)
end
it_behaves_like 'does not process incident issues due to error', http_status: :bad_request
@@ -230,17 +220,6 @@ RSpec.describe Projects::Alerting::NotifyService do
it_behaves_like 'processes incident issues'
- context 'with an invalid payload' do
- before do
- allow(Gitlab::Alerting::NotificationPayloadParser)
- .to receive(:call)
- .and_raise(Gitlab::Alerting::NotificationPayloadParser::BadPayloadError)
- end
-
- it_behaves_like 'does not process incident issues due to error', http_status: :bad_request
- it_behaves_like 'does not an create alert management alert'
- end
-
context 'when alert already exists' do
let(:fingerprint_sha) { Digest::SHA1.hexdigest(fingerprint) }
let!(:alert) { create(:alert_management_alert, project: project, fingerprint: fingerprint_sha) }
diff --git a/spec/services/projects/autocomplete_service_spec.rb b/spec/services/projects/autocomplete_service_spec.rb
index 336aa37096a..aff1aa41091 100644
--- a/spec/services/projects/autocomplete_service_spec.rb
+++ b/spec/services/projects/autocomplete_service_spec.rb
@@ -123,7 +123,7 @@ RSpec.describe Projects::AutocompleteService do
let!(:subgroup_milestone) { create(:milestone, group: subgroup) }
before do
- project.update(namespace: subgroup)
+ project.update!(namespace: subgroup)
end
it 'includes project milestones and all acestors milestones' do
@@ -138,7 +138,7 @@ RSpec.describe Projects::AutocompleteService do
def expect_labels_to_equal(labels, expected_labels)
expect(labels.size).to eq(expected_labels.size)
extract_title = lambda { |label| label['title'] }
- expect(labels.map(&extract_title)).to eq(expected_labels.map(&extract_title))
+ expect(labels.map(&extract_title)).to match_array(expected_labels.map(&extract_title))
end
let(:user) { create(:user) }
diff --git a/spec/services/projects/container_repository/cleanup_tags_service_spec.rb b/spec/services/projects/container_repository/cleanup_tags_service_spec.rb
index 2f2474f2681..8ddcb8ce660 100644
--- a/spec/services/projects/container_repository/cleanup_tags_service_spec.rb
+++ b/spec/services/projects/container_repository/cleanup_tags_service_spec.rb
@@ -12,8 +12,6 @@ RSpec.describe Projects::ContainerRepository::CleanupTagsService do
before do
project.add_maintainer(user)
- stub_feature_flags(container_registry_cleanup: true)
-
stub_container_registry_config(enabled: true)
stub_container_registry_tags(
diff --git a/spec/services/projects/container_repository/delete_tags_service_spec.rb b/spec/services/projects/container_repository/delete_tags_service_spec.rb
index 54375193067..c3ae26b1f05 100644
--- a/spec/services/projects/container_repository/delete_tags_service_spec.rb
+++ b/spec/services/projects/container_repository/delete_tags_service_spec.rb
@@ -87,59 +87,35 @@ RSpec.describe Projects::ContainerRepository::DeleteTagsService do
RSpec.shared_examples 'supporting fast delete' do
context 'when the registry supports fast delete' do
- context 'and the feature is enabled' do
- before do
- allow(repository.client).to receive(:supports_tag_delete?).and_return(true)
- end
-
- it_behaves_like 'calling the correct delete tags service', ::Projects::ContainerRepository::Gitlab::DeleteTagsService
-
- it_behaves_like 'handling invalid params'
+ before do
+ allow(repository.client).to receive(:supports_tag_delete?).and_return(true)
+ end
- context 'with the real service' do
- before do
- stub_delete_reference_requests(tags)
- expect_delete_tag_by_names(tags)
- end
+ it_behaves_like 'calling the correct delete tags service', ::Projects::ContainerRepository::Gitlab::DeleteTagsService
- it { is_expected.to include(status: :success) }
+ it_behaves_like 'handling invalid params'
- it_behaves_like 'logging a success response'
+ context 'with the real service' do
+ before do
+ stub_delete_reference_requests(tags)
+ expect_delete_tag_by_names(tags)
end
- context 'with a timeout error' do
- before do
- expect_next_instance_of(::Projects::ContainerRepository::Gitlab::DeleteTagsService) do |delete_service|
- expect(delete_service).to receive(:delete_tags).and_raise(::Projects::ContainerRepository::Gitlab::DeleteTagsService::TimeoutError)
- end
- end
-
- it { is_expected.to include(status: :error, message: 'timeout while deleting tags') }
+ it { is_expected.to include(status: :success) }
- it_behaves_like 'logging an error response', message: 'timeout while deleting tags'
- end
+ it_behaves_like 'logging a success response'
end
- context 'and the feature is disabled' do
+ context 'with a timeout error' do
before do
- stub_feature_flags(container_registry_fast_tag_delete: false)
- end
-
- it_behaves_like 'calling the correct delete tags service', ::Projects::ContainerRepository::ThirdParty::DeleteTagsService
-
- it_behaves_like 'handling invalid params'
-
- context 'with the real service' do
- before do
- stub_upload('sha256:4435000728ee66e6a80e55637fc22725c256b61de344a2ecdeaac6bdb36e8bc3')
- tags.each { |tag| stub_put_manifest_request(tag) }
- expect_delete_tag_by_digest('sha256:dummy')
+ expect_next_instance_of(::Projects::ContainerRepository::Gitlab::DeleteTagsService) do |delete_service|
+ expect(delete_service).to receive(:delete_tags).and_raise(::Projects::ContainerRepository::Gitlab::DeleteTagsService::TimeoutError)
end
+ end
- it { is_expected.to include(status: :success) }
+ it { is_expected.to include(status: :error, message: 'timeout while deleting tags') }
- it_behaves_like 'logging a success response'
- end
+ it_behaves_like 'logging an error response', message: 'timeout while deleting tags'
end
end
end
diff --git a/spec/services/projects/create_service_spec.rb b/spec/services/projects/create_service_spec.rb
index e1df8700795..d959cc87901 100644
--- a/spec/services/projects/create_service_spec.rb
+++ b/spec/services/projects/create_service_spec.rb
@@ -14,15 +14,30 @@ RSpec.describe Projects::CreateService, '#execute' do
}
end
- it 'creates labels on Project creation if there are templates' do
- Label.create(title: "bug", template: true)
- project = create_project(user, opts)
+ context 'with labels' do
+ subject(:project) { create_project(user, opts) }
+
+ before_all do
+ Label.create!(title: 'bug', template: true)
+ end
+
+ it 'creates labels on project creation' do
+ created_label = project.labels.last
- created_label = project.reload.labels.last
+ expect(created_label.type).to eq('ProjectLabel')
+ expect(created_label.project_id).to eq(project.id)
+ expect(created_label.title).to eq('bug')
+ end
+
+ context 'using gitlab project import' do
+ before do
+ opts[:import_type] = 'gitlab_project'
+ end
- expect(created_label.type).to eq('ProjectLabel')
- expect(created_label.project_id).to eq(project.id)
- expect(created_label.title).to eq('bug')
+ it 'does not creates labels on project creation' do
+ expect(project.labels.size).to eq(0)
+ end
+ end
end
context 'user namespace' do
@@ -59,10 +74,6 @@ RSpec.describe Projects::CreateService, '#execute' do
context "admin creates project with other user's namespace_id" do
it 'sets the correct permissions' do
admin = create(:admin)
- opts = {
- name: 'GitLab',
- namespace_id: user.namespace.id
- }
project = create_project(admin, opts)
expect(project).to be_persisted
@@ -487,18 +498,7 @@ RSpec.describe Projects::CreateService, '#execute' do
describe 'create service for the project' do
subject(:project) { create_project(user, opts) }
- context 'when there is an active instance-level and an active template integration' do
- let!(:template_integration) { create(:prometheus_service, :template, api_url: 'https://prometheus.template.com/') }
- let!(:instance_integration) { create(:prometheus_service, :instance, api_url: 'https://prometheus.instance.com/') }
-
- it 'creates a service from the instance-level integration' do
- expect(project.services.count).to eq(1)
- expect(project.services.first.api_url).to eq(instance_integration.api_url)
- expect(project.services.first.inherit_from_id).to eq(instance_integration.id)
- end
- end
-
- context 'when there is an active service template' do
+ context 'with an active service template' do
let!(:template_integration) { create(:prometheus_service, :template, api_url: 'https://prometheus.template.com/') }
it 'creates a service from the template' do
@@ -506,6 +506,60 @@ RSpec.describe Projects::CreateService, '#execute' do
expect(project.services.first.api_url).to eq(template_integration.api_url)
expect(project.services.first.inherit_from_id).to be_nil
end
+
+ context 'with an active instance-level integration' do
+ let!(:instance_integration) { create(:prometheus_service, :instance, api_url: 'https://prometheus.instance.com/') }
+
+ it 'creates a service from the instance-level integration' do
+ expect(project.services.count).to eq(1)
+ expect(project.services.first.api_url).to eq(instance_integration.api_url)
+ expect(project.services.first.inherit_from_id).to eq(instance_integration.id)
+ end
+
+ context 'with an active group-level integration' do
+ let!(:group_integration) { create(:prometheus_service, group: group, project: nil, api_url: 'https://prometheus.group.com/') }
+ let!(:group) do
+ create(:group).tap do |group|
+ group.add_owner(user)
+ end
+ end
+
+ let(:opts) do
+ {
+ name: 'GitLab',
+ namespace_id: group.id
+ }
+ end
+
+ it 'creates a service from the group-level integration' do
+ expect(project.services.count).to eq(1)
+ expect(project.services.first.api_url).to eq(group_integration.api_url)
+ expect(project.services.first.inherit_from_id).to eq(group_integration.id)
+ end
+
+ context 'with an active subgroup' do
+ let!(:subgroup_integration) { create(:prometheus_service, group: subgroup, project: nil, api_url: 'https://prometheus.subgroup.com/') }
+ let!(:subgroup) do
+ create(:group, parent: group).tap do |subgroup|
+ subgroup.add_owner(user)
+ end
+ end
+
+ let(:opts) do
+ {
+ name: 'GitLab',
+ namespace_id: subgroup.id
+ }
+ end
+
+ it 'creates a service from the subgroup-level integration' do
+ expect(project.services.count).to eq(1)
+ expect(project.services.first.api_url).to eq(subgroup_integration.api_url)
+ expect(project.services.first.inherit_from_id).to eq(subgroup_integration.id)
+ end
+ end
+ end
+ end
end
context 'when there is an invalid integration' do
@@ -739,4 +793,100 @@ RSpec.describe Projects::CreateService, '#execute' do
def create_project(user, opts)
Projects::CreateService.new(user, opts).execute
end
+
+ context 'shared Runners config' do
+ using RSpec::Parameterized::TableSyntax
+
+ let_it_be(:user) { create :user }
+
+ context 'when parent group is present' do
+ let_it_be(:group) do
+ create(:group) do |group|
+ group.add_owner(user)
+ end
+ end
+
+ before do
+ allow_next_found_instance_of(Group) do |group|
+ allow(group).to receive(:shared_runners_setting).and_return(shared_runners_setting)
+ end
+
+ user.refresh_authorized_projects # Ensure cache is warm
+ end
+
+ context 'default value based on parent group setting' do
+ where(:shared_runners_setting, :desired_config_for_new_project, :expected_result_for_project) do
+ 'enabled' | nil | true
+ 'disabled_with_override' | nil | false
+ 'disabled_and_unoverridable' | nil | false
+ end
+
+ with_them do
+ it 'creates project following the parent config' do
+ params = opts.merge(namespace_id: group.id)
+ params = params.merge(shared_runners_enabled: desired_config_for_new_project) unless desired_config_for_new_project.nil?
+ project = create_project(user, params)
+
+ expect(project).to be_valid
+ expect(project.shared_runners_enabled).to eq(expected_result_for_project)
+ end
+ end
+ end
+
+ context 'parent group is present and allows desired config' do
+ where(:shared_runners_setting, :desired_config_for_new_project, :expected_result_for_project) do
+ 'enabled' | true | true
+ 'enabled' | false | false
+ 'disabled_with_override' | false | false
+ 'disabled_with_override' | true | true
+ 'disabled_and_unoverridable' | false | false
+ end
+
+ with_them do
+ it 'creates project following the parent config' do
+ params = opts.merge(namespace_id: group.id, shared_runners_enabled: desired_config_for_new_project)
+ project = create_project(user, params)
+
+ expect(project).to be_valid
+ expect(project.shared_runners_enabled).to eq(expected_result_for_project)
+ end
+ end
+ end
+
+ context 'parent group is present and disallows desired config' do
+ where(:shared_runners_setting, :desired_config_for_new_project) do
+ 'disabled_and_unoverridable' | true
+ end
+
+ with_them do
+ it 'does not create project' do
+ params = opts.merge(namespace_id: group.id, shared_runners_enabled: desired_config_for_new_project)
+ project = create_project(user, params)
+
+ expect(project.persisted?).to eq(false)
+ expect(project).to be_invalid
+ expect(project.errors[:shared_runners_enabled]).to include('cannot be enabled because parent group does not allow it')
+ end
+ end
+ end
+ end
+
+ context 'parent group is not present' do
+ where(:desired_config, :expected_result) do
+ true | true
+ false | false
+ nil | true
+ end
+
+ with_them do
+ it 'follows desired config' do
+ opts[:shared_runners_enabled] = desired_config unless desired_config.nil?
+ project = create_project(user, opts)
+
+ expect(project).to be_valid
+ expect(project.shared_runners_enabled).to eq(expected_result)
+ end
+ end
+ end
+ end
end
diff --git a/spec/services/projects/destroy_service_spec.rb b/spec/services/projects/destroy_service_spec.rb
index a3711c9e17f..f0f09218b06 100644
--- a/spec/services/projects/destroy_service_spec.rb
+++ b/spec/services/projects/destroy_service_spec.rb
@@ -72,7 +72,7 @@ RSpec.describe Projects::DestroyService, :aggregate_failures do
context 'when project has remote mirrors' do
let!(:project) do
create(:project, :repository, namespace: user.namespace).tap do |project|
- project.remote_mirrors.create(url: 'http://test.com')
+ project.remote_mirrors.create!(url: 'http://test.com')
end
end
diff --git a/spec/services/projects/fork_service_spec.rb b/spec/services/projects/fork_service_spec.rb
index 166a2dae55b..555f2f5a5e5 100644
--- a/spec/services/projects/fork_service_spec.rb
+++ b/spec/services/projects/fork_service_spec.rb
@@ -179,7 +179,7 @@ RSpec.describe Projects::ForkService do
context "when origin has git depth specified" do
before do
- @from_project.update(ci_default_git_depth: 42)
+ @from_project.update!(ci_default_git_depth: 42)
end
it "inherits default_git_depth from the origin project" do
@@ -201,7 +201,7 @@ RSpec.describe Projects::ForkService do
context "when project has restricted visibility level" do
context "and only one visibility level is restricted" do
before do
- @from_project.update(visibility_level: Gitlab::VisibilityLevel::INTERNAL)
+ @from_project.update!(visibility_level: Gitlab::VisibilityLevel::INTERNAL)
stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::INTERNAL])
end
diff --git a/spec/services/projects/hashed_storage/base_attachment_service_spec.rb b/spec/services/projects/hashed_storage/base_attachment_service_spec.rb
index 969381b8748..86e3fb3820c 100644
--- a/spec/services/projects/hashed_storage/base_attachment_service_spec.rb
+++ b/spec/services/projects/hashed_storage/base_attachment_service_spec.rb
@@ -45,7 +45,7 @@ RSpec.describe Projects::HashedStorage::BaseAttachmentService do
describe '#move_folder!' do
context 'when old_path is not a directory' do
it 'adds information to the logger and returns true' do
- Tempfile.create do |old_path|
+ Tempfile.create do |old_path| # rubocop:disable Rails/SaveBang
new_path = "#{old_path}-new"
expect(subject.send(:move_folder!, old_path, new_path)).to be_truthy
diff --git a/spec/services/projects/move_access_service_spec.rb b/spec/services/projects/move_access_service_spec.rb
index de3871414af..02f80988dd1 100644
--- a/spec/services/projects/move_access_service_spec.rb
+++ b/spec/services/projects/move_access_service_spec.rb
@@ -17,9 +17,9 @@ RSpec.describe Projects::MoveAccessService do
project_with_access.add_maintainer(maintainer_user)
project_with_access.add_developer(developer_user)
project_with_access.add_reporter(reporter_user)
- project_with_access.project_group_links.create(group: maintainer_group, group_access: Gitlab::Access::MAINTAINER)
- project_with_access.project_group_links.create(group: developer_group, group_access: Gitlab::Access::DEVELOPER)
- project_with_access.project_group_links.create(group: reporter_group, group_access: Gitlab::Access::REPORTER)
+ project_with_access.project_group_links.create!(group: maintainer_group, group_access: Gitlab::Access::MAINTAINER)
+ project_with_access.project_group_links.create!(group: developer_group, group_access: Gitlab::Access::DEVELOPER)
+ project_with_access.project_group_links.create!(group: reporter_group, group_access: Gitlab::Access::REPORTER)
end
subject { described_class.new(target_project, user) }
@@ -97,7 +97,7 @@ RSpec.describe Projects::MoveAccessService do
end
it 'does not remove remaining group links' do
- target_project.project_group_links.create(group: maintainer_group, group_access: Gitlab::Access::MAINTAINER)
+ target_project.project_group_links.create!(group: maintainer_group, group_access: Gitlab::Access::MAINTAINER)
subject.execute(project_with_access, options)
diff --git a/spec/services/projects/move_project_group_links_service_spec.rb b/spec/services/projects/move_project_group_links_service_spec.rb
index 196a8f2b339..6304eded8d3 100644
--- a/spec/services/projects/move_project_group_links_service_spec.rb
+++ b/spec/services/projects/move_project_group_links_service_spec.rb
@@ -14,9 +14,9 @@ RSpec.describe Projects::MoveProjectGroupLinksService do
describe '#execute' do
before do
- project_with_groups.project_group_links.create(group: maintainer_group, group_access: Gitlab::Access::MAINTAINER)
- project_with_groups.project_group_links.create(group: developer_group, group_access: Gitlab::Access::DEVELOPER)
- project_with_groups.project_group_links.create(group: reporter_group, group_access: Gitlab::Access::REPORTER)
+ project_with_groups.project_group_links.create!(group: maintainer_group, group_access: Gitlab::Access::MAINTAINER)
+ project_with_groups.project_group_links.create!(group: developer_group, group_access: Gitlab::Access::DEVELOPER)
+ project_with_groups.project_group_links.create!(group: reporter_group, group_access: Gitlab::Access::REPORTER)
end
it 'moves the group links from one project to another' do
@@ -30,8 +30,8 @@ RSpec.describe Projects::MoveProjectGroupLinksService do
end
it 'does not move existent group links in the current project' do
- target_project.project_group_links.create(group: maintainer_group, group_access: Gitlab::Access::MAINTAINER)
- target_project.project_group_links.create(group: developer_group, group_access: Gitlab::Access::DEVELOPER)
+ target_project.project_group_links.create!(group: maintainer_group, group_access: Gitlab::Access::MAINTAINER)
+ target_project.project_group_links.create!(group: developer_group, group_access: Gitlab::Access::DEVELOPER)
expect(project_with_groups.project_group_links.count).to eq 3
expect(target_project.project_group_links.count).to eq 2
@@ -55,8 +55,8 @@ RSpec.describe Projects::MoveProjectGroupLinksService do
let(:options) { { remove_remaining_elements: false } }
it 'does not remove remaining project group links' do
- target_project.project_group_links.create(group: maintainer_group, group_access: Gitlab::Access::MAINTAINER)
- target_project.project_group_links.create(group: developer_group, group_access: Gitlab::Access::DEVELOPER)
+ target_project.project_group_links.create!(group: maintainer_group, group_access: Gitlab::Access::MAINTAINER)
+ target_project.project_group_links.create!(group: developer_group, group_access: Gitlab::Access::DEVELOPER)
subject.execute(project_with_groups, options)
diff --git a/spec/services/projects/operations/update_service_spec.rb b/spec/services/projects/operations/update_service_spec.rb
index 8a538bc67ed..018bfa8ef61 100644
--- a/spec/services/projects/operations/update_service_spec.rb
+++ b/spec/services/projects/operations/update_service_spec.rb
@@ -3,8 +3,8 @@
require 'spec_helper'
RSpec.describe Projects::Operations::UpdateService do
+ let_it_be_with_refind(:project) { create(:project) }
let_it_be(:user) { create(:user) }
- let_it_be(:project, refind: true) { create(:project) }
let(:result) { subject.execute }
@@ -12,7 +12,7 @@ RSpec.describe Projects::Operations::UpdateService do
describe '#execute' do
context 'alerting setting' do
- before do
+ before_all do
project.add_maintainer(user)
end
@@ -430,5 +430,93 @@ RSpec.describe Projects::Operations::UpdateService do
end
end
end
+
+ context 'tracing setting' do
+ context 'with valid params' do
+ let(:params) do
+ {
+ tracing_setting_attributes: {
+ external_url: 'http://some-url.com'
+ }
+ }
+ end
+
+ context 'with an existing setting' do
+ before do
+ create(:project_tracing_setting, project: project)
+ end
+
+ shared_examples 'setting deletion' do
+ let!(:original_params) { params.deep_dup }
+
+ it 'deletes the setting' do
+ expect(result[:status]).to eq(:success)
+ expect(project.reload.tracing_setting).to be_nil
+ end
+
+ it 'does not modify original params' do
+ subject.execute
+
+ expect(params).to eq(original_params)
+ end
+ end
+
+ it 'updates the setting' do
+ expect(project.tracing_setting).not_to be_nil
+
+ expect(result[:status]).to eq(:success)
+ expect(project.reload.tracing_setting.external_url)
+ .to eq('http://some-url.com')
+ end
+
+ context 'with missing external_url' do
+ before do
+ params[:tracing_setting_attributes].delete(:external_url)
+ end
+
+ it_behaves_like 'setting deletion'
+ end
+
+ context 'with empty external_url' do
+ before do
+ params[:tracing_setting_attributes][:external_url] = ''
+ end
+
+ it_behaves_like 'setting deletion'
+ end
+
+ context 'with blank external_url' do
+ before do
+ params[:tracing_setting_attributes][:external_url] = ' '
+ end
+
+ it_behaves_like 'setting deletion'
+ end
+ end
+
+ context 'without an existing setting' do
+ it 'creates a setting' do
+ expect(project.tracing_setting).to be_nil
+
+ expect(result[:status]).to eq(:success)
+ expect(project.reload.tracing_setting.external_url)
+ .to eq('http://some-url.com')
+ end
+ end
+ end
+
+ context 'with empty params' do
+ let(:params) { {} }
+
+ let!(:tracing_setting) do
+ create(:project_tracing_setting, project: project)
+ end
+
+ it 'does nothing' do
+ expect(result[:status]).to eq(:success)
+ expect(project.reload.tracing_setting).to eq(tracing_setting)
+ end
+ end
+ end
end
end
diff --git a/spec/services/projects/overwrite_project_service_spec.rb b/spec/services/projects/overwrite_project_service_spec.rb
index a03746d0271..cc6a863a11d 100644
--- a/spec/services/projects/overwrite_project_service_spec.rb
+++ b/spec/services/projects/overwrite_project_service_spec.rb
@@ -111,9 +111,9 @@ RSpec.describe Projects::OverwriteProjectService do
create_list(:deploy_keys_project, 2, project: project_from)
create_list(:notification_setting, 2, source: project_from)
create_list(:users_star_project, 2, project: project_from)
- project_from.project_group_links.create(group: maintainer_group, group_access: Gitlab::Access::MAINTAINER)
- project_from.project_group_links.create(group: developer_group, group_access: Gitlab::Access::DEVELOPER)
- project_from.project_group_links.create(group: reporter_group, group_access: Gitlab::Access::REPORTER)
+ project_from.project_group_links.create!(group: maintainer_group, group_access: Gitlab::Access::MAINTAINER)
+ project_from.project_group_links.create!(group: developer_group, group_access: Gitlab::Access::DEVELOPER)
+ project_from.project_group_links.create!(group: reporter_group, group_access: Gitlab::Access::REPORTER)
project_from.add_maintainer(maintainer_user)
project_from.add_developer(developer_user)
project_from.add_reporter(reporter_user)
diff --git a/spec/services/projects/transfer_service_spec.rb b/spec/services/projects/transfer_service_spec.rb
index a0e83fb4a21..3ae96d7a5ab 100644
--- a/spec/services/projects/transfer_service_spec.rb
+++ b/spec/services/projects/transfer_service_spec.rb
@@ -314,6 +314,37 @@ RSpec.describe Projects::TransferService do
end
end
+ context 'shared Runners group level configurations' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:project_shared_runners_enabled, :shared_runners_setting, :expected_shared_runners_enabled) do
+ true | 'disabled_and_unoverridable' | false
+ false | 'disabled_and_unoverridable' | false
+ true | 'disabled_with_override' | true
+ false | 'disabled_with_override' | false
+ true | 'enabled' | true
+ false | 'enabled' | false
+ end
+
+ with_them do
+ let(:project) { create(:project, :public, :repository, namespace: user.namespace, shared_runners_enabled: project_shared_runners_enabled) }
+ let(:group) { create(:group) }
+
+ before do
+ group.add_owner(user)
+ expect_next_found_instance_of(Group) do |group|
+ expect(group).to receive(:shared_runners_setting).and_return(shared_runners_setting)
+ end
+
+ execute_transfer
+ end
+
+ it 'updates shared runners based on the parent group' do
+ expect(project.shared_runners_enabled).to eq(expected_shared_runners_enabled)
+ end
+ end
+ end
+
context 'missing group labels applied to issues or merge requests' do
it 'delegates transfer to Labels::TransferService' do
group.add_owner(user)
diff --git a/spec/services/projects/unlink_fork_service_spec.rb b/spec/services/projects/unlink_fork_service_spec.rb
index 073e2e09397..2a8965e62ce 100644
--- a/spec/services/projects/unlink_fork_service_spec.rb
+++ b/spec/services/projects/unlink_fork_service_spec.rb
@@ -61,7 +61,7 @@ RSpec.describe Projects::UnlinkForkService, :use_clean_rails_memory_store_cachin
context 'when the original project was deleted' do
it 'does not fail when the original project is deleted' do
source = forked_project.forked_from_project
- source.destroy
+ source.destroy!
forked_project.reload
expect { subject.execute }.not_to raise_error
diff --git a/spec/services/projects/update_pages_service_spec.rb b/spec/services/projects/update_pages_service_spec.rb
index bfb3cbb0131..d3eb84a3137 100644
--- a/spec/services/projects/update_pages_service_spec.rb
+++ b/spec/services/projects/update_pages_service_spec.rb
@@ -16,8 +16,6 @@ RSpec.describe Projects::UpdatePagesService do
subject { described_class.new(project, build) }
before do
- stub_feature_flags(safezip_use_rubyzip: true)
-
project.remove_pages
end
@@ -59,6 +57,28 @@ RSpec.describe Projects::UpdatePagesService do
end
end
+ it 'creates pages_deployment and saves it in the metadata' do
+ expect do
+ expect(execute).to eq(:success)
+ end.to change { project.pages_deployments.count }.by(1)
+
+ deployment = project.pages_deployments.last
+
+ expect(deployment.size).to eq(file.size)
+ expect(deployment.file).to be
+ expect(project.pages_metadatum.reload.pages_deployment_id).to eq(deployment.id)
+ end
+
+ it 'does not create deployment when zip_pages_deployments feature flag is disabled' do
+ stub_feature_flags(zip_pages_deployments: false)
+
+ expect do
+ expect(execute).to eq(:success)
+ end.not_to change { project.pages_deployments.count }
+
+ expect(project.pages_metadatum.reload.pages_deployment_id).to be_nil
+ end
+
it 'limits pages size' do
stub_application_setting(max_pages_size: 1)
expect(execute).not_to eq(:success)
@@ -75,14 +95,14 @@ RSpec.describe Projects::UpdatePagesService do
expect(project.pages_deployed?).to be_truthy
expect(Dir.exist?(File.join(project.pages_path))).to be_truthy
- project.destroy
+ project.destroy!
expect(Dir.exist?(File.join(project.pages_path))).to be_falsey
expect(ProjectPagesMetadatum.find_by_project_id(project)).to be_nil
end
it 'fails if sha on branch is not latest' do
- build.update(ref: 'feature')
+ build.update!(ref: 'feature')
expect(execute).not_to eq(:success)
expect(project.pages_metadatum).not_to be_deployed
@@ -104,10 +124,6 @@ RSpec.describe Projects::UpdatePagesService do
let(:file) { fixture_file_upload("spec/fixtures/pages_non_writeable.zip") }
context 'when using RubyZip' do
- before do
- stub_feature_flags(safezip_use_rubyzip: true)
- end
-
it 'succeeds to extract' do
expect(execute).to eq(:success)
expect(project.pages_metadatum).to be_deployed
@@ -175,7 +191,7 @@ RSpec.describe Projects::UpdatePagesService do
it 'fails to remove project pages when no pages is deployed' do
expect(PagesWorker).not_to receive(:perform_in)
expect(project.pages_deployed?).to be_falsey
- project.destroy
+ project.destroy!
end
it 'fails if no artifacts' do
diff --git a/spec/services/projects/update_remote_mirror_service_spec.rb b/spec/services/projects/update_remote_mirror_service_spec.rb
index 1de04888e0a..30530da8013 100644
--- a/spec/services/projects/update_remote_mirror_service_spec.rb
+++ b/spec/services/projects/update_remote_mirror_service_spec.rb
@@ -68,25 +68,12 @@ RSpec.describe Projects::UpdateRemoteMirrorService do
end
context "when given URLs containing escaped elements" do
- using RSpec::Parameterized::TableSyntax
+ it_behaves_like "URLs containing escaped elements return expected status" do
+ let(:result) { execute! }
- where(:url, :result_status) do
- "https://user:0a%23@test.example.com/project.git" | :success
- "https://git.example.com:1%2F%2F@source.developers.google.com/project.git" | :success
- CGI.escape("git://localhost:1234/some-path?some-query=some-val\#@example.com/") | :error
- CGI.escape(CGI.escape("https://user:0a%23@test.example.com/project.git")) | :error
- end
-
- with_them do
before do
allow(remote_mirror).to receive(:url).and_return(url)
end
-
- it "returns expected status" do
- result = execute!
-
- expect(result[:status]).to eq(result_status)
- end
end
end
@@ -136,54 +123,36 @@ RSpec.describe Projects::UpdateRemoteMirrorService do
stub_lfs_setting(enabled: true)
end
- context 'feature flag enabled' do
- before do
- stub_feature_flags(push_mirror_syncs_lfs: true)
- end
-
- it 'pushes LFS objects to a HTTP repository' do
- expect_next_instance_of(Lfs::PushService) do |service|
- expect(service).to receive(:execute)
- end
-
- execute!
+ it 'pushes LFS objects to a HTTP repository' do
+ expect_next_instance_of(Lfs::PushService) do |service|
+ expect(service).to receive(:execute)
end
- it 'does nothing to an SSH repository' do
- remote_mirror.update!(url: 'ssh://example.com')
-
- expect_any_instance_of(Lfs::PushService).not_to receive(:execute)
-
- execute!
- end
+ execute!
+ end
- it 'does nothing if LFS is disabled' do
- expect(project).to receive(:lfs_enabled?) { false }
+ it 'does nothing to an SSH repository' do
+ remote_mirror.update!(url: 'ssh://example.com')
- expect_any_instance_of(Lfs::PushService).not_to receive(:execute)
+ expect_any_instance_of(Lfs::PushService).not_to receive(:execute)
- execute!
- end
+ execute!
+ end
- it 'does nothing if non-password auth is specified' do
- remote_mirror.update!(auth_method: 'ssh_public_key')
+ it 'does nothing if LFS is disabled' do
+ expect(project).to receive(:lfs_enabled?) { false }
- expect_any_instance_of(Lfs::PushService).not_to receive(:execute)
+ expect_any_instance_of(Lfs::PushService).not_to receive(:execute)
- execute!
- end
+ execute!
end
- context 'feature flag disabled' do
- before do
- stub_feature_flags(push_mirror_syncs_lfs: false)
- end
+ it 'does nothing if non-password auth is specified' do
+ remote_mirror.update!(auth_method: 'ssh_public_key')
- it 'does nothing' do
- expect_any_instance_of(Lfs::PushService).not_to receive(:execute)
+ expect_any_instance_of(Lfs::PushService).not_to receive(:execute)
- execute!
- end
+ execute!
end
end
end
diff --git a/spec/services/projects/update_service_spec.rb b/spec/services/projects/update_service_spec.rb
index 7832d727220..989426fde8b 100644
--- a/spec/services/projects/update_service_spec.rb
+++ b/spec/services/projects/update_service_spec.rb
@@ -141,7 +141,7 @@ RSpec.describe Projects::UpdateService do
let(:group) { create(:group, visibility_level: Gitlab::VisibilityLevel::INTERNAL) }
before do
- project.update(namespace: group, visibility_level: group.visibility_level)
+ project.update!(namespace: group, visibility_level: group.visibility_level)
end
it 'does not update project visibility level' do
@@ -151,6 +151,32 @@ RSpec.describe Projects::UpdateService do
expect(project.reload).to be_internal
end
end
+
+ context 'when updating shared runners' do
+ context 'can enable shared runners' do
+ let(:group) { create(:group, shared_runners_enabled: true) }
+ let(:project) { create(:project, namespace: group, shared_runners_enabled: false) }
+
+ it 'enables shared runners' do
+ result = update_project(project, user, shared_runners_enabled: true)
+
+ expect(result).to eq({ status: :success })
+ expect(project.reload.shared_runners_enabled).to be_truthy
+ end
+ end
+
+ context 'cannot enable shared runners' do
+ let(:group) { create(:group, :shared_runners_disabled) }
+ let(:project) { create(:project, namespace: group, shared_runners_enabled: false) }
+
+ it 'does not enable shared runners' do
+ result = update_project(project, user, shared_runners_enabled: true)
+
+ expect(result).to eq({ status: :error, message: 'Shared runners enabled cannot be enabled because parent group does not allow it' })
+ expect(project.reload.shared_runners_enabled).to be_falsey
+ end
+ end
+ end
end
describe 'when updating project that has forks' do
@@ -230,7 +256,7 @@ RSpec.describe Projects::UpdateService do
end
it 'handles empty project feature attributes' do
- project.project_feature.update(wiki_access_level: ProjectFeature::DISABLED)
+ project.project_feature.update!(wiki_access_level: ProjectFeature::DISABLED)
result = update_project(project, user, { name: 'test1' })
@@ -241,7 +267,7 @@ RSpec.describe Projects::UpdateService do
context 'when enabling a wiki' do
it 'creates a wiki' do
- project.project_feature.update(wiki_access_level: ProjectFeature::DISABLED)
+ project.project_feature.update!(wiki_access_level: ProjectFeature::DISABLED)
TestEnv.rm_storage_dir(project.repository_storage, project.wiki.path)
result = update_project(project, user, project_feature_attributes: { wiki_access_level: ProjectFeature::ENABLED })
@@ -252,7 +278,7 @@ RSpec.describe Projects::UpdateService do
end
it 'logs an error and creates a metric when wiki can not be created' do
- project.project_feature.update(wiki_access_level: ProjectFeature::DISABLED)
+ project.project_feature.update!(wiki_access_level: ProjectFeature::DISABLED)
expect_any_instance_of(ProjectWiki).to receive(:wiki).and_raise(Wiki::CouldNotCreateWikiError)
expect_any_instance_of(described_class).to receive(:log_error).with("Could not create wiki for #{project.full_name}")
diff --git a/spec/services/quick_actions/interpret_service_spec.rb b/spec/services/quick_actions/interpret_service_spec.rb
index b970a48051f..6f3814095f9 100644
--- a/spec/services/quick_actions/interpret_service_spec.rb
+++ b/spec/services/quick_actions/interpret_service_spec.rb
@@ -3,23 +3,27 @@
require 'spec_helper'
RSpec.describe QuickActions::InterpretService do
- let(:project) { create(:project, :public) }
- let(:developer) { create(:user) }
- let(:developer2) { create(:user) }
- let(:issue) { create(:issue, project: project) }
+ let_it_be(:public_project) { create(:project, :public) }
+ let_it_be(:repository_project) { create(:project, :repository) }
+ let_it_be(:project) { public_project }
+ let_it_be(:developer) { create(:user) }
+ let_it_be(:developer2) { create(:user) }
+ let_it_be_with_reload(:issue) { create(:issue, project: project) }
let(:milestone) { create(:milestone, project: project, title: '9.10') }
let(:commit) { create(:commit, project: project) }
- let(:inprogress) { create(:label, project: project, title: 'In Progress') }
- let(:helmchart) { create(:label, project: project, title: 'Helm Chart Registry') }
- let(:bug) { create(:label, project: project, title: 'Bug') }
- let(:note) { build(:note, commit_id: merge_request.diff_head_sha) }
+ let_it_be(:inprogress) { create(:label, project: project, title: 'In Progress') }
+ let_it_be(:helmchart) { create(:label, project: project, title: 'Helm Chart Registry') }
+ let_it_be(:bug) { create(:label, project: project, title: 'Bug') }
let(:service) { described_class.new(project, developer) }
+ before_all do
+ public_project.add_developer(developer)
+ repository_project.add_developer(developer)
+ end
+
before do
stub_licensed_features(multiple_issue_assignees: false,
multiple_merge_request_assignees: false)
-
- project.add_developer(developer)
end
describe '#execute' do
@@ -146,7 +150,6 @@ RSpec.describe QuickActions::InterpretService do
shared_examples 'multiword label name starting without ~' do
it 'fetches label ids and populates add_label_ids if content contains /label' do
- helmchart # populate the label
_, updates = service.execute(content, issuable)
expect(updates).to eq(add_label_ids: [helmchart.id])
@@ -155,7 +158,6 @@ RSpec.describe QuickActions::InterpretService do
shared_examples 'label name is included in the middle of another label name' do
it 'ignores the sublabel when the content contains the includer label name' do
- helmchart # populate the label
create(:label, project: project, title: 'Chart')
_, updates = service.execute(content, issuable)
@@ -226,7 +228,7 @@ RSpec.describe QuickActions::InterpretService do
it 'returns the todo message' do
_, _, message = service.execute(content, issuable)
- expect(message).to eq('Added a To Do.')
+ expect(message).to eq('Added a to do.')
end
end
@@ -242,7 +244,7 @@ RSpec.describe QuickActions::InterpretService do
TodoService.new.mark_todo(issuable, developer)
_, _, message = service.execute(content, issuable)
- expect(message).to eq('Marked To Do as done.')
+ expect(message).to eq('Marked to do as done.')
end
end
@@ -493,7 +495,7 @@ RSpec.describe QuickActions::InterpretService do
end
shared_examples 'merge immediately command' do
- let(:project) { create(:project, :repository) }
+ let(:project) { repository_project }
it 'runs merge command if content contains /merge' do
_, updates, _ = service.execute(content, issuable)
@@ -509,7 +511,7 @@ RSpec.describe QuickActions::InterpretService do
end
shared_examples 'merge automatically command' do
- let(:project) { create(:project, :repository) }
+ let(:project) { repository_project }
it 'runs merge command if content contains /merge and returns merge message' do
_, updates, message = service.execute(content, issuable)
@@ -600,7 +602,7 @@ RSpec.describe QuickActions::InterpretService do
context 'when issuable is already confidential' do
before do
- issuable.update(confidential: true)
+ issuable.update!(confidential: true)
end
it 'does not return the success message' do
@@ -722,7 +724,7 @@ RSpec.describe QuickActions::InterpretService do
end
context 'when sha is missing' do
- let(:project) { create(:project, :repository) }
+ let(:project) { repository_project }
let(:service) { described_class.new(project, developer, {}) }
it 'precheck passes and returns merge command' do
@@ -844,7 +846,7 @@ RSpec.describe QuickActions::InterpretService do
end
it 'returns the unassign message for all the assignee if content contains /unassign' do
- issue.update(assignee_ids: [developer.id, developer2.id])
+ issue.update!(assignee_ids: [developer.id, developer2.id])
_, _, message = service.execute(content, issue)
expect(message).to eq("Removed assignees #{developer.to_reference} and #{developer2.to_reference}.")
@@ -860,7 +862,7 @@ RSpec.describe QuickActions::InterpretService do
end
it 'returns the unassign message for all the assignee if content contains /unassign' do
- merge_request.update(assignee_ids: [developer.id, developer2.id])
+ merge_request.update!(assignee_ids: [developer.id, developer2.id])
_, _, message = service.execute(content, merge_request)
expect(message).to eq("Removed assignees #{developer.to_reference} and #{developer2.to_reference}.")
@@ -879,10 +881,14 @@ RSpec.describe QuickActions::InterpretService do
end
context 'only group milestones available' do
- let(:ancestor_group) { create(:group) }
- let(:group) { create(:group, parent: ancestor_group) }
- let(:project) { create(:project, :public, namespace: group) }
- let(:milestone) { create(:milestone, group: ancestor_group, title: '10.0') }
+ let_it_be(:ancestor_group) { create(:group) }
+ let_it_be(:group) { create(:group, parent: ancestor_group) }
+ let_it_be(:project) { create(:project, :public, namespace: group) }
+ let_it_be(:milestone) { create(:milestone, group: ancestor_group, title: '10.0') }
+
+ before_all do
+ project.add_developer(developer)
+ end
it_behaves_like 'milestone command' do
let(:content) { "/milestone %#{milestone.title}" }
@@ -1457,14 +1463,14 @@ RSpec.describe QuickActions::InterpretService do
end
context '/board_move command' do
- let(:todo) { create(:label, project: project, title: 'To Do') }
- let(:inreview) { create(:label, project: project, title: 'In Review') }
+ let_it_be(:todo) { create(:label, project: project, title: 'To Do') }
+ let_it_be(:inreview) { create(:label, project: project, title: 'In Review') }
let(:content) { %{/board_move ~"#{inreview.title}"} }
- let!(:board) { create(:board, project: project) }
- let!(:todo_list) { create(:list, board: board, label: todo) }
- let!(:inreview_list) { create(:list, board: board, label: inreview) }
- let!(:inprogress_list) { create(:list, board: board, label: inprogress) }
+ let_it_be(:board) { create(:board, project: project) }
+ let_it_be(:todo_list) { create(:list, board: board, label: todo) }
+ let_it_be(:inreview_list) { create(:list, board: board, label: inreview) }
+ let_it_be(:inprogress_list) { create(:list, board: board, label: inprogress) }
it 'populates remove_label_ids for all current board columns' do
issue.update!(label_ids: [todo.id, inprogress.id])
@@ -1599,6 +1605,10 @@ RSpec.describe QuickActions::InterpretService do
context "when logged user cannot create_merge_requests in the project" do
let(:project) { create(:project, :archived) }
+ before do
+ project.add_developer(developer)
+ end
+
it_behaves_like 'empty command'
end
@@ -1844,8 +1854,7 @@ RSpec.describe QuickActions::InterpretService do
end
describe 'relabel command' do
- let(:content) { '/relabel Bug' }
- let!(:bug) { create(:label, project: project, title: 'Bug') }
+ let(:content) { "/relabel #{bug.title}" }
let(:feature) { create(:label, project: project, title: 'Feature') }
it 'includes label name' do
@@ -1938,8 +1947,7 @@ RSpec.describe QuickActions::InterpretService do
end
describe 'board move command' do
- let(:content) { '/board_move ~bug' }
- let!(:bug) { create(:label, project: project, title: 'bug') }
+ let(:content) { "/board_move ~#{bug.title}" }
let!(:board) { create(:board, project: project) }
it 'includes the label name' do
diff --git a/spec/services/repositories/destroy_service_spec.rb b/spec/services/repositories/destroy_service_spec.rb
index 30ec84b44e7..81bda2130a6 100644
--- a/spec/services/repositories/destroy_service_spec.rb
+++ b/spec/services/repositories/destroy_service_spec.rb
@@ -9,7 +9,7 @@ RSpec.describe Repositories::DestroyService do
let(:path) { repository.disk_path }
let(:remove_path) { "#{path}+#{project.id}#{described_class::DELETED_FLAG}" }
- subject { described_class.new(project.repository).execute }
+ subject { described_class.new(repository).execute }
it 'moves the repository to a +deleted folder' do
expect(project.gitlab_shell.repository_exists?(project.repository_storage, path + '.git')).to be_truthy
@@ -92,4 +92,22 @@ RSpec.describe Repositories::DestroyService do
service.execute
end
end
+
+ context 'with a project wiki repository' do
+ let(:project) { create(:project, :wiki_repo) }
+ let(:repository) { project.wiki.repository }
+
+ it 'schedules the repository deletion' do
+ subject
+
+ expect(Repositories::ShellDestroyService).to receive(:new).with(repository).and_call_original
+
+ expect(GitlabShellWorker).to receive(:perform_in)
+ .with(Repositories::ShellDestroyService::REPO_REMOVAL_DELAY, :remove_repository, project.repository_storage, remove_path)
+
+ # Because GitlabShellWorker is inside a run_after_commit callback we need to
+ # trigger the callback
+ project.touch
+ end
+ end
end
diff --git a/spec/services/repository_archive_clean_up_service_spec.rb b/spec/services/repository_archive_clean_up_service_spec.rb
index c6d673fb1b5..8db1a6858fa 100644
--- a/spec/services/repository_archive_clean_up_service_spec.rb
+++ b/spec/services/repository_archive_clean_up_service_spec.rb
@@ -18,6 +18,16 @@ RSpec.describe RepositoryArchiveCleanUpService do
end
end
+ it 'removes outdated archives and directories in a versioned path' do
+ in_directory_with_files("project-#{non_existing_record_id}/#{sha}/@v2", %w[tar tar.bz2 tar.gz zip], 3.hours) do |dirname, files|
+ service.execute
+
+ files.each { |filename| expect(File.exist?(filename)).to be_falsy }
+ expect(File.directory?(dirname)).to be_falsy
+ expect(File.directory?(File.dirname(dirname))).to be_falsy
+ end
+ end
+
it 'does not remove directories when they contain outdated non-archives' do
in_directory_with_files("project-#{non_existing_record_id}/#{sha}", %w[tar conf rb], 2.hours) do |dirname, files|
service.execute
@@ -64,7 +74,9 @@ RSpec.describe RepositoryArchiveCleanUpService do
end
it 'removes files older than 2 hours that matches valid archive extensions' do
- in_directory_with_files('sample.git', %w[tar tar.bz2 tar.gz zip], 2.hours) do |dir, files|
+ # In macOS, the the `mmin` parameter for `find` rounds up, so add a full
+ # minute to ensure these files are deemed old.
+ in_directory_with_files('sample.git', %w[tar tar.bz2 tar.gz zip], 121.minutes) do |dir, files|
service.execute
files.each { |file| expect(File.exist?(file)).to eq false }
@@ -73,11 +85,11 @@ RSpec.describe RepositoryArchiveCleanUpService do
end
context 'with files older than 2 hours that does not matches valid archive extensions' do
- it_behaves_like 'invalid archive files', 'sample.git', %w[conf rb], 2.hours
+ it_behaves_like 'invalid archive files', 'sample.git', %w[conf rb], 121.minutes
end
context 'with files older than 2 hours inside invalid directories' do
- it_behaves_like 'invalid archive files', 'john/doe/sample.git', %w[conf rb tar tar.gz], 2.hours
+ it_behaves_like 'invalid archive files', 'john/t/doe/sample.git', %w[conf rb tar tar.gz], 121.minutes
end
context 'with files newer than 2 hours that matches valid archive extensions' do
@@ -110,8 +122,6 @@ RSpec.describe RepositoryArchiveCleanUpService do
def create_temporary_files(dir, extensions, mtime)
FileUtils.mkdir_p(dir)
- # rubocop: disable Rails/TimeZone
- FileUtils.touch(extensions.map { |ext| File.join(dir, "sample.#{ext}") }, mtime: Time.now - mtime)
- # rubocop: enable Rails/TimeZone
+ FileUtils.touch(extensions.map { |ext| File.join(dir, "sample.#{ext}") }, mtime: Time.now.utc - mtime)
end
end
diff --git a/spec/services/resource_access_tokens/create_service_spec.rb b/spec/services/resource_access_tokens/create_service_spec.rb
index 7dbd55a6909..d8b12cda632 100644
--- a/spec/services/resource_access_tokens/create_service_spec.rb
+++ b/spec/services/resource_access_tokens/create_service_spec.rb
@@ -24,26 +24,6 @@ RSpec.describe ResourceAccessTokens::CreateService do
end
end
- shared_examples 'fails when flag is disabled' do
- before do
- stub_feature_flags(resource_access_token: false)
- end
-
- it 'returns nil' do
- expect(subject).to be nil
- end
- end
-
- shared_examples 'fails on gitlab.com' do
- before do
- allow(Gitlab).to receive(:com?) { true }
- end
-
- it 'returns nil' do
- expect(subject).to be nil
- end
- end
-
shared_examples 'allows creation of bot with valid params' do
it { expect { subject }.to change { User.count }.by(1) }
@@ -53,6 +33,7 @@ RSpec.describe ResourceAccessTokens::CreateService do
access_token = response.payload[:access_token]
expect(access_token.user.reload.user_type).to eq("#{resource_type}_bot")
+ expect(access_token.user.created_by_id).to eq(user.id)
end
context 'email confirmation status' do
@@ -77,8 +58,8 @@ RSpec.describe ResourceAccessTokens::CreateService do
end
context 'bot name' do
- context 'when no value is passed' do
- it 'uses default value' do
+ context 'when no name is passed' do
+ it 'uses default name' do
response = subject
access_token = response.payload[:access_token]
@@ -86,10 +67,10 @@ RSpec.describe ResourceAccessTokens::CreateService do
end
end
- context 'when user provides value' do
+ context 'when user provides name' do
let_it_be(:params) { { name: 'Random bot' } }
- it 'overrides the default value' do
+ it 'overrides the default name value' do
response = subject
access_token = response.payload[:access_token]
@@ -121,7 +102,7 @@ RSpec.describe ResourceAccessTokens::CreateService do
context 'when user provides scope explicitly' do
let_it_be(:params) { { scopes: Gitlab::Auth::REPOSITORY_SCOPES } }
- it 'overrides the default value' do
+ it 'overrides the default scope value' do
response = subject
access_token = response.payload[:access_token]
@@ -130,24 +111,44 @@ RSpec.describe ResourceAccessTokens::CreateService do
end
context 'expires_at' do
- context 'when no value is passed' do
- it 'uses default value' do
+ context 'when no expiration value is passed' do
+ it 'uses nil expiration value' do
response = subject
access_token = response.payload[:access_token]
expect(access_token.expires_at).to eq(nil)
end
+
+ context 'expiry of the project bot member' do
+ it 'project bot membership does not expire' do
+ response = subject
+ access_token = response.payload[:access_token]
+ project_bot = access_token.user
+
+ expect(project.members.find_by(user_id: project_bot.id).expires_at).to eq(nil)
+ end
+ end
end
- context 'when user provides value' do
+ context 'when user provides expiration value' do
let_it_be(:params) { { expires_at: Date.today + 1.month } }
- it 'overrides the default value' do
+ it 'overrides the default expiration value' do
response = subject
access_token = response.payload[:access_token]
expect(access_token.expires_at).to eq(params[:expires_at])
end
+
+ context 'expiry of the project bot member' do
+ it 'sets the project bot to expire on the same day as the token' do
+ response = subject
+ access_token = response.payload[:access_token]
+ project_bot = access_token.user
+
+ expect(project.members.find_by(user_id: project_bot.id).expires_at).to eq(params[:expires_at])
+ end
+ end
end
context 'when invalid scope is passed' do
@@ -164,7 +165,7 @@ RSpec.describe ResourceAccessTokens::CreateService do
context 'when access provisioning fails' do
before do
- allow(resource).to receive(:add_maintainer).and_return(nil)
+ allow(resource).to receive(:add_user).and_return(nil)
end
it 'returns error' do
@@ -180,8 +181,6 @@ RSpec.describe ResourceAccessTokens::CreateService do
let_it_be(:resource) { project }
it_behaves_like 'fails when user does not have the permission to create a Resource Bot'
- it_behaves_like 'fails when flag is disabled'
- it_behaves_like 'fails on gitlab.com'
context 'user with valid permission' do
before_all do
diff --git a/spec/services/resource_access_tokens/revoke_service_spec.rb b/spec/services/resource_access_tokens/revoke_service_spec.rb
index ffc06d770f8..af29ee2a721 100644
--- a/spec/services/resource_access_tokens/revoke_service_spec.rb
+++ b/spec/services/resource_access_tokens/revoke_service_spec.rb
@@ -8,17 +8,17 @@ RSpec.describe ResourceAccessTokens::RevokeService do
let_it_be(:user) { create(:user) }
let(:access_token) { create(:personal_access_token, user: resource_bot) }
- describe '#execute' do
+ describe '#execute', :sidekiq_inline do
# Created shared_examples as it will easy to include specs for group bots in https://gitlab.com/gitlab-org/gitlab/-/issues/214046
shared_examples 'revokes access token' do
it { expect(subject.success?).to be true }
- it { expect(subject.message).to eq("Revoked access token: #{access_token.name}") }
+ it { expect(subject.message).to eq("Access token #{access_token.name} has been revoked and the bot user has been scheduled for deletion.") }
- it 'revokes token access' do
- subject
+ it 'calls delete user worker' do
+ expect(DeleteUserWorker).to receive(:perform_async).with(user.id, resource_bot.id, skip_authorization: true)
- expect(access_token.reload.revoked?).to be true
+ subject
end
it 'removes membership of bot user' do
@@ -34,6 +34,12 @@ RSpec.describe ResourceAccessTokens::RevokeService do
expect(issue.reload.author.ghost?).to be true
end
+
+ it 'deletes project bot user' do
+ subject
+
+ expect(User.exists?(resource_bot.id)).to be_falsy
+ end
end
shared_examples 'rollback revoke steps' do
@@ -56,49 +62,71 @@ RSpec.describe ResourceAccessTokens::RevokeService do
expect(issue.reload.author.ghost?).to be false
end
+
+ it 'does not destroy project bot user' do
+ subject
+
+ expect(User.exists?(resource_bot.id)).to be_truthy
+ end
end
context 'when resource is a project' do
let_it_be(:resource) { create(:project, :private) }
- let_it_be(:resource_bot) { create(:user, :project_bot) }
+ let(:resource_bot) { create(:user, :project_bot) }
- before_all do
+ before do
resource.add_maintainer(user)
resource.add_maintainer(resource_bot)
end
it_behaves_like 'revokes access token'
- context 'when revoke fails' do
- context 'invalid resource type' do
- subject { described_class.new(user, resource, access_token).execute }
+ context 'revoke fails' do
+ let_it_be(:other_user) { create(:user) }
- let_it_be(:resource) { double }
- let_it_be(:resource_bot) { create(:user, :project_bot) }
+ context 'when access token does not belong to this project' do
+ it 'does not find the bot' do
+ other_access_token = create(:personal_access_token, user: other_user)
- it 'returns error response' do
- response = subject
+ response = described_class.new(user, resource, other_access_token).execute
expect(response.success?).to be false
expect(response.message).to eq("Failed to find bot user")
+ expect(access_token.reload.revoked?).to be false
end
-
- it { expect { subject }.not_to change(access_token.reload, :revoked) }
end
- context 'when migration to ghost user fails' do
- before do
- allow_next_instance_of(::Members::DestroyService) do |service|
- allow(service).to receive(:execute).and_return(false)
+ context 'when user does not have permission to destroy bot' do
+ context 'when non-project member tries to delete project bot' do
+ it 'does not allow other user to delete bot' do
+ response = described_class.new(other_user, resource, access_token).execute
+
+ expect(response.success?).to be false
+ expect(response.message).to eq("#{other_user.name} cannot delete #{access_token.user.name}")
+ expect(access_token.reload.revoked?).to be false
end
end
- it_behaves_like 'rollback revoke steps'
+ context 'when non-maintainer project member tries to delete project bot' do
+ let(:developer) { create(:user) }
+
+ before do
+ resource.add_developer(developer)
+ end
+
+ it 'does not allow developer to delete bot' do
+ response = described_class.new(developer, resource, access_token).execute
+
+ expect(response.success?).to be false
+ expect(response.message).to eq("#{developer.name} cannot delete #{access_token.user.name}")
+ expect(access_token.reload.revoked?).to be false
+ end
+ end
end
- context 'when migration to ghost user fails' do
+ context 'when deletion of bot user fails' do
before do
- allow_next_instance_of(::Users::MigrateToGhostUserService) do |service|
+ allow_next_instance_of(::ResourceAccessTokens::RevokeService) do |service|
allow(service).to receive(:execute).and_return(false)
end
end
diff --git a/spec/services/search/global_service_spec.rb b/spec/services/search/global_service_spec.rb
index 90ad18e5571..7b914a4d3d6 100644
--- a/spec/services/search/global_service_spec.rb
+++ b/spec/services/search/global_service_spec.rb
@@ -52,4 +52,34 @@ RSpec.describe Search::GlobalService do
end
end
end
+
+ context 'issues' do
+ let(:scope) { 'issues' }
+
+ context 'sort by created_at' do
+ let!(:project) { create(:project, :public) }
+ let!(:old_result) { create(:issue, project: project, title: 'sorted old', created_at: 1.month.ago) }
+ let!(:new_result) { create(:issue, project: project, title: 'sorted recent', created_at: 1.day.ago) }
+ let!(:very_old_result) { create(:issue, project: project, title: 'sorted very old', created_at: 1.year.ago) }
+
+ include_examples 'search results sorted' do
+ let(:results) { described_class.new(nil, search: 'sorted', sort: sort).execute }
+ end
+ end
+ end
+
+ context 'merge_request' do
+ let(:scope) { 'merge_requests' }
+
+ context 'sort by created_at' do
+ let!(:project) { create(:project, :public) }
+ let!(:old_result) { create(:merge_request, :opened, source_project: project, source_branch: 'old-1', title: 'sorted old', created_at: 1.month.ago) }
+ let!(:new_result) { create(:merge_request, :opened, source_project: project, source_branch: 'new-1', title: 'sorted recent', created_at: 1.day.ago) }
+ let!(:very_old_result) { create(:merge_request, :opened, source_project: project, source_branch: 'very-old-1', title: 'sorted very old', created_at: 1.year.ago) }
+
+ include_examples 'search results sorted' do
+ let(:results) { described_class.new(nil, search: 'sorted', sort: sort).execute }
+ end
+ end
+ end
end
diff --git a/spec/services/search/group_service_spec.rb b/spec/services/search/group_service_spec.rb
index d3026d158d4..2bfe714f393 100644
--- a/spec/services/search/group_service_spec.rb
+++ b/spec/services/search/group_service_spec.rb
@@ -40,4 +40,36 @@ RSpec.describe Search::GroupService do
describe 'basic search' do
include_examples 'group search'
end
+
+ context 'issues' do
+ let(:scope) { 'issues' }
+
+ context 'sort by created_at' do
+ let!(:group) { create(:group) }
+ let!(:project) { create(:project, :public, group: group) }
+ let!(:old_result) { create(:issue, project: project, title: 'sorted old', created_at: 1.month.ago) }
+ let!(:new_result) { create(:issue, project: project, title: 'sorted recent', created_at: 1.day.ago) }
+ let!(:very_old_result) { create(:issue, project: project, title: 'sorted very old', created_at: 1.year.ago) }
+
+ include_examples 'search results sorted' do
+ let(:results) { described_class.new(nil, group, search: 'sorted', sort: sort).execute }
+ end
+ end
+ end
+
+ context 'merge requests' do
+ let(:scope) { 'merge_requests' }
+
+ context 'sort by created_at' do
+ let!(:group) { create(:group) }
+ let!(:project) { create(:project, :public, group: group) }
+ let!(:old_result) { create(:merge_request, :opened, source_project: project, source_branch: 'old-1', title: 'sorted old', created_at: 1.month.ago) }
+ let!(:new_result) { create(:merge_request, :opened, source_project: project, source_branch: 'new-1', title: 'sorted recent', created_at: 1.day.ago) }
+ let!(:very_old_result) { create(:merge_request, :opened, source_project: project, source_branch: 'very-old-1', title: 'sorted very old', created_at: 1.year.ago) }
+
+ include_examples 'search results sorted' do
+ let(:results) { described_class.new(nil, group, search: 'sorted', sort: sort).execute }
+ end
+ end
+ end
end
diff --git a/spec/services/search_service_spec.rb b/spec/services/search_service_spec.rb
index f6bb7acee57..fc613a6224a 100644
--- a/spec/services/search_service_spec.rb
+++ b/spec/services/search_service_spec.rb
@@ -444,7 +444,7 @@ RSpec.describe SearchService do
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: 7
+ it_behaves_like "redaction limits N+1 queries", limit: 8
end
end
@@ -481,7 +481,7 @@ RSpec.describe SearchService do
end
context 'with :with_api_entity_associations' do
- it_behaves_like "redaction limits N+1 queries", limit: 12
+ it_behaves_like "redaction limits N+1 queries", limit: 13
end
end
@@ -496,7 +496,7 @@ RSpec.describe SearchService do
end
context 'with :with_api_entity_associations' do
- it_behaves_like "redaction limits N+1 queries", limit: 3
+ it_behaves_like "redaction limits N+1 queries", limit: 4
end
end
diff --git a/spec/services/snippets/repository_validation_service_spec.rb b/spec/services/snippets/repository_validation_service_spec.rb
index e2a0d0faa18..8166ce144e1 100644
--- a/spec/services/snippets/repository_validation_service_spec.rb
+++ b/spec/services/snippets/repository_validation_service_spec.rb
@@ -40,7 +40,7 @@ RSpec.describe Snippets::RepositoryValidationService do
end
it 'returns error when the repository has more file than the limit' do
- limit = Snippet.max_file_limit(user) + 1
+ limit = Snippet.max_file_limit + 1
files = Array.new(limit) { FFaker::Filesystem.file_name }
allow(repository).to receive(:ls_files).and_return(files)
@@ -56,7 +56,9 @@ RSpec.describe Snippets::RepositoryValidationService do
end
it 'returns error when the repository size is over the limit' do
- expect_any_instance_of(Gitlab::RepositorySizeChecker).to receive(:above_size_limit?).and_return(true)
+ expect_next_instance_of(Gitlab::RepositorySizeChecker) do |checker|
+ expect(checker).to receive(:above_size_limit?).and_return(true)
+ end
expect(subject).to be_error
expect(subject.message).to match /Repository size is above the limit/
diff --git a/spec/services/snippets/update_service_spec.rb b/spec/services/snippets/update_service_spec.rb
index 641fc56294a..406ece30bd7 100644
--- a/spec/services/snippets/update_service_spec.rb
+++ b/spec/services/snippets/update_service_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe Snippets::UpdateService do
- describe '#execute' do
+ describe '#execute', :aggregate_failures do
let_it_be(:user) { create(:user) }
let_it_be(:admin) { create :user, admin: true }
let(:visibility_level) { Gitlab::VisibilityLevel::PRIVATE }
@@ -97,40 +97,81 @@ RSpec.describe Snippets::UpdateService do
end
shared_examples 'creates repository and creates file' do
- it 'creates repository' do
- expect(snippet.repository).not_to exist
+ context 'when file_name and content params are used' do
+ it 'creates repository' do
+ expect(snippet.repository).not_to exist
- subject
+ subject
- expect(snippet.repository).to exist
- end
+ expect(snippet.repository).to exist
+ end
- it 'commits the files to the repository' do
- subject
+ it 'commits the files to the repository' do
+ subject
- expect(snippet.blobs.count).to eq 1
+ expect(snippet.blobs.count).to eq 1
- blob = snippet.repository.blob_at('master', options[:file_name])
+ blob = snippet.repository.blob_at('master', options[:file_name])
- expect(blob.data).to eq options[:content]
+ expect(blob.data).to eq options[:content]
+ end
+
+ context 'when the repository creation fails' do
+ before do
+ allow(snippet).to receive(:repository_exists?).and_return(false)
+ end
+
+ it 'raise an error' do
+ expect(subject).to be_error
+ expect(subject.payload[:snippet].errors[:repository].to_sentence).to eq 'Error updating the snippet - Repository could not be created'
+ end
+
+ it 'does not try to commit file' do
+ expect(service).not_to receive(:create_commit)
+
+ subject
+ end
+ end
end
- context 'when the repository creation fails' do
- before do
- allow(snippet).to receive(:repository_exists?).and_return(false)
+ context 'when snippet_actions param is used' do
+ let(:file_path) { 'CHANGELOG' }
+ let(:created_file_path) { 'New file'}
+ let(:content) { 'foobar' }
+ let(:snippet_actions) { [{ action: :move, previous_path: snippet.file_name, file_path: file_path }, { action: :create, file_path: created_file_path, content: content }] }
+ let(:base_opts) do
+ {
+ snippet_actions: snippet_actions
+ }
end
- it 'raise an error' do
- response = subject
+ it 'performs operation without raising errors' do
+ db_content = snippet.content
- expect(response).to be_error
- expect(response.payload[:snippet].errors[:repository].to_sentence).to eq 'Error updating the snippet - Repository could not be created'
+ expect(subject).to be_success
+
+ new_blob = snippet.repository.blob_at('master', file_path)
+ created_file = snippet.repository.blob_at('master', created_file_path)
+
+ expect(new_blob.data).to eq db_content
+ expect(created_file.data).to eq content
end
- it 'does not try to commit file' do
- expect(service).not_to receive(:create_commit)
+ context 'when the repository is not created' do
+ it 'keeps snippet database data' do
+ old_file_name = snippet.file_name
+ old_file_content = snippet.content
- subject
+ expect_next_instance_of(described_class) do |instance|
+ expect(instance).to receive(:create_repository_for).and_raise(StandardError)
+ end
+
+ snippet = subject.payload[:snippet]
+
+ expect(subject).to be_error
+ expect(snippet.file_name).to eq(old_file_name)
+ expect(snippet.content).to eq(old_file_content)
+ end
end
end
end
@@ -366,10 +407,9 @@ RSpec.describe Snippets::UpdateService do
let(:snippet_actions) { [{ action: 'invalid_action' }] }
it 'raises a validation error' do
- response = subject
- snippet = response.payload[:snippet]
+ snippet = subject.payload[:snippet]
- expect(response).to be_error
+ expect(subject).to be_error
expect(snippet.errors.full_messages_for(:snippet_actions)).to eq ['Snippet actions have invalid data']
end
end
@@ -377,13 +417,12 @@ RSpec.describe Snippets::UpdateService do
context 'when an error is raised committing the file' do
it 'keeps any snippet modifications' do
expect_next_instance_of(described_class) do |instance|
- expect(instance).to receive(:create_repository_for).and_raise(StandardError)
+ expect(instance).to receive(:create_commit).and_raise(StandardError)
end
- response = subject
- snippet = response.payload[:snippet]
+ snippet = subject.payload[:snippet]
- expect(response).to be_error
+ expect(subject).to be_error
expect(snippet.title).to eq(new_title)
expect(snippet.file_name).to eq(file_path)
expect(snippet.content).to eq(content)
diff --git a/spec/services/static_site_editor/config_service_spec.rb b/spec/services/static_site_editor/config_service_spec.rb
index 5fff4e0af53..fed373828a1 100644
--- a/spec/services/static_site_editor/config_service_spec.rb
+++ b/spec/services/static_site_editor/config_service_spec.rb
@@ -7,8 +7,8 @@ RSpec.describe StaticSiteEditor::ConfigService do
let_it_be(:user) { create(:user) }
# params
- let(:ref) { double(:ref) }
- let(:path) { double(:path) }
+ let(:ref) { 'master' }
+ let(:path) { 'README.md' }
let(:return_url) { double(:return_url) }
# stub data
@@ -42,22 +42,84 @@ RSpec.describe StaticSiteEditor::ConfigService do
allow_next_instance_of(Gitlab::StaticSiteEditor::Config::GeneratedConfig) do |config|
allow(config).to receive(:data) { generated_data }
end
+ end
+
+ context 'when reading file from repo fails with an unexpected error' do
+ let(:unexpected_error) { RuntimeError.new('some unexpected error') }
- allow_next_instance_of(Gitlab::StaticSiteEditor::Config::FileConfig) do |config|
- allow(config).to receive(:data) { file_data }
+ before do
+ allow(project.repository).to receive(:blob_data_at).and_raise(unexpected_error)
+ end
+
+ it 'returns an error response' do
+ expect(Gitlab::ErrorTracking).to receive(:track_and_raise_exception).with(unexpected_error).and_call_original
+ expect { execute }.to raise_error(unexpected_error)
end
end
- it 'returns merged generated data and config file data' do
- expect(execute).to be_success
- expect(execute.payload).to eq(generated: true, file: true)
+ context 'when file is missing' do
+ before do
+ allow(project.repository).to receive(:blob_data_at).and_raise(GRPC::NotFound)
+ expect_next_instance_of(Gitlab::StaticSiteEditor::Config::FileConfig, '{}') do |config|
+ allow(config).to receive(:valid?) { true }
+ allow(config).to receive(:to_hash_with_defaults) { file_data }
+ end
+ end
+
+ it 'returns default config' do
+ expect(execute).to be_success
+ expect(execute.payload).to eq(generated: true, file: true)
+ end
end
- it 'returns an error if any keys would be overwritten by the merge' do
- generated_data[:duplicate_key] = true
- file_data[:duplicate_key] = true
- expect(execute).to be_error
- expect(execute.message).to match(/duplicate key.*duplicate_key.*found/i)
+ context 'when file is present' do
+ before do
+ allow(project.repository).to receive(:blob_data_at).with(ref, anything) do
+ config_content
+ end
+ end
+
+ context 'and configuration is not valid' do
+ let(:config_content) { 'invalid content' }
+
+ before do
+ expect_next_instance_of(Gitlab::StaticSiteEditor::Config::FileConfig, config_content) do |config|
+ error = 'error'
+ allow(config).to receive_message_chain('errors.first') { error }
+ allow(config).to receive(:valid?) { false }
+ end
+ end
+
+ it 'returns an error' do
+ expect(execute).to be_error
+ expect(execute.message).to eq('Invalid configuration format')
+ end
+ end
+
+ context 'and configuration is valid' do
+ # NOTE: This has to be a valid config, even though it is mocked, because
+ # `expect_next_instance_of` executes the constructor logic.
+ let(:config_content) { 'static_site_generator: middleman' }
+
+ before do
+ expect_next_instance_of(Gitlab::StaticSiteEditor::Config::FileConfig, config_content) do |config|
+ allow(config).to receive(:valid?) { true }
+ allow(config).to receive(:to_hash_with_defaults) { file_data }
+ end
+ end
+
+ it 'returns merged generated data and config file data' do
+ expect(execute).to be_success
+ expect(execute.payload).to eq(generated: true, file: true)
+ end
+
+ it 'returns an error if any keys would be overwritten by the merge' do
+ generated_data[:duplicate_key] = true
+ file_data[:duplicate_key] = true
+ expect(execute).to be_error
+ expect(execute.message).to match(/duplicate key.*duplicate_key.*found/i)
+ end
+ end
end
end
end
diff --git a/spec/services/system_note_service_spec.rb b/spec/services/system_note_service_spec.rb
index 47b8621b5c9..42e48b9ad81 100644
--- a/spec/services/system_note_service_spec.rb
+++ b/spec/services/system_note_service_spec.rb
@@ -64,6 +64,18 @@ RSpec.describe SystemNoteService do
end
end
+ describe '.change_issuable_reviewers' do
+ let(:reviewers) { [double, double] }
+
+ it 'calls IssuableService' do
+ expect_next_instance_of(::SystemNotes::IssuablesService) do |service|
+ expect(service).to receive(:change_issuable_reviewers).with(reviewers)
+ end
+
+ described_class.change_issuable_reviewers(noteable, project, author, reviewers)
+ end
+ end
+
describe '.close_after_error_tracking_resolve' do
it 'calls IssuableService' do
expect_next_instance_of(::SystemNotes::IssuablesService) do |service|
@@ -741,4 +753,16 @@ RSpec.describe SystemNoteService do
described_class.create_new_alert(alert, monitoring_tool)
end
end
+
+ describe '.change_incident_severity' do
+ let(:incident) { build(:incident) }
+
+ it 'calls IncidentService' do
+ expect_next_instance_of(SystemNotes::IncidentService) do |service|
+ expect(service).to receive(:change_incident_severity)
+ end
+
+ described_class.change_incident_severity(incident, author)
+ end
+ end
end
diff --git a/spec/services/system_notes/incident_service_spec.rb b/spec/services/system_notes/incident_service_spec.rb
new file mode 100644
index 00000000000..ab9b9eb2bd4
--- /dev/null
+++ b/spec/services/system_notes/incident_service_spec.rb
@@ -0,0 +1,59 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe ::SystemNotes::IncidentService do
+ let_it_be(:author) { create(:user) }
+ let_it_be(:project) { create(:project) }
+ let_it_be(:noteable) { create(:incident, project: project) }
+ let_it_be(:issuable_severity) { create(:issuable_severity, issue: noteable, severity: :medium) }
+
+ describe '#change_incident_severity' do
+ subject(:change_severity) { described_class.new(noteable: noteable, project: project, author: author).change_incident_severity }
+
+ before do
+ allow(Gitlab::AppLogger).to receive(:error).and_call_original
+ end
+
+ it_behaves_like 'a system note' do
+ let(:action) { 'severity' }
+ end
+
+ IssuableSeverity.severities.keys.each do |severity|
+ context "with #{severity} severity" do
+ before do
+ issuable_severity.update!(severity: severity)
+ end
+
+ it 'has the appropriate message' do
+ severity_label = IssuableSeverity::SEVERITY_LABELS.fetch(severity.to_sym)
+
+ expect(change_severity.note).to eq("changed the severity to **#{severity_label}**")
+ end
+ end
+ end
+
+ context 'when severity is invalid' do
+ let(:invalid_severity) { 'invalid-severity' }
+
+ before do
+ allow(noteable).to receive(:severity).and_return(invalid_severity)
+ end
+
+ it 'does not create system note' do
+ expect { change_severity }.not_to change { noteable.notes.count }
+ end
+
+ it 'writes error to logs' do
+ change_severity
+
+ expect(Gitlab::AppLogger).to have_received(:error).with(
+ message: 'Cannot create a system note for severity change',
+ noteable_class: noteable.class.to_s,
+ noteable_id: noteable.id,
+ severity: invalid_severity
+ )
+ end
+ end
+ end
+end
diff --git a/spec/services/system_notes/issuables_service_spec.rb b/spec/services/system_notes/issuables_service_spec.rb
index fec2a711dc2..e78b00fb67a 100644
--- a/spec/services/system_notes/issuables_service_spec.rb
+++ b/spec/services/system_notes/issuables_service_spec.rb
@@ -128,49 +128,76 @@ RSpec.describe ::SystemNotes::IssuablesService do
end
end
- describe '#change_status' do
- subject { service.change_status(status, source) }
+ describe '#change_issuable_reviewers' do
+ subject { service.change_issuable_reviewers([reviewer]) }
- context 'when resource state event tracking is enabled' do
- let(:status) { 'reopened' }
- let(:source) { nil }
+ let_it_be(:noteable) { create(:merge_request, :simple, source_project: project) }
+ let_it_be(:reviewer) { create(:user) }
+ let_it_be(:reviewer1) { create(:user) }
+ let_it_be(:reviewer2) { create(:user) }
+ let_it_be(:reviewer3) { create(:user) }
- it 'does not change note count' do
- expect { subject }.not_to change { Note.count }
- end
+ it_behaves_like 'a system note' do
+ let(:action) { 'reviewer' }
end
- context 'with status reopened' do
- before do
- stub_feature_flags(track_resource_state_change_events: false)
- end
+ def build_note(old_reviewers, new_reviewers)
+ noteable.reviewers = new_reviewers
+ service.change_issuable_reviewers(old_reviewers).note
+ end
- let(:status) { 'reopened' }
- let(:source) { nil }
+ it 'builds a correct phrase when a reviewer is added to a non-assigned merge request' do
+ expect(build_note([], [reviewer1])).to eq "requested review from @#{reviewer1.username}"
+ end
- it_behaves_like 'a note with overridable created_at'
+ it 'builds a correct phrase when reviewer is removed' do
+ expect(build_note([reviewer], [])).to eq "removed review request for @#{reviewer.username}"
+ end
- it_behaves_like 'a system note' do
- let(:action) { 'opened' }
- end
+ it 'builds a correct phrase when reviewers changed' do
+ expect(build_note([reviewer1], [reviewer2])).to(
+ eq("requested review from @#{reviewer2.username} and removed review request for @#{reviewer1.username}")
+ )
end
- context 'with a source' do
- before do
- stub_feature_flags(track_resource_state_change_events: false)
- end
+ it 'builds a correct phrase when three reviewers removed and one added' do
+ expect(build_note([reviewer, reviewer1, reviewer2], [reviewer3])).to(
+ eq("requested review from @#{reviewer3.username} and removed review request for @#{reviewer.username}, @#{reviewer1.username}, and @#{reviewer2.username}")
+ )
+ end
- let(:status) { 'opened' }
- let(:source) { double('commit', gfm_reference: 'commit 123456') }
+ it 'builds a correct phrase when one reviewer is changed from a set' do
+ expect(build_note([reviewer, reviewer1], [reviewer, reviewer2])).to(
+ eq("requested review from @#{reviewer2.username} and removed review request for @#{reviewer1.username}")
+ )
+ end
- it_behaves_like 'a note with overridable created_at'
+ 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}")
+ )
+ end
- it 'sets the note text' do
- expect(subject.note).to eq "#{status} via commit 123456"
+ it 'builds a correct phrase when the locale is different' do
+ Gitlab::I18n.with_locale('pt-BR') do
+ expect(build_note([reviewer, reviewer1, reviewer2], [reviewer3])).to(
+ eq("requested review from @#{reviewer3.username} and removed review request for @#{reviewer.username}, @#{reviewer1.username}, and @#{reviewer2.username}")
+ )
end
end
end
+ describe '#change_status' do
+ subject { service.change_status(status, source) }
+
+ let(:status) { 'reopened' }
+ let(:source) { nil }
+
+ it 'creates a resource state event' do
+ expect { subject }.to change { ResourceStateEvent.count }.by(1)
+ end
+ end
+
describe '#change_title' do
let(:noteable) { create(:issue, project: project, title: 'Lorem ipsum') }
@@ -636,67 +663,26 @@ RSpec.describe ::SystemNotes::IssuablesService do
describe '#close_after_error_tracking_resolve' do
subject { service.close_after_error_tracking_resolve }
- context 'when state tracking is enabled' do
- before do
- stub_feature_flags(track_resource_state_change_events: true)
- end
-
- it 'creates the expected state event' do
- subject
-
- event = ResourceStateEvent.last
-
- expect(event.close_after_error_tracking_resolve).to eq(true)
- expect(event.state).to eq('closed')
- end
- end
+ it 'creates the expected state event' do
+ subject
- context 'when state tracking is disabled' do
- before do
- stub_feature_flags(track_resource_state_change_events: false)
- end
+ event = ResourceStateEvent.last
- it_behaves_like 'a system note' do
- let(:action) { 'closed' }
- end
-
- it 'creates the expected system note' do
- expect(subject.note)
- .to eq('resolved the corresponding error and closed the issue.')
- end
+ expect(event.close_after_error_tracking_resolve).to eq(true)
+ expect(event.state).to eq('closed')
end
end
describe '#auto_resolve_prometheus_alert' do
subject { service.auto_resolve_prometheus_alert }
- context 'when state tracking is enabled' do
- before do
- stub_feature_flags(track_resource_state_change_events: true)
- end
+ it 'creates the expected state event' do
+ subject
- it 'creates the expected state event' do
- subject
+ event = ResourceStateEvent.last
- event = ResourceStateEvent.last
-
- expect(event.close_auto_resolve_prometheus_alert).to eq(true)
- expect(event.state).to eq('closed')
- end
- end
-
- context 'when state tracking is disabled' do
- before do
- stub_feature_flags(track_resource_state_change_events: false)
- end
-
- it_behaves_like 'a system note' do
- let(:action) { 'closed' }
- end
-
- it 'creates the expected system note' do
- expect(subject.note).to eq('automatically closed this issue because the alert resolved.')
- end
+ expect(event.close_auto_resolve_prometheus_alert).to eq(true)
+ expect(event.state).to eq('closed')
end
end
end
diff --git a/spec/services/system_notes/time_tracking_service_spec.rb b/spec/services/system_notes/time_tracking_service_spec.rb
index f671e66cdcd..ec126cb5447 100644
--- a/spec/services/system_notes/time_tracking_service_spec.rb
+++ b/spec/services/system_notes/time_tracking_service_spec.rb
@@ -6,124 +6,181 @@ RSpec.describe ::SystemNotes::TimeTrackingService do
let_it_be(:author) { create(:user) }
let_it_be(:project) { create(:project, :repository) }
- let(:noteable) { create(:issue, project: project) }
-
describe '#change_due_date' do
subject { described_class.new(noteable: noteable, project: project, author: author).change_due_date(due_date) }
let(:due_date) { Date.today }
- it_behaves_like 'a note with overridable created_at'
+ context 'when noteable is an issue' do
+ let_it_be(:noteable) { create(:issue, project: project) }
- it_behaves_like 'a system note' do
- let(:action) { 'due_date' }
- end
+ it_behaves_like 'a note with overridable created_at'
+
+ it_behaves_like 'a system note' do
+ let(:action) { 'due_date' }
+ end
- context 'when due date added' do
- it 'sets the note text' do
- expect(subject.note).to eq "changed due date to #{due_date.to_s(:long)}"
+ context 'when due date added' do
+ it 'sets the note text' do
+ expect(subject.note).to eq "changed due date to #{due_date.to_s(:long)}"
+ end
+ end
+
+ context 'when due date removed' do
+ let(:due_date) { nil }
+
+ it 'sets the note text' do
+ expect(subject.note).to eq 'removed due date'
+ end
+ end
+
+ it 'tracks the issue event in usage ping' do
+ expect(Gitlab::UsageDataCounters::IssueActivityUniqueCounter).to receive(:track_issue_due_date_changed_action).with(author: author)
+
+ subject
end
end
- context 'when due date removed' do
- let(:due_date) { nil }
+ context 'when noteable is a merge request' do
+ let_it_be(:noteable) { create(:merge_request, source_project: project) }
+
+ it 'does not track the issue event in usage ping' do
+ expect(Gitlab::UsageDataCounters::IssueActivityUniqueCounter).not_to receive(:track_issue_due_date_changed_action).with(author: author)
- it 'sets the note text' do
- expect(subject.note).to eq 'removed due date'
+ subject
end
end
end
- describe '.change_time_estimate' do
+ describe '#change_time_estimate' do
subject { described_class.new(noteable: noteable, project: project, author: author).change_time_estimate }
- it_behaves_like 'a system note' do
- let(:action) { 'time_tracking' }
- end
-
- context 'with a time estimate' do
- it 'sets the note text' do
- noteable.update_attribute(:time_estimate, 277200)
+ context 'when noteable is an issue' do
+ let_it_be(:noteable, reload: true) { create(:issue, project: project) }
- expect(subject.note).to eq "changed time estimate to 1w 4d 5h"
+ it_behaves_like 'a system note' do
+ let(:action) { 'time_tracking' }
end
- context 'when time_tracking_limit_to_hours setting is true' do
- before do
- stub_application_setting(time_tracking_limit_to_hours: true)
- end
-
+ context 'with a time estimate' do
it 'sets the note text' do
noteable.update_attribute(:time_estimate, 277200)
- expect(subject.note).to eq "changed time estimate to 77h"
+ expect(subject.note).to eq "changed time estimate to 1w 4d 5h"
+ end
+
+ context 'when time_tracking_limit_to_hours setting is true' do
+ before do
+ stub_application_setting(time_tracking_limit_to_hours: true)
+ end
+
+ it 'sets the note text' do
+ noteable.update_attribute(:time_estimate, 277200)
+
+ expect(subject.note).to eq "changed time estimate to 77h"
+ end
end
end
- end
- context 'without a time estimate' do
- it 'sets the note text' do
- expect(subject.note).to eq "removed time estimate"
+ context 'without a time estimate' do
+ it 'sets the note text' do
+ expect(subject.note).to eq "removed time estimate"
+ end
end
- end
- end
- describe '.change_time_spent' do
- # We need a custom noteable in order to the shared examples to be green.
- let(:noteable) do
- mr = create(:merge_request, source_project: project)
- mr.spend_time(duration: 360000, user_id: author.id)
- mr.save!
- mr
- end
+ it 'tracks the issue event in usage ping' do
+ expect(Gitlab::UsageDataCounters::IssueActivityUniqueCounter).to receive(:track_issue_time_estimate_changed_action).with(author: author)
- subject do
- described_class.new(noteable: noteable, project: project, author: author).change_time_spent
+ subject
+ end
end
- it_behaves_like 'a system note' do
- let(:action) { 'time_tracking' }
- end
+ context 'when noteable is a merge request' do
+ let_it_be(:noteable) { create(:merge_request, source_project: project) }
- context 'when time was added' do
- it 'sets the note text' do
- spend_time!(277200)
+ it 'does not track the issue event in usage ping' do
+ expect(Gitlab::UsageDataCounters::IssueActivityUniqueCounter).not_to receive(:track_issue_time_estimate_changed_action).with(author: author)
- expect(subject.note).to eq "added 1w 4d 5h of time spent"
+ subject
end
end
+ end
- context 'when time was subtracted' do
- it 'sets the note text' do
- spend_time!(-277200)
+ describe '#change_time_spent' do
+ subject { described_class.new(noteable: noteable, project: project, author: author).change_time_spent }
- expect(subject.note).to eq "subtracted 1w 4d 5h of time spent"
- end
- end
+ context 'when noteable is an issue' do
+ let_it_be(:noteable, reload: true) { create(:issue, project: project) }
- context 'when time was removed' do
- it 'sets the note text' do
- spend_time!(:reset)
+ it_behaves_like 'a system note' do
+ let(:action) { 'time_tracking' }
- expect(subject.note).to eq "removed time spent"
+ before do
+ spend_time!(277200)
+ end
end
- end
- context 'when time_tracking_limit_to_hours setting is true' do
- before do
- stub_application_setting(time_tracking_limit_to_hours: true)
+ context 'when time was added' do
+ it 'sets the note text' do
+ spend_time!(277200)
+
+ expect(subject.note).to eq "added 1w 4d 5h of time spent"
+ end
+
+ context 'when time was subtracted' do
+ it 'sets the note text' do
+ spend_time!(360000)
+ spend_time!(-277200)
+
+ expect(subject.note).to eq "subtracted 1w 4d 5h of time spent"
+ end
+ end
+
+ context 'when time was removed' do
+ it 'sets the note text' do
+ spend_time!(:reset)
+
+ expect(subject.note).to eq "removed time spent"
+ end
+ end
+
+ context 'when time_tracking_limit_to_hours setting is true' do
+ before do
+ stub_application_setting(time_tracking_limit_to_hours: true)
+ end
+
+ it 'sets the note text' do
+ spend_time!(277200)
+
+ expect(subject.note).to eq "added 77h of time spent"
+ end
+ end
+
+ it 'tracks the issue event in usage ping' do
+ expect(Gitlab::UsageDataCounters::IssueActivityUniqueCounter).to receive(:track_issue_time_spent_changed_action).with(author: author)
+
+ spend_time!(277200)
+
+ subject
+ end
end
- it 'sets the note text' do
- spend_time!(277200)
+ context 'when noteable is a merge request' do
+ let_it_be(:noteable) { create(:merge_request, source_project: project) }
+
+ it 'does not track the issue event in usage ping' do
+ expect(Gitlab::UsageDataCounters::IssueActivityUniqueCounter).not_to receive(:track_issue_time_estimate_changed_action).with(author: author)
+
+ spend_time!(277200)
- expect(subject.note).to eq "added 77h of time spent"
+ subject
+ end
end
- end
- def spend_time!(seconds)
- noteable.spend_time(duration: seconds, user_id: author.id)
- noteable.save!
+ def spend_time!(seconds)
+ noteable.spend_time(duration: seconds, user_id: author.id)
+ noteable.save!
+ end
end
end
end
diff --git a/spec/services/todos/destroy/entity_leave_service_spec.rb b/spec/services/todos/destroy/entity_leave_service_spec.rb
index 921037bd5db..4126eb88b0b 100644
--- a/spec/services/todos/destroy/entity_leave_service_spec.rb
+++ b/spec/services/todos/destroy/entity_leave_service_spec.rb
@@ -19,20 +19,14 @@ RSpec.describe Todos::Destroy::EntityLeaveService do
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) }
- shared_examples 'using different access permissions' do |access_table|
- using RSpec::Parameterized::TableSyntax
-
- where(:group_access, :project_access, :c_todos, :mr_todos, :method, &access_table)
-
- with_them do
- before do
- set_access(project, user, project_access) if project_access
- set_access(group, user, group_access) if group_access
- end
+ shared_examples 'using different access permissions' do
+ before do
+ set_access(project, user, project_access) if project_access
+ set_access(group, user, group_access) if group_access
+ end
- it "#{params[:method].to_s.humanize(capitalize: false)}" do
- send(method)
- end
+ it "#{params[:method].to_s.humanize(capitalize: false)}" do
+ send(method_name)
end
end
@@ -84,22 +78,20 @@ RSpec.describe Todos::Destroy::EntityLeaveService do
end
context 'access permissions' do
- # rubocop:disable RSpec/LeakyConstantDeclaration
- PRIVATE_PROJECT_PRIVATE_GROUP_ACCESS_TABLE =
- lambda do |_|
- [
- # :group_access, :project_access, :c_todos, :mr_todos, :method
- [nil, :reporter, :keep, :keep, :does_not_remove_any_todos],
- [nil, :guest, :delete, :delete, :removes_confidential_issues_and_merge_request_todos],
- [:reporter, nil, :keep, :keep, :does_not_remove_any_todos],
- [:guest, nil, :delete, :delete, :removes_confidential_issues_and_merge_request_todos],
- [:guest, :reporter, :keep, :keep, :does_not_remove_any_todos],
- [:guest, :guest, :delete, :delete, :removes_confidential_issues_and_merge_request_todos]
- ]
- end
- # rubocop:enable RSpec/LeakyConstantDeclaration
+ where(:group_access, :project_access, :method_name) do
+ [
+ [nil, :reporter, :does_not_remove_any_todos],
+ [nil, :guest, :removes_confidential_issues_and_merge_request_todos],
+ [:reporter, nil, :does_not_remove_any_todos],
+ [:guest, nil, :removes_confidential_issues_and_merge_request_todos],
+ [:guest, :reporter, :does_not_remove_any_todos],
+ [:guest, :guest, :removes_confidential_issues_and_merge_request_todos]
+ ]
+ end
- it_behaves_like 'using different access permissions', PRIVATE_PROJECT_PRIVATE_GROUP_ACCESS_TABLE
+ with_them do
+ it_behaves_like 'using different access permissions'
+ end
end
end
@@ -117,22 +109,20 @@ RSpec.describe Todos::Destroy::EntityLeaveService do
end
context 'access permissions' do
- # rubocop:disable RSpec/LeakyConstantDeclaration
- PRIVATE_PROJECT_INTERNAL_GROUP_ACCESS_TABLE =
- lambda do |_|
- [
- # :group_access, :project_access, :c_todos, :mr_todos, :method
- [nil, :reporter, :keep, :keep, :does_not_remove_any_todos],
- [nil, :guest, :delete, :delete, :removes_confidential_issues_and_merge_request_todos],
- [:reporter, nil, :keep, :keep, :does_not_remove_any_todos],
- [:guest, nil, :delete, :delete, :removes_confidential_issues_and_merge_request_todos],
- [:guest, :reporter, :keep, :keep, :does_not_remove_any_todos],
- [:guest, :guest, :delete, :delete, :removes_confidential_issues_and_merge_request_todos]
- ]
- end
- # rubocop:enable RSpec/LeakyConstantDeclaration
+ where(:group_access, :project_access, :method_name) do
+ [
+ [nil, :reporter, :does_not_remove_any_todos],
+ [nil, :guest, :removes_confidential_issues_and_merge_request_todos],
+ [:reporter, nil, :does_not_remove_any_todos],
+ [:guest, nil, :removes_confidential_issues_and_merge_request_todos],
+ [:guest, :reporter, :does_not_remove_any_todos],
+ [:guest, :guest, :removes_confidential_issues_and_merge_request_todos]
+ ]
+ end
- it_behaves_like 'using different access permissions', PRIVATE_PROJECT_INTERNAL_GROUP_ACCESS_TABLE
+ with_them do
+ it_behaves_like 'using different access permissions'
+ end
end
end
@@ -172,22 +162,20 @@ RSpec.describe Todos::Destroy::EntityLeaveService do
end
context 'access permissions' do
- # rubocop:disable RSpec/LeakyConstantDeclaration
- INTERNAL_PROJECT_INTERNAL_GROUP_ACCESS_TABLE =
- lambda do |_|
- [
- # :group_access, :project_access, :c_todos, :mr_todos, :method
- [nil, :reporter, :keep, :keep, :does_not_remove_any_todos],
- [nil, :guest, :delete, :keep, :removes_only_confidential_issues_todos],
- [:reporter, nil, :keep, :keep, :does_not_remove_any_todos],
- [:guest, nil, :delete, :keep, :removes_only_confidential_issues_todos],
- [:guest, :reporter, :keep, :keep, :does_not_remove_any_todos],
- [:guest, :guest, :delete, :keep, :removes_only_confidential_issues_todos]
- ]
- end
- # rubocop:enable RSpec/LeakyConstantDeclaration
-
- it_behaves_like 'using different access permissions', INTERNAL_PROJECT_INTERNAL_GROUP_ACCESS_TABLE
+ where(:group_access, :project_access, :method_name) do
+ [
+ [nil, :reporter, :does_not_remove_any_todos],
+ [nil, :guest, :removes_only_confidential_issues_todos],
+ [:reporter, nil, :does_not_remove_any_todos],
+ [:guest, nil, :removes_only_confidential_issues_todos],
+ [:guest, :reporter, :does_not_remove_any_todos],
+ [:guest, :guest, :removes_only_confidential_issues_todos]
+ ]
+ end
+
+ with_them do
+ it_behaves_like 'using different access permissions'
+ end
end
end
@@ -219,22 +207,20 @@ RSpec.describe Todos::Destroy::EntityLeaveService do
end
context 'access permissions' do
- # rubocop:disable RSpec/LeakyConstantDeclaration
- PRIVATE_GROUP_PRIVATE_PROJECT_ACCESS_TABLE =
- lambda do |_|
- [
- # :group_access, :project_access, :c_todos, :mr_todos, :method
- [nil, :reporter, :keep, :keep, :does_not_remove_any_todos],
- [nil, :guest, :delete, :delete, :removes_confidential_issues_and_merge_request_todos],
- [:reporter, nil, :keep, :keep, :does_not_remove_any_todos],
- [:guest, nil, :delete, :delete, :removes_confidential_issues_and_merge_request_todos],
- [:guest, :reporter, :keep, :keep, :does_not_remove_any_todos],
- [:guest, :guest, :delete, :delete, :removes_confidential_issues_and_merge_request_todos]
- ]
- end
- # rubocop:enable RSpec/LeakyConstantDeclaration
+ where(:group_access, :project_access, :method_name) do
+ [
+ [nil, :reporter, :does_not_remove_any_todos],
+ [nil, :guest, :removes_confidential_issues_and_merge_request_todos],
+ [:reporter, nil, :does_not_remove_any_todos],
+ [:guest, nil, :removes_confidential_issues_and_merge_request_todos],
+ [:guest, :reporter, :does_not_remove_any_todos],
+ [:guest, :guest, :removes_confidential_issues_and_merge_request_todos]
+ ]
+ end
- it_behaves_like 'using different access permissions', PRIVATE_GROUP_PRIVATE_PROJECT_ACCESS_TABLE
+ with_them do
+ it_behaves_like 'using different access permissions'
+ end
end
context 'with nested groups' do
@@ -320,23 +306,21 @@ RSpec.describe Todos::Destroy::EntityLeaveService do
end
context 'access permissions' do
- # rubocop:disable RSpec/LeakyConstantDeclaration
- INTERNAL_GROUP_INTERNAL_PROJECT_ACCESS_TABLE =
- lambda do |_|
- [
- # :group_access, :project_access, :c_todos, :mr_todos, :method
- [nil, nil, :delete, :keep, :removes_only_confidential_issues_todos],
- [nil, :reporter, :keep, :keep, :does_not_remove_any_todos],
- [nil, :guest, :delete, :keep, :removes_only_confidential_issues_todos],
- [:reporter, nil, :keep, :keep, :does_not_remove_any_todos],
- [:guest, nil, :delete, :keep, :removes_only_confidential_issues_todos],
- [:guest, :reporter, :keep, :keep, :does_not_remove_any_todos],
- [:guest, :guest, :delete, :keep, :removes_only_confidential_issues_todos]
- ]
- end
- # rubocop:enable RSpec/LeakyConstantDeclaration
+ where(:group_access, :project_access, :method_name) do
+ [
+ [nil, nil, :removes_only_confidential_issues_todos],
+ [nil, :reporter, :does_not_remove_any_todos],
+ [nil, :guest, :removes_only_confidential_issues_todos],
+ [:reporter, nil, :does_not_remove_any_todos],
+ [:guest, nil, :removes_only_confidential_issues_todos],
+ [:guest, :reporter, :does_not_remove_any_todos],
+ [:guest, :guest, :removes_only_confidential_issues_todos]
+ ]
+ end
- it_behaves_like 'using different access permissions', INTERNAL_GROUP_INTERNAL_PROJECT_ACCESS_TABLE
+ with_them do
+ it_behaves_like 'using different access permissions'
+ end
end
end
end
diff --git a/spec/services/users/approve_service_spec.rb b/spec/services/users/approve_service_spec.rb
new file mode 100644
index 00000000000..50f2b6b0827
--- /dev/null
+++ b/spec/services/users/approve_service_spec.rb
@@ -0,0 +1,106 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Users::ApproveService do
+ let_it_be(:current_user) { create(:admin) }
+ let(:user) { create(:user, :blocked_pending_approval) }
+
+ subject(:execute) { described_class.new(current_user).execute(user) }
+
+ describe '#execute' do
+ context 'failures' do
+ context 'when the executor user is not allowed to approve users' do
+ let(:current_user) { create(:user) }
+
+ it 'returns error result' do
+ expect(subject[:status]).to eq(:error)
+ expect(subject[:message]).to match(/You are not allowed to approve a user/)
+ end
+ end
+
+ context 'when user is not in pending approval state' do
+ let(:user) { create(:user, state: 'active') }
+
+ it 'returns error result' do
+ expect(subject[:status]).to eq(:error)
+ expect(subject[:message])
+ .to match(/The user you are trying to approve is not pending an approval/)
+ end
+ end
+
+ context 'when user cannot be activated' do
+ let(:user) do
+ build(:user, state: 'blocked_pending_approval', email: 'invalid email')
+ end
+
+ it 'returns error result' do
+ expect(subject[:status]).to eq(:error)
+ expect(subject[:message]).to match(/Email is invalid/)
+ end
+
+ it 'does not change the state of the user' do
+ expect { subject }.not_to change { user.state }
+ end
+ end
+ end
+
+ context 'success' do
+ it 'activates the user' do
+ expect(subject[:status]).to eq(:success)
+ expect(user.reload).to be_active
+ end
+
+ context 'email confirmation status' do
+ context 'user is unconfirmed' do
+ let(:user) { create(:user, :blocked_pending_approval, :unconfirmed) }
+
+ it 'sends confirmation instructions' do
+ expect { subject }
+ .to have_enqueued_mail(DeviseMailer, :confirmation_instructions)
+ end
+ end
+
+ context 'user is confirmed' do
+ it 'does not send a confirmation email' do
+ expect { subject }
+ .not_to have_enqueued_mail(DeviseMailer, :confirmation_instructions)
+ end
+ end
+ end
+
+ context 'pending invitiations' do
+ let!(:project_member_invite) { create(:project_member, :invited, invite_email: user.email) }
+ let!(:group_member_invite) { create(:group_member, :invited, invite_email: user.email) }
+
+ context 'user is unconfirmed' do
+ let(:user) { create(:user, :blocked_pending_approval, :unconfirmed) }
+
+ it 'does not accept pending invites of the user' do
+ expect(subject[:status]).to eq(:success)
+
+ group_member_invite.reload
+ project_member_invite.reload
+
+ expect(group_member_invite).to be_invite
+ expect(project_member_invite).to be_invite
+ end
+ end
+
+ context 'user is confirmed' do
+ it 'accepts pending invites of the user' do
+ expect(subject[:status]).to eq(:success)
+
+ group_member_invite.reload
+ project_member_invite.reload
+
+ expect(group_member_invite).not_to be_invite
+ expect(project_member_invite).not_to be_invite
+ expect(group_member_invite.user).to eq(user)
+ expect(project_member_invite.user).to eq(user)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/spec/services/users/block_service_spec.rb b/spec/services/users/block_service_spec.rb
index e170a5494aa..45a5b1e5100 100644
--- a/spec/services/users/block_service_spec.rb
+++ b/spec/services/users/block_service_spec.rb
@@ -34,5 +34,15 @@ RSpec.describe Users::BlockService do
expect { operation }.not_to change { user.state }
end
end
+
+ context 'when internal user' do
+ let(:user) { create(:user, :bot) }
+
+ it 'returns error result' do
+ expect(operation[:status]).to eq(:error)
+ expect(operation[:message]).to eq('An internal user cannot be blocked')
+ expect(operation[:http_status]).to eq(403)
+ end
+ end
end
end
diff --git a/spec/services/users/build_service_spec.rb b/spec/services/users/build_service_spec.rb
index c14fdb35bfa..446741221b3 100644
--- a/spec/services/users/build_service_spec.rb
+++ b/spec/services/users/build_service_spec.rb
@@ -4,11 +4,11 @@ require 'spec_helper'
RSpec.describe Users::BuildService do
describe '#execute' do
- let(:params) do
- { name: 'John Doe', username: 'jduser', email: 'jd@example.com', password: 'mydummypass' }
- end
+ let(:params) { build_stubbed(:user).slice(:first_name, :last_name, :username, :email, :password) }
context 'with an admin user' do
+ let(:params) { build_stubbed(:user).slice(:name, :username, :email, :password) }
+
let(:admin_user) { create(:admin) }
let(:service) { described_class.new(admin_user, ActionController::Parameters.new(params).permit!) }
@@ -16,6 +16,10 @@ RSpec.describe Users::BuildService do
expect(service.execute).to be_valid
end
+ it 'sets the created_by_id' do
+ expect(service.execute.created_by_id).to eq(admin_user.id)
+ end
+
context 'calls the UpdateCanonicalEmailService' do
specify do
expect(Users::UpdateCanonicalEmailService).to receive(:new).and_call_original
@@ -128,6 +132,16 @@ RSpec.describe Users::BuildService do
it 'raises AccessDeniedError exception' do
expect { service.execute }.to raise_error Gitlab::Access::AccessDeniedError
end
+
+ context 'when authorization is skipped' do
+ subject(:built_user) { service.execute(skip_authorization: true) }
+
+ it { is_expected.to be_valid }
+
+ it 'sets the created_by_id' do
+ expect(built_user.created_by_id).to eq(user.id)
+ end
+ end
end
context 'with nil user' do
diff --git a/spec/services/users/destroy_service_spec.rb b/spec/services/users/destroy_service_spec.rb
index ff919257b3c..6de685dd89a 100644
--- a/spec/services/users/destroy_service_spec.rb
+++ b/spec/services/users/destroy_service_spec.rb
@@ -234,6 +234,14 @@ RSpec.describe Users::DestroyService do
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 "migrating associated records" do
diff --git a/spec/services/users/validate_otp_service_spec.rb b/spec/services/users/validate_otp_service_spec.rb
new file mode 100644
index 00000000000..826755d6145
--- /dev/null
+++ b/spec/services/users/validate_otp_service_spec.rb
@@ -0,0 +1,34 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Users::ValidateOtpService do
+ let_it_be(:user) { create(:user) }
+ let(:otp_code) { 42 }
+
+ subject(:validate) { described_class.new(user).execute(otp_code) }
+
+ context 'Devise' do
+ it 'calls Devise strategy' do
+ expect_next_instance_of(::Gitlab::Auth::Otp::Strategies::Devise) do |strategy|
+ expect(strategy).to receive(:validate).with(otp_code).once
+ end
+
+ validate
+ end
+ end
+
+ context 'FortiAuthenticator' do
+ before do
+ stub_feature_flags(forti_authenticator: true)
+ end
+
+ it 'calls FortiAuthenticator strategy' do
+ expect_next_instance_of(::Gitlab::Auth::Otp::Strategies::FortiAuthenticator) do |strategy|
+ expect(strategy).to receive(:validate).with(otp_code).once
+ end
+
+ validate
+ end
+ end
+end
diff --git a/spec/services/web_hooks/destroy_service_spec.rb b/spec/services/web_hooks/destroy_service_spec.rb
new file mode 100644
index 00000000000..fda40eb01e2
--- /dev/null
+++ b/spec/services/web_hooks/destroy_service_spec.rb
@@ -0,0 +1,56 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe WebHooks::DestroyService do
+ let_it_be(:user) { create(:user) }
+
+ subject { described_class.new(user) }
+
+ shared_examples 'batched destroys' do
+ it 'destroys all hooks in batches' do
+ stub_const("#{described_class}::BATCH_SIZE", 1)
+ expect(subject).to receive(:delete_web_hook_logs_in_batches).exactly(4).times.and_call_original
+
+ expect do
+ status = subject.execute(hook)
+ expect(status[:async]).to be false
+ end
+ .to change { WebHook.count }.from(1).to(0)
+ .and change { WebHookLog.count }.from(3).to(0)
+ end
+
+ it 'returns an error if sync destroy fails' do
+ expect(hook).to receive(:destroy).and_return(false)
+
+ result = subject.sync_destroy(hook)
+
+ expect(result[:status]).to eq(:error)
+ expect(result[:message]).to eq("Unable to destroy #{hook.model_name.human}")
+ end
+
+ it 'schedules an async delete' do
+ stub_const('WebHooks::DestroyService::LOG_COUNT_THRESHOLD', 1)
+
+ expect(WebHooks::DestroyWorker).to receive(:perform_async).with(user.id, hook.id).and_call_original
+
+ status = subject.execute(hook)
+
+ expect(status[:async]).to be true
+ end
+ end
+
+ context 'with system hook' do
+ let_it_be(:hook) { create(:system_hook, url: "http://example.com") }
+ let_it_be(:log) { create_list(:web_hook_log, 3, web_hook: hook) }
+
+ it_behaves_like 'batched destroys'
+ end
+
+ context 'with project hook' do
+ let_it_be(:hook) { create(:project_hook) }
+ let_it_be(:log) { create_list(:web_hook_log, 3, web_hook: hook) }
+
+ it_behaves_like 'batched destroys'
+ end
+end
diff --git a/spec/simplecov_env.rb b/spec/simplecov_env.rb
index 17b76205d9e..617a45ae449 100644
--- a/spec/simplecov_env.rb
+++ b/spec/simplecov_env.rb
@@ -2,7 +2,6 @@
require 'simplecov'
require 'simplecov-cobertura'
-require 'active_support/core_ext/numeric/time'
require_relative '../lib/gitlab/utils'
module SimpleCovEnv
@@ -75,7 +74,7 @@ module SimpleCovEnv
add_group 'Libraries', %w[/lib /ee/lib]
add_group 'Tooling', %w[/haml_lint /rubocop /tooling]
- merge_timeout 365.days
+ merge_timeout 365 * 24 * 3600
end
end
end
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index 11a83bd9501..11a45e005b8 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -66,7 +66,11 @@ RSpec.configure do |config|
config.display_try_failure_messages = true
config.infer_spec_type_from_file_location!
- config.full_backtrace = !!ENV['CI']
+
+ # Add :full_backtrace tag to an example if full_backtrace output is desired
+ config.before(:each, full_backtrace: true) do |example|
+ config.full_backtrace = true
+ end
unless ENV['CI']
# Re-run failures locally with `--only-failures`
@@ -124,6 +128,7 @@ RSpec.configure do |config|
config.include LoginHelpers, type: :feature
config.include SearchHelpers, type: :feature
config.include WaitHelpers, type: :feature
+ config.include WaitForRequests, type: :feature
config.include EmailHelpers, :mailer, type: :mailer
config.include Warden::Test::Helpers, type: :request
config.include Gitlab::Routing, type: :routing
@@ -133,7 +138,6 @@ RSpec.configure do |config|
config.include InputHelper, :js
config.include SelectionHelper, :js
config.include InspectRequests, :js
- config.include WaitForRequests, :js
config.include LiveDebugger, :js
config.include MigrationsHelpers, :migration
config.include RedisHelpers
@@ -208,6 +212,10 @@ RSpec.configure do |config|
# 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)
+
enable_rugged = example.metadata[:enable_rugged].present?
# Disable Rugged features by default
@@ -225,7 +233,7 @@ RSpec.configure do |config|
end
# Enable Marginalia feature for all specs in the test suite.
- allow(Gitlab::Marginalia).to receive(:cached_feature_enabled?).and_return(true)
+ Gitlab::Marginalia.enabled = true
# Stub these calls due to being expensive operations
# It can be reenabled for specific tests via:
@@ -233,6 +241,12 @@ RSpec.configure do |config|
# expect(Gitlab::Git::KeepAround).to receive(:execute).and_call_original
allow(Gitlab::Git::KeepAround).to receive(:execute)
+ # Stub these calls due to being expensive operations
+ # It can be reenabled for specific tests via:
+ #
+ # expect(Gitlab::JobWaiter).to receive(:wait).and_call_original
+ allow_any_instance_of(Gitlab::JobWaiter).to receive(:wait)
+
Gitlab::ProcessMemoryCache.cache_backend.clear
Sidekiq::Worker.clear_all
diff --git a/spec/support/capybara.rb b/spec/support/capybara.rb
index 66fce4fddf1..ab55cf97ab4 100644
--- a/spec/support/capybara.rb
+++ b/spec/support/capybara.rb
@@ -50,6 +50,10 @@ Capybara.register_driver :chrome do |app|
)
options = Selenium::WebDriver::Chrome::Options.new
+
+ # Force the browser's scale factor to prevent inconsistencies on high-res devices
+ options.add_argument('--force-device-scale-factor=1')
+
options.add_argument("window-size=#{CAPYBARA_WINDOW_SIZE.join(',')}")
# Chrome won't work properly in a Docker container in sandbox mode
@@ -123,6 +127,10 @@ RSpec.configure do |config|
port: session.server.port,
protocol: 'http')
+ # CSRF protection is disabled by default. We only enable this for JS specs because some forms
+ # require Javascript to set the CSRF token.
+ allow_any_instance_of(ActionController::Base).to receive(:protect_against_forgery?).and_return(true)
+
# reset window size between tests
unless session.current_window.size == CAPYBARA_WINDOW_SIZE
begin
diff --git a/spec/support/counter_attribute.rb b/spec/support/counter_attribute.rb
index ea71b25b4c0..8bd40b72dcf 100644
--- a/spec/support/counter_attribute.rb
+++ b/spec/support/counter_attribute.rb
@@ -9,6 +9,12 @@ RSpec.configure do |config|
counter_attribute :build_artifacts_size
counter_attribute :commit_count
+
+ attr_accessor :flushed
+
+ counter_attribute_after_flush do |subject|
+ subject.flushed = true
+ end
end
end
end
diff --git a/spec/support/factory_bot.rb b/spec/support/factory_bot.rb
index a86161bfded..c9d372993b5 100644
--- a/spec/support/factory_bot.rb
+++ b/spec/support/factory_bot.rb
@@ -3,7 +3,3 @@
FactoryBot::SyntaxRunner.class_eval do
include RSpec::Mocks::ExampleMethods
end
-
-# Use FactoryBot 4.x behavior:
-# https://github.com/thoughtbot/factory_bot/blob/master/GETTING_STARTED.md#associations
-FactoryBot.use_parent_strategy = false
diff --git a/spec/support/google_api/cloud_platform_helpers.rb b/spec/support/google_api/cloud_platform_helpers.rb
index 38ffca8c5ae..840f948e377 100644
--- a/spec/support/google_api/cloud_platform_helpers.rb
+++ b/spec/support/google_api/cloud_platform_helpers.rb
@@ -22,7 +22,7 @@ module GoogleApi
.to_return(cloud_platform_response(cloud_platform_projects_billing_info_body(project_id, billing_enabled)))
end
- def stub_cloud_platform_get_zone_cluster(project_id, zone, cluster_id, **options)
+ def stub_cloud_platform_get_zone_cluster(project_id, zone, cluster_id, options = {})
WebMock.stub_request(:get, cloud_platform_get_zone_cluster_url(project_id, zone, cluster_id))
.to_return(cloud_platform_response(cloud_platform_cluster_body(options)))
end
@@ -32,7 +32,7 @@ module GoogleApi
.to_return(status: [500, "Internal Server Error"])
end
- def stub_cloud_platform_create_cluster(project_id, zone, **options)
+ def stub_cloud_platform_create_cluster(project_id, zone, options = {})
WebMock.stub_request(:post, cloud_platform_create_cluster_url(project_id, zone))
.to_return(cloud_platform_response(cloud_platform_operation_body(options)))
end
@@ -42,7 +42,7 @@ module GoogleApi
.to_return(status: [500, "Internal Server Error"])
end
- def stub_cloud_platform_get_zone_operation(project_id, zone, operation_id, **options)
+ def stub_cloud_platform_get_zone_operation(project_id, zone, operation_id, options = {})
WebMock.stub_request(:get, cloud_platform_get_zone_operation_url(project_id, zone, operation_id))
.to_return(cloud_platform_response(cloud_platform_operation_body(options)))
end
@@ -86,7 +86,7 @@ module GoogleApi
# https://cloud.google.com/kubernetes-engine/docs/reference/rest/v1/projects.zones.clusters/create
# rubocop:disable Metrics/CyclomaticComplexity
# rubocop:disable Metrics/PerceivedComplexity
- def cloud_platform_cluster_body(**options)
+ def cloud_platform_cluster_body(options)
{
"name": options[:name] || 'string',
"description": options[:description] || 'string',
@@ -121,7 +121,7 @@ module GoogleApi
}
end
- def cloud_platform_operation_body(**options)
+ def cloud_platform_operation_body(options)
{
"name": options[:name] || 'operation-1234567891234-1234567',
"zone": options[:zone] || 'us-central1-a',
@@ -136,7 +136,7 @@ module GoogleApi
}
end
- def cloud_platform_projects_body(**options)
+ def cloud_platform_projects_body(options)
{
"projects": [
{
diff --git a/spec/support/helpers/api_internal_base_helpers.rb b/spec/support/helpers/api_internal_base_helpers.rb
new file mode 100644
index 00000000000..94996f7480e
--- /dev/null
+++ b/spec/support/helpers/api_internal_base_helpers.rb
@@ -0,0 +1,85 @@
+# frozen_string_literal: true
+
+module APIInternalBaseHelpers
+ def gl_repository_for(container)
+ case container
+ when ProjectWiki
+ Gitlab::GlRepository::WIKI.identifier_for_container(container)
+ when Project
+ Gitlab::GlRepository::PROJECT.identifier_for_container(container)
+ when Snippet
+ Gitlab::GlRepository::SNIPPET.identifier_for_container(container)
+ else
+ nil
+ end
+ end
+
+ def full_path_for(container)
+ case container
+ when PersonalSnippet
+ "snippets/#{container.id}"
+ when ProjectSnippet
+ "#{container.project.full_path}/snippets/#{container.id}"
+ else
+ container.full_path
+ end
+ end
+
+ def pull(key, container, protocol = 'ssh')
+ post(
+ api("/internal/allowed"),
+ params: {
+ key_id: key.id,
+ project: full_path_for(container),
+ gl_repository: gl_repository_for(container),
+ action: 'git-upload-pack',
+ secret_token: secret_token,
+ protocol: protocol
+ }
+ )
+ end
+
+ def push(key, container, protocol = 'ssh', env: nil, changes: nil)
+ push_with_path(key,
+ full_path: full_path_for(container),
+ gl_repository: gl_repository_for(container),
+ protocol: protocol,
+ env: env,
+ changes: changes)
+ end
+
+ def push_with_path(key, full_path:, gl_repository: nil, protocol: 'ssh', env: nil, changes: nil)
+ changes ||= 'd14d6c0abdd253381df51a723d58691b2ee1ab08 570e7b2abdd848b95f2f578043fc23bd6f6fd24d refs/heads/master'
+
+ params = {
+ changes: changes,
+ key_id: key.id,
+ project: full_path,
+ action: 'git-receive-pack',
+ secret_token: secret_token,
+ protocol: protocol,
+ env: env
+ }
+ params[:gl_repository] = gl_repository if gl_repository
+
+ post(
+ api("/internal/allowed"),
+ params: params
+ )
+ end
+
+ def archive(key, container)
+ post(
+ api("/internal/allowed"),
+ params: {
+ ref: 'master',
+ key_id: key.id,
+ project: full_path_for(container),
+ gl_repository: gl_repository_for(container),
+ action: 'git-upload-archive',
+ secret_token: secret_token,
+ protocol: 'ssh'
+ }
+ )
+ end
+end
diff --git a/spec/support/helpers/cycle_analytics_helpers.rb b/spec/support/helpers/cycle_analytics_helpers.rb
index f4343b8b783..6d3ac699a7c 100644
--- a/spec/support/helpers/cycle_analytics_helpers.rb
+++ b/spec/support/helpers/cycle_analytics_helpers.rb
@@ -126,17 +126,15 @@ module CycleAnalyticsHelpers
end
def mock_gitaly_multi_action_dates(repository, commit_time)
- allow(repository.raw).to receive(:multi_action).and_wrap_original do |m, *args|
+ allow(repository.raw).to receive(:multi_action).and_wrap_original do |m, user, kargs|
new_date = commit_time || Time.now
- branch_update = m.call(*args)
+ branch_update = m.call(user, **kargs)
if branch_update.newrev
- _, opts = args
-
commit = rugged_repo(repository).rev_parse(branch_update.newrev)
branch_update.newrev = commit.amend(
- update_ref: "#{Gitlab::Git::BRANCH_REF_PREFIX}#{opts[:branch_name]}",
+ update_ref: "#{Gitlab::Git::BRANCH_REF_PREFIX}#{kargs[:branch_name]}",
author: commit.author.merge(time: new_date),
committer: commit.committer.merge(time: new_date)
)
diff --git a/spec/support/helpers/drag_to_helper.rb b/spec/support/helpers/drag_to_helper.rb
index 2e9932f2e8a..692a4d2b30e 100644
--- a/spec/support/helpers/drag_to_helper.rb
+++ b/spec/support/helpers/drag_to_helper.rb
@@ -1,7 +1,8 @@
# frozen_string_literal: true
module DragTo
- def drag_to(list_from_index: 0, from_index: 0, to_index: 0, list_to_index: 0, selector: '', scrollable: 'body', duration: 1000, perform_drop: true)
+ # rubocop:disable Metrics/ParameterLists
+ def drag_to(list_from_index: 0, from_index: 0, to_index: 0, list_to_index: 0, selector: '', scrollable: 'body', duration: 1000, perform_drop: true, extra_height: 0)
js = <<~JS
simulateDrag({
scrollable: document.querySelector('#{scrollable}'),
@@ -14,7 +15,8 @@ module DragTo
el: document.querySelectorAll('#{selector}')[#{list_to_index}],
index: #{to_index}
},
- performDrop: #{perform_drop}
+ performDrop: #{perform_drop},
+ extraHeight: #{extra_height}
});
JS
evaluate_script(js)
@@ -23,6 +25,7 @@ module DragTo
loop while drag_active?
end
end
+ # rubocop:enable Metrics/ParameterLists
def drag_active?
page.evaluate_script('window.SIMULATE_DRAG_ACTIVE').nonzero?
diff --git a/spec/support/helpers/features/blob_spec_helpers.rb b/spec/support/helpers/features/blob_spec_helpers.rb
new file mode 100644
index 00000000000..880a7249284
--- /dev/null
+++ b/spec/support/helpers/features/blob_spec_helpers.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+# These helpers help you interact within the blobs page and blobs edit page (Single file editor).
+module BlobSpecHelpers
+ include ActionView::Helpers::JavaScriptHelper
+
+ def set_default_button(type)
+ evaluate_script("localStorage.setItem('gl-web-ide-button-selected', '#{type}')")
+ end
+
+ def unset_default_button
+ set_default_button('')
+ end
+
+ def editor_value
+ evaluate_script('monaco.editor.getModels()[0].getValue()')
+ end
+
+ def set_editor_value(value)
+ execute_script("monaco.editor.getModels()[0].setValue('#{value}')")
+ end
+end
diff --git a/spec/support/helpers/features/canonical_link_helpers.rb b/spec/support/helpers/features/canonical_link_helpers.rb
new file mode 100644
index 00000000000..da3a28f1cb2
--- /dev/null
+++ b/spec/support/helpers/features/canonical_link_helpers.rb
@@ -0,0 +1,28 @@
+# frozen_string_literal: true
+
+# These helpers allow you to manipulate with notes.
+#
+# Usage:
+# describe "..." do
+# include Spec::Support::Helpers::Features::CanonicalLinkHelpers
+# ...
+#
+# expect(page).to have_canonical_link(url)
+#
+module Spec
+ module Support
+ module Helpers
+ module Features
+ module CanonicalLinkHelpers
+ def have_canonical_link(url)
+ have_xpath("//link[@rel=\"canonical\" and @href=\"#{url}\"]", visible: false)
+ end
+
+ def have_any_canonical_links
+ have_xpath('//link[@rel="canonical"]', visible: false)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/spec/support/helpers/features/snippet_helpers.rb b/spec/support/helpers/features/snippet_helpers.rb
index c01d179770c..c26849a9680 100644
--- a/spec/support/helpers/features/snippet_helpers.rb
+++ b/spec/support/helpers/features/snippet_helpers.rb
@@ -10,39 +10,69 @@ module Spec
include ActionView::Helpers::JavaScriptHelper
include Spec::Support::Helpers::Features::EditorLiteSpecHelpers
+ def snippet_description_locator
+ 'snippet-description'
+ end
+
+ def snippet_blob_path_locator
+ 'snippet_file_name'
+ end
+
+ def snippet_description_view_selector
+ '.snippet-header .snippet-description'
+ end
+
+ def snippet_description_field_collapsed
+ find('.js-description-input').find('input,textarea')
+ end
+
def snippet_get_first_blob_path
- page.find_field(snippet_blob_path_field, match: :first).value
+ page.find_field('snippet_file_name', match: :first).value
end
def snippet_get_first_blob_value
- page.find(snippet_blob_content_selector, match: :first)
+ page.find('.gl-editor-lite', match: :first)
end
def snippet_description_value
- page.find_field(snippet_description_field).value
+ page.find_field(snippet_description_locator).value
+ end
+
+ def snippet_fill_in_visibility(text)
+ page.find('#visibility-level-setting').choose(text)
end
- def snippet_fill_in_form(title:, content:, description: '')
- # fill_in snippet_title_field, with: title
- # editor_set_value(content)
- fill_in snippet_title_field, with: title
+ def snippet_fill_in_title(value)
+ fill_in 'snippet-title', with: value
+ end
- if description
- # Click placeholder first to expand full description field
- description_field.click
- fill_in snippet_description_field, with: description
- end
+ def snippet_fill_in_description(value)
+ # Click placeholder first to expand full description field
+ snippet_description_field_collapsed.click
+ fill_in snippet_description_locator, with: value
+ end
- page.within('.file-editor') do
+ def snippet_fill_in_content(value)
+ page.within('.gl-editor-lite') do
el = find('.inputarea')
- el.send_keys content
+ el.send_keys value
end
end
- private
+ def snippet_fill_in_file_name(value)
+ fill_in(snippet_blob_path_locator, match: :first, with: value)
+ end
+
+ def snippet_fill_in_form(title: nil, content: nil, file_name: nil, description: nil, visibility: nil)
+ snippet_fill_in_title(title) if title
- def description_field
- find('.js-description-input').find('input,textarea')
+ snippet_fill_in_description(description) if description
+
+ snippet_fill_in_file_name(file_name) if file_name
+
+ snippet_fill_in_content(content) if content
+
+ snippet_fill_in_visibility(visibility) if visibility
end
end
end
diff --git a/spec/support/helpers/git_http_helpers.rb b/spec/support/helpers/git_http_helpers.rb
index de8bb9ac8e3..c9c1c4dcfc9 100644
--- a/spec/support/helpers/git_http_helpers.rb
+++ b/spec/support/helpers/git_http_helpers.rb
@@ -5,45 +5,45 @@ require_relative 'workhorse_helpers'
module GitHttpHelpers
include WorkhorseHelpers
- def clone_get(project, options = {})
+ def clone_get(project, **options)
get "/#{project}/info/refs", params: { service: 'git-upload-pack' }, headers: auth_env(*options.values_at(:user, :password, :spnego_request_token))
end
- def clone_post(project, options = {})
+ def clone_post(project, **options)
post "/#{project}/git-upload-pack", headers: auth_env(*options.values_at(:user, :password, :spnego_request_token))
end
- def push_get(project, options = {})
+ def push_get(project, **options)
get "/#{project}/info/refs", params: { service: 'git-receive-pack' }, headers: auth_env(*options.values_at(:user, :password, :spnego_request_token))
end
- def push_post(project, options = {})
+ def push_post(project, **options)
post "/#{project}/git-receive-pack", headers: auth_env(*options.values_at(:user, :password, :spnego_request_token))
end
def download(project, user: nil, password: nil, spnego_request_token: nil)
- args = [project, { user: user, password: password, spnego_request_token: spnego_request_token }]
+ args = { user: user, password: password, spnego_request_token: spnego_request_token }
- clone_get(*args)
+ clone_get(project, **args)
yield response
- clone_post(*args)
+ clone_post(project, **args)
yield response
end
def upload(project, user: nil, password: nil, spnego_request_token: nil)
- args = [project, { user: user, password: password, spnego_request_token: spnego_request_token }]
+ args = { user: user, password: password, spnego_request_token: spnego_request_token }
- push_get(*args)
+ push_get(project, **args)
yield response
- push_post(*args)
+ push_post(project, **args)
yield response
end
- def download_or_upload(*args, &block)
- download(*args, &block)
- upload(*args, &block)
+ def download_or_upload(project, **args, &block)
+ download(project, **args, &block)
+ upload(project, **args, &block)
end
def auth_env(user, password, spnego_request_token)
diff --git a/spec/support/helpers/graphql_helpers.rb b/spec/support/helpers/graphql_helpers.rb
index 5635ba3df05..db769041f1e 100644
--- a/spec/support/helpers/graphql_helpers.rb
+++ b/spec/support/helpers/graphql_helpers.rb
@@ -23,7 +23,7 @@ module GraphqlHelpers
return early_return unless ready
- resolver.resolve(args)
+ resolver.resolve(**args)
end
# Eagerly run a loader's named resolver
@@ -219,6 +219,7 @@ module GraphqlHelpers
def as_graphql_literal(value)
case value
when Array then "[#{value.map { |v| as_graphql_literal(v) }.join(',')}]"
+ when Hash then "{#{attributes_to_graphql(value)}}"
when Integer, Float then value.to_s
when String then "\"#{value.gsub(/"/, '\\"')}\""
when Symbol then value
@@ -234,7 +235,8 @@ module GraphqlHelpers
end
def post_graphql(query, current_user: nil, variables: nil, headers: {})
- post api('/', current_user, version: 'graphql'), params: { query: query, variables: variables }, headers: headers
+ params = { query: query, variables: variables&.to_json }
+ post api('/', current_user, version: 'graphql'), params: params, headers: headers
end
def post_graphql_mutation(mutation, current_user: nil)
diff --git a/spec/support/helpers/javascript_fixtures_helpers.rb b/spec/support/helpers/javascript_fixtures_helpers.rb
index 4f11f8c6b24..2224af88ab9 100644
--- a/spec/support/helpers/javascript_fixtures_helpers.rb
+++ b/spec/support/helpers/javascript_fixtures_helpers.rb
@@ -39,6 +39,17 @@ module JavaScriptFixturesHelpers
Gitlab::Shell.new.remove_repository(project.repository_storage, project.disk_path)
end
+ # Public: Reads a GraphQL query from the filesystem as a string
+ #
+ # query_path - file path to the GraphQL query, relative to `app/assets/javascripts`
+ # fragment_paths - an optional array of file paths to any fragments the query uses,
+ # also relative to `app/assets/javascripts`
+ def get_graphql_query_as_string(query_path, fragment_paths = [])
+ [query_path, *fragment_paths].map do |path|
+ File.read(File.join(Rails.root, '/app/assets/javascripts', path))
+ end.join("\n")
+ end
+
private
# Private: Store a response object as fixture file
diff --git a/spec/support/helpers/kubernetes_helpers.rb b/spec/support/helpers/kubernetes_helpers.rb
index 8882f31e2f4..113bb31e4be 100644
--- a/spec/support/helpers/kubernetes_helpers.rb
+++ b/spec/support/helpers/kubernetes_helpers.rb
@@ -33,6 +33,10 @@ module KubernetesHelpers
kube_response(kube_deployments_body)
end
+ def kube_ingresses_response
+ kube_response(kube_ingresses_body)
+ end
+
def stub_kubeclient_discover_base(api_url)
WebMock.stub_request(:get, api_url + '/api/v1').to_return(kube_response(kube_v1_discovery_body))
WebMock
@@ -63,6 +67,9 @@ module KubernetesHelpers
WebMock
.stub_request(:get, api_url + '/apis/serving.knative.dev/v1alpha1')
.to_return(kube_response(kube_v1alpha1_serving_knative_discovery_body))
+ WebMock
+ .stub_request(:get, api_url + '/apis/networking.k8s.io/v1')
+ .to_return(kube_response(kube_v1_networking_discovery_body))
end
def stub_kubeclient_discover_knative_not_found(api_url)
@@ -148,12 +155,20 @@ module KubernetesHelpers
WebMock.stub_request(:get, deployments_url).to_return(response || kube_deployments_response)
end
+ def stub_kubeclient_ingresses(namespace, status: nil)
+ stub_kubeclient_discover(service.api_url)
+ ingresses_url = service.api_url + "/apis/extensions/v1beta1/namespaces/#{namespace}/ingresses"
+ response = { status: status } if status
+
+ WebMock.stub_request(:get, ingresses_url).to_return(response || kube_ingresses_response)
+ end
+
def stub_kubeclient_knative_services(options = {})
namespace_path = options[:namespace].present? ? "namespaces/#{options[:namespace]}/" : ""
options[:name] ||= "kubetest"
options[:domain] ||= "example.com"
- options[:response] ||= kube_response(kube_knative_services_body(options))
+ options[:response] ||= kube_response(kube_knative_services_body(**options))
stub_kubeclient_discover(service.api_url)
@@ -265,7 +280,7 @@ module KubernetesHelpers
.to_return(kube_response({}))
end
- def kube_v1_secret_body(**options)
+ def kube_v1_secret_body(options)
{
"kind" => "SecretList",
"apiVersion": "v1",
@@ -304,6 +319,14 @@ module KubernetesHelpers
}
end
+ # From Kubernetes 1.22+ Ingresses are no longer served from apis/extensions
+ def kube_1_22_extensions_v1beta1_discovery_body
+ {
+ "kind" => "APIResourceList",
+ "resources" => []
+ }
+ end
+
def kube_knative_discovery_body
{
"kind" => "APIResourceList",
@@ -416,6 +439,17 @@ module KubernetesHelpers
}
end
+ def kube_v1_networking_discovery_body
+ {
+ "kind" => "APIResourceList",
+ "apiVersion" => "v1",
+ "groupVersion" => "networking.k8s.io/v1",
+ "resources" => [
+ { "name" => "ingresses", "namespaced" => true, "kind" => "Ingress" }
+ ]
+ }
+ end
+
def kube_istio_gateway_body(name, namespace)
{
"apiVersion" => "networking.istio.io/v1alpha3",
@@ -507,6 +541,13 @@ module KubernetesHelpers
}
end
+ def kube_ingresses_body
+ {
+ "kind" => "List",
+ "items" => [kube_ingress]
+ }
+ end
+
def kube_knative_pods_body(name, namespace)
{
"kind" => "PodList",
@@ -517,7 +558,7 @@ module KubernetesHelpers
def kube_knative_services_body(**options)
{
"kind" => "List",
- "items" => [knative_09_service(options)]
+ "items" => [knative_09_service(**options)]
}
end
@@ -548,6 +589,38 @@ module KubernetesHelpers
}
end
+ def kube_ingress(track: :stable)
+ additional_annotations =
+ if track == :canary
+ {
+ "nginx.ingress.kubernetes.io/canary" => "true",
+ "nginx.ingress.kubernetes.io/canary-by-header" => "canary",
+ "nginx.ingress.kubernetes.io/canary-weight" => "50"
+ }
+ else
+ {}
+ end
+
+ {
+ "metadata" => {
+ "name" => "production-auto-deploy",
+ "labels" => {
+ "app" => "production",
+ "app.kubernetes.io/managed-by" => "Helm",
+ "chart" => "auto-deploy-app-2.0.0-beta.2",
+ "heritage" => "Helm",
+ "release" => "production"
+ },
+ "annotations" => {
+ "kubernetes.io/ingress.class" => "nginx",
+ "kubernetes.io/tls-acme" => "true",
+ "meta.helm.sh/release-name" => "production",
+ "meta.helm.sh/release-namespace" => "awesome-app-1-production"
+ }.merge(additional_annotations)
+ }
+ }
+ end
+
# This is a partial response, it will have many more elements in reality but
# these are the ones we care about at the moment
def kube_node
@@ -604,7 +677,7 @@ module KubernetesHelpers
}
end
- def kube_deployment(name: "kube-deployment", environment_slug: "production", project_slug: "project-path-slug", track: nil)
+ def kube_deployment(name: "kube-deployment", environment_slug: "production", project_slug: "project-path-slug", track: nil, replicas: 3)
{
"metadata" => {
"name" => name,
@@ -617,7 +690,7 @@ module KubernetesHelpers
"track" => track
}.compact
},
- "spec" => { "replicas" => 3 },
+ "spec" => { "replicas" => replicas },
"status" => {
"observedGeneration" => 4
}
@@ -862,8 +935,8 @@ module KubernetesHelpers
end
end
- def kube_deployment_rollout_status
- ::Gitlab::Kubernetes::RolloutStatus.from_deployments(kube_deployment)
+ def kube_deployment_rollout_status(ingresses: [])
+ ::Gitlab::Kubernetes::RolloutStatus.from_deployments(kube_deployment, ingresses: ingresses)
end
def empty_deployment_rollout_status
diff --git a/spec/support/helpers/multipart_helpers.rb b/spec/support/helpers/multipart_helpers.rb
index 043cb6e1420..2e8db0e9e42 100644
--- a/spec/support/helpers/multipart_helpers.rb
+++ b/spec/support/helpers/multipart_helpers.rb
@@ -31,7 +31,7 @@ module MultipartHelpers
raise ArgumentError, "can't handle #{mode} mode"
end
- return result if ::Feature.disabled?(:upload_middleware_jwt_params_handler)
+ return result if ::Feature.disabled?(:upload_middleware_jwt_params_handler, default_enabled: true)
# the HandlerForJWTParams expects a jwt token with the upload parameters
# *without* the "#{key}." prefix
diff --git a/spec/support/helpers/rack_attack_spec_helpers.rb b/spec/support/helpers/rack_attack_spec_helpers.rb
index 65082ec690f..a8ae69885d8 100644
--- a/spec/support/helpers/rack_attack_spec_helpers.rb
+++ b/spec/support/helpers/rack_attack_spec_helpers.rb
@@ -1,10 +1,6 @@
# frozen_string_literal: true
module RackAttackSpecHelpers
- def post_args_with_token_headers(url, token_headers)
- [url, params: nil, headers: token_headers]
- end
-
def api_get_args_with_token_headers(partial_url, token_headers)
["/api/#{API::API.version}#{partial_url}", params: nil, headers: token_headers]
end
diff --git a/spec/support/helpers/search_helpers.rb b/spec/support/helpers/search_helpers.rb
index db6e47459e9..328f272724a 100644
--- a/spec/support/helpers/search_helpers.rb
+++ b/spec/support/helpers/search_helpers.rb
@@ -1,6 +1,14 @@
# frozen_string_literal: true
module SearchHelpers
+ def fill_in_search(text)
+ page.within('.search-input-wrap') do
+ fill_in('search', with: text)
+ end
+
+ wait_for_all_requests
+ end
+
def submit_search(query, scope: nil)
page.within('.search-form, .search-page-form') do
field = find_field('search')
@@ -11,6 +19,8 @@ module SearchHelpers
else
click_button('Search')
end
+
+ wait_for_all_requests
end
end
diff --git a/spec/support/helpers/snippet_helpers.rb b/spec/support/helpers/snippet_helpers.rb
index de64ad7d3e2..1ec50bce070 100644
--- a/spec/support/helpers/snippet_helpers.rb
+++ b/spec/support/helpers/snippet_helpers.rb
@@ -8,7 +8,7 @@ module SnippetHelpers
def snippet_blob_file(blob)
{
"path" => blob.path,
- "raw_url" => gitlab_raw_snippet_blob_url(blob.container, blob.path)
+ "raw_url" => gitlab_raw_snippet_blob_url(blob.container, blob.path, host: 'localhost')
}
end
end
diff --git a/spec/support/helpers/snowplow_helpers.rb b/spec/support/helpers/snowplow_helpers.rb
index 83a5b7e48bc..3bde01c6fbf 100644
--- a/spec/support/helpers/snowplow_helpers.rb
+++ b/spec/support/helpers/snowplow_helpers.rb
@@ -32,8 +32,16 @@ module SnowplowHelpers
# end
# end
def expect_snowplow_event(category:, action:, **kwargs)
- expect(Gitlab::Tracking).to have_received(:event)
- .with(category, action, **kwargs).at_least(:once)
+ # This check will no longer be needed with Ruby 2.7 which
+ # would not pass any arguments when using **kwargs.
+ # https://gitlab.com/gitlab-org/gitlab/-/issues/263430
+ if kwargs.present?
+ expect(Gitlab::Tracking).to have_received(:event)
+ .with(category, action, **kwargs).at_least(:once)
+ else
+ expect(Gitlab::Tracking).to have_received(:event)
+ .with(category, action).at_least(:once)
+ end
end
# Asserts that no call to `Gitlab::Tracking#event` was made.
diff --git a/spec/support/helpers/stub_experiments.rb b/spec/support/helpers/stub_experiments.rb
index ff3b02dc3f6..7a6154d5ef9 100644
--- a/spec/support/helpers/stub_experiments.rb
+++ b/spec/support/helpers/stub_experiments.rb
@@ -22,10 +22,10 @@ module StubExperiments
# Examples
# - `stub_experiment_for_user(signup_flow: false)` ... Disable `signup_flow` experiment for user.
def stub_experiment_for_user(experiments)
- allow(Gitlab::Experimentation).to receive(:enabled_for_user?).and_call_original
+ allow(Gitlab::Experimentation).to receive(:enabled_for_value?).and_call_original
experiments.each do |experiment_key, enabled|
- allow(Gitlab::Experimentation).to receive(:enabled_for_user?).with(experiment_key, anything) { enabled }
+ allow(Gitlab::Experimentation).to receive(:enabled_for_value?).with(experiment_key, anything) { enabled }
end
end
end
diff --git a/spec/support/helpers/stub_feature_flags.rb b/spec/support/helpers/stub_feature_flags.rb
index 792a1c21c31..7f30a2a70cd 100644
--- a/spec/support/helpers/stub_feature_flags.rb
+++ b/spec/support/helpers/stub_feature_flags.rb
@@ -62,4 +62,8 @@ module StubFeatureFlags
StubFeatureGate.new(object)
end
+
+ def skip_feature_flags_yaml_validation
+ allow(Feature::Definition).to receive(:valid_usage!)
+ end
end
diff --git a/spec/support/helpers/stub_object_storage.rb b/spec/support/helpers/stub_object_storage.rb
index 476b7d34ee5..dba3d2b137e 100644
--- a/spec/support/helpers/stub_object_storage.rb
+++ b/spec/support/helpers/stub_object_storage.rb
@@ -82,13 +82,27 @@ module StubObjectStorage
**params)
end
- def stub_terraform_state_object_storage(uploader = described_class, **params)
+ def stub_terraform_state_object_storage(**params)
stub_object_storage_uploader(config: Gitlab.config.terraform_state.object_store,
- uploader: uploader,
+ uploader: Terraform::VersionedStateUploader,
+ remote_directory: 'terraform',
+ **params)
+ end
+
+ def stub_terraform_state_version_object_storage(**params)
+ stub_object_storage_uploader(config: Gitlab.config.terraform_state.object_store,
+ uploader: Terraform::StateUploader,
remote_directory: 'terraform',
**params)
end
+ def stub_pages_object_storage(uploader = described_class, **params)
+ stub_object_storage_uploader(config: Gitlab.config.pages.object_store,
+ uploader: uploader,
+ remote_directory: 'pages',
+ **params)
+ end
+
def stub_object_storage_multipart_init(endpoint, upload_id = "upload_id")
stub_request(:post, %r{\A#{endpoint}tmp/uploads/[a-z0-9-]*\?uploads\z})
.to_return status: 200, body: <<-EOS.strip_heredoc
diff --git a/spec/support/helpers/stubbed_feature.rb b/spec/support/helpers/stubbed_feature.rb
index d4e9af7a031..67ceb7d9b35 100644
--- a/spec/support/helpers/stubbed_feature.rb
+++ b/spec/support/helpers/stubbed_feature.rb
@@ -4,6 +4,14 @@
module StubbedFeature
extend ActiveSupport::Concern
+ prepended do
+ cattr_reader(:persist_used) do
+ # persist feature flags in CI
+ # nil: indicates that we do not want to persist used feature flags
+ Gitlab::Utils.to_boolean(ENV['CI']) ? {} : nil
+ end
+ end
+
class_methods do
# Turn stubbed feature flags on or off.
def stub=(stub)
@@ -29,10 +37,12 @@ module StubbedFeature
end
# Replace #enabled? method with the optional stubbed/unstubbed version.
- def enabled?(*args)
- feature_flag = super(*args)
+ def enabled?(*args, **kwargs)
+ feature_flag = super
return feature_flag unless stub?
+ persist_used!(args.first)
+
# If feature flag is not persisted we mark the feature flag as enabled
# We do `m.call` as we want to validate the execution of method arguments
# and a feature flag state if it is not persisted
@@ -42,5 +52,17 @@ module StubbedFeature
feature_flag
end
+
+ # This method creates a temporary file in `tmp/feature_flags`
+ # if feature flag was touched during execution
+ def persist_used!(name)
+ return unless persist_used
+ return if persist_used[name]
+
+ persist_used[name] = true
+ FileUtils.touch(
+ Rails.root.join('tmp', 'feature_flags', name.to_s + ".used")
+ )
+ end
end
end
diff --git a/spec/support/helpers/usage_data_helpers.rb b/spec/support/helpers/usage_data_helpers.rb
index d92fcdc2d4a..2592d9f8b42 100644
--- a/spec/support/helpers/usage_data_helpers.rb
+++ b/spec/support/helpers/usage_data_helpers.rb
@@ -99,6 +99,7 @@ module UsageDataHelpers
projects_with_error_tracking_enabled
projects_with_alerts_service_enabled
projects_with_prometheus_alerts
+ projects_with_tracing_enabled
projects_with_expiration_policy_enabled
projects_with_expiration_policy_disabled
projects_with_expiration_policy_enabled_with_keep_n_unset
@@ -133,6 +134,7 @@ module UsageDataHelpers
todos
uploads
web_hooks
+ user_preferences_user_gitpod_enabled
).push(*SMAU_KEYS)
USAGE_DATA_KEYS = %i(
@@ -171,6 +173,10 @@ module UsageDataHelpers
allow(Gitlab::Prometheus::Internal).to receive(:prometheus_enabled?).and_return(false)
end
+ def clear_memoized_values(values)
+ values.each { |v| described_class.clear_memoization(v) }
+ end
+
def stub_object_store_settings
allow(Settings).to receive(:[]).with('artifacts')
.and_return(
@@ -228,9 +234,9 @@ module UsageDataHelpers
receive_matchers.each { |m| expect(prometheus_client).to m }
end
- def for_defined_days_back(days: [29, 2])
+ def for_defined_days_back(days: [31, 3])
days.each do |n|
- Timecop.travel(n.days.ago) do
+ travel_to(n.days.ago) do
yield
end
end
diff --git a/spec/support/helpers/wait_for_requests.rb b/spec/support/helpers/wait_for_requests.rb
index 2cfd47634ca..43060e571a9 100644
--- a/spec/support/helpers/wait_for_requests.rb
+++ b/spec/support/helpers/wait_for_requests.rb
@@ -48,17 +48,10 @@ module WaitForRequests
def finished_all_js_requests?
return true unless javascript_test?
- finished_all_ajax_requests? &&
- finished_all_axios_requests?
- end
-
- def finished_all_axios_requests?
- Capybara.page.evaluate_script('window.pendingRequests || 0').zero? # rubocop:disable Style/NumericPredicate
+ finished_all_ajax_requests?
end
def finished_all_ajax_requests?
- return true if Capybara.page.evaluate_script('typeof jQuery === "undefined"')
-
- Capybara.page.evaluate_script('jQuery.active').zero? # rubocop:disable Style/NumericPredicate
+ Capybara.page.evaluate_script('window.pendingRequests || window.pendingRailsUJSRequests || 0').zero? # rubocop:disable Style/NumericPredicate
end
end
diff --git a/spec/support/helpers/wiki_helpers.rb b/spec/support/helpers/wiki_helpers.rb
index e59c6bde264..8873a90579d 100644
--- a/spec/support/helpers/wiki_helpers.rb
+++ b/spec/support/helpers/wiki_helpers.rb
@@ -13,16 +13,16 @@ module WikiHelpers
find('.svg-content .js-lazy-loaded') if example.nil? || example.metadata.key?(:js)
end
- def upload_file_to_wiki(container, user, file_name)
- opts = {
+ def upload_file_to_wiki(wiki, user, file_name)
+ params = {
file_name: file_name,
file_content: File.read(expand_fixture_path(file_name))
}
::Wikis::CreateAttachmentService.new(
- container: container,
+ container: wiki.container,
current_user: user,
- params: opts
- ).execute[:result][:file_path]
+ params: params
+ ).execute.dig(:result, :file_path)
end
end
diff --git a/spec/support/matchers/be_sorted.rb b/spec/support/matchers/be_sorted.rb
new file mode 100644
index 00000000000..1455060fe71
--- /dev/null
+++ b/spec/support/matchers/be_sorted.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+# Assert that this collection is sorted by argument and order
+#
+# By default, this checks that the collection is sorted ascending
+# but you can check order by specific field and order by passing
+# them, eg:
+#
+# ```
+# expect(collection).to be_sorted(:field, :desc)
+# ```
+RSpec::Matchers.define :be_sorted do |by, order = :asc|
+ match do |actual|
+ next true unless actual.present? # emtpy collection is sorted
+
+ actual
+ .then { |collection| by ? collection.sort_by(&by) : collection.sort }
+ .then { |sorted_collection| order.to_sym == :desc ? sorted_collection.reverse : sorted_collection }
+ .then { |sorted_collection| sorted_collection == actual }
+ end
+end
diff --git a/spec/support/migrations_helpers/cluster_helpers.rb b/spec/support/migrations_helpers/cluster_helpers.rb
index b54af15c29e..03104e22bcf 100644
--- a/spec/support/migrations_helpers/cluster_helpers.rb
+++ b/spec/support/migrations_helpers/cluster_helpers.rb
@@ -4,7 +4,7 @@ module MigrationHelpers
module ClusterHelpers
# Creates a list of cluster projects.
def create_cluster_project_list(quantity)
- group = namespaces_table.create(name: 'gitlab-org', path: 'gitlab-org')
+ group = namespaces_table.create!(name: 'gitlab-org', path: 'gitlab-org')
quantity.times do |id|
create_cluster_project(group, id)
@@ -25,14 +25,14 @@ module MigrationHelpers
namespace_id: group.id
)
- cluster = clusters_table.create(
+ cluster = clusters_table.create!(
name: 'test-cluster',
cluster_type: 3,
provider_type: :gcp,
platform_type: :kubernetes
)
- cluster_projects_table.create(project_id: project.id, cluster_id: cluster.id)
+ cluster_projects_table.create!(project_id: project.id, cluster_id: cluster.id)
provider_gcp_table.create!(
gcp_project_id: "test-gcp-project-#{id}",
@@ -43,7 +43,7 @@ module MigrationHelpers
zone: 'us-central1-a'
)
- platform_kubernetes_table.create(
+ platform_kubernetes_table.create!(
cluster_id: cluster.id,
api_url: 'https://kubernetes.example.com',
encrypted_token: 'a' * 40,
@@ -58,7 +58,7 @@ module MigrationHelpers
project = projects_table.find(cluster_project.project_id)
namespace = "#{project.path}-#{project.id}"
- cluster_kubernetes_namespaces_table.create(
+ cluster_kubernetes_namespaces_table.create!(
cluster_project_id: cluster_project.id,
cluster_id: cluster.id,
project_id: cluster_project.project_id,
diff --git a/spec/support/migrations_helpers/namespaces_helper.rb b/spec/support/migrations_helpers/namespaces_helper.rb
index 4ca01c87568..c62ef6a4620 100644
--- a/spec/support/migrations_helpers/namespaces_helper.rb
+++ b/spec/support/migrations_helpers/namespaces_helper.rb
@@ -3,7 +3,7 @@
module MigrationHelpers
module NamespacesHelpers
def create_namespace(name, visibility, options = {})
- table(:namespaces).create({
+ table(:namespaces).create!({
name: name,
path: name,
type: 'Group',
diff --git a/spec/support/migrations_helpers/schema_version_finder.rb b/spec/support/migrations_helpers/schema_version_finder.rb
new file mode 100644
index 00000000000..b677db7ea26
--- /dev/null
+++ b/spec/support/migrations_helpers/schema_version_finder.rb
@@ -0,0 +1,34 @@
+# frozen_string_literal: true
+
+# Sometimes data migration specs require adding invalid test data in order to test
+# the migration (e.g. adding a row with null foreign key). Certain db migrations that
+# add constraints (e.g. NOT NULL constraint) prevent invalid records from being added
+# and data migration from being tested. For this reason, SchemaVersionFinder can be used
+# to find and use schema prior to specified one.
+#
+# @example
+# RSpec.describe CleanupThings, :migration, schema: MigrationHelpers::SchemaVersionFinder.migration_prior(AddNotNullConstraint) do ...
+#
+# SchemaVersionFinder returns schema version prior to the one specified, which allows to then add
+# invalid records to the database, which in return allows to properly test data migration.
+module MigrationHelpers
+ class SchemaVersionFinder
+ def self.migrations_paths
+ ActiveRecord::Migrator.migrations_paths
+ end
+
+ def self.migration_context
+ ActiveRecord::MigrationContext.new(migrations_paths, ActiveRecord::SchemaMigration)
+ end
+
+ def self.migrations
+ migration_context.migrations
+ end
+
+ def self.migration_prior(migration_klass)
+ migrations.each_cons(2) do |previous, migration|
+ break previous.version if migration.name == migration_klass.name
+ end
+ end
+ end
+end
diff --git a/spec/support/models/merge_request_without_merge_request_diff.rb b/spec/support/models/merge_request_without_merge_request_diff.rb
new file mode 100644
index 00000000000..5cdf1feb7a5
--- /dev/null
+++ b/spec/support/models/merge_request_without_merge_request_diff.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+class MergeRequestWithoutMergeRequestDiff < ::MergeRequest
+ self.inheritance_column = :_type_disabled
+
+ def ensure_merge_request_diff; end
+end
diff --git a/spec/support/shared_contexts/cache_allowed_users_in_namespace_shared_context.rb b/spec/support/shared_contexts/cache_allowed_users_in_namespace_shared_context.rb
index e3c1d0afa53..bfb719fd840 100644
--- a/spec/support/shared_contexts/cache_allowed_users_in_namespace_shared_context.rb
+++ b/spec/support/shared_contexts/cache_allowed_users_in_namespace_shared_context.rb
@@ -25,7 +25,7 @@ RSpec.shared_examples 'allowed user IDs are cached' do
expect(described_class.l1_cache_backend).to receive(:fetch).and_call_original
expect(described_class.l2_cache_backend).to receive(:fetch).and_call_original
expect(subject).to be_truthy
- end.not_to exceed_query_limit(2)
+ end.not_to exceed_query_limit(3)
end
end
end
diff --git a/spec/support/shared_contexts/email_shared_context.rb b/spec/support/shared_contexts/email_shared_context.rb
index b4d7722f03d..298e03162c4 100644
--- a/spec/support/shared_contexts/email_shared_context.rb
+++ b/spec/support/shared_contexts/email_shared_context.rb
@@ -21,7 +21,7 @@ end
RSpec.shared_examples :reply_processing_shared_examples do
context "when the user could not be found" do
before do
- user.destroy
+ user.destroy!
end
it "raises a UserNotFoundError" do
diff --git a/spec/support/shared_contexts/finders/group_projects_finder_shared_contexts.rb b/spec/support/shared_contexts/finders/group_projects_finder_shared_contexts.rb
index 58ee48a98f1..2b6edb4c07d 100644
--- a/spec/support/shared_contexts/finders/group_projects_finder_shared_contexts.rb
+++ b/spec/support/shared_contexts/finders/group_projects_finder_shared_contexts.rb
@@ -18,8 +18,8 @@ RSpec.shared_context 'GroupProjectsFinder context' do
let!(:subgroup_private_project) { create(:project, :private, path: '7', group: subgroup) }
before do
- shared_project_1.project_group_links.create(group_access: Gitlab::Access::MAINTAINER, group: group)
- shared_project_2.project_group_links.create(group_access: Gitlab::Access::MAINTAINER, group: group)
- shared_project_3.project_group_links.create(group_access: Gitlab::Access::MAINTAINER, group: group)
+ shared_project_1.project_group_links.create!(group_access: Gitlab::Access::MAINTAINER, group: group)
+ shared_project_2.project_group_links.create!(group_access: Gitlab::Access::MAINTAINER, group: group)
+ shared_project_3.project_group_links.create!(group_access: Gitlab::Access::MAINTAINER, group: group)
end
end
diff --git a/spec/support/shared_contexts/lib/gitlab/import_export/relation_tree_restorer_shared_context.rb b/spec/support/shared_contexts/lib/gitlab/import_export/relation_tree_restorer_shared_context.rb
new file mode 100644
index 00000000000..6b9ddc70691
--- /dev/null
+++ b/spec/support/shared_contexts/lib/gitlab/import_export/relation_tree_restorer_shared_context.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+RSpec.shared_context 'relation tree restorer shared context' do
+ include ImportExport::CommonUtil
+
+ let(:user) { create(:user) }
+ let(:shared) { Gitlab::ImportExport::Shared.new(importable) }
+ let(:attributes) { relation_reader.consume_attributes(importable_name) }
+
+ let(:members_mapper) do
+ Gitlab::ImportExport::MembersMapper.new(exported_members: {}, user: user, importable: importable)
+ end
+end
diff --git a/spec/support/shared_contexts/mailers/notify_shared_context.rb b/spec/support/shared_contexts/mailers/notify_shared_context.rb
index de8c0d5d2b4..4b7d028410a 100644
--- a/spec/support/shared_contexts/mailers/notify_shared_context.rb
+++ b/spec/support/shared_contexts/mailers/notify_shared_context.rb
@@ -11,7 +11,7 @@ RSpec.shared_context 'gitlab email notification' do
let(:new_user_address) { 'newguy@example.com' }
before do
- email = recipient.emails.create(email: "notifications@example.com")
+ email = recipient.emails.create!(email: "notifications@example.com")
recipient.update_attribute(:notification_email, email.email)
stub_incoming_email_setting(enabled: true, address: "reply+%{key}@#{Gitlab.config.gitlab.host}")
end
diff --git a/spec/support/shared_contexts/navbar_structure_context.rb b/spec/support/shared_contexts/navbar_structure_context.rb
index 747358fc1e0..9ebfdcb9522 100644
--- a/spec/support/shared_contexts/navbar_structure_context.rb
+++ b/spec/support/shared_contexts/navbar_structure_context.rb
@@ -44,7 +44,8 @@ RSpec.shared_context 'project navbar structure' do
_('Boards'),
_('Labels'),
_('Service Desk'),
- _('Milestones')
+ _('Milestones'),
+ (_('Iterations') if Gitlab.ee?)
]
},
{
@@ -64,14 +65,16 @@ RSpec.shared_context 'project navbar structure' do
nav_item: _('Operations'),
nav_sub_items: [
_('Metrics'),
+ _('Logs'),
+ _('Tracing'),
+ _('Error Tracking'),
_('Alerts'),
_('Incidents'),
- _('Environments'),
- _('Error Tracking'),
- _('Product Analytics'),
_('Serverless'),
- _('Logs'),
- _('Kubernetes')
+ _('Kubernetes'),
+ _('Environments'),
+ _('Feature Flags'),
+ _('Product Analytics')
]
},
analytics_nav_item,
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 113252a6ab5..84910d0dfe4 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
@@ -85,7 +85,7 @@ RSpec.shared_examples 'multiple issue boards' do
wait_for_requests
- expect(page).to have_selector('.board', count: 3)
+ expect(page).to have_selector('.board', count: 5)
in_boards_switcher_dropdown do
click_link board.name
@@ -93,7 +93,7 @@ RSpec.shared_examples 'multiple issue boards' do
wait_for_requests
- expect(page).to have_selector('.board', count: 2)
+ expect(page).to have_selector('.board', count: 4)
end
it 'maintains sidebar state over board switch' do
diff --git a/spec/support/shared_examples/controllers/access_tokens_controller_shared_examples.rb b/spec/support/shared_examples/controllers/access_tokens_controller_shared_examples.rb
new file mode 100644
index 00000000000..54d41f9a68c
--- /dev/null
+++ b/spec/support/shared_examples/controllers/access_tokens_controller_shared_examples.rb
@@ -0,0 +1,106 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'project access tokens available #index' do
+ let_it_be(:active_project_access_token) { create(:personal_access_token, user: bot_user) }
+ let_it_be(:inactive_project_access_token) { create(:personal_access_token, :revoked, user: bot_user) }
+
+ it 'retrieves active project access tokens' do
+ subject
+
+ expect(assigns(:active_project_access_tokens)).to contain_exactly(active_project_access_token)
+ end
+
+ it 'retrieves inactive project access tokens' do
+ subject
+
+ expect(assigns(:inactive_project_access_tokens)).to contain_exactly(inactive_project_access_token)
+ end
+
+ it 'lists all available scopes' do
+ subject
+
+ expect(assigns(:scopes)).to eq(Gitlab::Auth.resource_bot_scopes)
+ end
+
+ it 'retrieves newly created personal access token value' do
+ token_value = 'random-value'
+ allow(PersonalAccessToken).to receive(:redis_getdel).with("#{user.id}:#{project.id}").and_return(token_value)
+
+ subject
+
+ expect(assigns(:new_project_access_token)).to eq(token_value)
+ end
+end
+
+RSpec.shared_examples 'project access tokens available #create' do
+ def created_token
+ PersonalAccessToken.order(:created_at).last
+ end
+
+ it 'returns success message' do
+ subject
+
+ expect(response.flash[:notice]).to match('Your new project access token has been created.')
+ end
+
+ it 'creates project access token' do
+ subject
+
+ expect(created_token.name).to eq(access_token_params[:name])
+ expect(created_token.scopes).to eq(access_token_params[:scopes])
+ expect(created_token.expires_at).to eq(access_token_params[:expires_at])
+ end
+
+ it 'creates project bot user' do
+ subject
+
+ expect(created_token.user).to be_project_bot
+ end
+
+ it 'stores newly created token redis store' do
+ expect(PersonalAccessToken).to receive(:redis_store!)
+
+ subject
+ end
+
+ it { expect { subject }.to change { User.count }.by(1) }
+ it { expect { subject }.to change { PersonalAccessToken.count }.by(1) }
+
+ context 'when unsuccessful' do
+ before do
+ allow_next_instance_of(ResourceAccessTokens::CreateService) do |service|
+ allow(service).to receive(:execute).and_return ServiceResponse.error(message: 'Failed!')
+ end
+ end
+
+ it { expect(subject).to render_template(:index) }
+ end
+end
+
+RSpec.shared_examples 'project access tokens available #revoke' do
+ it 'calls delete user worker' do
+ expect(DeleteUserWorker).to receive(:perform_async).with(user.id, bot_user.id, skip_authorization: true)
+
+ subject
+ end
+
+ it 'removes membership of bot user' do
+ subject
+
+ expect(project.reload.bots).not_to include(bot_user)
+ 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
+end
diff --git a/spec/support/shared_examples/controllers/cache_control_shared_examples.rb b/spec/support/shared_examples/controllers/cache_control_shared_examples.rb
index 426d7f95222..5496e04e26c 100644
--- a/spec/support/shared_examples/controllers/cache_control_shared_examples.rb
+++ b/spec/support/shared_examples/controllers/cache_control_shared_examples.rb
@@ -2,7 +2,7 @@
RSpec.shared_examples 'project cache control headers' do
before do
- project.update(visibility_level: visibility_level)
+ project.update!(visibility_level: visibility_level)
end
context 'when project is public' do
diff --git a/spec/support/shared_examples/controllers/destroy_hook_shared_examples.rb b/spec/support/shared_examples/controllers/destroy_hook_shared_examples.rb
new file mode 100644
index 00000000000..710aa333dec
--- /dev/null
+++ b/spec/support/shared_examples/controllers/destroy_hook_shared_examples.rb
@@ -0,0 +1,36 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'Web hook destroyer' do
+ it 'displays a message about synchronous delete', :aggregate_failures do
+ expect_next_instance_of(WebHooks::DestroyService) do |instance|
+ expect(instance).to receive(:execute).with(anything).and_call_original
+ end
+
+ delete :destroy, params: params
+
+ expect(response).to have_gitlab_http_status(:found)
+ expect(flash[:notice]).to eq("#{hook.model_name.human} was deleted")
+ end
+
+ it 'displays a message about async delete', :aggregate_failures do
+ expect_next_instance_of(WebHooks::DestroyService) do |instance|
+ expect(instance).to receive(:execute).with(anything).and_return({ status: :success, async: true } )
+ end
+
+ delete :destroy, params: params
+
+ expect(response).to have_gitlab_http_status(:found)
+ expect(flash[:notice]).to eq("#{hook.model_name.human} was scheduled for deletion")
+ end
+
+ it 'displays an error if deletion failed', :aggregate_failures do
+ expect_next_instance_of(WebHooks::DestroyService) do |instance|
+ expect(instance).to receive(:execute).with(anything).and_return({ status: :error, async: true, message: "failed" } )
+ end
+
+ delete :destroy, params: params
+
+ expect(response).to have_gitlab_http_status(:found)
+ expect(flash[:alert]).to eq("failed")
+ end
+end
diff --git a/spec/support/shared_examples/controllers/githubish_import_controller_shared_examples.rb b/spec/support/shared_examples/controllers/githubish_import_controller_shared_examples.rb
index 8bc91f72b8c..2fcc88ef36a 100644
--- a/spec/support/shared_examples/controllers/githubish_import_controller_shared_examples.rb
+++ b/spec/support/shared_examples/controllers/githubish_import_controller_shared_examples.rb
@@ -262,7 +262,7 @@ RSpec.shared_examples 'a GitHub-ish import controller: POST create' do
context "when the namespace is owned by the GitLab user" do
before do
user.username = other_username
- user.save
+ user.save!
end
it "takes the existing namespace" do
diff --git a/spec/support/shared_examples/controllers/known_sign_in_shared_examples.rb b/spec/support/shared_examples/controllers/known_sign_in_shared_examples.rb
index 7f26155f9d6..3f147f942ba 100644
--- a/spec/support/shared_examples/controllers/known_sign_in_shared_examples.rb
+++ b/spec/support/shared_examples/controllers/known_sign_in_shared_examples.rb
@@ -59,7 +59,7 @@ RSpec.shared_examples 'known sign in' do
it 'notifies the user when the cookie is expired' do
stub_cookie
- Timecop.freeze((KnownSignIn::KNOWN_SIGN_IN_COOKIE_EXPIRY + 1.day).from_now) do
+ travel_to((KnownSignIn::KNOWN_SIGN_IN_COOKIE_EXPIRY + 1.day).from_now) do
expect_next_instance_of(NotificationService) do |instance|
expect(instance).to receive(:unknown_sign_in)
end
diff --git a/spec/support/shared_examples/controllers/milestone_tabs_shared_examples.rb b/spec/support/shared_examples/controllers/milestone_tabs_shared_examples.rb
index 925c45005f0..2d35b1681ea 100644
--- a/spec/support/shared_examples/controllers/milestone_tabs_shared_examples.rb
+++ b/spec/support/shared_examples/controllers/milestone_tabs_shared_examples.rb
@@ -2,9 +2,28 @@
RSpec.shared_examples 'milestone tabs' do
def go(path, extra_params = {})
- params = { namespace_id: project.namespace.to_param, project_id: project, id: milestone.iid }
+ get path, params: request_params.merge(extra_params)
+ end
+
+ describe '#issues' do
+ context 'as html' do
+ before do
+ go(:issues, format: 'html')
+ end
- get path, params: params.merge(extra_params)
+ it 'redirects to milestone#show' do
+ expect(response).to redirect_to(milestone_path)
+ end
+ end
+
+ context 'as json' do
+ it 'renders the issues tab template to a string' do
+ go(:issues, format: 'json')
+
+ expect(response).to render_template('shared/milestones/_issues_tab')
+ expect(json_response).to have_key('html')
+ end
+ end
end
describe '#merge_requests' do
diff --git a/spec/support/shared_examples/controllers/sessionless_auth_controller_shared_examples.rb b/spec/support/shared_examples/controllers/sessionless_auth_controller_shared_examples.rb
index f2a97a86df6..b67eb0d99fd 100644
--- a/spec/support/shared_examples/controllers/sessionless_auth_controller_shared_examples.rb
+++ b/spec/support/shared_examples/controllers/sessionless_auth_controller_shared_examples.rb
@@ -44,7 +44,7 @@ RSpec.shared_examples 'authenticates sessionless user' do |path, format, params|
.to increment(:user_unauthenticated_counter)
end
- personal_access_token.update(scopes: [:read_user])
+ personal_access_token.update!(scopes: [:read_user])
get path, params: default_params.merge(private_token: personal_access_token.token)
diff --git a/spec/support/shared_examples/controllers/unique_hll_events_examples.rb b/spec/support/shared_examples/controllers/unique_hll_events_examples.rb
index 7e5a225f020..cf7ee17ea13 100644
--- a/spec/support/shared_examples/controllers/unique_hll_events_examples.rb
+++ b/spec/support/shared_examples/controllers/unique_hll_events_examples.rb
@@ -1,47 +1,24 @@
# frozen_string_literal: true
+#
+# Requires a context containing:
+# - request
+# - expected_type
+# - target_id
RSpec.shared_examples 'tracking unique hll events' do |feature_flag|
- context 'when format is HTML' do
- let(:format) { :html }
+ it 'tracks unique event' do
+ expect(Gitlab::UsageDataCounters::HLLRedisCounter).to receive(:track_event).with(expected_type, target_id)
- it 'tracks unique event' do
- expect(Gitlab::UsageDataCounters::HLLRedisCounter).to receive(:track_event).with(expected_type, target_id)
-
- subject
- end
-
- it 'tracks unique event if DNT is not enabled' do
- expect(Gitlab::UsageDataCounters::HLLRedisCounter).to receive(:track_event).with(expected_type, target_id)
- request.headers['DNT'] = '0'
-
- subject
- end
-
- it 'does not track unique event if DNT is enabled' do
- expect(Gitlab::UsageDataCounters::HLLRedisCounter).not_to receive(:track_event).with(expected_type, target_id)
- request.headers['DNT'] = '1'
-
- subject
- end
-
- context 'when feature flag is disabled' do
- it 'does not track unique event' do
- stub_feature_flags(feature_flag => false)
-
- expect(Gitlab::UsageDataCounters::HLLRedisCounter).not_to receive(:track_event).with(expected_type, target_id)
-
- subject
- end
- end
+ request
end
- context 'when format is JSON' do
- let(:format) { :json }
+ context 'when feature flag is disabled' do
+ it 'does not track unique event' do
+ stub_feature_flags(feature_flag => false)
- it 'does not track unique event if the format is JSON' do
- expect(Gitlab::UsageDataCounters::HLLRedisCounter).not_to receive(:track_event).with(expected_type, target_id)
+ expect(Gitlab::UsageDataCounters::HLLRedisCounter).not_to receive(:track_event)
- subject
+ request
end
end
end
diff --git a/spec/support/shared_examples/controllers/wiki_actions_shared_examples.rb b/spec/support/shared_examples/controllers/wiki_actions_shared_examples.rb
index 4ca400dd87b..a6ad8fc594c 100644
--- a/spec/support/shared_examples/controllers/wiki_actions_shared_examples.rb
+++ b/spec/support/shared_examples/controllers/wiki_actions_shared_examples.rb
@@ -15,10 +15,10 @@ RSpec.shared_examples 'wiki controller actions' do
end
describe 'GET #new' do
- subject { get :new, params: routing_params }
+ subject(:request) { get :new, params: routing_params }
it 'redirects to #show and appends a `random_title` param' do
- subject
+ request
expect(response).to be_redirect
expect(response.redirect_url).to match(%r{
@@ -35,7 +35,7 @@ RSpec.shared_examples 'wiki controller actions' do
end
it 'redirects to the wiki container and displays an error message' do
- subject
+ request
expect(response).to redirect_to(container)
expect(flash[:notice]).to eq('Could not create Wiki Repository at this time. Please try again later.')
@@ -146,13 +146,13 @@ RSpec.shared_examples 'wiki controller actions' do
let(:random_title) { nil }
- subject { get :show, params: routing_params.merge(id: id, random_title: random_title) }
+ subject(:request) { get :show, params: routing_params.merge(id: id, random_title: random_title) }
context 'when page exists' do
let(:id) { wiki_title }
it 'renders the page' do
- subject
+ request
expect(response).to have_gitlab_http_status(:ok)
expect(response).to render_template('shared/wikis/show')
@@ -161,19 +161,26 @@ RSpec.shared_examples 'wiki controller actions' do
expect(assigns(:sidebar_limited)).to be(false)
end
- it 'increases the page view counter' do
- expect do
- subject
+ context 'page view tracking' do
+ it_behaves_like 'tracking unique hll events', :track_unique_wiki_page_views do
+ let(:target_id) { 'wiki_action' }
+ let(:expected_type) { instance_of(String) }
+ end
- expect(response).to have_gitlab_http_status(:ok)
- end.to change { Gitlab::UsageDataCounters::WikiPageCounter.read(:view) }.by(1)
+ it 'increases the page view counter' do
+ expect do
+ request
+
+ expect(response).to have_gitlab_http_status(:ok)
+ end.to change { Gitlab::UsageDataCounters::WikiPageCounter.read(:view) }.by(1)
+ end
end
context 'when page content encoding is invalid' do
it 'sets flash error' do
allow(controller).to receive(:valid_encoding?).and_return(false)
- subject
+ request
expect(response).to have_gitlab_http_status(:ok)
expect(response).to render_template('shared/wikis/show')
@@ -187,7 +194,7 @@ RSpec.shared_examples 'wiki controller actions' do
context 'when the user can create pages' do
before do
- subject
+ request
expect(response).to have_gitlab_http_status(:ok)
expect(response).to render_template('shared/wikis/edit')
@@ -212,7 +219,7 @@ RSpec.shared_examples 'wiki controller actions' do
end
it 'shows the empty state' do
- subject
+ request
expect(response).to have_gitlab_http_status(:ok)
expect(response).to render_template('shared/wikis/empty')
@@ -226,10 +233,10 @@ RSpec.shared_examples 'wiki controller actions' do
where(:file_name) { ['dk.png', 'unsanitized.svg', 'git-cheat-sheet.pdf'] }
with_them do
- let(:id) { upload_file_to_wiki(container, user, file_name) }
+ let(:id) { upload_file_to_wiki(wiki, user, file_name) }
it 'delivers the file with the correct headers' do
- subject
+ request
expect(response).to have_gitlab_http_status(:ok)
expect(response.headers['Content-Disposition']).to match(/^inline/)
@@ -255,7 +262,7 @@ RSpec.shared_examples 'wiki controller actions' do
let(:id_param) { 'invalid' }
it 'redirects to show' do
- subject
+ request
expect(response).to redirect_to_wiki(wiki, 'invalid')
end
@@ -265,7 +272,7 @@ RSpec.shared_examples 'wiki controller actions' do
let(:id_param) { ' ' }
it 'redirects to the home page' do
- subject
+ request
expect(response).to redirect_to_wiki(wiki, 'home')
end
@@ -275,7 +282,7 @@ RSpec.shared_examples 'wiki controller actions' do
it 'redirects to show' do
allow(controller).to receive(:valid_encoding?).and_return(false)
- subject
+ request
expect(response).to redirect_to_wiki(wiki, wiki.list_pages.first)
end
@@ -288,7 +295,7 @@ RSpec.shared_examples 'wiki controller actions' do
allow(page).to receive(:content).and_return(nil)
allow(controller).to receive(:page).and_return(page)
- subject
+ request
expect(response).to redirect_to_wiki(wiki, page)
end
@@ -298,7 +305,7 @@ RSpec.shared_examples 'wiki controller actions' do
describe 'GET #edit' do
let(:id_param) { wiki_title }
- subject { get(:edit, params: routing_params.merge(id: id_param)) }
+ subject(:request) { get(:edit, params: routing_params.merge(id: id_param)) }
it_behaves_like 'edit action'
@@ -306,7 +313,7 @@ RSpec.shared_examples 'wiki controller actions' do
render_views
it 'shows the edit page' do
- subject
+ request
expect(response).to have_gitlab_http_status(:ok)
expect(response.body).to include(s_('Wiki|Edit Page'))
@@ -319,7 +326,7 @@ RSpec.shared_examples 'wiki controller actions' do
let(:new_content) { 'New content' }
let(:id_param) { wiki_title }
- subject do
+ subject(:request) do
patch(:update,
params: routing_params.merge(
id: id_param,
@@ -333,7 +340,7 @@ RSpec.shared_examples 'wiki controller actions' do
render_views
it 'updates the page' do
- subject
+ request
wiki_page = wiki.list_pages(load_content: true).first
@@ -348,7 +355,7 @@ RSpec.shared_examples 'wiki controller actions' do
end
it 'renders the empty state' do
- subject
+ request
expect(response).to render_template('shared/wikis/empty')
end
@@ -359,7 +366,7 @@ RSpec.shared_examples 'wiki controller actions' do
let(:new_title) { 'New title' }
let(:new_content) { 'New content' }
- subject do
+ subject(:request) do
post(:create,
params: routing_params.merge(
wiki: { title: new_title, content: new_content }
@@ -369,7 +376,7 @@ RSpec.shared_examples 'wiki controller actions' do
context 'when page is valid' do
it 'creates the page' do
expect do
- subject
+ request
end.to change { wiki.list_pages.size }.by 1
wiki_page = wiki.find_page(new_title)
@@ -384,7 +391,7 @@ RSpec.shared_examples 'wiki controller actions' do
it 'renders the edit state' do
expect do
- subject
+ request
end.not_to change { wiki.list_pages.size }
expect(response).to render_template('shared/wikis/edit')
@@ -395,7 +402,7 @@ RSpec.shared_examples 'wiki controller actions' do
describe 'DELETE #destroy' do
let(:id_param) { wiki_title }
- subject do
+ subject(:request) do
delete(:destroy,
params: routing_params.merge(
id: id_param
@@ -405,7 +412,7 @@ RSpec.shared_examples 'wiki controller actions' do
context 'when page exists' do
it 'deletes the page' do
expect do
- subject
+ request
end.to change { wiki.list_pages.size }.by(-1)
end
@@ -418,7 +425,7 @@ RSpec.shared_examples 'wiki controller actions' do
it 'renders the edit state' do
expect do
- subject
+ request
end.not_to change { wiki.list_pages.size }
expect(response).to render_template('shared/wikis/edit')
@@ -432,7 +439,7 @@ RSpec.shared_examples 'wiki controller actions' do
it 'renders 404' do
expect do
- subject
+ request
end.not_to change { wiki.list_pages.size }
expect(response).to have_gitlab_http_status(:not_found)
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 c9910487798..2fff4137934 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
@@ -11,6 +11,15 @@ RSpec.shared_examples 'an editable merge request' do
expect(page).to have_content user.name
end
+ find('.js-reviewer-search').click
+ page.within '.dropdown-menu-user' do
+ click_link user.name
+ end
+ expect(find('input[name="merge_request[reviewer_ids][]"]', visible: false).value).to match(user.id.to_s)
+ page.within '.js-reviewer-search' do
+ expect(page).to have_content user.name
+ end
+
click_button 'Milestone'
page.within '.issue-milestone' do
click_link milestone.title
@@ -38,6 +47,10 @@ RSpec.shared_examples 'an editable merge request' do
expect(page).to have_content user.name
end
+ page.within '.reviewer' do
+ expect(page).to have_content user.name
+ end
+
page.within '.milestone' do
expect(page).to have_content milestone.title
end
@@ -69,7 +82,7 @@ RSpec.shared_examples 'an editable merge request' do
end
it 'warns about version conflict' do
- merge_request.update(title: "New title")
+ merge_request.update!(title: "New title")
fill_in 'merge_request_title', with: 'bug 345'
fill_in 'merge_request_description', with: 'bug description'
@@ -124,16 +137,3 @@ end
def get_textarea_height
page.evaluate_script('document.getElementById("merge_request_description").offsetHeight')
end
-
-RSpec.shared_examples 'an editable merge request with reviewers' do
- it 'updates merge request', :js do
- find('.js-reviewer-search').click
- page.within '.dropdown-menu-user' do
- click_link user.name
- end
- expect(find('input[name="merge_request[reviewer_ids][]"]', visible: false).value).to match(user.id.to_s)
- page.within '.js-reviewer-search' do
- expect(page).to have_content user.name
- end
- end
-end
diff --git a/spec/support/shared_examples/features/issuable_invite_members_shared_examples.rb b/spec/support/shared_examples/features/issuable_invite_members_shared_examples.rb
new file mode 100644
index 00000000000..ac1cc2da7e3
--- /dev/null
+++ b/spec/support/shared_examples/features/issuable_invite_members_shared_examples.rb
@@ -0,0 +1,68 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'issuable invite members experiments' do
+ context 'when invite_members_version_a experiment is enabled' do
+ before do
+ stub_experiment_for_user(invite_members_version_a: true)
+ end
+
+ it 'shows a link for inviting members and follows through to the members page' do
+ project.add_maintainer(user)
+ visit issuable_path
+
+ find('.block.assignee .edit-link').click
+
+ wait_for_requests
+
+ page.within '.dropdown-menu-user' do
+ expect(page).to have_link('Invite Members', href: project_project_members_path(project))
+ expect(page).to have_selector('[data-track-event="click_invite_members"]')
+ expect(page).to have_selector('[data-track-label="edit_assignee"]')
+ end
+
+ click_link 'Invite Members'
+
+ expect(current_path).to eq project_project_members_path(project)
+ end
+ end
+
+ context 'when invite_members_version_b experiment is enabled' do
+ before do
+ stub_experiment_for_user(invite_members_version_b: true)
+ end
+
+ it 'shows a link for inviting members and follows through to modal' do
+ project.add_developer(user)
+ visit issuable_path
+
+ find('.block.assignee .edit-link').click
+
+ wait_for_requests
+
+ page.within '.dropdown-menu-user' do
+ expect(page).to have_link('Invite Members', href: '#')
+ expect(page).to have_selector('[data-track-event="click_invite_members_version_b"]')
+ expect(page).to have_selector('[data-track-label="edit_assignee"]')
+ end
+
+ click_link 'Invite Members'
+
+ expect(page).to have_content("Oops, this feature isn't ready yet")
+ end
+ end
+
+ context 'when no invite members experiments are enabled' do
+ it 'shows author in assignee dropdown and no invite link' do
+ project.add_maintainer(user)
+ visit issuable_path
+
+ find('.block.assignee .edit-link').click
+
+ wait_for_requests
+
+ page.within '.dropdown-menu-user' do
+ expect(page).not_to have_link('Invite Members')
+ end
+ end
+ end
+end
diff --git a/spec/support/shared_examples/features/multiple_assignees_mr_shared_examples.rb b/spec/support/shared_examples/features/multiple_assignees_mr_shared_examples.rb
index 19a5750cf6d..9d023d9514a 100644
--- a/spec/support/shared_examples/features/multiple_assignees_mr_shared_examples.rb
+++ b/spec/support/shared_examples/features/multiple_assignees_mr_shared_examples.rb
@@ -38,7 +38,7 @@ RSpec.shared_examples 'multiple assignees merge request' do |action, save_button
page.within '.issuable-sidebar' do
page.within '.assignee' do
# Closing dropdown to persist
- click_link 'Edit'
+ click_link 'Apply'
expect(page).to have_content user2.name
end
diff --git a/spec/support/shared_examples/features/multiple_reviewers_mr_shared_examples.rb b/spec/support/shared_examples/features/multiple_reviewers_mr_shared_examples.rb
new file mode 100644
index 00000000000..48cde90bd9b
--- /dev/null
+++ b/spec/support/shared_examples/features/multiple_reviewers_mr_shared_examples.rb
@@ -0,0 +1,47 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'multiple reviewers merge request' do |action, save_button_title|
+ it "#{action} a MR with multiple reviewers", :js do
+ find('.js-reviewer-search').click
+ page.within '.dropdown-menu-user' do
+ click_link user.name
+ click_link user2.name
+ end
+
+ # Extra click needed in order to toggle the dropdown
+ find('.js-reviewer-search').click
+
+ expect(all('input[name="merge_request[reviewer_ids][]"]', visible: false).map(&:value))
+ .to match_array([user.id.to_s, user2.id.to_s])
+
+ page.within '.js-reviewer-search' do
+ expect(page).to have_content "#{user2.name} + 1 more"
+ end
+
+ click_button save_button_title
+
+ page.within '.issuable-sidebar' do
+ page.within '.reviewer' do
+ expect(page).to have_content '2 Reviewers'
+
+ click_link 'Edit'
+
+ expect(page).to have_content user.name
+ expect(page).to have_content user2.name
+ end
+ end
+
+ page.within '.dropdown-menu-user' do
+ click_link user.name
+ end
+
+ page.within '.issuable-sidebar' do
+ page.within '.reviewer' do
+ # Closing dropdown to persist
+ click_link 'Edit'
+
+ expect(page).to have_content user2.name
+ end
+ end
+ end
+end
diff --git a/spec/support/shared_examples/features/navbar_shared_examples.rb b/spec/support/shared_examples/features/navbar_shared_examples.rb
index 91a4048fa7c..c768e95c45a 100644
--- a/spec/support/shared_examples/features/navbar_shared_examples.rb
+++ b/spec/support/shared_examples/features/navbar_shared_examples.rb
@@ -3,12 +3,14 @@
RSpec.shared_examples 'verified navigation bar' do
let(:expected_structure) do
structure.compact!
- structure.each { |s| s[:nav_sub_items].compact! }
+ structure.each { |s| s[:nav_sub_items]&.compact! }
structure
end
it 'renders correctly' do
current_structure = page.all('.sidebar-top-level-items > li', class: ['!hidden']).map do |item|
+ next if item.find_all('a').empty?
+
nav_item = item.find_all('a').first.text.gsub(/\s+\d+$/, '') # remove counts at the end
nav_sub_items = item.all('.sidebar-sub-level-items > li', class: ['!fly-out-top-item']).map do |list_item|
@@ -16,7 +18,7 @@ RSpec.shared_examples 'verified navigation bar' do
end
{ nav_item: nav_item, nav_sub_items: nav_sub_items }
- end
+ end.compact
expect(current_structure).to eq(expected_structure)
end
diff --git a/spec/support/shared_examples/features/packages_shared_examples.rb b/spec/support/shared_examples/features/packages_shared_examples.rb
index f201421e827..4d2e13aa5bc 100644
--- a/spec/support/shared_examples/features/packages_shared_examples.rb
+++ b/spec/support/shared_examples/features/packages_shared_examples.rb
@@ -84,11 +84,11 @@ RSpec.shared_examples 'shared package sorting' do
let(:packages) { [package_two, package_one] }
end
- it_behaves_like 'correctly sorted packages list', 'Created' do
+ it_behaves_like 'correctly sorted packages list', 'Published' do
let(:packages) { [package_two, package_one] }
end
- it_behaves_like 'correctly sorted packages list', 'Created', ascending: true do
+ it_behaves_like 'correctly sorted packages list', 'Published', ascending: true do
let(:packages) { [package_one, package_two] }
end
end
diff --git a/spec/support/shared_examples/features/page_description_shared_examples.rb b/spec/support/shared_examples/features/page_description_shared_examples.rb
new file mode 100644
index 00000000000..81653220b4c
--- /dev/null
+++ b/spec/support/shared_examples/features/page_description_shared_examples.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'page meta description' do |expected_description|
+ it 'renders the page with description, og:description, and twitter:description meta tags that contains a plain-text version of the markdown', :aggregate_failures do
+ %w(name='description' property='og:description' property='twitter:description').each do |selector|
+ expect(page).to have_selector("meta[#{selector}][content='#{expected_description}']", visible: false)
+ end
+ end
+end
diff --git a/spec/support/shared_examples/features/protected_branches_with_deploy_keys_examples.rb b/spec/support/shared_examples/features/protected_branches_with_deploy_keys_examples.rb
new file mode 100644
index 00000000000..a2d2143271c
--- /dev/null
+++ b/spec/support/shared_examples/features/protected_branches_with_deploy_keys_examples.rb
@@ -0,0 +1,95 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'when the deploy_keys_on_protected_branches FF is turned on' do
+ before do
+ stub_feature_flags(deploy_keys_on_protected_branches: true)
+ project.add_maintainer(user)
+ sign_in(user)
+ end
+
+ let(:dropdown_sections_minus_deploy_keys) { all_dropdown_sections - ['Deploy Keys'] }
+
+ context 'when deploy keys are enabled to this project' do
+ let!(:deploy_key_1) { create(:deploy_key, title: 'title 1', projects: [project]) }
+ let!(:deploy_key_2) { create(:deploy_key, title: 'title 2', projects: [project]) }
+
+ context 'when only one deploy key can push' do
+ before do
+ deploy_key_1.deploy_keys_projects.first.update!(can_push: true)
+ end
+
+ it "shows all dropdown sections in the 'Allowed to push' main dropdown, with only one deploy key" do
+ visit project_protected_branches_path(project)
+
+ find(".js-allowed-to-push").click
+ wait_for_requests
+
+ within('.qa-allowed-to-push-dropdown') do
+ dropdown_headers = page.all('.dropdown-header').map(&:text)
+
+ expect(dropdown_headers).to contain_exactly(*all_dropdown_sections)
+ expect(page).to have_content('title 1')
+ expect(page).not_to have_content('title 2')
+ end
+ end
+
+ it "shows all sections but not deploy keys in the 'Allowed to merge' main dropdown" do
+ visit project_protected_branches_path(project)
+
+ find(".js-allowed-to-merge").click
+ wait_for_requests
+
+ within('.qa-allowed-to-merge-dropdown') do
+ dropdown_headers = page.all('.dropdown-header').map(&:text)
+
+ expect(dropdown_headers).to contain_exactly(*dropdown_sections_minus_deploy_keys)
+ end
+ end
+
+ it "shows all sections in the 'Allowed to push' update dropdown" do
+ create(:protected_branch, :no_one_can_push, project: project, name: 'master')
+
+ visit project_protected_branches_path(project)
+
+ within(".js-protected-branch-edit-form") do
+ find(".js-allowed-to-push").click
+ wait_for_requests
+
+ dropdown_headers = page.all('.dropdown-header').map(&:text)
+
+ expect(dropdown_headers).to contain_exactly(*all_dropdown_sections)
+ end
+ end
+ end
+
+ context 'when no deploy key can push' do
+ it "just shows all sections but not deploy keys in the 'Allowed to push' dropdown" do
+ visit project_protected_branches_path(project)
+
+ find(".js-allowed-to-push").click
+ wait_for_requests
+
+ within('.qa-allowed-to-push-dropdown') do
+ dropdown_headers = page.all('.dropdown-header').map(&:text)
+
+ expect(dropdown_headers).to contain_exactly(*dropdown_sections_minus_deploy_keys)
+ end
+ end
+
+ it "just shows all sections but not deploy keys in the 'Allowed to push' update dropdown" do
+ create(:protected_branch, :no_one_can_push, project: project, name: 'master')
+
+ visit project_protected_branches_path(project)
+
+ within(".js-protected-branch-edit-form") do
+ find(".js-allowed-to-push").click
+ wait_for_requests
+
+ dropdown_headers = page.all('.dropdown-header').map(&:text)
+
+ expect(dropdown_headers).to contain_exactly(*dropdown_sections_minus_deploy_keys)
+ end
+ end
+ end
+ end
+end
diff --git a/spec/support/shared_examples/features/snippets_shared_examples.rb b/spec/support/shared_examples/features/snippets_shared_examples.rb
index 8d68b1e4c0a..bd1a67f3bb5 100644
--- a/spec/support/shared_examples/features/snippets_shared_examples.rb
+++ b/spec/support/shared_examples/features/snippets_shared_examples.rb
@@ -84,7 +84,7 @@ RSpec.shared_examples 'show and render proper snippet blob' do
expect(page).not_to have_selector('.js-blob-viewer-switcher')
# shows an enabled copy button
- expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)')
+ expect(page).to have_button('Copy file contents', disabled: false)
# shows a raw button
expect(page).to have_link('Open raw')
@@ -106,7 +106,6 @@ RSpec.shared_examples 'show and render proper snippet blob' do
it 'displays the blob using the rich viewer' do
aggregate_failures do
# hides the simple viewer
- expect(page).to have_selector('.blob-viewer[data-type="simple"]', visible: false)
expect(page).to have_selector('.blob-viewer[data-type="rich"]')
# shows rendered Markdown
@@ -116,7 +115,7 @@ RSpec.shared_examples 'show and render proper snippet blob' do
expect(page).to have_selector('.js-blob-viewer-switcher')
# shows a disabled copy button
- expect(page).to have_selector('.js-copy-blob-source-btn.disabled')
+ expect(page).to have_button('Copy file contents', disabled: true)
# shows a raw button
expect(page).to have_link('Open raw')
@@ -128,7 +127,7 @@ RSpec.shared_examples 'show and render proper snippet blob' do
context 'switching to the simple viewer' do
before do
- find('.js-blob-viewer-switch-btn[data-viewer=simple]').click
+ find_button('Display source').click
wait_for_requests
end
@@ -137,19 +136,18 @@ RSpec.shared_examples 'show and render proper snippet blob' do
aggregate_failures do
# hides the rich viewer
expect(page).to have_selector('.blob-viewer[data-type="simple"]')
- expect(page).to have_selector('.blob-viewer[data-type="rich"]', visible: false)
# shows highlighted Markdown code
expect(page).to have_content("[PEP-8](http://www.python.org/dev/peps/pep-0008/)")
# shows an enabled copy button
- expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)')
+ expect(page).to have_button('Copy file contents', disabled: false)
end
end
context 'switching to the rich viewer again' do
before do
- find('.js-blob-viewer-switch-btn[data-viewer=rich]').click
+ find_button('Display rendered file').click
wait_for_requests
end
@@ -157,11 +155,11 @@ RSpec.shared_examples 'show and render proper snippet blob' do
it 'displays the blob using the rich viewer' do
aggregate_failures do
# hides the simple viewer
- expect(page).to have_selector('.blob-viewer[data-type="simple"]', visible: false)
expect(page).to have_selector('.blob-viewer[data-type="rich"]')
- # shows an enabled copy button
- expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)')
+ # Used to show an enabled copy button since the code has already been fetched
+ # Will be resolved in https://gitlab.com/gitlab-org/gitlab/-/issues/262389
+ expect(page).to have_button('Copy file contents', disabled: true)
end
end
end
@@ -169,7 +167,8 @@ RSpec.shared_examples 'show and render proper snippet blob' do
end
context 'visiting with a line number anchor' do
- let(:anchor) { 'L1' }
+ # L1 used to work and will be revisited in https://gitlab.com/gitlab-org/gitlab/-/issues/262391
+ let(:anchor) { 'LC1' }
it 'displays the blob using the simple viewer' do
subject
@@ -177,7 +176,6 @@ RSpec.shared_examples 'show and render proper snippet blob' do
aggregate_failures do
# hides the rich viewer
expect(page).to have_selector('.blob-viewer[data-type="simple"]')
- expect(page).to have_selector('.blob-viewer[data-type="rich"]', visible: false)
# highlights the line in question
expect(page).to have_selector('#LC1.hll')
@@ -186,7 +184,7 @@ RSpec.shared_examples 'show and render proper snippet blob' do
expect(page).to have_content("[PEP-8](http://www.python.org/dev/peps/pep-0008/)")
# shows an enabled copy button
- expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)')
+ expect(page).to have_button('Copy file contents', disabled: false)
end
end
end
diff --git a/spec/support/shared_examples/features/wiki/file_attachments_shared_examples.rb b/spec/support/shared_examples/features/wiki/file_attachments_shared_examples.rb
new file mode 100644
index 00000000000..0ef1ccdfe57
--- /dev/null
+++ b/spec/support/shared_examples/features/wiki/file_attachments_shared_examples.rb
@@ -0,0 +1,86 @@
+# frozen_string_literal: true
+
+# Requires a context containing:
+# wiki
+
+RSpec.shared_examples 'wiki file attachments' do
+ include DropzoneHelper
+
+ context 'uploading attachments', :js do
+ def attach_with_dropzone(wait = false)
+ dropzone_file([Rails.root.join('spec', 'fixtures', 'dk.png')], 0, wait)
+ end
+
+ context 'before uploading' do
+ it 'shows "Attach a file" button' do
+ expect(page).to have_button('Attach a file')
+ expect(page).not_to have_selector('.uploading-progress-container', visible: true)
+ end
+ end
+
+ context 'uploading is in progress', :capybara_ignore_server_errors do
+ it 'cancels uploading on clicking to "Cancel" button' do
+ slow_requests do
+ attach_with_dropzone
+
+ click_button 'Cancel'
+ end
+
+ expect(page).to have_button('Attach a file')
+ expect(page).not_to have_button('Cancel')
+ expect(page).not_to have_selector('.uploading-progress-container', visible: true)
+ end
+
+ it 'shows "Attaching a file" message on uploading 1 file' do
+ slow_requests do
+ attach_with_dropzone
+
+ expect(page).to have_selector('.attaching-file-message', visible: true, text: 'Attaching a file -')
+ end
+ end
+ end
+
+ context 'uploading is complete' do
+ it 'shows "Attach a file" button on uploading complete' do
+ attach_with_dropzone
+ wait_for_requests
+
+ expect(page).to have_button('Attach a file')
+ expect(page).not_to have_selector('.uploading-progress-container', visible: true)
+ end
+
+ it 'the markdown link is added to the page' do
+ fill_in(:wiki_content, with: '')
+ attach_with_dropzone(true)
+ wait_for_requests
+
+ expect(page.find('#wiki_content').value)
+ .to match(%r{\!\[dk\]\(uploads/\h{32}/dk\.png\)$})
+ end
+
+ it 'the links point to the wiki root url' do
+ attach_with_dropzone(true)
+ wait_for_requests
+
+ find('.js-md-preview-button').click
+ file_path = page.find('input[name="files[]"]', visible: :hidden).value
+ link = page.find('a.no-attachment-icon')['href']
+ img_link = page.find('a.no-attachment-icon img')['src']
+
+ expect(link).to eq img_link
+ expect(URI.parse(link).path).to eq File.join(wiki.wiki_base_path, file_path)
+ end
+
+ it 'the file has been added to the wiki repository' do
+ expect do
+ attach_with_dropzone(true)
+ wait_for_requests
+ end.to change { wiki.repository.ls_files('HEAD').count }.by(1)
+
+ file_path = page.find('input[name="files[]"]', visible: :hidden).value
+
+ expect(wiki.find_file(file_path, 'HEAD').path).not_to be_nil
+ end
+ end
+ end
+end
diff --git a/spec/support/shared_examples/features/wiki/user_creates_wiki_page_shared_examples.rb b/spec/support/shared_examples/features/wiki/user_creates_wiki_page_shared_examples.rb
new file mode 100644
index 00000000000..44d82d2e753
--- /dev/null
+++ b/spec/support/shared_examples/features/wiki/user_creates_wiki_page_shared_examples.rb
@@ -0,0 +1,245 @@
+# frozen_string_literal: true
+
+# Requires a context containing:
+# wiki
+# user
+
+RSpec.shared_examples 'User creates wiki page' do
+ include WikiHelpers
+
+ before do
+ sign_in(user)
+ end
+
+ context "when wiki is empty" do
+ before do |example|
+ visit wiki_path(wiki)
+
+ wait_for_svg_to_be_loaded(example)
+
+ click_link "Create your first page"
+ end
+
+ it "shows validation error message" do
+ page.within(".wiki-form") do
+ fill_in(:wiki_content, with: "")
+
+ click_on("Create page")
+ end
+
+ expect(page).to have_content("The form contains the following error:").and have_content("Content can't be blank")
+
+ page.within(".wiki-form") do
+ fill_in(:wiki_content, with: "[link test](test)")
+
+ click_on("Create page")
+ end
+
+ expect(page).to have_content("Home").and have_content("link test")
+
+ click_link("link test")
+
+ expect(page).to have_content("Create New Page")
+ end
+
+ it "shows non-escaped link in the pages list" do
+ fill_in(:wiki_title, with: "one/two/three-test")
+
+ page.within(".wiki-form") do
+ fill_in(:wiki_content, with: "wiki content")
+
+ click_on("Create page")
+ end
+
+ expect(current_path).to include("one/two/three-test")
+ expect(page).to have_link(href: wiki_page_path(wiki, 'one/two/three-test'))
+ end
+
+ it "has `Create home` as a commit message", :js do
+ wait_for_requests
+
+ expect(page).to have_field("wiki[message]", with: "Create home")
+ end
+
+ it "creates a page from the home page" do
+ fill_in(:wiki_content, with: "[test](test)\n[GitLab API doc](api)\n[Rake tasks](raketasks)\n# Wiki header\n")
+ fill_in(:wiki_message, with: "Adding links to wiki")
+
+ page.within(".wiki-form") do
+ click_button("Create page")
+ end
+
+ expect(current_path).to eq(wiki_page_path(wiki, "home"))
+ expect(page).to have_content("test GitLab API doc Rake tasks Wiki header")
+ .and have_content("Home")
+ .and have_content("Last edited by #{user.name}")
+ .and have_header_with_correct_id_and_link(1, "Wiki header", "wiki-header")
+
+ click_link("test")
+
+ expect(current_path).to eq(wiki_page_path(wiki, "test"))
+
+ page.within(:css, ".nav-text") do
+ expect(page).to have_content("Create New Page")
+ end
+
+ click_link("Home")
+
+ expect(current_path).to eq(wiki_page_path(wiki, "home"))
+
+ click_link("GitLab API")
+
+ expect(current_path).to eq(wiki_page_path(wiki, "api"))
+
+ page.within(:css, ".nav-text") do
+ expect(page).to have_content("Create")
+ end
+
+ click_link("Home")
+
+ expect(current_path).to eq(wiki_page_path(wiki, "home"))
+
+ click_link("Rake tasks")
+
+ expect(current_path).to eq(wiki_page_path(wiki, "raketasks"))
+
+ page.within(:css, ".nav-text") do
+ expect(page).to have_content("Create")
+ end
+ end
+
+ it "creates ASCII wiki with LaTeX blocks", :js do
+ stub_application_setting(plantuml_url: "http://localhost", plantuml_enabled: true)
+
+ ascii_content = <<~MD
+ :stem: latexmath
+
+ [stem]
+ ++++
+ \\sqrt{4} = 2
+ ++++
+
+ another part
+
+ [latexmath]
+ ++++
+ \\beta_x \\gamma
+ ++++
+
+ stem:[2+2] is 4
+ MD
+
+ find("#wiki_format option[value=asciidoc]").select_option
+
+ fill_in(:wiki_content, with: ascii_content)
+
+ page.within(".wiki-form") do
+ click_button("Create page")
+ end
+
+ page.within ".md" do
+ expect(page).to have_selector(".katex", count: 3).and have_content("2+2 is 4")
+ end
+ end
+
+ it 'creates a wiki page with Org markup', :aggregate_failures do
+ org_content = <<~ORG
+ * Heading
+ ** Subheading
+ [[home][Link to Home]]
+ ORG
+
+ page.within('.wiki-form') do
+ find('#wiki_format option[value=org]').select_option
+ fill_in(:wiki_content, with: org_content)
+ click_button('Create page')
+ end
+
+ expect(page).to have_selector('h1', text: 'Heading')
+ expect(page).to have_selector('h2', text: 'Subheading')
+ expect(page).to have_link(href: wiki_page_path(wiki, 'home'))
+ end
+
+ it_behaves_like 'wiki file attachments'
+ end
+
+ context "when wiki is not empty", :js do
+ before do
+ create(:wiki_page, wiki: wiki, title: 'home', content: 'Home page')
+
+ visit wiki_path(wiki)
+ end
+
+ context "via the `new wiki page` page" do
+ it "creates a page with a single word" do
+ click_link("New page")
+
+ page.within(".wiki-form") do
+ fill_in(:wiki_title, with: "foo")
+ fill_in(:wiki_content, with: "My awesome wiki!")
+ end
+
+ # Commit message field should have correct value.
+ expect(page).to have_field("wiki[message]", with: "Create foo")
+
+ click_button("Create page")
+
+ expect(page).to have_content("foo")
+ .and have_content("Last edited by #{user.name}")
+ .and have_content("My awesome wiki!")
+ end
+
+ it "creates a page with spaces in the name" do
+ click_link("New page")
+
+ page.within(".wiki-form") do
+ fill_in(:wiki_title, with: "Spaces in the name")
+ fill_in(:wiki_content, with: "My awesome wiki!")
+ end
+
+ # Commit message field should have correct value.
+ expect(page).to have_field("wiki[message]", with: "Create Spaces in the name")
+
+ click_button("Create page")
+
+ expect(page).to have_content("Spaces in the name")
+ .and have_content("Last edited by #{user.name}")
+ .and have_content("My awesome wiki!")
+ end
+
+ it "creates a page with hyphens in the name" do
+ click_link("New page")
+
+ page.within(".wiki-form") do
+ fill_in(:wiki_title, with: "hyphens-in-the-name")
+ fill_in(:wiki_content, with: "My awesome wiki!")
+ end
+
+ # Commit message field should have correct value.
+ expect(page).to have_field("wiki[message]", with: "Create hyphens in the name")
+
+ page.within(".wiki-form") do
+ fill_in(:wiki_content, with: "My awesome wiki!")
+
+ click_button("Create page")
+ end
+
+ expect(page).to have_content("hyphens in the name")
+ .and have_content("Last edited by #{user.name}")
+ .and have_content("My awesome wiki!")
+ end
+ end
+
+ it "shows the emoji autocompletion dropdown" do
+ click_link("New page")
+
+ page.within(".wiki-form") do
+ find("#wiki_content").native.send_keys("")
+
+ fill_in(:wiki_content, with: ":")
+ end
+
+ expect(page).to have_selector(".atwho-view")
+ end
+ end
+end
diff --git a/spec/support/shared_examples/features/wiki/user_deletes_wiki_page_shared_examples.rb b/spec/support/shared_examples/features/wiki/user_deletes_wiki_page_shared_examples.rb
new file mode 100644
index 00000000000..e1fd9c8dbec
--- /dev/null
+++ b/spec/support/shared_examples/features/wiki/user_deletes_wiki_page_shared_examples.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+# Requires a context containing:
+# wiki
+# user
+
+RSpec.shared_examples 'User deletes wiki page' do
+ include WikiHelpers
+
+ let(:wiki_page) { create(:wiki_page, wiki: wiki) }
+
+ before do
+ sign_in(user)
+ visit wiki_page_path(wiki, wiki_page)
+ end
+
+ it 'deletes a page', :js do
+ click_on('Edit')
+ click_on('Delete')
+ find('.modal-footer .btn-danger').click
+
+ expect(page).to have_content('Page was successfully deleted')
+ end
+end
diff --git a/spec/support/shared_examples/features/wiki/user_previews_wiki_changes_shared_examples.rb b/spec/support/shared_examples/features/wiki/user_previews_wiki_changes_shared_examples.rb
new file mode 100644
index 00000000000..a22d98f20c4
--- /dev/null
+++ b/spec/support/shared_examples/features/wiki/user_previews_wiki_changes_shared_examples.rb
@@ -0,0 +1,110 @@
+# frozen_string_literal: true
+
+# Requires a context containing:
+# wiki
+# user
+
+RSpec.shared_examples 'User previews wiki changes' do
+ let(:wiki_page) { build(:wiki_page, wiki: wiki) }
+
+ before do
+ sign_in(user)
+ end
+
+ shared_examples 'relative links' do
+ let_it_be(:page_content) do
+ <<~HEREDOC
+ Some text so key event for [ does not trigger an incorrect replacement.
+ [regular link](regular)
+ [relative link 1](../relative)
+ [relative link 2](./relative)
+ [relative link 3](./e/f/relative)
+ [spaced link](title with spaces)
+ HEREDOC
+ end
+
+ def relative_path(path)
+ (Pathname.new(wiki.wiki_base_path) + File.dirname(wiki_page.path).tr(' ', '-') + path).to_s
+ end
+
+ shared_examples "rewrites relative links" do
+ specify do
+ expect(element).to have_link('regular link', href: wiki.wiki_base_path + '/regular')
+ expect(element).to have_link('spaced link', href: wiki.wiki_base_path + '/title%20with%20spaces')
+
+ expect(element).to have_link('relative link 1', href: relative_path('../relative'))
+ expect(element).to have_link('relative link 2', href: relative_path('./relative'))
+ expect(element).to have_link('relative link 3', href: relative_path('./e/f/relative'))
+ end
+ end
+
+ context "when there are no spaces or hyphens in the page name" do
+ let(:wiki_page) { build(:wiki_page, wiki: wiki, title: 'a/b/c/d', content: page_content) }
+
+ it_behaves_like 'rewrites relative links'
+ end
+
+ context "when there are spaces in the page name" do
+ let(:wiki_page) { build(:wiki_page, wiki: wiki, title: 'a page/b page/c page/d page', content: page_content) }
+
+ it_behaves_like 'rewrites relative links'
+ end
+
+ context "when there are hyphens in the page name" do
+ let(:wiki_page) { build(:wiki_page, wiki: wiki, title: 'a-page/b-page/c-page/d-page', content: page_content) }
+
+ it_behaves_like 'rewrites relative links'
+ end
+ end
+
+ context "when rendering a new wiki page", :js do
+ before do
+ wiki_page.create # rubocop:disable Rails/SaveBang
+ visit wiki_page_path(wiki, wiki_page)
+ end
+
+ it_behaves_like 'relative links' do
+ let(:element) { page.find('[data-testid="wiki_page_content"]') }
+ end
+ end
+
+ context "when previewing an existing wiki page", :js do
+ let(:preview) { page.find('.md-preview-holder') }
+
+ before do
+ wiki_page.create # rubocop:disable Rails/SaveBang
+ visit wiki_page_path(wiki, wiki_page, action: :edit)
+ end
+
+ it_behaves_like 'relative links' do
+ before do
+ click_on 'Preview'
+ end
+
+ let(:element) { preview }
+ end
+
+ it 'renders content with CommonMark' do
+ fill_in :wiki_content, with: "1. one\n - sublist\n"
+ click_on "Preview"
+
+ # the above generates two separate lists (not embedded) in CommonMark
+ expect(preview).to have_content("sublist")
+ expect(preview).not_to have_xpath("//ol//li//ul")
+ end
+
+ it "does not linkify double brackets inside code blocks as expected" do
+ fill_in :wiki_content, with: <<-HEREDOC
+ `[[do_not_linkify]]`
+ ```
+ [[also_do_not_linkify]]
+ ```
+ HEREDOC
+ click_on "Preview"
+
+ expect(preview).to have_content("do_not_linkify")
+ expect(preview).to have_content('[[do_not_linkify]]')
+ expect(preview).to have_content('[[also_do_not_linkify]]')
+ end
+ end
+end
diff --git a/spec/support/shared_examples/features/wiki/user_updates_wiki_page_shared_examples.rb b/spec/support/shared_examples/features/wiki/user_updates_wiki_page_shared_examples.rb
new file mode 100644
index 00000000000..1a5f8d7d8df
--- /dev/null
+++ b/spec/support/shared_examples/features/wiki/user_updates_wiki_page_shared_examples.rb
@@ -0,0 +1,231 @@
+# frozen_string_literal: true
+
+# Requires a context containing:
+# wiki
+# user
+
+RSpec.shared_examples 'User updates wiki page' do
+ include WikiHelpers
+
+ before do
+ sign_in(user)
+ end
+
+ context 'when wiki is empty' do
+ before do |example|
+ visit(wiki_path(wiki))
+
+ wait_for_svg_to_be_loaded(example)
+
+ click_link "Create your first page"
+ end
+
+ it 'redirects back to the home edit page' do
+ page.within(:css, '.wiki-form .form-actions') do
+ click_on('Cancel')
+ end
+
+ expect(current_path).to eq wiki_path(wiki)
+ end
+
+ it 'updates a page that has a path', :js do
+ fill_in(:wiki_title, with: 'one/two/three-test')
+
+ page.within '.wiki-form' do
+ fill_in(:wiki_content, with: 'wiki content')
+ click_on('Create page')
+ end
+
+ expect(current_path).to include('one/two/three-test')
+ expect(find('.wiki-pages')).to have_content('three')
+
+ first(:link, text: 'three').click
+
+ expect(find('[data-testid="wiki_page_title"]')).to have_content('three')
+
+ click_on('Edit')
+
+ expect(current_path).to include('one/two/three-test')
+ expect(page).to have_content('Edit Page')
+
+ fill_in('Content', with: 'Updated Wiki Content')
+ click_on('Save changes')
+
+ expect(page).to have_content('Updated Wiki Content')
+ end
+
+ it_behaves_like 'wiki file attachments'
+ end
+
+ context 'when wiki is not empty' do
+ let!(:wiki_page) { create(:wiki_page, wiki: wiki, title: 'home', content: 'Home page') }
+
+ before do
+ visit(wiki_path(wiki))
+
+ click_link('Edit')
+ end
+
+ it 'updates a page', :js do
+ # Commit message field should have correct value.
+ expect(page).to have_field('wiki[message]', with: 'Update home')
+
+ fill_in(:wiki_content, with: 'My awesome wiki!')
+ click_button('Save changes')
+
+ expect(page).to have_content('Home')
+ expect(page).to have_content("Last edited by #{user.name}")
+ expect(page).to have_content('My awesome wiki!')
+ end
+
+ it 'updates the commit message as the title is changed', :js do
+ fill_in(:wiki_title, with: '& < > \ \ { } &')
+
+ expect(page).to have_field('wiki[message]', with: 'Update & < > \ \ { } &')
+ end
+
+ it 'correctly escapes the commit message entities', :js do
+ fill_in(:wiki_title, with: 'Wiki title')
+
+ expect(page).to have_field('wiki[message]', with: 'Update Wiki title')
+ end
+
+ it 'shows a validation error message' do
+ fill_in(:wiki_content, with: '')
+ click_button('Save changes')
+
+ expect(page).to have_selector('.wiki-form')
+ expect(page).to have_content('Edit Page')
+ expect(page).to have_content('The form contains the following error:')
+ expect(page).to have_content("Content can't be blank")
+ expect(find('textarea#wiki_content').value).to eq('')
+ end
+
+ it 'shows the emoji autocompletion dropdown', :js do
+ find('#wiki_content').native.send_keys('')
+ fill_in(:wiki_content, with: ':')
+
+ expect(page).to have_selector('.atwho-view')
+ end
+
+ it 'shows the error message' do
+ wiki_page.update(content: 'Update') # rubocop:disable Rails/SaveBang
+
+ click_button('Save changes')
+
+ expect(page).to have_content('Someone edited the page the same time you did.')
+ end
+
+ it 'updates a page' do
+ fill_in('Content', with: 'Updated Wiki Content')
+ click_on('Save changes')
+
+ expect(page).to have_content('Updated Wiki Content')
+ end
+
+ it 'cancels editing of a page' do
+ page.within(:css, '.wiki-form .form-actions') do
+ click_on('Cancel')
+ end
+
+ expect(current_path).to eq(wiki_page_path(wiki, wiki_page))
+ end
+
+ it_behaves_like 'wiki file attachments'
+ end
+
+ context 'when the page is in a subdir' do
+ let(:page_name) { 'page_name' }
+ let(:page_dir) { "foo/bar/#{page_name}" }
+ let!(:wiki_page) { create(:wiki_page, wiki: wiki, title: page_dir, content: 'Home page') }
+
+ before do
+ visit wiki_page_path(wiki, wiki_page, action: :edit)
+ end
+
+ it 'moves the page to the root folder' do
+ fill_in(:wiki_title, with: "/#{page_name}")
+
+ click_button('Save changes')
+
+ expect(current_path).to eq(wiki_page_path(wiki, page_name))
+ end
+
+ it 'moves the page to other dir' do
+ new_page_dir = "foo1/bar1/#{page_name}"
+
+ fill_in(:wiki_title, with: new_page_dir)
+
+ click_button('Save changes')
+
+ expect(current_path).to eq(wiki_page_path(wiki, new_page_dir))
+ end
+
+ it 'remains in the same place if title has not changed' do
+ original_path = wiki_page_path(wiki, wiki_page)
+
+ fill_in(:wiki_title, with: page_name)
+
+ click_button('Save changes')
+
+ expect(current_path).to eq(original_path)
+ end
+
+ it 'can be moved to a different dir with a different name' do
+ new_page_dir = "foo1/bar1/new_page_name"
+
+ fill_in(:wiki_title, with: new_page_dir)
+
+ click_button('Save changes')
+
+ expect(current_path).to eq(wiki_page_path(wiki, new_page_dir))
+ end
+
+ it 'can be renamed and moved to the root folder' do
+ new_name = 'new_page_name'
+
+ fill_in(:wiki_title, with: "/#{new_name}")
+
+ click_button('Save changes')
+
+ expect(current_path).to eq(wiki_page_path(wiki, new_name))
+ end
+
+ it 'squishes the title before creating the page' do
+ new_page_dir = " foo1 / bar1 / #{page_name} "
+
+ fill_in(:wiki_title, with: new_page_dir)
+
+ click_button('Save changes')
+
+ expect(current_path).to eq(wiki_page_path(wiki, "foo1/bar1/#{page_name}"))
+ end
+
+ it_behaves_like 'wiki file attachments'
+ end
+
+ context 'when an existing page exceeds the content size limit' do
+ let!(:wiki_page) { create(:wiki_page, wiki: wiki, content: "one\ntwo\nthree") }
+
+ before do
+ stub_application_setting(wiki_page_max_content_bytes: 10)
+
+ visit wiki_page_path(wiki_page.wiki, wiki_page, action: :edit)
+ end
+
+ it 'allows changing the title if the content does not change' do
+ fill_in 'Title', with: 'new title'
+ click_on 'Save changes'
+
+ expect(page).to have_content('Wiki was successfully updated.')
+ end
+
+ it 'shows a validation error when trying to change the content' do
+ fill_in 'Content', with: 'new content'
+ click_on 'Save changes'
+
+ expect(page).to have_content('The form contains the following error:')
+ expect(page).to have_content('Content is too long (11 Bytes). The maximum size is 10 Bytes.')
+ end
+ end
+end
diff --git a/spec/support/shared_examples/features/wiki/user_uses_wiki_shortcuts_shared_examples.rb b/spec/support/shared_examples/features/wiki/user_uses_wiki_shortcuts_shared_examples.rb
new file mode 100644
index 00000000000..0330b345a18
--- /dev/null
+++ b/spec/support/shared_examples/features/wiki/user_uses_wiki_shortcuts_shared_examples.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+# Requires a context containing:
+# wiki
+# user
+
+RSpec.shared_examples 'User uses wiki shortcuts' do
+ let(:wiki_page) { create(:wiki_page, wiki: wiki, title: 'home', content: 'Home page') }
+
+ before do
+ sign_in(user)
+ visit wiki_page_path(wiki, wiki_page)
+ end
+
+ it 'Visit edit wiki page using "e" keyboard shortcut', :js do
+ find('body').native.send_key('e')
+
+ expect(find('.wiki-page-title')).to have_content('Edit Page')
+ end
+end
diff --git a/spec/support/shared_examples/features/wiki/user_views_asciidoc_page_with_includes_shared_examples.rb b/spec/support/shared_examples/features/wiki/user_views_asciidoc_page_with_includes_shared_examples.rb
new file mode 100644
index 00000000000..3b2fda4e05b
--- /dev/null
+++ b/spec/support/shared_examples/features/wiki/user_views_asciidoc_page_with_includes_shared_examples.rb
@@ -0,0 +1,77 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'User views AsciiDoc page with includes' do
+ let_it_be(:wiki_content_selector) { '[data-qa-selector=wiki_page_content]' }
+ let!(:included_wiki_page) { create_wiki_page('included_page', content: 'Content from the included page')}
+ let!(:wiki_page) { create_wiki_page('home', content: "Content from the main page.\ninclude::included_page.asciidoc[]") }
+
+ def create_wiki_page(title, content:)
+ attrs = {
+ title: title,
+ content: content,
+ format: :asciidoc
+ }
+
+ create(:wiki_page, wiki: wiki, **attrs)
+ end
+
+ before do
+ sign_in(user)
+ end
+
+ context 'when the file being included exists', :js do
+ it 'includes the file contents' do
+ visit(wiki_page_path(wiki, wiki_page))
+
+ page.within(:css, wiki_content_selector) do
+ expect(page).to have_content('Content from the main page. Content from the included page')
+ end
+ end
+
+ context 'when there are multiple versions of the wiki pages' do
+ before do
+ # rubocop:disable Rails/SaveBang
+ included_wiki_page.update(message: 'updated included file', content: 'Updated content from the included page')
+ wiki_page.update(message: 'updated wiki page', content: "Updated content from the main page.\ninclude::included_page.asciidoc[]")
+ # rubocop:enable Rails/SaveBang
+ end
+
+ let(:latest_version_id) { wiki_page.versions.first.id }
+ let(:oldest_version_id) { wiki_page.versions.last.id }
+
+ context 'viewing the latest version' do
+ it 'includes the latest content' do
+ visit(wiki_page_path(wiki, wiki_page, version_id: latest_version_id))
+
+ page.within(:css, wiki_content_selector) do
+ expect(page).to have_content('Updated content from the main page. Updated content from the included page')
+ end
+ end
+ end
+
+ context 'viewing the original version' do
+ it 'includes the content from the original version' do
+ visit(wiki_page_path(wiki, wiki_page, version_id: oldest_version_id))
+
+ page.within(:css, wiki_content_selector) do
+ expect(page).to have_content('Content from the main page. Content from the included page')
+ end
+ end
+ end
+ end
+ end
+
+ context 'when the file being included does not exist', :js do
+ before do
+ included_wiki_page.delete
+ end
+
+ it 'outputs an error' do
+ visit(wiki_page_path(wiki, wiki_page))
+
+ page.within(:css, wiki_content_selector) do
+ expect(page).to have_content('Content from the main page. [ERROR: include::included_page.asciidoc[] - unresolved directive]')
+ end
+ end
+ end
+end
diff --git a/spec/support/shared_examples/features/wiki/user_views_wiki_empty_shared_examples.rb b/spec/support/shared_examples/features/wiki/user_views_wiki_empty_shared_examples.rb
new file mode 100644
index 00000000000..d7f5b485a82
--- /dev/null
+++ b/spec/support/shared_examples/features/wiki/user_views_wiki_empty_shared_examples.rb
@@ -0,0 +1,62 @@
+# frozen_string_literal: true
+
+# Requires a context containing:
+# wiki
+
+RSpec.shared_examples 'User views empty wiki' do
+ let(:element) { page.find('.row.empty-state') }
+ let(:container_name) { wiki.container.class.name.humanize(capitalize: false) }
+ let(:confluence_link) { 'Enable the Confluence Wiki integration' }
+
+ shared_examples 'wiki is not found' do
+ it 'shows an error message' do
+ visit wiki_path(wiki)
+
+ if @current_user
+ expect(page).to have_content('Page Not Found')
+ else
+ expect(page).to have_content('You need to sign in')
+ end
+ end
+ end
+
+ shared_examples 'empty wiki message' do |writable: false, issuable: false, confluence: false|
+ # This mirrors the logic in:
+ # - app/views/shared/empty_states/_wikis.html.haml
+ # - WikiHelper#wiki_empty_state_messages
+ it 'shows the empty state message with the expected elements' do
+ visit wiki_path(wiki)
+
+ if writable
+ expect(element).to have_content("The wiki lets you write documentation for your #{container_name}")
+ else
+ expect(element).to have_content("This #{container_name} has no wiki pages")
+ expect(element).to have_content("You must be a #{container_name} member")
+ end
+
+ if issuable && !writable
+ expect(element).to have_content("improve the wiki for this #{container_name}")
+ expect(element).to have_link("issue tracker", href: project_issues_path(project))
+ expect(element).to have_link("Suggest wiki improvement", href: new_project_issue_path(project))
+ else
+ expect(element).not_to have_content("improve the wiki for this #{container_name}")
+ expect(element).not_to have_link("issue tracker")
+ expect(element).not_to have_link("Suggest wiki improvement")
+ end
+
+ if confluence
+ expect(element).to have_link(confluence_link)
+ else
+ expect(element).not_to have_link(confluence_link)
+ end
+
+ if writable
+ element.click_link 'Create your first page'
+
+ expect(page).to have_button('Create page')
+ else
+ expect(element).not_to have_link('Create your first page')
+ end
+ end
+ end
+end
diff --git a/spec/support/shared_examples/features/wiki/user_views_wiki_page_shared_examples.rb b/spec/support/shared_examples/features/wiki/user_views_wiki_page_shared_examples.rb
new file mode 100644
index 00000000000..85eedbf4cc5
--- /dev/null
+++ b/spec/support/shared_examples/features/wiki/user_views_wiki_page_shared_examples.rb
@@ -0,0 +1,274 @@
+# frozen_string_literal: true
+
+# Requires a context containing:
+# wiki
+# user
+
+RSpec.shared_examples 'User views a wiki page' do
+ include WikiHelpers
+
+ let(:path) { 'image.png' }
+ let(:wiki_page) do
+ create(:wiki_page,
+ wiki: wiki,
+ title: 'home', content: "Look at this [image](#{path})\n\n ![alt text](#{path})")
+ end
+
+ before do
+ sign_in(user)
+ end
+
+ context 'when wiki is empty', :js do
+ before do
+ visit wiki_path(wiki)
+
+ wait_for_svg_to_be_loaded
+
+ click_link "Create your first page"
+
+ fill_in(:wiki_title, with: 'one/two/three-test')
+
+ page.within('.wiki-form') do
+ fill_in(:wiki_content, with: 'wiki content')
+ click_on('Create page')
+ end
+
+ expect(page).to have_content('Wiki was successfully updated.')
+ end
+
+ it 'shows the history of a page that has a path' do
+ expect(current_path).to include('one/two/three-test')
+
+ first(:link, text: 'three').click
+ click_on('Page history')
+
+ expect(current_path).to include('one/two/three-test')
+
+ page.within(:css, '.nav-text') do
+ expect(page).to have_content('History')
+ end
+ end
+
+ it 'shows an old version of a page' do
+ expect(current_path).to include('one/two/three-test')
+ expect(find('.wiki-pages')).to have_content('three')
+
+ first(:link, text: 'three').click
+
+ expect(find('[data-testid="wiki_page_title"]')).to have_content('three')
+
+ click_on('Edit')
+
+ expect(current_path).to include('one/two/three-test')
+ expect(page).to have_content('Edit Page')
+
+ fill_in('Content', with: 'Updated Wiki Content')
+ click_on('Save changes')
+
+ expect(page).to have_content('Wiki was successfully updated.')
+
+ click_on('Page history')
+
+ within('.nav-text') do
+ expect(page).to have_content('History')
+ end
+
+ within('.wiki-history') do
+ expect(page).to have_css('a[href*="?version_id"]', count: 4)
+ end
+ end
+ end
+
+ context 'when a page does not have history' do
+ before do
+ visit(wiki_page_path(wiki, wiki_page))
+ end
+
+ it 'shows all the pages' do
+ expect(page).to have_content(user.name)
+ expect(find('.wiki-pages')).to have_content(wiki_page.title.capitalize)
+ end
+
+ context 'shows a file stored in a page' do
+ let(:path) { upload_file_to_wiki(wiki, user, 'dk.png') }
+
+ it do
+ expect(page).to have_xpath("//img[@data-src='#{wiki.wiki_base_path}/#{path}']")
+ expect(page).to have_link('image', href: "#{wiki.wiki_base_path}/#{path}")
+
+ click_on('image')
+
+ expect(current_path).to match("wikis/#{path}")
+ expect(page).not_to have_xpath('/html') # Page should render the image which means there is no html involved
+ end
+ end
+
+ it 'shows the creation page if file does not exist' do
+ expect(page).to have_link('image', href: "#{wiki.wiki_base_path}/#{path}")
+
+ click_on('image')
+
+ expect(current_path).to match("wikis/#{path}")
+ expect(page).to have_content('Create New Page')
+ end
+ end
+
+ context 'when a page has history' do
+ before do
+ wiki_page.update(message: 'updated home', content: 'updated [some link](other-page)') # rubocop:disable Rails/SaveBang
+ end
+
+ it 'shows the page history' do
+ visit(wiki_page_path(wiki, wiki_page))
+
+ expect(page).to have_selector('[data-testid="wiki_edit_button"]')
+
+ click_on('Page history')
+
+ expect(page).to have_content(user.name)
+ expect(page).to have_content("#{user.username} created page: home")
+ expect(page).to have_content('updated home')
+ end
+
+ it 'does not show the "Edit" button' do
+ visit(wiki_page_path(wiki, wiki_page, version_id: wiki_page.versions.last.id))
+
+ expect(page).not_to have_selector('[data-testid="wiki_edit_button"]')
+ end
+
+ context 'show the diff' do
+ def expect_diff_links(commit)
+ diff_path = wiki_page_path(wiki, wiki_page, version_id: commit, action: :diff)
+
+ expect(page).to have_link('Hide whitespace changes', href: "#{diff_path}&w=1")
+ expect(page).to have_link('Inline', href: "#{diff_path}&view=inline")
+ expect(page).to have_link('Side-by-side', href: "#{diff_path}&view=parallel")
+ expect(page).to have_link("View page @ #{commit.short_id}", href: wiki_page_path(wiki, wiki_page, version_id: commit))
+ expect(page).to have_css('.diff-file[data-blob-diff-path="%s"]' % diff_path)
+ end
+
+ it 'links to the correct diffs' do
+ visit wiki_page_path(wiki, wiki_page, action: :history)
+
+ commit1 = wiki.commit('HEAD^')
+ commit2 = wiki.commit
+
+ expect(page).to have_link('created page: home', href: wiki_page_path(wiki, wiki_page, version_id: commit1, action: :diff))
+ expect(page).to have_link('updated home', href: wiki_page_path(wiki, wiki_page, version_id: commit2, action: :diff))
+ end
+
+ it 'between the current and the previous version of a page' do
+ commit = wiki.commit
+ visit wiki_page_path(wiki, wiki_page, version_id: commit, action: :diff)
+
+ expect(page).to have_content('by John Doe')
+ expect(page).to have_content('updated home')
+ expect(page).to have_content('Showing 1 changed file with 1 addition and 3 deletions')
+ expect(page).to have_content('some link')
+
+ expect_diff_links(commit)
+ end
+
+ it 'between two old versions of a page' do
+ wiki_page.update(message: 'latest home change', content: 'updated [another link](other-page)') # rubocop:disable Rails/SaveBang:
+ commit = wiki.commit('HEAD^')
+ visit wiki_page_path(wiki, wiki_page, version_id: commit, action: :diff)
+
+ expect(page).to have_content('by John Doe')
+ expect(page).to have_content('updated home')
+ expect(page).to have_content('Showing 1 changed file with 1 addition and 3 deletions')
+ expect(page).to have_content('some link')
+ expect(page).not_to have_content('latest home change')
+ expect(page).not_to have_content('another link')
+
+ expect_diff_links(commit)
+ end
+
+ it 'for the oldest version of a page' do
+ commit = wiki.commit('HEAD^')
+ visit wiki_page_path(wiki, wiki_page, version_id: commit, action: :diff)
+
+ expect(page).to have_content('by John Doe')
+ expect(page).to have_content('created page: home')
+ expect(page).to have_content('Showing 1 changed file with 4 additions and 0 deletions')
+ expect(page).to have_content('Look at this')
+
+ expect_diff_links(commit)
+ end
+ end
+ end
+
+ context 'when a page has special characters in its title' do
+ let(:title) { '<foo> !@#$%^&*()[]{}=_+\'"\\|<>? <bar>' }
+
+ before do
+ wiki_page.update(title: title ) # rubocop:disable Rails/SaveBang
+ end
+
+ it 'preserves the special characters' do
+ visit(wiki_page_path(wiki, wiki_page))
+
+ expect(page).to have_css('[data-testid="wiki_page_title"]', text: title)
+ expect(page).to have_css('.wiki-pages li', text: title)
+ end
+ end
+
+ context 'when a page has XSS in its title or content' do
+ let(:title) { '<script>alert("title")<script>' }
+
+ before do
+ wiki_page.update(title: title, content: 'foo <script>alert("content")</script> bar') # rubocop:disable Rails/SaveBang
+ end
+
+ it 'safely displays the page' do
+ visit(wiki_page_path(wiki, wiki_page))
+
+ expect(page).to have_selector('[data-testid="wiki_page_title"]', text: title)
+ expect(page).to have_content('foo bar')
+ end
+ end
+
+ context 'when a page has XSS in its message' do
+ before do
+ wiki_page.update(message: '<script>alert(true)<script>', content: 'XSS update') # rubocop:disable Rails/SaveBang
+ end
+
+ it 'safely displays the message' do
+ visit(wiki_page_path(wiki, wiki_page, action: :history))
+
+ expect(page).to have_content('<script>alert(true)<script>')
+ end
+ end
+
+ context 'when page has invalid content encoding' do
+ let(:content) { (+'whatever').force_encoding('ISO-8859-1') }
+
+ before do
+ allow(Gitlab::EncodingHelper).to receive(:encode!).and_return(content)
+
+ visit(wiki_page_path(wiki, wiki_page))
+ end
+
+ it 'does not show "Edit" button' do
+ expect(page).not_to have_selector('[data-testid="wiki_edit_button"]')
+ end
+
+ it 'shows error' do
+ page.within(:css, '.flash-notice') do
+ expect(page).to have_content('The content of this page is not encoded in UTF-8. Edits can only be made via the Git repository.')
+ end
+ end
+ end
+
+ it 'opens a default wiki page', :js do
+ visit wiki.container.web_url
+
+ find('.shortcuts-wiki').click
+
+ wait_for_svg_to_be_loaded
+
+ click_link "Create your first page"
+
+ expect(page).to have_content('Create New Page')
+ end
+end
diff --git a/spec/support/shared_examples/features/wiki/user_views_wiki_pages_shared_examples.rb b/spec/support/shared_examples/features/wiki/user_views_wiki_pages_shared_examples.rb
new file mode 100644
index 00000000000..314c2074eee
--- /dev/null
+++ b/spec/support/shared_examples/features/wiki/user_views_wiki_pages_shared_examples.rb
@@ -0,0 +1,89 @@
+# frozen_string_literal: true
+
+# Requires a context containing:
+# wiki
+# user
+
+RSpec.shared_examples 'User views wiki pages' do
+ include WikiHelpers
+
+ let!(:wiki_page1) do
+ create(:wiki_page, wiki: wiki, title: '3 home', content: '3')
+ end
+
+ let!(:wiki_page2) do
+ create(:wiki_page, wiki: wiki, title: '1 home', content: '1')
+ end
+
+ let!(:wiki_page3) do
+ create(:wiki_page, wiki: wiki, title: '2 home', content: '2')
+ end
+
+ let(:pages) do
+ page.find('.wiki-pages-list').all('li').map { |li| li.find('a') }
+ end
+
+ before do
+ sign_in(user)
+ visit(wiki_path(wiki, action: :pages))
+ end
+
+ context 'ordered by title' do
+ let(:pages_ordered_by_title) { [wiki_page2, wiki_page3, wiki_page1] }
+
+ context 'asc' do
+ it 'pages are displayed in direct order' do
+ pages.each.with_index do |page_title, index|
+ expect(page_title.text).to eq(pages_ordered_by_title[index].title)
+ end
+ end
+ end
+
+ context 'desc' do
+ before do
+ page.within('.wiki-sort-dropdown') do
+ page.find('.rspec-reverse-sort').click
+ end
+ end
+
+ it 'pages are displayed in reversed order' do
+ pages.reverse_each.with_index do |page_title, index|
+ expect(page_title.text).to eq(pages_ordered_by_title[index].title)
+ end
+ end
+ end
+ end
+
+ context 'ordered by created_at' do
+ let(:pages_ordered_by_created_at) { [wiki_page1, wiki_page2, wiki_page3] }
+
+ before do
+ page.within('.wiki-sort-dropdown') do
+ click_button('Title')
+ click_link('Created date')
+ end
+ end
+
+ context 'asc' do
+ it 'pages are displayed in direct order' do
+ pages.each.with_index do |page_title, index|
+ expect(page_title.text).to eq(pages_ordered_by_created_at[index].title)
+ end
+ end
+ end
+
+ context 'desc' do
+ before do
+ page.within('.wiki-sort-dropdown') do
+ page.find('.rspec-reverse-sort').click
+ end
+ end
+
+ it 'pages are displayed in reversed order' do
+ pages.reverse_each.with_index do |page_title, index|
+ expect(page_title.text).to eq(pages_ordered_by_created_at[index].title)
+ end
+ end
+ end
+ end
+end
diff --git a/spec/support/shared_examples/features/wiki/user_views_wiki_sidebar_shared_examples.rb b/spec/support/shared_examples/features/wiki/user_views_wiki_sidebar_shared_examples.rb
new file mode 100644
index 00000000000..a7ba7a8ad07
--- /dev/null
+++ b/spec/support/shared_examples/features/wiki/user_views_wiki_sidebar_shared_examples.rb
@@ -0,0 +1,68 @@
+# frozen_string_literal: true
+
+# Requires a context containing:
+# wiki
+# user
+
+RSpec.shared_examples 'User views wiki sidebar' do
+ include WikiHelpers
+
+ before do
+ sign_in(user)
+ end
+
+ context 'when there are some existing pages' do
+ before do
+ create(:wiki_page, wiki: wiki, title: 'home', content: 'home')
+ create(:wiki_page, wiki: wiki, title: 'another', content: 'another')
+ end
+
+ it 'renders a default sidebar when there is no customized sidebar' do
+ visit wiki_path(wiki)
+
+ expect(page).to have_content('another')
+ expect(page).not_to have_link('View All Pages')
+ end
+
+ context 'when there is a customized sidebar' do
+ before do
+ create(:wiki_page, wiki: wiki, title: '_sidebar', content: 'My customized sidebar')
+ end
+
+ it 'renders my customized sidebar instead of the default one' do
+ visit wiki_path(wiki)
+
+ expect(page).to have_content('My customized sidebar')
+ expect(page).not_to have_content('Another')
+ end
+ end
+ end
+
+ context 'when there are 15 existing pages' do
+ before do
+ (1..5).each { |i| create(:wiki_page, wiki: wiki, title: "my page #{i}") }
+ (6..10).each { |i| create(:wiki_page, wiki: wiki, title: "parent/my page #{i}") }
+ (11..15).each { |i| create(:wiki_page, wiki: wiki, title: "grandparent/parent/my page #{i}") }
+ end
+
+ it 'shows all pages in the sidebar' do
+ visit wiki_path(wiki)
+
+ (1..15).each { |i| expect(page).to have_content("my page #{i}") }
+ expect(page).not_to have_link('View All Pages')
+ end
+
+ context 'when there are more than 15 existing pages' do
+ before do
+ create(:wiki_page, wiki: wiki, title: 'my page 16')
+ end
+
+ it 'shows the first 15 pages in the sidebar' do
+ visit wiki_path(wiki)
+
+ expect(page).to have_text('my page', count: 15)
+ expect(page).to have_link('View All Pages')
+ end
+ end
+ end
+end
diff --git a/spec/support/shared_examples/features/wiki_file_attachments_shared_examples.rb b/spec/support/shared_examples/features/wiki_file_attachments_shared_examples.rb
deleted file mode 100644
index d30e8241da0..00000000000
--- a/spec/support/shared_examples/features/wiki_file_attachments_shared_examples.rb
+++ /dev/null
@@ -1,88 +0,0 @@
-# frozen_string_literal: true
-
-# Requires a context containing:
-# project
-
-RSpec.shared_examples 'wiki file attachments' do
- include DropzoneHelper
-
- context 'uploading attachments', :js do
- let(:wiki) { project.wiki }
-
- def attach_with_dropzone(wait = false)
- dropzone_file([Rails.root.join('spec', 'fixtures', 'dk.png')], 0, wait)
- end
-
- context 'before uploading' do
- it 'shows "Attach a file" button' do
- expect(page).to have_button('Attach a file')
- expect(page).not_to have_selector('.uploading-progress-container', visible: true)
- end
- end
-
- context 'uploading is in progress', :capybara_ignore_server_errors do
- it 'cancels uploading on clicking to "Cancel" button' do
- slow_requests do
- attach_with_dropzone
-
- click_button 'Cancel'
- end
-
- expect(page).to have_button('Attach a file')
- expect(page).not_to have_button('Cancel')
- expect(page).not_to have_selector('.uploading-progress-container', visible: true)
- end
-
- it 'shows "Attaching a file" message on uploading 1 file' do
- slow_requests do
- attach_with_dropzone
-
- expect(page).to have_selector('.attaching-file-message', visible: true, text: 'Attaching a file -')
- end
- end
- end
-
- context 'uploading is complete' do
- it 'shows "Attach a file" button on uploading complete' do
- attach_with_dropzone
- wait_for_requests
-
- expect(page).to have_button('Attach a file')
- expect(page).not_to have_selector('.uploading-progress-container', visible: true)
- end
-
- it 'the markdown link is added to the page' do
- fill_in(:wiki_content, with: '')
- attach_with_dropzone(true)
- wait_for_requests
-
- expect(page.find('#wiki_content').value)
- .to match(%r{\!\[dk\]\(uploads/\h{32}/dk\.png\)$})
- end
-
- it 'the links point to the wiki root url' do
- attach_with_dropzone(true)
- wait_for_requests
-
- find('.js-md-preview-button').click
- file_path = page.find('input[name="files[]"]', visible: :hidden).value
- link = page.find('a.no-attachment-icon')['href']
- img_link = page.find('a.no-attachment-icon img')['src']
-
- expect(link).to eq img_link
- expect(URI.parse(link).path).to eq File.join(wiki.wiki_base_path, file_path)
- end
-
- it 'the file has been added to the wiki repository' do
- expect do
- attach_with_dropzone(true)
- wait_for_requests
- end.to change { wiki.repository.ls_files('HEAD').count }.by(1)
-
- file_path = page.find('input[name="files[]"]', visible: :hidden).value
-
- expect(wiki.find_file(file_path, 'HEAD').path).not_to be_nil
- end
- end
- end
-end
diff --git a/spec/support/shared_examples/graphql/mutations/boards_create_shared_examples.rb b/spec/support/shared_examples/graphql/mutations/boards_create_shared_examples.rb
new file mode 100644
index 00000000000..ec64519cd9c
--- /dev/null
+++ b/spec/support/shared_examples/graphql/mutations/boards_create_shared_examples.rb
@@ -0,0 +1,75 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'boards create mutation' do
+ include GraphqlHelpers
+
+ let_it_be(:current_user, reload: true) { create(:user) }
+ let(:name) { 'board name' }
+ let(:mutation) { graphql_mutation(:create_board, params) }
+
+ subject { post_graphql_mutation(mutation, current_user: current_user) }
+
+ def mutation_response
+ graphql_mutation_response(:create_board)
+ end
+
+ context 'when the user does not have permission' do
+ it_behaves_like 'a mutation that returns a top-level access error'
+
+ it 'does not create the board' do
+ expect { subject }.not_to change { Board.count }
+ end
+ end
+
+ context 'when the user has permission' do
+ before do
+ parent.add_maintainer(current_user)
+ end
+
+ context 'when the parent (project_path or group_path) param is given' do
+ context 'when everything is ok' do
+ it 'creates the board' do
+ expect { subject }.to change { Board.count }.from(0).to(1)
+ end
+
+ it 'returns the created board' do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ expect(mutation_response).to have_key('board')
+ expect(mutation_response['board']['name']).to eq(name)
+ end
+ end
+
+ context 'when the Boards::CreateService returns an error response' do
+ before do
+ allow_next_instance_of(Boards::CreateService) do |service|
+ allow(service).to receive(:execute).and_return(ServiceResponse.error(message: 'There was an error.'))
+ end
+ end
+
+ it 'does not create a board' do
+ expect { subject }.not_to change { Board.count }
+ end
+
+ it 'returns an error' do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ expect(mutation_response).to have_key('board')
+ expect(mutation_response['board']).to be_nil
+ expect(mutation_response['errors'].first).to eq('There was an error.')
+ end
+ end
+ end
+
+ context 'when neither project_path nor group_path param is given' do
+ let(:params) { { name: name } }
+
+ it_behaves_like 'a mutation that returns top-level errors',
+ errors: ['group_path or project_path arguments are required']
+
+ it 'does not create the board' do
+ expect { subject }.not_to change { Board.count }
+ end
+ end
+ end
+end
diff --git a/spec/support/shared_examples/graphql/mutations/spammable_mutation_fields_examples.rb b/spec/support/shared_examples/graphql/mutations/spammable_mutation_fields_examples.rb
new file mode 100644
index 00000000000..54b3f84a6e6
--- /dev/null
+++ b/spec/support/shared_examples/graphql/mutations/spammable_mutation_fields_examples.rb
@@ -0,0 +1,47 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.shared_examples 'spam flag is present' do
+ specify :aggregate_failures do
+ subject
+
+ expect(mutation_response).to have_key('spam')
+ expect(mutation_response['spam']).to be_falsey
+ end
+end
+
+RSpec.shared_examples 'can raise spam flag' do
+ it 'spam parameters are passed to the service' do
+ expect(service).to receive(:new).with(anything, anything, hash_including(api: true, request: instance_of(ActionDispatch::Request)))
+
+ subject
+ end
+
+ context 'when the snippet is detected as spam' do
+ it 'raises spam flag' do
+ allow_next_instance_of(service) do |instance|
+ allow(instance).to receive(:spam_check) do |snippet, user, _|
+ snippet.spam!
+ end
+ end
+
+ subject
+
+ expect(mutation_response['spam']).to be true
+ expect(mutation_response['errors']).to include("Your snippet has been recognized as spam and has been discarded.")
+ end
+ end
+
+ context 'when :snippet_spam flag is disabled' do
+ before do
+ stub_feature_flags(snippet_spam: false)
+ end
+
+ it 'request parameter is not passed to the service' do
+ expect(service).to receive(:new).with(anything, anything, hash_not_including(request: instance_of(ActionDispatch::Request)))
+
+ subject
+ end
+ 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 522211340ea..24c8a247c93 100644
--- a/spec/support/shared_examples/graphql/notes_creation_shared_examples.rb
+++ b/spec/support/shared_examples/graphql/notes_creation_shared_examples.rb
@@ -52,11 +52,15 @@ RSpec.shared_examples 'a Note mutation when the given resource id is not for a N
it_behaves_like 'a Note mutation that does not create a Note'
- it_behaves_like 'a mutation that returns top-level errors', errors: ['Cannot add notes to this resource']
+ it_behaves_like 'a mutation that returns top-level errors' do
+ let(:match_errors) { include(/ does not represent an instance of Noteable/) }
+ end
end
RSpec.shared_examples 'a Note mutation when the given resource id is not for a Note' do
let(:note) { create(:issue) }
- it_behaves_like 'a mutation that returns top-level errors', errors: ['Resource is not a note']
+ it_behaves_like 'a mutation that returns top-level errors' do
+ let(:match_errors) { include(/does not represent an instance of Note/) }
+ end
end
diff --git a/spec/support/shared_examples/lib/gitlab/background_migration/mentions_migration_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/background_migration/mentions_migration_shared_examples.rb
index e93077c42e1..7707e79386c 100644
--- a/spec/support/shared_examples/lib/gitlab/background_migration/mentions_migration_shared_examples.rb
+++ b/spec/support/shared_examples/lib/gitlab/background_migration/mentions_migration_shared_examples.rb
@@ -1,12 +1,13 @@
# frozen_string_literal: true
-RSpec.shared_examples 'resource mentions migration' do |migration_class, resource_class|
+RSpec.shared_examples 'resource mentions migration' do |migration_class, resource_class_name|
it 'migrates resource mentions' do
join = migration_class::JOIN
conditions = migration_class::QUERY_CONDITIONS
+ resource_class = "#{Gitlab::BackgroundMigration::UserMentions::Models}::#{resource_class_name}".constantize
expect do
- subject.perform(resource_class.name, join, conditions, false, resource_class.minimum(:id), resource_class.maximum(:id))
+ subject.perform(resource_class_name, join, conditions, false, resource_class.minimum(:id), resource_class.maximum(:id))
end.to change { user_mentions.count }.by(1)
user_mention = user_mentions.last
@@ -16,23 +17,23 @@ RSpec.shared_examples 'resource mentions migration' do |migration_class, resourc
# check that performing the same job twice does not fail and does not change counts
expect do
- subject.perform(resource_class.name, join, conditions, false, resource_class.minimum(:id), resource_class.maximum(:id))
+ subject.perform(resource_class_name, join, conditions, false, resource_class.minimum(:id), resource_class.maximum(:id))
end.to change { user_mentions.count }.by(0)
end
end
-RSpec.shared_examples 'resource notes mentions migration' do |migration_class, resource_class|
+RSpec.shared_examples 'resource notes mentions migration' do |migration_class, resource_class_name|
it 'migrates mentions from note' do
join = migration_class::JOIN
conditions = migration_class::QUERY_CONDITIONS
# there are 5 notes for each noteable_type, but two do not have mentions and
# another one's noteable_id points to an inexistent resource
- expect(notes.where(noteable_type: resource_class.to_s).count).to eq 5
+ expect(notes.where(noteable_type: resource_class_name).count).to eq 5
expect(user_mentions.count).to eq 0
expect do
- subject.perform(resource_class.name, join, conditions, true, Note.minimum(:id), Note.maximum(:id))
+ subject.perform(resource_class_name, join, conditions, true, Note.minimum(:id), Note.maximum(:id))
end.to change { user_mentions.count }.by(2)
# check that the user_mention for regular note is created
@@ -51,7 +52,7 @@ RSpec.shared_examples 'resource notes mentions migration' do |migration_class, r
# check that performing the same job twice does not fail and does not change counts
expect do
- subject.perform(resource_class.name, join, conditions, true, Note.minimum(:id), Note.maximum(:id))
+ subject.perform(resource_class_name, join, conditions, true, Note.minimum(:id), Note.maximum(:id))
end.to change { user_mentions.count }.by(0)
end
end
@@ -83,24 +84,25 @@ RSpec.shared_examples 'schedules resource mentions migration' do |resource_class
end
end
-RSpec.shared_examples 'resource migration not run' do |migration_class, resource_class|
+RSpec.shared_examples 'resource migration not run' do |migration_class, resource_class_name|
it 'does not migrate mentions' do
join = migration_class::JOIN
conditions = migration_class::QUERY_CONDITIONS
+ resource_class = "#{Gitlab::BackgroundMigration::UserMentions::Models}::#{resource_class_name}".constantize
expect do
- subject.perform(resource_class.name, join, conditions, false, resource_class.minimum(:id), resource_class.maximum(:id))
+ subject.perform(resource_class_name, join, conditions, false, resource_class.minimum(:id), resource_class.maximum(:id))
end.to change { user_mentions.count }.by(0)
end
end
-RSpec.shared_examples 'resource notes migration not run' do |migration_class, resource_class|
+RSpec.shared_examples 'resource notes migration not run' do |migration_class, resource_class_name|
it 'does not migrate mentions' do
join = migration_class::JOIN
conditions = migration_class::QUERY_CONDITIONS
expect do
- subject.perform(resource_class.name, join, conditions, true, Note.minimum(:id), Note.maximum(:id))
+ subject.perform(resource_class_name, join, conditions, true, Note.minimum(:id), Note.maximum(:id))
end.to change { user_mentions.count }.by(0)
end
end
diff --git a/spec/support/shared_examples/lib/gitlab/ci/ci_trace_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/ci/ci_trace_shared_examples.rb
index db5e9461f3f..0df1af3b10a 100644
--- a/spec/support/shared_examples/lib/gitlab/ci/ci_trace_shared_examples.rb
+++ b/spec/support/shared_examples/lib/gitlab/ci/ci_trace_shared_examples.rb
@@ -227,7 +227,7 @@ RSpec.shared_examples 'common trace features' do
let(:token) { 'my_secret_token' }
before do
- build.project.update(runners_token: token)
+ build.project.update!(runners_token: token)
trace.append(token, 0)
end
@@ -240,7 +240,7 @@ RSpec.shared_examples 'common trace features' do
let(:token) { 'my_secret_token' }
before do
- build.update(token: token)
+ build.update!(token: token)
trace.append(token, 0)
end
@@ -531,7 +531,7 @@ RSpec.shared_examples 'trace with disabled live trace feature' do
context "when erase old trace with 'save'" do
before do
build.send(:write_attribute, :trace, nil)
- build.save
+ build.save # rubocop:disable Rails/SaveBang
end
it 'old trace is not deleted' do
diff --git a/spec/support/shared_examples/lib/gitlab/diff_file_collections_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/diff_file_collections_shared_examples.rb
index e43ce936b90..469c0c287b1 100644
--- a/spec/support/shared_examples/lib/gitlab/diff_file_collections_shared_examples.rb
+++ b/spec/support/shared_examples/lib/gitlab/diff_file_collections_shared_examples.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
RSpec.shared_examples 'diff statistics' do |test_include_stats_flag: true|
- subject { described_class.new(diffable, collection_default_args) }
+ subject { described_class.new(diffable, **collection_default_args) }
def stub_stats_find_by_path(path, stats_mock)
expect_next_instance_of(Gitlab::Git::DiffStatsCollection) do |collection|
diff --git a/spec/support/shared_examples/lib/gitlab/import_export/relation_factory_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/import_export/relation_factory_shared_examples.rb
new file mode 100644
index 00000000000..33061f17bde
--- /dev/null
+++ b/spec/support/shared_examples/lib/gitlab/import_export/relation_factory_shared_examples.rb
@@ -0,0 +1,107 @@
+# frozen_string_literal: true
+
+# required context:
+# - importable: group or project
+# - relation_hash: a note relation that's being imported
+# - created_object: the object created with the relation factory
+RSpec.shared_examples 'Notes user references' do
+ let(:relation_sym) { :notes }
+ let(:mapped_user) { create(:user) }
+ let(:exported_member) do
+ {
+ 'id' => 111,
+ 'access_level' => 30,
+ 'source_id' => 1,
+ 'source_type' => importable.class.name == 'Project' ? 'Project' : 'Namespace',
+ 'user_id' => 3,
+ 'notification_level' => 3,
+ 'created_at' => '2016-11-18T09:29:42.634Z',
+ 'updated_at' => '2016-11-18T09:29:42.634Z',
+ 'user' => {
+ 'id' => 999,
+ 'email' => mapped_user.email,
+ 'username' => mapped_user.username
+ }
+ }
+ end
+
+ let(:members_mapper) do
+ Gitlab::ImportExport::MembersMapper.new(
+ exported_members: [exported_member].compact,
+ user: importer_user,
+ importable: importable
+ )
+ end
+
+ shared_examples 'sets the note author to the importer user' do
+ it { expect(created_object.author).to eq(importer_user) }
+ end
+
+ shared_examples 'sets the note author to the mapped user' do
+ it { expect(created_object.author).to eq(mapped_user) }
+ end
+
+ shared_examples 'does not add original autor note' do
+ it { expect(created_object.note).not_to include('*By Administrator') }
+ end
+
+ shared_examples 'adds original autor note' do
+ it { expect(created_object.note).to include('*By Administrator') }
+ end
+
+ context 'when the importer is admin' do
+ let(:importer_user) { create(:admin) }
+
+ context 'and the note author is not mapped' do
+ let(:exported_member) { nil }
+
+ include_examples 'sets the note author to the importer user'
+
+ include_examples 'adds original autor note'
+ end
+
+ context 'and the note author is the importer user' do
+ let(:mapped_user) { importer_user }
+
+ include_examples 'sets the note author to the mapped user'
+
+ include_examples 'does not add original autor note'
+ end
+
+ context 'and the note author exists in the target instance' do
+ let(:mapped_user) { create(:user) }
+
+ include_examples 'sets the note author to the mapped user'
+
+ include_examples 'does not add original autor note'
+ end
+ end
+
+ context 'when the importer is not admin' do
+ let(:importer_user) { create(:user) }
+
+ context 'and the note author is not mapped' do
+ let(:exported_member) { nil }
+
+ include_examples 'sets the note author to the importer user'
+
+ include_examples 'adds original autor note'
+ end
+
+ context 'and the note author is the importer user' do
+ let(:mapped_user) { importer_user }
+
+ include_examples 'sets the note author to the importer user'
+
+ include_examples 'adds original autor note'
+ end
+
+ context 'and the note author exists in the target instance' do
+ let(:mapped_user) { create(:user) }
+
+ include_examples 'sets the note author to the importer user'
+
+ include_examples 'adds original autor note'
+ end
+ end
+end
diff --git a/spec/support/shared_examples/lib/gitlab/repository_size_checker_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/repository_size_checker_shared_examples.rb
new file mode 100644
index 00000000000..bb909ffe82a
--- /dev/null
+++ b/spec/support/shared_examples/lib/gitlab/repository_size_checker_shared_examples.rb
@@ -0,0 +1,51 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'checker size above limit' do
+ context 'when size is above the limit' do
+ let(:current_size) { 100 }
+
+ it 'returns true' do
+ expect(subject.above_size_limit?).to eq(true)
+ end
+ end
+end
+
+RSpec.shared_examples 'checker size not over limit' do
+ it 'returns false when not over the limit' do
+ expect(subject.above_size_limit?).to eq(false)
+ end
+end
+
+RSpec.shared_examples 'checker size exceeded' do
+ context 'when current size is below or equal to the limit' do
+ let(:current_size) { 50 }
+
+ it 'returns zero' do
+ expect(subject.exceeded_size).to eq(0)
+ end
+ end
+
+ context 'when current size is over the limit' do
+ let(:current_size) { 51 }
+
+ it 'returns zero' do
+ expect(subject.exceeded_size).to eq(1.megabytes)
+ end
+ end
+
+ context 'when change size will be over the limit' do
+ let(:current_size) { 50 }
+
+ it 'returns zero' do
+ expect(subject.exceeded_size(1.megabytes)).to eq(1.megabytes)
+ end
+ end
+
+ context 'when change size will not be over the limit' do
+ let(:current_size) { 49 }
+
+ it 'returns zero' do
+ expect(subject.exceeded_size(1.megabytes)).to eq(0)
+ end
+ end
+end
diff --git a/spec/support/shared_examples/lib/gitlab/search/recent_items.rb b/spec/support/shared_examples/lib/gitlab/search/recent_items.rb
index f96ff4b101e..b3b33e434b9 100644
--- a/spec/support/shared_examples/lib/gitlab/search/recent_items.rb
+++ b/spec/support/shared_examples/lib/gitlab/search/recent_items.rb
@@ -1,12 +1,11 @@
# frozen_string_literal: true
require 'spec_helper'
-
RSpec.shared_examples 'search recent items' do
let_it_be(:user) { create(:user) }
- let_it_be(:recent_items) { described_class.new(user: user, items_limit: 5) }
- let(:item) { create_item(content: 'hello world 1', project: project) }
- let(:project) { create(:project, :public) }
+ let_it_be(:recent_items) { described_class.new(user: user) }
+ let(:item) { create_item(content: 'hello world 1', parent: parent) }
+ let(:parent) { create(parent_type, :public) }
describe '#log_view', :clean_gitlab_redis_shared_state do
it 'adds the item to the recent items' do
@@ -18,13 +17,15 @@ RSpec.shared_examples 'search recent items' do
end
it 'removes an item when it exceeds the size items_limit' do
- (1..6).each do |i|
- recent_items.log_view(create_item(content: "item #{i}", project: project))
+ recent_items = described_class.new(user: user, items_limit: 3)
+
+ 4.times do |i|
+ recent_items.log_view(create_item(content: "item #{i}", parent: parent))
end
results = recent_items.search('item')
- expect(results.map(&:title)).to contain_exactly('item 6', 'item 5', 'item 4', 'item 3', 'item 2')
+ expect(results.map(&:title)).to contain_exactly('item 3', 'item 2', 'item 1')
end
it 'expires the items after expires_after' do
@@ -39,7 +40,7 @@ RSpec.shared_examples 'search recent items' do
it 'does not include results logged for another user' do
another_user = create(:user)
- another_item = create_item(content: 'hello world 2', project: project)
+ another_item = create_item(content: 'hello world 2', parent: parent)
described_class.new(user: another_user).log_view(another_item)
recent_items.log_view(item)
@@ -50,11 +51,11 @@ RSpec.shared_examples 'search recent items' do
end
describe '#search', :clean_gitlab_redis_shared_state do
- let(:item1) { create_item(content: "matching item 1", project: project) }
- let(:item2) { create_item(content: "matching item 2", project: project) }
- let(:item3) { create_item(content: "matching item 3", project: project) }
- let(:non_matching_item) { create_item(content: "different item", project: project) }
- let!(:non_viewed_item) { create_item(content: "matching but not viewed item", project: project) }
+ let(:item1) { create_item(content: "matching item 1", parent: parent) }
+ let(:item2) { create_item(content: "matching item 2", parent: parent) }
+ let(:item3) { create_item(content: "matching item 3", parent: parent) }
+ let(:non_matching_item) { create_item(content: "different item", parent: parent) }
+ let!(:non_viewed_item) { create_item(content: "matching but not viewed item", parent: parent) }
before do
recent_items.log_view(item1)
@@ -74,14 +75,24 @@ RSpec.shared_examples 'search recent items' do
end
it 'does not leak items you no longer have access to' do
- private_project = create(:project, :public, namespace: create(:group))
- private_item = create_item(content: 'matching item title', project: private_project)
+ private_parent = create(parent_type, :public)
+ private_item = create_item(content: 'matching item title', parent: private_parent)
recent_items.log_view(private_item)
- private_project.update!(visibility_level: Project::PRIVATE)
+ private_parent.update!(visibility_level: ::Gitlab::VisibilityLevel::PRIVATE)
expect(recent_items.search('matching')).not_to include(private_item)
end
+
+ it "limits results to #{Gitlab::Search::RecentItems::SEARCH_LIMIT} items" do
+ (Gitlab::Search::RecentItems::SEARCH_LIMIT + 1).times do |i|
+ recent_items.log_view(create_item(content: "item #{i}", parent: parent))
+ end
+
+ results = recent_items.search('item')
+
+ expect(results.count).to eq(Gitlab::Search::RecentItems::SEARCH_LIMIT)
+ end
end
end
diff --git a/spec/support/shared_examples/lib/gitlab/search_confidential_filter_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/search_confidential_filter_shared_examples.rb
new file mode 100644
index 00000000000..d0bef2ad730
--- /dev/null
+++ b/spec/support/shared_examples/lib/gitlab/search_confidential_filter_shared_examples.rb
@@ -0,0 +1,69 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'search results filtered by confidential' do
+ context 'filter not provided (all behavior)' do
+ let(:filters) { {} }
+
+ context 'when Feature search_filter_by_confidential enabled' do
+ it 'returns confidential and not confidential results', :aggregate_failures do
+ expect(results.objects('issues')).to include confidential_result
+ expect(results.objects('issues')).to include opened_result
+ end
+ end
+
+ context 'when Feature search_filter_by_confidential not enabled' do
+ before do
+ stub_feature_flags(search_filter_by_confidential: false)
+ end
+
+ it 'returns confidential and not confidential results', :aggregate_failures do
+ expect(results.objects('issues')).to include confidential_result
+ expect(results.objects('issues')).to include opened_result
+ end
+ end
+ end
+
+ context 'confidential filter' do
+ let(:filters) { { confidential: true } }
+
+ context 'when Feature search_filter_by_confidential enabled' do
+ it 'returns only confidential results', :aggregate_failures do
+ expect(results.objects('issues')).to include confidential_result
+ expect(results.objects('issues')).not_to include opened_result
+ end
+ end
+
+ context 'when Feature search_filter_by_confidential not enabled' do
+ before do
+ stub_feature_flags(search_filter_by_confidential: false)
+ end
+
+ it 'returns confidential and not confidential results', :aggregate_failures do
+ expect(results.objects('issues')).to include confidential_result
+ expect(results.objects('issues')).to include opened_result
+ end
+ end
+ end
+
+ context 'not confidential filter' do
+ let(:filters) { { confidential: false } }
+
+ context 'when Feature search_filter_by_confidential enabled' do
+ it 'returns not confidential results', :aggregate_failures do
+ expect(results.objects('issues')).not_to include confidential_result
+ expect(results.objects('issues')).to include opened_result
+ end
+ end
+
+ context 'when Feature search_filter_by_confidential not enabled' do
+ before do
+ stub_feature_flags(search_filter_by_confidential: false)
+ end
+
+ it 'returns confidential and not confidential results', :aggregate_failures do
+ expect(results.objects('issues')).to include confidential_result
+ expect(results.objects('issues')).to include opened_result
+ end
+ end
+ end
+end
diff --git a/spec/support/shared_examples/lib/gitlab/search_results_sorted_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/search_results_sorted_shared_examples.rb
new file mode 100644
index 00000000000..765279a78fe
--- /dev/null
+++ b/spec/support/shared_examples/lib/gitlab/search_results_sorted_shared_examples.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'search results sorted' do
+ context 'sort: newest' do
+ let(:sort) { 'newest' }
+
+ it 'sorts results by created_at' do
+ expect(results.objects(scope).map(&:id)).to eq([new_result.id, old_result.id, very_old_result.id])
+ end
+ end
+
+ context 'sort: oldest' do
+ let(:sort) { 'oldest' }
+
+ it 'sorts results by created_at' do
+ expect(results.objects(scope).map(&:id)).to eq([very_old_result.id, old_result.id, new_result.id])
+ end
+ end
+end
diff --git a/spec/support/shared_examples/lib/gitlab/search_issue_state_filter_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/search_state_filter_shared_examples.rb
index e80ec516407..e80ec516407 100644
--- a/spec/support/shared_examples/lib/gitlab/search_issue_state_filter_shared_examples.rb
+++ b/spec/support/shared_examples/lib/gitlab/search_state_filter_shared_examples.rb
diff --git a/spec/support/shared_examples/mailers/notify_shared_examples.rb b/spec/support/shared_examples/mailers/notify_shared_examples.rb
index 1f5803b90a0..7ce7b2161f6 100644
--- a/spec/support/shared_examples/mailers/notify_shared_examples.rb
+++ b/spec/support/shared_examples/mailers/notify_shared_examples.rb
@@ -267,3 +267,9 @@ RSpec.shared_examples 'appearance header and footer not enabled' do
end
end
end
+
+RSpec.shared_examples 'no email is sent' do
+ it 'does not send an email' do
+ expect(subject.message).to be_a_kind_of(ActionMailer::Base::NullMail)
+ end
+end
diff --git a/spec/support/shared_examples/models/concerns/has_repository_shared_examples.rb b/spec/support/shared_examples/models/concerns/has_repository_shared_examples.rb
index f37ef3533c3..826ee453919 100644
--- a/spec/support/shared_examples/models/concerns/has_repository_shared_examples.rb
+++ b/spec/support/shared_examples/models/concerns/has_repository_shared_examples.rb
@@ -6,6 +6,14 @@ RSpec.shared_examples 'model with repository' do
let(:expected_full_path) { raise NotImplementedError }
let(:expected_web_url_path) { expected_full_path }
let(:expected_repo_url_path) { expected_full_path }
+ let(:expected_lfs_enabled) { false }
+
+ it 'container class includes HasRepository' do
+ # NOTE: This is not enforced at runtime, since we also need to support Geo::DeletedProject
+ expect(described_class).to include_module(HasRepository)
+ expect(container).to be_kind_of(HasRepository)
+ expect(stubbed_container).to be_kind_of(HasRepository)
+ end
describe '#commits_by' do
let(:commits) { container.repository.commits('HEAD', limit: 3).commits }
@@ -74,6 +82,10 @@ RSpec.shared_examples 'model with repository' do
it 'returns valid repo' do
expect(container.repository).to be_kind_of(Repository)
end
+
+ it 'uses the same container' do
+ expect(container.repository.container).to be(container)
+ end
end
describe '#storage' do
@@ -88,6 +100,16 @@ RSpec.shared_examples 'model with repository' do
end
end
+ describe '#lfs_enabled?' do
+ before do
+ stub_lfs_setting(enabled: true)
+ end
+
+ it 'returns the expected value' do
+ expect(container.lfs_enabled?).to eq(expected_lfs_enabled)
+ end
+ end
+
describe '#empty_repo?' do
context 'when the repo does not exist' do
it 'returns true' do
diff --git a/spec/support/shared_examples/models/concerns/shardable_shared_examples.rb b/spec/support/shared_examples/models/concerns/shardable_shared_examples.rb
new file mode 100644
index 00000000000..fa929d5b791
--- /dev/null
+++ b/spec/support/shared_examples/models/concerns/shardable_shared_examples.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'shardable scopes' do
+ let_it_be(:secondary_shard) { create(:shard, name: 'test_second_storage') }
+
+ before do
+ record_2.update!(shard: secondary_shard)
+ end
+
+ describe '.for_repository_storage' do
+ it 'returns the objects for a given repository storage' do
+ expect(described_class.for_repository_storage('default')).to eq([record_1])
+ end
+ end
+
+ describe '.excluding_repository_storage' do
+ it 'returns the objects excluding the given repository storage' do
+ expect(described_class.excluding_repository_storage('default')).to eq([record_2])
+ end
+ end
+end
diff --git a/spec/support/shared_examples/models/concerns/timebox_shared_examples.rb b/spec/support/shared_examples/models/concerns/timebox_shared_examples.rb
index d199bae4170..f91e4bd8cf7 100644
--- a/spec/support/shared_examples/models/concerns/timebox_shared_examples.rb
+++ b/spec/support/shared_examples/models/concerns/timebox_shared_examples.rb
@@ -9,6 +9,11 @@ RSpec.shared_examples 'a timebox' do |timebox_type|
let(:user) { create(:user) }
let(:timebox_table_name) { timebox_type.to_s.pluralize.to_sym }
+ # Values implementions can override
+ let(:mid_point) { Time.now.utc.to_date }
+ let(:open_on_left) { nil }
+ let(:open_on_right) { nil }
+
describe 'modules' do
context 'with a project' do
it_behaves_like 'AtomicInternalId' do
@@ -240,4 +245,85 @@ RSpec.shared_examples 'a timebox' do |timebox_type|
expect(timebox.to_ability_name).to eq(timebox_type.to_s)
end
end
+
+ describe '.within_timeframe' do
+ let(:factory) { timebox_type }
+ let(:min_date) { mid_point - 10.days }
+ let(:max_date) { mid_point + 10.days }
+
+ def box(from, to)
+ create(factory, *timebox_args,
+ start_date: from || open_on_left,
+ due_date: to || open_on_right)
+ end
+
+ it 'can find overlapping timeboxes' do
+ fully_open = box(nil, nil)
+ # ----| ................ # Not overlapping
+ non_overlapping_open_on_left = box(nil, min_date - 1.day)
+ # |--| ................ # Not overlapping
+ non_overlapping_closed_on_left = box(min_date - 2.days, min_date - 1.day)
+ # ------|............... # Overlapping
+ overlapping_open_on_left_just = box(nil, min_date)
+ # -----------------------| # Overlapping
+ overlapping_open_on_left_fully = box(nil, max_date + 1.day)
+ # ---------|............ # Overlapping
+ overlapping_open_on_left_partial = box(nil, min_date + 1.day)
+ # |-----|............ # Overlapping
+ overlapping_closed_partial = box(min_date - 1.day, min_date + 1.day)
+ # |--------------| # Overlapping
+ exact_match = box(min_date, max_date)
+ # |--------------------| # Overlapping
+ larger = box(min_date - 1.day, max_date + 1.day)
+ # ...|-----|...... # Overlapping
+ smaller = box(min_date + 1.day, max_date - 1.day)
+ # .........|-----| # Overlapping
+ at_end = box(max_date - 1.day, max_date)
+ # .........|--------- # Overlapping
+ at_end_open = box(max_date - 1.day, nil)
+ # |-------------------- # Overlapping
+ cover_from_left = box(min_date - 1.day, nil)
+ # .........|--------| # Overlapping
+ cover_from_middle_closed = box(max_date - 1.day, max_date + 1.day)
+ # ...............|--| # Overlapping
+ overlapping_at_end_just = box(max_date, max_date + 1.day)
+ # ............... |-| # Not Overlapping
+ not_overlapping_at_right_closed = box(max_date + 1.day, max_date + 2.days)
+ # ............... |-- # Not Overlapping
+ not_overlapping_at_right_open = box(max_date + 1.day, nil)
+
+ matches = described_class.within_timeframe(min_date, max_date)
+
+ expect(matches).to include(
+ overlapping_open_on_left_just,
+ overlapping_open_on_left_fully,
+ overlapping_open_on_left_partial,
+ overlapping_closed_partial,
+ exact_match,
+ larger,
+ smaller,
+ at_end,
+ at_end_open,
+ cover_from_left,
+ cover_from_middle_closed,
+ overlapping_at_end_just
+ )
+
+ expect(matches).not_to include(
+ non_overlapping_open_on_left,
+ non_overlapping_closed_on_left,
+ not_overlapping_at_right_closed,
+ not_overlapping_at_right_open
+ )
+
+ # Whether we match the 'fully-open' range depends on whether
+ # it is in fact open (i.e. whether the class allows infinite
+ # ranges)
+ if open_on_left.nil? && open_on_right.nil?
+ expect(matches).not_to include(fully_open)
+ else
+ expect(matches).to include(fully_open)
+ end
+ end
+ end
end
diff --git a/spec/support/shared_examples/models/mentionable_shared_examples.rb b/spec/support/shared_examples/models/mentionable_shared_examples.rb
index 94c52bdaaa6..0ee0b7e6d88 100644
--- a/spec/support/shared_examples/models/mentionable_shared_examples.rb
+++ b/spec/support/shared_examples/models/mentionable_shared_examples.rb
@@ -207,29 +207,8 @@ RSpec.shared_examples 'an editable mentionable' do
end
RSpec.shared_examples 'mentions in description' do |mentionable_type|
- describe 'when store_mentioned_users_to_db feature disabled' do
+ describe 'when storing user mentions' do
before do
- stub_feature_flags(store_mentioned_users_to_db: false)
- mentionable.store_mentions!
- end
-
- context 'when mentionable description contains mentions' do
- let(:user) { create(:user) }
- let(:mentionable) { create(mentionable_type, description: "#{user.to_reference} some description") }
-
- it 'stores no mentions' do
- expect(mentionable.user_mentions.count).to eq 0
- end
-
- it 'renders description_html correctly' do
- expect(mentionable.description_html).to include("<a href=\"/#{user.username}\" data-user=\"#{user.id}\"")
- end
- end
- end
-
- describe 'when store_mentioned_users_to_db feature enabled' do
- before do
- stub_feature_flags(store_mentioned_users_to_db: true)
mentionable.store_mentions!
end
diff --git a/spec/support/shared_examples/models/project_latest_successful_build_for_shared_examples.rb b/spec/support/shared_examples/models/project_latest_successful_build_for_shared_examples.rb
index 7701ab42007..66cd8d1df12 100644
--- a/spec/support/shared_examples/models/project_latest_successful_build_for_shared_examples.rb
+++ b/spec/support/shared_examples/models/project_latest_successful_build_for_shared_examples.rb
@@ -60,4 +60,20 @@ RSpec.shared_examples 'latest successful build for sha or ref' do
expect(subject).to be_nil
end
end
+
+ context 'with build belonging to a child pipeline' do
+ let(:child_pipeline) { create_pipeline(project) }
+ let(:parent_bridge) { create(:ci_bridge, pipeline: pipeline, project: pipeline.project) }
+ let!(:pipeline_source) { create(:ci_sources_pipeline, source_job: parent_bridge, pipeline: child_pipeline)}
+ let!(:child_build) { create_build(child_pipeline, 'child-build') }
+ let(:build_name) { child_build.name }
+
+ before do
+ child_pipeline.update!(source: :parent_pipeline)
+ end
+
+ it 'returns the child build' do
+ expect(subject).to eq(child_build)
+ end
+ end
end
diff --git a/spec/support/shared_examples/models/relative_positioning_shared_examples.rb b/spec/support/shared_examples/models/relative_positioning_shared_examples.rb
index d1437244082..b8d12a6da59 100644
--- a/spec/support/shared_examples/models/relative_positioning_shared_examples.rb
+++ b/spec/support/shared_examples/models/relative_positioning_shared_examples.rb
@@ -31,6 +31,41 @@ RSpec.shared_examples 'a class that supports relative positioning' do
end
end
+ def as_item(item)
+ item # Override to perform a transformation, if necessary
+ end
+
+ def as_items(items)
+ items.map { |item| as_item(item) }
+ end
+
+ describe '#scoped_items' do
+ it 'includes all items with the same scope' do
+ scope = as_items([item1, item2, new_item, create_item])
+ irrelevant = create(factory, {}) # This should not share the scope
+ context = RelativePositioning.mover.context(item1)
+
+ same_scope = as_items(context.scoped_items)
+
+ expect(same_scope).to include(*scope)
+ expect(same_scope).not_to include(as_item(irrelevant))
+ end
+ end
+
+ describe '#relative_siblings' do
+ it 'includes all items with the same scope, except self' do
+ scope = as_items([item2, new_item, create_item])
+ irrelevant = create(factory, {}) # This should not share the scope
+ context = RelativePositioning.mover.context(item1)
+
+ siblings = as_items(context.relative_siblings)
+
+ expect(siblings).to include(*scope)
+ expect(siblings).not_to include(as_item(item1))
+ expect(siblings).not_to include(as_item(irrelevant))
+ end
+ end
+
describe '.move_nulls_to_end' do
let(:item3) { create_item }
let(:sibling_query) { item1.class.relative_positioning_query_base(item1) }
@@ -47,7 +82,7 @@ RSpec.shared_examples 'a class that supports relative positioning' do
expect(item1.relative_position).to be(1000)
expect(sibling_query.where(relative_position: nil)).not_to exist
- expect(sibling_query.reorder(:relative_position, :id)).to eq([item1, item2, item3])
+ expect(as_items(sibling_query.reorder(:relative_position, :id))).to eq(as_items([item1, item2, item3]))
end
it 'preserves relative position' do
@@ -117,19 +152,36 @@ RSpec.shared_examples 'a class that supports relative positioning' do
expect(bunch.map(&:relative_position)).to all(be < nils.map(&:relative_position).min)
end
+ it 'manages to move nulls found in the relative scope' do
+ nils = create_items_with_positions([nil] * 4)
+
+ described_class.move_nulls_to_end(sibling_query.to_a)
+ positions = nils.map { |item| item.reset.relative_position }
+
+ expect(positions).to all(be_present)
+ expect(positions).to all(be_valid_position)
+ end
+
+ it 'can move many nulls' do
+ nils = create_items_with_positions([nil] * 101)
+
+ described_class.move_nulls_to_end(nils)
+
+ expect(nils.map(&:relative_position)).to all(be_valid_position)
+ end
+
it 'does not have an N+1 issue' do
create_items_with_positions(10..12)
-
- a, b, c, d, e, f = create_items_with_positions([nil, nil, nil, nil, nil, nil])
+ a, b, c, d, e, f, *xs = create_items_with_positions([nil] * 10)
baseline = ActiveRecord::QueryRecorder.new do
- described_class.move_nulls_to_end([a, e])
+ described_class.move_nulls_to_end([a, b])
end
- expect { described_class.move_nulls_to_end([b, c, d]) }
+ expect { described_class.move_nulls_to_end([c, d, e, f]) }
.not_to exceed_query_limit(baseline)
- expect { described_class.move_nulls_to_end([f]) }
+ expect { described_class.move_nulls_to_end(xs) }
.not_to exceed_query_limit(baseline.count)
end
end
@@ -149,7 +201,7 @@ RSpec.shared_examples 'a class that supports relative positioning' do
expect(items.sort_by(&:relative_position)).to eq(items)
expect(sibling_query.where(relative_position: nil)).not_to exist
- expect(sibling_query.reorder(:relative_position, :id)).to eq(items)
+ expect(as_items(sibling_query.reorder(:relative_position, :id))).to eq(as_items(items))
expect(item3.relative_position).to be(1000)
end
@@ -652,3 +704,119 @@ RSpec.shared_examples 'a class that supports relative positioning' do
(RelativePositioning::MIN_POSITION..).take(size)
end
end
+
+RSpec.shared_examples 'no-op relative positioning' do
+ def create_item(**params)
+ create(factory, params.merge(default_params))
+ end
+
+ let_it_be(:item1) { create_item }
+ let_it_be(:item2) { create_item }
+ let_it_be(:new_item) { create_item(relative_position: nil) }
+
+ def any_relative_positions
+ new_item.class.reorder(:relative_position, :id).pluck(:id, :relative_position)
+ end
+
+ shared_examples 'a no-op method' do
+ it 'does not raise errors' do
+ expect { perform }.not_to raise_error
+ end
+
+ it 'does not perform any DB queries' do
+ expect { perform }.not_to exceed_query_limit(0)
+ end
+
+ it 'does not change any relative_position' do
+ expect { perform }.not_to change { any_relative_positions }
+ end
+ end
+
+ describe '.scoped_items' do
+ subject { RelativePositioning.mover.context(item1).scoped_items }
+
+ it 'is empty' do
+ expect(subject).to be_empty
+ end
+ end
+
+ describe '.relative_siblings' do
+ subject { RelativePositioning.mover.context(item1).relative_siblings }
+
+ it 'is empty' do
+ expect(subject).to be_empty
+ end
+ end
+
+ describe '.move_nulls_to_end' do
+ subject { item1.class.move_nulls_to_end([new_item, item1]) }
+
+ it_behaves_like 'a no-op method' do
+ def perform
+ subject
+ end
+ end
+
+ it 'does not move any items' do
+ expect(subject).to eq(0)
+ end
+ end
+
+ describe '.move_nulls_to_start' do
+ subject { item1.class.move_nulls_to_start([new_item, item1]) }
+
+ it_behaves_like 'a no-op method' do
+ def perform
+ subject
+ end
+ end
+
+ it 'does not move any items' do
+ expect(subject).to eq(0)
+ end
+ end
+
+ describe 'instance methods' do
+ subject { new_item }
+
+ describe '#move_to_start' do
+ it_behaves_like 'a no-op method' do
+ def perform
+ subject.move_to_start
+ end
+ end
+ end
+
+ describe '#move_to_end' do
+ it_behaves_like 'a no-op method' do
+ def perform
+ subject.move_to_end
+ end
+ end
+ end
+
+ describe '#move_between' do
+ it_behaves_like 'a no-op method' do
+ def perform
+ subject.move_between(item1, item2)
+ end
+ end
+ end
+
+ describe '#move_before' do
+ it_behaves_like 'a no-op method' do
+ def perform
+ subject.move_before(item1)
+ end
+ end
+ end
+
+ describe '#move_after' do
+ it_behaves_like 'a no-op method' do
+ def perform
+ subject.move_after(item1)
+ end
+ end
+ end
+ end
+end
diff --git a/spec/support/shared_examples/models/resource_timebox_event_shared_examples.rb b/spec/support/shared_examples/models/resource_timebox_event_shared_examples.rb
index 07552b62cdd..5198508d48b 100644
--- a/spec/support/shared_examples/models/resource_timebox_event_shared_examples.rb
+++ b/spec/support/shared_examples/models/resource_timebox_event_shared_examples.rb
@@ -73,3 +73,13 @@ RSpec.shared_examples 'timebox resource event actions' do
end
end
end
+
+RSpec.shared_examples 'timebox resource tracks issue metrics' do |type|
+ describe '#usage_metrics' do
+ it 'tracks usage' do
+ expect(Gitlab::UsageDataCounters::IssueActivityUniqueCounter).to receive(:"track_issue_#{type}_changed_action")
+
+ create(described_class.name.underscore.to_sym, issue: create(:issue))
+ end
+ end
+end
diff --git a/spec/support/shared_examples/models/snippet_shared_examples.rb b/spec/support/shared_examples/models/snippet_shared_examples.rb
new file mode 100644
index 00000000000..a8fdf9bb81e
--- /dev/null
+++ b/spec/support/shared_examples/models/snippet_shared_examples.rb
@@ -0,0 +1,10 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'size checker for snippet' do |action|
+ it 'sets up size checker', :aggregate_failures do
+ expect(checker.current_size).to eq(current_size.megabytes)
+ expect(checker.limit).to eq(Gitlab::CurrentSettings.snippet_size_limit)
+ expect(checker.enabled?).to eq(true)
+ expect(checker.instance_variable_get(:@namespace)).to eq(namespace)
+ end
+end
diff --git a/spec/support/shared_examples/models/throttled_touch_shared_examples.rb b/spec/support/shared_examples/models/throttled_touch_shared_examples.rb
index 14b851d2828..e869cbce6ae 100644
--- a/spec/support/shared_examples/models/throttled_touch_shared_examples.rb
+++ b/spec/support/shared_examples/models/throttled_touch_shared_examples.rb
@@ -13,8 +13,8 @@ RSpec.shared_examples 'throttled touch' do
first_updated_at = Time.zone.now - (ThrottledTouch::TOUCH_INTERVAL * 2)
second_updated_at = Time.zone.now - (ThrottledTouch::TOUCH_INTERVAL * 1.5)
- Timecop.freeze(first_updated_at) { subject.touch }
- Timecop.freeze(second_updated_at) { subject.touch }
+ travel_to(first_updated_at) { subject.touch }
+ travel_to(second_updated_at) { subject.touch }
expect(subject.updated_at).to be_like_time(first_updated_at)
end
diff --git a/spec/support/shared_examples/models/update_project_statistics_shared_examples.rb b/spec/support/shared_examples/models/update_project_statistics_shared_examples.rb
index 557025569b8..7b591ad84d1 100644
--- a/spec/support/shared_examples/models/update_project_statistics_shared_examples.rb
+++ b/spec/support/shared_examples/models/update_project_statistics_shared_examples.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-RSpec.shared_examples 'UpdateProjectStatistics' do
+RSpec.shared_examples 'UpdateProjectStatistics' do |with_counter_attribute|
let(:project) { subject.project }
let(:project_statistics_name) { described_class.project_statistics_name }
let(:statistic_attribute) { described_class.statistic_attribute }
@@ -13,108 +13,230 @@ RSpec.shared_examples 'UpdateProjectStatistics' do
subject.read_attribute(statistic_attribute).to_i
end
- it { is_expected.to be_new_record }
+ def read_pending_increment
+ Gitlab::Redis::SharedState.with do |redis|
+ key = project.statistics.counter_key(project_statistics_name)
+ redis.get(key).to_i
+ end
+ end
- context 'when creating' do
- it 'updates the project statistics' do
- delta0 = reload_stat
+ it { is_expected.to be_new_record }
- subject.save!
+ context 'when feature flag efficient_counter_attribute is disabled' do
+ before do
+ stub_feature_flags(efficient_counter_attribute: false)
+ end
- delta1 = reload_stat
+ context 'when creating' do
+ it 'updates the project statistics' do
+ delta0 = reload_stat
- expect(delta1).to eq(delta0 + read_attribute)
- expect(delta1).to be > delta0
- end
+ subject.save!
- it 'schedules a namespace statistics worker' do
- expect(Namespaces::ScheduleAggregationWorker)
- .to receive(:perform_async).once
+ delta1 = reload_stat
- subject.save!
- end
- end
+ expect(delta1).to eq(delta0 + read_attribute)
+ expect(delta1).to be > delta0
+ end
- context 'when updating' do
- let(:delta) { 42 }
+ it 'schedules a namespace statistics worker' do
+ expect(Namespaces::ScheduleAggregationWorker)
+ .to receive(:perform_async).once
- before do
- subject.save!
+ subject.save!
+ end
end
- it 'updates project statistics' do
- expect(ProjectStatistics)
- .to receive(:increment_statistic)
- .and_call_original
+ context 'when updating' do
+ let(:delta) { 42 }
- subject.write_attribute(statistic_attribute, read_attribute + delta)
+ before do
+ subject.save!
+ end
- expect { subject.save! }
- .to change { reload_stat }
- .by(delta)
- end
+ it 'updates project statistics' do
+ expect(ProjectStatistics)
+ .to receive(:increment_statistic)
+ .and_call_original
- it 'schedules a namespace statistics worker' do
- expect(Namespaces::ScheduleAggregationWorker)
- .to receive(:perform_async).once
+ subject.write_attribute(statistic_attribute, read_attribute + delta)
- subject.write_attribute(statistic_attribute, read_attribute + delta)
- subject.save!
- end
+ expect { subject.save! }
+ .to change { reload_stat }
+ .by(delta)
+ end
- it 'avoids N + 1 queries' do
- subject.write_attribute(statistic_attribute, read_attribute + delta)
+ it 'schedules a namespace statistics worker' do
+ expect(Namespaces::ScheduleAggregationWorker)
+ .to receive(:perform_async).once
- control_count = ActiveRecord::QueryRecorder.new do
+ subject.write_attribute(statistic_attribute, read_attribute + delta)
subject.save!
end
- subject.write_attribute(statistic_attribute, read_attribute + delta)
+ it 'avoids N + 1 queries' do
+ subject.write_attribute(statistic_attribute, read_attribute + delta)
- expect do
- subject.save!
- end.not_to exceed_query_limit(control_count)
- end
- end
+ control_count = ActiveRecord::QueryRecorder.new do
+ subject.save!
+ end
- context 'when destroying' do
- before do
- subject.save!
+ subject.write_attribute(statistic_attribute, read_attribute + delta)
+
+ expect do
+ subject.save!
+ end.not_to exceed_query_limit(control_count)
+ end
end
- it 'updates the project statistics' do
- delta0 = reload_stat
+ context 'when destroying' do
+ before do
+ subject.save!
+ end
- subject.destroy!
+ it 'updates the project statistics' do
+ delta0 = reload_stat
- delta1 = reload_stat
+ subject.destroy!
- expect(delta1).to eq(delta0 - read_attribute)
- expect(delta1).to be < delta0
- end
+ delta1 = reload_stat
+
+ expect(delta1).to eq(delta0 - read_attribute)
+ expect(delta1).to be < delta0
+ end
+
+ it 'schedules a namespace statistics worker' do
+ expect(Namespaces::ScheduleAggregationWorker)
+ .to receive(:perform_async).once
- it 'schedules a namespace statistics worker' do
- expect(Namespaces::ScheduleAggregationWorker)
- .to receive(:perform_async).once
+ subject.destroy!
+ end
+
+ context 'when it is destroyed from the project level' do
+ it 'does not update the project statistics' do
+ expect(ProjectStatistics)
+ .not_to receive(:increment_statistic)
+
+ project.update!(pending_delete: true)
+ project.destroy!
+ end
+
+ it 'does not schedule a namespace statistics worker' do
+ expect(Namespaces::ScheduleAggregationWorker)
+ .not_to receive(:perform_async)
- subject.destroy!
+ project.update!(pending_delete: true)
+ project.destroy!
+ end
+ end
end
+ end
- context 'when it is destroyed from the project level' do
- it 'does not update the project statistics' do
- expect(ProjectStatistics)
- .not_to receive(:increment_statistic)
+ def expect_flush_counter_increments_worker_performed
+ expect(FlushCounterIncrementsWorker)
+ .to receive(:perform_in)
+ .with(CounterAttribute::WORKER_DELAY, project.statistics.class.name, project.statistics.id, project_statistics_name)
+ expect(FlushCounterIncrementsWorker)
+ .to receive(:perform_in)
+ .with(CounterAttribute::WORKER_DELAY, project.statistics.class.name, project.statistics.id, :storage_size)
- project.update!(pending_delete: true)
- project.destroy!
+ yield
+
+ # simulate worker running now
+ expect(Namespaces::ScheduleAggregationWorker).to receive(:perform_async)
+ FlushCounterIncrementsWorker.new.perform(project.statistics.class.name, project.statistics.id, project_statistics_name)
+ end
+
+ if with_counter_attribute
+ context 'when statistic is a counter attribute', :clean_gitlab_redis_shared_state do
+ context 'when creating' do
+ it 'stores pending increments for async update' do
+ initial_stat = reload_stat
+ expected_increment = read_attribute
+
+ expect_flush_counter_increments_worker_performed do
+ subject.save!
+
+ expect(read_pending_increment).to eq(expected_increment)
+ expect(expected_increment).to be > initial_stat
+ expect(expected_increment).to be_positive
+ end
+ end
end
- it 'does not schedule a namespace statistics worker' do
- expect(Namespaces::ScheduleAggregationWorker)
- .not_to receive(:perform_async)
+ context 'when updating' do
+ let(:delta) { 42 }
+
+ before do
+ subject.save!
+ redis_shared_state_cleanup!
+ end
+
+ it 'stores pending increments for async update' do
+ expect(ProjectStatistics)
+ .to receive(:increment_statistic)
+ .and_call_original
+
+ subject.write_attribute(statistic_attribute, read_attribute + delta)
+
+ expect_flush_counter_increments_worker_performed do
+ subject.save!
+
+ expect(read_pending_increment).to eq(delta)
+ end
+ end
+
+ it 'avoids N + 1 queries' do
+ subject.write_attribute(statistic_attribute, read_attribute + delta)
+
+ control_count = ActiveRecord::QueryRecorder.new do
+ subject.save!
+ end
+
+ subject.write_attribute(statistic_attribute, read_attribute + delta)
+
+ expect do
+ subject.save!
+ end.not_to exceed_query_limit(control_count)
+ end
+ end
- project.update!(pending_delete: true)
- project.destroy!
+ context 'when destroying' do
+ before do
+ subject.save!
+ redis_shared_state_cleanup!
+ end
+
+ it 'stores pending increment for async update' do
+ initial_stat = reload_stat
+ expected_increment = -read_attribute
+
+ expect_flush_counter_increments_worker_performed do
+ subject.destroy!
+
+ expect(read_pending_increment).to eq(expected_increment)
+ expect(expected_increment).to be < initial_stat
+ expect(expected_increment).to be_negative
+ end
+ end
+
+ context 'when it is destroyed from the project level' do
+ it 'does not update the project statistics' do
+ expect(ProjectStatistics)
+ .not_to receive(:increment_statistic)
+
+ project.update!(pending_delete: true)
+ project.destroy!
+ end
+
+ it 'does not schedule a namespace statistics worker' do
+ expect(Namespaces::ScheduleAggregationWorker)
+ .not_to receive(:perform_async)
+
+ project.update!(pending_delete: true)
+ project.destroy!
+ end
+ end
end
end
end
diff --git a/spec/support/shared_examples/models/wiki_shared_examples.rb b/spec/support/shared_examples/models/wiki_shared_examples.rb
index b87f7fe97e1..62da9e15259 100644
--- a/spec/support/shared_examples/models/wiki_shared_examples.rb
+++ b/spec/support/shared_examples/models/wiki_shared_examples.rb
@@ -4,21 +4,99 @@ RSpec.shared_examples 'wiki model' do
let_it_be(:user) { create(:user, :commit_email) }
let(:wiki_container) { raise NotImplementedError }
let(:wiki_container_without_repo) { raise NotImplementedError }
+ let(:wiki_lfs_enabled) { false }
let(:wiki) { described_class.new(wiki_container, user) }
let(:commit) { subject.repository.head_commit }
subject { wiki }
+ it 'container class includes HasWiki' do
+ # NOTE: This is not enforced at runtime, since we also need to support Geo::DeletedProject
+ expect(wiki_container).to be_kind_of(HasWiki)
+ expect(wiki_container_without_repo).to be_kind_of(HasWiki)
+ end
+
it_behaves_like 'model with repository' do
let(:container) { wiki }
let(:stubbed_container) { described_class.new(wiki_container_without_repo, user) }
let(:expected_full_path) { "#{container.container.full_path}.wiki" }
let(:expected_web_url_path) { "#{container.container.web_url(only_path: true).sub(%r{^/}, '')}/-/wikis/home" }
+ let(:expected_lfs_enabled) { wiki_lfs_enabled }
+ end
+
+ describe '.container_class' do
+ it 'is set to the container class' do
+ expect(described_class.container_class).to eq(wiki_container.class)
+ end
+ end
+
+ describe '.find_by_id' do
+ it 'returns a wiki instance if the container is found' do
+ wiki = described_class.find_by_id(wiki_container.id)
+
+ expect(wiki).to be_a(described_class)
+ expect(wiki.container).to eq(wiki_container)
+ end
+
+ it 'returns nil if the container is not found' do
+ expect(described_class.find_by_id(-1)).to be_nil
+ end
+ end
+
+ describe '#initialize' do
+ it 'accepts a valid user' do
+ expect do
+ described_class.new(wiki_container, user)
+ end.not_to raise_error
+ end
+
+ it 'accepts a blank user' do
+ expect do
+ described_class.new(wiki_container, nil)
+ end.not_to raise_error
+ end
+
+ it 'raises an error for invalid users' do
+ expect do
+ described_class.new(wiki_container, Object.new)
+ end.to raise_error(ArgumentError, 'user must be a User, got Object')
+ end
+ end
+
+ describe '#run_after_commit' do
+ it 'delegates to the container' do
+ expect(wiki_container).to receive(:run_after_commit)
+
+ wiki.run_after_commit
+ end
+ end
+
+ describe '#==' do
+ it 'returns true for wikis from the same container' do
+ expect(wiki).to eq(described_class.new(wiki_container))
+ end
+
+ it 'returns false for wikis from different containers' do
+ expect(wiki).not_to eq(described_class.new(wiki_container_without_repo))
+ end
+ end
+
+ describe '#id' do
+ it 'returns the ID of the container' do
+ expect(wiki.id).to eq(wiki_container.id)
+ end
+ end
+
+ describe '#to_global_id' do
+ it 'returns a global ID' do
+ expect(wiki.to_global_id.to_s).to eq("gid://gitlab/#{wiki.class.name}/#{wiki.id}")
+ end
end
describe '#repository' do
it 'returns a wiki repository' do
expect(subject.repository.repo_type).to be_wiki
+ expect(subject.repository.container).to be(subject)
end
end
@@ -164,7 +242,7 @@ RSpec.shared_examples 'wiki model' do
def total_pages(entries)
entries.sum do |entry|
- entry.is_a?(WikiDirectory) ? entry.pages.size : 1
+ entry.is_a?(WikiDirectory) ? total_pages(entry.entries) : 1
end
end
@@ -204,8 +282,9 @@ RSpec.shared_examples 'wiki model' do
expect(page.title).to eq('index page')
end
- it 'returns nil if the page does not exist' do
- expect(subject.find_page('non-existent')).to eq(nil)
+ it 'returns nil if the page or version does not exist' do
+ expect(subject.find_page('non-existent')).to be_nil
+ expect(subject.find_page('index page', 'non-existent')).to be_nil
end
it 'can find a page by slug' do
diff --git a/spec/support/shared_examples/policies/resource_access_token_shared_examples.rb b/spec/support/shared_examples/policies/resource_access_token_shared_examples.rb
new file mode 100644
index 00000000000..7710e756e5b
--- /dev/null
+++ b/spec/support/shared_examples/policies/resource_access_token_shared_examples.rb
@@ -0,0 +1,32 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'Self-managed Core resource access tokens' do
+ before do
+ allow(::Gitlab).to receive(:com?).and_return(false)
+ end
+
+ context 'with owner' do
+ let(:current_user) { owner }
+
+ it { is_expected.to be_allowed(:admin_resource_access_tokens) }
+ end
+
+ context 'with developer' do
+ let(:current_user) { developer }
+
+ it { is_expected.not_to be_allowed(:admin_resource_access_tokens) }
+ end
+end
+
+RSpec.shared_examples 'GitLab.com Core resource access tokens' do
+ before do
+ allow(::Gitlab).to receive(:com?).and_return(true)
+ stub_ee_application_setting(should_check_namespace_plan: true)
+ end
+
+ context 'with owner' do
+ let(:current_user) { owner }
+
+ it { is_expected.not_to be_allowed(:admin_resource_access_tokens) }
+ end
+end
diff --git a/spec/support/shared_examples/quick_actions/issuable/issuable_quick_actions_shared_examples.rb b/spec/support/shared_examples/quick_actions/issuable/issuable_quick_actions_shared_examples.rb
index 50a8b81b518..3cdba315d1f 100644
--- a/spec/support/shared_examples/quick_actions/issuable/issuable_quick_actions_shared_examples.rb
+++ b/spec/support/shared_examples/quick_actions/issuable/issuable_quick_actions_shared_examples.rb
@@ -109,7 +109,7 @@ RSpec.shared_examples 'issuable quick actions' do
QuickAction.new(
action_text: "/unlock",
before_action: -> {
- issuable.update(discussion_locked: true)
+ issuable.update!(discussion_locked: true)
},
expectation: ->(noteable, can_use_quick_action) {
if can_use_quick_action
@@ -128,7 +128,7 @@ RSpec.shared_examples 'issuable quick actions' do
QuickAction.new(
action_text: "/remove_milestone",
before_action: -> {
- issuable.update(milestone_id: milestone.id)
+ issuable.update!(milestone_id: milestone.id)
},
expectation: ->(noteable, can_use_quick_action) {
if can_use_quick_action
@@ -171,7 +171,7 @@ RSpec.shared_examples 'issuable quick actions' do
QuickAction.new(
action_text: "/remove_estimate",
before_action: -> {
- issuable.update(time_estimate: 30000)
+ issuable.update!(time_estimate: 30000)
},
expectation: ->(noteable, can_use_quick_action) {
if can_use_quick_action
@@ -228,7 +228,7 @@ RSpec.shared_examples 'issuable quick actions' do
before do
project.add_developer(old_assignee)
- issuable.update(assignees: [old_assignee])
+ issuable.update!(assignees: [old_assignee])
end
context 'when user can update issuable' do
diff --git a/spec/support/shared_examples/quick_actions/merge_request/merge_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/merge_request/merge_quick_action_shared_examples.rb
index 258d9ab85e4..acbc6429646 100644
--- a/spec/support/shared_examples/quick_actions/merge_request/merge_quick_action_shared_examples.rb
+++ b/spec/support/shared_examples/quick_actions/merge_request/merge_quick_action_shared_examples.rb
@@ -52,7 +52,7 @@ RSpec.shared_examples 'merge quick action' do
context 'when the head diff changes in the meanwhile' do
before do
merge_request.source_branch = 'another_branch'
- merge_request.save
+ merge_request.save!
sign_in(user)
visit project_merge_request_path(project, merge_request)
end
diff --git a/spec/support/shared_examples/requests/api/composer_packages_shared_examples.rb b/spec/support/shared_examples/requests/api/composer_packages_shared_examples.rb
index 5c122b4b5d6..4b5299cebec 100644
--- a/spec/support/shared_examples/requests/api/composer_packages_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/composer_packages_shared_examples.rb
@@ -75,7 +75,7 @@ RSpec.shared_examples 'Composer package creation' do |user_type, status, add_mem
expect(response).to have_gitlab_http_status(status)
end
- it_behaves_like 'a gitlab tracking event', described_class.name, 'push_package'
+ it_behaves_like 'a package tracking event', described_class.name, 'push_package'
end
end
diff --git a/spec/support/shared_examples/requests/api/container_repositories_shared_examples.rb b/spec/support/shared_examples/requests/api/container_repositories_shared_examples.rb
index 3e058838773..e776cf13217 100644
--- a/spec/support/shared_examples/requests/api/container_repositories_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/container_repositories_shared_examples.rb
@@ -79,11 +79,3 @@ RSpec.shared_examples 'returns repositories for allowed users' do |user_type, sc
end
end
end
-
-RSpec.shared_examples 'a gitlab tracking event' do |category, action|
- it "creates a gitlab tracking event #{action}" do
- expect(Gitlab::Tracking).to receive(:event).with(category, action, {})
-
- subject
- end
-end
diff --git a/spec/support/shared_examples/requests/api/debian_packages_shared_examples.rb b/spec/support/shared_examples/requests/api/debian_packages_shared_examples.rb
new file mode 100644
index 00000000000..ec32cb4b2ff
--- /dev/null
+++ b/spec/support/shared_examples/requests/api/debian_packages_shared_examples.rb
@@ -0,0 +1,309 @@
+# frozen_string_literal: true
+
+RSpec.shared_context 'Debian repository shared context' do |object_type|
+ before do
+ stub_feature_flags(debian_packages: true)
+ end
+
+ if object_type == :project
+ let(:project) { create(:project, :public) }
+ elsif object_type == :group
+ let(:group) { create(:group, :public) }
+ end
+
+ let(:user) { create(:user) }
+ let(:personal_access_token) { create(:personal_access_token, user: user) }
+
+ let(:distribution) { 'bullseye' }
+ let(:component) { 'main' }
+ let(:architecture) { 'amd64' }
+ let(:source_package) { 'sample' }
+ let(:letter) { source_package[0..2] == 'lib' ? source_package[0..3] : source_package[0] }
+ let(:package_name) { 'libsample0' }
+ let(:package_version) { '1.2.3~alpha2-1' }
+ let(:file_name) { "#{package_name}_#{package_version}_#{architecture}.deb" }
+
+ let(:method) { :get }
+
+ let(:workhorse_params) do
+ if method == :put
+ file_upload = fixture_file_upload("spec/fixtures/packages/debian/#{file_name}")
+ { file: file_upload }
+ else
+ {}
+ end
+ end
+
+ let(:params) { workhorse_params }
+
+ let(:auth_headers) { {} }
+ let(:workhorse_headers) do
+ if method == :put
+ workhorse_token = JWT.encode({ 'iss' => 'gitlab-workhorse' }, Gitlab::Workhorse.secret, 'HS256')
+ { 'GitLab-Workhorse' => '1.0', Gitlab::Workhorse::INTERNAL_API_REQUEST_HEADER => workhorse_token }
+ else
+ {}
+ end
+ end
+
+ let(:headers) { auth_headers.merge(workhorse_headers) }
+
+ let(:send_rewritten_field) { true }
+
+ subject do
+ if method == :put
+ workhorse_finalize(
+ api(url),
+ method: method,
+ file_key: :file,
+ params: params,
+ headers: headers,
+ send_rewritten_field: send_rewritten_field
+ )
+ else
+ send method, api(url), headers: headers, params: params
+ end
+ end
+end
+
+RSpec.shared_context 'Debian repository auth headers' do |user_role, user_token, auth_method = :token|
+ let(:token) { user_token ? personal_access_token.token : 'wrong' }
+
+ let(:auth_headers) do
+ if user_role == :anonymous
+ {}
+ elsif auth_method == :token
+ { 'Private-Token' => token }
+ else
+ basic_auth_header(user.username, token)
+ end
+ end
+end
+
+RSpec.shared_context 'Debian repository project access' do |project_visibility_level, user_role, user_token, auth_method|
+ include_context 'Debian repository auth headers', user_role, user_token, auth_method do
+ before do
+ project.update_column(:visibility_level, Gitlab::VisibilityLevel.const_get(project_visibility_level, false))
+ end
+ end
+end
+
+RSpec.shared_examples 'Debian project repository GET request' do |user_role, add_member, status, body|
+ context "for user type #{user_role}" do
+ before do
+ project.send("add_#{user_role}", user) if add_member && user_role != :anonymous
+ end
+
+ and_body = body.nil? ? '' : ' and expected body'
+
+ it "returns #{status}#{and_body}" do
+ subject
+
+ expect(response).to have_gitlab_http_status(status)
+
+ unless body.nil?
+ expect(response.body).to eq(body)
+ end
+ end
+ end
+end
+
+RSpec.shared_examples 'Debian project repository PUT request' do |user_role, add_member, status, body|
+ context "for user type #{user_role}" do
+ before do
+ project.send("add_#{user_role}", user) if add_member && user_role != :anonymous
+ end
+
+ and_body = body.nil? ? '' : ' and expected body'
+
+ if status == :created
+ it 'creates package files' do
+ pending "Debian package creation not implemented"
+ expect { subject }
+ .to change { project.packages.debian.count }.by(1)
+
+ expect(response).to have_gitlab_http_status(status)
+
+ unless body.nil?
+ expect(response.body).to eq(body)
+ end
+ end
+ it_behaves_like 'a package tracking event', described_class.name, 'push_package'
+ else
+ it "returns #{status}#{and_body}" do
+ subject
+
+ expect(response).to have_gitlab_http_status(status)
+
+ unless body.nil?
+ expect(response.body).to eq(body)
+ end
+ end
+ end
+ end
+end
+
+RSpec.shared_examples 'rejects Debian access with unknown project id' do
+ context 'with an unknown project' do
+ let(:project) { double(id: non_existing_record_id) }
+
+ context 'as anonymous' do
+ it_behaves_like 'Debian project repository GET request', :anonymous, true, :not_found, nil
+ end
+
+ context 'as authenticated user' do
+ subject { get api(url), headers: basic_auth_header(user.username, personal_access_token.token) }
+
+ it_behaves_like 'Debian project repository GET request', :anonymous, true, :not_found, nil
+ end
+ end
+end
+
+RSpec.shared_examples 'Debian project repository GET endpoint' do |success_status, success_body|
+ context 'with valid project' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:project_visibility_level, :user_role, :member, :user_token, :expected_status, :expected_body) do
+ 'PUBLIC' | :developer | true | true | success_status | success_body
+ 'PUBLIC' | :guest | true | true | success_status | success_body
+ 'PUBLIC' | :developer | true | false | success_status | success_body
+ 'PUBLIC' | :guest | true | false | success_status | success_body
+ 'PUBLIC' | :developer | false | true | success_status | success_body
+ 'PUBLIC' | :guest | false | true | success_status | success_body
+ 'PUBLIC' | :developer | false | false | success_status | success_body
+ 'PUBLIC' | :guest | false | false | success_status | success_body
+ 'PUBLIC' | :anonymous | false | true | success_status | success_body
+ 'PRIVATE' | :developer | true | true | success_status | success_body
+ 'PRIVATE' | :guest | true | true | :forbidden | nil
+ 'PRIVATE' | :developer | true | false | :not_found | nil
+ 'PRIVATE' | :guest | true | false | :not_found | nil
+ 'PRIVATE' | :developer | false | true | :not_found | nil
+ 'PRIVATE' | :guest | false | true | :not_found | nil
+ 'PRIVATE' | :developer | false | false | :not_found | nil
+ 'PRIVATE' | :guest | false | false | :not_found | nil
+ 'PRIVATE' | :anonymous | false | true | :not_found | nil
+ end
+
+ with_them do
+ include_context 'Debian repository project access', params[:project_visibility_level], params[:user_role], params[:user_token], :basic do
+ it_behaves_like 'Debian project repository GET request', params[:user_role], params[:member], params[:expected_status], params[:expected_body]
+ end
+ end
+ end
+
+ it_behaves_like 'rejects Debian access with unknown project id'
+end
+
+RSpec.shared_examples 'Debian project repository PUT endpoint' do |success_status, success_body|
+ context 'with valid project' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:project_visibility_level, :user_role, :member, :user_token, :expected_status, :expected_body) do
+ 'PUBLIC' | :developer | true | true | success_status | nil
+ 'PUBLIC' | :guest | true | true | :forbidden | nil
+ 'PUBLIC' | :developer | true | false | :unauthorized | nil
+ 'PUBLIC' | :guest | true | false | :unauthorized | nil
+ 'PUBLIC' | :developer | false | true | :forbidden | nil
+ 'PUBLIC' | :guest | false | true | :forbidden | nil
+ 'PUBLIC' | :developer | false | false | :unauthorized | nil
+ 'PUBLIC' | :guest | false | false | :unauthorized | nil
+ 'PUBLIC' | :anonymous | false | true | :unauthorized | nil
+ 'PRIVATE' | :developer | true | true | success_status | nil
+ 'PRIVATE' | :guest | true | true | :forbidden | nil
+ 'PRIVATE' | :developer | true | false | :not_found | nil
+ 'PRIVATE' | :guest | true | false | :not_found | nil
+ 'PRIVATE' | :developer | false | true | :not_found | nil
+ 'PRIVATE' | :guest | false | true | :not_found | nil
+ 'PRIVATE' | :developer | false | false | :not_found | nil
+ 'PRIVATE' | :guest | false | false | :not_found | nil
+ 'PRIVATE' | :anonymous | false | true | :not_found | nil
+ end
+
+ with_them do
+ include_context 'Debian repository project access', params[:project_visibility_level], params[:user_role], params[:user_token], :basic do
+ it_behaves_like 'Debian project repository PUT request', params[:user_role], params[:member], params[:expected_status], params[:expected_body]
+ end
+ end
+ end
+
+ it_behaves_like 'rejects Debian access with unknown project id'
+end
+
+RSpec.shared_context 'Debian repository group access' do |group_visibility_level, user_role, user_token, auth_method|
+ include_context 'Debian repository auth headers', user_role, user_token, auth_method do
+ before do
+ group.update_column(:visibility_level, Gitlab::VisibilityLevel.const_get(group_visibility_level, false))
+ end
+ end
+end
+
+RSpec.shared_examples 'Debian group repository GET request' do |user_role, add_member, status, body|
+ context "for user type #{user_role}" do
+ before do
+ group.send("add_#{user_role}", user) if add_member && user_role != :anonymous
+ end
+
+ and_body = body.nil? ? '' : ' and expected body'
+
+ it "returns #{status}#{and_body}" do
+ subject
+
+ expect(response).to have_gitlab_http_status(status)
+
+ unless body.nil?
+ expect(response.body).to eq(body)
+ end
+ end
+ end
+end
+
+RSpec.shared_examples 'rejects Debian access with unknown group id' do
+ context 'with an unknown group' do
+ let(:group) { double(id: non_existing_record_id) }
+
+ context 'as anonymous' do
+ it_behaves_like 'Debian group repository GET request', :anonymous, true, :not_found, nil
+ end
+
+ context 'as authenticated user' do
+ subject { get api(url), headers: basic_auth_header(user.username, personal_access_token.token) }
+
+ it_behaves_like 'Debian group repository GET request', :anonymous, true, :not_found, nil
+ end
+ end
+end
+
+RSpec.shared_examples 'Debian group repository GET endpoint' do |success_status, success_body|
+ context 'with valid group' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:group_visibility_level, :user_role, :member, :user_token, :expected_status, :expected_body) do
+ 'PUBLIC' | :developer | true | true | success_status | success_body
+ 'PUBLIC' | :guest | true | true | success_status | success_body
+ 'PUBLIC' | :developer | true | false | success_status | success_body
+ 'PUBLIC' | :guest | true | false | success_status | success_body
+ 'PUBLIC' | :developer | false | true | success_status | success_body
+ 'PUBLIC' | :guest | false | true | success_status | success_body
+ 'PUBLIC' | :developer | false | false | success_status | success_body
+ 'PUBLIC' | :guest | false | false | success_status | success_body
+ 'PUBLIC' | :anonymous | false | true | success_status | success_body
+ 'PRIVATE' | :developer | true | true | success_status | success_body
+ 'PRIVATE' | :guest | true | true | :forbidden | nil
+ 'PRIVATE' | :developer | true | false | :not_found | nil
+ 'PRIVATE' | :guest | true | false | :not_found | nil
+ 'PRIVATE' | :developer | false | true | :not_found | nil
+ 'PRIVATE' | :guest | false | true | :not_found | nil
+ 'PRIVATE' | :developer | false | false | :not_found | nil
+ 'PRIVATE' | :guest | false | false | :not_found | nil
+ 'PRIVATE' | :anonymous | false | true | :not_found | nil
+ end
+
+ with_them do
+ include_context 'Debian repository group access', params[:group_visibility_level], params[:user_role], params[:user_token], :basic do
+ it_behaves_like 'Debian group repository GET request', params[:user_role], params[:member], params[:expected_status], params[:expected_body]
+ end
+ end
+ end
+
+ it_behaves_like 'rejects Debian access with unknown group id'
+end
diff --git a/spec/support/shared_examples/requests/api/graphql/group_and_project_boards_query_shared_examples.rb b/spec/support/shared_examples/requests/api/graphql/group_and_project_boards_query_shared_examples.rb
index f26af6cb766..5145880ef9a 100644
--- a/spec/support/shared_examples/requests/api/graphql/group_and_project_boards_query_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/graphql/group_and_project_boards_query_shared_examples.rb
@@ -90,7 +90,7 @@ RSpec.shared_examples 'group and project boards query' do
it_behaves_like 'a working graphql query' do
before do
- post_graphql(query_single_board, current_user: current_user)
+ post_graphql(query_single_board("id: \"gid://gitlab/Board/1\""), current_user: current_user)
end
end
diff --git a/spec/support/shared_examples/requests/api/nuget_packages_shared_examples.rb b/spec/support/shared_examples/requests/api/nuget_packages_shared_examples.rb
index 6aac51a5903..58e99776fd9 100644
--- a/spec/support/shared_examples/requests/api/nuget_packages_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/nuget_packages_shared_examples.rb
@@ -26,7 +26,7 @@ RSpec.shared_examples 'process nuget service index request' do |user_type, statu
it_behaves_like 'returning response status', status
- it_behaves_like 'a gitlab tracking event', described_class.name, 'nuget_service_index'
+ it_behaves_like 'a package tracking event', described_class.name, 'cli_metadata'
it 'returns a valid json response' do
subject
@@ -169,7 +169,7 @@ RSpec.shared_examples 'process nuget upload' do |user_type, status, add_member =
context 'with correct params' do
it_behaves_like 'package workhorse uploads'
it_behaves_like 'creates nuget package files'
- it_behaves_like 'a gitlab tracking event', described_class.name, 'push_package'
+ it_behaves_like 'a package tracking event', described_class.name, 'push_package'
end
end
@@ -286,7 +286,7 @@ RSpec.shared_examples 'process nuget download content request' do |user_type, st
it_behaves_like 'returning response status', status
- it_behaves_like 'a gitlab tracking event', described_class.name, 'pull_package'
+ it_behaves_like 'a package tracking event', described_class.name, 'pull_package'
it 'returns a valid package archive' do
subject
@@ -336,7 +336,7 @@ RSpec.shared_examples 'process nuget search request' do |user_type, status, add_
it_behaves_like 'returns a valid json search response', status, 4, [1, 5, 5, 1]
- it_behaves_like 'a gitlab tracking event', described_class.name, 'search_package'
+ it_behaves_like 'a package tracking event', described_class.name, 'search_package'
context 'with skip set to 2' do
let(:skip) { 2 }
diff --git a/spec/support/shared_examples/requests/api/packages_shared_examples.rb b/spec/support/shared_examples/requests/api/packages_shared_examples.rb
index c9a33701161..d730ed53109 100644
--- a/spec/support/shared_examples/requests/api/packages_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/packages_shared_examples.rb
@@ -126,3 +126,11 @@ RSpec.shared_examples 'job token for package uploads' do
end
end
end
+
+RSpec.shared_examples 'a package tracking event' do |category, action|
+ it "creates a gitlab tracking event #{action}" do
+ expect(Gitlab::Tracking).to receive(:event).with(category, action, {})
+
+ expect { subject }.to change { Packages::Event.count }.by(1)
+ end
+end
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 715c494840e..bbcf856350d 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
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-RSpec.shared_examples 'PyPi package creation' do |user_type, status, add_member = true|
+RSpec.shared_examples 'PyPI package creation' do |user_type, status, add_member = true|
RSpec.shared_examples 'creating pypi package files' do
it 'creates package files' do
expect { subject }
@@ -52,7 +52,7 @@ RSpec.shared_examples 'PyPi package creation' do |user_type, status, add_member
context 'with correct params' do
it_behaves_like 'package workhorse uploads'
it_behaves_like 'creating pypi package files'
- it_behaves_like 'a gitlab tracking event', described_class.name, 'push_package'
+ it_behaves_like 'a package tracking event', described_class.name, 'push_package'
end
end
@@ -106,7 +106,7 @@ RSpec.shared_examples 'PyPi package creation' do |user_type, status, add_member
end
end
-RSpec.shared_examples 'PyPi package versions' do |user_type, status, add_member = true|
+RSpec.shared_examples 'PyPI package versions' do |user_type, status, add_member = true|
context "for user type #{user_type}" do
before do
project.send("add_#{user_type}", user) if add_member && user_type != :anonymous
@@ -119,11 +119,11 @@ RSpec.shared_examples 'PyPi package versions' do |user_type, status, add_member
end
it_behaves_like 'returning response status', status
- it_behaves_like 'a gitlab tracking event', described_class.name, 'list_package'
+ it_behaves_like 'a package tracking event', described_class.name, 'list_package'
end
end
-RSpec.shared_examples 'PyPi package download' do |user_type, status, add_member = true|
+RSpec.shared_examples 'PyPI package download' do |user_type, status, add_member = true|
context "for user type #{user_type}" do
before do
project.send("add_#{user_type}", user) if add_member && user_type != :anonymous
@@ -136,11 +136,11 @@ RSpec.shared_examples 'PyPi package download' do |user_type, status, add_member
end
it_behaves_like 'returning response status', status
- it_behaves_like 'a gitlab tracking event', described_class.name, 'pull_package'
+ it_behaves_like 'a package tracking event', described_class.name, 'pull_package'
end
end
-RSpec.shared_examples 'process PyPi api request' do |user_type, status, add_member = true|
+RSpec.shared_examples 'process PyPI api request' do |user_type, status, add_member = true|
context "for user type #{user_type}" do
before do
project.send("add_#{user_type}", user) if add_member && user_type != :anonymous
@@ -155,13 +155,13 @@ RSpec.shared_examples 'rejects PyPI access with unknown project id' do
let(:project) { OpenStruct.new(id: 1234567890) }
context 'as anonymous' do
- it_behaves_like 'process PyPi api request', :anonymous, :not_found
+ it_behaves_like 'process PyPI api request', :anonymous, :not_found
end
context 'as authenticated user' do
subject { get api(url), headers: basic_auth_header(user.username, personal_access_token.token) }
- it_behaves_like 'process PyPi api request', :anonymous, :not_found
+ it_behaves_like 'process PyPI api request', :anonymous, :not_found
end
end
end
diff --git a/spec/support/shared_examples/requests/api/snippets_shared_examples.rb b/spec/support/shared_examples/requests/api/snippets_shared_examples.rb
index 051367fbe96..2b72c69cb37 100644
--- a/spec/support/shared_examples/requests/api/snippets_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/snippets_shared_examples.rb
@@ -1,46 +1,30 @@
# frozen_string_literal: true
RSpec.shared_examples 'raw snippet files' do
- let_it_be(:unauthorized_user) { create(:user) }
+ let_it_be(:user_token) { create(:personal_access_token, user: snippet.author) }
let(:snippet_id) { snippet.id }
let(:user) { snippet.author }
let(:file_path) { '%2Egitattributes' }
let(:ref) { 'master' }
- context 'with no user' do
- it 'requires authentication' do
- get api(api_path)
+ subject { get api(api_path, personal_access_token: user_token) }
- expect(response).to have_gitlab_http_status(:unauthorized)
- end
- end
+ context 'with an invalid snippet ID' do
+ let(:snippet_id) { non_existing_record_id }
- shared_examples 'not found' do
it 'returns 404' do
- get api(api_path, user)
+ subject
expect(response).to have_gitlab_http_status(:not_found)
expect(json_response['message']).to eq('404 Snippet Not Found')
end
end
- context 'when not authorized' do
- let(:user) { unauthorized_user }
-
- it_behaves_like 'not found'
- end
-
- context 'with an invalid snippet ID' do
- let(:snippet_id) { 'invalid' }
-
- it_behaves_like 'not found'
- end
-
context 'with valid params' do
it 'returns the raw file info' do
expect(Gitlab::Workhorse).to receive(:send_git_blob).and_call_original
- get api(api_path, user)
+ subject
aggregate_failures do
expect(response).to have_gitlab_http_status(:ok)
@@ -52,6 +36,17 @@ RSpec.shared_examples 'raw snippet files' do
end
end
+ context 'with unauthorized user' do
+ let(:user_token) { create(:personal_access_token) }
+
+ it 'returns 404' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ expect(json_response['message']).to eq('404 Snippet Not Found')
+ end
+ end
+
context 'with invalid params' do
using RSpec::Parameterized::TableSyntax
@@ -68,12 +63,12 @@ RSpec.shared_examples 'raw snippet files' do
end
with_them do
- before do
- get api(api_path, user)
- end
+ it 'returns the proper response code and message' do
+ subject
- it { expect(response).to have_gitlab_http_status(status) }
- it { expect(json_response[key]).to eq(message) }
+ expect(response).to have_gitlab_http_status(status)
+ expect(json_response[key]).to eq(message)
+ end
end
end
end
@@ -216,3 +211,133 @@ RSpec.shared_examples 'invalid snippet updates' do
expect(json_response['error']).to eq 'title is empty'
end
end
+
+RSpec.shared_examples 'snippet access with different users' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:requester, :visibility, :status) do
+ :admin | :public | :ok
+ :admin | :private | :ok
+ :admin | :internal | :ok
+ :author | :public | :ok
+ :author | :private | :ok
+ :author | :internal | :ok
+ :other | :public | :ok
+ :other | :private | :not_found
+ :other | :internal | :ok
+ nil | :public | :ok
+ nil | :private | :not_found
+ nil | :internal | :not_found
+ end
+
+ with_them do
+ let(:snippet) { snippet_for(visibility) }
+
+ it 'returns the correct response' do
+ request_user = user_for(requester)
+
+ get api(path, request_user)
+
+ expect(response).to have_gitlab_http_status(status)
+ end
+ end
+
+ def user_for(user_type)
+ case user_type
+ when :author
+ user
+ when :other
+ other_user
+ when :admin
+ admin
+ else
+ nil
+ end
+ end
+
+ def snippet_for(snippet_type)
+ case snippet_type
+ when :private
+ private_snippet
+ when :internal
+ internal_snippet
+ when :public
+ public_snippet
+ end
+ end
+end
+
+RSpec.shared_examples 'expected response status' do
+ it 'returns the correct response' do
+ get api(path, personal_access_token: user_token)
+
+ expect(response).to have_gitlab_http_status(status)
+ end
+end
+
+RSpec.shared_examples 'unauthenticated project snippet access' do
+ using RSpec::Parameterized::TableSyntax
+
+ let(:user_token) { nil }
+
+ where(:project_visibility, :snippet_visibility, :status) do
+ :public | :public | :ok
+ :public | :private | :not_found
+ :public | :internal | :not_found
+ :internal | :public | :not_found
+ :private | :public | :not_found
+ end
+
+ with_them do
+ it_behaves_like 'expected response status'
+ end
+end
+
+RSpec.shared_examples 'non-member project snippet access' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:project_visibility, :snippet_visibility, :status) do
+ :public | :public | :ok
+ :public | :internal | :ok
+ :internal | :public | :ok
+ :public | :private | :not_found
+ :private | :public | :not_found
+ end
+
+ with_them do
+ it_behaves_like 'expected response status'
+ end
+end
+
+RSpec.shared_examples 'member project snippet access' do
+ using RSpec::Parameterized::TableSyntax
+
+ before do
+ project.add_guest(user)
+ end
+
+ where(:project_visibility, :snippet_visibility, :status) do
+ :public | :public | :ok
+ :public | :internal | :ok
+ :internal | :public | :ok
+ :public | :private | :ok
+ :private | :public | :ok
+ end
+
+ with_them do
+ it_behaves_like 'expected response status'
+ end
+end
+
+RSpec.shared_examples 'project snippet access levels' do
+ let_it_be(:user_token) { create(:personal_access_token, user: user) }
+
+ let(:project) { create(:project, project_visibility) }
+ let(:snippet) { create(:project_snippet, :repository, snippet_visibility, project: project) }
+
+ it_behaves_like 'unauthenticated project snippet access'
+
+ it_behaves_like 'non-member project snippet access'
+
+ it_behaves_like 'member project snippet access'
+end
diff --git a/spec/support/shared_examples/requests/api/tracking_shared_examples.rb b/spec/support/shared_examples/requests/api/tracking_shared_examples.rb
new file mode 100644
index 00000000000..2e6feae3f98
--- /dev/null
+++ b/spec/support/shared_examples/requests/api/tracking_shared_examples.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'a gitlab tracking event' do |category, action|
+ it "creates a gitlab tracking event #{action}" do
+ expect(Gitlab::Tracking).to receive(:event).with(category, action, {})
+
+ subject
+ end
+end
diff --git a/spec/support/shared_examples/requests/rack_attack_shared_examples.rb b/spec/support/shared_examples/requests/rack_attack_shared_examples.rb
index 08ccbd4a9c1..730df4dc5ab 100644
--- a/spec/support/shared_examples/requests/rack_attack_shared_examples.rb
+++ b/spec/support/shared_examples/requests/rack_attack_shared_examples.rb
@@ -48,7 +48,7 @@ RSpec.shared_examples 'rate-limited token-authenticated requests' do
expect_rejection { make_request(request_args) }
- Timecop.travel(period.from_now) do
+ travel_to(period.from_now) do
requests_per_period.times do
make_request(request_args)
expect(response).not_to have_gitlab_http_status(:too_many_requests)
@@ -175,7 +175,7 @@ RSpec.shared_examples 'rate-limited web authenticated requests' do
expect_rejection { request_authenticated_web_url }
- Timecop.travel(period.from_now) do
+ travel_to(period.from_now) do
requests_per_period.times do
request_authenticated_web_url
expect(response).not_to have_gitlab_http_status(:too_many_requests)
diff --git a/spec/support/shared_examples/requests/snippet_shared_examples.rb b/spec/support/shared_examples/requests/snippet_shared_examples.rb
index 84ef7723b9b..dae3a3e74be 100644
--- a/spec/support/shared_examples/requests/snippet_shared_examples.rb
+++ b/spec/support/shared_examples/requests/snippet_shared_examples.rb
@@ -99,18 +99,6 @@ RSpec.shared_examples 'snippet blob content' do
end
end
-RSpec.shared_examples 'snippet_multiple_files feature disabled' do
- before do
- stub_feature_flags(snippet_multiple_files: false)
-
- subject
- end
-
- it 'does not return files attributes' do
- expect(json_response).not_to have_key('files')
- end
-end
-
RSpec.shared_examples 'snippet creation with files parameter' do
using RSpec::Parameterized::TableSyntax
diff --git a/spec/support/shared_examples/requests/user_activity_shared_examples.rb b/spec/support/shared_examples/requests/user_activity_shared_examples.rb
new file mode 100644
index 00000000000..37da1ce5c63
--- /dev/null
+++ b/spec/support/shared_examples/requests/user_activity_shared_examples.rb
@@ -0,0 +1,97 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'updating of user activity' do |paths_to_visit|
+ let(:user) { create(:user, last_activity_on: nil) }
+
+ before do
+ group = create(:group, name: 'group')
+ project = create(:project, :public, namespace: group, name: 'project')
+
+ create(:issue, project: project, iid: 10)
+ create(:merge_request, source_project: project, iid: 15)
+
+ project.add_maintainer(user)
+ end
+
+ context 'without an authenticated user' do
+ it 'does not set the last activity cookie' do
+ get "/group/project"
+
+ expect(response.cookies['user_last_activity_on']).to be_nil
+ end
+ end
+
+ context 'with an authenticated user' do
+ before do
+ login_as(user)
+ end
+
+ context 'with a POST request' do
+ it 'does not set the last activity cookie' do
+ post "/group/project/archive"
+
+ expect(response.cookies['user_last_activity_on']).to be_nil
+ end
+ end
+
+ paths_to_visit.each do |path|
+ context "on GET to #{path}" do
+ it 'updates the last activity date' do
+ expect(Users::ActivityService).to receive(:new).and_call_original
+
+ get path
+
+ expect(user.last_activity_on).to eq(Date.today)
+ end
+
+ context 'when calling it twice' do
+ it 'updates last_activity_on just once' do
+ expect(Users::ActivityService).to receive(:new).once.and_call_original
+
+ 2.times do
+ get path
+ end
+ end
+ end
+
+ context 'when last_activity_on is nil' do
+ before do
+ user.update_attribute(:last_activity_on, nil)
+ end
+
+ it 'updates the last activity date' do
+ expect(user.last_activity_on).to be_nil
+
+ get path
+
+ expect(user.last_activity_on).to eq(Date.today)
+ end
+ end
+
+ context 'when last_activity_on is stale' do
+ before do
+ user.update_attribute(:last_activity_on, 2.days.ago.to_date)
+ end
+
+ it 'updates the last activity date' do
+ get path
+
+ expect(user.last_activity_on).to eq(Date.today)
+ end
+ end
+
+ context 'when last_activity_on is up to date' do
+ before do
+ user.update_attribute(:last_activity_on, Date.today)
+ end
+
+ it 'does not try to update it' do
+ expect(Users::ActivityService).not_to receive(:new)
+
+ get path
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/spec/support/shared_examples/serializers/note_entity_shared_examples.rb b/spec/support/shared_examples/serializers/note_entity_shared_examples.rb
index 7b2ec02c7b6..a90a2dc3667 100644
--- a/spec/support/shared_examples/serializers/note_entity_shared_examples.rb
+++ b/spec/support/shared_examples/serializers/note_entity_shared_examples.rb
@@ -24,7 +24,7 @@ RSpec.shared_examples 'note entity' do
context 'when note was edited' do
before do
- note.update(updated_at: 1.minute.from_now, updated_by: user)
+ note.update!(updated_at: 1.minute.from_now, updated_by: user)
end
it 'exposes last_edited_at and last_edited_by elements' do
@@ -34,7 +34,7 @@ RSpec.shared_examples 'note entity' do
context 'when note is a system note' do
before do
- note.update(system: true)
+ note.update!(system: true)
end
it 'exposes system_note_icon_name element' do
diff --git a/spec/support/shared_examples/services/boards/boards_create_service_shared_examples.rb b/spec/support/shared_examples/services/boards/boards_create_service_shared_examples.rb
index fced2e59ace..f28c78aec97 100644
--- a/spec/support/shared_examples/services/boards/boards_create_service_shared_examples.rb
+++ b/spec/support/shared_examples/services/boards/boards_create_service_shared_examples.rb
@@ -7,7 +7,7 @@ RSpec.shared_examples 'boards create service' do
end
it 'creates the default lists' do
- board = service.execute
+ board = service.execute.payload
expect(board.lists.size).to eq 2
expect(board.lists.first).to be_backlog
diff --git a/spec/support/shared_examples/services/boards/issues_move_service_shared_examples.rb b/spec/support/shared_examples/services/boards/issues_move_service_shared_examples.rb
index f352b430cc7..4aa5d7d890b 100644
--- a/spec/support/shared_examples/services/boards/issues_move_service_shared_examples.rb
+++ b/spec/support/shared_examples/services/boards/issues_move_service_shared_examples.rb
@@ -131,7 +131,7 @@ RSpec.shared_examples 'issues move service' do |group|
updated_at1 = issue1.updated_at
updated_at2 = issue2.updated_at
- Timecop.travel(1.minute.from_now) do
+ travel_to(1.minute.from_now) do
described_class.new(parent, user, params).execute(issue)
end
diff --git a/spec/support/shared_examples/services/incident_shared_examples.rb b/spec/support/shared_examples/services/incident_shared_examples.rb
index d6e79931df5..39c22ac8aa3 100644
--- a/spec/support/shared_examples/services/incident_shared_examples.rb
+++ b/spec/support/shared_examples/services/incident_shared_examples.rb
@@ -45,3 +45,74 @@ RSpec.shared_examples 'not an incident issue' do
expect(issue.labels).not_to include(have_attributes(label_properties))
end
end
+
+# This shared example is to test the execution of incident management label services
+# For example:
+# - IncidentManagement::CreateIncidentSlaExceededLabelService
+# - IncidentManagement::CreateIncidentLabelService
+
+# It doesn't require any defined variables
+
+RSpec.shared_examples 'incident management label service' do
+ let_it_be(:project) { create(:project, :private) }
+ let_it_be(:user) { User.alert_bot }
+ let(:service) { described_class.new(project, user) }
+
+ subject(:execute) { service.execute }
+
+ describe 'execute' do
+ let(:incident_label_attributes) { described_class::LABEL_PROPERTIES }
+ let(:title) { incident_label_attributes[:title] }
+ let(:color) { incident_label_attributes[:color] }
+ let(:description) { incident_label_attributes[:description] }
+
+ shared_examples 'existing label' do
+ it 'returns the existing label' do
+ expect { execute }.not_to change(Label, :count)
+
+ expect(execute).to be_success
+ expect(execute.payload).to eq(label: label)
+ end
+ end
+
+ shared_examples 'new label' do
+ it 'creates a new label' do
+ expect { execute }.to change(Label, :count).by(1)
+
+ label = project.reload.labels.last
+ expect(execute).to be_success
+ expect(execute.payload).to eq(label: label)
+ expect(label.title).to eq(title)
+ expect(label.color).to eq(color)
+ expect(label.description).to eq(description)
+ end
+ end
+
+ context 'with predefined project label' do
+ it_behaves_like 'existing label' do
+ let!(:label) { create(:label, project: project, title: title) }
+ end
+ end
+
+ context 'with predefined group label' do
+ let(:project) { create(:project, group: group) }
+ let(:group) { create(:group) }
+
+ it_behaves_like 'existing label' do
+ let!(:label) { create(:group_label, group: group, title: title) }
+ end
+ end
+
+ context 'without label' do
+ context 'when user has permissions to create labels' do
+ it_behaves_like 'new label'
+ end
+
+ context 'when user has no permissions to create labels' do
+ let_it_be(:user) { create(:user) }
+
+ it_behaves_like 'new label'
+ end
+ end
+ end
+end
diff --git a/spec/support/shared_examples/services/merge_request_shared_examples.rb b/spec/support/shared_examples/services/merge_request_shared_examples.rb
index a7032640217..2bd06ac3e9c 100644
--- a/spec/support/shared_examples/services/merge_request_shared_examples.rb
+++ b/spec/support/shared_examples/services/merge_request_shared_examples.rb
@@ -13,11 +13,10 @@ RSpec.shared_examples 'reviewer_ids filter' do
end
context 'with reviewer_ids' do
- let(:reviewer_ids_param) { { reviewer_ids: [reviewer1.id, reviewer2.id, reviewer3.id] } }
+ let(:reviewer_ids_param) { { reviewer_ids: [reviewer1.id, reviewer2.id] } }
let(:reviewer1) { create(:user) }
let(:reviewer2) { create(:user) }
- let(:reviewer3) { create(:user) }
context 'when the current user can admin the merge_request' do
context 'when merge_request_reviewer feature is enabled' do
@@ -25,14 +24,13 @@ RSpec.shared_examples 'reviewer_ids filter' do
stub_feature_flags(merge_request_reviewer: true)
end
- context 'with reviewers who can read the merge_request' do
+ context 'with a reviewer who can read the merge_request' do
before do
project.add_developer(reviewer1)
- project.add_developer(reviewer2)
end
it 'contains reviewers who can read the merge_request' do
- expect(execute.reviewers).to contain_exactly(reviewer1, reviewer2)
+ expect(execute.reviewers).to contain_exactly(reviewer1)
end
end
end
diff --git a/spec/support/shared_examples/services/packages_shared_examples.rb b/spec/support/shared_examples/services/packages_shared_examples.rb
index 7fd59c3d963..65f4b3b5513 100644
--- a/spec/support/shared_examples/services/packages_shared_examples.rb
+++ b/spec/support/shared_examples/services/packages_shared_examples.rb
@@ -170,6 +170,8 @@ RSpec.shared_examples 'filters on each package_type' do |is_project: false|
let_it_be(:package5) { create(:pypi_package, project: project) }
let_it_be(:package6) { create(:composer_package, project: project) }
let_it_be(:package7) { create(:generic_package, project: project) }
+ let_it_be(:package8) { create(:golang_package, project: project) }
+ let_it_be(:package9) { create(:debian_package, project: project) }
Packages::Package.package_types.keys.each do |package_type|
context "for package type #{package_type}" do
diff --git a/spec/support/shared_examples/services/projects/urls_with_escaped_elements_shared_example.rb b/spec/support/shared_examples/services/projects/urls_with_escaped_elements_shared_example.rb
new file mode 100644
index 00000000000..df8b1f91629
--- /dev/null
+++ b/spec/support/shared_examples/services/projects/urls_with_escaped_elements_shared_example.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+# Shared examples that test requests against URLs with escaped elements
+#
+RSpec.shared_examples "URLs containing escaped elements return expected status" do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:url, :result_status) do
+ "https://user:0a%23@test.example.com/project.git" | :success
+ "https://git.example.com:1%2F%2F@source.developers.google.com/project.git" | :success
+ CGI.escape("git://localhost:1234/some-path?some-query=some-val\#@example.com/") | :error
+ CGI.escape(CGI.escape("https://user:0a%23@test.example.com/project.git")) | :error
+ end
+
+ with_them do
+ it "returns expected status" do
+ expect(result[:status]).to eq(result_status)
+ end
+ end
+end
diff --git a/spec/support/shared_examples/validators/ip_address_validator_shared_examples.rb b/spec/support/shared_examples/validators/ip_address_validator_shared_examples.rb
new file mode 100644
index 00000000000..5680d4f772c
--- /dev/null
+++ b/spec/support/shared_examples/validators/ip_address_validator_shared_examples.rb
@@ -0,0 +1,10 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'validates IP address' do
+ subject { object }
+
+ it { is_expected.to allow_value('192.168.17.43').for(attribute.to_sym) }
+ it { is_expected.to allow_value('2001:0db8:85a3:0000:0000:8a2e:0370:7334').for(attribute.to_sym) }
+
+ it { is_expected.not_to allow_value('invalid IP').for(attribute.to_sym) }
+end
diff --git a/spec/support/test_reports/test_reports_helper.rb b/spec/support/test_reports/test_reports_helper.rb
index ad9ecb6f460..18b40a20cf1 100644
--- a/spec/support/test_reports/test_reports_helper.rb
+++ b/spec/support/test_reports/test_reports_helper.rb
@@ -3,6 +3,7 @@
module TestReportsHelper
def create_test_case_rspec_success(name = 'test_spec')
Gitlab::Ci::Reports::TestCase.new(
+ suite_name: 'rspec',
name: 'Test#sum when a is 1 and b is 3 returns summary',
classname: "spec.#{name}",
file: './spec/test_spec.rb',
@@ -12,6 +13,7 @@ module TestReportsHelper
def create_test_case_rspec_failed(name = 'test_spec', execution_time = 2.22)
Gitlab::Ci::Reports::TestCase.new(
+ suite_name: 'rspec',
name: 'Test#sum when a is 1 and b is 3 returns summary',
classname: "spec.#{name}",
file: './spec/test_spec.rb',
@@ -22,6 +24,7 @@ module TestReportsHelper
def create_test_case_rspec_skipped(name = 'test_spec')
Gitlab::Ci::Reports::TestCase.new(
+ suite_name: 'rspec',
name: 'Test#sum when a is 3 and b is 3 returns summary',
classname: "spec.#{name}",
file: './spec/test_spec.rb',
@@ -31,6 +34,7 @@ module TestReportsHelper
def create_test_case_rspec_error(name = 'test_spec')
Gitlab::Ci::Reports::TestCase.new(
+ suite_name: 'rspec',
name: 'Test#sum when a is 4 and b is 4 returns summary',
classname: "spec.#{name}",
file: './spec/test_spec.rb',
@@ -52,6 +56,7 @@ module TestReportsHelper
def create_test_case_java_success(name = 'addTest')
Gitlab::Ci::Reports::TestCase.new(
+ suite_name: 'java',
name: name,
classname: 'CalculatorTest',
execution_time: 5.55,
@@ -60,6 +65,7 @@ module TestReportsHelper
def create_test_case_java_failed(name = 'addTest')
Gitlab::Ci::Reports::TestCase.new(
+ suite_name: 'java',
name: name,
classname: 'CalculatorTest',
execution_time: 6.66,
@@ -69,6 +75,7 @@ module TestReportsHelper
def create_test_case_java_skipped(name = 'addTest')
Gitlab::Ci::Reports::TestCase.new(
+ suite_name: 'java',
name: name,
classname: 'CalculatorTest',
execution_time: 7.77,
@@ -77,6 +84,7 @@ module TestReportsHelper
def create_test_case_java_error(name = 'addTest')
Gitlab::Ci::Reports::TestCase.new(
+ suite_name: 'java',
name: name,
classname: 'CalculatorTest',
execution_time: 8.88,
diff --git a/spec/support_specs/helpers/stub_feature_flags_spec.rb b/spec/support_specs/helpers/stub_feature_flags_spec.rb
index 5d1e4e1627d..57dd3015f5e 100644
--- a/spec/support_specs/helpers/stub_feature_flags_spec.rb
+++ b/spec/support_specs/helpers/stub_feature_flags_spec.rb
@@ -3,12 +3,31 @@
require 'spec_helper'
RSpec.describe StubFeatureFlags do
- let(:feature_name) { :test_feature }
+ let_it_be(:dummy_feature_flag) { :dummy_feature_flag }
+
+ # We inject dummy feature flag defintion
+ # to ensure that we strong validate it's usage
+ # as well
+ before(:all) do
+ definition = Feature::Definition.new(
+ nil,
+ name: dummy_feature_flag,
+ type: 'development',
+ # we allow ambigious usage of `default_enabled:`
+ default_enabled: [false, true]
+ )
+
+ Feature::Definition.definitions[dummy_feature_flag] = definition
+ end
+
+ after(:all) do
+ Feature::Definition.definitions.delete(dummy_feature_flag)
+ end
describe '#stub_feature_flags' do
using RSpec::Parameterized::TableSyntax
- let(:feature_name) { :test_feature }
+ let(:feature_name) { dummy_feature_flag }
context 'when checking global state' do
where(:feature_actors, :expected_result) do
@@ -121,14 +140,14 @@ RSpec.describe StubFeatureFlags do
describe 'stub timing' do
context 'let_it_be variable' do
- let_it_be(:let_it_be_var) { Feature.enabled?(:any_feature_flag) }
+ let_it_be(:let_it_be_var) { Feature.enabled?(dummy_feature_flag) }
it { expect(let_it_be_var).to eq true }
end
context 'before_all variable' do
before_all do
- @suite_var = Feature.enabled?(:any_feature_flag)
+ @suite_var = Feature.enabled?(dummy_feature_flag)
end
it { expect(@suite_var).to eq true }
@@ -136,14 +155,14 @@ RSpec.describe StubFeatureFlags do
context 'before(:all) variable' do
before(:all) do
- @suite_var = Feature.enabled?(:any_feature_flag)
+ @suite_var = Feature.enabled?(dummy_feature_flag)
end
it { expect(@suite_var).to eq true }
end
context 'with stub_feature_flags meta' do
- let(:var) { Feature.enabled?(:any_feature_flag) }
+ let(:var) { Feature.enabled?(dummy_feature_flag) }
context 'as true', :stub_feature_flags do
it { expect(var).to eq true }
diff --git a/spec/tasks/gitlab/backup_rake_spec.rb b/spec/tasks/gitlab/backup_rake_spec.rb
index a2cc2b12e5e..8963164ac53 100644
--- a/spec/tasks/gitlab/backup_rake_spec.rb
+++ b/spec/tasks/gitlab/backup_rake_spec.rb
@@ -284,62 +284,75 @@ RSpec.describe 'gitlab:app namespace rake task', :delete do
end
context 'multiple repository storages' do
- let_it_be(:default_storage_hash) { Gitlab.config.repositories.storages.default.to_h }
+ include StubConfiguration
+
+ let(:default_storage_name) { 'default' }
+ let(:second_storage_name) { 'test_second_storage' }
before do
# We only need a backup of the repositories for this test
stub_env('SKIP', 'db,uploads,builds,artifacts,lfs,registry')
-
- allow(Gitlab.config.repositories).to receive(:storages).and_return(storages)
-
- # Avoid asking gitaly about the root ref (which will fail because of the
- # mocked storages)
- allow_any_instance_of(Repository).to receive(:empty?).and_return(false)
-
- FileUtils.mkdir_p(b_storage_dir)
-
- # Even when overriding the storage, we have to move it there, so it exists
- Gitlab::GitalyClient::StorageSettings.allow_disk_access do
- FileUtils.mv(
- File.join(Settings.absolute(storages['default'].legacy_disk_path), project_b.repository.disk_path + '.git'),
- Rails.root.join(storages['test_second_storage'].legacy_disk_path, project_b.repository.disk_path + '.git')
- )
- end
- end
-
- after do
- FileUtils.rm_rf(test_second_storage_dir)
+ stub_storage_settings( second_storage_name => {
+ 'gitaly_address' => Gitlab.config.repositories.storages.default.gitaly_address,
+ 'path' => TestEnv::SECOND_STORAGE_PATH
+ })
end
- let(:test_second_storage_dir) { Dir.mktmpdir }
+ shared_examples 'includes repositories in all repository storages' do
+ specify :aggregate_failures do
+ project_a = create(:project, :repository)
+ project_a.track_project_repository
+ project_snippet_a = create(:project_snippet, :repository, project: project_a, author: project_a.owner)
+ project_b = create(:project, :repository, repository_storage: second_storage_name)
+ project_b.track_project_repository
+ project_snippet_b = create(:project_snippet, :repository, project: project_b, author: project_b.owner)
+ project_snippet_b.snippet_repository.update!(shard: project_b.project_repository.shard)
+ create(:wiki_page, container: project_a)
+ create(:design, :with_file, issue: create(:issue, project: project_a))
+
+ move_repository_to_secondary(project_b)
+ move_repository_to_secondary(project_snippet_b)
- let(:test_second_storage) do
- Gitlab::GitalyClient::StorageSettings.new(default_storage_hash.merge('path' => test_second_storage_dir))
- end
-
- let(:storages) do
- {
- 'default' => Gitlab.config.repositories.storages.default,
- 'test_second_storage' => test_second_storage
- }
- end
-
- let!(:project_a) { create(:project, :repository) }
- let!(:project_b) { create(:project, :repository, repository_storage: 'test_second_storage') }
- let!(:b_storage_dir) { File.join(test_second_storage_dir, File.dirname(project_b.disk_path)) }
-
- context 'no concurrency' do
- it 'includes repositories in all repository storages' do
expect { run_rake_task('gitlab:backup:create') }.to output.to_stdout
tar_contents, exit_status = Gitlab::Popen.popen(
%W{tar -tvf #{backup_tar} repositories}
)
+ tar_lines = tar_contents.lines.grep(/\.bundle/)
+
expect(exit_status).to eq(0)
- expect(tar_contents).to match("repositories/#{project_a.disk_path}.bundle")
- expect(tar_contents).to match("repositories/#{project_b.disk_path}.bundle")
+
+ [
+ "#{project_a.disk_path}.bundle",
+ "#{project_a.disk_path}.wiki.bundle",
+ "#{project_a.disk_path}.design.bundle",
+ "#{project_b.disk_path}.bundle",
+ "#{project_snippet_a.disk_path}.bundle",
+ "#{project_snippet_b.disk_path}.bundle"
+ ].each do |repo_name|
+ expect(tar_lines.grep(/#{repo_name}/).size).to eq 1
+ end
end
+
+ def move_repository_to_secondary(record)
+ Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+ default_shard_legacy_path = Gitlab.config.repositories.storages.default.legacy_disk_path
+ secondary_legacy_path = Gitlab.config.repositories.storages[second_storage_name].legacy_disk_path
+ dst_dir = File.join(secondary_legacy_path, File.dirname(record.disk_path))
+
+ FileUtils.mkdir_p(dst_dir) unless Dir.exist?(dst_dir)
+
+ FileUtils.mv(
+ File.join(default_shard_legacy_path, record.disk_path + '.git'),
+ File.join(secondary_legacy_path, record.disk_path + '.git')
+ )
+ end
+ end
+ end
+
+ context 'no concurrency' do
+ it_behaves_like 'includes repositories in all repository storages'
end
context 'with concurrency' do
@@ -347,17 +360,7 @@ RSpec.describe 'gitlab:app namespace rake task', :delete do
stub_env('GITLAB_BACKUP_MAX_CONCURRENCY', 4)
end
- it 'includes repositories in all repository storages' do
- expect { run_rake_task('gitlab:backup:create') }.to output.to_stdout
-
- tar_contents, exit_status = Gitlab::Popen.popen(
- %W{tar -tvf #{backup_tar} repositories}
- )
-
- expect(exit_status).to eq(0)
- expect(tar_contents).to match("repositories/#{project_a.disk_path}.bundle")
- expect(tar_contents).to match("repositories/#{project_b.disk_path}.bundle")
- end
+ it_behaves_like 'includes repositories in all repository storages'
end
end
@@ -370,7 +373,7 @@ RSpec.describe 'gitlab:app namespace rake task', :delete do
end
it 'has defaults' do
- expect_next_instance_of(::Backup::Repository) do |instance|
+ expect_next_instance_of(::Backup::Repositories) do |instance|
expect(instance).to receive(:dump)
.with(max_concurrency: 1, max_storage_concurrency: 1)
.and_call_original
@@ -383,7 +386,7 @@ RSpec.describe 'gitlab:app namespace rake task', :delete do
stub_env('GITLAB_BACKUP_MAX_CONCURRENCY', 5)
stub_env('GITLAB_BACKUP_MAX_STORAGE_CONCURRENCY', 2)
- expect_next_instance_of(::Backup::Repository) do |instance|
+ expect_next_instance_of(::Backup::Repositories) do |instance|
expect(instance).to receive(:dump)
.with(max_concurrency: 5, max_storage_concurrency: 2)
.and_call_original
diff --git a/spec/tasks/gitlab/db_rake_spec.rb b/spec/tasks/gitlab/db_rake_spec.rb
index 99efd394e83..046e066a45f 100644
--- a/spec/tasks/gitlab/db_rake_spec.rb
+++ b/spec/tasks/gitlab/db_rake_spec.rb
@@ -98,6 +98,29 @@ RSpec.describe 'gitlab:db namespace rake task' do
end
end
+ describe 'unattended' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:schema_migration_table_exists, :needs_migrations, :rake_output) do
+ false | false | "unattended_migrations_completed"
+ false | true | "unattended_migrations_completed"
+ true | false | "unattended_migrations_static"
+ true | true | "unattended_migrations_completed"
+ end
+
+ before do
+ allow(Rake::Task['gitlab:db:configure']).to receive(:invoke).and_return(true)
+ end
+
+ with_them do
+ it 'outputs changed message for automation after operations happen' do
+ allow(ActiveRecord::Base.connection.schema_migration).to receive(:table_exists?).and_return(schema_migration_table_exists)
+ allow_any_instance_of(ActiveRecord::MigrationContext).to receive(:needs_migration?).and_return(needs_migrations)
+ expect { run_rake_task('gitlab:db:unattended') }. to output(/^#{rake_output}$/).to_stdout
+ end
+ end
+ end
+
describe 'clean_structure_sql' do
let_it_be(:clean_rake_task) { 'gitlab:db:clean_structure_sql' }
let_it_be(:test_task_name) { 'gitlab:db:_test_multiple_structure_cleans' }
@@ -164,25 +187,77 @@ RSpec.describe 'gitlab:db namespace rake task' do
end
end
+ describe 'drop_tables' do
+ subject { run_rake_task('gitlab:db:drop_tables') }
+
+ let(:tables) { %w(one two) }
+ let(:views) { %w(three four) }
+ let(:connection) { ActiveRecord::Base.connection }
+
+ before do
+ allow(connection).to receive(:execute).and_return(nil)
+
+ allow(connection).to receive(:tables).and_return(tables)
+ allow(connection).to receive(:views).and_return(views)
+ end
+
+ it 'drops all tables, except schema_migrations' do
+ expect(connection).to receive(:execute).with('DROP TABLE IF EXISTS "one" CASCADE')
+ expect(connection).to receive(:execute).with('DROP TABLE IF EXISTS "two" CASCADE')
+
+ subject
+ end
+
+ it 'drops all views' do
+ expect(connection).to receive(:execute).with('DROP VIEW IF EXISTS "three" CASCADE')
+ expect(connection).to receive(:execute).with('DROP VIEW IF EXISTS "four" CASCADE')
+
+ subject
+ end
+
+ it 'truncates schema_migrations table' do
+ expect(connection).to receive(:execute).with('TRUNCATE schema_migrations')
+
+ subject
+ end
+
+ it 'drops extra schemas' do
+ Gitlab::Database::EXTRA_SCHEMAS.each do |schema|
+ expect(connection).to receive(:execute).with("DROP SCHEMA IF EXISTS \"#{schema}\"")
+ end
+
+ subject
+ end
+ end
+
describe 'reindex' do
+ let(:reindex) { double('reindex') }
+ let(:indexes) { double('indexes') }
+
context 'when no index_name is given' do
- it 'raises an error' do
- expect do
- run_rake_task('gitlab:db:reindex', '')
- end.to raise_error(ArgumentError, /must give the index name/)
+ it 'rebuilds a random number of large indexes' do
+ expect(Gitlab::Database::Reindexing).to receive_message_chain('candidate_indexes.random_few').and_return(indexes)
+ expect(Gitlab::Database::Reindexing).to receive(:perform).with(indexes)
+
+ run_rake_task('gitlab:db:reindex')
end
end
- it 'calls the index rebuilder with the proper arguments' do
- reindex = double('rebuilder')
+ context 'with index name given' do
+ let(:index) { double('index') }
+
+ it 'calls the index rebuilder with the proper arguments' do
+ expect(Gitlab::Database::PostgresIndex).to receive(:by_identifier).with('public.foo_idx').and_return(index)
+ expect(Gitlab::Database::Reindexing).to receive(:perform).with([index])
- expect(Gitlab::Database::ConcurrentReindex).to receive(:new)
- .with('some_index_name', logger: instance_of(Logger))
- .and_return(reindex)
+ run_rake_task('gitlab:db:reindex', '[public.foo_idx]')
+ end
- expect(reindex).to receive(:execute)
+ it 'raises an error if the index does not exist' do
+ expect(Gitlab::Database::PostgresIndex).to receive(:by_identifier).with('public.absent_index').and_raise(ActiveRecord::RecordNotFound)
- run_rake_task('gitlab:db:reindex', '[some_index_name]')
+ expect { run_rake_task('gitlab:db:reindex', '[public.absent_index]') }.to raise_error(ActiveRecord::RecordNotFound)
+ end
end
end
diff --git a/spec/tasks/gitlab/web_hook_rake_spec.rb b/spec/tasks/gitlab/web_hook_rake_spec.rb
index 3e18ce5ab29..9f373e3a20a 100644
--- a/spec/tasks/gitlab/web_hook_rake_spec.rb
+++ b/spec/tasks/gitlab/web_hook_rake_spec.rb
@@ -36,7 +36,7 @@ RSpec.describe 'gitlab:web_hook namespace rake tasks' do
it 'raises an error if an unknown namespace is specified' do
stub_env('URL' => url, 'NAMESPACE' => group.full_path)
- group.destroy
+ group.destroy!
expect { run_rake_task('gitlab:web_hook:add') }.to raise_error(SystemExit)
end
@@ -69,7 +69,7 @@ RSpec.describe 'gitlab:web_hook namespace rake tasks' do
it 'raises an error if an unknown namespace is specified' do
stub_env('URL' => url, 'NAMESPACE' => group.full_path)
- group.destroy
+ group.destroy!
expect { run_rake_task('gitlab:web_hook:rm') }.to raise_error(SystemExit)
end
diff --git a/spec/uploaders/file_uploader_spec.rb b/spec/uploaders/file_uploader_spec.rb
index 9f1d276d092..1287b809223 100644
--- a/spec/uploaders/file_uploader_spec.rb
+++ b/spec/uploaders/file_uploader_spec.rb
@@ -285,7 +285,7 @@ RSpec.describe FileUploader do
end
let!(:fog_file) do
- fog_connection.directories.new(key: 'uploads').files.create(
+ fog_connection.directories.new(key: 'uploads').files.create( # rubocop:disable Rails/SaveBang
key: 'tmp/uploads/test/123123',
body: 'content'
)
diff --git a/spec/uploaders/object_storage_spec.rb b/spec/uploaders/object_storage_spec.rb
index c73a9a7aab1..ba8d0ccbd02 100644
--- a/spec/uploaders/object_storage_spec.rb
+++ b/spec/uploaders/object_storage_spec.rb
@@ -795,7 +795,7 @@ RSpec.describe ObjectStorage do
end
let!(:fog_file) do
- fog_connection.directories.new(key: 'uploads').files.create(
+ fog_connection.directories.new(key: 'uploads').files.create( # rubocop:disable Rails/SaveBang
key: 'tmp/uploads/test/123123',
body: 'content'
)
diff --git a/spec/uploaders/pages/deployment_uploader_spec.rb b/spec/uploaders/pages/deployment_uploader_spec.rb
new file mode 100644
index 00000000000..1832f73bd67
--- /dev/null
+++ b/spec/uploaders/pages/deployment_uploader_spec.rb
@@ -0,0 +1,59 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Pages::DeploymentUploader do
+ let(:pages_deployment) { create(:pages_deployment) }
+ let(:uploader) { described_class.new(pages_deployment, :file) }
+
+ let(:file) do
+ fixture_file_upload("spec/fixtures/pages.zip")
+ end
+
+ subject { uploader }
+
+ it_behaves_like "builds correct paths",
+ store_dir: %r[/\h{2}/\h{2}/\h{64}/pages_deployments/\d+],
+ cache_dir: %r[pages/@hashed/tmp/cache],
+ work_dir: %r[pages/@hashed/tmp/work]
+
+ context 'when object store is REMOTE' do
+ before do
+ stub_pages_object_storage
+ end
+
+ it_behaves_like 'builds correct paths', store_dir: %r[\A\h{2}/\h{2}/\h{64}/pages_deployments/\d+\z]
+
+ it 'preserves original file when stores it' do
+ uploader.store!(file)
+
+ expect(File.exist?(file.path)).to be true
+ end
+ end
+
+ context 'when file is stored in valid local_path' do
+ before do
+ uploader.store!(file)
+ end
+
+ subject { uploader.file.path }
+
+ it { is_expected.to match(%r[#{uploader.root}/@hashed/\h{2}/\h{2}/\h{64}/pages_deployments/#{pages_deployment.id}/pages.zip]) }
+
+ it 'preserves original file when stores it' do
+ expect(File.exist?(file.path)).to be true
+ end
+ end
+
+ describe '.default_store' do
+ it 'returns local store when object storage is not enabled' do
+ expect(described_class.default_store).to eq(ObjectStorage::Store::LOCAL)
+ end
+
+ it 'returns remote store when object storage is enabled' do
+ stub_pages_object_storage
+
+ expect(described_class.default_store).to eq(ObjectStorage::Store::REMOTE)
+ end
+ end
+end
diff --git a/spec/uploaders/terraform/versioned_state_uploader_spec.rb b/spec/uploaders/terraform/versioned_state_uploader_spec.rb
index ecc3f943480..eeb54cb61c7 100644
--- a/spec/uploaders/terraform/versioned_state_uploader_spec.rb
+++ b/spec/uploaders/terraform/versioned_state_uploader_spec.rb
@@ -12,9 +12,18 @@ RSpec.describe Terraform::VersionedStateUploader do
end
describe '#filename' do
- it 'contains the UUID of the terraform state record' do
+ it 'contains the version of the terraform state record' do
expect(subject.filename).to eq("#{model.version}.tfstate")
end
+
+ context 'legacy state with versioning disabled' do
+ let(:state) { create(:legacy_terraform_state) }
+ let(:model) { create(:terraform_state_version, terraform_state: state) }
+
+ it 'contains the UUID of the terraform state record' do
+ expect(subject.filename).to eq("#{model.uuid}.tfstate")
+ end
+ end
end
describe '#store_dir' do
@@ -25,5 +34,14 @@ RSpec.describe Terraform::VersionedStateUploader do
expect(subject.store_dir).to eq(:store_dir)
end
+
+ context 'legacy state with versioning disabled' do
+ let(:state) { create(:legacy_terraform_state) }
+ let(:model) { create(:terraform_state_version, terraform_state: state) }
+
+ it 'contains the ID of the project' do
+ expect(subject.store_dir).to include(model.project_id.to_s)
+ end
+ end
end
end
diff --git a/spec/validators/ip_address_validator_spec.rb b/spec/validators/ip_address_validator_spec.rb
new file mode 100644
index 00000000000..382250378c2
--- /dev/null
+++ b/spec/validators/ip_address_validator_spec.rb
@@ -0,0 +1,37 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe IpAddressValidator do
+ let(:model) do
+ Class.new do
+ include ActiveModel::Model
+ include ActiveModel::Validations
+
+ attr_accessor :ip_address
+ alias_method :ip_address_before_type_cast, :ip_address
+
+ validates :ip_address, ip_address: true
+ end.new
+ end
+
+ using RSpec::Parameterized::TableSyntax
+
+ where(:ip_address, :validity, :errors) do
+ 'invalid IP' | false | { ip_address: ['must be a valid IPv4 or IPv6 address'] }
+ '192.168.17.43' | true | {}
+ '2001:0db8:85a3::8a2e:0370:7334' | true | {}
+ nil | true | {}
+ '' | true | {}
+ end
+
+ with_them do
+ before do
+ model.ip_address = ip_address
+ model.validate
+ end
+
+ it { expect(model.valid?).to eq(validity) }
+ it { expect(model.errors.messages).to eq(errors) }
+ end
+end
diff --git a/spec/views/admin/dashboard/index.html.haml_spec.rb b/spec/views/admin/dashboard/index.html.haml_spec.rb
index 70fb77944cc..e9223c84674 100644
--- a/spec/views/admin/dashboard/index.html.haml_spec.rb
+++ b/spec/views/admin/dashboard/index.html.haml_spec.rb
@@ -37,7 +37,7 @@ RSpec.describe 'admin/dashboard/index.html.haml' do
render
expect(rendered).not_to have_content "Users in License"
- expect(rendered).not_to have_content "Active Users"
+ expect(rendered).not_to have_content "Billable Users"
expect(rendered).not_to have_content "Maximum Users"
expect(rendered).not_to have_content "Users over License"
end
diff --git a/spec/views/groups/edit.html.haml_spec.rb b/spec/views/groups/edit.html.haml_spec.rb
index 83623ea7bb4..f40b03fda2a 100644
--- a/spec/views/groups/edit.html.haml_spec.rb
+++ b/spec/views/groups/edit.html.haml_spec.rb
@@ -26,7 +26,7 @@ RSpec.describe 'groups/edit.html.haml' do
expect(rendered).to have_content("Prevent sharing a project within #{test_group.name} with other groups")
expect(rendered).to have_css('.js-descr', text: 'help text here')
- expect(rendered).to have_field('group_share_with_group_lock', checkbox_options)
+ expect(rendered).to have_field('group_share_with_group_lock', **checkbox_options)
end
end
diff --git a/spec/views/jira_connect/subscriptions/index.html.haml_spec.rb b/spec/views/jira_connect/subscriptions/index.html.haml_spec.rb
new file mode 100644
index 00000000000..dcc36c93327
--- /dev/null
+++ b/spec/views/jira_connect/subscriptions/index.html.haml_spec.rb
@@ -0,0 +1,30 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'jira_connect/subscriptions/index.html.haml' do
+ let(:user) { build_stubbed(:user) }
+
+ before do
+ allow(view).to receive(:current_user).and_return(user)
+ assign(:subscriptions, [])
+ end
+
+ context 'when the user is signed in' do
+ it 'shows link to user profile' do
+ render
+
+ expect(rendered).to have_link(user.to_reference)
+ end
+ end
+
+ context 'when the user is not signed in' do
+ let(:user) { nil }
+
+ it 'shows "Sign in" link' do
+ render
+
+ expect(rendered).to have_link('Sign in to GitLab')
+ end
+ end
+end
diff --git a/spec/views/layouts/nav/sidebar/_admin.html.haml_spec.rb b/spec/views/layouts/nav/sidebar/_admin.html.haml_spec.rb
index 777dc0c8571..2c37565328a 100644
--- a/spec/views/layouts/nav/sidebar/_admin.html.haml_spec.rb
+++ b/spec/views/layouts/nav/sidebar/_admin.html.haml_spec.rb
@@ -92,7 +92,11 @@ RSpec.describe 'layouts/nav/sidebar/_admin' do
end
context 'on settings' do
+ let(:gitlab_com?) { false }
+
before do
+ allow(::Gitlab).to receive(:com?) { gitlab_com? }
+
render
end
@@ -100,6 +104,20 @@ RSpec.describe 'layouts/nav/sidebar/_admin' do
expect(rendered).to have_link('General', href: general_admin_application_settings_path)
end
+ context 'when GitLab.com' do
+ let(:gitlab_com?) { true }
+
+ it 'does not include Integrations link' do
+ expect(rendered).not_to have_link('Integrations', href: integrations_admin_application_settings_path)
+ end
+ end
+
+ context 'when not GitLab.com' do
+ it 'includes Integrations link' do
+ expect(rendered).to have_link('Integrations', href: integrations_admin_application_settings_path)
+ end
+ end
+
context 'when GitLab FOSS' do
it 'does not include Templates link' do
expect(rendered).not_to have_link('Templates', href: '/admin/application_settings/templates')
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 bf5b5785b8d..3fb9fb54b01 100644
--- a/spec/views/layouts/nav/sidebar/_project.html.haml_spec.rb
+++ b/spec/views/layouts/nav/sidebar/_project.html.haml_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe 'layouts/nav/sidebar/_project' do
- let(:project) { create(:project, :repository) }
+ let_it_be_with_reload(:project) { create(:project, :repository) }
before do
assign(:project, project)
@@ -246,6 +246,30 @@ RSpec.describe 'layouts/nav/sidebar/_project' do
end
end
+ describe 'Tracing' do
+ it 'is not visible to unauthorized user' do
+ allow(view).to receive(:can?).and_return(false)
+
+ render
+
+ expect(rendered).not_to have_text 'Tracing'
+ end
+
+ it 'links to Tracing page' do
+ render
+
+ expect(rendered).to have_link('Tracing', href: project_tracing_path(project))
+ end
+
+ context 'without project.tracing_external_url' do
+ it 'links to Tracing page' do
+ render
+
+ expect(rendered).to have_link('Tracing', href: project_tracing_path(project))
+ end
+ end
+ end
+
describe 'Alert Management' do
it 'shows the Alerts sidebar entry' do
render
@@ -299,10 +323,10 @@ RSpec.describe 'layouts/nav/sidebar/_project' do
allow(Gitlab).to receive(:com?).and_return(true)
end
- it 'does not display "Access Tokens" nav item' do
+ it 'displays "Access Tokens" nav item' do
render
- expect(rendered).not_to have_link('Access Tokens', href: project_settings_access_tokens_path(project))
+ expect(rendered).to have_link('Access Tokens', href: project_settings_access_tokens_path(project))
end
end
end
diff --git a/spec/views/profiles/preferences/show.html.haml_spec.rb b/spec/views/profiles/preferences/show.html.haml_spec.rb
index 1b8b28367c1..aab50209953 100644
--- a/spec/views/profiles/preferences/show.html.haml_spec.rb
+++ b/spec/views/profiles/preferences/show.html.haml_spec.rb
@@ -20,6 +20,14 @@ RSpec.describe 'profiles/preferences/show' do
it 'has an id for anchoring' do
expect(rendered).to have_css('#navigation-theme')
end
+
+ it 'has correct stylesheet tags' do
+ Gitlab::Themes.each do |theme|
+ next unless theme.css_filename
+
+ expect(rendered).to have_selector("link[href*=\"themes/#{theme.css_filename}\"]", visible: false)
+ end
+ end
end
context 'syntax highlighting theme' do
@@ -67,7 +75,7 @@ RSpec.describe 'profiles/preferences/show' do
end
def have_integrations_section
- have_css('#integrations.profile-settings-sidebar', { text: 'Integrations' })
+ have_css('#integrations.profile-settings-sidebar', text: 'Integrations')
end
before do
diff --git a/spec/views/projects/merge_requests/diffs/_diffs.html.haml_spec.rb b/spec/views/projects/merge_requests/diffs/_diffs.html.haml_spec.rb
deleted file mode 100644
index 7cdc817d784..00000000000
--- a/spec/views/projects/merge_requests/diffs/_diffs.html.haml_spec.rb
+++ /dev/null
@@ -1,38 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe 'projects/merge_requests/diffs/_diffs.html.haml' do
- include Devise::Test::ControllerHelpers
-
- let(:user) { create(:user) }
- let(:project) { create(:project, :public, :repository) }
- let(:merge_request) { create(:merge_request_with_diffs, target_project: project, source_project: project, author: user) }
-
- before do
- allow(view).to receive(:url_for).and_return(controller.request.fullpath)
-
- assign(:merge_request, merge_request)
- assign(:environment, merge_request.environments_for(user).last)
- assign(:diffs, merge_request.diffs)
- assign(:merge_request_diffs, merge_request.diffs)
- assign(:diff_notes_disabled, true) # disable note creation
- assign(:use_legacy_diff_notes, false)
- assign(:grouped_diff_discussions, {})
- assign(:notes, [])
- end
-
- context 'for a commit' do
- let(:commit) { merge_request.commits.last }
-
- before do
- assign(:commit, commit)
- end
-
- it "shows the commit scope" do
- render
-
- expect(rendered).to have_content "Only comments from the following commit are shown below"
- end
- end
-end
diff --git a/spec/views/projects/settings/operations/show.html.haml_spec.rb b/spec/views/projects/settings/operations/show.html.haml_spec.rb
index b4d20da0a5c..24ab64b20f5 100644
--- a/spec/views/projects/settings/operations/show.html.haml_spec.rb
+++ b/spec/views/projects/settings/operations/show.html.haml_spec.rb
@@ -6,37 +6,85 @@ RSpec.describe 'projects/settings/operations/show' do
let_it_be(:project) { create(:project) }
let_it_be(:user) { create(:user) }
+ let_it_be(:error_tracking_setting) do
+ create(:project_error_tracking_setting, project: project)
+ end
+
+ let_it_be_with_reload(:tracing_setting) do
+ create(:project_tracing_setting, project: project)
+ end
+
+ let_it_be(:prometheus_service) { create(:prometheus_service, project: project) }
+ let_it_be(:alerts_service) { create(:alerts_service, project: project) }
+
let(:operations_show_locals) do
{
- prometheus_service: project.find_or_initialize_service('prometheus'),
- alerts_service: project.find_or_initialize_service('alerts')
+ prometheus_service: prometheus_service,
+ alerts_service: alerts_service
}
end
+ before_all do
+ project.add_reporter(user)
+ end
+
before do
assign :project, project
+
+ allow(view).to receive(:error_tracking_setting)
+ .and_return(error_tracking_setting)
+ allow(view).to receive(:tracing_setting)
+ .and_return(tracing_setting)
+ allow(view).to receive(:current_user).and_return(user)
end
describe 'Operations > Error Tracking' do
- before do
- project.add_reporter(user)
+ context 'Settings page ' do
+ it 'renders the Operations Settings page' do
+ render template: 'projects/settings/operations/show', locals: operations_show_locals
- allow(view).to receive(:error_tracking_setting)
- .and_return(error_tracking_setting)
- allow(view).to receive(:current_user).and_return(user)
- allow(view).to receive(:incident_management_available?) { false }
+ expect(rendered).to have_content _('Error tracking')
+ expect(rendered).to have_content _('To link Sentry to GitLab, enter your Sentry URL and Auth Token')
+ end
end
+ end
- let_it_be(:error_tracking_setting) do
- create(:project_error_tracking_setting, project: project)
+ describe 'Operations > Tracing' do
+ context 'with project.tracing_external_url' do
+ it 'links to project.tracing_external_url' do
+ render template: 'projects/settings/operations/show', locals: operations_show_locals
+
+ expect(rendered).to have_link('Tracing', href: tracing_setting.external_url)
+ end
+
+ context 'with malicious external_url' do
+ let(:malicious_tracing_url) { "https://replaceme.com/'><script>alert(document.cookie)</script>" }
+ let(:cleaned_url) { "https://replaceme.com/'>" }
+
+ before do
+ tracing_setting.update_column(:external_url, malicious_tracing_url)
+ end
+
+ it 'sanitizes external_url' do
+ render template: 'projects/settings/operations/show', locals: operations_show_locals
+
+ expect(tracing_setting.external_url).to eq(malicious_tracing_url)
+ expect(rendered).to have_link('Tracing', href: cleaned_url)
+ end
+ end
end
- context 'Settings page ' do
- it 'renders the Operations Settings page' do
+ context 'without project.tracing_external_url' do
+ let(:tracing_setting) { build(:project_tracing_setting, project: project) }
+
+ before do
+ tracing_setting.external_url = nil
+ end
+
+ it 'links to Tracing page' do
render template: 'projects/settings/operations/show', locals: operations_show_locals
- expect(rendered).to have_content _('Error tracking')
- expect(rendered).to have_content _('To link Sentry to GitLab, enter your Sentry URL and Auth Token')
+ expect(rendered).to have_link('Tracing', href: project_tracing_path(project))
end
end
end
diff --git a/spec/views/projects/tracing/show.html.haml_spec.rb b/spec/views/projects/tracing/show.html.haml_spec.rb
new file mode 100644
index 00000000000..96dc6a18fc7
--- /dev/null
+++ b/spec/views/projects/tracing/show.html.haml_spec.rb
@@ -0,0 +1,59 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'projects/tracings/show' do
+ let_it_be_with_reload(:project) { create(:project) }
+ let_it_be(:error_tracking_setting) { create(:project_error_tracking_setting, project: project) }
+
+ before do
+ assign(:project, project)
+ allow(view).to receive(:error_tracking_setting)
+ .and_return(error_tracking_setting)
+ end
+
+ context 'with project.tracing_external_url' do
+ let_it_be(:tracing_url) { 'https://tracing.url' }
+ let_it_be(:tracing_setting) { create(:project_tracing_setting, project: project, external_url: tracing_url) }
+
+ before do
+ allow(view).to receive(:can?).and_return(true)
+ allow(view).to receive(:tracing_setting).and_return(tracing_setting)
+ end
+
+ it 'renders iframe' do
+ render
+
+ expect(rendered).to match(/iframe/)
+ end
+
+ context 'with malicious external_url' do
+ let(:malicious_tracing_url) { "https://replaceme.com/'><script>alert(document.cookie)</script>" }
+ let(:cleaned_url) { "https://replaceme.com/'&gt;" }
+
+ before do
+ tracing_setting.update_column(:external_url, malicious_tracing_url)
+ end
+
+ it 'sanitizes external_url' do
+ render
+
+ expect(tracing_setting.external_url).to eq(malicious_tracing_url)
+ expect(rendered).to have_xpath("//iframe[@src=\"#{cleaned_url}\"]")
+ end
+ end
+ end
+
+ context 'without project.tracing_external_url' do
+ before do
+ allow(view).to receive(:can?).and_return(true)
+ end
+
+ it 'renders empty state' do
+ render
+
+ expect(rendered).to have_link('Add Jaeger URL')
+ expect(rendered).not_to match(/iframe/)
+ end
+ end
+end
diff --git a/spec/views/search/_results.html.haml_spec.rb b/spec/views/search/_results.html.haml_spec.rb
index 9e95dc40ff8..033b2304e33 100644
--- a/spec/views/search/_results.html.haml_spec.rb
+++ b/spec/views/search/_results.html.haml_spec.rb
@@ -60,6 +60,28 @@ RSpec.describe 'search/_results' do
expect(rendered).to have_selector('#js-search-filter-by-state')
end
+
+ context 'Feature search_filter_by_confidential' do
+ context 'when disabled' do
+ before do
+ stub_feature_flags(search_filter_by_confidential: false)
+ end
+
+ it 'does not render the confidential drop down' do
+ render
+
+ expect(rendered).not_to have_selector('#js-search-filter-by-confidential')
+ end
+ end
+
+ context 'when enabled' do
+ it 'renders the confidential drop down' do
+ render
+
+ expect(rendered).to have_selector('#js-search-filter-by-confidential')
+ end
+ end
+ end
end
end
end
diff --git a/spec/views/shared/_label_row.html.haml_spec.rb b/spec/views/shared/_label_row.html.haml_spec.rb
index 8f8aa3072e2..e9a0bfdcd4e 100644
--- a/spec/views/shared/_label_row.html.haml_spec.rb
+++ b/spec/views/shared/_label_row.html.haml_spec.rb
@@ -2,43 +2,126 @@
require 'spec_helper'
RSpec.describe 'shared/_label_row.html.haml' do
- label_types = {
- 'project label': :label,
- 'group label': :group_label
- }
+ let_it_be(:group) { create(:group) }
+ let(:label) { build_stubbed(:group_label, group: group).present(issuable_subject: group) }
- label_types.each do |label_type, label_factory|
- let!(:label) do
- label_record = create(label_factory) # rubocop: disable Rails/SaveBang
- label_record.present(issuable_subject: label_record.subject)
+ before do
+ allow(view).to receive(:label) { label }
+ end
+
+ context 'with a project context' do
+ let_it_be(:project) { create(:project, group: group) }
+ let(:label) { build_stubbed(:label, project: project).present(issuable_subject: project) }
+
+ before do
+ assign(:project, label.project)
+
+ render
+ end
+
+ it 'has label title' do
+ expect(rendered).to have_text(label.title)
+ end
+
+ it 'has a non-linked label title' do
+ expect(rendered).not_to have_link(label.title)
+ end
+
+ it 'has Issues link' do
+ expect(rendered).to have_link('Issues')
+ end
+
+ it 'has Merge request link' do
+ expect(rendered).to have_link('Merge requests')
+ end
+
+ it 'shows the path from where the label was created' do
+ expect(rendered).to have_css('.label-badge', text: project.full_name)
+ end
+ end
+
+ context 'with a subgroup context' do
+ let_it_be(:subgroup) { create(:group, parent: group) }
+ let(:label) { build_stubbed(:group_label, group: subgroup).present(issuable_subject: subgroup) }
+
+ before do
+ assign(:group, label.group)
+
+ render
+ end
+
+ it 'has label title' do
+ expect(rendered).to have_text(label.title)
+ end
+
+ it 'has a non-linked label title' do
+ expect(rendered).not_to have_link(label.title)
+ end
+
+ it 'has Issues link' do
+ expect(rendered).to have_link('Issues')
+ end
+
+ it 'has Merge request link' do
+ expect(rendered).to have_link('Merge requests')
+ end
+
+ it 'shows the path from where the label was created' do
+ expect(rendered).to have_css('.label-badge', text: subgroup.full_name)
+ end
+ end
+
+ context 'with a group context' do
+ before do
+ assign(:group, label.group)
+
+ render
+ end
+
+ it 'has label title' do
+ expect(rendered).to have_text(label.title)
+ end
+
+ it 'has a non-linked label title' do
+ expect(rendered).not_to have_link(label.title)
+ end
+
+ it 'has Issues link' do
+ expect(rendered).to have_link('Issues')
end
- context "for a #{label_type}" do
- before do
- if label.project_label?
- @project = label.project
- else
- @group = label.group
- end
- end
+ it 'has Merge request link' do
+ expect(rendered).to have_link('Merge requests')
+ end
+
+ it 'does not show a path from where the label was created' do
+ expect(rendered).not_to have_css('.label-badge')
+ end
+ end
- it 'has a non-linked label title' do
- render 'shared/label_row', label: label
+ context 'with an admin context' do
+ before do
+ render
+ end
- expect(rendered).not_to have_css('a', text: label.title)
- end
+ it 'has label title' do
+ expect(rendered).to have_text(label.title)
+ end
- it "has Issues link for #{label_type}" do
- render 'shared/label_row', label: label
+ it 'has a non-linked label title' do
+ expect(rendered).not_to have_link(label.title)
+ end
- expect(rendered).to have_css('a', text: 'Issues')
- end
+ it 'does not show Issues link' do
+ expect(rendered).not_to have_link('Issues')
+ end
- it "has Merge request link for #{label_type}" do
- render 'shared/label_row', label: label
+ it 'does not show Merge request link' do
+ expect(rendered).not_to have_link('Merge requests')
+ end
- expect(rendered).to have_css('a', text: 'Merge requests')
- end
+ it 'does not show a path from where the label was created' do
+ expect(rendered).not_to have_css('.label-badge')
end
end
end
diff --git a/spec/views/shared/milestones/_issuables.html.haml_spec.rb b/spec/views/shared/milestones/_issuables.html.haml_spec.rb
index 70ab6914580..5eed2c96a45 100644
--- a/spec/views/shared/milestones/_issuables.html.haml_spec.rb
+++ b/spec/views/shared/milestones/_issuables.html.haml_spec.rb
@@ -6,8 +6,7 @@ RSpec.describe 'shared/milestones/_issuables.html.haml' do
let(:issuables_size) { 100 }
before do
- allow(view).to receive_messages(title: nil, id: nil, show_project_name: nil,
- show_full_project_name: nil, dom_class: '',
+ allow(view).to receive_messages(title: nil, id: nil, show_project_name: nil, dom_class: '',
issuables: double(length: issuables_size).as_null_object)
stub_template 'shared/milestones/_issuable.html.haml' => ''
diff --git a/spec/workers/analytics/instance_statistics/count_job_trigger_worker_spec.rb b/spec/workers/analytics/instance_statistics/count_job_trigger_worker_spec.rb
index 620900b3402..ff692d0eda6 100644
--- a/spec/workers/analytics/instance_statistics/count_job_trigger_worker_spec.rb
+++ b/spec/workers/analytics/instance_statistics/count_job_trigger_worker_spec.rb
@@ -14,16 +14,4 @@ RSpec.describe Analytics::InstanceStatistics::CountJobTriggerWorker do
expect(Analytics::InstanceStatistics::CounterJobWorker.jobs.count).to eq(expected_count)
end
end
-
- context 'when the `store_instance_statistics_measurements` feature flag is off' do
- before do
- stub_feature_flags(store_instance_statistics_measurements: false)
- end
-
- it 'does not trigger any CounterJobWorker job' do
- subject.perform
-
- expect(Analytics::InstanceStatistics::CounterJobWorker.jobs.count).to eq(0)
- end
- end
end
diff --git a/spec/workers/analytics/instance_statistics/counter_job_worker_spec.rb b/spec/workers/analytics/instance_statistics/counter_job_worker_spec.rb
index 8db86071dc4..667ec0bcb75 100644
--- a/spec/workers/analytics/instance_statistics/counter_job_worker_spec.rb
+++ b/spec/workers/analytics/instance_statistics/counter_job_worker_spec.rb
@@ -18,7 +18,7 @@ RSpec.describe Analytics::InstanceStatistics::CounterJobWorker do
it 'counts a scope and stores the result' do
subject
- measurement = Analytics::InstanceStatistics::Measurement.first
+ measurement = Analytics::InstanceStatistics::Measurement.users.first
expect(measurement.recorded_at).to be_like_time(recorded_at)
expect(measurement.identifier).to eq('users')
expect(measurement.count).to eq(2)
@@ -33,7 +33,7 @@ RSpec.describe Analytics::InstanceStatistics::CounterJobWorker do
it 'sets 0 as the count' do
subject
- measurement = Analytics::InstanceStatistics::Measurement.first
+ measurement = Analytics::InstanceStatistics::Measurement.groups.first
expect(measurement.recorded_at).to be_like_time(recorded_at)
expect(measurement.identifier).to eq('groups')
expect(measurement.count).to eq(0)
@@ -51,4 +51,20 @@ RSpec.describe Analytics::InstanceStatistics::CounterJobWorker do
expect { subject }.not_to change { Analytics::InstanceStatistics::Measurement.count }
end
+
+ context 'when pipelines_succeeded identifier is passed' do
+ let_it_be(:pipeline) { create(:ci_pipeline, :success) }
+
+ let(:successful_pipelines_measurement_identifier) { ::Analytics::InstanceStatistics::Measurement.identifiers.fetch(:pipelines_succeeded) }
+ let(:job_args) { [successful_pipelines_measurement_identifier, pipeline.id, pipeline.id, recorded_at] }
+
+ it 'counts successful pipelines' do
+ subject
+
+ measurement = Analytics::InstanceStatistics::Measurement.pipelines_succeeded.first
+ expect(measurement.recorded_at).to be_like_time(recorded_at)
+ expect(measurement.identifier).to eq('pipelines_succeeded')
+ expect(measurement.count).to eq(1)
+ end
+ end
end
diff --git a/spec/workers/authorized_project_update/periodic_recalculate_worker_spec.rb b/spec/workers/authorized_project_update/periodic_recalculate_worker_spec.rb
index 2d633828ae3..9d4d48d0568 100644
--- a/spec/workers/authorized_project_update/periodic_recalculate_worker_spec.rb
+++ b/spec/workers/authorized_project_update/periodic_recalculate_worker_spec.rb
@@ -11,17 +11,5 @@ RSpec.describe AuthorizedProjectUpdate::PeriodicRecalculateWorker do
subject.perform
end
-
- context 'feature flag :periodic_project_authorization_recalculation is disabled' do
- before do
- stub_feature_flags(periodic_project_authorization_recalculation: false)
- end
-
- it 'does not call AuthorizedProjectUpdate::PeriodicRecalculateService' do
- expect(AuthorizedProjectUpdate::PeriodicRecalculateService).not_to receive(:new)
-
- subject.perform
- end
- end
end
end
diff --git a/spec/workers/authorized_project_update/user_refresh_over_user_range_worker_spec.rb b/spec/workers/authorized_project_update/user_refresh_over_user_range_worker_spec.rb
index c49e4c453bf..a27c431523e 100644
--- a/spec/workers/authorized_project_update/user_refresh_over_user_range_worker_spec.rb
+++ b/spec/workers/authorized_project_update/user_refresh_over_user_range_worker_spec.rb
@@ -14,17 +14,5 @@ RSpec.describe AuthorizedProjectUpdate::UserRefreshOverUserRangeWorker do
subject.perform(start_user_id, end_user_id)
end
-
- context 'feature flag :periodic_project_authorization_recalculation is disabled' do
- before do
- stub_feature_flags(periodic_project_authorization_recalculation: false)
- end
-
- it 'does not call AuthorizedProjectUpdate::RecalculateForUserRangeService' do
- expect(AuthorizedProjectUpdate::RecalculateForUserRangeService).not_to receive(:new)
-
- subject.perform(start_user_id, end_user_id)
- end
- end
end
end
diff --git a/spec/workers/build_finished_worker_spec.rb b/spec/workers/build_finished_worker_spec.rb
index e7f7ae84621..11b50961e9e 100644
--- a/spec/workers/build_finished_worker_spec.rb
+++ b/spec/workers/build_finished_worker_spec.rb
@@ -20,10 +20,10 @@ RSpec.describe BuildFinishedWorker do
expect_any_instance_of(BuildTraceSectionsWorker).to receive(:perform)
expect_any_instance_of(BuildCoverageWorker).to receive(:perform)
expect(BuildHooksWorker).to receive(:perform_async)
- expect(ArchiveTraceWorker).to receive(:perform_async)
expect(ExpirePipelineCacheWorker).to receive(:perform_async)
expect(ChatNotificationWorker).not_to receive(:perform_async)
expect(Ci::BuildReportResultWorker).not_to receive(:perform)
+ expect(ArchiveTraceWorker).to receive(:perform_in)
subject
end
diff --git a/spec/workers/ci/build_trace_chunk_flush_worker_spec.rb b/spec/workers/ci/build_trace_chunk_flush_worker_spec.rb
index 352ad6d4cf6..8aac80a02be 100644
--- a/spec/workers/ci/build_trace_chunk_flush_worker_spec.rb
+++ b/spec/workers/ci/build_trace_chunk_flush_worker_spec.rb
@@ -14,7 +14,7 @@ RSpec.describe Ci::BuildTraceChunkFlushWorker do
described_class.new.perform(chunk.id)
- expect(chunk.reload).to be_persisted
+ expect(chunk.reload).to be_migrated
end
describe '#perform' do
@@ -24,7 +24,7 @@ RSpec.describe Ci::BuildTraceChunkFlushWorker do
it 'migrates build trace chunk to a safe store' do
subject
- expect(chunk.reload).to be_persisted
+ expect(chunk.reload).to be_migrated
end
end
end
diff --git a/spec/workers/ci/delete_objects_worker_spec.rb b/spec/workers/ci/delete_objects_worker_spec.rb
new file mode 100644
index 00000000000..6cb8e0cba37
--- /dev/null
+++ b/spec/workers/ci/delete_objects_worker_spec.rb
@@ -0,0 +1,49 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Ci::DeleteObjectsWorker do
+ let(:worker) { described_class.new }
+
+ it { expect(described_class.idempotent?).to be_truthy }
+
+ describe '#perform' do
+ it 'executes a service' do
+ expect_next_instance_of(Ci::DeleteObjectsService) do |instance|
+ expect(instance).to receive(:execute)
+ expect(instance).to receive(:remaining_batches_count).once.and_call_original
+ end
+
+ worker.perform
+ end
+ end
+
+ describe '#max_running_jobs' do
+ using RSpec::Parameterized::TableSyntax
+
+ before do
+ stub_feature_flags(
+ ci_delete_objects_low_concurrency: low,
+ ci_delete_objects_medium_concurrency: medium,
+ ci_delete_objects_high_concurrency: high
+ )
+ end
+
+ subject(:max_running_jobs) { worker.max_running_jobs }
+
+ where(:low, :medium, :high, :expected) do
+ false | false | false | 0
+ true | true | true | 2
+ true | false | false | 2
+ false | true | false | 20
+ false | true | true | 20
+ false | false | true | 50
+ end
+
+ with_them do
+ it 'sets up concurrency depending on the feature flag' do
+ expect(max_running_jobs).to eq(expected)
+ end
+ end
+ end
+end
diff --git a/spec/workers/ci/schedule_delete_objects_cron_worker_spec.rb b/spec/workers/ci/schedule_delete_objects_cron_worker_spec.rb
new file mode 100644
index 00000000000..142df271f90
--- /dev/null
+++ b/spec/workers/ci/schedule_delete_objects_cron_worker_spec.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Ci::ScheduleDeleteObjectsCronWorker do
+ let(:worker) { described_class.new }
+
+ describe '#perform' do
+ it 'enqueues DeleteObjectsWorker jobs' do
+ expect(Ci::DeleteObjectsWorker).to receive(:perform_with_capacity)
+
+ worker.perform
+ end
+ end
+end
diff --git a/spec/workers/cleanup_container_repository_worker_spec.rb b/spec/workers/cleanup_container_repository_worker_spec.rb
index 0545f7a35e4..9cf8974a2a1 100644
--- a/spec/workers/cleanup_container_repository_worker_spec.rb
+++ b/spec/workers/cleanup_container_repository_worker_spec.rb
@@ -40,14 +40,35 @@ RSpec.describe CleanupContainerRepositoryWorker, :clean_gitlab_redis_shared_stat
context 'container expiration policy' do
let(:params) { { key: 'value', 'container_expiration_policy' => true } }
+ before do
+ allow(ContainerRepository)
+ .to receive(:find_by_id).with(repository.id).and_return(repository)
+ end
+
it 'executes the destroy service' do
+ expect(repository).to receive(:start_expiration_policy!).and_call_original
+ expect(repository).to receive(:reset_expiration_policy_started_at!).and_call_original
expect(Projects::ContainerRepository::CleanupTagsService).to receive(:new)
.with(project, nil, params.merge('container_expiration_policy' => true))
.and_return(service)
- expect(service).to receive(:execute)
+ expect(service).to receive(:execute).and_return(status: :success)
+
+ subject.perform(nil, repository.id, params)
+ expect(repository.reload.expiration_policy_started_at).to be_nil
+ end
+
+ it "doesn't reset the expiration policy started at if the destroy service returns an error" do
+ expect(repository).to receive(:start_expiration_policy!).and_call_original
+ expect(repository).not_to receive(:reset_expiration_policy_started_at!)
+ expect(Projects::ContainerRepository::CleanupTagsService).to receive(:new)
+ .with(project, nil, params.merge('container_expiration_policy' => true))
+ .and_return(service)
+
+ expect(service).to receive(:execute).and_return(status: :error, message: 'timeout while deleting tags')
subject.perform(nil, repository.id, params)
+ expect(repository.reload.expiration_policy_started_at).not_to be_nil
end
end
end
diff --git a/spec/workers/concerns/limited_capacity/job_tracker_spec.rb b/spec/workers/concerns/limited_capacity/job_tracker_spec.rb
new file mode 100644
index 00000000000..2c79f347903
--- /dev/null
+++ b/spec/workers/concerns/limited_capacity/job_tracker_spec.rb
@@ -0,0 +1,100 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe LimitedCapacity::JobTracker, :clean_gitlab_redis_queues do
+ let(:job_tracker) do
+ described_class.new('namespace')
+ end
+
+ describe '#register' do
+ it 'adds jid to the set' do
+ job_tracker.register('a-job-id')
+
+ expect(job_tracker.running_jids).to contain_exactly('a-job-id')
+ end
+
+ it 'updates the counter' do
+ expect { job_tracker.register('a-job-id') }
+ .to change { job_tracker.count }
+ .from(0)
+ .to(1)
+ end
+
+ it 'does it in only one Redis call' do
+ expect(job_tracker).to receive(:with_redis).once.and_call_original
+
+ job_tracker.register('a-job-id')
+ end
+ end
+
+ describe '#remove' do
+ before do
+ job_tracker.register(%w[a-job-id other-job-id])
+ end
+
+ it 'removes jid from the set' do
+ job_tracker.remove('other-job-id')
+
+ expect(job_tracker.running_jids).to contain_exactly('a-job-id')
+ end
+
+ it 'updates the counter' do
+ expect { job_tracker.remove('other-job-id') }
+ .to change { job_tracker.count }
+ .from(2)
+ .to(1)
+ end
+
+ it 'does it in only one Redis call' do
+ expect(job_tracker).to receive(:with_redis).once.and_call_original
+
+ job_tracker.remove('other-job-id')
+ end
+ end
+
+ describe '#clean_up' do
+ before do
+ job_tracker.register('a-job-id')
+ end
+
+ context 'with running jobs' do
+ before do
+ expect(Gitlab::SidekiqStatus).to receive(:completed_jids)
+ .with(%w[a-job-id])
+ .and_return([])
+ end
+
+ it 'does not remove the jid from the set' do
+ expect { job_tracker.clean_up }
+ .not_to change { job_tracker.running_jids.include?('a-job-id') }
+ end
+
+ it 'does only one Redis call to get the job ids' do
+ expect(job_tracker).to receive(:with_redis).once.and_call_original
+
+ job_tracker.clean_up
+ end
+ end
+
+ context 'with completed jobs' do
+ it 'removes the jid from the set' do
+ expect { job_tracker.clean_up }
+ .to change { job_tracker.running_jids.include?('a-job-id') }
+ end
+
+ it 'updates the counter' do
+ expect { job_tracker.clean_up }
+ .to change { job_tracker.count }
+ .from(1)
+ .to(0)
+ end
+
+ it 'gets the job ids, removes them, and updates the counter with only two Redis calls' do
+ expect(job_tracker).to receive(:with_redis).twice.and_call_original
+
+ job_tracker.clean_up
+ end
+ end
+ end
+end
diff --git a/spec/workers/concerns/limited_capacity/worker_spec.rb b/spec/workers/concerns/limited_capacity/worker_spec.rb
new file mode 100644
index 00000000000..8a15675c04d
--- /dev/null
+++ b/spec/workers/concerns/limited_capacity/worker_spec.rb
@@ -0,0 +1,285 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe LimitedCapacity::Worker, :clean_gitlab_redis_queues, :aggregate_failures do
+ let(:worker_class) do
+ Class.new do
+ def self.name
+ 'DummyWorker'
+ end
+
+ include ApplicationWorker
+ include LimitedCapacity::Worker
+ end
+ end
+
+ let(:worker) { worker_class.new }
+
+ let(:job_tracker) do
+ LimitedCapacity::JobTracker.new(worker_class.name)
+ end
+
+ before do
+ worker.jid = 'my-jid'
+ allow(worker).to receive(:job_tracker).and_return(job_tracker)
+ end
+
+ describe 'required methods' do
+ it { expect { worker.perform_work }.to raise_error(NotImplementedError) }
+ it { expect { worker.remaining_work_count }.to raise_error(NotImplementedError) }
+ it { expect { worker.max_running_jobs }.to raise_error(NotImplementedError) }
+ end
+
+ describe 'Sidekiq options' do
+ it 'does not retry failed jobs' do
+ expect(worker_class.sidekiq_options['retry']).to eq(0)
+ end
+
+ it 'does not deduplicate jobs' do
+ expect(worker_class.get_deduplicate_strategy).to eq(:none)
+ end
+ end
+
+ describe '.perform_with_capacity' do
+ subject(:perform_with_capacity) { worker_class.perform_with_capacity(:arg) }
+
+ before do
+ expect_next_instance_of(worker_class) do |instance|
+ expect(instance).to receive(:remove_failed_jobs)
+ expect(instance).to receive(:report_prometheus_metrics)
+
+ allow(instance).to receive(:remaining_work_count).and_return(remaining_work_count)
+ allow(instance).to receive(:remaining_capacity).and_return(remaining_capacity)
+ end
+ end
+
+ context 'when capacity is larger than work' do
+ let(:remaining_work_count) { 2 }
+ let(:remaining_capacity) { 3 }
+
+ it 'enqueues jobs for remaining work' do
+ expect(worker_class)
+ .to receive(:bulk_perform_async)
+ .with([[:arg], [:arg]])
+
+ perform_with_capacity
+ end
+ end
+
+ context 'when capacity is lower than work' do
+ let(:remaining_work_count) { 5 }
+ let(:remaining_capacity) { 3 }
+
+ it 'enqueues jobs for remaining work' do
+ expect(worker_class)
+ .to receive(:bulk_perform_async)
+ .with([[:arg], [:arg], [:arg]])
+
+ perform_with_capacity
+ end
+ end
+ end
+
+ describe '#perform' do
+ subject(:perform) { worker.perform(:arg) }
+
+ context 'with capacity' do
+ before do
+ allow(worker).to receive(:max_running_jobs).and_return(10)
+ allow(worker).to receive(:running_jobs_count).and_return(0)
+ allow(worker).to receive(:remaining_work_count).and_return(0)
+ end
+
+ it 'calls perform_work' do
+ expect(worker).to receive(:perform_work).with(:arg)
+
+ perform
+ end
+
+ it 're-enqueues itself' do
+ allow(worker).to receive(:perform_work)
+ expect(worker).to receive(:re_enqueue).with(:arg)
+
+ perform
+ end
+
+ it 'registers itself in the running set' do
+ allow(worker).to receive(:perform_work)
+ expect(job_tracker).to receive(:register).with('my-jid')
+
+ perform
+ end
+
+ it 'removes itself from the running set' do
+ expect(job_tracker).to receive(:remove).with('my-jid')
+
+ allow(worker).to receive(:perform_work)
+
+ perform
+ end
+
+ it 'reports prometheus metrics' do
+ allow(worker).to receive(:perform_work)
+ expect(worker).to receive(:report_prometheus_metrics)
+
+ perform
+ end
+ end
+
+ context 'with capacity and without work' do
+ before do
+ allow(worker).to receive(:max_running_jobs).and_return(10)
+ allow(worker).to receive(:running_jobs_count).and_return(0)
+ allow(worker).to receive(:remaining_work_count).and_return(0)
+ allow(worker).to receive(:perform_work)
+ end
+
+ it 'does not re-enqueue itself' do
+ expect(worker_class).not_to receive(:perform_async)
+
+ perform
+ end
+ end
+
+ context 'without capacity' do
+ before do
+ allow(worker).to receive(:max_running_jobs).and_return(10)
+ allow(worker).to receive(:running_jobs_count).and_return(15)
+ allow(worker).to receive(:remaining_work_count).and_return(10)
+ end
+
+ it 'does not call perform_work' do
+ expect(worker).not_to receive(:perform_work)
+
+ perform
+ end
+
+ it 'does not re-enqueue itself' do
+ expect(worker_class).not_to receive(:perform_async)
+
+ perform
+ end
+
+ it 'does not register in the running set' do
+ expect(job_tracker).not_to receive(:register)
+
+ perform
+ end
+
+ it 'removes itself from the running set' do
+ expect(job_tracker).to receive(:remove).with('my-jid')
+
+ perform
+ end
+
+ it 'reports prometheus metrics' do
+ expect(worker).to receive(:report_prometheus_metrics)
+
+ perform
+ end
+ end
+
+ context 'when perform_work fails' do
+ it 'does not re-enqueue itself' do
+ expect(worker).not_to receive(:re_enqueue)
+
+ expect { perform }.to raise_error(NotImplementedError)
+ end
+
+ it 'removes itself from the running set' do
+ expect(job_tracker).to receive(:remove)
+
+ expect { perform }.to raise_error(NotImplementedError)
+ end
+
+ it 'reports prometheus metrics' do
+ expect(worker).to receive(:report_prometheus_metrics)
+
+ expect { perform }.to raise_error(NotImplementedError)
+ end
+ end
+ end
+
+ describe '#remaining_capacity' do
+ subject(:remaining_capacity) { worker.remaining_capacity }
+
+ before do
+ expect(worker).to receive(:max_running_jobs).and_return(max_capacity)
+ end
+
+ context 'when changing the capacity to a lower value' do
+ let(:max_capacity) { -1 }
+
+ it { expect(remaining_capacity).to eq(0) }
+ end
+
+ context 'when registering new jobs' do
+ let(:max_capacity) { 2 }
+
+ before do
+ job_tracker.register('a-job-id')
+ end
+
+ it { expect(remaining_capacity).to eq(1) }
+ end
+
+ context 'with jobs in the queue' do
+ let(:max_capacity) { 2 }
+
+ before do
+ expect(worker_class).to receive(:queue_size).and_return(1)
+ end
+
+ it { expect(remaining_capacity).to eq(1) }
+ end
+
+ context 'with both running jobs and queued jobs' do
+ let(:max_capacity) { 10 }
+
+ before do
+ expect(worker_class).to receive(:queue_size).and_return(5)
+ expect(worker).to receive(:running_jobs_count).and_return(3)
+ end
+
+ it { expect(remaining_capacity).to eq(2) }
+ end
+ end
+
+ describe '#remove_failed_jobs' do
+ subject(:remove_failed_jobs) { worker.remove_failed_jobs }
+
+ before do
+ job_tracker.register('a-job-id')
+ allow(worker).to receive(:max_running_jobs).and_return(2)
+
+ expect(job_tracker).to receive(:clean_up).and_call_original
+ end
+
+ context 'with failed jobs' do
+ it 'update the available capacity' do
+ expect { remove_failed_jobs }.to change { worker.remaining_capacity }.by(1)
+ end
+ end
+ end
+
+ describe '#report_prometheus_metrics' do
+ subject(:report_prometheus_metrics) { worker.report_prometheus_metrics }
+
+ before do
+ allow(worker).to receive(:running_jobs_count).and_return(5)
+ allow(worker).to receive(:max_running_jobs).and_return(7)
+ allow(worker).to receive(:remaining_work_count).and_return(9)
+ end
+
+ it 'reports number of running jobs' do
+ labels = { worker: 'DummyWorker' }
+
+ report_prometheus_metrics
+
+ expect(Gitlab::Metrics.registry.get(:limited_capacity_worker_running_jobs).get(labels)).to eq(5)
+ expect(Gitlab::Metrics.registry.get(:limited_capacity_worker_max_running_jobs).get(labels)).to eq(7)
+ expect(Gitlab::Metrics.registry.get(:limited_capacity_worker_remaining_work_count).get(labels)).to eq(9)
+ end
+ end
+end
diff --git a/spec/workers/container_expiration_policy_worker_spec.rb b/spec/workers/container_expiration_policy_worker_spec.rb
index 868eb6b192e..6b185c30670 100644
--- a/spec/workers/container_expiration_policy_worker_spec.rb
+++ b/spec/workers/container_expiration_policy_worker_spec.rb
@@ -7,19 +7,24 @@ RSpec.describe ContainerExpirationPolicyWorker do
subject { described_class.new.perform }
- context 'With no container expiration policies' do
- it 'Does not execute any policies' do
+ RSpec.shared_examples 'not executing any policy' do
+ it 'does not run any policy' do
expect(ContainerExpirationPolicyService).not_to receive(:new)
subject
end
end
+ context 'With no container expiration policies' do
+ it_behaves_like 'not executing any policy'
+ end
+
context 'With container expiration policies' do
- context 'a valid policy' do
- let!(:container_expiration_policy) { create(:container_expiration_policy, :runnable) }
- let(:user) { container_expiration_policy.project.owner }
+ let_it_be(:container_expiration_policy, reload: true) { create(:container_expiration_policy, :runnable) }
+ let_it_be(:container_repository) { create(:container_repository, project: container_expiration_policy.project) }
+ let_it_be(:user) { container_expiration_policy.project.owner }
+ context 'a valid policy' do
it 'runs the policy' do
service = instance_double(ContainerExpirationPolicyService, execute: true)
@@ -31,33 +36,30 @@ RSpec.describe ContainerExpirationPolicyWorker do
end
context 'a disabled policy' do
- let!(:container_expiration_policy) { create(:container_expiration_policy, :runnable, :disabled) }
- let(:user) {container_expiration_policy.project.owner }
-
- it 'does not run the policy' do
- expect(ContainerExpirationPolicyService)
- .not_to receive(:new).with(container_expiration_policy, user)
-
- subject
+ before do
+ container_expiration_policy.disable!
end
+
+ it_behaves_like 'not executing any policy'
end
context 'a policy that is not due for a run' do
- let!(:container_expiration_policy) { create(:container_expiration_policy) }
- let(:user) {container_expiration_policy.project.owner }
+ before do
+ container_expiration_policy.update_column(:next_run_at, 2.minutes.from_now)
+ end
- it 'does not run the policy' do
- expect(ContainerExpirationPolicyService)
- .not_to receive(:new).with(container_expiration_policy, user)
+ it_behaves_like 'not executing any policy'
+ end
- subject
+ context 'a policy linked to no container repository' do
+ before do
+ container_expiration_policy.container_repositories.delete_all
end
+
+ it_behaves_like 'not executing any policy'
end
context 'an invalid policy' do
- let_it_be(:container_expiration_policy) { create(:container_expiration_policy, :runnable) }
- let_it_be(:user) {container_expiration_policy.project.owner }
-
before do
container_expiration_policy.update_column(:name_regex, '*production')
end
diff --git a/spec/workers/deployments/drop_older_deployments_worker_spec.rb b/spec/workers/deployments/drop_older_deployments_worker_spec.rb
new file mode 100644
index 00000000000..0cf524ca16f
--- /dev/null
+++ b/spec/workers/deployments/drop_older_deployments_worker_spec.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Deployments::DropOlderDeploymentsWorker do
+ subject { described_class.new.perform(deployment&.id) }
+
+ describe '#perform' do
+ let(:deployment) { create(:deployment, :success) }
+
+ it 'executes Deployments::OlderDeploymentsDropService' do
+ expect(Deployments::OlderDeploymentsDropService)
+ .to receive(:new).with(deployment.id).and_call_original
+
+ subject
+ end
+ end
+end
diff --git a/spec/workers/deployments/execute_hooks_worker_spec.rb b/spec/workers/deployments/execute_hooks_worker_spec.rb
new file mode 100644
index 00000000000..fb1dc8cf290
--- /dev/null
+++ b/spec/workers/deployments/execute_hooks_worker_spec.rb
@@ -0,0 +1,51 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Deployments::ExecuteHooksWorker do
+ let(:worker) { described_class.new }
+
+ describe '#perform' do
+ before do
+ allow(ProjectServiceWorker).to receive(:perform_async)
+ end
+
+ it 'executes project services for deployment_hooks' do
+ deployment = create(:deployment, :running)
+ project = deployment.project
+ service = create(:service, type: 'SlackService', project: project, deployment_events: true, active: true)
+
+ expect(ProjectServiceWorker).to receive(:perform_async).with(service.id, an_instance_of(Hash))
+
+ worker.perform(deployment.id)
+ end
+
+ it 'does not execute an inactive service' do
+ deployment = create(:deployment, :running)
+ project = deployment.project
+ create(:service, type: 'SlackService', project: project, deployment_events: true, active: false)
+
+ expect(ProjectServiceWorker).not_to receive(:perform_async)
+
+ worker.perform(deployment.id)
+ end
+
+ it 'does not execute if a deployment does not exist' do
+ expect(ProjectServiceWorker).not_to receive(:perform_async)
+
+ worker.perform(non_existing_record_id)
+ end
+
+ it 'execute webhooks' do
+ deployment = create(:deployment, :running)
+ project = deployment.project
+ web_hook = create(:project_hook, deployment_events: true, project: project)
+
+ expect_next_instance_of(WebHookService, web_hook, an_instance_of(Hash), "deployment_hooks") do |service|
+ expect(service).to receive(:async_execute)
+ end
+
+ worker.perform(deployment.id)
+ end
+ end
+end
diff --git a/spec/workers/deployments/link_merge_request_worker_spec.rb b/spec/workers/deployments/link_merge_request_worker_spec.rb
new file mode 100644
index 00000000000..a55dd897bc7
--- /dev/null
+++ b/spec/workers/deployments/link_merge_request_worker_spec.rb
@@ -0,0 +1,71 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Deployments::LinkMergeRequestWorker do
+ subject(:worker) { described_class.new }
+
+ describe '#perform' do
+ it 'links merge requests to the deployment' do
+ deployment = create(:deployment)
+ service = instance_double(Deployments::LinkMergeRequestsService)
+
+ expect(Deployments::LinkMergeRequestsService)
+ .to receive(:new)
+ .with(deployment)
+ .and_return(service)
+
+ expect(service).to receive(:execute)
+
+ worker.perform(deployment.id)
+ end
+
+ it 'does not link merge requests when the deployment is not found' do
+ expect(Deployments::LinkMergeRequestsService).not_to receive(:new)
+
+ worker.perform(non_existing_record_id)
+ end
+ end
+
+ context 'idempotent' do
+ include_examples 'an idempotent worker' do
+ let(:project) { create(:project, :repository) }
+ let(:environment) { create(:environment, project: project) }
+ let(:deployment) { create(:deployment, :success, project: project, environment: environment) }
+ let(:job_args) { deployment.id }
+
+ it 'links merge requests to deployment' do
+ mr1 = create(
+ :merge_request,
+ :merged,
+ source_project: project,
+ target_project: project,
+ source_branch: 'source1',
+ target_branch: deployment.ref
+ )
+
+ mr2 = create(
+ :merge_request,
+ :merged,
+ source_project: project,
+ target_project: project,
+ source_branch: 'source2',
+ target_branch: deployment.ref
+ )
+
+ mr3 = create(
+ :merge_request,
+ :merged,
+ source_project: project,
+ target_project: project,
+ target_branch: 'foo'
+ )
+
+ subject
+
+ expect(deployment.merge_requests).to include(mr1, mr2)
+ expect(deployment.merge_requests).not_to include(mr3)
+ end
+ end
+ end
+end
diff --git a/spec/workers/deployments/success_worker_spec.rb b/spec/workers/deployments/success_worker_spec.rb
index 7c21a3147a7..d9996e66919 100644
--- a/spec/workers/deployments/success_worker_spec.rb
+++ b/spec/workers/deployments/success_worker_spec.rb
@@ -8,8 +8,8 @@ RSpec.describe Deployments::SuccessWorker do
context 'when successful deployment' do
let(:deployment) { create(:deployment, :success) }
- it 'executes Deployments::AfterCreateService' do
- expect(Deployments::AfterCreateService)
+ it 'executes Deployments::UpdateEnvironmentService' do
+ expect(Deployments::UpdateEnvironmentService)
.to receive(:new).with(deployment).and_call_original
subject
@@ -19,8 +19,8 @@ RSpec.describe Deployments::SuccessWorker do
context 'when canceled deployment' do
let(:deployment) { create(:deployment, :canceled) }
- it 'does not execute Deployments::AfterCreateService' do
- expect(Deployments::AfterCreateService).not_to receive(:new)
+ it 'does not execute Deployments::UpdateEnvironmentService' do
+ expect(Deployments::UpdateEnvironmentService).not_to receive(:new)
subject
end
@@ -29,8 +29,8 @@ RSpec.describe Deployments::SuccessWorker do
context 'when deploy record does not exist' do
let(:deployment) { nil }
- it 'does not execute Deployments::AfterCreateService' do
- expect(Deployments::AfterCreateService).not_to receive(:new)
+ it 'does not execute Deployments::UpdateEnvironmentService' do
+ expect(Deployments::UpdateEnvironmentService).not_to receive(:new)
subject
end
diff --git a/spec/workers/deployments/update_environment_worker_spec.rb b/spec/workers/deployments/update_environment_worker_spec.rb
new file mode 100644
index 00000000000..d67cbd62616
--- /dev/null
+++ b/spec/workers/deployments/update_environment_worker_spec.rb
@@ -0,0 +1,63 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Deployments::UpdateEnvironmentWorker do
+ subject(:worker) { described_class.new }
+
+ context 'when successful deployment' do
+ let(:deployment) { create(:deployment, :success) }
+
+ it 'executes Deployments::UpdateEnvironmentService' do
+ service = instance_double(Deployments::UpdateEnvironmentService)
+
+ expect(Deployments::UpdateEnvironmentService)
+ .to receive(:new)
+ .with(deployment)
+ .and_return(service)
+
+ expect(service).to receive(:execute)
+
+ worker.perform(deployment.id)
+ end
+ end
+
+ context 'when canceled deployment' do
+ let(:deployment) { create(:deployment, :canceled) }
+
+ it 'does not execute Deployments::UpdateEnvironmentService' do
+ expect(Deployments::UpdateEnvironmentService).not_to receive(:new)
+
+ worker.perform(deployment.id)
+ end
+ end
+
+ context 'when deploy record does not exist' do
+ it 'does not execute Deployments::UpdateEnvironmentService' do
+ expect(Deployments::UpdateEnvironmentService).not_to receive(:new)
+
+ worker.perform(non_existing_record_id)
+ end
+ end
+
+ context 'idempotent' do
+ include_examples 'an idempotent worker' do
+ let(:project) { create(:project, :repository) }
+ let(:environment) { create(:environment, name: 'production') }
+ let(:deployment) { create(:deployment, :success, project: project, environment: environment) }
+ let(:merge_request) { create(:merge_request, target_branch: 'master', source_branch: 'feature', source_project: project) }
+ let(:job_args) { deployment.id }
+
+ before do
+ merge_request.metrics.update!(merged_at: 1.hour.ago)
+ end
+
+ it 'updates merge requests metrics' do
+ subject
+
+ expect(merge_request.reload.metrics.first_deployed_to_production_at)
+ .to be_like_time(deployment.finished_at)
+ end
+ end
+ end
+end
diff --git a/spec/workers/design_management/copy_design_collection_worker_spec.rb b/spec/workers/design_management/copy_design_collection_worker_spec.rb
new file mode 100644
index 00000000000..45bfc47ca7e
--- /dev/null
+++ b/spec/workers/design_management/copy_design_collection_worker_spec.rb
@@ -0,0 +1,39 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe DesignManagement::CopyDesignCollectionWorker, :clean_gitlab_redis_shared_state do
+ describe '#perform' do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:issue) { create(:issue) }
+ let_it_be(:target_issue) { create(:issue) }
+
+ subject { described_class.new.perform(user.id, issue.id, target_issue.id) }
+
+ it_behaves_like 'an idempotent worker' do
+ let(:job_args) { [user.id, issue.id, target_issue.id] }
+
+ specify { subject }
+ end
+
+ it 'calls DesignManagement::CopyDesignCollection::CopyService' do
+ expect_next_instance_of(DesignManagement::CopyDesignCollection::CopyService) do |service|
+ expect(service).to receive(:execute).and_return(ServiceResponse.success)
+ end
+
+ subject
+ end
+
+ it 'logs if there was an error calling the service' do
+ message = 'Error message'
+
+ allow_next_instance_of(DesignManagement::CopyDesignCollection::CopyService) do |service|
+ allow(service).to receive(:execute).and_return(ServiceResponse.error(message: message))
+ end
+
+ expect(Gitlab::AppLogger).to receive(:warn).with(message)
+
+ subject
+ end
+ end
+end
diff --git a/spec/workers/design_management/new_version_worker_spec.rb b/spec/workers/design_management/new_version_worker_spec.rb
index 4d57c46487e..3320d7a062d 100644
--- a/spec/workers/design_management/new_version_worker_spec.rb
+++ b/spec/workers/design_management/new_version_worker_spec.rb
@@ -36,6 +36,10 @@ RSpec.describe DesignManagement::NewVersionWorker do
expect { worker.perform(version.id) }.to change { Note.system.count }.by(1)
end
+ it 'does not create a system note if skip_system_notes is true' do
+ expect { worker.perform(version.id, true) }.not_to change { Note.system.count }
+ end
+
it 'invokes GenerateImageVersionsService' do
expect_next_instance_of(DesignManagement::GenerateImageVersionsService) do |service|
expect(service).to receive(:execute)
diff --git a/spec/workers/disallow_two_factor_for_group_worker_spec.rb b/spec/workers/disallow_two_factor_for_group_worker_spec.rb
new file mode 100644
index 00000000000..a69dd893f81
--- /dev/null
+++ b/spec/workers/disallow_two_factor_for_group_worker_spec.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe DisallowTwoFactorForGroupWorker do
+ let_it_be(:group) { create(:group, require_two_factor_authentication: true) }
+ let_it_be(:user) { create(:user, require_two_factor_authentication_from_group: true) }
+
+ it "updates group" do
+ described_class.new.perform(group.id)
+
+ expect(group.reload.require_two_factor_authentication).to eq(false)
+ end
+
+ it "updates group members" do
+ group.add_user(user, GroupMember::DEVELOPER)
+
+ described_class.new.perform(group.id)
+
+ expect(user.reload.require_two_factor_authentication_from_group).to eq(false)
+ end
+end
diff --git a/spec/workers/disallow_two_factor_for_subgroups_worker_spec.rb b/spec/workers/disallow_two_factor_for_subgroups_worker_spec.rb
new file mode 100644
index 00000000000..c3be8263171
--- /dev/null
+++ b/spec/workers/disallow_two_factor_for_subgroups_worker_spec.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe DisallowTwoFactorForSubgroupsWorker do
+ let_it_be(:group) { create(:group) }
+ let_it_be(:subgroup_with_2fa) { create(:group, parent: group, require_two_factor_authentication: true) }
+ let_it_be(:subgroup_without_2fa) { create(:group, parent: group, require_two_factor_authentication: false) }
+ let_it_be(:subsubgroup_with_2fa) { create(:group, parent: subgroup_with_2fa, require_two_factor_authentication: true) }
+
+ it "schedules updating subgroups" do
+ expect(DisallowTwoFactorForGroupWorker).to receive(:perform_in).with(0, subgroup_with_2fa.id)
+ expect(DisallowTwoFactorForGroupWorker).to receive(:perform_in).with(2, subsubgroup_with_2fa.id)
+
+ described_class.new.perform(group.id)
+ end
+end
diff --git a/spec/workers/export_csv_worker_spec.rb b/spec/workers/export_csv_worker_spec.rb
index 1a5b17ee35b..88ccfac0a02 100644
--- a/spec/workers/export_csv_worker_spec.rb
+++ b/spec/workers/export_csv_worker_spec.rb
@@ -10,25 +10,9 @@ RSpec.describe ExportCsvWorker do
described_class.new.perform(user.id, project.id, params)
end
- it 'emails a CSV' do
- expect {perform}.to change(ActionMailer::Base.deliveries, :size).by(1)
- end
-
- it 'ensures that project_id is passed to issues_finder' do
- expect(IssuesFinder).to receive(:new).with(anything, hash_including(project_id: project.id)).and_call_original
+ it 'delegates call to IssuableExportCsvWorker' do
+ expect(IssuableExportCsvWorker).to receive(:perform_async).with(:issue, user.id, project.id, anything)
perform
end
-
- it 'removes sort parameter' do
- expect(IssuesFinder).to receive(:new).with(anything, hash_not_including(:sort)).and_call_original
-
- perform
- end
-
- it 'converts controller string keys to symbol keys for IssuesFinder' do
- expect(IssuesFinder).to receive(:new).with(anything, hash_including(test_key: true)).and_call_original
-
- perform('test_key' => true)
- end
end
diff --git a/spec/workers/git_garbage_collect_worker_spec.rb b/spec/workers/git_garbage_collect_worker_spec.rb
index 1be6e86b650..fc9115a5ea1 100644
--- a/spec/workers/git_garbage_collect_worker_spec.rb
+++ b/spec/workers/git_garbage_collect_worker_spec.rb
@@ -56,7 +56,7 @@ RSpec.describe GitGarbageCollectWorker do
it "flushes ref caches when the task if 'gc'" do
expect(subject).to receive(:renew_lease).with(lease_key, lease_uuid).and_call_original
- expect_any_instance_of(Repository).to receive(:after_create_branch).and_call_original
+ expect_any_instance_of(Repository).to receive(:expire_branches_cache).and_call_original
expect_any_instance_of(Repository).to receive(:branch_names).and_call_original
expect_any_instance_of(Repository).to receive(:has_visible_content?).and_call_original
expect_any_instance_of(Gitlab::Git::Repository).to receive(:has_visible_content?).and_call_original
@@ -77,7 +77,7 @@ RSpec.describe GitGarbageCollectWorker do
end
it 'returns silently' do
- expect_any_instance_of(Repository).not_to receive(:after_create_branch).and_call_original
+ expect_any_instance_of(Repository).not_to receive(:expire_branches_cache).and_call_original
expect_any_instance_of(Repository).not_to receive(:branch_names).and_call_original
expect_any_instance_of(Repository).not_to receive(:has_visible_content?).and_call_original
@@ -102,7 +102,7 @@ RSpec.describe GitGarbageCollectWorker do
it "flushes ref caches when the task if 'gc'" do
expect(subject).to receive(:get_lease_uuid).with("git_gc:#{task}:#{project.id}").and_return(false)
- expect_any_instance_of(Repository).to receive(:after_create_branch).and_call_original
+ expect_any_instance_of(Repository).to receive(:expire_branches_cache).and_call_original
expect_any_instance_of(Repository).to receive(:branch_names).and_call_original
expect_any_instance_of(Repository).to receive(:has_visible_content?).and_call_original
expect_any_instance_of(Gitlab::Git::Repository).to receive(:has_visible_content?).and_call_original
@@ -129,46 +129,36 @@ RSpec.describe GitGarbageCollectWorker do
let_it_be(:lfs_reference) { create(:lfs_objects_project, project: project) }
let(:lfs_object) { lfs_reference.lfs_object }
- context 'with cleanup_lfs_during_gc feature flag enabled' do
- before do
- stub_feature_flags(cleanup_lfs_during_gc: true)
+ it 'cleans up unreferenced LFS objects' do
+ expect_next_instance_of(Gitlab::Cleanup::OrphanLfsFileReferences) do |svc|
+ expect(svc.project).to eq(project)
+ expect(svc.dry_run).to be_falsy
+ expect(svc).to receive(:run!).and_call_original
end
- it 'cleans up unreferenced LFS objects' do
- expect_next_instance_of(Gitlab::Cleanup::OrphanLfsFileReferences) do |svc|
- expect(svc.project).to eq(project)
- expect(svc.dry_run).to be_falsy
- expect(svc).to receive(:run!).and_call_original
- end
-
- subject.perform(*params)
-
- expect(project.lfs_objects.reload).not_to include(lfs_object)
- end
+ subject.perform(*params)
- it 'does nothing if the database is read-only' do
- allow(Gitlab::Database).to receive(:read_only?) { true }
+ expect(project.lfs_objects.reload).not_to include(lfs_object)
+ end
- expect_any_instance_of(Gitlab::Cleanup::OrphanLfsFileReferences).not_to receive(:run!)
+ it 'catches and logs exceptions' do
+ expect_any_instance_of(Gitlab::Cleanup::OrphanLfsFileReferences)
+ .to receive(:run!)
+ .and_raise(/Failed/)
- subject.perform(*params)
+ expect(Gitlab::GitLogger).to receive(:warn)
+ expect(Gitlab::ErrorTracking).to receive(:track_and_raise_for_dev_exception)
- expect(project.lfs_objects.reload).to include(lfs_object)
- end
+ subject.perform(*params)
end
- context 'with cleanup_lfs_during_gc feature flag disabled' do
- before do
- stub_feature_flags(cleanup_lfs_during_gc: false)
- end
-
- it 'does not clean up unreferenced LFS objects' do
- expect_any_instance_of(Gitlab::Cleanup::OrphanLfsFileReferences).not_to receive(:run!)
+ it 'does nothing if the database is read-only' do
+ allow(Gitlab::Database).to receive(:read_only?) { true }
+ expect_any_instance_of(Gitlab::Cleanup::OrphanLfsFileReferences).not_to receive(:run!)
- subject.perform(*params)
+ subject.perform(*params)
- expect(project.lfs_objects.reload).to include(lfs_object)
- end
+ expect(project.lfs_objects.reload).to include(lfs_object)
end
end
end
@@ -180,7 +170,7 @@ RSpec.describe GitGarbageCollectWorker do
it 'returns silently' do
expect(subject).not_to receive(:command)
- expect_any_instance_of(Repository).not_to receive(:after_create_branch).and_call_original
+ expect_any_instance_of(Repository).not_to receive(:expire_branches_cache).and_call_original
expect_any_instance_of(Repository).not_to receive(:branch_names).and_call_original
expect_any_instance_of(Repository).not_to receive(:has_visible_content?).and_call_original
diff --git a/spec/workers/group_export_worker_spec.rb b/spec/workers/group_export_worker_spec.rb
index 5697e66b7d1..4e58e3886a4 100644
--- a/spec/workers/group_export_worker_spec.rb
+++ b/spec/workers/group_export_worker_spec.rb
@@ -26,4 +26,14 @@ RSpec.describe GroupExportWorker do
end
end
end
+
+ describe 'sidekiq options' do
+ it 'disables retry' do
+ expect(described_class.sidekiq_options['retry']).to eq(false)
+ end
+
+ it 'disables dead' do
+ expect(described_class.sidekiq_options['dead']).to eq(false)
+ end
+ end
end
diff --git a/spec/workers/group_import_worker_spec.rb b/spec/workers/group_import_worker_spec.rb
index fb2d49c21af..5171de7086b 100644
--- a/spec/workers/group_import_worker_spec.rb
+++ b/spec/workers/group_import_worker_spec.rb
@@ -3,17 +3,29 @@
require 'spec_helper'
RSpec.describe GroupImportWorker do
- let!(:user) { create(:user) }
- let!(:group) { create(:group) }
+ let(:user) { create(:user) }
+ let(:group) { create(:group) }
subject { described_class.new }
before do
+ create(:group_import_state, group: group, user: user)
+
allow_next_instance_of(described_class) do |job|
allow(job).to receive(:jid).and_return(SecureRandom.hex(8))
end
end
+ describe 'sidekiq options' do
+ it 'disables retry' do
+ expect(described_class.sidekiq_options['retry']).to eq(false)
+ end
+
+ it 'disables dead' do
+ expect(described_class.sidekiq_options['dead']).to eq(false)
+ end
+ end
+
describe '#perform' do
context 'when it succeeds' do
before do
@@ -26,44 +38,11 @@ RSpec.describe GroupImportWorker do
subject.perform(user.id, group.id)
end
- context 'when the import state does not exist' do
- it 'creates group import' do
- expect(group.import_state).to be_nil
-
- subject.perform(user.id, group.id)
- import_state = group.reload.import_state
-
- expect(import_state).to be_instance_of(GroupImportState)
- expect(import_state.status_name).to eq(:finished)
- expect(import_state.jid).not_to be_empty
- end
-
- it 'sets the group import status to started' do
- expect_next_instance_of(GroupImportState) do |import|
- expect(import).to receive(:start!).and_call_original
- end
-
- subject.perform(user.id, group.id)
- end
-
- it 'sets the group import status to finished' do
- expect_next_instance_of(GroupImportState) do |import|
- expect(import).to receive(:finish!).and_call_original
- end
-
- subject.perform(user.id, group.id)
- end
- end
-
- context 'when the import state already exists' do
- it 'updates the existing state' do
- existing_state = create(:group_import_state, group: group)
-
- expect { subject.perform(user.id, group.id) }
- .not_to change { GroupImportState.count }
+ it 'updates the existing state' do
+ expect { subject.perform(user.id, group.id) }
+ .not_to change { GroupImportState.count }
- expect(existing_state.reload).to be_finished
- end
+ expect(group.import_state.reload).to be_finished
end
end
@@ -83,11 +62,9 @@ RSpec.describe GroupImportWorker do
end
it 'sets the group import status to failed' do
- expect_next_instance_of(GroupImportState) do |import|
- expect(import).to receive(:fail_op).and_call_original
- end
-
expect { subject.perform(user.id, group.id) }.to raise_exception(Gitlab::ImportExport::Error)
+
+ expect(group.import_state.reload.status).to eq(-1)
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
new file mode 100644
index 00000000000..203c62ffe6f
--- /dev/null
+++ b/spec/workers/incident_management/add_severity_system_note_worker_spec.rb
@@ -0,0 +1,60 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe IncidentManagement::AddSeveritySystemNoteWorker do
+ let_it_be(:project) { create(:project) }
+ let_it_be(:user) { create(:user) }
+ let_it_be(:incident) { create(:incident, project: project) }
+ let_it_be(:issuable_severity) { create(:issuable_severity, issue: incident, severity: :medium) }
+
+ describe '#perform' do
+ let(:incident_id) { incident.id }
+ let(:user_id) { user.id }
+
+ subject(:perform) { described_class.new.perform(incident_id, user_id) }
+
+ shared_examples 'does not add a system note' do
+ it 'does not change incident notes count' do
+ expect { perform }.not_to change { incident.notes.count }
+ 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
+ end
+
+ context 'when incident does not exist' do
+ let(:incident_id) { -1 }
+
+ it_behaves_like 'does not add a system note'
+ end
+
+ context 'when incident_id is nil' do
+ let(:incident_id) { nil }
+
+ it_behaves_like 'does not add a system note'
+ end
+
+ context 'when issue is not an incident' do
+ let_it_be(:issue) { create(:issue, project: project) }
+ let(:incident_id) { issue.id }
+
+ it_behaves_like 'does not add a system note'
+ end
+
+ context 'when user does not exist' do
+ let(:user_id) { -1 }
+
+ it_behaves_like 'does not add a system note'
+ end
+
+ context 'when user_id is nil' do
+ let(:user_id) { nil }
+
+ it_behaves_like 'does not add a system note'
+ end
+ end
+end
diff --git a/spec/workers/incident_management/process_alert_worker_spec.rb b/spec/workers/incident_management/process_alert_worker_spec.rb
index 20ab283b49b..41d4f31da24 100644
--- a/spec/workers/incident_management/process_alert_worker_spec.rb
+++ b/spec/workers/incident_management/process_alert_worker_spec.rb
@@ -9,7 +9,6 @@ RSpec.describe IncidentManagement::ProcessAlertWorker do
describe '#perform' do
let_it_be(:started_at) { Time.now.rfc3339 }
let_it_be(:payload) { { 'title' => 'title', 'start_time' => started_at } }
- let_it_be(:parsed_payload) { Gitlab::Alerting::NotificationPayloadParser.call(payload, project) }
let_it_be(:alert) { create(:alert_management_alert, project: project, payload: payload, started_at: started_at) }
let(:created_issue) { Issue.last! }
@@ -68,7 +67,6 @@ RSpec.describe IncidentManagement::ProcessAlertWorker do
context 'prometheus alert' do
let_it_be(:alert) { create(:alert_management_alert, :prometheus, project: project, started_at: started_at) }
- let_it_be(:parsed_payload) { alert.payload }
it_behaves_like 'creates issue successfully'
end
diff --git a/spec/workers/incident_management/process_prometheus_alert_worker_spec.rb b/spec/workers/incident_management/process_prometheus_alert_worker_spec.rb
index c294892a66f..2ca4193aa72 100644
--- a/spec/workers/incident_management/process_prometheus_alert_worker_spec.rb
+++ b/spec/workers/incident_management/process_prometheus_alert_worker_spec.rb
@@ -6,7 +6,7 @@ RSpec.describe IncidentManagement::ProcessPrometheusAlertWorker do
describe '#perform' do
let_it_be(:project) { create(:project) }
let_it_be(:prometheus_alert) { create(:prometheus_alert, project: project) }
- let(:payload_key) { Gitlab::Alerting::Alert.new(project: project, payload: alert_params).gitlab_fingerprint }
+ let(:payload_key) { Gitlab::AlertManagement::Payload::Prometheus.new(project: project, payload: alert_params).gitlab_fingerprint }
let!(:prometheus_alert_event) { create(:prometheus_alert_event, prometheus_alert: prometheus_alert, payload_key: payload_key) }
let!(:settings) { create(:project_incident_management_setting, project: project, create_issue: true) }
diff --git a/spec/workers/issuable_export_csv_worker_spec.rb b/spec/workers/issuable_export_csv_worker_spec.rb
new file mode 100644
index 00000000000..bcc2420996d
--- /dev/null
+++ b/spec/workers/issuable_export_csv_worker_spec.rb
@@ -0,0 +1,73 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe IssuableExportCsvWorker do
+ let(:user) { create(:user) }
+ let(:project) { create(:project, creator: user) }
+ let(:params) { {} }
+
+ subject { described_class.new.perform(issuable_type, user.id, project.id, params) }
+
+ context 'when issuable type is Issue' do
+ let(:issuable_type) { :issue }
+
+ it 'emails a CSV' do
+ expect { subject }.to change(ActionMailer::Base.deliveries, :size).by(1)
+ end
+
+ it 'ensures that project_id is passed to issues_finder' do
+ expect(IssuesFinder).to receive(:new).with(anything, hash_including(project_id: project.id)).and_call_original
+
+ subject
+ end
+
+ it 'removes sort parameter' do
+ expect(IssuesFinder).to receive(:new).with(anything, hash_not_including(:sort)).and_call_original
+
+ subject
+ end
+
+ it 'calls the issue export service' do
+ expect(Issues::ExportCsvService).to receive(:new).once.and_call_original
+
+ subject
+ end
+
+ context 'with params' do
+ let(:params) { { 'test_key' => true } }
+
+ it 'converts controller string keys to symbol keys for IssuesFinder' do
+ expect(IssuesFinder).to receive(:new).with(user, hash_including(test_key: true)).and_call_original
+
+ subject
+ end
+ end
+ end
+
+ context 'when issuable type is MergeRequest' do
+ let(:issuable_type) { :merge_request }
+
+ it 'emails a CSV' do
+ expect { subject }.to change(ActionMailer::Base.deliveries, :size).by(1)
+ end
+
+ it 'calls the MR export service' do
+ expect(MergeRequests::ExportCsvService).to receive(:new).with(anything, project).once.and_call_original
+
+ subject
+ end
+
+ it 'calls the MergeRequest finder' do
+ expect(MergeRequestsFinder).to receive(:new).once.and_call_original
+
+ subject
+ end
+ end
+
+ context 'when issuable type is User' do
+ let(:issuable_type) { :user }
+
+ it { expect { subject }.to raise_error(ArgumentError) }
+ end
+end
diff --git a/spec/workers/member_invitation_reminder_emails_worker_spec.rb b/spec/workers/member_invitation_reminder_emails_worker_spec.rb
new file mode 100644
index 00000000000..bfd08792c7c
--- /dev/null
+++ b/spec/workers/member_invitation_reminder_emails_worker_spec.rb
@@ -0,0 +1,39 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe MemberInvitationReminderEmailsWorker do
+ describe '#perform' do
+ subject { described_class.new.perform }
+
+ before do
+ create(:group_member, :invited, created_at: 2.days.ago)
+ end
+
+ context 'feature flag disabled' do
+ before do
+ stub_experiment(invitation_reminders: false)
+ end
+
+ it 'does not attempt to execute the invitation reminder service' do
+ expect(Members::InvitationReminderEmailService).not_to receive(:new)
+
+ subject
+ end
+ end
+
+ context 'feature flag enabled' do
+ before do
+ stub_experiment(invitation_reminders: true)
+ end
+
+ it 'executes the invitation reminder email service' do
+ expect_next_instance_of(Members::InvitationReminderEmailService) do |service|
+ expect(service).to receive(:execute)
+ end
+
+ subject
+ end
+ end
+ end
+end
diff --git a/spec/workers/metrics/dashboard/prune_old_annotations_worker_spec.rb b/spec/workers/metrics/dashboard/prune_old_annotations_worker_spec.rb
index d93612afe37..11343f69d6f 100644
--- a/spec/workers/metrics/dashboard/prune_old_annotations_worker_spec.rb
+++ b/spec/workers/metrics/dashboard/prune_old_annotations_worker_spec.rb
@@ -17,7 +17,7 @@ RSpec.describe Metrics::Dashboard::PruneOldAnnotationsWorker do
# is idempotent in the scope of 24h
expect { described_class.new.perform }.not_to change { Metrics::Dashboard::Annotation.all.to_a }
- Timecop.travel(24.hours.from_now) do
+ travel_to(24.hours.from_now) do
described_class.new.perform
expect(Metrics::Dashboard::Annotation.all).to match_array([one_day_old_annotation])
end
diff --git a/spec/workers/metrics/dashboard/sync_dashboards_worker_spec.rb b/spec/workers/metrics/dashboard/sync_dashboards_worker_spec.rb
new file mode 100644
index 00000000000..19b79835825
--- /dev/null
+++ b/spec/workers/metrics/dashboard/sync_dashboards_worker_spec.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Metrics::Dashboard::SyncDashboardsWorker do
+ include MetricsDashboardHelpers
+ subject(:worker) { described_class.new }
+
+ let(:project) { project_with_dashboard(dashboard_path) }
+ let(:dashboard_path) { '.gitlab/dashboards/test.yml' }
+
+ describe ".perform" do
+ it 'imports metrics' do
+ expect { worker.perform(project.id) }.to change(PrometheusMetric, :count).by(3)
+ end
+
+ it 'is idempotent' do
+ 2.times do
+ worker.perform(project.id)
+ end
+
+ expect(PrometheusMetric.count).to eq(3)
+ end
+ end
+end
diff --git a/spec/workers/post_receive_spec.rb b/spec/workers/post_receive_spec.rb
index 50d164d1705..77c1d16428f 100644
--- a/spec/workers/post_receive_spec.rb
+++ b/spec/workers/post_receive_spec.rb
@@ -281,7 +281,7 @@ RSpec.describe PostReceive do
before do
# Need to mock here so we can expect calls on project
- allow(Gitlab::GlRepository).to receive(:parse).and_return([project, project, Gitlab::GlRepository::WIKI])
+ allow(Gitlab::GlRepository).to receive(:parse).and_return([project.wiki, project, Gitlab::GlRepository::WIKI])
end
it 'updates project activity' do
@@ -290,7 +290,7 @@ RSpec.describe PostReceive do
# MySQL drops milliseconds in the timestamps, so advance at least
# a second to ensure we see changes.
- Timecop.freeze(1.second.from_now) do
+ travel_to(1.second.from_now) do
expect do
perform
project.reload
diff --git a/spec/workers/project_export_worker_spec.rb b/spec/workers/project_export_worker_spec.rb
index 1f54b6766a4..defecefc3cc 100644
--- a/spec/workers/project_export_worker_spec.rb
+++ b/spec/workers/project_export_worker_spec.rb
@@ -75,6 +75,10 @@ RSpec.describe ProjectExportWorker do
expect(described_class.sidekiq_options['retry']).to eq(false)
end
+ it 'disables dead' do
+ expect(described_class.sidekiq_options['dead']).to eq(false)
+ end
+
it 'sets default status expiration' do
expect(described_class.sidekiq_options['status_expiration']).to eq(StuckExportJobsWorker::EXPORT_JOBS_EXPIRATION)
end
diff --git a/spec/workers/propagate_integration_group_worker_spec.rb b/spec/workers/propagate_integration_group_worker_spec.rb
new file mode 100644
index 00000000000..fbf1fbf1fea
--- /dev/null
+++ b/spec/workers/propagate_integration_group_worker_spec.rb
@@ -0,0 +1,44 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe PropagateIntegrationGroupWorker do
+ describe '#perform' do
+ let_it_be(:group) { create(:group) }
+ let_it_be(:another_group) { create(:group) }
+ let_it_be(:subgroup1) { create(:group, parent: group) }
+ let_it_be(:subgroup2) { create(:group, parent: group) }
+ let_it_be(:integration) { create(:redmine_service, :instance) }
+ let(:job_args) { [integration.id, group.id, subgroup2.id] }
+
+ it_behaves_like 'an idempotent worker' do
+ it 'calls to BulkCreateIntegrationService' do
+ expect(BulkCreateIntegrationService).to receive(:new)
+ .with(integration, match_array([group, another_group, subgroup1, subgroup2]), 'group').twice
+ .and_return(double(execute: nil))
+
+ subject
+ end
+
+ context 'with a group integration' do
+ let_it_be(:integration) { create(:redmine_service, group: group, project: nil) }
+
+ it 'calls to BulkCreateIntegrationService' do
+ expect(BulkCreateIntegrationService).to receive(:new)
+ .with(integration, match_array([subgroup1, subgroup2]), 'group').twice
+ .and_return(double(execute: nil))
+
+ subject
+ end
+ end
+ end
+
+ context 'with an invalid integration id' do
+ it 'returns without failure' do
+ expect(BulkCreateIntegrationService).not_to receive(:new)
+
+ subject.perform(0, 1, 100)
+ end
+ end
+ end
+end
diff --git a/spec/workers/propagate_integration_inherit_worker_spec.rb b/spec/workers/propagate_integration_inherit_worker_spec.rb
new file mode 100644
index 00000000000..cbfee29a6a0
--- /dev/null
+++ b/spec/workers/propagate_integration_inherit_worker_spec.rb
@@ -0,0 +1,32 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe PropagateIntegrationInheritWorker do
+ describe '#perform' do
+ let_it_be(:integration) { create(:redmine_service, :instance) }
+ let_it_be(:integration1) { create(:redmine_service, inherit_from_id: integration.id) }
+ let_it_be(:integration2) { create(:bugzilla_service, inherit_from_id: integration.id) }
+ let_it_be(:integration3) { create(:redmine_service) }
+
+ it_behaves_like 'an idempotent worker' do
+ let(:job_args) { [integration.id, integration1.id, integration3.id] }
+
+ it 'calls to BulkCreateIntegrationService' do
+ expect(BulkUpdateIntegrationService).to receive(:new)
+ .with(integration, match_array(integration1)).twice
+ .and_return(double(execute: nil))
+
+ subject
+ end
+ end
+
+ context 'with an invalid integration id' do
+ it 'returns without failure' do
+ expect(BulkUpdateIntegrationService).not_to receive(:new)
+
+ subject.perform(0, integration1.id, integration3.id)
+ end
+ end
+ end
+end
diff --git a/spec/workers/propagate_integration_project_worker_spec.rb b/spec/workers/propagate_integration_project_worker_spec.rb
new file mode 100644
index 00000000000..0302af2acc9
--- /dev/null
+++ b/spec/workers/propagate_integration_project_worker_spec.rb
@@ -0,0 +1,44 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe PropagateIntegrationProjectWorker do
+ describe '#perform' do
+ let_it_be(:group) { create(:group) }
+ let_it_be(:project1) { create(:project) }
+ let_it_be(:project2) { create(:project, group: group) }
+ let_it_be(:project3) { create(:project, group: group) }
+ let_it_be(:integration) { create(:redmine_service, :instance) }
+ let(:job_args) { [integration.id, project1.id, project3.id] }
+
+ it_behaves_like 'an idempotent worker' do
+ it 'calls to BulkCreateIntegrationService' do
+ expect(BulkCreateIntegrationService).to receive(:new)
+ .with(integration, match_array([project1, project2, project3]), 'project').twice
+ .and_return(double(execute: nil))
+
+ subject
+ end
+
+ context 'with a group integration' do
+ let_it_be(:integration) { create(:redmine_service, group: group, project: nil) }
+
+ it 'calls to BulkCreateIntegrationService' do
+ expect(BulkCreateIntegrationService).to receive(:new)
+ .with(integration, match_array([project2, project3]), 'project').twice
+ .and_return(double(execute: nil))
+
+ subject
+ end
+ end
+ end
+
+ context 'with an invalid integration id' do
+ it 'returns without failure' do
+ expect(BulkCreateIntegrationService).not_to receive(:new)
+
+ subject.perform(0, 1, 100)
+ end
+ end
+ end
+end
diff --git a/spec/workers/web_hooks/destroy_worker_spec.rb b/spec/workers/web_hooks/destroy_worker_spec.rb
new file mode 100644
index 00000000000..fd26c8591ee
--- /dev/null
+++ b/spec/workers/web_hooks/destroy_worker_spec.rb
@@ -0,0 +1,59 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe WebHooks::DestroyWorker do
+ let_it_be(:project) { create(:project) }
+ let_it_be(:user) { create(:user) }
+
+ before_all do
+ project.add_maintainer(user)
+ end
+
+ subject { described_class.new }
+
+ describe "#perform" do
+ context 'with a Web hook' do
+ let!(:hook) { create(:project_hook, project: project) }
+ let!(:other_hook) { create(:project_hook, project: project) }
+ let!(:log) { create(:web_hook_log, web_hook: hook) }
+ let!(:other_log) { create(:web_hook_log, web_hook: other_hook) }
+
+ it "deletes the Web hook and logs", :aggregate_failures do
+ expect { subject.perform(user.id, hook.id) }
+ .to change { WebHookLog.count }.from(2).to(1)
+ .and change { WebHook.count }.from(2).to(1)
+
+ expect(WebHook.find(other_hook.id)).to be_present
+ expect(WebHookLog.find(other_log.id)).to be_present
+ end
+
+ it "raises and tracks an error if destroy failed" do
+ allow_next_instance_of(::WebHooks::DestroyService) do |instance|
+ expect(instance).to receive(:sync_destroy).with(anything).and_return({ status: :error, message: "failed" })
+ end
+
+ expect(Gitlab::ErrorTracking).to receive(:track_exception)
+ .with(an_instance_of(::WebHooks::DestroyService::DestroyError), web_hook_id: hook.id)
+ .and_call_original
+ expect { subject.perform(user.id, hook.id) }.to raise_error(::WebHooks::DestroyService::DestroyError)
+ end
+
+ context 'with unknown hook' do
+ it 'does not raise an error' do
+ expect { subject.perform(user.id, non_existing_record_id) }.not_to raise_error
+
+ expect(WebHook.count).to eq(2)
+ end
+ end
+
+ context 'with unknown user' do
+ it 'does not raise an error' do
+ expect { subject.perform(non_existing_record_id, hook.id) }.not_to raise_error
+
+ expect(WebHook.count).to eq(2)
+ end
+ end
+ end
+ end
+end
diff --git a/tmp/feature_flags/.gitkeep b/tmp/feature_flags/.gitkeep
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/tmp/feature_flags/.gitkeep
diff --git a/vendor/Dockerfile/Golang-alpine.Dockerfile b/vendor/Dockerfile/Golang-alpine.Dockerfile
index 0287315219b..acea2eb9ace 100644
--- a/vendor/Dockerfile/Golang-alpine.Dockerfile
+++ b/vendor/Dockerfile/Golang-alpine.Dockerfile
@@ -1,4 +1,4 @@
-FROM golang:1.8-alpine AS builder
+FROM golang:1.15-alpine AS builder
WORKDIR /usr/src/app
diff --git a/vendor/Dockerfile/Golang-scratch.Dockerfile b/vendor/Dockerfile/Golang-scratch.Dockerfile
index 9057a2d0e51..e5fd03c9a38 100644
--- a/vendor/Dockerfile/Golang-scratch.Dockerfile
+++ b/vendor/Dockerfile/Golang-scratch.Dockerfile
@@ -1,4 +1,4 @@
-FROM golang:1.8-alpine AS builder
+FROM golang:1.15-alpine AS builder
# We'll likely need to add SSL root certificates
RUN apk --no-cache add ca-certificates
diff --git a/vendor/Dockerfile/Golang.Dockerfile b/vendor/Dockerfile/Golang.Dockerfile
index f9699dff665..bef0fdce065 100644
--- a/vendor/Dockerfile/Golang.Dockerfile
+++ b/vendor/Dockerfile/Golang.Dockerfile
@@ -1,4 +1,4 @@
-FROM golang:1.8 AS builder
+FROM golang:1.15 AS builder
WORKDIR /usr/src/app
diff --git a/vendor/assets/stylesheets/cropper.css b/vendor/assets/stylesheets/cropper.css
deleted file mode 100644
index 8668c7c049a..00000000000
--- a/vendor/assets/stylesheets/cropper.css
+++ /dev/null
@@ -1,379 +0,0 @@
-/*!
- * Cropper v2.3.0
- * https://github.com/fengyuanchen/cropper
- *
- * Copyright (c) 2014-2016 Fengyuan Chen and contributors
- * Released under the MIT license
- *
- * Date: 2016-02-22T02:13:13.332Z
- */
-.cropper-container {
- font-size: 0;
- line-height: 0;
-
- position: relative;
-
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- user-select: none;
-
- direction: ltr !important;
- -ms-touch-action: none;
- touch-action: none;
- -webkit-tap-highlight-color: transparent;
- -webkit-touch-callout: none;
-}
-
-.cropper-container img {
- display: block;
-
- width: 100%;
- min-width: 0 !important;
- max-width: none !important;
- height: 100%;
- min-height: 0 !important;
- max-height: none !important;
-
- image-orientation: 0deg !important;
-}
-
-.cropper-wrap-box,
-.cropper-canvas,
-.cropper-drag-box,
-.cropper-crop-box,
-.cropper-modal {
- position: absolute;
- top: 0;
- right: 0;
- bottom: 0;
- left: 0;
-}
-
-.cropper-wrap-box {
- overflow: hidden;
-}
-
-.cropper-drag-box {
- opacity: 0;
- background-color: #fff;
-
- filter: alpha(opacity=0);
-}
-
-.cropper-modal {
- opacity: .5;
- background-color: #000;
-
- filter: alpha(opacity=50);
-}
-
-.cropper-view-box {
- display: block;
- overflow: hidden;
-
- width: 100%;
- height: 100%;
-
- outline: 1px solid #39f;
- outline-color: rgba(51, 153, 255, .75);
-}
-
-.cropper-dashed {
- position: absolute;
-
- display: block;
-
- opacity: .5;
- border: 0 dashed #eee;
-
- filter: alpha(opacity=50);
-}
-
-.cropper-dashed.dashed-h {
- top: 33.33333%;
- left: 0;
-
- width: 100%;
- height: 33.33333%;
-
- border-top-width: 1px;
- border-bottom-width: 1px;
-}
-
-.cropper-dashed.dashed-v {
- top: 0;
- left: 33.33333%;
-
- width: 33.33333%;
- height: 100%;
-
- border-right-width: 1px;
- border-left-width: 1px;
-}
-
-.cropper-center {
- position: absolute;
- top: 50%;
- left: 50%;
-
- display: block;
-
- width: 0;
- height: 0;
-
- opacity: .75;
-
- filter: alpha(opacity=75);
-}
-
-.cropper-center:before,
-.cropper-center:after {
- position: absolute;
-
- display: block;
-
- content: ' ';
-
- background-color: #eee;
-}
-
-.cropper-center:before {
- top: 0;
- left: -3px;
-
- width: 7px;
- height: 1px;
-}
-
-.cropper-center:after {
- top: -3px;
- left: 0;
-
- width: 1px;
- height: 7px;
-}
-
-.cropper-face,
-.cropper-line,
-.cropper-point {
- position: absolute;
-
- display: block;
-
- width: 100%;
- height: 100%;
-
- opacity: .1;
-
- filter: alpha(opacity=10);
-}
-
-.cropper-face {
- top: 0;
- left: 0;
-
- background-color: #fff;
-}
-
-.cropper-line {
- background-color: #39f;
-}
-
-.cropper-line.line-e {
- top: 0;
- right: -3px;
-
- width: 5px;
-
- cursor: e-resize;
-}
-
-.cropper-line.line-n {
- top: -3px;
- left: 0;
-
- height: 5px;
-
- cursor: n-resize;
-}
-
-.cropper-line.line-w {
- top: 0;
- left: -3px;
-
- width: 5px;
-
- cursor: w-resize;
-}
-
-.cropper-line.line-s {
- bottom: -3px;
- left: 0;
-
- height: 5px;
-
- cursor: s-resize;
-}
-
-.cropper-point {
- width: 5px;
- height: 5px;
-
- opacity: .75;
- background-color: #39f;
-
- filter: alpha(opacity=75);
-}
-
-.cropper-point.point-e {
- top: 50%;
- right: -3px;
-
- margin-top: -3px;
-
- cursor: e-resize;
-}
-
-.cropper-point.point-n {
- top: -3px;
- left: 50%;
-
- margin-left: -3px;
-
- cursor: n-resize;
-}
-
-.cropper-point.point-w {
- top: 50%;
- left: -3px;
-
- margin-top: -3px;
-
- cursor: w-resize;
-}
-
-.cropper-point.point-s {
- bottom: -3px;
- left: 50%;
-
- margin-left: -3px;
-
- cursor: s-resize;
-}
-
-.cropper-point.point-ne {
- top: -3px;
- right: -3px;
-
- cursor: ne-resize;
-}
-
-.cropper-point.point-nw {
- top: -3px;
- left: -3px;
-
- cursor: nw-resize;
-}
-
-.cropper-point.point-sw {
- bottom: -3px;
- left: -3px;
-
- cursor: sw-resize;
-}
-
-.cropper-point.point-se {
- right: -3px;
- bottom: -3px;
-
- width: 20px;
- height: 20px;
-
- cursor: se-resize;
-
- opacity: 1;
-
- filter: alpha(opacity=100);
-}
-
-.cropper-point.point-se:before {
- position: absolute;
- right: -50%;
- bottom: -50%;
-
- display: block;
-
- width: 200%;
- height: 200%;
-
- content: ' ';
-
- opacity: 0;
- background-color: #39f;
-
- filter: alpha(opacity=0);
-}
-
-@media (min-width: 768px) {
- .cropper-point.point-se {
- width: 15px;
- height: 15px;
- }
-}
-
-@media (min-width: 992px) {
- .cropper-point.point-se {
- width: 10px;
- height: 10px;
- }
-}
-
-@media (min-width: 1200px) {
- .cropper-point.point-se {
- width: 5px;
- height: 5px;
-
- opacity: .75;
-
- filter: alpha(opacity=75);
- }
-}
-
-.cropper-invisible {
- opacity: 0;
-
- filter: alpha(opacity=0);
-}
-
-.cropper-bg {
- background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAAA3NCSVQICAjb4U/gAAAABlBMVEXMzMz////TjRV2AAAACXBIWXMAAArrAAAK6wGCiw1aAAAAHHRFWHRTb2Z0d2FyZQBBZG9iZSBGaXJld29ya3MgQ1M26LyyjAAAABFJREFUCJlj+M/AgBVhF/0PAH6/D/HkDxOGAAAAAElFTkSuQmCC');
-}
-
-.cropper-hide {
- position: absolute;
-
- display: block;
-
- width: 0;
- height: 0;
-}
-
-.cropper-hidden {
- display: none !important;
-}
-
-.cropper-move {
- cursor: move;
-}
-
-.cropper-crop {
- cursor: crosshair;
-}
-
-.cropper-disabled .cropper-drag-box,
-.cropper-disabled .cropper-face,
-.cropper-disabled .cropper-line,
-.cropper-disabled .cropper-point {
- cursor: not-allowed;
-}
diff --git a/vendor/languages.yml b/vendor/languages.yml
index a6edb0415b2..5e7a955b1bb 100755
--- a/vendor/languages.yml
+++ b/vendor/languages.yml
@@ -1,7 +1,8 @@
-# Extracted from https://github.com/github/linguist/blob/master/lib/linguist/languages.yml
-
# Defines all Languages known to GitHub.
#
+# fs_name - Optional field. Only necessary as a replacement for the sample directory name if the
+# language name is not a valid filename under the Windows filesystem (e.g., if it
+# contains an asterisk).
# type - Either data, programming, markup, prose, or nil
# aliases - An Array of additional aliases (implicitly
# includes name.downcase)
@@ -22,7 +23,7 @@
# language_id - Integer used as a language-name-independent indexed field so that we can rename
# languages in Linguist without reindexing all the code on GitHub. Must not be
# changed for existing languages without the explicit permission of GitHub staff.
-# color - CSS hex color to represent the language. Only used if type is "programming" or "prose".
+# color - CSS hex color to represent the language. Only used if type is "programming" or "markup".
# tm_scope - The TextMate scope that represents this programming
# language. This should match one of the scopes listed in
# the grammars.yml file. Use "none" if there is no grammar
@@ -45,11 +46,19 @@
tm_scope: source.bsl
ace_mode: text
language_id: 0
+4D:
+ type: programming
+ extensions:
+ - ".4dm"
+ tm_scope: source.4dm
+ ace_mode: text
+ language_id: 577529595
ABAP:
type: programming
color: "#E8274B"
extensions:
- ".abap"
+ tm_scope: source.abap
ace_mode: abap
language_id: 1
ABNF:
@@ -72,6 +81,14 @@ AGS Script:
codemirror_mode: clike
codemirror_mime_type: text/x-c++src
language_id: 2
+AL Code:
+ type: programming
+ color: "#3AA2B5"
+ extensions:
+ - ".al"
+ tm_scope: source.al
+ ace_mode: text
+ language_id: 658971832
AMPL:
type: programming
color: "#E6EFBB"
@@ -86,6 +103,7 @@ ANTLR:
color: "#9DC3FF"
extensions:
- ".g4"
+ tm_scope: source.antlr
ace_mode: text
language_id: 4
API Blueprint:
@@ -111,6 +129,14 @@ APL:
codemirror_mode: apl
codemirror_mime_type: text/apl
language_id: 6
+ASL:
+ type: programming
+ ace_mode: text
+ extensions:
+ - ".asl"
+ - ".dsl"
+ tm_scope: source.asl
+ language_id: 124996147
ASN.1:
type: data
extensions:
@@ -121,15 +147,14 @@ ASN.1:
codemirror_mode: asn.1
codemirror_mime_type: text/x-ttcn-asn
language_id: 7
-ASP:
+ASP.NET:
type: programming
- color: "#6a40fd"
tm_scope: text.html.asp
+ color: "#9400ff"
aliases:
- aspx
- aspx-vb
extensions:
- - ".asp"
- ".asax"
- ".ascx"
- ".ashx"
@@ -139,7 +164,7 @@ ASP:
ace_mode: text
codemirror_mode: htmlembedded
codemirror_mime_type: application/x-aspx
- language_id: 8
+ language_id: 564186416
ATS:
type: programming
color: "#1ac620"
@@ -174,6 +199,7 @@ Ada:
aliases:
- ada95
- ada2005
+ tm_scope: source.ada
ace_mode: ada
language_id: 11
Adobe Font Metrics:
@@ -193,6 +219,7 @@ Agda:
color: "#315665"
extensions:
- ".agda"
+ tm_scope: source.agda
ace_mode: text
language_id: 12
Alloy:
@@ -200,6 +227,7 @@ Alloy:
color: "#64C800"
extensions:
- ".als"
+ tm_scope: source.alloy
ace_mode: text
language_id: 13
Alpine Abuild:
@@ -215,6 +243,18 @@ Alpine Abuild:
codemirror_mode: shell
codemirror_mime_type: text/x-sh
language_id: 14
+Altium Designer:
+ type: data
+ aliases:
+ - altium
+ extensions:
+ - ".OutJob"
+ - ".PcbDoc"
+ - ".PrjPCB"
+ - ".SchDoc"
+ tm_scope: source.ini
+ ace_mode: ini
+ language_id: 187772328
AngelScript:
type: programming
color: "#C7D7DC"
@@ -253,6 +293,7 @@ ApacheConf:
language_id: 16
Apex:
type: programming
+ color: "#1797c0"
extensions:
- ".cls"
tm_scope: source.java
@@ -277,6 +318,7 @@ AppleScript:
- ".scpt"
interpreters:
- osascript
+ tm_scope: source.applescript
ace_mode: applescript
color: "#101F1F"
language_id: 19
@@ -315,11 +357,24 @@ Assembly:
extensions:
- ".asm"
- ".a51"
+ - ".i"
- ".inc"
- ".nasm"
tm_scope: source.assembly
ace_mode: assembly_x86
language_id: 24
+Asymptote:
+ type: programming
+ color: "#ff0000"
+ extensions:
+ - ".asy"
+ interpreters:
+ - asy
+ tm_scope: source.c++
+ ace_mode: c_cpp
+ codemirror_mode: clike
+ codemirror_mime_type: text/x-kotlin
+ language_id: 591605007
Augeas:
type: programming
extensions:
@@ -350,6 +405,13 @@ AutoIt:
tm_scope: source.autoit
ace_mode: autohotkey
language_id: 27
+Avro IDL:
+ type: data
+ extensions:
+ - ".avdl"
+ tm_scope: source.avro
+ ace_mode: text
+ language_id: 785497837
Awk:
type: programming
extensions:
@@ -363,6 +425,7 @@ Awk:
- gawk
- mawk
- nawk
+ tm_scope: source.awk
ace_mode: text
language_id: 28
Ballerina:
@@ -391,12 +454,24 @@ Befunge:
type: programming
extensions:
- ".befunge"
+ tm_scope: source.befunge
ace_mode: text
language_id: 30
+BibTeX:
+ type: markup
+ group: TeX
+ extensions:
+ - ".bib"
+ - ".bibtex"
+ tm_scope: text.bibtex
+ ace_mode: tex
+ codemirror_mode: stex
+ codemirror_mime_type: text/x-stex
+ language_id: 982188347
Bison:
type: programming
group: Yacc
- tm_scope: source.bison
+ tm_scope: source.yacc
extensions:
- ".bison"
ace_mode: text
@@ -410,7 +485,7 @@ BitBake:
language_id: 32
Blade:
type: markup
- group: HTML
+ color: "#f7523f"
extensions:
- ".blade"
- ".blade.php"
@@ -437,6 +512,7 @@ BlitzMax:
- ".bmx"
aliases:
- bmax
+ tm_scope: source.blitzmax
ace_mode: text
language_id: 35
Bluespec:
@@ -472,12 +548,6 @@ Brightscript:
tm_scope: source.brightscript
ace_mode: text
language_id: 39
-Bro:
- type: programming
- extensions:
- - ".bro"
- ace_mode: text
- language_id: 40
C:
type: programming
color: "#555555"
@@ -488,6 +558,7 @@ C:
- ".idc"
interpreters:
- tcc
+ tm_scope: source.c
ace_mode: c_cpp
codemirror_mode: clike
codemirror_mime_type: text/x-csrc
@@ -504,11 +575,12 @@ C#:
extensions:
- ".cs"
- ".cake"
- - ".cshtml"
- ".csx"
+ - ".linq"
language_id: 42
C++:
type: programming
+ tm_scope: source.c++
ace_mode: c_cpp
codemirror_mode: clike
codemirror_mime_type: text/x-c++src
@@ -567,6 +639,7 @@ CMake:
- ".cmake.in"
filenames:
- CMakeLists.txt
+ tm_scope: source.cmake
ace_mode: text
codemirror_mode: cmake
codemirror_mime_type: text/x-cmake
@@ -579,6 +652,7 @@ COBOL:
- ".ccp"
- ".cobol"
- ".cpy"
+ tm_scope: source.cobol
ace_mode: cobol
codemirror_mode: cobol
codemirror_mime_type: text/x-cobol
@@ -594,12 +668,11 @@ COLLADA:
language_id: 49
CSON:
type: data
- group: CoffeeScript
+ color: "#244776"
tm_scope: source.coffee
ace_mode: coffee
codemirror_mode: coffeescript
codemirror_mime_type: text/x-coffeescript
- searchable: false
extensions:
- ".cson"
language_id: 424
@@ -627,6 +700,20 @@ CWeb:
tm_scope: none
ace_mode: text
language_id: 657332628
+Cabal Config:
+ type: data
+ aliases:
+ - Cabal
+ extensions:
+ - ".cabal"
+ filenames:
+ - cabal.config
+ - cabal.project
+ ace_mode: haskell
+ codemirror_mode: haskell
+ codemirror_mime_type: text/x-haskell
+ tm_scope: source.cabal
+ language_id: 677095381
Cap'n Proto:
type: programming
tm_scope: source.capnp
@@ -658,6 +745,7 @@ Chapel:
- chpl
extensions:
- ".chpl"
+ tm_scope: source.chapel
ace_mode: text
language_id: 55
Charity:
@@ -679,6 +767,7 @@ ChucK:
Cirru:
type: programming
color: "#ccccff"
+ tm_scope: source.cirru
ace_mode: cirru
extensions:
- ".cirru"
@@ -691,6 +780,16 @@ Clarion:
- ".clw"
tm_scope: source.clarion
language_id: 59
+Classic ASP:
+ type: programming
+ color: "#6a40fd"
+ tm_scope: text.html.asp
+ aliases:
+ - asp
+ extensions:
+ - ".asp"
+ ace_mode: text
+ language_id: 8
Clean:
type: programming
color: "#3F85AF"
@@ -710,6 +809,7 @@ Click:
language_id: 61
Clojure:
type: programming
+ tm_scope: source.clojure
ace_mode: clojure
codemirror_mode: clojure
codemirror_mime_type: text/x-clojure
@@ -759,6 +859,16 @@ CoNLL-U:
- CoNLL
- CoNLL-X
language_id: 421026389
+CodeQL:
+ type: programming
+ extensions:
+ - ".ql"
+ - ".qll"
+ tm_scope: source.ql
+ ace_mode: text
+ language_id: 424259634
+ aliases:
+ - ql
CoffeeScript:
type: programming
tm_scope: source.coffee
@@ -868,6 +978,7 @@ Coq:
extensions:
- ".coq"
- ".v"
+ tm_scope: source.coq
ace_mode: text
language_id: 69
Cpp-ObjDump:
@@ -893,7 +1004,7 @@ Creole:
language_id: 71
Crystal:
type: programming
- color: "#776791"
+ color: "#000100"
extensions:
- ".cr"
ace_mode: ruby
@@ -960,6 +1071,7 @@ Cython:
- ".pxi"
aliases:
- pyrex
+ tm_scope: source.cython
ace_mode: text
codemirror_mode: python
codemirror_mime_type: text/x-cython
@@ -970,6 +1082,7 @@ D:
extensions:
- ".d"
- ".di"
+ tm_scope: source.d
ace_mode: d
codemirror_mode: d
codemirror_mime_type: text/x-d
@@ -1021,6 +1134,16 @@ DTrace:
codemirror_mode: clike
codemirror_mime_type: text/x-csrc
language_id: 85
+Dafny:
+ type: programming
+ color: "#FFEC25"
+ extensions:
+ - ".dfy"
+ interpreters:
+ - dafny
+ tm_scope: text.dfy.dafny
+ ace_mode: text
+ language_id: 969323346
Darcs Patch:
type: data
aliases:
@@ -1038,6 +1161,7 @@ Dart:
- ".dart"
interpreters:
- dart
+ tm_scope: source.dart
ace_mode: dart
codemirror_mode: dart
codemirror_mime_type: application/dart
@@ -1050,6 +1174,16 @@ DataWeave:
ace_mode: text
tm_scope: source.data-weave
language_id: 974514097
+Dhall:
+ type: programming
+ color: "#dfafff"
+ extensions:
+ - ".dhall"
+ tm_scope: source.haskell
+ ace_mode: haskell
+ codemirror_mode: haskell
+ codemirror_mime_type: text/x-haskell
+ language_id: 793969321
Diff:
type: data
extensions:
@@ -1062,9 +1196,16 @@ Diff:
codemirror_mode: diff
codemirror_mime_type: text/x-diff
language_id: 88
+DirectX 3D File:
+ type: data
+ extensions:
+ - ".x"
+ ace_mode: text
+ tm_scope: none
+ language_id: 201049282
Dockerfile:
type: programming
- color: "#0db7ed"
+ color: "#384d54"
tm_scope: source.dockerfile
extensions:
- ".dockerfile"
@@ -1090,6 +1231,7 @@ Dylan:
- ".dyl"
- ".intr"
- ".lid"
+ tm_scope: source.dylan
ace_mode: text
codemirror_mode: dylan
codemirror_mime_type: text/x-dylan
@@ -1137,9 +1279,19 @@ EJS:
group: HTML
extensions:
- ".ejs"
+ - ".ect"
+ - ".jst"
tm_scope: text.html.js
ace_mode: ejs
language_id: 95
+EML:
+ type: data
+ extensions:
+ - ".eml"
+ - ".mbox"
+ tm_scope: text.eml.basic
+ ace_mode: text
+ language_id: 529653389
EQ:
type: programming
color: "#a78649"
@@ -1180,20 +1332,33 @@ Ecere Projects:
codemirror_mode: javascript
codemirror_mime_type: application/json
language_id: 98
+EditorConfig:
+ type: data
+ group: INI
+ filenames:
+ - ".editorconfig"
+ aliases:
+ - editor-config
+ ace_mode: ini
+ codemirror_mode: properties
+ codemirror_mime_type: text/x-properties
+ tm_scope: source.editorconfig
+ language_id: 96139566
Edje Data Collection:
type: data
extensions:
- ".edc"
- tm_scope: source.json
- ace_mode: json
- codemirror_mode: javascript
- codemirror_mime_type: application/json
+ tm_scope: source.c++
+ ace_mode: c_cpp
+ codemirror_mode: clike
+ codemirror_mime_type: text/x-c++src
language_id: 342840478
Eiffel:
type: programming
- color: "#946d57"
+ color: "#4d6977"
extensions:
- ".e"
+ tm_scope: source.eiffel
ace_mode: eiffel
codemirror_mode: eiffel
codemirror_mime_type: text/x-eiffel
@@ -1204,6 +1369,7 @@ Elixir:
extensions:
- ".ex"
- ".exs"
+ tm_scope: source.elixir
ace_mode: elixir
filenames:
- mix.lock
@@ -1273,6 +1439,7 @@ Erlang:
- rebar.config
- rebar.config.lock
- rebar.lock
+ tm_scope: source.erlang
ace_mode: erlang
codemirror_mode: erlang
codemirror_mime_type: text/x-erlang
@@ -1293,6 +1460,26 @@ F#:
codemirror_mode: mllike
codemirror_mime_type: text/x-fsharp
language_id: 105
+F*:
+ fs_name: Fstar
+ type: programming
+ color: "#572e30"
+ aliases:
+ - fstar
+ extensions:
+ - ".fst"
+ tm_scope: source.fstar
+ ace_mode: text
+ language_id: 336943375
+FIGlet Font:
+ type: data
+ aliases:
+ - FIGfont
+ extensions:
+ - ".flf"
+ tm_scope: source.figfont
+ ace_mode: text
+ language_id: 686129783
FLUX:
type: programming
color: "#88ccff"
@@ -1310,6 +1497,7 @@ Factor:
filenames:
- ".factor-boot-rc"
- ".factor-rc"
+ tm_scope: source.factor
ace_mode: text
codemirror_mode: factor
codemirror_mime_type: text/x-factor
@@ -1322,6 +1510,7 @@ Fancy:
- ".fancypack"
filenames:
- Fakefile
+ tm_scope: source.fancy
ace_mode: text
language_id: 109
Fantom:
@@ -1332,6 +1521,14 @@ Fantom:
tm_scope: source.fan
ace_mode: text
language_id: 110
+Faust:
+ type: programming
+ color: "#c37240"
+ extensions:
+ - ".dsp"
+ tm_scope: source.faust
+ ace_mode: text
+ language_id: 622529198
Filebench WML:
type: programming
extensions:
@@ -1367,27 +1564,38 @@ Forth:
- ".fr"
- ".frt"
- ".fs"
+ tm_scope: source.forth
ace_mode: forth
codemirror_mode: forth
codemirror_mime_type: text/x-forth
language_id: 114
Fortran:
+ group: Fortran
type: programming
color: "#4d41b1"
extensions:
- - ".f90"
- ".f"
- - ".f03"
- - ".f08"
- ".f77"
- - ".f95"
- ".for"
- ".fpp"
- tm_scope: source.fortran.modern
+ tm_scope: source.fortran
ace_mode: text
codemirror_mode: fortran
codemirror_mime_type: text/x-fortran
language_id: 107
+Fortran Free Form:
+ group: Fortran
+ type: programming
+ extensions:
+ - ".f90"
+ - ".f03"
+ - ".f08"
+ - ".f95"
+ tm_scope: source.fortran.modern
+ ace_mode: text
+ codemirror_mode: fortran
+ codemirror_mime_type: text/x-fortran
+ language_id: 761352333
FreeMarker:
type: programming
color: "#0050b2"
@@ -1406,15 +1614,33 @@ Frege:
tm_scope: source.haskell
ace_mode: haskell
language_id: 116
+Futhark:
+ type: programming
+ color: "#5f021f"
+ extensions:
+ - ".fut"
+ tm_scope: source.futhark
+ ace_mode: text
+ language_id: 97358117
G-code:
- type: data
+ type: programming
+ color: "#D08CF2"
extensions:
- ".g"
+ - ".cnc"
- ".gco"
- ".gcode"
tm_scope: source.gcode
ace_mode: gcode
language_id: 117
+GAML:
+ type: programming
+ color: "#FFC766"
+ extensions:
+ - ".gaml"
+ tm_scope: none
+ ace_mode: text
+ language_id: 290345951
GAMS:
type: programming
extensions:
@@ -1458,6 +1684,13 @@ GDScript:
tm_scope: source.gdscript
ace_mode: text
language_id: 123
+GEDCOM:
+ type: data
+ ace_mode: text
+ extensions:
+ - ".ged"
+ tm_scope: source.gedcom
+ language_id: 459577965
GLSL:
type: programming
extensions:
@@ -1470,7 +1703,9 @@ GLSL:
- ".fshader"
- ".geo"
- ".geom"
+ - ".glslf"
- ".glslv"
+ - ".gs"
- ".gshader"
- ".shader"
- ".tesc"
@@ -1479,6 +1714,7 @@ GLSL:
- ".vrx"
- ".vsh"
- ".vshader"
+ tm_scope: source.glsl
ace_mode: glsl
language_id: 124
GN:
@@ -1497,7 +1733,7 @@ GN:
language_id: 302957008
Game Maker Language:
type: programming
- color: "#8fb200"
+ color: "#71b417"
extensions:
- ".gml"
tm_scope: source.c++
@@ -1556,12 +1792,14 @@ Gerber Image:
- ".gbp"
- ".gbs"
- ".gko"
+ - ".gml"
- ".gpb"
- ".gpt"
- ".gtl"
- ".gto"
- ".gtp"
- ".gts"
+ - ".sol"
interpreters:
- gerbv
- gerbview
@@ -1583,12 +1821,41 @@ Gherkin:
type: programming
extensions:
- ".feature"
+ - ".story"
tm_scope: text.gherkin.feature
aliases:
- cucumber
ace_mode: text
color: "#5B2063"
language_id: 76
+Git Attributes:
+ type: data
+ group: INI
+ aliases:
+ - gitattributes
+ filenames:
+ - ".gitattributes"
+ tm_scope: source.gitattributes
+ ace_mode: gitignore
+ codemirror_mode: shell
+ codemirror_mime_type: text/x-sh
+ language_id: 956324166
+Git Config:
+ type: data
+ group: INI
+ aliases:
+ - gitconfig
+ - gitmodules
+ extensions:
+ - ".gitconfig"
+ filenames:
+ - ".gitconfig"
+ - ".gitmodules"
+ ace_mode: ini
+ codemirror_mode: properties
+ codemirror_mime_type: text/x-properties
+ tm_scope: source.gitconfig
+ language_id: 807968997
Glyph:
type: programming
color: "#c1ac7f"
@@ -1599,6 +1866,13 @@ Glyph:
codemirror_mode: tcl
codemirror_mime_type: text/x-tcl
language_id: 130
+Glyph Bitmap Distribution Format:
+ type: data
+ extensions:
+ - ".bdf"
+ tm_scope: source.bdf
+ ace_mode: text
+ language_id: 997665271
Gnuplot:
type: programming
color: "#f0a9f0"
@@ -1606,19 +1880,22 @@ Gnuplot:
- ".gp"
- ".gnu"
- ".gnuplot"
+ - ".p"
- ".plot"
- ".plt"
interpreters:
- gnuplot
+ tm_scope: source.gnuplot
ace_mode: text
language_id: 131
Go:
type: programming
- color: "#375eab"
+ color: "#00ADD8"
aliases:
- golang
extensions:
- ".go"
+ tm_scope: source.go
ace_mode: golang
codemirror_mode: go
codemirror_mime_type: text/x-go
@@ -1660,12 +1937,10 @@ Grammatical Framework:
type: programming
aliases:
- gf
- wrap: false
extensions:
- ".gf"
- searchable: true
- color: "#79aa7a"
- tm_scope: source.haskell
+ color: "#ff0000"
+ tm_scope: source.gf
ace_mode: haskell
codemirror_mode: haskell
codemirror_mime_type: text/x-haskell
@@ -1682,6 +1957,7 @@ GraphQL:
extensions:
- ".graphql"
- ".gql"
+ - ".graphqls"
tm_scope: source.graphql
ace_mode: text
language_id: 139
@@ -1695,6 +1971,7 @@ Graphviz (DOT):
language_id: 140
Groovy:
type: programming
+ tm_scope: source.groovy
ace_mode: groovy
codemirror_mode: groovy
codemirror_mime_type: text/x-groovy
@@ -1722,12 +1999,25 @@ Groovy Server Pages:
codemirror_mode: htmlembedded
codemirror_mime_type: application/x-jsp
language_id: 143
+HAProxy:
+ type: data
+ extensions:
+ - ".cfg"
+ filenames:
+ - haproxy.cfg
+ tm_scope: source.haproxy-config
+ ace_mode: text
+ language_id: 366607477
HCL:
type: programming
extensions:
- ".hcl"
+ - ".nomad"
- ".tf"
- ".tfvars"
+ - ".workflow"
+ aliases:
+ - terraform
ace_mode: ruby
codemirror_mode: ruby
codemirror_mime_type: text/x-ruby
@@ -1768,8 +2058,8 @@ HTML+Django:
group: HTML
extensions:
- ".jinja"
+ - ".j2"
- ".jinja2"
- - ".mustache"
- ".njk"
aliases:
- django
@@ -1812,9 +2102,12 @@ HTML+ERB:
group: HTML
aliases:
- erb
+ - rhtml
+ - html+ruby
extensions:
- ".erb"
- ".erb.deface"
+ - ".rhtml"
ace_mode: text
codemirror_mode: htmlembedded
codemirror_mime_type: application/x-erb
@@ -1829,6 +2122,19 @@ HTML+PHP:
codemirror_mode: php
codemirror_mime_type: application/x-httpd-php
language_id: 151
+HTML+Razor:
+ type: markup
+ tm_scope: text.html.cshtml
+ group: HTML
+ aliases:
+ - razor
+ extensions:
+ - ".cshtml"
+ - ".razor"
+ ace_mode: razor
+ codemirror_mode: htmlmixed
+ codemirror_mime_type: text/html
+ language_id: 479039817
HTTP:
type: data
extensions:
@@ -1851,24 +2157,27 @@ Hack:
codemirror_mode: php
codemirror_mime_type: application/x-httpd-php
extensions:
+ - ".hack"
- ".hh"
+ - ".hhi"
- ".php"
- tm_scope: text.html.php
+ tm_scope: source.hack
color: "#878787"
language_id: 153
Haml:
- group: HTML
type: markup
+ color: "#ece2a9"
extensions:
- ".haml"
- ".haml.deface"
+ tm_scope: text.haml
ace_mode: haml
codemirror_mode: haml
codemirror_mime_type: text/x-haml
language_id: 154
Handlebars:
type: markup
- group: HTML
+ color: "#f7931e"
aliases:
- hbs
- htmlbars
@@ -1891,9 +2200,11 @@ Haskell:
color: "#5e5086"
extensions:
- ".hs"
+ - ".hs-boot"
- ".hsc"
interpreters:
- runhaskell
+ tm_scope: source.haskell
ace_mode: haskell
codemirror_mode: haskell
codemirror_mime_type: text/x-haskell
@@ -1913,10 +2224,21 @@ HiveQL:
type: programming
extensions:
- ".q"
+ - ".hql"
color: "#dce200"
tm_scope: source.hql
ace_mode: sql
language_id: 931814087
+HolyC:
+ type: programming
+ color: "#ffefaf"
+ extensions:
+ - ".hc"
+ tm_scope: source.hc
+ ace_mode: c_cpp
+ codemirror_mode: clike
+ codemirror_mime_type: text/x-csrc
+ language_id: 928121743
Hy:
type: programming
ace_mode: text
@@ -1924,10 +2246,10 @@ Hy:
extensions:
- ".hy"
interpreters:
- - "hy"
+ - hy
aliases:
- hylang
- tm_scope: none
+ tm_scope: source.hy
language_id: 159
HyPhy:
type: programming
@@ -1942,18 +2264,20 @@ IDL:
extensions:
- ".pro"
- ".dlm"
+ tm_scope: source.idl
ace_mode: text
codemirror_mode: idl
codemirror_mime_type: text/x-idl
language_id: 161
IGOR Pro:
type: programming
+ color: "#0000cc"
extensions:
- ".ipf"
aliases:
- igor
- igorpro
- tm_scope: none
+ tm_scope: source.igor
ace_mode: text
language_id: 162
INI:
@@ -1961,12 +2285,12 @@ INI:
extensions:
- ".ini"
- ".cfg"
+ - ".dof"
+ - ".lektorproject"
- ".prefs"
- ".pro"
- ".properties"
filenames:
- - ".editorconfig"
- - ".gitconfig"
- buildozer.spec
tm_scope: source.ini
aliases:
@@ -1997,6 +2321,36 @@ Idris:
ace_mode: text
tm_scope: source.idris
language_id: 165
+Ignore List:
+ type: data
+ group: INI
+ aliases:
+ - ignore
+ - gitignore
+ - git-ignore
+ extensions:
+ - ".gitignore"
+ filenames:
+ - ".atomignore"
+ - ".babelignore"
+ - ".bzrignore"
+ - ".coffeelintignore"
+ - ".cvsignore"
+ - ".dockerignore"
+ - ".eslintignore"
+ - ".gitignore"
+ - ".nodemonignore"
+ - ".npmignore"
+ - ".prettierignore"
+ - ".stylelintignore"
+ - ".vscodeignore"
+ - gitignore-global
+ - gitignore_global
+ ace_mode: gitignore
+ tm_scope: source.gitignore
+ codemirror_mode: shell
+ codemirror_mime_type: text/x-sh
+ language_id: 74444240
Inform 7:
type: programming
wrap: true
@@ -2013,7 +2367,8 @@ Inno Setup:
type: programming
extensions:
- ".iss"
- tm_scope: none
+ - ".isl"
+ tm_scope: source.inno
ace_mode: text
language_id: 167
Io:
@@ -2023,6 +2378,7 @@ Io:
- ".io"
interpreters:
- io
+ tm_scope: source.io
ace_mode: io
language_id: 168
Ioke:
@@ -2032,6 +2388,7 @@ Ioke:
- ".ik"
interpreters:
- ioke
+ tm_scope: source.ioke
ace_mode: text
language_id: 169
Isabelle:
@@ -2072,7 +2429,6 @@ JFlex:
JSON:
type: data
tm_scope: source.json
- group: JavaScript
ace_mode: json
codemirror_mode: javascript
codemirror_mime_type: application/json
@@ -2082,18 +2438,24 @@ JSON:
- ".avsc"
- ".geojson"
- ".gltf"
+ - ".har"
+ - ".ice"
- ".JSON-tmLanguage"
- ".jsonl"
+ - ".mcmeta"
- ".tfstate"
- ".tfstate.backup"
- ".topojson"
- ".webapp"
- ".webmanifest"
+ - ".yy"
+ - ".yyp"
filenames:
- ".arcconfig"
- ".htmlhintrc"
- ".tern-config"
- ".tern-project"
+ - ".watchmanconfig"
- composer.lock
- mcmod.info
language_id: 174
@@ -2107,6 +2469,7 @@ JSON with Comments:
aliases:
- jsonc
extensions:
+ - ".jsonc"
- ".sublime-build"
- ".sublime-commands"
- ".sublime-completions"
@@ -2126,7 +2489,10 @@ JSON with Comments:
- ".jscsrc"
- ".jshintrc"
- ".jslintrc"
+ - jsconfig.json
+ - language-configuration.json
- tsconfig.json
+ - tslint.json
language_id: 423
JSON5:
type: data
@@ -2139,11 +2505,12 @@ JSON5:
language_id: 175
JSONLD:
type: data
- group: JavaScript
- ace_mode: javascript
extensions:
- ".jsonld"
tm_scope: source.js
+ ace_mode: javascript
+ codemirror_mode: javascript
+ codemirror_mime_type: application/json
language_id: 176
JSONiq:
color: "#40d47e"
@@ -2174,6 +2541,7 @@ Jasmin:
language_id: 180
Java:
type: programming
+ tm_scope: source.java
ace_mode: java
codemirror_mode: clike
codemirror_mime_type: text/x-java
@@ -2181,6 +2549,15 @@ Java:
extensions:
- ".java"
language_id: 181
+Java Properties:
+ type: data
+ extensions:
+ - ".properties"
+ tm_scope: source.java-properties
+ ace_mode: properties
+ codemirror_mode: properties
+ codemirror_mime_type: text/x-properties
+ language_id: 519377561
Java Server Pages:
type: programming
group: Java
@@ -2207,6 +2584,7 @@ JavaScript:
- ".js"
- "._js"
- ".bones"
+ - ".cjs"
- ".es"
- ".es6"
- ".frag"
@@ -2227,8 +2605,27 @@ JavaScript:
filenames:
- Jakefile
interpreters:
+ - chakra
+ - d8
+ - gjs
+ - js
- node
+ - nodejs
+ - qjs
+ - rhino
+ - v8
+ - v8-shell
language_id: 183
+JavaScript+ERB:
+ type: programming
+ tm_scope: source.js
+ group: JavaScript
+ extensions:
+ - ".js.erb"
+ ace_mode: javascript
+ codemirror_mode: javascript
+ codemirror_mime_type: application/javascript
+ language_id: 914318960
Jison:
type: programming
group: Yacc
@@ -2256,6 +2653,15 @@ Jolie:
ace_mode: text
tm_scope: source.jolie
language_id: 998078858
+Jsonnet:
+ color: "#0064bd"
+ type: programming
+ ace_mode: text
+ extensions:
+ - ".jsonnet"
+ - ".libsonnet"
+ tm_scope: source.jsonnet
+ language_id: 664885656
Julia:
type: programming
extensions:
@@ -2263,6 +2669,7 @@ Julia:
interpreters:
- julia
color: "#a270ba"
+ tm_scope: source.julia
ace_mode: julia
codemirror_mode: julia
codemirror_mime_type: text/x-julia
@@ -2289,6 +2696,18 @@ KRL:
tm_scope: none
ace_mode: text
language_id: 186
+Kaitai Struct:
+ type: programming
+ aliases:
+ - ksy
+ ace_mode: yaml
+ codemirror_mode: yaml
+ codemirror_mime_type: text/x-yaml
+ color: "#773b37"
+ extensions:
+ - ".ksy"
+ tm_scope: source.yaml
+ language_id: 818804755
KiCad Layout:
type: data
aliases:
@@ -2355,6 +2774,7 @@ LLVM:
type: programming
extensions:
- ".ll"
+ tm_scope: source.llvm
ace_mode: text
color: "#185619"
language_id: 191
@@ -2368,6 +2788,7 @@ LOLCODE:
language_id: 192
LSL:
type: programming
+ tm_scope: source.lsl
ace_mode: lsl
extensions:
- ".lsl"
@@ -2376,6 +2797,15 @@ LSL:
- lsl
color: "#3d9970"
language_id: 193
+LTspice Symbol:
+ type: data
+ extensions:
+ - ".asy"
+ tm_scope: source.ltspice.symbol
+ ace_mode: text
+ codemirror_mode: spreadsheet
+ codemirror_mime_type: text/x-spreadsheet
+ language_id: 1013566805
LabVIEW:
type: programming
extensions:
@@ -2393,7 +2823,6 @@ Lasso:
- ".las"
- ".lasso8"
- ".lasso9"
- - ".ldml"
tm_scope: file.lasso
aliases:
- lassoscript
@@ -2401,7 +2830,7 @@ Lasso:
language_id: 195
Latte:
type: markup
- group: HTML
+ color: "#f2a542"
extensions:
- ".latte"
tm_scope: text.html.smarty
@@ -2414,11 +2843,12 @@ Lean:
extensions:
- ".lean"
- ".hlean"
+ tm_scope: source.lean
ace_mode: text
language_id: 197
Less:
type: markup
- group: CSS
+ color: "#1d365d"
extensions:
- ".less"
tm_scope: source.css.less
@@ -2434,7 +2864,10 @@ Lex:
extensions:
- ".l"
- ".lex"
- tm_scope: none
+ filenames:
+ - Lexer.x
+ - lexer.x
+ tm_scope: source.lex
ace_mode: text
language_id: 199
LilyPond:
@@ -2442,6 +2875,7 @@ LilyPond:
extensions:
- ".ly"
- ".ily"
+ tm_scope: source.lilypond
ace_mode: text
language_id: 200
Limbo:
@@ -2495,6 +2929,7 @@ Literate CoffeeScript:
- litcoffee
extensions:
- ".litcoffee"
+ - ".coffee.md"
language_id: 206
Literate Haskell:
type: programming
@@ -2520,6 +2955,7 @@ LiveScript:
- "._ls"
filenames:
- Slakefile
+ tm_scope: source.livescript
ace_mode: livescript
codemirror_mode: livescript
codemirror_mime_type: text/x-livescript
@@ -2538,6 +2974,7 @@ Logtalk:
extensions:
- ".lgt"
- ".logtalk"
+ tm_scope: source.logtalk
ace_mode: text
language_id: 210
LookML:
@@ -2561,6 +2998,7 @@ LoomScript:
language_id: 212
Lua:
type: programming
+ tm_scope: source.lua
ace_mode: lua
codemirror_mode: lua
codemirror_mime_type: text/x-lua
@@ -2572,7 +3010,10 @@ Lua:
- ".p8"
- ".pd_lua"
- ".rbxs"
+ - ".rockspec"
- ".wlua"
+ filenames:
+ - ".luacheckrc"
interpreters:
- lua
language_id: 213
@@ -2592,7 +3033,7 @@ M4:
type: programming
extensions:
- ".m4"
- tm_scope: none
+ tm_scope: source.m4
ace_mode: text
language_id: 215
M4Sugar:
@@ -2604,9 +3045,22 @@ M4Sugar:
- ".m4"
filenames:
- configure.ac
- tm_scope: none
+ tm_scope: source.m4
ace_mode: text
language_id: 216
+MATLAB:
+ type: programming
+ color: "#e16737"
+ aliases:
+ - octave
+ extensions:
+ - ".matlab"
+ - ".m"
+ tm_scope: source.matlab
+ ace_mode: matlab
+ codemirror_mode: octave
+ codemirror_mime_type: text/x-octave
+ language_id: 225
MAXScript:
type: programming
color: "#00a6a6"
@@ -2616,6 +3070,14 @@ MAXScript:
tm_scope: source.maxscript
ace_mode: text
language_id: 217
+MLIR:
+ type: programming
+ color: "#5EC8DB"
+ extensions:
+ - ".mlir"
+ tm_scope: source.mlir
+ ace_mode: text
+ language_id: 448253929
MQL4:
type: programming
color: "#62A8D6"
@@ -2655,6 +3117,18 @@ MUF:
codemirror_mode: forth
codemirror_mime_type: text/x-forth
language_id: 219
+Macaulay2:
+ type: programming
+ extensions:
+ - ".m2"
+ aliases:
+ - m2
+ interpreters:
+ - M2
+ ace_mode: text
+ tm_scope: source.m2
+ color: "#d8ffff"
+ language_id: 34167825
Makefile:
type: programming
color: "#427819"
@@ -2684,6 +3158,7 @@ Makefile:
- mkfile
interpreters:
- make
+ tm_scope: source.makefile
ace_mode: makefile
codemirror_mode: cmake
codemirror_mime_type: text/x-cmake
@@ -2698,6 +3173,7 @@ Mako:
language_id: 221
Markdown:
type: prose
+ color: "#083fa1"
aliases:
- pandoc
ace_mode: markdown
@@ -2709,16 +3185,19 @@ Markdown:
- ".markdown"
- ".mdown"
- ".mdwn"
+ - ".mdx"
- ".mkd"
- ".mkdn"
- ".mkdown"
- ".ronn"
- ".workbook"
+ filenames:
+ - contents.lr
tm_scope: source.gfm
language_id: 222
Marko:
- group: HTML
type: markup
+ color: "#42bff2"
tm_scope: text.marko
extensions:
- ".marko"
@@ -2750,22 +3229,11 @@ Mathematica:
- ".wlt"
aliases:
- mma
+ tm_scope: source.mathematica
ace_mode: text
codemirror_mode: mathematica
codemirror_mime_type: text/x-mathematica
language_id: 224
-Matlab:
- type: programming
- color: "#e16737"
- aliases:
- - octave
- extensions:
- - ".matlab"
- - ".m"
- ace_mode: matlab
- codemirror_mode: octave
- codemirror_mime_type: text/x-octave
- language_id: 225
Maven POM:
type: data
tm_scope: text.xml.pom
@@ -2831,6 +3299,13 @@ Metal:
codemirror_mode: clike
codemirror_mime_type: text/x-c++src
language_id: 230
+Microsoft Developer Studio Project:
+ type: data
+ extensions:
+ - ".dsp"
+ tm_scope: none
+ ace_mode: text
+ language_id: 800983837
MiniD:
type: programming
searchable: false
@@ -2910,8 +3385,44 @@ MoonScript:
- ".moon"
interpreters:
- moon
+ tm_scope: source.moonscript
ace_mode: text
language_id: 238
+Motorola 68K Assembly:
+ type: programming
+ group: Assembly
+ aliases:
+ - m68k
+ extensions:
+ - ".asm"
+ - ".i"
+ - ".inc"
+ - ".s"
+ - ".x68"
+ tm_scope: source.m68k
+ ace_mode: assembly_x86
+ language_id: 477582706
+Muse:
+ type: prose
+ extensions:
+ - ".muse"
+ tm_scope: text.muse
+ ace_mode: text
+ wrap: true
+ language_id: 474864066
+ aliases:
+ - amusewiki
+ - emacs muse
+Mustache:
+ type: markup
+ group: HTML
+ extensions:
+ - ".mustache"
+ tm_scope: text.html.smarty
+ ace_mode: smarty
+ codemirror_mode: smarty
+ codemirror_mime_type: text/x-smarty
+ language_id: 638334590
Myghty:
type: programming
extensions:
@@ -2919,6 +3430,14 @@ Myghty:
tm_scope: none
ace_mode: text
language_id: 239
+NASL:
+ type: programming
+ extensions:
+ - ".nasl"
+ - ".inc"
+ tm_scope: source.nasl
+ ace_mode: text
+ language_id: 171666519
NCL:
type: programming
color: "#28431f"
@@ -2927,6 +3446,16 @@ NCL:
tm_scope: source.ncl
ace_mode: text
language_id: 240
+NEON:
+ type: data
+ extensions:
+ - ".neon"
+ tm_scope: source.neon
+ ace_mode: text
+ aliases:
+ - nette object notation
+ - ne-on
+ language_id: 481192983
NL:
type: data
extensions:
@@ -2934,11 +3463,22 @@ NL:
tm_scope: none
ace_mode: text
language_id: 241
+NPM Config:
+ type: data
+ group: INI
+ aliases:
+ - npmrc
+ filenames:
+ - ".npmrc"
+ tm_scope: source.ini.npmrc
+ ace_mode: text
+ language_id: 685022663
NSIS:
type: programming
extensions:
- ".nsi"
- ".nsh"
+ tm_scope: source.nsis
ace_mode: text
codemirror_mode: nsis
codemirror_mime_type: text/x-nsis
@@ -2957,6 +3497,7 @@ Nemerle:
color: "#3d3c6e"
extensions:
- ".n"
+ tm_scope: source.nemerle
ace_mode: text
language_id: 243
NetLinx:
@@ -3016,6 +3557,7 @@ Nextflow:
Nginx:
type: data
extensions:
+ - ".nginx"
- ".nginxconf"
- ".vhost"
filenames:
@@ -3029,10 +3571,15 @@ Nginx:
language_id: 248
Nim:
type: programming
- color: "#37775b"
+ color: "#ffc200"
extensions:
- ".nim"
+ - ".nim.cfg"
+ - ".nimble"
- ".nimrod"
+ - ".nims"
+ filenames:
+ - nim.cfg
ace_mode: text
tm_scope: source.nim
language_id: 249
@@ -3116,6 +3663,21 @@ ObjDump:
tm_scope: objdump.x86asm
ace_mode: assembly_x86
language_id: 256
+Object Data Instance Notation:
+ type: data
+ extensions:
+ - ".odin"
+ tm_scope: source.odin-ehr
+ ace_mode: text
+ language_id: 985227236
+ObjectScript:
+ type: programming
+ extensions:
+ - ".cls"
+ language_id: 202735509
+ tm_scope: source.objectscript
+ color: "#424893"
+ ace_mode: text
Objective-C:
type: programming
tm_scope: source.objc
@@ -3158,6 +3720,17 @@ Objective-J:
tm_scope: source.js.objj
ace_mode: text
language_id: 259
+Odin:
+ type: programming
+ color: "#60AFFE"
+ aliases:
+ - odinlang
+ - odin-lang
+ extensions:
+ - ".odin"
+ tm_scope: source.odin
+ ace_mode: text
+ language_id: 889244082
Omgrofl:
type: programming
extensions:
@@ -3170,6 +3743,7 @@ Opa:
type: programming
extensions:
- ".opa"
+ tm_scope: source.opa
ace_mode: text
language_id: 261
Opal:
@@ -3180,6 +3754,13 @@ Opal:
tm_scope: source.opal
ace_mode: text
language_id: 262
+Open Policy Agent:
+ type: programming
+ ace_mode: text
+ extensions:
+ - ".rego"
+ language_id: 840483232
+ tm_scope: source.rego
OpenCL:
type: programming
group: C
@@ -3204,6 +3785,14 @@ OpenEdge ABL:
tm_scope: source.abl
ace_mode: text
language_id: 264
+OpenQASM:
+ type: programming
+ extensions:
+ - ".qasm"
+ color: "#AA70FF"
+ tm_scope: source.qasm
+ ace_mode: text
+ language_id: 153739399
OpenRC runscript:
type: programming
group: Shell
@@ -3223,6 +3812,13 @@ OpenSCAD:
tm_scope: source.scad
ace_mode: scad
language_id: 266
+OpenStep Property List:
+ type: data
+ extensions:
+ - ".plist"
+ tm_scope: source.plist
+ ace_mode: text
+ language_id: 598917541
OpenType Feature File:
type: data
aliases:
@@ -3275,15 +3871,6 @@ P4:
tm_scope: source.p4
ace_mode: text
language_id: 348895984
-PAWN:
- type: programming
- color: "#dbb284"
- extensions:
- - ".pwn"
- - ".inc"
- tm_scope: source.pawn
- ace_mode: text
- language_id: 271
PHP:
type: programming
tm_scope: text.html.php
@@ -3344,6 +3931,7 @@ PLpgSQL:
codemirror_mime_type: text/x-sql
tm_scope: source.sql
extensions:
+ - ".pgsql"
- ".sql"
language_id: 274
POV-Ray SDL:
@@ -3354,6 +3942,7 @@ POV-Ray SDL:
extensions:
- ".pov"
- ".inc"
+ tm_scope: source.pov-ray sdl
ace_mode: text
language_id: 275
Pan:
@@ -3417,10 +4006,21 @@ Pascal:
- ".pp"
interpreters:
- instantfpc
+ tm_scope: source.pascal
ace_mode: pascal
codemirror_mode: pascal
codemirror_mime_type: text/x-pascal
language_id: 281
+Pawn:
+ type: programming
+ color: "#dbb284"
+ extensions:
+ - ".pwn"
+ - ".inc"
+ - ".sma"
+ tm_scope: source.pawn
+ ace_mode: text
+ language_id: 271
Pep8:
type: programming
color: "#C76F5B"
@@ -3458,30 +4058,6 @@ Perl:
aliases:
- cperl
language_id: 282
-Perl 6:
- type: programming
- color: "#0000fb"
- extensions:
- - ".6pl"
- - ".6pm"
- - ".nqp"
- - ".p6"
- - ".p6l"
- - ".p6m"
- - ".pl"
- - ".pl6"
- - ".pm"
- - ".pm6"
- - ".t"
- interpreters:
- - perl6
- aliases:
- - perl6
- tm_scope: source.perl6fe
- ace_mode: perl
- codemirror_mode: perl
- codemirror_mime_type: text/x-perl
- language_id: 283
Pic:
type: markup
group: Roff
@@ -3526,8 +4102,18 @@ Pike:
- ".pmod"
interpreters:
- pike
+ tm_scope: source.pike
ace_mode: text
language_id: 287
+PlantUML:
+ type: data
+ extensions:
+ - ".puml"
+ - ".iuml"
+ - ".plantuml"
+ tm_scope: source.wsd
+ ace_mode: text
+ language_id: 833504686
Pod:
type: prose
ace_mode: perl
@@ -3540,6 +4126,17 @@ Pod:
- perl
tm_scope: none
language_id: 288
+Pod 6:
+ type: prose
+ ace_mode: perl
+ tm_scope: source.perl6fe
+ wrap: true
+ extensions:
+ - ".pod"
+ - ".pod6"
+ interpreters:
+ - perl6
+ language_id: 155357471
PogoScript:
type: programming
color: "#d80074"
@@ -3561,6 +4158,7 @@ PostCSS:
group: CSS
extensions:
- ".pcss"
+ - ".postcss"
ace_mode: text
language_id: 262764437
PostScript:
@@ -3569,6 +4167,7 @@ PostScript:
extensions:
- ".ps"
- ".eps"
+ - ".epsi"
- ".pfa"
tm_scope: source.postscript
aliases:
@@ -3589,6 +4188,7 @@ PowerBuilder:
PowerShell:
type: programming
color: "#012456"
+ tm_scope: source.powershell
ace_mode: powershell
codemirror_mode: powershell
codemirror_mime_type: application/x-powershell
@@ -3602,13 +4202,29 @@ PowerShell:
interpreters:
- pwsh
language_id: 293
+Prisma:
+ type: data
+ color: "#0c344b"
+ extensions:
+ - ".prisma"
+ tm_scope: source.prisma
+ ace_mode: text
+ language_id: 499933428
Processing:
type: programming
color: "#0096D8"
extensions:
- ".pde"
+ tm_scope: source.processing
ace_mode: text
language_id: 294
+Proguard:
+ type: data
+ extensions:
+ - ".pro"
+ tm_scope: none
+ ace_mode: text
+ language_id: 716513858
Prolog:
type: programming
color: "#74283c"
@@ -3654,8 +4270,8 @@ Public Key:
codemirror_mime_type: application/pgp
language_id: 298
Pug:
- group: HTML
type: markup
+ color: "#a86454"
extensions:
- ".jade"
- ".pug"
@@ -3704,13 +4320,13 @@ PureScript:
language_id: 302
Python:
type: programming
+ tm_scope: source.python
ace_mode: python
codemirror_mode: python
codemirror_mime_type: text/x-python
color: "#3572A5"
extensions:
- ".py"
- - ".bzl"
- ".cgi"
- ".fcgi"
- ".gyp"
@@ -3723,27 +4339,25 @@ Python:
- ".pyt"
- ".pyw"
- ".rpy"
+ - ".smk"
- ".spec"
- ".tac"
- ".wsgi"
- ".xpy"
filenames:
- ".gclient"
- - BUCK
- - BUILD
- - BUILD.bazel
+ - DEPS
- SConscript
- SConstruct
- Snakefile
- - WORKSPACE
- wscript
interpreters:
- python
- python2
- python3
aliases:
- - rusthon
- python3
+ - rusthon
language_id: 303
Python console:
type: programming
@@ -3763,6 +4377,16 @@ Python traceback:
tm_scope: text.python.traceback
ace_mode: text
language_id: 304
+Q#:
+ type: programming
+ extensions:
+ - ".qs"
+ aliases:
+ - qsharp
+ color: "#fed659"
+ ace_mode: text
+ tm_scope: source.qsharp
+ language_id: 697448245
QML:
type: programming
color: "#44a51c"
@@ -3779,8 +4403,22 @@ QMake:
- ".pri"
interpreters:
- qmake
+ tm_scope: source.qmake
ace_mode: text
language_id: 306
+Qt Script:
+ type: programming
+ ace_mode: javascript
+ codemirror_mode: javascript
+ codemirror_mime_type: text/javascript
+ extensions:
+ - ".qs"
+ filenames:
+ - installscript.qs
+ - toolchain_installscript.qs
+ color: "#00b841"
+ tm_scope: source.js
+ language_id: 558193693
Quake:
type: programming
filenames:
@@ -3806,6 +4444,7 @@ R:
- expr-dist
interpreters:
- Rscript
+ tm_scope: source.r
ace_mode: r
codemirror_mode: r
codemirror_mime_type: text/x-rsrc
@@ -3854,18 +4493,6 @@ REXX:
tm_scope: source.rexx
ace_mode: text
language_id: 311
-RHTML:
- type: markup
- group: HTML
- extensions:
- - ".rhtml"
- tm_scope: text.html.erb
- aliases:
- - html+ruby
- ace_mode: rhtml
- codemirror_mode: htmlembedded
- codemirror_mime_type: application/x-erb
- language_id: 312
RMarkdown:
type: prose
wrap: true
@@ -3904,12 +4531,13 @@ RUNOFF:
extensions:
- ".rnh"
- ".rno"
+ wrap: true
tm_scope: text.runoff
ace_mode: text
language_id: 315
Racket:
type: programming
- color: "#22228f"
+ color: "#3c5caa"
extensions:
- ".rkt"
- ".rktd"
@@ -3931,6 +4559,33 @@ Ragel:
tm_scope: none
ace_mode: text
language_id: 317
+Raku:
+ type: programming
+ color: "#0000fb"
+ extensions:
+ - ".6pl"
+ - ".6pm"
+ - ".nqp"
+ - ".p6"
+ - ".p6l"
+ - ".p6m"
+ - ".pl"
+ - ".pl6"
+ - ".pm"
+ - ".pm6"
+ - ".t"
+ interpreters:
+ - perl6
+ - raku
+ - rakudo
+ aliases:
+ - perl6
+ - perl-6
+ tm_scope: source.perl6fe
+ ace_mode: perl
+ codemirror_mode: perl
+ codemirror_mime_type: text/x-perl
+ language_id: 283
Rascal:
type: programming
color: "#fffaa0"
@@ -3948,9 +4603,21 @@ Raw token data:
tm_scope: none
ace_mode: text
language_id: 318
+Readline Config:
+ type: data
+ group: INI
+ aliases:
+ - inputrc
+ - readline
+ filenames:
+ - ".inputrc"
+ - inputrc
+ tm_scope: source.inputrc
+ ace_mode: text
+ language_id: 538732839
Reason:
type: programming
- group: OCaml
+ color: "#ff5847"
ace_mode: rust
codemirror_mode: rust
codemirror_mime_type: text/x-rustsrc
@@ -4020,6 +4687,13 @@ RenderScript:
tm_scope: none
ace_mode: text
language_id: 323
+Rich Text Format:
+ type: markup
+ extensions:
+ - ".rtf"
+ tm_scope: text.rtf
+ ace_mode: text
+ language_id: 51601661
Ring:
type: programming
color: "#2D54CB"
@@ -4028,6 +4702,14 @@ Ring:
tm_scope: source.ring
ace_mode: text
language_id: 431
+Riot:
+ type: markup
+ color: "#A71E49"
+ ace_mode: html
+ extensions:
+ - ".riot"
+ tm_scope: text.html.riot
+ language_id: 878396783
RobotFramework:
type: programming
extensions:
@@ -4039,7 +4721,7 @@ Roff:
type: markup
color: "#ecdebe"
extensions:
- - ".man"
+ - ".roff"
- ".1"
- ".1in"
- ".1m"
@@ -4048,6 +4730,8 @@ Roff:
- ".3"
- ".3in"
- ".3m"
+ - ".3p"
+ - ".3pm"
- ".3qt"
- ".3x"
- ".4"
@@ -4057,23 +4741,65 @@ Roff:
- ".8"
- ".9"
- ".l"
+ - ".man"
+ - ".mdoc"
- ".me"
- ".ms"
- ".n"
- ".nr"
- ".rno"
- - ".roff"
- ".tmac"
filenames:
+ - eqnrc
- mmn
- mmt
+ - troffrc
+ - troffrc-end
tm_scope: text.roff
aliases:
+ - groff
+ - man
+ - manpage
+ - man page
+ - man-page
+ - mdoc
- nroff
+ - troff
+ wrap: true
ace_mode: text
codemirror_mode: troff
codemirror_mime_type: text/troff
language_id: 141
+Roff Manpage:
+ type: markup
+ group: Roff
+ extensions:
+ - ".1"
+ - ".1in"
+ - ".1m"
+ - ".1x"
+ - ".2"
+ - ".3"
+ - ".3in"
+ - ".3m"
+ - ".3p"
+ - ".3pm"
+ - ".3qt"
+ - ".3x"
+ - ".4"
+ - ".5"
+ - ".6"
+ - ".7"
+ - ".8"
+ - ".9"
+ - ".man"
+ - ".mdoc"
+ wrap: true
+ tm_scope: text.roff
+ ace_mode: text
+ codemirror_mode: troff
+ codemirror_mime_type: text/troff
+ language_id: 612669833
Rouge:
type: programming
ace_mode: clojure
@@ -4086,6 +4812,7 @@ Rouge:
language_id: 325
Ruby:
type: programming
+ tm_scope: source.ruby
ace_mode: ruby
codemirror_mode: ruby
codemirror_mime_type: text/x-ruby
@@ -4109,6 +4836,7 @@ Ruby:
- ".podspec"
- ".rabl"
- ".rake"
+ - ".rbi"
- ".rbuild"
- ".rbw"
- ".rbx"
@@ -4126,6 +4854,7 @@ Ruby:
filenames:
- ".irbrc"
- ".pryrc"
+ - ".simplecov"
- Appraisals
- Berksfile
- Brewfile
@@ -4153,6 +4882,7 @@ Rust:
extensions:
- ".rs"
- ".rs.in"
+ tm_scope: source.rust
ace_mode: rust
codemirror_mode: rust
codemirror_mime_type: text/x-rustsrc
@@ -4169,8 +4899,8 @@ SAS:
language_id: 328
SCSS:
type: markup
- tm_scope: source.scss
- group: CSS
+ color: "#c6538c"
+ tm_scope: source.css.scss
ace_mode: scss
codemirror_mode: css
codemirror_mime_type: text/x-scss
@@ -4252,6 +4982,19 @@ SRecode Template:
extensions:
- ".srt"
language_id: 335
+SSH Config:
+ type: data
+ group: INI
+ filenames:
+ - ssh-config
+ - ssh_config
+ - sshconfig
+ - sshconfig.snip
+ - sshd-config
+ - sshd_config
+ ace_mode: text
+ tm_scope: source.ssh-config
+ language_id: 554920715
STON:
type: data
group: Smalltalk
@@ -4262,16 +5005,25 @@ STON:
language_id: 336
SVG:
type: data
+ color: "#ff9900"
extensions:
- ".svg"
- tm_scope: text.xml
+ tm_scope: text.xml.svg
ace_mode: xml
codemirror_mode: xml
codemirror_mime_type: text/xml
language_id: 337
+SWIG:
+ type: programming
+ extensions:
+ - ".i"
+ tm_scope: source.c++
+ ace_mode: c_cpp
+ codemirror_mode: clike
+ codemirror_mime_type: text/x-c++src
+ language_id: 1066250075
Sage:
type: programming
- group: Python
extensions:
- ".sage"
- ".sagews"
@@ -4295,8 +5047,8 @@ SaltStack:
language_id: 339
Sass:
type: markup
+ color: "#a53b70"
tm_scope: source.sass
- group: CSS
extensions:
- ".sass"
ace_mode: sass
@@ -4305,6 +5057,7 @@ Sass:
language_id: 340
Scala:
type: programming
+ tm_scope: source.scala
ace_mode: scala
codemirror_mode: clike
codemirror_mime_type: text/x-scala
@@ -4336,12 +5089,14 @@ Scheme:
- ".sps"
- ".ss"
interpreters:
+ - scheme
- guile
- bigloo
- chicken
- csi
- gosh
- r6rs
+ tm_scope: source.scheme
ace_mode: scheme
codemirror_mode: scheme
codemirror_mime_type: text/x-scheme
@@ -4352,6 +5107,7 @@ Scilab:
- ".sci"
- ".sce"
- ".tst"
+ tm_scope: source.scilab
ace_mode: text
language_id: 344
Self:
@@ -4383,6 +5139,7 @@ Shell:
- ".bats"
- ".cgi"
- ".command"
+ - ".env"
- ".fcgi"
- ".ksh"
- ".sh.in"
@@ -4390,11 +5147,15 @@ Shell:
- ".tool"
- ".zsh"
filenames:
+ - ".bash_aliases"
- ".bash_history"
- ".bash_logout"
- ".bash_profile"
- ".bashrc"
- ".cshrc"
+ - ".env"
+ - ".env.example"
+ - ".flaskenv"
- ".login"
- ".profile"
- ".zlogin"
@@ -4404,6 +5165,7 @@ Shell:
- ".zshrc"
- 9fs
- PKGBUILD
+ - bash_aliases
- bash_logout
- bash_profile
- bashrc
@@ -4427,6 +5189,7 @@ Shell:
- rc
- sh
- zsh
+ tm_scope: source.shell
ace_mode: sh
codemirror_mode: shell
codemirror_mime_type: text/x-sh
@@ -4451,6 +5214,15 @@ Shen:
tm_scope: source.shen
ace_mode: text
language_id: 348
+Sieve:
+ type: programming
+ tm_scope: source.sieve
+ ace_mode: text
+ extensions:
+ - ".sieve"
+ codemirror_mode: sieve
+ codemirror_mime_type: application/sieve
+ language_id: 208976687
Slash:
type: programming
color: "#007eff"
@@ -4459,9 +5231,17 @@ Slash:
tm_scope: text.html.slash
ace_mode: text
language_id: 349
+Slice:
+ type: programming
+ color: "#003fa2"
+ tm_scope: source.slice
+ ace_mode: text
+ extensions:
+ - ".ice"
+ language_id: 894641667
Slim:
- group: HTML
type: markup
+ color: "#2b2b2b"
extensions:
- ".slim"
tm_scope: text.slim
@@ -4469,6 +5249,16 @@ Slim:
codemirror_mode: slim
codemirror_mime_type: text/x-slim
language_id: 350
+SmPL:
+ type: programming
+ extensions:
+ - ".cocci"
+ aliases:
+ - coccinelle
+ ace_mode: text
+ tm_scope: source.smpl
+ color: "#c94949"
+ language_id: 164123055
Smali:
type: programming
extensions:
@@ -4484,6 +5274,7 @@ Smalltalk:
- ".cs"
aliases:
- squeak
+ tm_scope: source.smalltalk
ace_mode: text
codemirror_mode: smalltalk
codemirror_mime_type: text/x-stsrc
@@ -4502,17 +5293,18 @@ Solidity:
color: "#AA6746"
ace_mode: text
tm_scope: source.solidity
+ extensions:
+ - ".sol"
language_id: 237469032
SourcePawn:
type: programming
- color: "#5c7611"
+ color: "#f69e1d"
aliases:
- sourcemod
extensions:
- ".sp"
- ".inc"
- - ".sma"
- tm_scope: source.sp
+ tm_scope: source.sourcepawn
ace_mode: text
language_id: 354
Spline Font Database:
@@ -4546,7 +5338,7 @@ Standard ML:
aliases:
- sml
extensions:
- - ".ML"
+ - ".ml"
- ".fun"
- ".sig"
- ".sml"
@@ -4555,6 +5347,25 @@ Standard ML:
codemirror_mode: mllike
codemirror_mime_type: text/x-ocaml
language_id: 357
+Starlark:
+ type: programming
+ tm_scope: source.python
+ ace_mode: python
+ codemirror_mode: python
+ codemirror_mime_type: text/x-python
+ color: "#76d275"
+ extensions:
+ - ".bzl"
+ filenames:
+ - BUCK
+ - BUILD
+ - BUILD.bazel
+ - Tiltfile
+ - WORKSPACE
+ aliases:
+ - bazel
+ - bzl
+ language_id: 960266174
Stata:
type: programming
extensions:
@@ -4565,11 +5376,12 @@ Stata:
- ".mata"
- ".matah"
- ".sthlp"
+ tm_scope: source.stata
ace_mode: text
language_id: 358
Stylus:
type: markup
- group: CSS
+ color: "#ff6347"
extensions:
- ".styl"
tm_scope: source.stylus
@@ -4602,11 +5414,22 @@ SuperCollider:
tm_scope: source.supercollider
ace_mode: text
language_id: 361
+Svelte:
+ type: markup
+ color: "#ff3e00"
+ tm_scope: source.svelte
+ ace_mode: html
+ codemirror_mode: htmlmixed
+ codemirror_mime_type: text/html
+ extensions:
+ - ".svelte"
+ language_id: 928734530
Swift:
type: programming
color: "#ffac45"
extensions:
- ".swift"
+ tm_scope: source.swift
ace_mode: text
codemirror_mode: swift
codemirror_mime_type: text/x-swift
@@ -4618,6 +5441,7 @@ SystemVerilog:
- ".sv"
- ".svh"
- ".vh"
+ tm_scope: source.systemverilog
ace_mode: verilog
codemirror_mode: verilog
codemirror_mime_type: text/x-systemverilog
@@ -4647,11 +5471,36 @@ TOML:
filenames:
- Cargo.lock
- Gopkg.lock
+ - poetry.lock
tm_scope: source.toml
ace_mode: toml
codemirror_mode: toml
codemirror_mime_type: text/x-toml
language_id: 365
+TSQL:
+ type: programming
+ extensions:
+ - ".sql"
+ ace_mode: sql
+ tm_scope: source.tsql
+ language_id: 918334941
+TSV:
+ type: data
+ ace_mode: text
+ tm_scope: source.generic-db
+ extensions:
+ - ".tsv"
+ language_id: 1035892117
+TSX:
+ type: programming
+ group: TypeScript
+ extensions:
+ - ".tsx"
+ tm_scope: source.tsx
+ ace_mode: javascript
+ codemirror_mode: jsx
+ codemirror_mime_type: text/jsx
+ language_id: 94901924
TXL:
type: programming
extensions:
@@ -4672,6 +5521,7 @@ Tcl:
interpreters:
- tclsh
- wish
+ tm_scope: source.tcl
ace_mode: tcl
codemirror_mode: tcl
codemirror_mime_type: text/x-tcl
@@ -4682,6 +5532,9 @@ Tcsh:
extensions:
- ".tcsh"
- ".csh"
+ interpreters:
+ - tcsh
+ - csh
tm_scope: source.shell
ace_mode: sh
codemirror_mode: shell
@@ -4693,6 +5546,7 @@ TeX:
ace_mode: tex
codemirror_mode: stex
codemirror_mime_type: text/x-stex
+ tm_scope: text.tex.latex
wrap: true
aliases:
- latex
@@ -4700,7 +5554,6 @@ TeX:
- ".tex"
- ".aux"
- ".bbx"
- - ".bib"
- ".cbx"
- ".cls"
- ".dtx"
@@ -4725,12 +5578,25 @@ Terra:
extensions:
- ".t"
color: "#00004c"
+ tm_scope: source.terra
ace_mode: lua
codemirror_mode: lua
codemirror_mime_type: text/x-lua
interpreters:
- lua
language_id: 371
+Texinfo:
+ type: prose
+ wrap: true
+ extensions:
+ - ".texinfo"
+ - ".texi"
+ - ".txi"
+ ace_mode: text
+ tm_scope: text.texinfo
+ interpreters:
+ - makeinfo
+ language_id: 988020015
Text:
type: prose
wrap: true
@@ -4757,10 +5623,17 @@ Text:
- README.mysql
- click.me
- delete.me
+ - go.mod
+ - go.sum
- keep.me
+ - package.mask
+ - package.use.mask
+ - package.use.stable.mask
- read.me
- readme.1st
- test.me
+ - use.mask
+ - use.stable.mask
tm_scope: none
ace_mode: text
language_id: 372
@@ -4801,7 +5674,7 @@ Turtle:
language_id: 376
Twig:
type: markup
- group: HTML
+ color: "#c1d026"
extensions:
- ".twig"
tm_scope: text.html.twig
@@ -4823,9 +5696,11 @@ TypeScript:
color: "#2b7489"
aliases:
- ts
+ interpreters:
+ - deno
+ - ts-node
extensions:
- ".ts"
- - ".tsx"
tm_scope: source.ts
ace_mode: typescript
codemirror_mode: javascript
@@ -4849,6 +5724,7 @@ Unity3D Asset:
extensions:
- ".anim"
- ".asset"
+ - ".mask"
- ".mat"
- ".meta"
- ".prefab"
@@ -4866,6 +5742,7 @@ Unix Assembly:
language_id: 120
Uno:
type: programming
+ color: "#9933cc"
extensions:
- ".uno"
ace_mode: csharp
@@ -4894,6 +5771,46 @@ UrWeb:
tm_scope: source.ur
ace_mode: text
language_id: 383
+V:
+ type: programming
+ color: "#4f87c4"
+ aliases:
+ - vlang
+ extensions:
+ - ".v"
+ tm_scope: source.v
+ ace_mode: golang
+ codemirror_mode: go
+ codemirror_mime_type: text/x-go
+ language_id: 603371597
+VBA:
+ type: programming
+ color: "#867db1"
+ extensions:
+ - ".bas"
+ - ".cls"
+ - ".frm"
+ - ".frx"
+ - ".vba"
+ tm_scope: source.vbnet
+ aliases:
+ - vb6
+ - visual basic 6
+ - visual basic for applications
+ ace_mode: text
+ codemirror_mode: vb
+ codemirror_mime_type: text/x-vb
+ language_id: 399230729
+VBScript:
+ type: programming
+ color: "#15dcdc"
+ extensions:
+ - ".vbs"
+ tm_scope: source.vbnet
+ ace_mode: text
+ codemirror_mode: vbscript
+ codemirror_mime_type: text/vbscript
+ language_id: 408016005
VCL:
type: programming
color: "#148AA8"
@@ -4914,6 +5831,7 @@ VHDL:
- ".vhs"
- ".vht"
- ".vhw"
+ tm_scope: source.vhdl
ace_mode: vhdl
codemirror_mode: vhdl
codemirror_mime_type: text/x-vhdl
@@ -4924,6 +5842,7 @@ Vala:
extensions:
- ".vala"
- ".vapi"
+ tm_scope: source.vala
ace_mode: vala
language_id: 386
Verilog:
@@ -4932,10 +5851,34 @@ Verilog:
extensions:
- ".v"
- ".veo"
+ tm_scope: source.verilog
ace_mode: verilog
codemirror_mode: verilog
codemirror_mime_type: text/x-verilog
language_id: 387
+Vim Help File:
+ type: prose
+ aliases:
+ - vimhelp
+ extensions:
+ - ".txt"
+ tm_scope: text.vim-help
+ ace_mode: text
+ language_id: 508563686
+Vim Snippet:
+ type: markup
+ aliases:
+ - SnipMate
+ - UltiSnip
+ - UltiSnips
+ - NeoSnippet
+ extensions:
+ - ".snip"
+ - ".snippet"
+ - ".snippets"
+ tm_scope: source.vim-snippet
+ ace_mode: text
+ language_id: 81265970
Vim script:
type: programming
color: "#199f4b"
@@ -4946,7 +5889,10 @@ Vim script:
- nvim
extensions:
- ".vim"
+ - ".vba"
+ - ".vmb"
filenames:
+ - ".exrc"
- ".gvimrc"
- ".nvimrc"
- ".vimrc"
@@ -4956,22 +5902,18 @@ Vim script:
- vimrc
ace_mode: text
language_id: 388
-Visual Basic:
+Visual Basic .NET:
type: programming
color: "#945db7"
extensions:
- ".vb"
- - ".bas"
- - ".cls"
- - ".frm"
- - ".frx"
- - ".vba"
- ".vbhtml"
- - ".vbs"
- tm_scope: source.vbnet
aliases:
- - vb.net
+ - visual basic
- vbnet
+ - vb .net
+ - vb.net
+ tm_scope: source.vbnet
ace_mode: text
codemirror_mode: vb
codemirror_mime_type: text/x-vb
@@ -5038,6 +5980,41 @@ WebIDL:
codemirror_mode: webidl
codemirror_mime_type: text/x-webidl
language_id: 395
+WebVTT:
+ type: data
+ wrap: true
+ extensions:
+ - ".vtt"
+ tm_scope: source.vtt
+ ace_mode: text
+ language_id: 658679714
+Wget Config:
+ type: data
+ group: INI
+ aliases:
+ - wgetrc
+ filenames:
+ - ".wgetrc"
+ tm_scope: source.wgetrc
+ ace_mode: text
+ language_id: 668457123
+Windows Registry Entries:
+ type: data
+ extensions:
+ - ".reg"
+ tm_scope: source.reg
+ ace_mode: ini
+ codemirror_mode: properties
+ codemirror_mime_type: text/x-properties
+ language_id: 969674868
+Wollok:
+ type: programming
+ color: "#a23738"
+ extensions:
+ - ".wlk"
+ ace_mode: text
+ tm_scope: source.wollok
+ language_id: 632745969
World of Warcraft Addon Data:
type: data
extensions:
@@ -5057,6 +6034,16 @@ X BitMap:
codemirror_mode: clike
codemirror_mime_type: text/x-csrc
language_id: 782911107
+X Font Directory Index:
+ type: data
+ filenames:
+ - encodings.dir
+ - fonts.alias
+ - fonts.dir
+ - fonts.scale
+ tm_scope: source.fontdir
+ ace_mode: text
+ language_id: 208700028
X PixMap:
type: data
group: C
@@ -5101,6 +6088,7 @@ XCompose:
language_id: 225167241
XML:
type: data
+ tm_scope: text.xml
ace_mode: xml
codemirror_mode: xml
codemirror_mime_type: text/xml
@@ -5135,7 +6123,9 @@ XML:
- ".fxml"
- ".glade"
- ".gml"
+ - ".gmx"
- ".grxml"
+ - ".gst"
- ".iml"
- ".ivy"
- ".jelly"
@@ -5155,7 +6145,6 @@ XML:
- ".odd"
- ".osm"
- ".pkgproj"
- - ".plist"
- ".pluginspec"
- ".proj"
- ".props"
@@ -5171,15 +6160,9 @@ XML:
- ".shproj"
- ".srdf"
- ".storyboard"
- - ".stTheme"
- ".sublime-snippet"
- ".targets"
- - ".tmCommand"
- ".tml"
- - ".tmLanguage"
- - ".tmPreferences"
- - ".tmSnippet"
- - ".tmTheme"
- ".ts"
- ".tsx"
- ".ui"
@@ -5192,6 +6175,7 @@ XML:
- ".vstemplate"
- ".vxml"
- ".wixproj"
+ - ".workflow"
- ".wsdl"
- ".wsf"
- ".wxi"
@@ -5222,6 +6206,22 @@ XML:
- Web.config
- packages.config
language_id: 399
+XML Property List:
+ type: data
+ group: XML
+ extensions:
+ - ".plist"
+ - ".stTheme"
+ - ".tmCommand"
+ - ".tmLanguage"
+ - ".tmPreferences"
+ - ".tmSnippet"
+ - ".tmTheme"
+ tm_scope: text.xml.plist
+ ace_mode: xml
+ codemirror_mode: xml
+ codemirror_mime_type: text/xml
+ language_id: 75622871
XPages:
type: data
extensions:
@@ -5287,17 +6287,19 @@ Xojo:
- ".xojo_script"
- ".xojo_toolbar"
- ".xojo_window"
- tm_scope: source.vbnet
+ tm_scope: source.xojo
ace_mode: text
language_id: 405
Xtend:
type: programming
extensions:
- ".xtend"
+ tm_scope: source.xtend
ace_mode: text
language_id: 406
YAML:
type: data
+ color: "#cb171e"
tm_scope: source.yaml
aliases:
- yml
@@ -5310,12 +6312,14 @@ YAML:
- ".syntax"
- ".yaml"
- ".yaml-tmlanguage"
+ - ".yaml.sed"
- ".yml.mysql"
filenames:
- ".clang-format"
- ".clang-tidy"
- ".gemrc"
- glide.lock
+ - yarn.lock
ace_mode: yaml
codemirror_mode: yaml
codemirror_mime_type: text/x-yaml
@@ -5328,23 +6332,71 @@ YANG:
ace_mode: text
language_id: 408
YARA:
- type: data
+ type: programming
+ color: "#220000"
ace_mode: text
extensions:
- ".yar"
- ".yara"
tm_scope: source.yara
language_id: 805122868
+YASnippet:
+ type: markup
+ aliases:
+ - snippet
+ - yas
+ color: "#32AB90"
+ extensions:
+ - ".yasnippet"
+ tm_scope: source.yasnippet
+ ace_mode: text
+ language_id: 378760102
Yacc:
type: programming
extensions:
- ".y"
- ".yacc"
- ".yy"
- tm_scope: source.bison
+ tm_scope: source.yacc
ace_mode: text
color: "#4B6C4B"
language_id: 409
+ZAP:
+ type: programming
+ color: "#0d665e"
+ extensions:
+ - ".zap"
+ - ".xzap"
+ tm_scope: source.zap
+ ace_mode: text
+ language_id: 952972794
+ZIL:
+ type: programming
+ color: "#dc75e5"
+ extensions:
+ - ".zil"
+ - ".mud"
+ tm_scope: source.zil
+ ace_mode: text
+ language_id: 973483626
+Zeek:
+ type: programming
+ aliases:
+ - bro
+ extensions:
+ - ".zeek"
+ - ".bro"
+ tm_scope: source.zeek
+ ace_mode: text
+ language_id: 40
+ZenScript:
+ type: programming
+ color: "#00BCD1"
+ extensions:
+ - ".zs"
+ tm_scope: source.zenscript
+ ace_mode: text
+ language_id: 494938890
Zephir:
type: programming
color: "#118f9e"
@@ -5353,6 +6405,14 @@ Zephir:
tm_scope: source.php.zephir
ace_mode: php
language_id: 410
+Zig:
+ type: programming
+ color: "#ec915c"
+ extensions:
+ - ".zig"
+ tm_scope: source.zig
+ ace_mode: text
+ language_id: 646424281
Zimpl:
type: programming
extensions:
@@ -5362,6 +6422,17 @@ Zimpl:
tm_scope: none
ace_mode: text
language_id: 411
+cURL Config:
+ type: data
+ group: INI
+ aliases:
+ - curlrc
+ filenames:
+ - ".curlrc"
+ - _curlrc
+ tm_scope: source.curlrc
+ ace_mode: text
+ language_id: 992375436
desktop:
type: data
extensions:
@@ -5370,6 +6441,20 @@ desktop:
tm_scope: source.desktop
ace_mode: text
language_id: 412
+dircolors:
+ type: data
+ extensions:
+ - ".dircolors"
+ filenames:
+ - ".dir_colors"
+ - ".dircolors"
+ - DIR_COLORS
+ - _dir_colors
+ - _dircolors
+ - dir_colors
+ tm_scope: source.dircolors
+ ace_mode: text
+ language_id: 691605112
eC:
type: programming
color: "#913960"
@@ -5398,12 +6483,40 @@ fish:
tm_scope: source.fish
ace_mode: text
language_id: 415
+mIRC Script:
+ type: programming
+ color: "#3d57c3"
+ extensions:
+ - ".mrc"
+ tm_scope: source.msl
+ ace_mode: text
+ language_id: 517654727
+mcfunction:
+ type: programming
+ color: "#E22837"
+ extensions:
+ - ".mcfunction"
+ tm_scope: source.mcfunction
+ ace_mode: text
+ language_id: 462488745
mupad:
type: programming
extensions:
- ".mu"
+ tm_scope: source.mupad
ace_mode: text
language_id: 416
+nanorc:
+ type: data
+ group: INI
+ extensions:
+ - ".nanorc"
+ filenames:
+ - ".nanorc"
+ - nanorc
+ tm_scope: source.nanorc
+ ace_mode: text
+ language_id: 775996197
nesC:
type: programming
color: "#94B0C7"
@@ -5417,6 +6530,7 @@ ooc:
color: "#b0b77e"
extensions:
- ".ooc"
+ tm_scope: source.ooc
ace_mode: text
language_id: 418
q:
@@ -5437,6 +6551,7 @@ reStructuredText:
- ".rest"
- ".rest.txt"
- ".rst.txt"
+ tm_scope: text.restructuredtext
ace_mode: text
codemirror_mode: rst
codemirror_mime_type: text/x-rst
diff --git a/vendor/project_templates/gitpod_spring_petclinic.tar.gz b/vendor/project_templates/gitpod_spring_petclinic.tar.gz
new file mode 100644
index 00000000000..76308dc73df
--- /dev/null
+++ b/vendor/project_templates/gitpod_spring_petclinic.tar.gz
Binary files differ
diff --git a/vendor/sample_data_templates/basic.tar.gz b/vendor/sample_data_templates/basic.tar.gz
new file mode 100644
index 00000000000..1ab09f8dc41
--- /dev/null
+++ b/vendor/sample_data_templates/basic.tar.gz
Binary files differ
diff --git a/vendor/sample_data_templates/serenity_valley.tar.gz b/vendor/sample_data_templates/serenity_valley.tar.gz
new file mode 100644
index 00000000000..e469d61ca7b
--- /dev/null
+++ b/vendor/sample_data_templates/serenity_valley.tar.gz
Binary files differ
diff --git a/yarn.lock b/yarn.lock
index 9bb1756daa6..731828e3049 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2,12 +2,12 @@
# yarn lockfile v1
-"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.1":
- version "7.10.1"
- resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.10.1.tgz#d5481c5095daa1c57e16e54c6f9198443afb49ff"
- integrity sha512-IGhtTmpjGbYzcEDOw7DcQtbQSXcG9ftmAXtWTu9V936vDye4xjjekktFAtgZsWpzTj/X01jocB46mTywm/4SZw==
+"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.1", "@babel/code-frame@^7.10.4":
+ version "7.10.4"
+ resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.10.4.tgz#168da1a36e90da68ae8d49c0f1b48c7c6249213a"
+ integrity sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==
dependencies:
- "@babel/highlight" "^7.10.1"
+ "@babel/highlight" "^7.10.4"
"@babel/compat-data@^7.10.1":
version "7.10.1"
@@ -18,7 +18,7 @@
invariant "^2.2.4"
semver "^5.5.0"
-"@babel/core@>=7.2.2", "@babel/core@^7.1.0", "@babel/core@^7.10.1":
+"@babel/core@>=7.2.2", "@babel/core@^7.1.0", "@babel/core@^7.10.1", "@babel/core@^7.7.5":
version "7.10.2"
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.10.2.tgz#bd6786046668a925ac2bd2fd95b579b92a23b36a"
integrity sha512-KQmV9yguEjQsXqyOUGKjS4+3K8/DlOCE2pZcq4augdQmtTy5iv5EHtmMSJ7V4c1BIPjuwtZYqYLCq9Ga+hGBRQ==
@@ -40,14 +40,13 @@
semver "^5.4.1"
source-map "^0.5.0"
-"@babel/generator@^7.10.1", "@babel/generator@^7.10.2", "@babel/generator@^7.4.0":
- version "7.10.2"
- resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.10.2.tgz#0fa5b5b2389db8bfdfcc3492b551ee20f5dd69a9"
- integrity sha512-AxfBNHNu99DTMvlUPlt1h2+Hn7knPpH5ayJ8OqDWSeLld+Fi2AYBTC/IejWDM9Edcii4UzZRCsbUt0WlSDsDsA==
+"@babel/generator@^7.10.2", "@babel/generator@^7.11.5", "@babel/generator@^7.4.0":
+ version "7.11.6"
+ resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.11.6.tgz#b868900f81b163b4d464ea24545c61cbac4dc620"
+ integrity sha512-DWtQ1PV3r+cLbySoHrwn9RWEgKMBLLma4OBQloPRyDYvc5msJM9kvTLo1YnlJd1P/ZuKbdli3ijr5q3FvAF3uA==
dependencies:
- "@babel/types" "^7.10.2"
+ "@babel/types" "^7.11.5"
jsesc "^2.5.1"
- lodash "^4.17.13"
source-map "^0.5.0"
"@babel/helper-annotate-as-pure@^7.10.1":
@@ -114,21 +113,21 @@
"@babel/traverse" "^7.10.1"
"@babel/types" "^7.10.1"
-"@babel/helper-function-name@^7.10.1":
- version "7.10.1"
- resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.10.1.tgz#92bd63829bfc9215aca9d9defa85f56b539454f4"
- integrity sha512-fcpumwhs3YyZ/ttd5Rz0xn0TpIwVkN7X0V38B9TWNfVF42KEkhkAAuPCQ3oXmtTRtiPJrmZ0TrfS0GKF0eMaRQ==
+"@babel/helper-function-name@^7.10.1", "@babel/helper-function-name@^7.10.4":
+ version "7.10.4"
+ resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz#d2d3b20c59ad8c47112fa7d2a94bc09d5ef82f1a"
+ integrity sha512-YdaSyz1n8gY44EmN7x44zBn9zQ1Ry2Y+3GTA+3vH6Mizke1Vw0aWDM66FOYEPw8//qKkmqOckrGgTYa+6sceqQ==
dependencies:
- "@babel/helper-get-function-arity" "^7.10.1"
- "@babel/template" "^7.10.1"
- "@babel/types" "^7.10.1"
+ "@babel/helper-get-function-arity" "^7.10.4"
+ "@babel/template" "^7.10.4"
+ "@babel/types" "^7.10.4"
-"@babel/helper-get-function-arity@^7.10.1":
- version "7.10.1"
- resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.1.tgz#7303390a81ba7cb59613895a192b93850e373f7d"
- integrity sha512-F5qdXkYGOQUb0hpRaPoetF9AnsXknKjWMZ+wmsIRsp5ge5sFh4c3h1eH2pRTTuy9KKAA2+TTYomGXAtEL2fQEw==
+"@babel/helper-get-function-arity@^7.10.1", "@babel/helper-get-function-arity@^7.10.4":
+ version "7.10.4"
+ resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz#98c1cbea0e2332f33f9a4661b8ce1505b2c19ba2"
+ integrity sha512-EkN3YDB+SRDgiIUnNgcmiD361ti+AVbL3f3Henf6dqqUyr5dMsorno0lJWJuLhDhkI5sYEpgj6y9kB8AOU1I2A==
dependencies:
- "@babel/types" "^7.10.1"
+ "@babel/types" "^7.10.4"
"@babel/helper-hoist-variables@^7.10.1":
version "7.10.1"
@@ -137,44 +136,44 @@
dependencies:
"@babel/types" "^7.10.1"
-"@babel/helper-member-expression-to-functions@^7.10.1":
- version "7.10.1"
- resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.10.1.tgz#432967fd7e12a4afef66c4687d4ca22bc0456f15"
- integrity sha512-u7XLXeM2n50gb6PWJ9hoO5oO7JFPaZtrh35t8RqKLT1jFKj9IWeD1zrcrYp1q1qiZTdEarfDWfTIP8nGsu0h5g==
+"@babel/helper-member-expression-to-functions@^7.10.1", "@babel/helper-member-expression-to-functions@^7.10.4":
+ version "7.11.0"
+ resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.11.0.tgz#ae69c83d84ee82f4b42f96e2a09410935a8f26df"
+ integrity sha512-JbFlKHFntRV5qKw3YC0CvQnDZ4XMwgzzBbld7Ly4Mj4cbFy3KywcR8NtNctRToMWJOVvLINJv525Gd6wwVEx/Q==
dependencies:
- "@babel/types" "^7.10.1"
+ "@babel/types" "^7.11.0"
-"@babel/helper-module-imports@^7.0.0-beta.49", "@babel/helper-module-imports@^7.10.1":
- version "7.10.1"
- resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.10.1.tgz#dd331bd45bccc566ce77004e9d05fe17add13876"
- integrity sha512-SFxgwYmZ3HZPyZwJRiVNLRHWuW2OgE5k2nrVs6D9Iv4PPnXVffuEHy83Sfx/l4SqF+5kyJXjAyUmrG7tNm+qVg==
+"@babel/helper-module-imports@^7.0.0-beta.49", "@babel/helper-module-imports@^7.10.1", "@babel/helper-module-imports@^7.10.4":
+ version "7.10.4"
+ resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.10.4.tgz#4c5c54be04bd31670a7382797d75b9fa2e5b5620"
+ integrity sha512-nEQJHqYavI217oD9+s5MUBzk6x1IlvoS9WTPfgG43CbMEeStE0v+r+TucWdx8KFGowPGvyOkDT9+7DHedIDnVw==
dependencies:
- "@babel/types" "^7.10.1"
+ "@babel/types" "^7.10.4"
-"@babel/helper-module-transforms@^7.10.1":
- version "7.10.1"
- resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.10.1.tgz#24e2f08ee6832c60b157bb0936c86bef7210c622"
- integrity sha512-RLHRCAzyJe7Q7sF4oy2cB+kRnU4wDZY/H2xJFGof+M+SJEGhZsb+GFj5j1AD8NiSaVBJ+Pf0/WObiXu/zxWpFg==
+"@babel/helper-module-transforms@^7.10.1", "@babel/helper-module-transforms@^7.10.4":
+ version "7.11.0"
+ resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.11.0.tgz#b16f250229e47211abdd84b34b64737c2ab2d359"
+ integrity sha512-02EVu8COMuTRO1TAzdMtpBPbe6aQ1w/8fePD2YgQmxZU4gpNWaL9gK3Jp7dxlkUlUCJOTaSeA+Hrm1BRQwqIhg==
dependencies:
- "@babel/helper-module-imports" "^7.10.1"
- "@babel/helper-replace-supers" "^7.10.1"
- "@babel/helper-simple-access" "^7.10.1"
- "@babel/helper-split-export-declaration" "^7.10.1"
- "@babel/template" "^7.10.1"
- "@babel/types" "^7.10.1"
- lodash "^4.17.13"
+ "@babel/helper-module-imports" "^7.10.4"
+ "@babel/helper-replace-supers" "^7.10.4"
+ "@babel/helper-simple-access" "^7.10.4"
+ "@babel/helper-split-export-declaration" "^7.11.0"
+ "@babel/template" "^7.10.4"
+ "@babel/types" "^7.11.0"
+ lodash "^4.17.19"
-"@babel/helper-optimise-call-expression@^7.10.1":
- version "7.10.1"
- resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.10.1.tgz#b4a1f2561870ce1247ceddb02a3860fa96d72543"
- integrity sha512-a0DjNS1prnBsoKx83dP2falChcs7p3i8VMzdrSbfLhuQra/2ENC4sbri34dz/rWmDADsmF1q5GbfaXydh0Jbjg==
+"@babel/helper-optimise-call-expression@^7.10.1", "@babel/helper-optimise-call-expression@^7.10.4":
+ version "7.10.4"
+ resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.10.4.tgz#50dc96413d594f995a77905905b05893cd779673"
+ integrity sha512-n3UGKY4VXwXThEiKrgRAoVPBMqeoPgHVqiHZOanAJCG9nQUL2pLRQirUzl0ioKclHGpGqRgIOkgcIJaIWLpygg==
dependencies:
- "@babel/types" "^7.10.1"
+ "@babel/types" "^7.10.4"
-"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.1", "@babel/helper-plugin-utils@^7.8.0":
- version "7.10.1"
- resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.1.tgz#ec5a5cf0eec925b66c60580328b122c01230a127"
- integrity sha512-fvoGeXt0bJc7VMWZGCAEBEMo/HAjW2mP8apF5eXK0wSqwLAVHAISCWRoLMBMUs2kqeaG77jltVqu4Hn8Egl3nA==
+"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.1", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.8.0":
+ version "7.10.4"
+ resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz#2f75a831269d4f677de49986dff59927533cf375"
+ integrity sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==
"@babel/helper-regex@^7.10.1":
version "7.10.1"
@@ -194,35 +193,35 @@
"@babel/traverse" "^7.10.1"
"@babel/types" "^7.10.1"
-"@babel/helper-replace-supers@^7.10.1":
- version "7.10.1"
- resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.10.1.tgz#ec6859d20c5d8087f6a2dc4e014db7228975f13d"
- integrity sha512-SOwJzEfpuQwInzzQJGjGaiG578UYmyi2Xw668klPWV5n07B73S0a9btjLk/52Mlcxa+5AdIYqws1KyXRfMoB7A==
+"@babel/helper-replace-supers@^7.10.1", "@babel/helper-replace-supers@^7.10.4":
+ version "7.10.4"
+ resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.10.4.tgz#d585cd9388ea06e6031e4cd44b6713cbead9e6cf"
+ integrity sha512-sPxZfFXocEymYTdVK1UNmFPBN+Hv5mJkLPsYWwGBxZAxaWfFu+xqp7b6qWD0yjNuNL2VKc6L5M18tOXUP7NU0A==
dependencies:
- "@babel/helper-member-expression-to-functions" "^7.10.1"
- "@babel/helper-optimise-call-expression" "^7.10.1"
- "@babel/traverse" "^7.10.1"
- "@babel/types" "^7.10.1"
+ "@babel/helper-member-expression-to-functions" "^7.10.4"
+ "@babel/helper-optimise-call-expression" "^7.10.4"
+ "@babel/traverse" "^7.10.4"
+ "@babel/types" "^7.10.4"
-"@babel/helper-simple-access@^7.10.1":
- version "7.10.1"
- resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.10.1.tgz#08fb7e22ace9eb8326f7e3920a1c2052f13d851e"
- integrity sha512-VSWpWzRzn9VtgMJBIWTZ+GP107kZdQ4YplJlCmIrjoLVSi/0upixezHCDG8kpPVTBJpKfxTH01wDhh+jS2zKbw==
+"@babel/helper-simple-access@^7.10.4":
+ version "7.10.4"
+ resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.10.4.tgz#0f5ccda2945277a2a7a2d3a821e15395edcf3461"
+ integrity sha512-0fMy72ej/VEvF8ULmX6yb5MtHG4uH4Dbd6I/aHDb/JVg0bbivwt9Wg+h3uMvX+QSFtwr5MeItvazbrc4jtRAXw==
dependencies:
- "@babel/template" "^7.10.1"
- "@babel/types" "^7.10.1"
+ "@babel/template" "^7.10.4"
+ "@babel/types" "^7.10.4"
-"@babel/helper-split-export-declaration@^7.10.1":
- version "7.10.1"
- resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.10.1.tgz#c6f4be1cbc15e3a868e4c64a17d5d31d754da35f"
- integrity sha512-UQ1LVBPrYdbchNhLwj6fetj46BcFwfS4NllJo/1aJsT+1dLTEnXJL0qHqtY7gPzF8S2fXBJamf1biAXV3X077g==
+"@babel/helper-split-export-declaration@^7.10.1", "@babel/helper-split-export-declaration@^7.11.0":
+ version "7.11.0"
+ resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.11.0.tgz#f8a491244acf6a676158ac42072911ba83ad099f"
+ integrity sha512-74Vejvp6mHkGE+m+k5vHY93FX2cAtrw1zXrZXRlG4l410Nm9PxfEiVTn1PjDPV5SnmieiueY4AFg2xqhNFuuZg==
dependencies:
- "@babel/types" "^7.10.1"
+ "@babel/types" "^7.11.0"
-"@babel/helper-validator-identifier@^7.10.1":
- version "7.10.1"
- resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.1.tgz#5770b0c1a826c4f53f5ede5e153163e0318e94b5"
- integrity sha512-5vW/JXLALhczRCWP0PnFDMCJAchlBvM7f4uk/jXritBnIa6E1KmqmtrS3yn1LAnxFBypQ3eneLuXjsnfQsgILw==
+"@babel/helper-validator-identifier@^7.10.4":
+ version "7.10.4"
+ resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz#a78c7a7251e01f616512d31b10adcf52ada5e0d2"
+ integrity sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==
"@babel/helper-wrap-function@^7.10.1":
version "7.10.1"
@@ -243,19 +242,19 @@
"@babel/traverse" "^7.10.1"
"@babel/types" "^7.10.1"
-"@babel/highlight@^7.10.1":
- version "7.10.1"
- resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.10.1.tgz#841d098ba613ba1a427a2b383d79e35552c38ae0"
- integrity sha512-8rMof+gVP8mxYZApLF/JgNDAkdKa+aJt3ZYxF8z6+j/hpeXL7iMsKCPHa2jNMHu/qqBwzQF4OHNoYi8dMA/rYg==
+"@babel/highlight@^7.10.4":
+ version "7.10.4"
+ resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.10.4.tgz#7d1bdfd65753538fabe6c38596cdb76d9ac60143"
+ integrity sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==
dependencies:
- "@babel/helper-validator-identifier" "^7.10.1"
+ "@babel/helper-validator-identifier" "^7.10.4"
chalk "^2.0.0"
js-tokens "^4.0.0"
-"@babel/parser@^7.0.0", "@babel/parser@^7.1.0", "@babel/parser@^7.10.1", "@babel/parser@^7.10.2", "@babel/parser@^7.4.3":
- version "7.10.2"
- resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.10.2.tgz#871807f10442b92ff97e4783b9b54f6a0ca812d0"
- integrity sha512-PApSXlNMJyB4JiGVhCOlzKIif+TKFTvu0aQAhnTvfP/z3vVSN6ZypH5bfUNwFXXjRQtUEBNFd2PtmCmG2Py3qQ==
+"@babel/parser@^7.0.0", "@babel/parser@^7.1.0", "@babel/parser@^7.10.2", "@babel/parser@^7.10.4", "@babel/parser@^7.11.5", "@babel/parser@^7.4.3":
+ version "7.11.5"
+ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.11.5.tgz#c7ff6303df71080ec7a4f5b8c003c58f1cf51037"
+ integrity sha512-X9rD8qqm695vgmeaQ4fvz/o3+Wk4ZzQvSHkDBgpYKxpD4qTAUm88ZKtHkVqIOsYFFbIQ6wQYhC6q7pjqVK0E0Q==
"@babel/plugin-proposal-async-generator-functions@^7.10.1":
version "7.10.1"
@@ -347,14 +346,21 @@
"@babel/helper-create-regexp-features-plugin" "^7.10.1"
"@babel/helper-plugin-utils" "^7.10.1"
-"@babel/plugin-syntax-async-generators@^7.8.0":
+"@babel/plugin-syntax-async-generators@^7.8.0", "@babel/plugin-syntax-async-generators@^7.8.4":
version "7.8.4"
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d"
integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==
dependencies:
"@babel/helper-plugin-utils" "^7.8.0"
-"@babel/plugin-syntax-class-properties@^7.10.1":
+"@babel/plugin-syntax-bigint@^7.8.3":
+ version "7.8.3"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz#4c9a6f669f5d0cdf1b90a1671e9a146be5300cea"
+ integrity sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.8.0"
+
+"@babel/plugin-syntax-class-properties@^7.10.1", "@babel/plugin-syntax-class-properties@^7.8.3":
version "7.10.1"
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.10.1.tgz#d5bc0645913df5b17ad7eda0fa2308330bde34c5"
integrity sha512-Gf2Yx/iRs1JREDtVZ56OrjjgFHCaldpTnuy9BHla10qyVT3YkIIGEtoDWhyop0ksu1GvNjHIoYRBqm3zoR1jyQ==
@@ -368,49 +374,56 @@
dependencies:
"@babel/helper-plugin-utils" "^7.8.0"
-"@babel/plugin-syntax-import-meta@^7.10.1":
- version "7.10.1"
- resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.1.tgz#3e59120ed8b3c2ccc5abb1cfc7aaa3ea01cd36b6"
- integrity sha512-ypC4jwfIVF72og0dgvEcFRdOM2V9Qm1tu7RGmdZOlhsccyK0wisXmMObGuWEOd5jQ+K9wcIgSNftCpk2vkjUfQ==
+"@babel/plugin-syntax-import-meta@^7.10.1", "@babel/plugin-syntax-import-meta@^7.8.3":
+ version "7.10.4"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51"
+ integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==
dependencies:
- "@babel/helper-plugin-utils" "^7.10.1"
+ "@babel/helper-plugin-utils" "^7.10.4"
-"@babel/plugin-syntax-json-strings@^7.8.0":
+"@babel/plugin-syntax-json-strings@^7.8.0", "@babel/plugin-syntax-json-strings@^7.8.3":
version "7.8.3"
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a"
integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==
dependencies:
"@babel/helper-plugin-utils" "^7.8.0"
-"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.0":
+"@babel/plugin-syntax-logical-assignment-operators@^7.8.3":
+ version "7.10.1"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.1.tgz#fffee77b4934ce77f3b427649ecdddbec1958550"
+ integrity sha512-XyHIFa9kdrgJS91CUH+ccPVTnJShr8nLGc5bG2IhGXv5p1Rd+8BleGE5yzIg2Nc1QZAdHDa0Qp4m6066OL96Iw==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.10.1"
+
+"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.0", "@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3":
version "7.8.3"
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9"
integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==
dependencies:
"@babel/helper-plugin-utils" "^7.8.0"
-"@babel/plugin-syntax-numeric-separator@^7.10.1":
+"@babel/plugin-syntax-numeric-separator@^7.10.1", "@babel/plugin-syntax-numeric-separator@^7.8.3":
version "7.10.1"
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.1.tgz#25761ee7410bc8cf97327ba741ee94e4a61b7d99"
integrity sha512-uTd0OsHrpe3tH5gRPTxG8Voh99/WCU78vIm5NMRYPAqC8lR4vajt6KkCAknCHrx24vkPdd/05yfdGSB4EIY2mg==
dependencies:
"@babel/helper-plugin-utils" "^7.10.1"
-"@babel/plugin-syntax-object-rest-spread@^7.0.0", "@babel/plugin-syntax-object-rest-spread@^7.8.0":
+"@babel/plugin-syntax-object-rest-spread@^7.8.0", "@babel/plugin-syntax-object-rest-spread@^7.8.3":
version "7.8.3"
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871"
integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==
dependencies:
"@babel/helper-plugin-utils" "^7.8.0"
-"@babel/plugin-syntax-optional-catch-binding@^7.8.0":
+"@babel/plugin-syntax-optional-catch-binding@^7.8.0", "@babel/plugin-syntax-optional-catch-binding@^7.8.3":
version "7.8.3"
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1"
integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==
dependencies:
"@babel/helper-plugin-utils" "^7.8.0"
-"@babel/plugin-syntax-optional-chaining@^7.8.0":
+"@babel/plugin-syntax-optional-chaining@^7.8.0", "@babel/plugin-syntax-optional-chaining@^7.8.3":
version "7.8.3"
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a"
integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==
@@ -545,13 +558,13 @@
babel-plugin-dynamic-import-node "^2.3.3"
"@babel/plugin-transform-modules-commonjs@^7.10.1", "@babel/plugin-transform-modules-commonjs@^7.2.0":
- version "7.10.1"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.10.1.tgz#d5ff4b4413ed97ffded99961056e1fb980fb9301"
- integrity sha512-AQG4fc3KOah0vdITwt7Gi6hD9BtQP/8bhem7OjbaMoRNCH5Djx42O2vYMfau7QnAzQCa+RJnhJBmFFMGpQEzrg==
+ version "7.10.4"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.10.4.tgz#66667c3eeda1ebf7896d41f1f16b17105a2fbca0"
+ integrity sha512-Xj7Uq5o80HDLlW64rVfDBhao6OX89HKUmb+9vWYaLXBZOma4gA6tw4Ni1O5qVDoZWUV0fxMYA0aYzOawz0l+1w==
dependencies:
- "@babel/helper-module-transforms" "^7.10.1"
- "@babel/helper-plugin-utils" "^7.10.1"
- "@babel/helper-simple-access" "^7.10.1"
+ "@babel/helper-module-transforms" "^7.10.4"
+ "@babel/helper-plugin-utils" "^7.10.4"
+ "@babel/helper-simple-access" "^7.10.4"
babel-plugin-dynamic-import-node "^2.3.3"
"@babel/plugin-transform-modules-systemjs@^7.10.1":
@@ -764,10 +777,10 @@
core-js-pure "^3.0.0"
regenerator-runtime "^0.13.4"
-"@babel/runtime@^7.10.2", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.10.4.tgz#a6724f1a6b8d2f6ea5236dbfe58c7d7ea9c5eb99"
- integrity sha512-UpTN5yUJr9b4EX2CnGNWIvER7Ab83ibv0pcvvHc4UOdrBI5jb8bj+32cCwPX6xu0mt2daFNjYhoi+X7beH0RSw==
+"@babel/runtime@^7.10.2", "@babel/runtime@^7.10.3", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2":
+ version "7.11.2"
+ resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.11.2.tgz#f549c13c754cc40b87644b9fa9f09a6a95fe0736"
+ integrity sha512-TeWkU52so0mPtDcaCTxNBI/IHiz0pZgr8VEFqXFtZWpYD08ZB6FaSwVAS8MKRQAP3bYKiVjwysOJgMFY28o6Tw==
dependencies:
regenerator-runtime "^0.13.4"
@@ -776,48 +789,53 @@
resolved "https://registry.yarnpkg.com/@babel/standalone/-/standalone-7.10.2.tgz#49dbbadcbc4b199df064d7d8b3e21c915b84abdb"
integrity sha512-PNQuj9oQH6BL/3l9iiL8hJLQwX14woA2/FHcPtNIZAc7IgFZYJdtMBMXiy4xcefADHTSvoBnmc2AybrHRW1IKQ==
-"@babel/template@^7.10.1", "@babel/template@^7.4.0":
- version "7.10.1"
- resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.10.1.tgz#e167154a94cb5f14b28dc58f5356d2162f539811"
- integrity sha512-OQDg6SqvFSsc9A0ej6SKINWrpJiNonRIniYondK2ViKhB06i3c0s+76XUft71iqBEe9S1OKsHwPAjfHnuvnCig==
- dependencies:
- "@babel/code-frame" "^7.10.1"
- "@babel/parser" "^7.10.1"
- "@babel/types" "^7.10.1"
-
-"@babel/traverse@^7.0.0", "@babel/traverse@^7.1.0", "@babel/traverse@^7.10.1", "@babel/traverse@^7.4.3":
- version "7.10.1"
- resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.10.1.tgz#bbcef3031e4152a6c0b50147f4958df54ca0dd27"
- integrity sha512-C/cTuXeKt85K+p08jN6vMDz8vSV0vZcI0wmQ36o6mjbuo++kPMdpOYw23W2XH04dbRt9/nMEfA4W3eR21CD+TQ==
- dependencies:
- "@babel/code-frame" "^7.10.1"
- "@babel/generator" "^7.10.1"
- "@babel/helper-function-name" "^7.10.1"
- "@babel/helper-split-export-declaration" "^7.10.1"
- "@babel/parser" "^7.10.1"
- "@babel/types" "^7.10.1"
+"@babel/template@^7.10.1", "@babel/template@^7.10.4", "@babel/template@^7.3.3", "@babel/template@^7.4.0":
+ version "7.10.4"
+ resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.10.4.tgz#3251996c4200ebc71d1a8fc405fba940f36ba278"
+ integrity sha512-ZCjD27cGJFUB6nmCB1Enki3r+L5kJveX9pq1SvAUKoICy6CZ9yD8xO086YXdYhvNjBdnekm4ZnaP5yC8Cs/1tA==
+ dependencies:
+ "@babel/code-frame" "^7.10.4"
+ "@babel/parser" "^7.10.4"
+ "@babel/types" "^7.10.4"
+
+"@babel/traverse@^7.0.0", "@babel/traverse@^7.1.0", "@babel/traverse@^7.10.1", "@babel/traverse@^7.10.4", "@babel/traverse@^7.4.3":
+ version "7.11.5"
+ resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.11.5.tgz#be777b93b518eb6d76ee2e1ea1d143daa11e61c3"
+ integrity sha512-EjiPXt+r7LiCZXEfRpSJd+jUMnBd4/9OUv7Nx3+0u9+eimMwJmG0Q98lw4/289JCoxSE8OolDMNZaaF/JZ69WQ==
+ dependencies:
+ "@babel/code-frame" "^7.10.4"
+ "@babel/generator" "^7.11.5"
+ "@babel/helper-function-name" "^7.10.4"
+ "@babel/helper-split-export-declaration" "^7.11.0"
+ "@babel/parser" "^7.11.5"
+ "@babel/types" "^7.11.5"
debug "^4.1.0"
globals "^11.1.0"
- lodash "^4.17.13"
+ lodash "^4.17.19"
-"@babel/types@^7.0.0", "@babel/types@^7.0.0-beta.49", "@babel/types@^7.10.1", "@babel/types@^7.10.2", "@babel/types@^7.3.0", "@babel/types@^7.4.0", "@babel/types@^7.4.4":
- version "7.10.2"
- resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.10.2.tgz#30283be31cad0dbf6fb00bd40641ca0ea675172d"
- integrity sha512-AD3AwWBSz0AWF0AkCN9VPiWrvldXq+/e3cHa4J89vo4ymjz1XwrBFFVZmkJTsQIPNk+ZVomPSXUJqq8yyjZsng==
+"@babel/types@^7.0.0", "@babel/types@^7.0.0-beta.49", "@babel/types@^7.10.1", "@babel/types@^7.10.2", "@babel/types@^7.10.4", "@babel/types@^7.11.0", "@babel/types@^7.11.5", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.0", "@babel/types@^7.4.4":
+ version "7.11.5"
+ resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.11.5.tgz#d9de577d01252d77c6800cee039ee64faf75662d"
+ integrity sha512-bvM7Qz6eKnJVFIn+1LPtjlBFPVN5jNDc1XmN15vWe7Q3DPBufWWsLiIvUu7xW87uTG6QoggpIDnUgLQvPheU+Q==
dependencies:
- "@babel/helper-validator-identifier" "^7.10.1"
- lodash "^4.17.13"
+ "@babel/helper-validator-identifier" "^7.10.4"
+ lodash "^4.17.19"
to-fast-properties "^2.0.0"
+"@bcoe/v8-coverage@^0.2.3":
+ version "0.2.3"
+ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"
+ integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==
+
"@braintree/sanitize-url@^3.1.0":
version "3.1.0"
resolved "https://registry.yarnpkg.com/@braintree/sanitize-url/-/sanitize-url-3.1.0.tgz#8ff71d51053cd5ee4981e5a501d80a536244f7fd"
integrity sha512-GcIY79elgB+azP74j8vqkiXz8xLFfIzbQJdlwOPisgbKT00tviJQuEghOXSMVxJ00HoYJbGswr4kcllUc4xCcg==
"@cnakazawa/watch@^1.0.3":
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/@cnakazawa/watch/-/watch-1.0.3.tgz#099139eaec7ebf07a27c1786a3ff64f39464d2ef"
- integrity sha512-r5160ogAvGyHsal38Kux7YYtodEKOj89RGb28ht1jh3SJb08VwRwAKKJL0bGb04Zd/3r9FL3BFIc3bBidYffCA==
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/@cnakazawa/watch/-/watch-1.0.4.tgz#f864ae85004d0fcab6f50be9141c4da368d1656a"
+ integrity sha512-v9kIhKwjeZThiWrLmj0y17CWoyddASLj9O2yvbZkbvw/N3rWOYy9zkV66ursAoVr0mV15bL8g0c4QZUE6cdDoQ==
dependencies:
exec-sh "^0.3.2"
minimist "^1.2.0"
@@ -843,21 +861,21 @@
eslint-plugin-vue "^6.2.1"
vue-eslint-parser "^7.0.0"
-"@gitlab/svgs@1.164.0":
- version "1.164.0"
- resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.164.0.tgz#6cefad871c45f945ef92b99015d0f510b1d2de4a"
- integrity sha512-a9e/cYUc1QQk7azjH4x/m6/p3icavwGEi5F9ipNlDqiJtUor5tqojxvMxPOhuVbN/mTwnC6lGsSZg4tqTsdJAQ==
+"@gitlab/svgs@1.171.0":
+ version "1.171.0"
+ resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.171.0.tgz#abc3092bf804f0898301626130e0f3231834924a"
+ integrity sha512-TPfdqIxQDda+0CQHhb9XdF50lmqDmADu6yT8R4oZi6BoUtWLdiHbyFt+RnVU6t7EmjIKicNAii7Ga+f2ljCfUA==
-"@gitlab/ui@21.3.1":
- version "21.3.1"
- resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-21.3.1.tgz#027b767804540539da73d4874370895d7398adea"
- integrity sha512-ynyg8i8W8Ud+GoySr4hAjJoW55kWMwSEFLX5MEX8CbdqGurkTLqHYLLpXPBSSnVEcw4stR+bFbKSc35rmBkWPA==
+"@gitlab/ui@21.33.0":
+ version "21.33.0"
+ resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-21.33.0.tgz#83dd7e4d65557f7b82ce1f9d7d6e7a1c54cb3dbc"
+ integrity sha512-UBLTz5A1z1Usxw2yfjFNuQ1Ccgx7dYD3M+lDfewDYlU48s0PY7Hm/VXsd543XIuIf+4GEJ1b43kptEZI1wtrbQ==
dependencies:
"@babel/standalone" "^7.0.0"
"@gitlab/vue-toasted" "^1.3.0"
bootstrap-vue "2.13.1"
copy-to-clipboard "^3.0.8"
- dompurify "^2.0.12"
+ dompurify "^2.1.1"
echarts "^4.2.1"
highlight.js "^9.13.1"
js-beautify "^1.8.8"
@@ -877,162 +895,181 @@
resolved "https://registry.yarnpkg.com/@gitlab/vue-toasted/-/vue-toasted-1.3.0.tgz#f21550d4ce406ee5f99447a02abf36250ecc922d"
integrity sha512-xexu7YbbIkQS5FDqPaewrOTQ4/myth5VyU8+hWZ+Tj1e5CuAlDNha3dHbvwyLW8/2flm/2mfslFNPAX2DRe8ZQ==
-"@jest/console@^24.7.1":
- version "24.7.1"
- resolved "https://registry.yarnpkg.com/@jest/console/-/console-24.7.1.tgz#32a9e42535a97aedfe037e725bd67e954b459545"
- integrity sha512-iNhtIy2M8bXlAOULWVTUxmnelTLFneTNEkHCgPmgd+zNwy9zVddJ6oS5rZ9iwoscNdT5mMwUd0C51v/fSlzItg==
+"@istanbuljs/load-nyc-config@^1.0.0":
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced"
+ integrity sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==
dependencies:
- "@jest/source-map" "^24.3.0"
- chalk "^2.0.1"
- slash "^2.0.0"
+ camelcase "^5.3.1"
+ find-up "^4.1.0"
+ get-package-type "^0.1.0"
+ js-yaml "^3.13.1"
+ resolve-from "^5.0.0"
-"@jest/core@^24.8.0":
- version "24.8.0"
- resolved "https://registry.yarnpkg.com/@jest/core/-/core-24.8.0.tgz#fbbdcd42a41d0d39cddbc9f520c8bab0c33eed5b"
- integrity sha512-R9rhAJwCBQzaRnrRgAdVfnglUuATXdwTRsYqs6NMdVcAl5euG8LtWDe+fVkN27YfKVBW61IojVsXKaOmSnqd/A==
- dependencies:
- "@jest/console" "^24.7.1"
- "@jest/reporters" "^24.8.0"
- "@jest/test-result" "^24.8.0"
- "@jest/transform" "^24.8.0"
- "@jest/types" "^24.8.0"
- ansi-escapes "^3.0.0"
- chalk "^2.0.1"
- exit "^0.1.2"
- graceful-fs "^4.1.15"
- jest-changed-files "^24.8.0"
- jest-config "^24.8.0"
- jest-haste-map "^24.8.0"
- jest-message-util "^24.8.0"
- jest-regex-util "^24.3.0"
- jest-resolve-dependencies "^24.8.0"
- jest-runner "^24.8.0"
- jest-runtime "^24.8.0"
- jest-snapshot "^24.8.0"
- jest-util "^24.8.0"
- jest-validate "^24.8.0"
- jest-watcher "^24.8.0"
- micromatch "^3.1.10"
- p-each-series "^1.0.0"
- pirates "^4.0.1"
- realpath-native "^1.1.0"
- rimraf "^2.5.4"
- strip-ansi "^5.0.0"
+"@istanbuljs/schema@^0.1.2":
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.2.tgz#26520bf09abe4a5644cd5414e37125a8954241dd"
+ integrity sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw==
-"@jest/environment@^24.8.0":
- version "24.8.0"
- resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-24.8.0.tgz#0342261383c776bdd652168f68065ef144af0eac"
- integrity sha512-vlGt2HLg7qM+vtBrSkjDxk9K0YtRBi7HfRFaDxoRtyi+DyVChzhF20duvpdAnKVBV6W5tym8jm0U9EfXbDk1tw==
+"@jest/console@^26.5.2":
+ version "26.5.2"
+ resolved "https://registry.yarnpkg.com/@jest/console/-/console-26.5.2.tgz#94fc4865b1abed7c352b5e21e6c57be4b95604a6"
+ integrity sha512-lJELzKINpF1v74DXHbCRIkQ/+nUV1M+ntj+X1J8LxCgpmJZjfLmhFejiMSbjjD66fayxl5Z06tbs3HMyuik6rw==
dependencies:
- "@jest/fake-timers" "^24.8.0"
- "@jest/transform" "^24.8.0"
- "@jest/types" "^24.8.0"
- jest-mock "^24.8.0"
+ "@jest/types" "^26.5.2"
+ "@types/node" "*"
+ chalk "^4.0.0"
+ jest-message-util "^26.5.2"
+ jest-util "^26.5.2"
+ slash "^3.0.0"
-"@jest/fake-timers@^24.8.0":
- version "24.8.0"
- resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-24.8.0.tgz#2e5b80a4f78f284bcb4bd5714b8e10dd36a8d3d1"
- integrity sha512-2M4d5MufVXwi6VzZhJ9f5S/wU4ud2ck0kxPof1Iz3zWx6Y+V2eJrES9jEktB6O3o/oEyk+il/uNu9PvASjWXQw==
+"@jest/core@^26.5.2":
+ version "26.5.2"
+ resolved "https://registry.yarnpkg.com/@jest/core/-/core-26.5.2.tgz#e39f14676f4ba4632ecabfdc374071ab22131f22"
+ integrity sha512-LLTo1LQMg7eJjG/+P1NYqFof2B25EV1EqzD5FonklihG4UJKiK2JBIvWonunws6W7e+DhNLoFD+g05tCY03eyA==
dependencies:
- "@jest/types" "^24.8.0"
- jest-message-util "^24.8.0"
- jest-mock "^24.8.0"
+ "@jest/console" "^26.5.2"
+ "@jest/reporters" "^26.5.2"
+ "@jest/test-result" "^26.5.2"
+ "@jest/transform" "^26.5.2"
+ "@jest/types" "^26.5.2"
+ "@types/node" "*"
+ ansi-escapes "^4.2.1"
+ chalk "^4.0.0"
+ exit "^0.1.2"
+ graceful-fs "^4.2.4"
+ jest-changed-files "^26.5.2"
+ jest-config "^26.5.2"
+ jest-haste-map "^26.5.2"
+ jest-message-util "^26.5.2"
+ jest-regex-util "^26.0.0"
+ jest-resolve "^26.5.2"
+ jest-resolve-dependencies "^26.5.2"
+ jest-runner "^26.5.2"
+ jest-runtime "^26.5.2"
+ jest-snapshot "^26.5.2"
+ jest-util "^26.5.2"
+ jest-validate "^26.5.2"
+ jest-watcher "^26.5.2"
+ micromatch "^4.0.2"
+ p-each-series "^2.1.0"
+ rimraf "^3.0.0"
+ slash "^3.0.0"
+ strip-ansi "^6.0.0"
-"@jest/fake-timers@^25.1.0":
- version "25.5.0"
- resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-25.5.0.tgz#46352e00533c024c90c2bc2ad9f2959f7f114185"
- integrity sha512-9y2+uGnESw/oyOI3eww9yaxdZyHq7XvprfP/eeoCsjqKYts2yRlsHS/SgjPDV8FyMfn2nbMy8YzUk6nyvdLOpQ==
+"@jest/environment@^26.5.2":
+ version "26.5.2"
+ resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-26.5.2.tgz#eba3cfc698f6e03739628f699c28e8a07f5e65fe"
+ integrity sha512-YjhCD/Zhkz0/1vdlS/QN6QmuUdDkpgBdK4SdiVg4Y19e29g4VQYN5Xg8+YuHjdoWGY7wJHMxc79uDTeTOy9Ngw==
dependencies:
- "@jest/types" "^25.5.0"
- jest-message-util "^25.5.0"
- jest-mock "^25.5.0"
- jest-util "^25.5.0"
- lolex "^5.0.0"
-
-"@jest/reporters@^24.8.0":
- version "24.8.0"
- resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-24.8.0.tgz#075169cd029bddec54b8f2c0fc489fd0b9e05729"
- integrity sha512-eZ9TyUYpyIIXfYCrw0UHUWUvE35vx5I92HGMgS93Pv7du+GHIzl+/vh8Qj9MCWFK/4TqyttVBPakWMOfZRIfxw==
- dependencies:
- "@jest/environment" "^24.8.0"
- "@jest/test-result" "^24.8.0"
- "@jest/transform" "^24.8.0"
- "@jest/types" "^24.8.0"
- chalk "^2.0.1"
+ "@jest/fake-timers" "^26.5.2"
+ "@jest/types" "^26.5.2"
+ "@types/node" "*"
+ jest-mock "^26.5.2"
+
+"@jest/fake-timers@^26.5.2":
+ version "26.5.2"
+ resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-26.5.2.tgz#1291ac81680ceb0dc7daa1f92c059307eea6400a"
+ integrity sha512-09Hn5Oraqt36V1akxQeWMVL0fR9c6PnEhpgLaYvREXZJAh2H2Y+QLCsl0g7uMoJeoWJAuz4tozk1prbR1Fc1sw==
+ dependencies:
+ "@jest/types" "^26.5.2"
+ "@sinonjs/fake-timers" "^6.0.1"
+ "@types/node" "*"
+ jest-message-util "^26.5.2"
+ jest-mock "^26.5.2"
+ jest-util "^26.5.2"
+
+"@jest/globals@^26.5.2":
+ version "26.5.2"
+ resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-26.5.2.tgz#c333f82c29e19ecb609a75d1a532915a5c956c59"
+ integrity sha512-9PmnFsAUJxpPt1s/stq02acS1YHliVBDNfAWMe1bwdRr1iTCfhbNt3ERQXrO/ZfZSweftoA26Q/2yhSVSWQ3sw==
+ dependencies:
+ "@jest/environment" "^26.5.2"
+ "@jest/types" "^26.5.2"
+ expect "^26.5.2"
+
+"@jest/reporters@^26.5.2":
+ version "26.5.2"
+ resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-26.5.2.tgz#0f1c900c6af712b46853d9d486c9c0382e4050f6"
+ integrity sha512-zvq6Wvy6MmJq/0QY0YfOPb49CXKSf42wkJbrBPkeypVa8I+XDxijvFuywo6TJBX/ILPrdrlE/FW9vJZh6Rf9vA==
+ dependencies:
+ "@bcoe/v8-coverage" "^0.2.3"
+ "@jest/console" "^26.5.2"
+ "@jest/test-result" "^26.5.2"
+ "@jest/transform" "^26.5.2"
+ "@jest/types" "^26.5.2"
+ chalk "^4.0.0"
+ collect-v8-coverage "^1.0.0"
exit "^0.1.2"
glob "^7.1.2"
- istanbul-lib-coverage "^2.0.2"
- istanbul-lib-instrument "^3.0.1"
- istanbul-lib-report "^2.0.4"
- istanbul-lib-source-maps "^3.0.1"
- istanbul-reports "^2.1.1"
- jest-haste-map "^24.8.0"
- jest-resolve "^24.8.0"
- jest-runtime "^24.8.0"
- jest-util "^24.8.0"
- jest-worker "^24.6.0"
- node-notifier "^5.2.1"
- slash "^2.0.0"
+ graceful-fs "^4.2.4"
+ istanbul-lib-coverage "^3.0.0"
+ istanbul-lib-instrument "^4.0.3"
+ istanbul-lib-report "^3.0.0"
+ istanbul-lib-source-maps "^4.0.0"
+ istanbul-reports "^3.0.2"
+ jest-haste-map "^26.5.2"
+ jest-resolve "^26.5.2"
+ jest-util "^26.5.2"
+ jest-worker "^26.5.0"
+ slash "^3.0.0"
source-map "^0.6.0"
- string-length "^2.0.0"
+ string-length "^4.0.1"
+ terminal-link "^2.0.0"
+ v8-to-istanbul "^5.0.1"
+ optionalDependencies:
+ node-notifier "^8.0.0"
-"@jest/source-map@^24.3.0":
- version "24.3.0"
- resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-24.3.0.tgz#563be3aa4d224caf65ff77edc95cd1ca4da67f28"
- integrity sha512-zALZt1t2ou8le/crCeeiRYzvdnTzaIlpOWaet45lNSqNJUnXbppUUFR4ZUAlzgDmKee4Q5P/tKXypI1RiHwgag==
+"@jest/source-map@^26.5.0":
+ version "26.5.0"
+ resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-26.5.0.tgz#98792457c85bdd902365cd2847b58fff05d96367"
+ integrity sha512-jWAw9ZwYHJMe9eZq/WrsHlwF8E3hM9gynlcDpOyCb9bR8wEd9ZNBZCi7/jZyzHxC7t3thZ10gO2IDhu0bPKS5g==
dependencies:
callsites "^3.0.0"
- graceful-fs "^4.1.15"
+ graceful-fs "^4.2.4"
source-map "^0.6.0"
-"@jest/test-result@^24.8.0":
- version "24.8.0"
- resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-24.8.0.tgz#7675d0aaf9d2484caa65e048d9b467d160f8e9d3"
- integrity sha512-+YdLlxwizlfqkFDh7Mc7ONPQAhA4YylU1s529vVM1rsf67vGZH/2GGm5uO8QzPeVyaVMobCQ7FTxl38QrKRlng==
+"@jest/test-result@^26.5.2":
+ version "26.5.2"
+ resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-26.5.2.tgz#cc1a44cfd4db2ecee3fb0bc4e9fe087aa54b5230"
+ integrity sha512-E/Zp6LURJEGSCWpoMGmCFuuEI1OWuI3hmZwmULV0GsgJBh7u0rwqioxhRU95euUuviqBDN8ruX/vP/4bwYolXw==
dependencies:
- "@jest/console" "^24.7.1"
- "@jest/types" "^24.8.0"
+ "@jest/console" "^26.5.2"
+ "@jest/types" "^26.5.2"
"@types/istanbul-lib-coverage" "^2.0.0"
+ collect-v8-coverage "^1.0.0"
-"@jest/test-sequencer@^24.8.0":
- version "24.8.0"
- resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-24.8.0.tgz#2f993bcf6ef5eb4e65e8233a95a3320248cf994b"
- integrity sha512-OzL/2yHyPdCHXEzhoBuq37CE99nkme15eHkAzXRVqthreWZamEMA0WoetwstsQBCXABhczpK03JNbc4L01vvLg==
+"@jest/test-sequencer@^26.5.2":
+ version "26.5.2"
+ resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-26.5.2.tgz#c4559c7e134b27b020317303ee5399bf62917a4b"
+ integrity sha512-XmGEh7hh07H2B8mHLFCIgr7gA5Y6Hw1ZATIsbz2fOhpnQ5AnQtZk0gmP0Q5/+mVB2xygO64tVFQxOajzoptkNA==
dependencies:
- "@jest/test-result" "^24.8.0"
- jest-haste-map "^24.8.0"
- jest-runner "^24.8.0"
- jest-runtime "^24.8.0"
+ "@jest/test-result" "^26.5.2"
+ graceful-fs "^4.2.4"
+ jest-haste-map "^26.5.2"
+ jest-runner "^26.5.2"
+ jest-runtime "^26.5.2"
-"@jest/transform@^24.8.0":
- version "24.8.0"
- resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-24.8.0.tgz#628fb99dce4f9d254c6fd9341e3eea262e06fef5"
- integrity sha512-xBMfFUP7TortCs0O+Xtez2W7Zu1PLH9bvJgtraN1CDST6LBM/eTOZ9SfwS/lvV8yOfcDpFmwf9bq5cYbXvqsvA==
+"@jest/transform@^26.5.2":
+ version "26.5.2"
+ resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-26.5.2.tgz#6a0033a1d24316a1c75184d010d864f2c681bef5"
+ integrity sha512-AUNjvexh+APhhmS8S+KboPz+D3pCxPvEAGduffaAJYxIFxGi/ytZQkrqcKDUU0ERBAo5R7087fyOYr2oms1seg==
dependencies:
"@babel/core" "^7.1.0"
- "@jest/types" "^24.8.0"
- babel-plugin-istanbul "^5.1.0"
- chalk "^2.0.1"
+ "@jest/types" "^26.5.2"
+ babel-plugin-istanbul "^6.0.0"
+ chalk "^4.0.0"
convert-source-map "^1.4.0"
fast-json-stable-stringify "^2.0.0"
- graceful-fs "^4.1.15"
- jest-haste-map "^24.8.0"
- jest-regex-util "^24.3.0"
- jest-util "^24.8.0"
- micromatch "^3.1.10"
- realpath-native "^1.1.0"
- slash "^2.0.0"
+ graceful-fs "^4.2.4"
+ jest-haste-map "^26.5.2"
+ jest-regex-util "^26.0.0"
+ jest-util "^26.5.2"
+ micromatch "^4.0.2"
+ pirates "^4.0.1"
+ slash "^3.0.0"
source-map "^0.6.1"
- write-file-atomic "2.4.1"
-
-"@jest/types@^24.8.0":
- version "24.8.0"
- resolved "https://registry.yarnpkg.com/@jest/types/-/types-24.8.0.tgz#f31e25948c58f0abd8c845ae26fcea1491dea7ad"
- integrity sha512-g17UxVr2YfBtaMUxn9u/4+siG1ptg9IGYAYwvpwn61nBg779RXnjE/m7CxYcIzEt0AbHZZAHSEZNhkE2WxURVg==
- dependencies:
- "@types/istanbul-lib-coverage" "^2.0.0"
- "@types/istanbul-reports" "^1.1.1"
- "@types/yargs" "^12.0.9"
+ write-file-atomic "^3.0.0"
"@jest/types@^25.5.0":
version "25.5.0"
@@ -1044,6 +1081,17 @@
"@types/yargs" "^15.0.0"
chalk "^3.0.0"
+"@jest/types@^26.5.2":
+ version "26.5.2"
+ resolved "https://registry.yarnpkg.com/@jest/types/-/types-26.5.2.tgz#44c24f30c8ee6c7f492ead9ec3f3c62a5289756d"
+ integrity sha512-QDs5d0gYiyetI8q+2xWdkixVQMklReZr4ltw7GFDtb4fuJIBCE6mzj2LnitGqCuAlLap6wPyb8fpoHgwZz5fdg==
+ dependencies:
+ "@types/istanbul-lib-coverage" "^2.0.0"
+ "@types/istanbul-reports" "^3.0.0"
+ "@types/node" "*"
+ "@types/yargs" "^15.0.0"
+ chalk "^4.0.0"
+
"@miragejs/pretender-node-polyfill@^0.1.0":
version "0.1.2"
resolved "https://registry.yarnpkg.com/@miragejs/pretender-node-polyfill/-/pretender-node-polyfill-0.1.2.tgz#d26b6b7483fb70cd62189d05c95d2f67153e43f2"
@@ -1071,62 +1119,15 @@
consola "^2.10.1"
node-fetch "^2.6.0"
-"@rails/actioncable@^6.0.3-1":
- version "6.0.3-1"
- resolved "https://registry.yarnpkg.com/@rails/actioncable/-/actioncable-6.0.3-1.tgz#9b9eb8858a6507162911007d355d9a206e1c5caa"
- integrity sha512-szFhWD+V5TAxVNVIG16klgq+ypqA5k5AecLarTTrXgOG8cawVbQdOAwLbCmzkwiQ60rGSxAFoC1u2LrzxSK2Aw==
-
-"@sentry/browser@^5.22.3":
- version "5.22.3"
- resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-5.22.3.tgz#7a64bd1cf01bf393741a3e4bf35f82aa927f5b4e"
- integrity sha512-2TzE/CoBa5ZkvxJizDdi1Iz1ldmXSJpFQ1mL07PIXBjCt0Wxf+WOuFSj5IP4L40XHfJE5gU8wEvSH0VDR8nXtA==
- dependencies:
- "@sentry/core" "5.22.3"
- "@sentry/types" "5.22.3"
- "@sentry/utils" "5.22.3"
- tslib "^1.9.3"
-
-"@sentry/core@5.22.3":
- version "5.22.3"
- resolved "https://registry.yarnpkg.com/@sentry/core/-/core-5.22.3.tgz#030f435f2b518f282ba8bd954dac90cd70888bd7"
- integrity sha512-eGL5uUarw3o4i9QUb9JoFHnhriPpWCaqeaIBB06HUpdcvhrjoowcKZj1+WPec5lFg5XusE35vez7z/FPzmJUDw==
- dependencies:
- "@sentry/hub" "5.22.3"
- "@sentry/minimal" "5.22.3"
- "@sentry/types" "5.22.3"
- "@sentry/utils" "5.22.3"
- tslib "^1.9.3"
+"@rails/actioncable@^6.0.3-3":
+ version "6.0.3-3"
+ resolved "https://registry.yarnpkg.com/@rails/actioncable/-/actioncable-6.0.3-3.tgz#fb1a46d3d353512764d5fa3cea2f492391601b7a"
+ integrity sha512-+DEbtzvD2ITPKOGBAV0lLdUvImCsHtUYfxwW7TDKOrGNEFqgbVJij7aO6ZE8a3aDPQ7NnO/MlyrPwLVeiIZRSw==
-"@sentry/hub@5.22.3":
- version "5.22.3"
- resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-5.22.3.tgz#08309a70d2ea8d5e313d05840c1711f34f2fffe5"
- integrity sha512-INo47m6N5HFEs/7GMP9cqxOIt7rmRxdERunA3H2L37owjcr77MwHVeeJ9yawRS6FMtbWXplgWTyTIWIYOuqVbw==
- dependencies:
- "@sentry/types" "5.22.3"
- "@sentry/utils" "5.22.3"
- tslib "^1.9.3"
-
-"@sentry/minimal@5.22.3":
- version "5.22.3"
- resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-5.22.3.tgz#706e4029ae5494123d3875c658ba8911aa5cc440"
- integrity sha512-HoINpYnVYCpNjn2XIPIlqH5o4BAITpTljXjtAftOx6Hzj+Opjg8tR8PWliyKDvkXPpc4kXK9D6TpEDw8MO0wZA==
- dependencies:
- "@sentry/hub" "5.22.3"
- "@sentry/types" "5.22.3"
- tslib "^1.9.3"
-
-"@sentry/types@5.22.3":
- version "5.22.3"
- resolved "https://registry.yarnpkg.com/@sentry/types/-/types-5.22.3.tgz#d1d547b30ee8bd7771fa893af74c4f3d71f0fd18"
- integrity sha512-cv+VWK0YFgCVDvD1/HrrBWOWYG3MLuCUJRBTkV/Opdy7nkdNjhCAJQrEyMM9zX0sac8FKWKOHT0sykNh8KgmYw==
-
-"@sentry/utils@5.22.3":
- version "5.22.3"
- resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-5.22.3.tgz#e3bda3e789239eb16d436f768daa12829f33d18f"
- integrity sha512-AHNryXMBvIkIE+GQxTlmhBXD0Ksh+5w1SwM5qi6AttH+1qjWLvV6WB4+4pvVvEoS8t5F+WaVUZPQLmCCWp6zKw==
- dependencies:
- "@sentry/types" "5.22.3"
- tslib "^1.9.3"
+"@rails/ujs@^6.0.3-2":
+ version "6.0.3-2"
+ resolved "https://registry.yarnpkg.com/@rails/ujs/-/ujs-6.0.3-2.tgz#e14c1f29086858215ce7ccd9ad6d8888c458b4a3"
+ integrity sha512-WcpIEftNCfGDEgk6KerOugiet75Mir5q/HT1yt3dDhpBI91BaZ15lfSQIsZwMw2nyeDz9A9QBz8dAFAd4gXIzg==
"@sindresorhus/is@^0.14.0":
version "0.14.0"
@@ -1134,12 +1135,19 @@
integrity sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==
"@sinonjs/commons@^1.7.0":
- version "1.8.0"
- resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.0.tgz#c8d68821a854c555bba172f3b06959a0039b236d"
- integrity sha512-wEj54PfsZ5jGSwMX68G8ZXFawcSglQSXqCftWX3ec8MDUzQdHgcKvw97awHbY0efQEL5iKUOAmmVtoYgmrSG4Q==
+ version "1.8.1"
+ resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.1.tgz#e7df00f98a203324f6dc7cc606cad9d4a8ab2217"
+ integrity sha512-892K+kWUUi3cl+LlqEWIDrhvLgdL79tECi8JZUyq6IviKy/DNhuzCRlbHUjxK89f4ypPMMaFnFuR9Ie6DoIMsw==
dependencies:
type-detect "4.0.8"
+"@sinonjs/fake-timers@^6.0.1":
+ version "6.0.1"
+ resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz#293674fccb3262ac782c7aadfdeca86b10c75c40"
+ integrity sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA==
+ dependencies:
+ "@sinonjs/commons" "^1.7.0"
+
"@sourcegraph/code-host-integration@0.0.50":
version "0.0.50"
resolved "https://registry.yarnpkg.com/@sourcegraph/code-host-integration/-/code-host-integration-0.0.50.tgz#3f91be4c1b117efbf3d49c73033a6b1880db1c70"
@@ -1153,14 +1161,17 @@
defer-to-connect "^1.0.1"
"@testing-library/dom@^7.16.2":
- version "7.16.2"
- resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-7.16.2.tgz#f7a20b5548817e5c7ed26077913372d977be90af"
- integrity sha512-4fT5l5L+5gfNhUZVCg0wnSszbRJ7A1ZHEz32v7OzH3mcY5lUsK++brI3IB2L9F5zO4kSDc2TRGEVa8v2hgl9vA==
- dependencies:
- "@babel/runtime" "^7.10.2"
- aria-query "^4.0.2"
- dom-accessibility-api "^0.4.5"
- pretty-format "^25.5.0"
+ version "7.24.5"
+ resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-7.24.5.tgz#862124eec8c37ad184716379f09742476b23815d"
+ integrity sha512-oyOp8R2rhmnkOjgrySb4iYc2q73dzvQUAGddpbmicGJdCf4jkLmf5U9zOyobLMLWXbIHHK4UUHHjDTH8tSPLsA==
+ dependencies:
+ "@babel/code-frame" "^7.10.4"
+ "@babel/runtime" "^7.10.3"
+ "@types/aria-query" "^4.2.0"
+ aria-query "^4.2.2"
+ chalk "^4.1.0"
+ dom-accessibility-api "^0.5.1"
+ pretty-format "^26.4.2"
"@toast-ui/editor@^2.4.0":
version "2.4.0"
@@ -1177,10 +1188,15 @@
dependencies:
"@toast-ui/editor" "^2.4.0"
-"@types/babel__core@^7.1.0":
- version "7.1.2"
- resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.2.tgz#608c74f55928033fce18b99b213c16be4b3d114f"
- integrity sha512-cfCCrFmiGY/yq0NuKNxIQvZFy9kY/1immpSpTngOnyIbD4+eJOG5mxphhHDv3CHL9GltO4GcKr54kGBg3RNdbg==
+"@types/aria-query@^4.2.0":
+ version "4.2.0"
+ resolved "https://registry.yarnpkg.com/@types/aria-query/-/aria-query-4.2.0.tgz#14264692a9d6e2fa4db3df5e56e94b5e25647ac0"
+ integrity sha512-iIgQNzCm0v7QMhhe4Jjn9uRh+I6GoPmt03CbEtwx3ao8/EfoQcmgtqH4vQ5Db/lxiIGaWDv6nwvunuh0RyX0+A==
+
+"@types/babel__core@^7.0.0", "@types/babel__core@^7.1.7":
+ version "7.1.9"
+ resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.9.tgz#77e59d438522a6fb898fa43dc3455c6e72f3963d"
+ integrity sha512-sY2RsIJ5rpER1u3/aQ8OFSI7qGIy8o1NEEbgb2UaJcvOtXOMpd39ko723NBpjQFg9SIX7TXtjejZVGeIMLhoOw==
dependencies:
"@babel/parser" "^7.1.0"
"@babel/types" "^7.0.0"
@@ -1203,10 +1219,10 @@
"@babel/parser" "^7.1.0"
"@babel/types" "^7.0.0"
-"@types/babel__traverse@*", "@types/babel__traverse@^7.0.6":
- version "7.0.6"
- resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.0.6.tgz#328dd1a8fc4cfe3c8458be9477b219ea158fd7b2"
- integrity sha512-XYVgHF2sQ0YblLRMLNPB3CkFMewzFmlDsH/TneZFHUXDlABQgh88uOxuez7ZcXxayLFrqLwtDH1t+FmlFwNZxw==
+"@types/babel__traverse@*", "@types/babel__traverse@^7.0.4", "@types/babel__traverse@^7.0.6":
+ version "7.0.15"
+ resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.0.15.tgz#db9e4238931eb69ef8aab0ad6523d4d4caa39d03"
+ integrity sha512-Pzh9O3sTK8V6I1olsXpCfj2k/ygO2q1X0vhhnDrEQyYLHZesWz+zMZMVcwXLCYf0U36EtmyYaFGPfXlTtDHe3A==
dependencies:
"@babel/types" "^7.3.0"
@@ -1241,10 +1257,17 @@
"@types/minimatch" "*"
"@types/node" "*"
-"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0":
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz#42995b446db9a48a11a07ec083499a860e9138ff"
- integrity sha512-hRJD2ahnnpLgsj6KWMYSrmXkM3rm2Dl1qkx6IOFD5FnuNPXJIG5L0dhgKXCYTRMGzU4n0wImQ/xfmRc4POUFlg==
+"@types/graceful-fs@^4.1.2":
+ version "4.1.3"
+ resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.3.tgz#039af35fe26bec35003e8d86d2ee9c586354348f"
+ integrity sha512-AiHRaEB50LQg0pZmm659vNBb9f4SJ0qrAnteuzhSeAUcJKxoYgEnprg/83kppCnc2zvtCKbdZry1a5pVY3lOTQ==
+ dependencies:
+ "@types/node" "*"
+
+"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1":
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.2.tgz#79d7a78bad4219f4c03d6557a1c72d9ca6ba62d5"
+ integrity sha512-rsZg7eL+Xcxsxk2XlBt9KcG8nOp9iYdKCOikY9x2RFJCyOdNj4MKPQty0e8oZr29vVAzKXr1BmR+kZauti3o1w==
"@types/istanbul-lib-report@*":
version "1.1.1"
@@ -1261,6 +1284,21 @@
"@types/istanbul-lib-coverage" "*"
"@types/istanbul-lib-report" "*"
+"@types/istanbul-reports@^3.0.0":
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.0.tgz#508b13aa344fa4976234e75dddcc34925737d821"
+ integrity sha512-nwKNbvnwJ2/mndE9ItP/zc2TCzw6uuodnF4EHYWD+gCQDVBuRQL5UzbZD0/ezy1iKsFU2ZQiDqg4M9dN4+wZgA==
+ dependencies:
+ "@types/istanbul-lib-report" "*"
+
+"@types/jest@26.x":
+ version "26.0.14"
+ resolved "https://registry.yarnpkg.com/@types/jest/-/jest-26.0.14.tgz#078695f8f65cb55c5a98450d65083b2b73e5a3f3"
+ integrity sha512-Hz5q8Vu0D288x3iWXePSn53W7hAjP0H7EQ6QvDO9c7t46mR0lNOLlfuwQ+JkVxuhygHzlzPX+0jKdA3ZgSh+Vg==
+ dependencies:
+ jest-diff "^25.2.1"
+ pretty-format "^25.2.1"
+
"@types/json-schema@^7.0.3":
version "7.0.4"
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.4.tgz#38fd73ddfd9b55abb1e1b2ed578cb55bd7b7d339"
@@ -1276,15 +1314,25 @@
resolved "https://registry.yarnpkg.com/@types/node/-/node-10.12.9.tgz#a07bfa74331471e1dc22a47eb72026843f7b95c8"
integrity sha512-eajkMXG812/w3w4a1OcBlaTwsFPO5F7fJ/amy+tieQxEMWBlbV1JGSjkFM+zkHNf81Cad+dfIRA+IBkvmvdAeA==
+"@types/normalize-package-data@^2.4.0":
+ version "2.4.0"
+ resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz#e486d0d97396d79beedd0a6e33f4534ff6b4973e"
+ integrity sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==
+
"@types/parse5@^5":
version "5.0.0"
resolved "https://registry.yarnpkg.com/@types/parse5/-/parse5-5.0.0.tgz#9ae2106efc443d7c1e26570aa8247828c9c80f11"
integrity sha512-J5D3z703XTDIGQFYXsnU9uRCW9e9mMEFO0Kpe6kykyiboqziru/RlZ0hM2P+PKTG4NHG1SjLrqae/NrV2iJApQ==
-"@types/stack-utils@^1.0.1":
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-1.0.1.tgz#0a851d3bd96498fa25c33ab7278ed3bd65f06c3e"
- integrity sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw==
+"@types/prettier@^2.0.0":
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.0.2.tgz#5bb52ee68d0f8efa9cc0099920e56be6cc4e37f3"
+ integrity sha512-IkVfat549ggtkZUthUzEX49562eGikhSYeVGX97SkMFn+sTZrgRewXjQ4tPKFPCykZHkX1Zfd9OoELGqKU2jJA==
+
+"@types/stack-utils@^2.0.0":
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.0.tgz#7036640b4e21cc2f259ae826ce843d277dad8cff"
+ integrity sha512-RJJrrySY7A8havqpGObOB4W92QXKJo63/jFLLgpvOtsGUqbQZ9Sbgl35KMm1DjC6j7AvmmU2bIno+3IyEaemaw==
"@types/tern@*":
version "0.23.3"
@@ -1320,11 +1368,6 @@
resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-15.0.0.tgz#cb3f9f741869e20cce330ffbeb9271590483882d"
integrity sha512-FA/BWv8t8ZWJ+gEOnLLd8ygxH/2UFbAvgEonyfN6yWGLKc7zVjbpl2Y4CTjid9h2RfgPP6SEt6uHwEOply00yw==
-"@types/yargs@^12.0.2", "@types/yargs@^12.0.9":
- version "12.0.12"
- resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-12.0.12.tgz#45dd1d0638e8c8f153e87d296907659296873916"
- integrity sha512-SOhuU4wNBxhhTHxYaiG5NY4HBhDIDnJF60GU+2LqHAdKKer86//e4yg69aENCtQ04n0ovz+tq2YPME5t5yp4pw==
-
"@types/yargs@^15.0.0":
version "15.0.5"
resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-15.0.5.tgz#947e9a6561483bdee9adffc983e91a6902af8b79"
@@ -1360,21 +1403,6 @@
semver "^6.3.0"
tsutils "^3.17.1"
-"@vue/component-compiler-utils@^2.4.0":
- version "2.6.0"
- resolved "https://registry.yarnpkg.com/@vue/component-compiler-utils/-/component-compiler-utils-2.6.0.tgz#aa46d2a6f7647440b0b8932434d22f12371e543b"
- integrity sha512-IHjxt7LsOFYc0DkTncB7OXJL7UzwOLPPQCfEUNyxL2qt+tF12THV+EO33O1G2Uk4feMSWua3iD39Itszx0f0bw==
- dependencies:
- consolidate "^0.15.1"
- hash-sum "^1.0.2"
- lru-cache "^4.1.2"
- merge-source-map "^1.1.0"
- postcss "^7.0.14"
- postcss-selector-parser "^5.0.0"
- prettier "1.16.3"
- source-map "~0.6.1"
- vue-template-es2015-compiler "^1.9.0"
-
"@vue/component-compiler-utils@^3.1.0":
version "3.1.1"
resolved "https://registry.yarnpkg.com/@vue/component-compiler-utils/-/component-compiler-utils-3.1.1.tgz#d4ef8f80292674044ad6211e336a302e4d2a6575"
@@ -1575,15 +1603,15 @@
resolved "https://registry.yarnpkg.com/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz#e77a97fbd345b76d83245edcd17d393b1b41fb31"
integrity sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==
-abab@^2.0.0, abab@^2.0.3:
- version "2.0.3"
- resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.3.tgz#623e2075e02eb2d3f2475e49f99c91846467907a"
- integrity sha512-tsFzPpcttalNjFBCFMqsKYQcWxxen1pgJR56by//QwvJc4/OUS3kPOOttx2tSIfjsylB0pYu7f5D3K1RCxUnUg==
+abab@^2.0.3:
+ version "2.0.5"
+ resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.5.tgz#c0b678fb32d60fc1219c784d6a826fe385aeb79a"
+ integrity sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==
abbrev@1:
- version "1.0.9"
- resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.0.9.tgz#91b4792588a7738c25f35dd6f63752a2f8776135"
- integrity sha1-kbR5JYinc4wl813W9jdSovh3YTU=
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8"
+ integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==
accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.7:
version "1.3.7"
@@ -1593,14 +1621,6 @@ accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.7:
mime-types "~2.1.24"
negotiator "0.6.2"
-acorn-globals@^4.1.0:
- version "4.3.0"
- resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-4.3.0.tgz#e3b6f8da3c1552a95ae627571f7dd6923bb54103"
- integrity sha512-hMtHj3s5RnuhvHPowpBYvJVj3rAar82JiDQHvGs1zO0l10ocX/xEdBShNHTJaboucJUsScghp74pH3s7EnHHQw==
- dependencies:
- acorn "^6.0.1"
- acorn-walk "^6.0.1"
-
acorn-globals@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-6.0.0.tgz#46cdd39f0f8ff08a876619b55f5ac8a6dc770b45"
@@ -1614,30 +1634,25 @@ acorn-jsx@^5.1.0:
resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.1.0.tgz#294adb71b57398b0680015f0a38c563ee1db5384"
integrity sha512-tMUqwBWfLFbJbizRmEcWSLw6HnFzfdJs2sOJEOwwtVPMoH/0Ay+E703oZz78VSXZiiDcZrQ5XKjPIUQixhmgVw==
-acorn-walk@^6.0.1, acorn-walk@^6.1.1:
+acorn-walk@^6.1.1:
version "6.2.0"
resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-6.2.0.tgz#123cb8f3b84c2171f1f7fb252615b1c78a6b1a8c"
integrity sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA==
acorn-walk@^7.1.1:
- version "7.1.1"
- resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.1.1.tgz#345f0dffad5c735e7373d2fec9a1023e6a44b83e"
- integrity sha512-wdlPY2tm/9XBr7QkKlq0WQVgiuGTX6YWPyRyBviSoScBuLfTVQhvwg6wJ369GJ/1nPfTLMfnrFIfjqVg6d+jQQ==
-
-acorn@^5.5.3:
- version "5.7.3"
- resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.3.tgz#67aa231bf8812974b85235a96771eb6bd07ea279"
- integrity sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==
+ version "7.2.0"
+ resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc"
+ integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==
-acorn@^6.0.1, acorn@^6.0.7, acorn@^6.2.1, acorn@^6.3.0:
+acorn@^6.0.7, acorn@^6.2.1, acorn@^6.3.0:
version "6.3.0"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.3.0.tgz#0087509119ffa4fc0a0041d1e93a417e68cb856e"
integrity sha512-/czfa8BwS88b9gWQVhc8eknunSA2DoJpJyTQkhheIf5E48u1N0R4q/YxxsAeqRrmK9TQ/uYfgLDfZo91UlANIA==
acorn@^7.1.0, acorn@^7.1.1:
- version "7.2.0"
- resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.2.0.tgz#17ea7e40d7c8640ff54a694c889c26f31704effe"
- integrity sha512-apwXVmYVpQ34m/i71vrApRrRKCWQnZZF1+npOD0WV5xZFfwWOmKGQ2RWlfdy9vWITsenisM8M0Qeq8agcFHNiQ==
+ version "7.4.1"
+ resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa"
+ integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==
after@0.8.2:
version "0.8.2"
@@ -1662,10 +1677,10 @@ ajv-keywords@^3.1.0, ajv-keywords@^3.4.1:
resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.4.1.tgz#ef916e271c64ac12171fd8384eaae6b2345854da"
integrity sha512-RO1ibKvd27e6FEShVFfPALuHI3WjSVNeK5FIsmme/LYRNxjKuNj+Dt7bucLa6NdSv3JcVTyMlm9kGR84z1XpaQ==
-ajv@^6.1.0, ajv@^6.10.0, ajv@^6.10.2, ajv@^6.5.5:
- version "6.11.0"
- resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.11.0.tgz#c3607cbc8ae392d8a5a536f25b21f8e5f3f87fe9"
- integrity sha512-nCprB/0syFYy9fVYU1ox1l2KN8S9I+tziH8D4zdZuLT3N6RMlGSGt5FSTpAiHB/Whv8Qs1cWHma1aMKZyaHRKA==
+ajv@^6.1.0, ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.3:
+ version "6.12.5"
+ resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.5.tgz#19b0e8bae8f476e5ba666300387775fb1a00a4da"
+ integrity sha512-lRF8RORchjpKG50/WFf8xmg7sgCLFiYNNnqdKflk63whMQcWR5ngGjiSXkL9bjxy6B2npOK2HSMN49jEBMSkag==
dependencies:
fast-deep-equal "^3.1.1"
fast-json-stable-stringify "^2.0.0"
@@ -1689,11 +1704,6 @@ ansi-colors@^3.0.0:
resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.4.tgz#e3a3da4bfbae6c86a9c285625de124a234026fbf"
integrity sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==
-ansi-escapes@^3.0.0:
- version "3.2.0"
- resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b"
- integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==
-
ansi-escapes@^4.2.1:
version "4.3.0"
resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.0.tgz#a4ce2b33d6b214b7950d8595c212f12ac9cc569d"
@@ -1716,7 +1726,7 @@ ansi-regex@^3.0.0:
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998"
integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=
-ansi-regex@^4.0.0, ansi-regex@^4.1.0:
+ansi-regex@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997"
integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==
@@ -1754,7 +1764,7 @@ anymatch@^2.0.0:
micromatch "^3.1.4"
normalize-path "^2.1.1"
-anymatch@~3.1.1:
+anymatch@^3.0.3, anymatch@~3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.1.tgz#c55ecf02185e2469259399310c173ce31233b142"
integrity sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==
@@ -1879,10 +1889,10 @@ argparse@^1.0.7:
dependencies:
sprintf-js "~1.0.2"
-aria-query@^4.0.2:
- version "4.2.0"
- resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-4.2.0.tgz#3774158e138a84c4790b58afc17e09711071d888"
- integrity sha512-tpVyXGt6gJVTVwCmu8qgBkDHhvtQ/es80y6J8ziybiwQU/x+LnCy+v8p9CWOTHv3i1BMnH5/IfzMpuTcFPCMQA==
+aria-query@^4.2.2:
+ version "4.2.2"
+ resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-4.2.2.tgz#0d2ca6c9aceb56b8977e9fed6aed7e15bbd2f83b"
+ integrity sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==
dependencies:
"@babel/runtime" "^7.10.2"
"@babel/runtime-corejs3" "^7.10.2"
@@ -1902,11 +1912,6 @@ arr-union@^3.1.0:
resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4"
integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=
-array-equal@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93"
- integrity sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=
-
array-find-index@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1"
@@ -2030,7 +2035,7 @@ asynckit@^0.4.0:
resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
integrity sha1-x57Zf380y48robyXkLzDZkdLS3k=
-atob@^2.1.1:
+atob@^2.1.2:
version "2.1.2"
resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9"
integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==
@@ -2074,9 +2079,9 @@ aws-sign2@~0.7.0:
integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=
aws4@^1.8.0:
- version "1.8.0"
- resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f"
- integrity sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==
+ version "1.10.1"
+ resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.10.1.tgz#e1e82e4f3e999e2cfd61b161280d16a111f86428"
+ integrity sha512-zg7Hz2k5lI8kb7U32998pRRFin7zJlkfezGJjUc2heaD4Pw2wObakCDVzkKztTm/Ln7eiVvYsjqak0Ed4LkMDA==
axios-mock-adapter@^1.15.0:
version "1.15.0"
@@ -2104,18 +2109,19 @@ babel-eslint@^10.0.3:
eslint-visitor-keys "^1.0.0"
resolve "^1.12.0"
-babel-jest@^24.1.0, babel-jest@^24.8.0:
- version "24.8.0"
- resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-24.8.0.tgz#5c15ff2b28e20b0f45df43fe6b7f2aae93dba589"
- integrity sha512-+5/kaZt4I9efoXzPlZASyK/lN9qdRKmmUav9smVc0ruPQD7IsfucQ87gpOE8mn2jbDuS6M/YOW6n3v9ZoIfgnw==
- dependencies:
- "@jest/transform" "^24.8.0"
- "@jest/types" "^24.8.0"
- "@types/babel__core" "^7.1.0"
- babel-plugin-istanbul "^5.1.0"
- babel-preset-jest "^24.6.0"
- chalk "^2.4.2"
- slash "^2.0.0"
+babel-jest@^26.5.2:
+ version "26.5.2"
+ resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-26.5.2.tgz#164f367a35946c6cf54eaccde8762dec50422250"
+ integrity sha512-U3KvymF3SczA3vOL/cgiUFOznfMET+XDIXiWnoJV45siAp2pLMG8i2+/MGZlAC3f/F6Q40LR4M4qDrWZ9wkK8A==
+ dependencies:
+ "@jest/transform" "^26.5.2"
+ "@jest/types" "^26.5.2"
+ "@types/babel__core" "^7.1.7"
+ babel-plugin-istanbul "^6.0.0"
+ babel-preset-jest "^26.5.0"
+ chalk "^4.0.0"
+ graceful-fs "^4.2.4"
+ slash "^3.0.0"
babel-loader@^8.0.6:
version "8.0.6"
@@ -2127,27 +2133,32 @@ babel-loader@^8.0.6:
mkdirp "^0.5.1"
pify "^4.0.1"
-babel-plugin-dynamic-import-node@^2.2.0, babel-plugin-dynamic-import-node@^2.3.3:
+babel-plugin-dynamic-import-node@^2.3.3:
version "2.3.3"
resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz#84fda19c976ec5c6defef57f9427b3def66e17a3"
integrity sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==
dependencies:
object.assign "^4.1.0"
-babel-plugin-istanbul@^5.1.0:
- version "5.1.0"
- resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-5.1.0.tgz#6892f529eff65a3e2d33d87dc5888ffa2ecd4a30"
- integrity sha512-CLoXPRSUWiR8yao8bShqZUIC6qLfZVVY3X1wj+QPNXu0wfmrRRfarh1LYy+dYMVI+bDj0ghy3tuqFFRFZmL1Nw==
- dependencies:
- find-up "^3.0.0"
- istanbul-lib-instrument "^3.0.0"
- test-exclude "^5.0.0"
-
-babel-plugin-jest-hoist@^24.6.0:
- version "24.6.0"
- resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-24.6.0.tgz#f7f7f7ad150ee96d7a5e8e2c5da8319579e78019"
- integrity sha512-3pKNH6hMt9SbOv0F3WVmy5CWQ4uogS3k0GY5XLyQHJ9EGpAT9XWkFd2ZiXXtkwFHdAHa5j7w7kfxSP5lAIwu7w==
+babel-plugin-istanbul@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.0.0.tgz#e159ccdc9af95e0b570c75b4573b7c34d671d765"
+ integrity sha512-AF55rZXpe7trmEylbaE1Gv54wn6rwU03aptvRoVIGP8YykoSxqdVLV1TfwflBCE/QtHmqtP8SWlTENqbK8GCSQ==
dependencies:
+ "@babel/helper-plugin-utils" "^7.0.0"
+ "@istanbuljs/load-nyc-config" "^1.0.0"
+ "@istanbuljs/schema" "^0.1.2"
+ istanbul-lib-instrument "^4.0.0"
+ test-exclude "^6.0.0"
+
+babel-plugin-jest-hoist@^26.5.0:
+ version "26.5.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-26.5.0.tgz#3916b3a28129c29528de91e5784a44680db46385"
+ integrity sha512-ck17uZFD3CDfuwCLATWZxkkuGGFhMij8quP8CNhwj8ek1mqFgbFzRJ30xwC04LLscj/aKsVFfRST+b5PT7rSuw==
+ dependencies:
+ "@babel/template" "^7.3.3"
+ "@babel/types" "^7.3.3"
+ "@types/babel__core" "^7.0.0"
"@types/babel__traverse" "^7.0.6"
babel-plugin-lodash@^3.3.4:
@@ -2161,13 +2172,30 @@ babel-plugin-lodash@^3.3.4:
lodash "^4.17.10"
require-package-name "^2.0.1"
-babel-preset-jest@^24.6.0:
- version "24.6.0"
- resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-24.6.0.tgz#66f06136eefce87797539c0d63f1769cc3915984"
- integrity sha512-pdZqLEdmy1ZK5kyRUfvBb2IfTPb2BUvIJczlPspS8fWmBQslNNDBqVfh7BW5leOVJMDZKzjD8XEyABTk6gQ5yw==
- dependencies:
- "@babel/plugin-syntax-object-rest-spread" "^7.0.0"
- babel-plugin-jest-hoist "^24.6.0"
+babel-preset-current-node-syntax@^0.1.3:
+ version "0.1.4"
+ resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-0.1.4.tgz#826f1f8e7245ad534714ba001f84f7e906c3b615"
+ integrity sha512-5/INNCYhUGqw7VbVjT/hb3ucjgkVHKXY7lX3ZjlN4gm565VyFmJUrJ/h+h16ECVB38R/9SF6aACydpKMLZ/c9w==
+ dependencies:
+ "@babel/plugin-syntax-async-generators" "^7.8.4"
+ "@babel/plugin-syntax-bigint" "^7.8.3"
+ "@babel/plugin-syntax-class-properties" "^7.8.3"
+ "@babel/plugin-syntax-import-meta" "^7.8.3"
+ "@babel/plugin-syntax-json-strings" "^7.8.3"
+ "@babel/plugin-syntax-logical-assignment-operators" "^7.8.3"
+ "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3"
+ "@babel/plugin-syntax-numeric-separator" "^7.8.3"
+ "@babel/plugin-syntax-object-rest-spread" "^7.8.3"
+ "@babel/plugin-syntax-optional-catch-binding" "^7.8.3"
+ "@babel/plugin-syntax-optional-chaining" "^7.8.3"
+
+babel-preset-jest@^26.5.0:
+ version "26.5.0"
+ resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-26.5.0.tgz#f1b166045cd21437d1188d29f7fba470d5bdb0e7"
+ integrity sha512-F2vTluljhqkiGSJGBg/jOruA8vIIIL11YrxRcO7nviNTMbbofPSHwnm8mgP7d/wS7wRSexRoI6X1A6T74d4LQA==
+ dependencies:
+ babel-plugin-jest-hoist "^26.5.0"
+ babel-preset-current-node-syntax "^0.1.3"
babylon@7.0.0-beta.19:
version "7.0.0-beta.19"
@@ -2261,13 +2289,6 @@ binaryextensions@2:
resolved "https://registry.yarnpkg.com/binaryextensions/-/binaryextensions-2.1.1.tgz#3209a51ca4a4ad541a3b8d3d6a6d5b83a2485935"
integrity sha512-XBaoWE9RW8pPdPQNibZsW2zh8TW6gcarXp1FZPwT8Uop8ScSNldJEWf2k9l3HeTqdrEwsOsFcq74RiJECW34yA==
-bindings@^1.5.0:
- version "1.5.0"
- resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df"
- integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==
- dependencies:
- file-uri-to-path "1.0.0"
-
blob@0.0.4:
version "0.0.4"
resolved "https://registry.yarnpkg.com/blob/-/blob-0.0.4.tgz#bcf13052ca54463f30f9fc7e95b9a47630a94921"
@@ -2389,13 +2410,6 @@ browser-process-hrtime@^1.0.0:
resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz#3c9b4b7d782c8121e56f10106d84c0d0ffc94626"
integrity sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==
-browser-resolve@^1.11.3:
- version "1.11.3"
- resolved "https://registry.yarnpkg.com/browser-resolve/-/browser-resolve-1.11.3.tgz#9b7cbb3d0f510e4cb86bdbd796124d28b5890af6"
- integrity sha512-exDi1BYWB/6raKHmDTCicQfTkqwN5fioMFV4j8BsfMU4R2DK/QfZfK7kOVkmWCNANf0snkBzqGqAJBao9gZMdQ==
- dependencies:
- resolve "1.1.7"
-
browserify-aes@^1.0.0, browserify-aes@^1.0.4:
version "1.1.1"
resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.1.1.tgz#38b7ab55edb806ff2dcda1a7f1620773a477c49f"
@@ -2471,10 +2485,10 @@ bs-logger@0.x:
dependencies:
fast-json-stable-stringify "2.x"
-bser@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/bser/-/bser-2.0.0.tgz#9ac78d3ed5d915804fd87acb158bc797147a1719"
- integrity sha1-mseNPtXZFYBP2HrLFYvHlxR6Fxk=
+bser@2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05"
+ integrity sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==
dependencies:
node-int64 "^0.4.0"
@@ -2671,11 +2685,6 @@ camelcase@^2.0.0:
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f"
integrity sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=
-camelcase@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a"
- integrity sha1-MvxLn82vhF/N9+c7uXysImHwqwo=
-
camelcase@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd"
@@ -2686,6 +2695,11 @@ camelcase@^5.0.0, camelcase@^5.2.0, camelcase@^5.3.1:
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320"
integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==
+camelcase@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.0.0.tgz#5259f7c30e35e278f1bdc2a4d91230b37cad981e"
+ integrity sha512-8KMDF1Vz2gzOq54ONPJS65IvTUaB1cHJ2DMM7MbPmLZljDH1qpzzLsWdiN9pHh6qvkRVDTi/07+eNGch/oLU4w==
+
caniuse-lite@^1.0.30000980, caniuse-lite@^1.0.30001043:
version "1.0.30001081"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001081.tgz#40615a3c416a047c5a4d45673e5257bf128eb3b5"
@@ -2743,6 +2757,19 @@ chalk@^3.0.0:
ansi-styles "^4.1.0"
supports-color "^7.1.0"
+chalk@^4.0.0, chalk@^4.1.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.0.tgz#4e14870a618d9e2edd97dd8345fd9d9dc315646a"
+ integrity sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==
+ dependencies:
+ ansi-styles "^4.1.0"
+ supports-color "^7.1.0"
+
+char-regex@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf"
+ integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==
+
character-entities-html4@^1.0.0:
version "1.1.2"
resolved "https://registry.yarnpkg.com/character-entities-html4/-/character-entities-html4-1.1.2.tgz#c44fdde3ce66b52e8d321d6c1bf46101f0150610"
@@ -2875,15 +2902,6 @@ clipboard@^2.0.0:
select "^1.1.2"
tiny-emitter "^2.0.0"
-cliui@^3.2.0:
- version "3.2.0"
- resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d"
- integrity sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=
- dependencies:
- string-width "^1.0.1"
- strip-ansi "^3.0.1"
- wrap-ansi "^2.0.0"
-
cliui@^4.0.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/cliui/-/cliui-4.1.0.tgz#348422dbe82d800b3022eef4f6ac10bf2e4d1b49"
@@ -2902,6 +2920,15 @@ cliui@^5.0.0:
strip-ansi "^5.2.0"
wrap-ansi "^5.1.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"
+
clone-deep@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387"
@@ -2964,6 +2991,11 @@ collapse-white-space@^1.0.2:
resolved "https://registry.yarnpkg.com/collapse-white-space/-/collapse-white-space-1.0.5.tgz#c2495b699ab1ed380d29a1091e01063e75dbbe3a"
integrity sha512-703bOOmytCYAX9cXYqoikYIx6twmFCXsnzRQheBcTG3nzKYBR4P/+wkYeH+Mvj7qUz8zZDtdyzbxfnEi/kYzRQ==
+collect-v8-coverage@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz#cc2c8e94fc18bbdffe64d6534570c8a673b27f59"
+ integrity sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==
+
collection-visit@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0"
@@ -3007,9 +3039,9 @@ colors@^1.1.0:
integrity sha512-mmGt/1pZqYRjMxB1axhTo16/snVZ5krrKkcmMeVKxzECMMXoCgnvTPp10QgHfcbQZw8Dq2jMNG6je4JlWU0gWg==
combined-stream@^1.0.6, combined-stream@~1.0.6:
- version "1.0.7"
- resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.7.tgz#2d1d24317afb8abe95d6d2c0b07b57813539d828"
- integrity sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==
+ version "1.0.8"
+ resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
+ integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
dependencies:
delayed-stream "~1.0.0"
@@ -3192,7 +3224,7 @@ content-type@~1.0.4:
resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b"
integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==
-convert-source-map@^1.4.0, convert-source-map@^1.7.0:
+convert-source-map@^1.4.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0:
version "1.7.0"
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442"
integrity sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==
@@ -3355,6 +3387,15 @@ cross-spawn@^3.0.0:
lru-cache "^4.0.1"
which "^1.2.9"
+cross-spawn@^7.0.0:
+ version "7.0.3"
+ resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
+ integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==
+ dependencies:
+ path-key "^3.1.0"
+ shebang-command "^2.0.0"
+ which "^2.0.1"
+
crypt@~0.0.1:
version "0.0.2"
resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b"
@@ -3426,11 +3467,6 @@ css@^2.1.0:
source-map-resolve "^0.5.2"
urix "^0.1.0"
-cssesc@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-2.0.0.tgz#3b13bd1bb1cb36e1bcb5a4dcd27f54c5dcb35703"
- integrity sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg==
-
cssesc@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee"
@@ -3441,22 +3477,15 @@ cssfontparser@^1.2.1:
resolved "https://registry.yarnpkg.com/cssfontparser/-/cssfontparser-1.2.1.tgz#f4022fc8f9700c68029d542084afbaf425a3f3e3"
integrity sha1-9AIvyPlwDGgCnVQghK+69CWj8+M=
-cssom@0.3.x, "cssom@>= 0.3.2 < 0.4.0", cssom@~0.3.6:
- version "0.3.8"
- resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.8.tgz#9f1276f5b2b463f2114d3f2c75250af8c1a36f4a"
- integrity sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==
-
cssom@^0.4.4:
version "0.4.4"
resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.4.4.tgz#5a66cf93d2d0b661d80bf6a44fb65f5c2e4e0a10"
integrity sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==
-cssstyle@^1.0.0:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-1.1.1.tgz#18b038a9c44d65f7a8e428a653b9f6fe42faf5fb"
- integrity sha512-364AI1l/M5TYcFH83JnOH/pSqgaNnKmYgKrm0didZMGKWjQB60dymwWy1rKUgL3J1ffdq9xVi2yGLHdSjjSNog==
- dependencies:
- cssom "0.3.x"
+cssom@~0.3.6:
+ version "0.3.8"
+ resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.8.tgz#9f1276f5b2b463f2114d3f2c75250af8c1a36f4a"
+ integrity sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==
cssstyle@^2.2.0:
version "2.3.0"
@@ -3768,15 +3797,6 @@ dashdash@^1.12.0:
dependencies:
assert-plus "^1.0.0"
-data-urls@^1.0.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-1.1.0.tgz#15ee0582baa5e22bb59c77140da8f9c76963bbfe"
- integrity sha512-YTWYI9se1P55u58gL5GkQHW4P6VJBJ5iBT+B5a7i2Tjadhv52paJG0qHX4A0OR6/t52odI64KP2YvFpkDOi3eQ==
- dependencies:
- abab "^2.0.0"
- whatwg-mimetype "^2.2.0"
- whatwg-url "^7.0.0"
-
data-urls@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-2.0.0.tgz#156485a72963a970f5d5821aaf642bef2bf2db9b"
@@ -3842,15 +3862,15 @@ decamelize-keys@^1.0.0:
decamelize "^1.1.0"
map-obj "^1.0.0"
-decamelize@^1.1.0, decamelize@^1.1.1, decamelize@^1.1.2, decamelize@^1.2.0:
+decamelize@^1.1.0, decamelize@^1.1.2, decamelize@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=
decimal.js@^10.2.0:
- version "10.2.0"
- resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.2.0.tgz#39466113a9e036111d02f82489b5fd6b0b5ed231"
- integrity sha512-vDPw+rDgn3bZe1+F/pyEwb1oMG2XTlRVgAa6B4KccTEpYgF8w6eQllVbQcfIJnZyvzFtFpxnpGtx8dd7DJp/Rw==
+ version "10.2.1"
+ resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.2.1.tgz#238ae7b0f0c793d3e3cea410108b35a2c01426a3"
+ integrity sha512-KaL7+6Fw6i5A2XSnsbhm/6B+NuEA7TZ4vqxnd5tXz9sbKtrN9Srj8ab4vKVdK8YAqZO9P1kg45Y6YLoduPf+kw==
deckar01-task_list@^2.3.1:
version "2.3.1"
@@ -3889,6 +3909,11 @@ deep-is@~0.1.3:
resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34"
integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=
+deepmerge@^4.2.2:
+ version "4.2.2"
+ resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955"
+ integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==
+
default-gateway@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/default-gateway/-/default-gateway-4.2.0.tgz#167104c7500c2115f6dd69b0a536bb8ed720552b"
@@ -3994,10 +4019,10 @@ detect-file@^1.0.0:
resolved "https://registry.yarnpkg.com/detect-file/-/detect-file-1.0.0.tgz#f0d66d03672a825cb1b73bdb3fe62310c8e552b7"
integrity sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=
-detect-newline@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-2.1.0.tgz#f41f1c10be4b00e87b5f13da680759f2c5bfd3e2"
- integrity sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I=
+detect-newline@^3.0.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651"
+ integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==
detect-node@^2.0.4:
version "2.0.4"
@@ -4009,10 +4034,15 @@ di@^0.0.1:
resolved "https://registry.yarnpkg.com/di/-/di-0.0.1.tgz#806649326ceaa7caa3306d75d985ea2748ba913c"
integrity sha1-gGZJMmzqp8qjMG112YXqJ0i6kTw=
-diff-sequences@^24.3.0:
- version "24.3.0"
- resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-24.3.0.tgz#0f20e8a1df1abddaf4d9c226680952e64118b975"
- integrity sha512-xLqpez+Zj9GKSnPWS0WZw1igGocZ+uua8+y+5dDNTT934N3QuY1sp2LkHzwiaYQGz60hMq0pjAshdeXm5VUOEw==
+diff-sequences@^25.2.6:
+ version "25.2.6"
+ resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-25.2.6.tgz#5f467c00edd35352b7bca46d7927d60e687a76dd"
+ integrity sha512-Hq8o7+6GaZeoFjtpgvRBUknSXNeJiCx7V9Fr94ZMljNiCr9n9L8H8aJqgWOQiDDGdyn29fRNcDdRVJ5fdyihfg==
+
+diff-sequences@^26.5.0:
+ version "26.5.0"
+ resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-26.5.0.tgz#ef766cf09d43ed40406611f11c6d8d9dd8b2fefd"
+ integrity sha512-ZXx86srb/iYy6jG71k++wBN9P9J05UNQ5hQHQd9MtMPvcqXPx/vKU69jfHV637D00Q2gSgPk2D+jSx3l1lDW/Q==
diff@^3.2.0, diff@^3.4.0:
version "3.5.0"
@@ -4082,10 +4112,10 @@ document-register-element@1.14.3:
dependencies:
lightercollective "^0.3.0"
-dom-accessibility-api@^0.4.5:
- version "0.4.5"
- resolved "https://registry.yarnpkg.com/dom-accessibility-api/-/dom-accessibility-api-0.4.5.tgz#d9c1cefa89f509d8cf132ab5d250004d755e76e3"
- integrity sha512-HcPDilI95nKztbVikaN2vzwvmv0sE8Y2ZJFODy/m15n7mGXLeOKGiys9qWVbFbh+aq/KYj2lqMLybBOkYAEXqg==
+dom-accessibility-api@^0.5.1:
+ version "0.5.3"
+ resolved "https://registry.yarnpkg.com/dom-accessibility-api/-/dom-accessibility-api-0.5.3.tgz#0ea493c924d4070dfbf531c4aaca3d7a2c601aab"
+ integrity sha512-yfqzAi1GFxK6EoJIZKgxqJyK6j/OjEFEUi2qkNThD/kUhoCFSG1izq31B5xuxzbJBGw9/67uPtkPMYAzWL7L7Q==
dom-event-types@^1.0.0:
version "1.0.0"
@@ -4130,13 +4160,6 @@ domelementtype@^2.0.1:
resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.0.1.tgz#1f8bdfe91f5a78063274e803b4bdcedf6e94f94d"
integrity sha512-5HOHUDsYZWV8FGWN0Njbr/Rn7f/eWSQi1v7+HsUVwXgn8nWWlL64zKDkS0n8ZmQ3mlWOMuXOnR+7Nx/5tMO5AQ==
-domexception@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/domexception/-/domexception-1.0.1.tgz#937442644ca6a31261ef36e3ec677fe805582c90"
- integrity sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug==
- dependencies:
- webidl-conversions "^4.0.2"
-
domexception@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/domexception/-/domexception-2.0.1.tgz#fb44aefba793e1574b0af6aed2801d057529f304"
@@ -4151,10 +4174,10 @@ domhandler@^2.3.0:
dependencies:
domelementtype "1"
-dompurify@^2.0.11, dompurify@^2.0.12:
- version "2.0.12"
- resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.0.12.tgz#284a2b041e1c60b8e72d7b4d2fadad36141254ae"
- integrity sha512-Fl8KseK1imyhErHypFPA8qpq9gPzlsJ/EukA6yk9o0gX23p1TzC+rh9LqNg1qvErRTc0UNMYlKxEGSfSh43NDg==
+dompurify@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.1.1.tgz#b5aa988676b093a9c836d8b855680a8598af25fe"
+ integrity sha512-NijiNVkS/OL8mdQL1hUbCD6uty/cgFpmNiuFxrmJ5YPH2cXrPKIewoixoji56rbZ6XBPmtM8GA8/sf9unlSuwg==
domutils@^1.5.1:
version "1.6.2"
@@ -4261,6 +4284,11 @@ elliptic@^6.0.0:
minimalistic-assert "^1.0.0"
minimalistic-crypto-utils "^1.0.0"
+emittery@^0.7.1:
+ version "0.7.1"
+ resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.7.1.tgz#c02375a927a40948c0345cc903072597f5270451"
+ integrity sha512-d34LN4L6h18Bzz9xpoku2nPwKxCPlPMr3EEKTkoEBi+1/+b0lcRkRJ1UVyyZaKNeqGR3swcGl6s390DNO4YVgQ==
+
emoji-regex@^7.0.1, emoji-regex@^7.0.3:
version "7.0.3"
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156"
@@ -4392,7 +4420,7 @@ error-ex@^1.2.0, error-ex@^1.3.1:
dependencies:
is-arrayish "^0.2.1"
-es-abstract@^1.12.0, es-abstract@^1.17.0-next.1, es-abstract@^1.5.1, es-abstract@^1.7.0:
+es-abstract@^1.12.0, es-abstract@^1.17.0-next.1, es-abstract@^1.7.0:
version "1.17.4"
resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.4.tgz#e3aedf19706b20e7c2594c35fc0d57605a79e184"
integrity sha512-Ae3um/gb8F0mui/jPL+QiqmglkUsaQf7FwBEHYIFkztkneosu9imhqHpBzQ3h1vit8t5iQ74t6PEVvphBZiuiQ==
@@ -4438,15 +4466,20 @@ escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5, escape-string-regexp@~
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
+escape-string-regexp@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344"
+ integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==
+
escaper@^2.5.3:
version "2.5.3"
resolved "https://registry.yarnpkg.com/escaper/-/escaper-2.5.3.tgz#8b8fe90ba364054151ab7eff18b4ce43b1e13ab5"
integrity sha512-QGb9sFxBVpbzMggrKTX0ry1oiI4CSDAl9vIL702hzl1jGW8VZs7qfqTRX7WDOjoNDoEVGcEtu1ZOQgReSfT2kQ==
-escodegen@^1.14.1, escodegen@^1.9.1:
- version "1.14.2"
- resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.14.2.tgz#14ab71bf5026c2aa08173afba22c6f3173284a84"
- integrity sha512-InuOIiKk8wwuOFg6x9BQXbzjrQhtyXh46K9bqVTPzSo2FnyMBaYGBMC6PhQy7yxxil9vIedFBweQBMK74/7o8A==
+escodegen@^1.14.1:
+ version "1.14.3"
+ resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.14.3.tgz#4e7b81fba61581dc97582ed78cab7f0e8d63f503"
+ integrity sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==
dependencies:
esprima "^4.0.1"
estraverse "^4.2.0"
@@ -4690,9 +4723,9 @@ esrecurse@^4.1.0:
estraverse "^4.1.0"
estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1, estraverse@^4.2.0:
- version "4.2.0"
- resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13"
- integrity sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=
+ version "4.3.0"
+ resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d"
+ integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==
esutils@^2.0.2:
version "2.0.3"
@@ -4740,9 +4773,9 @@ evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3:
safe-buffer "^5.1.1"
exec-sh@^0.3.2:
- version "0.3.2"
- resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.3.2.tgz#6738de2eb7c8e671d0366aea0b0db8c6f7d7391b"
- integrity sha512-9sLAvzhI5nc8TpuQUh4ahMdCrWT00wPWz7j47/emR5+2qEfoZP5zzUXvx+vdx+H6ohhnsYC31iX04QLYJK8zTg==
+ version "0.3.4"
+ resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.3.4.tgz#3a018ceb526cc6f6df2bb504b2bfe8e3a4934ec5"
+ integrity sha512-sEFIkc61v75sWeOe72qyrqg2Qg0OuLESziUDk/O/z2qgS15y2gWVFrI6f2Qn/qw/0/NCfCEsmNA4zOjkwEZT1A==
execa@^1.0.0:
version "1.0.0"
@@ -4757,6 +4790,21 @@ execa@^1.0.0:
signal-exit "^3.0.0"
strip-eof "^1.0.0"
+execa@^4.0.0:
+ version "4.0.3"
+ resolved "https://registry.yarnpkg.com/execa/-/execa-4.0.3.tgz#0a34dabbad6d66100bd6f2c576c8669403f317f2"
+ integrity sha512-WFDXGHckXPWZX19t1kCsXzOpqX9LWYNqn4C+HqZlk/V0imTkzJZqf87ZBhvpHaftERYknpk0fjSylnXVlVgI0A==
+ dependencies:
+ cross-spawn "^7.0.0"
+ get-stream "^5.0.0"
+ human-signals "^1.1.1"
+ is-stream "^2.0.0"
+ merge-stream "^2.0.0"
+ npm-run-path "^4.0.0"
+ onetime "^5.1.0"
+ signal-exit "^3.0.2"
+ strip-final-newline "^2.0.0"
+
execall@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/execall/-/execall-2.0.0.tgz#16a06b5fe5099df7d00be5d9c06eecded1663b45"
@@ -4789,17 +4837,17 @@ expand-tilde@^2.0.0, expand-tilde@^2.0.2:
dependencies:
homedir-polyfill "^1.0.1"
-expect@^24.8.0:
- version "24.8.0"
- resolved "https://registry.yarnpkg.com/expect/-/expect-24.8.0.tgz#471f8ec256b7b6129ca2524b2a62f030df38718d"
- integrity sha512-/zYvP8iMDrzaaxHVa724eJBCKqSHmO0FA7EDkBiRHxg6OipmMn1fN+C8T9L9K8yr7UONkOifu6+LLH+z76CnaA==
+expect@^26.5.2:
+ version "26.5.2"
+ resolved "https://registry.yarnpkg.com/expect/-/expect-26.5.2.tgz#3e0631c4a657a83dbec769ad246a2998953a55a6"
+ integrity sha512-ccTGrXZd8DZCcvCz4htGXTkd/LOoy6OEtiDS38x3/VVf6E4AQL0QoeksBiw7BtGR5xDNiRYPB8GN6pfbuTOi7w==
dependencies:
- "@jest/types" "^24.8.0"
- ansi-styles "^3.2.0"
- jest-get-type "^24.8.0"
- jest-matcher-utils "^24.8.0"
- jest-message-util "^24.8.0"
- jest-regex-util "^24.3.0"
+ "@jest/types" "^26.5.2"
+ ansi-styles "^4.0.0"
+ jest-get-type "^26.3.0"
+ jest-matcher-utils "^26.5.2"
+ jest-message-util "^26.5.2"
+ jest-regex-util "^26.0.0"
exports-loader@^0.7.0:
version "0.7.0"
@@ -4911,9 +4959,9 @@ fake-xml-http-request@^2.1.1:
integrity sha512-Kn2WYYS6cDBS5jq/voOfSGCA0TafOYAUPbEp8mUVpD/DVV5bQIDjlq+MLLvNUokkbTpjBVlLDaM5PnX+PwZMlw==
fast-deep-equal@^3.1.1:
- version "3.1.1"
- resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz#545145077c501491e33b15ec408c294376e94ae4"
- integrity sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA==
+ version "3.1.3"
+ resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
+ integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
fast-glob@^2.2.6:
version "2.2.6"
@@ -4928,9 +4976,9 @@ fast-glob@^2.2.6:
micromatch "^3.1.10"
fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2"
- integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I=
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633"
+ integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==
fast-levenshtein@~2.0.6:
version "2.0.6"
@@ -4959,11 +5007,11 @@ faye-websocket@~0.11.1:
websocket-driver ">=0.5.1"
fb-watchman@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.0.tgz#54e9abf7dfa2f26cd9b1636c588c1afc05de5d58"
- integrity sha1-VOmr99+i8mzZsWNsWIwa/AXeXVg=
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.1.tgz#fc84fb39d2709cf3ff6d743706157bb5708a8a85"
+ integrity sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg==
dependencies:
- bser "^2.0.0"
+ bser "2.1.1"
figgy-pudding@^3.5.1:
version "3.5.1"
@@ -4992,11 +5040,6 @@ file-loader@^5.1.0:
loader-utils "^1.4.0"
schema-utils "^2.5.0"
-file-uri-to-path@1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd"
- integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==
-
fileset@^2.0.3:
version "2.0.3"
resolved "https://registry.yarnpkg.com/fileset/-/fileset-2.0.3.tgz#8e7548a96d3cc2327ee5e674168723a333bba2a0"
@@ -5098,7 +5141,7 @@ find-up@^3.0.0:
dependencies:
locate-path "^3.0.0"
-find-up@^4.0.0:
+find-up@^4.0.0, find-up@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19"
integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==
@@ -5228,15 +5271,7 @@ fs.realpath@^1.0.0:
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8=
-fsevents@^1.2.7:
- version "1.2.13"
- resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.13.tgz#f325cb0455592428bcf11b383370ef70e3bfcc38"
- integrity sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==
- dependencies:
- bindings "^1.5.0"
- nan "^2.12.1"
-
-fsevents@~2.1.2:
+fsevents@^2.1.2, fsevents@~2.1.2:
version "2.1.3"
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.3.tgz#fb738703ae8d2f9fe900c33836ddebee8b97f23e"
integrity sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==
@@ -5302,6 +5337,11 @@ get-caller-file@^2.0.1:
resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
+get-package-type@^0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a"
+ integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==
+
get-stdin@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe"
@@ -5329,10 +5369,10 @@ get-stream@^4.0.0, get-stream@^4.1.0:
dependencies:
pump "^3.0.0"
-get-stream@^5.1.0:
- version "5.1.0"
- resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.1.0.tgz#01203cdc92597f9b909067c3e656cc1f4d3c4dc9"
- integrity sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw==
+get-stream@^5.0.0, get-stream@^5.1.0:
+ version "5.2.0"
+ resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3"
+ integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==
dependencies:
pump "^3.0.0"
@@ -5513,9 +5553,9 @@ globjoin@^0.1.4:
integrity sha1-L0SUrIkZ43Z8XLtpHp9GMyQoXUM=
globule@^1.0.0:
- version "1.2.1"
- resolved "https://registry.yarnpkg.com/globule/-/globule-1.2.1.tgz#5dffb1b191f22d20797a9369b49eab4e9839696d"
- integrity sha512-g7QtgWF4uYSL5/dn71WxubOrS7JVGCnFPEnoeChJmBnyR9Mw8nGoEwOgJL/RC2Te0WhbsEUCejfH8SZNJ+adYQ==
+ version "1.3.2"
+ resolved "https://registry.yarnpkg.com/globule/-/globule-1.3.2.tgz#d8bdd9e9e4eef8f96e245999a5dee7eb5d8529c4"
+ integrity sha512-7IDTQTIu2xzXkT+6mlluidnWo+BypnbSoEVVQCGfzqnl5Ik8d3e1d4wycb8Rj9tWW+Z39uPWsdlquqiqPCd/pA==
dependencies:
glob "~7.1.1"
lodash "~4.17.10"
@@ -5552,7 +5592,7 @@ got@^9.6.0:
to-readable-stream "^1.0.0"
url-parse-lax "^3.0.0"
-graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9, graceful-fs@^4.2.2, graceful-fs@^4.2.4:
+graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9, graceful-fs@^4.2.2, graceful-fs@^4.2.4:
version "4.2.4"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb"
integrity sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==
@@ -5581,16 +5621,6 @@ graphql@^14.7.0:
dependencies:
iterall "^1.2.2"
-gray-matter@^4.0.2:
- version "4.0.2"
- resolved "https://registry.yarnpkg.com/gray-matter/-/gray-matter-4.0.2.tgz#9aa379e3acaf421193fce7d2a28cebd4518ac454"
- integrity sha512-7hB/+LxrOjq/dd8APlK0r24uL/67w7SkYnfwhNFwg/VDIGWGmduTDYf3WNstLW2fbbmRwrDGCVSJ2isuf2+4Hw==
- dependencies:
- js-yaml "^3.11.0"
- kind-of "^6.0.2"
- section-matter "^1.0.0"
- strip-bom-string "^1.0.0"
-
growly@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081"
@@ -5626,11 +5656,11 @@ har-schema@^2.0.0:
integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=
har-validator@~5.1.3:
- version "5.1.3"
- resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.3.tgz#1ef89ebd3e4996557675eed9893110dc350fa080"
- integrity sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==
+ version "5.1.5"
+ resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.5.tgz#1f0803b9f8cb20c0fa13822df1ecddb36bde1efd"
+ integrity sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==
dependencies:
- ajv "^6.5.5"
+ ajv "^6.12.3"
har-schema "^2.0.0"
has-ansi@^2.0.0:
@@ -5775,9 +5805,9 @@ hoopy@^0.1.2:
integrity sha512-HRcs+2mr52W0K+x8RzcLzuPPmVIKMSv97RGHy0Ea9y/mpcaK+xTrjICA04KAHi4GRzxliNqNJEFYWHghy3rSfQ==
hosted-git-info@^2.1.4:
- version "2.2.0"
- resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.2.0.tgz#7a0d097863d886c0fabbdcd37bf1758d8becf8a5"
- integrity sha1-eg0JeGPYhsD6u9zTe/F1jYvs+KU=
+ version "2.8.8"
+ resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.8.tgz#7539bd4bc1e0e0a895815a2e0262420b12858488"
+ integrity sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==
hpack.js@^2.1.6:
version "2.1.6"
@@ -5789,13 +5819,6 @@ hpack.js@^2.1.6:
readable-stream "^2.0.1"
wbuf "^1.1.0"
-html-encoding-sniffer@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz#e70d84b94da53aa375e11fe3a351be6642ca46f8"
- integrity sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw==
- dependencies:
- whatwg-encoding "^1.0.1"
-
html-encoding-sniffer@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz#42a6dc4fd33f00281176e8b23759ca4e4fa185f3"
@@ -5907,6 +5930,11 @@ https-browserify@^1.0.0:
resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73"
integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=
+human-signals@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3"
+ integrity sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==
+
iconv-lite@0.4, iconv-lite@0.4.24, iconv-lite@^0.4.24:
version "0.4.24"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
@@ -6000,6 +6028,14 @@ import-local@2.0.0, import-local@^2.0.0:
pkg-dir "^3.0.0"
resolve-cwd "^2.0.0"
+import-local@^3.0.2:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.0.2.tgz#a8cfd0431d1de4a2199703d003e3e62364fa6db6"
+ integrity sha512-vjL3+w0oulAVZ0hBHnxa/Nm5TAurf9YLQJDhqRZyqb+VKGOB6LU8t9H1Nr5CIo16vh9XfJTOoHwU0B71S557gA==
+ dependencies:
+ pkg-dir "^4.2.0"
+ resolve-cwd "^3.0.0"
+
imports-loader@^0.8.0:
version "0.8.0"
resolved "https://registry.yarnpkg.com/imports-loader/-/imports-loader-0.8.0.tgz#030ea51b8ca05977c40a3abfd9b4088fe0be9a69"
@@ -6014,9 +6050,9 @@ imurmurhash@^0.1.4:
integrity sha1-khi5srkoojixPcT7a21XbyMUU+o=
in-publish@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/in-publish/-/in-publish-2.0.0.tgz#e20ff5e3a2afc2690320b6dc552682a9c7fadf51"
- integrity sha1-4g/146KvwmkDILbcVSaCqcf631E=
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/in-publish/-/in-publish-2.0.1.tgz#948b1a535c8030561cea522f73f78f4be357e00c"
+ integrity sha512-oDM0kUSNFC31ShNxHKUyfZKy8ZeXZBWMjMdZHKLOk13uvT27VTL/QzRGfRUcevJhpkZAvlhPYuXkF7eNWrtyxQ==
indent-string@^2.1.0:
version "2.1.0"
@@ -6117,11 +6153,6 @@ invariant@^2.2.2, invariant@^2.2.4:
dependencies:
loose-envify "^1.0.0"
-invert-kv@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6"
- integrity sha1-EEqOSqym09jNFXqO+L+rLXo//bY=
-
invert-kv@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-2.0.0.tgz#7393f5afa59ec9ff5f67a27620d11c226e3eec02"
@@ -6265,6 +6296,11 @@ is-directory@^0.3.1:
resolved "https://registry.yarnpkg.com/is-directory/-/is-directory-0.3.1.tgz#61339b6f2475fc772fd9c9d83f5c8575dc154ae1"
integrity sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=
+is-docker@^2.0.0:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.1.1.tgz#4125a88e44e450d384e09047ede71adc2d144156"
+ integrity sha512-ZOoqiXfEwtGknTiuDEy8pN2CfE3TxMHprvNer1mXiqwkOT77Rw3YVrUQ52EqAOU3QAWDQ+bQdx7HJzrv7LS2Hw==
+
is-extendable@^0.1.0, is-extendable@^0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89"
@@ -6283,11 +6319,9 @@ is-extglob@^2.1.0, is-extglob@^2.1.1:
integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=
is-finite@^1.0.0:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa"
- integrity sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=
- dependencies:
- number-is-nan "^1.0.0"
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.1.0.tgz#904135c77fb42c0641d6aa1bcdbc4daa8da082f3"
+ integrity sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w==
is-fullwidth-code-point@^1.0.0:
version "1.0.0"
@@ -6433,6 +6467,11 @@ is-stream@^1.1.0:
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ=
+is-stream@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.0.tgz#bde9c32680d6fae04129d6ac9d921ce7815f78e3"
+ integrity sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==
+
is-symbol@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.2.tgz#a055f6ae57192caee329e7a860118b497a950f38"
@@ -6475,6 +6514,13 @@ is-wsl@^1.1.0:
resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d"
integrity sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=
+is-wsl@^2.2.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271"
+ integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==
+ dependencies:
+ is-docker "^2.0.0"
+
is-yarn-global@^0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/is-yarn-global/-/is-yarn-global-0.3.0.tgz#d502d3382590ea3004893746754c89139973e232"
@@ -6536,7 +6582,7 @@ istanbul-api@^2.1.6:
minimatch "^3.0.4"
once "^1.4.0"
-istanbul-lib-coverage@^2.0.2, istanbul-lib-coverage@^2.0.5:
+istanbul-lib-coverage@^2.0.5:
version "2.0.5"
resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz#675f0ab69503fad4b1d849f736baaca803344f49"
integrity sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==
@@ -6553,7 +6599,7 @@ istanbul-lib-hook@^2.0.7:
dependencies:
append-transform "^1.0.0"
-istanbul-lib-instrument@^3.0.0, istanbul-lib-instrument@^3.0.1, istanbul-lib-instrument@^3.3.0:
+istanbul-lib-instrument@^3.3.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-3.3.0.tgz#a5f63d91f0bbc0c3e479ef4c5de027335ec6d630"
integrity sha512-5nnIN4vo5xQZHdXno/YDXJ0G+I3dAm4XgzfSVTPLQpj/zAV2dV6Juy0yaf10/zrJOJeHoN3fraFe+XRq2bFVZA==
@@ -6566,7 +6612,17 @@ istanbul-lib-instrument@^3.0.0, istanbul-lib-instrument@^3.0.1, istanbul-lib-ins
istanbul-lib-coverage "^2.0.5"
semver "^6.0.0"
-istanbul-lib-report@^2.0.4, istanbul-lib-report@^2.0.8:
+istanbul-lib-instrument@^4.0.0, istanbul-lib-instrument@^4.0.3:
+ version "4.0.3"
+ resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz#873c6fff897450118222774696a3f28902d77c1d"
+ integrity sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==
+ dependencies:
+ "@babel/core" "^7.7.5"
+ "@istanbuljs/schema" "^0.1.2"
+ istanbul-lib-coverage "^3.0.0"
+ semver "^6.3.0"
+
+istanbul-lib-report@^2.0.8:
version "2.0.8"
resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-2.0.8.tgz#5a8113cd746d43c4889eba36ab10e7d50c9b4f33"
integrity sha512-fHBeG573EIihhAblwgxrSenp0Dby6tJMFR/HvlerBsrCTD5bkUuoNtn3gVh29ZCS824cGGBPn7Sg7cNk+2xUsQ==
@@ -6584,7 +6640,7 @@ istanbul-lib-report@^3.0.0:
make-dir "^3.0.0"
supports-color "^7.1.0"
-istanbul-lib-source-maps@^3.0.1, istanbul-lib-source-maps@^3.0.6:
+istanbul-lib-source-maps@^3.0.6:
version "3.0.6"
resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.6.tgz#284997c48211752ec486253da97e3879defba8c8"
integrity sha512-R47KzMtDJH6X4/YW9XTx+jrLnZnscW4VpNN+1PViSYTejLVPWv7oov+Duf8YQSPyVRUvueQqz1TcsC6mooZTXw==
@@ -6595,17 +6651,26 @@ istanbul-lib-source-maps@^3.0.1, istanbul-lib-source-maps@^3.0.6:
rimraf "^2.6.3"
source-map "^0.6.1"
-istanbul-reports@^2.1.1, istanbul-reports@^2.2.4:
+istanbul-lib-source-maps@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.0.tgz#75743ce6d96bb86dc7ee4352cf6366a23f0b1ad9"
+ integrity sha512-c16LpFRkR8vQXyHZ5nLpY35JZtzj1PQY1iZmesUbf1FZHbIupcWfjgOXBY9YHkLEQ6puz1u4Dgj6qmU/DisrZg==
+ dependencies:
+ debug "^4.1.1"
+ istanbul-lib-coverage "^3.0.0"
+ source-map "^0.6.1"
+
+istanbul-reports@^2.2.4:
version "2.2.6"
resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-2.2.6.tgz#7b4f2660d82b29303a8fe6091f8ca4bf058da1af"
integrity sha512-SKi4rnMyLBKe0Jy2uUdx28h8oG7ph2PPuQPvIAh31d+Ci+lSiEu4C+h3oBPuJ9+mPKhOyW0M8gY4U5NM1WLeXA==
dependencies:
handlebars "^4.1.2"
-istanbul-reports@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.0.0.tgz#d4d16d035db99581b6194e119bbf36c963c5eb70"
- integrity sha512-2osTcC8zcOSUkImzN2EWQta3Vdi4WjjKw99P2yWx5mLnigAM0Rd5uYFn1cf2i/Ois45GkNjaoTqc5CxgMSX80A==
+istanbul-reports@^3.0.0, istanbul-reports@^3.0.2:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.0.2.tgz#d593210e5000683750cb09fc0644e4b6e27fd53b"
+ integrity sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw==
dependencies:
html-escaper "^2.0.0"
istanbul-lib-report "^3.0.0"
@@ -6654,427 +6719,412 @@ jest-canvas-mock@^2.1.2:
cssfontparser "^1.2.1"
parse-color "^1.0.0"
-jest-changed-files@^24.8.0:
- version "24.8.0"
- resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-24.8.0.tgz#7e7eb21cf687587a85e50f3d249d1327e15b157b"
- integrity sha512-qgANC1Yrivsq+UrLXsvJefBKVoCsKB0Hv+mBb6NMjjZ90wwxCDmU3hsCXBya30cH+LnPYjwgcU65i6yJ5Nfuug==
+jest-changed-files@^26.5.2:
+ version "26.5.2"
+ resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-26.5.2.tgz#330232c6a5c09a7f040a5870e8f0a9c6abcdbed5"
+ integrity sha512-qSmssmiIdvM5BWVtyK/nqVpN3spR5YyvkvPqz1x3BR1bwIxsWmU/MGwLoCrPNLbkG2ASAKfvmJpOduEApBPh2w==
dependencies:
- "@jest/types" "^24.8.0"
- execa "^1.0.0"
- throat "^4.0.0"
+ "@jest/types" "^26.5.2"
+ execa "^4.0.0"
+ throat "^5.0.0"
-jest-cli@^24.8.0:
- version "24.8.0"
- resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-24.8.0.tgz#b075ac914492ed114fa338ade7362a301693e989"
- integrity sha512-+p6J00jSMPQ116ZLlHJJvdf8wbjNbZdeSX9ptfHX06/MSNaXmKihQzx5vQcw0q2G6JsdVkUIdWbOWtSnaYs3yA==
+jest-cli@^26.5.2:
+ version "26.5.2"
+ resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-26.5.2.tgz#0df114399b4036a3f046f0a9f25c50372c76b3a2"
+ integrity sha512-usm48COuUvRp8YEG5OWOaxbSM0my7eHn3QeBWxiGUuFhvkGVBvl1fic4UjC02EAEQtDv8KrNQUXdQTV6ZZBsoA==
dependencies:
- "@jest/core" "^24.8.0"
- "@jest/test-result" "^24.8.0"
- "@jest/types" "^24.8.0"
- chalk "^2.0.1"
+ "@jest/core" "^26.5.2"
+ "@jest/test-result" "^26.5.2"
+ "@jest/types" "^26.5.2"
+ chalk "^4.0.0"
exit "^0.1.2"
- import-local "^2.0.0"
+ graceful-fs "^4.2.4"
+ import-local "^3.0.2"
is-ci "^2.0.0"
- jest-config "^24.8.0"
- jest-util "^24.8.0"
- jest-validate "^24.8.0"
+ jest-config "^26.5.2"
+ jest-util "^26.5.2"
+ jest-validate "^26.5.2"
prompts "^2.0.1"
- realpath-native "^1.1.0"
- yargs "^12.0.2"
+ yargs "^15.4.1"
-jest-config@^24.8.0:
- version "24.8.0"
- resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-24.8.0.tgz#77db3d265a6f726294687cbbccc36f8a76ee0f4f"
- integrity sha512-Czl3Nn2uEzVGsOeaewGWoDPD8GStxCpAe0zOYs2x2l0fZAgPbCr3uwUkgNKV3LwE13VXythM946cd5rdGkkBZw==
+jest-config@^26.5.2:
+ version "26.5.2"
+ resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-26.5.2.tgz#6e828e25f10124433dd008fbd83348636de0972a"
+ integrity sha512-dqJOnSegNdE5yDiuGHsjTM5gec7Z4AcAMHiW+YscbOYJAlb3LEtDSobXCq0or9EmGQI5SFmKy4T7P1FxetJOfg==
dependencies:
"@babel/core" "^7.1.0"
- "@jest/test-sequencer" "^24.8.0"
- "@jest/types" "^24.8.0"
- babel-jest "^24.8.0"
- chalk "^2.0.1"
+ "@jest/test-sequencer" "^26.5.2"
+ "@jest/types" "^26.5.2"
+ babel-jest "^26.5.2"
+ chalk "^4.0.0"
+ deepmerge "^4.2.2"
glob "^7.1.1"
- jest-environment-jsdom "^24.8.0"
- jest-environment-node "^24.8.0"
- jest-get-type "^24.8.0"
- jest-jasmine2 "^24.8.0"
- jest-regex-util "^24.3.0"
- jest-resolve "^24.8.0"
- jest-util "^24.8.0"
- jest-validate "^24.8.0"
- micromatch "^3.1.10"
- pretty-format "^24.8.0"
- realpath-native "^1.1.0"
-
-jest-diff@^24.8.0:
- version "24.8.0"
- resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-24.8.0.tgz#146435e7d1e3ffdf293d53ff97e193f1d1546172"
- integrity sha512-wxetCEl49zUpJ/bvUmIFjd/o52J+yWcoc5ZyPq4/W1LUKGEhRYDIbP1KcF6t+PvqNrGAFk4/JhtxDq/Nnzs66g==
- dependencies:
- chalk "^2.0.1"
- diff-sequences "^24.3.0"
- jest-get-type "^24.8.0"
- pretty-format "^24.8.0"
-
-jest-docblock@^24.3.0:
- version "24.3.0"
- resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-24.3.0.tgz#b9c32dac70f72e4464520d2ba4aec02ab14db5dd"
- integrity sha512-nlANmF9Yq1dufhFlKG9rasfQlrY7wINJbo3q01tu56Jv5eBU5jirylhF2O5ZBnLxzOVBGRDz/9NAwNyBtG4Nyg==
- dependencies:
- detect-newline "^2.1.0"
+ graceful-fs "^4.2.4"
+ jest-environment-jsdom "^26.5.2"
+ jest-environment-node "^26.5.2"
+ jest-get-type "^26.3.0"
+ jest-jasmine2 "^26.5.2"
+ jest-regex-util "^26.0.0"
+ jest-resolve "^26.5.2"
+ jest-util "^26.5.2"
+ jest-validate "^26.5.2"
+ micromatch "^4.0.2"
+ pretty-format "^26.5.2"
-jest-each@^24.8.0:
- version "24.8.0"
- resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-24.8.0.tgz#a05fd2bf94ddc0b1da66c6d13ec2457f35e52775"
- integrity sha512-NrwK9gaL5+XgrgoCsd9svsoWdVkK4gnvyhcpzd6m487tXHqIdYeykgq3MKI1u4I+5Zf0tofr70at9dWJDeb+BA==
+jest-diff@^25.2.1:
+ version "25.5.0"
+ resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-25.5.0.tgz#1dd26ed64f96667c068cef026b677dfa01afcfa9"
+ integrity sha512-z1kygetuPiREYdNIumRpAHY6RXiGmp70YHptjdaxTWGmA085W3iCnXNx0DhflK3vwrKmrRWyY1wUpkPMVxMK7A==
dependencies:
- "@jest/types" "^24.8.0"
- chalk "^2.0.1"
- jest-get-type "^24.8.0"
- jest-util "^24.8.0"
- pretty-format "^24.8.0"
+ chalk "^3.0.0"
+ diff-sequences "^25.2.6"
+ jest-get-type "^25.2.6"
+ pretty-format "^25.5.0"
-jest-environment-jsdom-sixteen@^1.0.0:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/jest-environment-jsdom-sixteen/-/jest-environment-jsdom-sixteen-1.0.3.tgz#e222228fac537ef15cca5ad470b19b47d9690165"
- integrity sha512-CwMqDUUfSl808uGPWXlNA1UFkWFgRmhHvyAjhCmCry6mYq4b/nn80MMN7tglqo5XgrANIs/w+mzINPzbZ4ZZrQ==
- dependencies:
- "@jest/fake-timers" "^25.1.0"
- jest-mock "^25.1.0"
- jest-util "^25.1.0"
- jsdom "^16.2.1"
-
-jest-environment-jsdom@^24.8.0:
- version "24.8.0"
- resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-24.8.0.tgz#300f6949a146cabe1c9357ad9e9ecf9f43f38857"
- integrity sha512-qbvgLmR7PpwjoFjM/sbuqHJt/NCkviuq9vus9NBn/76hhSidO+Z6Bn9tU8friecegbJL8gzZQEMZBQlFWDCwAQ==
- dependencies:
- "@jest/environment" "^24.8.0"
- "@jest/fake-timers" "^24.8.0"
- "@jest/types" "^24.8.0"
- jest-mock "^24.8.0"
- jest-util "^24.8.0"
- jsdom "^11.5.1"
-
-jest-environment-node@^24.8.0:
- version "24.8.0"
- resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-24.8.0.tgz#d3f726ba8bc53087a60e7a84ca08883a4c892231"
- integrity sha512-vIGUEScd1cdDgR6sqn2M08sJTRLQp6Dk/eIkCeO4PFHxZMOgy+uYLPMC4ix3PEfM5Au/x3uQ/5Tl0DpXXZsJ/Q==
- dependencies:
- "@jest/environment" "^24.8.0"
- "@jest/fake-timers" "^24.8.0"
- "@jest/types" "^24.8.0"
- jest-mock "^24.8.0"
- jest-util "^24.8.0"
-
-jest-get-type@^24.8.0:
- version "24.8.0"
- resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-24.8.0.tgz#a7440de30b651f5a70ea3ed7ff073a32dfe646fc"
- integrity sha512-RR4fo8jEmMD9zSz2nLbs2j0zvPpk/KCEz3a62jJWbd2ayNo0cb+KFRxPHVhE4ZmgGJEQp0fosmNz84IfqM8cMQ==
-
-jest-haste-map@^24.8.0:
- version "24.8.0"
- resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-24.8.0.tgz#51794182d877b3ddfd6e6d23920e3fe72f305800"
- integrity sha512-ZBPRGHdPt1rHajWelXdqygIDpJx8u3xOoLyUBWRW28r3tagrgoepPrzAozW7kW9HrQfhvmiv1tncsxqHJO1onQ==
- dependencies:
- "@jest/types" "^24.8.0"
- anymatch "^2.0.0"
+jest-diff@^26.5.2:
+ version "26.5.2"
+ resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-26.5.2.tgz#8e26cb32dc598e8b8a1b9deff55316f8313c8053"
+ integrity sha512-HCSWDUGwsov5oTlGzrRM+UPJI/Dpqi9jzeV0fdRNi3Ch5bnoXhnyJMmVg2juv9081zLIy3HGPI5mcuGgXM2xRA==
+ dependencies:
+ chalk "^4.0.0"
+ diff-sequences "^26.5.0"
+ jest-get-type "^26.3.0"
+ pretty-format "^26.5.2"
+
+jest-docblock@^26.0.0:
+ version "26.0.0"
+ resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-26.0.0.tgz#3e2fa20899fc928cb13bd0ff68bd3711a36889b5"
+ integrity sha512-RDZ4Iz3QbtRWycd8bUEPxQsTlYazfYn/h5R65Fc6gOfwozFhoImx+affzky/FFBuqISPTqjXomoIGJVKBWoo0w==
+ dependencies:
+ detect-newline "^3.0.0"
+
+jest-each@^26.5.2:
+ version "26.5.2"
+ resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-26.5.2.tgz#35e68d6906a7f826d3ca5803cfe91d17a5a34c31"
+ integrity sha512-w7D9FNe0m2D3yZ0Drj9CLkyF/mGhmBSULMQTypzAKR746xXnjUrK8GUJdlLTWUF6dd0ks3MtvGP7/xNFr9Aphg==
+ dependencies:
+ "@jest/types" "^26.5.2"
+ chalk "^4.0.0"
+ jest-get-type "^26.3.0"
+ jest-util "^26.5.2"
+ pretty-format "^26.5.2"
+
+jest-environment-jsdom@^26.5.2:
+ version "26.5.2"
+ resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-26.5.2.tgz#5feab05b828fd3e4b96bee5e0493464ddd2bb4bc"
+ integrity sha512-fWZPx0bluJaTQ36+PmRpvUtUlUFlGGBNyGX1SN3dLUHHMcQ4WseNEzcGGKOw4U5towXgxI4qDoI3vwR18H0RTw==
+ dependencies:
+ "@jest/environment" "^26.5.2"
+ "@jest/fake-timers" "^26.5.2"
+ "@jest/types" "^26.5.2"
+ "@types/node" "*"
+ jest-mock "^26.5.2"
+ jest-util "^26.5.2"
+ jsdom "^16.4.0"
+
+jest-environment-node@^26.5.2:
+ version "26.5.2"
+ resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-26.5.2.tgz#275a0f01b5e47447056f1541a15ed4da14acca03"
+ integrity sha512-YHjnDsf/GKFCYMGF1V+6HF7jhY1fcLfLNBDjhAOvFGvt6d8vXvNdJGVM7uTZ2VO/TuIyEFhPGaXMX5j3h7fsrA==
+ dependencies:
+ "@jest/environment" "^26.5.2"
+ "@jest/fake-timers" "^26.5.2"
+ "@jest/types" "^26.5.2"
+ "@types/node" "*"
+ jest-mock "^26.5.2"
+ jest-util "^26.5.2"
+
+jest-get-type@^25.2.6:
+ version "25.2.6"
+ resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-25.2.6.tgz#0b0a32fab8908b44d508be81681487dbabb8d877"
+ integrity sha512-DxjtyzOHjObRM+sM1knti6or+eOgcGU4xVSb2HNP1TqO4ahsT+rqZg+nyqHWJSvWgKC5cG3QjGFBqxLghiF/Ig==
+
+jest-get-type@^26.3.0:
+ version "26.3.0"
+ resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-26.3.0.tgz#e97dc3c3f53c2b406ca7afaed4493b1d099199e0"
+ integrity sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig==
+
+jest-haste-map@^26.5.2:
+ version "26.5.2"
+ resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-26.5.2.tgz#a15008abfc502c18aa56e4919ed8c96304ceb23d"
+ integrity sha512-lJIAVJN3gtO3k4xy+7i2Xjtwh8CfPcH08WYjZpe9xzveDaqGw9fVNCpkYu6M525wKFVkLmyi7ku+DxCAP1lyMA==
+ dependencies:
+ "@jest/types" "^26.5.2"
+ "@types/graceful-fs" "^4.1.2"
+ "@types/node" "*"
+ anymatch "^3.0.3"
fb-watchman "^2.0.0"
- graceful-fs "^4.1.15"
- invariant "^2.2.4"
- jest-serializer "^24.4.0"
- jest-util "^24.8.0"
- jest-worker "^24.6.0"
- micromatch "^3.1.10"
+ graceful-fs "^4.2.4"
+ jest-regex-util "^26.0.0"
+ jest-serializer "^26.5.0"
+ jest-util "^26.5.2"
+ jest-worker "^26.5.0"
+ micromatch "^4.0.2"
sane "^4.0.3"
walker "^1.0.7"
optionalDependencies:
- fsevents "^1.2.7"
+ fsevents "^2.1.2"
-jest-jasmine2@^24.8.0:
- version "24.8.0"
- resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-24.8.0.tgz#a9c7e14c83dd77d8b15e820549ce8987cc8cd898"
- integrity sha512-cEky88npEE5LKd5jPpTdDCLvKkdyklnaRycBXL6GNmpxe41F0WN44+i7lpQKa/hcbXaQ+rc9RMaM4dsebrYong==
+jest-jasmine2@^26.5.2:
+ version "26.5.2"
+ resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-26.5.2.tgz#0e33819d31b1f2aab5efd1e02ce502209c0e64a2"
+ integrity sha512-2J+GYcgLVPTkpmvHEj0/IDTIAuyblGNGlyGe4fLfDT2aktEPBYvoxUwFiOmDDxxzuuEAD2uxcYXr0+1Yw4tjFA==
dependencies:
"@babel/traverse" "^7.1.0"
- "@jest/environment" "^24.8.0"
- "@jest/test-result" "^24.8.0"
- "@jest/types" "^24.8.0"
- chalk "^2.0.1"
+ "@jest/environment" "^26.5.2"
+ "@jest/source-map" "^26.5.0"
+ "@jest/test-result" "^26.5.2"
+ "@jest/types" "^26.5.2"
+ "@types/node" "*"
+ chalk "^4.0.0"
co "^4.6.0"
- expect "^24.8.0"
+ expect "^26.5.2"
is-generator-fn "^2.0.0"
- jest-each "^24.8.0"
- jest-matcher-utils "^24.8.0"
- jest-message-util "^24.8.0"
- jest-runtime "^24.8.0"
- jest-snapshot "^24.8.0"
- jest-util "^24.8.0"
- pretty-format "^24.8.0"
- throat "^4.0.0"
-
-jest-junit@^6.3.0:
- version "6.3.0"
- resolved "https://registry.yarnpkg.com/jest-junit/-/jest-junit-6.3.0.tgz#99e64ebc54eddcb21238f0cc49f5820c89a8c785"
- integrity sha512-3PH9UkpaomX6CUzqjlnk0m4yBCW/eroxV6v61OM6LkCQFO848P3YUhfIzu8ypZSBKB3vvCbB4WaLTKT0BrIf8A==
- dependencies:
- jest-validate "^24.0.0"
- mkdirp "^0.5.1"
- strip-ansi "^4.0.0"
+ jest-each "^26.5.2"
+ jest-matcher-utils "^26.5.2"
+ jest-message-util "^26.5.2"
+ jest-runtime "^26.5.2"
+ jest-snapshot "^26.5.2"
+ jest-util "^26.5.2"
+ pretty-format "^26.5.2"
+ throat "^5.0.0"
+
+jest-junit@^12.0.0:
+ version "12.0.0"
+ resolved "https://registry.yarnpkg.com/jest-junit/-/jest-junit-12.0.0.tgz#3ebd4a6a84b50c4ab18323a8f7d9cceb9d845df6"
+ integrity sha512-+8K35LlboWiPuCnXSyiid7rFdxNlpCWWM20WEYe6IZH6psfUWKZmSpSRQ5tk0C0cBeDsvsnIzcef5mYhyJsbug==
+ dependencies:
+ mkdirp "^1.0.4"
+ strip-ansi "^5.2.0"
+ uuid "^3.3.3"
xml "^1.0.1"
-jest-leak-detector@^24.8.0:
- version "24.8.0"
- resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-24.8.0.tgz#c0086384e1f650c2d8348095df769f29b48e6980"
- integrity sha512-cG0yRSK8A831LN8lIHxI3AblB40uhv0z+SsQdW3GoMMVcK+sJwrIIyax5tu3eHHNJ8Fu6IMDpnLda2jhn2pD/g==
+jest-leak-detector@^26.5.2:
+ version "26.5.2"
+ resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-26.5.2.tgz#83fcf9a4a6ef157549552cb4f32ca1d6221eea69"
+ integrity sha512-h7ia3dLzBFItmYERaLPEtEKxy3YlcbcRSjj0XRNJgBEyODuu+3DM2o62kvIFvs3PsaYoIIv+e+nLRI61Dj1CNw==
dependencies:
- pretty-format "^24.8.0"
+ jest-get-type "^26.3.0"
+ pretty-format "^26.5.2"
-jest-matcher-utils@^24.8.0:
- version "24.8.0"
- resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-24.8.0.tgz#2bce42204c9af12bde46f83dc839efe8be832495"
- integrity sha512-lex1yASY51FvUuHgm0GOVj7DCYEouWSlIYmCW7APSqB9v8mXmKSn5+sWVF0MhuASG0bnYY106/49JU1FZNl5hw==
+jest-matcher-utils@^26.5.2:
+ version "26.5.2"
+ resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-26.5.2.tgz#6aa2c76ce8b9c33e66f8856ff3a52bab59e6c85a"
+ integrity sha512-W9GO9KBIC4gIArsNqDUKsLnhivaqf8MSs6ujO/JDcPIQrmY+aasewweXVET8KdrJ6ADQaUne5UzysvF/RR7JYA==
dependencies:
- chalk "^2.0.1"
- jest-diff "^24.8.0"
- jest-get-type "^24.8.0"
- pretty-format "^24.8.0"
-
-jest-message-util@^24.8.0:
- version "24.8.0"
- resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-24.8.0.tgz#0d6891e72a4beacc0292b638685df42e28d6218b"
- integrity sha512-p2k71rf/b6ns8btdB0uVdljWo9h0ovpnEe05ZKWceQGfXYr4KkzgKo3PBi8wdnd9OtNh46VpNIJynUn/3MKm1g==
- dependencies:
- "@babel/code-frame" "^7.0.0"
- "@jest/test-result" "^24.8.0"
- "@jest/types" "^24.8.0"
- "@types/stack-utils" "^1.0.1"
- chalk "^2.0.1"
- micromatch "^3.1.10"
- slash "^2.0.0"
- stack-utils "^1.0.1"
+ chalk "^4.0.0"
+ jest-diff "^26.5.2"
+ jest-get-type "^26.3.0"
+ pretty-format "^26.5.2"
-jest-message-util@^25.5.0:
- version "25.5.0"
- resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-25.5.0.tgz#ea11d93204cc7ae97456e1d8716251185b8880ea"
- integrity sha512-ezddz3YCT/LT0SKAmylVyWWIGYoKHOFOFXx3/nA4m794lfVUskMcwhip6vTgdVrOtYdjeQeis2ypzes9mZb4EA==
+jest-message-util@^26.5.2:
+ version "26.5.2"
+ resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-26.5.2.tgz#6c4c4c46dcfbabb47cd1ba2f6351559729bc11bb"
+ integrity sha512-Ocp9UYZ5Jl15C5PNsoDiGEk14A4NG0zZKknpWdZGoMzJuGAkVt10e97tnEVMYpk7LnQHZOfuK2j/izLBMcuCZw==
dependencies:
"@babel/code-frame" "^7.0.0"
- "@jest/types" "^25.5.0"
- "@types/stack-utils" "^1.0.1"
- chalk "^3.0.0"
+ "@jest/types" "^26.5.2"
+ "@types/stack-utils" "^2.0.0"
+ chalk "^4.0.0"
graceful-fs "^4.2.4"
micromatch "^4.0.2"
slash "^3.0.0"
- stack-utils "^1.0.1"
+ stack-utils "^2.0.2"
-jest-mock@^24.8.0:
- version "24.8.0"
- resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-24.8.0.tgz#2f9d14d37699e863f1febf4e4d5a33b7fdbbde56"
- integrity sha512-6kWugwjGjJw+ZkK4mDa0Df3sDlUTsV47MSrT0nGQ0RBWJbpODDQ8MHDVtGtUYBne3IwZUhtB7elxHspU79WH3A==
+jest-mock@^26.5.2:
+ version "26.5.2"
+ resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-26.5.2.tgz#c9302e8ef807f2bfc749ee52e65ad11166a1b6a1"
+ integrity sha512-9SiU4b5PtO51v0MtJwVRqeGEroH66Bnwtq4ARdNP7jNXbpT7+ByeWNAk4NeT/uHfNSVDXEXgQo1XRuwEqS6Rdw==
dependencies:
- "@jest/types" "^24.8.0"
+ "@jest/types" "^26.5.2"
+ "@types/node" "*"
-jest-mock@^25.1.0, jest-mock@^25.5.0:
- version "25.5.0"
- resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-25.5.0.tgz#a91a54dabd14e37ecd61665d6b6e06360a55387a"
- integrity sha512-eXWuTV8mKzp/ovHc5+3USJMYsTBhyQ+5A1Mak35dey/RG8GlM4YWVylZuGgVXinaW6tpvk/RSecmF37FKUlpXA==
- dependencies:
- "@jest/types" "^25.5.0"
+jest-pnp-resolver@^1.2.2:
+ version "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-regex-util@^26.0.0:
+ version "26.0.0"
+ resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-26.0.0.tgz#d25e7184b36e39fd466c3bc41be0971e821fee28"
+ integrity sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A==
+
+jest-resolve-dependencies@^26.5.2:
+ version "26.5.2"
+ resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-26.5.2.tgz#ee30b7cfea81c81bf5e195a9287d7ec07f893170"
+ integrity sha512-LLkc8LuRtxqOx0AtX/Npa2C4I23WcIrwUgNtHYXg4owYF/ZDQShcwBAHjYZIFR06+HpQcZ43+kCTMlQ3aDCYTg==
+ dependencies:
+ "@jest/types" "^26.5.2"
+ jest-regex-util "^26.0.0"
+ jest-snapshot "^26.5.2"
+
+jest-resolve@^26.5.2:
+ version "26.5.2"
+ resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-26.5.2.tgz#0d719144f61944a428657b755a0e5c6af4fc8602"
+ integrity sha512-XsPxojXGRA0CoDD7Vis59ucz2p3cQFU5C+19tz3tLEAlhYKkK77IL0cjYjikY9wXnOaBeEdm1rOgSJjbZWpcZg==
+ dependencies:
+ "@jest/types" "^26.5.2"
+ chalk "^4.0.0"
+ graceful-fs "^4.2.4"
+ jest-pnp-resolver "^1.2.2"
+ jest-util "^26.5.2"
+ read-pkg-up "^7.0.1"
+ resolve "^1.17.0"
+ slash "^3.0.0"
-jest-pnp-resolver@^1.2.1:
- version "1.2.1"
- resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.1.tgz#ecdae604c077a7fbc70defb6d517c3c1c898923a"
- integrity sha512-pgFw2tm54fzgYvc/OHrnysABEObZCUNFnhjoRjaVOCN8NYc032/gVjPaHD4Aq6ApkSieWtfKAFQtmDKAmhupnQ==
-
-jest-regex-util@^24.3.0:
- version "24.3.0"
- resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-24.3.0.tgz#d5a65f60be1ae3e310d5214a0307581995227b36"
- integrity sha512-tXQR1NEOyGlfylyEjg1ImtScwMq8Oh3iJbGTjN7p0J23EuVX1MA8rwU69K4sLbCmwzgCUbVkm0FkSF9TdzOhtg==
-
-jest-resolve-dependencies@^24.8.0:
- version "24.8.0"
- resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-24.8.0.tgz#19eec3241f2045d3f990dba331d0d7526acff8e0"
- integrity sha512-hyK1qfIf/krV+fSNyhyJeq3elVMhK9Eijlwy+j5jqmZ9QsxwKBiP6qukQxaHtK8k6zql/KYWwCTQ+fDGTIJauw==
- dependencies:
- "@jest/types" "^24.8.0"
- jest-regex-util "^24.3.0"
- jest-snapshot "^24.8.0"
-
-jest-resolve@^24.8.0:
- version "24.8.0"
- resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-24.8.0.tgz#84b8e5408c1f6a11539793e2b5feb1b6e722439f"
- integrity sha512-+hjSzi1PoRvnuOICoYd5V/KpIQmkAsfjFO71458hQ2Whi/yf1GDeBOFj8Gxw4LrApHsVJvn5fmjcPdmoUHaVKw==
- dependencies:
- "@jest/types" "^24.8.0"
- browser-resolve "^1.11.3"
- chalk "^2.0.1"
- jest-pnp-resolver "^1.2.1"
- realpath-native "^1.1.0"
-
-jest-runner@^24.8.0:
- version "24.8.0"
- resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-24.8.0.tgz#4f9ae07b767db27b740d7deffad0cf67ccb4c5bb"
- integrity sha512-utFqC5BaA3JmznbissSs95X1ZF+d+4WuOWwpM9+Ak356YtMhHE/GXUondZdcyAAOTBEsRGAgH/0TwLzfI9h7ow==
- dependencies:
- "@jest/console" "^24.7.1"
- "@jest/environment" "^24.8.0"
- "@jest/test-result" "^24.8.0"
- "@jest/types" "^24.8.0"
- chalk "^2.4.2"
+jest-runner@^26.5.2:
+ version "26.5.2"
+ resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-26.5.2.tgz#4f9e6b0bb7eb4710c209a9e145b8a10894f4c19f"
+ integrity sha512-GKhYxtSX5+tXZsd2QwfkDqPIj5C2HqOdXLRc2x2qYqWE26OJh17xo58/fN/mLhRkO4y6o60ZVloan7Kk5YA6hg==
+ dependencies:
+ "@jest/console" "^26.5.2"
+ "@jest/environment" "^26.5.2"
+ "@jest/test-result" "^26.5.2"
+ "@jest/types" "^26.5.2"
+ "@types/node" "*"
+ chalk "^4.0.0"
+ emittery "^0.7.1"
exit "^0.1.2"
- graceful-fs "^4.1.15"
- jest-config "^24.8.0"
- jest-docblock "^24.3.0"
- jest-haste-map "^24.8.0"
- jest-jasmine2 "^24.8.0"
- jest-leak-detector "^24.8.0"
- jest-message-util "^24.8.0"
- jest-resolve "^24.8.0"
- jest-runtime "^24.8.0"
- jest-util "^24.8.0"
- jest-worker "^24.6.0"
+ graceful-fs "^4.2.4"
+ jest-config "^26.5.2"
+ jest-docblock "^26.0.0"
+ jest-haste-map "^26.5.2"
+ jest-leak-detector "^26.5.2"
+ jest-message-util "^26.5.2"
+ jest-resolve "^26.5.2"
+ jest-runtime "^26.5.2"
+ jest-util "^26.5.2"
+ jest-worker "^26.5.0"
source-map-support "^0.5.6"
- throat "^4.0.0"
-
-jest-runtime@^24.8.0:
- version "24.8.0"
- resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-24.8.0.tgz#05f94d5b05c21f6dc54e427cd2e4980923350620"
- integrity sha512-Mq0aIXhvO/3bX44ccT+czU1/57IgOMyy80oM0XR/nyD5zgBcesF84BPabZi39pJVA6UXw+fY2Q1N+4BiVUBWOA==
- dependencies:
- "@jest/console" "^24.7.1"
- "@jest/environment" "^24.8.0"
- "@jest/source-map" "^24.3.0"
- "@jest/transform" "^24.8.0"
- "@jest/types" "^24.8.0"
- "@types/yargs" "^12.0.2"
- chalk "^2.0.1"
+ throat "^5.0.0"
+
+jest-runtime@^26.5.2:
+ version "26.5.2"
+ resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-26.5.2.tgz#b72f5f79eb2fe0c46bfef4cdb9c1e01d1c69ba41"
+ integrity sha512-zArr4DatX/Sn0wswX/AnAuJgmwgAR5rNtrUz36HR8BfMuysHYNq5sDbYHuLC4ICyRdy5ae/KQ+sczxyS9G6Qvw==
+ dependencies:
+ "@jest/console" "^26.5.2"
+ "@jest/environment" "^26.5.2"
+ "@jest/fake-timers" "^26.5.2"
+ "@jest/globals" "^26.5.2"
+ "@jest/source-map" "^26.5.0"
+ "@jest/test-result" "^26.5.2"
+ "@jest/transform" "^26.5.2"
+ "@jest/types" "^26.5.2"
+ "@types/yargs" "^15.0.0"
+ chalk "^4.0.0"
+ collect-v8-coverage "^1.0.0"
exit "^0.1.2"
glob "^7.1.3"
- graceful-fs "^4.1.15"
- jest-config "^24.8.0"
- jest-haste-map "^24.8.0"
- jest-message-util "^24.8.0"
- jest-mock "^24.8.0"
- jest-regex-util "^24.3.0"
- jest-resolve "^24.8.0"
- jest-snapshot "^24.8.0"
- jest-util "^24.8.0"
- jest-validate "^24.8.0"
- realpath-native "^1.1.0"
- slash "^2.0.0"
- strip-bom "^3.0.0"
- yargs "^12.0.2"
+ graceful-fs "^4.2.4"
+ jest-config "^26.5.2"
+ jest-haste-map "^26.5.2"
+ jest-message-util "^26.5.2"
+ jest-mock "^26.5.2"
+ jest-regex-util "^26.0.0"
+ jest-resolve "^26.5.2"
+ jest-snapshot "^26.5.2"
+ jest-util "^26.5.2"
+ jest-validate "^26.5.2"
+ slash "^3.0.0"
+ strip-bom "^4.0.0"
+ yargs "^15.4.1"
-jest-serializer@^24.4.0:
- version "24.4.0"
- resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-24.4.0.tgz#f70c5918c8ea9235ccb1276d232e459080588db3"
- integrity sha512-k//0DtglVstc1fv+GY/VHDIjrtNjdYvYjMlbLUed4kxrE92sIUewOi5Hj3vrpB8CXfkJntRPDRjCrCvUhBdL8Q==
+jest-serializer@^26.5.0:
+ version "26.5.0"
+ resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-26.5.0.tgz#f5425cc4c5f6b4b355f854b5f0f23ec6b962bc13"
+ integrity sha512-+h3Gf5CDRlSLdgTv7y0vPIAoLgX/SI7T4v6hy+TEXMgYbv+ztzbg5PSN6mUXAT/hXYHvZRWm+MaObVfqkhCGxA==
+ dependencies:
+ "@types/node" "*"
+ graceful-fs "^4.2.4"
-jest-snapshot@^24.8.0:
- version "24.8.0"
- resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-24.8.0.tgz#3bec6a59da2ff7bc7d097a853fb67f9d415cb7c6"
- integrity sha512-5ehtWoc8oU9/cAPe6fez6QofVJLBKyqkY2+TlKTOf0VllBB/mqUNdARdcjlZrs9F1Cv+/HKoCS/BknT0+tmfPg==
+jest-snapshot@^26.5.2:
+ version "26.5.2"
+ resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-26.5.2.tgz#0cf7642eaf8e8d2736bd443f619959bf237f9ccf"
+ integrity sha512-MkXIDvEefzDubI/WaDVSRH4xnkuirP/Pz8LhAIDXcVQTmcEfwxywj5LGwBmhz+kAAIldA7XM4l96vbpzltSjqg==
dependencies:
"@babel/types" "^7.0.0"
- "@jest/types" "^24.8.0"
- chalk "^2.0.1"
- expect "^24.8.0"
- jest-diff "^24.8.0"
- jest-matcher-utils "^24.8.0"
- jest-message-util "^24.8.0"
- jest-resolve "^24.8.0"
- mkdirp "^0.5.1"
+ "@jest/types" "^26.5.2"
+ "@types/babel__traverse" "^7.0.4"
+ "@types/prettier" "^2.0.0"
+ chalk "^4.0.0"
+ expect "^26.5.2"
+ graceful-fs "^4.2.4"
+ jest-diff "^26.5.2"
+ jest-get-type "^26.3.0"
+ jest-haste-map "^26.5.2"
+ jest-matcher-utils "^26.5.2"
+ jest-message-util "^26.5.2"
+ jest-resolve "^26.5.2"
natural-compare "^1.4.0"
- pretty-format "^24.8.0"
- semver "^5.5.0"
+ pretty-format "^26.5.2"
+ semver "^7.3.2"
jest-transform-graphql@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/jest-transform-graphql/-/jest-transform-graphql-2.1.0.tgz#903cb66bb27bc2772fd3e5dd4f7e9b57230f5829"
integrity sha1-kDy2a7J7wncv0+XdT36bVyMPWCk=
-jest-util@^24.0.0, jest-util@^24.8.0:
- version "24.8.0"
- resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-24.8.0.tgz#41f0e945da11df44cc76d64ffb915d0716f46cd1"
- integrity sha512-DYZeE+XyAnbNt0BG1OQqKy/4GVLPtzwGx5tsnDrFcax36rVE3lTA5fbvgmbVPUZf9w77AJ8otqR4VBbfFJkUZA==
+jest-util@^26.1.0, jest-util@^26.5.2:
+ version "26.5.2"
+ resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-26.5.2.tgz#8403f75677902cc52a1b2140f568e91f8ed4f4d7"
+ integrity sha512-WTL675bK+GSSAYgS8z9FWdCT2nccO1yTIplNLPlP0OD8tUk/H5IrWKMMRudIQQ0qp8bb4k+1Qa8CxGKq9qnYdg==
dependencies:
- "@jest/console" "^24.7.1"
- "@jest/fake-timers" "^24.8.0"
- "@jest/source-map" "^24.3.0"
- "@jest/test-result" "^24.8.0"
- "@jest/types" "^24.8.0"
- callsites "^3.0.0"
- chalk "^2.0.1"
- graceful-fs "^4.1.15"
+ "@jest/types" "^26.5.2"
+ "@types/node" "*"
+ chalk "^4.0.0"
+ graceful-fs "^4.2.4"
is-ci "^2.0.0"
- mkdirp "^0.5.1"
- slash "^2.0.0"
- source-map "^0.6.0"
+ micromatch "^4.0.2"
-jest-util@^25.1.0, jest-util@^25.5.0:
- version "25.5.0"
- resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-25.5.0.tgz#31c63b5d6e901274d264a4fec849230aa3fa35b0"
- integrity sha512-KVlX+WWg1zUTB9ktvhsg2PXZVdkI1NBevOJSkTKYAyXyH4QSvh+Lay/e/v+bmaFfrkfx43xD8QTfgobzlEXdIA==
+jest-validate@^26.5.2:
+ version "26.5.2"
+ resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-26.5.2.tgz#7ea266700b64234cd1c0cee982490c5a80e9b0f0"
+ integrity sha512-FmJks0zY36mp6Af/5sqO6CTL9bNMU45yKCJk3hrz8d2aIqQIlN1pr9HPIwZE8blLaewOla134nt5+xAmWsx3SQ==
dependencies:
- "@jest/types" "^25.5.0"
- chalk "^3.0.0"
- graceful-fs "^4.2.4"
- is-ci "^2.0.0"
- make-dir "^3.0.0"
+ "@jest/types" "^26.5.2"
+ camelcase "^6.0.0"
+ chalk "^4.0.0"
+ jest-get-type "^26.3.0"
+ leven "^3.1.0"
+ pretty-format "^26.5.2"
-jest-validate@^24.0.0, jest-validate@^24.8.0:
- version "24.8.0"
- resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-24.8.0.tgz#624c41533e6dfe356ffadc6e2423a35c2d3b4849"
- integrity sha512-+/N7VOEMW1Vzsrk3UWBDYTExTPwf68tavEPKDnJzrC6UlHtUDU/fuEdXqFoHzv9XnQ+zW6X3qMZhJ3YexfeLDA==
+jest-watcher@^26.5.2:
+ version "26.5.2"
+ resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-26.5.2.tgz#2957f4461007e0769d74b537379ecf6b7c696916"
+ integrity sha512-i3m1NtWzF+FXfJ3ljLBB/WQEp4uaNhX7QcQUWMokcifFTUQBDFyUMEwk0JkJ1kopHbx7Een3KX0Q7+9koGM/Pw==
dependencies:
- "@jest/types" "^24.8.0"
- camelcase "^5.0.0"
- chalk "^2.0.1"
- jest-get-type "^24.8.0"
- leven "^2.1.0"
- pretty-format "^24.8.0"
-
-jest-watcher@^24.8.0:
- version "24.8.0"
- resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-24.8.0.tgz#58d49915ceddd2de85e238f6213cef1c93715de4"
- integrity sha512-SBjwHt5NedQoVu54M5GEx7cl7IGEFFznvd/HNT8ier7cCAx/Qgu9ZMlaTQkvK22G1YOpcWBLQPFSImmxdn3DAw==
- dependencies:
- "@jest/test-result" "^24.8.0"
- "@jest/types" "^24.8.0"
- "@types/yargs" "^12.0.9"
- ansi-escapes "^3.0.0"
- chalk "^2.0.1"
- jest-util "^24.8.0"
- string-length "^2.0.0"
+ "@jest/test-result" "^26.5.2"
+ "@jest/types" "^26.5.2"
+ "@types/node" "*"
+ ansi-escapes "^4.2.1"
+ chalk "^4.0.0"
+ jest-util "^26.5.2"
+ string-length "^4.0.1"
-jest-worker@^24.6.0:
- version "24.6.0"
- resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-24.6.0.tgz#7f81ceae34b7cde0c9827a6980c35b7cdc0161b3"
- integrity sha512-jDwgW5W9qGNvpI1tNnvajh0a5IE/PuGLFmHk6aR/BZFz8tSgGw17GsDPXAJ6p91IvYDjOw8GpFbvvZGAK+DPQQ==
+jest-worker@^26.5.0:
+ version "26.5.0"
+ resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-26.5.0.tgz#87deee86dbbc5f98d9919e0dadf2c40e3152fa30"
+ integrity sha512-kTw66Dn4ZX7WpjZ7T/SUDgRhapFRKWmisVAF0Rv4Fu8SLFD7eLbqpLvbxVqYhSgaWa7I+bW7pHnbyfNsH6stug==
dependencies:
- merge-stream "^1.0.1"
- supports-color "^6.1.0"
+ "@types/node" "*"
+ merge-stream "^2.0.0"
+ supports-color "^7.0.0"
-jest@^24.1.0:
- version "24.8.0"
- resolved "https://registry.yarnpkg.com/jest/-/jest-24.8.0.tgz#d5dff1984d0d1002196e9b7f12f75af1b2809081"
- integrity sha512-o0HM90RKFRNWmAWvlyV8i5jGZ97pFwkeVoGvPW1EtLTgJc2+jcuqcbbqcSZLE/3f2S5pt0y2ZBETuhpWNl1Reg==
+jest@^26.5.2:
+ version "26.5.2"
+ resolved "https://registry.yarnpkg.com/jest/-/jest-26.5.2.tgz#c6791642b331fe7abd2f993b0a74aa546f7be0fb"
+ integrity sha512-4HFabJVwsgDwul/7rhXJ3yFAF/aUkVIXiJWmgFxb+WMdZG39fVvOwYAs8/3r4AlFPc4m/n5sTMtuMbOL3kNtrQ==
dependencies:
- import-local "^2.0.0"
- jest-cli "^24.8.0"
+ "@jest/core" "^26.5.2"
+ import-local "^3.0.2"
+ jest-cli "^26.5.2"
jmespath@0.15.0:
version "0.15.0"
resolved "https://registry.yarnpkg.com/jmespath/-/jmespath-0.15.0.tgz#a3f222a9aae9f966f5d27c796510e28091764217"
integrity sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc=
-jquery-ujs@1.2.2:
- version "1.2.2"
- resolved "https://registry.yarnpkg.com/jquery-ujs/-/jquery-ujs-1.2.2.tgz#6a8ef1020e6b6dda385b90a4bddc128c21c56397"
- integrity sha1-ao7xAg5rbdo4W5CkvdwSjCHFY5c=
- dependencies:
- jquery ">=1.8.0"
-
jquery.caret@^0.3.1:
version "0.3.1"
resolved "https://registry.yarnpkg.com/jquery.caret/-/jquery.caret-0.3.1.tgz#9c093318faf327eff322e826ca9f3241368bc7b8"
@@ -7085,26 +7135,26 @@ jquery.waitforimages@^2.2.0:
resolved "https://registry.yarnpkg.com/jquery.waitforimages/-/jquery.waitforimages-2.2.0.tgz#63f23131055a1b060dc913e6d874bcc9b9e6b16b"
integrity sha1-Y/IxMQVaGwYNyRPm2HS8ybnmsWs=
-"jquery@>= 1.9.1", jquery@>=1.8.0, jquery@^3.5.0:
+"jquery@>= 1.9.1", jquery@^3.5.0:
version "3.5.1"
resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.5.1.tgz#d7b4d08e1bfdb86ad2f1a3d039ea17304717abb5"
integrity sha512-XwIBPqcMn57FxfT+Go5pzySnm4KWkT1Tv7gjrpT1srtf8Weynl6R273VJ5GjkRb51IzMp5nbaPjJXMWeju2MKg==
js-base64@^2.1.8:
- version "2.5.1"
- resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.5.1.tgz#1efa39ef2c5f7980bb1784ade4a8af2de3291121"
- integrity sha512-M7kLczedRMYX4L8Mdh4MzyAMM9O5osx+4FcOQuTvr3A9F2D9S5JXheN0ewNbrvK2UatkTRhL5ejGmGSjNMiZuw==
+ version "2.6.4"
+ resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.6.4.tgz#f4e686c5de1ea1f867dbcad3d46d969428df98c4"
+ integrity sha512-pZe//GGmwJndub7ZghVHz7vjb2LgC1m8B07Au3eYqeqv9emhESByMXxaEgkUkEqJe87oBbSniGYoQNIBklc7IQ==
js-beautify@^1.6.12, js-beautify@^1.8.8:
- version "1.10.3"
- resolved "https://registry.yarnpkg.com/js-beautify/-/js-beautify-1.10.3.tgz#c73fa10cf69d3dfa52d8ed624f23c64c0a6a94c1"
- integrity sha512-wfk/IAWobz1TfApSdivH5PJ0miIHgDoYb1ugSqHcODPmaYu46rYe5FVuIEkhjg8IQiv6rDNPyhsqbsohI/C2vQ==
+ version "1.11.0"
+ resolved "https://registry.yarnpkg.com/js-beautify/-/js-beautify-1.11.0.tgz#afb873dc47d58986360093dcb69951e8bcd5ded2"
+ integrity sha512-a26B+Cx7USQGSWnz9YxgJNMmML/QG2nqIaL7VVYPCXbqiKz8PN0waSNvroMtvAK6tY7g/wPdNWGEP+JTNIBr6A==
dependencies:
config-chain "^1.1.12"
editorconfig "^0.15.3"
glob "^7.1.3"
- mkdirp "~0.5.1"
- nopt "~4.0.1"
+ mkdirp "~1.0.3"
+ nopt "^4.0.3"
js-cookie@^2.2.1:
version "2.2.1"
@@ -7116,7 +7166,7 @@ js-cookie@^2.2.1:
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
-js-yaml@^3.11.0, js-yaml@^3.12.0, js-yaml@^3.13.1, js-yaml@~3.13.1:
+js-yaml@^3.12.0, js-yaml@^3.13.1, js-yaml@~3.13.1:
version "3.13.1"
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847"
integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==
@@ -7159,42 +7209,10 @@ jsdoc@^3.5.5:
taffydb "2.6.2"
underscore "~1.8.3"
-jsdom@^11.5.1:
- version "11.12.0"
- resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-11.12.0.tgz#1a80d40ddd378a1de59656e9e6dc5a3ba8657bc8"
- integrity sha512-y8Px43oyiBM13Zc1z780FrfNLJCXTL40EWlty/LXUtcjykRBNgLlCjWXpfSPBl2iv+N7koQN+dvqszHZgT/Fjw==
- dependencies:
- abab "^2.0.0"
- acorn "^5.5.3"
- acorn-globals "^4.1.0"
- array-equal "^1.0.0"
- cssom ">= 0.3.2 < 0.4.0"
- cssstyle "^1.0.0"
- data-urls "^1.0.0"
- domexception "^1.0.1"
- escodegen "^1.9.1"
- html-encoding-sniffer "^1.0.2"
- left-pad "^1.3.0"
- nwsapi "^2.0.7"
- parse5 "4.0.0"
- pn "^1.1.0"
- request "^2.87.0"
- request-promise-native "^1.0.5"
- sax "^1.2.4"
- symbol-tree "^3.2.2"
- tough-cookie "^2.3.4"
- w3c-hr-time "^1.0.1"
- webidl-conversions "^4.0.2"
- whatwg-encoding "^1.0.3"
- whatwg-mimetype "^2.1.0"
- whatwg-url "^6.4.1"
- ws "^5.2.0"
- xml-name-validator "^3.0.0"
-
-jsdom@^16.2.1:
- version "16.2.2"
- resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-16.2.2.tgz#76f2f7541646beb46a938f5dc476b88705bedf2b"
- integrity sha512-pDFQbcYtKBHxRaP55zGXCJWgFHkDAYbKcsXEK/3Icu9nKYZkutUXfLBwbD+09XDutkYSHcgfQLZ0qvpAAm9mvg==
+jsdom@^16.4.0:
+ version "16.4.0"
+ resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-16.4.0.tgz#36005bde2d136f73eee1a830c6d45e55408edddb"
+ integrity sha512-lYMm3wYdgPhrl7pDcRmvzPhhrGVBeVhPIqeHjzeiHN3DFmD1RBpbExbi8vU7BJdH8VAZYovR8DMt0PNNDM7k8w==
dependencies:
abab "^2.0.3"
acorn "^7.1.1"
@@ -7216,7 +7234,7 @@ jsdom@^16.2.1:
tough-cookie "^3.0.1"
w3c-hr-time "^1.0.2"
w3c-xmlserializer "^2.0.0"
- webidl-conversions "^6.0.0"
+ webidl-conversions "^6.1.0"
whatwg-encoding "^1.0.5"
whatwg-mimetype "^2.3.0"
whatwg-url "^8.0.0"
@@ -7243,6 +7261,11 @@ json-parse-better-errors@^1.0.1, json-parse-better-errors@^1.0.2:
resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9"
integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==
+json-parse-even-better-errors@^2.3.0:
+ version "2.3.1"
+ resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d"
+ integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==
+
json-schema-traverse@^0.4.1:
version "0.4.1"
resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
@@ -7459,7 +7482,7 @@ klaw@~2.0.0:
dependencies:
graceful-fs "^4.1.9"
-kleur@^3.0.2:
+kleur@^3.0.3:
version "3.0.3"
resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e"
integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==
@@ -7476,13 +7499,6 @@ latest-version@^5.0.0:
dependencies:
package-json "^6.3.0"
-lcid@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835"
- integrity sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=
- dependencies:
- invert-kv "^1.0.0"
-
lcid@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/lcid/-/lcid-2.0.0.tgz#6ef5d2df60e52f82eb228a4c373e8d1f397253cf"
@@ -7490,16 +7506,6 @@ lcid@^2.0.0:
dependencies:
invert-kv "^2.0.0"
-left-pad@^1.3.0:
- version "1.3.0"
- resolved "https://registry.yarnpkg.com/left-pad/-/left-pad-1.3.0.tgz#5b8a3a7765dfe001261dde915589e782f8c94d1e"
- integrity sha512-XI5MPzVNApjAyhQzphX8BkmKsKUxD4LdyK24iZeQGinBN9yTQT3bFlCBy/aVx2HrNcqQGsdot8ghrjyrvMCoEA==
-
-leven@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/leven/-/leven-2.1.0.tgz#c2e7a9f772094dee9d34202ae8acce4687875580"
- integrity sha1-wuep93IJTe6dNCAq6KzORoeHVYA=
-
leven@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2"
@@ -7532,6 +7538,11 @@ lightercollective@^0.3.0:
resolved "https://registry.yarnpkg.com/lightercollective/-/lightercollective-0.3.0.tgz#1f07638642ec645d70bdb69ab2777676f35a28f0"
integrity sha512-RFOLSUVvwdK3xA0P8o6G7QGXLIyy1L2qv5caEI7zXN5ciaEjbAriRF182kbsoJ1S1TgvpyGcN485fMky6qxOPw==
+lines-and-columns@^1.1.6:
+ version "1.1.6"
+ resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00"
+ integrity sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=
+
linkify-it@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-2.1.0.tgz#c4caf38a6cd7ac2212ef3c7d2bde30a91561f9db"
@@ -7539,6 +7550,11 @@ linkify-it@^2.0.0:
dependencies:
uc.micro "^1.0.1"
+linkifyjs@^2.1.9:
+ version "2.1.9"
+ resolved "https://registry.yarnpkg.com/linkifyjs/-/linkifyjs-2.1.9.tgz#af06e45a2866ff06c4766582590d098a4d584702"
+ integrity sha512-74ivurkK6WHvHFozVaGtQWV38FzBwSTGNmJolEgFp7QgR2bl6ArUWlvT4GcHKbPe1z3nWYi+VUdDZk16zDOVug==
+
load-json-file@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0"
@@ -7716,6 +7732,11 @@ lodash.mapvalues@^4.6.0:
resolved "https://registry.yarnpkg.com/lodash.mapvalues/-/lodash.mapvalues-4.6.0.tgz#1bafa5005de9dd6f4f26668c30ca37230cc9689c"
integrity sha1-G6+lAF3p3W9PJmaMMMo3IwzJaJw=
+lodash.memoize@4.x:
+ version "4.1.2"
+ resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe"
+ integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=
+
lodash.pick@^4.4.0:
version "4.4.0"
resolved "https://registry.yarnpkg.com/lodash.pick/-/lodash.pick-4.4.0.tgz#52f05610fff9ded422611441ed1fc123a03001b3"
@@ -7751,7 +7772,7 @@ lodash.values@^4.3.0:
resolved "https://registry.yarnpkg.com/lodash.values/-/lodash.values-4.3.0.tgz#a3a6c2b0ebecc5c2cba1c17e6e620fe81b53d347"
integrity sha1-o6bCsOvsxcLLocF+bmIP6BtT00c=
-lodash@^4.0.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.20, lodash@~4.17.10:
+lodash@^4.0.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@~4.17.10:
version "4.17.20"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52"
integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==
@@ -7786,13 +7807,6 @@ loglevel@^1.6.6:
resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.6.7.tgz#b3e034233188c68b889f5b862415306f565e2c56"
integrity sha512-cY2eLFrQSAfVPhCgH1s7JI73tMbg9YC3v3+ZHVW67sBS7UxWzNEk/ZBbSfLykBWHp33dqqtOv82gjhKEi81T/A==
-lolex@^5.0.0:
- version "5.1.2"
- resolved "https://registry.yarnpkg.com/lolex/-/lolex-5.1.2.tgz#953694d098ce7c07bc5ed6d0e42bc6c0c6d5a367"
- integrity sha512-h4hmjAvHTmd+25JSwrtTIuwbKdwg5NzZVRMLn9saij4SZaepCrTCxPr35H/3bjwfMJtN+t3CX8672UIkglz28A==
- dependencies:
- "@sinonjs/commons" "^1.7.0"
-
longest-streak@^2.0.1:
version "2.0.2"
resolved "https://registry.yarnpkg.com/longest-streak/-/longest-streak-2.0.2.tgz#2421b6ba939a443bb9ffebf596585a50b4c38e2e"
@@ -7872,9 +7886,9 @@ make-dir@^3.0.0:
semver "^6.0.0"
make-error@1.x:
- version "1.3.5"
- resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.5.tgz#efe4e81f6db28cadd605c70f29c831b58ef776c8"
- integrity sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g==
+ version "1.3.6"
+ resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2"
+ integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==
makeerror@1.0.x:
version "1.0.11"
@@ -8090,12 +8104,10 @@ merge-source-map@^1.1.0:
dependencies:
source-map "^0.6.1"
-merge-stream@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-1.0.1.tgz#4041202d508a342ba00174008df0c251b8c135e1"
- integrity sha1-QEEgLVCKNCugAXQAjfDCUbjBNeE=
- dependencies:
- readable-stream "^2.0.1"
+merge-stream@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60"
+ integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==
merge2@^1.2.3:
version "1.2.3"
@@ -8164,17 +8176,17 @@ miller-rabin@^4.0.0:
bn.js "^4.0.0"
brorand "^1.0.1"
-mime-db@1.40.0, "mime-db@>= 1.40.0 < 2":
- version "1.40.0"
- resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.40.0.tgz#a65057e998db090f732a68f6c276d387d4126c32"
- integrity sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==
+mime-db@1.44.0, "mime-db@>= 1.40.0 < 2":
+ version "1.44.0"
+ resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.44.0.tgz#fa11c5eb0aca1334b4233cb4d52f10c5a6272f92"
+ integrity sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==
mime-types@^2.1.12, mime-types@~2.1.17, mime-types@~2.1.19, mime-types@~2.1.24:
- version "2.1.24"
- resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.24.tgz#b6f8d0b3e951efb77dedeca194cff6d16f676f81"
- integrity sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==
+ version "2.1.27"
+ resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.27.tgz#47949f98e279ea53119f5722e0f34e529bec009f"
+ integrity sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==
dependencies:
- mime-db "1.40.0"
+ mime-db "1.44.0"
mime@1.6.0:
version "1.6.0"
@@ -8340,7 +8352,12 @@ mixin-deep@^1.2.0:
for-in "^1.0.2"
is-extendable "^1.0.1"
-mkdirp@0.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.1:
+mkdirp@1.x, mkdirp@^1.0.4, mkdirp@~1.0.3:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e"
+ integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==
+
+"mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.1:
version "0.5.1"
resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=
@@ -8426,7 +8443,7 @@ mute-stream@0.0.8:
resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d"
integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==
-nan@^2.12.1, nan@^2.13.2:
+nan@^2.13.2:
version "2.14.1"
resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.1.tgz#d7be34dfa3105b91494c3147089315eff8874b01"
integrity sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw==
@@ -8547,26 +8564,27 @@ node-modules-regexp@^1.0.0:
resolved "https://registry.yarnpkg.com/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz#8d9dbe28964a4ac5712e9131642107c71e90ec40"
integrity sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=
-node-notifier@^5.2.1:
- version "5.4.0"
- resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-5.4.0.tgz#7b455fdce9f7de0c63538297354f3db468426e6a"
- integrity sha512-SUDEb+o71XR5lXSTyivXd9J7fCloE3SyP4lSgt3lU2oSANiox+SxlNRGPjDKrwU1YN3ix2KN/VGGCg0t01rttQ==
+node-notifier@^8.0.0:
+ version "8.0.0"
+ resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-8.0.0.tgz#a7eee2d51da6d0f7ff5094bc7108c911240c1620"
+ integrity sha512-46z7DUmcjoYdaWyXouuFNNfUo6eFa94t23c53c+lG/9Cvauk4a98rAUp9672X5dxGdQmLpPzTxzu8f/OeEPaFA==
dependencies:
growly "^1.3.0"
- is-wsl "^1.1.0"
- semver "^5.5.0"
+ is-wsl "^2.2.0"
+ semver "^7.3.2"
shellwords "^0.1.1"
- which "^1.3.0"
+ uuid "^8.3.0"
+ which "^2.0.2"
node-releases@^1.1.53:
version "1.1.58"
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.58.tgz#8ee20eef30fa60e52755fcc0942def5a734fe935"
integrity sha512-NxBudgVKiRh/2aPWMgPR7bPTX0VPmGx5QBwCtdHitnqFE5/O8DeBXuIMH1nwNnw/aMo6AjOrpsHzfY3UbUJ7yg==
-node-sass@^4.12.0:
- version "4.12.0"
- resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-4.12.0.tgz#0914f531932380114a30cc5fa4fa63233a25f017"
- integrity sha512-A1Iv4oN+Iel6EPv77/HddXErL2a+gZ4uBeZUy+a8O35CFYTXhgA8MgLCWBtwpGZdCvTvQ9d+bQxX/QC36GDPpQ==
+node-sass@^4.14.1:
+ version "4.14.1"
+ resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-4.14.1.tgz#99c87ec2efb7047ed638fb4c9db7f3a42e2217b5"
+ integrity sha512-sjCuOlvGyCJS40R8BscF5vhVlQjNN069NtQ1gSxyK1u9iqvn6tf7O1R4GNowVZfiZUCRt5MmMs1xd+4V/7Yr0g==
dependencies:
async-foreach "^0.1.3"
chalk "^1.1.1"
@@ -8575,14 +8593,14 @@ node-sass@^4.12.0:
get-stdin "^4.0.1"
glob "^7.0.3"
in-publish "^2.0.0"
- lodash "^4.17.11"
+ lodash "^4.17.15"
meow "^3.7.0"
mkdirp "^0.5.1"
nan "^2.13.2"
node-gyp "^3.8.0"
npmlog "^4.0.0"
request "^2.88.0"
- sass-graph "^2.2.4"
+ sass-graph "2.2.5"
stdout-stream "^1.4.0"
"true-case-path" "^1.0.2"
@@ -8609,6 +8627,14 @@ nodemon@^2.0.4:
dependencies:
abbrev "1"
+nopt@^4.0.3:
+ version "4.0.3"
+ resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.3.tgz#a375cad9d02fd921278d954c2254d5aa57e15e48"
+ integrity sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==
+ dependencies:
+ abbrev "1"
+ osenv "^0.1.4"
+
nopt@~1.0.10:
version "1.0.10"
resolved "https://registry.yarnpkg.com/nopt/-/nopt-1.0.10.tgz#6ddd21bd2a31417b92727dd585f8a6f37608ebee"
@@ -8616,15 +8642,7 @@ nopt@~1.0.10:
dependencies:
abbrev "1"
-nopt@~4.0.1:
- version "4.0.1"
- resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d"
- integrity sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=
- dependencies:
- abbrev "1"
- osenv "^0.1.4"
-
-normalize-package-data@^2.3.2, normalize-package-data@^2.3.4:
+normalize-package-data@^2.3.2, normalize-package-data@^2.3.4, normalize-package-data@^2.5.0:
version "2.5.0"
resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8"
integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==
@@ -8668,6 +8686,13 @@ npm-run-path@^2.0.0:
dependencies:
path-key "^2.0.0"
+npm-run-path@^4.0.0:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea"
+ integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==
+ dependencies:
+ path-key "^3.0.0"
+
"npmlog@0 || 1 || 2 || 3 || 4", npmlog@^4.0.0:
version "4.1.2"
resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b"
@@ -8688,7 +8713,7 @@ number-is-nan@^1.0.0:
resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d"
integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=
-nwsapi@^2.0.7, nwsapi@^2.2.0:
+nwsapi@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.0.tgz#204879a9e3d068ff2a55139c2c772780681a38b7"
integrity sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==
@@ -8754,14 +8779,6 @@ object.entries@^1.1.0:
function-bind "^1.1.1"
has "^1.0.3"
-object.getownpropertydescriptors@^2.0.3:
- version "2.0.3"
- resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz#8758c846f5b407adab0f236e0986f14b051caa16"
- integrity sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY=
- dependencies:
- define-properties "^1.1.2"
- es-abstract "^1.5.1"
-
object.pick@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747"
@@ -8871,13 +8888,6 @@ os-homedir@^1.0.0:
resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3"
integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M=
-os-locale@^1.4.0:
- version "1.4.0"
- resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9"
- integrity sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=
- dependencies:
- lcid "^1.0.0"
-
os-locale@^3.0.0, os-locale@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-3.1.0.tgz#a802a6ee17f24c10483ab9935719cef4ed16bf1a"
@@ -8910,12 +8920,10 @@ p-defer@^1.0.0:
resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c"
integrity sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=
-p-each-series@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/p-each-series/-/p-each-series-1.0.0.tgz#930f3d12dd1f50e7434457a22cd6f04ac6ad7f71"
- integrity sha1-kw89Et0fUOdDRFeiLNbwSsatf3E=
- dependencies:
- p-reduce "^1.0.0"
+p-each-series@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/p-each-series/-/p-each-series-2.1.0.tgz#961c8dd3f195ea96c747e636b262b800a6b1af48"
+ integrity sha512-ZuRs1miPT4HrjFa+9fRfOFXxGJfORgelKV9f9nNOWw2gl6gVsRaVDOQP0+MI0G0wGKns1Yacsu0GjOFbTK0JFQ==
p-finally@^1.0.0:
version "1.0.0"
@@ -8974,11 +8982,6 @@ p-map@^3.0.0:
dependencies:
aggregate-error "^3.0.0"
-p-reduce@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/p-reduce/-/p-reduce-1.0.0.tgz#18c2b0dd936a4690a529f8231f58a0fdb6a47dfa"
- integrity sha1-GMKw3ZNqRpClKfgjH1ig/bakffo=
-
p-retry@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/p-retry/-/p-retry-3.0.1.tgz#316b4c8893e2c8dc1cfa891f406c4b422bebf328"
@@ -9079,16 +9082,21 @@ parse-json@^4.0.0:
error-ex "^1.3.1"
json-parse-better-errors "^1.0.1"
+parse-json@^5.0.0:
+ version "5.1.0"
+ resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.1.0.tgz#f96088cdf24a8faa9aea9a009f2d9d942c999646"
+ integrity sha512-+mi/lmVVNKFNVyLXV31ERiy2CY5E1/F6QtJFEzoChPRwwngMNXRDQ9GJ5WdE2Z2P4AujsOi0/+2qHID68KwfIQ==
+ dependencies:
+ "@babel/code-frame" "^7.0.0"
+ error-ex "^1.3.1"
+ json-parse-even-better-errors "^2.3.0"
+ lines-and-columns "^1.1.6"
+
parse-passwd@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6"
integrity sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=
-parse5@4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/parse5/-/parse5-4.0.0.tgz#6d78656e3da8d78b4ec0b906f7c08ef1dfe3f608"
- integrity sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA==
-
parse5@5.1.1, parse5@^5:
version "5.1.1"
resolved "https://registry.yarnpkg.com/parse5/-/parse5-5.1.1.tgz#f68e4e5ba1852ac2cadc00f4555fff6c2abb6178"
@@ -9160,6 +9168,11 @@ path-key@^2.0.0, path-key@^2.0.1:
resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40"
integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=
+path-key@^3.0.0, path-key@^3.1.0:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375"
+ integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==
+
path-parse@^1.0.6:
version "1.0.6"
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c"
@@ -9282,7 +9295,7 @@ pkg-dir@^3.0.0:
dependencies:
find-up "^3.0.0"
-pkg-dir@^4.1.0:
+pkg-dir@^4.1.0, pkg-dir@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3"
integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==
@@ -9296,11 +9309,6 @@ pkg-up@^2.0.0:
dependencies:
find-up "^2.1.0"
-pn@^1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/pn/-/pn-1.1.0.tgz#e2f4cef0e219f463c179ab37463e4e1ecdccbafb"
- integrity sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==
-
pngjs@^3.0.0:
version "3.3.3"
resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-3.3.3.tgz#85173703bde3edac8998757b96e5821d0966a21b"
@@ -9447,15 +9455,6 @@ postcss-selector-parser@^3.1.0:
indexes-of "^1.0.1"
uniq "^1.0.1"
-postcss-selector-parser@^5.0.0:
- version "5.0.0"
- resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz#249044356697b33b64f1a8f7c80922dddee7195c"
- integrity sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ==
- dependencies:
- cssesc "^2.0.0"
- indexes-of "^1.0.1"
- uniq "^1.0.1"
-
postcss-selector-parser@^6.0.0, postcss-selector-parser@^6.0.2:
version "6.0.2"
resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.2.tgz#934cf799d016c83411859e09dcecade01286ec5c"
@@ -9507,11 +9506,6 @@ pretender@^3.4.3:
fake-xml-http-request "^2.1.1"
route-recognizer "^0.3.3"
-prettier@1.16.3:
- version "1.16.3"
- resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.16.3.tgz#8c62168453badef702f34b45b6ee899574a6a65d"
- integrity sha512-kn/GU6SMRYPxUakNXhpP0EedT/KmaPzr0H5lIsDogrykbaxOpOfAFfk5XA7DZrJyMAv1wlMV3CPcZruGXVVUZw==
-
prettier@1.18.2:
version "1.18.2"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.18.2.tgz#6823e7c5900017b4bd3acf46fe9ac4b4d7bda9ea"
@@ -9522,17 +9516,7 @@ prettier@^1.18.2, prettier@^1.19.1:
resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.19.1.tgz#f7d7f5ff8a9cd872a7be4ca142095956a60797cb"
integrity sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==
-pretty-format@^24.8.0:
- version "24.8.0"
- resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-24.8.0.tgz#8dae7044f58db7cb8be245383b565a963e3c27f2"
- integrity sha512-P952T7dkrDEplsR+TuY7q3VXDae5Sr7zmQb12JU/NDQa/3CH7/QW0yvqLcGN6jL+zQFKaoJcPc+yJxMTGmosqw==
- dependencies:
- "@jest/types" "^24.8.0"
- ansi-regex "^4.0.0"
- ansi-styles "^3.2.0"
- react-is "^16.8.4"
-
-pretty-format@^25.5.0:
+pretty-format@^25.2.1, pretty-format@^25.5.0:
version "25.5.0"
resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-25.5.0.tgz#7873c1d774f682c34b8d48b6743a2bf2ac55791a"
integrity sha512-kbo/kq2LQ/A/is0PQwsEHM7Ca6//bGPPvU6UnsdDRSKTWxT/ru/xb88v4BJf6a69H+uTytOEsTusT9ksd/1iWQ==
@@ -9542,6 +9526,16 @@ pretty-format@^25.5.0:
ansi-styles "^4.0.0"
react-is "^16.12.0"
+pretty-format@^26.4.2, pretty-format@^26.5.2:
+ version "26.5.2"
+ resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-26.5.2.tgz#5d896acfdaa09210683d34b6dc0e6e21423cd3e1"
+ integrity sha512-VizyV669eqESlkOikKJI8Ryxl/kPpbdLwNdPs2GrbQs18MpySB5S0Yo0N7zkg2xTRiFq4CFw8ct5Vg4a0xP0og==
+ dependencies:
+ "@jest/types" "^26.5.2"
+ ansi-regex "^5.0.0"
+ ansi-styles "^4.0.0"
+ react-is "^16.12.0"
+
pretty@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/pretty/-/pretty-2.0.0.tgz#adbc7960b7bbfe289a557dc5f737619a220d06a5"
@@ -9589,12 +9583,12 @@ promise-inflight@^1.0.1:
integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM=
prompts@^2.0.1:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.1.0.tgz#bf90bc71f6065d255ea2bdc0fe6520485c1b45db"
- integrity sha512-+x5TozgqYdOwWsQFZizE/Tra3fKvAoy037kOyU6cgz84n8f6zxngLOV4O32kTwt9FcLCxAqw0P/c8rOr9y+Gfg==
+ version "2.3.2"
+ resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.3.2.tgz#480572d89ecf39566d2bd3fe2c9fccb7c4c0b068"
+ integrity sha512-Q06uKs2CkNYVID0VqwfAl9mipo99zkBv/n2JtWY89Yxa3ZabWSrs0e2KTudKVa3peLUvYXMefDqIleLPVUBZMA==
dependencies:
- kleur "^3.0.2"
- sisteransi "^1.0.0"
+ kleur "^3.0.3"
+ sisteransi "^1.0.4"
prosemirror-commands@^1.0.7:
version "1.0.7"
@@ -9888,7 +9882,7 @@ rc@^1.2.8, rc@~1.2.7:
minimist "^1.2.0"
strip-json-comments "~2.0.1"
-react-is@^16.12.0, react-is@^16.8.4:
+react-is@^16.12.0:
version "16.13.1"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
@@ -9917,13 +9911,14 @@ read-pkg-up@^3.0.0:
find-up "^2.0.0"
read-pkg "^3.0.0"
-read-pkg-up@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-4.0.0.tgz#1b221c6088ba7799601c808f91161c66e58f8978"
- integrity sha512-6etQSH7nJGsK0RbG/2TeDzZFa8shjQ1um+SwQQ5cwKy0dhSXdOncEhb1CPpvQG4h7FyOV6EB6YlV0yJvZQNAkA==
+read-pkg-up@^7.0.1:
+ version "7.0.1"
+ resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-7.0.1.tgz#f3a6135758459733ae2b95638056e1854e7ef507"
+ integrity sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==
dependencies:
- find-up "^3.0.0"
- read-pkg "^3.0.0"
+ find-up "^4.1.0"
+ read-pkg "^5.2.0"
+ type-fest "^0.8.1"
read-pkg@^1.0.0:
version "1.1.0"
@@ -9952,10 +9947,20 @@ read-pkg@^3.0.0:
normalize-package-data "^2.3.2"
path-type "^3.0.0"
+read-pkg@^5.2.0:
+ version "5.2.0"
+ resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-5.2.0.tgz#7bf295438ca5a33e56cd30e053b34ee7250c93cc"
+ integrity sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==
+ dependencies:
+ "@types/normalize-package-data" "^2.4.0"
+ normalize-package-data "^2.5.0"
+ parse-json "^5.0.0"
+ type-fest "^0.6.0"
+
"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.6, readable-stream@~2.3.6:
- version "2.3.6"
- resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf"
- integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==
+ version "2.3.7"
+ resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57"
+ integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==
dependencies:
core-util-is "~1.0.0"
inherits "~2.0.3"
@@ -10001,13 +10006,6 @@ readdirp@~3.4.0:
dependencies:
picomatch "^2.2.1"
-realpath-native@^1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/realpath-native/-/realpath-native-1.1.0.tgz#2003294fea23fb0672f2476ebe22fcf498a2d65c"
- integrity sha512-wlgPA6cCIIg9gKz0fgAPjnzh4yR/LnXovwuo9hvyGvx3h8nX4+/iLZplfUWasXpqD8BdnGnP5njOFjkUwPzvjA==
- dependencies:
- util.promisify "^1.0.0"
-
redent@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde"
@@ -10182,19 +10180,19 @@ replace-ext@1.0.0:
resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-1.0.0.tgz#de63128373fcbf7c3ccfa4de5a480c45a67958eb"
integrity sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs=
-request-promise-core@1.1.3:
- version "1.1.3"
- resolved "https://registry.yarnpkg.com/request-promise-core/-/request-promise-core-1.1.3.tgz#e9a3c081b51380dfea677336061fea879a829ee9"
- integrity sha512-QIs2+ArIGQVp5ZYbWD5ZLCY29D5CfWizP8eWnm8FoGD1TX61veauETVQbrV60662V0oFBkrDOuaBI8XgtuyYAQ==
+request-promise-core@1.1.4:
+ version "1.1.4"
+ resolved "https://registry.yarnpkg.com/request-promise-core/-/request-promise-core-1.1.4.tgz#3eedd4223208d419867b78ce815167d10593a22f"
+ integrity sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw==
dependencies:
- lodash "^4.17.15"
+ lodash "^4.17.19"
-request-promise-native@^1.0.5, request-promise-native@^1.0.8:
- version "1.0.8"
- resolved "https://registry.yarnpkg.com/request-promise-native/-/request-promise-native-1.0.8.tgz#a455b960b826e44e2bf8999af64dff2bfe58cb36"
- integrity sha512-dapwLGqkHtwL5AEbfenuzjTYg35Jd6KPytsC2/TLkVMz8rm+tNt72MGUWT1RP/aYawMpN6HqbNGBQaRcBtjQMQ==
+request-promise-native@^1.0.8:
+ version "1.0.9"
+ resolved "https://registry.yarnpkg.com/request-promise-native/-/request-promise-native-1.0.9.tgz#e407120526a5efdc9a39b28a5679bf47b9d9dc28"
+ integrity sha512-wcW+sIUiWnKgNY0dqCpOZkUbF/I+YPi+f09JZIDa39Ec+q82CpSYniDp+ISgTTbKmnpJWASeJBPZmoxH84wt3g==
dependencies:
- request-promise-core "1.1.3"
+ request-promise-core "1.1.4"
stealthy-require "^1.1.1"
tough-cookie "^2.3.3"
@@ -10268,6 +10266,13 @@ resolve-cwd@^2.0.0:
dependencies:
resolve-from "^3.0.0"
+resolve-cwd@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d"
+ integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==
+ dependencies:
+ resolve-from "^5.0.0"
+
resolve-dir@^1.0.0, resolve-dir@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/resolve-dir/-/resolve-dir-1.0.1.tgz#79a40644c362be82f26effe739c9bb5382046f43"
@@ -10296,15 +10301,10 @@ resolve-url@^0.2.1:
resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a"
integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=
-resolve@1.1.7:
- version "1.1.7"
- resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b"
- integrity sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=
-
-resolve@1.x, resolve@^1.10.0, resolve@^1.12.0, resolve@^1.13.1, resolve@^1.3.2, resolve@^1.5.0:
- version "1.15.0"
- resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.15.0.tgz#1b7ca96073ebb52e741ffd799f6b39ea462c67f5"
- integrity sha512-+hTmAldEGE80U2wJJDC1lebb5jWqvTYAfm3YZ1ckk1gBr0MnCqUKlwK1e+anaFljIl+F5tR5IoZcm4ZDA1zMQw==
+resolve@^1.10.0, resolve@^1.12.0, resolve@^1.13.1, resolve@^1.17.0, resolve@^1.3.2, resolve@^1.5.0:
+ version "1.17.0"
+ resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.17.0.tgz#b25941b54968231cc2d1bb76a79cb7f2c0bf8444"
+ integrity sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==
dependencies:
path-parse "^1.0.6"
@@ -10352,6 +10352,13 @@ rimraf@2.6.3:
dependencies:
glob "^7.1.3"
+rimraf@^3.0.0:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
+ integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==
+ dependencies:
+ glob "^7.1.3"
+
ripemd160@^2.0.0, ripemd160@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.1.tgz#0f4584295c53a3628af7e6d79aca21ce57d1c6e7"
@@ -10433,26 +10440,21 @@ sane@^4.0.3:
minimist "^1.1.1"
walker "~1.0.5"
-sass-graph@^2.2.4:
- version "2.2.4"
- resolved "https://registry.yarnpkg.com/sass-graph/-/sass-graph-2.2.4.tgz#13fbd63cd1caf0908b9fd93476ad43a51d1e0b49"
- integrity sha1-E/vWPNHK8JCLn9k0dq1DpR0eC0k=
+sass-graph@2.2.5:
+ version "2.2.5"
+ resolved "https://registry.yarnpkg.com/sass-graph/-/sass-graph-2.2.5.tgz#a981c87446b8319d96dce0671e487879bd24c2e8"
+ integrity sha512-VFWDAHOe6mRuT4mZRd4eKE+d8Uedrk6Xnh7Sh9b4NGufQLQjOrvf/MQoOdx+0s92L89FeyUUNfU597j/3uNpag==
dependencies:
glob "^7.0.0"
lodash "^4.0.0"
scss-tokenizer "^0.2.3"
- yargs "^7.0.0"
+ yargs "^13.3.2"
-sax@1.2.1:
+sax@1.2.1, sax@>=0.6.0:
version "1.2.1"
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.1.tgz#7b8e656190b228e81a66aea748480d828cd2d37a"
integrity sha1-e45lYZCyKOgaZq6nSEgNgozS03o=
-sax@>=0.6.0, sax@^1.2.4:
- version "1.2.4"
- resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
- integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==
-
saxes@^5.0.0:
version "5.0.1"
resolved "https://registry.yarnpkg.com/saxes/-/saxes-5.0.1.tgz#eebab953fa3b7608dbe94e5dadb15c888fa6696d"
@@ -10502,14 +10504,6 @@ scss-tokenizer@^0.2.3:
js-base64 "^2.1.8"
source-map "^0.4.2"
-section-matter@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/section-matter/-/section-matter-1.0.0.tgz#e9041953506780ec01d59f292a19c7b850b84167"
- integrity sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==
- dependencies:
- extend-shallow "^2.0.1"
- kind-of "^6.0.0"
-
select-hose@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca"
@@ -10539,7 +10533,7 @@ semver-diff@^3.1.1:
dependencies:
semver "^6.3.0"
-"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.4.1, semver@^5.5, semver@^5.5.0, semver@^5.6.0, semver@^5.7.1:
+"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.6.0, semver@^5.7.1:
version "5.7.1"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
@@ -10549,6 +10543,11 @@ semver@7.0.0:
resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e"
integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==
+semver@7.x, semver@^7.3.2:
+ version "7.3.2"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.2.tgz#604962b052b81ed0786aae84389ffba70ffd3938"
+ integrity sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==
+
semver@^6.0.0, semver@^6.1.2, semver@^6.2.0, semver@^6.3.0:
version "6.3.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
@@ -10658,11 +10657,23 @@ shebang-command@^1.2.0:
dependencies:
shebang-regex "^1.0.0"
+shebang-command@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea"
+ integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==
+ dependencies:
+ shebang-regex "^3.0.0"
+
shebang-regex@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3"
integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=
+shebang-regex@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172"
+ integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
+
shellwords@^0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b"
@@ -10674,14 +10685,14 @@ sigmund@^1.0.1:
integrity sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=
signal-exit@^3.0.0, signal-exit@^3.0.2:
- version "3.0.2"
- resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
- integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c"
+ integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==
-sisteransi@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.0.tgz#77d9622ff909080f1c19e5f4a1df0c1b0a27b88c"
- integrity sha512-N+z4pHB4AmUv0SjveWRd6q1Nj5w62m5jodv+GD8lvmbY/83T/rpbJGZOnK5T149OldDj4Db07BSv9xY4K6NTPQ==
+sisteransi@^1.0.4:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed"
+ integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==
slash@^1.0.0:
version "1.0.0"
@@ -10828,20 +10839,20 @@ source-list-map@^2.0.0:
integrity sha512-I2UmuJSRr/T8jisiROLU3A3ltr+swpniSmNPI4Ml3ZCX6tVnDsuZzK7F2hl5jTqbZBWCEKlj5HRQiPExXLgE8A==
source-map-resolve@^0.5.0, source-map-resolve@^0.5.2:
- version "0.5.2"
- resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259"
- integrity sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==
+ version "0.5.3"
+ resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a"
+ integrity sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==
dependencies:
- atob "^2.1.1"
+ atob "^2.1.2"
decode-uri-component "^0.2.0"
resolve-url "^0.2.1"
source-map-url "^0.4.0"
urix "^0.1.0"
source-map-support@^0.5.6, source-map-support@~0.5.12:
- version "0.5.13"
- resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.13.tgz#31b24a9c2e73c2de85066c0feb7d44767ed52932"
- integrity sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==
+ version "0.5.19"
+ resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61"
+ integrity sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==
dependencies:
buffer-from "^1.0.0"
source-map "^0.6.0"
@@ -10856,6 +10867,11 @@ source-map@0.5.0:
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.0.tgz#0fe96503ac86a5adb5de63f4e412ae4872cdbe86"
integrity sha1-D+llA6yGpa213mP05BKuSHLNvoY=
+source-map@0.5.6, source-map@^0.5.0, source-map@^0.5.6:
+ version "0.5.6"
+ resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412"
+ integrity sha1-dc449SvwczxafwwRjYEzSiu19BI=
+
source-map@^0.4.2:
version "0.4.4"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b"
@@ -10863,11 +10879,6 @@ source-map@^0.4.2:
dependencies:
amdefine ">=0.0.4"
-source-map@^0.5.0, source-map@^0.5.6:
- version "0.5.7"
- resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
- integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=
-
source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
@@ -10878,22 +10889,31 @@ source-map@^0.7.3:
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383"
integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==
-spdx-correct@~1.0.0:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-1.0.2.tgz#4b3073d933ff51f3912f03ac5519498a4150db40"
- integrity sha1-SzBz2TP/UfORLwOsVRlJikFQ20A=
+spdx-correct@^3.0.0:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.1.tgz#dece81ac9c1e6713e5f7d1b6f17d468fa53d89a9"
+ integrity sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==
dependencies:
- spdx-license-ids "^1.0.2"
+ spdx-expression-parse "^3.0.0"
+ spdx-license-ids "^3.0.0"
-spdx-expression-parse@~1.0.0:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz#9bdf2f20e1f40ed447fbe273266191fced51626c"
- integrity sha1-m98vIOH0DtRH++JzJmGR/O1RYmw=
+spdx-exceptions@^2.1.0:
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz#3f28ce1a77a00372683eade4a433183527a2163d"
+ integrity sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==
-spdx-license-ids@^1.0.2:
- version "1.2.2"
- resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz#c9df7a3424594ade6bd11900d596696dc06bac57"
- integrity sha1-yd96NCRZSt5r0RkA1ZZpbcBrrFc=
+spdx-expression-parse@^3.0.0:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679"
+ integrity sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==
+ dependencies:
+ spdx-exceptions "^2.1.0"
+ spdx-license-ids "^3.0.0"
+
+spdx-license-ids@^3.0.0:
+ version "3.0.6"
+ resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.6.tgz#c80757383c28abf7296744998cbc106ae8b854ce"
+ integrity sha512-+orQK83kyMva3WyPf59k1+Y525csj5JejicWut55zeTWANuN17qSiSLUXWtzHeNWORSvT7GLDJ/E/XiIWoXBTw==
spdy-transport@^3.0.0:
version "3.0.0"
@@ -10941,9 +10961,9 @@ sql.js@^0.4.0:
integrity sha1-I76WNVIOsP9Dp0Hn6DA5cmbohEU=
sshpk@^1.7.0:
- version "1.15.2"
- resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.15.2.tgz#c946d6bd9b1a39d0e8635763f5242d6ed6dcb629"
- integrity sha512-Ra/OXQtuh0/enyl4ETZAfTaeksa6BXks5ZcjpSUNrjBr0DvrJKX+1fsKDPpT9TBXgHAFsa4510aNVgI8g/+SzA==
+ version "1.16.1"
+ resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877"
+ integrity sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==
dependencies:
asn1 "~0.2.3"
assert-plus "^1.0.0"
@@ -10970,10 +10990,12 @@ ssri@^7.0.0:
figgy-pudding "^3.5.1"
minipass "^3.1.1"
-stack-utils@^1.0.1:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-1.0.2.tgz#33eba3897788558bebfc2db059dc158ec36cebb8"
- integrity sha512-MTX+MeG5U994cazkjd/9KNAapsHnibjMLnfXodlkXw76JEea0UiNzrqidzo1emMwk7w5Qhc9jd4Bn9TBb1MFwA==
+stack-utils@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.2.tgz#5cf48b4557becb4638d0bc4f21d23f5d19586593"
+ integrity sha512-0H7QK2ECz3fyZMzQ8rH0j2ykpfbnd20BFtfg/SqVC2+sCTtcw0aDTGB7dk+de4U4uUeuz6nOtJcrkFFLG1B0Rg==
+ dependencies:
+ escape-string-regexp "^2.0.0"
state-toggle@^1.0.0:
version "1.0.1"
@@ -11063,15 +11085,15 @@ string-hash@1.1.3:
resolved "https://registry.yarnpkg.com/string-hash/-/string-hash-1.1.3.tgz#e8aafc0ac1855b4666929ed7dd1275df5d6c811b"
integrity sha1-6Kr8CsGFW0Zmkp7X3RJ1311sgRs=
-string-length@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/string-length/-/string-length-2.0.0.tgz#d40dbb686a3ace960c1cffca562bf2c45f8363ed"
- integrity sha1-1A27aGo6zpYMHP/KVivyxF+DY+0=
+string-length@^4.0.1:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.1.tgz#4a973bf31ef77c4edbceadd6af2611996985f8a1"
+ integrity sha512-PKyXUd0LK0ePjSOnWn34V2uD6acUWev9uy0Ft05k0E8xRW+SKcA0F7eMr7h5xlzfn+4O3N+55rduYyet3Jk+jw==
dependencies:
- astral-regex "^1.0.0"
- strip-ansi "^4.0.0"
+ char-regex "^1.0.2"
+ strip-ansi "^6.0.0"
-string-width@^1.0.1, string-width@^1.0.2:
+string-width@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3"
integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=
@@ -11097,7 +11119,7 @@ string-width@^3.0.0, string-width@^3.1.0:
is-fullwidth-code-point "^2.0.0"
strip-ansi "^5.1.0"
-string-width@^4.0.0, string-width@^4.1.0:
+string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.0.tgz#952182c46cc7b2c313d1596e623992bd163b72b5"
integrity sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==
@@ -11172,11 +11194,6 @@ strip-ansi@^6.0.0:
dependencies:
ansi-regex "^5.0.0"
-strip-bom-string@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/strip-bom-string/-/strip-bom-string-1.0.0.tgz#e5211e9224369fbb81d633a2f00044dc8cedad92"
- integrity sha1-5SEekiQ2n7uB1jOi8ABE3IztrZI=
-
strip-bom@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e"
@@ -11189,6 +11206,11 @@ strip-bom@^3.0.0:
resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3"
integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=
+strip-bom@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878"
+ integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==
+
strip-css-comments@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/strip-css-comments/-/strip-css-comments-3.0.0.tgz#7a5625eff8a2b226cf8947a11254da96e13dae89"
@@ -11201,6 +11223,11 @@ strip-eof@^1.0.0:
resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf"
integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=
+strip-final-newline@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad"
+ integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==
+
strip-indent@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-1.0.1.tgz#0c7962a6adefa7bbd4ac366460a638552ae1a0a2"
@@ -11332,13 +11359,21 @@ supports-color@^5.3.0, supports-color@^5.5.0:
dependencies:
has-flag "^3.0.0"
-supports-color@^7.1.0:
- version "7.1.0"
- resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.1.0.tgz#68e32591df73e25ad1c4b49108a2ec507962bfd1"
- integrity sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==
+supports-color@^7.0.0, supports-color@^7.1.0:
+ version "7.2.0"
+ resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da"
+ integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==
dependencies:
has-flag "^4.0.0"
+supports-hyperlinks@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-2.1.0.tgz#f663df252af5f37c5d49bbd7eeefa9e0b9e59e47"
+ integrity sha512-zoE5/e+dnEijk6ASB6/qrK+oYdm2do1hjoLWrqUC/8WEIW1gbxFcKuBof7sW8ArN6e+AYvsE8HBGiVRWL/F5CA==
+ dependencies:
+ has-flag "^4.0.0"
+ supports-color "^7.0.0"
+
svg-tags@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/svg-tags/-/svg-tags-1.0.0.tgz#58f71cee3bd519b59d4b2a843b6c7de64ac04764"
@@ -11354,7 +11389,7 @@ symbol-observable@^1.0.2:
resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804"
integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==
-symbol-tree@^3.2.2, symbol-tree@^3.2.4:
+symbol-tree@^3.2.4:
version "3.2.4"
resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2"
integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==
@@ -11398,6 +11433,14 @@ term-size@^2.1.0:
resolved "https://registry.yarnpkg.com/term-size/-/term-size-2.2.0.tgz#1f16adedfe9bdc18800e1776821734086fcc6753"
integrity sha512-a6sumDlzyHVJWb8+YofY4TW112G6p2FCPEAFk+59gIYHv3XHRhm9ltVQ9kli4hNWeQBwSpe8cRN25x0ROunMOw==
+terminal-link@^2.0.0:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/terminal-link/-/terminal-link-2.1.1.tgz#14a64a27ab3c0df933ea546fba55f2d078edc994"
+ integrity sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==
+ dependencies:
+ ansi-escapes "^4.2.1"
+ supports-hyperlinks "^2.0.0"
+
terser-webpack-plugin@^1.4.3:
version "1.4.3"
resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-1.4.3.tgz#5ecaf2dbdc5fb99745fd06791f46fc9ddb1c9a7c"
@@ -11422,15 +11465,14 @@ terser@^4.0.0, terser@^4.1.2:
source-map "~0.6.1"
source-map-support "~0.5.12"
-test-exclude@^5.0.0:
- version "5.0.0"
- resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-5.0.0.tgz#cdce7cece785e0e829cd5c2b27baf18bc583cfb7"
- integrity sha512-bO3Lj5+qFa9YLfYW2ZcXMOV1pmQvw+KS/DpjqhyX6Y6UZ8zstpZJ+mA2ERkXfpOqhxsJlQiLeVXD3Smsrs6oLw==
+test-exclude@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e"
+ integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==
dependencies:
- arrify "^1.0.1"
+ "@istanbuljs/schema" "^0.1.2"
+ glob "^7.1.4"
minimatch "^3.0.4"
- read-pkg-up "^4.0.0"
- require-main-filename "^1.0.1"
text-table@^0.2.0:
version "0.2.0"
@@ -11457,10 +11499,10 @@ three@^0.84.0:
resolved "https://registry.yarnpkg.com/three/-/three-0.84.0.tgz#95be85a55a0fa002aa625ed559130957dcffd918"
integrity sha1-lb6FpVoPoAKqYl7VWRMJV9z/2Rg=
-throat@^4.0.0:
- version "4.1.0"
- resolved "https://registry.yarnpkg.com/throat/-/throat-4.1.0.tgz#89037cbc92c56ab18926e6ba4cbb200e15672a6a"
- integrity sha1-iQN8vJLFarGJJua6TLsgDhVnKmo=
+throat@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/throat/-/throat-5.0.0.tgz#c5199235803aad18754a667d659b5e72ce16764b"
+ integrity sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==
throttle-debounce@^2.1.0:
version "2.1.0"
@@ -11639,7 +11681,7 @@ touch@^3.1.0:
dependencies:
nopt "~1.0.10"
-tough-cookie@^2.3.3, tough-cookie@^2.3.4, tough-cookie@~2.5.0:
+tough-cookie@^2.3.3, tough-cookie@~2.5.0:
version "2.5.0"
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2"
integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==
@@ -11656,13 +11698,6 @@ tough-cookie@^3.0.1:
psl "^1.1.28"
punycode "^2.1.1"
-tr46@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/tr46/-/tr46-1.0.1.tgz#a8b13fd6bfd2489519674ccde55ba3693b706d09"
- integrity sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=
- dependencies:
- punycode "^2.1.0"
-
tr46@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/tr46/-/tr46-2.0.2.tgz#03273586def1595ae08fedb38d7733cee91d2479"
@@ -11729,20 +11764,22 @@ ts-invariant@^0.4.0:
dependencies:
tslib "^1.9.3"
-ts-jest@24.0.0, ts-jest@^23.10.5:
- version "24.0.0"
- resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-24.0.0.tgz#3f26bf2ec1fa584863a5a9c29bd8717d549efbf6"
- integrity sha512-o8BO3TkMREpAATaFTrXkovMsCpBl2z4NDBoLJuWZcJJj1ijI49UnvDMfVpj+iogn/Jl8Pbhuei5nc/Ti+frEHw==
+ts-jest@26.x:
+ version "26.4.1"
+ resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-26.4.1.tgz#08ec0d3fc2c3a39e4a46eae5610b69fafa6babd0"
+ integrity sha512-F4aFq01aS6mnAAa0DljNmKr/Kk9y4HVZ1m6/rtJ0ED56cuxINGq3Q9eVAh+z5vcYKe5qnTMvv90vE8vUMFxomg==
dependencies:
+ "@types/jest" "26.x"
bs-logger "0.x"
buffer-from "1.x"
fast-json-stable-stringify "2.x"
+ jest-util "^26.1.0"
json5 "2.x"
+ lodash.memoize "4.x"
make-error "1.x"
- mkdirp "0.x"
- resolve "1.x"
- semver "^5.5"
- yargs-parser "10.x"
+ mkdirp "1.x"
+ semver "7.x"
+ yargs-parser "20.x"
tslib@^1.10.0, tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3:
version "1.13.0"
@@ -11790,6 +11827,11 @@ type-fest@^0.5.2:
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.5.2.tgz#d6ef42a0356c6cd45f49485c3b6281fc148e48a2"
integrity sha512-DWkS49EQKVX//Tbupb9TFa19c7+MK1XmzkrZUR8TAktmE/DizXoaoJV6TZ/tSIPXipqNiRI6CyAe7x69Jb6RSw==
+type-fest@^0.6.0:
+ version "0.6.0"
+ resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.6.0.tgz#8d2a2370d3df886eb5c90ada1c5bf6188acf838b"
+ integrity sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==
+
type-fest@^0.8.1:
version "0.8.1"
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d"
@@ -11816,9 +11858,9 @@ typedarray@^0.0.6:
integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
"typescript@2 - 3":
- version "3.3.4000"
- resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.3.4000.tgz#76b0f89cfdbf97827e1112d64f283f1151d6adf0"
- integrity sha512-jjOcCZvpkl2+z7JFn0yBOoLQyLoIkNZAs/fYJkUG6VKy6zLPHJGfQJYFHzibB6GJaF/8QrcECtlQ5cpvRHSMEA==
+ version "3.9.7"
+ resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.7.tgz#98d600a5ebdc38f40cb277522f12dc800e9e25fa"
+ integrity sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw==
uc.micro@^1.0.1, uc.micro@^1.0.5:
version "1.0.5"
@@ -12024,9 +12066,9 @@ upper-case@^1.1.1:
integrity sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg=
uri-js@^4.2.2:
- version "4.2.2"
- resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0"
- integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==
+ version "4.4.0"
+ resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.0.tgz#aa714261de793e8a82347a7bcc9ce74e86f28602"
+ integrity sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g==
dependencies:
punycode "^2.1.0"
@@ -12098,14 +12140,6 @@ util-deprecate@^1.0.1, util-deprecate@~1.0.1:
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
-util.promisify@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.0.0.tgz#440f7165a459c9a16dc145eb8e72f35687097030"
- integrity sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==
- dependencies:
- define-properties "^1.1.2"
- object.getownpropertydescriptors "^2.0.3"
-
util@0.10.3:
version "0.10.3"
resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9"
@@ -12125,7 +12159,7 @@ utils-merge@1.0.1:
resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=
-uuid@3.3.2, uuid@^3.0.1, uuid@^3.3.2:
+uuid@3.3.2:
version "3.3.2"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131"
integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==
@@ -12135,18 +12169,37 @@ uuid@8.1.0:
resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.1.0.tgz#6f1536eb43249f473abc6bd58ff983da1ca30d8d"
integrity sha512-CI18flHDznR0lq54xBycOVmphdCYnQLKn8abKn7PXUiKUGdEd+/l9LWNJmugXel4hXq7S+RMNl34ecyC9TntWg==
+uuid@^3.0.1, uuid@^3.3.2, uuid@^3.3.3:
+ version "3.4.0"
+ resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
+ integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
+
+uuid@^8.3.0:
+ version "8.3.1"
+ resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.1.tgz#2ba2e6ca000da60fce5a196954ab241131e05a31"
+ integrity sha512-FOmRr+FmWEIG8uhZv6C2bTgEVXsHk08kE7mPlrBbEe+c3r9pjceVPgupIfNIhc4yx55H69OXANrUaSuu9eInKg==
+
v8-compile-cache@2.0.3, v8-compile-cache@^2.0.3:
version "2.0.3"
resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.0.3.tgz#00f7494d2ae2b688cfe2899df6ed2c54bef91dbe"
integrity sha512-CNmdbwQMBjwr9Gsmohvm0pbL954tJrNzf6gWL3K+QMQf00PF7ERGrEiLgjuU3mKreLC2MeGhUsNV9ybTbLgd3w==
+v8-to-istanbul@^5.0.1:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-5.0.1.tgz#0608f5b49a481458625edb058488607f25498ba5"
+ integrity sha512-mbDNjuDajqYe3TXFk5qxcQy8L1msXNE37WTlLoqqpBfRsimbNcrlhQlDPntmECEcUvdC+AQ8CyMMf6EUx1r74Q==
+ dependencies:
+ "@types/istanbul-lib-coverage" "^2.0.1"
+ convert-source-map "^1.6.0"
+ source-map "^0.7.3"
+
validate-npm-package-license@^3.0.1:
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz#2804babe712ad3379459acfbe24746ab2c303fbc"
- integrity sha1-KAS6vnEq0zeUWaz74kdGqywwP7w=
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a"
+ integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==
dependencies:
- spdx-correct "~1.0.0"
- spdx-expression-parse "~1.0.0"
+ spdx-correct "^3.0.0"
+ spdx-expression-parse "^3.0.0"
vary@~1.1.2:
version "1.1.2"
@@ -12292,22 +12345,22 @@ vue-hot-reload-api@^2.3.0:
resolved "https://registry.yarnpkg.com/vue-hot-reload-api/-/vue-hot-reload-api-2.3.0.tgz#97976142405d13d8efae154749e88c4e358cf926"
integrity sha512-2j/t+wIbyVMP5NvctQoSUvLkYKoWAAk2QlQiilrM2a6/ulzFgdcLUJfTvs4XQ/3eZhHiBmmEojbjmM4AzZj8JA==
-vue-jest@4.0.0-beta.2:
- version "4.0.0-beta.2"
- resolved "https://registry.yarnpkg.com/vue-jest/-/vue-jest-4.0.0-beta.2.tgz#f2120ea9d24224aad3a100c2010b0760d47ee6fe"
- integrity sha512-SywBIciuIfqsCb8Eb9UQ02s06+NV8Ry8KnbyhAfnvnyFFulIuh7ujtga9eJYq720nCS4Hz4TpVtS4pD1ZbUILQ==
+vue-jest@4.0.0-rc.0:
+ version "4.0.0-rc.0"
+ resolved "https://registry.yarnpkg.com/vue-jest/-/vue-jest-4.0.0-rc.0.tgz#0ce263c7f923441d0eeb99841620e8e9470336f4"
+ integrity sha512-0U1osuxR8cubzwUJDWU9VNOMYMwrMayaDUH+IYhoMHyi3zaa34nvr8BrdGLqo2ufnaiOCni2JgSy8nkcOi+Awg==
dependencies:
"@babel/plugin-transform-modules-commonjs" "^7.2.0"
- "@vue/component-compiler-utils" "^2.4.0"
+ "@vue/component-compiler-utils" "^3.1.0"
chalk "^2.1.0"
extract-from-css "^0.4.4"
- source-map "^0.5.6"
- ts-jest "^23.10.5"
+ source-map "0.5.6"
+ ts-jest "26.x"
-vue-loader@^15.9.0:
- version "15.9.0"
- resolved "https://registry.yarnpkg.com/vue-loader/-/vue-loader-15.9.0.tgz#5d4b0378a4606188fc83e587ed23c94bc3a10998"
- integrity sha512-FeDHvTSpwyLeF7LIV1PYkvqUQgTJ8UmOxhSlCyRSxaXCKk+M6NF4tDQsLsPPNeDPyR7TfRQ8MLg6v+8PsDV9xQ==
+vue-loader@^15.9.3:
+ version "15.9.3"
+ resolved "https://registry.yarnpkg.com/vue-loader/-/vue-loader-15.9.3.tgz#0de35d9e555d3ed53969516cac5ce25531299dda"
+ integrity sha512-Y67VnGGgVLH5Voostx8JBZgPQTlDQeOVBLOEsjc2cXbCYBKexSKEpOA56x0YZofoDOTszrLnIShyOX1p9uCEHA==
dependencies:
"@vue/component-compiler-utils" "^3.1.0"
hash-sum "^1.0.2"
@@ -12315,10 +12368,10 @@ vue-loader@^15.9.0:
vue-hot-reload-api "^2.3.0"
vue-style-loader "^4.1.0"
-vue-router@^3.4.3:
- version "3.4.3"
- resolved "https://registry.yarnpkg.com/vue-router/-/vue-router-3.4.3.tgz#fa93768616ee338aa174f160ac965167fa572ffa"
- integrity sha512-BADg1mjGWX18Dpmy6bOGzGNnk7B/ZA0RxuA6qedY/YJwirMfKXIDzcccmHbQI0A6k5PzMdMloc0ElHfyOoX35A==
+vue-router@^3.4.7:
+ version "3.4.7"
+ resolved "https://registry.yarnpkg.com/vue-router/-/vue-router-3.4.7.tgz#bf189bafd16f4e4ef783c4a6250a3090f2c1fa1b"
+ integrity sha512-CbHXue5BLrDivOk5O4eZ0WT4Yj8XwdXa4kCnsEIOzYUPF/07ZukayA2jGxDCJxLc9SgVQX9QX0OuGOwGlVB4Qg==
vue-runtime-helpers@^1.1.2:
version "1.1.2"
@@ -12333,10 +12386,10 @@ vue-style-loader@^4.1.0:
hash-sum "^1.0.2"
loader-utils "^1.0.2"
-vue-template-compiler@^2.5.20, vue-template-compiler@^2.6.10:
- version "2.6.10"
- resolved "https://registry.yarnpkg.com/vue-template-compiler/-/vue-template-compiler-2.6.10.tgz#323b4f3495f04faa3503337a82f5d6507799c9cc"
- integrity sha512-jVZkw4/I/HT5ZMvRnhv78okGusqe0+qH2A0Em0Cp8aq78+NK9TII263CDVz2QXZsIT+yyV/gZc/j/vlwa+Epyg==
+vue-template-compiler@^2.5.20, vue-template-compiler@^2.6.12:
+ version "2.6.12"
+ resolved "https://registry.yarnpkg.com/vue-template-compiler/-/vue-template-compiler-2.6.12.tgz#947ed7196744c8a5285ebe1233fe960437fcc57e"
+ integrity sha512-OzzZ52zS41YUbkCBfdXShQTe69j1gQDZ9HIX8miuC9C3rBCk9wIRjLiZZLrmX9V+Ftq/YEyv1JaVr5Y/hNtByg==
dependencies:
de-indent "^1.0.2"
he "^1.1.0"
@@ -12351,10 +12404,10 @@ vue-virtual-scroll-list@^1.4.4:
resolved "https://registry.yarnpkg.com/vue-virtual-scroll-list/-/vue-virtual-scroll-list-1.4.4.tgz#5fca7a13f785899bbfb70471ec4fe222437d8495"
integrity sha512-wU7FDpd9Xy4f62pf8SBg/ak21jMI/pdx4s4JPah+z/zuhmeAafQgp8BjtZvvt+b0BZOsOS1FJuCfUH7azTkivQ==
-vue@^2.6.10:
- version "2.6.10"
- resolved "https://registry.yarnpkg.com/vue/-/vue-2.6.10.tgz#a72b1a42a4d82a721ea438d1b6bf55e66195c637"
- integrity sha512-ImThpeNU9HbdZL3utgMCq0oiMzAkt1mcgy3/E6zWC/G6AaQoeuFdsl9nDhTDU3X1R6FK7nsIUuRACVcjI+A2GQ==
+vue@^2.6.12:
+ version "2.6.12"
+ resolved "https://registry.yarnpkg.com/vue/-/vue-2.6.12.tgz#f5ebd4fa6bd2869403e29a896aed4904456c9123"
+ integrity sha512-uhmLFETqPPNyuLLbsKz6ioJ4q7AZHzD8ZVFNATNyICSZouqP2Sz0rotWQC8UNBF6VGSCs5abnKJoStA6JbCbfg==
vuedraggable@^2.23.0:
version "2.23.0"
@@ -12368,7 +12421,7 @@ vuex@^3.5.1:
resolved "https://registry.yarnpkg.com/vuex/-/vuex-3.5.1.tgz#f1b8dcea649bc25254cf4f4358081dbf5da18b3d"
integrity sha512-w7oJzmHQs0FM9LXodfskhw9wgKBiaB+totOdb8sNzbTB2KDCEEwEs29NzBZFh/lmEK1t5tDmM1vtsO7ubG1DFw==
-w3c-hr-time@^1.0.1, w3c-hr-time@^1.0.2:
+w3c-hr-time@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd"
integrity sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==
@@ -12424,17 +12477,12 @@ web-vitals@^0.2.4:
resolved "https://registry.yarnpkg.com/web-vitals/-/web-vitals-0.2.4.tgz#ec3df43c834a207fd7cdefd732b2987896e08511"
integrity sha512-6BjspCO9VriYy12z356nL6JBS0GYeEcA457YyRzD+dD6XYCQ75NKhcOHUMHentOE7OcVCIXXDvOm0jKFfQG2Gg==
-webidl-conversions@^4.0.2:
- version "4.0.2"
- resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad"
- integrity sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==
-
webidl-conversions@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-5.0.0.tgz#ae59c8a00b121543a2acc65c0434f57b0fc11aff"
integrity sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==
-webidl-conversions@^6.0.0:
+webidl-conversions@^6.1.0:
version "6.1.0"
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-6.1.0.tgz#9111b4d7ea80acd40f5270d666621afa78b69514"
integrity sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==
@@ -12587,36 +12635,18 @@ websocket-extensions@>=0.1.1:
resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.1.tgz#76899499c184b6ef754377c2dbb0cd6cb55d29e7"
integrity sha1-domUmcGEtu91Q3fC27DNbLVdKec=
-whatwg-encoding@^1.0.1, whatwg-encoding@^1.0.3, whatwg-encoding@^1.0.5:
+whatwg-encoding@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz#5abacf777c32166a51d085d6b4f3e7d27113ddb0"
integrity sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==
dependencies:
iconv-lite "0.4.24"
-whatwg-mimetype@^2.1.0, whatwg-mimetype@^2.2.0, whatwg-mimetype@^2.3.0:
+whatwg-mimetype@^2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf"
integrity sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==
-whatwg-url@^6.4.1:
- version "6.5.0"
- resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-6.5.0.tgz#f2df02bff176fd65070df74ad5ccbb5a199965a8"
- integrity sha512-rhRZRqx/TLJQWUpQ6bmrt2UV4f0HCQ463yQuONJqC6fO2VoEb1pTYddbe59SkYq87aoM5A3bdhMZiUiVws+fzQ==
- dependencies:
- lodash.sortby "^4.7.0"
- tr46 "^1.0.1"
- webidl-conversions "^4.0.2"
-
-whatwg-url@^7.0.0:
- version "7.0.0"
- resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-7.0.0.tgz#fde926fa54a599f3adf82dff25a9f7be02dc6edd"
- integrity sha512-37GeVSIJ3kn1JgKyjiYNmSLP1yzbpb29jdmwBSgkD9h40/hyrR/OifpVUndji3tmwGgD8qpw7iQu3RSbCrBpsQ==
- dependencies:
- lodash.sortby "^4.7.0"
- tr46 "^1.0.1"
- webidl-conversions "^4.0.2"
-
whatwg-url@^8.0.0:
version "8.1.0"
resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-8.1.0.tgz#c628acdcf45b82274ce7281ee31dd3c839791771"
@@ -12626,23 +12656,25 @@ whatwg-url@^8.0.0:
tr46 "^2.0.2"
webidl-conversions "^5.0.0"
-which-module@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f"
- integrity sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=
-
which-module@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a"
integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=
-which@1, which@^1.2.1, which@^1.2.14, which@^1.2.9, which@^1.3.0, which@^1.3.1:
+which@1, which@^1.2.1, which@^1.2.14, which@^1.2.9, which@^1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==
dependencies:
isexe "^2.0.0"
+which@^2.0.1, which@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"
+ integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==
+ dependencies:
+ isexe "^2.0.0"
+
wide-align@^1.1.0:
version "1.1.3"
resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457"
@@ -12699,20 +12731,20 @@ wrap-ansi@^5.1.0:
string-width "^3.0.0"
strip-ansi "^5.0.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"
+
wrappy@1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
-write-file-atomic@2.4.1:
- version "2.4.1"
- resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-2.4.1.tgz#d0b05463c188ae804396fd5ab2a370062af87529"
- integrity sha512-TGHFeZEZMnv+gBFRfjAcxL5bPHrsGKtnb4qsFAws7/vlh+QfwAaySIw4AXP9ZskTTh5GWu3FLuJhsWVdiJPGvg==
- dependencies:
- graceful-fs "^4.1.11"
- imurmurhash "^0.1.4"
- signal-exit "^3.0.2"
-
write-file-atomic@^3.0.0:
version "3.0.3"
resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-3.0.3.tgz#56bd5c5a5c70481cd19c571bd39ab965a5de56e8"
@@ -12730,13 +12762,6 @@ write@1.0.3:
dependencies:
mkdirp "^0.5.1"
-ws@^5.2.0:
- version "5.2.2"
- resolved "https://registry.yarnpkg.com/ws/-/ws-5.2.2.tgz#dffef14866b8e8dc9133582514d1befaf96e980f"
- integrity sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA==
- dependencies:
- async-limiter "~1.0.0"
-
ws@^6.0.0, ws@^6.2.1:
version "6.2.1"
resolved "https://registry.yarnpkg.com/ws/-/ws-6.2.1.tgz#442fdf0a47ed64f59b6a5d8ff130f4748ed524fb"
@@ -12829,11 +12854,6 @@ xterm@3.14.5:
resolved "https://registry.yarnpkg.com/xterm/-/xterm-3.14.5.tgz#c9d14e48be6873aa46fb429f22f2165557fd2dea"
integrity sha512-DVmQ8jlEtL+WbBKUZuMxHMBgK/yeIZwkXB81bH+MGaKKnJGYwA+770hzhXPfwEIokK9On9YIFPRleVp/5G7z9g==
-y18n@^3.2.1:
- version "3.2.1"
- resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41"
- integrity sha1-bRX7qITAhnnA136I53WegR4H+kE=
-
"y18n@^3.2.1 || ^4.0.0", y18n@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b"
@@ -12854,7 +12874,12 @@ yallist@^4.0.0:
resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
-yargs-parser@10.x, yargs-parser@^10.0.0:
+yargs-parser@20.x:
+ version "20.2.1"
+ resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.1.tgz#28f3773c546cdd8a69ddae68116b48a5da328e77"
+ integrity sha512-yYsjuSkjbLMBp16eaOt7/siKTjNVjMm3SoJnIg3sEh/JsvqVVDyjRKmaJV4cl+lNIgq6QEco2i3gDebJl7/vLA==
+
+yargs-parser@^10.0.0:
version "10.1.0"
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-10.1.0.tgz#7202265b89f7e9e9f2e5765e0fe735a905edbaa8"
integrity sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ==
@@ -12869,22 +12894,23 @@ yargs-parser@^11.1.1:
camelcase "^5.0.0"
decamelize "^1.2.0"
-yargs-parser@^13.1.0:
- version "13.1.1"
- resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.1.tgz#d26058532aa06d365fe091f6a1fc06b2f7e5eca0"
- integrity sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==
+yargs-parser@^13.1.0, yargs-parser@^13.1.2:
+ version "13.1.2"
+ resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.2.tgz#130f09702ebaeef2650d54ce6e3e5706f7a4fb38"
+ integrity sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==
dependencies:
camelcase "^5.0.0"
decamelize "^1.2.0"
-yargs-parser@^5.0.0:
- version "5.0.0"
- resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-5.0.0.tgz#275ecf0d7ffe05c77e64e7c86e4cd94bf0e1228a"
- integrity sha1-J17PDX/+Bcd+ZOfIbkzZS/DhIoo=
+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 "^3.0.0"
+ camelcase "^5.0.0"
+ decamelize "^1.2.0"
-yargs@12.0.5, yargs@^12.0.2:
+yargs@12.0.5:
version "12.0.5"
resolved "https://registry.yarnpkg.com/yargs/-/yargs-12.0.5.tgz#05f5997b609647b64f66b81e3b4b10a368e7ad13"
integrity sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==
@@ -12919,24 +12945,38 @@ yargs@13.2.4:
y18n "^4.0.0"
yargs-parser "^13.1.0"
-yargs@^7.0.0:
- version "7.1.0"
- resolved "https://registry.yarnpkg.com/yargs/-/yargs-7.1.0.tgz#6ba318eb16961727f5d284f8ea003e8d6154d0c8"
- integrity sha1-a6MY6xaWFyf10oT46gA+jWFU0Mg=
+yargs@^13.3.2:
+ version "13.3.2"
+ resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.2.tgz#ad7ffefec1aa59565ac915f82dccb38a9c31a2dd"
+ integrity sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==
dependencies:
- camelcase "^3.0.0"
- cliui "^3.2.0"
- decamelize "^1.1.1"
- get-caller-file "^1.0.1"
- os-locale "^1.4.0"
- read-pkg-up "^1.0.1"
+ cliui "^5.0.0"
+ find-up "^3.0.0"
+ get-caller-file "^2.0.1"
require-directory "^2.1.1"
- require-main-filename "^1.0.1"
+ require-main-filename "^2.0.0"
+ set-blocking "^2.0.0"
+ string-width "^3.0.0"
+ which-module "^2.0.0"
+ y18n "^4.0.0"
+ yargs-parser "^13.1.2"
+
+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 "^1.0.2"
- which-module "^1.0.0"
- y18n "^3.2.1"
- yargs-parser "^5.0.0"
+ string-width "^4.2.0"
+ which-module "^2.0.0"
+ y18n "^4.0.0"
+ yargs-parser "^18.1.2"
yarn-check-webpack-plugin@^1.2.0:
version "1.2.0"